[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*.{c,c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]\ncharset = utf-8\nend_of_line = crlf\nindent_style = space\nindent_size = 4\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files\n* text=auto working-tree-encoding=UTF-8\n\n# Custom for Visual Studio\n*.cs            diff=csharp\n*.sln           merge=union\n*.slnx          merge=union\n*.csproj        merge=union\n*.vbproj        merge=union\n*.fsproj        merge=union\n*.dbproj        merge=union\n\n# Project files\n*.appinstaller  text\n*.bat           text\n*.c             text\n*.cs            text\n*.cpp           text\n*.config        text\n*.cmake         text\n*.cmd           text\n*.csproj        text\n*.def           text\n*.ddf           text\n*.editorconfig  text\n*.gitattributes text\n*.gitignore     text\n*.h             text\n*.hpp           text\n*.inc           text\n*.inf           text\n*.json          text\n*.map           text\n*.manifest      text\n*.mc            text\n*.md            text\n*.natvis        text\n*.ps1           text\n*.props         text\n*.pubxml        text\n*.resx          text\n*.rc            text\n*.sh            text eol=lf\n*.sln           text\n*.slnx          text\n*.txt           text\n*.vsconfig      text\n*.vcxproj       text\n*.filters       text\n*.xml           text\n*.yml           text\n*.yaml          text\n\n**AUTHORS       text\n**COPYING       text\n**CHANGELOG     text\n**CODEOWNERS    text\n**LICENSE       text\n**LICENCE       text\n**README        text\n\n*.bmp           binary\n*.dll           binary\n*.exe           binary\n*.ico           binary\n*.lib           binary\n*.pdb           binary\n*.png           binary\n*.s             binary\n*.sys           binary\n*.zip           binary\n\n# svg standard require LF\n*.svg           text eol=lf\n\n# Standard to msysgit\n*.doc           diff=astextplain\n*.DOC           diff=astextplain\n*.docx          diff=astextplain\n*.DOCX          diff=astextplain\n*.dot           diff=astextplain\n*.DOT           diff=astextplain\n*.pdf           diff=astextplain\n*.PDF           diff=astextplain\n*.rtf           diff=astextplain\n*.RTF           diff=astextplain\n\n# Ignore files during repository export\n.gitattributes  export-ignore\n.gitignore      export-ignore\n.gitmodules     export-ignore\n.github         export-ignore\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# Below is a list of System Informer team members' GitHub handles who are\n# suggested reviewers for contributions to this repository.\n#\n# These names are just suggestions. It is fine to have your changes\n# reviewed by someone else.\n#\n# Use git ls-files '<pattern>' without a / prefix to see the list of matching files.\n\n/CODEOWNERS @dmex @jxy-s\n/KSystemInformer @jxy-s\n/SystemInformer @dmex @jxy-s\n/build @dmex @jxy-s\n/kphlib @jxy-s\n/phlib @dmex @jxy-s\n/phnt @dmex @jxy-s\n/plugins @dmex @jxy-s\n/tools @dmex\n/tools/CustomBuildTool/DynData.cs @jxy-s\n.github/workflows @dmex @jxy-s\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [dmex, jxy-s]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: 'Bug report'\ndescription: Report bugs or other issues\nbody:\n  - type: textarea\n    attributes:\n      label: Brief description of your issue\n      placeholder: Briefly describe your issue here.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Steps to reproduce (optional)\n      placeholder: How to reproduce the issue?\n    validations:\n      required: false\n  - type: textarea\n    attributes:\n      label: Expected behavior (optional)\n      placeholder: What did you expect to happen?\n    validations:\n      required: false\n  - type: textarea\n    attributes:\n      label: Actual behavior (optional)\n      placeholder: What is currently happening?\n    validations:\n      required: false\n  - type: textarea\n    attributes:\n      label: Environment (optional)\n      placeholder: |\n        System Informer version\n        Windows version\n        Any other information?\n      render: shell\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n  - name: General Questions\n    url: https://github.com/winsiderss/systeminformer/discussions/new\n    about: Have a question? Start a new discussion.\n  - name: Review open issues\n    url: https://github.com/winsiderss/systeminformer/issues\n    about: Check existing bug reports for already reported issues.\n  - name: Create a blank issue\n    url: https://github.com/winsiderss/systeminformer/issues/new\n    about: Create a blank issue for anything else.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: \"Feature request\"\ndescription: Suggest features, modifications or ideas\ntype: \"Feature\"\nlabels: [\"enhancement\"]\nbody:\n  - type: textarea\n    attributes:\n      label: Description of the feature, modification, idea or suggestion\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Proposed implementation details (optional)\n      placeholder: Suggest how to implement the feature.\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/workflows/cla.yml",
    "content": "name: \"CLA Assistant\"\non:\n  issue_comment:\n    types: [created]\n  pull_request_target:\n    types: [opened,closed,synchronize]\n\npermissions:\n  actions: write\n  checks: read\n  contents: read\n  issues: read\n  discussions: read\n  pull-requests: write\n  statuses: read\n\njobs:\n  CLAssistant:\n    if: ${{ github.event_name == 'pull_request_target' || github.event.issue.pull_request }}\n    runs-on: ubuntu-latest\n    steps:\n      - name: \"CLA Assistant\"\n        if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'\n        uses: cla-assistant/github-action@dbc1c64d82d3aad5072007a41fff2828ae6d23ec\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          PERSONAL_ACCESS_TOKEN : ${{ secrets.CLA_ASSISTANT_TOKEN }}\n        with:\n          path-to-signatures: 'systeminformer/cla-signatures.json'\n          path-to-document: 'https://github.com/winsiderss/systeminformer/blob/master/CLA.md'\n          branch: 'main'\n          remote-organization-name: 'winsiderss'\n          remote-repository-name: 'winsiderss-cla'\n          lock-pullrequest-aftermerge: false\n"
  },
  {
    "path": ".github/workflows/cmake.yml",
    "content": "name: 'cmake-continuous-integration'\n\non:\n  workflow_dispatch:\n  push:\n    branches: ['master']\n  pull_request:\n    branches: ['master']\n\njobs:\n  build:\n    permissions:\n      contents: read\n    strategy:\n      fail-fast: false\n      matrix:\n        os:\n          - windows-latest\n        toolchain:\n          - msvc-amd64\n          - msvc-arm64\n          - msvc-x86\n          - clang-msvc-amd64\n          - clang-msvc-arm64\n          - clang-msvc-x86\n        configuration:\n          - Debug\n          - Release\n        generator:\n          - Ninja\n    runs-on: ${{ matrix.os }}\n    name: ${{ matrix.configuration }} ${{ matrix.toolchain }}\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1\n\n    - name: NuGet Cache\n      uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # 5.0.0\n      with:\n        path: packages\n        key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}\n        restore-keys: nuget-${{ runner.os }}-\n\n    - name: Nuget Restore\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: nuget restore .\\packages.config -PackagesDirectory .\\packages\\\n\n    - name: Build Tools\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_tools.cmd\n\n    - name: Generate\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_cmake.cmd \"${{ matrix.generator }}\" ${{ matrix.configuration }} ${{ matrix.toolchain }} generate\n\n    - name: Build\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_cmake.cmd \"${{ matrix.generator }}\" ${{ matrix.configuration }} ${{ matrix.toolchain }} build\n"
  },
  {
    "path": ".github/workflows/msbuild.yml",
    "content": "name: 'continuous-integration'\n\non:\n  workflow_dispatch:\n  push:\n    branches: ['master']\n  pull_request:\n    branches: ['master']\n\njobs:\n  build:\n    permissions:\n      contents: read\n    strategy:\n      fail-fast: false\n      matrix:\n        os: ['windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1\n\n    - name: NuGet Cache\n      uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # 5.0.0\n      with:\n        path: packages\n        key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}\n        restore-keys: nuget-${{ runner.os }}-\n\n    - name: Nuget Restore\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: nuget restore .\\packages.config -PackagesDirectory .\\packages\\\n\n    - name: Build Tools\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_init.cmd\n\n    - name: Build Solution\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_debug.cmd\n\n  build-release:\n    permissions:\n      contents: read\n    strategy:\n      matrix:\n        os: ['windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1\n\n    - name: NuGet Cache\n      uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # 5.0.0\n      with:\n        path: packages\n        key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}\n        restore-keys: nuget-${{ runner.os }}-\n\n    - name: Nuget Restore\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: nuget restore .\\packages.config -PackagesDirectory .\\packages\\\n\n    - name: Build Tools\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_init.cmd\n\n    - name: Build Solution\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_release.cmd\n\n  build-driver:\n    permissions:\n      contents: read\n    strategy:\n      matrix:\n        os: ['windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1\n\n    - name: NuGet Cache\n      uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # 5.0.0\n      with:\n        path: packages\n        key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}\n        restore-keys: nuget-${{ runner.os }}-\n\n    - name: Nuget Restore\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: nuget restore .\\packages.config -PackagesDirectory .\\packages\\\n\n    - name: Build Tools\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_tools.cmd\n\n    - name: Build Driver\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_zdriver.cmd prefast\n\n  build-driver-release:\n    permissions:\n      contents: read\n    strategy:\n      matrix:\n        os: ['windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1\n\n    - name: NuGet Cache\n      uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # 5.0.0\n      with:\n        path: packages\n        key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}\n        restore-keys: nuget-${{ runner.os }}-\n\n    - name: Nuget Restore\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: nuget restore .\\packages.config -PackagesDirectory .\\packages\\\n\n    - name: Build Tools\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_tools.cmd\n\n    - name: Build Driver\n      shell: cmd\n      working-directory: ${{github.workspace}}\n      run: build\\build_zdriver.cmd release\n"
  },
  {
    "path": ".github/workflows/scan.yml",
    "content": "name: 'CodeQL Analysis'\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: '0 0 * * 0'\n\njobs:\n  analyze_driver:\n    name: analyze-driver\n    runs-on: windows-2025\n    permissions:\n      security-events: write\n      actions: read\n      contents: read\n    strategy:\n      fail-fast: false\n      matrix:\n        language: ['cpp']\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1\n        with:\n          fetch-depth: 0\n\n      - name: Nuget Cache\n        uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # 5.0.0\n        with:\n          path: packages\n          key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}\n          restore-keys: nuget-${{ runner.os }}-\n\n      - name: Nuget Restore\n        shell: cmd\n        run: nuget restore .\\packages.config -PackagesDirectory .\\packages\\\n\n      - name: Build Tools\n        shell: cmd\n        run: build\\build_tools.cmd\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # 4.31.7\n        with:\n          languages: ${{ matrix.language }}\n\n      - name: Build Driver\n        shell: cmd\n        run: build\\build_zdriver.cmd\n\n      - name: Finalize CodeQL Database\n        run: |\n          $codeqlPath = (Get-ChildItem -Path \"$env:RUNNER_TOOL_CACHE\\CodeQL\" -Recurse -Filter \"codeql.exe\" | Select-Object -First 1).FullName\n          & $codeqlPath database finalize \"${{ runner.temp }}\\codeql_databases\\cpp\"\n\n      - name: Download Windows Driver Query Packs\n        shell: pwsh\n        run: |\n          $codeqlPath = (Get-ChildItem -Path \"$env:RUNNER_TOOL_CACHE\\CodeQL\" -Recurse -Filter \"codeql.exe\" | Select-Object -First 1).FullName\n          & $codeqlPath pack download microsoft/windows-drivers@1.8.2\n          & $codeqlPath pack download microsoft/cpp-queries@0.0.4\n\n      - name: Run Windows Driver Analysis\n        shell: pwsh\n        run: |\n          $codeqlPath = (Get-ChildItem -Path \"$env:RUNNER_TOOL_CACHE\\CodeQL\" -Recurse -Filter \"codeql.exe\" | Select-Object -First 1).FullName\n          $sarifOut = Join-Path \"${{ runner.temp }}\" \"driver-analysis.sarif\"\n          & $codeqlPath database analyze \"${{ runner.temp }}\\codeql_databases\\cpp\" microsoft/windows-drivers --format=sarifv2.1.0 --output=$sarifOut\n          if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }\n\n      - name: Filter CodeQL Results\n        uses: advanced-security/filter-sarif@f3b8118a9349d88f7b1c0c488476411145b6270d # 1.0.1\n        with:\n          input: ${{ runner.temp }}\\driver-analysis.sarif\n          output: ${{ runner.temp }}\\driver-filtered.sarif\n          patterns: packages/**\n\n      - name: Upload CodeQL Results\n        uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # 4.31.7\n        with:\n          sarif_file: ${{ runner.temp }}\\driver-filtered.sarif\n\n  analyze_library:\n    name: analyze-software\n    runs-on: windows-2025\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    strategy:\n      fail-fast: false\n      matrix:\n        language: ['cpp']\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1\n        with:\n          fetch-depth: 0\n\n      - name: Nuget Cache\n        uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # 5.0.0\n        with:\n          path: packages\n          key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}\n          restore-keys: nuget-${{ runner.os }}-\n\n      - name: Nuget Restore\n        shell: cmd\n        run: nuget restore .\\packages.config -PackagesDirectory .\\packages\\\n\n      - name: Build Init\n        shell: cmd\n        run: build\\build_init.cmd\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # 4.31.7\n        with:\n          languages: ${{ matrix.language }}\n\n      - name: Build Driver\n        shell: cmd\n        run: build\\build_zdriver.cmd\n\n      - name: Build Release\n        shell: cmd\n        run: build\\build_release.cmd\n\n      - name: Perform CodeQL analysis\n        uses: github/codeql-action/analyze@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # 4.31.7\n        with:\n          category: '/language:${{ matrix.language }}'\n          output: sarif-results\n          upload: never\n\n      - name: Filter CodeQL Results\n        uses: advanced-security/filter-sarif@f3b8118a9349d88f7b1c0c488476411145b6270d # 1.0.1\n        with:\n          input: sarif-results/cpp.sarif\n          output: sarif-results/filtered.sarif\n          patterns: |\n            packages/**/*\n            tools/CustomBuildTool/generated/**/*\n            tools/CustomBuildTool/obj/**/*\n            tools/thirdparty/**/*\n\n      - name: Upload CodeQL Results\n        uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # 4.31.7\n        with:\n          sarif_file: sarif-results/filtered.sarif\n\n  analyze_csharp:\n     name: analyze-tools\n     runs-on: windows-2025\n     permissions:\n       actions: read\n       contents: read\n       security-events: write\n     strategy:\n       fail-fast: false\n       matrix:\n         language: ['csharp']\n     steps:\n       - name: Checkout repository\n         uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1\n         with:\n           fetch-depth: 0\n\n       - name: Nuget Cache\n         uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # 5.0.0\n         with:\n           path: packages\n           key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}\n           restore-keys: nuget-${{ runner.os }}-\n\n       - name: Nuget Restore\n         shell: cmd\n         run: nuget restore .\\packages.config -PackagesDirectory .\\packages\\\n\n       - name: Initialize CodeQL\n         uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # 4.31.7\n         with:\n           languages: ${{ matrix.language }}\n\n       - name: Build Tools\n         shell: cmd\n         run: build\\build_tools.cmd\n\n       - name: Perform CodeQL analysis\n         uses: github/codeql-action/analyze@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # 4.31.7\n         with:\n           category: '/language:${{ matrix.language }}'\n           output: sarif-results\n           upload: never\n\n       - name: Filter CodeQL Results\n         uses: advanced-security/filter-sarif@f3b8118a9349d88f7b1c0c488476411145b6270d # 1.0.1\n         with:\n           input: sarif-results/csharp.sarif\n           output: sarif-results/filtered.sarif\n           patterns: |\n             packages/**/*\n             tools/CustomBuildTool/generated/**/*\n             tools/CustomBuildTool/obj/**/*\n             tools/thirdparty/**/*\n\n       - name: Upload CodeQL Results\n         uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # 4.31.7\n         with:\n           sarif_file: sarif-results/filtered.sarif\n"
  },
  {
    "path": ".gitignore",
    "content": "#################\n## Visual Studio\n#################\n\n# User-specific files\n*.suo\n*.user\n*.key\n*.sig\n*.orig\n\n# Build results\n*.exe\n*.sys\n*.dll\n*.lib\n*.appx\n*.appxbundle\n*.cer\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pfx\n*.pgc\n*.pgd\n*.pvk\n*.res\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tlog\n*.tmp\n*.vspscc\n*_i.c\n*_p.c\n*.bak\n\n# Visual C++ cache files\n*.aps\n*.idb\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.db\n\n# Visual Studio profiler\n*.psess\n*.vsp\n\n# ReSharper is a .NET coding add-in\n_ReSharper*\n\n# Click-Once directory\npublish\n\n# Others\n[Bb]in\n[Oo]bj\n*.Cache\n~$*\n\n# Backup & report files\n_UpgradeReport_Files/\n#Backup*/\nUpgradeLog*.XML\n\n# Windows image file caches\nThumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Visual Studio files\nipch/\n.vs/\n\n# VS Code files\n.vscode/*\n.vscode/settings.json\n!.vscode/launch.json\n!.vscode/tasks.json\n!.vscode/extensions.json\n\n*.code-workspace\n\n# NuGet Packages\n*.nupkg\n**/packages/\n**/vcpkg_installed/\n\n# CMake files\n**/.cmake/\n**/CMakeCache.txt\n**/CMakeFiles/\n\n# JSON Compilation Database\n**/compile_commands.json\n**/.cache/\n\n# AI instructions and caches\n.github/copilot-instructions.md\n.clinerules\nmemory-bank/\n\n##########################\n## Project specific rules\n##########################\n\n**/bin/\n**/out/\nbuild/output/\nplugins-extra/\nsdk/\ntarget/\ntools/thirdparty/vcpkg_installed/*\n\nbin-cmake/\nbuild-*/\n\n!KSystemInformer/bin-signed/*/ksi.dll\n!KSystemInformer/bin-signed/*/ksi.pdb\n!KSystemInformer/bin-signed/*/systeminformer.sys\n!KSystemInformer/bin-signed/*/systeminformer.pdb\n!tools/CustomSignTool/bin/Release*/CustomSignTool.exe\n!tools/fixlib/bin/Release/fixlib.exe\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Launch SystemInformer (Debug64)\",\n            \"type\": \"cppvsdbg\",\n            \"request\": \"launch\",\n            \"program\": \"${workspaceFolder}/bin/Debug64/SystemInformer.exe\",\n            \"args\": [],\n            \"stopAtEntry\": false,\n            \"cwd\": \"${workspaceFolder}\",\n            \"environment\": [],\n            \"console\": \"integratedTerminal\"\n        },\n        {\n            \"name\": \"Attach to Process\",\n            \"type\": \"cppvsdbg\",\n            \"request\": \"attach\",\n            \"processId\": \"${command:pickProcess}\"\n        }\n    ]\n}"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"label\": \"Build SystemInformer (Debug64)\",\n            \"type\": \"shell\",\n            \"command\": \"msbuild\",\n            \"args\": [\n                \"${workspaceFolder}/SystemInformer.sln\",\n                \"/p:Configuration=Debug\",\n                \"/p:Platform=x64\",\n                \"/t:Rebuild\",\n                \"/m\"\n            ],\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            },\n            \"problemMatcher\": \"$msCompile\"\n        },\n        {\n            \"label\": \"Build Plugins (Debug64)\",\n            \"type\": \"shell\",\n            \"command\": \"msbuild\",\n            \"args\": [\n                \"${workspaceFolder}/Plugins/Plugins.sln\",\n                \"/p:Configuration=Debug\",\n                \"/p:Platform=x64\",\n                \"/t:Rebuild\",\n                \"/m\"\n            ],\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            },\n            \"problemMatcher\": \"$msCompile\"\n        },\n        {\n            \"label\": \"Build ThirdParty (Debug64)\",\n            \"type\": \"shell\",\n            \"command\": \"msbuild\",\n            \"args\": [\n                \"${workspaceFolder}/tools/thirdparty/thirdparty.sln\",\n                \"/p:Configuration=Debug\",\n                \"/p:Platform=x64\",\n                \"/t:Rebuild\",\n                \"/m\"\n            ],\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            },\n            \"problemMatcher\": \"$msCompile\"\n        },\n        {\n            \"label\": \"Build SystemInformer (kernel driver) (Debug64)\",\n            \"type\": \"shell\",\n            \"command\": \"msbuild\",\n            \"args\": [\n                \"${workspaceFolder}/KSystemInformer/KSystemInformer.sln\",\n                \"/p:Configuration=Debug\",\n                \"/p:Platform=x64\",\n                \"/t:Rebuild\",\n                \"/m\"\n            ],\n            \"options\": { \n                \"env\": { \n                    \"KSI_NO_WPP\": \"1\" \n                }\n            },\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            },\n            \"problemMatcher\": \"$msCompile\"\n        },\n        {\n            \"label\": \"Build Initialize (Debug64)\",\n            \"type\": \"shell\",\n            \"command\": \"${workspaceFolder}/build/build_init.cmd\",\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            },\n        },\n        {\n            \"label\": \"Build devenv [CMD] (Debug64)\",\n            \"type\": \"shell\",\n            \"command\": \"${workspaceFolder}/build/build_devenv.cmd\",\n            \"group\": { \"kind\": \"build\", }\n        },\n        \n        {\n            \"label\": \"Build prefast [CMD] (Debug64)\",\n            \"type\": \"shell\",\n            \"command\": \"${workspaceFolder}/build/build_zdriver.cmd\",\n            \"args\": [\n                \"debug\",\n                \"rebuild\",\n                \"prefast\"\n            ],\n            \"options\": { \n                \"env\": { \n                    \"KSI_NO_WPP\": \"1\" \n                }\n            },\n            \"group\": {\n                \"kind\": \"build\",\n            }\n        }\n    ]\n}"
  },
  {
    "path": ".vsconfig",
    "content": "{\n  \"version\": \"1.0\",\n  \"components\": [\n    \"Microsoft.Component.MSBuild\",\n    \"Microsoft.VisualStudio.Component.Git\",\n    \"Microsoft.VisualStudio.Component.VC.Redist.14.Latest\",\n    \"Microsoft.VisualStudio.Component.VC.Tools.x86.x64\",\n    \"Microsoft.VisualStudio.Component.VC.Tools.ARM64\",\n    \"Microsoft.VisualStudio.Component.VC.Runtimes.x86.x64.Spectre\",\n    \"Microsoft.VisualStudio.Component.VC.Runtimes.ARM64.Spectre\",\n    \"Microsoft.VisualStudio.Component.NuGet.BuildTools\",\n    \"Microsoft.VisualStudio.Workload.NativeDesktop\"\n  ],\n  \"extensions\": []\n}"
  },
  {
    "path": "CHANGELOG.txt",
    "content": "Process Hacker\n\n3.0\n * HIGHLIGHTS:\n   * New Process Hacker setup.\n   * New process properties handle search.\n   * Added F11 hotkey for fullscreen System Information window.\n * OTHER CHANGES:\n* Updated Updater plugin:\n     * New design and layout.\n* Updated WindowExplorer plugin:\n     * Added Windows process properties page.\n * NOTE:\n   * Support for Windows XP and Vista has been dropped. For those platforms, use Process Hacker 2.38.\n   * This release has significant internal code changes. Please make sure all plugins are up-to-date.\n\n2.39\n * HIGHLIGHTS:\n   * Improved compatibility with security and anti-cheat software\n   * Added ability to edit process environment variables\n   * Fixed .NET process detection\n * OTHER CHANGES:\n   * Improved tooltip information for dllhost.exe\n   * Removed Terminator\n   * Updated DotNetTools plugin:\n     * Fixed .NET assembly tab performance issues\n     * Added extra .NET memory counters to the .NET performance tab\n     * Added \"Show sizes in bytes\" checkbox to the .NET performance tab\n     * Added right-click menu to the .NET assembly tab\n   * Updated ExtendedTools plugin:\n     * Fixed \"No process\" disk event bug\n   * Updated HardwareDevices plugin:\n     * Fixed incorrect drive letters\n     * Fixed drive letter and panel clipping issue\n\n2.38\n * HIGHLIGHTS:\n   * Added labels to indicate the maximum data point in each I/O graph\n   * Graph grids now scale correctly when resized\n   * Improved high DPI scaling\n   * Added exploit mitigation policy information to process properties (Windows 8 and above)\n   * Added File modified time and File size columns for processes and modules\n   * Added Key modified time column for services\n   * Clicking a tray icon now shows the pop-up UI (useful for touch-enabled devices)\n   * The NetAdapters plugin has been renamed to HardwareDevices\n     * This plugin shows network adapter and disk drive graphs\n     * If you are manually upgrading, please delete NetAdapters.dll from the plugins folder\n   * Updated UserNotes plugin:\n     * Added \"Collapse by default\" option for processes\n * OTHER CHANGES:\n   * Added \"Start when I log on\" option\n   * Added \"Not responding\" text to tray icon rich pop-up for programs that are hung\n   * Added right-click menu and double-click action for environment variables\n   * Added dialog box to show long command line strings\n   * Added Time stamp column for processes\n   * Added -sysinfo command line parameter for opening System Information at startup\n   * Added 32x32 icons for high DPI displays\n   * Digital signature verification is now performed with very low I/O priority\n   * Improved performance when handling a large number of threads, modules or handles\n   * The pop-up UI no longer displays when double-clicking the tray icon\n   * Fixed ASLR state being shown as N/A in process properties\n   * Fixed multi monitor window placement bug\n   * Fixed handle enumeration bug affecting processes with PID >= 65536\n   * Fixed Interrupts being missing from the max CPU usage history\n   * Updated ToolStatus plugin:\n     * Added 32x32 icons for high DPI displays\n     * Fixed status bar crash\n * NOTE:\n   * This release has significant internal code changes. Please make sure all plugins are up-to-date.\n\n2.37\n * HIGHLIGHTS:\n   * Updated for Windows 10\n   * The \"Include CPU (and other) usage of children in collapsed processes\" option now aggregates memory and I/O statistics\n   * Added regex search to \"Find Handles or DLLs\"\n   * Added process exit codes to log\n   * Fixed crash that occurred under some conditions when processes terminated\n * OTHER CHANGES:\n   * Added warning when trying to search for handles when the system has too many handles open\n   * Upgraded to PCRE2\n   * Updated DotNetTools plugin:\n     * Rewrite of .NET Performance statistics and AppDomain enumeration\n   * Updated OnlineChecks plugin:\n     * Fixed virusscan.jotti.org uploader\n   * Updated NetAdapters plugin:\n     * Added adapter details window\n   * Updated ToolStatus plugin:\n     * Added CPU, Memory and I/O graphs to the toolbar (not enabled by default)\n     * Added toolbar and status bar customization, as well as a new theme\n     * Added option to auto-hide the main menu\n   * Updated UserNotes plugin:\n     * Added individual process highlighting support\n\n2.36\n * HIGHLIGHTS:\n   * New rich pop-up UI when hovering the cursor over a tray icon, showing the most active processes\n   * Completely new Memory tab for processes, with heap, stack and working set usage\n   * Process Hacker now takes 32-bit dumps of 32-bit processes on 64-bit Windows\n     * NOTE: When using the portable (.zip) release, the entire archive must be extracted\n   * Updated DotNetTools plugin:\n     * Process Hacker now displays managed stack traces for 32-bit .NET processes on 64-bit Windows\n     * Fixed inaccurate stack traces when clicking Refresh\n     * Added AppDomain column for threads in .NET programs\n * OTHER CHANGES:\n   * Added customizable bytes per row setting for memory editor\n   * Dramatically faster handle listing and search when running without administrative privileges\n   * Improved accuracy and speed of symbol resolution, especially when new modules are loaded\n   * Added trigger and delayed start information to service list\n   * Added file information to service list tooltips\n   * Balloon tips for process/service notifications are now clickable\n   * Added handle names for unnamed File objects\n   * Added I/O Priority to tray icon process menu\n   * Added warning for users who attempt to start the 32-bit version on 64-bit Windows\n   * Updated ExtendedServices plugin:\n     * Added service protection and SID information\n     * Added auto-elevation when saving recovery information, triggers and other service settings\n   * Updated ExtendedTools plugin:\n     * Added tray icon mini info window support\n     * Improved automatic GPU node selection\n   * Updated UserNotes plugin:\n     * Added tray icon mini info window support\n   * Fixed a bug in phsvc that caused hangs when automatically elevating actions\n   * Fixed hang when viewing handle security for certain File objects\n   * Fixed lack of information on startup when using slower refresh intervals\n   * Fixed Read/Write Address crash\n   * Fixed service non-polling mode on Windows 8 and above\n   * Fixed file dialog crash in Windows PE environments\n   * Fixed string scanning false positive case\n   * Fixed process window detection for Modern UI apps\n   * Fixed handle list selection bug when disabling \"Hide unnamed handles\"\n * NOTE:\n   * This release has significant internal code changes. Please make sure all plugins are up-to-date.\n\n2.35\n * NEW/IMPROVED:\n   * Added Load Time and Load Reason columns for modules (Windows 8 and above)\n   * Added handle names for Job and Section objects\n   * Added Read/Write Memory for Section objects (in process Handles tab)\n   * Added CF Guard (Control Flow Guard) column for processes and modules\n   * Added highlighting for AppContainer DLLs\n   * Added AppContainer and CF Guard image characteristics to peview\n   * Added Open Key and Open File Location menu items for services\n   * Set priority and I/O priority for multiple processes at once\n   * Support for up to 64 processors when setting process/thread affinity\n   * Updated ExtendedTools plugin:\n     * Added Disk and Network graphs for all processes\n   * Updated UserNotes plugin:\n     * Added ability to save I/O priority\n * FIXED:\n   * Fixed memory editor copy bug\n\n2.34\n * NEW/IMPROVED:\n   * Proper Unicode support\n   * CPU and GPU graphs are displayed in a grid now (thanks pavel_kv!)\n   * Start Task Manager now elevates when necessary\n   * Better names for memory regions in Memory tab (for PEBs, TEBs, thread stacks)\n   * Added tooltip information for user-mode driver framework (UMDF) host processes\n   * Added option to reduce row height (set ThinRows to 1 in settings.xml)\n   * Added NetAdapters plugin: adds graphs for selected network adapters to the System Information window\n   * Updated ExtendedTools plugin:\n     * Added GPU graphs for all processes\n     * Can now use the search box in the Disk tab\n     * Improved kernel logger handling\n * FIXED:\n   * Fixed touch scrolling\n   * Fixed EtwRegistration object names for 64-bit Windows 8.1\n   * Fixed tray icons being clipped in high DPI environments\n   * Fixed crash in memory editor\n   * Fixed multi monitor window placement bug\n\n2.33\n * NEW/IMPROVED:\n   * View digital signature information from process properties and peview\n   * Signatures for Windows 8 apps are now detected\n   * Improved file, key, process and thread handle properties\n   * Added DPI Awareness column\n   * Added new Windows 8.1 process protection information\n   * KProcessHacker is no longer needed for highlighting of GUI threads\n   * Added suspend count for threads on Windows 8.1\n   * Updated DotNetTools plugin:\n     * Improved .NET assembly enumeration timeout handling\n * FIXED:\n   * Service start type and error control are never updated if modified outside of Process Hacker\n\n2.32\n * NOTE:\n   * All executable files are now signed.\n * NEW/IMPROVED:\n   * Updated for Windows 8.1\n   * Added progress display for thread stacks\n   * Updated ExtendedServices plugin:\n     * Added new trigger data types\n   * Updated NetworkTools plugin:\n     * Updated UI\n   * Updated OnlineChecks plugin:\n     * Added file analyzed prompt\n * FIXED:\n   * Fixed handling of long symbol names\n   * Fixed Run As preventing Windows 8 apps from starting\n   * Fixed console host information for Windows 8.1\n   * Fixed reflected processes not terminating on Windows 8.1\n   * Fixed CPU frequency on Windows 8.1\n\n2.31\n * NEW/IMPROVED:\n   * Updated ExtendedServices plugin:\n     * Fixed some bugs relating to Windows 8\n   * Updated OnlineChecks plugin:\n     * Added upload progress\n   * Updated UserNotes plugin:\n     * Fixed bug where process priorities were not actually saved\n * FIXED:\n   * Fixed module list not updating properly\n   * DLL enumeration crash\n\n2.30\n * NEW/IMPROVED:\n   * Added \"Icon click toggles visibility\" option\n   * Re-enabled powerful process termination on 32-bit Windows 8\n   * Updated UserNotes plugin:\n     * Added ability to save process priority\n     * Added \"Only for processes with the same command line\" option for process comments\n * FIXED:\n   * Fixed crash on CPUs without SSE2\n\n2.29\n * NEW/IMPROVED:\n   * Added App ID column for processes\n   * Added new ASLR information for Windows 8\n   * Added Restart to Boot Options and Hybrid Shutdown menu items for Windows 8\n   * Added ability to specify processes by their names and inject and unload DLLs in command line\n   * Removed 512 character limit when copying text\n   * Moved Terminator to Miscellaneous menu\n   * Updated default dbghelp.dll path for Windows SDK v8\n   * Updated ExtendedServices plugin:\n     * Added new triggers for Windows 8\n     * Fixed bug when restarting services\n   * Updated ExtendedTools plugin:\n     * Improved support for multiple GPUs (again)\n     * GPU column now respects \"Include CPU usage of children\" option\n   * Updated ToolStatus plugin:\n     * Fixed search box fonts\n     * Fixed controls not being properly hidden/removed from the window when disabled\n   * Updated WindowExplorer plugin:\n     * Fixed window list not displaying Modern UI windows\n * FIXED:\n   * Fixed Load Count column sorting bug\n   * Fixed signature verification on Windows 8\n   * Fixed task scheduler information on Windows 8\n   * Fixed drag bug in tree list\n   * Fixed KProcessHacker bug affecting TmTx objects\n   * Fixed Run As feature on Windows 8\n   * Fixed bug where -settings parameter is not propagated\n   * Fixed tab key behavior on main window\n   * Fixed recognition of Modern UI windows\n\n2.28\n * NEW/IMPROVED:\n   * peview now resolves .lnk targets\n   * Fixed Ctrl+A for processes, services and network connections and added Ctrl+A for other windows\n   * Changed confirmation prompts to select the destructive action by default\n   * Updated DotNetTools plugin:\n     * Fixed inaccurate stack traces for certain .NET programs\n   * Updated ExtendedTools plugin:\n     * Fixed network graph scaling\n   * Updated ToolStatus plugin:\n     * Added search box\n   * Updated Updater plugin\n * FIXED:\n   * Fixed Verification Status column sorting bug in module list\n   * Fixed rare System Information crash\n   * Fixed bug in opening process handles\n   * Fixed freezing when viewing stack traces of certain system threads\n\n2.27\n * NEW/IMPROVED:\n   * Updated OnlineChecks plugin:\n     * 2012-01-16: Updated VirusTotal uploader and added hash checking\n * FIXED:\n   * Fixed Description column sorting bug\n   * Fixed notification icon bug\n\n2.26\n * NEW/IMPROVED:\n   * Added option to show Commit Charge in system information summary view\n   * Added -priority and -selectpid command line options\n   * Updated ExtendedTools plugin:\n     * Improved support for multiple GPUs\n * FIXED:\n   * Fixed 100% CPU when starting on some machines\n\n2.25\n * NEW/IMPROVED:\n   * Improved CPU frequency calculation\n   * Updated ExtendedTools plugin:\n     * Added GPU node selection\n     * Fixed incorrect GPU usage calculation\n * FIXED:\n   * Graph tooltip position with large cursors\n   * Fixed .NET process detection\n   * Fixed incorrect values in Bits column\n\n2.24\n * NOTE:\n   * This release has significant internal code changes. Please make sure all plugins are up-to-date.\n * NEW/IMPROVED:\n   * Completely new system information window\n   * Added option to scroll to new processes\n   * Added option to hide driver services\n   * Added menu item to copy individual cells\n   * Improved module scanning\n   * Added Start Task Manager menu item\n   * Added Image base to peview\n   * Updated ExtendedTools plugin:\n     * Added support for new system information window\n     * Added Disk, Network and GPU tray icons\n     * Added support for custom fonts in the Disk tab\n   * Updated Updater plugin:\n     * Added download speed\n     * Added remaining time\n * FIXED:\n   * Fixed retrieval of version information for certain files\n   * Fixed driver file names on Windows XP\n   * Fixed Run As Administrator when used with complex commands\n\n2.23\n * NEW/IMPROVED:\n   * Added display of token capabilities, user/device claims and security attributes\n   * Added ability to change token integrity levels\n   * Added Description column to service list\n   * Added option to reset all settings\n   * Made grid color darker\n   * Enabled multi-selection in the hidden processes window\n   * Added UserNotes plugin\n   * Updated ExtendedNotifications plugin:\n     * Added Growl support\n   * Updated ExtendedTools plugin:\n     * Added GPU monitoring\n     * Added rate columns for disk and network I/O\n * FIXED:\n   * Fixed copying lists when plugin columns are enabled\n   * Freezing when viewing the tooltip for a process with a very long command line\n   * Disabled Hidden Processes feature on 64-bit systems\n\n2.22\n * NEW/IMPROVED:\n   * Added highlighting for metro style apps\n   * Added Package Name column\n   * Added package name to process tooltip\n   * Improved .NET process detection\n   * Updated OS Context column for Windows 8\n   * Updated ExtendedTools plugin:\n     * Updated disk monitoring for Windows 8\n     * Updated memory list information for Windows 8\n   * Updated WindowExplorer plugin:\n     * Fixed hook support for low integrity processes\n * FIXED:\n   * Fixed memory leaks\n   * Fixed bug preventing Interrupts/DPCs from being shown as the max. CPU process on 64-bit systems\n   * Fixed DEP Status column on 64-bit systems\n\n2.21\n * NEW/IMPROVED:\n   * Added Private Bytes Delta, ASLR and Subsystem columns\n   * Added ASLR and Time Stamp columns to modules list\n   * Added check for debugger in Terminator\n * FIXED:\n   * Fixed Show CPU Below 0.01 not respecting locale\n   * Fixed copying from network list\n\n2.20\n * NEW/IMPROVED:\n   * Added support for managed thread stacks on x64\n   * Added column selection for handle list\n   * Added CPU column to threads list\n   * Improved module detection\n   * Added Ideal Processor to Threads tab\n   * Added pool usage and minimum/maximum working set columns\n   * Implemented Properties button for Thread handles\n   * Set descending sort as the default for most numeric columns\n   * Extended header context menu\n   * Removed tooltip text truncation\n   * Improved cycle-based CPU usage calculation\n   * Set default KProcessHacker security level to only allow connections when Process Hacker is running as administrator.\n     See README.txt for instructions on how to restore the old behavior.\n   * Added Updater plugin\n   * Updated DotNetTools plugin:\n     * Added managed symbol resolution for thread stacks\n   * Updated ExtendedTools plugin:\n     * Added Disk tab\n     * Added Hard Faults, Hard Faults Delta and Peak Threads columns to process tree list\n     * Added Firewall Status column\n * FIXED:\n   * Fixed file name resolution bug\n   * Save settings on shutdown/logoff\n   * Fixed state highlighting bug\n   * Fixed command line propagation for -elevate\n   * Fixed tree list mouse wheel handling\n   * Fixed saving network list\n\n2.19\n * NEW/IMPROVED:\n   * Added cycle-based CPU usage for Windows 7\n   * Added Show CPU Below 0.01\n   * Added OS Context column\n   * Rewrote graph drawing code for improved performance\n   * Optimized retrieval of cycle time and private working set information for Windows 7\n   * Added Open File Location to process context menu and reorganized some items\n   * Added checkboxes to Terminator\n * FIXED:\n   * Crash when sorting by Time Stamp\n   * GDI handle leak in drag selection\n\n2.18\n * NEW/IMPROVED:\n   * Completely rewritten tree list control:\n     * Process Name column is now fixed to the left\n     * Tooltips for column headers\n     * Improved performance\n     * Bug fixes\n   * Added more process tree list columns\n   * Added Time stamp column to network list\n   * Date/time display is now swapped (so time is shown before date)\n   * Added W3 terminator test\n   * Added DotNetTools plugin\n   * Updated ExtendedServices plugin:\n     * Disabled editing of required privileges for drivers\n   * Updated ExtendedTools plugin:\n     * Added ETW columns for processes and network connections\n   * Updated OnlineChecks plugin:\n     * Added Comodo Instant Malware Analysis\n   * Updated WindowExplorer plugin:\n     * Fixed hook bugs\n * FIXED:\n   * Fixed Run As This User\n   * Verification Status sorting\n\n2.17\n * NEW/IMPROVED:\n   * Added support for setting page priority\n   * Added elevation support for setting priority\n   * Added support for automatically using a settings file in the program directory (e.g. ProcessHacker.exe.settings.xml)\n   * Improved Run As mechanism\n   * Updated ExtendedServices plugin:\n     * Added support for editing triggers\n     * Added support for editing preshutdown time-out\n     * Added support for editing required privileges\n     * Added elevation support for restarting services\n   * Updated WindowExplorer plugin:\n     * Added more window properties\n * FIXED:\n   * Handle leak\n\n2.16\n * NEW/IMPROVED:\n   * Updated WindowExplorer plugin\n   * PE viewer: Added version string to CLR tab\n   * PE viewer: Added display of delay imports\n   * PE viewer: Added Load Config tab\n   * Improved wait analysis\n   * Added arrows to the service list to indicate whether a service is running\n * FIXED:\n   * Fixed the IPv6-related workaround causing crashes\n   * Incorrect handling of window positions\n\n2.15\n * NEW/IMPROVED:\n   * Updated ExtendedServices plugin\n   * Updated ToolStatus plugin\n   * Added DEP Status column\n   * Improved User Name column\n * FIXED:\n   * Image file versions\n   * Workaround for an IPv6-related bug in Windows XP\n   * DPCs and Interrupts in System Information tooltips\n   * File dialog crash on Windows XP\n   * ExtendedTools plugin: WS Watch refresh bug\n\n2.14\n * NEW/IMPROVED:\n   * ExtendedServices plugin: Option to add a Services menu for processes\n   * Command line support for setting process priority and I/O priority\n   * Improved termination of explorer.exe\n * FIXED:\n   * Icon should restore the main window if it is minimized\n   * System Information window crashes\n   * Hide Processes From Other Users and Hide Signed Processes settings are now saved\n   * Font selection on Windows XP\n   * ToolStatus plugin: Always on Top status being reset by Find Window\n   * Service-related crashes\n   * WindowExplorer plugin: sorting in tree list\n   * Process minidump creation with old versions of dbghelp.dll\n\n2.13\n * NEW/IMPROVED:\n   * Added copy support to PE viewer\n   * Added Connect Time, Disconnect Time and Last Input Time to session properties\n   * Added more working set counters to the Statistics tab\n * FIXED:\n   * Column sort arrows\n   * CPU usage calculations\n\n2.12\n * NEW/IMPROVED:\n   * Updated KProcessHacker for Windows 7 SP1\n   * Added elevation support for more actions\n   * Added ability to disable plugins\n   * Updated ToolStatus plugin\n   * Added Remote Control for sessions\n   * More command line options\n * FIXED:\n   * Memory leaks\n   * Run As issues with different sessions\n\n2.11\n * NEW/IMPROVED:\n   * Added WS Watch and other features to ExtendedTools plugin\n   * Added WindowExplorer plugin\n   * Properties for hidden processes\n   * Improved menus\n   * Debug console can now be closed without affecting the entire program\n * FIXED:\n   * Always on Top issues\n   * Hang when setting DEP status of a terminating process\n   * Encoding bug in NetworkTools plugin\n   * LSA interfacing issues\n   * Creating dumps of self\n\n2.10\n * NEW/IMPROVED:\n   * KProcessHacker is now signed, so it works on 64-bit systems. Thank you to the ReactOS Foundation.\n   * Added Run As Limited User\n   * Added CPU, private bytes and I/O history columns\n   * Added font selection\n   * Slightly improved highlighting configuration\n * FIXED:\n   * High DPI support\n   * Multi-monitor support in graph tooltips\n   * DEP status retrieval\n   * ExtendedTools plugin crash\n   * Notification icon menu crash\n   * Memory leaks\n   * Other small bug fixes\n\n2.9\n * NEW/IMPROVED:\n   * Added column selection for modules list\n   * Added wait analysis for 64-bit systems\n   * Added signature verification for modules\n   * Added ExtendedTools plugin (Vista and above only) with Disk and Network information\n   * Updated ExtendedNotifications plugin: added ability to log events to a file\n   * Updated ExtendedServices plugin: new tab on Vista and above\n   * Updated ToolStatus plugin: resolves ghost windows to hung windows\n   * Environment variables and current directory are now correctly shown for WOW64 processes\n   * I/O priority names are now used instead of numbers\n * FIXED:\n   * Network list bug\n   * Memory leaks\n\n2.8\n * NEW/IMPROVED:\n   * Better service list (including column selection)\n   * Added Peak Handles\n   * Process tree sorting is now preserved\n   * Save works for services and network connections\n   * Pausing now works correctly with the Network tab\n   * Added option to display inclusive CPU usages for collapsed processes\n   * Added CLR tab to peview\n   * Added ability to destroy heaps\n   * Improved process tree list appearance\n   * Certain command line parameters are now propagated\n * FIXED:\n   * Icon handling bugs\n   * Memory leaks\n   * Extended tooltips for WOW64 processes\n\n2.7\n * NEW/IMPROVED:\n   * Vastly improved startup time and lower memory usage\n   * Added Cycles and Cycles Delta columns\n   * Added option to disable address resolution for network connections\n   * Added Logon Time to session properties\n   * Added time stamp display to peview\n * FIXED:\n   * ToolStatus layout problems\n   * .NET highlighting crashes\n   * Run As on Windows XP\n\n2.6\n * NEW/IMPROVED:\n   * Sorting for most lists is now much faster\n   * Hide Signed Processes option\n   * Added plugin for uploading files to online virus scanners\n   * Added Network tools plugin\n   * Updated ExtendedServices plugin\n   * PE viewer now verifies checksums\n   * Performance improvements\n * FIXED:\n   * Fixed service handle leak\n\n2.5\n * NEW/IMPROVED:\n   * Unmap section views in Memory tab\n   * Plugin for extended service information (including recovery information, dependencies and dependents)\n * FIXED:\n   * Critical bug for file dialogs on Windows XP\n   * Esc couldn't close Service Properties on open\n   * Small bug fixes\n\n2.4\n * NEW/IMPROVED:\n   * Better Run As behaviour\n   * Show Processes From All Users option\n   * Can now unmap section views\n   * Control over thread affinity\n   * Window Title and Window Status columns\n   * Plugin for filtering notifications\n   * Plugin for toolbar and status bar\n   * Performance improvements\n * FIXED:\n   * Memory leak\n   * SbieSupport plugin on 64-bit\n   * Crash when running under certain conditions\n   * Memory case-insensitive filter\n   * Process parent association bug\n * REMOVED:\n   * Process database\n\n2.3\n * NEW/IMPROVED:\n   * Can add processes to jobs\n   * Double-clicking in the system information graphs now opens information for the relevant process\n   * Setting I/O priority doesn't need KProcessHacker anymore\n   * Elevation for certain actions\n * FIXED:\n   * HKCU key name resolution\n   * Network connection host resolution\n   * Information window resizing\n   * Log clearing\n\n2.2\n * NEW/IMPROVED:\n   * Plugins support\n   * Can now unload 32-bit modules on 64-bit systems\n   * Tasks are shown in tooltips for taskeng.exe/taskhost.exe processes\n   * Run As can now start processes elevated\n   * Handle count by type\n   * Process priorities in notification icon menu\n   * CSV export\n   * Relative start times\n * FIXED:\n   * Run and Run As shortcuts\n   * Command line handling\n   * Process tree selection\n\n2.1\n * NEW/IMPROVED:\n   * Add Pause key shortcut to pause/resume updates\n   * Added Ctrl+Tab and Ctrl+Shift+Tab shortcuts\n   * Grid is a bit darker\n   * Checks for digital signatures and packing is now off by default and optional\n * FIXED:\n   * MD5 calculation code for files was wrong\n   * Process record bugs\n\n2.0\n * First release in the Process Hacker 2.x branch.\n"
  },
  {
    "path": "CLA.md",
    "content": "# Contribution License Agreement\n\nThis Contribution License Agreement (“Agreement”) is agreed to by the party signing (“You”), \nand conveys certain license rights to Winsider Seminars & Solutions, Inc. and its affiliates \n(“Winsiderss”) for Your contributions to Winsider Seminars & Solutions, Inc. open source projects. \nThis Agreement is effective as of the latest signature date.\n\n1. **Definitions**. “**Code**” means the computer software code, whether in human-readable or\nmachine-executable form, that is delivered by You to Winsider Seminars & Solutions, Inc. under \nthis Agreement. “**Project**” means the System Informer project owned or managed by Winsider \nSeminars & Solutions, Inc. and offered under the terms of the following license(s) MIT (including \nany right to adopt any future version of a license if permitted). “**Submit**” is the act of \nuploading, submitting, transmitting, or distributing code or other content to any Project, \nincluding but not limited to communication on electronic mailing lists, source code control \nsystems, and issue tracking systems that are managed by, or on behalf of, the Project for the \npurpose of discussing and improving that Project, but excluding communication that is conspicuously \nmarked or otherwise designated in writing by You as “Not a Submission.” “**Submission**” means the \nCode and any other copyrightable material Submitted by You, including any associated comments and \ndocumentation.\n\n2. **Your Submission**. You must agree to the terms of this Agreement before making a Submission\nto any Project. This Agreement covers any and all Submissions that You, now or in the future\n(except as described in Section 4 below), Submit to any Project.\n\n3. **Originality of Work**. You represent that each of Your Submissions is entirely Your original \nwork. Should You wish to Submit materials that are not Your original work, You may Submit them \nseparately to the Project if You (a) retain all copyright and license information that was in the \nmaterials as You received them, (b) in the description accompanying Your Submission, include the \nphrase “Submission containing materials of a third party:” followed by the names of the third \nparty and any licenses or other restrictions of which You are aware, and (c) follow any other \ninstructions in the Project’s written guidelines concerning Submissions.\n\n4. **Your Employer**. References to “employer” in this Agreement include Your employer or anyone \nelse for whom You are acting in making Your Submission, e.g. as a contractor, vendor, or agent. \nIf Your Submission is made in the course of Your work for an employer or Your employer has \nintellectual property rights in Your Submission by contract or applicable law, You must secure \npermission from Your employer to make the Submission before signing this Agreement. In that case, \nthe term “You” in this Agreement will refer to You and the employer collectively. If You change \nemployers in the future and desire to Submit additional Submissions for the new employer, then \nYou agree to sign a new Agreement and secure permission from the new employer before Submitting \nthose Submissions.\n\n5. **Licenses**.\n\n    - **Copyright License**. You grant Winsider Seminars & Solutions, Inc., and those who receive \n    the Submission directly or indirectly from Winsider Seminars & Solutions, Inc., a perpetual, \n    worldwide, non-exclusive, royalty-free, irrevocable license in the Submission to reproduce, \n    prepare derivative works of, publicly display, publicly perform, and distribute the Submission \n    and such derivative works, and to sublicense any or all of the foregoing rights to third parties.\n\n    - **Patent License**. You grant Winsider Seminars & Solutions, Inc., and those who receive the \n    Submission directly or indirectly from Winsider Seminars & Solutions, Inc., a perpetual, \n    worldwide, non-exclusive, royalty-free, irrevocable license under Your patent claims that are \n    necessarily infringed by the Submission or the combination of the Submission with the Project \n    to which it was Submitted to make, have made, use, offer to sell, sell and import or otherwise \n    dispose of the Submission alone or with the Project.\n\n    - **Other Rights Reserved**. Each party reserves all rights not expressly granted in this\n    Agreement. No additional licenses or rights whatsoever (including, without limitation, any\n    implied licenses) are granted by implication, exhaustion, estoppel or otherwise.\n    \n6. **Representations and Warranties**. You represent that You are legally entitled to grant the \nabove licenses. You represent that each of Your Submissions is entirely Your original work (except\nas You may have disclosed under Section 3). You represent that You have secured permission from \nYour employer to make the Submission in cases where Your Submission is made in the course of Your \nwork for Your employer or Your employer has intellectual property rights in Your Submission by \ncontract or applicable law. If You are signing this Agreement on behalf of Your employer, You \nrepresent and warrant that You have the necessary authority to bind the listed employer to the \nobligations contained in this Agreement.  You are not expected to provide support for Your \nSubmission, unless You choose to do so. UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, \nAND EXCEPT FOR THE WARRANTIES EXPRESSLY STATED IN SECTIONS 3, 4, AND 6, THE SUBMISSION PROVIDED \nUNDER THIS AGREEMENT IS PROVIDED WITHOUT WARRANTY OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, ANY \nWARRANTY OF NONINFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.\n\n7. **Notice to Winsider Seminars & Solutions, Inc.**. You agree to notify Winsider Seminars & \nSolutions, Inc. in writing of any facts or circumstances of which You later become aware that would \nmake Your representations in this Agreement inaccurate in any respect.\n\n8. **Information about Submissions**. You agree that contributions to Projects and information\nabout contributions may be maintained indefinitely and disclosed publicly, including Your name \nand other information that You submit with Your Submission.\n\n9. **Governing Law/Jurisdiction**. This Agreement and all disputes, claims, actions, suits or \nother proceedings arising out of this agreement or relating in any way to it shall be governed by \nthe laws of Quebec, Canada excluding its private international law provisions. \n\n10. **Entire Agreement/Assignment**. This Agreement is the entire agreement between the parties,\nand supersedes any and all prior agreements, understandings or communications, written or oral, \nbetween the parties relating to the subject matter hereof. This Agreement may be assigned by \nWinsider Seminars & Solutions, Inc.."
  },
  {
    "path": "CMakeLists.txt",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\ncmake_minimum_required(VERSION 3.30.0 FATAL_ERROR)\n\nproject(SystemInformer)\n\nset(SI_ROOT ${CMAKE_CURRENT_SOURCE_DIR})\nlist(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)\ninclude(commands)\n\nset(CMAKE_CONFIGURATION_TYPES \"Debug;Release\" CACHE STRING \"\" FORCE)\n# TODO change this to bin once we fully transition to cmake\n# set up to allow user to disable with \"\" or \"OFF\"\nset(SI_OUTPUT_DIR \"${SI_ROOT}/bin-cmake\" CACHE PATH \"Output directory\")\n\noption(SI_WITH_CORE          \"Configure core projects\"          ON)\noption(SI_WITH_PLUGINS       \"Configure plugin projects\"        OFF)\noption(SI_WITH_KERNEL        \"Configure kernel projects\"        OFF)\noption(SI_WITH_PREFAST       \"Enables prefast analysis\"         OFF)\noption(SI_WITH_WPP_USER      \"Enables user mode WPP trace\"      OFF)\noption(SI_WITH_WPP_KERNEL    \"Enables kernel mode WPP trace\"    ON)\n\nif (MSVC_NOT_CLANG AND CMAKE_BUILD_TYPE STREQUAL \"Release\")\n    add_compile_options(/d1trimfile:${SI_ROOT})\nendif()\n\nif(SI_WITH_CORE)\n    add_subdirectory(SystemInformer)\n    add_subdirectory(phnt)\n    add_subdirectory(phlib)\n    add_subdirectory(tools)\nendif()\n\nif(SI_WITH_KERNEL)\n    message(FATAL_ERROR \"Kernel mode projects are not supported\")\n    add_subdirectory(KSystemInformer)\nendif()\n\nif(SI_WITH_PLUGINS)\n    add_subdirectory(plugins)\nendif()\n\nif(SI_WITH_CORE OR SI_WITH_KERNEL)\n    add_subdirectory(kphlib)\nendif()\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at dmex04@gmail.com and johnny.shaw@live.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribution Guidelines\n"
  },
  {
    "path": "COPYRIGHT.txt",
    "content": "== System Informer ==\nSystem Informer is licensed. A full copy of the license is provided in LICENSE.txt.\n\n    Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n\n== Mini-XML ==\nSystem Informer uses Mini-XML licensed under the following terms:\n\n    The Mini-XML library and included programs are provided under the\n    terms of the GNU Library General Public License (LGPL) with the\n    following exceptions:\n\n        1. Static linking of applications to the Mini-XML library\n           does not constitute a derivative work and does not require\n           the author to provide source code for the application, use\n           the shared Mini-XML libraries, or link their applications\n           against a user-supplied version of Mini-XML.\n\n           If you link the application to a modified version of\n           Mini-XML, then the changes to Mini-XML must be provided\n           under the terms of the LGPL in sections 1, 2, and 4.\n\n        2. You do not have to provide a copy of the Mini-XML license\n           with programs that are linked to the Mini-XML library, nor\n           do you have to identify the Mini-XML license in your\n           program or documentation as required by section 6 of the\n           LGPL.\n\n== PCRE ==\nSystem Informer uses Perl-Compatible Regular Expressions licensed under the\nfollowing terms:\n\n    PCRE is a library of functions to support regular expressions whose syntax\n    and semantics are as close as possible to those of the Perl 5 language.\n\n    Release 8 of PCRE is distributed under the terms of the \"BSD\" licence, as\n    specified below.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are met:\n\n        * Redistributions of source code must retain the above copyright notice,\n          this list of conditions and the following disclaimer.\n\n        * Redistributions in binary form must reproduce the above copyright\n          notice, this list of conditions and the following disclaimer in the\n          documentation and/or other materials provided with the distribution.\n\n        * Neither the name of the University of Cambridge nor the name of Google\n          Inc. nor the names of their contributors may be used to endorse or\n          promote products derived from this software without specific prior\n          written permission.\n\n    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n\n== MD5 ==\nSystem Informer uses a MD5 implementation licensed under the following terms:\n\n    MD5 hash implementation and interface functions\n    Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License version 2 as\n    published by the Free Software Foundation.\n\n== SHA ==\nSystem Informer uses a SHA implementation licensed under the following terms:\n\n    Copyright 2004 Filip Navara\n    Based on public domain SHA code by Steve Reid <steve@edmweb.com>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Lesser General Public\n    License as published by the Free Software Foundation; either\n    version 2.1 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\n\n== Natural order string comparison ==\nSystem Informer uses \"strnatcmp.c\" licensed under the following terms:\n\n    strnatcmp.c -- Perform 'natural order' comparisons of strings in C.\n    Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>\n\n    This software is provided 'as-is', without any express or implied\n    warranty.  In no event will the authors be held liable for any damages\n    arising from the use of this software.\n\n    Permission is granted to anyone to use this software for any purpose,\n    including commercial applications, and to alter it and redistribute it\n    freely, subject to the following restrictions:\n\n    1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n    2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n    3. This notice may not be removed or altered from any source distribution.\n\n    This code has been modified for System Informer.\n"
  },
  {
    "path": "Common.Kernel.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup Label=\"Global\">\n    <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>\n    <DriverType>WDM</DriverType>\n    <MSBuildProjectExtensionsPath>$(ProjectDir)$(ProjectName)\\obj\\</MSBuildProjectExtensionsPath>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ResolveNuGetPackages>false</ResolveNuGetPackages>\n    <SignMode>Off</SignMode>\n    <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\">\n    <CharacterSet>Unicode</CharacterSet>\n    <Driver_SpectreMitigation>Spectre</Driver_SpectreMitigation>\n    <TargetVersion>Windows10</TargetVersion>\n    <_NT_TARGET_VERSION Condition=\"'$(Platform)'=='x64'\">0x0A00</_NT_TARGET_VERSION>\n    <_NT_TARGET_VERSION Condition=\"'$(Platform)'=='ARM64'\">0xA000004</_NT_TARGET_VERSION>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"$(Configuration)=='Debug'\" Label=\"Configuration\">\n    <LinkIncremental>true</LinkIncremental>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"$(Configuration)=='Release'\" Label=\"Configuration\">\n    <LinkIncremental>false</LinkIncremental>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup>\n    <CodeAnalysisRuleSet>$(SystemInformerRoot)\\Common.Kernel.ruleset</CodeAnalysisRuleSet>\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n    <EnableInf2cat>false</EnableInf2cat>\n  </PropertyGroup>\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(CRT_IncludePath);$(KM_IncludePath);$(KIT_SHARED_IncludePath)</AdditionalIncludeDirectories>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SystemInformerRoot)phnt\\include\\</AdditionalIncludeDirectories>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SystemInformerRoot)kphlib\\include\\</AdditionalIncludeDirectories>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)include\\</AdditionalIncludeDirectories>\n      <AdditionalOptions>/kernel /utf-8 /INTEGRITYCHECK /d1nodatetime %(AdditionalOptions)</AdditionalOptions>\n      <AdditionalOptions Condition=\"'$(Platform)'=='x64'\">/d2guardretpoline %(AdditionalOptions)</AdditionalOptions>\n      <CallingConvention>StdCall</CallingConvention>\n      <ConformanceMode>true</ConformanceMode>\n      <ControlFlowGuard>Guard</ControlFlowGuard>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <DisableSpecificWarnings>4201</DisableSpecificWarnings>\n      <GuardEHContMetadata>true</GuardEHContMetadata>\n      <GuardSignedReturns Condition=\"'$(Platform)'=='ARM64'\">true</GuardSignedReturns>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <LanguageStandard_C>stdc17</LanguageStandard_C>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <PreprocessorDefinitions>POOL_NX_OPTIN;POOL_ZERO_DOWN_LEVEL_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions>_WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Platform)'=='x64'\">_AMD64_;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Platform)'=='ARM64'\">_ARM64_;ARM64;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)'=='DEBUG'\">_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <StringPooling>true</StringPooling>\n      <UseStandardPreprocessor>true</UseStandardPreprocessor>\n      <WarningLevel>Level4</WarningLevel>\n    </ClCompile>\n    <ClCompile Condition=\"'$(Configuration)'=='Release'\">\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <Optimization>MaxSpeed</Optimization>\n    </ClCompile>\n    <Link>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>\n      <AdditionalOptions>/INTEGRITYCHECK /DEPENDENTLOADFLAG:0x800 /FILEALIGN:0x1000 %(AdditionalOptions)</AdditionalOptions>\n      <AdditionalOptions>/NATVIS:$(SystemInformerRoot)SystemInformer.natvis %(AdditionalOptions)</AdditionalOptions>\n      <AdditionalOptions Condition=\"'$(Platform)'=='x64'\">/guard:retpoline %(AdditionalOptions)</AdditionalOptions>\n      <AdditionalOptions Condition=\"'$(Configuration)'=='Release'\">/BREPRO /NOVCFEATURE /NOCOFFGRPINFO %(AdditionalOptions)</AdditionalOptions>\n      <CETCompat Condition=\"'$(Platform)'!='ARM64'\">true</CETCompat>\n      <LinkTimeCodeGeneration Condition=\"'$(Configuration)'=='Release'\">UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n      <RandomizedBaseAddress>true</RandomizedBaseAddress>\n      <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>\n    </Link>\n    <Lib>\n      <LinkTimeCodeGeneration Condition=\"'$(Configuration)'=='Release'\">UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n      <TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>\n      <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n    </Lib>\n    <ResourceCompile>\n      <AdditionalOptions>/c 65001 %(AdditionalOptions)</AdditionalOptions>\n    </ResourceCompile>\n  </ItemDefinitionGroup>\n  <!-- WPP Trace\n      - Set KSI_NO_WPP to disable WPP trace compile entirely.\n  -->\n  <PropertyGroup>\n    <KsiNoWpp Condition=\"'$(KSI_NO_WPP)'!=''\">true</KsiNoWpp>\n  </PropertyGroup>\n  <Target Name=\"KsiRunWpp\"\n          BeforeTargets=\"BeforeClCompile\"\n          Condition=\"'$(KsiNoWpp)'!='true'\"\n          Inputs=\"@(ClInclude);@(ClCompile)\"\n          Outputs=\"@(ClInclude->'$(IntDir)tmh\\%(Filename).tmh');@(ClCompile->'$(IntDir)tmh\\%(Filename).tmh')\">\n      <MakeDir Directories=\"$(IntDir)tmh\" Condition=\"!Exists('$(IntDir)tmh')\" />\n      <PropertyGroup>\n          <TraceWppCmd>tracewpp.exe</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -km</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -ext:.c.cpp.h.hpp</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -preserveext:.c.cpp.h.hpp</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -I\"$(WindowsSdkDir)bin\\$(TargetPlatformVersion)\\WppConfig\\Rev1\"</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -odir:\"$(IntDir)tmh\"</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -scan:\"$(SystemInformerRoot)KSystemInformer\\include\\trace.h\"</TraceWppCmd>\n      </PropertyGroup>\n      <Exec Command=\"$(TraceWppCmd) @(ClInclude->'&quot;%(FullPath)&quot;', ' ') @(ClCompile->'&quot;%(FullPath)&quot;', ' ')\"/>\n  </Target>\n  <ItemDefinitionGroup Condition=\"'$(KsiNoWpp)'!='true'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IntDir)tmh\\</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>TMH_FILE=%(FileName)%(Extension).tmh;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(KsiNoWpp)'=='true'\">\n    <ClCompile>\n      <PreprocessorDefinitions>KSI_NO_WPP;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n</Project>\n"
  },
  {
    "path": "Common.Kernel.ruleset",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RuleSet Name=\"Rules for KSystemInformer\" Description=\"Code analysis rules for KSystemInformer.\" ToolsVersion=\"17.0\">\n  <Include Path=\"AllRules.ruleset\" Action=\"Default\" />\n  <Rules AnalyzerId=\"Microsoft.Analyzers.NativeCodeAnalysis\" RuleNamespace=\"Microsoft.Rules.Native\">\n    <Rule Id=\"C6014\" Action=\"None\" />\n    <Rule Id=\"C6320\" Action=\"None\" />\n    <Rule Id=\"C6262\" Action=\"None\" />\n    <Rule Id=\"C28023\" Action=\"None\" />\n    <Rule Id=\"C28194\" Action=\"None\" />\n    <Rule Id=\"C28195\" Action=\"None\" />\n  </Rules>\n</RuleSet>"
  },
  {
    "path": "Common.User.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <!-- Global -->\n  <ItemDefinitionGroup>\n      <ClCompile>\n          <TreatWarningAsError>true</TreatWarningAsError>\n          <WarningLevel>Level3</WarningLevel>\n          <SDLCheck>true</SDLCheck>\n          <MinimalRebuild>false</MinimalRebuild>\n          <MultiProcessorCompilation>true</MultiProcessorCompilation>\n          <LanguageStandard>stdcpplatest</LanguageStandard>\n          <LanguageStandard_C>stdclatest</LanguageStandard_C>\n          <StringPooling>true</StringPooling>\n          <SupportJustMyCode>false</SupportJustMyCode>\n          <UseFullPaths>false</UseFullPaths>\n          <UseStandardPreprocessor>true</UseStandardPreprocessor>\n          <ConformanceMode>true</ConformanceMode>\n          <EnforceTypeConversionRules>true</EnforceTypeConversionRules>\n          <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>\n      </ClCompile>\n      <Link>\n          <GenerateDebugInformation>true</GenerateDebugInformation>\n          <SubSystem>Windows</SubSystem>\n          <LargeAddressAware>true</LargeAddressAware>\n      </Link>\n      <Lib>\n          <TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>\n          <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n          <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>\n      </Lib>\n      <ResourceCompile>\n          <Culture>0x0009</Culture>\n          <AdditionalOptions>/c 65001 %(AdditionalOptions)</AdditionalOptions>\n          <PreprocessorDefinitions>%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n      </ResourceCompile>\n  </ItemDefinitionGroup>\n\n  <!-- WPP Trace (optional, disabled by default)\n       - Conditional based on presence of necessary WDK parts.\n       - Set SI_WITH_WPP to enable WPP trace compile.\n  -->\n  <PropertyGroup>\n    <SiNoWpp Condition=\"'$(SI_WITH_WPP)'==''\">true</SiNoWpp>\n  </PropertyGroup>\n  <Target Name=\"SiRunWpp\"\n          BeforeTargets=\"BeforeClCompile\"\n          Condition=\"'$(SiNoWpp)'!='true' and Exists('$(WindowsSdkDir)\\bin\\$(TargetPlatformVersion)\\WppConfig\\Rev1\\')\"\n          Inputs=\"@(ClInclude);@(ClCompile)\"\n          Outputs=\"@(ClInclude->'$(IntDir)tmh\\%(Filename).tmh');@(ClCompile->'$(IntDir)tmh\\%(Filename).tmh')\">\n      <MakeDir Directories=\"$(IntDir)tmh\" Condition=\"!Exists('$(IntDir)tmh')\" />\n      <PropertyGroup>\n          <TraceWppCmd>tracewpp.exe</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -um</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -ext:.c.cpp.h.hpp</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -preserveext:.c.cpp.h.hpp</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -I\"$(WindowsSdkDir)bin\\$(TargetPlatformVersion)\\WppConfig\\Rev1\"</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -odir:\"$(IntDir)tmh\"</TraceWppCmd>\n          <TraceWppCmd>$(TraceWppCmd) -scan:\"$(SystemInformerRoot)phlib\\include\\trace.h\"</TraceWppCmd>\n      </PropertyGroup>\n      <Exec Command=\"$(TraceWppCmd) @(ClInclude->'&quot;%(FullPath)&quot;', ' ') @(ClCompile->'&quot;%(FullPath)&quot;', ' ')\"/>\n  </Target>\n  <ItemDefinitionGroup Condition=\"'$(SiNoWpp)'!='true' and Exists('$(WindowsSdkDir)\\bin\\$(TargetPlatformVersion)\\WppConfig\\Rev1\\')\">\n      <ClCompile>\n          <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IntDir)tmh\\</AdditionalIncludeDirectories>\n          <PreprocessorDefinitions>TMH_FILE=%(FileName)%(Extension).tmh;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(SiNoWpp)'=='true' or !Exists('$(WindowsSdkDir)\\bin\\$(TargetPlatformVersion)\\WppConfig\\Rev1\\')\">\n      <ClCompile>\n          <PreprocessorDefinitions>SI_NO_WPP;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      </ClCompile>\n  </ItemDefinitionGroup>\n\n  <!-- Debug Builds -->\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <CharacterSet>Unicode</CharacterSet>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <SpectreMitigation>false</SpectreMitigation>\n    <LinkIncremental>true</LinkIncremental>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <CharacterSet>Unicode</CharacterSet>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <SpectreMitigation>false</SpectreMitigation>\n    <LinkIncremental>true</LinkIncremental>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"Configuration\">\n    <CharacterSet>Unicode</CharacterSet>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <SpectreMitigation>false</SpectreMitigation>\n    <LinkIncremental>true</LinkIncremental>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <!-- Release Builds -->\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <CharacterSet>Unicode</CharacterSet>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <SpectreMitigation>Spectre</SpectreMitigation>\n    <LinkIncremental>false</LinkIncremental>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <CharacterSet>Unicode</CharacterSet>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <SpectreMitigation>Spectre</SpectreMitigation>\n    <LinkIncremental>false</LinkIncremental>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"Configuration\">\n    <CharacterSet>Unicode</CharacterSet>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <SpectreMitigation>Spectre</SpectreMitigation>\n    <LinkIncremental>false</LinkIncremental>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n\n  <!-- Debug|Win32 Builds -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n      <ClCompile>\n          <AdditionalOptions>/utf-8 /d1nodatetime %(AdditionalOptions)</AdditionalOptions>\n          <PreprocessorDefinitions>WIN32;DEBUG;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n          <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n          <EnableEnhancedInstructionSet>$(ExternalSimdOptions)</EnableEnhancedInstructionSet>\n          <Optimization>Disabled</Optimization>\n          <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n          <CallingConvention>StdCall</CallingConvention>\n          <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n          <FloatingPointModel>Precise</FloatingPointModel>\n          <FunctionLevelLinking>true</FunctionLevelLinking>\n          <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n          <WholeProgramOptimization>false</WholeProgramOptimization>\n          <IntrinsicFunctions>true</IntrinsicFunctions>\n      </ClCompile>\n      <Link>\n          <AdditionalOptions>/BREPRO /DEBUGTYPE:CV,PDATA /DEPENDENTLOADFLAG:0x800 /FILEALIGN:0x1000 /NOOPTIDATA /BASERELOCCLUSTERING /NATVIS:$(MSBuildThisFileDirectory)\\SystemInformer.natvis %(AdditionalOptions) $(ExternalLinkerOptions)</AdditionalOptions>\n          <AdditionalDependencies>invalidcontinue.obj;noarg.obj;noenv.obj;nothrownew.obj;%(AdditionalDependencies)</AdditionalDependencies>\n          <MinimumRequiredVersion>6.01</MinimumRequiredVersion>\n          <TargetMachine>MachineX86</TargetMachine>\n          <FullProgramDatabaseFile>true</FullProgramDatabaseFile>\n          <GenerateDebugInformation>true</GenerateDebugInformation>\n          <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>\n          <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n          <LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>\n      </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Debug|x64 Builds -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n      <ClCompile>\n          <AdditionalOptions>/utf-8 /d1nodatetime /d1import_no_registry /jumptablerdata %(AdditionalOptions) $(ExternalAdditionalOptions)</AdditionalOptions>\n          <PreprocessorDefinitions>WIN64;DEBUG;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n          <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n          <EnableEnhancedInstructionSet>$(ExternalSimdOptions)</EnableEnhancedInstructionSet>\n          <Optimization>Disabled</Optimization>\n          <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n          <CallingConvention>StdCall</CallingConvention>\n          <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n          <FloatingPointModel>Precise</FloatingPointModel>\n          <FunctionLevelLinking>true</FunctionLevelLinking>\n          <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n          <WholeProgramOptimization>false</WholeProgramOptimization>\n          <IntrinsicFunctions>true</IntrinsicFunctions>\n      </ClCompile>\n      <Link>\n          <AdditionalOptions>/BREPRO /DEBUGTYPE:CV,PDATA /DEPENDENTLOADFLAG:0x800 /FILEALIGN:0x1000 /NOOPTIDATA /BASERELOCCLUSTERING /NATVIS:$(MSBuildThisFileDirectory)\\SystemInformer.natvis %(AdditionalOptions) $(ExternalLinkerOptions)</AdditionalOptions>\n          <AdditionalDependencies>invalidcontinue.obj;noarg.obj;noenv.obj;nothrownew.obj;%(AdditionalDependencies)</AdditionalDependencies>\n          <MinimumRequiredVersion>6.01</MinimumRequiredVersion>\n          <TargetMachine>MachineX64</TargetMachine>\n          <FullProgramDatabaseFile>true</FullProgramDatabaseFile>\n          <GenerateDebugInformation>true</GenerateDebugInformation>\n          <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>\n          <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n          <LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>\n      </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Debug|ARM64 Builds -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\n      <ClCompile>\n          <AdditionalOptions>/utf-8 /d1nodatetime /d1import_no_registry %(AdditionalOptions)</AdditionalOptions>\n          <PreprocessorDefinitions>WIN64;DEBUG;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n          <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n          <EnableEnhancedInstructionSet>$(ExternalSimdOptions)</EnableEnhancedInstructionSet>\n          <Optimization>Disabled</Optimization>\n          <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n          <CallingConvention>StdCall</CallingConvention>\n          <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n          <FloatingPointModel>Precise</FloatingPointModel>\n          <FunctionLevelLinking>true</FunctionLevelLinking>\n          <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n          <WholeProgramOptimization>false</WholeProgramOptimization>\n          <IntrinsicFunctions>true</IntrinsicFunctions>\n          <GuardSignedReturns>true</GuardSignedReturns>\n      </ClCompile>\n      <Link>\n          <AdditionalOptions>/BREPRO /DEBUGTYPE:CV,PDATA /DEPENDENTLOADFLAG:0x800 /FILEALIGN:0x1000 /NOOPTIDATA /BASERELOCCLUSTERING /NATVIS:$(MSBuildThisFileDirectory)\\SystemInformer.natvis %(AdditionalOptions) $(ExternalLinkerOptions)</AdditionalOptions>\n          <AdditionalDependencies>invalidcontinue.obj;noarg.obj;noenv.obj;nothrownew.obj;%(AdditionalDependencies)</AdditionalDependencies>\n          <MinimumRequiredVersion>10</MinimumRequiredVersion>\n          <TargetMachine>MachineARM64</TargetMachine>\n          <FullProgramDatabaseFile>true</FullProgramDatabaseFile>\n          <GenerateDebugInformation>true</GenerateDebugInformation>\n          <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>\n          <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n          <LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>\n      </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Release|Win32 Builds -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n      <ClCompile>\n          <AdditionalOptions>/utf-8 /d1nodatetime /d1import_no_registry /d1trimfile:\"$(MSBuildThisFileDirectory)\\\" %(AdditionalOptions)</AdditionalOptions>\n          <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n          <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n          <Optimization>MaxSpeed</Optimization>\n          <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n          <CallingConvention>StdCall</CallingConvention>\n          <FloatingPointModel>Precise</FloatingPointModel>\n          <FunctionLevelLinking>true</FunctionLevelLinking>\n          <IntrinsicFunctions>true</IntrinsicFunctions>\n          <SpectreMitigation>Spectre</SpectreMitigation>\n          <IntelJCCErratum>true</IntelJCCErratum>\n          <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n          <WholeProgramOptimization>true</WholeProgramOptimization>\n          <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n          <ControlFlowGuard>Guard</ControlFlowGuard>\n      </ClCompile>\n      <Link>\n          <AdditionalOptions>/BREPRO /DEBUGTYPE:CV,PDATA /DEPENDENTLOADFLAG:0x800 /PDBALTPATH:%_PDB% /FILEALIGN:0x1000 /NOOPTIDATA /NOVCFEATURE /NOCOFFGRPINFO /BASERELOCCLUSTERING %(AdditionalOptions) $(ExternalLinkerOptions)</AdditionalOptions>\n          <AdditionalDependencies>invalidcontinue.obj;noarg.obj;noenv.obj;nothrownew.obj;%(AdditionalDependencies)</AdditionalDependencies>\n          <CETCompat>true</CETCompat>\n          <MinimumRequiredVersion>6.01</MinimumRequiredVersion>\n          <TargetMachine>MachineX86</TargetMachine>\n          <GenerateDebugInformation>true</GenerateDebugInformation>\n          <SetChecksum>true</SetChecksum>\n          <StripPrivateSymbols>$(OutDir)$(TargetName)_stripped.pdb</StripPrivateSymbols>\n          <OptimizeReferences>true</OptimizeReferences>\n          <EnableCOMDATFolding>true</EnableCOMDATFolding>\n          <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>\n          <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n          <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n      </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Release|x64 Builds -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n      <ClCompile>\n          <AdditionalOptions>/utf-8 /d1nodatetime /d1import_no_registry /guard:xfg /jumptablerdata /d1trimfile:\"$(MSBuildThisFileDirectory)\\\" %(AdditionalOptions)</AdditionalOptions>\n          <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n          <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n          <EnableEnhancedInstructionSet>$(ExternalSimdOptions)</EnableEnhancedInstructionSet>\n          <Optimization>MaxSpeed</Optimization>\n          <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n          <CallingConvention>StdCall</CallingConvention>\n          <FloatingPointModel>Precise</FloatingPointModel>\n          <FunctionLevelLinking>true</FunctionLevelLinking>\n          <IntrinsicFunctions>true</IntrinsicFunctions>\n          <SpectreMitigation>Spectre</SpectreMitigation>\n          <IntelJCCErratum>true</IntelJCCErratum>\n          <GuardEHContMetadata>true</GuardEHContMetadata>\n          <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n          <WholeProgramOptimization>true</WholeProgramOptimization>\n          <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n          <ControlFlowGuard>Guard</ControlFlowGuard>\n      </ClCompile>\n      <Link>\n          <AdditionalOptions>/BREPRO /DEBUGTYPE:CV,PDATA /DEPENDENTLOADFLAG:0x800 /PDBALTPATH:%_PDB% /FILEALIGN:0x1000 /LTCG /GUARD:XFG /NOOPTIDATA /NOVCFEATURE /NOCOFFGRPINFO /BASERELOCCLUSTERING %(AdditionalOptions) $(ExternalLinkerOptions)</AdditionalOptions>\n          <AdditionalDependencies>invalidcontinue.obj;noarg.obj;noenv.obj;nothrownew.obj;%(AdditionalDependencies)</AdditionalDependencies>\n          <CETCompat>true</CETCompat>\n          <MinimumRequiredVersion>6.01</MinimumRequiredVersion>\n          <TargetMachine>MachineX64</TargetMachine>\n          <GenerateDebugInformation>true</GenerateDebugInformation>\n          <SetChecksum>true</SetChecksum>\n          <StripPrivateSymbols>$(OutDir)$(TargetName)_stripped.pdb</StripPrivateSymbols>\n          <OptimizeReferences>true</OptimizeReferences>\n          <EnableCOMDATFolding>true</EnableCOMDATFolding>\n          <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>\n          <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n          <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n      </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Release|ARM64 Builds -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\n      <ClCompile>\n          <AdditionalOptions>/utf-8 /d1nodatetime /d1import_no_registry /d1trimfile:\"$(MSBuildThisFileDirectory)\\\" %(AdditionalOptions)</AdditionalOptions>\n          <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n          <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n          <EnableEnhancedInstructionSet>$(ExternalSimdOptions)</EnableEnhancedInstructionSet>\n          <Optimization>MaxSpeed</Optimization>\n          <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n          <CallingConvention>StdCall</CallingConvention>\n          <FloatingPointModel>Precise</FloatingPointModel>\n          <FunctionLevelLinking>true</FunctionLevelLinking>\n          <IntrinsicFunctions>true</IntrinsicFunctions>\n          <GuardSignedReturns>true</GuardSignedReturns>\n          <GuardEHContMetadata>true</GuardEHContMetadata>\n          <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n          <WholeProgramOptimization>true</WholeProgramOptimization>\n          <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n          <ControlFlowGuard>Guard</ControlFlowGuard>\n      </ClCompile>\n      <Link>\n          <AdditionalOptions>/BREPRO /DEBUGTYPE:CV,PDATA /DEPENDENTLOADFLAG:0x800 /PDBALTPATH:%_PDB% /FILEALIGN:0x1000 /LTCG /NOOPTIDATA /NOVCFEATURE /NOCOFFGRPINFO /BASERELOCCLUSTERING %(AdditionalOptions) $(ExternalLinkerOptions)</AdditionalOptions>\n          <AdditionalDependencies>invalidcontinue.obj;noarg.obj;noenv.obj;nothrownew.obj;%(AdditionalDependencies)</AdditionalDependencies>\n          <MinimumRequiredVersion>10</MinimumRequiredVersion>\n          <TargetMachine>MachineARM64</TargetMachine>\n          <GenerateDebugInformation>true</GenerateDebugInformation>\n          <SetChecksum>true</SetChecksum>\n          <StripPrivateSymbols>$(OutDir)$(TargetName)_stripped.pdb</StripPrivateSymbols>\n          <OptimizeReferences>true</OptimizeReferences>\n          <EnableCOMDATFolding>true</EnableCOMDATFolding>\n          <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>\n          <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n          <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n      </Link>\n  </ItemDefinitionGroup>\n\n</Project>\n"
  },
  {
    "path": "Directory.Build.props",
    "content": "<Project>\n  <PropertyGroup>\n    <SystemInformerRoot>$(MSBuildThisFileDirectory)</SystemInformerRoot>\n  </PropertyGroup>\n  <Import Project=\"packages\\Microsoft.Windows.SDK.CPP.10.0.26100.7463\\build\\native\\Microsoft.Windows.SDK.cpp.props\" Condition=\"Exists('packages\\Microsoft.Windows.SDK.CPP.10.0.26100.7463\\build\\native\\Microsoft.Windows.SDK.cpp.props')\"/>\n  <Import Project=\"packages\\Microsoft.Windows.SDK.CPP.x86.10.0.26100.7463\\build\\native\\Microsoft.Windows.SDK.cpp.x86.props\" Condition=\"Exists('packages\\Microsoft.Windows.SDK.CPP.x86.10.0.26100.7463\\build\\native\\Microsoft.Windows.SDK.cpp.x86.props') and '$(Platform)' == 'Win32'\"/>\n  <Import Project=\"packages\\Microsoft.Windows.SDK.CPP.x64.10.0.26100.7463\\build\\native\\Microsoft.Windows.SDK.cpp.x64.props\" Condition=\"Exists('packages\\Microsoft.Windows.SDK.CPP.x64.10.0.26100.7463\\build\\native\\Microsoft.Windows.SDK.cpp.x64.props') and '$(Platform)' == 'x64'\"/>\n  <Import Project=\"packages\\Microsoft.Windows.SDK.CPP.ARM64.10.0.26100.7463\\build\\native\\Microsoft.Windows.SDK.cpp.ARM64.props\" Condition=\"Exists('packages\\Microsoft.Windows.SDK.CPP.ARM64.10.0.26100.7463\\build\\native\\Microsoft.Windows.SDK.cpp.ARM64.props') and '$(Platform)' == 'ARM64'\"/>\n  <Import Project=\"packages\\Microsoft.Windows.WDK.x64.10.0.26100.6584\\build\\native\\Microsoft.Windows.WDK.x64.props\" Condition=\"Exists('packages\\Microsoft.Windows.WDK.x64.10.0.26100.6584\\build\\native\\Microsoft.Windows.WDK.x64.props') and '$(Platform)' == 'x64'\"/>\n  <Import Project=\"packages\\Microsoft.Windows.WDK.ARM64.10.0.26100.6584\\build\\native\\Microsoft.Windows.WDK.ARM64.props\" Condition=\"Exists('packages\\Microsoft.Windows.WDK.ARM64.10.0.26100.6584\\build\\native\\Microsoft.Windows.WDK.ARM64.props') and '$(Platform)' == 'ARM64'\"/>\n</Project>\n"
  },
  {
    "path": "HACKING.md",
    "content": "## Conventions\n\n### Names\n* Functions, function parameters, and global variables use CamelCase.\n* Local variables use lowerCamelCase.\n* Structs, enums and unions use CAPS_WITH_UNDERSCORES.\n\nAll names must have an appropriate prefix (with some exceptions):\n\n* `Ph` or `PH_` (structures) for public names.\n* `Php` or `PHP_` for private names.\n* Some variants such as `Pha`.\n* Private prefixes are created by appending `p` to the prefix. E.g. `Ph` -> `Php`, `Pha` -> `Phap`.\n* Functions and global variables without a prefix must be declared \"static\".\n  * `static` names must not have a public prefix.\n  * Names with a private prefix do not have to be `static`.\n* Structures without a prefix must be declared in a `.c/.cpp` file. Structures declared in a `.c/.cpp` file do not require a prefix.\n\n### Types\nUnless used for the Win32 API, the standard types are:\n\n* `BOOLEAN` for a 1 byte boolean, or `LOGICAL` for a 4 byte boolean.\n* `UCHAR` for 1 byte.\n* `SHORT`/`USHORT` for 2 bytes.\n* `LONG`/`ULONG` for 4 bytes.\n* `LONG64`/`ULONG64` for 8 bytes.\n* `CHAR` for a 1 byte character.\n* `WCHAR` for a 2 byte character.\n* `PSTR` for a string of 1 byte characters.\n* `PWSTR` for a string of 2 byte characters.\n\n#### Booleans\nAlways use:\n\n```\n    if (booleanVariable) // not \"if (booleanVariable == TRUE)\"\n    {\n        ...\n    }\n```\n\nto test a boolean value.\n\n### Annotations, qualifiers\n* All functions use SAL annotations, such as `_In_`, `_Inout_`, `_Out_`, etc.\n* Do not use `volatile` in definitions. Instead, cast to a volatile pointer when necessary.\n\n### Function success indicators\nThere are three main types of indicators used:\n\n* A `BOOLEAN` value is returned. `TRUE` indicates success.\n* A `NTSTATUS` value is returned. The `NT_SUCCESS` macro checks if a status value indicates success.\n* A `HRESULT` value is returned. The `HR_SUCCESS` macro checks if a status value indicates success.\n  *  Do not use the `SUCCEEDED` macro since third parties return `S_FALSE` for errors which  `SUCCEEDED` considers a success code. \n* The result of the function is returned (e.g. a pointer). A special value (e.g. `NULL`) indicates failure.\n\nUnless indicated, a function which fails is guaranteed not to modify any of its output parameters (`_Out_`, `_Out_opt_`, etc.).\n\nFor functions which are passed a callback function, it is not guaranteed that a failed function has not executed the callback function.\n\n### Threads\nEvery thread start routine must have the following signature:\n\n```\n    _Function_class_(USER_THREAD_START_ROUTINE)\n    NTSTATUS NTAPI NameOfRoutine(\n        _In_ PVOID Parameter\n        );\n```\n\nThread creation is done through the `PhCreateThread` and `PhCreateThreadEx` functions.\n\n### Collections\nThe collections available are summarized below:\n\nName                  | Use                     | Type\n--------------------- | ----------------------- | ---------------\n`PH_ARRAY`            | Array                   | Non-intrusive\n`PH_LIST`             | Array                   | Non-intrusive\n`LIST_ENTRY`          | Doubly linked list      | Intrusive\n`SINGLE_LIST_ENTRY`   | Singly linked list      | Intrusive\n`PH_POINTER_LIST`     | Array                   | Non-intrusive\n`LIST_ENTRY`          | Stack                   | Intrusive\n`SINGLE_LIST_ENTRY`   | Stack                   | Intrusive\n`LIST_ENTRY`          | Queue                   | Intrusive\n`RTL_AVL_TABLE`       | Binary tree (AVL)       | Non-intrusive\n`PH_AVL_LINKS`        | Binary tree (AVL)       | Intrusive\n`RTL_GENERIC_TABLE`   | Binary tree (splay)     | Non-intrusive\n`PH_HASHTABLE`        | Hashtable               | Non-intrusive\n`PH_HASH_ENTRY`       | Hashtable               | Intrusive\n`PH_CIRCULAR_BUFFER`  | Circular buffer         | Non-intrusive\n\n### Synchronization\nThe queued lock should be used for all synchronization, due to its small size and good performance. Although the queued lock is a reader-writer lock, it can be used as a mutex simply by using the exclusive acquire/release functions.\n\n- Events can be used through `PH_EVENT`. This object does not create a kernel event object until needed, and testing its state is very fast.\n\n- Rundown protection is available through `PH_RUNDOWN_PROTECT`.\n\n- Condition variables are available using the queued lock. Simply declare and initialize a queued lock variable, and use the `PhPulse(All)Condition` and `PhWaitForCondition` functions.\n\n- Custom locking with low overhead can be built using the wake event, built on the queued lock. Test one or more conditions in a loop and use `PhQueueWakeEvent`/`PhWaitForWakeEvent` to block. When a condition is modified use `PhSetWakeEvent` to wake waiters. If after calling `PhQueueWakeEvent` it is determined that no blocking should occur, use `PhSetWakeEvent`.\n\n### Exceptions (SEH)\nThe only method of error handling used in Process Hacker is the return value (`NTSTATUS`, `BOOLEAN`, etc.). Exceptions are used for exceptional situations which cannot easily be recovered from (e.g. a lock acquire function fails to block, or an object has a negative reference count.\n\nExceptions to this rule include:\n\n* `PhAllocate`, which raises an exception if it fails to allocate. Checking the return value of each allocation to increase reliability is not worth the extra effort involved, as failed allocations are very rare.\n* `PhProbeAddress`, which raises an exception if an address lies outside of a specified range. Raising an exception makes it possible to conduct multiple checks in one SEH block.\n* `STATUS_NOT_IMPLEMENTED` exceptions triggered by code paths which should not be reached, purely due to programmer error. `assert(FALSE)` could also be used in this case.\n\n### Memory management\nUse `PhAllocate`/`PhFree` to allocate/free memory. For complex objects, use the reference counting system.\n\nThere is semi-automatic reference counting available in the form of auto-dereference pools (similar to Apple's `NSAutoreleasePool`s). Use the `PhAutoDereferenceObject` to add an object to the thread's pool, and the object will be dereferenced at an unspecified time in the future. However, the object is guaranteed to not be dereferenced while the current function is executing.\n\nReferencing an object is necessary whenever a pointer to the object is stored in a globally visible location or passed to another thread. In most other cases, referencing is not necessary.\n\nAll objects passed to functions must have a guaranteed reference for the duration of that call. One mistake is to keep a reference which could be destroyed in a window procedure, and to use that reference implicitly inside the window procedure. Messages can still be pumped (e.g. dialog boxes) while the window procedure is executing, so the window procedure must reference the object as soon as possible.\n\n### Names (2)\n\n#### Object creation/deletion\n* Allocate means allocate memory without initialization.\n* Create means allocate memory for an object and initialize the object.\n* Free can be used for objects created with Allocate or Create functions.\n* Destroy can also be used for objects created with Create functions.\n* Initialize means initialize an object with caller-supplied storage.\n* Delete is paired with Initialize and does not free the object as it was allocated by the caller.\n* Create is used when objects are being created through the reference counting system.\n\nExamples:\n* `PhAllocateFromFreeList`/`PhFreeToFreeList`\n* `PhCreateFileDialog`/`PhFreeFileDialog`\n* `PhInitializeWorkQueue`/`PhDeleteWorkQueue`\n* `PhCreateString`/`PhDereferenceObject`\n\n#### Element counts\n* Length specifies the length in bytes. E.g. `PhCreateString` requires the length to be specified in bytes.\n* Count specifies the length in elements. E.g. `PhSubstring` requires the length to be specified in characters.\n* Index specifies the index in elements. E.g. `PhSubstring` requires the index to be specified in characters.\n\nWhen null terminated strings are being written to output, the return count, if any, must be specified as the number of characters written including the null terminator.\n\n### Strings\nStrings use the `PH_STRING` type, managed by reference counting. To create a string object from a null-terminated string:\n\n```\n    PPH_STRING myString = PhCreateString(L\"My string\");\n\n    wprintf(\n        L\"My string is \\\"%s\\\", and uses %Iu bytes.\\n\",\n        myString->Buffer,\n        myString->Length\n        );\n```\n\nAll string objects have an embedded length (always in bytes), and the string is additionally null-terminated for compatibility reasons.\n\nString objects must be treated as immutable unless a string object is created and modified before the pointer is shared with any other functions or stored in any global variables. This exception applies only when creating a string using `PhCreateString` or `PhCreateStringEx`.\n\nStrings can be concatenated with `PhConcatStrings`:\n\n```\n    PPH_STRING newString;\n\n    newString = PhConcatStrings(\n        4,\n        L\"My first string, \",\n        L\"My second string, \",\n        aStringFromSomewhere,\n        L\"My fourth string.\"\n        );\n```\n\nAnother version concatenates two strings:\n\n```\n    PPH_STRING newString;\n\n    newString = PhConcatStrings2(\n        L\"My first string, \",\n        L\"My second string.\"\n        );\n```\n\nStrings can be formatted:\n\n```\n    PPH_STRING newString;\n\n    newString = PhFormatString(\n        L\"%d: %s, %#x\",\n        100,\n        L\"test\",\n        0xff\n        );\n```\n\n### Tips\n * Use !! to \"cast\" to a boolean.\n"
  },
  {
    "path": "KSystemInformer/Directory.Build.props",
    "content": "<Project>\n  <!-- Merge with parent Directory.Build.props -->\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />\n  <Import Project=\"$(SystemInformerRoot)/Common.Kernel.props\" />\n</Project>\n"
  },
  {
    "path": "KSystemInformer/KSystemInformer.inf",
    "content": ";\n; Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n;\n; This file is part of System Informer.\n;\n; Authors:\n;\n;     jxy-s   2022-2025\n;\n\n[Version]\nSignature    = \"$WINDOWS NT$\"\nClass        = ActivityMonitor\nClassGuid    = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}\nProvider     = SystemInformer\nDriverVer    = 09/01/2022,3.0.0000.0000\nCatalogFile  = KSystemInformer.cat\nPnpLockdown  = 1\n\n[DestinationDirs]\nDefaultDestDir = 13\n\n[SystemInformer.Service]\nDisplayName    = KSystemInformer\nServiceType    = 1               ; SERVICE_KERNEL_DRIVER\nStartType      = 3               ; SERVICE_DEMAND_START\nErrorControl   = 1               ; SERVICE_ERROR_NORMAL\nServiceBinary  = %13%\\systeminformer.sys\n\n[SystemInformer.CopyFiles]\nsysteminformer.sys\nksi.dll\n\n[SourceDisksFiles]\nsysteminformer.sys = 1,,\nksi.dll = 1,,\n\n[SourceDisksNames]\n1 = %DiskId1%,,,\"\"\n\n[Strings]\nDiskId1 = \"KSystemInformer Disk #1\"\n\n;\n; AMD64 Section\n;\n\n[DefaultInstall.NTamd64]\nCopyFiles = SystemInformer.CopyFiles\n\n[DefaultInstall.NTamd64.Services]\nAddService = KSystemInformer,,SystemInformer.Service\n\n;\n; ARM64 Section\n;\n\n[DefaultInstall.NTarm64]\nCopyFiles = SystemInformer.CopyFiles\n\n[DefaultInstall.NTarm64.Services]\nAddService = KSystemInformer,,SystemInformer.Service\n"
  },
  {
    "path": "KSystemInformer/KSystemInformer.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.7.34024.191\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"KSystemInformer\", \"KSystemInformer.vcxproj\", \"{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321} = {B1863396-A667-42DB-97AC-C5E033CEE321}\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0} = {B385D394-19CC-48BC-827E-AF9ADCE559E0}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"kphlib\", \"..\\kphlib\\kphlib_km.vcxproj\", \"{B1863396-A667-42DB-97AC-C5E033CEE321}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"ksidll\", \"ksidll.vcxproj\", \"{B385D394-19CC-48BC-827E-AF9ADCE559E0}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321} = {B1863396-A667-42DB-97AC-C5E033CEE321}\n\tEndProjectSection\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|ARM64 = Debug|ARM64\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|ARM64 = Release|ARM64\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|ARM64.Deploy.0 = Debug|ARM64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|x64.Build.0 = Debug|x64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|ARM64.Deploy.0 = Release|ARM64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|x64.ActiveCfg = Release|x64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|x64.Build.0 = Release|x64\n\t\t{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|x64.Deploy.0 = Release|x64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Debug|ARM64.Deploy.0 = Debug|ARM64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Debug|x64.Build.0 = Debug|x64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Release|ARM64.Deploy.0 = Release|ARM64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Release|x64.ActiveCfg = Release|x64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Release|x64.Build.0 = Release|x64\n\t\t{B1863396-A667-42DB-97AC-C5E033CEE321}.Release|x64.Deploy.0 = Release|x64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Debug|ARM64.Deploy.0 = Debug|ARM64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Debug|x64.Build.0 = Debug|x64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Release|ARM64.Deploy.0 = Release|ARM64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Release|x64.ActiveCfg = Release|x64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Release|x64.Build.0 = Release|x64\n\t\t{B385D394-19CC-48BC-827E-AF9ADCE559E0}.Release|x64.Deploy.0 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {4989C8A8-DCF1-48A9-9012-23369AB01403}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "KSystemInformer/KSystemInformer.slnx",
    "content": "<Solution>\n  <Configurations>\n    <Platform Name=\"ARM64\" />\n    <Platform Name=\"x64\" />\n  </Configurations>\n  <Project Path=\"../kphlib/kphlib_km.vcxproj\" Id=\"b1863396-a667-42db-97ac-c5e033cee321\">\n  </Project>\n  <Project Path=\"ksidll.vcxproj\" Id=\"b385d394-19cc-48bc-827e-af9adce559e0\">\n    <BuildDependency Project=\"../kphlib/kphlib_km.vcxproj\" />\n  </Project>\n  <Project Path=\"KSystemInformer.vcxproj\" Id=\"f4853009-c5d2-4a25-be4d-bb0d9f84e2ff\">\n    <BuildDependency Project=\"../kphlib/kphlib_km.vcxproj\" />\n    <BuildDependency Project=\"ksidll.vcxproj\" />\n  </Project>\n</Solution>\n"
  },
  {
    "path": "KSystemInformer/KSystemInformer.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}</ProjectGuid>\n    <TemplateGuid>{dd38f7fc-d7bd-488b-9242-7d8754cde80d}</TemplateGuid>\n    <ConfigurationType>Driver</ConfigurationType>\n    <RootNamespace>KSystemInformer</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <IntDir>$(SystemInformerRoot)KSystemInformer\\obj\\$(Configuration)$(PlatformArchitecture)\\$(ProjectName)\\</IntDir>\n    <OutDir>$(SystemInformerRoot)KSystemInformer\\bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <TargetName>SystemInformer</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup>\n    <Link>\n      <AdditionalDependencies>ksi.lib;FltMgr.lib;ksecdd.lib;kphlib_km.lib;volatileaccessk.lib;umaccess.lib%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ResourceCompile>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SystemInformerRoot)kphlib\\include\\</AdditionalIncludeDirectories>\n    </ResourceCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"alloc.c\" />\n    <ClCompile Include=\"alpc.c\" />\n    <ClCompile Include=\"back_trace.c\" />\n    <ClCompile Include=\"cid_table.c\" />\n    <ClCompile Include=\"cid_tracking.c\" />\n    <ClCompile Include=\"comms.c\" />\n    <ClCompile Include=\"comms_handlers.c\" />\n    <ClCompile Include=\"device.c\" />\n    <ClCompile Include=\"driver.c\" />\n    <ClCompile Include=\"dyndata.c\" />\n    <ClCompile Include=\"dynimp.c\" />\n    <ClCompile Include=\"file.c\" />\n    <ClCompile Include=\"hash.c\" />\n    <ClCompile Include=\"imgcoherency.c\" />\n    <ClCompile Include=\"informer_debug.c\" />\n    <ClCompile Include=\"informer_file.c\" />\n    <ClCompile Include=\"informer_fileop.c\" />\n    <ClCompile Include=\"informer_filenc.c\" />\n    <ClCompile Include=\"informer_image.c\" />\n    <ClCompile Include=\"informer_object.c\" />\n    <ClCompile Include=\"informer_process.c\" />\n    <ClCompile Include=\"informer.c\" />\n    <ClCompile Include=\"informer_registry.c\" />\n    <ClCompile Include=\"informer_thread.c\" />\n    <ClCompile Include=\"knowndll.c\" />\n    <ClCompile Include=\"kphobject.c\" />\n    <ClCompile Include=\"kphthread.c\" />\n    <ClCompile Include=\"lsa.c\" />\n    <ClCompile Include=\"main.c\" />\n    <ClCompile Include=\"object.c\" />\n    <ClCompile Include=\"parameters.c\" />\n    <ClCompile Include=\"process.c\" />\n    <ClCompile Include=\"protection.c\" />\n    <ClCompile Include=\"ratelmt.c\" />\n    <ClCompile Include=\"ringbuff.c\" />\n    <ClCompile Include=\"session_token.c\" />\n    <ClCompile Include=\"system.c\" />\n    <ClCompile Include=\"thread.c\" />\n    <ClCompile Include=\"umaccess.c\" />\n    <ClCompile Include=\"util.c\" />\n    <ClCompile Include=\"verify.c\" />\n    <ClCompile Include=\"vm.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"resource.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\comms.h\" />\n    <ClInclude Include=\"include\\informer.h\" />\n    <ClInclude Include=\"include\\informer_filep.h\" />\n    <ClInclude Include=\"include\\kph.h\" />\n    <ClInclude Include=\"include\\ntfill.h\" />\n    <ClInclude Include=\"include\\pooltags.h\" />\n    <ClInclude Include=\"include\\trace.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>\n"
  },
  {
    "path": "KSystemInformer/KSystemInformer.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"dyndata.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"dynimp.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"main.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"object.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"process.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"driver.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"thread.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"vm.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"util.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"verify.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer_file.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"comms.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer_image.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer_process.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer_thread.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer_debug.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"comms_handlers.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hash.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer_object.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"alloc.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"cid_table.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphobject.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"cid_tracking.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"protection.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"alpc.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"system.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"file.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"knowndll.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"back_trace.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"parameters.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer_fileop.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer_filenc.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer_registry.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"session_token.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lsa.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"imgcoherency.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"device.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ringbuff.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphthread.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"resource.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\kph.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\ntfill.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\comms.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\informer.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\trace.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\pooltags.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\informer_filep.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "KSystemInformer/README.md",
    "content": "# System Informer Kernel\n\n- optimizes retrieval of information from the system\n- enables broader inspection into the system\n- informs of system activity in realtime\n- assists in removal of malware\n\n## Security\n\n[Security Policies and Procedures](../SECURITY.md)\n\nBecause the information exposed through the driver enables, by design, broader\naccess into the system. Access is strictly limited to verified callers.\nAccess is restricted based on the state of the calling process. This involves\nsigning, privilege, and other state checks. If the client does not meet the\nstate requirements they are denied access.\n\nAny binaries built with the intention of loading into System Informer must\nhave a `.sig` from the key pair integrated into the build process and driver.\nOr be signed by Microsoft or an anti-malware vendor. Loading of unsigned\nmodules will restrict access to the driver. Third-party plugins are supported,\nhowever when they are loaded access to the driver will be restricted as they\nare not signed.\n\nThe driver tracks verified clients, restricts access by other actors on the\nsystem, and denies access if the process is tampered with. The intention is to\ndiscourage exploitation of the client when the driver is active. If tampering\nor exploitation is detected the client is denied access.\n\n## Development\n\nDevelopers may suppress protections and state requirements by disabling secure\nboot (if applicable) then enabling debug and test signing mode. Doing this will\npermit the client process to be debugged and enables use of test signing keys.\n```\nbcdedit /debug on\nbcdedit /set testsigning on\n```\n\nDevelopers may generate their own key pair for use in their environment.\n\n1. execute `tools\\CustomSignTool\\bin\\Release64\\CustomSignTool.exe createkeypair kph.key public.key`\n2. copy `kph.key` into `tools\\CustomSignTool\\resources`\n3. copy the bytes for `public.key` into the `KphpPublicKeys` array in [verify.c](verify.c)\n    - `KphKeyTypeProd` does not require debug and test signing enablement\n    - `KphKeyTypeTest` requires debug and test signing enablement\n4. regenerate dynamic data `tools\\CustomBuildTool\\bin\\Release\\amd64\\CustomBuildTool.exe -dyndata`\n5. rebuild the kernel _and_ user components\n\nIt's important to regenerate the dynamic data and build the kernel and user\ncomponents after creating and placing the new key pair. The driver uses the\npublic key to validate the dynamic data and user mode binaries. Neglecting to\ndo this will result in failures to load or connect to the driver.\n\nOnce these steps are completed builds of System Informer components will\ngenerate a `.sig` file next to the output binaries. And the developer built\ndriver will use the specified key when doing verification checks. Any plugins\nnot built through the regular build process must also have their own `.sig`.\n"
  },
  {
    "path": "KSystemInformer/alloc.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_LOOKASIDE_INIT\n{\n    SIZE_T Size;\n    ULONG Tag;\n} KPH_LOOKASIDE_INIT, *PKPH_LOOKASIDE_INIT;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpPagedLookasideObjectTypeName = RTL_CONSTANT_STRING(L\"KphPagedLookaside\");\nstatic const UNICODE_STRING KphpNPagedLookasideObjectTypeName = RTL_CONSTANT_STRING(L\"KphNPagedLookaside\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_OBJECT_TYPE KphpPagedLookasideObjectType = NULL;\nstatic PKPH_OBJECT_TYPE KphpNPagedLookasideObjectType = NULL;\nstatic ULONG KphpRandomPoolTag = 0;\nKPH_PROTECTED_DATA_SECTION_POP();\n\n/**\n * \\brief Allocates non-page-able memory.\n *\n * \\param[in] NumberOfBytes The number of bytes to allocate.\n * \\param[in] Tag The pool tag to use.\n *\n * \\return Allocated non-page-able memory. Null on failure.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_size_(NumberOfBytes)\nPVOID KphAllocateNPaged(\n    _In_ SIZE_T NumberOfBytes,\n    _In_ ULONG Tag\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (KphpRandomPoolTag)\n    {\n        Tag = KphpRandomPoolTag;\n    }\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    return ExAllocatePoolZero(NonPagedPoolNx, NumberOfBytes, Tag);\n}\n\n/**\n * \\brief Frees memory.\n *\n * \\param[in] Memory The memory to free.\n * \\param[in] Tag The tag associated with the allocation.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphFree(\n    _FreesMem_ PVOID Memory,\n    _In_ ULONG Tag\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n    NT_ASSERT(Memory);\n\n    if (KphpRandomPoolTag)\n    {\n        Tag = KphpRandomPoolTag;\n    }\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    ExFreePoolWithTag(Memory, Tag);\n}\n\n/**\n * \\brief Initialized a non-page-able lookaside list.\n *\n * \\param[out] Lookaside The lookaside list to initialize.\n * \\param[in] Size The size of entries in the lookaside list.\n * \\param[in] Tag The pool tag to use.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphInitializeNPagedLookaside(\n    _Out_ PNPAGED_LOOKASIDE_LIST Lookaside,\n    _In_ SIZE_T Size,\n    _In_ ULONG Tag\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (KphpRandomPoolTag)\n    {\n        Tag = KphpRandomPoolTag;\n    }\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    ExInitializeNPagedLookasideList(Lookaside,\n                                    NULL,\n                                    NULL,\n                                    POOL_NX_ALLOCATION,\n                                    Size,\n                                    Tag,\n                                    0);\n}\n\n/**\n * \\brief Deletes a non-page-able lookaside list.\n *\n * \\param[in,out] Lookaside The lookaside to delete.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphDeleteNPagedLookaside(\n    _Inout_ PNPAGED_LOOKASIDE_LIST Lookaside\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    ExDeleteNPagedLookasideList(Lookaside);\n}\n\n/**\n * \\brief Allocates non-page-able memory from the lookaside list.\n *\n * \\param[in,out] Lookaside The lookaside list to allocate from.\n *\n * \\return Allocated non-page-able memory. Null on failure.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_size_(Lookaside->L.Size)\nPVOID KphAllocateFromNPagedLookaside(\n    _Inout_ PNPAGED_LOOKASIDE_LIST Lookaside\n    )\n{\n    PVOID memory;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    memory = ExAllocateFromNPagedLookasideList(Lookaside);\n    if (memory)\n    {\n        RtlZeroMemory(memory, Lookaside->L.Size);\n    }\n\n    return memory;\n}\n\n/**\n * \\brief Frees non-page-able memory back to the lookaside list.\n *\n * \\param[in,out] Lookaside The lookaside list to free back to.\n * \\param[in] Memory The memory to free.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphFreeToNPagedLookaside(\n    _Inout_ PNPAGED_LOOKASIDE_LIST Lookaside,\n    _In_freesMem_ PVOID Memory\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n    NT_ASSERT(Memory);\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    ExFreeToNPagedLookasideList(Lookaside, Memory);\n}\n\n/**\n * \\brief Allocates a non-page-able lookaside object.\n *\n * \\param[in] Size The size of the lookaside object.\n *\n * \\return Allocated lookaside object, null on allocation failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateNPagedLookasideObject(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    return KphAllocateNPaged(Size, KPH_TAG_NPAGED_LOOKASIDE_OBJECT);\n}\n\n/**\n * \\brief Initializes a non-page-able lookaside object.\n *\n * \\param[in,out] Object The lookaside object to initialize.\n * \\param[in] Parameter The lookaside initialization parameters.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializeNPagedLookasideObject(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_NPAGED_LOOKASIDE_OBJECT lookaside;\n    PKPH_LOOKASIDE_INIT init;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    NT_ASSERT(Parameter);\n\n    lookaside = Object;\n    init = Parameter;\n\n    KphInitializeNPagedLookaside((PNPAGED_LOOKASIDE_LIST)lookaside,\n                                 init->Size,\n                                 init->Tag);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Deletes a non-page-able lookaside object.\n *\n * \\param[in,out] Object The lookaside object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\nVOID KSIAPI KphpDeleteNPagedLookasideObject(\n    _Inout_ PVOID Object\n    )\n{\n    PKPH_NPAGED_LOOKASIDE_OBJECT lookaside;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    lookaside = Object;\n\n    KphDeleteNPagedLookaside((PNPAGED_LOOKASIDE_LIST)Object);\n}\n\n/**\n * \\brief Frees a non-page-page lookaside object.\n *\n * \\param[in] Object The lookaside object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\nVOID KSIAPI KphpFreeNPagedLookasideObject(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    KphFree(Object, KPH_TAG_NPAGED_LOOKASIDE_OBJECT);\n}\n\n/**\n * \\brief Creates a non-page-able lookaside object.\n *\n * \\param[out] Lookaside Set to the new non-page-able lookaside object on success.\n * \\param[in] Size The size of entries in the lookaside list.\n * \\param[in] Tag The pool tag to use.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nNTSTATUS KphCreateNPagedLookasideObject(\n    _Outptr_result_nullonfailure_ PKPH_NPAGED_LOOKASIDE_OBJECT* Lookaside,\n    _In_ SIZE_T Size,\n    _In_ ULONG Tag\n    )\n{\n    NTSTATUS status;\n    KPH_LOOKASIDE_INIT init;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (KphpRandomPoolTag)\n    {\n        Tag = KphpRandomPoolTag;\n    }\n\n    init.Size = Size;\n    init.Tag = Tag;\n\n    *Lookaside = NULL;\n\n    status = KphCreateObject(KphpNPagedLookasideObjectType,\n                             sizeof(KPH_NPAGED_LOOKASIDE_OBJECT),\n                             Lookaside,\n                             &init);\n    if (!NT_SUCCESS(status))\n    {\n        *Lookaside = NULL;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Allocates from a non-page-able lookaside object.\n *\n * \\param[in,out] Lookaside The non-page-able lookaside object to allocate from.\n *\n * \\return Allocated non-page-able memory. Null on failure.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_size_(Lookaside->L.Size)\nPVOID KphAllocateFromNPagedLookasideObject(\n    _Inout_ PKPH_NPAGED_LOOKASIDE_OBJECT Lookaside\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    return KphAllocateFromNPagedLookaside((PNPAGED_LOOKASIDE_LIST)Lookaside);\n}\n\n/**\n * \\brief Frees non-page-able memory back to the lookaside object.\n *\n * \\param[in,out] Lookaside The lookaside object to free back to.\n * \\param[in] Memory The memory to free.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphFreeToNPagedLookasideObject(\n    _Inout_ PKPH_NPAGED_LOOKASIDE_OBJECT Lookaside,\n    _In_freesMem_ PVOID Memory\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    KphFreeToNPagedLookaside((PNPAGED_LOOKASIDE_LIST)Lookaside, Memory);\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Allocates page-able memory.\n *\n * \\param[in] NumberOfBytes The number of bytes to allocate.\n * \\param[in] Tag The pool tag to use.\n *\n * \\return Allocated page-able memory. Null on failure.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(NumberOfBytes)\nPVOID KphAllocatePaged(\n    _In_ SIZE_T NumberOfBytes,\n    _In_ ULONG Tag\n    )\n{\n    KPH_PAGED_CODE();\n\n    if (KphpRandomPoolTag)\n    {\n        Tag = KphpRandomPoolTag;\n    }\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    return ExAllocatePoolZero(PagedPool, NumberOfBytes, Tag);\n}\n\n/**\n * \\brief Initialized a page-able lookaside list.\n *\n * \\param[in] Lookaside The lookaside list to initialize.\n * \\param[in] Size The size of entries in the lookaside list.\n * \\param[in] Tag The pool tag to use.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphInitializePagedLookaside(\n    _Out_ PPAGED_LOOKASIDE_LIST Lookaside,\n    _In_ SIZE_T Size,\n    _In_ ULONG Tag\n    )\n{\n    KPH_PAGED_CODE();\n\n    if (KphpRandomPoolTag)\n    {\n        Tag = KphpRandomPoolTag;\n    }\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    ExInitializePagedLookasideList(Lookaside, NULL, NULL, 0, Size, Tag, 0);\n}\n\n/**\n * \\brief Deletes a page-able lookaside list.\n *\n * \\param[in,out] Lookaside The lookaside to delete.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphDeletePagedLookaside(\n    _Inout_ PPAGED_LOOKASIDE_LIST Lookaside\n    )\n{\n    KPH_PAGED_CODE();\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    ExDeletePagedLookasideList(Lookaside);\n}\n\n/**\n * \\brief Allocates page-able memory from the lookaside list.\n *\n * \\param[in,out] Lookaside The lookaside list to allocate from.\n *\n * \\return Allocated page-able memory. Null on failure.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(Lookaside->L.Size)\nPVOID KphAllocateFromPagedLookaside(\n    _Inout_ PPAGED_LOOKASIDE_LIST Lookaside\n    )\n{\n    PVOID memory;\n\n    KPH_PAGED_CODE();\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    memory = ExAllocateFromPagedLookasideList(Lookaside);\n    if (memory)\n    {\n        RtlZeroMemory(memory, Lookaside->L.Size);\n    }\n\n    return memory;\n}\n\n/**\n * \\brief Frees page-able memory back to the lookaside list.\n *\n * \\param[in,out] Lookaside The lookaside list to free back to.\n * \\param[in] Memory The memory to free.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeToPagedLookaside(\n    _Inout_ PPAGED_LOOKASIDE_LIST Lookaside,\n    _In_freesMem_ PVOID Memory\n    )\n{\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Memory);\n\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    ExFreeToPagedLookasideList(Lookaside, Memory);\n}\n\n/**\n * \\brief Allocates a page-able lookaside object.\n *\n * \\param[in] Size The size of the lookaside object.\n *\n * \\return Allocated lookaside object, null on allocation failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocatePagedLookasideObject(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_PAGED_CODE();\n\n    return KphAllocateNPaged(Size, KPH_TAG_PAGED_LOOKASIDE_OBJECT);\n}\n\n/**\n * \\brief Initializes a page-able lookaside object.\n *\n * \\param[in,out] Object The lookaside object to initialize.\n * \\param[in] Parameter The lookaside initialization parameters.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializePagedLookasideObject(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_PAGED_LOOKASIDE_OBJECT lookaside;\n    PKPH_LOOKASIDE_INIT init;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Parameter);\n\n    lookaside = Object;\n    init = Parameter;\n\n    KphInitializePagedLookaside((PPAGED_LOOKASIDE_LIST)lookaside,\n                                init->Size,\n                                init->Tag);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Deletes a page-able lookaside object.\n *\n * \\param[in,out] Object The lookaside object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\nVOID KSIAPI KphpDeletePagedLookasideObject(\n    _Inout_ PVOID Object\n    )\n{\n    PKPH_PAGED_LOOKASIDE_OBJECT lookaside;\n\n    KPH_PAGED_CODE();\n\n    lookaside = Object;\n\n    KphDeletePagedLookaside((PPAGED_LOOKASIDE_LIST)Object);\n}\n\n/**\n * \\brief Frees a page-page lookaside object.\n *\n * \\param[in] Object The lookaside object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\nVOID KSIAPI KphpFreePagedLookasideObject(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphFree(Object, KPH_TAG_PAGED_LOOKASIDE_OBJECT);\n}\n\n/**\n * \\brief Creates a page-able lookaside object.\n *\n * \\param[out] Lookaside Set to the new page-able lookaside object on success.\n * \\param[in] Size The size of entries in the lookaside list.\n * \\param[in] Tag The pool tag to use.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphCreatePagedLookasideObject(\n    _Outptr_result_nullonfailure_ PKPH_PAGED_LOOKASIDE_OBJECT* Lookaside,\n    _In_ SIZE_T Size,\n    _In_ ULONG Tag\n    )\n{\n    NTSTATUS status;\n    KPH_LOOKASIDE_INIT init;\n\n    KPH_PAGED_CODE();\n\n    if (KphpRandomPoolTag)\n    {\n        Tag = KphpRandomPoolTag;\n    }\n\n    init.Size = Size;\n    init.Tag = Tag;\n\n    *Lookaside = NULL;\n\n    status = KphCreateObject(KphpPagedLookasideObjectType,\n                             sizeof(KPH_PAGED_LOOKASIDE_OBJECT),\n                             Lookaside,\n                             &init);\n    if (!NT_SUCCESS(status))\n    {\n        *Lookaside = NULL;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Allocates from a page-able lookaside object.\n *\n * \\param[in,out] Lookaside The page-able lookaside object to allocate from.\n *\n * \\return Allocated page-able memory. Null on failure.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(Lookaside->L.Size)\nPVOID KphAllocateFromPagedLookasideObject(\n    _Inout_ PKPH_PAGED_LOOKASIDE_OBJECT Lookaside\n    )\n{\n    KPH_PAGED_CODE();\n\n    return KphAllocateFromPagedLookaside((PPAGED_LOOKASIDE_LIST)Lookaside);\n}\n\n/**\n * \\brief Frees page-able memory back to the lookaside object.\n *\n * \\param[in,out] Lookaside The lookaside object to free back to.\n * \\param[in] Memory The memory to free.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeToPagedLookasideObject(\n    _Inout_ PKPH_PAGED_LOOKASIDE_OBJECT Lookaside,\n    _In_freesMem_ PVOID Memory\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphFreeToPagedLookaside((PPAGED_LOOKASIDE_LIST)Lookaside, Memory);\n}\n\n/**\n * \\brief Makes a byte suitable for a pool tag.\n *\n * \\param[in] Byte A byte to make suitable for a pool tag.\n *\n * \\return A byte suitable for a pool tag.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nBYTE KphpMakePoolTagByte(\n    _In_ BYTE Byte\n    )\n{\n    BYTE outByte;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    outByte = Byte % '~';\n    if (outByte < ' ')\n    {\n        outByte += ' ';\n    }\n    return outByte;\n}\n\n/**\n * \\brief Generates a randomized pool tag.\n *\n * \\return Randomized pool tag.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nULONG KphpGenerateRandomPoolTag(\n    VOID\n    )\n{\n    ULONG64 interruptTime;\n    ULONG seed;\n    ULONG randomValue;\n    BYTE byte;\n    ULONG poolTag;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    interruptTime = KeQueryInterruptTime();\n    seed = (ULONG)(interruptTime >> 32);\n    seed |= (ULONG)interruptTime;\n    seed ^= PtrToUlong(PsGetCurrentThread());\n\n    do\n    {\n        randomValue = RtlRandomEx(&seed);\n    } while (!randomValue);\n\n    poolTag = 0;\n    byte = KphpMakePoolTagByte(randomValue & 0xff);\n    poolTag = (ULONG)byte;\n    byte = KphpMakePoolTagByte((randomValue >> 8) & 0xff);\n    poolTag |= ((ULONG)byte << 8);\n    byte = KphpMakePoolTagByte((randomValue >> 16) & 0xff);\n    poolTag |= ((ULONG)byte << 16);\n    byte = KphpMakePoolTagByte((randomValue >> 24) & 0xff);\n    poolTag |= ((ULONG)byte << 24);\n\n    return poolTag;\n}\n\n/**\n * \\brief Initializes allocation infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeAlloc(\n    VOID\n    )\n{\n    KPH_OBJECT_TYPE_INFO typeInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (KphParameterFlags.RandomizedPoolTag)\n    {\n        KphpRandomPoolTag = KphpGenerateRandomPoolTag();\n    }\n\n    typeInfo.Allocate = KphpAllocatePagedLookasideObject;\n    typeInfo.Initialize = KphpInitializePagedLookasideObject;\n    typeInfo.Delete = KphpDeletePagedLookasideObject;\n    typeInfo.Free = KphpFreePagedLookasideObject;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpPagedLookasideObjectTypeName,\n                        &typeInfo,\n                        &KphpPagedLookasideObjectType);\n\n    typeInfo.Allocate = KphpAllocateNPagedLookasideObject;\n    typeInfo.Initialize = KphpInitializeNPagedLookasideObject;\n    typeInfo.Delete = KphpDeleteNPagedLookasideObject;\n    typeInfo.Free = KphpFreeNPagedLookasideObject;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpNPagedLookasideObjectTypeName,\n                        &typeInfo,\n                        &KphpNPagedLookasideObjectType);\n}\n"
  },
  {
    "path": "KSystemInformer/alpc.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PAGED_FILE();\n\n#define KPH_ALPC_NAME_BUFFER_SIZE ((MAX_PATH * 2) + sizeof(OBJECT_NAME_INFORMATION))\n\n/**\n * \\brief References any communication ports associated with the input port.\n * The caller must dereference any returned objects by calling ObDereferenceObject.\n *\n * \\param[in] Dyn Dynamic configuration.\n * \\param[in] Port The ALPC port to references the associated ports of.\n * \\param[out] ConnectionPort Set to the connection port.\n * \\param[out] ServerPort Set to the server port.\n * \\param[out] ClientPort Set to the client port.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpReferenceAlpcCommunicationPorts(\n    _In_ PKPH_DYN Dyn,\n    _In_ PVOID Port,\n    _Outptr_result_maybenull_ PVOID* ConnectionPort,\n    _Outptr_result_maybenull_ PVOID* ServerPort,\n    _Outptr_result_maybenull_ PVOID* ClientPort\n    )\n{\n    NTSTATUS status;\n    PVOID communicationInfo;\n    PVOID handleTable;\n    PVOID handleTableLock;\n    BOOLEAN typeMismatch;\n    PVOID connectionPort;\n    PVOID serverPort;\n    PVOID clientPort;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    *ConnectionPort = NULL;\n    *ServerPort = NULL;\n    *ClientPort = NULL;\n\n    connectionPort = NULL;\n    serverPort = NULL;\n    clientPort = NULL;\n\n    if ((Dyn->AlpcCommunicationInfo == ULONG_MAX) ||\n        (Dyn->AlpcHandleTable == ULONG_MAX) ||\n        (Dyn->AlpcHandleTableLock == ULONG_MAX))\n    {\n        status = STATUS_NOINTERFACE;\n        goto Exit;\n    }\n\n    communicationInfo = *(PVOID*)Add2Ptr(Port, Dyn->AlpcCommunicationInfo);\n    if (!communicationInfo)\n    {\n        status = STATUS_NOT_FOUND;\n        goto Exit;\n    }\n\n    handleTable = Add2Ptr(communicationInfo, Dyn->AlpcHandleTable);\n    handleTableLock = Add2Ptr(handleTable, Dyn->AlpcHandleTableLock);\n\n    typeMismatch = FALSE;\n\n    FltAcquirePushLockShared(handleTableLock);\n\n    if (Dyn->AlpcConnectionPort != ULONG_MAX)\n    {\n        connectionPort = *(PVOID*)Add2Ptr(communicationInfo,\n                                          Dyn->AlpcConnectionPort);\n        if (connectionPort)\n        {\n            if (ObGetObjectType(connectionPort) != *AlpcPortObjectType)\n            {\n                typeMismatch = TRUE;\n                connectionPort = NULL;\n            }\n            else\n            {\n                ObReferenceObject(connectionPort);\n            }\n        }\n    }\n\n    if (Dyn->AlpcServerCommunicationPort != ULONG_MAX)\n    {\n        serverPort = *(PVOID*)Add2Ptr(communicationInfo,\n                                      Dyn->AlpcServerCommunicationPort);\n        if (serverPort)\n        {\n            if (ObGetObjectType(serverPort) != *AlpcPortObjectType)\n            {\n                typeMismatch = TRUE;\n                serverPort = NULL;\n            }\n            else\n            {\n                ObReferenceObject(serverPort);\n            }\n        }\n    }\n\n    if (Dyn->AlpcClientCommunicationPort != ULONG_MAX)\n    {\n        clientPort = *(PVOID*)Add2Ptr(communicationInfo,\n                                      Dyn->AlpcClientCommunicationPort);\n        if (clientPort)\n        {\n            if (ObGetObjectType(clientPort) != *AlpcPortObjectType)\n            {\n                typeMismatch = TRUE;\n                clientPort = NULL;\n            }\n            else\n            {\n                ObReferenceObject(clientPort);\n            }\n        }\n    }\n\n    FltReleasePushLock(handleTableLock);\n\n    if (typeMismatch)\n    {\n        status = STATUS_OBJECT_TYPE_MISMATCH;\n        goto Exit;\n    }\n\n    *ConnectionPort = connectionPort;\n    connectionPort = NULL;\n    *ServerPort = serverPort;\n    serverPort = NULL;\n    *ClientPort = clientPort;\n    clientPort = NULL;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (connectionPort)\n    {\n        ObDereferenceObject(connectionPort);\n    }\n\n    if (serverPort)\n    {\n        ObDereferenceObject(serverPort);\n    }\n\n    if (clientPort)\n    {\n        ObDereferenceObject(clientPort);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Retrieves the basic information for an ALPC port.\n *\n * \\param[in] Dyn Dynamic configuration.\n * \\param[in] Port The ALPC port to get the basic information of.\n * \\param[out] Info Populated with the basic information.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpAlpcBasicInfo(\n    _In_ PKPH_DYN Dyn,\n    _In_ PVOID Port,\n    _Out_ PKPH_ALPC_BASIC_INFORMATION Info\n    )\n{\n    PEPROCESS process;\n    PVOID portObjectLock;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlZeroMemory(Info, sizeof(*Info));\n\n    if ((Dyn->AlpcOwnerProcess == ULONG_MAX) ||\n        (Dyn->AlpcPortObjectLock == ULONG_MAX))\n    {\n        return STATUS_NOINTERFACE;\n    }\n\n    //\n    // The OS uses the first bit of the OwnerProcess to denote if it is valid,\n    // if the first bit of the OwnerProcess is set is it invalid. Checking the\n    // bit should be done under the PortObjectLock.\n    // See: ntoskrnl!AlpcpPortQueryServerSessionInfo\n    //\n\n    portObjectLock = Add2Ptr(Port, Dyn->AlpcPortObjectLock);\n    FltAcquirePushLockShared(portObjectLock);\n\n    process = *(PEPROCESS*)Add2Ptr(Port, Dyn->AlpcOwnerProcess);\n    if (process && (((ULONG_PTR)process & 1) == 0))\n    {\n        Info->OwnerProcessId = PsGetProcessId(process);\n    }\n\n    FltReleasePushLock(portObjectLock);\n\n    if ((Dyn->AlpcAttributes != ULONG_MAX) &&\n        (Dyn->AlpcAttributesFlags != ULONG_MAX))\n    {\n        Info->Flags = *(PULONG)Add2Ptr(Add2Ptr(Port, Dyn->AlpcAttributes),\n                                       Dyn->AlpcAttributesFlags);\n    }\n\n    if (Dyn->AlpcPortContext != ULONG_MAX)\n    {\n        Info->PortContext = *(PVOID*)Add2Ptr(Port, Dyn->AlpcPortContext);\n    }\n\n    if (Dyn->AlpcSequenceNo != ULONG_MAX)\n    {\n        Info->SequenceNo = *(PULONG)Add2Ptr(Port, Dyn->AlpcSequenceNo);\n    }\n\n    if (Dyn->AlpcState != ULONG_MAX)\n    {\n        Info->State = *(PULONG)Add2Ptr(Port, Dyn->AlpcState);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Retrieves the communication information for an ALPC port.\n *\n * \\param[in] Dyn Dynamic configuration.\n * \\param[in] Port The ALPC port to get the information of.\n * \\param[out] Info Populated with the communication information.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpAlpcCommunicationInfo(\n    _In_ PKPH_DYN Dyn,\n    _In_ PVOID Port,\n    _Out_ PKPH_ALPC_COMMUNICATION_INFORMATION Info\n    )\n{\n    NTSTATUS status;\n    PVOID connectionPort;\n    PVOID serverPort;\n    PVOID clientPort;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlZeroMemory(Info, sizeof(*Info));\n\n    status = KphpReferenceAlpcCommunicationPorts(Dyn,\n                                                 Port,\n                                                 &connectionPort,\n                                                 &serverPort,\n                                                 &clientPort);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphpReferenceAlpcCommunicationPorts failed: %!STATUS!\",\n                      status);\n\n        connectionPort = NULL;\n        serverPort = NULL;\n        clientPort = NULL;\n        goto Exit;\n    }\n\n    if (connectionPort)\n    {\n        status = KphpAlpcBasicInfo(Dyn,\n                                   connectionPort,\n                                   &Info->ConnectionPort);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\n    if (serverPort)\n    {\n        status = KphpAlpcBasicInfo(Dyn,\n                                   serverPort,\n                                   &Info->ServerCommunicationPort);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\n    if (clientPort)\n    {\n        status = KphpAlpcBasicInfo(Dyn,\n                                   clientPort,\n                                   &Info->ClientCommunicationPort);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\nExit:\n\n    if (connectionPort)\n    {\n        ObDereferenceObject(connectionPort);\n    }\n\n    if (serverPort)\n    {\n        ObDereferenceObject(serverPort);\n    }\n\n    if (clientPort)\n    {\n        ObDereferenceObject(clientPort);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Utility function for copying the ALPC port name into an output string.\n *\n * \\param[in] Port The ALPC port to copy the name of.\n * \\param[in] NameBuffer Preallocated name buffer to use to get the name.\n * \\param[in,out] Buffer The space to write the string.\n * \\param[in,out] RemainingLength The remaining space to write the string.\n * \\param[in,out] ReturnLength Updated by number of bytes written or required.\n * \\param[out] String The string to populate.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpAlpcCopyPortName(\n    _In_ PVOID Port,\n    _In_bytecount_(KPH_ALPC_NAME_BUFFER_SIZE) POBJECT_NAME_INFORMATION NameBuffer,\n    _Inout_ PVOID* Buffer,\n    _Inout_ PULONG RemainingLength,\n    _Inout_ PULONG ReturnLength,\n    _Out_opt_ PUNICODE_STRING String\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (String)\n    {\n        RtlZeroMemory(String, sizeof(*String));\n    }\n\n    status = KphQueryNameObject(Port,\n                                NameBuffer,\n                                KPH_ALPC_NAME_BUFFER_SIZE,\n                                &returnLength);\n    if (!NT_SUCCESS(status) || (NameBuffer->Name.Length == 0))\n    {\n        //\n        // We're best effort here.\n        //\n        return STATUS_SUCCESS;\n    }\n\n    status = RtlULongAdd(*ReturnLength, NameBuffer->Name.Length, ReturnLength);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    if (!String || (NameBuffer->Name.Length > *RemainingLength))\n    {\n        //\n        // Success, return length is updated with the needed length.\n        //\n        return STATUS_SUCCESS;\n    }\n\n    String->Buffer = *Buffer;\n    String->MaximumLength = NameBuffer->Name.Length;\n    *Buffer = Add2Ptr(*Buffer, NameBuffer->Name.Length);\n    *RemainingLength -= NameBuffer->Name.Length;\n    RtlCopyUnicodeString(String, &NameBuffer->Name);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Retrieves the names of the communication ports for a given ALPC port.\n *\n * \\param[in] Dyn Dynamic configuration.\n * \\param[in] Port The port to retrieve the names of.\n * \\param[out] Info Populated with the name information.\n * \\param[in] InfoLength The length of the information buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpAlpcCommunicationNamesInfo(\n    _In_ PKPH_DYN Dyn,\n    _In_ PVOID Port,\n    _Out_writes_bytes_opt_(InfoLength) PKPH_ALPC_COMMUNICATION_NAMES_INFORMATION Info,\n    _In_ ULONG InfoLength,\n    _Out_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    POBJECT_NAME_INFORMATION nameBuffer;\n    PVOID connectionPort;\n    PVOID serverPort;\n    PVOID clientPort;\n    PVOID buffer;\n    ULONG remainingLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    *ReturnLength = sizeof(KPH_ALPC_COMMUNICATION_NAMES_INFORMATION);\n\n    nameBuffer = NULL;\n\n    if (Info && (InfoLength >= sizeof(KPH_ALPC_COMMUNICATION_NAMES_INFORMATION)))\n    {\n        RtlZeroMemory(Info, sizeof(KPH_ALPC_COMMUNICATION_NAMES_INFORMATION));\n        remainingLength = (InfoLength - sizeof(KPH_ALPC_COMMUNICATION_NAMES_INFORMATION));\n        buffer = Add2Ptr(Info, sizeof(KPH_ALPC_COMMUNICATION_NAMES_INFORMATION));\n    }\n    else\n    {\n        remainingLength = 0;\n        buffer = NULL;\n    }\n\n    status = KphpReferenceAlpcCommunicationPorts(Dyn,\n                                                 Port,\n                                                 &connectionPort,\n                                                 &serverPort,\n                                                 &clientPort);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphpReferenceAlpcCommunicationPorts failed: %!STATUS!\",\n                      status);\n\n        connectionPort = NULL;\n        serverPort = NULL;\n        clientPort = NULL;\n        goto Exit;\n    }\n\n    nameBuffer = KphAllocatePaged(KPH_ALPC_NAME_BUFFER_SIZE,\n                                  KPH_TAG_ALPC_NAME_QUERY);\n    if (!nameBuffer)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    if (connectionPort)\n    {\n        status = KphpAlpcCopyPortName(connectionPort,\n                                      nameBuffer,\n                                      &buffer,\n                                      &remainingLength,\n                                      ReturnLength,\n                                      (Info ? &Info->ConnectionPort : NULL));\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\n    if (serverPort)\n    {\n        status = KphpAlpcCopyPortName(serverPort,\n                                      nameBuffer,\n                                      &buffer,\n                                      &remainingLength,\n                                      ReturnLength,\n                                      (Info ? &Info->ServerCommunicationPort : NULL));\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\n    if (clientPort)\n    {\n        status = KphpAlpcCopyPortName(clientPort,\n                                      nameBuffer,\n                                      &buffer,\n                                      &remainingLength,\n                                      ReturnLength,\n                                      (Info ? &Info->ClientCommunicationPort : NULL));\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\n    if (*ReturnLength > InfoLength)\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n    }\n    else\n    {\n        status = STATUS_SUCCESS;\n    }\n\nExit:\n\n    if (nameBuffer)\n    {\n        KphFree(nameBuffer, KPH_TAG_ALPC_NAME_QUERY);\n    }\n\n    if (connectionPort)\n    {\n        ObDereferenceObject(connectionPort);\n    }\n\n    if (serverPort)\n    {\n        ObDereferenceObject(serverPort);\n    }\n\n    if (clientPort)\n    {\n        ObDereferenceObject(clientPort);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries information about an ALPC port.\n *\n * \\param[in] ProceessHandle Handle to the process where the ALPC handle resides.\n * \\param[in] PortHandle Handle to the ALPC port to query.\n * \\param[in] AlpcInformationClass Information class to query.\n * \\param[out] AlpcInformation Populated with information by ALPC port.\n * \\param[in] AlpcInformationLength Length of the ALPC information buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAlpcQueryInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE PortHandle,\n    _In_ KPH_ALPC_INFORMATION_CLASS AlpcInformationClass,\n    _Out_writes_bytes_opt_(AlpcInformationLength) PVOID AlpcInformation,\n    _In_ ULONG AlpcInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    PEPROCESS process;\n    KAPC_STATE apcState;\n    PVOID port;\n    ULONG returnLength;\n    PVOID buffer;\n    BYTE stackBuffer[64];\n    KPROCESSOR_MODE accessMode;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = NULL;\n    port = NULL;\n    returnLength = 0;\n    buffer = NULL;\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        process = NULL;\n        goto Exit;\n    }\n\n    if (process == PsInitialSystemProcess)\n    {\n        PortHandle = MakeKernelHandle(PortHandle);\n        accessMode = KernelMode;\n    }\n    else\n    {\n        if (IsKernelHandle(PortHandle))\n        {\n            status = STATUS_INVALID_HANDLE;\n            goto Exit;\n        }\n        accessMode = AccessMode;\n    }\n\n    KeStackAttachProcess(process, &apcState);\n    status = ObReferenceObjectByHandle(PortHandle,\n                                       0,\n                                       *AlpcPortObjectType,\n                                       accessMode,\n                                       &port,\n                                       NULL);\n    KeUnstackDetachProcess(&apcState);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        port = NULL;\n        goto Exit;\n    }\n\n    switch (AlpcInformationClass)\n    {\n        case KphAlpcBasicInformation:\n        {\n            KPH_ALPC_BASIC_INFORMATION info;\n\n            dyn = KphReferenceDynData();\n            if (!dyn)\n            {\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            if (!AlpcInformation ||\n                (AlpcInformationLength < sizeof(KPH_ALPC_BASIC_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_ALPC_BASIC_INFORMATION);\n                goto Exit;\n            }\n\n            status = KphpAlpcBasicInfo(dyn, port, &info);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"KphpAlpcBasicInfo failed: %!STATUS!\",\n                              status);\n                goto Exit;\n            }\n\n            status = KphCopyToMode(AlpcInformation,\n                                   &info,\n                                   sizeof(KPH_ALPC_BASIC_INFORMATION),\n                                   AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_ALPC_BASIC_INFORMATION);\n            }\n\n            break;\n        }\n        case KphAlpcCommunicationInformation:\n        {\n            KPH_ALPC_COMMUNICATION_INFORMATION info;\n\n            dyn = KphReferenceDynData();\n            if (!dyn)\n            {\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            if (!AlpcInformation ||\n                (AlpcInformationLength < sizeof(KPH_ALPC_COMMUNICATION_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_ALPC_COMMUNICATION_INFORMATION);\n                goto Exit;\n            }\n\n            status = KphpAlpcCommunicationInfo(dyn, port, &info);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"KphpAlpcCommunicationInfo failed: %!STATUS!\",\n                              status);\n                goto Exit;\n            }\n\n            status = KphCopyToMode(AlpcInformation,\n                                   &info,\n                                   sizeof(KPH_ALPC_COMMUNICATION_INFORMATION),\n                                   AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_ALPC_COMMUNICATION_INFORMATION);\n            }\n\n            break;\n        }\n        case KphAlpcCommunicationNamesInformation:\n        {\n            ULONG allocatedSize;\n            PKPH_ALPC_COMMUNICATION_NAMES_INFORMATION info;\n\n            dyn = KphReferenceDynData();\n            if (!dyn)\n            {\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            allocatedSize = AlpcInformationLength;\n            if (allocatedSize < sizeof(KPH_ALPC_COMMUNICATION_NAMES_INFORMATION))\n            {\n                allocatedSize = sizeof(KPH_ALPC_COMMUNICATION_NAMES_INFORMATION);\n            }\n\n            buffer = KphAllocatePagedA(allocatedSize,\n                                       KPH_TAG_ALPC_QUERY,\n                                       stackBuffer);\n            if (!buffer)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            info = buffer;\n            status = KphpAlpcCommunicationNamesInfo(dyn,\n                                                    port,\n                                                    info,\n                                                    AlpcInformationLength,\n                                                    &returnLength);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"KphpAlpcCommunicationNamesInfo failed: %!STATUS!\",\n                              status);\n                goto Exit;\n            }\n\n            if (!AlpcInformation)\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n                goto Exit;\n            }\n\n            RebaseUnicodeString(&info->ConnectionPort,\n                                buffer,\n                                AlpcInformation);\n            RebaseUnicodeString(&info->ServerCommunicationPort,\n                                buffer,\n                                AlpcInformation);\n            RebaseUnicodeString(&info->ClientCommunicationPort,\n                                buffer,\n                                AlpcInformation);\n\n            status = KphCopyToMode(AlpcInformation,\n                                   info,\n                                   returnLength,\n                                   AccessMode);\n\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n\nExit:\n\n    if (buffer)\n    {\n        KphFreeA(buffer, KPH_TAG_ALPC_QUERY, stackBuffer);\n    }\n\n    if (port)\n    {\n        ObDereferenceObject(port);\n    }\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    if (dyn)\n    {\n        KphDereferenceObject(dyn);\n    }\n\n    if (ReturnLength)\n    {\n        KphWriteULongToMode(ReturnLength, returnLength, AccessMode);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/back_trace.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_STACK_BACK_TRACE_OBJECT\n{\n    KSI_KAPC Apc;\n    KEVENT CompletedEvent;\n    ULONG FramesToSkip;\n    ULONG FramesToCapture;\n    ULONG CapturedFrames;\n    ULONG BackTraceHash;\n    ULONG Flags;\n    BOOLEAN DoHash;\n    PKPH_THREAD_CONTEXT Thread;\n    PVOID BackTrace[ANYSIZE_ARRAY];\n} KPH_STACK_BACK_TRACE_OBJECT, *PKPH_STACK_BACK_TRACE_OBJECT;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpStackBackTraceTypeName = RTL_CONSTANT_STRING(L\"KphStackBackTrace\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PVOID KphpSelfImageBase = NULL;\nstatic PVOID KphpSelfImageEnd = NULL;\nstatic PVOID KphpKsiImageBase = NULL;\nstatic PVOID KphpKsiImageEnd = NULL;\nstatic PKPH_OBJECT_TYPE KphpStackBackTraceType = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\n\n//\n// Sentinel value inserted into the stack back trace when part of the stack\n// couldn't be captured for some reason.\n//\n#define KPH_STACK_SENTINEL_FRAME ((PVOID)(ULONG_PTR)0xbad)\n\n/**\n * \\brief Tries to add a sentinel frame to the stack back trace.\n *\n * \\param[in] FramesToCapture The number of frames to capture.\n * \\param[out] BackTrace Buffer to store the back trace in.\n * \\param[in,out] Frames On input, the number of frames captured so far. If a\n * sentinel frame is added, this is incremented.\n * \\param[in] Flags A combination of KPH_STACK_BACK_TRACE_* flags.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphpTryAddSentinelFrame(\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID* BackTrace,\n    _Inout_ PULONG Frames,\n    _In_ ULONG Flags\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (FlagOn(Flags, KPH_STACK_BACK_TRACE_NO_SENTINEL))\n    {\n        return;\n    }\n\n    if (*Frames < FramesToCapture)\n    {\n        BackTrace[*Frames] = KPH_STACK_SENTINEL_FRAME;\n        (*Frames)++;\n    }\n}\n\n/**\n * \\brief Captures a stack back trace.\n *\n * \\param[in] FramesToSkip The number of kernel frames to skip.\n * \\param[in] FramesToCapture The number of frames to capture.\n * \\param[out] BackTrace Buffer to store the back trace in.\n * \\param[out] BackTraceHash Optionally receives a hash of the back trace.\n * \\param[in] Flags A combination of KPH_STACK_BACK_TRACE_* flags.\n * \\param[in] Thread Optional thread context of the target thread, used for\n * internal tracking to prevent accidental recursion.\n *\n * \\return The number of captured frames.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Success_(return != 0)\nULONG KphpCaptureStackBackTrace(\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID* BackTrace,\n    _Out_opt_ PULONG BackTraceHash,\n    _In_ ULONG Flags,\n    _In_opt_ PKPH_THREAD_CONTEXT Thread\n    )\n{\n    ULONG frames;\n    ULONG skip;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    FramesToSkip += 1;\n\n    skip = (FramesToSkip << RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT);\n\n    frames = RtlWalkFrameChain(BackTrace, FramesToCapture, skip);\n\n    if (frames <= FramesToSkip)\n    {\n        frames = 0;\n        goto ContinueCapture;\n    }\n\n    frames -= FramesToSkip;\n\n    if (FlagOn(Flags, KPH_STACK_BACK_TRACE_SKIP_KPH))\n    {\n        for (skip = 0; skip < frames; skip++)\n        {\n            if (((BackTrace[skip] < KphpSelfImageBase) ||\n                 (BackTrace[skip] >= KphpSelfImageEnd)) &&\n                ((BackTrace[skip] < KphpKsiImageBase) ||\n                 (BackTrace[skip] >= KphpKsiImageEnd)))\n            {\n                break;\n            }\n        }\n\n        if (frames <= skip)\n        {\n            frames = 0;\n            goto ContinueCapture;\n        }\n\n        frames -= skip;\n        RtlMoveMemory(BackTrace, &BackTrace[skip], frames * sizeof(PVOID));\n    }\n\nContinueCapture:\n\n    if (!FlagOn(Flags, KPH_STACK_BACK_TRACE_USER_MODE) ||\n        (KeGetCurrentIrql() == DISPATCH_LEVEL))\n    {\n        goto Exit;\n    }\n\n    if (!Thread)\n    {\n        KphpTryAddSentinelFrame(FramesToCapture, BackTrace, &frames, Flags);\n        goto Exit;\n    }\n\n    NT_ASSERT(Thread->EThread == PsGetCurrentThread());\n\n    //\n    // N.B. This path can become accidentally recursive if the user mode stack\n    // needs to be paged in and another kernel callback lands here again. In\n    // that case skip the capture.\n    //\n    if (Thread->CapturingUserModeStack)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Skipping user mode stack capture for \"\n                      \"thread %lu in process %wZ (%lu)\",\n                      HandleToULong(Thread->ClientId.UniqueThread),\n                      KphGetThreadImageName(Thread),\n                      HandleToULong(Thread->ClientId.UniqueProcess));\n\n        KphpTryAddSentinelFrame(FramesToCapture, BackTrace, &frames, Flags);\n        goto Exit;\n    }\n\n    Thread->CapturingUserModeStack = TRUE;\n\n    __try\n    {\n        frames += RtlWalkFrameChain(&BackTrace[frames],\n                                    FramesToCapture - frames,\n                                    RTL_WALK_USER_MODE_STACK);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        KphpTryAddSentinelFrame(FramesToCapture, BackTrace, &frames, Flags);\n    }\n\n    Thread->CapturingUserModeStack = FALSE;\n\nExit:\n\n    NT_ASSERT(frames <= FramesToCapture);\n\n    if (BackTraceHash)\n    {\n        *BackTraceHash = 0;\n\n        for (ULONG i = 0; i < frames; i++)\n        {\n#pragma prefast(suppress: 6385)\n            *BackTraceHash += PtrToUlong(BackTrace[i]);\n        }\n    }\n\n    return frames;\n}\n\n/**\n * \\brief Captures a stack back trace.\n *\n * \\param[in] FramesToSkip The number of kernel frames to skip.\n * \\param[in] FramesToCapture The number of frames to capture.\n * \\param[out] BackTrace Buffer to store the back trace in.\n * \\param[out] BackTraceHash Optionally receives a hash of the back trace.\n * \\param[in] Flags A combination of KPH_STACK_BACK_TRACE_* flags.\n *\n * \\return The number of captured frames.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Success_(return != 0)\nULONG KphCaptureStackBackTrace(\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID* BackTrace,\n    _Out_opt_ PULONG BackTraceHash,\n    _In_ ULONG Flags\n    )\n{\n    ULONG frames;\n    PKPH_THREAD_CONTEXT thread;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (FlagOn(Flags, KPH_STACK_BACK_TRACE_USER_MODE) &&\n        (KeGetCurrentIrql() < DISPATCH_LEVEL))\n    {\n        thread = KphGetCurrentThreadContext();\n    }\n    else\n    {\n        thread = NULL;\n    }\n\n    frames = KphpCaptureStackBackTrace(FramesToSkip,\n                                       FramesToCapture,\n                                       BackTrace,\n                                       BackTraceHash,\n                                       Flags,\n                                       thread);\n\n    if (thread)\n    {\n        KphDereferenceObject(thread);\n    }\n\n    return frames;\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Captures the current stack back trace into a back trace object.\n *\n * \\param[in,out] BackTrace The back trace object to populate.\n */\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KphpCaptureStackBackTraceIntoObject(\n    _Inout_ PKPH_STACK_BACK_TRACE_OBJECT BackTrace\n    )\n{\n    PULONG backTraceHash;\n    ULONG capturedFrames;\n\n    KPH_PAGED_CODE_APC();\n\n    if (BackTrace->DoHash)\n    {\n        backTraceHash = &BackTrace->BackTraceHash;\n    }\n    else\n    {\n        backTraceHash = NULL;\n    }\n\n    capturedFrames = KphpCaptureStackBackTrace(BackTrace->FramesToSkip,\n                                               BackTrace->FramesToCapture,\n                                               BackTrace->BackTrace,\n                                               backTraceHash,\n                                               BackTrace->Flags,\n                                               BackTrace->Thread);\n\n    BackTrace->CapturedFrames = capturedFrames;\n\n    KeSetEvent(&BackTrace->CompletedEvent, EVENT_INCREMENT, FALSE);\n}\n\n/**\n * \\brief APC routine for capturing the stack back trace of a thread.\n *\n * \\param[in] Apc The ACP executed, contained within the back trace object.\n * \\param[in] NormalRoutine Unused.\n * \\param[in] NormalContext Unused.\n * \\param[in] SystemArgument1 Unused.\n * \\param[in] SystemArgument2 Unused.\n */\n_Function_class_(KSI_KKERNEL_ROUTINE)\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpCaptureStackBackTraceThreadSpecialApc(\n    _In_ PKSI_KAPC Apc,\n    _Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE *NormalRoutine,\n    _Inout_ _Deref_pre_maybenull_ PVOID *NormalContext,\n    _Inout_ _Deref_pre_maybenull_ PVOID *SystemArgument1,\n    _Inout_ _Deref_pre_maybenull_ PVOID *SystemArgument2\n    )\n{\n    PKPH_STACK_BACK_TRACE_OBJECT backTrace;\n\n    KPH_PAGED_CODE_APC();\n\n    UNREFERENCED_PARAMETER(NormalRoutine);\n    UNREFERENCED_PARAMETER(NormalContext);\n    UNREFERENCED_PARAMETER(SystemArgument1);\n    UNREFERENCED_PARAMETER(SystemArgument2);\n\n    backTrace = CONTAINING_RECORD(Apc, KPH_STACK_BACK_TRACE_OBJECT, Apc);\n\n    KphpCaptureStackBackTraceIntoObject(backTrace);\n}\n\n/**\n * \\brief APC cleanup routine for stack back trace capture.\n *\n * \\param[in] Apc The ACP to clean up.\n * \\param[in] Reason Unused.\n */\n_Function_class_(KSI_KCLEANUP_ROUTINE)\n_IRQL_requires_min_(PASSIVE_LEVEL)\n_IRQL_requires_max_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpCaptureStackBackTraceThreadSpecialApcCleanup(\n    _In_ PKSI_KAPC Apc,\n    _In_ KSI_KAPC_CLEANUP_REASON Reason\n    )\n{\n    PKPH_STACK_BACK_TRACE_OBJECT backTrace;\n\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(Apc);\n    DBG_UNREFERENCED_PARAMETER(Reason);\n\n    backTrace = CONTAINING_RECORD(Apc, KPH_STACK_BACK_TRACE_OBJECT, Apc);\n\n    KphDereferenceObject(backTrace);\n}\n\n/**\n * \\brief Allocates a stack back trace object.\n *\n * \\param[in] Size The size to allocate.\n *\n * \\return Allocated object, null on allocation failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpStackBackTraceAllocate(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_PAGED_CODE();\n\n    return KphAllocateNPaged(Size, KPH_TAG_BACK_TRACE_OBJECT);\n}\n\n/**\n * \\brief Frees a stack back trace object.\n *\n * \\param[in] Object The stack back trace object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\nVOID KSIAPI KphpStackBackTraceFree(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphFree(Object, KPH_TAG_BACK_TRACE_OBJECT);\n}\n\n/**\n * \\brief Initializes a stack back trace object.\n *\n * \\param[in,out] Object The stack back trace object to initialize.\n * \\param[in] Parameter The thread to initialize the back trace object for.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpStackBackTraceInitialize(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_STACK_BACK_TRACE_OBJECT backTrace;\n    PETHREAD thread;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Parameter);\n\n    backTrace = Object;\n    thread = Parameter;\n\n    KsiInitializeApc(&backTrace->Apc,\n                     KphDriverObject,\n                     thread,\n                     OriginalApcEnvironment,\n                     KphpCaptureStackBackTraceThreadSpecialApc,\n                     KphpCaptureStackBackTraceThreadSpecialApcCleanup,\n                     NULL,\n                     KernelMode,\n                     NULL);\n\n    KeInitializeEvent(&backTrace->CompletedEvent, NotificationEvent, FALSE);\n\n    backTrace->Thread = KphGetEThreadContext(thread);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Deletes a stack back trace object.\n *\n * \\param[in] Object The stack back trace object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\nVOID KSIAPI KphpStackBackTraceDelete(\n    _Inout_ PVOID Object\n    )\n{\n    PKPH_STACK_BACK_TRACE_OBJECT backTrace;\n\n    KPH_PAGED_CODE();\n\n    backTrace = Object;\n\n    if (backTrace->Thread)\n    {\n        KphDereferenceObject(backTrace->Thread);\n    }\n}\n\n/**\n * \\brief Captures a stack back trace for a given thread.\n *\n * \\param[in] Thread The thread to capture the stack back trace of.\n * \\param[in] FramesToSkip The number of kernel frames to skip.\n * \\param[in] FramesToCapture The number of frames to capture.\n * \\param[out] BackTrace Buffer to store the back trace in.\n * \\param[out] CapturedFrames Receives the number of captured frames.\n * \\param[out] BackTraceHash Optionally receives a hash of the back trace.\n * \\param[in] Flags A combination of KPH_STACK_BACK_TRACE_* flags.\n * \\param[in] Timeout Optionally specifies a timeout for the capture operation.\n *\n * \\return STATUS_SUCCES, STATUS_TIMEOUT, or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCaptureStackBackTraceThread(\n    _In_ PETHREAD Thread,\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID* BackTrace,\n    _Out_ PULONG CapturedFrames,\n    _Out_opt_ PULONG BackTraceHash,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n    ULONG backTraceSize;\n    PKPH_STACK_BACK_TRACE_OBJECT backTrace;\n\n    KPH_PAGED_CODE();\n\n    if (Thread == PsGetCurrentThread())\n    {\n        *CapturedFrames = KphCaptureStackBackTrace(FramesToSkip,\n                                                   FramesToCapture,\n                                                   BackTrace,\n                                                   BackTraceHash,\n                                                   Flags);\n        return (*CapturedFrames ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);\n    }\n\n    NT_ASSERT(KphpStackBackTraceType);\n\n    *CapturedFrames = 0;\n\n    if (BackTraceHash)\n    {\n        *BackTraceHash = 0;\n    }\n\n    backTrace = NULL;\n\n    status = RtlULongAdd(FramesToCapture,\n                         sizeof(KPH_STACK_BACK_TRACE_OBJECT),\n                         &backTraceSize);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"RtlULongAdd failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = KphCreateObject(KphpStackBackTraceType,\n                             backTraceSize,\n                             &backTrace,\n                             Thread);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        backTrace = NULL;\n        goto Exit;\n    }\n\n    backTrace->FramesToCapture = FramesToCapture;\n    backTrace->FramesToSkip = FramesToSkip;\n    backTrace->Flags = Flags;\n    backTrace->DoHash = (BackTraceHash != NULL);\n\n    //\n    // The APC could fire immediately we must reference before trying to queue.\n    //\n    KphReferenceObject(backTrace);\n    if (!KsiInsertQueueApc(&backTrace->Apc, NULL, NULL, IO_NO_INCREMENT))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KsiInsertQueueApc failed\");\n\n        KphDereferenceObject(backTrace);\n        status = STATUS_UNSUCCESSFUL;\n        goto Exit;\n    }\n\n    status = KeWaitForSingleObject(&backTrace->CompletedEvent,\n                                   Executive,\n                                   KernelMode,\n                                   FALSE,\n                                   Timeout);\n    if (status != STATUS_SUCCESS)\n    {\n        NTSTATUS removeStatus;\n\n        NT_ASSERT(status == STATUS_TIMEOUT);\n\n        removeStatus = KsiRemoveQueueApc(&backTrace->Apc);\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KsiRemoveQueueApc: %!STATUS!\",\n                      removeStatus);\n\n        goto Exit;\n    }\n\n    NT_ASSERT(backTrace->CapturedFrames <= FramesToCapture);\n\n    RtlCopyMemory(BackTrace,\n                  backTrace->BackTrace,\n                  backTrace->CapturedFrames * sizeof(PVOID));\n\n    *CapturedFrames = backTrace->CapturedFrames;\n\n    if (BackTraceHash)\n    {\n        *BackTraceHash = backTrace->BackTraceHash;\n    }\n\nExit:\n\n    if (backTrace)\n    {\n        KphDereferenceObject(backTrace);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Initialized stack back trace infrastructure.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphInitializeStackBackTrace(\n    VOID\n    )\n{\n    NTSTATUS status;\n    KPH_OBJECT_TYPE_INFO typeInfo;\n    SYSTEM_SINGLE_MODULE_INFORMATION info;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    typeInfo.Allocate = KphpStackBackTraceAllocate;\n    typeInfo.Initialize = KphpStackBackTraceInitialize;\n    typeInfo.Delete = KphpStackBackTraceDelete;\n    typeInfo.Free = KphpStackBackTraceFree;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpStackBackTraceTypeName,\n                        &typeInfo,\n                        &KphpStackBackTraceType);\n\n    RtlZeroMemory(&info, sizeof(SYSTEM_SINGLE_MODULE_INFORMATION));\n\n    info.TargetModuleAddress = (PVOID)KphInitializeStackBackTrace;\n    status = ZwQuerySystemInformation(SystemSingleModuleInformation,\n                                      &info,\n                                      sizeof(SYSTEM_SINGLE_MODULE_INFORMATION),\n                                      NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ZwQuerySystemInformation failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    KphpSelfImageBase = info.ExInfo.BaseInfo.ImageBase;\n    KphpSelfImageEnd = Add2Ptr(KphpSelfImageBase, info.ExInfo.BaseInfo.ImageSize);\n\n    RtlZeroMemory(&info, sizeof(SYSTEM_SINGLE_MODULE_INFORMATION));\n\n    info.TargetModuleAddress = (PVOID)KsiInitializeApc;\n    status = ZwQuerySystemInformation(SystemSingleModuleInformation,\n                                      &info,\n                                      sizeof(SYSTEM_SINGLE_MODULE_INFORMATION),\n                                      NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ZwQuerySystemInformation failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    KphpKsiImageBase = info.ExInfo.BaseInfo.ImageBase;\n    KphpKsiImageEnd = Add2Ptr(KphpKsiImageBase, info.ExInfo.BaseInfo.ImageSize);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "KSystemInformer/cid_table.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\n#define KPH_CID_TABLE_LEVEL_MASK ((ULONG_PTR)3)\n#define KPH_CID_TABLE_L0 ((ULONG_PTR)0)\n#define KPH_CID_TABLE_L1 ((ULONG_PTR)1)\n#define KPH_CID_TABLE_L2 ((ULONG_PTR)2)\n#define KPH_CID_TABLE_POINTER_MASK ~KPH_CID_TABLE_LEVEL_MASK\n\n#define KPH_CID_LIMIT (1 << 24)\n\n#define KPH_CID_L0_COUNT (PAGE_SIZE / sizeof(KPH_CID_TABLE_ENTRY))\n#define KPH_CID_L1_COUNT (PAGE_SIZE / sizeof(PKPH_CID_TABLE_ENTRY))\n#define KPH_CID_L2_COUNT (KPH_CID_LIMIT / (KPH_CID_L0_COUNT * KPH_CID_L1_COUNT))\n\n#define KPH_CID_MAX_L0 KPH_CID_L0_COUNT\n#define KPH_CID_MAX_L1 (KPH_CID_L1_COUNT * KPH_CID_L0_COUNT)\n#define KPH_CID_MAX_L2 (KPH_CID_L2_COUNT * KPH_CID_L1_COUNT * KPH_CID_L0_COUNT)\n\n#define KPH_CID_MAX KPH_CID_MAX_L2\nC_ASSERT(KPH_CID_MAX == KPH_CID_LIMIT);\n\n#define KphpCidToId(x) ((ULONG_PTR)x / 4)\n\n/**\n * \\brief Assigns an object to the table entry.\n *\n * \\param[in,out] Entry The entry to assign to.\n * \\param[in] Object Optional object pointer to assign into the table entry.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCidAssignObject(\n    _Inout_ PKPH_CID_TABLE_ENTRY Entry,\n    _In_opt_ PVOID Object\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    KphAtomicAssignObjectReference(&Entry->ObjectRef, Object);\n}\n\n/**\n * \\brief References the object in the table entry.\n *\n * \\param[in,out] Entry The entry to reference the object of.\n *\n * \\return Referenced object pointer, NULL if no object is assigned.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPVOID KphCidReferenceObject(\n    _In_ PKPH_CID_TABLE_ENTRY Entry\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    return KphAtomicReferenceObject(&Entry->ObjectRef);\n}\n\n/**\n * \\brief Allocates a CID table for a given level.\n *\n * \\param[in] Level The level to allocate for.\n *\n * \\return Allocated table or null on allocation failure.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_When_(Level == KPH_CID_TABLE_L0, _Return_allocatesMem_size_(KPH_CID_L0_COUNT * sizeof(KPH_CID_TABLE_ENTRY)))\n_When_(Level == KPH_CID_TABLE_L1, _Return_allocatesMem_size_(KPH_CID_L1_COUNT * sizeof(PKPH_CID_TABLE_ENTRY)))\n_When_(Level == KPH_CID_TABLE_L2, _Return_allocatesMem_size_(KPH_CID_L2_COUNT * sizeof(PKPH_CID_TABLE_ENTRY)))\nPVOID KphpCidAllocateTable(\n    _In_ ULONG_PTR Level\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    switch (Level)\n    {\n        case KPH_CID_TABLE_L0:\n        {\n            return KphAllocateNPaged(KPH_CID_L0_COUNT * sizeof(KPH_CID_TABLE_ENTRY),\n                                     KPH_TAG_CID_TABLE);\n        }\n        case KPH_CID_TABLE_L1:\n        {\n            return KphAllocateNPaged(KPH_CID_L1_COUNT * sizeof(PKPH_CID_TABLE_ENTRY),\n                                     KPH_TAG_CID_TABLE);\n        }\n        case KPH_CID_TABLE_L2:\n        {\n            return KphAllocateNPaged(KPH_CID_L2_COUNT * sizeof(PKPH_CID_TABLE_ENTRY),\n                                     KPH_TAG_CID_TABLE);\n        }\n        default:\n        {\n            NT_ASSERT(FALSE);\n            break;\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * \\brief Creates and initializes a CID table\n *\n * \\param[out] Table The table to create an initialize.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCidTableCreate(\n    _Out_ PKPH_CID_TABLE Table\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    Table->Table = (ULONG_PTR)KphpCidAllocateTable(KPH_CID_TABLE_L0);\n    if (!Table->Table)\n    {\n        return STATUS_INSUFFICIENT_RESOURCES;\n    }\n\n    KeInitializeSpinLock(&Table->Lock);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Deletes a CID table.\n *\n * \\param[in] Table The table to delete.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCidTableDelete(\n    _In_ PKPH_CID_TABLE Table\n    )\n{\n    ULONG_PTR tableCode;\n    PKPH_CID_TABLE_ENTRY tableL0;\n    PKPH_CID_TABLE_ENTRY* tableL1;\n    PKPH_CID_TABLE_ENTRY** tableL2;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    tableCode = ReadULongPtrAcquire(&Table->Table);\n\n    if (!tableCode)\n    {\n        return;\n    }\n\n    switch (tableCode & KPH_CID_TABLE_LEVEL_MASK)\n    {\n        case KPH_CID_TABLE_L0:\n        {\n            tableL0 = (PKPH_CID_TABLE_ENTRY)(tableCode & KPH_CID_TABLE_POINTER_MASK);\n\n            NT_ASSERT(tableL0);\n\n            KphFree(tableL0, KPH_TAG_CID_TABLE);\n\n            break;\n        }\n        case KPH_CID_TABLE_L1:\n        {\n            tableL1 = (PKPH_CID_TABLE_ENTRY*)(tableCode & KPH_CID_TABLE_POINTER_MASK);\n\n            NT_ASSERT(tableL1);\n\n            for (ULONG i = 0; i < KPH_CID_L1_COUNT; i++)\n            {\n#pragma prefast(suppress : 6001) // memory is initialized\n                if (tableL1[i])\n                {\n                    KphFree(tableL1[i], KPH_TAG_CID_TABLE);\n                }\n            }\n\n            KphFree(tableL1, KPH_TAG_CID_TABLE);\n\n            break;\n        }\n        case KPH_CID_TABLE_L2:\n        {\n            tableL2 = (PKPH_CID_TABLE_ENTRY**)(tableCode & KPH_CID_TABLE_POINTER_MASK);\n\n            NT_ASSERT(tableL2);\n\n            for (ULONG i = 0; i < KPH_CID_L2_COUNT; i++)\n            {\n                tableL1 = tableL2[i];\n                if (!tableL1)\n                {\n                    continue;\n                }\n\n                for (ULONG j = 0; j < KPH_CID_L1_COUNT; j++)\n                {\n#pragma prefast(suppress : 6001) // memory is initialized\n                    if (tableL1[j])\n                    {\n                        KphFree(tableL1[j], KPH_TAG_CID_TABLE);\n                    }\n                }\n\n                KphFree(tableL1, KPH_TAG_CID_TABLE);\n            }\n\n            KphFree(tableL2, KPH_TAG_CID_TABLE);\n\n            break;\n        }\n        default:\n        {\n            NT_ASSERT(FALSE);\n            break;\n        }\n    }\n}\n\n/**\n * \\brief Looks up an entry in the CID table.\n *\n * \\param[in] Cid The CID to look up the entry of.\n * \\param[in] Table The table to look up the CID in.\n *\n * \\return Pointer to the CID table entry, null if the table hasn't been\n * expanded enough.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nPKPH_CID_TABLE_ENTRY KphpCidLookupEntry(\n    _In_ HANDLE Cid,\n    _In_ PKPH_CID_TABLE Table\n    )\n{\n    ULONG_PTR table;\n    PKPH_CID_TABLE_ENTRY tableL0;\n    PKPH_CID_TABLE_ENTRY* tableL1;\n    PKPH_CID_TABLE_ENTRY** tableL2;\n    ULONG_PTR id;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    id = KphpCidToId(Cid);\n\n    table = ReadULongPtrAcquire(&Table->Table);\n\n    switch (table & KPH_CID_TABLE_LEVEL_MASK)\n    {\n        case KPH_CID_TABLE_L0:\n        {\n            if (id >= KPH_CID_MAX_L0)\n            {\n                return NULL;\n            }\n\n            tableL0 = (PKPH_CID_TABLE_ENTRY)(table & KPH_CID_TABLE_POINTER_MASK);\n\n            return &tableL0[id];\n        }\n        case KPH_CID_TABLE_L1:\n        {\n            if (id >= KPH_CID_MAX_L1)\n            {\n                return NULL;\n            }\n\n            tableL1 = (PKPH_CID_TABLE_ENTRY*)(table & KPH_CID_TABLE_POINTER_MASK);\n            tableL0 = tableL1[id / KPH_CID_MAX_L0];\n            if (!tableL0)\n            {\n                return NULL;\n            }\n\n            return &tableL0[id % KPH_CID_MAX_L0];\n        }\n        case KPH_CID_TABLE_L2:\n        {\n            if (id >= KPH_CID_MAX_L2)\n            {\n                return NULL;\n            }\n\n            tableL2 = (PKPH_CID_TABLE_ENTRY**)(table & KPH_CID_TABLE_POINTER_MASK);\n            tableL1 = tableL2[id / KPH_CID_MAX_L1];\n            if (!tableL1)\n            {\n                return NULL;\n            }\n\n            tableL0 = tableL1[(id % KPH_CID_MAX_L1) / KPH_CID_MAX_L0];\n            if (!tableL0)\n            {\n                return NULL;\n            }\n\n            return &tableL0[(id % KPH_CID_MAX_L1) % KPH_CID_MAX_L0];\n        }\n        default:\n        {\n            NT_ASSERT(FALSE);\n            return NULL;\n        }\n    }\n}\n\n/**\n * \\brief Expands a CID table making it capable of holding an entry for a CID.\n *\n * \\param[in] Cid The CID for which the table should be expanded for.\n * \\param[in,out] Table The table that should be expanded to hold the CID.\n *\n * \\return Pointer to the table entry for the CID, null on allocation failure.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nPKPH_CID_TABLE_ENTRY KphpCidExpandTableFor(\n    _In_ HANDLE Cid,\n    _Inout_ PKPH_CID_TABLE Table\n    )\n{\n    PKPH_CID_TABLE_ENTRY entry;\n    ULONG_PTR table;\n    ULONG_PTR level;\n    PKPH_CID_TABLE_ENTRY tableL0;\n    PKPH_CID_TABLE_ENTRY* tableL1;\n    PKPH_CID_TABLE_ENTRY** tableL2;\n    ULONG_PTR id;\n    KIRQL oldIrql;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    id = KphpCidToId(Cid);\n\n    if (id >= KPH_CID_MAX)\n    {\n        //\n        // We can't, as of now, service CIDs over the maximum. It is extremely\n        // unlikely we'll ever get here. The system is likely to run out of\n        // memory before this happens. It also should be impossible given the\n        // limit enforced by handle tables for PspCidTable. Unless Microsoft\n        // changes it, the limit is 1 << 24.\n        //\n        NT_ASSERT(FALSE);\n        return NULL;\n    }\n\n    KeAcquireSpinLock(&Table->Lock, &oldIrql);\n\n    //\n    // See if another thread beat us.\n    //\n    entry = KphpCidLookupEntry(Cid, Table);\n    if (entry)\n    {\n        //\n        // Rock and roll!\n        //\n        goto Exit;\n    }\n\n    //\n    // We are the chosen one. Go expand the tree.\n    //\n\n    table = ReadULongPtrAcquire(&Table->Table);\n\n    level = (table & KPH_CID_TABLE_LEVEL_MASK);\n\n    if (level == KPH_CID_TABLE_L0)\n    {\n        //\n        // If we're here then we *must* be migrating to level 1.\n        //\n        NT_ASSERT(id >= KPH_CID_MAX_L0);\n\n        tableL1 = KphpCidAllocateTable(KPH_CID_TABLE_L1);\n        if (!tableL1)\n        {\n            entry = NULL;\n            goto Exit;\n        }\n\n        tableL1[0] = (PKPH_CID_TABLE_ENTRY)(table & KPH_CID_TABLE_POINTER_MASK);\n        table = ((ULONG_PTR)tableL1 | KPH_CID_TABLE_L1);\n        level = KPH_CID_TABLE_L1;\n        InterlockedExchangePointer((PVOID*)&Table->Table, (PVOID)table);\n\n        //\n        // Fall through for level 1 expansion.\n        //\n    }\n\n    if (level == KPH_CID_TABLE_L1)\n    {\n        if (id < KPH_CID_MAX_L1)\n        {\n            //\n            // Allocate a new block in the level 1 table.\n            //\n            tableL1 = (PKPH_CID_TABLE_ENTRY*)(table & KPH_CID_TABLE_POINTER_MASK);\n            NT_ASSERT(!tableL1[id / KPH_CID_MAX_L0]);\n            tableL1[id / KPH_CID_MAX_L0] = KphpCidAllocateTable(KPH_CID_TABLE_L0);\n            tableL0 = tableL1[id / KPH_CID_MAX_L0];\n            if (!tableL0)\n            {\n                entry = NULL;\n                goto Exit;\n            }\n\n            entry = &tableL0[id % KPH_CID_MAX_L0];\n            goto Exit;\n        }\n\n        //\n        // We have to migrate to a level 2 table.\n        //\n        tableL2 = KphpCidAllocateTable(KPH_CID_TABLE_L2);\n        if (!tableL2)\n        {\n            entry = NULL;\n            goto Exit;\n        }\n\n        tableL2[0] = (PKPH_CID_TABLE_ENTRY*)(table & KPH_CID_TABLE_POINTER_MASK);\n        table = ((ULONG_PTR)tableL2 | KPH_CID_TABLE_L2);\n        level = KPH_CID_TABLE_L2;\n        InterlockedExchangePointer((PVOID*)&Table->Table, (PVOID)table);\n\n        //\n        // Fall through for level 2 expansion\n        //\n    }\n\n    NT_ASSERT(level == KPH_CID_TABLE_L2);\n    NT_ASSERT(id < KPH_CID_MAX_L2);\n\n    //\n    // Allocate new block(s) in the level 2 table.\n    //\n\n    tableL2 = (PKPH_CID_TABLE_ENTRY**)(table & KPH_CID_TABLE_POINTER_MASK);\n    tableL1 = tableL2[id / KPH_CID_MAX_L1];\n    if (!tableL1)\n    {\n        tableL2[id / KPH_CID_MAX_L1] = KphpCidAllocateTable(KPH_CID_TABLE_L1);\n        tableL1 = tableL2[id / KPH_CID_MAX_L1];\n        if (!tableL1)\n        {\n            entry = NULL;\n            goto Exit;\n        }\n    }\n\n    NT_ASSERT(!tableL1[(id % KPH_CID_MAX_L1) / KPH_CID_MAX_L0]);\n    tableL1[(id % KPH_CID_MAX_L1) / KPH_CID_MAX_L0] = KphpCidAllocateTable(KPH_CID_TABLE_L0);\n    tableL0 = tableL1[(id % KPH_CID_MAX_L1) / KPH_CID_MAX_L0];\n    if (!tableL0)\n    {\n        entry = NULL;\n        goto Exit;\n    }\n\n    entry = &tableL0[(id % KPH_CID_MAX_L1) % KPH_CID_MAX_L0];\n\nExit:\n\n    KeReleaseSpinLock(&Table->Lock, oldIrql);\n\n    return entry;\n}\n\n/**\n * \\brief Retrieves the table entry for a given CID.\n *\n * \\param[in] Cid The CID to retrieve the entry for.\n * \\param[in,out] Table The table to retrieve the entry from.\n *\n * \\return Pointer to the table entry for the CID, null on allocation failure.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_CID_TABLE_ENTRY KphCidGetEntry(\n    _In_ HANDLE Cid,\n    _Inout_ PKPH_CID_TABLE Table\n    )\n{\n    PKPH_CID_TABLE_ENTRY entry;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    entry = KphpCidLookupEntry(Cid, Table);\n    if (entry)\n    {\n        return entry;\n    }\n\n    return KphpCidExpandTableFor(Cid, Table);\n}\n\n/**\n * \\brief Handles invoking the callback during enumeration.\n *\n * \\param[in] Entry The CID table entry to invoke the callback for.\n * \\param[in] Callback The object callback to invoke.\n * \\param[in] Rundown The rundown callback to invoke.\n * \\param[in] Parameter Optional parameter passed to the callback.\n *\n * \\return TRUE if enumeration should stop, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphpCidEnumerateInvokeCallback(\n    _In_ PKPH_CID_TABLE_ENTRY Entry,\n    _When_(!Rundown, _In_) _When_(Rundown, _Pre_null_) PKPH_CID_ENUMERATE_CALLBACK Callback,\n    _When_(!Callback, _In_) _When_(Callback, _Pre_null_) PKPH_CID_RUNDOWN_CALLBACK Rundown,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PVOID object;\n    BOOLEAN res;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    res = FALSE;\n\n    if (Callback)\n    {\n        object = KphAtomicReferenceObject(&Entry->ObjectRef);\n\n        if (object)\n        {\n            res = Callback(object, Parameter);\n\n            KphDereferenceObject(object);\n        }\n    }\n    else\n    {\n        NT_ASSERT(Rundown);\n\n        object = KphAtomicMoveObjectReference(&Entry->ObjectRef, NULL);\n\n        if (object)\n        {\n            Rundown(object, Parameter);\n\n            KphDereferenceObject(object);\n        }\n    }\n\n    return res;\n}\n\n/**\n * \\brief Enumerates a CID table.\n *\n * \\param[in] Table The table to enumerate.\n * \\param[in] Callback The object callback to invoke.\n * \\param[in] Rundown The rundown callback to invoke.\n * \\param[in] Parameter Optional parameter passed to the callback.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphpCidEnumerate(\n    _In_ PKPH_CID_TABLE Table,\n    _When_(!Rundown, _In_) _When_(Rundown, _Pre_null_) PKPH_CID_ENUMERATE_CALLBACK Callback,\n    _When_(!Callback, _In_) _When_(Callback, _Pre_null_) PKPH_CID_RUNDOWN_CALLBACK Rundown,\n    _In_opt_ PVOID Parameter\n    )\n{\n    ULONG_PTR table;\n    BOOLEAN leaveCriticalRegion;\n    PKPH_CID_TABLE_ENTRY tableL0;\n    PKPH_CID_TABLE_ENTRY* tableL1;\n    PKPH_CID_TABLE_ENTRY** tableL2;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    table = ReadULongPtrAcquire(&Table->Table);\n\n    if (!table)\n    {\n        return;\n    }\n\n    if (KeGetCurrentIrql() <= APC_LEVEL)\n    {\n        KeEnterCriticalRegion();\n        leaveCriticalRegion = TRUE;\n    }\n    else\n    {\n        leaveCriticalRegion = FALSE;\n    }\n\n    switch (table & KPH_CID_TABLE_LEVEL_MASK)\n    {\n        case KPH_CID_TABLE_L0:\n        {\n            tableL0 = (PKPH_CID_TABLE_ENTRY)(table & KPH_CID_TABLE_POINTER_MASK);\n\n            NT_ASSERT(tableL0);\n\n            for (ULONG i = 0; i < KPH_CID_L0_COUNT; i++)\n            {\n                if (KphpCidEnumerateInvokeCallback(&tableL0[i],\n                                                   Callback,\n                                                   Rundown,\n                                                   Parameter))\n                {\n                    goto Exit;\n                }\n            }\n\n            break;\n        }\n        case KPH_CID_TABLE_L1:\n        {\n            tableL1 = (PKPH_CID_TABLE_ENTRY*)(table & KPH_CID_TABLE_POINTER_MASK);\n\n            NT_ASSERT(tableL1);\n\n            for (ULONG i = 0; i < KPH_CID_L1_COUNT; i++)\n            {\n                tableL0 = tableL1[i];\n                if (!tableL0)\n                {\n                    continue;\n                }\n\n                for (ULONG j = 0; j < KPH_CID_L0_COUNT; j++)\n                {\n                    if (KphpCidEnumerateInvokeCallback(&tableL0[j],\n                                                       Callback,\n                                                       Rundown,\n                                                       Parameter))\n                    {\n                        goto Exit;\n                    }\n                }\n            }\n\n            break;\n        }\n        case KPH_CID_TABLE_L2:\n        {\n            tableL2 = (PKPH_CID_TABLE_ENTRY**)(table & KPH_CID_TABLE_POINTER_MASK);\n\n            NT_ASSERT(tableL2);\n\n            for (ULONG i = 0; i < KPH_CID_L2_COUNT; i++)\n            {\n                tableL1 = tableL2[i];\n                if (!tableL1)\n                {\n                    continue;\n                }\n\n                for (ULONG j = 0; j < KPH_CID_L1_COUNT; j++)\n                {\n                    tableL0 = tableL1[j];\n                    if (!tableL0)\n                    {\n                        continue;\n                    }\n\n                    for (ULONG k = 0; k < KPH_CID_L0_COUNT; k++)\n                    {\n                        if (KphpCidEnumerateInvokeCallback(&tableL0[k],\n                                                           Callback,\n                                                           Rundown,\n                                                           Parameter))\n                        {\n                            goto Exit;\n                        }\n                    }\n                }\n            }\n\n            break;\n        }\n        default:\n        {\n            NT_ASSERT(FALSE);\n            break;\n        }\n    }\n\nExit:\n\n    if (leaveCriticalRegion)\n    {\n        KeLeaveCriticalRegion();\n    }\n}\n\n/**\n * \\brief Enumerates objects in a CID table.\n *\n * \\param[in] Table The table to enumerate.\n * \\param[in] Callback The object callback to invoke. The callback should\n * return TRUE to stop enumerating and return FALSE to continue.\n * \\param[in] Parameter Optional parameter passed to the callback.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCidEnumerate(\n    _In_ PKPH_CID_TABLE Table,\n    _In_ PKPH_CID_ENUMERATE_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    KphpCidEnumerate(Table, Callback, NULL, Parameter);\n}\n\n/**\n * \\brief Enumerates CID entries a CID table for rundown.\n *\n * \\details This routine removes all items from the table. After the callback\n * returns all object references in the table is dereferenced and removed from\n * the table.\n *\n * \\param[in] Table The table to enumerate.\n * \\param[in] Callback The rundown callback to invoke.\n * \\param[in] Parameter Optional parameter passed to the callback.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCidRundown(\n    _In_ PKPH_CID_TABLE Table,\n    _In_ PKPH_CID_RUNDOWN_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    KphpCidEnumerate(Table, NULL, Callback, Parameter);\n}\n"
  },
  {
    "path": "KSystemInformer/cid_tracking.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <informer.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_CID_APC\n{\n    KSI_KAPC Apc;\n    KEVENT CompletedEvent;\n    PKPH_THREAD_CONTEXT Thread;\n} KPH_CID_APC, *PKPH_CID_APC;\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_OBJECT_TYPE KphpCidApcType = NULL;\nPKPH_OBJECT_TYPE KphProcessContextType = NULL;\nPKPH_OBJECT_TYPE KphThreadContextType = NULL;\nstatic PKPH_NPAGED_LOOKASIDE_OBJECT KphpCidApcLookaside = NULL;\nstatic PKPH_NPAGED_LOOKASIDE_OBJECT KphpProcessContextLookaside = NULL;\nstatic PKPH_NPAGED_LOOKASIDE_OBJECT KphpThreadContextLookaside = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpCidApcTypeName = RTL_CONSTANT_STRING(L\"KphCidApc\");\nstatic const UNICODE_STRING KphpProcessContextTypeName = RTL_CONSTANT_STRING(L\"KphProcessContext\");\nstatic const UNICODE_STRING KphpThreadContextTypeName = RTL_CONSTANT_STRING(L\"KphThreadContext\");\nstatic const LARGE_INTEGER KphpCidApcTimeout = KPH_TIMEOUT(3 * 1000);\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nstatic BOOLEAN KphpCidTrackingInitialized = FALSE;\nstatic KPH_CID_TABLE KphpCidTable;\nstatic LONG KphpCidPopulated = 0;\nstatic KEVENT KphpCidPopulatedEvent;\nstatic PKPH_PROCESS_CONTEXT KphpSystemProcessContext = NULL;\nstatic ULONG64 KphpProcessSequence = 0;\n\n/**\n * \\brief Looks up a context object in the CID tracking.\n *\n * \\param[in] Cid The CID of the object to look up.\n * \\param[in] ObjectType The expected object type if the CID.\n *\n * \\return Pointer to the context object, null if not found or the object is\n * not of the expected type. The caller *must* dereference the object when\n * they are through with it.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPVOID KphpLookupContext(\n    _In_ HANDLE Cid,\n    _In_ PKPH_OBJECT_TYPE ObjectType\n    )\n{\n    PVOID object;\n    PKPH_CID_TABLE_ENTRY entry;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    entry = KphCidGetEntry(Cid, &KphpCidTable);\n    if (!entry)\n    {\n        return NULL;\n    }\n\n    object = KphCidReferenceObject(entry);\n    if (object && (KphGetObjectType(object) != ObjectType))\n    {\n        KphDereferenceObject(object);\n        object = NULL;\n    }\n\n    return object;\n}\n\n/**\n * \\brief Retrieves the system process context.\n *\n * \\return Pointer to the system process context, null if not found. The caller\n * *must* dereference the object when they are through with it.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphGetSystemProcessContext(\n    VOID\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (KphpSystemProcessContext)\n    {\n        KphReferenceObject(KphpSystemProcessContext);\n    }\n\n    return KphpSystemProcessContext;\n}\n\n/**\n * \\brief Retrieves a process context.\n *\n * \\param[in] ProcessId The process ID of the process to get the context for.\n *\n * \\return Pointer to the process context, null if not found. The caller\n * *must* dereference the object when they are through with it.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphGetProcessContext(\n    _In_ HANDLE ProcessId\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    return KphpLookupContext(ProcessId, KphProcessContextType);\n}\n\n/**\n * \\brief Retrieves a process context by process object.\n *\n * \\param[in] Process The process object of the process to get the context for.\n *\n * \\return Pointer to the process context, null if not found. The caller\n * *must* dereference the object when they are through with it.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphGetEProcessContext(\n    _In_ PEPROCESS Process\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (Process == PsInitialSystemProcess)\n    {\n        return KphGetSystemProcessContext();\n    }\n\n    return KphGetProcessContext(PsGetProcessId(Process));\n}\n\n/**\n * \\brief Retrieves a thread context.\n *\n * \\param[in] ThreadId The thread ID of the thread to get the context for.\n *\n * \\return Pointer to the thread context, null if not found. The caller\n * *must* dereference the object when they are through with it.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_THREAD_CONTEXT KphGetThreadContext(\n    _In_ HANDLE ThreadId\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    return KphpLookupContext(ThreadId, KphThreadContextType);\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Marks the CID tracking populated, which unblocks public tracking APIs.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCidMarkPopulated(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!KphpCidTrackingInitialized)\n    {\n        return;\n    }\n\n    WriteRelease(&KphpCidPopulated, 1);\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  TRACKING,\n                  \"Marked CID tracking populated, unblocking routines.\");\n\n    KeSetEvent(&KphpCidPopulatedEvent, EVENT_INCREMENT, FALSE);\n}\n\n/**\n * \\brief Waits for the CID tracking to be marked as populated.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpCidWaitForPopulate(\n    VOID\n    )\n{\n    KPH_PAGED_CODE();\n\n    if (ReadAcquire(&KphpCidPopulated))\n    {\n        return;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  TRACKING,\n                  \"Waiting for CID tracking population...\");\n\n    KeWaitForSingleObject(&KphpCidPopulatedEvent,\n                          Executive,\n                          KernelMode,\n                          FALSE,\n                          NULL);\n}\n\n/**\n * \\brief Allocates a CID APC object.\n *\n * \\return Pointer to CID APC object, null on failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateCidApc(\n    _In_ SIZE_T Size\n    )\n{\n    PVOID object;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(KphpCidApcLookaside);\n    NT_ASSERT(Size <= KphpCidApcLookaside->L.Size);\n    DBG_UNREFERENCED_PARAMETER(Size);\n\n    object = KphAllocateFromNPagedLookasideObject(KphpCidApcLookaside);\n    if (object)\n    {\n        KphReferenceObject(KphpCidApcLookaside);\n    }\n\n    return object;\n}\n\n/**\n * \\brief Initializes a CID APC object.\n *\n * \\param[in] Object The CID APC object to initialize.\n * \\param[in] Parameter Unused.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializeCidApc(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_CID_APC apc;\n\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(Parameter);\n\n    apc = Object;\n\n    KeInitializeEvent(&apc->CompletedEvent, NotificationEvent, FALSE);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Deletes a CID APC object.\n *\n * \\param[in] Object The CID APC  object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\nVOID KSIAPI KphpDeleteCidApc(\n    _Inout_ PVOID Object\n    )\n{\n    PKPH_CID_APC apc;\n\n    KPH_PAGED_CODE();\n\n    apc = Object;\n\n    if (apc->Thread)\n    {\n        KphDereferenceObject(apc->Thread);\n    }\n}\n\n/**\n * \\brief Frees a CID APC object.\n *\n * \\param[in] Object The CID APC object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\nVOID KSIAPI KphpFreeCidApc(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(KphpCidApcLookaside);\n\n    KphFreeToNPagedLookasideObject(KphpCidApcLookaside, Object);\n    KphDereferenceObject(KphpCidApcLookaside);\n}\n\n/**\n * \\brief APC cleanup routine for APC APCs.\n *\n * \\param[in] Apc The ACP to clean up.\n * \\param[in] Reason Unused.\n */\n_Function_class_(KSI_KCLEANUP_ROUTINE)\n_IRQL_requires_min_(PASSIVE_LEVEL)\n_IRQL_requires_max_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpCidApcCleanup(\n    _In_ PKSI_KAPC Apc,\n    _In_ KSI_KAPC_CLEANUP_REASON Reason\n    )\n{\n    PKPH_CID_APC apc;\n\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(Apc);\n    DBG_UNREFERENCED_PARAMETER(Reason);\n\n    apc = CONTAINING_RECORD(Apc, KPH_CID_APC, Apc);\n\n    KphDereferenceObject(apc);\n}\n\n/**\n * \\brief Allocates a process context object.\n *\n * \\param[in] Size The size requested from the object infrastructure.\n *\n * \\return Allocated process context object, null on allocation failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateProcessContext(\n    _In_ SIZE_T Size\n    )\n{\n    PVOID object;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    DBG_UNREFERENCED_PARAMETER(Size);\n    NT_ASSERT(KphpProcessContextLookaside);\n    NT_ASSERT(Size <= KphpProcessContextLookaside->L.Size);\n\n    object = KphAllocateFromNPagedLookasideObject(KphpProcessContextLookaside);\n    if (object)\n    {\n        KphReferenceObject(KphpProcessContextLookaside);\n    }\n\n    return object;\n}\n\n/**\n * \\brief Initializes a process context.\n *\n * \\param[in] Object The process context object to initialize.\n * \\param[in] Parameter The kernel process object associated with this context.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializeProcessContext(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PKPH_PROCESS_CONTEXT process;\n    PEPROCESS processObject;\n    HANDLE processHandle;\n    PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    process = Object;\n    processObject = Parameter;\n\n    process->SequenceNumber = InterlockedIncrementU64(&KphpProcessSequence);\n\n    status = ObOpenObjectByPointer(processObject,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   PROCESS_ALL_ACCESS,\n                                   *PsProcessType,\n                                   KernelMode,\n                                   &processHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        processHandle = NULL;\n        goto Exit;\n    }\n\n    status = ZwQueryInformationProcess(processHandle,\n                                       ProcessSubsystemInformation,\n                                       &process->SubsystemType,\n                                       sizeof(SUBSYSTEM_INFORMATION_TYPE),\n                                       NULL);\n    if (status == STATUS_INVALID_INFO_CLASS)\n    {\n        process->SubsystemType = SubsystemInformationTypeWin32;\n    }\n    else if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"ProcessSubsystemInformation failed: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    basicInfo.Size = sizeof(PROCESS_EXTENDED_BASIC_INFORMATION);\n    status = ZwQueryInformationProcess(processHandle,\n                                       ProcessBasicInformation,\n                                       &basicInfo,\n                                       sizeof(PROCESS_EXTENDED_BASIC_INFORMATION),\n                                       NULL);\n    if (status == STATUS_INVALID_INFO_CLASS)\n    {\n        process->IsSubsystemProcess = FALSE;\n    }\n    else if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"ProcessBasicInformation failed: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n    else\n    {\n        process->IsSubsystemProcess = basicInfo.IsSubsystemProcess;\n    }\n\n    process->EProcess = processObject;\n    ObReferenceObject(process->EProcess);\n\n    process->ProcessId = PsGetProcessId(process->EProcess);\n\n    if (KphDynPsGetProcessStartKey)\n    {\n        process->ProcessStartKey = KphDynPsGetProcessStartKey(processObject);\n    }\n    else\n    {\n        PROCESS_TELEMETRY_ID_INFORMATION telemetryIdInfo;\n\n        telemetryIdInfo.HeaderSize = 0;\n\n        status = ZwQueryInformationProcess(processHandle,\n                                           ProcessTelemetryIdInformation,\n                                           &telemetryIdInfo,\n                                           sizeof(PROCESS_TELEMETRY_ID_INFORMATION),\n                                           NULL);\n\n        if ((status == STATUS_BUFFER_OVERFLOW) &&\n            RTL_CONTAINS_FIELD(&telemetryIdInfo,\n                               telemetryIdInfo.HeaderSize,\n                               ProcessStartKey))\n        {\n            status = STATUS_SUCCESS;\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            process->ProcessStartKey = telemetryIdInfo.ProcessStartKey;\n        }\n        else\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"ProcessTelemetryIdInformation failed: %!STATUS!\",\n                          status);\n\n            NT_ASSERT(process->ProcessStartKey == 0);\n        }\n    }\n\n#ifdef _WIN64\n    if (PsGetProcessWow64Process(process->EProcess))\n    {\n        process->IsWow64 = TRUE;\n    }\n    else\n#endif\n    {\n        process->IsWow64 = FALSE;\n    }\n\n    KphInitializeRWLock(&process->ThreadListLock);\n    InitializeListHead(&process->ThreadListHead);\n\n    KphInitializeRWLock(&process->ProtectionLock);\n\n    status = PsReferenceProcessFilePointer(process->EProcess,\n                                           &process->FileObject);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"PsReferenceProcessFilePointer failed: %!STATUS!\",\n                      status);\n\n        process->FileObject = NULL;\n    }\n\n    if (process->FileObject)\n    {\n        ULONG returnLength;\n\n        status = KphQueryNameFileObject(process->FileObject,\n                                        NULL,\n                                        0,\n                                        &returnLength);\n        if (status == STATUS_BUFFER_TOO_SMALL)\n        {\n            POBJECT_NAME_INFORMATION nameInfo;\n\n            nameInfo = KphAllocateNPaged(returnLength,\n                                         KPH_TAG_PROCESS_IMAGE_FILE_NAME);\n            if (nameInfo)\n            {\n                status = KphQueryNameFileObject(process->FileObject,\n                                                nameInfo,\n                                                returnLength,\n                                                &returnLength);\n                if (NT_SUCCESS(status))\n                {\n                    C_ASSERT(FIELD_OFFSET(OBJECT_NAME_INFORMATION, Name) == 0);\n                    process->ImageFileName = (PUNICODE_STRING)nameInfo;\n                }\n                else\n                {\n                    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                                  TRACKING,\n                                  \"KphQueryNameFileObject failed: %!STATUS!\",\n                                  status);\n\n                    KphFree(nameInfo, KPH_TAG_PROCESS_IMAGE_FILE_NAME);\n                }\n            }\n            else\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              TRACKING,\n                              \"Failed to allocate process image file name.\");\n            }\n        }\n    }\n\n    if (!process->ImageFileName)\n    {\n        status = SeLocateProcessImageName(process->EProcess,\n                                          &process->ImageFileName);\n        if (NT_SUCCESS(status))\n        {\n            process->SystemAllocatedImageFileName = TRUE;\n        }\n        else\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"SeLocateProcessImageName failed: %!STATUS!\",\n                          status);\n\n            process->ImageFileName = NULL;\n        }\n    }\n\n    if (process->ImageFileName)\n    {\n        status = KphGetFileNameFinalComponent(process->ImageFileName,\n                                              &process->ImageName);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"KphGetFileNameFinalComponent failed: %!STATUS!\",\n                          status);\n\n            NT_ASSERT(process->ImageName.Length == 0);\n        }\n    }\n\n    if (process->ImageName.Length == 0)\n    {\n        status = KphGetProcessImageName(process->EProcess,\n                                        &process->ImageName);\n        if (NT_SUCCESS(status))\n        {\n            process->AllocatedImageName = TRUE;\n        }\n        else\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"KphGetProcessImageName failed: %!STATUS!\",\n                          status);\n\n            NT_ASSERT(process->ImageName.Length == 0);\n        }\n    }\n\n    if (process->EProcess == PsInitialSystemProcess)\n    {\n        NT_ASSERT(!KphpSystemProcessContext);\n        KphReferenceObject(process);\n        KphpSystemProcessContext = process;\n    }\n\n    KphValidateLsass(process->EProcess);\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (processHandle)\n    {\n        ObCloseHandle(processHandle, KernelMode);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Deletes a process context.\n *\n * \\param[in] Object The process context object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpDeleteProcessContext(\n    _Inout_ PVOID Object\n    )\n{\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    process = Object;\n\n    KphAtomicAssignObjectReference(&process->InformerState.Atomic, NULL);\n    KphAtomicAssignObjectReference(&process->SessionToken.Atomic, NULL);\n\n    if (process->Protected)\n    {\n        KphStopProtectingProcess(process);\n    }\n\n    if (process->ImageFileName)\n    {\n        if (process->SystemAllocatedImageFileName)\n        {\n            KphFreePool(process->ImageFileName);\n        }\n        else\n        {\n            KphFree(process->ImageFileName, KPH_TAG_PROCESS_IMAGE_FILE_NAME);\n        }\n    }\n\n    if (process->AllocatedImageName)\n    {\n        KphFreeProcessImageName(&process->ImageName);\n    }\n\n    if (process->FileObject)\n    {\n        ObDereferenceObject(process->FileObject);\n    }\n\n    KphDeleteRWLock(&process->ProtectionLock);\n\n    NT_ASSERT(IsListEmpty(&process->ThreadListHead));\n    NT_ASSERT(process->NumberOfThreads == 0);\n    KphDeleteRWLock(&process->ThreadListLock);\n\n    KphInvalidateLsass(process->EProcess);\n\n    NT_ASSERT(process->EProcess);\n    ObDereferenceObject(process->EProcess);\n}\n\n/**\n * \\brief Frees a process context object.\n *\n * \\param[in] Object The process context object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpFreeProcessContext(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KphpProcessContextLookaside);\n\n    KphFreeToNPagedLookasideObject(KphpProcessContextLookaside, Object);\n    KphDereferenceObject(KphpProcessContextLookaside);\n}\n\n/**\n * \\brief Allocates a thread context object.\n *\n * \\param[in] Size The size requested from the object infrastructure.\n *\n * \\return Allocated thread context object, null on allocation failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateThreadContext(\n    _In_ SIZE_T Size\n    )\n{\n    PVOID object;\n\n    KPH_PAGED_CODE();\n\n    DBG_UNREFERENCED_PARAMETER(Size);\n    NT_ASSERT(KphpThreadContextLookaside);\n    NT_ASSERT(Size <= KphpThreadContextLookaside->L.Size);\n\n    object = KphAllocateFromNPagedLookasideObject(KphpThreadContextLookaside);\n    if (object)\n    {\n        KphReferenceObject(KphpThreadContextLookaside);\n    }\n\n    return object;\n}\n\n/**\n * \\brief Performs thread context initialization for a WSL thread.\n *\n * \\param[in] Dyn Dynamic configuration.\n * \\param[in] ThreadContext The thread context to initialize.\n */\n_IRQL_requires_(APC_LEVEL)\nVOID KphpInitializeWSLThreadContext(\n    _In_ PKPH_DYN Dyn,\n    _In_ PKPH_THREAD_CONTEXT ThreadContext\n    )\n{\n    PVOID picoContext;\n    PVOID value;\n\n    KPH_PAGED_CODE_APC();\n\n    //\n    // We use an APC here to reach into the thread pico context. We could\n    // reach directly into the pico context elsewhere, but reversing shows\n    // intent for possible other pico subsystem providers in the future.\n    // So, we use some \"undocumented\" APIs in the APC to ask \"nicely\" for\n    // the correct pico context.\n    //\n\n    if ((ThreadContext->SubsystemType != SubsystemInformationTypeWSL) ||\n        !KphDynLxpThreadGetCurrent ||\n        (Dyn->LxPicoThrdInfo == ULONG_MAX) ||\n        (Dyn->LxPicoThrdInfoTID == ULONG_MAX) ||\n        (Dyn->LxPicoProc == ULONG_MAX) ||\n        (Dyn->LxPicoProcInfo == ULONG_MAX) ||\n        (Dyn->LxPicoProcInfoPID == ULONG_MAX))\n    {\n        return;\n    }\n\n    if (!KphDynLxpThreadGetCurrent(&picoContext))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"LxpThreadGetCurrent failed\");\n\n        return;\n    }\n\n    if (!ThreadContext->WSL.ValidThreadId)\n    {\n        value = *(PVOID*)Add2Ptr(picoContext, Dyn->LxPicoThrdInfo);\n        ThreadContext->WSL.ThreadId =\n            *(PULONG)Add2Ptr(value, Dyn->LxPicoThrdInfoTID);\n\n        ThreadContext->WSL.ValidThreadId = TRUE;\n    }\n\n    if (ThreadContext->ProcessContext &&\n        !ThreadContext->ProcessContext->WSL.ValidProcessId)\n    {\n        value = *(PVOID*)Add2Ptr(picoContext, Dyn->LxPicoProc);\n        value = *(PVOID*)Add2Ptr(value, Dyn->LxPicoProcInfo);\n        ThreadContext->ProcessContext->WSL.ProcessId =\n            *(PULONG)Add2Ptr(value, Dyn->LxPicoProcInfoPID);\n\n        ThreadContext->ProcessContext->WSL.ValidProcessId = TRUE;\n    }\n}\n\n/**\n * \\brief APC routine for thread tracking.\n *\n * \\param[in] Apc The ACP executed, contained within the CID APC.\n * \\param[in] NormalRoutine Unused.\n * \\param[in] NormalContext Unused.\n * \\param[in] SystemArgument1 Unused.\n * \\param[in] SystemArgument2 Unused.\n */\n_Function_class_(KSI_KKERNEL_ROUTINE)\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpInitializeThreadContextSpecialApc(\n    _In_ PKSI_KAPC Apc,\n    _Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE* NormalRoutine,\n    _Inout_ _Deref_pre_maybenull_ PVOID* NormalContext,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument1,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2\n    )\n{\n    PKPH_CID_APC apc;\n    PKPH_DYN dyn;\n    PTEB teb;\n\n    KPH_PAGED_CODE_APC();\n\n    UNREFERENCED_PARAMETER(NormalRoutine);\n    UNREFERENCED_PARAMETER(NormalContext);\n    UNREFERENCED_PARAMETER(SystemArgument1);\n    UNREFERENCED_PARAMETER(SystemArgument2);\n\n    apc = CONTAINING_RECORD(Apc, KPH_CID_APC, Apc);\n\n    NT_ASSERT(apc->Thread->EThread == KeGetCurrentThread());\n#ifdef _WIN64\n    C_ASSERT(FIELD_OFFSET(TEB, SubProcessTag) == 0x1720);\n#endif\n\n    teb = PsGetCurrentThreadTeb();\n    if (teb)\n    {\n        __try\n        {\n            apc->Thread->SubProcessTag = ReadPointerFromUser(&teb->SubProcessTag);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"Failed to populate SubProcessTag: %!STATUS!\",\n                          GetExceptionCode());\n        }\n    }\n\n    dyn = KphReferenceDynData();\n    if (dyn)\n    {\n        KphpInitializeWSLThreadContext(dyn, apc->Thread);\n        KphDereferenceObject(dyn);\n    }\n\n    KeSetEvent(&apc->CompletedEvent, EVENT_INCREMENT, FALSE);\n}\n\n/**\n * \\brief Initializes thread context parts in the original thread environment.\n *\n * \\param[in] ThreadContext The thread context to initialize.\n * \\param[in] Wait If TRUE this routine will try to wait for the APC to\n * complete, otherwise this routine will not wait.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpInitThreadContextInOriginalEnvironment(\n    _In_ PKPH_THREAD_CONTEXT ThreadContext,\n    _In_ BOOLEAN Wait\n    )\n{\n    NTSTATUS status;\n    PKPH_CID_APC apc;\n\n    KPH_PAGED_CODE();\n\n    status = KphCreateObject(KphpCidApcType, sizeof(KPH_CID_APC), &apc, NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    apc->Thread = ThreadContext;\n    KphReferenceObject(apc->Thread);\n\n    KsiInitializeApc(&apc->Apc,\n                     KphDriverObject,\n                     ThreadContext->EThread,\n                     OriginalApcEnvironment,\n                     KphpInitializeThreadContextSpecialApc,\n                     KphpCidApcCleanup,\n                     NULL,\n                     KernelMode,\n                     NULL);\n\n    //\n    // The APC could fire immediately we must reference before trying to queue.\n    //\n    KphReferenceObject(apc);\n    if (!KsiInsertQueueApc(&apc->Apc, NULL, NULL, IO_NO_INCREMENT))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KsiInsertQueueApc failed\");\n\n        KphDereferenceObject(apc);\n        status = STATUS_UNSUCCESSFUL;\n        goto Exit;\n    }\n\n    if (!Wait)\n    {\n        status = STATUS_SUCCESS;\n        goto Exit;\n    }\n\n    status = KeWaitForSingleObject(&apc->CompletedEvent,\n                                   Executive,\n                                   KernelMode,\n                                   FALSE,\n                                   (PLARGE_INTEGER)&KphpCidApcTimeout);\n    if (status != STATUS_SUCCESS)\n    {\n        NTSTATUS removeStatus;\n\n        NT_ASSERT(status == STATUS_TIMEOUT);\n\n        removeStatus = KsiRemoveQueueApc(&apc->Apc);\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KsiRemoveQueueApc: %!STATUS!\",\n                      removeStatus);\n\n        goto Exit;\n    }\n\nExit:\n\n    if (apc)\n    {\n        KphDereferenceObject(apc);\n    }\n\n    if (!NT_SUCCESS(status) || (status == STATUS_TIMEOUT))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KphpInitializeThreadContextApc failed: %!STATUS!\",\n                      status);\n    }\n}\n\n/**\n * \\brief Initializes a thread context.\n *\n * \\param[in] Object The thread context object to initialize.\n * \\param[in] Parameter Unused\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializeThreadContext(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PKPH_THREAD_CONTEXT thread;\n    PETHREAD threadObject;\n    HANDLE threadHandle;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Parameter);\n\n    thread = Object;\n    threadObject = Parameter;\n\n    status = ObOpenObjectByPointer(threadObject,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   THREAD_ALL_ACCESS,\n                                   *PsThreadType,\n                                   KernelMode,\n                                   &threadHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"ObOpenObjectByPointer failed %!STATUS!\",\n                      status);\n\n        threadHandle = NULL;\n        goto Exit;\n    }\n\n    status = ZwQueryInformationThread(threadHandle,\n                                      ThreadSubsystemInformation,\n                                      &thread->SubsystemType,\n                                      sizeof(SUBSYSTEM_INFORMATION_TYPE),\n                                      NULL);\n    if (status == STATUS_INVALID_INFO_CLASS)\n    {\n        thread->SubsystemType = SubsystemInformationTypeWin32;\n    }\n    else if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"ThreadSubsystemInformation failed %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    thread->EThread = threadObject;\n    ObReferenceObject(thread->EThread);\n\n    thread->ClientId.UniqueThread = PsGetThreadId(thread->EThread);\n    thread->ClientId.UniqueProcess = PsGetThreadProcessId(thread->EThread);\n\n    NT_ASSERT(!thread->ProcessContext);\n    thread->ProcessContext = KphGetProcessContext(thread->ClientId.UniqueProcess);\n\n    if (thread->ProcessContext)\n    {\n        KphAcquireRWLockExclusive(&thread->ProcessContext->ThreadListLock);\n\n        if (!thread->ProcessContext->InitialThread)\n        {\n            thread->ProcessContext->InitialThread = thread;\n            KphReferenceObject(thread);\n        }\n\n        InsertTailList(&thread->ProcessContext->ThreadListHead,\n                       &thread->ThreadListEntry);\n        thread->ProcessContext->NumberOfThreads++;\n        thread->InThreadList = TRUE;\n        KphReferenceObject(thread);\n\n        KphReleaseRWLock(&thread->ProcessContext->ThreadListLock);\n    }\n\n    if (!PsIsSystemThread(thread->EThread))\n    {\n        KphpInitThreadContextInOriginalEnvironment(thread, FALSE);\n    }\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (threadHandle)\n    {\n        ObCloseHandle(threadHandle, KernelMode);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Deletes a thread context.\n *\n * \\param[in] Object The thread context object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpDeleteThreadContext(\n    _Inout_ PVOID Object\n    )\n{\n    PKPH_THREAD_CONTEXT thread;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    thread = Object;\n\n    NT_ASSERT(!thread->InThreadList);\n\n    KphAtomicAssignObjectReference(&thread->RequestSessionToken.Atomic, NULL);\n    KphAtomicAssignObjectReference(&thread->SessionToken.Atomic, NULL);\n\n    NT_ASSERT(thread->EThread);\n    ObDereferenceObject(thread->EThread);\n\n    if (thread->ProcessContext)\n    {\n        KphDereferenceObject(thread->ProcessContext);\n    }\n}\n\n/**\n * \\brief Frees a thread context object.\n *\n * \\param[in] Object The thread context object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpFreeThreadContext(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KphpThreadContextLookaside);\n\n    KphFreeToNPagedLookasideObject(KphpThreadContextLookaside, Object);\n    KphDereferenceObject(KphpThreadContextLookaside);\n}\n\n/**\n * \\brief Initializes the CID tracking infrastructure.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCidInitialize(\n    VOID\n    )\n{\n    NTSTATUS status;\n    KPH_OBJECT_TYPE_INFO typeInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = KphCidTableCreate(&KphpCidTable);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    KeInitializeEvent(&KphpCidPopulatedEvent, NotificationEvent, FALSE);\n\n    status = KphCreateNPagedLookasideObject(&KphpCidApcLookaside,\n                                            KphAddObjectHeaderSize(sizeof(KPH_CID_APC)),\n                                            KPH_TAG_CID_APC);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KphCreateNPagedLookasideObject failed: %!STATUS!\",\n                      status);\n\n        KphpCidApcLookaside = NULL;\n        goto Exit;\n    }\n\n    status = KphCreateNPagedLookasideObject(&KphpProcessContextLookaside,\n                                            KphAddObjectHeaderSize(sizeof(KPH_PROCESS_CONTEXT)),\n                                            KPH_TAG_PROCESS_CONTEXT);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KphCreatePagedLookasideObject failed: %!STATUS!\",\n                      status);\n\n        KphpProcessContextLookaside = NULL;\n        goto Exit;\n    }\n\n    status = KphCreateNPagedLookasideObject(&KphpThreadContextLookaside,\n                                            KphAddObjectHeaderSize(sizeof(KPH_THREAD_CONTEXT)),\n                                            KPH_TAG_THREAD_CONTEXT);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KphCreatePagedLookasideObject failed: %!STATUS!\",\n                      status);\n\n        KphpThreadContextLookaside = NULL;\n        goto Exit;\n    }\n\n    typeInfo.Allocate = KphpAllocateProcessContext;\n    typeInfo.Initialize = KphpInitializeProcessContext;\n    typeInfo.Delete = KphpDeleteProcessContext;\n    typeInfo.Free = KphpFreeProcessContext;\n    typeInfo.Flags = 0;\n    typeInfo.DeferDelete = TRUE;\n\n    KphCreateObjectType(&KphpProcessContextTypeName,\n                        &typeInfo,\n                        &KphProcessContextType);\n\n    typeInfo.Allocate = KphpAllocateThreadContext;\n    typeInfo.Initialize = KphpInitializeThreadContext;\n    typeInfo.Delete = KphpDeleteThreadContext;\n    typeInfo.Free = KphpFreeThreadContext;\n    typeInfo.Flags = 0;\n    typeInfo.DeferDelete = TRUE;\n\n    KphCreateObjectType(&KphpThreadContextTypeName,\n                        &typeInfo,\n                        &KphThreadContextType);\n\n    typeInfo.Allocate = KphpAllocateCidApc;\n    typeInfo.Initialize = KphpInitializeCidApc;\n    typeInfo.Delete = KphpDeleteCidApc;\n    typeInfo.Free = KphpFreeCidApc;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpCidApcTypeName,\n                        &typeInfo,\n                        &KphpCidApcType);\n\n    KphpCidTrackingInitialized = TRUE;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (!NT_SUCCESS(status))\n    {\n        KphCidTableDelete(&KphpCidTable);\n\n        if (KphpProcessContextLookaside)\n        {\n            KphDereferenceObject(KphpProcessContextLookaside);\n            KphpProcessContextLookaside = NULL;\n        }\n\n        if (KphpThreadContextLookaside)\n        {\n            KphDereferenceObject(KphpThreadContextLookaside);\n            KphpThreadContextLookaside = NULL;\n        }\n\n        if (KphpCidApcLookaside)\n        {\n            KphDereferenceObject(KphpCidApcLookaside);\n            KphpCidApcLookaside = NULL;\n        }\n    }\n\n    return status;\n}\n\n/**\n * \\brief Unlinks thread contexts from a process context.\n *\n * \\param[in] Process The process context to unlink thread contexts from.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpUnlinkProcessContextThreadContexts(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphAcquireRWLockExclusive(&Process->ThreadListLock);\n\n    while (!IsListEmpty(&Process->ThreadListHead))\n    {\n        PKPH_THREAD_CONTEXT thread;\n\n        thread = CONTAINING_RECORD(RemoveHeadList(&Process->ThreadListHead),\n                                   KPH_THREAD_CONTEXT,\n                                   ThreadListEntry);\n        NT_ASSERT(thread->InThreadList);\n\n        Process->NumberOfThreads--;\n        Process->NumberOfUnlinkedThreads++;\n\n        thread->InThreadList = FALSE;\n        KphDereferenceObject(thread);\n    }\n\n    if (Process->InitialThread)\n    {\n        KphDereferenceObject(Process->InitialThread);\n        Process->InitialThread = NULL;\n    }\n\n    KphReleaseRWLock(&Process->ThreadListLock);\n}\n\n/**\n * \\brief Cleanup callback for enumerating the CID tracking table.\n *\n * \\param[in] Object The CID table entry to clean up.\n * \\param[in] Parameter Unused\n *\n * \\return FALSE to continue enumerating.\n */\n_Function_class_(KPH_CID_RUNDOWN_CALLBACK)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpCidCleanupCallback(\n    _In_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(Parameter);\n\n    if (KphGetObjectType(Object) == KphProcessContextType)\n    {\n        PKPH_PROCESS_CONTEXT process;\n\n        process = Object;\n\n        KphpUnlinkProcessContextThreadContexts(process);\n    }\n}\n\n/**\n * \\brief Cleans up the CID tracking infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCidCleanup(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!KphpCidTrackingInitialized)\n    {\n        return;\n    }\n\n    KphCidRundown(&KphpCidTable, KphpCidCleanupCallback, NULL);\n\n    if (KphpSystemProcessContext)\n    {\n        KphDereferenceObject(KphpSystemProcessContext);\n    }\n\n    KphCidTableDelete(&KphpCidTable);\n\n    KphDereferenceObject(KphpCidApcLookaside);\n    KphDereferenceObject(KphpThreadContextLookaside);\n    KphDereferenceObject(KphpProcessContextLookaside);\n}\n\n/**\n * \\brief Begins tracking a context object in the CID tracking. May return an\n * existing object if it is already being tracked.\n *\n * \\param[in] Cid The CID of the object to being tracking.\n * \\param[in] ObjectType The expected object type if the CID.\n * \\param[in] ObjectBodySize The size of the context body.\n * \\param[in] Parameter The parameter passed to the creation routine.\n *\n * \\return Pointer to the context object, null on allocation failure or if the\n * object is already being tracked and is not of the expected type. The caller\n * *must* dereference the object when they are through with it.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nPVOID KphpTrackContext(\n    _In_ HANDLE Cid,\n    _In_ PKPH_OBJECT_TYPE ObjectType,\n    _In_ ULONG ObjectBodySize,\n    _In_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PKPH_CID_TABLE_ENTRY entry;\n    PVOID object;\n\n    KPH_PAGED_CODE();\n\n    entry = KphCidGetEntry(Cid, &KphpCidTable);\n    if (!entry)\n    {\n        return NULL;\n    }\n\n    object = KphCidReferenceObject(entry);\n    if (object)\n    {\n        if (KphGetObjectType(object) != ObjectType)\n        {\n            KphDereferenceObject(object);\n            object = NULL;\n        }\n\n        return object;\n    }\n\n    status = KphCreateObject(ObjectType, ObjectBodySize, &object, Parameter);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KphCreateObject (%lu) failed: %!STATUS!\",\n                      HandleToULong(Cid),\n                      status);\n\n        return NULL;\n    }\n\n    KphCidAssignObject(entry, object);\n\n    return object;\n}\n\n/**\n * \\brief Stops tracking a context object in the CID tracking.\n *\n * \\param[in] Cid The CID of the object to being tracking.\n * \\param[in] ObjectType The expected object type if the CID.\n * \\param[in] ObjectBodySize The size of the context body.\n *\n * \\return Pointer to the context object, null if not found or the object is\n * not of the expected type. The caller *must* dereference the object when they\n * are through with it.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nPVOID KphpUntrackContext(\n    _In_ HANDLE Cid,\n    _In_ PKPH_OBJECT_TYPE ObjectType\n    )\n{\n    PKPH_CID_TABLE_ENTRY entry;\n    PVOID object;\n\n    KPH_PAGED_CODE();\n\n    entry = KphCidGetEntry(Cid, &KphpCidTable);\n    if (!entry)\n    {\n        return NULL;\n    }\n\n    object = KphCidReferenceObject(entry);\n\n    if (object && (KphGetObjectType(object) != ObjectType))\n    {\n        KphDereferenceObject(object);\n        return NULL;\n    }\n\n    KphCidAssignObject(entry, NULL);\n\n    return object;\n}\n\n/**\n * \\brief Performs actions post population of CID table.\n *\n * \\param[in] Process The context being enumerated.\n * \\param[in] Parameter Unused.\n *\n * \\return FALSE\n */\n_Function_class_(KPH_ENUM_CID_CONTEXTS_CALLBACK)\n_Must_inspect_result_\nBOOLEAN KSIAPI KphpCidEnumPostPopulate(\n    _In_ PVOID Context,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_OBJECT_TYPE objectType;\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(Parameter);\n\n    objectType = KphGetObjectType(Context);\n\n    if (objectType == KphProcessContextType)\n    {\n        process = Context;\n        KphVerifyProcessAndProtectIfAppropriate(process);\n    }\n\n    return FALSE;\n}\n\n// from phnative.h\n#define KPH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes))\n#define KPH_NEXT_PROCESS(Process) (                                            \\\n    ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ?                \\\n    (PSYSTEM_PROCESS_INFORMATION)Add2Ptr((Process),                            \\\n    ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) :               \\\n    NULL                                                                       \\\n    )\n\n/**\n * \\brief Populates the CID tracking.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCidPopulate(\n    VOID\n    )\n{\n    NTSTATUS status;\n    ULONG size;\n    PVOID buffer;\n    PSYSTEM_PROCESS_INFORMATION info;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    size = (PAGE_SIZE * 4);\n    buffer = KphAllocatePaged(size, KPH_TAG_CID_POPULATE);\n    if (!buffer)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Failed to allocate buffer for process information.\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    for (;;)\n    {\n        status = ZwQuerySystemInformation(SystemProcessInformation,\n                                          buffer,\n                                          size,\n                                          &size);\n        if (NT_SUCCESS(status))\n        {\n            break;\n        }\n\n        if ((status != STATUS_BUFFER_TOO_SMALL) &&\n            (status != STATUS_INFO_LENGTH_MISMATCH))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"ZwQuerySystemInformation failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        if (size == 0)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"ZwQuerySystemInformation returned zero size!\");\n\n            NT_ASSERT(!NT_SUCCESS(status));\n            goto Exit;\n        }\n\n        KphFree(buffer, KPH_TAG_CID_POPULATE);\n        buffer = KphAllocatePaged(size, KPH_TAG_CID_POPULATE);\n        if (!buffer)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"Failed to allocate buffer for process information.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Trying again with larger buffer (%lu)...\",\n                      size);\n    }\n\n    //\n    // N.B. Because of the way we start up we guarantee the thread and process\n    // notifications routines are blocked until we complete this work. This\n    // gives us a guarantee that a new process/thread can't be fully created or\n    // tracked before we get here. However, this is still the possibility of\n    // a TOCTOU for an exiting process/thread. We need to take care here during\n    // initialization. If the process/thread is already exited we should not\n    // track it.\n    //\n\n    NT_ASSERT(NT_SUCCESS(status));\n    NT_ASSERT(size >= sizeof(SYSTEM_PROCESS_INFORMATION));\n\n    for (info = KPH_FIRST_PROCESS(buffer); info; info = KPH_NEXT_PROCESS(info))\n    {\n        PKPH_PROCESS_CONTEXT process;\n        PEPROCESS processObject;\n\n        if (!info->UniqueProcessId)\n        {\n            //\n            // Idle Process.\n            // For now we aren't going to track it. There are \"valid\" watchdog\n            // threads in the idle process, but we can't look up their thread\n            // objects in a documented way. For simplicity, for now, we opt\n            // not to track it.\n            //\n            continue;\n        }\n\n        if (info->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))\n        {\n            //\n            // System Process\n            //\n            processObject = PsInitialSystemProcess;\n            ObReferenceObject(processObject);\n        }\n        else\n        {\n            //\n            // Check if we should track this process during population.\n            // Ultimately here we're ensuring the process isn't already exited.\n            // Otherwise there is the possibility of an object leak from TOCTOU.\n            //\n\n            status = PsLookupProcessByProcessId(info->UniqueProcessId,\n                                                &processObject);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              TRACKING,\n                              \"PsLookupProcessByProcessId failed: %!STATUS!\",\n                              status);\n\n                continue;\n            }\n\n            if (PsGetProcessExitProcessCalled(processObject))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              TRACKING,\n                              \"PsGetProcessExitProcessCalled reported TRUE \"\n                              \"(process %lu)\",\n                              HandleToULong(info->UniqueProcessId));\n\n                ObDereferenceObject(processObject);\n                continue;\n            }\n        }\n\n        process = KphpTrackContext(info->UniqueProcessId,\n                                   KphProcessContextType,\n                                   sizeof(KPH_PROCESS_CONTEXT),\n                                   processObject);\n\n        ObDereferenceObject(processObject);\n        processObject = NULL;\n\n        if (!process)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"KphpTrackContext failed (process %lu)\",\n                          HandleToULong(info->UniqueProcessId));\n            continue;\n        }\n\n        process->CreatorClientId.UniqueProcess = NtCurrentProcess();\n        process->CreatorClientId.UniqueThread = NtCurrentThread();\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Tracking process %wZ (%lu)\",\n                      &process->ImageName,\n                      HandleToULong(process->ProcessId));\n\n        for (ULONG i = 0; i < info->NumberOfThreads; i++)\n        {\n            PKPH_THREAD_CONTEXT thread;\n            PETHREAD threadObject;\n            PSYSTEM_THREAD_INFORMATION threadInfo;\n\n            threadInfo = &info->Threads[i];\n\n            status = PsLookupThreadByThreadId(threadInfo->ClientId.UniqueThread,\n                                              &threadObject);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              TRACKING,\n                              \"PsLookupThreadByThreadId failed \"\n                              \"(thread %lu in process %wZ (%lu))): %!STATUS!\",\n                              HandleToULong(threadInfo->ClientId.UniqueThread),\n                              &process->ImageName,\n                              HandleToULong(process->ProcessId),\n                              status);\n\n                continue;\n            }\n\n            if (PsIsThreadTerminating(threadObject))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              TRACKING,\n                              \"PsIsThreadTerminating reported TRUE \"\n                              \"(thread %lu in process %wZ (%lu)))\",\n                              HandleToULong(threadInfo->ClientId.UniqueThread),\n                              &process->ImageName,\n                              HandleToULong(process->ProcessId));\n\n                ObDereferenceObject(threadObject);\n                continue;\n            }\n\n            thread = KphpTrackContext(threadInfo->ClientId.UniqueThread,\n                                      KphThreadContextType,\n                                      sizeof(KPH_THREAD_CONTEXT),\n                                      threadObject);\n\n            ObDereferenceObject(threadObject);\n            threadObject = NULL;\n\n            if (!thread)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              TRACKING,\n                              \"KphpTrackContext failed \"\n                              \"(thread %lu in process %wZ (%lu))\",\n                              HandleToULong(threadInfo->ClientId.UniqueThread),\n                              &process->ImageName,\n                              HandleToULong(process->ProcessId));\n                continue;\n            }\n\n            thread->CreatorClientId.UniqueProcess = NtCurrentProcess();\n            thread->CreatorClientId.UniqueThread = NtCurrentThread();\n\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"Tracking thread %lu in process %wZ (%lu)\",\n                          HandleToULong(thread->ClientId.UniqueThread),\n                          &process->ImageName,\n                          HandleToULong(thread->ClientId.UniqueProcess));\n\n            KphDereferenceObject(thread);\n        }\n\n        KphDereferenceObject(process);\n    }\n\nExit:\n\n    KphCidMarkPopulated();\n\n    if (buffer)\n    {\n        KphFree(buffer, KPH_TAG_CID_POPULATE);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        KphEnumerateCidContexts(KphpCidEnumPostPopulate, NULL);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Tracks a process context.\n *\n * \\param[in] Process The process to start tracking.\n *\n * \\return Pointer to the process context, null on allocation failure. May\n * return an existing process context if the process is already tracked. The\n * caller *must* dereference the object when they are through with it.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphTrackProcessContext(\n    _In_ PEPROCESS Process\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphpCidWaitForPopulate();\n\n    return KphpTrackContext(PsGetProcessId(Process),\n                            KphProcessContextType,\n                            sizeof(KPH_PROCESS_CONTEXT),\n                            Process);\n}\n\n/**\n * \\brief Stops tracking a process context.\n *\n * \\param[in] ProcessId The process ID of the process stop tracking.\n *\n * \\return Pointer to the process context, null if not found. The caller *must*\n * dereference the object when they are through with it.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphUntrackProcessContext(\n    _In_ HANDLE ProcessId\n    )\n{\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphpCidWaitForPopulate();\n\n    process = KphpUntrackContext(ProcessId, KphProcessContextType);\n    if (!process)\n    {\n        return NULL;\n    }\n\n    KphpUnlinkProcessContextThreadContexts(process);\n\n    return process;\n}\n\n/**\n * \\brief Tracks a thread context.\n *\n * \\param[in] Thread The thread to start tracking.\n *\n * \\return Pointer to the thread context, null on allocation failure. May\n * return an existing thread context if the thread is already tracked. The\n * caller *must* dereference the object when they are through with it.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nPKPH_THREAD_CONTEXT KphTrackThreadContext(\n    _In_ PETHREAD Thread\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphpCidWaitForPopulate();\n\n    return KphpTrackContext(PsGetThreadId(Thread),\n                            KphThreadContextType,\n                            sizeof(KPH_THREAD_CONTEXT),\n                            Thread);\n}\n\n/**\n * \\brief Stops tracking a thread context.\n *\n * \\param[in] ThreadId The thread ID of the thread stop tracking.\n *\n * \\return Pointer to the thread context, null if not found. The caller *must*\n * dereference the object when they are through with it.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nPKPH_THREAD_CONTEXT KphUntrackThreadContext(\n    _In_ HANDLE ThreadId\n    )\n{\n    PKPH_THREAD_CONTEXT thread;\n\n    KPH_PAGED_CODE();\n\n    KphpCidWaitForPopulate();\n\n    thread = KphpUntrackContext(ThreadId, KphThreadContextType);\n    if (!thread)\n    {\n        return NULL;\n    }\n\n    if (thread->ProcessContext)\n    {\n        KphAcquireRWLockExclusive(&thread->ProcessContext->ThreadListLock);\n\n        if (thread->InThreadList)\n        {\n            RemoveEntryList(&thread->ThreadListEntry);\n            thread->InThreadList = FALSE;\n            thread->ProcessContext->NumberOfThreads--;\n            KphDereferenceObject(thread);\n        }\n\n        if (thread->ProcessContext->InitialThread == thread)\n        {\n            thread->ProcessContext->InitialThread = NULL;\n            KphDereferenceObject(thread);\n        }\n\n        KphReleaseRWLock(&thread->ProcessContext->ThreadListLock);\n    }\n\n    return thread;\n}\n\ntypedef struct _KPH_ENUM_CONTEXT\n{\n    PKPH_ENUM_CID_CONTEXTS_CALLBACK CidCallback;\n    PKPH_ENUM_PROCESS_CONTEXTS_CALLBACK ProcessCallback;\n    PKPH_ENUM_THREAD_CONTEXTS_CALLBACK ThreadCallback;\n    PVOID Parameter;\n} KPH_ENUM_CONTEXT, *PKPH_ENUM_CONTEXT;\n\n/**\n * \\brief Enumeration callback.\n *\n * \\param[in] Object The object from the enumeration.\n * \\param[in] Parameter The enumeration context from the caller.\n *\n * \\return FALSE to keep enumerating if the object type is not what was asked\n * for or the return value from callers callback.\n */\n_Function_class_(KPH_CID_ENUMERATE_CALLBACK)\nBOOLEAN KSIAPI KphpEnumerateContexts(\n    _In_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_ENUM_CONTEXT context;\n    PKPH_OBJECT_TYPE objectType;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Parameter);\n\n    context = Parameter;\n    objectType = KphGetObjectType(Object);\n\n    if (context->CidCallback)\n    {\n        NT_ASSERT((objectType == KphProcessContextType) ||\n                  (objectType == KphThreadContextType));\n        NT_ASSERT(!context->ProcessCallback);\n        NT_ASSERT(!context->ThreadCallback);\n\n        return context->CidCallback(Object, context->Parameter);\n    }\n\n    if (context->ProcessCallback)\n    {\n        NT_ASSERT(!context->CidCallback);\n        NT_ASSERT(!context->ThreadCallback);\n\n        if (objectType != KphProcessContextType)\n        {\n            return FALSE;\n        }\n\n        return context->ProcessCallback(Object, context->Parameter);\n    }\n\n    NT_ASSERT(!context->CidCallback);\n    NT_ASSERT(!context->ProcessCallback);\n    NT_ASSERT(context->ThreadCallback);\n\n    if (objectType != KphThreadContextType)\n    {\n        return FALSE;\n    }\n\n    return context->ThreadCallback(Object, context->Parameter);\n}\n\n/**\n * \\brief Enumerates process contexts.\n *\n * \\param[in] Callback The callback to invoke for each process context. The\n * callback should return TRUE to stop enumerating or FALSE to continue.\n * \\param[in] Parameter Optional parameter passed to the callback.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphEnumerateProcessContexts(\n    _In_ PKPH_ENUM_PROCESS_CONTEXTS_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    )\n{\n    KPH_ENUM_CONTEXT context;\n\n    KPH_PAGED_CODE();\n\n    context.CidCallback = NULL;\n    context.ProcessCallback = Callback;\n    context.ThreadCallback = NULL;\n    context.Parameter = Parameter;\n\n    KphCidEnumerate(&KphpCidTable, KphpEnumerateContexts, &context);\n}\n\n/**\n * \\brief Enumerates thread contexts.\n *\n * \\param[in] Callback The callback to invoke for each thread context. The\n * callback should return TRUE to stop enumerating or FALSE to continue.\n * \\param[in] Parameter Optional parameter passed to the callback.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphEnumerateThreadContexts(\n    _In_ PKPH_ENUM_THREAD_CONTEXTS_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    )\n{\n    KPH_ENUM_CONTEXT context;\n\n    KPH_PAGED_CODE();\n\n    context.CidCallback = NULL;\n    context.ProcessCallback = NULL;\n    context.ThreadCallback = Callback;\n    context.Parameter = Parameter;\n\n    KphCidEnumerate(&KphpCidTable, KphpEnumerateContexts, &context);\n}\n\n/**\n * \\brief Enumerates CID contexts.\n *\n * \\param[in] Callback The callback to invoke for each CID context. The\n * callback should return TRUE to stop enumerating or FALSE to continue.\n * \\param[in] Parameter Optional parameter passed to the callback.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphEnumerateCidContexts(\n    _In_ KPH_ENUM_CID_CONTEXTS_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    )\n{\n    KPH_ENUM_CONTEXT context;\n\n    KPH_PAGED_CODE();\n\n    context.CidCallback = Callback;\n    context.ProcessCallback = NULL;\n    context.ThreadCallback = NULL;\n    context.Parameter = Parameter;\n\n    KphCidEnumerate(&KphpCidTable, KphpEnumerateContexts, &context);\n}\n\n/**\n * \\brief Checks the APC no-op routine for a given process.\n *\n * \\param[in] Process The context of a process to check the routine of.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCheckProcessApcNoopRoutine(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (Process->ApcNoopRoutine)\n    {\n        return STATUS_SUCCESS;\n    }\n\n    status = ObOpenObjectByPointer(Process->EProcess,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   PROCESS_ALL_ACCESS,\n                                   *PsProcessType,\n                                   KernelMode,\n                                   &processHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        processHandle = NULL;\n        goto Exit;\n    }\n\n    policyInfo.Policy = ProcessControlFlowGuardPolicy;\n    policyInfo.ControlFlowGuardPolicy.Flags = 0;\n    status = ZwQueryInformationProcess(processHandle,\n                                       ProcessMitigationPolicy,\n                                       &policyInfo,\n                                       sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"ZwQueryInformationProcess failed: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    if (policyInfo.ControlFlowGuardPolicy.EnableXfg)\n    {\n        status = KphDisableXfgOnTarget(processHandle, KphNtDllRtlSetBits);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"KphDisableXfgOnTarget failed (0x%08lx): %!STATUS!\",\n                          policyInfo.ControlFlowGuardPolicy.Flags,\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    if (policyInfo.ControlFlowGuardPolicy.EnableExportSuppression)\n    {\n        status = KphGuardGrantSuppressedCallAccess(processHandle,\n                                                   KphNtDllRtlSetBits);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"KphGuardGrantSuppressedCallAccess failed \"\n                          \"(0x%08lx): %!STATUS!\",\n                          policyInfo.ControlFlowGuardPolicy.Flags,\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    Process->ApcNoopRoutine = (PKNORMAL_ROUTINE)KphNtDllRtlSetBits;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (processHandle)\n    {\n        ObCloseHandle(processHandle, KernelMode);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Performs actions to verify a process and begin protecting it. Process\n * protection is only started processes that meet the necessary requirements.\n *\n * \\param[in] Process The context of a process verify and protect.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphVerifyProcessAndProtectIfAppropriate(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (Process->ImageFileName &&\n        Process->FileObject &&\n        !Process->VerifiedProcess)\n    {\n        status = KphVerifyFile(Process->ImageFileName, Process->FileObject);\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"KphVerifyFile: %lu \\\"%wZ\\\": %!STATUS!\",\n                      HandleToULong(Process->ProcessId),\n                      Process->ImageFileName,\n                      status);\n\n        if (NT_SUCCESS(status))\n        {\n            Process->VerifiedProcess = TRUE;\n        }\n    }\n\n    if (KphTestProcessContextState(Process, KPH_PROCESS_STATE_LOW))\n    {\n        ACCESS_MASK processAllowedMask;\n        ACCESS_MASK threadAllowedMask;\n\n        if (KphProtectionsSuppressed())\n        {\n            //\n            // Allow all access, but still exercise the code by registering.\n            //\n            processAllowedMask = ((ACCESS_MASK)-1);\n            threadAllowedMask = ((ACCESS_MASK)-1);\n        }\n        else\n        {\n            processAllowedMask = KPH_PROTECTED_PROCESS_MASK;\n            threadAllowedMask = KPH_PROTECTED_THREAD_MASK;\n        }\n\n        status = KphStartProtectingProcess(Process,\n                                           processAllowedMask,\n                                           threadAllowedMask);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"KphStartProtectingProcess failed: %!STATUS!\",\n                          status);\n\n            NT_ASSERT(!Process->Protected);\n        }\n    }\n}\n\n/**\n * \\brief Gets the process image name for a given thread.\n *\n * \\details The image name of a thread might not be available if there is no\n * process context associated with the thread. This is very unlikely but\n * possible if resources are constrained on the system. If there is no process\n * context associated with the thread, this function will return NULL.\n *\n * \\param[in] Thread The thread context to get the process image name of.\n *\n * \\return Image name for the process of the given thread, otherwise NULL.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\n_Maybenull_\nPUNICODE_STRING KphGetThreadImageName(\n    _In_ PKPH_THREAD_CONTEXT Thread\n    )\n{\n    KPH_PAGED_CODE();\n\n    if (!Thread->ProcessContext)\n    {\n        return NULL;\n    }\n\n    return &Thread->ProcessContext->ImageName;\n}\n\n/**\n * \\brief Retrieves the process state mask from a process.\n *\n * \\param[in] Process The process to get the state from.\n *\n * \\return State mask describing what state the process is in.\n */\n_IRQL_requires_max_(APC_LEVEL)\nKPH_PROCESS_STATE KphGetProcessState(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    )\n{\n    KPH_PROCESS_STATE processState;\n\n    KPH_PAGED_CODE();\n\n    if (KphProtectionsSuppressed())\n    {\n        //\n        // This ultimately permits low state callers into the driver. But still\n        // check for verification. We still want to exercise the code below,\n        // regardless.\n        //\n        processState = ~KPH_PROCESS_VERIFIED_PROCESS;\n    }\n    else\n    {\n        processState = 0;\n    }\n\n    if (Process->SecurelyCreated)\n    {\n        processState |= KPH_PROCESS_SECURELY_CREATED;\n    }\n\n    if (Process->VerifiedProcess)\n    {\n        processState |= KPH_PROCESS_VERIFIED_PROCESS;\n    }\n\n    if (Process->Protected)\n    {\n        processState |= KPH_PROCESS_PROTECTED_PROCESS;\n    }\n\n    if (Process->CreateNotification)\n    {\n        processState |= KPH_PROCESS_CREATE_NOTIFICATION;\n    }\n\n    if (ReadSizeTAcquire(&Process->NumberOfUntrustedImageLoads) == 0)\n    {\n        processState |= KPH_PROCESS_NO_UNTRUSTED_IMAGES;\n    }\n\n    if (!Process->StateTracking.Debugged)\n    {\n        if (!PsIsProcessBeingDebugged(Process->EProcess))\n        {\n            processState |= KPH_PROCESS_NOT_BEING_DEBUGGED;\n        }\n        else\n        {\n            Process->StateTracking.Debugged = TRUE;\n        }\n    }\n\n    if (!Process->FileObject)\n    {\n        return processState;\n    }\n\n    processState |= KPH_PROCESS_HAS_FILE_OBJECT;\n\n    if (!Process->StateTracking.FileObjectWritable)\n    {\n        if (!Process->FileObject->WriteAccess || !Process->FileObject->SharedWrite)\n        {\n            processState |= KPH_PROCESS_NO_WRITABLE_FILE_OBJECT;\n        }\n        else\n        {\n            Process->StateTracking.FileObjectWritable = TRUE;\n        }\n    }\n\n    if (!Process->StateTracking.FileObjectTransaction)\n    {\n        if (!IoGetTransactionParameterBlock(Process->FileObject))\n        {\n            processState |= KPH_PROCESS_NO_FILE_TRANSACTION;\n        }\n        else\n        {\n            Process->StateTracking.FileObjectTransaction = TRUE;\n        }\n    }\n\n    if (!Process->FileObject->SectionObjectPointer)\n    {\n        return processState;\n    }\n\n    processState |= KPH_PROCESS_HAS_SECTION_OBJECT_POINTERS;\n\n    if (!Process->StateTracking.UserWritableReferences)\n    {\n        if (!MmDoesFileHaveUserWritableReferences(Process->FileObject->SectionObjectPointer))\n        {\n            processState |= KPH_PROCESS_NO_USER_WRITABLE_REFERENCES;\n        }\n        else\n        {\n            Process->StateTracking.UserWritableReferences = TRUE;\n        }\n    }\n\n    return processState;\n}\n\n/**\n * \\brief Queries information about a process context.\n *\n * \\details Some information is not cached up front for one reason or another.\n * Usually because dynamic data isn't available. This path enables a generic\n * way to query information about a process context and try to populate and the\n * cache the information if it is not already available.\n *\n * \\param[in] Process The process context to query.\n * \\param[in] InformationClass The information class to query.\n * \\param[out] Information Optional buffer to receive the information.\n * \\param[in] InformationLength The size of the information buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationProcessContext(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_ KPH_PROCESS_CONTEXT_INFORMATION_CLASS InformationClass,\n    _Out_writes_bytes_opt_(InformationLength) PVOID Information,\n    _In_ ULONG InformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    returnLength = 0;\n\n    switch (InformationClass)\n    {\n        case KphProcessContextWSLProcessId:\n        {\n            if (Process->SubsystemType != SubsystemInformationTypeWSL)\n            {\n                status = STATUS_INVALID_PARAMETER;\n                goto Exit;\n            }\n\n            returnLength = sizeof(ULONG);\n\n            if (!Information || (InformationLength < sizeof(ULONG)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                goto Exit;\n            }\n\n            if (!Process->WSL.ValidProcessId)\n            {\n                PKPH_THREAD_CONTEXT thread;\n\n                KphAcquireRWLockShared(&Process->ThreadListLock);\n\n                thread = Process->InitialThread;\n                if (thread)\n                {\n                    KphReferenceObject(thread);\n                }\n\n                KphReleaseRWLock(&Process->ThreadListLock);\n\n                if (!thread)\n                {\n                    status = STATUS_INSUFFICIENT_RESOURCES;\n                    goto Exit;\n                }\n\n                KphpInitThreadContextInOriginalEnvironment(thread, TRUE);\n\n                KphDereferenceObject(thread);\n            }\n\n            if (!Process->WSL.ValidProcessId)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"WSL process ID is not valid.\");\n\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            *(PULONG)Information = Process->WSL.ProcessId;\n\n            status = STATUS_SUCCESS;\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n\nExit:\n\n    if (ReturnLength)\n    {\n        *ReturnLength = returnLength;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries information about a thread context.\n *\n * \\details Some information is not cached up front for one reason or another.\n * Usually because dynamic data isn't available. This path enables a generic\n * way to query information about a thread context and try to populate and the\n * cache the information if it is not already available.\n *\n * \\param[in] Thread The thread context to query.\n * \\param[in] InformationClass The information class to query.\n * \\param[out] Information Optional buffer to receive the information.\n * \\param[in] InformationLength The size of the information buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationThreadContext(\n    _In_ PKPH_THREAD_CONTEXT Thread,\n    _In_ KPH_THREAD_CONTEXT_INFORMATION_CLASS InformationClass,\n    _Out_writes_bytes_opt_(InformationLength) PVOID Information,\n    _In_ ULONG InformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    returnLength = 0;\n\n    switch (InformationClass)\n    {\n        case KphThreadContextWSLThreadId:\n        {\n            if (Thread->SubsystemType != SubsystemInformationTypeWSL)\n            {\n                status = STATUS_INVALID_HANDLE;\n                goto Exit;\n            }\n\n            returnLength = sizeof(ULONG);\n\n            if (!Information || (InformationLength < sizeof(ULONG)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                goto Exit;\n            }\n\n            if (!Thread->WSL.ValidThreadId)\n            {\n                KphpInitThreadContextInOriginalEnvironment(Thread, TRUE);\n            }\n\n            if (!Thread->WSL.ValidThreadId)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"WSL thread ID is not valid.\");\n\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            *(PULONG)Information = Thread->WSL.ThreadId;\n\n            status = STATUS_SUCCESS;\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n\nExit:\n\n    if (ReturnLength)\n    {\n        *ReturnLength = returnLength;\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/comms.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <comms.h>\n#include <informer.h>\n#include <kphmsgdyn.h>\n\n#include <trace.h>\n\n#define KPH_COMMS_MIN_QUEUE_THREADS 2\n#define KPH_COMMS_MAX_QUEUE_THREADS 64\n#define KPH_COMMS_MAX_CLIENTS       32\n\ntypedef struct _KPHM_QUEUE_ITEM\n{\n    LIST_ENTRY Entry;\n    BOOLEAN NonPaged;\n    PKPH_MESSAGE Message;\n    ULONG TargetClientCount;\n    PKPH_CLIENT TargetClients[KPH_COMMS_MAX_CLIENTS];\n} KPHM_QUEUE_ITEM, *PKPHM_QUEUE_ITEM;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpClientTypeName = RTL_CONSTANT_STRING(L\"KphClient\");\nstatic const UNICODE_STRING KphpClientInformerStateTypeName = RTL_CONSTANT_STRING(L\"KphClientInformerState\");\nstatic const LARGE_INTEGER KphpMessageMinTimeout = KPH_TIMEOUT(300);\nstatic const UNICODE_STRING KphpMessageQueueThreadName = RTL_CONSTANT_STRING(L\"System Informer Message Queue\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PFLT_PORT KphpFltServerPort = NULL;\nstatic PKPH_OBJECT_TYPE KphpClientType = NULL;\nstatic PKPH_OBJECT_TYPE KphpClientInformerStateType = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\nstatic KPH_RUNDOWN KphpCommsRundown;\nstatic PAGED_LOOKASIDE_LIST KphpMessageLookaside;\nstatic NPAGED_LOOKASIDE_LIST KphpNPagedMessageLookaside;\nstatic NPAGED_LOOKASIDE_LIST KphpMessageQueueItemLookaside;\nstatic ALIGNED_EX_SPINLOCK KphpConnectedClientsLock = 0;\nstatic ULONG KphpConnectedClientsCount = 0;\nstatic PKPH_CLIENT KphpConnectedClients[KPH_COMMS_MAX_CLIENTS] = { NULL };\nstatic KQUEUE KphpMessageQueue;\nstatic PETHREAD* KphpMessageQueueThreads = NULL;\nstatic ULONG KphpMessageQueueThreadsCount = 0;\n\n/**\n * \\brief Gets the number of connected clients.\n *\n * \\return Number of connected clients.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG KphGetConnectedClientCount(\n    VOID\n    )\n{\n    ULONG count;\n    KIRQL oldIrql;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    oldIrql = ExAcquireSpinLockShared(&KphpConnectedClientsLock);\n\n    count = KphpConnectedClientsCount;\n\n    ExReleaseSpinLockShared(&KphpConnectedClientsLock, oldIrql);\n\n    return count;\n}\n\n/**\n * \\brief Gets the number of active informer clients.\n *\n * \\return Number of active informer clients.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG KphGetInformerClientCount(\n    VOID\n    )\n{\n    ULONG count;\n    KIRQL oldIrql;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    count = 0;\n\n    oldIrql = ExAcquireSpinLockShared(&KphpConnectedClientsLock);\n\n    for (ULONG i = 0; i < KphpConnectedClientsCount; i++)\n    {\n        PKPH_CLIENT client;\n        PKPH_CLIENT_INFORMER_STATE state;\n\n        client = KphpConnectedClients[i];\n        state = KphAtomicReferenceObject(&client->InformerState.Atomic);\n        if (state)\n        {\n            count++;\n            KphDereferenceObject(state);\n        }\n    }\n\n    ExReleaseSpinLockShared(&KphpConnectedClientsLock, oldIrql);\n\n    return count;\n}\n\n/**\n * \\brief Retrieves the connected clients. The caller is responsible for\n * dereferencing the clients after use.\n *\n * \\param[out] Clients Receives the connected clients.\n *\n * \\return Number of connected clients.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG KphpGetInformerClients(\n    _Out_writes_to_(KPH_COMMS_MAX_CLIENTS, return) PKPH_CLIENT* Clients\n    )\n{\n    ULONG count;\n    KIRQL oldIrql;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    count = 0;\n\n    oldIrql = ExAcquireSpinLockShared(&KphpConnectedClientsLock);\n\n    for (ULONG i = 0; i < KphpConnectedClientsCount; i++)\n    {\n        PKPH_CLIENT client;\n        PKPH_CLIENT_INFORMER_STATE state;\n\n        client = KphpConnectedClients[i];\n        state = KphAtomicReferenceObject(&client->InformerState.Atomic);\n        if (state)\n        {\n            KphReferenceObject(client);\n            Clients[count++] = client;\n            KphDereferenceObject(state);\n        }\n    }\n\n    ExReleaseSpinLockShared(&KphpConnectedClientsLock, oldIrql);\n\n    return count;\n}\n\n/**\n * \\brief Adds a client to the connected clients list.\n *\n * \\param[in] Client The client to add.\n *\n * \\return TRUE if the client was added successfully, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphpAddConnectedClient(\n    _In_ PKPH_CLIENT Client\n    )\n{\n    BOOLEAN result;\n    KIRQL oldIrql;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    result = FALSE;\n\n    oldIrql = ExAcquireSpinLockExclusive(&KphpConnectedClientsLock);\n\n    if (KphpConnectedClientsCount < KPH_COMMS_MAX_CLIENTS)\n    {\n        KphpConnectedClients[KphpConnectedClientsCount++] = Client;\n        KphReferenceObject(Client);\n        result = TRUE;\n    }\n\n    ExReleaseSpinLockExclusive(&KphpConnectedClientsLock, oldIrql);\n\n    return result;\n}\n\n/**\n * \\brief Removes a client from the connected clients list. The caller is\n * responsible for dereferencing any return client.\n *\n * \\param[in] Client The client to remove.\n *\n * \\return The removed client if it was found, NULL otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_CLIENT KphpRemoveConnectedClient(\n    _In_ PKPH_CLIENT Client\n    )\n{\n    PKPH_CLIENT client;\n    KIRQL oldIrql;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    client = NULL;\n\n    oldIrql = ExAcquireSpinLockExclusive(&KphpConnectedClientsLock);\n\n    for (ULONG i = 0; i < KphpConnectedClientsCount; i++)\n    {\n        if (KphpConnectedClients[i] != Client)\n        {\n            continue;\n        }\n\n        client = KphpConnectedClients[i];\n        KphpConnectedClientsCount--;\n\n        RtlMoveMemory(&KphpConnectedClients[i],\n                      &KphpConnectedClients[i + 1],\n                      sizeof(PKPH_CLIENT) * ((KPH_COMMS_MAX_CLIENTS - i) - 1));\n\n        KphpConnectedClients[KPH_COMMS_MAX_CLIENTS - 1] = NULL;\n\n        break;\n    }\n\n    ExReleaseSpinLockExclusive(&KphpConnectedClientsLock, oldIrql);\n\n    return client;\n}\n\n/**\n * \\brief Allocates a message queue item.\n *\n * \\return Message queue item, null on allocation failure.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_\nPKPHM_QUEUE_ITEM KphpAllocateMessageQueueItem()\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    return KphAllocateFromNPagedLookaside(&KphpMessageQueueItemLookaside);\n}\n\n/**\n * \\brief Allocates a non-paged message.\n *\n * \\return Non-paged message, null on allocation failure.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_\nPKPH_MESSAGE KphAllocateNPagedMessage(\n    VOID\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    return KphAllocateFromNPagedLookaside(&KphpNPagedMessageLookaside);\n}\n\n/**\n * \\brief Frees a non-paged message.\n *\n * \\param[in] Message The message to free.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphFreeNPagedMessage(\n    _In_freesMem_ PKPH_MESSAGE Message\n    )\n{\n    NT_ASSERT(Message);\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    KphFreeToNPagedLookaside(&KphpNPagedMessageLookaside, Message);\n}\n\n/**\n * \\brief Determines whether a message is rate limited for a client.\n *\n * \\param[in] Client The client to check the rate limit for.\n * \\param[in] Message The message to check the rate limit for.\n *\n * \\return TRUE if the message is rate limited, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphpCommsMessageIsRateLimited(\n    _In_ PKPH_CLIENT Client,\n    _In_ PKPH_MESSAGE Message\n    )\n{\n    PKPH_CLIENT_INFORMER_STATE state;\n    BOOLEAN limited;\n    ULONG index;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    limited = FALSE;\n\n    state = KphAtomicReferenceObject(&Client->InformerState.Atomic);\n    if (!state)\n    {\n        goto Exit;\n    }\n\n    index = (Message->Header.MessageId - (MaxKphMsgClientAllowed + 1));\n    if (!NT_VERIFY(index < KPH_INFORMER_COUNT))\n    {\n        goto Exit;\n    }\n\n    if (KphRateLimitConsumeToken(&state->InformerRateLimit[index],\n                                 &Message->Header.TimeStamp))\n    {\n        goto Exit;\n    }\n\n    limited = TRUE;\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  COMMS,\n                  \"Message rate limited (%lu - %!TIME!) to client: \"\n                  \"%wZ (%lu)\",\n                  (ULONG)Message->Header.MessageId,\n                  Message->Header.TimeStamp.QuadPart,\n                  &Client->Process->ImageName,\n                  HandleToULong(Client->Process->ProcessId));\n\nExit:\n\n    if (state)\n    {\n        KphDereferenceObject(state);\n    }\n\n    return limited;\n}\n\n/**\n * \\brief Determines whether a queue is rate limited for a client.\n *\n * \\param[in] Client The client to check the rate limit for.\n * \\param[in] Message The message to check the rate limit for.\n *\n * \\return TRUE if the queue is rate limited, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphpCommsQueueIsRateLimited(\n    _In_ PKPH_CLIENT Client,\n    _In_ PKPH_MESSAGE Message\n    )\n{\n    PKPH_CLIENT_INFORMER_STATE state;\n    BOOLEAN limited;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    limited = FALSE;\n\n    state = KphAtomicReferenceObject(&Client->InformerState.Atomic);\n    if (!state)\n    {\n        goto Exit;\n    }\n\n    if (KphRateLimitConsumeToken(&state->AsyncQueueRateLimit,\n                                 &Message->Header.TimeStamp))\n    {\n        goto Exit;\n    }\n\n    limited = TRUE;\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  COMMS,\n                  \"Message rate limited (%lu - %!TIME!) to client: \"\n                  \"%wZ (%lu)\",\n                  (ULONG)Message->Header.MessageId,\n                  Message->Header.TimeStamp.QuadPart,\n                  &Client->Process->ImageName,\n                  HandleToULong(Client->Process->ProcessId));\n\nExit:\n\n    if (state)\n    {\n        KphDereferenceObject(state);\n    }\n\n    return limited;\n}\n\n/**\n * \\brief Retrieves the non-rate-limited clients for a message. The caller is\n * responsible for dereferencing the clients after use.\n *\n * \\param[in] Message The message to check the rate limits for.\n * \\param[out] Clients Receives the non-rate-limited clients.\n *\n * \\return Number of non-rate-limited clients.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG KphpGetNonRateLimitedClients(\n    _Out_writes_to_(KPH_COMMS_MAX_CLIENTS, return) PKPH_CLIENT* Clients,\n    _In_ PKPH_MESSAGE Message\n    )\n{\n    ULONG count;\n    ULONG clientsCount;\n    PKPH_CLIENT clients[KPH_COMMS_MAX_CLIENTS];\n\n    count = 0;\n    clientsCount = KphpGetInformerClients(clients);\n\n    for (ULONG i = 0; i < clientsCount; i++)\n    {\n        if (KphpCommsMessageIsRateLimited(clients[i], Message))\n        {\n            KphDereferenceObjectDeferDelete(clients[i]);\n            continue;\n        }\n\n        Clients[count++] = clients[i];\n    }\n\n    return count;\n}\n\n/**\n * \\brief Copies a message to a client ring buffer.\n *\n * \\param[in] Client The client to copy the message to.\n * \\param[in] Message The message to copy to the ring buffer.\n *\n * \\return TRUE if the message was copied successfully, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphpCommsCopyMessageToRingBuffer(\n    _In_ PKPH_CLIENT Client,\n    _In_ PKPH_MESSAGE Message\n    )\n{\n    PVOID buffer;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (!Client->RingBuffer)\n    {\n        return FALSE;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  COMMS,\n                  \"Sending message (%lu - %!TIME!) to client: %wZ (%lu)\",\n                  (ULONG)Message->Header.MessageId,\n                  Message->Header.TimeStamp.QuadPart,\n                  &Client->Process->ImageName,\n                  HandleToULong(Client->Process->ProcessId));\n\n    buffer = KphReserveRingBuffer(Client->RingBuffer,\n                                  Message->Header.Size);\n    if (!buffer)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Ring buffer exhausted (%lu - %!TIME!) %wZ (%lu)\",\n                      (ULONG)Message->Header.MessageId,\n                      Message->Header.TimeStamp.QuadPart,\n                      &Client->Process->ImageName,\n                      HandleToULong(Client->Process->ProcessId));\n\n        return FALSE;\n    }\n\n    RtlCopyMemory(buffer, Message, Message->Header.Size);\n    KphCommitRingBuffer(Client->RingBuffer, buffer);\n\n    return TRUE;\n}\n\n/**\n * \\brief Sends a message to all connected client ring buffers.\n *\n * \\details If a client can not receive the message in its ring buffer, it is\n * added to the output. The caller is responsible for dereferencing the clients\n * that could not receive the message. The output clients are destined to have\n * the message send to them using the asynchronous queue. Client rate limits\n * are checked for the message by this routine. If the client is rate limited\n * then the client is not added to the output.\n *\n * \\param[out] Clients Receives the clients that could not receive the message.\n * \\param[in] Message The message to send to the clients.\n *\n * \\return Number of clients that could not receive the message.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG KphpCommsSendMessageToRingBuffers(\n    _Out_writes_to_(KPH_COMMS_MAX_CLIENTS, return) PKPH_CLIENT* Clients,\n    _In_ PKPH_MESSAGE Message\n    )\n{\n    ULONG count;\n    ULONG clientsCount;\n    PKPH_CLIENT clients[KPH_COMMS_MAX_CLIENTS];\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    count = 0;\n\n    clientsCount = KphpGetNonRateLimitedClients(clients, Message);\n\n    for (ULONG i = 0; i < clientsCount; i++)\n    {\n        if (KphpCommsCopyMessageToRingBuffer(clients[i], Message) ||\n            KphpCommsQueueIsRateLimited(clients[i], Message))\n        {\n            KphDereferenceObjectDeferDelete(clients[i]);\n            continue;\n        }\n\n        Clients[count++] = clients[i];\n    }\n\n    return count;\n}\n\n/**\n * \\brief Sends a non-paged message asynchronously.\n *\n * \\param[in] Message The message to send asynchronously. The call assumes\n * ownership over the message. The caller should *not* free the message after\n * it is passed to this function.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCommsSendNPagedMessageAsync(\n    _In_aliasesMem_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUEUE_ITEM item;\n    ULONG targetClientCount;\n    PKPH_CLIENT targetClients[KPH_COMMS_MAX_CLIENTS];\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (!KphAcquireRundown(&KphpCommsRundown))\n    {\n        KphTracePrint(TRACE_LEVEL_WARNING,\n                      COMMS,\n                      \"Failed to acquire rundown, dropping message \"\n                      \"(%lu - %!TIME!)\",\n                      (ULONG)Message->Header.MessageId,\n                      Message->Header.TimeStamp.QuadPart);\n\n        KphFreeNPagedMessage(Message);\n        return;\n    }\n\n    targetClientCount = KphpCommsSendMessageToRingBuffers(targetClients,\n                                                          Message);\n    if (!targetClientCount)\n    {\n        goto Exit;\n    }\n\n    item = KphpAllocateMessageQueueItem();\n    if (!item)\n    {\n        KphTracePrint(TRACE_LEVEL_WARNING,\n                      COMMS,\n                      \"Failed to allocate queue item, dropping message \"\n                      \"(%lu - %!TIME!)\",\n                      (ULONG)Message->Header.MessageId,\n                      Message->Header.TimeStamp.QuadPart);\n\n        goto Exit;\n    }\n\n    item->Message = Message;\n    item->NonPaged = TRUE;\n    Message = NULL;\n\n    item->TargetClientCount = targetClientCount;\n    RtlCopyMemory(item->TargetClients,\n                  targetClients,\n                  sizeof(PKPH_CLIENT) * targetClientCount);\n    targetClientCount = 0;\n\n    KeInsertQueue(&KphpMessageQueue, &item->Entry);\n\nExit:\n\n    for (ULONG i = 0; i < targetClientCount; i++)\n    {\n        KphDereferenceObjectDeferDelete(targetClients[i]);\n    }\n\n    if (Message)\n    {\n        KphFreeNPagedMessage(Message);\n    }\n\n    KphReleaseRundown(&KphpCommsRundown);\n}\n\n/**\n * \\brief Captures the current stack and adds it to the message.\n *\n * \\param[in,out] Message The message to populate with the current stack.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCaptureStackInMessage(\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    NTSTATUS status;\n    PVOID frames[150];\n    KPHM_STACK_TRACE stack;\n    ULONG flags;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    flags = (KPH_STACK_BACK_TRACE_USER_MODE | KPH_STACK_BACK_TRACE_SKIP_KPH);\n\n    stack.Count = (USHORT)KphCaptureStackBackTrace(0,\n                                                   ARRAYSIZE(frames),\n                                                   frames,\n                                                   NULL,\n                                                   flags);\n    if (stack.Count == 0)\n    {\n        return;\n    }\n\n    stack.Frames = frames;\n\n    status = KphMsgDynAddStackTrace(Message, KphMsgFieldStackTrace, &stack);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"KphMsgDynAddStackTrace failed: %!STATUS!\",\n                      status);\n    }\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Frees a message queue item.\n *\n * \\param[in] Item Message queue item to free.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFreeMessageQueueItem(_In_freesMem_ PKPHM_QUEUE_ITEM Item)\n{\n    KPH_PAGED_CODE();\n\n    for (ULONG i = 0; i < Item->TargetClientCount; i++)\n    {\n        KphDereferenceObject(Item->TargetClients[i]);\n    }\n\n    if (Item->NonPaged)\n    {\n        KphFreeNPagedMessage(Item->Message);\n    }\n    else\n    {\n        KphFreeMessage(Item->Message);\n    }\n\n    KphFreeToNPagedLookaside(&KphpMessageQueueItemLookaside, Item);\n}\n\n/**\n * \\brief Allocates a client object.\n *\n * \\param[in] Size The size requested from the object infrastructure.\n *\n * \\return Allocated client object, null on allocation failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateClient(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    return KphAllocateNPaged(Size, KPH_TAG_CLIENT);\n}\n\n/**\n * \\brief Initializes a client object.\n *\n * \\param[in] Object The client object to initialize.\n * \\param[in] Parameter The process context associated with the client.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializeClient(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_CLIENT client;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Parameter);\n\n    client = Object;\n\n    client->Process = Parameter;\n    KphReferenceObject(client->Process);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Deletes a client object.\n *\n * \\param[in] Object The client object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpDeleteClient(\n    _Inout_ PVOID Object\n    )\n{\n    NTSTATUS status;\n    PKPH_CLIENT client;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    client = Object;\n\n    if (client->DriverUnloadProtectionRef.Count)\n    {\n        //\n        // The client is being destroyed while it has acquired driver unload\n        // protection. The communication handlers only acquire or release the\n        // protection once for each client, so we only need to call this once\n        // here.\n        //\n        status = KphReleaseDriverUnloadProtection(NULL);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          COMMS,\n                          \"KphReleaseDriverUnloadProtection failed: %!STATUS!\",\n                          status);\n        }\n    }\n\n    KphDereferenceObject(client->Process);\n\n    if (client->Port)\n    {\n        FltCloseClientPort(KphFltFilter, &client->Port);\n    }\n\n    if (client->RingBuffer)\n    {\n        KphDereferenceObject(client->RingBuffer);\n    }\n\n    KphAtomicAssignObjectReference(&client->InformerState.Atomic, NULL);\n}\n\n/**\n * \\brief Frees a client object.\n *\n * \\param[in] Object The client object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpFreeClient(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphFree(Object, KPH_TAG_CLIENT);\n}\n\n/**\n * \\brief Allocates a client informer state object.\n *\n * \\param[in] Size The size requested from the object infrastructure.\n *\n * \\return Allocated client informer state object, null on allocation failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateClientInformerState(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    return KphAllocateNPaged(Size, KPH_TAG_CLIENT_INFORMER_STATE);\n}\n\n/**\n * \\brief Initializes a client informer state object.\n *\n * \\param[in] Object The client informer state object to initialize.\n * \\param[in] Parameter The client informer settings.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializeClientInformerState(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_CLIENT_INFORMER_STATE state;\n    PKPH_INFORMER_CLIENT_SETTINGS settings;\n    LARGE_INTEGER timeStamp;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Parameter);\n\n    state = Object;\n    settings = Parameter;\n\n    KeQuerySystemTime(&timeStamp);\n\n    RtlCopyMemory(&state->MessageTimeouts,\n                  &settings->MessageTimeouts,\n                  sizeof(KPH_MESSAGE_TIMEOUTS));\n\n    KphInitializeRateLimit(&settings->AsyncQueuePolicy,\n                           &timeStamp,\n                           &state->AsyncQueueRateLimit);\n\n    for (ULONG i = 0; i < KPH_INFORMER_COUNT; i++)\n    {\n        KphInitializeRateLimit(&settings->InformerPolicy[i],\n                               &timeStamp,\n                               &state->InformerRateLimit[i]);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Frees a client informer state object.\n *\n * \\param[in] Object The client informer state object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpFreeClientInformerState(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphFree(Object, KPH_TAG_CLIENT_INFORMER_STATE);\n}\n\n/**\n * \\brief Initializes the client ring buffer.\n *\n * \\param[in] Client The client to initialize the ring buffer for.\n * \\param[in,out] Connection Pointer to the ring buffer connection context.\n *\n * \\return Successful status or an errant one.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphpCommsInitializeRingBuffer(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_RING_BUFFER_CONNECT Connection\n    )\n{\n    NTSTATUS status;\n    PKPH_RING_BUFFER ring;\n    KPH_RING_BUFFER_CONNECT connection;\n    PKEVENT event;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    ring = NULL;\n    event = NULL;\n\n    __try\n    {\n        CopyFromUser(&connection, Connection, sizeof(KPH_RING_BUFFER_CONNECT));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    if (connection.EventHandle)\n    {\n        status = ObReferenceObjectByHandle(connection.EventHandle,\n                                           EVENT_MODIFY_STATE,\n                                           *ExEventObjectType,\n                                           UserMode,\n                                           &event,\n                                           NULL);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          COMMS,\n                          \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                          status);\n\n            event = NULL;\n            goto Exit;\n        }\n    }\n\n    status = KphCreateRingBuffer(&ring,\n                                 &Connection->Ring,\n                                 connection.Length,\n                                 event,\n                                 UserMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"KphCreateRingBuffer failed: %!STATUS!\",\n                      status);\n\n        ring = NULL;\n        goto Exit;\n    }\n\n    Client->RingBuffer = ring;\n    KphReferenceObject(ring);\n\nExit:\n\n    if (ring)\n    {\n        KphDereferenceObject(ring);\n    }\n\n    if (event)\n    {\n        ObDereferenceObject(event);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Communication port connect notify callback.\n *\n * \\param[in] ClientPort Client port for this client.\n * \\param[in] ServerPortCookie Unused\n * \\param[in] ConnectionContext Context from the connecting client.\n * \\param[in] SizeOfContext Size of the connection context from the client.\n * \\param[out] ConnectionPortCookie Returns the client object on success.\n *\n * \\return Successful status or an errant one.\n */\n_Function_class_(PFLT_CONNECT_NOTIFY)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS FLTAPI KphpCommsConnectNotifyCallback(\n    _In_ PFLT_PORT ClientPort,\n    _In_ PVOID ServerPortCookie,\n    _In_ PVOID ConnectionContext,\n    _In_ ULONG SizeOfContext,\n    _Out_ PVOID* ConnectionPortCookie\n    )\n{\n    NTSTATUS status;\n    PKPH_PROCESS_CONTEXT process;\n    KPH_PROCESS_STATE processState;\n    PKPH_CLIENT client;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(ServerPortCookie);\n\n    *ConnectionPortCookie = NULL;\n\n    process = NULL;\n    client = NULL;\n\n    if (!KphSinglePrivilegeCheck(SeDebugPrivilege, UserMode))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"KphSinglePrivilegeCheck failed %lu\",\n                      HandleToULong(PsGetCurrentProcessId()));\n\n        status = STATUS_PRIVILEGE_NOT_HELD;\n        goto Exit;\n    }\n\n    process = KphGetCurrentProcessContext();\n    if (!process)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Untracked process %lu\",\n                      HandleToULong(PsGetCurrentProcessId()));\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    processState = KphGetProcessState(process);\n    if (!KphTestProcessState(processState, KPH_PROCESS_STATE_LOW))\n    {\n        KphTracePrint(TRACE_LEVEL_CRITICAL,\n                      COMMS,\n                      \"Untrusted client %wZ (%lu) (0x%08x)\",\n                      &process->ImageName,\n                      HandleToULong(process->ProcessId),\n                      processState);\n\n        status = STATUS_ACCESS_DENIED;\n        goto Exit;\n    }\n\n    status = KphCreateObject(KphpClientType,\n                             sizeof(KPH_CLIENT),\n                             &client,\n                             process);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Failed to allocate client object\");\n\n        client = NULL;\n        goto Exit;\n    }\n\n    if (ConnectionContext && (SizeOfContext >= sizeof(PVOID)))\n    {\n        PKPH_RING_BUFFER_CONNECT connection;\n\n        NT_ASSERT(ConnectionContext > MmHighestUserAddress);\n\n        connection = *(PVOID*)ConnectionContext;\n\n        status = KphpCommsInitializeRingBuffer(client, connection);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          COMMS,\n                          \"KphpCommsInitializeRingBuffer failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    client->Port = ClientPort;\n\n    if (!KphpAddConnectedClient(client))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      COMMS,\n                      \"Clients at maximum: %wZ (%lu) (0x%08x)\",\n                      &client->Process->ImageName,\n                      HandleToULong(client->Process->ProcessId),\n                      processState);\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_INFORMATION,\n                  COMMS,\n                  \"Client connected: %wZ (%lu) (0x%08x)\",\n                  &client->Process->ImageName,\n                  HandleToULong(client->Process->ProcessId),\n                  processState);\n\n    *ConnectionPortCookie = client;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (client)\n    {\n        KphDereferenceObject(client);\n    }\n\n    if (process)\n    {\n        KphDereferenceObject(process);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Communication port disconnect notification callback.\n *\n * \\param[in] ConnectionCookie Client object\n */\n_Function_class_(PFLT_DISCONNECT_NOTIFY)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID FLTAPI KphpCommsDisconnectNotifyCallback(\n    _In_ PVOID ConnectionCookie\n    )\n{\n    PKPH_CLIENT client;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(ConnectionCookie);\n\n    client = KphpRemoveConnectedClient(ConnectionCookie);\n    if (client)\n    {\n        KphTracePrint(TRACE_LEVEL_INFORMATION,\n                      COMMS,\n                      \"Client disconnected: %wZ (%lu)\",\n                      &client->Process->ImageName,\n                      HandleToULong(client->Process->ProcessId));\n\n        KphDereferenceObject(client);\n    }\n}\n\n/**\n * \\brief Signals clients when a required state failure occurs on inbound requests.\n *\n * \\param[in] MessageId The message ID that failed.\n * \\param[in] ClientState The client state that was checked.\n * \\param[in] RequiredState The state that was required.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpSendRequiredStateFailure(\n    _In_ KPH_MESSAGE_ID MessageId,\n    _In_ KPH_PROCESS_STATE ClientState,\n    _In_ KPH_PROCESS_STATE RequiredState\n    )\n{\n    PKPH_MESSAGE msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    msg = KphAllocateMessage();\n    if (!msg)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Failed to allocate message\");\n        return;\n    }\n\n    KphMsgInit(msg, KphMsgRequiredStateFailure);\n    msg->Kernel.RequiredStateFailure.ClientId.UniqueProcess = PsGetCurrentProcessId();\n    msg->Kernel.RequiredStateFailure.ClientId.UniqueThread = PsGetCurrentThreadId();\n    msg->Kernel.RequiredStateFailure.MessageId = MessageId;\n    msg->Kernel.RequiredStateFailure.ClientState = ClientState;\n    msg->Kernel.RequiredStateFailure.RequiredState = RequiredState;\n\n    if (KphInformerOpts(NULL).EnableStackTraces)\n    {\n        KphCaptureStackInMessage(msg);\n    }\n\n    KphCommsSendMessageAsync(msg);\n}\n\n/**\n * \\brief Connection port message notification callback.\n *\n * \\param[in] PortCookie Client object\n * \\param[in] InputBuffer Input buffer from client.\n * \\param[in] InputBufferLength Length of the input buffer.\n * \\param[out] OutputBuffer Output buffer from client.\n * \\param[in] OutputBufferLength Length of the output buffer.\n * \\param[out] ReturnOutputBufferLength Receives the number of bytes written.\n *\n * \\return Successful or errant status.\n */\n_Function_class_(PFLT_MESSAGE_NOTIFY)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS FLTAPI KphpCommsMessageNotifyCallback(\n    _In_ PVOID PortCookie,\n    _In_opt_ PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_opt_ PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _Out_ PULONG ReturnOutputBufferLength\n    )\n{\n    NTSTATUS status;\n    PKPH_CLIENT client;\n    PKPH_MESSAGE msg;\n    const KPH_MESSAGE_HANDLER* handler;\n    KPH_PROCESS_STATE processState;\n    KPH_PROCESS_STATE requiredState;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    client = (PKPH_CLIENT)PortCookie;\n\n    msg = NULL;\n\n    if ((PsGetCurrentProcess() != client->Process->EProcess) ||\n        (ExGetPreviousMode() != UserMode))\n    {\n        KphTracePrint(TRACE_LEVEL_CRITICAL,\n                      COMMS,\n                      \"Unexpected caller process!\");\n\n        status = STATUS_ACCESS_DENIED;\n        goto Exit;\n    }\n\n    *ReturnOutputBufferLength = 0;\n\n    if (!InputBuffer ||\n        (InputBufferLength < KPH_MESSAGE_MIN_SIZE) ||\n        (InputBufferLength > sizeof(KPH_MESSAGE)) ||\n        OutputBuffer ||\n        (OutputBufferLength > 0))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Client message input invalid\");\n\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    msg = KphAllocateMessage();\n    if (!msg)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Failed to allocate message\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    __try\n    {\n        CopyFromUser(msg, InputBuffer, KPH_MESSAGE_MIN_SIZE);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    status = KphMsgValidate(msg);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"KphMsgValidate failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (msg->Header.Size > KPH_MESSAGE_MIN_SIZE)\n    {\n        __try\n        {\n            CopyFromUser(msg->_Dyn.Buffer,\n                         Add2Ptr(InputBuffer, KPH_MESSAGE_MIN_SIZE),\n                         (msg->Header.Size - KPH_MESSAGE_MIN_SIZE));\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n    }\n\n    if ((msg->Header.MessageId <= InvalidKphMsg) ||\n        (msg->Header.MessageId >= MaxKphMsgClient) ||\n        ((ULONG)msg->Header.MessageId >= KphCommsMessageHandlerCount))\n    {\n        KphTracePrint(TRACE_LEVEL_WARNING,\n                      COMMS,\n                      \"Client message ID invalid: %lu\",\n                      (ULONG)msg->Header.MessageId);\n\n        status = STATUS_MESSAGE_NOT_FOUND;\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  COMMS,\n                  \"Received input (%lu - %!TIME!) from client: %wZ (%lu)\",\n                  (ULONG)msg->Header.MessageId,\n                  msg->Header.TimeStamp.QuadPart,\n                  &client->Process->ImageName,\n                  HandleToULong(client->Process->ProcessId));\n\n    handler = &KphCommsMessageHandlers[msg->Header.MessageId];\n\n    NT_ASSERT(handler->MessageId == msg->Header.MessageId);\n    NT_ASSERT(handler->Handler);\n    NT_ASSERT(handler->RequiredState);\n\n    processState = KphGetProcessState(client->Process);\n    requiredState = handler->RequiredState(client, msg);\n\n    if (!KphTestProcessState(processState, requiredState))\n    {\n        KphTracePrint(TRACE_LEVEL_CRITICAL,\n                      COMMS,\n                      \"Untrusted client %wZ (%lu) (0x%08x, 0x%08x)\",\n                      &client->Process->ImageName,\n                      HandleToULong(client->Process->ProcessId),\n                      processState,\n                      requiredState);\n\n        KphpSendRequiredStateFailure(handler->MessageId,\n                                     processState,\n                                     requiredState);\n\n        status = STATUS_ACCESS_DENIED;\n        goto Exit;\n    }\n\n    status = handler->Handler(client, msg);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    NT_ASSERT(NT_SUCCESS(KphMsgValidate(msg)));\n\n    //\n    // We use the input buffer as the input and output. This is on purpose\n    // to minimize the allocations and copies we have to do.\n    //\n    if (InputBufferLength < msg->Header.Size)\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n        goto Exit;\n    }\n\n    __try\n    {\n        CopyToUser(InputBuffer, msg, msg->Header.Size);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  COMMS,\n                  \"Sending output (%lu - %!TIME!) to client: %wZ (%lu)\",\n                  (ULONG)msg->Header.MessageId,\n                  msg->Header.TimeStamp.QuadPart,\n                  &client->Process->ImageName,\n                  HandleToULong(client->Process->ProcessId));\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (msg)\n    {\n        KphFreeMessage(msg);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Frees the communication port security descriptor.\n *\n * \\param[in] SecurityDescriptor Security descriptor to free.\n */\n_IRQL_always_function_max_(PASSIVE_LEVEL)\nVOID KphpFreeCommsSecurityDescriptor(\n    _In_freesMem_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    FltFreeSecurityDescriptor(SecurityDescriptor);\n}\n\n/**\n * \\brief Builds the communication port security descriptor.\n *\n * \\param[out] SecurityDescriptor On success set to the security descriptor for\n * the communication port. Null on failure. The caller should free this pointer\n * with KphpFreeCommsSecurityDescriptor.\n *\n * \\return Successful or errant status.\n */\n_IRQL_always_function_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpBuildCommsSecurityDescriptor(\n    _Outptr_allocatesMem_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = FltBuildDefaultSecurityDescriptor(SecurityDescriptor,\n                                               FLT_PORT_ALL_ACCESS);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"FltBuildDefaultSecurityDescriptor failed: %!STATUS!\",\n                      status);\n\n        *SecurityDescriptor = NULL;\n        goto Exit;\n    }\n\nExit:\n\n    return status;\n}\n\n/**\n * \\brief Gets the client informer settings.\n *\n * \\param[in] Client The client to get the settings from.\n * \\param[out] Settings Receives the informer settings.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerClientSettings(\n    _In_ PKPH_CLIENT Client,\n    _Out_ PKPH_INFORMER_CLIENT_SETTINGS Settings\n    )\n{\n    NTSTATUS status;\n    PKPH_CLIENT_INFORMER_STATE state;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    state = NULL;\n\n    __try\n    {\n        ZeroUserMemory(Settings, sizeof(KPH_INFORMER_CLIENT_SETTINGS));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    state = KphAtomicReferenceObject(&Client->InformerState.Atomic);\n    if (!state)\n    {\n        status = STATUS_NOT_FOUND;\n        goto Exit;\n    }\n\n    __try\n    {\n        CopyToUser(&Settings->MessageTimeouts,\n                   &state->MessageTimeouts,\n                   sizeof(KPH_MESSAGE_TIMEOUTS));\n\n        CopyToUser(&Settings->AsyncQueuePolicy,\n                   &state->AsyncQueueRateLimit.Policy,\n                   sizeof(KPH_RATE_LIMIT_POLICY));\n\n        for (ULONG i = 0; i < KPH_INFORMER_COUNT; i++)\n        {\n            CopyToUser(&Settings->InformerPolicy[i],\n                       &state->InformerRateLimit[i].Policy,\n                       sizeof(KPH_RATE_LIMIT_POLICY));\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (state)\n    {\n        KphDereferenceObject(state);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Sets the client informer settings.\n *\n * \\param[in] Client The client to get the settings for.\n * \\param[in] Settings The settings to apply.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformerClientSettings(\n    _In_ PKPH_CLIENT Client,\n    _In_ PKPH_INFORMER_CLIENT_SETTINGS Settings\n    )\n{\n    NTSTATUS status;\n    PKPH_INFORMER_CLIENT_SETTINGS settings;\n    PKPH_CLIENT_INFORMER_STATE state;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    state = NULL;\n\n    settings = KphAllocatePaged(sizeof(KPH_INFORMER_CLIENT_SETTINGS),\n                                KPH_TAG_CLIENT_INFORMER_SETTINGS);\n    if (!settings)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Failed to allocate message settings\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    __try\n    {\n        CopyFromUser(settings, Settings, sizeof(KPH_INFORMER_CLIENT_SETTINGS));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    status = KphCreateObject(KphpClientInformerStateType,\n                             sizeof(KPH_CLIENT_INFORMER_STATE),\n                             &state,\n                             settings);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        state = NULL;\n        goto Exit;\n    }\n\n    KphAtomicAssignObjectReference(&Client->InformerState.Atomic, state);\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (state)\n    {\n        KphDereferenceObject(state);\n    }\n\n    if (settings)\n    {\n        KphFree(settings, KPH_TAG_CLIENT_INFORMER_SETTINGS);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Gets informer statistics for a client.\n *\n * \\param[in] Client The client to get the informer statistics for.\n * \\param[out] Stats Receives the informer statistics.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerClientStats(\n    _In_ PKPH_CLIENT Client,\n    _Out_ PKPH_INFORMER_CLIENT_STATS Stats\n    )\n{\n    NTSTATUS status;\n    PKPH_CLIENT_INFORMER_STATE state;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    state = NULL;\n\n    __try\n    {\n        ZeroUserMemory(Stats, sizeof(KPH_INFORMER_STATS));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    state = KphAtomicReferenceObject(&Client->InformerState.Atomic);\n    if (!state)\n    {\n        status = STATUS_NOT_FOUND;\n        goto Exit;\n    }\n\n    __try\n    {\n        CopyToUser(&Stats->AsyncQueueRateLimit.Policy,\n                   &state->AsyncQueueRateLimit.Policy,\n                   sizeof(KPH_RATE_LIMIT_POLICY));\n        WriteLong64ToUser(&Stats->AsyncQueueRateLimit.Allowed,\n                          ReadNoFence64(&state->AsyncQueueRateLimit.Allowed));\n        WriteLong64ToUser(&Stats->AsyncQueueRateLimit.Dropped,\n                          ReadNoFence64(&state->AsyncQueueRateLimit.Dropped));\n        WriteLong64ToUser(&Stats->AsyncQueueRateLimit.CasMiss,\n                          ReadNoFence64(&state->AsyncQueueRateLimit.CasMiss));\n\n        for (ULONG i = 0; i < KPH_INFORMER_COUNT; i++)\n        {\n            CopyToUser(&Stats->InformerRateLimit[i].Policy,\n                       &state->InformerRateLimit[i].Policy,\n                       sizeof(KPH_RATE_LIMIT_POLICY));\n            WriteLong64ToUser(&Stats->InformerRateLimit[i].Allowed,\n                              ReadNoFence64(&state->InformerRateLimit[i].Allowed));\n            WriteLong64ToUser(&Stats->InformerRateLimit[i].Dropped,\n                              ReadNoFence64(&state->InformerRateLimit[i].Dropped));\n            WriteLong64ToUser(&Stats->InformerRateLimit[i].CasMiss,\n                              ReadNoFence64(&state->InformerRateLimit[i].CasMiss));\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (state)\n    {\n        KphDereferenceObject(state);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Retrieves the timeout for a message.\n *\n * \\param[in] Client The client to get the timeout for.\n * \\param[in] Message The message to retrieve the timeout for.\n * \\param[in] AsyncTimeout If TRUE the asynchronous timeout is returned, else\n * the timeout appropriate for the message is returned.\n * \\param[out] Timeout Receives the timeout for the message.\n *\n * \\return TRUE if a timeout was retrieved, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphpGetTimeoutForMessage(\n    _In_ PKPH_CLIENT Client,\n    _In_ PKPH_MESSAGE Message,\n    _In_ BOOLEAN AsyncTimeout,\n    _Out_ PLARGE_INTEGER Timeout\n    )\n{\n    PKPH_CLIENT_INFORMER_STATE state;\n\n    KPH_PAGED_CODE();\n\n    state = KphAtomicReferenceObject(&Client->InformerState.Atomic);\n    if (!state)\n    {\n        RtlZeroMemory(Timeout, sizeof(LARGE_INTEGER));\n\n        return FALSE;\n    }\n\n    if (AsyncTimeout)\n    {\n        *Timeout = state->MessageTimeouts.AsyncTimeout;\n    }\n    else\n    {\n        switch (Message->Header.MessageId)\n        {\n            case KphMsgProcessCreate:\n            {\n                *Timeout = state->MessageTimeouts.ProcessCreateTimeout;\n                break;\n            }\n            case KphMsgFilePreCreate:\n            {\n                *Timeout = state->MessageTimeouts.FilePreCreateTimeout;\n                break;\n            }\n            case KphMsgFilePostCreate:\n            {\n                *Timeout = state->MessageTimeouts.FilePostCreateTimeout;\n                break;\n            }\n            default:\n            {\n                *Timeout = state->MessageTimeouts.DefaultTimeout;\n                break;\n            }\n        }\n    }\n\n    KphDereferenceObject(state);\n\n    return TRUE;\n}\n\n/**\n * \\brief Wrapper for the communication port message send API.\n *\n * \\param[in] ClientPort Client port to send message to.\n * \\param[in] SendBuffer Buffer to send.\n * \\param[in] SendBufferLength Length of send buffer.\n * \\param[out] ReplyBuffer Reply buffer.\n * \\param[in,out] ReplyBufferLength Length of reply buffer on input, set to\n * number of bytes written to reply buffer on output.\n * \\param[in] Timeout Time allotted for message to be received. If a reply is\n * expected this waits for a reply to be received too. If not provided the\n * call waits indefinitely.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltSendMessage(\n    _In_ PFLT_PORT* ClientPort,\n    _In_reads_bytes_(SendBufferLength) PVOID SendBuffer,\n    _In_ ULONG SendBufferLength,\n    _Out_writes_bytes_opt_(*ReplyBufferLength) PVOID ReplyBuffer,\n    _Inout_opt_ PULONG ReplyBufferLength,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(KphFltFilter);\n\n    status = FltObjectReference(KphFltFilter);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"FltObjectReference failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    status = FltSendMessage(KphFltFilter,\n                            ClientPort,\n                            SendBuffer,\n                            SendBufferLength,\n                            ReplyBuffer,\n                            ReplyBufferLength,\n                            Timeout);\n    if (status == STATUS_TIMEOUT)\n    {\n        //\n        // return an error status instead\n        //\n        status = STATUS_IO_TIMEOUT;\n    }\n\n    FltObjectDereference(KphFltFilter);\n\n    return status;\n}\n\n/**\n * \\brief Sends a message asynchronously to a single target client process.\n *\n * \\param[in] Message The message to send asynchronously. This function assumes\n * ownership over the message. The caller should *not* free the message after\n * it is passed to this function.\n * \\param[in] TargetClient Optional target client to send the message to. If\n * provided the message will only be sent to the target client from the queue\n * processing. Otherwise, the message will be sent to all clients.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpCommsSendMessageAsync(\n    _In_aliasesMem_ PKPH_MESSAGE Message,\n    _In_opt_ PKPH_CLIENT TargetClient\n    )\n{\n    PKPHM_QUEUE_ITEM item;\n    ULONG targetClientCount;\n    PKPH_CLIENT targetClients[KPH_COMMS_MAX_CLIENTS];\n\n    KPH_PAGED_CODE();\n\n    if (!KphAcquireRundown(&KphpCommsRundown))\n    {\n        KphTracePrint(TRACE_LEVEL_WARNING,\n                      COMMS,\n                      \"Failed to acquire rundown, dropping message \"\n                      \"(%lu - %!TIME!)\",\n                      (ULONG)Message->Header.MessageId,\n                      Message->Header.TimeStamp.QuadPart);\n\n        KphFreeMessage(Message);\n        return;\n    }\n\n    if (TargetClient)\n    {\n        targetClientCount = 1;\n        targetClients[0] = TargetClient;\n        KphReferenceObject(TargetClient);\n    }\n    else\n    {\n        targetClientCount = KphpCommsSendMessageToRingBuffers(targetClients,\n                                                              Message);\n        if (!targetClientCount)\n        {\n            goto Exit;\n        }\n    }\n\n    item = KphpAllocateMessageQueueItem();\n    if (!item)\n    {\n        KphTracePrint(TRACE_LEVEL_WARNING,\n                      COMMS,\n                      \"Failed to allocate queue item, dropping message \"\n                      \"(%lu - %!TIME!)\",\n                      (ULONG)Message->Header.MessageId,\n                      Message->Header.TimeStamp.QuadPart);\n\n        goto Exit;\n    }\n\n    item->Message = Message;\n    item->NonPaged = FALSE;\n    Message = NULL;\n\n    item->TargetClientCount = targetClientCount;\n    RtlCopyMemory(item->TargetClients,\n                  targetClients,\n                  sizeof(PKPH_CLIENT) * targetClientCount);\n    targetClientCount = 0;\n\n    KeInsertQueue(&KphpMessageQueue, &item->Entry);\n\nExit:\n\n    for (ULONG i = 0; i < targetClientCount; i++)\n    {\n        KphDereferenceObject(targetClients[i]);\n    }\n\n    if (Message)\n    {\n        KphFreeMessage(Message);\n    }\n\n    KphReleaseRundown(&KphpCommsRundown);\n}\n\n/**\n * \\brief Sends a message to a specific client.\n *\n * \\param[in] Client The client to send the message to.\n * \\param[in] Message The message to send. May contain multiple messages if\n * the send is originating from the asynchronous message queue and the\n * asynchronous message queue has coalesced multiple messages into one.\n * \\param[in] Length The length of the message to send. May constitute multiple\n * messages if the send is originating from the asynchronous message queue and\n * the asynchronous message queue has coalesced multiple messages into one.\n * \\param[out] Reply The reply from last client.\n * \\param[in] FromAsyncQueue If TRUE the message is being sent from the\n * asynchronous message queue, otherwise FALSE.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpCommsSendMessage(\n    _In_ PKPH_CLIENT Client,\n    _In_ PKPH_MESSAGE Message,\n    _In_ ULONG Length,\n    _Inout_opt_ PKPH_MESSAGE Reply,\n    _In_ BOOLEAN FromAsyncQueue\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE reply;\n    ULONG replyLength;\n    KPH_PROCESS_STATE processState;\n    LARGE_INTEGER timeout;\n\n    KPH_PAGED_CODE();\n\n    //\n    // Since we support multiple clients and only one client may be the\n    // authoritative reply. We choose to honor the first client to reply.\n    //\n    if (Reply && (Reply->Header.MessageId == KphMsgUnhandled))\n    {\n        reply = Reply;\n        replyLength = sizeof(KPH_MESSAGE);\n    }\n    else\n    {\n        reply = NULL;\n        replyLength = 0;\n    }\n\n    if (reply && (PsGetCurrentProcess() == Client->Process->EProcess))\n    {\n        PKPH_MESSAGE async;\n\n        NT_ASSERT(!FromAsyncQueue);\n        NT_ASSERT(Message->Header.Size == Length);\n\n        //\n        // This is a precaution to prevent a bottleneck. In this case the kernel\n        // will block for the client to fully reply. If the client generates\n        // more activity that too ends up fully synchronous it could exhaust\n        // the client thread pool. This may introduce a bottleneck into the\n        // system. To avoid this we force this one message to be sent to the\n        // target client asynchronously. The client will not be permitted to\n        // reply but will still have visibility.\n        //\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Bottleneck protection, forcing asynchronous send \"\n                      \"(%lu - %!TIME!) to client: %wZ (%lu)\",\n                      (ULONG)Message->Header.MessageId,\n                      Message->Header.TimeStamp.QuadPart,\n                      &Client->Process->ImageName,\n                      HandleToULong(Client->Process->ProcessId));\n\n        //\n        // We must make a copy of this message to send asynchronously.\n        //\n        async = KphAllocateMessage();\n        if (!async)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          COMMS,\n                          \"Failed to allocate message\");\n\n            return;\n        }\n\n        RtlCopyMemory(async, Message, Message->Header.Size);\n\n        KphpCommsSendMessageAsync(async, Client);\n\n        status = STATUS_POSSIBLE_DEADLOCK;\n        goto Exit;\n    }\n\n    for (ULONG offset = 0; offset < Length; NOTHING)\n    {\n        PKPH_MESSAGE message;\n\n        NT_ASSERT(offset < sizeof(KPH_MESSAGE));\n\n        message = Add2Ptr(Message, offset);\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Sending message (%lu - %!TIME!) to client: %wZ (%lu)\",\n                      (ULONG)message->Header.MessageId,\n                      message->Header.TimeStamp.QuadPart,\n                      &Client->Process->ImageName,\n                      HandleToULong(Client->Process->ProcessId));\n\n        offset += message->Header.Size;\n    }\n\n    if (!KphpGetTimeoutForMessage(Client, Message, FromAsyncQueue, &timeout))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"KphpGetTimeoutForMessage failed\");\n\n        status = STATUS_NOT_FOUND;\n        goto Exit;\n    }\n\n    status = KphpFltSendMessage(&Client->Port,\n                                Message,\n                                Length,\n                                reply,\n                                (reply ? &replyLength : NULL),\n                                &timeout);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"KphpFltSendMessage failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (!reply)\n    {\n        goto Exit;\n    }\n\n    processState = KphGetProcessState(Client->Process);\n    if (!KphTestProcessState(processState, KPH_PROCESS_STATE_MAXIMUM))\n    {\n        KphTracePrint(TRACE_LEVEL_CRITICAL,\n                      COMMS,\n                      \"Untrusted client %wZ (%lu) (0x%08x)\",\n                      &Client->Process->ImageName,\n                      HandleToULong(Client->Process->ProcessId),\n                      processState);\n\n        status = STATUS_REPLY_MESSAGE_MISMATCH;\n        goto Exit;\n    }\n\n    status = KphMsgValidate(reply);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_WARNING,\n                      COMMS,\n                      \"Received invalid reply from client: %wZ (%lu)\",\n                      &Client->Process->ImageName,\n                      HandleToULong(Client->Process->ProcessId));\n\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  COMMS,\n                  \"Received reply (%lu - %!TIME!) from client: %wZ (%lu)\",\n                  (ULONG)reply->Header.MessageId,\n                  reply->Header.TimeStamp.QuadPart,\n                  &Client->Process->ImageName,\n                  HandleToULong(Client->Process->ProcessId));\n\nExit:\n\n    if (!NT_SUCCESS(status) && reply)\n    {\n        KphMsgInit(reply, KphMsgUnhandled);\n    }\n}\n\n/**\n * \\brief Attempts to coalesce consecutive items in a message queue to minimize\n * the number of individual message transactions.\n *\n * \\details This function optimizes message transmission by combining compatible\n * items from the queue into a single message. If coalescing is not possible,\n * it simply returns the next item to be sent as-is.\n *\n * \\param[in] Items The items to process.\n * \\param[in] Count The number of items to process.\n * \\param[in,out] Index The index of the first item to consider for coalescing.\n * Incremented for each coalesced item.\n * \\param[out] Length Receives the length (in bytes) of the message to send,\n * including any coalesced items.\n * \\param[out] Rundown Set to TRUE if rundown is active, FALSE otherwise.\n *\n * \\return The next item to send, NULL otherwise.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nPKPHM_QUEUE_ITEM KphpMessageQueueCoalesceItems(\n    _In_reads_(Count) PLIST_ENTRY* Items,\n    _In_ ULONG Count,\n    _Inout_ PULONG Index,\n    _Out_ PULONG Length,\n    _Out_ PBOOLEAN Rundown\n    )\n{\n    NTSTATUS status;\n    PKPHM_QUEUE_ITEM first;\n    ULONG coalescedCount;\n    ULONG remainingLength;\n    PVOID messagePointer;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(*Index < Count);\n\n    *Rundown = FALSE;\n\n    first = NULL;\n    remainingLength = sizeof(KPH_MESSAGE);\n    coalescedCount = 0;\n\n    status = (NTSTATUS)(LONG_PTR)Items[*Index];\n\n    if ((status == STATUS_TIMEOUT) ||\n        (status == STATUS_USER_APC))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      COMMS,\n                      \"Unexpected queue status: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (status == STATUS_ABANDONED)\n    {\n        //\n        // The rundown logic is responsible for draining/servicing the\n        // remaining queue items.\n        //\n        KphTracePrint(TRACE_LEVEL_INFORMATION,\n                      COMMS,\n                      \"Message queue running down\");\n\n        *Rundown = TRUE;\n        goto Exit;\n    }\n\n    first = CONTAINING_RECORD(Items[*Index], KPHM_QUEUE_ITEM, Entry);\n\n    NT_ASSERT(first);\n\n    messagePointer = Add2Ptr(first->Message, first->Message->Header.Size);\n    remainingLength = (sizeof(KPH_MESSAGE) - first->Message->Header.Size);\n\n    for (ULONG i = (*Index + 1); i < Count; i++)\n    {\n        PKPHM_QUEUE_ITEM item;\n        BOOLEAN clientsMatch;\n\n        status = (NTSTATUS)(LONG_PTR)Items[i];\n\n        if ((status == STATUS_TIMEOUT) ||\n            (status == STATUS_USER_APC))\n        {\n            KphTracePrint(TRACE_LEVEL_ERROR,\n                          COMMS,\n                          \"Unexpected queue status: %!STATUS!\",\n                          status);\n\n            continue;\n        }\n\n        if (status == STATUS_ABANDONED)\n        {\n            //\n            // The rundown logic is responsible for draining/servicing the\n            // remaining queue items.\n            //\n            KphTracePrint(TRACE_LEVEL_INFORMATION,\n                          COMMS,\n                          \"Message queue running down\");\n\n            *Rundown = TRUE;\n            goto Exit;\n        }\n\n        item = CONTAINING_RECORD(Items[i], KPHM_QUEUE_ITEM, Entry);\n\n        NT_ASSERT(item);\n\n        //\n        // Verify that the client list matches and there is sufficient room to\n        // coalesce this message into the first.\n        //\n\n        if (first->TargetClientCount != item->TargetClientCount)\n        {\n            break;\n        }\n\n        clientsMatch = TRUE;\n\n        for (ULONG j = 0; j < first->TargetClientCount; j++)\n        {\n            if (first->TargetClients[j] != item->TargetClients[j])\n            {\n                clientsMatch = FALSE;\n                break;\n            }\n        }\n\n        if (!clientsMatch)\n        {\n            break;\n        }\n\n        if (remainingLength < item->Message->Header.Size)\n        {\n            break;\n        }\n\n        RtlCopyMemory(messagePointer,\n                      item->Message,\n                      item->Message->Header.Size);\n\n        messagePointer = Add2Ptr(messagePointer, item->Message->Header.Size);\n        remainingLength -= item->Message->Header.Size;\n\n        (*Index)++;\n        coalescedCount++;\n\n        KphpFreeMessageQueueItem(item);\n    }\n\nExit:\n\n    *Length = (sizeof(KPH_MESSAGE) - remainingLength);\n\n    if (coalescedCount)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Coalesced %lu messages (%lu bytes)\",\n                      coalescedCount + 1,\n                      *Length);\n    }\n\n    return first;\n}\n\n/**\n * \\brief Processes message queue items.\n *\n * \\param[in] Items The items to process.\n * \\param[in] Count The number of items to process.\n *\n * \\return TRUE if rundown is active, FALSE otherwise.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nBOOLEAN KphpMessageQueueProcessItems(\n    _In_reads_(Count) PLIST_ENTRY* Items,\n    _In_ ULONG Count\n    )\n{\n    BOOLEAN rundown;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    rundown = FALSE;\n\n    for (ULONG i = 0; i < Count; i++)\n    {\n        PKPHM_QUEUE_ITEM item;\n        ULONG length;\n\n        item = KphpMessageQueueCoalesceItems(Items,\n                                             Count,\n                                             &i,\n                                             &length,\n                                             &rundown);\n        if (item)\n        {\n            for (ULONG j = 0; j < item->TargetClientCount; j++)\n            {\n                KphpCommsSendMessage(item->TargetClients[j],\n                                     item->Message,\n                                     length,\n                                     NULL,\n                                     TRUE);\n            }\n\n            KphpFreeMessageQueueItem(item);\n        }\n\n        if (rundown)\n        {\n            break;\n        }\n    }\n\n    return rundown;\n}\n\n/**\n * \\brief Asynchronous message queue thread.\n *\n * \\param[in] Parameter Unused\n */\n_Function_class_(KPH_THREAD_START_ROUTINE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nNTSTATUS KphpMessageQueueThread(\n    _In_opt_ PVOID Parameter\n    )\n{\n    PLIST_ENTRY items[32];\n    ULONG count;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(Parameter);\n\n    count = ARRAYSIZE(items);\n\n    for (;;)\n    {\n        RtlZeroMemory(items, count * sizeof(PLIST_ENTRY));\n\n        count = KeRemoveQueueEx(&KphpMessageQueue,\n                                KernelMode,\n                                FALSE,\n                                NULL,\n                                items,\n                                ARRAYSIZE(items));\n\n        if (KphpMessageQueueProcessItems(items, count))\n        {\n            break;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Starts the communications infrastructure.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCommsStart(\n    VOID\n    )\n{\n    NTSTATUS status;\n    KPH_OBJECT_TYPE_INFO typeInfo;\n    OBJECT_ATTRIBUTES objectAttributes;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    ULONG threadCount;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(KphFltFilter);\n    NT_ASSERT(!KphpFltServerPort);\n    NT_ASSERT(KphPortName);\n\n    securityDescriptor = NULL;\n\n    KphInitializeRundown(&KphpCommsRundown);\n\n    threadCount = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);\n\n    typeInfo.Allocate = KphpAllocateClient;\n    typeInfo.Initialize = KphpInitializeClient;\n    typeInfo.Delete = KphpDeleteClient;\n    typeInfo.Free = KphpFreeClient;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpClientTypeName, &typeInfo, &KphpClientType);\n\n    typeInfo.Allocate = KphpAllocateClientInformerState;\n    typeInfo.Initialize = KphpInitializeClientInformerState;\n    typeInfo.Delete = NULL;\n    typeInfo.Free = KphpFreeClientInformerState;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpClientInformerStateTypeName,\n                        &typeInfo,\n                        &KphpClientInformerStateType);\n\n    KphInitializePagedLookaside(&KphpMessageLookaside,\n                                sizeof(KPH_MESSAGE),\n                                KPH_TAG_MESSAGE);\n\n    KphInitializeNPagedLookaside(&KphpNPagedMessageLookaside,\n                                 sizeof(KPH_MESSAGE),\n                                 KPH_TAG_NPAGED_MESSAGE);\n\n    KphInitializeNPagedLookaside(&KphpMessageQueueItemLookaside,\n                                 sizeof(KPHM_QUEUE_ITEM),\n                                 KPH_TAG_QUEUE_ITEM);\n\n    if (threadCount < KPH_COMMS_MIN_QUEUE_THREADS)\n    {\n        threadCount = KPH_COMMS_MIN_QUEUE_THREADS;\n    }\n    else if (threadCount > KPH_COMMS_MAX_QUEUE_THREADS)\n    {\n        threadCount = KPH_COMMS_MAX_QUEUE_THREADS;\n    }\n\n    KeInitializeQueue(&KphpMessageQueue, threadCount);\n\n    KphpMessageQueueThreads = KphAllocatePaged((sizeof(PKTHREAD) * threadCount),\n                                               KPH_TAG_THREAD_POOL);\n    if (!KphpMessageQueueThreads)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"Failed to allocate queue threads array\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    NT_ASSERT(KphpMessageQueueThreadsCount == 0);\n    for (ULONG i = 0; i < threadCount; i++)\n    {\n        status = KphCreateSystemThread(NULL,\n                                       &KphpMessageQueueThreads[i],\n                                       KphpMessageQueueThread,\n                                       NULL,\n                                       &KphpMessageQueueThreadName,\n                                       KPH_CREATE_SYSTEM_THREAD_IN_KSI_PROCESS);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          COMMS,\n                          \"KphCreateSystemThread failed: %!STATUS!\",\n                          status);\n\n            KphpMessageQueueThreads[i] = NULL;\n            goto Exit;\n        }\n\n        ++KphpMessageQueueThreadsCount;\n    }\n\n    status = KphpBuildCommsSecurityDescriptor(&securityDescriptor);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"KphpBuildCommsSecurityDescriptor failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    InitializeObjectAttributes(&objectAttributes,\n                               KphPortName,\n                               OBJ_KERNEL_HANDLE,\n                               NULL,\n                               securityDescriptor);\n\n    status = FltCreateCommunicationPort(KphFltFilter,\n                                        &KphpFltServerPort,\n                                        &objectAttributes,\n                                        NULL,\n                                        KphpCommsConnectNotifyCallback,\n                                        KphpCommsDisconnectNotifyCallback,\n                                        KphpCommsMessageNotifyCallback,\n                                        KPH_COMMS_MAX_CLIENTS);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      COMMS,\n                      \"FltCreateCommunicationPort failed: %!STATUS!\",\n                      status);\n\n        KphpFltServerPort = NULL;\n        goto Exit;\n    }\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (!NT_SUCCESS(status))\n    {\n        NT_ASSERT(!KphpFltServerPort);\n\n        KphDeleteNPagedLookaside(&KphpMessageQueueItemLookaside);\n        KphDeleteNPagedLookaside(&KphpNPagedMessageLookaside);\n        KphDeletePagedLookaside(&KphpMessageLookaside);\n\n        NT_VERIFY(KeRundownQueue(&KphpMessageQueue) == NULL);\n\n        if (KphpMessageQueueThreads)\n        {\n            for (ULONG i = 0; i < KphpMessageQueueThreadsCount; i++)\n            {\n                KeWaitForSingleObject(KphpMessageQueueThreads[i],\n                                      Executive,\n                                      KernelMode,\n                                      FALSE,\n                                      NULL);\n                ObDereferenceObject(KphpMessageQueueThreads[i]);\n            }\n            KphFree(KphpMessageQueueThreads, KPH_TAG_THREAD_POOL);\n            KphpMessageQueueThreads = NULL;\n            KphpMessageQueueThreadsCount = 0;\n        }\n    }\n\n    if (securityDescriptor)\n    {\n        KphpFreeCommsSecurityDescriptor(securityDescriptor);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Stops the communications infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCommsStop(\n    VOID\n    )\n{\n    PLIST_ENTRY entry;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!KphpFltServerPort)\n    {\n        return;\n    }\n\n    KphWaitForRundown(&KphpCommsRundown);\n\n    entry = KeRundownQueue(&KphpMessageQueue);\n\n    for (ULONG i = 0; i < KphpMessageQueueThreadsCount; i++)\n    {\n        KeWaitForSingleObject(KphpMessageQueueThreads[i],\n                              Executive,\n                              KernelMode,\n                              FALSE,\n                              NULL);\n        ObDereferenceObject(KphpMessageQueueThreads[i]);\n    }\n\n    KphFree(KphpMessageQueueThreads, KPH_TAG_THREAD_POOL);\n    KphpMessageQueueThreads = NULL;\n    KphpMessageQueueThreadsCount = 0;\n\n    //\n    // Rundown any remaining items in the queue, if there are any.\n    //\n    if (entry != NULL)\n    {\n        PLIST_ENTRY first;\n\n        first = entry;\n\n        do\n        {\n            PLIST_ENTRY item;\n\n            item = entry;\n\n            entry = entry->Flink;\n\n            KphpMessageQueueProcessItems(&item, 1);\n\n        } while (entry != first);\n    }\n\n    FltCloseCommunicationPort(KphpFltServerPort);\n\n    KphDeleteNPagedLookaside(&KphpMessageQueueItemLookaside);\n    KphDeleteNPagedLookaside(&KphpNPagedMessageLookaside);\n    KphDeletePagedLookaside(&KphpMessageLookaside);\n}\n\n/**\n * \\brief Allocates a message.\n *\n * \\return Allocated message, null on allocation failure.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_\nPKPH_MESSAGE KphAllocateMessage(\n    VOID\n    )\n{\n    KPH_PAGED_CODE();\n\n    return KphAllocateFromPagedLookaside(&KphpMessageLookaside);\n}\n\n/**\n * \\brief Frees a message.\n *\n * \\param[in] Message The message to free.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID\nKphFreeMessage(\n    _In_freesMem_ PKPH_MESSAGE Message\n    )\n{\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Message);\n\n    KphFreeToPagedLookaside(&KphpMessageLookaside, Message);\n}\n\n/**\n * \\brief Sends a message asynchronously.\n *\n * \\param[in] Message The message to send asynchronously. This function assumes\n * ownership over the message. The caller should *not* free the message after\n * it is passed to this function.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphCommsSendMessageAsync(\n    _In_aliasesMem_ PKPH_MESSAGE Message\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphpCommsSendMessageAsync(Message, NULL);\n}\n\n/**\n * \\brief Sends a message to all connected clients. The first client to respond\n * is given authority for any reply.\n *\n * \\details Callers expecting a specific reply should check for the reply\n * message identifier even on success. This function will return success with\n * KphMsgUnhandled when no client handles the message.\n *\n * \\param[in] Message The message to send.\n * \\param[out] Reply Optional reply from last client.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCommsSendMessage(\n    _In_ PKPH_MESSAGE Message,\n    _Out_opt_ PKPH_MESSAGE Reply\n    )\n{\n    NTSTATUS status;\n    ULONG clientCount;\n    PKPH_CLIENT clients[KPH_COMMS_MAX_CLIENTS];\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(NT_SUCCESS(KphMsgValidate(Message)));\n\n    if (!KphAcquireRundown(&KphpCommsRundown))\n    {\n        return STATUS_TOO_LATE;\n    }\n\n    if (Reply)\n    {\n        KphMsgInit(Reply, KphMsgUnhandled);\n    }\n\n    status = STATUS_PORT_DISCONNECTED;\n\n    clientCount = KphpGetNonRateLimitedClients(clients, Message);\n\n    for (ULONG i = 0; i < clientCount; i++)\n    {\n        KphpCommsSendMessage(clients[i],\n                             Message,\n                             Message->Header.Size,\n                             Reply,\n                             FALSE);\n\n        KphDereferenceObject(clients[i]);\n\n        status = STATUS_SUCCESS;\n    }\n\n    KphReleaseRundown(&KphpCommsRundown);\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/comms_handlers.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <comms.h>\n#include <informer.h>\n\n#include <trace.h>\n\nKPHM_DEFINE_HANDLER(KphpCommsGetInformerSettings);\nKPHM_DEFINE_HANDLER(KphpCommsSetInformerSettings);\nKPHM_DEFINE_HANDLER(KphpCommsOpenProcess);\nKPHM_DEFINE_HANDLER(KphpCommsOpenProcessToken);\nKPHM_DEFINE_HANDLER(KphpCommsOpenProcessJob);\nKPHM_DEFINE_HANDLER(KphpCommsTerminateProcess);\nKPHM_DEFINE_HANDLER(KphpCommsReadVirtualMemory);\nKPHM_DEFINE_HANDLER(KphpCommsOpenThread);\nKPHM_DEFINE_HANDLER(KphpCommsOpenThreadProcess);\nKPHM_DEFINE_HANDLER(KphpCommsCaptureStackBackTraceThread);\nKPHM_DEFINE_HANDLER(KphpCommsEnumerateProcessHandles);\nKPHM_DEFINE_HANDLER(KphpCommsQueryInformationObject);\nKPHM_DEFINE_HANDLER(KphpCommsSetInformationObject);\nKPHM_DEFINE_HANDLER(KphpCommsOpenDriver);\nKPHM_DEFINE_HANDLER(KphpCommsQueryInformationDriver);\nKPHM_DEFINE_HANDLER(KphpCommsQueryInformationProcess);\nKPHM_DEFINE_HANDLER(KphpCommsSetInformationProcess);\nKPHM_DEFINE_HANDLER(KphpCommsSetInformationThread);\nKPHM_DEFINE_HANDLER(KphpCommsSystemControl);\nKPHM_DEFINE_HANDLER(KphpCommsAlpcQueryInformation);\nKPHM_DEFINE_HANDLER(KphpCommsQueryInformationFile);\nKPHM_DEFINE_HANDLER(KphpCommsQueryVolumeInformationFile);\nKPHM_DEFINE_HANDLER(KphpCommsDuplicateObject);\nKPHM_DEFINE_HANDLER(KphpCommsQueryPerformanceCounter);\nKPHM_DEFINE_HANDLER(KphpCommsCreateFile);\nKPHM_DEFINE_HANDLER(KphpCommsQueryInformationThread);\nKPHM_DEFINE_HANDLER(KphpCommsQuerySection);\nKPHM_DEFINE_HANDLER(KphpCommsCompareObjects);\nKPHM_DEFINE_HANDLER(KphpCommsGetInformerClientSettings);\nKPHM_DEFINE_HANDLER(KphpCommsSetInformerClientSettings);\nKPHM_DEFINE_HANDLER(KphpCommsAcquireDriverUnloadProtection);\nKPHM_DEFINE_HANDLER(KphpCommsReleaseDriverUnloadProtection);\nKPHM_DEFINE_HANDLER(KphpCommsGetConnectedClientCount);\nKPHM_DEFINE_HANDLER(KphpCommsActivateDynData);\nKPHM_DEFINE_HANDLER(KphpCommsIsDynDataActive);\nKPHM_DEFINE_HANDLER(KphpCommsRequestSessionAccessToken);\nKPHM_DEFINE_HANDLER(KphpCommsAssignProcessSessionToken);\nKPHM_DEFINE_HANDLER(KphpCommsAssignThreadSessionToken);\nKPHM_DEFINE_HANDLER(KphpCommsGetInformerProcessSettings);\nKPHM_DEFINE_HANDLER(KphpCommsSetInformerProcessSettings);\nKPHM_DEFINE_HANDLER(KphpCommsStripProtectedProcessMasks);\nKPHM_DEFINE_HANDLER(KphpCommsQueryVirtualMemory);\nKPHM_DEFINE_HANDLER(KphpCommsQueryHashInformationFile);\nKPHM_DEFINE_HANDLER(KphpCommsOpenDevice);\nKPHM_DEFINE_HANDLER(KphpCommsOpenDeviceDriver);\nKPHM_DEFINE_HANDLER(KphpCommsOpenDeviceBaseDevice);\nKPHM_DEFINE_HANDLER(KphpCommsGetInformerStats);\nKPHM_DEFINE_HANDLER(KphpCommsGetInformerClientStats);\n\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsRequireMaximum);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsRequireMedium);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsRequireLow);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsOpenProcessRequires);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsOpenProcessTokenRequires);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsOpenProcessJobRequires);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsOpenThreadRequires);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsOpenThreadProcessRequires);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsQueryInformationProcessRequires);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsCreateFileRequires);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsQueryInformationThreadRequires);\nKPHM_DEFINE_REQUIRED_STATE(KphpCommsQueryVirtualMemoryRequires);\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nconst KPH_MESSAGE_HANDLER KphCommsMessageHandlers[] =\n{\n{ InvalidKphMsg,                       NULL,                                   NULL },\n{ KphMsgGetInformerSettings,           KphpCommsGetInformerSettings,           KphpCommsRequireLow },\n{ KphMsgSetInformerSettings,           KphpCommsSetInformerSettings,           KphpCommsRequireLow },\n{ KphMsgOpenProcess,                   KphpCommsOpenProcess,                   KphpCommsOpenProcessRequires },\n{ KphMsgOpenProcessToken,              KphpCommsOpenProcessToken,              KphpCommsOpenProcessTokenRequires },\n{ KphMsgOpenProcessJob,                KphpCommsOpenProcessJob,                KphpCommsOpenProcessJobRequires },\n{ KphMsgTerminateProcess,              KphpCommsTerminateProcess,              KphpCommsRequireMaximum },\n{ KphMsgReadVirtualMemory,             KphpCommsReadVirtualMemory,             KphpCommsRequireMaximum },\n{ KphMsgOpenThread,                    KphpCommsOpenThread,                    KphpCommsOpenThreadRequires },\n{ KphMsgOpenThreadProcess,             KphpCommsOpenThreadProcess,             KphpCommsOpenThreadProcessRequires },\n{ KphMsgCaptureStackBackTraceThread,   KphpCommsCaptureStackBackTraceThread,   KphpCommsRequireMedium },\n{ KphMsgEnumerateProcessHandles,       KphpCommsEnumerateProcessHandles,       KphpCommsRequireMedium },\n{ KphMsgQueryInformationObject,        KphpCommsQueryInformationObject,        KphpCommsRequireMedium },\n{ KphMsgSetInformationObject,          KphpCommsSetInformationObject,          KphpCommsRequireMaximum },\n{ KphMsgOpenDriver,                    KphpCommsOpenDriver,                    KphpCommsRequireMaximum },\n{ KphMsgQueryInformationDriver,        KphpCommsQueryInformationDriver,        KphpCommsRequireMaximum },\n{ KphMsgQueryInformationProcess,       KphpCommsQueryInformationProcess,       KphpCommsQueryInformationProcessRequires },\n{ KphMsgSetInformationProcess,         KphpCommsSetInformationProcess,         KphpCommsRequireMaximum },\n{ KphMsgSetInformationThread,          KphpCommsSetInformationThread,          KphpCommsRequireMaximum },\n{ KphMsgSystemControl,                 KphpCommsSystemControl,                 KphpCommsRequireMaximum },\n{ KphMsgAlpcQueryInformation,          KphpCommsAlpcQueryInformation,          KphpCommsRequireMedium },\n{ KphMsgQueryInformationFile,          KphpCommsQueryInformationFile,          KphpCommsRequireMedium },\n{ KphMsgQueryVolumeInformationFile,    KphpCommsQueryVolumeInformationFile,    KphpCommsRequireMedium },\n{ KphMsgDuplicateObject,               KphpCommsDuplicateObject,               KphpCommsRequireMaximum },\n{ KphMsgQueryPerformanceCounter,       KphpCommsQueryPerformanceCounter,       KphpCommsRequireLow },\n{ KphMsgCreateFile,                    KphpCommsCreateFile,                    KphpCommsCreateFileRequires },\n{ KphMsgQueryInformationThread,        KphpCommsQueryInformationThread,        KphpCommsQueryInformationThreadRequires },\n{ KphMsgQuerySection,                  KphpCommsQuerySection,                  KphpCommsRequireMedium },\n{ KphMsgCompareObjects,                KphpCommsCompareObjects,                KphpCommsRequireMedium },\n{ KphMsgGetInformerClientSettings,     KphpCommsGetInformerClientSettings,     KphpCommsRequireLow },\n{ KphMsgSetInformerClientSettings,     KphpCommsSetInformerClientSettings,     KphpCommsRequireLow },\n{ KphMsgAcquireDriverUnloadProtection, KphpCommsAcquireDriverUnloadProtection, KphpCommsRequireMaximum },\n{ KphMsgReleaseDriverUnloadProtection, KphpCommsReleaseDriverUnloadProtection, KphpCommsRequireMaximum },\n{ KphMsgGetConnectedClientCount,       KphpCommsGetConnectedClientCount,       KphpCommsRequireLow },\n{ KphMsgActivateDynData,               KphpCommsActivateDynData,               KphpCommsRequireLow },\n{ KphMsgIsDynDataActive,               KphpCommsIsDynDataActive,               KphpCommsRequireLow },\n{ KphMsgRequestSessionAccessToken,     KphpCommsRequestSessionAccessToken,     KphpCommsRequireMaximum },\n{ KphMsgAssignProcessSessionToken,     KphpCommsAssignProcessSessionToken,     KphpCommsRequireMaximum },\n{ KphMsgAssignThreadSessionToken,      KphpCommsAssignThreadSessionToken,      KphpCommsRequireMaximum },\n{ KphMsgGetInformerProcessSettings,    KphpCommsGetInformerProcessSettings,    KphpCommsRequireLow },\n{ KphMsgSetInformerProcessSettings,    KphpCommsSetInformerProcessSettings,    KphpCommsRequireLow },\n{ KphMsgStripProtectedProcessMasks,    KphpCommsStripProtectedProcessMasks,    KphpCommsRequireMaximum },\n{ KphMsgQueryVirtualMemory,            KphpCommsQueryVirtualMemory,            KphpCommsQueryVirtualMemoryRequires },\n{ KphMsgQueryHashInformationFile,      KphpCommsQueryHashInformationFile,      KphpCommsRequireMaximum },\n{ KphMsgOpenDevice,                    KphpCommsOpenDevice,                    KphpCommsRequireMaximum },\n{ KphMsgOpenDeviceDriver,              KphpCommsOpenDeviceDriver,              KphpCommsRequireMaximum },\n{ KphMsgOpenDeviceBaseDevice,          KphpCommsOpenDeviceBaseDevice,          KphpCommsRequireMaximum },\n{ KphMsgGetInformerStats,              KphpCommsGetInformerStats,              KphpCommsRequireLow },\n{ KphMsgGetInformerClientStats,        KphpCommsGetInformerClientStats,        KphpCommsRequireLow },\n};\nconst ULONG KphCommsMessageHandlerCount = ARRAYSIZE(KphCommsMessageHandlers);\nC_ASSERT(ARRAYSIZE(KphCommsMessageHandlers) == MaxKphMsgClient);\nKPH_PROTECTED_DATA_SECTION_RO_POP();\n\nKPH_PAGED_FILE();\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsRequireMaximum(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n\n    UNREFERENCED_PARAMETER(Client);\n    UNREFERENCED_PARAMETER(Message);\n\n    return KPH_PROCESS_STATE_MAXIMUM;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsRequireMedium(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n\n    UNREFERENCED_PARAMETER(Client);\n    UNREFERENCED_PARAMETER(Message);\n\n    return KPH_PROCESS_STATE_MEDIUM;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsRequireLow(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n\n    UNREFERENCED_PARAMETER(Client);\n    UNREFERENCED_PARAMETER(Message);\n\n    return KPH_PROCESS_STATE_LOW;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsGetInformerSettings(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_GET_INFORMER_SETTINGS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgGetInformerSettings);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.GetInformerSettings;\n\n    msg->Status = KphGetInformerSettings(msg->Settings, UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsSetInformerSettings(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_SET_INFORMER_SETTINGS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgSetInformerSettings);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.SetInformerSettings;\n\n    msg->Status = KphSetInformerSettings(msg->Settings, UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsOpenProcessRequires(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    ACCESS_MASK desiredAccess;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenProcess);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    desiredAccess = Message->User.OpenProcess.DesiredAccess;\n\n    if ((desiredAccess & KPH_PROCESS_READ_ACCESS) != desiredAccess)\n    {\n        return KPH_PROCESS_STATE_MAXIMUM;\n    }\n\n    return KPH_PROCESS_STATE_MEDIUM;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsOpenProcess(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_OPEN_PROCESS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenProcess);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.OpenProcess;\n\n    msg->Status = KphOpenProcess(msg->ProcessHandle,\n                                 msg->DesiredAccess,\n                                 msg->ClientId,\n                                 UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsOpenProcessTokenRequires(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    ACCESS_MASK desiredAccess;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenProcessToken);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    desiredAccess = Message->User.OpenProcessToken.DesiredAccess;\n\n    if ((desiredAccess & KPH_TOKEN_READ_ACCESS) != desiredAccess)\n    {\n        return KPH_PROCESS_STATE_MAXIMUM;\n    }\n\n    return KPH_PROCESS_STATE_MEDIUM;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsOpenProcessToken(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_OPEN_PROCESS_TOKEN msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenProcessToken);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.OpenProcessToken;\n\n    msg->Status = KphOpenProcessToken(msg->ProcessHandle,\n                                      msg->DesiredAccess,\n                                      msg->TokenHandle,\n                                      UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsOpenProcessJobRequires(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    ACCESS_MASK desiredAccess;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenProcessJob);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    desiredAccess = Message->User.OpenProcessJob.DesiredAccess;\n\n    if ((desiredAccess & KPH_JOB_READ_ACCESS) != desiredAccess)\n    {\n        return KPH_PROCESS_STATE_MAXIMUM;\n    }\n\n    return KPH_PROCESS_STATE_MEDIUM;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsOpenProcessJob(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_OPEN_PROCESS_JOB msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenProcessJob);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.OpenProcessJob;\n\n    msg->Status = KphOpenProcessJob(msg->ProcessHandle,\n                                    msg->DesiredAccess,\n                                    msg->JobHandle,\n                                    UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsTerminateProcess(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_TERMINATE_PROCESS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgTerminateProcess);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.TerminateProcess;\n\n    msg->Status = KphTerminateProcess(msg->ProcessHandle,\n                                      msg->ExitStatus,\n                                      UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsReadVirtualMemory(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_READ_VIRTUAL_MEMORY msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgReadVirtualMemory);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.ReadVirtualMemory;\n\n    msg->Status = KphReadVirtualMemory(msg->ProcessHandle,\n                                       msg->BaseAddress,\n                                       msg->Buffer,\n                                       msg->BufferSize,\n                                       msg->NumberOfBytesRead,\n                                       UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsOpenThreadRequires(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    ACCESS_MASK desiredAccess;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenThread);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    desiredAccess = Message->User.OpenThread.DesiredAccess;\n\n    if ((desiredAccess & KPH_THREAD_READ_ACCESS) != desiredAccess)\n    {\n        return KPH_PROCESS_STATE_MAXIMUM;\n    }\n\n    return KPH_PROCESS_STATE_MEDIUM;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsOpenThread(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_OPEN_THREAD msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenThread);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.OpenThread;\n\n    msg->Status = KphOpenThread(msg->ThreadHandle,\n                                msg->DesiredAccess,\n                                msg->ClientId,\n                                UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsOpenThreadProcessRequires(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    ACCESS_MASK desiredAccess;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenThreadProcess);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    desiredAccess = Message->User.OpenThreadProcess.DesiredAccess;\n\n    if ((desiredAccess & KPH_PROCESS_READ_ACCESS) != desiredAccess)\n    {\n        return KPH_PROCESS_STATE_MAXIMUM;\n    }\n\n    return KPH_PROCESS_STATE_MEDIUM;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsOpenThreadProcess(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_OPEN_THREAD_PROCESS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenThreadProcess);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.OpenThreadProcess;\n\n    msg->Status = KphOpenThreadProcess(msg->ThreadHandle,\n                                       msg->DesiredAccess,\n                                       msg->ProcessHandle,\n                                       UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsCaptureStackBackTraceThread(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_CAPTURE_STACK_BACKTRACE_THREAD msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgCaptureStackBackTraceThread);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.CaptureStackBackTraceThread;\n\n    msg->Status = KphCaptureStackBackTraceThreadByHandle(msg->ThreadHandle,\n                                                         msg->FramesToSkip,\n                                                         msg->FramesToCapture,\n                                                         msg->BackTrace,\n                                                         msg->CapturedFrames,\n                                                         msg->BackTraceHash,\n                                                         msg->Flags,\n                                                         msg->Timeout,\n                                                         UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsEnumerateProcessHandles(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_ENUMERATE_PROCESS_HANDLES msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgEnumerateProcessHandles);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.EnumerateProcessHandles;\n\n    msg->Status = KphEnumerateProcessHandles(msg->ProcessHandle,\n                                             msg->Buffer,\n                                             msg->BufferLength,\n                                             msg->ReturnLength,\n                                             UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQueryInformationObject(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_INFORMATION_OBJECT msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryInformationObject);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QueryInformationObject;\n\n    msg->Status = KphQueryInformationObject(msg->ProcessHandle,\n                                            msg->Handle,\n                                            msg->ObjectInformationClass,\n                                            msg->ObjectInformation,\n                                            msg->ObjectInformationLength,\n                                            msg->ReturnLength,\n                                            UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsSetInformationObject(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_SET_INFORMATION_OBJECT msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgSetInformationObject);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.SetInformationObject;\n\n    msg->Status = KphSetInformationObject(msg->ProcessHandle,\n                                          msg->Handle,\n                                          msg->ObjectInformationClass,\n                                          msg->ObjectInformation,\n                                          msg->ObjectInformationLength,\n                                          UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsOpenDriver(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_OPEN_DRIVER msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenDriver);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.OpenDriver;\n\n    msg->Status = KphOpenDriver(msg->DriverHandle,\n                                msg->DesiredAccess,\n                                msg->ObjectAttributes,\n                                UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQueryInformationDriver(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_INFORMATION_DRIVER msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryInformationDriver);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QueryInformationDriver;\n\n    msg->Status = KphQueryInformationDriver(msg->DriverHandle,\n                                            msg->DriverInformationClass,\n                                            msg->DriverInformation,\n                                            msg->DriverInformationLength,\n                                            msg->ReturnLength,\n                                            UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsQueryInformationProcessRequires(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryInformationProcess);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    switch (Message->User.QueryInformationProcess.ProcessInformationClass)\n    {\n        case KphProcessWSLProcessId:\n        case KphProcessStateInformation:\n        case KphProcessSequenceNumber:\n        case KphProcessStartKey:\n        {\n            return KPH_PROCESS_STATE_LOW;\n        }\n        case KphProcessBasicInformation:\n        case KphProcessImageSection:\n        {\n            return KPH_PROCESS_STATE_MEDIUM;\n        }\n        default:\n        {\n            return KPH_PROCESS_STATE_MAXIMUM;\n        }\n    }\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQueryInformationProcess(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_INFORMATION_PROCESS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryInformationProcess);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QueryInformationProcess;\n\n    msg->Status = KphQueryInformationProcess(msg->ProcessHandle,\n                                             msg->ProcessInformationClass,\n                                             msg->ProcessInformation,\n                                             msg->ProcessInformationLength,\n                                             msg->ReturnLength,\n                                             UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsSetInformationProcess(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_SET_INFORMATION_PROCESS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgSetInformationProcess);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.SetInformationProcess;\n\n    msg->Status = KphSetInformationProcess(msg->ProcessHandle,\n                                           msg->ProcessInformationClass,\n                                           msg->ProcessInformation,\n                                           msg->ProcessInformationLength,\n                                           UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsSetInformationThread(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_SET_INFORMATION_THREAD msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgSetInformationThread);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.SetInformationThread;\n\n    msg->Status = KphSetInformationThread(msg->ThreadHandle,\n                                          msg->ThreadInformationClass,\n                                          msg->ThreadInformation,\n                                          msg->ThreadInformationLength,\n                                          UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsSystemControl(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_SYSTEM_CONTROL msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgSystemControl);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.SystemControl;\n\n    msg->Status = KphSystemControl(msg->SystemControlClass,\n                                   msg->SystemControlInfo,\n                                   msg->SystemControlInfoLength,\n                                   UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsAlpcQueryInformation(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_ALPC_QUERY_INFORMATION msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgAlpcQueryInformation);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.AlpcQueryInformation;\n\n    msg->Status = KphAlpcQueryInformation(msg->ProcessHandle,\n                                          msg->PortHandle,\n                                          msg->AlpcInformationClass,\n                                          msg->AlpcInformation,\n                                          msg->AlpcInformationLength,\n                                          msg->ReturnLength,\n                                          UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQueryInformationFile(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_INFORMATION_FILE msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryInformationFile);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QueryInformationFile;\n\n    msg->Status = KphQueryInformationFile(msg->ProcessHandle,\n                                          msg->FileHandle,\n                                          msg->FileInformationClass,\n                                          msg->FileInformation,\n                                          msg->FileInformationLength,\n                                          msg->IoStatusBlock,\n                                          UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQueryVolumeInformationFile(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_VOLUME_INFORMATION_FILE msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryVolumeInformationFile);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QueryVolumeInformationFile;\n\n    msg->Status = KphQueryVolumeInformationFile(msg->ProcessHandle,\n                                                msg->FileHandle,\n                                                msg->FsInformationClass,\n                                                msg->FsInformation,\n                                                msg->FsInformationLength,\n                                                msg->IoStatusBlock,\n                                                UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsDuplicateObject(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_DUPLICATE_OBJECT msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgDuplicateObject);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.DuplicateObject;\n\n    msg->Status = KphDuplicateObject(msg->ProcessHandle,\n                                     msg->SourceHandle,\n                                     msg->DesiredAccess,\n                                     msg->TargetHandle,\n                                     UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQueryPerformanceCounter(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_PERFORMANCE_COUNTER msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryPerformanceCounter);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QueryPerformanceCounter;\n\n    msg->PerformanceCounter = KeQueryPerformanceCounter(&msg->PerformanceFrequency);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsCreateFileRequires(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    ACCESS_MASK desiredAccess;\n    ULONG createDisposition;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgCreateFile);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    desiredAccess = Message->User.CreateFile.DesiredAccess;\n\n    if ((desiredAccess & KPH_FILE_READ_ACCESS) != desiredAccess)\n    {\n        return KPH_PROCESS_STATE_MAXIMUM;\n    }\n\n    createDisposition = Message->User.CreateFile.CreateDisposition;\n\n    if (createDisposition != KPH_FILE_READ_DISPOSITION)\n    {\n        return KPH_PROCESS_STATE_MAXIMUM;\n    }\n\n    return KPH_PROCESS_STATE_MEDIUM;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsCreateFile(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_CREATE_FILE msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgCreateFile);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.CreateFile;\n\n    msg->Status = KphCreateFile(msg->FileHandle,\n                                msg->DesiredAccess,\n                                msg->ObjectAttributes,\n                                msg->IoStatusBlock,\n                                msg->AllocationSize,\n                                msg->FileAttributes,\n                                msg->ShareAccess,\n                                msg->CreateDisposition,\n                                msg->CreateOptions,\n                                msg->EaBuffer,\n                                msg->EaLength,\n                                msg->Options,\n                                UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsQueryInformationThreadRequires(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryInformationThread);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    switch (Message->User.QueryInformationThread.ThreadInformationClass)\n    {\n        case KphThreadIoCounters:\n        case KphThreadWSLThreadId:\n        {\n            return KPH_PROCESS_STATE_LOW;\n        }\n        case KphThreadKernelStackInformation:\n        {\n            return KPH_PROCESS_STATE_MAXIMUM;\n        }\n        default:\n        {\n            return KPH_PROCESS_STATE_MAXIMUM;\n        }\n    }\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQueryInformationThread(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_INFORMATION_THREAD msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryInformationThread);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QueryInformationThread;\n\n    msg->Status = KphQueryInformationThread(msg->ThreadHandle,\n                                            msg->ThreadInformationClass,\n                                            msg->ThreadInformation,\n                                            msg->ThreadInformationLength,\n                                            msg->ReturnLength,\n                                            UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQuerySection(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_SECTION msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQuerySection);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QuerySection;\n\n    msg->Status = KphQuerySection(msg->SectionHandle,\n                                  msg->SectionInformationClass,\n                                  msg->SectionInformation,\n                                  msg->SectionInformationLength,\n                                  msg->ReturnLength,\n                                  UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsCompareObjects(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_COMPARE_OBJECTS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgCompareObjects);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.CompareObjects;\n\n    msg->Status = KphCompareObjects(msg->ProcessHandle,\n                                    msg->FirstObjectHandle,\n                                    msg->SecondObjectHandle,\n                                    UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsGetInformerClientSettings(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_GET_INFORMER_CLIENT_SETTINGS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgGetInformerClientSettings);\n\n    msg = &Message->User.GetInformerClientSettings;\n\n    msg->Status = KphGetInformerClientSettings(Client, msg->Settings);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsSetInformerClientSettings(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_SET_INFORMER_CLIENT_SETTINGS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgSetInformerClientSettings);\n\n    msg = &Message->User.SetInformerClientSettings;\n\n    msg->Status = KphSetInformerClientSettings(Client, msg->Settings);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsAcquireDriverUnloadProtection(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_ACQUIRE_DRIVER_UNLOAD_PROTECTION msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgAcquireDriverUnloadProtection);\n\n    msg = &Message->User.AcquireDriverUnloadProtection;\n\n    msg->Status = KphAcquireReference(&Client->DriverUnloadProtectionRef,\n                                      &msg->ClientPreviousCount);\n    if (NT_SUCCESS(msg->Status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Client %wZ (%lu) \"\n                      \"acquired driver unload protection (%ld)\",\n                      &Client->Process->ImageName,\n                      HandleToULong(Client->Process->ProcessId),\n                      msg->ClientPreviousCount + 1);\n\n        if (msg->ClientPreviousCount == 0)\n        {\n            msg->Status = KphAcquireDriverUnloadProtection(&msg->PreviousCount);\n        }\n        else\n        {\n            msg->PreviousCount = KphGetDriverUnloadProtectionCount();\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsReleaseDriverUnloadProtection(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_RELEASE_DRIVER_UNLOAD_PROTECTION msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgReleaseDriverUnloadProtection);\n\n    msg = &Message->User.ReleaseDriverUnloadProtection;\n\n    msg->Status = KphReleaseReference(&Client->DriverUnloadProtectionRef,\n                                      &msg->ClientPreviousCount);\n    if (NT_SUCCESS(msg->Status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Client %wZ (%lu) \"\n                      \"released driver unload protection (%ld)\",\n                      &Client->Process->ImageName,\n                      HandleToULong(Client->Process->ProcessId),\n                      msg->ClientPreviousCount - 1);\n\n        if (msg->ClientPreviousCount == 1)\n        {\n            msg->Status = KphReleaseDriverUnloadProtection(&msg->PreviousCount);\n        }\n        else\n        {\n            msg->PreviousCount = KphGetDriverUnloadProtectionCount();\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsGetConnectedClientCount(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_GET_CONNECTED_CLIENT_COUNT msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgGetConnectedClientCount);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.GetConnectedClientCount;\n\n    msg->Count = KphGetConnectedClientCount();\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsActivateDynData(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_ACTIVATE_DYNDATA msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgActivateDynData);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.ActivateDynData;\n\n    msg->Status = KphActivateDynData(msg->DynData,\n                                     msg->DynDataLength,\n                                     msg->Signature,\n                                     msg->SignatureLength,\n                                     UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsIsDynDataActive(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_IS_DYNDATA_ACTIVE msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgIsDynDataActive);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.IsDynDataActive;\n\n    msg->Status = KphIsDynDataActive(msg->IsActive, UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsRequestSessionAccessToken(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_REQUEST_SESSION_ACCESS_TOKEN msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgRequestSessionAccessToken);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.RequestSessionAccessToken;\n\n    msg->Status = KphRequestSessionAccessToken(&msg->AccessToken,\n                                               &msg->Expiry,\n                                               msg->Privileges,\n                                               msg->Uses);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsAssignProcessSessionToken(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_ASSIGN_PROCESS_SESSION_TOKEN msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgAssignProcessSessionToken);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.AssignProcessSessionToken;\n\n    msg->Status = KphAssignProcessSessionToken(msg->ProcessHandle,\n                                               msg->Signature,\n                                               msg->SignatureLength,\n                                               UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsAssignThreadSessionToken(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_ASSIGN_THREAD_SESSION_TOKEN msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgAssignThreadSessionToken);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.AssignThreadSessionToken;\n\n    msg->Status = KphAssignThreadSessionToken(msg->ThreadHandle,\n                                              msg->Signature,\n                                              msg->SignatureLength,\n                                              UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsGetInformerProcessSettings(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_GET_INFORMER_PROCESS_SETTINGS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgGetInformerProcessSettings);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.GetInformerProcessSettings;\n\n    msg->Status = KphGetInformerProcessSettings(msg->ProcessHandle,\n                                                msg->Settings,\n                                                UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsSetInformerProcessSettings(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_SET_INFORMER_PROCESS_SETTINGS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgSetInformerProcessSettings);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.SetInformerProcessSettings;\n\n    msg->Status = KphSetInformerProcessSettings(msg->ProcessHandle,\n                                                msg->Settings,\n                                                UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsStripProtectedProcessMasks(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_STRIP_PROTECTED_PROCESS_MASKS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgStripProtectedProcessMasks);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.StripProtectedProcessMasks;\n\n    msg->Status = KphStripProtectedProcessMasks(msg->ProcessHandle,\n                                                msg->ProcessAllowedMask,\n                                                msg->ThreadAllowedMask,\n                                                UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE KSIAPI KphpCommsQueryVirtualMemoryRequires(\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryVirtualMemory);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    switch (Message->User.QueryVirtualMemory.MemoryInformationClass)\n    {\n        case KphMemoryImageSection:\n        case KphMemoryDataSection:\n        {\n            return KPH_PROCESS_STATE_MEDIUM;\n        }\n        case KphMemoryMappedInformation:\n        default:\n        {\n            return KPH_PROCESS_STATE_MAXIMUM;\n        }\n    }\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQueryVirtualMemory(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_VIRTUAL_MEMORY msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryVirtualMemory);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QueryVirtualMemory;\n\n    msg->Status = KphQueryVirtualMemory(msg->ProcessHandle,\n                                        msg->BaseAddress,\n                                        msg->MemoryInformationClass,\n                                        msg->MemoryInformation,\n                                        msg->MemoryInformationLength,\n                                        msg->ReturnLength,\n                                        UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsQueryHashInformationFile(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_QUERY_HASH_INFORMATION_FILE msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgQueryHashInformationFile);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.QueryHashInformationFile;\n\n    msg->Status = KphQueryHashInformationFile(msg->FileHandle,\n                                              msg->HashingInformation,\n                                              msg->HashingInformationLength,\n                                              UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsOpenDevice(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_OPEN_DEVICE msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenDevice);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.OpenDevice;\n\n    msg->Status = KphOpenDevice(msg->DeviceHandle,\n                                msg->DesiredAccess,\n                                msg->ObjectAttributes,\n                                UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsOpenDeviceDriver(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_OPEN_DEVICE_DRIVER msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenDeviceDriver);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.OpenDeviceDriver;\n\n    msg->Status = KphOpenDeviceDriver(msg->DeviceHandle,\n                                      msg->DesiredAccess,\n                                      msg->DriverHandle,\n                                      UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsOpenDeviceBaseDevice(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_OPEN_DEVICE_BASE_DEVICE msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgOpenDeviceBaseDevice);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.OpenDeviceBaseDevice;\n\n    msg->Status = KphOpenDeviceBaseDevice(msg->DeviceHandle,\n                                          msg->DesiredAccess,\n                                          msg->BaseDeviceHandle,\n                                          UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsGetInformerStats(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_GET_INFORMER_STATS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgGetInformerStats);\n\n    UNREFERENCED_PARAMETER(Client);\n\n    msg = &Message->User.GetInformerStats;\n\n    msg->Status = KphGetInformerStats(msg->ProcessHandle, msg->Stats, UserMode);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpCommsGetInformerClientStats(\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPHM_GET_INFORMER_CLIENT_STATS msg;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(ExGetPreviousMode() == UserMode);\n    NT_ASSERT(Message->Header.MessageId == KphMsgGetInformerClientStats);\n\n    msg = &Message->User.GetInformerClientStats;\n\n    msg->Status = KphGetInformerClientStats(Client, msg->Stats);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "KSystemInformer/device.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2024-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Open a device object.\n *\n * \\param[out] DriverHandle Set to the opened handle to the device.\n * \\param[in] DesiredAccess Desired access to the device object.\n * \\param[in] ObjectAttributes Object attributes for opening the device object.\n * \\param[in] AccessMode The mode in which to perform access checks.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenDevice(\n    _Out_ PHANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    PFILE_OBJECT fileObject;\n    PUNICODE_STRING capturedObjectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    POBJECT_ATTRIBUTES objectAttributesPtr;\n    ULONG options;\n    IO_STATUS_BLOCK ioStatusBlock;\n    HANDLE deviceHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    fileHandle = NULL;\n    fileObject = NULL;\n    capturedObjectName = NULL;\n\n    if (AccessMode != KernelMode)\n    {\n        OBJECT_ATTRIBUTES capturedAttributes;\n\n        __try\n        {\n            ReadStructFromUser(&capturedAttributes, ObjectAttributes);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n\n        if (capturedAttributes.ObjectName)\n        {\n            status = KphCaptureUnicodeString(capturedAttributes.ObjectName,\n                                             &capturedObjectName);\n            if (!NT_SUCCESS(status))\n            {\n                goto Exit;\n            }\n        }\n\n        SetFlag(capturedAttributes.Attributes, OBJ_KERNEL_HANDLE);\n        SetFlag(capturedAttributes.Attributes, OBJ_FORCE_ACCESS_CHECK);\n\n        InitializeObjectAttributes(&objectAttributes,\n                                   capturedObjectName,\n                                   capturedAttributes.Attributes,\n                                   capturedAttributes.RootDirectory,\n                                   NULL);\n\n        objectAttributesPtr = &objectAttributes;\n        options = IO_FORCE_ACCESS_CHECK;\n    }\n    else\n    {\n        objectAttributesPtr = ObjectAttributes;\n        options = 0;\n    }\n\n    status = KphCreateFile(&fileHandle,\n                           DesiredAccess,\n                           objectAttributesPtr,\n                           &ioStatusBlock,\n                           NULL,\n                           0,\n                           FILE_SHARE_READ | FILE_SHARE_WRITE,\n                           FILE_OPEN,\n                           FILE_NON_DIRECTORY_FILE,\n                           NULL,\n                           0,\n                           options,\n                           KernelMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphCreateFile failed: %!STATUS!\",\n                      status);\n\n        fileHandle = NULL;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(fileHandle,\n                                       0,\n                                       *IoFileObjectType,\n                                       KernelMode,\n                                       &fileObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        fileObject = NULL;\n        goto Exit;\n    }\n\n    status = ObOpenObjectByPointer(IoGetRelatedDeviceObject(fileObject),\n                                   (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                   NULL,\n                                   DesiredAccess,\n                                   *IoDeviceObjectType,\n                                   AccessMode,\n                                   &deviceHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        deviceHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphWriteHandleToMode(DeviceHandle, deviceHandle, AccessMode);\n\nExit:\n\n    if (fileObject)\n    {\n        ObDereferenceObject(fileObject);\n    }\n\n    if (fileHandle)\n    {\n        ObCloseHandle(fileHandle, KernelMode);\n    }\n\n    if (capturedObjectName)\n    {\n        KphReleaseUnicodeString(capturedObjectName);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Opens a driver object associated with a device object.\n *\n * \\param[in] DeviceHandle Handle to a device object.\n * \\param[in] DesiredAccess Desired access to the driver object.\n * \\param[out] DriverHandle Set to the opened handle to the driver object.\n * \\param[in] AccessMode The mode in which to perform access checks.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenDeviceDriver(\n    _In_ HANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE DriverHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PDEVICE_OBJECT deviceObject;\n    HANDLE driverHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n\n    status = ObReferenceObjectByHandle(DeviceHandle,\n                                       DesiredAccess,\n                                       *IoDeviceObjectType,\n                                       AccessMode,\n                                       &deviceObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        deviceObject = NULL;\n        goto Exit;\n    }\n\n    status = ObOpenObjectByPointer(deviceObject->DriverObject,\n                                   (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                   NULL,\n                                   DesiredAccess,\n                                   *IoDriverObjectType,\n                                   AccessMode,\n                                   &driverHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        driverHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphWriteHandleToMode(DriverHandle, driverHandle, AccessMode);\n\nExit:\n\n    if (deviceObject)\n    {\n        ObDereferenceObject(deviceObject);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Opens the base device object associated with a device object.\n *\n * \\details The base device object is the lowest-level device object in the file\n * system or device driver stack.\n *\n * \\param[in] DeviceHandle Handle to a device object.\n * \\param[in] DesiredAccess Desired access to the base device object.\n * \\param[out] BaseDeviceHandle Set to the opened handle to the device object.\n * \\param[in] AccessMode The mode in which to perform access checks.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphOpenDeviceBaseDevice(\n    _In_ HANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE BaseDeviceHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PDEVICE_OBJECT deviceObject;\n    PDEVICE_OBJECT baseDeviceObject;\n    HANDLE baseDeviceHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    baseDeviceObject = NULL;\n\n    status = ObReferenceObjectByHandle(DeviceHandle,\n                                       DesiredAccess,\n                                       *IoDeviceObjectType,\n                                       AccessMode,\n                                       &deviceObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        deviceObject = NULL;\n        goto Exit;\n    }\n\n    baseDeviceObject = IoGetDeviceAttachmentBaseRef(deviceObject);\n\n    status = ObOpenObjectByPointer(baseDeviceObject,\n                                   (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                   NULL,\n                                   DesiredAccess,\n                                   *IoDeviceObjectType,\n                                   AccessMode,\n                                   &baseDeviceHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        baseDeviceHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphWriteHandleToMode(BaseDeviceHandle,\n                                  baseDeviceHandle,\n                                  AccessMode);\n\nExit:\n\n    if (baseDeviceObject)\n    {\n        ObDereferenceObject(baseDeviceObject);\n    }\n\n    if (deviceObject)\n    {\n        ObDereferenceObject(deviceObject);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/driver.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Opens a driver object.\n *\n * \\param[out] DriverHandle Set to the opened handle to the driver.\n * \\param[in] DesiredAccess Desired access to the driver object.\n * \\param[in] ObjectAttributes Object attributes for opening the driver object.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenDriver(\n    _Out_ PHANDLE DriverHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    return KphOpenNamedObject(DriverHandle,\n                              DesiredAccess,\n                              ObjectAttributes,\n                              *IoDriverObjectType,\n                              AccessMode);\n}\n\n/**\n * \\brief Queries information about a driver.\n *\n * \\param[in] DriverHandle Handle to driver to query.\n * \\param[in] DriverInformationClass Information class to query.\n * \\param[out] DriverInformation Populated with driver information by class.\n * \\param[in] DriverInformationLength Length of the driver information buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationDriver(\n    _In_ HANDLE DriverHandle,\n    _In_ KPH_DRIVER_INFORMATION_CLASS DriverInformationClass,\n    _Out_writes_bytes_opt_(DriverInformationLength) PVOID DriverInformation,\n    _In_ ULONG DriverInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PDRIVER_OBJECT driverObject;\n    ULONG returnLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    returnLength = 0;\n\n    status = ObReferenceObjectByHandle(DriverHandle,\n                                       0,\n                                       *IoDriverObjectType,\n                                       KernelMode,\n                                       &driverObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        driverObject = NULL;\n        goto Exit;\n    }\n\n    //\n    // We reach into the driver object on purpose\n    //\n#pragma prefast(push)\n#pragma prefast(disable : 28175)\n    switch (DriverInformationClass)\n    {\n        case KphDriverBasicInformation:\n        {\n            //\n            // Basic information such as flags, driver base and driver size.\n            //\n\n            KPH_DRIVER_BASIC_INFORMATION basicInfo;\n\n            if (!DriverInformation ||\n                (DriverInformationLength < sizeof(KPH_DRIVER_BASIC_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_DRIVER_BASIC_INFORMATION);\n                goto Exit;\n            }\n\n            RtlZeroMemory(&basicInfo, sizeof(KPH_DRIVER_BASIC_INFORMATION));\n\n            basicInfo.Flags = driverObject->Flags;\n            basicInfo.DriverStart = driverObject->DriverStart;\n            basicInfo.DriverSize = driverObject->DriverSize;\n\n            status = KphCopyToMode(DriverInformation,\n                                   &basicInfo,\n                                   sizeof(KPH_DRIVER_BASIC_INFORMATION),\n                                   AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_DRIVER_BASIC_INFORMATION);\n            }\n\n            break;\n        }\n        case KphDriverNameInformation:\n        {\n            //\n            // The name of the driver - e.g. \\Driver\\Null.\n            //\n\n            status = KphCopyUnicodeStringToMode(DriverInformation,\n                                                DriverInformationLength,\n                                                &driverObject->DriverName,\n                                                &returnLength,\n                                                AccessMode);\n\n            break;\n        }\n        case KphDriverServiceKeyNameInformation:\n        {\n            PCUNICODE_STRING serviceKeyName;\n\n            //\n            // The name of the driver's service key - e.g. \\REGISTRY\\...\n            //\n\n            if (driverObject->DriverExtension)\n            {\n                serviceKeyName = &driverObject->DriverExtension->ServiceKeyName;\n            }\n            else\n            {\n                serviceKeyName = NULL;\n            }\n\n            status = KphCopyUnicodeStringToMode(DriverInformation,\n                                                DriverInformationLength,\n                                                serviceKeyName,\n                                                &returnLength,\n                                                AccessMode);\n\n            break;\n        }\n        case KphDriverImageFileNameInformation:\n        {\n            UNICODE_STRING fullDriverPath;\n\n            if ((KphOsVersionInfo.dwMajorVersion < 10) ||\n                (KphOsVersionInfo.dwMajorVersion == 10) &&\n                (KphOsVersionInfo.dwBuildNumber < 16299))\n            {\n                //\n                // Per documentation it is not safe to call IoQueryFullDriverPath\n                // on anything but our own driver object.\n                //\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            RtlZeroMemory(&fullDriverPath, sizeof(UNICODE_STRING));\n\n            status = IoQueryFullDriverPath(driverObject, &fullDriverPath);\n            if (!NT_SUCCESS(status))\n            {\n                goto Exit;\n            }\n\n            status = KphCopyUnicodeStringToMode(DriverInformation,\n                                                DriverInformationLength,\n                                                &fullDriverPath,\n                                                &returnLength,\n                                                AccessMode);\n\n            KphFreePool(fullDriverPath.Buffer);\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n#pragma prefast(pop)\n\nExit:\n\n    if (driverObject)\n    {\n        ObDereferenceObject(driverObject);\n    }\n\n    if (ReturnLength)\n    {\n        KphWriteULongToMode(ReturnLength, returnLength, AccessMode);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/dyndata.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <kphdyndata.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_DYN_INIT\n{\n    PKPH_DYN_CONFIG Config;\n    PKPH_DYN_KERNEL_FIELDS Kernel;\n    PKPH_DYN_LXCORE_FIELDS Lxcore;\n} KPH_DYN_INIT, *PKPH_DYN_INIT;\n\ntypedef union _KPH_DYN_ATOMIC\n{\n    PKPH_DYN Dyn;\n    KPH_ATOMIC_OBJECT_REF Atomic;\n} KPH_DYN_ATOMIC, *PKPH_DYN_ATOMIC;\n\ntypedef struct _KPH_DYN_MODULE\n{\n    USHORT Class;\n    UNICODE_STRING Name;\n    BOOLEAN Valid;\n    USHORT Machine;\n    ULONG TimeDateStamp;\n    ULONG SizeOfImage;\n} KPH_DYN_MODULE, *PKPH_DYN_MODULE;\n\ntypedef enum _KPH_DYN_MODULE_CLASS\n{\n    KphDynNtoskrnl,\n    KphDynNtkrla57,\n    KphDynLxcore,\n} KPH_DYN_MODULE_CLASS, *PKPH_DYN_MODULE_CLASS;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpDynDataTypeName = RTL_CONSTANT_STRING(L\"KphDynData\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_OBJECT_TYPE KphpDynDataType = NULL;\nstatic KPH_DYN_MODULE KphpDynModules[] =\n{\n    { KPH_DYN_CLASS_NTOSKRNL, RTL_CONSTANT_STRING(L\"ntoskrnl.exe\"), FALSE, 0, 0, 0 },\n    { KPH_DYN_CLASS_NTKRLA57, RTL_CONSTANT_STRING(L\"ntkrla57.exe\"), FALSE, 0, 0, 0 },\n    { KPH_DYN_CLASS_LXCORE,   RTL_CONSTANT_STRING(L\"lxcore.sys\"),   FALSE, 0, 0, 0 },\n};\nKPH_PROTECTED_DATA_SECTION_POP();\nstatic KPH_DYN_ATOMIC KphpDynData = { .Atomic = KPH_ATOMIC_OBJECT_REF_INIT };\n\n/**\n * \\brief Reference the dynamic configuration.\n *\n * \\return Pointer to the dynamic configuration, NULL if not activated. The\n * caller must eventually dereference the object.\n */\n_Must_inspect_result_\nPKPH_DYN KphReferenceDynData(\n    VOID\n    )\n{\n    return KphAtomicReferenceObject(&KphpDynData.Atomic);\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Allocates a dynamic configuration object.\n *\n * \\param[in] Size The size of the object to allocate.\n *\n * \\return Pointer to the allocated object, NULL on failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateDynData(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    return KphAllocateNPaged(Size, KPH_TAG_DYNDATA);\n}\n\n/**\n * \\brief Initializes a dynamic configuration object.\n *\n * \\param[in] Object Dynamic configuration object to initialize.\n * \\param[in] Parameter Initialization parameters for dynamic configuration.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializeDynData(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    PKPH_DYN_INIT init;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(Parameter);\n\n    dyn = Object;\n    init = Parameter;\n\n#define KPH_LOAD_DYNITEM_KERNEL(x) dyn->x = C_2sTo4(init->Kernel->x)\n#define KPH_LOAD_DYNITEM_LXCORE(x) dyn->x = init->Lxcore ? C_2sTo4(init->Lxcore->x) : ULONG_MAX;\n\n    KPH_LOAD_DYNITEM_KERNEL(EgeGuid);\n    KPH_LOAD_DYNITEM_KERNEL(EpObjectTable);\n    KPH_LOAD_DYNITEM_KERNEL(EreGuidEntry);\n    KPH_LOAD_DYNITEM_KERNEL(HtHandleContentionEvent);\n    KPH_LOAD_DYNITEM_KERNEL(OtName);\n    KPH_LOAD_DYNITEM_KERNEL(OtIndex);\n    KPH_LOAD_DYNITEM_KERNEL(ObDecodeShift);\n    KPH_LOAD_DYNITEM_KERNEL(ObAttributesShift);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcCommunicationInfo);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcOwnerProcess);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcConnectionPort);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcServerCommunicationPort);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcClientCommunicationPort);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcHandleTable);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcHandleTableLock);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcAttributes);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcAttributesFlags);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcPortContext);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcPortObjectLock);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcSequenceNo);\n    KPH_LOAD_DYNITEM_KERNEL(AlpcState);\n    KPH_LOAD_DYNITEM_KERNEL(KtInitialStack);\n    KPH_LOAD_DYNITEM_KERNEL(KtStackLimit);\n    KPH_LOAD_DYNITEM_KERNEL(KtStackBase);\n    KPH_LOAD_DYNITEM_KERNEL(KtKernelStack);\n    KPH_LOAD_DYNITEM_KERNEL(KtReadOperationCount);\n    KPH_LOAD_DYNITEM_KERNEL(KtWriteOperationCount);\n    KPH_LOAD_DYNITEM_KERNEL(KtOtherOperationCount);\n    KPH_LOAD_DYNITEM_KERNEL(KtReadTransferCount);\n    KPH_LOAD_DYNITEM_KERNEL(KtWriteTransferCount);\n    KPH_LOAD_DYNITEM_KERNEL(KtOtherTransferCount);\n    KPH_LOAD_DYNITEM_KERNEL(MmSectionControlArea);\n    KPH_LOAD_DYNITEM_KERNEL(MmControlAreaListHead);\n    KPH_LOAD_DYNITEM_KERNEL(MmControlAreaLock);\n    KPH_LOAD_DYNITEM_KERNEL(EpSectionObject);\n\n    KPH_LOAD_DYNITEM_LXCORE(LxPicoProc);\n    KPH_LOAD_DYNITEM_LXCORE(LxPicoProcInfo);\n    KPH_LOAD_DYNITEM_LXCORE(LxPicoProcInfoPID);\n    KPH_LOAD_DYNITEM_LXCORE(LxPicoThrdInfo);\n    KPH_LOAD_DYNITEM_LXCORE(LxPicoThrdInfoTID);\n\n    status = KphVerifyCreateKey(&dyn->SessionTokenPublicKeyHandle,\n                                init->Config->SessionTokenPublicKey,\n                                KPH_DYN_SESSION_TOKEN_PUBLIC_KEY_LENGTH);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphVerifyCreateKey failed: %!STATUS!\",\n                      status);\n\n        dyn->SessionTokenPublicKeyHandle = NULL;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Deletes a dynamic configuration object.\n *\n * \\param[in] Object Dynamic configuration object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpDeleteDynData(\n    _In_freesMem_ PVOID Object\n    )\n{\n    PKPH_DYN dyn;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = Object;\n\n    if (dyn->SessionTokenPublicKeyHandle)\n    {\n        KphVerifyCloseKey(dyn->SessionTokenPublicKeyHandle);\n    }\n}\n\n/**\n * \\brief Frees a dynamic configuration object.\n *\n * \\param[in] Object Dynamic configuration object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpFreeDynData(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphFree(Object, KPH_TAG_DYNDATA);\n}\n\n/**\n * \\brief Activates dynamic data.\n *\n * \\param[in] DynConfig The dynamic configuration to activate.\n * \\param[in] DynConfigLength The length of the dynamic configuration.\n * \\param[in] Signature The signature of the dynamic data.\n * \\param[in] SignatureLength The length of the signature.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpActivateDynData(\n    _In_ PBYTE DynConfig,\n    _In_ ULONG DynConfigLength,\n    _In_opt_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    KPH_DYN_INIT init;\n    PKPH_DYN_KERNEL_FIELDS kernel;\n    PKPH_DYN_LXCORE_FIELDS lxcore;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = NULL;\n    kernel = NULL;\n    lxcore = NULL;\n\n    if (Signature)\n    {\n        status = KphVerifyBuffer(DynConfig,\n                                 DynConfigLength,\n                                 Signature,\n                                 SignatureLength);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"KphVerifyBuffer failed: %!STATUS!\",\n                          status);\n\n            status = STATUS_SI_DYNDATA_INVALID_SIGNATURE;\n            goto Exit;\n        }\n    }\n\n    if (KphpDynModules[KphDynNtoskrnl].Valid)\n    {\n        status = KphDynDataLookup((PKPH_DYN_CONFIG)DynConfig,\n                                  DynConfigLength,\n                                  KphpDynModules[KphDynNtoskrnl].Class,\n                                  KphpDynModules[KphDynNtoskrnl].Machine,\n                                  KphpDynModules[KphDynNtoskrnl].TimeDateStamp,\n                                  KphpDynModules[KphDynNtoskrnl].SizeOfImage,\n                                  NULL,\n                                  &kernel);\n    }\n    else if (KphpDynModules[KphDynNtkrla57].Valid)\n    {\n        status = KphDynDataLookup((PKPH_DYN_CONFIG)DynConfig,\n                                  DynConfigLength,\n                                  KphpDynModules[KphDynNtkrla57].Class,\n                                  KphpDynModules[KphDynNtkrla57].Machine,\n                                  KphpDynModules[KphDynNtkrla57].TimeDateStamp,\n                                  KphpDynModules[KphDynNtkrla57].SizeOfImage,\n                                  NULL,\n                                  &kernel);\n    }\n    else\n    {\n        status = STATUS_NOT_FOUND;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphDynDataLookup failed: %!STATUS!\",\n                      status);\n\n        //\n        // Activating dynamic data requires at least kernel data.\n        //\n        goto Exit;\n    }\n\n    if (KphpDynModules[KphDynLxcore].Valid)\n    {\n        status = KphDynDataLookup((PKPH_DYN_CONFIG)DynConfig,\n                                  DynConfigLength,\n                                  KphpDynModules[KphDynLxcore].Class,\n                                  KphpDynModules[KphDynLxcore].Machine,\n                                  KphpDynModules[KphDynLxcore].TimeDateStamp,\n                                  KphpDynModules[KphDynLxcore].SizeOfImage,\n                                  NULL,\n                                  &lxcore);\n    }\n    else\n    {\n        status = STATUS_NOT_FOUND;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphDynDataLookup failed: %!STATUS!\",\n                      status);\n\n        //\n        // Activating dynamic data does not require lxcore data.\n        //\n        lxcore = NULL;\n    }\n\n    init.Config = (PKPH_DYN_CONFIG)DynConfig;\n    init.Kernel = kernel;\n    init.Lxcore = lxcore;\n\n    status = KphCreateObject(KphpDynDataType, sizeof(KPH_DYN), &dyn, &init);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    KphAtomicAssignObjectReference(&KphpDynData.Atomic, dyn);\n\n    KphTracePrint(TRACE_LEVEL_INFORMATION,\n                  GENERAL,\n                  \"Activated Dynamic Configuration \"\n                  \"for Windows %lu.%lu.%lu Kernel %hu.%hu.%hu.%hu\",\n                  KphOsVersionInfo.dwMajorVersion,\n                  KphOsVersionInfo.dwMinorVersion,\n                  KphOsVersionInfo.dwBuildNumber,\n                  KphKernelVersion.MajorVersion,\n                  KphKernelVersion.MinorVersion,\n                  KphKernelVersion.BuildNumber,\n                  KphKernelVersion.Revision);\n\nExit:\n\n    if (dyn)\n    {\n        KphDereferenceObject(dyn);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Activates dynamic data.\n *\n * \\param[in] DynData The dynamic data to activate.\n * \\param[in] DynDataLength The length of the dynamic data.\n * \\param[in] Signature The signature of the dynamic data.\n * \\param[in] SignatureLength The length of the signature.\n * \\param[in] AccessMode The access mode of the caller.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphActivateDynData(\n    _In_ PBYTE DynData,\n    _In_ ULONG DynDataLength,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PBYTE dynData;\n    PBYTE signature;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dynData = NULL;\n    signature = NULL;\n\n    if (!DynData || !DynDataLength)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    if (!Signature || !SignatureLength)\n    {\n        status = STATUS_SI_DYNDATA_INVALID_SIGNATURE;\n        goto Exit;\n    }\n\n    if (AccessMode != KernelMode)\n    {\n        dynData = KphAllocatePaged(DynDataLength, KPH_TAG_DYNDATA);\n        if (!dynData)\n        {\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        signature = KphAllocatePaged(SignatureLength, KPH_TAG_DYNDATA);\n        if (!signature)\n        {\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        __try\n        {\n            CopyFromUser(dynData, DynData, DynDataLength);\n            CopyFromUser(signature, Signature, SignatureLength);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n    }\n    else\n    {\n        dynData = DynData;\n        signature = Signature;\n    }\n\n    status = KphpActivateDynData(dynData,\n                                 DynDataLength,\n                                 signature,\n                                 SignatureLength);\n\nExit:\n\n    if (dynData && (dynData != DynData))\n    {\n        KphFree(dynData, KPH_TAG_DYNDATA);\n    }\n\n    if (signature && (signature != Signature))\n    {\n        KphFree(signature, KPH_TAG_DYNDATA);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Checks if dynamic data is active.\n *\n * \\param[out] IsActive Receives TRUE if active, FALSE otherwise.\n * \\param[in] AccessMode The access mode of the caller.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphIsDynDataActive(\n    _Out_ PBOOLEAN IsActive,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    PKPH_DYN dyn;\n    BOOLEAN isActive;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = KphReferenceDynData();\n    if (dyn)\n    {\n        isActive = TRUE;\n        KphDereferenceObject(dyn);\n    }\n    else\n    {\n        isActive = FALSE;\n    }\n\n    return KphWriteUCharToMode(IsActive, isActive, AccessMode);\n}\n\n/**\n * \\brief Initializes the dynamic modules.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpInitializeDynModules(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KeEnterCriticalRegion();\n    if (!ExAcquireResourceSharedLite(PsLoadedModuleResource, TRUE))\n    {\n        KeLeaveCriticalRegion();\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Failed to acquire PsLoadedModuleResource\");\n\n        return;\n    }\n\n    for (ULONG i = 0; i < ARRAYSIZE(KphpDynModules); i++)\n    {\n        PKPH_DYN_MODULE dynModule;\n\n        dynModule = &KphpDynModules[i];\n\n        for (PLIST_ENTRY link = PsLoadedModuleList->Flink;\n             link != PsLoadedModuleList;\n             link = link->Flink)\n        {\n            NTSTATUS status;\n            PKLDR_DATA_TABLE_ENTRY entry;\n            KPH_IMAGE_NT_HEADERS image;\n\n            entry = CONTAINING_RECORD(link, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n\n            if (!RtlEqualUnicodeString(&entry->BaseDllName, &dynModule->Name, TRUE))\n            {\n                continue;\n            }\n\n            __try\n            {\n                status = KphImageNtHeader(entry->DllBase, entry->SizeOfImage, &image);\n                if (!NT_SUCCESS(status))\n                {\n                    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                                  GENERAL,\n                                  \"KphImageNtHeader failed: %!STATUS!\",\n                                  status);\n\n                    break;\n                }\n\n                dynModule->Machine = image.Headers->FileHeader.Machine;\n                dynModule->TimeDateStamp = image.Headers->FileHeader.TimeDateStamp;\n                if (RTL_CONTAINS_FIELD(&image.Headers->OptionalHeader,\n                                       image.Headers->FileHeader.SizeOfOptionalHeader,\n                                       SizeOfImage))\n                {\n                    dynModule->SizeOfImage = image.Headers->OptionalHeader.SizeOfImage;\n                    dynModule->Valid = TRUE;\n                }\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"Failed to read module headers: %!STATUS!\",\n                              GetExceptionCode());\n            }\n\n            break;\n        }\n    }\n\n    ExReleaseResourceLite(PsLoadedModuleResource);\n    KeLeaveCriticalRegion();\n}\n\n/**\n * \\brief Initializes the dynamic data infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeDynData(\n    VOID\n    )\n{\n    NTSTATUS status;\n    KPH_OBJECT_TYPE_INFO typeInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphpInitializeDynModules();\n\n    typeInfo.Allocate = KphpAllocateDynData;\n    typeInfo.Initialize = KphpInitializeDynData;\n    typeInfo.Delete = KphpDeleteDynData;\n    typeInfo.Free = KphpFreeDynData;\n    typeInfo.Flags = 0;\n    typeInfo.DeferDelete = TRUE;\n\n    KphCreateObjectType(&KphpDynDataTypeName, &typeInfo, &KphpDynDataType);\n\n    if (KphParameterFlags.DynDataNoEmbedded)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Embedded Dynamic Configuration disabled\");\n    }\n    else\n    {\n        status = KphpActivateDynData((PBYTE)KphDynConfig,\n                                     KphDynConfigLength,\n                                     NULL,\n                                     0);\n\n        NT_ANALYSIS_ASSUME(NT_SUCCESS(status));\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Embedded Dynamic Configuration: %!STATUS!\",\n                      status);\n    }\n}\n\n/**\n * \\brief Cleans up the dynamic data infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupDynData(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphAtomicAssignObjectReference(&KphpDynData.Atomic, NULL);\n}\n"
  },
  {
    "path": "KSystemInformer/dynimp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     jxy-s   2020-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nPPS_SET_LOAD_IMAGE_NOTIFY_ROUTINE_EX KphDynPsSetLoadImageNotifyRoutineEx = NULL;\nPPS_SET_CREATE_PROCESS_NOTIFY_ROUTINE_EX2 KphDynPsSetCreateProcessNotifyRoutineEx2 = NULL;\nPMM_PROTECT_DRIVER_SECTION KphDynMmProtectDriverSection = NULL;\nPPS_GET_PROCESS_SEQUENCE_NUMBER KphDynPsGetProcessSequenceNumber = NULL;\nPPS_GET_PROCESS_START_KEY KphDynPsGetProcessStartKey = NULL;\nPSE_REGISTER_IMAGE_VERIFICATION_CALLBACK KphSeRegisterImageVerificationCallback = NULL;\nPSE_UNREGISTER_IMAGE_VERIFICATION_CALLBACK KphSeUnregisterImageVerificationCallback = NULL;\nPCI_VALIDATE_FILE_OBJECT KphDynCiValidateFileObject = NULL;\nPCI_FREE_POLICY_INFO KphDynCiFreePolicyInfo = NULL;\nPLXP_THREAD_GET_CURRENT KphDynLxpThreadGetCurrent = NULL;\nPIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_SOURCE KphDynIoCheckFileObjectOpenedAsCopySource = NULL;\nPIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_DESTINATION KphDynIoCheckFileObjectOpenedAsCopyDestination = NULL;\nPFLT_GET_COPY_INFORMATION_FROM_CALLBACK_DATA KphDynFltGetCopyInformationFromCallbackData = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Dynamically imports routines.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphDynamicImport(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphDynPsSetLoadImageNotifyRoutineEx = (PPS_SET_LOAD_IMAGE_NOTIFY_ROUTINE_EX)KphGetSystemRoutineAddress(L\"PsSetLoadImageNotifyRoutineEx\");\n    KphDynPsSetCreateProcessNotifyRoutineEx2 = (PPS_SET_CREATE_PROCESS_NOTIFY_ROUTINE_EX2)KphGetSystemRoutineAddress(L\"PsSetCreateProcessNotifyRoutineEx2\");\n    KphDynMmProtectDriverSection = (PMM_PROTECT_DRIVER_SECTION)KphGetSystemRoutineAddress(L\"MmProtectDriverSection\");\n    KphDynPsGetProcessSequenceNumber = (PPS_GET_PROCESS_SEQUENCE_NUMBER)KphGetSystemRoutineAddress(L\"PsGetProcessSequenceNumber\");\n    KphDynPsGetProcessStartKey = (PPS_GET_PROCESS_START_KEY)KphGetSystemRoutineAddress(L\"PsGetProcessStartKey\");\n    KphSeRegisterImageVerificationCallback = (PSE_REGISTER_IMAGE_VERIFICATION_CALLBACK)KphGetSystemRoutineAddress(L\"SeRegisterImageVerificationCallback\");\n    KphSeUnregisterImageVerificationCallback = (PSE_UNREGISTER_IMAGE_VERIFICATION_CALLBACK)KphGetSystemRoutineAddress(L\"SeUnregisterImageVerificationCallback\");\n    KphDynCiValidateFileObject = (PCI_VALIDATE_FILE_OBJECT)KphGetRoutineAddress(L\"ci.dll\", \"CiValidateFileObject\");\n    KphDynCiFreePolicyInfo = (PCI_FREE_POLICY_INFO)KphGetRoutineAddress(L\"ci.dll\", \"CiFreePolicyInfo\");\n    KphDynLxpThreadGetCurrent = (PLXP_THREAD_GET_CURRENT)KphGetRoutineAddress(L\"lxcore.sys\", \"LxpThreadGetCurrent\");\n    KphDynIoCheckFileObjectOpenedAsCopySource = (PIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_SOURCE)KphGetSystemRoutineAddress(L\"IoCheckFileObjectOpenedAsCopySource\");\n    KphDynIoCheckFileObjectOpenedAsCopyDestination = (PIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_DESTINATION)KphGetSystemRoutineAddress(L\"IoCheckFileObjectOpenedAsCopyDestination\");\n    KphDynFltGetCopyInformationFromCallbackData = (PFLT_GET_COPY_INFORMATION_FROM_CALLBACK_DATA)KphGetRoutineAddress(L\"fltMgr.sys\", \"FltGetCopyInformationFromCallbackData\");\n}\n\n/**\n * \\brief Retrieves the address of a function exported by NTOS or HAL.\n *\n * \\param SystemRoutineName The name of the function.\n *\n * \\return The address of the function, or NULL if the function could\n * not be found.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nPVOID KphGetSystemRoutineAddress(\n    _In_z_ PCWSTR SystemRoutineName\n    )\n{\n    UNICODE_STRING systemRoutineName;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlInitUnicodeString(&systemRoutineName, SystemRoutineName);\n\n    return MmGetSystemRoutineAddress(&systemRoutineName);\n}\n\n/**\n * \\brief Retrieves the address of a function using the exported module list.\n * Caller must guarantee that PsLoadedModuleList and PsLoadedModuleResource\n * is available prior to this call.\n *\n * \\param ModuleName The name of the module to retrieve the function from.\n * \\param RoutineName The name of the routine to retrieve.\n *\n * \\return The address of the function, or NULL if the function could\n * not be found.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nPVOID KphpGetRoutineAddressByModuleList(\n    _In_z_ PCWSTR ModuleName,\n    _In_z_ PCSTR RoutineName\n    )\n{\n    PVOID routine;\n    UNICODE_STRING moduleName;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    routine = NULL;\n    RtlInitUnicodeString(&moduleName, ModuleName);\n\n    KeEnterCriticalRegion();\n    if (!ExAcquireResourceSharedLite(PsLoadedModuleResource, TRUE))\n    {\n        KeLeaveCriticalRegion();\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Failed to acquire PsLoadedModuleResource to \"\n                      \"get routine %ls!%hs\",\n                      ModuleName,\n                      RoutineName);\n\n        return routine;\n    }\n\n    for (PLIST_ENTRY link = PsLoadedModuleList->Flink;\n         link != PsLoadedModuleList;\n         link = link->Flink)\n    {\n        PKLDR_DATA_TABLE_ENTRY entry;\n\n        entry = CONTAINING_RECORD(link, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n\n        if (!RtlEqualUnicodeString(&entry->BaseDllName, &moduleName, TRUE))\n        {\n            continue;\n        }\n\n        routine = RtlFindExportedRoutineByName(entry->DllBase, RoutineName);\n        if (routine)\n        {\n            break;\n        }\n    }\n\n    ExReleaseResourceLite(PsLoadedModuleResource);\n    KeLeaveCriticalRegion();\n\n    if (!routine)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Failed to find routine %ls!%hs\",\n                      ModuleName,\n                      RoutineName);\n    }\n\n    return routine;\n}\n\n/**\n * \\brief Retrieves the address of a function.\n *\n * \\param ModuleName The name of the module to retrieve the function from.\n * \\param RoutineName The name of the routine to retrieve.\n *\n * \\return The address of the function, or NULL if the function could\n * not be found.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nPVOID KphGetRoutineAddress(\n    _In_z_ PCWSTR ModuleName,\n    _In_z_ PCSTR RoutineName\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    return KphpGetRoutineAddressByModuleList(ModuleName, RoutineName);\n}\n"
  },
  {
    "path": "KSystemInformer/file.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Checks if a file handle is safe to issue a query through.\n *\n * \\details Expects to be stack attached to the process that owns the handle.\n *\n * \\param[in] FileHandle The file handle to check.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpCheckFileHandleForQuery(\n    _In_ HANDLE FileHandle\n    )\n{\n    NTSTATUS status;\n    PFILE_OBJECT fileObject;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    //\n    // We are stack attached and \"invading\" the process to perform the query.\n    // If the file object is \"Busy\" it means it's a synchronous file object\n    // that is currently servicing an I/O request. If we were to issue another\n    // request the call would block until the other completes. Since we don't\n    // control this handle it's possible the call will never complete.\n    //\n    // This check isn't perfect, there is still a race, but it's narrower and\n    // makes it safer and faster for the client. As this stands it's a pretty\n    // gross hack, but we get value out of these APIs, so the hack is better\n    // than nothing.\n    //\n    // TODO(jxy-s) investigate other options to close or eliminate the race\n    //\n\n    status = ObReferenceObjectByHandle(FileHandle,\n                                       0,\n                                       *IoFileObjectType,\n                                       KernelMode,\n                                       &fileObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    status = fileObject->Busy ? STATUS_POSSIBLE_DEADLOCK : STATUS_SUCCESS;\n\n    ObDereferenceObject(fileObject);\n\n    return status;\n}\n\n/**\n * \\brief Queries file information.\n *\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[in] FileHandle A file handle which is present in the process.\n * \\param[in] FileInformationClass The type of information to retrieve.\n * \\param[out] FileInformation The buffer to store the information.\n * \\param[in] FileInformationLength Length of the information buffer.\n * \\param[in] IoStatusBlock Receives completion status and information.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationFile(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_writes_bytes_(FileInformationLength) PVOID FileInformation,\n    _In_ ULONG FileInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS process;\n    KAPC_STATE apcState;\n    IO_STATUS_BLOCK ioStatusBlock;\n    PVOID buffer;\n    BYTE stackBuffer[64];\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    process = NULL;\n    buffer = NULL;\n    RtlZeroMemory(&ioStatusBlock, sizeof(IO_STATUS_BLOCK));\n\n    if (!FileInformation || !IoStatusBlock)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (process == PsInitialSystemProcess)\n    {\n        FileHandle = MakeKernelHandle(FileHandle);\n    }\n    else\n    {\n        if (IsKernelHandle(FileHandle))\n        {\n            status = STATUS_INVALID_HANDLE;\n            goto Exit;\n        }\n    }\n\n    buffer = KphAllocatePagedA(FileInformationLength,\n                               KPH_TAG_FILE_QUERY,\n                               stackBuffer);\n    if (!buffer)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    KeStackAttachProcess(process, &apcState);\n    status = KphpCheckFileHandleForQuery(FileHandle);\n    if (NT_SUCCESS(status))\n    {\n        status = ZwQueryInformationFile(FileHandle,\n                                        &ioStatusBlock,\n                                        buffer,\n                                        FileInformationLength,\n                                        FileInformationClass);\n    }\n    KeUnstackDetachProcess(&apcState);\n    if (NT_SUCCESS(status))\n    {\n        status = KphCopyToMode(FileInformation,\n                               buffer,\n                               FileInformationLength,\n                               AccessMode);\n    }\n\n    KphCopyToMode(IoStatusBlock,\n                  &ioStatusBlock,\n                  sizeof(IO_STATUS_BLOCK),\n                  AccessMode);\n\nExit:\n\n    if (buffer)\n    {\n        KphFreeA(buffer, KPH_TAG_FILE_QUERY, stackBuffer);\n    }\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries file volume information.\n *\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[in] FileHandle A file handle which is present in the process.\n * \\param[in] FsInformationClass The type of information to retrieve.\n * \\param[out] FsInformation The buffer to store the information.\n * \\param[in] FsInformationLength Length of the information buffer.\n * \\param[in] IoStatusBlock Receives completion status and information.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryVolumeInformationFile(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FS_INFORMATION_CLASS FsInformationClass,\n    _Out_writes_bytes_(FsInformationLength) PVOID FsInformation,\n    _In_ ULONG FsInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS process;\n    KAPC_STATE apcState;\n    IO_STATUS_BLOCK ioStatusBlock;\n    PVOID buffer;\n    BYTE stackBuffer[64];\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    process = NULL;\n    buffer = NULL;\n    RtlZeroMemory(&ioStatusBlock, sizeof(IO_STATUS_BLOCK));\n\n    if (!FsInformation || !IoStatusBlock)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (process == PsInitialSystemProcess)\n    {\n        FileHandle = MakeKernelHandle(FileHandle);\n    }\n    else\n    {\n        if (IsKernelHandle(FileHandle))\n        {\n            status = STATUS_INVALID_HANDLE;\n            goto Exit;\n        }\n    }\n\n    buffer = KphAllocatePagedA(FsInformationLength,\n                               KPH_TAG_VOL_FILE_QUERY,\n                               stackBuffer);\n    if (!buffer)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    KeStackAttachProcess(process, &apcState);\n    status = KphpCheckFileHandleForQuery(FileHandle);\n    if (NT_SUCCESS(status))\n    {\n        status = ZwQueryVolumeInformationFile(FileHandle,\n                                              &ioStatusBlock,\n                                              buffer,\n                                              FsInformationLength,\n                                              FsInformationClass);\n    }\n    KeUnstackDetachProcess(&apcState);\n    if (NT_SUCCESS(status))\n    {\n        status = KphCopyToMode(FsInformation,\n                               buffer,\n                               FsInformationLength,\n                               AccessMode);\n    }\n\n    KphCopyToMode(IoStatusBlock,\n                  &ioStatusBlock,\n                  sizeof(IO_STATUS_BLOCK),\n                  AccessMode);\n\nExit:\n\n    if (buffer)\n    {\n        KphFreeA(buffer, KPH_TAG_VOL_FILE_QUERY, stackBuffer);\n    }\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Creates a file.\n *\n * \\param[out] FileHandle Populated with file handle on success.\n * \\param[in] DesiredAccess The desired access to the file.\n * \\param[in] ObjectAttributes Object attributes for the create.\n * \\param[out] IoStatusBlock Receives final completion status and information.\n * \\param[in] AllocationSize Optional allocation size, in bytes, for the file.\n * \\param[in] FileAttributes Explicitly specified attributes are applied only\n * when the file is created, superseded, or, in some cases, overwritten.\n * \\param[in] ShareAccess Specifies the type of share access to the file that\n * the caller would like.\n * \\param[in] CreateDisposition Value that determines how the file should be\n * handled when the file already exists.\n * \\param[in] CreateOptions Specifies the options to be applied when creating\n * or opening the file.\n * \\param[in] EaBuffer Optional pointer to an EA buffer.\n * \\param[in] EaLength Length of EA buffer.\n * \\param[in] Options Specifies options to be used during the generation of\n * the create request.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCreateFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,\n    _In_ ULONG EaLength,\n    _In_ ULONG Options,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (AccessMode != KernelMode)\n    {\n        if (ExGetPreviousMode() == KernelMode)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Unexpected previous mode\");\n\n            NT_ASSERT(ExGetPreviousMode() != KernelMode);\n            status = STATUS_INVALID_LEVEL;\n            goto Exit;\n        }\n\n        if (Options & ~(IO_OPEN_TARGET_DIRECTORY |\n                        IO_STOP_ON_SYMLINK |\n                        IO_IGNORE_SHARE_ACCESS_CHECK |\n                        IO_OPEN_PAGING_FILE))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Invalid options 0x%lx\",\n                          Options);\n\n            status = STATUS_INVALID_PARAMETER;\n            goto Exit;\n        }\n    }\n    else\n    {\n        Options |= (IO_NO_PARAMETER_CHECKING | IO_CHECK_CREATE_PARAMETERS);\n    }\n\n    status = IoCreateFile(FileHandle,\n                          DesiredAccess,\n                          ObjectAttributes,\n                          IoStatusBlock,\n                          AllocationSize,\n                          FileAttributes,\n                          ShareAccess,\n                          CreateDisposition,\n                          CreateOptions,\n                          EaBuffer,\n                          EaLength,\n                          CreateFileTypeNone,\n                          NULL,\n                          Options);\n\nExit:\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/hash.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\n#define KPH_HASHING_BUFFER_SIZE (16 * 1024)\n\n#define KPH_HASH_EACACHE_MD5                 KPH_KERNEL_PURGE_EA \"MD5\"\n#define KPH_HASH_EACACHE_SHA1                KPH_KERNEL_PURGE_EA \"SHA1\"\n#define KPH_HASH_EACACHE_SHA1_AUTHENTICODE   KPH_KERNEL_PURGE_EA \"SHA1A\"\n#define KPH_HASH_EACACHE_SHA256              KPH_KERNEL_PURGE_EA \"SHA256\"\n#define KPH_HASH_EACACHE_SHA256_AUTHENTICODE KPH_KERNEL_PURGE_EA \"SHA256A\"\n#define KPH_HASH_EACACHE_SHA384              KPH_KERNEL_PURGE_EA \"SHA384\"\n#define KPH_HASH_EACACHE_SHA512              KPH_KERNEL_PURGE_EA \"SHA512\"\n\nC_ASSERT(sizeof(KPH_HASH_EACACHE_MD5)                 < MAXUCHAR);\nC_ASSERT(sizeof(KPH_HASH_EACACHE_SHA1)                < MAXUCHAR);\nC_ASSERT(sizeof(KPH_HASH_EACACHE_SHA1_AUTHENTICODE)   < MAXUCHAR);\nC_ASSERT(sizeof(KPH_HASH_EACACHE_SHA256)              < MAXUCHAR);\nC_ASSERT(sizeof(KPH_HASH_EACACHE_SHA256_AUTHENTICODE) < MAXUCHAR);\nC_ASSERT(sizeof(KPH_HASH_EACACHE_SHA384)              < MAXUCHAR);\nC_ASSERT(sizeof(KPH_HASH_EACACHE_SHA512)              < MAXUCHAR);\n\n#define KPH_HASH_EACACHE_LEN(x)                                                \\\n    ALIGN_UP_BY(FIELD_OFFSET(FILE_GET_EA_INFORMATION, EaName) +                \\\n                sizeof(x),                                                     \\\n                sizeof(ULONG))\n\n#define KPH_HASH_EACACHE_FULL_LEN(x)                                           \\\n    ALIGN_UP_BY(FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +               \\\n                sizeof(x) +                                                    \\\n                KPH_HASH_ALGORITHM_MAX_LENGTH,                                 \\\n                sizeof(ULONG))\n\n#define KPH_HASH_EACACHE_MAX_LENGTH (                                          \\\n    KPH_HASH_EACACHE_LEN(KPH_HASH_EACACHE_MD5) +                               \\\n    KPH_HASH_EACACHE_LEN(KPH_HASH_EACACHE_SHA1) +                              \\\n    KPH_HASH_EACACHE_LEN(KPH_HASH_EACACHE_SHA1_AUTHENTICODE) +                 \\\n    KPH_HASH_EACACHE_LEN(KPH_HASH_EACACHE_SHA256) +                            \\\n    KPH_HASH_EACACHE_LEN(KPH_HASH_EACACHE_SHA256_AUTHENTICODE) +               \\\n    KPH_HASH_EACACHE_LEN(KPH_HASH_EACACHE_SHA384) +                            \\\n    KPH_HASH_EACACHE_LEN(KPH_HASH_EACACHE_SHA512))\n\n#define KPH_HASH_EACACHE_FULL_MAX_LENGTH (                                     \\\n    KPH_HASH_EACACHE_FULL_LEN(KPH_HASH_EACACHE_MD5) +                          \\\n    KPH_HASH_EACACHE_FULL_LEN(KPH_HASH_EACACHE_SHA1) +                         \\\n    KPH_HASH_EACACHE_FULL_LEN(KPH_HASH_EACACHE_SHA1_AUTHENTICODE) +            \\\n    KPH_HASH_EACACHE_FULL_LEN(KPH_HASH_EACACHE_SHA256) +                       \\\n    KPH_HASH_EACACHE_FULL_LEN(KPH_HASH_EACACHE_SHA256_AUTHENTICODE) +          \\\n    KPH_HASH_EACACHE_FULL_LEN(KPH_HASH_EACACHE_SHA384) +                       \\\n    KPH_HASH_EACACHE_FULL_LEN(KPH_HASH_EACACHE_SHA512))\n\nC_ASSERT(KPH_HASH_EACACHE_FULL_MAX_LENGTH <= KPH_HASHING_BUFFER_SIZE);\n\ntypedef struct _KPH_HASHING_INFRASTRUCTURE\n{\n    PAGED_LOOKASIDE_LIST HashingLookaside;\n    BYTE EaList[KPH_HASH_EACACHE_MAX_LENGTH];\n} KPH_HASHING_INFRASTRUCTURE, *PKPH_HASHING_INFRASTRUCTURE;\n\ntypedef struct _KPH_HASHING_EACACHE_INFORMATION\n{\n    ULONG HashSize;\n    ANSI_STRING EaName;\n} KPH_HASHING_EACACHE_INFORMATION, *PKPH_HASHING_EACACHE_INFORMATION;\ntypedef const KPH_HASHING_EACACHE_INFORMATION *PCKPH_HASHING_EACACHE_INFORMATION;\n\ntypedef struct _KPH_HASHING_EACACHE_CONTEXT\n{\n    HANDLE FileHandle;\n    PFILE_OBJECT FileObject;\n    HANDLE OplockEventHandle;\n    PKEVENT OplockEventObject;\n    IO_STATUS_BLOCK IoStatusBlock;\n    REQUEST_OPLOCK_OUTPUT_BUFFER OplockOutput;\n} KPH_HASHING_EACACHE_CONTEXT, *PKPH_HASHING_EACACHE_CONTEXT;\n\ntypedef struct _KPH_HASHING_AUTHENTICODE_CONTEXT\n{\n    KPH_MEMORY_REGION Regions[4];\n    PVOID SecurityBase;\n    ULONG SecuritySize;\n} KPH_HASHING_AUTHENTICODE_CONTEXT, *PKPH_HASHING_AUTHENTICODE_CONTEXT;\n\ntypedef struct _KPH_HASHING_ENTRY\n{\n    BCRYPT_HASH_HANDLE Handle;\n    BOOLEAN HashComplete;\n    ULONG Length;\n    BYTE Hash[KPH_HASH_ALGORITHM_MAX_LENGTH];\n} KPH_HASHING_ENTRY, *PKPH_HASHING_ENTRY;\n\ntypedef struct _KPH_HASHING_CONTEXT\n{\n    KPH_HASHING_ENTRY Hash[MaxKphHashAlgorithm];\n    KPH_HASHING_AUTHENTICODE_CONTEXT Authenticode;\n    BOOLEAN RequiresHashing;\n    KPH_HASHING_EACACHE_CONTEXT EaCache;\n    BYTE Buffer[KPH_HASHING_BUFFER_SIZE];\n} KPH_HASHING_CONTEXT, *PKPH_HASHING_CONTEXT;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpHashingInfraName = RTL_CONSTANT_STRING(L\"KphHashingInfrastructure\");\nstatic const KPH_HASHING_EACACHE_INFORMATION KphpHashEaCacheInfo[] =\n{\n    { (128 / 8), RTL_CONSTANT_STRING(KPH_HASH_EACACHE_MD5) },\n    { (160 / 8), RTL_CONSTANT_STRING(KPH_HASH_EACACHE_SHA1) },\n    { (160 / 8), RTL_CONSTANT_STRING(KPH_HASH_EACACHE_SHA1_AUTHENTICODE) },\n    { (256 / 8), RTL_CONSTANT_STRING(KPH_HASH_EACACHE_SHA256) },\n    { (256 / 8), RTL_CONSTANT_STRING(KPH_HASH_EACACHE_SHA256_AUTHENTICODE) },\n    { (384 / 8), RTL_CONSTANT_STRING(KPH_HASH_EACACHE_SHA384) },\n    { (512 / 8), RTL_CONSTANT_STRING(KPH_HASH_EACACHE_SHA512) },\n};\nC_ASSERT(ARRAYSIZE(KphpHashEaCacheInfo) == MaxKphHashAlgorithm);\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_HASHING_INFRASTRUCTURE KphpHashingInfra = NULL;\nstatic PKPH_OBJECT_TYPE KphpHashingInfraType = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Allocates hashing infrastructure object.\n *\n * \\param[in] Size The size to allocate.\n *\n * \\return Allocated hashing infrastructure object, null on failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateHashingInfra(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_PAGED_CODE();\n\n    return KphAllocateNPaged(Size, KPH_TAG_HASHING_INFRA);\n}\n\n/**\n * \\brief Initializes hashing infrastructure.\n *\n * \\param[in,out] Object The hashing infrastructure to initialize.\n * \\param[in] Parameter Unused\n *\n * \\return Successful or errant status.\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitHashingInfra(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_HASHING_INFRASTRUCTURE infra;\n    PFILE_GET_EA_INFORMATION eaInfo;\n\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(Parameter);\n\n    infra = Object;\n\n    //\n    // Pre-populate the EA cache items into the buffer to be used when querying\n    // for the cached EA values. We compile time assert that it will all fit in\n    // the buffer.\n    //\n\n    eaInfo = (PFILE_GET_EA_INFORMATION)infra->EaList;\n    eaInfo->NextEntryOffset = 0;\n\n    for (ULONG i = 0; i < ARRAYSIZE(KphpHashEaCacheInfo); i++)\n    {\n        PCKPH_HASHING_EACACHE_INFORMATION eaCacheInfo;\n\n        eaInfo = Add2Ptr(eaInfo, eaInfo->NextEntryOffset);\n\n        eaCacheInfo = &KphpHashEaCacheInfo[i];\n\n        RtlCopyMemory(eaInfo->EaName,\n                      eaCacheInfo->EaName.Buffer,\n                      eaCacheInfo->EaName.Length);\n\n        eaInfo->EaNameLength = (UCHAR)eaCacheInfo->EaName.Length;\n        eaInfo->EaName[eaInfo->EaNameLength] = ANSI_NULL;\n\n        eaInfo->NextEntryOffset = FIELD_OFFSET(FILE_GET_EA_INFORMATION, EaName);\n        eaInfo->NextEntryOffset += eaCacheInfo->EaName.Length;\n        eaInfo->NextEntryOffset += sizeof(ANSI_NULL);\n        eaInfo->NextEntryOffset = ALIGN_UP_BY(eaInfo->NextEntryOffset,\n                                              sizeof(ULONG));\n    }\n\n    eaInfo->NextEntryOffset = 0;\n\n    KphInitializePagedLookaside(&infra->HashingLookaside,\n                                sizeof(KPH_HASHING_CONTEXT),\n                                KPH_TAG_HASHING_CONTEXT);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Deletes hashing infrastructure.\n *\n * \\param[in,out] Object The hashing infrastructure to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\nVOID KSIAPI KphpDeleteHashingInfra(\n    _Inout_ PVOID Object\n    )\n{\n    PKPH_HASHING_INFRASTRUCTURE infra;\n\n    KPH_PAGED_CODE();\n\n    infra = Object;\n\n    KphDeletePagedLookaside(&infra->HashingLookaside);\n}\n\n/**\n * \\brief Frees hashing infrastructure object.\n *\n * \\param[in] Object The object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\nVOID KSIAPI KphpFreeHashingInfra(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphFree(Object, KPH_TAG_HASHING_INFRA);\n}\n\n/**\n * \\brief Allocates a hashing context from the hashing look-aside list.\n *\n * \\return Hashing context, null on failure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Return_allocatesMem_\nPKPH_HASHING_CONTEXT KphpAllocateHashingContext(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KphpHashingInfra);\n\n    return KphAllocateFromPagedLookaside(&KphpHashingInfra->HashingLookaside);\n}\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpCloseHashingEaCacheContext(\n    _Inout_ PKPH_HASHING_EACACHE_CONTEXT Context\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (Context->FileObject)\n    {\n        ObDereferenceObject(Context->FileObject);\n        Context->FileObject = NULL;\n    }\n\n    if (Context->FileHandle)\n    {\n        NT_ASSERT(!KeAreAllApcsDisabled());\n\n        ObCloseHandle(Context->FileHandle, KernelMode);\n        Context->FileHandle = NULL;\n    }\n\n    if (Context->OplockEventObject)\n    {\n        KeWaitForSingleObject(Context->OplockEventObject,\n                              Executive,\n                              KernelMode,\n                              FALSE,\n                              NULL);\n\n        ObDereferenceObject(Context->OplockEventObject);\n        Context->OplockEventObject = NULL;\n    }\n\n    if (Context->OplockEventHandle)\n    {\n        ObCloseHandle(Context->OplockEventHandle, KernelMode);\n        Context->OplockEventHandle = NULL;\n    }\n}\n\n/**\n * \\brief Frees a hashing context back to the look-aside list.\n *\n * \\param[in] Buffer The context to free back to the look-aside list.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpFreeHashingContext(\n    _In_freesMem_ PKPH_HASHING_CONTEXT Context\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KphpHashingInfra);\n\n    for (ULONG i = 0; i < ARRAYSIZE(Context->Hash); i++)\n    {\n        if (Context->Hash[i].Handle)\n        {\n            BCryptDestroyHash(Context->Hash[i].Handle);\n        }\n    }\n\n    KphpCloseHashingEaCacheContext(&Context->EaCache);\n\n    KphFreeToPagedLookaside(&KphpHashingInfra->HashingLookaside, Context);\n}\n\n/**\n * \\brief Initializes hashing infrastructure.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphInitializeHashing(\n    VOID\n    )\n{\n    NTSTATUS status;\n    KPH_OBJECT_TYPE_INFO typeInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    typeInfo.Allocate = KphpAllocateHashingInfra;\n    typeInfo.Initialize = KphpInitHashingInfra;\n    typeInfo.Delete = KphpDeleteHashingInfra;\n    typeInfo.Free = KphpFreeHashingInfra;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpHashingInfraName,\n                        &typeInfo,\n                        &KphpHashingInfraType);\n\n    status = KphCreateObject(KphpHashingInfraType,\n                             sizeof(KPH_HASHING_INFRASTRUCTURE),\n                             &KphpHashingInfra,\n                             NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphpHashingInfra = NULL;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Cleans up hashing infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupHashing(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (KphpHashingInfra)\n    {\n        KphDereferenceObject(KphpHashingInfra);\n    }\n}\n\n/**\n * \\brief References the signing infrastructure.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphReferenceHashingInfrastructure(\n    VOID\n    )\n{\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(KphpHashingInfra);\n\n    KphReferenceObject(KphpHashingInfra);\n}\n\n/**\n * \\brief Dereferences the signing infrastructure.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphDereferenceHashingInfrastructure(\n    VOID\n    )\n{\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(KphpHashingInfra);\n\n    KphDereferenceObject(KphpHashingInfra);\n}\n\n/**\n * \\brief Hashes a buffer.\n *\n * \\param[in] Buffer The buffer to hash.\n * \\param[in] BufferLength The length of the buffer.\n * \\param[in] HashAlgorithm The algorithm to use for hashing.\n * \\param[out] HashInformation Populated with the hash information.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphHashBuffer(\n    _In_ PBYTE Buffer,\n    _In_ ULONG BufferLength,\n    _In_ KPH_HASH_ALGORITHM HashAlgorithm,\n    _Out_ PKPH_HASH_INFORMATION HashInformation\n    )\n{\n    NTSTATUS status;\n    BCRYPT_ALG_HANDLE algHandle;\n    BCRYPT_HASH_HANDLE hashHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KphpHashingInfra);\n\n    hashHandle = NULL;\n\n    RtlZeroMemory(HashInformation, sizeof(*HashInformation));\n\n    HashInformation->Algorithm = HashAlgorithm;\n\n    switch (HashAlgorithm)\n    {\n        case KphHashAlgorithmMd5:\n        {\n            HashInformation->Length = (128 / 8);\n            algHandle = BCRYPT_MD5_ALG_HANDLE;\n            break;\n        }\n        case KphHashAlgorithmSha1:\n        {\n            HashInformation->Length = (160 / 8);\n            algHandle = BCRYPT_SHA1_ALG_HANDLE;\n            break;\n        }\n        case KphHashAlgorithmSha256:\n        {\n            HashInformation->Length = (256 / 8);\n            algHandle = BCRYPT_SHA256_ALG_HANDLE;\n            break;\n        }\n        case KphHashAlgorithmSha384:\n        {\n            HashInformation->Length = (384 / 8);\n            algHandle = BCRYPT_SHA384_ALG_HANDLE;\n            break;\n        }\n        case KphHashAlgorithmSha512:\n        {\n            HashInformation->Length = (512 / 8);\n            algHandle = BCRYPT_SHA512_ALG_HANDLE;\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_PARAMETER;\n            goto Exit;\n        }\n    }\n\n    status = BCryptCreateHash(algHandle, &hashHandle, NULL, 0, NULL, 0, 0);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"BCryptCreateHash failed: %!STATUS!\",\n                      status);\n\n        hashHandle = NULL;\n        goto Exit;\n    }\n\n    status = BCryptHashData(hashHandle, Buffer, BufferLength, 0);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"BCryptHashData failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = BCryptFinishHash(hashHandle,\n                              HashInformation->Hash,\n                              HashInformation->Length,\n                              0);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"BCryptFinishHash failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\nExit:\n\n    if (hashHandle)\n    {\n        BCryptDestroyHash(hashHandle);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Updates a hash with a buffer from the context.\n *\n * \\details The internal context buffer must already be updated with a copy of\n * data pointed to by UnsafeBuffer.\n *\n * \\param[in,out] Entry The hash entry to update.\n * \\param[in] Context The hashing context.\n * \\param[in] Authenticode Whether the hash is for authenticode or not.\n * \\param[in] UnsafeBuffer Address from which the information was copied.\n * \\param[in] Length The length of the buffer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpUpdateHash(\n    _Inout_ PKPH_HASHING_ENTRY Entry,\n    _In_ PKPH_HASHING_CONTEXT Context,\n    _In_ BOOLEAN Authenticode,\n    _In_ PVOID UnsafeBuffer,\n    _In_ ULONG Length\n    )\n{\n    PVOID unsafeEnd;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(Entry->Handle && !Entry->HashComplete);\n\n    if (!Authenticode)\n    {\n        return BCryptHashData(Entry->Handle, Context->Buffer, Length, 0);\n    }\n\n    //\n    // Only hash within a region relevant for authenticode hashing.\n    //\n\n    unsafeEnd = Add2Ptr(UnsafeBuffer, Length);\n\n    for (ULONG i = 0; i < ARRAYSIZE(Context->Authenticode.Regions); i++)\n    {\n        NTSTATUS status;\n        PKPH_MEMORY_REGION region;\n        PVOID start;\n        PVOID end;\n        PVOID buffer;\n        ULONG length;\n\n        region = &Context->Authenticode.Regions[i];\n\n        if (!region->Start)\n        {\n            break;\n        }\n\n        if ((UnsafeBuffer >= region->Start) && (UnsafeBuffer < region->End))\n        {\n            start = UnsafeBuffer;\n        }\n        else if ((region->Start >= UnsafeBuffer) && (region->Start < unsafeEnd))\n        {\n            start = region->Start;\n        }\n        else\n        {\n            start = NULL;\n        }\n\n        if ((unsafeEnd >= region->Start) && (unsafeEnd < region->End))\n        {\n            end = unsafeEnd;\n        }\n        else if ((region->End >= UnsafeBuffer) && (region->End < unsafeEnd))\n        {\n            end = region->End;\n        }\n        else\n        {\n            end = NULL;\n        }\n\n        if (start && end)\n        {\n            NOTHING;\n        }\n        else if (start && !end)\n        {\n            end = unsafeEnd;\n        }\n        else if (!start && end)\n        {\n            start = UnsafeBuffer;\n        }\n        else\n        {\n            continue;\n        }\n\n        NT_ASSERT(start <= end);\n\n        buffer = Add2Ptr(Context->Buffer, PtrOffset(UnsafeBuffer, start));\n        length = PtrOffset(start, end);\n\n        status = BCryptHashData(Entry->Handle, buffer, length, 0);\n        if (!NT_SUCCESS(status))\n        {\n            return status;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Updates all hashes in the context with the context buffer.\n *\n * \\details The internal context buffer must already be updated with a copy of\n * data pointed to by UnsafeBuffer.\n *\n * \\param[in,out] Context The hashing context.\n * \\param[in] UnsafeBuffer Address from which the information was copied.\n * \\param[in] Length The length of the buffer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpUpdateHashes(\n    _Inout_ PKPH_HASHING_CONTEXT Context,\n    _In_ PVOID UnsafeBuffer,\n    _In_ ULONG Length\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    for (ULONG i = 0; i < ARRAYSIZE(Context->Hash); i++)\n    {\n        NTSTATUS status;\n        PKPH_HASHING_ENTRY entry;\n        BOOLEAN authenticode;\n\n        entry = &Context->Hash[i];\n\n        if (entry->HashComplete || !entry->Handle)\n        {\n            continue;\n        }\n\n        authenticode = ((i == KphHashAlgorithmSha1Authenticode) ||\n                        (i == KphHashAlgorithmSha256Authenticode));\n\n        status = KphpUpdateHash(entry,\n                                Context,\n                                authenticode,\n                                UnsafeBuffer,\n                                Length);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          HASH,\n                          \"KphpUpdateHash failed: %!STATUS!\",\n                          status);\n\n            return status;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Initializes a hashing context.\n *\n * \\param[in,out] Context The hashing context to initialize.\n * \\param[in] HashInformation The hash information to use for initialization.\n * \\param[in] NumberOfHashes The number of hashing information items.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpInitializeHashingContext(\n    _Inout_ PKPH_HASHING_CONTEXT Context,\n    _In_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG NumberOfHashes\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = STATUS_SUCCESS;\n\n    for (ULONG i = 0; i < NumberOfHashes; i++)\n    {\n        PKPH_HASHING_ENTRY entry;\n        BCRYPT_ALG_HANDLE algHandle;\n\n        if ((HashInformation[i].Algorithm >= MaxKphHashAlgorithm) ||\n            (HashInformation[i].Algorithm < 0))\n        {\n            status = STATUS_INVALID_PARAMETER;\n            goto Exit;\n        }\n\n        entry = &Context->Hash[HashInformation[i].Algorithm];\n\n        if (entry->HashComplete || entry->Handle)\n        {\n            continue;\n        }\n\n        Context->RequiresHashing = TRUE;\n\n        switch (HashInformation[i].Algorithm)\n        {\n            case KphHashAlgorithmMd5:\n            {\n                entry->Length = (128 / 8);\n                algHandle = BCRYPT_MD5_ALG_HANDLE;\n                break;\n            }\n            case KphHashAlgorithmSha1:\n            case KphHashAlgorithmSha1Authenticode:\n            {\n                entry->Length = (160 / 8);\n                algHandle = BCRYPT_SHA1_ALG_HANDLE;\n                break;\n            }\n            case KphHashAlgorithmSha256:\n            case KphHashAlgorithmSha256Authenticode:\n            {\n                entry->Length = (256 / 8);\n                algHandle = BCRYPT_SHA256_ALG_HANDLE;\n                break;\n            }\n            case KphHashAlgorithmSha384:\n            {\n                entry->Length = (384 / 8);\n                algHandle = BCRYPT_SHA384_ALG_HANDLE;\n                break;\n            }\n            case KphHashAlgorithmSha512:\n            {\n                entry->Length = (512 / 8);\n                algHandle = BCRYPT_SHA512_ALG_HANDLE;\n                break;\n            }\n            DEFAULT_UNREACHABLE;\n        }\n\n        NT_ASSERT(entry->Length <= sizeof(Context->Hash));\n\n        status = BCryptCreateHash(algHandle,\n                                  &entry->Handle,\n                                  NULL,\n                                  0,\n                                  NULL,\n                                  0,\n                                  0);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          HASH,\n                          \"BCryptCreateHash failed: %!STATUS!\",\n                          status);\n\n            entry->Handle = NULL;\n            goto Exit;\n        }\n    }\n\nExit:\n\n    return status;\n}\n\n/**\n * \\brief Loads hashes from the EA cache into the hashing context.\n *\n * \\param[in,out] Context The hashing context to load the hashes into.\n * \\param[in] FileHandle The file handle to load the hashes from.\n * \\param[in] AccessMode The mode in which to perform access checks.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpLoadHashesFromEaCache(\n    _Inout_ PKPH_HASHING_CONTEXT Context,\n    _In_ HANDLE FileHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PFILE_OBJECT fileObject;\n    ULONG returnLength;\n    PFILE_FULL_EA_INFORMATION fullEaInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = ObReferenceObjectByHandle(FileHandle,\n                                       0,\n                                       *IoFileObjectType,\n                                       AccessMode,\n                                       &fileObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        return;\n    }\n\n    //\n    // N.B. We compile time assert that all the information we might store in\n    // our extended attributes will fit within the supplied buffer.\n    //\n\n    status = FsRtlQueryKernelEaFile(fileObject,\n                                    Context->Buffer,\n                                    sizeof(Context->Buffer),\n                                    FALSE,\n                                    KphpHashingInfra->EaList,\n                                    sizeof(KphpHashingInfra->EaList),\n                                    NULL,\n                                    TRUE,\n                                    &returnLength);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"FsRtlQueryKernelEaFile failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    fullEaInfo = (PFILE_FULL_EA_INFORMATION)Context->Buffer;\n\n    for (;;)\n    {\n        ANSI_STRING eaName;\n\n        eaName.Buffer = fullEaInfo->EaName;\n        eaName.Length = fullEaInfo->EaNameLength;\n        eaName.MaximumLength = fullEaInfo->EaNameLength;\n\n        for (ULONG i = 0; i < ARRAYSIZE(KphpHashEaCacheInfo); i++)\n        {\n            PCKPH_HASHING_EACACHE_INFORMATION eaCacheInfo;\n            PKPH_HASHING_ENTRY entry;\n            PVOID buffer;\n\n            eaCacheInfo = &KphpHashEaCacheInfo[i];\n\n            //\n            // None of our EA names will reach this limit. We compile time\n            // assert this and runtime assert here for clarity. This is\n            // necessary when advancing the buffer pointer below.\n            //\n            NT_ASSERT(eaCacheInfo->EaName.Length < MAXUCHAR);\n\n            if (fullEaInfo->EaValueLength != eaCacheInfo->HashSize)\n            {\n                continue;\n            }\n\n            if (!RtlEqualString(&eaName, &eaCacheInfo->EaName, FALSE))\n            {\n                continue;\n            }\n\n            entry = &Context->Hash[i];\n\n            buffer = Add2Ptr(fullEaInfo->EaName,\n                             fullEaInfo->EaNameLength + sizeof(ANSI_NULL));\n\n            RtlCopyMemory(entry->Hash, buffer, fullEaInfo->EaValueLength);\n\n            entry->Length = fullEaInfo->EaValueLength;\n            entry->HashComplete = TRUE;\n\n            break;\n        }\n\n        if (!fullEaInfo->NextEntryOffset)\n        {\n            break;\n        }\n\n        fullEaInfo = Add2Ptr(fullEaInfo, fullEaInfo->NextEntryOffset);\n    }\n\nExit:\n\n    ObDereferenceObject(fileObject);\n}\n\n/**\n * \\brief Initializes the EA cache context for hashing.\n *\n * \\details The EA caching is completely opportunistic and will only be used if\n * we can guarantee cache consistency. We do this using an opportunistic lock.\n * The caller should call KphpProgressEaCacheContext to after each read from\n * the file data to determine if there is another contender for writing to the\n * file. If contention is detected, the EA cache will be closed and the cache\n * will not be updated. This avoids contention on the system and ensures cache\n * consistency.\n *\n * \\param[in,out] Context The hashing context to initialize.\n * \\param[in] FileHandle The file handle to initialize the context with.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpInitializeEaCacheContext(\n    _Inout_ PKPH_HASHING_CONTEXT Context,\n    _In_ HANDLE FileHandle\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n    REQUEST_OPLOCK_INPUT_BUFFER oplockInput;\n    ULONG64 usnValue;\n    ULONG returnLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlInitUnicodeString(&objectName, NULL);\n\n    InitializeObjectAttributes(&objectAttributes,\n                               &objectName,\n                               OBJ_KERNEL_HANDLE,\n                               FileHandle,\n                               NULL);\n\n    status = KphCreateFile(&Context->EaCache.FileHandle,\n                           FILE_WRITE_EA | FILE_READ_DATA | FILE_READ_ATTRIBUTES,\n                           &objectAttributes,\n                           &ioStatusBlock,\n                           NULL,\n                           FILE_ATTRIBUTE_NORMAL,\n                           FILE_SHARE_READ,\n                           FILE_OPEN,\n                           FILE_NON_DIRECTORY_FILE | FILE_OPEN_REQUIRING_OPLOCK,\n                           NULL,\n                           0,\n                           0,\n                           KernelMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"KphCreateFile failed: %!STATUS!\",\n                      status);\n\n        Context->EaCache.FileHandle = NULL;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(Context->EaCache.FileHandle,\n                                       FILE_ALL_ACCESS,\n                                       *IoFileObjectType,\n                                       KernelMode,\n                                       &Context->EaCache.FileObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        Context->EaCache.FileObject = NULL;\n        goto Exit;\n    }\n\n    status = ZwCreateEvent(&Context->EaCache.OplockEventHandle,\n                           EVENT_ALL_ACCESS,\n                           NULL,\n                           NotificationEvent,\n                           TRUE);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"ZwCreateEvent failed: %!STATUS!\",\n                      status);\n\n        Context->EaCache.OplockEventHandle = NULL;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(Context->EaCache.OplockEventHandle,\n                                       EVENT_ALL_ACCESS,\n                                       *ExEventObjectType,\n                                       KernelMode,\n                                       &Context->EaCache.OplockEventObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        Context->EaCache.OplockEventObject = NULL;\n        goto Exit;\n    }\n\n    oplockInput.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION;\n    oplockInput.StructureLength = sizeof(REQUEST_OPLOCK_INPUT_BUFFER);\n    oplockInput.Flags = REQUEST_OPLOCK_INPUT_FLAG_REQUEST;\n    oplockInput.RequestedOplockLevel = (OPLOCK_LEVEL_CACHE_READ |\n                                        OPLOCK_LEVEL_CACHE_HANDLE);\n\n    KeResetEvent(Context->EaCache.OplockEventObject);\n\n    status = ZwFsControlFile(Context->EaCache.FileHandle,\n                             Context->EaCache.OplockEventHandle,\n                             NULL,\n                             NULL,\n                             &Context->EaCache.IoStatusBlock,\n                             FSCTL_REQUEST_OPLOCK,\n                             &oplockInput,\n                             sizeof(REQUEST_OPLOCK_INPUT_BUFFER),\n                             &Context->EaCache.OplockOutput,\n                             sizeof(Context->EaCache.OplockOutput));\n    if (status != STATUS_PENDING)\n    {\n        KeSetEvent(Context->EaCache.OplockEventObject, IO_NO_INCREMENT, FALSE);\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"ZwFsControlFile returned: %!STATUS!\",\n                      status);\n\n        if (NT_SUCCESS(status))\n        {\n            status = STATUS_UNEXPECTED_IO_ERROR;\n        }\n\n        goto Exit;\n    }\n\n    status = FsRtlKernelFsControlFile(Context->EaCache.FileObject,\n                                      FSCTL_WRITE_USN_CLOSE_RECORD,\n                                      NULL,\n                                      0,\n                                      &usnValue,\n                                      sizeof(ULONG64),\n                                      &returnLength);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"FsRtlKernelFsControlFile failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\nExit:\n\n    if (!NT_SUCCESS(status))\n    {\n        KphpCloseHashingEaCacheContext(&Context->EaCache);\n    }\n}\n\n/**\n * \\brief Progresses the EA cache context.\n *\n * \\details This function should be called after each read from the file data.\n *\n * \\param[in,out] Context The hashing context to progress the EA cache of.\n *\n * \\return TRUE if the EA cache is available and the opportunistic lock has not\n * been broken, FALSE otherwise.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nBOOLEAN KphpProgressEaCacheContext(\n    _Inout_ PKPH_HASHING_CONTEXT Context\n    )\n{\n    LARGE_INTEGER zeroTimeout = KPH_TIMEOUT(0);\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!Context->EaCache.OplockEventObject)\n    {\n        return FALSE;\n    }\n\n    if (KeWaitForSingleObject(Context->EaCache.OplockEventObject,\n                              Executive,\n                              KernelMode,\n                              FALSE,\n                              &zeroTimeout) != STATUS_SUCCESS)\n    {\n        return TRUE;\n    }\n\n    //\n    // The opportunistic lock has been broken. We could try to guarantee cache\n    // consistency by not closing the handle. Doing so would block the thread\n    // attempting to open a write handle until we acknowledge the break.\n    //\n    // An opportunistic lock break can also happen when a write occurs to the\n    // file, but this will not suspend the write operation for acknowledgment.\n    // Therefore, acknowledging the break here is important to avoid the\n    // possible cache inconsistency.\n    //\n    // We choose to completely get out of the way of the system and acknowledge\n    // the break of the opportunistic lock by closing the handle. We will\n    // continue to hash and return whatever that result is, but we will not\n    // update the EA cache since we can not guarantee cash consistency.\n    //\n    // N.B. It is important to close the handle instead of using the lock break\n    // acknowledgment control code, otherwise we could be the cause of a\n    // sharing violation.\n    //\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE, HASH, \"Opportunistic lock broken\");\n\n    KphpCloseHashingEaCacheContext(&Context->EaCache);\n\n    return FALSE;\n}\n\n/**\n * \\brief Initializes the hashing context for file hashing.\n *\n * \\param[in,out] Context The hashing context to initialize.\n * \\param[in] FileHandle The file handle to initialize the context with.\n * \\param[in] HashInformation The hash information to use for initialization.\n * \\param[in] NumberOfHashes The number of hashing information items.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpInitializeFileHashingContext(\n    _Inout_ PKPH_HASHING_CONTEXT Context,\n    _In_ HANDLE FileHandle,\n    _In_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG NumberOfHashes,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphpLoadHashesFromEaCache(Context, FileHandle, AccessMode);\n\n    status = KphpInitializeHashingContext(Context,\n                                          HashInformation,\n                                          NumberOfHashes);\n    if (NT_SUCCESS(status) && Context->RequiresHashing)\n    {\n        KphpInitializeEaCacheContext(Context, FileHandle);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Initializes the hashing context for authenticode hashing.\n *\n * \\details This function can raise a structured exception due to an in-page\n * error, which callers should be prepared to handle.\n *\n * \\param[in,out] Context The hashing context to initialize.\n * \\param[in] MappedBase The base address of the mapped image.\n * \\param[in] ViewSize The size of the mapped image.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphpInitializeAuthenticodeHashing(\n    _Inout_ PKPH_HASHING_CONTEXT Context,\n    _In_ PVOID MappedBase,\n    _In_ SIZE_T ViewSize\n    )\n{\n    NTSTATUS status;\n    PVOID mappedEnd;\n    KPH_IMAGE_NT_HEADERS image;\n    PIMAGE_DATA_DIRECTORY securityDir;\n    PVOID securityBase;\n    ULONG securitySize;\n    PVOID securityEnd;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlZeroMemory(&Context->Authenticode, sizeof(Context->Authenticode));\n\n    mappedEnd = Add2Ptr(MappedBase, ViewSize);\n    securityDir = NULL;\n    securityBase = NULL;\n    securityEnd = NULL;\n\n    NT_ASSERT(MappedBase <= mappedEnd);\n\n    status = KphImageNtHeader(MappedBase, ViewSize, &image);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    if (!RTL_CONTAINS_FIELD(&image.Headers->OptionalHeader,\n                            image.Headers->FileHeader.SizeOfOptionalHeader,\n                            Magic))\n    {\n        Context->Authenticode.Regions[0].Start = MappedBase;\n        Context->Authenticode.Regions[0].End = mappedEnd;\n        status = STATUS_SUCCESS;\n        goto VerifyRegions;\n    }\n\n    if (image.Headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        if (!RTL_CONTAINS_FIELD(&image.Headers32->OptionalHeader,\n                                image.Headers->FileHeader.SizeOfOptionalHeader,\n                                CheckSum))\n        {\n            Context->Authenticode.Regions[0].Start = MappedBase;\n            Context->Authenticode.Regions[0].End = mappedEnd;\n            status = STATUS_SUCCESS;\n            goto VerifyRegions;\n        }\n\n        Context->Authenticode.Regions[0].Start = MappedBase;\n        Context->Authenticode.Regions[0].End = &image.Headers32->OptionalHeader.CheckSum;\n\n        Context->Authenticode.Regions[1].Start = &image.Headers32->OptionalHeader.Subsystem;\n        if (!RTL_CONTAINS_FIELD(&image.Headers32->OptionalHeader,\n                                image.Headers->FileHeader.SizeOfOptionalHeader,\n                                NumberOfRvaAndSizes) ||\n            (image.Headers32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_SECURITY))\n        {\n            Context->Authenticode.Regions[1].End = mappedEnd;\n            status = STATUS_SUCCESS;\n            goto VerifyRegions;\n        }\n\n        securityDir = &image.Headers32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];\n        Context->Authenticode.Regions[1].End = securityDir;\n    }\n    else if (image.Headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        if (!RTL_CONTAINS_FIELD(&image.Headers64->OptionalHeader,\n                                image.Headers->FileHeader.SizeOfOptionalHeader,\n                                CheckSum))\n        {\n            Context->Authenticode.Regions[0].Start = MappedBase;\n            Context->Authenticode.Regions[0].End = mappedEnd;\n            status = STATUS_SUCCESS;\n            goto VerifyRegions;\n        }\n\n        Context->Authenticode.Regions[0].Start = MappedBase;\n        Context->Authenticode.Regions[0].End = &image.Headers64->OptionalHeader.CheckSum;\n\n        Context->Authenticode.Regions[1].Start = &image.Headers64->OptionalHeader.Subsystem;\n        if (!RTL_CONTAINS_FIELD(&image.Headers64->OptionalHeader,\n                                image.Headers->FileHeader.SizeOfOptionalHeader,\n                                NumberOfRvaAndSizes) ||\n            (image.Headers64->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_SECURITY))\n        {\n            Context->Authenticode.Regions[1].End = mappedEnd;\n            status = STATUS_SUCCESS;\n            goto VerifyRegions;\n        }\n\n        securityDir = &image.Headers64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];\n        Context->Authenticode.Regions[1].End = securityDir;\n    }\n    else\n    {\n        status = STATUS_INVALID_IMAGE_FORMAT;\n        goto Exit;\n    }\n\n    NT_ASSERT(securityDir);\n\n    Context->Authenticode.Regions[2].Start = &securityDir[1];\n\n    if (!securityDir->VirtualAddress || !securityDir->Size)\n    {\n        Context->Authenticode.Regions[2].End = mappedEnd;\n        status = STATUS_SUCCESS;\n        goto VerifyRegions;\n    }\n\n    securityBase = Add2Ptr(MappedBase, securityDir->VirtualAddress);\n    securitySize = securityDir->Size;\n    securityEnd = Add2Ptr(securityBase, securitySize);\n\n    Context->Authenticode.SecurityBase = securityBase;\n    Context->Authenticode.SecuritySize = securitySize;\n\n    Context->Authenticode.Regions[2].End = securityBase;\n\n    if (securityEnd < mappedEnd)\n    {\n        Context->Authenticode.Regions[3].Start = securityEnd;\n        Context->Authenticode.Regions[3].End = mappedEnd;\n    }\n\nVerifyRegions:\n\n    for (ULONG i = 0; i < ARRAYSIZE(Context->Authenticode.Regions); i++)\n    {\n        PKPH_MEMORY_REGION region;\n\n        region = &Context->Authenticode.Regions[i];\n\n        if (!region->Start)\n        {\n            break;\n        }\n\n        if (!KphIsValidMemoryRegion(region, MappedBase, mappedEnd))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          HASH,\n                          \"Authenticode region overflows mapping.\");\n\n            status = STATUS_BUFFER_OVERFLOW;\n            goto Exit;\n        }\n    }\n\n    if (securityBase)\n    {\n        KPH_MEMORY_REGION securityRegion;\n\n        securityRegion.Start = securityBase;\n        securityRegion.End = securityEnd;\n\n        if (!KphIsValidMemoryRegion(&securityRegion, MappedBase, mappedEnd))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          HASH,\n                          \"Security directory overflows mapping.\");\n\n            status = STATUS_BUFFER_OVERFLOW;\n            goto Exit;\n        }\n    }\n\nExit:\n\n    if (!NT_SUCCESS(status))\n    {\n        RtlZeroMemory(&Context->Authenticode, sizeof(Context->Authenticode));\n    }\n\n    return status;\n}\n\n/**\n * \\brief Finishes hashes in the hashing context.\n *\n * \\param[in,out] Context The hashing context to finish the hashes in.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFinishHashes(\n    _In_ PKPH_HASHING_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    PFILE_FULL_EA_INFORMATION fullEaInfo;\n    ULONG fullEaInfoLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    fullEaInfoLength = 0;\n\n    if (Context->EaCache.FileObject)\n    {\n        fullEaInfo = (PFILE_FULL_EA_INFORMATION)Context->Buffer;\n        fullEaInfo->NextEntryOffset = 0;\n    }\n    else\n    {\n        fullEaInfo = NULL;\n    }\n\n    for (ULONG i = 0; i < ARRAYSIZE(Context->Hash); i++)\n    {\n        PKPH_HASHING_ENTRY entry;\n        PCKPH_HASHING_EACACHE_INFORMATION eaInfo;\n        PVOID buffer;\n\n        entry = &Context->Hash[i];\n\n        if (!entry->Handle)\n        {\n            continue;\n        }\n\n        status = BCryptFinishHash(entry->Handle,\n                                  entry->Hash,\n                                  entry->Length,\n                                  0);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          HASH,\n                          \"BCryptFinishHash failed: %!STATUS!\",\n                          status);\n\n            return status;\n        }\n\n        entry->HashComplete = TRUE;\n\n        if (!fullEaInfo)\n        {\n            continue;\n        }\n\n        fullEaInfo = Add2Ptr(fullEaInfo, fullEaInfo->NextEntryOffset);\n\n        eaInfo = &KphpHashEaCacheInfo[i];\n\n        fullEaInfo->Flags = 0;\n        fullEaInfo->EaNameLength = (UCHAR)eaInfo->EaName.Length;\n        fullEaInfo->EaValueLength = (USHORT)entry->Length;\n\n        RtlCopyMemory(fullEaInfo->EaName,\n                      eaInfo->EaName.Buffer,\n                      eaInfo->EaName.Length);\n\n        fullEaInfo->EaName[eaInfo->EaName.Length] = ANSI_NULL;\n\n        buffer = Add2Ptr(fullEaInfo->EaName,\n                         fullEaInfo->EaNameLength + sizeof(ANSI_NULL));\n\n        RtlCopyMemory(buffer, entry->Hash, entry->Length);\n\n        buffer = Add2Ptr(buffer, entry->Length);\n\n        fullEaInfo->NextEntryOffset = ALIGN_UP_BY(PtrOffset(fullEaInfo, buffer),\n                                                  sizeof(ULONG));\n\n        fullEaInfoLength += fullEaInfo->NextEntryOffset;\n    }\n\n    if (fullEaInfoLength && KphpProgressEaCacheContext(Context))\n    {\n        NT_ASSERT(Context->EaCache.FileObject);\n        NT_ASSERT(fullEaInfo);\n\n        fullEaInfo->NextEntryOffset = 0;\n\n        status = FsRtlSetKernelEaFile(Context->EaCache.FileObject,\n                                      Context->Buffer,\n                                      fullEaInfoLength);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          HASH,\n                          \"FsRtlSetKernelEaFile failed: %!STATUS!\",\n                          status);\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Copies hashes from the hashing context to the hash information.\n *\n * \\param[in] Context The hashing context to copy the hashes from.\n * \\param[in,out] HashInformation The hash information to copy the hashes to.\n * \\param[in] NumberOfHashes The number of hashing information items.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpCopyHashes(\n    _In_ PKPH_HASHING_CONTEXT Context,\n    _Inout_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG NumberOfHashes\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    for (ULONG i = 0; i < NumberOfHashes; i++)\n    {\n        PKPH_HASHING_ENTRY entry;\n        PKPH_HASH_INFORMATION info;\n\n        info = &HashInformation[i];\n\n        NT_ASSERT((info->Algorithm < MaxKphHashAlgorithm) &&\n                  (info->Algorithm >= 0));\n\n        entry = &Context->Hash[info->Algorithm];\n\n        NT_ASSERT(entry->HashComplete);\n\n        info->Length = entry->Length;\n\n        RtlCopyMemory(info->Hash, entry->Hash, entry->Length);\n    }\n}\n\n/**\n * \\brief Hashes a file.\n *\n * \\param[in] FileHandle Handle to a file to hash.\n * \\param[in,out] HashInformation The hash information to populate with the\n * requested hash algorithms. On input this array contains the requested hash\n * algorithms to use, and on output the hash information items are populated\n * with the requested hash values.\n * \\param[in] NumberOfHashes The number of hash information items.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpHashFile(\n    _In_ HANDLE FileHandle,\n    _Inout_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG NumberOfHashes,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_HASHING_CONTEXT context;\n    PVOID mappedBase;\n    SIZE_T viewSize;\n    ULONG readSize;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    mappedBase = NULL;\n\n    context = KphpAllocateHashingContext();\n    if (!context)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphpInitializeFileHashingContext(context,\n                                              FileHandle,\n                                              HashInformation,\n                                              NumberOfHashes,\n                                              AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"KphpInitializeFileHashingContext failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (!context->RequiresHashing)\n    {\n        goto Finish;\n    }\n\n    viewSize = 0;\n\n    status = KphMapViewInSystem(FileHandle,\n                                KPH_MAP_DATA,\n                                &mappedBase,\n                                &viewSize);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"KphMapViewInSystem failed: %!STATUS!\",\n                      status);\n\n        mappedBase = NULL;\n        goto Exit;\n    }\n\n    if (context->Hash[KphHashAlgorithmSha1Authenticode].Handle ||\n        context->Hash[KphHashAlgorithmSha256Authenticode].Handle)\n    {\n        __try\n        {\n            KphpInitializeAuthenticodeHashing(context, mappedBase, viewSize);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n    }\n\n    readSize = 0;\n\n    for (SIZE_T offset = 0; offset < viewSize; offset += readSize)\n    {\n        PVOID buffer;\n\n        buffer = &((PBYTE)mappedBase)[offset];\n        readSize = (ULONG)min(viewSize - offset, sizeof(context->Buffer));\n\n        __try\n        {\n            RtlCopyMemory(context->Buffer, buffer, readSize);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n\n        KphpProgressEaCacheContext(context);\n\n        status = KphpUpdateHashes(context, buffer, readSize);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          HASH,\n                          \"KphpUpdateHashes failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    status = KphpFinishHashes(context);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"KphpFinishHashes failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\nFinish:\n\n    KphpCopyHashes(context, HashInformation, NumberOfHashes);\n\nExit:\n\n    if (mappedBase)\n    {\n        KphUnmapViewInSystem(mappedBase);\n    }\n\n    if (context)\n    {\n        KphpFreeHashingContext(context);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries hash information for a file.\n *\n * \\param[in] FileHandle Handle to a file to query.\n * \\param[in,out] HashInformation The hash information to populate with the\n * requested hash algorithms. On input this array contains the requested hash\n * algorithms to use, and on output the hash information items are populated\n * with the requested hash values.\n * \\param[in] HashInformationLength The length of the hash information in bytes.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryHashInformationFile(\n    _In_ HANDLE FileHandle,\n    _Inout_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG HashInformationLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_HASH_INFORMATION hashInfo;\n    ULONG numberOfHashes;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    hashInfo = NULL;\n    numberOfHashes = HashInformationLength / sizeof(KPH_HASH_INFORMATION);\n\n    if (!HashInformation || !numberOfHashes)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    if (AccessMode != KernelMode)\n    {\n        hashInfo = KphAllocatePaged(HashInformationLength,\n                                    KPH_TAG_CAPTURED_HASHES);\n        if (!hashInfo)\n        {\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        __try\n        {\n            CopyFromUser(hashInfo, HashInformation, HashInformationLength);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n    }\n    else\n    {\n        hashInfo = HashInformation;\n    }\n\n    status = KphpHashFile(FileHandle, hashInfo, numberOfHashes, AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"KphpHashFile failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (AccessMode != KernelMode)\n    {\n        __try\n        {\n            CopyToUser(HashInformation, hashInfo, HashInformationLength);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n    }\n\nExit:\n\n    if (hashInfo && (hashInfo != HashInformation))\n    {\n        KphFree(hashInfo, KPH_TAG_CAPTURED_HASHES);\n    }\n\n    return status;\n}\n\n\n/**\n * \\brief Queries hash information for a file object.\n *\n * \\param[in] FileObject The file to query.\n * \\param[in,out] HashInformation The hash information to populate with the\n * requested hash algorithms. On input this array contains the requested hash\n * algorithms to use, and on output the hash information items are populated\n * with the requested hash values.\n * \\param[in] HashInformationLength The length of the hash information in bytes.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryHashInformationFileObject(\n    _In_ PFILE_OBJECT FileObject,\n    _Inout_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG HashInformationLength\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = ObOpenObjectByPointer(FileObject,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   0,\n                                   *IoFileObjectType,\n                                   KernelMode,\n                                   &fileHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      HASH,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    status = KphQueryHashInformationFile(fileHandle,\n                                         HashInformation,\n                                         HashInformationLength,\n                                         KernelMode);\n\n    ObCloseHandle(fileHandle, KernelMode);\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/imgcoherency.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2024-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Checks an image for coherency against the data backing the image.\n *\n * \\details Always called from within structured exception handling.\n *\n * \\param[in] ImageBase Base address of the image mapping.\n * \\param[in] ImageSize Size of the image mapping.\n * \\param[in] DataBase Base address of the data mapping.\n * \\param[in] DataSize Size of the data mapping.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpCheckImageCoherency(\n    _In_ PVOID ImageBase,\n    _In_ SIZE_T ImageSize,\n    _In_ PVOID DataBase,\n    _In_ SIZE_T DataSize\n    )\n{\n    NTSTATUS status;\n    KPH_MEMORY_REGION regions[4];\n    KPH_IMAGE_NT_HEADERS image;\n    SIZE_T size;\n    PVOID dataEnd;\n    PVOID imageEnd;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlZeroMemory(&regions, sizeof(regions));\n\n    regions[0].Start = DataBase;\n    regions[0].End = Add2Ptr(DataBase, sizeof(IMAGE_DOS_HEADER));\n\n    status = KphImageNtHeader(DataBase, DataSize, &image);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphImageNtHeader failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    size = (image.Headers->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));\n    regions[1].Start = IMAGE_FIRST_SECTION(image.Headers);\n    regions[1].End = Add2Ptr(regions[1].Start, size);\n\n    regions[2].Start = &image.Headers->FileHeader.NumberOfSections;\n\n    if (!RTL_CONTAINS_FIELD(&image.Headers->OptionalHeader,\n                            image.Headers->FileHeader.SizeOfOptionalHeader,\n                            Magic))\n    {\n        regions[2].End = &image.Headers->OptionalHeader.Magic;\n        goto VerifyRegions;\n    }\n\n    if (image.Headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        if (!RTL_CONTAINS_FIELD(&image.Headers32->OptionalHeader,\n                                image.Headers->FileHeader.SizeOfOptionalHeader,\n                                ImageBase))\n        {\n            regions[2].End = Add2Ptr(&image.Headers32->OptionalHeader,\n                                     image.Headers->FileHeader.SizeOfOptionalHeader);\n            goto VerifyRegions;\n        }\n\n        regions[2].End = &image.Headers32->OptionalHeader.ImageBase;\n        regions[3].Start = &image.Headers32->OptionalHeader.SectionAlignment;\n        regions[3].End = Add2Ptr(&image.Headers32->OptionalHeader,\n                                 image.Headers->FileHeader.SizeOfOptionalHeader);\n    }\n    else if (image.Headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        if (!RTL_CONTAINS_FIELD(&image.Headers64->OptionalHeader,\n                                image.Headers->FileHeader.SizeOfOptionalHeader,\n                                ImageBase))\n        {\n            regions[2].End = Add2Ptr(&image.Headers64->OptionalHeader,\n                                     image.Headers->FileHeader.SizeOfOptionalHeader);\n            goto VerifyRegions;\n        }\n\n        regions[2].End = &image.Headers64->OptionalHeader.ImageBase;\n        regions[3].Start = &image.Headers64->OptionalHeader.SectionAlignment;\n        regions[3].End = Add2Ptr(&image.Headers64->OptionalHeader,\n                                 image.Headers->FileHeader.SizeOfOptionalHeader);\n    }\n    else\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Invalid image optional header magic: 0x%04x\",\n                      image.Headers->OptionalHeader.Magic);\n\n        return STATUS_INVALID_IMAGE_FORMAT;\n    }\n\nVerifyRegions:\n\n    imageEnd = Add2Ptr(ImageBase, ImageSize);\n    dataEnd = Add2Ptr(DataBase, DataSize);\n\n    for (ULONG i = 0; i < ARRAYSIZE(regions); i++)\n    {\n        PKPH_MEMORY_REGION region;\n        KPH_MEMORY_REGION other;\n\n        region = &regions[i];\n\n        if (!region->Start)\n        {\n            break;\n        }\n\n        if (!KphIsValidMemoryRegion(region, DataBase, dataEnd))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Image region overflows mapping.\");\n\n            return STATUS_BUFFER_OVERFLOW;\n        }\n\n        other.Start = RebasePtr(region->Start, DataBase, ImageBase);\n        other.End = RebasePtr(region->End, DataBase, ImageBase);\n\n        if (!KphIsValidMemoryRegion(&other, ImageBase, imageEnd))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Data region overflows mapping.\");\n\n            return STATUS_BUFFER_OVERFLOW;\n        }\n\n        size = PtrOffset(region->Start, region->End);\n\n        if (!KphEqualMemory(region->Start, other.Start, size))\n        {\n            return STATUS_IMAGE_CHECKSUM_MISMATCH;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Checks an image for coherency against the data backing the image.\n *\n * \\param[in] ImageBase Base address of the image mapping.\n * \\param[in] ImageSize Size of the image mapping.\n * \\param[in] DataBase Base address of the data mapping.\n * \\param[in] DataSize Size of the data mapping.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCheckImageCoherency(\n    _In_ PVOID ImageBase,\n    _In_ SIZE_T ImageSize,\n    _In_ PVOID DataBase,\n    _In_ SIZE_T DataSize\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    __try\n    {\n        status = KphpCheckImageCoherency(ImageBase,\n                                         ImageSize,\n                                         DataBase,\n                                         DataSize);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/include/comms.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n#include <kphmsg.h>\n\ntypedef struct _KPH_CLIENT_INFORMER_STATE\n{\n    KPH_MESSAGE_TIMEOUTS MessageTimeouts;\n    KPH_RATE_LIMIT AsyncQueueRateLimit;\n    KPH_RATE_LIMIT InformerRateLimit[KPH_INFORMER_COUNT];\n} KPH_CLIENT_INFORMER_STATE, *PKPH_CLIENT_INFORMER_STATE;\n\ntypedef union _KPH_CLIENT_INFORMER_STATE_ATOMIC\n{\n    struct _KPH_CLIENT_RATE_LIMITS* Limits;\n    KPH_ATOMIC_OBJECT_REF Atomic;\n} KPH_CLIENT_INFORMER_STATE_ATOMIC, *PKPH_CLIENT_INFORMER_STATE_ATOMIC;\n\ntypedef struct _KPH_CLIENT\n{\n    PKPH_PROCESS_CONTEXT Process;\n    PFLT_PORT Port;\n    KPH_REFERENCE DriverUnloadProtectionRef;\n    KPH_CLIENT_INFORMER_STATE_ATOMIC InformerState;\n    PKPH_RING_BUFFER RingBuffer;\n} KPH_CLIENT, *PKPH_CLIENT;\n\ntypedef\n_Function_class_(KPHM_HANDLER)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS\nKSIAPI\nKPHM_HANDLER (\n    _In_ PKPH_CLIENT Client,\n    _Inout_ PKPH_MESSAGE Message\n    );\ntypedef KPHM_HANDLER* PKPHM_HANDLER;\n\n#define KPHM_DEFINE_HANDLER(name)                                              \\\n_Function_class_(KPHM_HANDLER)                                                 \\\n_IRQL_requires_max_(PASSIVE_LEVEL)                                             \\\n_Must_inspect_result_                                                          \\\nNTSTATUS name(                                                                 \\\n    _In_ PKPH_CLIENT Client,                                                   \\\n    _Inout_ PKPH_MESSAGE Message                                               \\\n    )\n\ntypedef\n_Function_class_(KPHM_REQUIRED_STATE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nKPH_PROCESS_STATE\nKSIAPI\nKPHM_REQUIRED_STATE (\n    _In_ PKPH_CLIENT Client,\n    _In_ PCKPH_MESSAGE Message\n    );\ntypedef KPHM_REQUIRED_STATE* PKPHM_REQUIRED_STATE;\n\n#define KPHM_DEFINE_REQUIRED_STATE(name)                                       \\\n_Function_class_(KPHM_REQUIRED_STATE)                                          \\\n_IRQL_requires_max_(PASSIVE_LEVEL)                                             \\\n_Must_inspect_result_                                                          \\\nKPH_PROCESS_STATE name(                                                        \\\n    _In_ PKPH_CLIENT Client,                                                   \\\n    _In_ PCKPH_MESSAGE Message                                                 \\\n    )\n\ntypedef struct _KPH_MESSAGE_HANDLER\n{\n    KPH_MESSAGE_ID MessageId;\n    PKPHM_HANDLER Handler;\n    PKPHM_REQUIRED_STATE RequiredState;\n} KPH_MESSAGE_HANDLER, *PKPH_MESSAGE_HANDLER;\n\nextern const KPH_MESSAGE_HANDLER KphCommsMessageHandlers[];\nextern const ULONG KphCommsMessageHandlerCount;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCommsStart(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCommsStop(\n    VOID\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG KphGetConnectedClientCount(\n    VOID\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG KphGetInformerClientCount(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerClientSettings(\n    _In_ PKPH_CLIENT Client,\n    _Out_ PKPH_INFORMER_CLIENT_SETTINGS Settings\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformerClientSettings(\n    _In_ PKPH_CLIENT Client,\n    _In_ PKPH_INFORMER_CLIENT_SETTINGS Settings\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerClientStats(\n    _In_ PKPH_CLIENT Client,\n    _Out_ PKPH_INFORMER_CLIENT_STATS Stats\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_\nPKPH_MESSAGE KphAllocateMessage(\n    VOID\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeMessage(\n    _In_freesMem_ PKPH_MESSAGE Message\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_\nPKPH_MESSAGE KphAllocateNPagedMessage(\n    VOID\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphFreeNPagedMessage(\n    _In_freesMem_ PKPH_MESSAGE Message\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCommsSendMessage(\n    _In_ PKPH_MESSAGE Message,\n    _Out_opt_ PKPH_MESSAGE Reply\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphCommsSendMessageAsync(\n    _In_aliasesMem_ PKPH_MESSAGE Message\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCommsSendNPagedMessageAsync(\n    _In_aliasesMem_ PKPH_MESSAGE Message\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCaptureStackInMessage(\n    _Inout_ PKPH_MESSAGE Message\n    );\n"
  },
  {
    "path": "KSystemInformer/include/informer.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n#include <kph.h>\n#include <kphmsg.h>\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupInformer(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphInitializeInformer(\n    VOID\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphInformerAllowed(\n    _In_ ULONG Index,\n    _In_opt_ PKPH_PROCESS_CONTEXT ActorProcess,\n    _In_opt_ PKPH_PROCESS_CONTEXT TargetProcess\n    );\n\n#define KphInformerEnabled(name, proc)                                         \\\n    KphInformerAllowed(KPH_INFORMER_INDEX(name), proc, NULL)\n\n#define KphInformerEnabled2(name, actor, target)                               \\\n    KphInformerAllowed(KPH_INFORMER_INDEX(name), actor, target)\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nKPH_INFORMER_OPTIONS KphInformerOptions(\n    _In_opt_ PKPH_PROCESS_CONTEXT ActorProcess,\n    _In_opt_ PKPH_PROCESS_CONTEXT TargetProcess\n    );\n\n#define KphInformerOpts(proc)                                                  \\\n    KphInformerOptions(proc, NULL)\n\n#define KphInformerOpts2(proc, target)                                         \\\n    KphInformerOptions(proc, target)\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerSettings(\n    _Out_ PKPH_INFORMER_SETTINGS Settings,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformerSettings(\n    _In_ PKPH_INFORMER_SETTINGS Settings,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerProcessSettings(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKPH_INFORMER_SETTINGS Settings,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformerProcessSettings(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PKPH_INFORMER_SETTINGS Settings,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerStats(\n    _In_opt_ HANDLE ProcessHandle,\n    _Out_ PKPH_INFORMER_STATS Stats,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// mini-filter informer\n\nextern PFLT_FILTER KphFltFilter;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphFltRegister(\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PUNICODE_STRING RegistryPath\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphFltUnregister(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphFltInformerStart(\n    VOID\n    );\n\n// process informer\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphProcessInformerStart(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphProcessInformerStop(\n    VOID\n    );\n\n// thread informer\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphThreadInformerStart(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphThreadInformerStop(\n    VOID\n    );\n\n// image informer\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphImageInformerStart(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphImageInformerStop(\n    VOID\n    );\n\n// object informer\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphObjectInformerStart(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphObjectInformerStop(\n    VOID\n    );\n\n// registry informer\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphRegistryInformerStart(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphRegistryInformerStop(\n    VOID\n    );\n\n// debug informer\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDebugInformerStart(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphDebugInformerStop(\n    VOID\n    );\n"
  },
  {
    "path": "KSystemInformer/include/informer_filep.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n#pragma once\n\n// informer_fileop.c\n\n_Function_class_(PFLT_POST_OPERATION_CALLBACK)\n_IRQL_requires_max_(DISPATCH_LEVEL)\nFLT_POSTOP_CALLBACK_STATUS FLTAPI KphpFltPostOp(\n    _Inout_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _In_opt_ PVOID CompletionContext,\n    _In_ FLT_POST_OPERATION_FLAGS Flags\n    );\n\n_Function_class_(PFLT_PRE_OPERATION_CALLBACK)\n_IRQL_requires_max_(APC_LEVEL)\nFLT_PREOP_CALLBACK_STATUS FLTAPI KphpFltPreOp(\n    _Inout_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Outptr_result_maybenull_ PVOID* CompletionContext\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpFltCleanupFileOp(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpFltInitializeFileOp(\n    VOID\n    );\n\n// informer_filenc.c\n\ntypedef enum _KPH_FLT_FILE_NAME_TYPE\n{\n    KphFltFileNameTypeNone,\n    KphFltFileNameTypeNameInfo,\n    KphFltFileNameTypeContext,\n    KphFltFileNameTypeFileName,\n    KphFltFileNameTypeNameCache,\n} KPH_FLT_FILE_NAME_TYPE, *PKPH_FLT_FILE_NAME_ITYPE;\n\ntypedef struct _KPH_FLT_FILE_NAME_CACHE_ENTRY\n{\n    LIST_ENTRY ListEntry;\n    PFILE_OBJECT FileObject;\n    UNICODE_STRING FileName;\n} KPH_FLT_FILE_NAME_CACHE_ENTRY, *PKPH_FLT_FILE_NAME_CACHE_ENTRY;\n\ntypedef struct _KPH_FLT_FILE_NAME\n{\n    //\n    // N.B. PFLT_CONTEXT stores a PUNICODE_STRING\n    //\n    KPH_FLT_FILE_NAME_TYPE Type;\n    union\n    {\n        PFLT_FILE_NAME_INFORMATION NameInfo;\n        PFLT_CONTEXT Context;\n        PUNICODE_STRING FileName;\n        PKPH_FLT_FILE_NAME_CACHE_ENTRY NameCache;\n    };\n} KPH_FLT_FILE_NAME, *PKPH_FLT_FILE_NAME;\n\n#define KphpFltZeroFileName(info)                                              \\\n    (info)->Type = KphFltFileNameTypeNone;                                     \\\n    (info)->NameInfo = NULL;\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetFileName(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Out_ PKPH_FLT_FILE_NAME FltFileName\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetDestFileName(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Out_ PKPH_FLT_FILE_NAME FltDestFileName\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFltReleaseFileName(\n    _In_ PKPH_FLT_FILE_NAME FltFileName\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphpFltReapFileNameCache(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpFltCleanupFileNameCache(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpFltInitializeFileNameCache(\n    VOID\n    );\n"
  },
  {
    "path": "KSystemInformer/include/kph.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n#pragma warning(push)\n#pragma warning(disable: 5103) // invalid preprocessing token (/Zc:preprocessor)\n#include <ntifs.h>\n#include <ntintsafe.h>\n#include <minwindef.h>\n#include <ntstrsafe.h>\n#include <fltKernel.h>\n#include <ntimage.h>\n#include <bcrypt.h>\n#include <usermode_accessors.h>\n#pragma warning(pop)\n#include <pooltags.h>\n#define PHNT_MODE PHNT_MODE_KERNEL\n#include <phnt.h>\n#include <ntfill.h>\n#include <ntpebteb.h>\n#include <ntldr.h>\n#include <ntwow64.h>\n#include <kphapi.h>\n#include <kphringbuff.h>\n\n#define KSIAPI NTAPI\n\n#define KPH_PAGED_CODE()                                                       \\\n    PAGED_CODE();                                                              \\\n    NT_ANALYSIS_ASSUME((KeGetCurrentIrql() == APC_LEVEL) ||                    \\\n                       (KeGetCurrentIrql() == PASSIVE_LEVEL))\n#define KPH_PAGED_CODE_PASSIVE()                                               \\\n    PAGED_CODE();                                                              \\\n    NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);                            \\\n    NT_ANALYSIS_ASSUME(KeGetCurrentIrql() == PASSIVE_LEVEL)\n#define KPH_PAGED_CODE_APC()                                                   \\\n    PAGED_CODE();                                                              \\\n    NT_ASSERT(KeGetCurrentIrql() == APC_LEVEL);                                \\\n    NT_ANALYSIS_ASSUME(KeGetCurrentIrql() == APC_LEVEL)\n#define KPH_NPAGED_CODE_PASSIVE()                                              \\\n    NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);                            \\\n    NT_ANALYSIS_ASSUME(KeGetCurrentIrql() == PASSIVE_LEVEL)\n#define KPH_NPAGED_CODE_APC_MAX()                                              \\\n    NT_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);                                \\\n    NT_ANALYSIS_ASSUME((KeGetCurrentIrql() == APC_LEVEL) ||                    \\\n                       (KeGetCurrentIrql() == PASSIVE_LEVEL))\n#define KPH_NPAGED_CODE_DISPATCH_MAX()                                         \\\n    NT_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);                           \\\n    NT_ANALYSIS_ASSUME((KeGetCurrentIrql() == DISPATCH_LEVEL) ||               \\\n                       (KeGetCurrentIrql() == APC_LEVEL) ||                    \\\n                       (KeGetCurrentIrql() == PASSIVE_LEVEL))\n#define KPH_NPAGED_CODE_DISPATCH_MIN()                                         \\\n    NT_ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);                           \\\n    NT_ANALYSIS_ASSUME((KeGetCurrentIrql() == DISPATCH_LEVEL) ||               \\\n                       (KeGetCurrentIrql() == HIGH_LEVEL))\n#define KPH_NPAGED_CODE_DISPATCH()                                             \\\n    NT_ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);                           \\\n    NT_ANALYSIS_ASSUME(KeGetCurrentIrql() == DISPATCH_LEVEL)\n\n//\n// N.B. This decorates code to indicate that the code supports up to APC_LEVEL\n// but is in a non-paged segment since it can be called in a paging I/O path.\n// Code in this path should also only allocate from non-paged pool to avoid\n// deadlocks.\n//\n#define KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO() KPH_NPAGED_CODE_APC_MAX()\n\n#define KPH_PAGED_FILE()                                                       \\\n    __pragma(bss_seg(\"PAGEBBS\"))                                               \\\n    __pragma(code_seg(\"PAGE\"))                                                 \\\n    __pragma(data_seg(\"PAGEDATA\"))                                             \\\n    __pragma(const_seg(\"PAGERO\"))\n\n#define KPH_PROTECTED_DATA_SECTION_PUSH()                                      \\\n    __pragma(data_seg(push))                                                   \\\n    __pragma(data_seg(\"KSIDATA\"))\n#define KPH_PROTECTED_DATA_SECTION_POP()                                       \\\n    __pragma(data_seg(pop))\n#define KPH_PROTECTED_DATA_SECTION_RO_PUSH()                                   \\\n    __pragma(const_seg(push))                                                  \\\n    __pragma(const_seg(\"KSIRO\"))\n#define KPH_PROTECTED_DATA_SECTION_RO_POP()                                    \\\n    __pragma(const_seg(pop))\n\n#define _Outptr_allocatesMem_ _Outptr_result_nullonfailure_ __drv_allocatesMem(Mem)\n#define _Out_allocatesMem_ _Out_ __drv_allocatesMem(Mem)\n#define _Out_allocatesMem_size_(size) _Out_allocatesMem_ _Post_writable_byte_size_(size)\n#define _FreesMem_ _Pre_notnull_ _Post_ptr_invalid_ __drv_freesMem(Mem)\n#define _In_freesMem_ _In_ _FreesMem_\n#define _In_aliasesMem_ _In_ _Pre_notnull_ _Post_ptr_invalid_ __drv_aliasesMem\n#define _Return_allocatesMem_ __drv_allocatesMem(Mem) _Check_return_ _Ret_maybenull_\n#define _Return_allocatesMem_size_(size) _Return_allocatesMem_ _Post_writable_byte_size_(size)\n#define _IRQL_requires_for_wait_(timeout)                                      \\\n    _When_(((timeout == NULL) || (timeout->QuadPart != 0)),                    \\\n           _IRQL_requires_max_(APC_LEVEL))                                     \\\n    _When_(((timeout != NULL) && (timeout->QuadPart == 0)),                    \\\n           _IRQL_requires_max_(DISPATCH_LEVEL))\n\ntypedef const void* PCVOID;\n#ifndef MAX_PATH\n#define MAX_PATH 260\n#endif\n\nFORCEINLINE\nULONG64 InterlockedExchangeU64(\n    _Inout_ _Interlocked_operand_ volatile ULONG64* Target,\n    _In_ ULONG64 Value\n    )\n{\n    return (ULONG64)InterlockedExchange64((LONG64*)Target, (LONG64)Value);\n}\n\nFORCEINLINE\nULONG64 InterlockedCompareExchangeU64(\n    _Inout_ _Interlocked_operand_ volatile ULONG64* Target,\n    _In_ ULONG64 Value,\n    _In_ ULONG64 Expected\n    )\n{\n    return (ULONG64)InterlockedCompareExchange64((LONG64*)Target,\n                                                 (LONG64)Value,\n                                                 (LONG64)Expected);\n}\n\nFORCEINLINE\nULONG64 InterlockedIncrementU64(\n    _Inout_ _Interlocked_operand_ volatile ULONG64* Target\n    )\n{\n    return (ULONG64)InterlockedIncrement64((LONG64*)Target);\n}\n\nFORCEINLINE\nULONG_PTR InterlockedExchangeULongPtr(\n    _Inout_ _Interlocked_operand_ volatile ULONG_PTR* Target,\n    _In_ ULONG_PTR Value\n    )\n{\n#ifdef _WIN64\n    return (ULONG_PTR)InterlockedExchange64((LONG64*)Target, (LONG64)Value);\n#else\n    return (ULONG_PTR)InterlockedExchange((LONG*)Target, (LONG)Value);\n#endif\n}\n\nFORCEINLINE\nULONG_PTR InterlockedExchangeAddULongPtr(\n    _Inout_ _Interlocked_operand_ volatile ULONG_PTR* Target,\n    _In_ ULONG_PTR Value\n    )\n{\n    return (ULONG_PTR)InterlockedExchangeAddSizeT((SIZE_T*)Target, (SIZE_T)Value);\n}\n\nFORCEINLINE\nBOOLEAN InterlockedBitTestAndResetULongPtr(\n    _Inout_ _Interlocked_operand_ volatile ULONG_PTR* Target,\n    _In_ ULONG_PTR Bit\n    )\n{\n#ifdef _WIN64\n    return InterlockedBitTestAndReset64((LONG64*)Target, (LONG64)Bit);\n#else\n    return InterlockedBitTestAndReset((LONG*)Target, (LONG)Bit);\n#endif\n}\n\nFORCEINLINE\nULONG_PTR InterlockedCompareExchangeULongPtr(\n    _Inout_ _Interlocked_operand_ volatile ULONG_PTR* Target,\n    _In_ ULONG_PTR Value,\n    _In_ ULONG_PTR Expected\n    )\n{\n#ifdef _WIN64\n    return (ULONG_PTR)InterlockedCompareExchange64((LONG64*)Target,\n                                                   (LONG64)Value,\n                                                   (LONG64)Expected);\n#else\n    return (ULONG_PTR)InterlockedCompareExchange((LONG*)Target,\n                                                 (LONG)Value,\n                                                 (LONG)Expected);\n#endif\n}\n\nFORCEINLINE\nULONG_PTR InterlockedDecrementULongPtr(\n    _Inout_ _Interlocked_operand_ volatile ULONG_PTR* Target\n    )\n{\n    return (ULONG_PTR)InterlockedDecrementSizeT((SIZE_T*)Target);\n}\n\nFORCEINLINE\nSSIZE_T InterlockedIncrementSSizeT(\n    _Inout_ _Interlocked_operand_ volatile SSIZE_T* Target\n    )\n{\n    return (SSIZE_T)InterlockedIncrementSizeT((SIZE_T*)Target);\n}\n\nFORCEINLINE\nVOID WriteSSizeTNoFence(\n    _Out_ _Interlocked_operand_ volatile SSIZE_T* Target,\n    _In_ SSIZE_T Value\n    )\n{\n    WriteSizeTNoFence((SIZE_T*)Target, (SIZE_T)Value);\n}\n\nFORCEINLINE\nSSIZE_T InterlockedIncrementSSizeTNoFence(\n    _Inout_ _Interlocked_operand_ volatile SSIZE_T* Target\n    )\n{\n    return (SSIZE_T)InterlockedIncrementSizeTNoFence((SIZE_T*)Target);\n}\n\nFORCEINLINE\nSSIZE_T InterlockedDecrementSSizeT(\n    _Inout_ _Interlocked_operand_ volatile SSIZE_T* Target\n    )\n{\n    return (SSIZE_T)InterlockedDecrementSizeT((SIZE_T*)Target);\n}\n\nFORCEINLINE\nSIZE_T InterlockedCompareExchangeSizeT(\n    _Inout_ _Interlocked_operand_ volatile SIZE_T* Target,\n    _In_ SIZE_T Value,\n    _In_ SIZE_T Expected\n    )\n{\n    return (SIZE_T)InterlockedCompareExchangePointer((PVOID*)Target,\n                                                     (PVOID)Value,\n                                                     (PVOID)Expected);\n}\n\nFORCEINLINE\nVOID InterlockedExchangeIfGreaterSizeT(\n    _Inout_ _Interlocked_operand_ volatile SIZE_T* Target,\n    _In_ SIZE_T Value\n    )\n{\n    SIZE_T max;\n\n    max = ReadSizeTAcquire(Target);\n    while (Value > max)\n    {\n        SIZE_T expected;\n\n        expected = max;\n\n        max = InterlockedCompareExchangeSizeT(Target, Value, expected);\n        if (max == expected)\n        {\n            break;\n        }\n    }\n}\n\n//\n// Use user-mode accessors (UMA) APIs instead.\n//\n#pragma deprecated(\"ProbeForRead\")\n#pragma deprecated(\"ProbeForWrite\")\n\n#define C_2sTo4(x) ((unsigned int)(signed short)(x))\n\n#define RebasePtr(pointer, oldBase, newBase)                                   \\\nAdd2Ptr(newBase, PtrOffset(oldBase, pointer))\n\n#define RebaseUnicodeString(string, oldBase, newBase)                          \\\nif ((string)->Buffer)                                                          \\\n{                                                                              \\\n    (string)->Buffer = Add2Ptr(newBase, PtrOffset(oldBase, (string)->Buffer)); \\\n}\n\n#define KPH_TIMEOUT(ms) { .QuadPart = (-10000ll * (ms)) }\n\n#define KPH_KERNEL_PURGE_EA \"$KERNEL.PURGE.SI.\"\n\ntypedef struct _KPH_FILE_VERSION\n{\n    USHORT MajorVersion;\n    USHORT MinorVersion;\n    USHORT BuildNumber;\n    USHORT Revision;\n} KPH_FILE_VERSION, *PKPH_FILE_VERSION;\n\ntypedef struct _KPH_MEMORY_REGION\n{\n    PVOID Start;\n    PVOID End;\n} KPH_MEMORY_REGION, *PKPH_MEMORY_REGION;\n\n_Must_inspect_result_\nFORCEINLINE\nBOOLEAN KphIsValidMemoryRegion(\n    _In_ PKPH_MEMORY_REGION Region,\n    _In_ PVOID Start,\n    _In_ PVOID End\n    )\n{\n    return ((Region->Start <= Region->End) &&\n            (Region->Start >= Start) &&\n            (Region->End <= End));\n}\n\n//\n// C30030 - Probably allocating executable memory via specifying a\n// MM_PAGE_PRIORITY type without a bitwise OR with MdlMappingNoExecute\n//\n#pragma deprecated(\"MmGetSystemAddressForMdl\")\n#pragma deprecated(\"MmGetSystemAddressForMdlSafe\")\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Post_writable_byte_size_(Mdl->ByteCount)\n_At_(Mdl->MappedSystemVa, _Post_writable_byte_size_(Mdl->ByteCount))\n_Check_return_\n_Success_(return != NULL)\nFORCEINLINE\nPVOID KphpGetSystemAddressForMdl(\n    _Inout_ PMDL Mdl,\n    _In_ MM_PAGE_PRIORITY Priority\n    )\n{\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    return MmGetSystemAddressForMdlSafe(Mdl, Priority | MdlMappingNoExecute);\n}\n#define KphGetSystemAddressForMdl(mdl, priority)                               \\\n_Pragma(\"warning(push)\")                                                       \\\n_Pragma(\"warning(disable : 30030)\")                                            \\\nKphpGetSystemAddressForMdl(mdl, priority)                                      \\\n_Pragma(\"warning(pop)\")\n\n#pragma deprecated(\"ObReferenceObjectByHandle\")\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nFORCEINLINE\nNTSTATUS KphpObReferenceObjectByHandle(\n    _In_ HANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_TYPE ObjectType,\n    _In_ KPROCESSOR_MODE AccessMode,\n    _Out_ PVOID *Object,\n    _Out_opt_ POBJECT_HANDLE_INFORMATION HandleInformation\n    )\n{\n#pragma warning(disable: 4995)   // suppress deprecation warning\n#pragma prefast(suppress: 28118) // allow at APC_LEVEL\n    return ObReferenceObjectByHandle(Handle,\n                                     DesiredAccess,\n                                     ObjectType,\n                                     AccessMode,\n                                     Object,\n                                     HandleInformation);\n}\n#define ObReferenceObjectByHandle KphpObReferenceObjectByHandle\n\n// main\n\nextern PDRIVER_OBJECT KphDriverObject;\nextern RTL_OSVERSIONINFOEXW KphOsVersionInfo;\nextern KPH_FILE_VERSION KphKernelVersion;\nextern BOOLEAN KphIgnoreProtectionsSuppressed;\nextern BOOLEAN KphIgnoreTestSigningEnabled;\nextern SYSTEM_SECUREBOOT_INFORMATION KphSecureBootInfo;\nextern SYSTEM_CODEINTEGRITY_INFORMATION KphCodeIntegrityInfo;\n\nFORCEINLINE\nBOOLEAN KphInDeveloperMode(\n    VOID\n    )\n{\n    if (KphSecureBootInfo.SecureBootCapable &&\n        KphSecureBootInfo.SecureBootEnabled)\n    {\n        return FALSE;\n    }\n\n    if (!KD_DEBUGGER_ENABLED)\n    {\n        return FALSE;\n    }\n\n    if (!FlagOn(KphCodeIntegrityInfo.CodeIntegrityOptions,\n                CODEINTEGRITY_OPTION_TESTSIGN))\n    {\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nFORCEINLINE\nBOOLEAN KphProtectionsSuppressed(\n    VOID\n    )\n{\n    if (KphIgnoreProtectionsSuppressed)\n    {\n        return FALSE;\n    }\n\n    return KphInDeveloperMode();\n}\n\nFORCEINLINE\nBOOLEAN KphTestSigningEnabled(\n    VOID\n    )\n{\n    if (KphIgnoreTestSigningEnabled)\n    {\n        return FALSE;\n    }\n\n    return KphInDeveloperMode();\n}\n\n// parameters\n\nextern PUNICODE_STRING KphAltitude;\nextern PUNICODE_STRING KphPortName;\nextern KPH_PARAMETER_FLAGS KphParameterFlags;\nextern PUNICODE_STRING KphSystemProcessName;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupParameters(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeParameters(\n    _In_ PCUNICODE_STRING RegistryPath\n    );\n\n// alloc\n\n//\n// Always use wrapped allocators, unless explicitly necessary.\n//\n// This helps catch programmer error. Deprecate the original ones here, the\n// allocation infrastructure will internally suppress the deprecated warnings.\n//\n#pragma deprecated(\"ExAllocateCacheAwareRundownProtection\")\n#pragma deprecated(\"ExAllocateFromLookasideListEx\")\n#pragma deprecated(\"ExAllocateFromNPagedLookasideList\")\n#pragma deprecated(\"ExAllocateFromPagedLookasideList\")\n#pragma deprecated(\"ExAllocatePool\")\n#pragma deprecated(\"ExAllocatePool2\")\n#pragma deprecated(\"ExAllocatePool3\")\n#pragma deprecated(\"ExAllocatePoolPriorityUninitialized\")\n#pragma deprecated(\"ExAllocatePoolPriorityZero\")\n#pragma deprecated(\"ExAllocatePoolQuotaUninitialized\")\n#pragma deprecated(\"ExAllocatePoolQuotaZero\")\n#pragma deprecated(\"ExAllocatePoolUninitialized\")\n#pragma deprecated(\"ExAllocatePoolWithQuota\")\n#pragma deprecated(\"ExAllocatePoolWithQuotaTag\")\n#pragma deprecated(\"ExAllocatePoolWithTag\")\n#pragma deprecated(\"ExAllocatePoolWithTagPriority\")\n#pragma deprecated(\"ExAllocatePoolZero\")\n#pragma deprecated(\"ExFreePool\")\n#pragma deprecated(\"ExFreePool2\")\n#pragma deprecated(\"ExFreePoolWithTag\")\n#pragma deprecated(\"ExFreeToLookasideListEx\")\n#pragma deprecated(\"ExFreeToNPagedLookasideList\")\n#pragma deprecated(\"ExFreeToPagedLookasideList\")\n#pragma deprecated(\"ExDeleteLookasideListEx\")\n#pragma deprecated(\"ExDeleteNPagedLookasideList\")\n#pragma deprecated(\"ExDeletePagedLookasideList\")\n#pragma deprecated(\"ExInitializeLookasideListEx\")\n#pragma deprecated(\"ExInitializeNPagedLookasideList\")\n#pragma deprecated(\"ExInitializePagedLookasideList\")\n\nFORCEINLINE\nVOID KphFreePool(\n    _FreesMem_ PVOID Memory\n    )\n{\n#pragma warning(suppress: 4995) // intentional use of ExFreePool\n    ExFreePoolWithTag(Memory, 0);\n}\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeAlloc(\n    VOID\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_size_(NumberOfBytes)\nPVOID KphAllocateNPaged(\n    _In_ SIZE_T NumberOfBytes,\n    _In_ ULONG Tag\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(NumberOfBytes)\nPVOID KphAllocatePaged(\n    _In_ SIZE_T NumberOfBytes,\n    _In_ ULONG Tag\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphFree(\n    _FreesMem_ PVOID Memory,\n    _In_ ULONG Tag\n    );\n\n#pragma prefast(push)\n#pragma prefast(disable: 28195) // acquire memory without doing so\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_size_(NumberOfBytes)\nFORCEINLINE\nPVOID KphpAllocateNPagedA(\n    _In_ SIZE_T NumberOfBytes,\n    _In_ ULONG Tag,\n    _Out_writes_bytes_(SizeOfStack) PBYTE Stack,\n    _In_ ULONG SizeOfStack\n    )\n{\n    if (NumberOfBytes <= SizeOfStack)\n    {\n        RtlZeroMemory(Stack, SizeOfStack);\n        return Stack;\n    }\n\n    return KphAllocateNPaged(NumberOfBytes, Tag);\n}\n#pragma prefast(pop)\n\n#define KphAllocateNPagedA(NumberOfBytes, Tag, Stack)                          \\\n    KphpAllocateNPagedA(NumberOfBytes, Tag, Stack, sizeof(Stack))\n\n#pragma prefast(push)\n#pragma prefast(disable: 28195) // acquire memory without doing so\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(NumberOfBytes)\nFORCEINLINE\nPVOID KphpAllocatePagedA(\n    _In_ SIZE_T NumberOfBytes,\n    _In_ ULONG Tag,\n    _Out_writes_bytes_(SizeOfStack) PBYTE Stack,\n    _In_ ULONG SizeOfStack\n    )\n{\n    if (NumberOfBytes <= SizeOfStack)\n    {\n        RtlZeroMemory(Stack, SizeOfStack);\n        return Stack;\n    }\n\n    return KphAllocatePaged(NumberOfBytes, Tag);\n}\n#pragma prefast(pop)\n\n#define KphAllocatePagedA(NumberOfBytes, Tag, Stack)                           \\\n    KphpAllocatePagedA(NumberOfBytes, Tag, Stack, sizeof(Stack))\n\n#pragma prefast(push)\n#pragma prefast(disable: 6014) // leaking memory\n_IRQL_requires_max_(DISPATCH_LEVEL)\nFORCEINLINE\nVOID KphpFreeA(\n    _FreesMem_ PVOID Memory,\n    _In_ ULONG Tag,\n    _In_ PBYTE Stack\n    )\n{\n    if (Memory != Stack)\n    {\n        KphFree(Memory, Tag);\n    }\n}\n#pragma prefast(pop)\n\n#define KphFreeA(Memory, Tag, Stack) KphpFreeA(Memory, Tag, Stack)\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphInitializeNPagedLookaside(\n    _Out_ PNPAGED_LOOKASIDE_LIST Lookaside,\n    _In_ SIZE_T Size,\n    _In_ ULONG Tag\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphDeleteNPagedLookaside(\n    _Inout_ PNPAGED_LOOKASIDE_LIST Lookaside\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_size_(Lookaside->L.Size)\nPVOID KphAllocateFromNPagedLookaside(\n    _Inout_ PNPAGED_LOOKASIDE_LIST Lookaside\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphFreeToNPagedLookaside(\n    _Inout_ PNPAGED_LOOKASIDE_LIST Lookaside,\n    _In_freesMem_ PVOID Memory\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphInitializePagedLookaside(\n    _Out_ PPAGED_LOOKASIDE_LIST Lookaside,\n    _In_ SIZE_T Size,\n    _In_ ULONG Tag\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphDeletePagedLookaside(\n    _Inout_ PPAGED_LOOKASIDE_LIST Lookaside\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(Lookaside->L.Size)\nPVOID KphAllocateFromPagedLookaside(\n    _Inout_ PPAGED_LOOKASIDE_LIST Lookaside\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeToPagedLookaside(\n    _Inout_ PPAGED_LOOKASIDE_LIST Lookaside,\n    _In_freesMem_ PVOID Memory\n    );\n\ntypedef PAGED_LOOKASIDE_LIST KPH_PAGED_LOOKASIDE_OBJECT;\ntypedef KPH_PAGED_LOOKASIDE_OBJECT* PKPH_PAGED_LOOKASIDE_OBJECT;\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphCreatePagedLookasideObject(\n    _Outptr_result_nullonfailure_ PKPH_PAGED_LOOKASIDE_OBJECT* Lookaside,\n    _In_ SIZE_T Size,\n    _In_ ULONG Tag\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(Lookaside->L.Size)\nPVOID KphAllocateFromPagedLookasideObject(\n    _Inout_ PKPH_PAGED_LOOKASIDE_OBJECT Lookaside\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeToPagedLookasideObject(\n    _Inout_ PKPH_PAGED_LOOKASIDE_OBJECT Lookaside,\n    _In_freesMem_ PVOID Memory\n    );\n\ntypedef NPAGED_LOOKASIDE_LIST KPH_NPAGED_LOOKASIDE_OBJECT;\ntypedef KPH_NPAGED_LOOKASIDE_OBJECT* PKPH_NPAGED_LOOKASIDE_OBJECT;\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nNTSTATUS KphCreateNPagedLookasideObject(\n    _Outptr_result_nullonfailure_ PKPH_NPAGED_LOOKASIDE_OBJECT* Lookaside,\n    _In_ SIZE_T Size,\n    _In_ ULONG Tag\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_size_(Lookaside->L.Size)\nPVOID KphAllocateFromNPagedLookasideObject(\n    _Inout_ PKPH_NPAGED_LOOKASIDE_OBJECT Lookaside\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphFreeToNPagedLookasideObject(\n    _Inout_ PKPH_NPAGED_LOOKASIDE_OBJECT Lookaside,\n    _In_freesMem_ PVOID Memory\n    );\n\n// dynimp\n\nextern PPS_SET_LOAD_IMAGE_NOTIFY_ROUTINE_EX KphDynPsSetLoadImageNotifyRoutineEx;\nextern PPS_SET_CREATE_PROCESS_NOTIFY_ROUTINE_EX2 KphDynPsSetCreateProcessNotifyRoutineEx2;\nextern PMM_PROTECT_DRIVER_SECTION KphDynMmProtectDriverSection;\nextern PPS_GET_PROCESS_SEQUENCE_NUMBER KphDynPsGetProcessSequenceNumber;\nextern PPS_GET_PROCESS_START_KEY KphDynPsGetProcessStartKey;\nextern PSE_REGISTER_IMAGE_VERIFICATION_CALLBACK KphSeRegisterImageVerificationCallback;\nextern PSE_UNREGISTER_IMAGE_VERIFICATION_CALLBACK KphSeUnregisterImageVerificationCallback;\nextern PCI_VALIDATE_FILE_OBJECT KphDynCiValidateFileObject;\nextern PCI_FREE_POLICY_INFO KphDynCiFreePolicyInfo;\nextern PLXP_THREAD_GET_CURRENT KphDynLxpThreadGetCurrent;\nextern PIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_SOURCE KphDynIoCheckFileObjectOpenedAsCopySource;\nextern PIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_DESTINATION KphDynIoCheckFileObjectOpenedAsCopyDestination;\nextern PFLT_GET_COPY_INFORMATION_FROM_CALLBACK_DATA KphDynFltGetCopyInformationFromCallbackData;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphDynamicImport(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nPVOID KphGetSystemRoutineAddress(\n    _In_z_ PCWSTR SystemRoutineName\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nPVOID KphGetRoutineAddress(\n    _In_z_ PCWSTR ModuleName,\n    _In_z_ PCSTR RoutineName\n    );\n\n// dyndata\n\ntypedef struct _KPH_DYN\n{\n    ULONG EgeGuid;\n    ULONG EpObjectTable;\n    ULONG EreGuidEntry;\n    ULONG HtHandleContentionEvent;\n    ULONG OtName;\n    ULONG OtIndex;\n    ULONG ObDecodeShift;\n    ULONG ObAttributesShift;\n    ULONG AlpcCommunicationInfo;\n    ULONG AlpcOwnerProcess;\n    ULONG AlpcConnectionPort;\n    ULONG AlpcServerCommunicationPort;\n    ULONG AlpcClientCommunicationPort;\n    ULONG AlpcHandleTable;\n    ULONG AlpcHandleTableLock;\n    ULONG AlpcAttributes;\n    ULONG AlpcAttributesFlags;\n    ULONG AlpcPortContext;\n    ULONG AlpcPortObjectLock;\n    ULONG AlpcSequenceNo;\n    ULONG AlpcState;\n    ULONG KtInitialStack;\n    ULONG KtStackLimit;\n    ULONG KtStackBase;\n    ULONG KtKernelStack;\n    ULONG KtReadOperationCount;\n    ULONG KtWriteOperationCount;\n    ULONG KtOtherOperationCount;\n    ULONG KtReadTransferCount;\n    ULONG KtWriteTransferCount;\n    ULONG KtOtherTransferCount;\n    ULONG MmSectionControlArea;\n    ULONG MmControlAreaListHead;\n    ULONG MmControlAreaLock;\n    ULONG EpSectionObject;\n\n    ULONG LxPicoProc;\n    ULONG LxPicoProcInfo;\n    ULONG LxPicoProcInfoPID;\n    ULONG LxPicoThrdInfo;\n    ULONG LxPicoThrdInfoTID;\n\n    BCRYPT_KEY_HANDLE SessionTokenPublicKeyHandle;\n} KPH_DYN, *PKPH_DYN;\n\n_Must_inspect_result_\nPKPH_DYN KphReferenceDynData(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphActivateDynData(\n    _In_ PBYTE DynData,\n    _In_ ULONG DynDataLength,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphIsDynDataActive(\n    _Out_ PBOOLEAN IsActive,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeDynData(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupDynData(\n    VOID\n    );\n\n// object\n\n#ifdef _X86_\n#define KERNEL_HANDLE_BIT (0x80000000)\n#else\n#define KERNEL_HANDLE_BIT (0xffffffff80000000)\n#endif\n\n#define IsKernelHandle(Handle) ((LONG_PTR)(Handle) < 0)\n#define MakeKernelHandle(Handle) ((HANDLE)((ULONG_PTR)(Handle) | KERNEL_HANDLE_BIT))\n#define IsPseudoHandle(Handle) (((ULONG_PTR)(Handle) <= (ULONG_PTR)-1) && \\\n                                ((ULONG_PTR)(Handle) >= (ULONG_PTR)-6))\n\n_Must_inspect_result_\nPVOID KphObpDecodeObject(\n    _In_ PKPH_DYN Dyn,\n    _In_ PHANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nULONG KphObpGetHandleAttributes(\n    _In_ PKPH_DYN Dyn,\n    _In_ PHANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\n_When_(NT_SUCCESS(return), _Acquires_lock_(Process))\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReferenceProcessHandleTable(\n    _In_ PKPH_DYN Dyn,\n    _In_ PEPROCESS Process,\n    _Outptr_result_nullonfailure_ PHANDLE_TABLE* HandleTable\n    );\n\n_Releases_lock_(Process)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphDereferenceProcessHandleTable(\n    _In_ PEPROCESS Process\n    );\n\ntypedef\n_Function_class_(KPH_ENUM_PROCESS_HANDLES_CALLBACK)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nBOOLEAN\nKSIAPI\nKPH_ENUM_PROCESS_HANDLES_CALLBACK(\n    _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,\n    _In_ HANDLE Handle,\n    _In_opt_ PVOID Parameter\n    );\ntypedef KPH_ENUM_PROCESS_HANDLES_CALLBACK* PKPH_ENUM_PROCESS_HANDLES_CALLBACK;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphEnumerateProcessHandlesEx(\n    _In_ PEPROCESS Process,\n    _In_ PKPH_ENUM_PROCESS_HANDLES_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphEnumerateProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryNameObject(\n    _In_ PVOID Object,\n    _Out_writes_bytes_opt_(BufferLength) POBJECT_NAME_INFORMATION Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG ReturnLength\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryNameFileObject(\n    _In_ PFILE_OBJECT FileObject,\n    _Out_writes_bytes_opt_(BufferLength) POBJECT_NAME_INFORMATION Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG ReturnLength\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenNamedObject(\n    _Out_ PHANDLE ObjectHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ POBJECT_TYPE ObjectType,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDuplicateObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE SourceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TargetHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCompareObjects(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// process\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenProcessJob(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE JobHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _Out_writes_bytes_opt_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// driver\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenDriver(\n    _Out_ PHANDLE DriverHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationDriver(\n    _In_ HANDLE DriverHandle,\n    _In_ KPH_DRIVER_INFORMATION_CLASS DriverInformationClass,\n    _Out_writes_bytes_opt_(DriverInformationLength) PVOID DriverInformation,\n    _In_ ULONG DriverInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// device\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenDevice(\n    _Out_ PHANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenDeviceDriver(\n    _In_ HANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE DriverHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphOpenDeviceBaseDevice(\n    _In_ HANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE BaseDeviceHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// thread\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCaptureStackBackTraceThreadByHandle(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID* BackTrace,\n    _Out_ PULONG CapturedFrames,\n    _Out_opt_ PULONG BackTraceHash,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _Out_writes_bytes_opt_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// util\n\n#pragma deprecated(\"memcmp\")\n#pragma deprecated(\"RtlCompareMemory\")\n#pragma deprecated(\"RtlEqualMemory\")\n\n_Must_inspect_result_\nFORCEINLINE\nINT KphCompareMemory(\n    _In_reads_bytes_(Length) PVOID Buffer1,\n    _In_reads_bytes_(Length) PVOID Buffer2,\n    _In_ SIZE_T Length\n    )\n{\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    return memcmp(Buffer1, Buffer2, Length);\n}\n\n_Must_inspect_result_\nFORCEINLINE\nBOOLEAN KphEqualMemory(\n    _In_reads_bytes_(Length) PVOID Buffer1,\n    _In_reads_bytes_(Length) PVOID Buffer2,\n    _In_ SIZE_T Length\n    )\n{\n#pragma warning(suppress: 4995) // suppress deprecation warning\n    return (memcmp(Buffer1, Buffer2, Length) == 0);\n}\n\ntypedef\n_Function_class_(KPH_BINARY_SEARCH_CALLBACK)\nINT\nKSIAPI\nKPH_BINARY_SEARCH_CALLBACK(\n    _In_opt_ PVOID Context,\n    _In_ PCVOID Key,\n    _In_ PCVOID Element\n    );\ntypedef KPH_BINARY_SEARCH_CALLBACK* PKPH_BINARY_SEARCH_CALLBACK;\n\n_Must_inspect_result_\n_Success_(return != NULL)\nPVOID KphBinarySearch(\n    _In_ PCVOID Key,\n    _In_reads_bytes_(NumberOfElements * SizeOfElement) PCVOID Base,\n    _In_ ULONG NumberOfElements,\n    _In_ ULONG SizeOfElement,\n    _In_ PKPH_BINARY_SEARCH_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef\n_Function_class_(KPH_QUICK_SORT_CALLBACK)\nINT\nKSIAPI\nKPH_QUICK_SORT_CALLBACK(\n    _In_opt_ PVOID Context,\n    _In_ PCVOID LeftElement,\n    _In_ PCVOID RightElement\n    );\ntypedef KPH_QUICK_SORT_CALLBACK* PKPH_QUICK_SORT_CALLBACK;\n\nVOID KphQuickSort(\n    _Inout_updates_bytes_(NumberOfElements * SizeOfElement) PVOID Base,\n    _In_ ULONG NumberOfElements,\n    _In_ ULONG SizeOfElement,\n    _In_ PKPH_QUICK_SORT_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\n_Must_inspect_result_\n_Success_(return != NULL)\nPVOID KphSearchMemory(\n    _In_reads_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _In_reads_bytes_(PatternLength) PVOID Pattern,\n    _In_ ULONG PatternLength\n    );\n\ntypedef EX_RUNDOWN_REF KPH_RUNDOWN;\ntypedef KPH_RUNDOWN* PKPH_RUNDOWN;\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphAcquireRundown(\n    _Inout_ PKPH_RUNDOWN Rundown\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphReleaseRundown(\n    _Inout_ PKPH_RUNDOWN Rundown\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphInitializeRundown(\n    _Out_ PKPH_RUNDOWN Rundown\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphWaitForRundown(\n    _Inout_ PKPH_RUNDOWN Rundown\n    );\n\ntypedef EX_PUSH_LOCK KPH_RWLOCK;\ntypedef KPH_RWLOCK* PKPH_RWLOCK;\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphInitializeRWLock(\n    _Out_ PKPH_RWLOCK Lock\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphDeleteRWLock(\n    _In_ PKPH_RWLOCK Lock\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Acquires_lock_(_Global_critical_region_)\nVOID KphAcquireRWLockExclusive(\n    _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PKPH_RWLOCK Lock\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Acquires_lock_(_Global_critical_region_)\nVOID KphAcquireRWLockShared(\n    _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PKPH_RWLOCK Lock\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Releases_lock_(_Global_critical_region_)\nVOID KphReleaseRWLock(\n    _Inout_ _Requires_lock_held_(*_Curr_) _Releases_lock_(*_Curr_) PKPH_RWLOCK Lock\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphIsSameFile(\n    _In_ PFILE_OBJECT FirstFileObject,\n    _In_ PFILE_OBJECT SecondFileObject\n    );\n\ntypedef struct _KPH_REFERENCE\n{\n    LONG Count;\n} KPH_REFERENCE, *PKPH_REFERENCE;\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAcquireReference(\n    _Inout_ PKPH_REFERENCE Reference,\n    _Out_opt_ PLONG PreviousCount\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReleaseReference(\n    _Inout_ PKPH_REFERENCE Reference,\n    _Out_opt_ PLONG PreviousCount\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphValidateAddressForSystemModules(\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryRegistryString(\n    _In_ HANDLE KeyHandle,\n    _In_ PCUNICODE_STRING ValueName,\n    _Outptr_allocatesMem_ PUNICODE_STRING* String\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeRegistryString(\n    _In_freesMem_ PUNICODE_STRING String\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryRegistryBinary(\n    _In_ HANDLE KeyHandle,\n    _In_ PCUNICODE_STRING ValueName,\n    _Outptr_allocatesMem_ PBYTE* Buffer,\n    _Out_ PULONG Length\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeRegistryBinary(\n    _In_freesMem_ PBYTE Buffer\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryRegistryULong(\n    _In_ HANDLE KeyHandle,\n    _In_ PCUNICODE_STRING ValueName,\n    _Out_ PULONG Value\n    );\n\n#define KPH_MAP_DATA     0x00000000ul\n#define KPH_MAP_IMAGE    0x00000001ul\n\n_IRQL_always_function_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphMapViewInSystem(\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags,\n    _Outptr_result_bytebuffer_(*ViewSize) PVOID *MappedBase,\n    _Inout_ PSIZE_T ViewSize\n    );\n\n_IRQL_always_function_max_(PASSIVE_LEVEL)\nVOID KphUnmapViewInSystem(\n    _In_ PVOID MappedBase\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetNameFileObject(\n    _In_ PFILE_OBJECT FileObject,\n    _Outptr_allocatesMem_ PUNICODE_STRING* FileName\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeNameFileObject(\n    _In_freesMem_ PUNICODE_STRING FileName\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nBOOLEAN KphSinglePrivilegeCheckEx(\n    _In_ LUID PrivilegeValue,\n    _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nBOOLEAN KphSinglePrivilegeCheck(\n    _In_ LUID PrivilegeValue,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetFileVersion(\n    _In_ PCUNICODE_STRING FileName,\n    _Out_ PKPH_FILE_VERSION Version\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetKernelVersion(\n    _Out_ PKPH_FILE_VERSION Version\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGuardGrantSuppressedCallAccess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDisableXfgOnTarget(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetFileNameFinalComponent(\n    _In_ PCUNICODE_STRING FileName,\n    _Out_ PUNICODE_STRING FinalComponent\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetProcessImageName(\n    _In_ PEPROCESS Process,\n    _Out_allocatesMem_ PUNICODE_STRING ImageName\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeProcessImageName(\n    _In_freesMem_ PUNICODE_STRING ImageName\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenParametersKey(\n    _In_ PCUNICODE_STRING RegistryPath,\n    _Out_ PHANDLE KeyHandle\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDominationCheck(\n    _In_ PEPROCESS Process,\n    _In_ PEPROCESS ProcessTarget,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDominationAndPrivilegeCheck(\n    _In_ ULONG Privileges,\n    _In_ PETHREAD Thread,\n    _In_ PEPROCESS ProcessTarget,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG64 KphGetProcessSequenceNumber(\n    _In_ PEPROCESS Process\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG64 KphGetProcessStartKey(\n    _In_ PEPROCESS Process\n    );\n\n#define KphGetCurrentProcessStartKey() KphGetProcessStartKey(PsGetCurrentProcess())\n#define KphGetThreadProcessStartKey(thread) KphGetProcessStartKey(PsGetThreadProcess(thread))\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nPVOID KphGetCurrentThreadSubProcessTag(\n    VOID\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nPVOID KphGetThreadSubProcessTagEx(\n    _In_ PETHREAD Thread,\n    _In_ BOOLEAN CacheOnly\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nPVOID KphGetThreadSubProcessTag(\n    _In_ PETHREAD Thread\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetSigningLevel(\n    _In_ PFILE_OBJECT FileObject,\n    _Out_ PSE_SIGNING_LEVEL SigningLevel\n    );\n\ntypedef union _KPH_IMAGE_NT_HEADERS\n{\n    PIMAGE_NT_HEADERS Headers;\n    PIMAGE_NT_HEADERS32 Headers32;\n    PIMAGE_NT_HEADERS64 Headers64;\n} KPH_IMAGE_NT_HEADERS, *PKPH_IMAGE_NT_HEADERS;\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphImageNtHeader(\n    _In_ PVOID Base,\n    _In_ ULONG64 Size,\n    _Out_ PKPH_IMAGE_NT_HEADERS Headers\n    );\n\n// lsa\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphProcessIsLsass(\n    _In_ PEPROCESS Process,\n    _Out_ PBOOLEAN IsLsass\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphValidateLsass(\n    _In_ PEPROCESS Process\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInvalidateLsass(\n    _In_ PEPROCESS Process\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphCanIdentifyLsass(\n    VOID\n    );\n\n// vm\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReadVirtualMemory(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQuerySection(\n    _In_ HANDLE SectionHandle,\n    _In_ KPH_SECTION_INFORMATION_CLASS SectionInformationClass,\n    _Out_writes_bytes_opt_(SectionInformationLength) PVOID SectionInformation,\n    _In_ ULONG SectionInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\ntypedef struct _KPH_VM_TLS_CREATE_DATA_SECTION\n{\n    NTSTATUS Status;\n    HANDLE SectionHandle;\n    LARGE_INTEGER SectionFileSize;\n    KPROCESSOR_MODE AccessMode;\n} KPH_VM_TLS_CREATE_DATA_SECTION, *PKPH_VM_TLS_CREATE_DATA_SECTION;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ KPH_MEMORY_INFORMATION_CLASS MemoryInformationClass,\n    _Out_writes_bytes_opt_(MemoryInformationLength) PVOID MemoryInformation,\n    _In_ ULONG MemoryInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// hash\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphInitializeHashing(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupHashing(\n    VOID\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphReferenceHashingInfrastructure(\n    VOID\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphDereferenceHashingInfrastructure(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphHashBuffer(\n    _In_ PBYTE Buffer,\n    _In_ ULONG BufferLength,\n    _In_ KPH_HASH_ALGORITHM HashAlgorithm,\n    _Out_ PKPH_HASH_INFORMATION HashInformation\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryHashInformationFile(\n    _In_ HANDLE FileHandle,\n    _Inout_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG HashInformationLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryHashInformationFileObject(\n    _In_ PFILE_OBJECT FileObject,\n    _Inout_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG HashInformationLength\n    );\n\n// kphobject\n\ntypedef struct _KPH_OBJECT_HEADER\n{\n    SSIZE_T PointerCount;\n    UCHAR TypeIndex;\n    SLIST_ENTRY ListEntry;\n    QUAD Body;\n} KPH_OBJECT_HEADER, *PKPH_OBJECT_HEADER;\n\nC_ASSERT((FIELD_OFFSET(KPH_OBJECT_HEADER, Body) % MEMORY_ALLOCATION_ALIGNMENT) == 0);\n\n#define KphObjectToObjectHeader(x) ((PKPH_OBJECT_HEADER)CONTAINING_RECORD((PCHAR)x, KPH_OBJECT_HEADER, Body))\n#define KphObjectHeaderToObject(x) ((PVOID)&((PKPH_OBJECT_HEADER)(x))->Body)\n#define KphAddObjectHeaderSize(x) ((SIZE_T)(x) + FIELD_OFFSET(KPH_OBJECT_HEADER, Body))\n\ntypedef\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_Return_allocatesMem_size_(Size)\nPVOID\nKSIAPI\nKPH_TYPE_ALLOCATE_PROCEDURE(\n    _In_ SIZE_T Size\n    );\ntypedef KPH_TYPE_ALLOCATE_PROCEDURE* PKPH_TYPE_ALLOCATE_PROCEDURE;\n\ntypedef\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_Must_inspect_result_\nNTSTATUS\nKSIAPI\nKPH_TYPE_INITIALIZE_PROCEDURE(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    );\ntypedef KPH_TYPE_INITIALIZE_PROCEDURE* PKPH_TYPE_INITIALIZE_PROCEDURE;\n\ntypedef\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\nVOID\nKSIAPI\nKPH_TYPE_DELETE_PROCEDURE(\n    _Inout_ PVOID Object\n    );\ntypedef KPH_TYPE_DELETE_PROCEDURE* PKPH_TYPE_DELETE_PROCEDURE;\n\ntypedef\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\nVOID\nKSIAPI\nKPH_TYPE_FREE_PROCEDURE(\n    _In_freesMem_ PVOID Object\n    );\ntypedef KPH_TYPE_FREE_PROCEDURE* PKPH_TYPE_FREE_PROCEDURE;\n\ntypedef struct _KPH_OBJECT_TYPE_INFO\n{\n    PKPH_TYPE_ALLOCATE_PROCEDURE Allocate;\n    PKPH_TYPE_INITIALIZE_PROCEDURE Initialize;\n    PKPH_TYPE_DELETE_PROCEDURE Delete;\n    PKPH_TYPE_FREE_PROCEDURE Free;\n\n    union\n    {\n        struct\n        {\n            ULONG DeferDelete : 1;\n            ULONG Spare : 31;\n        };\n\n        ULONG Flags;\n    };\n} KPH_OBJECT_TYPE_INFO, *PKPH_OBJECT_TYPE_INFO;\n\ntypedef struct _KPH_OBJECT_TYPE\n{\n    UNICODE_STRING Name;\n    UCHAR Index;\n    SIZE_T TotalNumberOfObjects;\n    SIZE_T HighWaterNumberOfObjects;\n    KPH_OBJECT_TYPE_INFO TypeInfo;\n} KPH_OBJECT_TYPE, *PKPH_OBJECT_TYPE;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphObjectInitialize(\n    VOID\n    );\n\nVOID KphCreateObjectType(\n    _In_ PCUNICODE_STRING TypeName,\n    _In_ PKPH_OBJECT_TYPE_INFO TypeInfo,\n    _Outptr_ PKPH_OBJECT_TYPE* ObjectType\n    );\n\n_Must_inspect_result_\nNTSTATUS KphCreateObject(\n    _In_ PKPH_OBJECT_TYPE ObjectType,\n    _In_ ULONG ObjectBodySize,\n    _Outptr_result_nullonfailure_ PVOID* Object,\n    _In_opt_ PVOID Parameter\n    );\n\nVOID KphReferenceObject(\n    _In_ PVOID Object\n    );\n\nVOID KphDereferenceObject(\n    _In_ PVOID Object\n    );\n\nVOID KphDereferenceObjectDeferDelete(\n    _In_ PVOID Object\n    );\n\n_Must_inspect_result_\nPKPH_OBJECT_TYPE KphGetObjectType(\n    _In_ PVOID Object\n    );\n\ntypedef struct _KPH_ATOMIC_OBJECT_REF\n{\n    ULONG_PTR Object;\n} KPH_ATOMIC_OBJECT_REF, *PKPH_ATOMIC_OBJECT_REF;\n\n#define KPH_ATOMIC_OBJECT_REF_INIT { .Object = 0 }\n\n_Must_inspect_result_\nPVOID KphAtomicReferenceObject(\n    _In_ PKPH_ATOMIC_OBJECT_REF ObjectRef\n    );\n\nVOID KphAtomicAssignObjectReference(\n    _Inout_ PKPH_ATOMIC_OBJECT_REF ObjectRef,\n    _In_opt_ PVOID Object\n    );\n\n_Must_inspect_result_\nPVOID KphAtomicMoveObjectReference(\n    _Inout_ PKPH_ATOMIC_OBJECT_REF ObjectRef,\n    _In_opt_ PVOID Object\n    );\n\n// cid_table\n\ntypedef struct _KPH_CID_TABLE_ENTRY\n{\n    KPH_ATOMIC_OBJECT_REF ObjectRef;\n} KPH_CID_TABLE_ENTRY, *PKPH_CID_TABLE_ENTRY;\n\ntypedef struct _KPH_CID_TABLE\n{\n    KSPIN_LOCK Lock;\n    ULONG_PTR Table;\n} KPH_CID_TABLE, *PKPH_CID_TABLE;\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCidTableCreate(\n    _Out_ PKPH_CID_TABLE Table\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCidTableDelete(\n    _In_ PKPH_CID_TABLE Table\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCidAssignObject(\n    _Inout_ PKPH_CID_TABLE_ENTRY Entry,\n    _In_opt_ PVOID Object\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPVOID KphCidReferenceObject(\n    _In_ PKPH_CID_TABLE_ENTRY Entry\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_CID_TABLE_ENTRY KphCidGetEntry(\n    _In_ HANDLE Cid,\n    _Inout_ PKPH_CID_TABLE Table\n    );\n\ntypedef\n_Function_class_(KPH_CID_ENUMERATE_CALLBACK)\nBOOLEAN\nKSIAPI\nKPH_CID_ENUMERATE_CALLBACK(\n    _In_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    );\ntypedef KPH_CID_ENUMERATE_CALLBACK* PKPH_CID_ENUMERATE_CALLBACK;\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCidEnumerate(\n    _In_ PKPH_CID_TABLE Table,\n    _In_ PKPH_CID_ENUMERATE_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    );\n\ntypedef\n_Function_class_(KPH_CID_RUNDOWN_CALLBACK)\nVOID\nKSIAPI\nKPH_CID_RUNDOWN_CALLBACK(\n    _In_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    );\ntypedef KPH_CID_RUNDOWN_CALLBACK* PKPH_CID_RUNDOWN_CALLBACK;\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphCidRundown(\n    _In_ PKPH_CID_TABLE Table,\n    _In_ PKPH_CID_RUNDOWN_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    );\n\n// cid_tracking\n\n#define KPH_PROTECTED_PROCESS_MASK (KPH_PROCESS_READ_ACCESS                   |\\\n                                    PROCESS_TERMINATE                         |\\\n                                    PROCESS_SUSPEND_RESUME)\n#define KPH_PROTECTED_THREAD_MASK  (KPH_THREAD_READ_ACCESS                    |\\\n                                    THREAD_TERMINATE                          |\\\n                                    THREAD_SUSPEND_RESUME                     |\\\n                                    THREAD_RESUME)\n\ntypedef union _KPH_SESSION_TOKEN_ATOMIC\n{\n    struct _KPH_SESSION_TOKEN* Token;\n    KPH_ATOMIC_OBJECT_REF Atomic;\n} KPH_SESSION_TOKEN_ATOMIC, *PKPH_SESSION_TOKEN_ATOMIC;\n\ntypedef union _KPH_INFORMER_STATE_ATOMIC\n{\n    struct _KPH_INFORMER_STATE* State;\n    KPH_ATOMIC_OBJECT_REF Atomic;\n} KPH_INFORMER_STATE_ATOMIC, *PKPH_INFORMER_STATE_ATOMIC;\n\ntypedef struct _KPH_PROCESS_CONTEXT\n{\n    PEPROCESS EProcess;\n\n    HANDLE ProcessId;\n    ULONG64 SequenceNumber;\n    ULONG64 ProcessStartKey;\n    CLIENT_ID CreatorClientId;\n\n    PUNICODE_STRING ImageFileName;\n    UNICODE_STRING ImageName;\n    PFILE_OBJECT FileObject;\n\n    SIZE_T NumberOfImageLoads;\n\n    KPH_SESSION_TOKEN_ATOMIC SessionToken;\n    KPH_INFORMER_STATE_ATOMIC InformerState;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG CreateNotification : 1;\n            ULONG ExitNotification : 1;\n            ULONG VerifiedProcess : 1;\n            ULONG SecurelyCreated : 1;\n            ULONG Protected : 1;\n            ULONG IsWow64 : 1;\n            ULONG IsSubsystemProcess : 1;\n            ULONG AllocatedImageName : 1;\n            ULONG SystemAllocatedImageFileName : 1;\n            ULONG Reserved : 23;\n        };\n    };\n\n    KPH_RWLOCK ThreadListLock;\n    struct _KPH_THREAD_CONTEXT* InitialThread;\n    SIZE_T NumberOfThreads;\n    LIST_ENTRY ThreadListHead;\n    SIZE_T NumberOfUnlinkedThreads;\n\n    //\n    // Masks are only valid if Protected flag is set.\n    //\n    KPH_RWLOCK ProtectionLock;\n    ACCESS_MASK ProcessAllowedMask;\n    ACCESS_MASK ThreadAllowedMask;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Debugged : 1;\n            ULONG FileObjectWritable : 1;\n            ULONG FileObjectTransaction : 1;\n            ULONG UserWritableReferences : 1;\n            ULONG Reserved : 28;\n        };\n    } StateTracking;\n\n    //\n    // Only tracked for verified processes.\n    //\n    SIZE_T NumberOfMicrosoftImageLoads;\n    SIZE_T NumberOfAntimalwareImageLoads;\n    SIZE_T NumberOfVerifiedImageLoads;\n    SIZE_T NumberOfUntrustedImageLoads;\n\n    PKNORMAL_ROUTINE ApcNoopRoutine;\n\n    SUBSYSTEM_INFORMATION_TYPE SubsystemType;\n\n    //\n    // SubsystemInformationTypeWSL information\n    //\n    struct\n    {\n        BOOLEAN ValidProcessId;\n        ULONG ProcessId;\n    } WSL;\n} KPH_PROCESS_CONTEXT, *PKPH_PROCESS_CONTEXT;\n\nextern PKPH_OBJECT_TYPE KphProcessContextType;\n\ntypedef enum _KPH_PROCESS_CONTEXT_INFORMATION_CLASS\n{\n    KphProcessContextWSLProcessId, // q: ULONG\n} KPH_PROCESS_CONTEXT_INFORMATION_CLASS, *PKPH_PROCESS_CONTEXT_INFORMATION_CLASS;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationProcessContext(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_ KPH_PROCESS_CONTEXT_INFORMATION_CLASS InformationClass,\n    _Out_writes_bytes_opt_(InformationLength) PVOID Information,\n    _In_ ULONG InformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\ntypedef struct _KPH_THREAD_CONTEXT\n{\n    PETHREAD EThread;\n\n    PKPH_PROCESS_CONTEXT ProcessContext;\n\n    CLIENT_ID ClientId;\n    CLIENT_ID CreatorClientId;\n\n    PVOID SubProcessTag;\n\n    KPH_SESSION_TOKEN_ATOMIC SessionToken;\n    KPH_SESSION_TOKEN_ATOMIC RequestSessionToken;\n\n    union\n    {\n        volatile ULONG Flags;\n        struct\n        {\n            ULONG CreateNotification : 1;\n            ULONG ExecuteNotification : 1;\n            ULONG ExitNotification : 1;\n            ULONG InThreadList : 1;\n            ULONG IsCreatingProcess : 1;\n            ULONG CapturingUserModeStack : 1;\n            ULONG Reserved : 26;\n        };\n    };\n\n    LIST_ENTRY ThreadListEntry;\n\n    //\n    // Only valid if IsCreatingProcess flag is set.\n    //\n    HANDLE IsCreatingProcessId;\n\n    SUBSYSTEM_INFORMATION_TYPE SubsystemType;\n\n    //\n    // SubsystemInformationTypeWSL information\n    //\n    struct\n    {\n        BOOLEAN ValidThreadId;\n        ULONG ThreadId;\n    } WSL;\n\n    PVOID VmTlsCreateDataSection;\n    PVOID VmTlsMappedInformation;\n} KPH_THREAD_CONTEXT, *PKPH_THREAD_CONTEXT;\n\nextern PKPH_OBJECT_TYPE KphThreadContextType;\n\ntypedef enum _KPH_THREAD_CONTEXT_INFORMATION_CLASS\n{\n    KphThreadContextWSLThreadId,  // q: ULONG\n} KPH_THREAD_CONTEXT_INFORMATION_CLASS, *PKPH_THREAD_CONTEXT_INFORMATION_CLASS;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationThreadContext(\n    _In_ PKPH_THREAD_CONTEXT Thread,\n    _In_ KPH_THREAD_CONTEXT_INFORMATION_CLASS InformationClass,\n    _Out_writes_bytes_opt_(InformationLength) PVOID Information,\n    _In_ ULONG InformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCidInitialize(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCidPopulate(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCidCleanup(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCidMarkPopulated(\n    VOID\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphGetSystemProcessContext(\n    VOID\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphGetProcessContext(\n    _In_ HANDLE ProcessId\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphGetEProcessContext(\n    _In_ PEPROCESS Process\n    );\n\n#define KphGetCurrentProcessContext() KphGetEProcessContext(PsGetCurrentProcess())\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nPKPH_THREAD_CONTEXT KphGetThreadContext(\n    _In_ HANDLE ThreadId\n    );\n\n#define KphGetEThreadContext(thread) KphGetThreadContext(PsGetThreadId(thread))\n\n#define KphGetCurrentThreadContext() KphGetThreadContext(PsGetCurrentThreadId())\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphTrackProcessContext(\n    _In_ PEPROCESS Process\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphUntrackProcessContext(\n    _In_ HANDLE ProcessId\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nPKPH_THREAD_CONTEXT KphTrackThreadContext(\n    _In_ PETHREAD Thread\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nPKPH_THREAD_CONTEXT KphUntrackThreadContext(\n    _In_ HANDLE ThreadId\n    );\n\ntypedef\n_Function_class_(KPH_ENUM_PROCESS_CONTEXTS_CALLBACK)\n_Must_inspect_result_\nBOOLEAN\nKSIAPI\nKPH_ENUM_PROCESS_CONTEXTS_CALLBACK(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_opt_ PVOID Parameter\n    );\ntypedef KPH_ENUM_PROCESS_CONTEXTS_CALLBACK* PKPH_ENUM_PROCESS_CONTEXTS_CALLBACK;\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphEnumerateProcessContexts(\n    _In_ PKPH_ENUM_PROCESS_CONTEXTS_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    );\n\ntypedef\n_Function_class_(KPH_ENUM_THREAD_CONTEXTS_CALLBACK)\n_Must_inspect_result_\nBOOLEAN\nKSIAPI\nKPH_ENUM_THREAD_CONTEXTS_CALLBACK(\n    _In_ PKPH_PROCESS_CONTEXT Thread,\n    _In_opt_ PVOID Parameter\n    );\ntypedef KPH_ENUM_THREAD_CONTEXTS_CALLBACK* PKPH_ENUM_THREAD_CONTEXTS_CALLBACK;\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphEnumerateThreadContexts(\n    _In_ PKPH_ENUM_THREAD_CONTEXTS_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    );\n\ntypedef\n_Function_class_(KPH_ENUM_CID_CONTEXTS_CALLBACK)\n_Must_inspect_result_\nBOOLEAN\nKSIAPI\nKPH_ENUM_CID_CONTEXTS_CALLBACK(\n    _In_ PVOID Context,\n    _In_opt_ PVOID Parameter\n    );\ntypedef KPH_ENUM_CID_CONTEXTS_CALLBACK* PKPH_ENUM_CID_CONTEXTS_CALLBACK;\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphEnumerateCidContexts(\n    _In_ KPH_ENUM_CID_CONTEXTS_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCheckProcessApcNoopRoutine(\n    _In_ PKPH_PROCESS_CONTEXT ProcessContext\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphVerifyProcessAndProtectIfAppropriate(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\n_Maybenull_\nPUNICODE_STRING KphGetThreadImageName(\n    _In_ PKPH_THREAD_CONTEXT Thread\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nKPH_PROCESS_STATE KphGetProcessState(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nFORCEINLINE\nBOOLEAN KphTestProcessState(\n    _In_ KPH_PROCESS_STATE ProcessState,\n    _In_ KPH_PROCESS_STATE State\n    )\n{\n    return ((ProcessState & State) == State);\n}\n\n_IRQL_requires_max_(APC_LEVEL)\nFORCEINLINE\nBOOLEAN KphTestProcessContextState(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_ KPH_PROCESS_STATE State\n    )\n{\n    return KphTestProcessState(KphGetProcessState(Process), State);\n}\n\n// protection\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeProtection(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphStartProtectingProcess(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_ ACCESS_MASK ProcessAllowedMask,\n    _In_ ACCESS_MASK ThreadAllowedMask\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphStopProtectingProcess(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nBOOLEAN KphIsProtectedProcess(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphApplyObProtections(\n    _Inout_ POB_PRE_OPERATION_INFORMATION Info\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphApplyImageProtections(\n    _Inout_ PKPH_PROCESS_CONTEXT Process,\n    _In_ PIMAGE_INFO_EX ImageInfo\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAcquireDriverUnloadProtection(\n    _Out_opt_ PLONG PreviousCount\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReleaseDriverUnloadProtection(\n    _Out_opt_ PLONG PreviousCount\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nLONG KphGetDriverUnloadProtectionCount(\n    VOID\n    );\n\nFORCEINLINE\nBOOLEAN KphIsDriverUnloadProtected(\n    VOID\n    )\n{\n    return (KphGetDriverUnloadProtectionCount() > 0);\n}\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphStripProtectedProcessMasks(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK ProcessAllowedMask,\n    _In_ ACCESS_MASK ThreadAllowedMask,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// imgcoherency\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCheckImageCoherency(\n    _In_ PVOID ImageBase,\n    _In_ SIZE_T ImageSize,\n    _In_ PVOID DataBase,\n    _In_ SIZE_T DataSize\n    );\n\n// verify\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphVerifyCloseKey(\n    _In_ BCRYPT_KEY_HANDLE KeyHandle\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyCreateKey(\n    _Out_ BCRYPT_KEY_HANDLE* KeyHandle,\n    _In_ PBYTE KeyMaterial,\n    _In_ ULONG KeyMaterialLength\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyBufferEx(\n    _In_opt_ BCRYPT_KEY_HANDLE KeyHandle,\n    _In_ PBYTE Buffer,\n    _In_ ULONG BufferLength,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyBuffer(\n    _In_ PBYTE Buffer,\n    _In_ ULONG BufferLength,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyFileObject(\n    _In_ PFILE_OBJECT FileObject,\n    _In_opt_ PCUNICODE_STRING FileName\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyFile(\n    _In_ PCUNICODE_STRING FileName,\n    _In_opt_ PFILE_OBJECT FileObject\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphInitializeVerify(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupVerify(\n    VOID\n    );\n\n// ksi.dll\n\n#if !defined(_KSIDLL_)\n#define KSISYSAPI DECLSPEC_IMPORT\n#else\n#define KSISYSAPI\n#endif\n\n#define KSIDLL_CURRENT_VERSION 1\n\nKSISYSAPI\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS\nKSIAPI\nKsiInitialize(\n    _In_ ULONG Version,\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_opt_ PVOID Reserved\n    );\n\nKSISYSAPI\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID\nKSIAPI\nKsiUninitialize(\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ ULONG Reserved\n    );\n\ntypedef struct _KSI_KAPC\n{\n    KAPC Apc;\n    PDRIVER_OBJECT DriverObject;\n    PVOID InternalRoutine;\n    PVOID InternalCleanup;\n    PVOID InternalContext;\n} KSI_KAPC, *PKSI_KAPC;\n\ntypedef enum _KSI_KAPC_CLEANUP_REASON\n{\n    KsiApcCleanupKernel,\n    KsiApcCleanupNormal,\n    KsiApcCleanupRundown,\n    KsiApcCleanupRemoved\n} KSI_KAPC_CLEANUP_REASON;\n\ntypedef\n_Function_class_(KSI_KCLEANUP_ROUTINE)\n_IRQL_requires_min_(PASSIVE_LEVEL)\n_IRQL_requires_max_(APC_LEVEL)\n_IRQL_requires_same_\nVOID\nKSIAPI\nKSI_KCLEANUP_ROUTINE(\n    _In_ PKSI_KAPC Apc,\n    _In_ KSI_KAPC_CLEANUP_REASON Reason\n    );\ntypedef KSI_KCLEANUP_ROUTINE *PKSI_KCLEANUP_ROUTINE;\n\ntypedef\n_Function_class_(KSI_KKERNEL_ROUTINE)\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID\nKSIAPI\nKSI_KKERNEL_ROUTINE(\n    _In_ PKSI_KAPC Apc,\n    _Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE* NormalRoutine,\n    _Inout_ _Deref_pre_maybenull_ PVOID* NormalContext,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument1,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2\n    );\ntypedef KSI_KKERNEL_ROUTINE *PKSI_KKERNEL_ROUTINE;\n\nC_ASSERT(FIELD_OFFSET(KSI_KAPC, Apc) == 0);\n\nKSISYSAPI\nVOID\nKSIAPI\nKsiInitializeApc(\n    _Out_ PKSI_KAPC Apc,\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PRKTHREAD Thread,\n    _In_ KAPC_ENVIRONMENT Environment,\n    _In_ PKSI_KKERNEL_ROUTINE KernelRoutine,\n    _In_ PKSI_KCLEANUP_ROUTINE CleanupRoutine,\n    _In_opt_ PKNORMAL_ROUTINE NormalRoutine,\n    _In_ KPROCESSOR_MODE ApcMode,\n    _In_opt_ PVOID NormalContext\n    );\n\nKSISYSAPI\nBOOLEAN\nKSIAPI\nKsiInsertQueueApc(\n    _Inout_ PKSI_KAPC Apc,\n    _In_opt_ PVOID SystemArgument1,\n    _In_opt_ PVOID SystemArgument2,\n    _In_ KPRIORITY PriorityBoost\n    );\n\nKSISYSAPI\nNTSTATUS\nKSIAPI\nKsiRemoveQueueApc(\n    _Inout_ PKSI_KAPC Apc\n    );\n\ntypedef\n_Function_class_(KSI_WORK_QUEUE_ROUTINE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID\nKSIAPI\nKSI_WORK_QUEUE_ROUTINE(\n    _In_opt_ PVOID Parameter\n    );\ntypedef KSI_WORK_QUEUE_ROUTINE *PKSI_WORK_QUEUE_ROUTINE;\n\ntypedef struct _KSI_WORK_QUEUE_ITEM\n{\n    WORK_QUEUE_ITEM WorkItem;\n    PDRIVER_OBJECT DriverObject;\n    PKSI_WORK_QUEUE_ROUTINE Routine;\n    PVOID Parameter;\n} KSI_WORK_QUEUE_ITEM, *PKSI_WORK_QUEUE_ITEM;\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nKSISYSAPI\nVOID\nKSIAPI\nKsiInitializeWorkItem(\n    _Out_ PKSI_WORK_QUEUE_ITEM WorkItem,\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PKSI_WORK_QUEUE_ROUTINE Routine,\n    _In_opt_ PVOID Parameter\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nKSISYSAPI\nVOID\nKSIAPI\nKsiQueueWorkItem(\n    _Inout_ PKSI_WORK_QUEUE_ITEM WorkItem,\n    _In_ WORK_QUEUE_TYPE QueueType\n    );\n\nextern KSISYSAPI PEPROCESS KsiSystemProcess;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nKSISYSAPI\nNTSTATUS\nKSIAPI\nKsiInitializeSystemProcess(\n    _In_ PCUNICODE_STRING ProcessName\n    );\n\n// system\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSystemControl(\n    _In_ KPH_SYSTEM_CONTROL_CLASS SystemControlClass,\n    _In_reads_bytes_(SystemControlInfoLength) PVOID SystemControlInfo,\n    _In_ ULONG SystemControlInfoLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// alpc\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAlpcQueryInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE PortHandle,\n    _In_ KPH_ALPC_INFORMATION_CLASS AlpcInformationClass,\n    _Out_writes_bytes_opt_(AlpcInformationLength) PVOID AlpcInformation,\n    _In_ ULONG AlpcInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// file\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationFile(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_writes_bytes_(FileInformationLength) PVOID FileInformation,\n    _In_ ULONG FileInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryVolumeInformationFile(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FS_INFORMATION_CLASS FsInformationClass,\n    _Out_writes_bytes_(FsInformationLength) PVOID FsInformation,\n    _In_ ULONG FsInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCreateFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,\n    _In_ ULONG EaLength,\n    _In_ ULONG Options,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// knowndll\n\nextern PVOID KphNtDllBaseAddress;\nextern PVOID KphNtDllRtlSetBits;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphInitializeKnownDll(\n    VOID\n    );\n\n// back_trace\n\n#define KPH_STACK_BACK_TRACE_USER_MODE   0x00000001ul\n#define KPH_STACK_BACK_TRACE_SKIP_KPH    0x00000002ul\n#define KPH_STACK_BACK_TRACE_NO_SENTINEL 0x00000004ul\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphInitializeStackBackTrace(\n    VOID\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Success_(return != 0)\nULONG KphCaptureStackBackTrace(\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID* BackTrace,\n    _Out_opt_ PULONG BackTraceHash,\n    _In_ ULONG Flags\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCaptureStackBackTraceThread(\n    _In_ PETHREAD Thread,\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID* BackTrace,\n    _Out_ PULONG CapturedFrames,\n    _Out_opt_ PULONG BackTraceHash,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n// session_token\n\ntypedef struct _KPH_SESSION_TOKEN\n{\n    KPH_SESSION_ACCESS_TOKEN AccessToken;\n    LONG UseCount;\n} KPH_SESSION_TOKEN, *PKPH_SESSION_TOKEN;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphRequestSessionAccessToken(\n    _Out_ PKPH_SESSION_ACCESS_TOKEN AccessToken,\n    _In_ PLARGE_INTEGER Expiry,\n    _In_ ULONG Privileges,\n    _In_ LONG Uses\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAssignProcessSessionToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAssignThreadSessionToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphSessionTokenPrivilegeCheck(\n    _In_ PKPH_THREAD_CONTEXT Thread,\n    _In_ ULONG Privileges\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeSessionToken(\n    VOID\n    );\n\n// ringbuff\n\ntypedef struct _KPH_RING_SECTION\n{\n    PVOID SectionObject;\n    PMDL Mdl;\n    PVOID KernelBase;\n} KPH_RING_SECTION, *PKPH_RING_SECTION;\n\ntypedef struct _KPH_RING_BUFFER\n{\n    KSPIN_LOCK ProducerLock;\n    PULONG ProducerPos;\n    PULONG ConsumerPos;\n    PULONG ConsumerProcessing;\n    ULONG Length;\n    PVOID Buffer;\n    PKEVENT Event;\n    KPH_RING_SECTION ProducerSection;\n    KPH_RING_SECTION ConsumerSection;\n    PEPROCESS Process;\n} KPH_RING_BUFFER, *PKPH_RING_BUFFER;\n\n_Return_allocatesMem_size_(Length)\nPVOID KphReserveRingBuffer(\n    _In_ PKPH_RING_BUFFER Ring,\n    _In_ ULONG Length\n    );\n\nVOID KphCommitRingBuffer(\n    _In_ PKPH_RING_BUFFER Ring,\n    _In_freesMem_ PVOID Buffer\n    );\n\nVOID KphDiscardRingBuffer(\n    _In_ PKPH_RING_BUFFER Ring,\n    _In_freesMem_ PVOID Buffer\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCreateRingBuffer(\n    _Out_ PKPH_RING_BUFFER* Ring,\n    _Out_ PKPH_RING_BUFFER_USER User,\n    _In_ ULONG Length,\n    _In_opt_ PKEVENT Event,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeRingBuffer(\n    VOID\n    );\n\n// kphthread\n\ntypedef\n_Function_class_(KPH_THREAD_START_ROUTINE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nNTSTATUS\nKPH_THREAD_START_ROUTINE(\n    _In_opt_ PVOID Parameter\n    );\ntypedef KPH_THREAD_START_ROUTINE *PKPH_THREAD_START_ROUTINE;\n\n#define KPH_CREATE_SYSTEM_THREAD_IN_KSI_PROCESS 0x00000001ul\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphCreateSystemThread(\n    _Out_opt_ PHANDLE ThreadHandle,\n    _Out_opt_ PETHREAD* ThreadObject,\n    _In_ PKPH_THREAD_START_ROUTINE StartRoutine,\n    _In_opt_ _When_(return >= 0, __drv_aliasesMem) PVOID Parameter,\n    _In_opt_ PCUNICODE_STRING ThreadName,\n    _In_ ULONG Flags\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupThreading(\n    VOID\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeThreading(\n    VOID\n    );\n\n// umaccess\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCaptureUnicodeString(\n    _In_ PUNICODE_STRING UnicodeString,\n    _Out_ PUNICODE_STRING* CapturedUnicodeString\n    );\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphReleaseUnicodeString(\n    _In_ PUNICODE_STRING UnicodeString\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphZeroModeMemory(\n    _Out_writes_bytes_all_(Length) PVOID Destination,\n    _In_ SIZE_T Length,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphCopyToMode(\n    _Out_writes_bytes_all_(Length) PVOID Destination,\n    _In_reads_bytes_(Length) PVOID Source,\n    _In_ SIZE_T Length,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCopyFromMode(\n    _Out_writes_bytes_all_(Length) PVOID Destination,\n    _In_reads_bytes_(Length) PVOID Source,\n    _In_ SIZE_T Length,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteUCharToMode(\n    _Out_ PUCHAR Destination,\n    _In_ UCHAR Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteULongToMode(\n    _Out_ PULONG Destination,\n    _In_ ULONG Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteULong64ToMode(\n    _Out_ PULONG64 Destination,\n    _In_ ULONG64 Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteLong64ToMode(\n    _Out_ PLONG64 Destination,\n    _In_ LONG64 Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteSizeTToMode(\n    _Out_ PSIZE_T Destination,\n    _In_ SIZE_T Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWritePointerToMode(\n    _Out_ PVOID* Destination,\n    _In_ PVOID Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteHandleToMode(\n    _Out_ PHANDLE Destination,\n    _In_ _Post_ptr_invalid_ HANDLE Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphCopyUnicodeStringToMode(\n    _Out_writes_bytes_opt_(Length) PVOID Destination,\n    _In_ SIZE_T Length,\n    _In_opt_ PCUNICODE_STRING String,\n    _Out_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReadLargeIntegerFromMode(\n    _Out_ PLARGE_INTEGER Destination,\n    _In_ PLARGE_INTEGER Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\n// ratelmt\n\ntypedef union _KPH_RATE_BUCKET\n{\n    struct\n    {\n        ULONG CurrentTokens;\n        ULONG LastRefillTime;\n    };\n\n    LONG64 Quad;\n} KPH_RATE_BUCKET, *PKPH_RATE_BUCKET;\n\ntypedef struct _KPH_RATE_LIMIT\n{\n    KPH_RATE_BUCKET Bucket;\n    KPH_RATE_LIMIT_POLICY Policy;\n    LONG64 Allowed;\n    LONG64 Dropped;\n    LONG64 CasMiss;\n} KPH_RATE_LIMIT, *PKPH_RATE_LIMIT;\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphInitializeRateLimit(\n    _In_ PCKPH_RATE_LIMIT_POLICY Policy,\n    _In_ PLARGE_INTEGER TimeStamp,\n    _Out_ PKPH_RATE_LIMIT RateLimit\n    );\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphRateLimitConsumeToken(\n    _Inout_ PKPH_RATE_LIMIT RateLimit,\n    _In_ PLARGE_INTEGER TimeStamp\n    );\n"
  },
  {
    "path": "KSystemInformer/include/ntfill.h",
    "content": "/*\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n\ntypedef struct _CLIENT_ID32\n{\n    ULONG UniqueProcess;\n    ULONG UniqueThread;\n} CLIENT_ID32, *PCLIENT_ID32;\n\ntypedef struct _CLIENT_ID64\n{\n    ULONGLONG UniqueProcess;\n    ULONGLONG UniqueThread;\n} CLIENT_ID64, *PCLIENT_ID64;\n\ntypedef const STRING32 *PCUNICODE_STRING32;\n\n// EX\n\ntypedef struct _EX_FAST_REF\n{\n    union\n    {\n        PVOID Object;\n        ULONG_PTR RefCnt : 4;\n        ULONG_PTR Value;\n    };\n} EX_FAST_REF, *PEX_FAST_REF;\n\ntypedef struct _EX_PUSH_LOCK_WAIT_BLOCK *PEX_PUSH_LOCK_WAIT_BLOCK;\n\nNTKERNELAPI\nVOID\nFASTCALL\nExfUnblockPushLock(\n    _Inout_ PEX_PUSH_LOCK PushLock,\n    _Inout_opt_ PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock\n    );\n\n/*\n0:000> dt ntoskrnl!_HANDLE_TABLE_ENTRY\n   +0x000 VolatileLowValue : Int8B\n   +0x000 LowValue         : Int8B\n   +0x000 InfoTable        : Ptr64 _HANDLE_TABLE_ENTRY_INFO\n   +0x008 HighValue        : Int8B\n   +0x008 NextFreeHandleEntry : Ptr64 _HANDLE_TABLE_ENTRY\n   +0x008 LeafHandleValue  : _EXHANDLE\n   +0x000 RefCountField    : Int8B\n   +0x000 Unlocked         : Pos 0, 1 Bit\n   +0x000 RefCnt           : Pos 1, 16 Bits\n   +0x000 Attributes       : Pos 17, 3 Bits\n   +0x000 ObjectPointerBits : Pos 20, 44 Bits\n   +0x008 GrantedAccessBits : Pos 0, 25 Bits\n   +0x008 NoRightsUpgrade  : Pos 25, 1 Bit\n   +0x008 Spare1           : Pos 26, 6 Bits\n   +0x00c Spare2           : Uint4B\n\n0:000> dt ntkrla57!_HANDLE_TABLE_ENTRY\n   +0x000 VolatileLowValue : Int8B\n   +0x000 LowValue         : Int8B\n   +0x000 InfoTable        : Ptr64 _HANDLE_TABLE_ENTRY_INFO\n   +0x008 HighValue        : Int8B\n   +0x008 NextFreeHandleEntry : Ptr64 _HANDLE_TABLE_ENTRY\n   +0x008 LeafHandleValue  : _EXHANDLE\n   +0x000 RefCountField    : Int8B\n   +0x000 Unlocked         : Pos 0, 1 Bit\n   +0x000 RefCnt           : Pos 1, 7 Bits\n   +0x000 Attributes       : Pos 8, 3 Bits\n   +0x000 ObjectPointerBits : Pos 11, 53 Bits\n   +0x008 GrantedAccessBits : Pos 0, 25 Bits\n   +0x008 NoRightsUpgrade  : Pos 25, 1 Bit\n   +0x008 Spare1           : Pos 26, 6 Bits\n   +0x00c Spare2           : Uint4B\n*/\n//\n// N.B. We define HANDLE_TABLE_ENTRY this way to allow for dynamic data to\n// support different kernels (see above). The number of ObjectPointerBits are\n// different for LA57.\n//\ntypedef struct _HANDLE_TABLE_ENTRY\n{\n    union\n    {\n        PVOID Object;\n        ULONG ObAttributes;\n        ULONG_PTR Value;\n    };\n    union\n    {\n        ACCESS_MASK GrantedAccess;\n        LONG NextFreeTableEntry;\n    };\n} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;\n\ntypedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE;\n\ntypedef\n_Function_class_(EX_ENUM_HANDLE_CALLBACK)\n_Must_inspect_result_\nBOOLEAN\nNTAPI\nEX_ENUM_HANDLE_CALLBACK(\n    _In_ PHANDLE_TABLE HandleTable,\n    _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,\n    _In_ HANDLE Handle,\n    _In_opt_ PVOID Context\n    );\ntypedef EX_ENUM_HANDLE_CALLBACK* PEX_ENUM_HANDLE_CALLBACK;\n\nNTKERNELAPI\nBOOLEAN\nNTAPI\nExEnumHandleTable(\n    _In_ PHANDLE_TABLE HandleTable,\n    _In_ PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,\n    _Inout_ PVOID Context,\n    _Out_opt_ PHANDLE Handle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySystemInformation(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySection(\n    _In_ HANDLE SectionHandle,\n    _In_ SECTION_INFORMATION_CLASS SectionInformationClass,\n    _Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation,\n    _In_ SIZE_T SectionInformationLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\n// IO\n\nextern POBJECT_TYPE *IoDriverObjectType;\nextern POBJECT_TYPE *IoDeviceObjectType;\n\ntypedef\n_Function_class_(IO_CHECK_FILE_OBJECT_OPENED_AS_COPY_SOURCE)\nBOOLEAN\nNTAPI\nIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_SOURCE(\n    _In_ PFILE_OBJECT FileObject\n    );\ntypedef IO_CHECK_FILE_OBJECT_OPENED_AS_COPY_SOURCE* PIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_SOURCE;\n\ntypedef\n_Function_class_(IO_CHECK_FILE_OBJECT_OPENED_AS_COPY_DESTINATION)\nBOOLEAN\nIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_DESTINATION(\n    _In_ PFILE_OBJECT FileObject\n    );\ntypedef IO_CHECK_FILE_OBJECT_OPENED_AS_COPY_DESTINATION* PIO_CHECK_FILE_OBJECT_OPENED_AS_COPY_DESTINATION;\n\ntypedef struct _COPY_INFORMATION\n{\n    PFILE_OBJECT SourceFileObject;\n    LONGLONG SourceFileOffset;\n} COPY_INFORMATION, *PCOPY_INFORMATION;\n\ntypedef\n_Function_class_(IO_GET_COPY_INFORMATION_EXTENSION)\nNTSTATUS\nIO_GET_COPY_INFORMATION_EXTENSION(\n    _In_ PIRP Irp,\n    _Out_ PCOPY_INFORMATION CopyInformation\n    );\ntypedef IO_GET_COPY_INFORMATION_EXTENSION* PIO_GET_COPY_INFORMATION_EXTENSION;\n\n// FLT\n\ntypedef\n_Function_class_(FLT_GET_COPY_INFORMATION_FROM_CALLBACK_DATA)\n_IRQL_requires_max_(DISPATCH_LEVEL)\nNTSTATUS\nFLTAPI\nFLT_GET_COPY_INFORMATION_FROM_CALLBACK_DATA(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _Out_ PCOPY_INFORMATION CopyInformation\n    );\ntypedef FLT_GET_COPY_INFORMATION_FROM_CALLBACK_DATA* PFLT_GET_COPY_INFORMATION_FROM_CALLBACK_DATA;\n\n// KE\n\ntypedef enum _KAPC_ENVIRONMENT\n{\n    OriginalApcEnvironment,\n    AttachedApcEnvironment,\n    CurrentApcEnvironment,\n    InsertApcEnvironment\n} KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT;\n\ntypedef\n_Function_class_(KNORMAL_ROUTINE)\n_IRQL_requires_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID\nNTAPI\nKNORMAL_ROUTINE(\n    _In_opt_ PVOID NormalContext,\n    _In_opt_ PVOID SystemArgument1,\n    _In_opt_ PVOID SystemArgument2\n    );\ntypedef KNORMAL_ROUTINE *PKNORMAL_ROUTINE;\n\ntypedef\n_Function_class_(KRUNDOWN_ROUTINE)\n_IRQL_requires_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID\nNTAPI\nKRUNDOWN_ROUTINE(\n    _In_ PRKAPC Apc\n    );\ntypedef KRUNDOWN_ROUTINE *PKRUNDOWN_ROUTINE;\n\ntypedef\n_Function_class_(KKERNEL_ROUTINE)\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID\nNTAPI\nKKERNEL_ROUTINE(\n    _In_ PRKAPC Apc,\n    _Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE *NormalRoutine,\n    _Inout_ _Deref_pre_maybenull_ PVOID* NormalContext,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument1,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2\n    );\ntypedef KKERNEL_ROUTINE *PKKERNEL_ROUTINE;\n\nNTKERNELAPI\nVOID\nNTAPI\nKeInitializeApc(\n    _Out_ PRKAPC Apc,\n    _In_ PRKTHREAD Thread,\n    _In_ KAPC_ENVIRONMENT Environment,\n    _In_ PKKERNEL_ROUTINE KernelRoutine,\n    _In_opt_ PKRUNDOWN_ROUTINE RundownRoutine,\n    _In_opt_ PKNORMAL_ROUTINE NormalRoutine,\n    _In_ KPROCESSOR_MODE Mode,\n    _In_opt_ PVOID NormalContext\n    );\n\nNTKERNELAPI\nBOOLEAN\nNTAPI\nKeInsertQueueApc(\n    _Inout_ PRKAPC Apc,\n    _In_opt_ PVOID SystemArgument1,\n    _In_opt_ PVOID SystemArgument2,\n    _In_ KPRIORITY Increment\n    );\n\nNTKERNELAPI\nBOOLEAN\nNTAPI\nKeTestAlertThread(\n    _In_ KPROCESSOR_MODE Mode\n    );\n\ntypedef\n_Function_class_(KE_REMOVE_QUEUE_APC)\nBOOLEAN\nNTAPI\nKE_REMOVE_QUEUE_APC(\n    _Inout_ PKAPC Apc\n    );\ntypedef KE_REMOVE_QUEUE_APC* PKE_REMOVE_QUEUE_APC;\n\n// OB\n\n// These definitions are no longer correct, but they produce correct results.\n\n#define OBJ_PROTECT_CLOSE 0x00000001\n#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)\n\n// This attribute is now stored in the GrantedAccess field.\n#define ObpAccessProtectCloseBit 0x2000000\n\n// GrantedAccess in the table entry is the low 25 bits\n#define OBJ_GRANTED_ACCESS_MASK 0x01ffffff\n\n#define ObpDecodeGrantedAccess(Access) ((Access) & OBJ_GRANTED_ACCESS_MASK)\n\nFORCEINLINE\nVOID\nObpSetGrantedAccess(\n    _Inout_ PACCESS_MASK GrantedAccess,\n    _In_ ACCESS_MASK Access\n    )\n{\n    //\n    // Preserve the high bits and only set the low 25 bits.\n    //\n    *GrantedAccess = (Access | (*GrantedAccess & ~OBJ_GRANTED_ACCESS_MASK));\n}\n\ntypedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION;\n\ntypedef struct _OBJECT_HEADER\n{\n    SSIZE_T PointerCount;\n    union\n    {\n        SSIZE_T HandleCount;\n        PVOID NextToFree;\n    };\n    EX_PUSH_LOCK Lock;\n    UCHAR TypeIndex;\n    union\n    {\n        UCHAR TraceFlags;\n        struct\n        {\n            UCHAR DbgRefTrace : 1;\n            UCHAR DbgTracePermanent : 1;\n        };\n    };\n    UCHAR InfoMask;\n    union\n    {\n        UCHAR Flags;\n        struct\n        {\n            UCHAR NewObject : 1;\n            UCHAR KernelObject : 1;\n            UCHAR KernelOnlyAccess : 1;\n            UCHAR ExclusiveObject : 1;\n            UCHAR PermanentObject : 1;\n            UCHAR DefaultSecurityQuota : 1;\n            UCHAR SingleHandleEntry : 1;\n            UCHAR DeletedInline : 1;\n        };\n    };\n#ifdef _WIN64\n    ULONG Reserved;\n#endif\n    union\n    {\n        POBJECT_CREATE_INFORMATION ObjectCreateInfo;\n        PVOID QuotaBlockCharged;\n    };\n    PVOID SecurityDescriptor;\n    QUAD Body;\n} OBJECT_HEADER, *POBJECT_HEADER;\n\n#if defined(_M_X64) || defined(_M_ARM64)\nC_ASSERT(FIELD_OFFSET(OBJECT_HEADER, Body) == 0x030);\nC_ASSERT(sizeof(OBJECT_HEADER) == 0x038);\n#else\nC_ASSERT(FIELD_OFFSET(OBJECT_HEADER, Body) == 0x018);\nC_ASSERT(sizeof(OBJECT_HEADER) == 0x020);\n#endif\n\n#define OBJECT_TO_OBJECT_HEADER(Object) CONTAINING_RECORD((Object), OBJECT_HEADER, Body)\n\nNTKERNELAPI\nPOBJECT_TYPE\nNTAPI\nObGetObjectType(\n    _In_ PVOID Object\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nObOpenObjectByName(\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ POBJECT_TYPE ObjectType,\n    _In_ KPROCESSOR_MODE AccessMode,\n    _In_opt_ PACCESS_STATE AccessState,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID ParseContext,\n    _Out_ PHANDLE Handle\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nObSetHandleAttributes(\n    _In_ HANDLE Handle,\n    _In_ POBJECT_HANDLE_FLAG_INFORMATION HandleFlags,\n    _In_ KPROCESSOR_MODE AccessMode\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nObDuplicateObject(\n    _In_ PEPROCESS SourceProcess,\n    _In_ HANDLE SourceHandle,\n    _In_opt_ PEPROCESS TargetProcess,\n    _Out_opt_ PHANDLE TargetHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_ ULONG Options,\n    _In_ KPROCESSOR_MODE PreviousMode\n    );\n\n// CM\n\n#if (NTDDI_VERSION < NTDDI_WIN10_FE)\ntypedef struct _REG_SAVE_MERGED_KEY_INFORMATION\n{\n    PVOID Object;\n    HANDLE FileHandle;\n    PVOID HighKeyObject;\n    PVOID LowKeyObject;\n    PVOID CallContext;\n    PVOID ObjectContext;\n    PVOID Reserved;\n} REG_SAVE_MERGED_KEY_INFORMATION, *PREG_SAVE_MERGED_KEY_INFORMATION;\n#endif\n\n// LDR\n\n#define IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16) == 0)\n#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))\n#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))\n#ifdef UNICODE\n#define MAKEINTRESOURCE  MAKEINTRESOURCEW\n#else\n#define MAKEINTRESOURCE  MAKEINTRESOURCEA\n#endif\n\n#define RT_VERSION      MAKEINTRESOURCE(16)\n\n#define VS_FILE_INFO            RT_VERSION\n#define VS_VERSION_INFO         1\n\n#define VS_FFI_SIGNATURE        0xFEEF04BDL\n\ntypedef struct _IMAGE_RESOURCE_DATA_ENTRY IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nLdrAccessResource(\n    _In_ PVOID DllHandle,\n    _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,\n    _Out_opt_ PVOID *ResourceBuffer,\n    _Out_opt_ ULONG *ResourceLength\n    );\n\ntypedef struct _LDR_RESOURCE_INFO\n{\n    ULONG_PTR Type;\n    ULONG_PTR Name;\n    ULONG_PTR Language;\n} LDR_RESOURCE_INFO, *PLDR_RESOURCE_INFO;\n\n#define RESOURCE_TYPE_LEVEL 0\n#define RESOURCE_NAME_LEVEL 1\n#define RESOURCE_LANGUAGE_LEVEL 2\n#define RESOURCE_DATA_LEVEL 3\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nLdrFindResource_U(\n    _In_ PVOID DllHandle,\n    _In_ PLDR_RESOURCE_INFO ResourceInfo,\n    _In_ ULONG Level,\n    _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry\n    );\n\ntypedef struct _VS_VERSION_INFO_STRUCT\n{\n    USHORT Length;\n    USHORT ValueLength;\n    USHORT Type;\n    WCHAR Key[1];\n} VS_VERSION_INFO_STRUCT, *PVS_VERSION_INFO_STRUCT;\n\ntypedef struct _FIXEDFILEINFO\n{\n    DWORD   dwSignature;\n    DWORD   dwStrucVersion;\n    DWORD   dwFileVersionMS;\n    DWORD   dwFileVersionLS;\n    DWORD   dwProductVersionMS;\n    DWORD   dwProductVersionLS;\n    DWORD   dwFileFlagsMask;\n    DWORD   dwFileFlags;\n    DWORD   dwFileOS;\n    DWORD   dwFileType;\n    DWORD   dwFileSubtype;\n    DWORD   dwFileDateMS;\n    DWORD   dwFileDateLS;\n} VS_FIXEDFILEINFO, *PVS_FIXEDFILEINFO;\n\ntypedef struct _NON_PAGED_DEBUG_INFO NON_PAGED_DEBUG_INFO, *PNON_PAGED_DEBUG_INFO;\n\ntypedef struct _KLDR_DATA_TABLE_ENTRY\n{\n    LIST_ENTRY InLoadOrderLinks;\n    PVOID ExceptionTable;\n    ULONG ExceptionTableSize;\n    PVOID GpValue;\n    PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;\n    PVOID DllBase;\n    PVOID EntryPoint;\n    ULONG SizeOfImage;\n    UNICODE_STRING FullDllName;\n    UNICODE_STRING BaseDllName;\n    ULONG Flags;\n    USHORT LoadCount;\n    union\n    {\n        USHORT SignatureLevel : 4;\n        USHORT SignatureType : 3;\n        USHORT Frozen : 2;\n        USHORT HotPatch : 1;\n        USHORT Unused : 6;\n        USHORT EntireField;\n    } u1;\n    PVOID SectionPointer;\n    ULONG CheckSum;\n    ULONG CoverageSectionSize;\n    PVOID CoverageSection;\n    PVOID LoadedImports;\n    union\n    {\n        PVOID Spare;\n        struct _KLDR_DATA_TABLE_ENTRY* NtDataTableEntry; // win11\n    };\n    ULONG SizeOfImageNotRounded;\n    ULONG TimeDateStamp;\n} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;\n\n// PS\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ THREADINFOCLASS ThreadInformationClass,\n    _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nPsLookupProcessThreadByCid(\n    _In_ PCLIENT_ID ClientId,\n    _Out_opt_ PEPROCESS *Process,\n    _Out_ PETHREAD *Thread\n    );\n\ntypedef struct _EJOB *PEJOB;\n\nextern POBJECT_TYPE *PsJobType;\n\nNTKERNELAPI\nPEJOB\nNTAPI\nPsGetProcessJob(\n    _In_ PEPROCESS Process\n    );\n\n_When_(NT_SUCCESS(return), _Acquires_lock_(Process))\nNTKERNELAPI\nNTSTATUS\nNTAPI\nPsAcquireProcessExitSynchronization(\n    _In_ PEPROCESS Process\n    );\n\n_Releases_lock_(Process)\nNTKERNELAPI\nVOID\nNTAPI\nPsReleaseProcessExitSynchronization(\n    _In_ PEPROCESS Process\n    );\n\nNTKERNELAPI\nPVOID\nNTAPI\nPsGetProcessSectionBaseAddress(\n    _In_ PEPROCESS Process\n    );\n\nNTKERNELAPI\nBOOLEAN\nNTAPI\nPsGetProcessExitProcessCalled(\n    _In_ PEPROCESS Process\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nPsSuspendProcess(\n    _In_ PEPROCESS Process\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nPsResumeProcess(\n    _In_ PEPROCESS Process\n    );\n\ntypedef struct _PS_PROTECTION\n{\n    union\n    {\n        UCHAR Level;\n        struct\n        {\n            UCHAR Type   : 3;\n            UCHAR Audit  : 1;                  // Reserved\n            UCHAR Signer : 4;\n        };\n    };\n} PS_PROTECTION, *PPS_PROTECTION;\n\ntypedef enum _PS_PROTECTED_TYPE\n{\n    PsProtectedTypeNone = 0,\n    PsProtectedTypeProtectedLight = 1,\n    PsProtectedTypeProtected = 2\n} PS_PROTECTED_TYPE, *PPS_PROTECTED_TYPE;\n\ntypedef enum _PS_PROTECTED_SIGNER\n{\n    PsProtectedSignerNone = 0,\n    PsProtectedSignerAuthenticode,\n    PsProtectedSignerCodeGen,\n    PsProtectedSignerAntimalware,\n    PsProtectedSignerLsa,\n    PsProtectedSignerWindows,\n    PsProtectedSignerWinTcb,\n    PsProtectedSignerWinSystem,\n    PsProtectedSignerApp,\n    PsProtectedSignerMax\n} PS_PROTECTED_SIGNER, *PPS_PROTECTED_SIGNER;\n\n#if (NTDDI_VERSION >= NTDDI_WIN10)\nNTKERNELAPI\nPS_PROTECTION\nNTAPI\nPsGetProcessProtection(\n    _In_ PEPROCESS Process\n    );\n#endif\n\ntypedef\n_Function_class_(PS_SET_LOAD_IMAGE_NOTIFY_ROUTINE_EX)\nNTSTATUS\nNTAPI\nPS_SET_LOAD_IMAGE_NOTIFY_ROUTINE_EX(\n    _In_ PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine,\n    _In_ ULONG_PTR Flags\n    );\ntypedef PS_SET_LOAD_IMAGE_NOTIFY_ROUTINE_EX* PPS_SET_LOAD_IMAGE_NOTIFY_ROUTINE_EX;\n\n#if (NTDDI_VERSION < NTDDI_WIN10_RS2)\ntypedef enum _PSCREATEPROCESSNOTIFYTYPE\n{\n    PsCreateProcessNotifySubsystems = 0\n\n} PSCREATEPROCESSNOTIFYTYPE;\n#endif\n\ntypedef\n_Function_class_(PS_SET_CREATE_PROCESS_NOTIFY_ROUTINE_EX2)\nNTSTATUS\nNTAPI\nPS_SET_CREATE_PROCESS_NOTIFY_ROUTINE_EX2(\n    _In_ PSCREATEPROCESSNOTIFYTYPE NotifyType,\n    _In_ PVOID NotifyInformation,\n    _In_ BOOLEAN Remove\n    );\ntypedef PS_SET_CREATE_PROCESS_NOTIFY_ROUTINE_EX2* PPS_SET_CREATE_PROCESS_NOTIFY_ROUTINE_EX2;\n\n#ifndef PS_IMAGE_NOTIFY_CONFLICTING_ARCHITECTURE\n#define PS_IMAGE_NOTIFY_CONFLICTING_ARCHITECTURE            0x1\n#endif\n\nNTKERNELAPI\n_Must_inspect_result_\nNTSTATUS\nNTAPI\nPsReferenceProcessFilePointer(\n    _In_ PEPROCESS Process,\n    _Out_ PFILE_OBJECT* FileObject\n    );\n\nNTKERNELAPI\nHANDLE\nNTAPI\nPsGetProcessInheritedFromUniqueProcessId(\n    _In_ PEPROCESS Process\n    );\n\n#ifdef _WIN64\n\nNTKERNELAPI\nPVOID\nNTAPI\nPsGetProcessWow64Process(\n    _In_ PEPROCESS Process\n    );\n\nNTKERNELAPI\nPVOID\nNTAPI\nPsGetCurrentProcessWow64Process(\n    VOID\n    );\n\n#endif\n\nNTKERNELAPI\nPVOID\nNTAPI\nPsGetThreadTeb(\n    _In_ PETHREAD Thread\n    );\n\nNTKERNELAPI\nBOOLEAN\nNTAPI\nPsIsProcessBeingDebugged(\n    _In_ PEPROCESS Process\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nZwSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength\n    );\n\n#define ProcessPowerThrottlingState    77\n#define ProcessPriorityClassEx        108\n\n#define ThreadPowerThrottlingState     49\n#define ThreadNameInformation          38\n#define ThreadExplicitCaseSensitivity  43\n\n#if (NTDDI_VERSION >= NTDDI_WIN10)\nextern PLIST_ENTRY PsLoadedModuleList;\nextern PERESOURCE PsLoadedModuleResource;\n#endif\n\ntypedef struct _PROCESS_MITIGATION_POLICY_INFORMATION\n{\n    PROCESS_MITIGATION_POLICY Policy;\n    union\n    {\n        PROCESS_MITIGATION_ASLR_POLICY ASLRPolicy;\n        PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY StrictHandleCheckPolicy;\n        PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY SystemCallDisablePolicy;\n        PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY ExtensionPointDisablePolicy;\n        PROCESS_MITIGATION_DYNAMIC_CODE_POLICY DynamicCodePolicy;\n        PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY ControlFlowGuardPolicy;\n        PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY SignaturePolicy;\n        PROCESS_MITIGATION_FONT_DISABLE_POLICY FontDisablePolicy;\n        PROCESS_MITIGATION_IMAGE_LOAD_POLICY ImageLoadPolicy;\n        PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy;\n        PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy;\n        PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy;\n        PROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY SideChannelIsolationPolicy;\n        PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY UserShadowStackPolicy;\n        PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY RedirectionTrustPolicy;\n        PROCESS_MITIGATION_USER_POINTER_AUTH_POLICY UserPointerAuthPolicy;\n        PROCESS_MITIGATION_SEHOP_POLICY SEHOPPolicy;\n    };\n} PROCESS_MITIGATION_POLICY_INFORMATION, *PPROCESS_MITIGATION_POLICY_INFORMATION;\n\nNTKERNELAPI\nPUCHAR\nNTAPI\nPsGetProcessImageFileName(\n    _In_ PEPROCESS Process\n    );\n\ntypedef\n_Function_class_(PS_GET_PROCESS_SEQUENCE_NUMBER)\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONGLONG\nPS_GET_PROCESS_SEQUENCE_NUMBER(\n    _In_ PEPROCESS Process\n    );\ntypedef PS_GET_PROCESS_SEQUENCE_NUMBER* PPS_GET_PROCESS_SEQUENCE_NUMBER;\n\ntypedef\n_Function_class_(PS_GET_PROCESS_START_KEY)\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONGLONG\nPS_GET_PROCESS_START_KEY(\n    _In_ PEPROCESS Process\n    );\ntypedef PS_GET_PROCESS_START_KEY* PPS_GET_PROCESS_START_KEY;\n\ntypedef struct _PROCESS_TELEMETRY_ID_INFORMATION\n{\n    ULONG HeaderSize;\n    ULONG ProcessId;\n    ULONGLONG ProcessStartKey;\n    ULONGLONG CreateTime;\n    ULONGLONG CreateInterruptTime;\n    ULONGLONG CreateUnbiasedInterruptTime;\n    ULONGLONG ProcessSequenceNumber;\n    ULONGLONG SessionCreateTime;\n    ULONG SessionId;\n    ULONG BootId;\n    ULONG ImageChecksum;\n    ULONG ImageTimeDateStamp;\n    ULONG UserSidOffset;\n    ULONG ImagePathOffset;\n    ULONG PackageNameOffset;\n    ULONG RelativeAppNameOffset;\n    ULONG CommandLineOffset;\n} PROCESS_TELEMETRY_ID_INFORMATION, *PPROCESS_TELEMETRY_ID_INFORMATION;\n\n#define PROCESS_CREATE_FLAGS_MINIMAL_PROCESS 0x00000800 // NtCreateProcessEx only\n\ntypedef\n_Function_class_(ZW_CREATE_PROCESS_EX)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZW_CREATE_PROCESS_EX(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ParentProcess,\n    _In_ ULONG Flags, // PROCESS_CREATE_FLAGS_*\n    _In_opt_ HANDLE SectionHandle,\n    _In_opt_ HANDLE DebugPort,\n    _In_opt_ HANDLE TokenHandle,\n    _Reserved_ ULONG Reserved // JobMemberLevel\n    );\ntypedef ZW_CREATE_PROCESS_EX* PZW_CREATE_PROCESS_EX;\n\n\n// RTL\n\n#ifndef RTL_MAX_DRIVE_LETTERS\n#define RTL_MAX_DRIVE_LETTERS 32\n#endif\n\n#define RTL_WALK_USER_MODE_STACK 0x00000001\n#define RTL_WALK_VALID_FLAGS     0x00000001\n\n#define RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT 8\n\nNTKERNELAPI\nPIMAGE_NT_HEADERS\nNTAPI\nRtlImageNtHeader(\n    _In_ PVOID Base\n    );\n\n#define RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK 0x00000001\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nRtlImageNtHeaderEx(\n    _In_ ULONG Flags,\n    _In_ PVOID Base,\n    _In_ ULONG64 Size,\n    _Out_ PIMAGE_NT_HEADERS* OutHeaders\n    );\n\nNTKERNELAPI\nPVOID\nNTAPI\nRtlImageDirectoryEntryToData(\n    _In_ PVOID BaseAddress,\n    _In_ BOOLEAN MappedAsImage,\n    _In_ USHORT Directory,\n    _Out_ PULONG Size\n    );\n\n#if (NTDDI_VERSION >= NTDDI_WIN10)\nNTKERNELAPI\nPVOID\nNTAPI\nRtlFindExportedRoutineByName(\n    _In_ PVOID BaseAddress,\n    _In_z_ PCSTR RoutineName\n    );\n#endif\n\n// MM\n\n#define SEC_DRIVER_IMAGE 0x00100000\n\nextern POBJECT_TYPE *MmSectionObjectType;\n\ntypedef\n_Function_class_(MM_PROTECT_DRIVER_SECTION)\nNTSTATUS\nMM_PROTECT_DRIVER_SECTION(\n    _In_ PVOID AddressWithinSection,\n    _In_ SIZE_T Size,\n    _In_ ULONG Flags\n    );\ntypedef MM_PROTECT_DRIVER_SECTION* PMM_PROTECT_DRIVER_SECTION;\n\n#define MM_PROTECT_DRIVER_SECTION_ALLOW_UNLOAD          (0x1)\n\n#define MM_PROTECT_DRIVER_SECTION_VALID_FLAGS \\\n    (MM_PROTECT_DRIVER_SECTION_ALLOW_UNLOAD)\n\ntypedef struct _MMVAD_FLAGS\n{\n    ULONG Lock : 1;\n    ULONG LockContended : 1;\n    ULONG DeleteInProgress : 1;\n    ULONG NoChange : 1;\n    ULONG VadType : 3;\n    ULONG Protection : 5;\n    ULONG PreferredNode : 7;\n    ULONG PageSize : 2;\n    ULONG PrivateMemory : 1;\n} MMVAD_FLAGS, *PMMVAD_FLAGS;\n\ntypedef struct _MM_PRIVATE_VAD_FLAGS\n{\n    ULONG Lock : 1;\n    ULONG LockContended : 1;\n    ULONG DeleteInProgress : 1;\n    ULONG NoChange : 1;\n    ULONG VadType : 3;\n    ULONG Protection : 5;\n    ULONG PreferredNode : 7;\n    ULONG PageSize : 2;\n    ULONG PrivateMemoryAlwaysSet : 1;\n    ULONG WriteWatch : 1;\n    ULONG FixedLargePageSize : 1;\n    ULONG ZeroFillPagesOptional : 1;\n    ULONG Graphics : 1;\n    ULONG Enclave : 1;\n    ULONG ShadowStack : 1;\n    ULONG PhysicalMemoryPfnsReferenced : 1;\n} MM_PRIVATE_VAD_FLAGS, *PMM_PRIVATE_VAD_FLAGS;\n\ntypedef struct _MM_GRAPHICS_VAD_FLAGS\n{\n    ULONG Lock : 1;\n    ULONG LockContended : 1;\n    ULONG DeleteInProgress : 1;\n    ULONG NoChange : 1;\n    ULONG VadType : 3;\n    ULONG Protection : 5;\n    ULONG PreferredNode : 7;\n    ULONG PageSize : 2;\n    ULONG PrivateMemoryAlwaysSet : 1;\n    ULONG WriteWatch : 1;\n    ULONG FixedLargePageSize : 1;\n    ULONG ZeroFillPagesOptional : 1;\n    ULONG GraphicsAlwaysSet : 1;\n    ULONG GraphicsUseCoherentBus : 1;\n    ULONG GraphicsNoCache : 1;\n    ULONG GraphicsPageProtection : 3;\n} MM_GRAPHICS_VAD_FLAGS, *PMM_GRAPHICS_VAD_FLAGS;\n\ntypedef struct _MM_SHARED_VAD_FLAGS\n{\n    ULONG Lock : 1;\n    ULONG LockContended : 1;\n    ULONG DeleteInProgress : 1;\n    ULONG NoChange : 1;\n    ULONG VadType : 3;\n    ULONG Protection : 5;\n    ULONG PreferredNode : 7;\n    ULONG PageSize : 2;\n    ULONG PrivateMemoryAlwaysClear : 1;\n    ULONG PrivateFixup : 1;\n    ULONG HotPatchState : 2;\n} MM_SHARED_VAD_FLAGS, *PMM_SHARED_VAD_FLAGS;\n\ntypedef struct _MMVAD_FLAGS1\n{\n    ULONG CommitCharge : 31;\n    ULONG MemCommit : 1;\n}MMVAD_FLAGS1, *PMMVAD_FLAGS1;\n\ntypedef struct _MMVAD_SHORT\n{\n    union\n    {\n        struct\n        {\n            struct _MMVAD_SHORT* NextVad;\n            PVOID ExtraCreateInfo;\n        };\n        RTL_BALANCED_NODE VadNode;\n    };\n    ULONG StartingVpn;\n    ULONG EndingVpn;\n#ifdef _WIN64\n    UCHAR StartingVpnHigh;\n    UCHAR EndingVpnHigh;\n    UCHAR CommitChargeHigh;\n    union\n    {\n        UCHAR SpareNT64VadUChar;\n        struct // LA57\n        {\n            UCHAR EndingVpnHigher : 4;\n            UCHAR CommitChargeHigher : 4;\n        };\n    };\n#endif\n    LONG ReferenceCount;\n    EX_PUSH_LOCK PushLock;\n    union\n    {\n        ULONG LongFlags;\n        MMVAD_FLAGS VadFlags;\n        MM_PRIVATE_VAD_FLAGS PrivateVadFlags;\n        MM_GRAPHICS_VAD_FLAGS GraphicsVadFlags;\n        MM_SHARED_VAD_FLAGS SharedVadFlags;\n        volatile ULONG VolatileVadLong;\n    } u;\n    union\n    {\n        ULONG LongFlags1;\n        MMVAD_FLAGS1 VadFlags1;\n    } u1;\n#ifdef _WIN64\n    union\n    {\n        ULONG_PTR EventListULongPtr;\n        UCHAR StartingVpnHigher : 4; // LA57\n    } u5;\n#else\n    PVOID EventList; // PMI_VAD_EVENT_BLOCK\n#endif\n} MMVAD_SHORT, *PMMVAD_SHORT;\n\nFORCEINLINE\nPVOID\nMiGetVadShortStartAddress(\n    _In_ PMMVAD_SHORT Vad\n    )\n{\n#ifdef _WIN64\n    ULONG_PTR higher = Vad->u5.StartingVpnHigher;\n    ULONG_PTR high = Vad->StartingVpnHigh;\n    ULONG_PTR low = Vad->StartingVpn;\n    return (PVOID)((low | ((high | (higher << 8)) << 32)) << PAGE_SHIFT);\n#else\n    return (PVOID)((ULONG_PTR)Vad->StartingVpn << PAGE_SHIFT);\n#endif\n}\n\nFORCEINLINE\nPVOID\nMiGetVadShortEndAddress(\n    _In_ PMMVAD_SHORT Vad\n    )\n{\n#ifdef _WIN64\n    ULONG_PTR higher = Vad->EndingVpnHigher;\n    ULONG_PTR high = Vad->EndingVpnHigh;\n    ULONG_PTR low = Vad->EndingVpn;\n    return (PVOID)(((low + 1) | ((high | (higher << 8)) << 32)) << PAGE_SHIFT);\n#else\n    return (PVOID)(((ULONG_PTR)Vad->StartingVpn + 1) << PAGE_SHIFT);\n#endif\n}\n\ntypedef struct _MMVAD_FLAGS2\n{\n    ULONG FileOffset : 24;\n    ULONG Large : 1;\n    ULONG TrimBehind : 1;\n    ULONG Inherit : 1;\n    ULONG NoValidationNeeded : 1;\n    ULONG PrivateDemandZero : 1;\n    ULONG Spare : 3;\n} MMVAD_FLAGS2, *PMMVAD_FLAGS2;\n\ntypedef struct _MI_VAD_SEQUENTIAL_INFO\n{\n    ULONGLONG Length : 12;\n    ULONGLONG Vpn : 52;\n} MI_VAD_SEQUENTIAL_INFO, *PMI_VAD_SEQUENTIAL_INFO;\n\ntypedef struct _MMEXTEND_INFO\n{\n    ULONGLONG CommittedSize;\n    ULONG ReferenceCount;\n} MMEXTEND_INFO, *PMMEXTEND_INFO;\n\ntypedef struct _MMPTE_HIGHLOW\n{\n    ULONG LowPart;\n    ULONG HighPart;\n} MMPTE_HIGHLOW, *PMMPTE_HIGHLOW;\n\ntypedef struct _MMPTE_HARDWARE\n{\n    ULONGLONG Valid : 1;\n    ULONGLONG Dirty1 : 1;\n    ULONGLONG Owner : 1;\n    ULONGLONG WriteThrough : 1;\n    ULONGLONG CacheDisable : 1;\n    ULONGLONG Accessed : 1;\n    ULONGLONG Dirty : 1;\n    ULONGLONG LargePage : 1;\n    ULONGLONG Global : 1;\n    ULONGLONG CopyOnWrite : 1;\n    ULONGLONG Unused : 1;\n    ULONGLONG Write : 1;\n    ULONGLONG PageFrameNumber : 40;\n    ULONGLONG ReservedForSoftware : 4;\n    ULONGLONG WsleAge : 4;\n    ULONGLONG WsleProtection : 3;\n    ULONGLONG NoExecute : 1;\n} MMPTE_HARDWARE, *PMMPTE_HARDWARE;\n\ntypedef struct _MMPTE_PROTOTYPE\n{\n    ULONGLONG Valid : 1;\n    ULONGLONG DemandFillProto : 1;\n    ULONGLONG HiberVerifyConverted : 1;\n    ULONGLONG ReadOnly : 1;\n    ULONGLONG SwizzleBit : 1;\n    ULONGLONG Protection : 5;\n    ULONGLONG Prototype : 1;\n    ULONGLONG Combined : 1;\n    ULONGLONG Unused1 : 4;\n    LONGLONG ProtoAddress : 48;\n} MMPTE_PROTOTYPE, * PMMPTE_PROTOTYPE;\n\ntypedef struct _MMPTE_SOFTWARE\n{\n    ULONGLONG Valid : 1;\n    ULONGLONG PageFileReserved : 1;\n    ULONGLONG PageFileAllocated : 1;\n    ULONGLONG ColdPage : 1;\n    ULONGLONG SwizzleBit : 1;\n    ULONGLONG Protection : 5;\n    ULONGLONG Prototype : 1;\n    ULONGLONG Transition : 1;\n    ULONGLONG PageFileLow : 4;\n    ULONGLONG UsedPageTableEntries : 10;\n    ULONGLONG ShadowStack : 1;\n    ULONGLONG OnStandbyLookaside : 1;\n    ULONGLONG Unused : 4;\n    ULONGLONG PageFileHigh : 32;\n} MMPTE_SOFTWARE, * PMMPTE_SOFTWARE;\n\ntypedef struct _MMPTE_TIMESTAMP\n{\n    ULONGLONG MustBeZero : 1;\n    ULONGLONG Unused : 3;\n    ULONGLONG SwizzleBit : 1;\n    ULONGLONG Protection : 5;\n    ULONGLONG Prototype : 1;\n    ULONGLONG Transition : 1;\n    ULONGLONG PageFileLow : 4;\n    ULONGLONG Reserved : 16;\n    ULONGLONG GlobalTimeStamp : 32;\n} MMPTE_TIMESTAMP, *PMMPTE_TIMESTAMP;\n\ntypedef struct _MMPTE_TRANSITION\n{\n    ULONGLONG Valid : 1;\n    ULONGLONG Write : 1;\n    ULONGLONG OnStandbyLookaside : 1;\n    ULONGLONG IoTracker : 1;\n    ULONGLONG SwizzleBit : 1;\n    ULONGLONG Protection : 5;\n    ULONGLONG Prototype : 1;\n    ULONGLONG Transition : 1;\n    ULONGLONG PageFrameNumber : 40;\n    ULONGLONG Unused : 12;\n} MMPTE_TRANSITION, *PMMPTE_TRANSITION;\n\ntypedef struct _MMPTE_SUBSECTION\n{\n    ULONGLONG Valid : 1;\n    ULONGLONG Unused0 : 2;\n    ULONGLONG OnStandbyLookaside : 1;\n    ULONGLONG SwizzleBit : 1;\n    ULONGLONG Protection : 5;\n    ULONGLONG Prototype : 1;\n    ULONGLONG ColdPage : 1;\n    ULONGLONG Unused2 : 3;\n    ULONGLONG ExecutePrivilege : 1;\n    LONGLONG SubsectionAddress : 48;\n} MMPTE_SUBSECTION, * PMMPTE_SUBSECTION;\n\ntypedef struct _MMPTE_LIST\n{\n    ULONGLONG Valid : 1;\n    ULONGLONG OneEntry : 1;\n    ULONGLONG filler0 : 2;\n    ULONGLONG SwizzleBit : 1;\n    ULONGLONG Protection : 5;\n    ULONGLONG Prototype : 1;\n    ULONGLONG Transition : 1;\n    ULONGLONG filler1 : 16;\n    ULONGLONG NextEntry : 36;\n} MMPTE_LIST, *PMMPTE_LIST;\n\ntypedef struct _MMPTE\n{\n    union\n    {\n        ULONGLONG Long;\n        volatile ULONGLONG VolatileLong;\n#ifndef _WIN64\n        MMPTE_HIGHLOW HighLow;\n#endif\n        MMPTE_HARDWARE Hard;\n        MMPTE_PROTOTYPE Proto;\n        MMPTE_SOFTWARE Soft;\n        MMPTE_TIMESTAMP TimeStamp;\n        MMPTE_TRANSITION Trans;\n        MMPTE_SUBSECTION Subsect;\n        MMPTE_LIST List;\n    } u;\n} MMPTE, *PMMPTE;\n\ntypedef struct _MMVAD\n{\n    struct _MMVAD_SHORT Core;\n    union\n    {\n        ULONG LongFlags2;\n        MMVAD_FLAGS2 VadFlags2;\n    } u2;\n    PVOID Subsection; // PSUBSECTION\n    PMMPTE FirstPrototypePte;\n    PMMPTE LastContiguousPte;\n    LIST_ENTRY ViewLinks;\n    union\n    {\n        PEPROCESS VadsProcess;\n        UCHAR ViewMapType : 3; // VIEW_MAP_TYPE_*\n    };\n    union\n    {\n        MI_VAD_SEQUENTIAL_INFO SequentialVa;\n        PMMEXTEND_INFO ExtendedInfo;\n    } u4;\n    PFILE_OBJECT FileObject; // since WIN10\n} MMVAD, *PMMVAD;\n\nFORCEINLINE\nPVOID\nMiGetVadStartAddress(\n    _In_ PMMVAD Vad\n    )\n{\n    return MiGetVadShortStartAddress(&Vad->Core);\n}\n\nFORCEINLINE\nPVOID\nMiGetVadEndAddress(\n    _In_ PMMVAD Vad\n    )\n{\n    return MiGetVadShortEndAddress(&Vad->Core);\n}\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nMmCreateSection(\n    _Out_ PVOID* SectionObject,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG SectionPageProtection,\n    _In_ ULONG AllocationAttributes,\n    _In_opt_ HANDLE FileHandle,\n    _In_opt_ PFILE_OBJECT FileObject\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nMmMapViewOfSection(\n    _In_ PVOID SectionObject,\n    _In_ PEPROCESS Process,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress,\n    _In_ ULONG_PTR ZeroBits,\n    _In_ SIZE_T CommitSize,\n    _Inout_opt_ PLARGE_INTEGER SectionOffset,\n    _Inout_ PSIZE_T ViewSize,\n    _In_ SECTION_INHERIT InheritDisposition,\n    _In_ ULONG AllocationType,\n    _In_ ULONG PageProtection\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nMmUnmapViewOfSection(\n    _In_ PEPROCESS Process,\n    _In_ PVOID BaseAddress\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nMmCopyVirtualMemory(\n    _In_ PEPROCESS SourceProcess,\n    _In_reads_bytes_(BufferSize) PVOID SourceAddress,\n    _In_ PEPROCESS TargetProcess,\n    _Out_writes_bytes_(BufferSize) PVOID TargetAddress,\n    _In_ SIZE_T BufferSize,\n    _In_ KPROCESSOR_MODE PreviousMode,\n    _Out_ PSIZE_T ReturnSize\n    );\n\n// CI\n\n#ifndef ALGIDDEF\n#define ALGIDDEF\ntypedef unsigned int ALG_ID;\n#endif\n\n#ifndef ALG_SID_MD5\n#define ALG_SID_MD5                     3\n#endif ALG_SID_MD5\n#ifndef ALG_SID_SHA1\n#define ALG_SID_SHA1                    4\n#endif\n#ifndef ALG_SID_SHA_256\n#define ALG_SID_SHA_256                 12\n#endif\n\n#ifndef ALG_CLASS_HASH\n#define ALG_CLASS_HASH                  (4 << 13)\n#endif\n#ifndef ALG_TYPE_ANY\n#define ALG_TYPE_ANY                    (0)\n#endif\n\n#ifndef CALG_MD5\n#define CALG_MD5                (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5)\n#endif\n#ifndef CALG_SHA1\n#define CALG_SHA1               (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1)\n#endif\n#ifndef CALG_SHA_256\n#define CALG_SHA_256            (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)\n#endif\n\n#ifndef CRYPTO_BLOBS_DEFINED\n#define CRYPTO_BLOBS_DEFINED\ntypedef struct _CRYPTOAPI_BLOB\n{\n    ULONG cbData;\n    _Field_size_bytes_(cbData) UCHAR *pbData;\n}\nCRYPT_INTEGER_BLOB, *PCRYPT_INTEGER_BLOB,\nCRYPT_UINT_BLOB, *PCRYPT_UINT_BLOB,\nCRYPT_OBJID_BLOB, *PCRYPT_OBJID_BLOB,\nCERT_NAME_BLOB, *PCERT_NAME_BLOB,\nCERT_RDN_VALUE_BLOB, *PCERT_RDN_VALUE_BLOB,\nCERT_BLOB, *PCERT_BLOB,\nCRL_BLOB, *PCRL_BLOB,\nDATA_BLOB, *PDATA_BLOB,\nCRYPT_DATA_BLOB, *PCRYPT_DATA_BLOB,\nCRYPT_HASH_BLOB, *PCRYPT_HASH_BLOB,\nCRYPT_DIGEST_BLOB, *PCRYPT_DIGEST_BLOB,\nCRYPT_DER_BLOB, *PCRYPT_DER_BLOB,\nCRYPT_ATTR_BLOB, *PCRYPT_ATTR_BLOB;\n#endif\n\n#ifndef MINCRYPT_MAX_HASH_LEN\n#define MINCRYPT_MAX_HASH_LEN 64\n#endif\n\n#ifndef MINCRYPT_SHA1_HASH_LEN\n#define MINCRYPT_SHA1_HASH_LEN (160 / 8)\n#endif\n\n#ifndef MINCRYPT_SHA256_HASH_LEN\n#define MINCRYPT_SHA256_HASH_LEN (256 / 8)\n#endif\n\n//\n// Self-signed\n//\n#define MINCRYPT_POLICY_NO_ROOT           0x1\n//\n// Microsoft Authenticode Root Authority\n// Microsoft Root Authority\n// Microsoft Root Certificate Authority\n//\n#define MINCRYPT_POLICY_MICROSOFT_ROOT    0x2\n//\n// Microsoft Test Root Authority\n//\n#define MINCRYPT_POLICY_TEST_ROOT         0x4\n//\n// Microsoft Code Verification Root\n//\n#define MINCRYPT_POLICY_CODE_ROOT         0x8\n//\n// Win 10 RS5 started using Unknown Root\n//\n#define MINCRYPT_POLICY_UNKNOWN_ROOT      0x10\n//\n// Microsoft Digital Media Authority 2005\n// Microsoft Digital Media Authority 2005 for preview releases\n//\n#define MINCRYPT_POLICY_DMD_ROOT          0x20\n//\n// MS Protected Media Test Root\n//\n#define MINCRYPT_POLICY_DMD_TEST_ROOT     0x40\n//\n// Win 8.1/10 flags\n//\n#define MINCRYPT_POLICY_3RD_PARTY_ROOT    0x80\n#define MINCRYPT_POLICY_TRUSTED_BOOT_ROOT 0x100\n#define MINCRYPT_POLICY_UEFI_ROOT         0x200\n#define MINCRYPT_POLICY_FLIGHT_ROOT       0x400\n#define MINCRYPT_POLICY_PRS_WIN81_ROOT    0x800\n#define MINCRYPT_POLICY_TEST_WIN81_ROOT   0x1000\n#define MINCRYPT_POLICY_OTHER_ROOT        0x2000\n//\n// Undefined bits\n//\n#define MINCRYPT_POLICY_INVALID_BITS      0xC000\n\n//\n// This flag masks out errors and only keeps policies\n//\n#define MINCRYPT_POLICY_ROOT_FLAG         0xFFFF\n\n//\n// All these are errors instead\n//\n#define MINCRYPT_POLICY_NO_SIGNATURE      0x00010000\n#define MINCRYPT_POLICY_BAD_CHAIN         0x00020000\n#define MINCRYPT_POLICY_BAD_SIGNATURE     0x00040000\n#define MINCRYPT_POLICY_NO_CODE_EKU       0x00080000\n#define MINCRYPT_POLICY_NO_PAGE_HASHES    0x00100000\n#define MINCRYPT_POLICY_CERT_REVOKED      0x00200000\n#define MINCRYPT_POLICY_CERT_EXPIRED      0x00400000\n#define MINCRYPT_POLICY_UNKNOWN_ERROR     0x10000000\n#define MINCRYPT_POLICY_ERROR_BIT_SHIFT   16\n#define MINCRYPT_POLICY_ERROR_FLAGS       0xFFFF0000\n\n//\n// This set of flags ignores an invalid/unknown root authority and too long\n// signing chain.\n//\n#define MINCRYPT_POLICY_BAD_ERROR_FLAGS (MINCRYPT_POLICY_ERROR_FLAGS & ~MINCRYPT_POLICY_BAD_CHAIN)\n\n// https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/event-tag-explanations#microsoft-root-cas-trusted-by-windows\ntypedef enum _MINCRYPT_KNOWN_ROOT\n{\n    MincryptRootNone,\n    MincryptRootUnknown,\n    MincryptRootSelfSigned,\n    MincryptRootAuthenticode,\n    MincryptRootMicrosoftProduct1997,\n    MincryptRootMicrosoftProduct2001,\n    MincryptRootMicrosoftProduct2010,\n    MincryptRootMicrosoftStandard2011,\n    MincryptRootMicrosoftCodeVerification2006,\n    MincryptRootMicrosoftTest1999,\n    MincryptRootMicrosoftTest2010,\n    MincryptRootMicrosoftDMDTest2005,\n    MincryptRootMicrosoftDMD2005,\n    MincryptRootMicrosoftDMDPreview2005,\n    MincryptRootMicrosoftFlight2014,\n    MincryptRootMicrosoftThirdPartyMarketplace,\n    MincryptRootMicrosoftECCTestingRoot2017,\n    MincryptRootMicrosoftECCDevelopmentRoot2018,\n    MincryptRootMicrosoftECCProduct2018,\n    MincryptRootMicrosoftECCProduct2017\n} MINCRYPT_KNOWN_ROOT;\n\ntypedef struct _MINCRYPT_STRING\n{\n    PCHAR Buffer;\n    USHORT Length;\n    UCHAR Asn1EncodingTag;\n    UCHAR Spare[1];\n} MINCRYPT_STRING, *PMINCRYPT_STRING;\n\ntypedef struct _MINCRYPT_CHAIN_ELEMENT\n{\n    ALG_ID AlgorithmId;\n    ULONG HashSize;\n    UCHAR Hash[MINCRYPT_MAX_HASH_LEN];\n    MINCRYPT_STRING Subject;\n    MINCRYPT_STRING Issuer;\n    CRYPT_DER_BLOB Certificate;\n} MINCRYPT_CHAIN_ELEMENT, *PMINCRYPT_CHAIN_ELEMENT;\n\ntypedef struct _MINCRYPT_CHAIN_INFO\n{\n    ULONG Size;\n    PCRYPT_DER_BLOB PublicKeys;\n    ULONG NumberOfPublicKeys;\n    PCRYPT_OBJID_BLOB ExtendedKeyUses;\n    ULONG NumberOfExtendedKeyUses;\n\n    // win10+\n\n    PMINCRYPT_CHAIN_ELEMENT ChainElements;\n    ULONG NumberOfChainElements;\n    MINCRYPT_KNOWN_ROOT KnownRoot;\n    CRYPT_ATTR_BLOB AuthenticodeAttributes;\n    UCHAR PlatformManifest[MINCRYPT_SHA256_HASH_LEN];\n} MINCRYPT_CHAIN_INFO, *PMINCRYPT_CHAIN_INFO;\n\ntypedef struct _MINCRYPT_POLICY_INFO\n{\n    ULONG Size;\n    NTSTATUS VerificationStatus;\n    ULONG PolicyBits;\n    PMINCRYPT_CHAIN_INFO ChainInfo;\n\n    // win8+\n\n    LARGE_INTEGER RevocationTime;\n\n    // win10+\n\n    LARGE_INTEGER ValidFromTime;\n    LARGE_INTEGER ValidToTime;\n} MINCRYPT_POLICY_INFO, *PMINCRYPT_POLICY_INFO;\n\n// rev\n// CiFreePolicyInfo\ntypedef\n_Function_class_(CI_FREE_POLICY_INFO)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID\nNTAPI\nCI_FREE_POLICY_INFO(\n    _Inout_ PMINCRYPT_POLICY_INFO PolicyInfo\n    );\ntypedef CI_FREE_POLICY_INFO* PCI_FREE_POLICY_INFO;\n\n// rev\n// CiCheckSignedFile (pre 6.1.7601.18519)\ntypedef\n_Function_class_(CI_CHECK_SIGNED_FILE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS\nNTAPI\nCI_CHECK_SIGNED_FILE(\n    _In_bytecount_(MINCRYPT_SHA1_HASH_LEN) PBYTE Hash,\n    _In_bytecount_(SignatureSize) PBYTE Signature,\n    _In_ ULONG SignatureSize,\n    _Inout_opt_ PMINCRYPT_POLICY_INFO PolicyInfo,\n    _Out_opt_ PLARGE_INTEGER SigningTime,\n    _Inout_opt_ PMINCRYPT_POLICY_INFO TimeStampPolicyInfo\n    );\ntypedef CI_CHECK_SIGNED_FILE* PCI_CHECK_SIGNED_FILE;\n\n// rev\n// CiCheckSignedFile\ntypedef\n_Function_class_(CI_CHECK_SIGNED_FILE_EX)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS\nNTAPI\nCI_CHECK_SIGNED_FILE_EX(\n    _In_bytecount_(HashSize) PBYTE Hash,\n    _In_ ULONG HashSize,\n    _In_ ALG_ID AlgorithmId,\n    _In_bytecount_(SignatureSize) PBYTE Signature,\n    _In_ ULONG SignatureSize,\n    _Inout_opt_ PMINCRYPT_POLICY_INFO PolicyInfo,\n    _Out_opt_ PLARGE_INTEGER SigningTime,\n    _Inout_opt_ PMINCRYPT_POLICY_INFO TimeStampPolicyInfo\n    );\ntypedef CI_CHECK_SIGNED_FILE_EX* PCI_CHECK_SIGNED_FILE_EX;\n\n// rev\n// CiVerifyHashInCatalog (pre 6.1.7601.18519)\ntypedef\n_Function_class_(CI_VERIFY_HASH_IN_CATALOG)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS\nNTAPI\nCI_VERIFY_HASH_IN_CATALOG(\n    _In_bytecount_(MINCRYPT_SHA1_HASH_LEN) PBYTE Hash,\n    _In_ ULONG ReloadCatalogs,\n    _In_ ULONG SecureProcess,\n    _In_ ULONG AcceptRoots,\n    _Inout_opt_ PMINCRYPT_POLICY_INFO PolicyInfo,\n    _Out_opt_ PUNICODE_STRING CatalogName, // RtlFreeUnicodeString\n    _Out_opt_ PLARGE_INTEGER SigningTime,\n    _Inout_opt_ PMINCRYPT_POLICY_INFO TimeStampPolicyInfo\n    );\ntypedef CI_VERIFY_HASH_IN_CATALOG* PCI_VERIFY_HASH_IN_CATALOG;\n\n// rev\n// CiVerifyHashInCatalog\ntypedef\n_Function_class_(CI_VERIFY_HASH_IN_CATALOG_EX)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS\nNTAPI\nCI_VERIFY_HASH_IN_CATALOG_EX(\n    _In_bytecount_(HashSize) PBYTE Hash,\n    _In_ ULONG HashSize,\n    _In_ ALG_ID AlgorithmId,\n    _In_ ULONG ReloadCatalogs,\n    _In_ ULONG SecureProcess,\n    _In_ ULONG AcceptRoots,\n    _Inout_opt_ PMINCRYPT_POLICY_INFO PolicyInfo,\n    _Out_opt_ PUNICODE_STRING CatalogName, // RtlFreeUnicodeString\n    _Out_opt_ PLARGE_INTEGER SigningTime,\n    _Inout_opt_ PMINCRYPT_POLICY_INFO TimeStampPolicyInfo\n    );\ntypedef CI_VERIFY_HASH_IN_CATALOG_EX* PCI_VERIFY_HASH_IN_CATALOG_EX;\n\n// rev\n#define CI_POLICY_VALID_FLAGS                        0x1BE00078ul\n#define CI_POLICY_DEFAULT                            0x00000000ul\n#define CI_POLICY_REQUIRE_MICROSOFT                  0x00000001ul // ? legacy\n#define CI_POLICY_REQUIRE_SIGNED                     0x00000002ul // ? legacy\n#define CI_POLICY_ALLOW_UNSIGNED                     0x00000004ul // ? legacy\n#define CI_POLICY_REJECT_UNSIGNED                    0x80000000ul // ? legacy\n#define CI_POLICY_CHECK_PROTECTED_PROCESS_EKU        0x00000008ul\n#define CI_POLICY_FORCE_PROTECTED_PROCESS_POLICY     0x00000010ul\n#define CI_POLICY_ACCEPT_ANY_ROOT_CERTIFICATE        0x00000020ul\n#define CI_POLICY_ALLOW_REVOKED_CERTIFICATE          0x00800000ul\n#define CI_POLICY_ALLOW_EXPIRED_REVOKED_CERTIFICATE  0x08000000ul\n\n// rev\n// CiValidateFileObject\ntypedef\n_Function_class_(CI_VALIDATE_FILE_OBJECT)\nNTSTATUS\nNTAPI\nCI_VALIDATE_FILE_OBJECT(\n    _In_ PFILE_OBJECT FileObject,\n    _In_ ULONG PolicyFlags,\n    _In_ SE_SIGNING_LEVEL LevelCheck,\n    _Inout_ PMINCRYPT_POLICY_INFO PolicyInfo,\n    _Inout_ PMINCRYPT_POLICY_INFO TimeStampPolicyInfo,\n    _Out_ PLARGE_INTEGER SigningTime,\n    _Out_writes_bytes_to_(*ThumbprintSize, *ThumbprintSize) PUCHAR Thumbprint,\n    _Inout_ PULONG ThumbprintSize,\n    _Out_ PULONG ThumbprintAlgorithm\n    );\ntypedef CI_VALIDATE_FILE_OBJECT* PCI_VALIDATE_FILE_OBJECT;\n\n// rev\ntypedef _Function_class_(CI_ALLOCATE_ROUTINE)\nPVOID\nNTAPI\nCI_ALLOCATE_ROUTINE(\n    _In_ ULONG NumberOfBytes\n    );\ntypedef CI_ALLOCATE_ROUTINE* PCI_ALLOCATE_ROUTINE;\n\n// rev\n// CiGetCertPublisherName\ntypedef\n_Function_class_(CI_GET_CERT_PUBLISHER_NAME)\nNTSTATUS\nNTAPI\nCI_GET_CERT_PUBLISHER_NAME(\n    _In_ PCRYPT_DER_BLOB Certificate, // MINCRYPT_POLICY_INFO.ChainInfo.ChainElements.Certificate\n    _In_ PCI_ALLOCATE_ROUTINE AllocateRoutine,\n    _Out_ PUNICODE_STRING PublisherName\n    );\ntypedef CI_GET_CERT_PUBLISHER_NAME* PCI_GET_CERT_PUBLISHER_NAME;\n\n// alpc\n\nextern POBJECT_TYPE *LpcPortObjectType;\n#define AlpcPortObjectType LpcPortObjectType\n\n#define PORT_CONNECT 0x0001\n#define PORT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | PORT_CONNECT)\n\ntypedef struct _PORT_MESSAGE\n{\n    union\n    {\n        struct\n        {\n            CSHORT DataLength;\n            CSHORT TotalLength;\n        } s1;\n        ULONG Length;\n    } u1;\n    union\n    {\n        struct\n        {\n            CSHORT Type;\n            CSHORT DataInfoOffset;\n        } s2;\n        ULONG ZeroInit;\n    } u2;\n    union\n    {\n        CLIENT_ID ClientId;\n        double DoNotUseThisField;\n    };\n    ULONG MessageId;\n    union\n    {\n        SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages\n        ULONG CallbackId; // only valid for LPC_REQUEST messages\n    };\n} PORT_MESSAGE, *PPORT_MESSAGE;\n\ntypedef HANDLE ALPC_HANDLE, *PALPC_HANDLE;\n\n#define ALPC_PORFLG_ALLOW_LPC_REQUESTS 0x20000 // rev\n#define ALPC_PORFLG_WAITABLE_PORT 0x40000 // dbg\n#define ALPC_PORFLG_SYSTEM_PROCESS 0x100000 // dbg\n\ntypedef struct _ALPC_PORT_ATTRIBUTES\n{\n    ULONG Flags;\n    SECURITY_QUALITY_OF_SERVICE SecurityQos;\n    SIZE_T MaxMessageLength;\n    SIZE_T MemoryBandwidth;\n    SIZE_T MaxPoolUsage;\n    SIZE_T MaxSectionSize;\n    SIZE_T MaxViewSize;\n    SIZE_T MaxTotalSectionSize;\n    ULONG DupObjectTypes;\n#ifdef _WIN64\n    ULONG Reserved;\n#endif\n} ALPC_PORT_ATTRIBUTES, *PALPC_PORT_ATTRIBUTES;\n\n#define ALPC_MESSAGE_SECURITY_ATTRIBUTE 0x80000000\n#define ALPC_MESSAGE_VIEW_ATTRIBUTE 0x40000000\n#define ALPC_MESSAGE_CONTEXT_ATTRIBUTE 0x20000000\n#define ALPC_MESSAGE_HANDLE_ATTRIBUTE 0x10000000\n\ntypedef struct _ALPC_MESSAGE_ATTRIBUTES\n{\n    ULONG AllocatedAttributes;\n    ULONG ValidAttributes;\n} ALPC_MESSAGE_ATTRIBUTES, *PALPC_MESSAGE_ATTRIBUTES;\n\n#define ALPC_MSGFLG_REPLY_MESSAGE 0x1\n#define ALPC_MSGFLG_LPC_MODE 0x2 // ?\n#define ALPC_MSGFLG_RELEASE_MESSAGE 0x10000 // dbg\n#define ALPC_MSGFLG_SYNC_REQUEST 0x20000 // dbg\n#define ALPC_MSGFLG_WAIT_USER_MODE 0x100000\n#define ALPC_MSGFLG_WAIT_ALERTABLE 0x200000\n#define ALPC_MSGFLG_WOW64_CALL 0x80000000 // dbg\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PUNICODE_STRING PortName,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_ ULONG Flags,\n    _In_opt_ PSID RequiredServerSid,\n    _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage,\n    _Inout_opt_ PSIZE_T BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n// LXCORE\n\ntypedef\n_Function_class_(LXP_PROCESS_GET_CURRENT)\n_Must_inspect_result_\nBOOLEAN\nNTAPI\nLXP_PROCESS_GET_CURRENT(\n    _Out_ PVOID* Thread\n    );\ntypedef LXP_PROCESS_GET_CURRENT* PLXP_PROCESS_GET_CURRENT;\n\ntypedef\n_Function_class_(LXP_THREAD_GET_CURRENT)\n_Must_inspect_result_\nBOOLEAN\nNTAPI\nLXP_THREAD_GET_CURRENT(\n    _Out_ PVOID* Thread\n    );\ntypedef LXP_THREAD_GET_CURRENT* PLXP_THREAD_GET_CURRENT;\n\n// CFG\n\n//\n// Define flags for setting process CFG valid call target entries.\n//\n\n//\n// Call target should be made valid.  If not set, the call target is made\n// invalid.  Input flag.\n//\n\n#define CFG_CALL_TARGET_VALID                               (0x00000001)\n\n//\n// Call target has been successfully processed.  Used to report to the caller\n// how much progress has been made.  Output flag.\n//\n\n#define CFG_CALL_TARGET_PROCESSED                           (0x00000002)\n\n//\n// Call target should be made valid only if it is suppressed export.\n// What this flag means is that it can *only* be used on a cell which is\n// currently in the CFG export suppressed state (only considered for export\n// suppressed processes and not legacy CFG processes!), and it is also\n// allowed to be used even if the process is a restricted (i.e. no ACG) process.\n//\n\n#define CFG_CALL_TARGET_CONVERT_EXPORT_SUPPRESSED_TO_VALID  (0x00000004)\n\n//\n// Call target should be made into an XFG call target.\n//\n\n#define CFG_CALL_TARGET_VALID_XFG                           (0x00000008)\n\n//\n// Call target should be made valid only if it is already an XFG target\n// in a process which has XFG audit mode enabled.\n//\n\n#define CFG_CALL_TARGET_CONVERT_XFG_TO_CFG                  (0x00000010)\n\ntypedef struct _CFG_CALL_TARGET_INFO {\n    ULONG_PTR Offset;\n    ULONG_PTR Flags;\n} CFG_CALL_TARGET_INFO, *PCFG_CALL_TARGET_INFO;\n\ntypedef struct _CFG_CALL_TARGET_LIST_INFORMATION\n{\n    ULONG NumberOfEntries;\n    ULONG Reserved;\n    PULONG NumberOfEntriesProcessed;\n    PCFG_CALL_TARGET_INFO CallTargetInfo;\n    PVOID Section; // since REDSTONE5\n    ULONGLONG FileOffset;\n} CFG_CALL_TARGET_LIST_INFORMATION, *PCFG_CALL_TARGET_LIST_INFORMATION;\n\n// SE\n\n#define SeDebugPrivilege RtlConvertUlongToLuid(SE_DEBUG_PRIVILEGE)\n#define SeCreateTokenPrivilege RtlConvertUlongToLuid(SE_CREATE_TOKEN_PRIVILEGE)\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nSeCaptureSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR OriginalSecurityDescriptor,\n    _In_ KPROCESSOR_MODE CurrentMode,\n    _In_ POOL_TYPE PoolType,\n    _In_ BOOLEAN CaptureIfKernel,\n    _Out_ PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor\n    );\n\nNTKERNELAPI\nNTSTATUS\nNTAPI\nSeReleaseSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR CapturedSecurityDescriptor,\n    _In_ KPROCESSOR_MODE CurrentMode,\n    _In_ BOOLEAN CaptureIfKernelMode\n    );\n\n#if (NTDDI_VERSION >= NTDDI_WINBLUE)\nNTKERNELAPI\nNTSTATUS\nNTAPI\nSeGetCachedSigningLevel(\n    _In_ PFILE_OBJECT FileObject,\n    _Out_ PULONG Flags,\n    _Out_ PSE_SIGNING_LEVEL SigningLevel,\n    _Out_writes_bytes_to_opt_(*ThumbprintSize, *ThumbprintSize) PUCHAR Thumbprint,\n    _Inout_opt_ PULONG ThumbprintSize,\n    _Out_opt_ PULONG ThumbprintAlgorithm\n    );\n#endif\n\ntypedef\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Function_class_(SE_REGISTER_IMAGE_VERIFICATION_CALLBACK)\nNTKERNELAPI\nNTSTATUS\nSE_REGISTER_IMAGE_VERIFICATION_CALLBACK(\n    _In_ SE_IMAGE_TYPE ImageType,\n    _In_ SE_IMAGE_VERIFICATION_CALLBACK_TYPE CallbackType,\n    _In_ PSE_IMAGE_VERIFICATION_CALLBACK_FUNCTION CallbackFunction,\n    _In_opt_ PVOID CallbackContext,\n    _Reserved_ SE_IMAGE_VERIFICATION_CALLBACK_TOKEN Token,\n    _Out_ PVOID* CallbackHandle\n    );\ntypedef SE_REGISTER_IMAGE_VERIFICATION_CALLBACK* PSE_REGISTER_IMAGE_VERIFICATION_CALLBACK;\n\ntypedef\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Function_class_(SE_UNREGISTER_IMAGE_VERIFICATION_CALLBACK)\nNTKERNELAPI\nVOID\nSE_UNREGISTER_IMAGE_VERIFICATION_CALLBACK(\n    _In_ PVOID CallbackHandle\n    );\ntypedef SE_UNREGISTER_IMAGE_VERIFICATION_CALLBACK* PSE_UNREGISTER_IMAGE_VERIFICATION_CALLBACK;\n\n// schannel.h\n\n#define UNISP_NAME_A    \"Microsoft Unified Security Protocol Provider\"\n#define UNISP_NAME_W    L\"Microsoft Unified Security Protocol Provider\"\n\n#define SSL2SP_NAME_A    \"Microsoft SSL 2.0\"\n#define SSL2SP_NAME_W    L\"Microsoft SSL 2.0\"\n\n#define SSL3SP_NAME_A    \"Microsoft SSL 3.0\"\n#define SSL3SP_NAME_W    L\"Microsoft SSL 3.0\"\n\n#define TLS1SP_NAME_A    \"Microsoft TLS 1.0\"\n#define TLS1SP_NAME_W    L\"Microsoft TLS 1.0\"\n\n#define PCT1SP_NAME_A    \"Microsoft PCT 1.0\"\n#define PCT1SP_NAME_W    L\"Microsoft PCT 1.0\"\n\n#define SCHANNEL_NAME_A  \"Schannel\"\n#define SCHANNEL_NAME_W  L\"Schannel\"\n\n#define DEFAULT_TLS_SSP_NAME_A  \"Default TLS SSP\"\n#define DEFAULT_TLS_SSP_NAME_W  L\"Default TLS SSP\"\n\n#ifdef UNICODE\n\n#define UNISP_NAME  UNISP_NAME_W\n#define PCT1SP_NAME  PCT1SP_NAME_W\n#define SSL2SP_NAME  SSL2SP_NAME_W\n#define SSL3SP_NAME  SSL3SP_NAME_W\n#define TLS1SP_NAME  TLS1SP_NAME_W\n#define SCHANNEL_NAME  SCHANNEL_NAME_W\n#define DEFAULT_TLS_SSP_NAME  DEFAULT_TLS_SSP_NAME_W\n\n#else\n\n#define UNISP_NAME  UNISP_NAME_A\n#define PCT1SP_NAME  PCT1SP_NAME_A\n#define SSL2SP_NAME  SSL2SP_NAME_A\n#define SSL3SP_NAME  SSL3SP_NAME_A\n#define TLS1SP_NAME  TLS1SP_NAME_A\n#define SCHANNEL_NAME  SCHANNEL_NAME_A\n#define DEFAULT_TLS_SSP_NAME  DEFAULT_TLS_SSP_NAME_A\n\n#endif\n\n#define SP_PROT_PCT1_SERVER             0x00000001\n#define SP_PROT_PCT1_CLIENT             0x00000002\n#define SP_PROT_PCT1                    (SP_PROT_PCT1_SERVER | SP_PROT_PCT1_CLIENT)\n\n#define SP_PROT_SSL2_SERVER             0x00000004\n#define SP_PROT_SSL2_CLIENT             0x00000008\n#define SP_PROT_SSL2                    (SP_PROT_SSL2_SERVER | SP_PROT_SSL2_CLIENT)\n\n#define SP_PROT_SSL3_SERVER             0x00000010\n#define SP_PROT_SSL3_CLIENT             0x00000020\n#define SP_PROT_SSL3                    (SP_PROT_SSL3_SERVER | SP_PROT_SSL3_CLIENT)\n\n#define SP_PROT_TLS1_SERVER             0x00000040\n#define SP_PROT_TLS1_CLIENT             0x00000080\n#define SP_PROT_TLS1                    (SP_PROT_TLS1_SERVER | SP_PROT_TLS1_CLIENT)\n\n#define SP_PROT_SSL3TLS1_CLIENTS        (SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT)\n#define SP_PROT_SSL3TLS1_SERVERS        (SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER)\n#define SP_PROT_SSL3TLS1                (SP_PROT_SSL3 | SP_PROT_TLS1)\n\n#define SP_PROT_UNI_SERVER              0x40000000\n#define SP_PROT_UNI_CLIENT              0x80000000\n#define SP_PROT_UNI                     (SP_PROT_UNI_SERVER | SP_PROT_UNI_CLIENT)\n\n#define SP_PROT_ALL                     0xffffffff\n#define SP_PROT_NONE                    0\n#define SP_PROT_CLIENTS                 (SP_PROT_PCT1_CLIENT | SP_PROT_SSL2_CLIENT | SP_PROT_SSL3_CLIENT | SP_PROT_UNI_CLIENT | SP_PROT_TLS1_CLIENT)\n#define SP_PROT_SERVERS                 (SP_PROT_PCT1_SERVER | SP_PROT_SSL2_SERVER | SP_PROT_SSL3_SERVER | SP_PROT_UNI_SERVER | SP_PROT_TLS1_SERVER)\n\n\n#define SP_PROT_TLS1_0_SERVER           SP_PROT_TLS1_SERVER\n#define SP_PROT_TLS1_0_CLIENT           SP_PROT_TLS1_CLIENT\n#define SP_PROT_TLS1_0                  (SP_PROT_TLS1_0_SERVER | \\\n                                         SP_PROT_TLS1_0_CLIENT)\n\n#define SP_PROT_TLS1_1_SERVER           0x00000100\n#define SP_PROT_TLS1_1_CLIENT           0x00000200\n#define SP_PROT_TLS1_1                  (SP_PROT_TLS1_1_SERVER | \\\n                                         SP_PROT_TLS1_1_CLIENT)\n\n#define SP_PROT_TLS1_2_SERVER           0x00000400\n#define SP_PROT_TLS1_2_CLIENT           0x00000800\n#define SP_PROT_TLS1_2                  (SP_PROT_TLS1_2_SERVER | \\\n                                         SP_PROT_TLS1_2_CLIENT)\n\n#define SP_PROT_TLS1_3_SERVER           0x00001000\n#define SP_PROT_TLS1_3_CLIENT           0x00002000\n#define SP_PROT_TLS1_3                  (SP_PROT_TLS1_3_SERVER | \\\n                                         SP_PROT_TLS1_3_CLIENT)\n\n#define SP_PROT_DTLS_SERVER             0x00010000\n#define SP_PROT_DTLS_CLIENT             0x00020000\n#define SP_PROT_DTLS                    (SP_PROT_DTLS_SERVER | \\\n                                         SP_PROT_DTLS_CLIENT)\n\n#define SP_PROT_DTLS1_0_SERVER          SP_PROT_DTLS_SERVER\n#define SP_PROT_DTLS1_0_CLIENT          SP_PROT_DTLS_CLIENT\n#define SP_PROT_DTLS1_0                 (SP_PROT_DTLS1_0_SERVER | SP_PROT_DTLS1_0_CLIENT)\n\n#define SP_PROT_DTLS1_2_SERVER          0x00040000\n#define SP_PROT_DTLS1_2_CLIENT          0x00080000\n#define SP_PROT_DTLS1_2                 (SP_PROT_DTLS1_2_SERVER | SP_PROT_DTLS1_2_CLIENT)\n\n#define SP_PROT_DTLS1_X_SERVER          (SP_PROT_DTLS1_0_SERVER | \\\n                                         SP_PROT_DTLS1_2_SERVER)\n\n#define SP_PROT_DTLS1_X_CLIENT          (SP_PROT_DTLS1_0_CLIENT | \\\n                                         SP_PROT_DTLS1_2_CLIENT)\n\n#define SP_PROT_DTLS1_X                 (SP_PROT_DTLS1_X_SERVER | \\\n                                         SP_PROT_DTLS1_X_CLIENT)\n\n#define SP_PROT_TLS1_1PLUS_SERVER       (SP_PROT_TLS1_1_SERVER | \\\n                                         SP_PROT_TLS1_2_SERVER | \\\n                                         SP_PROT_TLS1_3_SERVER)\n#define SP_PROT_TLS1_1PLUS_CLIENT       (SP_PROT_TLS1_1_CLIENT | \\\n                                         SP_PROT_TLS1_2_CLIENT | \\\n                                         SP_PROT_TLS1_3_CLIENT)\n\n#define SP_PROT_TLS1_1PLUS              (SP_PROT_TLS1_1PLUS_SERVER | \\\n                                         SP_PROT_TLS1_1PLUS_CLIENT)\n\n#define SP_PROT_TLS1_3PLUS_SERVER       SP_PROT_TLS1_3_SERVER\n#define SP_PROT_TLS1_3PLUS_CLIENT       SP_PROT_TLS1_3_CLIENT\n#define SP_PROT_TLS1_3PLUS              (SP_PROT_TLS1_3PLUS_SERVER | \\\n                                         SP_PROT_TLS1_3PLUS_CLIENT)\n\n#define SP_PROT_TLS1_X_SERVER           (SP_PROT_TLS1_0_SERVER | \\\n                                         SP_PROT_TLS1_1_SERVER | \\\n                                         SP_PROT_TLS1_2_SERVER | \\\n                                         SP_PROT_TLS1_3_SERVER)\n#define SP_PROT_TLS1_X_CLIENT           (SP_PROT_TLS1_0_CLIENT | \\\n                                         SP_PROT_TLS1_1_CLIENT | \\\n                                         SP_PROT_TLS1_2_CLIENT | \\\n                                         SP_PROT_TLS1_3_CLIENT)\n#define SP_PROT_TLS1_X                  (SP_PROT_TLS1_X_SERVER | \\\n                                         SP_PROT_TLS1_X_CLIENT)\n\n#define SP_PROT_SSL3TLS1_X_CLIENTS      (SP_PROT_TLS1_X_CLIENT | \\\n                                         SP_PROT_SSL3_CLIENT)\n#define SP_PROT_SSL3TLS1_X_SERVERS      (SP_PROT_TLS1_X_SERVER | \\\n                                         SP_PROT_SSL3_SERVER)\n#define SP_PROT_SSL3TLS1_X              (SP_PROT_SSL3 | SP_PROT_TLS1_X)\n\n#define SP_PROT_X_CLIENTS               (SP_PROT_CLIENTS | \\\n                                         SP_PROT_TLS1_X_CLIENT | \\\n                                         SP_PROT_DTLS1_X_CLIENT)\n#define SP_PROT_X_SERVERS               (SP_PROT_SERVERS | \\\n                                         SP_PROT_TLS1_X_SERVER | \\\n                                         SP_PROT_DTLS1_X_SERVER)\n\n#define SCH_CRED_NO_SYSTEM_MAPPER                    0x00000002\n#define SCH_CRED_NO_SERVERNAME_CHECK                 0x00000004\n#define SCH_CRED_MANUAL_CRED_VALIDATION              0x00000008\n#define SCH_CRED_NO_DEFAULT_CREDS                    0x00000010\n#define SCH_CRED_AUTO_CRED_VALIDATION                0x00000020\n#define SCH_CRED_USE_DEFAULT_CREDS                   0x00000040\n#define SCH_CRED_DISABLE_RECONNECTS                  0x00000080\n\n#define SCH_CRED_REVOCATION_CHECK_END_CERT           0x00000100\n#define SCH_CRED_REVOCATION_CHECK_CHAIN              0x00000200\n#define SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT 0x00000400\n#define SCH_CRED_IGNORE_NO_REVOCATION_CHECK          0x00000800\n#define SCH_CRED_IGNORE_REVOCATION_OFFLINE           0x00001000\n\n#define SCH_CRED_RESTRICTED_ROOTS                    0x00002000\n#define SCH_CRED_REVOCATION_CHECK_CACHE_ONLY         0x00004000\n#define SCH_CRED_CACHE_ONLY_URL_RETRIEVAL            0x00008000\n\n#define SCH_CRED_MEMORY_STORE_CERT                   0x00010000\n\n#define SCH_CRED_CACHE_ONLY_URL_RETRIEVAL_ON_CREATE  0x00020000\n\n#define SCH_SEND_ROOT_CERT                           0x00040000\n#define SCH_CRED_SNI_CREDENTIAL                      0x00080000\n#define SCH_CRED_SNI_ENABLE_OCSP                     0x00100000\n#define SCH_SEND_AUX_RECORD                          0x00200000\n#define SCH_USE_STRONG_CRYPTO                        0x00400000\n#define SCH_USE_PRESHAREDKEY_ONLY                    0x00800000\n#define SCH_USE_DTLS_ONLY                            0x01000000\n#define SCH_ALLOW_NULL_ENCRYPTION                    0x02000000\n\n#define SCHANNEL_RENEGOTIATE    0   // renegotiate a connection\n#define SCHANNEL_SHUTDOWN       1   // gracefully close down a connection\n#define SCHANNEL_ALERT          2   // build an error message\n#define SCHANNEL_SESSION        3   // session control\n\n#define SCH_CRED_V1              0x00000001\n#define SCH_CRED_V2              0x00000002  // for legacy code\n#define SCH_CRED_VERSION         0x00000002  // for legacy code\n#define SCH_CRED_V3              0x00000003  // for legacy code\n#define SCHANNEL_CRED_VERSION    0x00000004  // for legacy code\n#define SCH_CREDENTIALS_VERSION  0x00000005\n\ntypedef struct _SCHANNEL_CRED\n{\n    DWORD           dwVersion;      // always SCHANNEL_CRED_VERSION\n    DWORD           cCreds;\n    //PCCERT_CONTEXT *paCred;\n    PVOID           paCred;\n    //HCERTSTORE      hRootStore;\n    PVOID           hRootStore;\n\n    DWORD           cMappers;\n    struct _HMAPPER **aphMappers;\n\n    DWORD           cSupportedAlgs;\n    ALG_ID *        palgSupportedAlgs;\n\n    DWORD           grbitEnabledProtocols;\n    DWORD           dwMinimumCipherStrength;\n    DWORD           dwMaximumCipherStrength;\n    DWORD           dwSessionLifespan;\n    DWORD           dwFlags;\n    DWORD           dwCredFormat;\n} SCHANNEL_CRED, *PSCHANNEL_CRED;\n\ntypedef enum _eTlsAlgorithmUsage\n{\n    TlsParametersCngAlgUsageKeyExchange,          // Key exchange algorithm. RSA, ECHDE, DHE, etc.\n    TlsParametersCngAlgUsageSignature,            // Signature algorithm. RSA, DSA, ECDSA, etc.\n    TlsParametersCngAlgUsageCipher,               // Encryption algorithm. AES, DES, RC4, etc.\n    TlsParametersCngAlgUsageDigest,               // Digest of cipher suite. SHA1, SHA256, SHA384, etc.\n    TlsParametersCngAlgUsageCertSig               // Signature and/or hash used to sign certificate. RSA, DSA, ECDSA, SHA1, SHA256, etc.\n} eTlsAlgorithmUsage;\n\n//\n// SCH_CREDENTIALS structures\n//\ntypedef struct _CRYPTO_SETTINGS\n{\n    eTlsAlgorithmUsage  eAlgorithmUsage;         // How this algorithm is being used.\n    UNICODE_STRING      strCngAlgId;             // CNG algorithm identifier.\n    DWORD               cChainingModes;          // Set to 0 if CNG algorithm does not have a chaining mode.\n    PUNICODE_STRING     rgstrChainingModes;      // Set to NULL if CNG algorithm does not have a chaining mode.\n    DWORD               dwMinBitLength;          // Blacklist key sizes less than this. Set to 0 if not defined or CNG algorithm implies bit length.\n    DWORD               dwMaxBitLength;          // Blacklist key sizes greater than this. Set to 0 if not defined or CNG algorithm implies bit length.\n} CRYPTO_SETTINGS, *PCRYPTO_SETTINGS;\n\ntypedef struct _TLS_PARAMETERS\n{\n    DWORD               cAlpnIds;                // Valid for server applications only. Must be zero otherwise. Number of ALPN IDs in rgstrAlpnIds; set to 0 if applies to all.\n    PUNICODE_STRING     rgstrAlpnIds;            // Valid for server applications only. Must be NULL otherwise. Array of ALPN IDs that the following settings apply to; set to NULL if applies to all.\n    DWORD               grbitDisabledProtocols;  // List protocols you DO NOT want negotiated.\n    DWORD               cDisabledCrypto;         // Number of CRYPTO_SETTINGS structures; set to 0 if there are none.\n    PCRYPTO_SETTINGS    pDisabledCrypto;         // Array of CRYPTO_SETTINGS structures; set to NULL if there are none;\n    DWORD               dwFlags;                 // Optional flags to pass; set to 0 if there are none.\n} TLS_PARAMETERS, *PTLS_PARAMETERS;\n\n#define TLS_PARAMS_OPTIONAL 0x00000001           // Valid for server applications only. Must be zero otherwise.\n                                                 // TLS_PARAMETERS that will only be honored if they do not cause this server to terminate the handshake.\n\ntypedef struct _SCH_CREDENTIALS\n{\n    DWORD               dwVersion;               // Always SCH_CREDENTIALS_VERSION.\n    DWORD               dwCredFormat;\n    DWORD               cCreds;\n    //PCCERT_CONTEXT     *paCred;\n    PVOID               *paCred;\n    //HCERTSTORE          hRootStore;\n    PVOID               hRootStore;\n\n    DWORD               cMappers;\n    struct _HMAPPER   **aphMappers;\n\n    DWORD               dwSessionLifespan;\n    DWORD               dwFlags;\n    DWORD               cTlsParameters;\n    PTLS_PARAMETERS     pTlsParameters;\n} SCH_CREDENTIALS, *PSCH_CREDENTIALS;\n\n#define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16\n#define SCH_CRED_MAX_SUPPORTED_ALPN_IDS 16\n#define SCH_CRED_MAX_SUPPORTED_CRYPTO_SETTINGS 16\n#define SCH_CRED_MAX_SUPPORTED_CHAINING_MODES 16\n\n#define SECPKG_ATTR_ISSUER_LIST          0x50   // (OBSOLETE) returns SecPkgContext_IssuerListInfo\n#define SECPKG_ATTR_REMOTE_CRED          0x51   // (OBSOLETE) returns SecPkgContext_RemoteCredentialInfo\n#define SECPKG_ATTR_LOCAL_CRED           0x52   // (OBSOLETE) returns SecPkgContext_LocalCredentialInfo\n#define SECPKG_ATTR_REMOTE_CERT_CONTEXT  0x53   // returns PCCERT_CONTEXT\n#define SECPKG_ATTR_LOCAL_CERT_CONTEXT   0x54   // returns PCCERT_CONTEXT\n#define SECPKG_ATTR_ROOT_STORE           0x55   // returns HCERTCONTEXT to the root store\n#define SECPKG_ATTR_SUPPORTED_ALGS       0x56   // returns SecPkgCred_SupportedAlgs\n#define SECPKG_ATTR_CIPHER_STRENGTHS     0x57   // returns SecPkgCred_CipherStrengths\n#define SECPKG_ATTR_SUPPORTED_PROTOCOLS  0x58   // returns SecPkgCred_SupportedProtocols\n#define SECPKG_ATTR_ISSUER_LIST_EX       0x59   // returns SecPkgContext_IssuerListInfoEx\n#define SECPKG_ATTR_CONNECTION_INFO      0x5a   // returns SecPkgContext_ConnectionInfo\n#define SECPKG_ATTR_EAP_KEY_BLOCK        0x5b   // returns SecPkgContext_EapKeyBlock\n#define SECPKG_ATTR_MAPPED_CRED_ATTR     0x5c   // returns SecPkgContext_MappedCredAttr\n#define SECPKG_ATTR_SESSION_INFO         0x5d   // returns SecPkgContext_SessionInfo\n#define SECPKG_ATTR_APP_DATA             0x5e   // sets/returns SecPkgContext_SessionAppData\n#define SECPKG_ATTR_REMOTE_CERTIFICATES  0x5F   // returns SecPkgContext_Certificates\n#define SECPKG_ATTR_CLIENT_CERT_POLICY   0x60   // sets    SecPkgCred_ClientCertCtlPolicy\n#define SECPKG_ATTR_CC_POLICY_RESULT     0x61   // returns SecPkgContext_ClientCertPolicyResult\n#define SECPKG_ATTR_USE_NCRYPT           0x62   // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group\n#define SECPKG_ATTR_LOCAL_CERT_INFO      0x63   // returns SecPkgContext_CertInfo\n#define SECPKG_ATTR_CIPHER_INFO          0x64   // returns new CNG SecPkgContext_CipherInfo\n#define SECPKG_ATTR_EAP_PRF_INFO         0x65   // sets    SecPkgContext_EapPrfInfo\n#define SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66   // returns SecPkgContext_SupportedSignatures\n#define SECPKG_ATTR_REMOTE_CERT_CHAIN    0x67   // returns PCCERT_CONTEXT\n#define SECPKG_ATTR_UI_INFO              0x68   // sets SEcPkgContext_UiInfo\n#define SECPKG_ATTR_EARLY_START          0x69   // sets SecPkgContext_EarlyStart\n#define SECPKG_ATTR_KEYING_MATERIAL_INFO 0x6a   // sets SecPkgContext_KeyingMaterialInfo\n#define SECPKG_ATTR_KEYING_MATERIAL      0x6b   // returns SecPkgContext_KeyingMaterial\n#define SECPKG_ATTR_SRTP_PARAMETERS      0x6c   // returns negotiated SRTP parameters\n#define SECPKG_ATTR_TOKEN_BINDING        0x6d   // returns SecPkgContext_TokenBinding\n#define SECPKG_ATTR_CONNECTION_INFO_EX   0x6e   // returns SecPkgContext_ConnectionInfoEx\n#define SECPKG_ATTR_KEYING_MATERIAL_TOKEN_BINDING 0x6f // returns SecPkgContext_KeyingMaterial specific to Token Binding\n#define SECPKG_ATTR_KEYING_MATERIAL_INPROC        0x70 // returns SecPkgContext_KeyingMaterial_Inproc\n#define SECPKG_ATTR_CERT_CHECK_RESULT        0x71 // returns SecPkgContext_CertificateValidationResult, use during and after SSPI handshake loop\n#define SECPKG_ATTR_CERT_CHECK_RESULT_INPROC 0x72 // returns SecPkgContext_CertificateValidationResult, use only after SSPI handshake loop\n#define SECPKG_ATTR_SESSION_TICKET_KEYS      0x73 // sets    SecPkgCred_SessionTicketKeys\n#define SECPKG_ATTR_SERIALIZED_REMOTE_CERT_CONTEXT_INPROC 0x74 // returns CERT_BLOB, use only after SSPI handshake loop\n#define SECPKG_ATTR_SERIALIZED_REMOTE_CERT_CONTEXT 0x75 // returns CERT_BLOB, use during and after SSPI handshake loop\n\ntypedef struct _SecPkgContext_ConnectionInfo\n{\n    DWORD   dwProtocol;\n    ALG_ID  aiCipher;\n    DWORD   dwCipherStrength;\n    ALG_ID  aiHash;\n    DWORD   dwHashStrength;\n    ALG_ID  aiExch;\n    DWORD   dwExchStrength;\n} SecPkgContext_ConnectionInfo, *PSecPkgContext_ConnectionInfo;\n\n#define SZ_ALG_MAX_SIZE 64\n\n#define SECPKGCONTEXT_CONNECTION_INFO_EX_V1   1\n\ntypedef struct _SecPkgContext_ConnectionInfoEx\n{\n    DWORD   dwVersion;\n    DWORD   dwProtocol;\n    WCHAR   szCipher[SZ_ALG_MAX_SIZE];\n    DWORD   dwCipherStrength;\n    WCHAR   szHash[SZ_ALG_MAX_SIZE];\n    DWORD   dwHashStrength;\n    WCHAR   szExchange[SZ_ALG_MAX_SIZE];\n    DWORD   dwExchStrength;\n} SecPkgContext_ConnectionInfoEx, *PSecPkgContext_ConnectionInfoEx;\n\n#define SECPKGCONTEXT_CIPHERINFO_V1 1\n\ntypedef struct _SecPkgContext_CipherInfo\n{\n\n    DWORD dwVersion;\n    DWORD dwProtocol;\n    DWORD dwCipherSuite;\n    DWORD dwBaseCipherSuite;\n    WCHAR szCipherSuite[SZ_ALG_MAX_SIZE];\n    WCHAR szCipher[SZ_ALG_MAX_SIZE];\n    DWORD dwCipherLen;\n    DWORD dwCipherBlockLen;    // in bytes\n    WCHAR szHash[SZ_ALG_MAX_SIZE];\n    DWORD dwHashLen;\n    WCHAR szExchange[SZ_ALG_MAX_SIZE];\n    DWORD dwMinExchangeLen;\n    DWORD dwMaxExchangeLen;\n    WCHAR szCertificate[SZ_ALG_MAX_SIZE];\n    DWORD dwKeyType;\n} SecPkgContext_CipherInfo, *PSecPkgContext_CipherInfo;\n"
  },
  {
    "path": "KSystemInformer/include/pooltags.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n\n// alloc\n\n#define KPH_TAG_PAGED_LOOKASIDE_OBJECT          '0ApK'\n#define KPH_TAG_NPAGED_LOOKASIDE_OBJECT         '1ApK'\n\n// comms\n\n#define KPH_TAG_CLIENT                          '0CpK'\n#define KPH_TAG_MESSAGE                         '1CpK'\n#define KPH_TAG_NPAGED_MESSAGE                  '2CpK'\n#define KPH_TAG_QUEUE_ITEM                      '3CpK'\n#define KPH_TAG_THREAD_POOL                     '4CpK'\n#define KPH_TAG_CLIENT_INFORMER_STATE           '5CpK'\n#define KPH_TAG_CLIENT_INFORMER_SETTINGS        '6CpK'\n\n// dyndata\n\n#define KPH_TAG_DYNDATA                         '0YpK'\n\n// object\n\n#define KPH_TAG_OBJECT_QUERY                    '0OpK'\n#define KPH_TAG_OBJECT_INFO                     '1OpK'\n\n// process\n\n#define KPH_TAG_PROCESS_INFO                    '0PpK'\n\n// thread\n\n#define KPH_TAG_THREAD_BACK_TRACE               '0TpK'\n#define KPH_TAG_THREAD_INFO                     '1TpK'\n\n// util\n\n#define KPH_TAG_REG_STRING                      '0UpK'\n#define KPH_TAG_REG_BINARY                      '1UpK'\n#define KPH_TAG_FILE_OBJECT_NAME                '2UpK'\n#define KPH_TAG_CAPTURED_UNICODE_STRING         '3UpK'\n\n// vm\n\n#define KPH_TAG_COPY_VM                         '0vpK'\n#define KPH_TAG_SECTION_QUERY                   '1vpK'\n#define KPH_TAG_VM_QUERY                        '2vpK'\n\n// debug\n\n#define KPH_TAG_DBG_SLOTS                       '0dpK'\n\n// hash\n\n#define KPH_TAG_HASHING_CONTEXT                 '0HpK'\n#define KPH_TAG_HASHING_INFRA                   '1HpK'\n#define KPH_TAG_CAPTURED_HASHES                 '2HpK'\n\n// verify\n\n#define KPH_TAG_VERIFY_SIGNATURE                '0VpK'\n\n// informer\n\n#define KPH_TAG_OB_OBJECT_NAME                  '0IpK'\n#define KPH_TAG_PROCESS_CREATE_APC              '1IpK'\n#define KPH_TAG_FLT_STREAMHANDLE_CONTEXT        '2IpK'\n#define KPH_TAG_FLT_FILE_NAME                   '3IpK'\n#define KPH_TAG_FLT_CACHED_FILE_NAME            '4IpK'\n#define KPH_TAG_FLT_COMPLETION_CONTEXT          '5IpK'\n#define KPH_TAG_REG_CALL_CONTEXT                '6IpK'\n#define KPH_TAG_REG_OBJECT_NAME                 '7IpK'\n#define KPH_TAG_REG_VALUE_NAMES                 '8IpK'\n#define KPH_TAG_OB_CALL_CONTEXT                 '9IpK'\n#define KPH_TAG_INFORMER_STATE                  'SIpK'\n#define KPH_TAG_INFORMER_SETTINGS               'sIpK'\n\n// cid_tracking\n\n#define KPH_TAG_CID_TABLE                       '0cpK'\n#define KPH_TAG_CID_POPULATE                    '1cpK'\n#define KPH_TAG_PROCESS_CONTEXT                 '2cpK'\n#define KPH_TAG_THREAD_CONTEXT                  '3cpK'\n#define KPH_TAG_CID_APC                         '4cpK'\n#define KPH_TAG_PROCESS_IMAGE_FILE_NAME         '5cpK'\n\n// protection\n\n#define KPH_TAG_IMAGE_LOAD_APC                  '0ppK'\n\n// alpc\n\n#define KPH_TAG_ALPC_NAME_QUERY                 '0apK'\n#define KPH_TAG_ALPC_QUERY                      '1apK'\n\n// file\n\n#define KPH_TAG_FILE_QUERY                      '0FpK'\n#define KPH_TAG_VOL_FILE_QUERY                  '1FpK'\n\n// back_trace\n\n#define KPH_TAG_BACK_TRACE_OBJECT               '0BpK'\n\n// session_token\n\n#define KPH_TAG_SESSION_TOKEN_OBJECT            '0tpK'\n#define KPH_TAG_SESSION_TOKEN_SIGNATURE         '1tpK'\n\n// ringbuff\n\n#define KPH_TAG_RING_BUFFER                     '0RpK'\n\n// kphthread\n\n#define KPH_TAG_THREAD_START_CONTEXT             '0rpK'\n"
  },
  {
    "path": "KSystemInformer/include/trace.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n\n#define WPP_CONTROL_GUIDS                                                      \\\n    WPP_DEFINE_CONTROL_GUID(                                                   \\\n        KSystemInformer, (f64b58a2, 8214, 4037, 8c7d, b96ce6098f3d),           \\\n        WPP_DEFINE_BIT(GENERAL)     /* bit  0 = 0x00000001 */                  \\\n        WPP_DEFINE_BIT(UTIL)        /* bit  1 = 0x00000002 */                  \\\n        WPP_DEFINE_BIT(COMMS)       /* bit  2 = 0x00000004 */                  \\\n        WPP_DEFINE_BIT(INFORMER)    /* bit  3 = 0x00000008 */                  \\\n        WPP_DEFINE_BIT(VERIFY)      /* bit  4 = 0x00000010 */                  \\\n        WPP_DEFINE_BIT(HASH)        /* bit  5 = 0x00000020 */                  \\\n        WPP_DEFINE_BIT(TRACKING)    /* bit  5 = 0x00000040 */                  \\\n        WPP_DEFINE_BIT(PROTECTION)  /* bit  5 = 0x00000080 */                  \\\n        )\n\n#define WPP_LEVEL_EVENT_LOGGER(level,event) WPP_LEVEL_LOGGER(event)\n#define WPP_LEVEL_EVENT_ENABLED(level,event) \\\n    (WPP_LEVEL_ENABLED(event) && \\\n     WPP_CONTROL(WPP_BIT_ ## event).Level >= level)\n\n//\n// begin_wpp config\n// FUNC KphTracePrint(LEVEL,EVENT,MSG, ...);\n// end_wpp\n//\n\n#ifdef KSI_NO_WPP\n#define KphTracePrint(LEVEL,EVENT,MSG,...) ((void)(MSG, ## __VA_ARGS__))\n#define WPP_INIT_TRACING(...)              ((void)0)\n#define WPP_CLEANUP(...)                   ((void)0)\n#endif\n\n#define TMH_STRINGIFYX(x) #x\n#define TMH_STRINGIFY(x) TMH_STRINGIFYX(x)\n\n#ifdef TMH_FILE\n#include TMH_STRINGIFY(TMH_FILE)\n#endif\n"
  },
  {
    "path": "KSystemInformer/informer.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n\n#include <kph.h>\n#include <comms.h>\n#include <informer.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_INFORMER_STATE\n{\n    KPH_INFORMER_OPTIONS Options;\n    KPH_RATE_LIMIT RateLimit[KPH_INFORMER_COUNT];\n} KPH_INFORMER_STATE, *PKPH_INFORMER_STATE;\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_OBJECT_TYPE KphpInformerStateType = NULL;\nstatic PKPH_NPAGED_LOOKASIDE_OBJECT KphpInformerStateLookaside = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpInformerStateTypeName = RTL_CONSTANT_STRING(L\"KphInformerState\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nstatic KPH_INFORMER_STATE_ATOMIC KphpInformerState = { .Atomic = KPH_ATOMIC_OBJECT_REF_INIT };\n\n/**\n * \\brief Allocates an informer state object.\n *\n * \\return Pointer to informer state object, null on failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateInformerState(\n    _In_ SIZE_T Size\n    )\n{\n    PVOID object;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    NT_ASSERT(KphpInformerStateLookaside);\n    NT_ASSERT(Size <= KphpInformerStateLookaside->L.Size);\n    DBG_UNREFERENCED_PARAMETER(Size);\n\n    object = KphAllocateFromNPagedLookasideObject(KphpInformerStateLookaside);\n    if (object)\n    {\n        KphReferenceObject(KphpInformerStateLookaside);\n    }\n\n    return object;\n}\n\n/**\n * \\brief Initializes an informer state object.\n *\n * \\param[in] Object The informer state object to initialize.\n * \\param[in] Parameter Optional settings to initialize with.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_Must_inspect_result_\nNTSTATUS\nKSIAPI\nKphpInitializeInformerState(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_INFORMER_STATE state;\n    PKPH_INFORMER_SETTINGS settings;\n    LARGE_INTEGER timeStamp;\n\n    state = Object;\n    settings = Parameter;\n\n    KeQuerySystemTime(&timeStamp);\n\n    if (settings)\n    {\n        state->Options.Flags = settings->Options.Flags;\n\n        for (ULONG i = 0; i < KPH_INFORMER_COUNT; i++)\n        {\n            KphInitializeRateLimit(&settings->Policy[i],\n                                   &timeStamp,\n                                   &state->RateLimit[i]);\n        }\n    }\n    else\n    {\n        KPH_RATE_LIMIT_POLICY policy = KPH_RATE_LIMIT_DENY_ALL;\n\n        state->Options.Flags = 0;\n\n        for (ULONG i = 0; i < KPH_INFORMER_COUNT; i++)\n        {\n            KphInitializeRateLimit(&policy, &timeStamp, &state->RateLimit[i]);\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Frees an informer state object.\n *\n * \\param[in] Object The informer state object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KSIAPI KphpFreeInformerState(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    NT_ASSERT(KphpInformerStateLookaside);\n\n    KphFreeToNPagedLookasideObject(KphpInformerStateLookaside, Object);\n    KphDereferenceObject(KphpInformerStateLookaside);\n}\n\n/**\n * \\brief Checks if an informer is allowed for a process.\n *\n * \\param[in] Index The informer index to check.\n * \\param[in] TimeStamp The current time stamp.\n * \\param[in] Process The process context to check.\n *\n * \\return TRUE if the informer is allowed, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphInformerProcessAllowed(\n    _In_ ULONG Index,\n    _In_ PLARGE_INTEGER TimeStamp,\n    _In_opt_ PKPH_PROCESS_CONTEXT Process\n    )\n{\n    BOOLEAN allowed;\n    PKPH_INFORMER_STATE state;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (!Process)\n    {\n        return TRUE;\n    }\n\n    if (!NT_VERIFY(Index < KPH_INFORMER_COUNT))\n    {\n        return FALSE;\n    }\n\n    state = KphAtomicReferenceObject(&Process->InformerState.Atomic);\n    if (!state)\n    {\n        return TRUE;\n    }\n\n    allowed = KphRateLimitConsumeToken(&state->RateLimit[Index], TimeStamp);\n\n    KphDereferenceObject(state);\n\n    return allowed;\n}\n\n/**\n * \\brief Checks if an informer is globally allowed.\n *\n * \\param[in] Index The informer index to check.\n * \\param[in] TimeStamp The current time stamp.\n *\n * \\return TRUE if the informer is allowed, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphInformerGlobalAllowed(\n    _In_ ULONG Index,\n    _In_ PLARGE_INTEGER TimeStamp\n    )\n{\n    BOOLEAN allowed;\n    PKPH_INFORMER_STATE state;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (!NT_VERIFY(Index < KPH_INFORMER_COUNT))\n    {\n        return FALSE;\n    }\n\n    state = KphAtomicReferenceObject(&KphpInformerState.Atomic);\n    NT_ASSERT(state);\n\n    allowed = KphRateLimitConsumeToken(&state->RateLimit[Index], TimeStamp);\n\n    KphDereferenceObject(state);\n\n    return allowed;\n}\n\n/**\n * \\brief Checks if an informer is allowed.\n *\n * \\param[in] Index The informer index to check.\n * \\param[in] ActorProcess The actor process check.\n * \\param[in] TargetProcess The target process check.\n *\n * \\return TRUE if the informer is allowed, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphInformerAllowed(\n    _In_ ULONG Index,\n    _In_opt_ PKPH_PROCESS_CONTEXT ActorProcess,\n    _In_opt_ PKPH_PROCESS_CONTEXT TargetProcess\n    )\n{\n    LARGE_INTEGER timeStamp;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (!KphGetInformerClientCount())\n    {\n        return FALSE;\n    }\n\n    KeQuerySystemTime(&timeStamp);\n\n    if (!KphInformerProcessAllowed(Index, &timeStamp, ActorProcess))\n    {\n        if (ActorProcess == TargetProcess)\n        {\n            return FALSE;\n        }\n\n        if (!KphInformerProcessAllowed(Index, &timeStamp, TargetProcess))\n        {\n            return FALSE;\n        }\n    }\n\n    if (!KphInformerGlobalAllowed(Index, &timeStamp))\n    {\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * \\brief Retrieves the active informer options.\n *\n * \\param[in] ActorProcess The actor process check.\n * \\param[in] TargetProcess The target process check.\n *\n * \\return Active informer options.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nKPH_INFORMER_OPTIONS KphInformerOptions(\n    _In_opt_ PKPH_PROCESS_CONTEXT ActorProcess,\n    _In_opt_ PKPH_PROCESS_CONTEXT TargetProcess\n    )\n{\n    PKPH_INFORMER_STATE state;\n    KPH_INFORMER_OPTIONS options;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    options.Flags = 0;\n\n    state = KphAtomicReferenceObject(&KphpInformerState.Atomic);\n    NT_ASSERT(state);\n\n    SetFlag(options.Flags, state->Options.Flags);\n\n    KphDereferenceObject(state);\n\n    if (ActorProcess)\n    {\n        state = KphAtomicReferenceObject(&ActorProcess->InformerState.Atomic);\n        if (state)\n        {\n            SetFlag(options.Flags, state->Options.Flags);\n            KphDereferenceObject(state);\n        }\n    }\n\n    if (TargetProcess)\n    {\n        state = KphAtomicReferenceObject(&TargetProcess->InformerState.Atomic);\n        if (state)\n        {\n            SetFlag(options.Flags, state->Options.Flags);\n            KphDereferenceObject(state);\n        }\n    }\n\n    return options;\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Copies informer settings from state to mode.\n *\n * \\param[out] Settings Receives the settings.\n * \\param[in] State The informer state to copy from.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpInformerCopySettingsToMode(\n    _Out_ PKPH_INFORMER_SETTINGS Settings,\n    _In_ PKPH_INFORMER_STATE State,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = KphCopyToMode(Settings,\n                           &State->Options,\n                           sizeof(KPH_INFORMER_OPTIONS),\n                           AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    for (ULONG i = 0; i < KPH_INFORMER_COUNT; i++)\n    {\n        status = KphCopyToMode(&Settings->Policy[i],\n                               &State->RateLimit[i].Policy,\n                               sizeof(KPH_RATE_LIMIT_POLICY),\n                               AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            return status;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Gets informer settings.\n *\n * \\param[out] Settings Receives the settings.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerSettings(\n    _Out_ PKPH_INFORMER_SETTINGS Settings,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_INFORMER_STATE state;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    state = KphAtomicReferenceObject(&KphpInformerState.Atomic);\n    NT_ASSERT(state);\n\n    status = KphZeroModeMemory(Settings,\n                               sizeof(KPH_INFORMER_SETTINGS),\n                               AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    status = KphpInformerCopySettingsToMode(Settings, state, AccessMode);\n\nExit:\n\n    KphDereferenceObject(state);\n\n    return status;\n}\n\n/**\n * \\brief Sets informer settings.\n *\n * \\param[in] Settings The settings to apply.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformerSettings(\n    _In_ PKPH_INFORMER_SETTINGS Settings,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_INFORMER_SETTINGS settings;\n    PKPH_INFORMER_STATE state;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    state = NULL;\n\n    settings = KphAllocatePaged(sizeof(KPH_INFORMER_SETTINGS),\n                                KPH_TAG_INFORMER_SETTINGS);\n    if (!settings)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Failed to allocate informer settings\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphCopyFromMode(settings,\n                             Settings,\n                             sizeof(KPH_INFORMER_SETTINGS),\n                             AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    status = KphCreateObject(KphpInformerStateType,\n                             sizeof(KPH_INFORMER_STATE),\n                             &state,\n                             settings);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        state = NULL;\n        goto Exit;\n    }\n\n    KphAtomicAssignObjectReference(&KphpInformerState.Atomic, state);\n\nExit:\n\n    if (state)\n    {\n        KphDereferenceObject(state);\n    }\n\n    if (settings)\n    {\n        KphFree(settings, KPH_TAG_INFORMER_SETTINGS);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Gets informer settings for a process.\n *\n * \\param[in] ProcessHandle Handle to the process to get settings of.\n * \\param[out] Settings Receives the settings.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerProcessSettings(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKPH_INFORMER_SETTINGS Settings,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS processObject;\n    PKPH_PROCESS_CONTEXT processContext;\n    PKPH_INFORMER_STATE state;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    processObject = NULL;\n    processContext = NULL;\n    state = NULL;\n\n    status = KphZeroModeMemory(Settings,\n                               sizeof(KPH_INFORMER_SETTINGS),\n                               AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &processObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        processObject = NULL;\n        goto Exit;\n    }\n\n    processContext = KphGetEProcessContext(processObject);\n    if (!processContext)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphGetEProcessContext return null.\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    state = KphAtomicReferenceObject(&processContext->InformerState.Atomic);\n    if (!state)\n    {\n        status = STATUS_NOT_FOUND;\n        goto Exit;\n    }\n\n    status = KphpInformerCopySettingsToMode(Settings, state, AccessMode);\n\nExit:\n\n    if (processContext)\n    {\n        KphDereferenceObject(processContext);\n    }\n\n    if (processObject)\n    {\n        ObDereferenceObject(processObject);\n    }\n\n    if (state)\n    {\n        KphDereferenceObject(state);\n    }\n\n    return status;\n}\n\ntypedef struct _KPH_SET_INFORMER_PROCESS_SETTINGS_CONTEXT\n{\n    NTSTATUS Status;\n    PKPH_INFORMER_SETTINGS Settings;\n} KPH_SET_INFORMER_PROCESS_SETTINGS_CONTEXT, *PKPH_SET_INFORMER_PROCESS_SETTINGS_CONTEXT;\n\n/**\n * \\brief Callback for setting process informer settings.\n *\n * \\param[in] Process The process to set the informer settings for.\n * \\param[in] Parameter The settings to apply.\n *\n * \\return FALSE\n */\n_Function_class_(KPH_ENUM_PROCESS_CONTEXTS_CALLBACK)\n_Must_inspect_result_\nBOOLEAN KSIAPI KphpSetInformerProcessSettings(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PKPH_SET_INFORMER_PROCESS_SETTINGS_CONTEXT context;\n    PKPH_PROCESS_STATE state;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(Parameter);\n\n    context = Parameter;\n\n    status = KphCreateObject(KphpInformerStateType,\n                             sizeof(KPH_INFORMER_STATE),\n                             &state,\n                             context->Settings);\n    if (!NT_SUCCESS(status))\n    {\n        if (NT_SUCCESS(context->Status))\n        {\n            context->Status = status;\n        }\n\n        return FALSE;\n    }\n\n    KphAtomicAssignObjectReference(&Process->InformerState.Atomic, state);\n\n    KphDereferenceObject(state);\n\n    return FALSE;\n}\n\n/**\n * \\brief Sets informer settings for a process.\n *\n * \\param[in] ProcessHandle Optional handle to the process to set settings of.\n *  If not provided the settings are applied to all processes.\n * \\param[in] Settings The settings to apply.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformerProcessSettings(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PKPH_INFORMER_SETTINGS Settings,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS processObject;\n    PKPH_PROCESS_CONTEXT processContext;\n    PKPH_INFORMER_SETTINGS settings;\n    KPH_SET_INFORMER_PROCESS_SETTINGS_CONTEXT context;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    processObject = NULL;\n    processContext = NULL;\n\n    settings = KphAllocatePaged(sizeof(KPH_INFORMER_SETTINGS),\n                                KPH_TAG_INFORMER_SETTINGS);\n    if (!settings)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Failed to allocate informer settings\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphCopyFromMode(settings,\n                             Settings,\n                             sizeof(KPH_INFORMER_SETTINGS),\n                             AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    if (ProcessHandle)\n    {\n        status = ObReferenceObjectByHandle(ProcessHandle,\n                                           0,\n                                           *PsProcessType,\n                                           AccessMode,\n                                           &processObject,\n                                           NULL);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                          status);\n\n            processObject = NULL;\n            goto Exit;\n        }\n\n        processContext = KphGetEProcessContext(processObject);\n        if (!processContext)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"KphGetEProcessContext return null.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        context.Status = STATUS_SUCCESS;\n        context.Settings = settings;\n        (VOID)KphpSetInformerProcessSettings(processContext, &context);\n        status = context.Status;\n    }\n    else\n    {\n        context.Status = STATUS_SUCCESS;\n        context.Settings = settings;\n        KphEnumerateProcessContexts(KphpSetInformerProcessSettings, &context);\n        status = context.Status;\n    }\n\nExit:\n\n    if (processContext)\n    {\n        KphDereferenceObject(processContext);\n    }\n\n    if (processObject)\n    {\n        ObDereferenceObject(processObject);\n    }\n\n    if (settings)\n    {\n        KphFree(settings, KPH_TAG_INFORMER_SETTINGS);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Gets informer statistics.\n *\n * \\param[in] ProcessHandle Optional handle to the process to get stats of. If\n *  not provided the global stats are returned.\n * \\param[out] Stats Receives the informer statistics.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetInformerStats(\n    _In_opt_ HANDLE ProcessHandle,\n    _Out_ PKPH_INFORMER_STATS Stats,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_INFORMER_STATE state;\n    PEPROCESS processObject;\n    PKPH_PROCESS_CONTEXT processContext;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    state = NULL;\n    processObject = NULL;\n    processContext = NULL;\n\n    status = KphZeroModeMemory(Stats, sizeof(KPH_INFORMER_STATS), AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    if (ProcessHandle)\n    {\n        status = ObReferenceObjectByHandle(ProcessHandle,\n                                           0,\n                                           *PsProcessType,\n                                           AccessMode,\n                                           &processObject,\n                                           NULL);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                          status);\n\n            processObject = NULL;\n            goto Exit;\n        }\n\n        processContext = KphGetEProcessContext(processObject);\n        if (!processContext)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"KphGetEProcessContext return null.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        state = KphAtomicReferenceObject(&processContext->InformerState.Atomic);\n        if (!state)\n        {\n            status = STATUS_NOT_FOUND;\n            goto Exit;\n        }\n    }\n    else\n    {\n        state = KphAtomicReferenceObject(&KphpInformerState.Atomic);\n    }\n\n    NT_ASSERT(state);\n\n    for (ULONG i = 0; i < KPH_INFORMER_COUNT; i++)\n    {\n        status = KphCopyToMode(&Stats->RateLimit[i].Policy,\n                               &state->RateLimit[i].Policy,\n                               sizeof(KPH_RATE_LIMIT_POLICY),\n                               AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n\n        status = KphWriteLong64ToMode(&Stats->RateLimit[i].Allowed,\n                                      ReadNoFence64(&state->RateLimit[i].Allowed),\n                                      AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n\n        status = KphWriteLong64ToMode(&Stats->RateLimit[i].Dropped,\n                                      ReadNoFence64(&state->RateLimit[i].Dropped),\n                                      AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n\n        status = KphWriteLong64ToMode(&Stats->RateLimit[i].CasMiss,\n                                      ReadNoFence64(&state->RateLimit[i].CasMiss),\n                                      AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\nExit:\n\n    if (processContext)\n    {\n        KphDereferenceObject(processContext);\n    }\n\n    if (processObject)\n    {\n        ObDereferenceObject(processObject);\n    }\n\n    if (state)\n    {\n        KphDereferenceObject(state);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Cleans up informer infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupInformer(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphAtomicAssignObjectReference(&KphpInformerState.Atomic, NULL);\n\n    if (KphpInformerStateLookaside)\n    {\n        KphDereferenceObject(KphpInformerStateLookaside);\n    }\n}\n\n/**\n * \\brief Initialize the informer infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphInitializeInformer(\n    VOID\n    )\n{\n    NTSTATUS status;\n    PKPH_INFORMER_STATE state;\n    KPH_OBJECT_TYPE_INFO typeInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    state = NULL;\n\n    status = KphCreateNPagedLookasideObject(&KphpInformerStateLookaside,\n                                            KphAddObjectHeaderSize(sizeof(KPH_INFORMER_STATE)),\n                                            KPH_TAG_INFORMER_STATE);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KphCreatePagedLookasideObject failed: %!STATUS!\",\n                      status);\n\n        KphpInformerStateLookaside = NULL;\n        goto Exit;\n    }\n\n    typeInfo.Allocate = KphpAllocateInformerState;\n    typeInfo.Initialize = KphpInitializeInformerState;\n    typeInfo.Delete = NULL;\n    typeInfo.Free = KphpFreeInformerState;\n\n    KphCreateObjectType(&KphpInformerStateTypeName,\n                        &typeInfo,\n                        &KphpInformerStateType);\n\n    status = KphCreateObject(KphpInformerStateType,\n                             sizeof(KPH_INFORMER_STATE),\n                             &state,\n                             NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        state = NULL;\n        goto Exit;\n    }\n\n    KphAtomicAssignObjectReference(&KphpInformerState.Atomic, state);\n\nExit:\n\n    if (state)\n    {\n        KphDereferenceObject(state);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/informer_debug.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <informer.h>\n#include <comms.h>\n#include <kphmsgdyn.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_DBG_PRINT_SLOT\n{\n    KDPC Dpc;\n    LARGE_INTEGER TimeStamp;\n    CLIENT_ID ContextClientId;\n    ULONG ComponentId;\n    ULONG Level;\n    USHORT Length;\n    CHAR Buffer[FIELD_SIZE(KPH_MESSAGE, _Dyn.Buffer)];\n} KPH_DBG_PRINT_SLOT, *PKPH_DBG_PRINT_SLOT;\n\nstatic BOOLEAN KphpDbgPrintInitialized = FALSE;\nstatic KSPIN_LOCK KphpDbgPrintLock;\nstatic ULONG KphpDbgPrintSlotNext = 0;\nstatic ULONG KphpDbgPrintSlotCount = 0;\nstatic PKPH_DBG_PRINT_SLOT KphpDbgPrintSlots = NULL;\n\n/**\n * \\brief Flushes the debug print slots to the communication port.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_IRQL_requires_min_(DISPATCH_LEVEL)\n_IRQL_requires_(DISPATCH_LEVEL)\n_Requires_lock_held_(KphpDbgPrintLock)\nVOID KphpDebugPrintFlush(\n    VOID\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH();\n\n    for (ULONG i = 0; i < KphpDbgPrintSlotNext; i++)\n    {\n        NTSTATUS status;\n        PKPH_PROCESS_CONTEXT process;\n        BOOLEAN enabled;\n        USHORT remaining;\n        ANSI_STRING output;\n        PKPH_MESSAGE msg;\n        PKPH_DBG_PRINT_SLOT slot;\n\n        slot = &KphpDbgPrintSlots[i];\n\n        process = KphGetProcessContext(slot->ContextClientId.UniqueProcess);\n        enabled = KphInformerEnabled(DebugPrint, process);\n        if (process)\n        {\n            KphDereferenceObjectDeferDelete(process);\n        }\n\n        if (!enabled)\n        {\n            continue;\n        }\n\n        msg = KphAllocateNPagedMessage();\n        if (!msg)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to allocate message\");\n            continue;\n        }\n\n        KphMsgInit(msg, KphMsgDebugPrint);\n        msg->Header.TimeStamp.QuadPart = slot->TimeStamp.QuadPart;\n        msg->Kernel.DebugPrint.ContextClientId.UniqueProcess = slot->ContextClientId.UniqueProcess;\n        msg->Kernel.DebugPrint.ContextClientId.UniqueThread = slot->ContextClientId.UniqueThread;\n        msg->Kernel.DebugPrint.ComponentId = slot->ComponentId;\n        msg->Kernel.DebugPrint.Level = slot->Level;\n\n        remaining = KphMsgDynRemaining(msg);\n\n        if (slot->Length > remaining)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Truncated debug print line\");\n        }\n\n        output.Length = min(slot->Length, remaining);\n        output.MaximumLength = slot->Length;\n        output.Buffer = slot->Buffer;\n\n        status = KphMsgDynAddAnsiString(msg, KphMsgFieldOutput, &output);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphMsgDynAddAnsiString failed: %!STATUS!\",\n                          status);\n        }\n\n        KphCommsSendNPagedMessageAsync(msg);\n    }\n\n    KphpDbgPrintSlotNext = 0;\n}\n\n/**\n * \\brief DPC routine for debug informer.\n *\n * \\param Dpc Unused\n * \\param DeferredContext Unused\n * \\param SystemArgument1 Unused\n * \\param SystemArgument2 Unused\n */\n_Function_class_(KDEFERRED_ROUTINE)\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_IRQL_requires_min_(DISPATCH_LEVEL)\n_IRQL_requires_(DISPATCH_LEVEL)\n_IRQL_requires_same_\nVOID KphpDebugPrintDpc(\n    _In_ PKDPC Dpc,\n    _In_opt_ PVOID DeferredContext,\n    _In_opt_ PVOID SystemArgument1,\n    _In_opt_ PVOID SystemArgument2\n    )\n{\n    KIRQL oldIrql;\n\n    UNREFERENCED_PARAMETER(Dpc);\n    UNREFERENCED_PARAMETER(DeferredContext);\n    UNREFERENCED_PARAMETER(SystemArgument1);\n    UNREFERENCED_PARAMETER(SystemArgument2);\n\n    //\n    // We use threaded DPCs so we could be invoked at passive or dispatch.\n    //\n\n    oldIrql = KeAcquireSpinLockForDpc(&KphpDbgPrintLock);\n    KphpDebugPrintFlush();\n    KeReleaseSpinLockForDpc(&KphpDbgPrintLock, oldIrql);\n}\n\n/**\n * \\brief Debug print callback.\n *\n * \\param[in] Output Debug print string output.\n * \\param[in] ComponentId Component ID printing to the debug output.\n * \\param[in] Level Debug print level.\n */\n_IRQL_always_function_min_(DISPATCH_LEVEL)\nVOID KphpDebugPrintCallback(\n    _In_ PSTRING Output,\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level\n    )\n{\n    PKPH_DBG_PRINT_SLOT slot;\n\n    KPH_NPAGED_CODE_DISPATCH_MIN();\n\n    slot = NULL;\n\n    if (!Output->Buffer || (Output->Length == 0))\n    {\n        return;\n    }\n\n    KeAcquireSpinLockAtDpcLevel(&KphpDbgPrintLock);\n\n    if (KphpDbgPrintSlotNext >= KphpDbgPrintSlotCount)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Out of debug print slots!\");\n        goto Exit;\n    }\n\n    slot = &KphpDbgPrintSlots[KphpDbgPrintSlotNext++];\n\n    KeQuerySystemTime(&slot->TimeStamp);\n    slot->ContextClientId.UniqueProcess = PsGetCurrentProcessId();\n    slot->ContextClientId.UniqueThread = PsGetCurrentThreadId();\n    slot->ComponentId = ComponentId;\n    slot->Level = Level;\n    slot->Length = min(Output->Length, ARRAYSIZE(slot->Buffer));\n    RtlCopyMemory(slot->Buffer, Output->Buffer, slot->Length);\n\n    if (Output->Length > ARRAYSIZE(slot->Buffer))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Truncated debug print line\");\n    }\n\nExit:\n\n    KeReleaseSpinLockFromDpcLevel(&KphpDbgPrintLock);\n\n    if (slot)\n    {\n        KeInsertQueueDpc(&slot->Dpc, NULL, NULL);\n    }\n}\n\n/**\n * \\brief Starts the debug informer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDebugInformerStart(\n    VOID\n    )\n{\n    NTSTATUS status;\n    ULONG count;\n\n    KPH_NPAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KphpDbgPrintSlotNext == 0);\n    NT_ASSERT(!KphpDbgPrintInitialized);\n\n    KeInitializeSpinLock(&KphpDbgPrintLock);\n    count = (KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS) * 2);\n\n    KphpDbgPrintSlots = KphAllocateNPaged((sizeof(KPH_DBG_PRINT_SLOT) * count),\n                                          KPH_TAG_DBG_SLOTS);\n    if (!KphpDbgPrintSlots)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate slots for debug print callback\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    RtlZeroMemory(KphpDbgPrintSlots, sizeof(KPH_DBG_PRINT_SLOT) * count);\n\n    KphpDbgPrintSlotCount = count;\n\n    for (ULONG i = 0; i < KphpDbgPrintSlotCount; i++)\n    {\n        KeInitializeThreadedDpc(&KphpDbgPrintSlots[i].Dpc,\n                                KphpDebugPrintDpc,\n                                NULL);\n    }\n\n    status = DbgSetDebugPrintCallback(KphpDebugPrintCallback, TRUE);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to register debug print callback: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = STATUS_SUCCESS;\n    KphpDbgPrintInitialized = TRUE;\n\nExit:\n\n    if (!NT_SUCCESS(status))\n    {\n        NT_ASSERT(!KphpDbgPrintInitialized);\n\n        KphpDbgPrintSlotCount = 0;\n\n        if (KphpDbgPrintSlots)\n        {\n            KphFree(KphpDbgPrintSlots, KPH_TAG_DBG_SLOTS);\n            KphpDbgPrintSlots = NULL;\n        }\n    }\n\n    return status;\n}\n\n/**\n * \\brief Stops the debug informer.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphDebugInformerStop(\n    VOID\n    )\n{\n    KIRQL oldIrql;\n\n    KPH_NPAGED_CODE_PASSIVE();\n\n    if (!KphpDbgPrintInitialized)\n    {\n        return;\n    }\n\n    DbgSetDebugPrintCallback(KphpDebugPrintCallback, FALSE);\n\n    for (ULONG i = 0; i < KphpDbgPrintSlotCount; i++)\n    {\n        KeRemoveQueueDpcEx(&KphpDbgPrintSlots[i].Dpc, TRUE);\n    }\n\n    KeAcquireSpinLock(&KphpDbgPrintLock, &oldIrql);\n\n    KphpDebugPrintFlush();\n\n    KphpDbgPrintSlotCount = 0;\n    KphFree(KphpDbgPrintSlots, KPH_TAG_DBG_SLOTS);\n    KphpDbgPrintSlots = NULL;\n\n    KeReleaseSpinLock(&KphpDbgPrintLock, oldIrql);\n\n    KphpDbgPrintInitialized = FALSE;\n}\n"
  },
  {
    "path": "KSystemInformer/informer_file.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <comms.h>\n#include <informer_filep.h>\n\n#include <trace.h>\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpDefaultInstaceName = RTL_CONSTANT_STRING(L\"DefaultInstance\");\nstatic const UNICODE_STRING KphpAltitudeName = RTL_CONSTANT_STRING(L\"Altitude\");\nstatic const UNICODE_STRING KphpFlagsName = RTL_CONSTANT_STRING(L\"Flags\");\nstatic const DWORD KphpFlagsValue = 0;\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nPFLT_FILTER KphFltFilter = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Invoked when the mini-filter driver is asked to unload.\n *\n * \\param[in] Flags Unused\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(PFLT_FILTER_UNLOAD_CALLBACK)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS FLTAPI KphpFltFilterUnloadCallback(\n    _In_ FLT_FILTER_UNLOAD_FLAGS Flags\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(Flags);\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE, INFORMER, \"Filter unload invoked\");\n\n    if (KphIsDriverUnloadProtected())\n    {\n        return STATUS_FLT_DO_NOT_DETACH;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Invoked when the mini-filter instance is asked to be removed.\n *\n * \\param[in] FltObjects Unused\n * \\param[in] Flags Unused\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS FLTAPI KphpFltInstanceQueryTeardownCallback(\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(FltObjects);\n    UNREFERENCED_PARAMETER(Flags);\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  INFORMER,\n                  \"Filter query teardown invoked\");\n\n    if (KphIsDriverUnloadProtected())\n    {\n        return STATUS_FLT_DO_NOT_DETACH;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const FLT_OPERATION_REGISTRATION KphpFltOperationRegistration[] =\n{\n{ IRP_MJ_CREATE,                              0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_CREATE_NAMED_PIPE,                   0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_CLOSE,                               0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_READ,                                0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_WRITE,                               0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_QUERY_INFORMATION,                   0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_SET_INFORMATION,                     0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_QUERY_EA,                            0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_SET_EA,                              0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_FLUSH_BUFFERS,                       0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_QUERY_VOLUME_INFORMATION,            0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_SET_VOLUME_INFORMATION,              0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_DIRECTORY_CONTROL,                   0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_FILE_SYSTEM_CONTROL,                 0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_DEVICE_CONTROL,                      0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_INTERNAL_DEVICE_CONTROL,             0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_SHUTDOWN,                            0, KphpFltPreOp, NULL,          0 },\n{ IRP_MJ_LOCK_CONTROL,                        0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_CLEANUP,                             0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_CREATE_MAILSLOT,                     0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_QUERY_SECURITY,                      0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_SET_SECURITY,                        0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_POWER,                               0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_SYSTEM_CONTROL,                      0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_DEVICE_CHANGE,                       0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_QUERY_QUOTA,                         0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_SET_QUOTA,                           0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_PNP,                                 0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION, 0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION, 0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_ACQUIRE_FOR_MOD_WRITE,               0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_RELEASE_FOR_MOD_WRITE,               0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_ACQUIRE_FOR_CC_FLUSH,                0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_RELEASE_FOR_CC_FLUSH,                0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_QUERY_OPEN,                          0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE,           0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_NETWORK_QUERY_OPEN,                  0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_MDL_READ,                            0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_MDL_READ_COMPLETE,                   0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_PREPARE_MDL_WRITE,                   0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_MDL_WRITE_COMPLETE,                  0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_VOLUME_MOUNT,                        0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_VOLUME_DISMOUNT,                     0, KphpFltPreOp, KphpFltPostOp, 0 },\n{ IRP_MJ_OPERATION_END }\n};\nstatic const FLT_CONTEXT_REGISTRATION KphpFltContextRegistration[] =\n{\n    {\n        FLT_STREAMHANDLE_CONTEXT,\n        0,\n        NULL,\n        FLT_VARIABLE_SIZED_CONTEXTS,\n        KPH_TAG_FLT_STREAMHANDLE_CONTEXT\n    },\n    { FLT_CONTEXT_END }\n};\nstatic const FLT_REGISTRATION KphpFltRegistration =\n{\n    sizeof(FLT_REGISTRATION),\n    FLT_REGISTRATION_VERSION,\n    (FLTFL_REGISTRATION_SUPPORT_NPFS_MSFS |\n     FLTFL_REGISTRATION_SUPPORT_DAX_VOLUME |\n     FLTFL_REGISTRATION_SUPPORT_WCOS),\n    KphpFltContextRegistration,\n    KphpFltOperationRegistration,\n    KphpFltFilterUnloadCallback,\n    NULL,\n    KphpFltInstanceQueryTeardownCallback,\n    NULL,\n    NULL,\n    NULL,\n    NULL,\n    NULL,\n    NULL\n};\nKPH_PROTECTED_DATA_SECTION_RO_POP();\n\n/**\n * \\brief Registers the driver with the mini-filter.\n *\n * \\param[in] DriverObject Driver object of this driver.\n * \\param[in] RegistryPath Registry path from the entry point.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphFltRegister(\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PUNICODE_STRING RegistryPath\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE instancesKeyHandle;\n    HANDLE defaultInstanceKeyHandle;\n    WCHAR instancesBuffer[MAX_PATH];\n    UNICODE_STRING keyName;\n    BYTE objectInfoBuffer[MAX_PATH];\n    POBJECT_NAME_INFORMATION objectInfo;\n    ULONG returnLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n    NT_ASSERT(!KphFltFilter);\n\n    instancesKeyHandle = NULL;\n    defaultInstanceKeyHandle = NULL;\n\n    objectInfo = (POBJECT_NAME_INFORMATION)objectInfoBuffer;\n\n    status = ObQueryNameString(DriverObject,\n                               objectInfo,\n                               sizeof(objectInfoBuffer),\n                               &returnLength);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ObQueryNameString failed: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    for (USHORT i = (objectInfo->Name.Length / sizeof(WCHAR)); i > 0; i--)\n    {\n        if (i == 1)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Driver object name is invalid\");\n\n            status = STATUS_OBJECT_NAME_INVALID;\n            goto Exit;\n        }\n\n        if (objectInfo->Name.Buffer[i - 1] == OBJ_NAME_PATH_SEPARATOR)\n        {\n            objectInfo->Name.Length -= (i * sizeof(WCHAR));\n            RtlMoveMemory(objectInfo->Name.Buffer,\n                          &objectInfo->Name.Buffer[i],\n                          objectInfo->Name.Length);\n            break;\n        }\n    }\n\n    //\n    // We null terminate this for the registry later.\n    //\n    NT_ASSERT(objectInfo->Name.MaximumLength >= (objectInfo->Name.Length + sizeof(WCHAR)));\n    objectInfo->Name.Buffer[objectInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;\n\n    keyName.Buffer = instancesBuffer;\n    keyName.Length = 0;\n    keyName.MaximumLength = sizeof(instancesBuffer);\n\n    status = RtlAppendUnicodeStringToString(&keyName, RegistryPath);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"RtlAppendUnicodeStringToString failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = RtlAppendUnicodeToString(&keyName, L\"\\\\Instances\");\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"RtlAppendUnicodeToString failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    InitializeObjectAttributes(&objectAttributes,\n                               &keyName,\n                               OBJ_KERNEL_HANDLE,\n                               NULL,\n                               NULL);\n\n    status = ZwCreateKey(&instancesKeyHandle,\n                         KEY_ALL_ACCESS,\n                         &objectAttributes,\n                         0,\n                         NULL,\n                         0,\n                         NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ZwCreateKey failed: %!STATUS!\",\n                      status);\n\n        instancesKeyHandle = NULL;\n        goto Exit;\n    }\n\n    //\n    // We guarantee this above.\n    //\n    NT_ASSERT(objectInfo->Name.MaximumLength >= (objectInfo->Name.Length + sizeof(WCHAR)));\n    NT_ASSERT(objectInfo->Name.Buffer[objectInfo->Name.Length / sizeof(WCHAR)] == UNICODE_NULL);\n    status = ZwSetValueKey(instancesKeyHandle,\n                           (PUNICODE_STRING)&KphpDefaultInstaceName,\n                           0,\n                           REG_SZ,\n                           objectInfo->Name.Buffer,\n                           objectInfo->Name.Length + sizeof(WCHAR));\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ZwSetValueKey failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = RtlAppendUnicodeToString(&keyName, L\"\\\\\");\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"RtlAppendUnicodeToString failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = RtlAppendUnicodeStringToString(&keyName, &objectInfo->Name);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"RtlAppendUnicodeStringToString failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    InitializeObjectAttributes(&objectAttributes,\n                               &keyName,\n                               OBJ_KERNEL_HANDLE,\n                               NULL,\n                               NULL);\n\n    status = ZwCreateKey(&defaultInstanceKeyHandle,\n                         KEY_ALL_ACCESS,\n                         &objectAttributes,\n                         0,\n                         NULL,\n                         0,\n                         NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ZwCreateKey failed: %!STATUS!\",\n                      status);\n\n        defaultInstanceKeyHandle = NULL;\n        goto Exit;\n    }\n\n    NT_ASSERT(KphAltitude);\n    NT_ASSERT(KphAltitude->MaximumLength >= (KphAltitude->Length + sizeof(WCHAR)));\n    NT_ASSERT(KphAltitude->Buffer[KphAltitude->Length / sizeof(WCHAR)] == UNICODE_NULL);\n    status = ZwSetValueKey(defaultInstanceKeyHandle,\n                           (PUNICODE_STRING)&KphpAltitudeName,\n                           0,\n                           REG_SZ,\n                           KphAltitude->Buffer,\n                           KphAltitude->Length + sizeof(WCHAR));\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ZwSetValueKey failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = ZwSetValueKey(defaultInstanceKeyHandle,\n                           (PUNICODE_STRING)&KphpFlagsName,\n                           0,\n                           REG_DWORD,\n                           (PVOID)&KphpFlagsValue,\n                           sizeof(KphpFlagsValue));\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ZwSetValueKey failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = FltRegisterFilter(DriverObject,\n                               &KphpFltRegistration,\n                               &KphFltFilter);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"FltRegisterFilter failed: %!STATUS!\",\n                      status);\n\n        KphFltFilter = NULL;\n        goto Exit;\n    }\n\n    status = KphCommsStart();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphCommsStart failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (instancesKeyHandle)\n    {\n        ObCloseHandle(instancesKeyHandle, KernelMode);\n    }\n\n    if (defaultInstanceKeyHandle)\n    {\n        ObCloseHandle(defaultInstanceKeyHandle, KernelMode);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Unregisters this driver with the mini-filter.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphFltUnregister(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphCommsStop();\n\n    if (!KphFltFilter)\n    {\n        return;\n    }\n\n    FltUnregisterFilter(KphFltFilter);\n\n    KphpFltCleanupFileNameCache();\n    KphpFltCleanupFileOp();\n}\n\n/**\n * \\brief Begins informing on file activity from the mini-filter.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphFltInformerStart(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KphFltFilter);\n\n    KphpFltInitializeFileOp();\n    KphpFltInitializeFileNameCache();\n\n    return FltStartFiltering(KphFltFilter);\n}\n"
  },
  {
    "path": "KSystemInformer/informer_filenc.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n\n#include <kph.h>\n#include <informer_filep.h>\n\n#include <trace.h>\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic UNICODE_STRING KphpCachedFileNameTypeName = RTL_CONSTANT_STRING(L\"KphCachedFileName\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_OBJECT_TYPE KphpCachedFileNameType = NULL;\nstatic BOOLEAN KphpFileNameCacheInitialized = FALSE;\nKPH_PROTECTED_DATA_SECTION_POP();\n\n//\n// We use a simple list and spin lock here since we are very selective about\n// what we cache. The list is not expected to grow very large.\n//\nstatic ALIGNED_EX_SPINLOCK KphpFileNameCacheLock = 0;\nstatic LIST_ENTRY KphpFileNameCacheList;\n\n/**\n * \\brief Retrieves file name information using the filter name cache.\n *\n * \\param[in] Data The callback data for the operation.\n * \\param[out] FltFileName Receives the file name.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetFileNameInformation(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _Out_ PKPH_FLT_FILE_NAME FltFileName\n    )\n{\n    NTSTATUS status;\n    ULONG flags;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(Data->Iopb->TargetFileObject);\n\n    flags = (FLT_FILE_NAME_NORMALIZED |\n             FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP);\n\n    status = FltGetFileNameInformation(Data, flags, &FltFileName->NameInfo);\n    if (NT_SUCCESS(status))\n    {\n        FltFileName->Type = KphFltFileNameTypeNameInfo;\n        return status;\n    }\n\n    flags = (FLT_FILE_NAME_OPENED |\n             FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP);\n\n    status = FltGetFileNameInformation(Data, flags, &FltFileName->NameInfo);\n    if (NT_SUCCESS(status))\n    {\n        FltFileName->Type = KphFltFileNameTypeNameInfo;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Retrieves the length of the file name from the related objects.\n *\n * \\param[in] FltObjects The related objects for the operation.\n *\n * \\return The length of the file name.\n */\n_IRQL_requires_max_(APC_LEVEL)\nULONG KphpFltNameCacheFileNameLength(\n    _In_ PCFLT_RELATED_OBJECTS FltObjects\n    )\n{\n    ULONG length;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(FltObjects->FileObject && FltObjects->Volume);\n\n    NT_VERIFY(FltGetVolumeName(FltObjects->Volume, NULL, &length)\n              == STATUS_BUFFER_TOO_SMALL);\n\n    length += FltObjects->FileObject->FileName.Length;\n\n    return length;\n}\n\n/**\n * \\brief Copies the file name into the related objects.\n *\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[in,out] FileName The file name to copy into.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFltNameCacheCopyFileName(\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Inout_ PUNICODE_STRING FileName\n    )\n{\n    PUNICODE_STRING fileName;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(FltObjects->FileObject && FltObjects->Volume);\n\n    NT_VERIFY(NT_SUCCESS(FltGetVolumeName(FltObjects->Volume, FileName, NULL)));\n\n    fileName = &FltObjects->FileObject->FileName;\n\n    NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeStringToString(FileName, fileName)));\n}\n\n/**\n * \\brief Retrieves the file name, using the stream handle context as a cache.\n *\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[out] FltFileName Receives the file name.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetFileNameUseContext(\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Out_ PKPH_FLT_FILE_NAME FltFileName\n    )\n{\n    NTSTATUS status;\n    ULONG length;\n    PFLT_CONTEXT oldContext;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(FltObjects->FileObject);\n\n    //\n    // Check if the context already exists.\n    //\n\n    status = FltGetStreamHandleContext(FltObjects->Instance,\n                                       FltObjects->FileObject,\n                                       &FltFileName->Context);\n    if (NT_SUCCESS(status))\n    {\n        FltFileName->Type = KphFltFileNameTypeContext;\n        return status;\n    }\n\n    //\n    // Try to create a new context.\n    //\n\n    length = KphpFltNameCacheFileNameLength(FltObjects);\n\n    status = FltAllocateContext(FltObjects->Filter,\n                                FLT_STREAMHANDLE_CONTEXT,\n                                length + sizeof(UNICODE_STRING),\n                                NonPagedPoolNx,\n                                &FltFileName->Context);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"FltAllocateContext failed: %!STATUS!\",\n                      status);\n\n        FltFileName->Context = NULL;\n        return status;\n    }\n\n    NT_ASSERT(FltFileName->Context == FltFileName->FileName);\n\n    FltFileName->FileName->Length = 0;\n    FltFileName->FileName->MaximumLength = (USHORT)length;\n    FltFileName->FileName->Buffer = Add2Ptr(FltFileName->FileName,\n                                            sizeof(UNICODE_STRING));\n\n    KphpFltNameCacheCopyFileName(FltObjects, FltFileName->FileName);\n\n    //\n    // Set the new context.\n    //\n\n    status = FltSetStreamHandleContext(FltObjects->Instance,\n                                       FltObjects->FileObject,\n                                       FLT_SET_CONTEXT_KEEP_IF_EXISTS,\n                                       FltFileName->Context,\n                                       &oldContext);\n    if (NT_SUCCESS(status))\n    {\n        FltFileName->Type = KphFltFileNameTypeContext;\n        return status;\n    }\n\n    //\n    // We raced and lost, or failed for some other reason.\n    //\n\n    FltReleaseContext(FltFileName->Context);\n    FltFileName->Context = NULL;\n\n    if (status == STATUS_FLT_CONTEXT_ALREADY_DEFINED)\n    {\n        //\n        // Return the existing context.\n        //\n        FltFileName->Type = KphFltFileNameTypeContext;\n        FltFileName->Context = oldContext;\n        return STATUS_SUCCESS;\n    }\n\n    //\n    // This is unexpected, we could do more juggling, but instead choose to\n    // just give up.\n    //\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  INFORMER,\n                  \"FltSetStreamHandleContext failed: %!STATUS!\",\n                  status);\n\n    return status;\n}\n\n/**\n * \\brief Retrieves the file name, using the global name cache.\n *\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[out] FltFileName Receives the file name.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetFileNameUseNameCache(\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Out_ PKPH_FLT_FILE_NAME FltFileName\n    )\n{\n    NTSTATUS status;\n    KIRQL previousIrql;\n    ULONG length;\n    PKPH_FLT_FILE_NAME_CACHE_ENTRY cacheEntry;\n    PKPH_FLT_FILE_NAME_CACHE_ENTRY existingCacheEntry;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(FltObjects->FileObject);\n\n    //\n    // Check if the file object is already in the cache.\n    //\n\n    cacheEntry = NULL;\n    previousIrql = ExAcquireSpinLockShared(&KphpFileNameCacheLock);\n\n    for (PLIST_ENTRY entry = KphpFileNameCacheList.Flink;\n         entry != &KphpFileNameCacheList;\n         entry = entry->Flink)\n    {\n        cacheEntry = CONTAINING_RECORD(entry,\n                                        KPH_FLT_FILE_NAME_CACHE_ENTRY,\n                                        ListEntry);\n\n        if (FltObjects->FileObject == cacheEntry->FileObject)\n        {\n            KphReferenceObject(cacheEntry);\n            break;\n        }\n\n        cacheEntry = NULL;\n    }\n\n    ExReleaseSpinLockShared(&KphpFileNameCacheLock, previousIrql);\n\n    if (cacheEntry)\n    {\n        //\n        // Return a reference (taken above) to the existing cached entry.\n        //\n        FltFileName->NameCache = cacheEntry;\n        FltFileName->Type = KphFltFileNameTypeNameCache;\n        return STATUS_SUCCESS;\n    }\n\n    //\n    // Try to create new entry and insert it into the cache.\n    //\n\n    length = KphpFltNameCacheFileNameLength(FltObjects);\n\n    status = KphCreateObject(KphpCachedFileNameType,\n                             length + sizeof(KPH_FLT_FILE_NAME_CACHE_ENTRY),\n                             &cacheEntry,\n                             NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    cacheEntry->FileObject = FltObjects->FileObject;\n\n    cacheEntry->FileName.Length = 0;\n    cacheEntry->FileName.MaximumLength = (USHORT)length;\n    cacheEntry->FileName.Buffer = Add2Ptr(cacheEntry,\n                                          sizeof(KPH_FLT_FILE_NAME_CACHE_ENTRY));\n\n    KphpFltNameCacheCopyFileName(FltObjects, &cacheEntry->FileName);\n\n    //\n    // Insert it into the cache, and check if we've raced.\n    //\n\n    existingCacheEntry = NULL;\n    previousIrql = ExAcquireSpinLockExclusive(&KphpFileNameCacheLock);\n\n    for (PLIST_ENTRY entry = KphpFileNameCacheList.Flink;\n         entry != &KphpFileNameCacheList;\n         entry = entry->Flink)\n    {\n        existingCacheEntry = CONTAINING_RECORD(entry,\n                                               KPH_FLT_FILE_NAME_CACHE_ENTRY,\n                                               ListEntry);\n\n        if (cacheEntry->FileObject == existingCacheEntry->FileObject)\n        {\n            KphReferenceObject(existingCacheEntry);\n            break;\n        }\n\n        existingCacheEntry = NULL;\n    }\n\n    if (!existingCacheEntry)\n    {\n        //\n        // Insert the new entry (with a reference) in the list.\n        //\n        KphReferenceObject(cacheEntry);\n        InsertHeadList(&KphpFileNameCacheList, &cacheEntry->ListEntry);\n    }\n\n    ExReleaseSpinLockExclusive(&KphpFileNameCacheLock, previousIrql);\n\n    if (existingCacheEntry)\n    {\n        //\n        // Return the existing cached entry reference (taken above) to the\n        // caller, and drop the one we just created.\n        //\n        FltFileName->NameCache = existingCacheEntry;\n        KphDereferenceObject(cacheEntry);\n    }\n    else\n    {\n        //\n        // New entry inserted into the cache\n        //\n        FltFileName->NameCache = cacheEntry;\n    }\n\n    FltFileName->Type = KphFltFileNameTypeNameCache;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Retrieves the file name, by copying it from the related objects.\n *\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[out] FltFileName Receives the file name.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetFileNameCopy(\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Out_ PKPH_FLT_FILE_NAME FltFileName\n    )\n{\n    ULONG length;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(FltObjects->Volume);\n    NT_ASSERT(FltObjects->FileObject);\n\n    length = KphpFltNameCacheFileNameLength(FltObjects);\n\n    FltFileName->FileName = KphAllocateNPaged(length + sizeof(UNICODE_STRING),\n                                              KPH_TAG_FLT_FILE_NAME);\n    if (!FltFileName->FileName)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate file name.\");\n\n        return STATUS_INSUFFICIENT_RESOURCES;\n    }\n\n    FltFileName->FileName->Length = 0;\n    FltFileName->FileName->MaximumLength = (USHORT)length;\n    FltFileName->FileName->Buffer = Add2Ptr(FltFileName->FileName,\n                                            sizeof(UNICODE_STRING));\n\n    KphpFltNameCacheCopyFileName(FltObjects, FltFileName->FileName);\n\n    FltFileName->Type = KphFltFileNameTypeFileName;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Retrieves the volume name, by copying it from the related objects.\n *\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[out] FltFileName Receives the file name.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetVolumeName(\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Out_ PKPH_FLT_FILE_NAME FltFileName\n    )\n{\n    ULONG length;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    if (!FltObjects->Volume)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE, INFORMER, \"Volume is null\");\n\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n    }\n\n    (VOID)FltGetVolumeName(FltObjects->Volume, NULL, &length);\n\n    FltFileName->FileName = KphAllocateNPaged(length + sizeof(UNICODE_STRING),\n                                              KPH_TAG_FLT_FILE_NAME);\n    if (!FltFileName->FileName)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate file name.\");\n\n        return STATUS_INSUFFICIENT_RESOURCES;\n    }\n\n    FltFileName->FileName->Length = 0;\n    FltFileName->FileName->MaximumLength = (USHORT)length;\n    FltFileName->FileName->Buffer = Add2Ptr(FltFileName->FileName,\n                                            sizeof(UNICODE_STRING));\n\n    (VOID)FltGetVolumeName(FltObjects->Volume, FltFileName->FileName, NULL);\n\n    FltFileName->Type = KphFltFileNameTypeFileName;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Retrieves the file name for the given callback data.\n *\n * \\param[in] Data The callback data for the operation.\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[out] FltFileName Receives the file name, must be related using\n * KphpFltReleaseFileName.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetFileName(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Out_ PKPH_FLT_FILE_NAME FltFileName\n    )\n{\n    NTSTATUS status;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(FltObjects->FileObject == Data->Iopb->TargetFileObject);\n\n    KphpFltZeroFileName(FltFileName);\n\n    if (!FltObjects->FileObject)\n    {\n        if ((Data->Iopb->MajorFunction == IRP_MJ_VOLUME_MOUNT) ||\n            (Data->Iopb->MajorFunction == IRP_MJ_VOLUME_DISMOUNT))\n        {\n            return KphpFltGetVolumeName(FltObjects, FltFileName);\n        }\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE, INFORMER, \"FileObject is null\");\n\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n    }\n\n    status = KphpFltGetFileNameInformation(Data, FltFileName);\n    if (NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    if (!FltObjects->Volume)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE, INFORMER, \"Volume is null\");\n\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n    }\n\n    if (FltSupportsStreamHandleContexts(FltObjects->FileObject))\n    {\n        status = KphpFltGetFileNameUseContext(FltObjects, FltFileName);\n    }\n    else if (FsRtlIsPagingFile(FltObjects->FileObject))\n    {\n        status = KphpFltGetFileNameUseNameCache(FltObjects, FltFileName);\n    }\n    else\n    {\n        status = KphpFltGetFileNameCopy(FltObjects, FltFileName);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Retrieves destination file name information using the filter name\n * cache.\n *\n * \\param[in] Data The callback data for the operation.\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[out] FltFileName Receives the destination file name.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetDestinationFileNameInformation(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Out_ PKPH_FLT_FILE_NAME FltDestFileName\n    )\n{\n    NTSTATUS status;\n    HANDLE rootDirectory;\n    PWSTR fileName;\n    ULONG fileNameLength;\n    ULONG flags;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(FltObjects->FileObject);\n\n    if (Data->Iopb->MajorFunction != IRP_MJ_SET_INFORMATION)\n    {\n        NT_ASSERT(Data->Iopb->MinorFunction == IRP_MJ_SET_INFORMATION);\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    switch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass)\n    {\n        case FileRenameInformation:\n        case FileRenameInformationBypassAccessCheck:\n        case FileRenameInformationEx:\n        case FileRenameInformationExBypassAccessCheck:\n        {\n            PFILE_RENAME_INFORMATION renameInfo;\n\n            renameInfo = Data->Iopb->Parameters.SetFileInformation.InfoBuffer;\n\n            rootDirectory = renameInfo->RootDirectory;\n            fileName = renameInfo->FileName;\n            fileNameLength = renameInfo->FileNameLength;\n\n            break;\n        }\n        case FileLinkInformation:\n        case FileLinkInformationBypassAccessCheck:\n        case FileLinkInformationEx:\n        case FileLinkInformationExBypassAccessCheck:\n        {\n            PFILE_LINK_INFORMATION linkInfo;\n\n            linkInfo = Data->Iopb->Parameters.SetFileInformation.InfoBuffer;\n\n            rootDirectory = linkInfo->RootDirectory;\n            fileName = linkInfo->FileName;\n            fileNameLength = linkInfo->FileNameLength;\n\n            break;\n        }\n        default:\n        {\n            NT_ASSERT(FALSE);\n            return STATUS_INVALID_PARAMETER;\n        }\n    }\n\n    flags = (FLT_FILE_NAME_NORMALIZED |\n             FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP);\n\n    status = FltGetDestinationFileNameInformation(FltObjects->Instance,\n                                                  FltObjects->FileObject,\n                                                  rootDirectory,\n                                                  fileName,\n                                                  fileNameLength,\n                                                  flags,\n                                                  &FltDestFileName->NameInfo);\n    if (NT_SUCCESS(status))\n    {\n        FltDestFileName->Type = KphFltFileNameTypeNameInfo;\n        return status;\n    }\n\n    flags = (FLT_FILE_NAME_OPENED |\n             FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP);\n    status = FltGetDestinationFileNameInformation(FltObjects->Instance,\n                                                  FltObjects->FileObject,\n                                                  rootDirectory,\n                                                  fileName,\n                                                  fileNameLength,\n                                                  flags,\n                                                  &FltDestFileName->NameInfo);\n    if (NT_SUCCESS(status))\n    {\n        FltDestFileName->Type = KphFltFileNameTypeNameInfo;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Retrieves the destination file name for the given callback data.\n *\n * \\param[in] Data The callback data for the operation.\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[out] FltFileName Receives the destination file name, must be related\n * using KphpFltReleaseFileName.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltGetDestFileName(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Out_ PKPH_FLT_FILE_NAME FltDestFileName\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(FltObjects->FileObject == Data->Iopb->TargetFileObject);\n\n    KphpFltZeroFileName(FltDestFileName);\n\n    if (!FltObjects->FileObject)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE, INFORMER, \"FileObject is null\");\n\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n    }\n\n    return KphpFltGetDestinationFileNameInformation(Data,\n                                                    FltObjects,\n                                                    FltDestFileName);\n}\n\n/**\n * \\brief Releases the file name.\n *\n * \\param[in] FltFileName The file name to release.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFltReleaseFileName(\n    _In_ PKPH_FLT_FILE_NAME FltFileName\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    switch (FltFileName->Type)\n    {\n        case KphFltFileNameTypeNameInfo:\n        {\n            NT_ASSERT(FltFileName->NameInfo);\n            FltReleaseFileNameInformation(FltFileName->NameInfo);\n            break;\n        }\n        case KphFltFileNameTypeContext:\n        {\n            NT_ASSERT(FltFileName->Context);\n            FltReleaseContext(FltFileName->Context);\n            break;\n        }\n        case KphFltFileNameTypeFileName:\n        {\n            NT_ASSERT(FltFileName->FileName);\n            KphFree(FltFileName->FileName, KPH_TAG_FLT_FILE_NAME);\n            break;\n        }\n        case KphFltFileNameTypeNameCache:\n        {\n            NT_ASSERT(FltFileName->NameCache);\n            KphDereferenceObject(FltFileName->NameCache);\n            break;\n        }\n        case KphFltFileNameTypeNone:\n        default:\n        {\n            //\n            // This is a union, assert is only needed once.\n            //\n            NT_ASSERT(!FltFileName->NameInfo);\n            break;\n        }\n    }\n}\n\n/**\n * \\brief Reaps the file name cache entry for the given callback data.\n *\n * \\details A global name cache is used in limited cases to cache the file name\n * for a given file object. In order to cleanly reap information from the cache\n * this must be called in the post operation callback for IRP_MJ_CLOSE.\n *\n * \\param[in] Data The callback data for the operation.\n * \\param[in] FltObjects The related objects for the operation.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphpFltReapFileNameCache(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects\n    )\n{\n    KIRQL previosIrql;\n    PKPH_FLT_FILE_NAME_CACHE_ENTRY cacheEntry;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    NT_ASSERT(FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION));\n    NT_ASSERT(Data->Iopb->MajorFunction == IRP_MJ_CLOSE);\n    DBG_UNREFERENCED_PARAMETER(Data);\n\n    cacheEntry = NULL;\n    previosIrql = ExAcquireSpinLockExclusive(&KphpFileNameCacheLock);\n\n    for (PLIST_ENTRY entry = KphpFileNameCacheList.Flink;\n         entry != &KphpFileNameCacheList;\n         entry = entry->Flink)\n    {\n        cacheEntry = CONTAINING_RECORD(entry,\n                                       KPH_FLT_FILE_NAME_CACHE_ENTRY,\n                                       ListEntry);\n\n        if (cacheEntry->FileObject == FltObjects->FileObject)\n        {\n            RemoveEntryList(&cacheEntry->ListEntry);\n            break;\n        }\n\n        cacheEntry = NULL;\n    }\n\n    ExReleaseSpinLockExclusive(&KphpFileNameCacheLock, previosIrql);\n\n    if (cacheEntry)\n    {\n        KphDereferenceObject(cacheEntry);\n    }\n}\n\n/**\n * \\brief Allocates a cached file name object.\n *\n * \\param[in] Size The size of the object to allocate.\n *\n * \\return The allocated object, or NULL on failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpFltAllocateCachedFileName(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    return KphAllocateNPaged(Size, KPH_TAG_FLT_CACHED_FILE_NAME);\n}\n\n/**\n * \\brief Frees a cached file name object.\n *\n * \\param[in] Object The object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\nVOID KSIAPI KphpFltFreeCachedFileName(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    KphFree(Object, KPH_TAG_FLT_CACHED_FILE_NAME);\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Cleans up the file name cache.\n *\n * \\details A global name cache is used in limited cases to cache the file name\n * for a given file object. This must be called after the filter stops\n * filtering.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpFltCleanupFileNameCache(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!KphpFileNameCacheInitialized)\n    {\n        return;\n    }\n\n    while (!IsListEmpty(&KphpFileNameCacheList))\n    {\n        PKPH_FLT_FILE_NAME_CACHE_ENTRY cacheEntry;\n\n        cacheEntry = CONTAINING_RECORD(RemoveHeadList(&KphpFileNameCacheList),\n                                       KPH_FLT_FILE_NAME_CACHE_ENTRY,\n                                       ListEntry);\n\n        KphDereferenceObject(cacheEntry);\n    }\n}\n\n/**\n * \\brief Initializes the file name cache.\n *\n * \\details A global name cache is used in limited cases to cache the file name\n * for a given file object. This must be called before the filter is begins\n * filtering.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpFltInitializeFileNameCache(\n    VOID\n    )\n{\n    KPH_OBJECT_TYPE_INFO typeInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    InitializeListHead(&KphpFileNameCacheList);\n\n    typeInfo.Allocate = KphpFltAllocateCachedFileName;\n    typeInfo.Initialize = NULL;\n    typeInfo.Delete = NULL;\n    typeInfo.Free = KphpFltFreeCachedFileName;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpCachedFileNameTypeName,\n                        &typeInfo,\n                        &KphpCachedFileNameType);\n\n    KphpFileNameCacheInitialized = TRUE;\n}\n"
  },
  {
    "path": "KSystemInformer/informer_fileop.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n\n#include <kph.h>\n#include <informer.h>\n#include <comms.h>\n#include <kphmsgdyn.h>\n#include <informer_filep.h>\n\n#include <trace.h>\n\ntypedef union _KPH_FLT_OPTIONS\n{\n    USHORT Flags;\n    struct\n    {\n        USHORT PreEnabled : 1;\n        USHORT PostEnabled : 1;\n        USHORT EnableStackTraces : 1;\n        USHORT EnablePostFileNames : 1;\n        USHORT EnablePagingIo : 1;\n        USHORT EnableSyncPagingIo : 1;\n        USHORT EnableIoControlBuffers : 1;\n        USHORT EnableFsControlBuffers : 1;\n        USHORT EnableDirControlBuffers : 1;\n        USHORT EnablePreCreateReply : 1;\n        USHORT EnablePostCreateReply : 1;\n        USHORT Spare : 5;\n    };\n} KPH_FLT_OPTIONS, *PKPH_FLT_OPTIONS;\n\ntypedef struct _KPH_FLT_COMPLETION_CONTEXT\n{\n    PKPH_MESSAGE Message;\n    KPH_FLT_OPTIONS Options;\n    PFLT_FILE_NAME_INFORMATION FileNameInfo;\n    PFLT_FILE_NAME_INFORMATION DestFileNameInfo;\n} KPH_FLT_COMPLETION_CONTEXT, *PKPH_FLT_COMPLETION_CONTEXT;\n\nstatic ULONG64 KphpFltSequence = 0;\nstatic BOOLEAN KphpFltOpInitialized = FALSE;\nstatic NPAGED_LOOKASIDE_LIST KphpFltCompletionContextLookaside = { 0 };\n\n/**\n * \\brief Gets the options for the filter.\n *\n * \\param[in] Data The callback data for the operation.\n *\n * \\return Options for the filter.\n */\n_IRQL_requires_max_(APC_LEVEL)\nKPH_FLT_OPTIONS KphpFltGetOptions(\n    _In_ PFLT_CALLBACK_DATA Data\n    )\n{\n    KPH_FLT_OPTIONS options;\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    options.Flags = 0;\n\n    if (Data->Thread)\n    {\n        process = KphGetEProcessContext(PsGetThreadProcess(Data->Thread));\n    }\n    else\n    {\n        process = KphGetSystemProcessContext();\n    }\n\n#define KPH_FLT_SETTING(majorFunction, name)                                   \\\n    case majorFunction:                                                        \\\n    {                                                                          \\\n        if (KphInformerEnabled(FilePre##name, process))                        \\\n        {                                                                      \\\n            options.PreEnabled = TRUE;                                         \\\n        }                                                                      \\\n        if (KphInformerEnabled(FilePost##name, process))                       \\\n        {                                                                      \\\n            options.PostEnabled = TRUE;                                        \\\n        }                                                                      \\\n        break;                                                                 \\\n    }\n\n    switch (Data->Iopb->MajorFunction)\n    {\n        KPH_FLT_SETTING(IRP_MJ_CREATE, Create)\n        KPH_FLT_SETTING(IRP_MJ_CREATE_NAMED_PIPE, CreateNamedPipe)\n        KPH_FLT_SETTING(IRP_MJ_CLOSE, Close)\n        KPH_FLT_SETTING(IRP_MJ_READ, Read)\n        KPH_FLT_SETTING(IRP_MJ_WRITE, Write)\n        KPH_FLT_SETTING(IRP_MJ_QUERY_INFORMATION, QueryInformation)\n        KPH_FLT_SETTING(IRP_MJ_SET_INFORMATION, SetInformation)\n        KPH_FLT_SETTING(IRP_MJ_QUERY_EA, QueryEa)\n        KPH_FLT_SETTING(IRP_MJ_SET_EA, SetEa)\n        KPH_FLT_SETTING(IRP_MJ_FLUSH_BUFFERS, FlushBuffers)\n        KPH_FLT_SETTING(IRP_MJ_QUERY_VOLUME_INFORMATION, QueryVolumeInformation)\n        KPH_FLT_SETTING(IRP_MJ_SET_VOLUME_INFORMATION, SetVolumeInformation)\n        KPH_FLT_SETTING(IRP_MJ_DIRECTORY_CONTROL, DirectoryControl)\n        KPH_FLT_SETTING(IRP_MJ_FILE_SYSTEM_CONTROL, FileSystemControl)\n        KPH_FLT_SETTING(IRP_MJ_DEVICE_CONTROL, DeviceControl)\n        KPH_FLT_SETTING(IRP_MJ_INTERNAL_DEVICE_CONTROL, InternalDeviceControl)\n        KPH_FLT_SETTING(IRP_MJ_SHUTDOWN, Shutdown)\n        KPH_FLT_SETTING(IRP_MJ_LOCK_CONTROL, LockControl)\n        KPH_FLT_SETTING(IRP_MJ_CLEANUP, Cleanup)\n        KPH_FLT_SETTING(IRP_MJ_CREATE_MAILSLOT, CreateMailslot)\n        KPH_FLT_SETTING(IRP_MJ_QUERY_SECURITY, QuerySecurity)\n        KPH_FLT_SETTING(IRP_MJ_SET_SECURITY, SetSecurity)\n        KPH_FLT_SETTING(IRP_MJ_POWER, Power)\n        KPH_FLT_SETTING(IRP_MJ_SYSTEM_CONTROL, SystemControl)\n        KPH_FLT_SETTING(IRP_MJ_DEVICE_CHANGE, DeviceChange)\n        KPH_FLT_SETTING(IRP_MJ_QUERY_QUOTA, QueryQuota)\n        KPH_FLT_SETTING(IRP_MJ_SET_QUOTA, SetQuota)\n        KPH_FLT_SETTING(IRP_MJ_PNP, Pnp)\n        KPH_FLT_SETTING(IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION, AcquireForSectionSync)\n        KPH_FLT_SETTING(IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION, ReleaseForSectionSync)\n        KPH_FLT_SETTING(IRP_MJ_ACQUIRE_FOR_MOD_WRITE, AcquireForModWrite)\n        KPH_FLT_SETTING(IRP_MJ_RELEASE_FOR_MOD_WRITE, ReleaseForModWrite)\n        KPH_FLT_SETTING(IRP_MJ_ACQUIRE_FOR_CC_FLUSH, AcquireForCcFlush)\n        KPH_FLT_SETTING(IRP_MJ_RELEASE_FOR_CC_FLUSH, ReleaseForCcFlush)\n        KPH_FLT_SETTING(IRP_MJ_QUERY_OPEN, QueryOpen)\n        KPH_FLT_SETTING(IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE, FastIoCheckIfPossible)\n        KPH_FLT_SETTING(IRP_MJ_NETWORK_QUERY_OPEN, NetworkQueryOpen)\n        KPH_FLT_SETTING(IRP_MJ_MDL_READ, MdlRead)\n        KPH_FLT_SETTING(IRP_MJ_MDL_READ_COMPLETE, MdlReadComplete)\n        KPH_FLT_SETTING(IRP_MJ_PREPARE_MDL_WRITE, PrepareMdlWrite)\n        KPH_FLT_SETTING(IRP_MJ_MDL_WRITE_COMPLETE, MdlWriteComplete)\n        KPH_FLT_SETTING(IRP_MJ_VOLUME_MOUNT, VolumeMount)\n        KPH_FLT_SETTING(IRP_MJ_VOLUME_DISMOUNT, VolumeDismount)\n        DEFAULT_UNREACHABLE;\n    }\n\n    if (options.PreEnabled || options.PostEnabled)\n    {\n        KPH_INFORMER_OPTIONS opts;\n\n        opts = KphInformerOpts(process);\n\n        options.EnableStackTraces = !!opts.EnableStackTraces;\n        options.EnablePostFileNames = !!opts.FileEnablePostFileNames;\n        options.EnablePagingIo = !!opts.FileEnablePagingIo;\n        options.EnableSyncPagingIo = !!opts.FileEnableSyncPagingIo;\n        options.EnableIoControlBuffers = !!opts.FileEnableIoControlBuffers;\n        options.EnableFsControlBuffers = !!opts.FileEnableFsControlBuffers;\n        options.EnableDirControlBuffers = !!opts.FileEnableDirControlBuffers;\n        options.EnablePreCreateReply = !!opts.FileEnablePreCreateReply;\n        options.EnablePostCreateReply = !!opts.FileEnablePostCreateReply;\n    }\n\n    if (process)\n    {\n        KphDereferenceObject(process);\n    }\n\n    return options;\n}\n\n/**\n * \\brief Retrieves the message ID for a given operation.\n *\n * \\param[in] MajorFunction The major function of the operation.\n * \\param[in] PostOperation Denotes if this is a pre or post operation message.\n *\n * \\return The message ID for the operation.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nKPH_MESSAGE_ID KphpFltGetMessageId(\n    _In_ UCHAR MajorFunction,\n    _In_ BOOLEAN PostOperation\n    )\n{\n    KPH_MESSAGE_ID messageId;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n#define KPH_FLT_MESSAGE_ID(majorFunction, name)                               \\\n    case majorFunction:                                                       \\\n    {                                                                         \\\n        if (PostOperation)                                                    \\\n        {                                                                     \\\n            messageId = KphMsgFilePost##name;                                 \\\n        }                                                                     \\\n        else                                                                  \\\n        {                                                                     \\\n            messageId = KphMsgFilePre##name;                                  \\\n        }                                                                     \\\n        break;                                                                \\\n    }\n\n    switch (MajorFunction)\n    {\n        KPH_FLT_MESSAGE_ID(IRP_MJ_CREATE, Create)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_CREATE_NAMED_PIPE, CreateNamedPipe)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_CLOSE, Close)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_READ, Read)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_WRITE, Write)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_QUERY_INFORMATION, QueryInformation)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_SET_INFORMATION, SetInformation)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_QUERY_EA, QueryEa)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_SET_EA, SetEa)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_FLUSH_BUFFERS, FlushBuffers)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_QUERY_VOLUME_INFORMATION, QueryVolumeInformation)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_SET_VOLUME_INFORMATION, SetVolumeInformation)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_DIRECTORY_CONTROL, DirectoryControl)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_FILE_SYSTEM_CONTROL, FileSystemControl)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_DEVICE_CONTROL, DeviceControl)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_INTERNAL_DEVICE_CONTROL, InternalDeviceControl)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_SHUTDOWN, Shutdown)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_LOCK_CONTROL, LockControl)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_CLEANUP, Cleanup)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_CREATE_MAILSLOT, CreateMailslot)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_QUERY_SECURITY, QuerySecurity)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_SET_SECURITY, SetSecurity)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_POWER, Power)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_SYSTEM_CONTROL, SystemControl)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_DEVICE_CHANGE, DeviceChange)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_QUERY_QUOTA, QueryQuota)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_SET_QUOTA, SetQuota)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_PNP, Pnp)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION, AcquireForSectionSync)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION, ReleaseForSectionSync)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_ACQUIRE_FOR_MOD_WRITE, AcquireForModWrite)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_RELEASE_FOR_MOD_WRITE, ReleaseForModWrite)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_ACQUIRE_FOR_CC_FLUSH, AcquireForCcFlush)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_RELEASE_FOR_CC_FLUSH, ReleaseForCcFlush)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_QUERY_OPEN, QueryOpen)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE, FastIoCheckIfPossible)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_NETWORK_QUERY_OPEN, NetworkQueryOpen)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_MDL_READ, MdlRead)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_MDL_READ_COMPLETE, MdlReadComplete)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_PREPARE_MDL_WRITE, PrepareMdlWrite)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_MDL_WRITE_COMPLETE, MdlWriteComplete)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_VOLUME_MOUNT, VolumeMount)\n        KPH_FLT_MESSAGE_ID(IRP_MJ_VOLUME_DISMOUNT, VolumeDismount)\n        DEFAULT_UNREACHABLE;\n    }\n\n    return messageId;\n}\n\n/**\n * \\brief Initializes a message for a file operation.\n *\n * \\param[in,out] Message The message to initialize.\n * \\param[in] FltObjects The filter objects for the operation.\n * \\param[in] MajorFunction The major function of the operation.\n * \\param[in] PostOperation Denotes if this is a pre or post operation message.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFltInitMessage(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _In_ UCHAR MajorFunction,\n    _In_ BOOLEAN PostOperation\n    )\n{\n    ULONG_PTR stackLowLimit;\n    ULONG_PTR stackHighLimit;\n    POPLOCK_KEY_CONTEXT oplockKeyContext;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    KphMsgInit(Message, KphpFltGetMessageId(MajorFunction, PostOperation));\n\n    Message->Kernel.File.TransactionContext = FltObjects->TransactionContext;\n    Message->Kernel.File.Volume = FltObjects->Volume;\n    Message->Kernel.File.FileObject = FltObjects->FileObject;\n    Message->Kernel.File.Transaction = FltObjects->Transaction;\n\n    if (!FltObjects->FileObject)\n    {\n        return;\n    }\n\n    if (FltObjects->FileObject->SectionObjectPointer)\n    {\n        PSECTION_OBJECT_POINTERS sectionPointers;\n\n        sectionPointers = FltObjects->FileObject->SectionObjectPointer;\n\n        Message->Kernel.File.DataSectionObject = sectionPointers->DataSectionObject;\n        Message->Kernel.File.ImageSectionObject = sectionPointers->ImageSectionObject;\n    }\n\n    if (FsRtlIsPagingFile(FltObjects->FileObject))\n    {\n        Message->Kernel.File.IsPagingFile = TRUE;\n    }\n\n    if (FsRtlIsSystemPagingFile(FltObjects->FileObject))\n    {\n        Message->Kernel.File.IsSystemPagingFile = TRUE;\n    }\n\n    if (IoIsFileOriginRemote(FltObjects->FileObject))\n    {\n        Message->Kernel.File.OriginRemote = TRUE;\n    }\n\n    if (IoIsFileObjectIgnoringSharing(FltObjects->FileObject))\n    {\n        Message->Kernel.File.IgnoringSharing = TRUE;\n    }\n\n    IoGetStackLimits(&stackLowLimit, &stackHighLimit);\n    if (((ULONG_PTR)FltObjects->FileObject >= stackLowLimit) &&\n        ((ULONG_PTR)FltObjects->FileObject <= stackHighLimit))\n    {\n        Message->Kernel.File.InStackFileObject = TRUE;\n    }\n\n    Message->Kernel.File.LockOperation = (FltObjects->FileObject->LockOperation != FALSE);\n    Message->Kernel.File.ReadAccess = (FltObjects->FileObject->ReadAccess != FALSE);\n    Message->Kernel.File.WriteAccess = (FltObjects->FileObject->WriteAccess != FALSE);\n    Message->Kernel.File.DeleteAccess = (FltObjects->FileObject->DeleteAccess != FALSE);\n    Message->Kernel.File.SharedRead = (FltObjects->FileObject->SharedRead != FALSE);\n    Message->Kernel.File.SharedWrite = (FltObjects->FileObject->SharedWrite != FALSE);\n    Message->Kernel.File.SharedDelete = (FltObjects->FileObject->SharedDelete != FALSE);\n\n    oplockKeyContext = IoGetOplockKeyContextEx(FltObjects->FileObject);\n    if (oplockKeyContext)\n    {\n        RtlCopyMemory(&Message->Kernel.File.OplockKeyContext,\n                      oplockKeyContext,\n                      sizeof(OPLOCK_KEY_CONTEXT));\n    }\n\n    if (KphDynIoCheckFileObjectOpenedAsCopySource &&\n        KphDynIoCheckFileObjectOpenedAsCopySource(FltObjects->FileObject))\n    {\n        Message->Kernel.File.OpenedAsCopySource = TRUE;\n    }\n\n    if (KphDynIoCheckFileObjectOpenedAsCopyDestination &&\n        KphDynIoCheckFileObjectOpenedAsCopyDestination(FltObjects->FileObject))\n    {\n        Message->Kernel.File.OpenedAsCopyDestination = TRUE;\n    }\n}\n\n/**\n * \\brief Copies a file name into a message.\n *\n * \\param[in,out] Message The message to copy the file name into.\n * \\param[in] FieldId The field to copy the file name into.\n * \\param[in] FltFileName The file name information to copy.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFltCopyFileName(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PKPH_FLT_FILE_NAME FltFileName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING string;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    switch (FltFileName->Type)\n    {\n        case KphFltFileNameTypeNameInfo:\n        {\n            string = &FltFileName->NameInfo->Name;\n            break;\n        }\n        case KphFltFileNameTypeContext:\n        {\n            //\n            // N.B. PFLT_CONTEXT stores a PUNICODE_STRING, this is a union so\n            // fall through and use the FileName field.\n            //\n            NT_ASSERT(FltFileName->Context == FltFileName->FileName);\n            __fallthrough;\n        }\n        case KphFltFileNameTypeFileName:\n        {\n            string = FltFileName->FileName;\n            break;\n        }\n        case KphFltFileNameTypeNameCache:\n        {\n            string = &FltFileName->NameCache->FileName;\n            break;\n        }\n        default:\n        {\n            return;\n        }\n    }\n\n    status = KphMsgDynAddUnicodeString(Message, FieldId, string);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n}\n\n/**\n * \\brief Copies a file system buffer into a message.\n *\n * \\details This function handles various buffers from the file system filter\n * to capture and copy information into the message. This function is overall\n * best effort. It can truncate buffers to fit into the message.\n *\n * \\param[in,out] Message The message to copy the buffer into.\n * \\param[in] Data The callback data for the operation.\n * \\param[in] FieldId The field to copy the buffer into. Optional if DestBuffer\n * is non-NULL. Certain Unicode string fields are special cased to be copied as\n * a Unicode string instead of a sized buffer.\n * \\param[in] SystemBuffer Denotes if the buffer is a system buffer. If TRUE\n * this function assumes the buffer doesn't need to be probed and locked. In\n * some cases the filter parameters are known to be a system buffer, such as\n * METHOD_BUFFERED.\n * \\param[out] DestBuffer Optional destination buffer to copy into, if NULL the\n * data will be copied into the dynamic message buffer for FieldId.\n * \\param[in] DestLength The length of the destination buffer.\n * \\param[in] Mdl Optional memory descriptor list which the buffer will be\n * copied from instead, if non-NULL the MDL is used instead of any provided\n * input buffer.\n * \\param[in] Buffer Optional buffer to copy from, if NULL and the Mdl is NULL\n * this function will do nothing.\n * \\param[in] Length The length to copy.\n * \\param[in] Truncate If TRUE the buffer will be truncated to fit into the\n * message, otherwise the buffer copy may fail.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFltCopyBuffer(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ BOOLEAN SystemBuffer,\n    _Out_writes_bytes_to_opt_(DestLength, Length) PVOID DestBuffer,\n    _In_ ULONG DestLength,\n    _In_opt_ PMDL Mdl,\n    _In_opt_ PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN Truncate\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    PMDL mdl;\n    BOOLEAN unlockPages;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    mdl = NULL;\n    unlockPages = FALSE;\n\n    if (DestBuffer)\n    {\n        NT_ASSERT(FieldId == InvalidKphMsgField);\n        NT_ASSERT(DestLength >= Length);\n\n        RtlZeroMemory(DestBuffer, DestLength);\n    }\n    else if (Truncate)\n    {\n        USHORT remaining;\n\n        NT_ASSERT(FieldId != InvalidKphMsgField);\n\n        remaining = KphMsgDynRemaining(Message);\n\n        if (Length > remaining)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Buffer too large for message, truncating %lu -> %lu\",\n                          Length,\n                          remaining);\n\n            Length = remaining;\n        }\n    }\n\n    if (!Length)\n    {\n        goto Exit;\n    }\n\n    if (Mdl)\n    {\n        buffer = KphGetSystemAddressForMdl(Mdl, NormalPagePriority);\n        goto CopyBuffer;\n    }\n\n    if (SystemBuffer ||\n        FLT_IS_FASTIO_OPERATION(Data) ||\n        FLT_IS_SYSTEM_BUFFER(Data))\n    {\n        buffer = Buffer;\n        goto CopyBuffer;\n    }\n\n    if (!Buffer)\n    {\n        goto Exit;\n    }\n\n    if (!Data->Thread)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Missing thread for buffer capture\");\n\n        goto Exit;\n    }\n\n    mdl = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL);\n    if (!mdl)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate MDL\");\n\n        goto Exit;\n    }\n\n    __try\n    {\n        MmProbeAndLockProcessPages(mdl,\n                                   PsGetThreadProcess(Data->Thread),\n                                   KernelMode,\n                                   IoReadAccess);\n        unlockPages = TRUE;\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"MmProbeAndLockProcessPages failed: %!STATUS!\",\n                      GetExceptionCode());\n\n        goto Exit;\n    }\n\n    buffer = KphGetSystemAddressForMdl(mdl, NormalPagePriority);\n\nCopyBuffer:\n\n    if (!buffer)\n    {\n        goto Exit;\n    }\n\n    __try\n    {\n        if (DestBuffer)\n        {\n            NT_ASSERT(FieldId == InvalidKphMsgField);\n            NT_ASSERT(Length <= DestLength);\n\n            RtlCopyMemory(DestBuffer, buffer, Length);\n        }\n        else if (FieldId == KphMsgFieldDestinationFileName)\n        {\n            UNICODE_STRING fileName;\n\n            NT_ASSERT(Length <= USHORT_MAX);\n\n            fileName.Buffer = Buffer;\n            fileName.Length = (USHORT)Length;\n            fileName.MaximumLength = fileName.Length;\n\n            status = KphMsgDynAddUnicodeString(Message, FieldId, &fileName);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"KphMsgDynAddSizedBuffer failed: %!STATUS!\",\n                              status);\n            }\n        }\n        else\n        {\n            KPHM_SIZED_BUFFER sizedBuffer;\n\n            NT_ASSERT(FieldId != InvalidKphMsgField);\n            NT_ASSERT(Length <= USHORT_MAX);\n\n            sizedBuffer.Buffer = buffer;\n            sizedBuffer.Size = (USHORT)Length;\n\n            status = KphMsgDynAddSizedBuffer(Message, FieldId, &sizedBuffer);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"KphMsgDynAddSizedBuffer failed: %!STATUS!\",\n                              status);\n            }\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Exception copying buffer: %!STATUS!\",\n                      GetExceptionCode());\n\n        if (FieldId != InvalidKphMsgField)\n        {\n            //\n            // N.B. The KphMsgDynAdd* routines will first reserve a table\n            // entry then copy data into the buffer. If we get here it means\n            // the control flow was arrested after the reservation. Since we\n            // can't guarantee it was all copied successfully clear the last\n            // entry that was reserved.\n            //\n            KphMsgDynClearLast(Message);\n        }\n    }\n\nExit:\n\n    if (mdl)\n    {\n        if (unlockPages)\n        {\n            MmUnlockPages(mdl);\n        }\n\n        IoFreeMdl(mdl);\n    }\n}\n\n/**\n * \\brief Copies file system control buffers into the message.\n *\n * \\param[in,out] Message The message to copy the buffers into.\n * \\param[in] Data The callback data for the operation.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFltCopyFsControl(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PFLT_CALLBACK_DATA Data\n    )\n{\n    UCHAR method;\n    PMDL mdl;\n    PVOID buffer;\n    ULONG length;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(Data->Iopb->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL);\n\n    method = METHOD_FROM_CTL_CODE(Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode);\n\n    switch (method)\n    {\n        case METHOD_NEITHER:\n        {\n            //\n            // Capture the input and output buffer always since it is possible\n            // to use them interchangeably.\n            //\n\n            buffer = Data->Iopb->Parameters.FileSystemControl.Neither.InputBuffer;\n            if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n            {\n                length = min((ULONG)Data->IoStatus.Information,\n                             Data->Iopb->Parameters.FileSystemControl.Neither.InputBufferLength);\n            }\n            else\n            {\n                length = Data->Iopb->Parameters.FileSystemControl.Neither.InputBufferLength;\n            }\n\n            KphpFltCopyBuffer(Message,\n                              Data,\n                              KphMsgFieldInput,\n                              FALSE,\n                              NULL,\n                              0,\n                              NULL,\n                              buffer,\n                              length,\n                              TRUE);\n\n            mdl = Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress;\n            buffer = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBuffer;\n            if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n            {\n                length = min((ULONG)Data->IoStatus.Information,\n                             Data->Iopb->Parameters.FileSystemControl.Neither.OutputBufferLength);\n            }\n            else\n            {\n                length = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBufferLength;\n            }\n\n            KphpFltCopyBuffer(Message,\n                              Data,\n                              KphMsgFieldOutput,\n                              FALSE,\n                              NULL,\n                              0,\n                              mdl,\n                              buffer,\n                              length,\n                              TRUE);\n            break;\n        }\n        case METHOD_BUFFERED:\n        {\n            buffer = Data->Iopb->Parameters.FileSystemControl.Buffered.SystemBuffer;\n\n            if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n            {\n                length = min((ULONG)Data->IoStatus.Information,\n                             Data->Iopb->Parameters.FileSystemControl.Buffered.OutputBufferLength);\n\n                KphpFltCopyBuffer(Message,\n                                  Data,\n                                  KphMsgFieldOutput,\n                                  TRUE,\n                                  NULL,\n                                  0,\n                                  NULL,\n                                  buffer,\n                                  length,\n                                  TRUE);\n\n            }\n            else\n            {\n                length = Data->Iopb->Parameters.FileSystemControl.Buffered.InputBufferLength;\n\n                KphpFltCopyBuffer(Message,\n                                  Data,\n                                  KphMsgFieldInput,\n                                  TRUE,\n                                  NULL,\n                                  0,\n                                  NULL,\n                                  buffer,\n                                  length,\n                                  TRUE);\n            }\n            break;\n        }\n        case METHOD_IN_DIRECT:\n        case METHOD_OUT_DIRECT:\n        {\n            if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n            {\n                mdl = Data->Iopb->Parameters.FileSystemControl.Direct.OutputMdlAddress;\n                buffer = Data->Iopb->Parameters.FileSystemControl.Direct.OutputBuffer;\n                length = min((ULONG)Data->IoStatus.Information,\n                             Data->Iopb->Parameters.FileSystemControl.Direct.OutputBufferLength);\n\n                KphpFltCopyBuffer(Message,\n                                  Data,\n                                  KphMsgFieldOutput,\n                                  FALSE,\n                                  NULL,\n                                  0,\n                                  mdl,\n                                  buffer,\n                                  length,\n                                  TRUE);\n            }\n            else\n            {\n                buffer = Data->Iopb->Parameters.FileSystemControl.Direct.InputSystemBuffer;\n                length = Data->Iopb->Parameters.FileSystemControl.Direct.InputBufferLength;\n\n                KphpFltCopyBuffer(Message,\n                                  Data,\n                                  KphMsgFieldInput,\n                                  TRUE,\n                                  NULL,\n                                  0,\n                                  NULL,\n                                  buffer,\n                                  length,\n                                  TRUE);\n            }\n            break;\n        }\n        default:\n        {\n            return;\n        }\n    }\n}\n\n/**\n * \\brief Copies device control buffers into the message.\n *\n * \\param[in,out] Message The message to copy the buffers into.\n * \\param[in] Data The callback data for the operation.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFltCopyIoControl(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PFLT_CALLBACK_DATA Data\n    )\n{\n    UCHAR method;\n    PMDL mdl;\n    PVOID buffer;\n    ULONG length;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT((Data->Iopb->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||\n              (Data->Iopb->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL));\n\n    if (FLT_IS_FASTIO_OPERATION(Data))\n    {\n        //\n        // Capture the input and output buffer always since it is possible\n        // to use them interchangeably.\n        //\n\n        buffer = Data->Iopb->Parameters.DeviceIoControl.FastIo.InputBuffer;\n        if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n        {\n            length = min((ULONG)Data->IoStatus.Information,\n                         length = Data->Iopb->Parameters.DeviceIoControl.FastIo.InputBufferLength);\n\n        }\n        else\n        {\n            length = Data->Iopb->Parameters.DeviceIoControl.FastIo.InputBufferLength;\n        }\n\n        KphpFltCopyBuffer(Message,\n                          Data,\n                          KphMsgFieldInput,\n                          FALSE,\n                          NULL,\n                          0,\n                          NULL,\n                          buffer,\n                          length,\n                          TRUE);\n\n        buffer = Data->Iopb->Parameters.DeviceIoControl.FastIo.OutputBuffer;\n        if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n        {\n            length = min((ULONG)Data->IoStatus.Information,\n                         Data->Iopb->Parameters.DeviceIoControl.FastIo.OutputBufferLength);\n        }\n        else\n        {\n            length = Data->Iopb->Parameters.DeviceIoControl.FastIo.OutputBufferLength;\n        }\n\n        KphpFltCopyBuffer(Message,\n                          Data,\n                          KphMsgFieldOutput,\n                          FALSE,\n                          NULL,\n                          0,\n                          NULL,\n                          buffer,\n                          length,\n                          TRUE);\n        return;\n    }\n\n    method = METHOD_FROM_CTL_CODE(Data->Iopb->Parameters.DeviceIoControl.Common.IoControlCode);\n\n    switch (method)\n    {\n        case METHOD_NEITHER:\n        {\n            //\n            // Capture the input and output buffer always since it is possible\n            // to use them interchangeably.\n            //\n\n            buffer = Data->Iopb->Parameters.DeviceIoControl.Neither.InputBuffer;\n            if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n            {\n                length = min((ULONG)Data->IoStatus.Information,\n                             Data->Iopb->Parameters.DeviceIoControl.Neither.InputBufferLength);\n            }\n            else\n            {\n                length = Data->Iopb->Parameters.DeviceIoControl.Neither.InputBufferLength;\n            }\n\n            KphpFltCopyBuffer(Message,\n                              Data,\n                              KphMsgFieldInput,\n                              FALSE,\n                              NULL,\n                              0,\n                              NULL,\n                              buffer,\n                              length,\n                              TRUE);\n\n            mdl = Data->Iopb->Parameters.DeviceIoControl.Neither.OutputMdlAddress;\n            buffer = Data->Iopb->Parameters.DeviceIoControl.Neither.OutputBuffer;\n            if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n            {\n                length = min((ULONG)Data->IoStatus.Information,\n                             Data->Iopb->Parameters.DeviceIoControl.Neither.OutputBufferLength);\n            }\n            else\n            {\n                length = Data->Iopb->Parameters.DeviceIoControl.Neither.OutputBufferLength;\n            }\n\n            KphpFltCopyBuffer(Message,\n                              Data,\n                              KphMsgFieldOutput,\n                              FALSE,\n                              NULL,\n                              0,\n                              mdl,\n                              buffer,\n                              length,\n                              TRUE);\n            break;\n        }\n        case METHOD_BUFFERED:\n        {\n            buffer = Data->Iopb->Parameters.DeviceIoControl.Buffered.SystemBuffer;\n\n            if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n            {\n                length = min((ULONG)Data->IoStatus.Information,\n                             Data->Iopb->Parameters.DeviceIoControl.Buffered.OutputBufferLength);\n\n                KphpFltCopyBuffer(Message,\n                                  Data,\n                                  KphMsgFieldOutput,\n                                  TRUE,\n                                  NULL,\n                                  0,\n                                  NULL,\n                                  buffer,\n                                  length,\n                                  TRUE);\n\n            }\n            else\n            {\n                length = Data->Iopb->Parameters.DeviceIoControl.Buffered.InputBufferLength;\n\n                KphpFltCopyBuffer(Message,\n                                  Data,\n                                  KphMsgFieldInput,\n                                  TRUE,\n                                  NULL,\n                                  0,\n                                  NULL,\n                                  buffer,\n                                  length,\n                                  TRUE);\n            }\n            break;\n        }\n        case METHOD_IN_DIRECT:\n        case METHOD_OUT_DIRECT:\n        {\n            if (FlagOn(Data->Flags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n            {\n                mdl = Data->Iopb->Parameters.DeviceIoControl.Direct.OutputMdlAddress;\n                buffer = Data->Iopb->Parameters.DeviceIoControl.Direct.OutputBuffer;\n                length = min((ULONG)Data->IoStatus.Information,\n                             Data->Iopb->Parameters.DeviceIoControl.Direct.OutputBufferLength);\n\n                KphpFltCopyBuffer(Message,\n                                  Data,\n                                  KphMsgFieldOutput,\n                                  FALSE,\n                                  NULL,\n                                  0,\n                                  mdl,\n                                  buffer,\n                                  length,\n                                  TRUE);\n            }\n            else\n            {\n                buffer = Data->Iopb->Parameters.DeviceIoControl.Direct.InputSystemBuffer;\n                length = Data->Iopb->Parameters.DeviceIoControl.Direct.InputBufferLength;\n\n                KphpFltCopyBuffer(Message,\n                                  Data,\n                                  KphMsgFieldInput,\n                                  TRUE,\n                                  NULL,\n                                  0,\n                                  NULL,\n                                  buffer,\n                                  length,\n                                  TRUE);\n            }\n            break;\n        }\n        default:\n        {\n            return;\n        }\n    }\n}\n\n/**\n * \\brief Fills a message with common information.\n *\n * \\param[in,out] Message The message to fill.\n * \\param[in] Data The callback data for the operation.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphpFltFillCommonMessage(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PFLT_CALLBACK_DATA Data\n    )\n{\n    COPY_INFORMATION copyInfo;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (Data->Thread)\n    {\n        PEPROCESS process;\n        BOOLEAN cacheOnly;\n\n        process = PsGetThreadProcess(Data->Thread);\n\n        Message->Kernel.File.ClientId.UniqueProcess = PsGetProcessId(process);\n        Message->Kernel.File.ClientId.UniqueThread = PsGetThreadId(Data->Thread);\n        Message->Kernel.File.ProcessStartKey = KphGetProcessStartKey(process);\n\n        cacheOnly = (FlagOn(Data->Iopb->IrpFlags, IRP_PAGING_IO) ||\n                     FlagOn(Data->Iopb->IrpFlags, IRP_SYNCHRONOUS_PAGING_IO));\n\n        Message->Kernel.File.ThreadSubProcessTag = KphGetThreadSubProcessTagEx(Data->Thread, cacheOnly);\n    }\n\n    if (KphDynFltGetCopyInformationFromCallbackData &&\n        NT_SUCCESS(KphDynFltGetCopyInformationFromCallbackData(Data, &copyInfo)))\n    {\n        Message->Kernel.File.CopyInformation.SourceFileObject = copyInfo.SourceFileObject;\n        Message->Kernel.File.CopyInformation.SourceFileOffset = copyInfo.SourceFileOffset;\n    }\n\n    Message->Kernel.File.RequestorMode = (Data->RequestorMode != KernelMode);\n    Message->Kernel.File.MajorFunction = Data->Iopb->MajorFunction;\n    Message->Kernel.File.MinorFunction = Data->Iopb->MinorFunction;\n    Message->Kernel.File.Irql = KeGetCurrentIrql();\n    Message->Kernel.File.OperationFlags = Data->Iopb->OperationFlags;\n    Message->Kernel.File.FltFlags = Data->Flags;\n    Message->Kernel.File.IrpFlags = Data->Iopb->IrpFlags;\n\n    Message->Kernel.File.Parameters.Others.Argument1 = Data->Iopb->Parameters.Others.Argument1;\n    Message->Kernel.File.Parameters.Others.Argument2 = Data->Iopb->Parameters.Others.Argument2;\n    Message->Kernel.File.Parameters.Others.Argument3 = Data->Iopb->Parameters.Others.Argument3;\n    Message->Kernel.File.Parameters.Others.Argument4 = Data->Iopb->Parameters.Others.Argument4;\n    Message->Kernel.File.Parameters.Others.Argument5 = Data->Iopb->Parameters.Others.Argument5;\n    Message->Kernel.File.Parameters.Others.Argument6 = Data->Iopb->Parameters.Others.Argument6;\n\n    if (!Data->Iopb->TargetFileObject)\n    {\n        return;\n    }\n\n    Message->Kernel.File.DeletePending = (Data->Iopb->TargetFileObject->DeletePending != FALSE);\n    Message->Kernel.File.Busy = (Data->Iopb->TargetFileObject->Busy != 0);\n    Message->Kernel.File.Flags = Data->Iopb->TargetFileObject->Flags;\n    Message->Kernel.File.Waiters = Data->Iopb->TargetFileObject->Waiters;\n    Message->Kernel.File.CurrentByteOffset = Data->Iopb->TargetFileObject->CurrentByteOffset;\n}\n\n/**\n * \\brief Fills a message with pre operation information.\n *\n * \\param[in,out] Message The message to fill.\n * \\param[in] Data The callback data for the operation.\n * \\param[in] Options The options for the filter.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFltFillPreOpMessage(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PKPH_FLT_OPTIONS Options\n    )\n{\n    PMDL mdl;\n    PVOID buffer;\n    ULONG length;\n    KPH_MESSAGE_FIELD_ID fieldId;\n    PVOID destBuffer;\n    ULONG destLength;\n    BOOLEAN truncate;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    KphpFltFillCommonMessage(Message, Data);\n\n    mdl = NULL;\n    fieldId = InvalidKphMsgField;\n    destBuffer = NULL;\n    destLength = 0;\n    truncate = TRUE;\n\n    switch (Data->Iopb->MajorFunction)\n    {\n        case IRP_MJ_CREATE:\n        {\n            NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\n\n            buffer = Data->Iopb->Parameters.Create.EaBuffer;\n            length = Data->Iopb->Parameters.Create.EaLength;\n            fieldId = KphMsgFieldEaBuffer;\n            break;\n        }\n        case IRP_MJ_CREATE_NAMED_PIPE:\n        {\n            buffer = Data->Iopb->Parameters.CreatePipe.Parameters;\n            length = sizeof(NAMED_PIPE_CREATE_PARAMETERS);\n            destBuffer = &Message->Kernel.File.Pre.CreateNamedPipe.Parameters;\n            destLength = sizeof(NAMED_PIPE_CREATE_PARAMETERS);\n            break;\n        }\n        case IRP_MJ_SET_INFORMATION:\n        {\n            buffer = Data->Iopb->Parameters.SetFileInformation.InfoBuffer;\n            length = Data->Iopb->Parameters.SetFileInformation.Length;\n            fieldId = KphMsgFieldInformationBuffer;\n            break;\n        }\n        case IRP_MJ_QUERY_EA:\n        {\n            //\n            // Pre operation captures the input query list. Post operation will\n            // capture any returned information.\n            //\n            buffer = Data->Iopb->Parameters.QueryEa.EaList;\n            length = Data->Iopb->Parameters.QueryEa.EaListLength;\n            fieldId = KphMsgFieldInformationBuffer; // FILE_GET_EA_INFORMATION\n            break;\n        }\n        case IRP_MJ_SET_EA:\n        {\n            mdl = Data->Iopb->Parameters.SetEa.MdlAddress;\n            buffer = Data->Iopb->Parameters.SetEa.EaBuffer;\n            length = Data->Iopb->Parameters.SetEa.Length;\n            fieldId = KphMsgFieldInformationBuffer; // FILE_FULL_EA_INFORMATION\n            break;\n        }\n        case IRP_MJ_SET_VOLUME_INFORMATION:\n        {\n            buffer = Data->Iopb->Parameters.SetVolumeInformation.VolumeBuffer;\n            length = Data->Iopb->Parameters.SetVolumeInformation.Length;\n            fieldId = KphMsgFieldInformationBuffer;\n            break;\n        }\n        case IRP_MJ_DIRECTORY_CONTROL:\n        {\n            PUNICODE_STRING fileName;\n\n            if (Data->Iopb->MinorFunction != IRP_MN_QUERY_DIRECTORY)\n            {\n                return;\n            }\n\n            fileName = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName;\n            if (!fileName)\n            {\n                return;\n            }\n\n            __try\n            {\n                buffer = fileName->Buffer;\n                length = fileName->Length;\n                fieldId = KphMsgFieldDestinationFileName;\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"Exception capturing file name: %!STATUS!\",\n                              GetExceptionCode());\n\n                return;\n            }\n\n            truncate = FALSE;\n            break;\n        }\n        case IRP_MJ_FILE_SYSTEM_CONTROL:\n        {\n            if (Options->EnableFsControlBuffers)\n            {\n                KphpFltCopyFsControl(Message, Data);\n            }\n            return;\n        }\n        case IRP_MJ_DEVICE_CONTROL:\n        case IRP_MJ_INTERNAL_DEVICE_CONTROL:\n        {\n            if (Options->EnableIoControlBuffers)\n            {\n                KphpFltCopyIoControl(Message, Data);\n            }\n            return;\n        }\n        case IRP_MJ_LOCK_CONTROL:\n        {\n            buffer = Data->Iopb->Parameters.LockControl.Length;\n            length = sizeof(LARGE_INTEGER);\n            destBuffer = &Message->Kernel.File.Pre.LockControl.Length;\n            destLength = sizeof(LARGE_INTEGER);\n            break;\n        }\n        case IRP_MJ_CREATE_MAILSLOT:\n        {\n            buffer = Data->Iopb->Parameters.CreateMailslot.Parameters;\n            length = sizeof(MAILSLOT_CREATE_PARAMETERS);\n            destBuffer = &Message->Kernel.File.Pre.CreateMailslot.Parameters;\n            destLength = sizeof(MAILSLOT_CREATE_PARAMETERS);\n            break;\n        }\n        case IRP_MJ_ACQUIRE_FOR_MOD_WRITE:\n        {\n            buffer = Data->Iopb->Parameters.AcquireForModifiedPageWriter.EndingOffset;\n            length = sizeof(LARGE_INTEGER);\n            destBuffer = &Message->Kernel.File.Pre.AcquireForModWrite.EndingOffset;\n            destLength = sizeof(LARGE_INTEGER);\n            break;\n        }\n        case IRP_MJ_QUERY_OPEN:\n        {\n            buffer = Data->Iopb->Parameters.QueryOpen.Length;\n            length = sizeof(ULONG);\n            destBuffer = &Message->Kernel.File.Pre.QueryOpen.Length;\n            destLength = sizeof(ULONG);\n            break;\n        }\n        default:\n        {\n            return;\n        }\n    }\n\n    KphpFltCopyBuffer(Message,\n                      Data,\n                      fieldId,\n                      FALSE,\n                      destBuffer,\n                      destLength,\n                      mdl,\n                      buffer,\n                      length,\n                      truncate);\n}\n\n/**\n * \\brief Fills a message with post operation information.\n *\n * \\param[in,out] Message The message to fill.\n * \\param[in] Data The callback data for the operation.\n * \\param[in] Options The options for the filter.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphpFltFillPostOpMessage(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PKPH_FLT_OPTIONS Options\n    )\n{\n    PMDL mdl;\n    PVOID buffer;\n    ULONG length;\n    KPH_MESSAGE_FIELD_ID fieldId;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    KphpFltFillCommonMessage(Message, Data);\n\n    Message->Kernel.File.Post.IoStatus = Data->IoStatus;\n\n    if (KeGetCurrentIrql() > APC_LEVEL)\n    {\n        return;\n    }\n\n    mdl = NULL;\n    fieldId = InvalidKphMsgField;\n\n    switch (Data->Iopb->MajorFunction)\n    {\n        case IRP_MJ_QUERY_INFORMATION:\n        {\n            buffer = Data->Iopb->Parameters.QueryFileInformation.InfoBuffer;\n            length = min((ULONG)Data->IoStatus.Information,\n                         Data->Iopb->Parameters.QueryFileInformation.Length);\n            fieldId = KphMsgFieldInformationBuffer;\n            break;\n        }\n        case IRP_MJ_QUERY_EA:\n        {\n            //\n            // Pre operation captured the input EA list.\n            //\n            mdl = Data->Iopb->Parameters.QueryEa.MdlAddress;\n            buffer = Data->Iopb->Parameters.QueryEa.EaBuffer;\n            length = min((ULONG)Data->IoStatus.Information,\n                         Data->Iopb->Parameters.QueryEa.Length);\n            fieldId = KphMsgFieldInformationBuffer; // FILE_FULL_EA_INFORMATION\n            break;\n        }\n        case IRP_MJ_QUERY_VOLUME_INFORMATION:\n        {\n            buffer = Data->Iopb->Parameters.QueryVolumeInformation.VolumeBuffer;\n            length = min((ULONG)Data->IoStatus.Information,\n                         Data->Iopb->Parameters.QueryVolumeInformation.Length);\n            fieldId = KphMsgFieldInformationBuffer;\n            break;\n        }\n        case IRP_MJ_DIRECTORY_CONTROL:\n        {\n            if (!Options->EnableDirControlBuffers)\n            {\n                return;\n            }\n\n            switch (Data->Iopb->MinorFunction)\n            {\n                case IRP_MN_QUERY_DIRECTORY:\n                {\n                    //\n                    // Pre operation captured the input file name.\n                    //\n                    mdl = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress;\n                    buffer = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;\n                    length = min((ULONG)Data->IoStatus.Information,\n                                 Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length);\n                    fieldId = KphMsgFieldInformationBuffer;\n                    break;\n                }\n                case IRP_MN_NOTIFY_CHANGE_DIRECTORY:\n                {\n                    buffer = Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.DirectoryBuffer;\n                    length = min((ULONG)Data->IoStatus.Information,\n                                 Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.Length);\n                    fieldId = KphMsgFieldInformationBuffer;\n                    break;\n                }\n                case IRP_MN_NOTIFY_CHANGE_DIRECTORY_EX:\n                {\n                    mdl = Data->Iopb->Parameters.DirectoryControl.NotifyDirectoryEx.MdlAddress;\n                    buffer = Data->Iopb->Parameters.DirectoryControl.NotifyDirectoryEx.DirectoryBuffer;\n                    length = min((ULONG)Data->IoStatus.Information,\n                                 Data->Iopb->Parameters.DirectoryControl.NotifyDirectoryEx.Length);\n                    fieldId = KphMsgFieldInformationBuffer;\n                    break;\n                }\n                default:\n                {\n                    return;\n                }\n            }\n            break;\n        }\n        case IRP_MJ_FILE_SYSTEM_CONTROL:\n        {\n            if (Options->EnableFsControlBuffers)\n            {\n                KphpFltCopyFsControl(Message, Data);\n            }\n            return;\n        }\n        case IRP_MJ_DEVICE_CONTROL:\n        case IRP_MJ_INTERNAL_DEVICE_CONTROL:\n        {\n            if (Options->EnableIoControlBuffers)\n            {\n                KphpFltCopyIoControl(Message, Data);\n            }\n            return;\n        }\n        case IRP_MJ_QUERY_SECURITY:\n        {\n            mdl = Data->Iopb->Parameters.QuerySecurity.MdlAddress;\n            buffer = Data->Iopb->Parameters.QuerySecurity.SecurityBuffer;\n            length = min((ULONG)Data->IoStatus.Information,\n                         Data->Iopb->Parameters.QuerySecurity.Length);\n            fieldId = KphMsgFieldInformationBuffer;\n            break;\n        }\n        case IRP_MJ_QUERY_OPEN:\n        {\n            //\n            // The File System does not fill in the Information field in the\n            // IO_STATUS block. Filters shouldn't inspect this value in their\n            // post-calls. Use the length from the QueryOpen parameters.\n            //\n\n            if (!Data->Iopb->Parameters.QueryOpen.Length)\n            {\n                return;\n            }\n\n            __try\n            {\n                length = *Data->Iopb->Parameters.QueryOpen.Length;\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"Exception capturing length: %!STATUS!\",\n                              GetExceptionCode());\n\n                return;\n            }\n\n            buffer = Data->Iopb->Parameters.QueryOpen.FileInformation;\n            fieldId = KphMsgFieldInformationBuffer;\n            break;\n        }\n        case IRP_MJ_NETWORK_QUERY_OPEN:\n        {\n            buffer = Data->Iopb->Parameters.NetworkQueryOpen.NetworkInformation;\n            length = sizeof(FILE_NETWORK_OPEN_INFORMATION);\n            fieldId = KphMsgFieldInformationBuffer;\n            break;\n        }\n        default:\n        {\n            return;\n        }\n    }\n\n    KphpFltCopyBuffer(Message,\n                      Data,\n                      fieldId,\n                      FALSE,\n                      NULL,\n                      0,\n                      mdl,\n                      buffer,\n                      length,\n                      TRUE);\n}\n\n/**\n * \\brief Handles name tunneling for a given file name information.\n *\n * \\details If the file name was tunneled, the re-tunneled file name will be\n * copied into the message, otherwise the original file name will be copied.\n *\n * \\param[in,out] Message The message to copy the file name into.\n * \\param[in] Data The callback data for the operation.\n * \\param[in] FieldId The field to copy the file name into.\n * \\param[in] FileNameInfo The file name information to handle.\n *\n * \\return TRUE if the file name was tunneled, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\nBOOLEAN KphpFltHandleNameTunneling(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PFLT_FILE_NAME_INFORMATION FileNameInfo\n    )\n{\n    NTSTATUS status;\n    PFLT_FILE_NAME_INFORMATION reTunneledFileNameInfo;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    NT_ASSERT(FileNameInfo->Format == FLT_FILE_NAME_NORMALIZED);\n\n    status = FltGetTunneledName(Data,\n                                FileNameInfo,\n                                &reTunneledFileNameInfo);\n    if (!NT_SUCCESS(status))\n    {\n        if (NT_SUCCESS(Data->IoStatus.Status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"FltGetTunneledName failed: %!STATUS!\",\n                          status);\n        }\n\n        reTunneledFileNameInfo = FALSE;\n    }\n\n    if (!reTunneledFileNameInfo)\n    {\n        //\n        // The file name was not tunneled.\n        //\n        status = KphMsgDynAddUnicodeString(Message,\n                                           FieldId,\n                                           &FileNameInfo->Name);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                          status);\n        }\n\n        return FALSE;\n    }\n\n    status = KphMsgDynAddUnicodeString(Message,\n                                       FieldId,\n                                       &reTunneledFileNameInfo->Name);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\n    FltReleaseFileNameInformation(reTunneledFileNameInfo);\n\n    return TRUE;\n}\n\n/**\n * \\brief Check if name tunneling is relevant for the operation.\n *\n * \\param[in] Data The callback data for the operation.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphpFltIsNameTunnelingPossible(\n    _In_ PFLT_CALLBACK_DATA Data\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (Data->Iopb->MajorFunction == IRP_MJ_CREATE)\n    {\n        return TRUE;\n    }\n    else if (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION)\n    {\n        switch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass)\n        {\n            case FileRenameInformation:\n            case FileRenameInformationBypassAccessCheck:\n            case FileRenameInformationEx:\n            case FileRenameInformationExBypassAccessCheck:\n            case FileLinkInformation:\n            case FileLinkInformationBypassAccessCheck:\n            case FileLinkInformationEx:\n            case FileLinkInformationExBypassAccessCheck:\n            {\n                return TRUE;\n            }\n            default:\n            {\n                break;\n            }\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * \\brief Handles name tunneling in the post operation callback.\n *\n * \\param[in] Data The callback data for the operation.\n * \\param[in,out] Context The completion context for the operation.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphpFltPostOpHandleNameTunneling(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _Inout_ PKPH_FLT_COMPLETION_CONTEXT Context\n    )\n{\n    BOOLEAN tunneledFileName;\n    BOOLEAN tunneledDestFileName;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    NT_ASSERT(KphpFltIsNameTunnelingPossible(Data));\n\n    tunneledFileName = FALSE;\n    tunneledDestFileName = FALSE;\n\n    if (Context->FileNameInfo)\n    {\n        NT_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);\n        NT_ASSERT(Context->FileNameInfo->Format == FLT_FILE_NAME_NORMALIZED);\n        NT_ASSERT((Data->Iopb->MajorFunction == IRP_MJ_CREATE) ||\n                  (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION));\n\n        if (KphpFltHandleNameTunneling(Context->Message,\n                                       Data,\n                                       KphMsgFieldFileName,\n                                       Context->FileNameInfo))\n        {\n            tunneledFileName = TRUE;\n        }\n    }\n\n    if (Context->DestFileNameInfo)\n    {\n        NT_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);\n        NT_ASSERT(Context->DestFileNameInfo->Format == FLT_FILE_NAME_NORMALIZED);\n        NT_ASSERT(Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION);\n\n        if (KphpFltHandleNameTunneling(Context->Message,\n                                       Data,\n                                       KphMsgFieldDestinationFileName,\n                                       Context->DestFileNameInfo))\n        {\n            tunneledDestFileName = TRUE;\n        }\n    }\n\n    if (Data->Iopb->MajorFunction == IRP_MJ_CREATE)\n    {\n        Context->Message->Kernel.File.Post.Create.TunneledFileName = tunneledFileName;\n    }\n    else if (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION)\n    {\n        Context->Message->Kernel.File.Post.SetInformation.TunneledFileName = tunneledFileName;\n        Context->Message->Kernel.File.Post.SetInformation.TunneledDestinationFileName = tunneledDestFileName;\n    }\n}\n\n/**\n * \\brief Frees a completion context.\n *\n * \\param[in] CompletionContext The completion context to free.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphpFltFreeCompletionContext(\n    _In_ PKPH_FLT_COMPLETION_CONTEXT CompletionContext\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (CompletionContext->Message)\n    {\n        KphFreeNPagedMessage(CompletionContext->Message);\n    }\n\n    //\n    // N.B. The file name information is released in the post operation should\n    // only occur from IRP_MJ_CREATE or IRP_MJ_SET_INFORMATION when the name\n    // needs to be possibly re-tunneled. This should only happen at or below\n    // APC_LEVEL.\n    //\n\n    if (CompletionContext->FileNameInfo)\n    {\n        NT_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);\n        FltReleaseFileNameInformation(CompletionContext->FileNameInfo);\n    }\n\n    if (CompletionContext->DestFileNameInfo)\n    {\n        NT_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);\n        FltReleaseFileNameInformation(CompletionContext->DestFileNameInfo);\n    }\n\n    KphFreeToNPagedLookaside(&KphpFltCompletionContextLookaside,\n                             CompletionContext);\n}\n\n/**\n * \\brief Filter post operation callback for file operations.\n *\n * \\param[in] Data The callback data for the operation.\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[in] CompletionContext The completion context for the operation.\n * \\param[in] Flags Filter post operation flags.\n *\n * \\return FLT_POSTOP_FINISHED_PROCESSING\n */\n_Function_class_(PFLT_POST_OPERATION_CALLBACK)\n_IRQL_requires_max_(DISPATCH_LEVEL)\nFLT_POSTOP_CALLBACK_STATUS FLTAPI KphpFltPostOp(\n    _Inout_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _In_opt_ PVOID CompletionContext,\n    _In_ FLT_POST_OPERATION_FLAGS Flags\n    )\n{\n    NTSTATUS status;\n    ULONG64 sequence;\n    KPH_MESSAGE_ID messageId;\n    PKPH_FLT_COMPLETION_CONTEXT context;\n    PKPH_MESSAGE reply;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    sequence = InterlockedIncrementU64(&KphpFltSequence);\n\n    context = CompletionContext;\n    reply = NULL;\n\n    if (!context)\n    {\n        goto Exit;\n    }\n\n    if (FlagOn(Flags, FLTFL_POST_OPERATION_DRAINING))\n    {\n        NT_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);\n        goto Exit;\n    }\n\n    //\n    // Message was already initialized by the pre operation callback.\n    // But we need to update a few things for the post operation callback.\n    //\n    NT_ASSERT(NT_SUCCESS(KphMsgValidate(context->Message)));\n    NT_ASSERT(context->Message->Kernel.File.Sequence == 0);\n    NT_ASSERT(context->Message->Header.TimeStamp.QuadPart == 0);\n\n    messageId = KphpFltGetMessageId(Data->Iopb->MajorFunction, TRUE);\n    context->Message->Header.MessageId = messageId;\n    KeQuerySystemTime(&context->Message->Header.TimeStamp);\n    context->Message->Kernel.File.Sequence = sequence;\n\n    if (KphpFltIsNameTunnelingPossible(Data))\n    {\n        KphpFltPostOpHandleNameTunneling(Data, context);\n    }\n\n    KphpFltFillPostOpMessage(context->Message, Data, &context->Options);\n\n    if (context->Options.EnableStackTraces)\n    {\n        KphCaptureStackInMessage(context->Message);\n    }\n\n    if ((Data->Iopb->MajorFunction != IRP_MJ_CREATE) ||\n        !context->Options.EnablePostCreateReply)\n    {\n        KphCommsSendNPagedMessageAsync(context->Message);\n        context->Message = NULL;\n\n        goto Exit;\n    }\n\n    NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\n\n    reply = KphAllocateNPagedMessage();\n    if (!reply)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphAllocateNPagedMessage failed\");\n\n        goto Exit;\n    }\n\n    status = KphCommsSendMessage(context->Message, reply);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to send message (%lu): %!STATUS!\",\n                      (ULONG)context->Message->Header.MessageId,\n                      status);\n\n        goto Exit;\n    }\n\n    if ((reply->Header.MessageId == KphMsgFilePostCreate) &&\n        (reply->Reply.File.Post.Create.Status != STATUS_SUCCESS))\n    {\n        Data->IoStatus.Status = reply->Reply.File.Post.Create.Status;\n        Data->IoStatus.Information = 0;\n        FltCancelFileOpen(FltObjects->Instance, FltObjects->FileObject);\n    }\n\nExit:\n\n    if (reply)\n    {\n        KphFreeNPagedMessage(reply);\n    }\n\n    if (context)\n    {\n        KphpFltFreeCompletionContext(context);\n    }\n\n    if (Data->Iopb->MajorFunction == IRP_MJ_CLOSE)\n    {\n        KphpFltReapFileNameCache(Data, FltObjects);\n    }\n\n    return FLT_POSTOP_FINISHED_PROCESSING;\n}\n\n/**\n * \\brief Creates a message from pre the operation callback the post operation.\n *\n * \\param[in] Data The callback data for the operation.\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[in] Options The options for the filter.\n * \\param[in] FltFileName The file name information for the operation.\n * \\param[in] FltDestFileName The destination file name information, if any.\n * \\param[in] Sequence The sequence number for the pre operation.\n * \\param[in] TimeStamp The time stamp for the pre operation.\n * \\param[out] Context Set to the completion context for the operation.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpFltPreOpCreateCompletionContext(\n    _In_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _In_ PKPH_FLT_OPTIONS Options,\n    _In_ PKPH_FLT_FILE_NAME FltFileName,\n    _In_ PKPH_FLT_FILE_NAME FltDestFileName,\n    _In_ ULONG64 Sequence,\n    _In_ PLARGE_INTEGER TimeStamp,\n    _Out_ PKPH_FLT_COMPLETION_CONTEXT* CompletionContext\n    )\n{\n    NTSTATUS status;\n    PKPH_FLT_COMPLETION_CONTEXT context;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    *CompletionContext = NULL;\n\n    context = KphAllocateFromNPagedLookaside(&KphpFltCompletionContextLookaside);\n    if (!context)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphAllocateFromNPagedLookaside failed\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    context->Options.Flags = Options->Flags;\n\n    //\n    // Create the message for the post operation to finish filling in. We\n    // will populate what we can in the pre operation callback. In some cases\n    // this is necessary since post operation can complete at dispatch.\n    //\n\n    context->Message = KphAllocateNPagedMessage();\n    if (!context->Message)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphAllocateNPagedMessage failed\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    KphpFltInitMessage(context->Message,\n                       FltObjects,\n                       Data->Iopb->MajorFunction,\n                       TRUE);\n\n    //\n    // Will be populated when the operation completes. Set a sentinel value\n    // for the time stamp to indicate that it is not yet valid.\n    //\n    NT_ASSERT(context->Message->Kernel.File.Sequence == 0);\n    context->Message->Header.TimeStamp.QuadPart = 0;\n\n    context->Message->Kernel.File.Post.PreSequence = Sequence;\n    context->Message->Kernel.File.Post.PreTimeStamp = *TimeStamp;\n\n    if (Options->EnablePostFileNames)\n    {\n        //\n        // Only if we have to will we fill in the file name information in the post\n        // operation (and resolve a possibly tunneled names there). In most cases\n        // we will copy the file name information into the post message here.\n        //\n        if (!KphpFltIsNameTunnelingPossible(Data))\n        {\n            KphpFltCopyFileName(context->Message, KphMsgFieldFileName, FltFileName);\n            KphpFltCopyFileName(context->Message, KphMsgFieldDestinationFileName, FltDestFileName);\n        }\n        else if (Data->Iopb->MajorFunction == IRP_MJ_CREATE)\n        {\n            if ((FltFileName->Type == KphFltFileNameTypeNameInfo) &&\n                (FltFileName->NameInfo->Format == FLT_FILE_NAME_NORMALIZED))\n            {\n                context->FileNameInfo = FltFileName->NameInfo;\n                FltReferenceFileNameInformation(context->FileNameInfo);\n            }\n            else\n            {\n                KphpFltCopyFileName(context->Message, KphMsgFieldFileName, FltFileName);\n            }\n        }\n        else\n        {\n            NT_ASSERT(Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION);\n\n            if ((FltFileName->Type == KphFltFileNameTypeNameInfo) &&\n                (FltFileName->NameInfo->Format == FLT_FILE_NAME_NORMALIZED))\n            {\n                context->FileNameInfo = FltFileName->NameInfo;\n                FltReferenceFileNameInformation(context->FileNameInfo);\n            }\n            else\n            {\n                KphpFltCopyFileName(context->Message, KphMsgFieldFileName, FltFileName);\n            }\n\n            if ((FltDestFileName->Type == KphFltFileNameTypeNameInfo) &&\n                (FltDestFileName->NameInfo->Format == FLT_FILE_NAME_NORMALIZED))\n            {\n                context->DestFileNameInfo = FltDestFileName->NameInfo;\n                FltReferenceFileNameInformation(context->DestFileNameInfo);\n            }\n            else\n            {\n                KphpFltCopyFileName(context->Message, KphMsgFieldDestinationFileName, FltDestFileName);\n            }\n        }\n    }\n\n    *CompletionContext = context;\n    context = NULL;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (context)\n    {\n        KphpFltFreeCompletionContext(context);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Sends a pre operation message.\n *\n * \\param[in,out] Data The callback data for the operation.\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[in] Options The options for the filter.\n * \\param[in] FltFileName The file name information for the operation.\n * \\param[in] FltDestFileName The destination file name information, if any.\n * \\param[in] Sequence The sequence number for the operation.\n * \\param[out] TimeStamp Set to the time stamp for the pre operation.\n *\n * \\return FLT_PREOP_SUCCESS_NO_CALLBACK or FLT_PREOP_COMPLETE\n */\n_IRQL_requires_max_(APC_LEVEL)\nFLT_PREOP_CALLBACK_STATUS KphpFltPreOpSend(\n    _Inout_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _In_ PKPH_FLT_OPTIONS Options,\n    _In_ PKPH_FLT_FILE_NAME FltFileName,\n    _In_ PKPH_FLT_FILE_NAME FltDestFileName,\n    _In_ ULONG64 Sequence,\n    _Out_ PLARGE_INTEGER TimeStamp\n    )\n{\n    FLT_PREOP_CALLBACK_STATUS callbackStatus;\n    NTSTATUS status;\n    PKPH_MESSAGE message;\n    PKPH_MESSAGE reply;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    callbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;\n    reply = NULL;\n\n    message = KphAllocateNPagedMessage();\n    if (!message)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphAllocateNPagedMessage failed\");\n\n        KeQuerySystemTime(TimeStamp);\n        goto Exit;\n    }\n\n    KphpFltInitMessage(message, FltObjects, Data->Iopb->MajorFunction, FALSE);\n\n    *TimeStamp = message->Header.TimeStamp;\n\n    message->Kernel.File.Sequence = Sequence;\n\n    KphpFltCopyFileName(message, KphMsgFieldFileName, FltFileName);\n    KphpFltCopyFileName(message, KphMsgFieldDestinationFileName, FltDestFileName);\n\n    //\n    // The post operation callback will resolve this name and note if it\n    // was a re-tunneled file name. For the pre operation callback we can\n    // only denote in the message that the file name is possibly tunneled.\n    //\n    if (!KphpFltIsNameTunnelingPossible(Data))\n    {\n        NOTHING;\n    }\n    else if (Data->Iopb->MajorFunction == IRP_MJ_CREATE)\n    {\n        if ((FltFileName->Type == KphFltFileNameTypeNameInfo) &&\n            (FltFileName->NameInfo->Format == FLT_FILE_NAME_NORMALIZED))\n        {\n            message->Kernel.File.Pre.Create.MaybeTunneledFileName = TRUE;\n        }\n    }\n    else\n    {\n        NT_ASSERT(Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION);\n\n        if ((FltFileName->Type == KphFltFileNameTypeNameInfo) &&\n            (FltFileName->NameInfo->Format == FLT_FILE_NAME_NORMALIZED))\n        {\n            message->Kernel.File.Pre.SetInformation.MaybeTunneledFileName = TRUE;\n        }\n\n        if ((FltDestFileName->Type == KphFltFileNameTypeNameInfo) &&\n            (FltDestFileName->NameInfo->Format == FLT_FILE_NAME_NORMALIZED))\n        {\n            message->Kernel.File.Pre.SetInformation.MaybeTunneledDestinationFileName = TRUE;\n        }\n    }\n\n    KphpFltFillPreOpMessage(message, Data, Options);\n\n    if (Options->EnableStackTraces)\n    {\n        KphCaptureStackInMessage(message);\n    }\n\n    if ((Data->Iopb->MajorFunction != IRP_MJ_CREATE) ||\n        !Options->EnablePreCreateReply)\n    {\n        KphCommsSendNPagedMessageAsync(message);\n        message = NULL;\n\n        goto Exit;\n    }\n\n    reply = KphAllocateNPagedMessage();\n    if (!reply)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphAllocateNPagedMessage failed\");\n\n        goto Exit;\n    }\n\n    status = KphCommsSendMessage(message, reply);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to send message (%lu): %!STATUS!\",\n                      (ULONG)message->Header.MessageId,\n                      status);\n\n        goto Exit;\n    }\n\n    if ((reply->Header.MessageId == KphMsgFilePreCreate) &&\n        (reply->Reply.File.Pre.Create.Status != STATUS_SUCCESS))\n    {\n        Data->IoStatus.Status = reply->Reply.File.Pre.Create.Status;\n        Data->IoStatus.Information = 0;\n        callbackStatus = FLT_PREOP_COMPLETE;\n    }\n\nExit:\n\n    if (reply)\n    {\n        KphFreeNPagedMessage(reply);\n    }\n\n    if (message)\n    {\n        KphFreeNPagedMessage(message);\n    }\n\n    return callbackStatus;\n}\n\n/**\n * \\brief Handles a request to perform an action inside of the filter.\n *\n * \\param[in,out] Data The callback data for the operation.\n * \\param[in] FltObjects The related objects for the operation.\n */\nVOID KphpFltRequestHandler(\n    _Inout_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects\n    )\n{\n    PKPH_THREAD_CONTEXT thread;\n\n    //\n    // KphQueryVirtualMemory will use this to create a data section object.\n    // It will do this by issuing a MemoryMappedFilenameInformation. This\n    // results in an IRP_MJ_QUERY_INFORMATION with FileNameInformation. And will\n    // have previously set the one of the \"TLS slots\" to the address of the\n    // KphQueryVirtualMemory stack to pass information to and from this call.\n    //\n\n    if ((Data->Iopb->MajorFunction != IRP_MJ_QUERY_INFORMATION) ||\n        (Data->Iopb->Parameters.QueryFileInformation.FileInformationClass != FileNameInformation))\n    {\n        return;\n    }\n\n    thread = KphGetCurrentThreadContext();\n    if (!thread)\n    {\n        return;\n    }\n\n    if (thread->VmTlsCreateDataSection)\n    {\n        PKPH_VM_TLS_CREATE_DATA_SECTION tls;\n        NTSTATUS status;\n        OBJECT_ATTRIBUTES objectAttributes;\n        PVOID sectionObject;\n\n        tls = thread->VmTlsCreateDataSection;\n\n        thread->VmTlsCreateDataSection = NULL;\n\n        InitializeObjectAttributes(&objectAttributes,\n                                   NULL,\n                                   (tls->AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                   NULL,\n                                   NULL);\n\n        status = FsRtlCreateSectionForDataScan(&tls->SectionHandle,\n                                               &sectionObject,\n                                               &tls->SectionFileSize,\n                                               FltObjects->FileObject,\n                                               SECTION_QUERY | SECTION_MAP_READ,\n                                               &objectAttributes,\n                                               NULL,\n                                               PAGE_READONLY,\n                                               SEC_COMMIT,\n                                               0);\n        if (NT_SUCCESS(status))\n        {\n            ObDereferenceObject(sectionObject);\n        }\n\n        tls->Status = status;\n    }\n    else if (thread->VmTlsMappedInformation)\n    {\n        PKPH_MEMORY_MAPPED_INFORMATION tls;\n\n        tls = thread->VmTlsMappedInformation;\n\n        thread->VmTlsMappedInformation = NULL;\n\n        tls->FileObject = FltObjects->FileObject;\n        tls->SectionObjectPointers = FltObjects->FileObject->SectionObjectPointer;\n        if (FltObjects->FileObject->SectionObjectPointer)\n        {\n            tls->DataControlArea = FltObjects->FileObject->SectionObjectPointer->DataSectionObject;\n            tls->SharedCacheMap = FltObjects->FileObject->SectionObjectPointer->SharedCacheMap;\n            tls->ImageControlArea = FltObjects->FileObject->SectionObjectPointer->ImageSectionObject;\n            tls->UserWritableReferences = MmDoesFileHaveUserWritableReferences(FltObjects->FileObject->SectionObjectPointer);\n        }\n    }\n\n    KphDereferenceObject(thread);\n}\n\n/**\n * \\brief Filter pre operation callback for file operations.\n *\n * \\param[in,out] Data The callback data for the operation.\n * \\param[in] FltObjects The related objects for the operation.\n * \\param[out] CompletionContext Set to the completion context if necessary.\n *\n * \\return An appropriate callback status depending on the a post operation\n * is needed or the pre operation should be completed.\n */\n_Function_class_(PFLT_PRE_OPERATION_CALLBACK)\n_IRQL_requires_max_(APC_LEVEL)\nFLT_PREOP_CALLBACK_STATUS FLTAPI KphpFltPreOp(\n    _Inout_ PFLT_CALLBACK_DATA Data,\n    _In_ PCFLT_RELATED_OBJECTS FltObjects,\n    _Outptr_result_maybenull_ PVOID* CompletionContext\n    )\n{\n    ULONG64 sequence;\n    FLT_PREOP_CALLBACK_STATUS callbackStatus;\n    KPH_FLT_OPTIONS options;\n    NTSTATUS status;\n    KPH_FLT_FILE_NAME fltFileName;\n    KPH_FLT_FILE_NAME fltDestFileName;\n    LARGE_INTEGER timeStamp;\n\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    *CompletionContext = NULL;\n\n    KphpFltRequestHandler(Data, FltObjects);\n\n    sequence = InterlockedIncrementU64(&KphpFltSequence);\n    callbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;\n\n    KphpFltZeroFileName(&fltFileName);\n    KphpFltZeroFileName(&fltDestFileName);\n\n    options = KphpFltGetOptions(Data);\n\n    if (!options.PreEnabled && !options.PostEnabled)\n    {\n        goto Exit;\n    }\n\n    if (!options.EnablePagingIo &&\n        FlagOn(Data->Iopb->IrpFlags, IRP_PAGING_IO))\n    {\n        goto Exit;\n    }\n\n    if (!options.EnableSyncPagingIo &&\n        FlagOn(Data->Iopb->IrpFlags, IRP_SYNCHRONOUS_PAGING_IO))\n    {\n        goto Exit;\n    }\n\n    //\n    // Either pre or post is enabled, gather what is needed.\n    //\n\n    status = KphpFltGetFileName(Data, FltObjects, &fltFileName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphpFltGetFileName failed: %!STATUS!\",\n                      status);\n    }\n\n    if (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION)\n    {\n        switch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass)\n        {\n            case FileRenameInformation:\n            case FileRenameInformationBypassAccessCheck:\n            case FileRenameInformationEx:\n            case FileRenameInformationExBypassAccessCheck:\n            case FileLinkInformation:\n            case FileLinkInformationBypassAccessCheck:\n            case FileLinkInformationEx:\n            case FileLinkInformationExBypassAccessCheck:\n            {\n                status = KphpFltGetDestFileName(Data,\n                                                FltObjects,\n                                                &fltDestFileName);\n                if (!NT_SUCCESS(status))\n                {\n                    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                                  INFORMER,\n                                  \"KphpFltGetDestFileName failed: %!STATUS!\",\n                                  status);\n                }\n\n                break;\n            }\n        }\n    }\n\n    if (options.PreEnabled)\n    {\n        callbackStatus = KphpFltPreOpSend(Data,\n                                          FltObjects,\n                                          &options,\n                                          &fltFileName,\n                                          &fltDestFileName,\n                                          sequence,\n                                          &timeStamp);\n\n        NT_ASSERT((callbackStatus == FLT_PREOP_SUCCESS_NO_CALLBACK) ||\n                  (callbackStatus == FLT_PREOP_COMPLETE));\n\n        if (callbackStatus == FLT_PREOP_COMPLETE)\n        {\n            goto Exit;\n        }\n    }\n    else\n    {\n        //\n        // Pre operations aren't enabled, but we need to grab the time stamp\n        // for the post operation to use.\n        //\n        KeQuerySystemTime(&timeStamp);\n    }\n\n    if (options.PostEnabled)\n    {\n        PKPH_FLT_COMPLETION_CONTEXT context;\n\n        status = KphpFltPreOpCreateCompletionContext(Data,\n                                                     FltObjects,\n                                                     &options,\n                                                     &fltFileName,\n                                                     &fltDestFileName,\n                                                     sequence,\n                                                     &timeStamp,\n                                                     &context);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphpFltPreOpCreatePostOpMessage failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        if (Data->Iopb->MajorFunction == IRP_MJ_SHUTDOWN)\n        {\n            //\n            // Post operation for IRP_MJ_SHUTDOWN is not supported, we do not\n            // register for one, fake it here by directly calling the post\n            // operation handler.\n            //\n            KphpFltPostOp(Data, FltObjects, context, 0);\n        }\n        else\n        {\n            *CompletionContext = context;\n            callbackStatus = FLT_PREOP_SUCCESS_WITH_CALLBACK;\n        }\n    }\n\nExit:\n\n    KphpFltReleaseFileName(&fltDestFileName);\n    KphpFltReleaseFileName(&fltFileName);\n\n    NT_ASSERT((callbackStatus == FLT_PREOP_SUCCESS_NO_CALLBACK) ||\n              (callbackStatus == FLT_PREOP_SUCCESS_WITH_CALLBACK) ||\n              (callbackStatus == FLT_PREOP_COMPLETE));\n\n    if ((callbackStatus != FLT_PREOP_SUCCESS_WITH_CALLBACK) &&\n        (Data->Iopb->MajorFunction == IRP_MJ_CLOSE))\n    {\n        NT_ASSERT(callbackStatus != FLT_PREOP_COMPLETE);\n        //\n        // N.B. We always require a post operation callback for IRP_MJ_CLOSE\n        // in order to do reaping (see: KphpFltReapFileNameCache).\n        //\n        callbackStatus = FLT_PREOP_SUCCESS_WITH_CALLBACK;\n    }\n\n    return callbackStatus;\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Cleans up the file operation filter.\n*/\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpFltCleanupFileOp(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!KphpFltOpInitialized)\n    {\n        return;\n    }\n\n    KphDeleteNPagedLookaside(&KphpFltCompletionContextLookaside);\n}\n\n/**\n * \\brief Initializes the file operation filter.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpFltInitializeFileOp(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphInitializeNPagedLookaside(&KphpFltCompletionContextLookaside,\n                                 sizeof(KPH_FLT_COMPLETION_CONTEXT),\n                                 KPH_TAG_FLT_COMPLETION_CONTEXT);\n\n    KphpFltOpInitialized = TRUE;\n}\n\n//\n// These are some ugly compile time asserts intentionally hidden at the bottom\n// of the file. Essentially, this is asserting that FLT_PARAMETERS has not\n// changed enough to update KPHM_FILE_PARAMETERS. Realistically it should never\n// change, but they're here for posterity.\n//\n\nC_ASSERT(sizeof(KPHM_FILE_PARAMETERS) == sizeof(FLT_PARAMETERS));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, Create) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Create));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, CreateNamedPipe) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       CreatePipe));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, CreateMailslot) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       CreateMailslot));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, Read) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Read));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, Write) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Write));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryInformation) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       QueryFileInformation));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetInformation) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       SetFileInformation));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryEa) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       QueryEa));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetEa) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       SetEa));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryVolumeInformation) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       QueryVolumeInformation));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetVolumeInformation) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       SetVolumeInformation));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, DirectoryControl) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       DirectoryControl));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, FileSystemControl) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       FileSystemControl));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, DeviceControl) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       DeviceIoControl));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, LockControl) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       LockControl));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QuerySecurity) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       QuerySecurity));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetSecurity) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       SetSecurity));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SystemControl) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       WMI));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryQuota) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       QueryQuota));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetQuota) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       SetQuota));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, Pnp) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Pnp));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, AcquireForSectionSync) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       AcquireForSectionSynchronization));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, AcquireForModWrite) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       AcquireForModifiedPageWriter));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, ReleaseForModWrite) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       ReleaseForModifiedPageWriter));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryOpen) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       QueryOpen));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, FastIoCheckIfPossible) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       FastIoCheckIfPossible));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, NetworkQueryOpen) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       NetworkQueryOpen));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, MdlRead) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       MdlRead));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, MdlReadComplete) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       MdlReadComplete));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, PrepareMdlWrite) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       PrepareMdlWrite));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, MdlWriteComplete) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       MdlWriteComplete));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, VolumeMount) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       MountVolume));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, Others) ==\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\n\n//\n// N.B. We make an optimization that we only need to copy these 6 arguments\n// when copying the parameter data into the message. Any of these asserts fire\n// we must update KPHM_FILE_PARAMETERS.\n//\n\nC_ASSERT(RTL_SIZEOF_THROUGH_FIELD(FLT_PARAMETERS, Others.Argument1) == 0x08);\nC_ASSERT(RTL_SIZEOF_THROUGH_FIELD(FLT_PARAMETERS, Others.Argument2) == 0x10);\nC_ASSERT(RTL_SIZEOF_THROUGH_FIELD(FLT_PARAMETERS, Others.Argument3) == 0x18);\nC_ASSERT(RTL_SIZEOF_THROUGH_FIELD(FLT_PARAMETERS, Others.Argument4) == 0x20);\nC_ASSERT(RTL_SIZEOF_THROUGH_FIELD(FLT_PARAMETERS, Others.Argument5) == 0x28);\nC_ASSERT(RTL_SIZEOF_THROUGH_FIELD(FLT_PARAMETERS, Others.Argument6) == 0x30);\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, Create) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, CreateNamedPipe) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, CreateMailslot) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, Read) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, Write) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryInformation) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetInformation) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryEa) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetEa) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryVolumeInformation) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetVolumeInformation) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, DirectoryControl) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, FileSystemControl) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, DeviceControl) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, LockControl) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QuerySecurity) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetSecurity) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SystemControl) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryQuota) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, SetQuota) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, Pnp) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, AcquireForSectionSync) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, AcquireForModWrite) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, ReleaseForModWrite) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, QueryOpen) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, FastIoCheckIfPossible) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, NetworkQueryOpen) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, MdlRead) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, MdlReadComplete) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, PrepareMdlWrite) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, MdlWriteComplete) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\nC_ASSERT(RTL_FIELD_SIZE(KPHM_FILE_PARAMETERS, VolumeMount) <=\n         RTL_FIELD_SIZE(FLT_PARAMETERS,       Others));\n"
  },
  {
    "path": "KSystemInformer/informer_image.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <informer.h>\n#include <comms.h>\n#include <kphmsgdyn.h>\n\n#include <trace.h>\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PVOID KphpImageVerificationCallbackHandle = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Performs image tracking.\n *\n * \\param[in,out] Process The process loading the image.\n * \\param[in] ImageInfo The image info from the notification routine.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpPerformImageTracking(\n    _Inout_ PKPH_PROCESS_CONTEXT Process,\n    _In_ PIMAGE_INFO_EX ImageInfo\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(ImageInfo);\n\n    InterlockedIncrementSizeT(&Process->NumberOfImageLoads);\n}\n\n/**\n * \\brief Informs any clients of image notify routine invocations.\n *\n * \\param[in] FullImageName File name of the loading image.\n * \\param[in] ProcessId Process ID where the image is being loaded.\n * \\param[in] ImageInfo Information about the image being loaded.\n */\n_Function_class_(PLOAD_IMAGE_NOTIFY_ROUTINE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpLoadImageNotifyInformer(\n    _In_opt_ PUNICODE_STRING FullImageName,\n    _In_ HANDLE ProcessId,\n    _In_ PIMAGE_INFO_EX ImageInfo\n    )\n{\n    NTSTATUS status;\n    PKPH_PROCESS_CONTEXT targetProcess;\n    PKPH_PROCESS_CONTEXT actorProcess;\n    PKPH_MESSAGE msg;\n    PUNICODE_STRING fileName;\n    BOOLEAN freeFileName;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    actorProcess = KphGetCurrentProcessContext();\n    targetProcess = KphGetProcessContext(ProcessId);\n\n    if (!KphInformerEnabled2(ImageLoad, actorProcess, targetProcess))\n    {\n        goto Exit;\n    }\n\n    msg = KphAllocateMessage();\n    if (!msg)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate message\");\n        goto Exit;\n    }\n\n    freeFileName = TRUE;\n    status = KphGetNameFileObject(ImageInfo->FileObject, &fileName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphGetNameFileObject failed: %!STATUS!\",\n                      status);\n\n        freeFileName = FALSE;\n        fileName = FullImageName;\n    }\n\n    KphMsgInit(msg, KphMsgImageLoad);\n\n    msg->Kernel.ImageLoad.LoadingClientId.UniqueProcess = PsGetCurrentProcessId();\n    msg->Kernel.ImageLoad.LoadingClientId.UniqueThread = PsGetCurrentThreadId();\n    msg->Kernel.ImageLoad.LoadingProcessStartKey = KphGetCurrentProcessStartKey();\n    msg->Kernel.ImageLoad.LoadingThreadSubProcessTag = KphGetCurrentThreadSubProcessTag();\n    msg->Kernel.ImageLoad.TargetProcessId = ProcessId;\n    msg->Kernel.ImageLoad.Properties = ImageInfo->ImageInfo.Properties;\n    msg->Kernel.ImageLoad.ImageBase = ImageInfo->ImageInfo.ImageBase;\n    msg->Kernel.ImageLoad.ImageSelector = ImageInfo->ImageInfo.ImageSelector;\n    msg->Kernel.ImageLoad.ImageSectionNumber = ImageInfo->ImageInfo.ImageSectionNumber;\n    msg->Kernel.ImageLoad.FileObject = ImageInfo->FileObject;\n\n    if (targetProcess)\n    {\n        ULONG64 startKey;\n\n        startKey = KphGetProcessStartKey(targetProcess->EProcess);\n\n        msg->Kernel.ImageLoad.TargetProcessStartKey = startKey;\n    }\n\n    if (fileName)\n    {\n        status = KphMsgDynAddUnicodeString(msg, KphMsgFieldFileName, fileName);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                          status);\n        }\n\n        if (freeFileName)\n        {\n            KphFreeNameFileObject(fileName);\n        }\n    }\n\n    if (KphInformerOpts2(actorProcess, targetProcess).EnableStackTraces)\n    {\n        KphCaptureStackInMessage(msg);\n    }\n\n    KphCommsSendMessageAsync(msg);\n\nExit:\n\n    if (targetProcess)\n    {\n        KphDereferenceObject(targetProcess);\n    }\n\n    if (actorProcess)\n    {\n        KphDereferenceObject(actorProcess);\n    }\n}\n\n/**\n * \\brief Image load notify routine.\n *\n * \\param[in] FullImageName File name of the loading image.\n * \\param[in] ProcessId Process ID where the image is being loaded.\n * \\param[in] ImageInfo Information about the image being loaded.\n */\n_Function_class_(PLOAD_IMAGE_NOTIFY_ROUTINE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpLoadImageNotifyRoutine(\n    _In_opt_ PUNICODE_STRING FullImageName,\n    _In_ HANDLE ProcessId,\n    _In_ PIMAGE_INFO ImageInfo\n    )\n{\n    PKPH_PROCESS_CONTEXT process;\n    PIMAGE_INFO_EX imageInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(FullImageName);\n    NT_ASSERT(ImageInfo->ExtendedInfoPresent);\n\n    imageInfo = CONTAINING_RECORD(ImageInfo, IMAGE_INFO_EX, ImageInfo);\n\n    process = KphGetProcessContext(ProcessId);\n    if (process)\n    {\n        KphpPerformImageTracking(process, imageInfo);\n\n        KphApplyImageProtections(process, imageInfo);\n\n        KphDereferenceObject(process);\n    }\n\n    KphpLoadImageNotifyInformer(FullImageName, ProcessId, imageInfo);\n}\n\n/**\n * \\brief Image verification callback.\n *\n * \\param[in] CallbackContext Unused.\n * \\param[in] ImageType The type of image being verified.\n * \\param[in,out] ImageInformation Information about the image being verified.\n */\n_IRQL_requires_same_\n_Function_class_(SE_IMAGE_VERIFICATION_CALLBACK_FUNCTION)\nVOID\nKphpImageVerificationCallback(\n    _In_opt_ PVOID CallbackContext,\n    _In_ SE_IMAGE_TYPE ImageType,\n    _Inout_ PBDCB_IMAGE_INFORMATION ImageInformation\n    )\n{\n    NTSTATUS status;\n    PKPH_PROCESS_CONTEXT actorProcess;\n    PKPH_MESSAGE msg;\n    KPHM_SIZED_BUFFER buffer;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(CallbackContext);\n\n    actorProcess = KphGetCurrentProcessContext();\n\n    if (!KphInformerEnabled(ImageVerify, actorProcess))\n    {\n        goto Exit;\n    }\n\n    msg = KphAllocateMessage();\n    if (!msg)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate message\");\n        goto Exit;\n    }\n\n    KphMsgInit(msg, KphMsgImageVerify);\n\n    msg->Kernel.ImageVerify.ClientId.UniqueProcess = PsGetCurrentProcessId();\n    msg->Kernel.ImageVerify.ClientId.UniqueThread = PsGetCurrentThreadId();\n    msg->Kernel.ImageVerify.ProcessStartKey = KphGetCurrentProcessStartKey();\n    msg->Kernel.ImageVerify.ThreadSubProcessTag = KphGetCurrentThreadSubProcessTag();\n    msg->Kernel.ImageVerify.ImageType = ImageType;\n    msg->Kernel.ImageVerify.Classification = ImageInformation->Classification;\n    msg->Kernel.ImageVerify.ImageFlags = ImageInformation->ImageFlags;\n    msg->Kernel.ImageVerify.ImageHashAlgorithm = ImageInformation->ImageHashAlgorithm;\n    msg->Kernel.ImageVerify.ThumbprintHashAlgorithm = ImageInformation->ThumbprintHashAlgorithm;\n\n    status = KphMsgDynAddUnicodeString(msg,\n                                       KphMsgFieldFileName,\n                                       &ImageInformation->ImageName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\n    buffer.Buffer = ImageInformation->ImageHash;\n    buffer.Size = (USHORT)ImageInformation->ImageHashLength;\n\n    status = KphMsgDynAddSizedBuffer(msg, KphMsgFieldHash, &buffer);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddSizedBuffer failed: %!STATUS!\",\n                      status);\n    }\n\n    status = KphMsgDynAddUnicodeString(msg,\n                                       KphMsgFieldCertificatePublisher,\n                                       &ImageInformation->CertificatePublisher);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\n    status = KphMsgDynAddUnicodeString(msg,\n                                       KphMsgFieldCertificateIssuer,\n                                       &ImageInformation->CertificateIssuer);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\n    buffer.Buffer = ImageInformation->CertificateThumbprint;\n    buffer.Size = (USHORT)ImageInformation->CertificateThumbprintLength;\n\n    status = KphMsgDynAddSizedBuffer(msg,\n                                     KphMsgFieldCertificateThumbprint,\n                                     &buffer);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddSizedBuffer failed: %!STATUS!\",\n                      status);\n    }\n\n    status = KphMsgDynAddUnicodeString(msg,\n                                       KphMsgFieldRegistryPath,\n                                       &ImageInformation->RegistryPath);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\n    if (KphInformerOpts(actorProcess).EnableStackTraces)\n    {\n        KphCaptureStackInMessage(msg);\n    }\n\n    KphCommsSendMessageAsync(msg);\n\nExit:\n\n    if (actorProcess)\n    {\n        KphDereferenceObject(actorProcess);\n    }\n}\n\n/**\n * \\brief Starts the image informer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphImageInformerStart(\n    VOID\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (KphDynPsSetLoadImageNotifyRoutineEx)\n    {\n        status = KphDynPsSetLoadImageNotifyRoutineEx(\n                                      KphpLoadImageNotifyRoutine,\n                                      PS_IMAGE_NOTIFY_CONFLICTING_ARCHITECTURE);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to register image notify routine: %!STATUS!\",\n                          status);\n\n            return status;\n        }\n    }\n    else\n    {\n        status = PsSetLoadImageNotifyRoutine(KphpLoadImageNotifyRoutine);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to register image notify routine: %!STATUS!\",\n                          status);\n\n            return status;\n        }\n    }\n\n    if (!KphSeRegisterImageVerificationCallback ||\n        !KphSeUnregisterImageVerificationCallback)\n    {\n        return STATUS_SUCCESS;\n    }\n\n    status = KphSeRegisterImageVerificationCallback(\n                                       SeImageTypeDriver,\n                                       SeImageVerificationCallbackInformational,\n                                       KphpImageVerificationCallback,\n                                       NULL,\n                                       NULL,\n                                       &KphpImageVerificationCallbackHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to register image verification callback: \"\n                      \"%!STATUS!\",\n                      status);\n\n        KphpImageVerificationCallbackHandle = NULL;\n        return status;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Stops the image informer.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphImageInformerStop(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (KphpImageVerificationCallbackHandle)\n    {\n        NT_ASSERT(KphSeUnregisterImageVerificationCallback);\n\n        KphSeUnregisterImageVerificationCallback(KphpImageVerificationCallbackHandle);\n    }\n\n    PsRemoveLoadImageNotifyRoutine(KphpLoadImageNotifyRoutine);\n}\n"
  },
  {
    "path": "KSystemInformer/informer_object.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <informer.h>\n#include <comms.h>\n#include <kphmsgdyn.h>\n\n#include <trace.h>\n\ntypedef union _KPH_OB_OPTIONS\n{\n    UCHAR Flags;\n    struct\n    {\n        UCHAR PreEnabled : 1;\n        UCHAR PostEnabled : 1;\n        UCHAR EnableStackTraces : 1;\n        UCHAR Spare : 5;\n    };\n} KPH_OB_OPTIONS, *PKPH_OB_OPTIONS;\n\ntypedef struct _KPH_OB_CALL_CONTEXT\n{\n    ULONG64 PreSequence;\n    LARGE_INTEGER PreTimeStamp;\n    KPH_OB_OPTIONS Options;\n    ACCESS_MASK DesiredAccess;\n    ACCESS_MASK OriginalDesiredAccess;\n    HANDLE SourceProcessId;\n    HANDLE TargetProcessId;\n} KPH_OB_CALL_CONTEXT, *PKPH_OB_CALL_CONTEXT;\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PVOID KphpObRegistrationHandle = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\nstatic PAGED_LOOKASIDE_LIST KphpObCallContextLookaside = { 0 };\n\nKPH_PAGED_FILE();\n\nstatic ULONG64 KphpObSequence = 0;\n\n/**\n * \\brief Retrieves the object operation options.\n *\n * \\param[in] Info Object manager pre-operation callback information.\n *\n * \\return The object operation options.\n */\n_IRQL_requires_max_(APC_LEVEL)\nKPH_OB_OPTIONS KphpObGetOptions(\n    _In_ POB_PRE_OPERATION_INFORMATION Info\n    )\n{\n    KPH_OB_OPTIONS options;\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_PAGED_CODE();\n\n    options.Flags = 0;\n\n    if (Info->KernelHandle)\n    {\n        process = KphGetSystemProcessContext();\n    }\n    else\n    {\n        process = KphGetCurrentProcessContext();\n    }\n\n#define KPH_OB_SETTING(name)                                                   \\\n    if (KphInformerEnabled(HandlePre##name, process))                          \\\n    {                                                                          \\\n        options.PreEnabled = TRUE;                                             \\\n    }                                                                          \\\n    if (KphInformerEnabled(HandlePost##name, process))                         \\\n    {                                                                          \\\n        options.PostEnabled = TRUE;                                            \\\n    }\n\n    if (Info->Operation == OB_OPERATION_HANDLE_CREATE)\n    {\n        if (Info->ObjectType == *PsProcessType)\n        {\n            KPH_OB_SETTING(CreateProcess);\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            KPH_OB_SETTING(CreateThread);\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n\n            KPH_OB_SETTING(CreateDesktop);\n        }\n    }\n    else\n    {\n        if (Info->ObjectType == *PsProcessType)\n        {\n            KPH_OB_SETTING(DuplicateProcess);\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            KPH_OB_SETTING(DuplicateThread);\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n\n            KPH_OB_SETTING(DuplicateDesktop);\n        }\n    }\n\n    if (options.PreEnabled || options.PostEnabled)\n    {\n        options.EnableStackTraces = !!KphInformerOpts(process).EnableStackTraces;\n    }\n\n    if (process)\n    {\n        KphDereferenceObject(process);\n    }\n\n    return options;\n}\n\n/**\n * \\brief Retrieves the message ID for the object pre-operation callback.\n *\n * \\param[in] Info Object manager pre-operation callback information.\n *\n * \\return The message ID for the callback.\n */\n_IRQL_requires_max_(APC_LEVEL)\nKPH_MESSAGE_ID KphpObPreGetMessageId(\n    _In_ POB_PRE_OPERATION_INFORMATION Info\n    )\n{\n    KPH_MESSAGE_ID messageId;\n\n    KPH_PAGED_CODE();\n\n    if (Info->Operation == OB_OPERATION_HANDLE_CREATE)\n    {\n        if (Info->ObjectType == *PsProcessType)\n        {\n            messageId = KphMsgHandlePreCreateProcess;\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            messageId = KphMsgHandlePreCreateThread;\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n\n            messageId = KphMsgHandlePreCreateDesktop;\n        }\n    }\n    else\n    {\n        NT_ASSERT(Info->Operation == OB_OPERATION_HANDLE_DUPLICATE);\n\n        if (Info->ObjectType == *PsProcessType)\n        {\n            messageId = KphMsgHandlePreDuplicateProcess;\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            messageId = KphMsgHandlePreDuplicateThread;\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n\n            messageId = KphMsgHandlePreDuplicateDesktop;\n        }\n    }\n\n    return messageId;\n}\n\n/**\n * \\brief Retrieves the message ID for the object post-operation callback.\n *\n * \\param[in] Info Object manager post-operation callback information.\n *\n * \\return The message ID for the callback.\n */\n_IRQL_requires_max_(APC_LEVEL)\nKPH_MESSAGE_ID KphpObPostGetMessageId(\n    _In_ POB_POST_OPERATION_INFORMATION Info\n    )\n{\n    KPH_MESSAGE_ID messageId;\n\n    KPH_PAGED_CODE();\n\n    if (Info->Operation == OB_OPERATION_HANDLE_CREATE)\n    {\n        if (Info->ObjectType == *PsProcessType)\n        {\n            messageId = KphMsgHandlePostCreateProcess;\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            messageId = KphMsgHandlePostCreateThread;\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n\n            messageId = KphMsgHandlePostCreateDesktop;\n        }\n    }\n    else\n    {\n        NT_ASSERT(Info->Operation == OB_OPERATION_HANDLE_DUPLICATE);\n\n        if (Info->ObjectType == *PsProcessType)\n        {\n            messageId = KphMsgHandlePostDuplicateProcess;\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            messageId = KphMsgHandlePostDuplicateThread;\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n\n            messageId = KphMsgHandlePostDuplicateDesktop;\n        }\n    }\n\n    return messageId;\n}\n\n/**\n * \\brief Copies the object name into a message for registered object callbacks.\n *\n * \\details Used to populate the desktop name for desktop object callbacks.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] Object The object for which the name is populated in the message.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpObCopyObjectName(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PVOID Object\n    )\n{\n    NTSTATUS status;\n    POBJECT_NAME_INFORMATION info;\n    ULONG length;\n\n    KPH_PAGED_CODE();\n\n    info = NULL;\n\n    status = ObQueryNameString(Object, NULL, 0, &length);\n    if ((status != STATUS_INFO_LENGTH_MISMATCH) &&\n        (status != STATUS_BUFFER_TOO_SMALL))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ObQueryNameString: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    info = KphAllocatePaged(length, KPH_TAG_OB_OBJECT_NAME);\n    if (!info)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate buffer for object name\");\n\n        goto Exit;\n    }\n\n    status = ObQueryNameString(Object, info, length, &length);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ObQueryNameString failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = KphMsgDynAddUnicodeString(Message,\n                                       KphMsgFieldObjectName,\n                                       &info->Name);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\nExit:\n\n    if (info)\n    {\n        KphFree(info, KPH_TAG_OB_OBJECT_NAME);\n    }\n}\n\n/**\n * \\brief Fills the object pre-operation callback message.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] Info Object manager pre-operation callback information.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpObPreFillMessage(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ POB_PRE_OPERATION_INFORMATION Info\n    )\n{\n    KPH_PAGED_CODE();\n\n    Message->Kernel.Handle.ContextClientId.UniqueProcess = PsGetCurrentProcessId();\n    Message->Kernel.Handle.ContextClientId.UniqueThread = PsGetCurrentThreadId();\n    Message->Kernel.Handle.ContextProcessStartKey = KphGetCurrentProcessStartKey();\n    Message->Kernel.Handle.Flags = Info->Flags;\n    Message->Kernel.Handle.Object = Info->Object;\n\n    if (Info->Operation == OB_OPERATION_HANDLE_CREATE)\n    {\n        POB_PRE_CREATE_HANDLE_INFORMATION params;\n\n        params = &Info->Parameters->CreateHandleInformation;\n\n        Message->Kernel.Handle.Pre.DesiredAccess = params->DesiredAccess;\n        Message->Kernel.Handle.Pre.OriginalDesiredAccess = params->OriginalDesiredAccess;\n\n        if (Info->ObjectType == *PsProcessType)\n        {\n            Message->Kernel.Handle.Pre.Create.Process.ProcessId =\n                PsGetProcessId(Info->Object);\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            Message->Kernel.Handle.Pre.Create.Thread.ClientId.UniqueProcess =\n                PsGetProcessId(PsGetThreadProcess(Info->Object));\n\n            Message->Kernel.Handle.Pre.Create.Thread.ClientId.UniqueThread =\n                PsGetThreadId(Info->Object);\n\n            Message->Kernel.Handle.Pre.Create.Thread.SubProcessTag =\n                KphGetThreadSubProcessTag(Info->Object);\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n            KphpObCopyObjectName(Message, Info->Object);\n        }\n    }\n    else\n    {\n        POB_PRE_DUPLICATE_HANDLE_INFORMATION params;\n\n        NT_ASSERT(Info->Operation == OB_OPERATION_HANDLE_DUPLICATE);\n\n        params = &Info->Parameters->DuplicateHandleInformation;\n\n        Message->Kernel.Handle.Duplicate = TRUE;\n\n        Message->Kernel.Handle.Pre.DesiredAccess = params->DesiredAccess;\n        Message->Kernel.Handle.Pre.OriginalDesiredAccess = params->OriginalDesiredAccess;\n\n        Message->Kernel.Handle.Pre.Duplicate.SourceProcessId = PsGetProcessId(params->SourceProcess);\n        Message->Kernel.Handle.Pre.Duplicate.TargetProcessId = PsGetProcessId(params->TargetProcess);\n\n        if (Info->ObjectType == *PsProcessType)\n        {\n            Message->Kernel.Handle.Pre.Duplicate.Process.ProcessId =\n                PsGetProcessId(Info->Object);\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            Message->Kernel.Handle.Pre.Duplicate.Thread.ClientId.UniqueProcess =\n                PsGetProcessId(PsGetThreadProcess(Info->Object));\n\n            Message->Kernel.Handle.Pre.Duplicate.Thread.ClientId.UniqueThread =\n                PsGetThreadId(Info->Object);\n\n            Message->Kernel.Handle.Pre.Duplicate.Thread.SubProcessTag =\n                KphGetThreadSubProcessTag(Info->Object);\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n            KphpObCopyObjectName(Message, Info->Object);\n        }\n    }\n}\n\n/**\n * \\brief Fills the object post-operation callback message.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] Info Object manager post-operation callback information.\n * \\param[in] Context The object call context.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpObPostFillMessage(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ POB_POST_OPERATION_INFORMATION Info,\n    _In_ PKPH_OB_CALL_CONTEXT Context\n    )\n{\n    KPH_PAGED_CODE();\n\n    Message->Kernel.Handle.ContextClientId.UniqueProcess = PsGetCurrentProcessId();\n    Message->Kernel.Handle.ContextClientId.UniqueThread = PsGetCurrentThreadId();\n    Message->Kernel.Handle.ContextProcessStartKey = KphGetCurrentProcessStartKey();\n    Message->Kernel.Handle.ContextThreadSubProcessTag = KphGetCurrentThreadSubProcessTag();\n    Message->Kernel.Handle.Flags = Info->Flags;\n    Message->Kernel.Handle.Object = Info->Object;\n\n    Message->Kernel.Handle.PostOperation = TRUE;\n    Message->Kernel.Handle.Post.PreSequence = Context->PreSequence;\n    Message->Kernel.Handle.Post.PreTimeStamp = Context->PreTimeStamp;\n    Message->Kernel.Handle.Post.ReturnStatus = Info->ReturnStatus;\n    Message->Kernel.Handle.Post.DesiredAccess = Context->DesiredAccess;\n    Message->Kernel.Handle.Post.OriginalDesiredAccess = Context->OriginalDesiredAccess;\n\n    if (Info->Operation == OB_OPERATION_HANDLE_CREATE)\n    {\n        POB_POST_CREATE_HANDLE_INFORMATION params;\n\n        params = &Info->Parameters->CreateHandleInformation;\n\n        Message->Kernel.Handle.Post.GrantedAccess = params->GrantedAccess;\n\n        if (Info->ObjectType == *PsProcessType)\n        {\n            Message->Kernel.Handle.Post.Create.Process.ProcessId =\n                PsGetProcessId(Info->Object);\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            Message->Kernel.Handle.Post.Create.Thread.ClientId.UniqueProcess =\n                PsGetProcessId(PsGetThreadProcess(Info->Object));\n\n            Message->Kernel.Handle.Post.Create.Thread.ClientId.UniqueThread =\n                PsGetThreadId(Info->Object);\n\n            Message->Kernel.Handle.Post.Create.Thread.SubProcessTag =\n                KphGetThreadSubProcessTag(Info->Object);\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n            KphpObCopyObjectName(Message, Info->Object);\n        }\n    }\n    else\n    {\n        POB_POST_DUPLICATE_HANDLE_INFORMATION params;\n\n        NT_ASSERT(Info->Operation == OB_OPERATION_HANDLE_DUPLICATE);\n\n        params = &Info->Parameters->DuplicateHandleInformation;\n\n        Message->Kernel.Handle.Duplicate = TRUE;\n\n        Message->Kernel.Handle.Post.GrantedAccess = params->GrantedAccess;\n\n        Message->Kernel.Handle.Post.Duplicate.SourceProcessId = Context->SourceProcessId;\n        Message->Kernel.Handle.Post.Duplicate.TargetProcessId = Context->TargetProcessId;\n\n        if (Info->ObjectType == *PsProcessType)\n        {\n            Message->Kernel.Handle.Post.Duplicate.Process.ProcessId =\n                PsGetProcessId(Info->Object);\n        }\n        else if (Info->ObjectType == *PsThreadType)\n        {\n            Message->Kernel.Handle.Post.Duplicate.Thread.ClientId.UniqueProcess =\n                PsGetProcessId(PsGetThreadProcess(Info->Object));\n\n            Message->Kernel.Handle.Post.Duplicate.Thread.ClientId.UniqueThread =\n                PsGetThreadId(Info->Object);\n\n            Message->Kernel.Handle.Post.Duplicate.Thread.SubProcessTag =\n                KphGetThreadSubProcessTag(Info->Object);\n        }\n        else\n        {\n            NT_ASSERT(Info->ObjectType == *ExDesktopObjectType);\n            KphpObCopyObjectName(Message, Info->Object);\n        }\n    }\n}\n\n/**\n * \\brief Sends an object post-operation callback message.\n *\n * \\param[in] Info Object manager post-operation callback information.\n * \\param[in] Sequence The sequence number for the message.\n * \\param[in] Context The object call context.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpObPostOpSend(\n    _In_ POB_POST_OPERATION_INFORMATION Info,\n    _In_ ULONG64 Sequence,\n    _In_ PKPH_OB_CALL_CONTEXT Context\n    )\n{\n    PKPH_MESSAGE msg;\n\n    KPH_PAGED_CODE();\n\n    msg = KphAllocateMessage();\n    if (!msg)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate message\");\n\n        return;\n    }\n\n    KphMsgInit(msg, KphpObPostGetMessageId(Info));\n\n    msg->Kernel.Handle.Sequence = Sequence;\n\n    KphpObPostFillMessage(msg, Info, Context);\n\n    if (Context->Options.EnableStackTraces)\n    {\n        KphCaptureStackInMessage(msg);\n    }\n\n    KphCommsSendMessageAsync(msg);\n}\n\n/**\n * \\brief Object manager post-operation callback.\n *\n * \\param[in] Context Not used.\n * \\param[in] Info The object post-operation information.\n */\n_Function_class_(POB_POST_OPERATION_CALLBACK)\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpObPostOp(\n    _In_ PVOID Context,\n    _In_ POB_POST_OPERATION_INFORMATION Info\n    )\n{\n    PKPH_OB_CALL_CONTEXT context;\n    ULONG64 sequence;\n\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(Context);\n\n    sequence = InterlockedIncrementU64(&KphpObSequence);\n\n    context = Info->CallContext;\n    if (context)\n    {\n        KphpObPostOpSend(Info, sequence, context);\n\n        KphFreeToPagedLookaside(&KphpObCallContextLookaside, context);\n    }\n}\n\n/**\n * \\brief Sets the object callback call context for the post-operation to use.\n *\n * \\param[in] Info Object manager pre-operation callback information.\n * \\param[in] Options Object operation options to use.\n * \\param[in] Sequence The pre-operation sequence number.\n * \\param[in] TimeStamp The pre-operation time stamp.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpObPreOpSetCallContext(\n    _In_ POB_PRE_OPERATION_INFORMATION Info,\n    _In_ PKPH_OB_OPTIONS Options,\n    _In_ ULONG64 Sequence,\n    _In_ PLARGE_INTEGER TimeStamp\n    )\n{\n    PKPH_OB_CALL_CONTEXT context;\n\n    KPH_PAGED_CODE();\n\n    context = KphAllocateFromPagedLookaside(&KphpObCallContextLookaside);\n    if (!context)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate call context\");\n\n        return;\n    }\n\n    context->PreSequence = Sequence;\n    context->PreTimeStamp = *TimeStamp;\n    context->Options.Flags = Options->Flags;\n\n    if (Info->Operation == OB_OPERATION_HANDLE_CREATE)\n    {\n        POB_PRE_CREATE_HANDLE_INFORMATION params;\n\n        params = &Info->Parameters->CreateHandleInformation;\n\n        context->DesiredAccess = params->DesiredAccess;\n        context->OriginalDesiredAccess = params->OriginalDesiredAccess;\n    }\n    else\n    {\n        POB_PRE_DUPLICATE_HANDLE_INFORMATION params;\n\n        NT_ASSERT(Info->Operation == OB_OPERATION_HANDLE_DUPLICATE);\n\n        params = &Info->Parameters->DuplicateHandleInformation;\n\n        context->DesiredAccess = params->DesiredAccess;\n        context->OriginalDesiredAccess = params->OriginalDesiredAccess;\n        context->SourceProcessId = PsGetProcessId(params->SourceProcess);\n        context->TargetProcessId = PsGetProcessId(params->TargetProcess);\n    }\n\n    Info->CallContext = context;\n}\n\n/**\n * \\brief Sends an object pre-operation callback message.\n *\n * \\param[in] Info Object manager pre-operation callback information.\n * \\param[in] Options Object operation options to use.\n * \\param[in] Sequence The sequence number for the message.\n * \\param[out] TimeStamp Receives the time stamp of the pre-operation message.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpObPreOpSend(\n    _In_ POB_PRE_OPERATION_INFORMATION Info,\n    _In_ PKPH_OB_OPTIONS Options,\n    _In_ ULONG64 Sequence,\n    _Out_ PLARGE_INTEGER TimeStamp\n    )\n{\n    PKPH_MESSAGE msg;\n\n    KPH_PAGED_CODE();\n\n    msg = KphAllocateMessage();\n    if (!msg)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate message\");\n\n        KeQuerySystemTime(TimeStamp);\n        return;\n    }\n\n    KphMsgInit(msg, KphpObPreGetMessageId(Info));\n\n    *TimeStamp = msg->Header.TimeStamp;\n\n    msg->Kernel.Handle.Sequence = Sequence;\n\n    KphpObPreFillMessage(msg, Info);\n\n    if (Options->EnableStackTraces)\n    {\n        KphCaptureStackInMessage(msg);\n    }\n\n    KphCommsSendMessageAsync(msg);\n}\n\n/**\n * \\brief Performs process tracking in object manager callbacks.\n *\n * \\param[in] ProcessObject The process object to track.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpObPerformProcessTracking(\n    _In_ PEPROCESS ProcessObject\n    )\n{\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    process = KphGetEProcessContext(ProcessObject);\n    if (process)\n    {\n        if (process->CreateNotification || process->NumberOfThreads)\n        {\n            //\n            // Let the process notification routine handle this process.\n            //\n            // N.B. We check CreateNotification and NumberOfThreads because we\n            // may have loaded too late to observe the original create\n            // notification. This avoids unnecessarily entering the logic below.\n            //\n            goto Exit;\n        }\n\n        //\n        // N.B. If a process is created and terminated without ever having a\n        // thread, the registered process notifications will not be called.\n        //\n        // In this case, indicators such as ExitTime, ExitStatus, and\n        // ProcessExiting will not be updated. However, the process exit\n        // synchronization (rundown) will be activated when the process\n        // terminates.\n        //\n        if (NT_SUCCESS(PsAcquireProcessExitSynchronization(ProcessObject)))\n        {\n            PsReleaseProcessExitSynchronization(ProcessObject);\n            goto Exit;\n        }\n\n        KphDereferenceObject(process);\n\n        process = KphUntrackProcessContext(PsGetProcessId(ProcessObject));\n        if (process)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          TRACKING,\n                          \"Stopped tracking process %wZ (%lu)\",\n                          &process->ImageName,\n                          HandleToULong(process->ProcessId));\n        }\n\n        goto Exit;\n    }\n\n    if (PsGetProcessExitProcessCalled(ProcessObject))\n    {\n        //\n        // Do not begin tracking the process if it has already exited.\n        //\n        goto Exit;\n    }\n\n    process = KphTrackProcessContext(ProcessObject);\n    if (process)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Tracking process %wZ (%lu)\",\n                      &process->ImageName,\n                      HandleToULong(process->ProcessId));\n\n        KphVerifyProcessAndProtectIfAppropriate(process);\n    }\n    else\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Failed to track process %lu\",\n                      HandleToULong(PsGetProcessId(ProcessObject)));\n    }\n\nExit:\n\n    if (process)\n    {\n        KphDereferenceObject(process);\n    }\n}\n\n/**\n * \\brief Performs thread tracking in object manager callbacks.\n *\n * \\param[in] ThreadObject The thread object to track.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpObPerformThreadTracking(\n    _In_ PETHREAD ThreadObject\n    )\n{\n    PKPH_THREAD_CONTEXT thread;\n\n    //\n    // N.B. Although Microsoft's documentation states that object callbacks\n    // are invoked at PASSIVE_LEVEL, they can and *do* get invoked at APC_LEVEL\n    // in practice.\n    //\n    // This is because thread creation can happen at APC_LEVEL and thread\n    // creation will open a handle to the thread object, which in turn invokes\n    // the object manager callbacks. This behavior has been observed and is\n    // triggered by Microsoft's own kernel components - no third-party drivers.\n    // As such, assuming callbacks always run at PASSIVE_LEVEL is unsafe. This\n    // contradicts the stated IRQL guarantees - use caution.\n    //\n    // For reference, see the documentation for PCREATE_THREAD_NOTIFY_ROUTINE.\n    // Note that although PsCreateSystemThread being documented as requiring\n    // PASSIVE_LEVEL, it can and *does* get invoked at APC_LEVEL in practice.\n    //\n    KPH_PAGED_CODE();\n\n    thread = KphGetEThreadContext(ThreadObject);\n    if (thread)\n    {\n        //\n        // Let the thread notification routine handle any exiting threads.\n        //\n        goto Exit;\n    }\n\n    if (PsIsThreadTerminating(ThreadObject))\n    {\n        //\n        // Do not begin tracking the thread if it is terminating.\n        //\n        goto Exit;\n    }\n\n    thread = KphTrackThreadContext(ThreadObject);\n    if (thread)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Tracking thread %lu in process %wZ (%lu)\",\n                      HandleToULong(thread->ClientId.UniqueThread),\n                      KphGetThreadImageName(thread),\n                      HandleToULong(thread->ClientId.UniqueProcess));\n    }\n    else\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Failed to track thread %lu in process %lu\",\n                      HandleToULong(PsGetThreadId(ThreadObject)),\n                      HandleToULong(PsGetThreadProcessId(ThreadObject)));\n    }\n\nExit:\n\n    if (thread)\n    {\n        KphDereferenceObject(thread);\n    }\n}\n\n/**\n * \\brief Performs process and thread tracking in object manager callbacks.\n *\n * \\param[in] Info Object manager pre-operation callback information.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpObPerformProcessAndThreadTracking(\n    _In_ POB_PRE_OPERATION_INFORMATION Info\n    )\n{\n    KIRQL currentIrql;\n\n    KPH_PAGED_CODE();\n\n    //\n    // During the object pre-operation callback, supplement process and thread\n    // tracking that is normally performed in the process and thread\n    // notification routines.\n    //\n    // The process notification routines are called when the initial thread is\n    // inserted into a process. However, a process can exist before those\n    // routines are invoked. If no thread is ever created in the process, it\n    // may exist without triggering any notification callbacks. When a handle is\n    // created for such a process (either during creation or by being opened\n    // from another process), we take this opportunity to perform tracking.\n    //\n    // We also use this point to sanity check that other contexts exist.\n    // If one doesn’t, it may be due to earlier resource constraints.\n    //\n    // N.B. If another driver has registered a process or thread notification\n    // routine before ours, it can cause us to land here before our own routines\n    // are called. Our tracking handles this scenario gracefully. This typically\n    // happens with security products that invoke user-mode code during process\n    // creation, and their user-mode component opens the process.\n    //\n\n    if (Info->KernelHandle)\n    {\n        //\n        // N.B. This prevents our own tracking routines from becoming reentrant.\n        // Our tracking routines always open a kernel handle.\n        //\n        return;\n    }\n\n    //\n    // N.B. Thread creation routines can be invoked at APC_LEVEL, which in turn\n    // causes the object manager's pre-operation callbacks to be invoked. Our\n    // thread tracking supports being called at APC_LEVEL, but process tracking\n    // requires PASSIVE_LEVEL. Therefore, we check the current IRQL below before\n    // attempting any process tracking.\n    //\n    currentIrql = KeGetCurrentIrql();\n\n    if (currentIrql == PASSIVE_LEVEL)\n    {\n        KphpObPerformProcessTracking(PsGetCurrentProcess());\n    }\n\n    KphpObPerformThreadTracking(PsGetCurrentThread());\n\n    if (Info->ObjectType == *PsProcessType)\n    {\n        if (currentIrql == PASSIVE_LEVEL)\n        {\n            KphpObPerformProcessTracking(Info->Object);\n        }\n    }\n    else if (Info->ObjectType == *PsThreadType)\n    {\n        if (currentIrql == PASSIVE_LEVEL)\n        {\n            KphpObPerformProcessTracking(PsGetThreadProcess(Info->Object));\n        }\n\n        KphpObPerformThreadTracking(Info->Object);\n    }\n}\n\n/**\n * \\brief Object manager pre-operation callback.\n *\n * \\param[in] Context Not used.\n * \\param[in,out] Info The object pre-operation information.\n *\n * \\return OB_PREOP_SUCCESS\n */\n_Function_class_(POB_PRE_OPERATION_CALLBACK)\n_IRQL_requires_max_(APC_LEVEL)\nOB_PREOP_CALLBACK_STATUS KphpObPreOp(\n    _In_ PVOID Context,\n    _Inout_ POB_PRE_OPERATION_INFORMATION Info\n    )\n{\n    KPH_OB_OPTIONS options;\n    ULONG64 sequence;\n    LARGE_INTEGER timeStamp;\n\n    //\n    // N.B. Although Microsoft's documentation states that object callbacks\n    // are invoked at PASSIVE_LEVEL, they can and *do* get invoked at APC_LEVEL\n    // in practice.\n    //\n    // This is because thread creation can happen at APC_LEVEL and thread\n    // creation will open a handle to the thread object, which in turn invokes\n    // the object manager callbacks. This behavior has been observed and is\n    // triggered by Microsoft's own kernel components - no third-party drivers.\n    // As such, assuming callbacks always run at PASSIVE_LEVEL is unsafe. This\n    // contradicts the stated IRQL guarantees - use caution.\n    //\n    // For reference, see the documentation for PCREATE_THREAD_NOTIFY_ROUTINE.\n    // Note that although PsCreateSystemThread being documented as requiring\n    // PASSIVE_LEVEL, it can and *does* get invoked at APC_LEVEL in practice.\n    //\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(Context);\n\n    KphpObPerformProcessAndThreadTracking(Info);\n\n    KphApplyObProtections(Info);\n\n    sequence = InterlockedIncrementU64(&KphpObSequence);\n\n    options = KphpObGetOptions(Info);\n\n    if (options.PreEnabled)\n    {\n        KphpObPreOpSend(Info, &options, sequence, &timeStamp);\n    }\n    else\n    {\n        //\n        // Pre operations aren't enabled, but we need the time stamp for the\n        // post operation to use.\n        //\n        KeQuerySystemTime(&timeStamp);\n    }\n\n    if (options.PostEnabled)\n    {\n        KphpObPreOpSetCallContext(Info, &options, sequence, &timeStamp);\n    }\n\n    return OB_PREOP_SUCCESS;\n}\n\n/**\n * \\brief Starts the object informer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphObjectInformerStart(\n    VOID\n    )\n{\n    NTSTATUS status;\n    OB_CALLBACK_REGISTRATION callbackRegistration;\n    OB_OPERATION_REGISTRATION operationRegistration[3];\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KphAltitude);\n\n    RtlZeroMemory(operationRegistration, sizeof(operationRegistration));\n\n    operationRegistration[0].ObjectType = PsProcessType;\n    operationRegistration[0].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;\n    operationRegistration[0].PreOperation = KphpObPreOp;\n    operationRegistration[0].PostOperation = KphpObPostOp;\n\n    operationRegistration[1].ObjectType = PsThreadType;\n    operationRegistration[1].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;\n    operationRegistration[1].PreOperation = KphpObPreOp;\n    operationRegistration[1].PostOperation = KphpObPostOp;\n\n    operationRegistration[2].ObjectType = ExDesktopObjectType;\n    operationRegistration[2].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;\n    operationRegistration[2].PreOperation = KphpObPreOp;\n    operationRegistration[2].PostOperation = KphpObPostOp;\n\n    callbackRegistration.Version = OB_FLT_REGISTRATION_VERSION;\n    callbackRegistration.OperationRegistrationCount = ARRAYSIZE(operationRegistration);\n    callbackRegistration.Altitude.Buffer = KphAltitude->Buffer;\n    callbackRegistration.Altitude.Length = KphAltitude->Length;\n    callbackRegistration.Altitude.MaximumLength = KphAltitude->MaximumLength;\n    callbackRegistration.RegistrationContext = NULL;\n    callbackRegistration.OperationRegistration = operationRegistration;\n\n    KphInitializePagedLookaside(&KphpObCallContextLookaside,\n                                sizeof(KPH_OB_CALL_CONTEXT),\n                                KPH_TAG_OB_CALL_CONTEXT);\n\n    status = ObRegisterCallbacks(&callbackRegistration,\n                                 &KphpObRegistrationHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ObRegisterCallbacks failed: %!STATUS!\",\n                      status);\n\n        KphDeletePagedLookaside(&KphpObCallContextLookaside);\n        KphpObRegistrationHandle = NULL;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Stops the object informer.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphObjectInformerStop(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (KphpObRegistrationHandle)\n    {\n        ObUnRegisterCallbacks(KphpObRegistrationHandle);\n        KphDeletePagedLookaside(&KphpObCallContextLookaside);\n    }\n}\n"
  },
  {
    "path": "KSystemInformer/informer_process.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <informer.h>\n#include <comms.h>\n#include <kphmsgdyn.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_PROCESS_CREATE_APC\n{\n    KSI_KAPC Apc;\n    PKPH_THREAD_CONTEXT Actor;\n} KPH_PROCESS_CREATE_APC, *PKPH_PROCESS_CREATE_APC;\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_NPAGED_LOOKASIDE_OBJECT KphpProcesCreateApcLookaside = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Allocates the process create APC which is used to track when a thread\n * is actively in the kernel creating a process.\n *\n * \\return Pointer to allocates process create APC, null on failure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Return_allocatesMem_\nPKPH_PROCESS_CREATE_APC KphpAllocateProcessCreateApc(\n    VOID\n    )\n{\n    PKPH_PROCESS_CREATE_APC apc;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KphpProcesCreateApcLookaside);\n\n    apc = KphAllocateFromNPagedLookasideObject(KphpProcesCreateApcLookaside);\n    if (apc)\n    {\n        KphReferenceObject(KphpProcesCreateApcLookaside);\n    }\n\n    return apc;\n}\n\n/**\n * \\brief Frees a previously allocated process create APC.\n *\n * \\param[in] Apc The process create APC to free.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpFreeProcessCreateApc(\n    _In_freesMem_ PKPH_PROCESS_CREATE_APC Apc\n    )\n{\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(KphpProcesCreateApcLookaside);\n\n    KphDereferenceObject(Apc->Actor);\n    KphFreeToNPagedLookasideObject(KphpProcesCreateApcLookaside, Apc);\n    KphDereferenceObject(KphpProcesCreateApcLookaside);\n}\n\n/**\n * \\brief Performing process tracking.\n *\n * \\param[in] Process The process object from the notification callback.\n * \\param[in] ProcessId Process ID from the notification callback.\n * \\param[in] CreateInfo The create information from the callback.\n *\n * \\return Pointer to the process context, may be null, the caller should\n * dereference this object if it is non-null.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nPKPH_PROCESS_CONTEXT KphpPerformProcessTracking(\n    _Inout_ PEPROCESS Process,\n    _In_ HANDLE ProcessId,\n    _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo\n    )\n{\n    PKPH_PROCESS_CONTEXT process;\n    PKPH_PROCESS_CONTEXT creatorProcess;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    creatorProcess = NULL;\n\n    if (!CreateInfo)\n    {\n        process = KphUntrackProcessContext(ProcessId);\n        if (!process)\n        {\n            goto Exit;\n        }\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Stopped tracking process %wZ (%lu)\",\n                      &process->ImageName,\n                      HandleToULong(process->ProcessId));\n\n        process->ExitNotification = TRUE;\n\n        NT_ASSERT(process->NumberOfThreads == 0);\n        NT_ASSERT(IsListEmpty(&process->ThreadListHead));\n\n        goto Exit;\n    }\n\n    NT_ASSERT(CreateInfo);\n\n    process = KphTrackProcessContext(Process);\n    if (!process)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Failed to track process %lu\",\n                      HandleToULong(ProcessId));\n\n        goto Exit;\n    }\n\n    process->CreateNotification = TRUE;\n    process->CreatorClientId.UniqueProcess = PsGetCurrentProcessId();\n    process->CreatorClientId.UniqueThread = PsGetCurrentThreadId();\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  TRACKING,\n                  \"Tracking process %wZ (%lu)\",\n                  &process->ImageName,\n                  HandleToULong(process->ProcessId));\n\n    KphVerifyProcessAndProtectIfAppropriate(process);\n\n    creatorProcess = KphGetCurrentProcessContext();\n    if (!creatorProcess)\n    {\n        goto Exit;\n    }\n\n    if (!KphTestProcessContextState(process, KPH_PROCESS_STATE_HIGH))\n    {\n        goto Exit;\n    }\n\n    if (KphTestProcessContextState(creatorProcess, KPH_PROCESS_STATE_MAXIMUM))\n    {\n        process->SecurelyCreated = TRUE;\n    }\n    else\n    {\n        PS_PROTECTION processProtection;\n\n        processProtection = PsGetProcessProtection(creatorProcess->EProcess);\n\n        if ((processProtection.Type != PsProtectedTypeNone) &&\n            ((processProtection.Signer == PsProtectedSignerWinTcb) ||\n             (processProtection.Signer == PsProtectedSignerWinSystem)))\n        {\n            process->SecurelyCreated = TRUE;\n        }\n    }\n\nExit:\n\n    if (creatorProcess)\n    {\n        KphDereferenceObject(creatorProcess);\n    }\n\n    return process;\n}\n\n/**\n * \\brief Informs any clients of process notify routine invocations.\n *\n * \\param[in,out] Process The process being created.\n * \\param[in,out] CreateInfo Information on the process being created, if the\n * process is being destroyed this is NULL.\n *\n */\n_Function_class_(PCREATE_PROCESS_NOTIFY_ROUTINE_EX)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpCreateProcessNotifyInformer(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n    PKPH_MESSAGE reply;\n    PEPROCESS parentProcess;\n    PKPH_PROCESS_CONTEXT actorProcess;\n    KPH_INFORMER_OPTIONS opts;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    msg = NULL;\n    reply = NULL;\n    parentProcess = NULL;\n    actorProcess = KphGetCurrentProcessContext();\n\n    if (CreateInfo)\n    {\n        if (!KphInformerEnabled(ProcessCreate, actorProcess))\n        {\n            goto Exit;\n        }\n\n        msg = KphAllocateMessage();\n        if (!msg)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to allocate message\");\n            goto Exit;\n        }\n\n        status = PsLookupProcessByProcessId(CreateInfo->ParentProcessId,\n                                            &parentProcess);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"PsLookupProcessByProcessId failed: %!STATUS!\",\n                          status);\n            parentProcess = NULL;\n        }\n\n        KphMsgInit(msg, KphMsgProcessCreate);\n        msg->Kernel.ProcessCreate.CreatingClientId.UniqueProcess = PsGetCurrentProcessId();\n        msg->Kernel.ProcessCreate.CreatingClientId.UniqueThread = PsGetCurrentThreadId();\n        msg->Kernel.ProcessCreate.CreatingProcessStartKey = KphGetCurrentProcessStartKey();\n        msg->Kernel.ProcessCreate.CreatingThreadSubProcessTag = KphGetCurrentThreadSubProcessTag();\n        msg->Kernel.ProcessCreate.TargetProcessId = Process->ProcessId;\n        msg->Kernel.ProcessCreate.TargetProcessStartKey = KphGetProcessStartKey(Process->EProcess);\n        msg->Kernel.ProcessCreate.Flags = CreateInfo->Flags;\n        msg->Kernel.ProcessCreate.FileObject = CreateInfo->FileObject;\n\n        msg->Kernel.ProcessCreate.ParentProcessId = CreateInfo->ParentProcessId;\n        if (parentProcess)\n        {\n            msg->Kernel.ProcessCreate.ParentProcessStartKey = KphGetProcessStartKey(parentProcess);\n        }\n\n        if (Process->ImageFileName)\n        {\n            status = KphMsgDynAddUnicodeString(msg,\n                                               KphMsgFieldFileName,\n                                               Process->ImageFileName);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                              status);\n            }\n        }\n\n        if (CreateInfo->CommandLine)\n        {\n            status = KphMsgDynAddUnicodeString(msg,\n                                               KphMsgFieldCommandLine,\n                                               CreateInfo->CommandLine);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                              status);\n            }\n        }\n\n        opts = KphInformerOpts(actorProcess);\n\n        if (opts.EnableStackTraces)\n        {\n            KphCaptureStackInMessage(msg);\n        }\n\n        if (!opts.EnableProcessCreateReply)\n        {\n            KphCommsSendMessageAsync(msg);\n            msg = NULL;\n\n            goto Exit;\n        }\n\n        reply = KphAllocateMessage();\n        if (!reply)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to allocate message\");\n\n            goto Exit;\n        }\n\n        status = KphCommsSendMessage(msg, reply);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to send message (%lu): %!STATUS!\",\n                          (ULONG)msg->Header.MessageId,\n                          status);\n\n            goto Exit;\n        }\n\n        if ((reply->Header.MessageId == KphMsgProcessCreate) &&\n            (reply->Reply.ProcessCreate.CreationStatus != STATUS_SUCCESS))\n        {\n            CreateInfo->CreationStatus = reply->Reply.ProcessCreate.CreationStatus;\n        }\n    }\n    else\n    {\n        if (!KphInformerEnabled(ProcessExit, actorProcess))\n        {\n            goto Exit;\n        }\n\n        msg = KphAllocateMessage();\n        if (!msg)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to allocate message\");\n            goto Exit;\n        }\n\n        KphMsgInit(msg, KphMsgProcessExit);\n        msg->Kernel.ProcessExit.ClientId.UniqueProcess = PsGetCurrentProcessId();\n        msg->Kernel.ProcessExit.ClientId.UniqueThread = PsGetCurrentThreadId();\n        msg->Kernel.ProcessExit.ProcessStartKey = KphGetProcessStartKey(Process->EProcess);\n        msg->Kernel.ProcessExit.ExitStatus = PsGetProcessExitStatus(Process->EProcess);\n\n        if (KphInformerOpts(actorProcess).EnableStackTraces)\n        {\n            KphCaptureStackInMessage(msg);\n        }\n\n        KphCommsSendMessageAsync(msg);\n        msg = NULL;\n    }\n\nExit:\n\n    if (reply)\n    {\n        KphFreeMessage(reply);\n    }\n\n    if (msg)\n    {\n        KphFreeMessage(msg);\n    }\n\n    if (parentProcess)\n    {\n        ObDereferenceObject(parentProcess);\n    }\n\n    if (actorProcess)\n    {\n        KphDereferenceObject(actorProcess);\n    }\n}\n\n/**\n * \\brief Cleanup routine for the create process APC.\n *\n * \\param[in] Apc The APC to clean up.\n * \\param[in] Reason Unused.\n */\n_Function_class_(KSI_KCLEANUP_ROUTINE)\n_IRQL_requires_min_(PASSIVE_LEVEL)\n_IRQL_requires_max_(APC_LEVEL)\n_IRQL_requires_same_\nVOID\nKSIAPI\nKphpProcessCreateCleanupRoutine(\n    _In_ PKSI_KAPC Apc,\n    _In_ KSI_KAPC_CLEANUP_REASON Reason\n    )\n{\n    PKPH_PROCESS_CREATE_APC apc;\n\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(Reason);\n\n    apc = CONTAINING_RECORD(Apc, KPH_PROCESS_CREATE_APC, Apc);\n\n    KphpFreeProcessCreateApc(apc);\n}\n\n/**\n * \\brief Performs process creation actions at return from system.\n *\n * \\details We use an APC to do state tracking in the current thread context.\n * This enables us to identify when the thread is currently in the kernel\n * creating a process. In this kernel routine we clear state from the acting\n * thread before it returns from the system.\n *\n * \\param[in] Apc The APC that is executing.\n * \\param[in] NormalRoutine Set to NULL to cancel the faked routine.\n * \\param[in,out] NormalContext Unused.\n * \\param[in,out] SystemArgument1 Unused.\n * \\param[in,out] SystemArgument2 Unused.\n */\n_Function_class_(KSI_KKERNEL_ROUTINE)\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpProcessCreateKernelRoutine(\n    _In_ PKSI_KAPC Apc,\n    _Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE* NormalRoutine,\n    _Inout_ _Deref_pre_maybenull_ PVOID* NormalContext,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument1,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2\n    )\n{\n    PKPH_PROCESS_CREATE_APC apc;\n\n    KPH_PAGED_CODE_APC();\n\n    apc = CONTAINING_RECORD(Apc, KPH_PROCESS_CREATE_APC, Apc);\n\n    DBG_UNREFERENCED_PARAMETER(NormalRoutine);\n    NT_ASSERT(apc->Actor->ProcessContext->ApcNoopRoutine);\n    NT_ASSERT(*NormalRoutine == apc->Actor->ProcessContext->ApcNoopRoutine);\n\n    *NormalContext = NULL;\n    *SystemArgument1 = NULL;\n    *SystemArgument2 = NULL;\n\n    NT_ASSERT(apc->Actor->IsCreatingProcess);\n\n    apc->Actor->IsCreatingProcess = FALSE;\n    apc->Actor->IsCreatingProcessId = NULL;\n}\n\n/**\n * \\brief Performs tracking of the actor thread creating a process.\n *\n * \\details We use an APC to do state tracking in the current thread context.\n * This enables us to identify when the thread is currently in the kernel\n * creating a process. This will be cleared when the kernel routine fires\n * before returning from the system.\n *\n * \\param[in] Process The process context of the process being created.\n * \\param[in,out] CreateInfo Information on the process being created, if the\n * process is being destroyed this is NULL.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpPerformProcessCreationTracking(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo\n    )\n{\n    NTSTATUS status;\n    PKPH_THREAD_CONTEXT actor;\n    PKPH_PROCESS_CREATE_APC apc;\n    BOOLEAN stopProtecting;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!CreateInfo)\n    {\n        return;\n    }\n\n    NT_ASSERT(PsGetCurrentProcessId() == CreateInfo->CreatingThreadId.UniqueProcess);\n    NT_ASSERT(PsGetCurrentThreadId() == CreateInfo->CreatingThreadId.UniqueThread);\n\n    if (!KphIsProtectedProcess(Process))\n    {\n        return;\n    }\n\n    //\n    // If we fail here we will stop protecting the process. If protection is\n    // stopped the process will not be given full access to the driver APIs.\n    //\n    stopProtecting = TRUE;\n    apc = NULL;\n\n    actor = KphGetCurrentThreadContext();\n    if (!actor || !actor->ProcessContext)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE, TRACKING, \"Insufficient tracking.\");\n        goto Exit;\n    }\n\n    if (actor->ProcessContext->IsSubsystemProcess)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Skipping for subsystem process.\");\n        goto Exit;\n    }\n\n    status = KphCheckProcessApcNoopRoutine(actor->ProcessContext);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"KphCheckProcessApcNoopRoutine failed: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    apc = KphpAllocateProcessCreateApc();\n    if (!apc)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Failed to allocate create process APC\");\n\n        goto Exit;\n    }\n\n    apc->Actor = actor;\n    actor = NULL;\n\n    apc->Actor->IsCreatingProcess = TRUE;\n    apc->Actor->IsCreatingProcessId = Process->ProcessId;\n\n    KsiInitializeApc(&apc->Apc,\n                     KphDriverObject,\n                     apc->Actor->EThread,\n                     OriginalApcEnvironment,\n                     KphpProcessCreateKernelRoutine,\n                     KphpProcessCreateCleanupRoutine,\n                     apc->Actor->ProcessContext->ApcNoopRoutine,\n                     UserMode,\n                     NULL);\n\n    if (!KsiInsertQueueApc(&apc->Apc, NULL, NULL, IO_NO_INCREMENT))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE, TRACKING, \"KsiInsertQueueApc failed\");\n\n        //\n        // No choice other than to reset the actor state immediately.\n        //\n        apc->Actor->IsCreatingProcess = FALSE;\n        apc->Actor->IsCreatingProcessId = NULL;\n        goto Exit;\n    }\n\n    //\n    // Stage the thread for user mode APC delivery.\n    //\n    KeTestAlertThread(UserMode);\n\n    stopProtecting = FALSE;\n    apc = NULL;\n\nExit:\n\n    if (apc)\n    {\n        KphpFreeProcessCreateApc(apc);\n    }\n\n    if (actor)\n    {\n        KphDereferenceObject(actor);\n    }\n\n    if (stopProtecting)\n    {\n        KphStopProtectingProcess(Process);\n    }\n}\n\n/**\n * \\brief Process create notify routine.\n *\n * \\param[in,out] Process The process object being created.\n * \\param[in] ProcessId ProcessID of the process being created.\n * \\param[in,out] CreateInfo Information on the process being created, if the\n * process is being destroyed this is NULL.\n */\n_Function_class_(PCREATE_PROCESS_NOTIFY_ROUTINE_EX)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpCreateProcessNotifyRoutine(\n    _Inout_ PEPROCESS Process,\n    _In_ HANDLE ProcessId,\n    _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo\n    )\n{\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    process = KphpPerformProcessTracking(Process, ProcessId, CreateInfo);\n    if (process)\n    {\n        KphpPerformProcessCreationTracking(process, CreateInfo);\n        KphpCreateProcessNotifyInformer(process, CreateInfo);\n        KphDereferenceObject(process);\n    }\n}\n\n/**\n * \\brief Starts the process informer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphProcessInformerStart(\n    VOID\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = KphCreateNPagedLookasideObject(&KphpProcesCreateApcLookaside,\n                                            sizeof(KPH_PROCESS_CREATE_APC),\n                                            KPH_TAG_PROCESS_CREATE_APC);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphCreateNPagedLookasideObject failed: %!STATUS!\",\n                      status);\n\n        KphpProcesCreateApcLookaside = NULL;\n        goto Exit;\n    }\n\n    if (KphDynPsSetCreateProcessNotifyRoutineEx2)\n    {\n        status = KphDynPsSetCreateProcessNotifyRoutineEx2(PsCreateProcessNotifySubsystems,\n                                                          (PVOID)KphpCreateProcessNotifyRoutine,\n                                                          FALSE);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to register process notify routine: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n    else\n    {\n        status = PsSetCreateProcessNotifyRoutineEx(KphpCreateProcessNotifyRoutine,\n                                                   FALSE);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to register process notify routine: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\nExit:\n\n    if (!NT_SUCCESS(status))\n    {\n        if (KphpProcesCreateApcLookaside)\n        {\n            KphDereferenceObject(KphpProcesCreateApcLookaside);\n            KphpProcesCreateApcLookaside = NULL;\n        }\n    }\n\n    return status;\n}\n\n/**\n * \\brief Stops the process informer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphProcessInformerStop(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!KphpProcesCreateApcLookaside)\n    {\n        return;\n    }\n\n    if (KphDynPsSetCreateProcessNotifyRoutineEx2)\n    {\n        KphDynPsSetCreateProcessNotifyRoutineEx2(PsCreateProcessNotifySubsystems,\n                                                 (PVOID)KphpCreateProcessNotifyRoutine,\n                                                 TRUE);\n    }\n    else\n    {\n        PsSetCreateProcessNotifyRoutineEx(KphpCreateProcessNotifyRoutine, TRUE);\n    }\n\n    KphDereferenceObject(KphpProcesCreateApcLookaside);\n}\n"
  },
  {
    "path": "KSystemInformer/informer_registry.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n\n#include <kph.h>\n#include <informer.h>\n#include <comms.h>\n#include <kphmsgdyn.h>\n\n#include <trace.h>\n\ntypedef union _KPH_REG_OPTIONS\n{\n    UCHAR Flags;\n    struct\n    {\n        UCHAR InPost : 1;\n        UCHAR PreEnabled : 1;\n        UCHAR PostEnabled : 1;\n        UCHAR EnableStackTraces : 1;\n        UCHAR EnablePostObjectNames : 1;\n        UCHAR EnablePostValueNames : 1;\n        UCHAR EnableValueBuffers : 1;\n        UCHAR Spare : 1;\n    };\n} KPH_REG_OPTIONS, *PKPH_REG_OPTIONS;\n\ntypedef struct _KPH_REG_CALL_CONTEXT\n{\n    ULONG64 PreSequence;\n    LARGE_INTEGER PreTimeStamp;\n    KPH_REG_OPTIONS Options;\n    ULONG_PTR ObjectId;\n    PUNICODE_STRING ObjectName;\n    PVOID Transaction;\n} KPH_REG_CALL_CONTEXT, *PKPH_REG_CALL_CONTEXT;\n\ntypedef union _KPH_REG_PRE_INFORMATION\n{\n    //\n    // Invalid for CreateKey and OpenKey. RootObject for LoadKey. Always NULL\n    // for SaveMergedKey. Otherwise valid.\n    //\n    PVOID Object;\n\n    REG_DELETE_KEY_INFORMATION DeleteKey;\n    REG_SET_VALUE_KEY_INFORMATION SetValueKey;\n    REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKey;\n    REG_SET_INFORMATION_KEY_INFORMATION SetInformationKey;\n    REG_RENAME_KEY_INFORMATION RenameKey;\n    REG_ENUMERATE_KEY_INFORMATION EnumerateKey;\n    REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKey;\n    REG_QUERY_KEY_INFORMATION QueryKey;\n    REG_QUERY_VALUE_KEY_INFORMATION QueryValueKey;\n    REG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION QueryMultipleValueKey;\n    REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleClose;\n    REG_CREATE_KEY_INFORMATION_V1 CreateKey;\n    REG_OPEN_KEY_INFORMATION_V1 OpenKey;\n    REG_FLUSH_KEY_INFORMATION FlushKey;\n    REG_LOAD_KEY_INFORMATION_V2 LoadKey;\n    REG_UNLOAD_KEY_INFORMATION UnLoadKey;\n    REG_QUERY_KEY_SECURITY_INFORMATION QueryKeySecurity;\n    REG_SET_KEY_SECURITY_INFORMATION SetKeySecurity;\n    REG_RESTORE_KEY_INFORMATION RestoreKey;\n    REG_SAVE_KEY_INFORMATION SaveKey;\n    REG_REPLACE_KEY_INFORMATION ReplaceKey;\n    REG_QUERY_KEY_NAME QueryKeyName;\n    REG_SAVE_MERGED_KEY_INFORMATION SaveMergedKey;\n} KPH_REG_PRE_INFORMATION, *PKPH_REG_PRE_INFORMATION;\n\ntypedef union _KPH_REG_POST_INFORMATION\n{\n    //\n    // Must inspect Common.Status for STATUS_SUCCESS for CreateKey and OpenKey.\n    // Always NULL for LoadKey and SaveMergedKey. Unsafe to use with\n    // CmCallbackGetKeyObjectIDEx during post KeyHandleClose. Otherwise valid.\n    //\n    PVOID Object;\n\n    REG_POST_OPERATION_INFORMATION Common;\n} KPH_REG_POST_INFORMATION, *PKPH_REG_POST_INFORMATION;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpCmDefaultValueName = RTL_CONSTANT_STRING(L\"(Default)\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nstatic PAGED_LOOKASIDE_LIST KphpCmCallContextLookaside = { 0 };\n\nKPH_PAGED_FILE();\n\nstatic ULONG64 KphpCmSequence = 0;\nstatic BOOLEAN KphpCmRegistered = FALSE;\nstatic LARGE_INTEGER KphpCmCookie = { 0 };\n\n/**\n * \\brief Retrieves the registry operation options for the specified class.\n *\n * \\param[in] RegClass The registry operation class.\n *\n * \\return Options for the specified class.\n */\n_IRQL_requires_max_(APC_LEVEL)\nKPH_REG_OPTIONS KphpRegGetOptions(\n    _In_ REG_NOTIFY_CLASS RegClass\n    )\n{\n    KPH_REG_OPTIONS options;\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_PAGED_CODE();\n\n    options.Flags = 0;\n\n    if (ExGetPreviousMode() != KernelMode)\n    {\n        process = KphGetCurrentProcessContext();\n    }\n    else\n    {\n        process = KphGetSystemProcessContext();\n    }\n\n#define KPH_REG_SETTING2(reg, name)                                            \\\n    case RegNtPre##reg:                                                        \\\n    {                                                                          \\\n        if (KphInformerEnabled(RegPre##name, process))                         \\\n        {                                                                      \\\n            options.PreEnabled = TRUE;                                         \\\n        }                                                                      \\\n        if (KphInformerEnabled(RegPost##name, process))                        \\\n        {                                                                      \\\n            options.PostEnabled = TRUE;                                        \\\n        }                                                                      \\\n        break;                                                                 \\\n    }                                                                          \\\n    case RegNtPost##reg:                                                       \\\n    {                                                                          \\\n        options.InPost = TRUE;                                                 \\\n        break;                                                                 \\\n    }\n#define KPH_REG_SETTING(name) KPH_REG_SETTING2(name, name)\n\n    switch (RegClass)\n    {\n        KPH_REG_SETTING(DeleteKey)\n        KPH_REG_SETTING(SetValueKey)\n        KPH_REG_SETTING(DeleteValueKey)\n        KPH_REG_SETTING(SetInformationKey)\n        KPH_REG_SETTING(RenameKey)\n        KPH_REG_SETTING(EnumerateKey)\n        KPH_REG_SETTING(EnumerateValueKey)\n        KPH_REG_SETTING(QueryKey)\n        KPH_REG_SETTING(QueryValueKey)\n        KPH_REG_SETTING(QueryMultipleValueKey)\n        KPH_REG_SETTING(KeyHandleClose)\n        KPH_REG_SETTING2(CreateKeyEx, CreateKey)\n        KPH_REG_SETTING2(OpenKeyEx, OpenKey)\n        KPH_REG_SETTING(FlushKey)\n        KPH_REG_SETTING(LoadKey)\n        KPH_REG_SETTING(UnLoadKey)\n        KPH_REG_SETTING(QueryKeySecurity)\n        KPH_REG_SETTING(SetKeySecurity)\n        KPH_REG_SETTING(RestoreKey)\n        KPH_REG_SETTING(SaveKey)\n        KPH_REG_SETTING(ReplaceKey)\n        KPH_REG_SETTING(QueryKeyName)\n        KPH_REG_SETTING(SaveMergedKey)\n        case RegNtPreCreateKey:   // XP\n        case RegNtPostCreateKey:  // XP\n        case RegNtPreOpenKey:     // XP\n        case RegNtPostOpenKey:    // XP\n        default:\n        {\n            NT_ASSERT(FALSE);\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Unsupported registry operation: %lu\",\n                          RegClass);\n            break;\n        }\n    }\n\n    if (!options.InPost && (options.PreEnabled || options.PostEnabled))\n    {\n        KPH_INFORMER_OPTIONS opts;\n\n        opts = KphInformerOpts(process);\n\n        options.EnableStackTraces = !!opts.EnableStackTraces;\n        options.EnablePostObjectNames = !!opts.RegEnablePostObjectNames;\n        options.EnablePostValueNames = !!opts.RegEnablePostValueNames;\n        options.EnableValueBuffers = !!opts.RegEnableValueBuffers;\n    }\n\n    if (process)\n    {\n        KphDereferenceObject(process);\n    }\n\n    return options;\n}\n\n/**\n * \\brief Retrieves the message ID for the specified registry operation class.\n *\n * \\param[in] RegClass The registry operation class.\n *\n * \\return The message ID for the specified class.\n */\n_IRQL_requires_max_(APC_LEVEL)\nKPH_MESSAGE_ID KphpRegGetMessageId(\n    _In_ REG_NOTIFY_CLASS RegClass\n    )\n{\n    KPH_MESSAGE_ID messageId;\n\n    KPH_PAGED_CODE();\n\n#define KPH_REG_MESSAGE_ID2(reg, name)                                        \\\n    case RegNtPre##reg:                                                       \\\n    {                                                                         \\\n        messageId = KphMsgRegPre##name;                                       \\\n        break;                                                                \\\n    }                                                                         \\\n    case RegNtPost##reg:                                                      \\\n    {                                                                         \\\n        messageId = KphMsgRegPost##name;                                      \\\n        break;                                                                \\\n    }\n#define KPH_REG_MESSAGE_ID(name) KPH_REG_MESSAGE_ID2(name, name)\n\n    switch (RegClass)\n    {\n        KPH_REG_MESSAGE_ID(DeleteKey)\n        KPH_REG_MESSAGE_ID(SetValueKey)\n        KPH_REG_MESSAGE_ID(DeleteValueKey)\n        KPH_REG_MESSAGE_ID(SetInformationKey)\n        KPH_REG_MESSAGE_ID(RenameKey)\n        KPH_REG_MESSAGE_ID(EnumerateKey)\n        KPH_REG_MESSAGE_ID(EnumerateValueKey)\n        KPH_REG_MESSAGE_ID(QueryKey)\n        KPH_REG_MESSAGE_ID(QueryValueKey)\n        KPH_REG_MESSAGE_ID(QueryMultipleValueKey)\n        KPH_REG_MESSAGE_ID(KeyHandleClose)\n        KPH_REG_MESSAGE_ID2(CreateKeyEx, CreateKey)\n        KPH_REG_MESSAGE_ID2(OpenKeyEx, OpenKey)\n        KPH_REG_MESSAGE_ID(FlushKey)\n        KPH_REG_MESSAGE_ID(LoadKey)\n        KPH_REG_MESSAGE_ID(UnLoadKey)\n        KPH_REG_MESSAGE_ID(QueryKeySecurity)\n        KPH_REG_MESSAGE_ID(SetKeySecurity)\n        KPH_REG_MESSAGE_ID(RestoreKey)\n        KPH_REG_MESSAGE_ID(SaveKey)\n        KPH_REG_MESSAGE_ID(ReplaceKey)\n        KPH_REG_MESSAGE_ID(QueryKeyName)\n        KPH_REG_MESSAGE_ID(SaveMergedKey)\n        DEFAULT_UNREACHABLE;\n    }\n\n    return messageId;\n}\n\n/**\n * \\brief Populates a registry operation message with common information.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] RegClass The registry operation class.\n * \\param[in] PreInfo The pre-operation information.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegFillCommonMessage(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ REG_NOTIFY_CLASS RegClass,\n    _In_ PKPH_REG_PRE_INFORMATION PreInfo\n    )\n{\n    KPH_PAGED_CODE();\n\n    Message->Kernel.Reg.ClientId.UniqueProcess = PsGetCurrentProcessId();\n    Message->Kernel.Reg.ClientId.UniqueThread = PsGetCurrentThreadId();\n    Message->Kernel.Reg.ProcessStartKey = KphGetCurrentProcessStartKey();\n    Message->Kernel.Reg.ThreadSubProcessTag = KphGetCurrentThreadSubProcessTag();\n    Message->Kernel.Reg.PreviousMode = (ExGetPreviousMode() != KernelMode);\n\n#define KPH_REG_COPY_PARAMETER(name, value)                                    \\\n    Message->Kernel.Reg.Parameters.name.value = PreInfo->name.value\n\n    switch (RegClass)\n    {\n        case RegNtPreDeleteKey:\n        case RegNtPostDeleteKey:\n        {\n            break;\n        }\n        case RegNtPreSetValueKey:\n        case RegNtPostSetValueKey:\n        {\n            KPH_REG_COPY_PARAMETER(SetValueKey, TitleIndex);\n            KPH_REG_COPY_PARAMETER(SetValueKey, Type);\n            KPH_REG_COPY_PARAMETER(SetValueKey, Data);\n            KPH_REG_COPY_PARAMETER(SetValueKey, DataSize);\n            break;\n        }\n        case RegNtPreDeleteValueKey:\n        case RegNtPostDeleteValueKey:\n        {\n            KPH_REG_COPY_PARAMETER(DeleteValueKey, ValueName);\n            break;\n        }\n        case RegNtPreSetInformationKey:\n        case RegNtPostSetInformationKey:\n        {\n            KPH_REG_COPY_PARAMETER(SetInformationKey, KeySetInformationClass);\n            KPH_REG_COPY_PARAMETER(SetInformationKey, KeySetInformation);\n            KPH_REG_COPY_PARAMETER(SetInformationKey, KeySetInformationLength);\n            break;\n        }\n        case RegNtPreRenameKey:\n        case RegNtPostRenameKey:\n        {\n            KPH_REG_COPY_PARAMETER(RenameKey, NewName);\n            break;\n        }\n        case RegNtPreEnumerateKey:\n        case RegNtPostEnumerateKey:\n        {\n            KPH_REG_COPY_PARAMETER(EnumerateKey, Index);\n            KPH_REG_COPY_PARAMETER(EnumerateKey, KeyInformationClass);\n            KPH_REG_COPY_PARAMETER(EnumerateKey, KeyInformation);\n            KPH_REG_COPY_PARAMETER(EnumerateKey, Length);\n            KPH_REG_COPY_PARAMETER(EnumerateKey, ResultLength);\n            break;\n        }\n        case RegNtPreEnumerateValueKey:\n        case RegNtPostEnumerateValueKey:\n        {\n            KPH_REG_COPY_PARAMETER(EnumerateValueKey, Index);\n            KPH_REG_COPY_PARAMETER(EnumerateValueKey, KeyValueInformationClass);\n            KPH_REG_COPY_PARAMETER(EnumerateValueKey, KeyValueInformation);\n            KPH_REG_COPY_PARAMETER(EnumerateValueKey, Length);\n            KPH_REG_COPY_PARAMETER(EnumerateValueKey, ResultLength);\n            break;\n        }\n        case RegNtPreQueryKey:\n        case RegNtPostQueryKey:\n        {\n            KPH_REG_COPY_PARAMETER(QueryKey, KeyInformationClass);\n            KPH_REG_COPY_PARAMETER(QueryKey, KeyInformation);\n            KPH_REG_COPY_PARAMETER(QueryKey, Length);\n            KPH_REG_COPY_PARAMETER(QueryKey, ResultLength);\n            break;\n        }\n        case RegNtPreQueryValueKey:\n        case RegNtPostQueryValueKey:\n        {\n            KPH_REG_COPY_PARAMETER(QueryValueKey, ValueName);\n            KPH_REG_COPY_PARAMETER(QueryValueKey, KeyValueInformationClass);\n            KPH_REG_COPY_PARAMETER(QueryValueKey, KeyValueInformation);\n            KPH_REG_COPY_PARAMETER(QueryValueKey, Length);\n            KPH_REG_COPY_PARAMETER(QueryValueKey, ResultLength);\n            break;\n        }\n        case RegNtPreQueryMultipleValueKey:\n        case RegNtPostQueryMultipleValueKey:\n        {\n            KPH_REG_COPY_PARAMETER(QueryMultipleValueKey, ValueEntries);\n            KPH_REG_COPY_PARAMETER(QueryMultipleValueKey, EntryCount);\n            KPH_REG_COPY_PARAMETER(QueryMultipleValueKey, ValueBuffer);\n            KPH_REG_COPY_PARAMETER(QueryMultipleValueKey, BufferLength);\n            KPH_REG_COPY_PARAMETER(QueryMultipleValueKey, RequiredBufferLength);\n            break;\n        }\n        case RegNtPreKeyHandleClose:\n        case RegNtPostKeyHandleClose:\n        {\n            break;\n        }\n        case RegNtPreCreateKeyEx:\n        case RegNtPostCreateKeyEx:\n        {\n            KPH_REG_COPY_PARAMETER(CreateKey, CompleteName);\n            KPH_REG_COPY_PARAMETER(CreateKey, RootObject);\n            KPH_REG_COPY_PARAMETER(CreateKey, ObjectType);\n            KPH_REG_COPY_PARAMETER(CreateKey, Options);\n            KPH_REG_COPY_PARAMETER(CreateKey, Class);\n            KPH_REG_COPY_PARAMETER(CreateKey, SecurityDescriptor);\n            KPH_REG_COPY_PARAMETER(CreateKey, SecurityQualityOfService);\n            KPH_REG_COPY_PARAMETER(CreateKey, DesiredAccess);\n            KPH_REG_COPY_PARAMETER(CreateKey, GrantedAccess);\n            KPH_REG_COPY_PARAMETER(CreateKey, Disposition);\n            KPH_REG_COPY_PARAMETER(CreateKey, RemainingName);\n            KPH_REG_COPY_PARAMETER(CreateKey, Wow64Flags);\n            KPH_REG_COPY_PARAMETER(CreateKey, Attributes);\n            KPH_REG_COPY_PARAMETER(CreateKey, CheckAccessMode);\n            break;\n        }\n        case RegNtPreOpenKeyEx:\n        case RegNtPostOpenKeyEx:\n        {\n            KPH_REG_COPY_PARAMETER(OpenKey, CompleteName);\n            KPH_REG_COPY_PARAMETER(OpenKey, RootObject);\n            KPH_REG_COPY_PARAMETER(OpenKey, ObjectType);\n            KPH_REG_COPY_PARAMETER(OpenKey, Options);\n            KPH_REG_COPY_PARAMETER(OpenKey, Class);\n            KPH_REG_COPY_PARAMETER(OpenKey, SecurityDescriptor);\n            KPH_REG_COPY_PARAMETER(OpenKey, SecurityQualityOfService);\n            KPH_REG_COPY_PARAMETER(OpenKey, DesiredAccess);\n            KPH_REG_COPY_PARAMETER(OpenKey, GrantedAccess);\n            KPH_REG_COPY_PARAMETER(OpenKey, Disposition);\n            KPH_REG_COPY_PARAMETER(OpenKey, RemainingName);\n            KPH_REG_COPY_PARAMETER(OpenKey, Wow64Flags);\n            KPH_REG_COPY_PARAMETER(OpenKey, Attributes);\n            KPH_REG_COPY_PARAMETER(OpenKey, CheckAccessMode);\n            break;\n        }\n        case RegNtPreFlushKey:\n        case RegNtPostFlushKey:\n        {\n            break;\n        }\n        case RegNtPreLoadKey:\n        case RegNtPostLoadKey:\n        {\n            Message->Kernel.Reg.Parameters.LoadKey.RootObject = PreInfo->LoadKey.Object;\n            KPH_REG_COPY_PARAMETER(LoadKey, KeyName);\n            KPH_REG_COPY_PARAMETER(LoadKey, SourceFile);\n            KPH_REG_COPY_PARAMETER(LoadKey, Flags);\n            KPH_REG_COPY_PARAMETER(LoadKey, TrustClassObject);\n            KPH_REG_COPY_PARAMETER(LoadKey, UserEvent);\n            KPH_REG_COPY_PARAMETER(LoadKey, DesiredAccess);\n            KPH_REG_COPY_PARAMETER(LoadKey, RootHandle);\n            KPH_REG_COPY_PARAMETER(LoadKey, FileAccessToken);\n            break;\n        }\n        case RegNtPreUnLoadKey:\n        case RegNtPostUnLoadKey:\n        {\n            KPH_REG_COPY_PARAMETER(UnLoadKey, UserEvent);\n            break;\n        }\n        case RegNtPreQueryKeySecurity:\n        case RegNtPostQueryKeySecurity:\n        {\n            KPH_REG_COPY_PARAMETER(QueryKeySecurity, SecurityInformation);\n            KPH_REG_COPY_PARAMETER(QueryKeySecurity, SecurityDescriptor);\n            KPH_REG_COPY_PARAMETER(QueryKeySecurity, Length);\n            break;\n        }\n        case RegNtPreSetKeySecurity:\n        case RegNtPostSetKeySecurity:\n        {\n            KPH_REG_COPY_PARAMETER(SetKeySecurity, SecurityInformation);\n            KPH_REG_COPY_PARAMETER(SetKeySecurity, SecurityDescriptor);\n            break;\n        }\n        case RegNtPreRestoreKey:\n        case RegNtPostRestoreKey:\n        {\n            KPH_REG_COPY_PARAMETER(RestoreKey, FileHandle);\n            KPH_REG_COPY_PARAMETER(RestoreKey, Flags);\n            break;\n        }\n        case RegNtPreSaveKey:\n        case RegNtPostSaveKey:\n        {\n            KPH_REG_COPY_PARAMETER(SaveKey, FileHandle);\n            KPH_REG_COPY_PARAMETER(SaveKey, Format);\n            break;\n        }\n        case RegNtPreReplaceKey:\n        case RegNtPostReplaceKey:\n        {\n            KPH_REG_COPY_PARAMETER(ReplaceKey, OldFileName);\n            KPH_REG_COPY_PARAMETER(ReplaceKey, NewFileName);\n            break;\n        }\n        case RegNtPreQueryKeyName:\n        case RegNtPostQueryKeyName:\n        {\n            KPH_REG_COPY_PARAMETER(QueryKeyName, ObjectNameInfo);\n            KPH_REG_COPY_PARAMETER(QueryKeyName, Length);\n            KPH_REG_COPY_PARAMETER(QueryKeyName, ReturnLength);\n            break;\n        }\n        case RegNtPreSaveMergedKey:\n        case RegNtPostSaveMergedKey:\n        {\n            KPH_REG_COPY_PARAMETER(SaveMergedKey, FileHandle);\n            KPH_REG_COPY_PARAMETER(SaveMergedKey, HighKeyObject);\n            KPH_REG_COPY_PARAMETER(SaveMergedKey, LowKeyObject);\n            break;\n        }\n        DEFAULT_UNREACHABLE;\n    }\n}\n\n/**\n * \\brief Copies the object name information into a message. And returns other\n * associated information for the object.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] FieldId The object name field ID to populate. Optional, when the\n * identifier is InvalidKphMsgField the object name is not copied.\n * \\param[in] InputObject The object to copy the information from.\n * \\param[out] Object Receives a copy of the input object pointer.\n * \\param[out] ObjectId Receives the object ID for the object.\n * \\param[out] Transaction Receives the transaction for the object, if any.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegCopyObjectInfo(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PVOID InputObject,\n    _Out_opt_ PVOID* Object,\n    _Out_opt_ PULONG_PTR ObjectId,\n    _Out_opt_ PVOID* Transaction\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING objectName;\n    PUNICODE_STRING* objectNamePointer;\n\n    KPH_PAGED_CODE();\n\n    objectName = NULL;\n\n    if (Object)\n    {\n        *Object = InputObject;\n    }\n\n    if (ObjectId)\n    {\n        *ObjectId = 0;\n    }\n\n    if (Transaction)\n    {\n        *Transaction = CmGetBoundTransaction(&KphpCmCookie, InputObject);\n    }\n\n    if (FieldId != InvalidKphMsgField)\n    {\n        objectNamePointer = &objectName;\n    }\n    else\n    {\n        objectNamePointer = NULL;\n    }\n\n    status = CmCallbackGetKeyObjectIDEx(&KphpCmCookie,\n                                        InputObject,\n                                        ObjectId,\n                                        objectNamePointer,\n                                        0);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"CmCallbackGetKeyObjectIDEx failed: %!STATUS!\",\n                      status);\n\n        if (ObjectId)\n        {\n            *ObjectId = 0;\n        }\n\n        objectName = NULL;\n        goto Exit;\n    }\n\n    if (FieldId != InvalidKphMsgField)\n    {\n        status = KphMsgDynAddUnicodeString(Message, FieldId, objectName);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                          status);\n        }\n    }\n\nExit:\n\n    if (objectName)\n    {\n        CmCallbackReleaseKeyObjectIDEx(objectName);\n    }\n}\n\n/**\n * \\brief Fills a message with information about the specified registry object.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] Object The object to copy the information from.\n * \\param[in] IncludeObjectName If TRUE the object name is included in the\n * message, when FALSE the object name is not copied into the message.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegFillObjectInfo(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PVOID Object,\n    _In_ BOOLEAN IncludeObjectName\n    )\n{\n    KPH_MESSAGE_FIELD_ID fieldId;\n\n    KPH_PAGED_CODE();\n\n    if (IncludeObjectName)\n    {\n        fieldId = KphMsgFieldObjectName;\n    }\n    else\n    {\n        fieldId = InvalidKphMsgField;\n    }\n\n    KphpRegCopyObjectInfo(Message,\n                          fieldId,\n                          Object,\n                          &Message->Kernel.Reg.Object,\n                          &Message->Kernel.Reg.ObjectId,\n                          &Message->Kernel.Reg.Transaction);\n}\n\n/**\n * \\brief Creates a registry object name from a root object and relative name.\n *\n * \\param[in] RootObject The root registry object.\n * \\param[in] RelativeName The relative name from the root object.\n * \\param[out] ObjectName Receives a pointer to the allocated object name.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpRegMakeObjectName(\n    _In_ PVOID RootObject,\n    _In_ PUNICODE_STRING RelativeName,\n    _Outptr_allocatesMem_ PUNICODE_STRING* ObjectName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING rootName;\n    PUNICODE_STRING objectName;\n    BOOLEAN needsSeparator;\n    ULONG length;\n\n    KPH_PAGED_CODE();\n\n    *ObjectName = NULL;\n\n    objectName = NULL;\n\n    status = CmCallbackGetKeyObjectIDEx(&KphpCmCookie,\n                                        RootObject,\n                                        NULL,\n                                        &rootName,\n                                        0);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"CmCallbackGetKeyObjectIDEx failed: %!STATUS!\",\n                      status);\n\n        rootName = NULL;\n        goto Exit;\n    }\n\n    length = (rootName->Length + RelativeName->Length);\n\n    if ((rootName->Length >= sizeof(WCHAR)) &&\n        (rootName->Buffer[(rootName->Length / sizeof(WCHAR)) - 1] != OBJ_NAME_PATH_SEPARATOR) &&\n        (RelativeName->Length >= sizeof(WCHAR)) &&\n        (RelativeName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR))\n    {\n        needsSeparator = TRUE;\n        length += sizeof(WCHAR);\n    }\n    else\n    {\n        needsSeparator = FALSE;\n    }\n\n    if (length > UNICODE_STRING_MAX_BYTES)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Object name too long: %lu\",\n                      length);\n\n        status = STATUS_INTEGER_OVERFLOW;\n        goto Exit;\n    }\n\n    objectName = KphAllocatePaged((length + sizeof(UNICODE_STRING)),\n                                  KPH_TAG_REG_OBJECT_NAME);\n    if (!objectName)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate object name.\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    objectName->Length = 0;\n    objectName->MaximumLength = (USHORT)length;\n    objectName->Buffer = Add2Ptr(objectName, sizeof(UNICODE_STRING));\n\n    RtlAppendUnicodeStringToString(objectName, rootName);\n\n    if (needsSeparator)\n    {\n        RtlAppendUnicodeToString(objectName, L\"\\\\\");\n    }\n\n    RtlAppendUnicodeStringToString(objectName, RelativeName);\n\n    *ObjectName = objectName;\n    objectName = NULL;\n\nExit:\n\n    if (rootName)\n    {\n        CmCallbackReleaseKeyObjectIDEx(rootName);\n    }\n\n    if (objectName)\n    {\n        KphFree(objectName, KPH_TAG_REG_OBJECT_NAME);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Fills a message with information about a creation or open operation.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] CreateInfo The creation or open information.\n * \\param[in] IncludeObjectName If TRUE the object name is included in the\n * message, when FALSE the object name is not copied into the message.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegFillCreateKeyObjectInfo(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PREG_CREATE_KEY_INFORMATION_V1 CreateInfo,\n    _In_ BOOLEAN IncludeObjectName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING objectName;\n\n    KPH_PAGED_CODE();\n\n    Message->Kernel.Reg.Transaction = CreateInfo->Transaction;\n\n    if (!IncludeObjectName)\n    {\n        return;\n    }\n\n    if ((CreateInfo->CompleteName->Length >= sizeof(WCHAR)) &&\n        (CreateInfo->CompleteName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))\n    {\n        objectName = CreateInfo->CompleteName;\n    }\n    else\n    {\n        status = KphpRegMakeObjectName(CreateInfo->RootObject,\n                                       CreateInfo->CompleteName,\n                                       &objectName);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphpRegMakeObjectName failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    status = KphMsgDynAddUnicodeString(Message,\n                                       KphMsgFieldObjectName,\n                                       objectName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\nExit:\n\n    if (objectName && (objectName != CreateInfo->CompleteName))\n    {\n        KphFree(objectName, KPH_TAG_REG_OBJECT_NAME);\n    }\n}\n\n/**\n * \\brief Fills a message with information about a load key operation.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] LoadInfo The load key information.\n * \\param[in] IncludeObjectName If TRUE the object name is included in the\n * message, when FALSE the object name is not copied into the message.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegFillLoadKeyObjectInfo(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ PREG_LOAD_KEY_INFORMATION_V2 LoadInfo,\n    _In_ BOOLEAN IncludeObjectName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING objectName;\n\n    KPH_PAGED_CODE();\n\n    if (!IncludeObjectName)\n    {\n        return;\n    }\n\n    if (LoadInfo->Object)\n    {\n        status = KphpRegMakeObjectName(LoadInfo->Object,\n                                       LoadInfo->KeyName,\n                                       &objectName);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphpRegMakeObjectName failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n    else\n    {\n        objectName = LoadInfo->KeyName;\n    }\n\n    status = KphMsgDynAddUnicodeString(Message,\n                                       KphMsgFieldObjectName,\n                                       objectName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\nExit:\n\n    if (objectName && (objectName != LoadInfo->KeyName))\n    {\n        KphFree(objectName, KPH_TAG_REG_OBJECT_NAME);\n    }\n}\n\n/**\n * \\brief Copies a Unicode string into a message\n *\n * \\param[in] Message The message to populate.\n * \\param[in] FieldId The field ID for the Unicode string.\n * \\param[in] String The string to populate into the message.\n * \\param[in] Default Default string to use input string length is zero.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegCopyUnicodeStringWithDefault(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_opt_ PUNICODE_STRING String,\n    _In_opt_ PCUNICODE_STRING Default\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING string;\n\n    KPH_PAGED_CODE();\n\n    if (!String)\n    {\n        return;\n    }\n\n    __try\n    {\n        string.Buffer = String->Buffer;\n        string.Length = String->Length;\n        string.MaximumLength = string.Length;\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Exception accessing string: %!STATUS!\",\n                      GetExceptionCode());\n\n        return;\n    }\n\n    if (!string.Length)\n    {\n        if (Default)\n        {\n            status = KphMsgDynAddUnicodeString(Message, FieldId, Default);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                              status);\n            }\n        }\n\n        return;\n    }\n\n    __try\n    {\n        status = KphMsgDynAddUnicodeString(Message, FieldId, &string);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                          status);\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Exception copying string: %!STATUS!\",\n                      GetExceptionCode());\n\n        //\n        // N.B. The KphMsgDynAdd* routines will first reserve a table\n        // entry then copy data into the buffer. If we get here it means\n        // the control flow was arrested after the reservation. Since we\n        // can't guarantee it was all copied successfully clear the last\n        // entry that was reserved.\n        //\n        KphMsgDynClearLast(Message);\n    }\n}\n\n/**\n * \\brief Copies a Unicode string into a message.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] FieldId The field ID for the Unicode string.\n * \\param[in] String The string to populate into the message.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegCopyUnicodeString(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_opt_ PUNICODE_STRING String\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphpRegCopyUnicodeStringWithDefault(Message, FieldId, String, NULL);\n}\n\n/**\n * \\brief Copies a registry value name into a message.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] ValueName The value name to populate into the message.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegCopyValueName(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_opt_ PUNICODE_STRING ValueName\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphpRegCopyUnicodeStringWithDefault(Message,\n                                        KphMsgFieldValueName,\n                                        ValueName,\n                                        &KphpCmDefaultValueName);\n}\n\n/**\n * \\brief Copies multiple value names into a message.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] ValueEntries The value entries to populate into the message.\n * \\param[in] EntryCount The number of value entries.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegCopyMultipleValueNames(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_opt_ PKEY_VALUE_ENTRY ValueEntries,\n    _In_ ULONG EntryCount\n    )\n{\n    NTSTATUS status;\n    ULONG length;\n    PUNICODE_STRING valueNames;\n    ULONG remaining;\n\n    KPH_PAGED_CODE();\n\n    if (!ValueEntries || !EntryCount)\n    {\n        return;\n    }\n\n    valueNames = NULL;\n\n    //\n    // Try to capture the values names as a sequence of null terminated strings.\n    //\n\n    length = sizeof(WCHAR);\n\n    __try\n    {\n        for (ULONG i = 0; i < EntryCount; i++)\n        {\n            PCUNICODE_STRING entry;\n            ULONG valueLength;\n\n            entry = ValueEntries[i].ValueName;\n            valueLength = entry->Length;\n\n            if (valueLength)\n            {\n                valueLength += sizeof(WCHAR);\n            }\n            else\n            {\n                valueLength = (KphpCmDefaultValueName.Length + sizeof(WCHAR));\n            }\n\n            status = RtlULongAdd(length, valueLength, &length);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"RtlULongAdd failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Exception accessing value entries: %!STATUS!\",\n                      GetExceptionCode());\n\n        goto Exit;\n    }\n\n    if (length > UNICODE_STRING_MAX_BYTES)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Value names too long: %lu\",\n                      length);\n\n        goto Exit;\n    }\n\n    valueNames = KphAllocatePaged((length + sizeof(UNICODE_STRING)),\n                                   KPH_TAG_REG_VALUE_NAMES);\n    if (!valueNames)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to allocate value names.\");\n\n        goto Exit;\n    }\n\n    valueNames->Length = 0;\n    valueNames->MaximumLength = (USHORT)length;\n    valueNames->Buffer = Add2Ptr(valueNames, sizeof(UNICODE_STRING));\n\n    __try\n    {\n        for (ULONG i = 0; i < EntryCount; i++)\n        {\n            PCUNICODE_STRING entry;\n\n            entry = ValueEntries[i].ValueName;\n\n            if (!entry->Length)\n            {\n                entry = &KphpCmDefaultValueName;\n            }\n\n            status = RtlAppendUnicodeStringToString(valueNames, entry);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"RtlAppendUnicodeStringToString failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            remaining = (valueNames->MaximumLength - valueNames->Length);\n\n            if (remaining < sizeof(WCHAR))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              INFORMER,\n                              \"Exhausted value names buffer.\");\n\n                goto Exit;\n            }\n\n            valueNames->Buffer[valueNames->Length / sizeof(WCHAR)] = UNICODE_NULL;\n            valueNames->Length += sizeof(WCHAR);\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Exception accessing value entries: %!STATUS!\",\n                      GetExceptionCode());\n\n        goto Exit;\n    }\n\n    remaining = (valueNames->MaximumLength - valueNames->Length);\n    if (remaining < sizeof(WCHAR))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Exhausted value names buffer.\");\n\n        goto Exit;\n    }\n\n    valueNames->Buffer[valueNames->Length / sizeof(WCHAR)] = UNICODE_NULL;\n    valueNames->Length += sizeof(WCHAR);\n\n    status = KphMsgDynAddUnicodeString(Message,\n                                       KphMsgFieldMultipleValueNames,\n                                       valueNames);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\nExit:\n\n    if (valueNames)\n    {\n        KphFree(valueNames, KPH_TAG_REG_VALUE_NAMES);\n    }\n}\n\n/**\n * \\brief Copies a buffer into a message.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] FieldId The field ID for the buffer.\n * \\param[in] Buffer The buffer to copy.\n * \\param[in] Length The length of the buffer.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegCopyBuffer(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_opt_ PVOID Buffer,\n    _In_ ULONG Length\n    )\n{\n    NTSTATUS status;\n    USHORT remaining;\n    KPHM_SIZED_BUFFER sizedBuffer;\n\n    KPH_PAGED_CODE();\n\n    if (!Buffer)\n    {\n        return;\n    }\n\n    remaining = KphMsgDynRemaining(Message);\n    if (remaining < Length)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Buffer too large for message, truncating %lu -> %lu\",\n                      Length,\n                      remaining);\n\n        Length = remaining;\n    }\n\n    if (!Length)\n    {\n        return;\n    }\n\n    sizedBuffer.Buffer = Buffer;\n    sizedBuffer.Size = (USHORT)Length;\n\n    __try\n    {\n        status = KphMsgDynAddSizedBuffer(Message, FieldId, &sizedBuffer);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphMsgDynAddSizedBuffer failed: %!STATUS!\",\n                          status);\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Exception copying buffer: %!STATUS!\",\n                      GetExceptionCode());\n\n        //\n        // N.B. The KphMsgDynAdd* routines will first reserve a table\n        // entry then copy data into the buffer. If we get here it means\n        // the control flow was arrested after the reservation. Since we\n        // can't guarantee it was all copied successfully clear the last\n        // entry that was reserved.\n        //\n        KphMsgDynClearLast(Message);\n    }\n}\n\n/**\n * \\brief Copies an object name into a message.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] FieldId The field ID for the object name.\n * \\param[in] Object The object to copy the name from.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegCopyObjectName(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_opt_ PVOID Object\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING objectName;\n    PUNICODE_STRING keyName;\n    POBJECT_NAME_INFORMATION nameInfo;\n    ULONG length;\n\n    KPH_PAGED_CODE();\n\n    if (!Object)\n    {\n        return;\n    }\n\n    keyName = NULL;\n    nameInfo = NULL;\n\n    if (ObGetObjectType(Object) == *CmKeyObjectType)\n    {\n        status = CmCallbackGetKeyObjectIDEx(&KphpCmCookie,\n                                            Object,\n                                            NULL,\n                                            &keyName,\n                                            0);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"CmCallbackGetKeyObjectIDEx failed: %!STATUS!\",\n                          status);\n\n            keyName = NULL;\n            goto Exit;\n        }\n\n        objectName = keyName;\n    }\n    else\n    {\n        status = KphQueryNameObject(Object, NULL, 0, &length);\n        if (status != STATUS_BUFFER_TOO_SMALL)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphQueryNameObject: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        nameInfo = KphAllocatePaged(length, KPH_TAG_REG_OBJECT_NAME);\n        if (!nameInfo)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to allocate object name.\");\n\n            goto Exit;\n        }\n\n        status = KphQueryNameObject(Object, nameInfo, length, &length);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphQueryNameObject failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        objectName = &nameInfo->Name;\n    }\n\n    status = KphMsgDynAddUnicodeString(Message, FieldId, objectName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                      status);\n    }\n\nExit:\n\n    if (nameInfo)\n    {\n        KphFree(nameInfo, KPH_TAG_REG_OBJECT_NAME);\n    }\n\n    if (keyName)\n    {\n        CmCallbackReleaseKeyObjectIDEx(keyName);\n    }\n}\n\n/**\n * \\brief Copies a handle name into a message.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] FieldId The field ID for the handle name.\n * \\param[in] Handle The handle to copy the name from.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegCopyHandleName(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ HANDLE Handle\n    )\n{\n    NTSTATUS status;\n    KAPC_STATE apcState;\n    PVOID object;\n\n    KPH_PAGED_CODE();\n\n    if (!Handle)\n    {\n        return;\n    }\n\n    if (IsKernelHandle(Handle) && !IsPseudoHandle(Handle))\n    {\n        KeStackAttachProcess(PsInitialSystemProcess, &apcState);\n    }\n\n    NT_ASSERT(Handle);\n#pragma prefast(suppress : 6387)\n    status = ObReferenceObjectByHandle(Handle,\n                                       0,\n                                       NULL,\n                                       KernelMode,\n                                       &object,\n                                       NULL);\n\n    if (IsKernelHandle(Handle) && !IsPseudoHandle(Handle))\n    {\n        KeUnstackDetachProcess(&apcState);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        return;\n    }\n\n    KphpRegCopyObjectName(Message, FieldId, object);\n\n    ObDereferenceObject(object);\n}\n\n/**\n * \\brief Fills a message with post operation information.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] RegClass The registry operation class.\n * \\param[in] PostInfo The post operation information.\n * \\param[in] Context The call context.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegFillPostOpMessage(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ REG_NOTIFY_CLASS RegClass,\n    _In_ PKPH_REG_POST_INFORMATION PostInfo,\n    _In_ PKPH_REG_CALL_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    PKPH_REG_PRE_INFORMATION preInfo;\n    BOOLEAN enableObjectNames;\n    BOOLEAN enableValueNames;\n\n    KPH_PAGED_CODE();\n\n    enableObjectNames = Context->Options.EnablePostObjectNames;\n    enableValueNames = Context->Options.EnablePostValueNames;\n\n    Message->Kernel.Reg.PostOperation = TRUE;\n\n    Message->Kernel.Reg.Post.PreSequence = Context->PreSequence;\n    Message->Kernel.Reg.Post.PreTimeStamp = Context->PreTimeStamp;\n\n    preInfo = PostInfo->Common.PreInformation;\n    Message->Kernel.Reg.Post.Status = PostInfo->Common.Status;\n\n    KphpRegFillCommonMessage(Message, RegClass, preInfo);\n\n#define KPH_REG_COPY_OUT_PARAM(n, v)                                           \\\n    if (preInfo->n.v)                                                          \\\n    {                                                                          \\\n        __try                                                                  \\\n        {                                                                      \\\n            Message->Kernel.Reg.Post.n.v = *preInfo->n.v;                      \\\n        }                                                                      \\\n        __except (EXCEPTION_EXECUTE_HANDLER)                                   \\\n        {                                                                      \\\n            Message->Kernel.Reg.Post.n.v = 0;                                  \\\n        }                                                                      \\\n    }\n\n    switch (RegClass)\n    {\n        case RegNtPostSetValueKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (enableValueNames)\n            {\n                KphpRegCopyValueName(Message, preInfo->SetValueKey.ValueName);\n            }\n            break;\n        }\n        case RegNtPostDeleteValueKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (enableValueNames)\n            {\n                KphpRegCopyValueName(Message, preInfo->DeleteValueKey.ValueName);\n            }\n            break;\n        }\n        case RegNtPostEnumerateKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (!NT_SUCCESS(Message->Kernel.Reg.Post.Status))\n            {\n                break;\n            }\n\n            KPH_REG_COPY_OUT_PARAM(EnumerateKey, ResultLength);\n\n            KphpRegCopyBuffer(Message,\n                              KphMsgFieldInformationBuffer,\n                              preInfo->EnumerateKey.KeyInformation,\n                              Message->Kernel.Reg.Post.EnumerateKey.ResultLength);\n            break;\n        }\n        case RegNtPostEnumerateValueKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (!NT_SUCCESS(PostInfo->Common.Status))\n            {\n                break;\n            }\n\n            KPH_REG_COPY_OUT_PARAM(EnumerateValueKey, ResultLength);\n\n            KphpRegCopyBuffer(Message,\n                              KphMsgFieldInformationBuffer,\n                              preInfo->EnumerateValueKey.KeyValueInformation,\n                              Message->Kernel.Reg.Post.EnumerateValueKey.ResultLength);\n            break;\n        }\n        case RegNtPostQueryKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (!NT_SUCCESS(PostInfo->Common.Status))\n            {\n                break;\n            }\n\n            KPH_REG_COPY_OUT_PARAM(QueryKey, ResultLength);\n\n            KphpRegCopyBuffer(Message,\n                              KphMsgFieldInformationBuffer,\n                              preInfo->QueryKey.KeyInformation,\n                              Message->Kernel.Reg.Post.QueryKey.ResultLength);\n            break;\n        }\n        case RegNtPostQueryValueKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (enableValueNames)\n            {\n                KphpRegCopyValueName(Message, preInfo->QueryValueKey.ValueName);\n            }\n\n            if (!NT_SUCCESS(PostInfo->Common.Status))\n            {\n                break;\n            }\n\n            KPH_REG_COPY_OUT_PARAM(QueryValueKey, ResultLength);\n\n            if (Context->Options.EnableValueBuffers)\n            {\n                KphpRegCopyBuffer(Message,\n                                  KphMsgFieldValueBuffer,\n                                  preInfo->QueryValueKey.KeyValueInformation,\n                                  Message->Kernel.Reg.Post.QueryValueKey.ResultLength);\n            }\n            break;\n        }\n        case RegNtPostQueryMultipleValueKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (enableValueNames)\n            {\n                KphpRegCopyMultipleValueNames(Message,\n                                              preInfo->QueryMultipleValueKey.ValueEntries,\n                                              preInfo->QueryMultipleValueKey.EntryCount);\n            }\n\n            KPH_REG_COPY_OUT_PARAM(QueryMultipleValueKey, RequiredBufferLength);\n\n            if (!NT_SUCCESS(PostInfo->Common.Status))\n            {\n                break;\n            }\n\n            KPH_REG_COPY_OUT_PARAM(QueryMultipleValueKey, BufferLength);\n\n            if (Context->Options.EnableValueBuffers)\n            {\n                ULONG entriesLength;\n\n                if (!NT_SUCCESS(RtlULongMult(preInfo->QueryMultipleValueKey.EntryCount,\n                                             sizeof(KEY_VALUE_ENTRY),\n                                             &entriesLength)))\n                {\n                    break;\n                }\n\n                KphpRegCopyBuffer(Message,\n                                  KphMsgFieldMultipleValueEntries,\n                                  preInfo->QueryMultipleValueKey.ValueEntries,\n                                  entriesLength);\n\n                KphpRegCopyBuffer(Message,\n                                  KphMsgFieldValueBuffer,\n                                  preInfo->QueryMultipleValueKey.ValueBuffer,\n                                  Message->Kernel.Reg.Post.QueryMultipleValueKey.BufferLength);\n            }\n            break;\n        }\n        case RegNtPostKeyHandleClose:\n        {\n            Message->Kernel.Reg.Object = preInfo->Object;\n            Message->Kernel.Reg.ObjectId = Context->ObjectId;\n            Message->Kernel.Reg.Transaction = Context->Transaction;\n\n            if (Context->ObjectName)\n            {\n                status = KphMsgDynAddUnicodeString(Message,\n                                                   KphMsgFieldObjectName,\n                                                   Context->ObjectName);\n                if (!NT_SUCCESS(status))\n                {\n                    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                                  INFORMER,\n                                  \"KphMsgDynAddUnicodeString failed: %!STATUS!\",\n                                  status);\n                }\n            }\n            break;\n        }\n        case RegNtPostCreateKeyEx:\n        {\n            if (PostInfo->Common.Status == STATUS_SUCCESS)\n            {\n                KphpRegFillObjectInfo(Message, PostInfo->Common.Object, enableObjectNames);\n            }\n            else\n            {\n                KphpRegFillCreateKeyObjectInfo(Message, &preInfo->CreateKey, enableObjectNames);\n            }\n\n            if (NT_SUCCESS(PostInfo->Common.Status))\n            {\n                KPH_REG_COPY_OUT_PARAM(CreateKey, Disposition);\n            }\n            break;\n        }\n        case RegNtPostOpenKeyEx:\n        {\n            if (PostInfo->Common.Status == STATUS_SUCCESS)\n            {\n                KphpRegFillObjectInfo(Message, PostInfo->Common.Object, enableObjectNames);\n            }\n            else\n            {\n                KphpRegFillCreateKeyObjectInfo(Message, &preInfo->OpenKey, enableObjectNames);\n            }\n\n            if (NT_SUCCESS(PostInfo->Common.Status))\n            {\n                KPH_REG_COPY_OUT_PARAM(OpenKey, Disposition);\n            }\n            break;\n        }\n        case RegNtPostLoadKey:\n        {\n            KphpRegFillLoadKeyObjectInfo(Message, &preInfo->LoadKey, enableObjectNames);\n\n            if (enableObjectNames)\n            {\n                KphpRegCopyUnicodeString(Message,\n                                         KphMsgFieldFileName,\n                                         preInfo->LoadKey.SourceFile);\n            }\n\n            if (NT_SUCCESS(PostInfo->Common.Status))\n            {\n                KPH_REG_COPY_OUT_PARAM(LoadKey, RootHandle);\n            }\n            break;\n        }\n        case RegNtPostQueryKeySecurity:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (NT_SUCCESS(PostInfo->Common.Status))\n            {\n                KPH_REG_COPY_OUT_PARAM(QueryKeySecurity, Length);\n            }\n            break;\n        }\n        case RegNtPostRestoreKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, TRUE);\n\n            if (enableObjectNames)\n            {\n                KphpRegCopyHandleName(Message,\n                                      KphMsgFieldFileName,\n                                      preInfo->RestoreKey.FileHandle);\n            }\n            break;\n        }\n        case RegNtPostSaveKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, TRUE);\n\n            if (enableObjectNames)\n            {\n                KphpRegCopyHandleName(Message,\n                                      KphMsgFieldFileName,\n                                      preInfo->SaveKey.FileHandle);\n            }\n            break;\n        }\n        case RegNtPostReplaceKey:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (enableObjectNames)\n            {\n                KphpRegCopyUnicodeString(Message,\n                                         KphMsgFieldFileName,\n                                         preInfo->ReplaceKey.NewFileName);\n                KphpRegCopyUnicodeString(Message,\n                                         KphMsgFieldDestinationFileName,\n                                         preInfo->ReplaceKey.OldFileName);\n            }\n            break;\n        }\n        case RegNtPostQueryKeyName:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n\n            if (NT_SUCCESS(PostInfo->Common.Status))\n            {\n                KPH_REG_COPY_OUT_PARAM(QueryKeyName, ReturnLength);\n            }\n            break;\n        }\n        case RegNtPostSaveMergedKey:\n        {\n            KPH_MESSAGE_FIELD_ID fieldId;\n\n            KphpRegFillObjectInfo(Message, preInfo->SaveMergedKey.HighKeyObject, enableObjectNames);\n\n            if (enableObjectNames)\n            {\n                fieldId = KphMsgFieldOtherObjectName;\n            }\n            else\n            {\n                fieldId = InvalidKphMsgField;\n            }\n\n            KphpRegCopyObjectInfo(Message,\n                                  fieldId,\n                                  preInfo->SaveMergedKey.LowKeyObject,\n                                  NULL,\n                                  &Message->Kernel.Reg.Post.SaveMergedKey.LowKeyObjectId,\n                                  &Message->Kernel.Reg.Post.SaveMergedKey.LowKeyTransaction);\n\n            if (enableObjectNames)\n            {\n                KphpRegCopyHandleName(Message,\n                                      KphMsgFieldFileName,\n                                      preInfo->SaveMergedKey.FileHandle);\n            }\n            break;\n        }\n        default:\n        {\n            KphpRegFillObjectInfo(Message, PostInfo->Object, enableObjectNames);\n            break;\n        }\n    }\n}\n\n/**\n * \\brief Fills a message with pre operation information.\n *\n * \\param[in,out] Message The message to populate.\n * \\param[in] RegClass The registry operation class.\n * \\param[in] PreInfo The pre operation information.\n * \\param[in] Options Registry options to use.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegFillPreOpMessage(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ REG_NOTIFY_CLASS RegClass,\n    _In_ PKPH_REG_PRE_INFORMATION PreInfo,\n    _In_ PKPH_REG_OPTIONS Options\n    )\n{\n    KPH_PAGED_CODE();\n\n    Message->Kernel.Reg.PostOperation = FALSE;\n\n    KphpRegFillCommonMessage(Message, RegClass, PreInfo);\n\n#define KPH_REG_COPY_IN_PARAM(n, v)                                            \\\n    if (PreInfo->n.v)                                                          \\\n    {                                                                          \\\n        __try                                                                  \\\n        {                                                                      \\\n            Message->Kernel.Reg.Pre.n.v = *PreInfo->n.v;                       \\\n        }                                                                      \\\n        __except (EXCEPTION_EXECUTE_HANDLER)                                   \\\n        {                                                                      \\\n            Message->Kernel.Reg.Pre.n.v = 0;                                   \\\n        }                                                                      \\\n    }\n\n    switch (RegClass)\n    {\n        case RegNtPreSetValueKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KphpRegCopyValueName(Message, PreInfo->SetValueKey.ValueName);\n\n            if (Options->EnableValueBuffers)\n            {\n                KphpRegCopyBuffer(Message,\n                                  KphMsgFieldValueBuffer,\n                                  PreInfo->SetValueKey.Data,\n                                  PreInfo->SetValueKey.DataSize);\n            }\n            break;\n        }\n        case RegNtPreDeleteValueKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KphpRegCopyValueName(Message, PreInfo->DeleteValueKey.ValueName);\n            break;\n        }\n        case RegNtPreSetInformationKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KphpRegCopyBuffer(Message,\n                              KphMsgFieldInformationBuffer,\n                              PreInfo->SetInformationKey.KeySetInformation,\n                              PreInfo->SetInformationKey.KeySetInformationLength);\n            break;\n        }\n        case RegNtPreRenameKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KphpRegCopyUnicodeString(Message,\n                                     KphMsgFieldNewName,\n                                     PreInfo->RenameKey.NewName);\n            break;\n        }\n        case RegNtPreQueryValueKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KphpRegCopyValueName(Message, PreInfo->QueryValueKey.ValueName);\n            break;\n        }\n        case RegNtPreQueryMultipleValueKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KphpRegCopyMultipleValueNames(Message,\n                                          PreInfo->QueryMultipleValueKey.ValueEntries,\n                                          PreInfo->QueryMultipleValueKey.EntryCount);\n            KPH_REG_COPY_IN_PARAM(QueryMultipleValueKey, BufferLength);\n            break;\n        }\n        case RegNtPreCreateKeyEx:\n        {\n            KphpRegFillCreateKeyObjectInfo(Message, &PreInfo->CreateKey, TRUE);\n            KphpRegCopyUnicodeString(Message,\n                                     KphMsgFieldClass,\n                                     PreInfo->CreateKey.Class);\n            break;\n        }\n        case RegNtPreOpenKeyEx:\n        {\n            KphpRegFillCreateKeyObjectInfo(Message, &PreInfo->OpenKey, TRUE);\n            break;\n        }\n        case RegNtPreLoadKey:\n        {\n            KphpRegFillLoadKeyObjectInfo(Message, &PreInfo->LoadKey, TRUE);\n            KphpRegCopyUnicodeString(Message,\n                                     KphMsgFieldFileName,\n                                     PreInfo->LoadKey.SourceFile);\n            break;\n        }\n        case RegNtPreQueryKeySecurity:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KPH_REG_COPY_IN_PARAM(QueryKeySecurity, SecurityInformation);\n            KPH_REG_COPY_IN_PARAM(QueryKeySecurity, Length);\n            break;\n        }\n        case RegNtPreSetKeySecurity:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KPH_REG_COPY_IN_PARAM(SetKeySecurity, SecurityInformation);\n            break;\n        }\n        case RegNtPreRestoreKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KphpRegCopyHandleName(Message,\n                                  KphMsgFieldFileName,\n                                  PreInfo->RestoreKey.FileHandle);\n            break;\n        }\n        case RegNtPreSaveKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KphpRegCopyHandleName(Message,\n                                  KphMsgFieldFileName,\n                                  PreInfo->SaveKey.FileHandle);\n            break;\n        }\n        case RegNtPreReplaceKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            KphpRegCopyUnicodeString(Message,\n                                     KphMsgFieldFileName,\n                                     PreInfo->ReplaceKey.NewFileName);\n            KphpRegCopyUnicodeString(Message,\n                                     KphMsgFieldDestinationFileName,\n                                     PreInfo->ReplaceKey.OldFileName);\n            break;\n        }\n        case RegNtPreSaveMergedKey:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->SaveMergedKey.HighKeyObject, TRUE);\n            KphpRegCopyObjectInfo(Message,\n                                  KphMsgFieldOtherObjectName,\n                                  PreInfo->SaveMergedKey.LowKeyObject,\n                                  NULL,\n                                  &Message->Kernel.Reg.Pre.SaveMergedKey.LowKeyObjectId,\n                                  &Message->Kernel.Reg.Pre.SaveMergedKey.LowKeyTransaction);\n            KphpRegCopyHandleName(Message,\n                                  KphMsgFieldFileName,\n                                  PreInfo->SaveMergedKey.FileHandle);\n            break;\n        }\n        default:\n        {\n            KphpRegFillObjectInfo(Message, PreInfo->Object, TRUE);\n            break;\n        }\n    }\n}\n\n/**\n * \\brief Sends a post operation message.\n *\n * \\param[in] RegClass The registry operation class.\n * \\param[in] PostInfo The post operation information.\n * \\param[in] Sequence The registry sequence number.\n * \\param[in] Context The call context.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegPostOpSend(\n    _In_ REG_NOTIFY_CLASS RegClass,\n    _In_ PKPH_REG_POST_INFORMATION PostInfo,\n    _In_ ULONG64 Sequence,\n    _In_ PKPH_REG_CALL_CONTEXT Context\n    )\n{\n    PKPH_MESSAGE msg;\n\n    KPH_PAGED_CODE();\n\n    msg = KphAllocateMessage();\n    if (!msg)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphAllocateMessage failed\");\n\n        return;\n    }\n\n    KphMsgInit(msg, KphpRegGetMessageId(RegClass));\n\n    msg->Kernel.Reg.Sequence = Sequence;\n\n    KphpRegFillPostOpMessage(msg, RegClass, PostInfo, Context);\n\n    if (Context->Options.EnableStackTraces)\n    {\n        KphCaptureStackInMessage(msg);\n    }\n\n    KphCommsSendMessageAsync(msg);\n}\n\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegFreeCallContext(\n    _In_ PKPH_REG_CALL_CONTEXT Context\n    )\n{\n    KPH_PAGED_CODE();\n\n    if (Context->ObjectName)\n    {\n        CmCallbackReleaseKeyObjectIDEx(Context->ObjectName);\n    }\n\n    KphFreeToPagedLookaside(&KphpCmCallContextLookaside, Context);\n}\n\n/**\n * \\brief Registry post operation callback.\n *\n * \\param[in] RegClass The registry operation class.\n * \\param[in] PostInfo The post operation information.\n * \\param[in] Sequence The registry sequence number for the post operation.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegPostOp(\n    _In_ REG_NOTIFY_CLASS RegClass,\n    _In_ PKPH_REG_POST_INFORMATION PostInfo,\n    _In_ ULONG64 Sequence\n    )\n{\n    PKPH_REG_CALL_CONTEXT context;\n\n    KPH_PAGED_CODE();\n\n    context = PostInfo->Common.CallContext;\n\n    if (context)\n    {\n        KphpRegPostOpSend(RegClass, PostInfo, Sequence, context);\n\n        KphpRegFreeCallContext(context);\n    }\n}\n\n/**\n * \\brief Sets the call context for a registry operation.\n *\n * \\details This routine sets the call context in the pre operation information\n * in preparation for the post operation to handle it.\n *\n * \\param[in] RegClass The registry operation class.\n * \\param[in] PreInfo The pre operation information.\n * \\param[in] Options Registry options to use.\n * \\param[in] Sequence The registry sequence number for the pre operation.\n * \\param[in] TimeStamp The time stamp for the pre operation.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpRegPreOpSetCallContext(\n    _In_ REG_NOTIFY_CLASS RegClass,\n    _In_ PKPH_REG_PRE_INFORMATION PreInfo,\n    _In_ PKPH_REG_OPTIONS Options,\n    _In_ ULONG64 Sequence,\n    _In_ PLARGE_INTEGER TimeStamp\n    )\n{\n    NTSTATUS status;\n    PKPH_REG_CALL_CONTEXT context;\n\n    KPH_PAGED_CODE();\n\n    context = KphAllocateFromPagedLookaside(&KphpCmCallContextLookaside);\n    if (!context)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphAllocateFromPagedLookaside failed\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    context->PreSequence = Sequence;\n    context->PreTimeStamp = *TimeStamp;\n    context->Options.Flags = Options->Flags;\n\n    if (RegClass == RegNtPreKeyHandleClose)\n    {\n        PVOID object;\n        PUNICODE_STRING* objectNamePointer;\n\n        object = PreInfo->KeyHandleClose.Object;\n\n        context->Transaction = CmGetBoundTransaction(&KphpCmCookie, object);\n\n        if (Options->EnablePostObjectNames)\n        {\n            objectNamePointer = &context->ObjectName;\n        }\n        else\n        {\n            objectNamePointer = NULL;\n        }\n\n        status = CmCallbackGetKeyObjectIDEx(&KphpCmCookie,\n                                            object,\n                                            &context->ObjectId,\n                                            objectNamePointer,\n                                            0);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"CmCallbackGetKeyObjectIDEx failed: %!STATUS!\",\n                          status);\n\n            context->ObjectId = 0;\n            context->ObjectName = NULL;\n        }\n    }\n\n    status = STATUS_SUCCESS;\n\n#define KPH_REG_SET_CALL_CONTEXT2(reg, name)                                   \\\n    case RegNtPre##reg:                                                        \\\n    {                                                                          \\\n        NT_ASSERT(!PreInfo->name.CallContext);                                 \\\n        PreInfo->name.CallContext = context;                                   \\\n        context = NULL;                                                        \\\n        break;                                                                 \\\n    }\n#define KPH_REG_SET_CALL_CONTEXT(name) KPH_REG_SET_CALL_CONTEXT2(name, name)\n\n    switch (RegClass)\n    {\n        KPH_REG_SET_CALL_CONTEXT(DeleteKey)\n        KPH_REG_SET_CALL_CONTEXT(SetValueKey)\n        KPH_REG_SET_CALL_CONTEXT(DeleteValueKey)\n        KPH_REG_SET_CALL_CONTEXT(SetInformationKey)\n        KPH_REG_SET_CALL_CONTEXT(RenameKey)\n        KPH_REG_SET_CALL_CONTEXT(EnumerateKey)\n        KPH_REG_SET_CALL_CONTEXT(EnumerateValueKey)\n        KPH_REG_SET_CALL_CONTEXT(QueryKey)\n        KPH_REG_SET_CALL_CONTEXT(QueryValueKey)\n        KPH_REG_SET_CALL_CONTEXT(QueryMultipleValueKey)\n        KPH_REG_SET_CALL_CONTEXT(KeyHandleClose)\n        KPH_REG_SET_CALL_CONTEXT2(CreateKeyEx, CreateKey)\n        KPH_REG_SET_CALL_CONTEXT2(OpenKeyEx, OpenKey)\n        KPH_REG_SET_CALL_CONTEXT(FlushKey)\n        KPH_REG_SET_CALL_CONTEXT(LoadKey)\n        KPH_REG_SET_CALL_CONTEXT(UnLoadKey)\n        KPH_REG_SET_CALL_CONTEXT(QueryKeySecurity)\n        KPH_REG_SET_CALL_CONTEXT(SetKeySecurity)\n        KPH_REG_SET_CALL_CONTEXT(RestoreKey)\n        KPH_REG_SET_CALL_CONTEXT(SaveKey)\n        KPH_REG_SET_CALL_CONTEXT(ReplaceKey)\n        KPH_REG_SET_CALL_CONTEXT(QueryKeyName)\n        KPH_REG_SET_CALL_CONTEXT(SaveMergedKey)\n        DEFAULT_UNREACHABLE;\n    }\n\nExit:\n\n    if (context)\n    {\n        KphFreeToPagedLookaside(&KphpCmCallContextLookaside, context);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Sends a pre operation message.\n *\n * \\param[in] RegClass The registry operation class.\n * \\param[in] PreInfo The pre operation information.\n * \\param[in] Options Registry options to use.\n * \\param[in] Sequence The registry sequence number for the pre operation.\n * \\param[out] TimeStamp Receives time stamp for the pre operation.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegPreOpSend(\n    _In_ REG_NOTIFY_CLASS RegClass,\n    _In_ PKPH_REG_PRE_INFORMATION PreInfo,\n    _In_ PKPH_REG_OPTIONS Options,\n    _In_ ULONG64 Sequence,\n    _Out_ PLARGE_INTEGER TimeStamp\n    )\n{\n    PKPH_MESSAGE msg;\n\n    KPH_PAGED_CODE();\n\n    msg = KphAllocateMessage();\n    if (!msg)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"KphAllocateMessage failed\");\n\n        KeQuerySystemTime(TimeStamp);\n        return;\n    }\n\n    KphMsgInit(msg, KphpRegGetMessageId(RegClass));\n    *TimeStamp = msg->Header.TimeStamp;\n    msg->Kernel.Reg.Sequence = Sequence;\n    KphpRegFillPreOpMessage(msg, RegClass, PreInfo, Options);\n\n    if (Options->EnableStackTraces)\n    {\n        KphCaptureStackInMessage(msg);\n    }\n\n    KphCommsSendMessageAsync(msg);\n}\n\n/**\n * \\brief Registry pre operation callback.\n *\n * \\param[in] RegClass The registry operation class.\n * \\param[in] PreInfo The pre operation information.\n * \\param[in] Options Registry options to use.\n * \\param[in] Sequence The registry sequence number for the pre operation.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpRegPreOp(\n    _In_ REG_NOTIFY_CLASS RegClass,\n    _In_ PKPH_REG_PRE_INFORMATION PreInfo,\n    _In_ PKPH_REG_OPTIONS Options,\n    _In_ ULONG64 Sequence\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER timeStamp;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(!Options->InPost);\n\n    if (Options->PreEnabled)\n    {\n        KphpRegPreOpSend(RegClass, PreInfo, Options, Sequence, &timeStamp);\n    }\n    else\n    {\n        //\n        // Pre operations aren't enabled, but we need the time stamp for the\n        // post operation to use.\n        //\n        KeQuerySystemTime(&timeStamp);\n    }\n\n    if (Options->PostEnabled)\n    {\n        status = KphpRegPreOpSetCallContext(RegClass,\n                                            PreInfo,\n                                            Options,\n                                            Sequence,\n                                            &timeStamp);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"KphpRegPreOpSetCallContext failed: %!STATUS!\",\n                          status);\n        }\n    }\n}\n\n/**\n * \\brief System registry callback, registered with the configuration manager.\n *\n * \\param[in] CallbackContext Unused.\n * \\param[in] Argument1 The registry operation class.\n * \\param[in] Argument2 The registry operation information.\n *\n * \\return STATUS_SUCCESS\n */\n_IRQL_requires_max_(APC_LEVEL)\n_IRQL_requires_same_\n_Function_class_(EX_CALLBACK_FUNCTION)\nNTSTATUS KphpRegistryCallback(\n    _In_ PVOID CallbackContext,\n    _In_opt_ PVOID Argument1,\n    _In_opt_ PVOID Argument2\n    )\n{\n    REG_NOTIFY_CLASS regClass;\n    ULONG64 sequence;\n    KPH_REG_OPTIONS options;\n\n    //\n    // N.B. Although Microsoft’s documentation states that registry callbacks\n    // (e.g. CmRegisterCallbackEx) are invoked at PASSIVE_LEVEL, they can and\n    // *do* get invoked at APC_LEVEL in practice.\n    //\n    // This behavior has been observed and is triggered by code in Microsoft’s\n    // own kernel components - not third-party drivers. As such, assuming\n    // callbacks always run at PASSIVE_LEVEL is unsafe. This contradicts the\n    // stated IRQL guarantees - use caution.\n    //\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(CallbackContext);\n\n    NT_ASSERT(Argument2);\n\n    regClass = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1;\n\n    if (regClass == RegNtCallbackObjectContextCleanup)\n    {\n        return STATUS_SUCCESS;\n    }\n\n    sequence = InterlockedIncrementU64(&KphpCmSequence);\n\n    options = KphpRegGetOptions(regClass);\n\n    if (options.InPost)\n    {\n        KphpRegPostOp(regClass, Argument2, sequence);\n    }\n    else\n    {\n        KphpRegPreOp(regClass, Argument2, &options, sequence);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Starts the registry informer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphRegistryInformerStart(\n    VOID\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphInitializePagedLookaside(&KphpCmCallContextLookaside,\n                                sizeof(KPH_REG_CALL_CONTEXT),\n                                KPH_TAG_REG_CALL_CONTEXT);\n\n    status = CmRegisterCallbackEx(KphpRegistryCallback,\n                                  KphAltitude,\n                                  KphDriverObject,\n                                  NULL,\n                                  &KphpCmCookie,\n                                  NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"CmRegisterCallbackEx failed: %!STATUS!\",\n                      status);\n\n        KphDeletePagedLookaside(&KphpCmCallContextLookaside);\n\n        return status;\n    }\n\n    KphpCmRegistered = TRUE;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Stops the registry informer.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphRegistryInformerStop(\n    VOID\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!KphpCmRegistered)\n    {\n        return;\n    }\n\n    status = CmUnRegisterCallback(KphpCmCookie);\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"CmUnRegisterCallback failed: %!STATUS!\",\n                      status);\n    }\n\n    KphDeletePagedLookaside(&KphpCmCallContextLookaside);\n}\n"
  },
  {
    "path": "KSystemInformer/informer_thread.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <informer.h>\n#include <comms.h>\n\n#include <trace.h>\n\ntypedef enum _KPH_THREAD_NOTIFY_TYPE\n{\n    KphThreadNotifyCreate,\n    KphThreadNotifyExecute,\n    KphThreadNotifyExit\n} KPH_THREAD_NOTIFY_TYPE;\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Performing thread tracking.\n *\n * \\param[in] ProcessId Process ID from the notification callback.\n * \\param[in] ThreadId Thread ID from the notification callback.\n * \\param[in] Create The create parameter from the notification callback.\n * \\param[in] Thread The thread object of the thread ID.\n *\n * \\return Pointer to the thread context, may be null, the caller should\n * dereference this object if it is non-null.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nPKPH_THREAD_CONTEXT KphpPerformThreadTracking(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId,\n    _In_ BOOLEAN Create,\n    _In_opt_ PETHREAD Thread\n    )\n{\n    PKPH_THREAD_CONTEXT thread;\n\n    KPH_PAGED_CODE();\n\n    if (!Create)\n    {\n        thread = KphUntrackThreadContext(ThreadId);\n        if (!thread)\n        {\n            return NULL;\n        }\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Stopped tracking thread %lu in process %wZ (%lu)\",\n                      HandleToULong(thread->ClientId.UniqueThread),\n                      KphGetThreadImageName(thread),\n                      HandleToULong(thread->ClientId.UniqueProcess));\n\n        thread->ExitNotification = TRUE;\n\n        return thread;\n    }\n\n    if (!Thread)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Failed to track thread %lu in process %lu\",\n                      HandleToULong(ThreadId),\n                      HandleToULong(ProcessId));\n\n        return NULL;\n    }\n\n    thread = KphTrackThreadContext(Thread);\n    if (!thread)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      TRACKING,\n                      \"Failed to track thread %lu in process %lu\",\n                      HandleToULong(ThreadId),\n                      HandleToULong(ProcessId));\n\n        return NULL;\n    }\n\n    thread->CreateNotification = TRUE;\n    thread->CreatorClientId.UniqueProcess = PsGetCurrentProcessId();\n    thread->CreatorClientId.UniqueThread = PsGetCurrentThreadId();\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  TRACKING,\n                  \"Tracking thread %lu in process %wZ (%lu)\",\n                  HandleToULong(thread->ClientId.UniqueThread),\n                  KphGetThreadImageName(thread),\n                  HandleToULong(thread->ClientId.UniqueProcess));\n\n    return thread;\n}\n\n/**\n * \\brief Informs any clients of thread notify routine invocations.\n *\n * \\param[in] Thread The thread being created.\n * \\param[in] ProcessId Process ID of the process where the thread is being\n * created.\n * \\param[in] ThreadID Thread ID of the thread being created.\n * \\param[in] Create If true the thread is being created, if false the thread\n * is being destroyed.\n */\n_Function_class_(PCREATE_THREAD_NOTIFY_ROUTINE)\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpCreateThreadNotifyInformer(\n    _In_ PKPH_THREAD_CONTEXT Thread,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId,\n    _In_ KPH_THREAD_NOTIFY_TYPE Type\n    )\n{\n    PKPH_MESSAGE msg;\n    PKPH_PROCESS_CONTEXT actorProcess;\n\n    KPH_PAGED_CODE();\n\n    msg = NULL;\n    actorProcess = KphGetCurrentProcessContext();\n\n    if (Type == KphThreadNotifyCreate)\n    {\n        if (!KphInformerEnabled2(ThreadCreate, actorProcess, Thread->ProcessContext))\n        {\n            goto Exit;\n        }\n\n        msg = KphAllocateMessage();\n        if (!msg)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to allocate message\");\n            goto Exit;\n        }\n\n        KphMsgInit(msg, KphMsgThreadCreate);\n        msg->Kernel.ThreadCreate.CreatingClientId.UniqueProcess = PsGetCurrentProcessId();\n        msg->Kernel.ThreadCreate.CreatingClientId.UniqueThread = PsGetCurrentThreadId();\n        msg->Kernel.ThreadCreate.CreatingProcessStartKey = KphGetCurrentProcessStartKey();\n        msg->Kernel.ThreadCreate.CreatingThreadSubProcessTag = KphGetCurrentThreadSubProcessTag();\n        msg->Kernel.ThreadCreate.TargetClientId.UniqueProcess = ProcessId;\n        msg->Kernel.ThreadCreate.TargetClientId.UniqueThread = ThreadId;\n        msg->Kernel.ThreadCreate.TargetProcessStartKey = KphGetThreadProcessStartKey(Thread->EThread);\n    }\n    else if (Type == KphThreadNotifyExecute)\n    {\n        PVOID subProcessTag;\n\n        //\n        // Call this even if the informer is disabled since this is the best\n        // place to update the cached sub-process tag in the thread context.\n        //\n        subProcessTag = KphGetCurrentThreadSubProcessTag();\n\n        if (!KphInformerEnabled2(ThreadExecute, actorProcess, Thread->ProcessContext))\n        {\n            goto Exit;\n        }\n\n        msg = KphAllocateMessage();\n        if (!msg)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to allocate message\");\n            goto Exit;\n        }\n\n        KphMsgInit(msg, KphMsgThreadExecute);\n        msg->Kernel.ThreadExecute.ClientId.UniqueProcess = ProcessId;\n        msg->Kernel.ThreadExecute.ClientId.UniqueThread = ThreadId;\n        NT_ASSERT(ProcessId == PsGetCurrentProcessId());\n        msg->Kernel.ThreadExecute.ProcessStartKey = KphGetCurrentProcessStartKey();\n        msg->Kernel.ThreadExecute.ThreadSubProcessTag = subProcessTag;\n    }\n    else\n    {\n        NT_ASSERT(Type == KphThreadNotifyExit);\n\n        if (!KphInformerEnabled2(ThreadExit, actorProcess, Thread->ProcessContext))\n        {\n            goto Exit;\n        }\n\n        msg = KphAllocateMessage();\n        if (!msg)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          INFORMER,\n                          \"Failed to allocate message\");\n            goto Exit;\n        }\n\n        KphMsgInit(msg, KphMsgThreadExit);\n        msg->Kernel.ThreadExit.ClientId.UniqueProcess = ProcessId;\n        msg->Kernel.ThreadExit.ClientId.UniqueThread = ThreadId;\n        msg->Kernel.ThreadExit.ExitStatus = PsGetThreadExitStatus(Thread->EThread);\n        NT_ASSERT(ProcessId == PsGetCurrentProcessId());\n        msg->Kernel.ThreadExit.ProcessStartKey = KphGetCurrentProcessStartKey();\n        msg->Kernel.ThreadExit.ThreadSubProcessTag = KphGetCurrentThreadSubProcessTag();\n    }\n\n    if (KphInformerOpts2(actorProcess, Thread->ProcessContext).EnableStackTraces)\n    {\n        KphCaptureStackInMessage(msg);\n    }\n\n    KphCommsSendMessageAsync(msg);\n    msg = NULL;\n\nExit:\n\n    if (msg)\n    {\n        KphFreeMessage(msg);\n    }\n\n    if (actorProcess)\n    {\n        KphDereferenceObject(actorProcess);\n    }\n}\n\n/**\n * \\brief Thread execution notify routine.\n *\n * \\param[in] ProcessId Process ID of the process where the thread is beginning\n * execution.\n * \\param[in] ThreadId Thread ID of the thread beginning execution.\n * \\param[in] Create Unused\n */\n_Function_class_(PCREATE_THREAD_NOTIFY_ROUTINE)\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpExecuteThreadNotifyRoutine(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId,\n    _In_ BOOLEAN Create\n    )\n{\n    PKPH_THREAD_CONTEXT thread;\n\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(Create);\n\n    thread = KphGetThreadContext(ThreadId);\n    if (thread)\n    {\n        thread->ExecuteNotification = TRUE;\n\n        KphpCreateThreadNotifyInformer(thread,\n                                       ProcessId,\n                                       ThreadId,\n                                       KphThreadNotifyExecute);\n\n        KphDereferenceObject(thread);\n    }\n}\n\n/**\n * \\brief Thread create notify routine.\n *\n * \\param[in] ProcessId Process ID of the process where the thread is being\n * created.\n * \\param[in] ThreadID Thread ID of the thread being created.\n * \\param[in] Create If true the thread is being created, if false the thread\n * is being destroyed.\n */\n_Function_class_(PCREATE_THREAD_NOTIFY_ROUTINE)\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpCreateThreadNotifyRoutine(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId,\n    _In_ BOOLEAN Create\n    )\n{\n    NTSTATUS status;\n    PKPH_THREAD_CONTEXT thread;\n    PETHREAD threadObject;\n\n    KPH_PAGED_CODE();\n\n    status = PsLookupThreadByThreadId(ThreadId, &threadObject);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"PsLookupThreadByThreadId failed: %!STATUS!\",\n                      status);\n\n        threadObject = NULL;\n    }\n\n    if (Create)\n    {\n        thread = KphpPerformThreadTracking(ProcessId,\n                                           ThreadId,\n                                           TRUE,\n                                           threadObject);\n        if (thread)\n        {\n            KphpCreateThreadNotifyInformer(thread,\n                                           ProcessId,\n                                           ThreadId,\n                                           KphThreadNotifyCreate);\n        }\n    }\n    else\n    {\n        thread = KphGetThreadContext(ThreadId);\n        if (thread)\n        {\n            KphpCreateThreadNotifyInformer(thread,\n                                           ProcessId,\n                                           ThreadId,\n                                           KphThreadNotifyExit);\n\n            KphDereferenceObject(thread);\n        }\n\n        thread = KphpPerformThreadTracking(ProcessId,\n                                           ThreadId,\n                                           FALSE,\n                                           threadObject);\n    }\n\n    if (thread)\n    {\n        KphDereferenceObject(thread);\n    }\n\n    if (threadObject)\n    {\n        ObDereferenceObject(threadObject);\n    }\n}\n\n/**\n * \\brief Starts the thread informer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphThreadInformerStart(\n    VOID\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = PsSetCreateThreadNotifyRoutineEx(PsCreateThreadNotifySubsystems,\n                                              (PVOID)KphpCreateThreadNotifyRoutine);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to register thread notify routine: %!STATUS!\",\n                      status);\n        return status;\n    }\n\n    status = PsSetCreateThreadNotifyRoutineEx(PsCreateThreadNotifyNonSystem,\n                                              (PVOID)KphpExecuteThreadNotifyRoutine);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      INFORMER,\n                      \"Failed to register thread notify routine: %!STATUS!\",\n                      status);\n        return status;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Stops the thread informer.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphThreadInformerStop(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    PsRemoveCreateThreadNotifyRoutine(KphpExecuteThreadNotifyRoutine);\n    PsRemoveCreateThreadNotifyRoutine(KphpCreateThreadNotifyRoutine);\n}\n"
  },
  {
    "path": "KSystemInformer/knowndll.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_KNOWN_DLL_EXPORT\n{\n    PCHAR Name;\n    PVOID* Storage;\n} KPH_KNOWN_DLL_EXPORT, *PKPH_KNOWN_DLL_EXPORT;\n\ntypedef struct _KPH_KNOWN_DLL_INFORMATION\n{\n    UNICODE_STRING SectionName;\n    PVOID* BaseAddressStorage;\n    PKPH_KNOWN_DLL_EXPORT Exports;\n} KPH_KNOWN_DLL_INFORMATION, *PKPH_KNOWN_DLL_INFORMATION;\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nPVOID KphNtDllBaseAddress = NULL;\nPVOID KphNtDllRtlSetBits = NULL;\nstatic KPH_KNOWN_DLL_EXPORT KphpNtDllExports[] =\n{\n    { \"RtlSetBits\", &KphNtDllRtlSetBits },\n    { NULL, NULL }\n};\nstatic KPH_KNOWN_DLL_INFORMATION KphpKnownDllInformation[] =\n{\n    {\n        RTL_CONSTANT_STRING(L\"\\\\KnownDlls\\\\ntdll.dll\"),\n        &KphNtDllBaseAddress,\n        KphpNtDllExports\n    }\n};\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Populates known DLL information.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphInitializeKnownDll(\n    VOID\n    )\n{\n    NTSTATUS status;\n    HANDLE sectionHandle;\n    PVOID sectionObject;\n    PVOID baseAddress;\n    SIZE_T viewSize;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    sectionHandle = NULL;\n    sectionObject = NULL;\n    baseAddress = NULL;\n\n    for (ULONG i = 0; i < ARRAYSIZE(KphpKnownDllInformation); i++)\n    {\n        PKPH_KNOWN_DLL_INFORMATION info;\n        OBJECT_ATTRIBUTES objectAttributes;\n        SECTION_IMAGE_INFORMATION sectionImageInfo;\n\n        if (baseAddress)\n        {\n            MmUnmapViewInSystemSpace(baseAddress);\n            baseAddress = NULL;\n        }\n\n        if (sectionObject)\n        {\n            ObDereferenceObject(sectionObject);\n            sectionObject = NULL;\n        }\n\n        if (sectionHandle)\n        {\n            ObCloseHandle(sectionHandle, KernelMode);\n            sectionHandle = NULL;\n        }\n\n        info = &KphpKnownDllInformation[i];\n\n        NT_ASSERT(info->BaseAddressStorage);\n\n        InitializeObjectAttributes(&objectAttributes,\n                                   &info->SectionName,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   NULL);\n\n        status = ZwOpenSection(&sectionHandle,\n                               SECTION_MAP_READ | SECTION_QUERY,\n                               &objectAttributes);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"ZwOpenSection failed: %!STATUS!\",\n                          status);\n\n\n            sectionHandle = NULL;\n            goto Exit;\n        }\n\n        status = ZwQuerySection(sectionHandle,\n                                SectionImageInformation,\n                                &sectionImageInfo,\n                                sizeof(SECTION_IMAGE_INFORMATION),\n                                NULL);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"ZwQuerySection failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        *info->BaseAddressStorage = sectionImageInfo.TransferAddress;\n\n        if (!info->Exports)\n        {\n            continue;\n        }\n\n        status = ObReferenceObjectByHandle(sectionHandle,\n                                           SECTION_MAP_READ | SECTION_QUERY,\n                                           *MmSectionObjectType,\n                                           KernelMode,\n                                           &sectionObject,\n                                           NULL);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                          status);\n\n            sectionObject = NULL;\n            goto Exit;\n        }\n\n        viewSize = 0;\n        status = MmMapViewInSystemSpace(sectionObject,\n                                        &baseAddress,\n                                        &viewSize);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"MmMapViewInSystemSpace failed: %!STATUS!\",\n                          status);\n\n            baseAddress = NULL;\n            goto Exit;\n        }\n\n        for (PKPH_KNOWN_DLL_EXPORT export = info->Exports;\n             export->Name != NULL;\n             export = export + 1)\n        {\n            PVOID exportAddress;\n\n            NT_ASSERT(export->Storage);\n\n            exportAddress = RtlFindExportedRoutineByName(baseAddress,\n                                                         export->Name);\n            if (!exportAddress)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"Failed to find %hs in %wZ\",\n                              export->Name,\n                              &info->SectionName);\n\n                status = STATUS_NOT_FOUND;\n                goto Exit;\n            }\n\n            *export->Storage = Add2Ptr(sectionImageInfo.TransferAddress,\n                                       PtrOffset(baseAddress, exportAddress));\n        }\n    }\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (baseAddress)\n    {\n        MmUnmapViewInSystemSpace(baseAddress);\n    }\n\n    if (sectionObject)\n    {\n        ObDereferenceObject(sectionObject);\n    }\n\n    if (sectionHandle)\n    {\n        ObCloseHandle(sectionHandle, KernelMode);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/kphobject.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\n#ifdef _WIN64\n#define KPH_ATOMIC_OBJECT_REF_SHARED_MAX    7\n#define KPH_ATOMIC_OBJECT_REF_EXCLUSIVE_BIT 3\n#define KPH_ATOMIC_OBJECT_REF_LOCK_MASK     0x000000000000000f\n#define KPH_ATOMIC_OBJECT_REF_OBJECT_MASK   0xfffffffffffffff0\n#else\n#define KPH_ATOMIC_OBJECT_REF_SHARED_MAX    3\n#define KPH_ATOMIC_OBJECT_REF_EXCLUSIVE_BIT 2\n#define KPH_ATOMIC_OBJECT_REF_LOCK_MASK     0x00000007\n#define KPH_ATOMIC_OBJECT_REF_OBJECT_MASK   0xfffffff8\n#endif\n#define KPH_ATOMIC_OBJECT_REF_EXCLUSIVE_FLAG (1 << KPH_ATOMIC_OBJECT_REF_EXCLUSIVE_BIT)\n\n//\n// N.B. If more object types are added the array must be expanded.\n//\nstatic KPH_OBJECT_TYPE KphpObjectTypes[16] = { 0 };\nC_ASSERT(ARRAYSIZE(KphpObjectTypes) < MAXUCHAR);\nstatic LONG KphpObjectTypeCount = 0;\nstatic KSI_WORK_QUEUE_ITEM KphpDeferDeleteObjectWorkItem;\nstatic SLIST_HEADER KphpDeferDeleteObjectList;\n\n/**\n * \\brief Carries out the deletion of an object.\n *\n * \\param[in] Header The header of an object to delete.\n */\nVOID KphpObjectDelete(\n    _In_freesMem_ PKPH_OBJECT_HEADER Header\n    )\n{\n    PKPH_OBJECT_TYPE type;\n\n    type = &KphpObjectTypes[Header->TypeIndex];\n\n    if (type->TypeInfo.Delete)\n    {\n        type->TypeInfo.Delete(KphObjectHeaderToObject(Header));\n    }\n\n    type->TypeInfo.Free(Header);\n\n    InterlockedDecrementSizeTNoFence(&type->TotalNumberOfObjects);\n}\n\n/**\n * \\brief Defers the deletion of an object.\n *\n * \\param[in] Header The header of an object to defer deletion of.\n */\nVOID KphpObjectDeferDelete(\n    _In_ PKPH_OBJECT_HEADER Header\n    )\n{\n    //\n    // Only queue the work item when the list was empty. The worker will flush\n    // the list, at that point the work item is already removed from the work\n    // queue and ready to be re-queued.\n    //\n    if (!InterlockedPushEntrySList(&KphpDeferDeleteObjectList,\n                                   &Header->ListEntry))\n    {\n        KsiQueueWorkItem(&KphpDeferDeleteObjectWorkItem, CriticalWorkQueue);\n    }\n}\n\n/**\n * \\brief Creates an object type.\n *\n * \\param[in] TypeName The name of the type, this must always be resident.\n * Preferably a string literal.\n * \\param[in] TypeInfo The information for the type being created.\n * \\param[out] ObjectType Set to a pointer to the object type on success.\n */\nVOID KphCreateObjectType(\n    _In_ PCUNICODE_STRING TypeName,\n    _In_ PKPH_OBJECT_TYPE_INFO TypeInfo,\n    _Outptr_ PKPH_OBJECT_TYPE* ObjectType\n    )\n{\n    PKPH_OBJECT_TYPE type;\n    LONG index;\n\n    index = (InterlockedIncrement(&KphpObjectTypeCount) - 1);\n\n    //\n    // We have failure free object type creation, to achieve this we have\n    // a pre-reserved sized array above. If this asserts the array wasn't\n    // expanded correctly to support a new type.\n    //\n    NT_ASSERT((index >= 0) && (index < ARRAYSIZE(KphpObjectTypes)));\n    NT_ASSERT(index < MAXUCHAR);\n\n    type = &KphpObjectTypes[index];\n\n    type->Name.Buffer = TypeName->Buffer;\n    type->Name.MaximumLength = TypeName->MaximumLength;\n    type->Name.Length = TypeName->Length;\n\n    type->Index = (UCHAR)index;\n    WriteSizeTNoFence(&type->TotalNumberOfObjects, 0);\n    WriteSizeTNoFence(&type->HighWaterNumberOfObjects, 0);\n\n    RtlCopyMemory(&type->TypeInfo, TypeInfo, sizeof(*TypeInfo));\n\n    *ObjectType = type;\n}\n\n/**\n * \\brief Creates an object of a given type.\n *\n * \\param[in] ObjectType The type of object to create.\n * \\param[in] ObjectBodySize The size of the object body to create.\n * \\param[out] Object Set to the new object on success.\n * \\param[in] Parameter Optional parameter passed to initialization routine.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphCreateObject(\n    _In_ PKPH_OBJECT_TYPE ObjectType,\n    _In_ ULONG ObjectBodySize,\n    _Outptr_result_nullonfailure_ PVOID* Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PKPH_OBJECT_HEADER header;\n    PVOID object;\n    SIZE_T total;\n\n    *Object = NULL;\n\n    header = ObjectType->TypeInfo.Allocate(KphAddObjectHeaderSize(ObjectBodySize));\n    if (!header)\n    {\n        return STATUS_INSUFFICIENT_RESOURCES;\n    }\n\n    WriteSSizeTNoFence(&header->PointerCount, 1);\n    header->TypeIndex = ObjectType->Index;\n\n    object = KphObjectHeaderToObject(header);\n\n    if (ObjectType->TypeInfo.Initialize)\n    {\n        status = ObjectType->TypeInfo.Initialize(object, Parameter);\n        if (!NT_SUCCESS(status))\n        {\n            ObjectType->TypeInfo.Free(header);\n            return status;\n        }\n    }\n\n    total = InterlockedIncrementSizeTNoFence(&ObjectType->TotalNumberOfObjects);\n\n    InterlockedExchangeIfGreaterSizeT(&ObjectType->HighWaterNumberOfObjects,\n                                      total);\n\n    *Object = object;\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief References an object.\n *\n * \\param[in] Object The object to reference.\n */\nVOID KphReferenceObject(\n    _In_ PVOID Object\n    )\n{\n    PKPH_OBJECT_HEADER header;\n\n    header = KphObjectToObjectHeader(Object);\n\n    NT_VERIFY(InterlockedIncrementSSizeTNoFence(&header->PointerCount) > 0);\n}\n\n/**\n * \\brief Dereferences an object.\n *\n * \\param[in] Object The object to dereference.\n */\nVOID KphDereferenceObject(\n    _In_ PVOID Object\n    )\n{\n    PKPH_OBJECT_HEADER header;\n    PKPH_OBJECT_TYPE type;\n    SSIZE_T refCount;\n\n    header = KphObjectToObjectHeader(Object);\n\n    refCount = InterlockedDecrementSSizeT(&header->PointerCount);\n    if (refCount > 0)\n    {\n        return;\n    }\n\n    NT_ASSERT(refCount == 0);\n\n    type = &KphpObjectTypes[header->TypeIndex];\n\n    if (type->TypeInfo.DeferDelete)\n    {\n        KphpObjectDeferDelete(header);\n    }\n    else\n    {\n        KphpObjectDelete(header);\n    }\n}\n\n/**\n * \\brief Dereferences an object and defers deletion of the object.\n *\n * \\param[in] Object The object to dereference.\n */\nVOID KphDereferenceObjectDeferDelete(\n    _In_ PVOID Object\n    )\n{\n    PKPH_OBJECT_HEADER header;\n    SSIZE_T refCount;\n\n    header = KphObjectToObjectHeader(Object);\n\n    refCount = InterlockedDecrementSSizeT(&header->PointerCount);\n    if (refCount > 0)\n    {\n        return;\n    }\n\n    NT_ASSERT(refCount == 0);\n\n    KphpObjectDeferDelete(header);\n}\n\n/**\n * \\brief Retrieves the type from an object.\n *\n * \\param[in] Object The object to get the type of.\n *\n * \\return Pointer to the type of object.\n */\n_Must_inspect_result_\nPKPH_OBJECT_TYPE KphGetObjectType(\n    _In_ PVOID Object\n    )\n{\n    PKPH_OBJECT_HEADER header;\n    UCHAR index;\n    LONG count;\n\n    header = KphObjectToObjectHeader(Object);\n    index = header->TypeIndex;\n    count = ReadAcquire(&KphpObjectTypeCount);\n\n    if (index >= count)\n    {\n        return NULL;\n    }\n\n    return &KphpObjectTypes[index];\n}\n\n//\n// Custom locking routines follow, disable pedantic prefast locking checks.\n//\n#pragma prefast(push)\n#pragma prefast(disable: 26165) // possibly failing to release lock\n#pragma prefast(disable: 26166) // possibly failing to acquire lock\n\n/**\n * \\brief Acquires the atomic object reference lock shared.\n *\n * \\param[in,out] ObjectRef The object reference to acquire the lock for.\n */\n_Requires_lock_not_held_(*ObjectRef)\n_Acquires_lock_(*ObjectRef)\nFORCEINLINE\nVOID KphpAtomicAcquireObjectLockShared(\n    _Inout_ PKPH_ATOMIC_OBJECT_REF ObjectRef\n    )\n{\n    ULONG_PTR object;\n\n    object = ReadULongPtrAcquire(&ObjectRef->Object);\n\n    for (;; YieldProcessor())\n    {\n        ULONG_PTR lock;\n        ULONG_PTR expected;\n\n        lock = object & KPH_ATOMIC_OBJECT_REF_LOCK_MASK;\n\n        if (lock >= KPH_ATOMIC_OBJECT_REF_SHARED_MAX)\n        {\n            object = ReadULongPtrAcquire(&ObjectRef->Object);\n            continue;\n        }\n\n        expected = object;\n\n        object = InterlockedCompareExchangeULongPtr(&ObjectRef->Object,\n                                                    object + 1,\n                                                    expected);\n        if (object == expected)\n        {\n            break;\n        }\n    }\n}\n\n/**\n * \\brief Releases the atomic object reference lock shared.\n *\n * \\param[in,out] ObjectRef The object reference to release the lock of.\n */\n_Requires_lock_held_(*ObjectRef)\n_Releases_lock_(*ObjectRef)\nFORCEINLINE\nVOID KphpAtomicReleaseObjectLockShared(\n    _Inout_ PKPH_ATOMIC_OBJECT_REF ObjectRef\n    )\n{\n    ULONG_PTR object;\n\n    object = InterlockedDecrementULongPtr(&ObjectRef->Object);\n\n    object = object & KPH_ATOMIC_OBJECT_REF_SHARED_MAX;\n\n    NT_ASSERT(object < KPH_ATOMIC_OBJECT_REF_SHARED_MAX);\n}\n\n/**\n * \\brief Acquires the atomic object reference lock exclusive.\n *\n * \\param[in,out] ObjectRef The object reference to acquire the lock for.\n */\n_Requires_lock_not_held_(*ObjectRef)\n_Acquires_lock_(*ObjectRef)\nFORCEINLINE\nVOID KphpAtomicAcquireObjectLockExclusive(\n    _Inout_ PKPH_ATOMIC_OBJECT_REF ObjectRef\n    )\n{\n    ULONG_PTR object;\n\n    object = ReadULongPtrAcquire(&ObjectRef->Object);\n\n    for (;; YieldProcessor())\n    {\n        ULONG_PTR locked;\n        ULONG_PTR expected;\n\n        if (object & KPH_ATOMIC_OBJECT_REF_EXCLUSIVE_FLAG)\n        {\n            object = ReadULongPtrAcquire(&ObjectRef->Object);\n            continue;\n        }\n\n        locked = object | KPH_ATOMIC_OBJECT_REF_EXCLUSIVE_FLAG;\n        expected = object;\n\n        object = InterlockedCompareExchangeULongPtr(&ObjectRef->Object,\n                                                    locked,\n                                                    expected);\n        if (object == expected)\n        {\n            break;\n        }\n    }\n\n    for (; object & KPH_ATOMIC_OBJECT_REF_SHARED_MAX; YieldProcessor())\n    {\n        object = ReadULongPtrAcquire(&ObjectRef->Object);\n    }\n}\n\n/**\n * \\brief Releases the atomic object reference lock shared.\n *\n * \\param[in,out] ObjectRef The object reference to release the lock of.\n */\n_Requires_lock_held_(*ObjectRef)\n_Releases_lock_(*ObjectRef)\nFORCEINLINE\nVOID KphpAtomicReleaseObjectLockExclusive(\n    _Inout_ PKPH_ATOMIC_OBJECT_REF ObjectRef\n    )\n{\n    BOOLEAN result;\n\n    result = InterlockedBitTestAndResetULongPtr(&ObjectRef->Object,\n                                                KPH_ATOMIC_OBJECT_REF_EXCLUSIVE_BIT);\n\n    NT_ASSERT(result);\n}\n\n#pragma prefast(pop)\n//\n// End of custom locking routines.\n//\n\n/**\n * \\brief Retrieves an addition object reference to an atomically managed\n * object reference.\n *\n * \\details This mechanism provides a light weight and fast way to atomically\n * managed a reference to an object. If an object is currently managed an\n * additional reference to that object is acquired and must be eventually\n * released by calling KphDereferenceObject.\n *\n * \\param[in] ObjectRef The object reference to retrieve the object from.\n *\n * \\return A referenced object, NULL if no object is managed.\n */\n_Must_inspect_result_\nPVOID KphAtomicReferenceObject(\n    _In_ PKPH_ATOMIC_OBJECT_REF ObjectRef\n    )\n{\n    ULONG_PTR value;\n    PVOID object;\n\n    KphpAtomicAcquireObjectLockShared(ObjectRef);\n\n    value = ReadULongPtrNoFence(&ObjectRef->Object);\n    object = (PVOID)(value & KPH_ATOMIC_OBJECT_REF_OBJECT_MASK);\n    if (object)\n    {\n        KphReferenceObject(object);\n    }\n\n    KphpAtomicReleaseObjectLockShared(ObjectRef);\n\n    return object;\n}\n\n/**\n * \\brief Stores an object to an atomically managed object reference.\n *\n * \\param[in,out] ObjectRef The object reference to assign the object to.\n * \\param[in] Object Optional object to reference and assign.\n *\n * \\return The previous object that was managed, NULL if no object was managed.\n */\n_Must_inspect_result_\nPVOID KphpAtomicStoreObjectReference(\n    _Inout_ PKPH_ATOMIC_OBJECT_REF ObjectRef,\n    _In_opt_ PVOID Object\n    )\n{\n    PVOID previous;\n    ULONG_PTR value;\n    ULONG_PTR object;\n\n    NT_ASSERT(((ULONG_PTR)Object & KPH_ATOMIC_OBJECT_REF_LOCK_MASK) == 0);\n\n    KphpAtomicAcquireObjectLockExclusive(ObjectRef);\n\n    value = ReadULongPtrNoFence(&ObjectRef->Object);\n    previous = (PVOID)(value & KPH_ATOMIC_OBJECT_REF_OBJECT_MASK);\n\n    object = (ULONG_PTR)Object | KPH_ATOMIC_OBJECT_REF_EXCLUSIVE_FLAG;\n\n    InterlockedExchangeULongPtr(&ObjectRef->Object, object);\n\n    KphpAtomicReleaseObjectLockExclusive(ObjectRef);\n\n    return previous;\n}\n\n/**\n * \\brief Assigns an object to an atomically managed object reference.\n *\n * \\details This mechanism provides a light weight and fast way to atomically\n * managed a reference to an object. Any previously managed reference will be\n * released. If an object is provided, this function will acquire an additional\n * reference to the object, the caller should still release their reference.\n *\n * \\param[in,out] ObjectRef The object reference to assign the object to.\n * \\param[in] Object Optional object to reference and assign, if NULL the\n * managed reference will be cleared.\n */\nVOID KphAtomicAssignObjectReference(\n    _Inout_ PKPH_ATOMIC_OBJECT_REF ObjectRef,\n    _In_opt_ PVOID Object\n    )\n{\n    PVOID previous;\n\n    if (Object)\n    {\n        KphReferenceObject(Object);\n    }\n\n    previous = KphpAtomicStoreObjectReference(ObjectRef, Object);\n\n    if (previous)\n    {\n        KphDereferenceObject(previous);\n    }\n}\n\n/**\n * \\brief Moves an object to an atomically managed object reference.\n *\n * \\details This mechanism provides a light weight and fast way to atomically\n * managed a reference to an object. If any object is provided, this function\n * will assume ownership over the reference, the caller should *not* release\n * their reference. If an object is returned the ownership of it is transferred\n * to the caller, the caller is responsible for eventually releasing it.\n *\n * \\param[in,out] ObjectRef The object reference to move the object into.\n * \\param[in] Object Optional object move into the object reference.\n *\n * \\return The previous object that was managed, NULL if no object was managed.\n */\n_Must_inspect_result_\nPVOID KphAtomicMoveObjectReference(\n    _Inout_ PKPH_ATOMIC_OBJECT_REF ObjectRef,\n    _In_opt_ PVOID Object\n    )\n{\n    return KphpAtomicStoreObjectReference(ObjectRef, Object);\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Worker routine for deleting objects in a deferred manner.\n *\n * \\param[in] Parameter Unused parameter.\n */\n_Function_class_(KSI_WORK_QUEUE_ROUTINE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpDeferDeleteObjectWorker(\n    _In_opt_ PVOID Parameter\n    )\n{\n    PSLIST_ENTRY entry;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(Parameter);\n\n    entry = InterlockedFlushSList(&KphpDeferDeleteObjectList);\n\n    while (entry)\n    {\n        PKPH_OBJECT_HEADER header;\n\n        header = CONTAINING_RECORD(entry, KPH_OBJECT_HEADER, ListEntry);\n\n        entry = entry->Next;\n\n        KphpObjectDelete(header);\n    }\n}\n\n/**\n * \\brief Initializes the object subsystem.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphObjectInitialize(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    InitializeSListHead(&KphpDeferDeleteObjectList);\n    KsiInitializeWorkItem(&KphpDeferDeleteObjectWorkItem,\n                          KphDriverObject,\n                          &KphpDeferDeleteObjectWorker,\n                          NULL);\n}\n"
  },
  {
    "path": "KSystemInformer/kphthread.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_THREAD_START_CONTEXT\n{\n    PKPH_THREAD_START_ROUTINE StartRoutine;\n    PVOID Parameter;\n    UNICODE_STRING ThreadName;\n} KPH_THREAD_START_CONTEXT, *PKPH_THREAD_START_CONTEXT;\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic HANDLE KphpKsiSystemProcessHandle = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Thread start routine for system threads.\n *\n * \\param[in] Context Pointer to a KPH_THREAD_START_CONTEXT.\n */\n_Function_class_(KSTART_ROUTINE)\n_IRQL_requires_same_\nVOID KphpThreadStartRoutine(\n    _In_ PVOID StartContext\n    )\n{\n    NTSTATUS status;\n    PKPH_THREAD_START_CONTEXT context;\n    PKPH_THREAD_START_ROUTINE startRoutine;\n    PVOID parameter;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    context = StartContext;\n\n    startRoutine = context->StartRoutine;\n    parameter = context->Parameter;\n\n    if (context->ThreadName.Length && !KphParameterFlags.DisableThreadNames)\n    {\n        status = ZwSetInformationThread(ZwCurrentThread(),\n                                        ThreadNameInformation,\n                                        &context->ThreadName,\n                                        sizeof(UNICODE_STRING));\n\n        if (NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Set thread (%lu) name \\\"%wZ\\\"\",\n                          HandleToULong(PsGetCurrentThreadId()),\n                          &context->ThreadName);\n        }\n        else\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Failed to set thread (%lu) name \\\"%wZ\\\": %!STATUS!\",\n                          HandleToULong(PsGetCurrentThreadId()),\n                          &context->ThreadName,\n                          status);\n        }\n    }\n\n    KphFree(context, KPH_TAG_THREAD_START_CONTEXT);\n\n    status = startRoutine(parameter);\n\n    PsTerminateSystemThread(status);\n}\n\n/**\n * \\brief Creates a system thread.\n *\n * \\param[out] ThreadHandle Optionally receives a handle to the created thread.\n * The caller must close the handle once the handle is no longer in use. The\n * handle is a kernel handle with THREAD_ALL_ACCESS access rights.\n * \\param[out] ThreadObject Optionally receives a the created thread object.\n * The caller must dereference the object once it is no longer in use.\n * \\param[in] StartRoutine The entry point for the newly created system thread.\n * \\param[in] Parameter Argument that is passed to the thread.\n * \\param[in] ThreadName Optionally specifies a name for the thread.\n * \\param[in] Flags Optional flags that control the thread creation.\n * KPH_CREATE_SYSTEM_THREAD_IN_KSI_PROCESS if possible the thread will be\n * created in a dedicated process that is used for system threads.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphCreateSystemThread(\n    _Out_opt_ PHANDLE ThreadHandle,\n    _Out_opt_ PETHREAD* ThreadObject,\n    _In_ PKPH_THREAD_START_ROUTINE StartRoutine,\n    _In_opt_ _When_(return >= 0, __drv_aliasesMem) PVOID Parameter,\n    _In_opt_ PCUNICODE_STRING ThreadName,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n    ULONG contextLength;\n    PKPH_THREAD_START_CONTEXT context;\n    HANDLE processHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (ThreadHandle)\n    {\n        *ThreadHandle = NULL;\n    }\n\n    if (ThreadObject)\n    {\n        *ThreadObject = NULL;\n    }\n\n    threadHandle = NULL;\n\n    contextLength = sizeof(KPH_THREAD_START_CONTEXT);\n    if (ThreadName)\n    {\n        contextLength += ThreadName->Length;\n    }\n\n    context = KphAllocatePaged(contextLength, KPH_TAG_THREAD_START_CONTEXT);\n    if (!context)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Failed to allocate thread start context.\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    context->StartRoutine = StartRoutine;\n    context->Parameter = Parameter;\n\n    if (ThreadName)\n    {\n        context->ThreadName.MaximumLength = ThreadName->Length;\n        context->ThreadName.Buffer = Add2Ptr(context, sizeof(KPH_THREAD_START_CONTEXT));\n        RtlCopyUnicodeString(&context->ThreadName, ThreadName);\n    }\n\n    if (FlagOn(Flags, KPH_CREATE_SYSTEM_THREAD_IN_KSI_PROCESS))\n    {\n        processHandle = KphpKsiSystemProcessHandle;\n    }\n    else\n    {\n        processHandle = NULL;\n    }\n\n    status = PsCreateSystemThread(&threadHandle,\n                                  THREAD_ALL_ACCESS,\n                                  NULL,\n                                  processHandle,\n                                  NULL,\n                                  KphpThreadStartRoutine,\n                                  context);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"PsCreateSystemThread failed: %!STATUS!\",\n                      status);\n\n        threadHandle = NULL;\n        goto Exit;\n    }\n\n    context = NULL;\n\n    if (ThreadObject)\n    {\n        NT_VERIFY(NT_SUCCESS(ObReferenceObjectByHandle(threadHandle,\n                                                       THREAD_ALL_ACCESS,\n                                                       *PsThreadType,\n                                                       KernelMode,\n                                                       ThreadObject,\n                                                       NULL)));\n    }\n\n    if (ThreadHandle)\n    {\n        *ThreadHandle = threadHandle;\n        threadHandle = NULL;\n    }\n\nExit:\n\n    if (threadHandle)\n    {\n        ObCloseHandle(threadHandle, KernelMode);\n    }\n\n    if (context)\n    {\n        KphFree(context, KPH_TAG_THREAD_START_CONTEXT);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Cleans up the threading subsystem.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupThreading(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (KphpKsiSystemProcessHandle)\n    {\n        ObCloseHandle(KphpKsiSystemProcessHandle, KernelMode);\n    }\n}\n\n/**\n * \\brief Initializes threading subsystem.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeThreading(\n    VOID\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (KphParameterFlags.DisableSystemProcess)\n    {\n        KphTracePrint(TRACE_LEVEL_INFORMATION,\n                      GENERAL,\n                      \"System process disabled.\");\n\n        return;\n    }\n\n    status = KsiInitializeSystemProcess(KphSystemProcessName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KsiInitializeSystemProcess failed: %!STATUS!\",\n                      status);\n\n        return;\n    }\n\n    status = ObOpenObjectByPointer(KsiSystemProcess,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   PROCESS_ALL_ACCESS,\n                                   *PsProcessType,\n                                   KernelMode,\n                                   &KphpKsiSystemProcessHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        KphpKsiSystemProcessHandle = NULL;\n    }\n}\n"
  },
  {
    "path": "KSystemInformer/ksidll.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <process.h>\n#include <sistatus.h>\n\n//\n// This library is intended to be an extension of core OS functionality which\n// enables drivers to perform operations within the system that would otherwise\n// be dangerous or impossible.\n//\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic BYTE KsipProtectedSection = 0;\nstatic PMM_PROTECT_DRIVER_SECTION KsipMmProtectDriverSection = NULL;\nstatic PKE_REMOVE_QUEUE_APC KsipKeRemoveQueueApc = NULL;\nstatic PZW_CREATE_PROCESS_EX KsipZwCreateProcessEx = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\nstatic KEVENT KsipDummyThreadEvent;\nstatic HANDLE KsipSystemProcessHandle = NULL;\nPEPROCESS KsiSystemProcess = NULL;\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nPVOID KsipGetSystemRoutineAddress(\n    _In_z_ PCWSTR SystemRoutineName\n    )\n{\n    UNICODE_STRING systemRoutineName;\n\n    RtlInitUnicodeString(&systemRoutineName, SystemRoutineName);\n\n    return MmGetSystemRoutineAddress(&systemRoutineName);\n}\n\n//\n// This is an extension of the APC functionality in Windows to enable a driver\n// to be unloaded while there are outstanding APCs on the system which\n// reference it.\n//\n// N.B. While this library guarantees the driver will not be unmapped, it does\n// not prevent DriverUnload from being invoked. Drivers using this library may\n// check DIRVER_OBJECT.Flags for DRVO_UNLOAD_INVOKED to know if the system has\n// or is about to invoke DriverUnload. If applicable the driver should act\n// accordingly in their routines.\n//\n// This extension guarantees that the cleanup routine will always be invoked.\n// Either due to normal APC rundown, removal, immediately after the kernel\n// routine is executed, or (in the case of normal kernel APC execution) after\n// the normal kernel routine executes. KSI_KAPC_CLEANUP_REASON indicates the\n// context in which this is called. Users may choose to implement their own\n// mechanism in the cleanup routine to synchronize with DriverUnload.\n//\n\n_Function_class_(KRUNDOWN_ROUTINE)\n_IRQL_requires_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID NTAPI KsipApcRundownRoutine(\n    _In_ PKAPC Apc\n    )\n{\n    PKSI_KAPC apc;\n    PDRIVER_OBJECT driverObject;\n    PKSI_KCLEANUP_ROUTINE cleanupRoutine;\n\n    apc = (PKSI_KAPC)Apc;\n    driverObject = apc->DriverObject;\n    cleanupRoutine = (PKSI_KCLEANUP_ROUTINE)apc->InternalCleanup;\n\n    cleanupRoutine(apc, KsiApcCleanupRundown);\n\n    ObDereferenceObjectDeferDelete(driverObject);\n}\n\n_Function_class_(KNORMAL_ROUTINE)\n_IRQL_requires_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID NTAPI KsipApcNormalRoutine(\n    _In_opt_ PVOID NormalContext,\n    _In_opt_ PVOID SystemArgument1,\n    _In_opt_ PVOID SystemArgument2\n    )\n{\n    PKSI_KAPC apc;\n    PDRIVER_OBJECT driverObject;\n    PKNORMAL_ROUTINE normalRoutine;\n    PKSI_KCLEANUP_ROUTINE cleanupRoutine;\n\n    NT_ASSERT(NormalContext);\n\n    apc = (PKSI_KAPC)NormalContext;\n    driverObject = apc->DriverObject;\n    normalRoutine = (PKNORMAL_ROUTINE)apc->InternalRoutine;\n    cleanupRoutine = (PKSI_KCLEANUP_ROUTINE)apc->InternalCleanup;\n\n    normalRoutine(apc->InternalContext, SystemArgument1, SystemArgument2);\n\n    cleanupRoutine(apc, KsiApcCleanupNormal);\n\n    ObDereferenceObjectDeferDelete(driverObject);\n}\n\n_Function_class_(KKERNEL_ROUTINE)\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID NTAPI KsipApcKernelRoutine(\n    _In_ PKAPC Apc,\n    _Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE *NormalRoutine,\n    _Inout_ _Deref_pre_maybenull_ PVOID* NormalContext,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument1,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2\n    )\n{\n    PKSI_KAPC apc;\n    PDRIVER_OBJECT driverObject;\n    PKSI_KKERNEL_ROUTINE kernelRoutine;\n    PKSI_KCLEANUP_ROUTINE cleanupRoutine;\n\n    apc = (PKSI_KAPC)Apc;\n    driverObject = apc->DriverObject;\n    kernelRoutine = (PKSI_KKERNEL_ROUTINE)apc->InternalRoutine;\n    cleanupRoutine = (PKSI_KCLEANUP_ROUTINE)apc->InternalCleanup;\n\n    kernelRoutine(apc,\n                  NormalRoutine,\n                  NormalContext,\n                  SystemArgument1,\n                  SystemArgument2);\n\n    if ((apc->Apc.ApcMode == KernelMode) && *NormalRoutine)\n    {\n        apc->InternalRoutine = (PVOID)*NormalRoutine;\n        apc->InternalContext = *NormalContext;\n        *NormalRoutine = KsipApcNormalRoutine;\n        *NormalContext = apc;\n        return;\n    }\n\n    cleanupRoutine(apc, KsiApcCleanupKernel);\n\n    ObDereferenceObjectDeferDelete(driverObject);\n}\n\nVOID KSIAPI KsiInitializeApc(\n    _Out_ PKSI_KAPC Apc,\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PRKTHREAD Thread,\n    _In_ KAPC_ENVIRONMENT Environment,\n    _In_ PKSI_KKERNEL_ROUTINE KernelRoutine,\n    _In_ PKSI_KCLEANUP_ROUTINE CleanupRoutine,\n    _In_opt_ PKNORMAL_ROUTINE NormalRoutine,\n    _In_ KPROCESSOR_MODE Mode,\n    _In_opt_ PVOID NormalContext\n    )\n{\n    KeInitializeApc(&Apc->Apc,\n                    Thread,\n                    Environment,\n                    KsipApcKernelRoutine,\n                    KsipApcRundownRoutine,\n                    NormalRoutine,\n                    Mode,\n                    NormalContext);\n\n    Apc->DriverObject = DriverObject;\n    Apc->InternalRoutine = (PVOID)KernelRoutine;\n    Apc->InternalCleanup = (PVOID)CleanupRoutine;\n    Apc->InternalContext = NULL;\n}\n\nBOOLEAN KSIAPI KsiInsertQueueApc(\n    _Inout_ PKSI_KAPC Apc,\n    _In_opt_ PVOID SystemArgument1,\n    _In_opt_ PVOID SystemArgument2,\n    _In_ KPRIORITY PriorityBoost\n    )\n{\n    BOOLEAN result;\n\n    ObReferenceObject(Apc->DriverObject);\n\n    result = KeInsertQueueApc(&Apc->Apc,\n                              SystemArgument1,\n                              SystemArgument2,\n                              PriorityBoost);\n    if (!result)\n    {\n        ObDereferenceObject(Apc->DriverObject);\n    }\n\n    return result;\n}\n\nNTSTATUS KSIAPI KsiRemoveQueueApc(\n    _Inout_ PKSI_KAPC Apc\n    )\n{\n    PDRIVER_OBJECT driverObject;\n    PKSI_KCLEANUP_ROUTINE cleanupRoutine;\n\n    if (!KsipKeRemoveQueueApc)\n    {\n        return STATUS_NOINTERFACE;\n    }\n\n    if (!KsipKeRemoveQueueApc(&Apc->Apc))\n    {\n        return STATUS_INVALID_STATE_TRANSITION;\n    }\n\n    driverObject = Apc->DriverObject;\n    cleanupRoutine = (PKSI_KCLEANUP_ROUTINE)Apc->InternalCleanup;\n\n    cleanupRoutine(Apc, KsiApcCleanupRemoved);\n\n    ObDereferenceObjectDeferDelete(driverObject);\n\n    return STATUS_SUCCESS;\n}\n\n//\n// This is an extension of the work queue functionality in Windows to enable a\n// driver to be unloaded while there are outstanding queued work items on the\n// system with which reference it.\n//\n// N.B. WORK_QUEUE_ITEM and IO_WORKITEM are not equivalent. WORK_QUEUE_ITEM does\n// not provide a mechanism to reference an object associated with the driver\n// that queued the work item. IO_WORKITEM does, but its implementation for work\n// scheduling and accounting differs. They are not interchangeable. Therefore,\n// this implementation adds support for associating a driver object with a\n// WORK_QUEUE_ITEM.\n//\n// N.B. While this library guarantees the driver will not be unmapped, it does\n// not prevent DriverUnload from being invoked. Drivers using this library may\n// check DIRVER_OBJECT.Flags for DRVO_UNLOAD_INVOKED to know if the system has\n// or is about to invoke DriverUnload. If applicable the driver should act\n// accordingly in their routines.\n//\n\n_Function_class_(WORKER_THREAD_ROUTINE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID KsipWorkItemRoutine(\n    _In_ PVOID Parameter\n    )\n{\n    PKSI_WORK_QUEUE_ITEM workItem;\n    PDRIVER_OBJECT driverObject;\n    PKSI_WORK_QUEUE_ROUTINE routine;\n\n    workItem = Parameter;\n    driverObject = workItem->DriverObject;\n    routine = workItem->Routine;\n\n    routine(workItem->Parameter);\n\n    ObDereferenceObjectDeferDelete(driverObject);\n}\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KSIAPI KsiInitializeWorkItem(\n    _Out_ PKSI_WORK_QUEUE_ITEM WorkItem,\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PKSI_WORK_QUEUE_ROUTINE Routine,\n    _In_opt_ PVOID Parameter\n    )\n{\n    WorkItem->DriverObject = DriverObject;\n    WorkItem->Routine = Routine;\n    WorkItem->Parameter = Parameter;\n\n#pragma warning(suppress: 4996)\n    ExInitializeWorkItem(&WorkItem->WorkItem, KsipWorkItemRoutine, WorkItem);\n}\n\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KSIAPI KsiQueueWorkItem(\n    _Inout_ PKSI_WORK_QUEUE_ITEM WorkItem,\n    _In_ WORK_QUEUE_TYPE QueueType\n    )\n{\n    ObReferenceObject(WorkItem->DriverObject);\n\n#pragma prefast(push)\n#pragma prefast(disable: 28159) // obsolete function\n#pragma warning(suppress: 4996)\n    ExQueueWorkItem(&WorkItem->WorkItem, QueueType);\n#pragma prefast(pop)\n}\n\n//\n// This is an extension that allows a minimal system process to be created.\n// Minimal processes must be terminated using PsTerminateMinimalProcess, but\n// this routine is not exported or accessible through normal means. If a minimal\n// process is deleted without first calling PsTerminateMinimalProcess, the\n// system will bug check with INVALID_MINIMAL_PROCESS_STATE.\n//\n// This implementation creates and exposes a minimal system process object that\n// the System Informer driver can use. To work around the limitation, the\n// lifetime of this process object is managed by this pinned module. This allows\n// System Informer to reuse the existing minimal process object without needing\n// to terminate it.\n//\n// As a result, the minimal process object is effectively \"leaked\" and requires\n// a system reboot to be removed. This is currently the most practical approach\n// until Microsoft provides official APIs for drivers to manage minimal\n// processes more appropriately.\n//\n// N.B. This implementation makes some assumptions. It assumes that the current\n// process is PsInitialSystemProcess. And the routine is not thread safe. It\n// should be used only by System Informer during driver initialization.\n//\n\n_IRQL_requires_same_\n_Function_class_(KSTART_ROUTINE)\nVOID KsipDummyThreadRoutine(\n    _In_ PVOID StartContext\n    )\n{\n    UNREFERENCED_PARAMETER(StartContext);\n\n    //\n    // This dummy thread ensures the process remains active. This is the same\n    // pattern that the Registry process uses to keep itself active (without a\n    // call to KeBugCheckEx if the wait returns).\n    //\n\n    KeWaitForSingleObject(&KsipDummyThreadEvent,\n                          Executive,\n                          KernelMode,\n                          FALSE,\n                          NULL);\n\n    PsTerminateSystemThread(STATUS_SUCCESS);\n}\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KSIAPI KsiInitializeSystemProcess(\n    _In_ PCUNICODE_STRING ProcessName\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    NT_ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);\n\n    if (!KsipZwCreateProcessEx)\n    {\n        return STATUS_NOINTERFACE;\n    }\n\n    if (KsiSystemProcess)\n    {\n        return STATUS_SUCCESS;\n    }\n\n    threadHandle = NULL;\n\n    if (!KsipSystemProcessHandle)\n    {\n        HANDLE processHandle;\n\n        InitializeObjectAttributes(&objectAttributes,\n                                   (PUNICODE_STRING)ProcessName,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   NULL);\n\n        status = KsipZwCreateProcessEx(&processHandle,\n                                       PROCESS_ALL_ACCESS,\n                                       &objectAttributes,\n                                       ZwCurrentProcess(),\n                                       PROCESS_CREATE_FLAGS_MINIMAL_PROCESS,\n                                       NULL,\n                                       NULL,\n                                       NULL,\n                                       0);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n\n        //\n        // N.B. We cannot close the handle at this point, as there is no clean\n        // way to call PsTerminateMinimalProcess. Closing the handle risks\n        // triggering a bug check with INVALID_MINIMAL_PROCESS_STATE. If we fail\n        // below, the process object pointer (KsiSystemProcess) will remain\n        // NULL, allowing us to re-enter this path and try again - though it\n        // will likely continue to fail.\n        //\n        KsipSystemProcessHandle = processHandle;\n    }\n\n    InitializeObjectAttributes(&objectAttributes,\n                               NULL,\n                               OBJ_KERNEL_HANDLE,\n                               NULL,\n                               NULL);\n\n    status = PsCreateSystemThread(&threadHandle,\n                                  THREAD_ALL_ACCESS,\n                                  &objectAttributes,\n                                  KsipSystemProcessHandle,\n                                  NULL,\n                                  KsipDummyThreadRoutine,\n                                  NULL);\n    if (!NT_SUCCESS(status))\n    {\n        threadHandle = NULL;\n        goto Exit;\n    }\n\n    NT_VERIFY(NT_SUCCESS(ObReferenceObjectByHandle(KsipSystemProcessHandle,\n                                                   PROCESS_ALL_ACCESS,\n                                                   *PsProcessType,\n                                                   KernelMode,\n                                                   &KsiSystemProcess,\n                                                   NULL)));\n\nExit:\n\n    if (threadHandle)\n    {\n        ObCloseHandle(threadHandle, KernelMode);\n    }\n\n    return status;\n}\n\n//\n// General Library Functions\n//\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KsiInitialize(\n    _In_ ULONG Version,\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_opt_ PVOID Reserved\n    )\n{\n    UNREFERENCED_PARAMETER(DriverObject);\n    UNREFERENCED_PARAMETER(Reserved);\n\n    if (Version != KSIDLL_CURRENT_VERSION)\n    {\n        return STATUS_SI_KSIDLL_VERSION_MISMATCH;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KsiUninitialize(\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ ULONG Reserved\n    )\n{\n    UNREFERENCED_PARAMETER(DriverObject);\n    UNREFERENCED_PARAMETER(Reserved);\n}\n\nNTSTATUS DllUnload(\n    VOID\n    )\n{\n    //\n    // N.B. It used to be that not specifying a DllUnload routine would\n    // enforce that your export driver can not be unloaded by not activating\n    // the reference count mechanism. 10.0.25997.1010 changed this so if you\n    // do not specify DllUnload the driver can be unmapped. This is resolved\n    // by implementing DllUnload and returning an error.\n    //\n    return STATUS_NOT_SUPPORTED;\n}\n\nNTSTATUS DllInitialize(\n    _In_ PUNICODE_STRING RegistryPath\n    )\n{\n    UNREFERENCED_PARAMETER(RegistryPath);\n\n    __security_init_cookie();\n\n    ExInitializeDriverRuntime(DrvRtPoolNxOptIn);\n\n    KeInitializeEvent(&KsipDummyThreadEvent, SynchronizationEvent, FALSE);\n\n    KsipMmProtectDriverSection = (PMM_PROTECT_DRIVER_SECTION)KsipGetSystemRoutineAddress(L\"MmProtectDriverSection\");\n    KsipKeRemoveQueueApc = (PKE_REMOVE_QUEUE_APC)KsipGetSystemRoutineAddress(L\"KeRemoveQueueApc\");\n    KsipZwCreateProcessEx = (PZW_CREATE_PROCESS_EX)KsipGetSystemRoutineAddress(L\"ZwCreateProcessEx\");\n\n    if (KsipMmProtectDriverSection)\n    {\n        KsipMmProtectDriverSection(&KsipProtectedSection, 0, 0);\n    }\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "KSystemInformer/ksidll.def",
    "content": "LIBRARY ksi.dll\nEXPORTS\n    DllInitialize                 PRIVATE\n    DllUnload                     PRIVATE\n    KsiInitialize\n    KsiUninitialize\n    KsiInitializeApc\n    KsiInsertQueueApc\n    KsiRemoveQueueApc\n    KsiInitializeWorkItem\n    KsiQueueWorkItem\n    KsiInitializeSystemProcess\n    KsiSystemProcess              DATA\n"
  },
  {
    "path": "KSystemInformer/ksidll.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>17.0</VCProjectVersion>\n    <ProjectGuid>{B385D394-19CC-48BC-827E-AF9ADCE559E0}</ProjectGuid>\n    <TemplateGuid>{dd38f7fc-d7bd-488b-9242-7d8754cde80d}</TemplateGuid>\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <RootNamespace>KSystemInformer</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <IntDir>$(SystemInformerRoot)KSystemInformer\\obj\\$(Configuration)$(PlatformArchitecture)\\$(ProjectName)\\</IntDir>\n    <OutDir>$(SystemInformerRoot)KSystemInformer\\bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <TargetName>ksi</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>_KSIDLL_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <NoEntryPoint>true</NoEntryPoint>\n      <ModuleDefinitionFile>ksidll.def</ModuleDefinitionFile>\n    </Link>\n    <ResourceCompile>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SystemInformerRoot)kphlib\\include\\;</AdditionalIncludeDirectories>\n    </ResourceCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"resource.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"ksidll.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"ksidll.def\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>\n"
  },
  {
    "path": "KSystemInformer/lsa.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2024-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpLsaPortName = RTL_CONSTANT_STRING(L\"\\\\SeLsaCommandPort\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nstatic HANDLE KphpLsassProcessId = NULL;\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Retrieves the process ID of lsass.\n *\n * \\param[out] ProcessId Set to the process ID of lsass.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphpGetLsassProcessId(\n    _Out_ PHANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    KIRQL currentIrql;\n    PKPH_DYN dyn;\n    HANDLE portHandle;\n    KAPC_STATE apcState;\n    KPH_ALPC_COMMUNICATION_INFORMATION info;\n\n    KPH_PAGED_CODE();\n\n    //\n    // We cache the process ID of lsass since opening and closing the connection\n    // port frequently can cause significant performance degradation. This cache\n    // is invalidated when:\n    //\n    // - A process exits and the process ID is what was cached.\n    // - The process does not have SeCreateTokenPrivilege.\n    //\n    // N.B. The privilege check is always performed when checking if a process\n    // is lsass, even when the cached process ID is used.\n    //\n\n    *ProcessId = InterlockedCompareExchangePointer(&KphpLsassProcessId,\n                                                   NULL,\n                                                   NULL);\n    if (*ProcessId)\n    {\n        return STATUS_SUCCESS;\n    }\n\n    currentIrql = KeGetCurrentIrql();\n    if (currentIrql > PASSIVE_LEVEL)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphpGetLsassProcessId called at %!irql!\",\n                      currentIrql);\n\n        return STATUS_INVALID_LEVEL;\n    }\n\n    //\n    // N.B. This is an optimization. In order to query the process ID of lsass\n    // through the LSA port, we need the dynamic data. Rather than doing the\n    // work to attach to the system process and open the port, if we know we\n    // do not have the dynamic data, exit early.\n    //\n    dyn = KphReferenceDynData();\n    if (!dyn)\n    {\n        return STATUS_NOINTERFACE;\n    }\n\n    //\n    // Attach to system to ensure we get a kernel handle from the following\n    // ZwAlpcConnectPort call. Opening the handle here does not ask for the\n    // object attributes. To keep our imports simple we choose to use this\n    // over the Ex version (might change in the future). Pattern is adopted\n    // from msrpc.sys.\n    //\n\n    KeStackAttachProcess(PsInitialSystemProcess, &apcState);\n\n    status = ZwAlpcConnectPort(&portHandle,\n                               (PUNICODE_STRING)&KphpLsaPortName,\n                               NULL,\n                               NULL,\n                               0,\n                               NULL,\n                               NULL,\n                               NULL,\n                               NULL,\n                               NULL,\n                               NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ZwAlpcConnectPort failed: %!STATUS!\",\n                      status);\n\n        portHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphAlpcQueryInformation(ZwCurrentProcess(),\n                                     portHandle,\n                                     KphAlpcCommunicationInformation,\n                                     &info,\n                                     sizeof(KPH_ALPC_COMMUNICATION_INFORMATION),\n                                     NULL,\n                                     KernelMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphAlpcQueryInformation failed: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    *ProcessId = info.ConnectionPort.OwnerProcessId;\n\nExit:\n\n    if (portHandle)\n    {\n        ObCloseHandle(portHandle, KernelMode);\n    }\n\n    KeUnstackDetachProcess(&apcState);\n\n    KphDereferenceObject(dyn);\n\n    return status;\n}\n\n/**\n * \\brief Caches the lsass process ID if appropriate.\n *\n * \\param[in] Process Optional lsass process object.\n * \\param[in] ProcessId The lsass process ID to cache.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphpCacheLsassProcessId(\n    _In_opt_ PEPROCESS Process,\n    _In_ HANDLE ProcessId\n    )\n{\n    PEPROCESS process;\n\n    KPH_PAGED_CODE();\n\n    if (ReadPointerAcquire(&KphpLsassProcessId) == ProcessId)\n    {\n        return;\n    }\n\n    if (Process)\n    {\n        process = Process;\n    }\n    else if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &process)))\n    {\n        return;\n    }\n\n    NT_ASSERT(PsGetProcessId(process) == ProcessId);\n\n    if (NT_SUCCESS(PsAcquireProcessExitSynchronization(process)))\n    {\n        InterlockedExchangePointer(&KphpLsassProcessId, ProcessId);\n        PsReleaseProcessExitSynchronization(process);\n    }\n\n    if (process != Process)\n    {\n        ObDereferenceObject(process);\n    }\n}\n\n/**\n * \\brief Checks if a given process is lsass.\n *\n * \\param[in] Process The process to check.\n * \\param[out] IsLsass TRUE if the process is lsass, FALSE otherwise.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphProcessIsLsass(\n    _In_ PEPROCESS Process,\n    _Out_ PBOOLEAN IsLsass\n    )\n{\n    NTSTATUS status;\n    PS_PROTECTION processProtection;\n    HANDLE processId;\n    SECURITY_SUBJECT_CONTEXT subjectContext;\n    BOOLEAN result;\n\n    KPH_PAGED_CODE();\n\n    *IsLsass = FALSE;\n\n    processProtection = PsGetProcessProtection(Process);\n\n    if ((processProtection.Type != PsProtectedTypeNone) &&\n        (processProtection.Signer == PsProtectedSignerLsa))\n    {\n        processId = PsGetProcessId(Process);\n\n        KphpCacheLsassProcessId(Process, processId);\n    }\n    else\n    {\n        status = KphpGetLsassProcessId(&processId);\n        if (!NT_SUCCESS(status))\n        {\n            return status;\n        }\n\n        KphpCacheLsassProcessId(NULL, processId);\n\n        if (processId != PsGetProcessId(Process))\n        {\n            return STATUS_SUCCESS;\n        }\n    }\n\n    SeCaptureSubjectContextEx(NULL, Process, &subjectContext);\n    result = KphSinglePrivilegeCheckEx(SeCreateTokenPrivilege,\n                                       &subjectContext,\n                                       UserMode);\n    SeReleaseSubjectContext(&subjectContext);\n    if (result)\n    {\n        *IsLsass = TRUE;\n    }\n    else\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"PID %lu does not have SeCreateTokenPrivilege\",\n                      HandleToULong(processId));\n\n        InterlockedExchangePointer(&KphpLsassProcessId, NULL);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Validates if a process is lsass and caches it.\n *\n * \\details This should be called whenever a new process is identified.\n *\n * \\param[in] Process The process to validate.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphValidateLsass(\n    _In_ PEPROCESS Process\n    )\n{\n    NTSTATUS status;\n    BOOLEAN isLsass;\n\n    KPH_PAGED_CODE();\n\n    status = KphProcessIsLsass(Process, &isLsass);\n    if (NT_SUCCESS(status) && isLsass)\n    {\n        KphTracePrint(TRACE_LEVEL_INFORMATION,\n                      GENERAL,\n                      \"Validated LSA process (%lu)\",\n                      HandleToULong(PsGetProcessId(Process)));\n    }\n}\n\n/**\n * \\brief Invalidates the cached lsass process ID if it matches.\n *\n * \\details This should be called whenever a process ID could be recycled.\n *\n * \\param[in] Process The process to invalidate.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInvalidateLsass(\n    _In_ PEPROCESS Process\n    )\n{\n    HANDLE processId;\n\n    KPH_PAGED_CODE();\n\n    processId = PsGetProcessId(Process);\n\n    if (InterlockedCompareExchangePointer(&KphpLsassProcessId,\n                                          NULL,\n                                          processId) == processId)\n    {\n        KphTracePrint(TRACE_LEVEL_INFORMATION,\n                      GENERAL,\n                      \"Invalidated LSA process (%lu)\",\n                      HandleToULong(processId));\n    }\n}\n\n/**\n * \\brief Checks if lsass can be identified.\n *\n * \\return TRUE if lsass can be identified, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphCanIdentifyLsass(\n    VOID\n    )\n{\n    NTSTATUS status;\n    BOOLEAN isLsass;\n\n    KPH_PAGED_CODE();\n\n    //\n    // N.B. It does not matter what process we use here and we intentionally\n    // ignore the output boolean. What matters is the return succeeds which\n    // indicates that we can identify lsass.\n    //\n    status = KphProcessIsLsass(PsInitialSystemProcess, &isLsass);\n\n    return NT_SUCCESS(status);\n}\n"
  },
  {
    "path": "KSystemInformer/main.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     jxy-s   2021-2026\n *\n */\n\n#include <kph.h>\n#include <informer.h>\n\n#include <trace.h>\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const BYTE KphpProtectedSectionReadOnly = 0;\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic BYTE KphpProtectedSection = 0;\nPDRIVER_OBJECT KphDriverObject = NULL;\nRTL_OSVERSIONINFOEXW KphOsVersionInfo = { 0 };\nKPH_FILE_VERSION KphKernelVersion = { 0 };\nBOOLEAN KphIgnoreProtectionsSuppressed = FALSE;\nBOOLEAN KphIgnoreTestSigningEnabled = FALSE;\nSYSTEM_SECUREBOOT_INFORMATION KphSecureBootInfo = { 0 };\nSYSTEM_CODEINTEGRITY_INFORMATION KphCodeIntegrityInfo = { 0 };\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Protects select sections.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpProtectSections(\n    VOID\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (!KphDynMmProtectDriverSection)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"MmProtectDriverSection not found\");\n\n        return;\n    }\n\n    status = KphDynMmProtectDriverSection(&KphpProtectedSection,\n                                          0,\n                                          MM_PROTECT_DRIVER_SECTION_ALLOW_UNLOAD);\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  GENERAL,\n                  \"MmProtectDriverSection %!STATUS!\",\n                  status);\n\n    status = KphDynMmProtectDriverSection((PVOID)&KphpProtectedSectionReadOnly,\n                                          0,\n                                          MM_PROTECT_DRIVER_SECTION_ALLOW_UNLOAD);\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  GENERAL,\n                  \"MmProtectDriverSection %!STATUS!\",\n                  status);\n}\n\n/**\n * \\brief Cleans up the driver state.\n *\n * \\param[in] DriverObject Driver object of this driver.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpDriverCleanup(\n    _In_ PDRIVER_OBJECT DriverObject\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphDebugInformerStop();\n    KphRegistryInformerStop();\n    KphObjectInformerStop();\n    KphImageInformerStop();\n    KphCidMarkPopulated();\n    KphThreadInformerStop();\n    KphProcessInformerStop();\n    KphFltUnregister();\n    KphCidCleanup();\n    KphCleanupInformer();\n    KphCleanupDynData();\n    KphCleanupVerify();\n    KphCleanupHashing();\n    KphCleanupThreading();\n    KphCleanupParameters();\n\n    KsiUninitialize(DriverObject, 0);\n}\n\n/**\n * \\brief Driver unload routine.\n *\n * \\param[in] DriverObject Driver object of this driver.\n */\n_Function_class_(DRIVER_UNLOAD)\n_IRQL_requires_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID DriverUnload(\n    _In_ PDRIVER_OBJECT DriverObject\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphTracePrint(TRACE_LEVEL_INFORMATION, GENERAL, \"Driver Unloading...\");\n\n    KphpDriverCleanup(DriverObject);\n\n    KphTracePrint(TRACE_LEVEL_INFORMATION, GENERAL, \"Driver Unloaded\");\n\n    WPP_CLEANUP(DriverObject);\n}\n\n/**\n * \\brief Driver entry point.\n *\n * \\param[in] DriverObject Driver object for this driver.\n * \\param[in] RegistryPath Registry path for this driver.\n *\n * \\return Successful or errant status.\n */\n_Function_class_(DRIVER_INITIALIZE)\n_IRQL_requires_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nNTSTATUS DriverEntry(\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PUNICODE_STRING RegistryPath\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    WPP_INIT_TRACING(DriverObject, RegistryPath);\n\n    KphTracePrint(TRACE_LEVEL_INFORMATION, GENERAL, \"Driver Loading...\");\n\n    KphDriverObject = DriverObject;\n    KphDriverObject->DriverUnload = DriverUnload;\n\n    ExInitializeDriverRuntime(DrvRtPoolNxOptIn);\n\n    status = KsiInitialize(KSIDLL_CURRENT_VERSION, DriverObject, NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"KsiInitialize failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    KphOsVersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);\n    status = RtlGetVersion((PRTL_OSVERSIONINFOW)&KphOsVersionInfo);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"RtlGetVersion failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (!NT_SUCCESS(ZwQuerySystemInformation(SystemSecureBootInformation,\n                                             &KphSecureBootInfo,\n                                             sizeof(KphSecureBootInfo),\n                                             NULL)))\n    {\n        RtlZeroMemory(&KphSecureBootInfo, sizeof(KphSecureBootInfo));\n    }\n\n    KphCodeIntegrityInfo.Length = sizeof(KphCodeIntegrityInfo);\n    if (!NT_SUCCESS(ZwQuerySystemInformation(SystemCodeIntegrityInformation,\n                                             &KphCodeIntegrityInfo,\n                                             sizeof(KphCodeIntegrityInfo),\n                                             NULL)))\n    {\n        RtlZeroMemory(&KphCodeIntegrityInfo, sizeof(KphCodeIntegrityInfo));\n    }\n\n    if (KphInDeveloperMode())\n    {\n        KphTracePrint(TRACE_LEVEL_INFORMATION, GENERAL, \"Developer Mode\");\n    }\n\n    KphDynamicImport();\n    KphObjectInitialize();\n    KphInitializeRingBuffer();\n    KphInitializeParameters(RegistryPath);\n    KphInitializeAlloc();\n    KphInitializeThreading();\n\n    status = KphInitializeKnownDll();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"KphInitializeKnownDll failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = KphGetKernelVersion(&KphKernelVersion);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"KphGetKernelVersion failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_INFORMATION,\n                  GENERAL,\n                  \"Windows %lu.%lu.%lu Kernel %lu.%lu.%lu.%lu\",\n                  KphOsVersionInfo.dwMajorVersion,\n                  KphOsVersionInfo.dwMinorVersion,\n                  KphOsVersionInfo.dwBuildNumber,\n                  KphKernelVersion.MajorVersion,\n                  KphKernelVersion.MinorVersion,\n                  KphKernelVersion.BuildNumber,\n                  KphKernelVersion.Revision);\n\n    status = KphInitializeHashing();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to initialize hashing: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = KphInitializeVerify();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to initialize verify: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    KphInitializeDynData();\n    KphInitializeProtection();\n    KphInitializeSessionToken();\n\n    status = KphInitializeStackBackTrace();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to initialize stack back trace: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = KphInitializeInformer();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to initialize informer: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = KphFltRegister(DriverObject, RegistryPath);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to register mini-filter: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    status = KphCidInitialize();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to initialize CID tracking: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    status = KphProcessInformerStart();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to start process informer: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    status = KphThreadInformerStart();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to start thread informer: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    status = KphCidPopulate();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to populate CID tracking: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    KphCidMarkPopulated();\n\n    status = KphFltInformerStart();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to start mini-filter informer: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    status = KphImageInformerStart();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to start image informer: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    status = KphObjectInformerStart();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to start object informer: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    status = KphRegistryInformerStart();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to start registry informer: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    status = KphDebugInformerStart();\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Failed to start debug informer: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    KphpProtectSections();\n\nExit:\n\n    if (NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_INFORMATION, GENERAL, \"Driver Loaded\");\n    }\n    else\n    {\n        KphTracePrint(TRACE_LEVEL_ERROR,\n                      GENERAL,\n                      \"Driver Load Failed: %!STATUS!\",\n                      status);\n\n        KphpDriverCleanup(DriverObject);\n\n        WPP_CLEANUP(DriverObject);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/object.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     jxy-s   2021-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_ENUMERATE_PROCESS_HANDLES_CONTEXT\n{\n    PKPH_DYN Dyn;\n    KPROCESSOR_MODE AccessMode;\n    PVOID Buffer;\n    PVOID BufferLimit;\n    PVOID CurrentEntry;\n    ULONG Count;\n    NTSTATUS Status;\n} KPH_ENUMERATE_PROCESS_HANDLES_CONTEXT, *PKPH_ENUMERATE_PROCESS_HANDLES_CONTEXT;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpEtwRegistrationName = RTL_CONSTANT_STRING(L\"EtwRegistration\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\n\n_Must_inspect_result_\nPVOID KphObpDecodeObject(\n    _In_ PKPH_DYN Dyn,\n    _In_ PHANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n#if defined(_M_X64) || defined(_M_ARM64)\n    if (Dyn->ObDecodeShift != ULONG_MAX)\n    {\n        LONG_PTR object;\n\n        object = (LONG_PTR)(HandleTableEntry->Object);\n\n        //\n        // Decode the object pointer, shift back up the lower nibble to zeros.\n        // N.B. LA57 is special but the way we define HANDLE_TABLE_ENTRY and\n        // use dynamic data supports it.\n        //\n        object >>= Dyn->ObDecodeShift;\n        object <<= 4;\n\n        return (PVOID)object;\n    }\n    else\n    {\n        return NULL;\n    }\n#else\n    return (PVOID)((ULONG_PTR)(HandleTableEntry->Object) & ~OBJ_HANDLE_ATTRIBUTES);\n#endif\n}\n\nULONG KphObpGetHandleAttributes(\n    _In_ PKPH_DYN Dyn,\n    _In_ PHANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n#if defined(_M_X64) || defined(_M_ARM64)\n    if (Dyn->ObAttributesShift != ULONG_MAX)\n    {\n        return (ULONG)(HandleTableEntry->Value >> Dyn->ObAttributesShift) & 0x3;\n    }\n    else\n    {\n        return 0;\n    }\n#else\n    return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) |\n        ((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0);\n#endif\n}\n\n/**\n * \\brief Retrieves information about a file object.\n *\n * \\param[in] FileObject The file object to retrieve information for.\n * \\param[out] Information Receives the file object information.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpGetFileObjectInformation(\n    _In_ PFILE_OBJECT FileObject,\n    _Out_ PKPH_FILE_OBJECT_INFORMATION Information\n    )\n{\n    PDEVICE_OBJECT attachedDevice;\n    PDEVICE_OBJECT relatedDevice;\n    KIRQL irql;\n    PVPB vpb;\n\n    //\n    // VPB lock will be acquired, code placed in non-paged segment on purpose.\n    //\n    KPH_NPAGED_CODE_PASSIVE();\n\n    attachedDevice = IoGetAttachedDevice(FileObject->DeviceObject);\n    relatedDevice = IoGetRelatedDeviceObject(FileObject);\n\n    RtlZeroMemory(Information, sizeof(KPH_FILE_OBJECT_INFORMATION));\n\n    Information->LockOperation = FileObject->LockOperation;\n    Information->DeletePending = FileObject->DeletePending;\n    Information->ReadAccess = FileObject->ReadAccess;\n    Information->WriteAccess = FileObject->WriteAccess;\n    Information->DeleteAccess = FileObject->DeleteAccess;\n    Information->SharedRead = FileObject->SharedRead;\n    Information->SharedWrite = FileObject->SharedWrite;\n    Information->SharedDelete = FileObject->SharedDelete;\n    Information->CurrentByteOffset = FileObject->CurrentByteOffset;\n    Information->Flags = FileObject->Flags;\n    if (FileObject->SectionObjectPointer)\n    {\n        Information->UserWritableReferences =\n            MmDoesFileHaveUserWritableReferences(FileObject->SectionObjectPointer);\n    }\n    Information->HasActiveTransaction =\n        (IoGetTransactionParameterBlock(FileObject) ? TRUE : FALSE);\n    Information->IsIgnoringSharing = IoIsFileObjectIgnoringSharing(FileObject);\n    Information->Waiters = FileObject->Waiters;\n    Information->Busy = FileObject->Busy;\n\n    Information->Device.Type = FileObject->DeviceObject->DeviceType;\n    Information->Device.Characteristics = FileObject->DeviceObject->Characteristics;\n    Information->Device.Flags = FileObject->DeviceObject->Flags;\n\n    Information->AttachedDevice.Type = attachedDevice->DeviceType;\n    Information->AttachedDevice.Characteristics = attachedDevice->Characteristics;\n    Information->AttachedDevice.Flags = attachedDevice->Flags;\n\n    Information->RelatedDevice.Type = relatedDevice->DeviceType;\n    Information->RelatedDevice.Characteristics = relatedDevice->Characteristics;\n    Information->RelatedDevice.Flags = relatedDevice->Flags;\n\n    C_ASSERT(ARRAYSIZE(Information->Vpb.VolumeLabel) == ARRAYSIZE(vpb->VolumeLabel));\n\n    IoAcquireVpbSpinLock(&irql);\n\n    //\n    // Accessing the VPB is reserved for \"certain classes of drivers\".\n    //\n#pragma prefast(push)\n#pragma prefast(disable : 28175)\n    vpb = FileObject->Vpb;\n    if (vpb)\n    {\n        Information->Vpb.Type = vpb->Type;\n        Information->Vpb.Size = vpb->Size;\n        Information->Vpb.Flags = vpb->Flags;\n        Information->Vpb.VolumeLabelLength = vpb->VolumeLabelLength;\n        Information->Vpb.SerialNumber = vpb->SerialNumber;\n        Information->Vpb.ReferenceCount = vpb->ReferenceCount;\n        RtlCopyMemory(Information->Vpb.VolumeLabel,\n                      vpb->VolumeLabel,\n                      ARRAYSIZE(vpb->VolumeLabel) * sizeof(WCHAR));\n    }\n\n    vpb = FileObject->DeviceObject->Vpb;\n    if (vpb)\n    {\n        Information->Device.Vpb.Type = vpb->Type;\n        Information->Device.Vpb.Size = vpb->Size;\n        Information->Device.Vpb.Flags = vpb->Flags;\n        Information->Device.Vpb.VolumeLabelLength = vpb->VolumeLabelLength;\n        Information->Device.Vpb.SerialNumber = vpb->SerialNumber;\n        Information->Device.Vpb.ReferenceCount = vpb->ReferenceCount;\n        RtlCopyMemory(Information->Device.Vpb.VolumeLabel,\n                      vpb->VolumeLabel,\n                      ARRAYSIZE(vpb->VolumeLabel) * sizeof(WCHAR));\n    }\n\n    vpb = attachedDevice->Vpb;\n    if (vpb)\n    {\n        Information->AttachedDevice.Vpb.Type = vpb->Type;\n        Information->AttachedDevice.Vpb.Size = vpb->Size;\n        Information->AttachedDevice.Vpb.Flags = vpb->Flags;\n        Information->AttachedDevice.Vpb.VolumeLabelLength = vpb->VolumeLabelLength;\n        Information->AttachedDevice.Vpb.SerialNumber = vpb->SerialNumber;\n        Information->AttachedDevice.Vpb.ReferenceCount = vpb->ReferenceCount;\n        RtlCopyMemory(Information->AttachedDevice.Vpb.VolumeLabel,\n                      vpb->VolumeLabel,\n                      ARRAYSIZE(vpb->VolumeLabel) * sizeof(WCHAR));\n    }\n\n    vpb = relatedDevice->Vpb;\n    if (vpb)\n    {\n        Information->RelatedDevice.Vpb.Type = vpb->Type;\n        Information->RelatedDevice.Vpb.Size = vpb->Size;\n        Information->RelatedDevice.Vpb.Flags = vpb->Flags;\n        Information->RelatedDevice.Vpb.VolumeLabelLength = vpb->VolumeLabelLength;\n        Information->RelatedDevice.Vpb.SerialNumber = vpb->SerialNumber;\n        Information->RelatedDevice.Vpb.ReferenceCount = vpb->ReferenceCount;\n        RtlCopyMemory(Information->RelatedDevice.Vpb.VolumeLabel,\n                      vpb->VolumeLabel,\n                      ARRAYSIZE(vpb->VolumeLabel) * sizeof(WCHAR));\n    }\n#pragma prefast(pop)\n\n    IoReleaseVpbSpinLock(irql);\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Gets a pointer to the handle table of a process. On success, acquires\n * process exit synchronization, the process should be released by calling\n * KphDereferenceProcessHandleTable.\n *\n * \\param[in] Dyn Dynamic configuration.\n * \\param[in] Process A process object.\n * \\param[out] HandleTable On success set to the process handle table.\n *\n * \\return Successful or errant status.\n */\n_When_(NT_SUCCESS(return), _Acquires_lock_(Process))\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReferenceProcessHandleTable(\n    _In_ PKPH_DYN Dyn,\n    _In_ PEPROCESS Process,\n    _Outptr_result_nullonfailure_ PHANDLE_TABLE* HandleTable\n    )\n{\n    PHANDLE_TABLE handleTable;\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    *HandleTable = NULL;\n\n    //\n    // Fail if we don't have an offset.\n    //\n    if (Dyn->EpObjectTable == ULONG_MAX)\n    {\n        return STATUS_NOINTERFACE;\n    }\n\n    //\n    // Prevent the process from terminating and get its handle table.\n    //\n    status = PsAcquireProcessExitSynchronization(Process);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"PsAcquireProcessExitSynchronization failed: %!STATUS!\",\n                      status);\n\n        return STATUS_TOO_LATE;\n    }\n\n    handleTable = *(PHANDLE_TABLE*)Add2Ptr(Process, Dyn->EpObjectTable);\n\n    if (!handleTable)\n    {\n        PsReleaseProcessExitSynchronization(Process);\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Process has no handle table.\");\n\n        return STATUS_NOT_FOUND;\n    }\n\n    *HandleTable = handleTable;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Releases process after acquiring the process handle table.\n *\n * \\param[in] Process A process object.\n */\n_Releases_lock_(Process)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphDereferenceProcessHandleTable(\n    _In_ PEPROCESS Process\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    PsReleaseProcessExitSynchronization(Process);\n}\n\n/**\n * \\brief Unlocks a handle table entry.\n *\n * \\param[in] Dyn Dynamic configuration.\n * \\param[in] HandleTable Handle table to unlock.\n * \\param[in] HandleTableEntry Handle table entry to unlock.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpUnlockHandleTableEntry(\n    _In_ PKPH_DYN Dyn,\n    _In_ PHANDLE_TABLE HandleTable,\n    _In_ PHANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    PEX_PUSH_LOCK handleContentionEvent;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(Dyn->HtHandleContentionEvent != ULONG_MAX);\n\n    //\n    // Set the unlocked bit.\n    //\n    InterlockedExchangeAddULongPtr(&HandleTableEntry->Value, 1);\n\n    //\n    // Allow waiters to wake up.\n    //\n    handleContentionEvent = (PEX_PUSH_LOCK)Add2Ptr(HandleTable,\n                                                   Dyn->HtHandleContentionEvent);\n    if (*(PULONG_PTR)handleContentionEvent != 0)\n    {\n        ExfUnblockPushLock(handleContentionEvent, NULL);\n    }\n}\n\ntypedef struct _KPH_ENUM_PROC_HANDLE_EX_CONTEXT\n{\n    PKPH_DYN Dyn;\n    PKPH_ENUM_PROCESS_HANDLES_CALLBACK Callback;\n    PVOID Parameter;\n} KPH_ENUM_PROC_HANDLE_EX_CONTEXT, *PKPH_ENUM_PROC_HANDLE_EX_CONTEXT;\n\n/**\n * \\brief Pass-through callback for handle table enumeration.\n *\n * \\param[in,out] HandleTableEntry Related handle table entry.\n * \\param[in] Handle The handle for this entry.\n * \\param[in] Context Enumeration context.\n *\n * \\return Result from wrapped callback.\n */\n_Function_class_(EX_ENUM_HANDLE_CALLBACK)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nBOOLEAN NTAPI KphEnumerateProcessHandlesExCallback(\n    _In_ PHANDLE_TABLE HandleTable,\n    _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,\n    _In_ HANDLE Handle,\n    _In_opt_ PVOID Context\n    )\n{\n    PKPH_ENUM_PROC_HANDLE_EX_CONTEXT context;\n    BOOLEAN result;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(Context);\n\n    context = Context;\n\n    result = context->Callback(HandleTableEntry, Handle, context->Parameter);\n\n    KphpUnlockHandleTableEntry(context->Dyn, HandleTable, HandleTableEntry);\n\n    return result;\n}\n\n/**\n * \\brief Enumerates the handles of a process.\n *\n * \\param[in] Process The process to enumerate handles of.\n * \\param[in] Callback The callback to invoke for each handle table entry.\n * \\param[in] Parameter Optional parameter to pass to the callback.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nNTSTATUS KphEnumerateProcessHandlesEx(\n    _In_ PEPROCESS Process,\n    _In_ PKPH_ENUM_PROCESS_HANDLES_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    KPH_ENUM_PROC_HANDLE_EX_CONTEXT context;\n    PHANDLE_TABLE handleTable;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = KphReferenceDynData();\n    if (!dyn ||\n        (dyn->HtHandleContentionEvent == ULONG_MAX) ||\n        (dyn->EpObjectTable == ULONG_MAX))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphEnumerateProcessHandlesEx not supported\");\n\n        status = STATUS_NOINTERFACE;\n        goto Exit;\n    }\n\n    status = KphReferenceProcessHandleTable(dyn, Process, &handleTable);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphReferenceProcessHandleTable failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    context.Dyn = dyn;\n    context.Callback = Callback;\n    context.Parameter = Parameter;\n\n    ExEnumHandleTable(handleTable,\n                      KphEnumerateProcessHandlesExCallback,\n                      &context,\n                      NULL);\n\n    KphDereferenceProcessHandleTable(Process);\n\nExit:\n\n    if (dyn)\n    {\n        KphDereferenceObject(dyn);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Enumeration callback for handle enumeration.\n *\n * \\param[in,out] HandleTableEntry Related handle table entry.\n * \\param[in] Handle The handle for this entry.\n * \\param[in] Context Enumeration context.\n *\n * \\return FALSE\n */\n_Function_class_(KPH_ENUM_PROCESS_HANDLES_CALLBACK)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphpEnumerateProcessHandlesCallback(\n    _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,\n    _In_ HANDLE Handle,\n    _In_ PVOID Context\n    )\n{\n    PKPH_ENUMERATE_PROCESS_HANDLES_CONTEXT context;\n    KPH_PROCESS_HANDLE handleInfo;\n    POBJECT_HEADER objectHeader;\n    POBJECT_TYPE objectType;\n    PKPH_PROCESS_HANDLE entryInBuffer;\n    KPH_MEMORY_REGION region;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    context = Context;\n\n    objectHeader = KphObpDecodeObject(context->Dyn, HandleTableEntry);\n    handleInfo.Handle = Handle;\n    handleInfo.Object = objectHeader ? &objectHeader->Body : NULL;\n    handleInfo.GrantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess);\n    handleInfo.ObjectTypeIndex = USHORT_MAX;\n    handleInfo.Reserved1 = 0;\n    handleInfo.HandleAttributes = KphObpGetHandleAttributes(context->Dyn,\n                                                            HandleTableEntry);\n    handleInfo.Reserved2 = 0;\n\n    if (handleInfo.Object)\n    {\n        objectType = ObGetObjectType(handleInfo.Object);\n\n        if (objectType && (context->Dyn->OtIndex != ULONG_MAX))\n        {\n            UCHAR typeIndex;\n\n            typeIndex = *(PUCHAR)Add2Ptr(objectType, context->Dyn->OtIndex);\n\n            handleInfo.ObjectTypeIndex = (USHORT)typeIndex;\n        }\n    }\n\n    //\n    // Advance the current entry pointer regardless of whether the information\n    // will be written. This will allow the parent function to report the\n    // correct return length.\n    //\n    entryInBuffer = context->CurrentEntry;\n    context->CurrentEntry = Add2Ptr(context->CurrentEntry, sizeof(KPH_PROCESS_HANDLE));\n    context->Count++;\n\n    //\n    // Only write if we have not exceeded the buffer length. Also check for a\n    // potential overflow (if the process has an extremely large number of\n    // handles, the buffer pointer may wrap).\n    //\n    region.Start = entryInBuffer;\n    region.End = Add2Ptr(entryInBuffer, sizeof(KPH_PROCESS_HANDLE));\n    if (KphIsValidMemoryRegion(&region, context->Buffer, context->BufferLimit))\n    {\n        context->Status = KphCopyToMode(entryInBuffer,\n                                        &handleInfo,\n                                        sizeof(KPH_PROCESS_HANDLE),\n                                        context->AccessMode);\n        if (!NT_SUCCESS(context->Status))\n        {\n            return TRUE;\n        }\n    }\n    else\n    {\n        if (context->Status == STATUS_SUCCESS)\n        {\n            context->Status = STATUS_BUFFER_TOO_SMALL;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * \\brief Enumerates the handles of a process.\n *\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[out] Buffer The buffer in which the handle information will be stored.\n * \\param[in] BufferLength The number of bytes available in Buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphEnumerateProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    PEPROCESS process;\n    KPH_ENUMERATE_PROCESS_HANDLES_CONTEXT context;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = NULL;\n    process = NULL;\n\n    if (!Buffer)\n    {\n        status = STATUS_INVALID_PARAMETER_2;\n        goto Exit;\n    }\n\n    dyn = KphReferenceDynData();\n    if (!dyn)\n    {\n        status = STATUS_NOINTERFACE;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    context.Dyn = dyn;\n    context.AccessMode = AccessMode;\n    context.Buffer = Buffer;\n    context.BufferLimit = Add2Ptr(Buffer, BufferLength);\n    context.CurrentEntry = ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->Handles;\n    context.Count = 0;\n    context.Status = STATUS_SUCCESS;\n\n    status = KphEnumerateProcessHandlesEx(process,\n                                          KphpEnumerateProcessHandlesCallback,\n                                          &context);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphEnumerateProcessHandlesEx failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (BufferLength >= UFIELD_OFFSET(KPH_PROCESS_HANDLE_INFORMATION, Handles))\n    {\n        PKPH_PROCESS_HANDLE_INFORMATION info;\n\n        info = Buffer;\n\n        status = KphWriteULongToMode(&info->HandleCount,\n                                     context.Count,\n                                     AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\n    if (ReturnLength)\n    {\n        ULONG_PTR returnLength;\n\n        status = RtlULongPtrSub((ULONG_PTR)context.CurrentEntry,\n                                (ULONG_PTR)Buffer,\n                                &returnLength);\n        if (!NT_SUCCESS(status) || (returnLength > ULONG_MAX))\n        {\n            status = STATUS_INTEGER_OVERFLOW;\n            goto Exit;\n        }\n\n        status = KphWriteULongToMode(ReturnLength,\n                                     (ULONG)returnLength,\n                                     AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\n    status = context.Status;\n\nExit:\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    if (dyn)\n    {\n        KphDereferenceObject(dyn);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries the name of an object.\n *\n * \\param[in] Object A pointer to an object.\n * \\param[out] Buffer The buffer in which the object name will be stored.\n * \\param[in] BufferLength The number of bytes available in Buffer.\n * \\param[out] ReturnLength Receives the number of bytes written.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryNameObject(\n    _In_ PVOID Object,\n    _Out_writes_bytes_opt_(BufferLength) POBJECT_NAME_INFORMATION Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    POBJECT_TYPE objectType;\n\n    KPH_PAGED_CODE();\n\n    objectType = ObGetObjectType(Object);\n\n    if (objectType == *IoFileObjectType)\n    {\n        status = KphQueryNameFileObject(Object,\n                                        Buffer,\n                                        BufferLength,\n                                        ReturnLength);\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphQueryNameFileObject: %!STATUS!\",\n                      status);\n    }\n    else\n    {\n        status = ObQueryNameString(Object, Buffer, BufferLength, ReturnLength);\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObQueryNameString: %!STATUS!\",\n                      status);\n    }\n\n    //\n    // Make the error returns consistent.\n    //\n    if ((status == STATUS_BUFFER_OVERFLOW) ||    // returned by I/O subsystem\n        (status == STATUS_INFO_LENGTH_MISMATCH)) // returned by ObQueryNameString\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        NT_ASSERT(Buffer);\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphQueryNameObject: %wZ\",\n                      &Buffer->Name);\n    }\n    else\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphQueryNameObject: %!STATUS!\",\n                      status);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Extracts the name of a file object by retrieving the device name,\n * walking the related file objects, and the target file object.\n *\n * \\param[in] FileObject A pointer to a file object.\n * \\param[out] Buffer The buffer in which the object name will be stored.\n * \\param[in] BufferLength The number of bytes available in Buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpExtractNameFileObject(\n    _In_ PFILE_OBJECT FileObject,\n    _Out_writes_bytes_opt_(BufferLength) POBJECT_NAME_INFORMATION Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    PFILE_OBJECT fileObject;\n    PUCHAR pos;\n    USHORT len;\n\n    KPH_PAGED_CODE();\n\n    *ReturnLength = 0;\n\n    if (!Buffer && BufferLength)\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    if (FlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE, GENERAL, \"File object closed\");\n\n        return STATUS_FILE_CLOSED;\n    }\n\n    if (FileObject->DeviceObject)\n    {\n        returnLength = 0;\n\n        status = ObQueryNameString(FileObject->DeviceObject,\n                                   Buffer,\n                                   BufferLength,\n                                   &returnLength);\n\n        if (NT_SUCCESS(status))\n        {\n            NT_ASSERT(Buffer && BufferLength);\n            NT_ASSERT(returnLength >= sizeof(OBJECT_NAME_INFORMATION));\n            NT_ASSERT(Buffer->Name.Buffer == Add2Ptr(Buffer, sizeof(OBJECT_NAME_INFORMATION)));\n        }\n        else if (status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            NT_ASSERT(returnLength);\n        }\n        else\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"ObQueryNameString failed: %!STATUS!\",\n                          status);\n\n            return status;\n        }\n    }\n    else\n    {\n        if (Buffer && (BufferLength >= sizeof(OBJECT_NAME_INFORMATION)))\n        {\n            Buffer->Name.Length = 0;\n            Buffer->Name.Buffer = Add2Ptr(Buffer, sizeof(OBJECT_NAME_INFORMATION));\n        }\n\n        returnLength = sizeof(OBJECT_NAME_INFORMATION);\n    }\n\n    //\n    // Walk the file object and related objects. This is walking the name in\n    // reverse order. Place the name at the end of the buffer to be moved into\n    // place afterwards. If along the way we exhaust the buffer we'll continue\n    // to calculate the needed length but not write to the buffer.\n    //\n\n    fileObject = FileObject;\n    pos = Buffer ? Add2Ptr(Buffer, BufferLength) : NULL;\n    len = 0;\n\n    do\n    {\n        //\n        // N.B. There are some drivers that aren't as tidy with their related\n        // file objects (condrv.sys) and leave a dangling pointer. Admittedly\n        // we're doing a \"non-blessed\" thing by extracting the name like this.\n        // So we sanity check that the pointer is a valid file object to work\n        // around this, it's not perfect but we get value from this routine\n        // for cases where extracting the full name is otherwise impossible.\n        //\n        if ((ObGetObjectType(fileObject) != *IoFileObjectType) ||\n            FlagOn(fileObject->Flags, FO_CLEANUP_COMPLETE))\n        {\n            break;\n        }\n\n        status = RtlULongAdd(returnLength,\n                             fileObject->FileName.Length,\n                             &returnLength);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"RtlULongAdd failed: %!STATUS!\",\n                          status);\n\n            return status;\n        }\n\n        status = RtlUShortAdd(len, fileObject->FileName.Length, &len);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"RtlUShortAdd failed: %!STATUS!\",\n                          status);\n\n            return status;\n        }\n\n        if (Buffer && (returnLength <= BufferLength))\n        {\n            pos -= fileObject->FileName.Length;\n            RtlCopyMemory(pos,\n                          fileObject->FileName.Buffer,\n                          fileObject->FileName.Length);\n        }\n\n        fileObject = fileObject->RelatedFileObject;\n\n    } while (fileObject);\n\n    *ReturnLength = returnLength;\n\n    if (!Buffer || (returnLength > BufferLength))\n    {\n        return STATUS_BUFFER_TOO_SMALL;\n    }\n\n    RtlMoveMemory(Add2Ptr(Buffer->Name.Buffer, Buffer->Name.Length), pos, len);\n\n    status = RtlUShortAdd(Buffer->Name.Length, len, &Buffer->Name.Length);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"RtlUShortAdd failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    if ((BufferLength - returnLength) > sizeof(UNICODE_NULL))\n    {\n        Buffer->Name.Buffer[Buffer->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;\n        returnLength += sizeof(UNICODE_NULL);\n    }\n\n    NT_ASSERT(returnLength >= sizeof(OBJECT_NAME_INFORMATION));\n\n    returnLength -= sizeof(OBJECT_NAME_INFORMATION);\n\n    NT_ASSERT(returnLength <= USHORT_MAX);\n\n    Buffer->Name.MaximumLength = (USHORT)returnLength;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Queries the name of a file object.\n *\n * \\param[in] FileObject A pointer to a file object.\n * \\param[out] Buffer The buffer in which the object name will be stored.\n * \\param[in] BufferLength The number of bytes available in Buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryNameFileObject(\n    _In_ PFILE_OBJECT FileObject,\n    _Out_writes_bytes_opt_(BufferLength) POBJECT_NAME_INFORMATION Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PFLT_FILE_NAME_INFORMATION fileNameInfo;\n    FLT_FILE_NAME_OPTIONS nameOptions;\n\n    KPH_PAGED_CODE();\n\n    nameOptions = FLT_FILE_NAME_NORMALIZED;\n\n    if (IoGetTopLevelIrp() || KeAreAllApcsDisabled())\n    {\n        nameOptions |= FLT_FILE_NAME_QUERY_CACHE_ONLY;\n    }\n    else\n    {\n        nameOptions |= FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP;\n    }\n\n    status = FltGetFileNameInformationUnsafe(FileObject,\n                                             NULL,\n                                             nameOptions,\n                                             &fileNameInfo);\n    if (!NT_SUCCESS(status))\n    {\n        fileNameInfo = NULL;\n\n        status = KphpExtractNameFileObject(FileObject,\n                                           Buffer,\n                                           BufferLength,\n                                           ReturnLength);\n        goto Exit;\n    }\n\n    *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);\n    *ReturnLength += fileNameInfo->Name.Length;\n    if (!Buffer || (BufferLength < *ReturnLength))\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n        goto Exit;\n    }\n\n    Buffer->Name.Length = 0;\n    Buffer->Name.MaximumLength = (USHORT)(BufferLength - sizeof(OBJECT_NAME_INFORMATION));\n    Buffer->Name.Buffer = (PWSTR)Add2Ptr(Buffer, sizeof(OBJECT_NAME_INFORMATION));\n\n    RtlCopyUnicodeString(&Buffer->Name, &fileNameInfo->Name);\n\nExit:\n\n    if (fileNameInfo)\n    {\n        FltReleaseFileNameInformation(fileNameInfo);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries object information.\n *\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[in] Handle A handle which is present in the process.\n * \\param[in] ObjectInformationClass The type of information to retrieve.\n * \\param[out] ObjectInformation Information buffer to populate.\n * \\param[in] ObjectInformationLength Length of the information buffer in bytes.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    PEPROCESS process;\n    KAPC_STATE apcState;\n    PVOID object;\n    ULONG returnLength;\n    PVOID buffer;\n    BYTE stackBuffer[64];\n    KPROCESSOR_MODE accessMode;\n    PKPH_PROCESS_CONTEXT processContext;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = NULL;\n    returnLength = 0;\n    object = NULL;\n    buffer = NULL;\n    processContext = NULL;\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (process == PsInitialSystemProcess)\n    {\n        Handle = MakeKernelHandle(Handle);\n        accessMode = KernelMode;\n    }\n    else\n    {\n        if (IsKernelHandle(Handle) && !IsPseudoHandle(Handle))\n        {\n            status = STATUS_INVALID_HANDLE;\n            goto Exit;\n        }\n        accessMode = AccessMode;\n    }\n\n    switch (ObjectInformationClass)\n    {\n        case KphObjectBasicInformation:\n        {\n            OBJECT_BASIC_INFORMATION basicInfo;\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(OBJECT_BASIC_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(OBJECT_BASIC_INFORMATION);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ZwQueryObject(Handle,\n                                   ObjectBasicInformation,\n                                   &basicInfo,\n                                   sizeof(OBJECT_BASIC_INFORMATION),\n                                   NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (NT_SUCCESS(status))\n            {\n                status = KphCopyToMode(ObjectInformation,\n                                       &basicInfo,\n                                       sizeof(OBJECT_BASIC_INFORMATION),\n                                       AccessMode);\n                if (NT_SUCCESS(status))\n                {\n                    returnLength = sizeof(OBJECT_BASIC_INFORMATION);\n                }\n            }\n\n            break;\n        }\n        case KphObjectNameInformation:\n        {\n            ULONG allocateSize;\n            POBJECT_NAME_INFORMATION nameInfo;\n\n            KeStackAttachProcess(process, &apcState);\n            status = ObReferenceObjectByHandle(Handle,\n                                               0,\n                                               NULL,\n                                               accessMode,\n                                               &object,\n                                               NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                              status);\n\n                object = NULL;\n                goto Exit;\n            }\n\n            allocateSize = ObjectInformationLength;\n\n            if (allocateSize < sizeof(OBJECT_NAME_INFORMATION))\n            {\n                allocateSize = sizeof(OBJECT_NAME_INFORMATION);\n            }\n\n            buffer = KphAllocatePagedA(allocateSize,\n                                       KPH_TAG_OBJECT_QUERY,\n                                       stackBuffer);\n            if (!buffer)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            nameInfo = (POBJECT_NAME_INFORMATION)buffer;\n\n            status = KphQueryNameObject(object,\n                                        nameInfo,\n                                        ObjectInformationLength,\n                                        &returnLength);\n            if (NT_SUCCESS(status))\n            {\n                if (!ObjectInformation)\n                {\n                    status = STATUS_BUFFER_TOO_SMALL;\n                    goto Exit;\n                }\n\n                RebaseUnicodeString(&nameInfo->Name,\n                                    nameInfo,\n                                    ObjectInformation);\n\n                status = KphCopyToMode(ObjectInformation,\n                                       nameInfo,\n                                       returnLength,\n                                       AccessMode);\n            }\n\n            break;\n        }\n        case KphObjectTypeInformation:\n        {\n            ULONG allocateSize;\n            POBJECT_TYPE_INFORMATION typeInfo;\n\n            returnLength = sizeof(OBJECT_TYPE_INFORMATION);\n            allocateSize = ObjectInformationLength;\n            if (allocateSize < sizeof(OBJECT_TYPE_INFORMATION))\n            {\n                allocateSize = sizeof(OBJECT_TYPE_INFORMATION);\n            }\n\n            //\n            // ObQueryTypeInfo uses ObjectType->Name.MaximumLength instead of\n            // ObjectType->Name.Length + sizeof(WCHAR) to calculate the\n            // required buffer size. In Windows 8, certain object types\n            // (e.g. TmTx) do NOT include the null terminator in MaximumLength,\n            // which causes ObQueryTypeInfo to overrun the given buffer. To\n            // work around this bug, we add some (generous) padding to our\n            // allocation.\n            //\n            allocateSize += sizeof(ULONG64);\n\n            buffer = KphAllocatePagedA(allocateSize,\n                                       KPH_TAG_OBJECT_QUERY,\n                                       stackBuffer);\n            if (!buffer)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            typeInfo = (POBJECT_TYPE_INFORMATION)buffer;\n\n            KeStackAttachProcess(process, &apcState);\n            status = ZwQueryObject(Handle,\n                                   ObjectTypeInformation,\n                                   typeInfo,\n                                   ObjectInformationLength,\n                                   &returnLength);\n            KeUnstackDetachProcess(&apcState);\n            if (NT_SUCCESS(status))\n            {\n                if (!ObjectInformation)\n                {\n                    status = STATUS_BUFFER_TOO_SMALL;\n                    goto Exit;\n                }\n\n                RebaseUnicodeString(&typeInfo->TypeName,\n                                    typeInfo,\n                                    ObjectInformation);\n\n                status = KphCopyToMode(ObjectInformation,\n                                       typeInfo,\n                                       returnLength,\n                                       AccessMode);\n            }\n\n            break;\n        }\n        case KphObjectHandleFlagInformation:\n        {\n            OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(OBJECT_HANDLE_FLAG_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(OBJECT_HANDLE_FLAG_INFORMATION);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ZwQueryObject(Handle,\n                                   ObjectHandleFlagInformation,\n                                   &handleFlagInfo,\n                                   sizeof(OBJECT_HANDLE_FLAG_INFORMATION),\n                                   NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (NT_SUCCESS(status))\n            {\n                status = KphCopyToMode(ObjectInformation,\n                                       &handleFlagInfo,\n                                       sizeof(OBJECT_HANDLE_FLAG_INFORMATION),\n                                       AccessMode);\n                if (NT_SUCCESS(status))\n                {\n                    returnLength = sizeof(OBJECT_HANDLE_FLAG_INFORMATION);\n                }\n            }\n\n            break;\n        }\n        case KphObjectProcessBasicInformation:\n        {\n            PROCESS_BASIC_INFORMATION basicInfo;\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(PROCESS_BASIC_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(PROCESS_BASIC_INFORMATION);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ZwQueryInformationProcess(Handle,\n                                               ProcessBasicInformation,\n                                               &basicInfo,\n                                               sizeof(PROCESS_BASIC_INFORMATION),\n                                               NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (NT_SUCCESS(status))\n            {\n                status = KphCopyToMode(ObjectInformation,\n                                       &basicInfo,\n                                       sizeof(PROCESS_BASIC_INFORMATION),\n                                       AccessMode);\n                if (NT_SUCCESS(status))\n                {\n                    returnLength = sizeof(PROCESS_BASIC_INFORMATION);\n                }\n            }\n\n            break;\n        }\n        case KphObjectThreadBasicInformation:\n        {\n            THREAD_BASIC_INFORMATION basicInfo;\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(THREAD_BASIC_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(THREAD_BASIC_INFORMATION);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ZwQueryInformationThread(Handle,\n                                              ThreadBasicInformation,\n                                              &basicInfo,\n                                              sizeof(THREAD_BASIC_INFORMATION),\n                                              NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (NT_SUCCESS(status))\n            {\n                status = KphCopyToMode(ObjectInformation,\n                                       &basicInfo,\n                                       sizeof(THREAD_BASIC_INFORMATION),\n                                       AccessMode);\n                if (NT_SUCCESS(status))\n                {\n                    returnLength = sizeof(THREAD_BASIC_INFORMATION);\n                }\n            }\n\n            break;\n        }\n        case KphObjectEtwRegBasicInformation:\n        {\n            PVOID objectType;\n            PUNICODE_STRING objectTypeName;\n            PVOID guidEntry;\n            KPH_ETWREG_BASIC_INFORMATION basicInfo;\n\n            dyn = KphReferenceDynData();\n            if (!dyn ||\n                (dyn->EgeGuid == ULONG_MAX) ||\n                (dyn->EreGuidEntry == ULONG_MAX) ||\n                (dyn->OtName == ULONG_MAX))\n            {\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(KPH_ETWREG_BASIC_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_ETWREG_BASIC_INFORMATION);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ObReferenceObjectByHandle(Handle,\n                                               0,\n                                               NULL,\n                                               accessMode,\n                                               &object,\n                                               NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                              status);\n\n                object = NULL;\n                goto Exit;\n            }\n\n            objectType = ObGetObjectType(object);\n            if (!objectType)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ObGetObjectType returned null\");\n\n                status = STATUS_NOT_SUPPORTED;\n                goto Exit;\n            }\n\n            objectTypeName = (PUNICODE_STRING)Add2Ptr(objectType, dyn->OtName);\n            if (!RtlEqualUnicodeString(objectTypeName,\n                                       &KphpEtwRegistrationName,\n                                       FALSE))\n            {\n                status = STATUS_OBJECT_TYPE_MISMATCH;\n                goto Exit;\n            }\n\n            guidEntry = *(PVOID*)Add2Ptr(object, dyn->EreGuidEntry);\n            if (guidEntry)\n            {\n                RtlCopyMemory(&basicInfo.Guid,\n                              Add2Ptr(guidEntry, dyn->EgeGuid),\n                              sizeof(GUID));\n            }\n            else\n            {\n                RtlZeroMemory(&basicInfo.Guid, sizeof(GUID));\n            }\n\n            //\n            // Not implemented.\n            //\n            basicInfo.SessionId = 0;\n\n            status = KphCopyToMode(ObjectInformation,\n                                   &basicInfo,\n                                   sizeof(KPH_ETWREG_BASIC_INFORMATION),\n                                   AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_ETWREG_BASIC_INFORMATION);\n            }\n\n            break;\n        }\n        case KphObjectFileObjectInformation:\n        {\n            KPH_FILE_OBJECT_INFORMATION fileInfo;\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(KPH_FILE_OBJECT_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_FILE_OBJECT_INFORMATION);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ObReferenceObjectByHandle(Handle,\n                                               0,\n                                               *IoFileObjectType,\n                                               accessMode,\n                                               &object,\n                                               NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                              status);\n\n                object = NULL;\n                goto Exit;\n            }\n\n            KphpGetFileObjectInformation(object, &fileInfo);\n\n            status = KphCopyToMode(ObjectInformation,\n                                   &fileInfo,\n                                   sizeof(KPH_FILE_OBJECT_INFORMATION),\n                                   AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_FILE_OBJECT_INFORMATION);\n            }\n\n            break;\n        }\n        case KphObjectFileObjectDriver:\n        {\n            PFILE_OBJECT fileObject;\n            HANDLE driverHandle;\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(HANDLE)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(HANDLE);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ObReferenceObjectByHandle(Handle,\n                                               0,\n                                               *IoFileObjectType,\n                                               accessMode,\n                                               &object,\n                                               NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                              status);\n\n                object = NULL;\n                goto Exit;\n            }\n\n            fileObject = (PFILE_OBJECT)object;\n            if (!fileObject->DeviceObject ||\n                !fileObject->DeviceObject->DriverObject)\n            {\n                status = STATUS_INVALID_DEVICE_REQUEST;\n                goto Exit;\n            }\n\n            status = ObOpenObjectByPointer(fileObject->DeviceObject->DriverObject,\n                                           (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                           NULL,\n                                           SYNCHRONIZE,\n                                           *IoDriverObjectType,\n                                           AccessMode,\n                                           &driverHandle);\n            if (NT_SUCCESS(status))\n            {\n                status = KphWriteHandleToMode(ObjectInformation,\n                                              driverHandle,\n                                              AccessMode);\n                if (NT_SUCCESS(status))\n                {\n                    returnLength = sizeof(HANDLE);\n                }\n            }\n\n            break;\n        }\n        case KphObjectProcessTimes:\n        {\n            KERNEL_USER_TIMES times;\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(KERNEL_USER_TIMES)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KERNEL_USER_TIMES);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ZwQueryInformationProcess(Handle,\n                                               ProcessTimes,\n                                               &times,\n                                               sizeof(KERNEL_USER_TIMES),\n                                               NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (NT_SUCCESS(status))\n            {\n                status = KphCopyToMode(ObjectInformation,\n                                       &times,\n                                       sizeof(KERNEL_USER_TIMES),\n                                       AccessMode);\n                if (NT_SUCCESS(status))\n                {\n                    returnLength = sizeof(KERNEL_USER_TIMES);\n                }\n            }\n\n            break;\n        }\n        case KphObjectThreadTimes:\n        {\n            KERNEL_USER_TIMES times;\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(KERNEL_USER_TIMES)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KERNEL_USER_TIMES);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ZwQueryInformationThread(Handle,\n                                              ThreadTimes,\n                                              &times,\n                                              sizeof(KERNEL_USER_TIMES),\n                                              NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (NT_SUCCESS(status))\n            {\n                status = KphCopyToMode(ObjectInformation,\n                                       &times,\n                                       sizeof(KERNEL_USER_TIMES),\n                                       AccessMode);\n                if (NT_SUCCESS(status))\n                {\n                    returnLength = sizeof(KERNEL_USER_TIMES);\n                }\n            }\n\n            break;\n        }\n        case KphObjectProcessImageFileName:\n        {\n            PEPROCESS targetProcess;\n\n            KeStackAttachProcess(process, &apcState);\n            status = ObReferenceObjectByHandle(Handle,\n                                               0,\n                                               *PsProcessType,\n                                               accessMode,\n                                               &targetProcess,\n                                               NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            processContext = KphGetEProcessContext(targetProcess);\n\n            ObDereferenceObject(targetProcess);\n\n            if (!processContext || !processContext->ImageFileName)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            status = KphCopyUnicodeStringToMode(ObjectInformation,\n                                                ObjectInformationLength,\n                                                processContext->ImageFileName,\n                                                &returnLength,\n                                                AccessMode);\n\n            break;\n        }\n        case KphObjectThreadNameInformation:\n        {\n            ULONG allocateSize;\n            PTHREAD_NAME_INFORMATION nameInfo;\n\n            returnLength = sizeof(THREAD_NAME_INFORMATION);\n            allocateSize = ObjectInformationLength;\n            if (allocateSize < sizeof(THREAD_NAME_INFORMATION))\n            {\n                allocateSize = sizeof(THREAD_NAME_INFORMATION);\n            }\n            allocateSize += sizeof(ULONG64);\n\n            buffer = KphAllocatePagedA(allocateSize,\n                                       KPH_TAG_OBJECT_QUERY,\n                                       stackBuffer);\n            if (!buffer)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            nameInfo = (PTHREAD_NAME_INFORMATION)buffer;\n\n            KeStackAttachProcess(process, &apcState);\n            status = ZwQueryInformationThread(Handle,\n                                              ThreadNameInformation,\n                                              nameInfo,\n                                              ObjectInformationLength,\n                                              &returnLength);\n            KeUnstackDetachProcess(&apcState);\n            if (NT_SUCCESS(status))\n            {\n                if (!ObjectInformation)\n                {\n                    status = STATUS_BUFFER_TOO_SMALL;\n                    goto Exit;\n                }\n\n                RebaseUnicodeString(&nameInfo->ThreadName,\n                                    nameInfo,\n                                    ObjectInformation);\n\n                status = KphCopyToMode(ObjectInformation,\n                                       nameInfo,\n                                       returnLength,\n                                       AccessMode);\n            }\n\n            break;\n        }\n        case KphObjectThreadIsTerminated:\n        {\n            ULONG threadIsTerminated;\n\n            if (!ObjectInformation || (ObjectInformationLength < sizeof(ULONG)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(ULONG);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ZwQueryInformationThread(Handle,\n                                              ThreadIsTerminated,\n                                              &threadIsTerminated,\n                                              sizeof(ULONG),\n                                              NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (NT_SUCCESS(status))\n            {\n                status = KphWriteULongToMode(ObjectInformation,\n                                             threadIsTerminated,\n                                             AccessMode);\n                if (NT_SUCCESS(status))\n                {\n                    returnLength = sizeof(ULONG);\n                }\n            }\n\n            break;\n        }\n        case KphObjectSectionBasicInformation:\n        case KphObjectSectionImageInformation:\n        case KphObjectSectionRelocationInformation:\n        case KphObjectSectionOriginalBaseInformation:\n        case KphObjectSectionInternalImageInformation:\n        case KphObjectSectionMappingsInformation:\n        {\n            if (ObjectInformation)\n            {\n                buffer = KphAllocatePagedA(ObjectInformationLength,\n                                           KPH_TAG_OBJECT_QUERY,\n                                           stackBuffer);\n                if (!buffer)\n                {\n                    status = STATUS_INSUFFICIENT_RESOURCES;\n                    goto Exit;\n                }\n            }\n            else\n            {\n                NT_ASSERT(!buffer);\n                ObjectInformationLength = 0;\n            }\n\n            if (ObjectInformationClass == KphObjectSectionMappingsInformation)\n            {\n                KeStackAttachProcess(process, &apcState);\n                status = KphQuerySection(Handle,\n                                         KphSectionMappingsInformation,\n                                         buffer,\n                                         ObjectInformationLength,\n                                         &returnLength,\n                                         KernelMode);\n                KeUnstackDetachProcess(&apcState);\n                if (NT_SUCCESS(status))\n                {\n                    status = KphCopyToMode(ObjectInformation,\n                                           buffer,\n                                           returnLength,\n                                           AccessMode);\n                }\n            }\n            else\n            {\n                SIZE_T length;\n                SECTION_INFORMATION_CLASS sectionInfoClass;\n\n                if (ObjectInformationClass == KphObjectSectionBasicInformation)\n                {\n                    sectionInfoClass = SectionBasicInformation;\n                }\n                else if (ObjectInformationClass == KphObjectSectionImageInformation)\n                {\n                    sectionInfoClass = SectionImageInformation;\n                }\n                else if (ObjectInformationClass == KphObjectSectionRelocationInformation)\n                {\n                    sectionInfoClass = SectionRelocationInformation;\n                }\n                else if (ObjectInformationClass == KphObjectSectionOriginalBaseInformation)\n                {\n                    sectionInfoClass = SectionOriginalBaseInformation;\n                }\n                else\n                {\n                    NT_ASSERT(ObjectInformationClass == KphObjectSectionInternalImageInformation);\n                    sectionInfoClass = SectionInternalImageInformation;\n                }\n\n                length = 0;\n                KeStackAttachProcess(process, &apcState);\n                status = ZwQuerySection(Handle,\n                                        sectionInfoClass,\n                                        buffer,\n                                        ObjectInformationLength,\n                                        &length);\n                KeUnstackDetachProcess(&apcState);\n                if (NT_SUCCESS(status))\n                {\n                    if (length > ULONG_MAX)\n                    {\n                        status = STATUS_INTEGER_OVERFLOW;\n                        returnLength = 0;\n                        goto Exit;\n                    }\n\n                    status = KphCopyToMode(ObjectInformation,\n                                           buffer,\n                                           length,\n                                           AccessMode);\n                    if (NT_SUCCESS(status))\n                    {\n                        returnLength = (ULONG)length;\n                    }\n                }\n            }\n\n            break;\n        }\n        case KphObjectSectionFileName:\n        {\n            PUNICODE_STRING sectionFileName;\n            ULONG allocateSize;\n            HANDLE sectionHandle;\n            PVOID baseAddress;\n            SIZE_T viewSize;\n\n            returnLength = sizeof(UNICODE_STRING);\n            allocateSize = ObjectInformationLength;\n            if (allocateSize < sizeof(UNICODE_STRING))\n            {\n                allocateSize = sizeof(UNICODE_STRING);\n            }\n            allocateSize += sizeof(ULONG64);\n\n            buffer = KphAllocatePagedA(allocateSize,\n                                       KPH_TAG_OBJECT_QUERY,\n                                       stackBuffer);\n            if (!buffer)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            sectionFileName = (PUNICODE_STRING)buffer;\n\n            status = ObDuplicateObject(process,\n                                       Handle,\n                                       PsInitialSystemProcess,\n                                       &sectionHandle,\n                                       SECTION_QUERY | SECTION_MAP_READ,\n                                       OBJ_KERNEL_HANDLE,\n                                       0,\n                                       KernelMode);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ObDuplicateObject failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            KeStackAttachProcess(PsInitialSystemProcess, &apcState);\n\n            baseAddress = NULL;\n            viewSize = PAGE_SIZE;\n            status = ZwMapViewOfSection(sectionHandle,\n                                        ZwCurrentProcess(),\n                                        &baseAddress,\n                                        0,\n                                        0,\n                                        NULL,\n                                        &viewSize,\n                                        ViewUnmap,\n                                        0,\n                                        PAGE_READONLY);\n            if (NT_SUCCESS(status))\n            {\n                SIZE_T length;\n\n                length = 0;\n                status = ZwQueryVirtualMemory(ZwCurrentProcess(),\n                                              baseAddress,\n                                              MemoryMappedFilenameInformation,\n                                              sectionFileName,\n                                              ObjectInformationLength,\n                                              &length);\n                if (length > ULONG_MAX)\n                {\n                    status = STATUS_INTEGER_OVERFLOW;\n                    returnLength = 0;\n                }\n                else\n                {\n                    returnLength = (ULONG)length;\n                }\n\n                ZwUnmapViewOfSection(ZwCurrentProcess(), baseAddress);\n            }\n\n            KeUnstackDetachProcess(&apcState);\n\n            ObCloseHandle(sectionHandle, KernelMode);\n\n            if (NT_SUCCESS(status))\n            {\n                if (!ObjectInformation)\n                {\n                    status = STATUS_BUFFER_TOO_SMALL;\n                    goto Exit;\n                }\n\n                RebaseUnicodeString(sectionFileName,\n                                    sectionFileName,\n                                    ObjectInformation);\n\n                status = KphCopyToMode(ObjectInformation,\n                                       sectionFileName,\n                                       returnLength,\n                                       AccessMode);\n            }\n\n            break;\n        }\n        case KphObjectAttributesInformation:\n        {\n            PKPH_OBJECT_ATTRIBUTES_INFORMATION attributesInfo;\n\n            if (!ObjectInformation ||\n                (ObjectInformationLength < sizeof(KPH_OBJECT_ATTRIBUTES_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_OBJECT_ATTRIBUTES_INFORMATION);\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ObReferenceObjectByHandle(Handle,\n                                               0,\n                                               NULL,\n                                               accessMode,\n                                               &object,\n                                               NULL);\n            KeUnstackDetachProcess(&apcState);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                              status);\n\n                object = NULL;\n                goto Exit;\n            }\n\n            attributesInfo = ObjectInformation;\n\n            C_ASSERT(sizeof(KPH_OBJECT_ATTRIBUTES_INFORMATION) == sizeof(UCHAR));\n\n            status = KphWriteUCharToMode(&attributesInfo->Flags,\n                                         OBJECT_TO_OBJECT_HEADER(object)->Flags,\n                                         AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_OBJECT_ATTRIBUTES_INFORMATION);\n            }\n\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n\nExit:\n\n    if (processContext)\n    {\n        KphDereferenceObject(processContext);\n    }\n\n    if (buffer)\n    {\n        KphFreeA(buffer, KPH_TAG_OBJECT_QUERY, stackBuffer);\n    }\n\n    if (object)\n    {\n        ObDereferenceObject(object);\n    }\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    if (dyn)\n    {\n        KphDereferenceObject(dyn);\n    }\n\n    if (ReturnLength)\n    {\n        KphWriteULongToMode(ReturnLength, returnLength, AccessMode);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Sets object information.\n *\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[in] Handle A handle which is present in the process.\n * \\param[in] ObjectInformationClass The type of information to set.\n * \\param[in] ObjectInformation A buffer which contains the information to set.\n * \\param[in] ObjectInformationLength Length of the information buffer in bytes.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PVOID objectInformation;\n    BYTE stackBuffer[64];\n    PEPROCESS process;\n    KAPC_STATE apcState;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    objectInformation = NULL;\n    process = NULL;\n\n    if (!ObjectInformation)\n    {\n        status = STATUS_INVALID_PARAMETER_4;\n        goto Exit;\n    }\n\n    if (AccessMode != KernelMode)\n    {\n        objectInformation = KphAllocatePagedA(ObjectInformationLength,\n                                              KPH_TAG_OBJECT_INFO,\n                                              stackBuffer);\n        if (!objectInformation)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Failed to allocate object info buffer.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        __try\n        {\n            CopyFromUser(objectInformation,\n                         ObjectInformation,\n                         ObjectInformationLength);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n    }\n    else\n    {\n        objectInformation = ObjectInformation;\n    }\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       PROCESS_SET_INFORMATION,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        process = NULL;\n        goto Exit;\n    }\n\n    if (process == PsInitialSystemProcess)\n    {\n        Handle = MakeKernelHandle(Handle);\n    }\n    else\n    {\n        if (IsKernelHandle(Handle))\n        {\n            status = STATUS_INVALID_HANDLE;\n            goto Exit;\n        }\n    }\n\n    switch (ObjectInformationClass)\n    {\n        case KphObjectHandleFlagInformation:\n        {\n            if (ObjectInformationLength < sizeof(OBJECT_HANDLE_FLAG_INFORMATION))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                goto Exit;\n            }\n\n            KeStackAttachProcess(process, &apcState);\n            status = ObSetHandleAttributes(Handle, objectInformation, KernelMode);\n            KeUnstackDetachProcess(&apcState);\n\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n\nExit:\n\n    if (objectInformation && (objectInformation != ObjectInformation))\n    {\n        KphFreeA(objectInformation, KPH_TAG_OBJECT_INFO, stackBuffer);\n    }\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Opens a named object.\n *\n * \\param[out] ObjectHandle Set to the opened handle.\n * \\param[in] DesiredAccess Desires access to the object.\n * \\param[in] ObjectAttributes Attributes to open the object.\n * \\param[in] ObjectType Type of object to open.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenNamedObject(\n    _Out_ PHANDLE ObjectHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ POBJECT_TYPE ObjectType,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    HANDLE objectHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = ObOpenObjectByName(ObjectAttributes,\n                                ObjectType,\n                                AccessMode,\n                                NULL,\n                                DesiredAccess,\n                                NULL,\n                                &objectHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByName failed: %!STATUS!\",\n                      status);\n\n        objectHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphWriteHandleToMode(ObjectHandle, objectHandle, AccessMode);\n\nExit:\n\n    return status;\n}\n\n/**\n * \\brief Duplicates an object.\n *\n * \\param[in] ProcessHandle Handle to process where the source handle exists.\n * \\param[in] SourceHandle Source handle in the target process.\n * \\param[in] DesiredAccess Desired access for duplicated handle.\n * \\param[out] TargetHandle Populated with the duplicated handle.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDuplicateObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE SourceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TargetHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS sourceProcess;\n    PEPROCESS targetProcess;\n    HANDLE targetHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    targetProcess = NULL;\n    sourceProcess = NULL;\n\n    if (DesiredAccess & ~(READ_CONTROL | ACCESS_SYSTEM_SECURITY | SYNCHRONIZE))\n    {\n        status = STATUS_ACCESS_DENIED;\n        goto Exit;\n    }\n\n    if (!TargetHandle)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &sourceProcess,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed %!STATUS!\",\n                      status);\n\n        sourceProcess = NULL;\n        goto Exit;\n    }\n\n    if (sourceProcess == PsInitialSystemProcess)\n    {\n        SourceHandle = MakeKernelHandle(SourceHandle);\n    }\n    else\n    {\n        if (IsKernelHandle(SourceHandle))\n        {\n            status = STATUS_INVALID_HANDLE;\n            goto Exit;\n        }\n    }\n\n    status = ObReferenceObjectByHandle(ZwCurrentProcess(),\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &targetProcess,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed %!STATUS!\",\n                      status);\n\n        targetProcess = NULL;\n        goto Exit;\n    }\n\n    status = ObDuplicateObject(sourceProcess,\n                               SourceHandle,\n                               targetProcess,\n                               &targetHandle,\n                               DesiredAccess,\n                               (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                               0,\n                               KernelMode);\n    if (NT_SUCCESS(status))\n    {\n        status = KphWriteHandleToMode(TargetHandle, targetHandle, AccessMode);\n    }\n\nExit:\n\n    if (targetProcess)\n    {\n        ObDereferenceObject(targetProcess);\n    }\n\n    if (sourceProcess)\n    {\n        ObDereferenceObject(sourceProcess);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Checks if two object handles refer to the same object.\n *\n * \\param[in] FirstObjectHandle First handle to compare with the second.\n * \\param[in] SecondObjectHandle Second handle to compare with the first.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return STATUS_SUCCESS if the object handles refer to the same object,\n * STATUS_NOT_SAME_OBJECT if the object handles refer to different objects,\n * and STATUS_INVALID_HANDLE if one of the handles is invalid.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpCompareObjects(\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PVOID firstObject;\n    PVOID secondObject;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = ObReferenceObjectByHandle(FirstObjectHandle,\n                                       0,\n                                       NULL,\n                                       AccessMode,\n                                       &firstObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed %!STATUS!\",\n                      status);\n\n        firstObject = NULL;\n        secondObject = NULL;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(SecondObjectHandle,\n                                       0,\n                                       NULL,\n                                       AccessMode,\n                                       &secondObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed %!STATUS!\",\n                      status);\n\n        secondObject = NULL;\n        goto Exit;\n    }\n\n    status = (firstObject == secondObject) ?\n        STATUS_SUCCESS : STATUS_NOT_SAME_OBJECT;\n\nExit:\n\n    if (secondObject)\n    {\n        ObDereferenceObject(secondObject);\n    }\n\n    if (firstObject)\n    {\n        ObDereferenceObject(firstObject);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Checks if two object handles refer to the same object, for a process.\n *\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[in] FirstObjectHandle First handle to compare with the second.\n * \\param[in] SecondObjectHandle Second handle to compare with the first.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return STATUS_SUCCESS if the object handles refer to the same object,\n * STATUS_NOT_SAME_OBJECT if the object handles refer to different objects,\n * and STATUS_INVALID_HANDLE if one of the handles is invalid.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCompareObjects(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS process;\n    KPROCESSOR_MODE accessMode;\n    KAPC_STATE apcState;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed %!STATUS!\",\n                      status);\n\n        process = NULL;\n        goto Exit;\n    }\n\n    if (process == PsInitialSystemProcess)\n    {\n        FirstObjectHandle = MakeKernelHandle(FirstObjectHandle);\n        SecondObjectHandle = MakeKernelHandle(SecondObjectHandle);\n        accessMode = KernelMode;\n    }\n    else\n    {\n        accessMode = AccessMode;\n    }\n\n    KeStackAttachProcess(process, &apcState);\n    status = KphpCompareObjects(FirstObjectHandle,\n                                SecondObjectHandle,\n                                accessMode);\n    KeUnstackDetachProcess(&apcState);\n\nExit:\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/parameters.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n\n#include <kph.h>\n\ntypedef enum _KPH_PARAMETER_TYPE\n{\n    KphParameterTypeULong,\n    KphParameterTypeString,\n} KPH_PARAMETER_TYPE, *PKPH_PARAMETER_TYPE;\n\ntypedef struct _KPH_PARAMETER\n{\n    UNICODE_STRING Name;\n    KPH_PARAMETER_TYPE Type;\n    PVOID Value;\n    PVOID Default;\n} KPH_PARAMETER, *PKPH_PARAMETER;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpDefaultAltitude = RTL_CONSTANT_STRING(L\"385210.5\");\nstatic const UNICODE_STRING KphpDefaultPortName = RTL_CONSTANT_STRING(L\"\\\\KSystemInformer\");\nstatic const UNICODE_STRING KphpDefaultSystemProcessName = RTL_CONSTANT_STRING(L\"System Informer Kernel\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nPUNICODE_STRING KphAltitude = NULL;\nPUNICODE_STRING KphPortName = NULL;\nKPH_PARAMETER_FLAGS KphParameterFlags = { .Flags = 0 };\nPUNICODE_STRING KphSystemProcessName = NULL;\nC_ASSERT(sizeof(KPH_PARAMETER_FLAGS) == sizeof(ULONG));\nstatic KPH_PARAMETER KphpParameters[] =\n{\n    {\n        RTL_CONSTANT_STRING(L\"Altitude\"),\n        KphParameterTypeString,\n        &KphAltitude,\n        (PVOID)&KphpDefaultAltitude\n    },\n    {\n        RTL_CONSTANT_STRING(L\"PortName\"),\n        KphParameterTypeString,\n        &KphPortName,\n        (PVOID)&KphpDefaultPortName\n    },\n    {\n        RTL_CONSTANT_STRING(L\"Flags\"),\n        KphParameterTypeULong,\n        &KphParameterFlags,\n        (PVOID)(ULONG_PTR)0\n    },\n    {\n        RTL_CONSTANT_STRING(L\"SystemProcessName\"),\n        KphParameterTypeString,\n        &KphSystemProcessName,\n        (PVOID)&KphpDefaultSystemProcessName\n    },\n};\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Cleans up the driver parameters.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupParameters(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    for (ULONG i = 0; i < ARRAYSIZE(KphpParameters); i++)\n    {\n        PKPH_PARAMETER parameter;\n        PUNICODE_STRING value;\n\n        parameter = &KphpParameters[i];\n\n        if (parameter->Type != KphParameterTypeString)\n        {\n            continue;\n        }\n\n        value = *(PUNICODE_STRING*)parameter->Value;\n\n        if (value && (value != parameter->Default))\n        {\n            KphFreeRegistryString(value);\n        }\n    }\n}\n\n/**\n * \\brief Initializes the driver parameters.\n *\n * \\param[in] RegistryPath Registry path from the entry point.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeParameters(\n    _In_ PCUNICODE_STRING RegistryPath\n    )\n{\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = KphOpenParametersKey(RegistryPath, &keyHandle);\n    if (!NT_SUCCESS(status))\n    {\n        keyHandle = NULL;\n    }\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    for (ULONG i = 0; i < ARRAYSIZE(KphpParameters); i++)\n    {\n        PKPH_PARAMETER parameter;\n\n        parameter = &KphpParameters[i];\n\n        switch (parameter->Type)\n        {\n            case KphParameterTypeULong:\n            {\n                ULONG value;\n\n                if (keyHandle)\n                {\n                    status = KphQueryRegistryULong(keyHandle,\n                                                   &parameter->Name,\n                                                   &value);\n                    if (!NT_SUCCESS(status))\n                    {\n                        value = (ULONG)(ULONG_PTR)parameter->Default;\n                    }\n                }\n                else\n                {\n                    value = (ULONG)(ULONG_PTR)parameter->Default;\n                }\n\n                *(PULONG)parameter->Value = value;\n                break;\n            }\n            case KphParameterTypeString:\n            {\n                PUNICODE_STRING value;\n\n                if (keyHandle)\n                {\n                    status = KphQueryRegistryString(keyHandle,\n                                                    &parameter->Name,\n                                                    &value);\n                    if (!NT_SUCCESS(status))\n                    {\n                        value = (PUNICODE_STRING)parameter->Default;\n                    }\n                }\n                else\n                {\n                    value = (PUNICODE_STRING)parameter->Default;\n                }\n\n                *(PUNICODE_STRING*)parameter->Value = value;\n                break;\n            }\n            DEFAULT_UNREACHABLE;\n        }\n    }\n\n    if (keyHandle)\n    {\n        ObCloseHandle(keyHandle, KernelMode);\n    }\n}\n"
  },
  {
    "path": "KSystemInformer/process.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     jxy-s   2020-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Opens a process.\n *\n * \\param[out] ProcessHandle A variable which receives the process handle.\n * \\param[in] DesiredAccess The desired access to the process.\n * \\param[in] ClientId The identifier of a client. UniqueThread is optional.\n * If UniqueThread is present, the thread of the referenced process will be\n * checked against this identifier.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    CLIENT_ID clientId;\n    PEPROCESS process;\n    HANDLE processHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    process = NULL;\n\n    status = KphCopyFromMode(&clientId,\n                             ClientId,\n                             sizeof(CLIENT_ID),\n                             AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    //\n    // Use the thread ID if it was specified.\n    //\n    if (clientId.UniqueThread)\n    {\n        PETHREAD thread;\n\n        status = PsLookupProcessThreadByCid(&clientId, &process, &thread);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"PsLookupProcessThreadByCid failed: %!STATUS!\",\n                          status);\n\n            process = NULL;\n            thread = NULL;\n            goto Exit;\n        }\n\n        ObDereferenceObject(thread);\n    }\n    else\n    {\n        status = PsLookupProcessByProcessId(clientId.UniqueProcess, &process);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"PsLookupProcessByProcessId failed: %!STATUS!\",\n                          status);\n\n            process = NULL;\n            goto Exit;\n        }\n    }\n\n    if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) != DesiredAccess)\n    {\n        status = KphDominationCheck(PsGetCurrentProcess(),\n                                    process,\n                                    AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"KphDominationCheck failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    //\n    // Always open in KernelMode to skip ordinary access checks.\n    //\n    status = ObOpenObjectByPointer(process,\n                                   (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                   NULL,\n                                   DesiredAccess,\n                                   *PsProcessType,\n                                   KernelMode,\n                                   &processHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        processHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphWriteHandleToMode(ProcessHandle, processHandle, AccessMode);\n\nExit:\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Opens the token of a process.\n *\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[in] DesiredAccess The desired access to the token.\n * \\param[out] TokenHandle A variable which receives the token handle.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS process;\n    PACCESS_TOKEN primaryToken;\n    HANDLE tokenHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    primaryToken = NULL;\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        process = NULL;\n        goto Exit;\n    }\n\n    primaryToken = PsReferencePrimaryToken(process);\n    if (!primaryToken)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"PsReferencePrimaryToken returned null\");\n\n        status = STATUS_NO_TOKEN;\n        goto Exit;\n    }\n\n    if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) != DesiredAccess)\n    {\n        status = KphDominationCheck(PsGetCurrentProcess(),\n                                    process,\n                                    AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"KphDominationCheck failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    //\n    // Always open in KernelMode to skip ordinary access checks.\n    //\n    status = ObOpenObjectByPointer(primaryToken,\n                                   (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                   NULL,\n                                   DesiredAccess,\n                                   *SeTokenObjectType,\n                                   KernelMode,\n                                   &tokenHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        tokenHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphWriteHandleToMode(TokenHandle, tokenHandle, AccessMode);\n\nExit:\n\n    if (primaryToken)\n    {\n        PsDereferencePrimaryToken(primaryToken);\n    }\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Opens the job object of a process.\n *\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[in] DesiredAccess The desired access to the job.\n * \\param[out] JobHandle A variable which receives the job object handle.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenProcessJob(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE JobHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS process;\n    PEJOB job;\n    HANDLE jobHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        process = NULL;\n        goto Exit;\n    }\n\n    job = PsGetProcessJob(process);\n    if (!job)\n    {\n        status = STATUS_NOT_FOUND;\n        goto Exit;\n    }\n\n    if ((DesiredAccess & KPH_JOB_READ_ACCESS) != DesiredAccess)\n    {\n        status = KphDominationCheck(PsGetCurrentProcess(),\n                                    process,\n                                    AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"KphDominationCheck failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    //\n    // Always open in KernelMode to skip ordinary access checks.\n    //\n    status = ObOpenObjectByPointer(job,\n                                   (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                   NULL,\n                                   DesiredAccess,\n                                   *PsJobType,\n                                   KernelMode,\n                                   &jobHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        jobHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphWriteHandleToMode(JobHandle, jobHandle, AccessMode);\n\nExit:\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    return status;\n}\n\n/**\n * Terminates a process.\n *\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[in] ExitStatus A status value initiating why the process terminated.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS process;\n    HANDLE processHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    process = NULL;\n    processHandle = NULL;\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        process = NULL;\n        goto Exit;\n    }\n\n    status = KphDominationAndPrivilegeCheck(KPH_TOKEN_PRIVILEGE_TERMINATE,\n                                            PsGetCurrentThread(),\n                                            process,\n                                            AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphDominationAndPrivilegeCheck failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (process == PsGetCurrentProcess())\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE, GENERAL, \"Can not terminate self.\");\n\n        status = STATUS_ACCESS_DENIED;\n        goto Exit;\n    }\n\n    //\n    // Re-open the process to get a kernel handle.\n    //\n    status = ObOpenObjectByPointer(process,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   PROCESS_TERMINATE,\n                                   *PsProcessType,\n                                   KernelMode,\n                                   &processHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        processHandle = NULL;\n        goto Exit;\n    }\n\n    status = ZwTerminateProcess(processHandle, ExitStatus);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ZwTerminateProcess failed: %!STATUS!\",\n                      status);\n    }\n\nExit:\n\n    if (processHandle)\n    {\n        ObCloseHandle(processHandle, KernelMode);\n    }\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries information about a process.\n *\n * \\param[in] ProcessHandle Handle to process to query.\n * \\param[in] ProcessInformationClass Information class to query.\n * \\param[out] ProcessInformation Populated with process information by class.\n * \\param[in] ProcessInformationLength Length of the process information buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _Out_writes_bytes_opt_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    PEPROCESS processObject;\n    PKPH_PROCESS_CONTEXT process;\n    ULONG returnLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = NULL;\n    process = NULL;\n    returnLength = 0;\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &processObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        processObject = NULL;\n        goto Exit;\n    }\n\n    process = KphGetEProcessContext(processObject);\n    if (!process)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphGetEProcessContext return null.\");\n\n        status = STATUS_OBJECTID_NOT_FOUND;\n        goto Exit;\n    }\n\n    switch (ProcessInformationClass)\n    {\n        case KphProcessBasicInformation:\n        {\n            KPH_PROCESS_BASIC_INFORMATION info;\n\n            if (!ProcessInformation ||\n                (ProcessInformationLength < sizeof(KPH_PROCESS_BASIC_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_PROCESS_BASIC_INFORMATION);\n                goto Exit;\n            }\n\n            KphAcquireRWLockShared(&process->ThreadListLock);\n            KphAcquireRWLockShared(&process->ProtectionLock);\n\n            info.ProcessState = KphGetProcessState(process);\n            info.ProcessStartKey = KphGetProcessStartKey(processObject);\n            info.CreatorClientId.UniqueProcess = process->CreatorClientId.UniqueProcess;\n            info.CreatorClientId.UniqueThread = process->CreatorClientId.UniqueThread;\n            info.NumberOfImageLoads = ReadSizeTNoFence(&process->NumberOfImageLoads);\n            info.Flags = process->Flags;\n            info.NumberOfThreads = process->NumberOfThreads;\n            info.ProcessAllowedMask = process->ProcessAllowedMask;\n            info.ThreadAllowedMask = process->ThreadAllowedMask;\n            info.NumberOfMicrosoftImageLoads = ReadSizeTNoFence(&process->NumberOfMicrosoftImageLoads);\n            info.NumberOfAntimalwareImageLoads = ReadSizeTNoFence(&process->NumberOfAntimalwareImageLoads);\n            info.NumberOfVerifiedImageLoads = ReadSizeTNoFence(&process->NumberOfVerifiedImageLoads);\n            info.NumberOfUntrustedImageLoads = ReadSizeTNoFence(&process->NumberOfUntrustedImageLoads);\n\n            info.UserWritableReferences = 0;\n            if (process->FileObject &&\n                process->FileObject->SectionObjectPointer)\n            {\n                info.UserWritableReferences =\n                    MmDoesFileHaveUserWritableReferences(process->FileObject->SectionObjectPointer);\n            }\n\n            KphReleaseRWLock(&process->ProtectionLock);\n            KphReleaseRWLock(&process->ThreadListLock);\n\n            status = KphCopyToMode(ProcessInformation,\n                                   &info,\n                                   sizeof(KPH_PROCESS_BASIC_INFORMATION),\n                                   AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_PROCESS_BASIC_INFORMATION);\n            }\n\n            break;\n        }\n        case KphProcessStateInformation:\n        {\n            KPH_PROCESS_STATE processState;\n\n            if (!ProcessInformation ||\n                (ProcessInformationLength < sizeof(KPH_PROCESS_STATE)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_PROCESS_STATE);\n                goto Exit;\n            }\n\n            processState = KphGetProcessState(process);\n\n            status = KphWriteULongToMode(ProcessInformation,\n                                         processState,\n                                         AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_PROCESS_STATE);\n            }\n\n            break;\n        }\n        case KphProcessWSLProcessId:\n        {\n            ULONG processId;\n\n            if (process->SubsystemType != SubsystemInformationTypeWSL)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"Invalid subsystem for WSL process ID query.\");\n\n                status = STATUS_INVALID_HANDLE;\n                goto Exit;\n            }\n\n            if (!ProcessInformation ||\n                (ProcessInformationLength < sizeof(ULONG)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(ULONG);\n                goto Exit;\n            }\n\n            status = KphQueryInformationProcessContext(process,\n                                                       KphProcessContextWSLProcessId,\n                                                       &processId,\n                                                       sizeof(ULONG),\n                                                       NULL);\n            if (!NT_SUCCESS(status))\n            {\n                goto Exit;\n            }\n\n            status = KphWriteULongToMode(ProcessInformation,\n                                         processId,\n                                         AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(ULONG);\n            }\n\n            break;\n        }\n        case KphProcessSequenceNumber:\n        {\n            ULONG64 sequenceNumber;\n\n            if (!ProcessInformation ||\n                (ProcessInformationLength < sizeof(ULONG64)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(ULONG64);\n                goto Exit;\n            }\n\n            sequenceNumber = KphGetProcessSequenceNumber(processObject);\n\n            status = KphWriteULong64ToMode(ProcessInformation,\n                                           sequenceNumber,\n                                           AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(ULONG64);\n            }\n\n            break;\n        }\n        case KphProcessStartKey:\n        {\n            ULONG64 startKey;\n\n            if (!ProcessInformation ||\n                (ProcessInformationLength < sizeof(ULONG64)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(ULONG64);\n                goto Exit;\n            }\n\n            startKey = KphGetProcessStartKey(processObject);\n\n            status = KphWriteULong64ToMode(ProcessInformation,\n                                           startKey,\n                                           AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(ULONG64);\n            }\n\n            break;\n        }\n        case KphProcessImageSection:\n        {\n            PVOID processSectionObject;\n            HANDLE processSectionHandle;\n\n            dyn = KphReferenceDynData();\n            if (!dyn || (dyn->EpSectionObject == ULONG_MAX))\n            {\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            if (!ProcessInformation ||\n                (ProcessInformationLength < sizeof(HANDLE)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(HANDLE);\n                goto Exit;\n            }\n\n            status = PsAcquireProcessExitSynchronization(processObject);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"PsAcquireProcessExitSynchronization failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            processSectionObject = *(PVOID*)Add2Ptr(processObject,\n                                                    dyn->EpSectionObject);\n\n            if (processSectionObject)\n            {\n                ObReferenceObject(processSectionObject);\n            }\n\n            PsReleaseProcessExitSynchronization(processObject);\n\n            if (!processSectionObject)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"Process section object pointer is null.\");\n\n                status = STATUS_INVALID_PARAMETER;\n                goto Exit;\n            }\n\n            status = ObOpenObjectByPointer(processSectionObject,\n                                           (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                           NULL,\n                                           SECTION_QUERY | SECTION_MAP_READ,\n                                           *MmSectionObjectType,\n                                           KernelMode,\n                                           &processSectionHandle);\n\n            ObDereferenceObject(processSectionObject);\n\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ObOpenObjectByPointer failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            status = KphWriteHandleToMode(ProcessInformation,\n                                          processSectionHandle,\n                                          AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(HANDLE);\n            }\n\n            break;\n        }\n        case KphProcessImageFileName:\n        {\n            if (!process->ImageFileName)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            status = KphCopyUnicodeStringToMode(ProcessInformation,\n                                                ProcessInformationLength,\n                                                process->ImageFileName,\n                                                &returnLength,\n                                                AccessMode);\n\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n\nExit:\n\n    if (ReturnLength)\n    {\n        KphWriteULongToMode(ReturnLength, returnLength, AccessMode);\n    }\n\n    if (process)\n    {\n        KphDereferenceObject(process);\n    }\n\n    if (processObject)\n    {\n        ObDereferenceObject(processObject);\n    }\n\n    if (dyn)\n    {\n        KphDereferenceObject(dyn);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Sets information about a process.\n *\n * \\param[in] ProcessHandle Handle to process to set information for.\n * \\param[in] ProcessInformationClass Information class to set.\n * \\param[in] ProcessInformation Information to set.\n * \\param[in] ProcessInformationLength Length of the process information buffer.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PVOID processInformation;\n    BYTE stackBuffer[64];\n    PEPROCESS process;\n    HANDLE processHandle;\n    PROCESSINFOCLASS processInformationClass;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    processInformation = NULL;\n    process = NULL;\n    processHandle = NULL;\n\n    if (!ProcessInformation)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    if (AccessMode != KernelMode)\n    {\n        processInformation = KphAllocatePagedA(ProcessInformationLength,\n                                               KPH_TAG_PROCESS_INFO,\n                                               stackBuffer);\n        if (!processInformation)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Failed to allocate process info buffer.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        __try\n        {\n            CopyFromUser(processInformation,\n                         ProcessInformation,\n                         ProcessInformationLength);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n    }\n    else\n    {\n        processInformation = ProcessInformation;\n    }\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &process,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        process = NULL;\n        goto Exit;\n    }\n\n    switch (ProcessInformationClass)\n    {\n        case KphProcessEmptyWorkingSet:\n        {\n            //\n            // Permitted across PPL boundaries.\n            //\n            break;\n        }\n        case KphProcessQuotaLimits:\n        case KphProcessBasePriority:\n        case KphProcessRaisePriority:\n        case KphProcessPriorityClass:\n        case KphProcessAffinityMask:\n        case KphProcessPriorityBoost:\n        case KphProcessIoPriority:\n        case KphProcessPagePriority:\n        case KphProcessPowerThrottlingState:\n        case KphProcessPriorityClassEx:\n        default:\n        {\n            status = KphDominationCheck(PsGetCurrentProcess(),\n                                        process,\n                                        AccessMode);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"KphDominationCheck failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n            break;\n        }\n    }\n\n    status = ObOpenObjectByPointer(process,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   PROCESS_SET_INFORMATION,\n                                   *PsProcessType,\n                                   KernelMode,\n                                   &processHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        processHandle = NULL;\n        goto Exit;\n    }\n\n    switch (ProcessInformationClass)\n    {\n        case KphProcessQuotaLimits:\n        {\n            processInformationClass = ProcessQuotaLimits;\n            break;\n        }\n        case KphProcessBasePriority:\n        {\n            processInformationClass = ProcessBasePriority;\n            break;\n        }\n        case KphProcessRaisePriority:\n        {\n            processInformationClass = ProcessRaisePriority;\n            break;\n        }\n        case KphProcessPriorityClass:\n        {\n            processInformationClass = ProcessPriorityClass;\n            break;\n        }\n        case KphProcessAffinityMask:\n        {\n            processInformationClass = ProcessAffinityMask;\n            break;\n        }\n        case KphProcessPriorityBoost:\n        {\n            processInformationClass = ProcessPriorityBoost;\n            break;\n        }\n        case KphProcessIoPriority:\n        {\n            processInformationClass = ProcessIoPriority;\n            break;\n        }\n        case KphProcessPagePriority:\n        {\n            processInformationClass = ProcessPagePriority;\n            break;\n        }\n        case KphProcessPowerThrottlingState:\n        {\n            processInformationClass = ProcessPowerThrottlingState;\n            break;\n        }\n        case KphProcessPriorityClassEx:\n        {\n            processInformationClass = ProcessPriorityClassEx;\n            break;\n        }\n        case KphProcessEmptyWorkingSet:\n        {\n            QUOTA_LIMITS_EX quotaLimits;\n\n            RtlZeroMemory(&quotaLimits, sizeof(QUOTA_LIMITS_EX));\n            quotaLimits.MinimumWorkingSetSize = SIZE_T_MAX;\n            quotaLimits.MaximumWorkingSetSize = SIZE_T_MAX;\n\n            status = ZwSetInformationProcess(processHandle,\n                                             ProcessQuotaLimits,\n                                             &quotaLimits,\n                                             sizeof(QUOTA_LIMITS_EX));\n            //\n            // Bypass generic call to exit immediately.\n            //\n            goto Exit;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            goto Exit;\n        }\n    }\n\n    status = ZwSetInformationProcess(processHandle,\n                                     processInformationClass,\n                                     processInformation,\n                                     ProcessInformationLength);\n\nExit:\n\n    if (processHandle)\n    {\n        ObCloseHandle(processHandle, KernelMode);\n    }\n\n    if (process)\n    {\n        ObDereferenceObject(process);\n    }\n\n    if (processInformation && (processInformation != ProcessInformation))\n    {\n        KphFreeA(processInformation, KPH_TAG_PROCESS_INFO, stackBuffer);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/protection.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     jxy-s   2020-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_ENUM_FOR_PROTECTION\n{\n    PKPH_DYN Dyn;\n    PKPH_PROCESS_CONTEXT ProcessEnum;\n    PKPH_PROCESS_CONTEXT Process;\n    NTSTATUS Status;\n} KPH_ENUM_FOR_PROTECTION, *PKPH_ENUM_FOR_PROTECTION;\n\ntypedef struct _KPH_IMAGE_LOAD_APC\n{\n    KSI_KAPC Apc;\n    PKPH_PROCESS_CONTEXT Process;\n    PVOID ImageBase;\n    PFILE_OBJECT FileObject;\n} KPH_IMAGE_LOAD_APC, *PKPH_IMAGE_LOAD_APC;\n\ntypedef struct _KPH_IMAGE_LOAD_APC_INIT\n{\n    PKPH_PROCESS_CONTEXT Process;\n    PVOID ImageBase;\n    PFILE_OBJECT FileObject;\n} KPH_IMAGE_LOAD_APC_INIT, *PKPH_IMAGE_LOAD_APC_INIT;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpImageLoadApcTypeName = RTL_CONSTANT_STRING(L\"KphImageLoadApc\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_OBJECT_TYPE KphpImageLoadApcType = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\nstatic KPH_REFERENCE KphpDriverUnloadProtectionRef = { 0 };\nstatic PVOID KphpDriverUnloadPreviousRoutine = NULL;\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Allocates an image load APC object.\n *\n * \\param[in] Size The size to allocate.\n *\n * \\return Allocates image load APC object, null on failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateImageLoadApc(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_PAGED_CODE();\n\n    return KphAllocateNPaged(Size, KPH_TAG_IMAGE_LOAD_APC);\n}\n\n/**\n * \\brief Initializes image load APC object.\n *\n * \\param[in,out] Object The image load APC object to initialize.\n * \\param[in] Parameter The image load ACP initialization structure.\n *\n * \\return STATUS_SUCCESS\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializeImageLoadApc(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_IMAGE_LOAD_APC apc;\n    PKPH_IMAGE_LOAD_APC_INIT init;\n\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Parameter);\n\n    apc = Object;\n    init = Parameter;\n\n    apc->Process = init->Process;\n    KphReferenceObject(apc->Process);\n    apc->ImageBase = init->ImageBase;\n    apc->FileObject = init->FileObject;\n    if (apc->FileObject)\n    {\n        ObReferenceObject(apc->FileObject);\n    }\n\n    KphReferenceHashingInfrastructure();\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Deletes image load APC object.\n *\n * \\param[in,out] Object The image load APC object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\nVOID KSIAPI KphpDeleteImageLoadApc(\n    _Inout_ PVOID Object\n    )\n{\n    PKPH_IMAGE_LOAD_APC apc;\n\n    KPH_PAGED_CODE();\n\n    apc = Object;\n\n    KphDereferenceObject(apc->Process);\n\n    if (apc->FileObject)\n    {\n        ObDereferenceObject(apc->FileObject);\n    }\n\n    KphDereferenceHashingInfrastructure();\n}\n\n/**\n * \\brief Frees an image load APC object.\n *\n * \\param[in] Object Image load APC object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\nVOID KSIAPI KphpFreeImageLoadApc(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphFree(Object, KPH_TAG_IMAGE_LOAD_APC);\n}\n\n/**\n * \\brief Checks if object protections should be allowed.\n *\n * \\param[in] Info Optional object pre operation information.\n * \\param[in] Actor The actor process requesting access.\n * \\param[in] Object The process context associated with the object.\n * \\param[out] Allow Receives TRUE if object protections should be allowed,\n * FALSE otherwise.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpShouldAllowObjectAccess(\n    _In_opt_ POB_PRE_OPERATION_INFORMATION Info,\n    _In_ PKPH_PROCESS_CONTEXT Actor,\n    _In_ PKPH_PROCESS_CONTEXT Object,\n    _Out_ PBOOLEAN Allow\n    )\n{\n    NTSTATUS status;\n    PKPH_PROCESS_CONTEXT source;\n    PKPH_PROCESS_CONTEXT target;\n    BOOLEAN isLsass;\n\n    KPH_PAGED_CODE();\n\n    *Allow = FALSE;\n\n    source = NULL;\n    target = NULL;\n\n    NT_ASSERT(Object->Protected);\n\n    if (!Info || (Info->Operation == OB_OPERATION_HANDLE_CREATE))\n    {\n        //\n        // Allow access to itself.\n        //\n        if (Actor->EProcess == Object->EProcess)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"Process %wZ (%lu) allowed to access itself\",\n                          &Actor->ImageName,\n                          HandleToULong(Actor->ProcessId));\n\n            *Allow = TRUE;\n            status = STATUS_SUCCESS;\n            goto Exit;\n        }\n\n        //\n        // Allow maximum state processes access to one another.\n        //\n        if (KphTestProcessContextState(Actor, KPH_PROCESS_STATE_MAXIMUM) &&\n            KphTestProcessContextState(Object, KPH_PROCESS_STATE_MAXIMUM))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"Maximum state process %wZ (%lu) allowed to access \"\n                          \"maximum state process %wZ (%lu)\",\n                          &Actor->ImageName,\n                          HandleToULong(Actor->ProcessId),\n                          &Object->ImageName,\n                          HandleToULong(Object->ProcessId));\n\n            *Allow = TRUE;\n            status = STATUS_SUCCESS;\n            goto Exit;\n        }\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Process %wZ (%lu) possibly subject to limited access \"\n                      \"to process %wZ (%lu)\",\n                      &Actor->ImageName,\n                      HandleToULong(Actor->ProcessId),\n                      &Object->ImageName,\n                      HandleToULong(Object->ProcessId));\n    }\n    else if (Info && (Info->Operation == OB_OPERATION_HANDLE_DUPLICATE))\n    {\n        PEPROCESS process;\n\n        //\n        // Allow duplication to itself into itself from itself.\n        //\n        if ((Object->EProcess == Actor->EProcess) &&\n            (Object->EProcess == Info->Parameters->DuplicateHandleInformation.SourceProcess) &&\n            (Object->EProcess == Info->Parameters->DuplicateHandleInformation.TargetProcess))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"Process %wZ (%lu) allowed to access itself\",\n                          &Actor->ImageName,\n                          HandleToULong(Actor->ProcessId));\n\n            *Allow = TRUE;\n            status = STATUS_SUCCESS;\n            goto Exit;\n        }\n\n        process = Info->Parameters->DuplicateHandleInformation.SourceProcess;\n        source = KphGetEProcessContext(process);\n        if (!source)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"KphGetEProcessContext(%lu) returned NULL\",\n                          HandleToULong(PsGetProcessId(process)));\n\n            status = STATUS_INVALID_CID;\n            goto Exit;\n        }\n\n        process = Info->Parameters->DuplicateHandleInformation.TargetProcess;\n        target = KphGetEProcessContext(process);\n        if (!target)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"KphGetEProcessContext(%lu) returned NULL\",\n                          HandleToULong(PsGetProcessId(process)));\n\n            status = STATUS_INVALID_CID;\n            goto Exit;\n        }\n\n        //\n        // Allow duplication between maximum state processes.\n        //\n        if (KphTestProcessContextState(Actor, KPH_PROCESS_STATE_MAXIMUM) &&\n            KphTestProcessContextState(source, KPH_PROCESS_STATE_MAXIMUM) &&\n            KphTestProcessContextState(target, KPH_PROCESS_STATE_MAXIMUM))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"Maximum state process %wZ (%lu) allowed to duplicate \"\n                          \"object for process %wZ (%lu) from maximum state \"\n                          \"process %wZ (%lu) to maximum state process %wZ (%lu)\",\n                          &Actor->ImageName,\n                          HandleToULong(Actor->ProcessId),\n                          &Object->ImageName,\n                          HandleToULong(Object->ProcessId),\n                          &source->ImageName,\n                          HandleToULong(source->ProcessId),\n                          &target->ImageName,\n                          HandleToULong(target->ProcessId));\n\n            *Allow = TRUE;\n            status = STATUS_SUCCESS;\n            goto Exit;\n        }\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Process %wZ (%lu) possibly subject to limited access \"\n                      \"to object for process %wZ (%lu) when duplicating object \"\n                      \"from process %wZ (%lu) to process %wZ (%lu)\",\n                      &Actor->ImageName,\n                      HandleToULong(Actor->ProcessId),\n                      &Object->ImageName,\n                      HandleToULong(Object->ProcessId),\n                      &source->ImageName,\n                      HandleToULong(source->ProcessId),\n                      &target->ImageName,\n                      HandleToULong(target->ProcessId));\n    }\n\n    status = KphDominationCheck(Object->EProcess, Actor->EProcess, UserMode);\n    if (!NT_SUCCESS(status))\n    {\n        //\n        // Allow access when the actor is a protected process and the target is\n        // not protected at a higher level.\n        //\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"PPL process %wZ (%lu) allowed to access process %wZ (%lu)\",\n                      &Actor->ImageName,\n                      HandleToULong(Actor->ProcessId),\n                      &Object->ImageName,\n                      HandleToULong(Object->ProcessId));\n\n        *Allow = TRUE;\n        status = STATUS_SUCCESS;\n        goto Exit;\n    }\n\n    status = KphProcessIsLsass(Actor->EProcess, &isLsass);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphProcessIsLsass failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (isLsass)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"LSA process %wZ (%lu) allowed to access process %wZ (%lu)\",\n                      &Actor->ImageName,\n                      HandleToULong(Actor->ProcessId),\n                      &Object->ImageName,\n                      HandleToULong(Object->ProcessId));\n\n        *Allow = TRUE;\n        goto Exit;\n    }\n\nExit:\n\n    if (target)\n    {\n        KphDereferenceObject(target);\n    }\n\n    if (source)\n    {\n        KphDereferenceObject(source);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Handle enumeration callback for protecting a process.\n *\n * \\param[in,out] HandleTableEntry The handle table entry being enumerated.\n * \\param[in] Handle The handle being enumerated.\n * \\param[in] Parameter The enumerate for protection context.\n *\n * \\return FALSE to continue enumerating, TRUE to stop.\n */\n_Function_class_(KPH_ENUM_PROCESS_HANDLES_CALLBACK)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nBOOLEAN KSIAPI KphpEnumProcessHandlesForProtection(\n    _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,\n    _In_ HANDLE Handle,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PKPH_ENUM_FOR_PROTECTION parameter;\n    POBJECT_HEADER objectHeader;\n    PVOID object;\n    POBJECT_TYPE objectType;\n    ACCESS_MASK grantedAccess;\n    ACCESS_MASK allowedAccessMask;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(Parameter);\n\n    parameter = Parameter;\n\n    if (IsKernelHandle(Handle))\n    {\n        //\n        // Don't screw with kernel handles.\n        //\n        return FALSE;\n    }\n\n    objectHeader = KphObpDecodeObject(parameter->Dyn, HandleTableEntry);\n    if (!objectHeader)\n    {\n        //\n        // We don't have the dynamic data necessary to do work.\n        //\n        parameter->Status = STATUS_NOINTERFACE;\n        return TRUE;\n    }\n\n    object = (PVOID)&objectHeader->Body;\n    objectType = ObGetObjectType(object);\n\n    if (objectType == *PsProcessType)\n    {\n        if (parameter->Process->EProcess != object)\n        {\n            return FALSE;\n        }\n\n        grantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess);\n        allowedAccessMask = parameter->Process->ProcessAllowedMask;\n\n        if ((grantedAccess & allowedAccessMask) != grantedAccess)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"Modifying process handle (0x%04x, 0x%08x -> 0x%08x) \"\n                          \"permissions in process %wZ (%lu) for process %wZ (%lu)\",\n                          HandleToULong(Handle),\n                          grantedAccess,\n                          (grantedAccess & allowedAccessMask),\n                          &parameter->ProcessEnum->ImageName,\n                          HandleToULong(parameter->ProcessEnum->ProcessId),\n                          &parameter->Process->ImageName,\n                          HandleToULong(parameter->Process->ProcessId));\n\n            ObpSetGrantedAccess(&HandleTableEntry->GrantedAccess,\n                                (grantedAccess & allowedAccessMask));\n        }\n\n        return FALSE;\n    }\n\n    if (objectType == *PsThreadType)\n    {\n        PEPROCESS process;\n\n        process = PsGetThreadProcess(object);\n\n        if (parameter->Process->EProcess != process)\n        {\n            return FALSE;\n        }\n\n        grantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess);\n        allowedAccessMask = parameter->Process->ThreadAllowedMask;\n\n        if ((grantedAccess & allowedAccessMask) != grantedAccess)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"Modifying thread handle (0x%04x, 0x%08x -> 0x%08x) \"\n                          \"permissions in process %wZ (%lu) for process %wZ (%lu)\",\n                          HandleToULong(Handle),\n                          grantedAccess,\n                          (grantedAccess & allowedAccessMask),\n                          &parameter->ProcessEnum->ImageName,\n                          HandleToULong(parameter->ProcessEnum->ProcessId),\n                          &parameter->Process->ImageName,\n                          HandleToULong(parameter->Process->ProcessId));\n\n            ObpSetGrantedAccess(&HandleTableEntry->GrantedAccess,\n                                (grantedAccess & allowedAccessMask));\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * \\brief Process context enumeration callback for process protection.\n *\n * \\param[in] Process The process context being enumerated.\n * \\param[in] Parameter The enumerate for protection context.\n *\n * \\return FALSE to continue enumerating, TRUE to stop.\n */\n_Function_class_(KPH_ENUM_PROCESS_CONTEXTS_CALLBACK)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nBOOLEAN KSIAPI KphpEnumProcessContextsForProtection(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PKPH_ENUM_FOR_PROTECTION parameter;\n    BOOLEAN allow;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(Parameter);\n\n    parameter = Parameter;\n\n    allow = FALSE;\n    status = KphpShouldAllowObjectAccess(NULL,\n                                         Process,\n                                         parameter->Process,\n                                         &allow);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphpShouldAllowObjectAccess failed: %!STATUS!\",\n                      status);\n\n        //\n        // This usually means we don't have the dynamic data to do work.\n        // We can't guarantee both protection and application compatibility.\n        //\n        parameter->Status = status;\n\n        return TRUE;\n    }\n\n    if (allow)\n    {\n        return FALSE;\n    }\n\n    parameter->ProcessEnum = Process;\n\n    status = KphEnumerateProcessHandlesEx(Process->EProcess,\n                                          KphpEnumProcessHandlesForProtection,\n                                          parameter);\n    if (status == STATUS_NOINTERFACE)\n    {\n        //\n        // This means we don't have the dynamic data necessary to do work.\n        // All other errors are failure to access process objects because\n        // the process is exiting or has no object table.\n        //\n        parameter->Status = status;\n\n        return TRUE;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphEnumerateProcessHandlesEx failed: %!STATUS!\",\n                      status);\n    }\n\n    return FALSE;\n}\n\n/**\n * \\brief Stops protecting a process.\n *\n * \\param[in] Process The process to stop protecting.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphStopProtectingProcess(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphAcquireRWLockExclusive(&Process->ProtectionLock);\n    Process->Protected = FALSE;\n    Process->ProcessAllowedMask = 0;\n    Process->ThreadAllowedMask = 0;\n    KphReleaseRWLock(&Process->ProtectionLock);\n\n    KphTracePrint(TRACE_LEVEL_INFORMATION,\n                  PROTECTION,\n                  \"Stopped protecting process %wZ (%lu)\",\n                  &Process->ImageName,\n                  HandleToULong(Process->ProcessId));\n}\n\n/**\n * \\brief Determines if a process is protected.\n *\n * \\param[in] Process The process to check.\n *\n * \\return TRUE if the process is protected, FALSE otherwise.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nBOOLEAN KphIsProtectedProcess(\n    _In_ PKPH_PROCESS_CONTEXT Process\n    )\n{\n    BOOLEAN isProtectedProcess;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphAcquireRWLockShared(&Process->ProtectionLock);\n    isProtectedProcess = Process->Protected ? TRUE : FALSE;\n    KphReleaseRWLock(&Process->ProtectionLock);\n\n    return isProtectedProcess;\n}\n\n/**\n * \\brief Starts protecting a process.\n *\n * \\param[in] Process The process to start protecting.\n * \\param[in] ProcessAllowedMask Access mask containing the allowed access to\n * the process.\n * \\param[in] ThreadAllowedMask Access mask containing the allowed access to\n * the process threads.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphStartProtectingProcess(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_ ACCESS_MASK ProcessAllowedMask,\n    _In_ ACCESS_MASK ThreadAllowedMask\n    )\n{\n    NTSTATUS status;\n    BOOLEAN releaseLock;\n    SECURITY_SUBJECT_CONTEXT subjectContext;\n    BOOLEAN accessGranted;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    releaseLock = FALSE;\n\n    //\n    // N.B. We must be able to identify lsass before applying protections.\n    // Without the ability to identify lsass, a process may fail to start.\n    // Normally, lsass runs as a protected process; however, if it is not,\n    // we rely on dynamic data to identify it. If a system configuration\n    // does not run lsass as a protected process and also lacks dynamic data\n    // support, we cannot guarantee application compatibility or protection.\n    // In that case, access to the driver will be restricted.\n    //\n    // This distinction is important later within the object callbacks.\n    // Note that the KphpShouldAllowObjectAccess call in KphApplyObProtections\n    // depends on KphProcessIsLsass.\n    //\n    if (!KphCanIdentifyLsass())\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphCanIdentifyLsass failed\");\n\n        status = STATUS_NOINTERFACE;\n        goto Exit;\n    }\n\n    SeCaptureSubjectContextEx(NULL, Process->EProcess, &subjectContext);\n    accessGranted = KphSinglePrivilegeCheckEx(SeDebugPrivilege,\n                                              &subjectContext,\n                                              UserMode);\n    SeReleaseSubjectContext(&subjectContext);\n    if (!accessGranted)\n    {\n        status = STATUS_PRIVILEGE_NOT_HELD;\n        goto Exit;\n    }\n\n    KphAcquireRWLockExclusive(&Process->ProtectionLock);\n    releaseLock = TRUE;\n\n    if (Process->Protected)\n    {\n        KphTracePrint(TRACE_LEVEL_INFORMATION,\n                      PROTECTION,\n                      \"Already protecting process %wZ (%lu)\",\n                      &Process->ImageName,\n                      HandleToULong(Process->ProcessId));\n\n        status = STATUS_ALREADY_COMPLETE;\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_INFORMATION,\n                  PROTECTION,\n                  \"Started protecting process %wZ (%lu)\",\n                  &Process->ImageName,\n                  HandleToULong(Process->ProcessId));\n\n    Process->Protected = TRUE;\n    Process->ProcessAllowedMask = ProcessAllowedMask;\n    Process->ThreadAllowedMask = ThreadAllowedMask;\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (releaseLock)\n    {\n        KphReleaseRWLock(&Process->ProtectionLock);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Returns true if we should permit extending handle permissions for\n * the creator process.\n *\n * \\param[in] Info Object pre operation information.\n * \\param[in] Actor The actor thread.\n * \\param[in] ProcessTarget The process to check against.\n *\n * \\return TRUE if we should permit, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\nBOOLEAN KphpShouldPermitCreatorProcess(\n    _In_ POB_PRE_OPERATION_INFORMATION Info,\n    _In_ PKPH_THREAD_CONTEXT Actor,\n    _In_ PKPH_PROCESS_CONTEXT Process\n    )\n{\n    KPH_PAGED_CODE();\n\n    NT_ASSERT(Process->VerifiedProcess);\n\n    if (Info->Operation == OB_OPERATION_HANDLE_DUPLICATE)\n    {\n        return FALSE;\n    }\n\n    NT_ASSERT(Info->Operation == OB_OPERATION_HANDLE_CREATE);\n\n    if (!Actor->IsCreatingProcess ||\n        (Actor->IsCreatingProcessId != Process->ProcessId))\n    {\n        return FALSE;\n    }\n\n    return KphTestProcessContextState(Actor->ProcessContext,\n                                      KPH_PROCESS_STATE_MINIMUM);\n}\n\n/**\n * \\brief Applies object protections to protected processes. Invoked by the\n * object manager callbacks.\n *\n * \\param[in,out] Info Object pre operation information to apply protections.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphApplyObProtections(\n    _Inout_ POB_PRE_OPERATION_INFORMATION Info\n    )\n{\n    NTSTATUS status;\n    PKPH_PROCESS_CONTEXT process;\n    PKPH_THREAD_CONTEXT actor;\n    BOOLEAN releaseLock;\n    ACCESS_MASK allowedAccessMask;\n    ACCESS_MASK desiredAccess;\n    PACCESS_MASK access;\n    BOOLEAN allow;\n\n    KPH_PAGED_CODE();\n\n    process = NULL;\n    actor = NULL;\n    releaseLock = FALSE;\n\n    if ((Info->ObjectType != *PsProcessType) &&\n        (Info->ObjectType != *PsThreadType))\n    {\n        goto Exit;\n    }\n\n    if (Info->KernelHandle)\n    {\n        goto Exit;\n    }\n\n    actor = KphGetCurrentThreadContext();\n    if (!actor || !actor->ProcessContext)\n    {\n        goto Exit;\n    }\n\n    if (Info->ObjectType == *PsProcessType)\n    {\n        process = KphGetEProcessContext(Info->Object);\n    }\n    else\n    {\n        PKPH_THREAD_CONTEXT thread;\n\n        NT_ASSERT(Info->ObjectType == *PsThreadType);\n\n        thread = KphGetEThreadContext(Info->Object);\n        if (thread)\n        {\n            process = thread->ProcessContext;\n            if (process)\n            {\n                KphReferenceObject(process);\n            }\n\n            KphDereferenceObject(thread);\n        }\n    }\n\n    if (!process)\n    {\n        goto Exit;\n    }\n\n    if (Info->Operation == OB_OPERATION_HANDLE_CREATE)\n    {\n        access = &Info->Parameters->CreateHandleInformation.DesiredAccess;\n        desiredAccess = *access;\n    }\n    else\n    {\n        NT_ASSERT(Info->Operation == OB_OPERATION_HANDLE_DUPLICATE);\n\n        access = &Info->Parameters->DuplicateHandleInformation.DesiredAccess;\n        desiredAccess = *access;\n    }\n\n    KphAcquireRWLockShared(&process->ProtectionLock);\n    releaseLock = TRUE;\n\n    if (!process->Protected)\n    {\n        goto Exit;\n    }\n\n    allow = FALSE;\n    status = KphpShouldAllowObjectAccess(Info,\n                                         actor->ProcessContext,\n                                         process,\n                                         &allow);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_WARNING,\n                      PROTECTION,\n                      \"KphpShouldAllowObjectAccess failed: %!STATUS!\",\n                      status);\n\n        //\n        // We shouldn't get here since we would have succeeded when starting to\n        // protect the process to begin with. So if we fail here we fail-safe\n        // and do not allow.\n        //\n        allow = FALSE;\n    }\n\n    if (allow)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Allowing process %wZ (%lu) access (0x%08x) to \"\n                      \"process %wZ (%lu)\",\n                      &actor->ProcessContext->ImageName,\n                      HandleToULong(actor->ProcessContext->ProcessId),\n                      desiredAccess,\n                      &process->ImageName,\n                      HandleToULong(process->ProcessId));\n\n        goto Exit;\n    }\n\n    if (Info->ObjectType == *PsProcessType)\n    {\n        allowedAccessMask = process->ProcessAllowedMask;\n\n        if (KphpShouldPermitCreatorProcess(Info, actor, process))\n        {\n            allowedAccessMask |= (KPH_PROCESS_READ_ACCESS |\n                                  PROCESS_TERMINATE |\n                                  PROCESS_VM_OPERATION |\n                                  PROCESS_VM_WRITE);\n\n            if ((allowedAccessMask & process->ProcessAllowedMask)\n                != allowedAccessMask)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              PROTECTION,\n                              \"Permitting extra process handle access \"\n                              \"(0x%08x -> 0x%08x) in creator process %wZ (%lu) for \"\n                              \"process %wZ (%lu)\",\n                              process->ProcessAllowedMask,\n                              allowedAccessMask,\n                              &actor->ProcessContext->ImageName,\n                              HandleToULong(actor->ProcessContext->ProcessId),\n                              &process->ImageName,\n                              HandleToULong(process->ProcessId));\n            }\n        }\n\n        if ((desiredAccess & allowedAccessMask) != desiredAccess)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"Stripping process handle (0x%08x -> 0x%08x) \"\n                          \"permissions in process %wZ (%lu) for process %wZ (%lu) (0x%08x)\",\n                          desiredAccess,\n                          (desiredAccess & allowedAccessMask),\n                          &actor->ProcessContext->ImageName,\n                          HandleToULong(actor->ProcessContext->ProcessId),\n                          &process->ImageName,\n                          HandleToULong(process->ProcessId),\n                          allowedAccessMask);\n\n            *access = (desiredAccess & allowedAccessMask);\n        }\n    }\n    else\n    {\n        NT_ASSERT(Info->ObjectType == *PsThreadType);\n\n        allowedAccessMask = process->ThreadAllowedMask;\n\n        if (KphpShouldPermitCreatorProcess(Info, actor, process))\n        {\n            allowedAccessMask |= (KPH_THREAD_READ_ACCESS |\n                                  THREAD_TERMINATE |\n                                  THREAD_RESUME);\n\n            if ((allowedAccessMask & process->ThreadAllowedMask)\n                != allowedAccessMask)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              PROTECTION,\n                              \"Permitting extra thread handle access \"\n                              \"(0x%08x -> 0x%08x) in creator process %wZ (%lu) for \"\n                              \"process %wZ (%lu)\",\n                              process->ThreadAllowedMask,\n                              allowedAccessMask,\n                              &actor->ProcessContext->ImageName,\n                              HandleToULong(actor->ProcessContext->ProcessId),\n                              &process->ImageName,\n                              HandleToULong(process->ProcessId));\n            }\n        }\n\n        if ((desiredAccess & allowedAccessMask) != desiredAccess)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          PROTECTION,\n                          \"Stripping thread handle (0x%08x -> 0x%08x) \"\n                          \"permissions in process %wZ (%lu) for process %wZ (%lu) (0x%08x)\",\n                          desiredAccess,\n                          (desiredAccess & allowedAccessMask),\n                          &actor->ProcessContext->ImageName,\n                          HandleToULong(actor->ProcessContext->ProcessId),\n                          &process->ImageName,\n                          HandleToULong(process->ProcessId),\n                          allowedAccessMask);\n\n            *access = (desiredAccess & allowedAccessMask);\n        }\n    }\n\nExit:\n\n    if (process)\n    {\n        if (releaseLock)\n        {\n            KphReleaseRWLock(&process->ProtectionLock);\n        }\n\n        KphDereferenceObject(process);\n    }\n\n    if (actor)\n    {\n        KphDereferenceObject(actor);\n    }\n}\n\n/**\n * \\brief Cleanup routine for the image load APC.\n *\n * \\param[in] Apc The APC to clean up.\n * \\param[in] Reason Unused.\n */\n_Function_class_(KSI_KCLEANUP_ROUTINE)\n_IRQL_requires_min_(PASSIVE_LEVEL)\n_IRQL_requires_max_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpImageLoadCleanupRoutine(\n    _In_ PKSI_KAPC Apc,\n    _In_ KSI_KAPC_CLEANUP_REASON Reason\n    )\n{\n    PKPH_IMAGE_LOAD_APC apc;\n\n    KPH_PAGED_CODE();\n\n    UNREFERENCED_PARAMETER(Reason);\n\n    apc = CONTAINING_RECORD(Apc, KPH_IMAGE_LOAD_APC, Apc);\n\n    KphDereferenceObject(apc);\n}\n\n/**\n * \\brief Normal kernel APC routine where we carry out image load denial.\n *\n * \\param[in] NormalContext Unused.\n * \\param[in] SystemArgument1 Image load APC object.\n * \\param[in] SystemArgument2 Unused.\n */\n_Function_class_(KNORMAL_ROUTINE)\n_IRQL_requires_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID NTAPI KphpImageLoadKernelNormalRoutine(\n    _In_opt_ PVOID NormalContext,\n    _In_opt_ PVOID SystemArgument1,\n    _In_opt_ PVOID SystemArgument2\n    )\n{\n    NTSTATUS status;\n    PKPH_IMAGE_LOAD_APC apc;\n    KAPC_STATE apcState;\n    BOOLEAN attachToTarget;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(NormalContext);\n    UNREFERENCED_PARAMETER(SystemArgument2);\n\n    NT_ASSERT(SystemArgument1);\n\n    apc = SystemArgument1;\n\n    NT_ASSERT(apc->ImageBase <= MmHighestUserAddress);\n\n    attachToTarget = (apc->Process->EProcess != PsGetCurrentProcess());\n    if (attachToTarget)\n    {\n        KeStackAttachProcess(apc->Process->EProcess, &apcState);\n    }\n\n    status = ZwUnmapViewOfSection(ZwCurrentProcess(), apc->ImageBase);\n\n    if (attachToTarget)\n    {\n        KeUnstackDetachProcess(&apcState);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"ZwUnmapViewOfSection failed (%wZ (%lu), %p): %!STATUS!\",\n                      &apc->Process->ImageName,\n                      HandleToULong(apc->Process->ProcessId),\n                      apc->ImageBase,\n                      status);\n\n        InterlockedIncrementSizeT(&apc->Process->NumberOfUntrustedImageLoads);\n    }\n    else\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Unmapped %p from process %wZ (%lu)\",\n                      apc->ImageBase,\n                      &apc->Process->ImageName,\n                      HandleToULong(apc->Process->ProcessId));\n    }\n}\n\n/**\n * \\param Second kernel APC routine, say hi on the way down to passive :).\n *\n * \\param[in] Apc Unused.\n * \\param[in,out] NormalRoutine Pointer to the normal kernel APC routine.\n * \\param[in,out] NormalContext Unused.\n * \\param[in,out] SystemArgument1 Pointer to the image load APC object.\n * \\param[in,out] SystemArgument2 Unused.\n */\n_Function_class_(KSI_KKERNEL_ROUTINE)\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpImageLoadKernelRoutineSecond(\n    _In_ PKSI_KAPC Apc,\n    _Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE* NormalRoutine,\n    _Inout_ _Deref_pre_maybenull_ PVOID* NormalContext,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument1,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2\n    )\n{\n    KPH_PAGED_CODE_APC();\n\n    UNREFERENCED_PARAMETER(Apc);\n    DBG_UNREFERENCED_PARAMETER(NormalRoutine);\n    UNREFERENCED_PARAMETER(NormalContext);\n    DBG_UNREFERENCED_PARAMETER(SystemArgument1);\n    UNREFERENCED_PARAMETER(SystemArgument2);\n\n    NT_ASSERT(*NormalRoutine == KphpImageLoadKernelNormalRoutine);\n    NT_ASSERT(*SystemArgument1);\n    NT_ASSERT(KphGetObjectType(*SystemArgument1) == KphpImageLoadApcType);\n}\n\n/**\n * \\brief First kernel APC routine, fired by the thread returning from the\n * system. We will stage another normal kernel APC to fire at passive here.\n *\n * \\param[in] Apc The APC object that is executing.\n * \\param[in,out] NormalRoutine Points to the faked routine, we'll cancel it.\n * \\param[in,out] NormalContext Unused.\n * \\param[in,out] SystemArgument1 Unused.\n * \\param[in,out] SystemArgument2 Unused.\n */\n_Function_class_(KSI_KKERNEL_ROUTINE)\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpImageLoadKernelRoutineFirst(\n    _In_ PKSI_KAPC Apc,\n    _Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE* NormalRoutine,\n    _Inout_ _Deref_pre_maybenull_ PVOID* NormalContext,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument1,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2\n    )\n{\n    NTSTATUS status;\n    PKPH_IMAGE_LOAD_APC firstApc;\n    PKPH_IMAGE_LOAD_APC secondApc;\n    KPH_IMAGE_LOAD_APC_INIT init;\n\n    KPH_PAGED_CODE_APC();\n\n    secondApc = NULL;\n\n    firstApc = CONTAINING_RECORD(Apc, KPH_IMAGE_LOAD_APC, Apc);\n\n    UNREFERENCED_PARAMETER(NormalRoutine);\n\n    *NormalContext = NULL;\n    *SystemArgument1 = NULL;\n    *SystemArgument2 = NULL;\n\n    init.Process = firstApc->Process;\n    init.ImageBase = firstApc->ImageBase;\n    init.FileObject = NULL;\n    status = KphCreateObject(KphpImageLoadApcType,\n                             sizeof(KPH_IMAGE_LOAD_APC),\n                             &secondApc,\n                             &init);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n\n        secondApc = NULL;\n        goto Exit;\n    }\n\n    //\n    // Initialize a normal kernel ACP to drop down to passive.\n    //\n    KsiInitializeApc(&secondApc->Apc,\n                     KphDriverObject,\n                     KeGetCurrentThread(),\n                     OriginalApcEnvironment,\n                     KphpImageLoadKernelRoutineSecond,\n                     KphpImageLoadCleanupRoutine,\n                     KphpImageLoadKernelNormalRoutine,\n                     KernelMode,\n                     NULL);\n\n    if (!KsiInsertQueueApc(&secondApc->Apc, secondApc, NULL, IO_NO_INCREMENT))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KsiInsertQueueApc failed\");\n\n        status = STATUS_UNSUCCESSFUL;\n        goto Exit;\n    }\n\n    secondApc = NULL;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (secondApc)\n    {\n        KphDereferenceObject(secondApc);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Untrusted image load (%wZ (%lu), %p): %!STATUS!\",\n                      &firstApc->Process->ImageName,\n                      HandleToULong(firstApc->Process->ProcessId),\n                      firstApc->ImageBase,\n                      status);\n\n        //\n        // No choice other than to just track that there is an untrusted image.\n        //\n        InterlockedIncrementSizeT(&firstApc->Process->NumberOfUntrustedImageLoads);\n    }\n}\n\n/**\n * \\brief Handles an untrusted image load in a verified process.\n *\n * \\details If a failure is encountered in this path or if image load denial\n * is disabled we will denote in the target process that an untrusted image\n * was loaded. The approach here is to queue a user APC to execute when\n * the thread returns from the system. Then, we issue another APC to drop\n * down to passive level and remove the image mapping from the process.\n *\n * \\param[in,out] Process The process where the image is being loaded.\n * \\param[in] ImageBase The base address of the untrusted image.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpHandleUntrustedImageLoad(\n    _Inout_ PKPH_PROCESS_CONTEXT Process,\n    _In_ PVOID ImageBase\n    )\n{\n    NTSTATUS status;\n    PKPH_THREAD_CONTEXT actor;\n    KPH_IMAGE_LOAD_APC_INIT init;\n    PKPH_IMAGE_LOAD_APC apc;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(Process->VerifiedProcess);\n\n    status = STATUS_UNSUCCESSFUL;\n    actor = NULL;\n    apc = NULL;\n\n    if (KphParameterFlags.DisableImageLoadProtection)\n    {\n        //\n        // Image load protections are disable. Do not deny the image load. We\n        // will still mark an untrusted image load. This will restrict access\n        // to the driver.\n        //\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Image load protections are disabled.\");\n        goto Exit;\n    }\n\n    if ((ReadSizeTAcquire(&Process->NumberOfImageLoads) == 1) &&\n        (PsGetProcessSectionBaseAddress(Process->EProcess) == ImageBase))\n    {\n        //\n        // The primary image is being loaded. Rather than deny the image load\n        // we will allow it to go through but will still mark an untrusted\n        // image load. This will restrict access to the driver. But will allow\n        // the process to continue starting.\n        //\n        // N.B. If another untrusted image is loaded other than the primary\n        // image that is critical to starting the process, it will still fail\n        // to start.\n        //\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Image base is the process section base address.\");\n        goto Exit;\n    }\n\n    actor = KphGetCurrentThreadContext();\n    if (!actor || !actor->ProcessContext)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Insufficient tracking.\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphCheckProcessApcNoopRoutine(actor->ProcessContext);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphCheckProcessApcNoopRoutine failed: %!STATUS!\",\n                      status);\n        goto Exit;\n    }\n\n    if (ImageBase > MmHighestUserAddress)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE, PROTECTION, \"Invalid image base!\");\n\n        //\n        // This isn't an error, we just check for safety downstream.\n        //\n        status = STATUS_SUCCESS;\n        goto Exit;\n    }\n\n    init.Process = Process;\n    init.ImageBase = ImageBase;\n    init.FileObject = NULL;\n    status = KphCreateObject(KphpImageLoadApcType,\n                             sizeof(KPH_IMAGE_LOAD_APC),\n                             &apc,\n                             &init);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        apc = NULL;\n        goto Exit;\n    }\n\n    KsiInitializeApc(&apc->Apc,\n                     KphDriverObject,\n                     actor->EThread,\n                     OriginalApcEnvironment,\n                     KphpImageLoadKernelRoutineFirst,\n                     KphpImageLoadCleanupRoutine,\n                     actor->ProcessContext->ApcNoopRoutine,\n                     UserMode,\n                     NULL);\n\n    if (!KsiInsertQueueApc(&apc->Apc, NULL, NULL, IO_NO_INCREMENT))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KsiInsertQueueApc failed\");\n\n        status = STATUS_UNSUCCESSFUL;\n        goto Exit;\n    }\n\n    //\n    // Stage the thread for user mode APC delivery.\n    //\n    KeTestAlertThread(UserMode);\n\n    apc = NULL;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (apc)\n    {\n        KphDereferenceObject(apc);\n    }\n\n    if (actor)\n    {\n        KphDereferenceObject(actor);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Untrusted image load (%wZ (%lu), %p): %!STATUS!\",\n                      &Process->ImageName,\n                      HandleToULong(Process->ProcessId),\n                      ImageBase,\n                      status);\n\n        //\n        // No choice other than to just track that there is an untrusted image.\n        //\n        InterlockedIncrementSizeT(&Process->NumberOfUntrustedImageLoads);\n    }\n}\n\n/**\n * \\brief Re-opens the image file object for the image being loaded.\n *\n * \\details This is unfortunately necessary since the file object from the\n * image load callback is in a state that renders I/O inoperable, due to\n * FO_CLEANUP_COMPLETE being set.\n *\n * \\param[in] ImageFileObject The image file object.\n * \\param[out] FileHandle Receives a handle the to the file.\n * \\param[out] FileObject Receives a reference to the file object.\n * \\param[out] Filename Receives the file name of the image, must be freed\n * using KphFreeNameFileObject.\n * \\param[out] ImageBase Receives the base address of the image mapping in the\n * system address space. Must be unmapped with KphUnmapViewInSystem.\n * \\param[out] ImageSize Receives the size of the image mapping.\n * \\param[out] DataBase Receives the base address of the data mapping in the\n * system address space. Must be unmapped with KphUnmapViewInSystem.\n * \\param[out] DataSize Receives the size of the data mapping.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpReOpenImageFile(\n    _In_ PFILE_OBJECT ImageFileObject,\n    _Out_ PHANDLE FileHandle,\n    _Out_ PFILE_OBJECT* FileObject,\n    _Out_ PUNICODE_STRING* FileName,\n    _Out_ PVOID* ImageBase,\n    _Out_ PSIZE_T ImageSize,\n    _Out_ PVOID* DataBase,\n    _Out_ PSIZE_T DataSize\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n    HANDLE fileHandle;\n    PFILE_OBJECT fileObject;\n    PVOID imageBase;\n    SIZE_T imageSize;\n    PVOID dataBase;\n    SIZE_T dataSize;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    fileHandle = NULL;\n    fileObject = NULL;\n    imageBase = NULL;\n    dataBase = NULL;\n\n    *FileObject = NULL;\n    *FileName = NULL;\n    *ImageBase = NULL;\n    *ImageSize = 0;\n    *DataBase = NULL;\n    *DataSize = 0;\n\n    status = KphGetNameFileObject(ImageFileObject, &fileName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphGetNameFileObject failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    InitializeObjectAttributes(&objectAttributes,\n                               fileName,\n                               OBJ_KERNEL_HANDLE | OBJ_DONT_REPARSE,\n                               NULL,\n                               NULL);\n\n    status = KphCreateFile(&fileHandle,\n                           FILE_READ_ACCESS | SYNCHRONIZE,\n                           &objectAttributes,\n                           &ioStatusBlock,\n                           NULL,\n                           FILE_ATTRIBUTE_NORMAL,\n                           FILE_SHARE_READ,\n                           FILE_OPEN,\n                           (FILE_NON_DIRECTORY_FILE |\n                            FILE_SYNCHRONOUS_IO_NONALERT |\n                            FILE_COMPLETE_IF_OPLOCKED),\n                           NULL,\n                           0,\n                           IO_IGNORE_SHARE_ACCESS_CHECK,\n                           KernelMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphCreateFile failed: %!STATUS!\",\n                      status);\n\n        fileHandle = NULL;\n        goto Exit;\n    }\n    else if (status == STATUS_OPLOCK_BREAK_IN_PROGRESS)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphCreateFile failed: %!STATUS!\",\n                      status);\n\n        status = STATUS_SHARING_VIOLATION;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(fileHandle,\n                                       0,\n                                       *IoFileObjectType,\n                                       KernelMode,\n                                       &fileObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        fileObject = NULL;\n        goto Exit;\n    }\n\n    imageSize = 0;\n    status = KphMapViewInSystem(fileHandle,\n                                KPH_MAP_IMAGE,\n                                &imageBase,\n                                &imageSize);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphMapViewInSystem failed: %!STATUS!\",\n                      status);\n\n        imageBase = NULL;\n        goto Exit;\n    }\n\n    dataSize = 0;\n    status = KphMapViewInSystem(fileHandle,\n                                KPH_MAP_DATA,\n                                &dataBase,\n                                &dataSize);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphMapViewInSystem failed: %!STATUS!\",\n                      status);\n\n        imageBase = NULL;\n        goto Exit;\n    }\n\n    *FileHandle = fileHandle;\n    fileHandle = NULL;\n    *FileObject = fileObject;\n    fileObject = NULL;\n    *FileName = fileName;\n    fileName = NULL;\n    *ImageBase = imageBase;\n    imageBase = NULL;\n    *ImageSize = imageSize;\n    *DataBase = dataBase;\n    dataBase = NULL;\n    *DataSize = dataSize;\n\nExit:\n\n    if (dataBase)\n    {\n        KphUnmapViewInSystem(dataBase);\n    }\n\n    if (imageBase)\n    {\n        KphUnmapViewInSystem(imageBase);\n    }\n\n    if (fileHandle)\n    {\n        ObCloseHandle(fileHandle, KernelMode);\n    }\n\n    if (fileObject)\n    {\n        ObDereferenceObject(fileObject);\n    }\n\n    if (fileName)\n    {\n        KphFreeNameFileObject(fileName);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Applies image protections on verified processes.\n *\n * \\param[in,out] Process The process where the image is being loaded.\n * \\param[in] ImageBase The base address of the image.\n * \\param[in] FileObject The file object for the image being loaded.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpApplyImageProtections(\n    _Inout_ PKPH_PROCESS_CONTEXT Process,\n    _In_ PVOID ImageBase,\n    _In_ PFILE_OBJECT FileObject\n    )\n{\n    NTSTATUS status;\n    PSIZE_T imageLoadCounter;\n    HANDLE fileHandle;\n    PFILE_OBJECT fileObject;\n    PUNICODE_STRING fileName;\n    PVOID imageBase;\n    SIZE_T imageSize;\n    PVOID dataBase;\n    SIZE_T dataSize;\n    SE_SIGNING_LEVEL signingLevel;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(!KeAreAllApcsDisabled());\n\n    imageLoadCounter = NULL;\n    fileHandle = NULL;\n    fileObject = NULL;\n    fileName = NULL;\n    imageBase = NULL;\n    dataBase = NULL;\n\n    if (FileObject->WriteAccess)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"%wZ (%lu) image \\\"%wZ\\\" is writable\",\n                      &Process->ImageName,\n                      HandleToULong(Process->ProcessId),\n                      &FileObject->FileName);\n\n        goto Exit;\n    }\n\n    if (IoGetTransactionParameterBlock(FileObject))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"%wZ (%lu) image \\\"%wZ\\\" is in a transaction\",\n                      &Process->ImageName,\n                      HandleToULong(Process->ProcessId),\n                      &FileObject->FileName);\n\n        goto Exit;\n    }\n\n    if (!FileObject->SectionObjectPointer ||\n        MmDoesFileHaveUserWritableReferences(FileObject->SectionObjectPointer))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"%wZ (%lu) image \\\"%wZ\\\" has user writable references\",\n                      &Process->ImageName,\n                      HandleToULong(Process->ProcessId),\n                      &FileObject->FileName);\n\n        goto Exit;\n    }\n\n    status = KphpReOpenImageFile(FileObject,\n                                 &fileHandle,\n                                 &fileObject,\n                                 &fileName,\n                                 &imageBase,\n                                 &imageSize,\n                                 &dataBase,\n                                 &dataSize);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphpReOpenImageFile: %wZ (%lu) \\\"%wZ\\\": %!STATUS!\",\n                      &Process->ImageName,\n                      HandleToULong(Process->ProcessId),\n                      &FileObject->FileName,\n                      status);\n\n        goto Exit;\n    }\n\n    if (!KphIsSameFile(FileObject, fileObject))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphIsSameFile failed: %wZ (%lu) \\\"%wZ\\\" \\\"%wZ\\\"\",\n                      &Process->ImageName,\n                      HandleToULong(Process->ProcessId),\n                      &FileObject->FileName,\n                      fileName);\n\n        goto Exit;\n    }\n\n    status = KphGetSigningLevel(fileObject, &signingLevel);\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  PROTECTION,\n                  \"KphpGetSigningLevel: %wZ (%lu) \\\"%wZ\\\": 0x%02x %!STATUS!\",\n                  &Process->ImageName,\n                  HandleToULong(Process->ProcessId),\n                  fileName,\n                  signingLevel,\n                  status);\n\n    if (!NT_SUCCESS(status))\n    {\n        signingLevel = SE_SIGNING_LEVEL_UNCHECKED;\n    }\n\n    switch (signingLevel)\n    {\n        case SE_SIGNING_LEVEL_MICROSOFT:\n        case SE_SIGNING_LEVEL_WINDOWS:\n        case SE_SIGNING_LEVEL_WINDOWS_TCB:\n        {\n            imageLoadCounter = &Process->NumberOfMicrosoftImageLoads;\n            goto CheckCoherency;\n        }\n        case SE_SIGNING_LEVEL_ANTIMALWARE:\n        {\n            imageLoadCounter = &Process->NumberOfAntimalwareImageLoads;\n            goto CheckCoherency;\n        }\n        default:\n        {\n            break;\n        }\n    }\n\n    status = KphVerifyFileObject(fileObject, fileName);\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  PROTECTION,\n                  \"KphVerifyFileObject: %wZ (%lu) \\\"%wZ\\\": %!STATUS!\",\n                  &Process->ImageName,\n                  HandleToULong(Process->ProcessId),\n                  fileName,\n                  status);\n\n    if (NT_SUCCESS(status))\n    {\n        imageLoadCounter = &Process->NumberOfVerifiedImageLoads;\n        goto CheckCoherency;\n    }\n\nCheckCoherency:\n\n    status = KphCheckImageCoherency(imageBase, imageSize, dataBase, dataSize);\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  PROTECTION,\n                  \"KphCheckImageCoherency: %wZ (%lu) \\\"%wZ\\\": %!STATUS!\",\n                  &Process->ImageName,\n                  HandleToULong(Process->ProcessId),\n                  fileName,\n                  status);\n\n    if (!NT_SUCCESS(status))\n    {\n        imageLoadCounter = NULL;\n         goto Exit;\n    }\n\nExit:\n\n    if (dataBase)\n    {\n        KphUnmapViewInSystem(dataBase);\n    }\n\n    if (imageBase)\n    {\n        KphUnmapViewInSystem(imageBase);\n    }\n\n    if (imageLoadCounter)\n    {\n        InterlockedIncrementSizeT(imageLoadCounter);\n    }\n    else\n    {\n        KphpHandleUntrustedImageLoad(Process, ImageBase);\n    }\n\n    if (fileName)\n    {\n        KphFreeNameFileObject(fileName);\n    }\n\n    if (fileObject)\n    {\n        ObDereferenceObject(fileObject);\n    }\n\n    if (fileHandle)\n    {\n        ObCloseHandle(fileHandle, KernelMode);\n    }\n}\n\n/**\n * \\brief Normal kernel APC routine for when we must get outside of APC\n * disablement.\n *\n * \\param[in] NormalContext Unused.\n * \\param[in] SystemArgument1 Image load APC object.\n * \\param[in] SystemArgument2 Unused.\n */\n_Function_class_(KNORMAL_ROUTINE)\n_IRQL_requires_(PASSIVE_LEVEL)\n_IRQL_requires_same_\nVOID NTAPI KphpImageLoadKernelNormalRoutineApcsDisabled(\n    _In_opt_ PVOID NormalContext,\n    _In_opt_ PVOID SystemArgument1,\n    _In_opt_ PVOID SystemArgument2\n    )\n{\n    PKPH_IMAGE_LOAD_APC apc;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(NormalContext);\n    UNREFERENCED_PARAMETER(SystemArgument2);\n\n    NT_ASSERT(SystemArgument1);\n\n    apc = SystemArgument1;\n\n    NT_ASSERT(apc->FileObject);\n\n    KphpApplyImageProtections(apc->Process, apc->ImageBase, apc->FileObject);\n}\n\n/**\n * \\brief Kernel APC routine for when we must get outside of APC disablement.\n *\n * \\param[in] Apc Unused.\n * \\param[in,out] NormalRoutine Pointer to the normal kernel APC routine.\n * \\param[in,out] NormalContext Unused.\n * \\param[in,out] SystemArgument1 Pointer to the image load APC object.\n * \\param[in,out] SystemArgument2 Unused.\n */\n_Function_class_(KSI_KKERNEL_ROUTINE)\n_IRQL_requires_(APC_LEVEL)\n_IRQL_requires_same_\nVOID KSIAPI KphpImageLoadKernelRoutineApcsDisabled(\n    _In_ PKSI_KAPC Apc,\n    _Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE* NormalRoutine,\n    _Inout_ _Deref_pre_maybenull_ PVOID* NormalContext,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument1,\n    _Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2\n    )\n{\n    KPH_PAGED_CODE_APC();\n\n    UNREFERENCED_PARAMETER(Apc);\n    DBG_UNREFERENCED_PARAMETER(NormalRoutine);\n    UNREFERENCED_PARAMETER(NormalContext);\n    DBG_UNREFERENCED_PARAMETER(SystemArgument1);\n    UNREFERENCED_PARAMETER(SystemArgument2);\n\n    NT_ASSERT(*NormalRoutine == KphpImageLoadKernelNormalRoutineApcsDisabled);\n    NT_ASSERT(*SystemArgument1);\n    NT_ASSERT(KphGetObjectType(*SystemArgument1) == KphpImageLoadApcType);\n}\n\n/**\n * \\brief Applies image protections on verified processes.\n *\n * \\param[in,out] Process The process where the image is being loaded.\n * \\param[in] ImageBase The base address of the image.\n * \\param[in] FileObject The file object for the image being loaded.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpApplyImageProtectionsApcsDisabled(\n    _Inout_ PKPH_PROCESS_CONTEXT Process,\n    _In_ PVOID ImageBase,\n    _In_ PFILE_OBJECT FileObject\n    )\n{\n    NTSTATUS status;\n    PKPH_IMAGE_LOAD_APC apc;\n    KPH_IMAGE_LOAD_APC_INIT init;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(KeAreAllApcsDisabled());\n\n    init.Process = Process;\n    init.ImageBase = ImageBase;\n    init.FileObject = FileObject;\n    status = KphCreateObject(KphpImageLoadApcType,\n                             sizeof(KPH_IMAGE_LOAD_APC),\n                             &apc,\n                             &init);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        apc = NULL;\n        goto Exit;\n    }\n\n    //\n    // Initialize a normal kernel ACP to handle this outside of the callback.\n    //\n    KsiInitializeApc(&apc->Apc,\n                     KphDriverObject,\n                     KeGetCurrentThread(),\n                     OriginalApcEnvironment,\n                     KphpImageLoadKernelRoutineApcsDisabled,\n                     KphpImageLoadCleanupRoutine,\n                     KphpImageLoadKernelNormalRoutineApcsDisabled,\n                     KernelMode,\n                     NULL);\n\n    if (!KsiInsertQueueApc(&apc->Apc, apc, NULL, IO_NO_INCREMENT))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KsiInsertQueueApc failed\");\n\n        status = STATUS_UNSUCCESSFUL;\n        goto Exit;\n    }\n\n    apc = NULL;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (apc)\n    {\n        KphDereferenceObject(apc);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"Untrusted image load (%wZ (%lu), %p): %!STATUS!\",\n                      &Process->ImageName,\n                      HandleToULong(Process->ProcessId),\n                      ImageBase,\n                      status);\n\n        //\n        // No choice other than to just track that there is an untrusted image.\n        //\n        InterlockedIncrementSizeT(&Process->NumberOfUntrustedImageLoads);\n    }\n}\n\n/**\n * \\brief Applies image protections on verified processes.\n *\n * \\param[in,out] Process The process where the image is being loaded.\n * \\param[in] ImageInfo The image info from the notification routine.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphApplyImageProtections(\n    _Inout_ PKPH_PROCESS_CONTEXT Process,\n    _In_ PIMAGE_INFO_EX ImageInfo\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphAcquireRWLockShared(&Process->ProtectionLock);\n\n    if (!Process->VerifiedProcess || !Process->Protected)\n    {\n        goto Exit;\n    }\n\n    if ((ImageInfo->ImageInfo.ImageSignatureLevel == SE_SIGNING_LEVEL_MICROSOFT) ||\n        (ImageInfo->ImageInfo.ImageSignatureLevel == SE_SIGNING_LEVEL_WINDOWS) ||\n        (ImageInfo->ImageInfo.ImageSignatureLevel == SE_SIGNING_LEVEL_WINDOWS_TCB))\n    {\n        InterlockedIncrementSizeT(&Process->NumberOfMicrosoftImageLoads);\n        goto Exit;\n    }\n\n    if (ImageInfo->ImageInfo.ImageSignatureLevel == SE_SIGNING_LEVEL_ANTIMALWARE)\n    {\n        InterlockedIncrementSizeT(&Process->NumberOfAntimalwareImageLoads);\n        goto Exit;\n    }\n\n    //\n    // We have to do a signing check ourselves which involves looking up the\n    // file name. If we can do it now, do so, otherwise handle it later.\n    //\n\n    if (KeAreAllApcsDisabled())\n    {\n        //\n        // We can't safely (or accurately) look up the file name. We have to\n        // special case it.\n        //\n        KphpApplyImageProtectionsApcsDisabled(Process,\n                                              ImageInfo->ImageInfo.ImageBase,\n                                              ImageInfo->FileObject);\n    }\n    else\n    {\n        KphpApplyImageProtections(Process,\n                                  ImageInfo->ImageInfo.ImageBase,\n                                  ImageInfo->FileObject);\n    }\n\nExit:\n\n    KphReleaseRWLock(&Process->ProtectionLock);\n}\n\n/**\n * \\brief Acquires a reference to the driver unload protection. Enables driver\n * unload protection if this is the first reference.\n *\n * \\param[out] PreviousCount Optionally set to the previous reference count.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAcquireDriverUnloadProtection(\n    _Out_opt_ PLONG PreviousCount\n    )\n{\n    NTSTATUS status;\n    LONG previousCount;\n\n    KPH_PAGED_CODE();\n\n    status = KphAcquireReference(&KphpDriverUnloadProtectionRef,\n                                 &previousCount);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphAcquireReference failed: %!STATUS!\",\n                      status);\n\n        previousCount = 0;\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  PROTECTION,\n                  \"Acquired driver unload protection (%ld)\",\n                  previousCount + 1);\n\n    if (previousCount == 0)\n    {\n#pragma prefast(push)\n#pragma prefast(disable : 28175)\n\n        NT_ASSERT(KphDriverObject->DriverUnload);\n        NT_ASSERT(!KphpDriverUnloadPreviousRoutine);\n\n        KphpDriverUnloadPreviousRoutine = InterlockedExchangePointer(\n                                         (PVOID*)&KphDriverObject->DriverUnload,\n                                         NULL);\n\n        NT_ASSERT(!KphDriverObject->DriverUnload);\n        NT_ASSERT(KphpDriverUnloadPreviousRoutine);\n\n#pragma prefast(pop)\n\n        KphTracePrint(TRACE_LEVEL_INFORMATION,\n                      PROTECTION,\n                      \"Driver unload protection activated\");\n    }\n\nExit:\n\n    if (PreviousCount)\n    {\n        *PreviousCount = previousCount;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Releases a reference to the driver unload protection. Disables driver\n * unload protection if this is the last reference.\n *\n * \\param[out] PreviousCount Optionally set to the previous reference count.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReleaseDriverUnloadProtection(\n    _Out_opt_ PLONG PreviousCount\n    )\n{\n    NTSTATUS status;\n    LONG previousCount;\n\n    KPH_PAGED_CODE();\n\n    status = KphReleaseReference(&KphpDriverUnloadProtectionRef,\n                                 &previousCount);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphReleaseReference failed: %!STATUS!\",\n                      status);\n\n        previousCount = 0;\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  PROTECTION,\n                  \"Released driver unload protection (%ld)\",\n                  previousCount - 1);\n\n    if (previousCount == 1)\n    {\n#pragma prefast(push)\n#pragma prefast(disable : 28175)\n\n        NT_ASSERT(!KphDriverObject->DriverUnload);\n        NT_ASSERT(KphpDriverUnloadPreviousRoutine);\n\n        KphpDriverUnloadPreviousRoutine = InterlockedExchangePointer(\n                                         (PVOID*)&KphDriverObject->DriverUnload,\n                                         KphpDriverUnloadPreviousRoutine);\n\n        NT_ASSERT(KphDriverObject->DriverUnload);\n        NT_ASSERT(!KphpDriverUnloadPreviousRoutine);\n\n#pragma prefast(pop)\n\n        KphTracePrint(TRACE_LEVEL_INFORMATION,\n                      PROTECTION,\n                      \"Driver unload protection deactivated\");\n    }\n\nExit:\n\n    if (PreviousCount)\n    {\n        *PreviousCount = previousCount;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Retrieves the current driver unload protection reference count.\n *\n * \\details If the driver unload protection reference count is greater than\n * zero, the driver unload protection is active.\n *\n * \\return The current driver unload protection reference count.\n */\n_IRQL_requires_max_(APC_LEVEL)\nLONG KphGetDriverUnloadProtectionCount(\n    VOID\n    )\n{\n    LONG count;\n\n    KPH_PAGED_CODE();\n\n    count = ReadAcquire(&KphpDriverUnloadProtectionRef.Count);\n\n    return count;\n}\n\n/**\n * \\brief Strips the process and thread allowed masks from a protected process.\n *\n * \\details Callers may only strip allowed masks. In other words, callers may\n * only make the protection more restrictive.\n *\n * \\param[in] Process The protected process to strip the masks from.\n * \\param[in] ProcessAllowedMask The process allowed mask to strip.\n * \\param[in] ThreadAllowedMask The thread allowed mask to strip.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpStripProtectedProcessMasks(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_ ACCESS_MASK ProcessAllowedMask,\n    _In_ ACCESS_MASK ThreadAllowedMask\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    KPH_ENUM_FOR_PROTECTION context;\n    ACCESS_MASK prevProcessAllowedMask;\n    ACCESS_MASK prevThreadAllowedMask;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = KphReferenceDynData();\n    if (!dyn)\n    {\n        return STATUS_NOINTERFACE;\n    }\n\n    KphAcquireRWLockExclusive(&Process->ProtectionLock);\n\n    if (!Process->Protected)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    prevProcessAllowedMask = Process->ProcessAllowedMask;\n    prevThreadAllowedMask = Process->ThreadAllowedMask;\n\n    Process->ProcessAllowedMask &= ~ProcessAllowedMask;\n    Process->ThreadAllowedMask &= ~ThreadAllowedMask;\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  PROTECTION,\n                  \"Modifying protected process %wZ (%lu) allowed masks, \"\n                  \"process: 0x%08x -> 0x%08x, \"\n                  \"thread: 0x%08x -> 0x%08x\",\n                  &Process->ImageName,\n                  HandleToULong(Process->ProcessId),\n                  prevProcessAllowedMask,\n                  Process->ProcessAllowedMask,\n                  prevThreadAllowedMask,\n                  Process->ThreadAllowedMask);\n\n    if ((Process->ProcessAllowedMask == prevProcessAllowedMask) &&\n        (Process->ThreadAllowedMask == prevThreadAllowedMask))\n    {\n        status = STATUS_SUCCESS;\n        goto Exit;\n    }\n\n    context.Dyn = dyn;\n    context.Status = STATUS_SUCCESS;\n    context.Process = Process;\n\n    KphEnumerateProcessContexts(KphpEnumProcessContextsForProtection, &context);\n\n    status = context.Status;\n\n    if (!NT_SUCCESS(status))\n    {\n        Process->ProcessAllowedMask = prevProcessAllowedMask;\n        Process->ThreadAllowedMask = prevThreadAllowedMask;\n    }\n\nExit:\n\n    KphReleaseRWLock(&Process->ProtectionLock);\n\n    KphDereferenceObject(dyn);\n\n    return status;\n}\n\n/**\n * \\brief Strips the process and thread allowed masks from a protected process.\n *\n * \\details Callers may only strip allowed masks. In other words, callers may\n * only make the protection more restrictive.\n *\n * \\param[in] ProcessHandle A handle to a process to strip the masks from.\n * \\param[in] ProcessAllowedMask The process allowed mask to strip.\n * \\param[in] ThreadAllowedMask The thread allowed mask to strip.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphStripProtectedProcessMasks(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK ProcessAllowedMask,\n    _In_ ACCESS_MASK ThreadAllowedMask,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS processObject;\n    PKPH_PROCESS_CONTEXT processContext;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    processContext = NULL;\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       PROCESS_SET_INFORMATION,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &processObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        processObject = NULL;\n        goto Exit;\n    }\n\n    processContext = KphGetEProcessContext(processObject);\n    if (!processContext)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      PROTECTION,\n                      \"KphGetEProcessContext failed\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphpStripProtectedProcessMasks(processContext,\n                                            ProcessAllowedMask,\n                                            ThreadAllowedMask);\n\nExit:\n\n    if (processContext)\n    {\n        KphDereferenceObject(processContext);\n    }\n\n    if (processObject)\n    {\n        ObDereferenceObject(processObject);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Initializes the protection infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeProtection(\n    VOID\n    )\n{\n    KPH_OBJECT_TYPE_INFO typeInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    typeInfo.Allocate = KphpAllocateImageLoadApc;\n    typeInfo.Initialize = KphpInitializeImageLoadApc;\n    typeInfo.Delete = KphpDeleteImageLoadApc;\n    typeInfo.Free = KphpFreeImageLoadApc;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpImageLoadApcTypeName,\n                        &typeInfo,\n                        &KphpImageLoadApcType);\n}\n"
  },
  {
    "path": "KSystemInformer/ratelmt.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\n//\n// Time granularity for rate limiter timestamps (100-nano units per tick).\n// 10,000,000 / 100 = 100 ms granularity.\n// 2^32 * 100 ms ~= 13.62 years before rollover.\n// 100 ms granularity provides a good balance of fill frequency and rollover.\n//\n#define KPH_RATE_LIMIT_SEC_MULT   (100)\n#define KPH_RATE_LIMIT_TIME_UNIT  (10000000 / KPH_RATE_LIMIT_SEC_MULT)\n#define KPH_RATE_LIMIT_ROLL_CHECK (86400 * KPH_RATE_LIMIT_SEC_MULT)\n\n/**\n * \\brief Initializes a rate limit.\n *\n * \\param[in] Policy The rate limit policy to use.\n * \\param[in] TimeStamp The current time stamp.\n * \\param[in] RateLimit Receives the initialized rate limit.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphInitializeRateLimit(\n    _In_ PCKPH_RATE_LIMIT_POLICY Policy,\n    _In_ PLARGE_INTEGER TimeStamp,\n    _Out_ PKPH_RATE_LIMIT RateLimit\n    )\n{\n    KPH_RATE_BUCKET bucket;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    bucket.CurrentTokens = Policy->MaxBucketSize;\n    bucket.LastRefillTime = (ULONG)(TimeStamp->QuadPart / KPH_RATE_LIMIT_TIME_UNIT);\n\n    RtlZeroMemory(RateLimit, sizeof(KPH_RATE_LIMIT));\n    WriteNoFence64(&RateLimit->Bucket.Quad, bucket.Quad);\n    RtlCopyMemory(&RateLimit->Policy, Policy, sizeof(KPH_RATE_LIMIT_POLICY));\n}\n\n/**\n * \\brief Consumes a token from the rate limit.\n *\n * \\param[in] RateLimit The rate limit to consume a token from.\n * \\param[in] TimeStamp The current time stamp.\n *\n * \\return TRUE if a token was consumed, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nBOOLEAN KphRateLimitConsumeToken(\n    _Inout_ PKPH_RATE_LIMIT RateLimit,\n    _In_ PLARGE_INTEGER TimeStamp\n    )\n{\n    KPH_RATE_BUCKET oldBucket;\n    KPH_RATE_BUCKET newBucket;\n    ULONG currentTime;\n    ULONG elapsedTime;\n    ULONG64 tokensToAdd;\n    BOOLEAN allowed;\n    LONG64 expected;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    //\n    // KPH_RATE_LIMIT_UNLIMITED\n    //\n    if ((RateLimit->Policy.TokensPerPeriod == ULONG_MAX) ||\n        (RateLimit->Policy.MaxBucketSize == ULONG_MAX))\n    {\n        InterlockedIncrementNoFence64(&RateLimit->Allowed);\n        return TRUE;\n    }\n\n    //\n    // KPH_RATE_LIMIT_DENY_ALL\n    //\n    if ((RateLimit->Policy.TokensPerPeriod == 0) ||\n        (RateLimit->Policy.PeriodInSeconds == 0) ||\n        (RateLimit->Policy.MaxBucketSize == 0))\n    {\n        InterlockedIncrementNoFence64(&RateLimit->Dropped);\n        return FALSE;\n    }\n\n    currentTime = (ULONG)(TimeStamp->QuadPart / KPH_RATE_LIMIT_TIME_UNIT);\n    oldBucket.Quad = ReadNoFence64(&RateLimit->Bucket.Quad);\n\n    for (;;)\n    {\n        newBucket.Quad = oldBucket.Quad;\n\n        if (newBucket.LastRefillTime > currentTime)\n        {\n            if ((newBucket.LastRefillTime - currentTime) > KPH_RATE_LIMIT_ROLL_CHECK)\n            {\n                newBucket.CurrentTokens = RateLimit->Policy.MaxBucketSize;\n                newBucket.LastRefillTime = currentTime;\n            }\n\n            goto ConsumeToken;\n        }\n\n        elapsedTime = (currentTime - newBucket.LastRefillTime);\n        tokensToAdd = ((ULONG64)elapsedTime * RateLimit->Policy.TokensPerPeriod);\n        tokensToAdd /= ((ULONG64)RateLimit->Policy.PeriodInSeconds * KPH_RATE_LIMIT_SEC_MULT);\n\n        if (tokensToAdd == 0)\n        {\n            goto ConsumeToken;\n        }\n\n        if ((tokensToAdd >= RateLimit->Policy.MaxBucketSize) ||\n            (tokensToAdd > (RateLimit->Policy.MaxBucketSize - newBucket.CurrentTokens)))\n        {\n            newBucket.CurrentTokens = RateLimit->Policy.MaxBucketSize;\n        }\n        else\n        {\n            newBucket.CurrentTokens = (newBucket.CurrentTokens + (ULONG)tokensToAdd);\n        }\n\n        newBucket.LastRefillTime = currentTime;\n\nConsumeToken:\n\n        if (newBucket.CurrentTokens > 0)\n        {\n            newBucket.CurrentTokens--;\n            allowed = TRUE;\n        }\n        else\n        {\n            allowed = FALSE;\n        }\n\n        expected = oldBucket.Quad;\n\n        oldBucket.Quad = InterlockedCompareExchange64(&RateLimit->Bucket.Quad,\n                                                      newBucket.Quad,\n                                                      expected);\n        if (oldBucket.Quad != expected)\n        {\n            InterlockedIncrementNoFence64(&RateLimit->CasMiss);\n            continue;\n        }\n\n        if (allowed)\n        {\n            InterlockedIncrementNoFence64(&RateLimit->Allowed);\n            return TRUE;\n        }\n        else\n        {\n            InterlockedIncrementNoFence64(&RateLimit->Dropped);\n            return FALSE;\n        }\n    }\n}\n"
  },
  {
    "path": "KSystemInformer/resource.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#pragma code_page(65001)\n\n#include <windows.h>\n#include <sistatus.rc>\n\n#define VER_FILEVERSION             4,0,0,0\n#define VER_FILEVERSION_STR         \"4.0.0\\0\"\n\n#define VER_PRODUCTVERSION          VER_FILEVERSION\n#define VER_PRODUCTVERSION_STR      VER_FILEVERSION_STR\n\n#if DEBUG\n#define VER_DEBUG                   VS_FF_DEBUG\n#define VER_PRERELEASE              VS_FF_PRERELEASE\n#define VER_PRIVATE                 VS_FF_PRIVATEBUILD\n#else\n#define VER_DEBUG                   0\n#define VER_PRERELEASE              0\n#define VER_PRIVATE                 0\n#endif\n\n#define VER_FILEFLAGSMASK           VS_FFI_FILEFLAGSMASK\n#define VER_FILEFLAGS               (VER_PRERELEASE | VER_DEBUG | VER_PRIVATE)\n#define VER_FILEOS                  VOS_NT_WINDOWS32\n\n#define VER_FILETYPE                VFT_DRV\n#define VER_FILESUBTYPE             VFT2_DRV_SYSTEM\n\n#define VER_COMPANYNAME_STR         \"System Informer\\0\"\n#define VER_FILEDESCRIPTION_STR     \"System Informer\\0\"\n#define VER_LEGALCOPYRIGHT_STR      \"Copyright (c) Winsider Seminars & Solutions, Inc.  All rights reserved.\\0\"\n#define VER_ORIGINALFILENAME_STR    \"SystemInformer.sys\\0\"\n#define VER_INTERNALNAME_STR        \"SystemInformer.sys\\0\"\n#define VER_PRODUCTNAME_STR         \"System Informer\\0\"\n\n#if !defined(DEFAULT_VERSIONINFO)\nVS_VERSION_INFO VERSIONINFO\nFILEVERSION     VER_FILEVERSION\nPRODUCTVERSION  VER_PRODUCTVERSION\nFILEFLAGSMASK   VER_FILEFLAGSMASK\nFILEFLAGS       VER_FILEFLAGS\nFILEOS          VER_FILEOS\nFILETYPE        VER_FILETYPE\nFILESUBTYPE     VER_FILESUBTYPE\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904E4\"\n        BEGIN\n            VALUE \"CompanyName\",      VER_COMPANYNAME_STR\n            VALUE \"FileDescription\",  VER_FILEDESCRIPTION_STR\n            VALUE \"FileVersion\",      VER_FILEVERSION_STR\n            VALUE \"InternalName\",     VER_INTERNALNAME_STR\n            VALUE \"LegalCopyright\",   VER_LEGALCOPYRIGHT_STR\n            VALUE \"OriginalFilename\", VER_ORIGINALFILENAME_STR\n            VALUE \"ProductName\",      VER_PRODUCTNAME_STR\n            VALUE \"ProductVersion\",   VER_PRODUCTVERSION_STR\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1252\n    END\nEND\n#else\n#include <ntverp.h>\n#include \"common.ver\"\n#endif\n"
  },
  {
    "path": "KSystemInformer/ringbuff.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_OBJECT_TYPE KphpRingBufferType = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpRingBufferTypeName = RTL_CONSTANT_STRING(L\"KphRingBuffer\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\n\n/**\n * \\brief Reserves a ring buffer entry.\n *\n * \\details This routine reserves space in the ring buffer to be written to. On\n * a successful call to this routine the returned buffer is marked busy and the\n * caller must commit the buffer with KphCommitRingBuffer or discard it with\n * KphDiscardRingBuffer.\n *\n * \\param[in] Ring Pointer to a buffer object.\n * \\param[in] Length The length of the buffer to reserve.\n *\n * \\return Reserved buffer, null on failure.\n */\n_Return_allocatesMem_size_(Length)\nPVOID KphReserveRingBuffer(\n    _In_ PKPH_RING_BUFFER Ring,\n    _In_ ULONG Length\n    )\n{\n    PVOID buffer;\n    KIRQL previousIrql;\n    KLOCK_QUEUE_HANDLE lockHandle;\n    ULONG consumerPos;\n    ULONG producerPos;\n    ULONG remainingLength;\n    ULONG requiredLength;\n    ULONG alignment;\n    PKPH_RING_HEADER headerPointer;\n    KPH_RING_HEADER header;\n\n    //\n    // Maximum reserve accounts for the maximum encoded length bits, additional\n    // headers, and any necessary alignment.\n    //\n    if (Length > KPH_RING_BUFFER_RESERVE_MAX)\n    {\n        return NULL;\n    }\n\n    buffer = NULL;\n\n    previousIrql = KeGetCurrentIrql();\n    if (previousIrql >= DISPATCH_LEVEL)\n    {\n        KeAcquireInStackQueuedSpinLockAtDpcLevel(&Ring->ProducerLock,\n                                                 &lockHandle);\n    }\n    else\n    {\n        KeAcquireInStackQueuedSpinLock(&Ring->ProducerLock, &lockHandle);\n    }\n\n    consumerPos = ReadULongAcquire(Ring->ConsumerPos);\n    producerPos = ReadULongNoFence(Ring->ProducerPos);\n\n    if (producerPos >= consumerPos)\n    {\n        remainingLength = (Ring->Length - producerPos);\n    }\n    else\n    {\n        //\n        // Producer position wrapped.\n        //\n        remainingLength = (consumerPos - producerPos);\n    }\n\n    if (!NT_VERIFY(remainingLength <= Ring->Length))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Ring buffer position overflow: %lu %lu %lu\",\n                      producerPos,\n                      consumerPos,\n                      Ring->Length);\n\n        goto Exit;\n    }\n\n    requiredLength = (Length + KPH_RING_BUFFER_HEADER_SIZE);\n    requiredLength = ALIGN_UP_BY(requiredLength, MEMORY_ALLOCATION_ALIGNMENT);\n    alignment = (requiredLength - Length - KPH_RING_BUFFER_HEADER_SIZE);\n\n    //\n    // Always reserve an extra header for the reset marker.\n    //\n    requiredLength += KPH_RING_BUFFER_HEADER_SIZE;\n\n    if (requiredLength > remainingLength)\n    {\n        if ((producerPos < consumerPos) || (requiredLength > consumerPos))\n        {\n            //\n            // Ring buffer exhausted.\n            //\n            goto Exit;\n        }\n\n        //\n        // There is sufficient space to wrap, do so now.\n        //\n\n        if (!NT_VERIFY(remainingLength >= KPH_RING_BUFFER_HEADER_SIZE))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Ring buffer accounting failure: %lu %lu %lu\",\n                          producerPos,\n                          consumerPos,\n                          Ring->Length);\n\n            goto Exit;\n        }\n\n        headerPointer = Add2Ptr(Ring->Buffer, producerPos);\n        header.Value = 0;\n        header.Reset = TRUE;\n\n        WriteULong64Release(&headerPointer->Value, header.Value);\n\n        producerPos = 0;\n    }\n\n    headerPointer = Add2Ptr(Ring->Buffer, producerPos);\n    buffer = Add2Ptr(headerPointer, KPH_RING_BUFFER_HEADER_SIZE);\n\n    header.Value = 0;\n    header.Length = Length;\n    header.Busy = TRUE;\n    header.Alignment = alignment;\n\n    producerPos += (requiredLength - KPH_RING_BUFFER_HEADER_SIZE);\n\n    //\n    // Sync with the consumer.\n    //\n    WriteULong64Release(&headerPointer->Value, header.Value);\n    WriteULongRelease(Ring->ProducerPos, producerPos);\n\nExit:\n\n    if (previousIrql >= DISPATCH_LEVEL)\n    {\n        KeReleaseInStackQueuedSpinLockFromDpcLevel(&lockHandle);\n    }\n    else\n    {\n        KeReleaseInStackQueuedSpinLock(&lockHandle);\n    }\n\n    return buffer;\n}\n\n/**\n * \\brief Helper routine to submits a previously reserved ring buffer entry.\n *\n * \\param[in] Ring Pointer to a ring buffer object.\n * \\param[in] Buffer Pointer to the buffer to submit.\n * \\param[in] Discard If TRUE the buffer is discarded, if FALSE is it committed.\n */\nVOID KphpSubmitRingBuffer(\n    _In_ PKPH_RING_BUFFER Ring,\n    _In_aliasesMem_ PVOID Buffer,\n    _In_ BOOLEAN Discard\n    )\n{\n    PKPH_RING_HEADER headerPointer;\n    KPH_RING_HEADER header;\n\n    headerPointer = Add2Ptr(Buffer, -KPH_RING_BUFFER_HEADER_SIZE);\n\n    header.Value = ReadULong64NoFence(&headerPointer->Value);\n    header.Busy = FALSE;\n    header.Discard = !!Discard;\n\n    WriteULong64Release(&headerPointer->Value, header.Value);\n\n    if (Ring->Event && !ReadULongAcquire(Ring->ConsumerProcessing))\n    {\n        KeSetEvent(Ring->Event, EVENT_INCREMENT, FALSE);\n    }\n}\n\n/**\n * \\brief Commits a previously reserved ring buffer entry.\n *\n * \\details After this call the busy ring buffer entry is made available for\n * for the consumer to process.\n *\n * \\param[in] Ring Pointer to a ring buffer object.\n * \\param[in] Buffer Pointer to the buffer to commit, previously returned from\n * KphReserveRingBuffer.\n */\nVOID KphCommitRingBuffer(\n    _In_ PKPH_RING_BUFFER Ring,\n    _In_freesMem_ PVOID Buffer\n    )\n{\n    KphpSubmitRingBuffer(Ring, Buffer, FALSE);\n}\n\n/**\n * \\brief Discards a previously reserved ring buffer entry.\n *\n * \\details After this call the busy ring buffer entry is marked as discarded\n * the consumer should skip over it when processing the ring buffer.\n *\n * \\param[in] Ring Pointer to a ring buffer object.\n * \\param[in] Buffer Pointer to the buffer to discard, previously returned from\n * KphReserveRingBuffer.\n */\nVOID KphDiscardRingBuffer(\n    _In_ PKPH_RING_BUFFER Ring,\n    _In_freesMem_ PVOID Buffer\n    )\n{\n    KphpSubmitRingBuffer(Ring, Buffer, TRUE);\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Creates a ring buffer section.\n *\n * \\details The section is created in a way that restricts read or write access\n * to the ring buffer section by user mode. Kernel mode is always permitted to\n * read or write to the section. The kernel mapping is locked in the system\n * virtual address space. This routine does not map the section into user mode.\n * It does provide the section object to be mapped to user mode by the caller.\n * The method for creating the sections ensures appropriate memory protection is\n * applied to the related section objects and that an eventual mapping into\n * user mode can be paged out if necessary.\n *\n * \\param[in] Section Pointer to a ring buffer section to populate.\n * \\param[in] Length The length of the ring buffer section.\n * \\param[in] PageProtection The page protection for the ring buffer section.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpCreateRingBufferSection(\n    _Out_ PKPH_RING_SECTION Section,\n    _In_ ULONG Length,\n    _In_ ULONG PageProtection\n    )\n{\n    NTSTATUS status;\n    ULONG sectionAccess;\n    LARGE_INTEGER maximumSize;\n    SIZE_T viewSize;\n    PVOID kernelMappedBase;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    kernelMappedBase = NULL;\n\n    if (PageProtection == PAGE_READONLY)\n    {\n        sectionAccess = SECTION_MAP_READ;\n    }\n    else if (PageProtection == PAGE_READWRITE)\n    {\n        sectionAccess = SECTION_MAP_READ | SECTION_MAP_WRITE;\n    }\n    else\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    maximumSize.QuadPart = Length;\n\n    status = MmCreateSection(&Section->SectionObject,\n                             sectionAccess,\n                             NULL,\n                             &maximumSize,\n                             PageProtection,\n                             SEC_COMMIT,\n                             NULL,\n                             NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"MmCreateSection failed: %!STATUS!\",\n                      status);\n\n        Section->SectionObject = NULL;\n        goto Exit;\n    }\n\n    kernelMappedBase = NULL;\n    viewSize = 0;\n\n    status = MmMapViewInSystemSpace(Section->SectionObject,\n                                    &kernelMappedBase,\n                                    &viewSize);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"MmMapViewInSystemSpace failed: %!STATUS!\",\n                      status);\n\n        kernelMappedBase = NULL;\n        goto Exit;\n    }\n\n    NT_ASSERT((viewSize >= Length) && (viewSize <= ULONG_MAX));\n\n    Section->Mdl = IoAllocateMdl(kernelMappedBase,\n                                 (ULONG)viewSize,\n                                 FALSE,\n                                 FALSE,\n                                 NULL);\n    if (!Section->Mdl)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE, GENERAL, \"IoAllocateMdl failed\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    __try\n    {\n        MmProbeAndLockPages(Section->Mdl, KernelMode, IoReadAccess);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        IoFreeMdl(Section->Mdl);\n        Section->Mdl = NULL;\n\n        status = GetExceptionCode();\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"MmProbeAndLockPages failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    Section->KernelBase = KphGetSystemAddressForMdl(Section->Mdl,\n                                                    NormalPagePriority);\n    if (!Section->KernelBase)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"MmGetSystemAddressForMdlSafe failed\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    RtlZeroMemory(Section->KernelBase, viewSize);\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (kernelMappedBase)\n    {\n        MmUnmapViewInSystemSpace(kernelMappedBase);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Deletes a ring buffer section.\n *\n * \\param[in] Section Pointer to a ring buffer section to delete.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphpDeleteRingBufferSection(\n    _In_ PKPH_RING_SECTION Section\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    if (Section->Mdl)\n    {\n        MmUnlockPages(Section->Mdl);\n        IoFreeMdl(Section->Mdl);\n    }\n\n    if (Section->SectionObject)\n    {\n        ObDereferenceObject(Section->SectionObject);\n    }\n}\n\n/**\n * \\brief Allocates a ring buffer object.\n *\n * \\param[in] Size The size of the ring buffer object to allocate.\n *\n * \\return Allocated ring buffer object, null on failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateRingBuffer(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    return KphAllocateNPaged(Size, KPH_TAG_RING_BUFFER);\n}\n\n/**\n * \\brief Deletes a ring buffer object.\n *\n * \\param[in,out] Object Pointer to a ring buffer object to delete.\n */\n_Function_class_(KPH_TYPE_DELETE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpDeleteRingBuffer(\n    _Inout_ PVOID Object\n    )\n{\n    PKPH_RING_BUFFER ring;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    ring = Object;\n\n    KphpDeleteRingBufferSection(&ring->ProducerSection);\n    KphpDeleteRingBufferSection(&ring->ConsumerSection);\n\n    if (ring->Event)\n    {\n        ObDereferenceObject(ring->Event);\n    }\n\n    ObDereferenceObject(ring->Process);\n}\n\n/**\n * \\brief Frees a ring buffer object.\n *\n * \\param[in] Object Pointer to a ring buffer object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KSIAPI KphpFreeRingBuffer(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphFree(Object, KPH_TAG_RING_BUFFER);\n}\n\n/**\n * \\brief Creates a ring buffer object.\n *\n * \\details This ring buffer is a multiple-producer single-consumer ring buffer.\n * The producer (kernel mode) populates to the ring buffer and single consumer\n * (in user mode) processes the data written to the buffer. The producer may\n * reserve, write, and commit to the ring buffer from an arbitrary thread.\n *\n * \\param[out] Ring Receives the ring buffer object.\n * \\param[out] User Receives the user mode ring buffer information.\n * \\param[in] Length Desired length of the ring buffer.\n * \\param[in] Event Optional event object to an event to signal when new data is\n * committed and the consumer was previously caught up with processing. Must be\n * an ExEventObjectType as a reference is taken to the object.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCreateRingBuffer(\n    _Out_ PKPH_RING_BUFFER* Ring,\n    _Out_ PKPH_RING_BUFFER_USER User,\n    _In_ ULONG Length,\n    _In_opt_ PKEVENT Event,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_RING_BUFFER ring;\n    PVOID userProducerBase;\n    PVOID userConsumerBase;\n    ULONG sectionLength;\n    ULONG roundedLength;\n    ULONG bufferLength;\n    PKPH_RING_PRODUCER_BLOCK producer;\n    PKPH_RING_CONSUMER_BLOCK consumer;\n    LARGE_INTEGER sectionOffset;\n    SIZE_T viewSize;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    *Ring = NULL;\n\n    ring = NULL;\n    userProducerBase = NULL;\n    userConsumerBase = NULL;\n\n    if (Event && (ObGetObjectType(Event) != *ExEventObjectType))\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    status = KphZeroModeMemory(User, sizeof(KPH_RING_BUFFER_USER), AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    status = RtlULongAdd(Length,\n                         FIELD_OFFSET(KPH_RING_PRODUCER_BLOCK, Buffer),\n                         &sectionLength);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"RtlULongAdd failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    roundedLength = ROUND_TO_PAGES(sectionLength);\n    if (roundedLength < sectionLength)\n    {\n        status = STATUS_INTEGER_OVERFLOW;\n        goto Exit;\n    }\n\n    sectionLength = roundedLength;\n    bufferLength = sectionLength;\n    bufferLength -= FIELD_OFFSET(KPH_RING_PRODUCER_BLOCK, Buffer);\n\n    status = KphCreateObject(KphpRingBufferType,\n                             sizeof(KPH_RING_BUFFER),\n                             &ring,\n                             NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    ring->Process = PsGetCurrentProcess();\n    ObReferenceObject(ring->Process);\n\n    KeInitializeSpinLock(&ring->ProducerLock);\n\n    if (Event)\n    {\n        ring->Event = Event;\n        ObReferenceObject(ring->Event);\n    }\n\n    status = KphpCreateRingBufferSection(&ring->ProducerSection,\n                                         sectionLength,\n                                         PAGE_READONLY);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphpCreateRingBufferSection failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = KphpCreateRingBufferSection(&ring->ConsumerSection,\n                                         sizeof(KPH_RING_CONSUMER_BLOCK),\n                                         PAGE_READWRITE);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphpCreateRingBufferSection failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    producer = ring->ProducerSection.KernelBase;\n    consumer = ring->ConsumerSection.KernelBase;\n\n    producer->Length = bufferLength;\n\n    ring->ProducerPos = &producer->Position;\n    ring->ConsumerPos = &consumer->Position;\n    ring->ConsumerProcessing = &consumer->Processing;\n    ring->Length = bufferLength;\n    ring->Buffer = producer->Buffer;\n\n    //\n    // Set up the user mode portion of the ring buffer.\n    //\n\n    sectionOffset.QuadPart = 0;\n    viewSize = 0;\n\n    status = MmMapViewOfSection(ring->ProducerSection.SectionObject,\n                                PsGetCurrentProcess(),\n                                &userProducerBase,\n                                0,\n                                0,\n                                &sectionOffset,\n                                &viewSize,\n                                ViewUnmap,\n                                0,\n                                PAGE_READONLY);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"MmMapViewOfSection failed: %!STATUS!\",\n                      status);\n\n        userProducerBase = NULL;\n        goto Exit;\n    }\n\n    sectionOffset.QuadPart = 0;\n    viewSize = 0;\n\n    status = MmMapViewOfSection(ring->ConsumerSection.SectionObject,\n                                PsGetCurrentProcess(),\n                                &userConsumerBase,\n                                0,\n                                0,\n                                &sectionOffset,\n                                &viewSize,\n                                ViewUnmap,\n                                0,\n                                PAGE_READWRITE);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"MmMapViewOfSection failed: %!STATUS!\",\n                      status);\n\n        userConsumerBase = NULL;\n        goto Exit;\n    }\n\n    status = KphWritePointerToMode(&User->Consumer,\n                                   userConsumerBase,\n                                   AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    status = KphWritePointerToMode(&User->Producer,\n                                   userProducerBase,\n                                   AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    userProducerBase = NULL;\n    userConsumerBase = NULL;\n\n    *Ring = ring;\n    ring = NULL;\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (userConsumerBase)\n    {\n        MmUnmapViewOfSection(PsGetCurrentProcess(), userConsumerBase);\n    }\n\n    if (userProducerBase)\n    {\n        MmUnmapViewOfSection(PsGetCurrentProcess(), userProducerBase);\n    }\n\n    if (ring)\n    {\n        KphDereferenceObject(ring);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Initializes the ring buffer infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeRingBuffer(\n    VOID\n    )\n{\n    KPH_OBJECT_TYPE_INFO typeInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    typeInfo.Allocate = KphpAllocateRingBuffer;\n    typeInfo.Initialize = NULL;\n    typeInfo.Delete = KphpDeleteRingBuffer;\n    typeInfo.Free = KphpFreeRingBuffer;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpRingBufferTypeName,\n                        &typeInfo,\n                        &KphpRingBufferType);\n}\n"
  },
  {
    "path": "KSystemInformer/session_token.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\ntypedef struct _KPH_SESSION_TOKEN_INIT\n{\n    LARGE_INTEGER Expiry;\n    ULONG Privileges;\n    LONG Uses;\n} KPH_SESSION_TOKEN_INIT, *PKPH_SESSION_TOKEN_INIT;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const UNICODE_STRING KphpSessionTokenTypeName = RTL_CONSTANT_STRING(L\"KphSessionToken\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic PKPH_OBJECT_TYPE KphpSessionTokenType = NULL;\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Allocate a session token object.\n *\n * \\param[in] Size The size of the object to allocate.\n *\n * \\return A pointer to the allocated object, NULL on failure.\n */\n_Function_class_(KPH_TYPE_ALLOCATE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\n_Return_allocatesMem_size_(Size)\nPVOID KSIAPI KphpAllocateSessionToken(\n    _In_ SIZE_T Size\n    )\n{\n    KPH_PAGED_CODE();\n\n    //\n    // N.B. The session token object is allocated from non-paged pool because it\n    // is stored in an atomic object reference in process and thread contexts.\n    //\n\n    return KphAllocateNPaged(Size, KPH_TAG_SESSION_TOKEN_OBJECT);\n}\n\n/**\n * \\brief Free a session token object.\n *\n * \\param[in] Object The session token object to free.\n */\n_Function_class_(KPH_TYPE_FREE_PROCEDURE)\n_IRQL_requires_max_(APC_LEVEL)\nVOID KSIAPI KphpFreeSessionToken(\n    _In_freesMem_ PVOID Object\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphFree(Object, KPH_TAG_SESSION_TOKEN_OBJECT);\n}\n\n/**\n * \\brief Initialize a session token object.\n *\n * \\param[in] Object The session token object to initialize.\n * \\param[in] Parameter The session token object initialization parameters.\n *\n * \\return Successful or errant status.\n */\n_Function_class_(KPH_TYPE_INITIALIZE_PROCEDURE)\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KSIAPI KphpInitializeSessionToken(\n    _Inout_ PVOID Object,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PKPH_SESSION_TOKEN token;\n    PKPH_SESSION_TOKEN_INIT init;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    NT_ASSERT(Parameter);\n\n    token = Object;\n    init = Parameter;\n\n    status = ExUuidCreate(&token->AccessToken.Identifier);\n    if (status != STATUS_SUCCESS)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ExUuidCreate failed: %!STATUS!\",\n                      status);\n\n        if (NT_SUCCESS(status))\n        {\n            status = STATUS_UNSUCCESSFUL;\n        }\n\n        return status;\n    }\n\n    status = BCryptGenRandom(NULL,\n                             token->AccessToken.Material,\n                             sizeof(token->AccessToken.Material),\n                             BCRYPT_USE_SYSTEM_PREFERRED_RNG);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"BCryptGenRandom failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    if (init->Expiry.QuadPart < 0)\n    {\n        KeQuerySystemTime(&token->AccessToken.Expiry);\n\n        token->AccessToken.Expiry.QuadPart += -(init->Expiry.QuadPart);\n    }\n    else\n    {\n        token->AccessToken.Expiry = init->Expiry;\n    }\n\n    token->AccessToken.Privileges = init->Privileges;\n    token->AccessToken.Uses = init->Uses;\n\n    WriteNoFence(&token->UseCount, 0);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Requests an access session token.\n *\n * \\details After a request for an access session token has been made, the\n * current thread is responsible for assigning the session token to a process\n * or thread later by providing the signature for the access session token\n * content.\n *\n * \\param[out] AccessToken Populated with the access session token.\n * \\param[in] Expiry The expiry time of the session token.\n * \\param[in] Privileges The privileges of the session token.\n * \\param[in] Uses The number of uses of the session token.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphRequestSessionAccessToken(\n    _Out_ PKPH_SESSION_ACCESS_TOKEN AccessToken,\n    _In_ PLARGE_INTEGER Expiry,\n    _In_ ULONG Privileges,\n    _In_ LONG Uses\n    )\n{\n    NTSTATUS status;\n    PKPH_THREAD_CONTEXT thread;\n    KPH_SESSION_TOKEN_INIT tokenInit;\n    PKPH_SESSION_TOKEN token;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlZeroMemory(AccessToken, sizeof(KPH_SESSION_ACCESS_TOKEN));\n\n    thread = NULL;\n    token = NULL;\n\n    if (!Privileges || (Privileges & ~KPH_TOKEN_VALID_PRIVILEGES))\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    thread = KphGetCurrentThreadContext();\n    if (!thread)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    tokenInit.Expiry = *Expiry;\n    tokenInit.Privileges = Privileges;\n    tokenInit.Uses = Uses;\n\n    status = KphCreateObject(KphpSessionTokenType,\n                             sizeof(KPH_SESSION_TOKEN),\n                             &token,\n                             &tokenInit);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphCreateObject failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    RtlCopyMemory(AccessToken,\n                  &token->AccessToken,\n                  sizeof(KPH_SESSION_ACCESS_TOKEN));\n\n    KphAtomicAssignObjectReference(&thread->RequestSessionToken.Atomic, token);\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  GENERAL,\n                  \"[%!GUID!] %!TIME! %ld\",\n                  &token->AccessToken.Identifier,\n                  token->AccessToken.Expiry.QuadPart,\n                  token->AccessToken.Uses);\n\nExit:\n\n    if (token)\n    {\n        KphDereferenceObject(token);\n    }\n\n    if (thread)\n    {\n        KphDereferenceObject(thread);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Verifies an access session token.\n *\n * \\param[in] Actor The actor process setting the session token.\n * \\param[in] Target The target process receiving the session token.\n * \\param[in] Token The session token to verify.\n * \\param[in] Signature The signature of the session token.\n * \\param[in] SignatureLength The length of the signature.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpVerifySessionToken(\n    _In_ PKPH_PROCESS_CONTEXT Actor,\n    _In_ PKPH_PROCESS_CONTEXT Target,\n    _In_ PKPH_SESSION_TOKEN Token,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    PBYTE signature;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    signature = NULL;\n    dyn = NULL;\n\n    dyn = KphReferenceDynData();\n    if (!dyn || !dyn->SessionTokenPublicKeyHandle)\n    {\n        status = STATUS_NOINTERFACE;\n        goto Exit;\n    }\n\n    if (AccessMode != KernelMode)\n    {\n        signature = KphAllocatePaged(SignatureLength,\n                                     KPH_TAG_SESSION_TOKEN_SIGNATURE);\n        if (!signature)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Failed to allocate signature buffer.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        __try\n        {\n            CopyFromUser(signature, Signature, SignatureLength);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n    }\n    else\n    {\n        signature = Signature;\n    }\n\n    status = KphVerifyBufferEx(dyn->SessionTokenPublicKeyHandle,\n                               (PBYTE)&Token->AccessToken,\n                               sizeof(Token->AccessToken),\n                               signature,\n                               SignatureLength);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphVerifyBufferEx failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (!KphTestProcessContextState(Actor, KPH_PROCESS_STATE_MAXIMUM) ||\n        !KphTestProcessContextState(Target, KPH_PROCESS_STATE_MAXIMUM))\n    {\n        status = STATUS_ACCESS_DENIED;\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  GENERAL,\n                  \"[%!GUID!] %!TIME! %ld\",\n                  &Token->AccessToken.Identifier,\n                  Token->AccessToken.Expiry.QuadPart,\n                  Token->AccessToken.Uses);\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (dyn)\n    {\n        KphDereferenceObject(dyn);\n    }\n\n    if (signature && (signature != Signature))\n    {\n        KphFree(signature, KPH_TAG_SESSION_TOKEN_SIGNATURE);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Assigns an access session token to a process.\n *\n * \\param[in] Process The process to assign the session token to.\n * \\param[in] Signature The signature of the session token.\n * \\param[in] SignatureLength The length of the signature.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpAssignProcessSessionToken(\n    _Inout_ PKPH_PROCESS_CONTEXT Process,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_THREAD_CONTEXT actor;\n    PKPH_SESSION_TOKEN token;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    token = NULL;\n\n    actor = KphGetCurrentThreadContext();\n    if (!actor)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    token = KphAtomicMoveObjectReference(&actor->RequestSessionToken.Atomic,\n                                         NULL);\n    if (!token)\n    {\n        status = STATUS_INVALID_STATE_TRANSITION;\n        goto Exit;\n    }\n\n    if (!actor->ProcessContext)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphpVerifySessionToken(actor->ProcessContext,\n                                    Process,\n                                    token,\n                                    Signature,\n                                    SignatureLength,\n                                    AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphpVerifyToken failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    KphAtomicAssignObjectReference(&Process->SessionToken.Atomic, token);\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (token)\n    {\n        KphDereferenceObject(token);\n    }\n\n    if (actor)\n    {\n        KphDereferenceObject(actor);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Assigns an access session token to a process.\n *\n * \\param[in] ProcessHandle Handle to the process to assign the session token.\n * \\param[in] Signature The signature of the session token.\n * \\param[in] SignatureLength The length of the signature.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAssignProcessSessionToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PEPROCESS processObject;\n    PKPH_PROCESS_CONTEXT processContext;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    processObject = NULL;\n    processContext = NULL;\n\n    if (!Signature || !SignatureLength)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(ProcessHandle,\n                                       0,\n                                       *PsProcessType,\n                                       AccessMode,\n                                       &processObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        processObject = NULL;\n        goto Exit;\n    }\n\n    processContext = KphGetEProcessContext(processObject);\n    if (!processContext)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphpAssignProcessSessionToken(processContext,\n                                           Signature,\n                                           SignatureLength,\n                                           AccessMode);\n\nExit:\n\n    if (processContext)\n    {\n        KphDereferenceObject(processContext);\n    }\n\n    if (processObject)\n    {\n        ObDereferenceObject(processObject);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Assigns an access session token to a thread.\n *\n * \\param[in] Thread The thread to assign the session token to.\n * \\param[in] Signature The signature of the session token.\n * \\param[in] SignatureLength The length of the signature.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpAssignThreadSessionToken(\n    _Inout_ PKPH_THREAD_CONTEXT Thread,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_THREAD_CONTEXT actor;\n    PKPH_SESSION_TOKEN token;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    actor = NULL;\n    token = NULL;\n\n    actor = KphGetCurrentThreadContext();\n    if (!actor)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    token = KphAtomicMoveObjectReference(&actor->RequestSessionToken.Atomic,\n                                         NULL);\n    if (!token)\n    {\n        status = STATUS_INVALID_STATE_TRANSITION;\n        goto Exit;\n    }\n\n    if (!actor->ProcessContext || !Thread->ProcessContext)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphpVerifySessionToken(actor->ProcessContext,\n                                    Thread->ProcessContext,\n                                    token,\n                                    Signature,\n                                    SignatureLength,\n                                    AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphpVerifyToken failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    KphAtomicAssignObjectReference(&Thread->SessionToken.Atomic,\n                                   token);\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (token)\n    {\n        KphDereferenceObject(token);\n    }\n\n    if (actor)\n    {\n        KphDereferenceObject(actor);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Assigns an access session token to a thread.\n *\n * \\param[in] ThreadHandle Handle to the thread to assign the session token.\n * \\param[in] Signature The signature of the session token.\n * \\param[in] SignatureLength The length of the signature.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAssignThreadSessionToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PETHREAD threadObject;\n    PKPH_THREAD_CONTEXT threadContext;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    threadObject = NULL;\n    threadContext = NULL;\n\n    if (!Signature || !SignatureLength)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(ThreadHandle,\n                                       0,\n                                       *PsThreadType,\n                                       AccessMode,\n                                       &threadObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        threadObject = NULL;\n        goto Exit;\n    }\n\n    threadContext = KphGetEThreadContext(threadObject);\n    if (!threadContext)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphpAssignThreadSessionToken(threadContext,\n                                          Signature,\n                                          SignatureLength,\n                                          AccessMode);\n\nExit:\n\n    if (threadContext)\n    {\n        KphDereferenceObject(threadContext);\n    }\n\n    if (threadObject)\n    {\n        ObDereferenceObject(threadObject);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Performs a session token privilege check.\n *\n * \\param[in,out] Token The session token to perform the check on.\n * \\param[in] Privileges The privileges to check.\n *\n * \\return TRUE if the privilege is granted, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphpSessionTokenPrivilegeCheck(\n    _Inout_ PKPH_SESSION_TOKEN Token,\n    _In_ ULONG Privileges\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER systemTime;\n    LONG useCount;\n\n    KPH_PAGED_CODE();\n\n    KeQuerySystemTime(&systemTime);\n\n    useCount = ReadAcquire(&Token->UseCount);\n\n    if (Token->AccessToken.Expiry.QuadPart <= systemTime.QuadPart)\n    {\n        status = STATUS_TIMEOUT;\n        goto Exit;\n    }\n\n    if ((Token->AccessToken.Privileges & Privileges) != Privileges)\n    {\n        status = STATUS_PRIVILEGE_NOT_HELD;\n        goto Exit;\n    }\n\n    if (Token->AccessToken.Uses < 0)\n    {\n        status = STATUS_SUCCESS;\n        goto Exit;\n    }\n\n    for (;;)\n    {\n        LONG expected;\n\n        if (useCount >= Token->AccessToken.Uses)\n        {\n            status = STATUS_QUOTA_EXCEEDED;\n            goto Exit;\n        }\n\n        expected = useCount;\n\n        useCount = InterlockedCompareExchange(&Token->UseCount,\n                                              useCount + 1,\n                                              expected);\n        if (useCount == expected)\n        {\n            useCount++;\n            status = STATUS_SUCCESS;\n            break;\n        }\n    }\n\nExit:\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  GENERAL,\n                  \"[%!GUID!] %!TIME! %ld/%ld %!STATUS!\",\n                  &Token->AccessToken.Identifier,\n                  Token->AccessToken.Expiry.QuadPart,\n                  useCount,\n                  Token->AccessToken.Uses,\n                  status);\n\n    return (status == STATUS_SUCCESS);\n}\n\n/**\n * \\brief Performs a session token privilege check on a thread.\n *\n * \\param[in] Thread The thread to perform the session token check on.\n * \\param[in] Privileges The privileges to check.\n *\n * \\return TRUE if the privilege is granted, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphpThreadSessionTokenPrivilegeCheck(\n    _In_ PKPH_THREAD_CONTEXT Thread,\n    _In_ ULONG Privileges\n    )\n{\n    BOOLEAN result;\n    PKPH_SESSION_TOKEN token;\n\n    KPH_PAGED_CODE();\n\n    result = FALSE;\n\n    token = KphAtomicReferenceObject(&Thread->SessionToken.Atomic);\n    if (token)\n    {\n        result = KphpSessionTokenPrivilegeCheck(token, Privileges);\n\n        KphDereferenceObject(token);\n    }\n\n    return result;\n}\n\n/**\n * \\brief Performs a session token privilege check on a process.\n *\n * \\param[in] Process The process to perform the session token check on.\n * \\param[in] Privileges The privileges to check.\n *\n * \\return TRUE if the privilege is granted, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphpProcessSessionTokenPrivilegeCheck(\n    _In_ PKPH_PROCESS_CONTEXT Process,\n    _In_ ULONG Privileges\n    )\n{\n    BOOLEAN result;\n    PKPH_SESSION_TOKEN token;\n\n    KPH_PAGED_CODE();\n\n    result = FALSE;\n\n    token = KphAtomicReferenceObject(&Process->SessionToken.Atomic);\n    if (token)\n    {\n        result = KphpSessionTokenPrivilegeCheck(token, Privileges);\n\n        KphDereferenceObject(token);\n    }\n\n    return result;\n}\n\n/**\n * \\brief Performs a session token privilege check.\n *\n * \\param[in] Thread The thread to perform the session token check on.\n * \\param[in] Privileges The privileges to check.\n *\n * \\return TRUE if the privilege is granted, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphSessionTokenPrivilegeCheck(\n    _In_ PKPH_THREAD_CONTEXT Thread,\n    _In_ ULONG Privileges\n    )\n{\n    KPH_PAGED_CODE();\n\n    if (KphpThreadSessionTokenPrivilegeCheck(Thread, Privileges))\n    {\n        return TRUE;\n    }\n\n    if (!Thread->ProcessContext)\n    {\n        return FALSE;\n    }\n\n    return KphpProcessSessionTokenPrivilegeCheck(Thread->ProcessContext,\n                                                 Privileges);\n}\n\n/**\n * \\brief Initialize the session token infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphInitializeSessionToken(\n    VOID\n    )\n{\n    KPH_OBJECT_TYPE_INFO typeInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    typeInfo.Allocate = KphpAllocateSessionToken;\n    typeInfo.Initialize = KphpInitializeSessionToken;\n    typeInfo.Delete = NULL;\n    typeInfo.Free = KphpFreeSessionToken;\n    typeInfo.Flags = 0;\n\n    KphCreateObjectType(&KphpSessionTokenTypeName,\n                        &typeInfo,\n                        &KphpSessionTokenType);\n}\n"
  },
  {
    "path": "KSystemInformer/system.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Performs generic system control actions.\n *\n * \\param[in] SystemControlClass System control classification.\n * \\param[in] SystemControlInfo Control input buffer.\n * \\param[in] SystemControlInfoLength Length of control input buffer.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSystemControl(\n    _In_ KPH_SYSTEM_CONTROL_CLASS SystemControlClass,\n    _In_reads_bytes_(SystemControlInfoLength) PVOID SystemControlInfo,\n    _In_ ULONG SystemControlInfoLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    UNREFERENCED_PARAMETER(SystemControlInfo);\n    UNREFERENCED_PARAMETER(SystemControlInfoLength);\n    UNREFERENCED_PARAMETER(AccessMode);\n\n    processHandle = NULL;\n\n    switch (SystemControlClass)\n    {\n        case KphSystemControlEmptyCompressionStore:\n        {\n            SYSTEM_STORE_INFORMATION storeInfo;\n            SM_STORE_COMPRESSION_INFORMATION_REQUEST compressionInfo;\n            CLIENT_ID clientId;\n            OBJECT_ATTRIBUTES objectAttributes;\n            QUOTA_LIMITS_EX quotaLimits;\n\n#ifdef _WIN64\n            C_ASSERT(sizeof(SYSTEM_STORE_INFORMATION) == 24);\n            C_ASSERT(SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION_V1 == 3);\n            C_ASSERT(SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V1 == 40);\n#endif\n\n            RtlZeroMemory(&compressionInfo, sizeof(SM_STORE_COMPRESSION_INFORMATION_REQUEST));\n            compressionInfo.Version = SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION_V1;\n\n            RtlZeroMemory(&storeInfo, sizeof(SYSTEM_STORE_INFORMATION));\n            storeInfo.Version = SYSTEM_STORE_INFORMATION_VERSION;\n            storeInfo.StoreInformationClass = MemCompressionInfoRequest;\n            storeInfo.Data = &compressionInfo;\n            storeInfo.Length = SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V1;\n\n            status = ZwQuerySystemInformation(SystemStoreInformation,\n                                              &storeInfo,\n                                              sizeof(SYSTEM_STORE_INFORMATION),\n                                              NULL);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ZwQuerySystemInformation failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            if (compressionInfo.CompressionPid == 0)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"Compression PID is zero\");\n\n                status = STATUS_INVALID_CID;\n                goto Exit;\n            }\n\n            InitializeObjectAttributes(&objectAttributes,\n                                       NULL,\n                                       OBJ_KERNEL_HANDLE,\n                                       NULL,\n                                       NULL);\n\n            clientId.UniqueProcess = ULongToHandle(compressionInfo.CompressionPid);\n            clientId.UniqueThread = NULL;\n\n            status = ZwOpenProcess(&processHandle,\n                                   PROCESS_SET_QUOTA,\n                                   &objectAttributes,\n                                   &clientId);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ZwOpenProcess failed: %!STATUS!\",\n                              status);\n\n                processHandle = NULL;\n                goto Exit;\n            }\n\n            RtlZeroMemory(&quotaLimits, sizeof(QUOTA_LIMITS_EX));\n            quotaLimits.MinimumWorkingSetSize = SIZE_T_MAX;\n            quotaLimits.MaximumWorkingSetSize = SIZE_T_MAX;\n\n            status = ZwSetInformationProcess(processHandle,\n                                             ProcessQuotaLimits,\n                                             &quotaLimits,\n                                             sizeof(QUOTA_LIMITS_EX));\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ZwSetInformationProcess failed: %!STATUS!\",\n                              status);\n            }\n\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            goto Exit;\n        }\n    }\n\nExit:\n\n    if (processHandle)\n    {\n        ObCloseHandle(processHandle, KernelMode);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/thread.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Opens a thread.\n *\n * \\param[out] ThreadHandle A variable which receives the thread handle.\n * \\param[in] DesiredAccess The desired access to the thread.\n * \\param[in] ClientId The identifier of a client. UniqueThread must be present.\n * If UniqueProcess is present, the process of the referenced thread will be\n * checked against this identifier.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    CLIENT_ID clientId;\n    PETHREAD thread;\n    HANDLE threadHandle = NULL;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    thread = NULL;\n\n    status = KphCopyFromMode(&clientId,\n                             ClientId,\n                             sizeof(CLIENT_ID),\n                             AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    //\n    // Use the process ID if it was specified.\n    //\n    if (clientId.UniqueProcess)\n    {\n        status = PsLookupProcessThreadByCid(&clientId, NULL, &thread);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"PsLookupProcessThreadByCid failed: %!STATUS!\",\n                          status);\n\n            thread = NULL;\n            goto Exit;\n        }\n    }\n    else\n    {\n        status = PsLookupThreadByThreadId(clientId.UniqueThread, &thread);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"PsLookupThreadByThreadId failed: %!STATUS!\",\n                          status);\n\n            thread = NULL;\n            goto Exit;\n        }\n    }\n\n    if ((DesiredAccess & KPH_THREAD_READ_ACCESS) != DesiredAccess)\n    {\n        status = KphDominationCheck(PsGetCurrentProcess(),\n                                    PsGetThreadProcess(thread),\n                                    AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"KphDominationCheck failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    //\n    // Always open in KernelMode to skip access checks.\n    //\n    status = ObOpenObjectByPointer(thread,\n                                   (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                   NULL,\n                                   DesiredAccess,\n                                   *PsThreadType,\n                                   KernelMode,\n                                   &threadHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        threadHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphWriteHandleToMode(ThreadHandle, threadHandle, AccessMode);\n\nExit:\n    if (thread)\n    {\n        ObDereferenceObject(thread);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Opens the process of a thread.\n *\n * \\param[in] ThreadHandle A handle to a thread.\n * \\param[in] DesiredAccess The desired access to the process.\n * \\param[out] ProcessHandle A variable which receives the process handle.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PETHREAD thread;\n    HANDLE processHandle;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = ObReferenceObjectByHandle(ThreadHandle,\n                                       0,\n                                       *PsThreadType,\n                                       AccessMode,\n                                       &thread,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        thread = NULL;\n        goto Exit;\n    }\n\n    if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) != DesiredAccess)\n    {\n        status = KphDominationCheck(PsGetCurrentProcess(),\n                                    PsGetThreadProcess(thread),\n                                    AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"KphDominationCheck failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    //\n    // Always open in KernelMode to skip access checks.\n    //\n    status = ObOpenObjectByPointer(PsGetThreadProcess(thread),\n                                   (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                   NULL,\n                                   DesiredAccess,\n                                   *PsProcessType,\n                                   KernelMode,\n                                   &processHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        processHandle = NULL;\n        goto Exit;\n    }\n\n    status = KphWriteHandleToMode(ProcessHandle, processHandle, AccessMode);\n\nExit:\n    if (thread)\n    {\n        ObDereferenceObject(thread);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Captures the stack trace of a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread to capture the stack trace of.\n * \\param[in] FramesToSkip The number of kernel frames to skip.\n * \\param[in] FramesToCapture The number of frames to capture.\n * \\param[out] BackTrace Buffer to store the back trace in.\n * \\param[out] CapturedFrames Receives the number of captured frames.\n * \\param[out] BackTraceHash Optionally receives a hash of the back trace.\n * \\param[in] Flags A combination of KPH_STACK_BACK_TRACE_* flags.\n * \\param[in] Timeout Optionally specifies a timeout for the capture operation.\n *\n * \\return STATUS_SUCCES, STATUS_TIMEOUT, or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCaptureStackBackTraceThreadByHandle(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID* BackTrace,\n    _Out_ PULONG CapturedFrames,\n    _Out_opt_ PULONG BackTraceHash,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    PETHREAD thread;\n    PVOID backTrace;\n    ULONG capturedFrames;\n    ULONG backTraceHash;\n    LARGE_INTEGER timeout;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    backTrace = NULL;\n    thread = NULL;\n    backTraceHash = 0;\n\n    if (!CapturedFrames)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    status = KphWriteULongToMode(CapturedFrames, 0, AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    if (BackTraceHash)\n    {\n        status = KphWriteULongToMode(BackTraceHash, 0, AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\n    if (Timeout)\n    {\n        status = KphReadLargeIntegerFromMode(&timeout, Timeout, AccessMode);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n    }\n\n    if (AccessMode != KernelMode)\n    {\n        backTrace = KphAllocatePaged(FramesToCapture * sizeof(PVOID),\n                                     KPH_TAG_THREAD_BACK_TRACE);\n        if (!backTrace)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Failed to allocate back trace buffer.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n    }\n    else\n    {\n        backTrace = BackTrace;\n    }\n\n    status = ObReferenceObjectByHandle(ThreadHandle,\n                                       0,\n                                       *PsThreadType,\n                                       AccessMode,\n                                       &thread,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        thread = NULL;\n        goto Exit;\n    }\n\n    status = KphCaptureStackBackTraceThread(thread,\n                                            FramesToSkip,\n                                            FramesToCapture,\n                                            backTrace,\n                                            &capturedFrames,\n                                            (BackTraceHash ? &backTraceHash : NULL),\n                                            Flags,\n                                            (Timeout ? &timeout : NULL));\n    if (!NT_SUCCESS(status) || (status == STATUS_TIMEOUT))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphCaptureStackBackTraceThread failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    if (AccessMode != KernelMode)\n    {\n        __try\n        {\n            CopyToUser(BackTrace, backTrace, capturedFrames * sizeof(PVOID));\n\n            WriteULongToUser(CapturedFrames, capturedFrames);\n\n            if (BackTraceHash)\n            {\n                WriteULongToUser(BackTraceHash, backTraceHash);\n            }\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n        }\n    }\n    else\n    {\n        *CapturedFrames = capturedFrames;\n\n        if (BackTraceHash)\n        {\n            *BackTraceHash = backTraceHash;\n        }\n    }\n\nExit:\n\n    if (backTrace && (backTrace != BackTrace))\n    {\n        KphFree(backTrace, KPH_TAG_THREAD_BACK_TRACE);\n    }\n\n    if (thread)\n    {\n        ObDereferenceObject(thread);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Sets information about a thread.\n *\n * \\param[in] ThreadHandle Handle to thread to set information for.\n * \\param[in] ThreadInformationClass Information class to set.\n * \\param[in] ThreadInformation Information to set.\n * \\param[in] ThreadInformationLength Length of the thread information buffer.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PVOID threadInformation;\n    BYTE stackBuffer[64];\n    PETHREAD thread;\n    HANDLE threadHandle;\n    THREADINFOCLASS threadInformationClass;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    threadInformation = NULL;\n    thread = NULL;\n    threadHandle = NULL;\n\n    if (!ThreadInformation)\n    {\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    if (AccessMode != KernelMode)\n    {\n        threadInformation = KphAllocatePagedA(ThreadInformationLength,\n                                              KPH_TAG_THREAD_INFO,\n                                              stackBuffer);\n        if (!threadInformation)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Failed to allocate thread info buffer.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        __try\n        {\n            CopyFromUser(threadInformation,\n                         ThreadInformation,\n                         ThreadInformationLength);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            status = GetExceptionCode();\n            goto Exit;\n        }\n    }\n    else\n    {\n        threadInformation = ThreadInformation;\n    }\n\n    status = ObReferenceObjectByHandle(ThreadHandle,\n                                       0,\n                                       *PsThreadType,\n                                       AccessMode,\n                                       &thread,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        thread = NULL;\n        goto Exit;\n    }\n\n    status = KphDominationCheck(PsGetCurrentProcess(),\n                                PsGetThreadProcess(thread),\n                                AccessMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphDominationCheck failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = ObOpenObjectByPointer(thread,\n                                   OBJ_KERNEL_HANDLE,\n                                   NULL,\n                                   THREAD_SET_INFORMATION,\n                                   *PsThreadType,\n                                   KernelMode,\n                                   &threadHandle);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObOpenObjectByPointer failed: %!STATUS!\",\n                      status);\n\n        threadHandle = NULL;\n        goto Exit;\n    }\n\n    switch (ThreadInformationClass)\n    {\n        case KphThreadPriority:\n        {\n            threadInformationClass = ThreadPriority;\n            break;\n        }\n        case KphThreadBasePriority:\n        {\n            threadInformationClass = ThreadBasePriority;\n            break;\n        }\n        case KphThreadAffinityMask:\n        {\n            threadInformationClass = ThreadAffinityMask;\n            break;\n        }\n        case KphThreadIdealProcessor:\n        {\n            threadInformationClass = ThreadIdealProcessor;\n            break;\n        }\n        case KphThreadPriorityBoost:\n        {\n            threadInformationClass = ThreadPriorityBoost;\n            break;\n        }\n        case KphThreadIoPriority:\n        {\n            threadInformationClass = ThreadIoPriority;\n            break;\n        }\n        case KphThreadPagePriority:\n        {\n            threadInformationClass = ThreadPagePriority;\n            break;\n        }\n        case KphThreadActualBasePriority:\n        {\n            threadInformationClass = ThreadActualBasePriority;\n            break;\n        }\n        case KphThreadGroupInformation:\n        {\n            threadInformationClass = ThreadGroupInformation;\n            break;\n        }\n        case KphThreadIdealProcessorEx:\n        {\n            threadInformationClass = ThreadIdealProcessorEx;\n            break;\n        }\n        case KphThreadActualGroupAffinity:\n        {\n            threadInformationClass = ThreadActualGroupAffinity;\n            break;\n        }\n        case KphThreadPowerThrottlingState:\n        {\n            threadInformationClass = ThreadPowerThrottlingState;\n            break;\n        }\n        case KphThreadExplicitCaseSensitivity:\n        {\n            threadInformationClass = ThreadExplicitCaseSensitivity;\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            goto Exit;\n        }\n    }\n\n    status = ZwSetInformationThread(threadHandle,\n                                    threadInformationClass,\n                                    threadInformation,\n                                    ThreadInformationLength);\n\nExit:\n\n    if (threadHandle)\n    {\n        ObCloseHandle(threadHandle, KernelMode);\n    }\n\n    if (thread)\n    {\n        ObDereferenceObject(thread);\n    }\n\n    if (threadInformation && (threadInformation != ThreadInformation))\n    {\n        KphFreeA(threadInformation, KPH_TAG_THREAD_INFO, stackBuffer);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries thread information.\n *\n * \\param[in] ThreadHandle Handle to thread to query information of.\n * \\param[in] ThreadInformationClass Information class to query.\n * \\param[out] ThreadInformation Populated with thread information by class.\n * \\param[in] ThreadInformationLength Length of the thread information buffer.\n * \\param[out] ReturnLength Received the number of bytes written or required.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _Out_writes_bytes_opt_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    PETHREAD threadObject;\n    PKPH_THREAD_CONTEXT thread;\n    ULONG returnLength;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    dyn = NULL;\n    thread = NULL;\n    returnLength = 0;\n\n    status = ObReferenceObjectByHandle(ThreadHandle,\n                                       0,\n                                       *PsThreadType,\n                                       AccessMode,\n                                       &threadObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        threadObject = NULL;\n        goto Exit;\n    }\n\n    thread = KphGetEThreadContext(threadObject);\n    if (!thread)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"KphGetThreadContext returned null.\");\n\n        status = STATUS_OBJECTID_NOT_FOUND;\n        goto Exit;\n    }\n\n    switch (ThreadInformationClass)\n    {\n        case KphThreadIoCounters:\n        {\n            IO_COUNTERS counters;\n            PULONG64 value;\n\n            dyn = KphReferenceDynData();\n\n            if (!dyn ||\n                (dyn->KtReadOperationCount == ULONG_MAX) ||\n                (dyn->KtWriteOperationCount == ULONG_MAX) ||\n                (dyn->KtOtherOperationCount == ULONG_MAX) ||\n                (dyn->KtReadTransferCount == ULONG_MAX) ||\n                (dyn->KtWriteTransferCount == ULONG_MAX) ||\n                (dyn->KtOtherTransferCount == ULONG_MAX))\n            {\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            if (!ThreadInformation ||\n                (ThreadInformationLength < sizeof(IO_COUNTERS)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(IO_COUNTERS);\n                goto Exit;\n            }\n\n            RtlZeroMemory(&counters, sizeof(IO_COUNTERS));\n\n            value = Add2Ptr(threadObject, dyn->KtReadOperationCount);\n            counters.ReadOperationCount = *value;\n            value = Add2Ptr(threadObject, dyn->KtWriteOperationCount);\n            counters.WriteOperationCount = *value;\n            value = Add2Ptr(threadObject, dyn->KtOtherOperationCount);\n            counters.OtherOperationCount = *value;\n            value = Add2Ptr(threadObject, dyn->KtReadTransferCount);\n            counters.ReadTransferCount = *value;\n            value = Add2Ptr(threadObject, dyn->KtWriteTransferCount);\n            counters.WriteTransferCount = *value;\n            value = Add2Ptr(threadObject, dyn->KtOtherTransferCount);\n            counters.OtherTransferCount = *value;\n\n            status = KphCopyToMode(ThreadInformation,\n                                   &counters,\n                                   sizeof(IO_COUNTERS),\n                                   AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(IO_COUNTERS);\n            }\n\n            break;\n        }\n        case KphThreadWSLThreadId:\n        {\n            ULONG threadId;\n\n            if (thread->SubsystemType != SubsystemInformationTypeWSL)\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"Invalid subsystem for WSL thread ID query.\");\n\n                status = STATUS_INVALID_HANDLE;\n                goto Exit;\n            }\n\n            if (!ThreadInformation ||\n                (ThreadInformationLength < sizeof(ULONG)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(ULONG);\n                goto Exit;\n            }\n\n            status = KphQueryInformationThreadContext(thread,\n                                                      KphThreadContextWSLThreadId,\n                                                      &threadId,\n                                                      sizeof(ULONG),\n                                                      NULL);\n            if (!NT_SUCCESS(status))\n            {\n                goto Exit;\n            }\n\n            status = KphWriteULongToMode(ThreadInformation,\n                                         threadId,\n                                         AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(ULONG);\n            }\n\n            break;\n        }\n        case KphThreadKernelStackInformation:\n        {\n            KPH_KERNEL_STACK_INFORMATION info;\n\n            dyn = KphReferenceDynData();\n\n            if (!dyn ||\n                (dyn->KtInitialStack == ULONG_MAX) ||\n                (dyn->KtStackLimit == ULONG_MAX) ||\n                (dyn->KtStackBase == ULONG_MAX) ||\n                (dyn->KtKernelStack == ULONG_MAX))\n            {\n                status = STATUS_NOINTERFACE;\n                goto Exit;\n            }\n\n            if (!ThreadInformation ||\n                (ThreadInformationLength < sizeof(KPH_KERNEL_STACK_INFORMATION)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_KERNEL_STACK_INFORMATION);\n                goto Exit;\n            }\n\n            RtlZeroMemory(&info, sizeof(KPH_KERNEL_STACK_INFORMATION));\n\n            info.InitialStack = *(PVOID*)Add2Ptr(threadObject, dyn->KtInitialStack);\n            info.StackLimit = *(PVOID*)Add2Ptr(threadObject, dyn->KtStackLimit);\n            info.StackBase = *(PVOID*)Add2Ptr(threadObject, dyn->KtStackBase);\n            info.KernelStack = *(PVOID*)Add2Ptr(threadObject, dyn->KtKernelStack);\n\n            status = KphCopyToMode(ThreadInformation,\n                                   &info,\n                                   sizeof(KPH_KERNEL_STACK_INFORMATION),\n                                   AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_KERNEL_STACK_INFORMATION);\n            }\n\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n\nExit:\n\n    if (ReturnLength)\n    {\n        KphWriteULongToMode(ReturnLength, returnLength, AccessMode);\n    }\n\n    if (thread)\n    {\n        KphDereferenceObject(thread);\n    }\n\n    if (threadObject)\n    {\n        ObDereferenceObject(threadObject);\n    }\n\n    if (dyn)\n    {\n        KphDereferenceObject(dyn);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "KSystemInformer/umaccess.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Captures a Unicode string from user mode.\n *\n * \\param[in] UnicodeString Unicode string to capture from user mode.\n * \\param[out] CapturedUnicodeString Receives the captured Unicode string, the\n * captured buffer must be freed using KphReleaseUnicodeString.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCaptureUnicodeString(\n    _In_ PUNICODE_STRING UnicodeString,\n    _Out_ PUNICODE_STRING* CapturedUnicodeString\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING inputString;\n    PUNICODE_STRING outputString;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    outputString = NULL;\n\n    __try\n    {\n        CopyFromUser(&inputString, UnicodeString, sizeof(UNICODE_STRING));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    outputString = KphAllocatePaged(sizeof(UNICODE_STRING) + inputString.Length,\n                                    KPH_TAG_CAPTURED_UNICODE_STRING);\n    if (!outputString)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    outputString->Buffer = Add2Ptr(outputString, sizeof(UNICODE_STRING));\n    outputString->Length = 0;\n    outputString->MaximumLength = inputString.Length;\n\n    __try\n    {\n        CopyFromUser(outputString->Buffer,\n                     inputString.Buffer,\n                     inputString.Length);\n        outputString->Length = inputString.Length;\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n        goto Exit;\n    }\n\n    *CapturedUnicodeString = outputString;\n    outputString = NULL;\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (outputString)\n    {\n        KphFree(outputString, KPH_TAG_CAPTURED_UNICODE_STRING);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Releases a previously captured Unicode string.\n *\n * \\param[in] UnicodeString Unicode string to release.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphReleaseUnicodeString(\n    _In_ PUNICODE_STRING CaputredUnicodeString\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    KphFree(CaputredUnicodeString, KPH_TAG_CAPTURED_UNICODE_STRING);\n}\n\n/**\n * \\brief Zeros memory in the specified mode.\n *\n * \\param[out] Destination Address to zero memory at.\n * \\param[in] Length The length of the memory to zero, in bytes.\n * \\param[in] AccessMode The access mode to use for the zeroing.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphZeroModeMemory(\n    _Out_writes_bytes_all_(Length) PVOID Destination,\n    _In_ SIZE_T Length,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        ZeroModeMemory(Destination, Length, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Copies memory to the specified mode.\n *\n * \\param[out] Destination Address to copy memory to.\n * \\param[in] Source Address to copy memory from.\n * \\param[in] Length The length of the memory to copy, in bytes.\n * \\param[in] AccessMode The access mode to use for the copy.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphCopyToMode(\n    _Out_writes_bytes_all_(Length) PVOID Destination,\n    _In_reads_bytes_(Length) PVOID Source,\n    _In_ SIZE_T Length,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        CopyToMode(Destination, Source, Length, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Copies memory from the specified mode.\n *\n * \\param[out] Destination Address to copy memory to.\n * \\param[in] Source Address to copy memory from.\n * \\param[in] Length The length of the memory to copy, in bytes.\n * \\param[in] AccessMode The access mode to use for the copy.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphCopyFromMode(\n    _Out_writes_bytes_all_(Length) PVOID Destination,\n    _In_reads_bytes_(Length) PVOID Source,\n    _In_ SIZE_T Length,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        CopyFromMode(Destination, Source, Length, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Writes an unsigned 8-bit value to the specified mode.\n *\n * \\param[out] Destination Address to write the unsigned 8-bit value to.\n * \\param[in] Source The unsigned 8-bit value to write.\n * \\param[in] AccessMode The access mode to use for the write.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteUCharToMode(\n    _Out_ PUCHAR Destination,\n    _In_ UCHAR Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        WriteUCharToMode(Destination, Source, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Writes an unsigned 32-bit value to the specified mode.\n *\n * \\param[out] Destination Address to write the unsigned 32-bit value to.\n * \\param[in] Source The unsigned 32-bit value to write.\n * \\param[in] AccessMode The access mode to use for the write.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteULongToMode(\n    _Out_ PULONG Destination,\n    _In_ ULONG Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        WriteULongToMode(Destination, Source, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Writes an unsigned 64-bit value to the specified mode.\n *\n * \\param[out] Destination Address to write the unsigned 64-bit value to.\n * \\param[in] Source The unsigned 64-bit value to write.\n * \\param[in] AccessMode The access mode to use for the write.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteULong64ToMode(\n    _Out_ PULONG64 Destination,\n    _In_ ULONG64 Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        WriteULong64ToMode(Destination, Source, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Writes an signed 64-bit value to the specified mode.\n *\n * \\param[out] Destination Address to write the signed 64-bit value to.\n * \\param[in] Source The signed 64-bit value to write.\n * \\param[in] AccessMode The access mode to use for the write.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteLong64ToMode(\n    _Out_ PLONG64 Destination,\n    _In_ LONG64 Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        WriteLong64ToMode(Destination, Source, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Writes an unsigned size width value to the specified mode.\n *\n * \\param[out] Destination Address to write the unsigned sized width value to.\n * \\param[in] Source The unsigned sized width value to write.\n * \\param[in] AccessMode The access mode to use for the write.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteSizeTToMode(\n    _Out_ PSIZE_T Destination,\n    _In_ SIZE_T Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        WriteSizeTToMode(Destination, Source, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Writes a pointer to the specified mode.\n *\n * \\param[out] Destination Address to write the pointer to.\n * \\param[in] Source The pointer to write.\n * \\param[in] AccessMode The access mode to use for the write.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWritePointerToMode(\n    _Out_ PVOID* Destination,\n    _In_ PVOID Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        WritePointerToMode(Destination, Source, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Writes a handle to the specified mode.\n *\n * \\details If the write fails then the handle is closed oh behalf of the caller\n * to prevent a handle leak.\n *\n * \\param[out] Destination Address to write the handle to.\n * \\param[in] Source The handle to write.\n * \\param[in] AccessMode The access mode to use for the write.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphWriteHandleToMode(\n    _Out_ PHANDLE Destination,\n    _In_ _Post_ptr_invalid_ HANDLE Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        WriteHandleToMode(Destination, Source, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        ObCloseHandle(Source, AccessMode);\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Copies a Unicode string to the specified mode.\n *\n * \\details The Unicode string is constructed at the destination address and the\n * string content immediately follows the string structure.\n *\n * \\param[out] Destination Optional address to copy the Unicode string to.\n * \\param[in] Length The length of the destination buffer, in bytes.\n * \\param[in] String Optional Unicode string to copy.\n * \\param[out] ReturnLength Number of bytes copied to the destination buffer,\n * including the string structure and following content.\n * \\param[in] AccessMode The access mode to use for the copy.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\nNTSTATUS KphCopyUnicodeStringToMode(\n    _Out_writes_bytes_opt_(Length) PVOID Destination,\n    _In_ SIZE_T Length,\n    _In_opt_ PCUNICODE_STRING String,\n    _Out_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    PUNICODE_STRING destination;\n    USHORT maximumLength;\n\n    KPH_PAGED_CODE();\n\n    if (!String)\n    {\n        *ReturnLength = sizeof(UNICODE_STRING);\n\n        if (!Destination || (Length < sizeof(UNICODE_STRING)))\n        {\n            return STATUS_BUFFER_TOO_SMALL;\n        }\n\n        destination = Destination;\n\n        return KphZeroModeMemory(destination,\n                                 sizeof(UNICODE_STRING),\n                                 AccessMode);\n    }\n\n    *ReturnLength = (sizeof(UNICODE_STRING) + String->Length);\n\n    if (!Destination || (Length < (sizeof(UNICODE_STRING) + String->Length)))\n    {\n        return STATUS_BUFFER_TOO_SMALL;\n    }\n\n    destination = Destination;\n    maximumLength = (USHORT)(Length - sizeof(UNICODE_STRING));\n\n    if (AccessMode != KernelMode)\n    {\n        __try\n        {\n            WriteUShortToUser(&destination->Length, String->Length);\n            WriteUShortToUser(&destination->MaximumLength, maximumLength);\n            WritePointerToUser(&destination->Buffer,\n                               Add2Ptr(destination, sizeof(UNICODE_STRING)));\n\n            NT_ASSERT(destination->Buffer);\n\n            CopyToUser(destination->Buffer, String->Buffer, String->Length);\n\n            if ((String->Length + sizeof(UNICODE_NULL)) <= maximumLength)\n            {\n                PWCHAR end;\n\n                end = &destination->Buffer[String->Length / sizeof(WCHAR)];\n\n                WriteUShortToUser(end, UNICODE_NULL);\n            }\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n    else\n    {\n        destination->Length = 0;\n        destination->MaximumLength = maximumLength;\n        destination->Buffer = Add2Ptr(destination, sizeof(UNICODE_STRING));\n        RtlCopyUnicodeString(destination, String);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Reads a LARGE_INTEGER from the specified mode.\n *\n * \\param[out] Destination Address to read the LARGE_INTEGER to.\n * \\param[in] Source The LARGE_INTEGER to read.\n * \\param[in] AccessMode The access mode to use for the read.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReadLargeIntegerFromMode(\n    _Out_ PLARGE_INTEGER Destination,\n    _In_ PLARGE_INTEGER Source,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    KPH_PAGED_CODE();\n\n    __try\n    {\n        *Destination = ReadLargeIntegerFromMode(Source, AccessMode);\n    }\n    __except (UmaExceptionFilter(AccessMode))\n    {\n        return GetExceptionCode();\n    }\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "KSystemInformer/util.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n#include <search.h>\n\n#include <trace.h>\n\n/**\n * \\brief Performs a binary search of a sorted array.\n *\n * \\param[in] Key Pointer to the key to search for.\n * \\param[in] Base Pointer to the base of the search data.\n * \\param[in] NumberOfElements Number of elements in the array.\n * \\param[in] SizeOfElement Size of each element in the array.\n * \\param[in] Callback Comparison callback.\n * \\param[in] Context Optional context for the callback.\n *\n * \\return Pointer to the found element, NULL if not found.\n */\n_Must_inspect_result_\n_Success_(return != NULL)\nPVOID KphBinarySearch(\n    _In_ PCVOID Key,\n    _In_reads_bytes_(NumberOfElements * SizeOfElement) PCVOID Base,\n    _In_ ULONG NumberOfElements,\n    _In_ ULONG SizeOfElement,\n    _In_ PKPH_BINARY_SEARCH_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    return bsearch_s(Key,\n                     Base,\n                     NumberOfElements,\n                     SizeOfElement,\n                     Callback,\n                     Context);\n}\n\n/**\n * \\brief Performs a quick sort of an array.\n *\n * \\param[in] Base Pointer to the base of the array to sort.\n * \\param[in] NumberOfElements Number of elements in the array.\n * \\param[in] SizeOfElement Size of each element in the array.\n * \\param[in] Callback Comparison callback.\n * \\param[in] Context Optional context for the callback.\n */\nVOID KphQuickSort(\n    _Inout_updates_bytes_(NumberOfElements * SizeOfElement) PVOID Base,\n    _In_ ULONG NumberOfElements,\n    _In_ ULONG SizeOfElement,\n    _In_ PKPH_QUICK_SORT_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    qsort_s(Base, NumberOfElements, SizeOfElement, Callback, Context);\n}\n\n/**\n * \\brief Searches memory for a given pattern.\n *\n * \\param[in] Buffer The memory to search.\n * \\param[in] BufferLength The length of the memory to search.\n * \\param[in] Pattern The pattern to search for.\n * \\param[in] PatternLength The length of the pattern to search for.\n *\n * \\return Pointer to the beginning of the first found pattern, NULL if the\n * pattern is not found.\n */\n_Must_inspect_result_\n_Success_(return != NULL)\nPVOID KphSearchMemory(\n    _In_reads_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _In_reads_bytes_(PatternLength) PVOID Pattern,\n    _In_ ULONG PatternLength\n    )\n{\n    PBYTE buffer;\n    PBYTE end;\n\n    if (!BufferLength || !PatternLength)\n    {\n        return NULL;\n    }\n\n    if (PatternLength > BufferLength)\n    {\n        return NULL;\n    }\n\n    buffer = Buffer;\n    end = Add2Ptr(Buffer, BufferLength - PatternLength);\n\n    //\n    // Move the loop into the switch to ensure optimal code generation.\n    //\n#define KPH_SEARCH_MEMORY_FOR for (; buffer <= end; buffer++)\n\n    //\n    // Optimization for a pattern size that fits into a register.\n    //\n#define KPH_SEARCH_MEMORY_SIZED(type)                                          \\\n    case sizeof(type):                                                         \\\n    {                                                                          \\\n        KPH_SEARCH_MEMORY_FOR                                                  \\\n        {                                                                      \\\n            if (*(type*)buffer == *(type*)Pattern)                             \\\n            {                                                                  \\\n                return buffer;                                                 \\\n            }                                                                  \\\n        }                                                                      \\\n        break;                                                                 \\\n    }\n\n    switch (PatternLength)\n    {\n        KPH_SEARCH_MEMORY_SIZED(UCHAR)\n        KPH_SEARCH_MEMORY_SIZED(USHORT)\n        KPH_SEARCH_MEMORY_SIZED(ULONG)\n        KPH_SEARCH_MEMORY_SIZED(ULONG64)\n        default:\n        {\n            KPH_SEARCH_MEMORY_FOR\n            {\n#pragma warning(suppress: 4995) // suppress deprecation warning\n                if (memcmp(buffer, Pattern, PatternLength) == 0)\n                {\n                    return buffer;\n                }\n            }\n            break;\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * \\brief Acquires rundown. On successful return the caller should release\n * the rundown using KphReleaseRundown.\n *\n * \\param[in,out] Rundown The rundown object to acquire.\n *\n * \\return TRUE if rundown is acquired, FALSE if object is already ran down.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphAcquireRundown(\n    _Inout_ PKPH_RUNDOWN Rundown\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    return ExAcquireRundownProtection(Rundown);\n}\n\n/**\n * \\brief Releases rundown previously acquired by KphAcquireRundown.\n *\n * \\param[in,out] Rundown The rundown object to release.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nVOID KphReleaseRundown(\n    _Inout_ PKPH_RUNDOWN Rundown\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    ExReleaseRundownProtection(Rundown);\n}\n\n/**\n * \\brief Retrieves the process sequence number for a given process.\n *\n * \\param[in] Process The process to get the sequence number of.\n *\n * \\return The sequence number key.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG64 KphGetProcessSequenceNumber(\n    _In_ PEPROCESS Process\n    )\n{\n    ULONG64 sequence;\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (KphDynPsGetProcessSequenceNumber)\n    {\n        return KphDynPsGetProcessSequenceNumber(Process);\n    }\n\n    process = KphGetEProcessContext(Process);\n    if (!process)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"Failed to get process sequence number for PID %lu\",\n                      HandleToULong(PsGetProcessId(Process)));\n\n        return 0;\n    }\n\n    sequence = process->SequenceNumber;\n\n    KphDereferenceObject(process);\n\n    return sequence;\n}\n\n/**\n * \\brief Retrieves the process start key for a given process.\n *\n * \\param[in] Process The process to get the start key of.\n *\n * \\return The process start key.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nULONG64 KphGetProcessStartKey(\n    _In_ PEPROCESS Process\n    )\n{\n    ULONG64 key;\n    PKPH_PROCESS_CONTEXT process;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (KphDynPsGetProcessStartKey)\n    {\n        return KphDynPsGetProcessStartKey(Process);\n    }\n\n    process = KphGetEProcessContext(Process);\n    if (!process)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"Failed to get process start key for PID %lu\",\n                      HandleToULong(PsGetProcessId(Process)));\n\n        return 0;\n    }\n\n    if (process->ProcessStartKey)\n    {\n        key = process->ProcessStartKey;\n    }\n    else\n    {\n        key = (process->SequenceNumber | ((ULONG64)SharedUserData->BootId << 48));\n    }\n\n    KphDereferenceObject(process);\n\n    return key;\n}\n\n/**\n * \\brief Retrieves the current thread's sub-process tag.\n *\n * \\return The current thread's sub-process tag.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nPVOID KphGetCurrentThreadSubProcessTag(\n    VOID\n    )\n{\n    PKPH_THREAD_CONTEXT thread;\n    PVOID subProcessTag;\n    PTEB teb;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (PsIsSystemThread(PsGetCurrentThread()))\n    {\n        return NULL;\n    }\n\n    //\n    // We support lookups at dispatch. To achieve this we cache the last lookup\n    // in the thread context. If we're at dispatch use the cache. Otherwise go\n    // do the lookup and cache the result in the thread context.\n    //\n\n    if (KeGetCurrentIrql() > APC_LEVEL)\n    {\n        subProcessTag = NULL;\n\n        thread = KphGetCurrentThreadContext();\n        if (thread)\n        {\n            subProcessTag = thread->SubProcessTag;\n\n            KphDereferenceObject(thread);\n        }\n\n        return subProcessTag;\n    }\n\n    teb = PsGetCurrentThreadTeb();\n    if (!teb)\n    {\n        return NULL;\n    }\n\n    __try\n    {\n        subProcessTag = ReadPointerFromUser(&teb->SubProcessTag);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return NULL;\n    }\n\n    thread = KphGetCurrentThreadContext();\n    if (thread)\n    {\n        thread->SubProcessTag = subProcessTag;\n\n        KphDereferenceObject(thread);\n    }\n\n    return subProcessTag;\n}\n\n/**\n * \\brief Retrieves a thread's sub-process tag.\n *\n * \\param[in] Thread The thread to get the sub-process tag of.\n * \\param[in] CacheOnly If TRUE, only the cached value is returned. This is\n * useful when the caller knows that touching the TEB is not safe.\n *\n * \\return The thread's sub-process tag.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nPVOID KphGetThreadSubProcessTagEx(\n    _In_ PETHREAD Thread,\n    _In_ BOOLEAN CacheOnly\n    )\n{\n    PKPH_THREAD_CONTEXT thread;\n    PVOID subProcessTag;\n    PTEB teb;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    if (PsIsSystemThread(Thread))\n    {\n        return NULL;\n    }\n\n    //\n    // We support lookups at dispatch and across process boundaries. To achieve\n    // this we cache the last lookup in the thread context. If we're at dispatch\n    // or across process boundaries use the cache. Otherwise go do the lookup\n    // and cache the result in the thread context. We choose not to attach to\n    // a process to retrieve the information to avoid performance penalties.\n    //\n\n    if (CacheOnly ||\n        (KeGetCurrentIrql() > APC_LEVEL) ||\n        (PsGetThreadProcess(Thread) != PsGetCurrentProcess()))\n    {\n        subProcessTag = NULL;\n\n        thread = KphGetEThreadContext(Thread);\n        if (thread)\n        {\n            subProcessTag = thread->SubProcessTag;\n\n            KphDereferenceObject(thread);\n        }\n\n        return subProcessTag;\n    }\n\n    teb = PsGetThreadTeb(Thread);\n    if (!teb)\n    {\n        return NULL;\n    }\n\n    __try\n    {\n        subProcessTag = ReadPointerFromUser(&teb->SubProcessTag);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return NULL;\n    }\n\n    thread = KphGetEThreadContext(Thread);\n    if (thread)\n    {\n        thread->SubProcessTag = subProcessTag;\n\n        KphDereferenceObject(thread);\n    }\n\n    return subProcessTag;\n}\n\n/**\n * \\brief Retrieves a thread's sub-process tag.\n *\n * \\param[in] Thread The thread to get the sub-process tag of.\n *\n * \\return The thread's sub-process tag.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\nPVOID KphGetThreadSubProcessTag(\n    _In_ PETHREAD Thread\n    )\n{\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    return KphGetThreadSubProcessTagEx(Thread, FALSE);\n}\n\n/**\n * \\brief Initializes rundown object.\n *\n * \\param[out] Rundown The rundown object to initialize.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphInitializeRundown(\n    _Out_ PKPH_RUNDOWN Rundown\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    ExInitializeRundownProtection(Rundown);\n}\n\n/**\n * \\brief Marks rundown active and waits for rundown release. Subsequent\n * attempts to acquire rundown will fail.\n *\n * \\param[in,out] Rundown The rundown object to activate and wait for.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphWaitForRundown(\n    _Inout_ PKPH_RUNDOWN Rundown\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    ExWaitForRundownProtectionRelease(Rundown);\n}\n\n/**\n * \\brief Initializes a readers-writer lock.\n *\n * \\param[in] Lock The readers-writer lock to initialize.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphInitializeRWLock(\n    _Out_ PKPH_RWLOCK Lock\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    FltInitializePushLock(Lock);\n}\n\n/**\n * \\brief Deletes a readers-writer lock.\n *\n * \\param[in] Lock The readers-writer lock to delete.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphDeleteRWLock(\n    _In_ PKPH_RWLOCK Lock\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    FltDeletePushLock(Lock);\n}\n\n/**\n * \\brief Acquires a readers-writer lock exclusive.\n *\n * \\param[in,out] Lock The readers-writer lock to acquire exclusively.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Acquires_lock_(_Global_critical_region_)\nVOID KphAcquireRWLockExclusive(\n    _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PKPH_RWLOCK Lock\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    FltAcquirePushLockExclusive(Lock);\n}\n\n/**\n * \\brief Acquires readers-writer lock shared.\n *\n * \\param[in,out] Lock The readers-writer lock to acquire shared.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Acquires_lock_(_Global_critical_region_)\nVOID KphAcquireRWLockShared(\n    _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PKPH_RWLOCK Lock\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    FltAcquirePushLockShared(Lock);\n}\n\n/**\n * \\brief Releases a readers-writer lock.\n *\n * \\param[in,out] Lock The readers-writer lock to release.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Releases_lock_(_Global_critical_region_)\nVOID KphReleaseRWLock(\n    _Inout_ _Requires_lock_held_(*_Curr_) _Releases_lock_(*_Curr_) PKPH_RWLOCK Lock\n    )\n{\n    KPH_NPAGED_CODE_APC_MAX_FOR_PAGING_IO();\n\n    FltReleasePushLock(Lock);\n}\n\n/**\n * \\brief Checks if two file objects are associated with the same data.\n *\n * \\param[in] FirstFileObject The first file object to check.\n * \\param[in] SecondFileObject The second file object to check.\n *\n * \\return TRUE if the files are the same, FALSE otherwise.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nBOOLEAN KphIsSameFile(\n    _In_ PFILE_OBJECT FirstFileObject,\n    _In_ PFILE_OBJECT SecondFileObject\n    )\n{\n    PSECTION_OBJECT_POINTERS first;\n    PSECTION_OBJECT_POINTERS second;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    first = FirstFileObject->SectionObjectPointer;\n    second = SecondFileObject->SectionObjectPointer;\n\n    if (first != second)\n    {\n        return FALSE;\n    }\n\n    if (!first)\n    {\n        return TRUE;\n    }\n\n    if ((first->DataSectionObject != second->DataSectionObject) ||\n        (first->SharedCacheMap != second->SharedCacheMap) ||\n        (first->ImageSectionObject != second->ImageSectionObject))\n    {\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Acquires a reference to a reference object.\n *\n * \\details KPH_REFERENCE provides underflow and overflow guarantees. For this\n * reason, KPH_REFERENCE may not be suitable for all applications since it is\n * more expensive than a simple reference count.\n *\n * \\param[in,out] Reference The reference object to acquire.\n * \\param[out] PreviousCount Optionally set to the previous reference count.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphAcquireReference(\n    _Inout_ PKPH_REFERENCE Reference,\n    _Out_opt_ PLONG PreviousCount\n    )\n{\n    LONG count;\n\n    KPH_PAGED_CODE();\n\n    count = ReadAcquire(&Reference->Count);\n\n    for (;;)\n    {\n        LONG expected;\n\n        if (count == LONG_MAX)\n        {\n            if (PreviousCount)\n            {\n                *PreviousCount = LONG_MAX;\n            }\n\n            return STATUS_INTEGER_OVERFLOW;\n        }\n\n        expected = count;\n\n        count = InterlockedCompareExchange(&Reference->Count,\n                                           count + 1,\n                                           expected);\n        if (count == expected)\n        {\n            if (PreviousCount)\n            {\n                *PreviousCount = count;\n            }\n\n            return STATUS_SUCCESS;\n        }\n    }\n}\n\n/**\n * \\brief Releases a reference to a reference object.\n *\n * \\details KPH_REFERENCE provides underflow and overflow guarantees. For this\n * reason, KPH_REFERENCE may not be suitable for all applications since it is\n * more expensive than a simple reference count.\n *\n * \\param[in,out] Reference The reference object to release.\n * \\param[out] PreviousCount Optionally set to the previous reference count.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReleaseReference(\n    _Inout_ PKPH_REFERENCE Reference,\n    _Out_opt_ PLONG PreviousCount\n    )\n{\n    LONG count;\n\n    KPH_PAGED_CODE();\n\n    count = ReadAcquire(&Reference->Count);\n\n    for (;;)\n    {\n        LONG expected;\n\n        if (count == 0)\n        {\n            if (PreviousCount)\n            {\n                *PreviousCount = 0;\n            }\n\n            return STATUS_INTEGER_OVERFLOW;\n        }\n\n        expected = count;\n\n        count = InterlockedCompareExchange(&Reference->Count,\n                                           count - 1,\n                                           count);\n        if (count == expected)\n        {\n            if (PreviousCount)\n            {\n                *PreviousCount = count;\n            }\n\n            return STATUS_SUCCESS;\n        }\n    }\n}\n\n/**\n * \\brief Checks if an address range lies within a kernel module.\n *\n * \\param[in] Address The beginning of the address range.\n * \\param[in] Length The number of bytes in the address range.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphValidateAddressForSystemModules(\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    )\n{\n    BOOLEAN valid;\n    PVOID endAddress;\n\n    KPH_PAGED_CODE();\n\n    if (Add2Ptr(Address, Length) < Address)\n    {\n        return STATUS_BUFFER_OVERFLOW;\n    }\n\n    endAddress = Add2Ptr(Address, Length);\n\n    KeEnterCriticalRegion();\n    if (!ExAcquireResourceSharedLite(PsLoadedModuleResource, TRUE))\n    {\n        KeLeaveCriticalRegion();\n\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"Failed to acquire PsLoadedModuleResource\");\n\n        return STATUS_RESOURCE_NOT_OWNED;\n    }\n\n    valid = FALSE;\n\n    for (PLIST_ENTRY link = PsLoadedModuleList->Flink;\n         link != PsLoadedModuleList;\n         link = link->Flink)\n    {\n        PKLDR_DATA_TABLE_ENTRY entry;\n        PVOID endOfImage;\n\n        entry = CONTAINING_RECORD(link, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n\n        endOfImage = Add2Ptr(entry->DllBase, entry->SizeOfImage);\n\n        if ((Address >= entry->DllBase) && (endAddress <= endOfImage))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"Validated address in %wZ\",\n                          &entry->FullDllName);\n            valid = TRUE;\n            break;\n        }\n    }\n\n    ExReleaseResourceLite(PsLoadedModuleResource);\n    KeLeaveCriticalRegion();\n\n    return (valid ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION);\n}\n\n/**\n * \\brief Queries the registry key for a string value.\n *\n * \\param[in] KeyHandle Handle to key to query.\n * \\param[in] ValueName Name of value to query.\n * \\param[out] String Populated with the queried registry string. The string is\n * guaranteed to be null terminated and the MaximumLength will reflect this\n * when compared to the Length. This string should be freed using\n * KphFreeRegistryString.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryRegistryString(\n    _In_ HANDLE KeyHandle,\n    _In_ PCUNICODE_STRING ValueName,\n    _Outptr_allocatesMem_ PUNICODE_STRING* String\n    )\n{\n    NTSTATUS status;\n    ULONG resultLength;\n    PKEY_VALUE_PARTIAL_INFORMATION info;\n    PUNICODE_STRING string;\n    ULONG length;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    *String = NULL;\n    info = NULL;\n\n    status = ZwQueryValueKey(KeyHandle,\n                             (PUNICODE_STRING)ValueName,\n                             KeyValuePartialInformation,\n                             NULL,\n                             0,\n                             &resultLength);\n    if ((status != STATUS_BUFFER_OVERFLOW) &&\n        (status != STATUS_BUFFER_TOO_SMALL))\n    {\n        if (NT_SUCCESS(status))\n        {\n            status = STATUS_UNSUCCESSFUL;\n        }\n\n        goto Exit;\n    }\n\n    info = KphAllocatePaged(resultLength, KPH_TAG_REG_STRING);\n    if (!info)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = ZwQueryValueKey(KeyHandle,\n                             (PUNICODE_STRING)ValueName,\n                             KeyValuePartialInformation,\n                             info,\n                             resultLength,\n                             &resultLength);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    if (resultLength < sizeof(KEY_VALUE_PARTIAL_INFORMATION))\n    {\n        status = STATUS_INFO_LENGTH_MISMATCH;\n        goto Exit;\n    }\n\n    status = RtlULongAdd(info->DataLength, sizeof(WCHAR), &length);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    if ((info->Type != REG_SZ) ||\n        (length > UNICODE_STRING_MAX_BYTES) ||\n        ((info->DataLength % 2) != 0))\n    {\n        status = STATUS_OBJECT_TYPE_MISMATCH;\n        goto Exit;\n    }\n\n    string = KphAllocatePaged((sizeof(UNICODE_STRING) + length),\n                              KPH_TAG_REG_STRING);\n    if (!string)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    string->Buffer = Add2Ptr(string, sizeof(UNICODE_STRING));\n    RtlZeroMemory(string->Buffer, length);\n\n    NT_ASSERT(info->DataLength < UNICODE_STRING_MAX_BYTES);\n    NT_ASSERT(length < UNICODE_STRING_MAX_BYTES);\n\n    string->Length = (USHORT)info->DataLength;\n    string->MaximumLength = (USHORT)length;\n\n    if (string->Length)\n    {\n        PWCHAR sz;\n\n        sz = (PWCHAR)info->Data;\n\n        NT_ASSERT(info->DataLength >= sizeof(WCHAR));\n\n        if (sz[(info->DataLength / sizeof(WCHAR)) - 1] == UNICODE_NULL)\n        {\n            string->Length -= sizeof(WCHAR);\n        }\n\n        RtlCopyMemory(string->Buffer, info->Data, string->Length);\n    }\n\n    *String = string;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (info)\n    {\n        KphFree(info, KPH_TAG_REG_STRING);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Frees a string retrieved by KphQueryRegistryString.\n *\n * \\param[in] String The string to free.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeRegistryString(\n    _In_freesMem_ PUNICODE_STRING String\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphFree(String, KPH_TAG_REG_STRING);\n}\n\n/**\n * \\brief Queries the registry key for a string value.\n *\n * \\param[in] KeyHandle Handle to key to query.\n * \\param[in] ValueName Name of value to query.\n * \\param[out] Buffer Registry binary buffer on success, should be freed using\n * KphFreeRegistryBinary.\n * \\param[out] Length Set to the length of the buffer.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryRegistryBinary(\n    _In_ HANDLE KeyHandle,\n    _In_ PCUNICODE_STRING ValueName,\n    _Outptr_allocatesMem_ PBYTE* Buffer,\n    _Out_ PULONG Length\n    )\n{\n    NTSTATUS status;\n    PBYTE buffer;\n    ULONG resultLength;\n    PKEY_VALUE_PARTIAL_INFORMATION info;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    *Buffer = NULL;\n    *Length = 0;\n    buffer = NULL;\n\n    status = ZwQueryValueKey(KeyHandle,\n                             (PUNICODE_STRING)ValueName,\n                             KeyValuePartialInformation,\n                             NULL,\n                             0,\n                             &resultLength);\n    if ((status != STATUS_BUFFER_OVERFLOW) &&\n        (status != STATUS_BUFFER_TOO_SMALL))\n    {\n        if (NT_SUCCESS(status))\n        {\n            status = STATUS_UNSUCCESSFUL;\n        }\n\n        goto Exit;\n    }\n\n    buffer = KphAllocatePaged(resultLength, KPH_TAG_REG_BINARY);\n    if (!buffer)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = ZwQueryValueKey(KeyHandle,\n                             (PUNICODE_STRING)ValueName,\n                             KeyValuePartialInformation,\n                             buffer,\n                             resultLength,\n                             &resultLength);\n    if (!NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    if (resultLength < sizeof(KEY_VALUE_PARTIAL_INFORMATION))\n    {\n        status = STATUS_INFO_LENGTH_MISMATCH;\n        goto Exit;\n    }\n\n    info = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;\n\n    if (info->Type != REG_BINARY)\n    {\n        status = STATUS_OBJECT_TYPE_MISMATCH;\n        goto Exit;\n    }\n\n    *Length = info->DataLength;\n    *Buffer = info->Data;\n    buffer = NULL;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (buffer)\n    {\n        KphFree(buffer, KPH_TAG_REG_BINARY);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Frees a buffer retrieved by KphQueryRegistryBinary.\n *\n * \\param[in] String String to free.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeRegistryBinary(\n    _In_freesMem_ PBYTE Buffer\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphFree(CONTAINING_RECORD(Buffer, KEY_VALUE_PARTIAL_INFORMATION, Data),\n            KPH_TAG_REG_BINARY);\n}\n\n/**\n * \\brief Queries the registry key for a string value.\n *\n * \\param[in] KeyHandle Handle to key to query.\n * \\param[in] ValueName Name of value to query.\n * \\param[out] Value Registry unsigned long.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryRegistryULong(\n    _In_ HANDLE KeyHandle,\n    _In_ PCUNICODE_STRING ValueName,\n    _Out_ PULONG Value\n    )\n{\n    NTSTATUS status;\n    BYTE buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG64)];\n    ULONG resultLength;\n    PKEY_VALUE_PARTIAL_INFORMATION info;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    *Value = 0;\n\n    status = ZwQueryValueKey(KeyHandle,\n                             (PUNICODE_STRING)ValueName,\n                             KeyValuePartialInformation,\n                             buffer,\n                             ARRAYSIZE(buffer),\n                             &resultLength);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    if (resultLength < sizeof(KEY_VALUE_PARTIAL_INFORMATION))\n    {\n        return STATUS_INFO_LENGTH_MISMATCH;\n    }\n\n    info = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;\n\n#pragma prefast(suppress: 28199) // possibly uninitialized\n    if (info->Type != REG_DWORD)\n    {\n        return STATUS_OBJECT_TYPE_MISMATCH;\n    }\n\n    if (info->DataLength != sizeof(ULONG))\n    {\n        return STATUS_INFO_LENGTH_MISMATCH;\n    }\n\n    *Value = *(PULONG)info->Data;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Maps view into the system address space. The caller should unmap the\n * view by calling KphUnmapViewInSystem.\n *\n * \\param[in] FileHandle Handle to file to map.\n * \\param[in] Flags Options for the mapping (see: KPH_MAP..).\n * \\param[out] MappedBase Base address of the mapping.\n * \\param[out] ViewSize Size of the mapped view. If not an image mapping and\n * if the view exceeds the file size, it is clamped to the file size.\n *\n * \\return Successful or errant status.\n */\n_IRQL_always_function_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphMapViewInSystem(\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags,\n    _Outptr_result_bytebuffer_(*ViewSize) PVOID *MappedBase,\n    _Inout_ PSIZE_T ViewSize\n    )\n{\n    NTSTATUS status;\n    HANDLE sectionHandle;\n    PVOID sectionObject;\n    OBJECT_ATTRIBUTES objectAttributes;\n    ULONG allocationAttributes;\n    SIZE_T fileSize;\n    LARGE_INTEGER sectionOffset;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    sectionHandle = NULL;\n    sectionObject = NULL;\n    *MappedBase = NULL;\n\n    if (BooleanFlagOn(Flags, KPH_MAP_IMAGE))\n    {\n        allocationAttributes = SEC_IMAGE_NO_EXECUTE;\n        fileSize = SIZE_T_MAX;\n    }\n    else\n    {\n        IO_STATUS_BLOCK ioStatusBlock;\n        FILE_STANDARD_INFORMATION fileInfo;\n\n        allocationAttributes = SEC_COMMIT;\n\n        status = ZwQueryInformationFile(FileHandle,\n                                        &ioStatusBlock,\n                                        &fileInfo,\n                                        sizeof(FILE_STANDARD_INFORMATION),\n                                        FileStandardInformation);\n        if (!NT_SUCCESS(status))\n        {\n            goto Exit;\n        }\n\n        if (fileInfo.EndOfFile.QuadPart < 0)\n        {\n            status = STATUS_FILE_TOO_LARGE;\n            goto Exit;\n        }\n\n#ifdef _WIN64\n        fileSize = (SIZE_T)fileInfo.EndOfFile.QuadPart;\n#else\n        if (fileInfo.EndOfFile.HighPart != 0)\n        {\n            status = STATUS_FILE_TOO_LARGE;\n            goto Exit;\n        }\n        fileSize = fileInfo.EndOfFile.LowPart;\n#endif\n    }\n\n    InitializeObjectAttributes(&objectAttributes,\n                               NULL,\n                               OBJ_KERNEL_HANDLE,\n                               NULL,\n                               NULL);\n\n    status = ZwCreateSection(&sectionHandle,\n                             SECTION_MAP_READ,\n                             &objectAttributes,\n                             NULL,\n                             PAGE_READONLY,\n                             allocationAttributes,\n                             FileHandle);\n    if (!NT_SUCCESS(status))\n    {\n        sectionHandle = NULL;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(sectionHandle,\n                                       SECTION_MAP_READ,\n                                       *MmSectionObjectType,\n                                       KernelMode,\n                                       &sectionObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        sectionObject = NULL;\n        goto Exit;\n    }\n\n    sectionOffset.QuadPart = 0;\n    status = MmMapViewInSystemSpaceEx(sectionObject,\n                                      MappedBase,\n                                      ViewSize,\n                                      &sectionOffset,\n                                      MM_SYSTEM_VIEW_EXCEPTIONS_FOR_INPAGE_ERRORS);\n    if (!NT_SUCCESS(status))\n    {\n        *MappedBase = NULL;\n        *ViewSize = 0;\n        goto Exit;\n    }\n\n    if (*ViewSize > fileSize)\n    {\n        *ViewSize = fileSize;\n    }\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (sectionObject)\n    {\n        ObDereferenceObject(sectionObject);\n    }\n\n    if (sectionHandle)\n    {\n        ObCloseHandle(sectionHandle, KernelMode);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Unmaps view from the system process address space.\n *\n * \\param[in] MappedBase Base address of the mapping.\n */\n_IRQL_always_function_max_(PASSIVE_LEVEL)\nVOID KphUnmapViewInSystem(\n    _In_ PVOID MappedBase\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    MmUnmapViewInSystemSpace(MappedBase);\n}\n\n/**\n * \\brief Gets the file name from a file object.\n *\n * \\param[in] FileObject The file object to get the name from.\n * \\param[out] FileName Set to a point to the file name on success, caller\n * should free this using KphFreeFileNameObject.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetNameFileObject(\n    _In_ PFILE_OBJECT FileObject,\n    _Outptr_allocatesMem_ PUNICODE_STRING* FileName\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    POBJECT_NAME_INFORMATION nameInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    *FileName = NULL;\n\n    returnLength = (sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH);\n    nameInfo = KphAllocatePaged(returnLength, KPH_TAG_FILE_OBJECT_NAME);\n    if (!nameInfo)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"Failed to allocate for file object name.\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = KphQueryNameFileObject(FileObject,\n                                    nameInfo,\n                                    returnLength,\n                                    &returnLength);\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        KphFree(nameInfo, KPH_TAG_FILE_OBJECT_NAME);\n        nameInfo = KphAllocatePaged(returnLength, KPH_TAG_FILE_OBJECT_NAME);\n        if (!nameInfo)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"Failed to allocate for file object name.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        status = KphQueryNameFileObject(FileObject,\n                                        nameInfo,\n                                        returnLength,\n                                        &returnLength);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"KphQueryNameFileObject failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    *FileName = &nameInfo->Name;\n    nameInfo = NULL;\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (nameInfo)\n    {\n        KphFree(nameInfo, KPH_TAG_FILE_OBJECT_NAME);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Frees a file name previously retrieved by KphGetFileNameObject.\n *\n * \\param[out] FileName The file name to free.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeNameFileObject(\n    _In_freesMem_ PUNICODE_STRING FileName\n    )\n{\n    KPH_PAGED_CODE();\n\n    KphFree(CONTAINING_RECORD(FileName, OBJECT_NAME_INFORMATION, Name),\n            KPH_TAG_FILE_OBJECT_NAME);\n}\n\n/**\n * \\brief Perform a single privilege check on the supplied subject context.\n *\n * \\param[in] PrivilegeValue The privilege value to check.\n * \\param[in] SubjectSecurityContext The subject context to check.\n * \\param[in] AccessMode The access mode used for the access check.\n *\n * \\return TRUE if the subject has the desired privilege, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\nBOOLEAN KphSinglePrivilegeCheckEx(\n    _In_ LUID PrivilegeValue,\n    _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    PRIVILEGE_SET requiredPrivileges;\n\n    KPH_PAGED_CODE();\n\n    requiredPrivileges.PrivilegeCount = 1;\n    requiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY;\n    requiredPrivileges.Privilege[0].Luid = PrivilegeValue;\n    requiredPrivileges.Privilege[0].Attributes = 0;\n\n    return SePrivilegeCheck(&requiredPrivileges,\n                            SubjectSecurityContext,\n                            AccessMode);\n}\n\n/**\n * \\brief Perform a single privilege check on the current subject context.\n *\n * \\param[in] PrivilegeValue The privilege value to check.\n * \\param[in] AccessMode The access mode used for the access check.\n *\n * \\return TRUE if the subject has the desired privilege, FALSE otherwise.\n */\n_IRQL_requires_max_(APC_LEVEL)\nBOOLEAN KphSinglePrivilegeCheck(\n    _In_ LUID PrivilegeValue,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    BOOLEAN accessGranted;\n    SECURITY_SUBJECT_CONTEXT subjectContext;\n\n    KPH_PAGED_CODE();\n\n    SeCaptureSubjectContext(&subjectContext);\n\n    accessGranted = KphSinglePrivilegeCheckEx(PrivilegeValue,\n                                              &subjectContext,\n                                              AccessMode);\n\n    SeReleaseSubjectContext(&subjectContext);\n\n    return accessGranted;\n}\n\n/**\n * \\brief Retrieves the kernel file name.\n *\n * \\param[out] FileName On success set to the file name for the kernel. Must be\n * freed using RtlFreeUnicodeString.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpGetKernelFileName(\n    _Out_allocatesMem_ PUNICODE_STRING FileName\n    )\n{\n    NTSTATUS status;\n    SYSTEM_SINGLE_MODULE_INFORMATION info;\n    ANSI_STRING fullPathName;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlZeroMemory(FileName, sizeof(UNICODE_STRING));\n\n    RtlZeroMemory(&info, sizeof(SYSTEM_SINGLE_MODULE_INFORMATION));\n\n    info.TargetModuleAddress = (PVOID)ObCloseHandle;\n    status = ZwQuerySystemInformation(SystemSingleModuleInformation,\n                                      &info,\n                                      sizeof(SYSTEM_SINGLE_MODULE_INFORMATION),\n                                      NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"ZwQuerySystemInformation failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    status = RtlInitAnsiStringEx(&fullPathName,\n                                 (PCSZ)info.ExInfo.BaseInfo.FullPathName);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    return RtlAnsiStringToUnicodeString(FileName, &fullPathName, TRUE);\n}\n\n/**\n * \\brief Retrieves the version of the kernel.\n *\n * \\param[out] Version Set to the kernel build version.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetKernelVersion(\n    _Out_ PKPH_FILE_VERSION Version\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING kernelFileName;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = KphpGetKernelFileName(&kernelFileName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"KphGetKernelFileName failed: %!STATUS!\",\n                      status);\n\n        RtlZeroMemory(Version, sizeof(KPH_FILE_VERSION));\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_INFORMATION,\n                  UTIL,\n                  \"Kernel file name: \\\"%wZ\\\"\",\n                  &kernelFileName);\n\n    status = KphGetFileVersion(&kernelFileName, Version);\n\nExit:\n\n    RtlFreeUnicodeString(&kernelFileName);\n\n    return status;\n}\n\n/**\n * \\brief Retrieves the file version from a mapped file.\n *\n * \\param[in] ImageBase The base address of the mapped file.\n * \\param[in] ViewSize The size of the mapped file.\n * \\param[in] ResourceLanguage The language of the resource to locate.\n * \\param[out] Version Set to the file version.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpParseFileVersion(\n    _In_ PVOID ImageBase,\n    _In_ SIZE_T ViewSize,\n    _In_ ULONG_PTR ResourceLanguage,\n    _Out_ PKPH_FILE_VERSION Version\n    )\n{\n    NTSTATUS status;\n    LDR_RESOURCE_INFO resourceInfo;\n    PIMAGE_RESOURCE_DATA_ENTRY resourceData;\n    PVOID resourceBuffer;\n    ULONG resourceLength;\n    PVOID imageEnd;\n    PVS_VERSION_INFO_STRUCT versionInfo;\n    UNICODE_STRING keyName;\n    PVS_FIXEDFILEINFO fileInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlZeroMemory(Version, sizeof(KPH_FILE_VERSION));\n\n    resourceInfo.Type = (ULONG_PTR)VS_FILE_INFO;\n    resourceInfo.Name = (ULONG_PTR)MAKEINTRESOURCEW(VS_VERSION_INFO);\n    resourceInfo.Language = ResourceLanguage;\n\n    __try\n    {\n        status = LdrFindResource_U(ImageBase,\n                                   &resourceInfo,\n                                   RESOURCE_DATA_LEVEL,\n                                   &resourceData);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"LdrFindResource_U failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        status = LdrAccessResource(ImageBase,\n                                   resourceData,\n                                   &resourceBuffer,\n                                   &resourceLength);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"LdrAccessResource failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        imageEnd = Add2Ptr(ImageBase, ViewSize);\n\n        if (Add2Ptr(resourceBuffer, resourceLength) >= imageEnd)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"Resource buffer overflows mapping\");\n\n            status = STATUS_BUFFER_OVERFLOW;\n            goto Exit;\n        }\n\n        if (resourceLength < sizeof(VS_VERSION_INFO_STRUCT))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"Resource length insufficient\");\n\n            status = STATUS_BUFFER_TOO_SMALL;\n            goto Exit;\n        }\n\n        versionInfo = resourceBuffer;\n\n        if (Add2Ptr(resourceBuffer, versionInfo->Length) >= imageEnd)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"Version info overflows mapping\");\n\n            status = STATUS_BUFFER_OVERFLOW;\n            goto Exit;\n        }\n\n        if (versionInfo->ValueLength < sizeof(VS_FIXEDFILEINFO))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"Value length insufficient\");\n\n            status = STATUS_BUFFER_TOO_SMALL;\n            goto Exit;\n        }\n\n        status = RtlInitUnicodeStringEx(&keyName, versionInfo->Key);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"RtlInitUnicodeStringEx failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        fileInfo = Add2Ptr(versionInfo, RTL_SIZEOF_THROUGH_FIELD(VS_VERSION_INFO_STRUCT, Type));\n        fileInfo = (PVS_FIXEDFILEINFO)ALIGN_UP(Add2Ptr(fileInfo, keyName.MaximumLength), ULONG);\n\n        if (Add2Ptr(fileInfo, sizeof(VS_FIXEDFILEINFO)) >= imageEnd)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"File version info overflows mapping\");\n\n            status = STATUS_BUFFER_TOO_SMALL;\n            goto Exit;\n        }\n\n        if (fileInfo->dwSignature != VS_FFI_SIGNATURE)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"Invalid file version information signature (0x%08x)\",\n                          fileInfo->dwSignature);\n\n            status = STATUS_INVALID_SIGNATURE;\n            goto Exit;\n        }\n\n        if (fileInfo->dwStrucVersion != 0x10000)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          UTIL,\n                          \"Unknown file version information structure (0x%08x)\",\n                          fileInfo->dwStrucVersion);\n\n            status = STATUS_REVISION_MISMATCH;\n            goto Exit;\n        }\n\n        Version->MajorVersion = HIWORD(fileInfo->dwFileVersionMS);\n        Version->MinorVersion = LOWORD(fileInfo->dwFileVersionMS);\n        Version->BuildNumber = HIWORD(fileInfo->dwFileVersionLS);\n        Version->Revision = LOWORD(fileInfo->dwFileVersionLS);\n        status = STATUS_SUCCESS;\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        RtlZeroMemory(Version, sizeof(KPH_FILE_VERSION));\n        status = GetExceptionCode();\n    }\n\nExit:\n\n    return status;\n}\n\n/**\n * \\brief Retrieves the file version from a file.\n *\n * \\param[in] FileName The name of the file to get the version from.\n * \\param[out] Version Set to the file version.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetFileVersion(\n    _In_ PCUNICODE_STRING FileName,\n    _Out_ PKPH_FILE_VERSION Version\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE fileHandle;\n    IO_STATUS_BLOCK ioStatusBlock;\n    PVOID imageBase;\n    SIZE_T imageSize;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    RtlZeroMemory(Version, sizeof(KPH_FILE_VERSION));\n\n    imageBase = NULL;\n    fileHandle = NULL;\n\n    InitializeObjectAttributes(&objectAttributes,\n                               (PUNICODE_STRING)FileName,\n                               OBJ_KERNEL_HANDLE,\n                               NULL,\n                               NULL);\n\n    status = KphCreateFile(&fileHandle,\n                           FILE_READ_ACCESS | SYNCHRONIZE,\n                           &objectAttributes,\n                           &ioStatusBlock,\n                           NULL,\n                           FILE_ATTRIBUTE_NORMAL,\n                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n                           FILE_OPEN,\n                           FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n                           NULL,\n                           0,\n                           IO_IGNORE_SHARE_ACCESS_CHECK,\n                           KernelMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"KphCreateFile failed: %!STATUS!\",\n                      status);\n\n        fileHandle = NULL;\n        goto Exit;\n    }\n\n    imageSize = 0;\n    status = KphMapViewInSystem(fileHandle,\n                                KPH_MAP_IMAGE,\n                                &imageBase,\n                                &imageSize);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"KphMapViewInSystem failed: %!STATUS!\",\n                      status);\n\n        imageBase = NULL;\n        goto Exit;\n    }\n\n    status = KphpParseFileVersion(imageBase,\n                                  imageSize,\n                                  MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),\n                                  Version);\n    if (NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  UTIL,\n                  \"KphpParseFileVersion failed: %!STATUS!\",\n                  status);\n\n    //\n    // Try again with a neutral sub language.\n    //\n\n    status = KphpParseFileVersion(imageBase,\n                                  imageSize,\n                                  MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),\n                                  Version);\n    if (NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  UTIL,\n                  \"KphpParseFileVersion failed: %!STATUS!\",\n                  status);\n\n    //\n    // Try again with neutral language and sub language.\n    //\n\n    status = KphpParseFileVersion(imageBase,\n                                  imageSize,\n                                  MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),\n                                  Version);\n    if (NT_SUCCESS(status))\n    {\n        goto Exit;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  UTIL,\n                  \"KphpParseFileVersion failed: %!STATUS!\",\n                  status);\n\nExit:\n\n    if (imageBase)\n    {\n        KphUnmapViewInSystem(imageBase);\n    }\n\n    if (fileHandle)\n    {\n        ObCloseHandle(fileHandle, KernelMode);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Sets CFG call target information for a process.\n *\n * \\param[in] ProcessHandle Handle to the process to configure CFG for.\n * \\param[in] VirtualAddress Virtual address to configure CFG for.\n * \\param[in] Flags CFG call target flags (CFG_CALL_TARGET_).\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpSetCfgCallTargetInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress,\n    _In_ ULONG Flags\n    )\n{\n    MEMORY_RANGE_ENTRY memoryRange;\n    CFG_CALL_TARGET_INFO targetInfo;\n    CFG_CALL_TARGET_LIST_INFORMATION targetListInfo;\n    ULONG numberOfEntriesProcessed;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n#ifdef _WIN64\n    C_ASSERT(sizeof(CFG_CALL_TARGET_INFO) == 16);\n    C_ASSERT(sizeof(CFG_CALL_TARGET_LIST_INFORMATION) == 40);\n#endif\n\n    memoryRange.VirtualAddress = PAGE_ALIGN(VirtualAddress);\n    memoryRange.NumberOfBytes = PAGE_SIZE;\n\n    targetInfo.Offset = BYTE_OFFSET(VirtualAddress);\n    targetInfo.Flags = Flags;\n\n    numberOfEntriesProcessed = 0;\n\n    RtlZeroMemory(&targetListInfo, sizeof(CFG_CALL_TARGET_LIST_INFORMATION));\n    targetListInfo.NumberOfEntries = 1;\n    targetListInfo.NumberOfEntriesProcessed = &numberOfEntriesProcessed;\n    targetListInfo.CallTargetInfo = &targetInfo;\n\n    return ZwSetInformationVirtualMemory(ProcessHandle,\n                                         VmCfgCallTargetInformation,\n                                         1,\n                                         &memoryRange,\n                                         &targetListInfo,\n                                         sizeof(CFG_CALL_TARGET_LIST_INFORMATION));\n}\n\n/**\n * \\brief Grants a suppressed call access to a target.\n *\n * \\param[in] ProcessHandle Handle to the process to configure CFG for.\n * \\param[in] VirtualAddress Virtual address of the target.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGuardGrantSuppressedCallAccess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress\n    )\n{\n    ULONG flags;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    flags = CFG_CALL_TARGET_CONVERT_EXPORT_SUPPRESSED_TO_VALID;\n\n    return KphpSetCfgCallTargetInformation(ProcessHandle,\n                                           VirtualAddress,\n                                           flags);\n}\n\n/**\n * \\brief Disables XFG on a target.\n *\n * \\param[in] ProcessHandle Handle to the process to configure CFG for.\n * \\param[in] VirtualAddress Virtual address of the target.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDisableXfgOnTarget(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress\n    )\n{\n    ULONG flags;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    flags = CFG_CALL_TARGET_CONVERT_XFG_TO_CFG;\n\n    return KphpSetCfgCallTargetInformation(ProcessHandle,\n                                           VirtualAddress,\n                                           flags);\n}\n\n/**\n * \\brief Gets the final component of a file name.\n *\n * \\details The final component is the last part of the file name, e.g. for\n * \"\\SystemRoot\\System32\\ntoskrnl.exe\" it would be \"ntoskrnl.exe\". Returns an\n * error if the final component is not found.\n *\n * \\param[in] FileName File name to get the final component of.\n * \\param[out] FinalComponent Final component of the file name, references\n * input string, this string should not be freed and the input string must\n * remain valid as long as this is in use.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetFileNameFinalComponent(\n    _In_ PCUNICODE_STRING FileName,\n    _Out_ PUNICODE_STRING FinalComponent\n    )\n{\n    KPH_PAGED_CODE();\n\n    for (USHORT i = (FileName->Length / sizeof(WCHAR)); i > 0; i--)\n    {\n        if (FileName->Buffer[i - 1] == OBJ_NAME_PATH_SEPARATOR)\n        {\n            FinalComponent->Buffer = &FileName->Buffer[i];\n            FinalComponent->Length = FileName->Length - (i * sizeof(WCHAR));\n            FinalComponent->MaximumLength = FinalComponent->Length;\n\n            return STATUS_SUCCESS;\n        }\n    }\n\n    RtlZeroMemory(FinalComponent, sizeof(*FinalComponent));\n\n    return STATUS_NOT_FOUND;\n}\n\n/**\n * \\brief Gets the image name from a process.\n *\n * \\param[in] Process The process to get the image name from.\n * \\param[out] ImageName Populated with the image name of the process, this\n * string should be freed using KphFreeProcessImageName.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetProcessImageName(\n    _In_ PEPROCESS Process,\n    _Out_allocatesMem_ PUNICODE_STRING ImageName\n    )\n{\n    NTSTATUS status;\n    PUCHAR fileName;\n    SIZE_T len;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    fileName = PsGetProcessImageFileName(Process);\n\n    status = RtlStringCbLengthA((STRSAFE_PCNZCH)fileName, 15, &len);\n    if (NT_SUCCESS(status))\n    {\n        ANSI_STRING string;\n\n        string.Buffer = (PCHAR)fileName;\n        string.Length = (USHORT)len;\n        string.MaximumLength = string.Length;\n\n        status = RtlAnsiStringToUnicodeString(ImageName, &string, TRUE);\n        if (NT_SUCCESS(status))\n        {\n            return status;\n        }\n    }\n\n    RtlZeroMemory(ImageName, sizeof(*ImageName));\n\n    return status;\n}\n\n/**\n * \\brief Frees a process image file name from KphGetProcessImageName.\n *\n * \\param[in] ImageName The image name to free.\n */\n_IRQL_requires_max_(APC_LEVEL)\nVOID KphFreeProcessImageName(\n    _In_freesMem_ PUNICODE_STRING ImageName\n    )\n{\n    KPH_PAGED_CODE();\n\n#pragma prefast(suppress : 28121) // SAL is incorrect in wdm.h\n    RtlFreeUnicodeString(ImageName);\n}\n\n/**\n * \\brief Opens the driver parameters key.\n *\n * \\param[in] RegistryPath Registry path from the entry point.\n * \\param[out] KeyHandle Handle to parameters key on success, null on failure.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphOpenParametersKey(\n    _In_ PCUNICODE_STRING RegistryPath,\n    _Out_ PHANDLE KeyHandle\n    )\n{\n    NTSTATUS status;\n    WCHAR buffer[MAX_PATH];\n    UNICODE_STRING parametersKeyName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    *KeyHandle = NULL;\n\n    parametersKeyName.Buffer = buffer;\n    parametersKeyName.Length = 0;\n    parametersKeyName.MaximumLength = sizeof(buffer);\n\n    status = RtlAppendUnicodeStringToString(&parametersKeyName, RegistryPath);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    status = RtlAppendUnicodeToString(&parametersKeyName, L\"\\\\Parameters\");\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    InitializeObjectAttributes(&objectAttributes,\n                               &parametersKeyName,\n                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\n                               NULL,\n                               NULL);\n\n    status = ZwOpenKey(KeyHandle, KEY_READ, &objectAttributes);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      UTIL,\n                      \"Unable to open Parameters key: %!STATUS!\",\n                      status);\n\n        *KeyHandle = NULL;\n        return status;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Performs a domination check between a calling process and a target\n * process.\n *\n * \\details A process dominates the other when the protected level of the\n * process exceeds the other. This domination check is not ideal, it is overly\n * strict and lacks enough information from the kernel to fully understand the\n * protected process state.\n *\n * \\param[in] Process The calling process.\n * \\param[in] ProcessTarget Target process to check against the caller.\n * \\param[in] AccessMode Access mode of the request.\n *\n * \\return Appropriate status:\n * STATUS_SUCCESS The calling process dominates the target.\n * STATUS_ACCESS_DENIED The calling process does not dominate the target.\n*/\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDominationCheck(\n    _In_ PEPROCESS Process,\n    _In_ PEPROCESS ProcessTarget,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    PS_PROTECTION processProtection;\n    PS_PROTECTION targetProtection;\n\n    KPH_PAGED_CODE();\n\n    if (AccessMode == KernelMode)\n    {\n        //\n        // Give the kernel what it wants...\n        //\n        return STATUS_SUCCESS;\n    }\n\n    //\n    // Until Microsoft gives us more insight into protected process domination\n    // we'll do a very strict check here:\n    //\n\n    processProtection = PsGetProcessProtection(Process);\n    targetProtection = PsGetProcessProtection(ProcessTarget);\n\n    if ((targetProtection.Type != PsProtectedTypeNone) &&\n        (targetProtection.Type >= processProtection.Type))\n    {\n        //\n        // Calling process protection does not dominate the other, deny access.\n        // We could do our own domination check/mapping here with the signing\n        // level, but it won't be great and Microsoft might change it, so we'll\n        // do this strict check until Microsoft exports:\n        // PsTestProtectedProcessIncompatibility\n        // RtlProtectedAccess/RtlTestProtectedAccess\n        //\n        return STATUS_ACCESS_DENIED;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Performs a domination and privilege check to verify that the calling\n * thread has the required privilege to perform the action.\n *\n * \\details This function replaces a call to KphDominationCheck in certain\n * paths. It grants access to a protected process *only* if the calling thread\n * or associated process has been granted permission to do so. Session tokens\n * implement an expiring token validated using asymmetric keys. This involves\n * verification coordinated between the driver, client, and server which\n * requires end user authentication and may be audited or revoked at any time.\n * This feature is a service similar to those provided by various security\n * or system management focused products. System Informer provides this service\n * to users in this same light. System Informer provides security and system\n * management capabilities to users.\n *\n * \\param[in] Privileges The specific privileges to be checked.\n * \\param[in] Thread The calling thread.\n * \\param[in] ProcessTarget Target process to check against the caller.\n * \\param[in] AccessMode Describes the access mode of the request.\n *\n * \\return Appropriate status:\n * STATUS_SUCCESS The calling thread or process is granted access.\n * STATUS_ACCESS_DENIED The calling process does not dominate the target.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphDominationAndPrivilegeCheck(\n    _In_ ULONG Privileges,\n    _In_ PETHREAD Thread,\n    _In_ PEPROCESS ProcessTarget,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    BOOLEAN granted;\n    PKPH_THREAD_CONTEXT thread;\n\n    KPH_PAGED_CODE();\n\n    if (AccessMode == KernelMode)\n    {\n        return STATUS_SUCCESS;\n    }\n\n    granted = FALSE;\n\n    thread = KphGetEThreadContext(Thread);\n    if (thread)\n    {\n        granted = KphSessionTokenPrivilegeCheck(thread, Privileges);\n\n        KphDereferenceObject(thread);\n    }\n\n    if (granted)\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return KphDominationCheck(PsGetThreadProcess(Thread),\n                              ProcessTarget,\n                              AccessMode);\n}\n\n/**\n * \\brief Retrieves the signing level of a file object.\n *\n * \\param[in] FileObject The file object to query.\n * \\param[out] SigningLevel Receives the signing level of the file object.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphGetSigningLevel(\n    _In_ PFILE_OBJECT FileObject,\n    _Out_ PSE_SIGNING_LEVEL SigningLevel\n    )\n{\n    NTSTATUS status;\n    ULONG flags;\n    MINCRYPT_POLICY_INFO policyInfo;\n    MINCRYPT_POLICY_INFO timeStampPolicyInfo;\n    LARGE_INTEGER signingTime;\n    UCHAR thumbprint[MINCRYPT_MAX_HASH_LEN];\n    ULONG thumbprintSize;\n    ULONG thumbprintAlgorithm;\n    ANSI_STRING issuer;\n    ANSI_STRING subject;\n    BOOLEAN microsoftSigned;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = SeGetCachedSigningLevel(FileObject,\n                                     &flags,\n                                     SigningLevel,\n                                     NULL,\n                                     NULL,\n                                     NULL);\n    if (NT_SUCCESS(status) && (*SigningLevel != SE_SIGNING_LEVEL_UNCHECKED))\n    {\n        return status;\n    }\n\n    //\n    // Invoke CI to update the cache.\n    //\n\n    if (!KphDynCiValidateFileObject || !KphDynCiFreePolicyInfo)\n    {\n        return STATUS_NOINTERFACE;\n    }\n\n    RtlZeroMemory(&policyInfo, sizeof(MINCRYPT_POLICY_INFO));\n    RtlZeroMemory(&timeStampPolicyInfo, sizeof(MINCRYPT_POLICY_INFO));\n    thumbprintSize = sizeof(thumbprint);\n    thumbprintAlgorithm = 0;\n\n    status = KphDynCiValidateFileObject(FileObject,\n                                        CI_POLICY_ACCEPT_ANY_ROOT_CERTIFICATE,\n                                        SE_SIGNING_LEVEL_UNCHECKED,\n                                        &policyInfo,\n                                        &timeStampPolicyInfo,\n                                        &signingTime,\n                                        thumbprint,\n                                        &thumbprintSize,\n                                        &thumbprintAlgorithm);\n\n    if (policyInfo.ChainInfo &&\n        RTL_CONTAINS_FIELD(policyInfo.ChainInfo, policyInfo.ChainInfo->Size, ChainElements) &&\n        policyInfo.ChainInfo->ChainElements &&\n        policyInfo.ChainInfo->NumberOfChainElements)\n    {\n        issuer.Buffer = policyInfo.ChainInfo->ChainElements[0].Issuer.Buffer;\n        issuer.Length = policyInfo.ChainInfo->ChainElements[0].Issuer.Length;\n        issuer.MaximumLength = issuer.Length;\n\n        subject.Buffer = policyInfo.ChainInfo->ChainElements[0].Subject.Buffer;\n        subject.Length = policyInfo.ChainInfo->ChainElements[0].Subject.Length;\n        subject.MaximumLength = subject.Length;\n    }\n    else\n    {\n        RtlZeroMemory(&issuer, sizeof(ANSI_STRING));\n        RtlZeroMemory(&subject, sizeof(ANSI_STRING));\n    }\n\n    if (!NT_SUCCESS(status) ||\n        !NT_SUCCESS(policyInfo.VerificationStatus) ||\n        BooleanFlagOn(policyInfo.PolicyBits,\n                      (MINCRYPT_POLICY_ERROR_FLAGS |\n                       MINCRYPT_POLICY_3RD_PARTY_ROOT |\n                       MINCRYPT_POLICY_NO_ROOT |\n                       MINCRYPT_POLICY_OTHER_ROOT)))\n    {\n        microsoftSigned = FALSE;\n    }\n    else\n    {\n        microsoftSigned = TRUE;\n    }\n\n    KphTracePrint(TRACE_LEVEL_VERBOSE,\n                  UTIL,\n                  \"CiValidateFileObject: \\\"%wZ\\\" 0x%08lx \\\"%Z\\\" \\\"%Z\\\" \"\n                  \"%!STATUS! %!STATUS!\",\n                  &FileObject->FileName,\n                  policyInfo.PolicyBits,\n                  &subject,\n                  &issuer,\n                  policyInfo.VerificationStatus,\n                  status);\n\n    KphDynCiFreePolicyInfo(&policyInfo);\n    KphDynCiFreePolicyInfo(&timeStampPolicyInfo);\n\n    status = SeGetCachedSigningLevel(FileObject,\n                                     &flags,\n                                     SigningLevel,\n                                     NULL,\n                                     NULL,\n                                     NULL);\n    if (NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    //\n    // Caching of the signing level failed. If CI tells us this is Microsoft\n    // signed then we'll return that, otherwise return the errant status.\n    //\n\n    if (microsoftSigned)\n    {\n        *SigningLevel = SE_SIGNING_LEVEL_MICROSOFT;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *SigningLevel = SE_SIGNING_LEVEL_UNCHECKED;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Retrieves image headers from a mapped image.\n *\n * \\details Extends RtlImageNtHeaderEx and verifies that the optional headers\n * are within the region. The caller should still check that the optional\n * headers contains a given field with RTL_CONTAINS_FIELD.\n *\n * \\param[in] Base The base address of the image.\n * \\param[in] Size The size of the image.\n * \\param[out] Headers Receives the image headers.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(APC_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphImageNtHeader(\n    _In_ PVOID Base,\n    _In_ ULONG64 Size,\n    _Out_ PKPH_IMAGE_NT_HEADERS Headers\n    )\n{\n    NTSTATUS status;\n    ULONG64 size;\n\n    KPH_PAGED_CODE();\n\n    status = RtlImageNtHeaderEx(0, Base, Size, &Headers->Headers);\n    if (!NT_SUCCESS(status))\n    {\n        Headers->Headers = NULL;\n        return status;\n    }\n\n    size = PtrOffset(Base, Headers->Headers);\n    size += RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS, FileHeader);\n    size += Headers->Headers->FileHeader.SizeOfOptionalHeader;\n\n    if (size > Size)\n    {\n        Headers->Headers = NULL;\n        return STATUS_INVALID_IMAGE_FORMAT;\n    }\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "KSystemInformer/verify.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     jxy-s   2020-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\n#define KPH_KEY_MATERIAL_SIZE        ((ULONG)0x21B)\n#define KPH_KEY_ALG_HANDLE           BCRYPT_RSA_ALG_HANDLE\n#define KPH_KEY_ALGORITHM            BCRYPT_RSA_ALGORITHM\n#define KPH_KEY_HASH_ALGORITHM       BCRYPT_SHA512_ALGORITHM\n#define KPH_KEY_HASH_ALGORITHM_BYTES (512 / 8)\n#define KPH_KEY_BLOB_PUBLIC          BCRYPT_RSAPUBLIC_BLOB\n#define KPH_KEY_PADDING_FLAGS        BCRYPT_PAD_PSS\n#define KPH_KEY_PADDING_INFO         (PVOID)&KphpKeyPaddingInfo\n\n#define KPH_VERIFY_SIGNATURE_MAX_LENGTH 1024\n\ntypedef enum _KPH_KEY_TYPE\n{\n    KphKeyTypeTest,\n    KphKeyTypeProd,\n} KPH_KEY_TYPE, *PKPH_KEY_TYPE;\n\ntypedef struct _KPH_KEY\n{\n    KPH_KEY_TYPE Type;\n    BYTE Material[KPH_KEY_MATERIAL_SIZE];\n} KPH_KEY, *PKPH_KEY;\ntypedef const KPH_KEY* PCKPH_KEY;\n\nKPH_PROTECTED_DATA_SECTION_RO_PUSH();\nstatic const KPH_KEY KphpPublicKeys[] =\n{\n    {\n        KphKeyTypeProd, // kph\n        {\n            0x52, 0x53, 0x41, 0x31, 0x00, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n            0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x00, 0x01, 0xE5, 0xF2, 0xEF, 0xE0, 0xE0, 0x02, 0x05, 0xEA, 0x55,\n            0xF8, 0x4C, 0x26, 0xED, 0xF9, 0x55, 0xE3, 0xBD, 0x38, 0x06, 0x5D, 0xF6,\n            0x26, 0xA4, 0xFF, 0x69, 0xFC, 0x4D, 0x8C, 0x02, 0x7E, 0x82, 0x96, 0x3D,\n            0x90, 0xE8, 0xB7, 0xEB, 0x1A, 0xE3, 0x02, 0x57, 0x0F, 0x1C, 0xE9, 0x93,\n            0xD0, 0x61, 0xFC, 0x75, 0xF1, 0xF3, 0xC6, 0x49, 0xF9, 0xBC, 0x39, 0x6F,\n            0x80, 0x40, 0xC3, 0xF9, 0xB3, 0xDC, 0xFD, 0x21, 0x28, 0x25, 0x1B, 0x91,\n            0x42, 0xB0, 0x29, 0xA4, 0x76, 0x4D, 0x71, 0x4D, 0x38, 0x3C, 0x9F, 0x80,\n            0xD9, 0x11, 0xFD, 0xD5, 0x80, 0xB1, 0xFC, 0xB9, 0xC8, 0xCB, 0xE4, 0x6C,\n            0x1A, 0x11, 0x8E, 0xE4, 0x9D, 0x3C, 0x24, 0x58, 0x70, 0x64, 0x88, 0x08,\n            0x53, 0x7F, 0x8A, 0x30, 0x67, 0x59, 0x91, 0x2E, 0x77, 0xD5, 0x1F, 0x21,\n            0x9C, 0x8E, 0x7B, 0x5E, 0xC0, 0x3E, 0x52, 0x26, 0x69, 0x0F, 0x95, 0x14,\n            0x72, 0xE5, 0xE9, 0xA2, 0xF7, 0xFC, 0x22, 0x43, 0xB5, 0x1A, 0xB1, 0xDB,\n            0x01, 0xC4, 0x6A, 0x13, 0x99, 0xBE, 0x0F, 0x82, 0x59, 0xC8, 0x8F, 0xCA,\n            0xF2, 0x86, 0x54, 0x34, 0xF5, 0x4D, 0xD9, 0xD2, 0xA7, 0x4A, 0xDF, 0x94,\n            0x9E, 0x13, 0x53, 0xEA, 0xD0, 0x98, 0xB1, 0x15, 0x2D, 0x59, 0xD7, 0xFF,\n            0x9B, 0x9C, 0x78, 0x81, 0xDE, 0x90, 0xAF, 0x7E, 0xF4, 0x7D, 0x14, 0xAC,\n            0x40, 0x46, 0x13, 0x45, 0x16, 0x0A, 0x22, 0x51, 0xEC, 0x4F, 0x4F, 0xCF,\n            0x63, 0x0F, 0x6B, 0xF3, 0xFC, 0x7C, 0x85, 0x1C, 0x1E, 0xBB, 0xF1, 0x80,\n            0x34, 0x9F, 0x13, 0x57, 0xB5, 0x02, 0x37, 0xF6, 0xE5, 0x3A, 0x77, 0x90,\n            0x1B, 0xB7, 0x6E, 0xA9, 0xA3, 0xF1, 0x33, 0xE2, 0xC7, 0xD8, 0xFF, 0x82,\n            0x44, 0x0E, 0x28, 0x30, 0xD6, 0x25, 0x7D, 0x71, 0x4A, 0x68, 0x1C, 0xCD,\n            0x70, 0x6F, 0xB0, 0x64, 0x46, 0x0E, 0xE0, 0x1D, 0x30, 0x79, 0xE6, 0x69,\n            0x6D, 0x47, 0xF7, 0xEB, 0x09, 0x96, 0x30, 0x40, 0xEF, 0x5C, 0x62, 0xC0,\n            0x18, 0x36, 0xA4, 0x95, 0x85, 0x74, 0x91, 0x50, 0xFE, 0x6D, 0xE2, 0xD5,\n            0x52, 0xE4, 0x1F, 0x4A, 0x28, 0xB6, 0x9D, 0x5E, 0x34, 0xD5, 0x0C, 0x28,\n            0x4D, 0x49, 0xDD, 0x58, 0x40, 0x83, 0x84, 0xA4, 0x0E, 0x1D, 0xE6, 0xF5,\n            0xF0, 0x3B, 0x46, 0xAD, 0x2D, 0x64, 0xFA, 0xAC, 0x44, 0x95, 0x52, 0x31,\n            0x83, 0x43, 0x67, 0x65, 0x84, 0x74, 0xB3, 0xBD, 0x59, 0x2C, 0x13, 0x8A,\n            0x4B, 0xA2, 0xE2, 0x32, 0xF7, 0x42, 0xC6, 0xD6, 0x3D, 0x29, 0x39, 0x1D,\n            0x0F, 0xEC, 0x47, 0xA2, 0xBF, 0xED, 0x69, 0x6B, 0xEC, 0x45, 0x04, 0x32,\n            0x01, 0x8D, 0x50, 0x48, 0x8B, 0x9C, 0x8E, 0x1E, 0xFA, 0x11, 0x03, 0x87,\n            0x47, 0x23, 0x83, 0x98, 0x29, 0x2B, 0xB8, 0x76, 0xD3, 0x64, 0xE7, 0x8C,\n            0x22, 0xAE, 0x68, 0xA3, 0xC3, 0x58, 0xC0, 0xA0, 0xFE, 0x37, 0x90, 0x26,\n            0x27, 0x78, 0x4E, 0xC3, 0x63, 0x87, 0x3E, 0x20, 0xEF, 0x8A, 0xEA, 0x44,\n            0x1E, 0xCC, 0xAD, 0x1F, 0xFC, 0x05, 0x7B, 0x0A, 0x1B, 0x02, 0xFA, 0x1C,\n            0xEB, 0x5D, 0x81, 0x6B, 0x09, 0x2B, 0xDE, 0x49, 0x2A, 0xA6, 0xA1, 0x82,\n            0xE5, 0x08, 0xBF, 0x40, 0x6E, 0x67, 0x03, 0xAC, 0xB0, 0xDB, 0xB4, 0x9B,\n            0x66, 0x38, 0x78, 0x91, 0x79, 0x48, 0x54, 0xCE, 0xC5, 0x32, 0xAE, 0xAB,\n            0x35, 0x8B, 0x9C, 0xE9, 0x00, 0x42, 0xBE, 0x98, 0x2C, 0x00, 0x0F, 0x3C,\n            0xC7, 0x55, 0xA4, 0x45, 0x98, 0x7C, 0xE2, 0x5E, 0xFF, 0xC0, 0xEC, 0x97,\n            0x9C, 0x29, 0x5D, 0x65, 0x00, 0x68, 0x68, 0x97, 0x3B, 0x32, 0x4E, 0x39,\n            0x51, 0x95, 0x59, 0xA3, 0x81, 0xE5, 0xDC, 0xF0, 0xAF, 0x77, 0x34, 0x64,\n            0x6F, 0xD6, 0x88, 0x03, 0x23, 0xFB, 0x82, 0x62, 0x86, 0xFF, 0x59\n        }\n    },\n    {\n        KphKeyTypeTest, // kph-dev\n        {\n            0x52, 0x53, 0x41, 0x31, 0x00, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n            0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x00, 0x01, 0xAB, 0xDB, 0x39, 0x5E, 0xD1, 0xFA, 0x54, 0x35, 0xD7,\n            0x6B, 0x83, 0x62, 0x82, 0x06, 0xC7, 0x20, 0xDB, 0x05, 0x5E, 0x55, 0xF2,\n            0x3C, 0x6A, 0x52, 0x1F, 0x0B, 0xC6, 0xC2, 0xB4, 0x83, 0x13, 0xA9, 0xF2,\n            0xD6, 0xF7, 0x19, 0x99, 0xB5, 0xB3, 0x52, 0xE7, 0x54, 0x55, 0x17, 0x7F,\n            0xE3, 0xA6, 0x6B, 0xD6, 0xB7, 0xDA, 0x38, 0xC8, 0x44, 0xFF, 0x3F, 0x4A,\n            0x59, 0x0C, 0x3C, 0x45, 0xA3, 0x35, 0x8B, 0x34, 0x01, 0x82, 0xBD, 0x25,\n            0x9B, 0xAF, 0xFC, 0x56, 0x1F, 0x6E, 0xFE, 0xE2, 0xF5, 0xE1, 0x2D, 0xFB,\n            0x42, 0x41, 0x46, 0x48, 0x02, 0xEB, 0xEF, 0xEA, 0x41, 0x08, 0x8D, 0x58,\n            0xA5, 0x32, 0xFE, 0x8F, 0xE8, 0xBB, 0xF6, 0x36, 0xD9, 0x48, 0xC3, 0x2C,\n            0x30, 0x70, 0x57, 0xE0, 0x25, 0x1C, 0xA3, 0xE1, 0x72, 0x76, 0x48, 0xF9,\n            0x57, 0x8B, 0x50, 0x67, 0x27, 0x66, 0xD5, 0x70, 0x4F, 0x02, 0x94, 0x9F,\n            0xB3, 0xDE, 0x74, 0xF7, 0x7C, 0xD4, 0xEE, 0xFD, 0x95, 0x5D, 0x47, 0xF6,\n            0x0A, 0xDE, 0xA1, 0x76, 0x99, 0x52, 0x40, 0x0D, 0xB1, 0x63, 0x1C, 0x65,\n            0xA0, 0x04, 0xC8, 0x48, 0xE3, 0xC6, 0x3C, 0x6D, 0x26, 0x10, 0xB9, 0x22,\n            0x7D, 0x67, 0x5D, 0x81, 0x44, 0xAF, 0xE0, 0x85, 0xC3, 0xB3, 0x13, 0x27,\n            0xB8, 0xA3, 0xC2, 0x28, 0x2A, 0x57, 0xE2, 0xAE, 0x2D, 0xB7, 0x95, 0xC4,\n            0x13, 0x65, 0xB9, 0x5C, 0xF5, 0x29, 0x9D, 0x0E, 0x85, 0x37, 0x34, 0x34,\n            0xFF, 0x04, 0x17, 0x39, 0x0A, 0x5C, 0x31, 0xD8, 0x59, 0x11, 0xDA, 0x82,\n            0x1B, 0x18, 0x0C, 0x8E, 0x24, 0x24, 0x9B, 0x7F, 0x02, 0xB6, 0x5D, 0x31,\n            0x6D, 0xB5, 0x15, 0xB6, 0x54, 0x67, 0x1C, 0x6F, 0xF5, 0x2C, 0x42, 0x4B,\n            0x7F, 0x6F, 0xAC, 0xD7, 0x56, 0x8A, 0x18, 0xB7, 0x31, 0x02, 0x36, 0xF3,\n            0xB6, 0x8B, 0x47, 0x03, 0xFA, 0x84, 0xB5, 0x33, 0x90, 0xD7, 0x33, 0xF8,\n            0x32, 0x89, 0x7C, 0x0C, 0x31, 0xB8, 0xA3, 0xF3, 0xAF, 0x46, 0x3F, 0x77,\n            0x1A, 0x38, 0x8B, 0x82, 0xBD, 0x4A, 0xAD, 0x93, 0xC6, 0xFC, 0x24, 0x9F,\n            0xD4, 0xFF, 0xBB, 0x27, 0xE2, 0x6B, 0x5A, 0x99, 0x5F, 0x70, 0x08, 0xDB,\n            0xC9, 0x3A, 0xE8, 0x73, 0x87, 0x63, 0x09, 0x7F, 0x5D, 0x2A, 0x91, 0x24,\n            0xFA, 0xEE, 0x9D, 0xC5, 0x81, 0x97, 0x83, 0xC6, 0xD2, 0x6C, 0x5C, 0xFE,\n            0x45, 0x5A, 0xA4, 0xA9, 0x9C, 0xEA, 0xEF, 0x98, 0x52, 0xAE, 0x3A, 0xD0,\n            0x12, 0x54, 0x75, 0x9E, 0xD0, 0x1E, 0xF7, 0x9D, 0x03, 0x7E, 0xD5, 0x89,\n            0x3B, 0xE6, 0x87, 0x75, 0xB3, 0x7B, 0x7C, 0x45, 0x58, 0x1F, 0x8E, 0xE8,\n            0x59, 0x78, 0x54, 0xC3, 0xD5, 0x9B, 0x0F, 0xC7, 0x05, 0x34, 0xF2, 0x6C,\n            0xCF, 0x19, 0x40, 0x92, 0xDD, 0xF0, 0x1E, 0x5F, 0xA7, 0x04, 0xA2, 0x4D,\n            0x2E, 0x7C, 0x57, 0x43, 0x3C, 0xCC, 0xA0, 0x68, 0x0A, 0xEC, 0x47, 0x3D,\n            0x27, 0x16, 0x8C, 0x62, 0x33, 0x7F, 0x7D, 0x2D, 0xAA, 0x9D, 0x2F, 0x39,\n            0xF7, 0x44, 0xD7, 0x66, 0xE8, 0x1A, 0x38, 0x0C, 0x68, 0x9E, 0x37, 0x3E,\n            0x8F, 0xCF, 0x20, 0xBF, 0x9D, 0x3F, 0x4D, 0xA4, 0xFA, 0xFA, 0x67, 0xA8,\n            0xAD, 0xB5, 0x04, 0xFF, 0x29, 0x72, 0x4A, 0x87, 0xFD, 0x95, 0xC6, 0x1B,\n            0xE2, 0xA7, 0xB3, 0x7F, 0xC7, 0xCB, 0x4A, 0x5A, 0x7A, 0x02, 0x0B, 0x24,\n            0xBD, 0x27, 0xC1, 0xED, 0x94, 0x12, 0x5E, 0x7F, 0x45, 0x6E, 0xE5, 0x24,\n            0x38, 0x24, 0xA4, 0xF4, 0x93, 0xE6, 0xF6, 0x3F, 0x12, 0xD7, 0x9D, 0x2E,\n            0x15, 0xAC, 0x29, 0x2D, 0x83, 0xB2, 0x95, 0x5D, 0x7A, 0x1A, 0xCB, 0x9F,\n            0x23, 0xF3, 0x80, 0x3E, 0x8C, 0x72, 0x5F, 0x0F, 0xB2, 0x93, 0x1E, 0x15,\n            0xC5, 0xC0, 0x8B, 0xC3, 0xF8, 0x0A, 0xCA, 0x88, 0x07, 0x7F, 0x79\n        }\n    },\n    {\n        KphKeyTypeTest, // kph-test\n        {\n            0x52, 0x53, 0x41, 0x31, 0x00, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n            0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x00, 0x01, 0xC7, 0x95, 0x12, 0x92, 0x18, 0x6F, 0xA2, 0x01, 0x6C,\n            0x9A, 0x5F, 0xC1, 0x70, 0x7B, 0xF9, 0xE3, 0x57, 0x75, 0x28, 0x13, 0xC9,\n            0xBF, 0xBC, 0x93, 0xCD, 0x55, 0x5C, 0xA9, 0xC2, 0x80, 0x23, 0xA2, 0xEF,\n            0xF4, 0xB6, 0x3A, 0xBF, 0x6E, 0x39, 0xC6, 0x23, 0xC1, 0x3B, 0x04, 0xBE,\n            0xB5, 0x9B, 0x5C, 0x8A, 0x64, 0xAA, 0x7A, 0x1C, 0x20, 0x7E, 0x2D, 0x52,\n            0x55, 0xEC, 0x3E, 0x5C, 0x40, 0xD5, 0x76, 0xC8, 0x2F, 0xFF, 0x14, 0xD7,\n            0xA1, 0xE7, 0x1D, 0xF1, 0x3C, 0x73, 0x89, 0x6B, 0xF5, 0xA4, 0xC6, 0x01,\n            0x20, 0xB1, 0xD8, 0x21, 0x70, 0xF9, 0x61, 0x76, 0x87, 0x1D, 0x24, 0x0F,\n            0x79, 0xEF, 0x5A, 0xE9, 0x91, 0xB0, 0x97, 0x33, 0xB5, 0x6C, 0x9F, 0x91,\n            0xED, 0x56, 0x80, 0x6B, 0x40, 0x3C, 0xEF, 0x46, 0xB0, 0xC5, 0xD7, 0xA7,\n            0xB5, 0x9D, 0x45, 0x7F, 0x03, 0xEA, 0x70, 0xA1, 0x64, 0xE2, 0x29, 0xB4,\n            0x08, 0x69, 0x09, 0xC0, 0xD0, 0x57, 0x38, 0xF7, 0x4B, 0x33, 0x9D, 0xF4,\n            0x36, 0x28, 0x15, 0xBF, 0xB1, 0x62, 0x04, 0x10, 0x4D, 0xAB, 0x47, 0x03,\n            0x15, 0xAB, 0xC4, 0x78, 0x0E, 0x78, 0x9D, 0x8A, 0x28, 0x74, 0x54, 0xEB,\n            0x66, 0xE8, 0x89, 0x45, 0x45, 0x70, 0x2E, 0xB9, 0x03, 0x1C, 0xCB, 0x83,\n            0xA0, 0x7C, 0x0B, 0xC5, 0xB2, 0x93, 0x6A, 0x7F, 0x65, 0x4E, 0x35, 0xFB,\n            0xF1, 0x58, 0x21, 0xC7, 0x2D, 0x44, 0x53, 0x69, 0x9B, 0x46, 0x23, 0x10,\n            0x51, 0xAE, 0x4C, 0x36, 0x18, 0xC4, 0x62, 0xBE, 0x4E, 0x44, 0xFB, 0x98,\n            0x42, 0x46, 0x0B, 0x33, 0x48, 0x45, 0x86, 0xEA, 0x7F, 0x75, 0x32, 0xD2,\n            0x6B, 0x49, 0x5A, 0x0A, 0x18, 0x37, 0xB1, 0xC3, 0x3E, 0xB0, 0x94, 0xE8,\n            0x46, 0x01, 0x07, 0x59, 0x5F, 0xCD, 0xFF, 0x25, 0xE6, 0xB1, 0x23, 0x34,\n            0xD5, 0x3A, 0xBA, 0xB9, 0x96, 0xB8, 0xCA, 0xA5, 0x15, 0xD5, 0x07, 0xE3,\n            0xE1, 0x63, 0x6F, 0x97, 0x4F, 0x11, 0xA5, 0x49, 0x8E, 0x29, 0x3F, 0xC9,\n            0xAF, 0x59, 0x56, 0x4B, 0x11, 0x04, 0x6C, 0xBE, 0x3F, 0xAE, 0x3F, 0x72,\n            0xD1, 0x81, 0x15, 0xDE, 0xDB, 0x5B, 0x21, 0xA7, 0x02, 0xE6, 0x50, 0x6D,\n            0xB0, 0x9E, 0x98, 0x23, 0x44, 0x9D, 0x1D, 0x21, 0x12, 0x7C, 0x28, 0x1F,\n            0x37, 0x6D, 0xCB, 0xCB, 0x1B, 0x01, 0x63, 0xF3, 0xAC, 0xAF, 0x30, 0x41,\n            0xBD, 0xA8, 0x39, 0xD7, 0x37, 0x59, 0x56, 0xCC, 0x3B, 0x73, 0x5C, 0xF1,\n            0x21, 0x9C, 0xD2, 0x75, 0xEA, 0xE7, 0xBD, 0x82, 0xDF, 0x3D, 0x5A, 0x0E,\n            0x9D, 0x7A, 0x41, 0x16, 0x26, 0x72, 0x12, 0xA0, 0x89, 0xFF, 0xAC, 0x83,\n            0x87, 0xB5, 0x9F, 0xF0, 0x56, 0xAA, 0x36, 0x9A, 0x1B, 0x41, 0x3C, 0xDF,\n            0x75, 0x07, 0x0E, 0xC6, 0xF5, 0xB4, 0x41, 0xF6, 0xCA, 0xB6, 0xE8, 0xF0,\n            0x38, 0x98, 0x4C, 0xB1, 0x56, 0xBC, 0xFD, 0xD4, 0xD9, 0xB5, 0x7E, 0x80,\n            0x0D, 0xB2, 0xD0, 0x2F, 0x2E, 0x6F, 0x7D, 0xFF, 0xB0, 0xF7, 0x8C, 0xE2,\n            0x90, 0xDC, 0x3B, 0x15, 0xF6, 0x07, 0xBC, 0x36, 0x2C, 0x40, 0x93, 0x05,\n            0xEF, 0xF3, 0x02, 0xEB, 0x4D, 0xB0, 0xE8, 0xC9, 0x38, 0x4B, 0xBE, 0xA1,\n            0xBF, 0xEE, 0x9F, 0x8A, 0x31, 0xE0, 0x76, 0xE1, 0x79, 0x94, 0xB7, 0x4D,\n            0x7C, 0xF4, 0x65, 0xF6, 0x8C, 0x35, 0xF5, 0x78, 0x5E, 0xFE, 0x13, 0x72,\n            0xC6, 0x13, 0x4C, 0x3A, 0x5E, 0x2C, 0x2B, 0x68, 0x68, 0x59, 0x02, 0x06,\n            0xD5, 0x7F, 0x02, 0xA6, 0xF2, 0xB6, 0x16, 0xCA, 0xE8, 0x14, 0x75, 0xDA,\n            0x3D, 0xF5, 0x85, 0x3D, 0x6B, 0x2D, 0x03, 0xA4, 0xC1, 0x5F, 0x5D, 0x68,\n            0xCC, 0xB1, 0xDE, 0xC1, 0x69, 0x22, 0x99, 0x00, 0x4A, 0x5C, 0x61, 0x14,\n            0xAD, 0x50, 0x05, 0xCF, 0x6E, 0xEE, 0x4C, 0xC9, 0x58, 0xA4, 0xE5\n        }\n    }\n};\nstatic const BCRYPT_PSS_PADDING_INFO KphpKeyPaddingInfo =\n{\n    KPH_KEY_HASH_ALGORITHM,\n    KPH_KEY_HASH_ALGORITHM_BYTES\n};\nstatic const UNICODE_STRING KphpSigExtension = RTL_CONSTANT_STRING(L\".sig\");\nKPH_PROTECTED_DATA_SECTION_RO_POP();\nKPH_PROTECTED_DATA_SECTION_PUSH();\nstatic BCRYPT_KEY_HANDLE KphpPublicKeyHandles[ARRAYSIZE(KphpPublicKeys)] = { 0 };\nstatic ULONG KphpPublicKeyHandlesCount = 0;\nC_ASSERT(ARRAYSIZE(KphpPublicKeyHandles) == ARRAYSIZE(KphpPublicKeys));\nKPH_PROTECTED_DATA_SECTION_POP();\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Verifies that the specified signature matches the specified hash by\n * using one of the known public keys.\n *\n * \\param[in] KeyHandle The key handle to use for verification, if NULL the\n * pinned keys are used to verify the signature.\n * \\param[in] Hash The hash to verify.\n * \\param[in] Signature The signature to check.\n * \\param[in] SignatureLength The length of the signature.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpVerifyHash(\n    _In_opt_ BCRYPT_KEY_HANDLE KeyHandle,\n    _In_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = STATUS_UNSUCCESSFUL;\n\n    if (KeyHandle)\n    {\n        status = BCryptVerifySignature(KeyHandle,\n                                       KPH_KEY_PADDING_INFO,\n                                       HashInformation->Hash,\n                                       HashInformation->Length,\n                                       Signature,\n                                       SignatureLength,\n                                       KPH_KEY_PADDING_FLAGS);\n    }\n    else\n    {\n        for (ULONG i = 0; i < KphpPublicKeyHandlesCount; i++)\n        {\n            status = BCryptVerifySignature(KphpPublicKeyHandles[i],\n                                           KPH_KEY_PADDING_INFO,\n                                           HashInformation->Hash,\n                                           HashInformation->Length,\n                                           Signature,\n                                           SignatureLength,\n                                           KPH_KEY_PADDING_FLAGS);\n            if (NT_SUCCESS(status))\n            {\n                return status;\n            }\n        }\n    }\n\n    return status;\n}\n\n/**\n * \\brief Closes a verification key handle.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphVerifyCloseKey(\n    _In_ BCRYPT_KEY_HANDLE KeyHandle\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    BCryptDestroyKey(KeyHandle);\n}\n\n/**\n * \\brief Creates a verification key handle.\n *\n * \\param[out] KeyHandle The created key handle.\n * \\param[in] KeyMaterial The key material to use.\n * \\param[in] KeyMaterialLength The length of the key material.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyCreateKey(\n    _Out_ BCRYPT_KEY_HANDLE* KeyHandle,\n    _In_ PBYTE KeyMaterial,\n    _In_ ULONG KeyMaterialLength\n    )\n{\n    NTSTATUS status;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = BCryptImportKeyPair(KPH_KEY_ALG_HANDLE,\n                                 NULL,\n                                 KPH_KEY_BLOB_PUBLIC,\n                                 KeyHandle,\n                                 (PUCHAR)KeyMaterial,\n                                 KeyMaterialLength,\n                                 0);\n    if (!NT_SUCCESS(status))\n    {\n        *KeyHandle = NULL;\n    }\n\n    return status;\n}\n\n/**\n * \\brief Verifies a buffer matches the provided signature.\n *\n * \\param[in] KeyHandle The key handle to use for verification, if NULL the\n * pinned keys are used to verify the signature.\n * \\param[in] Buffer The buffer to verify.\n * \\param[in] BufferLength The length of the buffer.\n * \\param[in] Signature The signature to check.\n * \\param[in] SignatureLength The length of the signature.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyBufferEx(\n    _In_opt_ BCRYPT_KEY_HANDLE KeyHandle,\n    _In_ PBYTE Buffer,\n    _In_ ULONG BufferLength,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    )\n{\n    NTSTATUS status;\n    KPH_HASH_INFORMATION hashInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    status = KphHashBuffer(Buffer,\n                           BufferLength,\n                           KphHashAlgorithmSha512,\n                           &hashInfo);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"KphHashBuffer failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    status = KphpVerifyHash(KeyHandle, &hashInfo, Signature, SignatureLength);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"KphpVerifyHash failed: %!STATUS!\",\n                      status);\n\n        return status;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Verifies a buffer matches the provided signature.\n *\n * \\param[in] Buffer The buffer to verify.\n * \\param[in] BufferLength The length of the buffer.\n * \\param[in] Signature The signature to check.\n * \\param[in] SignatureLength The length of the signature.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyBuffer(\n    _In_ PBYTE Buffer,\n    _In_ ULONG BufferLength,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    return KphVerifyBufferEx(NULL,\n                             Buffer,\n                             BufferLength,\n                             Signature,\n                             SignatureLength);\n}\n\n#define KphpVerifyValidFileName(FileName)                                      \\\n    (((FileName)->Length > KphpSigExtension.Length) &&                         \\\n     ((FileName)->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))\n\n/**\n * \\brief Verifies a file object.\n *\n * \\param[in] FileObject File object to verify.\n * \\param[in] FileName Optional file name to use for verification, if not\n * provided the file name is looked up from the file object.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyFileObject(\n    _In_ PFILE_OBJECT FileObject,\n    _In_opt_ PCUNICODE_STRING FileName\n    )\n{\n    NTSTATUS status;\n    PCUNICODE_STRING fileName;\n    PUNICODE_STRING localFileName;\n    UNICODE_STRING signatureFileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE signatureFileHandle;\n    IO_STATUS_BLOCK ioStatusBlock;\n    PBYTE signature;\n    ULONG signatureLength;\n    KPH_HASH_INFORMATION hashInfo;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    localFileName = NULL;\n    RtlZeroMemory(&signatureFileName, sizeof(UNICODE_STRING));\n    signatureFileHandle = NULL;\n    signature = NULL;\n\n    if (FileName)\n    {\n        fileName = FileName;\n    }\n    else\n    {\n        status = KphGetNameFileObject(FileObject, &localFileName);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          VERIFY,\n                          \"KphGetNameFileObject failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        fileName = localFileName;\n    }\n\n    if (!KphpVerifyValidFileName(fileName))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"File name is invalid \\\"%wZ\\\"\",\n                      fileName);\n\n        status = STATUS_OBJECT_NAME_INVALID;\n        goto Exit;\n    }\n\n    status = RtlDuplicateUnicodeString(0, fileName, &signatureFileName);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"RtlDuplicateUnicodeString failed: %!STATUS!\",\n                      status);\n\n        RtlZeroMemory(&signatureFileName, sizeof(UNICODE_STRING));\n        goto Exit;\n    }\n\n    //\n    // Replace the file extension with \".sig\". Our verification requires that\n    // the signature file be placed alongside the file we're verifying.\n    //\n    if (signatureFileName.Length < KphpSigExtension.Length)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"Signature file name length invalid \\\"%wZ\\\"\",\n                      &signatureFileName);\n\n        status = STATUS_OBJECT_NAME_INVALID;\n        goto Exit;\n    }\n\n    signatureFileName.Length -= KphpSigExtension.Length;\n\n    status = RtlAppendUnicodeStringToString(&signatureFileName,\n                                            &KphpSigExtension);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"RtlAppendUnicodeStringToString failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    InitializeObjectAttributes(&objectAttributes,\n                               &signatureFileName,\n                               OBJ_KERNEL_HANDLE | OBJ_DONT_REPARSE,\n                               NULL,\n                               NULL);\n\n    status = KphCreateFile(&signatureFileHandle,\n                           FILE_READ_ACCESS | SYNCHRONIZE,\n                           &objectAttributes,\n                           &ioStatusBlock,\n                           NULL,\n                           FILE_ATTRIBUTE_NORMAL,\n                           FILE_SHARE_READ,\n                           FILE_OPEN,\n                           (FILE_NON_DIRECTORY_FILE |\n                            FILE_SYNCHRONOUS_IO_NONALERT |\n                            FILE_COMPLETE_IF_OPLOCKED),\n                           NULL,\n                           0,\n                           IO_IGNORE_SHARE_ACCESS_CHECK,\n                           KernelMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"Failed to open signature file \\\"%wZ\\\": %!STATUS!\",\n                      &signatureFileName,\n                      status);\n\n        signatureFileHandle = NULL;\n        goto Exit;\n    }\n    else if (status == STATUS_OPLOCK_BREAK_IN_PROGRESS)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"Failed to open signature file \\\"%wZ\\\": %!STATUS!\",\n                      &signatureFileName,\n                      status);\n\n        status = STATUS_SHARING_VIOLATION;\n        goto Exit;\n    }\n\n    signature = KphAllocatePaged(KPH_VERIFY_SIGNATURE_MAX_LENGTH,\n                                 KPH_TAG_VERIFY_SIGNATURE);\n    if (!signature)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"Failed to allocate signature buffer\");\n\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto Exit;\n    }\n\n    status = ZwReadFile(signatureFileHandle,\n                        NULL,\n                        NULL,\n                        NULL,\n                        &ioStatusBlock,\n                        signature,\n                        KPH_VERIFY_SIGNATURE_MAX_LENGTH,\n                        NULL,\n                        NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"Failed to read signature file \\\"%wZ\\\": %!STATUS!\",\n                      &signatureFileName,\n                      status);\n\n        goto Exit;\n    }\n\n    signatureLength = (ULONG)ioStatusBlock.Information;\n\n    hashInfo.Algorithm = KphHashAlgorithmSha512;\n\n    status = KphQueryHashInformationFileObject(FileObject,\n                                               &hashInfo,\n                                               sizeof(KPH_HASH_INFORMATION));\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"KphQueryHashInformationFileObject failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = KphpVerifyHash(NULL, &hashInfo, signature, signatureLength);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"KphpVerifyHash failed: %!STATUS!\",\n                      status);\n\n        goto Exit;\n    }\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    if (signature)\n    {\n        KphFree(signature, KPH_TAG_VERIFY_SIGNATURE);\n    }\n\n    if (signatureFileHandle)\n    {\n        ObCloseHandle(signatureFileHandle, KernelMode);\n    }\n\n    RtlFreeUnicodeString(&signatureFileName);\n\n    if (localFileName)\n    {\n        KphFreeNameFileObject(localFileName);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Verifies a file by name.\n *\n * \\param[in] FileName File name to verify.\n * \\param[in] FileObject Optional file object to use for verification. If\n * provided the opened file object is checked to match. This is useful when the\n * file object is known but not in a state where you can use it directly.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphVerifyFile(\n    _In_ PCUNICODE_STRING FileName,\n    _In_opt_ PFILE_OBJECT FileObject\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n    HANDLE fileHandle;\n    PFILE_OBJECT fileObject;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    fileObject = NULL;\n    fileHandle = NULL;\n\n    if (!KphpVerifyValidFileName(FileName))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"File name is invalid \\\"%wZ\\\"\",\n                      FileName);\n\n        status = STATUS_OBJECT_NAME_INVALID;\n        goto Exit;\n    }\n\n    InitializeObjectAttributes(&objectAttributes,\n                               (PUNICODE_STRING)FileName,\n                               OBJ_KERNEL_HANDLE | OBJ_DONT_REPARSE,\n                               NULL,\n                               NULL);\n\n    status = KphCreateFile(&fileHandle,\n                           FILE_READ_ACCESS | SYNCHRONIZE,\n                           &objectAttributes,\n                           &ioStatusBlock,\n                           NULL,\n                           FILE_ATTRIBUTE_NORMAL,\n                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n                           FILE_OPEN,\n                           (FILE_NON_DIRECTORY_FILE |\n                            FILE_SYNCHRONOUS_IO_NONALERT |\n                            FILE_COMPLETE_IF_OPLOCKED),\n                           NULL,\n                           0,\n                           IO_IGNORE_SHARE_ACCESS_CHECK,\n                           KernelMode);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"KphCreateFile failed: %!STATUS!\",\n                      status);\n\n        fileHandle = NULL;\n        goto Exit;\n    }\n    else if (status == STATUS_OPLOCK_BREAK_IN_PROGRESS)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"KphCreateFile failed: %!STATUS!\",\n                      status);\n\n        status = STATUS_SHARING_VIOLATION;\n        goto Exit;\n    }\n\n    status = ObReferenceObjectByHandle(fileHandle,\n                                       0,\n                                       *IoFileObjectType,\n                                       KernelMode,\n                                       &fileObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        fileObject = NULL;\n        goto Exit;\n    }\n\n    if (FileObject && !KphIsSameFile(FileObject, fileObject))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      VERIFY,\n                      \"File objects do not match!\");\n\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    status = KphVerifyFileObject(fileObject, FileName);\n\nExit:\n\n    if (fileObject)\n    {\n        ObDereferenceObject(fileObject);\n    }\n\n    if (fileHandle)\n    {\n        ObCloseHandle(fileHandle, KernelMode);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Initializes verification infrastructure.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphInitializeVerify(\n    VOID\n    )\n{\n    BOOLEAN testSigning;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    testSigning = KphTestSigningEnabled();\n\n    for (ULONG i = 0; i < ARRAYSIZE(KphpPublicKeys); i++)\n    {\n        NTSTATUS status;\n        PCKPH_KEY key;\n        BCRYPT_KEY_HANDLE keyHandle;\n\n        key = &KphpPublicKeys[i];\n\n        if (!testSigning && (key->Type == KphKeyTypeTest))\n        {\n            continue;\n        }\n\n        status = KphVerifyCreateKey(&keyHandle,\n                                    (PBYTE)key->Material,\n                                    KPH_KEY_MATERIAL_SIZE);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          VERIFY,\n                          \"KphVerifyCreateKey failed: %!STATUS!\",\n                          status);\n\n            return status;\n        }\n\n        KphpPublicKeyHandles[KphpPublicKeyHandlesCount++] = keyHandle;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Cleans up verification infrastructure.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\nVOID KphCleanupVerify(\n    VOID\n    )\n{\n    KPH_PAGED_CODE_PASSIVE();\n\n    for (ULONG i = 0; i < KphpPublicKeyHandlesCount; i++)\n    {\n        KphVerifyCloseKey(KphpPublicKeyHandles[i]);\n    }\n}\n"
  },
  {
    "path": "KSystemInformer/vm.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     jxy-s   2022-2026\n *\n */\n\n#include <kph.h>\n\n#include <trace.h>\n\n/**\n * \\brief Queries information on mappings for a given section object.\n *\n * \\param[in] SectionObject The section object to query the info of.\n * \\param[out] SectionInformation Populated with the information. This storage\n * must be located in non-paged system-space memory.\n * \\param[in] SectionInformationLength Length of the section information.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(DISPATCH_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphpQuerySectionMappings(\n    _In_ PVOID SectionObject,\n    _Out_writes_bytes_opt_(SectionInformationLength) PVOID SectionInformation,\n    _In_ ULONG SectionInformationLength,\n    _Out_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PKPH_DYN dyn;\n    ULONG returnLength;\n    PVOID controlArea;\n    PLIST_ENTRY listHead;\n    PKPH_SECTION_MAPPINGS_INFORMATION info;\n    PEX_SPIN_LOCK lock;\n    KIRQL oldIrql;\n\n    KPH_NPAGED_CODE_DISPATCH_MAX();\n\n    lock = NULL;\n    oldIrql = 0;\n    returnLength = 0;\n\n    dyn = KphReferenceDynData();\n\n    if (!dyn ||\n        (dyn->MmSectionControlArea == ULONG_MAX) ||\n        (dyn->MmControlAreaListHead == ULONG_MAX) ||\n        (dyn->MmControlAreaLock == ULONG_MAX))\n    {\n        status = STATUS_NOINTERFACE;\n        goto Exit;\n    }\n\n    controlArea = *(PVOID*)Add2Ptr(SectionObject, dyn->MmSectionControlArea);\n    if ((ULONG_PTR)controlArea & 3)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Section remote mappings not supported.\");\n\n        status = STATUS_NOT_SUPPORTED;\n        goto Exit;\n    }\n\n    controlArea = (PVOID)((ULONG_PTR)controlArea & ~3);\n    if (!controlArea)\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Section control area is null.\");\n\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    lock = Add2Ptr(controlArea, dyn->MmControlAreaLock);\n    oldIrql = ExAcquireSpinLockShared(lock);\n\n    listHead = Add2Ptr(controlArea, dyn->MmControlAreaListHead);\n\n    //\n    // Links are shared in a union with AweContext pointer. Ensure that both\n    // links look valid.\n    //\n    if (!listHead->Flink || !listHead->Blink ||\n        (listHead->Flink->Blink != listHead) ||\n        (listHead->Blink->Flink != listHead))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"Section unexpected control area links.\");\n\n        status = STATUS_INVALID_PARAMETER;\n        goto Exit;\n    }\n\n    returnLength = UFIELD_OFFSET(KPH_SECTION_MAPPINGS_INFORMATION, Mappings);\n\n    for (PLIST_ENTRY link = listHead->Flink;\n         link != listHead;\n         link = link->Flink)\n    {\n        status = RtlULongAdd(returnLength,\n                             sizeof(KPH_SECTION_MAP_ENTRY),\n                             &returnLength);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"RtlULongAdd failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n    }\n\n    if (!SectionInformation || (SectionInformationLength < returnLength))\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n        goto Exit;\n    }\n\n    info = SectionInformation;\n\n    info->NumberOfMappings = 0;\n\n    for (PLIST_ENTRY link = listHead->Flink;\n         link != listHead;\n         link = link->Flink)\n    {\n        PMMVAD vad;\n        PKPH_SECTION_MAP_ENTRY entry;\n\n        vad = CONTAINING_RECORD(link, MMVAD, ViewLinks);\n        entry = &info->Mappings[info->NumberOfMappings++];\n\n        entry->ViewMapType = vad->ViewMapType;\n        entry->ProcessId = NULL;\n        if (vad->ViewMapType == VIEW_MAP_TYPE_PROCESS)\n        {\n            PEPROCESS process;\n\n            process = (PEPROCESS)((ULONG_PTR)vad->VadsProcess & ~VIEW_MAP_TYPE_PROCESS);\n            if (process)\n            {\n                entry->ProcessId = PsGetProcessId(process);\n            }\n        }\n        entry->StartVa = MiGetVadStartAddress(vad);\n        entry->EndVa = MiGetVadEndAddress(vad);\n    }\n\n    status = STATUS_SUCCESS;\n\nExit:\n\n    *ReturnLength = returnLength;\n\n    if (lock)\n    {\n        ExReleaseSpinLockShared(lock, oldIrql);\n    }\n\n    if (dyn)\n    {\n        KphDereferenceObject(dyn);\n    }\n\n    return status;\n}\n\nKPH_PAGED_FILE();\n\n/**\n * \\brief Copies process or kernel memory into the current process.\n *\n * \\param[in] ProcessHandle A handle to a process. The handle must have\n * PROCESS_VM_READ access. This parameter may be NULL if BaseAddress is a kernel\n * address.\n * \\param[in] BaseAddress The address from which memory is to be copied.\n * \\param[out] Buffer A buffer which receives the copied memory.\n * \\param[in] BufferSize The number of bytes to copy.\n * \\param[out] NumberOfBytesRead Receives the number of bytes written.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphReadVirtualMemory(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    SIZE_T numberOfBytesRead;\n    BOOLEAN releaseModuleLock;\n    PVOID buffer;\n    BYTE stackBuffer[0x200];\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    numberOfBytesRead = 0;\n    releaseModuleLock = FALSE;\n    buffer = NULL;\n\n    if (!Buffer)\n    {\n        status = STATUS_INVALID_PARAMETER_3;\n        goto Exit;\n    }\n\n    if (Add2Ptr(BaseAddress, BufferSize) < BaseAddress)\n    {\n        status = STATUS_ACCESS_VIOLATION;\n        goto Exit;\n    }\n\n    if (!BufferSize)\n    {\n        status = STATUS_SUCCESS;\n        goto Exit;\n    }\n\n    //\n    // Select the appropriate copy method.\n    //\n\n    if (Add2Ptr(BaseAddress, BufferSize) > MmHighestUserAddress)\n    {\n        MM_COPY_ADDRESS copyAddress;\n\n        //\n        // Only permit reading from the system module ranges. Prevent TOCTOU\n        // between checking the system module list and copying.\n        //\n\n        KeEnterCriticalRegion();\n        if (!ExAcquireResourceSharedLite(PsLoadedModuleResource, TRUE))\n        {\n            KeLeaveCriticalRegion();\n\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Failed to acquire PsLoadedModuleResource\");\n\n            status = STATUS_RESOURCE_NOT_OWNED;\n            goto Exit;\n        }\n\n        releaseModuleLock = TRUE;\n\n        status = KphValidateAddressForSystemModules(BaseAddress, BufferSize);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"KphValidateAddressForSystemModules failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        buffer = KphAllocateNPagedA(BufferSize, KPH_TAG_COPY_VM, stackBuffer);\n        if (!buffer)\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"Failed to allocate copy buffer.\");\n\n            status = STATUS_INSUFFICIENT_RESOURCES;\n            goto Exit;\n        }\n\n        copyAddress.VirtualAddress = BaseAddress;\n\n        status = MmCopyMemory(buffer,\n                              copyAddress,\n                              BufferSize,\n                              MM_COPY_MEMORY_VIRTUAL,\n                              &numberOfBytesRead);\n\n        if (AccessMode != KernelMode)\n        {\n            __try\n            {\n                CopyToUser(Buffer, buffer, numberOfBytesRead);\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                status = GetExceptionCode();\n            }\n        }\n        else\n        {\n            RtlCopyMemory(Buffer, buffer, numberOfBytesRead);\n        }\n    }\n    else\n    {\n        PEPROCESS process;\n\n        if (!ProcessHandle)\n        {\n            status = STATUS_INVALID_PARAMETER_1;\n            goto Exit;\n        }\n\n        status = ObReferenceObjectByHandle(ProcessHandle,\n                                           0,\n                                           *PsProcessType,\n                                           AccessMode,\n                                           &process,\n                                           NULL);\n        if (!NT_SUCCESS(status))\n        {\n            KphTracePrint(TRACE_LEVEL_VERBOSE,\n                          GENERAL,\n                          \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                          status);\n\n            goto Exit;\n        }\n\n        status = MmCopyVirtualMemory(process,\n                                     BaseAddress,\n                                     PsGetCurrentProcess(),\n                                     Buffer,\n                                     BufferSize,\n                                     AccessMode,\n                                     &numberOfBytesRead);\n\n        ObDereferenceObject(process);\n    }\n\nExit:\n\n    if (buffer)\n    {\n        KphFreeA(buffer, KPH_TAG_COPY_VM, stackBuffer);\n    }\n\n    if (releaseModuleLock)\n    {\n        ExReleaseResourceLite(PsLoadedModuleResource);\n        KeLeaveCriticalRegion();\n    }\n\n    if (NumberOfBytesRead)\n    {\n        KphWriteSizeTToMode(NumberOfBytesRead, numberOfBytesRead, AccessMode);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries information about a section.\n *\n * \\param[in] SectionHandle Handle to the query to query information of.\n * \\param[in] SectionInformationClass Classification of information to query.\n * \\param[out] SectionInformation Populated with the requested information.\n * \\param[in] SectionInformationLength Length of the information buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQuerySection(\n    _In_ HANDLE SectionHandle,\n    _In_ KPH_SECTION_INFORMATION_CLASS SectionInformationClass,\n    _Out_writes_bytes_opt_(SectionInformationLength) PVOID SectionInformation,\n    _In_ ULONG SectionInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    PVOID sectionObject;\n    ULONG returnLength;\n    PVOID buffer;\n    BYTE stackBuffer[64];\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    returnLength = 0;\n    buffer = NULL;\n\n    status = ObReferenceObjectByHandle(SectionHandle,\n                                       0,\n                                       *MmSectionObjectType,\n                                       KernelMode,\n                                       &sectionObject,\n                                       NULL);\n    if (!NT_SUCCESS(status))\n    {\n        KphTracePrint(TRACE_LEVEL_VERBOSE,\n                      GENERAL,\n                      \"ObReferenceObjectByHandle failed: %!STATUS!\",\n                      status);\n\n        sectionObject = NULL;\n        goto Exit;\n    }\n\n    switch (SectionInformationClass)\n    {\n        case KphSectionMappingsInformation:\n        {\n            if (SectionInformation)\n            {\n                buffer = KphAllocateNPagedA(SectionInformationLength,\n                                            KPH_TAG_SECTION_QUERY,\n                                            stackBuffer);\n                if (!buffer)\n                {\n                    status = STATUS_INSUFFICIENT_RESOURCES;\n                    goto Exit;\n                }\n            }\n            else\n            {\n                NT_ASSERT(!buffer);\n                SectionInformationLength = 0;\n            }\n\n            status = KphpQuerySectionMappings(sectionObject,\n                                              buffer,\n                                              SectionInformationLength,\n                                              &returnLength);\n            if (!NT_SUCCESS(status))\n            {\n                goto Exit;\n            }\n\n            if (!SectionInformation)\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n                goto Exit;\n            }\n\n            status = KphCopyToMode(SectionInformation,\n                                   buffer,\n                                   returnLength,\n                                   AccessMode);\n\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n\nExit:\n\n    if (ReturnLength)\n    {\n        KphWriteULongToMode(ReturnLength, returnLength, AccessMode);\n    }\n\n    if (sectionObject)\n    {\n        ObDereferenceObject(sectionObject);\n    }\n\n    if (buffer)\n    {\n        KphFreeA(buffer, KPH_TAG_SECTION_QUERY, stackBuffer);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Queries information about a region of pages within the virtual address\n * space of the specified process.\n *\n * \\param[in] ProcessHandle Handle for the process whose context the pages to be\n * queried resides.\n * \\param[in] BaseAddress The base address of the region of pages to be queried.\n * \\param[in] MemoryInformationClass The memory information to retrieve.\n * \\param[out] MemoryInformation Populated with the requested information.\n * \\param[in] MemoryInformationLength Length of the information buffer.\n * \\param[out] ReturnLength Receives the number of bytes written or required.\n * \\param[in] AccessMode The mode in which to perform access checks.\n *\n * \\return Successful or errant status.\n */\n_IRQL_requires_max_(PASSIVE_LEVEL)\n_Must_inspect_result_\nNTSTATUS KphQueryVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ KPH_MEMORY_INFORMATION_CLASS MemoryInformationClass,\n    _Out_writes_bytes_opt_(MemoryInformationLength) PVOID MemoryInformation,\n    _In_ ULONG MemoryInformationLength,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ KPROCESSOR_MODE AccessMode\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    PKPH_THREAD_CONTEXT thread;\n    PUNICODE_STRING mappedFileName;\n\n    KPH_PAGED_CODE_PASSIVE();\n\n    returnLength = 0;\n    thread = NULL;\n    mappedFileName = NULL;\n\n    switch (MemoryInformationClass)\n    {\n        case KphMemoryImageSection:\n        {\n            SIZE_T length;\n            OBJECT_ATTRIBUTES objectAttributes;\n            IO_STATUS_BLOCK ioStatusBlock;\n            HANDLE fileHandle;\n            HANDLE sectionHandle;\n\n            if (!MemoryInformation ||\n                (MemoryInformationLength < sizeof(HANDLE)))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(HANDLE);\n                goto Exit;\n            }\n\n            //\n            // At this time there is no known way to open the image section\n            // for an address in a process without reopening the file.\n            //\n            // For image mappings the VAD does not retain a reference to the\n            // actual section object but does contain a pointer to the file\n            // object. There are a few exported APIs for creating sections\n            // using a file object directly. And, using the file object in the\n            // VAD, it is possible to map the data section but not the image\n            // section. Internally, MiCreateSection has checks for SEC_IMAGE\n            // when passing in a file object - this check will fail the\n            // operation.\n            //\n            // Unfortunately, to create the image section, we have to query the\n            // file name and open the file again. This introduces two points of\n            // failure that could be avoided if we could create the image\n            // section using the file object. The unfortunate failure mode is\n            // the file being \"gone\" or otherwise inaccessible. The other cases\n            // might be a resource constraint or a filter interfering with\n            // access to the file.\n            //\n\n            mappedFileName = KphAllocatePaged(MAX_PATH, KPH_TAG_VM_QUERY);\n            if (!mappedFileName)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            status = ZwQueryVirtualMemory(ProcessHandle,\n                                          BaseAddress,\n                                          MemoryMappedFilenameInformation,\n                                          mappedFileName,\n                                          MAX_PATH,\n                                          &length);\n            if ((status == STATUS_BUFFER_OVERFLOW) && (length > 0))\n            {\n                KphFree(mappedFileName, KPH_TAG_VM_QUERY);\n                mappedFileName = KphAllocatePaged(length, KPH_TAG_VM_QUERY);\n                if (!mappedFileName)\n                {\n                    status = STATUS_INSUFFICIENT_RESOURCES;\n                    goto Exit;\n                }\n\n                status = ZwQueryVirtualMemory(ProcessHandle,\n                                              BaseAddress,\n                                              MemoryMappedFilenameInformation,\n                                              mappedFileName,\n                                              length,\n                                              &length);\n            }\n\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ZwQueryVirtualMemory failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            InitializeObjectAttributes(&objectAttributes,\n                                       mappedFileName,\n                                       OBJ_KERNEL_HANDLE,\n                                       NULL,\n                                       NULL);\n\n            status = KphCreateFile(&fileHandle,\n                                   FILE_READ_ACCESS | SYNCHRONIZE,\n                                   &objectAttributes,\n                                   &ioStatusBlock,\n                                   NULL,\n                                   FILE_ATTRIBUTE_NORMAL,\n                                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n                                   FILE_OPEN,\n                                   FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n                                   NULL,\n                                   0,\n                                   IO_IGNORE_SHARE_ACCESS_CHECK,\n                                   KernelMode);\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"KphCreateFile failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            InitializeObjectAttributes(&objectAttributes,\n                                       NULL,\n                                       (AccessMode ? 0 : OBJ_KERNEL_HANDLE),\n                                       NULL,\n                                       NULL);\n\n            status = ZwCreateSection(&sectionHandle,\n                                     SECTION_QUERY | SECTION_MAP_READ,\n                                     &objectAttributes,\n                                     NULL,\n                                     PAGE_READONLY,\n                                     SEC_IMAGE_NO_EXECUTE,\n                                     fileHandle);\n\n            ObCloseHandle(fileHandle, KernelMode);\n\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"ZwCreateSection failed: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            status = KphWriteHandleToMode(MemoryInformation,\n                                          sectionHandle,\n                                          AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(HANDLE);\n            }\n\n            break;\n        }\n        case KphMemoryDataSection:\n        {\n            SIZE_T length;\n            KPH_VM_TLS_CREATE_DATA_SECTION tls;\n            PKPH_MEMORY_DATA_SECTION memoryInformation;\n\n            if (!MemoryInformation ||\n                (MemoryInformationLength) < sizeof(KPH_MEMORY_DATA_SECTION))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_MEMORY_DATA_SECTION);\n                goto Exit;\n            }\n\n            //\n            // The data section may be created using the file object in the VAD.\n            // First we have to access the file object from the VAD. We could do\n            // some dynamic data and walk the process VAD ourselves, but there\n            // is a \"cleaner\" option. Querying for the memory mapped file name\n            // will do the work to enumerate the VAD and will land us in our\n            // mini-filter instance with the file object. This still comes with\n            // possibility of filters interfering with the name query, but at\n            // least we don't have to go through an entire IRP_MJ_CREATE. The\n            // advantage here is we are able to create a section object for a\n            // file that might be \"gone\" or otherwise inaccessible.\n            //\n\n            thread = KphGetCurrentThreadContext();\n            if (!thread)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            RtlZeroMemory(&tls, sizeof(KPH_VM_TLS_CREATE_DATA_SECTION));\n\n            tls.AccessMode = AccessMode;\n\n            thread->VmTlsCreateDataSection = &tls;\n\n            status = ZwQueryVirtualMemory(ProcessHandle,\n                                          BaseAddress,\n                                          MemoryMappedFilenameInformation,\n                                          NULL,\n                                          0,\n                                          &length);\n\n            NT_ANALYSIS_ASSUME(NT_SUCCESS(status));\n\n            if (thread->VmTlsCreateDataSection)\n            {\n                thread->VmTlsCreateDataSection = NULL;\n\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"VmTlsCreateDataSection was not null! \"\n                              \"ZwQueryVirtualMemory returned: %!STATUS!\",\n                              status);\n\n                status = STATUS_UNEXPECTED_IO_ERROR;\n                goto Exit;\n            }\n\n            status = tls.Status;\n            if (!NT_SUCCESS(status))\n            {\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"KPH_VM_TLS_CREATE_DATA_SECTION status: %!STATUS!\",\n                              status);\n\n                goto Exit;\n            }\n\n            memoryInformation = MemoryInformation;\n\n            status = KphCopyToMode(&memoryInformation->SectionFileSize,\n                                   &tls.SectionFileSize,\n                                   sizeof(LARGE_INTEGER),\n                                   AccessMode);\n            if (!NT_SUCCESS(status))\n            {\n                ObCloseHandle(tls.SectionHandle, AccessMode);\n                goto Exit;\n            }\n\n            status = KphWriteHandleToMode(&memoryInformation->SectionHandle,\n                                          tls.SectionHandle,\n                                          AccessMode);\n\n            break;\n        }\n        case KphMemoryMappedInformation:\n        {\n            SIZE_T length;\n            KPH_MEMORY_MAPPED_INFORMATION tls;\n            KPH_MEMORY_MAPPED_INFORMATION memoryInformation;\n\n            if (!MemoryInformation ||\n                (MemoryInformationLength) < sizeof(KPH_MEMORY_MAPPED_INFORMATION))\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n                returnLength = sizeof(KPH_MEMORY_MAPPED_INFORMATION);\n                goto Exit;\n            }\n\n            thread = KphGetCurrentThreadContext();\n            if (!thread)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                goto Exit;\n            }\n\n            RtlZeroMemory(&tls, sizeof(KPH_MEMORY_MAPPED_INFORMATION));\n\n            thread->VmTlsMappedInformation = &tls;\n\n            status = ZwQueryVirtualMemory(ProcessHandle,\n                                          BaseAddress,\n                                          MemoryMappedFilenameInformation,\n                                          NULL,\n                                          0,\n                                          &length);\n\n            NT_ANALYSIS_ASSUME(NT_SUCCESS(status));\n\n            if (thread->VmTlsMappedInformation)\n            {\n                thread->VmTlsMappedInformation = NULL;\n\n                KphTracePrint(TRACE_LEVEL_VERBOSE,\n                              GENERAL,\n                              \"VmTlsMappedInformation was not null! \"\n                              \"ZwQueryVirtualMemory returned: %!STATUS!\",\n                              status);\n\n                status = STATUS_UNEXPECTED_IO_ERROR;\n                goto Exit;\n            }\n\n            RtlZeroMemory(&memoryInformation, sizeof(KPH_MEMORY_MAPPED_INFORMATION));\n\n            memoryInformation.FileObject = tls.FileObject;\n            memoryInformation.SectionObjectPointers = tls.SectionObjectPointers;\n            memoryInformation.DataControlArea = tls.DataControlArea;\n            memoryInformation.SharedCacheMap = tls.SharedCacheMap;\n            memoryInformation.ImageControlArea = tls.ImageControlArea;\n            memoryInformation.UserWritableReferences = tls.UserWritableReferences;\n\n            status = KphCopyToMode(MemoryInformation,\n                                   &memoryInformation,\n                                   sizeof(KPH_MEMORY_MAPPED_INFORMATION),\n                                   AccessMode);\n            if (NT_SUCCESS(status))\n            {\n                returnLength = sizeof(KPH_MEMORY_MAPPED_INFORMATION);\n            }\n\n            break;\n        }\n        default:\n        {\n            status = STATUS_INVALID_INFO_CLASS;\n            break;\n        }\n    }\n\nExit:\n\n    if (ReturnLength)\n    {\n        KphWriteULongToMode(ReturnLength, returnLength, AccessMode);\n    }\n\n    if (mappedFileName)\n    {\n        KphFree(mappedFileName, KPH_TAG_VM_QUERY);\n    }\n\n    if (thread)\n    {\n        KphDereferenceObject(thread);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "MIT License\n\nCopyright (c) 2022 Winsider Seminars & Solutions, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n    <a href=\"https://systeminformer.com\">\n        <img src=\"https://github.com/winsiderss/systeminformer/raw/master/SystemInformer/resources/systeminformer-128x128.png\"/>\n    </a>\n    <h1 align=\"center\">System Informer</h1>\n    <h5 align=\"center\">A free, powerful, multi-purpose tool that helps you monitor system resources, debug software and detect malware.</h5>\n    <h6 align=\"center\">Brought to you by Winsider Seminars & Solutions, Inc.</h6>\n</p>\n<p align=\"center\">\n    <a href=\"https://github.com/winsiderss/systeminformer/actions/workflows/msbuild.yml\">\n        <img src=\"https://img.shields.io/github/actions/workflow/status/winsiderss/systeminformer/msbuild.yml?branch=master&style=for-the-badge\"/>\n    </a>\n    <a href=\"https://github.com/winsiderss/systeminformer/graphs/contributors\">\n        <img src=\"https://img.shields.io/github/contributors/winsiderss/systeminformer.svg?style=for-the-badge&color=blue\"/>\n    </a>\n    <a href=\"https://opensource.org/licenses/MIT\">\n        <img src=\"https://img.shields.io/badge/license-MIT-blue.svg?style=for-the-badge&color=blue\"/>\n    </a>\n</p>\n<p align=\"center\">\n    <a href=\"https://systeminformer.com/downloads\">\n        <img src=\"https://img.shields.io/github/downloads/winsiderss/si-builds/total.svg?style=for-the-badge&color=blue\"/>\n    </a>\n    <a href=\"https://somsubhra.github.io/github-release-stats/?username=winsiderss&repository=systeminformer\">\n        <img src=\"https://img.shields.io/github/downloads/winsiderss/systeminformer/total.svg?style=for-the-badge&color=blue&label=\"/>\n    </a>\n    <a href=\"https://sourceforge.net/projects/processhacker/files/stats/timeline?period=monthly\">\n        <img src=\"https://img.shields.io/sourceforge/dt/processhacker.svg?style=for-the-badge&color=blue&label=\"/>\n    </a>\n</p>\n<p align=\"center\">\n    <a href=\"https://discord.com/invite/k2MQd2DzC2\">\n        <img src=\"https://img.shields.io/badge/Discord-grey?style=for-the-badge&logoColor=white&logo=discord\"/>\n    </a>\n    <a href=\"https://x.com/systeminformer\">\n        <img src=\"https://img.shields.io/badge/Twitter-grey?style=for-the-badge&logoColor=white&logo=x\"/>\n    </a>\n    <a href=\"https://systeminformer.com\">\n        <img src=\"https://img.shields.io/badge/Website-grey?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTIgMTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBjeD0iNiIgY3k9IjYiIHI9IjUuNSIgc3Ryb2tlPSJ3aGl0ZSIvPjxlbGxpcHNlIGN4PSI2IiBjeT0iNiIgcng9IjUuNSIgcnk9IjIiIHRyYW5zZm9ybT0icm90YXRlKDkwIDYgNikiIHN0cm9rZT0id2hpdGUiLz48cGF0aCBkPSJNMSA2SDExIiBzdHJva2U9IndoaXRlIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48L3N2Zz4=\"/>\n    </a>\n</p>\n\n## System requirements\n\nWindows 10 or higher, 32-bit or 64-bit.\n\n## Features\n\n* A detailed overview of system activity with highlighting.\n* Graphs and statistics allow you quickly to track down resource hogs and\n  runaway processes.\n* Can't edit or delete a file? Discover which processes are using that file.\n* See what programs have active network connections, and close them if\n  necessary.\n* Get real-time information on disk access.\n* View detailed stack traces with kernel-mode, WOW64 and .NET support.\n* Go beyond services.msc: create, edit and control services.\n* Small, portable and no installation required.\n* 100% [Free Software](https://www.gnu.org/philosophy/free-sw.en.html)\n  ([MIT](https://opensource.org/licenses/MIT))\n\n## Building the project\n\nRequires Visual Studio (2022 or later).\n\nAfter cloning the repo run `build_init.cmd` located in the `build` directory,\nthis doesn't not run again unless there are updates to the tools or third party\nlibraries.\n\nExecute `build_release.cmd` located in the `build` directory to compile the\nproject or load the `SystemInformer.sln` and `Plugins.sln` solutions if you\nprefer building the project using Visual Studio.\n\nYou can download the free\n[Visual Studio Community Edition](https://www.visualstudio.com/vs/community/)\nto build the System Informer source code.\n\nSee the [build readme](./build/README.md) for more information or if you're\nhaving trouble building.\n\n## Enhancements/Bugs\n\nPlease use the\n[GitHub issue tracker](https://github.com/winsiderss/systeminformer/issues) for\nreporting problems or suggesting new features.\n\n## Settings\n\nIf you are running System Informer from a USB drive, you may want to\nsave System Informer's settings there as well. To do this, create a\nblank file named \"SystemInformer.exe.settings.xml\" in the same\ndirectory as SystemInformer.exe. You can do this using Windows Explorer:\n\n1. Make sure \"Hide extensions for known file types\" is unticked in\n   Tools > Folder options > View.\n2. Right-click in the folder and choose New > Text Document.\n3. Rename the file to SystemInformer.exe.settings.xml (delete the \".txt\"\n   extension).\n"
  },
  {
    "path": "README.txt",
    "content": "System Informer is a powerful free and open source process viewer.\n\n## Getting started\n\nSimply run SystemInformer.exe to start System Informer. There are two\nversions, 32-bit (x86) and 64-bit (x64). If you are not sure which\nversion to use, open Control Panel > System and check the \"System\ntype\". You cannot run the 32-bit version of System Informer on a\n64-bit system and expect it to work correctly, unlike other programs.\n\n## System requirements\n\nWindows 7 or higher, 32-bit or 64-bit.\n\n## Settings\n\nIf you are running System Informer from a USB drive, you may want to\nsave System Informer's settings there as well. To do this, create a\nblank file named \"SystemInformer.exe.settings.xml\" in the same\ndirectory as SystemInformer.exe. You can do this using Windows Explorer:\n\n1. Make sure \"Hide extensions for known file types\" is unticked in\n   Tools > Folder options > View.\n2. Right-click in the folder and choose New > Text Document.\n3. Rename the file to SystemInformer.exe.settings.xml (delete the \".txt\"\n   extension).\n\n## Plugins\n\nPlugins can be configured from Hacker > Plugins.\n\nIf you experience any crashes involving plugins, make sure they\nare up to date.\n\nThe ExtendedTools plugin is only available for Windows Vista and\nabove. Disk and Network information provided by this plugin is\nonly available when running Process Hacker with administrative\nrights.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policies and Procedures\n\nThis document outlines security procedures and general policies for the System\nInformer project.\n\n  * [Reporting a Bug](#reporting-a-bug)\n  * [Disclosure Policy](#disclosure-policy)\n\n## Reporting a Bug\n\nThe System Informer team considers security our top priority and reviews all\nreports of vulnerabilities or security issues very seriously.\n\nWe appreciate responsible disclosure efforts and are committed to acknowledging\nyour contributions.\n\nIf you discover a security issue, please send a report by emailing\nsecurity@systeminformer.com or security@systeminformer.io.\n\nThe System Informer team will acknowledge your email within 48 hours, and will\nsend a more detailed response indicating the next steps in handling your report.\nAfter the initial reply to your report, the security team will endeavor to keep\nyou informed of the progress towards a fix and full announcement, and may ask\nfor additional information or guidance.\n\nReport security bugs in third-party modules to the person or team maintaining\nthe module.\n\n## Disclosure Policy\n\nWhen the System Informer team receives a security bug report, they will assign\nit to a primary developer. This person will coordinate the fix and release\nprocess, involving the following steps:\n\n  * Confirm the problem and determine the affected versions.\n  * Audit code to find any potential similar problems.\n  * Seek review from respected third-party security experts.\n  * Prepare fixes for all releases still under maintenance. These fixes will be\n    released as fast as possible.\n"
  },
  {
    "path": "SystemInformer/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(HEADERS\n    \"include/actions.h\"\n    \"include/appsup.h\"\n    \"include/colmgr.h\"\n    \"include/colsetmgr.h\"\n    \"include/devprv.h\"\n    \"include/extmgr.h\"\n    \"include/extmgri.h\"\n    \"include/heapstruct.h\"\n    \"include/hidnproc.h\"\n    \"include/hndllist.h\"\n    \"include/hndlmenu.h\"\n    \"include/hndlprv.h\"\n    \"include/informer.h\"\n    \"include/ksisup.h\"\n    \"include/mainwnd.h\"\n    \"include/mainwndp.h\"\n    \"include/memlist.h\"\n    \"include/memprv.h\"\n    \"include/memsrch.h\"\n    \"include/miniinfo.h\"\n    \"include/miniinfop.h\"\n    \"include/modlist.h\"\n    \"include/modprv.h\"\n    \"include/netlist.h\"\n    \"include/netprv.h\"\n    \"include/notifico.h\"\n    \"include/notificop.h\"\n    \"include/notiftoast.h\"\n    \"include/phapp.h\"\n    \"include/phappres.h\"\n    \"include/phfwddef.h\"\n    \"include/phplug.h\"\n    \"include/phsettings.h\"\n    \"include/phsvc.h\"\n    \"include/phsvcapi.h\"\n    \"include/phsvccl.h\"\n    \"include/phuisup.h\"\n    \"include/procgrp.h\"\n    \"include/procmtgn.h\"\n    \"include/procprp.h\"\n    \"include/procprpp.h\"\n    \"include/procprv.h\"\n    \"include/proctree.h\"\n    \"include/srvlist.h\"\n    \"include/srvprv.h\"\n    \"include/sysinfo.h\"\n    \"include/sysinfop.h\"\n    \"include/thrdlist.h\"\n    \"include/thrdprv.h\"\n    \"resource.h\"\n    \"sdk/phdk.h\"\n)\nsource_group(\"Header Files\" FILES ${HEADERS})\n\nset(RESOURCES\n    \"version.rc\"\n    \"SystemInformer.def\"\n    \"SystemInformer.rc\"\n    \"SystemInformer.manifest\"\n    \"resources/application.ico\"\n    \"resources/capslist.txt\"\n    \"resources/case_sensitive_modern_dark.svg\"\n    \"resources/case_sensitive_modern_light.svg\"\n    \"resources/cog.ico\"\n    \"resources/etwguids.txt\"\n    \"resources/pooltag.txt\"\n    \"resources/regex_modern_dark.svg\"\n    \"resources/regex_modern_light.svg\"\n    \"resources/search_modern_dark.svg\"\n    \"resources/search_modern_light.svg\"\n    \"resources/search_stop_modern_dark.svg\"\n    \"resources/search_stop_modern_light.svg\"\n    \"resources/systeminformer.png\"\n    \"SystemInformer.ico\"\n)\nsource_group(\"Resource Files\" FILES ${RESOURCES})\n\nset(SOURCES\n    \"about.c\"\n    \"actions.c\"\n    \"admintask.c\"\n    \"affinity.c\"\n    \"anawait.c\"\n    \"appsup.c\"\n    \"chcol.c\"\n    \"chdlg.c\"\n    \"chproc.c\"\n    \"colmgr.c\"\n    \"colsetmgr.c\"\n    \"dbgcon.c\"\n    \"delayhook.c\"\n    \"delayload.c\"\n    \"devprv.c\"\n    \"extmgr.c\"\n    \"findobj.c\"\n    \"gdihndl.c\"\n    \"heapinfo.c\"\n    \"hidnproc.c\"\n    \"hndllist.c\"\n    \"hndlmenu.c\"\n    \"hndlprp.c\"\n    \"hndlprv.c\"\n    \"hndlstat.c\"\n    \"infodlg.c\"\n    \"informer.c\"\n    \"itemtips.c\"\n    \"jobprp.c\"\n    \"kdump.c\"\n    \"ksidbg.c\"\n    \"ksisup.c\"\n    \"ksyscall.c\"\n    \"log.c\"\n    \"logwnd.c\"\n    \"main.c\"\n    \"mainwnd.c\"\n    \"mdump.c\"\n    \"memedit.c\"\n    \"memlist.c\"\n    \"memlists.c\"\n    \"memmod.c\"\n    \"memprot.c\"\n    \"memprv.c\"\n    \"memrslt.c\"\n    \"memsrch.c\"\n    \"memsrcht.c\"\n    \"miniinfo.c\"\n    \"modlist.c\"\n    \"modprv.c\"\n    \"mtgndlg.c\"\n    \"mwpgdev.c\"\n    \"mwpgnet.c\"\n    \"mwpgproc.c\"\n    \"mwpgsrv.c\"\n    \"netlist.c\"\n    \"netprv.c\"\n    \"netsup.c\"\n    \"notifico.c\"\n    \"notiftoast.cpp\"\n    \"ntobjprp.c\"\n    \"options.c\"\n    \"pagfiles.c\"\n    \"plugin.c\"\n    \"plugman.c\"\n    \"procgrp.c\"\n    \"procmtgn.c\"\n    \"procprp.c\"\n    \"procprv.c\"\n    \"procrec.c\"\n    \"proctree.c\"\n    \"prpgenv.c\"\n    \"prpggen.c\"\n    \"prpghndl.c\"\n    \"prpgjob.c\"\n    \"prpgmem.c\"\n    \"prpgmod.c\"\n    \"prpgperf.c\"\n    \"prpgsrv.c\"\n    \"prpgstat.c\"\n    \"prpgthrd.c\"\n    \"prpgtok.c\"\n    \"prpgvdm.c\"\n    \"prpgwmi.c\"\n    \"runas.c\"\n    \"searchbox.c\"\n    \"sessmsg.c\"\n    \"sessprp.c\"\n    \"sessshad.c\"\n    \"settings.c\"\n    \"srvcr.c\"\n    \"srvctl.c\"\n    \"srvlist.c\"\n    \"srvprp.c\"\n    \"srvprv.c\"\n    \"sysinfo.c\"\n    \"syssccpu.c\"\n    \"sysscio.c\"\n    \"sysscmem.c\"\n    \"thrdlist.c\"\n    \"thrdprv.c\"\n    \"thrdstk.c\"\n    \"thrdstks.c\"\n    \"tokprp.c\"\n    \"usrlist.c\"\n    \"phsvc/clapi.c\"\n    \"phsvc/svcapi.c\"\n    \"phsvc/svcapiport.c\"\n    \"phsvc/svcclient.c\"\n    \"phsvc/svcmain.c\"\n)\nsource_group(\"Source Files\" FILES ${SOURCES})\n\nset(ALL_FILES\n    ${HEADERS}\n    ${RESOURCES}\n    ${SOURCES}\n)\n\nsi_add_executable(SystemInformer WIN32 ${ALL_FILES})\n\nset_target_properties(SystemInformer PROPERTIES ENABLE_EXPORTS TRUE)\n\ntarget_include_directories(SystemInformer PRIVATE\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include\"\n)\n\ntarget_include_directories(SystemInformer INTERFACE\n    \"${SI_ROOT}/phnt/include\"\n    \"${SI_ROOT}/sdk/include\"\n)\n\ntarget_compile_definitions(SystemInformer PRIVATE\n    _PHAPP_\n)\n\ntarget_link_libraries(SystemInformer PRIVATE\n    phnt\n    phlib\n    kphlib_um\n    delayimp\n    user32\n    gdi32\n    comdlg32\n    advapi32\n    ole32\n    oleaut32\n    setupapi\n    cfgmgr32\n    aclui\n    comctl32\n    dnsapi\n    ntdll\n    userenv\n    wbemuuid\n    windowscodecs\n    winhttp\n    winsta\n)\n\ntarget_link_options(SystemInformer PRIVATE\n    /DELAYLOAD:setupapi.dll\n    /DELAYLOAD:cfgmgr32.dll\n    /DELAYLOAD:aclui.dll\n    /DELAYLOAD:comdlg32.dll\n    /DELAYLOAD:gdiplus.dll\n    /DELAYLOAD:oleaut32.dll\n    /DELAYLOAD:winhttp.dll\n    /DELAYLOAD:winsta.dll\n)\n\nsi_sdkbuild(SystemInformer)\n"
  },
  {
    "path": "SystemInformer/Directory.Build.props",
    "content": "<Project>\n  <!-- Merge with parent Directory.Build.props -->\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />\n  <Import Project=\"$(SystemInformerRoot)/Common.User.props\" />\n</Project>\n"
  },
  {
    "path": "SystemInformer/SystemInformer.def",
    "content": ";/*\n; * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n; *\n; * This file is part of System Informer.\n; *\n; * Authors:\n; *\n; *     wj32    2008-2016\n; *     dmex    2017-2024\n; *\n; */\n\n;\n; This file was automatically generated.\n;\n; Do not link at runtime. Use the SystemInformer.def.h header file instead.\n;\n\nEXPORTS\n\n; main\n    PhAddProcessPropPage\n    PhAddProcessPropPage2\n    PhAddPropPageLayoutItem\n    PhAddTreeNewFilter\n    PhAggregateProcessFieldIfNeeded\n    PhApplyTreeNewFilters\n    PhApplyTreeNewFiltersToNode\n    PhChoiceDialog\n    PhCmLoadSettings\n    PhCmSaveSettings\n    PhCopyListView\n    PhCopyListViewInfoTip\n    PhCreateKsiSettingsBlob\n    PhCreateHandleItem\n    PhCreateProcessPropContext\n    PhCreateProcessPropPageContext\n    PhCreateProcessPropPageContextEx\n    PhCreateSearchControl\n    PhCreateServiceListControl\n    PhDeleteMemoryItemList\n    PhDeleteStaticWindowIcon\n    PhDeleteTreeNewColumnMenu\n    PhDeleteTreeNewFilterSupport\n    PhDereferenceProcessRecord\n    PhDeselectAllProcessNodes\n    PhDeselectAllServiceNodes\n    PhDeselectAllNetworkNodes\n    PhDestroyWindowIcon\n    PhDeviceProviderInitialization\n    PhDoPropPageLayout\n    PhDuplicateProcessInformation\n    PhDuplicateProcessNodeList\n    PhEnumDeviceResources\n    PhEnumNetworkItems\n    PhEnumNetworkItemsByProcessId\n    PhEnumProcessItems\n    PhExecuteRunAsCommand2\n    PhExecuteRunAsCommand3\n    PhExpandAllProcessNodes\n    PhFindNetworkNode\n    PhFindProcessNode\n    PhFindProcessRecord\n    PhFindServiceNode\n    PhFormatLocalSystemTimeISO\n    PhFormatLogEntry\n    PhFormatLogType\n    PhFreezeThread\n    PhGetApplicationIcon\n    PhGetApplicationIconEx\n    PhGetClientIdName\n    PhGetClientIdNameEx\n    PhGetDeviceIcon\n    PhGetDeviceProperty\n    PhGetFilterSupportNetworkTreeList\n    PhGetFilterSupportProcessTreeList\n    PhGetFilterSupportServiceTreeList\n    PhGetGeneralCallback\n    PhGetImageListIcon\n    PhGetListViewContextMenuPoint\n    PhGetPhReleaseChannel\n    PhGetPhReleaseChannelString\n    PhGetPhVersion\n    PhGetPhVersionHash\n    PhGetPhVersionNumbers\n    PhGetProcessIsSuspended\n    PhGetProcessKnownType\n    PhGetProcessKnownTypeEx\n    PhGetProcessPriorityClassString\n    PhGetProcessSmallImageList\n    PhGetProtocolTypeName\n    PhGetSelectedAndPropagateProcessItems\n    PhGetSelectedProcessItem\n    PhGetSelectedProcessItems\n    PhGetSelectedProcessNode\n    PhGetSelectedProcessNodes\n    PhGetSelectedServiceItem\n    PhGetSelectedServiceItems\n    PhGetServiceChange\n    PhGetShieldBitmap\n    PhGetStatisticsTime\n    PhGetStatisticsTimeString\n    PhGetTcpStateName\n    PhHandleCopyCellEMenuItem\n    PhHandleCopyListViewEMenuItem\n    PhHandleListViewNotifyBehaviors\n    PhHandleListViewNotifyForCopy\n    PhHandleTreeNewColumnMenu\n    PhImageListExtractIcon\n    PhImageListFlushCache\n    PhInitializeTreeNewColumnMenu\n    PhInitializeTreeNewColumnMenuEx\n    PhInitializeTreeNewFilterSupport\n    PhInsertCopyCellEMenuItem\n    PhInsertCopyListViewEMenuItem\n    PhInsertHandleObjectPropertiesEMenuItems\n    PhInvalidateAllProcessNodes\n    PhIsProcessBackground\n    PhIsProcessSuspended\n    PhLoadSymbolProviderOptions\n    PhLogMessageEntry\n    PhLookupDeviceItem\n    PhLookupDeviceItemByHash\n    PhLookupDevicePropertyClass\n    PhLookupMemoryItemList\n    PhProcessImageListInitialization\n    PhPropPageDlgProcHeader\n    PhQueryKphCounters\n    PhQueryMemoryItemList\n    PhReferenceDeviceItem\n    PhReferenceDeviceItem2\n    PhReferenceDeviceItemByHash\n    PhReferenceDeviceTree\n    PhReferenceDeviceTreeEx\n    PhReferenceNetworkItem\n    PhReferenceProcessItem\n    PhReferenceProcessItemForParent\n    PhReferenceProcessItemForRecord\n    PhReferenceProcessRecord\n    PhReferenceProcessRecordForStatistics\n    PhReferenceProcessRecordSafe\n    PhReferenceServiceItem\n    PhRegisterDialog\n    PhRegisterMessageLoopFilter\n    PhRemoveTreeNewFilter\n    PhSearchControlClear\n    PhSearchControlMatch\n    PhSearchControlMatchLongHintZ\n    PhSearchControlMatchPointer\n    PhSearchControlMatchPointerRange\n    PhSearchControlMatchZ\n    PhSearchOnlineString\n    PhSelectAndEnsureVisibleProcessNode\n    PhSelectAndEnsureVisibleServiceNode\n    PhSetApplicationWindowIcon\n    PhSetApplicationWindowIconEx\n    PhSetProcessItemAffinityMask\n    PhSetProcessItemIoPriority\n    PhSetProcessItemPagePriority\n    PhSetProcessItemPriority\n    PhSetProcessItemPriorityBoost\n    PhSetProcessItemThrottlingState\n    PhSetSelectThreadIdProcessPropContext\n    PhSetStaticWindowIcon\n    PhSetWindowIcon\n    PhShellExecuteUserString\n    PhShellOpenKey\n    PhShellOpenKey2\n    PhShellProcessHacker\n    PhShowChooseProcessDialog\n    PhShowHandleObjectProperties1\n    PhShowHandleObjectProperties2\n    PhShowIconNotification\n    PhShowIconNotificationEx\n    PhShowProcessAffinityDialog2\n    PhShowProcessProperties\n    PhShowProcessRecordDialog\n    PhShowSystemInformationDialog\n    PhShowThreadAffinityDialog\n    PhSiDoubleLabelYFunction\n    PhSiSetColorsGraphDrawInfo\n    PhSiSizeLabelYFunction\n    PhSiUInt64LabelYFunction\n    PhThawThread\n    PhUnregisterDialog\n    PhUnregisterMessageLoopFilter\n    PhUpdateProcessNode\n    PhUpdateServiceNode\n    PhWordMatchStringRef\n    PhWritePhTextHeader\n    PhaChoiceDialog\n    PhaGetProcessKnownCommandLine\n\n; plugin\n    PhEnumeratePlugins\n    PhFindPlugin2\n    PhGetPluginCallback\n    PhGetPluginFileName\n    PhGetPluginInformation\n    PhGetPluginInterface\n    PhGetPluginName\n    PhPluginAddMenuHook\n    PhPluginAddTreeNewColumn\n    PhPluginCallPhSvc\n    PhPluginCreateEMenuItem\n    PhPluginCreateTabPage\n    PhPluginEnableTreeNewNotify\n    PhPluginGetObjectExtension\n    PhPluginGetSystemStatistics\n    PhPluginInvokeWindowCallback\n    PhPluginQueryPhSvc\n    PhPluginReserveIds\n    PhPluginSetObjectExtension\n    PhRegisterPluginByName\n\n; phsvc\n    PhSvcCallChangeServiceConfig\n    PhSvcCallChangeServiceConfig2\n    PhSvcCallPostMessage\n    PhSvcCallSendMessage\n\n; UI\n    PhUiCloseConnections\n    PhUiCloseHandles\n    PhUiConnectSession\n    PhUiConnectToPhSvc\n    PhUiConnectToPhSvcEx\n    PhUiContinueService\n    PhUiContinueServices\n    PhUiDebugProcess\n    PhUiDeleteService\n    PhUiDetachFromDebuggerProcess\n    PhUiDisconnectFromPhSvc\n    PhUiDisconnectSession\n    PhUiEmptyProcessMemoryWorkingSet\n    PhUiFlushHeapProcesses\n    PhUiFreeMemory\n    PhUiFreezeTreeProcess\n    PhUiHibernateComputer\n    PhUiLoadDllProcess\n    PhUiLockComputer\n    PhUiLogoffComputer\n    PhUiLogoffSession\n    PhUiPauseService\n    PhUiPauseServices\n    PhUiReduceWorkingSetProcesses\n    PhUiRestartComputer\n    PhUiRestartProcess\n    PhUiRestartServices\n    PhUiResumeProcesses\n    PhUiResumeThreads\n    PhUiResumeTreeProcess\n    PhUiSetActivityModeration\n    PhUiSetAttributesHandle\n    PhUiSetBoostPriorityProcess\n    PhUiSetBoostPriorityProcesses\n    PhUiSetBoostPriorityThread\n    PhUiSetBoostPriorityThreads\n    PhUiSetCriticalProcess\n    PhUiSetEcoModeProcess\n    PhUiSetEmptyWorkingSetProcesses\n    PhUiSetExecutionRequiredProcess\n    PhUiSetIoPriorityProcesses\n    PhUiSetIoPriorityThread\n    PhUiSetPagePriorityProcess\n    PhUiSetPagePriorityThread\n    PhUiSetPriorityClassProcesses\n    PhUiSetPriorityThread\n    PhUiSetPriorityThreads\n    PhUiSetVirtualizationProcess\n    PhUiShutdownComputer\n    PhUiSleepComputer\n    PhUiStartService\n    PhUiStartServices\n    PhUiStopService\n    PhUiStopServices\n    PhUiSuspendProcesses\n    PhUiSuspendThreads\n    PhUiSuspendTreeProcess\n    PhUiTerminateProcesses\n    PhUiTerminateThreads\n    PhUiTerminateTreeProcess\n    PhUiThawTreeProcess\n    PhUiUnloadModule\n\n;\n; phlib exports\n;\n\n; ref\n    PhAutoDereferenceObject\n    PhCreateAlloc\n    PhCreateObject\n    PhCreateObjectType\n    PhCreateObjectTypeEx\n    PhDeleteAutoPool\n    PhDereferenceObject\n    PhDereferenceObjectDeferDelete\n    PhDereferenceObjectEx\n    PhDrainAutoPool\n    PhGetObjectType\n    PhGetObjectTypeInformation\n    PhInitializeAutoPool\n    PhReferenceObject\n    PhReferenceObjectEx\n    PhReferenceObjectSafe\n\n; queuedlock\n    PhfAcquireQueuedLockExclusive\n    PhfAcquireQueuedLockShared\n    PhfPulseAllCondition\n    PhfPulseCondition\n    PhfQueueWakeEvent\n    PhfReleaseQueuedLockExclusive\n    PhfReleaseQueuedLockShared\n    PhfSetWakeEvent\n    PhfWaitForCondition\n    PhfWaitForConditionEx\n    PhfWaitForWakeEvent\n    PhfWakeForReleaseQueuedLock\n\n; phconfig\n    PhIsExecutingInWow64\n    PhSystemBasicInformation DATA\n\n; phbasesup\n    PhAddElementAvlTree\n    PhAddEntryHashtable\n    PhAddEntryHashtableEx\n    PhAddItemArray\n    PhAddItemList\n    PhAddItemPointerList\n    PhAddItemSimpleHashtable\n    PhAddItemsArray\n    PhAddItemsList\n    PhAddPlusMaxMemorySingles\n    PhAllocate\n    PhAllocateExSafe\n    PhAllocateFromFreeList\n    PhAllocatePage\n    PhAllocateSafe\n    PhAppendBytesBuilder\n    PhAppendBytesBuilderEx\n    PhAppendCharStringBuilder\n    PhAppendCharStringBuilder2\n    PhAppendFormatStringBuilder\n    PhAppendFormatStringBuilder_V\n    PhAppendFormatBytesBuilder\n    PhAppendFormatBytesBuilder_V\n    PhAppendStringBuilderEx\n    PhBufferToHexString\n    PhBufferToHexStringEx\n    PhClearArray\n    PhClearHashtable\n    PhClearList\n    PhCompareStringRef\n    PhCompareStringZNatural\n    PhConcatStringRef2\n    PhConcatStringRef3\n    PhConcatStringRef4\n    PhConcatStrings\n    PhConcatStrings2\n    PhConcatStrings_V\n    PhConvertMultiByteToUtf16\n    PhConvertMultiByteToUtf16Ex\n    PhConvertUtf16ToAsciiEx\n    PhConvertUtf16ToMultiByte\n    PhConvertUtf16ToMultiByteEx\n    PhConvertUtf16ToUtf8\n    PhConvertUtf16ToUtf8Buffer\n    PhConvertUtf16ToUtf8Ex\n    PhConvertUtf16ToUtf8Size\n    PhConvertUtf8ToUtf16\n    PhConvertUtf8ToUtf16Buffer\n    PhConvertUtf8ToUtf16Ex\n    PhConvertUtf8ToUtf16Size\n    PhCopyBytesZ\n    PhCopyConvertCircularBufferULONG\n    PhCopyStringZ\n    PhCopyStringZFromBytes\n    PhCopyStringZFromMultiByte\n    PhCountStringZ\n    PhCreateBytesEx\n    PhCreateHashtable\n    PhCreateList\n    PhCreatePointerList\n    PhCreateSimpleHashtable\n    PhCreateString3\n    PhCreateStringEx\n    PhCreateThread\n    PhCreateThread2\n    PhCreateThreadEx\n    PhDecodeUnicodeDecoder\n    PhDelayExecution\n    PhDeleteArray\n    PhDeleteBytesBuilder\n    PhDeleteCallback\n    PhDeleteFreeList\n    PhDeleteStringBuilder\n    PhDivideSinglesBySingle\n    PhDoesNameContainWildCards\n    PhDosErrorToNtStatus\n    PhDuplicateBytesZ\n    PhDuplicateBytesZSafe\n    PhDuplicateStringZ\n    PhEncodeUnicode\n    PhEnumAvlTree\n    PhEnumHashtable\n    PhEnumPointerListEx\n    PhEqualStringRef\n    PhExponentiate\n    PhExponentiate64\n    PhExtractIcon\n    PhExtractIconEx\n    PhFillMemoryUlong\n    PhFinalBytesBuilderBytes\n    PhFinalStringBuilderString\n    PhFindCharInStringRef\n    PhFindElementAvlTree\n    PhFindEntryHashtable\n    PhFindItemList\n    PhFindItemPointerList\n    PhFindItemSimpleHashtable\n    PhFindLastCharInStringRef\n    PhFindStringInStringRef\n    PhFormat\n    PhFormatBytes\n    PhFormatBytes_V\n    PhFormatString\n    PhFormatString_V\n    PhFormatSystemTimeISO\n    PhFormatToBuffer\n    PhFree\n    PhFreePage\n    PhFreeToFreeList\n    PhGetLastError\n    PhGetPrimeNumber\n    PhHashBytes\n    PhHashStringRef\n    PhHashStringRefEx\n    PhHexStringToBuffer\n    PhHexStringToBufferEx\n    PhHungWindowFromGhostWindow\n    PhInitializeArray\n    PhInitializeAvlTree\n    PhInitializeBytesBuilder\n    PhInitializeCallback\n    PhInitializeFreeList\n    PhInitializeStringBuilder\n    PhInsertItemList\n    PhInsertItemsList\n    PhInsertStringBuilder\n    PhInsertStringBuilder2\n    PhInsertStringBuilderEx\n    PhIntegerToString64\n    PhInvokeCallback\n    PhIsNameInExpression\n    PhLoadIndirectString\n    PhLoadResource\n    PhLocalTimeToSystemTime\n    PhLowerBoundElementAvlTree\n    PhLowerDualBoundElementAvlTree\n    PhMaxMemorySingles\n    PhMaximumElementAvlTree\n    PhMinimumElementAvlTree\n    PhNtStatusFileNotFound\n    PhNtStatusToDosError\n    PhPredecessorElementAvlTree\n    PhPrintTimeSpan\n    PhQueryPerformanceCounter\n    PhQueryPerformanceFrequency\n    PhQuerySystemTime\n    PhQueryTimeZoneBias\n    PhReAllocate\n    PhReAllocateSafe\n    PhReferenceEmptyString\n    PhRegisterCallback\n    PhRegisterCallbackEx\n    PhRemoveElementAvlTree\n    PhRemoveEntryHashtable\n    PhRemoveItemArray\n    PhRemoveItemList\n    PhRemoveItemPointerList\n    PhRemoveItemSimpleHashtable\n    PhRemoveItemsArray\n    PhRemoveItemsList\n    PhRemoveStringBuilder\n    PhResizeArray\n    PhResizeList\n    PhRoundUpToPowerOfTwo\n    PhSecondsSince1970ToTime\n    PhSplitStringRefAtChar\n    PhSplitStringRefAtLastChar\n    PhSplitStringRefAtString\n    PhSplitStringRefEx\n    PhSplitStringRef\n    PhFreeStringArray\n    PhStringFuzzyMatch\n    PhStringToDouble\n    PhStringToInteger64\n    PhStringToUInt64\n    PhSuccessorElementAvlTree\n    PhSystemTimeToLocalTime\n    PhTimeToSecondsSince1970\n    PhTrimStringRef\n    PhUnregisterCallback\n    PhUpperBoundElementAvlTree\n    PhUpperDualBoundElementAvlTree\n    PhWriteUnicodeDecoder\n    PhZeroExtendToUtf16Buffer\n    PhZeroExtendToUtf16Ex\n    PhfAcquireRundownProtection\n    PhfBeginInitOnce\n    PhfEndInitOnce\n    PhfInitializeBarrier\n    PhfInitializeEvent\n    PhfInitializeInitOnce\n    PhfInitializeRundownProtection\n    PhfReleaseRundownProtection\n    PhfResetEvent\n    PhfSetEvent\n    PhfWaitForBarrier\n    PhfWaitForEvent\n    PhfWaitForRundownProtection\n\n; phfirmware\n    PhEnumSMBIOS\n    PhGetSMBIOSString\n\n; phnative\n    PhAdjustPrivilege\n    PhConnectPipe\n    PhCreateDirectoryFullPathWin32\n    PhCreateDirectoryWin32\n    PhCreateEvent\n    PhCreateFile\n    PhCreateFileWin32\n    PhCreateFileWin32Ex\n    PhCreateKey\n    PhCreateNamedPipe\n    PhCreatePipe\n    PhDeleteDirectoryWin32\n    PhDeleteFile\n    PhDeleteFileWin32\n    PhDeleteValueKey\n    PhDestroyWindowRemote\n    PhDetermineDosPathNameType\n    PhDeviceIoControlFile\n    PhDisconnectNamedPipe\n    PhDoesFileExist\n    PhDoesFileExistWin32\n    PhDosPathNameToNtPathName\n    PhEnumBigPoolInformation\n    PhEnumDirectoryFile\n    PhEnumDirectoryObjects\n    PhEnumFileStreams\n    PhEnumFirmwareEnvironmentValues\n    PhEnumGenericModules\n    PhEnumHandlesEx\n    PhEnumKernelModules\n    PhEnumNextProcess\n    PhEnumNextThread\n    PhEnumObjectIdInformation\n    PhEnumPagefiles\n    PhEnumPoolTagInformation\n    PhEnumProcessEnvironmentVariables\n    PhEnumProcesses\n    PhEnumProcessesEx\n    PhEnumReparsePointInformation\n    PhEnumerateKey\n    PhEnumerateValueKey\n    PhEnumerateValueKeyEx\n    PhFilterConnectCommunicationPort\n    PhFindProcessInformation\n    PhFindProcessInformationByImageName\n    PhGetActiveProcessorCount\n    PhGetContextThread\n    PhGetDeviceType\n    PhGetDllHandle\n    PhGetDriverImageFileName\n    PhGetDriverName\n    PhGetDriverServiceKeyName\n    PhGetFileFullAttributesInformation\n    PhGetFileName\n    PhGetFilePosition\n    PhGetFileSize\n    PhGetFirmwareEnvironmentVariable\n    PhGetJobProcessIdList\n    PhGetKernelFileName\n    PhGetKernelFileNameEx\n    PhGetModuleProcAddress\n    PhGetNamedPipeClientComputerName\n    PhGetNamedPipeClientProcessId\n    PhGetNamedPipeServerProcessId\n    PhGetObjectSecurity\n    PhGetObjectTypeIndexName\n    PhGetObjectTypeNumber\n    PhGetOwnTokenAttributes\n    PhGetPnPDeviceName\n    PhGetProcedureAddress\n    PhGetProcedureAddressRemote\n    PhGetProcessAffinityMask\n    PhGetProcessCommandLine\n    PhGetProcessDepStatus\n    PhGetProcessDeviceMap\n    PhGetProcessEnvironment\n    PhGetProcessExtendedBasicInformation\n    PhGetProcessGroupAffinity\n    PhGetProcessGroupInformation\n    PhGetProcessImageFileName\n    PhGetProcessImageFileNameById\n    PhGetProcessImageFileNameByProcessId\n    PhGetProcessImageFileNameWin32\n    PhGetProcessIoPriority\n    PhGetProcessIsDotNet\n    PhGetProcessIsDotNetEx\n    PhGetProcessIsTerminated\n    PhGetProcessIsWow64\n    PhGetProcessMappedFileName\n    PhGetProcessPagePriority\n    PhGetProcessPebString\n    PhGetProcessPowerThrottlingState\n    PhGetProcessPriorityBoost\n    PhGetProcessPriorityClass\n    PhGetProcessUnloadedDlls\n    PhGetProcessWindowTitle\n    PhGetProcessWorkingSetInformation\n    PhGetProcessWsCounters\n    PhGetSectionFileName\n    PhGetThreadBasePriority\n    PhGetThreadBasicInformation\n    PhGetThreadIsTerminated\n    PhGetThreadIoPriority\n    PhGetThreadName\n    PhGetTokenAppContainerSid\n    PhGetTokenGroups\n    PhGetTokenIntegrityLevel\n    PhGetTokenIntegrityLevelRID\n    PhGetTokenOwner\n    PhGetTokenPackageFullName\n    PhGetTokenPrimaryGroup\n    PhGetTokenPrivileges\n    PhGetTokenUser\n    PhImpersonateToken\n    PhIsDebuggerPresent\n    PhIsFirmwareSupported\n    PhListenNamedPipe\n    PhLoadAppKey\n    PhMoveFileWin32\n    PhOpenDirectoryObject\n    PhOpenDriver\n    PhOpenFile\n    PhOpenFileById\n    PhOpenKey\n    PhOpenProcess\n    PhOpenProcessClientId\n    PhOpenProcessToken\n    PhOpenThread\n    PhOpenThreadClientId\n    PhOpenThreadProcess\n    PhPeekNamedPipe\n    PhQueryEnvironmentVariable\n    PhQueryFullAttributesFileWin32\n    PhQueryKey\n    PhQueryKeyLastWriteTime\n    PhQuerySymbolicLinkObject\n    PhQueryTokenVariableSize\n    PhQueryValueKey\n    PhQueueUserWorkItem\n    PhReadFile\n    PhResolveDevicePrefix\n    PhRevertImpersonationToken\n    PhSetFileAllocationSize\n    PhSetFileIoPriorityHint\n    PhSetFilePosition\n    PhSetFileSize\n    PhSetFirmwareEnvironmentVariable\n    PhSetObjectSecurity\n    PhSetProcessPowerThrottlingState\n    PhSetProcessPriorityBoost\n    PhSetProcessPriorityClass\n    PhSetThreadBasePriority\n    PhSetThreadIoPriority\n    PhSetThreadName\n    PhSetTokenIsVirtualizationEnabled\n    PhSetTokenPrivilege\n    PhSetTokenPrivilege2\n    PhSetTokenSessionId\n    PhSetValueKey\n    PhTerminateProcess\n    PhTraceControl\n    PhTransceiveNamedPipe\n    PhUnloadDllProcess\n    PhUnloadDriver\n    PhUpdateDosDevicePrefixes\n    PhUpdateMupDevicePrefixes\n    PhWaitForNamedPipe\n    PhWriteFile\n\n; phutil\n    PhAdjustRectangleToBounds\n    PhAdjustRectangleToWorkingArea\n    PhCenterRectangle\n    PhCenterWindow\n    PhCompareUnicodeStringZIgnoreMenuPrefix\n    PhConsoleSetForeground\n    PhConsoleSetWindow\n    PhCreateOpenFileDialog\n    PhCreateProcess\n    PhCreateProcessAsUser\n    PhCreateProcessRedirection\n    PhCreateProcessWin32\n    PhCreateProcessWin32Ex\n    PhCreateSaveFileDialog\n    PhDeleteImageVersionInfo\n    PhDevFreeObjectProperties\n    PhDevFreeObjects\n    PhDevGetObjectProperties\n    PhDevGetObjects\n    PhEllipsisString\n    PhEllipsisStringPath\n    PhEscapeCommandLinePart\n    PhEscapeStringForMenuPrefix\n    PhExpandEnvironmentStrings\n    PhFileReadAllTextWin32\n    PhFinalHash\n    PhFormatDate\n    PhFormatDateTime\n    PhFormatDecimal\n    PhFormatGuid\n    PhFormatImageVersionInfo\n    PhFormatSize\n    PhFormatTime\n    PhFormatTimeSpan\n    PhFormatTimeSpanRelative\n    PhFormatUInt64\n    PhFreeFileDialog\n    PhFreeLibrary\n    PhFreeLibraryAsImageResource\n    PhGenerateGuid\n    PhGenerateGuidFromName\n    PhGenerateRandomAlphaString\n    PhGenerateRandomNumber64\n    PhGetApplicationDataFileName\n    PhGetApplicationDirectory\n    PhGetApplicationDirectoryFileName\n    PhGetApplicationDirectoryWin32\n    PhGetApplicationFileNameWin32\n    PhGetApplicationFileName\n    PhGetBaseDirectory\n    PhGetBaseName\n    PhGetClassObject\n    PhGetDllFileName\n    PhGetDpiValue\n    PhGetFileDialogFileName\n    PhGetFileDialogFilterIndex\n    PhGetFileDialogOptions\n    PhGetFileVersionFixedInfo\n    PhGetFileVersionInfo\n    PhGetFileVersionInfoEx\n    PhGetFileVersionInfoLangCodePage\n    PhGetFileVersionInfoString\n    PhGetFileVersionInfoString2\n    PhGetFullPath\n    PhGetKnownFolderPath\n    PhGetKnownLocation\n    PhGetMessage\n    PhGetMonitorDpi\n    PhGetNtMessage\n    PhGetNtSystemRoot\n    PhGetRoamingAppDataDirectory\n    PhGetStatusMessage\n    PhGetSystemDirectory\n    PhGetSystemDpi\n    PhGetSystemMetrics\n    PhGetSystemParametersInfo\n    PhGetSystemRoot\n    PhGetTaskbarDpi\n    PhGetTemporaryDirectoryRandomAlphaFileName\n    PhGetUserLocaleInfoBool\n    PhGetWin32Message\n    PhGetWindowDpi\n    PhInitializeHash\n    PhInitializeImageVersionInfo\n    PhInitializeImageVersionInfoEx\n    PhInitializeProcThreadAttributeList\n    PhLargeIntegerToLocalSystemTime\n    PhLargeIntegerToSystemTime\n    PhLoadLibrary\n    PhLoadLibraryAsImageResource\n    PhMapFlags1\n    PhMapFlags2\n    PhMatchWildcards\n    PhParseCommandLine\n    PhParseCommandLineFuzzy\n    PhParseCommandLinePart\n    PhQueryRegistryString\n    PhQueryRegistryUlong\n    PhQueryRegistryUlong64\n    PhSetFileDialogFileName\n    PhSetFileDialogFilter\n    PhSetFileDialogOptions\n    PhShellExecute\n    PhShellExecuteEx\n    PhShellExploreFile\n    PhShellProperties\n    PhShowConfirmMessage\n    PhShowContinueStatus\n    PhShowFileDialog\n    PhShowMessage\n    PhShowMessage2\n    PhShowMessageOneTime\n    PhShowStatus\n    PhShowTaskDialog\n    PhStringToGuid\n    PhSystemTimeToLargeInteger\n    PhSystemTimeToTzSpecificLocalTime\n    PhTaskbarListCreate\n    PhTaskbarListDestroy\n    PhTaskbarListSetOverlayIcon\n    PhTaskbarListSetProgressState\n    PhTaskbarListSetProgressValue\n    PhUpdateHash\n    PhUpdateProcThreadAttribute\n    PhWaitForMultipleObjectsAndPump\n\n; circbuf\n    PhClearCircularBuffer_FLOAT\n    PhClearCircularBuffer_PVOID\n    PhClearCircularBuffer_ULONG\n    PhClearCircularBuffer_ULONG64\n    PhCopyCircularBuffer_FLOAT\n    PhCopyCircularBuffer_PVOID\n    PhCopyCircularBuffer_ULONG\n    PhCopyCircularBuffer_ULONG64\n    PhDeleteCircularBuffer_FLOAT\n    PhDeleteCircularBuffer_PVOID\n    PhDeleteCircularBuffer_ULONG\n    PhDeleteCircularBuffer_ULONG64\n    PhInitializeCircularBuffer_FLOAT\n    PhInitializeCircularBuffer_PVOID\n    PhInitializeCircularBuffer_ULONG\n    PhInitializeCircularBuffer_ULONG64\n    PhResizeCircularBuffer_FLOAT\n    PhResizeCircularBuffer_PVOID\n    PhResizeCircularBuffer_ULONG\n    PhResizeCircularBuffer_ULONG64\n\n; cpysave\n    PhGetGenericTreeNewLines\n    PhGetListViewItemText\n    PhGetListViewSelectedItemText\n    PhGetTreeNewText\n\n; emenu\n    PhCreateEMenu\n    PhCreateEMenuItem\n    PhDestroyEMenu\n    PhDestroyEMenuItem\n    PhFindEMenuItem\n    PhIndexOfEMenuItem\n    PhInsertEMenuItem\n    PhLoadResourceEMenuItem\n    PhModifyEMenuItem\n    PhRemoveAllEMenuItems\n    PhRemoveEMenuItem\n    PhSetFlagsAllEMenuItems\n    PhSetFlagsEMenuItem\n    PhShowEMenu\n\n; fastlock\n    PhDeleteFastLock\n    PhInitializeFastLock\n    PhfAcquireFastLockExclusive\n    PhfAcquireFastLockShared\n    PhfReleaseFastLockExclusive\n    PhfReleaseFastLockShared\n    PhfTryAcquireFastLockExclusive\n    PhfTryAcquireFastLockShared\n\n; filestream\n    PhCreateFileStream\n    PhCreateFileStream2\n    PhFlushFileStream\n    PhGetPositionFileStream\n    PhLockFileStream\n    PhReadFileStream\n    PhSeekFileStream\n    PhUnlockFileStream\n    PhVerifyFileStream\n    PhWriteFileStream\n    PhWriteStringAsUtf8FileStream\n    PhWriteStringAsUtf8FileStreamEx\n    PhWriteStringFormatAsUtf8FileStream\n    PhWriteStringFormatAsUtf8FileStream_V\n\n; graph\n    PhDeleteGraphState\n    PhDrawGraphDirect\n    PhDrawTrayIconText\n    PhGetDrawInfoGraphBuffers\n    PhGraphStateGetDrawInfo\n    PhInitializeGraphState\n    PhNfGetTrayIconFont\n    PhSetGraphText\n\n; guisup\n    PhAddLayoutItem\n    PhAddLayoutItemEx\n    PhAddListViewColumn\n    PhAddListViewGroup\n    PhAddListViewGroupItem\n    PhAddListViewItem\n    PhAddTabControlTab\n    PhBitmapSetAlpha\n    PhCloseThemeData\n    PhCreateCommonFont\n    PhCreateDialog\n    PhCreateDIBSection\n    PhCreateIconTitleFont\n    PhCreateWindowEx\n    PhDeleteLayoutManager\n    PhDialogBox\n    PhDuplicateFont\n    PhDuplicateFontWithNewWeight\n    PhEnumChildWindows\n    PhEnumWindows\n    PhEnumWindowsEx\n    PhFindListViewItemByFlags\n    PhFindListViewItemByParam\n    PhGetClassName\n    PhGetComboBoxString\n    PhGetDialogItemValue\n    PhGetListBoxString\n    PhGetListViewItemImageIndex\n    PhGetListViewItemParam\n    PhGetSelectedListViewItemParam\n    PhGetSelectedListViewItemParams\n    PhGetStockApplicationIcon\n    PhGetStockObject\n    PhGetThemeMargins\n    PhGetThemePartSize\n    PhGetWindowClientId\n    PhGetWindowCompositionAttribute\n    PhGetWindowContext\n    PhGetWindowText\n    PhGetWindowTextEx\n    PhGetWindowTextToBuffer\n    PhIconToBitmap\n    PhImageListAddBitmap\n    PhImageListAddIcon\n    PhImageListCreate\n    PhImageListDestroy\n    PhImageListDrawEx\n    PhImageListDrawIcon\n    PhImageListGetIcon\n    PhImageListRemoveIcon\n    PhImageListReplace\n    PhImageListSetBkColor\n    PhImageListSetIconSize\n    PhImageListSetImageCount\n    PhInitializeLayoutManager\n    PhIsThemeActive\n    PhLayoutManagerUpdate\n    PhLayoutManagerLayout\n    PhLoadIcon\n    PhLoadImageFormatFromResource\n    PhModalPropertySheet\n    PhOpenThemeData\n    PhQueryDirectXExclusiveOwnership\n    PhInitializeWindowTheme\n    PhReInitializeWindowTheme\n    PhRegisterWindowCallback\n    PhRemoveListViewItem\n    PhRemoveWindowContext\n    PhSelectComboBoxString\n    PhSetClipboardString\n    PhSetControlTheme\n    PhSetDialogItemText\n    PhSetDialogItemValue\n    PhSetExtendedListView\n    PhSetGroupBoxText\n    PhSetHeaderSortIcon\n    PhSetImageListBitmap\n    PhSetListViewItemImageIndex\n    PhSetListViewItemParam\n    PhSetListViewSubItem\n    PhSetStateAllListViewItems\n    PhSetWindowContext\n    PhSetWindowText\n    PhTerminateWindow\n    PhThemeWindowDrawRebar\n    PhThemeWindowDrawToolbar\n    PhUnregisterWindowCallback\n    PhUserQueryWindow\n    PhWindowThemeControlColor\n\n; hndlinfo\n    PhCallKphQueryFileInformationWithTimeout\n    PhCompareObjects\n    PhEnumObjectTypes\n    PhFormatNativeKeyName\n    PhGetEtwPublisherName\n    PhGetHandleInformation\n    PhGetHandleInformationEx\n    PhGetObjectTypeName\n    PhQueryObjectName\n    PhStdGetClientIdName\n\n; lsasup\n    PhEnumeratePrivileges\n    PhGetSidFullName\n    PhLookupName\n    PhLookupPrivilegeDisplayName\n    PhLookupPrivilegeName\n    PhLookupPrivilegeValue\n    PhLookupSid\n    PhOpenLsaPolicy\n    PhSidToStringSid\n\n; mapimg\n    PhLoadMappedImage\n    PhLoadMappedImageEx\n    PhLoadMappedImageHeaderPageSize\n    PhUnloadMappedImage\n\n; provider\n    PhBoostProvider\n    PhDeleteProviderThread\n    PhGetEnabledProvider\n    PhInitializeProviderThread\n    PhRegisterProvider\n    PhSetEnabledProvider\n    PhSetIntervalProviderThread\n    PhStartProviderThread\n    PhStopProviderThread\n    PhUnregisterProvider\n\n; settings\n    PhAddSetting\n    PhAddSettings\n    PhClearIgnoredSettings\n    PhConvertIgnoredSettings\n    PhGetIntegerPairStringRefSetting\n    PhGetIntegerStringRefSetting\n    PhGetScalableIntegerPairStringRefSetting\n    PhGetStringRefSetting\n    PhLoadCustomColorList\n    PhLoadListViewColumnSettings\n    PhLoadListViewColumnsFromSetting\n    PhLoadListViewGroupStatesFromSetting\n    PhLoadListViewSortColumnsFromSetting\n    PhLoadSettings\n    PhLoadWindowPlacementFromSetting\n    PhResetSettings\n    PhSaveCustomColorList\n    PhSaveListViewColumnSettings\n    PhSaveListViewColumnsToSetting\n    PhSaveListViewGroupStatesToSetting\n    PhSaveListViewSortColumnsToSetting\n    PhSaveSettings\n    PhSaveWindowPlacementToSetting\n    PhSetIntegerPairStringRefSetting\n    PhSetIntegerStringRefSetting\n    PhSetScalableIntegerPairStringRefSetting\n    PhSetScalableIntegerPairStringRefSetting2\n    PhSetStringRefSetting\n    PhUpdateCachedSettings\n\n; secedit\n    PhCreateSecurityPage\n    PhEditSecurity\n    PhGetAccessEntries\n    PhGetAccessString\n    PhGetSeObjectSecurity\n    PhSetSeObjectSecurity\n    PhStdGetObjectSecurity\n    PhStdSetObjectSecurity\n\n; svcsup\n    PhChangeServiceConfig2\n    PhCloseServiceHandle\n    PhEnumDependentServices\n    PhGetServiceConfig\n    PhGetServiceConfigFileName\n    PhGetServiceDescription\n    PhGetServiceDllParameter\n    PhGetServiceErrorControlInteger\n    PhGetServiceErrorControlString\n    PhGetServiceFileName\n    PhGetServiceNameFromTag\n    PhGetServiceStartTypeInteger\n    PhGetServiceStartTypeString\n    PhGetServiceStateString\n    PhGetServiceTypeInteger\n    PhGetServiceTypeString\n    PhGetThreadServiceTag\n    PhOpenService\n    PhOpenServiceKey\n    PhQueryServiceConfig\n    PhQueryServiceConfig2\n    PhQueryServiceStatus\n    PhQueryServiceVariableSize\n    PhStartService\n    PhStopService\n\n; symprv\n    PhCreateSymbolProvider\n    PhGetLineFromAddress\n    PhGetModuleFromAddress\n    PhGetSymbolFromAddress\n    PhGetSymbolFromName\n    PhLoadSymbolProviderModules\n    PhLoadModuleSymbolProvider\n    PhLoadModulesForVirtualSymbolProvider\n    PhSetOptionsSymbolProvider\n    PhSetSearchPathSymbolProvider\n    PhStackWalk\n    PhWalkThreadStack\n    PhWriteMiniDumpProcess\n\n; verify\n    PhVerifyFile\n    PhVerifyFileIsChainedToMicrosoft\n\n; workqueue\n    PhDeleteWorkQueue\n    PhGetGlobalWorkQueue\n    PhInitializeWorkQueue\n    PhInitializeWorkQueueEnvironment\n    PhQueueItemWorkQueue\n    PhQueueItemWorkQueueEx\n    PhWaitForWorkQueue\n\n; json\n    PhAddJsonArrayObject\n    PhAddJsonObject\n    PhAddJsonObject2\n    PhAddJsonObjectUtf8\n    PhAddJsonObjectInt64\n    PhAddJsonObjectUInt64\n    PhAddJsonObjectValue\n    PhCreateJsonArray\n    PhCreateJsonObject\n    PhCreateJsonParser\n    PhCreateJsonParserEx\n    PhFreeJsonObject\n    PhGetJsonArrayIndexObject\n    PhGetJsonArrayLength\n    PhGetJsonArrayLong64\n    PhGetJsonArrayString\n    PhGetJsonObject\n    PhGetJsonObjectAsArrayList\n    PhGetJsonObjectBool\n    PhGetJsonObjectLength\n    PhGetJsonObjectType\n    PhGetJsonValueAsInt64\n    PhGetJsonValueAsString\n    PhGetJsonValueAsUInt64\n    PhLoadJsonObjectFromFile\n    PhSaveJsonObjectToFile\n\n; xml\n    PhCreateXmlNode\n    PhCreateXmlOpaqueNode\n    PhFindXmlObject\n    PhFreeXmlObject\n    PhGetXmlNodeAttributeByIndex\n    PhGetXmlNodeAttributeCount\n    PhGetXmlNodeAttributeText\n    PhGetXmlNodeElementText\n    PhGetXmlNodeFirstChild\n    PhGetXmlNodeNextChild\n    PhGetXmlNodeOpaqueText\n    PhGetXmlObject\n    PhLoadXmlObjectFromFile\n    PhLoadXmlObjectFromString\n    PhSaveXmlObjectToFile\n    PhSetXmlNodeAttributeText\n\n; cache\n    PhClearCacheDirectory\n    PhCreateCacheFile\n    PhDeleteCacheFile\n\n; appresolver\n    PhAppResolverGetAppIdForWindow\n    PhGetProcessPackageFullName\n\n; http\n    PhDnsFree\n    PhDnsQuery\n    PhDnsQuery2\n    PhDnsReverseLookupNameFromAddress\n    PhHttpAddRequestHeaders\n    PhHttpBeginRequest\n    PhHttpClose\n    PhHttpConnect\n    PhHttpCrackUrl\n    PhHttpInitialize\n    PhHttpDestroy\n    PhHttpDownloadString\n    PhHttpReceiveResponse\n    PhHttpGetErrorMessage\n    PhHttpQueryHeaderString\n    PhHttpQueryHeaderUlong\n    PhHttpQueryHeaderUlong64\n    PhHttpQueryHeaders\n    PhHttpQueryOptionString\n    PhHttpReadData\n    PhHttpReadDataToBuffer\n    PhHttpSendRequest\n    PhHttpSetCredentials\n    PhHttpSetFeature\n    PhHttpSetSecurity\n    PhHttpSetProtocol\n    PhHttpWriteData\n    PhIpv4AddressToString\n    PhIpv6AddressToString\n    PhIpv4StringToAddress\n    PhIpv6StringToAddress\n\n; ksiuser\n    KsiLevel\n    KphAlpcQueryInformation\n    KphDuplicateObject\n    KphOpenDevice\n    KphOpenDeviceBaseDevice\n    KphOpenDeviceDriver\n    KphQueryInformationDriver\n    KphQueryInformationObject\n    KsiEnumerateProcessHandles\n    KsiQueryHashInformationFile\n"
  },
  {
    "path": "SystemInformer/SystemInformer.def.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2008-2016\n *     dmex    2017-2024\n *\n *\n * This file was automatically generated.\n *\n * Do not link at runtime. Use the SystemInformer.def.h header file instead.\n *\n */\n\n#pragma once\n\n#ifndef _PH_EXPORT_DEF_H\n#define _PH_EXPORT_DEF_H\n\n#define EXPORT_PHADDPROCESSPROPPAGE                                    1001\n#define EXPORT_PHADDPROCESSPROPPAGE2                                   1002\n#define EXPORT_PHADDPROPPAGELAYOUTITEM                                 1003\n#define EXPORT_PHADDTREENEWFILTER                                      1004\n#define EXPORT_PHAPPLYTREENEWFILTERS                                   1005\n#define EXPORT_PHAPPLYTREENEWFILTERSTONODE                             1006\n#define EXPORT_PHCHOICEDIALOG                                          1007\n#define EXPORT_PHCMLOADSETTINGS                                        1008\n#define EXPORT_PHCMSAVESETTINGS                                        1009\n#define EXPORT_PHCOPYLISTVIEW                                          1010\n#define EXPORT_PHCOPYLISTVIEWINFOTIP                                   1011\n#define EXPORT_PHCREATEKSISETTINGSBLOB                                 1012\n#define EXPORT_PHCREATEPROCESSPROPCONTEXT                              1013\n#define EXPORT_PHCREATEPROCESSPROPPAGECONTEXT                          1014\n#define EXPORT_PHCREATEPROCESSPROPPAGECONTEXTEX                        1015\n#define EXPORT_PHCREATESEARCHCONTROL                                   1016\n#define EXPORT_PHCREATESERVICELISTCONTROL                              1017\n#define EXPORT_PHDELETEMEMORYITEMLIST                                  1018\n#define EXPORT_PHDELETESTATICWINDOWICON                                1019\n#define EXPORT_PHDELETETREENEWCOLUMNMENU                               1020\n#define EXPORT_PHDELETETREENEWFILTERSUPPORT                            1021\n#define EXPORT_PHDEREFERENCEPROCESSRECORD                              1022\n#define EXPORT_PHDESELECTALLPROCESSNODES                               1023\n#define EXPORT_PHDESELECTALLSERVICENODES                               1024\n#define EXPORT_PHDESTROYWINDOWICON                                     1025\n#define EXPORT_PHDEVICEPROVIDERINITIALIZATION                          1026\n#define EXPORT_PHDOPROPPAGELAYOUT                                      1027\n#define EXPORT_PHDUPLICATEPROCESSINFORMATION                           1028\n#define EXPORT_PHDUPLICATEPROCESSNODELIST                              1029\n#define EXPORT_PHENUMNETWORKITEMS                                      1030\n#define EXPORT_PHENUMNETWORKITEMSBYPROCESSID                           1031\n#define EXPORT_PHENUMPROCESSITEMS                                      1032\n#define EXPORT_PHEXECUTERUNASCOMMAND2                                  1033\n#define EXPORT_PHEXECUTERUNASCOMMAND3                                  1034\n#define EXPORT_PHEXPANDALLPROCESSNODES                                 1035\n#define EXPORT_PHFINDNETWORKNODE                                       1036\n#define EXPORT_PHFINDPROCESSNODE                                       1037\n#define EXPORT_PHFINDPROCESSRECORD                                     1038\n#define EXPORT_PHFINDSERVICENODE                                       1039\n#define EXPORT_PHFORMATLOGENTRY                                        1040\n#define EXPORT_PHGETAPPLICATIONICON                                    1041\n#define EXPORT_PHGETAPPLICATIONICONEX                                  1042\n#define EXPORT_PHGETCLIENTIDNAME                                       1043\n#define EXPORT_PHGETCLIENTIDNAMEEX                                     1044\n#define EXPORT_PHGETDEVICEICON                                         1045\n#define EXPORT_PHGETDEVICEPROPERTY                                     1046\n#define EXPORT_PHGETFILTERSUPPORTNETWORKTREELIST                       1047\n#define EXPORT_PHGETFILTERSUPPORTPROCESSTREELIST                       1048\n#define EXPORT_PHGETFILTERSUPPORTSERVICETREELIST                       1049\n#define EXPORT_PHGETGENERALCALLBACK                                    1050\n#define EXPORT_PHGETIMAGELISTICON                                      1051\n#define EXPORT_PHGETLISTVIEWCONTEXTMENUPOINT                           1052\n#define EXPORT_PHGETPHRELEASECHANNEL                                   1053\n#define EXPORT_PHGETPHRELEASECHANNELSTRING                             1054\n#define EXPORT_PHGETPHVERSION                                          1055\n#define EXPORT_PHGETPHVERSIONHASH                                      1056\n#define EXPORT_PHGETPHVERSIONNUMBERS                                   1057\n#define EXPORT_PHGETPROCESSISSUSPENDED                                 1058\n#define EXPORT_PHGETPROCESSKNOWNTYPE                                   1059\n#define EXPORT_PHGETPROCESSKNOWNTYPEEX                                 1060\n#define EXPORT_PHGETPROCESSPRIORITYCLASSSTRING                         1061\n#define EXPORT_PHGETPROCESSSMALLIMAGELIST                              1062\n#define EXPORT_PHGETPROTOCOLTYPENAME                                   1063\n#define EXPORT_PHGETSELECTEDANDPROPAGATEPROCESSITEMS                   1064\n#define EXPORT_PHGETSELECTEDPROCESSITEM                                1065\n#define EXPORT_PHGETSELECTEDPROCESSITEMS                               1066\n#define EXPORT_PHGETSELECTEDPROCESSNODES                               1067\n#define EXPORT_PHGETSELECTEDSERVICEITEM                                1068\n#define EXPORT_PHGETSELECTEDSERVICEITEMS                               1069\n#define EXPORT_PHGETSERVICECHANGE                                      1070\n#define EXPORT_PHGETSHIELDBITMAP                                       1071\n#define EXPORT_PHGETSTATISTICSTIME                                     1072\n#define EXPORT_PHGETSTATISTICSTIMESTRING                               1073\n#define EXPORT_PHGETTCPSTATENAME                                       1074\n#define EXPORT_PHHANDLECOPYCELLEMENUITEM                               1075\n#define EXPORT_PHHANDLECOPYLISTVIEWEMENUITEM                           1076\n#define EXPORT_PHHANDLELISTVIEWNOTIFYBEHAVIORS                         1077\n#define EXPORT_PHHANDLELISTVIEWNOTIFYFORCOPY                           1078\n#define EXPORT_PHHANDLETREENEWCOLUMNMENU                               1079\n#define EXPORT_PHIMAGELISTEXTRACTICON                                  1080\n#define EXPORT_PHIMAGELISTFLUSHCACHE                                   1081\n#define EXPORT_PHINITIALIZETREENEWCOLUMNMENU                           1082\n#define EXPORT_PHINITIALIZETREENEWCOLUMNMENUEX                         1083\n#define EXPORT_PHINITIALIZETREENEWFILTERSUPPORT                        1084\n#define EXPORT_PHINSERTCOPYCELLEMENUITEM                               1085\n#define EXPORT_PHINSERTCOPYLISTVIEWEMENUITEM                           1086\n#define EXPORT_PHINSERTHANDLEOBJECTPROPERTIESEMENUITEMS                1087\n#define EXPORT_PHINVALIDATEALLPROCESSNODES                             1088\n#define EXPORT_PHISPROCESSSUSPENDED                                    1089\n#define EXPORT_PHLOADSYMBOLPROVIDEROPTIONS                             1090\n#define EXPORT_PHLOGMESSAGEENTRY                                       1091\n#define EXPORT_PHLOOKUPDEVICEITEM                                      1092\n#define EXPORT_PHLOOKUPDEVICEITEMBYHASH                                1093\n#define EXPORT_PHLOOKUPDEVICEPROPERTYCLASS                             1094\n#define EXPORT_PHLOOKUPMEMORYITEMLIST                                  1095\n#define EXPORT_PHPROCESSIMAGELISTINITIALIZATION                        1096\n#define EXPORT_PHPROPPAGEDLGPROCHEADER                                 1097\n#define EXPORT_PHQUERYMEMORYITEMLIST                                   1098\n#define EXPORT_PHREFERENCEDEVICEITEM                                   1099\n#define EXPORT_PHREFERENCEDEVICEITEM2                                  1100\n#define EXPORT_PHREFERENCEDEVICEITEMBYHASH                             1101\n#define EXPORT_PHREFERENCEDEVICETREE                                   1102\n#define EXPORT_PHREFERENCEDEVICETREEEX                                 1103\n#define EXPORT_PHREFERENCENETWORKITEM                                  1104\n#define EXPORT_PHREFERENCEPROCESSITEM                                  1105\n#define EXPORT_PHREFERENCEPROCESSITEMFORPARENT                         1106\n#define EXPORT_PHREFERENCEPROCESSITEMFORRECORD                         1107\n#define EXPORT_PHREFERENCEPROCESSRECORD                                1108\n#define EXPORT_PHREFERENCEPROCESSRECORDFORSTATISTICS                   1109\n#define EXPORT_PHREFERENCEPROCESSRECORDSAFE                            1110\n#define EXPORT_PHREFERENCESERVICEITEM                                  1111\n#define EXPORT_PHREGISTERDIALOG                                        1112\n#define EXPORT_PHREGISTERMESSAGELOOPFILTER                             1113\n#define EXPORT_PHREMOVETREENEWFILTER                                   1114\n#define EXPORT_PHSEARCHCONTROLMATCH                                    1115\n#define EXPORT_PHSEARCHCONTROLMATCHLONGHINTZ                           1116\n#define EXPORT_PHSEARCHCONTROLMATCHPOINTER                             1117\n#define EXPORT_PHSEARCHCONTROLMATCHPOINTERRANGE                        1118\n#define EXPORT_PHSEARCHCONTROLMATCHZ                                   1119\n#define EXPORT_PHSEARCHONLINESTRING                                    1120\n#define EXPORT_PHSELECTANDENSUREVISIBLEPROCESSNODE                     1121\n#define EXPORT_PHSELECTANDENSUREVISIBLESERVICENODE                     1122\n#define EXPORT_PHSETAPPLICATIONWINDOWICON                              1123\n#define EXPORT_PHSETAPPLICATIONWINDOWICONEX                            1124\n#define EXPORT_PHSETPROCESSITEMAFFINITYMASK                            1125\n#define EXPORT_PHSETPROCESSITEMIOPRIORITY                              1126\n#define EXPORT_PHSETPROCESSITEMPAGEPRIORITY                            1127\n#define EXPORT_PHSETPROCESSITEMPRIORITY                                1128\n#define EXPORT_PHSETPROCESSITEMPRIORITYBOOST                           1129\n#define EXPORT_PHSETPROCESSITEMTHROTTLINGSTATE                         1130\n#define EXPORT_PHSETSELECTTHREADIDPROCESSPROPCONTEXT                   1131\n#define EXPORT_PHSETSTATICWINDOWICON                                   1132\n#define EXPORT_PHSETWINDOWICON                                         1133\n#define EXPORT_PHSHELLEXECUTEUSERSTRING                                1134\n#define EXPORT_PHSHELLOPENKEY                                          1135\n#define EXPORT_PHSHELLOPENKEY2                                         1136\n#define EXPORT_PHSHELLPROCESSHACKER                                    1137\n#define EXPORT_PHSHOWCHOOSEPROCESSDIALOG                               1138\n#define EXPORT_PHSHOWHANDLEOBJECTPROPERTIES1                           1139\n#define EXPORT_PHSHOWHANDLEOBJECTPROPERTIES2                           1140\n#define EXPORT_PHSHOWICONNOTIFICATION                                  1141\n#define EXPORT_PHSHOWPROCESSAFFINITYDIALOG2                            1142\n#define EXPORT_PHSHOWPROCESSPROPERTIES                                 1143\n#define EXPORT_PHSHOWPROCESSRECORDDIALOG                               1144\n#define EXPORT_PHSHOWSYSTEMINFORMATIONDIALOG                           1145\n#define EXPORT_PHSHOWTHREADAFFINITYDIALOG                              1146\n#define EXPORT_PHSIDOUBLELABELYFUNCTION                                1147\n#define EXPORT_PHSISETCOLORSGRAPHDRAWINFO                              1148\n#define EXPORT_PHSISIZELABELYFUNCTION                                  1149\n#define EXPORT_PHSIUINT64LABELYFUNCTION                                1150\n#define EXPORT_PHUNREGISTERDIALOG                                      1151\n#define EXPORT_PHUNREGISTERMESSAGELOOPFILTER                           1152\n#define EXPORT_PHUPDATEPROCESSNODE                                     1153\n#define EXPORT_PHUPDATESERVICENODE                                     1154\n#define EXPORT_PHWORDMATCHSTRINGREF                                    1155\n#define EXPORT_PHWRITEPHTEXTHEADER                                     1156\n#define EXPORT_PHACHOICEDIALOG                                         1157\n#define EXPORT_PHAGETPROCESSKNOWNCOMMANDLINE                           1158\n#define EXPORT_PHENUMERATEPLUGINS                                      1159\n#define EXPORT_PHFINDPLUGIN2                                           1160\n#define EXPORT_PHGETPLUGINCALLBACK                                     1161\n#define EXPORT_PHGETPLUGINFILENAME                                     1162\n#define EXPORT_PHGETPLUGININFORMATION                                  1163\n#define EXPORT_PHGETPLUGININTERFACE                                    1164\n#define EXPORT_PHGETPLUGINNAME                                         1165\n#define EXPORT_PHPLUGINADDMENUHOOK                                     1166\n#define EXPORT_PHPLUGINADDTREENEWCOLUMN                                1167\n#define EXPORT_PHPLUGINCALLPHSVC                                       1168\n#define EXPORT_PHPLUGINCREATEEMENUITEM                                 1169\n#define EXPORT_PHPLUGINCREATETABPAGE                                   1170\n#define EXPORT_PHPLUGINENABLETREENEWNOTIFY                             1171\n#define EXPORT_PHPLUGINGETOBJECTEXTENSION                              1172\n#define EXPORT_PHPLUGINGETSYSTEMSTATISTICS                             1173\n#define EXPORT_PHPLUGININVOKEWINDOWCALLBACK                            1174\n#define EXPORT_PHPLUGINQUERYPHSVC                                      1175\n#define EXPORT_PHPLUGINRESERVEIDS                                      1176\n#define EXPORT_PHPLUGINSETOBJECTEXTENSION                              1177\n#define EXPORT_PHREGISTERPLUGIN                                        1178\n#define EXPORT_PHSVCCALLCHANGESERVICECONFIG                            1179\n#define EXPORT_PHSVCCALLCHANGESERVICECONFIG2                           1180\n#define EXPORT_PHSVCCALLPOSTMESSAGE                                    1181\n#define EXPORT_PHSVCCALLSENDMESSAGE                                    1182\n#define EXPORT_PHUICLOSECONNECTIONS                                    1183\n#define EXPORT_PHUICLOSEHANDLES                                        1184\n#define EXPORT_PHUICONNECTSESSION                                      1185\n#define EXPORT_PHUICONNECTTOPHSVC                                      1186\n#define EXPORT_PHUICONNECTTOPHSVCEX                                    1187\n#define EXPORT_PHUICONTINUESERVICE                                     1188\n#define EXPORT_PHUICONTINUESERVICES                                    1189\n#define EXPORT_PHUIDEBUGPROCESS                                        1190\n#define EXPORT_PHUIDELETESERVICE                                       1191\n#define EXPORT_PHUIDETACHFROMDEBUGGERPROCESS                           1192\n#define EXPORT_PHUIDISCONNECTFROMPHSVC                                 1193\n#define EXPORT_PHUIDISCONNECTSESSION                                   1194\n#define EXPORT_PHUIFLUSHHEAPPROCESSES                                  1195\n#define EXPORT_PHUIFREEMEMORY                                          1196\n#define EXPORT_PHUIFREEZETREEPROCESS                                   1197\n#define EXPORT_PHUIHIBERNATECOMPUTER                                   1198\n#define EXPORT_PHUILOADDLLPROCESS                                      1199\n#define EXPORT_PHUILOCKCOMPUTER                                        1200\n#define EXPORT_PHUILOGOFFCOMPUTER                                      1201\n#define EXPORT_PHUILOGOFFSESSION                                       1202\n#define EXPORT_PHUIPAUSESERVICE                                        1203\n#define EXPORT_PHUIPAUSESERVICES                                       1204\n#define EXPORT_PHUIREDUCEWORKINGSETPROCESSES                           1205\n#define EXPORT_PHUIRESTARTCOMPUTER                                     1206\n#define EXPORT_PHUIRESTARTPROCESS                                      1207\n#define EXPORT_PHUIRESUMEPROCESSES                                     1208\n#define EXPORT_PHUIRESUMETHREADS                                       1209\n#define EXPORT_PHUIRESUMETREEPROCESS                                   1210\n#define EXPORT_PHUISETATTRIBUTESHANDLE                                 1211\n#define EXPORT_PHUISETBOOSTPRIORITYPROCESS                             1212\n#define EXPORT_PHUISETBOOSTPRIORITYPROCESSES                           1213\n#define EXPORT_PHUISETBOOSTPRIORITYTHREAD                              1214\n#define EXPORT_PHUISETBOOSTPRIORITYTHREADS                             1215\n#define EXPORT_PHUISETCRITICALPROCESS                                  1216\n#define EXPORT_PHUISETECOMODEPROCESS                                   1217\n#define EXPORT_PHUISETEXECUTIONREQUIREDPROCESS                         1218\n#define EXPORT_PHUISETIOPRIORITYPROCESSES                              1219\n#define EXPORT_PHUISETIOPRIORITYTHREAD                                 1220\n#define EXPORT_PHUISETPAGEPRIORITYPROCESS                              1221\n#define EXPORT_PHUISETPAGEPRIORITYTHREAD                               1222\n#define EXPORT_PHUISETPRIORITYPROCESSES                                1223\n#define EXPORT_PHUISETPRIORITYTHREAD                                   1224\n#define EXPORT_PHUISETPRIORITYTHREADS                                  1225\n#define EXPORT_PHUISETVIRTUALIZATIONPROCESS                            1226\n#define EXPORT_PHUISHUTDOWNCOMPUTER                                    1227\n#define EXPORT_PHUISLEEPCOMPUTER                                       1228\n#define EXPORT_PHUISTARTSERVICE                                        1229\n#define EXPORT_PHUISTARTSERVICES                                       1230\n#define EXPORT_PHUISTOPSERVICE                                         1231\n#define EXPORT_PHUISTOPSERVICES                                        1232\n#define EXPORT_PHUISUSPENDPROCESSES                                    1233\n#define EXPORT_PHUISUSPENDTHREADS                                      1234\n#define EXPORT_PHUISUSPENDTREEPROCESS                                  1235\n#define EXPORT_PHUITERMINATEPROCESSES                                  1236\n#define EXPORT_PHUITERMINATETHREADS                                    1237\n#define EXPORT_PHUITERMINATETREEPROCESS                                1238\n#define EXPORT_PHUITHAWTREEPROCESS                                     1239\n#define EXPORT_PHUIUNLOADMODULE                                        1240\n#define EXPORT_PHAUTODEREFERENCEOBJECT                                 1241\n#define EXPORT_PHCREATEALLOC                                           1242\n#define EXPORT_PHCREATEOBJECT                                          1243\n#define EXPORT_PHCREATEOBJECTTYPE                                      1244\n#define EXPORT_PHCREATEOBJECTTYPEEX                                    1245\n#define EXPORT_PHDELETEAUTOPOOL                                        1246\n#define EXPORT_PHDEREFERENCEOBJECT                                     1247\n#define EXPORT_PHDEREFERENCEOBJECTDEFERDELETE                          1248\n#define EXPORT_PHDEREFERENCEOBJECTEX                                   1249\n#define EXPORT_PHDRAINAUTOPOOL                                         1250\n#define EXPORT_PHGETOBJECTTYPE                                         1251\n#define EXPORT_PHGETOBJECTTYPEINFORMATION                              1252\n#define EXPORT_PHINITIALIZEAUTOPOOL                                    1253\n#define EXPORT_PHREFERENCEOBJECT                                       1254\n#define EXPORT_PHREFERENCEOBJECTEX                                     1255\n#define EXPORT_PHREFERENCEOBJECTSAFE                                   1256\n#define EXPORT_PHFACQUIREQUEUEDLOCKEXCLUSIVE                           1257\n#define EXPORT_PHFACQUIREQUEUEDLOCKSHARED                              1258\n#define EXPORT_PHFPULSEALLCONDITION                                    1259\n#define EXPORT_PHFPULSECONDITION                                       1260\n#define EXPORT_PHFQUEUEWAKEEVENT                                       1261\n#define EXPORT_PHFRELEASEQUEUEDLOCKEXCLUSIVE                           1262\n#define EXPORT_PHFRELEASEQUEUEDLOCKSHARED                              1263\n#define EXPORT_PHFSETWAKEEVENT                                         1264\n#define EXPORT_PHFWAITFORCONDITION                                     1265\n#define EXPORT_PHFWAITFORCONDITIONEX                                   1266\n#define EXPORT_PHFWAITFORWAKEEVENT                                     1267\n#define EXPORT_PHFWAKEFORRELEASEQUEUEDLOCK                             1268\n#define EXPORT_PHISEXECUTINGINWOW64                                    1269\n#define EXPORT_PHSYSTEMBASICINFORMATION                                1270\n#define EXPORT_PHADDELEMENTAVLTREE                                     1271\n#define EXPORT_PHADDENTRYHASHTABLE                                     1272\n#define EXPORT_PHADDENTRYHASHTABLEEX                                   1273\n#define EXPORT_PHADDITEMARRAY                                          1274\n#define EXPORT_PHADDITEMLIST                                           1275\n#define EXPORT_PHADDITEMPOINTERLIST                                    1276\n#define EXPORT_PHADDITEMSIMPLEHASHTABLE                                1277\n#define EXPORT_PHADDITEMSARRAY                                         1278\n#define EXPORT_PHADDITEMSLIST                                          1279\n#define EXPORT_PHADDPLUSMAXMEMORYSINGLES                               1280\n#define EXPORT_PHALLOCATE                                              1281\n#define EXPORT_PHALLOCATEEXSAFE                                        1282\n#define EXPORT_PHALLOCATEFROMFREELIST                                  1283\n#define EXPORT_PHALLOCATEPAGE                                          1284\n#define EXPORT_PHALLOCATESAFE                                          1285\n#define EXPORT_PHAPPENDBYTESBUILDER                                    1286\n#define EXPORT_PHAPPENDBYTESBUILDER2                                   1287\n#define EXPORT_PHAPPENDBYTESBUILDEREX                                  1288\n#define EXPORT_PHAPPENDCHARSTRINGBUILDER                               1289\n#define EXPORT_PHAPPENDCHARSTRINGBUILDER2                              1290\n#define EXPORT_PHAPPENDFORMATSTRINGBUILDER                             1291\n#define EXPORT_PHAPPENDFORMATSTRINGBUILDER_V                           1292\n#define EXPORT_PHAPPENDSTRINGBUILDEREX                                 1293\n#define EXPORT_PHBUFFERTOHEXSTRING                                     1294\n#define EXPORT_PHBUFFERTOHEXSTRINGEX                                   1295\n#define EXPORT_PHCLEARARRAY                                            1296\n#define EXPORT_PHCLEARHASHTABLE                                        1297\n#define EXPORT_PHCLEARLIST                                             1298\n#define EXPORT_PHCOMPARESTRINGREF                                      1299\n#define EXPORT_PHCOMPARESTRINGZNATURAL                                 1300\n#define EXPORT_PHCONCATSTRINGREF2                                      1301\n#define EXPORT_PHCONCATSTRINGREF3                                      1302\n#define EXPORT_PHCONCATSTRINGREF4                                      1303\n#define EXPORT_PHCONCATSTRINGS                                         1304\n#define EXPORT_PHCONCATSTRINGS2                                        1305\n#define EXPORT_PHCONCATSTRINGS_V                                       1306\n#define EXPORT_PHCONVERTMULTIBYTETOUTF16                               1307\n#define EXPORT_PHCONVERTMULTIBYTETOUTF16EX                             1308\n#define EXPORT_PHCONVERTUTF16TOASCIIEX                                 1309\n#define EXPORT_PHCONVERTUTF16TOMULTIBYTE                               1310\n#define EXPORT_PHCONVERTUTF16TOMULTIBYTEEX                             1311\n#define EXPORT_PHCONVERTUTF16TOUTF8                                    1312\n#define EXPORT_PHCONVERTUTF16TOUTF8BUFFER                              1313\n#define EXPORT_PHCONVERTUTF16TOUTF8EX                                  1314\n#define EXPORT_PHCONVERTUTF16TOUTF8SIZE                                1315\n#define EXPORT_PHCONVERTUTF8TOUTF16                                    1316\n#define EXPORT_PHCONVERTUTF8TOUTF16BUFFER                              1317\n#define EXPORT_PHCONVERTUTF8TOUTF16EX                                  1318\n#define EXPORT_PHCONVERTUTF8TOUTF16SIZE                                1319\n#define EXPORT_PHCOPYBYTESZ                                            1320\n#define EXPORT_PHCOPYCONVERTCIRCULARBUFFERULONG                        1321\n#define EXPORT_PHCOPYSTRINGZ                                           1322\n#define EXPORT_PHCOPYSTRINGZFROMBYTES                                  1323\n#define EXPORT_PHCOPYSTRINGZFROMMULTIBYTE                              1324\n#define EXPORT_PHCOUNTSTRINGZ                                          1325\n#define EXPORT_PHCREATEBYTES                                           1326\n#define EXPORT_PHCREATEBYTESEX                                         1327\n#define EXPORT_PHCREATEHASHTABLE                                       1328\n#define EXPORT_PHCREATELIST                                            1329\n#define EXPORT_PHCREATEPOINTERLIST                                     1330\n#define EXPORT_PHCREATESIMPLEHASHTABLE                                 1331\n#define EXPORT_PHCREATESTRING3                                         1332\n#define EXPORT_PHCREATESTRINGEX                                        1333\n#define EXPORT_PHCREATETHREAD                                          1334\n#define EXPORT_PHCREATETHREAD2                                         1335\n#define EXPORT_PHCREATETHREADEX                                        1336\n#define EXPORT_PHDECODEUNICODEDECODER                                  1337\n#define EXPORT_PHDELAYEXECUTION                                        1338\n#define EXPORT_PHDELETEARRAY                                           1339\n#define EXPORT_PHDELETEBYTESBUILDER                                    1340\n#define EXPORT_PHDELETECALLBACK                                        1341\n#define EXPORT_PHDELETEFREELIST                                        1342\n#define EXPORT_PHDELETESTRINGBUILDER                                   1343\n#define EXPORT_PHDIVIDESINGLESBYSINGLE                                 1344\n#define EXPORT_PHDOSERRORTONTSTATUS                                    1345\n#define EXPORT_PHDUPLICATEBYTESZ                                       1346\n#define EXPORT_PHDUPLICATEBYTESZSAFE                                   1347\n#define EXPORT_PHDUPLICATESTRINGZ                                      1348\n#define EXPORT_PHENCODEUNICODE                                         1349\n#define EXPORT_PHENUMAVLTREE                                           1350\n#define EXPORT_PHENUMHASHTABLE                                         1351\n#define EXPORT_PHENUMPOINTERLISTEX                                     1352\n#define EXPORT_PHEQUALSTRINGREF                                        1353\n#define EXPORT_PHEXPONENTIATE                                          1354\n#define EXPORT_PHEXPONENTIATE64                                        1355\n#define EXPORT_PHEXTRACTICON                                           1356\n#define EXPORT_PHEXTRACTICONEX                                         1357\n#define EXPORT_PHFILLMEMORYULONG                                       1358\n#define EXPORT_PHFINALBYTESBUILDERBYTES                                1359\n#define EXPORT_PHFINALSTRINGBUILDERSTRING                              1360\n#define EXPORT_PHFINDCHARINSTRINGREF                                   1361\n#define EXPORT_PHFINDELEMENTAVLTREE                                    1362\n#define EXPORT_PHFINDENTRYHASHTABLE                                    1363\n#define EXPORT_PHFINDITEMLIST                                          1364\n#define EXPORT_PHFINDITEMPOINTERLIST                                   1365\n#define EXPORT_PHFINDITEMSIMPLEHASHTABLE                               1366\n#define EXPORT_PHFINDLASTCHARINSTRINGREF                               1367\n#define EXPORT_PHFINDSTRINGINSTRINGREF                                 1368\n#define EXPORT_PHFORMAT                                                1369\n#define EXPORT_PHFORMATBYTES                                           1370\n#define EXPORT_PHFORMATBYTES_V                                         1371\n#define EXPORT_PHFORMATSTRING                                          1372\n#define EXPORT_PHFORMATSTRING_V                                        1373\n#define EXPORT_PHFORMATTOBUFFER                                        1374\n#define EXPORT_PHFREE                                                  1375\n#define EXPORT_PHFREEPAGE                                              1376\n#define EXPORT_PHFREETOFREELIST                                        1377\n#define EXPORT_PHGETLASTERROR                                          1378\n#define EXPORT_PHGETPRIMENUMBER                                        1379\n#define EXPORT_PHHASHBYTES                                             1380\n#define EXPORT_PHHASHSTRINGREF                                         1381\n#define EXPORT_PHHASHSTRINGREFEX                                       1382\n#define EXPORT_PHHEXSTRINGTOBUFFER                                     1383\n#define EXPORT_PHHEXSTRINGTOBUFFEREX                                   1384\n#define EXPORT_PHHUNGWINDOWFROMGHOSTWINDOW                             1385\n#define EXPORT_PHINITIALIZEARRAY                                       1386\n#define EXPORT_PHINITIALIZEAVLTREE                                     1387\n#define EXPORT_PHINITIALIZEBYTESBUILDER                                1388\n#define EXPORT_PHINITIALIZECALLBACK                                    1389\n#define EXPORT_PHINITIALIZEFREELIST                                    1390\n#define EXPORT_PHINITIALIZESTRINGBUILDER                               1391\n#define EXPORT_PHINSERTITEMLIST                                        1392\n#define EXPORT_PHINSERTITEMSLIST                                       1393\n#define EXPORT_PHINSERTSTRINGBUILDER                                   1394\n#define EXPORT_PHINSERTSTRINGBUILDER2                                  1395\n#define EXPORT_PHINSERTSTRINGBUILDEREX                                 1396\n#define EXPORT_PHINTEGERTOSTRING64                                     1397\n#define EXPORT_PHINVOKECALLBACK                                        1398\n#define EXPORT_PHLOADINDIRECTSTRING                                    1399\n#define EXPORT_PHLOADRESOURCE                                          1400\n#define EXPORT_PHLOCALTIMETOSYSTEMTIME                                 1401\n#define EXPORT_PHLOWERBOUNDELEMENTAVLTREE                              1402\n#define EXPORT_PHLOWERDUALBOUNDELEMENTAVLTREE                          1403\n#define EXPORT_PHMAXMEMORYSINGLES                                      1404\n#define EXPORT_PHMAXIMUMELEMENTAVLTREE                                 1405\n#define EXPORT_PHMINIMUMELEMENTAVLTREE                                 1406\n#define EXPORT_PHNTSTATUSFILENOTFOUND                                  1407\n#define EXPORT_PHNTSTATUSTODOSERROR                                    1408\n#define EXPORT_PHPREDECESSORELEMENTAVLTREE                             1409\n#define EXPORT_PHPRINTTIMESPAN                                         1410\n#define EXPORT_PHQUERYPERFORMANCECOUNTER                               1411\n#define EXPORT_PHQUERYPERFORMANCEFREQUENCY                             1412\n#define EXPORT_PHQUERYSYSTEMTIME                                       1413\n#define EXPORT_PHQUERYTIMEZONEBIAS                                     1414\n#define EXPORT_PHREALLOCATE                                            1415\n#define EXPORT_PHREALLOCATESAFE                                        1416\n#define EXPORT_PHREADTIMESTAMPCOUNTER                                  1417\n#define EXPORT_PHREFERENCEEMPTYSTRING                                  1418\n#define EXPORT_PHREGISTERCALLBACK                                      1419\n#define EXPORT_PHREGISTERCALLBACKEX                                    1420\n#define EXPORT_PHREMOVEELEMENTAVLTREE                                  1421\n#define EXPORT_PHREMOVEENTRYHASHTABLE                                  1422\n#define EXPORT_PHREMOVEITEMARRAY                                       1423\n#define EXPORT_PHREMOVEITEMLIST                                        1424\n#define EXPORT_PHREMOVEITEMPOINTERLIST                                 1425\n#define EXPORT_PHREMOVEITEMSIMPLEHASHTABLE                             1426\n#define EXPORT_PHREMOVEITEMSARRAY                                      1427\n#define EXPORT_PHREMOVEITEMSLIST                                       1428\n#define EXPORT_PHREMOVESTRINGBUILDER                                   1429\n#define EXPORT_PHRESIZEARRAY                                           1430\n#define EXPORT_PHRESIZELIST                                            1431\n#define EXPORT_PHROUNDUPTOPOWEROFTWO                                   1432\n#define EXPORT_PHSECONDSSINCE1970TOTIME                                1433\n#define EXPORT_PHSPLITSTRINGREFATCHAR                                  1434\n#define EXPORT_PHSPLITSTRINGREFATLASTCHAR                              1435\n#define EXPORT_PHSPLITSTRINGREFATSTRING                                1436\n#define EXPORT_PHSPLITSTRINGREFEX                                      1437\n#define EXPORT_PHSTRINGTODOUBLE                                        1438\n#define EXPORT_PHSTRINGTOINTEGER64                                     1439\n#define EXPORT_PHSTRINGTOUINT64                                        1440\n#define EXPORT_PHSUCCESSORELEMENTAVLTREE                               1441\n#define EXPORT_PHSYSTEMTIMETOLOCALTIME                                 1442\n#define EXPORT_PHTIMETOSECONDSSINCE1970                                1443\n#define EXPORT_PHTRIMSTRINGREF                                         1444\n#define EXPORT_PHUNREGISTERCALLBACK                                    1445\n#define EXPORT_PHUPPERBOUNDELEMENTAVLTREE                              1446\n#define EXPORT_PHUPPERDUALBOUNDELEMENTAVLTREE                          1447\n#define EXPORT_PHWRITEUNICODEDECODER                                   1448\n#define EXPORT_PHZEROEXTENDTOUTF16BUFFER                               1449\n#define EXPORT_PHZEROEXTENDTOUTF16EX                                   1450\n#define EXPORT_PHFACQUIRERUNDOWNPROTECTION                             1451\n#define EXPORT_PHFBEGININITONCE                                        1452\n#define EXPORT_PHFENDINITONCE                                          1453\n#define EXPORT_PHFINITIALIZEBARRIER                                    1454\n#define EXPORT_PHFINITIALIZEEVENT                                      1455\n#define EXPORT_PHFINITIALIZEINITONCE                                   1456\n#define EXPORT_PHFINITIALIZERUNDOWNPROTECTION                          1457\n#define EXPORT_PHFRELEASERUNDOWNPROTECTION                             1458\n#define EXPORT_PHFRESETEVENT                                           1459\n#define EXPORT_PHFSETEVENT                                             1460\n#define EXPORT_PHFWAITFORBARRIER                                       1461\n#define EXPORT_PHFWAITFOREVENT                                         1462\n#define EXPORT_PHFWAITFORRUNDOWNPROTECTION                             1463\n#define EXPORT_PHENUMSMBIOS                                            1464\n#define EXPORT_PHGETSMBIOSSTRING                                       1465\n#define EXPORT_PHADJUSTPRIVILEGE                                       1466\n#define EXPORT_PHCONNECTPIPE                                           1467\n#define EXPORT_PHCREATEDIRECTORYFULLPATHWIN32                          1468\n#define EXPORT_PHCREATEDIRECTORYWIN32                                  1469\n#define EXPORT_PHCREATEEVENT                                           1470\n#define EXPORT_PHCREATEFILE                                            1471\n#define EXPORT_PHCREATEFILEWIN32                                       1472\n#define EXPORT_PHCREATEFILEWIN32EX                                     1473\n#define EXPORT_PHCREATEKEY                                             1474\n#define EXPORT_PHCREATENAMEDPIPE                                       1475\n#define EXPORT_PHCREATEPIPE                                            1476\n#define EXPORT_PHDELETEDIRECTORYWIN32                                  1477\n#define EXPORT_PHDELETEFILE                                            1478\n#define EXPORT_PHDELETEFILEWIN32                                       1479\n#define EXPORT_PHDELETEVALUEKEY                                        1480\n#define EXPORT_PHDESTROYWINDOWREMOTE                                   1481\n#define EXPORT_PHDETERMINEDOSPATHNAMETYPE                              1482\n#define EXPORT_PHDEVICEIOCONTROLFILE                                   1483\n#define EXPORT_PHDISCONNECTNAMEDPIPE                                   1484\n#define EXPORT_PHDOESFILEEXIST                                         1485\n#define EXPORT_PHDOESFILEEXISTWIN32                                    1486\n#define EXPORT_PHDOSPATHNAMETONTPATHNAME                               1487\n#define EXPORT_PHENUMBIGPOOLINFORMATION                                1488\n#define EXPORT_PHENUMDIRECTORYFILE                                     1489\n#define EXPORT_PHENUMDIRECTORYOBJECTS                                  1490\n#define EXPORT_PHENUMFILESTREAMS                                       1491\n#define EXPORT_PHENUMFIRMWAREENVIRONMENTVALUES                         1492\n#define EXPORT_PHENUMGENERICMODULES                                    1493\n#define EXPORT_PHENUMHANDLESEX                                         1494\n#define EXPORT_PHENUMKERNELMODULES                                     1495\n#define EXPORT_PHENUMNEXTPROCESS                                       1496\n#define EXPORT_PHENUMNEXTTHREAD                                        1497\n#define EXPORT_PHENUMOBJECTIDINFORMATION                               1498\n#define EXPORT_PHENUMPAGEFILES                                         1499\n#define EXPORT_PHENUMPOOLTAGINFORMATION                                1500\n#define EXPORT_PHENUMPROCESSENVIRONMENTVARIABLES                       1501\n#define EXPORT_PHENUMPROCESSES                                         1502\n#define EXPORT_PHENUMPROCESSESEX                                       1503\n#define EXPORT_PHENUMPROCESSHANDLES                                    1504\n#define EXPORT_PHENUMREPARSEPOINTINFORMATION                           1505\n#define EXPORT_PHENUMERATEKEY                                          1506\n#define EXPORT_PHENUMERATEVALUEKEY                                     1507\n#define EXPORT_PHFILTERCONNECTCOMMUNICATIONPORT                        1508\n#define EXPORT_PHFINDPROCESSINFORMATION                                1509\n#define EXPORT_PHFINDPROCESSINFORMATIONBYIMAGENAME                     1510\n#define EXPORT_PHGETACTIVEPROCESSORCOUNT                               1511\n#define EXPORT_PHGETCONTEXTTHREAD                                      1512\n#define EXPORT_PHGETDEVICETYPE                                         1513\n#define EXPORT_PHGETDLLHANDLE                                          1514\n#define EXPORT_PHGETDRIVERIMAGEFILENAME                                1515\n#define EXPORT_PHGETDRIVERNAME                                         1516\n#define EXPORT_PHGETDRIVERSERVICEKEYNAME                               1517\n#define EXPORT_PHGETFILEFULLATTRIBUTESINFORMATION                      1518\n#define EXPORT_PHGETFILENAME                                           1519\n#define EXPORT_PHGETFILEPOSITION                                       1520\n#define EXPORT_PHGETFILESIZE                                           1521\n#define EXPORT_PHGETFIRMWAREENVIRONMENTVARIABLE                        1522\n#define EXPORT_PHGETJOBPROCESSIDLIST                                   1523\n#define EXPORT_PHGETKERNELFILENAME                                     1524\n#define EXPORT_PHGETKERNELFILENAME2                                    1525\n#define EXPORT_PHGETKERNELFILENAMEEX                                   1526\n#define EXPORT_PHGETMODULEPROCADDRESS                                  1527\n#define EXPORT_PHGETNAMEDPIPECLIENTCOMPUTERNAME                        1528\n#define EXPORT_PHGETNAMEDPIPECLIENTPROCESSID                           1529\n#define EXPORT_PHGETNAMEDPIPESERVERPROCESSID                           1530\n#define EXPORT_PHGETOBJECTSECURITY                                     1531\n#define EXPORT_PHGETOBJECTTYPEINDEXNAME                                1532\n#define EXPORT_PHGETOBJECTTYPENUMBER                                   1533\n#define EXPORT_PHGETOWNTOKENATTRIBUTES                                 1534\n#define EXPORT_PHGETPNPDEVICENAME                                      1535\n#define EXPORT_PHGETPROCEDUREADDRESS                                   1536\n#define EXPORT_PHGETPROCEDUREADDRESSREMOTE                             1537\n#define EXPORT_PHGETPROCESSCOMMANDLINE                                 1538\n#define EXPORT_PHGETPROCESSDEPSTATUS                                   1539\n#define EXPORT_PHGETPROCESSDEVICEMAP                                   1540\n#define EXPORT_PHGETPROCESSENVIRONMENT                                 1541\n#define EXPORT_PHGETPROCESSIMAGEFILENAME                               1542\n#define EXPORT_PHGETPROCESSIMAGEFILENAMEBYPROCESSID                    1543\n#define EXPORT_PHGETPROCESSIMAGEFILENAMEWIN32                          1544\n#define EXPORT_PHGETPROCESSISDOTNET                                    1545\n#define EXPORT_PHGETPROCESSISDOTNETEX                                  1546\n#define EXPORT_PHGETPROCESSMAPPEDFILENAME                              1547\n#define EXPORT_PHGETPROCESSPEBSTRING                                   1548\n#define EXPORT_PHGETPROCESSPRIORITYCLASS                               1549\n#define EXPORT_PHGETPROCESSUNLOADEDDLLS                                1550\n#define EXPORT_PHGETPROCESSWINDOWTITLE                                 1551\n#define EXPORT_PHGETPROCESSWORKINGSETINFORMATION                       1552\n#define EXPORT_PHGETPROCESSWSCOUNTERS                                  1553\n#define EXPORT_PHGETSECTIONFILENAME                                    1554\n#define EXPORT_PHGETTOKENGROUPS                                        1555\n#define EXPORT_PHGETTOKENINTEGRITYLEVEL                                1556\n#define EXPORT_PHGETTOKENINTEGRITYLEVELRID                             1557\n#define EXPORT_PHGETTOKENOWNER                                         1558\n#define EXPORT_PHGETTOKENPRIMARYGROUP                                  1559\n#define EXPORT_PHGETTOKENPRIVILEGES                                    1560\n#define EXPORT_PHGETTOKENUSER                                          1561\n#define EXPORT_PHIMPERSONATETOKEN                                      1562\n#define EXPORT_PHISDEBUGGERPRESENT                                     1563\n#define EXPORT_PHISFIRMWARESUPPORTED                                   1564\n#define EXPORT_PHLISTENNAMEDPIPE                                       1565\n#define EXPORT_PHLOADAPPKEY                                            1566\n#define EXPORT_PHMOVEFILEWIN32                                         1567\n#define EXPORT_PHOPENDIRECTORYOBJECT                                   1568\n#define EXPORT_PHOPENDRIVER                                            1569\n#define EXPORT_PHOPENFILE                                              1570\n#define EXPORT_PHOPENFILEBYID                                          1571\n#define EXPORT_PHOPENKEY                                               1572\n#define EXPORT_PHOPENPROCESS                                           1573\n#define EXPORT_PHOPENPROCESSCLIENTID                                   1574\n#define EXPORT_PHOPENPROCESSTOKEN                                      1575\n#define EXPORT_PHOPENTHREAD                                            1576\n#define EXPORT_PHOPENTHREADPROCESS                                     1577\n#define EXPORT_PHPEEKNAMEDPIPE                                         1578\n#define EXPORT_PHQUERYENVIRONMENTVARIABLE                              1579\n#define EXPORT_PHQUERYFULLATTRIBUTESFILEWIN32                          1580\n#define EXPORT_PHQUERYKEY                                              1581\n#define EXPORT_PHQUERYSYMBOLICLINKOBJECT                               1582\n#define EXPORT_PHQUERYTOKENVARIABLESIZE                                1583\n#define EXPORT_PHQUERYVALUEKEY                                         1584\n#define EXPORT_PHQUEUEUSERWORKITEM                                     1585\n#define EXPORT_PHREADFILE                                              1586\n#define EXPORT_PHRESOLVEDEVICEPREFIX                                   1587\n#define EXPORT_PHREVERTIMPERSONATIONTOKEN                              1588\n#define EXPORT_PHSETFILEALLOCATIONSIZE                                 1589\n#define EXPORT_PHSETFILEPOSITION                                       1590\n#define EXPORT_PHSETFILESIZE                                           1591\n#define EXPORT_PHSETFIRMWAREENVIRONMENTVARIABLE                        1592\n#define EXPORT_PHSETOBJECTSECURITY                                     1593\n#define EXPORT_PHSETPROCESSPOWERTHROTTLINGSTATE                        1594\n#define EXPORT_PHSETPROCESSPRIORITYBOOST                               1595\n#define EXPORT_PHSETPROCESSPRIORITYCLASS                               1596\n#define EXPORT_PHSETTHREADBASEPRIORITY                                 1597\n#define EXPORT_PHSETTHREADIOPRIORITY                                   1598\n#define EXPORT_PHSETTHREADNAME                                         1599\n#define EXPORT_PHSETTOKENISVIRTUALIZATIONENABLED                       1600\n#define EXPORT_PHSETTOKENPRIVILEGE                                     1601\n#define EXPORT_PHSETTOKENPRIVILEGE2                                    1602\n#define EXPORT_PHSETTOKENSESSIONID                                     1603\n#define EXPORT_PHSETVALUEKEY                                           1604\n#define EXPORT_PHTERMINATEPROCESS                                      1605\n#define EXPORT_PHTRACECONTROL                                          1606\n#define EXPORT_PHTRANSCEIVENAMEDPIPE                                   1607\n#define EXPORT_PHUNLOADDLLPROCESS                                      1608\n#define EXPORT_PHUNLOADDRIVER                                          1609\n#define EXPORT_PHUPDATEDOSDEVICEPREFIXES                               1610\n#define EXPORT_PHUPDATEMUPDEVICEPREFIXES                               1611\n#define EXPORT_PHWAITFORNAMEDPIPE                                      1612\n#define EXPORT_PHWRITEFILE                                             1613\n#define EXPORT_PHADJUSTRECTANGLETOBOUNDS                               1614\n#define EXPORT_PHADJUSTRECTANGLETOWORKINGAREA                          1615\n#define EXPORT_PHCENTERRECTANGLE                                       1616\n#define EXPORT_PHCENTERWINDOW                                          1617\n#define EXPORT_PHCOMPAREUNICODESTRINGZIGNOREMENUPREFIX                 1618\n#define EXPORT_PHCONSOLESETFOREGROUND                                  1619\n#define EXPORT_PHCONSOLESETWINDOW                                      1620\n#define EXPORT_PHCREATEOPENFILEDIALOG                                  1621\n#define EXPORT_PHCREATEPROCESS                                         1622\n#define EXPORT_PHCREATEPROCESSASUSER                                   1623\n#define EXPORT_PHCREATEPROCESSREDIRECTION                              1624\n#define EXPORT_PHCREATEPROCESSWIN32                                    1625\n#define EXPORT_PHCREATEPROCESSWIN32EX                                  1626\n#define EXPORT_PHCREATESAVEFILEDIALOG                                  1627\n#define EXPORT_PHDELETEIMAGEVERSIONINFO                                1628\n#define EXPORT_PHDEVFREEOBJECTPROPERTIES                               1629\n#define EXPORT_PHDEVFREEOBJECTS                                        1630\n#define EXPORT_PHDEVGETOBJECTPROPERTIES                                1631\n#define EXPORT_PHDEVGETOBJECTS                                         1632\n#define EXPORT_PHELLIPSISSTRING                                        1633\n#define EXPORT_PHELLIPSISSTRINGPATH                                    1634\n#define EXPORT_PHESCAPECOMMANDLINEPART                                 1635\n#define EXPORT_PHESCAPESTRINGFORMENUPREFIX                             1636\n#define EXPORT_PHEXPANDENVIRONMENTSTRINGS                              1637\n#define EXPORT_PHFILEREADALLTEXTWIN32                                  1638\n#define EXPORT_PHFINALHASH                                             1639\n#define EXPORT_PHFORMATDATE                                            1640\n#define EXPORT_PHFORMATDATETIME                                        1641\n#define EXPORT_PHFORMATDECIMAL                                         1642\n#define EXPORT_PHFORMATGUID                                            1643\n#define EXPORT_PHFORMATIMAGEVERSIONINFO                                1644\n#define EXPORT_PHFORMATSIZE                                            1645\n#define EXPORT_PHFORMATTIME                                            1646\n#define EXPORT_PHFORMATTIMESPAN                                        1647\n#define EXPORT_PHFORMATTIMESPANRELATIVE                                1648\n#define EXPORT_PHFORMATUINT64                                          1649\n#define EXPORT_PHFREEFILEDIALOG                                        1650\n#define EXPORT_PHFREELIBRARY                                           1651\n#define EXPORT_PHFREELIBRARYASIMAGERESOURCE                            1652\n#define EXPORT_PHGENERATEGUID                                          1653\n#define EXPORT_PHGENERATEGUIDFROMNAME                                  1654\n#define EXPORT_PHGENERATERANDOMALPHASTRING                             1655\n#define EXPORT_PHGENERATERANDOMNUMBER64                                1656\n#define EXPORT_PHGETAPPLICATIONDATAFILENAME                            1657\n#define EXPORT_PHGETAPPLICATIONDIRECTORY                               1658\n#define EXPORT_PHGETAPPLICATIONDIRECTORYFILENAME                       1659\n#define EXPORT_PHGETAPPLICATIONDIRECTORYWIN32                          1660\n#define EXPORT_PHGETAPPLICATIONFILENAMEWIN32                           1661\n#define EXPORT_PHGETBASEDIRECTORY                                      1662\n#define EXPORT_PHGETBASENAME                                           1663\n#define EXPORT_PHGETCLASSOBJECT                                        1664\n#define EXPORT_PHGETDLLFILENAME                                        1665\n#define EXPORT_PHGETCLIENTRECT                                         1666\n#define EXPORT_PHGETDPI                                                1667\n#define EXPORT_PHGETDPIVALUE                                           1668\n#define EXPORT_PHGETFILEDIALOGFILENAME                                 1669\n#define EXPORT_PHGETFILEDIALOGFILTERINDEX                              1670\n#define EXPORT_PHGETFILEDIALOGOPTIONS                                  1671\n#define EXPORT_PHGETFILEVERSIONFIXEDINFO                               1672\n#define EXPORT_PHGETFILEVERSIONINFO                                    1673\n#define EXPORT_PHGETFILEVERSIONINFOEX                                  1674\n#define EXPORT_PHGETFILEVERSIONINFOLANGCODEPAGE                        1675\n#define EXPORT_PHGETFILEVERSIONINFOSTRING                              1676\n#define EXPORT_PHGETFILEVERSIONINFOSTRING2                             1677\n#define EXPORT_PHGETFULLPATH                                           1678\n#define EXPORT_PHGETKNOWNFOLDERPATH                                    1679\n#define EXPORT_PHGETKNOWNLOCATION                                      1680\n#define EXPORT_PHGETMESSAGE                                            1681\n#define EXPORT_PHGETMONITORDPI                                         1682\n#define EXPORT_PHGETNTMESSAGE                                          1683\n#define EXPORT_PHGETNTSYSTEMROOT                                       1684\n#define EXPORT_PHGETSIZEDPIVALUE                                       1685\n#define EXPORT_PHGETSTATUSMESSAGE                                      1686\n#define EXPORT_PHGETSYSTEMDIRECTORY                                    1687\n#define EXPORT_PHGETSYSTEMDPI                                          1688\n#define EXPORT_PHGETSYSTEMMETRICS                                      1689\n#define EXPORT_PHGETSYSTEMPARAMETERSINFO                               1690\n#define EXPORT_PHGETSYSTEMROOT                                         1691\n#define EXPORT_PHGETTASKBARDPI                                         1692\n#define EXPORT_PHGETTEMPORARYDIRECTORYRANDOMALPHAFILENAME              1693\n#define EXPORT_PHGETWIN32MESSAGE                                       1694\n#define EXPORT_PHGETWINDOWDPI                                          1695\n#define EXPORT_PHINITIALIZEHASH                                        1696\n#define EXPORT_PHINITIALIZEIMAGEVERSIONINFO                            1697\n#define EXPORT_PHINITIALIZEIMAGEVERSIONINFOEX                          1698\n#define EXPORT_PHINITIALIZEPROCTHREADATTRIBUTELIST                     1699\n#define EXPORT_PHLARGEINTEGERTOLOCALSYSTEMTIME                         1700\n#define EXPORT_PHLARGEINTEGERTOSYSTEMTIME                              1701\n#define EXPORT_PHLOADLIBRARY                                           1702\n#define EXPORT_PHLOADLIBRARYASIMAGERESOURCE                            1703\n#define EXPORT_PHMAPFLAGS1                                             1704\n#define EXPORT_PHMAPFLAGS2                                             1705\n#define EXPORT_PHMATCHWILDCARDS                                        1706\n#define EXPORT_PHPARSECOMMANDLINE                                      1707\n#define EXPORT_PHPARSECOMMANDLINEFUZZY                                 1708\n#define EXPORT_PHPARSECOMMANDLINEPART                                  1709\n#define EXPORT_PHQUERYREGISTRYSTRING                                   1710\n#define EXPORT_PHQUERYREGISTRYULONG                                    1711\n#define EXPORT_PHQUERYREGISTRYULONG64                                  1712\n#define EXPORT_PHSETFILEDIALOGFILENAME                                 1713\n#define EXPORT_PHSETFILEDIALOGFILTER                                   1714\n#define EXPORT_PHSETFILEDIALOGOPTIONS                                  1715\n#define EXPORT_PHSHELLEXECUTE                                          1716\n#define EXPORT_PHSHELLEXECUTEEX                                        1717\n#define EXPORT_PHSHELLEXPLOREFILE                                      1718\n#define EXPORT_PHSHELLPROPERTIES                                       1719\n#define EXPORT_PHSHOWCONFIRMMESSAGE                                    1720\n#define EXPORT_PHSHOWCONTINUESTATUS                                    1721\n#define EXPORT_PHSHOWFILEDIALOG                                        1722\n#define EXPORT_PHSHOWMESSAGE                                           1723\n#define EXPORT_PHSHOWMESSAGE2                                          1724\n#define EXPORT_PHSHOWMESSAGEONETIME                                    1725\n#define EXPORT_PHSHOWSTATUS                                            1726\n#define EXPORT_PHSHOWTASKDIALOG                                        1727\n#define EXPORT_PHSTRINGTOGUID                                          1728\n#define EXPORT_PHSYSTEMTIMETOLARGEINTEGER                              1729\n#define EXPORT_PHSYSTEMTIMETOTZSPECIFICLOCALTIME                       1730\n#define EXPORT_PHTASKBARLISTCREATE                                     1731\n#define EXPORT_PHTASKBARLISTDESTROY                                    1732\n#define EXPORT_PHTASKBARLISTSETOVERLAYICON                             1733\n#define EXPORT_PHTASKBARLISTSETPROGRESSSTATE                           1734\n#define EXPORT_PHTASKBARLISTSETPROGRESSVALUE                           1735\n#define EXPORT_PHUPDATEHASH                                            1736\n#define EXPORT_PHUPDATEPROCTHREADATTRIBUTE                             1737\n#define EXPORT_PHWAITFORMULTIPLEOBJECTSANDPUMP                         1738\n#define EXPORT_PHCLEARCIRCULARBUFFER_FLOAT                             1739\n#define EXPORT_PHCLEARCIRCULARBUFFER_PVOID                             1740\n#define EXPORT_PHCLEARCIRCULARBUFFER_ULONG                             1741\n#define EXPORT_PHCLEARCIRCULARBUFFER_ULONG64                           1742\n#define EXPORT_PHCOPYCIRCULARBUFFER_FLOAT                              1743\n#define EXPORT_PHCOPYCIRCULARBUFFER_PVOID                              1744\n#define EXPORT_PHCOPYCIRCULARBUFFER_ULONG                              1745\n#define EXPORT_PHCOPYCIRCULARBUFFER_ULONG64                            1746\n#define EXPORT_PHDELETECIRCULARBUFFER_FLOAT                            1747\n#define EXPORT_PHDELETECIRCULARBUFFER_PVOID                            1748\n#define EXPORT_PHDELETECIRCULARBUFFER_ULONG                            1749\n#define EXPORT_PHDELETECIRCULARBUFFER_ULONG64                          1750\n#define EXPORT_PHINITIALIZECIRCULARBUFFER_FLOAT                        1751\n#define EXPORT_PHINITIALIZECIRCULARBUFFER_PVOID                        1752\n#define EXPORT_PHINITIALIZECIRCULARBUFFER_ULONG                        1753\n#define EXPORT_PHINITIALIZECIRCULARBUFFER_ULONG64                      1754\n#define EXPORT_PHRESIZECIRCULARBUFFER_FLOAT                            1755\n#define EXPORT_PHRESIZECIRCULARBUFFER_PVOID                            1756\n#define EXPORT_PHRESIZECIRCULARBUFFER_ULONG                            1757\n#define EXPORT_PHRESIZECIRCULARBUFFER_ULONG64                          1758\n#define EXPORT_PHGETGENERICTREENEWLINES                                1759\n#define EXPORT_PHGETLISTVIEWITEMTEXT                                   1760\n#define EXPORT_PHGETLISTVIEWSELECTEDITEMTEXT                           1761\n#define EXPORT_PHGETTREENEWTEXT                                        1762\n#define EXPORT_PHCREATEEMENU                                           1763\n#define EXPORT_PHCREATEEMENUITEM                                       1764\n#define EXPORT_PHDESTROYEMENU                                          1765\n#define EXPORT_PHDESTROYEMENUITEM                                      1766\n#define EXPORT_PHFINDEMENUITEM                                         1767\n#define EXPORT_PHINDEXOFEMENUITEM                                      1768\n#define EXPORT_PHINSERTEMENUITEM                                       1769\n#define EXPORT_PHLOADRESOURCEEMENUITEM                                 1770\n#define EXPORT_PHMODIFYEMENUITEM                                       1771\n#define EXPORT_PHREMOVEALLEMENUITEMS                                   1772\n#define EXPORT_PHREMOVEEMENUITEM                                       1773\n#define EXPORT_PHSETFLAGSALLEMENUITEMS                                 1774\n#define EXPORT_PHSETFLAGSEMENUITEM                                     1775\n#define EXPORT_PHSHOWEMENU                                             1776\n#define EXPORT_PHDELETEFASTLOCK                                        1777\n#define EXPORT_PHINITIALIZEFASTLOCK                                    1778\n#define EXPORT_PHFACQUIREFASTLOCKEXCLUSIVE                             1779\n#define EXPORT_PHFACQUIREFASTLOCKSHARED                                1780\n#define EXPORT_PHFRELEASEFASTLOCKEXCLUSIVE                             1781\n#define EXPORT_PHFRELEASEFASTLOCKSHARED                                1782\n#define EXPORT_PHFTRYACQUIREFASTLOCKEXCLUSIVE                          1783\n#define EXPORT_PHFTRYACQUIREFASTLOCKSHARED                             1784\n#define EXPORT_PHCREATEFILESTREAM                                      1785\n#define EXPORT_PHCREATEFILESTREAM2                                     1786\n#define EXPORT_PHFLUSHFILESTREAM                                       1787\n#define EXPORT_PHGETPOSITIONFILESTREAM                                 1788\n#define EXPORT_PHLOCKFILESTREAM                                        1789\n#define EXPORT_PHREADFILESTREAM                                        1790\n#define EXPORT_PHSEEKFILESTREAM                                        1791\n#define EXPORT_PHUNLOCKFILESTREAM                                      1792\n#define EXPORT_PHVERIFYFILESTREAM                                      1793\n#define EXPORT_PHWRITEFILESTREAM                                       1794\n#define EXPORT_PHWRITESTRINGASUTF8FILESTREAM                           1795\n#define EXPORT_PHWRITESTRINGASUTF8FILESTREAMEX                         1796\n#define EXPORT_PHWRITESTRINGFORMATASUTF8FILESTREAM                     1797\n#define EXPORT_PHWRITESTRINGFORMATASUTF8FILESTREAM_V                   1798\n#define EXPORT_PHDELETEGRAPHSTATE                                      1799\n#define EXPORT_PHDRAWGRAPHDIRECT                                       1800\n#define EXPORT_PHDRAWTRAYICONTEXT                                      1801\n#define EXPORT_PHGETDRAWINFOGRAPHBUFFERS                               1802\n#define EXPORT_PHGRAPHSTATEGETDRAWINFO                                 1803\n#define EXPORT_PHINITIALIZEGRAPHSTATE                                  1804\n#define EXPORT_PHNFGETTRAYICONFONT                                     1805\n#define EXPORT_PHSETGRAPHTEXT                                          1806\n#define EXPORT_PHADDLAYOUTITEM                                         1807\n#define EXPORT_PHADDLAYOUTITEMEX                                       1808\n#define EXPORT_PHADDLISTVIEWCOLUMN                                     1809\n#define EXPORT_PHADDILISTVIEWCOLUMN                                    1810\n#define EXPORT_PHADDILISTVIEWGROUP                                     1811\n#define EXPORT_PHADDILISTVIEWGROUPITEM                                 1812\n#define EXPORT_PHADDLISTVIEWGROUP                                      1813\n#define EXPORT_PHADDLISTVIEWGROUPITEM                                  1814\n#define EXPORT_PHADDLISTVIEWITEM                                       1815\n#define EXPORT_PHADDILISTVIEWITEM                                      1816\n#define EXPORT_PHADDTABCONTROLTAB                                      1817\n#define EXPORT_PHBITMAPSETALPHA                                        1818\n#define EXPORT_PHCREATEDIALOG                                          1819\n#define EXPORT_PHCREATEWINDOWEX                                        1820\n#define EXPORT_PHDELETELAYOUTMANAGER                                   1821\n#define EXPORT_PHDIALOGBOX                                             1822\n#define EXPORT_PHENUMCHILDWINDOWS                                      1823\n#define EXPORT_PHENUMWINDOWS                                           1824\n#define EXPORT_PHFINDILISTVIEWITEMBYFLAGS                              1825\n#define EXPORT_PHFINDLISTVIEWITEMBYFLAGS                               1826\n#define EXPORT_PHFINDLISTVIEWITEMBYPARAM                               1827\n#define EXPORT_PHGETCOMBOBOXSTRING                                     1828\n#define EXPORT_PHGETDIALOGITEMVALUE                                    1829\n#define EXPORT_PHGETILISTVIEWITEMPARAM                                 1830\n#define EXPORT_PHGETLISTBOXSTRING                                      1831\n#define EXPORT_PHGETLISTVIEWITEMIMAGEINDEX                             1832\n#define EXPORT_PHGETLISTVIEWITEMPARAM                                  1833\n#define EXPORT_PHGETSELECTEDLISTVIEWITEMPARAM                          1834\n#define EXPORT_PHGETSELECTEDLISTVIEWITEMPARAMS                         1835\n#define EXPORT_PHGETSELECTEDILISTVIEWITEMPARAMS                        1836\n#define EXPORT_PHGETSTOCKAPPLICATIONICON                               1837\n#define EXPORT_PHGETSTOCKOBJECT                                        1838\n#define EXPORT_PHGETWINDOWCLIENTID                                     1839\n#define EXPORT_PHGETWINDOWCONTEXT                                      1840\n#define EXPORT_PHGETWINDOWTEXT                                         1841\n#define EXPORT_PHGETWINDOWTEXTEX                                       1842\n#define EXPORT_PHICONTOBITMAP                                          1843\n#define EXPORT_PHIMAGELISTADDBITMAP                                    1844\n#define EXPORT_PHIMAGELISTADDICON                                      1845\n#define EXPORT_PHIMAGELISTCREATE                                       1846\n#define EXPORT_PHIMAGELISTDESTROY                                      1847\n#define EXPORT_PHIMAGELISTDRAWEX                                       1848\n#define EXPORT_PHIMAGELISTDRAWICON                                     1849\n#define EXPORT_PHIMAGELISTGETICON                                      1850\n#define EXPORT_PHIMAGELISTREMOVEICON                                   1851\n#define EXPORT_PHIMAGELISTREPLACE                                      1852\n#define EXPORT_PHIMAGELISTSETBKCOLOR                                   1853\n#define EXPORT_PHIMAGELISTSETICONSIZE                                  1854\n#define EXPORT_PHIMAGELISTSETIMAGECOUNT                                1855\n#define EXPORT_PHINITIALIZELAYOUTMANAGER                               1856\n#define EXPORT_PHLAYOUTMANAGERLAYOUT                                   1857\n#define EXPORT_PHLOADICON                                              1858\n#define EXPORT_PHLOADIMAGEFORMATFROMRESOURCE                           1859\n#define EXPORT_PHMODALPROPERTYSHEET                                    1860\n#define EXPORT_PHQUERYDIRECTXEXCLUSIVEOWNERSHIP                        1861\n#define EXPORT_PHINITIALIZEWINDOWTHEME                                 1862\n#define EXPORT_PHREINITIALIZEWINDOWTHEME                               1863\n#define EXPORT_PHREGISTERWINDOWCALLBACK                                1864\n#define EXPORT_PHREMOVELISTVIEWITEM                                    1865\n#define EXPORT_PHREMOVEWINDOWCONTEXT                                   1866\n#define EXPORT_PHSELECTCOMBOBOXSTRING                                  1867\n#define EXPORT_PHSETCLIPBOARDSTRING                                    1868\n#define EXPORT_PHSETCONTROLTHEME                                       1869\n#define EXPORT_PHSETDIALOGITEMTEXT                                     1870\n#define EXPORT_PHSETDIALOGITEMVALUE                                    1871\n#define EXPORT_PHSETEXTENDEDLISTVIEW                                   1872\n#define EXPORT_PHSETGROUPBOXTEXT                                       1873\n#define EXPORT_PHSETHEADERSORTICON                                     1874\n#define EXPORT_PHSETIMAGELISTBITMAP                                    1875\n#define EXPORT_PHSETLISTVIEWITEMIMAGEINDEX                             1876\n#define EXPORT_PHSETLISTVIEWITEMPARAM                                  1877\n#define EXPORT_PHSETLISTVIEWSUBITEM                                    1878\n#define EXPORT_PHSETILISTVIEWSUBITEM                                   1879\n#define EXPORT_PHSETSTATEALLLISTVIEWITEMS                              1880\n#define EXPORT_PHSETWINDOWCONTEXT                                      1881\n#define EXPORT_PHSETWINDOWTEXT                                         1882\n#define EXPORT_PHTHEMEWINDOWDRAWREBAR                                  1883\n#define EXPORT_PHTHEMEWINDOWDRAWTOOLBAR                                1884\n#define EXPORT_PHUNREGISTERWINDOWCALLBACK                              1885\n#define EXPORT_PHWINDOWTHEMECONTROLCOLOR                               1886\n#define EXPORT_PHCALLKPHQUERYFILEINFORMATIONWITHTIMEOUT                1887\n#define EXPORT_PHCOMPAREOBJECTS                                        1888\n#define EXPORT_PHENUMOBJECTTYPES                                       1889\n#define EXPORT_PHFORMATNATIVEKEYNAME                                   1890\n#define EXPORT_PHGETETWPUBLISHERNAME                                   1891\n#define EXPORT_PHGETHANDLEINFORMATION                                  1892\n#define EXPORT_PHGETHANDLEINFORMATIONEX                                1893\n#define EXPORT_PHGETOBJECTTYPENAME                                     1894\n#define EXPORT_PHQUERYOBJECTNAME                                       1895\n#define EXPORT_PHSTDGETCLIENTIDNAME                                    1896\n#define EXPORT_PHENUMERATEPRIVILEGES                                   1897\n#define EXPORT_PHGETSIDFULLNAME                                        1898\n#define EXPORT_PHLOOKUPNAME                                            1899\n#define EXPORT_PHLOOKUPPRIVILEGEDISPLAYNAME                            1900\n#define EXPORT_PHLOOKUPPRIVILEGENAME                                   1901\n#define EXPORT_PHLOOKUPPRIVILEGEVALUE                                  1902\n#define EXPORT_PHLOOKUPSID                                             1903\n#define EXPORT_PHOPENLSAPOLICY                                         1904\n#define EXPORT_PHSIDTOSTRINGSID                                        1905\n#define EXPORT_PHLOADMAPPEDIMAGE                                       1906\n#define EXPORT_PHLOADMAPPEDIMAGEEX                                     1907\n#define EXPORT_PHLOADMAPPEDIMAGEHEADERPAGESIZE                         1908\n#define EXPORT_PHUNLOADMAPPEDIMAGE                                     1909\n#define EXPORT_PHBOOSTPROVIDER                                         1910\n#define EXPORT_PHDELETEPROVIDERTHREAD                                  1911\n#define EXPORT_PHGETENABLEDPROVIDER                                    1912\n#define EXPORT_PHINITIALIZEPROVIDERTHREAD                              1913\n#define EXPORT_PHREGISTERPROVIDER                                      1914\n#define EXPORT_PHSETENABLEDPROVIDER                                    1915\n#define EXPORT_PHSETINTERVALPROVIDERTHREAD                             1916\n#define EXPORT_PHSTARTPROVIDERTHREAD                                   1917\n#define EXPORT_PHSTOPPROVIDERTHREAD                                    1918\n#define EXPORT_PHUNREGISTERPROVIDER                                    1919\n#define EXPORT_PHADDSETTING                                            1920\n#define EXPORT_PHADDSETTINGS                                           1921\n#define EXPORT_PHCLEARIGNOREDSETTINGS                                  1922\n#define EXPORT_PHCONVERTIGNOREDSETTINGS                                1923\n#define EXPORT_PHGETINTEGERPAIRSTRINGREFSETTING                        1924\n#define EXPORT_PHGETINTEGERSTRINGREFSETTING                            1925\n#define EXPORT_PHGETSCALABLEINTEGERPAIRSTRINGREFSETTING                1926\n#define EXPORT_PHGETSTRINGREFSETTING                                   1927\n#define EXPORT_PHLOADCUSTOMCOLORLIST                                   1928\n#define EXPORT_PHLOADLISTVIEWCOLUMNSETTINGS                            1929\n#define EXPORT_PHLOADLISTVIEWCOLUMNSFROMSETTING                        1930\n#define EXPORT_PHLOADLISTVIEWGROUPSTATESFROMSETTING                    1931\n#define EXPORT_PHLOADLISTVIEWSORTCOLUMNSFROMSETTING                    1932\n#define EXPORT_PHLOADSETTINGS                                          1933\n#define EXPORT_PHLOADWINDOWPLACEMENTFROMSETTING                        1934\n#define EXPORT_PHRESETSETTINGS                                         1935\n#define EXPORT_PHSAVECUSTOMCOLORLIST                                   1936\n#define EXPORT_PHSAVELISTVIEWCOLUMNSETTINGS                            1937\n#define EXPORT_PHSAVELISTVIEWCOLUMNSTOSETTING                          1938\n#define EXPORT_PHSAVELISTVIEWGROUPSTATESTOSETTING                      1939\n#define EXPORT_PHSAVELISTVIEWSORTCOLUMNSTOSETTING                      1940\n#define EXPORT_PHSAVESETTINGS                                          1941\n#define EXPORT_PHSAVEWINDOWPLACEMENTTOSETTING                          1942\n#define EXPORT_PHSETINTEGERPAIRSTRINGREFSETTING                        1943\n#define EXPORT_PHSETINTEGERSTRINGREFSETTING                            1944\n#define EXPORT_PHSETSCALABLEINTEGERPAIRSTRINGREFSETTING                1945\n#define EXPORT_PHSETSCALABLEINTEGERPAIRSTRINGREFSETTING2               1946\n#define EXPORT_PHSETSTRINGREFSETTING                                   1947\n#define EXPORT_PHUPDATECACHEDSETTINGS                                  1948\n#define EXPORT_PHCREATESECURITYPAGE                                    1949\n#define EXPORT_PHEDITSECURITY                                          1950\n#define EXPORT_PHGETACCESSENTRIES                                      1951\n#define EXPORT_PHGETACCESSSTRING                                       1952\n#define EXPORT_PHGETSEOBJECTSECURITY                                   1953\n#define EXPORT_PHSETSEOBJECTSECURITY                                   1954\n#define EXPORT_PHSTDGETOBJECTSECURITY                                  1955\n#define EXPORT_PHSTDSETOBJECTSECURITY                                  1956\n#define EXPORT_PHCHANGESERVICECONFIG2                                  1957\n#define EXPORT_PHCLOSESERVICEHANDLE                                    1958\n#define EXPORT_PHENUMDEPENDENTSERVICES                                 1959\n#define EXPORT_PHGETSERVICECONFIG                                      1960\n#define EXPORT_PHGETSERVICECONFIGFILENAME                              1961\n#define EXPORT_PHGETSERVICEDESCRIPTION                                 1962\n#define EXPORT_PHGETSERVICEDLLPARAMETER                                1963\n#define EXPORT_PHGETSERVICEERRORCONTROLINTEGER                         1964\n#define EXPORT_PHGETSERVICEERRORCONTROLSTRING                          1965\n#define EXPORT_PHGETSERVICEFILENAME                                    1966\n#define EXPORT_PHGETSERVICENAMEFROMTAG                                 1967\n#define EXPORT_PHGETSERVICESTARTTYPEINTEGER                            1968\n#define EXPORT_PHGETSERVICESTARTTYPESTRING                             1969\n#define EXPORT_PHGETSERVICESTATESTRING                                 1970\n#define EXPORT_PHGETSERVICETYPEINTEGER                                 1971\n#define EXPORT_PHGETSERVICETYPESTRING                                  1972\n#define EXPORT_PHGETTHREADSERVICETAG                                   1973\n#define EXPORT_PHOPENSERVICE                                           1974\n#define EXPORT_PHOPENSERVICEKEY                                        1975\n#define EXPORT_PHQUERYSERVICECONFIG                                    1976\n#define EXPORT_PHQUERYSERVICECONFIG2                                   1977\n#define EXPORT_PHQUERYSERVICESTATUS                                    1978\n#define EXPORT_PHQUERYSERVICEVARIABLESIZE                              1979\n#define EXPORT_PHSTARTSERVICE                                          1980\n#define EXPORT_PHSTOPSERVICE                                           1981\n#define EXPORT_PHCREATESYMBOLPROVIDER                                  1982\n#define EXPORT_PHGETLINEFROMADDRESS                                    1983\n#define EXPORT_PHGETMODULEFROMADDRESS                                  1984\n#define EXPORT_PHGETSYMBOLFROMADDRESS                                  1985\n#define EXPORT_PHGETSYMBOLFROMNAME                                     1986\n#define EXPORT_PHLOADSYMBOLPROVIDERMODULES                             1987\n#define EXPORT_PHLOADMODULESYMBOLPROVIDER                              1988\n#define EXPORT_PHLOADMODULESFORVIRTUALSYMBOLPROVIDER                   1989\n#define EXPORT_PHSETOPTIONSSYMBOLPROVIDER                              1990\n#define EXPORT_PHSETSEARCHPATHSYMBOLPROVIDER                           1991\n#define EXPORT_PHSTACKWALK                                             1992\n#define EXPORT_PHWALKTHREADSTACK                                       1993\n#define EXPORT_PHWRITEMINIDUMPPROCESS                                  1994\n#define EXPORT_PHVERIFYFILE                                            1995\n#define EXPORT_PHVERIFYFILEISCHAINEDTOMICROSOFT                        1996\n#define EXPORT_PHDELETEWORKQUEUE                                       1997\n#define EXPORT_PHGETGLOBALWORKQUEUE                                    1998\n#define EXPORT_PHINITIALIZEWORKQUEUE                                   1999\n#define EXPORT_PHINITIALIZEWORKQUEUEENVIRONMENT                        2000\n#define EXPORT_PHQUEUEITEMWORKQUEUE                                    2001\n#define EXPORT_PHQUEUEITEMWORKQUEUEEX                                  2002\n#define EXPORT_PHWAITFORWORKQUEUE                                      2003\n#define EXPORT_PHADDJSONARRAYOBJECT                                    2004\n#define EXPORT_PHADDJSONOBJECT                                         2005\n#define EXPORT_PHADDJSONOBJECT2                                        2006\n#define EXPORT_PHADDJSONOBJECTINT64                                    2007\n#define EXPORT_PHADDJSONOBJECTUINT64                                   2008\n#define EXPORT_PHADDJSONOBJECTVALUE                                    2009\n#define EXPORT_PHCREATEJSONARRAY                                       2010\n#define EXPORT_PHCREATEJSONOBJECT                                      2011\n#define EXPORT_PHCREATEJSONPARSER                                      2012\n#define EXPORT_PHCREATEJSONPARSEREX                                    2013\n#define EXPORT_PHFREEJSONOBJECT                                        2014\n#define EXPORT_PHGETJSONARRAYINDEXOBJECT                               2015\n#define EXPORT_PHGETJSONARRAYLENGTH                                    2016\n#define EXPORT_PHGETJSONARRAYLONG64                                    2017\n#define EXPORT_PHGETJSONARRAYSTRING                                    2018\n#define EXPORT_PHGETJSONOBJECT                                         2019\n#define EXPORT_PHGETJSONOBJECTASARRAYLIST                              2020\n#define EXPORT_PHGETJSONOBJECTBOOL                                     2021\n#define EXPORT_PHGETJSONOBJECTLENGTH                                   2022\n#define EXPORT_PHGETJSONOBJECTTYPE                                     2023\n#define EXPORT_PHGETJSONVALUEASINT64                                   2024\n#define EXPORT_PHGETJSONVALUEASSTRING                                  2025\n#define EXPORT_PHGETJSONVALUEASUINT64                                  2026\n#define EXPORT_PHCREATEXMLNODE                                         2027\n#define EXPORT_PHCREATEXMLOPAQUENODE                                   2028\n#define EXPORT_PHFINDXMLOBJECT                                         2029\n#define EXPORT_PHFREEXMLOBJECT                                         2030\n#define EXPORT_PHGETXMLINTERFACE                                       2031\n#define EXPORT_PHGETXMLNODEATTRIBUTEBYINDEX                            2032\n#define EXPORT_PHGETXMLNODEATTRIBUTECOUNT                              2033\n#define EXPORT_PHGETXMLNODEATTRIBUTETEXT                               2034\n#define EXPORT_PHGETXMLNODEELEMENTTEXT                                 2035\n#define EXPORT_PHGETXMLNODEFIRSTCHILD                                  2036\n#define EXPORT_PHGETXMLNODENEXTCHILD                                   2037\n#define EXPORT_PHGETXMLNODEOPAQUETEXT                                  2038\n#define EXPORT_PHGETXMLOBJECT                                          2039\n#define EXPORT_PHLOADXMLOBJECTFROMFILE                                 2040\n#define EXPORT_PHLOADXMLOBJECTFROMSTRING                               2041\n#define EXPORT_PHSAVEXMLOBJECTTOFILE                                   2042\n#define EXPORT_PHSETXMLNODEATTRIBUTETEXT                               2043\n#define EXPORT_PHCLEARCACHEDIRECTORY                                   2044\n#define EXPORT_PHCREATECACHEFILE                                       2045\n#define EXPORT_PHDELETECACHEFILE                                       2046\n#define EXPORT_PHAPPRESOLVERGETAPPIDFORWINDOW                          2047\n#define EXPORT_PHGETPROCESSPACKAGEFULLNAME                             2048\n#define EXPORT_PHDNSFREE                                               2049\n#define EXPORT_PHDNSQUERY                                              2050\n#define EXPORT_PHDNSQUERY2                                             2051\n#define EXPORT_PHHTTPDNSQUERY                                          2052\n#define EXPORT_PHHTTPSOCKETADDREQUESTHEADERS                           2053\n#define EXPORT_PHHTTPSOCKETBEGINREQUEST                                2054\n#define EXPORT_PHHTTPSOCKETCLOSE                                       2055\n#define EXPORT_PHHTTPSOCKETCONNECT                                     2056\n#define EXPORT_PHHTTPSOCKETCREATE                                      2057\n#define EXPORT_PHHTTPSOCKETDESTROY                                     2058\n#define EXPORT_PHHTTPSOCKETDOWNLOADSTRING                              2059\n#define EXPORT_PHHTTPSOCKETENDREQUEST                                  2060\n#define EXPORT_PHHTTPSOCKETGETERRORMESSAGE                             2061\n#define EXPORT_PHHTTPSOCKETPARSEURL                                    2062\n#define EXPORT_PHHTTPSOCKETQUERYHEADERSTRING                           2063\n#define EXPORT_PHHTTPSOCKETQUERYHEADERULONG                            2064\n#define EXPORT_PHHTTPSOCKETQUERYHEADERULONG64                          2065\n#define EXPORT_PHHTTPSOCKETQUERYHEADERS                                2066\n#define EXPORT_PHHTTPSOCKETQUERYOPTIONSTRING                           2067\n#define EXPORT_PHHTTPSOCKETREADDATA                                    2068\n#define EXPORT_PHHTTPSOCKETREADDATATOBUFFER                            2069\n#define EXPORT_PHHTTPSOCKETSENDREQUEST                                 2070\n#define EXPORT_PHHTTPSOCKETSETCREDENTIALS                              2071\n#define EXPORT_PHHTTPSOCKETSETFEATURE                                  2072\n#define EXPORT_PHHTTPSOCKETSETSECURITY                                 2073\n#define EXPORT_PHHTTPSOCKETWRITEDATA                                   2074\n#define EXPORT_KSILEVEL                                                2075\n#define EXPORT_KPHALPCQUERYINFORMATION                                 2076\n#define EXPORT_KPHDUPLICATEOBJECT                                      2077\n#define EXPORT_KPHOPENDEVICE                                           2078\n#define EXPORT_KPHOPENDEVICEBASEDEVICE                                 2079\n#define EXPORT_KPHOPENDEVICEDRIVER                                     2080\n#define EXPORT_KPHQUERYINFORMATIONDRIVER                               2081\n#define EXPORT_KPHQUERYINFORMATIONOBJECT                               2082\n#define EXPORT_KSIENUMERATEPROCESSHANDLES                              2083\n#define EXPORT_KSIQUERYHASHINFORMATIONFILE                             2084\n\n#endif _PH_EXPORT_DEF_H"
  },
  {
    "path": "SystemInformer/SystemInformer.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <assemblyIdentity name=\"System Informer\" processorArchitecture=\"*\" version=\"2.0.0.0\" type=\"win32\"/>\n  <description>System Informer</description>\n  <dependency>\n    <dependentAssembly>\n      <assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n    </dependentAssembly>\n  </dependency>\n  <dependency>\n    <dependentAssembly>\n      <assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.GdiPlus\" version=\"1.1.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n    </dependentAssembly>\n  </dependency>\n  <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <security>\n      <requestedPrivileges>\n        <requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\"/>\n      </requestedPrivileges>\n    </security>\n  </trustInfo>\n  <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n    <application>\n      <supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/>\n      <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n      <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n      <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n      <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n      <maxversiontested Id=\"10.0.18362.0\"/>\n    </application>\n  </compatibility>\n  <application xmlns:asmv3=\"urn:schemas-microsoft-com:asm.v3\">\n    <windowsSettings>\n      <dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">true/pm</dpiAware>\n      <disableWindowFiltering xmlns=\"http://schemas.microsoft.com/SMI/2011/WindowsSettings\">true</disableWindowFiltering>\n      <printerDriverIsolation xmlns=\"http://schemas.microsoft.com/SMI/2011/WindowsSettings\">true</printerDriverIsolation>\n      <dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n      <longPathAware xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">true</longPathAware>\n      <activeCodePage xmlns=\"http://schemas.microsoft.com/SMI/2019/WindowsSettings\">UTF-8</activeCodePage>\n      <heapType xmlns=\"http://schemas.microsoft.com/SMI/2020/WindowsSettings\">SegmentHeap</heapType>\n    </windowsSettings>\n  </application>\n</assembly>"
  },
  {
    "path": "SystemInformer/SystemInformer.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#pragma code_page(65001)\n\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"winres.h\"\n#include \"include/phappres.h\"\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// English (United States) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE\nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE\nBEGIN\n    \"#include \"\"winres.h\"\"\\r\\n\"\n    \"#include \"\"include/phappres.h\"\"\\0\"\nEND\n\n3 TEXTINCLUDE\nBEGIN\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// PNG\n//\n\nIDB_SEARCH_ACTIVE_MODERN_LIGHT PNG                     \"resources\\\\search_stop_modern_light.png\"\n\nIDB_SEARCH_ACTIVE       PNG                     \"resources\\\\active_search.png\"\n\nIDB_SEARCH_INACTIVE     PNG                     \"resources\\\\inactive_search.png\"\n\nIDB_SEARCH_ACTIVE_SMALL PNG                     \"resources\\\\active_search_small.png\"\n\nIDB_SEARCH_INACTIVE_SMALL PNG                     \"resources\\\\inactive_search_small.png\"\n\nIDB_SEARCH_REGEX_MODERN_DARK PNG                     \"resources\\\\regex_modern_dark.png\"\n\nIDB_SEARCH_REGEX_MODERN_LIGHT PNG                     \"resources\\\\regex_modern_light.png\"\n\nIDB_SEARCH_CASE_MODERN_DARK PNG                     \"resources\\\\case_sensitive_modern_dark.png\"\n\nIDB_SEARCH_CASE_MODERN_LIGHT PNG                     \"resources\\\\case_sensitive_modern_light.png\"\n\nIDB_SEARCH_ACTIVE_MODERN_DARK PNG                     \"resources\\\\search_stop_modern_dark.png\"\n\nIDB_SEARCH_INACTIVE_MODERN_LIGHT PNG                     \"resources\\\\search_modern_light.png\"\n\nIDB_SEARCH_INACTIVE_MODERN_DARK PNG                     \"resources\\\\search_modern_dark.png\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nIDI_PROCESSHACKER       ICON                    \"SystemInformer.ico\"\n\nIDI_PHAPPLICATION       ICON                    \"resources\\\\application.ico\"\n\nIDI_COG                 ICON                    \"resources\\\\cog.ico\"\n\nIDI_PIN                 ICON                    \"resources\\\\pin.ico\"\n\nIDI_FOLDER              ICON                    \"resources\\\\folder.ico\"\n\nIDI_MAGNIFIER           ICON                    \"resources\\\\magnifier.ico\"\n\nIDI_UACSHIELD           ICON                    \"resources\\\\shield.ico\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Dialog\n//\n\nIDD_PROCGENERAL DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"General\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Permissions\",IDC_PERMISSIONS,143,218,50,14\n    PUSHBUTTON      \"Terminate\",IDC_TERMINATE,197,218,50,14\n    GROUPBOX        \"File\",IDC_FILE,7,7,246,103\n    ICON            \"\",IDC_FILEICON,14,18,20,20\n    EDITTEXT        IDC_NAME,44,17,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    EDITTEXT        IDC_COMPANYNAME,44,29,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    CONTROL         \"<a>Company name link</a>\",IDC_COMPANYNAME_LINK,\"SysLink\",LWS_NOPREFIX | NOT WS_VISIBLE | WS_TABSTOP,46,29,183,9\n    LTEXT           \"Version:\",IDC_STATIC,15,41,27,8\n    EDITTEXT        IDC_VERSION,44,41,113,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Image file name (Win32):\",IDC_STATIC,15,55,86,8\n    EDITTEXT        IDC_FILENAME,15,65,191,12,ES_AUTOHSCROLL | ES_READONLY\n    PUSHBUTTON      \"Inspect\",IDC_INSPECT,210,64,17,15,BS_ICON\n    PUSHBUTTON      \"Open\",IDC_OPENFILENAME,230,64,17,15,BS_ICON\n    GROUPBOX        \"Process\",IDC_PROCESS,7,112,246,142\n    LTEXT           \"Command line:\",IDC_STATIC,13,124,50,8\n    EDITTEXT        IDC_CMDLINE,79,122,147,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Current directory:\",IDC_STATIC,13,140,60,8\n    EDITTEXT        IDC_CURDIR,79,138,168,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Started:\",IDC_STATIC,13,156,28,8\n    EDITTEXT        IDC_STARTED,79,154,168,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Parent console:\",IDC_STATIC,13,172,52,8\n    EDITTEXT        IDC_PARENTCONSOLE,79,170,168,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Parent process:\",IDC_STATIC,13,188,52,8\n    EDITTEXT        IDC_PARENTPROCESS,79,186,147,12,ES_AUTOHSCROLL | ES_READONLY\n    PUSHBUTTON      \"View\",IDC_VIEWPARENTPROCESS,230,185,17,15,BS_ICON\n    LTEXT           \"Mitigation policies:\",IDC_STATIC,13,204,59,8\n    EDITTEXT        IDC_MITIGATION,79,202,126,12,ES_AUTOHSCROLL | ES_READONLY\n    PUSHBUTTON      \"Details\",IDC_VIEWMITIGATION,209,201,38,14\n    LTEXT           \"Protection:\",IDC_STATIC,13,222,40,8\n    EDITTEXT        IDC_PROTECTION,53,222,80,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Image type:\",IDC_STATIC,13,233,40,8\n    EDITTEXT        IDC_PROCESSTYPETEXT,53,233,160,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    PUSHBUTTON      \"View\",IDC_VIEWCOMMANDLINE,230,121,17,15,BS_ICON\n    LTEXT           \"Image file name:\",IDC_STATIC,15,80,86,8\n    EDITTEXT        IDC_FILENAMEWIN32,15,91,191,12,ES_AUTOHSCROLL | ES_READONLY\n    PUSHBUTTON      \"Inspect\",IDC_INSPECT2,210,90,17,15,BS_ICON\n    PUSHBUTTON      \"Open\",IDC_OPENFILENAME2,230,90,17,15,BS_ICON\n    PUSHBUTTON      \"Policy\",IDC_INTEGRITY,90,218,50,14\nEND\n\nIDD_PROCMODULES DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Modules\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE\n    EDITTEXT        IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Options\",IDC_FILTEROPTIONS,2,2,50,14\nEND\n\nIDD_PROCTHREADS DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Threads\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE\n    EDITTEXT        IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Options\",IDC_OPTIONS,2,2,50,14\n    LTEXT           \"\",IDC_STATE,56,5,8,8\nEND\n\nIDD_PROCHANDLES DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Handles\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Options\",IDC_OPTIONS,2,2,50,14\n    EDITTEXT        IDC_HANDLESEARCH,114,3,144,14,ES_AUTOHSCROLL\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,256,239,WS_EX_CLIENTEDGE\nEND\n\nIDD_PROCENVIRONMENT DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Environment\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE\n    EDITTEXT        IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,53,2,50,14\n    PUSHBUTTON      \"Options\",IDC_OPTIONS,2,2,50,14\nEND\n\nIDD_THRDSTACK DIALOGEX 0, 0, 273, 228\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Thread Stack\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Copy\",IDC_COPY,113,212,50,14\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,167,212,50,14\n    PUSHBUTTON      \"Close\",IDOK,221,212,50,14\n    CONTROL         \"\",IDC_TREELIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,0,0,273,211,WS_EX_CLIENTEDGE\n    PUSHBUTTON      \"Options\",IDC_OPTIONS,2,212,50,14\nEND\n\nIDD_ABOUT DIALOGEX 0, 0, 270, 215\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"About\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    ICON            IDI_PROCESSHACKER,IDC_FILEICON,16,11,20,20\n    CONTROL         \"System Informer\",IDC_ABOUT_NAME,\"SysLink\",WS_TABSTOP,45,12,192,8\n    LTEXT           \"Copyright (c) Winsider Seminars && Solutions, Inc.\",IDC_STATIC,45,24,193,8\n    CONTROL         \"Credits.\",IDC_CREDITS,\"SysLink\",WS_TABSTOP,15,49,248,141\n    CONTROL         \"<a href=\"\"https://systeminformer.sourceforge.io\"\">System Informer on SourceForge.net</a>\",IDC_LINK_SF,\n                    \"SysLink\",WS_TABSTOP,7,197,130,11\n    PUSHBUTTON      \"Diagnostics\",IDC_DIAGNOSTICS,160,194,50,14\n    DEFPUSHBUTTON   \"OK\",IDOK,213,194,50,14\nEND\n\nIDD_SRVLIST DIALOGEX 0, 0, 237, 201\nSTYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,0,237,141\n    EDITTEXT        IDC_DESCRIPTION,0,144,237,40,ES_MULTILINE | ES_READONLY | NOT WS_BORDER\n    PUSHBUTTON      \"&Start\",IDC_START,134,187,50,14\n    PUSHBUTTON      \"&Pause\",IDC_PAUSE,187,187,50,14\nEND\n\nIDD_SRVGENERAL DIALOGEX 0, 0, 282, 183\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"General\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    EDITTEXT        IDC_DESCRIPTION,7,7,268,45,ES_MULTILINE | ES_READONLY | WS_VSCROLL\n    LTEXT           \"Type:\",IDC_STATIC,7,57,20,8\n    COMBOBOX        IDC_TYPE,30,56,110,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Start type:\",IDC_STATIC,147,57,38,8\n    COMBOBOX        IDC_STARTTYPE,188,56,87,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Error control:\",IDC_STATIC,7,75,47,8\n    COMBOBOX        IDC_ERRORCONTROL,58,73,82,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Group:\",IDC_STATIC,147,75,23,8\n    EDITTEXT        IDC_GROUP,173,74,102,12,ES_AUTOHSCROLL\n    LTEXT           \"Binary path:\",IDC_STATIC,7,92,40,8\n    EDITTEXT        IDC_BINARYPATH,58,91,163,12,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Browse...\",IDC_BROWSE,225,90,50,14\n    LTEXT           \"User account:\",IDC_STATIC,7,110,46,8\n    EDITTEXT        IDC_USERACCOUNT,58,108,217,12,ES_AUTOHSCROLL\n    LTEXT           \"Password:\",IDC_STATIC,7,127,34,8\n    EDITTEXT        IDC_PASSWORD,58,125,204,12,ES_PASSWORD | ES_AUTOHSCROLL\n    CONTROL         \"\",IDC_PASSWORDCHECK,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,266,126,9,10\n    LTEXT           \"Service DLL:\",IDC_STATIC,7,144,48,8\n    EDITTEXT        IDC_SERVICEDLL,58,142,217,12,ES_AUTOHSCROLL | ES_READONLY\n    CONTROL         \"Delayed start\",IDC_DELAYEDSTART,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,158,59,10\n    PUSHBUTTON      \"Permissions\",IDC_PERMISSIONS,225,162,50,14\nEND\n\nIDD_HNDLGENERAL DIALOGEX 0, 0, 260, 181\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"General\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_TABSTOP,0,2,260,179\nEND\n\nIDD_INFORMATION DIALOGEX 0, 0, 317, 184\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Information\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    EDITTEXT        IDC_TEXT,7,7,303,152,ES_MULTILINE | ES_READONLY | WS_VSCROLL\n    PUSHBUTTON      \"Save...\",IDC_SAVE,154,163,50,14\n    PUSHBUTTON      \"Copy\",IDC_COPY,207,163,50,14\n    DEFPUSHBUTTON   \"Close\",IDOK,260,163,50,14\nEND\n\nIDD_FINDOBJECTS DIALOGEX 0, 0, 357, 233\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Find Handles or DLLs\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    EDITTEXT        IDC_FILTER,97,4,207,14,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Find\",IDOK,306,4,50,14\n    COMBOBOX        IDC_FILTERTYPE,2,5,93,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    CONTROL         \"\",IDC_TREELIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,20,353,212,WS_EX_CLIENTEDGE\nEND\n\nIDD_THRDSTACKS DIALOGEX 0, 0, 443, 254\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Thread Stacks\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    EDITTEXT        IDC_FILTER,2,3,388,14,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,391,3,50,14\n    CONTROL         \"\",IDC_TREELIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,439,219,WS_EX_CLIENTEDGE\n    LTEXT           \"\",IDC_MESSAGE,8,242,427,10\nEND\n\nIDD_USRLIST DIALOGEX 0, 0, 443, 254\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Users List\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    EDITTEXT        IDC_FILTER,2,3,388,14,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,391,3,50,14\n    CONTROL         \"\",IDC_TREELIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,439,219,WS_EX_CLIENTEDGE\n    LTEXT           \"\",IDC_MESSAGE,8,242,427,10\nEND\n\nIDD_OBJTOKEN DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Token\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"User:\",IDC_TOKENUSER,7,7,18,8\n    EDITTEXT        IDC_USER,48,7,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"User SID:\",IDC_TOKENSID,7,18,32,8\n    EDITTEXT        IDC_USERSID,48,18,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Session:\",IDC_STATIC,7,29,28,8\n    LTEXT           \"Unknown\",IDC_SESSIONID,38,29,30,8\n    LTEXT           \"Elevated:\",IDC_STATIC,78,29,32,8\n    LTEXT           \"Unknown\",IDC_ELEVATED,113,29,45,8\n    LTEXT           \"Virtualized:\",IDC_STATIC,169,29,36,8\n    LTEXT           \"Unknown\",IDC_VIRTUALIZED,209,29,44,8\n    CONTROL         \"\",IDC_GROUPS,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,42,246,194\n    PUSHBUTTON      \"Integrity\",IDC_INTEGRITY,149,239,50,14\n    PUSHBUTTON      \"Advanced\",IDC_ADVANCED,203,239,50,14\n    PUSHBUTTON      \"Permissions\",IDC_PERMISSIONS,95,239,50,14\n    PUSHBUTTON      \"Default token\",IDC_DEFAULTPERM,41,239,50,14\nEND\n\nIDD_ZOMBIEPROCESSES DIALOGEX 0, 0, 337, 221\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Zombie Processes\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Processes highlighted red are hidden while those highlighted grey have terminated.\",IDC_INTRO,7,7,323,12\n    CONTROL         \"\",IDC_PROCESSES,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,23,323,162\n    RTEXT           \"\",IDC_DESCRIPTION,7,187,323,11\n    COMBOBOX        IDC_METHOD,7,201,73,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP\n    PUSHBUTTON      \"Terminate\",IDC_TERMINATE,115,200,50,14\n    PUSHBUTTON      \"Save...\",IDC_SAVE,170,200,50,14\n    PUSHBUTTON      \"&Scan\",IDC_SCAN,225,200,50,14\n    DEFPUSHBUTTON   \"Close\",IDOK,280,200,50,14\nEND\n\nIDD_RUNAS DIALOGEX 0, 0, 293, 127\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Run As\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Enter the command to start as the specified user.\",IDC_TITLE,7,7,160,8\n    LTEXT           \"Program:\",IDC_STATIC,7,23,30,8\n    LTEXT           \"User name:\",IDC_STATIC,7,40,38,8\n    COMBOBOX        IDC_USERNAME,53,38,123,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Type:\",IDC_STATIC,184,40,20,8\n    COMBOBOX        IDC_TYPE,208,38,78,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Password:\",IDC_STATIC,7,56,34,8\n    EDITTEXT        IDC_PASSWORD,53,55,123,12,ES_PASSWORD | ES_AUTOHSCROLL\n    CONTROL         \"Toggle elevation\",IDC_TOGGLEELEVATION,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,183,56,69,10\n    LTEXT           \"Session ID:\",IDC_STATIC,7,73,37,8\n    LTEXT           \"Desktop:\",IDC_STATIC,7,90,30,8\n    DEFPUSHBUTTON   \"OK\",IDOK,127,106,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,182,106,50,14\n    COMBOBOX        IDC_SESSIONCOMBO,53,72,123,12,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP\n    COMBOBOX        IDC_DESKTOPCOMBO,53,88,123,12,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP\n    PUSHBUTTON      \"Browse\",IDC_BROWSE,237,106,50,14\n    CONTROL         \"Create suspended\",IDC_TOGGLESUSPENDED,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,183,70,75,10\n    COMBOBOX        IDC_PROGRAMCOMBO,53,21,233,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP\n    CONTROL         \"Create UIAccess\",IDC_TOGGLEUIACCESS,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,183,84,69,10\nEND\n\nIDD_PROGRESS DIALOGEX 0, 0, 216, 62\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Progress\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Cancel\",IDCANCEL,159,41,50,14\n    CONTROL         \"\",IDC_PROGRESS,\"msctls_progress32\",0x0,7,23,202,14\n    LTEXT           \"Please wait...\",IDC_PROGRESSTEXT,7,7,202,12\nEND\n\nIDD_PAGEFILES DIALOGEX 0, 0, 322, 162\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Pagefiles\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,2,2,318,142\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,215,146,50,14\n    DEFPUSHBUTTON   \"Close\",IDOK,269,146,50,14\nEND\n\nIDD_TOKGENERAL DIALOGEX 0, 0, 270, 228\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"General\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    GROUPBOX        \"Token\",IDC_STATIC,7,7,256,149\n    LTEXT           \"User:\",IDC_STATIC,15,19,18,8\n    EDITTEXT        IDC_USER,71,17,185,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"User SID:\",IDC_STATIC,15,36,32,8\n    EDITTEXT        IDC_USERSID,71,34,185,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Owner:\",IDC_STATIC,15,53,25,8\n    EDITTEXT        IDC_OWNER,71,51,185,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Primary group:\",IDC_STATIC,15,70,49,8\n    EDITTEXT        IDC_PRIMARYGROUP,71,68,185,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Session ID:\",IDC_STATIC,15,87,37,8\n    EDITTEXT        IDC_SESSIONID,71,85,88,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Elevated:\",IDC_STATIC,15,104,32,8\n    EDITTEXT        IDC_ELEVATED,71,102,117,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Virtualization:\",IDC_STATIC,15,121,44,8\n    EDITTEXT        IDC_VIRTUALIZATION,71,119,185,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"UIAccess:\",IDC_STATIC,15,138,32,8\n    EDITTEXT        IDC_UIACCESS,71,136,185,12,ES_AUTOHSCROLL | ES_READONLY\n    PUSHBUTTON      \"Linked token\",IDC_LINKEDTOKEN,193,101,63,14\n    GROUPBOX        \"Source\",IDC_STATIC,7,160,256,47\n    LTEXT           \"Name:\",IDC_STATIC,15,172,22,8\n    EDITTEXT        IDC_SOURCENAME,71,170,185,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"LUID:\",IDC_STATIC,15,190,19,8\n    EDITTEXT        IDC_SOURCELUID,71,188,185,12,ES_AUTOHSCROLL | ES_READONLY\nEND\n\nIDD_TOKADVANCED DIALOGEX 0, 0, 236, 186\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Advanced\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_ALIGNLEFT | WS_TABSTOP,0,0,236,186\nEND\n\nIDD_OBJJOB DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Job\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Name:\",IDC_STATIC,7,9,22,8\n    EDITTEXT        IDC_NAME,35,8,164,12,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Terminate\",IDC_TERMINATE,203,7,50,14\n    LTEXT           \"Processes in job:\",IDC_STATIC,7,25,55,8\n    CONTROL         \"\",IDC_PROCESSES,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,38,246,62\n    PUSHBUTTON      \"Add...\",IDC_ADD,203,103,50,14\n    LTEXT           \"Limits:\",IDC_STATIC,7,117,21,8\n    CONTROL         \"\",IDC_LIMITS,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,129,246,107\n    PUSHBUTTON      \"Advanced\",IDC_ADVANCED,203,239,50,14\nEND\n\nIDD_OBJEVENT DIALOGEX 0, 0, 186, 76\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Event\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Type:\",IDC_STATIC,7,7,20,8\n    LTEXT           \"Unknown\",IDC_TYPE,42,7,137,8\n    LTEXT           \"Signaled:\",IDC_STATIC,7,18,30,8\n    LTEXT           \"Unknown\",IDC_SIGNALED,42,18,137,8\n    PUSHBUTTON      \"Set\",IDC_SET,7,34,50,14\n    PUSHBUTTON      \"Reset\",IDC_RESET,61,34,50,14\n    PUSHBUTTON      \"Pulse\",IDC_PULSE,115,34,50,14\nEND\n\nIDD_OBJMUTANT DIALOGEX 0, 0, 186, 76\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Mutant\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Count:\",IDC_STATIC,7,7,23,8\n    LTEXT           \"Unknown\",IDC_COUNT,55,7,124,8\n    LTEXT           \"Abandoned:\",IDC_STATIC,7,18,40,8\n    LTEXT           \"Unknown\",IDC_ABANDONED,55,18,124,8\n    LTEXT           \"Owner:\",IDC_OWNERLABEL,7,29,25,8\n    LTEXT           \"Unknown\",IDC_OWNER,55,29,124,8\nEND\n\nIDD_OBJSEMAPHORE DIALOGEX 0, 0, 186, 76\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Semaphore\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Current count:\",IDC_STATIC,7,7,50,8\n    LTEXT           \"Unknown\",IDC_CURRENTCOUNT,66,7,113,8\n    LTEXT           \"Maximum count:\",IDC_STATIC,7,18,54,8\n    LTEXT           \"Unknown\",IDC_MAXIMUMCOUNT,66,18,113,8\n    PUSHBUTTON      \"Acquire\",IDC_ACQUIRE,7,34,50,14\n    PUSHBUTTON      \"Release\",IDC_RELEASE,61,34,50,14\nEND\n\nIDD_OBJTIMER DIALOGEX 0, 0, 186, 76\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Timer\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Signaled:\",-1,7,7,30,8\n    LTEXT           \"Unknown\",IDC_SIGNALED,42,7,137,8\n    PUSHBUTTON      \"Cancel\",IDC_CANCEL,7,19,50,14\nEND\n\nIDD_JOBSTATISTICS DIALOGEX 0, 0, 259, 186\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Statistics\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    GROUPBOX        \"General\",IDC_STATIC,7,7,133,47\n    LTEXT           \"Active processes\",IDC_STATIC,15,18,55,8\n    RTEXT           \"Static\",IDC_ZACTIVEPROCESSES_V,99,18,37,8,SS_ENDELLIPSIS\n    LTEXT           \"Total processes\",IDC_STATIC,15,28,51,8\n    RTEXT           \"Static\",IDC_ZTOTALPROCESSES_V,95,29,41,8,SS_ENDELLIPSIS\n    LTEXT           \"Terminated due to job limits\",IDC_STATIC,15,39,98,8\n    RTEXT           \"Static\",IDC_ZTERMINATEDPROCESSES_V,107,39,29,8,SS_ENDELLIPSIS\n    GROUPBOX        \"Time\",IDC_STATIC,7,57,133,57\n    LTEXT           \"User time\",IDC_STATIC,15,68,32,8\n    LTEXT           \"Kernel time\",IDC_STATIC,15,79,38,8\n    LTEXT           \"User time (period)\",IDC_STATIC,15,89,60,8\n    LTEXT           \"Kernel time (period)\",IDC_STATIC,15,99,65,8\n    RTEXT           \"Static\",IDC_ZUSERTIME_V,83,68,53,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZKERNELTIME_V,85,79,51,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZUSERTIMEPERIOD_V,87,89,49,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZKERNELTIMEPERIOD_V,87,99,49,8,SS_ENDELLIPSIS\n    GROUPBOX        \"Memory\",IDC_STATIC,7,118,133,48\n    LTEXT           \"Page faults\",IDC_STATIC,15,129,38,8\n    LTEXT           \"Peak process usage\",IDC_STATIC,15,140,65,8\n    LTEXT           \"Peak job usage\",IDC_STATIC,15,151,52,8\n    RTEXT           \"Static\",IDC_ZPAGEFAULTS_V,86,129,50,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZPEAKPROCESSUSAGE_V,85,140,51,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZPEAKJOBUSAGE_V,86,151,50,8,SS_ENDELLIPSIS\n    GROUPBOX        \"I/O\",IDC_STATIC,146,7,106,75\n    LTEXT           \"Reads\",IDC_STATIC,152,17,21,8\n    LTEXT           \"Read bytes\",IDC_STATIC,152,27,38,8\n    LTEXT           \"Writes\",IDC_STATIC,152,37,22,8\n    LTEXT           \"Write bytes\",IDC_STATIC,152,47,38,8\n    LTEXT           \"Other\",IDC_STATIC,152,57,20,8\n    LTEXT           \"Other bytes\",IDC_STATIC,152,67,40,8\n    RTEXT           \"Static\",IDC_ZIOREADS_V,200,17,47,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZIOREADBYTES_V,200,27,47,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZIOWRITES_V,200,37,47,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZIOWRITEBYTES_V,200,47,47,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZIOOTHER_V,200,57,47,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZIOOTHERBYTES_V,200,67,47,8,SS_ENDELLIPSIS\nEND\n\nIDD_OBJEVENTPAIR DIALOGEX 0, 0, 186, 76\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Event Pair\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Set low\",IDC_SETLOW,7,7,50,14\n    PUSHBUTTON      \"Set high\",IDC_SETHIGH,61,7,50,14\nEND\n\nIDD_AFFINITY DIALOGEX 0, 0, 279, 227\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Affinity\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    DEFPUSHBUTTON   \"OK\",IDOK,169,206,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,222,206,50,14\n    LTEXT           \"Affinity controls which CPUs threads are allowed to execute on.\",IDC_STATIC,7,7,212,11\n    CONTROL         \"CPU 0\",IDC_CPU0,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,21,35,10\n    CONTROL         \"CPU 1\",IDC_CPU1,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,33,35,10\n    CONTROL         \"CPU 2\",IDC_CPU2,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,35,10\n    CONTROL         \"CPU 3\",IDC_CPU3,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,56,35,10\n    CONTROL         \"CPU 4\",IDC_CPU4,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,35,10\n    CONTROL         \"CPU 5\",IDC_CPU5,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,78,35,10\n    CONTROL         \"CPU 6\",IDC_CPU6,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,89,35,10\n    CONTROL         \"CPU 7\",IDC_CPU7,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,35,10\n    CONTROL         \"CPU 8\",IDC_CPU8,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,111,35,10\n    CONTROL         \"CPU 9\",IDC_CPU9,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,35,10\n    CONTROL         \"CPU 10\",IDC_CPU10,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,134,39,10\n    CONTROL         \"CPU 11\",IDC_CPU11,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,145,39,10\n    CONTROL         \"CPU 12\",IDC_CPU12,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,156,39,10\n    CONTROL         \"CPU 13\",IDC_CPU13,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,167,39,10\n    CONTROL         \"CPU 14\",IDC_CPU14,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,178,39,10\n    CONTROL         \"CPU 15\",IDC_CPU15,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,190,39,10\n    CONTROL         \"CPU 16\",IDC_CPU16,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,21,39,10\n    CONTROL         \"CPU 17\",IDC_CPU17,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,33,39,10\n    CONTROL         \"CPU 18\",IDC_CPU18,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,44,39,10\n    CONTROL         \"CPU 19\",IDC_CPU19,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,56,39,10\n    CONTROL         \"CPU 20\",IDC_CPU20,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,67,39,10\n    CONTROL         \"CPU 21\",IDC_CPU21,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,78,39,10\n    CONTROL         \"CPU 22\",IDC_CPU22,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,89,39,10\n    CONTROL         \"CPU 23\",IDC_CPU23,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,100,39,10\n    CONTROL         \"CPU 24\",IDC_CPU24,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,111,39,10\n    CONTROL         \"CPU 25\",IDC_CPU25,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,122,39,10\n    CONTROL         \"CPU 26\",IDC_CPU26,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,134,39,10\n    CONTROL         \"CPU 27\",IDC_CPU27,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,145,39,10\n    CONTROL         \"CPU 28\",IDC_CPU28,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,156,39,10\n    CONTROL         \"CPU 29\",IDC_CPU29,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,167,39,10\n    CONTROL         \"CPU 30\",IDC_CPU30,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,178,39,10\n    CONTROL         \"CPU 31\",IDC_CPU31,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,79,190,39,10\n    CONTROL         \"CPU 32\",IDC_CPU32,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,21,39,10\n    CONTROL         \"CPU 33\",IDC_CPU33,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,33,39,10\n    CONTROL         \"CPU 34\",IDC_CPU34,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,44,39,10\n    CONTROL         \"CPU 35\",IDC_CPU35,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,56,39,10\n    CONTROL         \"CPU 36\",IDC_CPU36,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,67,39,10\n    CONTROL         \"CPU 37\",IDC_CPU37,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,78,39,10\n    CONTROL         \"CPU 38\",IDC_CPU38,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,89,39,10\n    CONTROL         \"CPU 39\",IDC_CPU39,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,100,39,10\n    CONTROL         \"CPU 40\",IDC_CPU40,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,111,39,10\n    CONTROL         \"CPU 41\",IDC_CPU41,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,122,39,10\n    CONTROL         \"CPU 42\",IDC_CPU42,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,134,39,10\n    CONTROL         \"CPU 43\",IDC_CPU43,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,145,39,10\n    CONTROL         \"CPU 44\",IDC_CPU44,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,156,39,10\n    CONTROL         \"CPU 45\",IDC_CPU45,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,167,39,10\n    CONTROL         \"CPU 46\",IDC_CPU46,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,178,39,10\n    CONTROL         \"CPU 47\",IDC_CPU47,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,150,190,39,10\n    CONTROL         \"CPU 48\",IDC_CPU48,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,21,39,10\n    CONTROL         \"CPU 49\",IDC_CPU49,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,33,39,10\n    CONTROL         \"CPU 50\",IDC_CPU50,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,44,39,10\n    CONTROL         \"CPU 51\",IDC_CPU51,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,56,39,10\n    CONTROL         \"CPU 52\",IDC_CPU52,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,67,39,10\n    CONTROL         \"CPU 53\",IDC_CPU53,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,78,39,10\n    CONTROL         \"CPU 54\",IDC_CPU54,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,89,39,10\n    CONTROL         \"CPU 55\",IDC_CPU55,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,100,39,10\n    CONTROL         \"CPU 56\",IDC_CPU56,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,111,39,10\n    CONTROL         \"CPU 57\",IDC_CPU57,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,122,39,10\n    CONTROL         \"CPU 58\",IDC_CPU58,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,134,39,10\n    CONTROL         \"CPU 59\",IDC_CPU59,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,145,39,10\n    CONTROL         \"CPU 60\",IDC_CPU60,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,156,39,10\n    CONTROL         \"CPU 61\",IDC_CPU61,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,167,39,10\n    CONTROL         \"CPU 62\",IDC_CPU62,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,178,39,10\n    CONTROL         \"CPU 63\",IDC_CPU63,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,224,190,39,10\n    PUSHBUTTON      \"Select all\",IDC_SELECTALL,7,206,50,14\n    PUSHBUTTON      \"Deselect all\",IDC_DESELECTALL,60,206,50,14\n    COMBOBOX        IDC_GROUPCPU,220,4,52,30,CBS_DROPDOWNLIST | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP\nEND\n\nIDD_SYSINFO DIALOGEX 0, 0, 423, 247\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nEXSTYLE WS_EX_APPWINDOW\nCAPTION \"System Information\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\nEND\n\nIDD_EDITMESSAGE DIALOGEX 0, 0, 282, 163\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Message\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Title:\",IDC_STATIC,7,8,17,8\n    EDITTEXT        IDC_TITLE,52,7,223,12,ES_AUTOHSCROLL\n    LTEXT           \"Text:\",IDC_STATIC,7,24,18,8\n    EDITTEXT        IDC_TEXT,52,23,223,79,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL\n    LTEXT           \"Icon:\",IDC_STATIC,7,107,18,8\n    COMBOBOX        IDC_TYPE,52,105,80,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Timeout (s):\",IDC_STATIC,7,123,40,8\n    EDITTEXT        IDC_TIMEOUT,52,122,43,12,ES_AUTOHSCROLL\n    DEFPUSHBUTTON   \"OK\",IDOK,172,142,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,225,142,50,14\nEND\n\nIDD_SESSION DIALOGEX 0, 0, 317, 267\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Session Properties\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    DEFPUSHBUTTON   \"Close\",IDOK,265,251,50,14\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,2,313,247\nEND\n\nIDD_PROCMEMORY DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Memory\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,53,2,50,14\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE\n    PUSHBUTTON      \"Options\",IDC_FILTEROPTIONS,2,2,50,14\n    EDITTEXT        IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL\nEND\n\nIDD_CHOOSE DIALOGEX 0, 0, 199, 73\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Dialog\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Text:\",IDC_MESSAGE,7,7,185,8,SS_ENDELLIPSIS\n    COMBOBOX        IDC_CHOICE,7,20,185,30,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP\n    CONTROL         \"Option\",IDC_OPTION,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,39,185,10\n    DEFPUSHBUTTON   \"OK\",IDOK,89,52,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,142,52,50,14\n    COMBOBOX        IDC_CHOICEUSER,7,20,185,30,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP\n    EDITTEXT        IDC_CHOICESIMPLE,7,20,185,13,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE\nEND\n\nIDD_OPTGENERAL DIALOGEX 0, 0, 315, 220\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"General\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Search engine:\",IDC_STATIC,7,8,49,8\n    EDITTEXT        IDC_SEARCHENGINE,61,7,247,12,ES_AUTOHSCROLL\n    LTEXT           \"PE viewer:\",IDC_STATIC,7,23,35,8\n    EDITTEXT        IDC_PEVIEWER,61,22,247,12,ES_AUTOHSCROLL\n    LTEXT           \"Max. size unit:\",IDC_STATIC,7,55,49,8\n    COMBOBOX        IDC_MAXSIZEUNIT,61,54,39,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Icon processes:\",IDC_STATIC,7,72,52,8\n    EDITTEXT        IDC_ICONPROCESSES,61,70,40,12,ES_AUTOHSCROLL | ES_NUMBER\n    PUSHBUTTON      \"Font...\",IDC_FONT,179,70,49,14\n    PUSHBUTTON      \"Monospace...\",IDC_FONTMONOSPACE,230,70,70,14\n    PUSHBUTTON      \"Make default...\",IDC_REPLACETASKMANAGER,179,86,72,14\n    LTEXT           \"Graph history length:\",IDC_STATIC,106,56,69,8\n    EDITTEXT        IDC_SAMPLECOUNT,180,55,48,12,ES_AUTOHSCROLL | ES_NUMBER\n    CONTROL         \"Automatic\",IDC_SAMPLECOUNTAUTOMATIC,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,233,56,48,10\n    CONTROL         \"\",IDC_SETTINGS,\"SysListView32\",LVS_LIST | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_TABSTOP,7,103,301,110\n    LTEXT           \"Application font:\",IDC_STATIC,121,72,54,8\n    RTEXT           \"System Informer is the default Task Manager:\",IDC_DEFSTATE,7,88,166,8\n    LTEXT           \"Symbol path:\",IDC_STATIC,7,39,43,8\n    EDITTEXT        IDC_DBGHELPSEARCHPATH,61,38,247,12,ES_AUTOHSCROLL\nEND\n\nIDD_OPTHIGHLIGHTING DIALOGEX 0, 0, 250, 174\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Highlighting\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Highlighting duration:\",IDC_STATIC,7,8,70,8\n    EDITTEXT        IDC_HIGHLIGHTINGDURATION,79,7,40,12,ES_AUTOHSCROLL | ES_NUMBER\n    LTEXT           \"New objects:\",IDC_STATIC,7,25,44,8\n    CONTROL         \"New objects\",IDC_NEWOBJECTS,\"PhColorBox\",WS_CLIPSIBLINGS | WS_TABSTOP,57,23,33,13\n    LTEXT           \"Removed objects:\",IDC_STATIC,127,25,60,8\n    CONTROL         \"Removed objects\",IDC_REMOVEDOBJECTS,\"PhColorBox\",WS_CLIPSIBLINGS | WS_TABSTOP,193,23,33,13\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,41,236,107\n    LTEXT           \"Double-click an item to change it.\",IDC_INFO,7,156,106,8\n    PUSHBUTTON      \"Enable all\",IDC_ENABLEALL,140,153,50,14\n    PUSHBUTTON      \"Disable all\",IDC_DISABLEALL,193,153,50,14\nEND\n\nIDD_CHOOSECOLUMNS DIALOGEX 0, 0, 381, 226\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Choose Columns\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Inactive columns:\",IDC_STATIC,7,21,57,8\n    LISTBOX         IDC_INACTIVE,7,49,129,153,LBS_SORT | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP\n    PUSHBUTTON      \"Show >\",IDC_SHOW,139,105,50,14\n    PUSHBUTTON      \"< Hide\",IDC_HIDE,139,121,50,14\n    LISTBOX         IDC_ACTIVE,192,49,129,153,LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP\n    PUSHBUTTON      \"Move up\",IDC_MOVEUP,326,49,50,14\n    PUSHBUTTON      \"Move down\",IDC_MOVEDOWN,326,66,50,14\n    PUSHBUTTON      \"OK\",IDOK,272,206,50,14\n    DEFPUSHBUTTON   \"Cancel\",IDCANCEL,326,206,50,14\n    LTEXT           \"Active columns:\",IDC_STATIC,192,21,51,8\n    LTEXT           \"Select the columns that will appear in the list.\",IDC_MESSAGE,7,7,369,10\n    EDITTEXT        IDC_SEARCH,7,33,129,14,ES_AUTOHSCROLL\n    EDITTEXT        IDC_FILTER,192,33,129,14,ES_AUTOHSCROLL\nEND\n\nIDD_NETSTACK DIALOGEX 0, 0, 261, 228\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Network Stack\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,247,196\n    PUSHBUTTON      \"Close\",IDOK,204,207,50,14\nEND\n\nIDD_CREATESERVICE DIALOGEX 0, 0, 287, 133\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Create Service\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Name:\",IDC_STATIC,7,8,22,8\n    EDITTEXT        IDC_NAME,61,7,219,12,ES_AUTOHSCROLL\n    LTEXT           \"Display name:\",IDC_STATIC,7,24,46,8\n    EDITTEXT        IDC_DISPLAYNAME,61,23,219,12,ES_AUTOHSCROLL\n    LTEXT           \"Type:\",IDC_STATIC,7,41,20,8\n    COMBOBOX        IDC_TYPE,61,39,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Start type:\",IDC_STATIC,7,58,38,8\n    COMBOBOX        IDC_STARTTYPE,61,56,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Error control:\",IDC_STATIC,7,75,45,8\n    COMBOBOX        IDC_ERRORCONTROL,61,73,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Binary path:\",IDC_STATIC,7,91,40,8\n    EDITTEXT        IDC_BINARYPATH,61,90,165,12,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Browse...\",IDC_BROWSE,230,89,50,14\n    DEFPUSHBUTTON   \"OK\",IDOK,176,112,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,230,112,50,14\nEND\n\nIDD_PROCPERFORMANCE DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Performance\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    GROUPBOX        \"CPU\",IDC_GROUPCPU,7,7,246,74,0,WS_EX_TRANSPARENT\n    GROUPBOX        \"Private bytes\",IDC_GROUPPRIVATEBYTES,7,86,246,77,0,WS_EX_TRANSPARENT\n    GROUPBOX        \"I/O\",IDC_GROUPIO,7,164,246,89,0,WS_EX_TRANSPARENT\n    CONTROL         \"\",IDC_CPU,\"PhGraph\",WS_CLIPSIBLINGS,105,42,50,14\n    CONTROL         \"\",IDC_PRIVATEBYTES,\"PhGraph\",WS_CLIPSIBLINGS,105,122,50,14\n    CONTROL         \"\",IDC_IO,\"PhGraph\",WS_CLIPSIBLINGS,105,204,50,14\nEND\n\nIDD_PROCSTATISTICS DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Statistics\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_STATISTICS_LIST,\"SysListView32\",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,3,255,255\nEND\n\nIDD_OPTADVANCED DIALOGEX 0, 0, 317, 225\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Advanced\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    EDITTEXT        IDC_SEARCH,171,3,144,14,ES_AUTOHSCROLL\n    PUSHBUTTON      \"Options\",IDC_FILTEROPTIONS,2,3,50,14\n    CONTROL         \"\",IDC_SETTINGS,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,313,204,WS_EX_CLIENTEDGE\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,53,3,50,14\nEND\n\nIDD_GDIHANDLES DIALOGEX 0, 0, 351, 307\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"GDI Handles\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,337,275\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,240,286,50,14\n    DEFPUSHBUTTON   \"Close\",IDOK,294,286,50,14\nEND\n\nIDD_LOG DIALOGEX 0, 0, 313, 303\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nEXSTYLE WS_EX_APPWINDOW\nCAPTION \"Log\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,299,272\n    PUSHBUTTON      \"Clear\",IDC_CLEAR,7,282,50,14\n    CONTROL         \"Auto-scroll\",IDC_AUTOSCROLL,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,61,284,50,10\n    PUSHBUTTON      \"Save...\",IDC_SAVE,148,282,50,14\n    PUSHBUTTON      \"Copy\",IDC_COPY,202,282,50,14\n    DEFPUSHBUTTON   \"Close\",IDOK,256,282,50,14\nEND\n\nIDD_MEMEDIT DIALOGEX 0, 0, 441, 269\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nEXSTYLE WS_EX_APPWINDOW\nCAPTION \"Memory\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_MEMORY,\"PhHexEdit\",WS_CLIPSIBLINGS | WS_VSCROLL | WS_TABSTOP,7,7,427,239\n    PUSHBUTTON      \"Re-read\",IDC_REREAD,7,248,50,14\n    PUSHBUTTON      \"Write\",IDC_WRITE,60,248,50,14\n    PUSHBUTTON      \"Go to...\",IDC_GOTO,112,248,50,14\n    PUSHBUTTON      \"Save...\",IDC_SAVE,331,248,50,14\n    PUSHBUTTON      \"Close\",IDOK,384,248,50,14\n    COMBOBOX        IDC_BYTESPERROW,164,249,86,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\nEND\n\nIDD_MEMPROTECT DIALOGEX 0, 0, 270, 171\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Memory Protection\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    EDITTEXT        IDC_INTRO,7,7,256,122,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"New value:\",IDC_STATIC,120,136,37,8\n    EDITTEXT        IDC_VALUE,161,135,102,12,ES_AUTOHSCROLL\n    DEFPUSHBUTTON   \"OK\",IDOK,161,150,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,213,150,50,14\nEND\n\nIDD_MEMSTRINGS DIALOGEX 0, 0, 443, 254\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Strings\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Options\",IDC_SETTINGS,2,3,50,14\n    PUSHBUTTON      \"Filter\",IDC_FILTER,53,3,50,14\n    EDITTEXT        IDC_SEARCH,105,3,336,14,ES_AUTOHSCROLL\n    CONTROL         \"\",IDC_TREELIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,439,219,WS_EX_CLIENTEDGE\n    LTEXT           \"\",IDC_MESSAGE,8,242,427,10\nEND\n\nIDD_MEMSTRINGSMINLEN DIALOGEX 0, 0, 123, 46\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"String Search\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Minimum length:\",IDC_STATIC,7,8,54,8\n    EDITTEXT        IDC_MINIMUMLENGTH,67,7,51,12,ES_AUTOHSCROLL\n    DEFPUSHBUTTON   \"OK\",IDOK,13,25,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,67,25,50,14\nEND\n\nIDD_MEMRESULTS DIALOGEX 0, 0, 313, 266\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Results\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Results.\",IDC_INTRO,7,9,299,8\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,21,299,221\n    PUSHBUTTON      \"Filter\",IDC_FILTER,7,245,50,14\n    PUSHBUTTON      \"Save...\",IDC_SAVE,149,245,50,14\n    PUSHBUTTON      \"Copy\",IDC_COPY,203,245,50,14\n    DEFPUSHBUTTON   \"Close\",IDOK,256,245,50,14\nEND\n\nIDD_MEMSTRING DIALOGEX 0, 0, 241, 86\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"String Search\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Minimum length:\",IDC_STATIC,7,8,54,8\n    EDITTEXT        IDC_MINIMUMLENGTH,67,7,51,12,ES_AUTOHSCROLL\n    CONTROL         \"Detect Unicode\",IDC_DETECTUNICODE,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,22,65,10\n    LTEXT           \"Search in the following types of memory regions:\",IDC_STATIC,7,36,157,8\n    CONTROL         \"Private\",IDC_PRIVATE,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,49,39,10\n    CONTROL         \"Image\",IDC_IMAGE,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,55,49,36,10\n    CONTROL         \"Mapped\",IDC_MAPPED,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,101,49,41,10\n    DEFPUSHBUTTON   \"OK\",IDOK,131,65,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,184,65,50,14\n    CONTROL         \"Extended Unicode\",IDC_EXTENDEDUNICODE,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,80,22,74,10\nEND\n\nIDD_OPTGRAPHS DIALOGEX 0, 0, 250, 156\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Graphs\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"Show text\",IDC_SHOWTEXT,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,49,10\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_DISABLED | WS_TABSTOP,7,44,236,105\n    CONTROL         \"Use old colors (black background)\",IDC_USEOLDCOLORS,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,123,10\n    CONTROL         \"Show commit charge instead of physical memory in summary view\",IDC_SHOWCOMMITINSUMMARY,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,31,227,10\nEND\n\nIDD_PLUGINMANAGER DIALOGEX 0, 0, 501, 272\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Plugins\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Changes may require a restart to take effect.\",IDC_INSTRUCTION,2,262,148,8\n    CONTROL         \"\",IDC_PLUGINTREE,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,2,497,253,WS_EX_CLIENTEDGE\n    PUSHBUTTON      \"Disabled plugins (0)\",IDC_DISABLED,427,256,72,14\nEND\n\nIDD_HANDLESTATS DIALOGEX 0, 0, 219, 175\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Handle Statistics\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,205,143\n    DEFPUSHBUTTON   \"Close\",IDOK,162,154,50,14\nEND\n\nIDD_PROCRECORD DIALOGEX 0, 0, 260, 202\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Process Record\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Name:\",IDC_STATIC,7,9,22,8\n    EDITTEXT        IDC_PROCESSNAME,39,9,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Parent:\",IDC_STATIC,7,21,25,8\n    EDITTEXT        IDC_PARENT,39,21,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    GROUPBOX        \"File\",IDC_FILE,7,38,246,79\n    ICON            \"\",IDC_FILEICON,14,49,20,20\n    EDITTEXT        IDC_NAME,44,48,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    EDITTEXT        IDC_COMPANYNAME,44,60,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Version:\",IDC_STATIC,15,72,27,8\n    EDITTEXT        IDC_VERSION,44,72,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Image file name:\",IDC_STATIC,15,86,56,8\n    EDITTEXT        IDC_FILENAME,15,96,211,12,ES_AUTOHSCROLL | ES_READONLY\n    PUSHBUTTON      \"Open\",IDC_OPENFILENAME,230,95,17,15,BS_ICON\n    LTEXT           \"Command line:\",IDC_STATIC,7,123,50,8\n    EDITTEXT        IDC_CMDLINE,65,121,188,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Started:\",IDC_STATIC,7,139,28,8\n    EDITTEXT        IDC_STARTED,65,137,188,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Terminated:\",IDC_STATIC,7,155,40,8\n    EDITTEXT        IDC_TERMINATED,65,153,188,12,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Session ID:\",IDC_STATIC,7,170,37,8\n    LTEXT           \"Static\",IDC_SESSIONID,50,170,19,8\n    PUSHBUTTON      \"Properties\",IDC_PROPERTIES,150,181,50,14\n    DEFPUSHBUTTON   \"Close\",IDOK,203,181,50,14\nEND\n\nIDD_CHOOSEPROCESS DIALOGEX 0, 0, 317, 239\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Select a Process\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Select a process from the list below.\",IDC_MESSAGE,7,7,303,8,SS_ENDELLIPSIS\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,21,303,193\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,7,218,50,14\n    DEFPUSHBUTTON   \"OK\",IDOK,205,218,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,260,218,50,14\nEND\n\nIDD_PROCSERVICES DIALOGEX 0, 0, 260, 261\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Services\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Services\",IDC_SERVICES_LAYOUT,7,7,246,247,NOT WS_VISIBLE | WS_BORDER\nEND\n\nIDD_SHADOWSESSION DIALOGEX 0, 0, 228, 84\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Remote Control\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"To end the remote control session, press this key and the modifiers selected below:\",IDC_STATIC,7,7,214,19\n    COMBOBOX        IDC_VIRTUALKEY,7,27,74,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\n    CONTROL         \"Shift\",IDC_SHIFT,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,47,31,10\n    CONTROL         \"Ctrl\",IDC_CTRL,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,49,47,27,10\n    CONTROL         \"Alt\",IDC_ALT,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,89,47,25,10\n    DEFPUSHBUTTON   \"OK\",IDOK,117,63,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,171,63,50,14\nEND\n\nIDD_TOKCAPABILITIES DIALOGEX 0, 0, 270, 228\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Capabilities\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228\nEND\n\nIDD_TOKATTRIBUTES DIALOGEX 0, 0, 270, 228\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Attributes\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228\nEND\n\nIDD_TOKAPPPOLICY DIALOGEX 0, 0, 270, 228\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Policy\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,0,0,270,228\nEND\n\nIDD_SYSINFO_CPU DIALOGEX 0, 0, 316, 195\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU\nEXSTYLE WS_EX_CONTROLPARENT\nCAPTION \"CPU\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    RTEXT           \"CPU name\",IDC_CPUNAME,41,4,274,16,SS_WORDELLIPSIS\n    LTEXT           \"CPU\",IDC_TITLE,0,0,37,21\n    LTEXT           \"Panel layout\",IDC_LAYOUT,0,105,315,88,NOT WS_VISIBLE\n    LTEXT           \"Graph layout\",IDC_GRAPH_LAYOUT,0,22,315,82,NOT WS_VISIBLE\nEND\n\nIDD_SYSINFO_CPUPANEL DIALOGEX 0, 0, 506, 86\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\nEXSTYLE WS_EX_CONTROLPARENT\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Utilization:\",IDC_STATIC,6,3,34,8\n    LTEXT           \"Speed:\",IDC_STATIC,108,3,24,8\n    LTEXT           \"Virtualization:\",IDC_STATIC,247,3,60,8\n    LTEXT           \"Static\",IDC_UTILIZATION,46,0,60,15\n    LTEXT           \"Static\",IDC_SPEED,137,0,100,15\n    LTEXT           \"Static\",IDC_VIRTUALIZATION,296,0,500,15\n    GROUPBOX        \"System\",IDC_STATIC,0,17,97,55\n    LTEXT           \"Processes\",IDC_STATIC,7,28,33,8\n    LTEXT           \"Threads\",IDC_STATIC,7,38,27,8\n    LTEXT           \"Handles\",IDC_STATIC,7,48,26,8\n    LTEXT           \"Uptime\",IDC_STATIC,7,58,23,8\n    RTEXT           \"Static\",IDC_ZPROCESSES_V,45,28,46,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZTHREADS_V,45,38,46,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZHANDLES_V,45,48,46,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZUPTIME_V,46,58,45,8,SS_ENDELLIPSIS\n    CONTROL         \"&Show one graph per CPU\",IDC_ONEGRAPHPERCPU,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,0,76,96,10\n    GROUPBOX        \"CPU\",IDC_STATIC,101,17,136,55\n    LTEXT           \"Context switches delta\",IDC_STATIC,109,28,76,8\n    LTEXT           \"Interrupts delta\",IDC_STATIC,109,38,52,8\n    LTEXT           \"DPCs delta\",IDC_STATIC,109,48,36,8\n    LTEXT           \"System calls delta\",IDC_STATIC,109,58,60,8\n    RTEXT           \"Static\",IDC_ZCONTEXTSWITCHESDELTA_V,191,28,40,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZINTERRUPTSDELTA_V,185,39,46,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZDPCSDELTA_V,181,48,50,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZSYSTEMCALLSDELTA_V,179,58,52,8,SS_ENDELLIPSIS\n    GROUPBOX        \"Topology\",IDC_STATIC,241,17,109,55\n    LTEXT           \"Cores\",IDC_STATIC,249,28,76,8\n    LTEXT           \"Sockets\",IDC_STATIC,249,38,26,8\n    LTEXT           \"Logical processors\",IDC_STATIC,249,48,58,8\n    LTEXT           \"Latency\",IDC_STATIC,249,58,60,8\n    RTEXT           \"Static\",IDC_ZCORES,305,28,40,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZSOCKETS,299,38,46,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLOGICAL,314,48,31,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLATENCY,293,58,52,8,SS_ENDELLIPSIS\n    GROUPBOX        \"Hardware\",IDC_STATIC,354,17,97,55\n    LTEXT           \"L1 cache\",IDC_STATIC,362,28,52,8\n    RTEXT           \"Static\",IDC_ZL1CACHE_V,394,28,52,8,SS_ENDELLIPSIS\n    LTEXT           \"L2 cache\",IDC_STATIC,362,38,53,8\n    RTEXT           \"Static\",IDC_ZL2CACHE_V,394,38,52,8,SS_ENDELLIPSIS\n    LTEXT           \"L3 cache\",IDC_STATIC,362,48,53,8\n    RTEXT           \"Static\",IDC_ZL3CACHE_V,394,48,52,8,SS_ENDELLIPSIS\nEND\n\nIDD_SYSINFO_MEMPANEL DIALOGEX 0, 0, 488, 171\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\nEXSTYLE WS_EX_CONTROLPARENT\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    GROUPBOX        \"Commit charge\",IDC_STATIC,0,0,108,44\n    LTEXT           \"Current\",IDC_STATIC,7,11,26,8\n    LTEXT           \"Peak\",IDC_STATIC,7,21,16,8\n    LTEXT           \"Limit\",IDC_STATIC,7,31,15,8\n    RTEXT           \"Static\",IDC_ZCOMMITCURRENT_V,45,11,56,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZCOMMITPEAK_V,41,21,60,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZCOMMITLIMIT_V,40,31,61,8,SS_ENDELLIPSIS\n    GROUPBOX        \"Physical memory\",IDC_STATIC,112,0,118,73\n    LTEXT           \"Current\",IDC_STATIC,120,11,26,8\n    LTEXT           \"Cache WS\",IDC_STATIC,120,41,34,8\n    RTEXT           \"Static\",IDC_ZPHYSICALCURRENT_V,151,11,71,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZPHYSICALTOTAL_V,145,21,77,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZPHYSICALCACHEWS_V,159,41,63,8,SS_ENDELLIPSIS\n    LTEXT           \"Total\",IDC_STATIC,120,21,17,8\n    LTEXT           \"Kernel WS\",IDC_STATIC,120,51,34,8\n    RTEXT           \"Static\",IDC_ZPHYSICALKERNELWS_V,159,51,63,8,SS_ENDELLIPSIS\n    LTEXT           \"Driver WS\",IDC_STATIC,120,61,33,8\n    RTEXT           \"Static\",IDC_ZPHYSICALDRIVERWS_V,159,61,63,8,SS_ENDELLIPSIS\n    GROUPBOX        \"Paged pool\",IDC_STATIC,0,47,108,64\n    LTEXT           \"Working set\",IDC_STATIC,7,58,40,8\n    LTEXT           \"Limit\",IDC_STATIC,7,78,15,8\n    RTEXT           \"Static\",IDC_ZPAGEDWORKINGSET_V,54,58,47,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZPAGEDVIRTUALSIZE_V,52,68,49,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZPAGEDLIMIT_V,36,78,65,8,SS_ENDELLIPSIS\n    LTEXT           \"Virtual size\",IDC_STATIC,7,68,36,8\n    LTEXT           \"Allocs delta\",IDC_STATIC,7,88,38,8\n    RTEXT           \"Static\",IDC_ZPAGEDALLOCSDELTA_V,53,88,48,8,SS_ENDELLIPSIS\n    LTEXT           \"Frees delta\",IDC_STATIC,7,98,38,8\n    RTEXT           \"Static\",IDC_ZPAGEDFREESDELTA_V,51,98,50,8,SS_ENDELLIPSIS\n    GROUPBOX        \"Non-paged pool\",IDC_STATIC,0,114,108,55\n    LTEXT           \"Usage\",IDC_STATIC,7,125,21,8\n    LTEXT           \"Allocs delta\",IDC_STATIC,7,145,38,8\n    RTEXT           \"Static\",IDC_ZNONPAGEDUSAGE_V,36,125,65,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZNONPAGEDLIMIT_V,29,135,72,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZNONPAGEDALLOCSDELTA_V,50,145,51,8,SS_ENDELLIPSIS\n    LTEXT           \"Limit\",IDC_STATIC,7,135,15,8\n    LTEXT           \"Frees delta\",IDC_STATIC,7,155,38,8\n    RTEXT           \"Static\",IDC_ZNONPAGEDFREESDELTA_V,48,155,53,8,SS_ENDELLIPSIS\n    GROUPBOX        \"Memory lists\",IDC_STATIC,234,0,123,169\n    LTEXT           \"Zeroed\",IDC_STATIC,242,11,24,8\n    LTEXT           \"Modified\",IDC_STATIC,242,31,28,8\n    RTEXT           \"Static\",IDC_ZLISTZEROED_V,304,11,47,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTFREE_V,302,21,49,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTMODIFIED_V,298,31,53,8,SS_ENDELLIPSIS\n    LTEXT           \"Free\",IDC_STATIC,242,21,16,8\n    LTEXT           \"Modified no-write\",IDC_STATIC,242,41,60,8\n    RTEXT           \"Static\",IDC_ZLISTMODIFIEDNOWRITE_V,303,41,48,8,SS_ENDELLIPSIS\n    LTEXT           \"Standby\",IDC_STATIC,242,61,28,8\n    LTEXT           \"Priority 0\",IDC_STATIC,251,71,30,8\n    LTEXT           \"Priority 1\",IDC_STATIC,251,80,30,8\n    LTEXT           \"Priority 2\",IDC_STATIC,251,90,30,8\n    LTEXT           \"Priority 3\",IDC_STATIC,251,100,30,8\n    LTEXT           \"Priority 4\",IDC_STATIC,251,110,30,8\n    LTEXT           \"Priority 5\",IDC_STATIC,251,120,30,8\n    LTEXT           \"Priority 6\",IDC_STATIC,251,130,30,8\n    LTEXT           \"Priority 7\",IDC_STATIC,251,140,30,8\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY_V,303,61,48,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY0_V,303,71,48,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY1_V,303,80,48,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY2_V,303,90,48,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY3_V,303,100,48,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY4_V,303,110,48,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY5_V,303,120,48,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY6_V,303,130,48,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY7_V,303,140,48,8,SS_ENDELLIPSIS\n    GROUPBOX        \"Paging\",IDC_STATIC,112,75,118,55\n    LTEXT           \"Page faults delta\",IDC_STATIC,120,86,57,8\n    LTEXT           \"Pagefile writes delta\",IDC_STATIC,120,106,68,8\n    RTEXT           \"Static\",IDC_ZPAGINGPAGEFAULTSDELTA_V,183,86,39,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZPAGINGPAGEREADSDELTA_V,179,96,43,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZPAGINGPAGEFILEWRITESDELTA_V,189,106,33,8,SS_ENDELLIPSIS\n    LTEXT           \"Page reads delta\",IDC_STATIC,120,96,58,8\n    LTEXT           \"Mapped writes delta\",IDC_STATIC,120,116,68,8\n    RTEXT           \"Static\",IDC_ZPAGINGMAPPEDWRITESDELTA_V,191,116,31,8,SS_ENDELLIPSIS\n    LTEXT           \"Modified pagefile\",IDC_STATIC,242,51,60,8\n    RTEXT           \"Static\",IDC_ZLISTMODIFIEDPAGEFILE_V,303,51,48,8,SS_ENDELLIPSIS\n    PUSHBUTTON      \"&More\",IDC_MORE,242,152,50,14\n    RTEXT           \"Static\",IDC_ZPHYSICALRESERVED_V,157,31,65,8,SS_ENDELLIPSIS\n    LTEXT           \"Reserved\",IDC_STATIC,120,31,32,8\n    GROUPBOX        \"Mapped IO\",IDC_STATIC,112,132,118,36\n    LTEXT           \"Mapped reads\",IDC_STATIC,119,145,68,8\n    RTEXT           \"Static\",IDC_ZMAPPEDREADIO,180,145,42,8,SS_ENDELLIPSIS\n    LTEXT           \"Mapped writes\",IDC_STATIC,119,156,68,8\n    RTEXT           \"Static\",IDC_ZMAPPEDWRITEIO,180,156,42,8,SS_ENDELLIPSIS\n    PUSHBUTTON      \"&Empty\",IDC_EMPTY,299,152,50,14\n    GROUPBOX        \"Hardware\",IDC_STATIC,361,0,114,63\n    LTEXT           \"Slots used\",IDC_STATIC,369,11,40,8\n    RTEXT           \"Static\",IDC_ZMEMSLOTS_V,415,11,54,8,SS_ENDELLIPSIS\n    LTEXT           \"Form factor\",IDC_STATIC,369,21,48,8\n    RTEXT           \"Static\",IDC_ZMEMFORMFACTOR_V,419,21,50,8,SS_ENDELLIPSIS\n    LTEXT           \"Technology\",IDC_STATIC,369,31,48,8\n    RTEXT           \"Static\",IDC_ZMEMTECHNOLOGY_V,419,31,50,8,SS_ENDELLIPSIS\n    LTEXT           \"Memory type\",IDC_STATIC,369,41,48,8\n    RTEXT           \"Static\",IDC_ZMEMTYPE_V,419,41,50,8,SS_ENDELLIPSIS\n    LTEXT           \"Speed\",IDC_STATIC,369,51,26,8\n    RTEXT           \"Static\",IDC_ZMEMSPEED_V,397,51,72,8,SS_ENDELLIPSIS\nEND\n\nIDD_SYSINFO_MEM DIALOGEX 0, 0, 316, 250\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU\nEXSTYLE WS_EX_CONTROLPARENT\nCAPTION \"Memory\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Memory\",IDC_TITLE,0,0,110,21\n    LTEXT           \"Panel layout\",IDC_LAYOUT,0,74,315,175,NOT WS_VISIBLE\n    LTEXT           \"Graph layout\",IDC_GRAPH_LAYOUT,0,22,315,51,NOT WS_VISIBLE\n    RTEXT           \"Total physical\",IDC_TOTALPHYSICAL,127,4,188,16,SS_WORDELLIPSIS\n    LTEXT           \"Commit charge:\",IDC_COMMIT_L,111,1,52,8\n    LTEXT           \"Physical memory:\",IDC_PHYSICAL_L,111,7,56,8\nEND\n\nIDD_SYSINFO_IO DIALOGEX 0, 0, 316, 187\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU\nCAPTION \"I/O\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"I/O\",IDC_TITLE,0,0,110,21\n    LTEXT           \"Panel layout\",IDC_LAYOUT,0,109,315,78,NOT WS_VISIBLE\n    LTEXT           \"Graph layout\",IDC_GRAPH_LAYOUT,0,22,315,84,NOT WS_VISIBLE\n    LTEXT           \"Read bytes:\",IDC_IOREAD_L,111,1,52,8\n    LTEXT           \"Write bytes:\",IDC_IOWRITE_L,111,7,56,8\n    LTEXT           \"Other bytes:\",IDC_IOOTHER_L,111,14,60,8\nEND\n\nIDD_SYSINFO_IOPANEL DIALOGEX 0, 0, 276, 75\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    GROUPBOX        \"I/O deltas\",IDC_STATIC,0,0,133,74\n    LTEXT           \"Reads delta\",IDC_STATIC,7,11,40,8\n    LTEXT           \"Read bytes delta\",IDC_STATIC,7,21,56,8\n    LTEXT           \"Writes delta\",IDC_STATIC,7,31,40,8\n    LTEXT           \"Write bytes delta\",IDC_STATIC,7,41,57,8\n    RTEXT           \"Static\",IDC_ZREADSDELTA_V,59,11,67,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZREADBYTESDELTA_V,75,21,51,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZWRITESDELTA_V,57,31,69,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZWRITEBYTESDELTA_V,73,41,53,8,SS_ENDELLIPSIS\n    LTEXT           \"Other delta\",IDC_STATIC,7,51,38,8\n    LTEXT           \"Other bytes delta\",IDC_STATIC,7,61,58,8\n    RTEXT           \"Static\",IDC_ZOTHERDELTA_V,67,51,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZOTHERBYTESDELTA_V,81,61,45,8,SS_ENDELLIPSIS\n    GROUPBOX        \"I/O totals\",IDC_STATIC,137,0,133,74\n    LTEXT           \"Reads\",IDC_STATIC,145,11,21,8\n    LTEXT           \"Read bytes\",IDC_STATIC,145,21,38,8\n    LTEXT           \"Writes\",IDC_STATIC,145,31,22,8\n    LTEXT           \"Write bytes\",IDC_STATIC,145,41,38,8\n    RTEXT           \"Static\",IDC_ZREADS_V,197,11,67,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZREADBYTES_V,192,21,72,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZWRITES_V,195,31,69,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZWRITEBYTES_V,190,41,74,8,SS_ENDELLIPSIS\n    LTEXT           \"Other\",IDC_STATIC,145,51,20,8\n    LTEXT           \"Other bytes\",IDC_STATIC,145,61,40,8\n    RTEXT           \"Static\",IDC_ZOTHER_V,191,51,73,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZOTHERBYTES_V,192,61,72,8,SS_ENDELLIPSIS\nEND\n\nIDD_MEMLISTS DIALOGEX 0, 0, 228, 195\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU\nEXSTYLE WS_EX_TOPMOST\nCAPTION \"Memory Lists\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    DEFPUSHBUTTON   \"Close\",IDOK,171,174,50,14\n    LTEXT           \"Zeroed\",IDC_STATIC,7,7,24,8\n    LTEXT           \"Free\",IDC_STATIC,7,17,16,8\n    LTEXT           \"Modified\",IDC_STATIC,7,28,28,8\n    LTEXT           \"Modified no-write\",IDC_STATIC,7,39,56,8\n    LTEXT           \"Bad\",IDC_STATIC,7,60,13,8\n    LTEXT           \"Standby\",IDC_STATIC,7,72,28,8\n    LTEXT           \"Priority 0\",IDC_STATIC,23,83,30,8\n    LTEXT           \"Priority 1\",IDC_STATIC,23,94,30,8\n    LTEXT           \"Priority 2\",IDC_STATIC,23,105,30,8\n    LTEXT           \"Priority 3\",IDC_STATIC,23,116,30,8\n    LTEXT           \"Priority 4\",IDC_STATIC,23,128,30,8\n    LTEXT           \"Priority 5\",IDC_STATIC,23,139,30,8\n    LTEXT           \"Priority 6\",IDC_STATIC,23,150,30,8\n    LTEXT           \"Priority 7\",IDC_STATIC,23,161,30,8\n    RTEXT           \"Static\",IDC_ZLISTZEROED_V,73,7,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTFREE_V,73,17,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTMODIFIED_V,73,28,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTMODIFIEDNOWRITE_V,73,39,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTBAD_V,73,60,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY_V,73,72,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY0_V,73,83,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY1_V,73,94,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY2_V,73,105,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY3_V,73,116,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY4_V,73,128,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY5_V,73,139,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY6_V,73,150,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTSTANDBY7_V,73,161,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTREPURPOSED_V,162,72,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTREPURPOSED0_V,162,84,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTREPURPOSED1_V,162,95,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTREPURPOSED2_V,162,106,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTREPURPOSED3_V,162,117,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTREPURPOSED4_V,162,128,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTREPURPOSED5_V,162,139,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTREPURPOSED6_V,162,150,59,8,SS_ENDELLIPSIS\n    RTEXT           \"Static\",IDC_ZLISTREPURPOSED7_V,162,161,59,8,SS_ENDELLIPSIS\n    RTEXT           \"(Repurposed)\",IDC_STATIC,162,60,59,8\n    PUSHBUTTON      \"&Empty\",IDC_EMPTY,117,174,50,14\n    LTEXT           \"Modified pagefile\",IDC_STATIC,7,49,55,8\n    RTEXT           \"Static\",IDC_ZLISTMODIFIEDPAGEFILE_V,73,49,59,8,SS_ENDELLIPSIS\nEND\n\nIDD_CONTAINER DIALOGEX 0, 0, 316, 182\nSTYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU\nEXSTYLE WS_EX_CONTROLPARENT\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\nEND\n\nIDD_MINIINFO DIALOGEX 0, 0, 217, 150\nSTYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Content layout\",IDC_LAYOUT,4,3,210,128,NOT WS_VISIBLE\n    CONTROL         \"Section\",IDC_SECTION,\"Static\",SS_LEFTNOWORDWRAP | SS_NOTIFY | SS_ENDELLIPSIS | WS_GROUP,4,134,177,13\n    PUSHBUTTON      \"Options\",IDC_OPTIONS,183,133,15,14,BS_ICON\n    CONTROL         \"Pin\",IDC_PINWINDOW,\"Button\",BS_AUTOCHECKBOX | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,199,133,15,14\nEND\n\nIDD_MINIINFO_LIST DIALOGEX 0, 0, 217, 141\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"CPU\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x82,0,0,217,140,WS_EX_CLIENTEDGE\nEND\n\nIDD_MITIGATION DIALOGEX 0, 0, 277, 217\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Mitigation Policies\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,7,263,108\n    LTEXT           \"Description:\",IDC_DESCRIPTIONLABEL,7,118,38,8\n    EDITTEXT        IDC_DESCRIPTION,7,129,263,62,ES_MULTILINE | ES_READONLY | WS_VSCROLL\n    DEFPUSHBUTTON   \"OK\",IDOK,220,196,50,14\nEND\n\nIDD_EDITENV DIALOGEX 0, 0, 311, 177\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Edit Environment Variable\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Name:\",IDC_STATIC,7,8,21,8\n    EDITTEXT        IDC_NAME,38,7,266,12,ES_AUTOHSCROLL\n    LTEXT           \"Value:\",IDC_STATIC,7,25,21,8\n    EDITTEXT        IDC_VALUE,38,24,266,128,ES_MULTILINE | WS_VSCROLL\n    DEFPUSHBUTTON   \"OK\",IDOK,200,156,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,254,156,50,14\nEND\n\nIDD_OPTIONS DIALOGEX 0, 0, 423, 247\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Options\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    DEFPUSHBUTTON   \"Close\",IDOK,371,231,50,14\n    CONTROL         \"\",IDC_SECTIONTREE,\"SysTreeView32\",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_FULLROWSELECT | WS_HSCROLL | WS_TABSTOP,2,1,103,244\n    CONTROL         \"\",IDD_CONTAINER,\"#32770\",0x44c,107,0,316,229,WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | 0xc0000800L\n    PUSHBUTTON      \"Reset\",IDC_RESET,108,231,50,14\n    PUSHBUTTON      \"Apply\",IDC_APPLY,319,231,50,14,NOT WS_VISIBLE\n    PUSHBUTTON      \"Cleanup\",IDC_CLEANUP,160,231,50,14\nEND\n\nIDD_PLUGINPROPERTIES DIALOGEX 0, 0, 291, 152\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Plugin Properties\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    GROUPBOX        \"Plugin\",IDC_STATIC,7,7,277,122\n    LTEXT           \"Name:\",IDC_STATIC,15,18,22,8\n    EDITTEXT        IDC_NAME,71,18,104,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Internal name:\",IDC_STATIC,15,30,49,8\n    EDITTEXT        IDC_INTERNALNAME,71,30,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Author:\",IDC_STATIC,15,41,26,8\n    EDITTEXT        IDC_AUTHOR,71,41,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"URL:\",IDC_STATIC,15,52,16,8\n    EDITTEXT        IDC_URL,71,52,174,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    CONTROL         \"<a>Open</a>\",IDC_OPENURL,\"SysLink\",WS_TABSTOP,250,52,26,10\n    LTEXT           \"File name:\",IDC_STATIC,15,63,34,8\n    EDITTEXT        IDC_FILENAME,71,63,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Version:\",IDC_STATIC,183,18,27,8\n    EDITTEXT        IDC_VERSION,215,18,59,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\n    LTEXT           \"Description:\",IDC_STATIC,15,74,39,8\n    EDITTEXT        IDC_DESCRIPTION,14,86,263,37,ES_MULTILINE | ES_READONLY\n    PUSHBUTTON      \"Options...\",IDC_OPTIONS,7,131,50,14\n    DEFPUSHBUTTON   \"Close\",IDOK,234,131,50,14\nEND\n\nIDD_PLUGINSDISABLED DIALOGEX 0, 0, 309, 176\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Disabled Plugins\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    DEFPUSHBUTTON   \"OK\",IDOK,257,160,50,14\n    CONTROL         \"\",IDC_LIST_DISABLED,\"SysListView32\",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,2,305,157\n    LTEXT           \"Changes may require a restart to take effect.\",IDC_INSTRUCTION,2,163,148,8,NOT WS_VISIBLE\nEND\n\nIDD_PROCWMIPROVIDERS DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"WMI\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,53,2,50,14\n    PUSHBUTTON      \"Options\",IDC_OPTIONS,2,2,50,14\n    EDITTEXT        IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE\nEND\n\nIDD_COLUMNSETS DIALOGEX 0, 0, 231, 188\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Organize Column Sets\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Move up\",IDC_MOVEUP,177,42,50,14\n    PUSHBUTTON      \"Move down\",IDC_MOVEDOWN,177,59,50,14\n    PUSHBUTTON      \"OK\",IDOK,177,171,50,14\n    PUSHBUTTON      \"Rename\",IDC_RENAME,177,4,50,14\n    PUSHBUTTON      \"Delete\",IDC_REMOVE,177,94,50,14\n    CONTROL         \"\",IDC_COLUMNSETLIST,\"SysListView32\",LVS_REPORT | LVS_SINGLESEL | LVS_EDITLABELS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,4,4,170,180\nEND\n\nIDD_RUNFILEDLG DIALOGEX 0, 0, 235, 105\nSTYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Run\"\nFONT 9, \"Segoe UI\", 0, 0, 0x1\nBEGIN\n    ICON            100,IDC_FILEICON,7,11,20,20\n    LTEXT           \"Type the name of a program, folder, document, or Internet resource, and Windows will open it for you.\",IDC_STATIC,36,11,182,22\n    LTEXT           \"&Open:\",IDC_STATIC,7,39,28,10\n    COMBOBOX        IDC_PROGRAMCOMBO,36,37,183,200,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP\n    DEFPUSHBUTTON   \"OK\",IDOK,62,82,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,116,82,50,14\n    PUSHBUTTON      \"&Browse...\",IDC_BROWSE,170,82,50,14\n    CONTROL         \"Create this task with TrustedInstaller privileges.\",IDC_TRUSTEDINSTALLER,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,40,62,180,10\n    CONTROL         \"Create this task with Administrative privileges.\",IDC_TOGGLEELEVATION,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,40,51,180,10\nEND\n\nIDD_PROCDUMP DIALOGEX 0, 0, 191, 296\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Process dump\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"Normal\",IDC_MINIDUMP_NORMAL,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,177,10\n    CONTROL         \"With data segments\",IDC_MINIDUMP_WITH_DATA_SEGS,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,17,177,10\n    CONTROL         \"With full memory\",IDC_MINIDUMP_WITH_FULL_MEM,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,27,177,10\n    CONTROL         \"With handle data\",IDC_MINIDUMP_WITH_HANDLE_DATA,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,37,177,10\n    CONTROL         \"Filter memory\",IDC_MINIDUMP_FILTER_MEMORY,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,47,177,10\n    CONTROL         \"Scan memory\",IDC_MINIDUMP_SCAN_MEMORY,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,57,177,10\n    CONTROL         \"With unloaded modules\",IDC_MINIDUMP_WITH_UNLOADED_MODULES,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,177,10\n    CONTROL         \"With indirectly referenced memory\",IDC_MINIDUMP_WITH_INDIRECT_REFERENCED_MEM,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,77,177,10\n    CONTROL         \"Filter module paths\",IDC_MINIDUMP_FILTER_MODULE_PATHS,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,87,179,10\n    CONTROL         \"With process and thread data\",IDC_MINIDUMP_WITH_PROC_THRD_DATA,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,97,177,10\n    CONTROL         \"With private read-write memory\",IDC_MINIDUMP_WITH_PRIVATE_RW_MEM,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,107,177,10\n    CONTROL         \"Without optional data\",IDC_MINIDUMP_WITHOUT_OPTIONAL_DATA,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,117,177,10\n    CONTROL         \"With full memory info\",IDC_MINIDUMP_WITH_FULL_MEM_INFO,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,127,177,10\n    CONTROL         \"With thread info\",IDC_MINIDUMP_WITH_THRD_INFO,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,137,177,10\n    CONTROL         \"With code segments\",IDC_MINIDUMP_WITH_CODE_SEGS,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,147,177,10\n    CONTROL         \"Without auxiliary state\",IDC_MINIDUMP_WITHOUT_AUXILIARY_STATE,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,157,177,10\n    CONTROL         \"With full auxiliary state\",IDC_MINIDUMP_WITH_FULL_AUXILIARY_STATE,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,167,177,10\n    CONTROL         \"With private write-copy memory\",IDC_MINIDUMP_WITH_PRIVATE_WRITE_COPY_MEM,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,177,177,10\n    CONTROL         \"Ignore inaccessible memory\",IDC_MINIDUMP_IGNORE_INACCESSIBLE_MEM,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,187,177,10\n    CONTROL         \"With token information\",IDC_MINIDUMP_WITH_TOKEN_INFO,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,197,177,10\n    CONTROL         \"With module headers\",IDC_MINIDUMP_WITH_MODULE_HEADERS,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,207,177,10\n    CONTROL         \"With filter triage data\",IDC_MINIDUMP_FILTER_TRIAGE,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,217,177,10\n    CONTROL         \"With AVX state context registers\",IDC_MINIDUMP_WITH_AVXX_STATE_CONTEXT,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,227,177,10\n    CONTROL         \"With Intel processor trace data\",IDC_MINIDUMP_WITH_IPT_TRACE,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,237,177,10\n    CONTROL         \"Scan inaccessible partial pages\",IDC_MINIDUMP_SCAN_INACCESSIBLE_PARTIAL_PAGES,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,247,177,10\n    CONTROL         \"Filter write-combined memory\",IDC_MINIDUMP_FILTER_WRITE_COMBINE_MEM,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,257,177,10\n    DEFPUSHBUTTON   \"Save\",IDOK,80,275,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,134,275,50,14\nEND\n\nIDD_LIVEDUMP DIALOGEX 0, 0, 191, 97\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Live kernel dump\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"Use dump storage stack\",IDC_DUMPSTACK,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,177,10\n    CONTROL         \"Compress memory pages\",IDC_COMPRESS,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,17,177,10\n    CONTROL         \"Capture user pages\",IDC_USERMODE,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,27,177,10\n    CONTROL         \"Capture Hypervisor pages\",IDC_HYPERVISOR,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,37,177,10\n    CONTROL         \"Include nonessential Hypervisor pages\",IDC_HYPERVISORNONESSENTIAL,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,47,177,10\n    CONTROL         \"Only kernel thread stacks\",IDC_ONLYKERNELTHREADSTACKS,\n                    \"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,57,177,10\n    DEFPUSHBUTTON   \"Save\",IDOK,80,76,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,134,76,50,14\nEND\n\nIDD_HEAPS DIALOGEX 0, 0, 343, 268\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Heaps\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    DEFPUSHBUTTON   \"Close\",IDCANCEL,289,251,50,14\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_TABSTOP,0,0,343,248\n    CONTROL         \"Sizes in bytes\",IDC_SIZESINBYTES,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,6,254,59,10\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,235,251,50,14\nEND\n\nIDD_PROCVDMHOST DIALOGEX 0, 0, 260, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"NTVDM\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,2,256,256\nEND\n\nIDD_RUNPACKAGE DIALOGEX 0, 0, 317, 239\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Select a package\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Select the identity for access to the package file system and registry.\",IDC_MESSAGE,7,36,303,8,SS_ENDELLIPSIS\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,144,218,50,14\n    DEFPUSHBUTTON   \"OK\",IDOK,205,218,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,260,218,50,14\n    COMBOBOX        IDC_PROGRAMCOMBO,7,20,250,200,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP\n    LTEXT           \"Enter the command to start as the specified package.\",IDC_TITLE,7,7,172,8\n    PUSHBUTTON      \"Browse\",IDC_BROWSE,260,19,50,14\n    CONTROL         \"\",IDC_LIST,\"PhTreeNew\",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,49,303,165,WS_EX_CLIENTEDGE\n    EDITTEXT        IDC_SEARCH,7,218,135,14,ES_AUTOHSCROLL\nEND\n\nIDD_OBJMAPPINGS DIALOGEX 0, 0, 300, 260\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Mappings\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,246\n    LTEXT           \"Static\",IDC_TEXT,7,7,286,246,NOT WS_VISIBLE\nEND\n\nIDD_MODIFIEDPAGES DIALOGEX 0, 0, 351, 307\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Modified pages\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,2,347,286\n    PUSHBUTTON      \"Refresh\",IDC_REFRESH,240,291,50,14\n    DEFPUSHBUTTON   \"Close\",IDOK,294,291,50,14\n    LTEXT           \"Status\",IDC_STATE,4,294,20,8\nEND\n\nIDD_CHOOSENEW DIALOGEX 0, 0, 270, 120\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Input Prompt\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x0\nBEGIN\n    LTEXT           \"Input Prompt\",IDC_TITLE,7,7,262,22\n    CONTROL         \"Input Prompt\",IDC_TEXT,\"SysLink\",WS_TABSTOP,7,33,259,23\n    CONTROL         \"\",IDC_SIZE_,\"Static\",SS_ETCHEDHORZ,0,90,271,1\n    DEFPUSHBUTTON   \"&Ok\",IDOK,158,98,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,212,98,50,14\n    COMBOBOX        IDC_INPUT,7,64,255,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP\nEND\n\nIDD_OBJAFDSOCKET DIALOGEX 0, 0, 260, 234\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Socket\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_TABSTOP,0,2,260,232\nEND\n\nIDD_HNDLSECURITY DIALOGEX 0, 0, 260, 181\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Permissions\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,60,260,94\n    PUSHBUTTON      \"Add\",IDC_ADD,1,160,47,14\n    PUSHBUTTON      \"Advanced\",IDC_ADVANCED,212,160,47,14\n    PUSHBUTTON      \"Remove\",IDC_REMOVE,51,160,47,14\n    PUSHBUTTON      \"View\",IDC_SHOW,103,160,47,14\n    CONTROL         \"\",IDC_SETTINGS,\"SysListView32\",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_TABSTOP,0,2,260,46\nEND\n\nIDD_HNDLSECAUDIT DIALOGEX 0, 0, 260, 181\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Auditing\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    CONTROL         \"\",IDC_LIST,\"SysListView32\",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,60,260,94\n    PUSHBUTTON      \"Add\",IDC_ADD,1,160,47,14,NOT WS_VISIBLE\n    PUSHBUTTON      \"Advanced\",IDC_ADVANCED,212,160,47,14\n    PUSHBUTTON      \"Remove\",IDC_REMOVE,51,160,47,14,NOT WS_VISIBLE\n    PUSHBUTTON      \"View\",IDC_SHOW,103,160,47,14,NOT WS_VISIBLE\n    CONTROL         \"\",IDC_SETTINGS,\"SysListView32\",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_TABSTOP,0,2,260,46\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// DESIGNINFO\n//\n\n#ifdef APSTUDIO_INVOKED\nGUIDELINES DESIGNINFO\nBEGIN\n    IDD_PROCGENERAL, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 254\n    END\n\n    IDD_PROCMODULES, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 258\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 258\n    END\n\n    IDD_PROCTHREADS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 253\n    END\n\n    IDD_PROCHANDLES, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 258\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 258\n    END\n\n    IDD_PROCENVIRONMENT, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 258\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 258\n    END\n\n    IDD_THRDSTACK, DIALOG\n    BEGIN\n        BOTTOMMARGIN, 226\n    END\n\n    IDD_USRLIST, DIALOG\n    BEGIN\n        BOTTOMMARGIN, 226\n    END\n\n    IDD_ABOUT, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 263\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 188\n    END\n\n    IDD_SRVLIST, DIALOG\n    BEGIN\n    END\n\n    IDD_SRVGENERAL, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 275\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 176\n    END\n\n    IDD_HNDLGENERAL, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 174\n    END\n\n    IDD_INFORMATION, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 310\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 177\n    END\n\n    IDD_FINDOBJECTS, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 355\n        TOPMARGIN, 4\n        BOTTOMMARGIN, 231\n    END\n\n    IDD_THRDSTACKS, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 441\n        TOPMARGIN, 4\n        BOTTOMMARGIN, 252\n    END\n\n    IDD_USRLIST, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 441\n        TOPMARGIN, 4\n        BOTTOMMARGIN, 252\n    END\n\n    IDD_OBJTOKEN, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 253\n    END\n\n    IDD_ZOMBIEPROCESSES, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 330\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 214\n    END\n\n    IDD_RUNAS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 286\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 120\n    END\n\n    IDD_PROGRESS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 209\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 55\n    END\n\n    IDD_PAGEFILES, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 320\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 160\n    END\n\n    IDD_TOKGENERAL, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 263\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 221\n    END\n\n    IDD_TOKADVANCED, DIALOG\n    BEGIN\n    END\n\n    IDD_OBJJOB, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 253\n    END\n\n    IDD_OBJEVENT, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 179\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 69\n    END\n\n    IDD_OBJMUTANT, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 179\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 69\n    END\n\n    IDD_OBJSEMAPHORE, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 179\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 69\n    END\n\n    IDD_OBJTIMER, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 179\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 69\n    END\n\n    IDD_JOBSTATISTICS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 252\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 179\n    END\n\n    IDD_OBJEVENTPAIR, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 179\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 69\n    END\n\n    IDD_AFFINITY, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 272\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 220\n    END\n\n    IDD_SYSINFO, DIALOG\n    BEGIN\n    END\n\n    IDD_EDITMESSAGE, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 275\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 156\n    END\n\n    IDD_SESSION, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 315\n        VERTGUIDE, 164\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 265\n    END\n\n    IDD_PROCMEMORY, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 258\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 258\n    END\n\n    IDD_CHOOSE, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 192\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 66\n    END\n\n    IDD_OPTGENERAL, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 308\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 213\n    END\n\n    IDD_OPTHIGHLIGHTING, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 243\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 167\n    END\n\n    IDD_CHOOSECOLUMNS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 376\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 220\n    END\n\n    IDD_NETSTACK, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 254\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 221\n    END\n\n    IDD_CREATESERVICE, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 280\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 126\n    END\n\n    IDD_PROCPERFORMANCE, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 253\n    END\n\n    IDD_PROCSTATISTICS, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 257\n        TOPMARGIN, 3\n        BOTTOMMARGIN, 258\n    END\n\n    IDD_OPTADVANCED, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 310\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 218\n    END\n\n    IDD_GDIHANDLES, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 344\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 300\n    END\n\n    IDD_LOG, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 306\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 296\n    END\n\n    IDD_MEMEDIT, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 434\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 262\n    END\n\n    IDD_MEMPROTECT, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 263\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 164\n    END\n\n    IDD_MEMSTRINGS, DIALOG\n    BEGIN\n        LEFTMARGIN, 3\n        RIGHTMARGIN, 298\n        TOPMARGIN, 3\n    END\n\n    IDD_MEMSTRINGSMINLEN, DIALOG\n    BEGIN\n        LEFTMARGIN, 3\n        TOPMARGIN, 3\n    END\n\n    IDD_OPTGRAPHS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 243\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 149\n    END\n\n    IDD_PLUGINMANAGER, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 499\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 270\n    END\n\n    IDD_HANDLESTATS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 212\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 168\n    END\n\n    IDD_PROCRECORD, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 195\n    END\n\n    IDD_CHOOSEPROCESS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 310\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 232\n    END\n\n    IDD_PROCSERVICES, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 254\n    END\n\n    IDD_SHADOWSESSION, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 221\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 77\n    END\n\n    IDD_TOKCAPABILITIES, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 263\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 221\n    END\n\n    IDD_TOKATTRIBUTES, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 263\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 221\n    END\n\n    IDD_SYSINFO_CPU, DIALOG\n    BEGIN\n        BOTTOMMARGIN, 193\n    END\n\n    IDD_SYSINFO_CPUPANEL, DIALOG\n    BEGIN\n        BOTTOMMARGIN, 85\n    END\n\n    IDD_SYSINFO_MEMPANEL, DIALOG\n    BEGIN\n    END\n\n    IDD_SYSINFO_MEM, DIALOG\n    BEGIN\n        BOTTOMMARGIN, 247\n    END\n\n    IDD_SYSINFO_IO, DIALOG\n    BEGIN\n    END\n\n    IDD_SYSINFO_IOPANEL, DIALOG\n    BEGIN\n        BOTTOMMARGIN, 74\n    END\n\n    IDD_MEMLISTS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 221\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 188\n    END\n\n    IDD_CONTAINER, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 309\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 175\n    END\n\n    IDD_MINIINFO, DIALOG\n    BEGIN\n        LEFTMARGIN, 4\n        RIGHTMARGIN, 214\n        TOPMARGIN, 3\n        BOTTOMMARGIN, 147\n    END\n\n    IDD_MINIINFO_LIST, DIALOG\n    BEGIN\n    END\n\n    IDD_MITIGATION, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 270\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 210\n    END\n\n    IDD_EDITENV, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 304\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 170\n    END\n\n    IDD_OPTIONS, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        BOTTOMMARGIN, 245\n    END\n\n    IDD_PLUGINPROPERTIES, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 284\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 145\n    END\n\n    IDD_PLUGINSDISABLED, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 307\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 174\n    END\n\n    IDD_PROCWMIPROVIDERS, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 258\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 258\n    END\n\n    IDD_COLUMNSETS, DIALOG\n    BEGIN\n        LEFTMARGIN, 4\n        RIGHTMARGIN, 227\n        TOPMARGIN, 4\n        BOTTOMMARGIN, 184\n    END\n\n    IDD_RUNFILEDLG, DIALOG\n    BEGIN\n    END\n\n    IDD_PROCDUMP, DIALOG\n    BEGIN\n        BOTTOMMARGIN, 289\n    END\n\n    IDD_LIVEDUMP, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 184\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 90\n    END\n\n    IDD_HEAPS, DIALOG\n    BEGIN\n    END\n\n    IDD_PROCVDMHOST, DIALOG\n    BEGIN\n        LEFTMARGIN, 2\n        RIGHTMARGIN, 258\n        TOPMARGIN, 2\n        BOTTOMMARGIN, 258\n    END\n\n    IDD_RUNPACKAGE, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 310\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 232\n    END\n\n    IDD_OBJMAPPINGS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 253\n    END\n\n    IDD_MODIFIEDPAGES, DIALOG\n    BEGIN\n    END\n\n    IDD_CHOOSENEW, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        TOPMARGIN, 7\n    END\n\n    IDD_OBJAFDSOCKET, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 253\n        TOPMARGIN, 7\n    END\n\n    IDD_HNDLSECURITY, DIALOG\n    BEGIN\n    END\n\n    IDD_HNDLSECAUDIT, DIALOG\n    BEGIN\n    END\nEND\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Accelerator\n//\n\nIDR_MAINWND_ACCEL ACCELERATORS\nBEGIN\n    VK_ESCAPE,      ID_ESC_EXIT,            VIRTKEY, NOINVERT\n    \"F\",            ID_HACKER_FINDHANDLESORDLLS, VIRTKEY, CONTROL, NOINVERT\n    \"R\",            ID_HACKER_RUN,          VIRTKEY, CONTROL, NOINVERT\n    \"R\",            ID_HACKER_RUNAS,        VIRTKEY, SHIFT, CONTROL, NOINVERT\n    \"S\",            ID_HACKER_SAVE,         VIRTKEY, CONTROL, NOINVERT\n    \"L\",            ID_HELP_LOG,            VIRTKEY, CONTROL, NOINVERT\n    \"M\",            ID_PROCESS_SEARCHONLINE, VIRTKEY, CONTROL, NOINVERT\n    VK_TAB,         ID_TAB_NEXT,            VIRTKEY, CONTROL, NOINVERT\n    VK_TAB,         ID_TAB_PREV,            VIRTKEY, SHIFT, CONTROL, NOINVERT\n    VK_F5,          ID_VIEW_REFRESH,        VIRTKEY, NOINVERT\n    \"I\",            ID_VIEW_SYSTEMINFORMATION, VIRTKEY, CONTROL, NOINVERT\n    VK_PAUSE,       ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT\n    VK_F6,          ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT\nEND\n\nIDR_SYSINFO_ACCEL ACCELERATORS\nBEGIN\n    \"1\",            ID_DIGIT1,              VIRTKEY, NOINVERT\n    \"2\",            ID_DIGIT2,              VIRTKEY, NOINVERT\n    \"3\",            ID_DIGIT3,              VIRTKEY, NOINVERT\n    \"4\",            ID_DIGIT4,              VIRTKEY, NOINVERT\n    \"5\",            ID_DIGIT5,              VIRTKEY, NOINVERT\n    \"6\",            ID_DIGIT6,              VIRTKEY, NOINVERT\n    \"7\",            ID_DIGIT7,              VIRTKEY, NOINVERT\n    \"8\",            ID_DIGIT8,              VIRTKEY, NOINVERT\n    \"9\",            ID_DIGIT9,              VIRTKEY, NOINVERT\n    \"B\",            IDC_BACK,               VIRTKEY, ALT, NOINVERT\n    VK_BACK,        IDC_BACK,               VIRTKEY, NOINVERT\n    VK_F6,          IDC_PAUSE,              VIRTKEY, NOINVERT\n    VK_PAUSE,       IDC_PAUSE,              VIRTKEY, NOINVERT\n    VK_F5,          IDC_REFRESH,            VIRTKEY, NOINVERT\n    VK_F11,         IDC_MAXSCREEN,          VIRTKEY, NOINVERT\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Bitmap\n//\n\nIDB_SEARCH_ACTIVE_BMP   BITMAP                  \"resources\\\\active_search.bmp\"\n\nIDB_SEARCH_INACTIVE_BMP BITMAP                  \"resources\\\\inactive_search.bmp\"\n\n#endif    // English (United States) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n"
  },
  {
    "path": "SystemInformer/SystemInformer.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>17.0</VCProjectVersion>\n    <ProjectGuid>{0271DD27-6707-4290-8DFE-285702B7115D}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectName>SystemInformer</ProjectName>\n    <RootNamespace>SystemInformer</RootNamespace>\n    <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;_PHAPP_;_WINDOWS;WIN32;_DEBUG;DEBUG;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>setupapi.lib;cfgmgr32.lib;aclui.lib;comctl32.lib;dnsapi.lib;gdiplus.lib;ntdll.lib;phlib.lib;userenv.lib;wbemuuid.lib;windowscodecs.lib;winhttp.lib;winsta.lib;kphlib_um.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);$(SolutionDir)phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <ModuleDefinitionFile>SystemInformer.def</ModuleDefinitionFile>\n      <DelayLoadDLLs>setupapi.dll;cfgmgr32.dll;aclui.dll;comdlg32.dll;gdiplus.dll;oleaut32.dll;winhttp.dll;winsta.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\n    </Link>\n    <ResourceCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)kphlib\\include;$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PostBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_zdriver_sdk.cmd\" \"$(OutDir)$(TargetName)$(TargetExt)\" \"-$(Configuration)\" \"-$(PlatformName)\"</Command>\n    </PostBuildEvent>\n    <Manifest>\n      <AdditionalManifestFiles>systeminformer.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;_PHAPP_;_WINDOWS;WIN64;_DEBUG;DEBUG;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>setupapi.lib;cfgmgr32.lib;aclui.lib;comctl32.lib;dnsapi.lib;gdiplus.lib;ntdll.lib;phlib.lib;userenv.lib;wbemuuid.lib;windowscodecs.lib;winhttp.lib;winsta.lib;kphlib_um.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);$(SolutionDir)phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <ModuleDefinitionFile>SystemInformer.def</ModuleDefinitionFile>\n      <DelayLoadDLLs>setupapi.dll;cfgmgr32.dll;aclui.dll;comdlg32.dll;gdiplus.dll;oleaut32.dll;winhttp.dll;winsta.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\n    </Link>\n    <ResourceCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)kphlib\\include;$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PostBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_zdriver_sdk.cmd\" \"$(OutDir)$(TargetName)$(TargetExt)\" \"-$(Configuration)\" \"-$(PlatformName)\"</Command>\n    </PostBuildEvent>\n    <Manifest>\n      <AdditionalManifestFiles>systeminformer.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;_PHAPP_;_WINDOWS;WIN64;_DEBUG;DEBUG;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>setupapi.lib;cfgmgr32.lib;aclui.lib;comctl32.lib;dnsapi.lib;gdiplus.lib;ntdll.lib;phlib.lib;userenv.lib;wbemuuid.lib;windowscodecs.lib;winhttp.lib;winsta.lib;kphlib_um.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);$(SolutionDir)phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <ModuleDefinitionFile>SystemInformer.def</ModuleDefinitionFile>\n      <DelayLoadDLLs>setupapi.dll;cfgmgr32.dll;aclui.dll;comdlg32.dll;gdiplus.dll;oleaut32.dll;winhttp.dll;winsta.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\n    </Link>\n    <ResourceCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)kphlib\\include;$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PostBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_zdriver_sdk.cmd\" \"$(OutDir)$(TargetName)$(TargetExt)\" \"-$(Configuration)\" \"-$(PlatformName)\"</Command>\n    </PostBuildEvent>\n    <Manifest>\n      <AdditionalManifestFiles>systeminformer.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;_PHAPP_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>setupapi.lib;cfgmgr32.lib;aclui.lib;comctl32.lib;dnsapi.lib;gdiplus.lib;ntdll.lib;phlib.lib;userenv.lib;wbemuuid.lib;windowscodecs.lib;winhttp.lib;winsta.lib;kphlib_um.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);$(SolutionDir)phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <ModuleDefinitionFile>SystemInformer.def</ModuleDefinitionFile>\n      <DelayLoadDLLs>setupapi.dll;cfgmgr32.dll;aclui.dll;comdlg32.dll;gdiplus.dll;oleaut32.dll;winhttp.dll;winsta.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\n    </Link>\n    <ResourceCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)kphlib\\include;$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PostBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_zdriver_sdk.cmd\" \"$(OutDir)$(TargetName)$(TargetExt)\" \"-$(Configuration)\" \"-$(PlatformName)\"</Command>\n    </PostBuildEvent>\n    <Manifest>\n      <AdditionalManifestFiles>systeminformer.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;_PHAPP_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>setupapi.lib;cfgmgr32.lib;aclui.lib;comctl32.lib;dnsapi.lib;gdiplus.lib;ntdll.lib;phlib.lib;userenv.lib;wbemuuid.lib;windowscodecs.lib;winhttp.lib;winsta.lib;kphlib_um.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);$(SolutionDir)phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <ModuleDefinitionFile>SystemInformer.def</ModuleDefinitionFile>\n      <DelayLoadDLLs>setupapi.dll;cfgmgr32.dll;aclui.dll;comdlg32.dll;gdiplus.dll;oleaut32.dll;winhttp.dll;winsta.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\n    </Link>\n    <ResourceCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)kphlib\\include;$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PostBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_zdriver_sdk.cmd\" \"$(OutDir)$(TargetName)$(TargetExt)\" \"-$(Configuration)\" \"-$(PlatformName)\"</Command>\n    </PostBuildEvent>\n    <Manifest>\n      <AdditionalManifestFiles>systeminformer.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;_PHAPP_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions);$(ExternalPreprocessorOptions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>setupapi.lib;cfgmgr32.lib;aclui.lib;comctl32.lib;dnsapi.lib;gdiplus.lib;ntdll.lib;phlib.lib;userenv.lib;wbemuuid.lib;windowscodecs.lib;winhttp.lib;winsta.lib;kphlib_um.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);$(SolutionDir)phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <ModuleDefinitionFile>SystemInformer.def</ModuleDefinitionFile>\n      <DelayLoadDLLs>setupapi.dll;cfgmgr32.dll;aclui.dll;comdlg32.dll;gdiplus.dll;oleaut32.dll;winhttp.dll;winsta.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\n    </Link>\n    <ResourceCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)kphlib\\include;$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PostBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_zdriver_sdk.cmd\" \"$(OutDir)$(TargetName)$(TargetExt)\" \"-$(Configuration)\" \"-$(PlatformName)\"</Command>\n    </PostBuildEvent>\n    <Manifest>\n      <AdditionalManifestFiles>systeminformer.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"about.c\" />\n    <ClCompile Include=\"actions.c\" />\n    <ClCompile Include=\"admintask.c\" />\n    <ClCompile Include=\"affinity.c\" />\n    <ClCompile Include=\"anawait.c\" />\n    <ClCompile Include=\"appsup.c\" />\n    <ClCompile Include=\"chcol.c\" />\n    <ClCompile Include=\"chdlg.c\" />\n    <ClCompile Include=\"chproc.c\" />\n    <ClCompile Include=\"colmgr.c\" />\n    <ClCompile Include=\"colsetmgr.c\" />\n    <ClCompile Include=\"dbgcon.c\" />\n    <ClCompile Include=\"delayhook.c\" />\n    <ClCompile Include=\"delayload.c\" />\n    <ClCompile Include=\"devprv.c\" />\n    <ClCompile Include=\"extmgr.c\" />\n    <ClCompile Include=\"findobj.c\" />\n    <ClCompile Include=\"gdihndl.c\" />\n    <ClCompile Include=\"heapinfo.c\" />\n    <ClCompile Include=\"hidnproc.c\" />\n    <ClCompile Include=\"hndllist.c\" />\n    <ClCompile Include=\"hndlmenu.c\" />\n    <ClCompile Include=\"hndlprp.c\" />\n    <ClCompile Include=\"hndlprv.c\" />\n    <ClCompile Include=\"hndlstat.c\" />\n    <ClCompile Include=\"infodlg.c\" />\n    <ClCompile Include=\"itemtips.c\" />\n    <ClCompile Include=\"jobprp.c\" />\n    <ClCompile Include=\"kdump.c\" />\n    <ClCompile Include=\"ksidbg.c\" />\n    <ClCompile Include=\"informer.c\" />\n    <ClCompile Include=\"memmod.c\" />\n    <ClCompile Include=\"ksisup.c\" />\n    <ClCompile Include=\"ksyscall.c\" />\n    <ClCompile Include=\"log.c\" />\n    <ClCompile Include=\"logwnd.c\" />\n    <ClCompile Include=\"main.c\" />\n    <ClCompile Include=\"mainwnd.c\" />\n    <ClCompile Include=\"mdump.c\" />\n    <ClCompile Include=\"memedit.c\" />\n    <ClCompile Include=\"memlist.c\" />\n    <ClCompile Include=\"memlists.c\" />\n    <ClCompile Include=\"memprot.c\" />\n    <ClCompile Include=\"memprv.c\" />\n    <ClCompile Include=\"memrslt.c\" />\n    <ClCompile Include=\"memsrch.c\" />\n    <ClCompile Include=\"memsrcht.c\" />\n    <ClCompile Include=\"miniinfo.c\" />\n    <ClCompile Include=\"modlist.c\" />\n    <ClCompile Include=\"modprv.c\" />\n    <ClCompile Include=\"mtgndlg.c\" />\n    <ClCompile Include=\"mwpgdev.c\" />\n    <ClCompile Include=\"mwpgnet.c\" />\n    <ClCompile Include=\"mwpgproc.c\" />\n    <ClCompile Include=\"mwpgsrv.c\" />\n    <ClCompile Include=\"netlist.c\" />\n    <ClCompile Include=\"netprv.c\" />\n    <ClCompile Include=\"netsup.c\" />\n    <ClCompile Include=\"notifico.c\" />\n    <ClCompile Include=\"notiftoast.cpp\" />\n    <ClCompile Include=\"ntobjprp.c\" />\n    <ClCompile Include=\"options.c\" />\n    <ClCompile Include=\"pagfiles.c\" />\n    <ClCompile Include=\"phsvc\\clapi.c\" />\n    <ClCompile Include=\"phsvc\\svcapi.c\" />\n    <ClCompile Include=\"phsvc\\svcapiport.c\" />\n    <ClCompile Include=\"phsvc\\svcclient.c\" />\n    <ClCompile Include=\"phsvc\\svcmain.c\" />\n    <ClCompile Include=\"plugin.c\" />\n    <ClCompile Include=\"plugman.c\" />\n    <ClCompile Include=\"procgrp.c\" />\n    <ClCompile Include=\"procmtgn.c\" />\n    <ClCompile Include=\"procprp.c\" />\n    <ClCompile Include=\"procprv.c\" />\n    <ClCompile Include=\"procrec.c\" />\n    <ClCompile Include=\"proctree.c\" />\n    <ClCompile Include=\"prpgenv.c\" />\n    <ClCompile Include=\"prpggen.c\" />\n    <ClCompile Include=\"prpghndl.c\" />\n    <ClCompile Include=\"prpgjob.c\" />\n    <ClCompile Include=\"prpgmem.c\" />\n    <ClCompile Include=\"prpgmod.c\" />\n    <ClCompile Include=\"prpgvdm.c\" />\n    <ClCompile Include=\"prpgperf.c\" />\n    <ClCompile Include=\"prpgsrv.c\" />\n    <ClCompile Include=\"prpgstat.c\" />\n    <ClCompile Include=\"prpgthrd.c\" />\n    <ClCompile Include=\"prpgtok.c\" />\n    <ClCompile Include=\"prpgwmi.c\" />\n    <ClCompile Include=\"runas.c\" />\n    <ClCompile Include=\"searchbox.c\" />\n    <ClCompile Include=\"sessprp.c\" />\n    <ClCompile Include=\"sessshad.c\" />\n    <ClCompile Include=\"settings.c\" />\n    <ClCompile Include=\"srvcr.c\" />\n    <ClCompile Include=\"srvctl.c\" />\n    <ClCompile Include=\"srvlist.c\" />\n    <ClCompile Include=\"srvprp.c\" />\n    <ClCompile Include=\"srvprv.c\" />\n    <ClCompile Include=\"sessmsg.c\" />\n    <ClCompile Include=\"sysinfo.c\" />\n    <ClCompile Include=\"syssccpu.c\" />\n    <ClCompile Include=\"sysscio.c\" />\n    <ClCompile Include=\"sysscmem.c\" />\n    <ClCompile Include=\"thrdlist.c\" />\n    <ClCompile Include=\"thrdprv.c\" />\n    <ClCompile Include=\"thrdstk.c\" />\n    <ClCompile Include=\"thrdstks.c\" />\n    <ClCompile Include=\"tokprp.c\" />\n    <ClCompile Include=\"usrlist.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\actions.h\" />\n    <ClInclude Include=\"include\\appsup.h\" />\n    <ClInclude Include=\"include\\colmgr.h\" />\n    <ClInclude Include=\"include\\colsetmgr.h\" />\n    <ClInclude Include=\"include\\devprv.h\" />\n    <ClInclude Include=\"include\\extmgr.h\" />\n    <ClInclude Include=\"include\\extmgri.h\" />\n    <ClInclude Include=\"include\\heapstruct.h\" />\n    <ClInclude Include=\"include\\hndllist.h\" />\n    <ClInclude Include=\"include\\hndlmenu.h\" />\n    <ClInclude Include=\"include\\hndlprv.h\" />\n    <ClInclude Include=\"include\\informer.h\" />\n    <ClInclude Include=\"include\\ksisup.h\" />\n    <ClInclude Include=\"include\\mainwnd.h\" />\n    <ClInclude Include=\"include\\mainwndp.h\" />\n    <ClInclude Include=\"include\\memlist.h\" />\n    <ClInclude Include=\"include\\miniinfop.h\" />\n    <ClInclude Include=\"include\\modlist.h\" />\n    <ClInclude Include=\"include\\modprv.h\" />\n    <ClInclude Include=\"include\\netlist.h\" />\n    <ClInclude Include=\"include\\netprv.h\" />\n    <ClInclude Include=\"include\\notifico.h\" />\n    <ClInclude Include=\"include\\notificop.h\" />\n    <ClInclude Include=\"include\\notiftoast.h\" />\n    <ClInclude Include=\"include\\phfwddef.h\" />\n    <ClInclude Include=\"include\\phsvccl.h\" />\n    <ClInclude Include=\"include\\procmtgn.h\" />\n    <ClInclude Include=\"include\\procprp.h\" />\n    <ClInclude Include=\"include\\procprv.h\" />\n    <ClInclude Include=\"include\\proctree.h\" />\n    <ClInclude Include=\"include\\phsettings.h\" />\n    <ClInclude Include=\"include\\srvlist.h\" />\n    <ClInclude Include=\"include\\srvprv.h\" />\n    <ClInclude Include=\"include\\sysinfo.h\" />\n    <ClInclude Include=\"include\\thrdlist.h\" />\n    <ClInclude Include=\"include\\thrdprv.h\" />\n    <ClInclude Include=\"include\\phuisup.h\" />\n    <ClInclude Include=\"include\\miniinfo.h\" />\n    <ClInclude Include=\"include\\hidnproc.h\" />\n    <ClInclude Include=\"include\\memsrch.h\" />\n    <ClInclude Include=\"include\\phapp.h\" />\n    <ClInclude Include=\"include\\phsvc.h\" />\n    <ClInclude Include=\"include\\phsvcapi.h\" />\n    <ClInclude Include=\"include\\phappres.h\" />\n    <ClInclude Include=\"include\\procgrp.h\" />\n    <ClInclude Include=\"sdk\\phdk.h\" />\n    <ClInclude Include=\"include\\phplug.h\" />\n    <ClInclude Include=\"include\\procprpp.h\" />\n    <ClInclude Include=\"include\\memprv.h\" />\n    <ClInclude Include=\"resource.h\" />\n    <ClInclude Include=\"include\\sysinfop.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"resources\\case_sensitive_modern_dark.svg\" />\n    <None Include=\"resources\\case_sensitive_modern_light.svg\" />\n    <None Include=\"resources\\regex_modern_dark.svg\" />\n    <None Include=\"resources\\regex_modern_light.svg\" />\n    <None Include=\"resources\\search_modern_dark.svg\" />\n    <None Include=\"resources\\search_modern_light.svg\" />\n    <None Include=\"resources\\search_stop_modern_dark.svg\" />\n    <None Include=\"resources\\search_stop_modern_light.svg\" />\n    <None Include=\"SystemInformer.def\" />\n    <None Include=\"resources\\application.ico\" />\n    <None Include=\"resources\\cog.ico\" />\n    <None Include=\"SystemInformer.ico\" />\n    <None Include=\"resources\\SystemInformer.png\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"SystemInformer.rc\" />\n    <ResourceCompile Include=\"version.rc\" />\n    <ResourceCompile Include=\"..\\kphlib\\include\\sistatus.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Manifest Include=\"SystemInformer.manifest\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"resources\\active_search.bmp\" />\n    <Image Include=\"resources\\active_search.png\" />\n    <Image Include=\"resources\\active_search_small.png\" />\n    <Image Include=\"resources\\case_sensitive_modern_dark.png\" />\n    <Image Include=\"resources\\case_sensitive_modern_light.png\" />\n    <Image Include=\"resources\\folder.ico\" />\n    <Image Include=\"resources\\inactive_search.bmp\" />\n    <Image Include=\"resources\\inactive_search.png\" />\n    <Image Include=\"resources\\inactive_search_small.png\" />\n    <Image Include=\"resources\\magnifier.ico\" />\n    <Image Include=\"resources\\pin.ico\" />\n    <Image Include=\"resources\\regex_modern_dark.png\" />\n    <Image Include=\"resources\\regex_modern_light.png\" />\n    <Image Include=\"resources\\search_modern_dark.png\" />\n    <Image Include=\"resources\\search_modern_light.png\" />\n    <Image Include=\"resources\\search_stop_modern_dark.png\" />\n    <Image Include=\"resources\\search_stop_modern_light.png\" />\n    <Image Include=\"resources\\shield.ico\" />\n    <Image Include=\"resources\\systeminformer-128x128.png\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"resources\\capslist.txt\" />\n    <Text Include=\"resources\\etwguids.txt\" />\n    <Text Include=\"resources\\pooltag.txt\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>\n"
  },
  {
    "path": "SystemInformer/SystemInformer.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Headers\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resources\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>\n    </Filter>\n    <Filter Include=\"System Informer\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"phsvc\">\n      <UniqueIdentifier>{84a3be0b-42cf-42ae-bcd3-16f165caa0db}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Module\">\n      <UniqueIdentifier>{67c40321-0b28-4c16-8c48-dc0b64c148d7}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"about.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"actions.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"affinity.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"anawait.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"appsup.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"chcol.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"chdlg.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"chproc.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"dbgcon.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"findobj.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"gdihndl.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hidnproc.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hndlprp.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hndlprv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hndlstat.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"infodlg.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"itemtips.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jobprp.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"log.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"logwnd.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"main.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mainwnd.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mdump.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memedit.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memprot.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memprv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memrslt.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memsrch.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"modprv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"netprv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"notifico.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ntobjprp.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"options.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"pagfiles.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"plugin.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"plugman.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"procprp.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"procprv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"procrec.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"proctree.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"runas.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sessprp.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"srvcr.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"srvprp.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"srvprv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sysinfo.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"thrdprv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"thrdstk.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"tokprp.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"srvctl.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"srvlist.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"modlist.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"phsvc\\svcmain.c\">\n      <Filter>phsvc</Filter>\n    </ClCompile>\n    <ClCompile Include=\"phsvc\\svcclient.c\">\n      <Filter>phsvc</Filter>\n    </ClCompile>\n    <ClCompile Include=\"phsvc\\svcapiport.c\">\n      <Filter>phsvc</Filter>\n    </ClCompile>\n    <ClCompile Include=\"phsvc\\svcapi.c\">\n      <Filter>phsvc</Filter>\n    </ClCompile>\n    <ClCompile Include=\"phsvc\\clapi.c\">\n      <Filter>phsvc</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sessmsg.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sessshad.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"colmgr.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"netlist.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"extmgr.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"thrdlist.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hndllist.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memlists.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memlist.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"miniinfo.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"procgrp.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"procmtgn.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mtgndlg.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hndlmenu.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"syssccpu.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sysscmem.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sysscio.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpggen.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgstat.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgperf.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgthrd.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgtok.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgmod.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgmem.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgenv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpghndl.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgjob.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgsrv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mwpgproc.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mwpgsrv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mwpgnet.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"searchbox.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"settings.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgwmi.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"colsetmgr.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kdump.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"heapinfo.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"prpgvdm.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"delayload.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"admintask.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ksisup.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"delayhook.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ksyscall.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memmod.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"devprv.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mwpgdev.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"notiftoast.cpp\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ksidbg.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"thrdstks.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"informer.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memsrcht.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"usrlist.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"netsup.c\">\n      <Filter>System Informer</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\hidnproc.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\memsrch.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phapp.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"sdk\\phdk.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phplug.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\procprpp.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"resource.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phsvcapi.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phsvc.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phsvccl.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phappres.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\colmgr.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\mainwndp.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\extmgr.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\extmgri.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\sysinfop.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\notifico.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\heapstruct.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\miniinfop.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\miniinfo.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\procgrp.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\sysinfo.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\notificop.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\procmtgn.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phfwddef.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\procprv.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\srvprv.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\netprv.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\modprv.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\thrdprv.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hndlprv.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\memprv.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phuisup.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\proctree.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\srvlist.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\netlist.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\thrdlist.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\modlist.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hndllist.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\memlist.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hndlmenu.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\actions.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\appsup.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\mainwnd.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\procprp.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phsettings.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\colsetmgr.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\notiftoast.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\ksisup.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\devprv.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\informer.h\">\n      <Filter>Headers</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"SystemInformer.ico\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\SystemInformer.png\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\application.ico\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\cog.ico\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"SystemInformer.def\">\n      <Filter>Module</Filter>\n    </None>\n    <None Include=\"resources\\case_sensitive_modern_dark.svg\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\case_sensitive_modern_light.svg\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\regex_modern_dark.svg\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\regex_modern_light.svg\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\search_modern_dark.svg\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\search_modern_light.svg\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\search_stop_modern_dark.svg\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"resources\\search_stop_modern_light.svg\">\n      <Filter>Resources</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"SystemInformer.rc\">\n      <Filter>Resources</Filter>\n    </ResourceCompile>\n    <ResourceCompile Include=\"version.rc\">\n      <Filter>Resources</Filter>\n    </ResourceCompile>\n    <ResourceCompile Include=\"..\\kphlib\\include\\sistatus.rc\">\n      <Filter>Resources</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Manifest Include=\"SystemInformer.manifest\">\n      <Filter>Resources</Filter>\n    </Manifest>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"resources\\pin.ico\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\folder.ico\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\magnifier.ico\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\active_search.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\active_search.bmp\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\inactive_search.bmp\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\inactive_search.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\shield.ico\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\active_search_small.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\inactive_search_small.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\case_sensitive_modern_dark.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\case_sensitive_modern_light.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\regex_modern_dark.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\regex_modern_light.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\search_modern_dark.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\search_modern_light.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\search_stop_modern_dark.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\search_stop_modern_light.png\">\n      <Filter>Resources</Filter>\n    </Image>\n    <Image Include=\"resources\\systeminformer-128x128.png\">\n      <Filter>Resources</Filter>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"resources\\capslist.txt\">\n      <Filter>Resources</Filter>\n    </Text>\n    <Text Include=\"resources\\etwguids.txt\">\n      <Filter>Resources</Filter>\n    </Text>\n    <Text Include=\"resources\\pooltag.txt\">\n      <Filter>Resources</Filter>\n    </Text>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "SystemInformer/about.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2024\n *\n */\n\n#include <phapp.h>\n#include <symprv.h>\n\n#include <hndlprv.h>\n#include <mainwnd.h>\n#include <memprv.h>\n#include <modprv.h>\n#include <netprv.h>\n#include <phappres.h>\n#include <phintrnl.h>\n#include <phsettings.h>\n#include <procprv.h>\n#include <settings.h>\n#include <srvprv.h>\n#include <thrdprv.h>\n\nstatic HWND PhAboutWindowHandle = NULL;\n\nstatic INT_PTR CALLBACK PhpAboutDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_STRING versionString;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhCenterWindow(hwndDlg, PhMainWndHandle);\n\n            versionString = PhGetApplicationVersionString(TRUE);\n            PhMoveReference(&versionString, PhConcatStringRefZ(&versionString->sr, L\"\\r\\n\"));\n            PhSetDialogItemText(hwndDlg, IDC_ABOUT_NAME, versionString->Buffer);\n            PhDereferenceObject(versionString);\n\n            PhSetDialogItemText(hwndDlg, IDC_CREDITS,\n                L\"Thanks to:\\n\"\n                L\"    <a href=\\\"https://github.com/wj32\\\">wj32</a> - Wen Jia Liu\\n\"\n                L\"    <a href=\\\"https://github.com/dmex\\\">dmex</a> - Steven G\\n\"\n                L\"    <a href=\\\"https://github.com/jxy-s\\\">jxy-s</a> - Johnny Shaw\\n\"\n                L\"    <a href=\\\"https://github.com/ionescu007\\\">ionescu007</a> - Alex Ionescu\\n\"\n                L\"    <a href=\\\"https://github.com/yardenshafir\\\">yardenshafir</a> - Yarden Shafir\\n\"\n                L\"    <a href=\\\"https://github.com/winsiderss/systeminformer/graphs/contributors\\\">Contributors</a> - thank you for your additions!\\n\"\n                L\"    Donors - thank you for your support!\\n\\n\"\n                L\"System Informer uses the following components:\\n\"\n                L\"    <a href=\\\"https://github.com/GameTechDev/PresentMon\\\">PresentMon</a> by Intel Corporation\\n\"\n                L\"    <a href=\\\"https://github.com/michaelrsweet/mxml\\\">Mini-XML</a> by Michael Sweet\\n\"\n                L\"    <a href=\\\"https://github.com/PCRE2Project/pcre2\\\">PCRE2</a> by Philip Hazel\\n\"\n                L\"    <a href=\\\"https://github.com/json-c/json-c\\\">json-c</a> by Michael Clark\\n\"\n                L\"    MD5 code by Jouni Malinen\\n\"\n                L\"    SHA1 code by Filip Navara, based on code by Steve Reid\\n\"\n                );\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));\n            PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhUnregisterWindowCallback(hwndDlg);\n            PhUnregisterDialog(PhAboutWindowHandle);\n            PhAboutWindowHandle = NULL;\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                DestroyWindow(hwndDlg);\n                break;\n            case IDC_DIAGNOSTICS:\n                {\n                    PhShowInformationDialog(hwndDlg, PH_AUTO_T(PH_STRING, PhGetDiagnosticsString())->Buffer, 0);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case NM_CLICK:\n                {\n                    switch (header->idFrom)\n                    {\n                    case IDC_ABOUT_NAME:\n                    case IDC_CREDITS:\n                    case IDC_LINK_SF:\n                        PhShellExecute(hwndDlg, ((PNMLINK)header)->item.szUrl, NULL);\n                        break;\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhShowAboutDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    if (!PhAboutWindowHandle)\n    {\n        PhAboutWindowHandle = PhCreateDialog(\n            PhInstanceHandle,\n            MAKEINTRESOURCE(IDD_ABOUT),\n            PhCsForceNoParent ? NULL : ParentWindowHandle,\n            PhpAboutDlgProc,\n            NULL\n            );\n        PhRegisterDialog(PhAboutWindowHandle);\n        ShowWindow(PhAboutWindowHandle, SW_SHOW);\n    }\n\n    if (IsMinimized(PhAboutWindowHandle))\n        ShowWindow(PhAboutWindowHandle, SW_RESTORE);\n    else\n        SetForegroundWindow(PhAboutWindowHandle);\n}\n\nFORCEINLINE ULONG PhpGetObjectTypeObjectCount(\n    _In_ PPH_OBJECT_TYPE ObjectType\n    )\n{\n    PH_OBJECT_TYPE_INFORMATION info;\n\n    memset(&info, 0, sizeof(PH_OBJECT_TYPE_INFORMATION));\n    if (ObjectType) PhGetObjectTypeInformation(ObjectType, &info);\n\n    return info.NumberOfObjects;\n}\n\nPPH_STRING PhGetDiagnosticsString(\n    VOID\n    )\n{\n    PPH_STRING versionString;\n    PH_STRING_BUILDER stringBuilder;\n\n    PhInitializeStringBuilder(&stringBuilder, 50);\n\n    versionString = PhGetApplicationVersionString(FALSE);\n    PhAppendStringBuilder(&stringBuilder, &versionString->sr);\n    PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    PhDereferenceObject(versionString);\n\n    PhAppendStringBuilder2(&stringBuilder, L\"OBJECT INFORMATION\\r\\n\");\n\n#define OBJECT_TYPE_COUNT(Type) PhAppendFormatStringBuilder(&stringBuilder, \\\n    TEXT(#Type) L\": %lu objects\\r\\n\", PhpGetObjectTypeObjectCount(Type))\n\n    // ref\n    OBJECT_TYPE_COUNT(PhObjectTypeObject);\n\n    // basesup\n    OBJECT_TYPE_COUNT(PhStringType);\n    OBJECT_TYPE_COUNT(PhBytesType);\n    OBJECT_TYPE_COUNT(PhListType);\n    OBJECT_TYPE_COUNT(PhPointerListType);\n    OBJECT_TYPE_COUNT(PhHashtableType);\n    OBJECT_TYPE_COUNT(PhFileStreamType);\n\n    // ph\n    OBJECT_TYPE_COUNT(PhSymbolProviderType);\n    OBJECT_TYPE_COUNT(PhProcessItemType);\n    OBJECT_TYPE_COUNT(PhServiceItemType);\n    OBJECT_TYPE_COUNT(PhNetworkItemType);\n    OBJECT_TYPE_COUNT(PhModuleProviderType);\n    OBJECT_TYPE_COUNT(PhModuleItemType);\n    OBJECT_TYPE_COUNT(PhThreadProviderType);\n    OBJECT_TYPE_COUNT(PhThreadItemType);\n    OBJECT_TYPE_COUNT(PhHandleProviderType);\n    OBJECT_TYPE_COUNT(PhHandleItemType);\n    OBJECT_TYPE_COUNT(PhMemoryItemType);\n    OBJECT_TYPE_COUNT(PhImageListItemType);\n\n#ifdef DEBUG\n    PhAppendStringBuilder2(&stringBuilder, L\"STATISTIC INFORMATION\\r\\n\");\n\n#define PRINT_STATISTIC(Name) PhAppendFormatStringBuilder(&stringBuilder, \\\n    TEXT(#Name) L\": %u\\r\\n\", PhLibStatisticsBlock.Name)\n\n    PRINT_STATISTIC(BaseThreadsCreated);\n    PRINT_STATISTIC(BaseThreadsCreateFailed);\n    PRINT_STATISTIC(BaseStringBuildersCreated);\n    PRINT_STATISTIC(BaseStringBuildersResized);\n    PRINT_STATISTIC(RefObjectsCreated);\n    PRINT_STATISTIC(RefObjectsDestroyed);\n    PRINT_STATISTIC(RefObjectsAllocated);\n    PRINT_STATISTIC(RefObjectsFreed);\n    PRINT_STATISTIC(RefObjectsAllocatedFromSmallFreeList);\n    PRINT_STATISTIC(RefObjectsFreedToSmallFreeList);\n    PRINT_STATISTIC(RefObjectsAllocatedFromTypeFreeList);\n    PRINT_STATISTIC(RefObjectsFreedToTypeFreeList);\n    PRINT_STATISTIC(RefObjectsDeleteDeferred);\n    PRINT_STATISTIC(RefAutoPoolsCreated);\n    PRINT_STATISTIC(RefAutoPoolsDestroyed);\n    PRINT_STATISTIC(RefAutoPoolsDynamicAllocated);\n    PRINT_STATISTIC(RefAutoPoolsDynamicResized);\n    PRINT_STATISTIC(QlBlockSpins);\n    PRINT_STATISTIC(QlBlockWaits);\n    PRINT_STATISTIC(QlAcquireExclusiveBlocks);\n    PRINT_STATISTIC(QlAcquireSharedBlocks);\n    PRINT_STATISTIC(WqWorkQueueThreadsCreated);\n    PRINT_STATISTIC(WqWorkQueueThreadsCreateFailed);\n    PRINT_STATISTIC(WqWorkItemsQueued);\n#endif\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nPPH_STRING PhGetApplicationVersionString(\n    _In_ BOOLEAN LinkToCommit\n    )\n{\n    PPH_STRING versionString;\n    PCWSTR channelName = PhGetPhReleaseChannelString();\n    PPH_STRING commitversionString = PhGetPhVersion();\n    PPH_STRING commitHashString = PhGetPhVersionHash();\n\n#if (PHAPP_VERSION_REVISION != 0)\n    if (LinkToCommit)\n    {\n        PH_FORMAT format[8];\n\n        // \"System Informer %lu.%lu.%lu (<a href=\\\"https://github.com/winsiderss/systeminformer/commit/%hs\\\">%hs</a>) %ls\"\n        PhInitFormatS(&format[0], L\"System Informer \");\n        PhInitFormatSR(&format[1], commitversionString->sr);\n        PhInitFormatS(&format[2], L\" (<a href=\\\"https://github.com/winsiderss/systeminformer/commit/\");\n        PhInitFormatSR(&format[3], commitHashString->sr);\n        PhInitFormatS(&format[4], L\"\\\">\");\n        PhInitFormatSR(&format[5], commitHashString->sr);\n        PhInitFormatS(&format[6], L\"</a>) \");\n        PhInitFormatS(&format[7], channelName);\n\n        versionString = PhFormat(format, RTL_NUMBER_OF(format), 0);\n    }\n    else\n    {\n        PH_FORMAT format[6];\n\n        // \"System Informer %lu.%lu.%lu (%hs) %ls\"\n        PhInitFormatS(&format[0], L\"System Informer \");\n        PhInitFormatSR(&format[1], commitversionString->sr);\n        PhInitFormatS(&format[2], L\" (\");\n        PhInitFormatSR(&format[3], commitHashString->sr);\n        PhInitFormatS(&format[4], L\") \");\n        PhInitFormatS(&format[5], channelName);\n\n        versionString = PhFormat(format, RTL_NUMBER_OF(format), 0);\n    }\n#else\n    PH_FORMAT format[4];\n\n    // \"System Informer %lu.%lu %ls\"\n    PhInitFormatS(&format[0], L\"System Informer \");\n    PhInitFormatSR(&format[1], commitversionString->sr);\n    PhInitFormatC(&format[2], L' ');\n    PhInitFormatS(&format[3], channelName);\n\n    versionString = PhFormat(format, RTL_NUMBER_OF(format), 0);\n#endif\n\n    PhClearReference(&commitHashString);\n    PhClearReference(&commitversionString);\n\n    return versionString;\n}\n"
  },
  {
    "path": "SystemInformer/actions.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2024\n *\n */\n\n/*\n * These are a set of consistent functions which will perform actions on objects such as processes,\n * threads and services, while displaying any necessary prompts and error messages. Automatic\n * elevation can also easily be added if necessary.\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <actions.h>\n\n#include <kphuser.h>\n#include <ksisup.h>\n#include <mapldr.h>\n#include <secwmi.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <svcsup.h>\n\n#include <apiimport.h>\n#include <bcd.h>\n#include <emenu.h>\n#include <hndlprv.h>\n#include <memprv.h>\n#include <modprv.h>\n#include <netprv.h>\n#include <phconsole.h>\n#include <phsvccl.h>\n#include <procprv.h>\n#include <srvprv.h>\n#include <thrdprv.h>\n\n#include <winsta.h>\n\nstatic volatile LONG PhSvcReferenceCount = 0;\nstatic PH_PHSVC_MODE PhSvcCurrentMode;\nstatic PH_QUEUED_LOCK PhSvcStartLock = PH_QUEUED_LOCK_INIT;\n\n/**\n * Callback used by elevation Task Dialogs to mark the primary action button\n * as requiring elevation when the dialog is constructed.\n *\n * \\param WindowHandle The handle to the task dialog window.\n * \\param Notification The Task Dialog notification code (e.g. TDN_DIALOG_CONSTRUCTED).\n * \\param wParam Notification-specific word parameter.\n * \\param lParam Notification-specific long parameter.\n * \\param Context Callback context (passed through lpCallbackData).\n * \\return HRESULT S_OK.\n */\nHRESULT CALLBACK PhpElevateActionCallbackProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT Notification,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR Context\n    )\n{\n    switch (Notification)\n    {\n    case TDN_DIALOG_CONSTRUCTED:\n        SendMessage(WindowHandle, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE);\n        break;\n    }\n\n    return S_OK;\n}\n\n/**\n * Display a Task Dialog asking the user to continue with an elevated action.\n *\n * \\param WindowHandle Parent window for the dialog.\n * \\param Message Main instruction text describing the operation requiring elevation.\n * \\param Context Optional callback context passed to the dialog callback.\n * \\param Button Receives the ID of the button pressed by the user when the dialog returns.\n * \\return BOOLEAN TRUE if the dialog was shown and a button value was returned, FALSE otherwise.\n */\n_Success_(return)\nBOOLEAN PhpShowElevatePrompt(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Message,\n    _In_opt_ PVOID Context,\n    _Out_ PLONG Button\n    )\n{\n    TASKDIALOGCONFIG config;\n    CONST TASKDIALOG_BUTTON buttons[1] =\n    {\n        { IDYES, L\"Continue\"}\n    };\n    LONG button;\n\n    // Currently the error dialog box is similar to the one displayed\n    // when you try to label a drive in Windows Explorer. It's much better\n    // than the clunky dialog in PH 1.x.\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.hwndParent = WindowHandle;\n    config.hInstance = NtCurrentImageBase();\n    config.dwFlags = IsWindowVisible(WindowHandle) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainIcon = TD_ERROR_ICON;\n    config.pszMainInstruction = PhaConcatStrings2(Message, L\".\")->Buffer;\n    config.pszContent = L\"You will need to provide administrator permission. \"\n        L\"Click Continue to complete this operation.\";\n    config.dwCommonButtons = TDCBF_CANCEL_BUTTON;\n\n    config.cButtons = 1;\n    config.pButtons = buttons;\n    config.nDefaultButton = IDYES;\n\n    config.pfCallback = PhpElevateActionCallbackProc;\n    config.lpCallbackData = (LONG_PTR)Context;\n\n    if (PhShowTaskDialog(\n        &config,\n        &button,\n        NULL,\n        NULL\n        ))\n    {\n        *Button = button;\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\n/**\n * Shows an error, prompts for elevation, and executes a command.\n *\n * \\param WindowHandle The window to display user interface components on.\n * \\param Connected A variable which receives TRUE if the elevated\n * action succeeded or FALSE if the action failed.\n * \\return TRUE if the user was prompted for elevation, otherwise\n * FALSE, in which case you need to show your own error message.\n */\n_Success_(return)\nBOOLEAN PhpElevationLevelAndConnectToPhSvc(\n    _In_ HWND WindowHandle,\n    _Out_ PBOOLEAN Connected\n    )\n{\n    PH_ACTION_ELEVATION_LEVEL elevationLevel;\n\n    *Connected = FALSE;\n\n    if (PhGetOwnTokenAttributes().Elevated)\n        return FALSE;\n\n    elevationLevel = PhGetIntegerSetting(SETTING_ELEVATION_LEVEL);\n\n    if (elevationLevel == NeverElevateAction)\n        return FALSE;\n\n    // Try to connect now so we can avoid prompting the user.\n    if (PhUiConnectToPhSvc(WindowHandle, TRUE))\n    {\n        *Connected = TRUE;\n        return TRUE;\n    }\n\n    if (\n        elevationLevel == PromptElevateAction ||\n        elevationLevel == AlwaysElevateAction\n        )\n    {\n        *Connected = PhUiConnectToPhSvc(WindowHandle, FALSE);\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Shows an error, prompts for elevation, and connects to phsvc.\n *\n * \\param WindowHandle The window to display user interface components on.\n * \\param Message A message describing the operation that failed.\n * \\param Status A NTSTATUS value.\n * \\param Connected A variable which receives TRUE if the user\n * elevated the action and phsvc was started, or FALSE if the user\n * cancelled elevation. If the value is TRUE, you need to\n * perform any necessary phsvc calls and use PhUiDisconnectFromPhSvc()\n * to disconnect from phsvc.\n * \\param Cancelled A variable which receives TRUE if the user cancelled\n * the action and phsvc was started.\n *\n * \\return TRUE if the user was prompted for elevation, otherwise\n * FALSE, in which case you need to show your own error message.\n */\nBOOLEAN PhpShowErrorAndConnectToPhSvc(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Message,\n    _In_ NTSTATUS Status,\n    _Out_ PBOOLEAN Connected,\n    _Out_ PBOOLEAN Cancelled\n    )\n{\n    PH_ACTION_ELEVATION_LEVEL elevationLevel;\n    LONG button = IDNO;\n\n    *Connected = FALSE;\n    *Cancelled = FALSE;\n\n    if (!(Status == STATUS_ACCESS_DENIED || Status == STATUS_PRIVILEGE_NOT_HELD))\n        return FALSE;\n\n    if (PhGetOwnTokenAttributes().Elevated)\n        return FALSE;\n\n    elevationLevel = PhGetIntegerSetting(SETTING_ELEVATION_LEVEL);\n\n    if (elevationLevel == NeverElevateAction)\n        return FALSE;\n\n    // Try to connect now so we can avoid prompting the user.\n    if (PhUiConnectToPhSvc(WindowHandle, TRUE))\n    {\n        *Connected = TRUE;\n        return TRUE;\n    }\n\n    if (elevationLevel == PromptElevateAction)\n    {\n        if (!PhpShowElevatePrompt(WindowHandle, Message, NULL, &button))\n            return FALSE;\n    }\n\n    if (elevationLevel == AlwaysElevateAction || button == IDYES)\n    {\n        *Connected = PhUiConnectToPhSvc(WindowHandle, FALSE);\n        return TRUE;\n    }\n\n    if (button == IDCANCEL)\n    {\n        *Cancelled = TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Connects to phsvc.\n *\n * \\param WindowHandle The window to display user interface components on.\n * \\param ConnectOnly TRUE to only try to connect to phsvc, otherwise\n * FALSE to try to elevate and start phsvc if the initial connection\n * attempt failed.\n */\nBOOLEAN PhUiConnectToPhSvc(\n    _In_opt_ HWND WindowHandle,\n    _In_ BOOLEAN ConnectOnly\n    )\n{\n    return PhUiConnectToPhSvcEx(WindowHandle, ElevatedPhSvcMode, ConnectOnly);\n}\n\n/**\n * Get the LPC/ALPC port name for the phsvc instance corresponding to the requested mode.\n *\n * \\param Mode The phsvc mode for which the port name is required.\n * \\param PortName Receives the UNICODE_STRING for the port name.\n * \\note Raises STATUS_INVALID_PARAMETER for unknown modes.\n */\nVOID PhpGetPhSvcPortName(\n    _In_ PH_PHSVC_MODE Mode,\n    _Out_ PUNICODE_STRING PortName\n    )\n{\n    switch (Mode)\n    {\n    case ElevatedPhSvcMode:\n        if (!PhIsExecutingInWow64())\n            RtlInitUnicodeString(PortName, PHSVC_PORT_NAME);\n        else\n            RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME);\n        break;\n    case Wow64PhSvcMode:\n        RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME);\n        break;\n    default:\n        PhRaiseStatus(STATUS_INVALID_PARAMETER);\n        break;\n    }\n}\n\n/**\n * Attempt to start the phsvc helper process for the specified mode.\n *\n * \\param WindowHandle Optional parent window for elevation UI created by ShellExecute.\n * \\param Mode The phsvc mode to start (ElevatedPhSvcMode or Wow64PhSvcMode).\n * \\return BOOLEAN TRUE on success (an attempt to start phsvc was made and succeeded), FALSE otherwise.\n */\nBOOLEAN PhpStartPhSvcProcess(\n    _In_opt_ HWND WindowHandle,\n    _In_ PH_PHSVC_MODE Mode\n    )\n{\n    switch (Mode)\n    {\n    case ElevatedPhSvcMode:\n        if (NT_SUCCESS(PhShellProcessHacker(\n            WindowHandle,\n            L\"-phsvc\",\n            SW_HIDE,\n            PH_SHELL_EXECUTE_ADMIN,\n            0,\n            0,\n            NULL\n            )))\n        {\n            return TRUE;\n        }\n\n        break;\n    case Wow64PhSvcMode:\n        {\n            static CONST PH_STRINGREF relativeFileNames[] =\n            {\n                PH_STRINGREF_INIT(L\"\\\\x86\\\\\"),\n#ifdef DEBUG\n                PH_STRINGREF_INIT(L\"\\\\..\\\\Debug32\\\\\"),\n                PH_STRINGREF_INIT(L\"\\\\..\\\\Release32\\\\\")\n#endif\n            };\n            ULONG i;\n            PPH_STRING applicationDirectory;\n            PPH_STRING applicationFileName;\n\n            if (!(applicationDirectory = PhGetApplicationDirectoryWin32()))\n                return FALSE;\n            if (!(applicationFileName = PhGetApplicationFileNameWin32()))\n                return FALSE;\n\n            PhMoveReference(&applicationFileName, PhGetBaseName(applicationFileName));\n\n            for (i = 0; i < RTL_NUMBER_OF(relativeFileNames); i++)\n            {\n                PPH_STRING fileName;\n                PPH_STRING fileFullPath;\n\n                fileName = PhConcatStringRef3(\n                    &applicationDirectory->sr,\n                    &relativeFileNames[i],\n                    &applicationFileName->sr\n                    );\n\n                if (NT_SUCCESS(PhGetFullPath(PhGetString(fileName), &fileFullPath, NULL)))\n                {\n                    PhMoveReference(&fileName, fileFullPath);\n                }\n\n                if (PhDoesFileExistWin32(PhGetString(fileName)))\n                {\n                    if (NT_SUCCESS(PhShellProcessHackerEx(\n                        WindowHandle,\n                        PhGetString(fileName),\n                        L\"-phsvc\",\n                        SW_HIDE,\n                        PH_SHELL_EXECUTE_DEFAULT,\n                        0,\n                        0,\n                        NULL\n                        )))\n                    {\n                        PhDereferenceObject(fileName);\n                        PhDereferenceObject(applicationFileName);\n                        PhDereferenceObject(applicationDirectory);\n                        return TRUE;\n                    }\n                }\n\n                PhDereferenceObject(fileName);\n            }\n\n            PhDereferenceObject(applicationFileName);\n            PhDereferenceObject(applicationDirectory);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n * Connects to phsvc.\n *\n * \\param WindowHandle The window to display user interface components on.\n * \\param Mode The type of phsvc instance to connect to.\n * \\param ConnectOnly TRUE to only try to connect to phsvc, otherwise\n * FALSE to try to elevate and start phsvc if the initial connection\n * attempt failed.\n */\nBOOLEAN PhUiConnectToPhSvcEx(\n    _In_opt_ HWND WindowHandle,\n    _In_ PH_PHSVC_MODE Mode,\n    _In_ BOOLEAN ConnectOnly\n    )\n{\n    NTSTATUS status;\n    BOOLEAN started;\n    UNICODE_STRING portName;\n\n    if (_InterlockedIncrementNoZero(&PhSvcReferenceCount))\n    {\n        if (PhSvcCurrentMode == Mode)\n        {\n            started = TRUE;\n        }\n        else\n        {\n            _InterlockedDecrement(&PhSvcReferenceCount);\n            started = FALSE;\n        }\n    }\n    else\n    {\n        PhAcquireQueuedLockExclusive(&PhSvcStartLock);\n\n        if (_InterlockedExchange(&PhSvcReferenceCount, 0) == 0)\n        {\n            started = FALSE;\n            PhpGetPhSvcPortName(Mode, &portName);\n\n            // Try to connect first, then start the server if we failed.\n            status = PhSvcConnectToServer(&portName, 0);\n\n            if (NT_SUCCESS(status))\n            {\n                started = TRUE;\n                PhSvcCurrentMode = Mode;\n                _InterlockedIncrement(&PhSvcReferenceCount);\n            }\n            else if (!ConnectOnly)\n            {\n                // Prompt for elevation, and then try to connect to the server.\n\n                if (PhpStartPhSvcProcess(WindowHandle, Mode))\n                    started = TRUE;\n\n                if (started)\n                {\n                    ULONG attempts = 10;\n\n                    // Try to connect several times because the server may take\n                    // a while to initialize.\n                    do\n                    {\n                        status = PhSvcConnectToServer(&portName, 0);\n\n                        if (NT_SUCCESS(status))\n                            break;\n\n                        PhDelayExecution(1000);\n\n                    } while (--attempts != 0);\n\n                    // Increment the reference count even if we failed.\n                    // We don't want to prompt the user again.\n\n                    PhSvcCurrentMode = Mode;\n                    _InterlockedIncrement(&PhSvcReferenceCount);\n                }\n            }\n        }\n        else\n        {\n            if (PhSvcCurrentMode == Mode)\n            {\n                started = TRUE;\n                _InterlockedIncrement(&PhSvcReferenceCount);\n            }\n            else\n            {\n                started = FALSE;\n            }\n        }\n\n        PhReleaseQueuedLockExclusive(&PhSvcStartLock);\n    }\n\n    return started;\n}\n\n/**\n * Disconnects from phsvc.\n */\nVOID PhUiDisconnectFromPhSvc(\n    VOID\n    )\n{\n    PhAcquireQueuedLockExclusive(&PhSvcStartLock);\n\n    if (_InterlockedDecrement(&PhSvcReferenceCount) == 0)\n    {\n        PhSvcDisconnectFromServer();\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSvcStartLock);\n}\n\n/**\n * Locks the current workstation.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\return BOOLEAN TRUE on success, FALSE on failure (and an error UI is shown).\n */\nBOOLEAN PhUiLockComputer(\n    _In_ HWND WindowHandle\n    )\n{\n    if (LockWorkStation())\n        return TRUE;\n    else\n        PhShowStatus(WindowHandle, L\"Unable to lock the computer.\", 0, PhGetLastError());\n\n    return FALSE;\n}\n\n/**\n * Log the current user off.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\return BOOLEAN TRUE on success, FALSE on failure (and an error UI is shown).\n */\nBOOLEAN PhUiLogoffComputer(\n    _In_ HWND WindowHandle\n    )\n{\n    if (ExitWindowsEx(EWX_LOGOFF, 0))\n        return TRUE;\n    else\n        PhShowStatus(WindowHandle, L\"Unable to log off the computer.\", 0, PhGetLastError());\n\n    return FALSE;\n}\n\n/**\n * Put the system into sleep (standby) state.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\return BOOLEAN TRUE on success, FALSE on failure (and an error UI is shown).\n */\nBOOLEAN PhUiSleepComputer(\n    _In_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n\n    if (NT_SUCCESS(status = NtInitiatePowerAction(\n        PowerActionSleep,\n        PowerSystemSleeping1,\n        0,\n        FALSE\n        )))\n        return TRUE;\n    else\n        PhShowStatus(WindowHandle, L\"Unable to sleep the computer.\", status, 0);\n\n    return FALSE;\n}\n\n/**\n * Put the system into hibernate state.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\return BOOLEAN TRUE on success, FALSE on failure (and an error UI is shown).\n */\nBOOLEAN PhUiHibernateComputer(\n    _In_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n\n    if (NT_SUCCESS(status = NtInitiatePowerAction(\n        PowerActionHibernate,\n        PowerSystemSleeping1,\n        0,\n        FALSE\n        )))\n        return TRUE;\n    else\n        PhShowStatus(WindowHandle, L\"Unable to hibernate the computer.\", status, 0);\n\n    return FALSE;\n}\n\n/**\n * Restart the computer using the specified power action type.\n *\n * \\param WindowHandle Parent window used for confirmation and error UI.\n * \\param Action The type of restart to perform (PH_POWERACTION_TYPE_*).\n * \\param Flags Additional flags passed to PhInitiateShutdown for Win32 restart.\n * \\return BOOLEAN TRUE if the restart action was initiated, FALSE otherwise.\n */\nBOOLEAN PhUiRestartComputer(\n    _In_ HWND WindowHandle,\n    _In_ PH_POWERACTION_TYPE Action,\n    _In_ ULONG Flags\n    )\n{\n    switch (Action)\n    {\n    case PH_POWERACTION_TYPE_WIN32:\n        {\n            if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                WindowHandle,\n                L\"restart\",\n                L\"the computer\",\n                NULL,\n                FALSE\n                ))\n            {\n                ULONG status = PhInitiateShutdown(PH_SHUTDOWN_RESTART | Flags);\n\n                if (status == ERROR_SUCCESS)\n                    return TRUE;\n\n                PhShowStatus(WindowHandle, L\"Unable to restart the computer.\", 0, status);\n\n                //if (ExitWindowsEx(EWX_REBOOT | EWX_BOOTOPTIONS, 0))\n                //    return TRUE;\n                //else\n                //    PhShowStatus(WindowHandle, L\"Unable to restart the computer.\", 0, GetLastError());\n            }\n        }\n        break;\n    case PH_POWERACTION_TYPE_NATIVE:\n        {\n            PPH_STRING messageText;\n\n            messageText = PhaFormatString(\n                L\"This option %s %s in a disorderly manner and may cause file corruption or system instability.\",\n                L\"performs a hard\",\n                L\"restart\");\n\n            // Ignore the EnableWarnings preference and always show the warning prompt. (dmex)\n            if (PhShowConfirmMessage(\n                WindowHandle,\n                L\"restart\",\n                L\"the computer\",\n                messageText->Buffer,\n                TRUE\n                ))\n            {\n                NTSTATUS status;\n\n                status = NtShutdownSystem(ShutdownReboot);\n\n                if (NT_SUCCESS(status))\n                    return TRUE;\n\n                PhShowStatus(WindowHandle, L\"Unable to restart the computer.\", status, 0);\n            }\n        }\n        break;\n    case PH_POWERACTION_TYPE_CRITICAL:\n        {\n            PPH_STRING messageText;\n\n            messageText = PhaFormatString(\n                L\"This option %s %s in an disorderly manner and may cause corrupted files or instability in the system.\",\n                L\"forces a critical\",\n                L\"restart\");\n\n            // Ignore the EnableWarnings preference and always show the warning prompt. (dmex)\n            if (PhShowConfirmMessage(\n                WindowHandle,\n                L\"restart\",\n                L\"the computer\",\n                messageText->Buffer,\n                TRUE\n                ))\n            {\n                NTSTATUS status;\n\n                status = NtSetSystemPowerState(\n                    PowerActionShutdownReset,\n                    PowerSystemShutdown,\n                    POWER_ACTION_CRITICAL\n                    );\n                //status = NtInitiatePowerAction(\n                //    PowerActionShutdownReset,\n                //    PowerSystemShutdown,\n                //    POWER_ACTION_CRITICAL,\n                //    FALSE\n                //    );\n\n                if (NT_SUCCESS(status))\n                    return TRUE;\n\n                PhShowStatus(WindowHandle, L\"Unable to restart the computer.\", status, 0);\n            }\n        }\n        break;\n    case PH_POWERACTION_TYPE_ADVANCEDBOOT:\n        {\n            if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                WindowHandle,\n                L\"restart\",\n                L\"the computer\",\n                NULL,\n                FALSE\n                ))\n            {\n                NTSTATUS status;\n\n                status = PhBcdSetAdvancedOptionsOneTime(\n                    TRUE\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    status = PhInitiateShutdown(PH_SHUTDOWN_RESTART);\n\n                    if (status == ERROR_SUCCESS)\n                        return TRUE;\n\n                    PhShowStatus(WindowHandle, L\"Unable to configure the advanced boot options.\", 0, status);\n                }\n                else\n                {\n                    PhShowStatus(WindowHandle, L\"Unable to configure the advanced boot options.\", status, 0);\n                }\n            }\n        }\n        break;\n    case PH_POWERACTION_TYPE_FIRMWAREBOOT:\n        {\n            if (!PhGetOwnTokenAttributes().Elevated)\n            {\n                PhShowMessage2(\n                    WindowHandle,\n                    TD_OK_BUTTON,\n                    TD_ERROR_ICON,\n                    L\"Unable to restart to firmware options.\",\n                    L\"Make sure System Informer is running with administrative privileges.\"\n                    );\n                break;\n            }\n\n            if (!NT_SUCCESS(PhAdjustPrivilege(NULL, SE_SYSTEM_ENVIRONMENT_PRIVILEGE, TRUE)))\n            {\n                PhShowMessage2(\n                    WindowHandle,\n                    TD_OK_BUTTON,\n                    TD_ERROR_ICON,\n                    L\"Unable to restart to firmware options.\",\n                    L\"Make sure System Informer is running with administrative privileges.\"\n                    );\n                break;\n            }\n\n            if (!PhIsFirmwareSupported())\n            {\n                PhShowMessage2(\n                    WindowHandle,\n                    TD_OK_BUTTON,\n                    TD_ERROR_ICON,\n                    L\"Unable to restart to firmware options.\",\n                    L\"This machine does not have UEFI support.\"\n                    );\n                break;\n            }\n\n            if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                WindowHandle,\n                L\"restart\",\n                L\"the computer\",\n                NULL,\n                FALSE\n                ))\n            {\n                NTSTATUS status;\n\n                status = PhSetSystemEnvironmentBootToFirmware();\n\n                if (NT_SUCCESS(status))\n                {\n                    status = PhInitiateShutdown(PH_SHUTDOWN_RESTART);\n\n                    if (status == ERROR_SUCCESS)\n                        return TRUE;\n\n                    PhShowStatus(WindowHandle, L\"Unable to restart the computer.\", 0, status);\n                }\n                else\n                {\n                    PhShowStatus(WindowHandle, L\"Unable to restart the computer.\", status, 0);\n                }\n            }\n        }\n        break;\n    case PH_POWERACTION_TYPE_UPDATE:\n        {\n            if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                WindowHandle,\n                L\"update and restart\",\n                L\"the computer\",\n                NULL,\n                FALSE\n                ))\n            {\n                ULONG status = PhInitiateShutdown(PH_SHUTDOWN_RESTART | PH_SHUTDOWN_INSTALL_UPDATES);\n\n                if (status == ERROR_SUCCESS)\n                    return TRUE;\n\n                PhShowStatus(WindowHandle, L\"Unable to restart the computer.\", 0, status);\n            }\n        }\n        break;\n    case PH_POWERACTION_TYPE_WDOSCAN:\n        {\n            if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                WindowHandle,\n                L\"restart\",\n                L\"the computer for Windows Defender Offline Scan\",\n                NULL,\n                FALSE\n                ))\n            {\n                HRESULT status = PhRestartDefenderOfflineScan();\n\n                if (status == S_OK)\n                    return TRUE;\n\n                if ((status & 0xFFFF0000) == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, 0))\n                {\n                    PhShowStatus(WindowHandle, L\"Unable to restart the computer.\", 0, HRESULT_CODE(status));\n                }\n                else\n                {\n                    PhShowStatus(WindowHandle, L\"Unable to restart the computer.\", STATUS_UNSUCCESSFUL, 0);\n                }\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n * Shutdown the computer using the specified power action type.\n *\n * \\param WindowHandle Parent window used for confirmation and error UI.\n * \\param Action The type of shutdown to perform (PH_POWERACTION_TYPE_*).\n * \\param Flags Additional flags passed to PhInitiateShutdown for Win32 shutdown.\n * \\return BOOLEAN TRUE if the shutdown action was initiated, FALSE otherwise.\n */\nBOOLEAN PhUiShutdownComputer(\n    _In_ HWND WindowHandle,\n    _In_ PH_POWERACTION_TYPE Action,\n    _In_ ULONG Flags\n    )\n{\n    switch (Action)\n    {\n    case PH_POWERACTION_TYPE_WIN32:\n        {\n            if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                WindowHandle,\n                L\"shut down\",\n                L\"the computer\",\n                NULL,\n                FALSE\n                ))\n            {\n                ULONG status = PhInitiateShutdown(PH_SHUTDOWN_POWEROFF | Flags);\n\n                if (status == ERROR_SUCCESS)\n                    return TRUE;\n\n                PhShowStatus(WindowHandle, L\"Unable to shut down the computer.\", 0, status);\n\n                //if (ExitWindowsEx(EWX_POWEROFF | EWX_HYBRID_SHUTDOWN, 0))\n                //    return TRUE;\n                //else if (ExitWindowsEx(EWX_SHUTDOWN | EWX_HYBRID_SHUTDOWN, 0))\n                //    return TRUE;\n                //else\n                //    PhShowStatus(WindowHandle, L\"Unable to shut down the computer.\", 0, GetLastError());\n            }\n        }\n        break;\n    case PH_POWERACTION_TYPE_NATIVE:\n        {\n            PPH_STRING messageText;\n\n            messageText = PhaFormatString(\n                L\"This option %s %s in an disorderly manner and may cause corrupted files or instability in the system.\",\n                L\"performs a hard\",\n                L\"shut down\");\n\n            // Ignore the EnableWarnings preference and always show the warning prompt. (dmex)\n            if (PhShowConfirmMessage(\n                WindowHandle,\n                L\"shut down\",\n                L\"the computer\",\n                messageText->Buffer,\n                TRUE\n                ))\n            {\n                NTSTATUS status;\n\n                status = NtShutdownSystem(ShutdownPowerOff);\n\n                if (NT_SUCCESS(status))\n                    return TRUE;\n\n                PhShowStatus(WindowHandle, L\"Unable to shut down the computer.\", status, 0);\n            }\n        }\n        break;\n    case PH_POWERACTION_TYPE_CRITICAL:\n        {\n            PPH_STRING messageText;\n\n            messageText = PhaFormatString(\n                L\"This option %s %s in an disorderly manner and may cause corrupted files or instability in the system.\",\n                L\"forces a critical\",\n                L\"shut down\");\n\n            // Ignore the EnableWarnings preference and always show the warning prompt. (dmex)\n            if (PhShowConfirmMessage(\n                WindowHandle,\n                L\"shut down\",\n                L\"the computer\",\n                messageText->Buffer,\n                TRUE\n                ))\n            {\n                NTSTATUS status;\n\n                status = NtSetSystemPowerState(\n                    PowerActionShutdownOff,\n                    PowerSystemShutdown,\n                    POWER_ACTION_CRITICAL\n                    );\n                //status = NtInitiatePowerAction(\n                //    PowerActionShutdownReset,\n                //    PowerSystemShutdown,\n                //    POWER_ACTION_CRITICAL,\n                //    FALSE\n                //    );\n\n                if (NT_SUCCESS(status))\n                    return TRUE;\n\n                PhShowStatus(WindowHandle, L\"Unable to shut down the computer.\", status, 0);\n            }\n        }\n        break;\n    case PH_POWERACTION_TYPE_UPDATE:\n        {\n            if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                WindowHandle,\n                L\"update and shutdown\",\n                L\"the computer\",\n                NULL,\n                FALSE\n                ))\n            {\n                ULONG status = PhInitiateShutdown(PH_SHUTDOWN_POWEROFF | PH_SHUTDOWN_INSTALL_UPDATES);\n\n                if (status == ERROR_SUCCESS)\n                    return TRUE;\n\n                PhShowStatus(WindowHandle, L\"Unable to shut down the computer.\", 0, status);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n * Build a dynamic menu listing boot applications (one-time boot entries).\n *\n * \\param DelayLoadMenu If TRUE, the function will create a placeholder menu item\n * and delay enumerating boot applications until the menu is opened.\n * \\return PVOID A menu item object (owner-managed); may be disabled if the caller lacks privileges.\n */\nPVOID PhUiCreateComputerBootDeviceMenu(\n    _In_ BOOLEAN DelayLoadMenu\n    )\n{\n    PPH_EMENU_ITEM menuItem;\n    PPH_LIST bootApplicationList;\n\n    menuItem = PhCreateEMenuItem(PH_EMENU_DISABLED, ID_COMPUTER_RESTARTBOOTDEVICE, L\"Restart to boot application\", NULL, NULL);\n\n    if (!PhGetOwnTokenAttributes().Elevated)\n        return menuItem;\n\n    if (!DelayLoadMenu)\n    {\n        BOOLEAN bootEnumerateAllObjects = !!PhGetIntegerSetting(SETTING_ENABLE_BOOT_OBJECTS_ENUMERATE);\n\n        if (bootApplicationList = PhBcdQueryBootApplicationList(bootEnumerateAllObjects))\n        {\n            for (ULONG i = 0; i < bootApplicationList->Count; i++)\n            {\n                PPH_BCD_OBJECT_LIST entry = bootApplicationList->Items[i];\n                PPH_EMENU_ITEM menuItemNew;\n\n                menuItemNew = PhCreateEMenuItem(\n                    PH_EMENU_TEXT_OWNED,\n                    ID_COMPUTER_RESTARTBOOTDEVICE,\n                    PhAllocateCopy(entry->ObjectName->Buffer, entry->ObjectName->Length + sizeof(UNICODE_NULL)),\n                    NULL,\n                    UlongToPtr(i)\n                    );\n\n                PhInsertEMenuItem(menuItem, menuItemNew, ULONG_MAX);\n            }\n\n            if (bootApplicationList->Count)\n                PhSetEnabledEMenuItem(menuItem, TRUE);\n\n            PhBcdDestroyBootApplicationList(bootApplicationList);\n        }\n    }\n\n    return menuItem;\n}\n\n/**\n * Build a dynamic menu listing firmware boot applications (UEFI).\n *\n * \\param DelayLoadMenu If TRUE, the function will create a placeholder menu item\n * and delay enumerating firmware applications until the menu is opened.\n * \\return PVOID A menu item object (owner-managed); may be disabled if the caller lacks privileges.\n */\nPVOID PhUiCreateComputerFirmwareDeviceMenu(\n    _In_ BOOLEAN DelayLoadMenu\n    )\n{\n    PPH_EMENU_ITEM menuItem;\n    PPH_LIST firmwareApplicationList;\n\n    menuItem = PhCreateEMenuItem(PH_EMENU_DISABLED, ID_COMPUTER_RESTARTFWDEVICE, L\"Restart to firmware application\", NULL, NULL);\n\n    if (!PhGetOwnTokenAttributes().Elevated)\n        return menuItem;\n\n    if (!DelayLoadMenu)\n    {\n        if (firmwareApplicationList = PhBcdQueryFirmwareBootApplicationList())\n        {\n            for (ULONG i = 0; i < firmwareApplicationList->Count; i++)\n            {\n                PPH_BCD_OBJECT_LIST entry = firmwareApplicationList->Items[i];\n                PPH_EMENU_ITEM menuItemNew;\n\n                menuItemNew = PhCreateEMenuItem(\n                    PH_EMENU_TEXT_OWNED,\n                    ID_COMPUTER_RESTARTFWDEVICE,\n                    PhAllocateCopy(entry->ObjectName->Buffer, entry->ObjectName->Length + sizeof(UNICODE_NULL)),\n                    NULL,\n                    UlongToPtr(i)\n                    );\n\n                PhInsertEMenuItem(menuItem, menuItemNew, ULONG_MAX);\n            }\n\n            if (firmwareApplicationList->Count)\n                PhSetEnabledEMenuItem(menuItem, TRUE);\n\n            PhBcdDestroyBootApplicationList(firmwareApplicationList);\n        }\n    }\n\n    return menuItem;\n}\n\n/**\n * Handle selection of a boot application menu entry by configuring a one-time boot entry\n * and initiating a restart if the operation succeeded.\n *\n * \\param WindowHandle Parent window for confirmation and error dialogs.\n * \\param MenuIndex Index of the selected boot application as returned from the created menu.\n */\nVOID PhUiHandleComputerBootApplicationMenu(\n    _In_ HWND WindowHandle,\n    _In_ ULONG MenuIndex\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    BOOLEAN bootEnumerateAllObjects;\n    BOOLEAN bootUpdateFwBootObjects;\n    PPH_LIST bootApplicationList;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) && !PhShowConfirmMessage(\n        WindowHandle,\n        L\"restart\",\n        L\"the computer\",\n        NULL,\n        FALSE\n        ))\n    {\n        return;\n    }\n\n    bootEnumerateAllObjects = !!PhGetIntegerSetting(SETTING_ENABLE_BOOT_OBJECTS_ENUMERATE);\n    bootUpdateFwBootObjects = !!PhGetIntegerSetting(SETTING_ENABLE_UPDATE_DEFAULT_FIRMWARE_BOOT_ENTRY);\n\n    if (bootApplicationList = PhBcdQueryBootApplicationList(bootEnumerateAllObjects))\n    {\n        if (MenuIndex < bootApplicationList->Count)\n        {\n            PPH_BCD_OBJECT_LIST entry = bootApplicationList->Items[MenuIndex];\n\n            status = PhBcdSetBootApplicationOneTime(&entry->ObjectGuid, bootUpdateFwBootObjects);\n        }\n\n        PhBcdDestroyBootApplicationList(bootApplicationList);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhInitiateShutdown(PH_SHUTDOWN_RESTART);\n\n        if (status != ERROR_SUCCESS)\n        {\n            PhShowStatus(WindowHandle, L\"Unable to configure the boot application.\", 0, status);\n        }\n    }\n    else\n    {\n        PhShowStatus(WindowHandle, L\"Unable to configure the boot application.\", status, 0);\n    }\n}\n\n/**\n * Handle selection of a firmware boot application menu entry by configuring a one-time firmware boot\n * entry and initiating a restart if the operation succeeded.\n *\n * \\param WindowHandle Parent window for confirmation and error dialogs.\n * \\param MenuIndex Index of the selected firmware application as returned from the created menu.\n */\nVOID PhUiHandleComputerFirmwareApplicationMenu(\n    _In_ HWND WindowHandle,\n    _In_ ULONG MenuIndex\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    PPH_LIST firmwareApplicationList;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) && !PhShowConfirmMessage(\n        WindowHandle,\n        L\"restart\",\n        L\"the computer\",\n        NULL,\n        FALSE\n        ))\n    {\n        return;\n    }\n\n    if (firmwareApplicationList = PhBcdQueryFirmwareBootApplicationList())\n    {\n        if (MenuIndex < firmwareApplicationList->Count)\n        {\n            PPH_BCD_OBJECT_LIST entry = firmwareApplicationList->Items[MenuIndex];\n\n            status = PhBcdSetFirmwareBootApplicationOneTime(&entry->ObjectGuid);\n        }\n\n        PhBcdDestroyBootApplicationList(firmwareApplicationList);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhInitiateShutdown(PH_SHUTDOWN_RESTART);\n\n        if (status != ERROR_SUCCESS)\n        {\n            PhShowStatus(WindowHandle, L\"Unable to configure the boot application.\", 0, status);\n        }\n    }\n    else\n    {\n        PhShowStatus(WindowHandle, L\"Unable to configure the boot application.\", status, 0);\n    }\n}\n\ntypedef struct _PHP_USERSMENU_ENTRY\n{\n    ULONG SessionId;\n    PPH_STRING UserName;\n} PHP_USERSMENU_ENTRY, *PPHP_USERSMENU_ENTRY;\n\n/**\n * Comparison callback used to sort user session menu entries.\n *\n * \\param Context Unused callback context.\n * \\param elem1 Pointer to the first element to compare.\n * \\param elem2 Pointer to the second element to compare.\n * \\return int <0 if elem1 < elem2, 0 if equal, >0 if elem1 > elem2.\n */\nstatic int __cdecl PhpUsersMainMenuNameCompare(\n    _In_ void* Context,\n    _In_ void const* elem1,\n    _In_ void const* elem2\n    )\n{\n    PPHP_USERSMENU_ENTRY item1 = *(PPHP_USERSMENU_ENTRY*)elem1;\n    PPHP_USERSMENU_ENTRY item2 = *(PPHP_USERSMENU_ENTRY*)elem2;\n\n    return PhCompareString(item1->UserName, item2->UserName, TRUE);\n}\n\n/**\n * Populate the provided users menu item with entries for each active WinStation session.\n *\n * \\param UsersMenuItem Menu object to populate with per-session submenus.\n */\nVOID PhUiCreateSessionMenu(\n    _In_ PVOID UsersMenuItem\n    )\n{\n    PPH_LIST userSessionList;\n    PSESSIONIDW sessions;\n    ULONG numberOfSessions;\n    ULONG i;\n\n    userSessionList = PhCreateList(1);\n\n    if (WinStationEnumerateW(WINSTATION_CURRENT_SERVER, &sessions, &numberOfSessions))\n    {\n        for (i = 0; i < numberOfSessions; i++)\n        {\n            WINSTATIONINFORMATION winStationInfo;\n            ULONG returnLength;\n            SIZE_T formatLength;\n            PH_FORMAT format[5];\n            PH_STRINGREF menuTextSr;\n            WCHAR formatBuffer[0x100];\n\n            if (!WinStationQueryInformationW(\n                WINSTATION_CURRENT_SERVER,\n                sessions[i].SessionId,\n                WinStationInformation,\n                &winStationInfo,\n                sizeof(WINSTATIONINFORMATION),\n                &returnLength\n                ))\n            {\n                winStationInfo.Domain[0] = UNICODE_NULL;\n                winStationInfo.UserName[0] = UNICODE_NULL;\n            }\n\n            if (winStationInfo.Domain[0] == UNICODE_NULL || winStationInfo.UserName[0] == UNICODE_NULL)\n            {\n                // Probably the Services or RDP-Tcp session.\n                continue;\n            }\n\n            PhInitFormatU(&format[0], sessions[i].SessionId);\n            PhInitFormatS(&format[1], L\": \");\n            PhInitFormatS(&format[2], winStationInfo.Domain);\n            PhInitFormatC(&format[3], OBJ_NAME_PATH_SEPARATOR);\n            PhInitFormatS(&format[4], winStationInfo.UserName);\n\n            if (!PhFormatToBuffer(\n                format,\n                RTL_NUMBER_OF(format),\n                formatBuffer,\n                sizeof(formatBuffer),\n                &formatLength\n                ))\n            {\n                continue;\n            }\n\n            menuTextSr.Length = formatLength - sizeof(UNICODE_NULL);\n            menuTextSr.Buffer = formatBuffer;\n\n            {\n                PPHP_USERSMENU_ENTRY entry;\n\n                entry = PhCreateAlloc(sizeof(PHP_USERSMENU_ENTRY));\n                entry->SessionId = sessions[i].SessionId;\n                entry->UserName = PhCreateString2(&menuTextSr);\n\n                PhAddItemList(userSessionList, entry);\n            }\n        }\n\n        WinStationFreeMemory(sessions);\n    }\n\n    // Sort the users. (dmex)\n    qsort_s(userSessionList->Items, userSessionList->Count, sizeof(PVOID), PhpUsersMainMenuNameCompare, NULL);\n\n    // Update the users menu. (dmex)\n    for (i = 0; i < userSessionList->Count; i++)\n    {\n        PPHP_USERSMENU_ENTRY entry;\n        PPH_STRING escapedMenuText;\n        PPH_EMENU_ITEM userMenu;\n\n        entry = userSessionList->Items[i];\n        escapedMenuText = PhEscapeStringForMenuPrefix(&entry->UserName->sr);\n        userMenu = PhCreateEMenuItem(\n            PH_EMENU_TEXT_OWNED,\n            0,\n            PhAllocateCopy(escapedMenuText->Buffer, escapedMenuText->Length + sizeof(UNICODE_NULL)),\n            NULL,\n            UlongToPtr(entry->SessionId)\n            );\n        PhDereferenceObject(escapedMenuText);\n        PhDereferenceObject(entry->UserName);\n\n        PhInsertEMenuItem(userMenu, PhCreateEMenuItem(0, ID_USER_CONNECT, L\"&Connect\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(userMenu, PhCreateEMenuItem(0, ID_USER_DISCONNECT, L\"&Disconnect\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(userMenu, PhCreateEMenuItem(0, ID_USER_LOGOFF, L\"&Logoff\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(userMenu, PhCreateEMenuItem(0, ID_USER_REMOTECONTROL, L\"Rem&ote control\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(userMenu, PhCreateEMenuItem(0, ID_USER_SENDMESSAGE, L\"Send &message...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(userMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(userMenu, PhCreateEMenuItem(0, ID_USER_PROPERTIES, L\"P&roperties\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(UsersMenuItem, userMenu, ULONG_MAX);\n    }\n\n    PhDereferenceObjects(userSessionList->Items, userSessionList->Count);\n    PhDereferenceObject(userSessionList);\n}\n\n/**\n * Connect the current console to a remote/non-current WinStation session. Prompts for a password\n * if an initial attempt without credentials fails.\n *\n * \\param WindowHandle Parent window for password prompts and error UI.\n * \\param SessionId The WinStation session id to connect to.\n * \\return BOOLEAN TRUE on success, FALSE on failure or user cancel.\n */\nBOOLEAN PhUiConnectSession(\n    _In_ HWND WindowHandle,\n    _In_ ULONG SessionId\n    )\n{\n    BOOLEAN success = FALSE;\n    PPH_STRING selectedChoice = NULL;\n    PPH_STRING oldSelectedChoice = NULL;\n\n    // Try once with no password.\n    if (WinStationConnectW(WINSTATION_CURRENT_SERVER, SessionId, LOGONID_CURRENT, L\"\", TRUE))\n        return TRUE;\n\n    while (PhaChoiceDialog(\n        WindowHandle,\n        L\"Connect to session\",\n        L\"Password:\",\n        NULL,\n        0,\n        NULL,\n        PH_CHOICE_DIALOG_PASSWORD,\n        &selectedChoice,\n        NULL,\n        NULL\n        ))\n    {\n        if (oldSelectedChoice)\n        {\n            RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length);\n            PhDereferenceObject(oldSelectedChoice);\n        }\n\n        oldSelectedChoice = selectedChoice;\n\n        if (WinStationConnectW(WINSTATION_CURRENT_SERVER, SessionId, LOGONID_CURRENT, selectedChoice->Buffer, TRUE))\n        {\n            success = TRUE;\n            break;\n        }\n        else\n        {\n            if (!PhShowContinueStatus(WindowHandle, L\"Unable to connect to the session\", 0, GetLastError()))\n                break;\n        }\n    }\n\n    if (oldSelectedChoice)\n    {\n        RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length);\n        PhDereferenceObject(oldSelectedChoice);\n    }\n\n    return success;\n}\n\n/**\n * Disconnect a WinStation session.\n *\n * \\param WindowHandle Parent window for error reporting.\n * \\param SessionId The WinStation session id to disconnect.\n * \\return BOOLEAN TRUE on success, FALSE on failure (and an error UI is shown).\n */\nBOOLEAN PhUiDisconnectSession(\n    _In_ HWND WindowHandle,\n    _In_ ULONG SessionId\n    )\n{\n    if (WinStationDisconnect(WINSTATION_CURRENT_SERVER, SessionId, FALSE))\n        return TRUE;\n    else\n        PhShowStatus(WindowHandle, L\"Unable to disconnect the session\", 0, GetLastError());\n\n    return FALSE;\n}\n\n/**\n * Log off a specific WinStation session after optional confirmation.\n *\n * \\param WindowHandle Parent window for confirmation and error UI.\n * \\param SessionId The WinStation session id to log off.\n * \\return BOOLEAN TRUE on success, FALSE on failure or if the user cancelled.\n */\nBOOLEAN PhUiLogoffSession(\n    _In_ HWND WindowHandle,\n    _In_ ULONG SessionId\n    )\n{\n    if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n        WindowHandle,\n        L\"logoff\",\n        L\"the user\",\n        NULL,\n        FALSE\n        ))\n    {\n        if (WinStationReset(WINSTATION_CURRENT_SERVER, SessionId, FALSE))\n            return TRUE;\n        else\n            PhShowStatus(WindowHandle, L\"Unable to logoff the session\", 0, GetLastError());\n    }\n\n    return FALSE;\n}\n\n/**\n * Determines if a process is a system process.\n *\n * \\param ProcessId The PID of the process to check.\n */\nBOOLEAN PhIsDangerousProcess(\n    _In_ HANDLE ProcessId\n    )\n{\n    static CONST ULONG DangerousProcesses[] =\n    {\n        0x6ccbdb46, // csrss.exe\n        0x5920bffe, // dwm.exe\n        0x8880527b, // logonui.exe\n        0x9fd9b2be, // lsass.exe\n        0xb1c6af0a, // lsm.exe\n        0xaafce8c2, // services.exe\n        0xfe38787e, // smss.exe\n        0x9d662730, // wininit.exe\n        0x2aa5caab, // winlogon.exe\n    };\n    PPH_STRING fileName;\n    ULONG hash;\n\n    if (ProcessId == SYSTEM_PROCESS_ID)\n        return TRUE;\n\n    if (!NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessId, &fileName)))\n        return FALSE;\n\n    PhMoveReference(&fileName, PhGetBaseName(fileName));\n    hash = PhHashStringRefEx(&fileName->sr, TRUE, PH_STRING_HASH_X65599);\n    PhDereferenceObject(fileName);\n\n    for (ULONG i = 0; i < RTL_NUMBER_OF(DangerousProcesses); i++)\n    {\n        if (hash == DangerousProcesses[i])\n            return TRUE;\n    }\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_IS_DANGEROUS_PROCESS processInfo;\n\n        processInfo.ProcessId = ProcessId;\n        processInfo.DangerousProcess = FALSE;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackDangerousProcess), &processInfo);\n\n        if (processInfo.DangerousProcess)\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n#if defined(PH_TS_IS_SYSTEM_PROCESS)\ntypedef struct _PH_IS_SYSTEM_PROCESS_CONTEXT\n{\n    PPH_STRING BaseName;\n    BOOLEAN Found;\n} PH_IS_SYSTEM_PROCESS_CONTEXT, *PPH_IS_SYSTEM_PROCESS_CONTEXT;\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nstatic BOOLEAN NTAPI PhIsSystemProcessCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PKEY_VALUE_FULL_INFORMATION Information,\n    _In_ PPH_IS_SYSTEM_PROCESS_CONTEXT Context\n    )\n{\n    if (Information->Type == REG_DWORD)\n    {\n        PH_STRINGREF string;\n\n        string.Buffer = PTR_ADD_OFFSET(Information, Information->DataOffset);\n        string.Length = Information->DataLength;\n\n        if (PhEqualStringRef(&string, &Context->BaseName->sr, TRUE))\n        {\n            Context->Found = TRUE;\n            return FALSE;\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Determines if a process is a system process.\n *\n * \\param ProcessId The PID of the process to check.\n */\nBOOLEAN PhIsTerminalServerSystemProcess(\n    _In_ HANDLE ProcessId\n    )\n{\n    static CONST PH_STRINGREF keyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Control\\\\Terminal Server\\\\SysProcs\");\n    PPH_STRING fileName;\n    HANDLE keyHandle;\n\n    if (ProcessId == SYSTEM_PROCESS_ID)\n        return TRUE;\n\n    if (!NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessId, &fileName)))\n        return FALSE;\n\n    PhMoveReference(&fileName, PhGetBaseName(fileName));\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &keyName,\n        0\n        )))\n    {\n        PH_IS_SYSTEM_PROCESS_CONTEXT context;\n\n        memset(&context, 0, sizeof(PH_IS_SYSTEM_PROCESS_CONTEXT));\n        context.BaseName = fileName;\n        context.Found = FALSE;\n\n        PhEnumerateValueKey(\n            keyHandle,\n            KeyValueFullInformation,\n            PhIsSystemProcessCallback,\n            &context\n            );\n\n        NtClose(keyHandle);\n\n        if (context.Found)\n        {\n            PhDereferenceObject(fileName);\n            return TRUE;\n        }\n    }\n\n    PhDereferenceObject(fileName);\n    return FALSE;\n}\n#endif\n\n/**\n * Checks if the user wants to proceed with an operation.\n *\n * \\param WindowHandle A handle to the parent window.\n * \\param Verb A verb describing the action.\n * \\param Message A message containing additional information\n * about the action.\n * \\param WarnOnlyIfDangerous TRUE to skip the confirmation\n * dialog if none of the processes are system processes,\n * FALSE to always show the confirmation dialog.\n * \\param Processes An array of pointers to process items.\n * \\param NumberOfProcesses The number of process items.\n * \\return TRUE if the user wants to proceed with the operation,\n * otherwise FALSE.\n */\nstatic BOOLEAN PhpShowContinueMessageProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Verb,\n    _In_opt_ PCWSTR Message,\n    _In_ BOOLEAN WarnOnlyIfDangerous,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    PWSTR object;\n    ULONG i;\n    BOOLEAN critical = FALSE;\n    BOOLEAN dangerous = FALSE;\n    BOOLEAN cont = FALSE;\n\n    if (NumberOfProcesses == 0)\n        return FALSE;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        HANDLE processHandle;\n        BOOLEAN breakOnTermination = FALSE;\n\n        if (PhIsDangerousProcess(Processes[i]->ProcessId))\n        {\n            critical = TRUE;\n            dangerous = TRUE;\n            break;\n        }\n\n        if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, Processes[i]->ProcessId)))\n        {\n            PhGetProcessBreakOnTermination(processHandle, &breakOnTermination);\n            NtClose(processHandle);\n        }\n\n        if (breakOnTermination)\n        {\n            critical = TRUE;\n            dangerous = TRUE;\n            break;\n        }\n    }\n\n    if (WarnOnlyIfDangerous && !dangerous)\n        return TRUE;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        if (NumberOfProcesses == 1)\n        {\n            object = Processes[0]->ProcessName->Buffer;\n        }\n        else if (NumberOfProcesses == 2)\n        {\n            object = PhaConcatStrings(\n                3,\n                Processes[0]->ProcessName->Buffer,\n                L\" and \",\n                Processes[1]->ProcessName->Buffer\n                )->Buffer;\n        }\n        else\n        {\n            object = L\"the selected processes\";\n        }\n\n        if (!dangerous)\n        {\n            cont = PhShowConfirmMessage(\n                WindowHandle,\n                Verb,\n                object,\n                Message,\n                FALSE\n                );\n        }\n        else if (!critical)\n        {\n            cont = PhShowConfirmMessage(\n                WindowHandle,\n                Verb,\n                object,\n                PhaConcatStrings(\n                3,\n                L\"You are about to \",\n                Verb,\n                L\" one or more system processes.\"\n                )->Buffer,\n                TRUE\n                );\n        }\n        else\n        {\n            PPH_STRING message;\n\n            if (PhEqualStringZ(Verb, L\"terminate\", FALSE))\n            {\n                message = PhaConcatStrings(\n                    3,\n                    L\"You are about to \",\n                    Verb,\n                    L\" one or more critical processes. This will shut down the operating system immediately.\"\n                    );\n            }\n            else\n            {\n                message = PhaConcatStrings(\n                    3,\n                    L\"You are about to \",\n                    Verb,\n                    L\" one or more critical processes.\"\n                    );\n            }\n\n            cont = PhShowConfirmMessage(\n                WindowHandle,\n                Verb,\n                object,\n                message->Buffer,\n                TRUE\n                );\n        }\n    }\n    else\n    {\n        cont = TRUE;\n    }\n\n    return cont;\n}\n\n/**\n * Shows an error message to the user and checks\n * if the user wants to continue.\n *\n * \\param WindowHandle A handle to the parent window.\n * \\param Verb A verb describing the action which\n * resulted in an error.\n * \\param Process The process item which the action\n * was performed on.\n * \\param Status A NT status value representing the\n * error.\n * \\param Win32Result A Win32 error code representing\n * the error.\n *\n * \\return TRUE if the user wants to continue, otherwise\n * FALSE. The result is typically only useful when\n * executing an action on multiple processes.\n */\nstatic BOOLEAN PhpShowErrorProcess(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Verb,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    if (!PH_IS_FAKE_PROCESS_ID(Process->ProcessId))\n    {\n        return PhShowContinueStatus(\n            WindowHandle,\n            PhaFormatString(\n            L\"Unable to %s %s (PID %lu)\",\n            Verb,\n            Process->ProcessName->Buffer,\n            HandleToUlong(Process->ProcessId)\n            )->Buffer,\n            Status,\n            Win32Result\n            );\n    }\n    else\n    {\n        return PhShowContinueStatus(\n            WindowHandle,\n            PhaFormatString(\n            L\"Unable to %s %s\",\n            Verb,\n            Process->ProcessName->Buffer\n            )->Buffer,\n            Status,\n            Win32Result\n            );\n    }\n}\n\nBOOLEAN PhUiTerminateProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    if (!PhpShowContinueMessageProcesses(\n        WindowHandle,\n        L\"terminate\",\n        L\"Terminating a process will cause unsaved data to be lost.\",\n        FALSE,\n        Processes,\n        NumberOfProcesses\n        ))\n        return FALSE;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        // Note: The current process is a special case (see GH#1770) (dmex)\n        if (Processes[i]->ProcessId == NtCurrentProcessId())\n        {\n            RtlExitUserProcess(STATUS_SUCCESS);\n        }\n\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_TERMINATE,\n            Processes[i]->ProcessId\n            )))\n        {\n            // An exit status of 1 is used here for compatibility reasons:\n            // 1. Both Task Manager and Process Explorer use 1.\n            // 2. winlogon tries to restart explorer.exe if the exit status is not 1.\n\n            status = PhTerminateProcess(processHandle, 1);\n\n            if (status == STATUS_SUCCESS || status == STATUS_PROCESS_IS_TERMINATING)\n                PhTerminateProcess(processHandle, DBG_TERMINATE_PROCESS); // debug terminate (dmex)\n\n            NtClose(processHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to terminate \", Processes[i]->ProcessName->Buffer)->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessTerminate, 0)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorProcess(WindowHandle, L\"terminate\", Processes[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorProcess(WindowHandle, L\"terminate\", Processes[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhpUiTerminateTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ PVOID Processes,\n    _Inout_ PBOOLEAN Success\n    )\n{\n    NTSTATUS status;\n    PSYSTEM_PROCESS_INFORMATION process;\n    HANDLE processHandle;\n    PPH_PROCESS_ITEM processItem;\n\n    // Note:\n    // FALSE should be written to Success if any part of the operation failed.\n    // The return value of this function indicates whether to continue with\n    // the operation (FALSE if user cancelled).\n\n    // Terminate the process.\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_TERMINATE,\n        Process->ProcessId\n        )))\n    {\n        status = PhTerminateProcess(processHandle, 1);\n\n        if (status == STATUS_SUCCESS || status == STATUS_PROCESS_IS_TERMINATING)\n            PhTerminateProcess(processHandle, DBG_TERMINATE_PROCESS); // debug terminate (dmex)\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        *Success = FALSE;\n\n        if (!PhpShowErrorProcess(WindowHandle, L\"terminate\", Process, status, 0))\n            return FALSE;\n    }\n\n    // Terminate the process' children.\n\n    process = PH_FIRST_PROCESS(Processes);\n\n    do\n    {\n        if (process->UniqueProcessId != Process->ProcessId &&\n            process->InheritedFromUniqueProcessId == Process->ProcessId)\n        {\n            if (processItem = PhReferenceProcessItem(process->UniqueProcessId))\n            {\n                if (WindowsVersion >= WINDOWS_10_RS3)\n                {\n                    // Check the sequence number to make sure it is a descendant.\n                    if (processItem->ProcessSequenceNumber >= Process->ProcessSequenceNumber)\n                    {\n                        if (!PhpUiTerminateTreeProcess(WindowHandle, processItem, Processes, Success))\n                        {\n                            PhDereferenceObject(processItem);\n                            return FALSE;\n                        }\n                    }\n                }\n                else\n                {\n                    // Check the creation time to make sure it is a descendant.\n                    if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart)\n                    {\n                        if (!PhpUiTerminateTreeProcess(WindowHandle, processItem, Processes, Success))\n                        {\n                            PhDereferenceObject(processItem);\n                            return FALSE;\n                        }\n                    }\n                }\n\n                PhDereferenceObject(processItem);\n            }\n        }\n    } while (process = PH_NEXT_PROCESS(process));\n\n    return TRUE;\n}\n\nBOOLEAN PhUiTerminateTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n    BOOLEAN success = TRUE;\n    BOOLEAN cont = FALSE;\n    PVOID processes;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        cont = PhShowConfirmMessage(\n            WindowHandle,\n            L\"terminate\",\n            PhaConcatStrings2(Process->ProcessName->Buffer, L\" and its descendants\")->Buffer,\n            L\"Terminating a process tree will cause the process and its descendants to be terminated.\",\n            FALSE\n            );\n    }\n    else\n    {\n        cont = TRUE;\n    }\n\n    if (!cont)\n        return FALSE;\n\n    if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to enumerate processes\", status, 0);\n        return FALSE;\n    }\n\n    PhpUiTerminateTreeProcess(WindowHandle, Process, processes, &success);\n    PhFree(processes);\n\n    return success;\n}\n\nBOOLEAN PhUiSuspendProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    if (!PhpShowContinueMessageProcesses(\n        WindowHandle,\n        L\"suspend\",\n        NULL,\n        TRUE,\n        Processes,\n        NumberOfProcesses\n        ))\n        return FALSE;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_SUSPEND_RESUME,\n            Processes[i]->ProcessId\n            )))\n        {\n            status = NtSuspendProcess(processHandle);\n            NtClose(processHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to suspend \", Processes[i]->ProcessName->Buffer)->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessSuspend, 0)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorProcess(WindowHandle, L\"suspend\", Processes[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorProcess(WindowHandle, L\"suspend\", Processes[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhpUiSuspendTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ PVOID Processes,\n    _Inout_ PBOOLEAN Success\n    )\n{\n    NTSTATUS status;\n    PSYSTEM_PROCESS_INFORMATION process;\n    HANDLE processHandle;\n    PPH_PROCESS_ITEM processItem;\n\n    // Note:\n    // FALSE should be written to Success if any part of the operation failed.\n    // The return value of this function indicates whether to continue with\n    // the operation (FALSE if user cancelled).\n\n    // Suspend the process.\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SUSPEND_RESUME,\n        Process->ProcessId\n        )))\n    {\n        status = NtSuspendProcess(processHandle);\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        *Success = FALSE;\n\n        if (!PhpShowErrorProcess(WindowHandle, L\"suspend\", Process, status, 0))\n            return FALSE;\n    }\n\n    // Suspend the process' children.\n\n    process = PH_FIRST_PROCESS(Processes);\n\n    do\n    {\n        if (process->UniqueProcessId != Process->ProcessId &&\n            process->InheritedFromUniqueProcessId == Process->ProcessId)\n        {\n            if (processItem = PhReferenceProcessItem(process->UniqueProcessId))\n            {\n                if (WindowsVersion >= WINDOWS_10_RS3)\n                {\n                    // Check the sequence number to make sure it is a descendant.\n                    if (processItem->ProcessSequenceNumber >= Process->ProcessSequenceNumber)\n                    {\n                        if (!PhpUiSuspendTreeProcess(WindowHandle, processItem, Processes, Success))\n                        {\n                            PhDereferenceObject(processItem);\n                            return FALSE;\n                        }\n                    }\n                }\n                else\n                {\n                    // Check the creation time to make sure it is a descendant.\n                    if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart)\n                    {\n                        if (!PhpUiSuspendTreeProcess(WindowHandle, processItem, Processes, Success))\n                        {\n                            PhDereferenceObject(processItem);\n                            return FALSE;\n                        }\n                    }\n                }\n\n                PhDereferenceObject(processItem);\n            }\n        }\n    } while (process = PH_NEXT_PROCESS(process));\n\n    return TRUE;\n}\n\nBOOLEAN PhUiSuspendTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n    BOOLEAN result;\n    PVOID processes;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        result = PhShowConfirmMessage(\n            WindowHandle,\n            L\"suspend\",\n            PhaConcatStrings2(Process->ProcessName->Buffer, L\" and its descendants\")->Buffer,\n            L\"Suspending a process tree will cause the process and its descendants to be suspend.\",\n            FALSE\n            );\n    }\n    else\n    {\n        result = TRUE;\n    }\n\n    if (!result)\n        return FALSE;\n\n    if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to enumerate processes\", status, 0);\n        return FALSE;\n    }\n\n    PhpUiSuspendTreeProcess(WindowHandle, Process, processes, &result);\n    PhFree(processes);\n\n    return result;\n}\n\nBOOLEAN PhUiResumeProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    if (!PhpShowContinueMessageProcesses(\n        WindowHandle,\n        L\"resume\",\n        NULL,\n        TRUE,\n        Processes,\n        NumberOfProcesses\n        ))\n        return FALSE;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_SUSPEND_RESUME,\n            Processes[i]->ProcessId\n            )))\n        {\n            status = NtResumeProcess(processHandle);\n            NtClose(processHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to resume \", Processes[i]->ProcessName->Buffer)->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessResume, 0)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorProcess(WindowHandle, L\"resume\", Processes[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorProcess(WindowHandle, L\"resume\", Processes[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhpUiResumeTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ PVOID Processes,\n    _Inout_ PBOOLEAN Success\n    )\n{\n    NTSTATUS status;\n    PSYSTEM_PROCESS_INFORMATION process;\n    HANDLE processHandle;\n    PPH_PROCESS_ITEM processItem;\n\n    // Note:\n    // FALSE should be written to Success if any part of the operation failed.\n    // The return value of this function indicates whether to continue with\n    // the operation (FALSE if user cancelled).\n\n    // Resume the process.\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SUSPEND_RESUME,\n        Process->ProcessId\n        )))\n    {\n        status = NtResumeProcess(processHandle);\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        *Success = FALSE;\n\n        if (!PhpShowErrorProcess(WindowHandle, L\"resume\", Process, status, 0))\n            return FALSE;\n    }\n\n    // Resume the process' children.\n\n    process = PH_FIRST_PROCESS(Processes);\n\n    do\n    {\n        if (process->UniqueProcessId != Process->ProcessId &&\n            process->InheritedFromUniqueProcessId == Process->ProcessId)\n        {\n            if (processItem = PhReferenceProcessItem(process->UniqueProcessId))\n            {\n                if (WindowsVersion >= WINDOWS_10_RS3)\n                {\n                    // Check the sequence number to make sure it is a descendant.\n                    if (processItem->ProcessSequenceNumber >= Process->ProcessSequenceNumber)\n                    {\n                        if (!PhpUiResumeTreeProcess(WindowHandle, processItem, Processes, Success))\n                        {\n                            PhDereferenceObject(processItem);\n                            return FALSE;\n                        }\n                    }\n                }\n                else\n                {\n                    // Check the creation time to make sure it is a descendant.\n                    if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart)\n                    {\n                        if (!PhpUiResumeTreeProcess(WindowHandle, processItem, Processes, Success))\n                        {\n                            PhDereferenceObject(processItem);\n                            return FALSE;\n                        }\n                    }\n                }\n\n                PhDereferenceObject(processItem);\n            }\n        }\n    } while (process = PH_NEXT_PROCESS(process));\n\n    return TRUE;\n}\n\nBOOLEAN PhUiResumeTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n    BOOLEAN result;\n    PVOID processes;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        result = PhShowConfirmMessage(\n            WindowHandle,\n            L\"resume\",\n            PhConcatStringRefZ(&Process->ProcessName->sr, L\" and its descendants\")->Buffer,\n            L\"Resuming a process tree will cause the process and its descendants to be resumed.\",\n            FALSE\n            );\n    }\n    else\n    {\n        result = TRUE;\n    }\n\n    if (!result)\n        return FALSE;\n\n    if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to enumerate processes\", status, 0);\n        return FALSE;\n    }\n\n    PhpUiResumeTreeProcess(WindowHandle, Process, processes, &result);\n    PhFree(processes);\n\n    return result;\n}\n\nBOOLEAN PhUiFreezeTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n    BOOLEAN result = FALSE;\n    HANDLE freezeHandle;\n\n    if (ReadPointerAcquire(&Process->FreezeHandle))\n        return FALSE;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        result = PhShowConfirmMessage(\n            WindowHandle,\n            L\"freeze\",\n            Process->ProcessName->Buffer,\n            L\"Freezing does not persist after exiting System Informer.\",\n            FALSE\n            );\n    }\n    else\n    {\n        result = TRUE;\n    }\n\n    if (!result)\n        return FALSE;\n\n    status = PhFreezeProcessById(\n        &freezeHandle,\n        Process->ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"freeze\", Process, status, 0);\n        return FALSE;\n    }\n\n    if (freezeHandle = InterlockedExchangePointer(&Process->FreezeHandle, freezeHandle))\n    {\n        NtClose(freezeHandle);\n    }\n\n    return TRUE;\n}\n\nBOOLEAN PhUiThawTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n    HANDLE freezeHandle;\n\n    if (!ReadPointerAcquire(&Process->FreezeHandle))\n        return FALSE;\n\n    status = PhThawProcessById(\n        Process->FreezeHandle,\n        Process->ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"thaw\", Process, status, 0);\n        return FALSE;\n    }\n\n    if (freezeHandle = InterlockedExchangePointer(&Process->FreezeHandle, NULL))\n    {\n        NtClose(freezeHandle);\n    }\n\n    return TRUE;\n}\n\nBOOLEAN PhUiRestartProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n    BOOLEAN result = FALSE;\n    BOOLEAN elevated = !!PhGetOwnTokenAttributes().Elevated;\n    BOOLEAN tokenIsStronglyNamed = FALSE;\n    BOOLEAN tokenIsUIAccessEnabled = FALSE;\n    BOOLEAN tokenRevertImpersonation = FALSE;\n    HANDLE processHandle = NULL;\n    HANDLE newProcessHandle = NULL;\n    HANDLE tokenHandle = NULL;\n    PPH_STRING fileNameWin32 = NULL;\n    PPH_STRING commandLine = NULL;\n    PPH_STRING currentDirectory = NULL;\n    STARTUPINFOEX startupInfo = { 0 };\n    PSECURITY_DESCRIPTOR processSecurityDescriptor = NULL;\n    PSECURITY_DESCRIPTOR tokenSecurityDescriptor = NULL;\n    PPROC_THREAD_ATTRIBUTE_LIST attributeList = NULL;\n    BOOLEAN environmentAllocated = FALSE;\n    PVOID environmentBuffer = NULL;\n    ULONG environmentLength;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        result = PhShowConfirmMessage(\n            WindowHandle,\n            L\"restart\",\n            Process->ProcessName->Buffer,\n            L\"The process will be restarted with the same command line, \"\n            L\"working directory and privileges.\",\n            FALSE\n            );\n    }\n    else\n    {\n        result = TRUE;\n    }\n\n    if (!result)\n        return FALSE;\n\n    // Fail when restarting the current process otherwise\n    // we get terminated before creating the new process. (dmex)\n    if (Process->ProcessId == NtCurrentProcessId())\n        return FALSE;\n\n    // Special handling for the current shell process. (dmex)\n    {\n        CLIENT_ID shellClientId;\n\n        if (NT_SUCCESS(PhGetWindowClientId(PhGetShellWindow(), &shellClientId)))\n        {\n            if (Process->ProcessId == shellClientId.UniqueProcess)\n            {\n                if (NT_SUCCESS(PhOpenProcess(\n                    &processHandle,\n                    PROCESS_TERMINATE,\n                    Process->ProcessId\n                    )))\n                {\n                    status = PhTerminateProcess(\n                        processHandle,\n                        STATUS_SUCCESS\n                        );\n\n                    NtClose(processHandle);\n\n                    if (NT_SUCCESS(status))\n                        goto CleanupExit;\n                }\n            }\n        }\n    }\n\n    fileNameWin32 = Process->FileName ? PhGetFileName(Process->FileName) : NULL;\n\n    if (PhIsNullOrEmptyString(fileNameWin32) || !PhDoesFileExistWin32(PhGetString(fileNameWin32)))\n    {\n        status = STATUS_NO_SUCH_FILE;\n        goto CleanupExit;\n    }\n\n    // Open the process and get the command line and current directory.\n\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n        Process->ProcessId\n        )))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhGetProcessCurrentDirectory(\n        processHandle,\n        !!Process->IsWow64Process,\n        &currentDirectory\n        )))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhGetProcessCommandLine(\n        processHandle,\n        &commandLine\n        )))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhGetProcessEnvironment(\n        processHandle,\n        !!Process->IsWow64Process,\n        &environmentBuffer,\n        &environmentLength\n        )))\n        goto CleanupExit;\n\n    NtClose(processHandle);\n    processHandle = NULL;\n\n    // Start the process.\n    //\n    // Use the existing process as the parent, and restarting the process will inherit most of the process configuration from itself (dmex)\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_CREATE_PROCESS | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE | (elevated ? READ_CONTROL : 0),\n        Process->ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhInitializeProcThreadAttributeList(&attributeList, 1);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhUpdateProcThreadAttribute(\n        attributeList,\n        PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,\n        &processHandle,\n        sizeof(HANDLE)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhOpenProcessToken(\n        processHandle,\n        TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | (elevated ? READ_CONTROL : 0),\n        &tokenHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetTokenUIAccess(tokenHandle, &tokenIsUIAccessEnabled);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n    else\n    {\n        status = PhOpenProcessToken(\n            processHandle,\n            TOKEN_QUERY | (elevated ? READ_CONTROL : 0),\n            &tokenHandle\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    if (elevated)\n    {\n        PhGetObjectSecurity(\n            processHandle,\n            OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,\n            &processSecurityDescriptor\n            );\n        PhGetObjectSecurity(\n            tokenHandle,\n            OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,\n            &tokenSecurityDescriptor\n            );\n    }\n\n    if (!environmentBuffer)\n    {\n        if (NT_SUCCESS(PhCreateEnvironmentBlock(&environmentBuffer, tokenHandle, FALSE)))\n        {\n            environmentAllocated = TRUE;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetProcessIsStronglyNamed(processHandle, &tokenIsStronglyNamed)) && tokenIsStronglyNamed)\n    {\n        tokenRevertImpersonation = NT_SUCCESS(PhImpersonateToken(NtCurrentThread(), tokenHandle));\n    }\n\n    memset(&startupInfo, 0, sizeof(STARTUPINFOEX));\n    startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX);\n    startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;\n    startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL;\n    startupInfo.lpAttributeList = attributeList;\n\n    status = PhCreateProcessWin32Ex(\n        PhGetString(fileNameWin32),\n        PhGetString(commandLine),\n        environmentBuffer,\n        PhGetString(currentDirectory),\n        &startupInfo,\n        PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO |\n        PH_CREATE_PROCESS_DEFAULT_ERROR_MODE | PH_CREATE_PROCESS_UNICODE_ENVIRONMENT,\n        tokenHandle,\n        NULL,\n        &newProcessHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status)) // Try without the token (dmex)\n    {\n        status = PhCreateProcessWin32Ex(\n            PhGetString(fileNameWin32),\n            PhGetString(commandLine),\n            environmentBuffer,\n            PhGetString(currentDirectory),\n            &startupInfo,\n            PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO |\n            PH_CREATE_PROCESS_DEFAULT_ERROR_MODE | PH_CREATE_PROCESS_UNICODE_ENVIRONMENT,\n            NULL,\n            NULL,\n            &newProcessHandle,\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status) && tokenIsUIAccessEnabled) // Try UIAccess (dmex)\n    {\n        status = PhShellExecuteEx(\n            WindowHandle,\n            PhGetString(fileNameWin32),\n            PhGetString(commandLine),\n            PhGetString(currentDirectory),\n            SW_SHOW,\n            PH_SHELL_EXECUTE_DEFAULT,\n            0,\n            &newProcessHandle\n            );\n    }\n\n    if (tokenRevertImpersonation)\n    {\n        PhRevertImpersonationToken(NtCurrentThread());\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        // See runas.c for a description of the Windows issue with PROC_THREAD_ATTRIBUTE_PARENT_PROCESS\n        // requiring the reset of the security descriptor. (dmex)\n\n        if (elevated && !tokenIsUIAccessEnabled) // Skip processes with UIAccess (dmex)\n        {\n            HANDLE tokenWriteHandle = NULL;\n\n            if (processSecurityDescriptor)\n            {\n                PhSetObjectSecurity(\n                    newProcessHandle,\n                    OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,\n                    processSecurityDescriptor\n                    );\n            }\n\n            if (tokenSecurityDescriptor && NT_SUCCESS(PhOpenProcessToken(\n                newProcessHandle,\n                WRITE_DAC | WRITE_OWNER,\n                &tokenWriteHandle\n                )))\n            {\n                PhSetObjectSecurity(\n                    tokenWriteHandle,\n                    OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,\n                    tokenSecurityDescriptor\n                    );\n                NtClose(tokenWriteHandle);\n            }\n        }\n\n        // Terminate the existing process.\n\n        PhTerminateProcess(processHandle, STATUS_SUCCESS);\n\n        // Update the console foreground.\n\n        PhConsoleSetForeground(newProcessHandle, TRUE);\n\n        // Resume the new process.\n\n        NtResumeProcess(newProcessHandle);\n    }\n\nCleanupExit:\n\n    if (tokenHandle)\n    {\n        NtClose(tokenHandle);\n    }\n\n    if (newProcessHandle)\n    {\n        NtClose(newProcessHandle);\n    }\n\n    if (processHandle)\n    {\n        NtClose(processHandle);\n    }\n\n    if (attributeList)\n    {\n        PhDeleteProcThreadAttributeList(attributeList);\n    }\n\n    if (environmentBuffer && environmentAllocated)\n    {\n        PhDestroyEnvironmentBlock(environmentBuffer);\n    }\n\n    if (tokenSecurityDescriptor)\n    {\n        PhFree(tokenSecurityDescriptor);\n    }\n\n    if (processSecurityDescriptor)\n    {\n        PhFree(processSecurityDescriptor);\n    }\n\n    if (currentDirectory)\n    {\n        PhDereferenceObject(currentDirectory);\n    }\n\n    if (commandLine)\n    {\n        PhDereferenceObject(commandLine);\n    }\n\n    if (fileNameWin32)\n    {\n        PhDereferenceObject(fileNameWin32);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"restart\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nstatic PPH_STRING PhFindDebuggerPath(\n    _In_ PCWSTR DebuggerName\n    )\n{\n    static PH_STRINGREF windowsKitsKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows Kits\\\\Installed Roots\");\n    PPH_STRING debuggerPath = NULL;\n    HANDLE keyHandle;\n    PPH_STRING kitsRoot;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &windowsKitsKeyName,\n        0\n        )))\n    {\n        if (kitsRoot = PhQueryRegistryStringZ(keyHandle, L\"KitsRoot10\"))\n        {\n            PPH_STRING testPath;\n\n#ifdef _WIN64\n            testPath = PhConcatStringRefZ(&kitsRoot->sr, L\"Debuggers\\\\x64\\\\\");\n#else\n            testPath = PhConcatStringRefZ(&kitsRoot->sr, L\"Debuggers\\\\x86\\\\\");\n#endif\n            PhMoveReference(&testPath, PhConcatStringRefZ(&testPath->sr, DebuggerName));\n\n            if (PhDoesFileExistWin32(PhGetString(testPath)))\n            {\n                debuggerPath = testPath;\n            }\n            else\n            {\n                PhDereferenceObject(testPath);\n            }\n\n            PhDereferenceObject(kitsRoot);\n        }\n\n        NtClose(keyHandle);\n    }\n\n    if (PhIsNullOrEmptyString(debuggerPath))\n    {\n        PhMoveReference(&debuggerPath, PhSearchFilePath(DebuggerName, L\".exe\"));\n    }\n\n    return debuggerPath;\n}\n\n//static PPH_STRING PhFindVisualStudioDebugger(\n//    _In_ PCPH_STRINGREF VersionRange\n//    )\n//{\n//    static const PH_STRINGREF vswhere = PH_STRINGREF_INIT(L\"%ProgramFiles(x86)%\\\\Microsoft Visual Studio\\\\Installer\\\\vswhere.exe\");\n//    static const PH_STRINGREF trimSet = PH_STRINGREF_INIT(L\"\\r\\n\");\n//    static const PH_STRINGREF args01 = PH_STRINGREF_INIT(L\" -prerelease -version \");\n//    static const PH_STRINGREF args02 = PH_STRINGREF_INIT(L\" -property installationPath \");\n//    NTSTATUS status;\n//    PPH_STRING expandedfileName = NULL;\n//    PPH_STRING expandedCommand = NULL;\n//    PPH_STRING devenvPath = NULL;\n//    PPH_STRING output = NULL;\n//\n//    if (!(expandedfileName = PhExpandEnvironmentStrings(&vswhere)))\n//        return NULL;\n//\n//    if (!PhDoesFileExistWin32(PhGetString(expandedfileName)))\n//    {\n//        PhDereferenceObject(expandedfileName);\n//        return NULL;\n//    }\n//\n//    // vswhere.exe -prerelease -version %s -property installationPath\n//    expandedCommand = PhConcatStringRef3(\n//        &args01,\n//        VersionRange,\n//        &args02\n//        );\n//\n//    status = PhCreateProcessRedirection(\n//        &expandedfileName->sr,\n//        &expandedCommand->sr,\n//        NULL,\n//        &output\n//        );\n//\n//    if (!NT_SUCCESS(status) || PhIsNullOrEmptyString(output))\n//        goto CleanupExit;\n//\n//    PhTrimStringRef(\n//        &output->sr,\n//        &trimSet,\n//        PH_TRIM_END_ONLY\n//        );\n//\n//    devenvPath = PhConcatStringRefZ(&output->sr, L\"\\\\Common7\\\\IDE\\\\devenv.exe\");\n//\n//    if (PhDoesFileExistWin32(devenvPath->Buffer))\n//    {\n//        PhClearReference(&output);\n//        PhClearReference(&expandedCommand);\n//        PhClearReference(&expandedfileName);\n//\n//        return devenvPath;\n//    }\n//\n//CleanupExit:\n//    PhClearReference(&output);\n//    PhClearReference(&devenvPath);\n//    PhClearReference(&expandedCommand);\n//    PhClearReference(&expandedfileName);\n//    return NULL;\n//}\n\n/**\n * Launch a system debugger attached to the specified process.\n *\n * \\param WindowHandle: The parent HWND for dialogs (Task Dialogs, errors, etc.).\n * \\param Process A pointer to a `PPH_PROCESS_ITEM` describing the target process.\n * \\return BOOLEAN: TRUE on success (debugger launched), FALSE on cancel or failure.\n */\nBOOLEAN PhUiDebugProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    static CONST PH_STRINGREF aeDebugKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug\");\n#ifdef _WIN64\n    static CONST PH_STRINGREF aeDebugWow64KeyName = PH_STRINGREF_INIT(L\"Software\\\\Wow6432Node\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug\");\n#endif\n    NTSTATUS status;\n    PPH_STRING commandLine = NULL;\n    PPH_STRING debuggerCommand = NULL;\n    PH_STRING_BUILDER commandLineBuilder;\n    HANDLE keyHandle;\n    PPH_STRING debugger;\n    PH_STRINGREF commandPart;\n    PH_STRINGREF dummy;\n    LONG debuggerChoice = 0;\n    PPH_STRING registryDebuggerPath = NULL;\n    PPH_STRING registryDebuggerName = NULL;\n\n    //if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    //{\n    //    result = PhShowConfirmMessage(\n    //        WindowHandle,\n    //        L\"debug\",\n    //        Process->ProcessName->Buffer,\n    //        L\"Debugging a process may result in loss of data.\",\n    //        FALSE\n    //        );\n    //}\n    //else\n    //{\n    //    result = TRUE;\n    //}\n    //\n    //if (!result)\n    //    return FALSE;\n\n    status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n#ifdef _WIN64\n        Process->IsWow64Process ? &aeDebugWow64KeyName : &aeDebugKeyName,\n#else\n        &aeDebugKeyName,\n#endif\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (debugger = PhQueryRegistryStringZ(keyHandle, L\"Debugger\"))\n        {\n            if (PhSplitStringRefAtChar(&debugger->sr, L'\"', &dummy, &commandPart) &&\n                PhSplitStringRefAtChar(&commandPart, L'\"', &commandPart, &dummy))\n            {\n                registryDebuggerPath = PhCreateString2(&commandPart);\n                registryDebuggerName = PhGetFileName(registryDebuggerPath);\n            }\n\n            PhDereferenceObject(debugger);\n        }\n\n        NtClose(keyHandle);\n    }\n\n    // Check for available debuggers and show selection dialog\n    {\n        PPH_STRING windbgPath = NULL;\n        PPH_STRING windbgPreviewPath = NULL;\n        //PPH_STRING vs2026Path = NULL;\n        //PPH_STRING vs2022Path = NULL;\n        PPH_STRING cdbPath = NULL;\n        PPH_STRING kdPath = NULL;\n        PPH_STRING ntsdPath = NULL;\n        TASKDIALOGCONFIG config;\n        TASKDIALOG_BUTTON buttons[11];\n        ULONG buttonCount = 0;\n        PPH_STRING registryButtonText = NULL;\n\n        if (windbgPath = PhFindDebuggerPath(L\"windbg.exe\"))\n            buttons[buttonCount++] = (TASKDIALOG_BUTTON){ 101, L\"\\U0001FA9F WinDbg\\nGraphical debugger for both user-mode and kernel-mode debugging.\" };\n        if (windbgPreviewPath = PhFindDebuggerPath(L\"windbgx.exe\"))\n            buttons[buttonCount++] = (TASKDIALOG_BUTTON){ 102, L\"\\U0001FA9F WinDbg (Preview)\\nModern graphical debugger for both user-mode and kernel-mode debugging.\" };\n        //if (vs2026Path = PhFindVisualStudioDebugger(SREF(L\"[18.0,19.0)\")))\n        //    buttons[buttonCount++] = (TASKDIALOG_BUTTON){ 107, L\"\\U0001F4D8 Visual Studio 2026\\nFull-featured IDE with integrated debugging.\" };\n        //if (vs2022Path = PhFindVisualStudioDebugger(SREF(L\"[16.0,17.0)\")))\n        //    buttons[buttonCount++] = (TASKDIALOG_BUTTON){ 108, L\"\\U0001F4D8 Visual Studio 2022\\nFull-featured IDE with integrated debugging.\" };\n        if (cdbPath = PhFindDebuggerPath(L\"cdb.exe\"))\n            buttons[buttonCount++] = (TASKDIALOG_BUTTON){ 103, L\"\\U0001F4FA CDB\\nCommand-line debugger for user-mode applications.\" };\n        if (kdPath = PhFindDebuggerPath(L\"kd.exe\"))\n            buttons[buttonCount++] = (TASKDIALOG_BUTTON){ 104, L\"\\U0001F4FA KD\\nKernel debugger for low-level system debugging.\" };\n        if (ntsdPath = PhFindDebuggerPath(L\"ntsd.exe\"))\n            buttons[buttonCount++] = (TASKDIALOG_BUTTON){ 105, L\"\\U0001F4FA NTSD\\nLegacy command-line debugger similar to CDB.\" };\n\n        // Always add registry debugger option\n        if (registryDebuggerPath && registryDebuggerName)\n        {\n            registryButtonText = PhFormatString(\n                L\"\\U00002699 (System Default)\\n%s\",\n                registryDebuggerName->Buffer,\n                registryDebuggerPath->Buffer\n                );\n            buttons[buttonCount++] = (TASKDIALOG_BUTTON){ 106, registryButtonText->Buffer };\n        }\n        else\n        {\n            buttons[buttonCount++] = (TASKDIALOG_BUTTON){ 106, L\"\\U00002699 System Default\\nNo debugger configured in AeDebug registry key.\" };\n        }\n\n        memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n        config.cbSize = sizeof(TASKDIALOGCONFIG);\n        config.hwndParent = WindowHandle;\n        config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_USE_COMMAND_LINKS | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_CAN_BE_MINIMIZED;\n        config.hMainIcon = PhGetApplicationIcon(FALSE);\n        config.dwCommonButtons = TDCBF_CANCEL_BUTTON;\n        config.pszWindowTitle = PhApplicationName;\n        config.pszMainInstruction = L\"Select a system debugger to use for this process:\";\n        config.pszContent = L\"You can choose from the installed debugging tools below.\";\n        config.cButtons = buttonCount;\n        config.pButtons = buttons;\n\n        if (PhShowTaskDialog(&config, &debuggerChoice, NULL, NULL) && debuggerChoice != 0)\n        {\n            switch (debuggerChoice)\n            {\n            case 101:\n                debuggerCommand = windbgPath;\n                windbgPath = NULL;\n                break;\n            case 102:\n                debuggerCommand = windbgPreviewPath;\n                windbgPreviewPath = NULL;\n                break;\n            case 103:\n                debuggerCommand = cdbPath;\n                cdbPath = NULL;\n                break;\n            case 104:\n                debuggerCommand = kdPath;\n                kdPath = NULL;\n                break;\n            case 105:\n                debuggerCommand = ntsdPath;\n                ntsdPath = NULL;\n                break;\n            case 106:\n                debuggerCommand = registryDebuggerPath;\n                registryDebuggerPath = NULL;\n                break;\n            //case 107:\n            //    debuggerCommand = vs2026Path;\n            //    vs2026Path = NULL;\n            //    break;\n            //case 108:\n            //    debuggerCommand = vs2022Path;\n            //    vs2022Path = NULL;\n            //    break;\n            }\n        }\n\n        PhClearReference(&windbgPath);\n        PhClearReference(&windbgPreviewPath);\n        //PhClearReference(&vs2026Path);\n        //PhClearReference(&vs2022Path);\n        PhClearReference(&cdbPath);\n        PhClearReference(&kdPath);\n        PhClearReference(&ntsdPath);\n        PhClearReference(&registryButtonText);\n    }\n\n    PhClearReference(&registryDebuggerName);\n    PhClearReference(&registryDebuggerPath);\n\n    if (!debuggerCommand || debuggerChoice == 0)\n    {\n        // User cancelled\n        return FALSE;\n    }\n\n    PhInitializeStringBuilder(&commandLineBuilder, debuggerCommand->Length + 30);\n    PhAppendCharStringBuilder(&commandLineBuilder, L'\"');\n    PhAppendStringBuilder(&commandLineBuilder, &debuggerCommand->sr);\n    PhAppendCharStringBuilder(&commandLineBuilder, L'\"');\n\n    switch (debuggerChoice)\n    {\n    case 101:\n    case 102:\n    case 103:\n    case 104:\n    case 105:\n    case 106:\n        PhAppendFormatStringBuilder(&commandLineBuilder, L\" -p %lu\", HandleToUlong(Process->ProcessId));\n        break;\n    case 107:\n    case 108:\n        PhAppendFormatStringBuilder(&commandLineBuilder, L\" /JITDebug /JITDebugParam %lx\", HandleToUlong(Process->ProcessId));\n        break;\n    }\n\n    commandLine = PhFinalStringBuilderString(&commandLineBuilder);\n\n    status = PhCreateProcessWin32(\n        NULL,\n        PhGetString(commandLine),\n        NULL,\n        NULL,\n        0,\n        NULL,\n        NULL,\n        NULL\n        );\n\n    PhDeleteStringBuilder(&commandLineBuilder);\n    PhDereferenceObject(debuggerCommand);\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"debug\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Reduce the working set of a list of processes.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\param Processes Array of process items to operate on.\n * \\param NumberOfProcesses Number of processes in the array.\n * \\return BOOLEAN TRUE if the operation succeeded for all processes, FALSE if one or more failed.\n */\nBOOLEAN PhUiReduceWorkingSetProcesses(\n    _In_ HWND WindowHandle,\n    _In_ CONST PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    BOOLEAN success = TRUE;\n    ULONG i;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_SET_QUOTA,\n            Processes[i]->ProcessId\n            );\n\n        if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n        {\n            status = PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION, // HACK for KphProcessEmptyWorkingSet (dmex)\n                Processes[i]->ProcessId\n                );\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhSetProcessEmptyWorkingSet(processHandle);\n            NtClose(processHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            success = FALSE;\n\n            if (!PhpShowErrorProcess(WindowHandle, L\"reduce the working set of\", Processes[i], status, 0))\n                break;\n        }\n    }\n\n    return success;\n}\n\n/**\n * Empty the working set of a list of processes.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\param Processes Array of process items to operate on.\n * \\param NumberOfProcesses Number of processes in the array.\n * \\return BOOLEAN TRUE if the operation succeeded for all processes, FALSE if one or more failed.\n */\nBOOLEAN PhUiSetEmptyWorkingSetProcesses(\n    _In_ HWND WindowHandle,\n    _In_ CONST PPH_PROCESS_ITEM* Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    BOOLEAN success = TRUE;\n    ULONG i;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_VM_OPERATION,\n            Processes[i]->ProcessId\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhSetProcessWorkingSetEmpty(processHandle);\n            NtClose(processHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            success = FALSE;\n\n            if (!PhpShowErrorProcess(WindowHandle, L\"empty the working set of\", Processes[i], status, 0))\n                break;\n        }\n    }\n\n    return success;\n}\n\n/**\n * Configure activity moderation (Eco/foreground throttling) for a process.\n *\n * \\param WindowHandle Parent window for dialogs.\n * \\param Process The process item to configure.\n * \\return BOOLEAN TRUE on success, FALSE on failure.\n */\nBOOLEAN PhUiSetActivityModeration(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    static CONST TASKDIALOG_BUTTON TaskDialogRadioButtonArray[] =\n    {\n        { SystemActivityModerationStateSystemManaged, L\"System managed\" },\n        { SystemActivityModerationStateUserManagedAllowThrottling, L\"Allow activity moderation throttling\" },\n        { SystemActivityModerationStateUserManagedDisableThrottling, L\"Disable activity moderation throttling\" },\n    };\n    static CONST TASKDIALOG_BUTTON TaskDialogButtonArray[] =\n    {\n        { IDYES, L\"Save\" },\n        { IDCANCEL, L\"Cancel\" },\n    };\n    NTSTATUS status;\n    SYSTEM_ACTIVITY_MODERATION_APP_SETTINGS activityModerationInfo = { 0 };\n    TASKDIALOGCONFIG config;\n    ULONG buttonId;\n    ULONG moderationState;\n    LARGE_INTEGER startTime;\n    LARGE_INTEGER currentTime;\n    SYSTEMTIME startTimeFields;\n    PPH_STRING startTimeRelativeString = NULL;\n    PPH_STRING startTimeString = NULL;\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_POSITION_RELATIVE_TO_WINDOW;\n    config.hMainIcon = PhGetApplicationIcon(FALSE);\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainInstruction = L\"Select the process activity moderation throttling state.\";\n    config.nDefaultButton = IDCANCEL;\n    config.pRadioButtons = TaskDialogRadioButtonArray;\n    config.cRadioButtons = RTL_NUMBER_OF(TaskDialogRadioButtonArray);\n    config.pButtons = TaskDialogButtonArray;\n    config.cButtons = RTL_NUMBER_OF(TaskDialogButtonArray);\n    config.hwndParent = WindowHandle;\n    config.cxWidth = 220;\n\n    if (PhIsNullOrEmptyString(Process->FileName))\n        return TRUE;\n\n    status = PhGetProcessActivityModerationState(\n        &Process->FileName->sr,\n        &activityModerationInfo\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        config.nDefaultRadioButton = activityModerationInfo.ModerationState;\n\n        PhQuerySystemTime(&currentTime);\n\n        if (activityModerationInfo.LastUpdatedTime.QuadPart < currentTime.QuadPart)\n        {\n            startTime = activityModerationInfo.LastUpdatedTime;\n            startTimeRelativeString = PH_AUTO(PhFormatTimeSpanRelative(currentTime.QuadPart - startTime.QuadPart));\n\n            PhLargeIntegerToLocalSystemTime(&startTimeFields, &startTime);\n            startTimeString = PhaFormatDateTime(&startTimeFields);\n        }\n    }\n    else\n    {\n        config.nDefaultRadioButton = SystemActivityModerationStateSystemManaged;\n    }\n\n    config.pszContent = PhaFormatString(\n        L\"System-managed activity moderation settings are automatically removed by Windows when the executable is deleted or was last executed more than 7 days ago.\\r\\n\\r\\n\"\n        L\"Image: %s\\r\\nUpdated: %s\",\n        PH_AUTO_T(PH_STRING, PhGetBaseName(Process->FileName))->Buffer,\n        (startTimeRelativeString && startTimeString) ? PhaFormatString(L\"%s ago (%s)\", PhGetString(startTimeRelativeString), PhGetString(startTimeString))->Buffer : L\"N/A\"\n        )->Buffer;\n\n    if (PhShowTaskDialog(\n        &config,\n        &buttonId,\n        &moderationState,\n        NULL\n        ) && buttonId == IDYES)\n    {\n        if (Process->IsPackagedProcess)\n        {\n            status = PhSetProcessActivityModerationState(\n                &Process->FileName->sr,\n                SystemActivityModerationAppTypePackaged,\n                moderationState\n                );\n        }\n        else\n        {\n            status = PhSetProcessActivityModerationState(\n                &Process->FileName->sr,\n                SystemActivityModerationAppTypeClassic,\n                moderationState\n                );\n        }\n    }\n    else\n    {\n        status = STATUS_SUCCESS;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"set background activity moderation for\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Enable or disable token virtualization for the specified process.\n *\n * \\param WindowHandle Parent window used for confirmation and error UI.\n * \\param Process The process item to operate on.\n * \\param Enable TRUE to enable virtualization, FALSE to disable.\n * \\return BOOLEAN TRUE on success, FALSE on failure.\n */\nBOOLEAN PhUiSetVirtualizationProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ BOOLEAN Enable\n    )\n{\n    NTSTATUS status;\n    BOOLEAN cont = FALSE;\n    HANDLE processHandle;\n    HANDLE tokenHandle;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        cont = PhShowConfirmMessage(\n            WindowHandle,\n            L\"set\",\n            L\"virtualization for the process\",\n            L\"Enabling or disabling virtualization for a process may \"\n            L\"alter its functionality and produce undesirable effects.\",\n            FALSE\n            );\n    }\n    else\n    {\n        cont = TRUE;\n    }\n\n    if (!cont)\n        return FALSE;\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        Process->ProcessId\n        )))\n    {\n        if (NT_SUCCESS(status = PhOpenProcessToken(\n            processHandle,\n            TOKEN_WRITE,\n            &tokenHandle\n            )))\n        {\n            status = PhSetTokenIsVirtualizationEnabled(tokenHandle, Enable);\n            NtClose(tokenHandle);\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"set virtualization for\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Toggle break-on-termination (critical process) for a process.\n *\n * \\param WindowHandle Parent window used for confirmation and error UI.\n * \\param Process The process item to operate on.\n * \\return BOOLEAN TRUE on success, FALSE on failure.\n */\nBOOLEAN PhUiSetCriticalProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    BOOLEAN breakOnTermination;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION,\n        Process->ProcessId\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetProcessBreakOnTermination(\n            processHandle,\n            &breakOnTermination\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (!breakOnTermination && (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                WindowHandle,\n                L\"enable\",\n                L\"critical status on the process\",\n                L\"If the process ends, the operating system will shut down immediately.\",\n                TRUE\n                )))\n            {\n                status = PhSetProcessBreakOnTermination(processHandle, TRUE);\n            }\n            else if (breakOnTermination && (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                WindowHandle,\n                L\"disable\",\n                L\"critical status on the process\",\n                NULL,\n                FALSE\n                )))\n            {\n                status = PhSetProcessBreakOnTermination(processHandle, FALSE);\n            }\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"set critical status for\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Enable or disable Eco mode for a process (power throttling).\n *\n * \\param WindowHandle Parent window used for confirmation and error UI.\n * \\param Process The process item to operate on.\n * \\return BOOLEAN TRUE on success, FALSE on failure.\n */\nBOOLEAN PhUiSetEcoModeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    POWER_THROTTLING_PROCESS_STATE powerThrottlingState;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_INFORMATION,\n        Process->ProcessId\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetProcessPowerThrottlingState(\n            processHandle,\n            &powerThrottlingState\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (!(\n                FlagOn(powerThrottlingState.ControlMask, POWER_THROTTLING_PROCESS_EXECUTION_SPEED) &&\n                FlagOn(powerThrottlingState.StateMask, POWER_THROTTLING_PROCESS_EXECUTION_SPEED)\n                ))\n            {\n                if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                    WindowHandle,\n                    L\"enable\",\n                    L\"Eco mode for this process\",\n                    L\"Eco mode will lower process priority and improve power efficiency but may cause instability in some processes.\",\n                    FALSE\n                    ))\n                {\n                    // Taskmgr sets the process priority to idle before enabling 'Eco mode'. (dmex)\n                    PhSetProcessPriorityClass(processHandle, PROCESS_PRIORITY_CLASS_IDLE);\n\n                    //\n                    // Turn PROCESS_EXECUTION_SPEED throttling on.\n                    //\n                    status = PhSetProcessPowerThrottlingState(\n                        processHandle,\n                        POWER_THROTTLING_PROCESS_EXECUTION_SPEED,\n                        POWER_THROTTLING_PROCESS_EXECUTION_SPEED\n                        );\n                }\n            }\n            else\n            {\n                //if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                //    WindowHandle,\n                //    L\"disable\",\n                //    L\"Eco mode for this process\",\n                //    L\"Eco mode will lower process priority and improve power efficiency but may cause instability in some processes.\",\n                //    FALSE\n                //    ))\n                {\n                    // Taskmgr does not properly restore the original priority after it has exited\n                    // and you later decide to disable 'Eco mode', so we'll restore normal priority\n                    // which isn't quite correct but still way better than what taskmgr does. (dmex)\n                    PhSetProcessPriorityClass(processHandle, PROCESS_PRIORITY_CLASS_NORMAL);\n\n                    //\n                    // Let system manage all power throttling.\n                    //\n                    status = PhSetProcessPowerThrottlingState(processHandle, 0, 0);\n                }\n            }\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"set Eco mode for\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Toggle the \"execution required\" state for a process (prevent PLM suspension/termination).\n *\n * \\param WindowHandle Parent window used for confirmation and error UI.\n * \\param Process The process item to operate on.\n * \\return BOOLEAN TRUE on success, FALSE on failure.\n */\nBOOLEAN PhUiSetExecutionRequiredProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        if (!PhShowConfirmMessage(\n            WindowHandle,\n            L\"change the execution required state\",\n            PhaConcatStrings2(L\"of \", Process->ProcessName->Buffer)->Buffer,\n            L\"The process continues to run instead of being suspended or terminated by process lifetime management (PLM).\",\n            FALSE\n            ))\n        {\n            return FALSE;\n        }\n    }\n\n    if (PhIsProcessExecutionRequired(Process->ProcessId))\n    {\n        status = PhProcessExecutionRequiredDisable(Process->ProcessId);\n    }\n    else\n    {\n        status = PhProcessExecutionRequiredEnable(Process->ProcessId);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"create execution required state for\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Detach the debugger from a process.\n *\n * \\param WindowHandle Parent window used for confirmation and error UI.\n * \\param Process The process item to operate on.\n * \\return BOOLEAN TRUE on success, FALSE on failure.\n */\nBOOLEAN PhUiDetachFromDebuggerProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    HANDLE debugObjectHandle;\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME,\n        Process->ProcessId\n        )))\n    {\n        if (NT_SUCCESS(status = PhGetProcessDebugObject(\n            processHandle,\n            &debugObjectHandle\n            )))\n        {\n            // Disable kill-on-close.\n            if (NT_SUCCESS(status = PhSetDebugKillProcessOnExit(\n                debugObjectHandle,\n                FALSE\n                )))\n            {\n                status = NtRemoveProcessDebug(processHandle, debugObjectHandle);\n            }\n\n            NtClose(debugObjectHandle);\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (status == STATUS_PORT_NOT_SET)\n    {\n        PhShowInformation2(WindowHandle, L\"Unable to detach the debugger.\", L\"%s\", L\"The process is not being debugged.\");\n        return FALSE;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"detach debugger from\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Load a DLL into the target process.\n *\n * \\param WindowHandle Parent window for dialogs.\n * \\param Process The process item to load the DLL into.\n * \\return BOOLEAN TRUE on success, FALSE on failure or cancel.\n */\nBOOLEAN PhUiLoadDllProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    )\n{\n    static PH_FILETYPE_FILTER filters[] =\n    {\n        { L\"DLL files (*.dll)\", L\"*.dll\" },\n        { L\"All files (*.*)\", L\"*.*\" }\n    };\n\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    HANDLE processHandle = NULL;\n    PVOID fileDialog;\n    PPH_STRING fileName;\n\n    fileDialog = PhCreateOpenFileDialog();\n    PhSetFileDialogOptions(fileDialog, PH_FILEDIALOG_DONTADDTORECENT);\n    PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters));\n\n    if (!PhShowFileDialog(WindowHandle, fileDialog))\n    {\n        PhFreeFileDialog(fileDialog);\n        return FALSE;\n    }\n\n    fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n    PhFreeFileDialog(fileDialog);\n\n    // Windows 8 requires ALL_ACCESS for PLM execution requests. (dmex)\n    if (WindowsVersion >= WINDOWS_8 && WindowsVersion <= WINDOWS_8_1)\n    {\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_ALL_ACCESS,\n            Process->ProcessId\n            );\n    }\n\n    // Windows 10 and above require SET_LIMITED for PLM execution requests. (dmex)\n    if (!NT_SUCCESS(status))\n    {\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_LIMITED_INFORMATION |\n            PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |\n            PROCESS_VM_READ | PROCESS_VM_WRITE | SYNCHRONIZE,\n            Process->ProcessId\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhLoadDllProcess(\n            processHandle,\n            &fileName->sr,\n            5000\n            );\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"load the DLL into\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Set I/O priority for a list of processes.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\param Processes Array of process items to operate on.\n * \\param NumberOfProcesses Number of processes in the array.\n * \\param IoPriority The IO priority hint to set.\n * \\return BOOLEAN TRUE if the operation succeeded for all processes, FALSE otherwise.\n */\nBOOLEAN PhUiSetIoPriorityProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses,\n    _In_ IO_PRIORITY_HINT IoPriority\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_SET_INFORMATION,\n            Processes[i]->ProcessId\n            )))\n        {\n            if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID)\n            {\n                status = PhSetProcessIoPriority(processHandle, IoPriority);\n            }\n            else\n            {\n                // See comment in PhUiSetPriorityClassProcesses.\n                status = STATUS_UNSUCCESSFUL;\n            }\n\n            NtClose(processHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to set the I/O priority of \", Processes[i]->ProcessName->Buffer)->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessIoPriority, IoPriority)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorProcess(WindowHandle, L\"set the I/O priority of\", Processes[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorProcess(WindowHandle, L\"set the I/O priority of\", Processes[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\n/**\n * Set page priority for a process.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\param Process The process item to operate on.\n * \\param PagePriority Page priority value to set.\n * \\return BOOLEAN TRUE on success, FALSE on failure.\n */\nBOOLEAN PhUiSetPagePriorityProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ ULONG PagePriority\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION,\n        Process->ProcessId\n        )))\n    {\n        if (Process->ProcessId != SYSTEM_PROCESS_ID)\n        {\n            status = PhSetProcessPagePriority(processHandle, PagePriority);\n        }\n        else\n        {\n            // See comment in PhUiSetPriorityClassProcesses.\n            status = STATUS_UNSUCCESSFUL;\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"set the page priority of\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Set the priority class for a list of processes.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\param Processes Array of process items to operate on.\n * \\param NumberOfProcesses Number of processes in the array.\n * \\param PriorityClass Priority class value to set.\n * \\return BOOLEAN TRUE if the operation succeeded for all processes, FALSE otherwise.\n */\nBOOLEAN PhUiSetPriorityClassProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses,\n    _In_ ULONG PriorityClass\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_SET_INFORMATION,\n            Processes[i]->ProcessId\n            )))\n        {\n            if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID)\n            {\n                status = PhSetProcessPriorityClass(processHandle, (UCHAR)PriorityClass);\n            }\n            else\n            {\n                // Changing the priority of System can lead to a BSOD on some versions of Windows,\n                // so disallow this.\n                status = STATUS_UNSUCCESSFUL;\n            }\n\n            NtClose(processHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to set the priority class of \", Processes[i]->ProcessName->Buffer)->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessPriority, PriorityClass)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorProcess(WindowHandle, L\"set the priority class of\", Processes[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorProcess(WindowHandle, L\"set the priority class of\", Processes[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\n/**\n * Set or clear priority boost for a list of processes.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\param Processes Array of process items to operate on.\n * \\param NumberOfProcesses Number of processes in the array.\n * \\param PriorityBoost TRUE to enable boost, FALSE to disable.\n * \\return BOOLEAN TRUE if the operation succeeded for all processes, FALSE otherwise.\n */\nBOOLEAN PhUiSetBoostPriorityProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM* Processes,\n    _In_ ULONG NumberOfProcesses,\n    _In_ BOOLEAN PriorityBoost\n    )\n{\n    BOOLEAN success = TRUE;\n    ULONG i;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_SET_INFORMATION,\n            Processes[i]->ProcessId\n            )))\n        {\n            status = PhSetProcessPriorityBoost(processHandle, PriorityBoost);\n            NtClose(processHandle);\n\n            if (!NT_SUCCESS(status))\n            {\n                success = FALSE;\n\n                if (!PhpShowErrorProcess(WindowHandle, L\"change boost priority of\", Processes[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\n/**\n * Set or clear priority boost for a single process.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\param Process The process item to operate on.\n * \\param PriorityBoost TRUE to enable boost, FALSE to disable.\n * \\return BOOLEAN TRUE on success, FALSE on failure.\n */\nBOOLEAN PhUiSetBoostPriorityProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ BOOLEAN PriorityBoost\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION,\n        Process->ProcessId\n        )))\n    {\n        status = PhSetProcessPriorityBoost(processHandle, PriorityBoost);\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorProcess(WindowHandle, L\"set the boost priority of\", Process, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n#pragma region Service Progress Dialog\ntypedef struct _PH_UI_SERVICE_PROGRESS_DIALOG\n{\n    HWND WindowHandle;\n    HWND ParentWindowHandle;\n\n    PCWSTR Verb;\n    PCWSTR Message;\n\n    PPH_STRING StatusMessage;\n    PPH_STRING StatusContent;\n\n    PPH_LIST ServiceItemList;\n\n    volatile LONG RequireElevation;\n    struct\n    {\n        BOOLEAN Flags;\n        union\n        {\n            BOOLEAN Warning : 1;\n            BOOLEAN Spare : 7;\n        };\n    };\n\n    WNDPROC OldWndProc;\n    PUSER_THREAD_START_ROUTINE ActionCallback;\n    PHSVC_API_CONTROLSERVICE_COMMAND ActionCommand;\n} PH_UI_SERVICE_PROGRESS_DIALOG, *PPH_UI_SERVICE_PROGRESS_DIALOG;\n\ntypedef struct _PH_UI_SERVICE_ITEM\n{\n    NTSTATUS Status;\n    PPH_SERVICE_ITEM Service;\n} PH_UI_SERVICE_ITEM, *PPH_UI_SERVICE_ITEM;\n\n#define WM_PHSVC_ERROR (WM_APP + 1)\n#define WM_PHSVC_EXIT (WM_APP + 2)\n\nVOID PhShowServiceProgressDialogStatusPage(\n    _In_ PPH_UI_SERVICE_PROGRESS_DIALOG Context\n    );\n#pragma endregion\n\nVOID PhpShowServiceProgressInitializeText(\n    _In_ PPH_UI_SERVICE_PROGRESS_DIALOG Context,\n    _Out_ PPH_STRING* Verb,\n    _Out_ PPH_STRING* VerbCaps,\n    _Out_ PPH_STRING* Action,\n    _Out_ PCWSTR* Object\n    )\n{\n    if (Context->ServiceItemList->Count == 1)\n        *Object = L\"the selected service\";\n    else\n        *Object = L\"the selected services\";\n\n    // Make sure the verb is all lowercase.\n    *Verb = PhaLowerString(PhaCreateString(Context->Verb));\n\n    // \"terminate\" -> \"Terminate\"\n    *VerbCaps = PhaDuplicateString(*Verb);\n    if (!PhIsNullOrEmptyString(*VerbCaps)) (*VerbCaps)->Buffer[0] = PhUpcaseUnicodeChar((*VerbCaps)->Buffer[0]);\n\n    // \"terminate\", \"the process\" -> \"terminate the process\"\n    *Action = PhaConcatStrings(3, (*Verb)->Buffer, L\" \", *Object);\n}\n\nHRESULT CALLBACK PhpUiServiceErrorDialogCallbackProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR Context\n    )\n{\n    PPH_UI_SERVICE_PROGRESS_DIALOG context = (PPH_UI_SERVICE_PROGRESS_DIALOG)Context;\n\n    switch (WindowMessage)\n    {\n    case TDN_NAVIGATED:\n        {\n            if (InterlockedCompareExchange(&context->RequireElevation, FALSE, FALSE))\n            {\n                SendMessage(WindowHandle, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE);\n            }\n        }\n        break;\n    case TDN_BUTTON_CLICKED:\n        {\n            ULONG buttonId = (ULONG)wParam;\n\n            if (buttonId == IDYES)\n            {\n                PhShowServiceProgressDialogStatusPage(context);\n                return S_FALSE;\n            }\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\nVOID PhUiNavigateServiceErrorDialogPage(\n    _In_ PPH_UI_SERVICE_PROGRESS_DIALOG Context,\n    _In_ PPH_STRING MainInstruction,\n    _In_opt_ PPH_STRING MainContent\n    )\n{\n    static CONST TASKDIALOG_BUTTON buttons[1] =\n    {\n        { IDNO, L\"Close\" }\n    };\n    static CONST TASKDIALOG_BUTTON buttonsElevation[2] =\n    {\n        { IDYES, L\"Continue\" },\n        { IDNO, L\"Cancel\" },\n    };\n    TASKDIALOGCONFIG config;\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainIcon = TD_ERROR_ICON;\n    config.lpCallbackData = (LONG_PTR)Context;\n    config.pfCallback = PhpUiServiceErrorDialogCallbackProc;\n    config.pszMainInstruction = PhGetString(MainInstruction);\n    if (MainContent) config.pszContent = PhGetString(MainContent);\n    config.cxWidth = 200;\n\n    if (InterlockedCompareExchange(&Context->RequireElevation, FALSE, FALSE))\n    {\n        config.cButtons = RTL_NUMBER_OF(buttonsElevation);\n        config.pButtons = buttonsElevation;\n        config.nDefaultButton = IDYES;\n    }\n    else\n    {\n        config.cButtons = RTL_NUMBER_OF(buttons);\n        config.pButtons = buttons;\n        config.nDefaultButton = IDNO;\n    }\n\n    PhTaskDialogNavigatePage(Context->WindowHandle, &config);\n}\n\nVOID PhUiNavigateServiceCompleteDialogPage(\n    _In_ PPH_UI_SERVICE_PROGRESS_DIALOG Context\n    )\n{\n    PostMessage(Context->WindowHandle, WM_PHSVC_EXIT, 0, 0);\n}\n\nVOID PhUiNavigateServiceErrorDialogPageFromThread(\n    _In_ PPH_UI_SERVICE_PROGRESS_DIALOG Context\n    )\n{\n    PostMessage(Context->WindowHandle, WM_PHSVC_ERROR, 0, 0);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpUiServicePendingStartCallback(\n    _In_ PPH_UI_SERVICE_PROGRESS_DIALOG Context\n    )\n{\n    PPH_LIST serviceErrorList = PhCreateList(1);\n\n    if (InterlockedCompareExchange(&Context->RequireElevation, FALSE, FALSE))\n    {\n        NTSTATUS status;\n        BOOLEAN connected;\n\n        if (PhpElevationLevelAndConnectToPhSvc(Context->WindowHandle, &connected) && connected)\n        {\n            for (ULONG i = 0; i < Context->ServiceItemList->Count; i++)\n            {\n                PPH_SERVICE_ITEM serviceItem = Context->ServiceItemList->Items[i];\n\n                status = PhSvcCallControlService(\n                    PhGetString(serviceItem->Name),\n                    Context->ActionCommand\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    ULONG index;\n\n                    index = PhFindItemList(Context->ServiceItemList, serviceItem);\n\n                    if (index != ULONG_MAX)\n                    {\n                        PhRemoveItemList(Context->ServiceItemList, index);\n                        PhDereferenceObject(serviceItem);\n                    }\n                }\n                else\n                {\n                    PhAddItemList(serviceErrorList, LongToPtr(status));\n                }\n            }\n\n            PhUiDisconnectFromPhSvc();\n        }\n        else\n        {\n            PhUiNavigateServiceCompleteDialogPage(Context);\n            goto CleanupExit;\n        }\n    }\n    else\n    {\n        for (ULONG i = 0; i < Context->ServiceItemList->Count; i++)\n        {\n            PPH_SERVICE_ITEM serviceItem = Context->ServiceItemList->Items[i];\n            NTSTATUS status;\n\n            status = Context->ActionCallback(serviceItem);\n\n            if (NT_SUCCESS(status))\n            {\n                ULONG index;\n\n                index = PhFindItemList(Context->ServiceItemList, serviceItem);\n\n                if (index != ULONG_MAX)\n                {\n                    PhRemoveItemList(Context->ServiceItemList, index);\n                    PhDereferenceObject(serviceItem);\n                }\n            }\n            else\n            {\n                PhAddItemList(serviceErrorList, LongToPtr(status));\n            }\n        }\n    }\n\n    InterlockedExchange(&Context->RequireElevation, FALSE);\n\n    if (serviceErrorList->Count && !PhGetOwnTokenAttributes().Elevated)\n    {\n        for (ULONG i = 0; i < serviceErrorList->Count; i++)\n        {\n            NTSTATUS status = PtrToLong(serviceErrorList->Items[i]);\n\n            if (status == STATUS_ACCESS_DENIED || status == STATUS_PRIVILEGE_NOT_HELD)\n            {\n                InterlockedExchange(&Context->RequireElevation, TRUE);\n                break;\n            }\n        }\n    }\n\n    if (Context->ServiceItemList->Count)\n    {\n        PH_STRING_BUILDER stringBuilder;\n\n        PhInitializeStringBuilder(&stringBuilder, 0x50);\n\n        for (ULONG i = 0; i < Context->ServiceItemList->Count; i++)\n        {\n            PPH_STRING serviceName = NULL;\n            PPH_STRING statusMessage = NULL;\n\n            if (!PhIsNullOrEmptyString(((PPH_SERVICE_ITEM)Context->ServiceItemList->Items[i])->Name))\n            {\n                serviceName = ((PPH_SERVICE_ITEM)Context->ServiceItemList->Items[i])->Name;\n            }\n\n            if (i < serviceErrorList->Count)\n            {\n                statusMessage = PhGetStatusMessage(PtrToLong(serviceErrorList->Items[i]), 0);\n            }\n\n            if (!PhIsNullOrEmptyString(serviceName))\n                PhAppendStringBuilder(&stringBuilder, &serviceName->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\": \");\n\n            PhAppendFormatStringBuilder(&stringBuilder, L\"(0x%lx) \", PtrToLong(serviceErrorList->Items[i]));\n\n            if (!PhIsNullOrEmptyString(statusMessage))\n            {\n                PhAppendStringBuilder(&stringBuilder, &statusMessage->sr);\n                PhClearReference(&statusMessage);\n            }\n\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n        }\n\n        if (stringBuilder.String->Length != 0)\n        {\n            PhRemoveEndStringBuilder(&stringBuilder, 2);\n        }\n\n        if (InterlockedCompareExchange(&Context->RequireElevation, FALSE, FALSE))\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\\r\\n\");\n            PhAppendStringBuilder2(&stringBuilder, L\"You will need to provide administrator permission. \"\n                L\"Click Continue to complete this operation.\");\n        }\n\n        {\n            PPH_STRING message;\n            PPH_STRING content;\n\n            message = PhFormatString(L\"Unable to %s services:\", Context->Verb);\n            content = PhFinalStringBuilderString(&stringBuilder);\n\n            InterlockedExchangePointer(&Context->StatusMessage, message);\n            InterlockedExchangePointer(&Context->StatusContent, content);\n\n            PhUiNavigateServiceErrorDialogPageFromThread(Context);\n        }\n    }\n    else\n    {\n        PhUiNavigateServiceCompleteDialogPage(Context);\n    }\n\nCleanupExit:\n    PhClearReference(&serviceErrorList);\n\n    PhDereferenceObject(Context);\n\n    return STATUS_SUCCESS;\n}\n\nHRESULT CALLBACK PhpUiServiceProgressDialogCallbackProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR Context\n    )\n{\n    PPH_UI_SERVICE_PROGRESS_DIALOG context = (PPH_UI_SERVICE_PROGRESS_DIALOG)Context;\n\n    switch (WindowMessage)\n    {\n    case TDN_NAVIGATED:\n        {\n            SendMessage(WindowHandle, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n            SendMessage(WindowHandle, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n\n            PhReferenceObject(context);\n            PhCreateThread2(PhpUiServicePendingStartCallback, context);\n        }\n        break;\n    case TDN_BUTTON_CLICKED:\n        {\n            ULONG buttonId = (ULONG)wParam;\n\n            if (buttonId != IDCANCEL)\n            {\n                return S_FALSE;\n            }\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\nVOID PhShowServiceProgressDialogStatusPage(\n    _In_ PPH_UI_SERVICE_PROGRESS_DIALOG Context\n    )\n{\n    TASKDIALOGCONFIG config;\n    PPH_STRING verb;\n    PPH_STRING verbCaps;\n    PPH_STRING action;\n    PCWSTR object;\n\n    PhpShowServiceProgressInitializeText(Context, &verb, &verbCaps, &action, &object);\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CAN_BE_MINIMIZED;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainIcon = TD_INFORMATION_ICON;\n    config.dwCommonButtons = TDCBF_CANCEL_BUTTON;\n    config.lpCallbackData = (LONG_PTR)Context;\n    config.pfCallback = PhpUiServiceProgressDialogCallbackProc;\n    config.pszMainInstruction = PhaConcatStrings(5, L\"Attempting to \", PhGetString(verb), L\" \", object, L\"...\")->Buffer;\n    config.cxWidth = 200;\n\n    PhTaskDialogNavigatePage(Context->WindowHandle, &config);\n}\n\nHRESULT CALLBACK PhpUiServiceConfirmDialogCallbackProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR Context\n    )\n{\n    PPH_UI_SERVICE_PROGRESS_DIALOG context = (PPH_UI_SERVICE_PROGRESS_DIALOG)Context;\n\n    switch (WindowMessage)\n    {\n    case TDN_BUTTON_CLICKED:\n        {\n            ULONG buttonId = (ULONG)wParam;\n\n            if (buttonId == IDYES)\n            {\n                PhShowServiceProgressDialogStatusPage(context);\n                return S_FALSE;\n            }\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\nVOID PhShowServiceProgressDialogConfirmMessage(\n    _In_ PPH_UI_SERVICE_PROGRESS_DIALOG Context\n    )\n{\n    TASKDIALOGCONFIG config;\n    TASKDIALOG_BUTTON buttons[2];\n    PPH_STRING verb;\n    PPH_STRING verbCaps;\n    PPH_STRING action;\n    PCWSTR object;\n\n    PhpShowServiceProgressInitializeText(Context, &verb, &verbCaps, &action, &object);\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED;\n    config.pszWindowTitle = PhApplicationName;\n    config.lpCallbackData = (LONG_PTR)Context;\n    config.pfCallback = PhpUiServiceConfirmDialogCallbackProc;\n    config.pszMainIcon = Context->Warning ? TD_WARNING_ICON : TD_INFORMATION_ICON;\n    config.pszMainInstruction = PhaConcatStrings(3, L\"Do you want to \", action->Buffer, L\"?\")->Buffer;\n    if (Context->Message) config.pszContent = PhaConcatStrings2(Context->Message, L\" Are you sure you want to continue?\")->Buffer;\n\n    buttons[0].nButtonID = IDYES;\n    buttons[0].pszButtonText = verbCaps->Buffer;\n    buttons[1].nButtonID = IDNO;\n    buttons[1].pszButtonText = L\"Cancel\";\n\n    config.cButtons = 2;\n    config.pButtons = buttons;\n    config.nDefaultButton = IDYES;\n    config.cxWidth = 200;\n\n    PhTaskDialogNavigatePage(Context->WindowHandle, &config);\n}\n\nstatic LRESULT CALLBACK PhpUiServiceProgressDialogWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_UI_SERVICE_PROGRESS_DIALOG context;\n    WNDPROC oldWndProc;\n\n    context = PhGetWindowContext(WindowHandle, MAXCHAR);\n\n    if (!context)\n        goto DefaultWndProc;\n\n    oldWndProc = context->OldWndProc;\n\n    switch (WindowMessage)\n    {\n    case WM_DESTROY:\n        {\n            PhSetWindowProcedure(WindowHandle, oldWndProc);\n            PhRemoveWindowContext(WindowHandle, MAXCHAR);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhSetApplicationWindowIconEx(WindowHandle, HIWORD(wParam));\n        }\n        break;\n    case WM_PHSVC_ERROR:\n        {\n            PPH_STRING message;\n            PPH_STRING content;\n\n            message = InterlockedExchangePointer(&context->StatusMessage, NULL);\n            content = InterlockedExchangePointer(&context->StatusContent, NULL);\n\n            PhUiNavigateServiceErrorDialogPage(\n                context,\n                message,\n                content\n                );\n\n            PhClearReference(&message);\n            PhClearReference(&content);\n        }\n        goto DefaultWndProc;\n    case WM_PHSVC_EXIT:\n        {\n            CallWindowProc(oldWndProc, WindowHandle, TDM_CLICK_BUTTON, IDCANCEL, 0);\n        }\n        goto DefaultWndProc;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n\nDefaultWndProc:\n    return DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n}\n\nHRESULT CALLBACK PhpUiServiceInitializeDialogCallbackProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR Context\n    )\n{\n    PPH_UI_SERVICE_PROGRESS_DIALOG context = (PPH_UI_SERVICE_PROGRESS_DIALOG)Context;\n\n    switch (WindowMessage)\n    {\n    case TDN_DIALOG_CONSTRUCTED:\n        {\n            context->WindowHandle = WindowHandle;\n\n            PhSetApplicationWindowIconEx(WindowHandle, PhGetWindowDpi(WindowHandle));\n\n            PhCenterWindow(WindowHandle, context->ParentWindowHandle);\n\n            PhRegisterWindowCallback(WindowHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL);\n\n            context->OldWndProc = PhGetWindowProcedure(WindowHandle);\n            PhSetWindowContext(WindowHandle, MAXCHAR, context);\n            PhSetWindowProcedure(WindowHandle, PhpUiServiceProgressDialogWndProc);\n\n            if (\n                PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) &&\n                context->ActionCommand != PhSvcControlServiceStart\n                )\n            {\n                PhShowServiceProgressDialogConfirmMessage(context);\n            }\n            else\n            {\n                PhShowServiceProgressDialogStatusPage(context);\n            }\n\n            PhInitializeWindowTheme(WindowHandle, !!PhGetIntegerSetting(SETTING_ENABLE_THEME_SUPPORT));\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhShowServiceProgressDialogThread(\n    _In_ PPH_UI_SERVICE_PROGRESS_DIALOG Context\n    )\n{\n    PH_AUTO_POOL autoPool;\n    TASKDIALOGCONFIG config;\n\n    PhInitializeAutoPool(&autoPool);\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED;\n    config.pfCallback = PhpUiServiceInitializeDialogCallbackProc;\n    config.lpCallbackData = (LONG_PTR)Context;\n    config.pszContent = L\"Initializing...\";\n    config.cxWidth = 200;\n\n    PhShowTaskDialog(&config, NULL, NULL, NULL);\n\n    PhDeleteAutoPool(&autoPool);\n    PhDereferenceObject(Context);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nstatic VOID PhServiceProgressContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_UI_SERVICE_PROGRESS_DIALOG context = Object;\n\n    PhDereferenceObjects(context->ServiceItemList->Items, context->ServiceItemList->Count);\n    PhDereferenceObject(context->ServiceItemList);\n}\n\nPPH_UI_SERVICE_PROGRESS_DIALOG PhCreateServiceProgressContext(\n    VOID\n    )\n{\n    static PPH_OBJECT_TYPE PhServiceProgressObjectType = NULL;\n    static PH_INITONCE PhServiceProgressTypeInitOnce = PH_INITONCE_INIT;\n    PPH_UI_SERVICE_PROGRESS_DIALOG context;\n\n    if (PhBeginInitOnce(&PhServiceProgressTypeInitOnce))\n    {\n        PhServiceProgressObjectType = PhCreateObjectType(L\"ServiceProgressObjectType\", 0, PhServiceProgressContextDeleteProcedure);\n        PhEndInitOnce(&PhServiceProgressTypeInitOnce);\n    }\n\n    context = PhCreateObject(sizeof(PH_UI_SERVICE_PROGRESS_DIALOG), PhServiceProgressObjectType);\n    memset(context, 0, sizeof(PH_UI_SERVICE_PROGRESS_DIALOG));\n\n    return context;\n}\n\nVOID PhShowServiceProgressDialog(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Verb,\n    _In_ PCWSTR Message,\n    _In_ BOOLEAN Warning,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices,\n    _In_ PUSER_THREAD_START_ROUTINE ActionCallback,\n    _In_ PHSVC_API_CONTROLSERVICE_COMMAND ActionCommand\n    )\n{\n    PPH_UI_SERVICE_PROGRESS_DIALOG context;\n\n    if (NumberOfServices == 0)\n        return;\n\n    PhReferenceObjects(Services, NumberOfServices);\n\n    context = PhCreateServiceProgressContext();\n    context->ParentWindowHandle = WindowHandle;\n    context->Verb = Verb;\n    context->Message = Message;\n    context->Warning = Warning;\n    context->ActionCallback = ActionCallback;\n    context->ActionCommand = ActionCommand;\n    context->ServiceItemList = PhCreateList(NumberOfServices);\n    PhAddItemsList(context->ServiceItemList, Services, NumberOfServices);\n\n    PhCreateThread2(PhShowServiceProgressDialogThread, context);\n}\n\nstatic BOOLEAN PhpShowContinueMessageServices(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Verb,\n    _In_ PCWSTR Message,\n    _In_ BOOLEAN Warning,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    )\n{\n    if (NumberOfServices == 0)\n        return FALSE;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        PCWSTR object;\n\n        if (NumberOfServices == 1)\n        {\n            object = L\"the selected service\";\n        }\n        else\n        {\n            object = L\"the selected services\";\n        }\n\n        return PhShowConfirmMessage(\n            WindowHandle,\n            Verb,\n            object,\n            Message,\n            Warning\n            );\n    }\n    else\n    {\n        return TRUE;\n    }\n}\n\nstatic BOOLEAN PhpShowErrorService(\n    _In_ HWND WindowHandle,\n    _In_ PWSTR Verb,\n    _In_ PPH_SERVICE_ITEM Service,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    return PhShowContinueStatus(\n        WindowHandle,\n        PhaFormatString(\n        L\"Unable to %s %s.\",\n        Verb,\n        Service->Name->Buffer\n        )->Buffer,\n        Status,\n        Win32Result\n        );\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhUiServiceStartCallback(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    NTSTATUS status;\n    SC_HANDLE serviceHandle;\n\n    status = PhOpenService(\n        &serviceHandle,\n        SERVICE_START,\n        PhGetString(ServiceItem->Name)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhStartService(serviceHandle, 0, NULL);\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    return status;\n}\n\nBOOLEAN PhUiStartServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_SERVICE_PROGRESS_DIALOG))\n    {\n        PhShowServiceProgressDialog(\n            WindowHandle,\n            L\"start\",\n            L\"Starting a service might prevent the system from functioning properly.\",\n            FALSE,\n            Services,\n            NumberOfServices,\n            PhUiServiceStartCallback,\n            PhSvcControlServiceStart\n            );\n        return FALSE;\n    }\n\n    if (!PhpShowContinueMessageServices(\n        WindowHandle,\n        L\"start\",\n        L\"Starting a service might prevent the system from functioning properly.\",\n        FALSE,\n        Services,\n        NumberOfServices\n        ))\n        return FALSE;\n\n    for (i = 0; i < NumberOfServices; i++)\n    {\n        NTSTATUS status;\n        SC_HANDLE serviceHandle;\n\n        success = FALSE;\n        status = PhOpenService(&serviceHandle, SERVICE_START, PhGetString(Services[i]->Name));\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhStartService(serviceHandle, 0, NULL);\n\n            if (NT_SUCCESS(status))\n                success = TRUE;\n\n            PhCloseServiceHandle(serviceHandle);\n        }\n\n        if (!success)\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to start \", PhGetString(Services[i]->Name))->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Services[i]->Name), PhSvcControlServiceStart)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorService(WindowHandle, L\"start\", Services[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorService(WindowHandle, L\"start\", Services[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n\n    //BOOLEAN result = TRUE;\n    //ULONG i;\n    //\n    //for (i = 0; i < NumberOfServices; i++)\n    //{\n    //    SC_HANDLE serviceHandle;\n    //    BOOLEAN success = FALSE;\n    //\n    //    serviceHandle = PhOpenService(PhGetString(Services[i]->Name), SERVICE_START);\n    //\n    //    if (serviceHandle)\n    //    {\n    //        if (StartService(serviceHandle, 0, NULL))\n    //            success = TRUE;\n    //\n    //        PhCloseServiceHandle(serviceHandle);\n    //    }\n    //\n    //    if (!success)\n    //    {\n    //        NTSTATUS status;\n    //\n    //        status = PhGetLastWin32ErrorAsNtStatus();\n    //        result = FALSE;\n    //\n    //        PhpShowErrorService(WindowHandle, L\"start\", Services[i], status, 0);\n    //    }\n    //}\n    //\n    //return result;\n}\n\nBOOLEAN PhUiStartService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    )\n{\n    SC_HANDLE serviceHandle;\n    NTSTATUS status;\n    BOOLEAN success = FALSE;\n\n    status = PhOpenService(&serviceHandle, SERVICE_START, PhGetString(Service->Name));\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhStartService(serviceHandle, 0, NULL);\n\n        if (NT_SUCCESS(status))\n            success = TRUE;\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    if (!success)\n    {\n        BOOLEAN connected;\n        BOOLEAN cancelled;\n\n        if (PhpShowErrorAndConnectToPhSvc(\n            WindowHandle,\n            PhaConcatStrings2(L\"Unable to start \", PhGetString(Service->Name))->Buffer,\n            status,\n            &connected,\n            &cancelled\n            ))\n        {\n            if (connected)\n            {\n                if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Service->Name), PhSvcControlServiceStart)))\n                    success = TRUE;\n                else\n                    PhpShowErrorService(WindowHandle, L\"start\", Service, status, 0);\n\n                PhUiDisconnectFromPhSvc();\n            }\n        }\n        else\n        {\n            if (!cancelled)\n            {\n                PhpShowErrorService(WindowHandle, L\"start\", Service, status, 0);\n            }\n        }\n    }\n\n    return success;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhUiServiceContinueCallback(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    NTSTATUS status;\n    SC_HANDLE serviceHandle;\n\n    status = PhOpenService(\n        &serviceHandle,\n        SERVICE_PAUSE_CONTINUE,\n        PhGetString(ServiceItem->Name)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhContinueService(serviceHandle);\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    return status;\n}\n\nBOOLEAN PhUiContinueServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_SERVICE_PROGRESS_DIALOG))\n    {\n        PhShowServiceProgressDialog(\n            WindowHandle,\n            L\"continue\",\n            L\"Continuing a service might prevent the system from functioning properly.\",\n            FALSE,\n            Services,\n            NumberOfServices,\n            PhUiServiceContinueCallback,\n            PhSvcControlServiceContinue\n            );\n        return FALSE;\n    }\n\n    if (!PhpShowContinueMessageServices(\n        WindowHandle,\n        L\"continue\",\n        L\"Continuing a service might prevent the system from functioning properly.\",\n        FALSE,\n        Services,\n        NumberOfServices\n        ))\n        return FALSE;\n\n    for (i = 0; i < NumberOfServices; i++)\n    {\n        NTSTATUS status;\n        SC_HANDLE serviceHandle;\n\n        success = FALSE;\n        status = PhOpenService(&serviceHandle, SERVICE_PAUSE_CONTINUE, PhGetString(Services[i]->Name));\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhContinueService(serviceHandle);\n\n            if (NT_SUCCESS(status))\n                success = TRUE;\n\n            PhCloseServiceHandle(serviceHandle);\n        }\n\n        if (!success)\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to continue \", PhGetString(Services[i]->Name))->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Services[i]->Name), PhSvcControlServiceContinue)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorService(WindowHandle, L\"continue\", Services[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorService(WindowHandle, L\"continue\", Services[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n\n    //BOOLEAN result = TRUE;\n    //ULONG i;\n    //\n    //for (i = 0; i < NumberOfServices; i++)\n    //{\n    //    SC_HANDLE serviceHandle;\n    //    BOOLEAN success = FALSE;\n    //\n    //    serviceHandle = PhOpenService(PhGetString(Services[i]->Name), SERVICE_PAUSE_CONTINUE);\n    //\n    //    if (serviceHandle)\n    //    {\n    //        SERVICE_STATUS serviceStatus;\n    //\n    //        if (ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus))\n    //            success = TRUE;\n    //\n    //        PhCloseServiceHandle(serviceHandle);\n    //    }\n    //\n    //    if (!success)\n    //    {\n    //        NTSTATUS status;\n    //\n    //        status = PhGetLastWin32ErrorAsNtStatus();\n    //        result = FALSE;\n    //\n    //        PhpShowErrorService(WindowHandle, L\"continue\", Services[i], status, 0);\n    //    }\n    //}\n    //\n    //return result;\n}\n\nBOOLEAN PhUiContinueService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    )\n{\n    SC_HANDLE serviceHandle;\n    NTSTATUS status;\n    BOOLEAN success = FALSE;\n\n    status = PhOpenService(&serviceHandle, SERVICE_PAUSE_CONTINUE, PhGetString(Service->Name));\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhContinueService(serviceHandle);\n\n        if (NT_SUCCESS(status))\n            success = TRUE;\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    if (!success)\n    {\n        BOOLEAN connected;\n        BOOLEAN cancelled;\n\n        if (PhpShowErrorAndConnectToPhSvc(\n            WindowHandle,\n            PhaConcatStrings2(L\"Unable to continue \", PhGetString(Service->Name))->Buffer,\n            status,\n            &connected,\n            &cancelled\n            ))\n        {\n            if (connected)\n            {\n                if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Service->Name), PhSvcControlServiceContinue)))\n                    success = TRUE;\n                else\n                    PhpShowErrorService(WindowHandle, L\"continue\", Service, status, 0);\n\n                PhUiDisconnectFromPhSvc();\n            }\n        }\n        else\n        {\n            if (!cancelled)\n            {\n                PhpShowErrorService(WindowHandle, L\"continue\", Service, status, 0);\n            }\n        }\n    }\n\n    return success;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhUiServicePauseCallback(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    NTSTATUS status;\n    SC_HANDLE serviceHandle;\n\n    status = PhOpenService(\n        &serviceHandle,\n        SERVICE_PAUSE_CONTINUE,\n        PhGetString(ServiceItem->Name)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhPauseService(serviceHandle);\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    return status;\n}\n\nBOOLEAN PhUiPauseServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_SERVICE_PROGRESS_DIALOG))\n    {\n        PhShowServiceProgressDialog(\n            WindowHandle,\n            L\"pause\",\n            L\"Pausing a service might prevent the system from functioning properly.\",\n            FALSE,\n            Services,\n            NumberOfServices,\n            PhUiServicePauseCallback,\n            PhSvcControlServicePause\n            );\n        return FALSE;\n    }\n\n    if (!PhpShowContinueMessageServices(\n        WindowHandle,\n        L\"pause\",\n        L\"Pausing a service might prevent the system from functioning properly.\",\n        FALSE,\n        Services,\n        NumberOfServices\n        ))\n        return FALSE;\n\n    for (i = 0; i < NumberOfServices; i++)\n    {\n        NTSTATUS status;\n        SC_HANDLE serviceHandle;\n\n        success = FALSE;\n        status = PhOpenService(&serviceHandle, SERVICE_PAUSE_CONTINUE, PhGetString(Services[i]->Name));\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhPauseService(serviceHandle);\n\n            if (NT_SUCCESS(status))\n                success = TRUE;\n\n            PhCloseServiceHandle(serviceHandle);\n        }\n\n        if (!success)\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to pause \", PhGetString(Services[i]->Name))->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Services[i]->Name), PhSvcControlServicePause)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorService(WindowHandle, L\"pause\", Services[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorService(WindowHandle, L\"pause\", Services[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n\n    //BOOLEAN result = TRUE;\n    //ULONG i;\n    //\n    //for (i = 0; i < NumberOfServices; i++)\n    //{\n    //    SC_HANDLE serviceHandle;\n    //    BOOLEAN success = FALSE;\n    //\n    //    serviceHandle = PhOpenService(PhGetString(Services[i]->Name), SERVICE_PAUSE_CONTINUE);\n    //\n    //    if (serviceHandle)\n    //    {\n    //        SERVICE_STATUS serviceStatus;\n    //\n    //        if (ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus))\n    //            success = TRUE;\n    //\n    //        PhCloseServiceHandle(serviceHandle);\n    //    }\n    //\n    //    if (!success)\n    //    {\n    //        NTSTATUS status;\n    //\n    //        status = PhGetLastWin32ErrorAsNtStatus();\n    //        result = FALSE;\n    //\n    //        PhpShowErrorService(WindowHandle, L\"pause\", Services[i], status, 0);\n    //    }\n    //}\n    //\n    //return result;\n}\n\nBOOLEAN PhUiPauseService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    )\n{\n    SC_HANDLE serviceHandle;\n    NTSTATUS status;\n    BOOLEAN success = FALSE;\n\n    status = PhOpenService(&serviceHandle, SERVICE_PAUSE_CONTINUE, PhGetString(Service->Name));\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhPauseService(serviceHandle);\n\n        if (NT_SUCCESS(status))\n            success = TRUE;\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    if (!success)\n    {\n        BOOLEAN connected;\n        BOOLEAN cancelled;\n\n        if (PhpShowErrorAndConnectToPhSvc(\n            WindowHandle,\n            PhaConcatStrings2(L\"Unable to pause \", Service->Name->Buffer)->Buffer,\n            status,\n            &connected,\n            &cancelled\n            ))\n        {\n            if (connected)\n            {\n                if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Service->Name), PhSvcControlServicePause)))\n                    success = TRUE;\n                else\n                    PhpShowErrorService(WindowHandle, L\"pause\", Service, status, 0);\n\n                PhUiDisconnectFromPhSvc();\n            }\n        }\n        else\n        {\n            if (!cancelled)\n            {\n                PhpShowErrorService(WindowHandle, L\"pause\", Service, status, 0);\n            }\n        }\n    }\n\n    return success;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhUiServiceStopCallback(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    NTSTATUS status;\n    SC_HANDLE serviceHandle;\n\n    status = PhOpenService(\n        &serviceHandle,\n        SERVICE_STOP,\n        PhGetString(ServiceItem->Name)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhStopService(serviceHandle);\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    return status;\n}\n\nBOOLEAN PhUiStopServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_SERVICE_PROGRESS_DIALOG))\n    {\n        PhShowServiceProgressDialog(\n            WindowHandle,\n            L\"stop\",\n            L\"Stopping a service might prevent the system from functioning properly.\",\n            FALSE,\n            Services,\n            NumberOfServices,\n            PhUiServiceStopCallback,\n            PhSvcControlServiceStop\n            );\n        return FALSE;\n    }\n\n    if (!PhpShowContinueMessageServices(\n        WindowHandle,\n        L\"stop\",\n        L\"Stopping a service might prevent the system from functioning properly.\",\n        FALSE,\n        Services,\n        NumberOfServices\n        ))\n        return FALSE;\n\n    for (i = 0; i < NumberOfServices; i++)\n    {\n        NTSTATUS status;\n        SC_HANDLE serviceHandle;\n\n        success = FALSE;\n        status = PhOpenService(&serviceHandle, SERVICE_STOP, PhGetString(Services[i]->Name));\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhStopService(serviceHandle);\n\n            if (NT_SUCCESS(status))\n                success = TRUE;\n\n            PhCloseServiceHandle(serviceHandle);\n        }\n\n        if (!success)\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to stop \", PhGetString(Services[i]->Name))->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Services[i]->Name), PhSvcControlServiceStop)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorService(WindowHandle, L\"stop\", Services[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorService(WindowHandle, L\"stop\", Services[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n\n    //BOOLEAN result = TRUE;\n    //ULONG i;\n    //\n    //for (i = 0; i < NumberOfServices; i++)\n    //{\n    //    SC_HANDLE serviceHandle;\n    //    BOOLEAN success = FALSE;\n    //\n    //    serviceHandle = PhOpenService(PhGetString(Services[i]->Name), SERVICE_STOP);\n    //\n    //    if (serviceHandle)\n    //    {\n    //        SERVICE_STATUS serviceStatus;\n    //\n    //        if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus))\n    //            success = TRUE;\n    //\n    //        PhCloseServiceHandle(serviceHandle);\n    //    }\n    //\n    //    if (!success)\n    //    {\n    //        NTSTATUS status;\n    //\n    //        status = PhGetLastWin32ErrorAsNtStatus();\n    //        result = FALSE;\n    //\n    //        PhpShowErrorService(WindowHandle, L\"stop\", Services[i], status, 0);\n    //    }\n    //}\n    //\n    //return result;\n}\n\nBOOLEAN PhUiStopService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    )\n{\n    SC_HANDLE serviceHandle;\n    NTSTATUS status;\n    BOOLEAN success = FALSE;\n\n    status = PhOpenService(&serviceHandle, SERVICE_STOP, PhGetString(Service->Name));\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhStopService(serviceHandle);\n\n        if (NT_SUCCESS(status))\n            success = TRUE;\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    if (!success)\n    {\n        BOOLEAN connected;\n        BOOLEAN cancelled;\n\n        if (PhpShowErrorAndConnectToPhSvc(\n            WindowHandle,\n            PhaConcatStrings2(L\"Unable to stop \", PhGetString(Service->Name))->Buffer,\n            status,\n            &connected,\n            &cancelled\n            ))\n        {\n            if (connected)\n            {\n                if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Service->Name), PhSvcControlServiceStop)))\n                    success = TRUE;\n                else\n                    PhpShowErrorService(WindowHandle, L\"stop\", Service, status, 0);\n\n                PhUiDisconnectFromPhSvc();\n            }\n        }\n        else\n        {\n            PhpShowErrorService(WindowHandle, L\"stop\", Service, status, 0);\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhUiDeleteService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    )\n{\n    SC_HANDLE serviceHandle;\n    NTSTATUS status;\n    BOOLEAN success = FALSE;\n\n    // Warnings cannot be disabled for service deletion.\n    if (!PhShowConfirmMessage(\n        WindowHandle,\n        L\"delete\",\n        Service->Name->Buffer,\n        L\"Deleting a service can prevent the system from starting \"\n        L\"or functioning properly.\",\n        TRUE\n        ))\n        return FALSE;\n\n    status = PhOpenService(&serviceHandle, DELETE, PhGetString(Service->Name));\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhDeleteService(serviceHandle);\n\n        if (NT_SUCCESS(status))\n            success = TRUE;\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    if (!success)\n    {\n        BOOLEAN connected;\n        BOOLEAN cancelled;\n\n        if (PhpShowErrorAndConnectToPhSvc(\n            WindowHandle,\n            PhaConcatStrings2(L\"Unable to delete \", PhGetString(Service->Name))->Buffer,\n            status,\n            &connected,\n            &cancelled\n            ))\n        {\n            if (connected)\n            {\n                if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Service->Name), PhSvcControlServiceDelete)))\n                    success = TRUE;\n                else\n                    PhpShowErrorService(WindowHandle, L\"delete\", Service, status, 0);\n\n                PhUiDisconnectFromPhSvc();\n            }\n        }\n        else\n        {\n            PhpShowErrorService(WindowHandle, L\"delete\", Service, status, 0);\n        }\n    }\n\n    return success;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhUiServiceRestartCallback(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n)\n{\n    NTSTATUS status;\n    SC_HANDLE serviceHandle;\n\n    status = PhOpenService(\n        &serviceHandle,\n        SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP,\n        PhGetString(ServiceItem->Name)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhStopService(serviceHandle);\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhWaitForServiceStatus(\n                serviceHandle,\n                SERVICE_STOPPED,\n                60 * 1000\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhStartService(serviceHandle, 0, NULL);\n\n                if (NT_SUCCESS(status))\n                {\n                    status = PhWaitForServiceStatus(\n                        serviceHandle,\n                        SERVICE_RUNNING,\n                        60 * 1000\n                        );\n                }\n            }\n        }\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    return status;\n}\n\nBOOLEAN PhUiRestartServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_SERVICE_PROGRESS_DIALOG))\n    {\n        PhShowServiceProgressDialog(\n            WindowHandle,\n            L\"restart\",\n            L\"Restarting a service might prevent the system from functioning properly.\",\n            FALSE,\n            Services,\n            NumberOfServices,\n            PhUiServiceRestartCallback,\n            PhSvcControlServiceRestart\n            );\n        return FALSE;\n    }\n\n    if (!PhpShowContinueMessageServices(\n        WindowHandle,\n        L\"restart\",\n        L\"Restarting a service might prevent the system from functioning properly.\",\n        FALSE,\n        Services,\n        NumberOfServices\n        ))\n        return FALSE;\n\n    for (i = 0; i < NumberOfServices; i++)\n    {\n        NTSTATUS status;\n        SC_HANDLE serviceHandle;\n\n        success = FALSE;\n        status = PhOpenService(\n            &serviceHandle,\n            SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP,\n            PhGetString(Services[i]->Name)\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhStopService(serviceHandle);\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhWaitForServiceStatus(\n                    serviceHandle,\n                    SERVICE_STOPPED,\n                    60 * 1000\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    status = PhStartService(serviceHandle, 0, NULL);\n\n                    if (NT_SUCCESS(status))\n                    {\n                        status = PhWaitForServiceStatus(\n                            serviceHandle,\n                            SERVICE_RUNNING,\n                            60 * 1000\n                            );\n\n                        if (NT_SUCCESS(status))\n                        {\n                            success = TRUE;\n                        }\n                    }\n                }\n            }\n\n            PhCloseServiceHandle(serviceHandle);\n        }\n\n        if (!success)\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to restart \", PhGetString(Services[i]->Name))->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlService(PhGetString(Services[i]->Name), PhSvcControlServiceRestart)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorService(WindowHandle, L\"restart\", Services[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorService(WindowHandle, L\"restart\", Services[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhUiCloseConnections(\n    _In_ HWND WindowHandle,\n    _In_ PPH_NETWORK_ITEM *Connections,\n    _In_ ULONG NumberOfConnections\n    )\n{\n    static ULONG (WINAPI* SetTcpEntry_I)(_In_ PMIB_TCPROW pTcpRow) = NULL;\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG result;\n    ULONG i;\n    MIB_TCPROW tcpRow;\n\n    if (!SetTcpEntry_I)\n    {\n        SetTcpEntry_I = PhGetDllProcedureAddressZ(L\"iphlpapi.dll\", \"SetTcpEntry\", 0);\n    }\n\n    if (!SetTcpEntry_I)\n    {\n        PhShowStatus(WindowHandle, L\"Unable to close the TCP connection\", STATUS_NOT_SUPPORTED, 0);\n        return FALSE;\n    }\n\n    for (i = 0; i < NumberOfConnections; i++)\n    {\n        if (Connections[i]->State != MIB_TCP_STATE_ESTAB)\n            continue;\n\n        result = PhSetTcpEntry(Connections[i]);\n\n        if (NT_SUCCESS(result))\n            continue;\n\n        if (Connections[i]->ProtocolType != PH_NETWORK_PROTOCOL_TCP4)\n            continue;\n\n        tcpRow.dwState = MIB_TCP_STATE_DELETE_TCB;\n        tcpRow.dwLocalAddr = Connections[i]->LocalEndpoint.Address.InAddr.s_addr;\n        tcpRow.dwLocalPort = _byteswap_ushort((USHORT)Connections[i]->LocalEndpoint.Port);\n        tcpRow.dwRemoteAddr = Connections[i]->RemoteEndpoint.Address.InAddr.s_addr;\n        tcpRow.dwRemotePort = _byteswap_ushort((USHORT)Connections[i]->RemoteEndpoint.Port);\n\n        if ((result = SetTcpEntry_I(&tcpRow)) != NO_ERROR)\n        {\n            NTSTATUS status;\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            // SetTcpEntry returns ERROR_MR_MID_NOT_FOUND for access denied errors for some reason.\n            if (result == ERROR_MR_MID_NOT_FOUND)\n                result = ERROR_ACCESS_DENIED;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                L\"Unable to close the TCP connection\",\n                PhDosErrorToNtStatus(result),\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallSetTcpEntry(&tcpRow)))\n                        success = TRUE;\n                    else\n                        PhShowStatus(WindowHandle, L\"Unable to close the TCP connection\", status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (PhShowMessage2(\n                    WindowHandle,\n                    TD_OK_BUTTON,\n                    TD_ERROR_ICON,\n                    L\"Unable to close the TCP connection.\",\n                    L\"Make sure System Informer is running with administrative privileges.\"\n                    ) != IDOK)\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\nstatic BOOLEAN PhpShowContinueMessageThreads(\n    _In_ HWND WindowHandle,\n    _In_ PWSTR Verb,\n    _In_ PWSTR Message,\n    _In_ BOOLEAN Warning,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads\n    )\n{\n    PWSTR object;\n    BOOLEAN cont = FALSE;\n\n    if (NumberOfThreads == 0)\n        return FALSE;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        if (NumberOfThreads == 1)\n        {\n            object = L\"the selected thread\";\n        }\n        else\n        {\n            object = L\"the selected threads\";\n        }\n\n        cont = PhShowConfirmMessage(\n            WindowHandle,\n            Verb,\n            object,\n            Message,\n            Warning\n            );\n    }\n    else\n    {\n        cont = TRUE;\n    }\n\n    return cont;\n}\n\nstatic BOOLEAN PhpShowErrorThread(\n    _In_ HWND WindowHandle,\n    _In_ PWSTR Verb,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    return PhShowContinueStatus(\n        WindowHandle,\n        PhaFormatString(\n        L\"Unable to %s thread %lu\",\n        Verb,\n        HandleToUlong(Thread->ThreadId)\n        )->Buffer,\n        Status,\n        Win32Result\n        );\n}\n\nBOOLEAN PhUiTerminateThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    if (!PhpShowContinueMessageThreads(\n        WindowHandle,\n        L\"terminate\",\n        L\"Terminating a thread may cause the process to stop working.\",\n        FALSE,\n        Threads,\n        NumberOfThreads\n        ))\n        return FALSE;\n\n    for (i = 0; i < NumberOfThreads; i++)\n    {\n        NTSTATUS status;\n        HANDLE threadHandle;\n\n        if (NT_SUCCESS(status = PhOpenThread(\n            &threadHandle,\n            THREAD_TERMINATE,\n            Threads[i]->ThreadId\n            )))\n        {\n            status = PhTerminateThread(threadHandle, STATUS_SUCCESS);\n\n            if (status == STATUS_SUCCESS || status == STATUS_THREAD_IS_TERMINATING)\n                PhTerminateThread(threadHandle, DBG_TERMINATE_THREAD); // debug terminate (dmex)\n\n            NtClose(threadHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaFormatString(L\"Unable to terminate thread %lu\", HandleToUlong(Threads[i]->ThreadId))->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadTerminate, 0)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorThread(WindowHandle, L\"terminate\", Threads[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorThread(WindowHandle, L\"terminate\", Threads[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhUiSuspendThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    for (i = 0; i < NumberOfThreads; i++)\n    {\n        NTSTATUS status;\n        HANDLE threadHandle;\n\n        if (NT_SUCCESS(status = PhOpenThread(\n            &threadHandle,\n            THREAD_SUSPEND_RESUME,\n            Threads[i]->ThreadId\n            )))\n        {\n            status = NtSuspendThread(threadHandle, NULL);\n            NtClose(threadHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaFormatString(L\"Unable to suspend thread %lu\", HandleToUlong(Threads[i]->ThreadId))->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadSuspend, 0)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorThread(WindowHandle, L\"suspend\", Threads[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorThread(WindowHandle, L\"suspend\", Threads[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhUiResumeThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads\n    )\n{\n    BOOLEAN success = TRUE;\n    BOOLEAN cancelled = FALSE;\n    ULONG i;\n\n    for (i = 0; i < NumberOfThreads; i++)\n    {\n        NTSTATUS status;\n        HANDLE threadHandle;\n\n        if (NT_SUCCESS(status = PhOpenThread(\n            &threadHandle,\n            THREAD_SUSPEND_RESUME,\n            Threads[i]->ThreadId\n            )))\n        {\n            status = NtResumeThread(threadHandle, NULL);\n            NtClose(threadHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            BOOLEAN connected;\n\n            success = FALSE;\n\n            if (!cancelled && PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaFormatString(L\"Unable to resume thread %lu\", HandleToUlong(Threads[i]->ThreadId))->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadResume, 0)))\n                        success = TRUE;\n                    else\n                        PhpShowErrorThread(WindowHandle, L\"resume\", Threads[i], status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n                else\n                {\n                    cancelled = TRUE;\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    break;\n\n                if (!PhpShowErrorThread(WindowHandle, L\"resume\", Threads[i], status, 0))\n                    break;\n            }\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhUiSetBoostPriorityThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads,\n    _In_ BOOLEAN PriorityBoost\n    )\n{\n    BOOLEAN success = TRUE;\n    ULONG i;\n\n    for (i = 0; i < NumberOfThreads; i++)\n    {\n        NTSTATUS status;\n        HANDLE threadHandle;\n\n        status = PhOpenThread(\n            &threadHandle,\n            THREAD_SET_LIMITED_INFORMATION,\n            Threads[i]->ThreadId\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhSetThreadPriorityBoost(threadHandle, PriorityBoost);\n            NtClose(threadHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            success = FALSE;\n\n            if (!PhpShowErrorThread(WindowHandle, L\"change boost priority of\", Threads[i], status, 0))\n                break;\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhUiSetBoostPriorityThread(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ BOOLEAN PriorityBoost\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n\n    if (NT_SUCCESS(status = PhOpenThread(\n        &threadHandle,\n        THREAD_SET_LIMITED_INFORMATION,\n        Thread->ThreadId\n        )))\n    {\n        status = PhSetThreadPriorityBoost(threadHandle, PriorityBoost);\n        NtClose(threadHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorThread(WindowHandle, L\"set the boost priority of\", Thread, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nBOOLEAN PhUiSetPriorityThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads,\n    _In_ LONG Increment\n    )\n{\n    BOOLEAN success = TRUE;\n    ULONG i;\n\n    // Special saturation values\n    if (Increment == THREAD_PRIORITY_TIME_CRITICAL)\n        Increment = THREAD_BASE_PRIORITY_LOWRT + 1;\n    else if (Increment == THREAD_PRIORITY_IDLE)\n        Increment = THREAD_BASE_PRIORITY_IDLE - 1;\n\n    for (i = 0; i < NumberOfThreads; i++)\n    {\n        NTSTATUS status;\n        HANDLE threadHandle;\n\n        status = PhOpenThread(\n            &threadHandle,\n            THREAD_SET_LIMITED_INFORMATION,\n            Threads[i]->ThreadId\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhSetThreadBasePriority(threadHandle, Increment);\n            NtClose(threadHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            success = FALSE;\n\n            if (!PhpShowErrorThread(WindowHandle, L\"change priority of\", Threads[i], status, 0))\n                break;\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhUiSetPriorityThread(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ LONG Increment\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n\n    if (NT_SUCCESS(status = PhOpenThread(\n        &threadHandle,\n        THREAD_SET_LIMITED_INFORMATION,\n        Thread->ThreadId\n        )))\n    {\n        status = PhSetThreadBasePriority(threadHandle, Increment);\n        NtClose(threadHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorThread(WindowHandle, L\"set the priority of\", Thread, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nBOOLEAN PhUiSetIoPriorityThread(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ IO_PRIORITY_HINT IoPriority\n    )\n{\n    NTSTATUS status;\n    BOOLEAN success = TRUE;\n    HANDLE threadHandle;\n\n    if (NT_SUCCESS(status = PhOpenThread(\n        &threadHandle,\n        THREAD_SET_INFORMATION,\n        Thread->ThreadId\n        )))\n    {\n        status = PhSetThreadIoPriority(threadHandle, IoPriority);\n        NtClose(threadHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        BOOLEAN connected;\n        BOOLEAN cancelled;\n\n        success = FALSE;\n\n        // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.\n        if (PhpShowErrorAndConnectToPhSvc(\n            WindowHandle,\n            PhaFormatString(L\"Unable to set the I/O priority of thread %lu\", HandleToUlong(Thread->ThreadId))->Buffer,\n            status,\n            &connected,\n            &cancelled\n            ))\n        {\n            if (connected)\n            {\n                if (NT_SUCCESS(status = PhSvcCallControlThread(Thread->ThreadId, PhSvcControlThreadIoPriority, IoPriority)))\n                    success = TRUE;\n                else\n                    PhpShowErrorThread(WindowHandle, L\"set the I/O priority of\", Thread, status, 0);\n\n                PhUiDisconnectFromPhSvc();\n            }\n        }\n        else\n        {\n            PhpShowErrorThread(WindowHandle, L\"set the I/O priority of\", Thread, status, 0);\n        }\n    }\n\n    return success;\n}\n\nBOOLEAN PhUiSetPagePriorityThread(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ ULONG PagePriority\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n\n    if (NT_SUCCESS(status = PhOpenThread(\n        &threadHandle,\n        THREAD_SET_INFORMATION,\n        Thread->ThreadId\n        )))\n    {\n        status = PhSetThreadPagePriority(threadHandle, PagePriority);\n\n        NtClose(threadHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorThread(WindowHandle, L\"set the page priority of\", Thread, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nBOOLEAN PhUiUnloadModule(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_MODULE_ITEM Module\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    HANDLE processHandle = NULL;\n    BOOLEAN cont = FALSE;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        PWSTR verb;\n        PWSTR message;\n\n        switch (Module->Type)\n        {\n        case PH_MODULE_TYPE_MODULE:\n        case PH_MODULE_TYPE_WOW64_MODULE:\n            verb = L\"unload\";\n            message = L\"Unloading a module may cause the process to crash.\";\n\n            if (WindowsVersion >= WINDOWS_8)\n                message = L\"Unloading a module may cause the process to crash. NOTE: This feature may not work correctly on your version of Windows and some programs may restrict access or ban your account.\";\n\n            break;\n        case PH_MODULE_TYPE_KERNEL_MODULE:\n            verb = L\"unload\";\n            message = L\"Unloading a driver may cause system instability.\";\n            break;\n        case PH_MODULE_TYPE_MAPPED_FILE:\n        case PH_MODULE_TYPE_MAPPED_IMAGE:\n            verb = L\"unmap\";\n            message = L\"Unmapping a section view may cause the process to crash.\";\n            break;\n        default:\n            return FALSE;\n        }\n\n        cont = PhShowConfirmMessage(\n            WindowHandle,\n            verb,\n            Module->Name->Buffer,\n            message,\n            TRUE\n            );\n    }\n    else\n    {\n        cont = TRUE;\n    }\n\n    if (!cont)\n        return FALSE;\n\n    switch (Module->Type)\n    {\n    case PH_MODULE_TYPE_MODULE:\n    case PH_MODULE_TYPE_WOW64_MODULE:\n        {\n            if (WindowsVersion < WINDOWS_8)\n            {\n                // Windows 7 requires QUERY_INFORMATION for MemoryMappedFileName. (dmex)\n\n                status = PhOpenProcess(\n                    &processHandle,\n                    PROCESS_QUERY_INFORMATION | PROCESS_SET_LIMITED_INFORMATION |\n                    PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |\n                    PROCESS_VM_READ | PROCESS_VM_WRITE,\n                    ProcessId\n                    );\n            }\n            else if (WindowsVersion < WINDOWS_10)\n            {\n                // Windows 8 requires ALL_ACCESS for PLM execution requests. (dmex)\n\n                status = PhOpenProcess(\n                    &processHandle,\n                    PROCESS_ALL_ACCESS,\n                    ProcessId\n                    );\n            }\n\n            if (!NT_SUCCESS(status))\n            {\n                // Windows 10 and above require SET_LIMITED for PLM execution requests. (dmex)\n\n                status = PhOpenProcess(\n                    &processHandle,\n                    PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_LIMITED_INFORMATION |\n                    PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |\n                    PROCESS_VM_READ | PROCESS_VM_WRITE,\n                    ProcessId\n                    );\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhUnloadDllProcess(\n                    processHandle,\n                    Module->BaseAddress,\n                    5000\n                    );\n\n                NtClose(processHandle);\n            }\n\n            if (status == STATUS_DLL_NOT_FOUND)\n            {\n                PhShowStatus(WindowHandle, L\"Unable to unload the module\", 0, ERROR_MOD_NOT_FOUND);\n                return FALSE;\n            }\n\n            if (!NT_SUCCESS(status))\n            {\n                PhShowStatus(\n                    WindowHandle,\n                    PhaConcatStrings2(L\"Unable to unload \", Module->Name->Buffer)->Buffer,\n                    status,\n                    0\n                    );\n                return FALSE;\n            }\n        }\n        break;\n\n    case PH_MODULE_TYPE_KERNEL_MODULE:\n        status = PhUnloadDriver(Module->BaseAddress, &Module->Name->sr, &Module->FileName->sr);\n\n        if (!NT_SUCCESS(status))\n        {\n            BOOLEAN success = FALSE;\n            BOOLEAN connected;\n            BOOLEAN cancelled;\n\n            if (PhpShowErrorAndConnectToPhSvc(\n                WindowHandle,\n                PhaConcatStrings2(L\"Unable to unload \", Module->Name->Buffer)->Buffer,\n                status,\n                &connected,\n                &cancelled\n                ))\n            {\n                if (connected)\n                {\n                    if (NT_SUCCESS(status = PhSvcCallUnloadDriver(Module->BaseAddress, Module->Name->Buffer, Module->FileName->Buffer)))\n                        success = TRUE;\n                    else\n                        PhShowStatus(WindowHandle, PhaConcatStrings2(L\"Unable to unload \", Module->Name->Buffer)->Buffer, status, 0);\n\n                    PhUiDisconnectFromPhSvc();\n                }\n            }\n            else\n            {\n                if (cancelled)\n                    return FALSE;\n\n                PhShowStatus(\n                    WindowHandle,\n                    PhaConcatStrings(\n                    3,\n                    L\"Unable to unload \",\n                    Module->Name->Buffer,\n                    L\". Make sure System Informer is running with \"\n                    L\"administrative privileges.\"\n                    )->Buffer,\n                    status,\n                    0\n                    );\n                return FALSE;\n            }\n\n            return success;\n        }\n\n        break;\n\n    case PH_MODULE_TYPE_MAPPED_FILE:\n    case PH_MODULE_TYPE_MAPPED_IMAGE:\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_VM_OPERATION,\n            ProcessId\n            )))\n        {\n            status = PhUnmapViewOfSection(processHandle, Module->BaseAddress);\n            NtClose(processHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhShowStatus(\n                WindowHandle,\n                PhaFormatString(L\"Unable to unmap the section view at 0x%p\", Module->BaseAddress)->Buffer,\n                status,\n                0\n                );\n            return FALSE;\n        }\n\n        break;\n\n    default:\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nBOOLEAN PhUiFreeMemory(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_MEMORY_ITEM MemoryItem,\n    _In_ BOOLEAN Free\n    )\n{\n    NTSTATUS status;\n    BOOLEAN cont = FALSE;\n    HANDLE processHandle;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        PWSTR verb;\n        PWSTR message;\n\n        if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))\n        {\n            if (Free)\n            {\n                verb = L\"free\";\n                message = L\"Freeing memory regions may cause the process to crash.\\r\\n\\r\\nSome programs may also restrict access or ban your account when freeing the memory of the process.\";\n            }\n            else\n            {\n                verb = L\"decommit\";\n                message = L\"Decommitting memory regions may cause the process to crash.\\r\\n\\r\\nSome programs may also restrict access or ban your account when decommitting the memory of the process.\";\n            }\n        }\n        else\n        {\n            verb = L\"unmap\";\n            message = L\"Unmapping a section view may cause the process to crash.\\r\\n\\r\\nSome programs may also restrict access or ban your account when unmapping the memory of the process.\";\n        }\n\n        cont = PhShowConfirmMessage(\n            WindowHandle,\n            verb,\n            L\"the memory region\",\n            message,\n            TRUE\n            );\n    }\n    else\n    {\n        cont = TRUE;\n    }\n\n    if (!cont)\n        return FALSE;\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_VM_OPERATION,\n        ProcessId\n        )))\n    {\n        PVOID baseAddress;\n        SIZE_T regionSize;\n\n        baseAddress = MemoryItem->BaseAddress;\n\n        if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))\n        {\n            // The size needs to be 0 if we're freeing.\n            if (Free)\n                regionSize = 0;\n            else\n                regionSize = MemoryItem->RegionSize;\n\n            status = NtFreeVirtualMemory(\n                processHandle,\n                &baseAddress,\n                &regionSize,\n                Free ? MEM_RELEASE : MEM_DECOMMIT\n                );\n        }\n        else\n        {\n            status = PhUnmapViewOfSection(processHandle, baseAddress);\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PWSTR message;\n\n        if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))\n        {\n            if (Free)\n                message = L\"Unable to free the memory region\";\n            else\n                message = L\"Unable to decommit the memory region\";\n        }\n        else\n        {\n            message = L\"Unable to unmap the section view\";\n        }\n\n        PhShowStatus(\n            WindowHandle,\n            message,\n            status,\n            0\n            );\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nBOOLEAN PhUiEmptyProcessMemoryWorkingSet(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_MEMORY_ITEM MemoryItem\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_VM_OPERATION,\n        ProcessId\n        )))\n    {\n        status = PhSetProcessEmptyPageWorkingSet(\n            processHandle,\n            MemoryItem->BaseAddress,\n            MemoryItem->RegionSize\n            );\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to empty the region working set.\", status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nstatic BOOLEAN PhpShowErrorHandle(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Verb,\n    _In_ PCWSTR Verb2,\n    _In_ PPH_HANDLE_ITEM Handle,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    WCHAR value[PH_PTR_STR_LEN_1];\n\n    PhPrintPointer(value, (PVOID)Handle->Handle);\n\n    if (!PhIsNullOrEmptyString(Handle->BestObjectName))\n    {\n        return PhShowContinueStatus(\n            WindowHandle,\n            PhaFormatString(\n            L\"Unable to %s handle \\\"%s\\\" (%s)%s\",\n            Verb,\n            Handle->BestObjectName->Buffer,\n            value,\n            Verb2\n            )->Buffer,\n            Status,\n            Win32Result\n            );\n    }\n    else\n    {\n        return PhShowContinueStatus(\n            WindowHandle,\n            PhaFormatString(\n            L\"Unable to %s handle %s%s\",\n            Verb,\n            value,\n            Verb2\n            )->Buffer,\n            Status,\n            Win32Result\n            );\n    }\n}\n\nBOOLEAN PhUiCloseHandles(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_HANDLE_ITEM *Handles,\n    _In_ ULONG NumberOfHandles,\n    _In_ BOOLEAN Warn\n    )\n{\n    NTSTATUS status;\n    BOOLEAN result = FALSE;\n    BOOLEAN success = TRUE;\n    HANDLE processHandle;\n\n    if (NumberOfHandles == 0)\n        return FALSE;\n\n    if (Warn && PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n    {\n        result = PhShowConfirmMessage(\n            WindowHandle,\n            L\"close\",\n            NumberOfHandles == 1 ? L\"the selected handle\" : L\"the selected handles\",\n            L\"Closing handles may cause system instability and data corruption.\",\n            FALSE\n            );\n    }\n    else\n    {\n        result = TRUE;\n    }\n\n    if (!result)\n        return FALSE;\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE,\n        ProcessId\n        )))\n    {\n        BOOLEAN critical = FALSE;\n        BOOLEAN strict = FALSE;\n\n        if (WindowsVersion >= WINDOWS_10)\n        {\n            BOOLEAN breakOnTermination;\n            PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;\n\n            if (NT_SUCCESS(PhGetProcessBreakOnTermination(\n                processHandle,\n                &breakOnTermination\n                )))\n            {\n                if (breakOnTermination)\n                {\n                    critical = TRUE;\n                }\n            }\n\n            if (NT_SUCCESS(PhGetProcessMitigationPolicy(\n                processHandle,\n                ProcessStrictHandleCheckPolicy,\n                &policyInfo\n                )))\n            {\n                if (policyInfo.StrictHandleCheckPolicy.Flags != 0)\n                {\n                    strict = TRUE;\n                }\n            }\n        }\n\n        if (critical && strict)\n        {\n            result = PhShowConfirmMessage(\n                WindowHandle,\n                L\"close\",\n                L\"critical process handle(s)\",\n                L\"You are about to close one or more handles for a critical process with strict handle checks enabled. This will shut down the operating system immediately.\\r\\n\\r\\n\",\n                TRUE\n                );\n        }\n\n        if (!result)\n            return FALSE;\n\n        for (ULONG i = 0; i < NumberOfHandles; i++)\n        {\n            if (FlagOn(Handles[i]->Attributes, OBJ_PROTECT_CLOSE))\n            {\n                if (!PhpShowErrorHandle(\n                    WindowHandle,\n                    L\"close\",\n                    NULL,\n                    Handles[i],\n                    STATUS_HANDLE_NOT_CLOSABLE,\n                    0\n                    ))\n                {\n                    break;\n                }\n            }\n\n            status = NtDuplicateObject(\n                processHandle,\n                Handles[i]->Handle,\n                NULL,\n                NULL,\n                0,\n                0,\n                DUPLICATE_CLOSE_SOURCE\n                );\n\n            if (!NT_SUCCESS(status))\n            {\n                success = FALSE;\n\n                if (!PhpShowErrorHandle(\n                    WindowHandle,\n                    L\"close\",\n                    NULL,\n                    Handles[i],\n                    status,\n                    0\n                    ))\n                    break;\n            }\n        }\n\n        NtClose(processHandle);\n    }\n    else\n    {\n        PhShowStatus(WindowHandle, L\"Unable to open the process\", status, 0);\n        return FALSE;\n    }\n\n    return success;\n}\n\nBOOLEAN PhUiSetAttributesHandle(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_HANDLE_ITEM Handle,\n    _In_ ULONG Attributes\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    if (KsiLevel() < KphLevelMax)\n    {\n        PhShowKsiNotConnected(\n            WindowHandle,\n            L\"Setting handle attributes requires a connection to the kernel driver.\"\n            );\n        return FALSE;\n    }\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION,\n        ProcessId\n        )))\n    {\n        OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;\n\n        handleFlagInfo.Inherit = !!(Attributes & OBJ_INHERIT);\n        handleFlagInfo.ProtectFromClose = !!(Attributes & OBJ_PROTECT_CLOSE);\n\n        status = KphSetInformationObject(\n            processHandle,\n            Handle->Handle,\n            KphObjectHandleFlagInformation,\n            &handleFlagInfo,\n            sizeof(OBJECT_HANDLE_FLAG_INFORMATION)\n            );\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhpShowErrorHandle(WindowHandle, L\"set attributes of\", NULL, Handle, status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Flush process heap(s) remotely for a list of processes.\n *\n * \\param WindowHandle Parent window used for error reporting.\n * \\param Processes Array of process items to operate on.\n * \\param NumberOfProcesses Number of processes in the array.\n * \\return BOOLEAN TRUE if all flush operations succeeded, FALSE if any failed.\n */\nBOOLEAN PhUiFlushHeapProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    BOOLEAN success = TRUE;\n    ULONG i;\n    LARGE_INTEGER timeout;\n\n    for (i = 0; i < NumberOfProcesses; i++)\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_CREATE_THREAD | PROCESS_QUERY_LIMITED_INFORMATION |\n            PROCESS_SET_LIMITED_INFORMATION | PROCESS_VM_READ,\n            Processes[i]->ProcessId\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhFlushProcessHeapsRemote(processHandle, PhTimeoutFromMilliseconds(&timeout, 4000));\n            NtClose(processHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            success = FALSE;\n\n            if (!PhpShowErrorProcess(WindowHandle, L\"flush the process heap(s) of\", Processes[i], status, 0))\n                break;\n        }\n    }\n\n    return success;\n}\n"
  },
  {
    "path": "SystemInformer/admintask.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <appsup.h>\n#include <taskschd.h>\n#include <secwmi.h>\n#include <phconsole.h>\n#include <trace.h>\n\nDEFINE_GUID(CLSID_TaskScheduler, 0x0f87369f, 0xa4e5, 0x4cfc, 0xbd, 0x3e, 0x73, 0xe6, 0x15, 0x45, 0x72, 0xdd);\nDEFINE_GUID(IID_ITaskService, 0x2FABA4C7, 0x4DA9, 0x4013, 0x96, 0x97, 0x20, 0xCC, 0x3F, 0xD4, 0x0F, 0x85);\nDEFINE_GUID(IID_ITaskSettings2, 0x2C05C3F0, 0x6EED, 0x4C05, 0xA1, 0x5F, 0xED, 0x7D, 0x7A, 0x98, 0xA3, 0x69);\nDEFINE_GUID(IID_ILogonTrigger, 0x72DADE38, 0xFAE4, 0x4b3e, 0xBA, 0xF4, 0x5D, 0x00, 0x9A, 0xF0, 0x2B, 0x1C);\nDEFINE_GUID(IID_IExecAction, 0x4C3D624D, 0xfd6b, 0x49A3, 0xB9, 0xB7, 0x09, 0xCB, 0x3C, 0xD3, 0xF0, 0x47);\n\nHRESULT PhCreateAdminTask(\n    _In_ PPH_STRINGREF TaskName,\n    _In_ PPH_STRINGREF FileName\n    )\n{\n    static CONST PH_STRINGREF taskTimeLimit = PH_STRINGREF_INIT(L\"PT0S\");\n#if (PH_ADMIN_TASK_FORWARD_COMMANDLINE_UNPRIVILEGED)\n    static CONST PH_STRINGREF taskArguments = PH_STRINGREF_INIT(L\"$(Arg0)\");\n#endif\n    HRESULT status;\n    BSTR taskNameString = NULL;\n    BSTR taskFileNameString = NULL;\n#if (PH_ADMIN_TASK_FORWARD_COMMANDLINE_UNPRIVILEGED)\n    BSTR taskArgumentsString = NULL;\n#endif\n    BSTR taskFolderString = NULL;\n    BSTR taskTimeLimitString = NULL;\n    VARIANT empty = { VT_EMPTY };\n    ITaskService* taskService = NULL;\n    ITaskFolder* taskFolder = NULL;\n    ITaskDefinition* taskDefinition = NULL;\n    ITaskSettings* taskSettings = NULL;\n    ITaskSettings2* taskSettings2 = NULL;\n    ITriggerCollection* taskTriggerCollection = NULL;\n    ITrigger* taskTrigger = NULL;\n    ILogonTrigger* taskLogonTrigger = NULL;\n    IRegisteredTask* taskRegisteredTask = NULL;\n    IPrincipal* taskPrincipal = NULL;\n    IActionCollection* taskActionCollection = NULL;\n    IAction* taskAction = NULL;\n    IExecAction* taskExecAction = NULL;\n\n    status = PhGetClassObject(\n        L\"taskschd.dll\",\n        &CLSID_TaskScheduler,\n        &IID_ITaskService,\n        &taskService\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    taskNameString = PhStringRefToBSTR(TaskName);\n    taskFileNameString = PhStringRefToBSTR(FileName);\n    taskFolderString = PhStringRefToBSTR(&PhNtPathSeparatorString);\n    taskTimeLimitString = PhStringRefToBSTR(&taskTimeLimit);\n#if (PH_ADMIN_TASK_FORWARD_COMMANDLINE_UNPRIVILEGED)\n    taskArgumentsString = PhStringRefToBSTR(&taskArguments);\n#endif\n\n    status = ITaskService_Connect(\n        taskService,\n        empty,\n        empty,\n        empty,\n        empty\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = ITaskService_GetFolder(\n        taskService,\n        taskFolderString,\n        &taskFolder\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = ITaskService_NewTask(\n        taskService,\n        0,\n        &taskDefinition\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = ITaskDefinition_get_Settings(\n        taskDefinition,\n        &taskSettings\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    ITaskSettings_put_Compatibility(taskSettings, TASK_COMPATIBILITY_V2_1);\n    ITaskSettings_put_StartWhenAvailable(taskSettings, VARIANT_TRUE);\n    ITaskSettings_put_DisallowStartIfOnBatteries(taskSettings, VARIANT_FALSE);\n    ITaskSettings_put_StopIfGoingOnBatteries(taskSettings, VARIANT_FALSE);\n    ITaskSettings_put_ExecutionTimeLimit(taskSettings, taskTimeLimitString);\n    ITaskSettings_put_Priority(taskSettings, 1);\n\n    if (SUCCEEDED(ITaskSettings_QueryInterface(\n        taskSettings,\n        &IID_ITaskSettings2,\n        &taskSettings2\n        )))\n    {\n        ITaskSettings2_put_UseUnifiedSchedulingEngine(taskSettings2, VARIANT_TRUE);\n        ITaskSettings2_put_DisallowStartOnRemoteAppSession(taskSettings2, VARIANT_TRUE);\n        ITaskSettings2_Release(taskSettings2);\n    }\n\n    //status = ITaskDefinition_get_Triggers(\n    //    taskDefinition,\n    //    &taskTriggerCollection\n    //    );\n    //\n    //if (FAILED(status))\n    //    goto CleanupExit;\n    //\n    //status = ITriggerCollection_Create(\n    //    taskTriggerCollection,\n    //    TASK_TRIGGER_LOGON,\n    //    &taskTrigger\n    //    );\n    //\n    //if (FAILED(status))\n    //    goto CleanupExit;\n    //\n    //status = ITrigger_QueryInterface(\n    //    taskTrigger,\n    //    &IID_ILogonTrigger,\n    //    &taskLogonTrigger\n    //    );\n    //\n    //if (FAILED(status))\n    //    goto CleanupExit;\n    //\n    //ILogonTrigger_put_Id(taskLogonTrigger, L\"LogonTriggerId\");\n    //ILogonTrigger_put_UserId(taskLogonTrigger, PhGetString(PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE)));\n\n    status = ITaskDefinition_get_Principal(\n        taskDefinition,\n        &taskPrincipal\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n#define TASK_RUNLEVEL_LUA 0\n#define TASK_RUNLEVEL_HIGHEST 1\n#define RUNLEVEL_ADMIN 2\n#define RUNLEVEL_MAX_NON_UIA 3\n#define RUNLEVEL_LUA_UIA 4\n#define RUNLEVEL_HIGHEST_UIA 5\n#define RUNLEVEL_ADMIN_UIA 6\n#define RUNLEVEL_MAX 7\n\n    IPrincipal_put_RunLevel(taskPrincipal, TASK_RUNLEVEL_HIGHEST);\n    IPrincipal_put_LogonType(taskPrincipal, TASK_LOGON_INTERACTIVE_TOKEN);\n\n    status = ITaskDefinition_get_Actions(\n        taskDefinition,\n        &taskActionCollection\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = IActionCollection_Create(\n        taskActionCollection,\n        TASK_ACTION_EXEC,\n        &taskAction\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = IAction_QueryInterface(\n        taskAction,\n        &IID_IExecAction,\n        &taskExecAction\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = IExecAction_put_Path(\n        taskExecAction,\n        taskFileNameString\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n#if (PH_ADMIN_TASK_FORWARD_COMMANDLINE_UNPRIVILEGED)\n    status = IExecAction_put_Arguments(\n        taskExecAction,\n        taskArgumentsString\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n#endif\n\n    ITaskFolder_DeleteTask(\n        taskFolder,\n        taskNameString,\n        0\n        );\n\n    status = ITaskFolder_RegisterTaskDefinition(\n        taskFolder,\n        taskNameString,\n        taskDefinition,\n        TASK_CREATE_OR_UPDATE,\n        empty,\n        empty,\n        TASK_LOGON_INTERACTIVE_TOKEN,\n        empty,\n        &taskRegisteredTask\n        );\n\nCleanupExit:\n\n    if (taskRegisteredTask)\n        IRegisteredTask_Release(taskRegisteredTask);\n    if (taskActionCollection)\n        IActionCollection_Release(taskActionCollection);\n    if (taskPrincipal)\n        IPrincipal_Release(taskPrincipal);\n    if (taskLogonTrigger)\n        ILogonTrigger_Release(taskLogonTrigger);\n    if (taskTrigger)\n        ITrigger_Release(taskTrigger);\n    if (taskTriggerCollection)\n        ITriggerCollection_Release(taskTriggerCollection);\n    if (taskSettings)\n        ITaskSettings_Release(taskSettings);\n    if (taskDefinition)\n        ITaskDefinition_Release(taskDefinition);\n    if (taskFolder)\n        ITaskFolder_Release(taskFolder);\n    if (taskService)\n        ITaskService_Release(taskService);\n    if (taskTimeLimitString)\n        SysFreeString(taskTimeLimitString);\n    if (taskNameString)\n        SysFreeString(taskNameString);\n    if (taskFileNameString)\n        SysFreeString(taskFileNameString);\n#if (PH_ADMIN_TASK_FORWARD_COMMANDLINE_UNPRIVILEGED)\n    if (taskArgumentsString)\n        SysFreeString(taskArgumentsString);\n#endif\n    if (taskFolderString)\n        SysFreeString(taskFolderString);\n\n    return status;\n}\n\nHRESULT PhDeleteAdminTask(\n    _In_ PPH_STRINGREF TaskName\n    )\n{\n    HRESULT status;\n    BSTR taskNameString = NULL;\n    BSTR taskFolderString = NULL;\n    VARIANT empty = { VT_EMPTY };\n    ITaskService* taskService = NULL;\n    ITaskFolder* taskFolder = NULL;\n\n    status = PhGetClassObject(\n        L\"taskschd.dll\",\n        &CLSID_TaskScheduler,\n        &IID_ITaskService,\n        &taskService\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    taskNameString = PhStringRefToBSTR(TaskName);\n    taskFolderString = PhStringRefToBSTR(&PhNtPathSeparatorString);\n\n    status = ITaskService_Connect(\n        taskService,\n        empty,\n        empty,\n        empty,\n        empty\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = ITaskService_GetFolder(\n        taskService,\n        taskFolderString,\n        &taskFolder\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = ITaskFolder_DeleteTask(\n        taskFolder,\n        taskNameString,\n        0\n        );\n\nCleanupExit:\n\n    if (taskFolder)\n        ITaskFolder_Release(taskFolder);\n    if (taskService)\n        ITaskService_Release(taskService);\n    if (taskFolderString)\n        SysFreeString(taskFolderString);\n    if (taskNameString)\n        SysFreeString(taskNameString);\n\n    return status;\n}\n\nHRESULT PhRunAsAdminTask(\n    _In_ PPH_STRINGREF TaskName\n    )\n{\n    HRESULT status;\n    ULONG sessionId = ULONG_MAX;\n    BSTR taskNameString = NULL;\n    BSTR taskFolderString = NULL;\n    VARIANT empty = { VT_EMPTY };\n    VARIANT params = { VT_EMPTY };\n    ITaskService* taskService = NULL;\n    ITaskFolder* taskFolder = NULL;\n    IRegisteredTask* taskRegisteredTask = NULL;\n    IRunningTask* taskRunningTask = NULL;\n\n    PhTraceFuncEnter(\"Run as admin task\");\n\n    status = PhGetClassObject(\n        L\"taskschd.dll\",\n        &CLSID_TaskScheduler,\n        &IID_ITaskService,\n        &taskService\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    taskNameString = PhStringRefToBSTR(TaskName);\n    taskFolderString = PhStringRefToBSTR(&PhNtPathSeparatorString);\n\n    status = ITaskService_Connect(\n        taskService,\n        empty,\n        empty,\n        empty,\n        empty\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = ITaskService_GetFolder(\n        taskService,\n        taskFolderString,\n        &taskFolder\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = ITaskFolder_GetTask(\n        taskFolder,\n        taskNameString,\n        &taskRegisteredTask\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n#if (PH_ADMIN_TASK_FORWARD_COMMANDLINE_UNPRIVILEGED)\n    if (CommandLine)\n    {\n        PH_STRINGREF commandline;\n\n        if (NT_SUCCESS(PhGetProcessCommandLineStringRef(&commandline)))\n        {\n            V_VT(&params) = VT_BSTR;\n            V_BSTR(&params) = PhStringRefToBSTR(&commandline);\n        }\n    }\n#endif\n\n    status = IRegisteredTask_RunEx(\n        taskRegisteredTask,\n        params,\n        TASK_RUN_AS_SELF | TASK_RUN_USE_SESSION_ID,\n        USER_SHARED_DATA->ActiveConsoleId,\n        NULL,\n        &taskRunningTask\n        );\n\nCleanupExit:\n\n    if (taskRunningTask)\n        IRunningTask_Release(taskRunningTask);\n    if (taskRegisteredTask)\n        IRegisteredTask_Release(taskRegisteredTask);\n    if (taskFolder)\n        ITaskFolder_Release(taskFolder);\n    if (taskService)\n        ITaskService_Release(taskService);\n#if (PH_ADMIN_TASK_FORWARD_COMMANDLINE_UNPRIVILEGED)\n    if (V_BSTR(&params))\n        SysFreeString(V_BSTR(&params));\n#endif\n    if (taskFolderString)\n        SysFreeString(taskFolderString);\n    if (taskNameString)\n        SysFreeString(taskNameString);\n\n    PhTraceFuncExit(\"Run as admin task: %!STATUS!\", status);\n\n    return status;\n}\n\nNTSTATUS PhRunAsAdminTaskUIAccess(\n    VOID\n    )\n{\n    NTSTATUS status;\n    BOOLEAN tokenIsUIAccess;\n    ULONG sessionId;\n    CLIENT_ID desktopId;\n    PPH_STRING fileName = NULL;\n\n    PhTraceFuncEnter(\"Run as admin task UI access\");\n\n    if (!PhGetOwnTokenAttributes().Elevated)\n    {\n        status = STATUS_UNSUCCESSFUL;\n        goto CleanupExit;\n    }\n\n    if (!NT_SUCCESS(PhGetTokenUIAccess(\n        PhGetOwnTokenAttributes().TokenHandle,\n        &tokenIsUIAccess\n        )) || tokenIsUIAccess)\n    {\n        status = STATUS_UNSUCCESSFUL;\n        goto CleanupExit;\n    }\n\n    fileName = PhGetApplicationFileNameWin32();\n\n    if (PhIsNullOrEmptyString(fileName))\n    {\n        status = STATUS_UNSUCCESSFUL;\n        goto CleanupExit;\n    }\n\n    // Query the process from the current desktop.\n\n    status = PhGetWindowClientId(PhGetShellWindow(), &desktopId);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Query the session from the current process.\n\n    status = PhGetProcessSessionId(NtCurrentProcess(), &sessionId);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhExecuteRunAsCommand3(\n        NULL,\n        PhGetString(fileName),\n        NULL,\n        NULL,\n        LOGON32_LOGON_INTERACTIVE,\n        desktopId.UniqueProcess,\n        sessionId,\n        NULL,\n        TRUE,\n        FALSE,\n        TRUE\n        );\n\nCleanupExit:\n\n    PhClearReference(&fileName);\n\n    PhTraceFuncExit(\"Run as admin task UI access: %!STATUS!\", status);\n\n    return status;\n}\n"
  },
  {
    "path": "SystemInformer/affinity.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2020-2023\n *\n */\n\n/*\n * The affinity dialog was originally created to support the modification\n * of process affinity masks, but now supports modifying thread affinity\n * and generic masks.\n */\n\n#include <phapp.h>\n#include <procprv.h>\n#include <thrdprv.h>\n\ntypedef struct _PH_AFFINITY_DIALOG_CONTEXT\n{\n    HWND WindowHandle;\n    HWND GroupComboHandle;\n\n    PPH_PROCESS_ITEM ProcessItem;\n    PPH_THREAD_ITEM ThreadItem;\n    KAFFINITY NewAffinityMask;\n\n    PPH_LIST CpuControlList;\n    USHORT AffinityGroup;\n    KAFFINITY AffinityMask;\n    KAFFINITY SystemAffinityMask;\n\n    // Multiple selected items (dmex)\n    PPH_THREAD_ITEM* Threads;\n    ULONG NumberOfThreads;\n    PHANDLE ThreadHandles;\n} PH_AFFINITY_DIALOG_CONTEXT, *PPH_AFFINITY_DIALOG_CONTEXT;\n\nINT_PTR CALLBACK PhpProcessAffinityDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowProcessAffinityDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_opt_ PPH_PROCESS_ITEM ProcessItem,\n    _In_opt_ PPH_THREAD_ITEM ThreadItem\n    )\n{\n    PH_AFFINITY_DIALOG_CONTEXT context;\n\n    assert(!!ProcessItem != !!ThreadItem); // make sure we have one and not the other (wj32)\n\n    memset(&context, 0, sizeof(PH_AFFINITY_DIALOG_CONTEXT));\n    context.ProcessItem = ProcessItem;\n    context.ThreadItem = ThreadItem;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_AFFINITY),\n        ParentWindowHandle,\n        PhpProcessAffinityDlgProc,\n        &context\n        );\n}\n\n_Success_(return)\nBOOLEAN PhShowProcessAffinityDialog2(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _Out_ PKAFFINITY NewAffinityMask\n    )\n{\n    PH_AFFINITY_DIALOG_CONTEXT context;\n\n    memset(&context, 0, sizeof(PH_AFFINITY_DIALOG_CONTEXT));\n    context.ProcessItem = ProcessItem;\n    context.ThreadItem = NULL;\n\n    if (PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_AFFINITY),\n        ParentWindowHandle,\n        PhpProcessAffinityDlgProc,\n        &context\n        ) == IDOK)\n    {\n        *NewAffinityMask = context.NewAffinityMask;\n\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\nVOID PhShowThreadAffinityDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_THREAD_ITEM* Threads,\n    _In_ ULONG NumberOfThreads\n    )\n{\n    PH_AFFINITY_DIALOG_CONTEXT context;\n\n    memset(&context, 0, sizeof(PH_AFFINITY_DIALOG_CONTEXT));\n    context.Threads = Threads;\n    context.NumberOfThreads = NumberOfThreads;\n    context.ThreadHandles = PhAllocateZero(NumberOfThreads * sizeof(HANDLE));\n\n    // Cache handles to each thread since the ThreadId gets\n    // reassigned to a different process after the thread exits. (dmex)\n    for (ULONG i = 0; i < NumberOfThreads; i++)\n    {\n        if (!NT_SUCCESS(PhOpenThread(\n            &context.ThreadHandles[i],\n            THREAD_QUERY_LIMITED_INFORMATION | THREAD_SET_LIMITED_INFORMATION | THREAD_SET_INFORMATION,\n            Threads[i]->ThreadId\n            )))\n        {\n            if (!NT_SUCCESS(PhOpenThread(\n                &context.ThreadHandles[i],\n                THREAD_QUERY_LIMITED_INFORMATION | THREAD_SET_LIMITED_INFORMATION,\n                Threads[i]->ThreadId\n                )))\n            {\n                context.ThreadHandles[i] = INVALID_HANDLE_VALUE;\n            }\n        }\n    }\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_AFFINITY),\n        ParentWindowHandle,\n        PhpProcessAffinityDlgProc,\n        &context\n        );\n}\n\nstatic BOOLEAN PhpShowProcessErrorAffinity(\n    _In_ HWND hWnd,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    return PhShowContinueStatus(\n        hWnd,\n        PhaFormatString(\n        L\"Unable to change affinity of process %lu\",\n        HandleToUlong(Process->ProcessId)\n        )->Buffer,\n        Status,\n        Win32Result\n        );\n}\n\nstatic BOOLEAN PhpShowThreadErrorAffinity(\n    _In_ HWND hWnd,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    return PhShowContinueStatus(\n        hWnd,\n        PhaFormatString(\n        L\"Unable to change affinity of thread %lu\",\n        HandleToUlong(Thread->ThreadId)\n        )->Buffer,\n        Status,\n        Win32Result\n        );\n}\n\nVOID PhpShowThreadErrorAffinityList(\n    _In_ PPH_AFFINITY_DIALOG_CONTEXT Context,\n    _Inout_ PPH_LIST AffinityErrorsList\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n\n    for (ULONG i = 0; i < AffinityErrorsList->Count; i++)\n    {\n        PhAppendFormatStringBuilder(\n            &stringBuilder,\n            L\"%s\\n\",\n            PhGetStringOrDefault(AffinityErrorsList->Items[i], L\"An unknown error occurred.\")\n            );\n    }\n\n    if (PhEndsWithStringRef2(&stringBuilder.String->sr, L\"\\n\", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhShowInformation2(\n        Context->WindowHandle,\n        L\"Unable to update affinity for thread(s)\",\n        L\"Unable to update affinity for thread(s):\\r\\n%s\",\n        PhGetString(PhFinalStringBuilderString(&stringBuilder))\n        );\n\n    PhDeleteStringBuilder(&stringBuilder);\n    PhDereferenceObjects(AffinityErrorsList->Items, AffinityErrorsList->Count);\n    PhDereferenceObject(AffinityErrorsList);\n}\n\nBOOLEAN PhpCheckThreadsHaveSameAffinity(\n    _In_ PPH_AFFINITY_DIALOG_CONTEXT Context\n    )\n{\n    BOOLEAN result = TRUE;\n    GROUP_AFFINITY groupAffinity;\n    KAFFINITY lastAffinityMask = 0;\n    KAFFINITY affinityMask = 0;\n\n    if (Context->ThreadHandles[0] != INVALID_HANDLE_VALUE)\n    {\n        if (NT_SUCCESS(PhGetThreadGroupAffinity(Context->ThreadHandles[0], &groupAffinity)))\n        {\n            lastAffinityMask = groupAffinity.Mask;\n        }\n    }\n\n    for (ULONG i = 0; i < Context->NumberOfThreads; i++)\n    {\n        if (Context->ThreadHandles[i] == INVALID_HANDLE_VALUE)\n            continue;\n\n        if (NT_SUCCESS(PhGetThreadGroupAffinity(Context->ThreadHandles[i], &groupAffinity)))\n        {\n            affinityMask = groupAffinity.Mask;\n        }\n\n        if (lastAffinityMask != affinityMask)\n        {\n            result = FALSE;\n            break;\n        }\n    }\n\n    return result;\n}\n\nINT_PTR CALLBACK PhpProcessAffinityDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_AFFINITY_DIALOG_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_AFFINITY_DIALOG_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            NTSTATUS status = STATUS_UNSUCCESSFUL;\n            BOOLEAN differentAffinity = FALSE;\n            ULONG i;\n\n            context->WindowHandle = hwndDlg;\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            {\n                context->CpuControlList = PhCreateList(MAXIMUM_PROC_PER_GROUP);\n\n                for (i = 0; i < MAXIMUM_PROC_PER_GROUP; i++)\n                {\n                    PhAddItemList(context->CpuControlList, GetDlgItem(hwndDlg, IDC_CPU0 + i));\n                }\n            }\n\n            if (!PhSystemProcessorInformation.SingleProcessorGroup)\n            {\n                context->GroupComboHandle = GetDlgItem(hwndDlg, IDC_GROUPCPU);\n\n                for (USHORT processorGroup = 0; processorGroup < PhSystemProcessorInformation.NumberOfProcessorGroups; processorGroup++)\n                {\n                    ComboBox_AddString(context->GroupComboHandle, PhaFormatString(L\"Group %hu\", processorGroup)->Buffer);\n                }\n\n                ShowWindow(context->GroupComboHandle, SW_SHOW);\n            }\n\n            if (context->ProcessItem)\n            {\n                HANDLE processHandle;\n                GROUP_AFFINITY processGroupAffinity = { 0 };\n\n                if (NT_SUCCESS(status = PhOpenProcess(\n                    &processHandle,\n                    PROCESS_QUERY_LIMITED_INFORMATION,\n                    context->ProcessItem->ProcessId\n                    )))\n                {\n                    status = PhGetProcessGroupAffinity(processHandle, &processGroupAffinity);\n\n                    if (NT_SUCCESS(status))\n                    {\n                        context->AffinityMask = processGroupAffinity.Mask;\n                        context->AffinityGroup = processGroupAffinity.Group;\n\n                        if (context->GroupComboHandle)\n                        {\n                            ComboBox_SetCurSel(context->GroupComboHandle, processGroupAffinity.Group);\n                        }\n                    }\n\n                    NtClose(processHandle);\n                }\n            }\n            else if (context->ThreadItem)\n            {\n                HANDLE threadHandle;\n                THREAD_BASIC_INFORMATION basicInfo;\n                GROUP_AFFINITY groupAffinity = { 0 };\n                HANDLE processHandle;\n\n                if (NT_SUCCESS(status = PhOpenThread(\n                    &threadHandle,\n                    THREAD_QUERY_LIMITED_INFORMATION,\n                    context->ThreadItem->ThreadId\n                    )))\n                {\n                    status = PhGetThreadGroupAffinity(threadHandle, &groupAffinity);\n\n                    if (NT_SUCCESS(status))\n                    {\n                        context->AffinityMask = groupAffinity.Mask;\n                        context->AffinityGroup = groupAffinity.Group;\n\n                        if (context->GroupComboHandle)\n                        {\n                            ComboBox_SetCurSel(context->GroupComboHandle, groupAffinity.Group);\n                        }\n\n                        if (NT_SUCCESS(PhGetThreadBasicInformation(\n                            threadHandle,\n                            &basicInfo\n                            )))\n                        {\n                            // A thread's affinity mask is restricted by the process affinity mask,\n                            // so use that as the system affinity mask. (wj32)\n\n                            if (NT_SUCCESS(PhOpenProcess(\n                                &processHandle,\n                                PROCESS_QUERY_LIMITED_INFORMATION,\n                                basicInfo.ClientId.UniqueProcess\n                                )))\n                            {\n                                GROUP_AFFINITY processGroupAffinity = { 0 };\n\n                                if (NT_SUCCESS(PhGetProcessGroupAffinity(processHandle, &processGroupAffinity)))\n                                {\n                                    context->SystemAffinityMask = processGroupAffinity.Mask;\n                                }\n\n                                NtClose(processHandle);\n                            }\n                        }\n                    }\n\n                    NtClose(threadHandle);\n                }\n            }\n            else if (context->Threads)\n            {\n                HANDLE processHandle;\n                THREAD_BASIC_INFORMATION basicInfo;\n                GROUP_AFFINITY groupAffinity = { 0 };\n                PPH_STRING windowText;\n\n                windowText = PH_AUTO(PhGetWindowText(hwndDlg));\n                PhSetWindowText(hwndDlg, PhaFormatString(\n                    L\"%s (%lu threads)\",\n                    windowText->Buffer,\n                    context->NumberOfThreads\n                    )->Buffer);\n\n                differentAffinity = !PhpCheckThreadsHaveSameAffinity(context);\n\n                if (context->ThreadHandles[0] != INVALID_HANDLE_VALUE)\n                {\n                    // Use affinity from the first thread when all threads are identical (dmex)\n                    status = PhGetThreadGroupAffinity(\n                        context->ThreadHandles[0],\n                        &groupAffinity\n                        );\n                }\n                else\n                {\n                    status = STATUS_UNSUCCESSFUL;\n                }\n\n                if (NT_SUCCESS(status))\n                {\n                    context->AffinityMask = groupAffinity.Mask;\n                    context->AffinityGroup = groupAffinity.Group;\n\n                    if (context->GroupComboHandle)\n                    {\n                        ComboBox_SetCurSel(context->GroupComboHandle, groupAffinity.Group);\n                    }\n\n                    if (NT_SUCCESS(PhGetThreadBasicInformation(\n                        context->ThreadHandles[0],\n                        &basicInfo\n                        )))\n                    {\n                        if (NT_SUCCESS(PhOpenProcess(\n                            &processHandle,\n                            PROCESS_QUERY_LIMITED_INFORMATION,\n                            basicInfo.ClientId.UniqueProcess\n                            )))\n                        {\n                            GROUP_AFFINITY processGroupAffinity = { 0 };\n\n                            if (NT_SUCCESS(PhGetProcessGroupAffinity(processHandle, &processGroupAffinity)))\n                            {\n                                context->SystemAffinityMask = processGroupAffinity.Mask;\n                            }\n\n                            NtClose(processHandle);\n                        }\n                    }\n                }\n            }\n\n            if (NT_SUCCESS(status) && context->SystemAffinityMask == 0)\n            {\n                KAFFINITY systemAffinityMask;\n\n                if (PhSystemProcessorInformation.SingleProcessorGroup)\n                {\n                    status = PhGetProcessorSystemAffinityMask(&systemAffinityMask);\n                }\n                else\n                {\n                    status = PhGetProcessorGroupActiveAffinityMask(context->AffinityGroup, &systemAffinityMask);\n                }\n\n                if (NT_SUCCESS(status))\n                {\n                    context->SystemAffinityMask = systemAffinityMask;\n                }\n            }\n\n            if (!NT_SUCCESS(status))\n            {\n                PhShowStatus(hwndDlg, L\"Unable to query the current affinity.\", status, 0);\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            }\n\n            // Disable the CPU checkboxes which aren't part of the system affinity mask,\n            // and check the CPU checkboxes which are part of the affinity mask. (wj32)\n\n            for (i = 0; i < MAXIMUM_PROC_PER_GROUP; i++)\n            {\n                if ((context->SystemAffinityMask >> i) & 0x1)\n                {\n                    if (differentAffinity) // Skip for multiple selection (dmex)\n                        continue;\n\n                    if ((context->AffinityMask >> i) & 0x1)\n                    {\n                        Button_SetCheck(context->CpuControlList->Items[i], BST_CHECKED);\n                    }\n                }\n                else\n                {\n                    EnableWindow(context->CpuControlList->Items[i], FALSE);\n                }\n            }\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            if (context->ThreadHandles)\n            {\n                for (ULONG i = 0; i < context->NumberOfThreads; i++)\n                {\n                    if (context->ThreadHandles[i] != INVALID_HANDLE_VALUE)\n                    {\n                        NtClose(context->ThreadHandles[i]);\n                        context->ThreadHandles[i] = NULL;\n                    }\n                }\n\n                PhFree(context->ThreadHandles);\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    NTSTATUS status = STATUS_SUCCESS;\n                    KAFFINITY affinityMask = 0;\n                    USHORT affinityGroup = 0;\n\n                    // Work out the affinity mask.\n\n                    for (ULONG i = 0; i < MAXIMUM_PROC_PER_GROUP; i++)\n                    {\n                        if (Button_GetCheck(context->CpuControlList->Items[i]) == BST_CHECKED)\n                            affinityMask |= AFFINITY_MASK(i);\n                    }\n\n                    if (context->GroupComboHandle)\n                    {\n                         LONG affinityGroupSelection = ComboBox_GetCurSel(context->GroupComboHandle);\n\n                         if (affinityGroupSelection == CB_ERR)\n                             affinityGroup = context->AffinityGroup;\n                         else\n                             affinityGroup = (USHORT)affinityGroupSelection;\n                    }\n\n                    if (affinityMask == 0)\n                    {\n                        PhShowError2(hwndDlg, L\"Unable to change affinity settings.\", L\"%s\", L\"You must select at least one CPU.\");\n                        break;\n                    }\n\n                    if (context->ProcessItem)\n                    {\n                        HANDLE processHandle;\n\n                        if (NT_SUCCESS(status = PhOpenProcess(\n                            &processHandle,\n                            PROCESS_SET_INFORMATION,\n                            context->ProcessItem->ProcessId\n                            )))\n                        {\n                            if (PhSystemProcessorInformation.SingleProcessorGroup)\n                            {\n                                status = PhSetProcessAffinityMask(processHandle, affinityMask);\n                            }\n                            else\n                            {\n                                GROUP_AFFINITY groupAffinity;\n\n                                memset(&groupAffinity, 0, sizeof(GROUP_AFFINITY));\n                                groupAffinity.Group = affinityGroup;\n                                groupAffinity.Mask = affinityMask;\n\n                                status = PhSetProcessGroupAffinity(processHandle, groupAffinity);\n                            }\n\n                            NtClose(processHandle);\n                        }\n\n                        if (NT_SUCCESS(status))\n                        {\n                            context->NewAffinityMask = affinityMask;\n                        }\n                        else\n                        {\n                            PhpShowProcessErrorAffinity(hwndDlg, context->ProcessItem, status, 0);\n                        }\n                    }\n                    else if (context->ThreadItem)\n                    {\n                        if (PhSystemProcessorInformation.SingleProcessorGroup)\n                        {\n                            HANDLE threadHandle;\n\n                            status = PhOpenThread(\n                                &threadHandle,\n                                THREAD_SET_LIMITED_INFORMATION,\n                                context->ThreadItem->ThreadId\n                                );\n\n                            if (NT_SUCCESS(status))\n                            {\n                                status = PhSetThreadAffinityMask(threadHandle, affinityMask);\n                                NtClose(threadHandle);\n                            }\n\n                            if (!NT_SUCCESS(status))\n                            {\n                                PhpShowThreadErrorAffinity(hwndDlg, context->ThreadItem, status, 0);\n                            }\n                        }\n                        else\n                        {\n                            HANDLE threadHandle;\n\n                            status = PhOpenThread(\n                                &threadHandle,\n                                THREAD_SET_INFORMATION,\n                                context->ThreadItem->ThreadId\n                                );\n\n                            if (NT_SUCCESS(status))\n                            {\n                                GROUP_AFFINITY groupAffinity;\n\n                                memset(&groupAffinity, 0, sizeof(GROUP_AFFINITY));\n                                groupAffinity.Group = affinityGroup;\n                                groupAffinity.Mask = affinityMask;\n\n                                status = PhSetThreadGroupAffinity(threadHandle, groupAffinity);\n                                NtClose(threadHandle);\n                            }\n\n                            if (!NT_SUCCESS(status))\n                            {\n                                PhpShowThreadErrorAffinity(hwndDlg, context->ThreadItem, status, 0);\n                            }\n                        }\n                    }\n                    else if (context->Threads)\n                    {\n                        PPH_LIST threadAffinityErrors = PhCreateList(1);\n\n                        for (ULONG i = 0; i < context->NumberOfThreads; i++)\n                        {\n                            if (context->ThreadHandles[i] == INVALID_HANDLE_VALUE)\n                                continue;\n\n                            if (PhSystemProcessorInformation.SingleProcessorGroup)\n                            {\n                                status = PhSetThreadAffinityMask(context->ThreadHandles[i], affinityMask);\n                            }\n                            else\n                            {\n                                GROUP_AFFINITY groupAffinity;\n\n                                memset(&groupAffinity, 0, sizeof(GROUP_AFFINITY));\n                                groupAffinity.Group = affinityGroup;\n                                groupAffinity.Mask = affinityMask;\n\n                                status = PhSetThreadGroupAffinity(context->ThreadHandles[i], groupAffinity);\n                            }\n\n                            if (!NT_SUCCESS(status))\n                            {\n                                PPH_STRING errorMessage;\n\n                                if (errorMessage = PhGetNtMessage(status))\n                                {\n                                    PhAddItemList(threadAffinityErrors, errorMessage);\n                                }\n                            }\n                        }\n\n                        if (threadAffinityErrors->Count > 0)\n                            PhpShowThreadErrorAffinityList(context, threadAffinityErrors);\n                        else\n                            PhDereferenceObject(threadAffinityErrors);\n                    }\n\n                    if (NT_SUCCESS(status))\n                    {\n                        EndDialog(hwndDlg, IDOK);\n                    }\n                }\n                break;\n            case IDC_SELECTALL:\n            case IDC_DESELECTALL:\n                {\n                    for (ULONG i = 0; i < MAXIMUM_PROC_PER_GROUP; i++)\n                    {\n                        HWND checkBox = context->CpuControlList->Items[i];\n\n                        if (IsWindowEnabled(checkBox))\n                            Button_SetCheck(checkBox, GET_WM_COMMAND_ID(wParam, lParam) == IDC_SELECTALL ? BST_CHECKED : BST_UNCHECKED);\n                    }\n                }\n                break;\n            case IDC_GROUPCPU:\n                {\n                    LONG index;\n\n                    if (!context->GroupComboHandle)\n                        break;\n\n                    index = ComboBox_GetCurSel(context->GroupComboHandle);\n\n                    if (index != CB_ERR)\n                    {\n                        if (index != context->AffinityGroup)\n                        {\n                            for (ULONG i = 0; i < MAXIMUM_PROC_PER_GROUP; i++)\n                            {\n                                Button_SetCheck(context->CpuControlList->Items[i], BST_UNCHECKED);\n                            }\n                        }\n                        else\n                        {\n                            BOOLEAN differentAffinity = FALSE;\n\n                            if (context->Threads)\n                            {\n                                differentAffinity = !PhpCheckThreadsHaveSameAffinity(context);\n                            }\n\n                            for (ULONG i = 0; i < MAXIMUM_PROC_PER_GROUP; i++)\n                            {\n                                if ((context->SystemAffinityMask >> i) & 0x1)\n                                {\n                                    if (differentAffinity) // Skip for multiple selection (dmex)\n                                        continue;\n\n                                    if ((context->AffinityMask >> i) & 0x1)\n                                    {\n                                        Button_SetCheck(context->CpuControlList->Items[i], BST_CHECKED);\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\n// Note: Workaround for UserNotes plugin dialog overrides (dmex)\nNTSTATUS PhSetProcessItemAffinityMask(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ KAFFINITY AffinityMask\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION,\n        ProcessItem->ProcessId\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhSetProcessAffinityMask(processHandle, AffinityMask);\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\n// Note: Workaround for UserNotes plugin dialog overrides (dmex)\nNTSTATUS PhSetProcessItemPagePriority(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG PagePriority\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION,\n        ProcessItem->ProcessId\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhSetProcessPagePriority(processHandle, PagePriority);\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\n// Note: Workaround for UserNotes plugin dialog overrides (dmex)\nNTSTATUS PhSetProcessItemIoPriority(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ IO_PRIORITY_HINT IoPriority\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION,\n        ProcessItem->ProcessId\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhSetProcessIoPriority(processHandle, IoPriority);\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\n// Note: Workaround for UserNotes plugin dialog overrides (dmex)\nNTSTATUS PhSetProcessItemPriority(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ UCHAR PriorityClass\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION,\n        ProcessItem->ProcessId\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhSetProcessPriorityClass(processHandle, PriorityClass);\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\n// Note: Workaround for UserNotes plugin dialog overrides (dmex)\nNTSTATUS PhSetProcessItemPriorityBoost(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ BOOLEAN PriorityBoost\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION,\n        ProcessItem->ProcessId\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhSetProcessPriorityBoost(processHandle, PriorityBoost);\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\n// Note: Workaround for UserNotes plugin dialog overrides (dmex)\nNTSTATUS PhSetProcessItemThrottlingState(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ BOOLEAN ClearThrottlingState\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION,\n        ProcessItem->ProcessId\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (ClearThrottlingState)\n        {\n            PhSetProcessPriorityClass(processHandle, PROCESS_PRIORITY_CLASS_NORMAL);\n\n            status = PhSetProcessPowerThrottlingState(processHandle, 0, 0);\n        }\n        else\n        {\n            // Taskmgr sets the process priority to idle before enabling 'Eco mode'. (dmex)\n            PhSetProcessPriorityClass(processHandle, PROCESS_PRIORITY_CLASS_IDLE);\n\n            status = PhSetProcessPowerThrottlingState(\n                processHandle,\n                POWER_THROTTLING_PROCESS_EXECUTION_SPEED,\n                POWER_THROTTLING_PROCESS_EXECUTION_SPEED\n                );\n        }\n\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "SystemInformer/anawait.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *\n */\n\n/*\n * There are two ways of seeing what a thread is waiting on. The first method\n * is to walk the stack of a thread and read the arguments to whatever system\n * call it is blocking on; this only works on x86 because on x64 the arguments\n * are passed in registers (at least the first four are). The second method\n * involves using the ThreadLastSystemCall info class for NtQueryInformationThread\n * to retrieve the first argument to the system call the thread is blocking on.\n * This is obviously only useful for NtWaitForSingleObject.\n *\n * There are other methods for specific scenarios, like USER messages and ALPC\n * calls.\n */\n\n#include <phapp.h>\n\n#include <hndlinfo.h>\n#include <symprv.h>\n\n#include <procprv.h>\n\ntypedef struct _ANALYZE_WAIT_CONTEXT\n{\n    BOOLEAN Found;\n    BOOLEAN IsWow64Process;\n    HANDLE ProcessId;\n    HANDLE ThreadId;\n    HANDLE ProcessHandle;\n\n    PPH_SYMBOL_PROVIDER SymbolProvider;\n    PH_STRING_BUILDER StringBuilder;\n\n    PVOID PrevParams[4];\n} ANALYZE_WAIT_CONTEXT, *PANALYZE_WAIT_CONTEXT;\n\nVOID PhpAnalyzeWaitPassive(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId\n    );\n\n_Function_class_(PH_WALK_THREAD_STACK_CALLBACK)\nBOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback(\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _In_ PVOID Context\n    );\n\nVOID PhpAnalyzeWaitFallbacks(\n    _In_ PANALYZE_WAIT_CONTEXT Context\n    );\n\nVOID PhpInitializeServiceNumbers(\n    VOID\n    );\n\nPPH_STRING PhpaGetHandleString(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle\n    );\n\nVOID PhpGetWfmoInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN IsWow64Process,\n    _In_ ULONG NumberOfHandles,\n    _In_ PHANDLE AddressOfHandles,\n    _In_ WAIT_TYPE WaitType,\n    _In_ BOOLEAN Alertable,\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    );\n\nPPH_STRING PhpaGetSendMessageReceiver(\n    _In_ HANDLE ThreadId\n    );\n\nPPH_STRING PhpaGetAlpcInformation(\n    _In_ HANDLE ThreadId\n    );\n\nstatic PH_INITONCE ServiceNumbersInitOnce = PH_INITONCE_INIT;\nstatic USHORT NumberForWfso = USHRT_MAX;\nstatic USHORT NumberForWfmo = USHRT_MAX;\nstatic USHORT NumberForRf = USHRT_MAX;\n\nVOID PhUiAnalyzeWaitThread(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId,\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n    HANDLE processHandle;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n    CLIENT_ID clientId;\n    ANALYZE_WAIT_CONTEXT context;\n\n    if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, ProcessId)))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to open the process.\", status, 0);\n        return;\n    }\n\n#ifdef _WIN64\n    // Determine if the process is WOW64. If not, we use the passive method.\n\n    if (!NT_SUCCESS(status = PhGetProcessIsWow64(processHandle, &isWow64)) || !isWow64)\n    {\n        PhpAnalyzeWaitPassive(WindowHandle, ProcessId, ThreadId);\n\n        NtClose(processHandle);\n        return;\n    }\n#endif\n\n    if (!NT_SUCCESS(status = PhOpenThread(\n        &threadHandle,\n        THREAD_QUERY_LIMITED_INFORMATION | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME,\n        ThreadId\n        )))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to open the thread.\", status, 0);\n        NtClose(processHandle);\n        return;\n    }\n\n    memset(&context, 0, sizeof(ANALYZE_WAIT_CONTEXT));\n    context.ProcessId = ProcessId;\n    context.ThreadId = ThreadId;\n    context.ProcessHandle = processHandle;\n    context.SymbolProvider = SymbolProvider;\n    PhInitializeStringBuilder(&context.StringBuilder, 100);\n\n    clientId.UniqueProcess = ProcessId;\n    clientId.UniqueThread = ThreadId;\n\n    PhWalkThreadStack(\n        threadHandle,\n        processHandle,\n        &clientId,\n        SymbolProvider,\n        PH_WALK_USER_WOW64_STACK,\n        PhpWalkThreadStackAnalyzeCallback,\n        &context\n        );\n    NtClose(threadHandle);\n    NtClose(processHandle);\n\n    PhpAnalyzeWaitFallbacks(&context);\n\n    if (context.Found)\n    {\n        PhShowInformationDialog(WindowHandle, PhFinalStringBuilderString(&context.StringBuilder)->Buffer, 0);\n    }\n    else\n    {\n        PhShowInformation2(WindowHandle, L\"Unable to analyze the thread.\", L\"%s\", L\"The thread does not appear to be waiting.\");\n    }\n\n    PhDeleteStringBuilder(&context.StringBuilder);\n}\n\nVOID PhpAnalyzeWaitPassive(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle = NULL;\n    HANDLE threadHandle = NULL;\n    PPH_STRING lastSystemCallName;\n    THREAD_LAST_SYSCALL_INFORMATION lastSystemCall;\n    PH_STRING_BUILDER stringBuilder;\n    PPH_STRING string;\n\n    if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE, ProcessId)))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to open the process.\", status, 0);\n        goto CleanupExit;\n    }\n\n    if (!NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, ThreadId)))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to open the thread.\", status, 0);\n        return;\n    }\n\n    if (!NT_SUCCESS(status = PhGetThreadLastSystemCall(threadHandle, &lastSystemCall)))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to determine whether the thread is waiting.\", status, 0);\n        goto CleanupExit;\n    }\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n\n    lastSystemCallName = PhGetSystemCallNumberName(lastSystemCall.SystemCallNumber);\n\n    if (!PhIsNullOrEmptyString(lastSystemCallName))\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Thread is waiting on system call: \");\n        PhAppendStringBuilder(&stringBuilder, &lastSystemCallName->sr);\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n\n        if (\n            PhEqualString2(lastSystemCallName, L\"NtWaitForSingleObject\", TRUE)\n            )\n        {\n            string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument);\n            PhAppendFormatStringBuilder(&stringBuilder, L\"Thread is waiting for:\\r\\n\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n        }\n        else if (\n            PhEqualString2(lastSystemCallName, L\"NtWaitForMultipleObjects\", TRUE) ||\n            PhEqualString2(lastSystemCallName, L\"NtUserMsgWaitForMultipleObjects\", TRUE) ||\n            PhEqualString2(lastSystemCallName, L\"NtUserMsgWaitForMultipleObjectsEx\", TRUE)\n            )\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"Thread is waiting for multiple (%lu) objects.\", PtrToUlong(lastSystemCall.FirstArgument));\n        }\n        else if (\n            PhEqualString2(lastSystemCallName, L\"NtReadFile\", TRUE) ||\n            PhEqualString2(lastSystemCallName, L\"NtWriteFile\", TRUE)\n            )\n        {\n            string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument);\n            PhAppendFormatStringBuilder(&stringBuilder, L\"Thread is waiting for file I/O:\\r\\n\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n        }\n        else\n        {\n            string = PhpaGetSendMessageReceiver(ThreadId);\n\n            if (string)\n            {\n                PhAppendStringBuilder2(&stringBuilder, L\"Thread is sending a USER message:\\r\\n\");\n                PhAppendStringBuilder(&stringBuilder, &string->sr);\n            }\n            else\n            {\n                string = PhpaGetAlpcInformation(ThreadId);\n\n                if (string)\n                {\n                    PhAppendStringBuilder2(&stringBuilder, L\"Thread is waiting for an ALPC port:\\r\\n\");\n                    PhAppendStringBuilder(&stringBuilder, &string->sr);\n                }\n            }\n        }\n    }\n    else\n    {\n        PhpInitializeServiceNumbers();\n\n        if (lastSystemCall.SystemCallNumber == NumberForWfso)\n        {\n            string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument);\n\n            PhAppendFormatStringBuilder(&stringBuilder, L\"Thread is waiting for:\\r\\n\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n        }\n        else if (lastSystemCall.SystemCallNumber == NumberForWfmo)\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"Thread is waiting for multiple (%lu) objects.\", PtrToUlong(lastSystemCall.FirstArgument));\n        }\n        else if (lastSystemCall.SystemCallNumber == NumberForRf)\n        {\n            string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument);\n\n            PhAppendFormatStringBuilder(&stringBuilder, L\"Thread is waiting for file I/O:\\r\\n\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n        }\n        else\n        {\n            string = PhpaGetSendMessageReceiver(ThreadId);\n\n            if (string)\n            {\n                PhAppendStringBuilder2(&stringBuilder, L\"Thread is sending a USER message:\\r\\n\");\n                PhAppendStringBuilder(&stringBuilder, &string->sr);\n            }\n            else\n            {\n                string = PhpaGetAlpcInformation(ThreadId);\n\n                if (string)\n                {\n                    PhAppendStringBuilder2(&stringBuilder, L\"Thread is waiting for an ALPC port:\\r\\n\");\n                    PhAppendStringBuilder(&stringBuilder, &string->sr);\n                }\n            }\n        }\n    }\n\n    if (stringBuilder.String->Length == 0)\n        PhAppendStringBuilder2(&stringBuilder, L\"Unable to determine why the thread is waiting.\");\n\n    PhShowInformationDialog(WindowHandle, stringBuilder.String->Buffer, 0);\n    PhDeleteStringBuilder(&stringBuilder);\n\nCleanupExit:\n\n    if (threadHandle)\n    {\n        NtClose(threadHandle);\n    }\n\n    if (processHandle)\n    {\n        NtClose(processHandle);\n    }\n}\n\n_Function_class_(PH_WALK_THREAD_STACK_CALLBACK)\nBOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback(\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _In_ PVOID Context\n    )\n{\n    PANALYZE_WAIT_CONTEXT context = (PANALYZE_WAIT_CONTEXT)Context;\n    PPH_STRING name;\n\n    name = PhGetSymbolFromAddress(\n        context->SymbolProvider,\n        StackFrame->PcAddress,\n        NULL,\n        NULL,\n        NULL,\n        NULL\n        );\n\n    if (PhIsNullOrEmptyString(name))\n        return TRUE;\n\n    context->Found = TRUE;\n\n#define FUNC_MATCH(Name) PhStartsWithString2(name, L##Name, TRUE)\n#define NT_FUNC_MATCH(Name) ( \\\n    PhStartsWithString2(name, L\"ntdll.dll!Nt\" L##Name, TRUE) || \\\n    PhStartsWithString2(name, L\"ntdll.dll!Zw\" L##Name, TRUE) \\\n    )\n\n    if (!name)\n    {\n        // Dummy\n    }\n    else if (FUNC_MATCH(\"kernel32.dll!Sleep\"))\n    {\n        PhAppendFormatStringBuilder(\n            &context->StringBuilder,\n            L\"Thread is sleeping. Timeout: %lu milliseconds.\",\n            PtrToUlong(StackFrame->Params[0])\n            );\n    }\n    else if (NT_FUNC_MATCH(\"DelayExecution\"))\n    {\n        BOOLEAN alertable = !!StackFrame->Params[0];\n        PVOID timeoutAddress = StackFrame->Params[1];\n        LONGLONG timeout;\n\n        if (NT_SUCCESS(PhReadVirtualMemory(\n            context->ProcessHandle,\n            timeoutAddress,\n            &timeout,\n            sizeof(LONGLONG),\n            NULL\n            )))\n        {\n            if (timeout < 0)\n            {\n                PhAppendFormatStringBuilder(\n                    &context->StringBuilder,\n                    L\"Thread is sleeping. Timeout: %llu milliseconds.\",\n                    -timeout / PH_TIMEOUT_MS\n                    );\n            }\n            else\n            {\n                // TODO\n            }\n        }\n        else\n        {\n            PhAppendStringBuilder2(\n                &context->StringBuilder,\n                L\"Thread is sleeping.\"\n                );\n        }\n    }\n    else if (NT_FUNC_MATCH(\"DeviceIoControlFile\"))\n    {\n        HANDLE handle = (HANDLE)StackFrame->Params[0];\n\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is waiting for an I/O control request:\\r\\n\"\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (NT_FUNC_MATCH(\"FsControlFile\"))\n    {\n        HANDLE handle = StackFrame->Params[0];\n\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is waiting for a FS control request:\\r\\n\"\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (NT_FUNC_MATCH(\"QueryObject\"))\n    {\n        HANDLE handle = StackFrame->Params[0];\n\n        // Use the KiFastSystemCall args if the handle we have is wrong.\n        if ((ULONG_PTR)handle % 4 != 0 || !handle)\n            handle = context->PrevParams[1];\n\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is querying an object:\\r\\n\"\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (NT_FUNC_MATCH(\"ReadFile\") || NT_FUNC_MATCH(\"WriteFile\"))\n    {\n        HANDLE handle = StackFrame->Params[0];\n\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is waiting for file I/O:\\r\\n\"\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (NT_FUNC_MATCH(\"RemoveIoCompletion\") || NT_FUNC_MATCH(\"RemoveIoCompletionEx\"))\n    {\n        HANDLE handle = StackFrame->Params[0];\n\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is waiting for an I/O completion port:\\r\\n\"\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (\n        NT_FUNC_MATCH(\"ReplyWaitReceivePort\") ||\n        NT_FUNC_MATCH(\"RequestWaitReplyPort\") ||\n        NT_FUNC_MATCH(\"AlpcSendWaitReceivePort\")\n        )\n    {\n        HANDLE handle = StackFrame->Params[0];\n        PPH_STRING alpcInfo;\n\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is waiting for an ALPC port:\\r\\n\"\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n\n        if (alpcInfo = PhpaGetAlpcInformation(context->ThreadId))\n        {\n            PhAppendStringBuilder2(\n                &context->StringBuilder,\n                L\"\\r\\n\"\n                );\n            PhAppendStringBuilder(\n                &context->StringBuilder,\n                &alpcInfo->sr\n                );\n        }\n    }\n    else if (\n        NT_FUNC_MATCH(\"SetHighWaitLowEventPair\") ||\n        NT_FUNC_MATCH(\"SetLowWaitHighEventPair\") ||\n        NT_FUNC_MATCH(\"WaitHighEventPair\") ||\n        NT_FUNC_MATCH(\"WaitLowEventPair\")\n        )\n    {\n        HANDLE handle = StackFrame->Params[0];\n\n        if ((ULONG_PTR)handle % 4 != 0 || !handle)\n            handle = context->PrevParams[1];\n\n        PhAppendFormatStringBuilder(\n            &context->StringBuilder,\n            L\"Thread is waiting (%s) for an event pair:\\r\\n\",\n            name->Buffer\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (\n        FUNC_MATCH(\"user32.dll!NtUserGetMessage\") ||\n        FUNC_MATCH(\"user32.dll!NtUserWaitMessage\")\n        )\n    {\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is waiting for a USER message.\\r\\n\"\n            );\n    }\n    else if (FUNC_MATCH(\"user32.dll!NtUserMessageCall\"))\n    {\n        PPH_STRING receiverString;\n\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is sending a USER message:\\r\\n\"\n            );\n\n        receiverString = PhpaGetSendMessageReceiver(context->ThreadId);\n\n        if (receiverString)\n        {\n            PhAppendStringBuilder(&context->StringBuilder, &receiverString->sr);\n            PhAppendStringBuilder2(&context->StringBuilder, L\"\\r\\n\");\n        }\n        else\n        {\n            PhAppendStringBuilder2(&context->StringBuilder, L\"Unknown.\\r\\n\");\n        }\n    }\n    else if (NT_FUNC_MATCH(\"WaitForDebugEvent\"))\n    {\n        HANDLE handle = StackFrame->Params[0];\n\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is waiting for a debug event:\\r\\n\"\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (\n        NT_FUNC_MATCH(\"WaitForKeyedEvent\") ||\n        NT_FUNC_MATCH(\"ReleaseKeyedEvent\")\n        )\n    {\n        HANDLE handle = StackFrame->Params[0];\n        ULONG_PTR key = (ULONG_PTR)StackFrame->Params[1];\n\n        PhAppendFormatStringBuilder(\n            &context->StringBuilder,\n            L\"Thread is waiting (%s) for a keyed event (key 0x%Ix):\\r\\n\",\n            name->Buffer,\n            key\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (\n        NT_FUNC_MATCH(\"WaitForMultipleObjects\") ||\n        FUNC_MATCH(\"kernel32.dll!WaitForMultipleObjects\")\n        )\n    {\n        ULONG numberOfHandles = PtrToUlong(StackFrame->Params[0]);\n        PVOID addressOfHandles = StackFrame->Params[1];\n        WAIT_TYPE waitType = (WAIT_TYPE)PtrToUlong(StackFrame->Params[2]);\n        BOOLEAN alertable = !!StackFrame->Params[3];\n\n        if (numberOfHandles > MAXIMUM_WAIT_OBJECTS)\n        {\n            numberOfHandles = PtrToUlong(context->PrevParams[1]);\n            addressOfHandles = context->PrevParams[2];\n            waitType = (WAIT_TYPE)PtrToUlong(context->PrevParams[3]);\n            alertable = FALSE;\n        }\n\n        PhpGetWfmoInformation(\n            context->ProcessHandle,\n            TRUE, // on x64 this function is only called for WOW64 processes\n            numberOfHandles,\n            addressOfHandles,\n            waitType,\n            alertable,\n            &context->StringBuilder\n            );\n    }\n    else if (\n        NT_FUNC_MATCH(\"WaitForSingleObject\") ||\n        FUNC_MATCH(\"kernel32.dll!WaitForSingleObject\")\n        )\n    {\n        HANDLE handle = StackFrame->Params[0];\n        BOOLEAN alertable = !!StackFrame->Params[1];\n\n        if ((ULONG_PTR)handle % 4 != 0 || !handle)\n        {\n            handle = context->PrevParams[1];\n            alertable = !!context->PrevParams[2];\n        }\n\n        PhAppendFormatStringBuilder(\n            &context->StringBuilder,\n            L\"Thread is waiting (%s) for:\\r\\n\",\n            alertable ? L\"alertable\" : L\"non-alertable\"\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (NT_FUNC_MATCH(\"WaitForWorkViaWorkerFactory\"))\n    {\n        HANDLE handle = StackFrame->Params[0];\n\n        PhAppendStringBuilder2(\n            &context->StringBuilder,\n            L\"Thread is waiting for work from a worker factory:\\r\\n\"\n            );\n        PhAppendStringBuilder(\n            &context->StringBuilder,\n            &PhpaGetHandleString(context->ProcessHandle, handle)->sr\n            );\n    }\n    else if (\n        FUNC_MATCH(\"win32u.dll!NtUserMsgWaitForMultipleObjects\") ||\n        FUNC_MATCH(\"win32u.dll!NtUserMsgWaitForMultipleObjectsEx\")\n        )\n    {\n        ULONG numberOfHandles = 0;\n        ULONG milliseconds = 0;\n        PVOID addressOfHandles = NULL;\n        BOOLEAN waitAllHandles = FALSE;\n        BOOLEAN alertable = FALSE;\n\n        if (FUNC_MATCH(\"win32u.dll!NtUserMsgWaitForMultipleObjects\"))\n        {\n            numberOfHandles = PtrToUlong(StackFrame->Params[0]);\n            addressOfHandles = StackFrame->Params[1];\n            waitAllHandles = !!StackFrame->Params[2];\n            milliseconds = PtrToUlong(StackFrame->Params[3]);\n        }\n        else\n        {\n            numberOfHandles = PtrToUlong(StackFrame->Params[0]);\n            addressOfHandles = StackFrame->Params[1];\n            milliseconds = PtrToUlong(StackFrame->Params[2]);\n            ULONG flags = PtrToUlong(StackFrame->Params[3]);\n\n            if (FlagOn(flags, MWMO_ALERTABLE))\n            {\n                alertable = TRUE;\n            }\n            if (FlagOn(flags, MWMO_WAITALL))\n            {\n                waitAllHandles = TRUE;\n            }\n        }\n\n        // if (numberOfHandles > MAXIMUM_WAIT_OBJECTS)\n\n        PhpGetWfmoInformation(\n            context->ProcessHandle,\n            TRUE, \n            numberOfHandles,\n            addressOfHandles,\n            waitAllHandles ? WaitAll : WaitAny,\n            alertable,\n            &context->StringBuilder\n            );\n    }\n    else\n    {\n        context->Found = FALSE;\n    }\n\n    PhDereferenceObject(name);\n    memcpy(&context->PrevParams, StackFrame->Params, sizeof(StackFrame->Params));\n\n    return !context->Found;\n}\n\nVOID PhpAnalyzeWaitFallbacks(\n    _In_ PANALYZE_WAIT_CONTEXT Context\n    )\n{\n    PPH_STRING info;\n\n    // We didn't detect NtUserMessageCall, but this may still apply due to another\n    // win32k system call (e.g. from EnableWindow).\n    if (!Context->Found && (info = PhpaGetSendMessageReceiver(Context->ThreadId)))\n    {\n        PhAppendStringBuilder2(\n            &Context->StringBuilder,\n            L\"Thread is sending a USER message:\\r\\n\"\n            );\n        PhAppendStringBuilder(&Context->StringBuilder, &info->sr);\n        PhAppendStringBuilder2(&Context->StringBuilder, L\"\\r\\n\");\n\n        Context->Found = TRUE;\n    }\n\n    // Nt(Alpc)ConnectPort doesn't get detected anywhere else.\n    if (!Context->Found && (info = PhpaGetAlpcInformation(Context->ThreadId)))\n    {\n        PhAppendStringBuilder2(\n            &Context->StringBuilder,\n            L\"Thread is waiting for an ALPC port:\\r\\n\"\n            );\n        PhAppendStringBuilder(&Context->StringBuilder, &info->sr);\n        PhAppendStringBuilder2(&Context->StringBuilder, L\"\\r\\n\");\n\n        Context->Found = TRUE;\n    }\n}\n\nstatic BOOLEAN PhpWaitUntilThreadIsWaiting(\n    _In_ HANDLE ThreadHandle\n    )\n{\n    ULONG attempts;\n    BOOLEAN isWaiting = FALSE;\n    THREAD_BASIC_INFORMATION basicInfo;\n\n    if (!NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return FALSE;\n\n    for (attempts = 0; attempts < 20; attempts++)\n    {\n        PVOID processes;\n        PSYSTEM_PROCESS_INFORMATION processInfo;\n        ULONG i;\n\n        PhDelayExecution(100);\n\n        if (!NT_SUCCESS(PhEnumProcesses(&processes)))\n            break;\n\n        processInfo = PhFindProcessInformation(processes, basicInfo.ClientId.UniqueProcess);\n\n        if (processInfo)\n        {\n            for (i = 0; i < processInfo->NumberOfThreads; i++)\n            {\n                if (\n                    processInfo->Threads[i].ClientId.UniqueThread == basicInfo.ClientId.UniqueThread &&\n                    processInfo->Threads[i].ThreadState == Waiting &&\n                    (processInfo->Threads[i].WaitReason == UserRequest ||\n                    processInfo->Threads[i].WaitReason == Executive)\n                    )\n                {\n                    isWaiting = TRUE;\n                    break;\n                }\n            }\n        }\n\n        PhFree(processes);\n\n        if (isWaiting)\n            break;\n\n        PhDelayExecution(500);\n    }\n\n    return isWaiting;\n}\n\n_Success_(return)\nstatic BOOLEAN PhpGetThreadLastSystemCallNumber(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PUSHORT LastSystemCallNumber\n    )\n{\n    THREAD_LAST_SYSCALL_INFORMATION lastSystemCall;\n\n    if (NT_SUCCESS(PhGetThreadLastSystemCall(ThreadHandle, &lastSystemCall)))\n    {\n        *LastSystemCallNumber = lastSystemCall.SystemCallNumber;\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhpWfsoThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    HANDLE eventHandle;\n    LARGE_INTEGER timeout;\n\n    eventHandle = Parameter;\n\n    timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC);\n    NtWaitForSingleObject(eventHandle, FALSE, &timeout);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhpWfmoThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    HANDLE eventHandle;\n    LARGE_INTEGER timeout;\n\n    eventHandle = Parameter;\n\n    timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC);\n    NtWaitForMultipleObjects(1, &eventHandle, WaitAll, FALSE, &timeout);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhpRfThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    HANDLE fileHandle;\n    IO_STATUS_BLOCK isb;\n    ULONG data;\n\n    fileHandle = Parameter;\n\n    NtReadFile(fileHandle, NULL, NULL, NULL, &isb, &data, sizeof(ULONG), NULL, NULL);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpInitializeServiceNumbers(\n    VOID\n    )\n{\n    if (PhBeginInitOnce(&ServiceNumbersInitOnce))\n    {\n        NTSTATUS status;\n        HANDLE eventHandle;\n        HANDLE threadHandle;\n        HANDLE pipeReadHandle;\n        HANDLE pipeWriteHandle;\n\n        // The ThreadLastSystemCall info class only works when the thread is in the Waiting\n        // state. We'll create a thread which blocks on an event object we create, then wait\n        // until it is in the Waiting state. Only then can we query the thread using\n        // ThreadLastSystemCall.\n\n        // NtWaitForSingleObject\n\n        status = PhCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NotificationEvent, FALSE);\n\n        if (NT_SUCCESS(status))\n        {\n            if (NT_SUCCESS(PhCreateThreadEx(&threadHandle, PhpWfsoThreadStart, eventHandle)))\n            {\n                if (PhpWaitUntilThreadIsWaiting(threadHandle))\n                {\n                    PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfso);\n                }\n\n                // Allow the thread to exit.\n                NtSetEvent(eventHandle, NULL);\n                NtClose(threadHandle);\n            }\n\n            NtClose(eventHandle);\n        }\n\n        // NtWaitForMultipleObjects\n\n        status = PhCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NotificationEvent, FALSE);\n\n        if (NT_SUCCESS(status))\n        {\n            if (NT_SUCCESS(PhCreateThreadEx(&threadHandle, PhpWfmoThreadStart, eventHandle)))\n            {\n                if (PhpWaitUntilThreadIsWaiting(threadHandle))\n                {\n                    PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfmo);\n                }\n\n                NtSetEvent(eventHandle, NULL);\n                NtClose(threadHandle);\n            }\n\n            NtClose(eventHandle);\n        }\n\n        // NtReadFile\n\n        status = PhCreatePipe(&pipeReadHandle, &pipeWriteHandle);\n\n        if (NT_SUCCESS(status))\n        {\n            if (NT_SUCCESS(PhCreateThreadEx(&threadHandle, PhpRfThreadStart, pipeReadHandle)))\n            {\n                ULONG data = 0;\n                IO_STATUS_BLOCK isb;\n\n                if (PhpWaitUntilThreadIsWaiting(threadHandle))\n                {\n                    PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForRf);\n                }\n\n                NtWriteFile(pipeWriteHandle, NULL, NULL, NULL, &isb, &data, sizeof(data), NULL, NULL);\n                NtClose(threadHandle);\n            }\n\n            NtClose(pipeReadHandle);\n            NtClose(pipeWriteHandle);\n        }\n\n        PhEndInitOnce(&ServiceNumbersInitOnce);\n    }\n}\n\nPPH_STRING PhpaGetHandleString(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle\n    )\n{\n    PPH_STRING typeName = NULL;\n    PPH_STRING name = NULL;\n    PPH_STRING result;\n\n    PhGetHandleInformation(\n        ProcessHandle,\n        Handle,\n        ULONG_MAX,\n        NULL,\n        &typeName,\n        NULL,\n        &name\n        );\n\n    if (typeName && name)\n    {\n        result = PhaFormatString(\n            L\"Handle 0x%lx (%s): %s\",\n            HandleToUlong(Handle),\n            typeName->Buffer,\n            !PhIsNullOrEmptyString(name) ? name->Buffer : L\"(unnamed object)\"\n            );\n    }\n    else\n    {\n        result = PhaFormatString(\n            L\"Handle 0x%lx: (error querying handle)\",\n            HandleToUlong(Handle)\n            );\n    }\n\n    if (typeName)\n        PhDereferenceObject(typeName);\n    if (name)\n        PhDereferenceObject(name);\n\n    return result;\n}\n\nVOID PhpGetWfmoInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN IsWow64Process,\n    _In_ ULONG NumberOfHandles,\n    _In_ PHANDLE AddressOfHandles,\n    _In_ WAIT_TYPE WaitType,\n    _In_ BOOLEAN Alertable,\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    )\n{\n    NTSTATUS status;\n    HANDLE handles[MAXIMUM_WAIT_OBJECTS];\n    ULONG i;\n\n    status = STATUS_SUCCESS;\n\n    if (NumberOfHandles <= MAXIMUM_WAIT_OBJECTS)\n    {\n#ifdef _WIN64\n        if (IsWow64Process)\n        {\n            ULONG handles32[MAXIMUM_WAIT_OBJECTS];\n\n            if (NT_SUCCESS(status = PhReadVirtualMemory(\n                ProcessHandle,\n                AddressOfHandles,\n                handles32,\n                NumberOfHandles * sizeof(ULONG),\n                NULL\n                )))\n            {\n                for (i = 0; i < NumberOfHandles; i++)\n                    handles[i] = UlongToHandle(handles32[i]);\n            }\n        }\n        else\n        {\n#endif\n            status = PhReadVirtualMemory(\n                ProcessHandle,\n                AddressOfHandles,\n                handles,\n                NumberOfHandles * sizeof(HANDLE),\n                NULL\n                );\n#ifdef _WIN64\n        }\n#endif\n\n        if (NT_SUCCESS(status))\n        {\n            PhAppendFormatStringBuilder(\n                StringBuilder,\n                L\"Thread is waiting (%s, %s) for:\\r\\n\",\n                Alertable ? L\"alertable\" : L\"non-alertable\",\n                WaitType == WaitAll ? L\"wait all\" : L\"wait any\"\n                );\n\n            for (i = 0; i < NumberOfHandles; i++)\n            {\n                PhAppendStringBuilder(\n                    StringBuilder,\n                    &PhpaGetHandleString(ProcessHandle, handles[i])->sr\n                    );\n                PhAppendStringBuilder2(\n                    StringBuilder,\n                    L\"\\r\\n\"\n                    );\n            }\n        }\n    }\n\n    if (!NT_SUCCESS(status) || NumberOfHandles > MAXIMUM_WAIT_OBJECTS)\n    {\n        PhAppendStringBuilder2(\n            StringBuilder,\n            L\"Thread is waiting for multiple objects.\"\n            );\n    }\n}\n\nPPH_STRING PhpaGetSendMessageReceiver(\n    _In_ HANDLE ThreadId\n    )\n{\n    HWND windowHandle;\n    CLIENT_ID clientId;\n    PPH_STRING clientIdName;\n    WCHAR windowClass[64];\n    PPH_STRING windowText;\n\n    if (!NT_SUCCESS(PhGetSendMessageReceiver(ThreadId, &windowHandle)))\n        return NULL;\n\n    if (!NT_SUCCESS(PhGetWindowClientId(windowHandle, &clientId)))\n        return NULL;\n\n    clientIdName = PH_AUTO(PhGetClientIdName(&clientId));\n\n    if (!GetClassName(windowHandle, windowClass, sizeof(windowClass) / sizeof(WCHAR)))\n        windowClass[0] = UNICODE_NULL;\n\n    windowText = PH_AUTO(PhGetWindowText(windowHandle));\n\n    return PhaFormatString(L\"Window 0x%Ix (%s): %s \\\"%s\\\"\", (ULONG_PTR)windowHandle, clientIdName->Buffer, windowClass, PhGetStringOrEmpty(windowText));\n}\n\nPPH_STRING PhpaGetAlpcInformation(\n    _In_ HANDLE ThreadId\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string = NULL;\n    HANDLE threadHandle;\n    PALPC_SERVER_INFORMATION serverInfo;\n    ULONG bufferLength;\n\n    if (!NT_SUCCESS(PhOpenThread(&threadHandle, THREAD_QUERY_INFORMATION, ThreadId)))\n        return NULL;\n\n    bufferLength = 0x110;\n    serverInfo = PhAllocate(bufferLength);\n    serverInfo->In.ThreadHandle = threadHandle;\n\n    status = NtAlpcQueryInformation(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength);\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(serverInfo);\n        serverInfo = PhAllocate(bufferLength);\n        serverInfo->In.ThreadHandle = threadHandle;\n\n        status = NtAlpcQueryInformation(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength);\n    }\n\n    if (NT_SUCCESS(status) && serverInfo->Out.ThreadBlocked)\n    {\n        CLIENT_ID clientId;\n        PPH_STRING clientIdName;\n\n        clientId.UniqueProcess = serverInfo->Out.ConnectedProcessId;\n        clientId.UniqueThread = NULL;\n        clientIdName = PH_AUTO(PhGetClientIdName(&clientId));\n\n        string = PhaFormatString(L\"ALPC Port: %.*s (%s)\", serverInfo->Out.ConnectionPortName.Length / sizeof(WCHAR), serverInfo->Out.ConnectionPortName.Buffer, clientIdName->Buffer);\n    }\n\n    PhFree(serverInfo);\n    NtClose(threadHandle);\n\n    return string;\n}\n"
  },
  {
    "path": "SystemInformer/appsup.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n\n#include <cpysave.h>\n#include <emenu.h>\n#include <symprv.h>\n#include <settings.h>\n#include <phsettings.h>\n\n#include <actions.h>\n#include <mainwnd.h>\n#include <lsasup.h>\n#include <phappres.h>\n#include <phsvccl.h>\n#include <thirdparty.h>\n#include <phconsole.h>\n\n/**\n * Determines whether a process is suspended.\n *\n * \\param Process The SYSTEM_PROCESS_INFORMATION structure\n * of the process.\n */\nBOOLEAN PhGetProcessIsSuspended(\n    _In_ PSYSTEM_PROCESS_INFORMATION Process\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Process->NumberOfThreads; i++)\n    {\n        if (\n            Process->Threads[i].ThreadState != Waiting ||\n            Process->Threads[i].WaitReason != Suspended\n            )\n            return FALSE;\n    }\n\n    return Process->UserTime.QuadPart + Process->KernelTime.QuadPart != 0 && Process->NumberOfThreads != 0;\n}\n\nBOOLEAN PhIsProcessSuspended(\n    _In_ HANDLE ProcessId\n    )\n{\n    BOOLEAN suspended = FALSE;\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n\n    if (NT_SUCCESS(PhEnumProcesses(&processes)))\n    {\n        if (process = PhFindProcessInformation(processes, ProcessId))\n        {\n            suspended = PhGetProcessIsSuspended(process);\n        }\n\n        PhFree(processes);\n    }\n\n    return suspended;\n}\n\nBOOLEAN PhIsProcessBackground(\n    _In_ ULONG PriorityClass\n    )\n{\n    // This is similar to PROCESS_MODE_BACKGROUND_BEGIN (dmex)\n    if (\n        PriorityClass == PROCESS_PRIORITY_CLASS_BELOW_NORMAL ||\n        PriorityClass == PROCESS_PRIORITY_CLASS_IDLE\n        )\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nstatic CONST PH_KEY_VALUE_PAIR ProcessPriorityClassTypePairs[] =\n{\n    SIP(SREF(L\"Unknown\"), PROCESS_PRIORITY_CLASS_UNKNOWN),\n    SIP(SREF(L\"Idle\"), PROCESS_PRIORITY_CLASS_IDLE),\n    SIP(SREF(L\"Normal\"), PROCESS_PRIORITY_CLASS_NORMAL),\n    SIP(SREF(L\"High\"), PROCESS_PRIORITY_CLASS_HIGH),\n    SIP(SREF(L\"Real time\"), PROCESS_PRIORITY_CLASS_REALTIME),\n    SIP(SREF(L\"Below normal\"), PROCESS_PRIORITY_CLASS_BELOW_NORMAL),\n    SIP(SREF(L\"Above normal\"), PROCESS_PRIORITY_CLASS_ABOVE_NORMAL),\n};\n\nPCPH_STRINGREF PhGetProcessPriorityClassString(\n    _In_ ULONG PriorityClass\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        ProcessPriorityClassTypePairs,\n        sizeof(ProcessPriorityClassTypePairs),\n        PriorityClass,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    static_assert(ARRAYSIZE(ProcessPriorityClassTypePairs) == PROCESS_PRIORITY_CLASS_ABOVE_NORMAL + 1, \"PriorityClassString must equal PROCESS_PRIORITY_CLASS_MAX\");\n\n    return (PCPH_STRINGREF)ProcessPriorityClassTypePairs[PROCESS_PRIORITY_CLASS_UNKNOWN].Key;\n\n    //switch (PriorityClass)\n    //{\n    //case PROCESS_PRIORITY_CLASS_REALTIME:\n    //    return L\"Real time\";\n    //case PROCESS_PRIORITY_CLASS_HIGH:\n    //    return L\"High\";\n    //case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL:\n    //    return L\"Above normal\";\n    //case PROCESS_PRIORITY_CLASS_NORMAL:\n    //    return L\"Normal\";\n    //case PROCESS_PRIORITY_CLASS_BELOW_NORMAL:\n    //    return L\"Below normal\";\n    //case PROCESS_PRIORITY_CLASS_IDLE:\n    //    return L\"Idle\";\n    //case PROCESS_PRIORITY_CLASS_UNKNOWN:\n    //default:\n    //    return L\"Unknown\";\n    //}\n}\n\nstatic CONST PH_KEY_VALUE_PAIR PhProtectedTypeStrings[] =\n{\n    SIP(L\"None\", NULL), // PsProtectedTypeNone\n    SIP(L\"Light\", PsProtectedTypeProtectedLight),\n    SIP(L\"Full\", PsProtectedTypeProtected),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR PhProtectedSignerStrings[] =\n{\n    SIP(L\"None\", NULL), // PsProtectedSignerNone\n    SIP(L\"Authenticode\", PsProtectedSignerAuthenticode),\n    SIP(L\"CodeGen\", PsProtectedSignerCodeGen),\n    SIP(L\"Antimalware\", PsProtectedSignerAntimalware),\n    SIP(L\"Lsa\", PsProtectedSignerLsa),\n    SIP(L\"Windows\", PsProtectedSignerWindows),\n    SIP(L\"WinTcb\", PsProtectedSignerWinTcb),\n    SIP(L\"WinSystem\", PsProtectedSignerWinSystem),\n    SIP(L\"StoreApp\", PsProtectedSignerApp),\n};\n\nstatic_assert(RTL_NUMBER_OF(PhProtectedTypeStrings) == PsProtectedTypeMax, \"PsProtectedTypeStrings must equal PsProtectedTypeMax (value offsets)\");\nstatic_assert(RTL_NUMBER_OF(PhProtectedSignerStrings) == PsProtectedSignerMax, \"PhProtectedSignerStrings must equal PsProtectedSignerMax (value offsets)\");\n\nPPH_STRING PhGetProcessProtectionString(\n    _In_ PS_PROTECTION Protection,\n    _In_ BOOLEAN IsSecureProcess\n    )\n{\n    if (Protection.Level)\n    {\n        static PPH_STRING PhpProtectionNoneString = NULL;\n        PH_FORMAT format[6];\n        ULONG count = 0;\n        PCWSTR type;\n        PCWSTR signer;\n\n        if (!PhpProtectionNoneString)\n            PhpProtectionNoneString = PhCreateString(L\"None\");\n\n        if (IsSecureProcess)\n        {\n            PhInitFormatS(&format[count++], L\"Secure \");\n        }\n\n        if (PhIndexStringSiKeyValuePairs(\n            PhProtectedTypeStrings,\n            sizeof(PhProtectedTypeStrings),\n            Protection.Type,\n            &type\n            ))\n        {\n            PhInitFormatS(&format[count++], type);\n        }\n        else\n        {\n            PhInitFormatS(&format[count++], L\"Unknown\");\n        }\n\n        if (PhIndexStringSiKeyValuePairs(\n            PhProtectedSignerStrings,\n            sizeof(PhProtectedSignerStrings),\n            Protection.Signer,\n            &signer\n            ))\n        {\n            PhInitFormatS(&format[count++], L\" (\");\n            PhInitFormatS(&format[count++], signer);\n            PhInitFormatS(&format[count++], L\")\");\n        }\n        else\n        {\n            PhInitFormatS(&format[count++], L\" (\");\n            PhInitFormatS(&format[count++], L\"Unknown\");\n            PhInitFormatS(&format[count++], L\")\");\n        }\n\n        if (Protection.Audit)\n        {\n            PhInitFormatS(&format[count++], L\" (Audit)\");\n        }\n\n        return PhFormat(format, count, 10);\n    }\n    else\n    {\n        static PPH_STRING PhpProtectionSecureIUMString = NULL;\n\n        if (!PhpProtectionSecureIUMString)\n            PhpProtectionSecureIUMString = PhCreateString(L\"Secure (IUM)\");\n\n        if (IsSecureProcess)\n        {\n            return PhReferenceObject(PhpProtectionSecureIUMString);\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Determines the OS compatibility context of a process.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param Guid A variable which receives a GUID identifying an\n * operating system version.\n */\nNTSTATUS PhGetProcessSwitchContext(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PGUID Guid\n    )\n{\n    NTSTATUS status;\n    PROCESS_BASIC_INFORMATION basicInfo;\n#ifdef _WIN64\n    PVOID peb32;\n    ULONG data32;\n#endif\n    PVOID data;\n\n    // Reverse-engineered from WdcGetProcessSwitchContext (wdc.dll).\n    // On Windows 8, the function is now SdbGetAppCompatData (apphelp.dll).\n    // On Windows 10, the function is again WdcGetProcessSwitchContext.\n\n#ifdef _WIN64\n    if (NT_SUCCESS(PhGetProcessPeb32(ProcessHandle, &peb32)) && peb32)\n    {\n        if (WindowsVersion >= WINDOWS_8)\n        {\n            if (!NT_SUCCESS(status = PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pShimData)),\n                &data32,\n                sizeof(ULONG),\n                NULL\n                )))\n                return status;\n        }\n        else\n        {\n            if (!NT_SUCCESS(status = PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pContextData)),\n                &data32,\n                sizeof(ULONG),\n                NULL\n                )))\n                return status;\n        }\n\n        data = UlongToPtr(data32);\n    }\n    else\n    {\n#endif\n        if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo)))\n            return status;\n\n        if (WindowsVersion >= WINDOWS_8)\n        {\n            if (!NT_SUCCESS(status = PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pShimData)),\n                &data,\n                sizeof(PVOID),\n                NULL\n                )))\n                return status;\n        }\n        else\n        {\n            if (!NT_SUCCESS(status = PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pContextData)),\n                &data,\n                sizeof(PVOID),\n                NULL\n                )))\n                return status;\n        }\n#ifdef _WIN64\n    }\n#endif\n\n    if (!data)\n        return STATUS_UNSUCCESSFUL; // no compatibility context data\n\n    if (WindowsVersion >= WINDOWS_10_RS5)\n    {\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(data, 2040 + 24), // Magic value from SbReadProcContextByHandle\n            Guid,\n            sizeof(GUID),\n            NULL\n            )))\n            return status;\n    }\n    else if (WindowsVersion >= WINDOWS_10_RS2)\n    {\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(data, 1544),\n            Guid,\n            sizeof(GUID),\n            NULL\n            )))\n            return status;\n    }\n    else if (WindowsVersion >= WINDOWS_10)\n    {\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(data, 2040 + 24), // Magic value from SbReadProcContextByHandle\n            Guid,\n            sizeof(GUID),\n            NULL\n            )))\n            return status;\n    }\n    else if (WindowsVersion >= WINDOWS_8_1)\n    {\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(data, 2040 + 16), // Magic value from SbReadProcContextByHandle\n            Guid,\n            sizeof(GUID),\n            NULL\n            )))\n            return status;\n    }\n    else if (WindowsVersion >= WINDOWS_8)\n    {\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(data, 2040), // Magic value from SbReadProcContextByHandle\n            Guid,\n            sizeof(GUID),\n            NULL\n            )))\n            return status;\n    }\n    else\n    {\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(data, 32), // Magic value from WdcGetProcessSwitchContext\n            Guid,\n            sizeof(GUID),\n            NULL\n            )))\n            return status;\n    }\n\n    //static ULONG (WINAPI *BaseReadAppCompatDataForProcess_I)(\n    //    _In_ HANDLE ProcessHandle,\n    //    _Out_ PULONG_PTR ShimData,\n    //    _Out_opt_ PULONG_PTR ShimDataBaseAddress\n    //    ) = NULL;\n    //static ULONG (WINAPI *BaseFreeAppCompatDataForProcess_I)(\n    //    _In_ ULONG_PTR ShimData\n    //    ) = NULL;\n    //\n    //if (!BaseReadAppCompatDataForProcess_I)\n    //    BaseReadAppCompatDataForProcess_I = PhGetDllProcedureAddressZ(L\"kernelbase.dll\", \"BaseReadAppCompatDataForProcess\", 0);\n    //if (!BaseFreeAppCompatDataForProcess_I)\n    //    BaseFreeAppCompatDataForProcess_I = PhGetDllProcedureAddressZ(L\"kernelbase.dll\", \"BaseFreeAppCompatDataForProcess\", 0);\n    //\n    //if (BaseReadAppCompatDataForProcess_I && BaseFreeAppCompatDataForProcess_I)\n    //{\n    //    ULONG_PTR pShimData;\n    //\n    //    if (BaseReadAppCompatDataForProcess_I(ProcessHandle, &pShimData, NULL) == ERROR_SUCCESS)\n    //    {\n    //        if (WindowsVersion >= WINDOWS_10_RS5)\n    //        {\n    //            *Guid = *(PGUID)PTR_ADD_OFFSET(pShimData, 2040 + 24);\n    //            BaseFreeAppCompatDataForProcess_I(pShimData);\n    //            return STATUS_SUCCESS;\n    //        }\n    //\n    //        BaseFreeAppCompatDataForProcess_I(pShimData);\n    //    }\n    //\n    //    return STATUS_UNSUCCESSFUL;\n    //}\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetProcessDefaultHeap(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID *Heap\n    )\n{\n    NTSTATUS status;\n#ifdef _WIN64\n    BOOLEAN IsWow64;\n\n    status = PhGetProcessIsWow64(ProcessHandle, &IsWow64);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (IsWow64)\n    {\n        PVOID peb32;\n        ULONG processHeapsPtr32;\n\n        status = PhGetProcessPeb32(ProcessHandle, &peb32);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(peb32, UFIELD_OFFSET(PEB32, ProcessHeap)),\n            &processHeapsPtr32,\n            sizeof(ULONG),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (Heap)\n        {\n            *Heap = UlongToPtr(processHeapsPtr32);\n        }\n\n        return status;\n    }\n    else\n    {\n#endif\n        PROCESS_BASIC_INFORMATION basicInfo;\n        PVOID processHeapsPtr;\n\n        status = PhGetProcessBasicInformation(\n            ProcessHandle,\n            &basicInfo\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.PebBaseAddress, UFIELD_OFFSET(PEB, ProcessHeap)),\n            &processHeapsPtr,\n            sizeof(PVOID),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (Heap)\n        {\n            *Heap = processHeapsPtr;\n        }\n\n        return status;\n#ifdef _WIN64\n    }\n#endif\n}\n\n/**\n * Determines the type of a process based on its image file name.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param KnownProcessType A variable which receives the process\n * type.\n */\nNTSTATUS PhGetProcessKnownType(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PH_KNOWN_PROCESS_TYPE *KnownProcessType\n    )\n{\n    NTSTATUS status;\n    PROCESS_BASIC_INFORMATION basicInfo;\n    PPH_STRING fileName;\n\n    if (!NT_SUCCESS(status = PhGetProcessBasicInformation(\n        ProcessHandle,\n        &basicInfo\n        )))\n        return status;\n\n    if (basicInfo.UniqueProcessId == SYSTEM_PROCESS_ID)\n    {\n        *KnownProcessType = SystemProcessType;\n        return STATUS_SUCCESS;\n    }\n\n    if (!NT_SUCCESS(status = PhGetProcessImageFileName(\n        ProcessHandle,\n        &fileName\n        )))\n    {\n        return status;\n    }\n\n    *KnownProcessType = PhGetProcessKnownTypeEx(\n        basicInfo.UniqueProcessId,\n        fileName\n        );\n\n    PhDereferenceObject(fileName);\n\n    return status;\n}\n\nPH_KNOWN_PROCESS_TYPE PhGetProcessKnownTypeEx(\n    _In_opt_ HANDLE ProcessId,\n    _In_ PPH_STRING FileName\n    )\n{\n    PH_KNOWN_PROCESS_TYPE knownProcessType;\n    PH_STRINGREF systemRootPrefix;\n    PPH_STRING fileName;\n    PH_STRINGREF name;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n\n    if (ProcessId == SYSTEM_PROCESS_ID || ProcessId == SYSTEM_IDLE_PROCESS_ID)\n        return SystemProcessType;\n\n    if (PhIsNullOrEmptyString(FileName))\n        return UnknownProcessType;\n\n    PhGetNtSystemRoot(&systemRootPrefix);\n\n    fileName = PhReferenceObject(FileName);\n    name = fileName->sr;\n\n    knownProcessType = UnknownProcessType;\n\n    if (PhStartsWithStringRef(&name, &systemRootPrefix, TRUE))\n    {\n        // Skip the system root, and we now have three cases:\n        // 1. \\\\xyz.exe - Windows executable.\n        // 2. \\\\System32\\\\xyz.exe - system32 executable.\n        // 3. \\\\SysWow64\\\\xyz.exe - system32 executable + WOW64.\n        PhSkipStringRef(&name, systemRootPrefix.Length);\n\n        if (PhEqualStringRef2(&name, L\"\\\\explorer.exe\", TRUE))\n        {\n            knownProcessType = ExplorerProcessType;\n        }\n        else if (\n            PhStartsWithStringRef2(&name, L\"\\\\System32\", TRUE)\n#ifdef _WIN64\n            || (PhStartsWithStringRef2(&name, L\"\\\\SysWOW64\", TRUE) && (isWow64 = TRUE, TRUE)) // ugly but necessary\n#ifdef _M_ARM64\n            || (PhStartsWithStringRef2(&name, L\"\\\\SysArm32\", TRUE) && (isWow64 = TRUE, TRUE)) // ugly but necessary\n            || (PhStartsWithStringRef2(&name, L\"\\\\SyChpe32\", TRUE) && (isWow64 = TRUE, TRUE)) // ugly but necessary\n#endif\n#endif\n            )\n        {\n            // System32, SysWow64, SysArm32, and SyChpe32 are all 8 characters long.\n            PhSkipStringRef(&name, 9 * sizeof(WCHAR));\n\n            if (FALSE)\n                ; // Dummy\n            else if (PhEqualStringRef2(&name, L\"\\\\smss.exe\", TRUE))\n                knownProcessType = SessionManagerProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\csrss.exe\", TRUE))\n                knownProcessType = WindowsSubsystemProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\wininit.exe\", TRUE))\n                knownProcessType = WindowsStartupProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\services.exe\", TRUE))\n                knownProcessType = ServiceControlManagerProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\lsass.exe\", TRUE))\n                knownProcessType = LocalSecurityAuthorityProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\lsm.exe\", TRUE))\n                knownProcessType = LocalSessionManagerProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\winlogon.exe\", TRUE))\n                knownProcessType = WindowsLogonProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\svchost.exe\", TRUE))\n                knownProcessType = ServiceHostProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\rundll32.exe\", TRUE))\n                knownProcessType = RunDllAsAppProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\dllhost.exe\", TRUE))\n                knownProcessType = ComSurrogateProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\taskeng.exe\", TRUE))\n                knownProcessType = TaskHostProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\taskhost.exe\", TRUE))\n                knownProcessType = TaskHostProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\taskhostex.exe\", TRUE))\n                knownProcessType = TaskHostProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\taskhostw.exe\", TRUE))\n                knownProcessType = TaskHostProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\wudfhost.exe\", TRUE))\n                knownProcessType = UmdfHostProcessType;\n            else if (PhEqualStringRef2(&name, L\"\\\\wbem\\\\WmiPrvSE.exe\", TRUE))\n                knownProcessType = WmiProviderHostType;\n            //else if (PhEqualStringRef2(&name, L\"\\\\MicrosoftEdgeCP.exe\", TRUE)) // RS5\n            //    knownProcessType = EdgeProcessType;\n            //else if (PhEqualStringRef2(&name, L\"\\\\MicrosoftEdgeSH.exe\", TRUE)) // RS5\n            //    knownProcessType = EdgeProcessType;\n#ifdef _M_IX86\n            else if (PhEqualStringRef2(&name, L\"\\\\ntvdm.exe\", TRUE))\n                knownProcessType = NtVdmHostProcessType;\n#endif\n        }\n        //else\n        //{\n        //    if (PhEndsWithStringRef2(&name, L\"\\\\MicrosoftEdgeCP.exe\", TRUE)) // RS4\n        //        knownProcessType = EdgeProcessType;\n        //    else if (PhEndsWithStringRef2(&name, L\"\\\\MicrosoftEdge.exe\", TRUE))\n        //        knownProcessType = EdgeProcessType;\n        //    else if (PhEndsWithStringRef2(&name, L\"\\\\ServiceWorkerHost.exe\", TRUE))\n        //        knownProcessType = EdgeProcessType;\n        //    else if (PhEndsWithStringRef2(&name, L\"\\\\Windows.WARP.JITService.exe\", TRUE))\n        //        knownProcessType = EdgeProcessType;\n        //}\n    }\n\n    PhDereferenceObject(fileName);\n\n#ifdef _WIN64\n    if (isWow64)\n        knownProcessType |= KnownProcessWow64;\n#endif\n\n    return knownProcessType;\n}\n\n_Function_class_(PH_COMMAND_LINE_CALLBACK)\nstatic BOOLEAN NTAPI PhpSvchostCommandLineCallback(\n    _In_opt_ PCPH_COMMAND_LINE_OPTION Option,\n    _In_opt_ PPH_STRING Value,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine = Context;\n\n    if (knownCommandLine && Option && Option->Id == 1)\n    {\n        PhSwapReference(&knownCommandLine->ServiceHost.GroupName, Value);\n    }\n\n    return TRUE;\n}\n\n_Success_(return)\nBOOLEAN PhaGetProcessKnownCommandLine(\n    _In_ PPH_STRING CommandLine,\n    _In_ PH_KNOWN_PROCESS_TYPE KnownProcessType,\n    _Out_ PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine\n    )\n{\n    switch (KnownProcessType & KnownProcessTypeMask)\n    {\n    case ServiceHostProcessType:\n        {\n            // svchost.exe -k <GroupName>\n\n            static CONST PH_COMMAND_LINE_OPTION options[] =\n            {\n                { 1, L\"k\", MandatoryArgumentType }\n            };\n\n            KnownCommandLine->ServiceHost.GroupName = NULL;\n\n            PhParseCommandLine(\n                &CommandLine->sr,\n                options,\n                sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION),\n                PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS,\n                PhpSvchostCommandLineCallback,\n                KnownCommandLine\n                );\n\n            if (KnownCommandLine->ServiceHost.GroupName)\n            {\n                PH_AUTO(KnownCommandLine->ServiceHost.GroupName);\n                return TRUE;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        break;\n    case RunDllAsAppProcessType:\n        {\n            // rundll32.exe <DllName>,<ProcedureName> ...\n\n            SIZE_T i;\n            PH_STRINGREF dllNamePart;\n            PH_STRINGREF procedureNamePart;\n            PPH_STRING dllName;\n            PPH_STRING procedureName;\n\n            i = 0;\n\n            // Get the rundll32.exe part.\n\n            dllName = PhParseCommandLinePart(&CommandLine->sr, &i);\n\n            if (!dllName)\n                return FALSE;\n\n            PhDereferenceObject(dllName);\n\n            // Get the DLL name part.\n\n            while (i < CommandLine->Length / sizeof(WCHAR) && CommandLine->Buffer[i] == L' ')\n                i++;\n\n            dllName = PhParseCommandLinePart(&CommandLine->sr, &i);\n\n            if (!dllName)\n                return FALSE;\n\n            PH_AUTO(dllName);\n\n            // The procedure name begins after the last comma.\n\n            if (!PhSplitStringRefAtLastChar(&dllName->sr, L',', &dllNamePart, &procedureNamePart))\n                return FALSE;\n\n            dllName = PH_AUTO(PhCreateString2(&dllNamePart));\n            procedureName = PH_AUTO(PhCreateString2(&procedureNamePart));\n\n            // If the DLL name isn't an absolute path, assume it's in system32.\n            // TODO: Use a proper search function.\n\n            if (PhDetermineDosPathNameType(&dllName->sr) == RtlPathTypeRelative)\n            {\n                dllName = PhGetSystemDirectoryWin32(&dllName->sr);\n            }\n\n            KnownCommandLine->RunDllAsApp.FileName = dllName;\n            KnownCommandLine->RunDllAsApp.ProcedureName = procedureName;\n        }\n        break;\n    case ComSurrogateProcessType:\n        {\n            // dllhost.exe /processid:<Guid>\n\n            static CONST PH_STRINGREF inprocServer32Name = PH_STRINGREF_INIT(L\"InprocServer32\");\n\n            SIZE_T i;\n            ULONG_PTR indexOfProcessId;\n            PPH_STRING argPart;\n            PPH_STRING guidString;\n            GUID guid;\n            HANDLE rootKeyHandle;\n            HANDLE inprocServer32KeyHandle;\n            PPH_STRING fileName;\n\n            i = 0;\n\n            // Get the dllhost.exe part.\n\n            argPart = PhParseCommandLinePart(&CommandLine->sr, &i);\n\n            if (!argPart)\n                return FALSE;\n\n            PhDereferenceObject(argPart);\n\n            // Get the argument part.\n\n            while (i < (ULONG)CommandLine->Length / sizeof(WCHAR) && CommandLine->Buffer[i] == L' ')\n                i++;\n\n            argPart = PhParseCommandLinePart(&CommandLine->sr, &i);\n\n            if (!argPart)\n                return FALSE;\n\n            PH_AUTO(argPart);\n\n            // Find \"/processid:\"; the GUID is just after that.\n\n            PhUpperStringRef(&argPart->sr);\n            indexOfProcessId = PhFindStringInString(argPart, 0, L\"/PROCESSID:\");\n\n            if (indexOfProcessId == SIZE_MAX)\n                return FALSE;\n\n            guidString = PhaSubstring(\n                argPart,\n                indexOfProcessId + 11,\n                argPart->Length / sizeof(WCHAR) - indexOfProcessId - 11\n                );\n\n            if (!NT_SUCCESS(PhStringToGuid(&guidString->sr, &guid)))\n                return FALSE;\n\n            KnownCommandLine->ComSurrogate.Guid = guid;\n            KnownCommandLine->ComSurrogate.Name = NULL;\n            KnownCommandLine->ComSurrogate.FileName = NULL;\n\n            // Lookup the GUID in the registry to determine the name and file name.\n\n            if (NT_SUCCESS(PhOpenKey(\n                &rootKeyHandle,\n                KEY_READ,\n                PH_KEY_CLASSES_ROOT,\n                &PhaConcatStrings2(L\"CLSID\\\\\", guidString->Buffer)->sr,\n                0\n                )))\n            {\n                KnownCommandLine->ComSurrogate.Name = PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL));\n\n                if (NT_SUCCESS(PhOpenKey(\n                    &inprocServer32KeyHandle,\n                    KEY_READ,\n                    rootKeyHandle,\n                    &inprocServer32Name,\n                    0\n                    )))\n                {\n                    KnownCommandLine->ComSurrogate.FileName = PH_AUTO(PhQueryRegistryString(inprocServer32KeyHandle, NULL));\n\n                    if (fileName = PH_AUTO(PhExpandEnvironmentStrings(&KnownCommandLine->ComSurrogate.FileName->sr)))\n                    {\n                        KnownCommandLine->ComSurrogate.FileName = fileName;\n                    }\n\n                    NtClose(inprocServer32KeyHandle);\n                }\n\n                NtClose(rootKeyHandle);\n            }\n            else if (NT_SUCCESS(PhOpenKey(\n                &rootKeyHandle,\n                KEY_READ,\n                PH_KEY_CLASSES_ROOT,\n                &PhaConcatStrings2(L\"AppID\\\\\", guidString->Buffer)->sr,\n                0\n                )))\n            {\n                KnownCommandLine->ComSurrogate.Name = PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL));\n                NtClose(rootKeyHandle);\n            }\n        }\n        break;\n    default:\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nPPH_STRING PhEscapeStringForDelimiter(\n    _In_ PPH_STRING String,\n    _In_ WCHAR Delimiter\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    SIZE_T length;\n    SIZE_T i;\n    WCHAR temp[2];\n\n    length = String->Length / sizeof(WCHAR);\n    PhInitializeStringBuilder(&stringBuilder, String->Length / sizeof(WCHAR) * 3);\n\n    temp[0] = L'\\\\';\n\n    for (i = 0; i < length; i++)\n    {\n        if (String->Buffer[i] == L'\\\\' || String->Buffer[i] == Delimiter)\n        {\n            temp[1] = String->Buffer[i];\n            PhAppendStringBuilderEx(&stringBuilder, temp, 4);\n        }\n        else\n        {\n            PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);\n        }\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nPPH_STRING PhUnescapeStringForDelimiter(\n    _In_ PPH_STRING String,\n    _In_ WCHAR Delimiter\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    SIZE_T length;\n    SIZE_T i;\n\n    length = String->Length / sizeof(WCHAR);\n    PhInitializeStringBuilder(&stringBuilder, String->Length / sizeof(WCHAR) * 3);\n\n    for (i = 0; i < length; i++)\n    {\n        if (String->Buffer[i] == L'\\\\')\n        {\n            if (i != length - 1)\n            {\n                PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i + 1]);\n                i++;\n            }\n            else\n            {\n                // Trailing backslash. Just ignore it.\n                break;\n            }\n        }\n        else\n        {\n            PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);\n        }\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nVOID PhSearchOnlineString(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR String\n    )\n{\n    PhShellExecuteUserString(WindowHandle, SETTING_SEARCH_ENGINE, String, TRUE, NULL);\n}\n\nVOID PhShellExecuteUserString(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Setting,\n    _In_ PCWSTR String,\n    _In_ BOOLEAN UseShellExecute,\n    _In_opt_ PCWSTR ErrorMessage\n    )\n{\n    static CONST PH_STRINGREF replacementToken = PH_STRINGREF_INIT(L\"%s\");\n    PPH_STRING applicationDirectory;\n    PPH_STRING executeString;\n    PH_STRINGREF stringBefore;\n    PH_STRINGREF stringAfter;\n    PPH_STRING ntMessage;\n\n    // Get the execute command. (dmex)\n    executeString = PhGetStringSetting(Setting);\n\n    if (PhEqualString2(executeString, L\"%SystemRoot%\\\\explorer.exe /select,\\\"%s\\\"\", TRUE))\n    {\n        // Special case: Use PhShowFileInExplorer for this specific setting. (dmex)\n\n        if (String[0] == OBJ_NAME_PATH_SEPARATOR)\n        {\n            PPH_STRING stringTemp;\n            PPH_STRING stringMiddle;\n           \n            stringTemp = PhCreateString(String);\n            stringMiddle = PhGetFileName(stringTemp);\n\n            PhShellExploreFile(WindowHandle, PhGetString(stringMiddle));\n\n            PhDereferenceObject(stringMiddle);\n            PhDereferenceObject(stringTemp);\n        }\n        else\n        {\n            PhShellExploreFile(WindowHandle, String);\n        }\n\n        PhDereferenceObject(executeString);\n        return;\n    }\n\n    // Expand environment strings. (dmex)\n    PhMoveReference(&executeString, PhExpandEnvironmentStrings(&executeString->sr));\n    \n    if (!(applicationDirectory = PhGetApplicationDirectoryWin32()))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to locate the application directory.\", STATUS_NOT_FOUND, 0);\n        return;\n    }\n\n    // Make sure the user executable string is absolute. We can't use PhDetermineDosPathNameType\n    // here because the string may be a URL. (dmex)\n    if (PhFindCharInString(executeString, 0, L':') == SIZE_MAX)\n    {\n        static CONST PH_STRINGREF separator = PH_STRINGREF_INIT(L\"\\\"\");\n        static CONST PH_STRINGREF space = PH_STRINGREF_INIT(L\" \");\n        PPH_LIST stringArgList;\n        PPH_STRING fileName = NULL;\n        PPH_STRING fileArgs = NULL;\n\n        // HACK: Escape the individual executeString components. (dmex)\n\n        if (stringArgList = PhCommandLineToList(executeString->Buffer))\n        {\n            fileName = PhReferenceObject(stringArgList->Items[0]);\n\n            if (stringArgList->Count == 2)\n            {\n                fileArgs = PhReferenceObject(stringArgList->Items[1]);\n            }\n\n            PhDereferenceObjects(stringArgList->Items, stringArgList->Count);\n            PhDereferenceObject(stringArgList);\n        }\n\n        if (fileName && fileArgs)\n        {\n            // Make sure the string is absolute and escape the filename.\n            if (PhDetermineDosPathNameType(&fileName->sr) == RtlPathTypeRelative)\n            {\n                PhMoveReference(&fileName, PhConcatStringRef3(&separator, &applicationDirectory->sr, &fileName->sr));\n                PhMoveReference(&fileName, PhConcatStringRef2(&fileName->sr, &separator));\n            }\n            else\n            {\n                PhMoveReference(&fileName, PhConcatStringRef3(&separator, &fileName->sr, &separator));\n            }\n\n            // Escape the parameters.\n            PhMoveReference(&fileArgs, PhConcatStringRef3(&separator, &fileArgs->sr, &separator));\n\n            // Create the escaped execute string.\n            PhMoveReference(&executeString, PhConcatStringRef3(&fileName->sr, &space, &fileArgs->sr));\n        }\n        else\n        {\n            if (PhDetermineDosPathNameType(&executeString->sr) == RtlPathTypeRelative)\n            {\n                PhMoveReference(&executeString, PhConcatStringRef3(&separator, &applicationDirectory->sr, &executeString->sr));\n                PhMoveReference(&executeString, PhConcatStringRef2(&executeString->sr, &separator));\n            }\n            else\n            {\n                PhMoveReference(&executeString, PhConcatStringRef3(&separator, &executeString->sr, &separator));\n            }\n        }\n\n        PhClearReference(&fileArgs);\n        PhClearReference(&fileName);\n    }\n\n    // Replace the token with the string, or use the original string if the token is not present.\n    if (PhSplitStringRefAtString(&executeString->sr, &replacementToken, FALSE, &stringBefore, &stringAfter))\n    {\n        // Note: See PhGetProcessImageFileNameWin32 for a description of\n        // the issue with some filenames and faulty RamDisk software (dmex)\n\n        if (String[0] == OBJ_NAME_PATH_SEPARATOR) // Workaround faulty software (dmex)\n        {\n            PPH_STRING stringTemp;\n            PPH_STRING stringMiddle;\n\n            stringTemp = PhCreateString(String);\n            stringMiddle = PhGetFileName(stringTemp);\n\n            PhMoveReference(&executeString, PhConcatStringRef3(&stringBefore, &stringMiddle->sr, &stringAfter));\n\n            PhDereferenceObject(stringMiddle);\n            PhDereferenceObject(stringTemp);\n        }\n        else\n        {\n            PH_STRINGREF stringMiddle;\n\n            PhInitializeStringRefLongHint(&stringMiddle, String);\n\n            PhMoveReference(&executeString, PhConcatStringRef3(&stringBefore, &stringMiddle, &stringAfter));\n        }\n    }\n\n    if (UseShellExecute)\n    {\n        PhShellExecute(WindowHandle, executeString->Buffer, NULL);\n    }\n    else\n    {\n        NTSTATUS status;\n        HANDLE processHandle;\n\n        status = PhCreateProcessWin32(\n            NULL,\n            executeString->Buffer,\n            NULL,\n            NULL,\n            0,\n            NULL,\n            &processHandle,\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            PhConsoleSetForeground(processHandle, TRUE);\n            NtClose(processHandle);\n        }\n        else\n        {\n            if (ErrorMessage)\n            {\n                ntMessage = PhGetNtMessage(status);\n                PhShowError2(\n                    WindowHandle,\n                    L\"Unable to execute the command.\",\n                    L\"%s\\n%s\",\n                    PhGetStringOrDefault(ntMessage, L\"An unknown error occurred.\"),\n                    ErrorMessage\n                    );\n                PhDereferenceObject(ntMessage);\n            }\n            else\n            {\n                PhShowStatus(WindowHandle, L\"Unable to execute the command.\", status, 0);\n            }\n        }\n    }\n\n    PhDereferenceObject(executeString);\n    PhDereferenceObject(applicationDirectory);\n}\n\nVOID PhLoadSymbolProviderOptions(\n    _Inout_ PPH_SYMBOL_PROVIDER SymbolProvider\n    )\n{\n    static CONST PH_STRINGREF symbolPath = PH_STRINGREF_INIT(L\"_NT_SYMBOL_PATH\");\n    PPH_STRING searchPath = NULL;\n\n    PhSetOptionsSymbolProvider(\n        PH_SYMOPT_UNDNAME | PH_SYMOPT_VERIFY_MICROSOFT_CHAIN,\n        (PhGetIntegerSetting(SETTING_DBGHELP_UNDECORATE) ? PH_SYMOPT_UNDNAME : 0) |\n        (PhGetIntegerSetting(SETTING_DBGHELP_VERIFY_MICROSOFT_CHAIN) ? PH_SYMOPT_VERIFY_MICROSOFT_CHAIN : 0)\n        );\n\n    PhQueryEnvironmentVariable(NULL, &symbolPath, &searchPath);\n\n    if (PhIsNullOrEmptyString(searchPath))\n        searchPath = PhGetStringSetting(SETTING_DBGHELP_SEARCH_PATH);\n    if (!PhIsNullOrEmptyString(searchPath))\n        PhSetSearchPathSymbolProvider(SymbolProvider, searchPath->Buffer);\n    if (searchPath)\n        PhDereferenceObject(searchPath);\n}\n\n/**\n * Copies a string into a NMLVGETINFOTIP structure.\n *\n * \\param GetInfoTip The NMLVGETINFOTIP structure.\n * \\param Tip The string to copy.\n *\n * \\remarks The text is truncated if it is too long.\n */\nVOID PhCopyListViewInfoTip(\n    _Inout_ LPNMLVGETINFOTIP GetInfoTip,\n    _In_ PPH_STRINGREF Tip\n    )\n{\n    ULONG copyIndex;\n    ULONG bufferRemaining;\n    ULONG copyLength;\n\n    if (GetInfoTip->dwFlags == 0)\n    {\n        copyIndex = (ULONG)PhCountStringZ(GetInfoTip->pszText) + 1; // plus one for newline\n\n        if (GetInfoTip->cchTextMax - copyIndex < 2) // need at least two bytes\n            return;\n\n        bufferRemaining = GetInfoTip->cchTextMax - copyIndex - 1;\n        GetInfoTip->pszText[copyIndex - 1] = L'\\n';\n    }\n    else\n    {\n        copyIndex = 0;\n        bufferRemaining = GetInfoTip->cchTextMax;\n    }\n\n    copyLength = min((ULONG)Tip->Length / sizeof(WCHAR), bufferRemaining - 1);\n    memcpy(\n        &GetInfoTip->pszText[copyIndex],\n        Tip->Buffer,\n        copyLength * sizeof(WCHAR)\n        );\n    GetInfoTip->pszText[copyIndex + copyLength] = UNICODE_NULL;\n}\n\nVOID PhCopyListView(\n    _In_ HWND ListViewHandle\n    )\n{\n    PPH_STRING text;\n\n    text = PhGetListViewText(ListViewHandle);\n    PhSetClipboardString(ListViewHandle, &text->sr);\n    PhDereferenceObject(text);\n}\n\nVOID PhHandleListViewNotifyForCopy(\n    _In_ LPARAM lParam,\n    _In_ HWND ListViewHandle\n    )\n{\n    PhHandleListViewNotifyBehaviors(lParam, ListViewHandle, PH_LIST_VIEW_CTRL_C_BEHAVIOR);\n}\n\nVOID PhHandleListViewNotifyBehaviors(\n    _In_ LPARAM lParam,\n    _In_ HWND ListViewHandle,\n    _In_ ULONG Behaviors\n    )\n{\n#pragma warning(push)\n#pragma warning(disable:26454) // disable Windows SDK warning (dmex)\n    if (((LPNMHDR)lParam)->hwndFrom == ListViewHandle && ((LPNMHDR)lParam)->code == LVN_KEYDOWN)\n    {\n        LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)lParam;\n\n        switch (keyDown->wVKey)\n        {\n        case 'C':\n            if (Behaviors & PH_LIST_VIEW_CTRL_C_BEHAVIOR)\n            {\n                if (GetKeyState(VK_CONTROL) < 0)\n                    PhCopyListView(ListViewHandle);\n            }\n            break;\n        case 'A':\n            if (Behaviors & PH_LIST_VIEW_CTRL_A_BEHAVIOR)\n            {\n                if (GetKeyState(VK_CONTROL) < 0)\n                    PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED);\n            }\n            break;\n        }\n    }\n#pragma warning(pop)\n}\n\nBOOLEAN PhGetListViewContextMenuPoint(\n    _In_ HWND ListViewHandle,\n    _Out_ PPOINT Point\n    )\n{\n    LONG selectedIndex;\n    RECT bounds;\n    RECT clientRect;\n\n    // The user pressed a key to display the context menu.\n    // Suggest where the context menu should display.\n\n    if ((selectedIndex = PhFindListViewItemByFlags(ListViewHandle, INT_ERROR, LVNI_SELECTED)) != INT_ERROR)\n    {\n        if (ListView_GetItemRect(ListViewHandle, selectedIndex, &bounds, LVIR_BOUNDS))\n        {\n            LONG dpiValue = PhGetWindowDpi(ListViewHandle);\n\n            Point->x = bounds.left + PhGetSystemMetrics(SM_CXSMICON, dpiValue) / 2;\n            Point->y = bounds.top + PhGetSystemMetrics(SM_CYSMICON, dpiValue) / 2;\n\n            if (!PhGetClientRect(ListViewHandle, &clientRect))\n                return FALSE;\n\n            if (Point->x < 0 || Point->y < 0 || Point->x >= clientRect.right || Point->y >= clientRect.bottom)\n            {\n                // The menu is going to be outside of the control. Just put it at the top-left.\n                Point->x = 0;\n                Point->y = 0;\n            }\n\n            ClientToScreen(ListViewHandle, Point);\n\n            return TRUE;\n        }\n    }\n\n    Point->x = 0;\n    Point->y = 0;\n    ClientToScreen(ListViewHandle, Point);\n\n    return FALSE;\n}\n\nVOID PhSetWindowOpacity(\n    _In_ HWND WindowHandle,\n    _In_ ULONG OpacityPercent\n    )\n{\n    if (OpacityPercent == 0)\n    {\n        // Make things a bit faster by removing the WS_EX_LAYERED bit.\n        PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, 0);\n        RedrawWindow(WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);\n        return;\n    }\n\n    PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED);\n\n    // Disallow opacity values of less than 10%.\n    OpacityPercent = min(OpacityPercent, 90);\n\n    // The opacity value is backwards - 0 means opaque, 100 means transparent.\n    SetLayeredWindowAttributes(\n        WindowHandle,\n        0,\n        (BYTE)(255 * (100 - OpacityPercent) / 100),\n        LWA_ALPHA\n        );\n}\n\nPPH_STRING PhGetPhVersion(\n    VOID\n    )\n{\n    PH_FORMAT format[7];\n\n    PhInitFormatU(&format[0], PHAPP_VERSION_MAJOR);\n    PhInitFormatC(&format[1], L'.');\n    PhInitFormatU(&format[2], PHAPP_VERSION_MINOR);\n    PhInitFormatC(&format[3], L'.');\n    PhInitFormatU(&format[4], PHAPP_VERSION_BUILD);\n    PhInitFormatC(&format[5], L'.');\n    PhInitFormatU(&format[6], PHAPP_VERSION_REVISION);\n\n    return PhFormat(format, RTL_NUMBER_OF(format), 0);\n}\n\nVOID PhGetPhVersionNumbers(\n    _Out_opt_ PULONG MajorVersion,\n    _Out_opt_ PULONG MinorVersion,\n    _Out_opt_ PULONG BuildNumber,\n    _Out_opt_ PULONG RevisionNumber\n    )\n{\n    if (MajorVersion)\n        *MajorVersion = PHAPP_VERSION_MAJOR;\n    if (MinorVersion)\n        *MinorVersion = PHAPP_VERSION_MINOR;\n    if (BuildNumber)\n        *BuildNumber = PHAPP_VERSION_BUILD;\n    if (RevisionNumber)\n        *RevisionNumber = PHAPP_VERSION_REVISION;\n}\n\nPPH_STRING PhGetPhVersionHash(\n    VOID\n    )\n{\n    return PhConvertUtf8ToUtf16(PHAPP_VERSION_COMMIT);\n}\n\nPH_RELEASE_CHANNEL PhGetPhReleaseChannel(\n    VOID\n    )\n{\n    return PhGetIntegerSetting(SETTING_RELEASE_CHANNEL);\n}\n\nPCWSTR PhGetPhReleaseChannelString(\n    VOID\n    )\n{\n    switch (PhGetIntegerSetting(SETTING_RELEASE_CHANNEL))\n    {\n    case PhReleaseChannel:\n        return L\"Release\";\n    case PhPreviewChannel:\n        return L\"Preview\";\n    case PhCanaryChannel:\n        return L\"Canary\";\n    case PhDeveloperChannel:\n        return L\"Developer\";\n    }\n\n    return L\"Unknown\";\n}\n\nVOID PhWritePhTextHeader(\n    _Inout_ PPH_FILE_STREAM FileStream\n    )\n{\n    PPH_STRING version;\n    LARGE_INTEGER time;\n    SYSTEMTIME systemTime;\n    PPH_STRING timeString;\n\n    PhWriteStringAsUtf8FileStream2(FileStream, L\"System Informer \");\n\n    if (version = PhGetPhVersion())\n    {\n        PhWriteStringAsUtf8FileStream(FileStream, &version->sr);\n        PhDereferenceObject(version);\n    }\n\n    PhWriteStringFormatAsUtf8FileStream(FileStream, L\"\\r\\nWindows NT %lu.%lu\", PhOsVersion.MajorVersion, PhOsVersion.MinorVersion);\n\n    if (PhOsVersion.CSDVersion[0] != UNICODE_NULL)\n        PhWriteStringFormatAsUtf8FileStream(FileStream, L\" %s\", PhOsVersion.CSDVersion);\n\n#ifdef _WIN64\n    PhWriteStringAsUtf8FileStream2(FileStream, L\" (64-bit)\");\n#else\n    PhWriteStringAsUtf8FileStream2(FileStream, L\" (32-bit)\");\n#endif\n\n    PhQuerySystemTime(&time);\n    PhLargeIntegerToLocalSystemTime(&systemTime, &time);\n\n    timeString = PhFormatDateTime(&systemTime);\n    PhWriteStringFormatAsUtf8FileStream(FileStream, L\"\\r\\n%s\\r\\n\\r\\n\", timeString->Buffer);\n    PhDereferenceObject(timeString);\n}\n\nNTSTATUS PhShellProcessHacker(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR Parameters,\n    _In_ ULONG ShowWindowType,\n    _In_ ULONG Flags,\n    _In_ ULONG AppFlags,\n    _In_opt_ ULONG Timeout,\n    _Out_opt_ PHANDLE ProcessHandle\n    )\n{\n    return PhShellProcessHackerEx(\n        WindowHandle,\n        NULL,\n        Parameters,\n        ShowWindowType,\n        Flags,\n        AppFlags,\n        Timeout,\n        ProcessHandle\n        );\n}\n\nVOID PhpAppendCommandLineArgument(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PCWSTR Name,\n    _In_ PPH_STRINGREF Value\n    )\n{\n    PPH_STRING temp;\n\n    PhAppendStringBuilder2(StringBuilder, L\" -\");\n    PhAppendStringBuilder2(StringBuilder, Name);\n    PhAppendStringBuilder2(StringBuilder, L\" \\\"\");\n    temp = PhEscapeCommandLinePart(Value);\n    PhAppendStringBuilder(StringBuilder, &temp->sr);\n    PhDereferenceObject(temp);\n    PhAppendCharStringBuilder(StringBuilder, L'\\\"');\n}\n\nNTSTATUS PhShellProcessHackerEx(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ PCWSTR Parameters,\n    _In_ ULONG ShowWindowType,\n    _In_ ULONG Flags,\n    _In_ ULONG AppFlags,\n    _In_opt_ ULONG Timeout,\n    _Out_opt_ PHANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    PPH_STRING applicationFileName;\n    PH_STRING_BUILDER sb;\n    PCWSTR parameters;\n\n    if (!(applicationFileName = PhGetApplicationFileNameWin32()))\n        return FALSE;\n\n    if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS)\n    {\n        PhInitializeStringBuilder(&sb, 128);\n\n        // Propagate parameters.\n\n        if (PhStartupParameters.NoSettings)\n        {\n            PhAppendStringBuilder2(&sb, L\" -nosettings\");\n        }\n        else\n        {\n            if (!PhIsNullOrEmptyString(PhSettingsFileName))\n            {\n                PhAppendStringBuilder2(&sb, L\" -settings \\\"\");\n                PhAppendStringBuilder(&sb, &PhSettingsFileName->sr);\n                PhAppendStringBuilder2(&sb, L\"\\\"\");\n            }\n        }\n\n        if (PhStartupParameters.NoKph)\n            PhAppendStringBuilder2(&sb, L\" -nokph\");\n        if (PhStartupParameters.Debug)\n            PhAppendStringBuilder2(&sb, L\" -debug\");\n        if (PhStartupParameters.NoPlugins)\n            PhAppendStringBuilder2(&sb, L\" -noplugins\");\n        if (PhStartupParameters.NewInstance)\n            PhAppendStringBuilder2(&sb, L\" -newinstance\");\n\n        if (PhStartupParameters.SelectPid != 0)\n            PhAppendFormatStringBuilder(&sb, L\" -selectpid %lu\", PhStartupParameters.SelectPid);\n\n        if (PhStartupParameters.PriorityClass != 0)\n        {\n            CHAR value = 0;\n\n            switch (PhStartupParameters.PriorityClass)\n            {\n            case PROCESS_PRIORITY_CLASS_REALTIME:\n                value = L'r';\n                break;\n            case PROCESS_PRIORITY_CLASS_HIGH:\n                value = L'h';\n                break;\n            case PROCESS_PRIORITY_CLASS_NORMAL:\n                value = L'n';\n                break;\n            case PROCESS_PRIORITY_CLASS_IDLE:\n                value = L'l';\n                break;\n            }\n\n            if (value != 0)\n            {\n                PhAppendStringBuilder2(&sb, L\" -priority \");\n                PhAppendCharStringBuilder(&sb, value);\n            }\n        }\n\n        if (PhStartupParameters.PluginParameters)\n        {\n            ULONG i;\n\n            for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++)\n            {\n                PPH_STRING value = PhStartupParameters.PluginParameters->Items[i];\n                PhpAppendCommandLineArgument(&sb, L\"plugin\", &value->sr);\n            }\n        }\n\n        if (PhStartupParameters.SelectTab)\n            PhpAppendCommandLineArgument(&sb, L\"selecttab\", &PhStartupParameters.SelectTab->sr);\n\n        if (!(AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY))\n        {\n            if (PhStartupParameters.ShowVisible)\n                PhAppendStringBuilder2(&sb, L\" -v\");\n            if (PhStartupParameters.ShowHidden)\n                PhAppendStringBuilder2(&sb, L\" -hide\");\n        }\n\n        // Add user-specified parameters last so they can override the propagated parameters.\n        if (Parameters)\n        {\n            PhAppendCharStringBuilder(&sb, L' ');\n            PhAppendStringBuilder2(&sb, Parameters);\n        }\n\n        if (sb.String->Length != 0 && sb.String->Buffer[0] == L' ')\n            parameters = sb.String->Buffer + 1;\n        else\n            parameters = sb.String->Buffer;\n    }\n    else\n    {\n        parameters = Parameters;\n    }\n\n    status = PhShellExecuteEx(\n        WindowHandle,\n        FileName ? FileName : PhGetString(applicationFileName),\n        parameters,\n        NULL,\n        ShowWindowType,\n        Flags,\n        Timeout,\n        ProcessHandle\n        );\n\n    if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS)\n        PhDeleteStringBuilder(&sb);\n\n    PhDereferenceObject(applicationFileName);\n\n    return status;\n}\n\nBOOLEAN PhCreateProcessIgnoreIfeoDebugger(\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR CommandLine\n    )\n{\n    BOOLEAN result;\n    BOOLEAN originalValue;\n    HANDLE processHandle;\n\n    result = FALSE;\n\n    RtlAcquirePebLock();\n    originalValue = NtCurrentPeb()->ReadImageFileExecOptions;\n    NtCurrentPeb()->ReadImageFileExecOptions = FALSE;\n    RtlReleasePebLock();\n\n    // The combination of ReadImageFileExecOptions = FALSE and the DEBUG_PROCESS flag\n    // allows us to skip the Debugger IFEO value. (wj32)\n\n    if (NT_SUCCESS(PhCreateProcessWin32(\n        FileName,\n        CommandLine,\n        NULL,\n        NULL,\n        PH_CREATE_PROCESS_DEBUG | PH_CREATE_PROCESS_DEBUG_ONLY_THIS_PROCESS,\n        NULL,\n        &processHandle,\n        NULL\n        )))\n    {\n        HANDLE debugObjectHandle;\n\n        if (NT_SUCCESS(PhGetProcessDebugObject(\n            processHandle,\n            &debugObjectHandle\n            )))\n        {\n            // Disable kill-on-close.\n            if (NT_SUCCESS(PhSetDebugKillProcessOnExit(\n                debugObjectHandle,\n                FALSE\n                )))\n            {\n                // Stop debugging the process now.\n                NtRemoveProcessDebug(processHandle, debugObjectHandle);\n            }\n\n            NtClose(debugObjectHandle);\n        }\n\n        // Ignore the debug object status.\n        result = TRUE;\n\n        PhConsoleSetForeground(processHandle, TRUE);\n        NtClose(processHandle);\n    }\n\n    if (originalValue)\n    {\n        RtlAcquirePebLock();\n        NtCurrentPeb()->ReadImageFileExecOptions = originalValue;\n        RtlReleasePebLock();\n    }\n\n    return result;\n}\n\nVOID PhInitializeTreeNewColumnMenu(\n    _Inout_ PPH_TN_COLUMN_MENU_DATA Data\n    )\n{\n    PhInitializeTreeNewColumnMenuEx(Data, 0);\n}\n\nVOID PhInitializeTreeNewColumnMenuEx(\n    _Inout_ PPH_TN_COLUMN_MENU_DATA Data,\n    _In_ ULONG Flags\n    )\n{\n    PPH_EMENU_ITEM resetSortMenuItem = NULL;\n    PPH_EMENU_ITEM sizeColumnToFitMenuItem;\n    PPH_EMENU_ITEM sizeAllColumnsToFitMenuItem;\n    PPH_EMENU_ITEM hideColumnMenuItem = NULL;\n    PPH_EMENU_ITEM chooseColumnsMenuItem = NULL;\n    ULONG minimumNumberOfColumns;\n\n    Data->Menu = PhCreateEMenu();\n    Data->Selection = NULL;\n    Data->ProcessedId = 0;\n\n    sizeColumnToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID, L\"Size column to fit\", NULL, NULL);\n    sizeAllColumnsToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID, L\"Size all columns to fit\", NULL, NULL);\n\n    if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY))\n    {\n        hideColumnMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_HIDE_COLUMN_ID, L\"Hide column\", NULL, NULL);\n        chooseColumnsMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID, L\"Choose columns...\", NULL, NULL);\n    }\n\n    if (Flags & PH_TN_COLUMN_MENU_SHOW_RESET_SORT)\n    {\n        ULONG sortColumn = 0;\n        PH_SORT_ORDER sortOrder = NoSortOrder;\n\n        TreeNew_GetSort(Data->TreeNewHandle, &sortColumn, &sortOrder);\n\n        if (sortOrder != Data->DefaultSortOrder || (Data->DefaultSortOrder != NoSortOrder && sortColumn != Data->DefaultSortColumn))\n            resetSortMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_RESET_SORT_ID, L\"Reset sort\", NULL, NULL);\n    }\n\n    PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, ULONG_MAX);\n    PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, ULONG_MAX);\n\n    if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY))\n    {\n        if (hideColumnMenuItem) PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, ULONG_MAX);\n        if (resetSortMenuItem) PhInsertEMenuItem(Data->Menu, resetSortMenuItem, ULONG_MAX);\n        PhInsertEMenuItem(Data->Menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        if (chooseColumnsMenuItem) PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, ULONG_MAX);\n\n        if (TreeNew_GetFixedColumn(Data->TreeNewHandle))\n            minimumNumberOfColumns = 2; // don't allow user to remove all normal columns (the fixed column can never be removed)\n        else\n            minimumNumberOfColumns = 1;\n\n        if (!Data->MouseEvent || !Data->MouseEvent->Column ||\n            Data->MouseEvent->Column->Fixed || // don't allow the fixed column to be hidden\n            TreeNew_GetVisibleColumnCount(Data->TreeNewHandle) < minimumNumberOfColumns + 1\n            )\n        {\n            if (hideColumnMenuItem)\n                PhSetDisabledEMenuItem(hideColumnMenuItem);\n        }\n    }\n    else\n    {\n        if (resetSortMenuItem)\n            PhInsertEMenuItem(Data->Menu, resetSortMenuItem, ULONG_MAX);\n    }\n\n    if (!Data->MouseEvent || !Data->MouseEvent->Column)\n    {\n        PhSetDisabledEMenuItem(sizeColumnToFitMenuItem);\n    }\n}\n\nVOID PhpEnsureValidSortColumnTreeNew(\n    _Inout_ HWND TreeNewHandle,\n    _In_ ULONG DefaultSortColumn,\n    _In_ PH_SORT_ORDER DefaultSortOrder\n    )\n{\n    ULONG sortColumn = 0;\n    PH_SORT_ORDER sortOrder = NoSortOrder;\n\n    // Make sure the column we're sorting by is actually visible, and if not, don't sort anymore.\n\n    TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder);\n\n    if (sortOrder != NoSortOrder)\n    {\n        PH_TREENEW_COLUMN column;\n\n        TreeNew_GetColumn(TreeNewHandle, sortColumn, &column);\n\n        if (!column.Visible)\n        {\n            if (DefaultSortOrder != NoSortOrder)\n            {\n                // Make sure the default sort column is visible.\n                TreeNew_GetColumn(TreeNewHandle, DefaultSortColumn, &column);\n\n                if (!column.Visible)\n                {\n                    ULONG maxId;\n                    ULONG id;\n                    BOOLEAN found;\n\n                    // Use the first visible column.\n                    maxId = TreeNew_GetMaxId(TreeNewHandle);\n                    id = 0;\n                    found = FALSE;\n\n                    while (id <= maxId)\n                    {\n                        if (TreeNew_GetColumn(TreeNewHandle, id, &column))\n                        {\n                            if (column.Visible)\n                            {\n                                DefaultSortColumn = id;\n                                found = TRUE;\n                                break;\n                            }\n                        }\n\n                        id++;\n                    }\n\n                    if (!found)\n                    {\n                        DefaultSortColumn = 0;\n                        DefaultSortOrder = NoSortOrder;\n                    }\n                }\n            }\n\n            TreeNew_SetSort(TreeNewHandle, DefaultSortColumn, DefaultSortOrder);\n        }\n    }\n}\n\nBOOLEAN PhHandleTreeNewColumnMenu(\n    _Inout_ PPH_TN_COLUMN_MENU_DATA Data\n    )\n{\n    if (!Data->Selection)\n        return FALSE;\n\n    switch (Data->Selection->Id)\n    {\n    case PH_TN_COLUMN_MENU_RESET_SORT_ID:\n        {\n            TreeNew_SetSort(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder);\n        }\n        break;\n    case PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID:\n        {\n            if (Data->MouseEvent && Data->MouseEvent->Column)\n            {\n                TreeNew_AutoSizeColumn(Data->TreeNewHandle, Data->MouseEvent->Column->Id, 0);\n            }\n        }\n        break;\n    case PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID:\n        {\n            ULONG maxId;\n            ULONG id;\n\n            maxId = TreeNew_GetMaxId(Data->TreeNewHandle);\n            id = 0;\n\n            while (id <= maxId)\n            {\n                TreeNew_AutoSizeColumn(Data->TreeNewHandle, id, 0);\n                id++;\n            }\n        }\n        break;\n    case PH_TN_COLUMN_MENU_HIDE_COLUMN_ID:\n        {\n            PH_TREENEW_COLUMN column;\n\n            if (Data->MouseEvent && Data->MouseEvent->Column && !Data->MouseEvent->Column->Fixed)\n            {\n                column.Id = Data->MouseEvent->Column->Id;\n                column.Visible = FALSE;\n                TreeNew_SetColumn(Data->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column);\n                PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder);\n                InvalidateRect(Data->TreeNewHandle, NULL, FALSE);\n            }\n        }\n        break;\n    case PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID:\n        {\n            PhShowChooseColumnsDialog(Data->TreeNewHandle, Data->TreeNewHandle, PH_CONTROL_TYPE_TREE_NEW);\n            PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder);\n        }\n        break;\n    default:\n        return FALSE;\n    }\n\n    Data->ProcessedId = Data->Selection->Id;\n\n    return TRUE;\n}\n\nVOID PhDeleteTreeNewColumnMenu(\n    _In_ PPH_TN_COLUMN_MENU_DATA Data\n    )\n{\n    if (Data->Menu)\n    {\n        PhDestroyEMenu(Data->Menu);\n        Data->Menu = NULL;\n    }\n}\n\nVOID PhInitializeTreeNewFilterSupport(\n    _Out_ PPH_TN_FILTER_SUPPORT Support,\n    _In_ HWND TreeNewHandle,\n    _In_ PPH_LIST NodeList\n    )\n{\n    Support->FilterList = NULL;\n    Support->TreeNewHandle = TreeNewHandle;\n    Support->NodeList = NodeList;\n}\n\nVOID PhDeleteTreeNewFilterSupport(\n    _In_ PPH_TN_FILTER_SUPPORT Support\n    )\n{\n    if (!Support->FilterList)\n        return;\n\n    PhDereferenceObject(Support->FilterList);\n    Support->FilterList = NULL;\n}\n\nPPH_TN_FILTER_ENTRY PhAddTreeNewFilter(\n    _In_ PPH_TN_FILTER_SUPPORT Support,\n    _In_ PPH_TN_FILTER_FUNCTION Filter,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_TN_FILTER_ENTRY entry;\n\n    entry = PhAllocate(sizeof(PH_TN_FILTER_ENTRY));\n    entry->Filter = Filter;\n    entry->Context = Context;\n\n    if (!Support->FilterList)\n        Support->FilterList = PhCreateList(2);\n\n    PhAddItemList(Support->FilterList, entry);\n\n    return entry;\n}\n\nVOID PhRemoveTreeNewFilter(\n    _In_ PPH_TN_FILTER_SUPPORT Support,\n    _In_ PPH_TN_FILTER_ENTRY Entry\n    )\n{\n    ULONG index;\n\n    if (!Support->FilterList)\n        return;\n\n    index = PhFindItemList(Support->FilterList, Entry);\n\n    if (index != ULONG_MAX)\n    {\n        PhRemoveItemList(Support->FilterList, index);\n        PhFree(Entry);\n    }\n}\n\nBOOLEAN PhApplyTreeNewFiltersToNode(\n    _In_ PPH_TN_FILTER_SUPPORT Support,\n    _In_ PPH_TREENEW_NODE Node\n    )\n{\n    BOOLEAN show;\n    ULONG i;\n\n    show = TRUE;\n\n    if (Support->FilterList)\n    {\n        for (i = 0; i < Support->FilterList->Count; i++)\n        {\n            PPH_TN_FILTER_ENTRY entry;\n\n            entry = Support->FilterList->Items[i];\n\n            if (!entry->Filter(Node, entry->Context))\n            {\n                show = FALSE;\n                break;\n            }\n        }\n    }\n\n    return show;\n}\n\nVOID PhApplyTreeNewFilters(\n    _In_ PPH_TN_FILTER_SUPPORT Support\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Support->NodeList->Count; i++)\n    {\n        PPH_TREENEW_NODE node;\n\n        node = Support->NodeList->Items[i];\n        node->Visible = PhApplyTreeNewFiltersToNode(Support, node);\n\n        if (!node->Visible && node->Selected)\n        {\n            node->Selected = FALSE;\n        }\n    }\n\n    if (Support->NodeList->Count)\n    {\n        TreeNew_NodesStructured(Support->TreeNewHandle);\n    }\n}\n\n_Function_class_(PH_EMENU_ITEM_DELETE_FUNCTION)\nVOID NTAPI PhpCopyCellEMenuItemDeleteFunction(\n    _In_ PPH_EMENU_ITEM Item\n    )\n{\n    PPH_COPY_CELL_CONTEXT context;\n\n    context = Item->Context;\n    PhDereferenceObject(context->MenuItemText);\n    PhFree(context);\n}\n\nBOOLEAN PhInsertCopyCellEMenuItem(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG InsertAfterId,\n    _In_ HWND TreeNewHandle,\n    _In_ PPH_TREENEW_COLUMN Column\n    )\n{\n    PPH_EMENU_ITEM parentItem = NULL;\n    ULONG indexInParent = 0;\n    PPH_COPY_CELL_CONTEXT context;\n    PH_STRINGREF columnText;\n    PPH_STRING escapedText;\n    PPH_STRING menuItemText;\n    PPH_EMENU_ITEM copyCellItem;\n    PH_FORMAT format[3];\n\n    if (!Column)\n        return FALSE;\n\n    if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent))\n        return FALSE;\n\n    indexInParent++;\n\n    PhInitializeStringRefLongHint(&columnText, Column->Text);\n    escapedText = PhEscapeStringForMenuPrefix(&columnText);\n    PhInitFormatS(&format[0], L\"Copy \\\"\"); // Copy \\\"%s\\\"\n    PhInitFormatSR(&format[1], escapedText->sr);\n    PhInitFormatS(&format[2], L\"\\\"\");\n    menuItemText = PhFormat(format, RTL_NUMBER_OF(format), 0);\n    PhDereferenceObject(escapedText);\n\n    context = PhAllocate(sizeof(PH_COPY_CELL_CONTEXT));\n    context->TreeNewHandle = TreeNewHandle;\n    context->Id = Column->Id;\n    context->MenuItemText = menuItemText;\n\n    copyCellItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context);\n    copyCellItem->DeleteFunction = PhpCopyCellEMenuItemDeleteFunction;\n\n    if (Column->CustomDraw)\n        copyCellItem->Flags |= PH_EMENU_DISABLED;\n\n    PhInsertEMenuItem(parentItem, copyCellItem, indexInParent);\n\n    return TRUE;\n}\n\nBOOLEAN PhHandleCopyCellEMenuItem(\n    _In_ PPH_EMENU_ITEM SelectedItem\n    )\n{\n    PPH_COPY_CELL_CONTEXT context;\n    PH_STRING_BUILDER stringBuilder;\n    ULONG count;\n    ULONG selectedCount;\n    ULONG i;\n    PPH_TREENEW_NODE node;\n    PH_TREENEW_GET_CELL_TEXT getCellText;\n\n    if (!SelectedItem)\n        return FALSE;\n    if (SelectedItem->Id != ID_COPY_CELL)\n        return FALSE;\n\n    context = SelectedItem->Context;\n\n    PhInitializeStringBuilder(&stringBuilder, 0x100);\n    count = TreeNew_GetFlatNodeCount(context->TreeNewHandle);\n    selectedCount = 0;\n\n    for (i = 0; i < count; i++)\n    {\n        node = TreeNew_GetFlatNode(context->TreeNewHandle, i);\n\n        if (node && node->Selected)\n        {\n            selectedCount++;\n\n            getCellText.Flags = 0;\n            getCellText.Node = node;\n            getCellText.Id = context->Id;\n            PhInitializeEmptyStringRef(&getCellText.Text);\n            TreeNew_GetCellText(context->TreeNewHandle, &getCellText);\n\n            PhAppendStringBuilder(&stringBuilder, &getCellText.Text);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n        }\n    }\n\n    if (stringBuilder.String->Length != 0 && selectedCount == 1)\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhSetClipboardString(context->TreeNewHandle, &stringBuilder.String->sr);\n    PhDeleteStringBuilder(&stringBuilder);\n\n    return TRUE;\n}\n\n_Function_class_(PH_EMENU_ITEM_DELETE_FUNCTION)\nVOID NTAPI PhpCopyListViewEMenuItemDeleteFunction(\n    _In_ PPH_EMENU_ITEM Item\n    )\n{\n    PPH_COPY_ITEM_CONTEXT context;\n\n    context = Item->Context;\n    PhDereferenceObject(context->MenuItemText);\n    PhFree(context);\n}\n\nBOOLEAN PhInsertCopyListViewEMenuItem(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG InsertAfterId,\n    _In_ HWND ListViewHandle\n    )\n{\n    PPH_EMENU_ITEM parentItem = NULL;\n    ULONG indexInParent = 0;\n    PPH_COPY_ITEM_CONTEXT context;\n    PH_STRINGREF columnText;\n    PPH_STRING escapedText;\n    PPH_STRING menuItemText;\n    PPH_EMENU_ITEM copyMenuItem;\n    POINT location;\n    LVHITTESTINFO lvHitInfo;\n    HDITEM headerItem;\n    HWND headerHandle;\n    PH_FORMAT format[3];\n    WCHAR headerText[MAX_PATH] = L\"\";\n\n    if (!PhGetClientPos(ListViewHandle, &location))\n        return FALSE;\n\n    memset(&lvHitInfo, 0, sizeof(LVHITTESTINFO));\n    lvHitInfo.pt = location;\n\n    if (ListView_SubItemHitTest(ListViewHandle, &lvHitInfo) == INT_ERROR)\n        return FALSE;\n\n    memset(&headerItem, 0, sizeof(HDITEM));\n    headerItem.mask = HDI_TEXT;\n    headerItem.cchTextMax = RTL_NUMBER_OF(headerText);\n    headerItem.pszText = headerText;\n    headerHandle = ListView_GetHeader(ListViewHandle);\n\n    if (!Header_GetItem(headerHandle, lvHitInfo.iSubItem, &headerItem))\n        return FALSE;\n\n    PhInitializeStringRefLongHint(&columnText, headerText);\n\n    if (PhIsNullOrEmptyStringRef(&columnText))\n        return FALSE;\n\n    if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent))\n        return FALSE;\n\n    indexInParent++;\n\n    escapedText = PhEscapeStringForMenuPrefix(&columnText);\n    PhInitFormatS(&format[0], L\"Copy \\\"\"); // Copy \\\"%s\\\"\n    PhInitFormatSR(&format[1], escapedText->sr);\n    PhInitFormatS(&format[2], L\"\\\"\");\n    menuItemText = PhFormat(format, RTL_NUMBER_OF(format), 0);\n    PhDereferenceObject(escapedText);\n\n    context = PhAllocate(sizeof(PH_COPY_ITEM_CONTEXT));\n    context->ListViewHandle = ListViewHandle;\n    context->Id = lvHitInfo.iItem;\n    context->SubId = lvHitInfo.iSubItem;\n    context->MenuItemText = menuItemText;\n\n    copyMenuItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context);\n    copyMenuItem->DeleteFunction = PhpCopyListViewEMenuItemDeleteFunction;\n\n    PhInsertEMenuItem(parentItem, copyMenuItem, indexInParent);\n\n    return TRUE;\n}\n\nBOOLEAN PhHandleCopyListViewEMenuItem(\n    _In_ PPH_EMENU_ITEM SelectedItem\n    )\n{\n    PPH_COPY_ITEM_CONTEXT context;\n    PH_STRING_BUILDER stringBuilder;\n    ULONG state = 0;\n    ULONG count = 0;\n    ULONG selectedCount;\n    ULONG i;\n    PPH_STRING getItemText;\n\n    if (!SelectedItem)\n        return FALSE;\n    if (SelectedItem->Id != ID_COPY_CELL)\n        return FALSE;\n\n    context = SelectedItem->Context;\n\n    PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n    count = ListView_GetItemCount(context->ListViewHandle);\n    selectedCount = 0;\n\n    for (i = 0; i < count; i++)\n    {\n        state = ListView_GetItemState(context->ListViewHandle, i, LVIS_SELECTED);\n\n        if (!FlagOn(state, LVIS_SELECTED))\n            continue;\n\n        if (getItemText = PhaGetListViewItemText(context->ListViewHandle, i, context->SubId))\n            PhAppendStringBuilder(&stringBuilder, &getItemText->sr);\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n        selectedCount++;\n    }\n\n    if (stringBuilder.String->Length != 0 && selectedCount == 1)\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhSetClipboardString(context->ListViewHandle, &stringBuilder.String->sr);\n    PhDeleteStringBuilder(&stringBuilder);\n\n    return TRUE;\n}\n\nBOOLEAN PhpSelectFavoriteInRegedit(\n    _In_ HWND RegeditWindow,\n    _In_ PPH_STRINGREF FavoriteName,\n    _In_ BOOLEAN UsePhSvc\n    )\n{\n    HMENU menu;\n    HMENU favoritesMenu;\n    ULONG count;\n    ULONG i;\n    ULONG id = ULONG_MAX;\n\n    if (!(menu = GetMenu(RegeditWindow)))\n        return FALSE;\n\n    // Cause the Registry Editor to refresh the Favorites menu.\n    if (UsePhSvc)\n        PhSvcCallSendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu);\n    else\n        PhSendMessageTimeout(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu, 5000, NULL);\n\n    if (!(favoritesMenu = GetSubMenu(menu, 3)))\n        return FALSE;\n\n    // Find our entry.\n\n    count = GetMenuItemCount(favoritesMenu);\n\n    if (count == ULONG_MAX)\n        return FALSE;\n    if (count > 1000)\n        count = 1000;\n\n    for (i = 0; i < count; i++)\n    {\n        MENUITEMINFO info;\n        WCHAR buffer[MAX_PATH];\n\n        memset(&info, 0, sizeof(MENUITEMINFO));\n        info.cbSize = sizeof(MENUITEMINFO);\n        info.fMask = MIIM_ID | MIIM_STRING;\n        info.dwTypeData = buffer;\n        info.cch = RTL_NUMBER_OF(buffer);\n\n        if (!GetMenuItemInfo(favoritesMenu, i, TRUE, &info))\n            continue;\n\n        if (info.cch == FavoriteName->Length / sizeof(WCHAR))\n        {\n            PH_STRINGREF text;\n\n            text.Buffer = buffer;\n            text.Length = info.cch * sizeof(WCHAR);\n\n            if (PhEqualStringRef(&text, FavoriteName, TRUE))\n            {\n                id = info.wID;\n                break;\n            }\n        }\n    }\n\n    if (id == ULONG_MAX)\n        return FALSE;\n\n    // Activate our entry.\n    if (UsePhSvc)\n        PhSvcCallSendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0);\n    else\n        PhSendMessageTimeout(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0, 5000, NULL);\n\n    // \"Close\" the Favorites menu and restore normal status bar text.\n    if (UsePhSvc)\n        PhSvcCallPostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0);\n    else\n        PostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0);\n\n    // Bring regedit to the top.\n    if (IsMinimized(RegeditWindow))\n    {\n        ShowWindow(RegeditWindow, SW_RESTORE);\n    }\n\n    SetForegroundWindow(RegeditWindow);\n\n    return TRUE;\n}\n\n/**\n * Opens a key in the Registry Editor.\n *\n * \\param WindowHandle A handle to the parent window.\n * \\param KeyName The key name to open.\n */\nVOID PhShellOpenKey(\n    _In_ HWND WindowHandle,\n    _In_ PPH_STRING KeyName\n    )\n{\n    static CONST PH_STRINGREF regeditKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Applets\\\\Regedit\");\n    NTSTATUS status;\n    HANDLE regeditKeyHandle;\n    PPH_STRING lastKey;\n    PPH_STRING regeditFileName;\n    PH_STRINGREF systemRootString;\n\n    status = PhCreateKey(\n        &regeditKeyHandle,\n        KEY_WRITE,\n        PH_KEY_CURRENT_USER,\n        &regeditKeyName,\n        0,\n        0,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to execute the program.\", status, 0);\n        return;\n    }\n\n    lastKey = PhExpandKeyName(KeyName, FALSE);\n    PhSetValueKeyZ(regeditKeyHandle, L\"LastKey\", REG_SZ, lastKey->Buffer, (ULONG)lastKey->Length + sizeof(UNICODE_NULL));\n    NtClose(regeditKeyHandle);\n    PhDereferenceObject(lastKey);\n\n    // Start regedit. If we aren't elevated, request that regedit be elevated. This is so we can get\n    // the consent dialog in the center of the specified window. (wj32)\n\n    PhGetSystemRoot(&systemRootString);\n    regeditFileName = PhConcatStringRefZ(&systemRootString, L\"\\\\regedit.exe\");\n\n    if (PhGetOwnTokenAttributes().Elevated)\n    {\n        status = PhShellExecuteEx(\n            WindowHandle,\n            regeditFileName->Buffer,\n            NULL,\n            NULL,\n            SW_SHOW,\n            0,\n            0,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            PhShowStatus(WindowHandle, L\"Unable to execute the program.\", status, 0);\n        }\n    }\n    else\n    {\n        status = PhShellExecuteEx(\n            WindowHandle,\n            regeditFileName->Buffer,\n            NULL,\n            NULL,\n            SW_SHOW,\n            PH_SHELL_EXECUTE_ADMIN,\n            0,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            PhShowStatus(WindowHandle, L\"Unable to execute the program.\", status, 0);\n        }\n    }\n\n    PhDereferenceObject(regeditFileName);\n}\n\nNTSTATUS PhRegeditOpenUserFavoritesKey(\n    _In_ HWND RegeditWindow,\n    _Out_ PHANDLE KeyHandle\n    )\n{\n    static CONST PH_STRINGREF favoritesKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Applets\\\\Regedit\\\\Favorites\");\n    NTSTATUS status;\n    CLIENT_ID clientId;\n    HANDLE processHandle;\n    HANDLE tokenHandle;\n    HANDLE keyUserHandle;\n    HANDLE keyFavoritesHandle;\n    PH_TOKEN_USER tokenUser;\n    PPH_STRING tokenUserSid;\n\n    status = PhGetWindowClientId(RegeditWindow, &clientId);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhOpenProcessClientId(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        &clientId\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhOpenProcessToken(\n        processHandle,\n        TOKEN_QUERY,\n        &tokenHandle\n        );\n\n    NtClose(processHandle);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetTokenUser(\n        tokenHandle,\n        &tokenUser\n        );\n\n    NtClose(tokenHandle);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (!(tokenUserSid = PhSidToStringSid(tokenUser.User.Sid)))\n    {\n        status = STATUS_NO_MEMORY;\n        goto CleanupExit;\n    }\n\n    status = PhOpenKey(\n        &keyUserHandle,\n        KEY_READ,\n        PH_KEY_USERS,\n        &tokenUserSid->sr,\n        0\n        );\n\n    PhDereferenceObject(tokenUserSid);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreateKey(\n        &keyFavoritesHandle,\n        KEY_WRITE,\n        keyUserHandle,\n        &favoritesKeyName,\n        0,\n        0,\n        NULL\n        );\n\n    NtClose(keyUserHandle);\n\n    if (NT_SUCCESS(status))\n    {\n        *KeyHandle = keyFavoritesHandle;\n        return STATUS_SUCCESS;\n    }\n\nCleanupExit:\n    status = PhCreateKey(\n        &keyFavoritesHandle,\n        KEY_WRITE,\n        PH_KEY_CURRENT_USER,\n        &favoritesKeyName,\n        0,\n        0,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *KeyHandle = keyFavoritesHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return status;\n}\n\n/**\n * Opens a key in the Registry Editor. If the Registry Editor is already open,\n * the specified key is selected in the Registry Editor.\n *\n * \\param WindowHandle A handle to the parent window.\n * \\param KeyName The key name to open.\n */\nBOOLEAN PhShellOpenKey2(\n    _In_ HWND WindowHandle,\n    _In_ PPH_STRING KeyName\n    )\n{\n    BOOLEAN result = FALSE;\n    HWND regeditWindow;\n    HANDLE favoritesKeyHandle;\n    WCHAR favoriteName[33];\n    PH_STRINGREF valueName;\n    PPH_STRING expandedKeyName;\n\n    regeditWindow = FindWindow(L\"RegEdit_RegEdit\", NULL);\n\n    if (!regeditWindow)\n    {\n        PhShellOpenKey(WindowHandle, KeyName);\n        return TRUE;\n    }\n\n    if (!PhGetOwnTokenAttributes().Elevated)\n    {\n        if (!PhUiConnectToPhSvc(WindowHandle, FALSE))\n            return FALSE;\n    }\n\n    // Create our entry in Favorites.\n\n    if (!NT_SUCCESS(PhRegeditOpenUserFavoritesKey(regeditWindow, &favoritesKeyHandle)))\n        goto CleanupExit;\n\n    memcpy(favoriteName, L\"A_SystemInformer\", 16 * sizeof(WCHAR));\n    PhGenerateRandomAlphaString(&favoriteName[16], ARRAYSIZE(favoriteName) - 16);\n    valueName.Buffer = favoriteName;\n    valueName.Length = sizeof(favoriteName) - sizeof(UNICODE_NULL);\n\n    expandedKeyName = PhExpandKeyName(KeyName, FALSE);\n    PhSetValueKey(favoritesKeyHandle, &valueName, REG_SZ, expandedKeyName->Buffer, (ULONG)expandedKeyName->Length + sizeof(UNICODE_NULL));\n    PhDereferenceObject(expandedKeyName);\n\n    // Select our entry in regedit.\n    result = PhpSelectFavoriteInRegedit(regeditWindow, &valueName, !PhGetOwnTokenAttributes().Elevated);\n\n    PhDeleteValueKey(favoritesKeyHandle, &valueName);\n    NtClose(favoritesKeyHandle);\n\nCleanupExit:\n    if (!PhGetOwnTokenAttributes().Elevated)\n        PhUiDisconnectFromPhSvc();\n\n    return result;\n}\n\nPPH_STRING PhPcre2GetErrorMessage(\n    _In_ LONG ErrorCode\n    )\n{\n    PPH_STRING buffer;\n    SIZE_T bufferLength;\n    INT_PTR returnLength;\n\n    bufferLength = 128 * sizeof(WCHAR);\n    buffer = PhCreateStringEx(NULL, bufferLength);\n\n    while (TRUE)\n    {\n        if ((returnLength = pcre2_get_error_message(ErrorCode, buffer->Buffer, bufferLength / sizeof(WCHAR) + 1)) >= 0)\n            break;\n\n        PhDereferenceObject(buffer);\n        bufferLength *= 2;\n\n        if (bufferLength > 0x1000 * sizeof(WCHAR))\n            break;\n\n        buffer = PhCreateStringEx(NULL, bufferLength);\n    }\n\n    if (returnLength < 0)\n        return NULL;\n\n    buffer->Length = returnLength * sizeof(WCHAR);\n    return buffer;\n}\n\nHBITMAP PhGetShieldBitmap(\n    _In_ LONG WindowDpi,\n    _In_opt_ LONG Width,\n    _In_opt_ LONG Height\n    )\n{\n    HICON shieldIcon;\n    HBITMAP shieldBitmap = NULL;\n\n    shieldIcon = PhLoadIcon(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDI_UACSHIELD),\n        0,\n        Width,\n        Height,\n        WindowDpi\n        );\n\n    if (!shieldIcon)\n    {\n        shieldIcon = PhLoadIcon(\n            NULL,\n            IDI_SHIELD,\n            0,\n            Width,\n            Height,\n            WindowDpi\n            );\n    }\n\n    if (shieldIcon)\n    {\n        shieldBitmap = PhIconToBitmap(\n            shieldIcon,\n            Width,\n            Height\n            );\n        DestroyIcon(shieldIcon);\n    }\n\n    return shieldBitmap;\n}\n\nHICON PhGetApplicationIcon(\n    _In_ BOOLEAN SmallIcon\n    )\n{\n    static HICON smallIcon = NULL;\n    static HICON largeIcon = NULL;\n    static LONG systemDpi = 0;\n\n    if (systemDpi != PhSystemDpi)\n    {\n        if (smallIcon)\n        {\n            DestroyIcon(smallIcon);\n            smallIcon = NULL;\n        }\n        if (largeIcon)\n        {\n            DestroyIcon(largeIcon);\n            largeIcon = NULL;\n        }\n\n        systemDpi = PhSystemDpi;\n    }\n\n    if (!smallIcon || !largeIcon)\n    {\n        if (!smallIcon)\n            smallIcon = PhLoadIcon(NtCurrentImageBase(), MAKEINTRESOURCE(IDI_PROCESSHACKER), PH_LOAD_ICON_SIZE_SMALL, 0, 0, systemDpi);\n        if (!largeIcon)\n            largeIcon = PhLoadIcon(NtCurrentImageBase(), MAKEINTRESOURCE(IDI_PROCESSHACKER), PH_LOAD_ICON_SIZE_LARGE, 0, 0, systemDpi);\n    }\n\n    return SmallIcon ? smallIcon : largeIcon;\n}\n\nHICON PhGetApplicationIconEx(\n    _In_ BOOLEAN SmallIcon,\n    _In_opt_ LONG WindowDpi\n    )\n{\n    if (SmallIcon)\n        return PhLoadIcon(NtCurrentImageBase(), MAKEINTRESOURCE(IDI_PROCESSHACKER), PH_LOAD_ICON_SIZE_SMALL, 0, 0, WindowDpi);\n    return PhLoadIcon(NtCurrentImageBase(), MAKEINTRESOURCE(IDI_PROCESSHACKER), PH_LOAD_ICON_SIZE_LARGE, 0, 0, WindowDpi);\n}\n\nVOID PhSetWindowIcon(\n    _In_ HWND WindowHandle,\n    _In_opt_ HICON SmallIcon,\n    _In_opt_ HICON LargeIcon,\n    _In_ BOOLEAN CleanupIcon\n    )\n{\n    if (SmallIcon)\n    {\n        HICON iconHandle = (HICON)SendMessage(WindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)SmallIcon);\n\n        if (iconHandle && CleanupIcon)\n        {\n            DestroyIcon(iconHandle);\n        }\n    }\n\n    if (LargeIcon)\n    {\n        HICON iconHandle = (HICON)SendMessage(WindowHandle, WM_SETICON, ICON_BIG, (LPARAM)LargeIcon);\n\n        if (iconHandle && CleanupIcon)\n        {\n            DestroyIcon(iconHandle);\n        }\n    }\n}\n\nVOID PhDestroyWindowIcon(\n    _In_ HWND WindowHandle\n    )\n{\n    HICON iconHandle;\n\n    if (iconHandle = (HICON)SendMessage(WindowHandle, WM_SETICON, ICON_SMALL, 0))\n    {\n        DestroyIcon(iconHandle);\n    }\n\n    if (iconHandle = (HICON)SendMessage(WindowHandle, WM_SETICON, ICON_BIG, 0))\n    {\n        DestroyIcon(iconHandle);\n    }\n}\n\nVOID PhSetApplicationWindowIcon(\n    _In_ HWND WindowHandle\n    )\n{\n    PhSetWindowIcon(\n        WindowHandle,\n        PhGetApplicationIcon(TRUE),\n        PhGetApplicationIcon(FALSE),\n        TRUE\n        );\n}\n\nVOID PhSetApplicationWindowIconEx(\n    _In_ HWND WindowHandle,\n    _In_opt_ LONG WindowDpi\n    )\n{\n    PhSetWindowIcon(\n        WindowHandle,\n        PhGetApplicationIconEx(TRUE, WindowDpi),\n        PhGetApplicationIconEx(FALSE, WindowDpi),\n        TRUE\n        );\n}\n\nVOID PhSetStaticWindowIcon(\n    _In_ HWND WindowHandle,\n    _In_opt_ LONG WindowDpi\n    )\n{\n    HICON largeIcon;\n    HICON destroyIcon;\n\n    if (largeIcon = PhGetApplicationIconEx(FALSE, WindowDpi))\n    {\n        if (destroyIcon = Static_SetIcon(WindowHandle, largeIcon))\n        {\n            DestroyIcon(destroyIcon);\n        }\n    }\n}\n\nVOID PhDeleteStaticWindowIcon(\n    _In_ HWND WindowHandle\n    )\n{\n    HICON destroyIcon;\n\n    if (destroyIcon = Static_GetIcon(WindowHandle, 0))\n    {\n        DestroyIcon(destroyIcon);\n    }\n}\n\nBOOLEAN PhWordMatchStringRef(\n    _In_ PPH_STRINGREF SearchText,\n    _In_ PPH_STRINGREF Text\n    )\n{\n    PH_STRINGREF part;\n    PH_STRINGREF remainingPart;\n\n    remainingPart = *SearchText;\n\n    while (remainingPart.Length)\n    {\n        PhSplitStringRefAtChar(&remainingPart, L'|', &part, &remainingPart);\n\n        if (part.Length)\n        {\n            if (PhFindStringInStringRef(Text, &part, TRUE) != SIZE_MAX)\n                return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n//BOOLEAN PhIsSystemRebootRequired(\n//    VOID\n//    )\n//{\n//    static PH_STRINGREF keyRootPath = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\WindowsUpdate\");\n//    static PH_STRINGREF keyAuPath = PH_STRINGREF_INIT(L\"Auto Update\\\\RebootRequired\");\n//    static PH_STRINGREF keyOrcPath = PH_STRINGREF_INIT(L\"Orchestrator\\\\RebootRequired\");\n//    BOOLEAN keyRebootRequired = FALSE;\n//    HANDLE keyRootHandle;\n//    HANDLE keyHandle;\n//\n//    if (NT_SUCCESS(PhOpenKey(\n//        &keyRootHandle,\n//        KEY_READ,\n//        PH_KEY_LOCAL_MACHINE,\n//        &keyRootPath,\n//        0\n//        )))\n//    {\n//        if (NT_SUCCESS(PhOpenKey(\n//            &keyHandle,\n//            KEY_READ,\n//            keyRootHandle,\n//            &keyAuPath,\n//            0\n//            )))\n//        {\n//            keyRebootRequired = TRUE;\n//            NtClose(keyHandle);\n//        }\n//\n//        if (NT_SUCCESS(PhOpenKey(\n//            &keyHandle,\n//            KEY_READ,\n//            keyRootHandle,\n//            &keyOrcPath,\n//            0\n//            )))\n//        {\n//            keyRebootRequired = TRUE;\n//            NtClose(keyHandle);\n//        }\n//\n//        NtClose(keyRootHandle);\n//    }\n//\n//    //#include <wuapi.h>\n//    //ISystemInformation* systemInformation = NULL;\n//    //\n//    //if (SUCCEEDED(PhGetClassObject(\n//    //    L\"wuapi.dll\",\n//    //    &CLSID_SystemInformation,\n//    //    &IID_ISystemInformation,\n//    //    &systemInformation\n//    //    )))\n//    //{\n//    //    VARIANT_BOOL rebootRequiredVariant = VARIANT_FALSE;\n//    //\n//    //    ISystemInformation_get_RebootRequired(systemInformation, &rebootRequiredVariant);\n//    //    ISystemInformation_Release(systemInformation);\n//    //\n//    //    keyRebootRequired = rebootRequiredVariant == VARIANT_TRUE;\n//    //}\n//\n//    return keyRebootRequired;\n//}\n"
  },
  {
    "path": "SystemInformer/chcol.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <settings.h>\n\ntypedef struct _COLUMNS_DIALOG_CONTEXT\n{\n    HWND ControlHandle;\n    HFONT ControlFont;\n    ULONG Type;\n    PPH_LIST Columns;\n\n    HBRUSH BrushNormal;\n    HBRUSH BrushPushed;\n    HBRUSH BrushHot;\n    COLORREF TextColor;\n\n    HWND InactiveWindowHandle;\n    HWND ActiveWindowHandle;\n    HWND SearchInactiveHandle;\n    HWND SearchActiveHandle;\n    HWND HideWindowHandle;\n    HWND ShowWindowHandle;\n    HWND MoveUpHandle;\n    HWND MoveDownHandle;\n    PPH_LIST InactiveListArray;\n    PPH_LIST ActiveListArray;\n} COLUMNS_DIALOG_CONTEXT, *PCOLUMNS_DIALOG_CONTEXT;\n\nINT_PTR CALLBACK PhpColumnsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowChooseColumnsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND ControlHandle,\n    _In_ ULONG Type\n    )\n{\n    COLUMNS_DIALOG_CONTEXT context;\n\n    memset(&context, 0, sizeof(COLUMNS_DIALOG_CONTEXT));\n    context.ControlHandle = ControlHandle;\n    context.Type = Type;\n\n    if (Type == PH_CONTROL_TYPE_TREE_NEW)\n        context.Columns = PhCreateList(TreeNew_GetColumnCount(ControlHandle));\n    else\n        return;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_CHOOSECOLUMNS),\n        ParentWindowHandle,\n        PhpColumnsDlgProc,\n        &context\n        );\n\n    PhDereferenceObject(context.Columns);\n}\n\nstatic int __cdecl PhpColumnsCompareDisplayIndexTn(\n    _In_ void* Context,\n    _In_ void const* elem1,\n    _In_ void const* elem2\n    )\n{\n    PPH_TREENEW_COLUMN column1 = *(PPH_TREENEW_COLUMN *)elem1;\n    PPH_TREENEW_COLUMN column2 = *(PPH_TREENEW_COLUMN *)elem2;\n\n    return uintcmp(column1->DisplayIndex, column2->DisplayIndex);\n}\n\nstatic long __cdecl PhpInactiveColumnsCompareNameTn(\n    _In_ const void* Context,\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PCWSTR column1 = *(PCWSTR *)elem1;\n    PCWSTR column2 = *(PCWSTR *)elem2;\n\n    return PhCompareStringZ(column1, column2, FALSE);\n}\n\n_Success_(return != ULONG_MAX)\nstatic ULONG IndexOfStringInList(\n    _In_ PPH_LIST List,\n    _In_ PCWSTR String\n    )\n{\n    for (ULONG i = 0; i < List->Count; i++)\n    {\n        if (PhEqualStringZ(List->Items[i], String, FALSE))\n            return i;\n    }\n\n    return ULONG_MAX;\n}\n\nVOID PhpColumnsResetListBox(\n    _In_ HWND ListBoxHandle,\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PPH_LIST Array,\n    _In_opt_ PVOID CompareFunction\n    )\n{\n    SendMessage(ListBoxHandle, WM_SETREDRAW, FALSE, 0);\n\n    ListBox_ResetContent(ListBoxHandle);\n\n    if (CompareFunction)\n        qsort_s(Array->Items, Array->Count, sizeof(ULONG_PTR), CompareFunction, NULL);\n\n    if (!MatchHandle)\n    {\n        for (ULONG i = 0; i < Array->Count; i++)\n        {\n            ListBox_InsertString(ListBoxHandle, i, Array->Items[i]);\n        }\n    }\n    else\n    {\n        ULONG index = 0;\n\n        for (ULONG i = 0; i < Array->Count; i++)\n        {\n            PH_STRINGREF text;\n\n            PhInitializeStringRefLongHint(&text, Array->Items[i]);\n\n            if (PhSearchControlMatch(MatchHandle, &text))\n            {\n                ListBox_InsertString(ListBoxHandle, index, Array->Items[i]);\n                index++;\n            }\n        }\n    }\n\n    SendMessage(ListBoxHandle, WM_SETREDRAW, TRUE, 0);\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhpInactiveColumnsSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PCOLUMNS_DIALOG_CONTEXT context = Context;\n\n    PhpColumnsResetListBox(\n        context->InactiveWindowHandle,\n        MatchHandle,\n        context->InactiveListArray,\n        PhpInactiveColumnsCompareNameTn\n        );\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhpActiveColumnsSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PCOLUMNS_DIALOG_CONTEXT context = Context;\n\n    PhpColumnsResetListBox(\n        context->ActiveWindowHandle,\n        MatchHandle,\n        context->ActiveListArray,\n        NULL\n        );\n}\n\nINT_PTR CALLBACK PhpColumnsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PCOLUMNS_DIALOG_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PCOLUMNS_DIALOG_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            ULONG count;\n            ULONG total;\n            ULONG i;\n            PPH_LIST displayOrderList = NULL;\n            LONG dpiValue;\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            dpiValue = PhGetWindowDpi(hwndDlg);\n\n            context->InactiveWindowHandle = GetDlgItem(hwndDlg, IDC_INACTIVE);\n            context->ActiveWindowHandle = GetDlgItem(hwndDlg, IDC_ACTIVE);\n            context->SearchInactiveHandle = GetDlgItem(hwndDlg, IDC_SEARCH);\n            context->SearchActiveHandle = GetDlgItem(hwndDlg, IDC_FILTER);\n            context->HideWindowHandle = GetDlgItem(hwndDlg, IDC_HIDE);\n            context->ShowWindowHandle = GetDlgItem(hwndDlg, IDC_SHOW);\n            context->MoveUpHandle = GetDlgItem(hwndDlg, IDC_MOVEUP);\n            context->MoveDownHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN);\n            context->InactiveListArray = PhCreateList(1);\n            context->ActiveListArray = PhCreateList(1);\n            context->ControlFont = PhCreateMessageFont(dpiValue); // PhDuplicateFont(PhTreeWindowFont)\n\n            PhCreateSearchControl(\n                hwndDlg,\n                context->SearchInactiveHandle,\n                L\"Inactive columns...\",\n                PhpInactiveColumnsSearchControlCallback,\n                context\n                );\n\n            PhCreateSearchControl(\n                hwndDlg,\n                context->SearchActiveHandle,\n                L\"Active columns...\",\n                PhpActiveColumnsSearchControlCallback,\n                context\n                );\n\n            ListBox_SetItemHeight(context->InactiveWindowHandle, 0, PhGetDpi(16, dpiValue));\n            ListBox_SetItemHeight(context->ActiveWindowHandle, 0, PhGetDpi(16, dpiValue));\n\n            Button_Enable(context->HideWindowHandle, FALSE);\n            Button_Enable(context->ShowWindowHandle, FALSE);\n            Button_Enable(context->MoveUpHandle, FALSE);\n            Button_Enable(context->MoveDownHandle, FALSE);\n\n            if (PhEnableThemeSupport)\n            {\n                context->BrushNormal = CreateSolidBrush(PhThemeWindowBackgroundColor);\n                context->BrushHot = CreateSolidBrush(PhThemeWindowHighlightColor);\n                context->BrushPushed = CreateSolidBrush(PhThemeWindowHighlight2Color);\n                context->TextColor = PhThemeWindowTextColor;\n            }\n            else\n            {\n                context->BrushNormal = GetSysColorBrush(COLOR_WINDOW);\n                context->BrushHot = CreateSolidBrush(RGB(145, 201, 247));\n                context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255));\n                context->TextColor = GetSysColor(COLOR_WINDOWTEXT);\n            }\n\n            if (context->Type == PH_CONTROL_TYPE_TREE_NEW)\n            {\n                PH_TREENEW_COLUMN column;\n\n                count = 0;\n                total = TreeNew_GetColumnCount(context->ControlHandle);\n                i = 0;\n\n                displayOrderList = PhCreateList(total);\n\n                while (count < total)\n                {\n                    if (TreeNew_GetColumn(context->ControlHandle, i, &column))\n                    {\n                        PPH_TREENEW_COLUMN copy;\n\n                        if (column.Fixed)\n                        {\n                            i++;\n                            total--;\n                            continue;\n                        }\n\n                        copy = PhAllocateCopy(&column, sizeof(PH_TREENEW_COLUMN));\n                        PhAddItemList(context->Columns, copy);\n                        count++;\n\n                        if (column.Visible)\n                        {\n                            PhAddItemList(displayOrderList, copy);\n                        }\n                        else\n                        {\n                            PhAddItemList(context->InactiveListArray, (PWSTR)column.Text);\n                        }\n                    }\n\n                    i++;\n                }\n\n                qsort_s(displayOrderList->Items, displayOrderList->Count, sizeof(PVOID), PhpColumnsCompareDisplayIndexTn, NULL);\n            }\n\n            PhpColumnsResetListBox(\n                context->InactiveWindowHandle,\n                0,\n                context->InactiveListArray,\n                PhpInactiveColumnsCompareNameTn\n                );\n\n            if (displayOrderList)\n            {\n                for (i = 0; i < displayOrderList->Count; i++)\n                {\n                    if (context->Type == PH_CONTROL_TYPE_TREE_NEW)\n                    {\n                        PPH_TREENEW_COLUMN copy = displayOrderList->Items[i];\n\n                        PhAddItemList(context->ActiveListArray, (PWSTR)copy->Text);\n                        ListBox_InsertString(context->ActiveWindowHandle, i, copy->Text);\n                    }\n                }\n\n                PhDereferenceObject(displayOrderList);\n            }\n\n            SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveWindowHandle);\n            SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveWindowHandle);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDCANCEL));\n        }\n        break;\n    case WM_DESTROY:\n        {\n            for (ULONG i = 0; i < context->Columns->Count; i++)\n                PhFree(context->Columns->Items[i]);\n\n            if (context->BrushNormal)\n                DeleteBrush(context->BrushNormal);\n            if (context->BrushHot)\n                DeleteBrush(context->BrushHot);\n            if (context->BrushPushed)\n                DeleteBrush(context->BrushPushed);\n            if (context->ControlFont)\n                DeleteFont(context->ControlFont);\n            if (context->InactiveListArray)\n                PhDereferenceObject(context->InactiveListArray);\n            if (context->ActiveListArray)\n                PhDereferenceObject(context->ActiveListArray);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            if (context->ControlFont) DeleteFont(context->ControlFont);\n            context->ControlFont = PhCreateMessageFont(LOWORD(wParam));\n\n            ListBox_SetItemHeight(context->InactiveWindowHandle, 0, PhGetDpi(16, LOWORD(wParam)));\n            ListBox_SetItemHeight(context->ActiveWindowHandle, 0, PhGetDpi(16, LOWORD(wParam)));\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    ULONG i;\n                    ULONG orderArraySize;\n                    PULONG orderArray;\n                    ULONG maxOrder;\n\n                    if (context->Type == PH_CONTROL_TYPE_TREE_NEW)\n                    {\n                        orderArraySize = (TreeNew_GetColumnCount(context->ControlHandle) + 1) * sizeof(ULONG);\n                        orderArray = _malloca(orderArraySize);\n\n                        memset(orderArray, 0, orderArraySize);\n                        maxOrder = 0;\n\n                        // Apply visibility settings and build the order array.\n\n                        TreeNew_SetRedraw(context->ControlHandle, FALSE);\n\n                        for (i = 0; i < context->Columns->Count; i++)\n                        {\n                            PPH_TREENEW_COLUMN column = context->Columns->Items[i];\n                            ULONG index;\n\n                            index = IndexOfStringInList(context->ActiveListArray, column->Text);\n                            column->Visible = index != ULONG_MAX;\n\n                            TreeNew_SetColumn(context->ControlHandle, TN_COLUMN_FLAG_VISIBLE, column);\n\n                            if (column->Visible)\n                            {\n                                orderArray[index] = column->Id;\n\n                                if (maxOrder < index + 1)\n                                    maxOrder = index + 1;\n                            }\n                        }\n\n                        // Apply display order.\n                        TreeNew_SetColumnOrderArray(context->ControlHandle, maxOrder, orderArray);\n\n                        TreeNew_SetRedraw(context->ControlHandle, TRUE);\n\n                        InvalidateRect(context->ControlHandle, NULL, FALSE);\n\n                        _freea(orderArray);\n                    }\n\n                    EndDialog(hwndDlg, IDOK);\n                }\n                break;\n            case IDC_INACTIVE:\n                {\n                    switch (GET_WM_COMMAND_CMD(wParam, lParam))\n                    {\n                    case LBN_DBLCLK:\n                        {\n                            SendMessage(hwndDlg, WM_COMMAND, IDC_SHOW, 0);\n                        }\n                        break;\n                    case LBN_SELCHANGE:\n                        {\n                            LONG sel = ListBox_GetCurSel(context->InactiveWindowHandle);\n\n                            EnableWindow(context->ShowWindowHandle, sel != LB_ERR);\n                        }\n                        break;\n                    }\n                }\n                break;\n            case IDC_ACTIVE:\n                {\n                    switch (GET_WM_COMMAND_CMD(wParam, lParam))\n                    {\n                    case LBN_DBLCLK:\n                        {\n                            SendMessage(hwndDlg, WM_COMMAND, IDC_HIDE, 0);\n                        }\n                        break;\n                    case LBN_SELCHANGE:\n                        {\n                            LONG sel = ListBox_GetCurSel(context->ActiveWindowHandle);\n                            LONG count = ListBox_GetCount(context->ActiveWindowHandle);\n\n                            if (sel != LB_ERR)\n                            {\n                                EnableWindow(context->HideWindowHandle, sel != 0);\n                                EnableWindow(context->MoveUpHandle, sel != 0);\n                                EnableWindow(context->MoveDownHandle, sel != count - 1);\n                            }\n                        }\n                        break;\n                    }\n                }\n                break;\n            case IDC_SHOW:\n                {\n                    LONG sel;\n                    LONG count;\n                    PPH_STRING string;\n\n                    sel = ListBox_GetCurSel(context->InactiveWindowHandle);\n                    count = ListBox_GetCount(context->InactiveWindowHandle);\n\n                    if (sel != LB_ERR)\n                    {\n                        string = PhGetListBoxString(context->InactiveWindowHandle, sel);\n\n                        if (!PhIsNullOrEmptyString(string))\n                        {\n                            ULONG index = IndexOfStringInList(context->InactiveListArray, string->Buffer);\n\n                            if (index != ULONG_MAX)\n                            {\n                                PVOID item = context->InactiveListArray->Items[index];\n\n                                PhRemoveItemsList(context->InactiveListArray, index, 1);\n                                PhAddItemList(context->ActiveListArray, item);\n\n                                ListBox_DeleteString(context->InactiveWindowHandle, sel);\n                                ListBox_AddString(context->ActiveWindowHandle, item);\n                            }\n\n                            count--;\n\n                            if (sel >= count - 1)\n                                sel = count - 1;\n\n                            if (sel != LB_ERR)\n                            {\n                                ListBox_SetCurSel(context->InactiveWindowHandle, sel);\n                            }\n                        }\n                    }\n\n                    SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveWindowHandle);\n                    SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveWindowHandle);\n                }\n                break;\n            case IDC_HIDE:\n                {\n                    LONG sel;\n                    LONG count;\n                    PPH_STRING string;\n\n                    sel = ListBox_GetCurSel(context->ActiveWindowHandle);\n                    count = ListBox_GetCount(context->ActiveWindowHandle);\n\n                    if (sel != LB_ERR)\n                    {\n                        string = PhGetListBoxString(context->ActiveWindowHandle, sel);\n\n                        if (!PhIsNullOrEmptyString(string))\n                        {\n                            ULONG index = IndexOfStringInList(context->ActiveListArray, string->Buffer);\n\n                            if (index != ULONG_MAX)\n                            {\n                                PVOID item = context->ActiveListArray->Items[index];\n\n                                // Remove from active array, insert into inactive\n                                PhRemoveItemsList(context->ActiveListArray, index, 1);\n                                PhAddItemList(context->InactiveListArray, item);\n\n                                // Sort inactive list with new entry\n                                qsort_s(context->InactiveListArray->Items, context->InactiveListArray->Count, sizeof(ULONG_PTR), PhpInactiveColumnsCompareNameTn, NULL);\n                                // Find index of new entry in inactive list\n                                ULONG lb_index = IndexOfStringInList(context->InactiveListArray, item);\n\n                                // Delete from active list\n                                ListBox_DeleteString(context->ActiveWindowHandle, sel);\n                                // Add to list in the same position as the inactive list\n                                ListBox_InsertString(context->InactiveWindowHandle, lb_index, item);\n\n                                PhpColumnsResetListBox(context->InactiveWindowHandle, 0, context->InactiveListArray, PhpInactiveColumnsCompareNameTn);\n                            }\n\n                            count--;\n\n                            if (sel >= count - 1)\n                                sel = count - 1;\n\n                            if (sel != LB_ERR)\n                            {\n                                ListBox_SetCurSel(context->ActiveWindowHandle, sel);\n                            }\n                        }\n\n                        PhClearReference(&string);\n                    }\n\n                    SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveWindowHandle);\n                    SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveWindowHandle);\n                }\n                break;\n            case IDC_MOVEUP:\n                {\n                    LONG sel;\n                    LONG count;\n                    PPH_STRING string;\n\n                    sel = ListBox_GetCurSel(context->ActiveWindowHandle);\n                    count = ListBox_GetCount(context->ActiveWindowHandle);\n\n                    if (sel != LB_ERR)\n                    {\n                        string = PhGetListBoxString(context->ActiveWindowHandle, sel);\n\n                        if (!PhIsNullOrEmptyString(string))\n                        {\n                            ULONG index = IndexOfStringInList(context->ActiveListArray, string->Buffer);\n\n                            if (index != ULONG_MAX)\n                            {\n                                PVOID item = context->ActiveListArray->Items[index];\n                                PhRemoveItemsList(context->ActiveListArray, index, 1);\n                                PhInsertItemList(context->ActiveListArray, index - 1, item);\n\n                                ListBox_DeleteString(context->ActiveWindowHandle, sel);\n                                sel -= 1;\n                                ListBox_InsertString(context->ActiveWindowHandle, sel, item);\n                                ListBox_SetCurSel(context->ActiveWindowHandle, sel);\n\n                                EnableWindow(context->MoveUpHandle, sel != 0);\n                                EnableWindow(context->MoveDownHandle, sel != count - 1);\n                            }\n                        }\n\n                        PhClearReference(&string);\n                    }\n                }\n                break;\n            case IDC_MOVEDOWN:\n                {\n                    LONG sel;\n                    LONG count;\n                    PPH_STRING string;\n\n                    sel = ListBox_GetCurSel(context->ActiveWindowHandle);\n                    count = ListBox_GetCount(context->ActiveWindowHandle);\n\n                    if (sel != LB_ERR && sel != count - 1)\n                    {\n                        string = PhGetListBoxString(context->ActiveWindowHandle, sel);\n\n                        if (!PhIsNullOrEmptyString(string))\n                        {\n                            ULONG index = IndexOfStringInList(context->ActiveListArray, string->Buffer);\n\n                            if (index != ULONG_MAX)\n                            {\n                                PVOID item = context->ActiveListArray->Items[index];\n                                PhRemoveItemsList(context->ActiveListArray, index, 1);\n                                PhInsertItemList(context->ActiveListArray, index + 1, item);\n\n                                ListBox_DeleteString(context->ActiveWindowHandle, sel);\n                                sel += 1;\n                                ListBox_InsertString(context->ActiveWindowHandle, sel, item);\n                                ListBox_SetCurSel(context->ActiveWindowHandle, sel);\n\n                                EnableWindow(context->MoveUpHandle, sel != 0);\n                                EnableWindow(context->MoveDownHandle, sel != count - 1);\n                            }\n                        }\n\n                        PhClearReference(&string);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n     case WM_DRAWITEM:\n         {\n             LPDRAWITEMSTRUCT drawInfo = (LPDRAWITEMSTRUCT)lParam;\n\n             if (\n                 drawInfo->hwndItem == context->InactiveWindowHandle ||\n                 drawInfo->hwndItem == context->ActiveWindowHandle\n                 )\n             {\n                 HDC bufferDc;\n                 HBITMAP bufferBitmap;\n                 HBITMAP oldBufferBitmap;\n                 PPH_STRING string;\n                 RECT bufferRect =\n                 {\n                     0, 0,\n                     drawInfo->rcItem.right - drawInfo->rcItem.left,\n                     drawInfo->rcItem.bottom - drawInfo->rcItem.top\n                 };\n                 BOOLEAN isSelected = (drawInfo->itemState & ODS_SELECTED) == ODS_SELECTED;\n                 BOOLEAN isFocused = (drawInfo->itemState & ODS_FOCUS) == ODS_FOCUS;\n\n                 if (drawInfo->itemID == LB_ERR)\n                     break;\n\n                 string = PhGetListBoxString(drawInfo->hwndItem, drawInfo->itemID);\n\n                 if (PhIsNullOrEmptyString(string))\n                 {\n                     PhClearReference(&string);\n                     break;\n                 }\n\n                 bufferDc = CreateCompatibleDC(drawInfo->hDC);\n                 bufferBitmap = CreateCompatibleBitmap(drawInfo->hDC, bufferRect.right, bufferRect.bottom);\n                 oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap);\n\n                 SelectFont(bufferDc, context->ControlFont);\n                 SetBkMode(bufferDc, TRANSPARENT);\n\n                 if (isSelected || isFocused)\n                 {\n                     FillRect(bufferDc, &bufferRect, context->BrushHot);\n                     //FrameRect(bufferDc, &bufferRect, PhGetStockBrush(BLACK_BRUSH));\n                     SetTextColor(bufferDc, context->TextColor);\n                 }\n                 else\n                 {\n                     FillRect(bufferDc, &bufferRect, context->BrushNormal);\n                     //FrameRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_HIGHLIGHTTEXT));\n                     SetTextColor(bufferDc, context->TextColor);\n                 }\n\n                 bufferRect.left += 5;\n                 DrawText(\n                     bufferDc,\n                     string->Buffer,\n                     (UINT)string->Length / sizeof(WCHAR),\n                     &bufferRect,\n                     DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP\n                     );\n                 bufferRect.left -= 5;\n\n                 BitBlt(\n                     drawInfo->hDC,\n                     drawInfo->rcItem.left,\n                     drawInfo->rcItem.top,\n                     drawInfo->rcItem.right,\n                     drawInfo->rcItem.bottom,\n                     bufferDc,\n                     0,\n                     0,\n                     SRCCOPY\n                     );\n\n                 SelectBitmap(bufferDc, oldBufferBitmap);\n                 DeleteBitmap(bufferBitmap);\n                 DeleteDC(bufferDc);\n                 PhClearReference(&string);\n\n                 return TRUE;\n             }\n         }\n         break;\n     case WM_CTLCOLORBTN:\n         return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n     case WM_CTLCOLORDLG:\n         return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n     case WM_CTLCOLORSTATIC:\n         return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/chdlg.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2013\n *     dmex    2015-2024\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <settings.h>\n#include <vsstyle.h>\n#include <vssym32.h>\n\ntypedef struct _PH_CHOICE_DIALOG_CONTEXT\n{\n    PCWSTR Title;\n    PCWSTR Message;\n    PCWSTR *Choices;\n    ULONG NumberOfChoices;\n    PCWSTR Option;\n    ULONG Flags;\n    PPH_STRING *SelectedChoice;\n    PBOOLEAN SelectedOption;\n    PCWSTR SavedChoicesSettingName;\n\n    HWND ComboBoxHandle;\n    HFONT FontHandle;\n} PH_CHOICE_DIALOG_CONTEXT, *PPH_CHOICE_DIALOG_CONTEXT;\n\nINT_PTR CALLBACK PhChoiceDlgProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_CHOICE_DIALOG_CONTEXT context;\n\n    if (WindowMessage == WM_INITDIALOG)\n    {\n        context = (PPH_CHOICE_DIALOG_CONTEXT)lParam;\n        PhSetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (WindowMessage)\n    {\n    case WM_INITDIALOG:\n        {\n            ULONG type;\n            SIZE_T i;\n            HWND comboBoxHandle;\n            HWND checkBoxHandle;\n            RECT checkBoxRect;\n            RECT rect;\n            ULONG diff;\n\n            checkBoxHandle = GetDlgItem(WindowHandle, IDC_OPTION);\n\n            PhSetWindowText(WindowHandle, context->Title);\n            PhSetWindowText(GetDlgItem(WindowHandle, IDC_MESSAGE), context->Message);\n            PhCenterWindow(WindowHandle, GetParent(WindowHandle));\n\n            type = context->Flags & PH_CHOICE_DIALOG_TYPE_MASK;\n\n            // Select the control to show, depending on the type. This is\n            // because it is impossible to change the style of the combo box\n            // after it is created.\n            switch (type)\n            {\n            case PH_CHOICE_DIALOG_USER_CHOICE:\n                comboBoxHandle = GetDlgItem(WindowHandle, IDC_CHOICEUSER);\n                break;\n            case PH_CHOICE_DIALOG_PASSWORD:\n                comboBoxHandle = GetDlgItem(WindowHandle, IDC_CHOICESIMPLE);\n\n                // Disable combo box features since it isn't a combo box.\n                context->SavedChoicesSettingName = NULL;\n                break;\n            case PH_CHOICE_DIALOG_CHOICE:\n            default:\n                comboBoxHandle = GetDlgItem(WindowHandle, IDC_CHOICE);\n                break;\n            }\n\n            context->ComboBoxHandle = comboBoxHandle;\n            ShowWindow(context->ComboBoxHandle, SW_SHOW);\n\n            if (type == PH_CHOICE_DIALOG_PASSWORD)\n            {\n                // Nothing\n            }\n            else if (type == PH_CHOICE_DIALOG_USER_CHOICE && context->SavedChoicesSettingName)\n            {\n                PPH_STRING savedChoices = PhGetStringSetting(context->SavedChoicesSettingName);\n                ULONG_PTR indexOfDelim;\n                PPH_STRING savedChoice;\n\n                i = 0;\n\n                // Split the saved choices using the delimiter.\n                while (i < savedChoices->Length / sizeof(WCHAR))\n                {\n                    // BUG BUG BUG - what if the user saves \"\\s\"?\n                    indexOfDelim = PhFindStringInString(savedChoices, i, L\"\\\\s\");\n\n                    if (indexOfDelim == SIZE_MAX)\n                        indexOfDelim = savedChoices->Length / sizeof(WCHAR);\n\n                    savedChoice = PhSubstring(savedChoices, i, indexOfDelim - i);\n\n                    if (savedChoice->Length != 0)\n                    {\n                        PPH_STRING unescaped;\n\n                        unescaped = PhUnescapeStringForDelimiter(savedChoice, L'\\\\');\n                        ComboBox_InsertString(comboBoxHandle, -1, unescaped->Buffer);\n                        PhDereferenceObject(unescaped);\n                    }\n\n                    PhDereferenceObject(savedChoice);\n\n                    i = indexOfDelim + 2;\n                }\n\n                PhDereferenceObject(savedChoices);\n            }\n            else\n            {\n                for (i = 0; i < context->NumberOfChoices; i++)\n                {\n                    ComboBox_AddString(comboBoxHandle, context->Choices[i]);\n                }\n\n                context->SavedChoicesSettingName = NULL; // make sure we don't try to save the choices\n            }\n\n            if (type == PH_CHOICE_DIALOG_PASSWORD)\n            {\n                if (!PhIsNullOrEmptyString(*context->SelectedChoice))\n                {\n                    PhSetWindowText(comboBoxHandle, PhGetString(*context->SelectedChoice));\n                }\n\n                Edit_SetSel(comboBoxHandle, 0, -1);\n            }\n            else if (type == PH_CHOICE_DIALOG_USER_CHOICE || type == PH_CHOICE_DIALOG_CHOICE)\n            {\n                // If we failed to choose a default choice based on what was specified,\n                // select the first one if possible, or set the text directly.\n                if (\n                    !PhIsNullOrEmptyString(*context->SelectedChoice) ||\n                    PhSelectComboBoxString(comboBoxHandle, PhGetString(*context->SelectedChoice), FALSE) == CB_ERR\n                    )\n                {\n                    if (type == PH_CHOICE_DIALOG_USER_CHOICE && !PhIsNullOrEmptyString(*context->SelectedChoice))\n                    {\n                        PhSetWindowText(comboBoxHandle, PhGetString(*context->SelectedChoice));\n                    }\n                    else if (type == PH_CHOICE_DIALOG_CHOICE && context->NumberOfChoices != 0)\n                    {\n                        ComboBox_SetCurSel(comboBoxHandle, 0);\n                    }\n                }\n\n                if (type == PH_CHOICE_DIALOG_USER_CHOICE)\n                    ComboBox_SetEditSel(comboBoxHandle, 0, -1);\n            }\n\n            if (context->Option)\n            {\n                PhSetWindowText(checkBoxHandle, context->Option);\n\n                if (context->SelectedOption)\n                    Button_SetCheck(checkBoxHandle, *context->SelectedOption ? BST_CHECKED : BST_UNCHECKED);\n            }\n            else\n            {\n                // Hide the check box and move the buttons up.\n\n                ShowWindow(checkBoxHandle, SW_HIDE);\n                PhGetWindowRect(checkBoxHandle, &checkBoxRect);\n                MapWindowRect(NULL, WindowHandle, &checkBoxRect);\n                PhGetWindowRect(GetDlgItem(WindowHandle, IDOK), &rect);\n                MapWindowRect(NULL, WindowHandle, &rect);\n                diff = rect.top - checkBoxRect.top;\n\n                // OK\n                rect.top -= diff;\n                rect.bottom -= diff;\n                SetWindowPos(GetDlgItem(WindowHandle, IDOK), NULL, rect.left, rect.top,\n                    rect.right - rect.left, rect.bottom - rect.top,\n                    SWP_NOACTIVATE | SWP_NOZORDER);\n\n                // Cancel\n                PhGetWindowRect(GetDlgItem(WindowHandle, IDCANCEL), &rect);\n                MapWindowRect(NULL, WindowHandle, &rect);\n                rect.top -= diff;\n                rect.bottom -= diff;\n                SetWindowPos(GetDlgItem(WindowHandle, IDCANCEL), NULL, rect.left, rect.top,\n                    rect.right - rect.left, rect.bottom - rect.top,\n                    SWP_NOACTIVATE | SWP_NOZORDER);\n\n                // Window\n                PhGetWindowRect(WindowHandle, &rect);\n                rect.bottom -= diff;\n                SetWindowPos(WindowHandle, NULL, rect.left, rect.top,\n                    rect.right - rect.left, rect.bottom - rect.top,\n                    SWP_NOACTIVATE | SWP_NOZORDER);\n            }\n\n            PhInitializeWindowTheme(WindowHandle, PhEnableThemeSupport);\n\n            PhSetDialogFocus(WindowHandle, comboBoxHandle);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(WindowHandle, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    PPH_STRING selectedChoice;\n\n                    if (FlagOn(context->Flags, PH_CHOICE_DIALOG_TYPE_MASK) != PH_CHOICE_DIALOG_PASSWORD)\n                    {\n                        selectedChoice = PH_AUTO(PhGetWindowText(context->ComboBoxHandle));\n                        *context->SelectedChoice = selectedChoice;\n                    }\n                    else\n                    {\n                        // Password values are never auto-dereferenced.\n                        selectedChoice = PhGetWindowText(context->ComboBoxHandle);\n                        *context->SelectedChoice = selectedChoice;\n                    }\n\n                    if (context->Option && context->SelectedOption)\n                    {\n                        *context->SelectedOption = Button_GetCheck(GetDlgItem(WindowHandle, IDC_OPTION)) == BST_CHECKED;\n                    }\n\n                    if (context->SavedChoicesSettingName)\n                    {\n                        PH_STRING_BUILDER savedChoices;\n                        ULONG i;\n                        ULONG choicesToSave = PH_CHOICE_DIALOG_SAVED_CHOICES;\n                        PPH_STRING choice;\n                        PPH_STRING escaped;\n\n                        PhInitializeStringBuilder(&savedChoices, 100);\n\n                        // Push the selected choice to the top, then save the others.\n\n                        if (selectedChoice->Length != 0)\n                        {\n                            escaped = PH_AUTO(PhEscapeStringForDelimiter(selectedChoice, L'\\\\'));\n                            PhAppendStringBuilder(&savedChoices, &escaped->sr);\n                            PhAppendStringBuilder2(&savedChoices, L\"\\\\s\");\n                        }\n\n                        for (i = 1; i < choicesToSave; i++)\n                        {\n                            choice = PH_AUTO(PhGetComboBoxString(context->ComboBoxHandle, i - 1));\n\n                            if (PhIsNullOrEmptyString(choice))\n                                break;\n\n                            // Don't save the choice if it's the same as the one\n                            // entered by the user (since we already saved it above).\n                            if (PhEqualString(choice, selectedChoice, FALSE))\n                            {\n                                choicesToSave++; // useless for now, but may be needed in the future\n                                continue;\n                            }\n\n                            escaped = PH_AUTO(PhEscapeStringForDelimiter(choice, L'\\\\'));\n                            PhAppendStringBuilder(&savedChoices, &escaped->sr);\n                            PhAppendStringBuilder2(&savedChoices, L\"\\\\s\");\n                        }\n\n                        if (PhEndsWithString2(savedChoices.String, L\"\\\\s\", FALSE))\n                            PhRemoveEndStringBuilder(&savedChoices, 2);\n\n                        PhSetStringSetting2(context->SavedChoicesSettingName, &savedChoices.String->sr);\n                        PhDeleteStringBuilder(&savedChoices);\n                    }\n\n                    EndDialog(WindowHandle, IDOK);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nINT_PTR CALLBACK PhChooseNewPageDlgProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_CHOICE_DIALOG_CONTEXT context;\n\n    if (WindowMessage == WM_INITDIALOG)\n    {\n        context = (PPH_CHOICE_DIALOG_CONTEXT)lParam;\n        PhSetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (WindowMessage)\n    {\n    case WM_INITDIALOG:\n        {\n            context->ComboBoxHandle = GetDlgItem(WindowHandle, IDC_INPUT);\n\n            PhCenterWindow(WindowHandle, GetParent(WindowHandle));\n            PhSetApplicationWindowIcon(WindowHandle);\n\n            PhSetWindowText(WindowHandle, PhApplicationName);\n            PhSetWindowText(GetDlgItem(WindowHandle, IDC_TITLE), context->Title);\n            PhSetWindowText(GetDlgItem(WindowHandle, IDC_TEXT), context->Message);\n\n            {\n                NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) };\n                LONG dpi = PhGetWindowDpi(WindowHandle);\n\n                if (PhGetSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, dpi))\n                {\n                    metrics.lfMessageFont.lfHeight = 4 * metrics.lfMessageFont.lfHeight / 3;\n\n                    if (context->FontHandle = CreateFontIndirect(&metrics.lfMessageFont))\n                    {\n                        SetWindowFont(GetDlgItem(WindowHandle, IDC_TITLE), context->FontHandle, FALSE);\n                    }\n\n                    metrics.lfMessageFont.lfHeight = -14;\n\n                    if (context->FontHandle = CreateFontIndirect(&metrics.lfMessageFont))\n                    {\n                        SetWindowFont(context->ComboBoxHandle, context->FontHandle, FALSE);\n                    }\n                }\n            }\n\n            {\n                if (FlagOn(context->Flags, PH_CHOICE_DIALOG_TYPE_MASK) == PH_CHOICE_DIALOG_PASSWORD)\n                {\n                    NOTHING;\n                }\n                else if (FlagOn(context->Flags, PH_CHOICE_DIALOG_TYPE_MASK) == PH_CHOICE_DIALOG_USER_CHOICE && context->SavedChoicesSettingName)\n                {\n                    PPH_STRING savedChoices = PhGetStringSetting(context->SavedChoicesSettingName);\n                    PPH_STRING savedChoice;\n                    ULONG_PTR indexOfDelim;\n                    ULONG_PTR i = 0;\n\n                    // Split the saved choices using the delimiter.\n                    while (i < savedChoices->Length / sizeof(WCHAR))\n                    {\n                        // BUG BUG BUG - what if the user saves \"\\s\"?\n                        indexOfDelim = PhFindStringInString(savedChoices, i, L\"\\\\s\");\n\n                        if (indexOfDelim == SIZE_MAX)\n                            indexOfDelim = savedChoices->Length / sizeof(WCHAR);\n\n                        savedChoice = PhSubstring(savedChoices, i, indexOfDelim - i);\n\n                        if (savedChoice->Length)\n                        {\n                            PPH_STRING unescaped;\n\n                            unescaped = PhUnescapeStringForDelimiter(savedChoice, L'\\\\');\n                            ComboBox_InsertString(context->ComboBoxHandle, UINT_MAX, unescaped->Buffer);\n                            PhDereferenceObject(unescaped);\n                        }\n\n                        PhDereferenceObject(savedChoice);\n\n                        i = indexOfDelim + 2;\n                    }\n\n                    PhDereferenceObject(savedChoices);\n                }\n                else\n                {\n                    for (ULONG i = 0; i < context->NumberOfChoices; i++)\n                    {\n                        ComboBox_AddString(context->ComboBoxHandle, context->Choices[i]);\n                    }\n\n                    context->SavedChoicesSettingName = NULL; // make sure we don't try to save the choices\n                }\n            }\n\n            PhSetDialogFocus(WindowHandle, context->ComboBoxHandle);\n\n            if (PhEnableThemeSupport)\n                ShowWindow(GetDlgItem(WindowHandle, IDC_SIZE_), SW_HIDE);\n            PhInitializeWindowTheme(WindowHandle, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n\n            if (context->FontHandle)\n            {\n                DeleteFont(context->FontHandle);\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                {\n                    EndDialog(WindowHandle, IDCANCEL);\n                }\n                break;\n            case IDOK:\n                {\n                    PPH_STRING selectedChoice;\n\n                    if (FlagOn(context->Flags, PH_CHOICE_DIALOG_TYPE_MASK) != PH_CHOICE_DIALOG_PASSWORD)\n                    {\n                        selectedChoice = PH_AUTO(PhGetWindowText(context->ComboBoxHandle));\n                        *context->SelectedChoice = selectedChoice;\n                    }\n                    else\n                    {\n                        // Password values are never auto-dereferenced.\n                        selectedChoice = PhGetWindowText(context->ComboBoxHandle);\n                        *context->SelectedChoice = selectedChoice;\n                    }\n\n                    if (context->SavedChoicesSettingName)\n                    {\n                        PH_STRING_BUILDER savedChoices;\n                        ULONG i;\n                        ULONG choicesToSave = PH_CHOICE_DIALOG_SAVED_CHOICES;\n                        PPH_STRING choice;\n                        PPH_STRING escaped;\n\n                        PhInitializeStringBuilder(&savedChoices, 100);\n\n                        // Push the selected choice to the top, then save the others.\n\n                        if (selectedChoice->Length != 0)\n                        {\n                            escaped = PH_AUTO(PhEscapeStringForDelimiter(selectedChoice, L'\\\\'));\n                            PhAppendStringBuilder(&savedChoices, &escaped->sr);\n                            PhAppendStringBuilder2(&savedChoices, L\"\\\\s\");\n                        }\n\n                        for (i = 1; i < choicesToSave; i++)\n                        {\n                            choice = PH_AUTO(PhGetComboBoxString(context->ComboBoxHandle, i - 1));\n\n                            if (PhIsNullOrEmptyString(choice))\n                                break;\n\n                            // Don't save the choice if it's the same as the one\n                            // entered by the user (since we already saved it above).\n                            if (PhEqualString(choice, selectedChoice, FALSE))\n                            {\n                                choicesToSave++; // useless for now, but may be needed in the future\n                                continue;\n                            }\n\n                            escaped = PH_AUTO(PhEscapeStringForDelimiter(choice, L'\\\\'));\n                            PhAppendStringBuilder(&savedChoices, &escaped->sr);\n                            PhAppendStringBuilder2(&savedChoices, L\"\\\\s\");\n                        }\n\n                        if (PhEndsWithString2(savedChoices.String, L\"\\\\s\", FALSE))\n                            PhRemoveEndStringBuilder(&savedChoices, 2);\n\n                        PhSetStringSetting2(context->SavedChoicesSettingName, &savedChoices.String->sr);\n                        PhDeleteStringBuilder(&savedChoices);\n                    }\n\n                    EndDialog(WindowHandle, IDOK);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_ERASEBKGND:\n        {\n            LONG dpi = PhGetWindowDpi(WindowHandle);\n            HDC hdc = (HDC)wParam;\n            RECT clientRect;\n\n            if (!PhGetClientRect(WindowHandle, &clientRect))\n                break;\n\n            SetBkMode(hdc, TRANSPARENT);\n\n            clientRect.bottom -= PhGetDpi(50, dpi);\n            FillRect(hdc, &clientRect, PhEnableThemeSupport ? PhThemeWindowBackgroundBrush : GetSysColorBrush(COLOR_WINDOW));\n\n            clientRect.top = clientRect.bottom;\n            clientRect.bottom = clientRect.top + PhGetDpi(50, dpi);\n\n            if (PhEnableThemeSupport)\n            {\n                SetDCBrushColor(hdc, RGB(50, 50, 50));\n                FillRect(hdc, &clientRect, PhGetStockBrush(DC_BRUSH));\n                clientRect.bottom = clientRect.top + 1;\n                SetDCBrushColor(hdc, PhThemeWindowForegroundColor);\n                FillRect(hdc, &clientRect, PhGetStockBrush(DC_BRUSH));\n                PhOffsetRect(&clientRect, 0, 1);\n                SetDCBrushColor(hdc, PhThemeWindowBackground2Color);\n                FillRect(hdc, &clientRect, PhGetStockBrush(DC_BRUSH));\n            }\n            else\n            {\n                FillRect(hdc, &clientRect, GetSysColorBrush(COLOR_3DFACE));\n            }\n\n            SetWindowLongPtr(WindowHandle, DWLP_MSGRESULT, TRUE);\n        }\n        return TRUE;\n    case WM_CTLCOLORSTATIC:\n        {\n            HDC hdc = (HDC)wParam;\n\n            if (PhEnableThemeSupport)\n                break;\n\n            SetBkMode(hdc, TRANSPARENT);\n\n            if ((HWND)lParam == GetDlgItem(WindowHandle, IDC_TITLE))\n            {\n                static COLORREF color = 0;\n\n                if (color == 0)\n                {\n                    HTHEME theme;\n\n                    if (theme = PhOpenThemeData(NULL, VSCLASS_TASKDIALOG, 0))\n                    {\n                        PhGetThemeColor(theme, TDLG_MAININSTRUCTIONPANE, 0, TMT_TEXTCOLOR, &color);\n                        PhCloseThemeData(theme);\n                    }\n                }\n\n                SetTextColor(hdc, color);\n            }\n\n            return (INT_PTR)PhGetStockBrush(WHITE_BRUSH);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n * Prompts the user for input.\n *\n * \\remarks If \\c PH_CHOICE_DIALOG_PASSWORD is specified, the string\n * returned in \\a SelectedChoice is NOT auto-dereferenced.\n */\nBOOLEAN PhaChoiceDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Message,\n    _In_opt_ PCWSTR*Choices,\n    _In_opt_ ULONG NumberOfChoices,\n    _In_opt_ PCWSTR Option,\n    _In_ ULONG Flags,\n    _Inout_ PPH_STRING *SelectedChoice,\n    _Inout_opt_ PBOOLEAN SelectedOption,\n    _In_opt_ PCWSTR SavedChoicesSettingName\n    )\n{\n    PH_CHOICE_DIALOG_CONTEXT context;\n\n    memset(&context, 0, sizeof(PH_CHOICE_DIALOG_CONTEXT));\n    context.Title = Title;\n    context.Message = Message;\n    context.Choices = Choices;\n    context.NumberOfChoices = NumberOfChoices;\n    context.Option = Option;\n    context.Flags = Flags;\n    context.SelectedChoice = SelectedChoice;\n    context.SelectedOption = SelectedOption;\n    context.SavedChoicesSettingName = SavedChoicesSettingName;\n\n    return PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_CHOOSE),\n        ParentWindowHandle,\n        PhChoiceDlgProc,\n        &context\n        ) == IDOK;\n}\n\nBOOLEAN PhChoiceDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Message,\n    _In_opt_ PCWSTR*Choices,\n    _In_opt_ ULONG NumberOfChoices,\n    _In_opt_ PCWSTR Option,\n    _In_ ULONG Flags,\n    _Inout_ PPH_STRING *SelectedChoice,\n    _Inout_opt_ PBOOLEAN SelectedOption,\n    _In_opt_ PCWSTR SavedChoicesSettingName\n    )\n{\n    PH_CHOICE_DIALOG_CONTEXT context;\n\n    memset(&context, 0, sizeof(PH_CHOICE_DIALOG_CONTEXT));\n    context.Title = Title;\n    context.Message = Message;\n    context.Choices = Choices;\n    context.NumberOfChoices = NumberOfChoices;\n    context.Option = Option;\n    context.Flags = Flags;\n    context.SelectedChoice = SelectedChoice;\n    context.SelectedOption = SelectedOption;\n    context.SavedChoicesSettingName = SavedChoicesSettingName;\n\n    return PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_CHOOSENEW),\n        PhCsForceNoParent ? NULL : ParentWindowHandle,\n        PhChooseNewPageDlgProc,\n        &context\n        ) == IDOK;\n}\n"
  },
  {
    "path": "SystemInformer/chproc.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2016-2023\n *\n */\n\n#include <phapp.h>\n#include <procprv.h>\n#include <lsasup.h>\n\ntypedef struct _PH_CHOOSE_PROCESS_DIALOG_CONTEXT\n{\n    PCWSTR Message;\n    HANDLE ProcessId;\n\n    PH_LAYOUT_MANAGER LayoutManager;\n    RECT MinimumSize;\n    HIMAGELIST ImageList;\n    HWND ListViewHandle;\n} PH_CHOOSE_PROCESS_DIALOG_CONTEXT, *PPH_CHOOSE_PROCESS_DIALOG_CONTEXT;\n\nINT_PTR CALLBACK PhpChooseProcessDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Success_(return)\nBOOLEAN PhShowChooseProcessDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR Message,\n    _Out_ PHANDLE ProcessId\n    )\n{\n    PH_CHOOSE_PROCESS_DIALOG_CONTEXT context;\n\n    memset(&context, 0, sizeof(PH_CHOOSE_PROCESS_DIALOG_CONTEXT));\n    context.Message = Message;\n    context.ProcessId = NULL;\n\n    if (PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_CHOOSEPROCESS),\n        ParentWindowHandle,\n        PhpChooseProcessDlgProc,\n        &context\n        ) == IDOK)\n    {\n        *ProcessId = context.ProcessId;\n\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\nstatic VOID PhpRefreshProcessList(\n    _In_ HWND hwndDlg,\n    _In_ PPH_CHOOSE_PROCESS_DIALOG_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n\n    if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))\n    {\n        PhShowStatus(hwndDlg, L\"Unable to enumerate processes\", status, 0);\n        return;\n    }\n\n    ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE);\n    ListView_DeleteAllItems(Context->ListViewHandle);\n    PhImageListRemoveAll(Context->ImageList);\n\n    process = PH_FIRST_PROCESS(processes);\n\n    do\n    {\n        LONG lvItemIndex;\n        PPH_STRING name;\n        HANDLE processHandle;\n        PPH_STRING fileName = NULL;\n        HICON icon = NULL;\n        WCHAR processIdString[PH_INT32_STR_LEN_1];\n        PPH_STRING userName = NULL;\n        LONG imageIndex = INT_MAX;\n\n        if (process->UniqueProcessId != SYSTEM_IDLE_PROCESS_ID)\n            name = PhCreateStringFromUnicodeString(&process->ImageName);\n        else\n            name = PhCreateStringFromUnicodeString(&SYSTEM_IDLE_PROCESS_NAME);\n\n        lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, name->Buffer, process->UniqueProcessId);\n        PhDereferenceObject(name);\n\n        if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, process->UniqueProcessId)))\n        {\n            HANDLE tokenHandle;\n            PH_TOKEN_USER tokenUser;\n\n            if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)))\n            {\n                if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser)))\n                {\n                    userName = PhGetSidFullName(tokenUser.User.Sid, TRUE, NULL);\n                }\n\n                NtClose(tokenHandle);\n            }\n\n            NtClose(processHandle);\n        }\n\n        if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID && !userName)\n        {\n            PhSetReference(&userName, PhGetSidFullName((PSID)&PhSeLocalSystemSid, TRUE, NULL));\n        }\n\n        if (process->UniqueProcessId == SYSTEM_PROCESS_ID)\n            fileName = PhGetKernelFileName();\n        else if (PH_IS_REAL_PROCESS_ID(process->UniqueProcessId))\n            PhGetProcessImageFileNameByProcessId(process->UniqueProcessId, &fileName);\n\n        if (fileName)\n            PhMoveReference(&fileName, PhGetFileName(fileName));\n\n        // Icon\n        if (!PhIsNullOrEmptyString(fileName))\n        {\n            PhExtractIcon(PhGetString(fileName), &icon, NULL);\n        }\n\n        if (icon)\n        {\n            imageIndex = PhImageListAddIcon(Context->ImageList, icon);\n            PhSetListViewItemImageIndex(Context->ListViewHandle, lvItemIndex, imageIndex);\n            DestroyIcon(icon);\n        }\n        else\n        {\n            PhGetStockApplicationIcon(NULL, &icon);\n            imageIndex = PhImageListAddIcon(Context->ImageList, icon);\n            PhSetListViewItemImageIndex(Context->ListViewHandle, lvItemIndex, imageIndex);\n        }\n\n        // PID\n        PhPrintUInt32(processIdString, HandleToUlong(process->UniqueProcessId));\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, processIdString);\n\n        // User Name\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, PhGetString(userName));\n\n        if (userName) PhDereferenceObject(userName);\n        if (fileName) PhDereferenceObject(fileName);\n    } while (process = PH_NEXT_PROCESS(process));\n\n    PhFree(processes);\n\n    ExtendedListView_SortItems(Context->ListViewHandle);\n    ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE);\n}\n\nstatic VOID PhpChooseProcessSetImagelist(\n    _Inout_ PPH_CHOOSE_PROCESS_DIALOG_CONTEXT context\n    )\n{\n    LONG dpiValue;\n\n    dpiValue = PhGetWindowDpi(context->ListViewHandle);\n\n    if (context->ImageList)\n    {\n        PhImageListSetIconSize(\n            context->ImageList,\n            PhGetSystemMetrics(SM_CXSMICON, dpiValue),\n            PhGetSystemMetrics(SM_CYSMICON, dpiValue)\n            );\n    }\n    else\n    {\n        context->ImageList = PhImageListCreate(\n            PhGetSystemMetrics(SM_CXSMICON, dpiValue),\n            PhGetSystemMetrics(SM_CYSMICON, dpiValue),\n            ILC_MASK | ILC_COLOR32,\n            0, 40\n            );\n    }\n\n    ListView_SetImageList(context->ListViewHandle, context->ImageList, LVSIL_SMALL);\n}\n\nINT_PTR CALLBACK PhpChooseProcessDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_CHOOSE_PROCESS_DIALOG_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_CHOOSE_PROCESS_DIALOG_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HWND lvHandle;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhSetDialogItemText(hwndDlg, IDC_MESSAGE, context->Message);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);\n            PhLayoutManagerLayout(&context->LayoutManager);\n\n            context->MinimumSize.left = 0;\n            context->MinimumSize.top = 0;\n            context->MinimumSize.right = 280;\n            context->MinimumSize.bottom = 170;\n            MapDialogRect(hwndDlg, &context->MinimumSize);\n\n            context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            PhSetListViewStyle(lvHandle, FALSE, TRUE);\n            PhSetControlTheme(lvHandle, L\"explorer\");\n            PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 180, L\"Name\");\n            PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 60, L\"PID\");\n            PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 160, L\"User name\");\n            PhSetExtendedListView(lvHandle);\n\n            PhpChooseProcessSetImagelist(context);\n\n            PhpRefreshProcessList(hwndDlg, context);\n\n            EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            if (context->ImageList)\n            {\n                PhImageListDestroy(context->ImageList);\n                context->ImageList = NULL;\n            }\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n\n            PhpChooseProcessSetImagelist(context);\n\n            PhpRefreshProcessList(hwndDlg, context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                {\n                    EndDialog(hwndDlg, IDCANCEL);\n                }\n                break;\n            case IDOK:\n                {\n                    if (ListView_GetSelectedCount(context->ListViewHandle) == 1)\n                    {\n                        context->ProcessId = (HANDLE)PhGetSelectedListViewItemParam(context->ListViewHandle);\n                        EndDialog(hwndDlg, IDOK);\n                    }\n                }\n                break;\n            case IDC_REFRESH:\n                {\n                    PhpRefreshProcessList(hwndDlg, context);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case LVN_ITEMCHANGED:\n                {\n                    EnableWindow(GetDlgItem(hwndDlg, IDOK), ListView_GetSelectedCount(context->ListViewHandle) == 1);\n                }\n                break;\n            case NM_DBLCLK:\n                {\n                    SendMessage(hwndDlg, WM_COMMAND, IDOK, 0);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/colmgr.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <colmgr.h>\n\n#include <extmgri.h>\n#include <phplug.h>\n\ntypedef struct _PH_CM_SORT_CONTEXT\n{\n    PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction;\n    ULONG SubId;\n    PVOID Context;\n    PPH_CM_POST_SORT_FUNCTION PostSortFunction;\n    PH_SORT_ORDER SortOrder;\n} PH_CM_SORT_CONTEXT, *PPH_CM_SORT_CONTEXT;\n\nVOID PhCmInitializeManager(\n    _Out_ PPH_CM_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_ ULONG MinId,\n    _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction\n    )\n{\n    Manager->Handle = Handle;\n    Manager->MinId = MinId;\n    Manager->NextId = MinId;\n    Manager->PostSortFunction = PostSortFunction;\n    InitializeListHead(&Manager->ColumnListHead);\n    Manager->NotifyList = NULL;\n}\n\nVOID PhCmDeleteManager(\n    _In_ PPH_CM_MANAGER Manager\n    )\n{\n    PLIST_ENTRY listEntry;\n    PPH_CM_COLUMN column;\n\n    listEntry = Manager->ColumnListHead.Flink;\n\n    while (listEntry != &Manager->ColumnListHead)\n    {\n        column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry);\n        listEntry = listEntry->Flink;\n\n        PhFree(column);\n    }\n\n    if (Manager->NotifyList)\n        PhDereferenceObject(Manager->NotifyList);\n}\n\nPPH_CM_COLUMN PhCmCreateColumn(\n    _Inout_ PPH_CM_MANAGER Manager,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ PPH_PLUGIN Plugin,\n    _In_ ULONG SubId,\n    _In_opt_ PVOID Context,\n    _In_opt_ PVOID SortFunction\n    )\n{\n    PPH_CM_COLUMN column;\n    PH_TREENEW_COLUMN tnColumn;\n\n    column = PhAllocateZero(sizeof(PH_CM_COLUMN));\n    column->Id = Manager->NextId++;\n    column->Plugin = Plugin;\n    column->SubId = SubId;\n    column->Context = Context;\n    column->SortFunction = SortFunction;\n    InsertTailList(&Manager->ColumnListHead, &column->ListEntry);\n\n    memset(&tnColumn, 0, sizeof(PH_TREENEW_COLUMN));\n    tnColumn.Id = column->Id;\n    tnColumn.Context = column;\n    tnColumn.Visible = Column->Visible;\n    tnColumn.CustomDraw = Column->CustomDraw;\n    tnColumn.SortDescending = Column->SortDescending;\n    tnColumn.Text = Column->Text;\n    tnColumn.Width = Column->Width;\n    tnColumn.Alignment = Column->Alignment;\n    tnColumn.DisplayIndex = Column->Visible ? Column->DisplayIndex : ULONG_MAX;\n    tnColumn.TextFlags = Column->TextFlags;\n    TreeNew_AddColumn(Manager->Handle, &tnColumn);\n\n    return column;\n}\n\nPPH_CM_COLUMN PhCmFindColumn(\n    _In_ PPH_CM_MANAGER Manager,\n    _In_ PCPH_STRINGREF PluginName,\n    _In_ ULONG SubId\n    )\n{\n    PLIST_ENTRY listEntry;\n    PPH_CM_COLUMN column;\n\n    listEntry = Manager->ColumnListHead.Flink;\n\n    while (listEntry != &Manager->ColumnListHead)\n    {\n        column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry);\n\n        if (column->SubId == SubId && PhEqualStringRef(PluginName, &column->Plugin->AppContext.AppName, FALSE))\n            return column;\n\n        listEntry = listEntry->Flink;\n    }\n\n    return NULL;\n}\n\nVOID PhCmSetNotifyPlugin(\n    _In_ PPH_CM_MANAGER Manager,\n    _In_ PPH_PLUGIN Plugin\n    )\n{\n    if (!Manager->NotifyList)\n    {\n        Manager->NotifyList = PhCreateList(8);\n    }\n    else\n    {\n        if (PhFindItemList(Manager->NotifyList, Plugin) != ULONG_MAX)\n            return;\n    }\n\n    PhAddItemList(Manager->NotifyList, Plugin);\n}\n\nBOOLEAN PhCmForwardMessage(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PPH_CM_MANAGER Manager\n    )\n{\n    PH_PLUGIN_TREENEW_MESSAGE pluginMessage;\n    PPH_PLUGIN plugin;\n\n    switch (Message)\n    {\n    case TreeNewDestroying:\n        {\n            return FALSE;\n        }\n        break;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            PH_TREENEW_COLUMN tnColumn;\n            PPH_CM_COLUMN column;\n\n            if (getCellText->Id < Manager->MinId)\n                return FALSE;\n\n            if (!TreeNew_GetColumn(WindowHandle, getCellText->Id, &tnColumn))\n                return FALSE;\n\n            column = tnColumn.Context;\n            pluginMessage.SubId = column->SubId;\n            pluginMessage.Context = column->Context;\n            plugin = column->Plugin;\n        }\n        break;\n    case TreeNewCustomDraw:\n        {\n            PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;\n            PPH_CM_COLUMN column;\n\n            if (customDraw->Column->Id < Manager->MinId)\n                return FALSE;\n\n            column = customDraw->Column->Context;\n            pluginMessage.SubId = column->SubId;\n            pluginMessage.Context = column->Context;\n            plugin = column->Plugin;\n        }\n        break;\n    case TreeNewColumnResized:\n        {\n            PPH_TREENEW_COLUMN tlColumn = Parameter1;\n            PPH_CM_COLUMN column;\n\n            if (tlColumn->Id < Manager->MinId)\n                return FALSE;\n\n            column = tlColumn->Context;\n            pluginMessage.SubId = column->SubId;\n            pluginMessage.Context = column->Context;\n            plugin = column->Plugin;\n        }\n        break;\n    case TreeNewGetHeaderText:\n        {\n            PPH_TREENEW_GET_HEADER_TEXT getHeaderText = Parameter1;\n            PPH_TREENEW_COLUMN tlColumn = getHeaderText->Column;\n            PPH_CM_COLUMN column;\n\n            if (tlColumn->Id < Manager->MinId)\n                return FALSE;\n\n            column = tlColumn->Context;\n            pluginMessage.SubId = column->SubId;\n            pluginMessage.Context = column->Context;\n            plugin = column->Plugin;\n        }\n        break;\n    default:\n        {\n            // Some plugins want to be notified about all messages.\n            if (Manager->NotifyList)\n            {\n                for (ULONG i = 0; i < Manager->NotifyList->Count; i++)\n                {\n                    plugin = Manager->NotifyList->Items[i];\n\n                    pluginMessage.TreeNewHandle = WindowHandle;\n                    pluginMessage.Message = Message;\n                    pluginMessage.Parameter1 = Parameter1;\n                    pluginMessage.Parameter2 = Parameter2;\n                    pluginMessage.SubId = 0;\n                    pluginMessage.Context = NULL;\n\n                    PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage);\n                }\n            }\n        }\n        return FALSE;\n    }\n\n    pluginMessage.TreeNewHandle = WindowHandle;\n    pluginMessage.Message = Message;\n    pluginMessage.Parameter1 = Parameter1;\n    pluginMessage.Parameter2 = Parameter2;\n\n    PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage);\n\n    return TRUE;\n}\n\nstatic int __cdecl PhCmpSortFunction(\n    _In_ void *context,\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_CM_SORT_CONTEXT sortContext = context;\n    PVOID node1 = *(PVOID *)elem1;\n    PVOID node2 = *(PVOID *)elem2;\n    LONG result;\n\n    result = sortContext->SortFunction(node1, node2, sortContext->SubId, sortContext->SortOrder, sortContext->Context);\n\n    return sortContext->PostSortFunction(result, node1, node2, sortContext->SortOrder);\n}\n\nBOOLEAN PhCmForwardSort(\n    _In_ PPH_TREENEW_NODE *Nodes,\n    _In_ ULONG NumberOfNodes,\n    _In_ ULONG SortColumn,\n    _In_ PH_SORT_ORDER SortOrder,\n    _In_ PPH_CM_MANAGER Manager\n    )\n{\n    PH_TREENEW_COLUMN tnColumn;\n    PPH_CM_COLUMN column;\n    PH_CM_SORT_CONTEXT sortContext;\n\n    if (SortColumn < Manager->MinId)\n        return FALSE;\n\n    if (!Manager->Handle)\n        return TRUE;\n\n    if (!TreeNew_GetColumn(Manager->Handle, SortColumn, &tnColumn))\n        return TRUE;\n\n    column = tnColumn.Context;\n\n    if (!column->SortFunction)\n        return TRUE;\n\n    sortContext.SortFunction = column->SortFunction;\n    sortContext.SubId = column->SubId;\n    sortContext.Context = column->Context;\n    sortContext.PostSortFunction = Manager->PostSortFunction;\n    sortContext.SortOrder = SortOrder;\n    qsort_s(Nodes, NumberOfNodes, sizeof(PVOID), PhCmpSortFunction, &sortContext);\n\n    return TRUE;\n}\n\nBOOLEAN PhCmLoadSettings(\n    _In_ HWND TreeNewHandle,\n    _In_ PCPH_STRINGREF Settings\n    )\n{\n    return PhCmLoadSettingsEx(TreeNewHandle, NULL, 0, Settings, NULL);\n}\n\nBOOLEAN PhCmLoadSettingsEx(\n    _In_ HWND TreeNewHandle,\n    _In_opt_ PPH_CM_MANAGER Manager,\n    _In_ ULONG Flags,\n    _In_ PCPH_STRINGREF Settings,\n    _In_opt_ PCPH_STRINGREF SortSettings\n    )\n{\n    BOOLEAN result = FALSE;\n    PH_STRINGREF scalePart;\n    PH_STRINGREF columnPart;\n    PH_STRINGREF remainingColumnPart;\n    PH_STRINGREF valuePart;\n    PH_STRINGREF subPart;\n    ULONG64 integer;\n    ULONG scale;\n    ULONG total;\n    BOOLEAN hasFixedColumn;\n    ULONG count;\n    ULONG i;\n    PPH_HASHTABLE columnHashtable;\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_KEY_VALUE_PAIR pair;\n    ULONG orderArray[PH_CM_ORDER_LIMIT];\n    ULONG maxOrder;\n    LONG dpiValue;\n\n    dpiValue = PhGetWindowDpi(TreeNewHandle);\n\n    if (Settings->Length != 0)\n    {\n        columnHashtable = PhCreateSimpleHashtable(20);\n\n        remainingColumnPart = *Settings;\n\n        if (remainingColumnPart.Length != 0 && remainingColumnPart.Buffer[0] == L'@')\n        {\n            PhSkipStringRef(&remainingColumnPart, sizeof(WCHAR));\n            PhSplitStringRefAtChar(&remainingColumnPart, L'|', &scalePart, &remainingColumnPart);\n\n            if (scalePart.Length == 0 || !PhStringToUInt64(&scalePart, 10, &integer))\n                goto CleanupExit;\n\n            scale = (ULONG)integer;\n        }\n        else\n        {\n            scale = USER_DEFAULT_SCREEN_DPI;\n        }\n\n        while (remainingColumnPart.Length != 0)\n        {\n            PPH_TREENEW_COLUMN column;\n            ULONG id;\n            ULONG displayIndex;\n            LONG width;\n\n            PhSplitStringRefAtChar(&remainingColumnPart, L'|', &columnPart, &remainingColumnPart);\n\n            if (columnPart.Length != 0)\n            {\n                // Id\n\n                PhSplitStringRefAtChar(&columnPart, L',', &valuePart, &columnPart);\n\n                if (valuePart.Length == 0)\n                    goto CleanupExit;\n\n                if (valuePart.Buffer[0] == L'+')\n                {\n                    PH_STRINGREF pluginName;\n                    ULONG subId;\n                    PPH_CM_COLUMN cmColumn;\n\n                    // This is a plugin-owned column.\n\n                    if (!Manager)\n                        continue;\n                    if (!PhEmParseCompoundId(&valuePart, &pluginName, &subId))\n                        continue;\n\n                    cmColumn = PhCmFindColumn(Manager, &pluginName, subId);\n\n                    if (!cmColumn)\n                        continue; // can't find the column, skip this part\n\n                    id = cmColumn->Id;\n                }\n                else\n                {\n                    if (!PhStringToUInt64(&valuePart, 10, &integer))\n                        goto CleanupExit;\n\n                    id = (ULONG)integer;\n                }\n\n                // Display Index\n\n                PhSplitStringRefAtChar(&columnPart, L',', &valuePart, &columnPart);\n\n                if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))\n                {\n                    if (valuePart.Length == 0 || !PhStringToUInt64(&valuePart, 10, &integer))\n                        goto CleanupExit;\n\n                    displayIndex = (ULONG)integer;\n                }\n                else\n                {\n                    if (valuePart.Length != 0)\n                        goto CleanupExit;\n\n                    displayIndex = ULONG_MAX;\n                }\n\n                // Width\n\n                if (columnPart.Length == 0 || !PhStringToUInt64(&columnPart, 10, &integer))\n                    goto CleanupExit;\n\n                width = (LONG)integer;\n\n                if (scale != dpiValue && scale != 0)\n                    width = PhMultiplyDivideSigned(width, dpiValue, scale);\n\n                column = PhAllocateZero(sizeof(PH_TREENEW_COLUMN));\n                column->Id = id;\n                column->DisplayIndex = displayIndex;\n                column->Width = width;\n                PhAddItemSimpleHashtable(columnHashtable, UlongToPtr(column->Id), column);\n            }\n        }\n\n        TreeNew_SetRedraw(TreeNewHandle, FALSE);\n\n        // Set visibility and width.\n\n        i = 0;\n        count = 0;\n        total = TreeNew_GetColumnCount(TreeNewHandle);\n        hasFixedColumn = !!TreeNew_GetFixedColumn(TreeNewHandle);\n        memset(orderArray, 0, sizeof(orderArray));\n        maxOrder = 0;\n\n        while (count < total)\n        {\n            PH_TREENEW_COLUMN setColumn;\n            PPH_TREENEW_COLUMN *columnPtr;\n\n            if (TreeNew_GetColumn(TreeNewHandle, i, &setColumn))\n            {\n                columnPtr = (PPH_TREENEW_COLUMN *)PhFindItemSimpleHashtable(columnHashtable, UlongToPtr(i));\n\n                if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))\n                {\n                    if (columnPtr)\n                    {\n                        setColumn.Visible = TRUE;\n                        setColumn.Width = (*columnPtr)->Width;\n                        TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE | TN_COLUMN_WIDTH, &setColumn);\n\n                        if (!setColumn.Fixed)\n                        {\n                            // For compatibility reasons, normal columns have their display indices stored\n                            // one higher than usual (so they start from 1, not 0). Fix that here.\n                            if (hasFixedColumn && (*columnPtr)->DisplayIndex != 0)\n                                (*columnPtr)->DisplayIndex--;\n\n                            if ((*columnPtr)->DisplayIndex < PH_CM_ORDER_LIMIT)\n                            {\n                                orderArray[(*columnPtr)->DisplayIndex] = i;\n\n                                if (maxOrder < (*columnPtr)->DisplayIndex + 1)\n                                    maxOrder = (*columnPtr)->DisplayIndex + 1;\n                            }\n                        }\n                    }\n                    else if (!setColumn.Fixed) // never hide the fixed column\n                    {\n                        setColumn.Visible = FALSE;\n                        TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &setColumn);\n                    }\n                }\n                else\n                {\n                    if (columnPtr)\n                    {\n                        setColumn.Width = (*columnPtr)->Width;\n                        TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_WIDTH, &setColumn);\n                    }\n                }\n\n                count++;\n            }\n\n            i++;\n        }\n\n        if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))\n        {\n            // Set the order array.\n            TreeNew_SetColumnOrderArray(TreeNewHandle, maxOrder, orderArray);\n        }\n\n        TreeNew_SetRedraw(TreeNewHandle, TRUE);\n\n        result = TRUE;\n\nCleanupExit:\n        PhBeginEnumHashtable(columnHashtable, &enumContext);\n\n        while (pair = PhNextEnumHashtable(&enumContext))\n            PhFree(pair->Value);\n\n        PhDereferenceObject(columnHashtable);\n    }\n\n    // Load sort settings.\n\n    if (SortSettings && SortSettings->Length != 0)\n    {\n        PhSplitStringRefAtChar(SortSettings, L',', &valuePart, &subPart);\n\n        if (valuePart.Length != 0 && subPart.Length != 0)\n        {\n            ULONG sortColumn;\n            PH_SORT_ORDER sortOrder;\n\n            sortColumn = ULONG_MAX;\n\n            if (valuePart.Buffer[0] == L'+')\n            {\n                PH_STRINGREF pluginName;\n                ULONG subId;\n                PPH_CM_COLUMN cmColumn;\n\n                if (\n                    Manager &&\n                    PhEmParseCompoundId(&valuePart, &pluginName, &subId) &&\n                    (cmColumn = PhCmFindColumn(Manager, &pluginName, subId))\n                    )\n                {\n                    sortColumn = cmColumn->Id;\n                }\n            }\n            else\n            {\n                PhStringToUInt64(&valuePart, 10, &integer);\n                sortColumn = (ULONG)integer;\n            }\n\n            PhStringToUInt64(&subPart, 10, &integer);\n            sortOrder = (PH_SORT_ORDER)integer;\n\n            if (sortColumn != ULONG_MAX && sortOrder <= DescendingSortOrder)\n            {\n                TreeNew_SetSort(TreeNewHandle, sortColumn, sortOrder);\n            }\n        }\n    }\n\n    return result;\n}\n\nPPH_STRING PhCmSaveSettings(\n    _In_ HWND TreeNewHandle\n    )\n{\n    return PhCmSaveSettingsEx(TreeNewHandle, NULL, 0, NULL);\n}\n\nPPH_STRING PhCmSaveSettingsEx(\n    _In_ HWND TreeNewHandle,\n    _In_opt_ PPH_CM_MANAGER Manager,\n    _In_ ULONG Flags,\n    _Out_opt_ PPH_STRING *SortSettings\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    ULONG i = 0;\n    ULONG count = 0;\n    ULONG total;\n    ULONG increment;\n    PH_TREENEW_COLUMN column;\n    LONG dpiValue;\n\n    dpiValue = PhGetWindowDpi(TreeNewHandle);\n\n    total = TreeNew_GetColumnCount(TreeNewHandle);\n\n    if (TreeNew_GetFixedColumn(TreeNewHandle))\n        increment = 1; // the first normal column should have a display index that starts with 1, for compatibility\n    else\n        increment = 0;\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n\n    {\n        PH_FORMAT format[3];\n        SIZE_T returnLength;\n        WCHAR buffer[PH_INT64_STR_LEN_1];\n\n        // @%lu|\n        PhInitFormatC(&format[0], L'@');\n        PhInitFormatU(&format[1], dpiValue);\n        PhInitFormatC(&format[2], L'|');\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n        {\n            PhAppendStringBuilderEx(&stringBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n        }\n        else\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"@%lu|\", dpiValue);\n        }\n    }\n\n    while (count < total)\n    {\n        if (TreeNew_GetColumn(TreeNewHandle, i, &column))\n        {\n            if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))\n            {\n                if (column.Visible)\n                {\n                    if (!Manager || i < Manager->MinId)\n                    {\n                        PH_FORMAT format[6];\n                        SIZE_T returnLength;\n                        WCHAR buffer[PH_INT64_STR_LEN_1];\n\n                        // %lu,%lu,%ld|\n                        PhInitFormatU(&format[0], i);\n                        PhInitFormatC(&format[1], L',');\n                        PhInitFormatU(&format[2], column.Fixed ? 0 : column.DisplayIndex + increment);\n                        PhInitFormatC(&format[3], L',');\n                        PhInitFormatU(&format[4], column.Width);\n                        PhInitFormatC(&format[5], L'|');\n\n                        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n                        {\n                            PhAppendStringBuilderEx(&stringBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n                        }\n                        else\n                        {\n                            PhAppendFormatStringBuilder(\n                                &stringBuilder,\n                                L\"%lu,%lu,%ld|\",\n                                i,\n                                column.Fixed ? 0 : column.DisplayIndex + increment,\n                                column.Width\n                                );\n                        }\n                    }\n                    else\n                    {\n                        PPH_CM_COLUMN cmColumn = column.Context;\n                        PH_FORMAT format[9];\n                        SIZE_T returnLength;\n                        WCHAR buffer[PH_INT64_STR_LEN_1];\n\n                        // +%s+%lu,%lu,%ld|\n                        PhInitFormatC(&format[0], L'+');\n                        PhInitFormatSR(&format[1], cmColumn->Plugin->Name);\n                        PhInitFormatC(&format[2], L'+');\n                        PhInitFormatU(&format[3], cmColumn->SubId);\n                        PhInitFormatC(&format[4], L',');\n                        PhInitFormatU(&format[5], column.DisplayIndex + increment);\n                        PhInitFormatC(&format[6], L',');\n                        PhInitFormatD(&format[7], column.Width);\n                        PhInitFormatC(&format[8], L'|');\n\n                        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n                        {\n                            PhAppendStringBuilderEx(&stringBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n                        }\n                        else\n                        {\n                            PhAppendFormatStringBuilder(\n                                &stringBuilder,\n                                L\"+%s+%lu,%lu,%ld|\",\n                                cmColumn->Plugin->Name.Buffer,\n                                cmColumn->SubId,\n                                column.DisplayIndex + increment,\n                                column.Width\n                                );\n                        }\n                    }\n                }\n            }\n            else\n            {\n                if (!Manager || i < Manager->MinId)\n                {\n                    PhAppendFormatStringBuilder(\n                        &stringBuilder,\n                        L\"%lu,,%ld|\",\n                        i,\n                        column.Width\n                        );\n                }\n                else\n                {\n                    PPH_CM_COLUMN cmColumn;\n\n                    cmColumn = column.Context;\n                    PhAppendFormatStringBuilder(\n                        &stringBuilder,\n                        L\"+%s+%lu,,%ld|\",\n                        cmColumn->Plugin->Name.Buffer,\n                        cmColumn->SubId,\n                        column.Width\n                        );\n                }\n            }\n\n            count++;\n        }\n\n        i++;\n    }\n\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    if (SortSettings)\n    {\n        ULONG sortColumn;\n        PH_SORT_ORDER sortOrder;\n\n        if (TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder))\n        {\n            if (sortOrder != NoSortOrder)\n            {\n                if (!Manager || sortColumn < Manager->MinId)\n                {\n                    PH_FORMAT format[3];\n\n                    // %lu,%lu\n                    PhInitFormatU(&format[0], sortColumn);\n                    PhInitFormatC(&format[1], L',');\n                    PhInitFormatU(&format[2], sortOrder);\n\n                    *SortSettings = PhFormat(format, RTL_NUMBER_OF(format), 32);\n                }\n                else\n                {\n                    if (TreeNew_GetColumn(TreeNewHandle, sortColumn, &column))\n                    {\n                        PPH_CM_COLUMN cmColumn;\n                        PH_FORMAT format[6];\n\n                        cmColumn = column.Context;\n\n                        // +%s+%lu,%lu\n                        PhInitFormatC(&format[0], L'+');\n                        PhInitFormatSR(&format[1], cmColumn->Plugin->Name);\n                        PhInitFormatC(&format[2], L'+');\n                        PhInitFormatU(&format[3], cmColumn->SubId);\n                        PhInitFormatC(&format[4], L',');\n                        PhInitFormatU(&format[5], sortOrder);\n\n                        *SortSettings = PhFormat(format, RTL_NUMBER_OF(format), 64);\n                    }\n                    else\n                    {\n                        *SortSettings = PhReferenceEmptyString();\n                    }\n                }\n            }\n            else\n            {\n                *SortSettings = PhCreateString(L\"0,0\");\n            }\n        }\n        else\n        {\n            *SortSettings = PhReferenceEmptyString();\n        }\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n"
  },
  {
    "path": "SystemInformer/colsetmgr.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017-2022\n *\n */\n\n#include <phapp.h>\n#include <colsetmgr.h>\n#include <settings.h>\n\nPPH_LIST PhInitializeColumnSetList(\n    _In_ PCWSTR SettingName\n    )\n{\n    PPH_LIST columnSetList;\n    PPH_STRING settingsString;\n    ULONG64 count;\n    ULONG64 index;\n    PH_STRINGREF remaining;\n    PH_STRINGREF part;\n\n    columnSetList = PhCreateList(10);\n    settingsString = PhaGetStringSetting(SettingName);\n    remaining = settingsString->sr;\n\n    if (remaining.Length == 0)\n        goto CleanupExit;\n    if (!PhSplitStringRefAtChar(&remaining, L'-', &part, &remaining))\n        goto CleanupExit;\n    if (!PhStringToInteger64(&part, 10, &count))\n        goto CleanupExit;\n\n    for (index = 0; index < count; index++)\n    {\n        PH_STRINGREF columnSetNamePart;\n        PH_STRINGREF columnSetSettingPart;\n        PH_STRINGREF columnSetSortPart;\n\n        if (remaining.Length == 0)\n            break;\n\n        PhSplitStringRefAtChar(&remaining, L'-', &columnSetNamePart, &remaining);\n        PhSplitStringRefAtChar(&remaining, L'-', &columnSetSettingPart, &remaining);\n        PhSplitStringRefAtChar(&remaining, L'-', &columnSetSortPart, &remaining);\n\n        {\n            PPH_COLUMN_SET_ENTRY entry;\n\n            entry = PhAllocate(sizeof(PH_COLUMN_SET_ENTRY));\n            entry->Name = PhCreateString2(&columnSetNamePart);\n            entry->Setting = PhCreateString2(&columnSetSettingPart);\n            entry->Sorting = PhCreateString2(&columnSetSortPart);\n\n            PhAddItemList(columnSetList, entry);\n        }\n    }\n\nCleanupExit:\n    return columnSetList;\n}\n\nVOID PhSaveSettingsColumnList(\n    _In_ PCWSTR SettingName,\n    _In_ PPH_LIST ColumnSetList\n    )\n{\n    ULONG index;\n    PPH_STRING settingsString;\n    PH_STRING_BUILDER stringBuilder;\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n    PhAppendFormatStringBuilder(\n        &stringBuilder,\n        L\"%lu-\",\n        ColumnSetList->Count\n        );\n\n    for (index = 0; index < ColumnSetList->Count; index++)\n    {\n        PPH_COLUMN_SET_ENTRY entry = ColumnSetList->Items[index];\n\n        if (PhIsNullOrEmptyString(entry->Name))\n            continue;\n\n        PhAppendFormatStringBuilder(\n            &stringBuilder,\n            L\"%s-%s-%s-\",\n            PhGetStringOrEmpty(entry->Name),\n            PhGetStringOrEmpty(entry->Setting),\n            PhGetStringOrEmpty(entry->Sorting)\n            );\n    }\n\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder));\n    PhSetStringSetting2(SettingName, &settingsString->sr);\n}\n\nVOID PhDeleteColumnSetList(\n    _In_ PPH_LIST ColumnSetList\n    )\n{\n    for (ULONG i = 0; i < ColumnSetList->Count; i++)\n    {\n        PPH_COLUMN_SET_ENTRY entry = ColumnSetList->Items[i];\n\n        //PhRemoveItemList(ColumnSetList, PhFindItemList(ColumnSetList, entry));\n\n        PhClearReference(&entry->Name);\n        PhClearReference(&entry->Setting);\n        PhClearReference(&entry->Sorting);\n\n        PhFree(entry);\n    }\n\n    PhDereferenceObject(ColumnSetList);\n}\n\n_Success_(return)\nBOOLEAN PhLoadSettingsColumnSet(\n    _In_ PCWSTR SettingName,\n    _In_ PPH_STRING ColumnSetName,\n    _Out_ PPH_STRING *TreeListSettings,\n    _Out_ PPH_STRING *TreeSortSettings\n    )\n{\n    PPH_STRING treeSettings = NULL;\n    PPH_STRING sortSettings = NULL;\n    PPH_STRING settingsString;\n    ULONG64 count;\n    ULONG64 index;\n    PH_STRINGREF remaining;\n    PH_STRINGREF part;\n\n    settingsString = PhaGetStringSetting(SettingName);\n    remaining = settingsString->sr;\n\n    if (remaining.Length == 0)\n        return FALSE;\n\n    if (!PhSplitStringRefAtChar(&remaining, L'-', &part, &remaining))\n        return FALSE;\n    if (!PhStringToInteger64(&part, 10, &count))\n        return FALSE;\n\n    for (index = 0; index < count; index++)\n    {\n        PH_STRINGREF columnSetNamePart;\n        PH_STRINGREF columnSetSettingPart;\n        PH_STRINGREF columnSetSortPart;\n\n        if (remaining.Length == 0)\n            break;\n\n        PhSplitStringRefAtChar(&remaining, L'-', &columnSetNamePart, &remaining);\n        PhSplitStringRefAtChar(&remaining, L'-', &columnSetSettingPart, &remaining);\n        PhSplitStringRefAtChar(&remaining, L'-', &columnSetSortPart, &remaining);\n\n        if (PhEqualStringRef(&columnSetNamePart, &ColumnSetName->sr, FALSE))\n        {\n            treeSettings = PhCreateString2(&columnSetSettingPart);\n            sortSettings = PhCreateString2(&columnSetSortPart);\n            break;\n        }\n    }\n\n    if (!PhIsNullOrEmptyString(treeSettings) && !PhIsNullOrEmptyString(sortSettings))\n    {\n        *TreeListSettings = treeSettings;\n        *TreeSortSettings = sortSettings;\n        return TRUE;\n    }\n    else\n    {\n        if (treeSettings)\n            PhDereferenceObject(treeSettings);\n        if (sortSettings)\n            PhDereferenceObject(sortSettings);\n        return FALSE;\n    }\n}\n\nVOID PhSaveSettingsColumnSet(\n    _In_ PCWSTR SettingName,\n    _In_ PPH_STRING ColumnSetName,\n    _In_ PPH_STRING TreeListSettings,\n    _In_ PPH_STRING TreeSortSettings\n    )\n{\n    ULONG index;\n    BOOLEAN found = FALSE;\n    PPH_LIST columnSetList;\n\n    columnSetList = PhInitializeColumnSetList(SettingName);\n\n    for (index = 0; index < columnSetList->Count; index++)\n    {\n        PPH_COLUMN_SET_ENTRY entry = columnSetList->Items[index];\n\n        if (PhEqualString(entry->Name, ColumnSetName, FALSE))\n        {\n            PhReferenceObject(TreeListSettings);\n            PhReferenceObject(TreeSortSettings);\n\n            PhMoveReference(&entry->Setting, TreeListSettings);\n            PhMoveReference(&entry->Sorting, TreeSortSettings);\n\n            found = TRUE;\n            break;\n        }\n    }\n\n    if (!found)\n    {\n        PPH_COLUMN_SET_ENTRY entry;\n\n        PhReferenceObject(ColumnSetName);\n        PhReferenceObject(TreeListSettings);\n        PhReferenceObject(TreeSortSettings);\n\n        entry = PhAllocate(sizeof(PH_COLUMN_SET_ENTRY));\n        entry->Name = ColumnSetName;\n        entry->Setting = TreeListSettings;\n        entry->Sorting = TreeSortSettings;\n\n        PhAddItemList(columnSetList, entry);\n    }\n\n    PhSaveSettingsColumnList(SettingName, columnSetList);\n\n    PhDeleteColumnSetList(columnSetList);\n}\n\n// Column Set Editor Dialog\n\ntypedef struct _PH_COLUMNSET_DIALOG_CONTEXT\n{\n    HWND DialogHandle;\n    HWND ListViewHandle;\n    HWND RenameButtonHandle;\n    HWND MoveUpButtonHandle;\n    HWND MoveDownButtonHandle;\n    HWND RemoveButtonHandle;\n    PPH_STRING SettingName;\n    PPH_LIST ColumnSetList;\n    BOOLEAN LabelEditActive;\n} PH_COLUMNSET_DIALOG_CONTEXT, *PPH_COLUMNSET_DIALOG_CONTEXT;\n\nINT_PTR CALLBACK PhpColumnSetEditorDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowColumnSetEditorDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR SettingName\n    )\n{\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_COLUMNSETS),\n        ParentWindowHandle,\n        PhpColumnSetEditorDlgProc,\n        (PVOID)SettingName\n        );\n}\n\nVOID PhpMoveListViewItem(\n    _In_ HWND ListViewHandle,\n    _In_ LONG ItemIndex1,\n    _In_ LONG ItemIndex2\n    )\n{\n    LVITEM item1;\n    LVITEM item2;\n    WCHAR buffer1[MAX_PATH];\n    WCHAR buffer2[MAX_PATH];\n\n    item1.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;\n    item1.stateMask = (UINT)-1;\n    item1.iItem = ItemIndex1;\n    item1.iSubItem = 0;\n    item1.cchTextMax = sizeof(buffer1);\n    item1.pszText = buffer1;\n\n    item2.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;\n    item2.stateMask = (UINT)-1;\n    item2.iItem = ItemIndex2;\n    item2.iSubItem = 0;\n    item2.cchTextMax = sizeof(buffer2);\n    item2.pszText = buffer2;\n\n    if (\n        ListView_GetItem(ListViewHandle, &item1) &&\n        ListView_GetItem(ListViewHandle, &item2)\n        )\n    {\n        item1.iItem = ItemIndex2;\n        item2.iItem = ItemIndex1;\n\n        ListView_SetItem(ListViewHandle, &item1);\n        ListView_SetItem(ListViewHandle, &item2);\n    }\n}\n\nVOID PhpMoveSelectedListViewItemUp(\n    _In_ HWND ListViewHandle\n    )\n{\n    LONG lvItemIndex = PhFindListViewItemByFlags(ListViewHandle, INT_ERROR, LVNI_SELECTED);\n\n    if (lvItemIndex != INT_ERROR)\n    {\n        PhpMoveListViewItem(ListViewHandle, lvItemIndex, lvItemIndex - 1);\n    }\n\n    SetFocus(ListViewHandle);\n    ListView_SetItemState(ListViewHandle, lvItemIndex - 1, LVNI_SELECTED, LVNI_SELECTED);\n    //ListView_EnsureVisible(ListViewHandle, lvItemIndex - 1, FALSE);\n}\n\nVOID PhpMoveSelectedListViewItemDown(\n    _In_ HWND ListViewHandle\n    )\n{\n    LONG lvItemIndex = PhFindListViewItemByFlags(ListViewHandle, INT_ERROR, LVNI_SELECTED);\n\n    if (lvItemIndex != INT_ERROR)\n    {\n        PhpMoveListViewItem(ListViewHandle, lvItemIndex, lvItemIndex + 1);\n    }\n\n    SetFocus(ListViewHandle);\n    ListView_SetItemState(ListViewHandle, lvItemIndex + 1, LVNI_SELECTED, LVNI_SELECTED);\n    //ListView_EnsureVisible(ListViewHandle, lvItemIndex + 1, FALSE);\n}\n\nINT_PTR CALLBACK PhpColumnSetEditorDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_COLUMNSET_DIALOG_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocateZero(sizeof(PH_COLUMNSET_DIALOG_CONTEXT));\n        context->SettingName = PhCreateString((PCWSTR)lParam);\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->DialogHandle = hwndDlg;\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_COLUMNSETLIST);\n            context->RenameButtonHandle = GetDlgItem(hwndDlg, IDC_RENAME);\n            context->MoveUpButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEUP);\n            context->MoveDownButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN);\n            context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE);\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L\"Name\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            context->ColumnSetList = PhInitializeColumnSetList(PhGetString(context->SettingName));\n\n            for (ULONG i = 0; i <  context->ColumnSetList->Count; i++)\n            {\n                PPH_COLUMN_SET_ENTRY entry = context->ColumnSetList->Items[i];\n\n                PhAddListViewItem(context->ListViewHandle, MAXINT, entry->Name->Buffer, entry);\n            }\n\n            Button_Enable(context->RenameButtonHandle, FALSE);\n            Button_Enable(context->MoveUpButtonHandle, FALSE);\n            Button_Enable(context->MoveDownButtonHandle, FALSE);\n            Button_Enable(context->RemoveButtonHandle, FALSE);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDeleteColumnSetList(context->ColumnSetList);\n\n            PhFree(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    if (context->LabelEditActive)\n                        break;\n\n                    PhSaveSettingsColumnList(PhGetString(context->SettingName), context->ColumnSetList);\n\n                    EndDialog(hwndDlg, IDOK);\n                }\n                break;\n            case IDC_RENAME:\n                {\n                    LONG lvItemIndex = PhFindListViewItemByFlags(context->ListViewHandle, INT_ERROR, LVNI_SELECTED);\n\n                    if (lvItemIndex != INT_ERROR)\n                    {\n                        SetFocus(context->ListViewHandle);\n                        ListView_EditLabel(context->ListViewHandle, lvItemIndex);\n                    }\n                }\n                break;\n            case IDC_MOVEUP:\n                {\n                    LONG lvItemIndex;\n                    PPH_COLUMN_SET_ENTRY entry;\n                    ULONG index;\n\n                    PhpMoveSelectedListViewItemUp(context->ListViewHandle);\n\n                    lvItemIndex = PhFindListViewItemByFlags(context->ListViewHandle, INT_ERROR, LVNI_SELECTED);\n\n                    if (lvItemIndex != INT_ERROR && PhGetListViewItemParam(context->ListViewHandle, lvItemIndex, (PVOID *)&entry))\n                    {\n                        index = PhFindItemList(context->ColumnSetList, entry);\n\n                        if (index != ULONG_MAX)\n                        {\n                            PhRemoveItemList(context->ColumnSetList, index);\n                            PhInsertItemList(context->ColumnSetList, lvItemIndex, entry);\n                        }\n                    }\n                }\n                break;\n            case IDC_MOVEDOWN:\n                {\n                    LONG lvItemIndex;\n                    PPH_COLUMN_SET_ENTRY entry;\n                    ULONG index;\n\n                    PhpMoveSelectedListViewItemDown(context->ListViewHandle);\n\n                    lvItemIndex = PhFindListViewItemByFlags(context->ListViewHandle, INT_ERROR, LVNI_SELECTED);\n\n                    if (lvItemIndex != INT_ERROR && PhGetListViewItemParam(context->ListViewHandle, lvItemIndex, (PVOID *)&entry))\n                    {\n                        index = PhFindItemList(context->ColumnSetList, entry);\n\n                        if (index != ULONG_MAX)\n                        {\n                            PhRemoveItemList(context->ColumnSetList, index);\n                            PhInsertItemList(context->ColumnSetList, lvItemIndex, entry);\n                        }\n                    }\n                }\n                break;\n            case IDC_REMOVE:\n                {\n                    LONG lvItemIndex;\n                    PPH_COLUMN_SET_ENTRY entry;\n                    ULONG index;\n\n                    lvItemIndex = PhFindListViewItemByFlags(context->ListViewHandle, INT_ERROR, LVNI_SELECTED);\n\n                    if (lvItemIndex != INT_ERROR && PhGetListViewItemParam(context->ListViewHandle, lvItemIndex, (PVOID *)&entry))\n                    {\n                        index = PhFindItemList(context->ColumnSetList, entry);\n\n                        if (index != ULONG_MAX)\n                        {\n                            PhRemoveItemList(context->ColumnSetList, index);\n                            PhRemoveListViewItem(context->ListViewHandle, lvItemIndex);\n\n                            PhClearReference(&entry->Name);\n                            PhClearReference(&entry->Setting);\n                            PhClearReference(&entry->Sorting);\n                            PhFree(entry);\n                        }\n\n                        SetFocus(context->ListViewHandle);\n                        ListView_SetItemState(context->ListViewHandle, 0, LVNI_SELECTED, LVNI_SELECTED);\n                        //ListView_EnsureVisible(context->ListViewHandle, 0, FALSE);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case NM_DBLCLK:\n                {\n                    LONG lvItemIndex = PhFindListViewItemByFlags(context->ListViewHandle, INT_ERROR, LVNI_SELECTED);\n\n                    if (lvItemIndex != INT_ERROR)\n                    {\n                        SetFocus(context->ListViewHandle);\n                        ListView_EditLabel(context->ListViewHandle, lvItemIndex);\n                    }\n                }\n                break;\n            case LVN_ITEMCHANGED:\n                {\n                    LPNMLISTVIEW listview = (LPNMLISTVIEW)lParam;\n                    LONG index;\n                    LONG lvItemIndex;\n                    LONG count;\n\n                    index = listview->iItem;\n                    lvItemIndex = PhFindListViewItemByFlags(context->ListViewHandle, INT_ERROR, LVNI_SELECTED);\n                    count = ListView_GetItemCount(context->ListViewHandle);\n\n                    if (count == 0 || index == -1 || lvItemIndex == -1)\n                    {\n                        Button_Enable(context->RenameButtonHandle, FALSE);\n                        Button_Enable(context->MoveUpButtonHandle, FALSE);\n                        Button_Enable(context->MoveDownButtonHandle, FALSE);\n                        Button_Enable(context->RemoveButtonHandle, FALSE);\n                        break;\n                    }\n\n                    if (index != lvItemIndex)\n                        break;\n\n                    if (index == 0 && count == 1)\n                    {\n                        // First and last item\n                        Button_Enable(context->MoveUpButtonHandle, FALSE);\n                        Button_Enable(context->MoveDownButtonHandle, FALSE);\n                    }\n                    else if (index == (count - 1))\n                    {\n                        // Last item\n                        Button_Enable(context->MoveUpButtonHandle, TRUE);\n                        Button_Enable(context->MoveDownButtonHandle, FALSE);\n                    }\n                    else if (index == 0)\n                    {\n                        // First item\n                        Button_Enable(context->MoveUpButtonHandle, FALSE);\n                        Button_Enable(context->MoveDownButtonHandle, TRUE);\n                    }\n                    else\n                    {\n                        Button_Enable(context->MoveUpButtonHandle, TRUE);\n                        Button_Enable(context->MoveDownButtonHandle, TRUE);\n                    }\n\n                    Button_Enable(context->RenameButtonHandle, TRUE);\n                    Button_Enable(context->RemoveButtonHandle, TRUE);\n                }\n                break;\n            case LVN_BEGINLABELEDIT:\n                context->LabelEditActive = TRUE;\n                break;\n            case LVN_ENDLABELEDIT:\n                {\n                    LV_DISPINFO* lvinfo = (LV_DISPINFO*)lParam;\n\n                    if (lvinfo->item.iItem != -1 && lvinfo->item.pszText)\n                    {\n                        BOOLEAN found = FALSE;\n                        PPH_COLUMN_SET_ENTRY entry;\n                        ULONG index;\n\n                        for (ULONG i = 0; i < context->ColumnSetList->Count; i++)\n                        {\n                            entry = context->ColumnSetList->Items[i];\n\n                            if (PhEqualStringRef2(&entry->Name->sr, lvinfo->item.pszText, FALSE))\n                            {\n                                found = TRUE;\n                                break;\n                            }\n                        }\n\n                        if (!found && PhGetListViewItemParam(context->ListViewHandle, lvinfo->item.iItem, (PVOID *)&entry))\n                        {\n                            index = PhFindItemList(context->ColumnSetList, entry);\n\n                            if (index != -1)\n                            {\n                                PhMoveReference(&entry->Name, PhCreateString(lvinfo->item.pszText));\n                                ListView_SetItemText(context->ListViewHandle, lvinfo->item.iItem, 0, lvinfo->item.pszText);\n                            }\n                        }\n                    }\n\n                    context->LabelEditActive = FALSE;\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/dbgcon.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *\n */\n\n/*\n * This is a simple debugging console which is able to explore phlib's\n * systems easily. Commands are provided to debug reference counting\n * problems and memory usage, as well as to do general performance testing.\n */\n\n#include <phapp.h>\n\n#include <phintrnl.h>\n#include <refp.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <symprv.h>\n#include <mapldr.h>\n#include <workqueue.h>\n#include <workqueuep.h>\n#include <phconsole.h>\n\n#include <procprv.h>\n#include <srvprv.h>\n#include <thrdprv.h>\n\ntypedef struct _STRING_TABLE_ENTRY\n{\n    PPH_STRING String;\n    ULONG_PTR Count;\n} STRING_TABLE_ENTRY, *PSTRING_TABLE_ENTRY;\n\nBOOL ConsoleHandlerRoutine(\n    _In_ ULONG dwCtrlType\n    );\n\nVOID PhpPrintHashtableStatistics(\n    _In_ PPH_HASHTABLE Hashtable\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpDebugConsoleThreadStart(\n    _In_ PVOID Parameter\n    );\n\nextern PH_FREE_LIST PhObjectSmallFreeList;\n\nstatic HANDLE DebugConsoleThreadHandle;\nstatic PPH_SYMBOL_PROVIDER DebugConsoleSymbolProvider;\n\nstatic PPH_HASHTABLE ObjectListSnapshot = NULL;\n#ifdef DEBUG\nstatic PPH_LIST NewObjectList = NULL;\nstatic PH_QUEUED_LOCK NewObjectListLock;\n#endif\n\nstatic BOOLEAN ShowAllLeaks = FALSE;\nstatic BOOLEAN InLeakDetection = FALSE;\nstatic ULONG NumberOfLeaks;\nstatic ULONG NumberOfLeaksShown;\n\nVOID PhShowDebugConsole(\n    VOID\n    )\n{\n    if (AllocConsole())\n    {\n        HMENU menu;\n\n        // Disable the close button because it's impossible to handle\n        // those events.\n        menu = GetSystemMenu(GetConsoleWindow(), FALSE);\n        EnableMenuItem(menu, SC_CLOSE, MF_GRAYED | MF_DISABLED);\n        DeleteMenu(menu, SC_CLOSE, 0);\n\n        // Set a handler so we can catch Ctrl+C and Ctrl+Break.\n        SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE);\n\n        _wfreopen(L\"CONOUT$\", L\"w\", stdout);\n        _wfreopen(L\"CONOUT$\", L\"w\", stderr);\n        _wfreopen(L\"CONIN$\", L\"r\", stdin);\n\n        SetConsoleCP(CP_UTF8);\n        SetConsoleOutputCP(CP_UTF8);\n\n        PhCreateThreadEx(&DebugConsoleThreadHandle, PhpDebugConsoleThreadStart, NULL);\n    }\n    else\n    {\n        HWND consoleWindow;\n\n        consoleWindow = GetConsoleWindow();\n\n        // Console window already exists, so bring it to the top.\n        if (IsMinimized(consoleWindow))\n            ShowWindow(consoleWindow, SW_RESTORE);\n        else\n            BringWindowToTop(consoleWindow);\n\n        return;\n    }\n}\n\nVOID PhCloseDebugConsole(\n    VOID\n    )\n{\n    _wfreopen(L\"NUL\", L\"w\", stdout);\n    _wfreopen(L\"NUL\", L\"w\", stderr);\n    _wfreopen(L\"NUL\", L\"r\", stdin);\n\n    PhFreeConsole();\n}\n\nBOOL ConsoleHandlerRoutine(\n    _In_ ULONG dwCtrlType\n    )\n{\n    switch (dwCtrlType)\n    {\n    case CTRL_C_EVENT:\n    case CTRL_BREAK_EVENT:\n    case CTRL_CLOSE_EVENT:\n        PhCloseDebugConsole();\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nstatic PWSTR PhpGetSymbolForAddress(\n    _In_ PVOID Address\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhGetSymbolFromAddress(\n        DebugConsoleSymbolProvider, Address, NULL, NULL, NULL, NULL\n        ))->Buffer;\n}\n\nstatic VOID PhpPrintObjectInfo(\n    _In_ PPH_OBJECT_HEADER ObjectHeader,\n    _In_ LONG RefToSubtract\n    )\n{\n    PVOID object;\n    PPH_OBJECT_TYPE objectType;\n    WCHAR c = L' ';\n\n    object = PhObjectHeaderToObject(ObjectHeader);\n    wprintf(L\"%Ix\", (ULONG_PTR)object);\n    objectType = PhGetObjectType(object);\n\n    wprintf(L\"\\t%20s\", objectType->Name);\n\n    if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST)\n        c = L'f';\n    else if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST)\n        c = L'F';\n\n    wprintf(L\"\\t%4d %c\", ObjectHeader->RefCount - RefToSubtract, c);\n\n    if (!objectType)\n    {\n        // Dummy\n    }\n    else if (objectType == PhObjectTypeObject)\n    {\n        wprintf(L\"\\t%.32s\", ((PPH_OBJECT_TYPE)object)->Name);\n    }\n    else if (objectType == PhStringType)\n    {\n        wprintf(L\"\\t%.32s\", ((PPH_STRING)object)->Buffer);\n    }\n    else if (objectType == PhBytesType)\n    {\n        wprintf(L\"\\t%.32S\", ((PPH_BYTES)object)->Buffer);\n    }\n    else if (objectType == PhListType)\n    {\n        wprintf(L\"\\tCount: %u\", ((PPH_LIST)object)->Count);\n    }\n    else if (objectType == PhPointerListType)\n    {\n        wprintf(L\"\\tCount: %u\", ((PPH_POINTER_LIST)object)->Count);\n    }\n    else if (objectType == PhHashtableType)\n    {\n        wprintf(L\"\\tCount: %u\", ((PPH_HASHTABLE)object)->Count);\n    }\n    else if (objectType == PhProcessItemType)\n    {\n        wprintf(\n            L\"\\t%.28s (%lu)\",\n            ((PPH_PROCESS_ITEM)object)->ProcessName->Buffer,\n            HandleToUlong(((PPH_PROCESS_ITEM)object)->ProcessId)\n            );\n    }\n    else if (objectType == PhServiceItemType)\n    {\n        wprintf(L\"\\t%s\", ((PPH_SERVICE_ITEM)object)->Name->Buffer);\n    }\n    else if (objectType == PhThreadItemType)\n    {\n        wprintf(L\"\\tTID: %lu\", HandleToUlong(((PPH_THREAD_ITEM)object)->ThreadId));\n    }\n\n    wprintf(L\"\\n\");\n}\n\nstatic VOID PhpDumpObjectInfo(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    )\n{\n    PVOID object;\n    PPH_OBJECT_TYPE objectType;\n\n    object = PhObjectHeaderToObject(ObjectHeader);\n    objectType = PhGetObjectType(object);\n\n    __try\n    {\n        wprintf(L\"Type: %s\\n\", objectType->Name);\n        wprintf(L\"Reference count: %ld\\n\", ObjectHeader->RefCount);\n        wprintf(L\"Flags: %x\\n\", ObjectHeader->Flags);\n\n        if (objectType == PhObjectTypeObject)\n        {\n            wprintf(L\"Name: %s\\n\", ((PPH_OBJECT_TYPE)object)->Name);\n            wprintf(L\"Number of objects: %lu\\n\", ((PPH_OBJECT_TYPE)object)->NumberOfObjects);\n            wprintf(L\"Flags: %u\\n\", ((PPH_OBJECT_TYPE)object)->Flags);\n            wprintf(L\"Type index: %u\\n\", ((PPH_OBJECT_TYPE)object)->TypeIndex);\n            wprintf(L\"Free list count: %lu\\n\", ((PPH_OBJECT_TYPE)object)->FreeList.Count);\n        }\n        else if (objectType == PhStringType)\n        {\n            wprintf(L\"%s\\n\", ((PPH_STRING)object)->Buffer);\n        }\n        else if (objectType == PhBytesType)\n        {\n            wprintf(L\"%S\\n\", ((PPH_BYTES)object)->Buffer);\n        }\n        else if (objectType == PhHashtableType)\n        {\n            PhpPrintHashtableStatistics((PPH_HASHTABLE)object);\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        wprintf(L\"Error.\\n\");\n    }\n}\n\nVOID PhpPrintHashtableStatistics(\n    _In_ PPH_HASHTABLE Hashtable\n    )\n{\n    ULONG i;\n    ULONG expectedLookupMisses = 0;\n\n    wprintf(L\"Count: %u\\n\", Hashtable->Count);\n    wprintf(L\"Allocated buckets: %u\\n\", Hashtable->AllocatedBuckets);\n    wprintf(L\"Allocated entries: %u\\n\", Hashtable->AllocatedEntries);\n    wprintf(L\"Next free entry: %d\\n\", Hashtable->FreeEntry);\n    wprintf(L\"Next usable entry: %d\\n\", Hashtable->NextEntry);\n\n    wprintf(L\"Equal function: %s\\n\", PhpGetSymbolForAddress(Hashtable->EqualFunction));\n    wprintf(L\"Hash function: %s\\n\", PhpGetSymbolForAddress(Hashtable->HashFunction));\n\n    wprintf(L\"\\nBuckets:\\n\");\n\n    for (i = 0; i < Hashtable->AllocatedBuckets; i++)\n    {\n        ULONG index;\n        ULONG count = 0;\n\n        // Count the number of entries in this bucket.\n\n        index = Hashtable->Buckets[i];\n\n        while (index != ULONG_MAX)\n        {\n            index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next;\n            count++;\n        }\n\n        if (count != 0)\n        {\n            expectedLookupMisses += count - 1;\n        }\n\n        if (count != 0)\n        {\n            wprintf(L\"%lu: \", i);\n\n            // Print out the entry indicies.\n\n            index = Hashtable->Buckets[i];\n\n            while (index != ULONG_MAX)\n            {\n                wprintf(L\"%lu\", index);\n\n                index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next;\n                count--;\n\n                if (count != 0)\n                    wprintf(L\", \");\n            }\n\n            wprintf(L\"\\n\");\n        }\n        else\n        {\n            //wprintf(L\"%u: (empty)\\n\");\n        }\n    }\n\n    wprintf(L\"\\nExpected lookup misses: %lu\\n\", expectedLookupMisses);\n}\n\n#ifdef DEBUG\nstatic VOID PhpDebugCreateObjectHook(\n    _In_ PVOID Object,\n    _In_ SIZE_T Size,\n    _In_ ULONG Flags,\n    _In_ PPH_OBJECT_TYPE ObjectType\n    )\n{\n    PhAcquireQueuedLockExclusive(&NewObjectListLock);\n\n    if (NewObjectList)\n    {\n        PhReferenceObject(Object);\n        PhAddItemList(NewObjectList, Object);\n    }\n\n    PhReleaseQueuedLockExclusive(&NewObjectListLock);\n}\n#endif\n\n#ifdef DEBUG\nstatic VOID PhpDeleteNewObjectList(\n    VOID\n    )\n{\n    if (NewObjectList)\n    {\n        PhDereferenceObjects(NewObjectList->Items, NewObjectList->Count);\n        PhDereferenceObject(NewObjectList);\n        NewObjectList = NULL;\n    }\n}\n#endif\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nstatic BOOLEAN PhpStringHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PSTRING_TABLE_ENTRY entry1 = Entry1;\n    PSTRING_TABLE_ENTRY entry2 = Entry2;\n\n    return PhEqualString(entry1->String, entry2->String, FALSE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nstatic ULONG PhpStringHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PSTRING_TABLE_ENTRY entry = Entry;\n\n    return PhHashBytes((PUCHAR)entry->String->Buffer, entry->String->Length);\n}\n\nstatic int __cdecl PhpStringEntryCompareByCount(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PSTRING_TABLE_ENTRY entry1 = *(PSTRING_TABLE_ENTRY *)elem1;\n    PSTRING_TABLE_ENTRY entry2 = *(PSTRING_TABLE_ENTRY *)elem2;\n\n    return uintptrcmp(entry2->Count, entry1->Count);\n}\n\nstatic NTSTATUS PhpLeakEnumerationRoutine(\n    _In_ LONG Reserved,\n    _In_ PVOID HeapHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T BlockSize,\n    _In_ ULONG StackTraceDepth,\n    _In_ PVOID *StackTrace\n    )\n{\n    ULONG i;\n\n    if (!InLeakDetection)\n        return 0;\n\n    if (!HeapHandle) // means no more entries\n        return 0;\n\n    if (ShowAllLeaks || HeapHandle == PhHeapHandle)\n    {\n        wprintf(L\"Leak at 0x%Ix (%Iu bytes). Stack trace:\\n\", (ULONG_PTR)BaseAddress, BlockSize);\n\n        for (i = 0; i < StackTraceDepth; i++)\n        {\n            PPH_STRING symbol;\n\n            symbol = PhGetSymbolFromAddress(DebugConsoleSymbolProvider, StackTrace[i], NULL, NULL, NULL, NULL);\n\n            if (symbol)\n            {\n                wprintf(L\"\\t%s\\n\", symbol->Buffer);\n                PhDereferenceObject(symbol);\n            }\n            else\n            {\n                wprintf(L\"\\t?\\n\");\n            }\n        }\n\n        NumberOfLeaksShown++;\n    }\n\n    NumberOfLeaks++;\n\n    return 0;\n}\n\ntypedef VOID (FASTCALL *PPHF_RW_LOCK_FUNCTION)(\n    _In_ PVOID Parameter\n    );\n\ntypedef struct _RW_TEST_CONTEXT\n{\n    PWSTR Name;\n\n    PPHF_RW_LOCK_FUNCTION AcquireExclusive;\n    PPHF_RW_LOCK_FUNCTION AcquireShared;\n    PPHF_RW_LOCK_FUNCTION ReleaseExclusive;\n    PPHF_RW_LOCK_FUNCTION ReleaseShared;\n\n    PVOID Parameter;\n} RW_TEST_CONTEXT, *PRW_TEST_CONTEXT;\n\nstatic PH_BARRIER RwStartBarrier;\nstatic LONG RwReadersActive;\nstatic LONG RwWritersActive;\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhpRwLockTestThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n#define RW_ITERS 10000\n#define RW_READ_ITERS 100\n#define RW_WRITE_ITERS 10\n#define RW_READ_SPIN_ITERS 60\n#define RW_WRITE_SPIN_ITERS 200\n\n    RW_TEST_CONTEXT context = *(PRW_TEST_CONTEXT)Parameter;\n    ULONG i;\n    ULONG j;\n    ULONG k;\n    ULONG m;\n\n    PhWaitForBarrier(&RwStartBarrier, FALSE);\n\n    for (i = 0; i < RW_ITERS; i++)\n    {\n        for (j = 0; j < RW_READ_ITERS; j++)\n        {\n            // Read zone\n\n            context.AcquireShared(context.Parameter);\n            _InterlockedIncrement(&RwReadersActive);\n\n            for (m = 0; m < RW_READ_SPIN_ITERS; m++)\n                YieldProcessor();\n\n            if (ReadAcquire(&RwWritersActive) != 0)\n            {\n                wprintf(L\"[fail]: writers active in read zone!\\n\");\n                NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL);\n            }\n\n            _InterlockedDecrement(&RwReadersActive);\n            context.ReleaseShared(context.Parameter);\n\n            // Spin for a while\n\n            for (m = 0; m < 10; m++)\n                YieldProcessor();\n\n            if (j == RW_READ_ITERS / 2)\n            {\n                // Write zone\n\n                for (k = 0; k < RW_WRITE_ITERS; k++)\n                {\n                    context.AcquireExclusive(context.Parameter);\n                    _InterlockedIncrement(&RwWritersActive);\n\n                    for (m = 0; m < RW_WRITE_SPIN_ITERS; m++)\n                        YieldProcessor();\n\n                    if (ReadAcquire(&RwReadersActive) != 0)\n                    {\n                        wprintf(L\"[fail]: readers active in write zone!\\n\");\n                        NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL);\n                    }\n\n                    _InterlockedDecrement(&RwWritersActive);\n                    context.ReleaseExclusive(context.Parameter);\n                }\n            }\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nstatic VOID PhpTestRwLock(\n    _In_ PRW_TEST_CONTEXT Context\n    )\n{\n#define RW_PROCESSORS 4\n\n    PH_STOPWATCH stopwatch;\n    ULONG i;\n    HANDLE threadHandles[RW_PROCESSORS];\n\n    // Dummy\n\n    Context->AcquireExclusive(Context->Parameter);\n    Context->ReleaseExclusive(Context->Parameter);\n    Context->AcquireShared(Context->Parameter);\n    Context->ReleaseShared(Context->Parameter);\n\n    // Null test\n    PhInitializeStopwatch(&stopwatch);\n    PhStartStopwatch(&stopwatch);\n\n    for (i = 0; i < 2000000; i++)\n    {\n        Context->AcquireExclusive(Context->Parameter);\n        Context->ReleaseExclusive(Context->Parameter);\n        Context->AcquireShared(Context->Parameter);\n        Context->ReleaseShared(Context->Parameter);\n    }\n\n    PhStopStopwatch(&stopwatch);\n\n    wprintf(L\"[null] %s: %ums\\n\", Context->Name, PhGetMillisecondsStopwatch(&stopwatch));\n\n    // Stress test\n\n    PhInitializeBarrier(&RwStartBarrier, RW_PROCESSORS + 1);\n    RwReadersActive = 0;\n    RwWritersActive = 0;\n\n    for (i = 0; i < RW_PROCESSORS; i++)\n    {\n        PhCreateThreadEx(&threadHandles[i], PhpRwLockTestThreadStart, Context);\n    }\n\n    PhWaitForBarrier(&RwStartBarrier, FALSE);\n    PhInitializeStopwatch(&stopwatch);\n    PhStartStopwatch(&stopwatch);\n    NtWaitForMultipleObjects(RW_PROCESSORS, threadHandles, WaitAll, FALSE, NULL);\n    PhStopStopwatch(&stopwatch);\n\n    for (i = 0; i < RW_PROCESSORS; i++)\n        NtClose(threadHandles[i]);\n\n    wprintf(L\"[strs] %s: %ums\\n\", Context->Name, PhGetMillisecondsStopwatch(&stopwatch));\n}\n\n_Acquires_exclusive_lock_(*CriticalSection)\nVOID FASTCALL PhfAcquireCriticalSection(\n    _In_ PRTL_CRITICAL_SECTION CriticalSection\n    )\n{\n    RtlEnterCriticalSection(CriticalSection);\n}\n\n_Releases_exclusive_lock_(*CriticalSection)\nVOID FASTCALL PhfReleaseCriticalSection(\n    _In_ PRTL_CRITICAL_SECTION CriticalSection\n    )\n{\n    RtlLeaveCriticalSection(CriticalSection);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpDebugConsoleThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PH_AUTO_POOL autoPool;\n    BOOLEAN exit = FALSE;\n\n    PhInitializeAutoPool(&autoPool);\n\n    DebugConsoleSymbolProvider = PhCreateSymbolProvider(NtCurrentProcessId());\n    PhLoadSymbolProviderOptions(DebugConsoleSymbolProvider);\n\n    {\n        static CONST PH_STRINGREF variableNameSr = PH_STRINGREF_INIT(L\"_NT_SYMBOL_PATH\");\n        PPH_STRING variableValue;\n        PPH_STRING newSearchPath;\n\n        if (NT_SUCCESS(PhQueryEnvironmentVariable(NULL, &variableNameSr, &variableValue)))\n        {\n            PPH_STRING currentDirectory = PhGetApplicationDirectoryWin32();\n            PPH_STRING currentSearchPath = PhGetStringSetting(SETTING_DBGHELP_SEARCH_PATH);\n\n            if (currentSearchPath->Length != 0)\n            {\n                newSearchPath = PhFormatString(\n                    L\"%s;%s;%s\",\n                    variableValue->Buffer,\n                    PhGetStringOrEmpty(currentSearchPath),\n                    PhGetStringOrEmpty(currentDirectory)\n                    );\n            }\n            else\n            {\n                newSearchPath = PhFormatString(\n                    L\"%s;%s\",\n                    variableValue->Buffer,\n                    PhGetStringOrEmpty(currentDirectory)\n                    );\n            }\n\n            PhSetSearchPathSymbolProvider(DebugConsoleSymbolProvider, PhGetString(newSearchPath));\n\n            PhDereferenceObject(variableValue);\n            PhDereferenceObject(newSearchPath);\n            PhDereferenceObject(currentDirectory);\n        }\n    }\n\n    PhLoadSymbolProviderModules(\n        DebugConsoleSymbolProvider,\n        NtCurrentProcessId()\n        );\n\n#ifdef DEBUG\n    PhInitializeQueuedLock(&NewObjectListLock);\n    PhDbgCreateObjectHook = PhpDebugCreateObjectHook;\n#endif\n\n    wprintf(L\"Press Ctrl+C or type \\\"exit\\\" to close the debug console. Type \\\"help\\\" for a list of commands.\\n\");\n\n    while (!exit)\n    {\n        static PCWSTR delims = L\" \\t\";\n        static PCWSTR commandDebugOnly = L\"This command is not available on non-debug builds.\\n\";\n\n        WCHAR line[201];\n        ULONG inputLength;\n        PWSTR context;\n        PWSTR command;\n\n        wprintf(L\"dbg>\");\n\n        if (!fgetws(line, sizeof(line) / sizeof(WCHAR) - 1, stdin))\n            break;\n\n        // Remove the terminating new line character.\n\n        inputLength = (ULONG)PhCountStringZ(line);\n\n        if (inputLength != 0)\n            line[inputLength - 1] = UNICODE_NULL;\n\n        context = NULL;\n        command = wcstok_s(line, delims, &context);\n\n        if (!command)\n        {\n            continue;\n        }\n        else if (PhEqualStringZ(command, L\"help\", TRUE))\n        {\n            wprintf(\n                L\"Commands:\\n\"\n                L\"exit\\n\"\n                L\"testperf\\n\"\n                L\"testlocks\\n\"\n                L\"stats\\n\"\n                L\"objects [type-name-filter]\\n\"\n                L\"objtrace object-address\\n\"\n                L\"objmksnap\\n\"\n                L\"objcmpsnap\\n\"\n                L\"objmknew\\n\"\n                L\"objdelnew\\n\"\n                L\"objviewnew\\n\"\n                L\"dumpobj\\n\"\n                L\"dumpautopool\\n\"\n                L\"threads\\n\"\n                L\"provthreads\\n\"\n                L\"workqueues\\n\"\n                L\"procrecords\\n\"\n                L\"procitem\\n\"\n                L\"uniquestr\\n\"\n                L\"enableleakdetect\\n\"\n                L\"leakdetect\\n\"\n                L\"mem\\n\"\n                );\n        }\n        else if (PhEqualStringZ(command, L\"exit\", TRUE))\n        {\n            PhCloseDebugConsole();\n            exit = TRUE;\n        }\n        else if (PhEqualStringZ(command, L\"testperf\", TRUE))\n        {\n            PH_STOPWATCH stopwatch;\n            ULONG i;\n            PPH_STRING testString;\n            RTL_CRITICAL_SECTION testCriticalSection;\n            PH_FAST_LOCK testFastLock;\n            PH_QUEUED_LOCK testQueuedLock;\n\n            // Control (string reference counting)\n\n            testString = PhCreateString(L\"\");\n            PhReferenceObject(testString);\n            PhDereferenceObject(testString);\n            PhStartStopwatch(&stopwatch);\n\n            for (i = 0; i < 10000000; i++)\n            {\n                PhReferenceObject(testString);\n                PhDereferenceObject(testString);\n            }\n\n            PhStopStopwatch(&stopwatch);\n            PhDereferenceObject(testString);\n\n            wprintf(L\"Referencing: %ums\\n\", PhGetMillisecondsStopwatch(&stopwatch));\n\n            // Critical section\n\n            RtlInitializeCriticalSection(&testCriticalSection);\n            RtlEnterCriticalSection(&testCriticalSection);\n            RtlLeaveCriticalSection(&testCriticalSection);\n            PhStartStopwatch(&stopwatch);\n\n            for (i = 0; i < 10000000; i++)\n            {\n                RtlEnterCriticalSection(&testCriticalSection);\n                RtlLeaveCriticalSection(&testCriticalSection);\n            }\n\n            PhStopStopwatch(&stopwatch);\n            RtlDeleteCriticalSection(&testCriticalSection);\n\n            wprintf(L\"Critical section: %ums\\n\", PhGetMillisecondsStopwatch(&stopwatch));\n\n            // Fast lock\n\n            PhInitializeFastLock(&testFastLock);\n            PhAcquireFastLockExclusive(&testFastLock);\n            PhReleaseFastLockExclusive(&testFastLock);\n            PhStartStopwatch(&stopwatch);\n\n            for (i = 0; i < 10000000; i++)\n            {\n                PhAcquireFastLockExclusive(&testFastLock);\n                PhReleaseFastLockExclusive(&testFastLock);\n            }\n\n            PhStopStopwatch(&stopwatch);\n            PhDeleteFastLock(&testFastLock);\n\n            wprintf(L\"Fast lock: %ums\\n\", PhGetMillisecondsStopwatch(&stopwatch));\n\n            // Queued lock\n\n            PhInitializeQueuedLock(&testQueuedLock);\n            PhAcquireQueuedLockExclusive(&testQueuedLock);\n            PhReleaseQueuedLockExclusive(&testQueuedLock);\n            PhStartStopwatch(&stopwatch);\n\n            for (i = 0; i < 10000000; i++)\n            {\n                PhAcquireQueuedLockExclusive(&testQueuedLock);\n                PhReleaseQueuedLockExclusive(&testQueuedLock);\n            }\n\n            PhStopStopwatch(&stopwatch);\n\n            wprintf(L\"Queued lock: %ums\\n\", PhGetMillisecondsStopwatch(&stopwatch));\n        }\n        else if (PhEqualStringZ(command, L\"testlocks\", TRUE))\n        {\n            RW_TEST_CONTEXT testContext;\n            PH_FAST_LOCK fastLock;\n            PH_QUEUED_LOCK queuedLock;\n            RTL_CRITICAL_SECTION criticalSection;\n\n            testContext.Name = L\"FastLock\";\n            testContext.AcquireExclusive = PhfAcquireFastLockExclusive;\n            testContext.AcquireShared = PhfAcquireFastLockShared;\n            testContext.ReleaseExclusive = PhfReleaseFastLockExclusive;\n            testContext.ReleaseShared = PhfReleaseFastLockShared;\n            testContext.Parameter = &fastLock;\n            PhInitializeFastLock(&fastLock);\n            PhpTestRwLock(&testContext);\n            PhDeleteFastLock(&fastLock);\n\n            testContext.Name = L\"QueuedLock\";\n            testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive;\n            testContext.AcquireShared = PhfAcquireQueuedLockShared;\n            testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive;\n            testContext.ReleaseShared = PhfReleaseQueuedLockShared;\n            testContext.Parameter = &queuedLock;\n            PhInitializeQueuedLock(&queuedLock);\n            PhpTestRwLock(&testContext);\n\n            testContext.Name = L\"CriticalSection\";\n            testContext.AcquireExclusive = PhfAcquireCriticalSection;\n            testContext.AcquireShared = PhfAcquireCriticalSection;\n            testContext.ReleaseExclusive = PhfReleaseCriticalSection;\n            testContext.ReleaseShared = PhfReleaseCriticalSection;\n            testContext.Parameter = &criticalSection;\n            RtlInitializeCriticalSection(&criticalSection);\n            PhpTestRwLock(&testContext);\n            RtlDeleteCriticalSection(&criticalSection);\n\n            testContext.Name = L\"QueuedLockMutex\";\n            testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive;\n            testContext.AcquireShared = PhfAcquireQueuedLockExclusive;\n            testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive;\n            testContext.ReleaseShared = PhfReleaseQueuedLockExclusive;\n            testContext.Parameter = &queuedLock;\n            PhInitializeQueuedLock(&queuedLock);\n            PhpTestRwLock(&testContext);\n        }\n        else if (PhEqualStringZ(command, L\"stats\", TRUE))\n        {\n#ifdef DEBUG\n            wprintf(L\"Object small free list count: %u\\n\", PhObjectSmallFreeList.Count);\n            wprintf(L\"Statistics:\\n\");\n#define PRINT_STATISTIC(Name) wprintf(TEXT(#Name) L\": %u\\n\", PhLibStatisticsBlock.Name);\n\n            PRINT_STATISTIC(BaseThreadsCreated);\n            PRINT_STATISTIC(BaseThreadsCreateFailed);\n            PRINT_STATISTIC(BaseStringBuildersCreated);\n            PRINT_STATISTIC(BaseStringBuildersResized);\n            PRINT_STATISTIC(RefObjectsCreated);\n            PRINT_STATISTIC(RefObjectsDestroyed);\n            PRINT_STATISTIC(RefObjectsAllocated);\n            PRINT_STATISTIC(RefObjectsFreed);\n            PRINT_STATISTIC(RefObjectsAllocatedFromSmallFreeList);\n            PRINT_STATISTIC(RefObjectsFreedToSmallFreeList);\n            PRINT_STATISTIC(RefObjectsAllocatedFromTypeFreeList);\n            PRINT_STATISTIC(RefObjectsFreedToTypeFreeList);\n            PRINT_STATISTIC(RefObjectsDeleteDeferred);\n            PRINT_STATISTIC(RefAutoPoolsCreated);\n            PRINT_STATISTIC(RefAutoPoolsDestroyed);\n            PRINT_STATISTIC(RefAutoPoolsDynamicAllocated);\n            PRINT_STATISTIC(RefAutoPoolsDynamicResized);\n            PRINT_STATISTIC(QlBlockSpins);\n            PRINT_STATISTIC(QlBlockWaits);\n            PRINT_STATISTIC(QlAcquireExclusiveBlocks);\n            PRINT_STATISTIC(QlAcquireSharedBlocks);\n            PRINT_STATISTIC(WqWorkQueueThreadsCreated);\n            PRINT_STATISTIC(WqWorkQueueThreadsCreateFailed);\n            PRINT_STATISTIC(WqWorkItemsQueued);\n\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"objects\", TRUE))\n        {\n#ifdef DEBUG\n            PWSTR typeFilter = wcstok_s(NULL, delims, &context);\n            PLIST_ENTRY currentEntry;\n            ULONG totalNumberOfObjects = 0;\n            //SIZE_T totalNumberOfBytes = 0;\n\n            if (typeFilter)\n                _wcslwr(typeFilter);\n\n            PhAcquireQueuedLockShared(&PhDbgObjectListLock);\n\n            currentEntry = PhDbgObjectListHead.Flink;\n\n            while (currentEntry != &PhDbgObjectListHead)\n            {\n                PPH_OBJECT_HEADER objectHeader;\n                WCHAR typeName[32];\n\n                objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);\n\n                // Make sure the object isn't being destroyed.\n                if (!PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader)))\n                {\n                    currentEntry = currentEntry->Flink;\n                    continue;\n                }\n\n                totalNumberOfObjects++;\n                //totalNumberOfBytes += objectHeader->Size;\n\n                if (typeFilter)\n                {\n                    wcscpy_s(typeName, sizeof(typeName) / sizeof(WCHAR), PhGetObjectType(PhObjectHeaderToObject(objectHeader))->Name);\n                    _wcslwr(typeName);\n                }\n\n                if (\n                    !typeFilter ||\n                    (typeFilter && wcsstr(typeName, typeFilter))\n                    )\n                {\n                    PhpPrintObjectInfo(objectHeader, 1);\n                }\n\n                currentEntry = currentEntry->Flink;\n                PhDereferenceObjectDeferDelete(PhObjectHeaderToObject(objectHeader));\n            }\n\n            PhReleaseQueuedLockShared(&PhDbgObjectListLock);\n\n            wprintf(L\"\\n\");\n            wprintf(L\"Total number: %lu\\n\", totalNumberOfObjects);\n            /*wprintf(L\"Total size (excl. header): %s\\n\",\n                ((PPH_STRING)PH_AUTO(PhFormatSize(totalNumberOfBytes, 1)))->Buffer);*/\n            wprintf(L\"Total overhead (header): %s\\n\",\n                ((PPH_STRING)PH_AUTO(\n                PhFormatSize(PhAddObjectHeaderSize(0) * totalNumberOfObjects, 1)\n                ))->Buffer);\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"objtrace\", TRUE))\n        {\n#ifdef DEBUG\n            PWSTR objectAddress = wcstok_s(NULL, delims, &context);\n            PH_STRINGREF objectAddressString;\n            ULONG64 address;\n\n            if (!objectAddress)\n            {\n                wprintf(L\"Missing object address.\\n\");\n                goto EndCommand;\n            }\n\n            PhInitializeStringRef(&objectAddressString, objectAddress);\n\n            if (PhStringToUInt64(&objectAddressString, 16, &address))\n            {\n                PPH_OBJECT_HEADER objectHeader = (PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address);\n                PVOID stackBackTrace[16];\n                ULONG i;\n\n                // The address may not be valid.\n                __try\n                {\n                    memcpy(stackBackTrace, objectHeader->StackBackTrace, 16 * sizeof(PVOID));\n                }\n                __except (EXCEPTION_EXECUTE_HANDLER)\n                {\n                    PPH_STRING message;\n\n                    message = PH_AUTO(PhGetNtMessage(GetExceptionCode()));\n                    wprintf(L\"Error: %s\\n\", PhGetString(message));\n\n                    goto EndCommand;\n                }\n\n                for (i = 0; i < 16; i++)\n                {\n                    if (!stackBackTrace[i])\n                        break;\n\n                    wprintf(L\"%s\\n\", PhpGetSymbolForAddress(stackBackTrace[i]));\n                }\n            }\n            else\n            {\n                wprintf(L\"Invalid object address.\\n\");\n            }\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"objmksnap\", TRUE))\n        {\n#ifdef DEBUG\n            PLIST_ENTRY currentEntry;\n\n            if (ObjectListSnapshot)\n            {\n                PhDereferenceObject(ObjectListSnapshot);\n                ObjectListSnapshot = NULL;\n            }\n\n            ObjectListSnapshot = PhCreateSimpleHashtable(100);\n\n            PhAcquireQueuedLockShared(&PhDbgObjectListLock);\n\n            currentEntry = PhDbgObjectListHead.Flink;\n\n            while (currentEntry != &PhDbgObjectListHead)\n            {\n                PPH_OBJECT_HEADER objectHeader;\n\n                objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);\n                currentEntry = currentEntry->Flink;\n\n                if (PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot)\n                    PhAddItemSimpleHashtable(ObjectListSnapshot, objectHeader, NULL);\n            }\n\n            PhReleaseQueuedLockShared(&PhDbgObjectListLock);\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"objcmpsnap\", TRUE))\n        {\n#ifdef DEBUG\n            PLIST_ENTRY currentEntry;\n            PPH_LIST newObjects;\n            ULONG i;\n\n            if (!ObjectListSnapshot)\n            {\n                wprintf(L\"No snapshot.\\n\");\n                goto EndCommand;\n            }\n\n            newObjects = PhCreateList(10);\n\n            PhAcquireQueuedLockShared(&PhDbgObjectListLock);\n\n            currentEntry = PhDbgObjectListHead.Flink;\n\n            while (currentEntry != &PhDbgObjectListHead)\n            {\n                PPH_OBJECT_HEADER objectHeader;\n\n                objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);\n                currentEntry = currentEntry->Flink;\n\n                if (\n                    PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot &&\n                    PhObjectHeaderToObject(objectHeader) != newObjects\n                    )\n                {\n                    if (!PhFindItemSimpleHashtable(ObjectListSnapshot, objectHeader))\n                    {\n                        if (PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader)))\n                            PhAddItemList(newObjects, objectHeader);\n                    }\n                }\n            }\n\n            PhReleaseQueuedLockShared(&PhDbgObjectListLock);\n\n            for (i = 0; i < newObjects->Count; i++)\n            {\n                PPH_OBJECT_HEADER objectHeader = newObjects->Items[i];\n\n                PhpPrintObjectInfo(objectHeader, 1);\n\n                PhDereferenceObject(PhObjectHeaderToObject(objectHeader));\n            }\n\n            PhDereferenceObject(newObjects);\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"objmknew\", TRUE))\n        {\n#ifdef DEBUG\n            PhAcquireQueuedLockExclusive(&NewObjectListLock);\n            PhpDeleteNewObjectList();\n            PhReleaseQueuedLockExclusive(&NewObjectListLock);\n\n            // Creation needs to be done outside of the lock,\n            // otherwise a deadlock will occur.\n            NewObjectList = PhCreateList(100);\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"objdelnew\", TRUE))\n        {\n#ifdef DEBUG\n            PhAcquireQueuedLockExclusive(&NewObjectListLock);\n            PhpDeleteNewObjectList();\n            PhReleaseQueuedLockExclusive(&NewObjectListLock);\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"objviewnew\", TRUE))\n        {\n#ifdef DEBUG\n            ULONG i;\n\n            PhAcquireQueuedLockExclusive(&NewObjectListLock);\n\n            if (!NewObjectList)\n            {\n                wprintf(L\"Object creation hooking not active.\\n\");\n                PhReleaseQueuedLockExclusive(&NewObjectListLock);\n                goto EndCommand;\n            }\n\n            for (i = 0; i < NewObjectList->Count; i++)\n            {\n                PhpPrintObjectInfo(PhObjectToObjectHeader(NewObjectList->Items[i]), 1);\n            }\n\n            PhReleaseQueuedLockExclusive(&NewObjectListLock);\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"dumpobj\", TRUE))\n        {\n            PWSTR addressString = wcstok_s(NULL, delims, &context);\n            PH_STRINGREF addressStringRef;\n            ULONG64 address;\n\n            if (!addressString)\n                goto EndCommand;\n\n            PhInitializeStringRef(&addressStringRef, addressString);\n\n            if (PhStringToUInt64(&addressStringRef, 16, &address))\n            {\n                PhpDumpObjectInfo((PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address));\n            }\n        }\n        else if (PhEqualStringZ(command, L\"dumpautopool\", TRUE))\n        {\n            PWSTR addressString = wcstok_s(NULL, delims, &context);\n            PH_STRINGREF addressStringRef;\n            ULONG64 address;\n\n            if (!addressString)\n                goto EndCommand;\n\n            PhInitializeStringRef(&addressStringRef, addressString);\n\n            if (PhStringToUInt64(&addressStringRef, 16, &address))\n            {\n                PPH_AUTO_POOL userAutoPool = (PPH_AUTO_POOL)address;\n                ULONG i;\n\n                __try\n                {\n                    wprintf(L\"Static count: %u\\n\", userAutoPool->StaticCount);\n                    wprintf(L\"Dynamic count: %u\\n\", userAutoPool->DynamicCount);\n                    wprintf(L\"Dynamic allocated: %u\\n\", userAutoPool->DynamicAllocated);\n\n                    wprintf(L\"Static objects:\\n\");\n\n                    for (i = 0; i < userAutoPool->StaticCount; i++)\n                        PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->StaticObjects[i]), 0);\n\n                    wprintf(L\"Dynamic objects:\\n\");\n\n                    for (i = 0; i < userAutoPool->DynamicCount; i++)\n                        PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->DynamicObjects[i]), 0);\n                }\n                __except (EXCEPTION_EXECUTE_HANDLER)\n                {\n                    goto EndCommand;\n                }\n            }\n        }\n        else if (PhEqualStringZ(command, L\"threads\", TRUE))\n        {\n#ifdef DEBUG\n            PLIST_ENTRY currentEntry;\n\n            PhAcquireQueuedLockShared(&PhDbgThreadListLock);\n\n            currentEntry = PhDbgThreadListHead.Flink;\n\n            while (currentEntry != &PhDbgThreadListHead)\n            {\n                PPHP_BASE_THREAD_DBG dbg;\n\n                dbg = CONTAINING_RECORD(currentEntry, PHP_BASE_THREAD_DBG, ListEntry);\n\n                wprintf(L\"Thread %u\\n\", HandleToUlong(dbg->ClientId.UniqueThread));\n                wprintf(L\"\\tStart Address: %s\\n\", PhpGetSymbolForAddress(dbg->StartAddress));\n                wprintf(L\"\\tParameter: %Ix\\n\", (ULONG_PTR)dbg->Parameter);\n                wprintf(L\"\\tCurrent auto-pool: %Ix\\n\", (ULONG_PTR)dbg->CurrentAutoPool);\n\n                currentEntry = currentEntry->Flink;\n            }\n\n            PhReleaseQueuedLockShared(&PhDbgThreadListLock);\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"provthreads\", TRUE))\n        {\n#ifdef DEBUG\n            ULONG i;\n\n            if (PhDbgProviderList)\n            {\n                PhAcquireQueuedLockShared(&PhDbgProviderListLock);\n\n                for (i = 0; i < PhDbgProviderList->Count; i++)\n                {\n                    PPH_PROVIDER_THREAD providerThread = PhDbgProviderList->Items[i];\n                    THREAD_BASIC_INFORMATION basicInfo;\n                    PLIST_ENTRY providerEntry;\n\n                    if (providerThread->ThreadHandle)\n                    {\n                        PhGetThreadBasicInformation(providerThread->ThreadHandle, &basicInfo);\n                        wprintf(L\"Thread %u\\n\", HandleToUlong(basicInfo.ClientId.UniqueThread));\n                    }\n                    else\n                    {\n                        wprintf(L\"Thread not running\\n\");\n                    }\n\n                    PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n                    providerEntry = providerThread->ListHead.Flink;\n\n                    while (providerEntry != &providerThread->ListHead)\n                    {\n                        PPH_PROVIDER_REGISTRATION registration;\n\n                        registration = CONTAINING_RECORD(providerEntry, PH_PROVIDER_REGISTRATION, ListEntry);\n\n                        wprintf(L\"\\tProvider registration at %Ix\\n\", (ULONG_PTR)registration);\n                        wprintf(L\"\\t\\tEnabled: %s\\n\", registration->Enabled ? L\"Yes\" : L\"No\");\n                        wprintf(L\"\\t\\tFunction: %s\\n\", PhpGetSymbolForAddress(registration->Function));\n\n                        if (registration->Object)\n                        {\n                            wprintf(L\"\\t\\tObject:\\n\");\n                            PhpPrintObjectInfo(PhObjectToObjectHeader(registration->Object), 0);\n                        }\n\n                        providerEntry = providerEntry->Flink;\n                    }\n\n                    PhReleaseQueuedLockExclusive(&providerThread->Lock);\n\n                    wprintf(L\"\\n\");\n                }\n\n                PhReleaseQueuedLockShared(&PhDbgProviderListLock);\n            }\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"workqueues\", TRUE))\n        {\n#ifdef DEBUG\n            ULONG i;\n\n            if (PhDbgWorkQueueList)\n            {\n                PhAcquireQueuedLockShared(&PhDbgWorkQueueListLock);\n\n                for (i = 0; i < PhDbgWorkQueueList->Count; i++)\n                {\n                    PPH_WORK_QUEUE workQueue = PhDbgWorkQueueList->Items[i];\n                    PLIST_ENTRY workQueueItemEntry;\n\n                    wprintf(L\"Work queue at %s\\n\", PhpGetSymbolForAddress(workQueue));\n                    wprintf(L\"Maximum threads: %lu\\n\", workQueue->MaximumThreads);\n                    wprintf(L\"Minimum threads: %lu\\n\", workQueue->MinimumThreads);\n                    wprintf(L\"No work timeout: %lu\\n\", workQueue->NoWorkTimeout);\n\n                    wprintf(L\"Current threads: %lu\\n\", workQueue->CurrentThreads);\n                    wprintf(L\"Busy count: %lu\\n\", workQueue->BusyCount);\n\n                    PhAcquireQueuedLockExclusive(&workQueue->QueueLock);\n\n                    // List the items backwards.\n                    workQueueItemEntry = workQueue->QueueListHead.Blink;\n\n                    while (workQueueItemEntry != &workQueue->QueueListHead)\n                    {\n                        PPH_WORK_QUEUE_ITEM workQueueItem;\n\n                        workQueueItem = CONTAINING_RECORD(workQueueItemEntry, PH_WORK_QUEUE_ITEM, ListEntry);\n\n                        wprintf(L\"\\tWork queue item at %Ix\\n\", (ULONG_PTR)workQueueItem);\n                        wprintf(L\"\\t\\tFunction: %s\\n\", PhpGetSymbolForAddress(workQueueItem->Function));\n                        wprintf(L\"\\t\\tContext: %Ix\\n\", (ULONG_PTR)workQueueItem->Context);\n\n                        workQueueItemEntry = workQueueItemEntry->Blink;\n                    }\n\n                    PhReleaseQueuedLockExclusive(&workQueue->QueueLock);\n\n                    wprintf(L\"\\n\");\n                }\n\n                PhReleaseQueuedLockShared(&PhDbgWorkQueueListLock);\n            }\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"procrecords\", TRUE))\n        {\n            PPH_PROCESS_RECORD record;\n            ULONG i;\n            SYSTEMTIME systemTime;\n            PPH_PROCESS_RECORD startRecord;\n\n            PhAcquireQueuedLockShared(&PhProcessRecordListLock);\n\n            for (i = 0; i < PhProcessRecordList->Count; i++)\n            {\n                record = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i];\n\n                PhLargeIntegerToLocalSystemTime(&systemTime, &record->CreateTime);\n                wprintf(L\"Records for %s %s:\\n\",\n                    ((PPH_STRING)PH_AUTO(PhFormatDate(&systemTime, NULL)))->Buffer,\n                    ((PPH_STRING)PH_AUTO(PhFormatTime(&systemTime, NULL)))->Buffer\n                    );\n\n                startRecord = record;\n\n                do\n                {\n                    wprintf(L\"\\tRecord at %Ix: %s (%lu) (refs: %ld)\\n\", (ULONG_PTR)record, record->ProcessName->Buffer, HandleToUlong(record->ProcessId), record->RefCount);\n\n                    if (record->FileName)\n                        wprintf(L\"\\t\\t%s\\n\", record->FileName->Buffer);\n\n                    record = CONTAINING_RECORD(record->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry);\n                } while (record != startRecord);\n            }\n\n            PhReleaseQueuedLockShared(&PhProcessRecordListLock);\n        }\n        else if (PhEqualStringZ(command, L\"procitem\", TRUE))\n        {\n            PWSTR filterString;\n            PH_STRINGREF filterRef;\n            ULONG64 filter64;\n            LONG_PTR processIdFilter = -9; // can't use -2, -1 or 0 because they're all used for process IDs\n            ULONG_PTR processAddressFilter = 0;\n            PWSTR imageNameFilter = NULL;\n            BOOLEAN showAll = FALSE;\n            PPH_PROCESS_ITEM *processes;\n            ULONG numberOfProcesses;\n            ULONG i;\n\n            filterString = wcstok_s(NULL, delims, &context);\n\n            if (filterString)\n            {\n                PhInitializeStringRef(&filterRef, filterString);\n\n                if (PhStringToInteger64(&filterRef, 10, &filter64))\n                    processIdFilter = (LONG_PTR)filter64;\n                if (PhStringToInteger64(&filterRef, 16, &filter64))\n                    processAddressFilter = (ULONG_PTR)filter64;\n\n                imageNameFilter = filterString;\n            }\n            else\n            {\n                showAll = TRUE;\n            }\n\n            PhEnumProcessItems(&processes, &numberOfProcesses);\n\n            for (i = 0; i < numberOfProcesses; i++)\n            {\n                PPH_PROCESS_ITEM process = processes[i];\n\n                if (\n                    showAll ||\n                    (processIdFilter != -9 && (LONG_PTR)process->ProcessId == processIdFilter) ||\n                    (processAddressFilter != 0 && (ULONG_PTR)process == processAddressFilter) ||\n                    (imageNameFilter && PhMatchWildcards(imageNameFilter, process->ProcessName->Buffer, TRUE))\n                    )\n                {\n                    wprintf(L\"Process item at %Ix: %s (%u)\\n\", (ULONG_PTR)process, process->ProcessName->Buffer, HandleToUlong(process->ProcessId));\n                    wprintf(L\"\\tRecord at %Ix\\n\", (ULONG_PTR)process->Record);\n                    wprintf(L\"\\tQuery handle %Ix\\n\", (ULONG_PTR)process->QueryHandle);\n                    wprintf(L\"\\tFile name at %Ix: %s\\n\", (ULONG_PTR)process->FileName, PhGetStringOrDefault(process->FileName, L\"(null)\"));\n                    wprintf(L\"\\tCommand line at %Ix: %s\\n\", (ULONG_PTR)process->CommandLine, PhGetStringOrDefault(process->CommandLine, L\"(null)\"));\n                    wprintf(L\"\\tFlags: %u\\n\", process->Flags);\n                    wprintf(L\"\\n\");\n                }\n            }\n\n            PhDereferenceObjects(processes, numberOfProcesses);\n        }\n        else if (PhEqualStringZ(command, L\"uniquestr\", TRUE))\n        {\n#ifdef DEBUG\n            PLIST_ENTRY currentEntry;\n            PPH_HASHTABLE hashtable;\n            PPH_LIST list;\n            PSTRING_TABLE_ENTRY stringEntry;\n            ULONG enumerationKey;\n            ULONG i;\n\n            hashtable = PhCreateHashtable(\n                sizeof(STRING_TABLE_ENTRY),\n                PhpStringHashtableEqualFunction,\n                PhpStringHashtableHashFunction,\n                1024\n                );\n\n            PhAcquireQueuedLockShared(&PhDbgObjectListLock);\n\n            currentEntry = PhDbgObjectListHead.Flink;\n\n            while (currentEntry != &PhDbgObjectListHead)\n            {\n                PPH_OBJECT_HEADER objectHeader;\n                PPH_STRING string;\n                STRING_TABLE_ENTRY localStringEntry;\n                BOOLEAN added;\n\n                objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);\n                currentEntry = currentEntry->Flink;\n                string = PhObjectHeaderToObject(objectHeader);\n\n                // Make sure this is a string.\n                if (PhGetObjectType(string) != PhStringType)\n                    continue;\n\n                // Make sure the object isn't being destroyed.\n                if (!PhReferenceObjectSafe(string))\n                    continue;\n\n                localStringEntry.String = string;\n                stringEntry = PhAddEntryHashtableEx(hashtable, &localStringEntry, &added);\n\n                if (added)\n                {\n                    stringEntry->Count = 1;\n                    PhReferenceObject(string);\n                }\n                else\n                {\n                    stringEntry->Count++;\n                }\n\n                PhDereferenceObjectDeferDelete(string);\n            }\n\n            PhReleaseQueuedLockShared(&PhDbgObjectListLock);\n\n            // Sort the string entries by count.\n\n            list = PhCreateList(hashtable->Count);\n\n            enumerationKey = 0;\n\n            while (PhEnumHashtable(hashtable, &stringEntry, &enumerationKey))\n            {\n                PhAddItemList(list, stringEntry);\n            }\n\n            qsort(list->Items, list->Count, sizeof(PSTRING_TABLE_ENTRY), PhpStringEntryCompareByCount);\n\n            // Display...\n\n            for (i = 0; i < 40 && i < list->Count; i++)\n            {\n                stringEntry = list->Items[i];\n                wprintf(L\"%Iu\\t%.64s\\n\", stringEntry->Count, stringEntry->String->Buffer);\n            }\n\n            wprintf(L\"\\nTotal unique strings: %u\\n\", list->Count);\n\n            // Cleanup\n\n            for (i = 0; i < list->Count; i++)\n            {\n                stringEntry = list->Items[i];\n                PhDereferenceObject(stringEntry->String);\n            }\n\n            PhDereferenceObject(list);\n            PhDereferenceObject(hashtable);\n#else\n            wprintf(commandDebugOnly);\n#endif\n        }\n        else if (PhEqualStringZ(command, L\"enableleakdetect\", TRUE))\n        {\n            HEAP_DEBUGGING_INFORMATION debuggingInfo;\n\n            memset(&debuggingInfo, 0, sizeof(HEAP_DEBUGGING_INFORMATION));\n            debuggingInfo.StackTraceDepth = 32;\n            debuggingInfo.HeapLeakEnumerationRoutine = PhpLeakEnumerationRoutine;\n\n            if (!NT_SUCCESS(RtlSetHeapInformation(NULL, HeapSetDebuggingInformation, &debuggingInfo, sizeof(HEAP_DEBUGGING_INFORMATION))))\n            {\n                wprintf(L\"Unable to initialize heap debugging. Make sure that you are using Windows 7 or above.\");\n            }\n        }\n        else if (PhEqualStringZ(command, L\"leakdetect\", TRUE))\n        {\n            VOID (NTAPI *rtlDetectHeapLeaks)(VOID);\n            PWSTR options = wcstok_s(NULL, delims, &context);\n\n            rtlDetectHeapLeaks = PhGetDllProcedureAddressZ(L\"ntdll.dll\", \"RtlDetectHeapLeaks\", 0);\n\n            if (!(NtCurrentPeb()->NtGlobalFlag & FLG_USER_STACK_TRACE_DB))\n            {\n                wprintf(L\"Warning: user-mode stack trace database is not enabled. Stack traces will not be displayed.\\n\");\n            }\n\n            ShowAllLeaks = FALSE;\n\n            if (options)\n            {\n                if (PhEqualStringZ(options, L\"all\", TRUE))\n                    ShowAllLeaks = TRUE;\n            }\n\n            if (rtlDetectHeapLeaks)\n            {\n                InLeakDetection = TRUE;\n                NumberOfLeaks = 0;\n                NumberOfLeaksShown = 0;\n                rtlDetectHeapLeaks();\n                InLeakDetection = FALSE;\n\n                wprintf(L\"\\nNumber of leaks: %lu (%lu displayed)\\n\", NumberOfLeaks, NumberOfLeaksShown);\n            }\n        }\n        else if (PhEqualStringZ(command, L\"mem\", TRUE))\n        {\n            PWSTR addressString;\n            PWSTR bytesString;\n            PH_STRINGREF addressStringRef;\n            PH_STRINGREF bytesStringRef;\n            ULONG64 address64;\n            ULONG64 numberOfBytes64;\n            PUCHAR address;\n            ULONG numberOfBytes;\n            ULONG blockSize;\n            UCHAR buffer[16];\n            ULONG i;\n\n            addressString = wcstok_s(NULL, delims, &context);\n\n            if (!addressString)\n                goto PrintMemUsage;\n\n            bytesString = wcstok_s(NULL, delims, &context);\n\n            if (!bytesString)\n            {\n                bytesString = L\"16\";\n            }\n\n            PhInitializeStringRef(&addressStringRef, addressString);\n            PhInitializeStringRef(&bytesStringRef, bytesString);\n\n            if (PhStringToUInt64(&addressStringRef, 16, &address64) && PhStringToUInt64(&bytesStringRef, 10, &numberOfBytes64))\n            {\n                address = (PUCHAR)address64;\n                numberOfBytes = (ULONG)numberOfBytes64;\n\n                if (numberOfBytes > 256)\n                {\n                    wprintf(L\"Number of bytes must be 256 or smaller.\\n\");\n                    goto EndCommand;\n                }\n\n                blockSize = sizeof(buffer);\n\n                while (numberOfBytes != 0)\n                {\n                    if (blockSize > numberOfBytes)\n                        blockSize = numberOfBytes;\n\n                    __try\n                    {\n                        memcpy(buffer, address, blockSize);\n                    }\n                    __except (EXCEPTION_EXECUTE_HANDLER)\n                    {\n                        wprintf(L\"Error reading address near %Ix.\\n\", (ULONG_PTR)address);\n                        goto EndCommand;\n                    }\n\n                    // Print hex dump\n                    for (i = 0; i < blockSize; i++)\n                        wprintf(L\"%02x \", buffer[i]);\n\n                    // Fill remaining space (for last, possibly partial block)\n                    for (; i < sizeof(buffer); i++)\n                        wprintf(L\"   \");\n\n                    wprintf(L\"   \");\n\n                    // Print ASCII dump\n                    for (i = 0; i < blockSize; i++)\n                        putwchar((ULONG)(buffer[i] - ' ') <= (ULONG)('~' - ' ') ? buffer[i] : '.');\n\n                    wprintf(L\"\\n\");\n\n                    address += blockSize;\n                    numberOfBytes -= blockSize;\n                }\n            }\n\n            goto EndCommand;\nPrintMemUsage:\n            wprintf(L\"Usage: mem address [numberOfBytes]\\n\");\n            wprintf(L\"Example: mem 12345678 16\\n\");\n        }\n        else\n        {\n            wprintf(L\"Unrecognized command.\\n\");\n            goto EndCommand; // get rid of the compiler warning about the label being unreferenced\n        }\n\nEndCommand:\n        PhDrainAutoPool(&autoPool);\n    }\n\n    PhDereferenceObject(DebugConsoleSymbolProvider);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "SystemInformer/delayhook.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2022-2023\n *\n */\n\n#include <phapp.h>\n#include <apiimport.h>\n#include <mapldr.h>\n#include <thirdparty.h>\n#include <vsstyle.h>\n#include <uxtheme.h>\n#include <Vssym32.h>\n\n#include \"settings.h\"\n#include <phsettings.h>\n\n// https://learn.microsoft.com/en-us/windows/win32/winmsg/about-window-procedures#window-procedure-superclassing\nstatic WNDPROC PhDefaultMenuWindowProcedure = NULL;\nstatic WNDPROC PhDefaultDialogWindowProcedure = NULL;\nstatic WNDPROC PhDefaultRebarWindowProcedure = NULL;\nstatic WNDPROC PhDefaultComboBoxWindowProcedure = NULL;\nstatic WNDPROC PhDefaultStaticWindowProcedure = NULL;\nstatic WNDPROC PhDefaultStatusbarWindowProcedure = NULL;\nstatic WNDPROC PhDefaultEditWindowProcedure = NULL;\nstatic WNDPROC PhDefaultHeaderWindowProcedure = NULL;\nstatic BOOLEAN PhDefaultEnableStreamerMode = FALSE;\nstatic BOOLEAN PhDefaultEnableThemeAcrylicWindowSupport = FALSE;\nstatic BOOLEAN PhDefaultEnableThemeAnimation = FALSE;\n\nLRESULT CALLBACK PhMenuWindowHookProcedure(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (WindowMessage)\n    {\n    case WM_NCCREATE:\n        {\n            //CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;\n\n            if (PhEnableThemeSupport)\n            {\n                HFONT fontHandle;\n                LONG windowDpi = PhGetWindowDpi(WindowHandle);\n\n                if (fontHandle = PhCreateMessageFont(windowDpi))\n                {\n                    PhSetWindowContext(WindowHandle, (ULONG)'font', fontHandle);\n                    SetWindowFont(WindowHandle, fontHandle, TRUE);\n                }\n            }\n        }\n        break;\n    case WM_CREATE:\n        {\n            //CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;\n\n            if (PhDefaultEnableStreamerMode)\n            {\n                SetWindowDisplayAffinity(WindowHandle, WDA_EXCLUDEFROMCAPTURE);\n            }\n\n            if (PhEnableThemeSupport)\n            {\n                if (PhEnableThemeAcrylicSupport)\n                {\n                    // Note: DWM crashes if called from WM_NCCREATE (dmex)\n                    PhSetWindowAcrylicCompositionColor(WindowHandle, MakeABGRFromCOLORREF(0, RGB(10, 10, 10)));\n                }\n            }\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            if (PhEnableThemeSupport)\n            {\n                HFONT fontHandle;\n\n                fontHandle = PhGetWindowContext(WindowHandle, (ULONG)'font');\n                PhRemoveWindowContext(WindowHandle, (ULONG)'font');\n\n                if (fontHandle)\n                {\n                    DeleteFont(fontHandle);\n                }\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(PhDefaultMenuWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n}\n\nLRESULT CALLBACK PhDialogWindowHookProcedure(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (WindowMessage)\n    {\n    case WM_CREATE:\n        {\n            //CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;\n            //IsTopLevelWindow(createStruct->hwndParent)\n\n            if (WindowHandle == GetAncestor(WindowHandle, GA_ROOT))\n            {\n                if (PhDefaultEnableStreamerMode)\n                {\n                    SetWindowDisplayAffinity(WindowHandle, WDA_EXCLUDEFROMCAPTURE);\n                }\n\n                if (PhEnableThemeSupport && PhDefaultEnableThemeAcrylicWindowSupport)\n                {\n                    // Note: DWM crashes if called from WM_NCCREATE (dmex)\n                    PhSetWindowAcrylicCompositionColor(WindowHandle, MakeABGRFromCOLORREF(0, RGB(10, 10, 10)));\n                }\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(PhDefaultDialogWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n}\n\nLRESULT CALLBACK PhRebarWindowHookProcedure(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (WindowMessage)\n    {\n    case WM_CTLCOLOREDIT:\n        {\n            HDC hdc = (HDC)wParam;\n\n            SetBkMode(hdc, TRANSPARENT);\n            SetTextColor(hdc, PhThemeWindowTextColor);\n            SetDCBrushColor(hdc, PhThemeWindowBackground2Color);\n            return (INT_PTR)PhGetStockBrush(DC_BRUSH);\n        }\n        break;\n    }\n\n    return CallWindowProc(PhDefaultRebarWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n}\n\nLRESULT CALLBACK PhComboBoxWindowHookProcedure(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    LRESULT result = CallWindowProc(PhDefaultComboBoxWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n\n    switch (WindowMessage)\n    {\n    case WM_NCCREATE:\n        {\n            //CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;\n            COMBOBOXINFO info = { sizeof(COMBOBOXINFO) };\n\n            if (SendMessage(WindowHandle, CB_GETCOMBOBOXINFO, 0, (LPARAM)&info))\n            {\n                if (PhDefaultEnableStreamerMode)\n                {\n                    SetWindowDisplayAffinity(info.hwndList, WDA_EXCLUDEFROMCAPTURE);\n                }\n            }\n        }\n        break;\n    }\n\n    return result;\n}\n\nLRESULT CALLBACK PhStaticWindowHookProcedure(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    if (WindowMessage == WM_NCCREATE)\n    {\n        ULONG style = PhGetWindowStyle(WindowHandle);\n\n        if ((style & SS_ICON) == SS_ICON)\n        {\n            PhSetWindowContext(WindowHandle, SCHAR_MAX, UlongToPtr(TRUE));\n        }\n    }\n\n    if (WindowMessage != WM_KILLFOCUS && !PhGetWindowContext(WindowHandle, SCHAR_MAX))\n        return CallWindowProc(PhDefaultStaticWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n\n    switch (WindowMessage)\n    {\n    case WM_NCDESTROY:\n        PhRemoveWindowContext(WindowHandle, SCHAR_MAX);\n        break;\n    case WM_ERASEBKGND:\n        return TRUE;\n    case WM_KILLFOCUS:\n        {\n            WCHAR windowClassName[MAX_PATH];\n            HWND ParentHandle = GetParent(WindowHandle);\n            if (!GetClassName(ParentHandle, windowClassName, RTL_NUMBER_OF(windowClassName)))\n                windowClassName[0] = UNICODE_NULL;\n            if (PhEqualStringZ(windowClassName, L\"CHECKLIST_ACLUI\", FALSE))\n            {\n                RECT rectClient;\n\n                if (PhGetClientRect(WindowHandle, &rectClient))\n                {\n                    PhInflateRect(&rectClient, 2, 2);\n                    MapWindowRect(WindowHandle, ParentHandle, &rectClient);\n                    InvalidateRect(ParentHandle, &rectClient, TRUE);     // fix the annoying white border left by the previous active control\n                }\n            }\n        }\n        break;\n    case WM_PAINT:\n        {\n            HICON iconHandle;\n            PAINTSTRUCT ps;\n            RECT clientRect;\n            WCHAR windowClassName[MAX_PATH];\n\n            if (!GetClassName(GetParent(WindowHandle), windowClassName, RTL_NUMBER_OF(windowClassName)))\n                windowClassName[0] = UNICODE_NULL;\n            if (PhEqualStringZ(windowClassName, L\"CHECKLIST_ACLUI\", FALSE))\n            {\n                if (iconHandle = (HICON)(UINT_PTR)CallWindowProc(PhDefaultStaticWindowProcedure, WindowHandle, STM_GETICON, 0, 0))\n                {\n                    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n                    static HFONT hCheckFont = NULL;\n\n                    HDC hdc = BeginPaint(WindowHandle, &ps);\n                    clientRect = ps.rcPaint;\n                    HDC bufferDc = CreateCompatibleDC(hdc);\n                    HBITMAP bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom);\n                    HBITMAP oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap);\n\n                    enum { nocheck, check, graycheck } checkType = nocheck;\n                    INT startX = clientRect.left + (clientRect.right - clientRect.bottom) / 2 + 1;\n                    INT startY = clientRect.top + (clientRect.bottom - clientRect.top) / 2;\n\n                    DrawIconEx(bufferDc, clientRect.left, clientRect.top, iconHandle, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top,\n                        0, NULL, DI_NORMAL);\n\n                    for (INT x = startX, y = startY; x < clientRect.right; x++)\n                    {\n                        COLORREF pixel = GetPixel(bufferDc, x, y);\n                        if (pixel == RGB(0xB4, 0xB4, 0xB4))\n                        {\n                            checkType = graycheck;\n                            goto draw_acl_check;\n                        }\n                    }\n                    for (INT x = startX, y = startY; x < clientRect.right; x++)\n                    {\n                        COLORREF pixel = GetPixel(bufferDc, x, y);\n                        if (pixel == RGB(0, 0, 0) || pixel == PhThemeWindowTextColor)\n                        {\n                            checkType = check;\n                            goto draw_acl_check;\n                        }\n                    }\n\n                draw_acl_check:\n                    if (checkType == check || checkType == graycheck)   // right is checked or special permission checked\n                    {\n                        if (PhBeginInitOnce(&initOnce)) // cache font\n                        {\n                            hCheckFont = CreateFont(\n                                clientRect.bottom - clientRect.top - 1,\n                                clientRect.right - clientRect.left - 3,\n                                0, 0,\n                                FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,\n                                CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,\n                                VARIABLE_PITCH, L\"Segoe UI\");\n                            PhEndInitOnce(&initOnce);\n                        }\n\n                        SetBkMode(hdc, TRANSPARENT);\n                        SetTextColor(hdc, checkType == check ? PhThemeWindowTextColor : RGB(0xB4, 0xB4, 0xB4));\n                        SelectFont(hdc, hCheckFont);\n                        //HFONT hFontOriginal = SelectFont(hdc, hCheckFont);\n                        FillRect(hdc, &clientRect, PhThemeWindowBackgroundBrush);\n                        DrawText(hdc, L\"✓\", 1, &clientRect, DT_CENTER | DT_VCENTER);\n                        //SelectFont(hdc, hFontOriginal);\n                    }\n\n                    SelectBitmap(bufferDc, oldBufferBitmap);\n                    DeleteBitmap(bufferBitmap);\n                    DeleteDC(bufferDc);\n                    EndPaint(WindowHandle, &ps);\n                    return 0;\n                }\n            }\n            //else if (iconHandle = (HICON)(UINT_PTR)CallWindowProc(PhDefaultStaticWindowProcedure, WindowHandle, STM_GETICON, 0, 0)) // Static_GetIcon(WindowHandle, 0)\n            //{\n            //    PAINTSTRUCT ps;\n            //    if (PhGetWindowContext(GetParent(WindowHandle), LONG_MAX) &&\n            //        BeginPaint(WindowHandle, &ps))\n            //    {\n            //        // Fix artefacts when window moving back from off-screen (Dart Vanya)\n            //        hdc = GetDC(WindowHandle);\n            //        GetClientRect(WindowHandle, &clientRect);\n\n            //        FillRect(hdc, &clientRect, PhThemeWindowBackgroundBrush);\n\n            //        DrawIconEx(\n            //            hdc,\n            //            clientRect.left,\n            //            clientRect.top,\n            //            iconHandle,\n            //            clientRect.right - clientRect.left,\n            //            clientRect.bottom - clientRect.top,\n            //            0,\n            //            NULL,\n            //            DI_NORMAL\n            //            );\n\n            //        ReleaseDC(WindowHandle, hdc);\n            //        EndPaint(WindowHandle, &ps);\n            //    }\n            //}\n        }\n    }\n\n    return CallWindowProc(PhDefaultStaticWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n}\n\ntypedef struct _PHP_THEME_WINDOW_STATUSBAR_CONTEXT\n{\n    struct\n    {\n       BOOLEAN Flags;\n       union\n       {\n            BOOLEAN NonMouseActive : 1;\n            BOOLEAN MouseActive : 1;\n            BOOLEAN HotTrack : 1;\n            BOOLEAN Hot : 1;\n            BOOLEAN Spare : 4;\n       };\n    };\n\n    HTHEME ThemeHandle;\n    POINT CursorPos;\n\n    HDC BufferedDc;\n    HBITMAP BufferedOldBitmap;\n    HBITMAP BufferedBitmap;\n    RECT BufferedContextRect;\n} PHP_THEME_WINDOW_STATUSBAR_CONTEXT, *PPHP_THEME_WINDOW_STATUSBAR_CONTEXT;\n\nVOID ThemeWindowStatusBarCreateBufferedContext(\n    _In_ PPHP_THEME_WINDOW_STATUSBAR_CONTEXT Context,\n    _In_ HDC Hdc,\n    _In_ PRECT BufferRect\n    )\n{\n    Context->BufferedDc = CreateCompatibleDC(Hdc);\n\n    if (!Context->BufferedDc)\n        return;\n\n    Context->BufferedContextRect = *BufferRect;\n    Context->BufferedBitmap = CreateCompatibleBitmap(\n        Hdc,\n        BufferRect->right,\n        BufferRect->bottom\n        );\n\n    Context->BufferedOldBitmap = SelectBitmap(Context->BufferedDc, Context->BufferedBitmap);\n}\n\nVOID ThemeWindowStatusBarDestroyBufferedContext(\n    _In_ PPHP_THEME_WINDOW_STATUSBAR_CONTEXT Context\n    )\n{\n    if (Context->BufferedDc && Context->BufferedOldBitmap)\n    {\n        SelectBitmap(Context->BufferedDc, Context->BufferedOldBitmap);\n    }\n\n    if (Context->BufferedBitmap)\n    {\n        DeleteBitmap(Context->BufferedBitmap);\n        Context->BufferedBitmap = NULL;\n    }\n\n    if (Context->BufferedDc)\n    {\n        DeleteDC(Context->BufferedDc);\n        Context->BufferedDc = NULL;\n    }\n}\n\nLONG ThemeWindowStatusBarUpdateRectToIndex(\n    _In_ HWND WindowHandle,\n    _In_ WNDPROC WindowProcedure,\n    _In_ PRECT UpdateRect,\n    _In_ LONG Count\n    )\n{\n    for (LONG i = 0; i < Count; i++)\n    {\n        RECT blockRect = { 0 };\n\n        if (!CallWindowProc(WindowProcedure, WindowHandle, SB_GETRECT, (WPARAM)i, (WPARAM)&blockRect))\n            continue;\n\n        if (\n            UpdateRect->bottom == blockRect.bottom &&\n            //UpdateRect->left == blockRect.left &&\n            UpdateRect->right == blockRect.right\n            //UpdateRect->top == blockRect.top\n            )\n        {\n            return i;\n        }\n    }\n\n    return INT_ERROR;\n}\n\nVOID ThemeWindowStatusBarDrawPart(\n    _In_ PPHP_THEME_WINDOW_STATUSBAR_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HDC bufferDc,\n    _In_ PRECT clientRect,\n    _In_ LONG Index\n    )\n{\n    RECT blockRect = { 0 };\n    WCHAR text[0x80] = { 0 };\n\n    if (!CallWindowProc(PhDefaultStatusbarWindowProcedure, WindowHandle, SB_GETRECT, (WPARAM)Index, (WPARAM)&blockRect))\n        return;\n    if (!RectVisible(bufferDc, &blockRect))\n        return;\n    if (CallWindowProc(PhDefaultStatusbarWindowProcedure, WindowHandle, SB_GETTEXTLENGTH, (WPARAM)Index, 0) >= RTL_NUMBER_OF(text))\n        return;\n    if (!CallWindowProc(PhDefaultStatusbarWindowProcedure, WindowHandle, SB_GETTEXT, (WPARAM)Index, (LPARAM)text))\n        return;\n\n    if (PhPtInRect(&blockRect, &Context->CursorPos))\n    {\n        SetTextColor(bufferDc, PhThemeWindowTextColor);\n        SetDCBrushColor(bufferDc, PhThemeWindowHighlightColor);\n        blockRect.left -= 3, blockRect.top -= 1;\n        FillRect(bufferDc, &blockRect, PhGetStockBrush(DC_BRUSH));\n        blockRect.left += 3, blockRect.top += 1;\n    }\n    else\n    {\n        RECT separator;\n        SetTextColor(bufferDc, PhThemeWindowTextColor);\n        FillRect(bufferDc, &blockRect, PhThemeWindowBackgroundBrush);\n\n        separator = blockRect;\n        separator.left = separator.right - 1;\n        PhInflateRect(&separator, 0, -1);\n        SetDCBrushColor(bufferDc, PhThemeWindowHighlightColor);\n        FillRect(bufferDc, &separator, PhGetStockBrush(DC_BRUSH));\n    }\n\n    blockRect.left += 2, blockRect.bottom -= 1;\n    DrawText(\n        bufferDc,\n        text,\n        (UINT)PhCountStringZ(text),\n        &blockRect,\n        DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX\n        );\n    blockRect.left -= 2, blockRect.bottom += 1;\n}\n\nVOID ThemeWindowRenderStatusBar(\n    _In_ PPHP_THEME_WINDOW_STATUSBAR_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HDC bufferDc,\n    _In_ PRECT clientRect\n    )\n{\n    SetBkMode(bufferDc, TRANSPARENT);\n    SelectFont(bufferDc, GetWindowFont(WindowHandle));\n\n    FillRect(bufferDc, clientRect, PhThemeWindowBackgroundBrush);\n\n    LONG blockCount = (LONG)CallWindowProc(\n        PhDefaultStatusbarWindowProcedure,\n        WindowHandle,\n        SB_GETPARTS,\n        0, 0\n        );\n\n    //INT index = ThemeWindowStatusBarUpdateRectToIndex( // used with BeginBufferedPaint (dmex)\n    //    WindowHandle,\n    //    WindowProcedure,\n    //    clientRect,\n    //    blockCount\n    //    );\n    //\n    //if (index == UINT_MAX)\n    {\n        RECT sizeGripRect;\n        LONG dpi;\n\n        dpi = PhGetWindowDpi(WindowHandle);\n        sizeGripRect.left = clientRect->right - PhGetSystemMetrics(SM_CXHSCROLL, dpi);\n        sizeGripRect.top = clientRect->bottom - PhGetSystemMetrics(SM_CYVSCROLL, dpi);\n        sizeGripRect.right = clientRect->right;\n        sizeGripRect.bottom = clientRect->bottom;\n\n        if (Context->ThemeHandle)\n        {\n            //if (IsThemeBackgroundPartiallyTransparent(Context->ThemeHandle, SP_GRIPPER, 0))\n            //    DrawThemeParentBackground(WindowHandle, bufferDc, NULL);\n\n            PhDrawThemeBackground(Context->ThemeHandle, bufferDc, SP_GRIPPER, 0, &sizeGripRect, &sizeGripRect);\n        }\n        else\n        {\n            DrawFrameControl(bufferDc, &sizeGripRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);\n        }\n\n        // Top statusbar border will be drawn by bottom tabcontrol border\n\n        for (LONG i = 0; i < blockCount; i++)\n        {\n            ThemeWindowStatusBarDrawPart(Context, WindowHandle, bufferDc, clientRect, i);\n        }\n    }\n    //else\n    //{\n    //    ThemeWindowStatusBarDrawPart(Context, WindowHandle, bufferDc, clientRect, WindowProcedure, index);\n    //}\n}\n\nLRESULT CALLBACK PhStatusBarWindowHookProcedure(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_THEME_WINDOW_STATUSBAR_CONTEXT context = NULL;\n\n    if (WindowMessage == WM_NCCREATE)\n    {\n        context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_STATUSBAR_CONTEXT));\n        context->ThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_STATUS, PhGetWindowDpi(WindowHandle));\n        context->CursorPos.x = LONG_MIN;\n        context->CursorPos.y = LONG_MIN;\n        PhSetWindowContext(WindowHandle, LONG_MAX, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(WindowHandle, LONG_MAX);\n    }\n\n    if (context)\n    {\n        switch (WindowMessage)\n        {\n        case WM_NCDESTROY:\n            {\n                PhRemoveWindowContext(WindowHandle, LONG_MAX);\n\n                ThemeWindowStatusBarDestroyBufferedContext(context);\n\n                if (context->ThemeHandle)\n                {\n                    PhCloseThemeData(context->ThemeHandle);\n                }\n\n                PhFree(context);\n            }\n            break;\n        case WM_THEMECHANGED:\n            {\n                if (context->ThemeHandle)\n                {\n                    PhCloseThemeData(context->ThemeHandle);\n                    context->ThemeHandle = NULL;\n                }\n\n                context->ThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_STATUS, PhGetWindowDpi(WindowHandle));\n            }\n            break;\n        case WM_ERASEBKGND:\n            return TRUE;\n        case WM_MOUSEMOVE:\n            {\n                if (!context->MouseActive)\n                {\n                    TRACKMOUSEEVENT trackEvent =\n                    {\n                        sizeof(TRACKMOUSEEVENT),\n                        TME_LEAVE,\n                        WindowHandle,\n                        0\n                    };\n\n                    TrackMouseEvent(&trackEvent);\n                    context->MouseActive = TRUE;\n                }\n\n                context->CursorPos.x = GET_X_LPARAM(lParam);\n                context->CursorPos.y = GET_Y_LPARAM(lParam);\n\n                InvalidateRect(WindowHandle, NULL, FALSE);\n            }\n            break;\n        case WM_MOUSELEAVE:\n            {\n                context->MouseActive = FALSE;\n                context->CursorPos.x = LONG_MIN;\n                context->CursorPos.y = LONG_MIN;\n\n                InvalidateRect(WindowHandle, NULL, FALSE);\n            }\n            break;\n        case WM_PAINT:\n            {\n                //PAINTSTRUCT ps;\n                //HDC BufferedHDC;\n                //HPAINTBUFFER BufferedPaint;\n                //\n                //if (!BeginPaint(WindowHandle, &ps))\n                //    break;\n                //\n                //if (BufferedPaint = BeginBufferedPaint(ps.hdc, &ps.rcPaint, BPBF_COMPATIBLEBITMAP, NULL, &BufferedHDC))\n                //{\n                //    ThemeWindowRenderStatusBar(context, WindowHandle, BufferedHDC, &ps.rcPaint, oldWndProc);\n                //    EndBufferedPaint(BufferedPaint, TRUE);\n                //}\n                //else\n                {\n                    RECT clientRect;\n                    RECT bufferRect;\n                    HDC hdc;\n\n                    if (!PhGetClientRect(WindowHandle, &clientRect))\n                        break;\n\n                    bufferRect.left = 0;\n                    bufferRect.top = 0;\n                    bufferRect.right = clientRect.right - clientRect.left;\n                    bufferRect.bottom = clientRect.bottom - clientRect.top;\n\n                    hdc = GetDC(WindowHandle);\n\n                    if (context->BufferedDc && (\n                        context->BufferedContextRect.right < bufferRect.right ||\n                        context->BufferedContextRect.bottom < bufferRect.bottom))\n                    {\n                        ThemeWindowStatusBarDestroyBufferedContext(context);\n                    }\n\n                    if (!context->BufferedDc)\n                    {\n                        ThemeWindowStatusBarCreateBufferedContext(context, hdc, &bufferRect);\n                    }\n\n                    if (context->BufferedDc)\n                    {\n                        ThemeWindowRenderStatusBar(\n                            context,\n                            WindowHandle,\n                            context->BufferedDc,\n                            &clientRect\n                            );\n\n                        BitBlt(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, context->BufferedDc, 0, 0, SRCCOPY);\n                    }\n\n                    ReleaseDC(WindowHandle, hdc);\n                }\n\n                //EndPaint(WindowHandle, &ps);\n            }\n            goto DefaultWndProc;\n        }\n    }\n\n    return CallWindowProc(PhDefaultStatusbarWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n\nDefaultWndProc:\n    return DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n}\n\nLRESULT CALLBACK PhEditWindowHookProcedure(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (WindowMessage)\n    {\n    case WM_NCPAINT:\n        {\n            HDC hdc;\n            ULONG flags;\n            RECT windowRect;\n            HRGN updateRegion;\n\n            // The searchbox control does its own theme drawing.\n            if (PhGetWindowContext(WindowHandle, SHRT_MAX))\n                break;\n            if (!PhGetWindowRect(WindowHandle, &windowRect))\n                break;\n\n            updateRegion = (HRGN)wParam;\n\n            if (updateRegion == HRGN_FULL)\n                updateRegion = NULL;\n\n            flags = DCX_WINDOW | DCX_CACHE | DCX_USESTYLE;\n\n            if (updateRegion)\n                flags |= DCX_INTERSECTRGN | DCX_NODELETERGN;\n\n            if (hdc = GetDCEx(WindowHandle, updateRegion, flags))\n            {\n                PhOffsetRect(&windowRect, -windowRect.left, -windowRect.top);\n\n                if (GetFocus() == WindowHandle)\n                {\n                    // A little bit nicer and contrast color (Dart Vanya)\n                    SetDCBrushColor(hdc, PhMakeColorBrighter(GetSysColor(COLOR_HOTLIGHT), 85)); // PhThemeWindowHighlightColor\n                    FrameRect(hdc, &windowRect, PhGetStockBrush(DC_BRUSH));\n                }\n                else\n                {\n                    SetDCBrushColor(hdc, PhThemeWindowBackground2Color);\n                    FrameRect(hdc, &windowRect, PhGetStockBrush(DC_BRUSH));\n                }\n\n                ReleaseDC(WindowHandle, hdc);\n                return 0;\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(PhDefaultEditWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n}\n\ntypedef struct _PHP_THEME_WINDOW_HEADER_CONTEXT\n{\n    HTHEME ThemeHandle;\n    BOOLEAN MouseActive;\n    POINT CursorPos;\n} PHP_THEME_WINDOW_HEADER_CONTEXT, *PPHP_THEME_WINDOW_HEADER_CONTEXT;\n\nVOID ThemeWindowRenderHeaderControl(\n    _In_ PPHP_THEME_WINDOW_HEADER_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HDC bufferDc,\n    _In_ PRECT clientRect\n    )\n{\n    SetBkMode(bufferDc, TRANSPARENT);\n    SelectFont(bufferDc, GetWindowFont(WindowHandle));\n\n    FillRect(bufferDc, clientRect, PhThemeWindowBackgroundBrush);\n\n    //INT headerItemCount = Header_GetItemCount(WindowHandle);\n    INT headerItemCount = (INT)CallWindowProc(\n        PhDefaultHeaderWindowProcedure,\n        WindowHandle,\n        HDM_GETITEMCOUNT,\n        0, 0\n        );\n\n    for (INT i = 0; i < headerItemCount; i++)\n    {\n        RECT headerRect = { 0 };\n\n        //Header_GetItemRect(WindowHandle, i, &headerRect);\n        if (!(BOOL)CallWindowProc(\n            PhDefaultHeaderWindowProcedure,\n            WindowHandle,\n            HDM_GETITEMRECT,\n            (WPARAM)i,\n            (LPARAM)&headerRect\n            ))\n        {\n            continue;\n        }\n\n        if (PhPtInRect(&headerRect, &Context->CursorPos))\n        {\n            SetTextColor(bufferDc, PhThemeWindowTextColor);\n            SetDCBrushColor(bufferDc, PhThemeWindowBackground2Color); // PhThemeWindowHighlightColor);\n            FillRect(bufferDc, &headerRect, PhGetStockBrush(DC_BRUSH));\n            //FrameRect(bufferDc, &headerRect, GetSysColorBrush(COLOR_HIGHLIGHT));\n        }\n        else\n        {\n            SetTextColor(bufferDc, PhThemeWindowTextColor);\n            FillRect(bufferDc, &headerRect, PhThemeWindowBackgroundBrush);\n\n            //FrameRect(hdc, &headerRect, GetSysColorBrush(COLOR_HIGHLIGHT));\n            //SetDCPenColor(hdc, RGB(0, 255, 0));\n            //SetDCBrushColor(hdc, RGB(0, 255, 0));\n            //DrawEdge(hdc, &headerRect, BDR_RAISEDOUTER | BF_FLAT, BF_RIGHT);\n\n            //RECT frameRect;\n            //frameRect.bottom = headerRect.bottom - 2;\n            //frameRect.left = headerRect.right - 1;\n            //frameRect.right = headerRect.right;\n            //frameRect.top = headerRect.top;\n            //SetDCBrushColor(hdc, RGB(68, 68, 68)); // RGB(0x77, 0x77, 0x77));\n            //FrameRect(hdc, &headerRect, PhGetStockBrush(DC_BRUSH));\n\n            //PatBlt(DrawInfo->hDC, DrawInfo->rcItem.right - 1, DrawInfo->rcItem.top, 1, DrawInfo->rcItem.bottom - DrawInfo->rcItem.top, PATCOPY);\n            //PatBlt(DrawInfo->hDC, DrawInfo->rcItem.left, DrawInfo->rcItem.bottom - 1, DrawInfo->rcItem.right - DrawInfo->rcItem.left, 1, PATCOPY);\n            DrawEdge(bufferDc, &headerRect, BDR_RAISEDOUTER, BF_RIGHT);\n        }\n\n        INT drawTextFlags = DT_SINGLELINE | DT_HIDEPREFIX | DT_WORD_ELLIPSIS;\n        WCHAR headerText[0x80] = { 0 };\n        HDITEM headerItem;\n\n        ZeroMemory(&headerItem, sizeof(HDITEM));\n        headerItem.mask = HDI_TEXT | HDI_FORMAT;\n        headerItem.cchTextMax = MAX_PATH;\n        headerItem.pszText = headerText;\n\n        //Header_GetItem(WindowHandle, i, &headerItem);\n        if (!(BOOL)CallWindowProc(\n            PhDefaultHeaderWindowProcedure,\n            WindowHandle,\n            HDM_GETITEM,\n            (WPARAM)i,\n            (LPARAM)&headerItem\n            ))\n        {\n            break;\n        }\n\n        if (headerItem.fmt & HDF_SORTUP)\n        {\n            if (Context->ThemeHandle)\n            {\n                RECT sortArrowRect = headerRect;\n                SIZE sortArrowSize;\n\n                if (PhGetThemePartSize(\n                    Context->ThemeHandle,\n                    bufferDc,\n                    HP_HEADERSORTARROW,\n                    HSAS_SORTEDUP,\n                    NULL,\n                    THEMEPARTSIZE_TRUE,\n                    &sortArrowSize\n                    ))\n                {\n                    sortArrowRect.bottom = sortArrowSize.cy;\n                }\n\n                PhDrawThemeBackground(\n                    Context->ThemeHandle,\n                    bufferDc,\n                    HP_HEADERSORTARROW,\n                    HSAS_SORTEDUP,\n                    &sortArrowRect,\n                    NULL\n                    );\n            }\n        }\n        else if (headerItem.fmt & HDF_SORTDOWN)\n        {\n            if (Context->ThemeHandle)\n            {\n                RECT sortArrowRect = headerRect;\n                SIZE sortArrowSize;\n\n                if (PhGetThemePartSize(\n                    Context->ThemeHandle,\n                    bufferDc,\n                    HP_HEADERSORTARROW,\n                    HSAS_SORTEDDOWN,\n                    NULL,\n                    THEMEPARTSIZE_TRUE,\n                    &sortArrowSize\n                    ))\n                {\n                    sortArrowRect.bottom = sortArrowSize.cy;\n                }\n\n                PhDrawThemeBackground(\n                    Context->ThemeHandle,\n                    bufferDc,\n                    HP_HEADERSORTARROW,\n                    HSAS_SORTEDDOWN,\n                    &sortArrowRect,\n                    NULL\n                    );\n            }\n        }\n\n        if (headerItem.fmt & HDF_RIGHT)\n            drawTextFlags |= DT_VCENTER | DT_RIGHT;\n        else\n            drawTextFlags |= DT_VCENTER | DT_LEFT;\n\n        headerRect.left += 4;\n        headerRect.right -= 8;\n        DrawText(\n            bufferDc,\n            headerText,\n            (UINT)PhCountStringZ(headerText),\n            &headerRect,\n            drawTextFlags\n            );\n    }\n}\n\nLRESULT CALLBACK PhHeaderWindowHookProcedure(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_THEME_WINDOW_HEADER_CONTEXT context = NULL;\n\n    if (WindowMessage == WM_NCCREATE)\n    {\n        CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;\n\n        if (createStruct->hwndParent)\n        {\n            WCHAR windowClassName[MAX_PATH];\n\n            if (!GetClassName(createStruct->hwndParent, windowClassName, RTL_NUMBER_OF(windowClassName)))\n                windowClassName[0] = UNICODE_NULL;\n\n            if (PhEqualStringZ(windowClassName, L\"PhTreeNew\", FALSE))\n            {\n                ULONG windowStyle = PhGetWindowStyle(createStruct->hwndParent);\n\n                if (BooleanFlagOn(windowStyle, TN_STYLE_CUSTOM_HEADERDRAW))\n                {\n                    PhSetControlTheme(WindowHandle, L\"DarkMode_ItemsView\");\n\n                    return CallWindowProc(PhDefaultHeaderWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n                }\n            }\n        }\n\n        context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT));\n        context->ThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_HEADER, PhGetWindowDpi(WindowHandle));\n        context->CursorPos.x = LONG_MIN;\n        context->CursorPos.y = LONG_MIN;\n        PhSetWindowContext(WindowHandle, LONG_MAX, context);\n\n        PhSetControlTheme(WindowHandle, L\"DarkMode_ItemsView\");\n\n        InvalidateRect(WindowHandle, NULL, FALSE);\n    }\n    else\n    {\n        context = PhGetWindowContext(WindowHandle, LONG_MAX);\n    }\n\n    if (context)\n    {\n        switch (WindowMessage)\n        {\n        case WM_NCDESTROY:\n            {\n                PhRemoveWindowContext(WindowHandle, LONG_MAX);\n\n                if (context->ThemeHandle)\n                {\n                    PhCloseThemeData(context->ThemeHandle);\n                }\n\n                PhFree(context);\n            }\n            break;\n        case WM_THEMECHANGED:\n            {\n                if (context->ThemeHandle)\n                {\n                    PhCloseThemeData(context->ThemeHandle);\n                    context->ThemeHandle = NULL;\n                }\n\n                context->ThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_HEADER, PhGetWindowDpi(WindowHandle));\n            }\n            break;\n        case WM_ERASEBKGND:\n            return TRUE;\n        case WM_MOUSEMOVE:\n            {\n                if (GetCapture() == WindowHandle)\n                    break;\n\n                if (!context->MouseActive)\n                {\n                    TRACKMOUSEEVENT trackEvent =\n                    {\n                        sizeof(TRACKMOUSEEVENT),\n                        TME_LEAVE,\n                        WindowHandle,\n                        0\n                    };\n\n                    TrackMouseEvent(&trackEvent);\n                    context->MouseActive = TRUE;\n                }\n\n                context->CursorPos.x = GET_X_LPARAM(lParam);\n                context->CursorPos.y = GET_Y_LPARAM(lParam);\n\n                InvalidateRect(WindowHandle, NULL, FALSE);\n            }\n            break;\n        case WM_CONTEXTMENU:\n            {\n                LRESULT result = CallWindowProc(PhDefaultHeaderWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n\n                InvalidateRect(WindowHandle, NULL, TRUE);\n\n                return result;\n            }\n            break;\n        case WM_MOUSELEAVE:\n            {\n                LRESULT result = CallWindowProc(PhDefaultHeaderWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n\n                context->MouseActive = FALSE;\n                context->CursorPos.x = LONG_MIN;\n                context->CursorPos.y = LONG_MIN;\n\n                InvalidateRect(WindowHandle, NULL, TRUE);\n\n                return result;\n            }\n            break;\n        case WM_PAINT:\n            {\n                // Don't apply header theme for unsupported dialogs: Advanced Security, Digital Signature Details, etc. (Dart Vanya)\n                if (!PhIsDarkModeAllowedForWindow(GetParent(WindowHandle)))\n                {\n                    PhRemoveWindowContext(WindowHandle, LONG_MAX);\n                    if (context->ThemeHandle)\n                        PhCloseThemeData(context->ThemeHandle);\n                    PhFree(context);\n                    PhSetControlTheme(WindowHandle, L\"Explorer\");\n                    break;\n                }\n\n                //PAINTSTRUCT ps;\n                //HDC BufferedHDC;\n                //HPAINTBUFFER BufferedPaint;\n                //\n                //if (!BeginPaint(WindowHandle, &ps))\n                //    break;\n                //\n                //DEBUG_BEGINPAINT_RECT(WindowHandle, ps.rcPaint);\n                //\n                //if (BufferedPaint = BeginBufferedPaint(ps.hdc, &ps.rcPaint, BPBF_COMPATIBLEBITMAP, NULL, &BufferedHDC))\n                //{\n                //    ThemeWindowRenderHeaderControl(context, WindowHandle, BufferedHDC, &ps.rcPaint, oldWndProc);\n                //    EndBufferedPaint(BufferedPaint, TRUE);\n                //}\n                //else\n                {\n                    RECT clientRect;\n                    HDC hdc;\n                    HDC bufferDc;\n                    HBITMAP bufferBitmap;\n                    HBITMAP oldBufferBitmap;\n\n                    if (!PhGetClientRect(WindowHandle, &clientRect))\n                        break;\n\n                    hdc = GetDC(WindowHandle);\n                    bufferDc = CreateCompatibleDC(hdc);\n                    bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom);\n                    oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap);\n\n                    ThemeWindowRenderHeaderControl(context, WindowHandle, bufferDc, &clientRect);\n\n                    BitBlt(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, bufferDc, 0, 0, SRCCOPY);\n                    SelectBitmap(bufferDc, oldBufferBitmap);\n                    DeleteBitmap(bufferBitmap);\n                    DeleteDC(bufferDc);\n                    ReleaseDC(WindowHandle, hdc);\n                }\n\n                //EndPaint(WindowHandle, &ps);\n            }\n            goto DefaultWndProc;\n        }\n    }\n\n    return CallWindowProc(PhDefaultHeaderWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);\n\nDefaultWndProc:\n    return DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n}\n\nVOID PhRegisterDialogSuperClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };\n\n    if (!GetClassInfoEx(NULL, L\"#32770\", &wcex))\n        return;\n\n    PhDefaultDialogWindowProcedure = wcex.lpfnWndProc;\n    wcex.lpfnWndProc = PhDialogWindowHookProcedure;\n    wcex.style = wcex.style | CS_GLOBALCLASS;\n\n    UnregisterClass(L\"#32770\", NULL);\n    if (RegisterClassEx(&wcex) == INVALID_ATOM)\n    {\n        PhShowStatus(NULL, L\"Unable to register window class.\", 0, GetLastError());\n    }\n}\n\nVOID PhRegisterMenuSuperClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };\n\n    if (!GetClassInfoEx(NULL, L\"#32768\", &wcex))\n        return;\n\n    PhDefaultMenuWindowProcedure = wcex.lpfnWndProc;\n    wcex.lpfnWndProc = PhMenuWindowHookProcedure;\n    wcex.style = wcex.style | CS_GLOBALCLASS;\n\n    UnregisterClass(L\"#32768\", NULL);\n    if (RegisterClassEx(&wcex) == INVALID_ATOM)\n    {\n        PhShowStatus(NULL, L\"Unable to register window class.\", 0, GetLastError());\n    }\n}\n\nVOID PhRegisterRebarSuperClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };\n\n    if (!GetClassInfoEx(NULL, REBARCLASSNAME, &wcex))\n        return;\n\n    PhDefaultRebarWindowProcedure = wcex.lpfnWndProc;\n    wcex.lpfnWndProc = PhRebarWindowHookProcedure;\n    wcex.style = wcex.style | CS_GLOBALCLASS;\n\n    UnregisterClass(REBARCLASSNAME, NULL);\n    if (RegisterClassEx(&wcex) == INVALID_ATOM)\n    {\n        PhShowStatus(NULL, L\"Unable to register window class.\", 0, GetLastError());\n    }\n}\n\nVOID PhRegisterComboBoxSuperClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };\n\n    if (!GetClassInfoEx(NULL, WC_COMBOBOX, &wcex))\n        return;\n\n    PhDefaultComboBoxWindowProcedure = wcex.lpfnWndProc;\n    wcex.lpfnWndProc = PhComboBoxWindowHookProcedure;\n    wcex.style = wcex.style | CS_GLOBALCLASS;\n\n    UnregisterClass(WC_COMBOBOX, NULL);\n    if (RegisterClassEx(&wcex) == INVALID_ATOM)\n    {\n        PhShowStatus(NULL, L\"Unable to register window class.\", 0, GetLastError());\n    }\n}\n\nVOID PhRegisterStaticSuperClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };\n\n    if (!GetClassInfoEx(NULL, WC_STATIC, &wcex))\n        return;\n\n    PhDefaultStaticWindowProcedure = wcex.lpfnWndProc;\n    wcex.lpfnWndProc = PhStaticWindowHookProcedure;\n    wcex.style = wcex.style | CS_GLOBALCLASS;\n\n    UnregisterClass(WC_STATIC, NULL);\n    if (RegisterClassEx(&wcex) == INVALID_ATOM)\n    {\n        PhShowStatus(NULL, L\"Unable to register window class.\", 0, GetLastError());\n    }\n}\n\nVOID PhRegisterStatusBarSuperClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };\n\n    if (!GetClassInfoEx(NULL, STATUSCLASSNAME, &wcex))\n        return;\n\n    PhDefaultStatusbarWindowProcedure = wcex.lpfnWndProc;\n    wcex.lpfnWndProc = PhStatusBarWindowHookProcedure;\n    wcex.style = wcex.style | CS_GLOBALCLASS;\n\n    UnregisterClass(STATUSCLASSNAME, NULL);\n    if (RegisterClassEx(&wcex) == INVALID_ATOM)\n    {\n        PhShowStatus(NULL, L\"Unable to register window class.\", 0, GetLastError());\n    }\n}\n\nVOID PhRegisterEditSuperClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };\n\n    if (!GetClassInfoEx(NULL, WC_EDIT, &wcex))\n        return;\n\n    PhDefaultEditWindowProcedure = wcex.lpfnWndProc;\n    wcex.lpfnWndProc = PhEditWindowHookProcedure;\n    wcex.style = wcex.style | CS_GLOBALCLASS;\n\n    UnregisterClass(WC_EDIT, NULL);\n    if (RegisterClassEx(&wcex) == INVALID_ATOM)\n    {\n        PhShowStatus(NULL, L\"Unable to register window class.\", 0, GetLastError());\n    }\n}\n\nVOID PhRegisterHeaderSuperClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };\n\n    if (!GetClassInfoEx(NULL, WC_HEADER, &wcex))\n        return;\n\n    PhDefaultHeaderWindowProcedure = wcex.lpfnWndProc;\n    wcex.lpfnWndProc = PhHeaderWindowHookProcedure;\n    wcex.style = wcex.style | CS_GLOBALCLASS;\n\n    UnregisterClass(WC_HEADER, NULL);\n    if (RegisterClassEx(&wcex) == INVALID_ATOM)\n    {\n        PhShowStatus(NULL, L\"Unable to register window class.\", 0, GetLastError());\n    }\n}\n\n// Detours export procedure hooks\n\nstatic typeof(&DrawThemeBackground) DefaultDrawThemeBackground = NULL;\nstatic typeof(&DrawThemeBackgroundEx) DefaultDrawThemeBackgroundEx = NULL;\nstatic typeof(&DrawThemeText) DefaultDrawThemeText = NULL;\nstatic typeof(&DrawThemeTextEx) DefaultDrawThemeTextEx = NULL;\nstatic typeof(&DrawTextW) DefaultComCtl32DrawTextW = NULL;\nstatic typeof(&TaskDialogIndirect) DefaultTaskDialogIndirect = NULL;\nstatic typeof(&GetThemeColor) DefaultGetThemeColor = NULL;\nstatic typeof(&SystemParametersInfoW) DefaultSystemParametersInfo = NULL;\nstatic typeof(&CreateWindowExW) DefaultCreateWindowEx = NULL;\n\n// uxtheme.dll ordinal 49\nstatic HTHEME(WINAPI* DefaultOpenNcThemeData)(\n    _In_ HWND    hwnd,\n    _In_ LPCWSTR pszClassList\n    ) = NULL;\n\ntypedef struct _TASKDIALOG_CALLBACK_WRAP\n{\n    PFTASKDIALOGCALLBACK pfCallback;\n    LONG_PTR lpCallbackData;\n} TASKDIALOG_CALLBACK_WRAP, *PTASKDIALOG_CALLBACK_WRAP;\n\ntypedef struct _TASKDIALOG_COMMON_CONTEXT\n{\n    WNDPROC DefaultWindowProc;\n    ULONG Painting;\n} TASKDIALOG_COMMON_CONTEXT, *PTASKDIALOG_COMMON_CONTEXT;\n\ntypedef struct _TASKDIALOG_WINDOW_CONTEXT\n{\n    WNDPROC DefaultWindowProc;\n    ULONG Painting;\n    PTASKDIALOG_CALLBACK_WRAP CallbackData;\n} TASKDIALOG_WINDOW_CONTEXT, *PTASKDIALOG_WINDOW_CONTEXT;\n\n#define TASKDIALOG_CONTEXT_TAG (ULONG)'TDLG'\n\n#define GETCLASSNAME_OR_NULL(WindowHandle, ClassName) if (!GetClassName(WindowHandle, ClassName, RTL_NUMBER_OF(ClassName))) ClassName[0] = UNICODE_NULL\n\nHRESULT CALLBACK ThemeTaskDialogCallbackHook(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR dwRefData\n    );\n\nLRESULT CALLBACK ThemeTaskDialogMasterSubclass(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nBOOLEAN CALLBACK PhInitializeTaskDialogTheme(\n    _In_ HWND hwndDlg,\n    _In_opt_ PVOID Context\n    );\n\nHRESULT PhDrawThemeBackgroundHook(\n    _In_ HTHEME Theme,\n    _In_ HDC Hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_ LPCRECT Rect,\n    _In_ LPCRECT ClipRect\n    )\n{\n    WCHAR className[MAX_PATH];\n    BOOLEAN hasThemeClass = PhGetThemeClass(Theme, className, RTL_NUMBER_OF(className));\n\n    if (WindowsVersion >= WINDOWS_11 && hasThemeClass)\n    {\n        if (PhEqualStringZ(className, VSCLASS_MENU, TRUE))\n        {\n            if (PartId == MENU_POPUPGUTTER || PartId == MENU_POPUPBORDERS)\n            {\n                FillRect(Hdc, Rect, PhThemeWindowBackgroundBrush);\n                return S_OK;\n            }\n        }\n    }\n\n    if (hasThemeClass && PhEqualStringZ(className, VSCLASS_PROGRESS, TRUE)\n        /*|| WindowsVersion < WINDOWS_11 && WindowFromDC(Hdc) == NULL*/)\n    {\n        if (PartId == PP_TRANSPARENTBAR || PartId == PP_TRANSPARENTBARVERT) // Progress bar background\n        {\n            FillRect(Hdc, Rect, PhThemeWindowBackgroundBrush);\n            SetDCBrushColor(Hdc, RGB(0x60, 0x60, 0x60));\n            FrameRect(Hdc, Rect, PhGetStockBrush(DC_BRUSH));\n            return S_OK;\n        }\n    }\n\n    return DefaultDrawThemeBackground(Theme, Hdc, PartId, StateId, Rect, ClipRect);\n}\n\nHRESULT WINAPI PhDrawThemeBackgroundExHook(\n    _In_ HTHEME         hTheme,\n    _In_ HDC            hdc,\n    _In_ int            iPartId,\n    _In_ int            iStateId,\n    _In_ LPCRECT        pRect,\n    _In_ const DTBGOPTS* pOptions\n)\n{\n    WCHAR className[MAX_PATH];\n\n    // Apply theme to ListView checkboxes\n    if (iPartId == BP_CHECKBOX /*|| iPartId == BP_RADIOBUTTON*/)\n    {\n        if (PhGetThemeClass(hTheme, className, RTL_NUMBER_OF(className)) &&\n            PhEqualStringZ(className, VSCLASS_BUTTON, TRUE))\n        {\n            HTHEME darkButtonTheme = PhOpenThemeData(NULL, L\"DarkMode_Explorer::Button\", 0);\n            HRESULT retVal = DefaultDrawThemeBackgroundEx(darkButtonTheme ? darkButtonTheme : hTheme, hdc, iPartId, iStateId, pRect, pOptions);\n            if (darkButtonTheme)\n                PhCloseThemeData(darkButtonTheme);\n            return retVal;\n        }\n    }\n\n    // Micro optimization\n    if ((iPartId == TDLG_PRIMARYPANEL || iPartId == TDLG_FOOTNOTEPANE || iPartId == TDLG_SECONDARYPANEL || iPartId == TDLG_FOOTNOTESEPARATOR || iPartId == TDLG_EXPANDOBUTTON) &&\n        PhGetThemeClass(hTheme, className, RTL_NUMBER_OF(className)) && PhEqualStringZ(className, VSCLASS_TASKDIALOG, TRUE)\n        /*|| WindowsVersion < WINDOWS_11 && WindowFromDC(hdc) == NULL*/)\n    {\n        switch (iPartId)\n        {\n        case TDLG_PRIMARYPANEL:\n            SetDCBrushColor(hdc, PhThemeWindowBackground2Color);\n            FillRect(hdc, pRect, PhGetStockBrush(DC_BRUSH));\n            return S_OK;\n        case TDLG_FOOTNOTEPANE:\n            FillRect(hdc, pRect, PhThemeWindowBackgroundBrush);\n            return S_OK;\n        case TDLG_SECONDARYPANEL:\n        {\n            FillRect(hdc, pRect, PhThemeWindowBackgroundBrush);\n            RECT rect = *pRect;\n            rect.bottom = rect.top + 1;\n            SetDCBrushColor(hdc, PhThemeWindowForegroundColor);\n            FillRect(hdc, &rect, PhGetStockBrush(DC_BRUSH));\n            PhOffsetRect(&rect, 0, 1);\n            SetDCBrushColor(hdc, PhThemeWindowBackground2Color);\n            FillRect(hdc, &rect, PhGetStockBrush(DC_BRUSH));\n            return S_OK;\n        }\n        case TDLG_FOOTNOTESEPARATOR:\n        {\n            SetDCBrushColor(hdc, PhThemeWindowForegroundColor);\n            FillRect(hdc, pRect, PhGetStockBrush(DC_BRUSH));\n            RECT rect = *pRect;\n            rect.top += 1;\n            SetDCBrushColor(hdc, PhThemeWindowBackground2Color);\n            FillRect(hdc, &rect, PhGetStockBrush(DC_BRUSH));\n            return S_OK;\n        }\n        case TDLG_EXPANDOBUTTON:\n            if (WindowsVersion >= WINDOWS_11)\n            {\n                // In Windows 11, buttons lack background, making them indistinguishable on dark backgrounds.\n                // To address this, we invert the button. This technique isn't applicable to Windows 10 as it causes the button's border to appear chipped.\n                static enum { yes, no, unknown } mustInvertButton = unknown;\n                if (mustInvertButton == unknown)\n                {\n                    DefaultDrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, pOptions);\n                    int buttonCenterX = pOptions->rcClip.left + (pOptions->rcClip.right - pOptions->rcClip.left) / 2;\n                    int buttonCenterY = pOptions->rcClip.top + (pOptions->rcClip.bottom - pOptions->rcClip.top) / 2;\n                    COLORREF centerPixel = GetPixel(hdc, buttonCenterX, buttonCenterY);\n                    mustInvertButton = centerPixel == PhThemeWindowTextColor ? no : yes;\n                }\n                FillRect(hdc, pRect, PhThemeWindowBackgroundBrush);\n                if (mustInvertButton == yes) InvertRect(hdc, pRect);\n                HRESULT retVal = DefaultDrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, pOptions);\n                if (mustInvertButton == yes) InvertRect(hdc, pRect);\n                return retVal;\n            }\n        }\n    }\n\n    return DefaultDrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, pOptions);\n}\n\nHWND PhCreateWindowExHook(\n    _In_ ULONG ExStyle,\n    _In_opt_ PCWSTR ClassName,\n    _In_opt_ PCWSTR WindowName,\n    _In_ ULONG Style,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_opt_ HWND Parent,\n    _In_opt_ HMENU Menu,\n    _In_opt_ PVOID Instance,\n    _In_opt_ PVOID Param\n    )\n{\n    HWND windowHandle = DefaultCreateWindowEx(\n        ExStyle,\n        ClassName,\n        WindowName,\n        Style,\n        X,\n        Y,\n        Width,\n        Height,\n        Parent,\n        Menu,\n        Instance,\n        Param\n        );\n\n    if (Parent == NULL)\n    {\n        if (PhDefaultEnableStreamerMode)\n        {\n            SetWindowDisplayAffinity(windowHandle, WDA_EXCLUDEFROMCAPTURE);\n        }\n\n        if (PhEnableThemeSupport && PhDefaultEnableThemeAcrylicWindowSupport)\n        {\n            PhSetWindowAcrylicCompositionColor(windowHandle, MakeABGRFromCOLORREF(0, RGB(10, 10, 10)));\n        }\n    }\n    else if (PhEnableThemeSupport)\n    {\n        // Early subclassing of the SysLink control to eliminate blinking during page switches.\n        if (!IS_INTRESOURCE(ClassName) && PhEqualStringZ(ClassName, WC_LINK, TRUE))\n        {\n            PhInitializeTaskDialogTheme(windowHandle, 0);\n        }\n        else if (!IS_INTRESOURCE(ClassName) && PhEqualStringZ(ClassName, WC_BUTTON, TRUE) &&\n                 PhGetWindowContext(GetAncestor(Parent, GA_ROOT), LONG_MAX))\n        {\n            PhSetControlTheme(windowHandle, L\"DarkMode_Explorer\");\n        }\n    }\n\n    return windowHandle;\n}\n\nBOOL WINAPI PhSystemParametersInfoHook(\n    _In_ UINT uiAction,\n    _In_ UINT uiParam,\n    _Pre_maybenull_ _Post_valid_ PVOID pvParam,\n    _In_ UINT fWinIni\n    )\n{\n    if (uiAction == SPI_GETMENUFADE && pvParam)\n    {\n        *((PBOOL)pvParam) = FALSE;\n        return TRUE;\n    }\n\n    if (uiAction == SPI_GETCLIENTAREAANIMATION && pvParam)\n    {\n        *((PBOOL)pvParam) = FALSE;\n        return TRUE;\n    }\n\n    if (uiAction == SPI_GETCOMBOBOXANIMATION && pvParam)\n    {\n        *((PBOOL)pvParam) = FALSE;\n        return TRUE;\n    }\n\n    if (uiAction == SPI_GETTOOLTIPANIMATION && pvParam)\n    {\n        *((PBOOL)pvParam) = FALSE;\n        return TRUE;\n    }\n\n    if (uiAction == SPI_GETMENUANIMATION && pvParam)\n    {\n        *((PBOOL)pvParam) = FALSE;\n        return TRUE;\n    }\n\n    if (uiAction == SPI_GETTOOLTIPFADE && pvParam)\n    {\n        *((PBOOL)pvParam) = FALSE;\n        return TRUE;\n    }\n\n    if (uiAction == SPI_GETMOUSEVANISH && pvParam)\n    {\n        *((PBOOL)pvParam) = FALSE;\n        return TRUE;\n    }\n\n    return DefaultSystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);\n}\n\n//ULONG WINAPI GetSysColorHook(int nIndex)\n//{\n//    if (nIndex == COLOR_WINDOW)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_MENUTEXT)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_WINDOWTEXT)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_CAPTIONTEXT)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_HIGHLIGHTTEXT)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_GRAYTEXT)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_BTNTEXT)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_INACTIVECAPTIONTEXT)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_BTNFACE)\n//        return PhThemeWindowBackgroundColor;\n//    if (nIndex == COLOR_BTNTEXT)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_BTNHIGHLIGHT)\n//        return PhThemeWindowBackgroundColor;\n//    if (nIndex == COLOR_INFOTEXT)\n//        return PhThemeWindowTextColor;\n//    if (nIndex == COLOR_INFOBK)\n//        return PhThemeWindowBackgroundColor;\n//    if (nIndex == COLOR_MENU)\n//        return PhThemeWindowBackgroundColor;\n//    if (nIndex == COLOR_HIGHLIGHT)\n//        return PhThemeWindowForegroundColor;\n//    return originalGetSysColor(nIndex);\n//}\n//\n//HBRUSH WINAPI GetSysColorBrushHook(_In_ int nIndex)\n//{\n//    //if (nIndex == COLOR_WINDOW)\n//    //   return originalCreateSolidBrush(PhThemeWindowBackgroundColor);\n//    if (nIndex == COLOR_BTNFACE)\n//        return originalCreateSolidBrush(PhThemeWindowBackgroundColor);\n//    return originalHook(nIndex);\n//}\n//\n// RGB(GetBValue(color), GetGValue(color), GetRValue(color));\n//#define RGB_FROM_COLOREF(cref) \\\n//    ((((cref) & 0x000000FF) << 16) | (((cref) & 0x0000FF00)) | (((cref) & 0x00FF0000) >> 16))\n\nHRESULT WINAPI PhDrawThemeTextHook(\n    _In_ HTHEME  hTheme,\n    _In_ HDC     hdc,\n    _In_ int     iPartId,\n    _In_ int     iStateId,\n    _In_ LPCWSTR pszText,\n    _In_ int     cchText,\n    _In_ DWORD   dwTextFlags,\n    _In_ DWORD   dwTextFlags2,\n    _In_ LPCRECT pRect\n    )\n{\n    if ((iPartId == BP_COMMANDLINK /*|| iPartId == BP_RADIOBUTTON*/) && iStateId != PBS_DISABLED)\n    {\n        WCHAR className[MAX_PATH];\n        if (PhGetThemeClass(hTheme, className, RTL_NUMBER_OF(className)) && PhEqualStringZ(className, VSCLASS_BUTTON, TRUE)\n            /*|| WindowsVersion < WINDOWS_11 && WindowFromDC(hdc) == NULL*/)\n        {\n            DTTOPTS options = { sizeof(DTTOPTS), DTT_TEXTCOLOR, PhThemeWindowTextColor };\n            return DefaultDrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, (LPRECT)pRect, &options);\n        }\n    }\n\n    return DefaultDrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, dwTextFlags2, pRect);\n}\n\nHRESULT WINAPI PhDrawThemeTextExHook(\n    _In_      HTHEME        hTheme,\n    _In_      HDC           hdc,\n    _In_      int           iPartId,\n    _In_      int           iStateId,\n    _In_      LPCWSTR       pszText,\n    _In_      int           cchText,\n    _In_      DWORD         dwTextFlags,\n    _Inout_   LPRECT        pRect,\n    _In_      const DTTOPTS* pOptions\n    )\n{\n    if (iPartId == BP_COMMANDLINK)\n    {\n        WCHAR className[MAX_PATH];\n        if (PhGetThemeClass(hTheme, className, RTL_NUMBER_OF(className)) && PhEqualStringZ(className, VSCLASS_BUTTON, TRUE)\n            /*|| WindowsVersion < WINDOWS_11 && WindowFromDC(hdc) == NULL*/)\n        {\n            DTTOPTS options = { sizeof(DTTOPTS) };\n            if (pOptions)\n                options = *pOptions;\n            options.dwFlags |= DTT_TEXTCOLOR;\n            DefaultGetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &options.crText);\n            options.crText = PhMakeColorBrighter(options.crText, 90);\n            return DefaultDrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, &options);\n        }\n    }\n\n    return DefaultDrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, pOptions);\n}\n\nint PhDetoursComCtl32DrawTextW(\n    _In_      HDC     hdc,\n    _Inout_   LPCWSTR lpchText,\n    _In_      int     cchText,\n    _Inout_   LPRECT  lprc,\n    _In_      UINT    format\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static COLORREF colLinkNormal = RGB(0, 0 ,0);\n    static COLORREF colLinkHot = RGB(0, 0, 0);\n    static COLORREF colLinkPressed = RGB(0, 0, 0);\n    HWND WindowHandle;\n\n    if ((WindowHandle = WindowFromDC(hdc)) &&\n        (PhIsDarkModeAllowedForWindow(WindowHandle) || PhGetWindowContext(WindowHandle, TASKDIALOG_CONTEXT_TAG)))    // HACK\n    {\n        WCHAR windowClassName[MAX_PATH];\n        GETCLASSNAME_OR_NULL(WindowHandle, windowClassName);\n        if (PhEqualStringZ(windowClassName, WC_LINK, FALSE))\n        {\n            if (PhBeginInitOnce(&initOnce))\n            {\n                HTHEME hTextTheme = PhOpenThemeData(WindowHandle, VSCLASS_TEXTSTYLE, PhGetWindowDpi(WindowHandle));\n                if (hTextTheme)\n                {\n                    PhGetThemeColor(hTextTheme, TEXT_HYPERLINKTEXT, TS_HYPERLINK_NORMAL, TMT_TEXTCOLOR, &colLinkNormal);\n                    PhGetThemeColor(hTextTheme, TEXT_HYPERLINKTEXT, TS_HYPERLINK_HOT, TMT_TEXTCOLOR, &colLinkHot);\n                    PhGetThemeColor(hTextTheme, TEXT_HYPERLINKTEXT, TS_HYPERLINK_PRESSED, TMT_TEXTCOLOR, &colLinkPressed);\n                    PhCloseThemeData(hTextTheme);\n                }\n                PhEndInitOnce(&initOnce);\n            }\n\n            COLORREF color = GetTextColor(hdc);\n\n            if (color == colLinkNormal || color == colLinkHot || color == colLinkPressed ||\n                WindowsVersion < WINDOWS_11 && color == RGB(0x00, 0x66, 0xCC))  // on Windows 10 PhGetThemeColor returns 0xFFFFFF for any StateId\n            {\n                SetTextColor(hdc, PhMakeColorBrighter(color, 95));\n            }\n        }\n    }\n\n    return DefaultComCtl32DrawTextW(hdc, lpchText, cchText, lprc, format);\n}\n\nHRESULT PhGetThemeColorHook(\n    _In_  HTHEME   hTheme,\n    _In_  int      iPartId,\n    _In_  int      iStateId,\n    _In_  int      iPropId,\n    _Out_ COLORREF* pColor\n    )\n{\n    WCHAR className[MAX_PATH];\n\n    HRESULT retVal = DefaultGetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor);\n\n    if (iPropId == TMT_TEXTCOLOR && iPartId == TDLG_MAININSTRUCTIONPANE)\n    {\n        if (PhGetThemeClass(hTheme, className, RTL_NUMBER_OF(className)) && PhEqualStringZ(className, VSCLASS_TASKDIALOGSTYLE, TRUE)\n            /*|| WindowsVersion < WINDOWS_11*/)\n        {\n            *pColor = PhMakeColorBrighter(*pColor, 150); // Main header.\n        }\n    }\n    else if (iPropId == TMT_TEXTCOLOR)\n    {\n        if (PhGetThemeClass(hTheme, className, RTL_NUMBER_OF(className)) && PhEqualStringZ(className, VSCLASS_TASKDIALOGSTYLE, TRUE)\n            /*|| WindowsVersion < WINDOWS_11*/)\n        {\n            *pColor = PhThemeWindowTextColor; // Text color for check boxes, expanded text, and expander button text.\n        }\n    }\n\n    return retVal;\n}\n\nHTHEME PhOpenNcThemeDataHook(\n    _In_ HWND    hwnd,\n    _In_ LPCWSTR pszClassList\n    )\n{\n    if (PhEqualStringZ((PWSTR)pszClassList, VSCLASS_SCROLLBAR, TRUE) &&\n        PhIsDarkModeAllowedForWindow(hwnd))\n    {\n        return DefaultOpenNcThemeData(NULL, L\"Explorer::ScrollBar\");\n    }\n\n    return DefaultOpenNcThemeData(hwnd, pszClassList);\n}\n\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nBOOLEAN CALLBACK PhInitializeTaskDialogTheme(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID CallbackData\n    )\n{\n    WCHAR windowClassName[MAX_PATH];\n    PTASKDIALOG_COMMON_CONTEXT context;\n    BOOLEAN windowHasContext = !!PhGetWindowContext(WindowHandle, TASKDIALOG_CONTEXT_TAG);\n\n    if (CallbackData && !windowHasContext)\n    {\n        if (PhDefaultEnableStreamerMode)\n        {\n            SetWindowDisplayAffinity(WindowHandle, WDA_EXCLUDEFROMCAPTURE);\n        }\n\n        PhInitializeThemeWindowFrame(WindowHandle);\n\n        PTASKDIALOG_WINDOW_CONTEXT context = PhAllocateZero(sizeof(TASKDIALOG_WINDOW_CONTEXT));\n        context->DefaultWindowProc = PhSetWindowProcedure(WindowHandle, ThemeTaskDialogMasterSubclass);\n        context->CallbackData = CallbackData;\n        PhSetWindowContext(WindowHandle, TASKDIALOG_CONTEXT_TAG, context);\n        windowHasContext = TRUE;\n    }\n\n    PhEnumChildWindows(\n        WindowHandle,\n        PhInitializeTaskDialogTheme,\n        NULL\n        );\n\n    if (windowHasContext)    // HACK\n        return TRUE;\n\n    GETCLASSNAME_OR_NULL(WindowHandle, windowClassName);\n\n    context = PhAllocateZero(sizeof(TASKDIALOG_COMMON_CONTEXT));\n    context->DefaultWindowProc = PhSetWindowProcedure(WindowHandle, ThemeTaskDialogMasterSubclass);\n    PhSetWindowContext(WindowHandle, TASKDIALOG_CONTEXT_TAG, context);\n\n    if (PhEqualStringZ(windowClassName, WC_BUTTON, FALSE) ||\n        PhEqualStringZ(windowClassName, WC_SCROLLBAR, FALSE))\n    {\n        PhSetControlTheme(WindowHandle, L\"DarkMode_Explorer\");\n    }\n    //else if (PhEqualStringZ(windowClassName, WC_LINK, FALSE))\n    //{\n    //    PhAllowDarkModeForWindow(WindowHandle);   // this doesn't work, idk why\n    //}\n    else if (PhEqualStringZ(windowClassName, L\"DirectUIHWND\", FALSE))\n    {\n        //WINDOWPLACEMENT pos = { 0 };\n        //GetWindowPlacement(GetParent(WindowHandle), &pos);\n        PhSetControlTheme(WindowHandle, L\"DarkMode_Explorer\");\n        //SetWindowPlacement(GetParent(WindowHandle), &pos);\n    }\n\n    return TRUE;\n}\n\nLRESULT CALLBACK ThemeTaskDialogMasterSubclass(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    LRESULT result;\n    PTASKDIALOG_COMMON_CONTEXT context;\n    WNDPROC OldWndProc;\n\n    if (!(context = PhGetWindowContext(hwnd, TASKDIALOG_CONTEXT_TAG)))\n        return 0;\n\n    OldWndProc = context->DefaultWindowProc;\n\n    switch (uMsg)\n    {\n    case WM_ERASEBKGND:\n        {\n            HDC hdc = (HDC)wParam;\n            RECT rect;\n            WCHAR windowClassName[MAX_PATH];\n\n            SetTextColor(hdc, PhThemeWindowTextColor); // Color for SysLink, which must be set in its parent.\n\n            if (!context->Painting)\n            {\n                GETCLASSNAME_OR_NULL(hwnd, windowClassName);\n                // Avoid erasing the background for links, as they will blink white on the extender and during page switches.\n                if (!PhEqualStringZ(windowClassName, WC_LINK, FALSE))\n                {\n                    GetClipBox(hdc, &rect);\n                    SetDCBrushColor(hdc, PhThemeWindowBackground2Color);\n                    FillRect(hdc, &rect, PhGetStockBrush(DC_BRUSH));\n                }\n            }\n        }\n        return TRUE;\n    case WM_NOTIFY:\n        {\n            LPNMHDR data = (LPNMHDR)lParam;\n\n            if (data->code == NM_CUSTOMDRAW)\n            {\n                LPNMCUSTOMDRAW customDraw = (LPNMCUSTOMDRAW)lParam;\n                WCHAR className[MAX_PATH];\n\n                if (!GetClassName(customDraw->hdr.hwndFrom, className, RTL_NUMBER_OF(className)))\n                    className[0] = UNICODE_NULL;\n                if (PhEqualStringZ(className, WC_BUTTON, FALSE))\n                {\n                    return PhThemeWindowDrawButton(customDraw);\n                }\n            }\n        }\n        break;\n    case TDM_NAVIGATE_PAGE:\n        {\n            PTASKDIALOG_WINDOW_CONTEXT WindowContext = (PTASKDIALOG_WINDOW_CONTEXT)context;\n            PTASKDIALOGCONFIG trueConfig = (PTASKDIALOGCONFIG)lParam;\n            PTASKDIALOGCONFIG myConfig;\n            TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) };\n\n            WindowContext->CallbackData->pfCallback = trueConfig ? trueConfig->pfCallback : NULL;\n            WindowContext->CallbackData->lpCallbackData = trueConfig ? trueConfig->lpCallbackData : 0;\n            myConfig = trueConfig ? trueConfig : &config;\n            myConfig->pfCallback = ThemeTaskDialogCallbackHook;\n            myConfig->lpCallbackData = (LONG_PTR)WindowContext->CallbackData;\n\n            return CallWindowProc(OldWndProc, hwnd, uMsg, wParam, (LPARAM)myConfig);\n        }\n    case WM_DESTROY:\n        {\n            PhSetWindowProcedure(hwnd, OldWndProc);\n            PhRemoveWindowContext(hwnd, TASKDIALOG_CONTEXT_TAG);\n            PhFree(context);\n        }\n        return CallWindowProc(OldWndProc, hwnd, uMsg, wParam, lParam);\n    case WM_CTLCOLORDLG:\n        return (LRESULT)PhThemeWindowBackgroundBrush; // Window background color when the extender resizes upward (Windows 10 only).\n    }\n\n    context->Painting++;\n    result = CallWindowProc(OldWndProc, hwnd, uMsg, wParam, lParam);\n    context->Painting--;\n    return result;\n}\n\nHRESULT CALLBACK ThemeTaskDialogCallbackHook(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR dwRefData\n    )\n{\n    HRESULT result = S_OK;\n\n    PTASKDIALOG_CALLBACK_WRAP CallbackData = (PTASKDIALOG_CALLBACK_WRAP)dwRefData;\n\n    if (uMsg == TDN_DIALOG_CONSTRUCTED) // Called on each new page, including the first one.\n    {\n        PhInitializeTaskDialogTheme(hwndDlg, CallbackData);\n    }\n\n    if (CallbackData->pfCallback)\n        result = CallbackData->pfCallback(hwndDlg, uMsg, wParam, lParam, CallbackData->lpCallbackData);\n\n    return result;\n}\n\n// https://github.com/SFTRS/DarkTaskDialog\nHRESULT PhTaskDialogIndirectHook(\n    _In_      const TASKDIALOGCONFIG* pTaskConfig,\n    _Out_opt_ int* pnButton,\n    _Out_opt_ int* pnRadioButton,\n    _Out_opt_ BOOL* pfVerificationFlagChecked\n    )\n{\n    TASKDIALOG_CALLBACK_WRAP CallbackData;\n    CallbackData.pfCallback = pTaskConfig->pfCallback;\n    CallbackData.lpCallbackData = pTaskConfig->lpCallbackData;\n    TASKDIALOGCONFIG myConfig = *pTaskConfig;\n    myConfig.pfCallback = ThemeTaskDialogCallbackHook;\n    myConfig.lpCallbackData = (LONG_PTR)&CallbackData;\n\n    return DefaultTaskDialogIndirect(&myConfig, pnButton, pnRadioButton, pfVerificationFlagChecked);\n}\n\nVOID PhRegisterDetoursHooks(\n    VOID\n    )\n{\n    NTSTATUS status;\n    PVOID baseAddress;\n\n    // For early TaskDialog with PhStartupParameters.ShowOptions\n    if (!PhThemeWindowBackgroundBrush)\n    {\n        PhThemeWindowBackgroundBrush = CreateSolidBrush(PhThemeWindowBackgroundColor);\n    }\n\n    if (baseAddress = PhGetLoaderEntryDllBaseZ(L\"user32.dll\"))\n    {\n        DefaultCreateWindowEx = PhGetDllBaseProcedureAddress(baseAddress, \"CreateWindowExW\", 0);\n        DefaultSystemParametersInfo = PhGetDllBaseProcedureAddress(baseAddress, \"SystemParametersInfoW\", 0);\n    }\n\n    if (baseAddress = PhGetLoaderEntryDllBaseZ(L\"uxtheme.dll\"))\n    {\n        DefaultDrawThemeBackground = PhGetDllBaseProcedureAddress(baseAddress, \"DrawThemeBackground\", 0);\n        DefaultDrawThemeBackgroundEx = PhGetDllBaseProcedureAddress(baseAddress, \"DrawThemeBackgroundEx\", 0);\n        DefaultDrawThemeText = PhGetDllBaseProcedureAddress(baseAddress, \"DrawThemeText\", 0);\n        DefaultDrawThemeTextEx = PhGetDllBaseProcedureAddress(baseAddress, \"DrawThemeTextEx\", 0);\n        DefaultGetThemeColor = PhGetDllBaseProcedureAddress(baseAddress, \"GetThemeColor\", 0);\n        DefaultOpenNcThemeData = PhGetDllBaseProcedureAddress(baseAddress, NULL, 49);\n    }\n\n    if (baseAddress = PhGetLoaderEntryDllBaseZ(L\"Comctl32.dll\"))\n    {\n        if (WindowsVersion >= WINDOWS_11)   // TaskDialog theme on Windows 10 currently unsupported...\n            DefaultTaskDialogIndirect = PhGetDllBaseProcedureAddress(baseAddress, \"TaskDialogIndirect\", 0);\n        PhLoaderEntryDetourImportProcedure(baseAddress, \"User32.dll\", \"DrawTextW\", PhDetoursComCtl32DrawTextW, (PVOID*)&DefaultComCtl32DrawTextW);\n    }\n\n    if (!NT_SUCCESS(status = DetourTransactionBegin()))\n        goto CleanupExit;\n\n    if (PhEnableThemeSupport || PhEnableThemeAcrylicSupport)\n    {\n        if (!NT_SUCCESS(status = DetourAttach((PVOID)&DefaultDrawThemeBackground, (PVOID)PhDrawThemeBackgroundHook)))\n            goto CleanupExit;\n        if (!NT_SUCCESS(status = DetourAttach((PVOID)&DefaultDrawThemeBackgroundEx, (PVOID)PhDrawThemeBackgroundExHook)))\n            goto CleanupExit;\n        if (!PhDefaultEnableThemeAnimation)\n        {\n            if (!NT_SUCCESS(status = DetourAttach((PVOID)&DefaultSystemParametersInfo, (PVOID)PhSystemParametersInfoHook)))\n                goto CleanupExit;\n        }\n        if (!NT_SUCCESS(status = DetourAttach((PVOID)&DefaultDrawThemeText, (PVOID)PhDrawThemeTextHook)))\n            goto CleanupExit;\n        if (!NT_SUCCESS(status = DetourAttach((PVOID)&DefaultDrawThemeTextEx, (PVOID)PhDrawThemeTextExHook)))\n            goto CleanupExit;\n        if (!NT_SUCCESS(status = DetourAttach((PVOID)&DefaultGetThemeColor, (PVOID)PhGetThemeColorHook)))\n            goto CleanupExit;\n        if (!NT_SUCCESS(status = DetourAttach((PVOID)&DefaultOpenNcThemeData, (PVOID)PhOpenNcThemeDataHook)))\n            goto CleanupExit;\n        if (WindowsVersion >= WINDOWS_11)\n            if (!NT_SUCCESS(status = DetourAttach((PVOID)&DefaultTaskDialogIndirect, (PVOID)PhTaskDialogIndirectHook)))\n                goto CleanupExit;\n    }\n\n    if (!NT_SUCCESS(status = DetourAttach((PVOID)&DefaultCreateWindowEx, (PVOID)PhCreateWindowExHook)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = DetourTransactionCommit()))\n        goto CleanupExit;\n\nCleanupExit:\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(NULL, L\"Unable to commit detours transaction.\", status, 0);\n    }\n}\n\nBOOLEAN PhIsThemeTransparencyEnabled(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF themesKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Themes\\\\Personalize\");\n    BOOLEAN themesEnableTransparency = FALSE;\n    HANDLE keyHandle;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_QUERY_VALUE,\n        PH_KEY_CURRENT_USER,\n        &themesKeyName,\n        0\n        )))\n    {\n        themesEnableTransparency = !!PhQueryRegistryUlongZ(keyHandle, L\"EnableTransparency\");\n        NtClose(keyHandle);\n    }\n\n    return themesEnableTransparency;\n}\n\nVOID PhInitializeSuperclassControls(\n    VOID\n    )\n{\n    PhDefaultEnableStreamerMode = !!PhGetIntegerSetting(SETTING_ENABLE_STREAMER_MODE);\n\n    if (PhEnableThemeAcrylicSupport && !PhEnableThemeSupport)\n        PhEnableThemeAcrylicSupport = FALSE;\n    if (PhEnableThemeAcrylicSupport)\n        PhEnableThemeAcrylicSupport = PhIsThemeTransparencyEnabled();\n\n    if (PhEnableThemeSupport || PhDefaultEnableStreamerMode)\n    {\n        if (WindowsVersion >= WINDOWS_11)\n        {\n            PhDefaultEnableThemeAcrylicWindowSupport = !!PhGetIntegerSetting(SETTING_ENABLE_THEME_ACRYLIC_WINDOW_SUPPORT);\n        }\n\n        PhDefaultEnableThemeAnimation = !!PhGetIntegerSetting(SETTING_ENABLE_THEME_ANIMATION);\n\n        PhRegisterDialogSuperClass();\n        PhRegisterMenuSuperClass();\n        PhRegisterRebarSuperClass();\n        PhRegisterComboBoxSuperClass();\n        PhRegisterStaticSuperClass();\n        PhRegisterStatusBarSuperClass();\n        PhRegisterEditSuperClass();\n        PhRegisterHeaderSuperClass();\n\n        PhRegisterDetoursHooks();\n    }\n}\n"
  },
  {
    "path": "SystemInformer/delayload.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2021-2023\n *\n */\n\n#include <phapp.h>\n#include <mapldr.h>\n\n// CRT delayload support\n// The msvc delayload handler throws exceptions when\n// imports are unavailable instead of returning NULL (dmex)\n\n#ifndef PH_NATIVE_DELAYLOAD\nPH_QUEUED_LOCK PhDelayLoadImportLock = PH_QUEUED_LOCK_INIT;\nULONG PhDelayLoadOldProtection = PAGE_WRITECOPY;\nULONG PhDelayLoadLockCount = 0;\n\n// based on \\MSVC\\14.31.31103\\include\\dloadsup.h (dmex)\nVOID PhDelayLoadImportAcquire(\n    _In_ PVOID ImportDirectorySectionAddress,\n    _In_ SIZE_T ImportDirectorySectionSize\n    )\n{\n    PhAcquireQueuedLockExclusive(&PhDelayLoadImportLock);\n    PhDelayLoadLockCount += 1;\n\n    if (PhDelayLoadLockCount == 1)\n    {\n        NTSTATUS status;\n\n        if (!NT_SUCCESS(status = PhProtectVirtualMemory(\n            NtCurrentProcess(),\n            ImportDirectorySectionAddress,\n            ImportDirectorySectionSize,\n            PAGE_READWRITE,\n            &PhDelayLoadOldProtection\n            )))\n        {\n            PhRaiseStatus(status);\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&PhDelayLoadImportLock);\n}\n\nVOID PhDelayLoadImportRelease(\n    _In_ PVOID ImportDirectorySectionAddress,\n    _In_ SIZE_T ImportDirectorySectionSize\n    )\n{\n    PhAcquireQueuedLockExclusive(&PhDelayLoadImportLock);\n    PhDelayLoadLockCount -= 1;\n\n    if (PhDelayLoadLockCount == 0)\n    {\n        ULONG importSectionOldProtection;\n        PhProtectVirtualMemory(\n            NtCurrentProcess(),\n            ImportDirectorySectionAddress,\n            ImportDirectorySectionSize,\n            PhDelayLoadOldProtection,\n            &importSectionOldProtection\n            );\n\n#ifdef _M_ARM64\n        NtFlushInstructionCache(\n            NtCurrentProcess(),\n            ImportDirectorySectionAddress,\n            ImportDirectorySectionSize\n            );\n#endif\n    }\n\n    PhReleaseQueuedLockExclusive(&PhDelayLoadImportLock);\n}\n#endif\n\nPVOID WINAPI __delayLoadHelper2(\n    _In_ PIMAGE_DELAYLOAD_DESCRIPTOR DelayloadDescriptor,\n    _In_ PIMAGE_THUNK_DATA ThunkAddress\n    )\n{\n#if !defined(PH_NATIVE_DELAYLOAD)\n    BOOLEAN importNeedsFree = FALSE;\n    PCSTR importDllName;\n    PVOID procedureAddress;\n    PVOID moduleHandle;\n    PVOID* importHandle;\n    PIMAGE_THUNK_DATA importEntry;\n    PIMAGE_THUNK_DATA importTable;\n    PIMAGE_THUNK_DATA importNameTable;\n    PIMAGE_NT_HEADERS imageNtHeaders;\n    SIZE_T importDirectorySectionSize;\n    PVOID importDirectorySectionAddress;\n\n    importDllName = PTR_ADD_OFFSET(NtCurrentImageBase(), DelayloadDescriptor->DllNameRVA);\n    importHandle = PTR_ADD_OFFSET(NtCurrentImageBase(), DelayloadDescriptor->ModuleHandleRVA);\n    importTable = PTR_ADD_OFFSET(NtCurrentImageBase(), DelayloadDescriptor->ImportAddressTableRVA);\n    importNameTable = PTR_ADD_OFFSET(NtCurrentImageBase(), DelayloadDescriptor->ImportNameTableRVA);\n\n    if (!(moduleHandle = InterlockedCompareExchangePointer(importHandle, NULL, NULL)))\n    {\n        WCHAR importDllNameBuffer[DOS_MAX_PATH_LENGTH] = L\"\";\n\n        PhZeroExtendToUtf16Buffer(importDllName, strlen(importDllName), importDllNameBuffer);\n\n        if (!(moduleHandle = PhLoadLibrary(importDllNameBuffer)))\n        {\n            return NULL;\n        }\n\n        importNeedsFree = TRUE;\n    }\n\n    importEntry = PTR_ADD_OFFSET(importNameTable, PTR_SUB_OFFSET(ThunkAddress, importTable));\n\n    if (IMAGE_SNAP_BY_ORDINAL(importEntry->u1.Ordinal))\n    {\n        USHORT procedureOrdinal = IMAGE_ORDINAL(importEntry->u1.Ordinal);\n        procedureAddress = PhGetDllBaseProcedureAddress(moduleHandle, NULL, procedureOrdinal);\n    }\n    else\n    {\n        PIMAGE_IMPORT_BY_NAME importByName = PTR_ADD_OFFSET(NtCurrentImageBase(), importEntry->u1.AddressOfData);\n        procedureAddress = PhGetDllBaseProcedureAddressWithHint(moduleHandle, importByName->Name, importByName->Hint);\n    }\n\n    if (!procedureAddress)\n        return NULL;\n\n    if (!NT_SUCCESS(PhGetLoaderEntryImageNtHeaders(\n        NtCurrentImageBase(),\n        &imageNtHeaders\n        )))\n    {\n        return NULL;\n    }\n\n    if (!NT_SUCCESS(PhGetLoaderEntryImageVaToSection(\n        NtCurrentImageBase(),\n        imageNtHeaders,\n        importTable,\n        &importDirectorySectionAddress,\n        &importDirectorySectionSize\n        )))\n    {\n        return NULL;\n    }\n\n    PhDelayLoadImportAcquire(importDirectorySectionAddress, importDirectorySectionSize);\n    InterlockedExchangePointer((PVOID)ThunkAddress, procedureAddress);\n    PhDelayLoadImportRelease(importDirectorySectionAddress, importDirectorySectionSize);\n\n    if ((InterlockedExchangePointer(importHandle, moduleHandle) == moduleHandle) && importNeedsFree)\n    {\n        PhFreeLibrary(moduleHandle); // already updated the cache (dmex)\n    }\n\n    return procedureAddress;\n#else\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID (WINAPI* DelayLoadFailureHook)(\n        _In_ PCSTR DllName,\n        _In_ PCSTR ProcName\n        ) = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        DelayLoadFailureHook = PhGetModuleProcAddress(L\"kernel32.dll\", \"DelayLoadFailureHook\"); // kernelbase.dll\n        PhEndInitOnce(&initOnce);\n    }\n\n    return LdrResolveDelayLoadedAPI(\n        NtCurrentImageBase(),\n        DelayloadDescriptor,\n        NULL,\n        DelayLoadFailureHook,\n        ThunkAddress,\n        0\n        );\n#endif\n}\n"
  },
  {
    "path": "SystemInformer/devprv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2023\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <settings.h>\n#include <secedit.h>\n\n#include <devprv.h>\n#include <devquery.h>\n\nDEFINE_GUID(GUID_DEVINTERFACE_A2DP_SIDEBAND_AUDIO, 0xf3b1362f, 0xc9f4, 0x4dd1, 0x9d, 0x55, 0xe0, 0x20, 0x38, 0xa1, 0x29, 0xfb);\nDEFINE_GUID(GUID_DEVINTERFACE_BLUETOOTH_HFP_SCO_HCIBYPASS, 0xbe446647, 0xf655, 0x4919, 0x8b, 0xd0, 0x12, 0x5b, 0xa5, 0xd4, 0xce, 0x65);\nDEFINE_GUID(GUID_DEVINTERFACE_CHARGING_ARBITRATION, 0xec0a1cc9, 0x4294, 0x43fb, 0xbf, 0x37, 0xb8, 0x50, 0xce, 0x95, 0xf3, 0x37);\nDEFINE_GUID(GUID_DEVINTERFACE_CONFIGURABLE_USBFN_CHARGER, 0x7158c35c, 0xc1bc, 0x4d90, 0xac, 0xb1, 0x80, 0x20, 0xbd, 0xe, 0x19, 0xca);\nDEFINE_GUID(GUID_DEVINTERFACE_CONFIGURABLE_WIRELESS_CHARGER, 0x3612b1c8, 0x3633, 0x47d3, 0x8a, 0xf5, 0x0, 0xa4, 0xdf, 0xa0, 0x47, 0x93);\nDEFINE_GUID(GUID_DEVINTERFACE_I2C, 0x2564AA4F, 0xDDDB, 0x4495, 0xB4, 0x97, 0x6A, 0xD4, 0xA8, 0x41, 0x63, 0xD7);\nDEFINE_GUID(GUID_DEVINTERFACE_OPM, 0xBF4672DE, 0x6B4E, 0x4BE4, 0xA3, 0x25, 0x68, 0xA9, 0x1E, 0xA4, 0x9C, 0x09);\nDEFINE_GUID(GUID_DEVINTERFACE_OPM_2_JTP, 0xE929EEA4, 0xB9F1, 0x407B, 0xAA, 0xB9, 0xAB, 0x08, 0xBB, 0x44, 0xFB, 0xF4);\nDEFINE_GUID(GUID_DEVINTERFACE_OPM_2, 0x7F098726, 0x2EBB, 0x4FF3, 0xA2, 0x7F, 0x10, 0x46, 0xB9, 0x5D, 0xC5, 0x17);\nDEFINE_GUID(GUID_DEVINTERFACE_OPM_3, 0x693a2cb1, 0x8c8d, 0x4ab6, 0x95, 0x55, 0x4b, 0x85, 0xef, 0x2c, 0x7c, 0x6b);\nDEFINE_GUID(GUID_DEVINTERFACE_BRIGHTNESS, 0xFDE5BBA4, 0xB3F9, 0x46FB, 0xBD, 0xAA, 0x07, 0x28, 0xCE, 0x31, 0x00, 0xB4);\nDEFINE_GUID(GUID_DEVINTERFACE_BRIGHTNESS_2, 0x148A3C98, 0x0ECD, 0x465A, 0xB6, 0x34, 0xB0, 0x5F, 0x19, 0x5F, 0x77, 0x39);\nDEFINE_GUID(GUID_DEVINTERFACE_MIRACAST_DISPLAY, 0xaf03f190, 0x22af, 0x48cb, 0x94, 0xbb, 0xb7, 0x8e, 0x76, 0xa2, 0x51, 0x7);\nDEFINE_GUID(GUID_DEVINTERFACE_BRIGHTNESS_3, 0x197a4a6e, 0x391, 0x4322, 0x96, 0xea, 0xc2, 0x76, 0xf, 0x88, 0x1d, 0x3a);\nDEFINE_GUID(GUID_DEVINTERFACE_HPMI, 0xdedae202, 0x1d20, 0x4c40, 0xa6, 0xf3, 0x18, 0x97, 0xe3, 0x19, 0xd5, 0x4f);\nDEFINE_GUID(GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE, 0xa13a7a93, 0x11f0, 0x4bd2, 0xa9, 0xf5, 0x6b, 0x5c, 0x5b, 0x88, 0x52, 0x7d);\nDEFINE_GUID(GUID_DEVINTERFACE_EMMC_PARTITION_ACCESS_RPMB, 0x27447c21L, 0xbcc3, 0x4d07, 0xa0, 0x5b, 0xa3, 0x39, 0x5b, 0xb4, 0xee, 0xe7);\nDEFINE_GUID(GUID_DEVINTERFACE_EMMC_PARTITION_ACCESS_GPP, 0x2e0e2e39L, 0x1f19, 0x4595, 0xa9, 0x06, 0x88, 0x78, 0x82, 0xe7, 0x39, 0x03);\nDEFINE_GUID(GUID_DEVINTERFACE_USB_SIDEBAND_AUDIO_HS_HCIBYPASS, 0x2baa4b5, 0x33b5, 0x4d97, 0xae, 0x4f, 0xe8, 0x6d, 0xde, 0x17, 0x53, 0x6f);\nDEFINE_GUID(GUID_BUS_VPCI, 0xc066f39a, 0xde00, 0x4667, 0x89, 0x41, 0x33, 0x68, 0xed, 0x5d, 0x83, 0xb5);\nDEFINE_GUID(GUID_VPCI_INTERFACE_STANDARD, 0x12e65e71, 0xb651, 0x4067, 0x83, 0x1a, 0x13, 0x83, 0x20, 0x3c, 0xb0, 0xcb);\nDEFINE_GUID(GUID_DEVINTERFACE_VPCI, 0x57863182, 0xc948, 0x4692, 0x97, 0xe3, 0x34, 0xb5, 0x76, 0x62, 0xa3, 0xe0);\nDEFINE_GUID(GUID_DEVINTERFACE_WWAN_CONTROLLER, 0x669159fd, 0xe3c0, 0x45cb, 0xbc, 0x5f, 0x95, 0x99, 0x5b, 0xcd, 0x6, 0xcd);\nDEFINE_GUID(GUID_DEVINTERFACE_WDDM3_ON_VB, 0xe922004d, 0xeb9c, 0x4de1, 0x92, 0x24, 0xa9, 0xce, 0xaa, 0x95, 0x9b, 0xce);\nDEFINE_GUID(GUID_DEVINTERFACE_GRAPHICSPOWER, 0xea5c6870, 0xe93c, 0x4588, 0xbe, 0xf1, 0xfe, 0xc4, 0x2f, 0xc9, 0x42, 0x9a);\nDEFINE_GUID(GUID_DEVINTERFACE_GNSS, 0x3336e5e4, 0x18a, 0x4669, 0x84, 0xc5, 0xbd, 0x5, 0xf3, 0xbd, 0x36, 0x8b);\nDEFINE_GUID(GUID_DEVINTERFACE_HID, 0x4D1E55B2L, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);\nDEFINE_GUID(GUID_DEVINTERFACE_LAMP, 0x6c11e9e3, 0x8238, 0x4f0a, 0x0a, 0x19, 0xaa, 0xec, 0x26, 0xca, 0x5e, 0x98);\nDEFINE_GUID(GUID_DEVINTERFACE_NFCDTA, 0x7fd3f30b, 0x5e49, 0x4be1, 0xb3, 0xaa, 0xaf, 0x06, 0x26, 0x0d, 0x23, 0x6a);\nDEFINE_GUID(GUID_DEVINTERFACE_NFCSE, 0x8dc7c854, 0xf5e5, 0x4bed, 0x81, 0x5d, 0xc, 0x85, 0xad, 0x4, 0x77, 0x25);\nDEFINE_GUID(GUID_DEVINTERFACE_NFP, 0xFB3842CD, 0x9E2A, 0x4F83, 0x8F, 0xCC, 0x4B, 0x07, 0x61, 0x13, 0x9A, 0xE9);\nDEFINE_GUID(GUID_DEVINTERFACE_KEYBOARD, 0x884b96c3, 0x56ef, 0x11d1, 0xbc, 0x8c, 0x00, 0xa0, 0xc9, 0x14, 0x05, 0xdd);\nDEFINE_GUID(GUID_DEVINTERFACE_MODEM, 0x2c7089aa, 0x2e0e, 0x11d1, 0xb1, 0x14, 0x00, 0xc0, 0x4f, 0xc2, 0xaa, 0xe4);\nDEFINE_GUID(GUID_DEVINTERFACE_MOUSE, 0x378de44c, 0x56ef, 0x11d1, 0xbc, 0x8c, 0x00, 0xa0, 0xc9, 0x14, 0x05, 0xdd );\nDEFINE_GUID(GUID_DEVINTERFACE_PARALLEL, 0x97F76EF0, 0xF883, 0x11D0, 0xAF, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x84, 0x5C);\nDEFINE_GUID(GUID_DEVINTERFACE_PARCLASS, 0x811FC6A5, 0xF728, 0x11D0, 0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1);\nDEFINE_GUID(GUID_PARALLEL_DEVICE, 0x97F76EF0, 0xF883, 0x11D0, 0xAF, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x84, 0x5C);\nDEFINE_GUID(GUID_PARCLASS_DEVICE, 0x811FC6A5, 0xF728, 0x11D0, 0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1);\nDEFINE_GUID(GUID_DEVINTERFACE_DISPLAY_ADAPTER, 0x5b45201d, 0xf2f2, 0x4f3b, 0x85, 0xbb, 0x30, 0xff, 0x1f, 0x95, 0x35, 0x99);\nDEFINE_GUID(GUID_DEVINTERFACE_MONITOR, 0xe6f07b5f, 0xee97, 0x4a90, 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7);\nDEFINE_GUID(GUID_DEVICE_BATTERY, 0x72631e54L, 0x78A4, 0x11d0, 0xbc, 0xf7, 0x00, 0xaa, 0x00, 0xb7, 0xb3, 0x2a);\nDEFINE_GUID(GUID_DEVICE_APPLICATIONLAUNCH_BUTTON, 0x629758eel, 0x986e, 0x4d9e, 0x8e, 0x47, 0xde, 0x27, 0xf8, 0xab, 0x05, 0x4d);\nDEFINE_GUID(GUID_DEVICE_SYS_BUTTON, 0x4AFA3D53L, 0x74A7, 0x11d0, 0xbe, 0x5e, 0x00, 0xA0, 0xC9, 0x06, 0x28, 0x57);\nDEFINE_GUID(GUID_DEVICE_LID, 0x4AFA3D52L, 0x74A7, 0x11d0, 0xbe, 0x5e, 0x00, 0xA0, 0xC9, 0x06, 0x28, 0x57);\nDEFINE_GUID(GUID_DEVICE_THERMAL_ZONE, 0x4AFA3D51L, 0x74A7, 0x11d0, 0xbe, 0x5e, 0x00, 0xA0, 0xC9, 0x06, 0x28, 0x57);\nDEFINE_GUID(GUID_DEVICE_FAN, 0x05ecd13dL, 0x81da, 0x4a2a, 0x8a, 0x4c, 0x52, 0x4f, 0x23, 0xdd, 0x4d, 0xc9);\nDEFINE_GUID(GUID_DEVICE_PROCESSOR, 0x97fadb10L, 0x4e33, 0x40ae, 0x35, 0x9c, 0x8b, 0xef, 0x02, 0x9d, 0xbd, 0xd0);\nDEFINE_GUID(GUID_DEVICE_MEMORY, 0x3fd0f03dL, 0x92e0, 0x45fb, 0xb7, 0x5c, 0x5e, 0xd8, 0xff, 0xb0, 0x10, 0x21);\nDEFINE_GUID(GUID_DEVICE_ACPI_TIME, 0x97f99bf6L, 0x4497, 0x4f18, 0xbb, 0x22, 0x4b, 0x9f, 0xb2, 0xfb, 0xef, 0x9c);\nDEFINE_GUID(GUID_DEVICE_MESSAGE_INDICATOR, 0XCD48A365L, 0xfa94, 0x4ce2, 0xa2, 0x32, 0xa1, 0xb7, 0x64, 0xe5, 0xd8, 0xb4);\nDEFINE_GUID(GUID_CLASS_INPUT, 0x4D1E55B2L, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);\nDEFINE_GUID(GUID_DEVINTERFACE_THERMAL_COOLING, 0xdbe4373d, 0x3c81, 0x40cb, 0xac, 0xe4, 0xe0, 0xe5, 0xd0, 0x5f, 0xc, 0x9f);\nDEFINE_GUID(GUID_DEVINTERFACE_THERMAL_MANAGER, 0x927ec093, 0x69a4, 0x4bc0, 0xbd, 0x2, 0x71, 0x16, 0x64, 0x71, 0x44, 0x63);\nDEFINE_GUID(GUID_DEVINTERFACE_PWM_CONTROLLER, 0x60824b4c, 0xeed1, 0x4c9c, 0xb4, 0x9c, 0x1b, 0x96, 0x14, 0x61, 0xa8, 0x19);\nDEFINE_GUID(GUID_DEVINTERFACE_USBPRINT, 0x28d78fad, 0x5a12, 0x11d1, 0xae, 0x5b, 0x0, 0x0, 0xf8, 0x3, 0xa8, 0xc2);\nDEFINE_GUID(GUID_DEVINTERFACE_IPPUSB_PRINT, 0xf2f40381, 0xf46d, 0x4e51, 0xbc, 0xe7, 0x62, 0xde, 0x6c, 0xf2, 0xd0, 0x98);\nDEFINE_GUID(GUID_DEVINTERFACE_VM_GENCOUNTER, 0x3ff2c92b, 0x6598, 0x4e60, 0x8e, 0x1c, 0x0c, 0xcf, 0x49, 0x27, 0xe3, 0x19);\nDEFINE_GUID(GUID_DEVINTERFACE_BIOMETRIC_READER, 0xe2b5183a, 0x99ea, 0x4cc3, 0xad, 0x6b, 0x80, 0xca, 0x8d, 0x71, 0x5b, 0x80);\nDEFINE_GUID(GUID_DEVINTERFACE_SMARTCARD_READER, 0x50DD5230, 0xBA8A, 0x11D1, 0xBF, 0x5D, 0x00, 0x00, 0xF8, 0x05, 0xF5, 0x30);\nDEFINE_GUID(GUID_DEVINTERFACE_DMR, 0xD0875FB4, 0x2196, 0x4c7a, 0xA6, 0x3D, 0xE4, 0x16, 0xAD, 0xDD, 0x60, 0xA1);\nDEFINE_GUID(GUID_DEVINTERFACE_DMP, 0x25B4E268, 0x2A05, 0x496e, 0x80, 0x3B, 0x26, 0x68, 0x37, 0xFB, 0xDA, 0x4B);\nDEFINE_GUID(GUID_DEVINTERFACE_DMS, 0xC96037AE, 0xA558, 0x4470, 0xB4, 0x32, 0x11, 0x5A, 0x31, 0xB8, 0x55, 0x53);\nDEFINE_GUID(GUID_DEVINTERFACE_ENHANCED_STORAGE_SILO, 0x3897f6a4, 0xfd35, 0x4bc8, 0xa0, 0xb7, 0x5d, 0xbb, 0xa3, 0x6a, 0xda, 0xfa);\nDEFINE_GUID(GUID_DEVINTERFACE_WPD, 0x6AC27878, 0xA6FA, 0x4155, 0xBA, 0x85, 0xF9, 0x8F, 0x49, 0x1D, 0x4F, 0x33);\nDEFINE_GUID(GUID_DEVINTERFACE_WPD_PRIVATE, 0xBA0C718F, 0x4DED, 0x49B7, 0xBD, 0xD3, 0xFA, 0xBE, 0x28, 0x66, 0x12, 0x11);\nDEFINE_GUID(GUID_DEVINTERFACE_WPD_SERVICE, 0x9EF44F80, 0x3D64, 0x4246, 0xA6, 0xAA, 0x20, 0x6F, 0x32, 0x8D, 0x1E, 0xDC);\nDEFINE_GUID(GUID_DEVINTERFACE_SENSOR, 0XBA1BB692, 0X9B7A, 0X4833, 0X9A, 0X1E, 0X52, 0X5E, 0XD1, 0X34, 0XE7, 0XE2);\nDEFINE_GUID(GUID_DEVINTERFACE_IMAGE, 0x6bdd1fc6L, 0x810f, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f);\nDEFINE_GUID(GUID_DEVINTERFACE_SIDESHOW, 0x152e5811, 0xfeb9, 0x4b00, 0x90, 0xf4, 0xd3, 0x29, 0x47, 0xae, 0x16, 0x81);\nDEFINE_GUID(GUID_DEVINTERFACE_WIFIDIRECT_DEVICE, 0x439b20af, 0x8955, 0x405b, 0x99, 0xf0, 0xa6, 0x2a, 0xf0, 0xc6, 0x8d, 0x43);\nDEFINE_GUID(GUID_AEPSERVICE_WIFIDIRECT_DEVICE, 0xcc29827c, 0x9caf, 0x4928, 0x99, 0xa9, 0x18, 0xf7, 0xc2, 0x38, 0x13, 0x89);\nDEFINE_GUID(GUID_DEVINTERFACE_ASP_INFRA_DEVICE, 0xff823995, 0x7a72, 0x4c80, 0x87, 0x57, 0xc6, 0x7e, 0xe1, 0x3d, 0x1a, 0x49);\nDEFINE_GUID(GUID_DXGKDDI_MITIGABLE_DEVICE_INTERFACE, 0x1387f270, 0x121a, 0x4a4a, 0xb2, 0x5e, 0x3b, 0x15, 0x89, 0x97, 0x6c, 0x61);\nDEFINE_GUID(GUID_DXGKDDI_FLEXIOV_DEVICE_INTERFACE, 0x7b73a997, 0x48e8, 0x4cab, 0x9f, 0xab, 0xe0, 0x77, 0x4b, 0x44, 0xf5, 0x99);\nDEFINE_GUID(GUID_SRIOV_DEVICE_INTERFACE_STANDARD, 0x937ee9b6, 0xed3, 0x411c, 0x98, 0x2b, 0x1f, 0x56, 0x4a, 0xfb, 0xab, 0xd3);\nDEFINE_GUID(GUID_MITIGABLE_DEVICE_INTERFACE, 0xadfd9567, 0x4245, 0x497e, 0x85, 0x72, 0x78, 0xd4, 0x5c, 0x16, 0x22, 0xb8);\nDEFINE_GUID(GUID_IO_VOLUME_DEVICE_INTERFACE, 0x53f5630d, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);\nDEFINE_GUID(GUID_NFC_RADIO_MEDIA_DEVICE_INTERFACE,  0x4d51e930, 0x750d, 0x4a36, 0xa9, 0xf7, 0x91, 0xdc, 0x54, 0x0f, 0xcd, 0x30);\nDEFINE_GUID(GUID_NFCSE_RADIO_MEDIA_DEVICE_INTERFACE, 0xef8ba08f, 0x148d, 0x4116, 0x83, 0xef, 0xa2, 0x67, 0x9d, 0xfc, 0x3f, 0xa5);\nDEFINE_GUID(GUID_BLUETOOTHLE_DEVICE_INTERFACE, 0x781aee18, 0x7733, 0x4ce4, 0xad, 0xd0, 0x91, 0xf4, 0x1c, 0x67, 0xb5, 0x92);\nDEFINE_GUID(GUID_BLUETOOTH_GATT_SERVICE_DEVICE_INTERFACE, 0x6e3bb679, 0x4372, 0x40c8, 0x9e, 0xaa, 0x45, 0x09, 0xdf, 0x26, 0x0c, 0xd8);\nDEFINE_GUID(GUID_BUS_TYPE_TREE, 0x4E815EE1, 0x20F8, 0x41EF, 0x8C, 0xFF, 0x3C, 0x28, 0x3F, 0x02, 0xD7, 0x22);\nDEFINE_GUID(GUID_TREE_TPM_SERVICE_FDTPM, 0x36deaa79, 0xc5dd, 0x447c, 0x95, 0xe6, 0xb3, 0x85, 0x95, 0x89, 0x29, 0x1a);\nDEFINE_GUID(GUID_TREE_TPM_SERVICE_STPM, 0x1F75CF6D, 0xF709, 0x4C0C, 0x8B, 0xCB, 0x0C, 0xDC, 0xA1, 0x28, 0x9D, 0xDD);\nDEFINE_GUID(GUID_DISPLAY_DEVICE_ARRIVAL, 0x1CA05180, 0xA699, 0x450A, 0x9A, 0x0C, 0xDE, 0x4F, 0xBE, 0x3D, 0xDD, 0x89);\nDEFINE_GUID(GUID_COMPUTE_DEVICE_ARRIVAL, 0x1024e4c9, 0x47c9, 0x48d3, 0xb4, 0xa8, 0xf9, 0xdf, 0x78, 0x52, 0x3b, 0x53);\n\nDEFINE_DEVPROPKEY(DEVPKEY_Gpu_Luid, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2); // DEVPROP_TYPE_UINT64\nDEFINE_DEVPROPKEY(DEVPKEY_Gpu_PhysicalAdapterIndex, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 3); // DEVPROP_TYPE_UINT32\n\n#include <SetupAPI.h>\n#include <cfgmgr32.h>\n#include <wdmguid.h>\n#include <bthdef.h>\n#include <devguid.h>\n#include <ndisguid.h>\n#include <usbiodef.h>\n\n#pragma push_macro(\"DEFINE_GUID\")\n#undef DEFINE_GUID\n#include <pciprop.h>\n#include <ntddstor.h>\n#pragma pop_macro(\"DEFINE_GUID\")\n\nstatic CONST PH_STRINGREF RootInstanceId = PH_STRINGREF_INIT(L\"HTREE\\\\ROOT\\\\0\");\nstatic ULONG RootInstanceIdHash = 2387464428; // PhHashStringRefEx(TRUE, PH_STRING_HASH_X65599);\nPPH_OBJECT_TYPE PhDeviceTreeType = NULL;\nPPH_OBJECT_TYPE PhDeviceItemType = NULL;\nPPH_OBJECT_TYPE PhDeviceNotifyType = NULL;\nstatic PPH_OBJECT_TYPE PhpDeviceInfoType = NULL;\nstatic PH_FAST_LOCK PhpDeviceTreeLock = PH_FAST_LOCK_INIT;\nstatic PPH_DEVICE_TREE PhpDeviceTree = NULL;\nstatic HCMNOTIFICATION PhpDeviceNotification = NULL;\nstatic HCMNOTIFICATION PhpDeviceInterfaceNotification = NULL;\nstatic PH_CALLBACK_REGISTRATION ServiceProviderUpdatedRegistration;\nstatic SLIST_HEADER PhDeviceNotifyListHead;\nstatic PH_FREE_LIST PhDeviceNotifyFreeList;\n\n#if !defined(NTDDI_WIN10_NI) || (NTDDI_VERSION < NTDDI_WIN10_NI)\n// Note: This propkey is required for building with 22H1 and older Windows SDK (dmex)\nDEFINE_DEVPROPKEY(DEVPKEY_Device_FirmwareVendor, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 26);   // DEVPROP_TYPE_STRING\n#endif\n\n#define DEVPROP_FILL_FLAG_CLASS  0x00000001\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\ntypedef\nVOID\nNTAPI\nPH_DEVICE_PROPERTY_FILL_CALLBACK(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    );\ntypedef PH_DEVICE_PROPERTY_FILL_CALLBACK* PPH_DEVICE_PROPERTY_FILL_CALLBACK;\n\ntypedef struct _PH_DEVICE_PROPERTY_TABLE_ENTRY\n{\n    PH_DEVICE_PROPERTY_CLASS PropClass;\n    const DEVPROPKEY* PropKey;\n    PPH_DEVICE_PROPERTY_FILL_CALLBACK Callback;\n    ULONG CallbackFlags;\n} PH_DEVICE_PROPERTY_TABLE_ENTRY, *PPH_DEVICE_PROPERTY_TABLE_ENTRY;\n\nBOOLEAN PhpGetDevicePropertyGuid(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PGUID Guid\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(GUID);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Guid,\n        sizeof(GUID),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_GUID))\n    {\n        return TRUE;\n    }\n\n    RtlZeroMemory(Guid, sizeof(GUID));\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyGuid(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PGUID Guid\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(GUID);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Guid,\n        sizeof(GUID),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_GUID))\n    {\n        return TRUE;\n    }\n\n    RtlZeroMemory(Guid, sizeof(GUID));\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetClassPropertyGuid(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PGUID Guid\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(GUID);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Guid,\n        sizeof(GUID),\n        &requiredLength,\n        Flags\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_GUID))\n    {\n        return TRUE;\n    }\n\n    RtlZeroMemory(Guid, sizeof(GUID));\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDevicePropertyUInt64(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PULONG64 Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(ULONG64);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(ULONG64),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_UINT64))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyUInt64(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PULONG64 Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(ULONG64);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(ULONG64),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_UINT64))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetClassPropertyUInt64(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PULONG64 Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(ULONG64);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(ULONG64),\n        &requiredLength,\n        Flags\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_UINT64))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDevicePropertyInt64(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PLONG64 Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(LONG64);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(LONG64),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_INT64))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyInt64(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PLONG64 Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(LONG64);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(LONG64),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_INT64))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetClassPropertyInt64(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PLONG64 Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(LONG64);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(LONG64),\n        &requiredLength,\n        Flags\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_INT64))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDevicePropertyUInt32(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PULONG Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(ULONG);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(ULONG),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_UINT32))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyUInt32(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PULONG Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(ULONG);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(ULONG),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_UINT32))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetClassPropertyUInt32(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PULONG Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(ULONG);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(ULONG),\n        &requiredLength,\n        Flags\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_UINT32))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDevicePropertyInt32(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PLONG Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(LONG);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(LONG),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_INT32))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyInt32(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PLONG Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(LONG);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(LONG),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_INT32))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetClassPropertyInt32(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PLONG Value\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(LONG);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Value,\n        sizeof(LONG),\n        &requiredLength,\n        Flags\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_INT32))\n    {\n        return TRUE;\n    }\n\n    *Value = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDevicePropertyNTSTATUS(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PNTSTATUS Status\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(NTSTATUS);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Status,\n        sizeof(NTSTATUS),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_NTSTATUS))\n    {\n        return TRUE;\n    }\n\n    *Status = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyNTSTATUS(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PNTSTATUS Status\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(NTSTATUS);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Status,\n        sizeof(NTSTATUS),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_NTSTATUS))\n    {\n        return TRUE;\n    }\n\n    *Status = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetClassPropertyNTSTATUS(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PNTSTATUS Status\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = sizeof(NTSTATUS);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)Status,\n        sizeof(NTSTATUS),\n        &requiredLength,\n        Flags\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_NTSTATUS))\n    {\n        return TRUE;\n    }\n\n    *Status = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDevicePropertyBoolean(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PBOOLEAN Boolean\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    DEVPROP_BOOLEAN boolean;\n    ULONG requiredLength = sizeof(DEVPROP_BOOLEAN);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)&boolean,\n        sizeof(DEVPROP_BOOLEAN),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_BOOLEAN))\n    {\n        *Boolean = boolean == DEVPROP_TRUE;\n\n        return TRUE;\n    }\n\n    *Boolean = FALSE;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyBoolean(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PBOOLEAN Boolean\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    DEVPROP_BOOLEAN boolean;\n    ULONG requiredLength = sizeof(DEVPROP_BOOLEAN);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)&boolean,\n        sizeof(DEVPROP_BOOLEAN),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_BOOLEAN))\n    {\n        *Boolean = boolean == DEVPROP_TRUE;\n\n        return TRUE;\n    }\n\n    *Boolean = FALSE;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetClassPropertyBoolean(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PBOOLEAN Boolean\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    DEVPROP_BOOLEAN boolean;\n    ULONG requiredLength = sizeof(DEVPROP_BOOLEAN);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)&boolean,\n        sizeof(DEVPROP_BOOLEAN),\n        &requiredLength,\n        Flags\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_BOOLEAN))\n    {\n        *Boolean = boolean == DEVPROP_TRUE;\n\n        return TRUE;\n    }\n\n    *Boolean = FALSE;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDevicePropertyTimeStamp(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PLARGE_INTEGER TimeStamp\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    FILETIME fileTime;\n    ULONG requiredLength = sizeof(FILETIME);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)&fileTime,\n        sizeof(FILETIME),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_FILETIME))\n    {\n        TimeStamp->HighPart = fileTime.dwHighDateTime;\n        TimeStamp->LowPart = fileTime.dwLowDateTime;\n\n        return TRUE;\n    }\n\n    TimeStamp->QuadPart = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyTimeStamp(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PLARGE_INTEGER TimeStamp\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    FILETIME fileTime;\n    ULONG requiredLength = sizeof(FILETIME);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)&fileTime,\n        sizeof(FILETIME),\n        &requiredLength,\n        0\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_FILETIME))\n    {\n        TimeStamp->HighPart = fileTime.dwHighDateTime;\n        TimeStamp->LowPart = fileTime.dwLowDateTime;\n\n        return TRUE;\n    }\n\n    TimeStamp->QuadPart = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetClassPropertyTimeStamp(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PLARGE_INTEGER TimeStamp\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    FILETIME fileTime;\n    ULONG requiredLength = sizeof(FILETIME);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)&fileTime,\n        sizeof(FILETIME),\n        &requiredLength,\n        Flags\n        );\n    if (result && (devicePropertyType == DEVPROP_TYPE_FILETIME))\n    {\n        TimeStamp->HighPart = fileTime.dwHighDateTime;\n        TimeStamp->LowPart = fileTime.dwLowDateTime;\n\n        return TRUE;\n    }\n\n    TimeStamp->QuadPart = 0;\n\n    return FALSE;\n}\n\nBOOLEAN PhpGetDevicePropertyString(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PPH_STRING* String\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = 0;\n    PPH_STRING string;\n\n    *String = NULL;\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        NULL,\n        0,\n        &requiredLength,\n        0\n        );\n    if (result ||\n        (requiredLength == 0) ||\n        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||\n        ((devicePropertyType != DEVPROP_TYPE_STRING) &&\n         (devicePropertyType != DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING)))\n    {\n        return FALSE;\n    }\n\n    if (requiredLength < sizeof(UNICODE_NULL))\n    {\n        *String = PhReferenceEmptyString();\n        return TRUE;\n    }\n\n    string = PhCreateStringEx(NULL, requiredLength - sizeof(UNICODE_NULL));\n\n    if (SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)string->Buffer,\n        requiredLength,\n        &requiredLength,\n        0\n        ))\n    {\n        *String = string;\n        return TRUE;\n    }\n\n    PhClearReference(&string);\n    return FALSE;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyString(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PPH_STRING* String\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = 0;\n    PPH_STRING string;\n\n    *String = NULL;\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        NULL,\n        0,\n        &requiredLength,\n        0\n        );\n    if (result ||\n        (requiredLength == 0) ||\n        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||\n        ((devicePropertyType != DEVPROP_TYPE_STRING) &&\n         (devicePropertyType != DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING)))\n    {\n        return FALSE;\n    }\n\n    if (requiredLength < sizeof(UNICODE_NULL))\n    {\n        *String = PhReferenceEmptyString();\n        return TRUE;\n    }\n\n    string = PhCreateStringEx(NULL, requiredLength - sizeof(UNICODE_NULL));\n\n    if (SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)string->Buffer,\n        requiredLength,\n        &requiredLength,\n        0\n        ))\n    {\n        *String = string;\n        return TRUE;\n    }\n\n    PhClearReference(&string);\n    return FALSE;\n}\n\nBOOLEAN PhpGetClassPropertyString(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PPH_STRING* String\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = 0;\n    PPH_STRING string;\n\n    *String = NULL;\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        NULL,\n        0,\n        &requiredLength,\n        Flags\n        );\n    if (result ||\n        (requiredLength == 0) ||\n        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||\n        ((devicePropertyType != DEVPROP_TYPE_STRING) &&\n         (devicePropertyType != DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING)))\n    {\n        return FALSE;\n    }\n\n    if (requiredLength < sizeof(UNICODE_NULL))\n    {\n        *String = PhReferenceEmptyString();\n        return TRUE;\n    }\n\n    string = PhCreateStringEx(NULL, requiredLength - sizeof(UNICODE_NULL));\n\n    if (SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        (PBYTE)string->Buffer,\n        requiredLength,\n        &requiredLength,\n        Flags\n        ))\n    {\n        *String = string;\n        return TRUE;\n    }\n\n    PhClearReference(&string);\n    return FALSE;\n}\n\nBOOLEAN PhpGetDevicePropertyStringList(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PPH_LIST* StringList\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = 0;\n    PVOID buffer = NULL;\n    PPH_LIST stringList;\n\n    *StringList = NULL;\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        NULL,\n        0,\n        &requiredLength,\n        0\n        );\n    if (result ||\n        (requiredLength == 0) ||\n        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||\n        (devicePropertyType != DEVPROP_TYPE_STRING_LIST))\n    {\n        goto Exit;\n    }\n\n    buffer = PhAllocate(requiredLength);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        buffer,\n        requiredLength,\n        &requiredLength,\n        0\n        );\n    if (!result)\n    {\n        goto Exit;\n    }\n\n    stringList = PhCreateList(1);\n\n    for (PZZWSTR item = buffer;;)\n    {\n        PH_STRINGREF string;\n\n        PhInitializeStringRefLongHint(&string, item);\n\n        if (string.Length == 0)\n        {\n            break;\n        }\n\n        PhAddItemList(stringList, PhCreateString2(&string));\n\n        item = PTR_ADD_OFFSET(item, string.Length + sizeof(UNICODE_NULL));\n    }\n\n    *StringList = stringList;\n\nExit:\n\n    if (buffer)\n        PhFree(buffer);\n\n    return !!result;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyStringList(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PPH_LIST* StringList\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = 0;\n    PVOID buffer = NULL;\n    PPH_LIST stringList;\n\n    *StringList = NULL;\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        NULL,\n        0,\n        &requiredLength,\n        0\n        );\n    if (result ||\n        (requiredLength == 0) ||\n        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||\n        (devicePropertyType != DEVPROP_TYPE_STRING_LIST))\n    {\n        goto Exit;\n    }\n\n    buffer = PhAllocate(requiredLength);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        buffer,\n        requiredLength,\n        &requiredLength,\n        0\n        );\n    if (!result)\n    {\n        goto Exit;\n    }\n\n    stringList = PhCreateList(1);\n\n    for (PZZWSTR item = buffer;;)\n    {\n        PH_STRINGREF string;\n\n        PhInitializeStringRefLongHint(&string, item);\n\n        if (string.Length == 0)\n        {\n            break;\n        }\n\n        PhAddItemList(stringList, PhCreateString2(&string));\n\n        item = PTR_ADD_OFFSET(item, string.Length + sizeof(UNICODE_NULL));\n    }\n\n    *StringList = stringList;\n\nExit:\n\n    if (buffer)\n        PhFree(buffer);\n\n    return !!result;\n}\n\nBOOLEAN PhpGetClassPropertyStringList(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PPH_LIST* StringList\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = 0;\n    PVOID buffer = NULL;\n    PPH_LIST stringList;\n\n    *StringList = NULL;\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        NULL,\n        0,\n        &requiredLength,\n        Flags\n        );\n    if (result ||\n        (requiredLength == 0) ||\n        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||\n        (devicePropertyType != DEVPROP_TYPE_STRING_LIST))\n    {\n        goto Exit;\n    }\n\n    buffer = PhAllocate(requiredLength);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        buffer,\n        requiredLength,\n        &requiredLength,\n        Flags\n        );\n    if (!result)\n    {\n        goto Exit;\n    }\n\n    stringList = PhCreateList(1);\n\n    for (PZZWSTR item = buffer;;)\n    {\n        PH_STRINGREF string;\n\n        PhInitializeStringRefLongHint(&string, item);\n\n        if (string.Length == 0)\n        {\n            break;\n        }\n\n        PhAddItemList(stringList, PhCreateString2(&string));\n\n        item = PTR_ADD_OFFSET(item, string.Length + sizeof(UNICODE_NULL));\n    }\n\n    *StringList = stringList;\n\nExit:\n\n    if (buffer)\n        PhFree(buffer);\n\n    return !!result;\n}\n\nBOOLEAN PhpGetDevicePropertyBinary(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PBYTE* Buffer,\n    _Out_ PULONG Size\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = 0;\n    PVOID buffer = NULL;\n\n    *Buffer = NULL;\n    *Size = 0;\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        NULL,\n        0,\n        &requiredLength,\n        0\n        );\n    if (result ||\n        (requiredLength == 0) ||\n        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||\n        ((devicePropertyType != DEVPROP_TYPE_BINARY) &&\n         (devicePropertyType != DEVPROP_TYPE_SECURITY_DESCRIPTOR)))\n    {\n        goto Exit;\n    }\n\n    buffer = PhAllocate(requiredLength);\n\n    result = SetupDiGetDevicePropertyW(\n        DeviceInfoSet,\n        DeviceInfoData,\n        DeviceProperty,\n        &devicePropertyType,\n        buffer,\n        requiredLength,\n        &requiredLength,\n        0\n        );\n    if (!result)\n    {\n        goto Exit;\n    }\n\n    *Size = requiredLength;\n    *Buffer = buffer;\n    buffer = NULL;\n\nExit:\n\n    if (buffer)\n        PhFree(buffer);\n\n    return !!result;\n}\n\nBOOLEAN PhpGetDeviceInterfacePropertyBinary(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _Out_ PBYTE* Buffer,\n    _Out_ PULONG Size\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = 0;\n    PVOID buffer = NULL;\n\n    *Buffer = NULL;\n    *Size = 0;\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        NULL,\n        0,\n        &requiredLength,\n        0\n        );\n    if (result ||\n        (requiredLength == 0) ||\n        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||\n        ((devicePropertyType != DEVPROP_TYPE_BINARY) &&\n         (devicePropertyType != DEVPROP_TYPE_SECURITY_DESCRIPTOR)))\n    {\n        goto Exit;\n    }\n\n    buffer = PhAllocate(requiredLength);\n\n    result = SetupDiGetDeviceInterfacePropertyW(\n        DeviceInfoSet,\n        DeviceInterfaceData,\n        DeviceProperty,\n        &devicePropertyType,\n        buffer,\n        requiredLength,\n        &requiredLength,\n        0\n        );\n    if (!result)\n    {\n        goto Exit;\n    }\n\n    *Size = requiredLength;\n    *Buffer = buffer;\n    buffer = NULL;\n\nExit:\n\n    if (buffer)\n        PhFree(buffer);\n\n    return !!result;\n}\n\nBOOLEAN PhpGetClassPropertyBinary(\n    _In_ const GUID* ClassGuid,\n    _In_ const DEVPROPKEY* DeviceProperty,\n    _In_ ULONG Flags,\n    _Out_ PBYTE* Buffer,\n    _Out_ PULONG Size\n    )\n{\n    BOOL result;\n    DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY;\n    ULONG requiredLength = 0;\n    PVOID buffer = NULL;\n\n    *Buffer = NULL;\n    *Size = 0;\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        NULL,\n        0,\n        &requiredLength,\n        Flags\n        );\n    if (result ||\n        (requiredLength == 0) ||\n        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||\n        ((devicePropertyType != DEVPROP_TYPE_BINARY) &&\n         (devicePropertyType != DEVPROP_TYPE_SECURITY_DESCRIPTOR)))\n    {\n        goto Exit;\n    }\n\n    buffer = PhAllocate(requiredLength);\n\n    result = SetupDiGetClassPropertyW(\n        ClassGuid,\n        DeviceProperty,\n        &devicePropertyType,\n        buffer,\n        requiredLength,\n        &requiredLength,\n        Flags\n        );\n    if (!result)\n    {\n        goto Exit;\n    }\n\n    *Size = requiredLength;\n    *Buffer = buffer;\n    buffer = NULL;\n\nExit:\n\n    if (buffer)\n        PhFree(buffer);\n\n    return !!result;\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillString(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeString;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyString(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->String\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyString(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->String\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyString(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->String\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyString(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->String\n                );\n        }\n    }\n\n    if (Property->Valid)\n    {\n        Property->AsString = Property->String;\n        PhReferenceObject(Property->AsString);\n    }\n}\n\nVOID PhpDevPropFillUInt64Common(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeUInt64;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyUInt64(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->UInt64\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyUInt64(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->UInt64\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyUInt64(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->UInt64\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyUInt64(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->UInt64\n                );\n        }\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillUInt64(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillUInt64Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        PH_FORMAT format[1];\n\n        PhInitFormatI64U(&format[0], Property->UInt64);\n\n        Property->AsString = PhFormat(format, ARRAYSIZE(format), 1);\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillUInt64Hex(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillUInt64Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        PH_FORMAT format[2];\n\n        PhInitFormatI64X(&format[1], Property->UInt64);\n\n        Property->AsString = PhFormat(format, ARRAYSIZE(format), 10);\n    }\n}\n\nVOID PhpDevPropFillInt64Common(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeInt64;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyInt64(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->Int64\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyInt64(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->Int64\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyInt64(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->Int64\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyInt64(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->Int64\n                );\n        }\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillInt64(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillInt64Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        PH_FORMAT format[1];\n\n        PhInitFormatI64D(&format[0], Property->Int64);\n\n        Property->AsString = PhFormat(format, ARRAYSIZE(format), 1);\n    }\n}\n\nVOID PhpDevPropFillUInt32Common(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeUInt32;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyUInt32(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->UInt32\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyUInt32(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->UInt32\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyUInt32(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->UInt32\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyUInt32(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->UInt32\n                );\n        }\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillUInt32(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillUInt32Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        PH_FORMAT format[1];\n\n        PhInitFormatU(&format[0], Property->UInt32);\n\n        Property->AsString = PhFormat(format, ARRAYSIZE(format), 1);\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillUInt32Hex(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillUInt32Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        PH_FORMAT format[2];\n\n        PhInitFormatS(&format[0], L\"0x\");\n        PhInitFormatIX(&format[1], Property->UInt32);\n\n        Property->AsString = PhFormat(format, ARRAYSIZE(format), 10);\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillInt32(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeUInt32;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyInt32(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->Int32\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyInt32(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->Int32\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyInt32(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->Int32\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyInt32(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->Int32\n                );\n        }\n    }\n\n    if (Property->Valid)\n    {\n        PH_FORMAT format[1];\n\n        PhInitFormatD(&format[0], Property->Int32);\n\n        Property->AsString = PhFormat(format, ARRAYSIZE(format), 1);\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillNTSTATUS(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeNTSTATUS;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyNTSTATUS(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->Status\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyNTSTATUS(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->Status\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyNTSTATUS(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->Status\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyNTSTATUS(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->Status\n                );\n        }\n    }\n\n    if (Property->Valid && Property->Status != STATUS_SUCCESS)\n    {\n        Property->AsString = PhGetStatusMessage(Property->Status, 0);\n    }\n}\n\ntypedef struct _PH_WELL_KNOWN_GUID\n{\n    const GUID* Guid;\n    PH_STRINGREF Symbol;\n} PH_WELL_KNOWN_GUID, *PPH_WELL_KNOWN_GUID;\n#define PH_DEFINE_WELL_KNOWN_GUID(guid) const PH_WELL_KNOWN_GUID PH_WELL_KNOWN_##guid = { &(guid), PH_STRINGREF_INIT(TEXT(#guid)) }\n\nPH_DEFINE_WELL_KNOWN_GUID(GUID_HWPROFILE_QUERY_CHANGE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_HWPROFILE_CHANGE_CANCELLED);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_HWPROFILE_CHANGE_COMPLETE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_INTERFACE_ARRIVAL);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_INTERFACE_REMOVAL);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_TARGET_DEVICE_QUERY_REMOVE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_TARGET_DEVICE_REMOVE_CANCELLED);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_TARGET_DEVICE_REMOVE_COMPLETE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PNP_CUSTOM_NOTIFICATION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PNP_POWER_NOTIFICATION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PNP_POWER_SETTING_CHANGE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_TARGET_DEVICE_TRANSPORT_RELATIONS_CHANGED);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_KERNEL_SOFT_RESTART_PREPARE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_KERNEL_SOFT_RESTART_CANCEL);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_RECOVERY_PCI_PREPARE_SHUTDOWN);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_RECOVERY_NVMED_PREPARE_SHUTDOWN);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_KERNEL_SOFT_RESTART_FINALIZE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_BUS_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_BUS_INTERFACE_STANDARD2);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_ARBITER_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_TRANSLATOR_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_ACPI_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_INT_ROUTE_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCMCIA_BUS_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_ACPI_REGS_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_LEGACY_DEVICE_DETECTION_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_DEVICE_PRESENT_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_MF_ENUMERATION_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_REENUMERATE_SELF_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_AGP_TARGET_BUS_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_ACPI_CMOS_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_ACPI_PORT_RANGES_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_ACPI_INTERFACE_STANDARD2);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PNP_LOCATION_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_EXPRESS_LINK_QUIESCENT_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_EXPRESS_ROOT_PORT_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_MSIX_TABLE_CONFIG_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_D3COLD_SUPPORT_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PROCESSOR_PCC_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_VIRTUALIZATION_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCC_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCC_INTERFACE_INTERNAL);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_THERMAL_COOLING_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DMA_CACHE_COHERENCY_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_RESET_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_IOMMU_BUS_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_SECURITY_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_SCM_BUS_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_SECURE_DRIVER_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_SDEV_IDENTIFIER_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_SCM_BUS_NVD_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_SCM_BUS_LD_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_SCM_PHYSICAL_NVDIMM_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PNP_EXTENDED_ADDRESS_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_D3COLD_AUX_POWER_AND_TIMING_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_FPGA_CONTROL_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_PTM_CONTROL_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_RESOURCE_UPDATE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_NPEM_CONTROL_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PCI_ATS_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_INTERNAL);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_PCMCIA);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_PCI);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_ISAPNP);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_EISA);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_MCA);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_SERENUM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_USB);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_LPTENUM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_USBPRINT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_DOT4PRT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_1394);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_HID);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_AVC);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_IRDA);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_SD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_ACPI);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_SW_DEVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_SCM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_POWER_DEVICE_ENABLE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_POWER_DEVICE_TIMEOUTS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_POWER_DEVICE_WAKE_ENABLE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_WUDF_DEVICE_HOST_PROBLEM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PARTITION_UNIT_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_QUERY_CRASHDUMP_FUNCTIONS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_DISK);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_CDROM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_PARTITION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_TAPE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_WRITEONCEDISK);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_VOLUME);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_MEDIUMCHANGER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_FLOPPY);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_CDCHANGER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_STORAGEPORT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_VMLUN);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_SES);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_ZNSDISK);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_SERVICE_VOLUME);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_UNIFIED_ACCESS_RPMB);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_SCM_PHYSICAL_DEVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_SCM_PD_HEALTH_NOTIFICATION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_SCM_PD_PASSTHROUGH_INVDIMM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_COMPORT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BTHPORT_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BTH_RFCOMM_SERVICE_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_1394);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_1394DEBUG);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_61883);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_ADAPTER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_APMSUPPORT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_AVC);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_BATTERY);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_BIOMETRIC);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_BLUETOOTH);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_CAMERA);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_CDROM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_COMPUTEACCELERATOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_COMPUTER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_DECODER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_DISKDRIVE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_DISPLAY);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_DOT4);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_DOT4PRINT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_EHSTORAGESILO);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_ENUM1394);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_EXTENSION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FDC);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FIRMWARE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FLOPPYDISK);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_GENERIC);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_GPS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_HDC);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_HIDCLASS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_HOLOGRAPHIC);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_IMAGE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_INFINIBAND);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_INFRARED);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_KEYBOARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_LEGACYDRIVER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_MEDIA);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_MEDIUM_CHANGER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_MEMORY);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_MODEM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_MONITOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_MOUSE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_MTD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_MULTIFUNCTION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_MULTIPORTSERIAL);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_NET);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_NETCLIENT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_NETDRIVER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_NETSERVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_NETTRANS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_NETUIO);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_NODRIVER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_PCMCIA);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_PNPPRINTERS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_PORTS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_PRIMITIVE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_PRINTER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_PRINTERUPGRADE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_PRINTQUEUE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_PROCESSOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SBP2);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SCMDISK);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SCMVOLUME);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SCSIADAPTER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SECURITYACCELERATOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SENSOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SIDESHOW);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SMARTCARDREADER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SMRDISK);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SMRVOLUME);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SOFTWARECOMPONENT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SOUND);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_SYSTEM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_TAPEDRIVE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_UNKNOWN);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_UCM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_USB);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_VOLUME);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_VOLUMESNAPSHOT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_WCEUSBS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_WPD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_TOP);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_ACTIVITYMONITOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_UNDELETE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_ANTIVIRUS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_REPLICATION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_CONTINUOUSBACKUP);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_CONTENTSCREENER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_QUOTAMANAGEMENT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_SYSTEMRECOVERY);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_CFSMETADATASERVER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_HSM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_COMPRESSION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_ENCRYPTION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_VIRTUALIZATION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_PHYSICALQUOTAMANAGEMENT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_OPENFILEBACKUP);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_SECURITYENHANCER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_COPYPROTECTION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_BOTTOM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_SYSTEM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVCLASS_FSFILTER_INFRASTRUCTURE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_USB_HUB);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_USB_BILLBOARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_USB_DEVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_USB_HOST_CONTROLLER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_A2DP_SIDEBAND_AUDIO);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_BLUETOOTH_HFP_SCO_HCIBYPASS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_CHARGING_ARBITRATION);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_CONFIGURABLE_USBFN_CHARGER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_CONFIGURABLE_WIRELESS_CHARGER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_I2C);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_OPM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_OPM_2_JTP);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_OPM_2);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_OPM_3);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_BRIGHTNESS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_BRIGHTNESS_2);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_MIRACAST_DISPLAY);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_BRIGHTNESS_3);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_HPMI);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_EMMC_PARTITION_ACCESS_RPMB);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_EMMC_PARTITION_ACCESS_GPP);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_USB_SIDEBAND_AUDIO_HS_HCIBYPASS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_VPCI);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_VPCI_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_VPCI);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_WWAN_CONTROLLER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_WDDM3_ON_VB);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_GRAPHICSPOWER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_GNSS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_HID);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_LAMP);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_NET);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_NETUIO);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_NFCDTA);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_NFCSE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_NFP);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_KEYBOARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_MODEM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_MOUSE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_PARALLEL);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_PARCLASS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PARALLEL_DEVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_PARCLASS_DEVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_DISPLAY_ADAPTER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_MONITOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_BATTERY);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_APPLICATIONLAUNCH_BUTTON);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_SYS_BUTTON);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_LID);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_THERMAL_ZONE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_FAN);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_PROCESSOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_MEMORY);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_ACPI_TIME);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVICE_MESSAGE_INDICATOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_CLASS_INPUT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_THERMAL_COOLING);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_THERMAL_MANAGER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_PWM_CONTROLLER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_USBPRINT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_IPPUSB_PRINT);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_VM_GENCOUNTER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_BIOMETRIC_READER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_SMARTCARD_READER);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_DMR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_DMP);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_DMS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_ENHANCED_STORAGE_SILO);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_WPD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_WPD_PRIVATE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_WPD_SERVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_SENSOR);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_IMAGE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_SIDESHOW);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_WIFIDIRECT_DEVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_AEPSERVICE_WIFIDIRECT_DEVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DEVINTERFACE_ASP_INFRA_DEVICE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DXGKDDI_MITIGABLE_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DXGKDDI_FLEXIOV_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_SRIOV_DEVICE_INTERFACE_STANDARD);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_MITIGABLE_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_IO_VOLUME_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_NDIS_LAN_CLASS);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_NFC_RADIO_MEDIA_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_NFCSE_RADIO_MEDIA_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BLUETOOTHLE_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BLUETOOTH_GATT_SERVICE_DEVICE_INTERFACE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_BUS_TYPE_TREE);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_TREE_TPM_SERVICE_FDTPM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_TREE_TPM_SERVICE_STPM);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_DISPLAY_DEVICE_ARRIVAL);\nPH_DEFINE_WELL_KNOWN_GUID(GUID_COMPUTE_DEVICE_ARRIVAL);\n\nstatic PH_INITONCE PhpWellKnownGuidsInitOnce = PH_INITONCE_INIT;\nstatic const PH_WELL_KNOWN_GUID* PhpWellKnownGuids[] =\n{\n    &PH_WELL_KNOWN_GUID_HWPROFILE_QUERY_CHANGE,\n    &PH_WELL_KNOWN_GUID_HWPROFILE_CHANGE_CANCELLED,\n    &PH_WELL_KNOWN_GUID_HWPROFILE_CHANGE_COMPLETE,\n    &PH_WELL_KNOWN_GUID_DEVICE_INTERFACE_ARRIVAL,\n    &PH_WELL_KNOWN_GUID_DEVICE_INTERFACE_REMOVAL,\n    &PH_WELL_KNOWN_GUID_TARGET_DEVICE_QUERY_REMOVE,\n    &PH_WELL_KNOWN_GUID_TARGET_DEVICE_REMOVE_CANCELLED,\n    &PH_WELL_KNOWN_GUID_TARGET_DEVICE_REMOVE_COMPLETE,\n    &PH_WELL_KNOWN_GUID_PNP_CUSTOM_NOTIFICATION,\n    &PH_WELL_KNOWN_GUID_PNP_POWER_NOTIFICATION,\n    &PH_WELL_KNOWN_GUID_PNP_POWER_SETTING_CHANGE,\n    &PH_WELL_KNOWN_GUID_TARGET_DEVICE_TRANSPORT_RELATIONS_CHANGED,\n    &PH_WELL_KNOWN_GUID_KERNEL_SOFT_RESTART_PREPARE,\n    &PH_WELL_KNOWN_GUID_KERNEL_SOFT_RESTART_CANCEL,\n    &PH_WELL_KNOWN_GUID_RECOVERY_PCI_PREPARE_SHUTDOWN,\n    &PH_WELL_KNOWN_GUID_RECOVERY_NVMED_PREPARE_SHUTDOWN,\n    &PH_WELL_KNOWN_GUID_KERNEL_SOFT_RESTART_FINALIZE,\n    &PH_WELL_KNOWN_GUID_BUS_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_PCI_BUS_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_PCI_BUS_INTERFACE_STANDARD2,\n    &PH_WELL_KNOWN_GUID_ARBITER_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_TRANSLATOR_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_ACPI_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_INT_ROUTE_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_PCMCIA_BUS_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_ACPI_REGS_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_LEGACY_DEVICE_DETECTION_STANDARD,\n    &PH_WELL_KNOWN_GUID_PCI_DEVICE_PRESENT_INTERFACE,\n    &PH_WELL_KNOWN_GUID_MF_ENUMERATION_INTERFACE,\n    &PH_WELL_KNOWN_GUID_REENUMERATE_SELF_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_AGP_TARGET_BUS_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_ACPI_CMOS_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_ACPI_PORT_RANGES_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_ACPI_INTERFACE_STANDARD2,\n    &PH_WELL_KNOWN_GUID_PNP_LOCATION_INTERFACE,\n    &PH_WELL_KNOWN_GUID_PCI_EXPRESS_LINK_QUIESCENT_INTERFACE,\n    &PH_WELL_KNOWN_GUID_PCI_EXPRESS_ROOT_PORT_INTERFACE,\n    &PH_WELL_KNOWN_GUID_MSIX_TABLE_CONFIG_INTERFACE,\n    &PH_WELL_KNOWN_GUID_D3COLD_SUPPORT_INTERFACE,\n    &PH_WELL_KNOWN_GUID_PROCESSOR_PCC_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_PCI_VIRTUALIZATION_INTERFACE,\n    &PH_WELL_KNOWN_GUID_PCC_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_PCC_INTERFACE_INTERNAL,\n    &PH_WELL_KNOWN_GUID_THERMAL_COOLING_INTERFACE,\n    &PH_WELL_KNOWN_GUID_DMA_CACHE_COHERENCY_INTERFACE,\n    &PH_WELL_KNOWN_GUID_DEVICE_RESET_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_IOMMU_BUS_INTERFACE,\n    &PH_WELL_KNOWN_GUID_PCI_SECURITY_INTERFACE,\n    &PH_WELL_KNOWN_GUID_SCM_BUS_INTERFACE,\n    &PH_WELL_KNOWN_GUID_SECURE_DRIVER_INTERFACE,\n    &PH_WELL_KNOWN_GUID_SDEV_IDENTIFIER_INTERFACE,\n    &PH_WELL_KNOWN_GUID_SCM_BUS_NVD_INTERFACE,\n    &PH_WELL_KNOWN_GUID_SCM_BUS_LD_INTERFACE,\n    &PH_WELL_KNOWN_GUID_SCM_PHYSICAL_NVDIMM_INTERFACE,\n    &PH_WELL_KNOWN_GUID_PNP_EXTENDED_ADDRESS_INTERFACE,\n    &PH_WELL_KNOWN_GUID_D3COLD_AUX_POWER_AND_TIMING_INTERFACE,\n    &PH_WELL_KNOWN_GUID_PCI_FPGA_CONTROL_INTERFACE,\n    &PH_WELL_KNOWN_GUID_PCI_PTM_CONTROL_INTERFACE,\n    &PH_WELL_KNOWN_GUID_BUS_RESOURCE_UPDATE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_NPEM_CONTROL_INTERFACE,\n    &PH_WELL_KNOWN_GUID_PCI_ATS_INTERFACE,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_INTERNAL,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_PCMCIA,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_PCI,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_ISAPNP,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_EISA,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_MCA,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_SERENUM,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_USB,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_LPTENUM,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_USBPRINT,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_DOT4PRT,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_1394,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_HID,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_AVC,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_IRDA,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_SD,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_ACPI,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_SW_DEVICE,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_SCM,\n    &PH_WELL_KNOWN_GUID_POWER_DEVICE_ENABLE,\n    &PH_WELL_KNOWN_GUID_POWER_DEVICE_TIMEOUTS,\n    &PH_WELL_KNOWN_GUID_POWER_DEVICE_WAKE_ENABLE,\n    &PH_WELL_KNOWN_GUID_WUDF_DEVICE_HOST_PROBLEM,\n    &PH_WELL_KNOWN_GUID_PARTITION_UNIT_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_QUERY_CRASHDUMP_FUNCTIONS,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_DISK,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_CDROM,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_PARTITION,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_TAPE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_WRITEONCEDISK,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_VOLUME,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_MEDIUMCHANGER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_FLOPPY,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_CDCHANGER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_STORAGEPORT,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_VMLUN,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_SES,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_ZNSDISK,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_SERVICE_VOLUME,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_HIDDEN_VOLUME,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_UNIFIED_ACCESS_RPMB,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_SCM_PHYSICAL_DEVICE,\n    &PH_WELL_KNOWN_GUID_SCM_PD_HEALTH_NOTIFICATION,\n    &PH_WELL_KNOWN_GUID_SCM_PD_PASSTHROUGH_INVDIMM,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_COMPORT,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR,\n    &PH_WELL_KNOWN_GUID_BTHPORT_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_BTH_RFCOMM_SERVICE_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_1394,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_1394DEBUG,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_61883,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_ADAPTER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_APMSUPPORT,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_AVC,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_BATTERY,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_BIOMETRIC,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_BLUETOOTH,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_CAMERA,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_CDROM,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_COMPUTEACCELERATOR,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_COMPUTER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_DECODER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_DISKDRIVE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_DISPLAY,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_DOT4,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_DOT4PRINT,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_EHSTORAGESILO,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_ENUM1394,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_EXTENSION,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FDC,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FIRMWARE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FLOPPYDISK,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_GENERIC,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_GPS,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_HDC,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_HIDCLASS,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_HOLOGRAPHIC,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_IMAGE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_INFINIBAND,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_INFRARED,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_KEYBOARD,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_LEGACYDRIVER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_MEDIA,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_MEDIUM_CHANGER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_MEMORY,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_MODEM,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_MONITOR,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_MOUSE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_MTD,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_MULTIFUNCTION,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_MULTIPORTSERIAL,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_NET,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_NETCLIENT,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_NETDRIVER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_NETSERVICE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_NETTRANS,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_NETUIO,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_NODRIVER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_PCMCIA,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_PNPPRINTERS,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_PORTS,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_PRIMITIVE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_PRINTER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_PRINTERUPGRADE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_PRINTQUEUE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_PROCESSOR,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SBP2,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SCMDISK,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SCMVOLUME,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SCSIADAPTER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SECURITYACCELERATOR,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SENSOR,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SIDESHOW,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SMARTCARDREADER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SMRDISK,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SMRVOLUME,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SOFTWARECOMPONENT,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SOUND,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_SYSTEM,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_TAPEDRIVE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_UNKNOWN,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_UCM,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_USB,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_VOLUME,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_VOLUMESNAPSHOT,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_WCEUSBS,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_WPD,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_TOP,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_ACTIVITYMONITOR,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_UNDELETE,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_ANTIVIRUS,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_REPLICATION,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_CONTINUOUSBACKUP,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_CONTENTSCREENER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_QUOTAMANAGEMENT,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_SYSTEMRECOVERY,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_CFSMETADATASERVER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_HSM,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_COMPRESSION,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_ENCRYPTION,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_VIRTUALIZATION,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_PHYSICALQUOTAMANAGEMENT,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_OPENFILEBACKUP,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_SECURITYENHANCER,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_COPYPROTECTION,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_BOTTOM,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_SYSTEM,\n    &PH_WELL_KNOWN_GUID_DEVCLASS_FSFILTER_INFRASTRUCTURE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_USB_HUB,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_USB_BILLBOARD,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_USB_DEVICE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_USB_HOST_CONTROLLER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_A2DP_SIDEBAND_AUDIO,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_BLUETOOTH_HFP_SCO_HCIBYPASS,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_CHARGING_ARBITRATION,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_CONFIGURABLE_USBFN_CHARGER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_CONFIGURABLE_WIRELESS_CHARGER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_I2C,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_OPM,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_OPM_2_JTP,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_OPM_2,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_OPM_3,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_BRIGHTNESS,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_BRIGHTNESS_2,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_MIRACAST_DISPLAY,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_BRIGHTNESS_3,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_HPMI,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_EMMC_PARTITION_ACCESS_RPMB,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_EMMC_PARTITION_ACCESS_GPP,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_USB_SIDEBAND_AUDIO_HS_HCIBYPASS,\n    &PH_WELL_KNOWN_GUID_BUS_VPCI,\n    &PH_WELL_KNOWN_GUID_VPCI_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_VPCI,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_WWAN_CONTROLLER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_WDDM3_ON_VB,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_GRAPHICSPOWER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_GNSS,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_HID,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_LAMP,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_NET,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_NETUIO,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_NFCDTA,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_NFCSE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_NFP,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_KEYBOARD,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_MODEM,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_MOUSE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_PARALLEL,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_PARCLASS,\n    &PH_WELL_KNOWN_GUID_PARALLEL_DEVICE,\n    &PH_WELL_KNOWN_GUID_PARCLASS_DEVICE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_DISPLAY_ADAPTER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_MONITOR,\n    &PH_WELL_KNOWN_GUID_DEVICE_BATTERY,\n    &PH_WELL_KNOWN_GUID_DEVICE_APPLICATIONLAUNCH_BUTTON,\n    &PH_WELL_KNOWN_GUID_DEVICE_SYS_BUTTON,\n    &PH_WELL_KNOWN_GUID_DEVICE_LID,\n    &PH_WELL_KNOWN_GUID_DEVICE_THERMAL_ZONE,\n    &PH_WELL_KNOWN_GUID_DEVICE_FAN,\n    &PH_WELL_KNOWN_GUID_DEVICE_PROCESSOR,\n    &PH_WELL_KNOWN_GUID_DEVICE_MEMORY,\n    &PH_WELL_KNOWN_GUID_DEVICE_ACPI_TIME,\n    &PH_WELL_KNOWN_GUID_DEVICE_MESSAGE_INDICATOR,\n    &PH_WELL_KNOWN_GUID_CLASS_INPUT,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_THERMAL_COOLING,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_THERMAL_MANAGER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_PWM_CONTROLLER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_USBPRINT,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_IPPUSB_PRINT,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_VM_GENCOUNTER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_BIOMETRIC_READER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_SMARTCARD_READER,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_DMR,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_DMP,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_DMS,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_ENHANCED_STORAGE_SILO,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_WPD,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_WPD_PRIVATE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_WPD_SERVICE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_SENSOR,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_IMAGE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_SIDESHOW,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_WIFIDIRECT_DEVICE,\n    &PH_WELL_KNOWN_GUID_AEPSERVICE_WIFIDIRECT_DEVICE,\n    &PH_WELL_KNOWN_GUID_DEVINTERFACE_ASP_INFRA_DEVICE,\n    &PH_WELL_KNOWN_GUID_DXGKDDI_MITIGABLE_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_DXGKDDI_FLEXIOV_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_SRIOV_DEVICE_INTERFACE_STANDARD,\n    &PH_WELL_KNOWN_GUID_MITIGABLE_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_IO_VOLUME_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_NDIS_LAN_CLASS,\n    &PH_WELL_KNOWN_GUID_NFC_RADIO_MEDIA_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_NFCSE_RADIO_MEDIA_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_BLUETOOTHLE_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_BLUETOOTH_GATT_SERVICE_DEVICE_INTERFACE,\n    &PH_WELL_KNOWN_GUID_BUS_TYPE_TREE,\n    &PH_WELL_KNOWN_GUID_TREE_TPM_SERVICE_FDTPM,\n    &PH_WELL_KNOWN_GUID_TREE_TPM_SERVICE_STPM,\n    &PH_WELL_KNOWN_GUID_DISPLAY_DEVICE_ARRIVAL,\n    &PH_WELL_KNOWN_GUID_COMPUTE_DEVICE_ARRIVAL,\n};\n\nstatic int __cdecl PhpWellKnownGuidSortFunction(\n    const void* Left,\n    const void* Right\n    )\n{\n    PPH_WELL_KNOWN_GUID lhsItem;\n    PPH_WELL_KNOWN_GUID rhsItem;\n\n    lhsItem = *(PPH_WELL_KNOWN_GUID*)Left;\n    rhsItem = *(PPH_WELL_KNOWN_GUID*)Right;\n\n    return memcmp(lhsItem->Guid, rhsItem->Guid, sizeof(GUID));\n}\n\nstatic int __cdecl PhpWellKnownGuidSearchFunction(\n    const GUID* Guid,\n    const void* Item\n    )\n{\n    PPH_WELL_KNOWN_GUID item;\n\n    item = *(PPH_WELL_KNOWN_GUID*)Item;\n\n    return memcmp(Guid, item->Guid, sizeof(GUID));\n}\n\nPPH_STRING PhpDevPropWellKnownGuidToString(\n    _In_ PGUID Guid\n    )\n{\n    const PH_WELL_KNOWN_GUID** entry;\n\n    if (PhBeginInitOnce(&PhpWellKnownGuidsInitOnce))\n    {\n        qsort(\n            (void*)PhpWellKnownGuids,\n            RTL_NUMBER_OF(PhpWellKnownGuids),\n            sizeof(PPH_WELL_KNOWN_GUID),\n            PhpWellKnownGuidSortFunction\n            );\n\n#ifdef DEBUG\n        // check for collisions\n        for (ULONG i = 0; i < RTL_NUMBER_OF(PhpWellKnownGuids) - 1; i++)\n        {\n            const PH_WELL_KNOWN_GUID* lhs = PhpWellKnownGuids[i];\n            const PH_WELL_KNOWN_GUID* rhs = PhpWellKnownGuids[i + 1];\n            assert(!IsEqualGUID(&lhs->Guid, &rhs->Guid));\n        }\n#endif\n\n        PhEndInitOnce(&PhpWellKnownGuidsInitOnce);\n    }\n\n    entry = bsearch(\n        Guid,\n        PhpWellKnownGuids,\n        RTL_NUMBER_OF(PhpWellKnownGuids),\n        sizeof(PPH_WELL_KNOWN_GUID),\n        PhpWellKnownGuidSearchFunction\n        );\n    if (!entry)\n        return NULL;\n\n    return PhCreateString2((PPH_STRINGREF)&(*entry)->Symbol);\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillGuid(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeGUID;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyGuid(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->Guid\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyGuid(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->Guid\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyGuid(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->Guid\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyGuid(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->Guid\n                );\n        }\n    }\n\n    if (Property->Valid)\n    {\n        Property->AsString = PhpDevPropWellKnownGuidToString(&Property->Guid);\n\n        if (!Property->AsString)\n            Property->AsString = PhFormatGuid(&Property->Guid);\n    }\n}\n\nPPH_STRING PhpDevPropPciDeviceTypeToString(\n    _In_ ULONG Flags\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    WCHAR pointer[PH_PTR_STR_LEN_1];\n\n    PhInitializeStringBuilder(&stringBuilder, 10);\n\n    if (BooleanFlagOn(Flags, DevProp_PciDevice_DeviceType_PciConventional))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciConventional, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_DeviceType_PciX))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciX, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_DeviceType_PciExpressEndpoint))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressEndpoint, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_DeviceType_PciExpressLegacyEndpoint))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressLegacyEndpoint, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_DeviceType_PciExpressRootComplexIntegratedEndpoint))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressRootComplexIntegratedEndpoint, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_DeviceType_PciExpressTreatedAsPci))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressTreatedAsPci, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_BridgeType_PciConventional))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciConventional, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_BridgeType_PciX))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciX, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_BridgeType_PciExpressRootPort))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressRootPort, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_BridgeType_PciExpressUpstreamSwitchPort))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressUpstreamSwitchPort, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_BridgeType_PciExpressDownstreamSwitchPort))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressDownstreamSwitchPort, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_BridgeType_PciExpressToPciXBridge))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressToPciXBridge, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_BridgeType_PciXToExpressBridge))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciXToExpressBridge, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_BridgeType_PciExpressTreatedAsPci))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressTreatedAsPci, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciDevice_BridgeType_PciExpressEventCollector))\n        PhAppendStringBuilder2(&stringBuilder, L\"PciExpressEventCollector, \");\n\n    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    if (Flags)\n    {\n        PhPrintPointer(pointer, UlongToPtr(Flags));\n        PhAppendFormatStringBuilder(&stringBuilder, L\" (%s)\", pointer);\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillPciDeviceType(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillUInt32Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        Property->AsString = PhpDevPropPciDeviceTypeToString(Property->UInt32);\n    }\n}\n\nPPH_STRING PhpDevPropPciDeviceInterruptSupportToString(\n    _In_ ULONG Flags\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    WCHAR pointer[PH_PTR_STR_LEN_1];\n\n    PhInitializeStringBuilder(&stringBuilder, 10);\n\n    if (BooleanFlagOn(Flags, DevProp_PciDevice_InterruptType_LineBased))\n        PhAppendStringBuilder2(&stringBuilder, L\"Line based, \");\n    if (BooleanFlagOn(Flags, DevProp_PciDevice_InterruptType_Msi))\n        PhAppendStringBuilder2(&stringBuilder, L\"Msi, \");\n    if (BooleanFlagOn(Flags, DevProp_PciDevice_InterruptType_MsiX))\n        PhAppendStringBuilder2(&stringBuilder, L\"MsiX, \");\n\n    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhPrintPointer(pointer, UlongToPtr(Flags));\n    PhAppendFormatStringBuilder(&stringBuilder, L\" (%s)\", pointer);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillPciDeviceInterruptSupport(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillUInt32Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        Property->AsString = PhpDevPropPciDeviceInterruptSupportToString(Property->UInt32);\n    }\n}\n\nPPH_STRING PhpDevPropPciDeviceRequestSizeToString(\n    _In_ ULONG Flags\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    WCHAR pointer[PH_PTR_STR_LEN_1];\n\n    PhInitializeStringBuilder(&stringBuilder, 10);\n\n    if (BooleanFlagOn(Flags, DevProp_PciExpressDevice_PayloadOrRequestSize_128Bytes))\n        PhAppendStringBuilder2(&stringBuilder, L\"128B, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciExpressDevice_PayloadOrRequestSize_256Bytes))\n        PhAppendStringBuilder2(&stringBuilder, L\"256B, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciExpressDevice_PayloadOrRequestSize_512Bytes))\n        PhAppendStringBuilder2(&stringBuilder, L\"512B, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciExpressDevice_PayloadOrRequestSize_1024Bytes))\n        PhAppendStringBuilder2(&stringBuilder, L\"1024B, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciExpressDevice_PayloadOrRequestSize_2048Bytes))\n        PhAppendStringBuilder2(&stringBuilder, L\"2048B, \");\n    else if (BooleanFlagOn(Flags, DevProp_PciExpressDevice_PayloadOrRequestSize_4096Bytes))\n        PhAppendStringBuilder2(&stringBuilder, L\"4096B, \");\n\n    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhPrintPointer(pointer, UlongToPtr(Flags));\n    PhAppendFormatStringBuilder(&stringBuilder, L\" (%s)\", pointer);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillPciDeviceRequestSize(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillUInt32Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        Property->AsString = PhpDevPropPciDeviceRequestSizeToString(Property->UInt32);\n    }\n}\n\nPPH_STRING PhpDevPropPciDeviceSriovSupportToString(\n    _In_ ULONG Flags\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    WCHAR pointer[PH_PTR_STR_LEN_1];\n\n    PhInitializeStringBuilder(&stringBuilder, 10);\n\n    if (BooleanFlagOn(Flags, DevProp_PciDevice_SriovSupport_Ok))\n        PhAppendStringBuilder2(&stringBuilder, L\"Ok, \");\n    if (BooleanFlagOn(Flags, DevProp_PciDevice_SriovSupport_MissingAcs))\n        PhAppendStringBuilder2(&stringBuilder, L\"MissingAcs, \");\n    if (BooleanFlagOn(Flags, DevProp_PciDevice_SriovSupport_MissingPfDriver))\n        PhAppendStringBuilder2(&stringBuilder, L\"MissingPfDriver, \");\n    if (BooleanFlagOn(Flags, DevProp_PciDevice_SriovSupport_NoBusResource))\n        PhAppendStringBuilder2(&stringBuilder, L\"NoBusResource, \");\n    if (BooleanFlagOn(Flags, DevProp_PciDevice_SriovSupport_DidntGetVfBarSpace))\n        PhAppendStringBuilder2(&stringBuilder, L\"DidntGetVfBarSpace, \");\n\n    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhPrintPointer(pointer, UlongToPtr(Flags));\n    PhAppendFormatStringBuilder(&stringBuilder, L\" (%s)\", pointer);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillPciDeviceSriovSupport(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillUInt32Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        Property->AsString = PhpDevPropPciDeviceSriovSupportToString(Property->UInt32);\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillBoolean(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeBoolean;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyBoolean(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->Boolean\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyBoolean(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->Boolean\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyBoolean(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->Boolean\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyBoolean(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->Boolean\n                );\n        }\n    }\n\n    if (Property->Valid)\n    {\n        if (Property->Boolean)\n        {\n            static CONST PH_STRINGREF string = PH_STRINGREF_INIT(L\"true\");\n            Property->AsString = PhCreateString2(&string);\n        }\n        else\n        {\n            static CONST PH_STRINGREF string = PH_STRINGREF_INIT(L\"false\");\n            Property->AsString = PhCreateString2(&string);\n        }\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillTimeStamp(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeTimeStamp;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyTimeStamp(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->TimeStamp\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyTimeStamp(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->TimeStamp\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyTimeStamp(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->TimeStamp\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyTimeStamp(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->TimeStamp\n                );\n        }\n    }\n\n    if (Property->Valid)\n    {\n        SYSTEMTIME systemTime;\n\n        PhLargeIntegerToLocalSystemTime(&systemTime, &Property->TimeStamp);\n\n        Property->AsString = PhFormatDateTime(&systemTime);\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillStringList(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeStringList;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyStringList(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->StringList\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyStringList(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->StringList\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyStringList(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->StringList\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyStringList(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->StringList\n                );\n        }\n    }\n\n    if (Property->Valid && Property->StringList->Count > 0)\n    {\n        PH_STRING_BUILDER stringBuilder;\n        PPH_STRING string;\n\n        PhInitializeStringBuilder(&stringBuilder, Property->StringList->Count);\n\n        for (ULONG i = 0; i < Property->StringList->Count - 1; i++)\n        {\n            string = Property->StringList->Items[i];\n\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\", \");\n        }\n\n        string = Property->StringList->Items[Property->StringList->Count - 1];\n\n        PhAppendStringBuilder(&stringBuilder, &string->sr);\n\n        Property->AsString = PhFinalStringBuilderString(&stringBuilder);\n        PhReferenceObject(Property->AsString);\n\n        PhDeleteStringBuilder(&stringBuilder);\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillStringOrStringList(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillString(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n    if (!Property->Valid)\n    {\n        PhpDevPropFillStringList(\n            DeviceInfoSet,\n            DeviceInfoData,\n            PropertyKey,\n            Property,\n            Flags\n            );\n    }\n}\n\nVOID PhpDevPropFillBinaryCommon(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    Property->Type = PhDevicePropertyTypeBinary;\n\n    if (DeviceInfoData->Interface)\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyBinary(\n                &DeviceInfoData->InterfaceData.InterfaceClassGuid,\n                PropertyKey,\n                DICLASSPROP_INTERFACE,\n                &Property->Binary.Buffer,\n                &Property->Binary.Size\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDeviceInterfacePropertyBinary(\n                DeviceInfoSet,\n                &DeviceInfoData->InterfaceData,\n                PropertyKey,\n                &Property->Binary.Buffer,\n                &Property->Binary.Size\n                );\n        }\n    }\n    else\n    {\n        if (Flags & DEVPROP_FILL_FLAG_CLASS)\n        {\n            Property->Valid = PhpGetClassPropertyBinary(\n                &DeviceInfoData->DeviceData.ClassGuid,\n                PropertyKey,\n                DICLASSPROP_INSTALLER,\n                &Property->Binary.Buffer,\n                &Property->Binary.Size\n                );\n        }\n        else\n        {\n            Property->Valid = PhpGetDevicePropertyBinary(\n                DeviceInfoSet,\n                &DeviceInfoData->DeviceData,\n                PropertyKey,\n                &Property->Binary.Buffer,\n                &Property->Binary.Size\n                );\n        }\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillBinary(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillBinaryCommon(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        Property->AsString = PhBufferToHexString(Property->Binary.Buffer, Property->Binary.Size);\n    }\n}\n\nstatic const PH_STRINGREF UnknownString = PH_STRINGREF_INIT(L\"Unk\");\n\nPCPH_STRINGREF PhpDevPowerStateString(\n    _In_ DEVICE_POWER_STATE PowerState\n    )\n{\n    static const PH_STRINGREF states[] =\n    {\n        PH_STRINGREF_INIT(L\"Uns\"), // PowerDeviceUnspecified\n        PH_STRINGREF_INIT(L\"D0\"),  // PowerDeviceD0\n        PH_STRINGREF_INIT(L\"D1\"),  // PowerDeviceD1\n        PH_STRINGREF_INIT(L\"D2\"),  // PowerDeviceD2\n        PH_STRINGREF_INIT(L\"D3\"),  // PowerDeviceD3\n        PH_STRINGREF_INIT(L\"D4\"),  // PowerDeviceD4\n        PH_STRINGREF_INIT(L\"Max\"), // PowerDeviceMaximum\n    };\n\n    if (PowerState >= 0 && PowerState < RTL_NUMBER_OF(states))\n        return &states[PowerState];\n\n    return &UnknownString;\n}\n\nPCPH_STRINGREF PhpDevSysPowerStateString(\n    _In_ SYSTEM_POWER_STATE PowerState\n    )\n{\n    static const PH_STRINGREF states[] =\n    {\n        PH_STRINGREF_INIT(L\"Uns\"), // PowerSystemUnspecified\n        PH_STRINGREF_INIT(L\"S0\"),  // PowerSystemWorking\n        PH_STRINGREF_INIT(L\"S1\"),  // PowerSystemSleep1\n        PH_STRINGREF_INIT(L\"S2\"),  // PowerSystemSleep2\n        PH_STRINGREF_INIT(L\"S3\"),  // PowerSystemSleep3\n        PH_STRINGREF_INIT(L\"S4\"),  // PowerSystemHybernate\n        PH_STRINGREF_INIT(L\"S5\"),  // PowerSystemShutdown\n        PH_STRINGREF_INIT(L\"Max\"), // PowerSystemMaximum\n    };\n\n    if (PowerState >= 0 && PowerState < RTL_NUMBER_OF(states))\n        return &states[PowerState];\n\n    return &UnknownString;\n}\n\nPPH_STRING PhpDevSysPowerPowerDataString(\n    _In_ PCM_POWER_DATA PowerData\n    )\n{\n    static const PH_ACCESS_ENTRY pdCap[] =\n    {\n        { L\"PDCAP_D0_SUPPORTED\", PDCAP_D0_SUPPORTED, FALSE, FALSE, L\"D0\" },\n        { L\"PDCAP_D1_SUPPORTED\", PDCAP_D1_SUPPORTED, FALSE, FALSE, L\"D1\" },\n        { L\"PDCAP_D2_SUPPORTED\", PDCAP_D2_SUPPORTED, FALSE, FALSE, L\"D2\" },\n        { L\"PDCAP_D3_SUPPORTED\", PDCAP_D3_SUPPORTED, FALSE, FALSE, L\"D3\" },\n        { L\"PDCAP_WAKE_FROM_D0_SUPPORTED\", PDCAP_WAKE_FROM_D0_SUPPORTED, FALSE, FALSE, L\"Wake from D0\" },\n        { L\"PDCAP_WAKE_FROM_D1_SUPPORTED\", PDCAP_WAKE_FROM_D1_SUPPORTED, FALSE, FALSE, L\"Wake from D1\" },\n        { L\"PDCAP_WAKE_FROM_D2_SUPPORTED\", PDCAP_WAKE_FROM_D2_SUPPORTED, FALSE, FALSE, L\"Wake from D2\" },\n        { L\"PDCAP_WAKE_FROM_D3_SUPPORTED\", PDCAP_WAKE_FROM_D3_SUPPORTED, FALSE, FALSE, L\"Wake from D3\" },\n        { L\"PDCAP_WARM_EJECT_SUPPORTED\", PDCAP_WARM_EJECT_SUPPORTED, FALSE, FALSE, L\"Warm eject\" },\n    };\n\n    PH_FORMAT format[29];\n    ULONG count = 0;\n    PPH_STRING capabilities;\n    PPH_STRING string;\n\n    PhInitFormatSR(&format[count++], *PhpDevPowerStateString(PowerData->PD_MostRecentPowerState));\n    if (PowerData->PD_D1Latency)\n    {\n        PhInitFormatS(&format[count++], L\", \");\n        PhInitFormatU(&format[count++], PowerData->PD_D1Latency);\n        PhInitFormatS(&format[count++], L\" D1 latency\");\n    }\n    if (PowerData->PD_D2Latency)\n    {\n        PhInitFormatS(&format[count++], L\", \");\n        PhInitFormatU(&format[count++], PowerData->PD_D2Latency);\n        PhInitFormatS(&format[count++], L\" D2 latency\");\n    }\n    if (PowerData->PD_D2Latency)\n    {\n        PhInitFormatS(&format[count++], L\", \");\n        PhInitFormatU(&format[count++], PowerData->PD_D3Latency);\n        PhInitFormatS(&format[count++], L\" D3 latency\");\n    }\n    PhInitFormatS(&format[count++], L\", S0->\");\n    PhInitFormatSR(&format[count++], *PhpDevPowerStateString(PowerData->PD_PowerStateMapping[PowerSystemWorking]));\n    PhInitFormatS(&format[count++], L\", S1->\");\n    PhInitFormatSR(&format[count++], *PhpDevPowerStateString(PowerData->PD_PowerStateMapping[PowerSystemSleeping1]));\n    PhInitFormatS(&format[count++], L\", S2->\");\n    PhInitFormatSR(&format[count++], *PhpDevPowerStateString(PowerData->PD_PowerStateMapping[PowerSystemSleeping2]));\n    PhInitFormatS(&format[count++], L\", S3->\");\n    PhInitFormatSR(&format[count++], *PhpDevPowerStateString(PowerData->PD_PowerStateMapping[PowerSystemSleeping3]));\n    PhInitFormatS(&format[count++], L\", S4->\");\n    PhInitFormatSR(&format[count++], *PhpDevPowerStateString(PowerData->PD_PowerStateMapping[PowerSystemHibernate]));\n    PhInitFormatS(&format[count++], L\", S5->\");\n    PhInitFormatSR(&format[count++], *PhpDevPowerStateString(PowerData->PD_PowerStateMapping[PowerSystemShutdown]));\n    capabilities = PhGetAccessString(PowerData->PD_Capabilities, (PVOID)pdCap, RTL_NUMBER_OF(pdCap));\n    PhInitFormatS(&format[count++], L\", (\");\n    PhInitFormatSR(&format[count++], capabilities->sr);\n    PhInitFormatS(&format[count++], L\" (0x\");\n    PhInitFormatX(&format[count++], PowerData->PD_Capabilities);\n    PhInitFormatS(&format[count++], L\"))\");\n    if (PowerData->PD_DeepestSystemWake != PowerSystemUnspecified)\n    {\n        PhInitFormatS(&format[count++], L\", Deepest wake \");\n        PhInitFormatSR(&format[count++], *PhpDevSysPowerStateString(PowerData->PD_DeepestSystemWake));\n    }\n\n    string = PhFormat(format, count, 20);\n\n    PhClearReference(&capabilities);\n\n    return string;\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillPowerData(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n    PhpDevPropFillBinaryCommon(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (Property->Valid)\n    {\n        if (Property->Binary.Size >= sizeof(CM_POWER_DATA))\n            Property->AsString = PhpDevSysPowerPowerDataString((PCM_POWER_DATA)Property->Binary.Buffer);\n        else\n            Property->AsString = PhBufferToHexString(Property->Binary.Buffer, Property->Binary.Size);\n    }\n}\n\n_Function_class_(PH_DEVICE_PROPERTY_FILL_CALLBACK)\nVOID NTAPI PhpDevPropFillUInt32Flags(\n    _In_ HDEVINFO DeviceInfoSet,\n    _In_ PPH_DEVINFO_DATA DeviceInfoData,\n    _In_ const DEVPROPKEY* PropertyKey,\n    _Out_ PPH_DEVICE_PROPERTY Property,\n    _In_ ULONG Flags\n    )\n{\n#define PH_DEVICE_FLAG(x, n) { TEXT(#x), x, FALSE, FALSE, n }\n\n    static const PH_ACCESS_ENTRY deviceCapabilities[] =\n    {\n        PH_DEVICE_FLAG(CM_DEVCAP_LOCKSUPPORTED, L\"Lock supported\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_EJECTSUPPORTED, L\"Eject supported\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_REMOVABLE, L\"Removable\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_DOCKDEVICE, L\"Dock device\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_UNIQUEID, L\"Unique ID\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_SILENTINSTALL, L\"Silent install\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_RAWDEVICEOK, L\"Raw device ok\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_SURPRISEREMOVALOK, L\"Surprise removal ok\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_HARDWAREDISABLED, L\"Hardware disabled\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_NONDYNAMIC, L\"No dynamic\"),\n        PH_DEVICE_FLAG(CM_DEVCAP_SECUREDEVICE, L\"Secure device\"),\n    };\n\n    static const PH_ACCESS_ENTRY devNodeStatus[] =\n    {\n        PH_DEVICE_FLAG(DN_ROOT_ENUMERATED, L\"Enumerated\"),\n        PH_DEVICE_FLAG(DN_DRIVER_LOADED, L\"Driver loaded\"),\n        PH_DEVICE_FLAG(DN_ENUM_LOADED, L\"Enumerator loaded\"),\n        PH_DEVICE_FLAG(DN_STARTED, L\"Started\"),\n        PH_DEVICE_FLAG(DN_MANUAL, L\"Manually installed\"),\n        PH_DEVICE_FLAG(DN_NEED_TO_ENUM, L\"Needs enumerated\"),\n        PH_DEVICE_FLAG(DN_DRIVER_BLOCKED, L\"Driver blocked\"),\n        PH_DEVICE_FLAG(DN_HARDWARE_ENUM, L\"Hardware enum\"),\n        PH_DEVICE_FLAG(DN_NEED_RESTART, L\"Needs reboot\"),\n        PH_DEVICE_FLAG(DN_CHILD_WITH_INVALID_ID, L\"Child with invalid ID\"),\n        PH_DEVICE_FLAG(DN_HAS_PROBLEM, L\"Has problem\"),\n        PH_DEVICE_FLAG(DN_FILTERED, L\"Filtered\"),\n        PH_DEVICE_FLAG(DN_LEGACY_DRIVER, L\"Legacy driver\"),\n        PH_DEVICE_FLAG(DN_DISABLEABLE, L\"Disabled\"),\n        PH_DEVICE_FLAG(DN_REMOVABLE, L\"Removable\"),\n        PH_DEVICE_FLAG(DN_PRIVATE_PROBLEM, L\"Has problem\"),\n        PH_DEVICE_FLAG(DN_QUERY_REMOVE_PENDING, L\"Query remove pending\"),\n        PH_DEVICE_FLAG(DN_QUERY_REMOVE_ACTIVE, L\"Query remove active\"),\n        PH_DEVICE_FLAG(DN_WILL_BE_REMOVED, L\"Being removed\"),\n        PH_DEVICE_FLAG(DN_NOT_FIRST_TIMEE, L\"Received config\"),\n        PH_DEVICE_FLAG(DN_STOP_FREE_RES, L\"To be freed\"),\n        PH_DEVICE_FLAG(DN_REBAL_CANDIDATE, L\"Rebalance candidate\"),\n        PH_DEVICE_FLAG(DN_BAD_PARTIAL, L\"Bad partial\"),\n        PH_DEVICE_FLAG(DN_NT_ENUMERATOR, L\"NT enumerator\"),\n        PH_DEVICE_FLAG(DN_NT_DRIVER, L\"NT driver\"),\n        PH_DEVICE_FLAG(DN_DEVICE_DISCONNECTED, L\"Disconnected\"),\n        PH_DEVICE_FLAG(DN_ARM_WAKEUP, L\"Wakeup device\"),\n        PH_DEVICE_FLAG(DN_APM_ENUMERATOR, L\"Advanced power enumerator\"),\n        PH_DEVICE_FLAG(DN_APM_DRIVER, L\"Advanced power aware\"),\n        PH_DEVICE_FLAG(DN_SILENT_INSTALL, L\"Silent install\"),\n        PH_DEVICE_FLAG(DN_NO_SHOW_IN_DM, L\"Hidden from device manager\"),\n        PH_DEVICE_FLAG(DN_BOOT_LOG_PROB, L\"Boot log problem\"),\n    };\n\n    static const PH_ACCESS_ENTRY characteristics[] =\n    {\n        PH_DEVICE_FLAG(FILE_REMOVABLE_MEDIA, L\"Removable media\"),\n        PH_DEVICE_FLAG(FILE_READ_ONLY_DEVICE, L\"Read only device\"),\n        PH_DEVICE_FLAG(FILE_FLOPPY_DISKETTE, L\"Floppy disk\"),\n        PH_DEVICE_FLAG(FILE_WRITE_ONCE_MEDIA, L\"Write once media\"),\n        PH_DEVICE_FLAG(FILE_REMOTE_DEVICE, L\"Remote device\"),\n        PH_DEVICE_FLAG(FILE_DEVICE_IS_MOUNTED, L\"Mounted\"),\n        PH_DEVICE_FLAG(FILE_VIRTUAL_VOLUME, L\"Virtual volume\"),\n        PH_DEVICE_FLAG(FILE_AUTOGENERATED_DEVICE_NAME, L\"Autogenerated device name\"),\n        PH_DEVICE_FLAG(FILE_DEVICE_SECURE_OPEN, L\"Secure open\"),\n        PH_DEVICE_FLAG(FILE_CHARACTERISTIC_PNP_DEVICE, L\"PnP device\"),\n        PH_DEVICE_FLAG(FILE_CHARACTERISTIC_TS_DEVICE, L\"Terminal services device\"),\n        PH_DEVICE_FLAG(FILE_CHARACTERISTIC_WEBDAV_DEVICE, L\"WebDAV device\"),\n        PH_DEVICE_FLAG(FILE_CHARACTERISTIC_CSV, L\"Cluster shared volume\"),\n        PH_DEVICE_FLAG(FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL, L\"Allow app container traversal\"),\n        PH_DEVICE_FLAG(FILE_PORTABLE_DEVICE, L\"Portable device\"),\n        PH_DEVICE_FLAG(FILE_REMOTE_DEVICE_VSMB, L\"Virtual SCSI device\"),\n        PH_DEVICE_FLAG(FILE_DEVICE_REQUIRE_SECURITY_CHECK, L\"Require security check\"),\n    };\n\n    static const PH_ACCESS_ENTRY nameAttributes[] =\n    {\n        PH_DEVICE_FLAG(CM_NAME_ATTRIBUTE_NAME_RETRIEVED_FROM_DEVICE, L\"Retrieved from device\"),\n        PH_DEVICE_FLAG(CM_NAME_ATTRIBUTE_USER_ASSIGNED_NAME, L\"User assigned name\"),\n    };\n\n    PPH_ACCESS_ENTRY entries = NULL;\n    ULONG count = 0;\n\n    PhpDevPropFillUInt32Common(\n        DeviceInfoSet,\n        DeviceInfoData,\n        PropertyKey,\n        Property,\n        Flags\n        );\n\n    if (PropertyKey == &DEVPKEY_Device_DevNodeStatus)\n    {\n        entries = (PPH_ACCESS_ENTRY)devNodeStatus;\n        count = RTL_NUMBER_OF(devNodeStatus);\n    }\n    else if (PropertyKey == &DEVPKEY_Device_Capabilities)\n    {\n        entries = (PPH_ACCESS_ENTRY)deviceCapabilities;\n        count = RTL_NUMBER_OF(deviceCapabilities);\n    }\n    else if (PropertyKey == &DEVPKEY_Device_Characteristics ||\n             PropertyKey == &DEVPKEY_DeviceClass_Characteristics)\n    {\n        entries = (PPH_ACCESS_ENTRY)characteristics;\n        count = RTL_NUMBER_OF(characteristics);\n    }\n    else if (PropertyKey == &DEVPKEY_Device_FriendlyNameAttributes)\n    {\n        entries = (PPH_ACCESS_ENTRY)nameAttributes;\n        count = RTL_NUMBER_OF(nameAttributes);\n    }\n\n    if (entries)\n    {\n        if (Property->UInt32)\n        {\n            PH_FORMAT format[4];\n            PPH_STRING string;\n\n            string = PhGetAccessString(Property->UInt32, entries, count);\n            PhInitFormatSR(&format[0], string->sr);\n            PhInitFormatS(&format[1], L\" (0x\");\n            PhInitFormatX(&format[2], Property->UInt32);\n            PhInitFormatS(&format[3], L\")\");\n\n            Property->AsString = PhFormat(format, ARRAYSIZE(format), 10);\n\n            PhDereferenceObject(string);\n        }\n        else\n        {\n            Property->AsString = PhReferenceEmptyString();\n        }\n    }\n    else\n    {\n        PH_FORMAT format[2];\n\n        PhInitFormatS(&format[0], L\"0x\");\n        PhInitFormatIX(&format[1], Property->UInt32);\n\n        Property->AsString = PhFormat(format, ARRAYSIZE(format), 10);\n    }\n}\n\nstatic const PH_DEVICE_PROPERTY_TABLE_ENTRY PhpDeviceItemPropertyTable[] =\n{\n    { PhDevicePropertyName, &DEVPKEY_NAME, PhpDevPropFillString, 0 },\n    { PhDevicePropertyManufacturer, &DEVPKEY_Device_Manufacturer, PhpDevPropFillString, 0 },\n    { PhDevicePropertyService, &DEVPKEY_Device_Service, PhpDevPropFillString, 0 },\n    { PhDevicePropertyClass, &DEVPKEY_Device_Class, PhpDevPropFillString, 0 },\n    { PhDevicePropertyEnumeratorName, &DEVPKEY_Device_EnumeratorName, PhpDevPropFillString, 0 },\n    { PhDevicePropertyInstallDate, &DEVPKEY_Device_InstallDate, PhpDevPropFillTimeStamp, 0 },\n\n    { PhDevicePropertyFirstInstallDate, &DEVPKEY_Device_FirstInstallDate, PhpDevPropFillTimeStamp, 0 },\n    { PhDevicePropertyLastArrivalDate, &DEVPKEY_Device_LastArrivalDate, PhpDevPropFillTimeStamp, 0 },\n    { PhDevicePropertyLastRemovalDate, &DEVPKEY_Device_LastRemovalDate, PhpDevPropFillTimeStamp, 0 },\n    { PhDevicePropertyDeviceDesc, &DEVPKEY_Device_DeviceDesc, PhpDevPropFillString, 0 },\n    { PhDevicePropertyFriendlyName, &DEVPKEY_Device_FriendlyName, PhpDevPropFillString, 0 },\n    { PhDevicePropertyInstanceId, &DEVPKEY_Device_InstanceId, PhpDevPropFillString, 0 },\n    { PhDevicePropertyParentInstanceId, &DEVPKEY_Device_Parent, PhpDevPropFillString, 0 },\n    { PhDevicePropertyPDOName, &DEVPKEY_Device_PDOName, PhpDevPropFillString, 0 },\n    { PhDevicePropertyLocationInfo, &DEVPKEY_Device_LocationInfo, PhpDevPropFillString, 0 },\n    { PhDevicePropertyClassGuid, &DEVPKEY_Device_ClassGuid, PhpDevPropFillGuid, 0 },\n    { PhDevicePropertyDriver, &DEVPKEY_Device_Driver, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverVersion, &DEVPKEY_Device_DriverVersion, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverDate, &DEVPKEY_Device_DriverDate, PhpDevPropFillTimeStamp, 0 },\n    { PhDevicePropertyFirmwareDate, &DEVPKEY_Device_FirmwareDate, PhpDevPropFillTimeStamp, 0 },\n    { PhDevicePropertyFirmwareVersion, &DEVPKEY_Device_FirmwareVersion, PhpDevPropFillString, 0 },\n    { PhDevicePropertyFirmwareRevision, &DEVPKEY_Device_FirmwareRevision, PhpDevPropFillString, 0 },\n    { PhDevicePropertyHasProblem, &DEVPKEY_Device_HasProblem, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyProblemCode, &DEVPKEY_Device_ProblemCode, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyProblemStatus, &DEVPKEY_Device_ProblemStatus, PhpDevPropFillNTSTATUS, 0 },\n    { PhDevicePropertyDevNodeStatus, &DEVPKEY_Device_DevNodeStatus, PhpDevPropFillUInt32Flags, 0 },\n    { PhDevicePropertyDevCapabilities, &DEVPKEY_Device_Capabilities, PhpDevPropFillUInt32Flags, 0 },\n    { PhDevicePropertyUpperFilters, &DEVPKEY_Device_UpperFilters, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyLowerFilters, &DEVPKEY_Device_LowerFilters, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyHardwareIds, &DEVPKEY_Device_HardwareIds, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyCompatibleIds, &DEVPKEY_Device_CompatibleIds, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyConfigFlags, &DEVPKEY_Device_ConfigFlags, PhpDevPropFillUInt32Hex, 0 },\n    { PhDevicePropertyUINumber, &DEVPKEY_Device_UINumber, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyBusTypeGuid, &DEVPKEY_Device_BusTypeGuid, PhpDevPropFillGuid, 0 },\n    { PhDevicePropertyLegacyBusType, &DEVPKEY_Device_LegacyBusType, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyBusNumber, &DEVPKEY_Device_BusNumber, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertySecurity, &DEVPKEY_Device_Security, PhpDevPropFillBinary, 0 }, // DEVPROP_TYPE_SECURITY_DESCRIPTOR as binary, PhDevicePropertySecuritySDS for string\n    { PhDevicePropertySecuritySDS, &DEVPKEY_Device_SecuritySDS, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDevType, &DEVPKEY_Device_DevType, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyExclusive, &DEVPKEY_Device_Exclusive, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyCharacteristics, &DEVPKEY_Device_Characteristics, PhpDevPropFillUInt32Flags, 0 },\n    { PhDevicePropertyAddress, &DEVPKEY_Device_Address, PhpDevPropFillUInt32Hex, 0 },\n    { PhDevicePropertyPowerData, &DEVPKEY_Device_PowerData, PhpDevPropFillPowerData, 0 },\n    { PhDevicePropertyRemovalPolicy, &DEVPKEY_Device_RemovalPolicy, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyRemovalPolicyDefault, &DEVPKEY_Device_RemovalPolicyDefault, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyRemovalPolicyOverride, &DEVPKEY_Device_RemovalPolicyOverride, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyInstallState, &DEVPKEY_Device_InstallState, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyLocationPaths, &DEVPKEY_Device_LocationPaths, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyBaseContainerId, &DEVPKEY_Device_BaseContainerId, PhpDevPropFillGuid, 0 },\n    { PhDevicePropertyEjectionRelations, &DEVPKEY_Device_EjectionRelations, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyRemovalRelations, &DEVPKEY_Device_RemovalRelations, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyPowerRelations, &DEVPKEY_Device_PowerRelations, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyBusRelations, &DEVPKEY_Device_BusRelations, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyChildren, &DEVPKEY_Device_Children, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertySiblings, &DEVPKEY_Device_Siblings, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyTransportRelations, &DEVPKEY_Device_TransportRelations, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyReported, &DEVPKEY_Device_Reported, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyLegacy, &DEVPKEY_Device_Legacy, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerId, &DEVPKEY_Device_ContainerId, PhpDevPropFillGuid, 0 },\n    { PhDevicePropertyInLocalMachineContainer, &DEVPKEY_Device_InLocalMachineContainer, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyModel, &DEVPKEY_Device_Model, PhpDevPropFillString, 0 },\n    { PhDevicePropertyModelId, &DEVPKEY_Device_ModelId, PhpDevPropFillGuid, 0 },\n    { PhDevicePropertyFriendlyNameAttributes, &DEVPKEY_Device_FriendlyNameAttributes, PhpDevPropFillUInt32Flags, 0 },\n    { PhDevicePropertyManufacturerAttributes, &DEVPKEY_Device_ManufacturerAttributes, PhpDevPropFillUInt32Hex, 0 },\n    { PhDevicePropertyPresenceNotForDevice, &DEVPKEY_Device_PresenceNotForDevice, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertySignalStrength, &DEVPKEY_Device_SignalStrength, PhpDevPropFillInt32, 0 },\n    { PhDevicePropertyIsAssociateableByUserAction, &DEVPKEY_Device_IsAssociateableByUserAction, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyShowInUninstallUI, &DEVPKEY_Device_ShowInUninstallUI, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyNumaProximityDomain, &DEVPKEY_Device_Numa_Proximity_Domain, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyDHPRebalancePolicy, &DEVPKEY_Device_DHP_Rebalance_Policy, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyNumaNode, &DEVPKEY_Device_Numa_Node, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyBusReportedDeviceDesc, &DEVPKEY_Device_BusReportedDeviceDesc, PhpDevPropFillString, 0 },\n    { PhDevicePropertyIsPresent, &DEVPKEY_Device_IsPresent, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyConfigurationId, &DEVPKEY_Device_ConfigurationId, PhpDevPropFillString, 0 },\n    { PhDevicePropertyReportedDeviceIdsHash, &DEVPKEY_Device_ReportedDeviceIdsHash, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPhysicalDeviceLocation, &DEVPKEY_Device_PhysicalDeviceLocation, PhpDevPropFillBinary, 0 }, // TODO(jxy-s) look into ACPI 4.0a Specification, section 6.1.6 for AsString formatting\n    { PhDevicePropertyBiosDeviceName, &DEVPKEY_Device_BiosDeviceName, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverProblemDesc, &DEVPKEY_Device_DriverProblemDesc, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDebuggerSafe, &DEVPKEY_Device_DebuggerSafe, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPostInstallInProgress, &DEVPKEY_Device_PostInstallInProgress, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyStack, &DEVPKEY_Device_Stack, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyExtendedConfigurationIds, &DEVPKEY_Device_ExtendedConfigurationIds, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyIsRebootRequired, &DEVPKEY_Device_IsRebootRequired, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyDependencyProviders, &DEVPKEY_Device_DependencyProviders, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyDependencyDependents, &DEVPKEY_Device_DependencyDependents, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertySoftRestartSupported, &DEVPKEY_Device_SoftRestartSupported, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyExtendedAddress, &DEVPKEY_Device_ExtendedAddress, PhpDevPropFillUInt64Hex, 0 },\n    { PhDevicePropertyAssignedToGuest, &DEVPKEY_Device_AssignedToGuest, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyCreatorProcessId, &DEVPKEY_Device_CreatorProcessId, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyFirmwareVendor, &DEVPKEY_Device_FirmwareVendor, PhpDevPropFillString, 0 },\n    { PhDevicePropertySessionId, &DEVPKEY_Device_SessionId, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyDriverDesc, &DEVPKEY_Device_DriverDesc, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverInfPath, &DEVPKEY_Device_DriverInfPath, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverInfSection, &DEVPKEY_Device_DriverInfSection, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverInfSectionExt, &DEVPKEY_Device_DriverInfSectionExt, PhpDevPropFillString, 0 },\n    { PhDevicePropertyMatchingDeviceId, &DEVPKEY_Device_MatchingDeviceId, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverProvider, &DEVPKEY_Device_DriverProvider, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverPropPageProvider, &DEVPKEY_Device_DriverPropPageProvider, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverCoInstallers, &DEVPKEY_Device_DriverCoInstallers, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyResourcePickerTags, &DEVPKEY_Device_ResourcePickerTags, PhpDevPropFillString, 0 },\n    { PhDevicePropertyResourcePickerExceptions, &DEVPKEY_Device_ResourcePickerExceptions, PhpDevPropFillString, 0 },\n    { PhDevicePropertyDriverRank, &DEVPKEY_Device_DriverRank, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyDriverLogoLevel, &DEVPKEY_Device_DriverLogoLevel, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyNoConnectSound, &DEVPKEY_Device_NoConnectSound, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyGenericDriverInstalled, &DEVPKEY_Device_GenericDriverInstalled, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyAdditionalSoftwareRequested, &DEVPKEY_Device_AdditionalSoftwareRequested, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertySafeRemovalRequired, &DEVPKEY_Device_SafeRemovalRequired, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertySafeRemovalRequiredOverride, &DEVPKEY_Device_SafeRemovalRequiredOverride, PhpDevPropFillBoolean, 0 },\n\n    { PhDevicePropertyPkgModel, &DEVPKEY_DrvPkg_Model, PhpDevPropFillString, 0 },\n    { PhDevicePropertyPkgVendorWebSite, &DEVPKEY_DrvPkg_VendorWebSite, PhpDevPropFillString, 0 },\n    { PhDevicePropertyPkgDetailedDescription, &DEVPKEY_DrvPkg_DetailedDescription, PhpDevPropFillString, 0 },\n    { PhDevicePropertyPkgDocumentationLink, &DEVPKEY_DrvPkg_DocumentationLink, PhpDevPropFillString, 0 },\n    { PhDevicePropertyPkgIcon, &DEVPKEY_DrvPkg_Icon, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyPkgBrandingIcon, &DEVPKEY_DrvPkg_BrandingIcon, PhpDevPropFillStringList, 0 },\n\n    { PhDevicePropertyClassUpperFilters, &DEVPKEY_DeviceClass_UpperFilters, PhpDevPropFillStringList, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassLowerFilters, &DEVPKEY_DeviceClass_LowerFilters, PhpDevPropFillStringList, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassSecurity, &DEVPKEY_DeviceClass_Security, PhpDevPropFillBinary, DEVPROP_FILL_FLAG_CLASS }, // DEVPROP_TYPE_SECURITY_DESCRIPTOR as binary, PhDevicePropertyClassSecuritySDS for string\n    { PhDevicePropertyClassSecuritySDS, &DEVPKEY_DeviceClass_SecuritySDS, PhpDevPropFillString, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassDevType, &DEVPKEY_DeviceClass_DevType, PhpDevPropFillUInt32, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassExclusive, &DEVPKEY_DeviceClass_Exclusive, PhpDevPropFillBoolean, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassCharacteristics, &DEVPKEY_DeviceClass_Characteristics, PhpDevPropFillUInt32Flags, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassName, &DEVPKEY_DeviceClass_Name, PhpDevPropFillString, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassClassName, &DEVPKEY_DeviceClass_ClassName, PhpDevPropFillString, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassIcon, &DEVPKEY_DeviceClass_Icon, PhpDevPropFillString, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassClassInstaller, &DEVPKEY_DeviceClass_ClassInstaller, PhpDevPropFillString, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassPropPageProvider, &DEVPKEY_DeviceClass_PropPageProvider, PhpDevPropFillString, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassNoInstallClass, &DEVPKEY_DeviceClass_NoInstallClass, PhpDevPropFillBoolean, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassNoDisplayClass, &DEVPKEY_DeviceClass_NoDisplayClass, PhpDevPropFillBoolean, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassSilentInstall, &DEVPKEY_DeviceClass_SilentInstall, PhpDevPropFillBoolean, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassNoUseClass, &DEVPKEY_DeviceClass_NoUseClass, PhpDevPropFillBoolean, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassDefaultService, &DEVPKEY_DeviceClass_DefaultService, PhpDevPropFillString, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassIconPath, &DEVPKEY_DeviceClass_IconPath, PhpDevPropFillStringList, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassDHPRebalanceOptOut, &DEVPKEY_DeviceClass_DHPRebalanceOptOut, PhpDevPropFillBoolean, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyClassClassCoInstallers, &DEVPKEY_DeviceClass_ClassCoInstallers, PhpDevPropFillStringList, DEVPROP_FILL_FLAG_CLASS },\n\n    { PhDevicePropertyInterfaceFriendlyName, &DEVPKEY_DeviceInterface_FriendlyName, PhpDevPropFillString, 0 },\n    { PhDevicePropertyInterfaceEnabled, &DEVPKEY_DeviceInterface_Enabled, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyInterfaceClassGuid, &DEVPKEY_DeviceInterface_ClassGuid, PhpDevPropFillGuid, 0 },\n    { PhDevicePropertyInterfaceReferenceString, &DEVPKEY_DeviceInterface_ReferenceString, PhpDevPropFillString, 0 },\n    { PhDevicePropertyInterfaceRestricted, &DEVPKEY_DeviceInterface_Restricted, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyInterfaceUnrestrictedAppCapabilities, &DEVPKEY_DeviceInterface_UnrestrictedAppCapabilities, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyInterfaceSchematicName, &DEVPKEY_DeviceInterface_SchematicName, PhpDevPropFillString, 0 },\n\n    { PhDevicePropertyInterfaceClassDefaultInterface, &DEVPKEY_DeviceInterfaceClass_DefaultInterface, PhpDevPropFillString, DEVPROP_FILL_FLAG_CLASS },\n    { PhDevicePropertyInterfaceClassName, &DEVPKEY_DeviceInterfaceClass_Name, PhpDevPropFillString, DEVPROP_FILL_FLAG_CLASS },\n\n    { PhDevicePropertyContainerAddress, &DEVPKEY_DeviceContainer_Address, PhpDevPropFillStringOrStringList, 0 },\n    { PhDevicePropertyContainerDiscoveryMethod, &DEVPKEY_DeviceContainer_DiscoveryMethod, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyContainerIsEncrypted, &DEVPKEY_DeviceContainer_IsEncrypted, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerIsAuthenticated, &DEVPKEY_DeviceContainer_IsAuthenticated, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerIsConnected, &DEVPKEY_DeviceContainer_IsConnected, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerIsPaired, &DEVPKEY_DeviceContainer_IsPaired, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerIcon, &DEVPKEY_DeviceContainer_Icon, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerVersion, &DEVPKEY_DeviceContainer_Version, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerLastSeen, &DEVPKEY_DeviceContainer_Last_Seen, PhpDevPropFillTimeStamp, 0 },\n    { PhDevicePropertyContainerLastConnected, &DEVPKEY_DeviceContainer_Last_Connected, PhpDevPropFillTimeStamp, 0 },\n    { PhDevicePropertyContainerIsShowInDisconnectedState, &DEVPKEY_DeviceContainer_IsShowInDisconnectedState, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerIsLocalMachine, &DEVPKEY_DeviceContainer_IsLocalMachine, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerMetadataPath, &DEVPKEY_DeviceContainer_MetadataPath, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerIsMetadataSearchInProgress, &DEVPKEY_DeviceContainer_IsMetadataSearchInProgress, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerIsMetadataChecksum, &DEVPKEY_DeviceContainer_MetadataChecksum, PhpDevPropFillBinary, 0 },\n    { PhDevicePropertyContainerIsNotInterestingForDisplay, &DEVPKEY_DeviceContainer_IsNotInterestingForDisplay, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerLaunchDeviceStageOnDeviceConnect, &DEVPKEY_DeviceContainer_LaunchDeviceStageOnDeviceConnect, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerLaunchDeviceStageFromExplorer, &DEVPKEY_DeviceContainer_LaunchDeviceStageFromExplorer, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerBaselineExperienceId, &DEVPKEY_DeviceContainer_BaselineExperienceId, PhpDevPropFillGuid, 0 },\n    { PhDevicePropertyContainerIsDeviceUniquelyIdentifiable, &DEVPKEY_DeviceContainer_IsDeviceUniquelyIdentifiable, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerAssociationArray, &DEVPKEY_DeviceContainer_AssociationArray, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyContainerDeviceDescription1, &DEVPKEY_DeviceContainer_DeviceDescription1, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerDeviceDescription2, &DEVPKEY_DeviceContainer_DeviceDescription2, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerHasProblem, &DEVPKEY_DeviceContainer_HasProblem, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerIsSharedDevice, &DEVPKEY_DeviceContainer_IsSharedDevice, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerIsNetworkDevice, &DEVPKEY_DeviceContainer_IsNetworkDevice, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerIsDefaultDevice, &DEVPKEY_DeviceContainer_IsDefaultDevice, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerMetadataCabinet, &DEVPKEY_DeviceContainer_MetadataCabinet, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerRequiresPairingElevation, &DEVPKEY_DeviceContainer_RequiresPairingElevation, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerExperienceId, &DEVPKEY_DeviceContainer_ExperienceId, PhpDevPropFillGuid, 0 },\n    { PhDevicePropertyContainerCategory, &DEVPKEY_DeviceContainer_Category, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyContainerCategoryDescSingular, &DEVPKEY_DeviceContainer_Category_Desc_Singular, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyContainerCategoryDescPlural, &DEVPKEY_DeviceContainer_Category_Desc_Plural, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyContainerCategoryIcon, &DEVPKEY_DeviceContainer_Category_Icon, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerCategoryGroupDesc, &DEVPKEY_DeviceContainer_CategoryGroup_Desc, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyContainerCategoryGroupIcon, &DEVPKEY_DeviceContainer_CategoryGroup_Icon, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerPrimaryCategory, &DEVPKEY_DeviceContainer_PrimaryCategory, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerUnpairUninstall, &DEVPKEY_DeviceContainer_UnpairUninstall, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerRequiresUninstallElevation, &DEVPKEY_DeviceContainer_RequiresUninstallElevation, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerDeviceFunctionSubRank, &DEVPKEY_DeviceContainer_DeviceFunctionSubRank, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyContainerAlwaysShowDeviceAsConnected, &DEVPKEY_DeviceContainer_AlwaysShowDeviceAsConnected, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerConfigFlags, &DEVPKEY_DeviceContainer_ConfigFlags, PhpDevPropFillUInt32Hex, 0 },\n    { PhDevicePropertyContainerPrivilegedPackageFamilyNames, &DEVPKEY_DeviceContainer_PrivilegedPackageFamilyNames, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyContainerCustomPrivilegedPackageFamilyNames, &DEVPKEY_DeviceContainer_CustomPrivilegedPackageFamilyNames, PhpDevPropFillStringList, 0 },\n    { PhDevicePropertyContainerIsRebootRequired, &DEVPKEY_DeviceContainer_IsRebootRequired, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyContainerFriendlyName, &DEVPKEY_DeviceContainer_FriendlyName, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerManufacturer, &DEVPKEY_DeviceContainer_Manufacturer, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerModelName, &DEVPKEY_DeviceContainer_ModelName, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerModelNumber, &DEVPKEY_DeviceContainer_ModelNumber, PhpDevPropFillString, 0 },\n    { PhDevicePropertyContainerInstallInProgress, &DEVPKEY_DeviceContainer_InstallInProgress, PhpDevPropFillBoolean, 0 },\n\n    { PhDevicePropertyObjectType, &DEVPKEY_DevQuery_ObjectType, PhpDevPropFillUInt32, 0 },\n\n    { PhDevicePropertyPciDeviceType, &DEVPKEY_PciDevice_DeviceType, PhpDevPropFillPciDeviceType, 0 },\n    { PhDevicePropertyPciCurrentSpeedAndMode, &DEVPKEY_PciDevice_CurrentSpeedAndMode, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciBaseClass, &DEVPKEY_PciDevice_BaseClass, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciSubClass, &DEVPKEY_PciDevice_SubClass, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciProgIf, &DEVPKEY_PciDevice_ProgIf, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciCurrentPayloadSize, &DEVPKEY_PciDevice_CurrentPayloadSize, PhpDevPropFillPciDeviceRequestSize, 0 },\n    { PhDevicePropertyPciMaxPayloadSize, &DEVPKEY_PciDevice_MaxPayloadSize, PhpDevPropFillPciDeviceRequestSize, 0 },\n    { PhDevicePropertyPciMaxReadRequestSize, &DEVPKEY_PciDevice_MaxReadRequestSize, PhpDevPropFillPciDeviceRequestSize, 0 },\n    { PhDevicePropertyPciCurrentLinkSpeed, &DEVPKEY_PciDevice_CurrentLinkSpeed, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciCurrentLinkWidth, &DEVPKEY_PciDevice_CurrentLinkWidth, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciMaxLinkSpeed, &DEVPKEY_PciDevice_MaxLinkSpeed, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciMaxLinkWidth, &DEVPKEY_PciDevice_MaxLinkWidth, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciExpressSpecVersion, &DEVPKEY_PciDevice_ExpressSpecVersion, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciInterruptSupport, &DEVPKEY_PciDevice_InterruptSupport, PhpDevPropFillPciDeviceInterruptSupport, 0 },\n    { PhDevicePropertyPciInterruptMessageMaximum, &DEVPKEY_PciDevice_InterruptMessageMaximum, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciBarTypes, &DEVPKEY_PciDevice_BarTypes, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciSriovSupport, &DEVPKEY_PciDevice_SriovSupport, PhpDevPropFillPciDeviceSriovSupport, 0 },\n    { PhDevicePropertyPciLabel_Id, &DEVPKEY_PciDevice_Label_Id, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciLabel_String, &DEVPKEY_PciDevice_Label_String, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyPciSerialNumber, &DEVPKEY_PciDevice_SerialNumber, PhpDevPropFillUInt32, 0 },\n\n    { PhDevicePropertyPciExpressCapabilityControl, &DEVPKEY_PciRootBus_PCIExpressCapabilityControl, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyPciNativeExpressControl, &DEVPKEY_PciRootBus_NativePciExpressControl, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyPciSystemMsiSupport, &DEVPKEY_PciRootBus_SystemMsiSupport, PhpDevPropFillBoolean, 0 },\n\n    { PhDevicePropertyStoragePortable, &DEVPKEY_Storage_Portable, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyStorageRemovableMedia, &DEVPKEY_Storage_Removable_Media, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyStorageSystemCritical, &DEVPKEY_Storage_System_Critical, PhpDevPropFillBoolean, 0 },\n    { PhDevicePropertyStorageDiskNumber, &DEVPKEY_Storage_Disk_Number, PhpDevPropFillUInt32, 0 },\n    { PhDevicePropertyStoragePartitionNumber, &DEVPKEY_Storage_Partition_Number, PhpDevPropFillUInt32, 0 },\n\n    { PhDevicePropertyGpuLuid, &DEVPKEY_Gpu_Luid, PhpDevPropFillUInt64, 0 },\n    { PhDevicePropertyGpuPhysicalAdapterIndex, &DEVPKEY_Gpu_PhysicalAdapterIndex, PhpDevPropFillUInt32, 0 },\n};\nC_ASSERT(RTL_NUMBER_OF(PhpDeviceItemPropertyTable) == PhMaxDeviceProperty);\n\n#ifdef DEBUG\nstatic BOOLEAN PhpBreakOnDeviceProperty = FALSE;\nstatic PH_DEVICE_PROPERTY_CLASS PhpBreakOnDevicePropertyClass = 0;\n#endif\n\nPPH_DEVICE_PROPERTY PhGetDeviceProperty(\n    _In_ PPH_DEVICE_ITEM Item,\n    _In_ PH_DEVICE_PROPERTY_CLASS Class\n    )\n{\n    PPH_DEVICE_PROPERTY prop;\n\n    prop = &Item->Properties[Class];\n    if (!prop->Initialized)\n    {\n        const PH_DEVICE_PROPERTY_TABLE_ENTRY* entry;\n\n        entry = &PhpDeviceItemPropertyTable[Class];\n\n#ifdef DEBUG\n        if (PhpBreakOnDeviceProperty && (PhpBreakOnDevicePropertyClass == Class))\n            __debugbreak();\n#endif\n\n        entry->Callback(\n            Item->DeviceInfo->Handle,\n            &Item->DeviceInfoData,\n            entry->PropKey,\n            prop,\n            entry->CallbackFlags\n            );\n\n        prop->Initialized = TRUE;\n    }\n\n    return prop;\n}\n\nBOOLEAN PhLookupDevicePropertyClass(\n    _In_ const DEVPROPKEY* Key,\n    _Out_ PPH_DEVICE_PROPERTY_CLASS Class\n    )\n{\n    for (ULONG i = 0; i < RTL_NUMBER_OF(PhpDeviceItemPropertyTable); i++)\n    {\n        const PH_DEVICE_PROPERTY_TABLE_ENTRY* entry = &PhpDeviceItemPropertyTable[i];\n\n        if (IsEqualDevPropKey(*Key, *entry->PropKey))\n        {\n            *Class = entry->PropClass;\n            return TRUE;\n        }\n    }\n\n    *Class = PhMaxDeviceProperty;\n    return FALSE;\n}\n\nHICON PhGetDeviceIcon(\n    _In_ PPH_DEVICE_ITEM Item,\n    _In_ PPH_INTEGER_PAIR IconSize\n    )\n{\n    HICON iconHandle;\n\n    if (Item->DeviceInfoData.Interface)\n    {\n        // try to give the icon for the parent device\n        if (Item->Parent && !Item->Parent->DeviceInfoData.Interface)\n        {\n            if (!SetupDiLoadDeviceIcon(\n                Item->Parent->DeviceInfo->Handle,\n                &Item->Parent->DeviceInfoData.DeviceData,\n                IconSize->X,\n                IconSize->Y,\n                0,\n                &iconHandle\n                ))\n            {\n                iconHandle = NULL;\n            }\n        }\n        else\n        {\n            iconHandle = NULL;\n        }\n    }\n    else\n    {\n        if (!SetupDiLoadDeviceIcon(\n            Item->DeviceInfo->Handle,\n            &Item->DeviceInfoData.DeviceData,\n            IconSize->X,\n            IconSize->Y,\n            0,\n            &iconHandle\n            ))\n        {\n            iconHandle = NULL;\n        }\n    }\n\n    return iconHandle;\n}\n\nULONG PhpGenerateInstanceIdHash(\n    _In_ PPH_STRINGREF InstanceId\n    )\n{\n    return PhHashStringRefEx(InstanceId, TRUE, PH_STRING_HASH_X65599);\n}\n\nstatic int __cdecl PhpDeviceItemSortFunction(\n    const void* Left,\n    const void* Right\n    )\n{\n    PPH_DEVICE_ITEM lhsItem;\n    PPH_DEVICE_ITEM rhsItem;\n\n    lhsItem = *(PPH_DEVICE_ITEM*)Left;\n    rhsItem = *(PPH_DEVICE_ITEM*)Right;\n\n    return uintcmp(lhsItem->InstanceIdHash, rhsItem->InstanceIdHash);\n}\n\nstatic int __cdecl PhpDeviceItemSearchFunction(\n    const void* Hash,\n    const void* Item\n    )\n{\n    PPH_DEVICE_ITEM item;\n\n    item = *(PPH_DEVICE_ITEM*)Item;\n\n    return uintcmp(PtrToUlong(Hash), item->InstanceIdHash);\n}\n\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM PhLookupDeviceItemByHash(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ ULONG InstanceIdHash\n    )\n{\n    PPH_DEVICE_ITEM* deviceItem;\n\n    deviceItem = bsearch(\n        UlongToPtr(InstanceIdHash),\n        Tree->DeviceList->Items,\n        Tree->DeviceList->Count,\n        sizeof(PVOID),\n        PhpDeviceItemSearchFunction\n        );\n\n    return deviceItem ? *deviceItem : NULL;\n}\n\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM PhLookupDeviceItem(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ PPH_STRINGREF InstanceId\n    )\n{\n    return PhLookupDeviceItemByHash(Tree, PhpGenerateInstanceIdHash(InstanceId));\n}\n\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM PhReferenceDeviceItemByHash(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ ULONG InstanceIdHash\n    )\n{\n    PPH_DEVICE_ITEM deviceItem;\n\n    PhSetReference(&deviceItem, PhLookupDeviceItemByHash(Tree, InstanceIdHash));\n\n    return deviceItem;\n}\n\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM PhReferenceDeviceItem(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ PPH_STRINGREF InstanceId\n    )\n{\n    PPH_DEVICE_ITEM deviceItem;\n\n    PhSetReference(&deviceItem, PhLookupDeviceItem(Tree, InstanceId));\n\n    return deviceItem;\n}\n\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM PhReferenceDeviceItem2(\n    _In_ PPH_STRINGREF InstanceId\n    )\n{\n    PPH_DEVICE_TREE tree;\n    PPH_DEVICE_ITEM deviceItem;\n\n    tree = PhReferenceDeviceTree();\n    PhSetReference(&deviceItem, PhLookupDeviceItem(tree, InstanceId));\n    PhClearReference(&tree);\n\n    return deviceItem;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpDeviceInfoDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_DEVINFO info = Object;\n\n    if (info->Handle != INVALID_HANDLE_VALUE)\n    {\n        SetupDiDestroyDeviceInfoList(info->Handle);\n        info->Handle = INVALID_HANDLE_VALUE;\n    }\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpDeviceItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_DEVICE_ITEM item = Object;\n\n    for (ULONG i = 0; i < ARRAYSIZE(item->Properties); i++)\n    {\n        PPH_DEVICE_PROPERTY prop;\n\n        prop = &item->Properties[i];\n\n        if (prop->Valid)\n        {\n            if (prop->Type == PhDevicePropertyTypeString)\n            {\n                PhClearReference(&prop->String);\n            }\n            else if (prop->Type == PhDevicePropertyTypeStringList)\n            {\n                for (ULONG j = 0; j < prop->StringList->Count; j++)\n                {\n                    PhClearReference(&prop->StringList->Items[j]);\n                }\n\n                PhClearReference(&prop->StringList);\n            }\n            else if (prop->Type == PhDevicePropertyTypeBinary)\n            {\n#pragma warning(suppress : 6001) // buffer is valid and initialized\n                PhFree(prop->Binary.Buffer);\n            }\n        }\n\n        PhClearReference(&prop->AsString);\n    }\n\n    PhClearReference(&item->InstanceId);\n    PhClearReference(&item->ParentInstanceId);\n    PhClearReference(&item->DeviceInfo);\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpDeviceTreeDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_DEVICE_TREE tree = Object;\n\n    for (ULONG i = 0; i < tree->DeviceList->Count; i++)\n    {\n        PPH_DEVICE_ITEM item;\n\n        item = tree->DeviceList->Items[i];\n\n        PhClearReference(&item);\n    }\n\n    for (ULONG i = 0; i < tree->DeviceInterfaceList->Count; i++)\n    {\n        PPH_DEVICE_ITEM item;\n\n        item = tree->DeviceInterfaceList->Items[i];\n\n        PhClearReference(&item);\n    }\n\n    PhClearReference(&tree->DeviceList);\n    PhClearReference(&tree->DeviceInterfaceList);\n    PhClearReference(&tree->DeviceInfo);\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpDeviceNotifyDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_DEVICE_NOTIFY notify = Object;\n\n    if (notify->Action == PhDeviceNotifyInstanceEnumerated ||\n        notify->Action == PhDeviceNotifyInstanceStarted ||\n        notify->Action == PhDeviceNotifyInstanceRemoved)\n    {\n        PhClearReference(&notify->DeviceInstance.InstanceId);\n    }\n}\n\nPPH_DEVICE_ITEM NTAPI PhpAddDeviceItem(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ PSP_DEVINFO_DATA DeviceInfoData\n    )\n{\n    PPH_DEVICE_ITEM item;\n\n    item = PhCreateObjectZero(sizeof(PH_DEVICE_ITEM), PhDeviceItemType);\n\n    item->Tree = Tree;\n    item->DeviceInfo = PhReferenceObject(Tree->DeviceInfo);\n    RtlCopyMemory(&item->DeviceInfoData.DeviceData, DeviceInfoData, sizeof(SP_DEVINFO_DATA));\n    RtlCopyMemory(&item->ClassGuid, &DeviceInfoData->ClassGuid, sizeof(GUID));\n\n    //\n    // Only get the minimum here, the rest will be retrieved later if necessary.\n    // For convenience later, other frequently referenced items are gotten here too.\n    //\n\n    item->InstanceId = PhGetDeviceProperty(item, PhDevicePropertyInstanceId)->AsString;\n    if (item->InstanceId)\n    {\n        item->InstanceIdHash = PhpGenerateInstanceIdHash(&item->InstanceId->sr);\n\n        //\n        // If this is the root enumerator override some properties.\n        //\n        //if (PhEqualStringRef(&item->InstanceId->sr, &RootInstanceId, TRUE))\n        if (item->InstanceIdHash == RootInstanceIdHash)\n        {\n            PPH_DEVICE_PROPERTY prop;\n\n            prop = &item->Properties[PhDevicePropertyName];\n            assert(!prop->Initialized);\n\n            prop->AsString = PhGetActiveComputerName();\n            prop->Initialized = TRUE;\n        }\n\n        PhReferenceObject(item->InstanceId);\n    }\n\n    item->ParentInstanceId = PhGetDeviceProperty(item, PhDevicePropertyParentInstanceId)->AsString;\n    if (item->ParentInstanceId)\n        PhReferenceObject(item->ParentInstanceId);\n\n    PhGetDeviceProperty(item, PhDevicePropertyProblemCode);\n    if (item->Properties[PhDevicePropertyProblemCode].Valid)\n        item->ProblemCode = item->Properties[PhDevicePropertyProblemCode].UInt32;\n    else\n        item->ProblemCode = CM_PROB_PHANTOM;\n\n    PhGetDeviceProperty(item, PhDevicePropertyDevNodeStatus);\n    if (item->Properties[PhDevicePropertyDevNodeStatus].Valid)\n        item->DevNodeStatus = item->Properties[PhDevicePropertyDevNodeStatus].UInt32;\n    else\n        item->DevNodeStatus = 0;\n\n    PhGetDeviceProperty(item, PhDevicePropertyDevCapabilities);\n    if (item->Properties[PhDevicePropertyDevCapabilities].Valid)\n        item->Capabilities = item->Properties[PhDevicePropertyDevCapabilities].UInt32;\n    else\n        item->Capabilities = 0;\n\n    PhGetDeviceProperty(item, PhDevicePropertyUpperFilters);\n    PhGetDeviceProperty(item, PhDevicePropertyClassUpperFilters);\n    if ((item->Properties[PhDevicePropertyUpperFilters].Valid &&\n         (item->Properties[PhDevicePropertyUpperFilters].StringList->Count > 0)) ||\n        (item->Properties[PhDevicePropertyClassUpperFilters].Valid &&\n         (item->Properties[PhDevicePropertyClassUpperFilters].StringList->Count > 0)))\n    {\n        item->HasUpperFilters = TRUE;\n    }\n\n    PhGetDeviceProperty(item, PhDevicePropertyLowerFilters);\n    PhGetDeviceProperty(item, PhDevicePropertyClassLowerFilters);\n    if ((item->Properties[PhDevicePropertyLowerFilters].Valid &&\n         (item->Properties[PhDevicePropertyLowerFilters].StringList->Count > 0)) ||\n        (item->Properties[PhDevicePropertyClassLowerFilters].Valid &&\n         (item->Properties[PhDevicePropertyClassLowerFilters].StringList->Count > 0)))\n    {\n        item->HasLowerFilters = TRUE;\n    }\n\n    PhAddItemList(Tree->DeviceList, item);\n\n    return item;\n}\n\nPPH_DEVICE_ITEM NTAPI PhpAddDeviceInterfaceItem(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ PPH_DEVICE_ITEM DeviceItem,\n    _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData\n    )\n{\n    PPH_DEVICE_ITEM item;\n    PPH_DEVICE_PROPERTY prop;\n\n    item = PhCreateObjectZero(sizeof(PH_DEVICE_ITEM), PhDeviceItemType);\n\n    item->Tree = Tree;\n    item->DeviceInfo = PhReferenceObject(Tree->DeviceInfo);\n    item->DeviceInfoData.Interface = TRUE;\n    RtlCopyMemory(&item->DeviceInfoData.InterfaceData, DeviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));\n    RtlCopyMemory(&item->ClassGuid, &DeviceInterfaceData->InterfaceClassGuid, sizeof(GUID));\n\n    item->Parent = DeviceItem;\n    item->InstanceId = PhGetDeviceProperty(item, PhDevicePropertyInstanceId)->AsString;\n    if (item->InstanceId)\n        PhReferenceObject(item->InstanceId);\n    item->ParentInstanceId = PhReferenceObject(DeviceItem->InstanceId);\n    item->DeviceInterface = TRUE;\n\n    // link the interface as a \"child\" of the device\n    DeviceItem->InterfaceCount++;\n    if (DeviceItem->Child)\n    {\n        PPH_DEVICE_ITEM sibling = DeviceItem->Child;\n\n        while (sibling->Sibling)\n            sibling = sibling->Sibling;\n\n        sibling->Sibling = item;\n    }\n    else\n    {\n        DeviceItem->Child = item;\n    }\n\n    // if the interface has no name, override it to be the best possible name\n    prop = PhGetDeviceProperty(item, PhDevicePropertyName);\n    if (!prop->AsString)\n    {\n        PPH_STRING string;\n\n        if (string = PhGetDeviceProperty(item, PhDevicePropertyInterfaceFriendlyName)->AsString)\n            prop->AsString = PhReferenceObject(string);\n        else if (string = PhGetDeviceProperty(item, PhDevicePropertyInterfaceClassName)->AsString)\n            prop->AsString = PhReferenceObject(string);\n        else if (string = PhGetDeviceProperty(item, PhDevicePropertyInstanceId)->AsString)\n            prop->AsString = PhReferenceObject(string);\n        else\n            prop->AsString = PhFormatGuid(&DeviceInterfaceData->InterfaceClassGuid);\n    }\n\n    PhAddItemList(Tree->DeviceInterfaceList, item);\n\n    return item;\n}\n\nVOID PhpGetInterfaceClassList(\n    _Out_ PGUID* InterfaceClassList,\n    _Out_ PSIZE_T InterfaceClassListCount\n    )\n{\n    const DEV_OBJECT* objects = NULL;\n    ULONG objectCount;\n    PH_ARRAY objectArray;\n\n    if (HR_FAILED(PhDevGetObjects(\n        DevObjectTypeDeviceInterfaceClass,\n        DevQueryFlagNone,\n        0,\n        NULL,\n        0,\n        NULL,\n        &objectCount,\n        &objects\n        )) || !objects)\n    {\n        *InterfaceClassList = NULL;\n        *InterfaceClassListCount = 0;\n        return;\n    }\n\n    PhInitializeArray(&objectArray, sizeof(GUID), objectCount);\n\n    for (ULONG i = 0; i < objectCount; i++)\n    {\n        GUID interfaceClassGuid;\n        PH_STRINGREF interfaceClassGuidString;\n\n        PhInitializeStringRefLongHint(&interfaceClassGuidString, objects[i].pszObjectId);\n\n        if (!NT_SUCCESS(PhStringToGuid(&interfaceClassGuidString, &interfaceClassGuid)))\n            continue;\n\n        PhAddItemArray(&objectArray, &interfaceClassGuid);\n    }\n\n    *InterfaceClassList = PhFinalArrayItems(&objectArray);\n    *InterfaceClassListCount = PhFinalArrayCount(&objectArray);\n\n    PhDevFreeObjects(objectCount, objects);\n}\n\nVOID PhpAssociateDeviceInterfaces(\n    _Inout_ PPH_DEVICE_TREE Tree,\n    _In_ PPH_DEVICE_ITEM DeviceItem,\n    _In_ PGUID InterfaceClassList,\n    _In_ SIZE_T InterfaceClassListCount\n    )\n{\n    assert(!DeviceItem->DeviceInfoData.Interface);\n\n    for (SIZE_T i = 0; i < InterfaceClassListCount; i++)\n    {\n        for (ULONG j = 0;; j++)\n        {\n            SP_DEVICE_INTERFACE_DATA deviceInterfaceData;\n\n            RtlZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));\n            deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);\n\n            if (!SetupDiEnumDeviceInterfaces(\n                Tree->DeviceInfo->Handle,\n                &DeviceItem->DeviceInfoData.DeviceData,\n                &InterfaceClassList[i],\n                j,\n                &deviceInterfaceData\n                ))\n            {\n                break;\n            }\n\n            PhpAddDeviceInterfaceItem(Tree, DeviceItem, &deviceInterfaceData);\n        }\n    }\n}\n\n#ifdef DEBUG\nVOID PhpCheckDeviceTree(\n    _In_ PPH_DEVICE_TREE Tree\n    )\n{\n    static ULONG runawayLimit = 5000;\n    ULONG count;\n\n    assert(!Tree->Root->Sibling);\n    assert(!Tree->Root->Parent);\n\n    for (ULONG i = 0; i < Tree->DeviceList->Count; i++)\n    {\n        PPH_DEVICE_ITEM item;\n        PPH_DEVICE_ITEM other;\n\n        item = Tree->DeviceList->Items[i];\n\n        // ensure children terminate\n        other = item->Child;\n        count = 0;\n        while (other)\n        {\n            other = other->Child;\n            assert(count < runawayLimit);\n        }\n\n        // ensure siblings terminate\n        other = item->Sibling;\n        count = 0;\n        while (other)\n        {\n            other = other->Sibling;\n            assert(count < runawayLimit);\n        }\n\n        // ensure parents terminate\n        other = item->Parent;\n        count = 0;\n        while (other)\n        {\n            other = other->Parent;\n            assert(count < runawayLimit);\n        }\n    }\n\n    for (ULONG i = 0; i < Tree->DeviceInterfaceList->Count; i++)\n    {\n        PPH_DEVICE_ITEM item;\n        PPH_DEVICE_ITEM other;\n\n        item = Tree->DeviceInterfaceList->Items[i];\n\n        // ensure children terminate\n        other = item->Child;\n        count = 0;\n        while (other)\n        {\n            other = other->Child;\n            assert(count < runawayLimit);\n        }\n\n        // ensure siblings terminate\n        other = item->Sibling;\n        count = 0;\n        while (other)\n        {\n            other = other->Sibling;\n            assert(count < runawayLimit);\n        }\n\n        // ensure parents terminate\n        other = item->Parent;\n        count = 0;\n        while (other)\n        {\n            other = other->Parent;\n            assert(count < runawayLimit);\n        }\n    }\n}\n#endif\n\nPPH_DEVICE_TREE PhpCreateDeviceTree(\n    VOID\n    )\n{\n    PPH_DEVICE_TREE tree;\n    PPH_DEVICE_ITEM root;\n    PGUID interfaceClassList;\n    SIZE_T interfaceClassListCount;\n\n    tree = PhCreateObjectZero(sizeof(PH_DEVICE_TREE), PhDeviceTreeType);\n    tree->DeviceList = PhCreateList(250);\n    tree->DeviceInterfaceList = PhCreateList(1024);\n    tree->DeviceInfo = PhCreateObject(sizeof(PH_DEVINFO), PhpDeviceInfoType);\n\n    tree->DeviceInfo->Handle = SetupDiGetClassDevsW(\n        NULL,\n        NULL,\n        NULL,\n        DIGCF_ALLCLASSES\n        );\n    if (tree->DeviceInfo->Handle == INVALID_HANDLE_VALUE)\n    {\n        return tree;\n    }\n\n    for (ULONG i = 0;; i++)\n    {\n        SP_DEVINFO_DATA deviceInfoData;\n\n        RtlZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));\n        deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);\n\n        if (!SetupDiEnumDeviceInfo(tree->DeviceInfo->Handle, i, &deviceInfoData))\n            break;\n\n        PhpAddDeviceItem(tree, &deviceInfoData);\n    }\n\n    // now add interfaces to the device info set, the return value will be the\n    // same pointer as the existing handle\n    (VOID)SetupDiGetClassDevsExW(\n        NULL,\n        NULL,\n        NULL,\n        DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE,\n        tree->DeviceInfo->Handle,\n        NULL,\n        NULL\n        );\n\n    PhpGetInterfaceClassList(&interfaceClassList, &interfaceClassListCount);\n\n    // Link the device relations.\n    root = NULL;\n\n    for (ULONG i = 0; i < tree->DeviceList->Count; i++)\n    {\n        BOOLEAN found;\n        PPH_DEVICE_ITEM item;\n        PPH_DEVICE_ITEM other;\n\n        found = FALSE;\n\n        item = tree->DeviceList->Items[i];\n\n        // for this device item associate any device interfaces\n        PhpAssociateDeviceInterfaces(tree, item, interfaceClassList, interfaceClassListCount);\n\n        for (ULONG j = 0; j < tree->DeviceList->Count; j++)\n        {\n            other = tree->DeviceList->Items[j];\n\n            if (item == other)\n            {\n                continue;\n            }\n\n            if (!other->InstanceId || !item->ParentInstanceId)\n            {\n                continue;\n            }\n\n            if (!PhEqualString(other->InstanceId, item->ParentInstanceId, TRUE))\n            {\n                continue;\n            }\n\n            found = TRUE;\n\n            item->Parent = other;\n            item->Parent->ChildrenCount++;\n\n            if (!other->Child)\n            {\n                other->Child = item;\n                break;\n            }\n\n            other = other->Child;\n            while (other->Sibling)\n            {\n                other = other->Sibling;\n            }\n\n            other->Sibling = item;\n            break;\n        }\n\n        if (!found)\n        {\n            assert(!root);\n            root = item;\n        }\n    }\n\n    tree->Root = root;\n\n    // sort the list for faster lookups later\n    qsort(\n        tree->DeviceList->Items,\n        tree->DeviceList->Count,\n        sizeof(PVOID),\n        PhpDeviceItemSortFunction\n        );\n\n    if (interfaceClassList)\n        PhFree(interfaceClassList);\n\n#ifdef DEBUG\n    PhpCheckDeviceTree(tree);\n#endif\n\n    return tree;\n}\n\nPPH_DEVICE_TREE PhpPublishDeviceTree(\n    VOID\n    )\n{\n    PPH_DEVICE_TREE newTree;\n    PPH_DEVICE_TREE oldTree;\n\n    newTree = PhpCreateDeviceTree();\n    PhReferenceObject(newTree);\n\n    PhAcquireFastLockExclusive(&PhpDeviceTreeLock);\n    oldTree = PhpDeviceTree;\n    PhpDeviceTree = newTree;\n    PhReleaseFastLockExclusive(&PhpDeviceTreeLock);\n\n    PhClearReference(&oldTree);\n\n    return newTree;\n}\n\nVOID PhpDeviceNotify(\n    _In_ PSLIST_ENTRY List\n    )\n{\n    PPH_DEVICE_TREE deviceTree;\n    PPH_DEVICE_NOTIFY entry;\n\n    // We process device notifications in blocks so that bursts of device changes\n    // don't each trigger a new tree each time. THe internal is determined by the\n    // interval update and the Service Provider Updated Event. (500ms/1000ms)\n\n    if (deviceTree = PhpPublishDeviceTree())\n    {\n        while (List)\n        {\n            entry = CONTAINING_RECORD(List, PH_DEVICE_NOTIFY, ListEntry);\n            List = List->Next;\n\n            // Restore TypeIndex and Flags.\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackDeviceNotificationEvent), entry);\n\n            PhFreeToFreeList(&PhDeviceNotifyFreeList, entry);\n        }\n    }\n\n    PhClearReference(&deviceTree);\n}\n\n_Function_class_(PCM_NOTIFY_CALLBACK)\nULONG CALLBACK PhpCmNotifyCallback(\n    _In_ HCMNOTIFICATION hNotify,\n    _In_opt_ PVOID Context,\n    _In_ CM_NOTIFY_ACTION Action,\n    _In_reads_bytes_(EventDataSize) PCM_NOTIFY_EVENT_DATA EventData,\n    _In_ ULONG EventDataSize\n    )\n{\n    PPH_DEVICE_NOTIFY entry;\n\n    switch (Action)\n    {\n    case CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL:\n        {\n            entry = PhAllocateFromFreeList(&PhDeviceNotifyFreeList);\n            memset(entry, 0, sizeof(PH_DEVICE_NOTIFY));\n            entry->Action = PhDeviceNotifyInterfaceArrival;\n            RtlCopyMemory(&entry->DeviceInterface.ClassGuid, &EventData->u.DeviceInterface.ClassGuid, sizeof(GUID));\n\n            InterlockedPushEntrySList(&PhDeviceNotifyListHead, &entry->ListEntry);\n        }\n        break;\n    case CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL:\n        {\n            entry = PhAllocateFromFreeList(&PhDeviceNotifyFreeList);\n            memset(entry, 0, sizeof(PH_DEVICE_NOTIFY));\n            entry->Action = PhDeviceNotifyInterfaceRemoval;\n            RtlCopyMemory(&entry->DeviceInterface.ClassGuid, &EventData->u.DeviceInterface.ClassGuid, sizeof(GUID));\n\n            InterlockedPushEntrySList(&PhDeviceNotifyListHead, &entry->ListEntry);\n        }\n        break;\n    case CM_NOTIFY_ACTION_DEVICEINSTANCEENUMERATED:\n        {\n            entry = PhAllocateFromFreeList(&PhDeviceNotifyFreeList);\n            memset(entry, 0, sizeof(PH_DEVICE_NOTIFY));\n            entry->Action = PhDeviceNotifyInstanceEnumerated;\n            entry->DeviceInstance.InstanceId = PhCreateString(EventData->u.DeviceInstance.InstanceId);\n\n            InterlockedPushEntrySList(&PhDeviceNotifyListHead, &entry->ListEntry);\n        }\n        break;\n    case CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED:\n        {\n            entry = PhAllocateFromFreeList(&PhDeviceNotifyFreeList);\n            memset(entry, 0, sizeof(PH_DEVICE_NOTIFY));\n            entry->Action = PhDeviceNotifyInstanceStarted;\n            entry->DeviceInstance.InstanceId = PhCreateString(EventData->u.DeviceInstance.InstanceId);\n\n            InterlockedPushEntrySList(&PhDeviceNotifyListHead, &entry->ListEntry);\n        }\n        break;\n    case CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED:\n        {\n            entry = PhAllocateFromFreeList(&PhDeviceNotifyFreeList);\n            memset(entry, 0, sizeof(PH_DEVICE_NOTIFY));\n            entry->Action = PhDeviceNotifyInstanceRemoved;\n            entry->DeviceInstance.InstanceId = PhCreateString(EventData->u.DeviceInstance.InstanceId);\n\n            InterlockedPushEntrySList(&PhDeviceNotifyListHead, &entry->ListEntry);\n        }\n        break;\n    }\n\n    return ERROR_SUCCESS;\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ServiceProviderUpdatedCallback(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    PSLIST_ENTRY list;\n\n    // drain the list\n\n    if (list = RtlInterlockedFlushSList(&PhDeviceNotifyListHead))\n    {\n        PhpDeviceNotify(list);\n    }\n}\n\nBOOLEAN PhpDeviceProviderInitialization(\n    VOID\n    )\n{\n    CM_NOTIFY_FILTER cmFilter;\n\n    if (WindowsVersion < WINDOWS_10 || !PhGetIntegerSetting(L\"EnableDeviceSupport\"))\n        return FALSE;\n\n    PhDeviceItemType = PhCreateObjectType(L\"DeviceItem\", 0, PhpDeviceItemDeleteProcedure);\n    PhDeviceTreeType = PhCreateObjectType(L\"DeviceTree\", 0, PhpDeviceTreeDeleteProcedure);\n    PhDeviceNotifyType = PhCreateObjectType(L\"DeviceNotify\", 0, PhpDeviceNotifyDeleteProcedure);\n    PhpDeviceInfoType = PhCreateObjectType(L\"DeviceInfo\", 0, PhpDeviceInfoDeleteProcedure);\n\n    PhInitializeSListHead(&PhDeviceNotifyListHead);\n    PhInitializeFreeList(&PhDeviceNotifyFreeList, sizeof(PH_DEVICE_NOTIFY), 16);\n\n    RtlZeroMemory(&cmFilter, sizeof(CM_NOTIFY_FILTER));\n    cmFilter.cbSize = sizeof(CM_NOTIFY_FILTER);\n    cmFilter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE;\n    cmFilter.Flags = CM_NOTIFY_FILTER_FLAG_ALL_DEVICE_INSTANCES;\n    if (CM_Register_Notification(\n        &cmFilter,\n        NULL,\n        PhpCmNotifyCallback,\n        &PhpDeviceNotification\n        ) != CR_SUCCESS)\n    {\n        return FALSE;\n    }\n\n    RtlZeroMemory(&cmFilter, sizeof(CM_NOTIFY_FILTER));\n    cmFilter.cbSize = sizeof(CM_NOTIFY_FILTER);\n    cmFilter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;\n    cmFilter.Flags = CM_NOTIFY_FILTER_FLAG_ALL_INTERFACE_CLASSES;\n    if (CM_Register_Notification(\n        &cmFilter,\n        NULL,\n        PhpCmNotifyCallback,\n        &PhpDeviceInterfaceNotification\n        ) != CR_SUCCESS)\n    {\n        return FALSE;\n    }\n\n    PhRegisterCallback(\n        PhGetGeneralCallback(GeneralCallbackServiceProviderUpdatedEvent),\n        ServiceProviderUpdatedCallback,\n        NULL,\n        &ServiceProviderUpdatedRegistration\n        );\n\n    return TRUE;\n}\n\nBOOLEAN PhDeviceProviderInitialization(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOLEAN initialized = FALSE;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        initialized = PhpDeviceProviderInitialization();\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return initialized;\n}\n\nPPH_DEVICE_TREE PhReferenceDeviceTree(\n    VOID\n    )\n{\n    return PhReferenceDeviceTreeEx(FALSE);\n}\n\nPPH_DEVICE_TREE PhReferenceDeviceTreeEx(\n    _In_ BOOLEAN ForceRefresh\n    )\n{\n    PPH_DEVICE_TREE deviceTree;\n\n    PhAcquireFastLockShared(&PhpDeviceTreeLock);\n    PhSetReference(&deviceTree, PhpDeviceTree);\n    PhReleaseFastLockShared(&PhpDeviceTreeLock);\n\n    if (ForceRefresh || !deviceTree)\n    {\n        PhMoveReference(&deviceTree, PhpPublishDeviceTree());\n    }\n\n    return deviceTree;\n}\n\nBOOLEAN PhEnumDeviceResources(\n    _In_ PPH_DEVICE_ITEM Item,\n    _In_ ULONG LogicalConfig,\n    _In_ PPH_DEVICE_ENUM_RESOURCES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    BOOLEAN done;\n    LOG_CONF logicalConfig;\n    PVOID buffer;\n    ULONG length;\n\n    if (CM_Get_First_Log_Conf(\n        &logicalConfig,\n        Item->DeviceInfoData.DeviceData.DevInst,\n        LogicalConfig\n        ) != CR_SUCCESS)\n        return FALSE;\n\n    done = FALSE;\n    buffer = PhAllocate(64);\n    length = 64;\n\n    while (!done)\n    {\n        LOG_CONF nextConfig;\n        ULONG size;\n        RES_DES deviceResource;\n        RESOURCEID resourceId;\n\n        if (CM_Get_Next_Res_Des(\n            &deviceResource,\n            logicalConfig,\n            ResType_All,\n            &resourceId,\n            0\n            ) == CR_SUCCESS)\n        {\n            while (!done)\n            {\n                RES_DES nextResource;\n\n                if (CM_Get_Res_Des_Data_Size(&size, deviceResource, 0) == CR_SUCCESS)\n                {\n                    if (size > length)\n                    {\n                        buffer = PhReAllocate(buffer, size);\n                        length = size;\n                    }\n\n                    assert(buffer);\n\n                    if (CM_Get_Res_Des_Data(deviceResource, buffer, size, 0) == CR_SUCCESS)\n                    {\n                        done = Callback(LogicalConfig, resourceId, buffer, size, Context);\n                        if (done)\n                            break;\n                    }\n                }\n\n                if (CM_Get_Next_Res_Des(\n                    &nextResource,\n                    deviceResource,\n                    ResType_All,\n                    &resourceId,\n                    0\n                    ) != CR_SUCCESS)\n                    break;\n\n                CM_Free_Res_Des_Handle(deviceResource);\n                deviceResource = nextResource;\n            }\n        }\n\n        CM_Free_Res_Des_Handle(deviceResource);\n\n        if (done)\n            break;\n\n        if (CM_Get_Next_Log_Conf(&nextConfig, logicalConfig, 0) != CR_SUCCESS)\n            break;\n\n        CM_Free_Log_Conf_Handle(logicalConfig);\n        logicalConfig = nextConfig;\n    }\n\n    CM_Free_Log_Conf_Handle(logicalConfig);\n\n    PhFree(buffer);\n\n    return TRUE;\n}\n"
  },
  {
    "path": "SystemInformer/extmgr.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011\n *\n */\n\n/*\n * The extension manager provides support for generic extensions. It sits directly\n * underneath the plugin manager, and has no knowledge of plugin details (how they are\n * loaded, plugin information, etc.).\n */\n\n#include <phapp.h>\n#include <extmgri.h>\n\nLIST_ENTRY PhEmAppContextListHead = { &PhEmAppContextListHead, &PhEmAppContextListHead };\nULONG PhEmAppContextCount = 0;\nPH_EM_OBJECT_TYPE_STATE PhEmObjectTypeState[EmMaximumObjectType] = { 0 };\n\n/**\n * Initializes the extension manager module.\n */\nVOID PhEmInitialization(\n    VOID\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < EmMaximumObjectType; i++)\n    {\n        InitializeListHead(&PhEmObjectTypeState[i].ExtensionListHead);\n    }\n}\n\n/**\n * Initializes an extension application context.\n *\n * \\param AppContext The application context.\n * \\param AppName The application name.\n */\nVOID PhEmInitializeAppContext(\n    _Out_ PPH_EM_APP_CONTEXT AppContext,\n    _In_ PCPH_STRINGREF AppName\n    )\n{\n    AppContext->AppName = *AppName;\n    memset(AppContext->Extensions, 0, sizeof(AppContext->Extensions));\n\n    InsertTailList(&PhEmAppContextListHead, &AppContext->ListEntry);\n    PhEmAppContextCount++;\n}\n\n/**\n * Sets the object extension size and callbacks for an object type.\n *\n * \\param AppContext The application context.\n * \\param ObjectType The type of object for which the extension is being registered.\n * \\param ExtensionSize The size of the extension, in bytes.\n * \\param CreateCallback The object creation callback.\n * \\param DeleteCallback The object deletion callback.\n */\nVOID PhEmSetObjectExtension(\n    _Inout_ PPH_EM_APP_CONTEXT AppContext,\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ SIZE_T ExtensionSize,\n    _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback,\n    _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback\n    )\n{\n    PPH_EM_OBJECT_TYPE_STATE objectTypeState;\n    PPH_EM_OBJECT_EXTENSION objectExtension;\n\n    objectTypeState = &PhEmObjectTypeState[ObjectType];\n    objectExtension = AppContext->Extensions[ObjectType];\n\n    if (!objectExtension)\n    {\n        objectExtension = PhAllocate(sizeof(PH_EM_OBJECT_EXTENSION));\n        memset(objectExtension, 0, sizeof(PH_EM_OBJECT_EXTENSION));\n        InsertTailList(&objectTypeState->ExtensionListHead, &objectExtension->ListEntry);\n        AppContext->Extensions[ObjectType] = objectExtension;\n\n        objectExtension->ExtensionSize = ExtensionSize;\n        objectExtension->ExtensionOffset = objectTypeState->ExtensionOffset;\n        objectTypeState->ExtensionOffset += ExtensionSize;\n    }\n\n    objectExtension->Callbacks[EmObjectCreate] = CreateCallback;\n    objectExtension->Callbacks[EmObjectDelete] = DeleteCallback;\n}\n\n/**\n * Gets the object for an extension.\n *\n * \\param AppContext The application context.\n * \\param ObjectType The type of object for which an extension has been registered.\n * \\param Extension The object extension.\n */\nPVOID PhEmGetObject(\n    _In_ PPH_EM_APP_CONTEXT AppContext,\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ PVOID Extension\n    )\n{\n    PPH_EM_OBJECT_EXTENSION objectExtension;\n\n    objectExtension = AppContext->Extensions[ObjectType];\n\n    if (!objectExtension)\n        return NULL;\n\n    return PTR_SUB_OFFSET(Extension, PhEmObjectTypeState[ObjectType].InitialSize + objectExtension->ExtensionOffset);\n}\n\n/**\n * Gets the object extension for an object.\n *\n * \\param AppContext The application context.\n * \\param ObjectType The type of object for which an extension has been registered.\n * \\param Object The object.\n */\nPVOID PhEmGetObjectExtension(\n    _In_ PPH_EM_APP_CONTEXT AppContext,\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ PVOID Object\n    )\n{\n    PPH_EM_OBJECT_EXTENSION objectExtension;\n\n    objectExtension = AppContext->Extensions[ObjectType];\n\n    if (!objectExtension)\n        return NULL;\n\n    return PTR_ADD_OFFSET(Object, PhEmObjectTypeState[ObjectType].InitialSize + objectExtension->ExtensionOffset);\n}\n\n/**\n * Determines the size of an object, including extensions.\n *\n * \\param ObjectType The object type.\n * \\param InitialSize The initial size of the object.\n */\nSIZE_T PhEmGetObjectSize(\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ SIZE_T InitialSize\n    )\n{\n    PhEmObjectTypeState[ObjectType].InitialSize = InitialSize;\n\n    return InitialSize + PhEmObjectTypeState[ObjectType].ExtensionOffset;\n}\n\n/**\n * Invokes callbacks for an object operation.\n *\n * \\param ObjectType The object type.\n * \\param Object The object.\n * \\param Operation The operation being performed.\n */\nVOID PhEmCallObjectOperation(\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ PVOID Object,\n    _In_ PH_EM_OBJECT_OPERATION Operation\n    )\n{\n    PPH_EM_OBJECT_TYPE_STATE objectTypeState;\n    PLIST_ENTRY listEntry;\n    PPH_EM_OBJECT_EXTENSION objectExtension;\n\n    if (PhEmAppContextCount == 0)\n        return;\n\n    objectTypeState = &PhEmObjectTypeState[ObjectType];\n\n    listEntry = objectTypeState->ExtensionListHead.Flink;\n\n    while (listEntry != &objectTypeState->ExtensionListHead)\n    {\n        objectExtension = CONTAINING_RECORD(listEntry, PH_EM_OBJECT_EXTENSION, ListEntry);\n\n        if (objectExtension->Callbacks[Operation])\n        {\n            objectExtension->Callbacks[Operation](\n                Object,\n                ObjectType,\n                PTR_ADD_OFFSET(Object, objectTypeState->InitialSize + objectExtension->ExtensionOffset)\n                );\n        }\n\n        listEntry = listEntry->Flink;\n    }\n}\n\n/**\n * Parses an application name and sub-ID pair.\n *\n * \\param CompoundId The compound identifier.\n * \\param AppName A variable which receives the application name.\n * \\param SubId A variable which receives the sub-ID.\n */\n_Success_(return)\nBOOLEAN PhEmParseCompoundId(\n    _In_ PCPH_STRINGREF CompoundId,\n    _Out_ PPH_STRINGREF AppName,\n    _Out_ PULONG SubId\n    )\n{\n    PH_STRINGREF firstPart;\n    PH_STRINGREF secondPart;\n    ULONG64 integer;\n\n    firstPart = *CompoundId;\n\n    if (firstPart.Length == 0)\n        return FALSE;\n    if (firstPart.Buffer[0] != L'+')\n        return FALSE;\n\n    PhSkipStringRef(&firstPart, sizeof(WCHAR));\n    PhSplitStringRefAtChar(&firstPart, L'+', &firstPart, &secondPart);\n\n    if (firstPart.Length == 0 || secondPart.Length == 0)\n        return FALSE;\n\n    if (!PhStringToUInt64(&secondPart, 10, &integer))\n        return FALSE;\n\n    if (PhIsLegacyPrefix(&firstPart))\n    {\n        PhSkipStringRef(&firstPart, 14 * sizeof(WCHAR));\n    }\n\n    *AppName = firstPart;\n    *SubId = (ULONG)integer;\n\n    return TRUE;\n}\n"
  },
  {
    "path": "SystemInformer/findobj.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <cpysave.h>\n#include <emenu.h>\n#include <hndlinfo.h>\n#include <kphuser.h>\n#include <secedit.h>\n#include <workqueue.h>\n\n#include <colmgr.h>\n#include <hndlmenu.h>\n#include <hndlprv.h>\n#include <mainwnd.h>\n#include <procprv.h>\n#include <proctree.h>\n#include <phsettings.h>\n#include <settings.h>\n\n#define WM_PH_SEARCH_SHOWDIALOG (WM_APP + 801)\n#define WM_PH_SEARCH_FINISHED (WM_APP + 802)\n#define WM_PH_SEARCH_SHOWMENU (WM_APP + 803)\n\nstatic PPH_OBJECT_TYPE PhFindObjectsItemType = NULL;\nstatic HANDLE PhFindObjectsThreadHandle = NULL;\nstatic HWND PhFindObjectsWindowHandle = NULL;\nstatic PH_EVENT PhFindObjectsInitializedEvent = PH_EVENT_INIT;\n\ntypedef struct _PH_HANDLE_SEARCH_CONTEXT\n{\n    PH_LAYOUT_MANAGER LayoutManager;\n    RECT MinimumSize;\n\n    HWND WindowHandle;\n    HWND TreeNewHandle;\n    HWND TypeWindowHandle;\n    HWND SearchWindowHandle;\n    PPH_STRING WindowText;\n    HFONT TypeWindowFont;\n\n    ULONG TreeNewSortColumn;\n    PH_SORT_ORDER TreeNewSortOrder;\n    //PPH_HASHTABLE NodeHashtable;\n    PPH_LIST NodeList;\n\n    HANDLE SearchThreadHandle;\n\n    BOOLEAN SearchAll;\n    BOOLEAN SearchStop;\n\n    PPH_STRING SearchTypeString;\n    ULONG_PTR SearchMatchHandle;\n    PPH_LIST SearchResults;\n    ULONG SearchResultsAddIndex;\n    PH_QUEUED_LOCK SearchResultsLock;\n} PH_HANDLE_SEARCH_CONTEXT, *PPH_HANDLE_SEARCH_CONTEXT;\n\ntypedef enum _PHP_OBJECT_RESULT_TYPE\n{\n    HandleSearchResult,\n    ModuleSearchResult,\n    MappedFileSearchResult\n} PHP_OBJECT_RESULT_TYPE;\n\ntypedef struct _PHP_OBJECT_SEARCH_RESULT\n{\n    HANDLE ProcessId;\n    PHP_OBJECT_RESULT_TYPE ResultType;\n\n    HANDLE Handle;\n    PVOID Object;\n    PPH_STRING TypeName;\n    PPH_STRING ObjectName;\n    PPH_STRING BestObjectName;\n\n    SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Info;\n} PHP_OBJECT_SEARCH_RESULT, *PPHP_OBJECT_SEARCH_RESULT;\n\ntypedef enum _PH_HANDLE_OBJECT_TREE_COLUMN_ITEM_NAME\n{\n    PH_OBJECT_SEARCH_TREE_COLUMN_PROCESS,\n    PH_OBJECT_SEARCH_TREE_COLUMN_TYPE,\n    PH_OBJECT_SEARCH_TREE_COLUMN_NAME,\n    PH_OBJECT_SEARCH_TREE_COLUMN_HANDLE,\n    PH_OBJECT_SEARCH_TREE_COLUMN_OBJECTADDRESS,\n    PH_OBJECT_SEARCH_TREE_COLUMN_ORIGINALNAME,\n    PH_OBJECT_SEARCH_TREE_COLUMN_GRANTEDACCESS,\n    PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM\n} PH_HANDLE_OBJECT_TREE_COLUMN_ITEM_NAME;\n\ntypedef struct _PH_HANDLE_OBJECT_TREE_ROOT_NODE\n{\n    PH_TREENEW_NODE Node;\n    ULONG64 UniqueId; // used to stabilize sorting\n    PHP_OBJECT_RESULT_TYPE ResultType;\n    PVOID HandleObject;\n    HANDLE Handle;\n    HANDLE ProcessId;\n    PPH_STRING ClientIdName;\n    PPH_STRING TypeNameString;\n    PPH_STRING ObjectNameString;\n    PPH_STRING BestObjectName;\n    PPH_STRING GrantedAccessSymbolicText;\n    WCHAR HandleString[PH_PTR_STR_LEN_1];\n    WCHAR ObjectString[PH_PTR_STR_LEN_1];\n\n    SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo;\n\n    PH_STRINGREF TextCache[PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM];\n} PH_HANDLE_OBJECT_TREE_ROOT_NODE, *PPH_HANDLE_OBJECT_TREE_ROOT_NODE;\n\n#define SORT_FUNCTION(Column) PhpHandleObjectTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpHandleObjectTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_HANDLE_SEARCH_CONTEXT context = ((PPH_HANDLE_SEARCH_CONTEXT)_context); \\\n    PPH_HANDLE_OBJECT_TREE_ROOT_NODE node1 = *(PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)_elem1; \\\n    PPH_HANDLE_OBJECT_TREE_ROOT_NODE node2 = *(PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)_elem2; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)node1->UniqueId, (ULONG_PTR)node2->UniqueId); \\\n    \\\n    return PhModifySort(sortResult, context->TreeNewSortOrder); \\\n}\n\nBEGIN_SORT_FUNCTION(Process)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->ClientIdName, node2->ClientIdName, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Type)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->TypeNameString, node2->TypeNameString, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->BestObjectName, node2->BestObjectName, context->TreeNewSortOrder, FALSE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Handle)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->Handle, (ULONG_PTR)node2->Handle);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ObjectAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->HandleObject, (ULONG_PTR)node2->HandleObject);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(OriginalName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->ObjectNameString, node2->ObjectNameString, context->TreeNewSortOrder, FALSE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(GrantedAccess)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->GrantedAccessSymbolicText, node2->GrantedAccessSymbolicText, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nVOID PhpHandleObjectLoadSettingsTreeList(\n    _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhGetStringSetting(SETTING_FIND_OBJ_TREE_LIST_COLUMNS);\n    PhCmLoadSettings(Context->TreeNewHandle, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\nVOID PhpHandleObjectSaveSettingsTreeList(\n    _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhCmSaveSettings(Context->TreeNewHandle);\n    PhSetStringSetting2(SETTING_FIND_OBJ_TREE_LIST_COLUMNS, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\n//BOOLEAN PhpHandleObjectNodeHashtableEqualFunction(\n//    _In_ PVOID Entry1,\n//    _In_ PVOID Entry2\n//    )\n//{\n//    PPH_HANDLE_OBJECT_TREE_ROOT_NODE node1 = *(PPH_HANDLE_OBJECT_TREE_ROOT_NODE *)Entry1;\n//    PPH_HANDLE_OBJECT_TREE_ROOT_NODE node2 = *(PPH_HANDLE_OBJECT_TREE_ROOT_NODE *)Entry2;\n//\n//    return node1->HandleObject == node2->HandleObject;\n//}\n//\n//ULONG PhpHandleObjectNodeHashtableHashFunction(\n//    _In_ PVOID Entry\n//    )\n//{\n//    return PhHashIntPtr((ULONG_PTR)(*(PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)Entry)->Handle);\n//}\n\nVOID PhpDestroyHandleObjectNode(\n    _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node\n    )\n{\n    PhClearReference(&Node->ClientIdName);\n    PhClearReference(&Node->TypeNameString);\n    PhClearReference(&Node->ObjectNameString);\n    PhClearReference(&Node->BestObjectName);\n    PhClearReference(&Node->GrantedAccessSymbolicText);\n\n    PhFree(Node);\n}\n\nPPH_HANDLE_OBJECT_TREE_ROOT_NODE PhpAddHandleObjectNode(\n    _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context,\n    _In_ HANDLE Handle\n    )\n{\n    static ULONG64 NextUniqueId = 0;\n    PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode;\n\n    handleObjectNode = PhAllocate(sizeof(PH_HANDLE_OBJECT_TREE_ROOT_NODE));\n    memset(handleObjectNode, 0, sizeof(PH_HANDLE_OBJECT_TREE_ROOT_NODE));\n    PhInitializeTreeNewNode(&handleObjectNode->Node);\n\n    memset(handleObjectNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM);\n    handleObjectNode->Node.TextCache = handleObjectNode->TextCache;\n    handleObjectNode->Node.TextCacheSize = PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM;\n\n    handleObjectNode->Handle = Handle;\n    handleObjectNode->UniqueId = ++NextUniqueId;\n\n    //PhAddEntryHashtable(Context->NodeHashtable, &handleObjectNode);\n    PhAddItemList(Context->NodeList, handleObjectNode);\n\n    //TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    return handleObjectNode;\n}\n\n//PPH_HANDLE_OBJECT_TREE_ROOT_NODE PhpFindHandleObjectNode(\n//    _In_ PPH_HANDLE_SEARCH_CONTEXT Context,\n//    _In_ HANDLE Handle\n//    )\n//{\n//    PH_HANDLE_OBJECT_TREE_ROOT_NODE lookupHandleObjectNode;\n//    PPH_HANDLE_OBJECT_TREE_ROOT_NODE lookupHandleObjectNodePtr = &lookupHandleObjectNode;\n//    PPH_HANDLE_OBJECT_TREE_ROOT_NODE *handleObjectNode;\n//\n//    lookupHandleObjectNode.Handle = Handle;\n//\n//    handleObjectNode = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)PhFindEntryHashtable(\n//        Context->NodeHashtable,\n//        &lookupHandleObjectNodePtr\n//        );\n//\n//    if (handleObjectNode)\n//        return *handleObjectNode;\n//    else\n//        return NULL;\n//}\n\nVOID PhpRemoveHandleObjectNode(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context,\n    _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node\n    )\n{\n    ULONG index = 0;\n\n    //PhRemoveEntryHashtable(Context->NodeHashtable, &Node);\n\n    if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX)\n    {\n        PhRemoveItemList(Context->NodeList, index);\n    }\n\n    PhpDestroyHandleObjectNode(Node);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhpUpdateHandleObjectNode(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context,\n    _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node\n    )\n{\n    memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM);\n\n    PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nBOOLEAN NTAPI PhpHandleObjectTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_HANDLE_SEARCH_CONTEXT context = Context;\n    PPH_HANDLE_OBJECT_TREE_ROOT_NODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)getChildren->Node;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(Process),\n                    SORT_FUNCTION(Type),\n                    SORT_FUNCTION(Name),\n                    SORT_FUNCTION(Handle),\n                    SORT_FUNCTION(ObjectAddress),\n                    SORT_FUNCTION(OriginalName),\n                    SORT_FUNCTION(GrantedAccess),\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (context->TreeNewSortColumn < PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM)\n                    sortFunction = sortFunctions[context->TreeNewSortColumn];\n                else\n                    sortFunction = NULL;\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1;\n            node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1;\n            node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case PH_OBJECT_SEARCH_TREE_COLUMN_PROCESS:\n                getCellText->Text = PhGetStringRef(node->ClientIdName);\n                break;\n            case PH_OBJECT_SEARCH_TREE_COLUMN_TYPE:\n                getCellText->Text = PhGetStringRef(node->TypeNameString);\n                break;\n            case PH_OBJECT_SEARCH_TREE_COLUMN_NAME:\n                getCellText->Text = PhGetStringRef(node->BestObjectName);\n                break;\n            case PH_OBJECT_SEARCH_TREE_COLUMN_HANDLE:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->HandleString);\n                break;\n            case PH_OBJECT_SEARCH_TREE_COLUMN_OBJECTADDRESS:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->ObjectString);\n                break;\n            case PH_OBJECT_SEARCH_TREE_COLUMN_ORIGINALNAME:\n                getCellText->Text = PhGetStringRef(node->ObjectNameString);\n                break;\n            case PH_OBJECT_SEARCH_TREE_COLUMN_GRANTEDACCESS:\n                getCellText->Text = PhGetStringRef(node->GrantedAccessSymbolicText);\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)getNodeColor->Node;\n\n            if (!node)\n                ; // Dummy\n            else if (PhCsUseColorProtectedInheritHandles && FlagOn(node->HandleInfo.HandleAttributes, OBJ_PROTECT_CLOSE) && FlagOn(node->HandleInfo.HandleAttributes, OBJ_INHERIT))\n                getNodeColor->BackColor = PhCsColorProtectedInheritHandles;\n            else if (PhCsUseColorProtectedHandles && FlagOn(node->HandleInfo.HandleAttributes, OBJ_PROTECT_CLOSE))\n                getNodeColor->BackColor = PhCsColorProtectedHandles;\n            else if (PhCsUseColorInheritHandles && FlagOn(node->HandleInfo.HandleAttributes, OBJ_INHERIT))\n                getNodeColor->BackColor = PhCsColorInheritHandles;\n\n            getNodeColor->Flags = TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_COPY, 0);\n                break;\n            case VK_DELETE:\n                SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_CLOSE, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_PROPERTIES, 0);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1;\n\n            SendMessage(\n                context->WindowHandle,\n                WM_COMMAND,\n                WM_PH_SEARCH_SHOWMENU,\n                (LPARAM)contextMenuEvent\n                );\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            memset(&data, 0, sizeof(PH_TN_COLUMN_MENU_DATA));\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = PH_OBJECT_SEARCH_TREE_COLUMN_PROCESS;\n            data.DefaultSortOrder = NoSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpClearHandleObjectTree(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        PhpDestroyHandleObjectNode(Context->NodeList->Items[i]);\n\n    //PhClearHashtable(Context->NodeHashtable);\n    PhClearList(Context->NodeList);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nPPH_HANDLE_OBJECT_TREE_ROOT_NODE PhpGetSelectedHandleObjectNode(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context\n    )\n{\n    PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleNode = NULL;\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        handleNode = Context->NodeList->Items[i];\n\n        if (handleNode->Node.Selected)\n            return handleNode;\n    }\n\n    return NULL;\n}\n\n_Success_(return)\nBOOLEAN PhpGetSelectedHandleObjectNodes(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context,\n    _Out_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE **HandleObjectNodes,\n    _Out_ PULONG NumberOfHandleObjectNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_HANDLE_OBJECT_TREE_ROOT_NODE node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            PhAddItemList(list, node);\n        }\n    }\n\n    if (list->Count)\n    {\n        *HandleObjectNodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfHandleObjectNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\nVOID PhpInitializeHandleObjectTree(\n    _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context\n    )\n{\n    Context->NodeList = PhCreateList(100);\n    //Context->NodeHashtable = PhCreateHashtable(\n    //    sizeof(PPH_HANDLE_OBJECT_TREE_ROOT_NODE),\n    //    PhpHandleObjectNodeHashtableEqualFunction,\n    //    PhpHandleObjectNodeHashtableHashFunction,\n    //    100\n    //    );\n\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n    TreeNew_SetCallback(Context->TreeNewHandle, PhpHandleObjectTreeNewCallback, Context);\n\n    // Default columns\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_PROCESS, TRUE, L\"Process\", 100, PH_ALIGN_LEFT, 0, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_TYPE, TRUE, L\"Type\", 100, PH_ALIGN_LEFT, 1, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_NAME, TRUE, L\"Name\", 200, PH_ALIGN_LEFT, 2, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_HANDLE, TRUE, L\"Handle\", 80, PH_ALIGN_LEFT, 3, 0);\n    // Customizable columns\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_OBJECTADDRESS, FALSE, L\"Object address\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_ORIGINALNAME, FALSE, L\"Original name\", 200, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_GRANTEDACCESS, FALSE, L\"Granted access\", 200, PH_ALIGN_LEFT, ULONG_MAX, 0);\n\n    TreeNew_SetTriState(Context->TreeNewHandle, TRUE);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n\n    PhpHandleObjectLoadSettingsTreeList(Context);\n}\n\nVOID PhpDeleteHandleObjectTree(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context\n    )\n{\n    PhpHandleObjectSaveSettingsTreeList(Context);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PhpDestroyHandleObjectNode(Context->NodeList->Items[i]);\n    }\n\n    //PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n}\n\nVOID PhpInitializeFindObjMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE *Results,\n    _In_ ULONG NumberOfResults\n    )\n{\n    BOOLEAN allCanBeClosed = TRUE;\n    ULONG i;\n\n    if (NumberOfResults == 1)\n    {\n        PH_HANDLE_ITEM_INFO info;\n\n        info.ProcessId = Results[0]->ProcessId;\n        info.Handle = Results[0]->Handle;\n        info.TypeName = Results[0]->TypeNameString;\n        info.BestObjectName = Results[0]->BestObjectName;\n        PhInsertHandleObjectPropertiesEMenuItems(Menu, ID_OBJECT_PROPERTIES, FALSE, &info);\n    }\n    else\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n        PhEnableEMenuItem(Menu, ID_OBJECT_COPY, TRUE);\n    }\n\n    for (i = 0; i < NumberOfResults; i++)\n    {\n        if (Results[i]->ResultType != HandleSearchResult)\n        {\n            allCanBeClosed = FALSE;\n            break;\n        }\n    }\n\n    PhEnableEMenuItem(Menu, ID_OBJECT_CLOSE, allCanBeClosed);\n}\n\nstatic int __cdecl PhpStringObjectTypeCompare(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_STRING entry1 = *(PPH_STRING *)elem1;\n    PPH_STRING entry2 = *(PPH_STRING *)elem2;\n\n    return PhCompareString(entry1, entry2, TRUE);\n}\n\nVOID PhpUpdateDropdownThemeMetrics(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context,\n    _In_ LONG WindowDpi\n    )\n{\n    LONG maxLength;\n    HDC comboDc;\n    HFONT oldFont;\n    INT count;\n\n    maxLength = 0;\n    comboDc = GetDC(Context->TypeWindowHandle);\n    oldFont = SelectFont(comboDc, Context->TypeWindowFont);\n\n    count = ComboBox_GetCount(Context->TypeWindowHandle);\n\n    for (INT i = 0; i < count; i++)\n    {\n        PPH_STRING entry = PhGetComboBoxString(Context->TypeWindowHandle, i);\n        SIZE textSize;\n\n        if (GetTextExtentPoint32(comboDc, entry->Buffer, (ULONG)entry->Length / sizeof(WCHAR), &textSize))\n        {\n            if (textSize.cx > maxLength)\n                maxLength = textSize.cx;\n        }\n\n        PhDereferenceObject(entry);\n    }\n\n    if (oldFont)\n        SelectFont(comboDc, oldFont);\n\n    ReleaseDC(Context->TypeWindowHandle, comboDc);\n\n    // Add some padding for the vertical scroll bar and margins.\n    maxLength += PhGetSystemMetrics(SM_CXVSCROLL, WindowDpi) * 2;\n\n    if (maxLength)\n    {\n        SendMessage(Context->TypeWindowHandle, CB_SETDROPPEDWIDTH, maxLength, 0);\n    }\n}\n\nVOID PhpPopulateObjectTypes(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context\n    )\n{\n    POBJECT_TYPES_INFORMATION objectTypes;\n    POBJECT_TYPE_INFORMATION objectType;\n    PPH_LIST objectTypeList;\n\n    objectTypeList = PhCreateList(100);\n\n    // Add a custom object type for searching all objects.\n    ComboBox_AddString(Context->TypeWindowHandle, L\"Everything\");\n    ComboBox_SetCurSel(Context->TypeWindowHandle, 0);\n\n    // Enumerate the available object types.\n    if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes)))\n    {\n        objectType = PH_FIRST_OBJECT_TYPE(objectTypes);\n\n        for (ULONG i = 0; i < objectTypes->NumberOfTypes; i++)\n        {\n            PhAddItemList(objectTypeList, PhCreateStringFromUnicodeString(&objectType->TypeName));\n            objectType = PH_NEXT_OBJECT_TYPE(objectType);\n        }\n\n        PhFree(objectTypes);\n    }\n\n    // Sort the object types.\n    qsort(objectTypeList->Items, objectTypeList->Count, sizeof(PVOID), PhpStringObjectTypeCompare);\n\n    // Set the font, add the dropdown entries and adjust the dropdown width.\n    {\n        LONG maxLength;\n        HDC comboDc;\n        HFONT oldFont;\n\n        maxLength = 0;\n        comboDc = GetDC(Context->TypeWindowHandle);\n        oldFont = SelectFont(comboDc, Context->TypeWindowFont);\n\n        SetWindowFont(Context->TypeWindowHandle, Context->TypeWindowFont, TRUE);\n\n        for (ULONG i = 0; i < objectTypeList->Count; i++)\n        {\n            PPH_STRING entry = objectTypeList->Items[i];\n            SIZE textSize;\n\n            if (GetTextExtentPoint32(comboDc, entry->Buffer, (ULONG)entry->Length / sizeof(WCHAR), &textSize))\n            {\n                if (textSize.cx > maxLength)\n                    maxLength = textSize.cx;\n            }\n\n            ComboBox_AddString(Context->TypeWindowHandle, PhGetString(objectTypeList->Items[i]));\n            PhDereferenceObject(objectTypeList->Items[i]);\n        }\n\n        if (oldFont)\n            SelectFont(comboDc, oldFont);\n\n        ReleaseDC(Context->TypeWindowHandle, comboDc);\n\n        maxLength += PhGetSystemMetrics(SM_CXVSCROLL, PhGetWindowDpi(Context->TypeWindowHandle)) * 2;\n\n        if (maxLength)\n        {\n            SendMessage(Context->TypeWindowHandle, CB_SETDROPPEDWIDTH, maxLength, 0);\n        }\n    }\n\n    PhDereferenceObject(objectTypeList);\n}\n\nVOID PhpFindObjectAddResultEntries(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    PhAcquireQueuedLockExclusive(&Context->SearchResultsLock);\n\n    if (Context->SearchResults->Count == 0 || Context->SearchResultsAddIndex == Context->SearchResults->Count)\n    {\n        PhReleaseQueuedLockExclusive(&Context->SearchResultsLock);\n        return;\n    }\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n\n    for (i = Context->SearchResultsAddIndex; i < Context->SearchResults->Count; i++)\n    {\n        PPHP_OBJECT_SEARCH_RESULT searchResult = Context->SearchResults->Items[i];\n        CLIENT_ID clientId;\n        PPH_PROCESS_ITEM processItem;\n        PPH_HANDLE_OBJECT_TREE_ROOT_NODE objectNode;\n\n        clientId.UniqueProcess = searchResult->ProcessId;\n        clientId.UniqueThread = NULL;\n\n        processItem = PhReferenceProcessItem(clientId.UniqueProcess);\n\n        objectNode = PhpAddHandleObjectNode(Context, searchResult->Handle);\n        objectNode->ProcessId = searchResult->ProcessId;\n        objectNode->ResultType = searchResult->ResultType;\n        objectNode->ClientIdName = PhGetClientIdNameEx(&clientId, processItem ? processItem->ProcessName : NULL);\n        objectNode->TypeNameString = searchResult->TypeName;\n        objectNode->ObjectNameString = searchResult->ObjectName;\n        objectNode->BestObjectName = searchResult->BestObjectName;\n        objectNode->HandleInfo = searchResult->Info;\n        PhPrintPointer(objectNode->HandleString, searchResult->Handle);\n\n        if (searchResult->Object)\n        {\n            objectNode->HandleObject = searchResult->Object;\n            PhPrintPointer(objectNode->ObjectString, searchResult->Object);\n        }\n\n        if (searchResult->Info.GrantedAccess != 0)\n        {\n            PPH_ACCESS_ENTRY accessEntries;\n            ULONG numberOfAccessEntries;\n\n            if (PhGetAccessEntries(PhGetStringOrEmpty(searchResult->TypeName), &accessEntries, &numberOfAccessEntries))\n            {\n                objectNode->GrantedAccessSymbolicText = PhGetAccessString(searchResult->Info.GrantedAccess, accessEntries, numberOfAccessEntries);\n                PhFree(accessEntries);\n            }\n\n            if (objectNode->GrantedAccessSymbolicText)\n            {\n                WCHAR grantedAccessString[PH_PTR_STR_LEN_1];\n\n                PhPrintPointer(grantedAccessString, UlongToPtr(searchResult->Info.GrantedAccess));\n                PhMoveReference(&objectNode->GrantedAccessSymbolicText, PhFormatString(\n                    L\"%s (%s)\",\n                    PhGetString(objectNode->GrantedAccessSymbolicText),\n                    grantedAccessString\n                    ));\n            }\n        }\n\n        if (processItem)\n        {\n            PhDereferenceObject(processItem);\n        }\n    }\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n\n    Context->SearchResultsAddIndex = i;\n\n    PhReleaseQueuedLockExclusive(&Context->SearchResultsLock);\n}\n\nVOID PhpFindObjectClearResultEntries(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context\n    )\n{\n    PhpClearHandleObjectTree(Context);\n\n    Context->SearchResultsAddIndex = 0;\n\n    for (ULONG i = 0; i < Context->SearchResults->Count; i++)\n        PhFree(Context->SearchResults->Items[i]);\n\n    PhClearList(Context->SearchResults);\n}\n\nstatic BOOLEAN MatchSearchString(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context,\n    _In_ PPH_STRINGREF Input\n    )\n{\n    return PhSearchControlMatch(Context->SearchMatchHandle, Input);\n}\n\nstatic BOOLEAN MatchTypeString(\n    _In_ PPH_HANDLE_SEARCH_CONTEXT Context,\n    _In_ PPH_STRINGREF Input\n    )\n{\n    if (PhEqualString2(Context->SearchTypeString, L\"Everything\", FALSE))\n        return TRUE;\n\n    return PhEqualStringRef(Input, &Context->SearchTypeString->sr, TRUE);\n}\n\ntypedef struct _SEARCH_HANDLE_CONTEXT\n{\n    PPH_HANDLE_SEARCH_CONTEXT WindowContext;\n    BOOLEAN NeedToFree;\n    PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo;\n    HANDLE ProcessHandle;\n} SEARCH_HANDLE_CONTEXT, *PSEARCH_HANDLE_CONTEXT;\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS NTAPI SearchHandleFunction(\n    _In_ PVOID Parameter\n    )\n{\n    PSEARCH_HANDLE_CONTEXT handleContext = Parameter;\n    PPH_HANDLE_SEARCH_CONTEXT context = handleContext->WindowContext;\n    PPH_STRING typeName;\n    PPH_STRING objectName;\n    PPH_STRING bestObjectName;\n\n    if (NT_SUCCESS(PhGetHandleInformation(\n        handleContext->ProcessHandle,\n        handleContext->HandleInfo->HandleValue,\n        handleContext->HandleInfo->ObjectTypeIndex,\n        NULL,\n        &typeName,\n        &objectName,\n        &bestObjectName\n        )))\n    {\n        PPH_STRING upperObjectName;\n        PPH_STRING upperBestObjectName;\n        PPH_STRING upperTypeName;\n\n        upperObjectName = PhUpperString(objectName);\n        upperBestObjectName = PhUpperString(bestObjectName);\n        upperTypeName = PhUpperString(typeName);\n\n        if (((context->SearchAll || MatchSearchString(context, &upperObjectName->sr) || MatchSearchString(context, &upperBestObjectName->sr)) &&\n            MatchTypeString(context, &upperTypeName->sr)) ||\n            PhSearchControlMatchPointer(context->SearchMatchHandle, handleContext->HandleInfo->Object) ||\n            PhSearchControlMatchPointer(context->SearchMatchHandle, handleContext->HandleInfo->HandleValue))\n        {\n            PPHP_OBJECT_SEARCH_RESULT searchResult;\n\n            searchResult = PhAllocateZero(sizeof(PHP_OBJECT_SEARCH_RESULT));\n            searchResult->ProcessId = handleContext->HandleInfo->UniqueProcessId;\n            searchResult->ResultType = HandleSearchResult;\n            searchResult->Object = handleContext->HandleInfo->Object;\n            searchResult->Handle = handleContext->HandleInfo->HandleValue;\n            searchResult->TypeName = typeName;\n            searchResult->ObjectName = objectName;\n            searchResult->BestObjectName = bestObjectName;\n            searchResult->Info = *handleContext->HandleInfo;\n\n            PhAcquireQueuedLockExclusive(&context->SearchResultsLock);\n            PhAddItemList(context->SearchResults, searchResult);\n            PhReleaseQueuedLockExclusive(&context->SearchResultsLock);\n        }\n        else\n        {\n            PhDereferenceObject(typeName);\n            PhDereferenceObject(objectName);\n            PhDereferenceObject(bestObjectName);\n        }\n\n        PhDereferenceObject(upperTypeName);\n        PhDereferenceObject(upperBestObjectName);\n        PhDereferenceObject(upperObjectName);\n    }\n\n    if (handleContext->NeedToFree)\n        PhFree(handleContext);\n\n    return STATUS_SUCCESS;\n}\n\ntypedef struct _SEARCH_MODULE_CONTEXT\n{\n    PPH_HANDLE_SEARCH_CONTEXT WindowContext;\n    HANDLE ProcessId;\n} SEARCH_MODULE_CONTEXT, *PSEARCH_MODULE_CONTEXT;\n\n_Function_class_(PH_ENUM_GENERIC_MODULES_CALLBACK)\nstatic BOOLEAN NTAPI EnumModulesCallback(\n    _In_ PPH_MODULE_INFO Module,\n    _In_ PSEARCH_MODULE_CONTEXT Context\n    )\n{\n    PPH_HANDLE_SEARCH_CONTEXT context = Context->WindowContext;\n    PPH_STRING filenameWin32;\n    PPH_STRING upperFileName;\n    PPH_STRING upperOriginalFileName;\n\n    filenameWin32 = PhGetFileName(Module->FileName);\n    upperFileName = PhUpperString(filenameWin32);\n    upperOriginalFileName = PhUpperString(Module->FileName);\n\n    if ((\n        context->SearchAll ||\n        MatchSearchString(context, &upperFileName->sr) ||\n        MatchSearchString(context, &upperOriginalFileName->sr)) ||\n        PhSearchControlMatchPointer(context->SearchMatchHandle, Module->BaseAddress))\n    {\n        PPHP_OBJECT_SEARCH_RESULT searchResult;\n        PCWSTR typeName;\n\n        switch (Module->Type)\n        {\n        case PH_MODULE_TYPE_MAPPED_FILE:\n            typeName = L\"Mapped file\";\n            break;\n        case PH_MODULE_TYPE_MAPPED_IMAGE:\n            typeName = L\"Mapped image\";\n            break;\n        default:\n            typeName = L\"DLL\";\n            break;\n        }\n\n        searchResult = PhAllocateZero(sizeof(PHP_OBJECT_SEARCH_RESULT));\n        searchResult->ProcessId = Context->ProcessId;\n        searchResult->ResultType = (Module->Type == PH_MODULE_TYPE_MAPPED_FILE || Module->Type == PH_MODULE_TYPE_MAPPED_IMAGE) ? MappedFileSearchResult : ModuleSearchResult;\n        searchResult->Handle = Module->BaseAddress;\n        searchResult->TypeName = PhCreateString(typeName);\n        PhSetReference(&searchResult->BestObjectName, filenameWin32);\n        PhSetReference(&searchResult->ObjectName, Module->FileName);\n\n        PhAcquireQueuedLockExclusive(&context->SearchResultsLock);\n        PhAddItemList(context->SearchResults, searchResult);\n        PhReleaseQueuedLockExclusive(&context->SearchResultsLock);\n    }\n\n    PhDereferenceObject(upperOriginalFileName);\n    PhDereferenceObject(upperFileName);\n    PhDereferenceObject(filenameWin32);\n\n    return TRUE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpFindObjectsThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_HANDLE_SEARCH_CONTEXT context = Parameter;\n    NTSTATUS status = STATUS_SUCCESS;\n    PSYSTEM_HANDLE_INFORMATION_EX handles;\n    PPH_HASHTABLE processHandleHashtable;\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n    ULONG i;\n\n    // Refuse to search with no filter.\n    if (!context->SearchMatchHandle && !context->SearchAll)\n    {\n        goto CleanupExit;\n    }\n\n    status = PhEnumHandlesEx(&handles);\n\n    if (NT_SUCCESS(status))\n    {\n        static PH_INITONCE initOnce = PH_INITONCE_INIT;\n        static USHORT fileObjectTypeIndex = USHRT_MAX;\n\n        BOOLEAN useWorkQueue = FALSE;\n        PH_WORK_QUEUE workQueue;\n        processHandleHashtable = PhCreateSimpleHashtable(8);\n\n        if (KsiLevel() < KphLevelMed)\n        {\n            useWorkQueue = TRUE;\n            PhInitializeWorkQueue(&workQueue, 1, 20, 1000);\n\n            if (PhBeginInitOnce(&initOnce))\n            {\n                fileObjectTypeIndex = (USHORT)PhGetObjectTypeNumberZ(L\"File\");\n                PhEndInitOnce(&initOnce);\n            }\n        }\n\n        for (i = 0; i < handles->NumberOfHandles; i++)\n        {\n            PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = &handles->Handles[i];\n            HANDLE processHandle;\n\n            // Don't continue if the user requested cancellation.\n            if (context->SearchStop)\n                break;\n\n            // Open a handle to the process if we don't already have one.\n\n            if (!(processHandle = PhFindItemSimpleHashtable2(processHandleHashtable, handleInfo->UniqueProcessId)))\n            {\n                if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, handleInfo->UniqueProcessId)))\n                {\n                    PhAddItemSimpleHashtable(processHandleHashtable, handleInfo->UniqueProcessId, processHandle);\n                }\n                else\n                {\n                    if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, handleInfo->UniqueProcessId)))\n                    {\n                        PhAddItemSimpleHashtable(processHandleHashtable, handleInfo->UniqueProcessId, processHandle);\n                    }\n                    else\n                    {\n                        continue;\n                    }\n                }\n            }\n\n            if (useWorkQueue && handleInfo->ObjectTypeIndex == fileObjectTypeIndex)\n            {\n                PSEARCH_HANDLE_CONTEXT searchHandleContext;\n\n                searchHandleContext = PhAllocateZero(sizeof(SEARCH_HANDLE_CONTEXT));\n                searchHandleContext->WindowContext = context;\n                searchHandleContext->NeedToFree = TRUE;\n                searchHandleContext->HandleInfo = handleInfo;\n                searchHandleContext->ProcessHandle = processHandle;\n\n                PhQueueItemWorkQueue(&workQueue, SearchHandleFunction, searchHandleContext);\n            }\n            else\n            {\n                SEARCH_HANDLE_CONTEXT searchHandleContext;\n\n                searchHandleContext.WindowContext = context;\n                searchHandleContext.NeedToFree = FALSE;\n                searchHandleContext.HandleInfo = handleInfo;\n                searchHandleContext.ProcessHandle = processHandle;\n\n                SearchHandleFunction(&searchHandleContext);\n            }\n        }\n\n        if (useWorkQueue)\n        {\n            PhWaitForWorkQueue(&workQueue);\n            PhDeleteWorkQueue(&workQueue);\n        }\n\n        {\n            PPH_KEY_VALUE_PAIR entry;\n\n            i = 0;\n\n            while (PhEnumHashtable(processHandleHashtable, &entry, &i))\n            {\n                if (entry->Value)\n                {\n                    status = NtClose(entry->Value);\n\n                    if (!NT_SUCCESS(status))\n                    {\n                        PhShowStatus(NULL, L\"Unidentified third party object.\", status, 0);\n                    }\n                }\n            }\n        }\n\n        PhDereferenceObject(processHandleHashtable);\n        PhFree(handles);\n    }\n\n    if (context->SearchStop)\n        goto CleanupExit;\n\n    if (PhEqualString2(context->SearchTypeString, L\"File\", TRUE) ||\n        PhEqualString2(context->SearchTypeString, L\"Everything\", FALSE))\n    {\n        if (NT_SUCCESS(PhEnumProcesses(&processes)))\n        {\n            process = PH_FIRST_PROCESS(processes);\n\n            do\n            {\n                SEARCH_MODULE_CONTEXT searchModuleContext;\n\n                if (context->SearchStop)\n                    break;\n\n                searchModuleContext.WindowContext = context;\n                searchModuleContext.ProcessId = process->UniqueProcessId;\n\n                PhEnumGenericModules(\n                    process->UniqueProcessId,\n                    NULL,\n                    PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES,\n                    EnumModulesCallback,\n                    &searchModuleContext\n                    );\n            } while (process = PH_NEXT_PROCESS(process));\n\n            PhFree(processes);\n        }\n    }\n\nCleanupExit:\n    PostMessage(context->WindowHandle, WM_PH_SEARCH_FINISHED, status, 0);\n\n    PhDereferenceObject(context);\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpFindObjectsDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_HANDLE_SEARCH_CONTEXT context = Object;\n\n    if (context->SearchResults)\n    {\n        for (ULONG i = 0; i < context->SearchResults->Count; i++)\n            PhFree(context->SearchResults->Items[i]);\n\n        PhClearList(context->SearchResults);\n        PhClearReference(&context->SearchResults);\n    }\n\n    PhClearReference(&context->SearchTypeString);\n}\n\nPPH_HANDLE_SEARCH_CONTEXT PhCreateFindObjectContext(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_HANDLE_SEARCH_CONTEXT context;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhFindObjectsItemType = PhCreateObjectType(L\"FindObjectsItem\", 0, PhpFindObjectsDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    context = PhCreateObject(sizeof(PH_HANDLE_SEARCH_CONTEXT), PhFindObjectsItemType);\n    memset(context, 0, sizeof(PH_HANDLE_SEARCH_CONTEXT));\n\n    return context;\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhFindObjectsSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_HANDLE_SEARCH_CONTEXT context = Context;\n\n    assert(context);\n\n    context->SearchMatchHandle = MatchHandle;\n}\n\nINT_PTR CALLBACK PhFindObjectsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_HANDLE_SEARCH_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhCreateFindObjectContext();\n        PhSetDialogContext(hwndDlg, context);\n    }\n    else\n    {\n        context = PhGetDialogContext(hwndDlg);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            context->WindowHandle = hwndDlg;\n            context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_TREELIST);\n            context->TypeWindowHandle = GetDlgItem(hwndDlg, IDC_FILTERTYPE);\n            context->SearchWindowHandle = GetDlgItem(hwndDlg, IDC_FILTER);\n            context->TypeWindowFont = PhDuplicateFont(PhApplicationFont);\n            context->WindowText = PhGetWindowText(hwndDlg);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->TypeWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP);\n            PhAddLayoutItem(&context->LayoutManager, context->SearchWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL);\n\n            PhRegisterDialog(hwndDlg);\n            PhCreateSearchControl(\n                hwndDlg,\n                context->SearchWindowHandle,\n                L\"Find Handles or DLLs\",\n                PhFindObjectsSearchControlCallback,\n                context\n                );\n            PhpPopulateObjectTypes(context);\n            PhpInitializeHandleObjectTree(context);\n\n            context->MinimumSize.left = 0;\n            context->MinimumSize.top = 0;\n            context->MinimumSize.right = 300;\n            context->MinimumSize.bottom = 100;\n            MapDialogRect(hwndDlg, &context->MinimumSize);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_FIND_OBJ_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_FIND_OBJ_WINDOW_POSITION, SETTING_FIND_OBJ_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, (HWND)lParam);\n\n            PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL);\n\n            context->SearchResults = PhCreateList(128);\n            context->SearchResultsAddIndex = 0;\n\n            PhSetTimer(hwndDlg, PH_WINDOW_TIMER_DEFAULT, 1000, NULL);\n\n            Edit_SetSel(context->SearchWindowHandle, 0, -1);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveDialogContext(hwndDlg);\n\n            context->SearchStop = TRUE;\n\n            PhKillTimer(hwndDlg, PH_WINDOW_TIMER_DEFAULT);\n\n            if (context->SearchThreadHandle)\n            {\n                NtWaitForSingleObject(context->SearchThreadHandle, FALSE, NULL);\n                NtClose(context->SearchThreadHandle);\n                context->SearchThreadHandle = NULL;\n            }\n\n            PhSaveWindowPlacementToSetting(SETTING_FIND_OBJ_WINDOW_POSITION, SETTING_FIND_OBJ_WINDOW_SIZE, hwndDlg);\n\n            PhUnregisterWindowCallback(hwndDlg);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhpDeleteHandleObjectTree(context);\n\n            if (context->WindowText)\n                PhDereferenceObject(context->WindowText);\n            if (context->TypeWindowFont)\n                DeleteFont(context->TypeWindowFont);\n\n            PhDereferenceObject(context);\n\n            PostQuitMessage(0);\n        }\n        break;\n    case WM_PH_SEARCH_SHOWDIALOG:\n        {\n            if (IsMinimized(hwndDlg))\n                ShowWindow(hwndDlg, SW_RESTORE);\n            else\n                ShowWindow(hwndDlg, SW_SHOW);\n\n            SetForegroundWindow(hwndDlg);\n        }\n        break;\n    case WM_SETCURSOR:\n        {\n            if (context->SearchThreadHandle)\n            {\n                PhSetCursor(PhLoadCursor(NULL, IDC_APPSTARTING));\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            if (GET_WM_COMMAND_HWND(wParam, lParam) == context->TypeWindowHandle)\n            {\n                switch (GET_WM_COMMAND_CMD(wParam, lParam))\n                {\n                case CBN_SELCHANGE:\n                    {\n                        // Change focus from the dropdown list to the searchbox.\n                        SetFocus(context->SearchWindowHandle);\n                    }\n                    break;\n                }\n            }\n\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDOK:\n                {\n                    // Don't continue if the user requested cancellation.\n                    if (context->SearchStop)\n                        break;\n\n                    // Restore the original window title. (dmex)\n                    PhSetWindowText(hwndDlg, PhGetStringOrEmpty(context->WindowText));\n\n                    if (!context->SearchThreadHandle)\n                    {\n                        // Setup search parameters.\n\n                        context->SearchAll = !!PhIsNullOrEmptyString(PhaGetWindowText(context->SearchWindowHandle));\n                        PhMoveReference(&context->SearchTypeString, PhGetWindowText(context->TypeWindowHandle));\n\n                        // Clean up previous results.\n\n                        PhpFindObjectClearResultEntries(context);\n\n                        // Start the search.\n\n                        PhReferenceObject(context);\n\n                        if (!NT_SUCCESS(PhCreateThreadEx(&context->SearchThreadHandle, PhpFindObjectsThreadStart, context)))\n                        {\n                            PhDereferenceObject(context);\n                            break;\n                        }\n\n                        PhSetDialogItemText(hwndDlg, IDOK, L\"Cancel\");\n\n                        PhSetCursor(PhLoadCursor(NULL, IDC_APPSTARTING));\n                    }\n                    else\n                    {\n                        context->SearchStop = TRUE;\n                        EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);\n                    }\n                }\n                break;\n            case IDCANCEL:\n                {\n                    DestroyWindow(hwndDlg);\n                }\n                break;\n            case WM_PH_SEARCH_SHOWMENU:\n                {\n                    PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM selectedItem;\n                    PPH_HANDLE_OBJECT_TREE_ROOT_NODE *handleObjectNodes = NULL;\n                    ULONG numberOfHandleObjectNodes = 0;\n\n                    if (!PhpGetSelectedHandleObjectNodes(context, &handleObjectNodes, &numberOfHandleObjectNodes))\n                        break;\n\n                    if (numberOfHandleObjectNodes != 0)\n                    {\n                        menu = PhCreateEMenu();\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_OBJECT_CLOSE, L\"C&lose\\bDel\", NULL, NULL), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_OBJECT_GOTOOWNINGPROCESS, L\"Go to &process...\", NULL, NULL), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_OBJECT_PROPERTIES, L\"Prope&rties\", NULL, NULL), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_OBJECT_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n                        PhInsertCopyCellEMenuItem(menu, ID_OBJECT_COPY, context->TreeNewHandle, contextMenuEvent->Column);\n                        PhSetFlagsEMenuItem(menu, ID_OBJECT_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n                        PhpInitializeFindObjMenu(menu, handleObjectNodes, numberOfHandleObjectNodes);\n\n                        selectedItem = PhShowEMenu(\n                            menu,\n                            hwndDlg,\n                            PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                            contextMenuEvent->Location.x,\n                            contextMenuEvent->Location.y\n                            );\n\n                        if (selectedItem && selectedItem->Id != ULONG_MAX)\n                        {\n                            PhHandleCopyCellEMenuItem(selectedItem);\n                        }\n\n                        PhDestroyEMenu(menu);\n                    }\n\n                    PhFree(handleObjectNodes);\n                }\n                break;\n            case ID_OBJECT_CLOSE:\n                {\n                    PPH_HANDLE_OBJECT_TREE_ROOT_NODE *handleObjectNodes = NULL;\n                    ULONG numberOfHandleObjectNodes = 0;\n                    BOOLEAN allCanBeClosed = TRUE;\n\n                    if (!PhpGetSelectedHandleObjectNodes(context, &handleObjectNodes, &numberOfHandleObjectNodes))\n                        break;\n\n                    // Check the item called by TreeNewKeyDown is valid (dmex)\n                    for (ULONG i = 0; i < numberOfHandleObjectNodes; i++)\n                    {\n                        if (handleObjectNodes[i]->ResultType != HandleSearchResult)\n                        {\n                            allCanBeClosed = FALSE;\n                            break;\n                        }\n                    }\n\n                    if (!allCanBeClosed)\n                        break;\n\n                    if (numberOfHandleObjectNodes != 0 && PhShowConfirmMessage(\n                        hwndDlg,\n                        L\"close\",\n                        numberOfHandleObjectNodes == 1 ? L\"the selected handle\" : L\"the selected handles\",\n                        L\"Closing handles may cause system instability and data corruption.\",\n                        FALSE\n                        ))\n                    {\n                        for (ULONG i = 0; i < numberOfHandleObjectNodes; i++)\n                        {\n                            NTSTATUS status;\n                            HANDLE processHandle;\n\n                            if (handleObjectNodes[i]->ResultType != HandleSearchResult)\n                                continue;\n\n                            if (WindowsVersion >= WINDOWS_10)\n                            {\n                                if (NT_SUCCESS(PhOpenProcess(\n                                    &processHandle,\n                                    PROCESS_QUERY_INFORMATION,\n                                    handleObjectNodes[i]->ProcessId\n                                    )))\n                                {\n                                    BOOLEAN critical = FALSE;\n                                    BOOLEAN strict = FALSE;\n                                    BOOLEAN breakOnTermination;\n                                    PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;\n\n                                    if (NT_SUCCESS(PhGetProcessBreakOnTermination(\n                                        processHandle,\n                                        &breakOnTermination\n                                        )))\n                                    {\n                                        if (breakOnTermination)\n                                        {\n                                            critical = TRUE;\n                                        }\n                                    }\n\n                                    policyInfo.Policy = ProcessStrictHandleCheckPolicy;\n                                    policyInfo.StrictHandleCheckPolicy.Flags = 0;\n\n                                    if (NT_SUCCESS(NtQueryInformationProcess(\n                                        processHandle,\n                                        ProcessMitigationPolicy,\n                                        &policyInfo,\n                                        sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),\n                                        NULL\n                                        )))\n                                    {\n                                        if (policyInfo.StrictHandleCheckPolicy.Flags != 0)\n                                        {\n                                            strict = TRUE;\n                                        }\n                                    }\n\n                                    NtClose(processHandle);\n\n                                    if (critical && strict)\n                                    {\n                                        if (!PhShowConfirmMessage(\n                                            hwndDlg,\n                                            L\"close\",\n                                            L\"critical handle(s)\",\n                                            L\"You are about to close one or more handles for a critical process with strict handle checks enabled. This will shut down the operating system immediately.\\r\\n\\r\\n\",\n                                            TRUE\n                                            ))\n                                        {\n                                            continue;\n                                        }\n                                    }\n                                }\n                            }\n\n                            if (NT_SUCCESS(status = PhOpenProcess(\n                                &processHandle,\n                                PROCESS_DUP_HANDLE,\n                                handleObjectNodes[i]->ProcessId\n                                )))\n                            {\n                                if (NT_SUCCESS(status = NtDuplicateObject(\n                                    processHandle,\n                                    handleObjectNodes[i]->Handle,\n                                    NULL,\n                                    NULL,\n                                    0,\n                                    0,\n                                    DUPLICATE_CLOSE_SOURCE\n                                    )))\n                                {\n                                    if (handleObjectNodes[i]->HandleInfo.HandleAttributes & OBJ_PROTECT_CLOSE)\n                                        status = STATUS_HANDLE_NOT_CLOSABLE;\n                                    else\n                                        PhpRemoveHandleObjectNode(context, handleObjectNodes[i]);\n                                }\n\n                                NtClose(processHandle);\n                            }\n\n                            if (!NT_SUCCESS(status))\n                            {\n                                if (!PhShowContinueStatus(hwndDlg,\n                                    PhaFormatString(L\"Unable to close \\\"%s\\\"\", PhGetStringOrDefault(handleObjectNodes[i]->BestObjectName, L\"??\"))->Buffer,\n                                    status,\n                                    0\n                                    ))\n                                    break;\n                            }\n                        }\n                    }\n\n                    PhFree(handleObjectNodes);\n                }\n                break;\n            case ID_HANDLE_OBJECTPROPERTIES1:\n            case ID_HANDLE_OBJECTPROPERTIES2:\n                {\n                    PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode;\n\n                    if (handleObjectNode = PhpGetSelectedHandleObjectNode(context))\n                    {\n                        PH_HANDLE_ITEM_INFO info;\n\n                        info.ProcessId = handleObjectNode->ProcessId;\n                        info.Handle = handleObjectNode->Handle;\n                        info.TypeName = handleObjectNode->TypeNameString;\n                        info.BestObjectName = handleObjectNode->BestObjectName;\n\n                        if (GET_WM_COMMAND_ID(wParam, lParam) == ID_HANDLE_OBJECTPROPERTIES1)\n                            PhShowHandleObjectProperties1(hwndDlg, &info);\n                        else\n                            PhShowHandleObjectProperties2(hwndDlg, &info);\n                    }\n                }\n                break;\n            case ID_OBJECT_GOTOOWNINGPROCESS:\n                {\n                    PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode;\n\n                    if (handleObjectNode = PhpGetSelectedHandleObjectNode(context))\n                    {\n                        PPH_PROCESS_NODE processNode;\n\n                        if (processNode = PhFindProcessNode(handleObjectNode->ProcessId))\n                        {\n                            SystemInformer_SelectTabPage(0);\n                            SystemInformer_SelectProcessNode(processNode);\n                            SystemInformer_ToggleVisible(TRUE);\n                        }\n                        else\n                        {\n                            PhShowStatus(hwndDlg, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n                        }\n                    }\n                }\n                break;\n            case ID_OBJECT_PROPERTIES:\n                {\n                    PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode;\n\n                    if (handleObjectNode = PhpGetSelectedHandleObjectNode(context))\n                    {\n                        if (handleObjectNode->ResultType == HandleSearchResult)\n                        {\n                            PPH_HANDLE_ITEM handleItem;\n\n                            handleItem = PhCreateHandleItem(&handleObjectNode->HandleInfo);\n\n                            if (!PhIsNullOrEmptyString(handleObjectNode->TypeNameString))\n                                handleItem->TypeName = PhReferenceObject(handleObjectNode->TypeNameString);\n\n                            if (!PhIsNullOrEmptyString(handleObjectNode->ObjectNameString))\n                                handleItem->ObjectName = PhReferenceObject(handleObjectNode->ObjectNameString);\n\n                            if (!PhIsNullOrEmptyString(handleObjectNode->BestObjectName))\n                                handleItem->BestObjectName = PhReferenceObject(handleObjectNode->BestObjectName);\n\n                            PhShowHandleProperties(\n                                hwndDlg,\n                                handleObjectNode->ProcessId,\n                                handleItem\n                                );\n                            PhDereferenceObject(handleItem);\n                        }\n                        else\n                        {\n                            // DLL or Mapped File. Just show file properties.\n                            PhShellProperties(hwndDlg, handleObjectNode->BestObjectName->Buffer);\n                        }\n                    }\n                }\n                break;\n            case ID_OBJECT_COPY:\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(context->TreeNewHandle, 0);\n                    PhSetClipboardString(context->TreeNewHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n\n            PhpUpdateDropdownThemeMetrics(context, LOWORD(wParam));\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom);\n        }\n        break;\n    case WM_TIMER:\n        {\n            switch (wParam)\n            {\n            case PH_WINDOW_TIMER_DEFAULT:\n                {\n                    if (!context->SearchThreadHandle)\n                        break;\n\n                    // Update the search results.\n                    PhpFindObjectAddResultEntries(context);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_PH_SEARCH_FINISHED:\n        {\n            // Add any un-added items.\n            PhpFindObjectAddResultEntries(context);\n\n            // Add the result count to the window title. (dmex)\n            PhSetWindowText(hwndDlg, PhaFormatString(\n                L\"%s (%lu results)\",\n                PhGetStringOrEmpty(context->WindowText),\n                context->SearchResultsAddIndex\n                )->Buffer);\n\n            NtWaitForSingleObject(context->SearchThreadHandle, FALSE, NULL);\n            NtClose(context->SearchThreadHandle);\n            context->SearchThreadHandle = NULL;\n            context->SearchStop = FALSE;\n\n            PhSetDialogItemText(hwndDlg, IDOK, L\"Find\");\n            EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);\n            PhSetCursor(PhLoadCursor(NULL, IDC_ARROW));\n\n            if ((NTSTATUS)wParam == STATUS_INSUFFICIENT_RESOURCES)\n            {\n                PhShowWarning2(\n                    hwndDlg,\n                    L\"Unable to search for handles because the total number of handles on the system is too large.\",\n                    L\"%s\",\n                    L\"Please check if there are any processes with an extremely large number of handles open.\"\n                    );\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpFindObjectsDialogThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    BOOL result;\n    MSG message;\n    PH_AUTO_POOL autoPool;\n\n    PhInitializeAutoPool(&autoPool);\n\n    PhFindObjectsWindowHandle = PhCreateDialog(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_FINDOBJECTS),\n        NULL,\n        PhFindObjectsDlgProc,\n        Parameter\n        );\n\n    PhSetEvent(&PhFindObjectsInitializedEvent);\n\n    while (result = GetMessage(&message, NULL, 0, 0))\n    {\n        if (result == INT_ERROR)\n            break;\n\n        if (!IsDialogMessage(PhFindObjectsWindowHandle, &message))\n        {\n            TranslateMessage(&message);\n            DispatchMessage(&message);\n        }\n\n        PhDrainAutoPool(&autoPool);\n    }\n\n    PhDeleteAutoPool(&autoPool);\n    PhResetEvent(&PhFindObjectsInitializedEvent);\n\n    if (PhFindObjectsThreadHandle)\n    {\n        NtClose(PhFindObjectsThreadHandle);\n        PhFindObjectsThreadHandle = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhShowFindObjectsDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    if (!PhFindObjectsThreadHandle)\n    {\n        if (!NT_SUCCESS(PhCreateThreadEx(&PhFindObjectsThreadHandle, PhpFindObjectsDialogThreadStart, ParentWindowHandle)))\n        {\n            PhShowStatus(ParentWindowHandle, L\"Unable to create the window.\", 0, ERROR_OUTOFMEMORY);\n            return;\n        }\n\n        PhWaitForEvent(&PhFindObjectsInitializedEvent, NULL);\n    }\n\n    PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_SHOWDIALOG, 0, 0);\n}\n"
  },
  {
    "path": "SystemInformer/gdihndl.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2021-2023\n *\n */\n\n#include <phapp.h>\n#include <procprv.h>\n#include <phsettings.h>\n#include <emenu.h>\n\n#include <ntgdi.h>\n\ntypedef struct _PH_GDI_HANDLES_CONTEXT\n{\n    HWND ListViewHandle;\n    HWND ParentWindowHandle;\n    PPH_PROCESS_ITEM ProcessItem;\n    PPH_LIST List;\n    PH_LAYOUT_MANAGER LayoutManager;\n} PH_GDI_HANDLES_CONTEXT, *PPH_GDI_HANDLES_CONTEXT;\n\ntypedef struct _PH_GDI_HANDLE_ITEM\n{\n    PGDI_HANDLE_ENTRY Entry;\n    ULONG Handle;\n    PVOID Object;\n    PCWSTR TypeName;\n    PPH_STRING Information;\n} PH_GDI_HANDLE_ITEM, *PPH_GDI_HANDLE_ITEM;\n\nINT_PTR CALLBACK PhpGdiHandlesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowGdiHandlesDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_GDI_HANDLES_CONTEXT context;\n    HWND windowHandle;\n\n    context = PhAllocateZero(sizeof(PH_GDI_HANDLES_CONTEXT));\n    context->ProcessItem = PhReferenceObject(ProcessItem);\n    context->List = PhCreateList(20);\n    context->ParentWindowHandle = ParentWindowHandle;\n\n    windowHandle = PhCreateDialog(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_GDIHANDLES),\n        PhCsForceNoParent ? NULL : ParentWindowHandle,\n        PhpGdiHandlesDlgProc,\n        context\n        );\n\n    ShowWindow(windowHandle, SW_SHOW);\n    SetForegroundWindow(windowHandle);\n}\n\nPCWSTR PhpGetGdiHandleTypeName(\n    _In_ ULONG Unique\n    )\n{\n    switch (GDI_CLIENT_TYPE_FROM_UNIQUE(Unique))\n    {\n    case GDI_CLIENT_ALTDC_TYPE:\n        return L\"Alt. DC\";\n    case GDI_CLIENT_BITMAP_TYPE:\n        return L\"Bitmap\";\n    case GDI_CLIENT_BRUSH_TYPE:\n        return L\"Brush\";\n    case GDI_CLIENT_CLIENTOBJ_TYPE:\n        return L\"Client Object\";\n    case GDI_CLIENT_DIBSECTION_TYPE:\n        return L\"DIB Section\";\n    case GDI_CLIENT_DC_TYPE:\n        return L\"DC\";\n    case GDI_CLIENT_EXTPEN_TYPE:\n        return L\"ExtPen\";\n    case GDI_CLIENT_FONT_TYPE:\n        return L\"Font\";\n    case GDI_CLIENT_METADC16_TYPE:\n        return L\"Metafile DC\";\n    case GDI_CLIENT_METAFILE_TYPE:\n        return L\"Enhanced Metafile\";\n    case GDI_CLIENT_METAFILE16_TYPE:\n        return L\"Metafile\";\n    case GDI_CLIENT_PALETTE_TYPE:\n        return L\"Palette\";\n    case GDI_CLIENT_PEN_TYPE:\n        return L\"Pen\";\n    case GDI_CLIENT_REGION_TYPE:\n        return L\"Region\";\n    default:\n        return NULL;\n    }\n}\n\nPPH_STRING PhpGetGdiHandleInformation(\n    _In_ ULONG Handle\n    )\n{\n    HGDIOBJ handle;\n\n    handle = (HGDIOBJ)UlongToPtr(Handle);\n\n    switch (GDI_CLIENT_TYPE_FROM_HANDLE(Handle))\n    {\n    case GDI_CLIENT_BITMAP_TYPE:\n    case GDI_CLIENT_DIBSECTION_TYPE:\n        {\n            BITMAP bitmap;\n\n            if (GetObject(handle, sizeof(BITMAP), &bitmap))\n            {\n                return PhFormatString(\n                    L\"Width: %u, Height: %u, Depth: %u\",\n                    bitmap.bmWidth,\n                    bitmap.bmHeight,\n                    bitmap.bmBitsPixel\n                    );\n            }\n        }\n        break;\n    case GDI_CLIENT_BRUSH_TYPE:\n        {\n            LOGBRUSH brush;\n\n            if (GetObject(handle, sizeof(LOGBRUSH), &brush))\n            {\n                return PhFormatString(\n                    L\"Style: %u, Color: 0x%08x, Hatch: 0x%Ix\",\n                    brush.lbStyle,\n                    _byteswap_ulong(brush.lbColor),\n                    brush.lbHatch\n                    );\n            }\n        }\n        break;\n    case GDI_CLIENT_EXTPEN_TYPE:\n        {\n            EXTLOGPEN pen;\n\n            if (GetObject(handle, sizeof(EXTLOGPEN), &pen))\n            {\n                return PhFormatString(\n                    L\"Style: 0x%x, Width: %u, Color: 0x%08x\",\n                    pen.elpPenStyle,\n                    pen.elpWidth,\n                    _byteswap_ulong(pen.elpColor)\n                    );\n            }\n        }\n        break;\n    case GDI_CLIENT_FONT_TYPE:\n        {\n            LOGFONT font;\n\n            if (GetObject(handle, sizeof(LOGFONT), &font))\n            {\n                return PhFormatString(\n                    L\"Face: %s, Height: %d\",\n                    font.lfFaceName,\n                    font.lfHeight\n                    );\n            }\n        }\n        break;\n    case GDI_CLIENT_PALETTE_TYPE:\n        {\n            USHORT count;\n\n            if (GetObject(handle, sizeof(USHORT), &count))\n            {\n                return PhFormatString(\n                    L\"Entries: %u\",\n                    (ULONG)count\n                    );\n            }\n        }\n        break;\n    case GDI_CLIENT_PEN_TYPE:\n        {\n            LOGPEN pen;\n\n            if (GetObject(handle, sizeof(LOGPEN), &pen))\n            {\n                return PhFormatString(\n                    L\"Style: %u, Width: %u, Color: 0x%08x\",\n                    pen.lopnStyle,\n                    pen.lopnWidth.x,\n                    _byteswap_ulong(pen.lopnColor)\n                    );\n            }\n        }\n        break;\n    }\n\n    return NULL;\n}\n\nVOID PhpRefreshGdiHandles(\n    _In_ PPH_GDI_HANDLES_CONTEXT Context\n    )\n{\n    ULONG i;\n    PGDI_SHARED_MEMORY gdiShared;\n    USHORT processId;\n    ULONG handleCount;\n    PGDI_HANDLE_ENTRY handle;\n    PPH_GDI_HANDLE_ITEM gdiHandleItem;\n    MEMORY_BASIC_INFORMATION basicInfo;\n\n    memset(&basicInfo, 0, sizeof(MEMORY_BASIC_INFORMATION));\n\n    ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE);\n    ListView_DeleteAllItems(Context->ListViewHandle);\n\n    for (i = 0; i < Context->List->Count; i++)\n    {\n        gdiHandleItem = Context->List->Items[i];\n\n        if (gdiHandleItem->Information)\n            PhDereferenceObject(gdiHandleItem->Information);\n\n        PhFree(Context->List->Items[i]);\n        Context->List->Items[i] = NULL;\n    }\n\n    PhClearList(Context->List);\n\n    gdiShared = (PGDI_SHARED_MEMORY)NtCurrentPeb()->GdiSharedHandleTable;\n    processId = (USHORT)HandleToUlong(Context->ProcessItem->ProcessId);\n    handleCount = GDI_MAX_HANDLE_COUNT;\n\n    if (NT_SUCCESS(NtQueryVirtualMemory(\n        NtCurrentProcess(),\n        gdiShared,\n        MemoryBasicInformation,\n        &basicInfo,\n        sizeof(MEMORY_BASIC_INFORMATION),\n        NULL\n        )))\n    {\n        handleCount = (ULONG)(basicInfo.RegionSize / sizeof(GDI_HANDLE_ENTRY));\n        handleCount = __min(GDI_MAX_HANDLE_COUNT, handleCount);\n    }\n\n    for (i = 0; i < handleCount; i++)\n    {\n        PCWSTR typeName;\n        LONG lvItemIndex;\n        WCHAR pointer[PH_PTR_STR_LEN_1];\n\n        handle = &gdiShared->Handles[i];\n\n        if (handle->Owner.ProcessId != processId)\n            continue;\n\n        typeName = PhpGetGdiHandleTypeName(handle->Unique);\n\n        if (!typeName)\n            continue;\n\n        gdiHandleItem = PhAllocateZero(sizeof(PH_GDI_HANDLE_ITEM));\n        gdiHandleItem->Entry = handle;\n        gdiHandleItem->Handle = GDI_MAKE_HANDLE(i, handle->Unique);\n        gdiHandleItem->Object = handle->Object;\n        gdiHandleItem->TypeName = typeName;\n        gdiHandleItem->Information = PhpGetGdiHandleInformation(gdiHandleItem->Handle);\n        PhAddItemList(Context->List, gdiHandleItem);\n\n        lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, gdiHandleItem->TypeName, gdiHandleItem);\n        PhPrintPointer(pointer, UlongToPtr(gdiHandleItem->Handle));\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, pointer);\n        PhPrintPointer(pointer, gdiHandleItem->Object);\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, pointer);\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 3, PhGetString(gdiHandleItem->Information));\n    }\n\n    ExtendedListView_SortItems(Context->ListViewHandle);\n    ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE);\n}\n\nLONG NTAPI PhpGdiHandleHandleCompareFunction(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_GDI_HANDLE_ITEM item1 = Item1;\n    PPH_GDI_HANDLE_ITEM item2 = Item2;\n\n    return uintcmp(item1->Handle, item2->Handle);\n}\n\nLONG NTAPI PhpGdiHandleObjectCompareFunction(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_GDI_HANDLE_ITEM item1 = Item1;\n    PPH_GDI_HANDLE_ITEM item2 = Item2;\n\n    return uintptrcmp((ULONG_PTR)item1->Object, (ULONG_PTR)item2->Object);\n}\n\nINT_PTR CALLBACK PhpGdiHandlesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_GDI_HANDLES_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_GDI_HANDLES_CONTEXT)lParam;\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhCenterWindow(hwndDlg, context->ParentWindowHandle);\n\n            PhRegisterDialog(hwndDlg);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n\n            PhSetListViewStyle(context->ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 100, L\"Type\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 80, L\"Handle\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 102, L\"Object\");\n            PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 200, L\"Information\");\n\n            PhSetExtendedListView(context->ListViewHandle);\n            ExtendedListView_SetCompareFunction(context->ListViewHandle, 1, PhpGdiHandleHandleCompareFunction);\n            ExtendedListView_SetCompareFunction(context->ListViewHandle, 2, PhpGdiHandleObjectCompareFunction);\n            ExtendedListView_AddFallbackColumn(context->ListViewHandle, 0);\n            ExtendedListView_AddFallbackColumn(context->ListViewHandle, 1);\n\n            {\n                PPH_STRING windowTitle;\n\n                windowTitle = PhGetWindowText(hwndDlg);\n                PhMoveReference(&windowTitle, PhFormatString(\n                    L\"%s: %s (%lu)\",\n                    PhGetStringOrEmpty(windowTitle),\n                    PhGetStringOrEmpty(context->ProcessItem->ProcessName),\n                    HandleToUlong(context->ProcessItem->ProcessId)\n                    ));\n\n                PhSetWindowText(hwndDlg, PhGetStringOrEmpty(windowTitle));\n                PhDereferenceObject(windowTitle);\n            }\n\n            PhpRefreshGdiHandles(context);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhUnregisterDialog(hwndDlg);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            if (context->List)\n            {\n                for (ULONG i = 0; i < context->List->Count; i++)\n                {\n                    PPH_GDI_HANDLE_ITEM gdiHandleItem = context->List->Items[i];\n\n                    if (gdiHandleItem->Information)\n                        PhDereferenceObject(gdiHandleItem->Information);\n\n                    PhFree(context->List->Items[i]);\n                    context->List->Items[i] = NULL;\n                }\n\n                PhDereferenceObject(context->List);\n            }\n\n            if (context->ProcessItem)\n            {\n                PhDereferenceObject(context->ProcessItem);\n            }\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n            PhFree(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                DestroyWindow(hwndDlg);\n                break;\n            case IDC_REFRESH:\n                PhpRefreshGdiHandles(context);\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID* listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        if (!PhHandleCopyListViewEMenuItem(item))\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                PhCopyListView(context->ListViewHandle);\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/heapinfo.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *     dmex    2020-2023\n *\n */\n\n#include <phapp.h>\n#include <phsvccl.h>\n#include <actions.h>\n#include <emenu.h>\n#include <procprv.h>\n#include <settings.h>\n#include <phsettings.h>\n\ntypedef struct _PH_PROCESS_HEAPS_CONTEXT\n{\n    HWND WindowHandle;\n    HWND ParentWindowHandle;\n    HWND ListViewHandle;\n    HFONT BoldFont;\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN Initialized : 1;\n            BOOLEAN IsWow64Process : 1;\n            BOOLEAN Spare : 6;\n        };\n    };\n    PPH_PROCESS_ITEM ProcessItem;\n    PVOID ProcessHeap;\n    PVOID DebugBuffer;\n    PH_LAYOUT_MANAGER LayoutManager;\n} PH_PROCESS_HEAPS_CONTEXT, *PPH_PROCESS_HEAPS_CONTEXT;\n\ntypedef struct _HEAP_COUNTERS\n{\n    ULONG_PTR TotalMemoryReserved;\n    ULONG_PTR TotalMemoryCommitted;\n    ULONG_PTR TotalMemoryLargeUCR;\n    ULONG_PTR TotalSizeInVirtualBlocks;\n    ULONG TotalSegments;\n    ULONG TotalUCRs;\n    ULONG CommittOps;\n    ULONG DeCommitOps;\n    ULONG LockAcquires;\n    ULONG LockCollisions;\n    ULONG CommitRate;\n    ULONG DecommittRate;\n    ULONG CommitFailures;\n    ULONG InBlockCommitFailures;\n    ULONG PollIntervalCounter;\n    ULONG DecommitsSinceLastCheck;\n    ULONG HeapPollInterval;\n    ULONG AllocAndFreeOps;\n    ULONG AllocationIndicesActive;\n    ULONG InBlockDeccommits;\n    ULONG_PTR InBlockDeccomitSize;\n    ULONG_PTR HighWatermarkSize;\n    ULONG_PTR LastPolledSize;\n} HEAP_COUNTERS, *PHEAP_COUNTERS;\n\ntypedef struct _HEAP_COUNTERS32\n{\n    ULONG TotalMemoryReserved;\n    ULONG TotalMemoryCommitted;\n    ULONG TotalMemoryLargeUCR;\n    ULONG TotalSizeInVirtualBlocks;\n    ULONG TotalSegments;\n    ULONG TotalUCRs;\n    ULONG CommittOps;\n    ULONG DeCommitOps;\n    ULONG LockAcquires;\n    ULONG LockCollisions;\n    ULONG CommitRate;\n    ULONG DecommittRate;\n    ULONG CommitFailures;\n    ULONG InBlockCommitFailures;\n    ULONG PollIntervalCounter;\n    ULONG DecommitsSinceLastCheck;\n    ULONG HeapPollInterval;\n    ULONG AllocAndFreeOps;\n    ULONG AllocationIndicesActive;\n    ULONG InBlockDeccommits;\n    ULONG InBlockDeccomitSize;\n    ULONG HighWatermarkSize;\n    ULONG LastPolledSize;\n} HEAP_COUNTERS32, *PHEAP_COUNTERS32;\n\ntypedef struct _HEAP_OPPORTUNISTIC_LARGE_PAGE_STATS\n{\n    ULONG_PTR SmallPagesInUseWithinLarge;\n    ULONG_PTR OpportunisticLargePageCount;\n} HEAP_OPPORTUNISTIC_LARGE_PAGE_STATS, *PHEAP_OPPORTUNISTIC_LARGE_PAGE_STATS;\n\ntypedef struct _HEAP_OPPORTUNISTIC_LARGE_PAGE_STATS32\n{\n    ULONG SmallPagesInUseWithinLarge;\n    ULONG OpportunisticLargePageCount;\n} HEAP_OPPORTUNISTIC_LARGE_PAGE_STATS32, *PHEAP_OPPORTUNISTIC_LARGE_PAGE_STATS32;\n\ntypedef struct _HEAP_RUNTIME_MEMORY_STATS\n{\n    ULONG_PTR TotalReservedPages;\n    ULONG_PTR TotalCommittedPages;\n    ULONG_PTR FreeCommittedPages;\n    ULONG_PTR LfhFreeCommittedPages;\n    HEAP_OPPORTUNISTIC_LARGE_PAGE_STATS LargePageStats[2];\n    //RTL_HP_SEG_ALLOC_POLICY LargePageUtilizationPolicy;\n} HEAP_RUNTIME_MEMORY_STATS, *PHEAP_RUNTIME_MEMORY_STATS;\n\ntypedef struct _HEAP_RUNTIME_MEMORY_STATS32\n{\n    ULONG TotalReservedPages;\n    ULONG TotalCommittedPages;\n    ULONG FreeCommittedPages;\n    ULONG LfhFreeCommittedPages;\n    HEAP_OPPORTUNISTIC_LARGE_PAGE_STATS32 LargePageStats[2];\n    //RTL_HP_SEG_ALLOC_POLICY32 LargePageUtilizationPolicy;\n} HEAP_RUNTIME_MEMORY_STATS32, *PHEAP_RUNTIME_MEMORY_STATS32;\n\nNTSTATUS PhGetProcessDefaultHeap(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID *Heap\n    );\n\nNTSTATUS PhGetProcessHeapSignature(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID HeapAddress,\n    _In_ ULONG IsWow64Process,\n    _Out_ ULONG* HeapSignature\n    );\n\nINT_PTR CALLBACK PhpProcessHeapsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowProcessHeapsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_PROCESS_HEAPS_CONTEXT context;\n\n    context = PhAllocateZero(sizeof(PH_PROCESS_HEAPS_CONTEXT));\n    context->ParentWindowHandle = ParentWindowHandle;\n    context->ProcessItem = PhReferenceObject(ProcessItem);\n    context->IsWow64Process = !!ProcessItem->IsWow64Process;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_HEAPS),\n        NULL,\n        PhpProcessHeapsDlgProc,\n        context\n        );\n}\n\nstatic INT NTAPI PhpHeapAddressCompareFunction(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_ PVOID Context\n    )\n{\n    PPH_PROCESS_HEAPS_CONTEXT context = Context;\n\n    if (context->IsWow64Process)\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo1 = Item1;\n        PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo2 = Item2;\n\n        return uintptrcmp((ULONG_PTR)heapInfo1->BaseAddress, (ULONG_PTR)heapInfo2->BaseAddress);\n    }\n    else\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo1 = Item1;\n        PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo2 = Item2;\n\n        return uintptrcmp((ULONG_PTR)heapInfo1->BaseAddress, (ULONG_PTR)heapInfo2->BaseAddress);\n    }\n}\n\nstatic INT NTAPI PhpHeapUsedCompareFunction(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_ PVOID Context\n    )\n{\n    PPH_PROCESS_HEAPS_CONTEXT context = Context;\n\n    if (context->IsWow64Process)\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo1 = Item1;\n        PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo2 = Item2;\n\n        return uintptrcmp(heapInfo1->BytesAllocated, heapInfo2->BytesAllocated);\n    }\n    else\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo1 = Item1;\n        PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo2 = Item2;\n\n        return uintptrcmp(heapInfo1->BytesAllocated, heapInfo2->BytesAllocated);\n    }\n}\n\nstatic INT NTAPI PhpHeapCommittedCompareFunction(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_ PVOID Context\n    )\n{\n    PPH_PROCESS_HEAPS_CONTEXT context = Context;\n\n    if (context->IsWow64Process)\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo1 = Item1;\n        PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo2 = Item2;\n\n        return uintptrcmp(heapInfo1->BytesCommitted, heapInfo2->BytesCommitted);\n    }\n    else\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo1 = Item1;\n        PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo2 = Item2;\n\n        return uintptrcmp(heapInfo1->BytesCommitted, heapInfo2->BytesCommitted);\n    }\n}\n\nstatic INT NTAPI PhpHeapEntriesCompareFunction(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_ PVOID Context\n    )\n{\n    PPH_PROCESS_HEAPS_CONTEXT context = Context;\n\n    if (context->IsWow64Process)\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo1 = Item1;\n        PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo2 = Item2;\n\n        return uintcmp(heapInfo1->NumberOfEntries, heapInfo2->NumberOfEntries);\n    }\n    else\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo1 = Item1;\n        PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo2 = Item2;\n\n        return uintcmp(heapInfo1->NumberOfEntries, heapInfo2->NumberOfEntries);\n    }\n}\n\nstatic HFONT NTAPI PhpHeapFontFunction(\n    _In_ INT Index,\n    _In_ PVOID Param,\n    _In_ PVOID Context\n    )\n{\n    PVOID heapBaseAddress = Param;\n    PPH_PROCESS_HEAPS_CONTEXT context = Context;\n\n    if (context->IsWow64Process)\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo = Param;\n        heapBaseAddress = UlongToPtr(heapInfo->BaseAddress);\n    }\n    else\n    {\n        PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo = Param;\n        heapBaseAddress = heapInfo->BaseAddress;\n    }\n\n    if (!context->ProcessHeap)\n    {\n        HANDLE processHandle;\n\n        if (NT_SUCCESS(PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n            context->ProcessItem->ProcessId\n            )))\n        {\n            PhGetProcessDefaultHeap(processHandle, &context->ProcessHeap);\n            NtClose(processHandle);\n        }\n    }\n\n    if (heapBaseAddress == context->ProcessHeap)\n    {\n        if (!context->BoldFont)\n            context->BoldFont = PhDuplicateFontWithNewWeight((HFONT)SendMessage(context->ListViewHandle, WM_GETFONT, 0, 0), FW_BOLD);\n\n        return context->BoldFont;\n    }\n\n    return NULL;\n}\n\nPPH_STRING PhGetProcessHeapFlagsText(\n    _In_ ULONG Flags\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n\n    PhInitializeStringBuilder(&stringBuilder, 10);\n\n    if (Flags & HEAP_NO_SERIALIZE)\n        PhAppendStringBuilder2(&stringBuilder, L\"No serialize, \");\n    if (Flags & HEAP_GROWABLE)\n        PhAppendStringBuilder2(&stringBuilder, L\"Growable, \");\n    if (Flags & HEAP_GENERATE_EXCEPTIONS)\n        PhAppendStringBuilder2(&stringBuilder, L\"Generate exceptions, \");\n    if (Flags & HEAP_ZERO_MEMORY)\n        PhAppendStringBuilder2(&stringBuilder, L\"Zero memory, \");\n    if (Flags & HEAP_REALLOC_IN_PLACE_ONLY)\n        PhAppendStringBuilder2(&stringBuilder, L\"Realloc in-place, \");\n    if (Flags & HEAP_TAIL_CHECKING_ENABLED)\n        PhAppendStringBuilder2(&stringBuilder, L\"Tail checking, \");\n    if (Flags & HEAP_FREE_CHECKING_ENABLED)\n        PhAppendStringBuilder2(&stringBuilder, L\"Free checking, \");\n    if (Flags & HEAP_DISABLE_COALESCE_ON_FREE)\n        PhAppendStringBuilder2(&stringBuilder, L\"Coalesce on free, \");\n    if (Flags & HEAP_CREATE_ALIGN_16)\n        PhAppendStringBuilder2(&stringBuilder, L\"Align 16, \");\n    if (Flags & HEAP_CREATE_ENABLE_TRACING)\n        PhAppendStringBuilder2(&stringBuilder, L\"Traceable, \");\n    if (Flags & HEAP_CREATE_ENABLE_EXECUTE)\n        PhAppendStringBuilder2(&stringBuilder, L\"Executable, \");\n    if (Flags & HEAP_CREATE_SEGMENT_HEAP)\n        PhAppendStringBuilder2(&stringBuilder, L\"Segment heap, \");\n    if (Flags & HEAP_CREATE_HARDENED)\n        PhAppendStringBuilder2(&stringBuilder, L\"Segment hardened, \");\n\n    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    if (Flags)\n    {\n        WCHAR pointer[PH_PTR_STR_LEN_1];\n\n        PhPrintPointer(pointer, UlongToPtr(Flags));\n\n        if (PhIsNullOrEmptyString(stringBuilder.String))\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s\", pointer);\n        else\n            PhAppendFormatStringBuilder(&stringBuilder, L\" (%s)\", pointer);\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nPCWSTR PhGetProcessHeapClassText(\n    _In_ ULONG HeapClass\n    )\n{\n    switch (HeapClass)\n    {\n    case HEAP_CLASS_0:\n        return L\"Process Heap\";\n    case HEAP_CLASS_1:\n        return L\"Private Heap\";\n    case HEAP_CLASS_2:\n        return L\"Kernel Heap\";\n    case HEAP_CLASS_3:\n        return L\"GDI Heap\";\n    case HEAP_CLASS_4:\n        return L\"User Heap\";\n    case HEAP_CLASS_5:\n        return L\"Console Heap\";\n    case HEAP_CLASS_6:\n        return L\"Desktop Heap\";\n    case HEAP_CLASS_7:\n        return L\"CSRSS Shared Heap\";\n    case HEAP_CLASS_8:\n        return L\"CSRSS Port Heap\";\n    }\n\n    return L\"Unknown Heap\";\n}\n\nVOID PhpEnumerateProcessHeaps(\n    _In_ PPH_PROCESS_HEAPS_CONTEXT Context\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    HANDLE processHandle = NULL;\n    HANDLE powerRequestHandle = NULL;\n    PROCESS_REFLECTION_INFORMATION reflectionInfo = { 0 };\n    HANDLE clientProcessId = Context->ProcessItem->ProcessId;\n    BOOLEAN sizesInBytes;\n\n    sizesInBytes = Button_GetCheck(GetDlgItem(Context->WindowHandle, IDC_SIZESINBYTES)) == BST_CHECKED;\n\n    ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE);\n    ListView_DeleteAllItems(Context->ListViewHandle);\n\n    if (Context->DebugBuffer)\n    {\n        PhFree(Context->DebugBuffer);\n        Context->DebugBuffer = NULL;\n    }\n\n    if (WindowsVersion >= WINDOWS_8 && WindowsVersion <= WINDOWS_8_1)\n    {\n        // Windows 8 requires ALL_ACCESS for PLM execution requests. (dmex)\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_ALL_ACCESS,\n            clientProcessId\n            );\n    }\n    else\n    {\n        // Windows 10 and above require SET_LIMITED for PLM execution requests. (dmex)\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_LIMITED_INFORMATION | // PLM\n            PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE, // Reflection\n            clientProcessId\n            );\n    }\n\n    if (processHandle)\n    {\n        PhCreateExecutionRequiredRequest(processHandle, &powerRequestHandle);\n\n        if (PhGetIntegerSetting(SETTING_ENABLE_HEAP_REFLECTION))\n        {\n            // NOTE: RtlQueryProcessDebugInformation injects a thread into the process causing deadlocks and other issues in rare cases.\n            // We mitigate these problems by reflecting the process and querying heap information from the clone. (dmex)\n\n            status = PhCreateProcessReflection(\n                &reflectionInfo,\n                processHandle\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                clientProcessId = reflectionInfo.ReflectionClientId.UniqueProcess;\n            }\n        }\n    }\n\n#ifdef _WIN64\n    if (Context->ProcessItem->IsWow64Process)\n    {\n        if (PhUiConnectToPhSvcEx(Context->WindowHandle, Wow64PhSvcMode, FALSE))\n        {\n            PPH_STRING capturedHeapInfoString;\n            PPH_PROCESS_DEBUG_HEAP_INFORMATION32 capturedHeapInfo;\n            ULONG capturedHeapInfoLength;\n\n            status = PhSvcCallQueryProcessHeapInformation(\n                clientProcessId,\n                &capturedHeapInfoString\n                );\n\n            if (!NT_SUCCESS(status))\n            {\n                PhUiDisconnectFromPhSvc();\n\n                PhShowStatus(Context->WindowHandle, L\"Unable to query heap information.\", status, 0);\n                goto CleanupExit;\n            }\n\n            PhUiDisconnectFromPhSvc();\n\n            capturedHeapInfoLength = sizeof(PH_PROCESS_DEBUG_HEAP_INFORMATION32) + 100 * sizeof(PH_PROCESS_DEBUG_HEAP_ENTRY32);\n            capturedHeapInfo = PhAllocateZero(capturedHeapInfoLength);\n\n            if (!PhHexStringToBufferEx(\n                &capturedHeapInfoString->sr,\n                capturedHeapInfoLength,\n                capturedHeapInfo\n                ))\n            {\n                PhFree(capturedHeapInfo);\n                goto CleanupExit;\n            }\n\n            Context->DebugBuffer = capturedHeapInfo;\n            Context->ProcessHeap = UlongToPtr(capturedHeapInfo->DefaultHeap);\n\n            for (ULONG i = 0; i < capturedHeapInfo->NumberOfHeaps; i++)\n            {\n                PPH_PROCESS_DEBUG_HEAP_ENTRY32 entry = &capturedHeapInfo->Heaps[i];\n                INT lvItemIndex;\n                WCHAR value[PH_INT64_STR_LEN_1];\n\n                PhPrintUInt32(value, i + 1);\n                lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, value, entry);\n                PhPrintPointer(value, UlongToPtr(entry->BaseAddress));\n                PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, value);\n                PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, PhaFormatSize(entry->BytesAllocated, sizesInBytes ? 0 : ULONG_MAX)->Buffer);\n                PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 3, PhaFormatSize(entry->BytesCommitted, sizesInBytes ? 0 : ULONG_MAX)->Buffer);\n                PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 4, PhaFormatUInt64(entry->NumberOfEntries, TRUE)->Buffer);\n                PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 5, PH_AUTO_T(PH_STRING, PhGetProcessHeapFlagsText(entry->Flags & ~HEAP_CLASS_MASK))->Buffer);\n                PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 6, PhGetProcessHeapClassText(entry->Flags & HEAP_CLASS_MASK));\n\n                switch (entry->Signature)\n                {\n                case RTL_HEAP_SIGNATURE:\n                    {\n                        switch (entry->HeapFrontEndType)\n                        {\n                        case 1:\n                            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"NT Heap (Lookaside)\");\n                            break;\n                        case 2:\n                            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"NT Heap (LFH)\");\n                            break;\n                        default:\n                            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"NT Heap\");\n                            break;\n                        }\n                    }\n                    break;\n                case RTL_HEAP_SEGMENT_SIGNATURE:\n                    {\n                        switch (entry->HeapFrontEndType)\n                        {\n                        case 1:\n                            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"Segment Heap (Lookaside)\");\n                            break;\n                        case 2:\n                            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"Segment Heap (LFH)\");\n                            break;\n                        default:\n                            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"Segment Heap\");\n                            break;\n                        }\n                    }\n                    break;\n                }\n            }\n\n            PhDereferenceObject(capturedHeapInfoString);\n        }\n        else\n        {\n            PhShowError2(\n                Context->WindowHandle,\n                L\"Unable to query 32bit heap information.\",\n                L\"%s\",\n                L\"The 32-bit version of System Informer could not be located.\"\n                );\n            goto CleanupExit;\n        }\n    }\n    else\n    {\n#endif\n        PPH_PROCESS_DEBUG_HEAP_INFORMATION heapDebugInfo;\n\n        status = PhQueryProcessHeapInformation(\n            clientProcessId,\n            &heapDebugInfo\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            PhShowStatus(Context->WindowHandle, L\"Unable to query heap information.\", status, 0);\n            goto CleanupExit;\n        }\n\n        Context->DebugBuffer = heapDebugInfo;\n        Context->ProcessHeap = heapDebugInfo->DefaultHeap;\n\n        for (ULONG i = 0; i < heapDebugInfo->NumberOfHeaps; i++)\n        {\n            PPH_PROCESS_DEBUG_HEAP_ENTRY entry = &heapDebugInfo->Heaps[i];\n            INT lvItemIndex;\n            WCHAR value[PH_INT64_STR_LEN_1];\n\n            PhPrintUInt32(value, i + 1);\n            lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, value, entry);\n            PhPrintPointer(value, entry->BaseAddress);\n            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, value);\n            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, PhaFormatSize(entry->BytesAllocated, sizesInBytes ? 0 : ULONG_MAX)->Buffer);\n            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 3, PhaFormatSize(entry->BytesCommitted, sizesInBytes ? 0 : ULONG_MAX)->Buffer);\n            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 4, PhaFormatUInt64(entry->NumberOfEntries, TRUE)->Buffer);\n            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 5, PH_AUTO_T(PH_STRING, PhGetProcessHeapFlagsText(entry->Flags & ~HEAP_CLASS_MASK))->Buffer);\n            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 6, PhGetProcessHeapClassText(entry->Flags & HEAP_CLASS_MASK));\n\n            switch (entry->Signature)\n            {\n            case RTL_HEAP_SIGNATURE:\n                {\n                    switch (entry->HeapFrontEndType)\n                    {\n                    case 1:\n                        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"NT Heap (Lookaside)\");\n                        break;\n                    case 2:\n                        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"NT Heap (LFH)\");\n                        break;\n                    default:\n                        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"NT Heap\");\n                        break;\n                    }\n                }\n                break;\n            case RTL_HEAP_SEGMENT_SIGNATURE:\n                {\n                    switch (entry->HeapFrontEndType)\n                    {\n                    case 1:\n                        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"Segment Heap (Lookaside)\");\n                        break;\n                    case 2:\n                        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"Segment Heap (LFH)\");\n                        break;\n                    default:\n                        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 7, L\"Segment Heap\");\n                        break;\n                    }\n                }\n                break;\n            }\n        }\n\n#ifdef _WIN64\n    }\n#endif\n\nCleanupExit:\n    PhFreeProcessReflection(&reflectionInfo);\n\n    if (processHandle)\n        NtClose(processHandle);\n\n    if (powerRequestHandle)\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n\n    ExtendedListView_SortItems(Context->ListViewHandle);\n    ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE);\n}\n\nVOID PhpSetProcessHeapsWindowText(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Title,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PH_FORMAT format[5];\n    WCHAR formatBuffer[260];\n\n    PhInitFormatS(&format[0], Title);\n    PhInitFormatSR(&format[1], ProcessItem->ProcessName->sr);\n    PhInitFormatS(&format[2], L\" (\");\n    PhInitFormatU(&format[3], HandleToUlong(ProcessItem->ProcessId));\n    PhInitFormatC(&format[4], L')');\n\n    if (PhFormatToBuffer(\n        format,\n        RTL_NUMBER_OF(format),\n        formatBuffer,\n        sizeof(formatBuffer),\n        NULL\n        ))\n    {\n        PhSetWindowText(WindowHandle, formatBuffer);\n    }\n}\n\nINT_PTR CALLBACK PhpProcessHeapsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n     PPH_PROCESS_HEAPS_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_PROCESS_HEAPS_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhpSetProcessHeapsWindowText(hwndDlg, L\"Heaps - \", context->ProcessItem);\n\n            PhSetListViewStyle(context->ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 40, L\"#\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 100, L\"Address\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 120, L\"Used\");\n            PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 120, L\"Committed\");\n            PhAddListViewColumn(context->ListViewHandle, 4, 4, 4, LVCFMT_LEFT, 80, L\"Entries\");\n            PhAddListViewColumn(context->ListViewHandle, 5, 5, 5, LVCFMT_LEFT, 80, L\"Flags\");\n            PhAddListViewColumn(context->ListViewHandle, 6, 6, 6, LVCFMT_LEFT, 80, L\"Class\");\n            PhAddListViewColumn(context->ListViewHandle, 7, 7, 7, LVCFMT_LEFT, 80, L\"Type\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            ExtendedListView_SetContext(context->ListViewHandle, context);\n            ExtendedListView_SetCompareFunction(context->ListViewHandle, 1, PhpHeapAddressCompareFunction);\n            ExtendedListView_SetCompareFunction(context->ListViewHandle, 2, PhpHeapUsedCompareFunction);\n            ExtendedListView_SetCompareFunction(context->ListViewHandle, 3, PhpHeapCommittedCompareFunction);\n            ExtendedListView_SetCompareFunction(context->ListViewHandle, 4, PhpHeapEntriesCompareFunction);\n            ExtendedListView_SetItemFontFunction(context->ListViewHandle, PhpHeapFontFunction);\n\n            PhLoadListViewColumnsFromSetting(SETTING_SEGMENT_HEAP_LIST_VIEW_COLUMNS, context->ListViewHandle);\n            PhLoadListViewSortColumnsFromSetting(SETTING_SEGMENT_HEAP_LIST_VIEW_SORT, context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SIZESINBYTES), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_SEGMENT_HEAP_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_SEGMENT_HEAP_WINDOW_POSITION, SETTING_SEGMENT_HEAP_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, context->ParentWindowHandle);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhSaveListViewSortColumnsToSetting(SETTING_SEGMENT_HEAP_LIST_VIEW_SORT, context->ListViewHandle);\n            PhSaveListViewColumnsToSetting(SETTING_SEGMENT_HEAP_LIST_VIEW_COLUMNS, context->ListViewHandle);\n            PhSaveWindowPlacementToSetting(SETTING_SEGMENT_HEAP_WINDOW_POSITION, SETTING_SEGMENT_HEAP_WINDOW_SIZE, hwndDlg);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            if (context->BoldFont)\n            {\n                DeleteFont(context->BoldFont);\n                context->BoldFont = NULL;\n            }\n\n            if (context->DebugBuffer)\n            {\n                PhFree(context->DebugBuffer);\n                context->DebugBuffer = NULL;\n            }\n\n            if (context->ProcessItem)\n            {\n                PhDereferenceObject(context->ProcessItem);\n                context->ProcessItem = NULL;\n            }\n\n            PhFree(context);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            if (!context->Initialized)\n            {\n                PostMessage(context->WindowHandle, WM_COMMAND, MAKEWPARAM(IDC_REFRESH, 0), 0);\n                context->Initialized = TRUE;\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDOK);\n                break;\n            case IDC_SIZESINBYTES:\n                {\n                    BOOLEAN sizesInBytes = Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED;\n                    INT index = -1;\n\n                    ExtendedListView_SetRedraw(context->ListViewHandle, FALSE);\n\n                    while ((index = ListView_GetNextItem(context->ListViewHandle, index, LVNI_ALL)) != -1)\n                    {\n                        PPH_STRING usedString = NULL;\n                        PPH_STRING committedString = NULL;\n\n                        if (context->IsWow64Process)\n                        {\n                            PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo;\n\n                            if (PhGetListViewItemParam(context->ListViewHandle, index, &heapInfo))\n                            {\n                                usedString = PhFormatSize(heapInfo->BytesAllocated, sizesInBytes ? 0 : ULONG_MAX);\n                                committedString = PhFormatSize(heapInfo->BytesCommitted, sizesInBytes ? 0 : ULONG_MAX);\n                            }\n                        }\n                        else\n                        {\n                            PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo;\n\n                            if (PhGetListViewItemParam(context->ListViewHandle, index, &heapInfo))\n                            {\n                                usedString = PhFormatSize(heapInfo->BytesAllocated, sizesInBytes ? 0 : ULONG_MAX);\n                                committedString = PhFormatSize(heapInfo->BytesCommitted, sizesInBytes ? 0 : ULONG_MAX);\n                            }\n                        }\n\n                        if (usedString)\n                        {\n                            PhSetListViewSubItem(context->ListViewHandle, index, 2, usedString->Buffer);\n                            PhDereferenceObject(usedString);\n                        }\n\n                        if (committedString)\n                        {\n                            PhSetListViewSubItem(context->ListViewHandle, index, 3, committedString->Buffer);\n                            PhDereferenceObject(committedString);\n                        }\n                    }\n\n                    ExtendedListView_SetRedraw(context->ListViewHandle, TRUE);\n                }\n                break;\n            case IDC_REFRESH:\n                {\n                    PhpEnumerateProcessHeaps(context);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle);\n\n            REFLECT_MESSAGE_DLG(hwndDlg, context->ListViewHandle, uMsg, wParam, lParam);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo;\n                PPH_EMENU menu;\n                INT selectedCount;\n                PPH_EMENU_ITEM menuItem;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                selectedCount = ListView_GetSelectedCount(context->ListViewHandle);\n                heapInfo = PhGetSelectedListViewItemParam(context->ListViewHandle);\n\n                if (selectedCount != 0)\n                {\n                    menu = PhCreateEMenu();\n                    //PhInsertEMenuItem(menu, PhCreateEMenuItem(selectedCount != 1 ? PH_EMENU_DISABLED : 0, 1, L\"Destroy\", NULL, NULL), ULONG_MAX);\n                    //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, USHRT_MAX, L\"Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, USHRT_MAX, context->ListViewHandle);\n\n                    menuItem = PhShowEMenu(\n                        menu,\n                        context->ListViewHandle,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (menuItem)\n                    {\n                        if (PhHandleCopyListViewEMenuItem(menuItem))\n                            break;\n\n                        switch (menuItem->Id)\n                        {\n                        case 1:\n                            //if (PhpDestroyHeap(hwndDlg, context->ProcessItem->ProcessId, heapInfo->BaseAddress))\n                            //    ListView_DeleteItem(context->ListViewHandle, PhFindListViewItemByParam(context->ListViewHandle, -1, heapInfo));\n                            //break;\n                        case USHRT_MAX:\n                            PhCopyListView(context->ListViewHandle);\n                            break;\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\n//NTSTATUS PhGetProcessHeapCompatibilityInformation(\n//    _In_ HANDLE ProcessHandle,\n//    _In_ PVOID HeapAddress,\n//    _In_ ULONG IsWow64Process,\n//    _Out_ ULONG* HeapCompatibility\n//    )\n//{\n//    NTSTATUS status = STATUS_UNSUCCESSFUL;\n//    ULONG frontEndHeapType = ULONG_MAX;\n//\n//    if (WindowsVersion >= WINDOWS_10_20H1)\n//    {\n//        status = PhReadVirtualMemory(\n//            ProcessHandle,\n//            PTR_ADD_OFFSET(HeapAddress, IsWow64Process ? 0xEA : 0x1A2),\n//            &frontEndHeapType,\n//            sizeof(ULONG),\n//            NULL\n//            );\n//    }\n//\n//    if (NT_SUCCESS(status))\n//    {\n//        if (HeapCompatibility)\n//            *HeapCompatibility = frontEndHeapType;\n//    }\n//\n//    return status;\n//}\n//\n//NTSTATUS PhGetProcessHeapCounters(\n//    _In_ HANDLE ProcessHandle,\n//    _In_ PVOID HeapAddress,\n//    _In_ ULONG IsWow64Process,\n//    _Out_ PVOID *HeapCounters\n//    )\n//{\n//    NTSTATUS status = STATUS_UNSUCCESSFUL;\n//    PVOID heapCounters;\n//    ULONG heapCountersLength;\n//\n//    if (IsWow64Process)\n//        heapCountersLength = sizeof(HEAP_COUNTERS32);\n//    else\n//        heapCountersLength = sizeof(HEAP_COUNTERS);\n//\n//    heapCounters = PhAllocate(heapCountersLength);\n//    memset(heapCounters, 0, heapCountersLength);\n//\n//    if (WindowsVersion >= WINDOWS_10_20H1)\n//    {\n//        status = PhReadVirtualMemory(\n//            ProcessHandle,\n//            PTR_ADD_OFFSET(HeapAddress, IsWow64Process ? 0x1F4 : 0x238),\n//            heapCounters,\n//            heapCountersLength,\n//            NULL\n//            );\n//    }\n//\n//    if (NT_SUCCESS(status))\n//    {\n//        if (HeapCounters)\n//            *HeapCounters = heapCounters;\n//        return status;\n//    }\n//\n//    PhFree(heapCounters);\n//    return status;\n//}\n//\n//NTSTATUS PhGetProcessSegmentHeapCounters(\n//    _In_ HANDLE ProcessHandle,\n//    _In_ PVOID HeapAddress,\n//    _In_ ULONG IsWow64Process,\n//    _Out_ PVOID *HeapCounters\n//    )\n//{\n//    NTSTATUS status = STATUS_UNSUCCESSFUL;\n//    PVOID heapCounters;\n//    ULONG heapCountersLength;\n//\n//    if (IsWow64Process)\n//        heapCountersLength = sizeof(HEAP_RUNTIME_MEMORY_STATS32);\n//    else\n//        heapCountersLength = sizeof(HEAP_RUNTIME_MEMORY_STATS);\n//\n//    heapCounters = PhAllocate(heapCountersLength);\n//    memset(heapCounters, 0, heapCountersLength);\n//\n//    if (WindowsVersion >= WINDOWS_10_20H1)\n//    {\n//        status = PhReadVirtualMemory(\n//            ProcessHandle,\n//            PTR_ADD_OFFSET(HeapAddress, IsWow64Process ? 0x80 : 0x80),\n//            heapCounters,\n//            heapCountersLength,\n//            NULL\n//            );\n//    }\n//\n//    if (NT_SUCCESS(status))\n//    {\n//        if (HeapCounters)\n//            *HeapCounters = heapCounters;\n//        return status;\n//    }\n//\n//    PhFree(heapCounters);\n//    return status;\n//}\n//\n//NTSTATUS PhGetProcessHeaps(\n//    _In_ HANDLE ProcessHandle\n//    )\n//{\n//    PROCESS_BASIC_INFORMATION basicInfo;\n//    ULONG numberOfHeaps;\n//    PVOID processHeapsPtr;\n//    PVOID* processHeaps;\n//#ifdef _WIN64\n//    PVOID peb32;\n//    ULONG processHeapsPtr32;\n//    ULONG* processHeaps32;\n//#endif\n//\n//    if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0)\n//    {\n//        if (NT_SUCCESS(PhReadVirtualMemory(\n//            ProcessHandle,\n//            PTR_ADD_OFFSET(basicInfo.PebBaseAddress, UFIELD_OFFSET(PEB, NumberOfHeaps)),\n//            &numberOfHeaps,\n//            sizeof(ULONG),\n//            NULL\n//            )) && numberOfHeaps < 1000)\n//        {\n//            processHeaps = PhAllocateZero(numberOfHeaps * sizeof(PVOID));\n//\n//            if (\n//                NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, PTR_ADD_OFFSET(basicInfo.PebBaseAddress, UFIELD_OFFSET(PEB, ProcessHeaps)), &processHeapsPtr, sizeof(PVOID), NULL)) &&\n//                NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, processHeapsPtr, processHeaps, numberOfHeaps * sizeof(PVOID), NULL))\n//                )\n//            {\n//                for (ULONG i = 0; i < numberOfHeaps; i++)\n//                {\n//                    ULONG signature = ULONG_MAX;\n//\n//                    if (!NT_SUCCESS(PhGetProcessHeapSignature(ProcessHandle, processHeaps[i], FALSE, &signature)))\n//                        continue;\n//\n//                    if (signature == RTL_HEAP_SIGNATURE)\n//                    {\n//                        PHEAP_COUNTERS counters;\n//\n//                        if (NT_SUCCESS(PhGetProcessHeapCounters(ProcessHandle, processHeaps[i], FALSE, &counters)))\n//                        {\n//                            dprintf(\n//                                \"NT-%lu - 0x%I64x - committed: %lu - allocated: %lu - count: %lu\\n\",\n//                                i + 1,\n//                                processHeaps[i],\n//                                counters->TotalMemoryCommitted,\n//                                counters->LastPolledSize,\n//                                counters->TotalSegments\n//                                );\n//\n//                            PhFree(counters);\n//                        }\n//                    }\n//                    else if (signature == RTL_HEAP_SEGMENT_SIGNATURE)\n//                    {\n//                        dprintf(\"Segment Heap\");\n//                    }\n//                }\n//            }\n//\n//            PhFree(processHeaps);\n//        }\n//    }\n//#ifdef _WIN64\n//\n//    if (NT_SUCCESS(PhGetProcessPeb32(ProcessHandle, &peb32)) && peb32 != 0)\n//    {\n//        if (NT_SUCCESS(PhReadVirtualMemory(\n//            ProcessHandle,\n//            PTR_ADD_OFFSET(peb32, UFIELD_OFFSET(PEB32, NumberOfHeaps)),\n//            &numberOfHeaps,\n//            sizeof(ULONG),\n//            NULL\n//            )) && numberOfHeaps < 1000)\n//        {\n//            processHeaps32 = PhAllocateZero(numberOfHeaps * sizeof(ULONG));\n//\n//            if (\n//                NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, PTR_ADD_OFFSET(peb32, UFIELD_OFFSET(PEB32, ProcessHeaps)), &processHeapsPtr32, sizeof(ULONG), NULL)) &&\n//                NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, UlongToPtr(processHeapsPtr32), processHeaps32, numberOfHeaps * sizeof(ULONG), NULL))\n//                )\n//            {\n//                for (ULONG i = 0; i < numberOfHeaps; i++)\n//                {\n//                    ULONG signature = ULONG_MAX;\n//\n//                    if (!NT_SUCCESS(PhGetProcessHeapSignature(ProcessHandle, UlongToPtr(processHeaps32[i]), TRUE, &signature)))\n//                        continue;\n//\n//                    if (signature == RTL_HEAP_SIGNATURE)\n//                    {\n//                        PHEAP_COUNTERS32 counters;\n//\n//                        if (NT_SUCCESS(PhGetProcessHeapCounters(ProcessHandle, UlongToPtr(processHeaps32[i]), TRUE, &counters)))\n//                        {\n//                            PhFree(counters);\n//                        }\n//                    }\n//                    else if (signature == RTL_HEAP_SEGMENT_SIGNATURE)\n//                    {\n//                        dprintf(\"Segment Heap\\n\");\n//                    }\n//                }\n//            }\n//\n//            PhFree(processHeaps32);\n//        }\n//    }\n//#endif\n//\n//    return STATUS_SUCCESS;\n//}\n//\n//BOOLEAN PhpDestroyHeap(\n//    _In_ HWND hWnd,\n//    _In_ HANDLE ProcessId,\n//    _In_ PVOID HeapHandle\n//    )\n//{\n//    NTSTATUS status;\n//    BOOLEAN cont = FALSE;\n//    HANDLE processHandle;\n//    HANDLE threadHandle;\n//\n//    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n//    {\n//        cont = PhShowConfirmMessage(\n//            hWnd,\n//            L\"destroy\",\n//            L\"the selected heap\",\n//            L\"Destroying heaps may cause the process to crash.\",\n//            FALSE\n//            );\n//    }\n//    else\n//    {\n//        cont = TRUE;\n//    }\n//\n//    if (!cont)\n//        return FALSE;\n//\n//    if (NT_SUCCESS(status = PhOpenProcess(\n//        &processHandle,\n//        PROCESS_CREATE_THREAD,\n//        ProcessId\n//        )))\n//    {\n//        if (WindowsVersion >= WINDOWS_VISTA)\n//        {\n//            status = RtlCreateUserThread(\n//                processHandle,\n//                NULL,\n//                FALSE,\n//                0,\n//                0,\n//                0,\n//                PhGetModuleProcAddress(L\"ntdll.dll\", \"RtlDestroyHeap\"),\n//                HeapHandle,\n//                &threadHandle,\n//                NULL\n//                );\n//        }\n//        else\n//        {\n//            if (!(threadHandle = CreateRemoteThread(\n//                processHandle,\n//                NULL,\n//                0,\n//                PhGetModuleProcAddress(L\"ntdll.dll\", \"RtlDestroyHeap\"),\n//                HeapHandle,\n//                0,\n//                NULL\n//                )))\n//            {\n//                status = PhGetLastWin32ErrorAsNtStatus();\n//            }\n//        }\n//\n//        if (NT_SUCCESS(status))\n//            NtClose(threadHandle);\n//\n//        NtClose(processHandle);\n//    }\n//\n//    if (!NT_SUCCESS(status))\n//    {\n//        PhShowStatus(hWnd, L\"Unable to destroy the heap\", status, 0);\n//        return FALSE;\n//    }\n//\n//    return TRUE;\n//}\n//\n//#include <tlhelp32.h>\n//\n//BOOLEAN PhpEnumerateHeapsWin32(\n//    _In_ PPROCESS_HEAPS_CONTEXT Context\n//    )\n//{\n//    HANDLE snapshotHandle;\n//    HEAPLIST32 heapList32;\n//\n//    snapshotHandle = CreateToolhelp32Snapshot(\n//        TH32CS_SNAPHEAPLIST,\n//        Context->ProcessItem->ProcessId\n//        );\n//\n//    if (snapshotHandle == INVALID_HANDLE_VALUE)\n//        return FALSE;\n//\n//    memset(&heapList32, 0, sizeof(HEAPLIST32));\n//    heapList32.dwSize = sizeof(HEAPLIST32);\n//\n//    if (Heap32ListFirst(snapshotHandle, &heapList32))\n//    {\n//        do\n//        {\n//            HEAPENTRY32 entry;\n//\n//            memset(&entry, 0, sizeof(HEAPENTRY32));\n//            entry.dwSize = sizeof(HEAPENTRY32);\n//\n//            dprintf(\"\\nHeap ID: %lu\\n\", heapList32.th32HeapID);\n//\n//            if (Heap32First(&entry, Context->ProcessItem->ProcessId, heapList32.th32HeapID))\n//            {\n//                do\n//                {\n//                    dprintf(\"Block size: %lu\\n\", entry.dwBlockSize);\n//\n//                    memset(&entry, 0, sizeof(HEAPENTRY32));\n//                    entry.dwSize = sizeof(HEAPENTRY32);\n//                } while (Heap32Next(&entry));\n//            }\n//\n//            memset(&heapList32, 0, sizeof(HEAPLIST32));\n//            heapList32.dwSize = sizeof(HEAPLIST32);\n//        } while (Heap32ListNext(snapshotHandle, &heapList32));\n//    }\n//\n//    NtClose(snapshotHandle);\n//}\n\ntypedef struct _PH_PROCESS_LOCKS_CONTEXT\n{\n    HWND WindowHandle;\n    HWND ParentWindowHandle;\n    HWND ListViewHandle;\n    HFONT BoldFont;\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN Initialized : 1;\n            BOOLEAN IsWow64Process : 1;\n            BOOLEAN Spare : 6;\n        };\n    };\n    PPH_PROCESS_ITEM ProcessItem;\n    PVOID ProcessHeap;\n    PVOID DebugBuffer;\n    PH_LAYOUT_MANAGER LayoutManager;\n} PH_PROCESS_LOCKS_CONTEXT, *PPH_PROCESS_LOCKS_CONTEXT;\n\nINT_PTR CALLBACK PhProcessLocksDlgProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowProcessLocksDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_PROCESS_LOCKS_CONTEXT context;\n\n    context = PhAllocateZero(sizeof(PH_PROCESS_LOCKS_CONTEXT));\n    context->ParentWindowHandle = ParentWindowHandle;\n    context->ProcessItem = PhReferenceObject(ProcessItem);\n    context->IsWow64Process = !!ProcessItem->IsWow64Process;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_HEAPS),\n        NULL,\n        PhProcessLocksDlgProc,\n        context\n        );\n}\n\n_Function_class_(PH_ENUM_PROCESS_LOCKS)\nNTSTATUS NTAPI PhEnumProcessLocksCallback(\n    _In_ ULONG NumberOfLocks,\n    _In_ PRTL_PROCESS_LOCK_INFORMATION Locks,\n    _In_opt_ PVOID Context\n    )\n{\n    if (!Context) return STATUS_INVALID_PARAMETER;\n    PPH_PROCESS_LOCKS_CONTEXT context = Context;\n    NTSTATUS status;\n    HANDLE processHandle = NULL;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        context->ProcessItem->ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    for (ULONG i = 0; i < NumberOfLocks; i++)\n    {\n        PRTL_PROCESS_LOCK_INFORMATION entry = &Locks[i];\n        INT lvItemIndex;\n        WCHAR value[PH_INT64_STR_LEN_1];\n        CLIENT_ID clientId;\n        PPH_STRING fileName = NULL;\n\n        clientId.UniqueProcess = NULL;\n        clientId.UniqueThread = entry->OwningThread;\n\n        if (processHandle && entry->Address)\n        {\n            if (NT_SUCCESS(PhGetProcessMappedFileName(processHandle, entry->Address, &fileName)))\n            {\n                PhMoveReference(&fileName, PhGetFileName(fileName));\n            }\n        }\n\n        PhPrintUInt32(value, i + 1);\n        lvItemIndex = PhAddListViewItem(context->ListViewHandle, MAXINT, value, PhAllocateCopy(entry, sizeof(*entry)));\n        PhPrintPointer(value, entry->Address);\n        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 2, value);\n        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 3, PhGetStringOrEmpty(fileName));\n        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 4, entry->OwningThread ? PH_AUTO_T(PH_STRING, PhGetClientIdName(&clientId))->Buffer : L\"\");\n        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 5, entry->LockCount != ULONG_MAX ? PhaFormatUInt64(entry->LockCount, TRUE)->Buffer : L\"\");\n        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 6, PhaFormatUInt64(entry->ContentionCount, TRUE)->Buffer);\n        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 7, PhaFormatUInt64(entry->EntryCount, TRUE)->Buffer);\n        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 8, PhaFormatUInt64(entry->RecursionCount, TRUE)->Buffer);\n        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 9, PhaFormatUInt64(entry->NumberOfWaitingShared, TRUE)->Buffer);\n        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 10, PhaFormatUInt64(entry->NumberOfWaitingExclusive, TRUE)->Buffer);\n\n        switch (entry->Type)\n        {\n        case RTL_CRITSECT_TYPE:\n            PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 1, L\"Critical section\");\n            break;\n        case RTL_RESOURCE_TYPE:\n            PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 1, L\"Resource\");\n            break;\n        }\n\n    }\n\n    NtClose(processHandle);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhEnumerateProcessLocks(\n    _In_ PPH_PROCESS_LOCKS_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n\n    ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE);\n    ListView_DeleteAllItems(Context->ListViewHandle);\n\n    status = PhQueryProcessLockInformation(\n        Context->ProcessItem->ProcessId,\n        PhEnumProcessLocksCallback,\n        Context\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(Context->WindowHandle, L\"Unable to query lock information.\", status, 0);\n        return;\n    }\n\n    ExtendedListView_SortItems(Context->ListViewHandle);\n    ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE);\n}\n\nINT_PTR CALLBACK PhProcessLocksDlgProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n     PPH_PROCESS_LOCKS_CONTEXT context = NULL;\n\n    if (WindowMessage == WM_INITDIALOG)\n    {\n        context = (PPH_PROCESS_LOCKS_CONTEXT)lParam;\n        PhSetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (WindowMessage)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = WindowHandle;\n            context->ListViewHandle = GetDlgItem(WindowHandle, IDC_LIST);\n\n            PhSetApplicationWindowIcon(WindowHandle);\n\n            PhpSetProcessHeapsWindowText(WindowHandle, L\"Locks - \", context->ProcessItem);\n\n            PhSetListViewStyle(context->ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 40, L\"#\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 50, L\"Type\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 100, L\"Address\");\n            PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 120, L\"Filename\");\n            PhAddListViewColumn(context->ListViewHandle, 4, 4, 4, LVCFMT_LEFT, 120, L\"Thread\");\n            PhAddListViewColumn(context->ListViewHandle, 5, 5, 5, LVCFMT_LEFT, 80, L\"Lock count\");\n            PhAddListViewColumn(context->ListViewHandle, 6, 6, 6, LVCFMT_LEFT, 80, L\"Entry count\");\n            PhAddListViewColumn(context->ListViewHandle, 7, 7, 7, LVCFMT_LEFT, 80, L\"Recursion count\");\n            PhAddListViewColumn(context->ListViewHandle, 8, 8, 8, LVCFMT_LEFT, 80, L\"Waiting shared count\");\n            PhAddListViewColumn(context->ListViewHandle, 9, 9, 9, LVCFMT_LEFT, 80, L\"Waiting exclusive count\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            ExtendedListView_SetContext(context->ListViewHandle, context);\n            ExtendedListView_SetItemFontFunction(context->ListViewHandle, PhpHeapFontFunction);\n\n            PhLoadListViewColumnsFromSetting(SETTING_SEGMENT_LOCKS_LIST_VIEW_COLUMNS, context->ListViewHandle);\n            PhLoadListViewSortColumnsFromSetting(SETTING_SEGMENT_LOCKS_LIST_VIEW_SORT, context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, WindowHandle);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(WindowHandle, IDC_SIZESINBYTES), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(WindowHandle, IDC_REFRESH), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(WindowHandle, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_SEGMENT_LOCKS_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_SEGMENT_LOCKS_WINDOW_POSITION, SETTING_SEGMENT_LOCKS_WINDOW_SIZE, WindowHandle);\n            else\n                PhCenterWindow(WindowHandle, context->ParentWindowHandle);\n\n            PhInitializeWindowTheme(WindowHandle, PhEnableThemeSupport);\n\n            ShowWindow(GetDlgItem(WindowHandle, IDC_SIZESINBYTES), SW_HIDE);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhSaveListViewSortColumnsToSetting(SETTING_SEGMENT_LOCKS_LIST_VIEW_SORT, context->ListViewHandle);\n            PhSaveListViewColumnsToSetting(SETTING_SEGMENT_LOCKS_LIST_VIEW_COLUMNS, context->ListViewHandle);\n            PhSaveWindowPlacementToSetting(SETTING_SEGMENT_LOCKS_WINDOW_POSITION, SETTING_SEGMENT_LOCKS_WINDOW_SIZE, WindowHandle);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            if (context->BoldFont)\n            {\n                DeleteFont(context->BoldFont);\n                context->BoldFont = NULL;\n            }\n\n            if (context->DebugBuffer)\n            {\n                PhFree(context->DebugBuffer);\n                context->DebugBuffer = NULL;\n            }\n\n            if (context->ProcessItem)\n            {\n                PhDereferenceObject(context->ProcessItem);\n                context->ProcessItem = NULL;\n            }\n\n            PhFree(context);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            if (!context->Initialized)\n            {\n                PostMessage(context->WindowHandle, WM_COMMAND, MAKEWPARAM(IDC_REFRESH, 0), 0);\n                context->Initialized = TRUE;\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(WindowHandle, IDOK);\n                break;\n            case IDC_SIZESINBYTES:\n                {\n                    BOOLEAN sizesInBytes = Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED;\n                    INT index = -1;\n\n                    ExtendedListView_SetRedraw(context->ListViewHandle, FALSE);\n\n                    while ((index = ListView_GetNextItem(context->ListViewHandle, index, LVNI_ALL)) != -1)\n                    {\n                        PPH_STRING usedString = NULL;\n                        PPH_STRING committedString = NULL;\n\n                        if (context->IsWow64Process)\n                        {\n                            PPH_PROCESS_DEBUG_HEAP_ENTRY32 heapInfo;\n\n                            if (PhGetListViewItemParam(context->ListViewHandle, index, &heapInfo))\n                            {\n                                usedString = PhFormatSize(heapInfo->BytesAllocated, sizesInBytes ? 0 : ULONG_MAX);\n                                committedString = PhFormatSize(heapInfo->BytesCommitted, sizesInBytes ? 0 : ULONG_MAX);\n                            }\n                        }\n                        else\n                        {\n                            PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo;\n\n                            if (PhGetListViewItemParam(context->ListViewHandle, index, &heapInfo))\n                            {\n                                usedString = PhFormatSize(heapInfo->BytesAllocated, sizesInBytes ? 0 : ULONG_MAX);\n                                committedString = PhFormatSize(heapInfo->BytesCommitted, sizesInBytes ? 0 : ULONG_MAX);\n                            }\n                        }\n\n                        if (usedString)\n                        {\n                            PhSetListViewSubItem(context->ListViewHandle, index, 2, usedString->Buffer);\n                            PhDereferenceObject(usedString);\n                        }\n\n                        if (committedString)\n                        {\n                            PhSetListViewSubItem(context->ListViewHandle, index, 3, committedString->Buffer);\n                            PhDereferenceObject(committedString);\n                        }\n                    }\n\n                    ExtendedListView_SetRedraw(context->ListViewHandle, TRUE);\n                }\n                break;\n            case IDC_REFRESH:\n                {\n                    PhEnumerateProcessLocks(context);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle);\n\n            REFLECT_MESSAGE_DLG(WindowHandle, context->ListViewHandle, WindowMessage, wParam, lParam);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_PROCESS_DEBUG_HEAP_ENTRY heapInfo;\n                PPH_EMENU menu;\n                INT selectedCount;\n                PPH_EMENU_ITEM menuItem;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                selectedCount = ListView_GetSelectedCount(context->ListViewHandle);\n                heapInfo = PhGetSelectedListViewItemParam(context->ListViewHandle);\n\n                if (selectedCount != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, USHRT_MAX, L\"Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, USHRT_MAX, context->ListViewHandle);\n\n                    menuItem = PhShowEMenu(\n                        menu,\n                        context->ListViewHandle,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (menuItem)\n                    {\n                        if (PhHandleCopyListViewEMenuItem(menuItem))\n                            break;\n\n                        switch (menuItem->Id)\n                        {\n                        case 1:\n                        case USHRT_MAX:\n                            PhCopyListView(context->ListViewHandle);\n                            break;\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/hidnproc.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2013\n *     dmex    2019-2023\n *\n */\n\n/*\n * There are two methods of zombie process detection implemented in this module.\n *\n * Brute Force. This attempts to open all possible PIDs within a certain range\n * in order to find processes which have been unlinked from the active process\n * list (EPROCESS.ActiveProcessLinks). This method is not effective when\n * either NtOpenProcess is hooked or PsLookupProcessByProcessId is hooked\n * (KSystemInformer cannot bypass this).\n *\n * CSR Handles. This enumerates handles in all running CSR processes, and works\n * even when a process has been unlinked from the active process list and\n * has been removed from the client ID table (PspCidTable). However, the method\n * does not detect native executables since CSR is not notified about them.\n * Some rootkits hook NtQuerySystemInformation in order to modify the returned\n * handle information; System Informer bypasses this by using KSystemInformer,\n * which calls ExEnumHandleTable directly. Note that both process and thread\n * handles are examined.\n */\n\n#include <phapp.h>\n#include <hidnproc.h>\n#include <hndlinfo.h>\n#include <kphuser.h>\n#include <mainwnd.h>\n#include <procprv.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <emenu.h>\n\nINT_PTR CALLBACK PhpZombieProcessesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nCOLORREF NTAPI PhpZombieProcessesColorFunction(\n    _In_ INT Index,\n    _In_ PVOID Param,\n    _In_opt_ PVOID Context\n    );\n\nBOOLEAN NTAPI PhpZombieProcessesCallback(\n    _In_ PPH_ZOMBIE_PROCESS_ENTRY Process,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhZombieProcessesUpdateListView(\n    _In_ PPH_LIST UpdateList\n    );\n\nNTSTATUS PhpCreateProcessItemForZombieProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_ZOMBIE_PROCESS_ENTRY Entry,\n    _Out_ PPH_PROCESS_ITEM* ProcessItem\n    );\n\nstatic HWND PhZombieProcessesWindowHandle = NULL;\nstatic HWND PhZombieProcessesListViewHandle = NULL;\nstatic PH_LAYOUT_MANAGER WindowLayoutManager;\nstatic RECT MinimumSize;\n\nstatic PH_ZOMBIE_PROCESS_METHOD ProcessesMethod;\nstatic PPH_LIST ProcessesList = NULL;\nstatic ULONG NumberOfZombieProcesses;\nstatic ULONG NumberOfTerminatedProcesses;\n\nVOID PhShowZombieProcessesDialog(\n    VOID\n    )\n{\n    if (!PhZombieProcessesWindowHandle)\n    {\n        PhZombieProcessesWindowHandle = PhCreateDialog(\n            PhInstanceHandle,\n            MAKEINTRESOURCE(IDD_ZOMBIEPROCESSES),\n            NULL,\n            PhpZombieProcessesDlgProc,\n            NULL\n            );\n    }\n\n    if (!IsWindowVisible(PhZombieProcessesWindowHandle))\n        ShowWindow(PhZombieProcessesWindowHandle, SW_SHOW);\n    else\n        SetForegroundWindow(PhZombieProcessesWindowHandle);\n}\n\nVOID PhZombieProcessesCleanupList(\n    _In_opt_ PPH_LIST UpdateList\n    )\n{\n    if (UpdateList)\n    {\n        for (ULONG i = 0; i < UpdateList->Count; i++)\n        {\n            PPH_ZOMBIE_PROCESS_ENTRY entry = UpdateList->Items[i];\n\n            PhClearReference(&entry->FileName);\n            PhFree(entry);\n        }\n\n        PhDereferenceObject(UpdateList);\n    }\n    {\n        PPH_STRING string = PhFormatString(L\"%u zombie process(es), %u terminated process(es).\",\n            NumberOfZombieProcesses, NumberOfTerminatedProcesses);\n        PhSetDialogItemText(PhZombieProcessesWindowHandle, IDC_DESCRIPTION, string->Buffer);\n        InvalidateRect(GetDlgItem(PhZombieProcessesWindowHandle, IDC_DESCRIPTION), NULL, TRUE);\n        PhDereferenceObject(string);\n    }\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\n NTSTATUS PhZombieProcessesThread(\n    _In_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PPH_LIST processList;\n\n    ExtendedListView_SetRedraw(PhZombieProcessesListViewHandle, FALSE);\n    ListView_DeleteAllItems(PhZombieProcessesListViewHandle);\n    ExtendedListView_SetRedraw(PhZombieProcessesListViewHandle, TRUE);\n\n    processList = PhCreateList(100);\n\n    status = PhEnumZombieProcesses(\n        ProcessesMethod,\n        PhpZombieProcessesCallback,\n        processList\n        );\n\n    if (PhZombieProcessesWindowHandle)\n        PostMessage(PhZombieProcessesWindowHandle, WM_PH_UPDATE_DIALOG, status, (LPARAM)processList);\n    else\n        PhZombieProcessesCleanupList(processList);\n\n    return STATUS_SUCCESS;\n}\n\nINT_PTR CALLBACK PhpZombieProcessesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HWND lvHandle;\n            HWND methodHandle;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhZombieProcessesListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_PROCESSES);\n            methodHandle = GetDlgItem(hwndDlg, IDC_METHOD);\n\n            PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_INTRO), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);\n            PhAddLayoutItem(&WindowLayoutManager, lvHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE);\n            PhAddLayoutItem(&WindowLayoutManager, methodHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_TERMINATE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SCAN), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            PhSetListViewStyle(lvHandle, TRUE, TRUE);\n            PhSetControlTheme(lvHandle, L\"explorer\");\n            PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 320, L\"Process\");\n            PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 60, L\"PID\");\n\n            PhSetExtendedListView(lvHandle);\n            PhLoadListViewColumnsFromSetting(SETTING_ZOMBIE_PROCESSES_LIST_VIEW_COLUMNS, lvHandle);\n            ExtendedListView_AddFallbackColumn(lvHandle, 0);\n            ExtendedListView_AddFallbackColumn(lvHandle, 1);\n            ExtendedListView_SetItemColorFunction(lvHandle, PhpZombieProcessesColorFunction);\n\n            ComboBox_AddString(methodHandle, L\"Brute force\");\n            ComboBox_AddString(methodHandle, L\"CSR handles\");\n            ComboBox_AddString(methodHandle, L\"ETW handles\");\n            ComboBox_AddString(methodHandle, L\"Process handles\");\n            ComboBox_AddString(methodHandle, L\"Registry handles\");\n            ComboBox_AddString(methodHandle, L\"Ntdll handles\");\n            PhSelectComboBoxString(methodHandle, L\"Process handles\", FALSE);\n\n            MinimumSize.left = 0;\n            MinimumSize.top = 0;\n            MinimumSize.right = 330;\n            MinimumSize.bottom = 140;\n            MapDialogRect(hwndDlg, &MinimumSize);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_ZOMBIE_PROCESSES_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_ZOMBIE_PROCESSES_WINDOW_POSITION, SETTING_ZOMBIE_PROCESSES_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            EnableWindow(GetDlgItem(hwndDlg, IDC_TERMINATE), FALSE);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveWindowPlacementToSetting(SETTING_ZOMBIE_PROCESSES_WINDOW_POSITION, SETTING_ZOMBIE_PROCESSES_WINDOW_SIZE, hwndDlg);\n            PhSaveListViewColumnsToSetting(SETTING_ZOMBIE_PROCESSES_LIST_VIEW_COLUMNS, PhZombieProcessesListViewHandle);\n\n            PhZombieProcessesCleanupList(ProcessesList);\n\n            PhZombieProcessesWindowHandle = NULL;\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                {\n                    DestroyWindow(hwndDlg);\n                }\n                break;\n            case IDC_SCAN:\n                {\n                    PPH_STRING method;\n\n                    method = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_METHOD)));\n\n                    PhZombieProcessesCleanupList(NULL);\n\n                    ProcessesList = PhCreateList(40);\n\n                    if (PhEqualString2(method, L\"Brute force\", TRUE))\n                        ProcessesMethod = BruteForceScanMethod;\n                    else if (PhEqualString2(method, L\"CSR handles\", TRUE))\n                        ProcessesMethod = CsrHandlesScanMethod;\n                    else if (PhEqualString2(method, L\"Process handles\", TRUE))\n                        ProcessesMethod = ProcessHandleScanMethod;\n                    else if (PhEqualString2(method, L\"Registry handles\", TRUE))\n                        ProcessesMethod = RegistryScanMethod;\n                    else if (PhEqualString2(method, L\"ETW handles\", TRUE))\n                        ProcessesMethod = EtwGuidScanMethod;\n                    else if (PhEqualString2(method, L\"Ntdll handles\", TRUE))\n                        ProcessesMethod = NtdllScanMethod;\n\n                    NumberOfZombieProcesses = 0;\n                    NumberOfTerminatedProcesses = 0;\n\n                    EnableWindow(GetDlgItem(hwndDlg, IDC_SCAN), FALSE);\n\n                    PhCreateThread2(PhZombieProcessesThread, NULL);\n                }\n                break;\n            case IDC_TERMINATE:\n                {\n                    PPH_ZOMBIE_PROCESS_ENTRY *entries;\n                    ULONG numberOfEntries;\n                    ULONG i;\n\n                    PhGetSelectedListViewItemParams(PhZombieProcessesListViewHandle, &entries, &numberOfEntries);\n\n                    if (numberOfEntries != 0)\n                    {\n                        if (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) ||\n                            PhShowConfirmMessage(\n                            hwndDlg,\n                            L\"terminate\",\n                            L\"the selected process(es)\",\n                            L\"Terminating a Zombie process may cause the system to become unstable \"\n                            L\"or crash.\",\n                            TRUE\n                            ))\n                        {\n                            NTSTATUS status;\n                            HANDLE processHandle;\n                            BOOLEAN refresh;\n\n                            refresh = FALSE;\n\n                            for (i = 0; i < numberOfEntries; i++)\n                            {\n                                if (ProcessesMethod == BruteForceScanMethod || ProcessesMethod == ProcessHandleScanMethod)\n                                {\n                                    status = PhOpenProcess(\n                                        &processHandle,\n                                        PROCESS_TERMINATE,\n                                        entries[i]->ProcessId\n                                        );\n                                }\n                                else\n                                {\n                                    status = PhOpenProcessByCsrHandles(\n                                        &processHandle,\n                                        PROCESS_TERMINATE,\n                                        entries[i]->ProcessId\n                                        );\n                                }\n\n                                if (NT_SUCCESS(status))\n                                {\n                                    status = PhTerminateProcess(processHandle, STATUS_SUCCESS);\n                                    NtClose(processHandle);\n\n                                    if (NT_SUCCESS(status))\n                                        refresh = TRUE;\n                                }\n                                else\n                                {\n                                    PhShowStatus(hwndDlg, L\"Unable to terminate the process\", status, 0);\n                                }\n                            }\n\n                            if (refresh)\n                            {\n                                // Sleep for a bit before continuing. It seems to help avoid BSODs.\n\n                                PhDelayExecution(250);\n\n                                SendMessage(hwndDlg, WM_COMMAND, IDC_SCAN, 0);\n                            }\n                        }\n                    }\n\n                    PhFree(entries);\n                }\n                break;\n            case IDC_SAVE:\n                {\n                    static PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Text files (*.txt)\", L\"*.txt\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog;\n\n                    fileDialog = PhCreateSaveFileDialog();\n\n                    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n                    PhSetFileDialogFileName(fileDialog, L\"Zombie Processes.txt\");\n\n                    if (PhShowFileDialog(hwndDlg, fileDialog))\n                    {\n                        NTSTATUS status;\n                        PPH_STRING fileName;\n                        PPH_FILE_STREAM fileStream;\n\n                        fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n\n                        if (NT_SUCCESS(status = PhCreateFileStream(\n                            &fileStream,\n                            fileName->Buffer,\n                            FILE_GENERIC_WRITE,\n                            FILE_SHARE_READ,\n                            FILE_OVERWRITE_IF,\n                            0\n                            )))\n                        {\n                            PhWriteStringAsUtf8FileStream(fileStream, (PPH_STRINGREF)&PhUnicodeByteOrderMark);\n                            PhWritePhTextHeader(fileStream);\n                            PhWriteStringAsUtf8FileStream2(fileStream, L\"Method: \");\n                            PhWriteStringAsUtf8FileStream2(fileStream,\n                                ProcessesMethod == BruteForceScanMethod ? L\"Brute Force\\r\\n\" : L\"CSR Handles\\r\\n\");\n                            PhWriteStringFormatAsUtf8FileStream(\n                                fileStream,\n                                L\"Zombie: %u\\r\\nTerminated: %u\\r\\n\\r\\n\",\n                                NumberOfZombieProcesses,\n                                NumberOfTerminatedProcesses\n                                );\n\n                            if (ProcessesList)\n                            {\n                                ULONG i;\n\n                                for (i = 0; i < ProcessesList->Count; i++)\n                                {\n                                    PPH_ZOMBIE_PROCESS_ENTRY entry = ProcessesList->Items[i];\n\n                                    if (entry->Type == ZombieProcess)\n                                        PhWriteStringAsUtf8FileStream2(fileStream, L\"[Zombie] \");\n                                    else if (entry->Type == TerminatedProcess)\n                                        PhWriteStringAsUtf8FileStream2(fileStream, L\"[Terminated] \");\n                                    else if (entry->Type != NormalProcess)\n                                        continue;\n\n                                    PhWriteStringFormatAsUtf8FileStream(\n                                        fileStream,\n                                        L\"%s (%u)\\r\\n\",\n                                        entry->FileName->Buffer,\n                                        HandleToUlong(entry->ProcessId)\n                                        );\n                                }\n                            }\n\n                            PhDereferenceObject(fileStream);\n                        }\n\n                        if (!NT_SUCCESS(status))\n                            PhShowStatus(hwndDlg, L\"Unable to create the file\", status, 0);\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            PhHandleListViewNotifyBehaviors(lParam, PhZombieProcessesListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);\n\n            switch (header->code)\n            {\n            case LVN_ITEMCHANGED:\n                {\n                    if (header->hwndFrom == PhZombieProcessesListViewHandle)\n                    {\n                        EnableWindow(\n                            GetDlgItem(hwndDlg, IDC_TERMINATE),\n                            ListView_GetSelectedCount(PhZombieProcessesListViewHandle) > 0\n                            );\n                    }\n                }\n                break;\n            case NM_DBLCLK:\n                {\n                    if (header->hwndFrom == PhZombieProcessesListViewHandle)\n                    {\n                        PPH_ZOMBIE_PROCESS_ENTRY entry;\n\n                        entry = PhGetSelectedListViewItemParam(PhZombieProcessesListViewHandle);\n\n                        if (entry)\n                        {\n                            NTSTATUS status;\n                            PPH_PROCESS_ITEM processItem;\n\n                            status = PhpCreateProcessItemForZombieProcess(hwndDlg, entry, &processItem);\n\n                            if (NT_SUCCESS(status))\n                            {\n                                SystemInformer_ShowProcessProperties(processItem);\n                                PhDereferenceObject(processItem);\n                            }\n                            else\n                            {\n                                PhShowStatus(hwndDlg, L\"Unable to create a process structure for the selected process.\", status, 0);\n                            }\n                        }\n                    }\n                }\n                break;\n            }\n\n            REFLECT_MESSAGE_DLG(hwndDlg, PhZombieProcessesListViewHandle, uMsg, wParam, lParam);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&WindowLayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&WindowLayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&WindowLayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == PhZombieProcessesListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID* listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(PhZombieProcessesListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(PhZombieProcessesListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, PhZombieProcessesListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                PhCopyListView(PhZombieProcessesListViewHandle);\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    case WM_PH_UPDATE_DIALOG:\n        {\n            NTSTATUS status = (NTSTATUS)wParam;\n            PPH_LIST list = (PPH_LIST)lParam;\n\n            ExtendedListView_SetRedraw(PhZombieProcessesListViewHandle, FALSE);\n            ListView_DeleteAllItems(PhZombieProcessesListViewHandle);\n            PhZombieProcessesUpdateListView(list);\n            ExtendedListView_SortItems(PhZombieProcessesListViewHandle);\n            ExtendedListView_SetRedraw(PhZombieProcessesListViewHandle, TRUE);\n\n            if (NT_SUCCESS(status))\n            {\n                PhSetDialogItemText(hwndDlg, IDC_DESCRIPTION, PhaFormatString(\n                    L\"%u zombie process(es), %u terminated process(es).\",\n                    NumberOfZombieProcesses,\n                    NumberOfTerminatedProcesses\n                    )->Buffer);\n                InvalidateRect(GetDlgItem(hwndDlg, IDC_DESCRIPTION), NULL, TRUE);\n            }\n            else\n            {\n                PhShowStatus(hwndDlg, L\"Unable to perform the scan\", status, 0);\n            }\n\n            EnableWindow(GetDlgItem(hwndDlg, IDC_SCAN), TRUE);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        {\n            if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_DESCRIPTION))\n            {\n                if (NumberOfZombieProcesses != 0)\n                {\n                    SetTextColor((HDC)wParam, RGB(0xff, 0x00, 0x00));\n                }\n\n                SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));\n\n                return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);\n            }\n\n            return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n        }\n    }\n\n    return FALSE;\n}\n\nCOLORREF NTAPI PhpZombieProcessesColorFunction(\n    _In_ INT Index,\n    _In_ PVOID Param,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_ZOMBIE_PROCESS_ENTRY entry = Param;\n\n    switch (entry->Type)\n    {\n    case UnknownProcess:\n    case ZombieProcess:\n        return RGB(229, 186, 208);\n    case TerminatedProcess:\n        return RGB(0x77, 0x77, 0x77);\n    }\n\n    return PhEnableThemeSupport ? PhThemeWindowBackgroundColor : GetSysColor(COLOR_WINDOW);\n}\n\nBOOLEAN NTAPI PhpZombieProcessesCallback(\n    _In_ PPH_ZOMBIE_PROCESS_ENTRY Process,\n    _In_ PVOID Context\n    )\n{\n    PPH_ZOMBIE_PROCESS_ENTRY entry;\n    ULONG count = ((PPH_LIST)Context)->Count;\n\n    for (ULONG i = 0; i < count; i++)\n    {\n        PPH_ZOMBIE_PROCESS_ENTRY item = ((PPH_LIST)Context)->Items[i];\n\n        if (item->ProcessId == Process->ProcessId)\n        {\n            return TRUE; // duplicate\n        }\n    }\n\n    entry = PhAllocateCopy(Process, sizeof(PH_ZOMBIE_PROCESS_ENTRY));\n\n    if (entry->FileName)\n        PhReferenceObject(entry->FileName);\n\n    PhAddItemList(Context, entry);\n\n    if (entry->Type == ZombieProcess)\n        InterlockedIncrement(&NumberOfZombieProcesses);\n    else if (entry->Type == TerminatedProcess)\n        InterlockedIncrement(&NumberOfTerminatedProcesses);\n\n    return TRUE;\n}\n\nVOID PhZombieProcessesUpdateListView(\n    _In_ PPH_LIST UpdateList\n    )\n{\n    for (ULONG i = 0; i < UpdateList->Count; i++)\n    {\n        PPH_ZOMBIE_PROCESS_ENTRY entry = UpdateList->Items[i];\n        INT lvItemIndex;\n        WCHAR pidString[PH_INT32_STR_LEN_1];\n\n        if (entry->FileName)\n        {\n            PhMoveReference(&entry->FileName, PhGetFileName(entry->FileName));\n        }\n\n        lvItemIndex = PhAddListViewItem(\n            PhZombieProcessesListViewHandle,\n            MAXINT,\n            PhGetStringOrDefault(entry->FileName, L\"(unknown)\"),\n            entry\n            );\n        PhPrintUInt32(pidString, HandleToUlong(entry->ProcessId));\n        PhSetListViewSubItem(PhZombieProcessesListViewHandle, lvItemIndex, 1, pidString);\n\n        PhAddItemList(ProcessesList, entry);\n    }\n}\n\nNTSTATUS PhpCreateProcessItemForZombieProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_ZOMBIE_PROCESS_ENTRY Entry,\n    _Out_ PPH_PROCESS_ITEM* ProcessItem\n    )\n{\n    NTSTATUS status;\n    PPH_PROCESS_ITEM processItem;\n    HANDLE processHandle;\n\n    if (Entry->Type == NormalProcess)\n    {\n        if (processItem = PhReferenceProcessItem(Entry->ProcessId))\n        {\n            *ProcessItem = processItem;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    if (ProcessesMethod != CsrHandlesScanMethod)\n    {\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            Entry->ProcessId\n            );\n    }\n    else\n    {\n        status = PhOpenProcessByCsrHandles(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            Entry->ProcessId\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (processItem = PhCreateProcessItemFromHandle(\n            Entry->ProcessId,\n            processHandle,\n            Entry->Type == TerminatedProcess\n            ))\n        {\n            *ProcessItem = processItem;\n            return STATUS_SUCCESS;\n        }\n\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\nNTSTATUS PhpEnumZombieProcessesBruteForce(\n    _In_ PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n    PPH_LIST pids;\n    ULONG pid;\n    BOOLEAN stop = FALSE;\n\n    if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))\n        return status;\n\n    pids = PhCreateList(40);\n\n    process = PH_FIRST_PROCESS(processes);\n\n    do\n    {\n        PhAddItemList(pids, process->UniqueProcessId);\n    } while (process = PH_NEXT_PROCESS(process));\n\n    PhFree(processes);\n\n    for (pid = 8; pid <= 65536; pid += 4)\n    {\n        NTSTATUS status2;\n        HANDLE processHandle;\n        PH_ZOMBIE_PROCESS_ENTRY entry;\n        KERNEL_USER_TIMES times;\n        PPH_STRING fileName;\n\n        status2 = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            UlongToHandle(pid)\n            );\n\n        if (NT_SUCCESS(status2))\n        {\n            entry.ProcessId = UlongToHandle(pid);\n\n            if (NT_SUCCESS(status2 = PhGetProcessTimes(\n                processHandle,\n                &times\n                )) &&\n                NT_SUCCESS(status2 = PhGetProcessImageFileName(\n                processHandle,\n                &fileName\n                )))\n            {\n                entry.FileName = fileName;\n\n                if (times.ExitTime.QuadPart != 0)\n                    entry.Type = TerminatedProcess;\n                else if (PhFindItemList(pids, UlongToHandle(pid)) != ULONG_MAX)\n                    entry.Type = NormalProcess;\n                else\n                    entry.Type = ZombieProcess;\n\n                if (!Callback(&entry, Context))\n                    stop = TRUE;\n\n                PhDereferenceObject(fileName);\n            }\n\n            NtClose(processHandle);\n        }\n\n        // Use an alternative method if we don't have sufficient access.\n        if (status2 == STATUS_ACCESS_DENIED)\n        {\n            if (NT_SUCCESS(status2 = PhGetProcessImageFileNameByProcessId(UlongToHandle(pid), &fileName)))\n            {\n                entry.ProcessId = UlongToHandle(pid);\n                entry.FileName = fileName;\n\n                if (PhFindItemList(pids, UlongToHandle(pid)) != ULONG_MAX)\n                    entry.Type = NormalProcess;\n                else\n                    entry.Type = ZombieProcess;\n\n                if (!Callback(&entry, Context))\n                    stop = TRUE;\n\n                PhDereferenceObject(fileName);\n            }\n        }\n\n        if (status2 == STATUS_INVALID_CID || status2 == STATUS_INVALID_PARAMETER)\n            status2 = STATUS_SUCCESS;\n\n        if (!NT_SUCCESS(status2))\n        {\n            entry.ProcessId = UlongToHandle(pid);\n            entry.FileName = NULL;\n            entry.Type = UnknownProcess;\n\n            if (!Callback(&entry, Context))\n                stop = TRUE;\n        }\n\n        if (stop)\n            break;\n    }\n\n    PhDereferenceObject(pids);\n\n    return status;\n}\n\ntypedef struct _CSR_HANDLES_CONTEXT\n{\n    PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback;\n    PVOID Context;\n    PPH_LIST Pids;\n} CSR_HANDLES_CONTEXT, *PCSR_HANDLES_CONTEXT;\n\nstatic BOOLEAN NTAPI PhpCsrProcessHandlesCallback(\n    _In_ PPH_CSR_HANDLE_INFO Handle,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    BOOLEAN cont = TRUE;\n    PCSR_HANDLES_CONTEXT context = Context;\n    HANDLE processHandle;\n    KERNEL_USER_TIMES times;\n    PPH_STRING fileName;\n    PH_ZOMBIE_PROCESS_ENTRY entry;\n\n    entry.ProcessId = Handle->ProcessId;\n\n    if (NT_SUCCESS(status = PhOpenProcessByCsrHandle(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        Handle\n        )))\n    {\n        if (NT_SUCCESS(status = PhGetProcessTimes(\n            processHandle,\n            &times\n            )) &&\n            NT_SUCCESS(status = PhGetProcessImageFileName(\n            processHandle,\n            &fileName\n            )))\n        {\n            entry.FileName = fileName;\n\n            if (times.ExitTime.QuadPart != 0)\n                entry.Type = TerminatedProcess;\n            else if (context && PhFindItemList(context->Pids, Handle->ProcessId) != ULONG_MAX)\n                entry.Type = NormalProcess;\n            else\n                entry.Type = ZombieProcess;\n\n            if (context && !context->Callback(&entry, context->Context))\n                cont = FALSE;\n\n            PhDereferenceObject(fileName);\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        entry.FileName = NULL;\n        entry.Type = UnknownProcess;\n\n        if (context && !context->Callback(&entry, context->Context))\n            cont = FALSE;\n    }\n\n    return cont;\n}\n\nNTSTATUS PhpEnumZombieProcessesCsrHandles(\n    _In_ PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n    PPH_LIST pids;\n    CSR_HANDLES_CONTEXT context;\n\n    if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))\n        return status;\n\n    pids = PhCreateList(40);\n\n    process = PH_FIRST_PROCESS(processes);\n\n    do\n    {\n        PhAddItemList(pids, process->UniqueProcessId);\n    } while (process = PH_NEXT_PROCESS(process));\n\n    PhFree(processes);\n\n    context.Callback = Callback;\n    context.Context = Context;\n    context.Pids = pids;\n\n    status = PhEnumCsrProcessHandles(PhpCsrProcessHandlesCallback, &context);\n\n    PhDereferenceObject(pids);\n\n    return status;\n}\n\ntypedef struct _PH_ENUM_NEXT_PROCESS_CONTEXT\n{\n    PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback;\n    PVOID Context;\n} PH_ENUM_NEXT_PROCESS_CONTEXT, *PPH_ENUM_NEXT_PROCESS_CONTEXT;\n\nNTSTATUS NTAPI PhpEnumNextProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID Context\n    )\n{\n    PPH_ENUM_NEXT_PROCESS_CONTEXT context = Context;\n    PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n    NTSTATUS status;\n    PVOID processes = NULL;\n\n    status = PhGetProcessExtendedBasicInformation(ProcessHandle, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhEnumProcesses(&processes);\n\n        if (NT_SUCCESS(status))\n        {\n            if (!PhFindProcessInformation(processes, basicInfo.BasicInfo.UniqueProcessId))\n            {\n                PH_ZOMBIE_PROCESS_ENTRY entry;\n                PPH_STRING fileName;\n\n                entry.ProcessId = basicInfo.BasicInfo.UniqueProcessId;\n\n                if (NT_SUCCESS(PhGetProcessImageFileName(ProcessHandle, &fileName)))\n                {\n                    entry.FileName = fileName;\n                    entry.Type = ZombieProcess;\n\n                    //if (basicInfo.IsProcessDeleting)\n                    //    entry.Type = TerminatedProcess;\n\n                    if (!context->Callback(&entry, context->Context))\n                        goto CleanupExit;\n\n                    PhDereferenceObject(fileName);\n                }\n                else\n                {\n                    entry.FileName = NULL;\n                    entry.Type = UnknownProcess;\n\n                    if (!context->Callback(&entry, context->Context))\n                        goto CleanupExit;\n                }\n            }\n        }\n    }\n\nCleanupExit:\n    if (processes)\n    {\n        PhFree(processes);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhpEnumZombieProcessHandles(\n    _In_ PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PH_ENUM_NEXT_PROCESS_CONTEXT context;\n\n    context.Callback = Callback;\n    context.Context = Context;\n\n    status = PhEnumNextProcess(\n        NULL,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        PhpEnumNextProcessHandles,\n        &context\n        );\n\n    return status;\n}\n\nNTSTATUS PhpEnumZombieSubKeyHandles(\n    _In_ PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    ULONG bufferSize;\n    PKEY_OPEN_SUBKEYS_INFORMATION buffer;\n    UNICODE_STRING subkeyName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    bufferSize = 0x200;\n    buffer = PhAllocate(bufferSize);\n\n    RtlInitUnicodeString(&subkeyName, L\"\\\\REGISTRY\");\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &subkeyName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    while (TRUE)\n    {\n        status = NtQueryOpenSubKeysEx(\n            &objectAttributes,\n            bufferSize,\n            buffer,\n            &bufferSize\n            );\n\n        if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        for (ULONG i = 0; i < buffer->Count; i++)\n        {\n            KEY_PID_ARRAY entry = buffer->KeyArray[i];\n            HANDLE processHandle;\n\n            if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, entry.ProcessId)))\n            {\n                PVOID processes;\n\n                if (NT_SUCCESS(PhEnumProcesses(&processes)))\n                {\n                    if (!PhFindProcessInformation(processes, entry.ProcessId))\n                    {\n                        PH_ZOMBIE_PROCESS_ENTRY process;\n                        PPH_STRING fileName;\n\n                        process.ProcessId = entry.ProcessId;\n\n                        if (NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName)))\n                        {\n                            PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n\n                            process.FileName = fileName;\n                            process.Type = ZombieProcess;\n\n                            if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo)))\n                            {\n                                if (basicInfo.IsProcessDeleting)\n                                    process.Type = TerminatedProcess;\n                            }\n\n                            if (!Callback(&process, Context))\n                                break;\n\n                            PhDereferenceObject(fileName);\n                        }\n                        else\n                        {\n                            process.FileName = NULL;\n                            process.Type = UnknownProcess;\n\n                            if (!Callback(&process, Context))\n                                break;\n                        }\n                    }\n\n                    PhFree(processes);\n                }\n\n                NtClose(processHandle);\n            }\n            else\n            {\n                PH_ZOMBIE_PROCESS_ENTRY process;\n                PPH_STRING fileName;\n\n                process.ProcessId = entry.ProcessId;\n\n                if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(process.ProcessId, &fileName)))\n                {\n                    process.FileName = fileName;\n                    process.Type = ZombieProcess;\n\n                    if (!Callback(&process, Context))\n                        break;\n\n                    PhDereferenceObject(fileName);\n                }\n                else\n                {\n                    process.FileName = NULL;\n                    process.Type = UnknownProcess;\n\n                    if (!Callback(&process, Context))\n                        break;\n                }\n            }\n        }\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\n#define PH_FIRST_ETW_GUID(TraceGuid) \\\n    (((PETW_TRACE_GUID_INFO)(TraceGuid))->InstanceCount ? \\\n    ((PETW_TRACE_PROVIDER_INSTANCE_INFO)PTR_ADD_OFFSET(TraceGuid, \\\n    sizeof(ETW_TRACE_GUID_INFO))) : NULL)\n#define PH_NEXT_ETW_GUID(TraceGuid) \\\n    (((PETW_TRACE_PROVIDER_INSTANCE_INFO)(TraceGuid))->NextOffset ? \\\n    (PETW_TRACE_PROVIDER_INSTANCE_INFO)PTR_ADD_OFFSET((TraceGuid), \\\n    ((PETW_TRACE_PROVIDER_INSTANCE_INFO)(TraceGuid))->NextOffset) : NULL)\n\nNTSTATUS PhpEnumEtwGuidHandles(\n    _In_ PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PGUID traceGuidList = NULL;\n    ULONG traceGuidListLength = 0;\n\n    status = PhTraceControlVariableSize(\n        EtwEnumTraceGuidList,\n        NULL,\n        0,\n        &traceGuidList,\n        &traceGuidListLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        for (ULONG i = 0; i < traceGuidListLength / sizeof(GUID); i++)\n        {\n            GUID providerGuid = traceGuidList[i];\n            PETW_TRACE_GUID_INFO traceGuidInfo;\n\n            status = PhTraceControlVariableSize(\n                EtwGetTraceGuidInfo,\n                &providerGuid,\n                sizeof(GUID),\n                &traceGuidInfo,\n                NULL\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                PETW_TRACE_PROVIDER_INSTANCE_INFO instance;\n                HANDLE processHandle;\n                //PVOID processes;\n\n                for (instance = PH_FIRST_ETW_GUID(traceGuidInfo);\n                    instance;\n                    instance = PH_NEXT_ETW_GUID(instance))\n                {\n                    if (instance->Pid == 0)\n                        continue;\n\n                    if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, UlongToHandle(instance->Pid))))\n                    {\n                        PPH_PROCESS_ITEM processItem;\n\n                        processItem = PhReferenceProcessItem(UlongToHandle(instance->Pid));\n         \n                        //if (NT_SUCCESS(PhEnumProcesses(&processes)))\n                        {\n                            //if (!PhFindProcessInformation(processes, UlongToHandle(instance->Pid)))\n                            if (!processItem)\n                            {\n                                PH_ZOMBIE_PROCESS_ENTRY process;\n                                PPH_STRING fileName;\n\n                                process.ProcessId = UlongToHandle(instance->Pid);\n\n                                if (NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName)))\n                                {\n                                    PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n\n                                    process.FileName = fileName;\n                                    process.Type = ZombieProcess;\n\n                                    if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo)))\n                                    {\n                                        if (basicInfo.IsProcessDeleting)\n                                            process.Type = TerminatedProcess;\n                                    }\n\n                                    if (!Callback(&process, Context))\n                                        break;\n\n                                    PhDereferenceObject(fileName);\n                                }\n                                else\n                                {\n                                    process.FileName = NULL;\n                                    process.Type = UnknownProcess;\n\n                                    if (!Callback(&process, Context))\n                                        break;\n                                }\n                            }\n\n                            //PhFree(processes);\n                        }\n\n                        PhClearReference(&processItem);\n\n                        NtClose(processHandle);\n                    }\n                    else\n                    {\n                        PH_ZOMBIE_PROCESS_ENTRY process;\n                        PPH_STRING fileName;\n\n                        process.ProcessId = UlongToHandle(instance->Pid);\n\n                        if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(process.ProcessId, &fileName)))\n                        {\n                            process.FileName = fileName;\n                            process.Type = ZombieProcess;\n\n                            if (!Callback(&process, Context))\n                                break;\n\n                            PhDereferenceObject(process.FileName);\n                        }\n                        else\n                        {\n                            process.FileName = NULL;\n                            process.Type = UnknownProcess;\n\n                            if (!Callback(&process, Context))\n                                break;\n                        }\n                    }\n                }\n\n                PhFree(traceGuidInfo);\n            }\n        }\n\n        PhFree(traceGuidList);\n    }\n\n    return status;\n}\n\nNTSTATUS PhpEnumNtdllHandles(\n    _In_ PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    static CONST PH_STRINGREF ntdllPath = PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\ntdll.dll\");\n    static CONST PH_STRINGREF ntfsPath = PH_STRINGREF_INIT(L\"\\\\ntfs\");\n    NTSTATUS status;\n    HANDLE fileHandle;\n\n    status = PhCreateFile(\n        &fileHandle,\n        &ntfsPath,\n        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        status = PhCreateFile(\n            &fileHandle,\n            &ntdllPath,\n            FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        PFILE_PROCESS_IDS_USING_FILE_INFORMATION processIds;\n\n        status = PhGetProcessIdsUsingFile(\n            fileHandle,\n            &processIds\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            for (ULONG i = 0; i < processIds->NumberOfProcessIdsInList; i++)\n            {\n                HANDLE processId;\n                HANDLE processHandle;\n\n                processId = (HANDLE)processIds->ProcessIdList[i];\n\n                if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, processId)))\n                {\n                    PVOID processes;\n\n                    if (NT_SUCCESS(PhEnumProcesses(&processes)))\n                    {\n                        if (!PhFindProcessInformation(processes, processId))\n                        {\n                            PH_ZOMBIE_PROCESS_ENTRY process;\n                            PPH_STRING fileName;\n\n                            process.ProcessId = processId;\n\n                            if (NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName)))\n                            {\n                                PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n\n                                process.FileName = fileName;\n                                process.Type = ZombieProcess;\n\n                                if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo)))\n                                {\n                                    //if (basicInfo.IsProcessDeleting)\n                                    //    process.Type = TerminatedProcess;\n                                }\n\n                                if (!Callback(&process, Context))\n                                    break;\n\n                                PhDereferenceObject(fileName);\n                            }\n                            else\n                            {\n                                process.FileName = NULL;\n                                process.Type = UnknownProcess;\n\n                                if (!Callback(&process, Context))\n                                    break;\n                            }\n                        }\n\n                        PhFree(processes);\n                    }\n\n                    NtClose(processHandle);\n                }\n                else\n                {\n                    PH_ZOMBIE_PROCESS_ENTRY process;\n                    PPH_STRING fileName;\n\n                    process.ProcessId = processId;\n\n                    if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(process.ProcessId, &fileName)))\n                    {\n                        process.FileName = fileName;\n                        process.Type = ZombieProcess;\n\n                        if (!Callback(&process, Context))\n                            break;\n\n                        PhDereferenceObject(fileName);\n                    }\n                    else\n                    {\n                        process.FileName = NULL;\n                        process.Type = UnknownProcess;\n\n                        if (!Callback(&process, Context))\n                            break;\n                    }\n                }\n            }\n\n            PhFree(processIds);\n        }\n\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\nNTSTATUS PhEnumZombieProcesses(\n    _In_ PH_ZOMBIE_PROCESS_METHOD Method,\n    _In_ PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    switch (Method)\n    {\n    case BruteForceScanMethod:\n        return PhpEnumZombieProcessesBruteForce(Callback, Context);\n    case CsrHandlesScanMethod:\n        return PhpEnumZombieProcessesCsrHandles(Callback, Context);\n    case ProcessHandleScanMethod:\n        return PhpEnumZombieProcessHandles(Callback, Context);\n    case RegistryScanMethod:\n        return PhpEnumZombieSubKeyHandles(Callback, Context);\n    case EtwGuidScanMethod:\n        return PhpEnumEtwGuidHandles(Callback, Context);\n    case NtdllScanMethod:\n        return PhpEnumNtdllHandles(Callback, Context);\n    }\n\n    return STATUS_FAIL_CHECK;\n}\n\nNTSTATUS PhpOpenCsrProcesses(\n    _Out_ PHANDLE *ProcessHandles,\n    _Out_ PULONG NumberOfProcessHandles\n    )\n{\n    NTSTATUS status;\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n    PPH_LIST processHandleList;\n\n    if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))\n        return status;\n\n    processHandleList = PhCreateList(8);\n\n    process = PH_FIRST_PROCESS(processes);\n\n    do\n    {\n        HANDLE processHandle;\n        PH_KNOWN_PROCESS_TYPE knownProcessType;\n\n        if (NT_SUCCESS(PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_DUP_HANDLE,\n            process->UniqueProcessId\n            )))\n        {\n            if (NT_SUCCESS(PhGetProcessKnownType(\n                processHandle,\n                &knownProcessType\n                )) &&\n                (knownProcessType & KnownProcessTypeMask) == WindowsSubsystemProcessType)\n            {\n                PhAddItemList(processHandleList, processHandle);\n            }\n            else\n            {\n                NtClose(processHandle);\n            }\n        }\n    } while (process = PH_NEXT_PROCESS(process));\n\n    PhFree(processes);\n\n\n    if (processHandleList->Count)\n    {\n        *ProcessHandles = PhAllocateCopy(processHandleList->Items, processHandleList->Count * sizeof(HANDLE));\n        *NumberOfProcessHandles = processHandleList->Count;\n\n        PhDereferenceObject(processHandleList);\n\n        return status;\n    }\n\n    PhDereferenceObject(processHandleList);\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nNTSTATUS PhpGetCsrHandleProcessId(\n    _Inout_ PPH_CSR_HANDLE_INFO Handle\n    )\n{\n    NTSTATUS status;\n    PROCESS_BASIC_INFORMATION processBasicInfo;\n    THREAD_BASIC_INFORMATION threadBasicInfo;\n\n    Handle->IsThreadHandle = FALSE;\n    Handle->ProcessId = NULL;\n\n    // Assume the handle is a process handle, and get the\n    // process ID.\n\n    status = KphQueryInformationObject(\n        Handle->CsrProcessHandle,\n        Handle->Handle,\n        KphObjectProcessBasicInformation,\n        &processBasicInfo,\n        sizeof(PROCESS_BASIC_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        Handle->ProcessId = processBasicInfo.UniqueProcessId;\n    }\n    else\n    {\n        // We failed to get the process ID. Assume the handle\n        // is a thread handle, and get the process ID.\n\n        status = KphQueryInformationObject(\n            Handle->CsrProcessHandle,\n            Handle->Handle,\n            KphObjectThreadBasicInformation,\n            &threadBasicInfo,\n            sizeof(THREAD_BASIC_INFORMATION),\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            Handle->ProcessId = threadBasicInfo.ClientId.UniqueProcess;\n            Handle->IsThreadHandle = TRUE;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhEnumCsrProcessHandles(\n    _In_ PPH_ENUM_CSR_PROCESS_HANDLES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PHANDLE csrProcessHandles;\n    ULONG numberOfCsrProcessHandles;\n    ULONG i;\n    BOOLEAN stop = FALSE;\n    PPH_LIST pids;\n\n    if (!NT_SUCCESS(status = PhpOpenCsrProcesses(\n        &csrProcessHandles,\n        &numberOfCsrProcessHandles\n        )))\n        return status;\n\n    pids = PhCreateList(40);\n\n    for (i = 0; i < numberOfCsrProcessHandles; i++)\n    {\n        PKPH_PROCESS_HANDLE_INFORMATION handles;\n        ULONG j;\n\n        if (stop)\n            break;\n\n        if (NT_SUCCESS(KsiEnumerateProcessHandles(csrProcessHandles[i], &handles)))\n        {\n            for (j = 0; j < handles->HandleCount; j++)\n            {\n                PH_CSR_HANDLE_INFO handle;\n\n                handle.CsrProcessHandle = csrProcessHandles[i];\n                handle.Handle = handles->Handles[j].Handle;\n\n                // Get the process ID associated with the handle.\n                // This call will fail if the handle is not a\n                // process or thread handle.\n                if (!NT_SUCCESS(PhpGetCsrHandleProcessId(&handle)))\n                    continue;\n\n                // Avoid duplicate PIDs.\n                if (PhFindItemList(pids, handle.ProcessId) != ULONG_MAX)\n                    continue;\n\n                PhAddItemList(pids, handle.ProcessId);\n\n                if (!Callback(&handle, Context))\n                {\n                    stop = TRUE;\n                    break;\n                }\n            }\n\n            PhFree(handles);\n        }\n    }\n\n    PhDereferenceObject(pids);\n\n    for (i = 0; i < numberOfCsrProcessHandles; i++)\n        NtClose(csrProcessHandles[i]);\n\n    PhFree(csrProcessHandles);\n\n    return status;\n}\n\nNTSTATUS PhOpenProcessByCsrHandle(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPH_CSR_HANDLE_INFO Handle\n    )\n{\n    NTSTATUS status;\n\n    if (!Handle->IsThreadHandle)\n    {\n        status = NtDuplicateObject(\n            Handle->CsrProcessHandle,\n            Handle->Handle,\n            NtCurrentProcess(),\n            ProcessHandle,\n            DesiredAccess,\n            0,\n            0\n            );\n    }\n    else\n    {\n        HANDLE threadHandle;\n\n        if (!NT_SUCCESS(status = NtDuplicateObject(\n            Handle->CsrProcessHandle,\n            Handle->Handle,\n            NtCurrentProcess(),\n            &threadHandle,\n            THREAD_QUERY_LIMITED_INFORMATION,\n            0,\n            0\n            )))\n            return status;\n\n        status = KphOpenThreadProcess(\n            threadHandle,\n            DesiredAccess,\n            ProcessHandle\n            );\n        NtClose(threadHandle);\n    }\n\n    return status;\n}\n\ntypedef struct _OPEN_PROCESS_BY_CSR_CONTEXT\n{\n    NTSTATUS Status;\n    PHANDLE ProcessHandle;\n    ACCESS_MASK DesiredAccess;\n    HANDLE ProcessId;\n} OPEN_PROCESS_BY_CSR_CONTEXT, *POPEN_PROCESS_BY_CSR_CONTEXT;\n\nstatic BOOLEAN NTAPI PhpOpenProcessByCsrHandlesCallback(\n    _In_ PPH_CSR_HANDLE_INFO Handle,\n    _In_opt_ PVOID Context\n    )\n{\n    POPEN_PROCESS_BY_CSR_CONTEXT context = Context;\n\n    if (context && Handle->ProcessId == context->ProcessId)\n    {\n        context->Status = PhOpenProcessByCsrHandle(\n            context->ProcessHandle,\n            context->DesiredAccess,\n            Handle\n            );\n\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nNTSTATUS PhOpenProcessByCsrHandles(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    OPEN_PROCESS_BY_CSR_CONTEXT context;\n\n    context.Status = STATUS_INVALID_CID;\n    context.ProcessHandle = ProcessHandle;\n    context.DesiredAccess = DesiredAccess;\n    context.ProcessId = ProcessId;\n\n    if (!NT_SUCCESS(status = PhEnumCsrProcessHandles(\n        PhpOpenProcessByCsrHandlesCallback,\n        &context\n        )))\n        return status;\n\n    return context.Status;\n}\n"
  },
  {
    "path": "SystemInformer/hndllist.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2013\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <hndllist.h>\n\n#include <emenu.h>\n#include <secedit.h>\n#include <settings.h>\n\n#include <extmgri.h>\n#include <hndlprv.h>\n#include <phsettings.h>\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpHandleNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpHandleNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\nVOID PhpDestroyHandleNode(\n    _In_ PPH_HANDLE_NODE HandleNode\n    );\n\nVOID PhpRemoveHandleNode(\n    _In_ PPH_HANDLE_NODE HandleNode,\n    _In_ PPH_HANDLE_LIST_CONTEXT Context\n    );\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpHandleTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    );\n\nBOOLEAN NTAPI PhpHandleTreeNewCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\nVOID PhInitializeHandleList(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND TreeNewHandle,\n    _Out_ PPH_HANDLE_LIST_CONTEXT Context\n    )\n{\n    HWND hwnd;\n\n    memset(Context, 0, sizeof(PH_HANDLE_LIST_CONTEXT));\n    Context->EnableStateHighlighting = TRUE;\n\n    Context->NodeHashtable = PhCreateHashtable(\n        sizeof(PPH_HANDLE_NODE),\n        PhpHandleNodeHashtableEqualFunction,\n        PhpHandleNodeHashtableHashFunction,\n        100\n        );\n    Context->NodeList = PhCreateList(100);\n\n    Context->ParentWindowHandle = ParentWindowHandle;\n    Context->TreeNewHandle = TreeNewHandle;\n    hwnd = TreeNewHandle;\n    PhSetControlTheme(hwnd, L\"explorer\");\n\n    TreeNew_SetCallback(hwnd, PhpHandleTreeNewCallback, Context);\n\n    TreeNew_SetRedraw(hwnd, FALSE);\n\n    // Default columns\n    PhAddTreeNewColumn(hwnd, PHHNTLC_TYPE, TRUE, L\"Type\", 100, PH_ALIGN_LEFT, 0, 0);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_NAME, TRUE, L\"Name\", 200, PH_ALIGN_LEFT, 1, 0);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESSSYMBOLIC, TRUE, L\"Granted access (symbolic)\", 140, PH_ALIGN_LEFT, 2, 0);\n\n    PhAddTreeNewColumn(hwnd, PHHNTLC_HANDLE, FALSE, L\"Handle\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_OBJECTADDRESS, FALSE, L\"Object address\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHHNTLC_ATTRIBUTES, FALSE, L\"Attributes\", 120, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESS, FALSE, L\"Granted access\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_ORIGINALNAME, FALSE, L\"Original name\", 200, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHHNTLC_FILESHAREACCESS, FALSE, L\"File share access\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_HANDLEVALUE, FALSE, L\"Handle value\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_HANDLECOUNT, FALSE, L\"Handle count\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_POINTERCOUNT, FALSE, L\"Reference count\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_PAGEDSIZE, FALSE, L\"Paged size\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHHNTLC_NONPAGEDSIZE, FALSE, L\"Nonpaged size\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n\n    TreeNew_SetRedraw(hwnd, TRUE);\n\n    TreeNew_SetSort(hwnd, 0, AscendingSortOrder);\n\n    PhCmInitializeManager(&Context->Cm, hwnd, PHHNTLC_MAXIMUM, PhpHandleTreeNewPostSortFunction);\n\n    PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, hwnd, Context->NodeList);\n}\n\nVOID PhDeleteHandleList(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport);\n\n    PhCmDeleteManager(&Context->Cm);\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n        PhpDestroyHandleNode(Context->NodeList->Items[i]);\n\n    PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpHandleNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_HANDLE_NODE handleNode1 = *(PPH_HANDLE_NODE *)Entry1;\n    PPH_HANDLE_NODE handleNode2 = *(PPH_HANDLE_NODE *)Entry2;\n\n    return handleNode1->Handle == handleNode2->Handle;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpHandleNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return HandleToUlong((*(PPH_HANDLE_NODE *)Entry)->Handle) / 4;\n}\n\nVOID PhLoadSettingsHandleList(\n    _Inout_ PPH_HANDLE_LIST_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhGetStringSetting(SETTING_HANDLE_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_HANDLE_TREE_LIST_SORT);\n    Context->Flags = PhGetIntegerSetting(SETTING_HANDLE_TREE_LIST_FLAGS);\n\n    PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSaveSettingsHandleList(\n    _Inout_ PPH_HANDLE_LIST_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings);\n\n    PhSetIntegerSetting(SETTING_HANDLE_TREE_LIST_FLAGS, Context->Flags);\n    PhSetStringSetting2(SETTING_HANDLE_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_HANDLE_TREE_LIST_SORT, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSetOptionsHandleList(\n    _Inout_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ ULONG Options\n    )\n{\n    switch (Options)\n    {\n    case PH_HANDLE_TREE_MENUITEM_HIDE_PROTECTED_HANDLES:\n        Context->HideProtectedHandles = !Context->HideProtectedHandles;\n        break;\n    case PH_HANDLE_TREE_MENUITEM_HIDE_INHERIT_HANDLES:\n        Context->HideInheritHandles = !Context->HideInheritHandles;\n        break;\n    case PH_HANDLE_TREE_MENUITEM_HIDE_UNNAMED_HANDLES:\n        Context->HideUnnamedHandles = !Context->HideUnnamedHandles;\n        break;\n    case PH_HANDLE_TREE_MENUITEM_HIDE_ETW_HANDLES:\n        Context->HideEtwHandles = !Context->HideEtwHandles;\n        break;\n    }\n}\n\nPPH_HANDLE_NODE PhAddHandleNode(\n    _Inout_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ PPH_HANDLE_ITEM HandleItem,\n    _In_ ULONG RunId\n    )\n{\n    PPH_HANDLE_NODE handleNode;\n\n    handleNode = PhAllocate(PhEmGetObjectSize(EmHandleNodeType, sizeof(PH_HANDLE_NODE)));\n    memset(handleNode, 0, sizeof(PH_HANDLE_NODE));\n    PhInitializeTreeNewNode(&handleNode->Node);\n\n    if (Context->EnableStateHighlighting && RunId != 1)\n    {\n        PhChangeShStateTn(\n            &handleNode->Node,\n            &handleNode->ShState,\n            &Context->NodeStateList,\n            NewItemState,\n            PhCsColorNew,\n            NULL\n            );\n    }\n\n    handleNode->Handle = HandleItem->Handle;\n    handleNode->HandleItem = HandleItem;\n    PhReferenceObject(HandleItem);\n\n    memset(handleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHHNTLC_MAXIMUM);\n    handleNode->Node.TextCache = handleNode->TextCache;\n    handleNode->Node.TextCacheSize = PHHNTLC_MAXIMUM;\n\n    PhAddEntryHashtable(Context->NodeHashtable, &handleNode);\n    PhAddItemList(Context->NodeList, handleNode);\n\n    if (Context->TreeFilterSupport.FilterList)\n        handleNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &handleNode->Node);\n\n    PhEmCallObjectOperation(EmHandleNodeType, handleNode, EmObjectCreate);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    return handleNode;\n}\n\nPPH_HANDLE_NODE PhFindHandleNode(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ HANDLE Handle\n    )\n{\n    PH_HANDLE_NODE lookupHandleNode;\n    PPH_HANDLE_NODE lookupHandleNodePtr = &lookupHandleNode;\n    PPH_HANDLE_NODE *handleNode;\n\n    lookupHandleNode.Handle = Handle;\n\n    handleNode = (PPH_HANDLE_NODE *)PhFindEntryHashtable(\n        Context->NodeHashtable,\n        &lookupHandleNodePtr\n        );\n\n    if (handleNode)\n        return *handleNode;\n    else\n        return NULL;\n}\n\nVOID PhRemoveHandleNode(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ PPH_HANDLE_NODE HandleNode\n    )\n{\n    // Remove from the hashtable here to avoid problems in case the key is re-used.\n    PhRemoveEntryHashtable(Context->NodeHashtable, &HandleNode);\n\n    if (Context->EnableStateHighlighting)\n    {\n        PhChangeShStateTn(\n            &HandleNode->Node,\n            &HandleNode->ShState,\n            &Context->NodeStateList,\n            RemovingItemState,\n            PhCsColorRemoved,\n            Context->TreeNewHandle\n            );\n    }\n    else\n    {\n        PhpRemoveHandleNode(HandleNode, Context);\n    }\n}\n\nVOID PhpDestroyHandleNode(\n    _In_ PPH_HANDLE_NODE HandleNode\n    )\n{\n    PhEmCallObjectOperation(EmHandleNodeType, HandleNode, EmObjectDelete);\n\n    if (HandleNode->GrantedAccessSymbolicText) PhDereferenceObject(HandleNode->GrantedAccessSymbolicText);\n    if (HandleNode->HandleValue) PhDereferenceObject(HandleNode->HandleValue);\n    if (HandleNode->HandleCountText) PhDereferenceObject(HandleNode->HandleCountText);\n    if (HandleNode->PointerCountText) PhDereferenceObject(HandleNode->PointerCountText);\n    if (HandleNode->PageSizeText) PhDereferenceObject(HandleNode->PageSizeText);\n    if (HandleNode->NonPageSizeText) PhDereferenceObject(HandleNode->NonPageSizeText);\n\n    PhDereferenceObject(HandleNode->HandleItem);\n\n    PhFree(HandleNode);\n}\n\nVOID PhpRemoveHandleNode(\n    _In_ PPH_HANDLE_NODE HandleNode,\n    _In_ PPH_HANDLE_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after HandleNode\n    )\n{\n    ULONG index;\n\n    // Remove from list and cleanup.\n\n    if ((index = PhFindItemList(Context->NodeList, HandleNode)) != ULONG_MAX)\n        PhRemoveItemList(Context->NodeList, index);\n\n    PhpDestroyHandleNode(HandleNode);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhUpdateHandleNode(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ PPH_HANDLE_NODE HandleNode\n    )\n{\n    memset(HandleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHHNTLC_MAXIMUM);\n\n    PhInvalidateTreeNewNode(&HandleNode->Node, TN_CACHE_COLOR);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhExpandAllHandleNodes(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ BOOLEAN Expand\n    )\n{\n    ULONG i;\n    BOOLEAN needsRestructure = FALSE;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_HANDLE_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Expanded != Expand)\n        {\n            node->Node.Expanded = Expand;\n            needsRestructure = TRUE;\n        }\n    }\n\n    if (needsRestructure)\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhTickHandleNodes(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context\n    )\n{\n    PH_TICK_SH_STATE_TN(PH_HANDLE_NODE, ShState, Context->NodeStateList, PhpRemoveHandleNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context);\n}\n\n#define SORT_FUNCTION(Column) PhpHandleTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpHandleTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_HANDLE_LIST_CONTEXT context = (PPH_HANDLE_LIST_CONTEXT)_context; \\\n    PPH_HANDLE_NODE node1 = *(PPH_HANDLE_NODE *)_elem1; \\\n    PPH_HANDLE_NODE node2 = *(PPH_HANDLE_NODE *)_elem2; \\\n    PPH_HANDLE_ITEM handleItem1 = node1->HandleItem; \\\n    PPH_HANDLE_ITEM handleItem2 = node2->HandleItem; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)node1->Handle, (ULONG_PTR)node2->Handle); \\\n    \\\n    return PhModifySort(sortResult, context->TreeNewSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpHandleTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    if (Result == 0)\n        Result = uintptrcmp((ULONG_PTR)((PPH_HANDLE_NODE)Node1)->Handle, (ULONG_PTR)((PPH_HANDLE_NODE)Node2)->Handle);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(Type)\n{\n    sortResult = PhCompareStringWithNullSortOrder(handleItem1->TypeName, handleItem2->TypeName, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareStringWithNullSortOrder(handleItem1->BestObjectName, handleItem2->BestObjectName, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Handle)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->Handle, (ULONG_PTR)node2->Handle);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ObjectAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)handleItem1->Object, (ULONG_PTR)handleItem2->Object);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Attributes)\n{\n    sortResult = uintcmp(handleItem1->Attributes, handleItem2->Attributes);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(GrantedAccess)\n{\n    sortResult = uintcmp(handleItem1->GrantedAccess, handleItem2->GrantedAccess);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(OriginalName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(handleItem1->ObjectName, handleItem2->ObjectName, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileShareAccess)\n{\n    sortResult = uintcmp(handleItem1->FileFlags & (PH_HANDLE_FILE_SHARED_MASK), handleItem2->FileFlags & (PH_HANDLE_FILE_SHARED_MASK));\n\n    // Make sure all file handles get grouped together regardless of share access.\n    if (sortResult == 0 && !PhIsNullOrEmptyString(handleItem1->TypeName))\n        sortResult = intcmp(PhEqualString2(handleItem1->TypeName, L\"File\", TRUE), PhEqualString2(handleItem2->TypeName, L\"File\", TRUE));\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(HandleCount)\n{\n    sortResult = uintcmp(handleItem1->HandleCount, handleItem2->HandleCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PointerCount)\n{\n    sortResult = uintcmp(handleItem1->PointerCount, handleItem2->PointerCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PagedPoolCharge)\n{\n    sortResult = uintcmp(handleItem1->PagedPoolCharge, handleItem2->PagedPoolCharge);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(NonPagedPoolCharge)\n{\n    sortResult = uintcmp(handleItem1->NonPagedPoolCharge, handleItem2->NonPagedPoolCharge);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpHandleTreeNewCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_HANDLE_LIST_CONTEXT context = Context;\n    PPH_HANDLE_NODE node;\n\n    if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm))\n        return TRUE;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n\n            if (!getChildren->Node)\n            {\n                static PVOID sortFunctions[] =\n                {\n                    SORT_FUNCTION(Type),\n                    SORT_FUNCTION(Name),\n                    SORT_FUNCTION(Handle),\n                    SORT_FUNCTION(ObjectAddress),\n                    SORT_FUNCTION(Attributes),\n                    SORT_FUNCTION(GrantedAccess),\n                    SORT_FUNCTION(GrantedAccess), // Granted Access (Symbolic)\n                    SORT_FUNCTION(OriginalName),\n                    SORT_FUNCTION(FileShareAccess),\n                    SORT_FUNCTION(Handle),\n                    SORT_FUNCTION(HandleCount),\n                    SORT_FUNCTION(PointerCount),\n                    SORT_FUNCTION(PagedPoolCharge),\n                    SORT_FUNCTION(NonPagedPoolCharge),\n                };\n                int (__cdecl *sortFunction)(void *, const void *, const void *);\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PHHNTLC_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (!PhCmForwardSort(\n                    (PPH_TREENEW_NODE *)context->NodeList->Items,\n                    context->NodeList->Count,\n                    context->TreeNewSortColumn,\n                    context->TreeNewSortOrder,\n                    &context->Cm\n                    ))\n                {\n                    if (context->TreeNewSortColumn < PHHNTLC_MAXIMUM)\n                        sortFunction = sortFunctions[context->TreeNewSortColumn];\n                    else\n                        sortFunction = NULL;\n                }\n                else\n                {\n                    sortFunction = NULL;\n                }\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            PPH_HANDLE_ITEM handleItem;\n\n            node = (PPH_HANDLE_NODE)getCellText->Node;\n            handleItem = node->HandleItem;\n\n            switch (getCellText->Id)\n            {\n            case PHHNTLC_TYPE:\n                getCellText->Text = PhGetStringRef(handleItem->TypeName);\n                break;\n            case PHHNTLC_NAME:\n                getCellText->Text = PhGetStringRef(handleItem->BestObjectName);\n                break;\n            case PHHNTLC_HANDLE:\n                {\n                    PhInitializeStringRefLongHint(&getCellText->Text, handleItem->HandleString);\n                }\n                break;\n            case PHHNTLC_OBJECTADDRESS:\n                {\n                    if (handleItem->Object)\n                        PhInitializeStringRefLongHint(&getCellText->Text, handleItem->ObjectString);\n                }\n                break;\n            case PHHNTLC_ATTRIBUTES:\n                {\n                    switch (handleItem->Attributes & (OBJ_PROTECT_CLOSE | OBJ_INHERIT))\n                    {\n                    case OBJ_PROTECT_CLOSE:\n                        PhInitializeStringRef(&getCellText->Text, L\"Protected\");\n                        break;\n                    case OBJ_INHERIT:\n                        PhInitializeStringRef(&getCellText->Text, L\"Inherit\");\n                        break;\n                    case OBJ_PROTECT_CLOSE | OBJ_INHERIT:\n                        PhInitializeStringRef(&getCellText->Text, L\"Protected, Inherit\");\n                        break;\n                    }\n                }\n                break;\n            case PHHNTLC_GRANTEDACCESS:\n                {\n                    PhInitializeStringRefLongHint(&getCellText->Text, handleItem->GrantedAccessString);\n                }\n                break;\n            case PHHNTLC_GRANTEDACCESSSYMBOLIC:\n                {\n                    if (handleItem->GrantedAccess != 0)\n                    {\n                        if (!node->GrantedAccessSymbolicText)\n                        {\n                            PPH_ACCESS_ENTRY accessEntries;\n                            ULONG numberOfAccessEntries;\n\n                            if (PhGetAccessEntries(PhGetStringOrEmpty(handleItem->TypeName), &accessEntries, &numberOfAccessEntries))\n                            {\n                                node->GrantedAccessSymbolicText = PhGetAccessString(handleItem->GrantedAccess, accessEntries, numberOfAccessEntries);\n                                PhFree(accessEntries);\n                            }\n                        }\n\n                        getCellText->Text = PhGetStringRef(node->GrantedAccessSymbolicText);\n                    }\n                }\n                break;\n            case PHHNTLC_ORIGINALNAME:\n                {\n                    getCellText->Text = PhGetStringRef(handleItem->ObjectName);\n                }\n                break;\n            case PHHNTLC_FILESHAREACCESS:\n                {\n                    if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_MASK)\n                    {\n                        node->FileShareAccessText[0] = L'-';\n                        node->FileShareAccessText[1] = L'-';\n                        node->FileShareAccessText[2] = L'-';\n                        node->FileShareAccessText[3] = UNICODE_NULL;\n\n                        if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_READ)\n                            node->FileShareAccessText[0] = L'R';\n                        if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_WRITE)\n                            node->FileShareAccessText[1] = L'W';\n                        if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_DELETE)\n                            node->FileShareAccessText[2] = L'D';\n\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->FileShareAccessText);\n                    }\n                }\n                break;\n            case PHHNTLC_HANDLEVALUE:\n                {\n                    PhMoveReference(&node->HandleValue, PhFormatUInt64((HANDLE_PTR)handleItem->Handle, FALSE));\n                    getCellText->Text = PhGetStringRef(node->HandleValue);\n                }\n                break;\n            case PHHNTLC_HANDLECOUNT:\n                {\n                    if (handleItem->HandleCount != 0)\n                    {\n                        PhMoveReference(&node->HandleCountText, PhFormatUInt64(handleItem->HandleCount, FALSE));\n                        getCellText->Text = PhGetStringRef(node->HandleCountText);\n                    }\n                }\n                break;\n            case PHHNTLC_POINTERCOUNT:\n                {\n                    if (handleItem->PointerCount != 0)\n                    {\n                        PhMoveReference(&node->PointerCountText, PhFormatUInt64(handleItem->PointerCount, FALSE));\n                        getCellText->Text = PhGetStringRef(node->PointerCountText);\n                    }\n                }\n                break;\n            case PHHNTLC_PAGEDSIZE:\n                {\n                    if (handleItem->PagedPoolCharge != 0)\n                    {\n                        PhMoveReference(&node->PageSizeText, PhFormatSize(handleItem->PagedPoolCharge, ULONG_MAX));\n                        getCellText->Text = PhGetStringRef(node->PageSizeText);\n                    }\n                }\n                break;\n            case PHHNTLC_NONPAGEDSIZE:\n                {\n                    if (handleItem->NonPagedPoolCharge != 0)\n                    {\n                        PhMoveReference(&node->NonPageSizeText, PhFormatSize(handleItem->NonPagedPoolCharge, ULONG_MAX));\n                        getCellText->Text = PhGetStringRef(node->NonPageSizeText);\n                    }\n                }\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            PPH_HANDLE_ITEM handleItem;\n\n            node = (PPH_HANDLE_NODE)getNodeColor->Node;\n            handleItem = node->HandleItem;\n\n            if (!handleItem)\n                ; // Dummy\n            else if (PhCsUseColorProtectedInheritHandles && FlagOn(handleItem->Attributes, OBJ_PROTECT_CLOSE) && FlagOn(handleItem->Attributes, OBJ_INHERIT))\n                getNodeColor->BackColor = PhCsColorProtectedInheritHandles;\n            else if (PhCsUseColorProtectedHandles && FlagOn(handleItem->Attributes, OBJ_PROTECT_CLOSE))\n                getNodeColor->BackColor = PhCsColorProtectedHandles;\n            else if (PhCsUseColorInheritHandles && FlagOn(handleItem->Attributes, OBJ_INHERIT))\n                getNodeColor->BackColor = PhCsColorInheritHandles;\n\n            getNodeColor->Flags = TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(hwnd);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_COPY, 0);\n                break;\n            case VK_DELETE:\n                // Pass a 1 in lParam to indicate that warnings should be enabled.\n                SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_CLOSE, 1);\n                break;\n            case VK_RETURN:\n                if (GetKeyState(VK_CONTROL) >= 0)\n                    SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_PROPERTIES, 0);\n                else\n                    SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_OBJECTPROPERTIES1, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            memset(&data, 0, sizeof(PH_TN_COLUMN_MENU_DATA));\n            data.TreeNewHandle = hwnd;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = PHHNTLC_TYPE;\n            data.DefaultSortOrder = AscendingSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_PROPERTIES, 0);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n\n            SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu);\n        }\n        return TRUE;\n    case TreeNewGetDialogCode:\n        {\n            PULONG code = Parameter2;\n\n            if (PtrToUlong(Parameter1) == VK_RETURN)\n            {\n                *code = DLGC_WANTMESSAGE;\n                return TRUE;\n            }\n        }\n        return FALSE;\n    }\n\n    return FALSE;\n}\n\nPPH_HANDLE_ITEM PhGetSelectedHandleItem(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context\n    )\n{\n    PPH_HANDLE_ITEM handleItem = NULL;\n    ULONG i;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_HANDLE_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            handleItem = node->HandleItem;\n            break;\n        }\n    }\n\n    return handleItem;\n}\n\nVOID PhGetSelectedHandleItems(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _Out_ PPH_HANDLE_ITEM **Handles,\n    _Out_ PULONG NumberOfHandles\n    )\n{\n    PH_ARRAY array;\n    ULONG i;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_HANDLE_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n            PhAddItemArray(&array, &node->HandleItem);\n    }\n\n    *NumberOfHandles = (ULONG)PhFinalArrayCount(&array);\n    *Handles = PhFinalArrayItems(&array);\n}\n\nVOID PhDeselectAllHandleNodes(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context\n    )\n{\n    TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1);\n}\n"
  },
  {
    "path": "SystemInformer/hndlmenu.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *\n */\n\n#include <phapp.h>\n#include <hndlmenu.h>\n\n#include <emenu.h>\n#include <hndlinfo.h>\n#include <kphuser.h>\n#include <phsettings.h>\n#include <mainwnd.h>\n#include <procprp.h>\n#include <procprv.h>\n\nVOID PhInsertHandleObjectPropertiesEMenuItems(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG InsertBeforeId,\n    _In_ BOOLEAN EnableShortcut,\n    _In_ PPH_HANDLE_ITEM_INFO Info\n    )\n{\n    PPH_EMENU_ITEM parentItem;\n    ULONG indexInParent;\n\n    if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertBeforeId, &parentItem, &indexInParent))\n        return;\n\n    if (PhIsNullOrEmptyString(Info->TypeName))\n        return;\n\n    if (PhEqualString2(Info->TypeName, L\"File\", TRUE) || PhEqualString2(Info->TypeName, L\"DLL\", TRUE) ||\n        PhEqualString2(Info->TypeName, L\"Mapped file\", TRUE) || PhEqualString2(Info->TypeName, L\"Mapped image\", TRUE))\n    {\n        if (PhEqualString2(Info->TypeName, L\"File\", TRUE))\n        {\n            PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES2, L\"File propert&ies\", NULL, NULL), indexInParent);\n            PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L\"Open &file location\", EnableShortcut), NULL, NULL), indexInParent + 1);\n            PhInsertEMenuItem(parentItem, PhCreateEMenuSeparator(), indexInParent + 2);\n        }\n        else\n        {\n            PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L\"Open &file location\", EnableShortcut), NULL, NULL), indexInParent);\n            PhInsertEMenuItem(parentItem, PhCreateEMenuSeparator(), indexInParent + 1);\n        }\n    }\n    else if (PhEqualString2(Info->TypeName, L\"Key\", TRUE))\n    {\n        PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L\"Open &key\", EnableShortcut), NULL, NULL), indexInParent);\n        PhInsertEMenuItem(parentItem, PhCreateEMenuSeparator(), indexInParent + 1);\n    }\n    else if (PhEqualString2(Info->TypeName, L\"Process\", TRUE))\n    {\n        PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_GOTOOWNINGPROCESS, L\"Go to process...\", NULL, NULL), indexInParent);\n        PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L\"Process propert&ies\", EnableShortcut), NULL, NULL), indexInParent + 1);\n        PhInsertEMenuItem(parentItem, PhCreateEMenuSeparator(), indexInParent + 2);\n    }\n    else if (PhEqualString2(Info->TypeName, L\"Section\", TRUE))\n    {\n        PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L\"Read/Write &memory\", EnableShortcut), NULL, NULL), indexInParent);\n        PhInsertEMenuItem(parentItem, PhCreateEMenuSeparator(), indexInParent + 1);\n    }\n    else if (PhEqualString2(Info->TypeName, L\"Thread\", TRUE))\n    {\n        PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L\"Go to t&hread...\", EnableShortcut), NULL, NULL), indexInParent);\n        PhInsertEMenuItem(parentItem, PhCreateEMenuSeparator(), indexInParent + 1);\n    }\n}\n\nstatic NTSTATUS PhpDuplicateHandleFromProcessItem(\n    _Out_ PHANDLE NewHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE Handle\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_DUP_HANDLE,\n        ProcessId\n        )))\n        return status;\n\n    status = NtDuplicateObject(\n        processHandle,\n        Handle,\n        NtCurrentProcess(),\n        NewHandle,\n        DesiredAccess,\n        0,\n        0\n        );\n    NtClose(processHandle);\n\n    return status;\n}\n\nstatic VOID PhpShowProcessPropContext(\n    _In_ PVOID Parameter\n    )\n{\n    PhShowProcessProperties(Parameter);\n    PhDereferenceObject(Parameter);\n}\n\nVOID PhShowHandleObjectProperties1(\n    _In_ HWND hWnd,\n    _In_ PPH_HANDLE_ITEM_INFO Info\n    )\n{\n    if (PhIsNullOrEmptyString(Info->TypeName))\n        return;\n\n    if (PhEqualString2(Info->TypeName, L\"File\", TRUE) || PhEqualString2(Info->TypeName, L\"DLL\", TRUE) ||\n        PhEqualString2(Info->TypeName, L\"Mapped file\", TRUE) || PhEqualString2(Info->TypeName, L\"Mapped image\", TRUE))\n    {\n        if (Info->BestObjectName)\n        {\n            PhShellExecuteUserString(\n                hWnd,\n                SETTING_FILE_BROWSE_EXECUTABLE,\n                Info->BestObjectName->Buffer,\n                FALSE,\n                L\"Make sure the Explorer executable file is present.\"\n                );\n        }\n        else\n            PhShowError2(hWnd, L\"Unable to open the file location.\", L\"%s\", L\"The object is unnamed.\");\n    }\n    else if (PhEqualString2(Info->TypeName, L\"Key\", TRUE))\n    {\n        if (Info->BestObjectName)\n            PhShellOpenKey2(hWnd, Info->BestObjectName);\n        else\n            PhShowError2(hWnd, L\"Unable to open key.\", L\"%s\", L\"The object is unnamed.\");\n    }\n    else if (PhEqualString2(Info->TypeName, L\"Process\", TRUE))\n    {\n        HANDLE processHandle;\n        HANDLE processId;\n        PPH_PROCESS_ITEM targetProcessItem;\n\n        processId = NULL;\n\n        if (KsiLevel() >= KphLevelMed)\n        {\n            if (NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION,\n                Info->ProcessId\n                )))\n            {\n                PROCESS_BASIC_INFORMATION basicInfo;\n\n                if (NT_SUCCESS(KphQueryInformationObject(\n                    processHandle,\n                    Info->Handle,\n                    KphObjectProcessBasicInformation,\n                    &basicInfo,\n                    sizeof(PROCESS_BASIC_INFORMATION),\n                    NULL\n                    )))\n                {\n                    processId = basicInfo.UniqueProcessId;\n                }\n\n                NtClose(processHandle);\n            }\n        }\n        else\n        {\n            HANDLE handle;\n            PROCESS_BASIC_INFORMATION basicInfo;\n\n            if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem(\n                &handle,\n                PROCESS_QUERY_LIMITED_INFORMATION,\n                Info->ProcessId,\n                Info->Handle\n                )))\n            {\n                if (NT_SUCCESS(PhGetProcessBasicInformation(handle, &basicInfo)))\n                    processId = basicInfo.UniqueProcessId;\n\n                NtClose(handle);\n            }\n        }\n\n        if (processId)\n        {\n            targetProcessItem = PhReferenceProcessItem(processId);\n\n            if (!targetProcessItem)\n            {\n                NTSTATUS status;\n\n                status = PhOpenProcess(\n                    &processHandle,\n                    PROCESS_QUERY_LIMITED_INFORMATION,\n                    processId\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    targetProcessItem = PhCreateProcessItemFromHandle(\n                        processId,\n                        processHandle,\n                        TRUE\n                        );\n                }\n            }\n\n            if (targetProcessItem)\n            {\n                SystemInformer_ShowProcessProperties(targetProcessItem);\n                PhDereferenceObject(targetProcessItem);\n            }\n            else\n            {\n                PhShowError2(hWnd, L\"Unable to show the process properties.\", L\"%s\", L\"The process does not exist.\");\n            }\n        }\n    }\n    else if (PhEqualString2(Info->TypeName, L\"Section\", TRUE))\n    {\n        NTSTATUS status;\n        HANDLE handle = NULL;\n        BOOLEAN readOnly = FALSE;\n\n        if (!NT_SUCCESS(status = PhpDuplicateHandleFromProcessItem(\n            &handle,\n            SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,\n            Info->ProcessId,\n            Info->Handle\n            )))\n        {\n            status = PhpDuplicateHandleFromProcessItem(\n                &handle,\n                SECTION_QUERY | SECTION_MAP_READ,\n                Info->ProcessId,\n                Info->Handle\n                );\n            readOnly = TRUE;\n        }\n\n        if (handle)\n        {\n            PPH_STRING sectionName = NULL;\n            SECTION_BASIC_INFORMATION basicInfo;\n            SIZE_T viewSize = PH_MAX_SECTION_EDIT_SIZE;\n            PVOID viewBase = NULL;\n            BOOLEAN tooBig = FALSE;\n\n            PhGetHandleInformation(NtCurrentProcess(), handle, ULONG_MAX, NULL, NULL, NULL, &sectionName);\n\n            if (NT_SUCCESS(status = PhGetSectionBasicInformation(handle, &basicInfo)))\n            {\n                if (basicInfo.MaximumSize.QuadPart <= PH_MAX_SECTION_EDIT_SIZE)\n                    viewSize = (SIZE_T)basicInfo.MaximumSize.QuadPart;\n                else\n                    tooBig = TRUE;\n\n                status = PhMapViewOfSection(\n                    handle,\n                    NtCurrentProcess(),\n                    &viewBase,\n                    0,\n                    NULL,\n                    &viewSize,\n                    ViewUnmap,\n                    0,\n                    readOnly ? PAGE_READONLY : PAGE_READWRITE\n                    );\n\n                if (status == STATUS_SECTION_PROTECTION && !readOnly)\n                {\n                    status = PhMapViewOfSection(\n                        handle,\n                        NtCurrentProcess(),\n                        &viewBase,\n                        0,\n                        NULL,\n                        &viewSize,\n                        ViewUnmap,\n                        0,\n                        PAGE_READONLY\n                        );\n                }\n\n                if (NT_SUCCESS(status))\n                {\n                    PPH_SHOW_MEMORY_EDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOW_MEMORY_EDITOR));\n\n                    if (tooBig)\n                    {\n                        PhShowWarning2(hWnd, L\"Unable to map a view of the section.\", L\"%s\", L\"The section size is greater than 32 MB. Only the first 32 MB will be available.\");\n                    }\n\n                    memset(showMemoryEditor, 0, sizeof(PH_SHOW_MEMORY_EDITOR));\n                    showMemoryEditor->ProcessId = NtCurrentProcessId();\n                    showMemoryEditor->BaseAddress = viewBase;\n                    showMemoryEditor->RegionSize = viewSize;\n                    showMemoryEditor->SelectOffset = ULONG_MAX;\n                    showMemoryEditor->SelectLength = 0;\n                    showMemoryEditor->Title = sectionName ? PhConcatStrings2(L\"Section - \", sectionName->Buffer) : PhCreateString(L\"Section\");\n                    showMemoryEditor->Flags = PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION;\n                    SystemInformer_ShowMemoryEditor(showMemoryEditor);\n                }\n                else\n                {\n                    PhShowStatus(hWnd, L\"Unable to map a view of the section.\", status, 0);\n                }\n            }\n            else\n            {\n                PhShowStatus(hWnd, L\"Unable to query the section.\", status, 0);\n            }\n\n            PhClearReference(&sectionName);\n\n            NtClose(handle);\n        }\n    }\n    else if (PhEqualString2(Info->TypeName, L\"Thread\", TRUE))\n    {\n        HANDLE processHandle;\n        CLIENT_ID clientId;\n        PPH_PROCESS_ITEM targetProcessItem;\n        PPH_PROCESS_PROPCONTEXT propContext;\n\n        clientId.UniqueProcess = NULL;\n        clientId.UniqueThread = NULL;\n\n        if (KsiLevel() >= KphLevelMed)\n        {\n            if (NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION,\n                Info->ProcessId\n                )))\n            {\n                THREAD_BASIC_INFORMATION basicInfo;\n\n                if (NT_SUCCESS(KphQueryInformationObject(\n                    processHandle,\n                    Info->Handle,\n                    KphObjectThreadBasicInformation,\n                    &basicInfo,\n                    sizeof(THREAD_BASIC_INFORMATION),\n                    NULL\n                    )))\n                {\n                    clientId = basicInfo.ClientId;\n                }\n\n                NtClose(processHandle);\n            }\n        }\n        else\n        {\n            HANDLE handle;\n            THREAD_BASIC_INFORMATION basicInfo;\n\n            if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem(\n                &handle,\n                THREAD_QUERY_LIMITED_INFORMATION,\n                Info->ProcessId,\n                Info->Handle\n                )))\n            {\n                if (NT_SUCCESS(PhGetThreadBasicInformation(handle, &basicInfo)))\n                    clientId = basicInfo.ClientId;\n\n                NtClose(handle);\n            }\n        }\n\n        if (clientId.UniqueProcess)\n        {\n            targetProcessItem = PhReferenceProcessItem(clientId.UniqueProcess);\n\n            if (!targetProcessItem)\n            {\n                NTSTATUS status;\n\n                status = PhOpenProcessClientId(\n                    &processHandle,\n                    PROCESS_QUERY_LIMITED_INFORMATION,\n                    &clientId\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    targetProcessItem = PhCreateProcessItemFromHandle(\n                        clientId.UniqueProcess,\n                        processHandle,\n                        TRUE\n                        );\n                }\n            }\n\n            if (targetProcessItem)\n            {\n                propContext = PhCreateProcessPropContext(NULL, targetProcessItem);\n                PhDereferenceObject(targetProcessItem);\n                PhSetSelectThreadIdProcessPropContext(propContext, clientId.UniqueThread);\n                SystemInformer_Invoke(PhpShowProcessPropContext, propContext);\n            }\n            else\n            {\n                PhShowError2(hWnd, L\"Unable to show the process properties.\", L\"%s\", L\"The process does not exist.\");\n            }\n        }\n    }\n}\n\nVOID PhShowHandleObjectProperties2(\n    _In_ HWND hWnd,\n    _In_ PPH_HANDLE_ITEM_INFO Info\n    )\n{\n    if (PhIsNullOrEmptyString(Info->TypeName))\n        return;\n\n    if (PhEqualString2(Info->TypeName, L\"File\", TRUE) || PhEqualString2(Info->TypeName, L\"DLL\", TRUE) ||\n        PhEqualString2(Info->TypeName, L\"Mapped file\", TRUE) || PhEqualString2(Info->TypeName, L\"Mapped image\", TRUE))\n    {\n        if (Info->BestObjectName)\n            PhShellProperties(hWnd, Info->BestObjectName->Buffer);\n        else\n            PhShowError2(hWnd, L\"Unable to open the file properties.\", L\"%s\", L\"The object is unnamed.\");\n    }\n}\n"
  },
  {
    "path": "SystemInformer/hndlprp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2013\n *     dmex    2018-2024\n *\n */\n\n#include <phapp.h>\n#include <appresolver.h>\n#include <hndlprv.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <kphuser.h>\n\n#include <emenu.h>\n#include <settings.h>\n#include <hndlinfo.h>\n#include <lsasup.h>\n#include <procprv.h>\n#include <secedit.h>\n#include <phafd.h>\n\ntypedef enum _PHP_HANDLE_GENERAL_CATEGORY\n{\n    // common\n    PH_HANDLE_GENERAL_CATEGORY_BASICINFO,\n    PH_HANDLE_GENERAL_CATEGORY_SECURITY,\n    PH_HANDLE_GENERAL_CATEGORY_REFERENCES,\n    PH_HANDLE_GENERAL_CATEGORY_QUOTA,\n    // extra\n    PH_HANDLE_GENERAL_CATEGORY_ALPC,\n    PH_HANDLE_GENERAL_CATEGORY_FILE,\n    PH_HANDLE_GENERAL_CATEGORY_SECTION,\n    PH_HANDLE_GENERAL_CATEGORY_MUTANT,\n    PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD,\n    PH_HANDLE_GENERAL_CATEGORY_ETW,\n    PH_HANDLE_GENERAL_CATEGORY_SYMBOLICLINK,\n\n    PH_HANDLE_GENERAL_CATEGORY_MAXIMUM\n} PHP_HANDLE_GENERAL_CATEGORY;\n\ntypedef enum _PHP_HANDLE_GENERAL_INDEX\n{\n    PH_HANDLE_GENERAL_INDEX_NAME,\n    PH_HANDLE_GENERAL_INDEX_TYPE,\n    PH_HANDLE_GENERAL_INDEX_OBJECT,\n    PH_HANDLE_GENERAL_INDEX_FULLNAME,\n\n    PH_HANDLE_GENERAL_INDEX_ACCESSS,\n    PH_HANDLE_GENERAL_INDEX_ACCESSGENERIC,\n    PH_HANDLE_GENERAL_INDEX_ACCESSMASK,\n    PH_HANDLE_GENERAL_INDEX_SDDL,\n\n    PH_HANDLE_GENERAL_INDEX_REFERENCES,\n    PH_HANDLE_GENERAL_INDEX_HANDLES,\n\n    PH_HANDLE_GENERAL_INDEX_PAGED,\n    PH_HANDLE_GENERAL_INDEX_NONPAGED,\n\n    PH_HANDLE_GENERAL_INDEX_FLAGS,\n    PH_HANDLE_GENERAL_INDEX_SEQUENCENUMBER,\n    PH_HANDLE_GENERAL_INDEX_PORTCONTEXT,\n\n    PH_HANDLE_GENERAL_INDEX_FILETYPE,\n    PH_HANDLE_GENERAL_INDEX_FILEMODE,\n    PH_HANDLE_GENERAL_INDEX_FILEPOSITION,\n    PH_HANDLE_GENERAL_INDEX_FILESIZE,\n    PH_HANDLE_GENERAL_INDEX_FILEPRIORITY,\n    PH_HANDLE_GENERAL_INDEX_FILEDRIVER,\n    PH_HANDLE_GENERAL_INDEX_FILEDRIVERIMAGE,\n\n    PH_HANDLE_GENERAL_INDEX_SECTIONTYPE,\n    PH_HANDLE_GENERAL_INDEX_SECTIONFILE,\n    PH_HANDLE_GENERAL_INDEX_SECTIONSIZE,\n\n    PH_HANDLE_GENERAL_INDEX_MUTANTCOUNT,\n    PH_HANDLE_GENERAL_INDEX_MUTANTABANDONED,\n    PH_HANDLE_GENERAL_INDEX_MUTANTOWNER,\n\n    PH_HANDLE_GENERAL_INDEX_ALPCCONNECTION,\n    PH_HANDLE_GENERAL_INDEX_ALPCSERVER,\n    PH_HANDLE_GENERAL_INDEX_ALPCCLIENT,\n    PH_HANDLE_GENERAL_INDEX_ALPCOWNER,\n\n    PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME,\n    PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME,\n    PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME,\n    PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE,\n\n    PH_HANDLE_GENERAL_INDEX_ETWORIGINALNAME,\n    PH_HANDLE_GENERAL_INDEX_ETWGROUPNAME,\n\n    PH_HANDLE_GENERAL_INDEX_SYMBOLICLINKLINK,\n\n    PH_HANDLE_GENERAL_INDEX_MAXIMUM\n} PHP_HANDLE_GENERAL_INDEX;\n\ntypedef struct _HANDLE_PROPERTIES_CONTEXT\n{\n    HWND ListViewHandle;\n    HWND ParentWindow;\n    HANDLE ProcessId;\n    PPH_LISTVIEW_CONTEXT ListViewClass;\n    PPH_HANDLE_ITEM HandleItem;\n    PH_LAYOUT_MANAGER LayoutManager;\n} HANDLE_PROPERTIES_CONTEXT, *PHANDLE_PROPERTIES_CONTEXT;\n\ntypedef struct _HANDLE_PERMISSIONS_CONTEXT\n{\n    PHANDLE_PROPERTIES_CONTEXT HandleProperties;\n    HWND ListViewHeader;\n    HWND ListViewHandle;\n    HWND ParentWindow;\n    HANDLE ProcessId;\n    PPH_LISTVIEW_CONTEXT ListViewClass;\n    PPH_HANDLE_ITEM HandleItem;\n    PH_LAYOUT_MANAGER LayoutManager;\n} HANDLE_PERMISSIONS_CONTEXT, *PHANDLE_PERMISSIONS_CONTEXT;\n\n#define PH_FILEMODE_ASYNC 0x01000000\n#define PhFileModeUpdAsyncFlag(mode) \\\n    ((mode) & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT) ? (mode) &~ PH_FILEMODE_ASYNC: (mode) | PH_FILEMODE_ASYNC)\n\nCONST PH_ACCESS_ENTRY FileModeAccessEntries[] =\n{\n    { L\"FILE_FLAG_OVERLAPPED\", PH_FILEMODE_ASYNC, FALSE, FALSE, L\"Asynchronous\" },\n    { L\"FILE_FLAG_WRITE_THROUGH\", FILE_WRITE_THROUGH, FALSE, FALSE, L\"Write through\" },\n    { L\"FILE_FLAG_SEQUENTIAL_SCAN\", FILE_SEQUENTIAL_ONLY, FALSE, FALSE, L\"Sequential\" },\n    { L\"FILE_FLAG_NO_BUFFERING\", FILE_NO_INTERMEDIATE_BUFFERING, FALSE, FALSE, L\"No buffering\" },\n    { L\"FILE_SYNCHRONOUS_IO_ALERT\", FILE_SYNCHRONOUS_IO_ALERT, FALSE, FALSE, L\"Synchronous alert\" },\n    { L\"FILE_SYNCHRONOUS_IO_NONALERT\", FILE_SYNCHRONOUS_IO_NONALERT, FALSE, FALSE, L\"Synchronous non-alert\" },\n};\n\nCONST PH_ACCESS_ENTRY AlpcFlags[] =\n{\n    { L\"ALPC_PORFLG_LPC_MODE\", ALPC_PORFLG_LPC_MODE, FALSE, FALSE, L\"LPC mode\"},\n    { L\"ALPC_PORFLG_ALLOW_IMPERSONATION\", ALPC_PORFLG_ALLOW_IMPERSONATION, FALSE, FALSE, L\"Allow impersonation\"},\n    { L\"ALPC_PORFLG_ALLOW_LPC_REQUESTS\", ALPC_PORFLG_ALLOW_LPC_REQUESTS, FALSE, FALSE, L\"Allow LPC requests\"},\n    { L\"ALPC_PORFLG_WAITABLE_PORT\", ALPC_PORFLG_WAITABLE_PORT, FALSE, FALSE, L\"Waitable\"},\n    { L\"ALPC_PORFLG_ALLOW_DUP_OBJECT\", ALPC_PORFLG_ALLOW_DUP_OBJECT, FALSE, FALSE, L\"Allow object duplication\"},\n    { L\"ALPC_PORFLG_SYSTEM_PROCESS\", ALPC_PORFLG_SYSTEM_PROCESS, FALSE, FALSE, L\"System process only\"},\n    { L\"ALPC_PORFLG_WAKE_POLICY1\", ALPC_PORFLG_WAKE_POLICY1, FALSE, FALSE, L\"Wake policy (1)\"},\n    { L\"ALPC_PORFLG_WAKE_POLICY2\", ALPC_PORFLG_WAKE_POLICY2, FALSE, FALSE, L\"Wake policy (2)\"},\n    { L\"ALPC_PORFLG_WAKE_POLICY3\", ALPC_PORFLG_WAKE_POLICY3, FALSE, FALSE, L\"Wake policy (3)\"},\n    { L\"ALPC_PORFLG_DIRECT_MESSAGE\", ALPC_PORFLG_DIRECT_MESSAGE, FALSE, FALSE, L\"No shared section (direct)\"},\n    { L\"ALPC_PORFLG_ALLOW_MULTIHANDLE_ATTRIBUTE\", ALPC_PORFLG_ALLOW_MULTIHANDLE_ATTRIBUTE, FALSE, FALSE, L\"Allow multi-handle attributes\"},\n};\n\nINT_PTR CALLBACK PhpHandleGeneralDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpHandlePermissionsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpHandleAuditingDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpDuplicateHandleFromProcess(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PVOID Context\n    )\n{\n    PHANDLE_PROPERTIES_CONTEXT context = Context;\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    *Handle = NULL;\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_DUP_HANDLE,\n        context->ProcessId\n        )))\n    {\n        status = NtDuplicateObject(\n            processHandle,\n            context->HandleItem->Handle,\n            NtCurrentProcess(),\n            Handle,\n            DesiredAccess,\n            0,\n            0\n            );\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status) && KsiLevel() >= KphLevelMax)\n    {\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            context->ProcessId\n            )))\n        {\n            status = KphDuplicateObject(\n                processHandle,\n                context->HandleItem->Handle,\n                DesiredAccess,\n                Handle\n                );\n            NtClose(processHandle);\n        }\n    }\n\n    return status;\n}\n\n_Function_class_(PH_CLOSE_OBJECT)\nstatic NTSTATUS PhpDuplicateHandleCloseProcess(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle)\n        NtClose(Handle);\n    return STATUS_SUCCESS;\n}\n\ntypedef struct _HANDLE_PROPERTIES_THREAD_CONTEXT\n{\n    HWND ParentWindowHandle;\n    HANDLE ProcessId;\n    PPH_HANDLE_ITEM HandleItem;\n} HANDLE_PROPERTIES_THREAD_CONTEXT, *PHANDLE_PROPERTIES_THREAD_CONTEXT;\n\nBOOLEAN PhpIsVerboseBestObjectName(\n    _In_ PPH_HANDLE_ITEM HandleItem\n    )\n{\n    // Some handles use a verbose BestObjectName for the sake of searching. And will display\n    // extended information in the property window consisting of the information contained in the\n    // BestObjectName. This routine is used to fall back to the normal ObjectName in the property\n    // window for these cases. (jxy-s)\n\n    if (PhIsNullOrEmptyString(HandleItem->TypeName))\n        return FALSE;\n\n    if (PhEqualString2(HandleItem->TypeName, L\"ALPC Port\", TRUE))\n        return TRUE;\n\n    if (PhEqualString2(HandleItem->TypeName, L\"File\", TRUE) &&\n        PhAfdIsSocketObjectName(HandleItem->ObjectName))\n        return TRUE;\n\n    return FALSE;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nstatic VOID PhHandlePropertiesContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PHANDLE_PROPERTIES_CONTEXT context = Object;\n\n    PhDereferenceObject(context->HandleItem);\n}\n\nPHANDLE_PROPERTIES_CONTEXT PhCreateHandlePropertiesContext(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PPH_OBJECT_TYPE PhHandlePropertiesContextType = NULL;\n    PHANDLE_PROPERTIES_CONTEXT context;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhHandlePropertiesContextType = PhCreateObjectType(L\"HandlePropertiesItem\", 0, PhHandlePropertiesContextDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    context = PhCreateObject(sizeof(HANDLE_PROPERTIES_CONTEXT), PhHandlePropertiesContextType);\n    memset(context, 0, sizeof(HANDLE_PROPERTIES_CONTEXT));\n\n    return context;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpShowHandlePropertiesThread(\n    _In_ PVOID Parameter\n    )\n{\n    PHANDLE_PROPERTIES_THREAD_CONTEXT handleContext = Parameter;\n    PROPSHEETHEADER propSheetHeader = { sizeof(PROPSHEETHEADER) };\n    PROPSHEETPAGE propSheetPage;\n    HPROPSHEETPAGE pages[16];\n    PHANDLE_PROPERTIES_CONTEXT context;\n    PH_AUTO_POOL autoPool;\n\n    context = PhCreateHandlePropertiesContext();\n    context->ProcessId = handleContext->ProcessId;\n    context->HandleItem = handleContext->HandleItem;\n    context->ParentWindow = handleContext->ParentWindowHandle;\n\n    PhInitializeAutoPool(&autoPool);\n\n    propSheetHeader.dwFlags =\n        PSH_MODELESS |\n        PSH_NOAPPLYNOW |\n        PSH_NOCONTEXTHELP |\n        PSH_PROPTITLE;\n    propSheetHeader.hInstance = NtCurrentImageBase();\n    propSheetHeader.hwndParent = PhCsForceNoParent ? NULL : handleContext->ParentWindowHandle;\n    propSheetHeader.pszCaption = L\"Handle\";\n    propSheetHeader.nPages = 0;\n    propSheetHeader.nStartPage = 0;\n    propSheetHeader.phpage = pages;\n\n    // General page\n    memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));\n    propSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_HNDLGENERAL);\n    propSheetPage.hInstance = NtCurrentImageBase();\n    propSheetPage.pfnDlgProc = PhpHandleGeneralDlgProc;\n    propSheetPage.lParam = (LPARAM)context;\n    pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);\n\n    // Permissions page\n    memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));\n    propSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_HNDLSECURITY);\n    propSheetPage.hInstance = NtCurrentImageBase();\n    propSheetPage.pfnDlgProc = PhpHandlePermissionsDlgProc;\n    propSheetPage.lParam = (LPARAM)context;\n    pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);\n\n    // Audiing page\n    memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));\n    propSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_HNDLSECAUDIT);\n    propSheetPage.hInstance = NtCurrentImageBase();\n    propSheetPage.pfnDlgProc = PhpHandleAuditingDlgProc;\n    propSheetPage.lParam = (LPARAM)context;\n    pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);\n\n    // Object-specific page\n    if (PhIsNullOrEmptyString(handleContext->HandleItem->TypeName))\n    {\n        NOTHING;\n    }\n    else if (PhEqualString2(handleContext->HandleItem->TypeName, L\"Event\", TRUE))\n    {\n        pages[propSheetHeader.nPages++] = PhCreateEventPage(\n            PhpDuplicateHandleFromProcess,\n            PhpDuplicateHandleCloseProcess,\n            context\n            );\n    }\n    else if (PhEqualString2(handleContext->HandleItem->TypeName, L\"EventPair\", TRUE))\n    {\n        pages[propSheetHeader.nPages++] = PhCreateEventPairPage(\n            PhpDuplicateHandleFromProcess,\n            PhpDuplicateHandleCloseProcess,\n            context\n            );\n    }\n    else if (PhEqualString2(handleContext->HandleItem->TypeName, L\"Job\", TRUE))\n    {\n        pages[propSheetHeader.nPages++] = PhCreateJobPage(\n            PhpDuplicateHandleFromProcess,\n            PhpDuplicateHandleCloseProcess,\n            context,\n            NULL\n            );\n    }\n    else if (PhEqualString2(handleContext->HandleItem->TypeName, L\"Semaphore\", TRUE))\n    {\n        pages[propSheetHeader.nPages++] = PhCreateSemaphorePage(\n            PhpDuplicateHandleFromProcess,\n            PhpDuplicateHandleCloseProcess,\n            context\n            );\n    }\n    else if (PhEqualString2(handleContext->HandleItem->TypeName, L\"Timer\", TRUE))\n    {\n        pages[propSheetHeader.nPages++] = PhCreateTimerPage(\n            PhpDuplicateHandleFromProcess,\n            PhpDuplicateHandleCloseProcess,\n            context\n            );\n    }\n    else if (PhEqualString2(handleContext->HandleItem->TypeName, L\"Token\", TRUE))\n    {\n        pages[propSheetHeader.nPages++] = PhCreateTokenPage(\n            PhpDuplicateHandleFromProcess,\n            PhpDuplicateHandleCloseProcess,\n            context->ProcessId,\n            context,\n            NULL\n            );\n    }\n    else if (PhEqualString2(handleContext->HandleItem->TypeName, L\"Section\", TRUE))\n    {\n        pages[propSheetHeader.nPages++] = PhCreateMappingsPage(\n            handleContext->ProcessId,\n            handleContext->HandleItem->Handle\n            );\n    }\n    else if (PhEqualString2(handleContext->HandleItem->TypeName, L\"File\", TRUE) &&\n        PhAfdIsSocketObjectName(handleContext->HandleItem->ObjectName))\n    {\n        pages[propSheetHeader.nPages++] = PhCreateAfdSocketPage(\n            context->ProcessId,\n            context->HandleItem->Handle\n            );\n    }\n\n    // Security page\n    {\n        PCWSTR objectName;\n\n        if (PhpIsVerboseBestObjectName(handleContext->HandleItem))\n            objectName = PhGetStringOrEmpty(handleContext->HandleItem->ObjectName);\n        else\n            objectName = PhGetStringOrEmpty(handleContext->HandleItem->BestObjectName);\n\n        pages[propSheetHeader.nPages++] = PhCreateSecurityPage(\n            objectName,\n            PhGetStringOrEmpty(handleContext->HandleItem->TypeName),\n            PhpDuplicateHandleFromProcess,\n            PhpDuplicateHandleCloseProcess,\n            context\n            );\n    }\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_OBJECT_PROPERTIES objectProperties;\n        PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT propertiesContext;\n\n        memset(&propertiesContext, 0, sizeof(PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT));\n        propertiesContext.ParentWindowHandle = handleContext->ParentWindowHandle;\n        propertiesContext.ProcessId = handleContext->ProcessId;\n        propertiesContext.HandleItem = handleContext->HandleItem;\n\n        memset(&objectProperties, 0, sizeof(PH_PLUGIN_OBJECT_PROPERTIES));\n        objectProperties.Parameter = &propertiesContext;\n        objectProperties.NumberOfPages = propSheetHeader.nPages;\n        objectProperties.MaximumNumberOfPages = RTL_NUMBER_OF(pages);\n        objectProperties.Pages = pages;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandlePropertiesInitializing), &objectProperties);\n\n        propSheetHeader.nPages = objectProperties.NumberOfPages;\n    }\n\n    PhModalPropertySheet(&propSheetHeader);\n\n    PhDeleteAutoPool(&autoPool);\n\n    PhDereferenceObject(context);\n    PhFree(handleContext);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhShowHandleProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_HANDLE_ITEM HandleItem\n    )\n{\n    PHANDLE_PROPERTIES_THREAD_CONTEXT context;\n\n    context = PhAllocateZero(sizeof(HANDLE_PROPERTIES_THREAD_CONTEXT));\n    context->ParentWindowHandle = ParentWindowHandle;\n    context->ProcessId = ProcessId;\n    context->HandleItem = HandleItem;\n    PhReferenceObject(HandleItem);\n\n    PhCreateThread2(PhpShowHandlePropertiesThread, context);\n}\n\nVOID PhAddHandleListViewItem(\n    _In_ PPH_LISTVIEW_CONTEXT ListViewClass,\n    _In_ LONG GroupId,\n    _In_ LONG Index,\n    _In_ PCWSTR Text\n    )\n{\n    PhListView_AddGroupItem(ListViewClass, GroupId, Index, Text, UlongToPtr(Index));\n}\n\nVOID PhSetHandleListViewItem(\n    _In_ PHANDLE_PROPERTIES_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex,\n    _In_ PCWSTR Text\n    )\n{\n    LONG index = PhFindListViewItemByParam(Context->ListViewHandle, INT_ERROR, UlongToPtr(Index));\n\n    if (index != INT_ERROR)\n    {\n        PhListView_SetSubItem(Context->ListViewClass, index, SubItemIndex, Text);\n    }\n}\n\nVOID PhpUpdateHandleGeneralListViewGroups(\n    _In_ PHANDLE_PROPERTIES_CONTEXT Context\n    )\n{\n    PhListView_EnableGroupView(Context->ListViewClass, TRUE);\n    PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, L\"Basic information\");\n    PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SECURITY, L\"Security information\");\n    PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, L\"References\");\n    PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_QUOTA, L\"Quota charges\");\n\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_NAME, L\"Name\");\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_TYPE, L\"Type\");\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_OBJECT, L\"Object address\");\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_FULLNAME, L\"FullPath\");\n\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SECURITY, PH_HANDLE_GENERAL_INDEX_ACCESSS, L\"Granted access\");\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SECURITY, PH_HANDLE_GENERAL_INDEX_ACCESSGENERIC, L\"Granted access (generic)\");\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SECURITY, PH_HANDLE_GENERAL_INDEX_ACCESSMASK, L\"Granted access (mask)\");\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SECURITY, PH_HANDLE_GENERAL_INDEX_SDDL, L\"SDDL\");\n\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, PH_HANDLE_GENERAL_INDEX_REFERENCES, L\"References\");\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, PH_HANDLE_GENERAL_INDEX_HANDLES, L\"Handles\");\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_QUOTA, PH_HANDLE_GENERAL_INDEX_PAGED, L\"Paged\");\n    PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_QUOTA, PH_HANDLE_GENERAL_INDEX_NONPAGED, L\"Virtual size\");\n\n    if (PhIsNullOrEmptyString(Context->HandleItem->TypeName))\n    {\n        NOTHING;\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"ALPC Port\", TRUE))\n    {\n        PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ALPC, L\"ALPC Port\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ALPC, PH_HANDLE_GENERAL_INDEX_FLAGS, L\"Flags\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ALPC, PH_HANDLE_GENERAL_INDEX_SEQUENCENUMBER, L\"Sequence Number\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ALPC, PH_HANDLE_GENERAL_INDEX_PORTCONTEXT, L\"Port Context\");\n\n        if (KsiLevel() >= KphLevelMed)\n        {\n            PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ALPC, PH_HANDLE_GENERAL_INDEX_ALPCCONNECTION, L\"Connection\");\n            PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ALPC, PH_HANDLE_GENERAL_INDEX_ALPCSERVER, L\"Server\");\n            PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ALPC, PH_HANDLE_GENERAL_INDEX_ALPCCLIENT, L\"Client\");\n        }\n\n        if (WindowsVersion >= WINDOWS_10_19H2)\n        {\n            PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ALPC, PH_HANDLE_GENERAL_INDEX_ALPCOWNER, L\"Owner\");\n        }\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"EtwRegistration\", TRUE))\n    {\n        PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ETW, L\"Event trace information\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ETW, PH_HANDLE_GENERAL_INDEX_ETWORIGINALNAME, L\"GUID\");\n        //PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_ETW, PH_HANDLE_GENERAL_INDEX_ETWGROUPNAME, L\"Group GUID\");\n    }\n    else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L\"File\", TRUE))\n    {\n        PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_FILE, L\"File information\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_FILE, PH_HANDLE_GENERAL_INDEX_FILETYPE, L\"Type\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_FILE, PH_HANDLE_GENERAL_INDEX_FILEMODE, L\"Mode\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_FILE, PH_HANDLE_GENERAL_INDEX_FILEPOSITION, L\"Position\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_FILE, PH_HANDLE_GENERAL_INDEX_FILESIZE, L\"Size\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_FILE, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, L\"Priority\");\n\n        if (KsiLevel() >= KphLevelMed)\n        {\n            PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_FILE, PH_HANDLE_GENERAL_INDEX_FILEDRIVER, L\"Driver\");\n            PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_FILE, PH_HANDLE_GENERAL_INDEX_FILEDRIVERIMAGE, L\"Driver Image\");\n        }\n    }\n    else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L\"Section\", TRUE))\n    {\n        PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SECTION, L\"Section information\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SECTION, PH_HANDLE_GENERAL_INDEX_SECTIONTYPE, L\"Type\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SECTION, PH_HANDLE_GENERAL_INDEX_SECTIONFILE, L\"File\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SECTION, PH_HANDLE_GENERAL_INDEX_SECTIONSIZE, L\"Size\");\n    }\n    else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L\"Mutant\", TRUE))\n    {\n        PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_MUTANT, L\"Mutant information\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_MUTANT, PH_HANDLE_GENERAL_INDEX_MUTANTCOUNT, L\"Count\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_MUTANT, PH_HANDLE_GENERAL_INDEX_MUTANTABANDONED, L\"Abandoned\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_MUTANT, PH_HANDLE_GENERAL_INDEX_MUTANTOWNER, L\"Owner\");\n    }\n    else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L\"Process\", TRUE))\n    {\n        PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, L\"Process information\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME, L\"Name\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME, L\"Created\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME, L\"Exited\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE, L\"Exit status\");\n    }\n    else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L\"Thread\", TRUE))\n    {\n        PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, L\"Thread information\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME, L\"Name\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME, L\"Created\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME, L\"Exited\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE, L\"Exit status\");\n    }\n    else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L\"SymbolicLink\", TRUE))\n    {\n        PhListView_AddGroup(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SYMBOLICLINK, L\"Symbolic Link information\");\n        PhAddHandleListViewItem(Context->ListViewClass, PH_HANDLE_GENERAL_CATEGORY_SYMBOLICLINK, PH_HANDLE_GENERAL_INDEX_SYMBOLICLINKLINK, L\"Link target\");\n    }\n}\n\nVOID PhpUpdateHandleGeneral(\n    _In_ PHANDLE_PROPERTIES_CONTEXT Context\n    )\n{\n    HANDLE processHandle;\n\n    // Name, FullName\n\n    if (PhpIsVerboseBestObjectName(Context->HandleItem) && !PhIsNullOrEmptyString(Context->HandleItem->ObjectName))\n    {\n        PPH_STRING objectName;\n\n        objectName = PhGetBaseName(Context->HandleItem->ObjectName);\n        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_NAME, 1, PhGetStringOrEmpty(objectName));\n        PhClearReference(&objectName);\n\n        objectName = PhReferenceObject(Context->HandleItem->ObjectName);\n        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FULLNAME, 1, PhGetStringOrEmpty(objectName));\n        PhClearReference(&objectName);\n    }\n    else if (!PhIsNullOrEmptyString(Context->HandleItem->BestObjectName))\n    {\n        PPH_STRING objectName;\n\n        objectName = PhGetBaseName(Context->HandleItem->BestObjectName);\n        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_NAME, 1, PhGetStringOrEmpty(objectName));\n        PhClearReference(&objectName);\n\n        objectName = PhReferenceObject(Context->HandleItem->BestObjectName);\n        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FULLNAME, 1, PhGetStringOrEmpty(objectName));\n        PhClearReference(&objectName);\n    }\n\n    // Type\n\n    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_TYPE, 1, PhGetStringOrEmpty(Context->HandleItem->TypeName));\n\n    // Address\n\n    if (Context->HandleItem->Object)\n    {\n        WCHAR string[PH_INT64_STR_LEN_1];\n\n        PhPrintPointer(string, Context->HandleItem->Object);\n        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_OBJECT, 1, string);\n    }\n    else\n    {\n        if (PhGetIntegerSetting(SETTING_ENABLE_HANDLE_SNAPSHOT))\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_OBJECT, 1, L\"N/A (snapshot)\");\n        else\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_OBJECT, 1, L\"N/A\");\n    }\n\n    // AccessMask (Symbolic)\n    {\n        PPH_ACCESS_ENTRY accessEntries;\n        ULONG numberOfAccessEntries;\n\n        if (PhGetAccessEntries(\n            PhGetStringOrEmpty(Context->HandleItem->TypeName),\n            &accessEntries,\n            &numberOfAccessEntries\n            ))\n        {\n            PPH_STRING accessString;\n\n            if (accessString = PH_AUTO(PhGetAccessString(\n                Context->HandleItem->GrantedAccess,\n                accessEntries,\n                numberOfAccessEntries\n                )))\n            {\n                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ACCESSS, 1, PhGetString(accessString));\n            }\n            else\n            {\n                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ACCESSS, 1, L\"N/A\");\n            }\n\n            PhFree(accessEntries);\n        }\n        else\n        {\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ACCESSS, 1, L\"N/A\");\n        }\n    }\n\n    // AccessMask (Generic)\n    {\n        PPH_STRING genericString = NULL;\n        GENERIC_MAPPING genericMapping;\n\n        if (Context->HandleItem->TypeName && NT_SUCCESS(PhGetObjectTypeMask(\n            &Context->HandleItem->TypeName->sr,\n            &genericMapping\n            )))\n        {\n            PH_STRING_BUILDER stringBuilder;\n\n            PhInitializeStringBuilder(&stringBuilder, 64);\n\n            if (FlagOn(Context->HandleItem->GrantedAccess, genericMapping.GenericRead))\n                PhAppendStringBuilder2(&stringBuilder, L\"Read, \");\n            if (FlagOn(Context->HandleItem->GrantedAccess, genericMapping.GenericWrite))\n                PhAppendStringBuilder2(&stringBuilder, L\"Write, \");\n            if (FlagOn(Context->HandleItem->GrantedAccess, genericMapping.GenericExecute))\n                PhAppendStringBuilder2(&stringBuilder, L\"Execute, \");\n            if (FlagOn(Context->HandleItem->GrantedAccess, genericMapping.GenericAll))\n                PhAppendStringBuilder2(&stringBuilder, L\"All, \");\n\n            if (PhEndsWithStringRef2(&stringBuilder.String->sr, L\", \", FALSE))\n                PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n            genericString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder));\n        }\n\n        if (!PhIsNullOrEmptyString(genericString))\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ACCESSGENERIC, 1, PhGetString(genericString));\n        else\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ACCESSGENERIC, 1, L\"N/A\");\n    }\n\n    // AccessMask (Hex)\n    {\n        WCHAR string[PH_INT64_STR_LEN_1];\n\n        PhPrintPointer(string, UlongToPtr(Context->HandleItem->GrantedAccess));\n        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ACCESSMASK, 1, string);\n    }\n\n    // AccessMask (SDDL)\n    {\n        NTSTATUS status;\n        PPH_STRING handleSddlString;\n\n        status = PhGetObjectSecurityDescriptorAsString(\n            Context->HandleItem->Handle,\n            &handleSddlString\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_SDDL, 1, PhGetString(handleSddlString));\n            PhDereferenceObject(handleSddlString);\n        }\n        else\n        {\n            WCHAR string[PH_INT64_STR_LEN_1];\n\n            PhPrintPointer(string, UlongToPtr(status));\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_SDDL, 1, string);\n        }\n    }\n\n    if (NT_SUCCESS(PhOpenProcess(\n        &processHandle,\n        (KsiLevel() >= KphLevelMed ? PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_DUP_HANDLE),\n        Context->ProcessId\n        )))\n    {\n        OBJECT_BASIC_INFORMATION basicInfo;\n\n        if (NT_SUCCESS(PhGetHandleInformation(\n            processHandle,\n            Context->HandleItem->Handle,\n            ULONG_MAX,\n            &basicInfo,\n            NULL,\n            NULL,\n            NULL\n            )))\n        {\n            WCHAR string[PH_INT64_STR_LEN_1];\n\n            PhPrintUInt32(string, basicInfo.PointerCount);\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_REFERENCES, 1, string);\n\n            PhPrintUInt32(string, basicInfo.HandleCount);\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_HANDLES, 1, string);\n\n            PhPrintUInt32(string, basicInfo.PagedPoolCharge);\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PAGED, 1, string);\n\n            PhPrintUInt32(string, basicInfo.NonPagedPoolCharge);\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_NONPAGED, 1, string);\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (PhIsNullOrEmptyString(Context->HandleItem->TypeName))\n    {\n        NOTHING;\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"ALPC Port\", TRUE))\n    {\n        NTSTATUS status;\n\n        if (KsiLevel() >= KphLevelMed && NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION,\n                Context->ProcessId\n                )))\n        {\n            //\n            // TODO this path doesn't use all the ALPC info returned yet\n            // see: KPH_ALPC_BASIC_INFORMATION.State\n            //\n            KPH_ALPC_BASIC_INFORMATION basicInfo;\n            PKPH_ALPC_COMMUNICATION_NAMES_INFORMATION connectionNames;\n            KPH_ALPC_COMMUNICATION_INFORMATION connectionInfo;\n\n            if (NT_SUCCESS(KphAlpcQueryInformation(\n                processHandle,\n                Context->HandleItem->Handle,\n                KphAlpcBasicInformation,\n                &basicInfo,\n                sizeof(basicInfo),\n                NULL\n                )))\n            {\n                PH_FORMAT format[5];\n                PPH_STRING alpcFlagsString;\n                WCHAR string[PH_INT64_STR_LEN_1];\n\n                alpcFlagsString = PhGetAccessString(\n                    basicInfo.Flags,\n                    (PPH_ACCESS_ENTRY)AlpcFlags,\n                    RTL_NUMBER_OF(AlpcFlags)\n                    );\n\n                PhInitFormatS(&format[0], L\"0x\");\n                PhInitFormatX(&format[1], basicInfo.Flags);\n                PhInitFormatS(&format[2], L\" (\");\n                PhInitFormatSR(&format[3], alpcFlagsString->sr);\n                PhInitFormatS(&format[4], L\")\");\n\n                PhMoveReference(&alpcFlagsString, PhFormat(format, RTL_NUMBER_OF(format), 40));\n                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FLAGS, 1, PhGetString(alpcFlagsString));\n                PhDereferenceObject(alpcFlagsString);\n\n                PhPrintUInt32(string, basicInfo.SequenceNo);\n                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_SEQUENCENUMBER, 1, string);\n\n                PhPrintPointer(string, basicInfo.PortContext);\n                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PORTCONTEXT, 1, string);\n            }\n\n            if (!NT_SUCCESS(KphAlpcQueryCommunicationsNamesInfo(\n                processHandle,\n                Context->HandleItem->Handle,\n                &connectionNames)))\n            {\n                connectionNames = NULL;\n            }\n\n            if (NT_SUCCESS(KphAlpcQueryInformation(\n                processHandle,\n                Context->HandleItem->Handle,\n                KphAlpcCommunicationInformation,\n                &connectionInfo,\n                sizeof(connectionInfo),\n                NULL\n                )))\n            {\n                CLIENT_ID clientId;\n                PPH_STRING name;\n\n                if (connectionInfo.ConnectionPort.OwnerProcessId)\n                {\n                    clientId.UniqueProcess = connectionInfo.ConnectionPort.OwnerProcessId;\n                    clientId.UniqueThread = 0;\n\n                    name = PhStdGetClientIdName(&clientId);\n\n                    if (connectionNames && connectionNames->ConnectionPort.Length > 0)\n                    {\n                        PPH_STRING newName;\n                        PH_FORMAT format[3];\n\n                        PhInitFormatSR(&format[0], name->sr);\n                        PhInitFormatS(&format[1], L\" - \");\n                        PhInitFormatUCS(&format[2], &connectionNames->ConnectionPort);\n\n                        newName = PhFormat(format, 3, MAX_PATH);\n                        PhDereferenceObject(name);\n                        name = newName;\n                    }\n\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ALPCCONNECTION, 1, name->Buffer);\n                    PhDereferenceObject(name);\n                }\n\n                if (connectionInfo.ServerCommunicationPort.OwnerProcessId)\n                {\n                    clientId.UniqueProcess = connectionInfo.ServerCommunicationPort.OwnerProcessId;\n                    clientId.UniqueThread = 0;\n\n                    name = PhStdGetClientIdName(&clientId);\n\n                    if (connectionNames && connectionNames->ServerCommunicationPort.Length > 0)\n                    {\n                        PPH_STRING newName;\n                        PH_FORMAT format[3];\n\n                        PhInitFormatSR(&format[0], name->sr);\n                        PhInitFormatS(&format[1], L\" - \");\n                        PhInitFormatUCS(&format[2], &connectionNames->ServerCommunicationPort);\n\n                        newName = PhFormat(format, 3, MAX_PATH);\n                        PhDereferenceObject(name);\n                        name = newName;\n                    }\n\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ALPCSERVER, 1, name->Buffer);\n                    PhDereferenceObject(name);\n                }\n\n                if (connectionInfo.ClientCommunicationPort.OwnerProcessId)\n                {\n                    clientId.UniqueProcess = connectionInfo.ClientCommunicationPort.OwnerProcessId;\n                    clientId.UniqueThread = 0;\n\n                    name = PhStdGetClientIdName(&clientId);\n\n                    if (connectionNames && connectionNames->ClientCommunicationPort.Length > 0)\n                    {\n                        PPH_STRING newName;\n                        PH_FORMAT format[3];\n\n                        PhInitFormatSR(&format[0], name->sr);\n                        PhInitFormatS(&format[1], L\" - \");\n                        PhInitFormatUCS(&format[2], &connectionNames->ClientCommunicationPort);\n\n                        newName = PhFormat(format, 3, MAX_PATH);\n                        PhDereferenceObject(name);\n                        name = newName;\n                    }\n\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ALPCCLIENT, 1, name->Buffer);\n                    PhDereferenceObject(name);\n                }\n\n                if (connectionNames)\n                    PhFree(connectionNames);\n\n                NtClose(processHandle);\n            }\n            else\n            {\n                HANDLE alpcPortHandle = NULL;\n\n                if (NT_SUCCESS(status = PhOpenProcess(\n                    &processHandle,\n                    PROCESS_DUP_HANDLE,\n                    Context->ProcessId\n                    )))\n                {\n                    status = NtDuplicateObject(\n                        processHandle,\n                        Context->HandleItem->Handle,\n                        NtCurrentProcess(),\n                        &alpcPortHandle,\n                        READ_CONTROL,\n                        0,\n                        0\n                        );\n                    NtClose(processHandle);\n                }\n\n                if (NT_SUCCESS(status) && alpcPortHandle)\n                {\n                    ALPC_BASIC_INFORMATION alpcBasicInfo;\n\n                    if (NT_SUCCESS(NtAlpcQueryInformation(\n                        alpcPortHandle,\n                        AlpcBasicInformation,\n                        &alpcBasicInfo,\n                        sizeof(ALPC_BASIC_INFORMATION),\n                        NULL\n                        )))\n                    {\n                        PH_FORMAT format[5];\n                        PPH_STRING alpcFlagsString;\n                        WCHAR string[PH_INT64_STR_LEN_1];\n\n                        alpcFlagsString = PhGetAccessString(\n                            alpcBasicInfo.Flags,\n                            (PPH_ACCESS_ENTRY)AlpcFlags,\n                            RTL_NUMBER_OF(AlpcFlags)\n                            );\n\n                        PhInitFormatS(&format[0], L\"0x\");\n                        PhInitFormatX(&format[1], alpcBasicInfo.Flags);\n                        PhInitFormatS(&format[2], L\" (\");\n                        PhInitFormatSR(&format[3], alpcFlagsString->sr);\n                        PhInitFormatS(&format[4], L\")\");\n\n                        PhMoveReference(&alpcFlagsString, PhFormat(format, RTL_NUMBER_OF(format), 40));\n\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FLAGS, 1, PhGetString(alpcFlagsString));\n\n                        PhDereferenceObject(alpcFlagsString);\n\n                        PhPrintUInt32(string, basicInfo.SequenceNo);\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_SEQUENCENUMBER, 1, string);\n\n                        PhPrintPointer(string, basicInfo.PortContext);\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PORTCONTEXT, 1, string);\n                    }\n\n                    if (WindowsVersion >= WINDOWS_10_19H2)\n                    {\n                        ALPC_SERVER_SESSION_INFORMATION serverInfo;\n\n                        if (NT_SUCCESS(NtAlpcQueryInformation(\n                            alpcPortHandle,\n                            AlpcServerSessionInformation,\n                            &serverInfo,\n                            sizeof(ALPC_SERVER_SESSION_INFORMATION),\n                            NULL\n                            )))\n                        {\n                            CLIENT_ID clientId;\n                            PPH_STRING name;\n\n                            clientId.UniqueProcess = UlongToHandle(serverInfo.ProcessId);\n                            clientId.UniqueThread = NULL;\n\n                            name = PhGetClientIdName(&clientId);\n                            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ALPCOWNER, 1, name->Buffer);\n                            PhDereferenceObject(name);\n                        }\n                    }\n\n                    NtClose(alpcPortHandle);\n                }\n            }\n        }\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"EtwRegistration\", TRUE))\n    {\n        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_ETWORIGINALNAME, 1, PhGetString(Context->HandleItem->ObjectName));\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"File\", TRUE))\n    {\n        NTSTATUS status;\n\n        if (KsiLevel() >= KphLevelMed && NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION,\n                Context->ProcessId\n                )))\n        {\n            BOOLEAN isFileOrDirectory = FALSE;\n            BOOLEAN isConsoleHandle = FALSE;\n            FILE_FS_DEVICE_INFORMATION fileDeviceInfo;\n            FILE_MODE_INFORMATION fileModeInfo;\n            FILE_STANDARD_INFORMATION fileStandardInfo;\n            FILE_POSITION_INFORMATION filePositionInfo;\n            FILE_IO_PRIORITY_HINT_INFORMATION_EX priorityInfo;\n            IO_STATUS_BLOCK isb;\n            HANDLE fileObjectDriver;\n\n            if (NT_SUCCESS(KphQueryVolumeInformationFile(\n                processHandle,\n                Context->HandleItem->Handle,\n                FileFsDeviceInformation,\n                &fileDeviceInfo,\n                sizeof(FILE_FS_DEVICE_INFORMATION),\n                &isb\n                )))\n            {\n                switch (fileDeviceInfo.DeviceType)\n                {\n                case FILE_DEVICE_NAMED_PIPE:\n                    //isPipeHandle = TRUE;\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"Pipe\");\n                    break;\n                case FILE_DEVICE_NETWORK:\n                    //isNetworkHandle = TRUE;\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"Network\");\n                    break;\n                case FILE_DEVICE_CD_ROM:\n                case FILE_DEVICE_CD_ROM_FILE_SYSTEM:\n                case FILE_DEVICE_CONTROLLER:\n                case FILE_DEVICE_DATALINK:\n                case FILE_DEVICE_DFS:\n                case FILE_DEVICE_DISK:\n                case FILE_DEVICE_DISK_FILE_SYSTEM:\n                case FILE_DEVICE_VIRTUAL_DISK:\n                    isFileOrDirectory = TRUE;\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"File or directory\");\n                    break;\n                case FILE_DEVICE_CONSOLE:\n                    isConsoleHandle = TRUE;\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"Console\");\n                    break;\n                default:\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"Other\");\n                    break;\n                }\n            }\n\n            // Note: These devices deadlock without a timeout (dmex)\n            // 1) Named pipes\n            // 2) \\Device\\ConDrv\\CurrentIn\n            // 3) \\Device\\VolMgrControl\n\n            if (NT_SUCCESS(status = PhCallKphQueryFileInformationWithTimeout(\n                processHandle,\n                Context->HandleItem->Handle,\n                FileModeInformation,\n                &fileModeInfo,\n                sizeof(FILE_MODE_INFORMATION)\n                )))\n            {\n                PH_FORMAT format[5];\n                PPH_STRING fileModeAccessStr;\n                WCHAR fileModeString[MAX_PATH];\n\n                // Since FILE_MODE_INFORMATION has no flag for asynchronous I/O we should use our own flag and set\n                // it only if none of synchronous flags are present. That's why we need PhFileModeUpdAsyncFlag.\n                fileModeAccessStr = PhGetAccessString(\n                    PhFileModeUpdAsyncFlag(fileModeInfo.Mode),\n                    (PPH_ACCESS_ENTRY)FileModeAccessEntries,\n                    RTL_NUMBER_OF(FileModeAccessEntries)\n                    );\n\n                PhInitFormatS(&format[0], L\"0x\");\n                PhInitFormatX(&format[1], fileModeInfo.Mode);\n                PhInitFormatS(&format[2], L\" (\");\n                PhInitFormatSR(&format[3], fileModeAccessStr->sr);\n                PhInitFormatS(&format[4], L\")\");\n\n                if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), fileModeString, sizeof(fileModeString), NULL))\n                {\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEMODE, 1, fileModeString);\n                }\n\n                PhDereferenceObject(fileModeAccessStr);\n            }\n\n            if (!isConsoleHandle)\n            {\n                if (NT_SUCCESS(status = PhCallKphQueryFileInformationWithTimeout(\n                    processHandle,\n                    Context->HandleItem->Handle,\n                    FileStandardInformation,\n                    &fileStandardInfo,\n                    sizeof(FILE_STANDARD_INFORMATION)\n                    )))\n                {\n                    PH_FORMAT format[1];\n                    WCHAR fileSizeString[PH_INT64_STR_LEN];\n\n                    PhInitFormatSize(&format[0], fileStandardInfo.EndOfFile.QuadPart);\n\n                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), fileSizeString, sizeof(fileSizeString), NULL))\n                    {\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILESIZE, 1, fileSizeString);\n                    }\n\n                    if (isFileOrDirectory)\n                    {\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, fileStandardInfo.Directory ? L\"Directory\" : L\"File\");\n                    }\n\n                    //disableFlushButton |= fileStandardInfo.Directory;\n                }\n\n                if (NT_SUCCESS(status = PhCallKphQueryFileInformationWithTimeout(\n                    processHandle,\n                    Context->HandleItem->Handle,\n                    FilePositionInformation,\n                    &filePositionInfo,\n                    sizeof(FILE_POSITION_INFORMATION)\n                    )))\n                {\n                    if (filePositionInfo.CurrentByteOffset.QuadPart != 0 && fileStandardInfo.EndOfFile.QuadPart != 0)\n                    {\n                        PH_FORMAT format[4];\n                        WCHAR filePositionString[PH_INT64_STR_LEN];\n\n                        PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart);\n                        PhInitFormatS(&format[1], L\" (\");\n                        PhInitFormatF(&format[2], (FLOAT)filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100.f, 1);\n                        PhInitFormatS(&format[3], L\"%)\");\n\n                        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL))\n                        {\n                            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPOSITION, 1, filePositionString);\n                        }\n                    }\n                    else if (filePositionInfo.CurrentByteOffset.QuadPart != 0)\n                    {\n                        PH_FORMAT format[1];\n                        WCHAR filePositionString[PH_INT64_STR_LEN];\n\n                        PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart);\n\n                        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL))\n                        {\n                            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPOSITION, 1, filePositionString);\n                        }\n                    }\n                }\n            }\n\n            if (NT_SUCCESS(status = PhCallKphQueryFileInformationWithTimeout(\n                processHandle,\n                Context->HandleItem->Handle,\n                FileIoPriorityHintInformation,\n                &priorityInfo,\n                sizeof(priorityInfo)\n                )))\n            {\n                switch (priorityInfo.PriorityHint)\n                {\n                case IoPriorityVeryLow:\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"Very Low\");\n                    break;\n                case IoPriorityLow:\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"Low\");\n                    break;\n                case IoPriorityNormal:\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"Normal\");\n                    break;\n                case IoPriorityHigh:\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"High\");\n                    break;\n                case IoPriorityCritical:\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"Critical\");\n                    break;\n                }\n            }\n\n            if (NT_SUCCESS(KphQueryInformationObject(\n                processHandle,\n                Context->HandleItem->Handle,\n                KphObjectFileObjectDriver,\n                &fileObjectDriver,\n                sizeof(HANDLE),\n                NULL\n                )))\n            {\n                PPH_STRING driverName;\n\n                if (NT_SUCCESS(PhGetDriverName(fileObjectDriver, &driverName)))\n                {\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEDRIVER, 1, PhGetString(driverName));\n                    PhDereferenceObject(driverName);\n                }\n\n                if (NT_SUCCESS(PhGetDriverImageFileName(fileObjectDriver, &driverName)))\n                {\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEDRIVERIMAGE, 1, PhGetString(driverName));\n                    PhDereferenceObject(driverName);\n                }\n\n                NtClose(fileObjectDriver);\n            }\n\n            NtClose(processHandle);\n        }\n        else\n        {\n            HANDLE fileHandle = NULL;\n\n            if (NT_SUCCESS(status = PhOpenProcess(\n                &processHandle,\n                PROCESS_DUP_HANDLE,\n                Context->ProcessId\n                )))\n            {\n                status = NtDuplicateObject(\n                    processHandle,\n                    Context->HandleItem->Handle,\n                    NtCurrentProcess(),\n                    &fileHandle,\n                    FILE_READ_ACCESS | SYNCHRONIZE,\n                    0,\n                    0\n                    );\n\n                if (!NT_SUCCESS(status))\n                {\n                    status = NtDuplicateObject(\n                        processHandle,\n                        Context->HandleItem->Handle,\n                        NtCurrentProcess(),\n                        &fileHandle,\n                        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n                        0,\n                        0\n                        );\n                }\n\n                //if (!NT_SUCCESS(status))\n                //{\n                //    status = NtDuplicateObject(\n                //        processHandle,\n                //        Context->HandleItem->Handle,\n                //        NtCurrentProcess(),\n                //        &fileHandle,\n                //        MAXIMUM_ALLOWED | SYNCHRONIZE,\n                //        0,\n                //        0\n                //        );\n                //}\n\n                if (!NT_SUCCESS(status))\n                {\n                    status = NtDuplicateObject(\n                        processHandle,\n                        Context->HandleItem->Handle,\n                        NtCurrentProcess(),\n                        &fileHandle,\n                        0,\n                        0,\n                        DUPLICATE_SAME_ACCESS\n                        );\n\n                    if (NT_SUCCESS(status))\n                    {\n                        HANDLE newhandle;\n\n                        if (NT_SUCCESS(PhReOpenFile(\n                            &newhandle,\n                            fileHandle,\n                            FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n                            FILE_SHARE_READ,\n                            0\n                            )))\n                        {\n                            NtClose(fileHandle);\n                            fileHandle = newhandle;\n                        }\n                    }\n                }\n\n                NtClose(processHandle);\n            }\n\n            if (NT_SUCCESS(status) && fileHandle)\n            {\n                //BOOLEAN disableFlushButton = FALSE;\n                BOOLEAN isFileOrDirectory = FALSE;\n                BOOLEAN isConsoleHandle = FALSE;\n                //BOOLEAN isPipeHandle = FALSE;\n                //BOOLEAN isNetworkHandle = FALSE;\n                FILE_FS_DEVICE_INFORMATION fileDeviceInfo;\n                FILE_MODE_INFORMATION fileModeInfo;\n                FILE_STANDARD_INFORMATION fileStandardInfo;\n                FILE_POSITION_INFORMATION filePositionInfo;\n                FILE_IO_PRIORITY_HINT_INFORMATION_EX priorityInfo;\n                IO_STATUS_BLOCK isb;\n\n                if (NT_SUCCESS(NtQueryVolumeInformationFile(\n                    fileHandle,\n                    &isb,\n                    &fileDeviceInfo,\n                    sizeof(FILE_FS_DEVICE_INFORMATION),\n                    FileFsDeviceInformation\n                    )))\n                {\n                    switch (fileDeviceInfo.DeviceType)\n                    {\n                    case FILE_DEVICE_NAMED_PIPE:\n                        //isPipeHandle = TRUE;\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"Pipe\");\n                        break;\n                    case FILE_DEVICE_NETWORK:\n                        //isNetworkHandle = TRUE;\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"Network\");\n                        break;\n                    case FILE_DEVICE_CD_ROM:\n                    case FILE_DEVICE_CD_ROM_FILE_SYSTEM:\n                    case FILE_DEVICE_CONTROLLER:\n                    case FILE_DEVICE_DATALINK:\n                    case FILE_DEVICE_DFS:\n                    case FILE_DEVICE_DISK:\n                    case FILE_DEVICE_DISK_FILE_SYSTEM:\n                    case FILE_DEVICE_VIRTUAL_DISK:\n                        isFileOrDirectory = TRUE;\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"File or directory\");\n                        break;\n                    case FILE_DEVICE_CONSOLE:\n                        isConsoleHandle = TRUE;\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"Console\");\n                        break;\n                    default:\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, L\"Other\");\n                        break;\n                    }\n                }\n\n                // Note: These devices deadlock without a timeout (dmex)\n                // 1) Named pipes\n                // 2) \\Device\\ConDrv\\CurrentIn\n                // 3) \\Device\\VolMgrControl\n\n                if (NT_SUCCESS(status = PhCallNtQueryFileInformationWithTimeout(\n                    fileHandle,\n                    FileModeInformation,\n                    &fileModeInfo,\n                    sizeof(FILE_MODE_INFORMATION)\n                    )))\n                {\n                    PH_FORMAT format[5];\n                    PPH_STRING fileModeAccessStr;\n                    WCHAR fileModeString[MAX_PATH];\n\n                    // Since FILE_MODE_INFORMATION has no flag for asynchronous I/O we should use our own flag and set\n                    // it only if none of synchronous flags are present. That's why we need PhFileModeUpdAsyncFlag.\n                    fileModeAccessStr = PhGetAccessString(\n                        PhFileModeUpdAsyncFlag(fileModeInfo.Mode),\n                        (PPH_ACCESS_ENTRY)FileModeAccessEntries,\n                        RTL_NUMBER_OF(FileModeAccessEntries)\n                        );\n\n                    PhInitFormatS(&format[0], L\"0x\");\n                    PhInitFormatX(&format[1], fileModeInfo.Mode);\n                    PhInitFormatS(&format[2], L\" (\");\n                    PhInitFormatSR(&format[3], fileModeAccessStr->sr);\n                    PhInitFormatS(&format[4], L\")\");\n\n                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), fileModeString, sizeof(fileModeString), NULL))\n                    {\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEMODE, 1, fileModeString);\n                    }\n\n                    PhDereferenceObject(fileModeAccessStr);\n                }\n\n                if (!isConsoleHandle)\n                {\n                    if (NT_SUCCESS(status = PhCallNtQueryFileInformationWithTimeout(\n                        fileHandle,\n                        FileStandardInformation,\n                        &fileStandardInfo,\n                        sizeof(FILE_STANDARD_INFORMATION)\n                        )))\n                    {\n                        PH_FORMAT format[1];\n                        WCHAR fileSizeString[PH_INT64_STR_LEN];\n\n                        PhInitFormatSize(&format[0], fileStandardInfo.EndOfFile.QuadPart);\n\n                        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), fileSizeString, sizeof(fileSizeString), NULL))\n                        {\n                            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILESIZE, 1, fileSizeString);\n                        }\n\n                        if (isFileOrDirectory)\n                        {\n                            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILETYPE, 1, fileStandardInfo.Directory ? L\"Directory\" : L\"File\");\n                        }\n\n                        //disableFlushButton |= fileStandardInfo.Directory;\n                    }\n\n                    if (NT_SUCCESS(status = PhCallNtQueryFileInformationWithTimeout(\n                        fileHandle,\n                        FilePositionInformation,\n                        &filePositionInfo,\n                        sizeof(FILE_POSITION_INFORMATION)\n                        )))\n                    {\n                        if (fileStandardInfo.EndOfFile.QuadPart != 0)\n                        {\n                            PH_FORMAT format[4];\n                            WCHAR filePositionString[PH_INT64_STR_LEN];\n\n                            PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart);\n                            PhInitFormatS(&format[1], L\" (\");\n                            PhInitFormatF(&format[2], (FLOAT)filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100.f, 1);\n                            PhInitFormatS(&format[3], L\"%)\");\n\n                            if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL))\n                            {\n                                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPOSITION, 1, filePositionString);\n                            }\n                        }\n                        else\n                        {\n                            PH_FORMAT format[1];\n                            WCHAR filePositionString[PH_INT64_STR_LEN];\n\n                            PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart);\n\n                            if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL))\n                            {\n                                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPOSITION, 1, filePositionString);\n                            }\n                        }\n                    }\n                }\n\n\n                if (NT_SUCCESS(status = PhCallNtQueryFileInformationWithTimeout(\n                    fileHandle,\n                    FileIoPriorityHintInformation,\n                    &priorityInfo,\n                    sizeof(priorityInfo)\n                    )))\n                {\n                    switch (priorityInfo.PriorityHint)\n                    {\n                    case IoPriorityVeryLow:\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"Very Low\");\n                        break;\n                    case IoPriorityLow:\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"Low\");\n                        break;\n                    case IoPriorityNormal:\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"Normal\");\n                        break;\n                    case IoPriorityHigh:\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"High\");\n                        break;\n                    case IoPriorityCritical:\n                        PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_FILEPRIORITY, 1, L\"Critical\");\n                        break;\n                    }\n                }\n\n                NtClose(fileHandle);\n            }\n        }\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"Section\", TRUE))\n    {\n        NTSTATUS status;\n        SECTION_BASIC_INFORMATION basicInfo = { NULL };\n        PPH_STRING fileName = NULL;\n\n        if (KsiLevel() >= KphLevelMed && NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION,\n                Context->ProcessId\n                )))\n        {\n            ULONG bufferSize;\n            ULONG returnLength;\n            PUNICODE_STRING buffer;\n            NTSTATUS status2;\n\n            returnLength = 0;\n            bufferSize = 0x100;\n            buffer = PhAllocate(bufferSize);\n\n            status = KphQueryInformationObject(\n                processHandle,\n                Context->HandleItem->Handle,\n                KphObjectSectionBasicInformation,\n                &basicInfo,\n                sizeof(basicInfo),\n                NULL\n                );\n\n            status2 = KphQueryInformationObject(\n                processHandle,\n                Context->HandleItem->Handle,\n                KphObjectSectionFileName,\n                buffer,\n                bufferSize,\n                &returnLength\n                );\n            if (status2 == STATUS_BUFFER_OVERFLOW && returnLength > 0)\n            {\n                PhFree(buffer);\n                bufferSize = returnLength;\n                buffer = PhAllocate(returnLength);\n\n                status2 = KphQueryInformationObject(\n                    processHandle,\n                    Context->HandleItem->Handle,\n                    KphObjectSectionFileName,\n                    buffer,\n                    bufferSize,\n                    &returnLength\n                    );\n            }\n\n            if (NT_SUCCESS(status2))\n            {\n                fileName = PhCreateStringFromUnicodeString(buffer);\n            }\n\n            PhFree(buffer);\n            NtClose(processHandle);\n        }\n        else\n        {\n            HANDLE sectionHandle = NULL;\n\n            if (NT_SUCCESS(status = PhOpenProcess(\n                &processHandle,\n                PROCESS_DUP_HANDLE,\n                Context->ProcessId\n                )))\n            {\n                status = NtDuplicateObject(\n                    processHandle,\n                    Context->HandleItem->Handle,\n                    NtCurrentProcess(),\n                    &sectionHandle,\n                    SECTION_QUERY | SECTION_MAP_READ,\n                    0,\n                    0\n                    );\n\n                if (!NT_SUCCESS(status))\n                {\n                    status = NtDuplicateObject(\n                        processHandle,\n                        Context->HandleItem->Handle,\n                        NtCurrentProcess(),\n                        &sectionHandle,\n                        SECTION_QUERY,\n                        0,\n                        0\n                        );\n                }\n\n                NtClose(processHandle);\n            }\n\n            if (NT_SUCCESS(status) && sectionHandle)\n            {\n                status = PhGetSectionBasicInformation(sectionHandle, &basicInfo);\n\n                if (!NT_SUCCESS(PhGetSectionFileName(sectionHandle, &fileName)))\n                {\n                    fileName = NULL;\n                }\n\n                NtClose(sectionHandle);\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            PCWSTR sectionType = L\"Unknown\";\n            PPH_STRING sectionSize = NULL;\n\n            if (FlagOn(basicInfo.AllocationAttributes, SEC_COMMIT))\n                sectionType = L\"Commit\";\n            else if (FlagOn(basicInfo.AllocationAttributes, SEC_FILE))\n                sectionType = L\"File\";\n            else if (FlagOn(basicInfo.AllocationAttributes, SEC_IMAGE))\n                sectionType = L\"Image\";\n            else if (FlagOn(basicInfo.AllocationAttributes, SEC_RESERVE))\n                sectionType = L\"Reserve\";\n\n            sectionSize = PhaFormatSize(basicInfo.MaximumSize.QuadPart, ULONG_MAX);\n\n            if (fileName)\n            {\n                PhMoveReference(&fileName, PhGetFileName(fileName));\n            }\n\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_SECTIONFILE, 1, PhGetStringOrDefault(fileName, L\"N/A\"));\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_SECTIONTYPE, 1, sectionType);\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_SECTIONSIZE, 1, PhGetStringOrDefault(sectionSize, L\"Unknown\"));\n        }\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"Mutant\", TRUE))\n    {\n        NTSTATUS status;\n        HANDLE mutantHandle = NULL;\n\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_DUP_HANDLE,\n            Context->ProcessId\n            )))\n        {\n            status = NtDuplicateObject(\n                processHandle,\n                Context->HandleItem->Handle,\n                NtCurrentProcess(),\n                &mutantHandle,\n                SEMAPHORE_QUERY_STATE,\n                0,\n                0\n                );\n            NtClose(processHandle);\n        }\n\n        if (NT_SUCCESS(status) && mutantHandle)\n        {\n            MUTANT_BASIC_INFORMATION basicInfo;\n            MUTANT_OWNER_INFORMATION ownerInfo;\n\n            if (NT_SUCCESS(PhGetMutantBasicInformation(mutantHandle, &basicInfo)))\n            {\n                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_MUTANTCOUNT, 1, PhaFormatUInt64(basicInfo.CurrentCount, TRUE)->Buffer);\n                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_MUTANTABANDONED, 1, basicInfo.AbandonedState ? L\"True\" : L\"False\");\n            }\n\n            if (NT_SUCCESS(PhGetMutantOwnerInformation(mutantHandle, &ownerInfo)))\n            {\n                PPH_STRING name;\n\n                if (ownerInfo.ClientId.UniqueProcess)\n                {\n                    name = PhGetClientIdName(&ownerInfo.ClientId);\n                    PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_MUTANTOWNER, 1, name->Buffer);\n                    PhDereferenceObject(name);\n                }\n            }\n\n            NtClose(mutantHandle);\n        }\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"Process\", TRUE))\n    {\n        NTSTATUS status;\n        NTSTATUS exitStatus = STATUS_PENDING;\n        PPH_STRING fileName = NULL;\n        PROCESS_BASIC_INFORMATION basicInfo;\n        KERNEL_USER_TIMES times;\n        BOOLEAN haveTimes = FALSE;\n\n        // TODO(jxy-s): Uncomment following code after next driver release (commented out as workaround for KphObjectProcessImageFileName memory leak) (dmex)\n        //if (KsiLevel() >= KphLevelMed && NT_SUCCESS(PhOpenProcess(\n        //        &processHandle,\n        //        PROCESS_QUERY_LIMITED_INFORMATION,\n        //        Context->ProcessId\n        //        )))\n        //{\n        //    ULONG bufferSize;\n        //    ULONG returnLength;\n        //    PUNICODE_STRING buffer;\n        //    NTSTATUS status2;\n\n        //    returnLength = 0;\n        //    bufferSize = 0x100;\n        //    buffer = PhAllocate(bufferSize);\n\n        //    if (NT_SUCCESS(KphQueryInformationObject(\n        //        processHandle,\n        //        Context->HandleItem->Handle,\n        //        KphObjectProcessBasicInformation,\n        //        &basicInfo,\n        //        sizeof(basicInfo),\n        //        NULL\n        //        )))\n        //    {\n        //        exitStatus = basicInfo.ExitStatus;\n        //    }\n\n        //    haveTimes = NT_SUCCESS(KphQueryInformationObject(\n        //        processHandle,\n        //        Context->HandleItem->Handle,\n        //        KphObjectProcessTimes,\n        //        &times,\n        //        sizeof(times),\n        //        NULL\n        //        ));\n\n        //    status2 = KphQueryInformationObject(\n        //        processHandle,\n        //        Context->HandleItem->Handle,\n        //        KphObjectProcessImageFileName,\n        //        buffer,\n        //        bufferSize,\n        //        &returnLength\n        //        );\n        //    if (status2 == STATUS_BUFFER_TOO_SMALL && returnLength > 0)\n        //    {\n        //        PhFree(buffer);\n        //        bufferSize = returnLength;\n        //        buffer = PhAllocate(returnLength);\n\n        //        status2 = KphQueryInformationObject(\n        //            processHandle,\n        //            Context->HandleItem->Handle,\n        //            KphObjectProcessImageFileName,\n        //            buffer,\n        //            bufferSize,\n        //            &returnLength\n        //            );\n        //    }\n\n        //    if (NT_SUCCESS(status2))\n        //    {\n        //        fileName = PhCreateStringFromUnicodeString(buffer);\n        //        PhMoveReference(&fileName, PhGetFileName(fileName));\n        //    }\n\n        //    NtClose(processHandle);\n        //}\n        //else\n        {\n            HANDLE dupHandle = NULL;\n\n            if (NT_SUCCESS(status = PhOpenProcess(\n                &processHandle,\n                PROCESS_DUP_HANDLE,\n                Context->ProcessId\n                )))\n            {\n                status = NtDuplicateObject(\n                    processHandle,\n                    Context->HandleItem->Handle,\n                    NtCurrentProcess(),\n                    &dupHandle,\n                    PROCESS_QUERY_LIMITED_INFORMATION,\n                    0,\n                    0\n                    );\n\n                NtClose(processHandle);\n            }\n\n            if (NT_SUCCESS(status) && dupHandle)\n            {\n                if (NT_SUCCESS(PhGetProcessImageFileName(dupHandle, &fileName)))\n                {\n                    PhMoveReference(&fileName, PhGetFileName(fileName));\n                }\n\n                if (NT_SUCCESS(PhGetProcessBasicInformation(dupHandle, &basicInfo)))\n                {\n                    exitStatus = basicInfo.ExitStatus;\n                }\n\n                haveTimes = NT_SUCCESS(PhGetProcessTimes(dupHandle, &times));\n\n                NtClose(dupHandle);\n            }\n        }\n\n        if (fileName)\n        {\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME, 1, PhGetStringOrEmpty(fileName));\n            PhDereferenceObject(fileName);\n        }\n\n        if (haveTimes)\n        {\n            SYSTEMTIME time;\n\n            PhLargeIntegerToLocalSystemTime(&time, &times.CreateTime);\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME, 1, PhaFormatDateTime(&time)->Buffer);\n\n            if (exitStatus != STATUS_PENDING)\n            {\n                PhLargeIntegerToLocalSystemTime(&time, &times.ExitTime);\n                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME, 1, PhaFormatDateTime(&time)->Buffer);\n            }\n        }\n\n        if (exitStatus != STATUS_PENDING)\n        {\n            PPH_STRING message;\n            PPH_STRING exitcode;\n\n            message = PhGetStatusMessage(exitStatus, 0);\n            exitcode = PhFormatString(L\"0x%x (%s)\", exitStatus, PhGetStringOrDefault(message, L\"Unknown\"));\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE, 1, PhGetStringOrEmpty(exitcode));\n            PhClearReference(&exitcode);\n            PhClearReference(&message);\n        }\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"Thread\", TRUE))\n    {\n        NTSTATUS status;\n        BOOLEAN isTerminated = FALSE;\n        PPH_STRING name = NULL;\n        KERNEL_USER_TIMES times;\n        NTSTATUS exitStatus = STATUS_PENDING;\n\n        if (KsiLevel() >= KphLevelMed && NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION,\n                Context->ProcessId\n                )))\n        {\n            PPH_STRING threadName;\n            ULONG threadIsTerminated;\n            THREAD_BASIC_INFORMATION basicInfo;\n\n            if (NT_SUCCESS(KphQueryObjectThreadName(\n                processHandle,\n                Context->HandleItem->Handle,\n                &threadName\n                )))\n            {\n                name = threadName;\n            }\n\n            if (NT_SUCCESS(KphQueryInformationObject(\n                processHandle,\n                Context->HandleItem->Handle,\n                KphObjectThreadIsTerminated,\n                &threadIsTerminated,\n                sizeof(threadIsTerminated),\n                NULL\n                )))\n            {\n                isTerminated = !!threadIsTerminated;\n            }\n\n            if (isTerminated && NT_SUCCESS(KphQueryInformationObject(\n                processHandle,\n                Context->HandleItem->Handle,\n                KphObjectThreadBasicInformation,\n                &basicInfo,\n                sizeof(basicInfo),\n                NULL\n                )))\n            {\n                exitStatus = basicInfo.ExitStatus;\n            }\n\n            status = KphQueryInformationObject(\n                processHandle,\n                Context->HandleItem->Handle,\n                KphObjectThreadTimes,\n                &times,\n                sizeof(times),\n                NULL\n                );\n\n            NtClose(processHandle);\n        }\n        else\n        {\n            HANDLE dupHandle = NULL;\n            PPH_STRING threadName;\n            THREAD_BASIC_INFORMATION basicInfo;\n\n            if (NT_SUCCESS(status = PhOpenProcess(\n                &processHandle,\n                PROCESS_DUP_HANDLE,\n                Context->ProcessId\n                )))\n            {\n                status = NtDuplicateObject(\n                    processHandle,\n                    Context->HandleItem->Handle,\n                    NtCurrentProcess(),\n                    &dupHandle,\n                    THREAD_QUERY_LIMITED_INFORMATION,\n                    0,\n                    0\n                    );\n\n                NtClose(processHandle);\n            }\n\n            if (NT_SUCCESS(status) && dupHandle)\n            {\n                if (NT_SUCCESS(PhGetThreadName(dupHandle, &threadName)))\n                {\n                    name = threadName;\n                }\n\n                PhGetThreadIsTerminated(dupHandle, &isTerminated);\n\n                if (isTerminated && NT_SUCCESS(PhGetThreadBasicInformation(dupHandle, &basicInfo)))\n                {\n                    exitStatus = basicInfo.ExitStatus;\n                }\n\n                status = PhGetThreadTimes(dupHandle, &times);\n\n                NtClose(dupHandle);\n            }\n        }\n\n        if (name)\n        {\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME, 1, PhGetStringOrEmpty(name));\n            PhDereferenceObject(name);\n        }\n\n        if (isTerminated)\n        {\n            PPH_STRING message;\n            PPH_STRING exitcode;\n\n            message = PhGetStatusMessage(exitStatus, 0);\n            exitcode = PhFormatString(L\"0x%x (%s)\", exitStatus, PhGetStringOrDefault(message, L\"Unknown\"));\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE, 1, PhGetStringOrEmpty(exitcode));\n            PhClearReference(&exitcode);\n            PhClearReference(&message);\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            SYSTEMTIME time;\n\n            PhLargeIntegerToLocalSystemTime(&time, &times.CreateTime);\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME, 1, PhaFormatDateTime(&time)->Buffer);\n\n            if (isTerminated)\n            {\n                PhLargeIntegerToLocalSystemTime(&time, &times.ExitTime);\n                PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME, 1, PhaFormatDateTime(&time)->Buffer);\n            }\n        }\n    }\n    else if (PhEqualString2(Context->HandleItem->TypeName, L\"SymbolicLink\", TRUE))\n    {\n        PPH_STRING linkTarget;\n\n        if (!PhIsNullOrEmptyString(Context->HandleItem->ObjectName) &&\n            NT_SUCCESS(PhQuerySymbolicLinkObject(&linkTarget, NULL, &Context->HandleItem->ObjectName->sr)))\n        {\n            PhSetHandleListViewItem(Context, PH_HANDLE_GENERAL_INDEX_SYMBOLICLINKLINK, 1, PhGetStringOrEmpty(linkTarget));\n            PhDereferenceObject(linkTarget);\n        }\n    }\n}\n\nINT_PTR CALLBACK PhpHandleGeneralDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PHANDLE_PROPERTIES_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;\n        context = (PHANDLE_PROPERTIES_CONTEXT)propSheetPage->lParam;\n        PhSetDialogContext(hwndDlg, context);\n    }\n    else\n    {\n        context = PhGetDialogContext(hwndDlg);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(context->ParentWindow);\n\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            context->ParentWindow = GetParent(hwndDlg);\n            context->ListViewClass = PhListView_Initialize(context->ListViewHandle);\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 120, L\"Name\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 250, L\"Value\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_HANDLE_PROPERTIES_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_HANDLE_PROPERTIES_WINDOW_POSITION, NULL, context->ParentWindow);\n            else\n                PhCenterWindow(context->ParentWindow, GetParent(context->ParentWindow)); // HACK\n\n            PhpUpdateHandleGeneralListViewGroups(context);\n            PhpUpdateHandleGeneral(context);\n\n            PhRegisterWindowCallback(context->ParentWindow, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL);\n\n            if (PhPluginsEnabled)\n            {\n                PPH_PLUGIN_HANDLE_PROPERTIES_WINDOW_CONTEXT Context;\n                Context = (PPH_PLUGIN_HANDLE_PROPERTIES_WINDOW_CONTEXT)context;\n\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandlePropertiesWindowInitialized), Context);\n            }\n\n            if (PhEnableThemeSupport) // TODO: Required for compat (dmex)\n                PhInitializeWindowTheme(context->ParentWindow, PhEnableThemeSupport);\n            else\n                PhInitializeWindowTheme(hwndDlg, FALSE);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhUnregisterWindowCallback(context->ParentWindow);\n\n            PhSaveWindowPlacementToSetting(SETTING_HANDLE_PROPERTIES_WINDOW_POSITION, NULL, context->ParentWindow);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhListView_Destroy(context->ListViewClass);\n\n            PhRemoveDialogContext(hwndDlg);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n            ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)context->ListViewHandle);\n                return TRUE;\n            }\n\n            REFLECT_MESSAGE_DLG(hwndDlg, context->ListViewHandle, uMsg, wParam, lParam);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID *listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(context->ListViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n        HANDLE_MSG(hwndDlg, WM_CTLCOLORBTN, PhWindowThemeControlColor);\n        HANDLE_MSG(hwndDlg, WM_CTLCOLORDLG, PhWindowThemeControlColor);\n        HANDLE_MSG(hwndDlg, WM_CTLCOLORSTATIC, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhAddStatusPermissionsTrustee(\n    _In_ PHANDLE_PERMISSIONS_CONTEXT Context,\n    _In_ HWND ListViewHandle,\n    _In_ NTSTATUS status,\n    _In_ ULONG Index\n    )\n{\n    //LONG index = PhAddListViewItem(ListViewHandle, MAXINT, Message, NULL);\n    //PhSetListViewSubItem(ListViewHandle, index, 1, L\"N/A\");\n    //PhSetListViewSubItem(ListViewHandle, index, 2, L\"N/A\");\n\n    //if (!NT_SUCCESS(status))\n    {\n        PPH_STRING string;\n\n        string = PhGetNtMessage(status);\n        PhMoveReference(&string, PhFormatString(L\"0x%x: %s\",\n            status,\n            PhGetStringOrDefault(string, L\"N/A\")\n            ));\n\n        PhSetListViewSubItem(ListViewHandle, 1, 1, PhGetString(string));\n        //PhSetListViewSubItem(ListViewHandle, 2, 1, PhGetString(string));\n        //PhSetListViewSubItem(ListViewHandle, 3, 1, PhGetString(string));\n        PhClearReference(&string);\n    }\n}\n\nVOID PhAddHandlePermissionsTrustee(\n    _In_ PHANDLE_PERMISSIONS_CONTEXT Context,\n    _In_ HWND ListViewHandle,\n    _In_ PSID TrusteeSid,\n    _In_ ACCESS_MASK TrusteeMask,\n    _In_ ULONG Index\n    )\n{\n    LONG index;\n    PPH_ACCESS_ENTRY accessEntries;\n    ULONG numberOfAccessEntries;\n    PPH_STRING string;\n    SID_NAME_USE sidNameUse;\n\n    if (string = PhGetSidFullName(TrusteeSid, FALSE, &sidNameUse))\n    {\n        switch (sidNameUse)\n        {\n        case SidTypeUser:\n        case SidTypeLogonSession:\n        case SidTypeDeletedAccount:\n            PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (User)\"));\n            break;\n        case SidTypeAlias:\n        case SidTypeGroup:\n        case SidTypeWellKnownGroup:\n            PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (Group)\"));\n            break;\n        case SidTypeDomain:\n        case SidTypeComputer:\n            PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (Computer)\"));\n            break;\n        }\n    }\n    else if (string = PhGetAppContainerPackageName(TrusteeSid))\n    {\n        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (APP_PACKAGE)\"));\n    }\n    else if (string = PhGetAppContainerName(TrusteeSid))\n    {\n        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (APP_CONTAINER)\"));\n    }\n    else if (string = PhGetCapabilitySidName(TrusteeSid))\n    {\n        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (APP_CAPABILITY)\"));\n    }\n\n    if (Index)\n    {\n        index = Index;\n        PhSetListViewSubItem(ListViewHandle, Index, 1, PhGetStringOrDefault(string, L\"N/A\"));\n    }\n    else\n    {\n        index = PhAddListViewItem(\n            ListViewHandle,\n            MAXINT,\n            PhGetStringOrDefault(string, L\"N/A\"),\n            NULL\n            );\n        PhSetListViewSubItem(ListViewHandle, index, 1, L\"Allow\");\n    }\n\n\n    if (PhGetAccessEntries(\n        PhGetStringOrEmpty(Context->HandleProperties->HandleItem->TypeName),\n        &accessEntries,\n        &numberOfAccessEntries\n        ))\n    {\n        PPH_STRING accessString;\n\n        if (accessString = PH_AUTO(PhGetAccessString(\n            TrusteeMask,\n            accessEntries,\n            numberOfAccessEntries\n            )))\n        {\n            PhSetListViewSubItem(Context->ListViewHandle, index, 2, PhGetStringOrEmpty(accessString));\n        }\n        else\n        {\n            PhSetListViewSubItem(Context->ListViewHandle, index, 2, L\"N/A\");\n        }\n\n        PhFree(accessEntries);\n    }\n}\n\nVOID PhUpdateHandlePermissionsOwnerSecurity(\n    _In_ PHANDLE_PERMISSIONS_CONTEXT Context,\n    _In_ HANDLE QueryHandle\n    )\n{\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n    BOOLEAN currentOwnerDefaulted;\n    PACL currentOwner;\n\n    status = PhGetObjectSecurity(\n        QueryHandle,\n        OWNER_SECURITY_INFORMATION,\n        &currentSecurityDescriptor\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetOwnerSecurityDescriptor(\n            currentSecurityDescriptor,\n            &currentOwner,\n            &currentOwnerDefaulted\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (currentOwner)\n            {\n                PPH_STRING string;\n                SID_NAME_USE sidNameUse;\n\n                if (string = PhGetSidFullName(currentOwner, FALSE, &sidNameUse))\n                {\n                    switch (sidNameUse)\n                    {\n                    case SidTypeUser:\n                    case SidTypeLogonSession:\n                    case SidTypeDeletedAccount:\n                        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (User)\"));\n                        break;\n                    case SidTypeAlias:\n                    case SidTypeGroup:\n                    case SidTypeWellKnownGroup:\n                        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (Group)\"));\n                        break;\n                    case SidTypeDomain:\n                    case SidTypeComputer:\n                        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (Computer)\"));\n                        break;\n                    }\n                }\n                else if (string = PhGetAppContainerPackageName(currentOwner))\n                {\n                    PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (APP_PACKAGE)\"));\n                }\n                else if (string = PhGetAppContainerName(currentOwner))\n                {\n                    PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (APP_CONTAINER)\"));\n                }\n                else if (string = PhGetCapabilitySidName(currentOwner))\n                {\n                    PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (APP_CAPABILITY)\"));\n                }\n\n                PhSetListViewSubItem(Context->ListViewHeader, 0, 1, PhGetStringOrDefault(string, L\"N/A\"));\n                PhClearReference(&string);\n            }\n            else\n            {\n                PhSetListViewSubItem(Context->ListViewHeader, 0, 1, L\"NULL\");\n            }\n        }\n        else\n        {\n            PPH_STRING string = PhGetNtMessage(status);;\n            PhSetListViewSubItem(Context->ListViewHeader, 0, 1, PH_AUTO_T(PH_STRING, PhFormatString(\n                L\"0x%x: %s\",\n                status,\n                PhGetStringOrEmpty(string)))->Buffer);\n            PhClearReference(&string);\n        }\n\n        PhFree(currentSecurityDescriptor);\n    }\n    else\n    {\n        PPH_STRING string = PhGetNtMessage(status);;\n        PhSetListViewSubItem(Context->ListViewHeader, 0, 1, PH_AUTO_T(PH_STRING, PhFormatString(\n            L\"0x%x: %s\",\n            status,\n            PhGetStringOrEmpty(string)))->Buffer);\n        PhClearReference(&string);\n    }\n}\n\nVOID PhUpdateHandlePermissionsGroupSecurity(\n    _In_ PHANDLE_PERMISSIONS_CONTEXT Context,\n    _In_ HANDLE QueryHandle\n    )\n{\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n    BOOLEAN currentGroupDefaulted;\n    PACL currentGroupSid;\n\n    status = PhGetObjectSecurity(\n        QueryHandle,\n        GROUP_SECURITY_INFORMATION,\n        &currentSecurityDescriptor\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetGroupSecurityDescriptor(\n            currentSecurityDescriptor,\n            &currentGroupSid,\n            &currentGroupDefaulted\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (currentGroupSid)\n            {\n                PPH_STRING string;\n                SID_NAME_USE sidNameUse;\n\n                if (string = PhGetSidFullName(currentGroupSid, FALSE, &sidNameUse))\n                {\n                    switch (sidNameUse)\n                    {\n                    case SidTypeUser:\n                    case SidTypeLogonSession:\n                    case SidTypeDeletedAccount:\n                        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (User)\"));\n                        break;\n                    case SidTypeAlias:\n                    case SidTypeGroup:\n                    case SidTypeWellKnownGroup:\n                        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (Group)\"));\n                        break;\n                    case SidTypeDomain:\n                    case SidTypeComputer:\n                        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (Computer)\"));\n                        break;\n                    }\n                }\n                else if (string = PhGetAppContainerPackageName(currentGroupSid))\n                {\n                    PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (APP_PACKAGE)\"));\n                }\n                else if (string = PhGetAppContainerName(currentGroupSid))\n                {\n                    PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (APP_CONTAINER)\"));\n                }\n                else if (string = PhGetCapabilitySidName(currentGroupSid))\n                {\n                    PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (APP_CAPABILITY)\"));\n                }\n\n                PhSetListViewSubItem(Context->ListViewHeader, 1, 1, PhGetStringOrDefault(string, L\"N/A\"));\n                PhClearReference(&string);\n            }\n            else\n            {\n                PhSetListViewSubItem(Context->ListViewHeader, 1, 1, L\"NULL\");\n            }\n        }\n        else\n        {\n            PPH_STRING string = PhGetNtMessage(status);;\n            PhSetListViewSubItem(Context->ListViewHeader, 1, 1, PH_AUTO_T(PH_STRING, PhFormatString(\n                L\"0x%x: %s\",\n                status,\n                PhGetStringOrEmpty(string)))->Buffer);\n            PhClearReference(&string);\n        }\n\n        PhFree(currentSecurityDescriptor);\n    }\n    else\n    {\n        PPH_STRING string = PhGetNtMessage(status);;\n        PhSetListViewSubItem(Context->ListViewHeader, 1, 1, PH_AUTO_T(PH_STRING, PhFormatString(\n            L\"0x%x: %s\",\n            status,\n            PhGetStringOrEmpty(string)))->Buffer);\n        PhClearReference(&string);\n    }\n}\n\nVOID PhUpdateHandlePermissionsSaclSecurity(\n    _In_ PHANDLE_PERMISSIONS_CONTEXT Context,\n    _In_ HANDLE QueryHandle\n    )\n{\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n    BOOLEAN currentSaclPresent;\n    BOOLEAN currentSaclDefaulted;\n    PACL currentSacl;\n\n    status = PhGetObjectSecurity(\n        QueryHandle,\n        SACL_SECURITY_INFORMATION,\n        &currentSecurityDescriptor\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetSaclSecurityDescriptor(\n            currentSecurityDescriptor,\n            &currentSaclPresent,\n            &currentSacl,\n            &currentSaclDefaulted\n            );\n\n        if (NT_SUCCESS(status) && currentSaclPresent && currentSacl)\n        {\n            PSYSTEM_MANDATORY_LABEL_ACE currentAce;\n\n            for (USHORT i = 0; i < currentSacl->AceCount; i++)\n            {\n                status = PhGetAce(currentSacl, i, &currentAce);\n\n                if (NT_SUCCESS(status))\n                {\n                    switch (currentAce->Header.AceType)\n                    {\n                    case SYSTEM_MANDATORY_LABEL_ACE_TYPE:\n                        {\n                            PSID trusteeSidBuffer = &currentAce->SidStart;\n                            ULONG trusteeSidlength = PhLengthSid(trusteeSidBuffer);\n                            ULONG opaqueDataLength = currentAce->Header.AceSize - trusteeSidlength - FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart);\n                            // The remaining bytes of the SID are stored in contiguous memory after the SidStart member. This SID can be appended with application data.\n\n                            PhAddHandlePermissionsTrustee(Context, Context->ListViewHandle, trusteeSidBuffer, currentAce->Mask, 0);\n                        }\n                        break;\n                    }\n                }\n                else\n                {\n                    PhAddStatusPermissionsTrustee(Context, Context->ListViewHeader, status, 0);\n                }\n            }\n        }\n\n        PhFree(currentSecurityDescriptor);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhAddStatusPermissionsTrustee(Context, Context->ListViewHeader, status, 0);\n    }\n}\n\nVOID PhUpdateHandlePermissionsLabelSecurity(\n    _In_ PHANDLE_PERMISSIONS_CONTEXT Context,\n    _In_ HANDLE QueryHandle\n    )\n{\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n    BOOLEAN currentSaclPresent;\n    BOOLEAN currentSaclDefaulted;\n    PACL currentSacl;\n\n    status = PhGetObjectSecurity(\n        QueryHandle,\n        LABEL_SECURITY_INFORMATION,\n        &currentSecurityDescriptor\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetSaclSecurityDescriptor(\n            currentSecurityDescriptor,\n            &currentSaclPresent,\n            &currentSacl,\n            &currentSaclDefaulted\n            );\n\n        if (NT_SUCCESS(status) && currentSaclPresent && currentSacl)\n        {\n            PSYSTEM_MANDATORY_LABEL_ACE currentAce;\n\n            for (USHORT i = 0; i < currentSacl->AceCount; i++)\n            {\n                status = PhGetAce(currentSacl, i, &currentAce);\n\n                if (NT_SUCCESS(status))\n                {\n                    switch (currentAce->Header.AceType)\n                    {\n                    case SYSTEM_MANDATORY_LABEL_ACE_TYPE:\n                        {\n                            PSID trusteeSidBuffer = &currentAce->SidStart;\n                            ULONG trusteeSidlength = PhLengthSid(trusteeSidBuffer);\n                            ULONG opaqueDataLength = currentAce->Header.AceSize - trusteeSidlength - FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart);\n                            // The remaining bytes of the SID are stored in contiguous memory after the SidStart member. This SID can be appended with application data.\n\n                            PhAddHandlePermissionsTrustee(Context, Context->ListViewHeader, trusteeSidBuffer, currentAce->Mask, 2);\n                        }\n                        break;\n                    }\n                }\n                else\n                {\n                    PhAddStatusPermissionsTrustee(Context, Context->ListViewHeader, status, 2);\n                }\n            }\n        }\n\n        PhFree(currentSecurityDescriptor);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhAddStatusPermissionsTrustee(Context, Context->ListViewHeader, status, 2);\n    }\n}\n\nVOID PhUpdateHandlePermissionsDaclSecurity(\n    _In_ PHANDLE_PERMISSIONS_CONTEXT Context,\n    _In_ HANDLE QueryHandle\n    )\n{\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n    BOOLEAN currentSaclPresent;\n    BOOLEAN currentSaclDefaulted;\n    PACL currentSacl;\n\n    status = PhGetObjectSecurity(\n        QueryHandle,\n        DACL_SECURITY_INFORMATION,\n        &currentSecurityDescriptor\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetDaclSecurityDescriptor(\n            currentSecurityDescriptor,\n            &currentSaclPresent,\n            &currentSacl,\n            &currentSaclDefaulted\n            );\n\n        if (NT_SUCCESS(status) && currentSaclPresent && currentSacl)\n        {\n            PACCESS_ALLOWED_ACE currentAce;\n\n            for (USHORT i = 0; i < currentSacl->AceCount; i++)\n            {\n                status = PhGetAce(currentSacl, i, &currentAce);\n\n                if (NT_SUCCESS(status))\n                {\n                    switch (currentAce->Header.AceType)\n                    {\n                    case ACCESS_ALLOWED_ACE_TYPE:\n                        {\n                            PSID trusteeSidBuffer = &currentAce->SidStart;\n                            ULONG trusteeSidlength = PhLengthSid(trusteeSidBuffer);\n                            ULONG opaqueDataLength = currentAce->Header.AceSize - trusteeSidlength - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart);\n                            // The remaining bytes of the SID are stored in contiguous memory after the SidStart member. This SID can be appended with application data.\n\n                            PhAddHandlePermissionsTrustee(Context, Context->ListViewHandle, trusteeSidBuffer, currentAce->Mask, 0);\n\n\n                            if (FlagOn(currentAce->Header.AceFlags, INHERITED_ACE))\n                            {\n                                // This ACE is inherited\n                            }\n\n                            if (FlagOn(currentAce->Header.AceFlags, OBJECT_INHERIT_ACE))\n                            {\n                                // This ACE can be inherited by child objects\n                            }\n\n                            if (FlagOn(currentAce->Header.AceFlags, CONTAINER_INHERIT_ACE))\n                            {\n                                // This ACE can be inherited by container child objects\n                            }\n\n                        }\n                        break;\n                    }\n                }\n            }\n        }\n\n        PhFree(currentSecurityDescriptor);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhAddStatusPermissionsTrustee(Context, Context->ListViewHeader, status, 2);\n    }\n\n}\n\n\nVOID PhUpdateHandlePermissionSecurity(\n    _In_ PHANDLE_PERMISSIONS_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    HANDLE dupHandle = NULL;\n\n    PhSetListViewStyle(Context->ListViewHeader, FALSE, TRUE);\n    PhSetControlTheme(Context->ListViewHeader, L\"explorer\");\n    PhAddListViewColumn(Context->ListViewHeader, 0, 0, 0, LVCFMT_LEFT, 120, L\"Name\");\n    PhAddListViewColumn(Context->ListViewHeader, 1, 1, 1, LVCFMT_LEFT, 250, L\"Value\");\n    PhSetExtendedListView(Context->ListViewHeader);\n\n    ListView_EnableGroupView(Context->ListViewHeader, TRUE);\n    PhAddListViewGroup(Context->ListViewHeader, PH_HANDLE_GENERAL_CATEGORY_SECURITY, L\"Security information\");\n    PhAddListViewGroupItem(Context->ListViewHeader, PH_HANDLE_GENERAL_CATEGORY_SECURITY, 0, L\"Owner\", NULL);\n    PhAddListViewGroupItem(Context->ListViewHeader, PH_HANDLE_GENERAL_CATEGORY_SECURITY, 1, L\"Group\", NULL);\n    PhAddListViewGroupItem(Context->ListViewHeader, PH_HANDLE_GENERAL_CATEGORY_SECURITY, 2, L\"Integrity\", NULL);\n    PhSetListViewSubItem(Context->ListViewHeader, 0, 1, L\"N/A\");\n    PhSetListViewSubItem(Context->ListViewHeader, 1, 1, L\"N/A\");\n    PhSetListViewSubItem(Context->ListViewHeader, 2, 1, L\"N/A\");\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_DUP_HANDLE,\n        Context->HandleProperties->ProcessId\n        )))\n    {\n        if (!NT_SUCCESS(status = NtDuplicateObject(\n            processHandle,\n            Context->HandleProperties->HandleItem->Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            READ_CONTROL | ACCESS_SYSTEM_SECURITY,\n            0,\n            0\n            )))\n        {\n            status = NtDuplicateObject(\n                processHandle,\n                Context->HandleProperties->HandleItem->Handle,\n                NtCurrentProcess(),\n                &dupHandle,\n                READ_CONTROL,\n                0,\n                0\n                );\n        }\n        NtClose(processHandle);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        PhUpdateHandlePermissionsDaclSecurity(Context, dupHandle);\n        PhUpdateHandlePermissionsOwnerSecurity(Context, dupHandle);\n        PhUpdateHandlePermissionsGroupSecurity(Context, dupHandle);\n        PhUpdateHandlePermissionsLabelSecurity(Context, dupHandle);\n        NtClose(dupHandle);\n    }\n    else\n    {\n        PPH_STRING string;\n\n        if (string = PhGetWin32Message(PhNtStatusToDosError(status)))\n        {\n            PhMoveReference(&string, PhFormatString(L\"0x%x: %s\",\n                status,\n                PhGetStringOrDefault(string, L\"N/A\")\n                ));\n        }\n        else\n        {\n            string = PhGetNtMessage(status);\n            PhMoveReference(&string, PhFormatString(L\"0x%x: %s\",\n                status,\n                PhGetStringOrDefault(string, L\"N/A\")\n                ));\n        }\n\n        PhSetListViewSubItem(Context->ListViewHeader, 0, 1, PhGetString(string));\n        PhSetListViewSubItem(Context->ListViewHeader, 1, 1, PhGetString(string));\n        PhSetListViewSubItem(Context->ListViewHeader, 2, 1, PhGetString(string));\n        PhClearReference(&string);\n    }\n}\n\nVOID PhUpdateHandleAuditingSecurity(\n    _In_ PHANDLE_PERMISSIONS_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    HANDLE dupHandle = NULL;\n\n    PhSetListViewStyle(Context->ListViewHeader, FALSE, TRUE);\n    PhSetControlTheme(Context->ListViewHeader, L\"explorer\");\n    PhAddListViewColumn(Context->ListViewHeader, 0, 0, 0, LVCFMT_LEFT, 120, L\"Name\");\n    PhAddListViewColumn(Context->ListViewHeader, 1, 1, 1, LVCFMT_LEFT, 250, L\"Value\");\n    PhSetExtendedListView(Context->ListViewHeader);\n\n    ListView_EnableGroupView(Context->ListViewHeader, TRUE);\n    PhAddListViewGroup(Context->ListViewHeader, PH_HANDLE_GENERAL_CATEGORY_SECURITY, L\"Auditing information\");\n    PhAddListViewGroupItem(Context->ListViewHeader, PH_HANDLE_GENERAL_CATEGORY_SECURITY, 0, L\"Owner\", NULL);\n    PhAddListViewGroupItem(Context->ListViewHeader, PH_HANDLE_GENERAL_CATEGORY_SECURITY, 1, L\"Group\", NULL);\n    PhAddListViewGroupItem(Context->ListViewHeader, PH_HANDLE_GENERAL_CATEGORY_SECURITY, 2, L\"Integrity\", NULL);\n    PhSetListViewSubItem(Context->ListViewHeader, 0, 1, L\"N/A\");\n    PhSetListViewSubItem(Context->ListViewHeader, 1, 1, L\"N/A\");\n    PhSetListViewSubItem(Context->ListViewHeader, 2, 1, L\"N/A\");\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_DUP_HANDLE,\n        Context->HandleProperties->ProcessId\n        )))\n    {\n        if (!NT_SUCCESS(status = NtDuplicateObject(\n            processHandle,\n            Context->HandleProperties->HandleItem->Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            READ_CONTROL | ACCESS_SYSTEM_SECURITY,\n            0,\n            0\n            )))\n        {\n            status = NtDuplicateObject(\n                processHandle,\n                Context->HandleProperties->HandleItem->Handle,\n                NtCurrentProcess(),\n                &dupHandle,\n                READ_CONTROL,\n                0,\n                0\n                );\n        }\n        NtClose(processHandle);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        PhUpdateHandlePermissionsOwnerSecurity(Context, dupHandle);\n        PhUpdateHandlePermissionsGroupSecurity(Context, dupHandle);\n        PhUpdateHandlePermissionsLabelSecurity(Context, dupHandle);\n        NtClose(dupHandle);\n    }\n    else\n    {\n        PPH_STRING string;\n\n        if (string = PhGetWin32Message(PhNtStatusToDosError(status)))\n        {\n            PhMoveReference(&string, PhFormatString(L\"0x%x: %s\",\n                status,\n                PhGetStringOrDefault(string, L\"N/A\")\n                ));\n        }\n        else\n        {\n            string = PhGetNtMessage(status);\n            PhMoveReference(&string, PhFormatString(L\"0x%x: %s\",\n                status,\n                PhGetStringOrDefault(string, L\"N/A\")\n                ));\n        }\n\n        PhSetListViewSubItem(Context->ListViewHeader, 0, 1, PhGetString(string));\n        PhSetListViewSubItem(Context->ListViewHeader, 1, 1, PhGetString(string));\n        PhSetListViewSubItem(Context->ListViewHeader, 2, 1, PhGetString(string));\n        PhClearReference(&string);\n    }\n}\n\nINT_PTR CALLBACK PhpHandlePermissionsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PHANDLE_PERMISSIONS_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;\n        context = PhAllocateZero(sizeof(HANDLE_PERMISSIONS_CONTEXT));\n        context->HandleProperties = (PHANDLE_PROPERTIES_CONTEXT)propSheetPage->lParam;\n        PhSetDialogContext(hwndDlg, context);\n    }\n    else\n    {\n        context = PhGetDialogContext(hwndDlg);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(context->ParentWindow);\n\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            context->ListViewHeader = GetDlgItem(hwndDlg, IDC_SETTINGS);\n            context->ParentWindow = GetParent(hwndDlg);\n            //context->ListViewClass = PhGetListViewInterface(context->ListViewHandle);\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 140, L\"Principal\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 50, L\"Type\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 80, L\"Access\");\n            //PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 80, L\"Inherited from\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHeader, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ADD), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REMOVE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SHOW), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ADVANCED), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n\n            ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);\n            ShowWindow(GetDlgItem(hwndDlg, IDC_REMOVE), SW_HIDE);\n            ShowWindow(GetDlgItem(hwndDlg, IDC_SHOW), SW_HIDE);\n            EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED), FALSE);\n\n            PhUpdateHandlePermissionSecurity(context);\n\n            //if (PhPluginsEnabled)\n            //{\n            //    PPH_PLUGIN_HANDLE_PROPERTIES_WINDOW_CONTEXT Context;\n            //    Context = (PPH_PLUGIN_HANDLE_PROPERTIES_WINDOW_CONTEXT)context;\n            //\n            //    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandlePropertiesWindowInitialized), Context);\n            //}\n\n            if (PhEnableThemeSupport) // TODO: Required for compat (dmex)\n                PhInitializeWindowTheme(context->ParentWindow, PhEnableThemeSupport);\n            else\n                PhInitializeWindowTheme(hwndDlg, FALSE);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            //PhUnregisterWindowCallback(context->ParentWindow);\n\n            //PhSaveWindowPlacementToSetting(SETTING_HANDLE_PROPERTIES_WINDOW_POSITION, NULL, context->ParentWindow);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            //PhDestroyListViewInterface(context->ListViewClass);\n\n            PhRemoveDialogContext(hwndDlg);\n\n            PhFree(context);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n            ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)context->ListViewHandle);\n                return TRUE;\n            }\n\n            REFLECT_MESSAGE_DLG(hwndDlg, context->ListViewHandle, uMsg, wParam, lParam);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID *listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(context->ListViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n        HANDLE_MSG(hwndDlg, WM_CTLCOLORBTN, PhWindowThemeControlColor);\n        HANDLE_MSG(hwndDlg, WM_CTLCOLORDLG, PhWindowThemeControlColor);\n        HANDLE_MSG(hwndDlg, WM_CTLCOLORSTATIC, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nINT_PTR CALLBACK PhpHandleAuditingDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PHANDLE_PERMISSIONS_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;\n        context = PhAllocateZero(sizeof(HANDLE_PERMISSIONS_CONTEXT));\n        context->HandleProperties = (PHANDLE_PROPERTIES_CONTEXT)propSheetPage->lParam;\n        PhSetDialogContext(hwndDlg, context);\n    }\n    else\n    {\n        context = PhGetDialogContext(hwndDlg);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(context->ParentWindow);\n\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            context->ListViewHeader = GetDlgItem(hwndDlg, IDC_SETTINGS);\n            context->ParentWindow = GetParent(hwndDlg);\n            //context->ListViewClass = PhGetListViewInterface(context->ListViewHandle);\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 140, L\"Principal\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 50, L\"Type\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 80, L\"Access\");\n            //PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 80, L\"Inherited from\");\n            //PhAddListViewColumn(context->ListViewHandle, 4, 4, 4, LVCFMT_LEFT, 80, L\"Source\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHeader, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ADD), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REMOVE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SHOW), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ADVANCED), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n\n            ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);\n            ShowWindow(GetDlgItem(hwndDlg, IDC_REMOVE), SW_HIDE);\n            ShowWindow(GetDlgItem(hwndDlg, IDC_SHOW), SW_HIDE);\n            EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED), FALSE);\n\n            PhUpdateHandleAuditingSecurity(context);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            //PhSaveWindowPlacementToSetting(SETTING_HANDLE_PROPERTIES_WINDOW_POSITION, NULL, context->ParentWindow);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            //PhDestroyListViewInterface(context->ListViewClass);\n\n            PhRemoveDialogContext(hwndDlg);\n\n            PhFree(context);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n            ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)context->ListViewHandle);\n                return TRUE;\n            }\n\n            REFLECT_MESSAGE_DLG(hwndDlg, context->ListViewHandle, uMsg, wParam, lParam);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID *listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(context->ListViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n        HANDLE_MSG(hwndDlg, WM_CTLCOLORBTN, PhWindowThemeControlColor);\n        HANDLE_MSG(hwndDlg, WM_CTLCOLORDLG, PhWindowThemeControlColor);\n        HANDLE_MSG(hwndDlg, WM_CTLCOLORSTATIC, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/hndlprv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <hndlprv.h>\n\n#include <hndlinfo.h>\n#include <kphuser.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <workqueue.h>\n\n#include <extmgri.h>\n\ntypedef struct _PHP_CREATE_HANDLE_ITEM_CONTEXT\n{\n    PPH_HANDLE_PROVIDER Provider;\n    PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handle;\n} PHP_CREATE_HANDLE_ITEM_CONTEXT, *PPHP_CREATE_HANDLE_ITEM_CONTEXT;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpHandleProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpHandleItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nPPH_OBJECT_TYPE PhHandleProviderType = NULL;\nPPH_OBJECT_TYPE PhHandleItemType = NULL;\n\nPPH_HANDLE_PROVIDER PhCreateHandleProvider(\n    _In_ HANDLE ProcessId\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_HANDLE_PROVIDER handleProvider;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhHandleProviderType = PhCreateObjectType(L\"HandleProvider\", 0, PhpHandleProviderDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    handleProvider = PhCreateObject(\n        PhEmGetObjectSize(EmHandleProviderType, sizeof(PH_HANDLE_PROVIDER)),\n        PhHandleProviderType\n        );\n    memset(handleProvider, 0, sizeof(PH_HANDLE_PROVIDER));\n\n    handleProvider->HandleHashSetSize = 128;\n    handleProvider->HandleHashSet = PhCreateHashSet(handleProvider->HandleHashSetSize);\n    handleProvider->HandleHashSetCount = 0;\n    PhInitializeQueuedLock(&handleProvider->HandleHashSetLock);\n\n    PhInitializeCallback(&handleProvider->HandleAddedEvent);\n    PhInitializeCallback(&handleProvider->HandleModifiedEvent);\n    PhInitializeCallback(&handleProvider->HandleRemovedEvent);\n    PhInitializeCallback(&handleProvider->HandleUpdatedEvent);\n\n    handleProvider->ProcessId = ProcessId;\n    handleProvider->ProcessHandle = NULL;\n\n    handleProvider->RunStatus = PhOpenProcess(\n        &handleProvider->ProcessHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE,\n        ProcessId\n        );\n    if (!NT_SUCCESS(handleProvider->RunStatus))\n    {\n        handleProvider->RunStatus = PhOpenProcess(\n            &handleProvider->ProcessHandle,\n            PROCESS_QUERY_INFORMATION,\n            ProcessId\n            );\n    }\n\n    handleProvider->TempListHashtable = PhCreateSimpleHashtable(512);\n\n    PhEmCallObjectOperation(EmHandleProviderType, handleProvider, EmObjectCreate);\n\n    return handleProvider;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpHandleProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_HANDLE_PROVIDER handleProvider = (PPH_HANDLE_PROVIDER)Object;\n\n    PhEmCallObjectOperation(EmHandleProviderType, handleProvider, EmObjectDelete);\n\n    // Dereference all handle items (we referenced them\n    // when we added them to the hashtable).\n    PhDereferenceAllHandleItems(handleProvider);\n\n    PhFree(handleProvider->HandleHashSet);\n    PhDeleteCallback(&handleProvider->HandleAddedEvent);\n    PhDeleteCallback(&handleProvider->HandleModifiedEvent);\n    PhDeleteCallback(&handleProvider->HandleRemovedEvent);\n\n    if (handleProvider->ProcessHandle) NtClose(handleProvider->ProcessHandle);\n\n    PhDereferenceObject(handleProvider->TempListHashtable);\n}\n\nPPH_HANDLE_ITEM PhCreateHandleItem(\n    _In_opt_ PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handle\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_HANDLE_ITEM handleItem;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhHandleItemType = PhCreateObjectType(L\"HandleItem\", 0, PhpHandleItemDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    handleItem = PhCreateObject(\n        PhEmGetObjectSize(EmHandleItemType, sizeof(PH_HANDLE_ITEM)),\n        PhHandleItemType\n        );\n    memset(handleItem, 0, sizeof(PH_HANDLE_ITEM));\n\n    if (Handle)\n    {\n        handleItem->Object = Handle->Object;\n        handleItem->ProcessId = Handle->UniqueProcessId;\n        handleItem->Handle = Handle->HandleValue;\n        handleItem->Attributes = Handle->HandleAttributes;\n        handleItem->GrantedAccess = Handle->GrantedAccess;\n        handleItem->TypeIndex = Handle->ObjectTypeIndex;\n\n        PhPrintPointer(handleItem->HandleString, (PVOID)handleItem->Handle);\n        PhPrintPointer(handleItem->GrantedAccessString, UlongToPtr(handleItem->GrantedAccess));\n\n        if (handleItem->Object)\n            PhPrintPointer(handleItem->ObjectString, handleItem->Object);\n    }\n\n    PhEmCallObjectOperation(EmHandleItemType, handleItem, EmObjectCreate);\n\n    return handleItem;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpHandleItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_HANDLE_ITEM handleItem = (PPH_HANDLE_ITEM)Object;\n\n    PhEmCallObjectOperation(EmHandleItemType, handleItem, EmObjectDelete);\n\n    if (handleItem->TypeName) PhDereferenceObject(handleItem->TypeName);\n    if (handleItem->ObjectName) PhDereferenceObject(handleItem->ObjectName);\n    if (handleItem->BestObjectName) PhDereferenceObject(handleItem->BestObjectName);\n}\n\nFORCEINLINE BOOLEAN PhCompareHandleItem(\n    _In_ PPH_HANDLE_ITEM Value1,\n    _In_ PPH_HANDLE_ITEM Value2\n    )\n{\n    return Value1->Handle == Value2->Handle;\n}\n\nFORCEINLINE ULONG PhHashHandleItem(\n    _In_ PPH_HANDLE_ITEM Value\n    )\n{\n    return HandleToUlong(Value->Handle) / 4;\n}\n\nPPH_HANDLE_ITEM PhpLookupHandleItem(\n    _In_ PPH_HANDLE_PROVIDER HandleProvider,\n    _In_ HANDLE Handle\n    )\n{\n    PH_HANDLE_ITEM lookupHandleItem;\n    PPH_HASH_ENTRY entry;\n    PPH_HANDLE_ITEM handleItem;\n\n    lookupHandleItem.Handle = Handle;\n    entry = PhFindEntryHashSet(\n        HandleProvider->HandleHashSet,\n        HandleProvider->HandleHashSetSize,\n        PhHashHandleItem(&lookupHandleItem)\n        );\n\n    for (; entry; entry = entry->Next)\n    {\n        handleItem = CONTAINING_RECORD(entry, PH_HANDLE_ITEM, HashEntry);\n\n        if (PhCompareHandleItem(&lookupHandleItem, handleItem))\n            return handleItem;\n    }\n\n    return NULL;\n}\n\nPPH_HANDLE_ITEM PhReferenceHandleItem(\n    _In_ PPH_HANDLE_PROVIDER HandleProvider,\n    _In_ HANDLE Handle\n    )\n{\n    PPH_HANDLE_ITEM handleItem;\n\n    PhAcquireQueuedLockShared(&HandleProvider->HandleHashSetLock);\n\n    handleItem = PhpLookupHandleItem(HandleProvider, Handle);\n\n    if (handleItem)\n        PhReferenceObject(handleItem);\n\n    PhReleaseQueuedLockShared(&HandleProvider->HandleHashSetLock);\n\n    return handleItem;\n}\n\nVOID PhDereferenceAllHandleItems(\n    _In_ PPH_HANDLE_PROVIDER HandleProvider\n    )\n{\n    ULONG i;\n    PPH_HASH_ENTRY entry;\n    PPH_HANDLE_ITEM handleItem;\n\n    PhAcquireQueuedLockExclusive(&HandleProvider->HandleHashSetLock);\n\n    for (i = 0; i < HandleProvider->HandleHashSetSize; i++)\n    {\n        entry = HandleProvider->HandleHashSet[i];\n\n        while (entry)\n        {\n            handleItem = CONTAINING_RECORD(entry, PH_HANDLE_ITEM, HashEntry);\n            entry = entry->Next;\n            PhDereferenceObject(handleItem);\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&HandleProvider->HandleHashSetLock);\n}\n\nVOID PhpAddHandleItem(\n    _In_ PPH_HANDLE_PROVIDER HandleProvider,\n    _In_ _Assume_refs_(1) PPH_HANDLE_ITEM HandleItem\n    )\n{\n    if (HandleProvider->HandleHashSetSize < HandleProvider->HandleHashSetCount + 1)\n    {\n        PhResizeHashSet(\n            &HandleProvider->HandleHashSet,\n            &HandleProvider->HandleHashSetSize,\n            HandleProvider->HandleHashSetSize * 2\n            );\n    }\n\n    PhAddEntryHashSet(\n        HandleProvider->HandleHashSet,\n        HandleProvider->HandleHashSetSize,\n        &HandleItem->HashEntry,\n        PhHashHandleItem(HandleItem)\n        );\n    HandleProvider->HandleHashSetCount++;\n}\n\nVOID PhpRemoveHandleItem(\n    _In_ PPH_HANDLE_PROVIDER HandleProvider,\n    _In_ PPH_HANDLE_ITEM HandleItem\n    )\n{\n    PhRemoveEntryHashSet(HandleProvider->HandleHashSet, HandleProvider->HandleHashSetSize, &HandleItem->HashEntry);\n    HandleProvider->HandleHashSetCount--;\n    PhDereferenceObject(HandleItem);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpCreateHandleItemFunction(\n    _In_ PVOID Parameter\n    )\n{\n    PPHP_CREATE_HANDLE_ITEM_CONTEXT context = Parameter;\n    PPH_HANDLE_ITEM handleItem;\n    OBJECT_BASIC_INFORMATION handleBasicInformation = { 0 };\n\n    handleItem = PhCreateHandleItem(context->Handle);\n\n    PhGetHandleInformationEx(\n        context->Provider->ProcessHandle,\n        handleItem->Handle,\n        context->Handle->ObjectTypeIndex,\n        0,\n        NULL,\n        &handleBasicInformation,\n        &handleItem->TypeName,\n        &handleItem->ObjectName,\n        &handleItem->BestObjectName,\n        NULL\n        );\n\n    if (PhIsNullOrEmptyString(handleItem->TypeName))\n    {\n        PhMoveReference(&handleItem->TypeName, PhGetObjectTypeIndexName(handleItem->TypeIndex));\n    }\n\n    handleItem->HandleCount = handleBasicInformation.HandleCount;\n    handleItem->PointerCount = handleBasicInformation.PointerCount;\n    handleItem->PagedPoolCharge = handleBasicInformation.PagedPoolCharge;\n    handleItem->NonPagedPoolCharge = handleBasicInformation.NonPagedPoolCharge;\n\n    if (handleItem->TypeName)\n    {\n        // Add the handle item to the hashtable.\n        PhAcquireQueuedLockExclusive(&context->Provider->HandleHashSetLock);\n        PhpAddHandleItem(context->Provider, handleItem);\n        PhReleaseQueuedLockExclusive(&context->Provider->HandleHashSetLock);\n\n        // Raise the handle added event.\n        PhInvokeCallback(&context->Provider->HandleAddedEvent, handleItem);\n    }\n    else\n    {\n        PhDereferenceObject(handleItem);\n    }\n\n    PhFree(context);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhHandleProviderUpdate(\n    _In_ PVOID Object\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static ULONG fileObjectTypeIndex = ULONG_MAX;\n    PPH_HANDLE_PROVIDER handleProvider = (PPH_HANDLE_PROVIDER)Object;\n    PSYSTEM_HANDLE_INFORMATION_EX handleInfo;\n    PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handles;\n    ULONG_PTR numberOfHandles;\n    ULONG i;\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_KEY_VALUE_PAIR handlePair;\n    BOOLEAN useWorkQueue = FALSE;\n    PH_WORK_QUEUE workQueue;\n    KPH_LEVEL level;\n\n    handleProvider->RunStatus = PhEnumHandlesGeneric(\n        handleProvider->ProcessId,\n        handleProvider->ProcessHandle,\n        !!PhCsEnableHandleSnapshot,\n        &handleInfo\n        );\n\n    level = KsiLevel();\n    if (level < KphLevelMed)\n    {\n        useWorkQueue = TRUE;\n        PhInitializeWorkQueue(&workQueue, 1, 20, 1000);\n\n        if (PhBeginInitOnce(&initOnce))\n        {\n            fileObjectTypeIndex = PhGetObjectTypeNumberZ(L\"File\");\n            PhEndInitOnce(&initOnce);\n        }\n    }\n\n    if (NT_SUCCESS(handleProvider->RunStatus))\n    {\n        handles = handleInfo->Handles;\n        numberOfHandles = handleInfo->NumberOfHandles;\n\n        for (i = 0; i < numberOfHandles; i++)\n        {\n            PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handles[i];\n\n            PhAddItemSimpleHashtable(\n                handleProvider->TempListHashtable,\n                handle->HandleValue,\n                handle\n                );\n        }\n    }\n\n    // Look for closed handles.\n    {\n        PPH_LIST handlesToRemove = NULL;\n        PPH_HASH_ENTRY entry;\n        PPH_HANDLE_ITEM handleItem;\n        PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX *tempHashtableValue;\n\n        for (i = 0; i < handleProvider->HandleHashSetSize; i++)\n        {\n            for (entry = handleProvider->HandleHashSet[i]; entry; entry = entry->Next)\n            {\n                BOOLEAN found = FALSE;\n\n                handleItem = CONTAINING_RECORD(entry, PH_HANDLE_ITEM, HashEntry);\n\n                // Check if the handle still exists.\n\n                tempHashtableValue = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX *)PhFindItemSimpleHashtable(\n                    handleProvider->TempListHashtable,\n                    handleItem->Handle\n                    );\n\n                if (tempHashtableValue)\n                {\n                    // Also compare the object pointers to make sure a different object wasn't\n                    // re-opened with the same handle value.\n                    if (level >= KphLevelMed && handleProvider->ProcessHandle)\n                    {\n                        found = NT_SUCCESS(KphCompareObjects(\n                            handleProvider->ProcessHandle,\n                            handleItem->Handle,\n                            (*tempHashtableValue)->HandleValue\n                            ));\n                    }\n                    // This isn't 100% accurate as pool addresses may be re-used, but it works well.\n                    else if (handleItem->Object && handleItem->Object == (*tempHashtableValue)->Object)\n                    {\n                        found = TRUE;\n                    }\n                    else\n                    {\n                        if (\n                            handleItem->Handle == (*tempHashtableValue)->HandleValue &&\n                            handleItem->GrantedAccess == (*tempHashtableValue)->GrantedAccess &&\n                            handleItem->TypeIndex == (*tempHashtableValue)->ObjectTypeIndex &&\n                            handleItem->Attributes == (*tempHashtableValue)->HandleAttributes &&\n                            handleItem->ProcessId == (*tempHashtableValue)->UniqueProcessId\n                            )\n                        {\n                            found = TRUE;\n                        }\n                    }\n                }\n\n                if (!found)\n                {\n                    // Raise the handle removed event.\n                    PhInvokeCallback(&handleProvider->HandleRemovedEvent, handleItem);\n\n                    if (!handlesToRemove)\n                        handlesToRemove = PhCreateList(2);\n\n                    PhAddItemList(handlesToRemove, handleItem);\n                }\n            }\n        }\n\n        if (handlesToRemove)\n        {\n            PhAcquireQueuedLockExclusive(&handleProvider->HandleHashSetLock);\n\n            for (i = 0; i < handlesToRemove->Count; i++)\n            {\n                PhpRemoveHandleItem(handleProvider, handlesToRemove->Items[i]);\n            }\n\n            PhReleaseQueuedLockExclusive(&handleProvider->HandleHashSetLock);\n            PhDereferenceObject(handlesToRemove);\n        }\n    }\n\n    // Look for new handles and update existing ones.\n\n    PhBeginEnumHashtable(handleProvider->TempListHashtable, &enumContext);\n\n    while (handlePair = PhNextEnumHashtable(&enumContext))\n    {\n        PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = handlePair->Value;\n        PPH_HANDLE_ITEM handleItem;\n\n        handleItem = PhpLookupHandleItem(handleProvider, handle->HandleValue);\n\n        if (!handleItem)\n        {\n            OBJECT_BASIC_INFORMATION handleBasicInformation = { 0 };\n\n            // When we don't have KPH, query handle information in parallel to take full advantage of the\n            // PhCallWithTimeout functionality.\n            if (useWorkQueue && handle->ObjectTypeIndex == fileObjectTypeIndex)\n            {\n                PPHP_CREATE_HANDLE_ITEM_CONTEXT context;\n\n                context = PhAllocate(sizeof(PHP_CREATE_HANDLE_ITEM_CONTEXT));\n                context->Provider = handleProvider;\n                context->Handle = handle;\n                PhQueueItemWorkQueue(&workQueue, PhpCreateHandleItemFunction, context);\n                continue;\n            }\n\n            handleItem = PhCreateHandleItem(handle);\n\n            PhGetHandleInformationEx(\n                handleProvider->ProcessHandle,\n                handleItem->Handle,\n                handle->ObjectTypeIndex,\n                0,\n                NULL,\n                &handleBasicInformation,\n                &handleItem->TypeName,\n                &handleItem->ObjectName,\n                &handleItem->BestObjectName,\n                NULL\n                );\n\n            handleItem->HandleCount = handleBasicInformation.HandleCount;\n            handleItem->PointerCount = handleBasicInformation.PointerCount;\n            handleItem->PagedPoolCharge = handleBasicInformation.PagedPoolCharge;\n            handleItem->NonPagedPoolCharge = handleBasicInformation.NonPagedPoolCharge;\n\n            if (PhIsNullOrEmptyString(handleItem->TypeName))\n            {\n                PPH_STRING typeName;\n\n                if (typeName = PhGetObjectTypeIndexName(handleItem->TypeIndex))\n                {\n                    PhMoveReference(&handleItem->TypeName, typeName);\n                }\n            }\n\n            if (handle->ObjectTypeIndex == fileObjectTypeIndex)\n            {\n                if (level >= KphLevelMed)\n                {\n                    KPH_FILE_OBJECT_INFORMATION objectInfo;\n\n                    if (NT_SUCCESS(KphQueryInformationObject(\n                        handleProvider->ProcessHandle,\n                        handleItem->Handle,\n                        KphObjectFileObjectInformation,\n                        &objectInfo,\n                        sizeof(KPH_FILE_OBJECT_INFORMATION),\n                        NULL\n                        )))\n                    {\n                        if (objectInfo.SharedRead)\n                            handleItem->FileFlags |= PH_HANDLE_FILE_SHARED_READ;\n                        if (objectInfo.SharedWrite)\n                            handleItem->FileFlags |= PH_HANDLE_FILE_SHARED_WRITE;\n                        if (objectInfo.SharedDelete)\n                            handleItem->FileFlags |= PH_HANDLE_FILE_SHARED_DELETE;\n\n                        // TODO add extra info from file objects here (jxy-s)\n                        // objectInfo.HasActiveTransaction;\n                        // objectInfo.UserWritableReferences;\n                        // objectInfo.IsIgnoringSharing;\n                        // ... more\n                    }\n                }\n            }\n\n            // Add the handle item to the hashtable.\n            PhAcquireQueuedLockExclusive(&handleProvider->HandleHashSetLock);\n            PhpAddHandleItem(handleProvider, handleItem);\n            PhReleaseQueuedLockExclusive(&handleProvider->HandleHashSetLock);\n\n            // Raise the handle added event.\n            PhInvokeCallback(&handleProvider->HandleAddedEvent, handleItem);\n        }\n        else\n        {\n            BOOLEAN modified = FALSE;\n            OBJECT_BASIC_INFORMATION handleBasicInformation = { 0 };\n\n            if (NT_SUCCESS(PhGetHandleInformationEx(\n                handleProvider->ProcessHandle,\n                handleItem->Handle,\n                handle->ObjectTypeIndex,\n                0,\n                NULL,\n                &handleBasicInformation,\n                NULL,\n                NULL,\n                NULL,\n                NULL\n                )))\n            {\n                if (handleItem->HandleCount != handleBasicInformation.HandleCount)\n                {\n                    handleItem->HandleCount = handleBasicInformation.HandleCount;\n                    modified = TRUE;\n                }\n\n                if (handleItem->PointerCount != handleBasicInformation.PointerCount)\n                {\n                    handleItem->PointerCount = handleBasicInformation.PointerCount;\n                    modified = TRUE;\n                }\n\n                if (handleItem->PagedPoolCharge != handleBasicInformation.PagedPoolCharge)\n                {\n                    handleItem->PagedPoolCharge = handleBasicInformation.PagedPoolCharge;\n                    modified = TRUE;\n                }\n\n                if (handleItem->NonPagedPoolCharge != handleBasicInformation.NonPagedPoolCharge)\n                {\n                    handleItem->NonPagedPoolCharge = handleBasicInformation.NonPagedPoolCharge;\n                    modified = TRUE;\n                }\n            }\n\n            if (handleItem->Attributes != handle->HandleAttributes)\n            {\n                handleItem->Attributes = handle->HandleAttributes;\n                modified = TRUE;\n            }\n\n            if (modified)\n            {\n                // Raise the handle modified event.\n                PhInvokeCallback(&handleProvider->HandleModifiedEvent, handleItem);\n            }\n        }\n    }\n\n    if (useWorkQueue)\n    {\n        PhWaitForWorkQueue(&workQueue);\n        PhDeleteWorkQueue(&workQueue);\n    }\n\n    if (NT_SUCCESS(handleProvider->RunStatus))\n    {\n        PhFree(handleInfo);\n    }\n\n    // Re-create the temporary hashtable if it got too big.\n    if (handleProvider->TempListHashtable->AllocatedEntries > 8192)\n    {\n        PhDereferenceObject(handleProvider->TempListHashtable);\n        handleProvider->TempListHashtable = PhCreateSimpleHashtable(512);\n    }\n    else\n    {\n        PhClearHashtable(handleProvider->TempListHashtable);\n    }\n\n    PhInvokeCallback(&handleProvider->HandleUpdatedEvent, NULL);\n}\n"
  },
  {
    "path": "SystemInformer/hndlstat.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2022-2023\n *\n */\n\n#include <phapp.h>\n#include <hndlinfo.h>\n#include <settings.h>\n#include <phsettings.h>\n\ntypedef struct _HANDLE_STATISTICS_ENTRY\n{\n    PPH_STRING Name;\n    ULONG Count;\n} HANDLE_STATISTICS_ENTRY, *PHANDLE_STATISTICS_ENTRY;\n\ntypedef struct _HANDLE_STATISTICS_CONTEXT\n{\n    HANDLE ProcessId;\n    HANDLE ProcessHandle;\n    HWND ListViewHandle;\n    PH_LAYOUT_MANAGER LayoutManager;\n    PSYSTEM_HANDLE_INFORMATION_EX Handles;\n    HANDLE_STATISTICS_ENTRY Entries[MAX_OBJECT_TYPE_NUMBER];\n} HANDLE_STATISTICS_CONTEXT, *PHANDLE_STATISTICS_CONTEXT;\n\nINT_PTR CALLBACK PhpHandleStatisticsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowHandleStatisticsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    PHANDLE_STATISTICS_CONTEXT context;\n    PSYSTEM_HANDLE_INFORMATION_EX handleInfo;\n    HANDLE processHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_DUP_HANDLE,\n        ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to open the process\", status, 0);\n        return;\n    }\n\n    status = PhEnumHandlesGeneric(\n        ProcessId,\n        processHandle,\n        !!PhCsEnableHandleSnapshot,\n        &handleInfo\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        NtClose(processHandle);\n        PhShowStatus(ParentWindowHandle, L\"Unable to enumerate process handles\", status, 0);\n        return;\n    }\n\n    context = PhAllocateZero(sizeof(HANDLE_STATISTICS_CONTEXT));\n    context->ProcessId = ProcessId;\n    context->ProcessHandle = processHandle;\n    context->Handles = handleInfo;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_HANDLESTATS),\n        ParentWindowHandle,\n        PhpHandleStatisticsDlgProc,\n        context\n        );\n}\n\nvoid PhDestroyHandleStatistics(\n    _In_ PHANDLE_STATISTICS_CONTEXT Context)\n{\n    for (ULONG i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++)\n    {\n        if (Context->Entries[i].Name)\n        {\n            PhDereferenceObject(Context->Entries[i].Name);\n        }\n    }\n\n    if (Context->Handles)\n    {\n        PhFree(Context->Handles);\n    }\n\n    if (Context->ProcessHandle)\n    {\n        NtClose(Context->ProcessHandle);\n    }\n}\n\nstatic LONG NTAPI PhpTypeCountCompareFunction(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_opt_ PVOID Context\n    )\n{\n    PHANDLE_STATISTICS_ENTRY entry1 = Item1;\n    PHANDLE_STATISTICS_ENTRY entry2 = Item2;\n\n    return uintcmp(entry1->Count, entry2->Count);\n}\n\nINT_PTR CALLBACK PhpHandleStatisticsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PHANDLE_STATISTICS_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PHANDLE_STATISTICS_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HANDLE processId;\n            ULONG_PTR i;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            processId = context->ProcessId;\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            PhSetListViewStyle(context->ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 140, L\"Type\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 100, L\"Count\");\n\n            PhSetExtendedListView(context->ListViewHandle);\n            ExtendedListView_SetCompareFunction(context->ListViewHandle, 1, PhpTypeCountCompareFunction);\n            PhLoadListViewColumnsFromSetting(SETTING_HANDLE_STATISTICS_LIST_VIEW_COLUMNS, context->ListViewHandle);\n            PhLoadListViewSortColumnsFromSetting(SETTING_HANDLE_STATISTICS_LIST_VIEW_SORT, context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_HANDLE_STATISTICS_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_HANDLE_STATISTICS_WINDOW_POSITION, SETTING_HANDLE_STATISTICS_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            for (i = 0; i < context->Handles->NumberOfHandles; i++)\n            {\n                PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo;\n                PHANDLE_STATISTICS_ENTRY entry;\n\n                handleInfo = &context->Handles->Handles[i];\n\n                if (handleInfo->UniqueProcessId != processId)\n                    continue;\n                if (handleInfo->ObjectTypeIndex >= MAX_OBJECT_TYPE_NUMBER)\n                    continue;\n\n                entry = &context->Entries[handleInfo->ObjectTypeIndex];\n\n                if (PhIsNullOrEmptyString(entry->Name))\n                {\n                    entry->Name = PhGetObjectTypeIndexName(handleInfo->ObjectTypeIndex);\n\n                    if (PhIsNullOrEmptyString(entry->Name))\n                    {\n                        PPH_STRING typeName = NULL;\n\n                        PhGetHandleInformation(\n                            context->ProcessHandle,\n                            handleInfo->HandleValue,\n                            handleInfo->ObjectTypeIndex,\n                            NULL,\n                            &typeName,\n                            NULL,\n                            NULL\n                            );\n\n                        PhMoveReference(&entry->Name, typeName);\n                    }\n                }\n\n                entry->Count++;\n            }\n\n            for (i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++)\n            {\n                PHANDLE_STATISTICS_ENTRY entry;\n                PPH_STRING unknownType;\n                PPH_STRING countString;\n                LONG lvItemIndex;\n\n                entry = &context->Entries[i];\n\n                if (entry->Count == 0)\n                    continue;\n\n                if (PhIsNullOrEmptyString(entry->Name))\n                {\n                    unknownType = PhFormatString(L\"(unknown: %lu)\", (ULONG)i);\n                    lvItemIndex = PhAddListViewItem(\n                        context->ListViewHandle,\n                        MAXINT,\n                        PhGetString(unknownType),\n                        entry\n                        );\n                    PhDereferenceObject(unknownType);\n                }\n                else\n                {\n                    lvItemIndex = PhAddListViewItem(\n                        context->ListViewHandle,\n                        MAXINT,\n                        PhGetString(entry->Name),\n                        entry\n                        );\n                }\n\n                countString = PhFormatUInt64(entry->Count, TRUE);\n                PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 1, PhGetString(countString));\n                PhDereferenceObject(countString);\n            }\n\n            ExtendedListView_SortItems(context->ListViewHandle);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDestroyHandleStatistics(context);\n\n            PhSaveListViewSortColumnsToSetting(SETTING_HANDLE_STATISTICS_LIST_VIEW_SORT, context->ListViewHandle);\n            PhSaveListViewColumnsToSetting(SETTING_HANDLE_STATISTICS_LIST_VIEW_COLUMNS, context->ListViewHandle);\n            PhSaveWindowPlacementToSetting(SETTING_HANDLE_STATISTICS_WINDOW_POSITION, SETTING_HANDLE_STATISTICS_WINDOW_SIZE, hwndDlg);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                EndDialog(hwndDlg, IDOK);\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/include/actions.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2018-2023\n *\n */\n\n#ifndef PH_ACTIONS_H\n#define PH_ACTIONS_H\n\nEXTERN_C_START\n\ntypedef enum _PH_ACTION_ELEVATION_LEVEL\n{\n    NeverElevateAction = 0,\n    PromptElevateAction = 1,\n    AlwaysElevateAction = 2\n} PH_ACTION_ELEVATION_LEVEL;\n\n// begin_phapppub\ntypedef enum _PH_PHSVC_MODE\n{\n    ElevatedPhSvcMode,\n    Wow64PhSvcMode\n} PH_PHSVC_MODE;\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiConnectToPhSvc(\n    _In_opt_ HWND WindowHandle,\n    _In_ BOOLEAN ConnectOnly\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiConnectToPhSvcEx(\n    _In_opt_ HWND WindowHandle,\n    _In_ PH_PHSVC_MODE Mode,\n    _In_ BOOLEAN ConnectOnly\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhUiDisconnectFromPhSvc(\n    VOID\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiLockComputer(\n    _In_ HWND WindowHandle\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiLogoffComputer(\n    _In_ HWND WindowHandle\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSleepComputer(\n    _In_ HWND WindowHandle\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiHibernateComputer(\n    _In_ HWND WindowHandle\n    );\n\ntypedef enum _PH_POWERACTION_TYPE\n{\n    PH_POWERACTION_TYPE_NONE,\n    PH_POWERACTION_TYPE_WIN32,\n    PH_POWERACTION_TYPE_NATIVE,\n    PH_POWERACTION_TYPE_CRITICAL,\n    PH_POWERACTION_TYPE_ADVANCEDBOOT,\n    PH_POWERACTION_TYPE_FIRMWAREBOOT,\n    PH_POWERACTION_TYPE_UPDATE,\n    PH_POWERACTION_TYPE_WDOSCAN,\n    PH_POWERACTION_TYPE_MAXIMUM\n} PH_POWERACTION_TYPE;\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiRestartComputer(\n    _In_ HWND WindowHandle,\n    _In_ PH_POWERACTION_TYPE Action,\n    _In_ ULONG Flags\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiShutdownComputer(\n    _In_ HWND WindowHandle,\n    _In_ PH_POWERACTION_TYPE Action,\n    _In_ ULONG Flags\n    );\n\nPVOID PhUiCreateComputerBootDeviceMenu(\n    _In_ BOOLEAN DelayLoadMenu\n    );\n\nPVOID PhUiCreateComputerFirmwareDeviceMenu(\n    _In_ BOOLEAN DelayLoadMenu\n    );\n\nVOID PhUiHandleComputerBootApplicationMenu(\n    _In_ HWND WindowHandle,\n    _In_ ULONG MenuIndex\n    );\n\nVOID PhUiHandleComputerFirmwareApplicationMenu(\n    _In_ HWND WindowHandle,\n    _In_ ULONG MenuIndex\n    );\n\nVOID PhUiCreateSessionMenu(\n    _In_ PVOID UsersMenuItem\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiConnectSession(\n    _In_ HWND WindowHandle,\n    _In_ ULONG SessionId\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiDisconnectSession(\n    _In_ HWND WindowHandle,\n    _In_ ULONG SessionId\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiLogoffSession(\n    _In_ HWND WindowHandle,\n    _In_ ULONG SessionId\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiTerminateProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiTerminateTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSuspendProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSuspendTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiResumeProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiResumeTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiFreezeTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiThawTreeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiRestartProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiDebugProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiReduceWorkingSetProcesses(\n    _In_ HWND WindowHandle,\n    _In_ CONST PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetEmptyWorkingSetProcesses(\n    _In_ HWND WindowHandle,\n    _In_ CONST PPH_PROCESS_ITEM* Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetActivityModeration(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetVirtualizationProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ BOOLEAN Enable\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetCriticalProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetEcoModeProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiDetachFromDebuggerProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetExecutionRequiredProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiLoadDllProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetIoPriorityProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses,\n    _In_ IO_PRIORITY_HINT IoPriority\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetPagePriorityProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ ULONG PagePriority\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetPriorityClassProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses,\n    _In_ ULONG PriorityClass\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetBoostPriorityProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM* Processes,\n    _In_ ULONG NumberOfProcesses,\n    _In_ BOOLEAN PriorityBoost\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetBoostPriorityProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM Process,\n    _In_ BOOLEAN PriorityBoost\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiStartServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiStartService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiContinueServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiContinueService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiPauseServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiPauseService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiStopServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiStopService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiDeleteService(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM Service\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiRestartServices(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiCloseConnections(\n    _In_ HWND WindowHandle,\n    _In_ PPH_NETWORK_ITEM *Connections,\n    _In_ ULONG NumberOfConnections\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiTerminateThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSuspendThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiResumeThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetBoostPriorityThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM* Threads,\n    _In_ ULONG NumberOfThreads,\n    _In_ BOOLEAN PriorityBoost\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetBoostPriorityThread(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ BOOLEAN PriorityBoost\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetPriorityThreads(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM* Threads,\n    _In_ ULONG NumberOfThreads,\n    _In_ LONG Increment\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetPriorityThread(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ LONG Increment\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetIoPriorityThread(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ IO_PRIORITY_HINT IoPriority\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetPagePriorityThread(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_ITEM Thread,\n    _In_ ULONG PagePriority\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiUnloadModule(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_MODULE_ITEM Module\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiFreeMemory(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_MEMORY_ITEM MemoryItem,\n    _In_ BOOLEAN Free\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiEmptyProcessMemoryWorkingSet(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_MEMORY_ITEM MemoryItem\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiCloseHandles(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_HANDLE_ITEM *Handles,\n    _In_ ULONG NumberOfHandles,\n    _In_ BOOLEAN Warn\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiSetAttributesHandle(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_HANDLE_ITEM Handle,\n    _In_ ULONG Attributes\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhUiFlushHeapProcesses(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM* Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n// end_phapppub\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/appsup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016-2017\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_APPSUP_H\n#define PH_APPSUP_H\n\nDEFINE_GUID(XP_CONTEXT_GUID, 0xbeb1b341, 0x6837, 0x4c83, 0x83, 0x66, 0x2b, 0x45, 0x1e, 0x7c, 0xe6, 0x9b);\nDEFINE_GUID(VISTA_CONTEXT_GUID, 0xe2011457, 0x1546, 0x43c5, 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0);\nDEFINE_GUID(WIN7_CONTEXT_GUID, 0x35138b9a, 0x5d96, 0x4fbd, 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a);\nDEFINE_GUID(WIN8_CONTEXT_GUID, 0x4a2f28e3, 0x53b9, 0x4441, 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38);\nDEFINE_GUID(WINBLUE_CONTEXT_GUID, 0x1f676c76, 0x80e1, 0x4239, 0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78);\nDEFINE_GUID(WIN10_CONTEXT_GUID, 0x8e0f7a12, 0xbfb3, 0x4fe8, 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a);\n\n// begin_phapppub\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhGetProcessIsSuspended(\n    _In_ PSYSTEM_PROCESS_INFORMATION Process\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhIsProcessSuspended(\n    _In_ HANDLE ProcessId\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhIsProcessBackground(\n    _In_ ULONG PriorityClass\n    );\n\nPHAPPAPI\nPCPH_STRINGREF\nNTAPI\nPhGetProcessPriorityClassString(\n    _In_ ULONG PriorityClass\n    );\n// end_phapppub\n\nPPH_STRING PhGetProcessProtectionString(\n    _In_ PS_PROTECTION Protection,\n    _In_ BOOLEAN IsSecureProcess\n    );\n\nNTSTATUS PhGetProcessSwitchContext(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PGUID Guid\n    );\n\nNTSTATUS PhGetProcessDefaultHeap(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID* Heap\n    );\n\n// begin_phapppub\ntypedef enum _PH_KNOWN_PROCESS_TYPE\n{\n    UnknownProcessType,\n    SystemProcessType, // ntoskrnl/ntkrnlpa/...\n    SessionManagerProcessType, // smss\n    WindowsSubsystemProcessType, // csrss\n    WindowsStartupProcessType, // wininit\n    ServiceControlManagerProcessType, // services\n    LocalSecurityAuthorityProcessType, // lsass\n    LocalSessionManagerProcessType, // lsm\n    WindowsLogonProcessType, // winlogon\n    ServiceHostProcessType, // svchost\n    RunDllAsAppProcessType, // rundll32\n    ComSurrogateProcessType, // dllhost\n    TaskHostProcessType, // taskeng, taskhost, taskhostex\n    ExplorerProcessType, // explorer\n    UmdfHostProcessType, // wudfhost\n    NtVdmHostProcessType, // ntvdm\n    //EdgeProcessType, // Microsoft Edge\n    WmiProviderHostType,\n    MaximumProcessType,\n    KnownProcessTypeMask = 0xffff,\n\n    KnownProcessWow64 = 0x20000\n} PH_KNOWN_PROCESS_TYPE;\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhGetProcessKnownType(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PH_KNOWN_PROCESS_TYPE *KnownProcessType\n    );\n\nPHAPPAPI\nPH_KNOWN_PROCESS_TYPE\nNTAPI\nPhGetProcessKnownTypeEx(\n    _In_opt_ HANDLE ProcessId,\n    _In_ PPH_STRING FileName\n    );\n\ntypedef union _PH_KNOWN_PROCESS_COMMAND_LINE\n{\n    struct\n    {\n        PPH_STRING GroupName;\n    } ServiceHost;\n    struct\n    {\n        PPH_STRING FileName;\n        PPH_STRING ProcedureName;\n    } RunDllAsApp;\n    struct\n    {\n        GUID Guid;\n        PPH_STRING Name; // optional\n        PPH_STRING FileName; // optional\n    } ComSurrogate;\n} PH_KNOWN_PROCESS_COMMAND_LINE, *PPH_KNOWN_PROCESS_COMMAND_LINE;\n\n_Success_(return)\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhaGetProcessKnownCommandLine(\n    _In_ PPH_STRING CommandLine,\n    _In_ PH_KNOWN_PROCESS_TYPE KnownProcessType,\n    _Out_ PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine\n    );\n// end_phapppub\n\nPPH_STRING PhEscapeStringForDelimiter(\n    _In_ PPH_STRING String,\n    _In_ WCHAR Delimiter\n    );\n\nPPH_STRING PhUnescapeStringForDelimiter(\n    _In_ PPH_STRING String,\n    _In_ WCHAR Delimiter\n    );\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhSearchOnlineString(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR String\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhShellExecuteUserString(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Setting,\n    _In_ PCWSTR String,\n    _In_ BOOLEAN UseShellExecute,\n    _In_opt_ PCWSTR ErrorMessage\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhLoadSymbolProviderOptions(\n    _Inout_ PPH_SYMBOL_PROVIDER SymbolProvider\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhCopyListViewInfoTip(\n    _Inout_ LPNMLVGETINFOTIP GetInfoTip,\n    _In_ PPH_STRINGREF Tip\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhCopyListView(\n    _In_ HWND ListViewHandle\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhHandleListViewNotifyForCopy(\n    _In_ LPARAM lParam,\n    _In_ HWND ListViewHandle\n    );\n\n#define PH_LIST_VIEW_CTRL_C_BEHAVIOR 0x1\n#define PH_LIST_VIEW_CTRL_A_BEHAVIOR 0x2\n#define PH_LIST_VIEW_DEFAULT_1_BEHAVIORS (PH_LIST_VIEW_CTRL_C_BEHAVIOR | PH_LIST_VIEW_CTRL_A_BEHAVIOR)\n\nPHAPPAPI\nVOID\nNTAPI\nPhHandleListViewNotifyBehaviors(\n    _In_ LPARAM lParam,\n    _In_ HWND ListViewHandle,\n    _In_ ULONG Behaviors\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhGetListViewContextMenuPoint(\n    _In_ HWND ListViewHandle,\n    _Out_ PPOINT Point\n    );\n\n// end_phapppub\n\nVOID PhSetWindowOpacity(\n    _In_ HWND WindowHandle,\n    _In_ ULONG OpacityPercent\n    );\n\n#define PH_OPACITY_TO_ID(Opacity) (ID_OPACITY_10 + (10 - (Opacity) / 10) - 1)\n#define PH_ID_TO_OPACITY(Id) (100 - (((Id) - ID_OPACITY_10) + 1) * 10)\n\n// begin_phapppub\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhGetPhVersion(\n    VOID\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhGetPhVersionNumbers(\n    _Out_opt_ PULONG MajorVersion,\n    _Out_opt_ PULONG MinorVersion,\n    _Out_opt_ PULONG BuildNumber,\n    _Out_opt_ PULONG RevisionNumber\n    );\n\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhGetPhVersionHash(\n    VOID\n    );\n\ntypedef enum _PH_RELEASE_CHANNEL\n{\n    PhReleaseChannel = 0,\n    PhPreviewChannel = 1, // unused, reserved\n    PhCanaryChannel = 2,\n    PhDeveloperChannel = 3,\n    PhInvalidChannel = ULONG_MAX,\n} PH_RELEASE_CHANNEL, *PPH_RELEASE_CHANNEL;\n\nPHAPPAPI\nPH_RELEASE_CHANNEL\nNTAPI\nPhGetPhReleaseChannel(\n    VOID\n    );\n\nPHAPPAPI\nPCWSTR\nNTAPI\nPhGetPhReleaseChannelString(\n    VOID\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhWritePhTextHeader(\n    _Inout_ PPH_FILE_STREAM FileStream\n    );\n\n#define PH_SHELL_APP_PROPAGATE_PARAMETERS 0x1\n#define PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY 0x2\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhShellProcessHacker(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR Parameters,\n    _In_ ULONG ShowWindowType,\n    _In_ ULONG Flags,\n    _In_ ULONG AppFlags,\n    _In_opt_ ULONG Timeout,\n    _Out_opt_ PHANDLE ProcessHandle\n    );\n// end_phapppub\n\nNTSTATUS PhShellProcessHackerEx(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ PCWSTR Parameters,\n    _In_ ULONG ShowWindowType,\n    _In_ ULONG Flags,\n    _In_ ULONG AppFlags,\n    _In_opt_ ULONG Timeout,\n    _Out_opt_ PHANDLE ProcessHandle\n    );\n\nBOOLEAN PhCreateProcessIgnoreIfeoDebugger(\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR CommandLine\n    );\n\n// begin_phapppub\ntypedef struct _PH_EMENU_ITEM* PPH_EMENU_ITEM;\n\ntypedef struct _PH_TN_COLUMN_MENU_DATA\n{\n    HWND TreeNewHandle;\n    PPH_TREENEW_HEADER_MOUSE_EVENT MouseEvent;\n    ULONG DefaultSortColumn;\n    PH_SORT_ORDER DefaultSortOrder;\n\n    PPH_EMENU_ITEM Menu;\n    PPH_EMENU_ITEM Selection;\n    ULONG ProcessedId;\n} PH_TN_COLUMN_MENU_DATA, *PPH_TN_COLUMN_MENU_DATA;\n\n#define PH_TN_COLUMN_MENU_HIDE_COLUMN_ID ((ULONG)-1)\n#define PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID ((ULONG)-2)\n#define PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID ((ULONG)-3)\n#define PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID ((ULONG)-4)\n#define PH_TN_COLUMN_MENU_RESET_SORT_ID ((ULONG)-5)\n\nPHAPPAPI\nVOID\nNTAPI\nPhInitializeTreeNewColumnMenu(\n    _Inout_ PPH_TN_COLUMN_MENU_DATA Data\n    );\n\n#define PH_TN_COLUMN_MENU_NO_VISIBILITY 0x1\n#define PH_TN_COLUMN_MENU_SHOW_RESET_SORT 0x2\n\nPHAPPAPI\nVOID\nNTAPI\nPhInitializeTreeNewColumnMenuEx(\n    _Inout_ PPH_TN_COLUMN_MENU_DATA Data,\n    _In_ ULONG Flags\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhHandleTreeNewColumnMenu(\n    _Inout_ PPH_TN_COLUMN_MENU_DATA Data\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhDeleteTreeNewColumnMenu(\n    _In_ PPH_TN_COLUMN_MENU_DATA Data\n    );\n\ntypedef struct _PH_TN_FILTER_SUPPORT\n{\n    PPH_LIST FilterList;\n    HWND TreeNewHandle;\n    PPH_LIST NodeList;\n} PH_TN_FILTER_SUPPORT, *PPH_TN_FILTER_SUPPORT;\n\ntypedef _Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN NTAPI PH_TN_FILTER_FUNCTION(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_TN_FILTER_FUNCTION* PPH_TN_FILTER_FUNCTION;\n\ntypedef struct _PH_TN_FILTER_ENTRY\n{\n    PPH_TN_FILTER_FUNCTION Filter;\n    PVOID Context;\n} PH_TN_FILTER_ENTRY, *PPH_TN_FILTER_ENTRY;\n\nPHAPPAPI\nVOID\nNTAPI\nPhInitializeTreeNewFilterSupport(\n    _Out_ PPH_TN_FILTER_SUPPORT Support,\n    _In_ HWND TreeNewHandle,\n    _In_ PPH_LIST NodeList\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhDeleteTreeNewFilterSupport(\n    _In_ PPH_TN_FILTER_SUPPORT Support\n    );\n\nPHAPPAPI\nPPH_TN_FILTER_ENTRY\nNTAPI\nPhAddTreeNewFilter(\n    _In_ PPH_TN_FILTER_SUPPORT Support,\n    _In_ PPH_TN_FILTER_FUNCTION Filter,\n    _In_opt_ PVOID Context\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhRemoveTreeNewFilter(\n    _In_ PPH_TN_FILTER_SUPPORT Support,\n    _In_ PPH_TN_FILTER_ENTRY Entry\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhApplyTreeNewFiltersToNode(\n    _In_ PPH_TN_FILTER_SUPPORT Support,\n    _In_ PPH_TREENEW_NODE Node\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhApplyTreeNewFilters(\n    _In_ PPH_TN_FILTER_SUPPORT Support\n    );\n\ntypedef struct _PH_COPY_CELL_CONTEXT\n{\n    HWND TreeNewHandle;\n    ULONG Id; // column ID\n    PPH_STRING MenuItemText;\n} PH_COPY_CELL_CONTEXT, *PPH_COPY_CELL_CONTEXT;\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhInsertCopyCellEMenuItem(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG InsertAfterId,\n    _In_ HWND TreeNewHandle,\n    _In_ PPH_TREENEW_COLUMN Column\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhHandleCopyCellEMenuItem(\n    _In_ PPH_EMENU_ITEM SelectedItem\n    );\n\ntypedef struct _PH_COPY_ITEM_CONTEXT\n{\n    HWND ListViewHandle;\n    ULONG Id;\n    ULONG SubId;\n    PPH_STRING MenuItemText;\n} PH_COPY_ITEM_CONTEXT, *PPH_COPY_ITEM_CONTEXT;\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhInsertCopyListViewEMenuItem(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG InsertAfterId,\n    _In_ HWND ListViewHandle\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhHandleCopyListViewEMenuItem(\n    _In_ PPH_EMENU_ITEM SelectedItem\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhShellOpenKey(\n    _In_ HWND WindowHandle,\n    _In_ PPH_STRING KeyName\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhShellOpenKey2(\n    _In_ HWND WindowHandle,\n    _In_ PPH_STRING KeyName\n    );\n// end_phapppub\n\nPPH_STRING PhPcre2GetErrorMessage(\n    _In_ LONG ErrorCode\n    );\n\n// begin_phapppub\nPHAPPAPI\nHBITMAP\nNTAPI\nPhGetShieldBitmap(\n    _In_ LONG WindowDpi,\n    _In_opt_ LONG Width,\n    _In_opt_ LONG Height\n    );\n\nPHAPPAPI\nHICON\nNTAPI\nPhGetApplicationIcon(\n    _In_ BOOLEAN SmallIcon\n    );\n\nPHAPPAPI\nHICON\nNTAPI\nPhGetApplicationIconEx(\n    _In_ BOOLEAN SmallIcon,\n    _In_opt_ LONG WindowDpi\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhSetApplicationWindowIcon(\n    _In_ HWND WindowHandle\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhSetApplicationWindowIconEx(\n    _In_ HWND WindowHandle,\n    _In_opt_ LONG WindowDpi\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhSetWindowIcon(\n    _In_ HWND WindowHandle,\n    _In_opt_ HICON SmallIcon,\n    _In_opt_ HICON LargeIcon,\n    _In_ BOOLEAN CleanupIcon\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhDestroyWindowIcon(\n    _In_ HWND WindowHandle\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhSetStaticWindowIcon(\n    _In_ HWND WindowHandle,\n    _In_opt_ LONG WindowDpi\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhDeleteStaticWindowIcon(\n    _In_ HWND WindowHandle\n    );\n// end_phapppub\n\n#define SI_RUNAS_ADMIN_TASK_NAME ((PH_STRINGREF)PH_STRINGREF_INIT(L\"SystemInformerTaskAdmin\"))\n\nHRESULT PhRunAsAdminTask(\n    _In_ PPH_STRINGREF TaskName\n    );\n\nHRESULT PhDeleteAdminTask(\n    _In_ PPH_STRINGREF TaskName\n    );\n\nHRESULT PhCreateAdminTask(\n    _In_ PPH_STRINGREF TaskName,\n    _In_ PPH_STRINGREF FileName\n    );\n\nNTSTATUS PhRunAsAdminTaskUIAccess(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhWordMatchStringRef(\n    _In_ PPH_STRINGREF SearchText,\n    _In_ PPH_STRINGREF Text\n    );\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhWordMatchStringZ(\n    _In_ PPH_STRING SearchText,\n    _In_ PCWSTR Text\n    )\n{\n    PH_STRINGREF text;\n\n    PhInitializeStringRef(&text, Text);\n\n    return PhWordMatchStringRef(&SearchText->sr, &text);\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhWordMatchStringLongHintZ(\n    _In_ PPH_STRING SearchText,\n    _In_ PCWSTR Text\n    )\n{\n    PH_STRINGREF text;\n\n    PhInitializeStringRefLongHint(&text, Text);\n\n    return PhWordMatchStringRef(&SearchText->sr, &text);\n}\n\nPHAPPAPI\nPVOID\nNTAPI\nPhCreateKsiSettingsBlob( // ksisup.c\n    VOID\n    );\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhQueryKphCounters( // ksisup.c\n    _Out_ PULONG64 Duration,\n    _Out_ PULONG64 DurationDown,\n    _Out_ PULONG64 DurationUp\n    );\n// end_phapppub\n\n#define PH_LOAD_SHARED_ICON_SMALL(BaseAddress, Name, dpiValue) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0, dpiValue) // phapppub\n#define PH_LOAD_SHARED_ICON_LARGE(BaseAddress, Name, dpiValue) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0, dpiValue) // phapppub\n\nFORCEINLINE PVOID PhpGenericPropertyPageHeader(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ ULONG ContextHash\n    )\n{\n    PVOID context;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;\n\n            context = (PVOID)propSheetPage->lParam;\n            PhSetWindowContext(hwndDlg, ContextHash, context);\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            context = PhGetWindowContext(hwndDlg, ContextHash);\n            PhRemoveWindowContext(hwndDlg, ContextHash);\n        }\n        break;\n    default:\n        {\n            context = PhGetWindowContext(hwndDlg, ContextHash);\n        }\n        break;\n    }\n\n    return context;\n}\n\n#define SWP_NO_ACTIVATE_MOVE_SIZE_ZORDER (SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER)\n#define SWP_SHOWWINDOW_ONLY (SWP_NO_ACTIVATE_MOVE_SIZE_ZORDER | SWP_SHOWWINDOW)\n#define SWP_HIDEWINDOW_ONLY (SWP_NO_ACTIVATE_MOVE_SIZE_ZORDER | SWP_HIDEWINDOW)\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/colmgr.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2015\n *     dmex    2023-2024\n *\n */\n\n#ifndef PH_COLMGR_H\n#define PH_COLMGR_H\n\n#define PH_CM_ORDER_LIMIT 160\n\n// begin_phapppub\ntypedef _Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG NTAPI PH_CM_POST_SORT_FUNCTION(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    );\ntypedef PH_CM_POST_SORT_FUNCTION* PPH_CM_POST_SORT_FUNCTION;\n// end_phapppub\n\ntypedef struct _PH_CM_MANAGER\n{\n    HWND Handle;\n    ULONG MinId;\n    ULONG NextId;\n    PPH_CM_POST_SORT_FUNCTION PostSortFunction;\n    LIST_ENTRY ColumnListHead;\n    PPH_LIST NotifyList;\n} PH_CM_MANAGER, *PPH_CM_MANAGER;\n\ntypedef struct _PH_PLUGIN PH_PLUGIN, *PPH_PLUGIN;\n\ntypedef struct _PH_CM_COLUMN\n{\n    LIST_ENTRY ListEntry;\n    ULONG Id;\n    PPH_PLUGIN Plugin;\n    ULONG SubId;\n    PVOID Context;\n    PVOID SortFunction;\n} PH_CM_COLUMN, *PPH_CM_COLUMN;\n\nVOID PhCmInitializeManager(\n    _Out_ PPH_CM_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_ ULONG MinId,\n    _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction\n    );\n\nVOID PhCmDeleteManager(\n    _In_ PPH_CM_MANAGER Manager\n    );\n\nPPH_CM_COLUMN PhCmCreateColumn(\n    _Inout_ PPH_CM_MANAGER Manager,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ PPH_PLUGIN Plugin,\n    _In_ ULONG SubId,\n    _In_opt_ PVOID Context,\n    _In_opt_ PVOID SortFunction\n    );\n\nPPH_CM_COLUMN PhCmFindColumn(\n    _In_ PPH_CM_MANAGER Manager,\n    _In_ PCPH_STRINGREF PluginName,\n    _In_ ULONG SubId\n    );\n\nVOID PhCmSetNotifyPlugin(\n    _In_ PPH_CM_MANAGER Manager,\n    _In_ PPH_PLUGIN Plugin\n    );\n\nBOOLEAN PhCmForwardMessage(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PPH_CM_MANAGER Manager\n    );\n\nBOOLEAN PhCmForwardSort(\n    _In_ PPH_TREENEW_NODE *Nodes,\n    _In_ ULONG NumberOfNodes,\n    _In_ ULONG SortColumn,\n    _In_ PH_SORT_ORDER SortOrder,\n    _In_ PPH_CM_MANAGER Manager\n    );\n\n// begin_phapppub\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhCmLoadSettings(\n    _In_ HWND TreeNewHandle,\n    _In_ PCPH_STRINGREF Settings\n    );\n// end_phapppub\n\n#define PH_CM_COLUMN_WIDTHS_ONLY 0x1\n\nBOOLEAN PhCmLoadSettingsEx(\n    _In_ HWND TreeNewHandle,\n    _In_opt_ PPH_CM_MANAGER Manager,\n    _In_ ULONG Flags,\n    _In_ PCPH_STRINGREF Settings,\n    _In_opt_ PCPH_STRINGREF SortSettings\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhCmSaveSettings(\n    _In_ HWND TreeNewHandle\n    );\n// end_phapppub\n\nPPH_STRING PhCmSaveSettingsEx(\n    _In_ HWND TreeNewHandle,\n    _In_opt_ PPH_CM_MANAGER Manager,\n    _In_ ULONG Flags,\n    _Out_opt_ PPH_STRING *SortSettings\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/colsetmgr.h",
    "content": "#ifndef PH_COLSETMGR_H\n#define PH_COLSETMGR_H\n\ntypedef struct _PH_COLUMN_SET_ENTRY\n{\n    PPH_STRING Name;\n    PPH_STRING Setting;\n    PPH_STRING Sorting;\n} PH_COLUMN_SET_ENTRY, *PPH_COLUMN_SET_ENTRY;\n\nPPH_LIST PhInitializeColumnSetList(\n    _In_ PCWSTR SettingName\n    );\n\nVOID PhDeleteColumnSetList(\n    _In_ PPH_LIST ColumnSetList\n    );\n\n_Success_(return)\nBOOLEAN PhLoadSettingsColumnSet(\n    _In_ PCWSTR SettingName,\n    _In_ PPH_STRING ColumnSetName,\n    _Out_ PPH_STRING *TreeListSettings,\n    _Out_ PPH_STRING *TreeSortSettings\n    );\n\nVOID PhSaveSettingsColumnSet(\n    _In_ PCWSTR SettingName,\n    _In_ PPH_STRING ColumnSetName,\n    _In_ PPH_STRING TreeListSettings,\n    _In_ PPH_STRING TreeSortSettings\n    );\n\n// Column Set Editor Dialog\n\nVOID PhShowColumnSetEditorDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR SettingName\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/devprv.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2023\n *\n */\n\n#ifndef _DEVICEPRV_H_\n#define _DEVICEPRV_H_\n\n#include <SetupAPI.h>\n\n// begin_phapppub\nextern PPH_OBJECT_TYPE PhDeviceTreeType;\nextern PPH_OBJECT_TYPE PhDeviceItemType;\nextern PPH_OBJECT_TYPE PhDeviceNotifyType;\n\ntypedef enum _PH_DEVICE_PROPERTY_CLASS\n{\n    PhDevicePropertyName,\n    PhDevicePropertyManufacturer,\n    PhDevicePropertyService,\n    PhDevicePropertyClass,\n    PhDevicePropertyEnumeratorName,\n    PhDevicePropertyInstallDate,\n\n    PhDevicePropertyFirstInstallDate,\n    PhDevicePropertyLastArrivalDate,\n    PhDevicePropertyLastRemovalDate,\n    PhDevicePropertyDeviceDesc,\n    PhDevicePropertyFriendlyName,\n    PhDevicePropertyInstanceId,\n    PhDevicePropertyParentInstanceId,\n    PhDevicePropertyPDOName,\n    PhDevicePropertyLocationInfo,\n    PhDevicePropertyClassGuid,\n    PhDevicePropertyDriver,\n    PhDevicePropertyDriverVersion,\n    PhDevicePropertyDriverDate,\n    PhDevicePropertyFirmwareDate,\n    PhDevicePropertyFirmwareVersion,\n    PhDevicePropertyFirmwareRevision,\n    PhDevicePropertyHasProblem,\n    PhDevicePropertyProblemCode,\n    PhDevicePropertyProblemStatus,\n    PhDevicePropertyDevNodeStatus,\n    PhDevicePropertyDevCapabilities,\n    PhDevicePropertyUpperFilters,\n    PhDevicePropertyLowerFilters,\n    PhDevicePropertyHardwareIds,\n    PhDevicePropertyCompatibleIds,\n    PhDevicePropertyConfigFlags,\n    PhDevicePropertyUINumber,\n    PhDevicePropertyBusTypeGuid,\n    PhDevicePropertyLegacyBusType,\n    PhDevicePropertyBusNumber,\n    PhDevicePropertySecurity,\n    PhDevicePropertySecuritySDS,\n    PhDevicePropertyDevType,\n    PhDevicePropertyExclusive,\n    PhDevicePropertyCharacteristics,\n    PhDevicePropertyAddress,\n    PhDevicePropertyPowerData,\n    PhDevicePropertyRemovalPolicy,\n    PhDevicePropertyRemovalPolicyDefault,\n    PhDevicePropertyRemovalPolicyOverride,\n    PhDevicePropertyInstallState,\n    PhDevicePropertyLocationPaths,\n    PhDevicePropertyBaseContainerId,\n    PhDevicePropertyEjectionRelations,\n    PhDevicePropertyRemovalRelations,\n    PhDevicePropertyPowerRelations,\n    PhDevicePropertyBusRelations,\n    PhDevicePropertyChildren,\n    PhDevicePropertySiblings,\n    PhDevicePropertyTransportRelations,\n    PhDevicePropertyReported,\n    PhDevicePropertyLegacy,\n    PhDevicePropertyContainerId,\n    PhDevicePropertyInLocalMachineContainer,\n    PhDevicePropertyModel,\n    PhDevicePropertyModelId,\n    PhDevicePropertyFriendlyNameAttributes,\n    PhDevicePropertyManufacturerAttributes,\n    PhDevicePropertyPresenceNotForDevice,\n    PhDevicePropertySignalStrength,\n    PhDevicePropertyIsAssociateableByUserAction,\n    PhDevicePropertyShowInUninstallUI,\n    PhDevicePropertyNumaProximityDomain,\n    PhDevicePropertyDHPRebalancePolicy,\n    PhDevicePropertyNumaNode,\n    PhDevicePropertyBusReportedDeviceDesc,\n    PhDevicePropertyIsPresent,\n    PhDevicePropertyConfigurationId,\n    PhDevicePropertyReportedDeviceIdsHash,\n    PhDevicePropertyPhysicalDeviceLocation,\n    PhDevicePropertyBiosDeviceName,\n    PhDevicePropertyDriverProblemDesc,\n    PhDevicePropertyDebuggerSafe,\n    PhDevicePropertyPostInstallInProgress,\n    PhDevicePropertyStack,\n    PhDevicePropertyExtendedConfigurationIds,\n    PhDevicePropertyIsRebootRequired,\n    PhDevicePropertyDependencyProviders,\n    PhDevicePropertyDependencyDependents,\n    PhDevicePropertySoftRestartSupported,\n    PhDevicePropertyExtendedAddress,\n    PhDevicePropertyAssignedToGuest,\n    PhDevicePropertyCreatorProcessId,\n    PhDevicePropertyFirmwareVendor,\n    PhDevicePropertySessionId,\n    PhDevicePropertyDriverDesc,\n    PhDevicePropertyDriverInfPath,\n    PhDevicePropertyDriverInfSection,\n    PhDevicePropertyDriverInfSectionExt,\n    PhDevicePropertyMatchingDeviceId,\n    PhDevicePropertyDriverProvider,\n    PhDevicePropertyDriverPropPageProvider,\n    PhDevicePropertyDriverCoInstallers,\n    PhDevicePropertyResourcePickerTags,\n    PhDevicePropertyResourcePickerExceptions,\n    PhDevicePropertyDriverRank,\n    PhDevicePropertyDriverLogoLevel,\n    PhDevicePropertyNoConnectSound,\n    PhDevicePropertyGenericDriverInstalled,\n    PhDevicePropertyAdditionalSoftwareRequested,\n    PhDevicePropertySafeRemovalRequired,\n    PhDevicePropertySafeRemovalRequiredOverride,\n\n    PhDevicePropertyPkgModel,\n    PhDevicePropertyPkgVendorWebSite,\n    PhDevicePropertyPkgDetailedDescription,\n    PhDevicePropertyPkgDocumentationLink,\n    PhDevicePropertyPkgIcon,\n    PhDevicePropertyPkgBrandingIcon,\n\n    PhDevicePropertyClassUpperFilters,\n    PhDevicePropertyClassLowerFilters,\n    PhDevicePropertyClassSecurity,\n    PhDevicePropertyClassSecuritySDS,\n    PhDevicePropertyClassDevType,\n    PhDevicePropertyClassExclusive,\n    PhDevicePropertyClassCharacteristics,\n    PhDevicePropertyClassName,\n    PhDevicePropertyClassClassName,\n    PhDevicePropertyClassIcon,\n    PhDevicePropertyClassClassInstaller,\n    PhDevicePropertyClassPropPageProvider,\n    PhDevicePropertyClassNoInstallClass,\n    PhDevicePropertyClassNoDisplayClass,\n    PhDevicePropertyClassSilentInstall,\n    PhDevicePropertyClassNoUseClass,\n    PhDevicePropertyClassDefaultService,\n    PhDevicePropertyClassIconPath,\n    PhDevicePropertyClassDHPRebalanceOptOut,\n    PhDevicePropertyClassClassCoInstallers,\n\n    PhDevicePropertyInterfaceFriendlyName,\n    PhDevicePropertyInterfaceEnabled,\n    PhDevicePropertyInterfaceClassGuid,\n    PhDevicePropertyInterfaceReferenceString,\n    PhDevicePropertyInterfaceRestricted,\n    PhDevicePropertyInterfaceUnrestrictedAppCapabilities,\n    PhDevicePropertyInterfaceSchematicName,\n\n    PhDevicePropertyInterfaceClassDefaultInterface,\n    PhDevicePropertyInterfaceClassName,\n\n    PhDevicePropertyContainerAddress,\n    PhDevicePropertyContainerDiscoveryMethod,\n    PhDevicePropertyContainerIsEncrypted,\n    PhDevicePropertyContainerIsAuthenticated,\n    PhDevicePropertyContainerIsConnected,\n    PhDevicePropertyContainerIsPaired,\n    PhDevicePropertyContainerIcon,\n    PhDevicePropertyContainerVersion,\n    PhDevicePropertyContainerLastSeen,\n    PhDevicePropertyContainerLastConnected,\n    PhDevicePropertyContainerIsShowInDisconnectedState,\n    PhDevicePropertyContainerIsLocalMachine,\n    PhDevicePropertyContainerMetadataPath,\n    PhDevicePropertyContainerIsMetadataSearchInProgress,\n    PhDevicePropertyContainerIsMetadataChecksum,\n    PhDevicePropertyContainerIsNotInterestingForDisplay,\n    PhDevicePropertyContainerLaunchDeviceStageOnDeviceConnect,\n    PhDevicePropertyContainerLaunchDeviceStageFromExplorer,\n    PhDevicePropertyContainerBaselineExperienceId,\n    PhDevicePropertyContainerIsDeviceUniquelyIdentifiable,\n    PhDevicePropertyContainerAssociationArray,\n    PhDevicePropertyContainerDeviceDescription1,\n    PhDevicePropertyContainerDeviceDescription2,\n    PhDevicePropertyContainerHasProblem,\n    PhDevicePropertyContainerIsSharedDevice,\n    PhDevicePropertyContainerIsNetworkDevice,\n    PhDevicePropertyContainerIsDefaultDevice,\n    PhDevicePropertyContainerMetadataCabinet,\n    PhDevicePropertyContainerRequiresPairingElevation,\n    PhDevicePropertyContainerExperienceId,\n    PhDevicePropertyContainerCategory,\n    PhDevicePropertyContainerCategoryDescSingular,\n    PhDevicePropertyContainerCategoryDescPlural,\n    PhDevicePropertyContainerCategoryIcon,\n    PhDevicePropertyContainerCategoryGroupDesc,\n    PhDevicePropertyContainerCategoryGroupIcon,\n    PhDevicePropertyContainerPrimaryCategory,\n    PhDevicePropertyContainerUnpairUninstall,\n    PhDevicePropertyContainerRequiresUninstallElevation,\n    PhDevicePropertyContainerDeviceFunctionSubRank,\n    PhDevicePropertyContainerAlwaysShowDeviceAsConnected,\n    PhDevicePropertyContainerConfigFlags,\n    PhDevicePropertyContainerPrivilegedPackageFamilyNames,\n    PhDevicePropertyContainerCustomPrivilegedPackageFamilyNames,\n    PhDevicePropertyContainerIsRebootRequired,\n    PhDevicePropertyContainerFriendlyName,\n    PhDevicePropertyContainerManufacturer,\n    PhDevicePropertyContainerModelName,\n    PhDevicePropertyContainerModelNumber,\n    PhDevicePropertyContainerInstallInProgress,\n\n    PhDevicePropertyObjectType,\n\n    PhDevicePropertyPciDeviceType,\n    PhDevicePropertyPciCurrentSpeedAndMode,\n    PhDevicePropertyPciBaseClass,\n    PhDevicePropertyPciSubClass,\n    PhDevicePropertyPciProgIf,\n    PhDevicePropertyPciCurrentPayloadSize,\n    PhDevicePropertyPciMaxPayloadSize,\n    PhDevicePropertyPciMaxReadRequestSize,\n    PhDevicePropertyPciCurrentLinkSpeed,\n    PhDevicePropertyPciCurrentLinkWidth,\n    PhDevicePropertyPciMaxLinkSpeed,\n    PhDevicePropertyPciMaxLinkWidth,\n    PhDevicePropertyPciExpressSpecVersion,\n    PhDevicePropertyPciInterruptSupport,\n    PhDevicePropertyPciInterruptMessageMaximum,\n    PhDevicePropertyPciBarTypes,\n    PhDevicePropertyPciSriovSupport,\n    PhDevicePropertyPciLabel_Id,\n    PhDevicePropertyPciLabel_String,\n    PhDevicePropertyPciSerialNumber,\n\n    PhDevicePropertyPciExpressCapabilityControl,\n    PhDevicePropertyPciNativeExpressControl,\n    PhDevicePropertyPciSystemMsiSupport,\n\n    PhDevicePropertyStoragePortable,\n    PhDevicePropertyStorageRemovableMedia,\n    PhDevicePropertyStorageSystemCritical,\n    PhDevicePropertyStorageDiskNumber,\n    PhDevicePropertyStoragePartitionNumber,\n\n    PhDevicePropertyGpuLuid,\n    PhDevicePropertyGpuPhysicalAdapterIndex,\n\n    PhMaxDeviceProperty\n} PH_DEVICE_PROPERTY_CLASS, *PPH_DEVICE_PROPERTY_CLASS;\n\ntypedef enum _PH_DEVICE_PROPERTY_TYPE\n{\n    PhDevicePropertyTypeString,\n    PhDevicePropertyTypeUInt64,\n    PhDevicePropertyTypeInt64,\n    PhDevicePropertyTypeUInt32,\n    PhDevicePropertyTypeInt32,\n    PhDevicePropertyTypeNTSTATUS,\n    PhDevicePropertyTypeGUID,\n    PhDevicePropertyTypeBoolean,\n    PhDevicePropertyTypeTimeStamp,\n    PhDevicePropertyTypeStringList,\n    PhDevicePropertyTypeBinary,\n\n    PhMaxDevicePropertyType\n} PH_DEVICE_PROPERTY_TYPE, PPH_DEVICE_PROPERTY_TYPE;\nC_ASSERT(PhMaxDevicePropertyType <= MAXSHORT);\n\ntypedef struct _PH_DEVICE_PROPERTY\n{\n    union\n    {\n        struct\n        {\n            ULONG Type : 16; // PH_DEVICE_PROPERTY_TYPE\n            ULONG Spare : 14;\n            ULONG Initialized : 1;\n            ULONG Valid : 1;\n        };\n        ULONG State;\n    };\n\n    union\n    {\n        PPH_STRING String;\n        ULONG64 UInt64;\n        LONG64 Int64;\n        ULONG UInt32;\n        LONG Int32;\n        NTSTATUS Status;\n        GUID Guid;\n        BOOLEAN Boolean;\n        LARGE_INTEGER TimeStamp;\n        PPH_LIST StringList;\n        struct\n        {\n            ULONG Size;\n            PBYTE Buffer;\n        } Binary;\n    };\n\n    PPH_STRING AsString;\n} PH_DEVICE_PROPERTY, *PPH_DEVICE_PROPERTY;\n\n// end_phapppub\ntypedef struct _PH_DEVINFO\n{\n    HDEVINFO Handle;\n} PH_DEVINFO, *PPH_DEVINFO;\n\ntypedef struct _PH_DEVINFO_DATA\n{\n    BOOLEAN Interface;\n    union\n    {\n        SP_DEVINFO_DATA DeviceData;\n        SP_DEVICE_INTERFACE_DATA InterfaceData;\n    };\n} PH_DEVINFO_DATA, *PPH_DEVINFO_DATA;\n// begin_phapppub\n\ntypedef struct _PH_DEVICE_ITEM\n{\n    struct _PH_DEVICE_TREE* Tree;\n    struct _PH_DEVICE_ITEM* Parent;\n    struct _PH_DEVICE_ITEM* Sibling;\n    struct _PH_DEVICE_ITEM* Child;\n\n    GUID ClassGuid;\n    ULONG InstanceIdHash;\n    PPH_STRING InstanceId;\n    PPH_STRING ParentInstanceId;\n    ULONG ProblemCode;\n    ULONG DevNodeStatus;\n    ULONG Capabilities;\n    ULONG ChildrenCount;\n    ULONG InterfaceCount;\n\n    union\n    {\n        struct\n        {\n            ULONG HasUpperFilters : 1;\n            ULONG HasLowerFilters : 1;\n            ULONG DeviceInterface : 1;\n            ULONG Spare : 29;\n        };\n        ULONG Flags;\n    };\n\n    PH_DEVICE_PROPERTY Properties[PhMaxDeviceProperty];\n\n// end_phapppub\n    PPH_DEVINFO DeviceInfo;\n    PH_DEVINFO_DATA DeviceInfoData;\n// begin_phapppub\n} PH_DEVICE_ITEM, *PPH_DEVICE_ITEM;\n\ntypedef struct _PH_DEVICE_TREE\n{\n    PPH_DEVICE_ITEM Root;\n    PPH_LIST DeviceList;\n    PPH_LIST DeviceInterfaceList;\n// end_phapppub\n    PPH_DEVINFO DeviceInfo;\n// begin_phapppub\n} PH_DEVICE_TREE, *PPH_DEVICE_TREE;\n\n_Function_class_(PH_DEVICE_ENUM_RESOURCES_CALLBACK)\ntypedef\nBOOLEAN\nNTAPI\nPH_DEVICE_ENUM_RESOURCES_CALLBACK(\n    _In_ ULONG LogicalConfig,\n    _In_ ULONG ResourceId,\n    _In_ PVOID Buffer,\n    _In_ ULONG Length,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_DEVICE_ENUM_RESOURCES_CALLBACK* PPH_DEVICE_ENUM_RESOURCES_CALLBACK;\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhEnumDeviceResources(\n    _In_ PPH_DEVICE_ITEM Item,\n    _In_ ULONG LogicalConfig,\n    _In_ PPH_DEVICE_ENUM_RESOURCES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHAPPAPI\nPPH_DEVICE_PROPERTY\nNTAPI\nPhGetDeviceProperty(\n    _In_ PPH_DEVICE_ITEM Item,\n    _In_ PH_DEVICE_PROPERTY_CLASS Class\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhLookupDevicePropertyClass(\n    _In_ const DEVPROPKEY* Key,\n    _Out_ PPH_DEVICE_PROPERTY_CLASS Class\n    );\n\nPHAPPAPI\nHICON\nNTAPI\nPhGetDeviceIcon(\n    _In_ PPH_DEVICE_ITEM Item,\n    _In_ PPH_INTEGER_PAIR IconSize\n    );\n\nPHAPPAPI\nPPH_DEVICE_TREE\nNTAPI\nPhReferenceDeviceTree(\n    VOID\n    );\n\nPHAPPAPI\nPPH_DEVICE_TREE\nNTAPI\nPhReferenceDeviceTreeEx(\n    _In_ BOOLEAN ForceRefresh\n    );\n\nPHAPPAPI\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM\nNTAPI\nPhLookupDeviceItemByHash(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ ULONG InstanceIdHash\n    );\n\nPHAPPAPI\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM\nNTAPI\nPhLookupDeviceItem(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ PPH_STRINGREF InstanceId\n    );\n\nPHAPPAPI\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM\nNTAPI\nPhReferenceDeviceItemByHash(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ ULONG InstanceIdHash\n    );\n\nPHAPPAPI\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM\nNTAPI\nPhReferenceDeviceItem(\n    _In_ PPH_DEVICE_TREE Tree,\n    _In_ PPH_STRINGREF InstanceId\n    );\n\nPHAPPAPI\n_Success_(return != NULL)\n_Must_inspect_result_\nPPH_DEVICE_ITEM\nNTAPI\nPhReferenceDeviceItem2(\n    _In_ PPH_STRINGREF InstanceId\n    );\n\ntypedef enum _PH_DEVICE_NOTIFY_ACTION\n{\n    PhDeviceNotifyInterfaceArrival,\n    PhDeviceNotifyInterfaceRemoval,\n    PhDeviceNotifyInstanceEnumerated,\n    PhDeviceNotifyInstanceStarted,\n    PhDeviceNotifyInstanceRemoved,\n} PH_DEVICE_NOTIFY_ACTION, *PPH_DEVICE_NOTIFY_ACTION;\n\ntypedef struct _PH_DEVICE_NOTIFY\n{\n    PH_DEVICE_NOTIFY_ACTION Action;\n\n    union\n    {\n        struct\n        {\n            GUID ClassGuid;\n        } DeviceInterface; // PhDeviceNotifyInterface...\n\n        struct\n        {\n            PPH_STRING InstanceId;\n        } DeviceInstance; // PhDeviceNotifyInstance...\n    };\n\n// end_phapppub\n    SLIST_ENTRY ListEntry;\n// begin_phapppub\n} PH_DEVICE_NOTIFY, *PPH_DEVICE_NOTIFY;\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhDeviceProviderInitialization(\n    VOID\n    );\n\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/extmgr.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2022\n *\n */\n\n#ifndef PH_EXTMGR_H\n#define PH_EXTMGR_H\n\n// begin_phapppub\ntypedef enum _PH_EM_OBJECT_TYPE\n{\n    EmProcessItemType,\n    EmProcessNodeType,\n    EmServiceItemType,\n    EmServiceNodeType,\n    EmNetworkItemType,\n    EmNetworkNodeType,\n    EmThreadItemType,\n    EmThreadNodeType,\n    EmModuleItemType,\n    EmModuleNodeType,\n    EmHandleItemType,\n    EmHandleNodeType,\n    EmThreadsContextType,\n    EmModulesContextType,\n    EmHandlesContextType,\n    EmThreadProviderType,\n    EmModuleProviderType,\n    EmHandleProviderType,\n    EmMemoryNodeType,\n    EmMemoryContextType,\n    EmMaximumObjectType\n} PH_EM_OBJECT_TYPE;\n\ntypedef enum _PH_EM_OBJECT_OPERATION\n{\n    EmObjectCreate,\n    EmObjectDelete,\n    EmMaximumObjectOperation\n} PH_EM_OBJECT_OPERATION;\n\ntypedef VOID (NTAPI *PPH_EM_OBJECT_CALLBACK)(\n    _In_ PVOID Object,\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ PVOID Extension\n    );\n// end_phapppub\n\ntypedef struct _PH_EM_APP_CONTEXT\n{\n    LIST_ENTRY ListEntry;\n    PH_STRINGREF AppName;\n    struct _PH_EM_OBJECT_EXTENSION *Extensions[EmMaximumObjectType];\n} PH_EM_APP_CONTEXT, *PPH_EM_APP_CONTEXT;\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/extmgri.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2013\n *     dmex    2017-2022\n *\n */\n\n#ifndef PH_EXTMGRI_H\n#define PH_EXTMGRI_H\n\n#include <extmgr.h>\n\ntypedef struct _PH_EM_OBJECT_TYPE_STATE\n{\n    SIZE_T InitialSize;\n    SIZE_T ExtensionOffset;\n    LIST_ENTRY ExtensionListHead;\n} PH_EM_OBJECT_TYPE_STATE, *PPH_EM_OBJECT_TYPE_STATE;\n\ntypedef struct _PH_EM_OBJECT_EXTENSION\n{\n    LIST_ENTRY ListEntry;\n    SIZE_T ExtensionSize;\n    SIZE_T ExtensionOffset;\n    PPH_EM_OBJECT_CALLBACK Callbacks[EmMaximumObjectOperation];\n} PH_EM_OBJECT_EXTENSION, *PPH_EM_OBJECT_EXTENSION;\n\nVOID PhEmInitialization(\n    VOID\n    );\n\nVOID PhEmInitializeAppContext(\n    _Out_ PPH_EM_APP_CONTEXT AppContext,\n    _In_ PCPH_STRINGREF AppName\n    );\n\nVOID PhEmSetObjectExtension(\n    _Inout_ PPH_EM_APP_CONTEXT AppContext,\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ SIZE_T ExtensionSize,\n    _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback,\n    _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback\n    );\n\nPVOID PhEmGetObject(\n    _In_ PPH_EM_APP_CONTEXT AppContext,\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ PVOID Extension\n    );\n\nPVOID PhEmGetObjectExtension(\n    _In_ PPH_EM_APP_CONTEXT AppContext,\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ PVOID Object\n    );\n\nSIZE_T PhEmGetObjectSize(\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ SIZE_T InitialSize\n    );\n\nVOID PhEmCallObjectOperation(\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ PVOID Object,\n    _In_ PH_EM_OBJECT_OPERATION Operation\n    );\n\n_Success_(return)\nBOOLEAN PhEmParseCompoundId(\n    _In_ PCPH_STRINGREF CompoundId,\n    _Out_ PPH_STRINGREF AppName,\n    _Out_ PULONG SubId\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/heapstruct.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015-2016\n *     dmex    2017-2022\n *\n */\n\n#ifndef PH_HEAPSTRUCT_H\n#define PH_HEAPSTRUCT_H\n\n// Not the actual structure, but has the same size.\ntypedef struct _HEAP_ENTRY\n{\n    PVOID Data1;\n    PVOID Data2;\n} HEAP_ENTRY, *PHEAP_ENTRY;\n\n#define HEAP_SEGMENT_SIGNATURE 0xffeeffee\n\n// Windows 7 and above\ntypedef struct _HEAP_SEGMENT\n{\n    HEAP_ENTRY Entry;\n    ULONG SegmentSignature;\n    ULONG SegmentFlags;\n    LIST_ENTRY SegmentListEntry;\n    struct _HEAP *Heap;\n    PVOID BaseAddress;\n    ULONG NumberOfPages;\n    PHEAP_ENTRY FirstEntry;\n    PHEAP_ENTRY LastValidEntry;\n    ULONG NumberOfUnCommittedPages;\n    ULONG NumberOfUnCommittedRanges;\n    USHORT SegmentAllocatorBackTraceIndex;\n    USHORT Reserved;\n    LIST_ENTRY UCRSegmentList;\n} HEAP_SEGMENT, *PHEAP_SEGMENT;\n\n#define HEAP_SIGNATURE 0xeeffeeff\n\n// Windows 7\ntypedef struct _HEAP_OLD\n{\n    HEAP_SEGMENT Segment;\n    ULONG Flags;\n    ULONG ForceFlags;\n    ULONG CompatibilityFlags;\n    ULONG EncodeFlagMask;\n    HEAP_ENTRY Encoding;\n    ULONG_PTR PointerKey; // Windows 7 only\n    ULONG Interceptor;\n    ULONG VirtualMemoryThreshold;\n    ULONG Signature;\n    // ...\n} HEAP_OLD, *PHEAP_OLD;\n\n// Windows 8 and above\ntypedef struct _HEAP_WIN8\n{\n    HEAP_SEGMENT Segment;\n    ULONG Flags;\n    ULONG ForceFlags;\n    ULONG CompatibilityFlags;\n    ULONG EncodeFlagMask;\n    HEAP_ENTRY Encoding;\n    ULONG Interceptor;\n    ULONG VirtualMemoryThreshold;\n    ULONG Signature;\n    // ...\n} HEAP_WIN8, *PHEAP_WIN8;\n\n//\n// Windows 10 and above\n//\n\ntypedef struct _RTLP_HEAP_COMMIT_LIMIT_DATA\n{\n    SIZE_T CommitLimitBytes;\n    SIZE_T CommitLimitFailureCode;\n} RTLP_HEAP_COMMIT_LIMIT_DATA, *PRTLP_HEAP_COMMIT_LIMIT_DATA;\n\ntypedef struct _HEAP_PSEUDO_TAG_ENTRY\n{\n    SIZE_T CommitLimitBytes;\n    SIZE_T CommitLimitFailureCode;\n} HEAP_PSEUDO_TAG_ENTRY, *PHEAP_PSEUDO_TAG_ENTRY;\n\ntypedef struct _HEAP_TUNING_PARAMETERS\n{\n    ULONG CommittThresholdShift;\n    SIZE_T MaxPreCommittThreshold;\n} HEAP_TUNING_PARAMETERS, *PHEAP_TUNING_PARAMETERS;\n\ntypedef struct _HEAP_COUNTERS\n{\n    SIZE_T TotalMemoryReserved;\n    SIZE_T TotalMemoryCommitted;\n    SIZE_T TotalMemoryLargeUCR;\n    SIZE_T TotalSizeInVirtualBlocks;\n    ULONG TotalSegments;\n    ULONG TotalUCRs;\n    ULONG CommittOps;\n    ULONG DeCommitOps;\n    ULONG LockAcquires;\n    ULONG LockCollisions;\n    ULONG CommitRate;\n    ULONG DecommittRate;\n    ULONG CommitFailures;\n    ULONG InBlockCommitFailures;\n    ULONG PollIntervalCounter;\n    ULONG DecommitsSinceLastCheck;\n    ULONG HeapPollInterval;\n    ULONG AllocAndFreeOps;\n    ULONG AllocationIndicesActive;\n    ULONG InBlockDeccommits;\n    SIZE_T InBlockDeccomitSize;\n    SIZE_T HighWatermarkSize;\n    SIZE_T LastPolledSize;\n} HEAP_COUNTERS, *PHEAP_COUNTERS;\n\ntypedef struct _HEAP\n{\n    HEAP_SEGMENT Segment;\n    HEAP_ENTRY Entry;\n    ULONG SegmentSignature;\n    ULONG SegmentFlags;\n    LIST_ENTRY SegmentListEntry;\n    struct _HEAP* Heap;\n    PVOID BaseAddress;\n    ULONG NumberOfPages;\n    PHEAP_ENTRY FirstEntry;\n    PHEAP_ENTRY LastValidEntry;\n    ULONG NumberOfUnCommittedPages;\n    ULONG NumberOfUnCommittedRanges;\n    USHORT SegmentAllocatorBackTraceIndex;\n    USHORT Reserved;\n    LIST_ENTRY UCRSegmentList;\n    ULONG Flags;\n    ULONG ForceFlags;\n    ULONG CompatibilityFlags;\n    ULONG EncodeFlagMask;\n    HEAP_ENTRY Encoding;\n    ULONG Interceptor;\n    ULONG VirtualMemoryThreshold;\n    ULONG Signature;\n    SIZE_T SegmentReserve;\n    SIZE_T SegmentCommit;\n    SIZE_T DeCommitFreeBlockThreshold;\n    SIZE_T DeCommitTotalFreeThreshold;\n    SIZE_T TotalFreeSize;\n    SIZE_T MaximumAllocationSize;\n    USHORT ProcessHeapsListIndex;\n    USHORT HeaderValidateLength;\n    PVOID HeaderValidateCopy;\n    USHORT NextAvailableTagIndex;\n    USHORT MaximumTagIndex;\n    struct _HEAP_TAG_ENTRY* TagEntries;\n    LIST_ENTRY UCRList;\n    SIZE_T AlignRound;\n    SIZE_T AlignMask;\n    LIST_ENTRY VirtualAllocdBlocks;\n    LIST_ENTRY SegmentList;\n    USHORT AllocatorBackTraceIndex;\n    ULONG NonDedicatedListLength;\n    PVOID BlocksIndex;\n    PVOID UCRIndex;\n    PHEAP_PSEUDO_TAG_ENTRY PseudoTagEntries;\n    LIST_ENTRY FreeLists;\n    struct _HEAP_LOCK* LockVariable;\n    long (*CommitRoutine)(void);\n    RTL_RUN_ONCE StackTraceInitVar;\n    RTLP_HEAP_COMMIT_LIMIT_DATA CommitLimitData;\n    PVOID UserContext;\n    ULONG_PTR Spare;\n    PVOID FrontEndHeap;\n    USHORT FrontHeapLockCount;\n    UCHAR FrontEndHeapType;\n    UCHAR RequestedFrontEndHeapType;\n    PUSHORT FrontEndHeapUsageData;\n    USHORT FrontEndHeapMaximumIndex;\n    UCHAR FrontEndHeapStatusBitmap[129];\n    UCHAR ReadOnly : 1;\n    UCHAR InternalFlags;\n    HEAP_COUNTERS Counters;\n    HEAP_TUNING_PARAMETERS TuningParameters;\n} HEAP;\n\n\n#define SEGMENT_HEAP_SIGNATURE 0xddeeddee\n\n// Windows 8.1 and above\ntypedef struct _SEGMENT_HEAP_WIN8\n{\n    ULONG_PTR Padding[2];\n    ULONG Signature;\n    ULONG GlobalFlags;\n    // ...\n} SEGMENT_HEAP_WIN8, PSEGMENT_HEAP_WIN8;\n\n//\n// Windows 10 and above\n//\n\ntypedef struct _RTL_HP_ENV_HANDLE\n{\n    ULONG_PTR h[2];\n} RTL_HP_ENV_HANDLE, PRTL_HP_ENV_HANDLE;\n\ntypedef struct _HEAP_OPPORTUNISTIC_LARGE_PAGE_STATS\n{\n    SIZE_T SmallPagesInUseWithinLarge;\n    SIZE_T OpportunisticLargePageCount;\n} HEAP_OPPORTUNISTIC_LARGE_PAGE_STATS, PHEAP_OPPORTUNISTIC_LARGE_PAGE_STATS;\n\ntypedef struct _RTL_HP_SEG_ALLOC_POLICY\n{\n    SIZE_T SmallPagesInUseWithinLarge;\n    SIZE_T OpportunisticLargePageCount;\n} RTL_HP_SEG_ALLOC_POLICY, PRTL_HP_SEG_ALLOC_POLICY;\n\ntypedef struct _HEAP_RUNTIME_MEMORY_STATS\n{\n    SIZE_T TotalReservedPages;\n    SIZE_T TotalCommittedPages;\n    SIZE_T FreeCommittedPages;\n    SIZE_T LfhFreeCommittedPages;\n    SIZE_T VsFreeCommittedPages;\n    HEAP_OPPORTUNISTIC_LARGE_PAGE_STATS LargePageStats[2];\n    RTL_HP_SEG_ALLOC_POLICY LargePageUtilizationPolicy;\n} HEAP_RUNTIME_MEMORY_STATS, PHEAP_RUNTIME_MEMORY_STATS;\n\ntypedef struct _SEGMENT_HEAP\n{\n    RTL_HP_ENV_HANDLE EnvHandle;\n    ULONG Signature;\n    ULONG GlobalFlags;\n    ULONG Interceptor;\n    USHORT ProcessHeapListIndex;\n    struct\n    {\n        USHORT AllocatedFromMetadata : 1;\n        USHORT ReadOnly : 1;\n        USHORT InternalFlags : 14;\n    };\n    RTLP_HEAP_COMMIT_LIMIT_DATA CommitLimitData;\n    SIZE_T ReservedMustBeZero;\n    PVOID UserContext;\n    SIZE_T LargeMetadataLock;\n    RTL_RB_TREE LargeAllocMetadata;\n    SIZE_T LargeReservedPages;\n    SIZE_T LargeCommittedPages;\n    SIZE_T Tag;\n    RTL_RUN_ONCE StackTraceInitVar;\n    HEAP_RUNTIME_MEMORY_STATS MemStats;\n    ULONG GlobalLockOwner;\n    SIZE_T ContextExtendLock;\n    PBYTE AllocatedBase;\n    PBYTE UncommittedBase;\n    PBYTE ReservedLimit;\n    PBYTE ReservedRegionEnd;\n    //RTL_HP_HEAP_VA_CALLBACKS_ENCODED CallbacksEncoded;\n    //HEAP_SEG_CONTEXT SegContexts[2];\n    //HEAP_VS_CONTEXT VsContext;\n    //HEAP_LFH_CONTEXT LfhContext;\n} SEGMENT_HEAP, PSEGMENT_HEAP;\n\n//\n// 32-bit versions\n//\n\ntypedef struct _HEAP_ENTRY32\n{\n    WOW64_POINTER(PVOID) Data1;\n    WOW64_POINTER(PVOID) Data2;\n} HEAP_ENTRY32, *PHEAP_ENTRY32;\n\ntypedef struct _HEAP_SEGMENT32\n{\n    HEAP_ENTRY32 HeapEntry;\n    ULONG SegmentSignature;\n    ULONG SegmentFlags;\n    LIST_ENTRY32 SegmentListEntry;\n    WOW64_POINTER(struct _HEAP32 *) Heap;\n    WOW64_POINTER(PVOID) BaseAddress;\n    ULONG NumberOfPages;\n    WOW64_POINTER(PHEAP_ENTRY32) FirstEntry;\n    WOW64_POINTER(PHEAP_ENTRY32) LastValidEntry;\n    ULONG NumberOfUnCommittedPages;\n    ULONG NumberOfUnCommittedRanges;\n    USHORT SegmentAllocatorBackTraceIndex;\n    USHORT Reserved;\n    LIST_ENTRY32 UCRSegmentList;\n} HEAP_SEGMENT32, *PHEAP_SEGMENT32;\n\ntypedef struct _HEAP_OLD32\n{\n    HEAP_SEGMENT32 Segment;\n    ULONG Flags;\n    ULONG ForceFlags;\n    ULONG CompatibilityFlags;\n    ULONG EncodeFlagMask;\n    HEAP_ENTRY32 Encoding;\n    WOW64_POINTER(ULONG_PTR) PointerKey;\n    ULONG Interceptor;\n    ULONG VirtualMemoryThreshold;\n    ULONG Signature;\n    // ...\n} HEAP_OLD32, *PHEAP_OLD32;\n\ntypedef struct _HEAP32\n{\n    HEAP_SEGMENT32 Segment;\n    ULONG Flags;\n    ULONG ForceFlags;\n    ULONG CompatibilityFlags;\n    ULONG EncodeFlagMask;\n    HEAP_ENTRY32 Encoding;\n    ULONG Interceptor;\n    ULONG VirtualMemoryThreshold;\n    ULONG Signature;\n    // ...\n} HEAP32, *PHEAP32;\n\ntypedef struct _SEGMENT_HEAP32\n{\n    WOW64_POINTER(ULONG_PTR) Padding[2];\n    ULONG Signature;\n    ULONG GlobalFlags;\n    // ...\n} SEGMENT_HEAP32, PSEGMENT_HEAP32;\n\ntypedef union _PH_ANY_HEAP\n{\n    HEAP_OLD HeapOld;\n    HEAP_OLD32 HeapOld32;\n    HEAP Heap;\n    HEAP32 Heap32;\n    SEGMENT_HEAP SegmentHeap;\n    SEGMENT_HEAP32 SegmentHeap32;\n} PH_ANY_HEAP;\n\n#define HEAP_SEGMENT_MAX_SIZE \\\n    (max(sizeof(HEAP_SEGMENT), sizeof(HEAP_SEGMENT32)))\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/hidnproc.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2015\n *     dmex    2017-2024\n *\n */\n\n#ifndef PH_HIDNPROC_H\n#define PH_HIDNPROC_H\n\ntypedef enum _PH_ZOMBIE_PROCESS_METHOD\n{\n    BruteForceScanMethod,\n    CsrHandlesScanMethod,\n    ProcessHandleScanMethod,\n    RegistryScanMethod,\n    EtwGuidScanMethod,\n    NtdllScanMethod,\n} PH_ZOMBIE_PROCESS_METHOD;\n\ntypedef enum _PH_ZOMBIE_PROCESS_TYPE\n{\n    UnknownProcess,\n    NormalProcess,\n    ZombieProcess,\n    TerminatedProcess\n} PH_ZOMBIE_PROCESS_TYPE;\n\ntypedef struct _PH_ZOMBIE_PROCESS_ENTRY\n{\n    HANDLE ProcessId;\n    PPH_STRING FileName;\n    PH_ZOMBIE_PROCESS_TYPE Type;\n} PH_ZOMBIE_PROCESS_ENTRY, *PPH_ZOMBIE_PROCESS_ENTRY;\n\ntypedef struct _PH_CSR_HANDLE_INFO\n{\n    HANDLE CsrProcessHandle;\n    HANDLE Handle;\n    BOOLEAN IsThreadHandle;\n\n    HANDLE ProcessId;\n} PH_CSR_HANDLE_INFO, *PPH_CSR_HANDLE_INFO;\n\ntypedef BOOLEAN (NTAPI *PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK)(\n    _In_ PPH_ZOMBIE_PROCESS_ENTRY Process,\n    _In_opt_ PVOID Context\n    );\n\nNTSTATUS\nNTAPI\nPhEnumZombieProcesses(\n    _In_ PH_ZOMBIE_PROCESS_METHOD Method,\n    _In_ PPH_ENUM_ZOMBIE_PROCESSES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef BOOLEAN (NTAPI *PPH_ENUM_CSR_PROCESS_HANDLES_CALLBACK)(\n    _In_ PPH_CSR_HANDLE_INFO Handle,\n    _In_opt_ PVOID Context\n    );\n\nNTSTATUS\nNTAPI\nPhEnumCsrProcessHandles(\n    _In_ PPH_ENUM_CSR_PROCESS_HANDLES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nNTSTATUS\nNTAPI\nPhOpenProcessByCsrHandle(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPH_CSR_HANDLE_INFO Handle\n    );\n\nNTSTATUS\nNTAPI\nPhOpenProcessByCsrHandles(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/hndllist.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2016-2023\n *\n */\n\n#ifndef PH_HNDLLIST_H\n#define PH_HNDLLIST_H\n\n#include <phuisup.h>\n#include <colmgr.h>\n\n// Columns\n\n#define PHHNTLC_TYPE 0\n#define PHHNTLC_NAME 1\n#define PHHNTLC_HANDLE 2\n\n#define PHHNTLC_OBJECTADDRESS 3\n#define PHHNTLC_ATTRIBUTES 4\n#define PHHNTLC_GRANTEDACCESS 5\n#define PHHNTLC_GRANTEDACCESSSYMBOLIC 6\n#define PHHNTLC_ORIGINALNAME 7\n#define PHHNTLC_FILESHAREACCESS 8\n#define PHHNTLC_HANDLEVALUE 9\n#define PHHNTLC_HANDLECOUNT 10\n#define PHHNTLC_POINTERCOUNT 11\n#define PHHNTLC_PAGEDSIZE 12\n#define PHHNTLC_NONPAGEDSIZE 13\n\n#define PHHNTLC_MAXIMUM 14\n\n// begin_phapppub\ntypedef enum _PH_HANDLE_TREE_MENUITEM\n{\n    PH_HANDLE_TREE_MENUITEM_NONE,\n\n    PH_HANDLE_TREE_MENUITEM_HIDE_PROTECTED_HANDLES,\n    PH_HANDLE_TREE_MENUITEM_HIDE_INHERIT_HANDLES,\n    PH_HANDLE_TREE_MENUITEM_HIDE_UNNAMED_HANDLES,\n    PH_HANDLE_TREE_MENUITEM_HIDE_ETW_HANDLES,\n\n    PH_HANDLE_TREE_MENUITEM_HIGHLIGHT_PROTECTED_HANDLES,\n    PH_HANDLE_TREE_MENUITEM_HIGHLIGHT_INHERIT_HANDLES,\n\n    PH_HANDLE_TREE_MENUITEM_HANDLESTATS,\n    PH_HANDLE_TREE_MENUITEM_MAXIMUM\n} PH_HANDLE_TREE_MENUITEM;\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_HANDLE_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PH_SH_STATE ShState;\n\n    HANDLE Handle;\n    PPH_HANDLE_ITEM HandleItem;\n// end_phapppub\n\n    PH_STRINGREF TextCache[PHHNTLC_MAXIMUM];\n\n    PPH_STRING GrantedAccessSymbolicText;\n    WCHAR FileShareAccessText[4];\n    PPH_STRING HandleValue;\n    PPH_STRING HandleCountText;\n    PPH_STRING PointerCountText;\n    PPH_STRING PageSizeText;\n    PPH_STRING NonPageSizeText;\n// begin_phapppub\n} PH_HANDLE_NODE, *PPH_HANDLE_NODE;\n// end_phapppub\n\ntypedef struct _PH_HANDLE_LIST_CONTEXT\n{\n    HWND ParentWindowHandle;\n    HWND TreeNewHandle;\n    ULONG TreeNewSortColumn;\n\n    PH_TN_FILTER_SUPPORT TreeFilterSupport;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PH_CM_MANAGER Cm;\n\n    BOOLEAN EnableStateHighlighting;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Reserved : 1;\n            ULONG HideUnnamedHandles : 1;\n            ULONG HideEtwHandles : 1;\n            ULONG HideProtectedHandles : 1;\n            ULONG HideInheritHandles : 1;\n            ULONG Spare : 27;\n        };\n    };\n\n    PPH_HASHTABLE NodeHashtable;\n    PPH_LIST NodeList;\n    PPH_POINTER_LIST NodeStateList;\n} PH_HANDLE_LIST_CONTEXT, *PPH_HANDLE_LIST_CONTEXT;\n\nVOID PhInitializeHandleList(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND TreeNewHandle,\n    _Out_ PPH_HANDLE_LIST_CONTEXT Context\n    );\n\nVOID PhDeleteHandleList(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context\n    );\n\nVOID PhLoadSettingsHandleList(\n    _Inout_ PPH_HANDLE_LIST_CONTEXT Context\n    );\n\nVOID PhSaveSettingsHandleList(\n    _Inout_ PPH_HANDLE_LIST_CONTEXT Context\n    );\n\nVOID PhSetOptionsHandleList(\n    _Inout_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ ULONG Options\n    );\n\nPPH_HANDLE_NODE PhAddHandleNode(\n    _Inout_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ PPH_HANDLE_ITEM HandleItem,\n    _In_ ULONG RunId\n    );\n\nPPH_HANDLE_NODE PhFindHandleNode(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ HANDLE Handle\n    );\n\nVOID PhRemoveHandleNode(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ PPH_HANDLE_NODE HandleNode\n    );\n\nVOID PhUpdateHandleNode(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ PPH_HANDLE_NODE HandleNode\n    );\n\nVOID PhExpandAllHandleNodes(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _In_ BOOLEAN Expand\n    );\n\nVOID PhTickHandleNodes(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context\n    );\n\nPPH_HANDLE_ITEM PhGetSelectedHandleItem(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context\n    );\n\nVOID PhGetSelectedHandleItems(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context,\n    _Out_ PPH_HANDLE_ITEM **Handles,\n    _Out_ PULONG NumberOfHandles\n    );\n\nVOID PhDeselectAllHandleNodes(\n    _In_ PPH_HANDLE_LIST_CONTEXT Context\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/hndlmenu.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *\n */\n\n#ifndef PH_HNDLMENU_H\n#define PH_HNDLMENU_H\n\n#define PhaAppendCtrlEnter(Text, Enable) ((Enable) ? PhaConcatStrings2((Text), L\"\\tCtrl+Enter\")->Buffer : (Text))\n\n#define PH_MAX_SECTION_EDIT_SIZE (32 * 1024 * 1024) // 32 MB\n\n // begin_phapppub\ntypedef struct _PH_HANDLE_ITEM_INFO\n{\n    HANDLE ProcessId;\n    HANDLE Handle;\n    PPH_STRING TypeName;\n    PPH_STRING BestObjectName;\n} PH_HANDLE_ITEM_INFO, *PPH_HANDLE_ITEM_INFO;\n\nVOID PhInsertHandleObjectPropertiesEMenuItems(\n    _In_ struct _PH_EMENU_ITEM *Menu,\n    _In_ ULONG InsertBeforeId,\n    _In_ BOOLEAN EnableShortcut,\n    _In_ PPH_HANDLE_ITEM_INFO Info\n    );\n\nVOID PhShowHandleObjectProperties1(\n    _In_ HWND hWnd,\n    _In_ PPH_HANDLE_ITEM_INFO Info\n    );\n\nVOID PhShowHandleObjectProperties2(\n    _In_ HWND hWnd,\n    _In_ PPH_HANDLE_ITEM_INFO Info\n    );\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/hndlprv.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_HNDLPRV_H\n#define PH_HNDLPRV_H\n\nextern PPH_OBJECT_TYPE PhHandleProviderType;\nextern PPH_OBJECT_TYPE PhHandleItemType;\n\n// begin_phapppub\n#define PH_HANDLE_FILE_SHARED_READ 0x1\n#define PH_HANDLE_FILE_SHARED_WRITE 0x2\n#define PH_HANDLE_FILE_SHARED_DELETE 0x4\n#define PH_HANDLE_FILE_SHARED_MASK 0x7\n\ntypedef struct _PH_HANDLE_ITEM\n{\n    PH_HASH_ENTRY HashEntry;\n\n    PVOID Object;\n    HANDLE Handle;\n    HANDLE ProcessId;\n    ULONG Attributes;\n    ACCESS_MASK GrantedAccess;\n    ULONG TypeIndex;\n    ULONG FileFlags;\n\n    ULONG HandleCount;\n    ULONG PointerCount;\n    ULONG PagedPoolCharge;\n    ULONG NonPagedPoolCharge;\n\n    PPH_STRING TypeName;\n    PPH_STRING ObjectName;\n    PPH_STRING BestObjectName;\n\n    WCHAR HandleString[PH_PTR_STR_LEN_1];\n    WCHAR GrantedAccessString[PH_PTR_STR_LEN_1];\n    WCHAR ObjectString[PH_PTR_STR_LEN_1];\n} PH_HANDLE_ITEM, *PPH_HANDLE_ITEM;\n\ntypedef struct _PH_HANDLE_PROVIDER\n{\n    PPH_HASH_ENTRY *HandleHashSet;\n    ULONG HandleHashSetSize;\n    ULONG HandleHashSetCount;\n    PH_QUEUED_LOCK HandleHashSetLock;\n\n    PH_CALLBACK HandleAddedEvent;\n    PH_CALLBACK HandleModifiedEvent;\n    PH_CALLBACK HandleRemovedEvent;\n    PH_CALLBACK HandleUpdatedEvent;\n\n    HANDLE ProcessId;\n    HANDLE ProcessHandle;\n\n    PPH_HASHTABLE TempListHashtable;\n    NTSTATUS RunStatus;\n} PH_HANDLE_PROVIDER, *PPH_HANDLE_PROVIDER;\n\nPPH_HANDLE_ITEM PhCreateHandleItem(\n    _In_opt_ PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handle\n    );\n// end_phapppub\n\nPPH_HANDLE_PROVIDER PhCreateHandleProvider(\n    _In_ HANDLE ProcessId\n    );\n\nPPH_HANDLE_ITEM PhReferenceHandleItem(\n    _In_ PPH_HANDLE_PROVIDER HandleProvider,\n    _In_ HANDLE Handle\n    );\n\nVOID PhDereferenceAllHandleItems(\n    _In_ PPH_HANDLE_PROVIDER HandleProvider\n    );\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhHandleProviderUpdate(\n    _In_ PVOID Object\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/informer.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2024\n *\n */\n\n#ifndef PH_KSIMSG_H\n#define PH_KSIMSG_H\n\ntypedef struct _PH_INFORMER_CONTEXT\n{\n    PKPH_MESSAGE Message;\n    ULONG_PTR ReplyToken;\n    BOOLEAN Handled;\n} PH_INFORMER_CONTEXT, *PPH_INFORMER_CONTEXT;\n\n/**\n * Callback registration for informer messages that can be replied to. Any\n * processing done by these callbacks **must** be brief as it is blocking\n * informer message handling on the system.\n *\n * Receives PPH_INFORMER_CONTEXT as the callback parameter. The callback\n * may use PhInformerReply to reply to a message. After a successful call to\n * PhInformerReply the context is updated with Handled set to TRUE. Callbacks\n * later in the chain will still be called, but the message should not be\n * replied to. Callbacks should generally check if the message has already\n * been handled prior to doing work.\n */\nextern PH_CALLBACK PhInformerCallback;\n\nNTSTATUS PhInformerReply(\n    _Inout_ PPH_INFORMER_CONTEXT Context,\n    _In_ PKPH_MESSAGE ReplyMessage\n    );\n\nBOOLEAN PhInformerDispatch(\n    _In_ ULONG_PTR ReplyToken,\n    _In_ PCKPH_MESSAGE Message\n    );\n\nVOID PhInformerInitialize(\n    VOID\n    );\n\nVOID PhInformerActivate(\n    VOID\n    );\n\nPPH_LIST PhInformerDatabaseQuery(\n    _In_ ULONG64 ProcessStartKey,\n    _In_opt_ PLARGE_INTEGER TimeStamp\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/ksisup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022\n *     dmex    2022-2023\n *\n */\n\n#ifndef PH_KSISUP_H\n#define PH_KSISUP_H\n\nVOID\nPhShowKsiStatus(\n    VOID\n    );\n\nVOID\nPhInitializeKsi(\n    VOID\n    );\n\nNTSTATUS\nPhCleanupKsi(\n    VOID\n    );\n\nPPH_STRING\nPhGetKsiMessage(\n    _In_opt_ NTSTATUS Status,\n    _In_ BOOLEAN Force,\n    _In_ PCWSTR Format,\n    ...\n    );\n\nLONG\nPhShowKsiMessage2(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ NTSTATUS Status,\n    _In_ BOOLEAN Force,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    );\n\nVOID\nPhShowKsiMessageEx(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ NTSTATUS Status,\n    _In_ BOOLEAN Force,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    );\n\nVOID\nPhShowKsiMessage(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR Icon,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    );\n\nPWSTR PhKsiStandardHelpText(\n    VOID\n    );\n\nFORCEINLINE\nVOID\nPhShowKsiNotConnected(\n    _In_opt_ HWND WindowHandle,\n    _In_ PWSTR Message\n    )\n{\n    PhShowKsiMessage(\n        WindowHandle,\n        TD_INFORMATION_ICON,\n        L\"Kernel driver not connected\",\n        L\"%s\\r\\n\\r\\n\"\n        L\"System Informer is not connected to the kernel driver or lacks the required state \"\n        L\"necessary for this feature. Make sure that the \\\"Enable kernel-mode driver\\\" option is \"\n        L\"enabled and that System Informer is running with administrator privileges.\",\n        Message\n        );\n}\n\nFORCEINLINE\nPPH_STRING\nPhGetKsiNotConnectedString(\n    _In_ PWSTR Message\n    )\n{\n    return PhGetKsiMessage(\n        0,\n        FALSE,\n        L\"%s\\r\\n\\r\\n%s\\r\\n\\r\\n%s\",\n        L\"Kernel driver not connected\",\n        L\"System Informer is not connected to the kernel driver or lacks the required state \"\n        L\"necessary for this feature. Make sure that the \\\"Enable kernel-mode driver\\\" option is \"\n        L\"enabled and that System Informer is running with administrator privileges.\",\n        Message\n        );\n}\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/mainwnd.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_MAINWND_H\n#define PH_MAINWND_H\n\nextern HWND PhMainWndHandle;\nextern BOOLEAN PhMainWndExiting;\n\n// begin_phapppub\n#define WM_PH_FIRST (WM_APP + 99)\n#define WM_PH_ACTIVATE (WM_APP + 99)\n#define WM_PH_SHOW_DIALOG (WM_APP + 100) // unused (plugins only)\n#define WM_PH_UPDATE_DIALOG (WM_APP + 101) // unused (plugins only)\n#define PH_ACTIVATE_REPLY 0x1119\n#define WM_PH_NOTIFY_ICON_MESSAGE (WM_APP + 126)\n#define WM_PH_UPDATE_FONT (WM_APP + 136)\n// end_phapppub\n#define WM_PH_DESTROY (WM_APP + 145)\n#define WM_PH_INVOKE (WM_APP + 146)\n#define WM_PH_PREPARE_FOR_EARLY_SHUTDOWN (WM_APP + 147)\n#define WM_PH_SAVE_ALL_SETTINGS (WM_APP + 148)\n#define WM_PH_SHOW_PROPERTIES (WM_APP + 149)\n#define WM_PH_ACTIVATE_WINDOW (WM_APP + 150)\n#define WM_PH_SELECT_NODE (WM_APP + 151)\n#define WM_PH_SHOW_EDITOR (WM_APP + 152)\n#define WM_PH_SHOW_RESULT (WM_APP + 153)\n#define WM_PH_LAST (WM_APP + 154)\n\n// begin_phapppub\ntypedef enum _PH_MAINWINDOW_CALLBACK_TYPE\n{\n    PH_MAINWINDOW_CALLBACK_TYPE_DESTROY,\n    PH_MAINWINDOW_CALLBACK_TYPE_SHOW_PROPERTIES,\n    PH_MAINWINDOW_CALLBACK_TYPE_SAVE_ALL_SETTINGS,\n    PH_MAINWINDOW_CALLBACK_TYPE_PREPARE_FOR_EARLY_SHUTDOWN,\n    PH_MAINWINDOW_CALLBACK_TYPE_CANCEL_EARLY_SHUTDOWN,\n    PH_MAINWINDOW_CALLBACK_TYPE_TOGGLE_VISIBLE,\n    PH_MAINWINDOW_CALLBACK_TYPE_SHOW_MEMORY_EDITOR,\n    PH_MAINWINDOW_CALLBACK_TYPE_SHOW_MEMORY_RESULTS,\n    PH_MAINWINDOW_CALLBACK_TYPE_SELECT_TAB_PAGE,\n    PH_MAINWINDOW_CALLBACK_TYPE_GET_CALLBACK_LAYOUT_PADDING,\n    PH_MAINWINDOW_CALLBACK_TYPE_INVALIDATE_LAYOUT_PADDING,\n    PH_MAINWINDOW_CALLBACK_TYPE_SELECT_PROCESS_NODE,\n    PH_MAINWINDOW_CALLBACK_TYPE_SELECT_SERVICE_ITEM,\n    PH_MAINWINDOW_CALLBACK_TYPE_SELECT_NETWORK_ITEM,\n    PH_MAINWINDOW_CALLBACK_TYPE_UPDATE_FONT,\n    PH_MAINWINDOW_CALLBACK_TYPE_GET_FONT,\n    PH_MAINWINDOW_CALLBACK_TYPE_INVOKE,\n    PH_MAINWINDOW_CALLBACK_TYPE_POST,\n    PH_MAINWINDOW_CALLBACK_TYPE_REFRESH,\n    PH_MAINWINDOW_CALLBACK_TYPE_CREATE_TAB_PAGE,\n    PH_MAINWINDOW_CALLBACK_TYPE_GET_UPDATE_AUTOMATICALLY,\n    PH_MAINWINDOW_CALLBACK_TYPE_SET_UPDATE_AUTOMATICALLY,\n    PH_MAINWINDOW_CALLBACK_TYPE_ICON_CLICK,\n    PH_MAINWINDOW_CALLBACK_TYPE_WINDOW_BASE,\n    PH_MAINWINDOW_CALLBACK_TYPE_GETWINDOW_PROCEDURE,\n    PH_MAINWINDOW_CALLBACK_TYPE_SETWINDOW_PROCEDURE,\n    PH_MAINWINDOW_CALLBACK_TYPE_WINDOW_HANDLE,\n    PH_MAINWINDOW_CALLBACK_TYPE_VERSION,\n    PH_MAINWINDOW_CALLBACK_TYPE_PORTABLE,\n    PH_MAINWINDOW_CALLBACK_TYPE_PAGEINDEX,\n    PH_MAINWINDOW_CALLBACK_TYPE_WINDOWDPI,\n    PH_MAINWINDOW_CALLBACK_TYPE_WINDOWNAME,\n    PH_MAINWINDOW_CALLBACK_TYPE_GET_MAIN_MENU,\n    PH_MAINWINDOW_CALLBACK_TYPE_GET_MAIN_SUBMENU,\n    PH_MAINWINDOW_CALLBACK_TYPE_SET_MAIN_SUBCMD,\n    PH_MAINWINDOW_CALLBACK_TYPE_MAXIMUM\n} PH_MAINWINDOW_CALLBACK_TYPE;\n\nPHAPPAPI\nPVOID\nNTAPI\nPhPluginInvokeWindowCallback(\n    _In_ PH_MAINWINDOW_CALLBACK_TYPE Event,\n    _In_opt_ PVOID wparam,\n    _In_opt_ PVOID lparam\n    );\n\n#define SystemInformer_Destroy() \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_DESTROY, 0, 0)\n#define SystemInformer_ShowProcessProperties(ProcessItem) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SHOW_PROPERTIES, 0, (PVOID)(ULONG_PTR)(ProcessItem))\n#define SystemInformer_SaveAllSettings() \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SAVE_ALL_SETTINGS, 0, 0)\n#define SystemInformer_PrepareForEarlyShutdown() \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_PREPARE_FOR_EARLY_SHUTDOWN, 0, 0)\n#define SystemInformer_CancelEarlyShutdown() \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_CANCEL_EARLY_SHUTDOWN, 0, 0)\n#define SystemInformer_ToggleVisible(AlwaysShow) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_TOGGLE_VISIBLE, (PVOID)(ULONG_PTR)(AlwaysShow), 0)\n#define SystemInformer_ShowMemoryEditor(ShowMemoryEditor) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SHOW_MEMORY_EDITOR, 0, (PVOID)(ULONG_PTR)(ShowMemoryEditor))\n#define SystemInformer_ShowMemoryResults(ShowMemoryResults) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SHOW_MEMORY_RESULTS, 0, (PVOID)(ULONG_PTR)(ShowMemoryResults))\n#define SystemInformer_SelectTabPage(Index) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SELECT_TAB_PAGE, 0, (PVOID)(ULONG_PTR)(Index))\n#define SystemInformer_GetCallbackLayoutPadding() \\\n    ((PPH_CALLBACK)PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_GET_CALLBACK_LAYOUT_PADDING, 0, 0))\n#define SystemInformer_InvalidateLayoutPadding() \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_INVALIDATE_LAYOUT_PADDING, 0, 0)\n#define SystemInformer_SelectProcessNode(ProcessNode) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SELECT_PROCESS_NODE, 0, (PVOID)(ULONG_PTR)(ProcessNode))\n#define SystemInformer_SelectServiceItem(ServiceItem) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SELECT_SERVICE_ITEM, 0, (PVOID)(ULONG_PTR)(ServiceItem))\n#define SystemInformer_SelectNetworkItem(NetworkItem) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SELECT_NETWORK_ITEM, 0, (PVOID)(ULONG_PTR)(NetworkItem))\n#define SystemInformer_UpdateFont() \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_UPDATE_FONT, 0, 0)\n#define SystemInformer_GetFont() \\\n    ((HFONT)PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_GET_FONT, 0, 0))\n#define SystemInformer_Invoke(Function, Parameter) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_INVOKE, (PVOID)(ULONG_PTR)(Parameter), (PVOID)(ULONG_PTR)(Function))\n//#define SystemInformer_Post(Function, Parameter) \\\n//    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_POST, (PVOID)(ULONG_PTR)(Parameter), (PVOID)(ULONG_PTR)(Function))\n//#define SystemInformer_CreateTabPage(Template) \\\n//    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_CREATE_TAB_PAGE, 0, (PVOID)(ULONG_PTR)(Template))\n#define SystemInformer_Refresh() \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_REFRESH, 0, 0)\n#define SystemInformer_GetUpdateAutomatically() \\\n    ((BOOLEAN)PtrToUlong(PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_GET_UPDATE_AUTOMATICALLY, 0, 0)))\n#define SystemInformer_SetUpdateAutomatically(Value) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SET_UPDATE_AUTOMATICALLY, (PVOID)(ULONG_PTR)(Value), 0)\n#define SystemInformer_IconClick() \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_ICON_CLICK, 0, 0)\n#define SystemInformer_GetInstanceHandle() \\\n    ((PVOID)PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_WINDOW_BASE, 0, 0))\n#define SystemInformer_GetWindowProcedure() \\\n    ((WNDPROC)PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_GETWINDOW_PROCEDURE, 0, 0))\n#define SystemInformer_SetWindowProcedure(Value) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SETWINDOW_PROCEDURE, (PVOID)(ULONG_PTR)(Value), 0)\n#define SystemInformer_GetWindowHandle() \\\n    ((HWND)PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_WINDOW_HANDLE, 0, 0))\n#define SystemInformer_GetWindowsVersion() \\\n    (PtrToUlong(PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_VERSION, 0, 0)))\n#define SystemInformer_IsPortableMode() \\\n    ((BOOLEAN)PtrToUlong(PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_PORTABLE, 0, 0)))\n#define SystemInformer_GetTabIndex(Value) \\\n    (PtrToUlong(PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_PAGEINDEX, (PVOID)(ULONG_PTR)(Value), 0)))\n#define SystemInformer_GetWindowDpi() \\\n    (PtrToUlong(PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_WINDOWDPI, 0, 0)))\n#define SystemInformer_GetWindowName() \\\n    (PWSTR)(PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_WINDOWNAME, 0, 0))\n#define SystemInformer_GetMainMenu() \\\n    ((PPH_EMENU)PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_GET_MAIN_MENU, 0, 0))\n#define SystemInformer_GetMainSubMenu(Index) \\\n    ((PPH_EMENU)PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_GET_MAIN_SUBMENU, (PVOID)(ULONG_PTR)(Index), 0))\n#define SystemInformer_SetMainSubCmd(Index, Context) \\\n    PhPluginInvokeWindowCallback(PH_MAINWINDOW_CALLBACK_TYPE_SET_MAIN_SUBCMD, (PVOID)(ULONG_PTR)(Index), (PVOID)Context)\n\n#define PhWindowsVersion SystemInformer_GetWindowsVersion() // Temporary backwards compat (dmex)\n// end_phapppub\n\n// begin_phapppub\nPHAPPAPI\nPVOID\nNTAPI\nPhPluginCreateTabPage(\n    _In_ PVOID Page\n    );\n// end_phapppub\n\ntypedef struct _PH_SHOW_MEMORY_EDITOR\n{\n    HWND OwnerWindow;\n    HANDLE ProcessId;\n    PVOID BaseAddress;\n    SIZE_T RegionSize;\n    ULONG SelectOffset;\n    ULONG SelectLength;\n    PPH_STRING Title;\n    ULONG Flags;\n} PH_SHOW_MEMORY_EDITOR, *PPH_SHOW_MEMORY_EDITOR;\n\ntypedef struct _PH_SHOW_MEMORY_RESULTS\n{\n    HANDLE ProcessId;\n    PPH_LIST Results;\n} PH_SHOW_MEMORY_RESULTS, *PPH_SHOW_MEMORY_RESULTS;\n\n// begin_phapppub\ntypedef struct _PH_LAYOUT_PADDING_DATA\n{\n    RECT Padding;\n} PH_LAYOUT_PADDING_DATA, *PPH_LAYOUT_PADDING_DATA;\n// end_phapppub\n\n// begin_phapppub\ntypedef enum _PH_MAIN_TAB_PAGE_MESSAGE\n{\n    MainTabPageCreate,\n    MainTabPageDestroy,\n    MainTabPageCreateWindow, // HWND *Parameter1 (WindowHandle), HWND Parameter2 (ParentWindow)\n    MainTabPageSelected, // BOOLEAN Parameter1 (Selected)\n    MainTabPageInitializeSectionMenuItems, // PPH_MAIN_TAB_PAGE_MENU_INFORMATION Parameter1\n\n    MainTabPageLoadSettings,\n    MainTabPageSaveSettings,\n    MainTabPageExportContent, // PPH_MAIN_TAB_PAGE_EXPORT_CONTENT Parameter1\n    MainTabPageFontChanged, // HFONT Parameter1 (Font)\n    MainTabPageUpdateAutomaticallyChanged, // BOOLEAN Parameter1 (UpdateAutomatically)\n    MainTabPageDpiChanged,\n\n    MaxMainTabPageMessage\n} PH_MAIN_TAB_PAGE_MESSAGE;\n\ntypedef struct _PH_MAIN_TAB_PAGE *PPH_MAIN_TAB_PAGE;\n\ntypedef _Function_class_(PH_MAIN_TAB_PAGE_CALLBACK)\nBOOLEAN NTAPI PH_MAIN_TAB_PAGE_CALLBACK(\n    _In_ PPH_MAIN_TAB_PAGE Page,\n    _In_ PH_MAIN_TAB_PAGE_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\ntypedef PH_MAIN_TAB_PAGE_CALLBACK* PPH_MAIN_TAB_PAGE_CALLBACK;\n\ntypedef struct _PH_MAIN_TAB_PAGE_EXPORT_CONTENT\n{\n    PPH_FILE_STREAM FileStream;\n    ULONG Mode;\n} PH_MAIN_TAB_PAGE_EXPORT_CONTENT, *PPH_MAIN_TAB_PAGE_EXPORT_CONTENT;\n\ntypedef struct _PH_MAIN_TAB_PAGE_MENU_INFORMATION\n{\n    PPH_EMENU_ITEM Menu;\n    ULONG StartIndex;\n} PH_MAIN_TAB_PAGE_MENU_INFORMATION, *PPH_MAIN_TAB_PAGE_MENU_INFORMATION;\n\ntypedef struct _PH_MAIN_TAB_PAGE\n{\n    // Public\n\n    PH_STRINGREF Name;\n    ULONG Flags;\n    PPH_MAIN_TAB_PAGE_CALLBACK Callback;\n    PVOID Context;\n\n    LONG Index;\n    union\n    {\n        ULONG StateFlags;\n        struct\n        {\n            ULONG Selected : 1;\n            ULONG CreateWindowCalled : 1;\n            ULONG SpareStateFlags : 30;\n        };\n    };\n    PVOID Reserved[2];\n// end_phapppub\n\n    // Private\n\n    HWND WindowHandle;\n// begin_phapppub\n} PH_MAIN_TAB_PAGE, *PPH_MAIN_TAB_PAGE;\n// end_phapppub\n\n// begin_phapppub\n#define PH_NOTIFY_MINIMUM 0x1\n#define PH_NOTIFY_PROCESS_CREATE 0x1\n#define PH_NOTIFY_PROCESS_DELETE 0x2\n#define PH_NOTIFY_SERVICE_CREATE 0x4\n#define PH_NOTIFY_SERVICE_DELETE 0x8\n#define PH_NOTIFY_SERVICE_START 0x10\n#define PH_NOTIFY_SERVICE_STOP 0x20\n#define PH_NOTIFY_SERVICE_MODIFIED 0x40\n#define PH_NOTIFY_DEVICE_ARRIVED 0x80\n#define PH_NOTIFY_DEVICE_REMOVED 0x100\n#define PH_NOTIFY_MAXIMUM 0x200\n#define PH_NOTIFY_VALID_MASK 0x1ff\n// end_phapppub\n\nBOOLEAN PhMainWndInitialization(\n    _In_ LONG ShowCommand\n    );\n\nVOID PhAddMiniProcessMenuItems(\n    _Inout_ PPH_EMENU_ITEM Menu,\n    _In_ HANDLE ProcessId\n    );\n\nBOOLEAN PhHandleMiniProcessMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem\n    );\n\nVOID PhShowIconContextMenu(\n    _In_ HWND WindowHandle,\n    _In_ PPOINT Location\n    );\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhShowIconNotification(\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Text\n    );\n\ntypedef enum _PH_TOAST_REASON\n{\n    PhToastReasonUserCanceled,\n    PhToastReasonApplicationHidden,\n    PhToastReasonTimedOut,\n    PhToastReasonActivated,\n    PhToastReasonError,\n    PhToastReasonUnknown\n} PH_TOAST_REASON;\n\ntypedef _Function_class_(PH_TOAST_CALLBACK)\nVOID NTAPI PH_TOAST_CALLBACK(\n    _In_ HRESULT Result,\n    _In_ PH_TOAST_REASON Reason,\n    _In_ PVOID Context\n);\ntypedef PH_TOAST_CALLBACK* PPH_TOAST_CALLBACK;\n\nPHAPPAPI\nHRESULT\nNTAPI\nPhShowIconNotificationEx(\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Text,\n    _In_ ULONG Timeout,\n    _In_opt_ PPH_TOAST_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n// end_phapppub\n\nVOID PhProcessInvokeQueue(\n    VOID\n    );\n\nVOID PhShowDetailsForIconNotification(\n    VOID\n    );\n\nVOID PhShowOptionsRestartRequired(\n    _In_ HWND WindowHandle\n    );\n\nBOOLEAN PhShowOptionsDefaultInstallLocation(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR Message\n    );\n\nVOID PhShowProcessContextMenu(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    );\n\nVOID PhShowServiceContextMenu(\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    );\n\nVOID PhShowNetworkContextMenu(\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    );\n\ntypedef struct _PH_EMENU_ITEM PH_EMENU, *PPH_EMENU;\n\nVOID PhServiceListInsertContextMenu(\n    _In_ HWND ParentWindow,\n    _In_ PPH_EMENU Menu,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/mainwndp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_MAINWNDP_H\n#define PH_MAINWNDP_H\n\n#define PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1 250\n#define PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_2 750\n#define PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM 1000\n\n#define TIMER_FLUSH_PROCESS_QUERY_DATA 1\n#define TIMER_ICON_CLICK_ACTIVATE 2\n#define TIMER_ICON_RESTORE_HOVER 3\n#define TIMER_ICON_POPUPOPEN 4\n\ntypedef union _PH_MWP_NOTIFICATION_DETAILS\n{\n    HANDLE ProcessId;\n    PPH_STRING ServiceName;\n} PH_MWP_NOTIFICATION_DETAILS, *PPH_MWP_NOTIFICATION_DETAILS;\n\nextern PH_PROVIDER_REGISTRATION PhMwpProcessProviderRegistration;\nextern PH_PROVIDER_REGISTRATION PhMwpServiceProviderRegistration;\nextern PH_PROVIDER_REGISTRATION PhMwpNetworkProviderRegistration;\nextern BOOLEAN PhMwpUpdateAutomatically;\n\nextern ULONG PhMwpNotifyIconNotifyMask;\nextern ULONG PhMwpLastNotificationType;\nextern PH_MWP_NOTIFICATION_DETAILS PhMwpLastNotificationDetails;\n\nLRESULT CALLBACK PhMwpWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n//\n// Initialization\n//\n\nRTL_ATOM PhMwpInitializeWindowClass(\n    VOID\n    );\n\nPPH_STRING PhMwpInitializeWindowTitle(\n    VOID\n    );\n\nVOID PhMwpInitializeProviders(\n    VOID\n    );\n\nVOID PhMwpShowWindow(\n    _In_ LONG ShowCommand\n    );\n\nVOID PhMwpApplyUpdateInterval(\n    _In_ ULONG Interval\n    );\n\nVOID PhMwpInitializeMetrics(\n    _In_ HWND WindowHandle,\n    _In_ LONG WindowDpi\n    );\n\nVOID PhMwpInitializeControls(\n    _In_ HWND WindowHandle\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhMwpLoadStage1Worker(\n    _In_ PVOID Parameter\n    );\n\nVOID PhMwpInvokePrepareEarlyExit(\n    _In_ HWND WindowHandle\n    );\n\nVOID PhMwpInvokeActivateWindow(\n    _In_ BOOLEAN Toggle\n    );\n\nVOID PhMwpInvokeSelectTabPage(\n    _In_ PVOID Parameter\n    );\n\nVOID PhMwpInvokeSelectServiceItem(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    );\n\nVOID PhMwpInvokeSelectNetworkItem(\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    );\n\nVOID PhMwpInvokeUpdateWindowFont(\n    _In_opt_ PVOID Parameter\n    );\n\nVOID PhMwpInvokeUpdateWindowFontMonospace(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID Parameter\n    );\n\n//\n// Main\n//\n\nLONG PhMainMessageLoop(\n    VOID\n    );\n\nVOID PhInitializePreviousInstance(\n    VOID\n    );\n\nVOID PhActivatePreviousInstance(\n    VOID\n    );\n\nVOID PhInitializeCommonControls(\n    VOID\n    );\n\nVOID PhInitializeSuperclassControls( // delayhook.c\n    VOID\n    );\n\nNTSTATUS PhInitializeAppSystem(\n    VOID\n    );\n\nVOID PhInitializeAppSettings(\n    VOID\n    );\n\nVOID PhpProcessStartupParameters(\n    VOID\n    );\n\nVOID PhpEnablePrivileges(\n    VOID\n    );\n\nVOID PhEnableTerminationPolicy(\n    _In_ BOOLEAN Enabled\n    );\n\nNTSTATUS PhInitializeDirectoryPolicy(\n    VOID\n    );\n\nNTSTATUS PhInitializeExceptionPolicy(\n    VOID\n    );\n\nNTSTATUS PhInitializeExecutionPolicy(\n    VOID\n    );\n\nNTSTATUS PhInitializeNamespacePolicy(\n    VOID\n    );\n\nNTSTATUS PhInitializeMitigationPolicy(\n    VOID\n    );\n\nNTSTATUS PhInitializeComPolicy(\n    VOID\n    );\n\nNTSTATUS PhInitializeTimerPolicy(\n    VOID\n    );\n\n//\n// Event handlers\n//\n\nVOID PhMwpOnDestroy(\n    _In_ HWND WindowHandle\n    );\n\nVOID PhMwpOnEndSession(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN SessionEnding,\n    _In_ ULONG Reason\n    );\n\nVOID PhMwpOnSettingChange(\n    _In_ HWND WindowHandle,\n    _In_opt_ ULONG Action,\n    _In_opt_ PCWSTR Metric\n    );\n\nVOID PhMwpOnCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id\n    );\n\nVOID PhMwpOnShowWindow(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN Showing,\n    _In_ ULONG State\n    );\n\nBOOLEAN PhMwpOnSysCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Type,\n    _In_ LONG CursorScreenX,\n    _In_ LONG CursorScreenY\n    );\n\nVOID PhMwpOnMenuCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Index,\n    _In_ HMENU Menu\n    );\n\nVOID PhMwpOnInitMenuPopup(\n    _In_ HWND WindowHandle,\n    _In_ HMENU Menu,\n    _In_ ULONG Index,\n    _In_ BOOLEAN IsWindowMenu\n    );\n\nVOID PhMwpOnSize(\n    _In_ HWND WindowHandle,\n    _In_ UINT State,\n    _In_ LONG Width,\n    _In_ LONG Height\n    );\n\nVOID PhMwpOnSizing(\n    _In_ ULONG Edge,\n    _In_ PRECT DragRectangle\n    );\n\nVOID PhMwpOnSetFocus(\n    _In_ HWND WindowHandle\n    );\n\nVOID PhMwpOnTimer(\n    _In_ HWND WindowHandle,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Success_(return)\nBOOLEAN PhMwpOnNotify(\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    );\n\nVOID PhMwpOnDeviceChanged(\n    _In_ HWND WindowHandle,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhMwpOnDpiChanged(\n    _In_ HWND WindowHandle,\n    _In_ LONG WindowDpi\n    );\n\nLRESULT PhMwpOnUserMessage(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    );\n\n//\n// Settings\n//\n\nVOID PhMwpLoadSettings(\n    _In_ HWND WindowHandle\n    );\n\nVOID PhMwpSaveSettings(\n    _In_ HWND WindowHandle\n    );\n\nVOID PhMwpSaveWindowState(\n    _In_ HWND WindowHandle\n    );\n\n//\n// Misc.\n//\n\nVOID PhMwpUpdateLayoutPadding(\n    VOID\n    );\n\nVOID PhMwpApplyLayoutPadding(\n    _Inout_ PRECT Rect,\n    _In_ PRECT Padding\n    );\n\nVOID PhMwpLayout(\n    _Inout_ HDWP *DeferHandle\n    );\n\nVOID PhMwpSetupComputerMenu(\n    _In_ PPH_EMENU_ITEM Root\n    );\n\nBOOLEAN PhMwpExecuteComputerCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id\n    );\n\nVOID PhMwpActivateWindow(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN Toggle\n    );\n\n//\n// Main menu\n//\n\nPPH_EMENU PhpCreateMainMenu(\n    _In_ ULONG SubMenuIndex\n    );\n\nVOID PhMwpInitializeMainMenu(\n    _In_ HWND WindowHandle\n    );\n\nVOID PhMwpDispatchMenuCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG ItemId,\n    _In_ ULONG_PTR ItemData\n    );\n\nVOID PhMwpInitializeSubMenu(\n    _In_ HWND WindowHandle,\n    _In_ PPH_EMENU Menu,\n    _In_ ULONG Index\n    );\n\nVOID PhMwpInitializeSectionMenuItems(\n    _In_ PPH_EMENU Menu,\n    _In_ ULONG StartIndex\n    );\n\nBOOLEAN PhMwpExecuteNotificationMenuCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id\n    );\n\nBOOLEAN PhMwpExecuteNotificationSettingsMenuCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id\n    );\n\nPPH_EMENU PhMwpCreateProcessMenu(\n    _In_ BOOLEAN SystemProcess\n    );\n\n//\n// Tab control\n//\n\nVOID PhMwpLayoutTabControl(\n    _Inout_ HDWP *DeferHandle\n    );\n\nVOID PhMwpNotifyTabControl(\n    _In_ NMHDR *Header\n    );\n\nVOID PhMwpSelectionChangedTabControl(\n    _In_ LONG OldIndex\n    );\n\nPPH_MAIN_TAB_PAGE PhMwpCreatePage(\n    _In_ PPH_MAIN_TAB_PAGE Template\n    );\n\nVOID PhMwpSelectPage(\n    _In_ ULONG Index\n    );\n\nPPH_MAIN_TAB_PAGE PhMwpFindPage(\n    _In_ PPH_STRINGREF Name\n    );\n\nPPH_MAIN_TAB_PAGE PhMwpCreateInternalPage(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_MAIN_TAB_PAGE_CALLBACK Callback\n    );\n\nVOID PhMwpNotifyAllPages(\n    _In_ PH_MAIN_TAB_PAGE_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\n\n//\n// Notifications\n//\n\nVOID PhMwpAddIconProcesses(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG NumberOfProcesses\n    );\n\nVOID PhMwpClearLastNotificationDetails(\n    VOID\n    );\n\nBOOLEAN PhMwpPluginNotifyEvent(\n    _In_ ULONG Type,\n    _In_ PVOID Parameter\n    );\n\ntypedef struct _PH_MAIN_TAB_PAGE *PPH_MAIN_TAB_PAGE;\ntypedef struct _PH_PROVIDER_EVENT_QUEUE PH_PROVIDER_EVENT_QUEUE, *PPH_PROVIDER_EVENT_QUEUE;\n\ntypedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _PH_INVOKE_ENTRY\n{\n    SLIST_ENTRY ListEntry;\n    PVOID Command;\n    PVOID Parameter;\n    //HANDLE ThreadId;\n    //ULONG64 SubmitTime;\n} PH_INVOKE_ENTRY, * PPH_INVOKE_ENTRY;\n\nextern SLIST_HEADER PhMainThreadInvokeQueue;\nextern PH_FREE_LIST PhMainThreadInvokeQueueFreeList;\nextern volatile LONG PhMainThreadInvokePending;\n\n//\n// Processes\n//\n\nextern PPH_MAIN_TAB_PAGE PhMwpProcessesPage;\nextern HWND PhMwpProcessTreeNewHandle;\nextern HWND PhMwpSelectedProcessWindowHandle;\nextern BOOLEAN PhMwpSelectedProcessVirtualizationEnabled;\nextern PH_PROVIDER_EVENT_QUEUE PhMwpProcessEventQueue;\n\n_Function_class_(PH_MAIN_TAB_PAGE_CALLBACK)\nBOOLEAN PhMwpProcessesPageCallback(\n    _In_ PPH_MAIN_TAB_PAGE Page,\n    _In_ PH_MAIN_TAB_PAGE_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\n\nVOID PhMwpShowProcessProperties(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\nVOID PhMwpToggleCurrentUserProcessTreeFilter(\n    VOID\n    );\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpCurrentUserProcessTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhMwpToggleSignedProcessTreeFilter(\n    _In_ HWND WindowHandle\n    );\n\nVOID PhMwpToggleMicrosoftProcessTreeFilter(\n    VOID\n    );\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpSignedProcessTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpMicrosoftProcessTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    );\n\nBOOLEAN PhMwpExecuteProcessPriorityClassCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n\nBOOLEAN PhMwpExecuteProcessIoPriorityCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n\nVOID PhMwpSetProcessMenuPriorityChecks(\n    _In_ PPH_EMENU Menu,\n    _In_opt_ HANDLE ProcessId,\n    _In_ BOOLEAN SetPriority,\n    _In_ BOOLEAN SetIoPriority,\n    _In_ BOOLEAN SetPagePriority\n    );\n\nVOID PhMwpInitializeProcessMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpProcessAddedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpProcessModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpProcessRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpProcessesUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\nVOID PhMwpOnProcessesUpdated(\n    _In_ ULONG RunId\n    );\n\n//\n// Services\n//\n\nextern PPH_MAIN_TAB_PAGE PhMwpServicesPage;\nextern HWND PhMwpServiceTreeNewHandle;\nextern PH_PROVIDER_EVENT_QUEUE PhMwpServiceEventQueue;\n\n_Function_class_(PH_MAIN_TAB_PAGE_CALLBACK)\nBOOLEAN PhMwpServicesPageCallback(\n    _In_ PPH_MAIN_TAB_PAGE Page,\n    _In_ PH_MAIN_TAB_PAGE_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    );\n\nVOID PhMwpNeedServiceTreeList(\n    VOID\n    );\n\nVOID PhMwpToggleDriverServiceTreeFilter(\n    VOID\n    );\n\nVOID PhMwpToggleMicrosoftServiceTreeFilter(\n    VOID\n    );\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpDriverServiceTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpMicrosoftServiceTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhMwpInitializeServiceMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ PPH_SERVICE_ITEM *Services,\n    _In_ ULONG NumberOfServices\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpServiceAddedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpServiceModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpServiceRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpServicesUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\nVOID PhMwpOnServicesUpdated(\n    _In_ ULONG RunId\n    );\n\n//\n// Network\n//\n\nextern PPH_MAIN_TAB_PAGE PhMwpNetworkPage;\nextern HWND PhMwpNetworkTreeNewHandle;\nextern PH_PROVIDER_EVENT_QUEUE PhMwpNetworkEventQueue;\n\n_Function_class_(PH_MAIN_TAB_PAGE_CALLBACK)\nBOOLEAN PhMwpNetworkPageCallback(\n    _In_ PPH_MAIN_TAB_PAGE Page,\n    _In_ PH_MAIN_TAB_PAGE_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    );\n\nVOID PhMwpNeedNetworkTreeList(\n    VOID\n    );\n\nVOID PhMwpToggleNetworkWaitingConnectionTreeFilter(\n    VOID\n    );\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpNetworkTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhMwpInitializeNetworkMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ PPH_NETWORK_ITEM *NetworkItems,\n    _In_ ULONG NumberOfNetworkItems\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhMwpNetworkItemAddedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhMwpNetworkItemModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhMwpNetworkItemRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhMwpNetworkItemsUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    );\n\nVOID PhMwpOnNetworkItemsUpdated(\n    _In_ ULONG RunId\n    );\n\n//\n// Devices\n//\n\nVOID PhMwpInitializeDeviceNotifications(\n    VOID\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/memlist.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_MEMLIST_H\n#define PH_MEMLIST_H\n\n#include <colmgr.h>\n\n// Columns\n\n#define PHMMTLC_BASEADDRESS 0\n#define PHMMTLC_TYPE 1\n#define PHMMTLC_SIZE 2\n#define PHMMTLC_PROTECTION 3\n#define PHMMTLC_USE 4\n#define PHMMTLC_TOTALWS 5\n#define PHMMTLC_PRIVATEWS 6\n#define PHMMTLC_SHAREABLEWS 7\n#define PHMMTLC_SHAREDWS 8\n#define PHMMTLC_LOCKEDWS 9\n#define PHMMTLC_COMMITTED 10\n#define PHMMTLC_PRIVATE 11\n#define PHMMTLC_SIGNING_LEVEL 12\n#define PHMMTLC_ORIGINAL_PROTECTION 13\n#define PHMMTLC_ORIGINAL_PAGES 14\n#define PHMMTLC_REGIONTYPE 15\n#define PHMMTLC_PRIORITY 16\n\n#define PHMMTLC_MAXIMUM 17\n\n// begin_phapppub\ntypedef struct _PH_MEMORY_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    BOOLEAN IsAllocationBase;\n    BOOLEAN Reserved1;\n    USHORT Reserved2;\n    PPH_MEMORY_ITEM MemoryItem;\n\n    struct _PH_MEMORY_NODE *Parent;\n    PPH_LIST Children;\n// end_phapppub\n\n    PH_STRINGREF TextCache[PHMMTLC_MAXIMUM];\n\n    WCHAR TypeText[30];\n    PPH_STRING SizeText;\n    WCHAR ProtectionText[17];\n    WCHAR OriginalProtectionText[17];\n    PPH_STRING UseText;\n    PPH_STRING TotalWsText;\n    PPH_STRING PrivateWsText;\n    PPH_STRING ShareableWsText;\n    PPH_STRING SharedWsText;\n    PPH_STRING LockedWsText;\n    PPH_STRING CommittedText;\n    PPH_STRING PrivateText;\n    PPH_STRING OriginalPagesText;\n    PPH_STRING RegionTypeText;\n    PPH_STRING PriorityText;\n// begin_phapppub\n} PH_MEMORY_NODE, *PPH_MEMORY_NODE;\n// end_phapppub\n\n#define PH_MEMORY_FLAGS_FREE_OPTION 1\n#define PH_MEMORY_FLAGS_RESERVED_OPTION 2\n#define PH_MEMORY_FLAGS_PRIVATE_OPTION 3\n#define PH_MEMORY_FLAGS_SYSTEM_OPTION 4\n#define PH_MEMORY_FLAGS_CFG_OPTION 5\n#define PH_MEMORY_FLAGS_EXECUTE_OPTION 6\n#define PH_MEMORY_FLAGS_GUARD_OPTION 7\n#define PH_MEMORY_FLAGS_ZERO_PAD_ADDRESSES 8\n\ntypedef struct _PH_MEMORY_LIST_CONTEXT\n{\n    HWND ParentWindowHandle;\n    HWND TreeNewHandle;\n    ULONG TreeNewSortColumn;\n    PH_TN_FILTER_SUPPORT AllocationTreeFilterSupport;\n    PH_TN_FILTER_SUPPORT TreeFilterSupport;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PH_CM_MANAGER Cm;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG HideFreeRegions : 1;\n            ULONG HideReservedRegions : 1;\n            ULONG HighlightPrivatePages : 1;\n            ULONG HighlightSystemPages : 1;\n            ULONG HighlightCfgPages : 1;\n            ULONG HighlightExecutePages : 1;\n            ULONG HideGuardRegions : 1;\n            ULONG ZeroPadAddresses : 1;\n            ULONG Spare : 24;\n        };\n    };\n\n    PPH_LIST AllocationBaseNodeList; // Allocation base nodes (list should always be sorted by base address)\n    PPH_LIST RegionNodeList; // Memory region nodes\n} PH_MEMORY_LIST_CONTEXT, *PPH_MEMORY_LIST_CONTEXT;\n\nVOID PhInitializeMemoryList(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND TreeNewHandle,\n    _Out_ PPH_MEMORY_LIST_CONTEXT Context\n    );\n\nVOID PhDeleteMemoryList(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    );\n\nVOID PhLoadSettingsMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context\n    );\n\nVOID PhSaveSettingsMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context\n    );\n\nVOID PhSetOptionsMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ ULONG Options\n    );\n\nVOID PhReplaceMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_opt_ PPH_MEMORY_ITEM_LIST List\n    );\n\nVOID PhRemoveMemoryNode(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ PPH_MEMORY_ITEM_LIST List,\n    _In_ PPH_MEMORY_NODE MemoryNode\n    );\n\nVOID PhUpdateMemoryNode(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ PPH_MEMORY_NODE MemoryNode\n    );\n\nVOID PhInvalidateAllMemoryNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    );\n\nVOID PhInvalidateAllMemoryBaseAddressNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    );\n\nVOID PhExpandAllMemoryNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ BOOLEAN Expand\n    );\n\nPPH_STRING PhGetMemoryRegionUseText(\n    _In_ PPH_MEMORY_ITEM MemoryItem\n    );\n\nPPH_MEMORY_NODE PhGetSelectedMemoryNode(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    );\n\nVOID PhGetSelectedMemoryNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context,\n    _Out_ PPH_MEMORY_NODE **MemoryNodes,\n    _Out_ PULONG NumberOfMemoryNodes\n    );\n\nVOID PhDeselectAllMemoryNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/memprv.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2018-2023\n *\n */\n\n#ifndef PH_MEMPRV_H\n#define PH_MEMPRV_H\n\nextern PPH_OBJECT_TYPE PhMemoryItemType;\n\n// begin_phapppub\ntypedef enum _PH_MEMORY_REGION_TYPE\n{\n    UnknownRegion,\n    CustomRegion,\n    UnusableRegion,\n    MappedFileRegion,\n    UserSharedDataRegion,\n    PebRegion,\n    Peb32Region,\n    TebRegion,\n    Teb32Region, // Not used\n    StackRegion,\n    Stack32Region,\n    HeapRegion,\n    Heap32Region,\n    HeapSegmentRegion,\n    HeapSegment32Region,\n    CfgBitmapRegion,\n    CfgBitmap32Region,\n    ApiSetMapRegion,\n    HypervisorSharedDataRegion,\n    ReadOnlySharedMemoryRegion,\n    CodePageDataRegion,\n    GdiSharedHandleTableRegion,\n    ShimDataRegion,\n    ActivationContextDataRegion,\n    WerRegistrationDataRegion,\n    SiloSharedDataRegion,\n    TelemetryCoverageRegion,\n    ProcessParametersRegion,\n    LeapSecondDataRegion,\n    DesktopHeapRegion,\n} PH_MEMORY_REGION_TYPE;\n\ntypedef enum _PH_ACTIVATION_CONTEXT_DATA_TYPE\n{\n    CustomActivationContext,\n    ProcessActivationContext,\n    SystemActivationContext\n} PH_ACTIVATION_CONTEXT_DATA_TYPE;\n\ntypedef struct _PH_MEMORY_ITEM\n{\n    LIST_ENTRY ListEntry;\n    PH_AVL_LINKS Links;\n\n    union\n    {\n        MEMORY_BASIC_INFORMATION BasicInfo;\n        struct\n        {\n            PVOID BaseAddress;\n            PVOID AllocationBase;\n            ULONG AllocationProtect;\n            SIZE_T RegionSize;\n            ULONG State;\n            ULONG Protect;\n            ULONG Type;\n        };\n    };\n\n    union\n    {\n        BOOLEAN Attributes;\n        struct\n        {\n            BOOLEAN Valid : 1;\n            BOOLEAN Bad : 1;\n            BOOLEAN Spare : 6;\n        };\n    };\n    union\n    {\n        ULONG RegionTypeEx;\n        struct\n        {\n            ULONG Private : 1;\n            ULONG MappedDataFile : 1;\n            ULONG MappedImage : 1;\n            ULONG MappedPageFile : 1;\n            ULONG MappedPhysical : 1;\n            ULONG DirectMapped : 1;\n            ULONG SoftwareEnclave : 1; // REDSTONE3\n            ULONG PageSize64K : 1;\n            ULONG PlaceholderReservation : 1; // REDSTONE4\n            ULONG MappedAwe : 1; // 21H1\n            ULONG MappedWriteWatch : 1;\n            ULONG PageSizeLarge : 1;\n            ULONG PageSizeHuge : 1;\n            ULONG Reserved : 19; // Sync with MemoryRegionInformationEx (dmex)\n        };\n    };\n\n    WCHAR BaseAddressString[PH_PTR_STR_LEN_1];\n\n    struct _PH_MEMORY_ITEM *AllocationBaseItem;\n\n    SIZE_T CommittedSize;\n    SIZE_T PrivateSize;\n\n    SIZE_T TotalWorkingSetPages;\n    SIZE_T PrivateWorkingSetPages;\n    SIZE_T SharedWorkingSetPages;\n    SIZE_T ShareableWorkingSetPages;\n    SIZE_T LockedWorkingSetPages;\n\n    SIZE_T SharedOriginalPages;\n\n    ULONG_PTR Priority;\n    PH_MEMORY_REGION_TYPE RegionType;\n\n    union\n    {\n        struct\n        {\n            PPH_STRING Text;\n            BOOLEAN PropertyOfAllocationBase;\n        } Custom;\n        struct\n        {\n            PPH_STRING FileName;\n            BOOLEAN SigningLevelValid;\n            SE_SIGNING_LEVEL SigningLevel;\n        } MappedFile;\n        struct\n        {\n            HANDLE ThreadId;\n        } Teb;\n        struct\n        {\n            HANDLE ThreadId;\n        } Stack;\n        struct\n        {\n            ULONG Index;\n            BOOLEAN ClassValid;\n            ULONG Class;\n        } Heap;\n        struct\n        {\n            struct _PH_MEMORY_ITEM *HeapItem;\n        } HeapSegment;\n        struct\n        {\n            PH_ACTIVATION_CONTEXT_DATA_TYPE Type;\n        } ActivationContextData;\n    } u;\n} PH_MEMORY_ITEM, *PPH_MEMORY_ITEM;\n\ntypedef struct _PH_MEMORY_ITEM_LIST\n{\n    HANDLE ProcessId;\n    PH_AVL_TREE Set;\n    LIST_ENTRY ListHead;\n} PH_MEMORY_ITEM_LIST, *PPH_MEMORY_ITEM_LIST;\n// end_phapppub\n\nVOID PhGetMemoryProtectionString(\n    _In_ ULONG Protection,\n    _Inout_z_ PWSTR String\n    );\n\nPCPH_STRINGREF PhGetMemoryStateString(\n    _In_ ULONG State\n    );\n\nPCPH_STRINGREF PhGetMemoryTypeString(\n    _In_ ULONG Type\n    );\n\nPCPH_STRINGREF PhGetSigningLevelString(\n    _In_ SE_SIGNING_LEVEL SigningLevel\n    );\n\nPCPH_STRINGREF PhGetMemoryPagePriorityString(\n    _In_ ULONG PagePriority\n    );\n\nPPH_STRING PhGetMemoryRegionTypeExString(\n    _In_ PPH_MEMORY_ITEM MemoryItem\n    );\n\nPPH_MEMORY_ITEM PhCreateMemoryItem(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhDeleteMemoryItemList(\n    _In_ PPH_MEMORY_ITEM_LIST List\n    );\n\nPHAPPAPI\nPPH_MEMORY_ITEM\nNTAPI\nPhLookupMemoryItemList(\n    _In_ PPH_MEMORY_ITEM_LIST List,\n    _In_ PVOID Address\n    );\n\n#define PH_QUERY_MEMORY_IGNORE_FREE        0x1\n#define PH_QUERY_MEMORY_REGION_TYPE        0x2\n#define PH_QUERY_MEMORY_WS_COUNTERS        0x4\n#define PH_QUERY_MEMORY_ZERO_PAD_ADDRESSES 0x8\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhQueryMemoryItemList(\n    _In_ HANDLE ProcessId,\n    _In_ ULONG Flags,\n    _Out_ PPH_MEMORY_ITEM_LIST List\n    );\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/memsrch.h",
    "content": "#ifndef PH_MEMSRCH_H\n#define PH_MEMSRCH_H\n\ntypedef struct _PH_MEMORY_RESULT\n{\n    LONG RefCount;\n    PVOID Address;\n    PVOID BaseAddress;\n    SIZE_T Length;\n    PH_STRINGREF Display;\n} PH_MEMORY_RESULT, *PPH_MEMORY_RESULT;\n\ntypedef VOID (NTAPI *PPH_MEMORY_RESULT_CALLBACK)(\n    _In_ _Assume_refs_(1) PPH_MEMORY_RESULT Result,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_DISPLAY_BUFFER_COUNT (PAGE_SIZE * 2 - 1)\n\ntypedef struct _PH_MEMORY_SEARCH_OPTIONS\n{\n    BOOLEAN Cancel;\n    PPH_MEMORY_RESULT_CALLBACK Callback;\n    PVOID Context;\n} PH_MEMORY_SEARCH_OPTIONS, *PPH_MEMORY_SEARCH_OPTIONS;\n\ntypedef struct _PH_MEMORY_STRING_OPTIONS\n{\n    PH_MEMORY_SEARCH_OPTIONS Header;\n\n    ULONG MinimumLength;\n    ULONG MemoryTypeMask;\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN DetectUnicode : 1;\n            BOOLEAN ExtendedUnicode : 1;\n            BOOLEAN Spare : 6;\n        };\n    };\n} PH_MEMORY_STRING_OPTIONS, *PPH_MEMORY_STRING_OPTIONS;\n\nPVOID PhAllocateForMemorySearch(\n    _In_ SIZE_T Size\n    );\n\nVOID PhFreeForMemorySearch(\n    _In_ _Post_invalid_ PVOID Memory\n    );\n\nPVOID PhCreateMemoryResult(\n    _In_ PVOID Address,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T Length\n    );\n\nVOID PhReferenceMemoryResult(\n    _In_ PPH_MEMORY_RESULT Result\n    );\n\nVOID PhDereferenceMemoryResult(\n    _In_ PPH_MEMORY_RESULT Result\n    );\n\nVOID PhDereferenceMemoryResults(\n    _In_reads_(NumberOfResults) PPH_MEMORY_RESULT *Results,\n    _In_ ULONG NumberOfResults\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/miniinfo.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_MINIINFO_H\n#define PH_MINIINFO_H\n\n#include <procgrp.h>\n\n// begin_phapppub\n// Section\n\ntypedef struct _PH_MINIINFO_SECTION PH_MINIINFO_SECTION, *PPH_MINIINFO_SECTION;\n\ntypedef VOID (NTAPI *PPH_MINIINFO_SET_SECTION_TEXT)(\n    _In_ PPH_MINIINFO_SECTION Section,\n    _In_opt_ PPH_STRING Text\n    );\n\ntypedef struct _PH_MINIINFO_PARAMETERS\n{\n    HWND ContainerWindowHandle;\n    HWND MiniInfoWindowHandle;\n\n    HFONT Font;\n    HFONT MediumFont;\n    ULONG FontHeight;\n    ULONG FontAverageWidth;\n    ULONG MediumFontHeight;\n    ULONG MediumFontAverageWidth;\n\n    PPH_MINIINFO_SET_SECTION_TEXT SetSectionText;\n} PH_MINIINFO_PARAMETERS, *PPH_MINIINFO_PARAMETERS;\n\ntypedef enum _PH_MINIINFO_SECTION_MESSAGE\n{\n    MiniInfoCreate,\n    MiniInfoDestroy,\n    MiniInfoTick,\n    MiniInfoSectionChanging, // PPH_MINIINFO_SECTION Parameter1\n    MiniInfoShowing, // BOOLEAN Parameter1 (Showing)\n    MiniInfoCreateDialog, // PPH_MINIINFO_CREATE_DIALOG Parameter1\n    MaxMiniInfoMessage\n} PH_MINIINFO_SECTION_MESSAGE;\n\ntypedef BOOLEAN (NTAPI *PPH_MINIINFO_SECTION_CALLBACK)(\n    _In_ PPH_MINIINFO_SECTION Section,\n    _In_ PH_MINIINFO_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\n\ntypedef struct _PH_MINIINFO_CREATE_DIALOG\n{\n    BOOLEAN CustomCreate;\n\n    // Parameters for default create\n    PVOID Instance;\n    PWSTR Template;\n    DLGPROC DialogProc;\n    PVOID Parameter;\n} PH_MINIINFO_CREATE_DIALOG, *PPH_MINIINFO_CREATE_DIALOG;\n\n#define PH_MINIINFO_SECTION_NO_UPPER_MARGINS 0x1\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_MINIINFO_SECTION\n{\n    // Public\n\n    // Initialization\n    PH_STRINGREF Name;\n    ULONG Flags;\n    PPH_MINIINFO_SECTION_CALLBACK Callback;\n    PVOID Context;\n    PVOID Reserved1[3];\n\n    PPH_MINIINFO_PARAMETERS Parameters;\n    PVOID Reserved2[3];\n// end_phapppub\n\n    // Private\n\n    ULONG SpareFlag;\n\n    HWND DialogHandle;\n    PPH_STRING Text;\n// begin_phapppub\n} PH_MINIINFO_SECTION, *PPH_MINIINFO_SECTION;\n// end_phapppub\n\ntypedef enum _PH_MINIINFO_PIN_TYPE\n{\n    MiniInfoManualPinType, // User pin\n    MiniInfoIconPinType, // Notification icon\n    MiniInfoActivePinType, // Window is active\n    MiniInfoHoverPinType, // Cursor is over mini info window\n    MiniInfoChildControlPinType, // Interacting with child control\n    MaxMiniInfoPinType\n} PH_MINIINFO_PIN_TYPE;\n\n#define PH_MINIINFO_ACTIVATE_WINDOW 0x1\n#define PH_MINIINFO_LOAD_POSITION 0x2\n#define PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED 0x4\n\nVOID PhPinMiniInformation(\n    _In_ PH_MINIINFO_PIN_TYPE PinType,\n    _In_ LONG PinCount,\n    _In_opt_ ULONG PinDelayMs,\n    _In_ ULONG Flags,\n    _In_opt_ PCWSTR SectionName,\n    _In_opt_ PPOINT SourcePoint\n    );\n\n// begin_phapppub\n// List section\n\ntypedef enum _PH_MINIINFO_LIST_SECTION_MESSAGE\n{\n    MiListSectionCreate,\n    MiListSectionDestroy,\n    MiListSectionTick,\n    MiListSectionShowing, // BOOLEAN Parameter1 (Showing)\n    MiListSectionDialogCreated, // HWND Parameter1 (DialogHandle)\n    MiListSectionSortProcessList, // PPH_MINIINFO_LIST_SECTION_SORT_LIST Parameter1\n    MiListSectionAssignSortData, // PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA Parameter1\n    MiListSectionSortGroupList, // PPH_MINIINFO_LIST_SECTION_SORT_LIST Parameter1\n    MiListSectionGetTitleText, // PPH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT Parameter1\n    MiListSectionGetUsageText, // PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT Parameter1\n    MiListSectionInitializeContextMenu, // PPH_MINIINFO_LIST_SECTION_MENU_INFORMATION Parameter1\n    MiListSectionHandleContextMenu, // PPH_MINIINFO_LIST_SECTION_MENU_INFORMATION Parameter1\n    MaxMiListSectionMessage\n} PH_MINIINFO_LIST_SECTION_MESSAGE;\n\ntypedef struct _PH_MINIINFO_LIST_SECTION PH_MINIINFO_LIST_SECTION, *PPH_MINIINFO_LIST_SECTION;\n\ntypedef BOOLEAN (NTAPI *PPH_MINIINFO_LIST_SECTION_CALLBACK)(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\n\n// The list section performs the following steps when constructing the list of process groups:\n// 1. MiListSectionSortProcessList is sent in order to sort the process list.\n// 2. A small number of process groups is created from the first few processes in the sorted list (typically high\n//    resource consumers).\n// 3. MiListSectionAssignSortData is sent for each process group so that the user can assign custom sort data to\n//    each process group.\n// 4. MiListSectionSortGroupList is sent in order to ensure that the process groups are correctly sorted by resource\n//    usage.\n// The user also has access to the sort data when handling MiListSectionGetTitleText and MiListSectionGetUsageText.\n\ntypedef struct _PH_MINIINFO_LIST_SECTION_SORT_DATA\n{\n    PH_TREENEW_NODE DoNotModify;\n    ULONGLONG UserData[4];\n} PH_MINIINFO_LIST_SECTION_SORT_DATA, *PPH_MINIINFO_LIST_SECTION_SORT_DATA;\n\ntypedef struct _PH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA\n{\n    PPH_PROCESS_GROUP ProcessGroup;\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData;\n} PH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA, *PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA;\n\ntypedef struct _PH_MINIINFO_LIST_SECTION_SORT_LIST\n{\n    // MiListSectionSortProcessList: List of PPH_PROCESS_NODE\n    // MiListSectionSortGroupList: List of PPH_MINIINFO_LIST_SECTION_SORT_DATA\n    PPH_LIST List;\n} PH_MINIINFO_LIST_SECTION_SORT_LIST, *PPH_MINIINFO_LIST_SECTION_SORT_LIST;\n\ntypedef struct _PH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT\n{\n    PPH_PROCESS_GROUP ProcessGroup;\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData;\n    PPH_STRING Title; // Top line (may already contain a string)\n    PPH_STRING Subtitle; // Bottom line (may already contain a string)\n    COLORREF TitleColor;\n    COLORREF SubtitleColor;\n} PH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT, *PPH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT;\n\ntypedef struct _PH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT\n{\n    PPH_PROCESS_GROUP ProcessGroup;\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData;\n    PPH_STRING Line1; // Top line\n    PPH_STRING Line2; // Bottom line\n    COLORREF Line1Color;\n    COLORREF Line2Color;\n} PH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT, *PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT;\n\ntypedef struct _PH_MINIINFO_LIST_SECTION_MENU_INFORMATION\n{\n    PPH_PROCESS_GROUP ProcessGroup;\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData;\n    PPH_TREENEW_CONTEXT_MENU ContextMenu;\n    PPH_EMENU_ITEM SelectedItem;\n} PH_MINIINFO_LIST_SECTION_MENU_INFORMATION, *PPH_MINIINFO_LIST_SECTION_MENU_INFORMATION;\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_MINIINFO_LIST_SECTION\n{\n    // Public\n\n    PPH_MINIINFO_SECTION Section; // State\n    HWND DialogHandle; // State\n    HWND TreeNewHandle; // State\n    PVOID Context; // Initialization\n    PPH_MINIINFO_LIST_SECTION_CALLBACK Callback; // Initialization\n// end_phapppub\n\n    // Private\n\n    PH_LAYOUT_MANAGER LayoutManager;\n    ULONG RunCount;\n    LONG SuspendUpdate;\n    PPH_LIST ProcessGroupList;\n    PPH_LIST NodeList;\n    HANDLE SelectedRepresentativeProcessId;\n    LARGE_INTEGER SelectedRepresentativeCreateTime;\n// begin_phapppub\n} PH_MINIINFO_LIST_SECTION, *PPH_MINIINFO_LIST_SECTION;\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/miniinfop.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_MINIINFOP_H\n#define PH_MINIINFOP_H\n\n// Constants\n\n#define MIP_TIMER_PIN_FIRST 1\n#define MIP_TIMER_PIN_LAST (MIP_TIMER_PIN_FIRST + MaxMiniInfoPinType - 1)\n\n#define MIP_MSG_FIRST (WM_APP + 150)\n#define MIP_MSG_UPDATE (WM_APP + 150)\n#define MIP_MSG_LAST (WM_APP + 151)\n\n#define MIP_UNPIN_CHILD_CONTROL_DELAY 1000\n#define MIP_UNPIN_HOVER_DELAY 250\n\n#define MIP_REFRESH_AUTOMATICALLY_PINNED 0x1\n#define MIP_REFRESH_AUTOMATICALLY_UNPINNED 0x2\n#define MIP_REFRESH_AUTOMATICALLY_FLAG(Pinned) \\\n    ((Pinned) ? MIP_REFRESH_AUTOMATICALLY_PINNED : MIP_REFRESH_AUTOMATICALLY_UNPINNED)\n\n// Misc.\n\n#define SET_BUTTON_ICON(hwndDlg, Id, Icon) \\\n    SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_ICON, (LPARAM)(Icon))\n\n// Dialog procedure\n\nRTL_ATOM PhMipContainerInitializeWindowClass(\n    VOID\n    );\n\nLRESULT CALLBACK PhMipContainerWndProc(\n    _In_ HWND hWnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhMipMiniInfoDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n// Container event handlers\n\nVOID PhMipContainerOnShowWindow(\n    _In_ BOOLEAN Showing,\n    _In_ ULONG State\n    );\n\nVOID PhMipContainerOnActivate(\n    _In_ ULONG Type,\n    _In_ BOOLEAN Minimized\n    );\n\nVOID PhMipContainerOnSize(\n    VOID\n    );\n\nVOID PhMipContainerOnSizing(\n    _In_ ULONG Edge,\n    _In_ PRECT DragRectangle\n    );\n\nVOID PhMipContainerOnExitSizeMove(\n    VOID\n    );\n\nBOOLEAN PhMipContainerOnEraseBkgnd(\n    _In_ HDC hdc\n    );\n\nVOID PhMipContainerOnTimer(\n    _In_ ULONG Id\n    );\n\n// Child dialog event handlers\n\nVOID PhMipOnInitDialog(\n    VOID\n    );\n\nVOID PhMipOnShowWindow(\n    _In_ BOOLEAN Showing,\n    _In_ ULONG State\n    );\n\nVOID PhMipOnCommand(\n    _In_ ULONG Id,\n    _In_ ULONG Code\n    );\n\n_Success_(return)\nBOOLEAN\nPhMipOnNotify(\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    );\n\n_Success_(return)\nBOOLEAN\nPhMipOnCtlColorXxx(\n    _In_ ULONG Message,\n    _In_ HWND WindowHandle,\n    _In_ HDC hdc,\n    _Out_ HBRUSH *Brush\n    );\n\nBOOLEAN PhMipOnDrawItem(\n    _In_ ULONG_PTR Id,\n    _In_ DRAWITEMSTRUCT *DrawItemStruct\n    );\n\nVOID PhMipOnUserMessage(\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    );\n\n// Framework\n\ntypedef enum _PH_MIP_ADJUST_PIN_RESULT\n{\n    NoAdjustPinResult,\n    ShowAdjustPinResult,\n    HideAdjustPinResult\n} PH_MIP_ADJUST_PIN_RESULT;\n\nBOOLEAN NTAPI PhMipMessageLoopFilter(\n    _In_ PMSG Message,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMipUpdateHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    );\n\nPH_MIP_ADJUST_PIN_RESULT PhMipAdjustPin(\n    _In_ PH_MINIINFO_PIN_TYPE PinType,\n    _In_ LONG PinCount\n    );\n\nVOID PhMipCalculateWindowRectangle(\n    _In_ PPOINT SourcePoint,\n    _Out_ PPH_RECTANGLE WindowRectangle\n    );\n\nVOID PhMipInitializeParameters(\n    VOID\n    );\n\n_Function_class_(PH_MINIINFO_CREATE_SECTION)\nPPH_MINIINFO_SECTION PhMipCreateSection(\n    _In_ PPH_MINIINFO_SECTION Template\n    );\n\nVOID PhMipDestroySection(\n    _In_ PPH_MINIINFO_SECTION Section\n    );\n\n_Function_class_(PH_MINIINFO_FIND_SECTION)\nPPH_MINIINFO_SECTION PhMipFindSection(\n    _In_ PPH_STRINGREF Name\n    );\n\nPPH_MINIINFO_SECTION PhMipCreateInternalSection(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_MINIINFO_SECTION_CALLBACK Callback\n    );\n\nVOID PhMipCreateSectionDialog(\n    _In_ PPH_MINIINFO_SECTION Section\n    );\n\nVOID PhMipChangeSection(\n    _In_ PPH_MINIINFO_SECTION NewSection\n    );\n\nVOID PhMipSetSectionText(\n    _In_ struct _PH_MINIINFO_SECTION *Section,\n    _In_opt_ PPH_STRING Text\n    );\n\nVOID PhMipUpdateSectionText(\n    _In_ PPH_MINIINFO_SECTION Section\n    );\n\nVOID PhMipLayout(\n    VOID\n    );\n\nVOID PhMipBeginChildControlPin(\n    VOID\n    );\n\nVOID PhMipEndChildControlPin(\n    VOID\n    );\n\nVOID PhMipRefresh(\n    VOID\n    );\n\nVOID PhMipToggleRefreshAutomatically(\n    VOID\n    );\n\nVOID PhMipSetPinned(\n    _In_ BOOLEAN Pinned,\n    _In_ BOOLEAN Update\n    );\n\nVOID PhMipShowSectionMenu(\n    VOID\n    );\n\nVOID PhMipShowOptionsMenu(\n    VOID\n    );\n\nLRESULT CALLBACK PhMipSectionControlHookWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n// List-based section\n\n#define MIP_MAX_PROCESS_GROUPS 15\n#define MIP_SINGLE_COLUMN_ID 0\n\n#define MIP_CELL_PADDING 5\n#define MIP_ICON_PADDING 3\n#define MIP_INNER_PADDING 3\n\ntypedef struct _PH_MIP_GROUP_NODE\n{\n    union\n    {\n        PH_TREENEW_NODE Node;\n        PH_MINIINFO_LIST_SECTION_SORT_DATA SortData;\n    };\n    PPH_PROCESS_GROUP ProcessGroup;\n    HANDLE RepresentativeProcessId;\n    LARGE_INTEGER RepresentativeCreateTime;\n    BOOLEAN RepresentativeIsHung;\n    BOOLEAN RepresentativeIsTerminated;\n    PPH_STRING TooltipText;\n} PH_MIP_GROUP_NODE, *PPH_MIP_GROUP_NODE;\n\nPPH_MINIINFO_LIST_SECTION PhMipCreateListSection(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_MINIINFO_LIST_SECTION Template\n    );\n\nPPH_MINIINFO_LIST_SECTION PhMipCreateInternalListSection(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_MINIINFO_LIST_SECTION_CALLBACK Callback\n    );\n\nBOOLEAN PhMipListSectionCallback(\n    _In_ PPH_MINIINFO_SECTION Section,\n    _In_ PH_MINIINFO_SECTION_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    );\n\nINT_PTR CALLBACK PhMipListSectionDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhMipListSectionSortFunction(\n    _In_ PPH_LIST List,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhMipTickListSection(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection\n    );\n\nVOID PhMipClearListSection(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection\n    );\n\nLONG PhMipCalculateRowHeight(\n    _In_ HWND WindowHandle\n    );\n\nPPH_MIP_GROUP_NODE PhMipAddGroupNode(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PPH_PROCESS_GROUP ProcessGroup\n    );\n\nVOID PhMipDestroyGroupNode(\n    _In_ PPH_MIP_GROUP_NODE Node\n    );\n\nBOOLEAN PhMipListSectionTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    );\n\nPPH_STRING PhMipGetGroupNodeTooltip(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PPH_MIP_GROUP_NODE Node\n    );\n\nPPH_MIP_GROUP_NODE PhMipGetSelectedGroupNode(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection\n    );\n\nVOID PhMipShowListSectionContextMenu(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    );\n\nVOID PhMipHandleListSectionCommand(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PPH_PROCESS_GROUP ProcessGroup,\n    _In_ ULONG Id\n    );\n\n// CPU section\n\nBOOLEAN PhMipCpuListSectionCallback(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\n\nint __cdecl PhMipCpuListSectionProcessCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    );\n\nint __cdecl PhMipCpuListSectionNodeCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    );\n\n// Commit charge section\n\nBOOLEAN PhMipCommitListSectionCallback(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\n\nint __cdecl PhMipCommitListSectionProcessCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    );\n\nint __cdecl PhMipCommitListSectionNodeCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    );\n\n// Physical memory section\n\nBOOLEAN PhMipPhysicalListSectionCallback(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\n\nint __cdecl PhMipPhysicalListSectionProcessCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    );\n\nint __cdecl PhMipPhysicalListSectionNodeCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    );\n\n// I/O section\n\nBOOLEAN PhMipIoListSectionCallback(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\n\nint __cdecl PhMipIoListSectionProcessCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    );\n\nint __cdecl PhMipIoListSectionNodeCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/modlist.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_MODLIST_H\n#define PH_MODLIST_H\n\n#include <phuisup.h>\n#include <colmgr.h>\n\n// Columns\n\n#define PHMOTLC_NAME 0\n#define PHMOTLC_BASEADDRESS 1\n#define PHMOTLC_SIZE 2\n#define PHMOTLC_DESCRIPTION 3\n\n#define PHMOTLC_COMPANYNAME 4\n#define PHMOTLC_VERSION 5\n#define PHMOTLC_FILENAME 6\n\n#define PHMOTLC_TYPE 7\n#define PHMOTLC_LOADCOUNT 8\n#define PHMOTLC_VERIFICATIONSTATUS 9\n#define PHMOTLC_VERIFIEDSIGNER 10\n#define PHMOTLC_ASLR 11\n#define PHMOTLC_TIMESTAMP 12\n#define PHMOTLC_CFGUARD 13\n#define PHMOTLC_LOADTIME 14\n#define PHMOTLC_LOADREASON 15\n#define PHMOTLC_FILEMODIFIEDTIME 16\n#define PHMOTLC_FILESIZE 17\n#define PHMOTLC_ENTRYPOINT 18\n#define PHMOTLC_PARENTBASEADDRESS 19\n#define PHMOTLC_CET 20\n#define PHMOTLC_COHERENCY 21\n#define PHMOTLC_TIMELINE 22\n#define PHMOTLC_ORIGINALNAME 23\n#define PHMOTLC_SERVICE 24\n#define PHMOTLC_ENCLAVE_TYPE 25\n#define PHMOTLC_ENCLAVE_BASE_ADDRESS 26\n#define PHMOTLC_ENCLAVE_SIZE 27\n#define PHMOTLC_ARCHITECTURE 28\n\n#define PHMOTLC_MAXIMUM 29\n\n// begin_phapppub\ntypedef struct _PH_MODULE_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PH_SH_STATE ShState;\n\n    PPH_MODULE_ITEM ModuleItem;\n// end_phapppub\n\n    PH_STRINGREF TextCache[PHMOTLC_MAXIMUM];\n\n    ULONG ValidMask;\n\n    PPH_STRING TooltipText;\n\n    PPH_STRING FileNameWin32;\n    PPH_STRING SizeText;\n    WCHAR LoadCountText[PH_INT32_STR_LEN_1];\n    PPH_STRING TimeStampText;\n    PPH_STRING LoadTimeText;\n    PPH_STRING FileModifiedTimeText;\n    PPH_STRING FileSizeText;\n    PPH_STRING ImageCoherencyText;\n    PPH_STRING ServiceText;\n    PPH_STRING EnclaveSizeText;\n\n    struct _PH_MODULE_NODE *Parent;\n    PPH_LIST Children;\n// begin_phapppub\n} PH_MODULE_NODE, *PPH_MODULE_NODE;\n// end_phapppub\n\n#define PH_MODULE_FLAGS_DYNAMIC_OPTION 1\n#define PH_MODULE_FLAGS_MAPPED_OPTION 2\n#define PH_MODULE_FLAGS_STATIC_OPTION 3\n#define PH_MODULE_FLAGS_SIGNED_OPTION 4\n#define PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION 5\n#define PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION 6\n#define PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION 7\n#define PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION 8\n#define PH_MODULE_FLAGS_LOAD_MODULE_OPTION 9\n#define PH_MODULE_FLAGS_MODULE_STRINGS_OPTION 10\n#define PH_MODULE_FLAGS_SYSTEM_OPTION 11\n#define PH_MODULE_FLAGS_HIGHLIGHT_SYSTEM_OPTION 12\n#define PH_MODULE_FLAGS_LOWIMAGECOHERENCY_OPTION 13\n#define PH_MODULE_FLAGS_HIGHLIGHT_LOWIMAGECOHERENCY_OPTION 14\n#define PH_MODULE_FLAGS_IMAGEKNOWNDLL_OPTION 15\n#define PH_MODULE_FLAGS_HIGHLIGHT_IMAGEKNOWNDLL 16\n#define PH_MODULE_FLAGS_ZERO_PAD_ADDRESSES 17\n#define PH_MODULE_FLAGS_SAVE_OPTION 40 // Always last (dmex)\n\ntypedef struct _PH_MODULE_LIST_CONTEXT\n{\n    HWND ParentWindowHandle;\n    HWND TreeNewHandle;\n\n    ULONG TreeNewSortColumn;\n    PH_TN_FILTER_SUPPORT TreeFilterSupport;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PH_CM_MANAGER Cm;\n\n    HANDLE ProcessId;\n    LARGE_INTEGER ProcessCreateTime;\n    BOOLEAN HasServices;\n    BOOLEAN EnableStateHighlighting;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Reserved : 1;\n            ULONG HideDynamicModules : 1;\n            ULONG HideMappedModules : 1;\n            ULONG HideSignedModules : 1;\n            ULONG HideStaticModules : 1;\n            ULONG HighlightUntrustedModules : 1;\n            ULONG HighlightDotNetModules : 1;\n            ULONG HighlightImmersiveModules : 1;\n            ULONG HighlightRelocatedModules : 1;\n            ULONG HideSystemModules : 1;\n            ULONG HighlightSystemModules : 1;\n            ULONG HideLowImageCoherency : 1;\n            ULONG HighlightLowImageCoherency : 1;\n            ULONG HideImageKnownDll : 1;\n            ULONG HighlightImageKnownDll : 1;\n            ULONG ZeroPadAddresses : 1;\n            ULONG Spare : 16;\n        };\n    };\n\n    PPH_HASHTABLE NodeHashtable;\n    PPH_LIST NodeList;\n    PPH_LIST NodeRootList;\n    PPH_POINTER_LIST NodeStateList;\n\n    HFONT BoldFont;\n} PH_MODULE_LIST_CONTEXT, *PPH_MODULE_LIST_CONTEXT;\n\nVOID PhInitializeModuleList(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND TreeNewHandle,\n    _Out_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\nVOID PhDeleteModuleList(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\nVOID PhLoadSettingsModuleList(\n    _Inout_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\nVOID PhSaveSettingsModuleList(\n    _Inout_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\nVOID PhSetOptionsModuleList(\n    _Inout_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ ULONG Options\n    );\n\nPPH_MODULE_NODE PhAddModuleNode(\n    _Inout_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_ITEM ModuleItem,\n    _In_ ULONG RunId\n    );\n\nPPH_MODULE_NODE PhFindModuleNode(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_ITEM ModuleItem\n    );\n\nVOID PhRemoveModuleNode(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_NODE ModuleNode\n    );\n\nVOID PhUpdateModuleNode(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_NODE ModuleNode\n    );\n\nVOID PhInvalidateAllModuleNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\nVOID PhInvalidateAllModuleBaseAddressNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\nVOID PhExpandAllModuleNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ BOOLEAN Expand\n    );\n\nVOID PhTickModuleNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\nPPH_MODULE_ITEM PhGetSelectedModuleItem(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\nVOID PhGetSelectedModuleItems(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _Out_ PPH_MODULE_ITEM **Modules,\n    _Out_ PULONG NumberOfModules\n    );\n\nVOID PhDeselectAllModuleNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\nBOOLEAN PhShouldShowModuleCoherency(\n    _In_ PPH_MODULE_ITEM ModuleItem,\n    _In_ BOOLEAN CheckThreshold\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/modprv.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_MODPRV_H\n#define PH_MODPRV_H\n\nextern PPH_OBJECT_TYPE PhModuleProviderType;\nextern PPH_OBJECT_TYPE PhModuleItemType;\n\n// begin_phapppub\ntypedef struct _PH_MODULE_ITEM\n{\n    PVOID BaseAddress;\n    PVOID ParentBaseAddress;\n    PVOID EntryPoint;\n    ULONG Size;\n    ULONG Flags;\n    ULONG Type;\n    USHORT LoadReason;\n    USHORT LoadCount;\n    PPH_STRING Name;\n    PPH_STRING FileName;\n    PH_IMAGE_VERSION_INFO VersionInfo;\n    ULONG EnclaveType;\n    PVOID EnclaveBaseAddress;\n    SIZE_T EnclaveSize;\n\n    union\n    {\n        BOOLEAN StateFlags;\n        struct\n        {\n            BOOLEAN JustProcessed : 1;\n            BOOLEAN IsFirst : 1;\n            BOOLEAN ImageNotAtBase : 1;\n            BOOLEAN ImageKnownDll : 1;\n            BOOLEAN Spare : 4;\n        };\n    };\n\n    ULONG VerifyResult;\n    PPH_STRING VerifySignerName;\n\n    USHORT ImageMachine;\n    ULONG ImageCHPEVersion;\n    ULONG ImageTimeDateStamp;\n    USHORT ImageCharacteristics;\n    USHORT ImageDllCharacteristics;\n    ULONG ImageDllCharacteristicsEx;\n    ULONG GuardFlags;\n\n    LARGE_INTEGER LoadTime;\n    LARGE_INTEGER FileLastWriteTime;\n    LARGE_INTEGER FileEndOfFile;\n\n    NTSTATUS ImageCoherencyStatus;\n    FLOAT ImageCoherency;\n\n    WCHAR BaseAddressString[PH_PTR_STR_LEN_1];\n    WCHAR ParentBaseAddressString[PH_PTR_STR_LEN_1];\n    WCHAR EntryPointAddressString[PH_PTR_STR_LEN_1];\n    WCHAR EnclaveBaseAddressString[PH_PTR_STR_LEN_1];\n} PH_MODULE_ITEM, *PPH_MODULE_ITEM;\n\ntypedef struct _PH_MODULE_PROVIDER\n{\n    PPH_HASHTABLE ModuleHashtable;\n    PH_FAST_LOCK ModuleHashtableLock;\n    PH_CALLBACK ModuleAddedEvent;\n    PH_CALLBACK ModuleModifiedEvent;\n    PH_CALLBACK ModuleRemovedEvent;\n    PH_CALLBACK UpdatedEvent;\n\n    HANDLE ProcessId;\n    HANDLE ProcessHandle;\n    PPH_STRING ProcessFileName;\n    PPH_STRING PackageFullName;\n    SLIST_HEADER QueryListHead;\n    NTSTATUS RunStatus;\n\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN HaveFirst : 1;\n            BOOLEAN IsHandleValid : 1;\n            BOOLEAN IsSubsystemProcess : 1;\n            BOOLEAN ControlFlowGuardEnabled : 1;\n            BOOLEAN CetEnabled : 1;\n            BOOLEAN CetStrictModeEnabled : 1;\n            BOOLEAN ZeroPadAddresses : 1;\n            BOOLEAN Spare : 1;\n        };\n    };\n    UCHAR ImageCoherencyScanLevel;\n} PH_MODULE_PROVIDER, *PPH_MODULE_PROVIDER;\n// end_phapppub\n\nPPH_MODULE_PROVIDER PhCreateModuleProvider(\n    _In_ HANDLE ProcessId\n    );\n\nPPH_MODULE_ITEM PhCreateModuleItem(\n    VOID\n    );\n\nPPH_MODULE_ITEM PhReferenceModuleItemEx(\n    _In_ PPH_MODULE_PROVIDER ModuleProvider,\n    _In_ PVOID BaseAddress,\n    _In_opt_ PVOID EnclaveBaseAddress,\n    _In_opt_ PPH_STRING FileName\n    );\n\nPPH_MODULE_ITEM PhReferenceModuleItem(\n    _In_ PPH_MODULE_PROVIDER ModuleProvider,\n    _In_ PVOID BaseAddress\n    );\n\nVOID PhDereferenceAllModuleItems(\n    _In_ PPH_MODULE_PROVIDER ModuleProvider\n    );\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhModuleProviderUpdate(\n    _In_ PVOID Object\n    );\n\nPCPH_STRINGREF PhGetModuleTypeName(\n    _In_ ULONG ModuleType\n    );\n\nPCPH_STRINGREF PhGetModuleLoadReasonTypeName(\n    _In_ USHORT LoadReason\n    );\n\nPCPH_STRINGREF PhGetModuleEnclaveTypeName(\n    _In_ ULONG EnclaveType\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/netlist.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_NETLIST_H\n#define PH_NETLIST_H\n\n#include <phuisup.h>\n\n// Columns\n\n#define PHNETLC_PROCESS 0\n#define PHNETLC_PID 1\n#define PHNETLC_LOCALADDRESS 2\n#define PHNETLC_LOCALPORT 3\n#define PHNETLC_REMOTEADDRESS 4\n#define PHNETLC_REMOTEPORT 5\n#define PHNETLC_PROTOCOL 6\n#define PHNETLC_STATE 7\n#define PHNETLC_OWNER 8\n#define PHNETLC_TIMESTAMP 9\n#define PHNETLC_LOCALHOSTNAME 10\n#define PHNETLC_REMOTEHOSTNAME 11\n#define PHNETLC_TIMELINE 12\n#define PHNETLC_HV_SERVICE 13\n#define PHNETLC_MAXIMUM 14\n\n// begin_phapppub\ntypedef struct _PH_NETWORK_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PH_SH_STATE ShState;\n\n    PPH_NETWORK_ITEM NetworkItem;\n\n    PPH_STRING ProcessNameText;\n    PPH_STRING TimeStampText;\n    WCHAR ProcessIdString[PH_INT32_STR_LEN_1];\n// end_phapppub\n\n    PPH_STRING TooltipText;\n\n    ULONG64 UniqueId;\n\n    PH_STRINGREF TextCache[PHNETLC_MAXIMUM];\n// begin_phapppub\n} PH_NETWORK_NODE, *PPH_NETWORK_NODE;\n// end_phapppub\n\nVOID PhNetworkTreeListInitialization(\n    VOID\n    );\n\nVOID PhInitializeNetworkTreeList(\n    _In_ HWND TreeNewHandle\n    );\n\nVOID PhLoadSettingsNetworkTreeList(\n    VOID\n    );\n\nVOID PhSaveSettingsNetworkTreeList(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_TN_FILTER_SUPPORT\nNTAPI\nPhGetFilterSupportNetworkTreeList(\n    VOID\n    );\n// end_phapppub\n\nPPH_NETWORK_NODE PhAddNetworkNode(\n    _In_ PPH_NETWORK_ITEM NetworkItem,\n    _In_ ULONG RunId\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_NETWORK_NODE\nNTAPI\nPhFindNetworkNode(\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    );\n// end_phapppub\n\nVOID PhRemoveNetworkNode(\n    _In_ PPH_NETWORK_NODE NetworkNode\n    );\n\nVOID PhUpdateNetworkNode(\n    _In_ PPH_NETWORK_NODE NetworkNode\n    );\n\nVOID PhTickNetworkNodes(\n    VOID\n    );\n\nPPH_NETWORK_ITEM PhGetSelectedNetworkItem(\n    VOID\n    );\n\nVOID PhGetSelectedNetworkItems(\n    _Out_ PPH_NETWORK_ITEM **NetworkItems,\n    _Out_ PULONG NumberOfNetworkItems\n    );\n\n// begin_phapppub\nVOID PhDeselectAllNetworkNodes(\n    VOID\n    );\n// end_phapppub\n\nBOOLEAN PhSelectAndEnsureVisibleNetworkNode(\n    _In_ PPH_NETWORK_NODE NetworkNode\n    );\n\nVOID PhInvalidateAllNetworkNodes(\n    VOID\n    );\n\nVOID PhInvalidateAllNetworkNodesHostnames(\n    VOID\n    );\n\nVOID PhCopyNetworkList(\n    VOID\n    );\n\nVOID PhWriteNetworkList(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ ULONG Mode\n    );\n\nPPH_LIST PhDuplicateNetworkNodeList(\n    VOID\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/netprv.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_NETPRV_H\n#define PH_NETPRV_H\n\nextern PPH_OBJECT_TYPE PhNetworkItemType;\nextern BOOLEAN PhEnableNetworkProviderResolve;\nextern BOOLEAN PhEnableNetworkBoundConnections;\n\ntypedef enum _PH_NETWORK_PROVIDER_FLAG\n{\n    PH_NETWORK_PROVIDER_FLAG_HOSTNAME = 0x1,\n} PH_NETWORK_PROVIDER_FLAG;\n\nextern ULONG PhNetworkProviderFlagsMask;\n\n// begin_phapppub\n#define PH_NETWORK_OWNER_INFO_SIZE 16\n\ntypedef struct _PH_NETWORK_ITEM\n{\n    ULONG ProtocolType;\n    PH_IP_ENDPOINT LocalEndpoint;\n    PH_IP_ENDPOINT RemoteEndpoint;\n    MIB_TCP_STATE State;\n    HANDLE ProcessId;\n\n    PPH_STRING ProcessName;\n    ULONG_PTR ProcessIconIndex;\n    BOOLEAN ProcessIconValid;\n    PPH_STRING OwnerName;\n\n    volatile LONG JustResolved;\n\n    PPH_STRING LocalAddressString;\n    WCHAR LocalPortString[PH_INT32_STR_LEN_1];\n    PPH_STRING RemoteAddressString;\n    WCHAR RemotePortString[PH_INT32_STR_LEN_1];\n    PPH_STRING LocalHostString;\n    PPH_STRING RemoteHostString;\n    PPH_STRING HvService;\n\n    LARGE_INTEGER CreateTime;\n    ULONG LocalScopeId;\n    ULONG RemoteScopeId;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG UnknownProcess : 1;\n            ULONG SubsystemProcess : 1;\n            ULONG Spare : 27;\n            ULONG InvalidateHostname : 1;\n            ULONG LocalHostnameResolved : 1;\n            ULONG RemoteHostnameResolved : 1;\n        };\n    };\n\n    PPH_PROCESS_ITEM ProcessItem;\n} PH_NETWORK_ITEM, *PPH_NETWORK_ITEM;\n// end_phapppub\n\nBOOLEAN PhNetworkProviderInitialization(\n    VOID\n    );\n\nPPH_NETWORK_ITEM PhCreateNetworkItem(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_NETWORK_ITEM\nNTAPI\nPhReferenceNetworkItem(\n    _In_ ULONG ProtocolType,\n    _In_ PPH_IP_ENDPOINT LocalEndpoint,\n    _In_ PPH_IP_ENDPOINT RemoteEndpoint,\n    _In_ HANDLE ProcessId\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhEnumNetworkItems(\n    _Out_opt_ PPH_NETWORK_ITEM** NetworkItems,\n    _Out_ PULONG NumberOfNetworkItems\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhEnumNetworkItemsByProcessId(\n    _In_opt_ HANDLE ProcessId,\n    _Out_opt_ PPH_NETWORK_ITEM** NetworkItems,\n    _Out_ PULONG NumberOfNetworkItems\n    );\n// end_phapppub\n\nVOID PhFlushNetworkItemResolveCache(\n    VOID\n    );\n\n//PPH_STRING PhGetHostNameFromAddress(\n//    _In_ PPH_IP_ADDRESS Address\n//    );\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhNetworkProviderUpdate(\n    _In_ PVOID Object\n    );\n\n// begin_phapppub\nPHAPPAPI\nPCPH_STRINGREF\nNTAPI\nPhGetProtocolTypeName(\n    _In_ ULONG ProtocolType\n    );\n\nPHAPPAPI\nPCPH_STRINGREF\nNTAPI\nPhGetTcpStateName(\n    _In_ ULONG State\n    );\n// end_phapppub\n\n// iphlpapi imports\n\ntypedef ULONG (WINAPI *_GetExtendedTcpTable)(\n    _Out_writes_bytes_opt_(*pdwSize) PVOID pTcpTable,\n    _Inout_ PULONG pdwSize,\n    _In_ BOOL bOrder,\n    _In_ ULONG ulAf,\n    _In_ TCP_TABLE_CLASS TableClass,\n    _In_ ULONG Reserved\n    );\n\ntypedef ULONG (WINAPI *_GetExtendedUdpTable)(\n    _Out_writes_bytes_opt_(*pdwSize) PVOID pUdpTable,\n    _Inout_ PULONG pdwSize,\n    _In_ BOOL bOrder,\n    _In_ ULONG ulAf,\n    _In_ UDP_TABLE_CLASS TableClass,\n    _In_ ULONG Reserved\n    );\n\n//DECLSPEC_IMPORT ULONG WINAPI InternalGetTcpTableWithOwnerModule(\n//    _Out_ PVOID* Tcp4Table, // PMIB_TCPTABLE_OWNER_MODULE\n//    _In_ PVOID HeapHandle,\n//    _In_opt_ ULONG HeapFlags\n//    );\n//DECLSPEC_IMPORT ULONG WINAPI InternalGetTcp6TableWithOwnerModule(\n//    _Out_ PVOID* Tcp6Table, // PMIB_TCP6TABLE_OWNER_MODULE\n//    _In_ PVOID HeapHandle,\n//    _In_opt_ ULONG HeapFlags\n//    );\n//DECLSPEC_IMPORT ULONG WINAPI InternalGetUdpTableWithOwnerModule(\n//    _Out_ PVOID* Udp4Table, // PMIB_UDPTABLE_OWNER_MODULE\n//    _In_ PVOID HeapHandle,\n//    _In_opt_ ULONG HeapFlags\n//    );\n//DECLSPEC_IMPORT ULONG WINAPI InternalGetUdp6TableWithOwnerModule(\n//    _Out_ PVOID* Udp6Table, // PMIB_UDP6TABLE_OWNER_MODULE\n//    _In_ PVOID HeapHandle,\n//    _In_opt_ ULONG HeapFlags\n//    );\n\ntypedef ULONG (WINAPI *_InternalGetBoundTcpEndpointTable)(\n    _Out_ _When_(return!=0, _Notnull_) PVOID* BoundTcpTable, // PMIB_TCPTABLE2\n    _In_ PVOID HeapHandle,\n    _In_opt_ ULONG HeapFlags\n    );\n\ntypedef ULONG (WINAPI *_InternalGetBoundTcp6EndpointTable)(\n    _Out_ _When_(return!=0, _Notnull_) PVOID* BoundTcpTable, // PMIB_TCP6TABLE2\n    _In_ PVOID HeapHandle,\n    _In_opt_ ULONG HeapFlags\n    );\n\n// netsup\n\nNTSTATUS\nNTAPI\nPhSetTcpEntry(\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/notifico.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_NOTIFICO_H\n#define PH_NOTIFICO_H\n\nextern PPH_LIST PhTrayIconItemList;\n\ntypedef enum _PH_TRAY_ICON_ID\n{\n    PH_TRAY_ICON_ID_NONE,\n    PH_TRAY_ICON_ID_CPU_USAGE,\n    PH_TRAY_ICON_ID_CPU_HISTORY,\n    PH_TRAY_ICON_ID_IO_HISTORY,\n    PH_TRAY_ICON_ID_COMMIT_HISTORY,\n    PH_TRAY_ICON_ID_PHYSICAL_HISTORY,\n    PH_TRAY_ICON_ID_CPU_TEXT,\n    PH_TRAY_ICON_ID_IO_TEXT,\n    PH_TRAY_ICON_ID_COMMIT_TEXT,\n    PH_TRAY_ICON_ID_PHYSICAL_TEXT,\n    PH_TRAY_ICON_ID_PLAIN_ICON,\n    PH_TRAY_ICON_ID_MAXIMUM\n} PH_TRAY_ICON_ID;\n\ntypedef enum _PH_TRAY_ICON_GUID\n{\n    PH_TRAY_ICON_GUID_CPU_USAGE,\n    PH_TRAY_ICON_GUID_CPU_HISTORY,\n    PH_TRAY_ICON_GUID_IO_HISTORY,\n    PH_TRAY_ICON_GUID_COMMIT_HISTORY,\n    PH_TRAY_ICON_GUID_PHYSICAL_HISTORY,\n    PH_TRAY_ICON_GUID_CPU_TEXT,\n    PH_TRAY_ICON_GUID_IO_TEXT,\n    PH_TRAY_ICON_GUID_COMMIT_TEXT,\n    PH_TRAY_ICON_GUID_PHYSICAL_TEXT,\n    PH_TRAY_ICON_GUID_PLAIN_ICON,\n    PH_TRAY_ICON_GUID_MAXIMUM\n} PH_TRAY_ICON_GUID;\n\n#define PH_TRAY_ICON_ID_PLUGIN 0x80\n\n#define PH_ICON_LIMIT 0x80000000\n#define PH_ICON_ALL 0xffffffff\n\n// begin_phapppub\ntypedef struct _PH_NF_ICON PH_NF_ICON, *PPH_NF_ICON;\n\ntypedef _Function_class_(PH_NF_UPDATE_REGISTERED_ICON)\nVOID NTAPI PH_NF_UPDATE_REGISTERED_ICON(\n    _In_ PPH_NF_ICON Icon\n    );\ntypedef PH_NF_UPDATE_REGISTERED_ICON* PPH_NF_UPDATE_REGISTERED_ICON;\n\ntypedef _Function_class_(PH_NF_BEGIN_BITMAP)\nVOID NTAPI PH_NF_BEGIN_BITMAP(\n    _Out_ PULONG Width,\n    _Out_ PULONG Height,\n    _Out_ HBITMAP *Bitmap,\n    _Out_opt_ PVOID *Bits,\n    _Out_ HDC *Hdc,\n    _Out_ HBITMAP *OldBitmap\n    );\ntypedef PH_NF_BEGIN_BITMAP* PPH_NF_BEGIN_BITMAP;\n\ntypedef struct _PH_NF_POINTERS\n{\n    PPH_NF_BEGIN_BITMAP BeginBitmap;\n} PH_NF_POINTERS, *PPH_NF_POINTERS;\n\n#define PH_NF_UPDATE_IS_BITMAP 0x1\n#define PH_NF_UPDATE_DESTROY_RESOURCE 0x2\n\ntypedef _Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID NTAPI PH_NF_ICON_UPDATE_CALLBACK(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_NF_ICON_UPDATE_CALLBACK* PPH_NF_ICON_UPDATE_CALLBACK;\n\ntypedef _Function_class_(PH_NF_ICON_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PH_NF_ICON_MESSAGE_CALLBACK(\n    _In_ PPH_NF_ICON Icon,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_NF_ICON_MESSAGE_CALLBACK* PPH_NF_ICON_MESSAGE_CALLBACK;\n\n// Special messages\n// The message type is stored in LOWORD(LParam), and the message data is in WParam.\n\n#define PH_NF_MSG_SHOWMINIINFOSECTION (WM_APP + 1)\n\ntypedef struct _PH_NF_MSG_SHOWMINIINFOSECTION_DATA\n{\n    PWSTR SectionName; // NULL to leave unchanged\n} PH_NF_MSG_SHOWMINIINFOSECTION_DATA, *PPH_NF_MSG_SHOWMINIINFOSECTION_DATA;\n\n// Structures and internal functions\n\n#define PH_NF_ICON_ENABLED 0x1\n#define PH_NF_ICON_UNAVAILABLE 0x2\n#define PH_NF_ICON_NOSHOW_MINIINFO 0x4\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_PLUGIN PH_PLUGIN, *PPH_PLUGIN;\n\ntypedef struct _PH_NF_ICON\n{\n    // Public\n\n    PPH_PLUGIN Plugin;\n    ULONG SubId;\n    PVOID Context;\n    PPH_NF_POINTERS Pointers;\n// end_phapppub\n\n    // Private\n\n    PCWSTR Text;\n    ULONG Flags;\n    ULONG IconId;\n    GUID IconGuid;\n    PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback;\n    PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback;\n\n    PPH_STRING TextCache;\n// begin_phapppub\n} PH_NF_ICON, *PPH_NF_ICON;\n// end_phapppub\n\nVOID PhNfLoadStage1(\n    VOID\n    );\n\nVOID PhNfLoadStage2(\n    VOID\n    );\n\nVOID PhNfSaveSettings(\n    VOID\n    );\n\nVOID PhNfUninitialization(\n    VOID\n    );\n\nVOID PhNfForwardMessage(\n    _In_ HWND WindowHandle,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    );\n\nVOID PhNfSetVisibleIcon(\n    _In_ PPH_NF_ICON Icon,\n    _In_ BOOLEAN Visible\n    );\n\nBOOLEAN PhNfShowBalloonTip(\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Text,\n    _In_ ULONG Timeout\n    );\n\nHRESULT PhNfShowBalloonTipEx(\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Text,\n    _In_ ULONG Timeout,\n    _In_opt_ PPH_TOAST_CALLBACK ToastCallback,\n    _In_opt_ PVOID Context\n    );\n\nHICON PhNfBitmapToIcon(\n    _In_ HBITMAP Bitmap\n    );\n\nPPH_NF_ICON PhNfRegisterIcon(\n    _In_opt_ PPH_PLUGIN Plugin,\n    _In_ ULONG Id,\n    _In_ GUID Guid,\n    _In_opt_ PVOID Context,\n    _In_ PCWSTR Text,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback,\n    _In_opt_ PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback\n    );\n\nPPH_NF_ICON PhNfGetIconById(\n    _In_ ULONG Id\n    );\n\nPPH_NF_ICON PhNfFindIcon(\n    _In_ PPH_STRINGREF PluginName,\n    _In_ ULONG SubId\n    );\n\nBOOLEAN PhNfIconsEnabled(\n    VOID\n    );\n\nVOID PhNfNotifyMiniInfoPinned(\n    _In_ BOOLEAN Pinned\n    );\n\n// begin_phapppub\n// Public registration data\n\ntypedef struct _PH_NF_ICON_REGISTRATION_DATA\n{\n    PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback;\n    PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback;\n} PH_NF_ICON_REGISTRATION_DATA, *PPH_NF_ICON_REGISTRATION_DATA;\n\nVOID PhDrawTrayIconText(\n    _In_ HDC hdc,\n    _In_ PVOID Bits,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text\n    );\n\nHFONT PhNfGetTrayIconFont(\n    _In_opt_ LONG DpiValue\n    );\n\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/notificop.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_NOTIFICOP_H\n#define PH_NOTIFICOP_H\n\n#define PH_NF_ENABLE_WORKQUEUE 1\n\ntypedef struct _PH_NF_WORKQUEUE_DATA\n{\n    SLIST_ENTRY ListEntry;\n    PPH_NF_ICON Icon;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Add : 1;\n            ULONG Delete : 1;\n            ULONG Update : 1;\n            ULONG ShowBalloon : 1;\n            ULONG Spare : 28;\n        };\n    };\n\n    PPH_STRING BalloonTitle;\n    PPH_STRING BalloonText;\n    ULONG BalloonTimeout;\n} PH_NF_WORKQUEUE_DATA, *PPH_NF_WORKQUEUE_DATA;\n\ntypedef struct _PH_NF_BITMAP\n{\n    BOOLEAN Initialized;\n    HDC Hdc;\n    HBITMAP Bitmap;\n    LPRGBQUAD Bits;\n    LONG Width;\n    LONG Height;\n    LONG TaskbarDpi;\n} PH_NF_BITMAP, *PPH_NF_BITMAP;\n\nHICON PhNfGetApplicationIcon(\n    _In_opt_ LONG DpiValue\n    );\n\nHICON PhNfpGetBlackIcon(\n    VOID\n    );\n\nBOOLEAN PhNfpAddNotifyIcon(\n    _In_ PPH_NF_ICON Icon\n    );\n\nBOOLEAN PhNfpRemoveNotifyIcon(\n    _In_ PPH_NF_ICON Icon\n    );\n\nBOOLEAN PhNfpModifyNotifyIcon(\n    _In_ PPH_NF_ICON Icon,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_STRING Text,\n    _In_opt_ HICON IconHandle\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhNfpTrayIconUpdateThread(\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhNfpProcessesUpdatedHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhNfpUpdateRegisteredIcon(\n    _In_ PPH_NF_ICON Icon\n    );\n\n_Function_class_(PH_NF_BEGIN_BITMAP)\nVOID PhNfpBeginBitmap(\n    _Out_ PULONG Width,\n    _Out_ PULONG Height,\n    _Out_ HBITMAP *Bitmap,\n    _Out_opt_ PVOID *Bits,\n    _Out_ HDC *Hdc,\n    _Out_ HBITMAP *OldBitmap\n    );\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpBeginBitmap2(\n    _Inout_ PPH_NF_BITMAP Context,\n    _Out_ PULONG Width,\n    _Out_ PULONG Height,\n    _Out_ HBITMAP *Bitmap,\n    _Out_opt_ PVOID *Bits,\n    _Out_ HDC *Hdc,\n    _Out_ HBITMAP *OldBitmap\n    );\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCpuHistoryIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpIoHistoryIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCommitHistoryIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpPhysicalHistoryIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCpuUsageIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n\n// Text icons\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCpuUsageTextIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpIoUsageTextIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCommitTextIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpPhysicalUsageTextIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n\n// plain icon\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpPlainIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    );\n\n_Success_(return)\nBOOLEAN PhNfpGetShowMiniInfoSectionData(\n    _In_ ULONG IconIndex,\n    _In_ PPH_NF_ICON RegisteredIcon,\n    _Out_ PPH_NF_MSG_SHOWMINIINFOSECTION_DATA Data\n    );\n\n#define NFP_ICON_CLICK_ACTIVATE_DELAY 140\n#define NFP_ICON_RESTORE_HOVER_DELAY 1000\n\nVOID PhNfpIconClickActivateTimerProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ UINT_PTR idEvent,\n    _In_ ULONG dwTime\n    );\n\nVOID PhNfpDisableHover(\n    VOID\n    );\n\nVOID PhNfpIconRestoreHoverTimerProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ UINT_PTR idEvent,\n    _In_ ULONG dwTime\n    );\n\nVOID PhNfpIconDisablePopupHoverWin11Workaround(\n    VOID\n    );\n\nVOID PhNfpIconShowPopupHoverTimerProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ UINT_PTR idEvent,\n    _In_ ULONG dwTime\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/notiftoast.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2021\n *\n */\n\n#pragma once\n\n#ifndef PH_NOTIFTOAST_H\n#define PH_NOTIFTOAST_H\n\nEXTERN_C_START\n\n_Must_inspect_result_\nHRESULT\nNTAPI\nPhInitializeToastRuntime();\n\nVOID\nNTAPI\nPhUninitializeToastRuntime();\n\n_Must_inspect_result_\nHRESULT\nNTAPI\nPhShowToast(\n    _In_ PCWSTR ApplicationId,\n    _In_ PCWSTR ToastXml,\n    _In_opt_ ULONG TimeoutMilliseconds,\n    _In_opt_ PPH_TOAST_CALLBACK ToastCallback,\n    _In_opt_ PVOID Context\n    );\n\n_Must_inspect_result_\nHRESULT\nNTAPI\nPhShowToastStringRef(\n    _In_ PPH_STRINGREF ApplicationId,\n    _In_ PPH_STRINGREF ToastXml,\n    _In_opt_ ULONG TimeoutMilliseconds,\n    _In_opt_ PPH_TOAST_CALLBACK ToastCallback,\n    _In_opt_ PVOID Context\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/phapp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2024\n *\n */\n\n#ifndef PHAPP_H\n#define PHAPP_H\n\n#if !defined(_PHAPP_)\n#define PHAPPAPI __declspec(dllimport)\n#else\n#define PHAPPAPI __declspec(dllexport)\n#endif\n\n#include <ph.h>\n#include <guisup.h>\n#include <provider.h>\n#include <filestream.h>\n#include <fastlock.h>\n#include <treenew.h>\n#include <graph.h>\n#include <circbuf.h>\n#include <dltmgr.h>\n#include <phnet.h>\n\n#include \"../resource.h\"\n\n#include <phfwddef.h>\n#include <appsup.h>\n#include <searchbox.h>\n\n// main\n\ntypedef struct _PH_STARTUP_PARAMETERS\n{\n    union\n    {\n        struct\n        {\n            ULONG NoSettings : 1;\n            ULONG ShowVisible : 1;\n            ULONG ShowHidden : 1;\n            ULONG NoKph : 1;\n            ULONG Debug : 1;\n            ULONG ShowOptions : 1;\n            ULONG PhSvc : 1;\n            ULONG NoPlugins : 1;\n            ULONG NewInstance : 1;\n            ULONG Elevate : 1;\n            ULONG Silent : 1;\n            ULONG Help : 1;\n            ULONG KphStartupHigh : 1;\n            ULONG KphStartupMax : 1;\n            ULONG Spare : 18;\n        };\n        ULONG Flags;\n    };\n\n    PPH_STRING SettingsFileName;\n    PPH_STRING RunAsServiceMode;\n\n    HWND WindowHandle;\n    POINT Point;\n\n    ULONG SelectPid;\n    ULONG PriorityClass;\n\n    PPH_LIST PluginParameters;\n    PPH_STRING SelectTab;\n    PPH_STRING SysInfo;\n    PH_RELEASE_CHANNEL UpdateChannel;\n} PH_STARTUP_PARAMETERS, *PPH_STARTUP_PARAMETERS;\n\nextern BOOLEAN PhPluginsEnabled;\nextern BOOLEAN PhPortableEnabled;\nextern PPH_STRING PhSettingsFileName;\nextern PH_STARTUP_PARAMETERS PhStartupParameters;\n\nextern PH_PROVIDER_THREAD PhPrimaryProviderThread;\nextern PH_PROVIDER_THREAD PhSecondaryProviderThread;\nextern PH_PROVIDER_THREAD PhTertiaryProviderThread;\n\nextern RTL_ATOM PhTreeWindowAtom;\nextern RTL_ATOM PhGraphWindowAtom;\nextern RTL_ATOM PhHexEditWindowAtom;\nextern RTL_ATOM PhColorBoxWindowAtom;\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhRegisterDialog(\n    _In_ HWND DialogWindowHandle\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhUnregisterDialog(\n    _In_ HWND DialogWindowHandle\n    );\n\ntypedef BOOLEAN (NTAPI *PPH_MESSAGE_LOOP_FILTER)(\n    _In_ PMSG Message,\n    _In_ PVOID Context\n    );\n\ntypedef struct _PH_MESSAGE_LOOP_FILTER_ENTRY\n{\n    PPH_MESSAGE_LOOP_FILTER Filter;\n    PVOID Context;\n} PH_MESSAGE_LOOP_FILTER_ENTRY, *PPH_MESSAGE_LOOP_FILTER_ENTRY;\n\nPHAPPAPI\nPPH_MESSAGE_LOOP_FILTER_ENTRY\nNTAPI\nPhRegisterMessageLoopFilter(\n    _In_ PPH_MESSAGE_LOOP_FILTER Filter,\n    _In_opt_ PVOID Context\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhUnregisterMessageLoopFilter(\n    _In_ PPH_MESSAGE_LOOP_FILTER_ENTRY FilterEntry\n    );\n// end_phapppub\n\n// plugin\n\nextern PH_AVL_TREE PhPluginsByName;\n\nVOID PhInitializeCallbacks(\n    VOID\n    );\n\nBOOLEAN PhIsPluginDisabled(\n    _In_ PCPH_STRINGREF BaseName\n    );\n\nVOID PhSetPluginDisabled(\n    _In_ PCPH_STRINGREF BaseName,\n    _In_ BOOLEAN Disable\n    );\n\nVOID PhLoadPlugins(\n    VOID\n    );\n\nVOID PhUnloadPlugins(\n    _In_ BOOLEAN SessionEnding\n    );\n\n// log\n\n#define PH_LOG_ENTRY_PROCESS_FIRST 1\n#define PH_LOG_ENTRY_PROCESS_CREATE 1\n#define PH_LOG_ENTRY_PROCESS_DELETE 2\n#define PH_LOG_ENTRY_PROCESS_LAST 2\n\n#define PH_LOG_ENTRY_SERVICE_FIRST 3\n#define PH_LOG_ENTRY_SERVICE_CREATE 3\n#define PH_LOG_ENTRY_SERVICE_DELETE 4\n#define PH_LOG_ENTRY_SERVICE_START 5\n#define PH_LOG_ENTRY_SERVICE_STOP 6\n#define PH_LOG_ENTRY_SERVICE_CONTINUE 7\n#define PH_LOG_ENTRY_SERVICE_PAUSE 8\n#define PH_LOG_ENTRY_SERVICE_MODIFIED 9\n#define PH_LOG_ENTRY_SERVICE_LAST 10\n\n#define PH_LOG_ENTRY_DEVICE_REMOVED 11\n#define PH_LOG_ENTRY_DEVICE_ARRIVED 12\n\n#define PH_LOG_ENTRY_MESSAGE 100 // phapppub\n\ntypedef struct _PH_LOG_ENTRY *PPH_LOG_ENTRY; // phapppub\n\ntypedef struct _PH_LOG_ENTRY\n{\n    UCHAR Type;\n    UCHAR Reserved1;\n    USHORT Flags;\n    LARGE_INTEGER Time;\n    union\n    {\n        struct\n        {\n            HANDLE ProcessId;\n            PPH_STRING Name;\n            HANDLE ParentProcessId;\n            PPH_STRING ParentName;\n            NTSTATUS ExitStatus;\n        } Process;\n        struct\n        {\n            PPH_STRING Name;\n            PPH_STRING DisplayName;\n        } Service;\n        struct\n        {\n            PPH_STRING Classification;\n            PPH_STRING Name;\n        } Device;\n        PPH_STRING Message;\n    };\n    UCHAR Buffer[1];\n} PH_LOG_ENTRY, *PPH_LOG_ENTRY;\n\nextern PH_CIRCULAR_BUFFER_PVOID PhLogBuffer;\n\nVOID PhLogInitialization(\n    VOID\n    );\n\nVOID PhClearLogEntries(\n    VOID\n    );\n\nVOID PhLogProcessEntry(\n    _In_ UCHAR Type,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_STRING Name,\n    _In_opt_ HANDLE ParentProcessId,\n    _In_opt_ PPH_STRING ParentName,\n    _In_opt_ ULONG Status\n    );\n\nVOID PhLogServiceEntry(\n    _In_ UCHAR Type,\n    _In_ PPH_STRING Name,\n    _In_ PPH_STRING DisplayName\n    );\n\nVOID PhLogDeviceEntry(\n    _In_ UCHAR Type,\n    _In_ PPH_STRING Classification,\n    _In_ PPH_STRING Name\n    );\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhLogMessageEntry(\n    _In_ UCHAR Type,\n    _In_ PPH_STRING Message\n    );\n\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhFormatLogEntry(\n    _In_ PPH_LOG_ENTRY Entry\n    );\n\nPHAPPAPI\nPCPH_STRINGREF\nNTAPI\nPhFormatLogType(\n    _In_ PPH_LOG_ENTRY Entry\n    );\n// end_phapppub\n\n// dbgcon\n\nVOID PhShowDebugConsole(\n    VOID\n    );\n\n// itemtips\n\nPPH_STRING PhGetProcessTooltipText(\n    _In_ PPH_PROCESS_ITEM Process,\n    _Out_opt_ PULONG64 ValidToTickCount\n    );\n\nPPH_STRING PhGetServiceTooltipText(\n    _In_ PPH_SERVICE_ITEM Service\n    );\n\n// cmdmode\n\nNTSTATUS PhCommandModeStart(\n    VOID\n    );\n\n// anawait\n\nVOID PhUiAnalyzeWaitThread(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId,\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider\n    );\n\n// mdump\n\nVOID PhUiCreateDumpFileProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ MINIDUMP_TYPE DumpType\n    );\n\nVOID PhShowCreateDumpFileProcessDialog(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\n// about\n\nVOID PhShowAboutDialog(\n    _In_ HWND ParentWindowHandle\n    );\n\nPPH_STRING PhGetDiagnosticsString(\n    VOID\n    );\n\nPPH_STRING PhGetApplicationVersionString(\n    _In_ BOOLEAN LinkToCommit\n    );\n\n// affinity\n\nVOID PhShowProcessAffinityDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_opt_ PPH_PROCESS_ITEM ProcessItem,\n    _In_opt_ PPH_THREAD_ITEM ThreadItem\n    );\n\n// begin_phapppub\n_Success_(return)\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhShowProcessAffinityDialog2(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _Out_ PKAFFINITY NewAffinityMask\n    );\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhSetProcessItemAffinityMask(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ KAFFINITY AffinityMask\n    );\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhSetProcessItemPagePriority(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG PagePriority\n    );\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhSetProcessItemIoPriority(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ IO_PRIORITY_HINT IoPriority\n    );\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhSetProcessItemPriority(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ UCHAR PriorityClass\n    );\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhSetProcessItemPriorityBoost(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ BOOLEAN PriorityBoost\n    );\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhSetProcessItemThrottlingState(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ BOOLEAN ClearThrottlingState\n    );\n// end_phapppub\n\nPHAPPAPI\nVOID\nNTAPI\nPhShowThreadAffinityDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads\n    );\n\n// chcol\n\n#define PH_CONTROL_TYPE_TREE_NEW 1\n\nVOID PhShowChooseColumnsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND ControlHandle,\n    _In_ ULONG Type\n    );\n\n// chdlg\n\n// begin_phapppub\n#define PH_CHOICE_DIALOG_SAVED_CHOICES 10\n\n#define PH_CHOICE_DIALOG_CHOICE 0x0\n#define PH_CHOICE_DIALOG_USER_CHOICE 0x1\n#define PH_CHOICE_DIALOG_PASSWORD 0x2\n#define PH_CHOICE_DIALOG_TYPE_MASK 0x3\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhaChoiceDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Message,\n    _In_opt_ PCWSTR *Choices,\n    _In_opt_ ULONG NumberOfChoices,\n    _In_opt_ PCWSTR Option,\n    _In_ ULONG Flags,\n    _Inout_ PPH_STRING *SelectedChoice,\n    _Inout_opt_ PBOOLEAN SelectedOption,\n    _In_opt_ PCWSTR SavedChoicesSettingName\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhChoiceDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Message,\n    _In_opt_ PCWSTR* Choices,\n    _In_opt_ ULONG NumberOfChoices,\n    _In_opt_ PCWSTR Option,\n    _In_ ULONG Flags,\n    _Inout_ PPH_STRING* SelectedChoice,\n    _Inout_opt_ PBOOLEAN SelectedOption,\n    _In_opt_ PCWSTR SavedChoicesSettingName\n    );\n// end_phapppub\n\n// chproc\n\n// begin_phapppub\n_Success_(return)\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhShowChooseProcessDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR Message,\n    _Out_ PHANDLE ProcessId\n    );\n// end_phapppub\n\n// findobj\n\nVOID PhShowFindObjectsDialog(\n    _In_ HWND ParentWindowHandle\n    );\n\n// gdihndl\n\nVOID PhShowGdiHandlesDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\n// heapinfo\n\nVOID PhShowProcessHeapsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\nVOID PhShowProcessLocksDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\n// hidnproc\n\nVOID PhShowZombieProcessesDialog(\n    VOID\n    );\n\n// hndlprp\n\nVOID PhShowHandleProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_HANDLE_ITEM HandleItem\n    );\n\n// hndlstat\n\nVOID PhShowHandleStatisticsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ HANDLE ProcessId\n    );\n\n// infodlg\n\nVOID PhShowInformationDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR String,\n    _Reserved_ ULONG Flags\n    );\n\n// jobprp\n\nVOID PhShowJobProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context,\n    _In_opt_ PCWSTR Title\n    );\n\nHPROPSHEETPAGE PhCreateJobPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context,\n    _In_opt_ DLGPROC HookProc\n    );\n\n// kdump\n\ntypedef union _PH_LIVE_DUMP_OPTIONS\n{\n    BOOLEAN Flags;\n    struct\n    {\n        BOOLEAN CompressMemoryPages : 1;\n        BOOLEAN IncludeUserSpaceMemory : 1;\n        BOOLEAN IncludeHypervisorPages : 1;\n        BOOLEAN OnlyKernelThreadStacks : 1;\n        BOOLEAN UseDumpStorageStack : 1;\n        BOOLEAN IncludeNonEssentialHypervisorPages : 1;\n        BOOLEAN Spare : 2;\n    };\n} PH_LIVE_DUMP_OPTIONS, *PPH_LIVE_DUMP_OPTIONS;\n\nVOID PhUiCreateLiveDump(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_LIVE_DUMP_OPTIONS Options\n    );\n\nVOID PhShowLiveDumpDialog(\n    _In_ HWND ParentWindowHandle\n    );\n\n// ksyscall\n\nPPH_STRING PhGetSystemCallNumberName(\n    _In_ USHORT SystemCallNumber\n    );\n\n// logwnd\n\nVOID PhShowLogDialog(\n    VOID\n    );\n\n// memedit\n\n#define PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION 0x1\n\nVOID PhShowMemoryEditorDialog(\n    _In_ HWND OwnerWindow,\n    _In_ HANDLE ProcessId,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize,\n    _In_ ULONG SelectOffset,\n    _In_ ULONG SelectLength,\n    _In_opt_ PPH_STRING Title,\n    _In_ ULONG Flags\n    );\n\n// memlists\n\nVOID PhShowMemoryListsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_opt_ VOID (NTAPI *RegisterDialog)(HWND),\n    _In_opt_ VOID (NTAPI *UnregisterDialog)(HWND)\n    );\n\n// memprot\n\nVOID PhShowMemoryProtectDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_MEMORY_ITEM MemoryItem\n    );\n\n// memrslt\n\nVOID PhShowMemoryResultsDialog(\n    _In_ HANDLE ProcessId,\n    _In_ PPH_LIST Results\n    );\n\n// memsrch\n\nVOID PhShowMemoryStringDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\n// msmsrcht\n\nVOID PhShowMemoryStringTreeDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\n// memmod\n\nVOID PhShowImagePageModifiedDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\n// mtgndlg\n\nVOID PhShowProcessMitigationPolicyDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ HANDLE ProcessId\n    );\n\n// ntobjprp\n\nHPROPSHEETPAGE PhCreateEventPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    );\n\nHPROPSHEETPAGE PhCreateEventPairPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    );\n\nHPROPSHEETPAGE PhCreateSemaphorePage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    );\n\nHPROPSHEETPAGE PhCreateTimerPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    );\n\nHPROPSHEETPAGE PhCreateAfdSocketPage(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE HandleValue\n    );\n\nHPROPSHEETPAGE PhCreateMappingsPage(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE SectionHandle\n    );\n\n// options\n\nVOID PhShowOptionsDialog(\n    _In_ HWND ParentWindowHandle\n    );\n\n// pagfiles\n\nVOID PhShowPagefilesDialog(\n    _In_ HWND ParentWindowHandle\n    );\n\n// plugman\n\nINT_PTR CALLBACK PhPluginsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n// procrec\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhShowProcessRecordDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_RECORD Record\n    );\n// end_phapppub\n\n// runas\n\ntypedef struct _PH_RUNAS_SERVICE_PARAMETERS\n{\n    ULONG ProcessId;\n    PCWSTR UserName;\n    PCWSTR Password;\n    ULONG LogonType;\n    ULONG SessionId;\n    PCWSTR CurrentDirectory;\n    PCWSTR CommandLine;\n    PCWSTR FileName;\n    PCWSTR DesktopName;\n    BOOLEAN UseLinkedToken;\n    PCWSTR ServiceName;\n    BOOLEAN CreateSuspendedProcess;\n    HWND WindowHandle;\n    BOOLEAN CreateUIAccessProcess;\n} PH_RUNAS_SERVICE_PARAMETERS, *PPH_RUNAS_SERVICE_PARAMETERS;\n\nVOID PhShowRunAsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_opt_ HANDLE ProcessId\n    );\n\nVOID PhShowRunAsPackageDialog(\n    _In_ HWND ParentWindowHandle\n    );\n\n// begin_phapppub\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShowRunFileDialog(\n    _In_ HWND ParentWindowHandle\n    );\n// end_phapppub\n\nNTSTATUS PhExecuteRunAsCommand(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    );\n\n// begin_phapppub\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhExecuteRunAsCommand2(\n    _In_ HWND hWnd,\n    _In_ PCWSTR Program,\n    _In_opt_ PCWSTR UserName,\n    _In_opt_ PCWSTR Password,\n    _In_opt_ ULONG LogonType,\n    _In_opt_ HANDLE ProcessIdWithToken,\n    _In_opt_ ULONG SessionId,\n    _In_opt_ PCWSTR DesktopName,\n    _In_ BOOLEAN UseLinkedToken\n    );\n// end_phapppub\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhExecuteRunAsCommand3(\n    _In_ HWND hWnd,\n    _In_ PCWSTR Program,\n    _In_opt_ PCWSTR UserName,\n    _In_opt_ PCWSTR Password,\n    _In_opt_ ULONG LogonType,\n    _In_opt_ HANDLE ProcessIdWithToken,\n    _In_opt_ ULONG SessionId,\n    _In_opt_ PCWSTR DesktopName,\n    _In_ BOOLEAN UseLinkedToken,\n    _In_ BOOLEAN CreateSuspendedProcess,\n    _In_ BOOLEAN CreateUIAccessProcess\n    );\n\nNTSTATUS PhRunAsServiceStart(\n    _In_ PPH_STRING ServiceName\n    );\n\nNTSTATUS PhInvokeRunAsService(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    );\n\n// searchbox\n\n// begin_phapppub\ntypedef _Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PH_SEARCHCONTROL_CALLBACK(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_SEARCHCONTROL_CALLBACK* PPH_SEARCHCONTROL_CALLBACK;\n\nPHAPPAPI\nVOID\nNTAPI\nPhCreateSearchControl(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND SearchWindowHandle,\n    _In_opt_ PCWSTR BannerText,\n    _In_ PPH_SEARCHCONTROL_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n// end_phapppub\n\n// sessmsg\n\nVOID PhShowSessionSendMessageDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ ULONG SessionId\n    );\n\n// sessprp\n\nVOID PhShowSessionProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ ULONG SessionId\n    );\n\n// sessshad\n\nVOID PhShowSessionShadowDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ ULONG SessionId\n    );\n\n// srvcr\n\nVOID PhShowCreateServiceDialog(\n    _In_ HWND ParentWindowHandle\n    );\n\n// srvctl\n\n// begin_phapppub\n#define WM_PH_SET_LIST_VIEW_SETTINGS (WM_APP + 701)\n\nPHAPPAPI\nHWND\nNTAPI\nPhCreateServiceListControl(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_SERVICE_ITEM *Services,\n    _In_ ULONG NumberOfServices\n    );\n// end_phapppub\n\n// srvprp\n\nVOID PhShowServiceProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    );\n\n// thrdstk\n\nVOID PhShowThreadStackDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId,\n    _In_ PPH_THREAD_PROVIDER ThreadProvider\n    );\n\n// thrdstks\n\nVOID PhShowThreadStacksDialog(\n    _In_ HWND ParentWindowHandle\n    );\n\n// userslist\n\nVOID PhShowUserListDialog(\n    _In_ HWND ParentWindowHandle\n    );\n\n// tokprp\n\nPPH_STRING PhGetGroupAttributesString(\n    _In_ ULONG Attributes,\n    _In_ BOOLEAN Restricted\n    );\n\nPCWSTR PhGetPrivilegeAttributesString(\n    _In_ ULONG Attributes\n    );\n\n_Success_(return)\nBOOLEAN PhGetElevationTypeString(\n    _In_ BOOLEAN IsElevated,\n    _In_ TOKEN_ELEVATION_TYPE ElevationType,\n    _Out_ PCPH_STRINGREF* ElevationTypeString\n    );\n\nVOID PhShowTokenProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_ HANDLE ProcessId,\n    _In_ PVOID Context,\n    _In_opt_ PCWSTR Title\n    );\n\nHPROPSHEETPAGE PhCreateTokenPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_ HANDLE ProcessId,\n    _In_opt_ PVOID Context,\n    _In_opt_ DLGPROC HookProc\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/phappres.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2016-2024\n *\n */\n\n#ifndef PH_PHAPPRES_H\n#define PH_PHAPPRES_H\n\n#ifndef PHAPP_VERSION_MAJOR\n#define PHAPP_VERSION_MAJOR 0\n#endif\n\n#ifndef PHAPP_VERSION_MINOR\n#define PHAPP_VERSION_MINOR 0\n#endif\n\n#ifndef PHAPP_VERSION_BUILD\n#define PHAPP_VERSION_BUILD 0\n#endif\n\n#ifndef PHAPP_VERSION_REVISION\n#define PHAPP_VERSION_REVISION 0\n#endif\n\n#ifndef PHAPP_VERSION_COMMITHASH\n#define PHAPP_VERSION_COMMITHASH \"0000000\"\n#endif\n\n#define DO_MAKE_STR(x) #x\n#define MAKE_STR(x)    DO_MAKE_STR(x)\n\n#define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) \".\" MAKE_STR(PHAPP_VERSION_MINOR) \".\" MAKE_STR(PHAPP_VERSION_BUILD) \".\" MAKE_STR(PHAPP_VERSION_REVISION)\n#define PHAPP_VERSION_NUMBER PHAPP_VERSION_MAJOR,PHAPP_VERSION_MINOR,PHAPP_VERSION_BUILD,PHAPP_VERSION_REVISION\n#define PHAPP_VERSION_COMMIT MAKE_STR(PHAPP_VERSION_COMMITHASH)\n\n#endif // PHAPPRES_H\n"
  },
  {
    "path": "SystemInformer/include/phfwddef.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2022\n *\n */\n\n#ifndef PH_PHFWDDEF_H\n#define PH_PHFWDDEF_H\n\n// begin_phapppub\n// phlib\n\ntypedef struct _PH_SYMBOL_PROVIDER *PPH_SYMBOL_PROVIDER;\n\n// Providers\n\ntypedef struct _PH_PROCESS_ITEM *PPH_PROCESS_ITEM;\ntypedef struct _PH_PROCESS_RECORD *PPH_PROCESS_RECORD;\ntypedef struct _PH_SERVICE_ITEM *PPH_SERVICE_ITEM;\ntypedef struct _PH_NETWORK_ITEM *PPH_NETWORK_ITEM;\ntypedef struct _PH_MODULE_ITEM *PPH_MODULE_ITEM;\ntypedef struct _PH_MODULE_PROVIDER *PPH_MODULE_PROVIDER;\ntypedef struct _PH_THREAD_ITEM *PPH_THREAD_ITEM;\ntypedef struct _PH_THREAD_PROVIDER *PPH_THREAD_PROVIDER;\ntypedef struct _PH_HANDLE_ITEM *PPH_HANDLE_ITEM;\ntypedef struct _PH_HANDLE_PROVIDER *PPH_HANDLE_PROVIDER;\ntypedef struct _PH_MEMORY_ITEM *PPH_MEMORY_ITEM;\ntypedef struct _PH_MEMORY_ITEM_LIST *PPH_MEMORY_ITEM_LIST;\n\n// uimodels\n\ntypedef struct _PH_PROCESS_NODE *PPH_PROCESS_NODE;\ntypedef struct _PH_SERVICE_NODE *PPH_SERVICE_NODE;\ntypedef struct _PH_NETWORK_NODE *PPH_NETWORK_NODE;\ntypedef struct _PH_MODULE_NODE *PPH_MODULE_NODE;\ntypedef struct _PH_THREAD_NODE *PPH_THREAD_NODE;\ntypedef struct _PH_HANDLE_NODE *PPH_HANDLE_NODE;\ntypedef struct _PH_MEMORY_NODE *PPH_MEMORY_NODE;\n\n// procprv\n\ntypedef struct _PH_PROCESS_PROPCONTEXT *PPH_PROCESS_PROPCONTEXT;\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/phplug.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2024\n *\n */\n\n#ifndef PH_PHPLUG_H\n#define PH_PHPLUG_H\n\n#include <extmgr.h>\n#include <sysinfo.h>\n#include <miniinfo.h>\n\n// begin_phapppub\n// Callbacks\n\ntypedef enum _PH_GENERAL_CALLBACK\n{\n    GeneralCallbackMainWindowShowing = 0, // INT ShowCommand [main thread]\n    GeneralCallbackProcessesUpdated = 1, // ULONG RunId [main thread]\n    GeneralCallbackGetProcessHighlightingColor = 2, // PPH_PLUGIN_GET_HIGHLIGHTING_COLOR Data [main thread]\n    GeneralCallbackGetProcessTooltipText = 3, // PPH_PLUGIN_GET_TOOLTIP_TEXT Data [main thread]\n    GeneralCallbackProcessPropertiesInitializing = 4, // PPH_PLUGIN_PROCESS_PROPCONTEXT Data [properties thread]\n    GeneralCallbackMainMenuInitializing = 5, // PPH_PLUGIN_MENU_INFORMATION Data [main thread]\n    GeneralCallbackNotifyEvent = 6, // PPH_PLUGIN_NOTIFY_EVENT Data [main thread]\n    GeneralCallbackServicePropertiesInitializing = 7, // PPH_PLUGIN_OBJECT_PROPERTIES Data [properties thread]\n    GeneralCallbackHandlePropertiesInitializing = 8, // PPH_PLUGIN_OBJECT_PROPERTIES Data [properties thread]\n    GeneralCallbackProcessMenuInitializing = 9, // PPH_PLUGIN_MENU_INFORMATION Data [main thread]\n    GeneralCallbackServiceMenuInitializing = 10, // PPH_PLUGIN_MENU_INFORMATION Data [main thread]\n    GeneralCallbackNetworkMenuInitializing = 11, // PPH_PLUGIN_MENU_INFORMATION Data [main thread]\n    GeneralCallbackIconMenuInitializing = 12, // PPH_PLUGIN_MENU_INFORMATION Data [main thread]\n    GeneralCallbackThreadMenuInitializing = 13, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread]\n    GeneralCallbackModuleMenuInitializing = 14, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread]\n    GeneralCallbackMemoryMenuInitializing = 15, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread]\n    GeneralCallbackHandleMenuInitializing = 16, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread]\n    GeneralCallbackProcessTreeNewInitializing = 17, // PPH_PLUGIN_TREENEW_INFORMATION Data [main thread]\n    GeneralCallbackServiceTreeNewInitializing = 18, // PPH_PLUGIN_TREENEW_INFORMATION Data [main thread]\n    GeneralCallbackNetworkTreeNewInitializing = 19, // PPH_PLUGIN_TREENEW_INFORMATION Data [main thread]\n    GeneralCallbackModuleTreeNewInitializing = 20, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread]\n    GeneralCallbackModuleTreeNewUninitializing = 21, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread]\n    GeneralCallbackThreadTreeNewInitializing = 22, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread]\n    GeneralCallbackThreadTreeNewUninitializing = 23, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread]\n    GeneralCallbackHandleTreeNewInitializing = 24, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread]\n    GeneralCallbackHandleTreeNewUninitializing = 25, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread]\n    GeneralCallbackThreadStackControl = 26, // PPH_PLUGIN_THREAD_STACK_CONTROL Data [properties thread]\n    GeneralCallbackSystemInformationInitializing = 27, // PPH_PLUGIN_SYSINFO_POINTERS Data [system information thread]\n    GeneralCallbackMainWindowTabChanged = 28, // INT NewIndex [main thread]\n    GeneralCallbackMemoryTreeNewInitializing = 29, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread]\n    GeneralCallbackMemoryTreeNewUninitializing = 30, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread]\n    GeneralCallbackMemoryItemListControl = 31, // PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL Data [properties thread]\n    GeneralCallbackMiniInformationInitializing = 32, // PPH_PLUGIN_MINIINFO_POINTERS Data [main thread]\n    GeneralCallbackMiListSectionMenuInitializing = 33, // PPH_PLUGIN_MENU_INFORMATION Data [main thread]\n    GeneralCallbackOptionsWindowInitializing = 34, // PH_PLUGIN_OPTIONS_POINTERS Data [main thread]\n    GeneralCallbackHandlePropertiesWindowInitialized = 35, // PPH_PLUGIN_HANDLE_PROPERTIES_WINDOW_CONTEXT Data [properties thread]\n    GeneralCallbackHandlePropertiesWindowUninitializing = 36, // PPH_PLUGIN_HANDLE_PROPERTIES_WINDOW_CONTEXT Data [properties thread]\n\n    GeneralCallbackProcessProviderAddedEvent, // [process provider thread]\n    GeneralCallbackProcessProviderModifiedEvent, // [process provider thread]\n    GeneralCallbackProcessProviderRemovedEvent, // [process provider thread]\n    GeneralCallbackProcessProviderUpdatedEvent, // PPH_PROCESS_PROVIDER_UPDATED_EVENT [process provider thread]\n    GeneralCallbackServiceProviderAddedEvent, // [service provider thread]\n    GeneralCallbackServiceProviderModifiedEvent, // [service provider thread]\n    GeneralCallbackServiceProviderRemovedEvent, // [service provider thread]\n    GeneralCallbackServiceProviderUpdatedEvent, // [service provider thread]\n    GeneralCallbackNetworkProviderAddedEvent, // [network provider thread]\n    GeneralCallbackNetworkProviderModifiedEvent, // [network provider thread]\n    GeneralCallbackNetworkProviderRemovedEvent, // [network provider thread]\n    GeneralCallbackNetworkProviderUpdatedEvent, // [network provider thread]\n\n    GeneralCallbackLoggedEvent, // [multiple provider threads]\n\n    GeneralCallbackDeviceNotificationEvent, // [device provider thread]\n\n    GeneralCallbackTrayIconsInitializing, // [work queue thread]\n    GeneralCallbackTrayIconsUpdatedEvent,\n\n    GeneralCallbackWindowNotifyEvent,\n    GeneralCallbackProcessStatsNotifyEvent,\n    GeneralCallbackSettingsUpdated,\n    GeneralCallbackDangerousProcess,\n    GeneralCallbackUpdateAutomatically,\n\n    GeneralCallbackMaximum\n} PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK;\n\ntypedef enum _PH_PLUGIN_CALLBACK\n{\n    PluginCallbackLoad = 0, // PPH_LIST Parameters [main thread] // list of strings, might be NULL\n    PluginCallbackUnload = 1, // BOOLEAN SessionEnding [main thread]\n    PluginCallbackShowOptions = 2, // HWND ParentWindowHandle [main thread]\n    PluginCallbackMenuItem = 3, // PPH_PLUGIN_MENU_ITEM MenuItem [main/properties thread]\n    PluginCallbackTreeNewMessage = 4, // PPH_PLUGIN_TREENEW_MESSAGE Message [main/properties thread]\n    PluginCallbackPhSvcRequest = 5, // PPH_PLUGIN_PHSVC_REQUEST Message [phsvc thread]\n    PluginCallbackMenuHook = 6, // PH_PLUGIN_MENU_HOOK_INFORMATION MenuHookInfo [menu thread]\n    PluginCallbackMaximum\n} PH_PLUGIN_CALLBACK, *PPH_PLUGIN_CALLBACK;\n\n// Provider events\n\ntypedef struct _PH_PROCESS_PROVIDER_UPDATED_EVENT\n{\n    ULONG RunCount;\n} PH_PROCESS_PROVIDER_UPDATED_EVENT, *PPH_PROCESS_PROVIDER_UPDATED_EVENT;\n\n// Plugin events\n\ntypedef struct _PH_PLUGIN_GET_HIGHLIGHTING_COLOR\n{\n    // Parameter is:\n    // PPH_PROCESS_ITEM for GeneralCallbackGetProcessHighlightingColor\n\n    PVOID Parameter;\n    COLORREF BackColor;\n    COLORREF ForeColor;\n    BOOLEAN Handled;\n    BOOLEAN Cache;\n} PH_PLUGIN_GET_HIGHLIGHTING_COLOR, *PPH_PLUGIN_GET_HIGHLIGHTING_COLOR;\n\ntypedef struct _PH_PLUGIN_GET_TOOLTIP_TEXT\n{\n    // Parameter is:\n    // PPH_PROCESS_ITEM for GeneralCallbackGetProcessTooltipText\n\n    PVOID Parameter;\n    PPH_STRING_BUILDER StringBuilder;\n    ULONG ValidForMs;\n} PH_PLUGIN_GET_TOOLTIP_TEXT, *PPH_PLUGIN_GET_TOOLTIP_TEXT;\n\ntypedef struct _PH_PLUGIN_PROCESS_PROPCONTEXT\n{\n    PPH_PROCESS_PROPCONTEXT PropContext;\n    PPH_PROCESS_ITEM ProcessItem;\n} PH_PLUGIN_PROCESS_PROPCONTEXT, *PPH_PLUGIN_PROCESS_PROPCONTEXT;\n\ntypedef struct _PH_PLUGIN_NOTIFY_EVENT\n{\n    // Parameter is:\n    // PPH_PROCESS_ITEM for Type = PH_NOTIFY_PROCESS_*\n    // PPH_SERVICE_ITEM for Type = PH_NOTIFY_SERVICE_*\n    // PPH_DEVICE_ITEM for type = PH_NOTIFY_DEVICE_*\n\n    ULONG Type;\n    BOOLEAN Handled;\n    PVOID Parameter;\n} PH_PLUGIN_NOTIFY_EVENT, *PPH_PLUGIN_NOTIFY_EVENT;\n\ntypedef struct _PH_PLUGIN_OBJECT_PROPERTIES\n{\n    // Parameter is:\n    // PPH_SERVICE_ITEM for GeneralCallbackServicePropertiesInitializing\n    // PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT for GeneralCallbackHandlePropertiesInitializing\n\n    PVOID Parameter;\n    ULONG NumberOfPages;\n    ULONG MaximumNumberOfPages;\n    HPROPSHEETPAGE *Pages;\n} PH_PLUGIN_OBJECT_PROPERTIES, *PPH_PLUGIN_OBJECT_PROPERTIES;\n\ntypedef struct _PH_PLUGIN_IS_DANGEROUS_PROCESS\n{\n    HANDLE ProcessId;\n    BOOLEAN DangerousProcess;\n} PH_PLUGIN_IS_DANGEROUS_PROCESS, *PPH_PLUGIN_IS_DANGEROUS_PROCESS;\n\ntypedef enum _PH_PLUGIN_HANDLE_GENERAL_CATEGORY\n{\n    // common\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_BASICINFO,\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_REFERENCES,\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_QUOTA,\n    // extra\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_ALPC,\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_FILE,\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_SECTION,\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_MUTANT,\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD,\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_ETW,\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_SYMBOLICLINK,\n\n    PH_PLUGIN_HANDLE_GENERAL_CATEGORY_MAXIMUM\n} PH_PLUGIN_HANDLE_GENERAL_CATEGORY;\n\ntypedef enum _PH_PLUGIN_HANDLE_GENERAL_INDEX\n{\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_NAME,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_TYPE,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_OBJECT,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_ACCESSMASK,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_REFERENCES,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_HANDLES,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_PAGED,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_NONPAGED,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_FLAGS,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_SEQUENCENUMBER,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_PORTCONTEXT,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_FILETYPE,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_FILEMODE,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_FILEPOSITION,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_FILESIZE,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_FILEPRIORITY,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_FILEDRIVER,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_FILEDRIVERIMAGE,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_SECTIONTYPE,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_SECTIONFILE,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_SECTIONSIZE,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_MUTANTCOUNT,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_MUTANTABANDONED,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_MUTANTOWNER,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_ALPCCONNECTION,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_ALPCSERVER,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_ALPCCLIENT,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_ETWORIGINALNAME,\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_ETWGROUPNAME,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_SYMBOLICLINKLINK,\n\n    PH_PLUGIN_HANDLE_GENERAL_INDEX_MAXIMUM\n} PH_PLUGIN_HANDLE_GENERAL_INDEX;\n\ntypedef struct _PH_PLUGIN PH_PLUGIN, *PPH_PLUGIN;\n\ntypedef struct _PH_PLUGIN_HANDLE_PROPERTIES_WINDOW_CONTEXT\n{\n    HWND ListViewHandle;\n    HWND ParentWindow;\n    HANDLE ProcessId;\n    PVOID ListViewClass;\n    PPH_HANDLE_ITEM HandleItem;\n    PH_LAYOUT_MANAGER LayoutManager;\n} PH_PLUGIN_HANDLE_PROPERTIES_WINDOW_CONTEXT, *PPH_PLUGIN_HANDLE_PROPERTIES_WINDOW_CONTEXT;\n\ntypedef struct _PH_PLUGIN_PROCESS_STATS_EVENT\n{\n    ULONG Version;\n    ULONG Type;\n    PPH_PROCESS_ITEM ProcessItem;\n    PVOID Parameter;\n} PH_PLUGIN_PROCESS_STATS_EVENT, *PPH_PLUGIN_PROCESS_STATS_EVENT;\n\ntypedef struct _PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT\n{\n    HWND ParentWindowHandle;\n    HANDLE ProcessId;\n    PPH_HANDLE_ITEM HandleItem;\n} PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT, *PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT;\n\ntypedef struct _PH_EMENU_ITEM *PPH_EMENU_ITEM, *PPH_EMENU;\n\n#define PH_PLUGIN_MENU_DISALLOW_HOOKS 0x1\n\ntypedef struct _PH_PLUGIN_MENU_INFORMATION\n{\n    PPH_EMENU Menu;\n    HWND OwnerWindow;\n\n    union\n    {\n        struct\n        {\n            PVOID Reserved[8]; // Reserve space for future expansion of this union\n        } DoNotUse;\n        struct\n        {\n            ULONG SubMenuIndex;\n        } MainMenu;\n        struct\n        {\n            PPH_PROCESS_ITEM *Processes;\n            ULONG NumberOfProcesses;\n        } Process;\n        struct\n        {\n            PPH_SERVICE_ITEM *Services;\n            ULONG NumberOfServices;\n        } Service;\n        struct\n        {\n            PPH_NETWORK_ITEM *NetworkItems;\n            ULONG NumberOfNetworkItems;\n        } Network;\n        struct\n        {\n            HANDLE ProcessId;\n            PPH_THREAD_ITEM *Threads;\n            ULONG NumberOfThreads;\n        } Thread;\n        struct\n        {\n            HANDLE ProcessId;\n            PPH_MODULE_ITEM *Modules;\n            ULONG NumberOfModules;\n        } Module;\n        struct\n        {\n            HANDLE ProcessId;\n            PPH_MEMORY_NODE *MemoryNodes;\n            ULONG NumberOfMemoryNodes;\n        } Memory;\n        struct\n        {\n            HANDLE ProcessId;\n            PPH_HANDLE_ITEM *Handles;\n            ULONG NumberOfHandles;\n        } Handle;\n        struct\n        {\n            PPH_STRINGREF SectionName;\n            PPH_PROCESS_GROUP ProcessGroup;\n        } MiListSection;\n    } u;\n\n    ULONG Flags;\n    PPH_LIST PluginHookList;\n} PH_PLUGIN_MENU_INFORMATION, *PPH_PLUGIN_MENU_INFORMATION;\n\nC_ASSERT(RTL_FIELD_SIZE(PH_PLUGIN_MENU_INFORMATION, u) == RTL_FIELD_SIZE(PH_PLUGIN_MENU_INFORMATION, u.DoNotUse));\n\ntypedef struct _PH_PLUGIN_MENU_HOOK_INFORMATION\n{\n    PPH_PLUGIN_MENU_INFORMATION MenuInfo;\n    PPH_EMENU SelectedItem;\n    PVOID Context;\n    BOOLEAN Handled;\n} PH_PLUGIN_MENU_HOOK_INFORMATION, *PPH_PLUGIN_MENU_HOOK_INFORMATION;\n\ntypedef struct _PH_PLUGIN_TREENEW_INFORMATION\n{\n    HWND TreeNewHandle;\n    PVOID CmData;\n    PVOID SystemContext; // e.g. PPH_THREADS_CONTEXT\n} PH_PLUGIN_TREENEW_INFORMATION, *PPH_PLUGIN_TREENEW_INFORMATION;\n\ntypedef enum _PH_PLUGIN_THREAD_STACK_CONTROL_TYPE\n{\n    PluginThreadStackInitializing,\n    PluginThreadStackUninitializing,\n    PluginThreadStackResolveSymbol,\n    PluginThreadStackGetTooltip,\n    PluginThreadStackWalkStack,\n    PluginThreadStackBeginDefaultWalkStack,\n    PluginThreadStackEndDefaultWalkStack,\n    PluginThreadStackMaximum\n} PH_PLUGIN_THREAD_STACK_CONTROL_TYPE;\n\ntypedef struct _PH_SYMBOL_PROVIDER *PPH_SYMBOL_PROVIDER;\ntypedef struct _PH_THREAD_STACK_FRAME *PPH_THREAD_STACK_FRAME;\n\ntypedef _Function_class_(PH_PLUGIN_WALK_THREAD_STACK_CALLBACK)\nBOOLEAN NTAPI PH_PLUGIN_WALK_THREAD_STACK_CALLBACK(\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_PLUGIN_WALK_THREAD_STACK_CALLBACK *PPH_PLUGIN_WALK_THREAD_STACK_CALLBACK;\n\ntypedef struct _PH_PLUGIN_THREAD_STACK_CONTROL\n{\n    PH_PLUGIN_THREAD_STACK_CONTROL_TYPE Type;\n    PVOID UniqueKey;\n\n    union\n    {\n        struct\n        {\n            HANDLE ProcessId;\n            HANDLE ThreadId;\n            HANDLE ThreadHandle;\n            HANDLE ProcessHandle;\n            PPH_SYMBOL_PROVIDER SymbolProvider;\n            BOOLEAN CustomWalk;\n        } Initializing;\n        struct\n        {\n            PPH_THREAD_STACK_FRAME StackFrame;\n            PPH_STRING Symbol;\n            PPH_STRING FileName;\n        } ResolveSymbol;\n        struct\n        {\n            PPH_THREAD_STACK_FRAME StackFrame;\n            PPH_STRING_BUILDER StringBuilder;\n        } GetTooltip;\n        struct\n        {\n            NTSTATUS Status;\n            HANDLE ThreadHandle;\n            HANDLE ProcessHandle;\n            PCLIENT_ID ClientId;\n            ULONG Flags;\n            PPH_PLUGIN_WALK_THREAD_STACK_CALLBACK Callback;\n            PVOID CallbackContext;\n        } WalkStack;\n    } u;\n} PH_PLUGIN_THREAD_STACK_CONTROL, *PPH_PLUGIN_THREAD_STACK_CONTROL;\n\ntypedef enum _PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL_TYPE\n{\n    PluginMemoryItemListInitialized,\n    PluginMemoryItemListMaximum\n} PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL_TYPE;\n\ntypedef struct _PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL\n{\n    PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL_TYPE Type;\n\n    union\n    {\n        struct\n        {\n            PPH_MEMORY_ITEM_LIST List;\n        } Initialized;\n    } u;\n} PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL, *PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL;\n\ntypedef _Function_class_(PH_SYSINFO_CREATE_SECTION)\nPPH_SYSINFO_SECTION NTAPI PH_SYSINFO_CREATE_SECTION(\n    _In_ PPH_SYSINFO_SECTION Template\n    );\ntypedef PH_SYSINFO_CREATE_SECTION *PPH_SYSINFO_CREATE_SECTION;\n\ntypedef _Function_class_(PH_SYSINFO_FIND_SECTION)\nPPH_SYSINFO_SECTION NTAPI PH_SYSINFO_FIND_SECTION(\n    _In_ PPH_STRINGREF Name\n    );\ntypedef PH_SYSINFO_FIND_SECTION *PPH_SYSINFO_FIND_SECTION;\n\ntypedef _Function_class_(PH_SYSINFO_ENTER_SECTION_VIEW)\nVOID NTAPI PH_SYSINFO_ENTER_SECTION_VIEW(\n    _In_ PPH_SYSINFO_SECTION NewSection\n    );\ntypedef PH_SYSINFO_ENTER_SECTION_VIEW *PPH_SYSINFO_ENTER_SECTION_VIEW;\n\ntypedef _Function_class_(PH_SYSINFO_RESTORE_SUMMARY_VIEW)\nVOID NTAPI PH_SYSINFO_RESTORE_SUMMARY_VIEW(\n    VOID\n    );\ntypedef PH_SYSINFO_RESTORE_SUMMARY_VIEW *PPH_SYSINFO_RESTORE_SUMMARY_VIEW;\n\ntypedef struct _PH_PLUGIN_SYSINFO_POINTERS\n{\n    HWND WindowHandle;\n    PPH_SYSINFO_CREATE_SECTION CreateSection;\n    PPH_SYSINFO_FIND_SECTION FindSection;\n    PPH_SYSINFO_ENTER_SECTION_VIEW EnterSectionView;\n    PPH_SYSINFO_RESTORE_SUMMARY_VIEW RestoreSummaryView;\n} PH_PLUGIN_SYSINFO_POINTERS, *PPH_PLUGIN_SYSINFO_POINTERS;\n\ntypedef _Function_class_(PH_MINIINFO_CREATE_SECTION)\nPPH_MINIINFO_SECTION NTAPI PH_MINIINFO_CREATE_SECTION(\n    _In_ PPH_MINIINFO_SECTION Template\n    );\ntypedef PH_MINIINFO_CREATE_SECTION *PPH_MINIINFO_CREATE_SECTION;\n\ntypedef _Function_class_(PH_MINIINFO_FIND_SECTION)\nPPH_MINIINFO_SECTION NTAPI PH_MINIINFO_FIND_SECTION(\n    _In_ PPH_STRINGREF Name\n    );\ntypedef PH_MINIINFO_FIND_SECTION *PPH_MINIINFO_FIND_SECTION;\n\ntypedef struct _PH_MINIINFO_LIST_SECTION PH_MINIINFO_LIST_SECTION, *PPH_MINIINFO_LIST_SECTION;\n\ntypedef PPH_MINIINFO_LIST_SECTION (NTAPI *PPH_MINIINFO_CREATE_LIST_SECTION)(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_MINIINFO_LIST_SECTION Template\n    );\n\ntypedef struct _PH_PLUGIN_MINIINFO_POINTERS\n{\n    HWND WindowHandle;\n    PPH_MINIINFO_CREATE_SECTION CreateSection;\n    PPH_MINIINFO_FIND_SECTION FindSection;\n    PPH_MINIINFO_CREATE_LIST_SECTION CreateListSection;\n} PH_PLUGIN_MINIINFO_POINTERS, *PPH_PLUGIN_MINIINFO_POINTERS;\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_NF_ICON_REGISTRATION_DATA *PPH_NF_ICON_REGISTRATION_DATA;\n\n/**\n * Creates a notification icon.\n *\n * \\param Plugin A plugin instance structure.\n * \\param SubId An identifier for the column. This should be unique within the\n * plugin.\n * \\param Guid A unique guid for this icon.\n * \\param Context A user-defined value.\n * \\param Text A string describing the notification icon.\n * \\param Flags A combination of flags.\n * \\li \\c PH_NF_ICON_UNAVAILABLE The notification icon is currently unavailable.\n * \\param RegistrationData A \\ref PH_NF_ICON_REGISTRATION_DATA structure that\n * contains registration information.\n */\ntypedef _Function_class_(PH_REGISTER_TRAY_ICON)\nPPH_PLUGIN NTAPI PH_REGISTER_TRAY_ICON(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ ULONG SubId,\n    _In_ GUID Guid,\n    _In_opt_ PVOID Context,\n    _In_ PCWSTR Text,\n    _In_ ULONG Flags,\n    _In_ PPH_NF_ICON_REGISTRATION_DATA RegistrationData\n    );\ntypedef PH_REGISTER_TRAY_ICON *PPH_REGISTER_TRAY_ICON;\n\ntypedef struct _PH_TRAY_ICON_POINTERS\n{\n    PPH_REGISTER_TRAY_ICON RegisterTrayIcon;\n} PH_TRAY_ICON_POINTERS, *PPH_TRAY_ICON_POINTERS;\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_OPTIONS_SECTION\n{\n    PH_STRINGREF Name;\n    // end_phapppub\n\n    PVOID Instance;\n    PCWSTR Template;\n    DLGPROC DialogProc;\n    PVOID Parameter;\n\n    HWND DialogHandle;\n    HTREEITEM TreeItemHandle;\n    // begin_phapppub\n} PH_OPTIONS_SECTION, *PPH_OPTIONS_SECTION;\n// end_phapppub\n\n// begin_phapppub\ntypedef _Function_class_(PH_OPTIONS_CREATE_SECTION)\nPPH_OPTIONS_SECTION NTAPI PH_OPTIONS_CREATE_SECTION(\n    _In_ PCWSTR Name,\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_ DLGPROC DialogProc,\n    _In_opt_ PVOID Parameter\n    );\ntypedef PH_OPTIONS_CREATE_SECTION *PPH_OPTIONS_CREATE_SECTION;\n\ntypedef _Function_class_(PH_OPTIONS_FIND_SECTION)\nPPH_OPTIONS_SECTION NTAPI PH_OPTIONS_FIND_SECTION(\n    _In_ PPH_STRINGREF Name\n    );\ntypedef PH_OPTIONS_FIND_SECTION *PPH_OPTIONS_FIND_SECTION;\n\ntypedef _Function_class_(PH_OPTIONS_ENTER_SECTION_VIEW)\nVOID NTAPI PH_OPTIONS_ENTER_SECTION_VIEW(\n    _In_ PPH_OPTIONS_SECTION NewSection\n    );\ntypedef PH_OPTIONS_ENTER_SECTION_VIEW *PPH_OPTIONS_ENTER_SECTION_VIEW;\n\ntypedef struct _PH_PLUGIN_OPTIONS_POINTERS\n{\n    HWND WindowHandle;\n    PPH_OPTIONS_CREATE_SECTION CreateSection;\n    PPH_OPTIONS_FIND_SECTION FindSection;\n    PPH_OPTIONS_ENTER_SECTION_VIEW EnterSectionView;\n} PH_PLUGIN_OPTIONS_POINTERS, *PPH_PLUGIN_OPTIONS_POINTERS;\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_PLUGIN_TREENEW_MESSAGE\n{\n    HWND TreeNewHandle;\n    PH_TREENEW_MESSAGE Message;\n    PVOID Parameter1;\n    PVOID Parameter2;\n    ULONG SubId;\n    PVOID Context;\n} PH_PLUGIN_TREENEW_MESSAGE, *PPH_PLUGIN_TREENEW_MESSAGE;\n\ntypedef _Function_class_(PH_PLUGIN_TREENEW_SORT_FUNCTION)\nLONG NTAPI PH_PLUGIN_TREENEW_SORT_FUNCTION(\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ ULONG SubId,\n    _In_ PH_SORT_ORDER SortOrder,\n    _In_ PVOID Context\n    );\ntypedef PH_PLUGIN_TREENEW_SORT_FUNCTION *PPH_PLUGIN_TREENEW_SORT_FUNCTION;\n\ntypedef _Function_class_(PHSVC_SERVER_PROBE_BUFFER)\nNTSTATUS NTAPI PHSVC_SERVER_PROBE_BUFFER(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ ULONG Alignment,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PVOID *Pointer\n    );\ntypedef PHSVC_SERVER_PROBE_BUFFER *PPHSVC_SERVER_PROBE_BUFFER;\n\ntypedef _Function_class_(PHSVC_SERVER_CAPTURE_BUFFER)\nNTSTATUS NTAPI PHSVC_SERVER_CAPTURE_BUFFER(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PVOID *CapturedBuffer\n    );\ntypedef PHSVC_SERVER_CAPTURE_BUFFER *PPHSVC_SERVER_CAPTURE_BUFFER;\n\ntypedef _Function_class_(PHSVC_SERVER_CAPTURE_STRING)\nNTSTATUS NTAPI PHSVC_SERVER_CAPTURE_STRING(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PPH_STRING *CapturedString\n    );\ntypedef PHSVC_SERVER_CAPTURE_STRING *PPHSVC_SERVER_CAPTURE_STRING;\n\ntypedef struct _PH_PLUGIN_PHSVC_REQUEST\n{\n    ULONG SubId;\n    NTSTATUS ReturnStatus;\n    PVOID InBuffer;\n    ULONG InLength;\n    PVOID OutBuffer;\n    ULONG OutLength;\n\n    PPHSVC_SERVER_PROBE_BUFFER ProbeBuffer;\n    PPHSVC_SERVER_CAPTURE_BUFFER CaptureBuffer;\n    PPHSVC_SERVER_CAPTURE_STRING CaptureString;\n} PH_PLUGIN_PHSVC_REQUEST, *PPH_PLUGIN_PHSVC_REQUEST;\n\ntypedef _Function_class_(PHSVC_CLIENT_FREE_HEAP)\nVOID NTAPI PHSVC_CLIENT_FREE_HEAP(\n    _In_ PVOID Memory\n    );\ntypedef PHSVC_CLIENT_FREE_HEAP *PPHSVC_CLIENT_FREE_HEAP;\n\ntypedef _Function_class_(PHSVC_CLIENT_CREATE_STRING)\nPVOID NTAPI PHSVC_CLIENT_CREATE_STRING(\n    _In_opt_ PVOID String,\n    _In_ SIZE_T Length,\n    _Out_ PPH_RELATIVE_STRINGREF StringRef\n    );\ntypedef PHSVC_CLIENT_CREATE_STRING *PPHSVC_CLIENT_CREATE_STRING;\n\ntypedef struct _PH_PLUGIN_PHSVC_CLIENT\n{\n    HANDLE ServerProcessId;\n    PPHSVC_CLIENT_FREE_HEAP FreeHeap;\n    PPHSVC_CLIENT_CREATE_STRING CreateString;\n} PH_PLUGIN_PHSVC_CLIENT, *PPH_PLUGIN_PHSVC_CLIENT;\n\n// Plugin structures\n\ntypedef struct _PH_PLUGIN_INFORMATION\n{\n    PCWSTR DisplayName;\n    PCWSTR Author;\n    PCWSTR Description;\n    PCWSTR Url;\n    BOOLEAN HasOptions;\n    BOOLEAN Reserved1[3];\n    PVOID Interface;\n} PH_PLUGIN_INFORMATION, *PPH_PLUGIN_INFORMATION;\n\n#define PH_PLUGIN_FLAG_RESERVED 0x1\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_PLUGIN\n{\n    // Public\n\n    PH_AVL_LINKS Links;\n\n    PVOID DllBase;\n// end_phapppub\n\n    // Private\n\n    PH_STRINGREF Name;\n    ULONG Flags;\n    PH_PLUGIN_INFORMATION Information;\n\n    PH_CALLBACK Callbacks[PluginCallbackMaximum];\n    PH_EM_APP_CONTEXT AppContext;\n// begin_phapppub\n} PH_PLUGIN, *PPH_PLUGIN;\n// end_phapppub\n\n// begin_phapppub\n// Plugin API\n\nPHAPPAPI\nPPH_PLUGIN\nNTAPI\nPhRegisterPluginByName(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PVOID DllBase,\n    _Out_opt_ PPH_PLUGIN_INFORMATION *Information\n    );\n\nFORCEINLINE\nPPH_PLUGIN\nNTAPI\nPhRegisterPlugin(\n    _In_ PCWSTR Name,\n    _In_ PVOID DllBase,\n    _Out_opt_ PPH_PLUGIN_INFORMATION* Information\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    return PhRegisterPluginByName(&name, DllBase, Information);\n}\n\nPHAPPAPI\nPPH_PLUGIN\nNTAPI\nPhFindPlugin2(\n    _In_ PCPH_STRINGREF Name\n    );\n\n/**\n * Locates a plugin instance structure.\n *\n * \\param Name The name of the plugin.\n *\n * \\return A plugin instance structure, or NULL if the plugin was not found.\n */\nFORCEINLINE\nPPH_PLUGIN\nNTAPI\nPhFindPlugin(\n    _In_ PCWSTR Name\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    return PhFindPlugin2(&name);\n}\n\nPHAPPAPI\nPVOID\nNTAPI\nPhGetPluginInterface(\n    _In_ PCPH_STRINGREF Name,\n    _In_opt_ ULONG Version\n    );\n\nFORCEINLINE\nPVOID\nNTAPI\nPhGetPluginInterfaceZ(\n    _In_ PCWSTR Name,\n    _In_opt_ ULONG Version\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    return PhGetPluginInterface(&name, Version);\n}\n\nPHAPPAPI\nPPH_PLUGIN_INFORMATION\nNTAPI\nPhGetPluginInformation(\n    _In_ PPH_PLUGIN Plugin\n    );\n\nPHAPPAPI\nPPH_CALLBACK\nNTAPI\nPhGetPluginCallback(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PH_PLUGIN_CALLBACK Callback\n    );\n\nPHAPPAPI\nPPH_CALLBACK\nNTAPI\nPhGetGeneralCallback(\n    _In_ PH_GENERAL_CALLBACK Callback\n    );\n\nPHAPPAPI\nULONG\nNTAPI\nPhPluginReserveIds(\n    _In_ ULONG Count\n    );\n\ntypedef struct _PH_PLUGIN_MENU_ITEM *PPH_PLUGIN_MENU_ITEM;\n\n_Function_class_(PH_PLUGIN_MENU_ITEM_DELETE_FUNCTION)\ntypedef VOID (NTAPI PH_PLUGIN_MENU_ITEM_DELETE_FUNCTION)(\n    _In_ PPH_PLUGIN_MENU_ITEM MenuItem\n    );\ntypedef PH_PLUGIN_MENU_ITEM_DELETE_FUNCTION *PPH_PLUGIN_MENU_ITEM_DELETE_FUNCTION;\n\ntypedef struct _PH_PLUGIN_MENU_ITEM\n{\n    PPH_PLUGIN Plugin;\n    ULONG Id;\n    ULONG Reserved1;\n    PVOID Context;\n\n    HWND OwnerWindow; // valid only when the menu item is chosen\n    PVOID Reserved2;\n    PVOID Reserved3;\n    PPH_PLUGIN_MENU_ITEM_DELETE_FUNCTION DeleteFunction; // valid only for EMENU-based menu items\n} PH_PLUGIN_MENU_ITEM, *PPH_PLUGIN_MENU_ITEM;\n\n// Location\n#define PH_MENU_ITEM_LOCATION_SYSTEM 0\n#define PH_MENU_ITEM_LOCATION_VIEW 1\n#define PH_MENU_ITEM_LOCATION_TOOLS 2\n#define PH_MENU_ITEM_LOCATION_USERS 3\n#define PH_MENU_ITEM_LOCATION_HELP 4\n\ntypedef struct _PH_PLUGIN_SYSTEM_STATISTICS\n{\n    PSYSTEM_PERFORMANCE_INFORMATION Performance;\n\n    ULONG NumberOfProcesses;\n    ULONG NumberOfThreads;\n    ULONG NumberOfHandles;\n\n    FLOAT CpuKernelUsage;\n    FLOAT CpuUserUsage;\n\n    PH_UINT64_DELTA IoReadDelta;\n    PH_UINT64_DELTA IoWriteDelta;\n    PH_UINT64_DELTA IoOtherDelta;\n\n    ULONG CommitPages;\n    ULONG PhysicalPages;\n\n    HANDLE MaxCpuProcessId;\n    HANDLE MaxIoProcessId;\n\n    PPH_CIRCULAR_BUFFER_FLOAT CpuKernelHistory;\n    PPH_CIRCULAR_BUFFER_FLOAT CpuUserHistory;\n    PPH_CIRCULAR_BUFFER_FLOAT *CpusKernelHistory;\n    PPH_CIRCULAR_BUFFER_FLOAT *CpusUserHistory;\n    PPH_CIRCULAR_BUFFER_ULONG64 IoReadHistory;\n    PPH_CIRCULAR_BUFFER_ULONG64 IoWriteHistory;\n    PPH_CIRCULAR_BUFFER_ULONG64 IoOtherHistory;\n    PPH_CIRCULAR_BUFFER_ULONG CommitHistory;\n    PPH_CIRCULAR_BUFFER_ULONG PhysicalHistory;\n    PPH_CIRCULAR_BUFFER_ULONG MaxCpuHistory; // ID of max. CPU process\n    PPH_CIRCULAR_BUFFER_ULONG MaxIoHistory; // ID of max. I/O process\n    PPH_CIRCULAR_BUFFER_FLOAT MaxCpuUsageHistory;\n    PPH_CIRCULAR_BUFFER_ULONG64 MaxIoReadOtherHistory;\n    PPH_CIRCULAR_BUFFER_ULONG64 MaxIoWriteHistory;\n} PH_PLUGIN_SYSTEM_STATISTICS, *PPH_PLUGIN_SYSTEM_STATISTICS;\n\nPHAPPAPI\nVOID\nNTAPI\nPhPluginGetSystemStatistics(\n    _Out_ PPH_PLUGIN_SYSTEM_STATISTICS Statistics\n    );\n\nPHAPPAPI\nPPH_EMENU_ITEM\nNTAPI\nPhPluginCreateEMenuItem(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ ULONG Flags,\n    _In_ ULONG Id,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Context\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhPluginAddMenuHook(\n    _Inout_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,\n    _In_ PPH_PLUGIN Plugin,\n    _In_opt_ PVOID Context\n    );\n// end_phapppub\n\nVOID\nNTAPI\nPhPluginInitializeMenuInfo(\n    _Out_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,\n    _In_opt_ PPH_EMENU Menu,\n    _In_ HWND OwnerWindow,\n    _In_ ULONG Flags\n    );\n\nBOOLEAN\nNTAPI\nPhPluginTriggerEMenuItem(\n    _In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,\n    _In_ PPH_EMENU_ITEM Item\n    );\n\n// begin_phapppub\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhPluginAddTreeNewColumn(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PVOID CmData,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG SubId,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhPluginSetObjectExtension(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ ULONG ExtensionSize,\n    _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback,\n    _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback\n    );\n\nPHAPPAPI\nPVOID\nNTAPI\nPhPluginGetObjectExtension(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PVOID Object,\n    _In_ PH_EM_OBJECT_TYPE ObjectType\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhPluginEnableTreeNewNotify(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PVOID CmData\n    );\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhPluginQueryPhSvc(\n    _Out_ PPH_PLUGIN_PHSVC_CLIENT Client\n    );\n\nPHAPPAPI\nNTSTATUS\nNTAPI\nPhPluginCallPhSvc(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ ULONG SubId,\n    _In_reads_bytes_opt_(InLength) PVOID InBuffer,\n    _In_ ULONG InLength,\n    _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer,\n    _In_ ULONG OutLength\n    );\n\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhGetPluginName(\n    _In_ PPH_PLUGIN Plugin\n    );\n\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhGetPluginFileName(\n    _In_ PPH_PLUGIN Plugin\n    );\n\n_Function_class_(PH_PLUGIN_ENUMERATE)\ntypedef NTSTATUS (NTAPI PH_PLUGIN_ENUMERATE)(\n    _In_ PPH_PLUGIN Information,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_PLUGIN_ENUMERATE *PPH_PLUGIN_ENUMERATE;\n\nPHAPPAPI\nVOID\nNTAPI\nPhEnumeratePlugins(\n    _In_ PPH_PLUGIN_ENUMERATE Callback,\n    _In_opt_ PVOID Context\n    );\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/phsettings.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_SETTINGS_H\n#define PH_SETTINGS_H\n\n//\n// Application Typedefs\n//\n\nEXTERN_C\nVOID\nNTAPI\nPhAddDefaultSettings(\n    VOID\n    );\n\nEXTERN_C\nVOID\nNTAPI\nPhUpdateCachedSettings(\n    VOID\n    );\n\n//\n// Cached settings\n//\n\n#pragma push_macro(\"EXT\")\n#undef EXT\n\n#ifdef PH_SETTINGS_PRIVATE\n#define EXT\n#else\n#define EXT extern\n#endif\n\nEXT BOOLEAN PhEnableProcessQueryStage2;\nEXT BOOLEAN PhEnableServiceQueryStage2;\nEXT BOOLEAN PhEnableWindowText;\nEXT BOOLEAN PhEnableTooltipSupport;\nEXT BOOLEAN PhEnableLinuxSubsystemSupport;\nEXT ULONG PhCsEnableNetworkResolveDoH;\nEXT ULONG PhCsEnableVersionSupport;\nEXT BOOLEAN PhEnableDeferredLayout;\nEXT BOOLEAN PhEnableKsiWarnings;\nEXT BOOLEAN PhEnableKsiSupport;\n\nEXT ULONG PhCsForceNoParent;\nEXT ULONG PhCsHighlightingDuration;\nEXT ULONG PhCsPropagateCpuUsage;\nEXT ULONG PhCsScrollToNewProcesses;\nEXT ULONG PhCsScrollToRemovedProcesses;\nEXT ULONG PhCsSortChildProcesses;\nEXT ULONG PhCsSortRootProcesses;\nEXT ULONG PhCsShowCpuBelow001;\nEXT ULONG PhCsUpdateInterval;\n\nEXT ULONG PhCsColorNew;\nEXT ULONG PhCsColorRemoved;\nEXT ULONG PhCsUseColorOwnProcesses;\nEXT ULONG PhCsColorOwnProcesses;\nEXT ULONG PhCsUseColorSystemProcesses;\nEXT ULONG PhCsColorSystemProcesses;\nEXT ULONG PhCsUseColorServiceProcesses;\nEXT ULONG PhCsColorServiceProcesses;\nEXT ULONG PhCsUseColorBackgroundProcesses;\nEXT ULONG PhCsColorBackgroundProcesses;\nEXT ULONG PhCsUseColorJobProcesses;\nEXT ULONG PhCsColorJobProcesses;\nEXT ULONG PhCsUseColorWow64Processes;\nEXT ULONG PhCsColorWow64Processes;\nEXT ULONG PhCsUseColorDebuggedProcesses;\nEXT ULONG PhCsColorDebuggedProcesses;\nEXT ULONG PhCsUseColorElevatedProcesses;\nEXT ULONG PhCsColorElevatedProcesses;\nEXT ULONG PhCsUseColorHandleFiltered;\nEXT ULONG PhCsColorHandleFiltered;\nEXT ULONG PhCsUseColorImmersiveProcesses;\nEXT ULONG PhCsColorImmersiveProcesses;\nEXT ULONG PhCsUseColorUIAccessProcesses;\nEXT ULONG PhCsColorUIAccessProcesses;\nEXT ULONG PhCsUseColorPicoProcesses;\nEXT ULONG PhCsColorPicoProcesses;\nEXT ULONG PhCsUseColorSuspended;\nEXT ULONG PhCsColorSuspended;\nEXT ULONG PhCsUseColorDotNet;\nEXT ULONG PhCsColorDotNet;\nEXT ULONG PhCsUseColorPacked;\nEXT ULONG PhCsColorPacked;\nEXT ULONG PhCsUseColorLowImageCoherency;\nEXT ULONG PhCsColorLowImageCoherency;\nEXT ULONG PhCsUseColorPartiallySuspended;\nEXT ULONG PhCsColorPartiallySuspended;\nEXT ULONG PhCsUseColorGuiThreads;\nEXT ULONG PhCsColorGuiThreads;\nEXT ULONG PhCsUseColorRelocatedModules;\nEXT ULONG PhCsColorRelocatedModules;\nEXT ULONG PhCsUseColorProtectedHandles;\nEXT ULONG PhCsColorProtectedHandles;\nEXT ULONG PhCsUseColorProtectedInheritHandles;\nEXT ULONG PhCsColorProtectedInheritHandles;\nEXT ULONG PhCsUseColorProtectedProcess;\nEXT ULONG PhCsColorProtectedProcess;\nEXT ULONG PhCsUseColorInheritHandles;\nEXT ULONG PhCsColorInheritHandles;\nEXT ULONG PhCsUseColorEfficiencyMode;\nEXT ULONG PhCsColorEfficiencyMode;\nEXT ULONG PhCsGraphShowText;\nEXT ULONG PhCsGraphColorMode;\nEXT ULONG PhCsColorCpuKernel;\nEXT ULONG PhCsColorCpuUser;\nEXT ULONG PhCsColorIoReadOther;\nEXT ULONG PhCsColorIoWrite;\nEXT ULONG PhCsColorPrivate;\nEXT ULONG PhCsColorPhysical;\nEXT ULONG PhCsColorPowerUsage;\nEXT ULONG PhCsColorTemperature;\nEXT ULONG PhCsColorFanRpm;\n\nEXT ULONG PhCsUseColorUnknown;\nEXT ULONG PhCsColorUnknown;\nEXT ULONG PhCsUseColorServiceDisabled;\nEXT ULONG PhCsColorServiceDisabled;\nEXT ULONG PhCsUseColorServiceStop;\nEXT ULONG PhCsColorServiceStop;\n\nEXT BOOLEAN PhEnableImageCoherencySupport;\nEXT ULONG PhCsImageCoherencyScanLevel;\nEXT ULONG PhCsEnableGraphMaxScale;\nEXT ULONG PhCsEnableGraphMaxText;\nEXT ULONG PhCsEnableAvxSupport;\nEXT ULONG PhCsEnableHandleSnapshot;\n\nEXT BOOLEAN PhEnableProcessMonitor;\nEXT ULONG PhProcessMonitorLookback;\nEXT ULONG PhProcessMonitorCacheLimit;\n\n#pragma pop_macro(\"EXT\")\n\n#define PH_GET_INTEGER_CACHED_SETTING(Name) ((PhCs##Name) = PhGetIntegerSetting(TEXT(#Name)))\n#define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(TEXT(#Name), (PhCs##Name) = (Value)))\n\n// begin_phapppub\n\n#define SETTING_SCHEMA_FILE                                         L\"$schema\"\n#define SETTING_ALLOW_ONLY_ONE_INSTANCE                             L\"AllowOnlyOneInstance\"\n#define SETTING_CLOSE_ON_ESCAPE                                     L\"CloseOnEscape\"\n#define SETTING_DBGHELP_SEARCH_PATH                                 L\"DbgHelpSearchPath\"\n#define SETTING_DBGHELP_UNDECORATE                                  L\"DbgHelpUndecorate\"\n#define SETTING_DBGHELP_VERIFY_MICROSOFT_CHAIN                      L\"DbgHelpVerifyMicrosoftChain\"\n#define SETTING_DISABLED_PLUGINS                                    L\"DisabledPlugins\"\n#define SETTING_ELEVATION_LEVEL                                     L\"ElevationLevel\"\n#define SETTING_ENABLE_ADVANCED_OPTIONS                             L\"EnableAdvancedOptions\"\n#define SETTING_ENABLE_AVX_SUPPORT                                  L\"EnableAvxSupport\"\n#define SETTING_ENABLE_BITMAP_SUPPORT                               L\"EnableBitmapSupport\"\n#define SETTING_ENABLE_BREAK_ON_TERMINATION                         L\"EnableBreakOnTermination\"\n#define SETTING_ENABLE_BOOT_OBJECTS_ENUMERATE                       L\"EnableBootObjectsEnumerate\"\n#define SETTING_ENABLE_COMMAND_LINE_TOOLTIPS                        L\"EnableCommandLineTooltips\"\n#define SETTING_ENABLE_CYCLE_CPU_USAGE                              L\"EnableCycleCpuUsage\"\n#define SETTING_ENABLE_DEFERRED_LAYOUT                              L\"EnableDeferredLayout\"\n#define SETTING_ENABLE_DEVICE_SUPPORT                               L\"EnableDeviceSupport\"\n#define SETTING_ENABLE_DEVICE_NOTIFY_SUPPORT                        L\"EnableDeviceNotifySupport\"\n#define SETTING_ENABLE_IMAGE_COHERENCY_SUPPORT                      L\"EnableImageCoherencySupport\"\n#define SETTING_ENABLE_INSTANT_TOOLTIPS                             L\"EnableInstantTooltips\"\n#define SETTING_ENABLE_HEAP_REFLECTION                              L\"EnableHeapReflection\"\n#define SETTING_ENABLE_HEAP_MEMORY_TAGGING                          L\"EnableHeapMemoryTagging\"\n#define SETTING_ENABLE_LAST_PROCESS_SHUTDOWN                        L\"EnableLastProcessShutdown\"\n#define SETTING_ENABLE_LINUX_SUBSYSTEM_SUPPORT                      L\"EnableLinuxSubsystemSupport\"\n#define SETTING_ENABLE_HANDLE_SNAPSHOT                              L\"EnableHandleSnapshot\"\n#define SETTING_ENABLE_MINIDUMP_KERNEL_MINIDUMP                     L\"EnableMinidumpKernelMinidump\"\n#define SETTING_ENABLE_MINIDUMP_SNAPSHOT                            L\"EnableMinidumpSnapshot\"\n#define SETTING_ENABLE_MONOSPACE_FONT                               L\"EnableMonospaceFont\"\n#define SETTING_ENABLE_NETWORK_BOUND_CONNECTIONS                    L\"EnableNetworkBoundConnections\"\n#define SETTING_ENABLE_NETWORK_RESOLVE                              L\"EnableNetworkResolve\"\n#define SETTING_ENABLE_NETWORK_RESOLVE_DOH                          L\"EnableNetworkResolveDoH\"\n#define SETTING_ENABLE_MEM_STRINGS_TREE_DIALOG                      L\"EnableMemStringsTreeDialog\"\n#define SETTING_ENABLE_PACKAGE_ICON_SUPPORT                         L\"EnablePackageIconSupport\"\n#define SETTING_ENABLE_PROCESS_HANDLE_PNP_DEVICE_NAME_SUPPORT       L\"EnableProcessHandlePnPDeviceNameSupport\"\n#define SETTING_ENABLE_PLUGINS                                      L\"EnablePlugins\"\n#define SETTING_ENABLE_PLUGINS_NATIVE                               L\"EnablePluginsNative\"\n#define SETTING_ENABLE_GRAPH_MAX_SCALE                              L\"EnableGraphMaxScale\"\n#define SETTING_ENABLE_GRAPH_MAX_TEXT                               L\"EnableGraphMaxText\"\n#define SETTING_ENABLE_HIGH_RESOLUTION_PROVIDER_TIMER               L\"EnableHighResolutionProviderTimer\"\n#define SETTING_ENABLE_SERVICE_NON_POLL                             L\"EnableServiceNonPoll\"\n#define SETTING_ENABLE_SERVICE_NON_POLL_NOTIFY                      L\"EnableServiceNonPollNotify\"\n#define SETTING_ENABLE_SERVICE_STAGE2                               L\"EnableServiceStage2\"\n#define SETTING_ENABLE_SERVICE_PROGRESS_DIALOG                      L\"EnableServiceProgressDialog\"\n#define SETTING_ENABLE_SHELL_EXECUTE_SKIP_IFEO_DEBUGGER             L\"EnableShellExecuteSkipIfeoDebugger\"\n#define SETTING_ENABLE_STAGE2                                       L\"EnableStage2\"\n#define SETTING_ENABLE_STREAMER_MODE                                L\"EnableStreamerMode\"\n#define SETTING_ENABLE_START_AS_ADMIN                               L\"EnableStartAsAdmin\"\n#define SETTING_ENABLE_START_AS_ADMIN_ALWAYS_ON_TOP                 L\"EnableStartAsAdminAlwaysOnTop\"\n#define SETTING_ENABLE_DEFAULT_SAFE_PLUGINS                         L\"EnableDefaultSafePlugins\"\n#define SETTING_ENABLE_SECURITY_ADVANCED_DIALOG                     L\"EnableSecurityAdvancedDialog\"\n#define SETTING_ENABLE_SHORT_RELATIVE_START_TIME                    L\"EnableShortRelativeStartTime\"\n#define SETTING_ENABLE_SHUTDOWN_CRITICAL_MENU                       L\"EnableShutdownCriticalMenu\"\n#define SETTING_ENABLE_SHUTDOWN_BOOT_MENU                           L\"EnableShutdownBootMenu\"\n#define SETTING_ENABLE_SILENT_CRASH_NOTIFY                          L\"EnableSilentCrashNotify\"\n#define SETTING_ENABLE_THEME_SUPPORT                                L\"EnableThemeSupport\"\n#define SETTING_ENABLE_THEME_ACRYLIC_SUPPORT                        L\"EnableThemeAcrylicSupport\"\n#define SETTING_ENABLE_THEME_ACRYLIC_WINDOW_SUPPORT                 L\"EnableThemeAcrylicWindowSupport\"\n#define SETTING_ENABLE_THEME_ANIMATION                              L\"EnableThemeAnimation\"\n#define SETTING_ENABLE_THEME_NATIVE_BUTTONS                         L\"EnableThemeNativeButtons\"\n#define SETTING_ENABLE_THREAD_STACK_INLINE_SYMBOLS                  L\"EnableThreadStackInlineSymbols\"\n#define SETTING_ENABLE_THREAD_STACK_LINE_INFORMATION                L\"EnableThreadStackLineInformation\"\n#define SETTING_ENABLE_TOKEN_REMOVED_PRIVILEGES                     L\"EnableTokenRemovedPrivileges\"\n#define SETTING_ENABLE_TOOLTIP_SUPPORT                              L\"EnableTooltipSupport\"\n#define SETTING_ENABLE_UPDATE_DEFAULT_FIRMWARE_BOOT_ENTRY           L\"EnableUpdateDefaultFirmwareBootEntry\"\n#define SETTING_ENABLE_VERSION_SUPPORT                              L\"EnableVersionSupport\"\n#define SETTING_ENABLE_WARNINGS                                     L\"EnableWarnings\"\n#define SETTING_ENABLE_WARNINGS_RUNAS                               L\"EnableWarningsRunas\"\n#define SETTING_ENABLE_WINDOW_TEXT                                  L\"EnableWindowText\"\n#define SETTING_ENVIRONMENT_TREE_LIST_COLUMNS                       L\"EnvironmentTreeListColumns\"\n#define SETTING_ENVIRONMENT_TREE_LIST_SORT                          L\"EnvironmentTreeListSort\"\n#define SETTING_ENVIRONMENT_TREE_LIST_FLAGS                         L\"EnvironmentTreeListFlags\"\n#define SETTING_SEARCH_CONTROL_REGEX                                L\"SearchControlRegex\"\n#define SETTING_SEARCH_CONTROL_CASE_SENSITIVE                       L\"SearchControlCaseSensitive\"\n#define SETTING_FIND_OBJ_TREE_LIST_COLUMNS                          L\"FindObjTreeListColumns\"\n#define SETTING_FIND_OBJ_WINDOW_POSITION                            L\"FindObjWindowPosition\"\n#define SETTING_FIND_OBJ_WINDOW_SIZE                                L\"FindObjWindowSize\"\n#define SETTING_THREAD_STACKS_TREE_LIST_COLUMNS                     L\"ThreadStacksTreeListColumns\"\n#define SETTING_THREAD_STACKS_WINDOW_POSITION                       L\"ThreadStacksWindowPosition\"\n#define SETTING_THREAD_STACKS_WINDOW_SIZE                           L\"ThreadStacksWindowSize\"\n#define SETTING_FILE_BROWSE_EXECUTABLE                              L\"FileBrowseExecutable\"\n#define SETTING_FIRST_RUN                                           L\"FirstRun\"\n#define SETTING_FONT                                                L\"Font\"\n#define SETTING_FONT_MONOSPACE                                      L\"FontMonospace\"\n#define SETTING_FONT_QUALITY                                        L\"FontQuality\"\n#define SETTING_FORCE_NO_PARENT                                     L\"ForceNoParent\"\n#define SETTING_HANDLE_TREE_LIST_COLUMNS                            L\"HandleTreeListColumns\"\n#define SETTING_HANDLE_TREE_LIST_SORT                               L\"HandleTreeListSort\"\n#define SETTING_HANDLE_TREE_LIST_FLAGS                              L\"HandleTreeListFlags\"\n#define SETTING_HANDLE_PROPERTIES_WINDOW_POSITION                   L\"HandlePropertiesWindowPosition\"\n#define SETTING_HANDLE_PROPERTIES_WINDOW_SIZE                       L\"HandlePropertiesWindowSize\"\n#define SETTING_HANDLE_STATISTICS_LIST_VIEW_COLUMNS                 L\"HandleStatisticsListViewColumns\"\n#define SETTING_HANDLE_STATISTICS_LIST_VIEW_SORT                    L\"HandleStatisticsListViewSort\"\n#define SETTING_HANDLE_STATISTICS_WINDOW_POSITION                   L\"HandleStatisticsWindowPosition\"\n#define SETTING_HANDLE_STATISTICS_WINDOW_SIZE                       L\"HandleStatisticsWindowSize\"\n#define SETTING_HIDE_DEFAULT_SERVICES                               L\"HideDefaultServices\"\n#define SETTING_HIDE_DRIVER_SERVICES                                L\"HideDriverServices\"\n#define SETTING_HIDE_FREE_REGIONS                                   L\"HideFreeRegions\"\n#define SETTING_HIDE_ON_CLOSE                                       L\"HideOnClose\"\n#define SETTING_HIDE_ON_MINIMIZE                                    L\"HideOnMinimize\"\n#define SETTING_HIDE_OTHER_USER_PROCESSES                           L\"HideOtherUserProcesses\"\n#define SETTING_HIDE_SIGNED_PROCESSES                               L\"HideSignedProcesses\"\n#define SETTING_HIDE_MICROSOFT_PROCESSES                            L\"HideMicrosoftProcesses\"\n#define SETTING_HIDE_WAITING_CONNECTIONS                            L\"HideWaitingConnections\"\n#define SETTING_HIGHLIGHTING_DURATION                               L\"HighlightingDuration\"\n#define SETTING_ICON_BALLOON_SHOW_ICON                              L\"IconBalloonShowIcon\"\n#define SETTING_ICON_BALLOON_MUTE_SOUND                             L\"IconBalloonMuteSound\"\n#define SETTING_TOAST_NOTIFY_ENABLED                                L\"ToastNotifyEnabled\"\n#define SETTING_ICON_TRAY_GUIDS                                     L\"IconTrayGuids\"\n#define SETTING_ICON_TRAY_PERSIST_GUID_ENABLED                      L\"IconTrayPersistGuidEnabled\"\n#define SETTING_ICON_TRAY_LAZY_START_DELAY                          L\"IconTrayLazyStartDelay\"\n#define SETTING_ICON_IGNORE_BALLOON_CLICK                           L\"IconIgnoreBalloonClick\"\n#define SETTING_ICON_SETTINGS                                       L\"IconSettings\"\n#define SETTING_ICON_NOTIFY_MASK                                    L\"IconNotifyMask\"\n#define SETTING_ICON_PROCESSES                                      L\"IconProcesses\"\n#define SETTING_ICON_SINGLE_CLICK                                   L\"IconSingleClick\"\n#define SETTING_ICON_TOGGLES_VISIBILITY                             L\"IconTogglesVisibility\"\n#define SETTING_ICON_TRANSPARENCY_ENABLED                           L\"IconTransparencyEnabled\"\n#define SETTING_INFORMATION_WINDOW_POSITION                         L\"InformationWindowPosition\"\n#define SETTING_INFORMATION_WINDOW_SIZE                             L\"InformationWindowSize\"\n#define SETTING_IMAGE_COHERENCY_SCAN_LEVEL                          L\"ImageCoherencyScanLevel\"\n#define SETTING_JOB_LIST_VIEW_COLUMNS                               L\"JobListViewColumns\"\n#define SETTING_LOG_ENTRIES                                         L\"LogEntries\"\n#define SETTING_LOG_LIST_VIEW_COLUMNS                               L\"LogListViewColumns\"\n#define SETTING_LOG_WINDOW_POSITION                                 L\"LogWindowPosition\"\n#define SETTING_LOG_WINDOW_SIZE                                     L\"LogWindowSize\"\n#define SETTING_MAIN_WINDOW_ALWAYS_ON_TOP                           L\"MainWindowAlwaysOnTop\"\n#define SETTING_MAIN_WINDOW_CLASS_NAME                              L\"MainWindowClassName\"\n#define SETTING_MAIN_WINDOW_OPACITY                                 L\"MainWindowOpacity\"\n#define SETTING_MAIN_WINDOW_POSITION                                L\"MainWindowPosition\"\n#define SETTING_MAIN_WINDOW_SIZE                                    L\"MainWindowSize\"\n#define SETTING_MAIN_WINDOW_STATE                                   L\"MainWindowState\"\n#define SETTING_MAIN_WINDOW_TAB_RESTORE_ENABLED                     L\"MainWindowTabRestoreEnabled\"\n#define SETTING_MAIN_WINDOW_TAB_RESTORE_INDEX                       L\"MainWindowTabRestoreIndex\"\n#define SETTING_MAX_SIZE_UNIT                                       L\"MaxSizeUnit\"\n#define SETTING_MAX_PRECISION_UNIT                                  L\"MaxPrecisionUnit\"\n#define SETTING_MEM_EDIT_BYTES_PER_ROW                              L\"MemEditBytesPerRow\"\n#define SETTING_MEM_EDIT_GOTO_CHOICES                               L\"MemEditGotoChoices\"\n#define SETTING_MEM_EDIT_POSITION                                   L\"MemEditPosition\"\n#define SETTING_MEM_EDIT_SIZE                                       L\"MemEditSize\"\n#define SETTING_MEM_FILTER_CHOICES                                  L\"MemFilterChoices\"\n#define SETTING_MEM_RESULTS_LIST_VIEW_COLUMNS                       L\"MemResultsListViewColumns\"\n#define SETTING_MEM_RESULTS_POSITION                                L\"MemResultsPosition\"\n#define SETTING_MEM_RESULTS_SIZE                                    L\"MemResultsSize\"\n#define SETTING_MEMORY_LIST_FLAGS                                   L\"MemoryListFlags\"\n#define SETTING_MEMORY_TREE_LIST_COLUMNS                            L\"MemoryTreeListColumns\"\n#define SETTING_MEMORY_TREE_LIST_SORT                               L\"MemoryTreeListSort\"\n#define SETTING_MEMORY_LISTS_WINDOW_POSITION                        L\"MemoryListsWindowPosition\"\n#define SETTING_MEMORY_READ_WRITE_ADDRESS_CHOICES                   L\"MemoryReadWriteAddressChoices\"\n#define SETTING_MEMORY_MODIFIED_WINDOW_POSITION                     L\"MemoryModifiedWindowPosition\"\n#define SETTING_MEMORY_MODIFIED_WINDOW_SIZE                         L\"MemoryModifiedWindowSize\"\n#define SETTING_MEMORY_MODIFIED_LIST_VIEW_COLUMNS                   L\"MemoryModifiedListViewColumns\"\n#define SETTING_MEMORY_MODIFIED_LIST_VIEW_SORT                      L\"MemoryModifiedListViewSort\"\n#define SETTING_MEM_STRINGS_TREE_LIST_COLUMNS                       L\"MemStringsTreeListColumns\"\n#define SETTING_MEM_STRINGS_TREE_LIST_SORT                          L\"MemStringsTreeListSort\"\n#define SETTING_MEM_STRINGS_TREE_LIST_FLAGS                         L\"MemStringsTreeListFlags\"\n#define SETTING_MEM_STRINGS_MINIMUM_LENGTH                          L\"MemStringsMinimumLength\"\n#define SETTING_MEM_STRINGS_WINDOW_POSITION                         L\"MemStringsWindowPosition\"\n#define SETTING_MEM_STRINGS_WINDOW_SIZE                             L\"MemStringsWindowSize\"\n#define SETTING_MINI_INFO_CONTAINER_CLASS_NAME                      L\"MiniInfoContainerClassName\"\n#define SETTING_MINI_INFO_WINDOW_CLASS_NAME                         L\"MiniInfoWindowClassName\"\n#define SETTING_MINI_INFO_WINDOW_ENABLED                            L\"MiniInfoWindowEnabled\"\n#define SETTING_MINI_INFO_WINDOW_OPACITY                            L\"MiniInfoWindowOpacity\"\n#define SETTING_MINI_INFO_WINDOW_PINNED                             L\"MiniInfoWindowPinned\"\n#define SETTING_MINI_INFO_WINDOW_POSITION                           L\"MiniInfoWindowPosition\"\n#define SETTING_MINI_INFO_WINDOW_REFRESH_AUTOMATICALLY              L\"MiniInfoWindowRefreshAutomatically\"\n#define SETTING_MINI_INFO_WINDOW_SIZE                               L\"MiniInfoWindowSize\"\n#define SETTING_MODULE_TREE_LIST_FLAGS                              L\"ModuleTreeListFlags\"\n#define SETTING_MODULE_TREE_LIST_COLUMNS                            L\"ModuleTreeListColumns\"\n#define SETTING_MODULE_TREE_LIST_SORT                               L\"ModuleTreeListSort\"\n#define SETTING_NETWORK_TREE_LIST_COLUMNS                           L\"NetworkTreeListColumns\"\n#define SETTING_NETWORK_TREE_LIST_SORT                              L\"NetworkTreeListSort\"\n#define SETTING_NON_POLL_FLUSH_INTERVAL                             L\"NonPollFlushInterval\"\n#define SETTING_NO_PURGE_PROCESS_RECORDS                            L\"NoPurgeProcessRecords\"\n#define SETTING_OPTIONS_CUSTOM_COLOR_LIST                           L\"OptionsCustomColorList\"\n#define SETTING_OPTIONS_WINDOW_ADVANCED_COLUMNS                     L\"OptionsWindowAdvancedColumns\"\n#define SETTING_OPTIONS_WINDOW_ADVANCED_FLAGS                       L\"OptionsWindowAdvancedFlags\"\n#define SETTING_OPTIONS_WINDOW_POSITION                             L\"OptionsWindowPosition\"\n#define SETTING_OPTIONS_WINDOW_SIZE                                 L\"OptionsWindowSize\"\n#define SETTING_PAGE_FILE_WINDOW_POSITION                           L\"PageFileWindowPosition\"\n#define SETTING_PAGE_FILE_WINDOW_SIZE                               L\"PageFileWindowSize\"\n#define SETTING_PAGE_FILE_LIST_VIEW_COLUMNS                         L\"PageFileListViewColumns\"\n#define SETTING_PLUGIN_MANAGER_TREE_LIST_COLUMNS                    L\"PluginManagerTreeListColumns\"\n#define SETTING_PROCESS_SERVICE_LIST_VIEW_COLUMNS                   L\"ProcessServiceListViewColumns\"\n#define SETTING_PROCESS_TREE_COLUMN_SET_CONFIG                      L\"ProcessTreeColumnSetConfig\"\n#define SETTING_PROCESS_TREE_LIST_COLUMNS                           L\"ProcessTreeListColumns\"\n#define SETTING_PROCESS_TREE_LIST_SORT                              L\"ProcessTreeListSort\"\n#define SETTING_PROCESS_TREE_LIST_NAME_DEFAULT                      L\"ProcessTreeListNameDefault\"\n#define SETTING_PROC_PROP_PAGE                                      L\"ProcPropPage\"\n#define SETTING_PROC_PROP_POSITION                                  L\"ProcPropPosition\"\n#define SETTING_PROC_PROP_SIZE                                      L\"ProcPropSize\"\n#define SETTING_PROC_STAT_PROP_PAGE_GROUP_LIST_VIEW_COLUMNS         L\"ProcStatPropPageGroupListViewColumns\"\n#define SETTING_PROC_STAT_PROP_PAGE_GROUP_LIST_VIEW_SORT            L\"ProcStatPropPageGroupListViewSort\"\n#define SETTING_PROC_STAT_PROP_PAGE_GROUP_STATES                    L\"ProcStatPropPageGroupStates\"\n#define SETTING_PROGRAM_INSPECT_EXECUTABLES                         L\"ProgramInspectExecutables\"\n#define SETTING_PROPAGATE_CPU_USAGE                                 L\"PropagateCpuUsage\"\n#define SETTING_RELEASE_CHANNEL                                     L\"ReleaseChannel\"\n#define SETTING_RUN_AS_ENABLE_AUTO_COMPLETE                         L\"RunAsEnableAutoComplete\"\n#define SETTING_RUN_AS_PROGRAM                                      L\"RunAsProgram\"\n#define SETTING_RUN_AS_USER_NAME                                    L\"RunAsUserName\"\n#define SETTING_RUN_AS_WINDOW_POSITION                              L\"RunAsWindowPosition\"\n#define SETTING_RUN_AS_PACKAGE_WINDOW_POSITION                      L\"RunAsPackageWindowPosition\"\n#define SETTING_RUN_AS_PACKAGE_WINDOW_SIZE                          L\"RunAsPackageWindowSize\"\n#define SETTING_RUN_FILE_DLG_STATE                                  L\"RunFileDlgState\"\n#define SETTING_SAMPLE_COUNT                                        L\"SampleCount\"\n#define SETTING_SAMPLE_COUNT_AUTOMATIC                              L\"SampleCountAutomatic\"\n#define SETTING_SCROLL_TO_NEW_PROCESSES                             L\"ScrollToNewProcesses\"\n#define SETTING_SCROLL_TO_REMOVED_PROCESSES                         L\"ScrollToRemovedProcesses\"\n#define SETTING_SEARCH_ENGINE                                       L\"SearchEngine\"\n#define SETTING_SEGMENT_HEAP_LIST_VIEW_COLUMNS                      L\"SegmentHeapListViewColumns\"\n#define SETTING_SEGMENT_HEAP_LIST_VIEW_SORT                         L\"SegmentHeapListViewSort\"\n#define SETTING_SEGMENT_HEAP_WINDOW_POSITION                        L\"SegmentHeapWindowPosition\"\n#define SETTING_SEGMENT_HEAP_WINDOW_SIZE                            L\"SegmentHeapWindowSize\"\n#define SETTING_SEGMENT_LOCKS_LIST_VIEW_COLUMNS                     L\"SegmentLocksListViewColumns\"\n#define SETTING_SEGMENT_LOCKS_LIST_VIEW_SORT                        L\"SegmentLocksListViewSort\"\n#define SETTING_SEGMENT_LOCKS_WINDOW_POSITION                       L\"SegmentLocksWindowPosition\"\n#define SETTING_SEGMENT_LOCKS_WINDOW_SIZE                           L\"SegmentLocksWindowSize\"\n#define SETTING_SERVICE_WINDOW_POSITION                             L\"ServiceWindowPosition\"\n#define SETTING_SERVICE_LIST_VIEW_COLUMNS                           L\"ServiceListViewColumns\"\n#define SETTING_SERVICE_TREE_LIST_COLUMNS                           L\"ServiceTreeListColumns\"\n#define SETTING_SERVICE_TREE_LIST_SORT                              L\"ServiceTreeListSort\"\n#define SETTING_SESSION_SHADOW_HOTKEY                               L\"SessionShadowHotkey\"\n#define SETTING_SHOW_PLUGIN_LOAD_ERRORS                             L\"ShowPluginLoadErrors\"\n#define SETTING_SHOW_COMMIT_IN_SUMMARY                              L\"ShowCommitInSummary\"\n#define SETTING_SHOW_CPU_BELOW_001                                  L\"ShowCpuBelow001\"\n#define SETTING_SHOW_HEX_ID                                         L\"ShowHexId\"\n#define SETTING_SORT_CHILD_PROCESSES                                L\"SortChildProcesses\"\n#define SETTING_SORT_ROOT_PROCESSES                                 L\"SortRootProcesses\"\n#define SETTING_START_HIDDEN                                        L\"StartHidden\"\n#define SETTING_SYSINFO_SHOW_CPU_SPEED_MHZ                          L\"SysInfoShowCpuSpeedMhz\"\n#define SETTING_SYSINFO_SHOW_CPU_SPEED_PER_CPU                      L\"SysInfoShowCpuSpeedPerCpu\"\n#define SETTING_SYSINFO_WINDOW_ALWAYS_ON_TOP                        L\"SysInfoWindowAlwaysOnTop\"\n#define SETTING_SYSINFO_WINDOW_ONE_GRAPH_PER_CPU                    L\"SysInfoWindowOneGraphPerCpu\"\n#define SETTING_SYSINFO_WINDOW_POSITION                             L\"SysInfoWindowPosition\"\n#define SETTING_SYSINFO_WINDOW_SECTION                              L\"SysInfoWindowSection\"\n#define SETTING_SYSINFO_WINDOW_SIZE                                 L\"SysInfoWindowSize\"\n#define SETTING_SYSINFO_WINDOW_STATE                                L\"SysInfoWindowState\"\n#define SETTING_TASKMGR_WINDOW_STATE                                L\"TaskmgrWindowState\"\n#define SETTING_THEME_WINDOW_FOREGROUND_COLOR                       L\"ThemeWindowForegroundColor\"\n#define SETTING_THEME_WINDOW_BACKGROUND_COLOR                       L\"ThemeWindowBackgroundColor\"\n#define SETTING_THEME_WINDOW_BACKGROUND2_COLOR                      L\"ThemeWindowBackground2Color\"\n#define SETTING_THEME_WINDOW_HIGHLIGHT_COLOR                        L\"ThemeWindowHighlightColor\"\n#define SETTING_THEME_WINDOW_HIGHLIGHT2_COLOR                       L\"ThemeWindowHighlight2Color\"\n#define SETTING_THEME_WINDOW_TEXT_COLOR                             L\"ThemeWindowTextColor\"\n#define SETTING_THIN_ROWS                                           L\"ThinRows\"\n#define SETTING_THREAD_TREE_LIST_COLUMNS                            L\"ThreadTreeListColumns\"\n#define SETTING_THREAD_TREE_LIST_SORT                               L\"ThreadTreeListSort\"\n#define SETTING_THREAD_TREE_LIST_FLAGS                              L\"ThreadTreeListFlags\"\n#define SETTING_THREAD_STACK_TREE_LIST_COLUMNS                      L\"ThreadStackTreeListColumns\"\n#define SETTING_THREAD_STACK_WINDOW_SIZE                            L\"ThreadStackWindowSize\"\n#define SETTING_TOKEN_WINDOW_POSITION                               L\"TokenWindowPosition\"\n#define SETTING_TOKEN_WINDOW_SIZE                                   L\"TokenWindowSize\"\n#define SETTING_TOKEN_GROUPS_LIST_VIEW_COLUMNS                      L\"TokenGroupsListViewColumns\"\n#define SETTING_TOKEN_GROUPS_LIST_VIEW_STATES                       L\"TokenGroupsListViewStates\"\n#define SETTING_TOKEN_GROUPS_LIST_VIEW_SORT                         L\"TokenGroupsListViewSort\"\n#define SETTING_TOKEN_PRIVILEGES_LIST_VIEW_COLUMNS                  L\"TokenPrivilegesListViewColumns\"\n#define SETTING_TREE_LIST_BORDER_ENABLE                             L\"TreeListBorderEnable\"\n#define SETTING_TREE_LIST_CUSTOM_COLORS_ENABLE                      L\"TreeListCustomColorsEnable\"\n#define SETTING_TREE_LIST_CUSTOM_COLOR_TEXT                         L\"TreeListCustomColorText\"\n#define SETTING_TREE_LIST_CUSTOM_COLOR_FOCUS                        L\"TreeListCustomColorFocus\"\n#define SETTING_TREE_LIST_CUSTOM_COLOR_SELECTION                    L\"TreeListCustomColorSelection\"\n#define SETTING_TREE_LIST_CUSTOM_ROW_SIZE                           L\"TreeListCustomRowSize\"\n#define SETTING_TREE_LIST_ENABLE_HEADER_TOTALS                      L\"TreeListEnableHeaderTotals\"\n#define SETTING_TREE_LIST_ENABLE_DRAG_REORDER                       L\"TreeListEnableDragReorder\"\n#define SETTING_UPDATE_INTERVAL                                     L\"UpdateInterval\"\n#define SETTING_USER_LIST_TREE_LIST_COLUMNS                         L\"UserListTreeListColumns\"\n#define SETTING_USER_LIST_WINDOW_POSITION                           L\"UserListWindowPosition\"\n#define SETTING_USER_LIST_WINDOW_SIZE                               L\"UserListWindowSize\"\n#define SETTING_WMI_PROVIDER_ENABLE_HIDDEN_MENU                     L\"WmiProviderEnableHiddenMenu\"\n#define SETTING_WMI_PROVIDER_ENABLE_TOOLTIP_SUPPORT                 L\"WmiProviderEnableTooltipSupport\"\n#define SETTING_WMI_PROVIDER_TREE_LIST_COLUMNS                      L\"WmiProviderTreeListColumns\"\n#define SETTING_WMI_PROVIDER_TREE_LIST_SORT                         L\"WmiProviderTreeListSort\"\n#define SETTING_WMI_PROVIDER_TREE_LIST_FLAGS                        L\"WmiProviderTreeListFlags\"\n#define SETTING_VDM_HOST_LIST_VIEW_COLUMNS                          L\"VdmHostListViewColumns\"\n#define SETTING_ZOMBIE_PROCESSES_LIST_VIEW_COLUMNS                  L\"ZombieProcessesListViewColumns\"\n#define SETTING_ZOMBIE_PROCESSES_WINDOW_POSITION                    L\"ZombieProcessesWindowPosition\"\n#define SETTING_ZOMBIE_PROCESSES_WINDOW_SIZE                        L\"ZombieProcessesWindowSize\"\n#define SETTING_COLOR_NEW                                           L\"ColorNew\"\n#define SETTING_COLOR_REMOVED                                       L\"ColorRemoved\"\n#define SETTING_USE_COLOR_OWN_PROCESSES                             L\"UseColorOwnProcesses\"\n#define SETTING_COLOR_OWN_PROCESSES                                 L\"ColorOwnProcesses\"\n#define SETTING_USE_COLOR_SYSTEM_PROCESSES                          L\"UseColorSystemProcesses\"\n#define SETTING_COLOR_SYSTEM_PROCESSES                              L\"ColorSystemProcesses\"\n#define SETTING_USE_COLOR_SERVICE_PROCESSES                         L\"UseColorServiceProcesses\"\n#define SETTING_COLOR_SERVICE_PROCESSES                             L\"ColorServiceProcesses\"\n#define SETTING_USE_COLOR_BACKGROUND_PROCESSES                      L\"UseColorBackgroundProcesses\"\n#define SETTING_COLOR_BACKGROUND_PROCESSES                          L\"ColorBackgroundProcesses\"\n#define SETTING_USE_COLOR_JOB_PROCESSES                             L\"UseColorJobProcesses\"\n#define SETTING_COLOR_JOB_PROCESSES                                 L\"ColorJobProcesses\"\n#define SETTING_USE_COLOR_WOW64_PROCESSES                           L\"UseColorWow64Processes\"\n#define SETTING_COLOR_WOW64_PROCESSES                               L\"ColorWow64Processes\"\n#define SETTING_USE_COLOR_DEBUGGED_PROCESSES                        L\"UseColorDebuggedProcesses\"\n#define SETTING_COLOR_DEBUGGED_PROCESSES                            L\"ColorDebuggedProcesses\"\n#define SETTING_USE_COLOR_ELEVATED_PROCESSES                        L\"UseColorElevatedProcesses\"\n#define SETTING_COLOR_ELEVATED_PROCESSES                            L\"ColorElevatedProcesses\"\n#define SETTING_USE_COLOR_HANDLE_FILTERED                           L\"UseColorHandleFiltered\"\n#define SETTING_COLOR_HANDLE_FILTERED                               L\"ColorHandleFiltered\"\n#define SETTING_USE_COLOR_IMMERSIVE_PROCESSES                       L\"UseColorImmersiveProcesses\"\n#define SETTING_COLOR_IMMERSIVE_PROCESSES                           L\"ColorImmersiveProcesses\"\n#define SETTING_USE_COLOR_UI_ACCESS_PROCESSES                       L\"UseColorUIAccessProcesses\"\n#define SETTING_COLOR_UI_ACCESS_PROCESSES                           L\"ColorUIAccessProcesses\"\n#define SETTING_USE_COLOR_PICO_PROCESSES                            L\"UseColorPicoProcesses\"\n#define SETTING_COLOR_PICO_PROCESSES                                L\"ColorPicoProcesses\"\n#define SETTING_USE_COLOR_SUSPENDED                                 L\"UseColorSuspended\"\n#define SETTING_COLOR_SUSPENDED                                     L\"ColorSuspended\"\n#define SETTING_USE_COLOR_DOT_NET                                   L\"UseColorDotNet\"\n#define SETTING_COLOR_DOT_NET                                       L\"ColorDotNet\"\n#define SETTING_USE_COLOR_PACKED                                    L\"UseColorPacked\"\n#define SETTING_COLOR_PACKED                                        L\"ColorPacked\"\n#define SETTING_USE_COLOR_LOW_IMAGE_COHERENCY                       L\"UseColorLowImageCoherency\"\n#define SETTING_COLOR_LOW_IMAGE_COHERENCY                           L\"ColorLowImageCoherency\"\n#define SETTING_USE_COLOR_PARTIALLY_SUSPENDED                       L\"UseColorPartiallySuspended\"\n#define SETTING_COLOR_PARTIALLY_SUSPENDED                           L\"ColorPartiallySuspended\"\n#define SETTING_USE_COLOR_GUI_THREADS                               L\"UseColorGuiThreads\"\n#define SETTING_COLOR_GUI_THREADS                                   L\"ColorGuiThreads\"\n#define SETTING_USE_COLOR_RELOCATED_MODULES                         L\"UseColorRelocatedModules\"\n#define SETTING_COLOR_RELOCATED_MODULES                             L\"ColorRelocatedModules\"\n#define SETTING_USE_COLOR_PROTECTED_HANDLES                         L\"UseColorProtectedHandles\"\n#define SETTING_COLOR_PROTECTED_HANDLES                             L\"ColorProtectedHandles\"\n#define SETTING_USE_COLOR_PROTECTED_INHERIT_HANDLES                 L\"UseColorProtectedInheritHandles\"\n#define SETTING_COLOR_PROTECTED_INHERIT_HANDLES                     L\"ColorProtectedInheritHandles\"\n#define SETTING_USE_COLOR_PROTECTED_PROCESS                         L\"UseColorProtectedProcess\"\n#define SETTING_COLOR_PROTECTED_PROCESS                             L\"ColorProtectedProcess\"\n#define SETTING_USE_COLOR_INHERIT_HANDLES                           L\"UseColorInheritHandles\"\n#define SETTING_COLOR_INHERIT_HANDLES                               L\"ColorInheritHandles\"\n#define SETTING_USE_COLOR_EFFICIENCY_MODE                           L\"UseColorEfficiencyMode\"\n#define SETTING_COLOR_EFFICIENCY_MODE                               L\"ColorEfficiencyMode\"\n#define SETTING_USE_COLOR_SERVICE_DISABLED                          L\"UseColorServiceDisabled\"\n#define SETTING_COLOR_SERVICE_DISABLED                              L\"ColorServiceDisabled\"\n#define SETTING_USE_COLOR_SERVICE_STOP                              L\"UseColorServiceStop\"\n#define SETTING_COLOR_SERVICE_STOP                                  L\"ColorServiceStop\"\n#define SETTING_USE_COLOR_UNKNOWN                                   L\"UseColorUnknown\"\n#define SETTING_COLOR_UNKNOWN                                       L\"ColorUnknown\"\n#define SETTING_USE_COLOR_SYSTEM_THREAD_STACK                       L\"UseColorSystemThreadStack\"\n#define SETTING_COLOR_SYSTEM_THREAD_STACK                           L\"ColorSystemThreadStack\"\n#define SETTING_USE_COLOR_USER_THREAD_STACK                         L\"UseColorUserThreadStack\"\n#define SETTING_COLOR_USER_THREAD_STACK                             L\"ColorUserThreadStack\"\n#define SETTING_USE_COLOR_INLINE_THREAD_STACK                       L\"UseColorInlineThreadStack\"\n#define SETTING_COLOR_INLINE_THREAD_STACK                           L\"ColorInlineThreadStack\"\n#define SETTING_GRAPH_SHOW_TEXT                                     L\"GraphShowText\"\n#define SETTING_GRAPH_COLOR_MODE                                    L\"GraphColorMode\"\n#define SETTING_COLOR_CPU_KERNEL                                    L\"ColorCpuKernel\"\n#define SETTING_COLOR_CPU_USER                                      L\"ColorCpuUser\"\n#define SETTING_COLOR_IO_READ_OTHER                                 L\"ColorIoReadOther\"\n#define SETTING_COLOR_IO_WRITE                                      L\"ColorIoWrite\"\n#define SETTING_COLOR_PRIVATE                                       L\"ColorPrivate\"\n#define SETTING_COLOR_PHYSICAL                                      L\"ColorPhysical\"\n#define SETTING_COLOR_POWER_USAGE                                   L\"ColorPowerUsage\"\n#define SETTING_COLOR_TEMPERATURE                                   L\"ColorTemperature\"\n#define SETTING_COLOR_FAN_RPM                                       L\"ColorFanRpm\"\n\n#define SETTING_KSI_ENABLE                                          L\"KsiEnable\"\n#define SETTING_KSI_ENABLE_WARNINGS                                 L\"KsiEnableWarnings\"\n#define SETTING_KSI_SERVICE_NAME                                    L\"KsiServiceName\"\n#define SETTING_KSI_OBJECT_NAME                                     L\"KsiObjectName\"\n#define SETTING_KSI_PORT_NAME                                       L\"KsiPortName\"\n#define SETTING_KSI_ALTITUDE                                        L\"KsiAltitude\"\n#define SETTING_KSI_SYSTEM_PROCESS_NAME                             L\"KsiSystemProcessName\"\n#define SETTING_KSI_DISABLE_IMAGE_LOAD_PROTECTION                   L\"KsiDisableImageLoadProtection\"\n#define SETTING_KSI_ENABLE_SPLASH_SCREEN                            L\"KsiEnableSplashScreen\"\n#define SETTING_KSI_ENABLE_LOAD_NATIVE                              L\"KsiEnableLoadNative\"\n#define SETTING_KSI_ENABLE_LOAD_FILTER                              L\"KsiEnableLoadFilter\"\n#define SETTING_KSI_UNLOAD_ON_EXIT                                  L\"KsiUnloadOnExit\"\n#define SETTING_KSI_RANDOMIZED_POOL_TAG                             L\"KsiRandomizedPoolTag\"\n#define SETTING_KSI_ENABLE_UNLOAD_PROTECTION                        L\"KsiEnableUnloadProtection\"\n#define SETTING_KSI_DYN_DATA_NO_EMBEDDED                            L\"KsiDynDataNoEmbedded\"\n#define SETTING_KSI_DISABLE_SYSTEM_PROCESS                          L\"KsiDisableSystemProcess\"\n#define SETTING_KSI_DISABLE_THREAD_NAMES                            L\"KsiDisableThreadNames\"\n#define SETTING_KSI_CLIENT_PROCESS_PROTECTION_LEVEL                 L\"KsiClientProcessProtectionLevel\"\n#define SETTING_KSI_PREVIOUS_TEMPORARY_DRIVER_FILE                  L\"KsiPreviousTemporaryDriverFile\"\n#define SETTING_KSI_ENABLE_FS_FEATURE_OFFLOAD_READ                  L\"KsiEnableFsFeatureOffloadRead\"\n#define SETTING_KSI_ENABLE_FS_FEATURE_OFFLOAD_WRITE                 L\"KsiEnableFsFeatureOffloadWrite\"\n#define SETTING_KSI_ENABLE_FS_FEATURE_QUERY_OPEN                    L\"KsiEnableFsFeatureQueryOpen\"\n#define SETTING_KSI_ENABLE_FS_FEATURE_BYPASS_IO                     L\"KsiEnableFsFeatureBypassIO\"\n#define SETTING_KSI_RING_BUFFER_LENGTH                              L\"KsiRingBufferLength\"\n#define SETTING_ENABLE_PROCESS_MONITOR                              L\"EnableProcessMonitor\"\n#define SETTING_PROCESS_MONITOR_LOOKBACK                            L\"ProcessMonitorLookback\"\n#define SETTING_PROCESS_MONITOR_CACHE_LIMIT                         L\"ProcessMonitorCacheLimit\"\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/phsvc.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2022\n *\n */\n\n#ifndef PH_PHSVC_H\n#define PH_PHSVC_H\n\n#include <phsvcapi.h>\n\n#define PHSVC_SHARED_SECTION_SIZE (512 * 1024)\n\n// svcmain\n\ntypedef struct _PHSVC_STOP\n{\n    BOOLEAN Stop;\n    HANDLE Event1;\n    HANDLE Event2;\n} PHSVC_STOP, *PPHSVC_STOP;\n\nNTSTATUS PhSvcMain(\n    _In_opt_ PPH_STRING PortName,\n    _Inout_opt_ PPHSVC_STOP Stop\n    );\n\nVOID PhSvcStop(\n    _Inout_ PPHSVC_STOP Stop\n    );\n\n// svcclient\n\ntypedef struct _PHSVC_CLIENT\n{\n    LIST_ENTRY ListEntry;\n\n    PH_EVENT ReadyEvent;\n    CLIENT_ID ClientId;\n    HANDLE PortHandle;\n    PVOID ClientViewBase;\n    PVOID ClientViewLimit;\n} PHSVC_CLIENT, *PPHSVC_CLIENT;\n\nPPHSVC_CLIENT PhSvcCreateClient(\n    _In_opt_ PCLIENT_ID ClientId\n    );\n\nPPHSVC_CLIENT PhSvcReferenceClientByClientId(\n    _In_ PCLIENT_ID ClientId\n    );\n\nPPHSVC_CLIENT PhSvcGetCurrentClient(\n    VOID\n    );\n\nBOOLEAN PhSvcAttachClient(\n    _In_ PPHSVC_CLIENT Client\n    );\n\nVOID PhSvcDetachClient(\n    _In_ PPHSVC_CLIENT Client\n    );\n\n// svcapiport\n\ntypedef struct _PHSVC_THREAD_CONTEXT\n{\n    PPHSVC_CLIENT CurrentClient;\n    PPHSVC_CLIENT OldClient;\n} PHSVC_THREAD_CONTEXT, *PPHSVC_THREAD_CONTEXT;\n\nNTSTATUS PhSvcApiPortInitialization(\n    _In_ PUNICODE_STRING PortName\n    );\n\nPPHSVC_THREAD_CONTEXT PhSvcGetCurrentThreadContext(\n    VOID\n    );\n\nVOID PhSvcHandleConnectionRequest(\n    _In_ PPORT_MESSAGE PortMessage\n    );\n\n// svcapi\n\ntypedef _Function_class_(PHSVC_API_PROCEDURE)\nNTSTATUS NTAPI PHSVC_API_PROCEDURE(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\ntypedef PHSVC_API_PROCEDURE* PPHSVC_API_PROCEDURE;\ntypedef CONST PPHSVC_API_PROCEDURE PCPHSVC_API_PROCEDURE;\n\nVOID PhSvcDispatchApiCall(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload,\n    _Out_ PHANDLE ReplyPortHandle\n    );\n\nPVOID PhSvcValidateString(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ ULONG Alignment\n    );\n\n_Function_class_(PHSVC_SERVER_PROBE_BUFFER)\nNTSTATUS PhSvcProbeBuffer(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ ULONG Alignment,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PVOID *Pointer\n    );\n\n_Function_class_(PHSVC_SERVER_CAPTURE_BUFFER)\nNTSTATUS PhSvcCaptureBuffer(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PVOID *CapturedBuffer\n    );\n\nNTSTATUS PhSvcCaptureString(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PPH_STRING *CapturedString\n    );\n\nNTSTATUS PhSvcCaptureSid(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PSID *CapturedSid\n    );\n\nNTSTATUS PhSvcCaptureSecurityDescriptor(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _In_ SECURITY_INFORMATION RequiredInformation,\n    _Out_ PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor\n    );\n\nNTSTATUS PhSvcApiDefault(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\n_Function_class_(PHSVC_API_PROCEDURE)\nNTSTATUS PhSvcApiPlugin(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiExecuteRunAsCommand(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiUnloadDriver(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiControlProcess(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiControlService(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiCreateService(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiChangeServiceConfig(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiChangeServiceConfig2(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiSetTcpEntry(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiControlThread(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiAddAccountRight(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiInvokeRunAsService(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiIssueMemoryListCommand(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiPostMessage(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiSendMessage(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiCreateProcessIgnoreIfeoDebugger(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiSetServiceSecurity(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiWriteMiniDumpProcess(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiQueryProcessHeapInformation(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\nNTSTATUS PhSvcApiCreateProcessForKsi(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/phsvcapi.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2015\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_PHSVCAPI_H\n#define PH_PHSVCAPI_H\n\n#define PHSVC_PORT_NAME (L\"\\\\BaseNamedObjects\\\\SiSvcApiPort\")\n#define PHSVC_WOW64_PORT_NAME (L\"\\\\BaseNamedObjects\\\\SiSvcWow64ApiPort\")\n\ntypedef enum _PHSVC_API_NUMBER\n{\n    PhSvcInvalidApiNumber = 0,\n    PhSvcPluginApiNumber = 1,\n    PhSvcExecuteRunAsCommandApiNumber = 2,\n    PhSvcUnloadDriverApiNumber = 3,\n    PhSvcControlProcessApiNumber = 4,\n    PhSvcControlServiceApiNumber = 5,\n    PhSvcCreateServiceApiNumber = 6,\n    PhSvcChangeServiceConfigApiNumber = 7,\n    PhSvcChangeServiceConfig2ApiNumber = 8,\n    PhSvcSetTcpEntryApiNumber = 9,\n    PhSvcControlThreadApiNumber = 10,\n    PhSvcAddAccountRightApiNumber = 11,\n    PhSvcInvokeRunAsServiceApiNumber = 12,\n    PhSvcIssueMemoryListCommandApiNumber = 13,\n    PhSvcPostMessageApiNumber = 14,\n    PhSvcSendMessageApiNumber = 15,\n    PhSvcCreateProcessIgnoreIfeoDebuggerApiNumber = 16,\n    PhSvcSetServiceSecurityApiNumber = 17,\n    PhSvcWriteMiniDumpProcessApiNumber = 18, // WOW64 compatible\n    PhSvcQueryProcessDebugInformationApiNumber = 19, // WOW64 compatible\n    PhSvcCreateProcessForKsi = 20,\n    PhSvcMaximumApiNumber\n} PHSVC_API_NUMBER, *PPHSVC_API_NUMBER;\n\ntypedef struct _PHSVC_API_CONNECTINFO\n{\n    ULONG ServerProcessId;\n} PHSVC_API_CONNECTINFO, *PPHSVC_API_CONNECTINFO;\n\ntypedef union _PHSVC_API_PLUGIN\n{\n    struct\n    {\n        PH_RELATIVE_STRINGREF ApiId;\n        ULONG Data[30];\n    } i;\n    struct\n    {\n        ULONG Data[32];\n    } o;\n} PHSVC_API_PLUGIN, *PPHSVC_API_PLUGIN;\n\ntypedef union _PHSVC_API_EXECUTERUNASCOMMAND\n{\n    struct\n    {\n        ULONG ProcessId;\n        PH_RELATIVE_STRINGREF UserName;\n        PH_RELATIVE_STRINGREF Password;\n        ULONG LogonType;\n        ULONG SessionId;\n        PH_RELATIVE_STRINGREF CurrentDirectory;\n        PH_RELATIVE_STRINGREF CommandLine;\n        PH_RELATIVE_STRINGREF FileName;\n        PH_RELATIVE_STRINGREF DesktopName;\n        BOOLEAN UseLinkedToken;\n        PH_RELATIVE_STRINGREF ServiceName;\n        BOOLEAN CreateSuspendedProcess;\n        BOOLEAN CreateUIAccessProcess;\n        HWND WindowHandle;\n    } i;\n} PHSVC_API_EXECUTERUNASCOMMAND, *PPHSVC_API_EXECUTERUNASCOMMAND;\n\ntypedef union _PHSVC_API_UNLOADDRIVER\n{\n    struct\n    {\n        PVOID BaseAddress;\n        PH_RELATIVE_STRINGREF Name;\n        PH_RELATIVE_STRINGREF FileName;\n    } i;\n} PHSVC_API_UNLOADDRIVER, *PPHSVC_API_UNLOADDRIVER;\n\ntypedef enum _PHSVC_API_CONTROLPROCESS_COMMAND\n{\n    PhSvcControlProcessTerminate = 1,\n    PhSvcControlProcessSuspend,\n    PhSvcControlProcessResume,\n    PhSvcControlProcessPriority,\n    PhSvcControlProcessIoPriority\n} PHSVC_API_CONTROLPROCESS_COMMAND;\n\ntypedef union _PHSVC_API_CONTROLPROCESS\n{\n    struct\n    {\n        HANDLE ProcessId;\n        PHSVC_API_CONTROLPROCESS_COMMAND Command;\n        ULONG Argument;\n    } i;\n} PHSVC_API_CONTROLPROCESS, *PPHSVC_API_CONTROLPROCESS;\n\ntypedef enum _PHSVC_API_CONTROLSERVICE_COMMAND\n{\n    PhSvcControlServiceStart = 1,\n    PhSvcControlServiceContinue,\n    PhSvcControlServicePause,\n    PhSvcControlServiceStop,\n    PhSvcControlServiceDelete,\n    PhSvcControlServiceRestart\n} PHSVC_API_CONTROLSERVICE_COMMAND;\n\ntypedef union _PHSVC_API_CONTROLSERVICE\n{\n    struct\n    {\n        PH_RELATIVE_STRINGREF ServiceName;\n        PHSVC_API_CONTROLSERVICE_COMMAND Command;\n    } i;\n} PHSVC_API_CONTROLSERVICE, *PPHSVC_API_CONTROLSERVICE;\n\ntypedef union _PHSVC_API_CREATESERVICE\n{\n    struct\n    {\n        // ServiceName is the only required string.\n        PH_RELATIVE_STRINGREF ServiceName;\n        PH_RELATIVE_STRINGREF DisplayName;\n        ULONG ServiceType;\n        ULONG StartType;\n        ULONG ErrorControl;\n        PH_RELATIVE_STRINGREF BinaryPathName;\n        PH_RELATIVE_STRINGREF LoadOrderGroup;\n        PH_RELATIVE_STRINGREF Dependencies;\n        PH_RELATIVE_STRINGREF ServiceStartName;\n        PH_RELATIVE_STRINGREF Password;\n        BOOLEAN TagIdSpecified;\n    } i;\n    struct\n    {\n        ULONG TagId;\n    } o;\n} PHSVC_API_CREATESERVICE, *PPHSVC_API_CREATESERVICE;\n\ntypedef union _PHSVC_API_CHANGESERVICECONFIG\n{\n    struct\n    {\n        PH_RELATIVE_STRINGREF ServiceName;\n        ULONG ServiceType;\n        ULONG StartType;\n        ULONG ErrorControl;\n        PH_RELATIVE_STRINGREF BinaryPathName;\n        PH_RELATIVE_STRINGREF LoadOrderGroup;\n        PH_RELATIVE_STRINGREF Dependencies;\n        PH_RELATIVE_STRINGREF ServiceStartName;\n        PH_RELATIVE_STRINGREF Password;\n        PH_RELATIVE_STRINGREF DisplayName;\n        BOOLEAN TagIdSpecified;\n    } i;\n    struct\n    {\n        ULONG TagId;\n    } o;\n} PHSVC_API_CHANGESERVICECONFIG, *PPHSVC_API_CHANGESERVICECONFIG;\n\ntypedef union _PHSVC_API_CHANGESERVICECONFIG2\n{\n    struct\n    {\n        PH_RELATIVE_STRINGREF ServiceName;\n        ULONG InfoLevel;\n        PH_RELATIVE_STRINGREF Info;\n    } i;\n} PHSVC_API_CHANGESERVICECONFIG2, *PPHSVC_API_CHANGESERVICECONFIG2;\n\ntypedef union _PHSVC_API_SETTCPENTRY\n{\n    struct\n    {\n        ULONG State;\n        ULONG LocalAddress;\n        ULONG LocalPort;\n        ULONG RemoteAddress;\n        ULONG RemotePort;\n    } i;\n} PHSVC_API_SETTCPENTRY, *PPHSVC_API_SETTCPENTRY;\n\ntypedef enum _PHSVC_API_CONTROLTHREAD_COMMAND\n{\n    PhSvcControlThreadTerminate = 1,\n    PhSvcControlThreadSuspend,\n    PhSvcControlThreadResume,\n    PhSvcControlThreadIoPriority\n} PHSVC_API_CONTROLTHREAD_COMMAND;\n\ntypedef union _PHSVC_API_CONTROLTHREAD\n{\n    struct\n    {\n        HANDLE ThreadId;\n        PHSVC_API_CONTROLTHREAD_COMMAND Command;\n        ULONG Argument;\n    } i;\n} PHSVC_API_CONTROLTHREAD, *PPHSVC_API_CONTROLTHREAD;\n\ntypedef union _PHSVC_API_ADDACCOUNTRIGHT\n{\n    struct\n    {\n        PH_RELATIVE_STRINGREF AccountSid;\n        PH_RELATIVE_STRINGREF UserRight;\n    } i;\n} PHSVC_API_ADDACCOUNTRIGHT, *PPHSVC_API_ADDACCOUNTRIGHT;\n\ntypedef union _PHSVC_API_ISSUEMEMORYLISTCOMMAND\n{\n    struct\n    {\n        SYSTEM_MEMORY_LIST_COMMAND Command;\n    } i;\n} PHSVC_API_ISSUEMEMORYLISTCOMMAND, *PPHSVC_API_ISSUEMEMORYLISTCOMMAND;\n\ntypedef union _PHSVC_API_POSTMESSAGE\n{\n    struct\n    {\n        HWND hWnd;\n        UINT Msg;\n        WPARAM wParam;\n        LPARAM lParam;\n    } i;\n} PHSVC_API_POSTMESSAGE, *PPHSVC_API_POSTMESSAGE;\n\ntypedef union _PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER\n{\n    struct\n    {\n        PH_RELATIVE_STRINGREF FileName;\n        PH_RELATIVE_STRINGREF CommandLine;\n    } i;\n} PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER, *PPHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER;\n\ntypedef union _PHSVC_API_SETSERVICESECURITY\n{\n    struct\n    {\n        PH_RELATIVE_STRINGREF ServiceName;\n        SECURITY_INFORMATION SecurityInformation;\n        PH_RELATIVE_STRINGREF SecurityDescriptor;\n    } i;\n} PHSVC_API_SETSERVICESECURITY, *PPHSVC_API_SETSERVICESECURITY;\n\ntypedef union _PHSVC_API_WRITEMINIDUMPPROCESS\n{\n    struct\n    {\n        ULONG LocalProcessHandle;\n        ULONG ProcessId;\n        ULONG LocalFileHandle;\n        ULONG DumpType;\n    } i;\n} PHSVC_API_WRITEMINIDUMPPROCESS, *PPHSVC_API_WRITEMINIDUMPPROCESS;\n\ntypedef union _PHSVC_API_PROCESSHEAPINFORMATION\n{\n    struct\n    {\n        ULONG ProcessId;\n        PH_RELATIVE_STRINGREF Data; // out\n    } i;\n    struct\n    {\n        ULONG DataLength;\n    } o;\n} PHSVC_API_PROCESSHEAPINFORMATION, *PPHSVC_API_PROCESSHEAPINFORMATION;\n\ntypedef union _PHSVC_API_CREATEPROCESSFORKSI\n{\n    struct\n    {\n        PH_RELATIVE_STRINGREF CommandLine;\n        ULONG64 MitigationFlags[2];\n    } i;\n} PHSVC_API_CREATEPROCESSFORKSI, *PPHSVC_API_CREATEPROCESSFORKSI;\n\ntypedef union _PHSVC_API_PAYLOAD\n{\n    PHSVC_API_CONNECTINFO ConnectInfo;\n    struct\n    {\n        PHSVC_API_NUMBER ApiNumber;\n        NTSTATUS ReturnStatus;\n\n        union\n        {\n            PHSVC_API_PLUGIN Plugin;\n            PHSVC_API_EXECUTERUNASCOMMAND ExecuteRunAsCommand;\n            PHSVC_API_UNLOADDRIVER UnloadDriver;\n            PHSVC_API_CONTROLPROCESS ControlProcess;\n            PHSVC_API_CONTROLSERVICE ControlService;\n            PHSVC_API_CREATESERVICE CreateService;\n            PHSVC_API_CHANGESERVICECONFIG ChangeServiceConfig;\n            PHSVC_API_CHANGESERVICECONFIG2 ChangeServiceConfig2;\n            PHSVC_API_SETTCPENTRY SetTcpEntry;\n            PHSVC_API_CONTROLTHREAD ControlThread;\n            PHSVC_API_ADDACCOUNTRIGHT AddAccountRight;\n            PHSVC_API_ISSUEMEMORYLISTCOMMAND IssueMemoryListCommand;\n            PHSVC_API_POSTMESSAGE PostMessage;\n            PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER CreateProcessIgnoreIfeoDebugger;\n            PHSVC_API_SETSERVICESECURITY SetServiceSecurity;\n            PHSVC_API_WRITEMINIDUMPPROCESS WriteMiniDumpProcess;\n            PHSVC_API_PROCESSHEAPINFORMATION QueryProcessHeap;\n            PHSVC_API_CREATEPROCESSFORKSI CreateProcessForKsi;\n        } u;\n    };\n} PHSVC_API_PAYLOAD, *PPHSVC_API_PAYLOAD;\n\ntypedef struct _PHSVC_API_MSG\n{\n    PORT_MESSAGE h;\n    PHSVC_API_PAYLOAD p;\n} PHSVC_API_MSG, *PPHSVC_API_MSG;\n\ntypedef struct _PHSVC_API_MSG64\n{\n    PORT_MESSAGE64 h;\n    PHSVC_API_PAYLOAD p;\n} PHSVC_API_MSG64, *PPHSVC_API_MSG64;\n\nC_ASSERT(FIELD_OFFSET(PHSVC_API_PAYLOAD, u) == 8);\nC_ASSERT(sizeof(PHSVC_API_MSG) <= PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH);\nC_ASSERT(sizeof(PHSVC_API_MSG64) <= PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH);\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/phsvccl.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_PHSVCCL_H\n#define PH_PHSVCCL_H\n\n#include <phsvcapi.h>\n\nextern HANDLE PhSvcClServerProcessId;\n\nNTSTATUS PhSvcConnectToServer(\n    _In_ PUNICODE_STRING PortName,\n    _In_opt_ SIZE_T PortSectionSize\n    );\n\nVOID PhSvcDisconnectFromServer(\n    VOID\n    );\n\nVOID PhSvcpFreeHeap(\n    _In_ PVOID Memory\n    );\n\n_Success_(return != NULL)\nPVOID PhSvcpCreateString(\n    _In_opt_ PCWSTR String,\n    _In_ SIZE_T Length,\n    _Out_ PPH_RELATIVE_STRINGREF StringRef\n    );\n\nNTSTATUS PhSvcCallPlugin(\n    _In_ PPH_STRINGREF ApiId,\n    _In_reads_bytes_opt_(InLength) PVOID InBuffer,\n    _In_ ULONG InLength,\n    _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer,\n    _In_ ULONG OutLength\n    );\n\nNTSTATUS PhSvcCallExecuteRunAsCommand(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    );\n\nNTSTATUS PhSvcCallUnloadDriver(\n    _In_opt_ PVOID BaseAddress,\n    _In_opt_ PCWSTR Name,\n    _In_opt_ PCWSTR FileName\n    );\n\nNTSTATUS PhSvcCallControlProcess(\n    _In_opt_ HANDLE ProcessId,\n    _In_ PHSVC_API_CONTROLPROCESS_COMMAND Command,\n    _In_ ULONG Argument\n    );\n\nNTSTATUS PhSvcCallControlService(\n    _In_ PCWSTR ServiceName,\n    _In_ PHSVC_API_CONTROLSERVICE_COMMAND Command\n    );\n\nNTSTATUS PhSvcCallCreateService(\n    _In_ PCWSTR ServiceName,\n    _In_opt_ PCWSTR DisplayName,\n    _In_ ULONG ServiceType,\n    _In_ ULONG StartType,\n    _In_ ULONG ErrorControl,\n    _In_opt_ PCWSTR BinaryPathName,\n    _In_opt_ PCWSTR LoadOrderGroup,\n    _Out_opt_ PULONG TagId,\n    _In_opt_ PCWSTR Dependencies,\n    _In_opt_ PCWSTR ServiceStartName,\n    _In_opt_ PCWSTR Password\n    );\n\n// begin_phapppub\nPHAPPAPI\nNTSTATUS PhSvcCallChangeServiceConfig(\n    _In_ PCWSTR ServiceName,\n    _In_ ULONG ServiceType,\n    _In_ ULONG StartType,\n    _In_ ULONG ErrorControl,\n    _In_opt_ PCWSTR BinaryPathName,\n    _In_opt_ PCWSTR LoadOrderGroup,\n    _Out_opt_ PULONG TagId,\n    _In_opt_ PCWSTR Dependencies,\n    _In_opt_ PCWSTR ServiceStartName,\n    _In_opt_ PCWSTR Password,\n    _In_opt_ PCWSTR DisplayName\n    );\n\nPHAPPAPI\nNTSTATUS PhSvcCallChangeServiceConfig2(\n    _In_ PCWSTR ServiceName,\n    _In_ ULONG InfoLevel,\n    _In_ PVOID Info\n    );\n// end_phapppub\n\nNTSTATUS PhSvcCallSetTcpEntry(\n    _In_ PVOID TcpRow\n    );\n\nNTSTATUS PhSvcCallControlThread(\n    _In_ HANDLE ThreadId,\n    _In_ PHSVC_API_CONTROLTHREAD_COMMAND Command,\n    _In_ ULONG Argument\n    );\n\nNTSTATUS PhSvcCallAddAccountRight(\n    _In_ PSID AccountSid,\n    _In_ PUNICODE_STRING UserRight\n    );\n\nNTSTATUS PhSvcCallInvokeRunAsService(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    );\n\nNTSTATUS PhSvcCallIssueMemoryListCommand(\n    _In_ SYSTEM_MEMORY_LIST_COMMAND Command\n    );\n\n// begin_phapppub\nPHAPPAPI\nNTSTATUS PhSvcCallPostMessage(\n    _In_opt_ HWND hWnd,\n    _In_ UINT Msg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nPHAPPAPI\nNTSTATUS PhSvcCallSendMessage(\n    _In_opt_ HWND hWnd,\n    _In_ UINT Msg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n// end_phapppub\n\nNTSTATUS PhSvcCallCreateProcessIgnoreIfeoDebugger(\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR CommandLine\n    );\n\nNTSTATUS PhSvcCallSetServiceSecurity(\n    _In_ PCWSTR ServiceName,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nNTSTATUS PhSvcCallWriteMiniDumpProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG DumpType\n    );\n\nNTSTATUS PhSvcCallQueryProcessHeapInformation(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING* HeapInformation\n    );\n\nNTSTATUS PhSvcCallCreateProcessForKsi(\n    _In_ PCWSTR CommandLine,\n    _In_ ULONG64 MitigationFlags[2]\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/phuisup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *\n */\n\n#ifndef PH_PHUISUP_H\n#define PH_PHUISUP_H\n\n// begin_phapppub\n// Common state highlighting support\n\ntypedef struct _PH_SH_STATE\n{\n    PH_ITEM_STATE State;\n    HANDLE StateListHandle;\n    ULONG64 TickCount;\n} PH_SH_STATE, *PPH_SH_STATE;\n\nFORCEINLINE VOID PhChangeShStateTn(\n    _Inout_ PPH_TREENEW_NODE Node,\n    _Inout_ PPH_SH_STATE ShState,\n    _Inout_ PPH_POINTER_LIST *StateList,\n    _In_ PH_ITEM_STATE NewState,\n    _In_ COLORREF NewTempBackColor,\n    _In_opt_ HWND TreeNewHandleForUpdate\n    )\n{\n    if (!*StateList)\n        *StateList = PhCreatePointerList(4);\n\n    if (ShState->State == NormalItemState)\n        ShState->StateListHandle = PhAddItemPointerList(*StateList, Node);\n\n    ShState->TickCount = NtGetTickCount64();\n    ShState->State = NewState;\n\n    Node->UseTempBackColor = TRUE;\n    Node->TempBackColor = NewTempBackColor;\n\n    if (TreeNewHandleForUpdate)\n        TreeNew_InvalidateNode(TreeNewHandleForUpdate, Node);\n}\n\n#define PH_TICK_SH_STATE_TN(NodeType, ShStateFieldName, StateList, RemoveFunction, HighlightingDuration, TreeNewHandleForUpdate, Invalidate, FullyInvalidated, Context) \\\n    do { \\\n        NodeType *node; \\\n        ULONG enumerationKey = 0; \\\n        ULONG64 tickCount; \\\n        BOOLEAN preferFullInvalidate; \\\n        HANDLE stateListHandle; \\\n        BOOLEAN needsFullInvalidate = FALSE; \\\n\\\n        if (!StateList || StateList->Count == 0) \\\n            break; \\\n\\\n        tickCount = NtGetTickCount64(); \\\n        preferFullInvalidate = StateList->Count > 8; \\\n\\\n        while (PhEnumPointerList(StateList, &enumerationKey, &node)) \\\n        { \\\n            if (PhRoundNumber(tickCount - node->ShStateFieldName.TickCount, 100) < (HighlightingDuration)) \\\n                continue; \\\n\\\n            stateListHandle = node->ShStateFieldName.StateListHandle; \\\n\\\n            if (node->ShStateFieldName.State == NewItemState) \\\n            { \\\n                node->ShStateFieldName.State = NormalItemState; \\\n                ((PPH_TREENEW_NODE)node)->UseTempBackColor = FALSE; \\\n                if (Invalidate) \\\n                { \\\n                    if (preferFullInvalidate) \\\n                    { \\\n                        needsFullInvalidate = TRUE; \\\n                    } \\\n                    else \\\n                    { \\\n                        if (TreeNewHandleForUpdate) \\\n                            TreeNew_InvalidateNode((TreeNewHandleForUpdate), node); \\\n                    } \\\n                } \\\n            } \\\n            else if (node->ShStateFieldName.State == RemovingItemState) \\\n            { \\\n                RemoveFunction(node, Context); \\\n                needsFullInvalidate = TRUE; \\\n            } \\\n\\\n            PhRemoveItemPointerList(StateList, stateListHandle); \\\n        } \\\n\\\n        if (TreeNewHandleForUpdate) \\\n        { \\\n            if (needsFullInvalidate && (FullyInvalidated && !(*(PBOOLEAN)FullyInvalidated))) \\\n            { \\\n                PhInvalidateRect((TreeNewHandleForUpdate), NULL, FALSE); \\\n                if (FullyInvalidated) \\\n                    *((PBOOLEAN)FullyInvalidated) = TRUE; \\\n            } \\\n        } \\\n    } while (0)\n\n// Provider event queues\n\ntypedef enum _PH_PROVIDER_EVENT_TYPE\n{\n    ProviderAddedEvent = 1,\n    ProviderModifiedEvent = 2,\n    ProviderRemovedEvent = 3\n} PH_PROVIDER_EVENT_TYPE;\n\ntypedef struct _PH_PROVIDER_EVENT\n{\n    ULONG_PTR TypeAndObject;\n    ULONG RunId;\n} PH_PROVIDER_EVENT, *PPH_PROVIDER_EVENT;\n\n#define PH_PROVIDER_EVENT_TYPE_MASK 0x3\n#define PH_PROVIDER_EVENT_OBJECT_MASK (~(ULONG_PTR)0x3)\n#define PH_PROVIDER_EVENT_TYPE(Event) ((ULONG)(Event).TypeAndObject & PH_PROVIDER_EVENT_TYPE_MASK)\n#define PH_PROVIDER_EVENT_OBJECT(Event) ((PVOID)((Event).TypeAndObject & PH_PROVIDER_EVENT_OBJECT_MASK))\n\ntypedef struct _PH_PROVIDER_EVENT_QUEUE\n{\n    PH_ARRAY Array;\n    PH_QUEUED_LOCK Lock;\n} PH_PROVIDER_EVENT_QUEUE, *PPH_PROVIDER_EVENT_QUEUE;\n\nFORCEINLINE VOID PhInitializeProviderEventQueue(\n    _Out_ PPH_PROVIDER_EVENT_QUEUE EventQueue,\n    _In_ SIZE_T InitialCapacity\n    )\n{\n    PhInitializeArray(&EventQueue->Array, sizeof(PH_PROVIDER_EVENT), InitialCapacity);\n    PhInitializeQueuedLock(&EventQueue->Lock);\n}\n\nFORCEINLINE VOID PhDeleteProviderEventQueue(\n    _Inout_ PPH_PROVIDER_EVENT_QUEUE EventQueue\n    )\n{\n    PPH_PROVIDER_EVENT events;\n    SIZE_T i;\n\n    events = (PPH_PROVIDER_EVENT)EventQueue->Array.Items;\n\n    for (i = 0; i < EventQueue->Array.Count; i++)\n    {\n        if (PH_PROVIDER_EVENT_TYPE(events[i]) == ProviderAddedEvent)\n            PhDereferenceObject(PH_PROVIDER_EVENT_OBJECT(events[i]));\n    }\n\n    PhDeleteArray(&EventQueue->Array);\n}\n\nFORCEINLINE VOID PhPushProviderEventQueue(\n    _Inout_ PPH_PROVIDER_EVENT_QUEUE EventQueue,\n    _In_ PH_PROVIDER_EVENT_TYPE Type,\n    _In_opt_ PVOID Object,\n    _In_ ULONG RunId\n    )\n{\n    PH_PROVIDER_EVENT event;\n\n    assert(!(PtrToUlong(Object) & PH_PROVIDER_EVENT_TYPE_MASK));\n    event.TypeAndObject = (ULONG_PTR)Object | Type;\n    event.RunId = RunId;\n\n    PhAcquireQueuedLockExclusive(&EventQueue->Lock);\n    PhAddItemArray(&EventQueue->Array, &event);\n    PhReleaseQueuedLockExclusive(&EventQueue->Lock);\n}\n\nFORCEINLINE PPH_PROVIDER_EVENT PhFlushProviderEventQueue(\n    _Inout_ PPH_PROVIDER_EVENT_QUEUE EventQueue,\n    _In_ ULONG UpToRunId,\n    _Out_ PULONG Count\n    )\n{\n    PPH_PROVIDER_EVENT availableEvents;\n    PPH_PROVIDER_EVENT events = NULL;\n    SIZE_T count;\n\n    PhAcquireQueuedLockExclusive(&EventQueue->Lock);\n    availableEvents = (PPH_PROVIDER_EVENT)EventQueue->Array.Items;\n\n    for (count = 0; count < EventQueue->Array.Count; count++)\n    {\n        if ((LONG)(UpToRunId - availableEvents[count].RunId) < 0)\n            break;\n    }\n\n    if (count != 0)\n    {\n        events = (PPH_PROVIDER_EVENT)PhAllocateCopy(availableEvents, count * sizeof(PH_PROVIDER_EVENT));\n        PhRemoveItemsArray(&EventQueue->Array, 0, count);\n    }\n\n    PhReleaseQueuedLockExclusive(&EventQueue->Lock);\n\n    *Count = (ULONG)count;\n\n    return events;\n}\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/procgrp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2022\n *\n */\n\n#ifndef PH_PROCGRP_H\n#define PH_PROCGRP_H\n\n// begin_phapppub\ntypedef struct _PH_PROCESS_GROUP\n{\n    PPH_PROCESS_ITEM Representative; // An element of Processes (no extra reference added)\n    PPH_LIST Processes; // List of PPH_PROCESS_ITEM\n    HWND WindowHandle; // Window handle of representative\n} PH_PROCESS_GROUP, *PPH_PROCESS_GROUP;\n// end_phapppub\n\ntypedef VOID (NTAPI *PPH_SORT_LIST_FUNCTION)(\n    _In_ PPH_LIST List,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_GROUP_PROCESSES_DONT_GROUP 0x1\n#define PH_GROUP_PROCESSES_FILE_PATH 0x2\n\nPPH_LIST PhCreateProcessGroupList(\n    _In_opt_ PPH_SORT_LIST_FUNCTION SortListFunction, // Sort a list of PPH_PROCESS_NODE\n    _In_opt_ PVOID Context,\n    _In_ ULONG MaximumGroups,\n    _In_ ULONG Flags\n    );\n\nVOID PhFreeProcessGroupList(\n    _In_ PPH_LIST List\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/procmtgn.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_PROCMITIGATION_H\n#define PH_PROCMITIGATION_H\n\ntypedef struct _PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION\n{\n    PVOID Pointers[MaxProcessMitigationPolicy];\n    PROCESS_MITIGATION_DEP_POLICY DEPPolicy; // ProcessDEPPolicy\n    PROCESS_MITIGATION_ASLR_POLICY ASLRPolicy; // ProcessASLRPolicy\n    PROCESS_MITIGATION_DYNAMIC_CODE_POLICY DynamicCodePolicy; // ProcessDynamicCodePolicy\n    PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY StrictHandleCheckPolicy; // ProcessStrictHandleCheckPolicy\n    PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY SystemCallDisablePolicy; // ProcessSystemCallDisablePolicy\n    // ProcessMitigationOptionsMask\n    PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY ExtensionPointDisablePolicy; // ProcessExtensionPointDisablePolicy\n    PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY ControlFlowGuardPolicy; // ProcessControlFlowGuardPolicy\n    PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY SignaturePolicy; // ProcessSignaturePolicy\n    PROCESS_MITIGATION_FONT_DISABLE_POLICY FontDisablePolicy; // ProcessFontDisablePolicy\n    PROCESS_MITIGATION_IMAGE_LOAD_POLICY ImageLoadPolicy; // ProcessImageLoadPolicy\n    PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy; // ProcessSystemCallFilterPolicy\n    PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy; // ProcessPayloadRestrictionPolicy\n    PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy; // ProcessChildProcessPolicy\n    PROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY SideChannelIsolationPolicy; // ProcessSideChannelIsolationPolicy\n    PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY UserShadowStackPolicy; // ProcessUserShadowStackPolicy\n    PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY RedirectionTrustPolicy; // ProcessRedirectionTrustPolicy\n    PROCESS_MITIGATION_USER_POINTER_AUTH_POLICY UserPointerAuthPolicy; // ProcessUserPointerAuthPolicy\n    PROCESS_MITIGATION_SEHOP_POLICY SEHOPPolicy; // ProcessSEHOPPolicy\n    PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY2 ActivationContextTrustPolicy; // ProcessActivationContextTrustPolicy2\n} PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION, *PPH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION;\n\nNTSTATUS PhGetProcessMitigationPolicyAllInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION Information\n    );\n\n_Success_(return)\nBOOLEAN PhDescribeProcessMitigationPolicy(\n    _In_ PROCESS_MITIGATION_POLICY Policy,\n    _In_ PVOID Data,\n    _Out_opt_ PPH_STRING *ShortDescription,\n    _Out_opt_ PPH_STRING *LongDescription\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/procprp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2008-2016\n *     dmex    2017-2022\n *\n */\n\n#ifndef PH_PROCPRP_H\n#define PH_PROCPRP_H\n\ntypedef struct _PH_PROCESS_WAITPROPCONTEXT\n{\n    SLIST_ENTRY ListEntry;\n    HWND PropSheetWindowHandle;\n    HANDLE ProcessWaitHandle;\n    HANDLE ProcessHandle;\n    PPH_PROCESS_ITEM ProcessItem;\n} PH_PROCESS_WAITPROPCONTEXT, *PPH_PROCESS_WAITPROPCONTEXT;\n\n#define PH_PROCESS_PROPCONTEXT_MAXPAGES 20\n\ntypedef struct _PH_PROCESS_PROPCONTEXT\n{\n    PPH_PROCESS_ITEM ProcessItem;\n    PPH_STRING Title;\n    PROPSHEETHEADER PropSheetHeader;\n    HPROPSHEETPAGE* PropSheetPages;\n\n    HANDLE SelectThreadId;\n\n    PPH_PROCESS_WAITPROPCONTEXT ProcessWaitContext;\n    BOOLEAN WaitInitialized;\n} PH_PROCESS_PROPCONTEXT, *PPH_PROCESS_PROPCONTEXT;\n\n// begin_phapppub\ntypedef struct _PH_PROCESS_PROPPAGECONTEXT\n{\n    PPH_PROCESS_PROPCONTEXT PropContext;\n    PVOID Context;\n    PROPSHEETPAGE PropSheetPage;\n\n    BOOLEAN LayoutInitialized;\n} PH_PROCESS_PROPPAGECONTEXT, *PPH_PROCESS_PROPPAGECONTEXT;\n// end_phapppub\n\n// begin_phapppub\nPHAPPAPI\nPPH_PROCESS_PROPCONTEXT\nNTAPI\nPhCreateProcessPropContext(\n    _In_opt_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n// end_phapppub\n\nVOID PhRefreshProcessPropContext(\n    _Inout_ PPH_PROCESS_PROPCONTEXT PropContext\n    );\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhSetSelectThreadIdProcessPropContext(\n    _Inout_ PPH_PROCESS_PROPCONTEXT PropContext,\n    _In_ HANDLE ThreadId\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhAddProcessPropPage(\n    _Inout_ PPH_PROCESS_PROPCONTEXT PropContext,\n    _In_ _Assume_refs_(1) PPH_PROCESS_PROPPAGECONTEXT PropPageContext\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhAddProcessPropPage2(\n    _Inout_ PPH_PROCESS_PROPCONTEXT PropContext,\n    _In_ HPROPSHEETPAGE PropSheetPageHandle\n    );\n\nPHAPPAPI\nPPH_PROCESS_PROPPAGECONTEXT\nNTAPI\nPhCreateProcessPropPageContext(\n    _In_ LPCWSTR Template,\n    _In_ DLGPROC DlgProc,\n    _In_opt_ PVOID Context\n    );\n\nPHAPPAPI\nPPH_PROCESS_PROPPAGECONTEXT\nNTAPI\nPhCreateProcessPropPageContextEx(\n    _In_opt_ PVOID InstanceHandle,\n    _In_ LPCWSTR Template,\n    _In_ DLGPROC DlgProc,\n    _In_opt_ PVOID Context\n    );\n\n_Success_(return)\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhPropPageDlgProcHeader(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ LPARAM lParam,\n    _Out_opt_ LPPROPSHEETPAGE *PropSheetPage,\n    _Out_opt_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext,\n    _Out_opt_ PPH_PROCESS_ITEM *ProcessItem\n    );\n\n#define PH_PROP_PAGE_TAB_CONTROL_PARENT ((PPH_LAYOUT_ITEM)0x1)\n\nPHAPPAPI\nPPH_LAYOUT_ITEM\nNTAPI\nPhAddPropPageLayoutItem(\n    _In_ HWND WindowHandle,\n    _In_ HWND Handle,\n    _In_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhDoPropPageLayout(\n    _In_ HWND WindowHandle\n    );\n\nFORCEINLINE\nPPH_LAYOUT_ITEM\nPhBeginPropPageLayout(\n    _In_ HWND hwndDlg,\n    _In_ PPH_PROCESS_PROPPAGECONTEXT PropPageContext\n    )\n{\n    if (!PropPageContext->LayoutInitialized)\n    {\n        return PhAddPropPageLayoutItem(hwndDlg, hwndDlg,\n            PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\nFORCEINLINE\nVOID\nPhEndPropPageLayout(\n    _In_ HWND hwndDlg,\n    _In_ PPH_PROCESS_PROPPAGECONTEXT PropPageContext\n    )\n{\n    PhDoPropPageLayout(hwndDlg);\n    PropPageContext->LayoutInitialized = TRUE;\n}\n\nPHAPPAPI\nVOID\nNTAPI\nPhShowProcessProperties(\n    _In_ PPH_PROCESS_PROPCONTEXT Context\n    );\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/procprpp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_PROCPRPP_H\n#define PH_PROCPRPP_H\n\n#include <phuisup.h>\n#include <colmgr.h>\n\n#include <thrdlist.h>\n#include <modlist.h>\n#include <hndllist.h>\n#include <memlist.h>\n#include <memprv.h>\n\ntypedef struct _PH_PROCESS_PROPSHEETCONTEXT\n{\n    WNDPROC PropSheetWindowHookProc;\n    PH_LAYOUT_MANAGER LayoutManager;\n    PPH_LAYOUT_ITEM TabPageItem;\n    BOOLEAN LayoutInitialized;\n    HFONT PropSheetWindowFont;\n    PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;\n    HWND OptionsButtonWindowHandle;\n    WNDPROC OldOptionsButtonWndProc;\n    //HWND PermissionsButtonWindowHandle;\n    HWND ButtonsLabelWindowHandle;\n} PH_PROCESS_PROPSHEETCONTEXT, *PPH_PROCESS_PROPSHEETCONTEXT;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpProcessPropContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nINT CALLBACK PhpPropSheetProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ LPARAM lParam\n    );\n\nPPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext(\n    _In_ HWND WindowHandle\n    );\n\nLRESULT CALLBACK PhpPropSheetWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpProcessPropPageContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nUINT CALLBACK PhpStandardPropPageProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ LPPROPSHEETPAGE ppsp\n    );\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpProcessPropPageWaitContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nVOID PhpCreateProcessPropSheetWaitContext(\n    _In_ PPH_PROCESS_PROPCONTEXT PropContext,\n    _In_ HWND WindowHandle\n    );\n\nVOID PhpFlushProcessPropSheetWaitContextData(\n    VOID\n    );\n\n_Function_class_(WAIT_CALLBACK_ROUTINE)\nVOID NTAPI PhpProcessPropertiesWaitCallback(\n    _In_ PVOID Context,\n    _In_ BOOLEAN TimerOrWaitFired\n    );\n\n#define SET_BUTTON_ICON(Id, Icon) \\\n    SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_ICON, (LPARAM)(Icon))\n\nINT_PTR CALLBACK PhpProcessGeneralDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpProcessStatisticsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpProcessPerformanceDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpProcessThreadsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(PH_OPEN_OBJECT)\nNTSTATUS NTAPI PhpOpenProcessTokenForPage(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_CLOSE_OBJECT)\nNTSTATUS NTAPI PhpCloseProcessTokenForPage(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    );\n\nINT_PTR CALLBACK PhpProcessTokenHookProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpProcessModulesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpProcessMemoryDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpProcessEnvironmentDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpProcessHandlesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(PH_OPEN_OBJECT)\nNTSTATUS NTAPI PhpOpenProcessJobForPage(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_CLOSE_OBJECT)\nNTSTATUS NTAPI PhpCloseProcessJobForPage(\n    _In_ HANDLE Handle,\n    _In_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    );\n\nINT_PTR CALLBACK PhpProcessJobHookProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpProcessServicesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpProcessWmiProvidersDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n#ifdef _M_IX86\nINT_PTR CALLBACK PhpProcessVdmHostProcessDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n#endif\n\nextern PH_STRINGREF PhProcessPropPageLoadingText;\n\n#define WM_PH_THREADS_UPDATED (WM_APP + 200)\n#define WM_PH_THREAD_SELECTION_CHANGED (WM_APP + 201)\n\n// begin_phapppub\ntypedef struct _PH_THREADS_CONTEXT\n{\n    PPH_THREAD_PROVIDER Provider;\n    PH_CALLBACK_REGISTRATION ProviderRegistration;\n    PH_CALLBACK_REGISTRATION AddedEventRegistration;\n    PH_CALLBACK_REGISTRATION ModifiedEventRegistration;\n    PH_CALLBACK_REGISTRATION RemovedEventRegistration;\n    PH_CALLBACK_REGISTRATION UpdatedEventRegistration;\n    PH_CALLBACK_REGISTRATION LoadingStateChangedEventRegistration;\n\n    HWND WindowHandle;\n// end_phapppub\n    HWND TreeNewHandle;\n    HWND StatusHandle;\n    HWND SearchboxHandle;\n    HFONT TreeNewFont;\n    ULONG_PTR SearchMatchHandle;\n    PPH_TN_FILTER_ENTRY FilterEntry;\n    union\n    {\n        PH_THREAD_LIST_CONTEXT ListContext;\n        struct\n        {\n            HWND Private; // phapppub\n            HWND TreeNewHandle; // phapppub\n        } PublicUse;\n    };\n    PH_PROVIDER_EVENT_QUEUE EventQueue;\n\n    PH_CALLBACK_REGISTRATION SymbolProviderEventRegistration;\n// begin_phapppub\n} PH_THREADS_CONTEXT, *PPH_THREADS_CONTEXT;\n// end_phapppub\n\n#define WM_PH_MODULES_UPDATED (WM_APP + 210)\n\n// begin_phapppub\ntypedef struct _PH_MODULES_CONTEXT\n{\n    PPH_MODULE_PROVIDER Provider;\n    PH_PROVIDER_REGISTRATION ProviderRegistration;\n    PH_CALLBACK_REGISTRATION AddedEventRegistration;\n    PH_CALLBACK_REGISTRATION ModifiedEventRegistration;\n    PH_CALLBACK_REGISTRATION RemovedEventRegistration;\n    PH_CALLBACK_REGISTRATION UpdatedEventRegistration;\n    PH_CALLBACK_REGISTRATION ChangedEventRegistration;\n\n    HWND WindowHandle;\n// end_phapppub\n    HWND SearchboxHandle;\n    HWND TreeNewHandle;\n    HFONT TreeNewFont;\n    union\n    {\n        PH_MODULE_LIST_CONTEXT ListContext;\n        struct\n        {\n            HWND Private; // phapppub\n            HWND TreeNewHandle; // phapppub\n        } PublicUse;\n    };\n    PH_PROVIDER_EVENT_QUEUE EventQueue;\n    NTSTATUS LastRunStatus;\n    PPH_STRING ErrorMessage;\n    ULONG_PTR SearchMatchHandle;\n    PPH_TN_FILTER_ENTRY FilterEntry;\n// begin_phapppub\n} PH_MODULES_CONTEXT, *PPH_MODULES_CONTEXT;\n// end_phapppub\n\n#define WM_PH_HANDLES_UPDATED (WM_APP + 220)\n\n// begin_phapppub\ntypedef struct _PH_HANDLES_CONTEXT\n{\n    PPH_HANDLE_PROVIDER Provider;\n    PH_PROVIDER_REGISTRATION ProviderRegistration;\n    PH_CALLBACK_REGISTRATION AddedEventRegistration;\n    PH_CALLBACK_REGISTRATION ModifiedEventRegistration;\n    PH_CALLBACK_REGISTRATION RemovedEventRegistration;\n    PH_CALLBACK_REGISTRATION UpdatedEventRegistration;\n    PH_CALLBACK_REGISTRATION ChangedEventRegistration;\n\n    HWND WindowHandle;\n// end_phapppub\n    HWND TreeNewHandle;\n    HWND SearchWindowHandle;\n    HFONT TreeNewFont;\n\n    union\n    {\n        PH_HANDLE_LIST_CONTEXT ListContext;\n        struct\n        {\n            HWND Private; // phapppub\n            HWND TreeNewHandle; // phapppub\n        } PublicUse;\n    };\n    PH_PROVIDER_EVENT_QUEUE EventQueue;\n    BOOLEAN SelectedHandleProtected;\n    BOOLEAN SelectedHandleInherit;\n    NTSTATUS LastRunStatus;\n    PPH_STRING ErrorMessage;\n\n    ULONG_PTR SearchMatchHandle;\n    PPH_TN_FILTER_ENTRY FilterEntry;\n// begin_phapppub\n} PH_HANDLES_CONTEXT, *PPH_HANDLES_CONTEXT;\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_MEMORY_CONTEXT\n{\n    HANDLE ProcessId;\n    HWND WindowHandle;\n// end_phapppub\n    HWND TreeNewHandle;\n    HWND SearchboxHandle;\n    HFONT TreeNewFont;\n\n    union\n    {\n        PH_MEMORY_LIST_CONTEXT ListContext;\n        struct\n        {\n            HWND Private; // phapppub\n            HWND TreeNewHandle; // phapppub\n        } PublicUse;\n    };\n    PH_MEMORY_ITEM_LIST MemoryItemList;\n    BOOLEAN MemoryItemListValid;\n    NTSTATUS LastRunStatus;\n    PPH_STRING ErrorMessage;\n\n    ULONG_PTR SearchMatchHandle;\n    PPH_TN_FILTER_ENTRY AllocationFilterEntry;\n    PPH_TN_FILTER_ENTRY FilterEntry;\n// begin_phapppub\n} PH_MEMORY_CONTEXT, *PPH_MEMORY_CONTEXT;\n// end_phapppub\n\n#define WM_PH_STATISTICS_UPDATE (WM_APP + 231)\n\ntypedef struct _PH_STATISTICS_CONTEXT\n{\n    PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;\n    HWND WindowHandle;\n    HWND ListViewHandle;\n    HFONT TreeNewFont;\n\n    PPH_LISTVIEW_CONTEXT ListViewContext;\n\n    BOOLEAN Enabled;\n    HANDLE ProcessHandle;\n    PPH_PROCESS_ITEM ProcessItem;\n\n    BOOLEAN GotCycles;\n    BOOLEAN GotCounters;\n\n    ULONG PagePriority;\n    IO_PRIORITY_HINT IoPriority;\n    ULONG PeakHandleCount;\n    ULONG HangCount;\n    ULONG GhostCount;\n    ULONGLONG RunningTime;\n    ULONGLONG SuspendedTime;\n    ULONGLONG NetworkTxRxBytes;\n    PH_UINT64_DELTA KeyboardDelta;\n    PH_UINT64_DELTA MouseDelta;\n\n    //PPH_STRING PrivateWs;\n    //PPH_STRING ShareableWs;\n    //PPH_STRING SharedWs;\n    PPH_STRING PeakHandles;\n    PPH_STRING GdiHandles;\n    PPH_STRING UserHandles;\n    PPH_STRING PeakGdiHandles;\n    PPH_STRING PeakUserHandles;\n\n    FLOAT CpuUsage; FLOAT CpuUsageMin; FLOAT CpuUsageMax; FLOAT CpuUsageDiff;\n    FLOAT CpuUsageUser; FLOAT CpuUsageUserMin; FLOAT CpuUsageUserMax; FLOAT CpuUsageUserDiff;\n    FLOAT CpuUsageKernel; FLOAT CpuUsageKernelMin; FLOAT CpuUsageKernelMax; FLOAT CpuUsageKernelDiff;\n    FLOAT CpuUsageAverage; FLOAT CpuUsageAverageMin; FLOAT CpuUsageAverageMax; FLOAT CpuUsageAverageDiff;\n    FLOAT CpuUsageRelative; FLOAT CpuUsageRelativeMin; FLOAT CpuUsageRelativeMax; FLOAT CpuUsageRelativeDiff;\n    ULONG64 CycleTime; ULONG64 CycleTimeMin; ULONG64 CycleTimeMax; ULONG64 CycleTimeDiff;\n    ULONG64 CycleTimeDelta; ULONG64 CycleTimeDeltaMin; ULONG64 CycleTimeDeltaMax; ULONG64 CycleTimeDeltaDiff;\n    ULONG64 ContextSwitches; ULONG64 ContextSwitchesMin; ULONG64 ContextSwitchesMax; ULONG64 ContextSwitchesDiff;\n    ULONG64 ContextSwitchesDelta; ULONG64 ContextSwitchesDeltaMin; ULONG64 ContextSwitchesDeltaMax; ULONG64 ContextSwitchesDeltaDiff;\n    ULONG64 KernelTime; ULONG64 KernelTimeMin; ULONG64 KernelTimeMax; ULONG64 KernelTimeDiff;\n    ULONG64 KernelTimeDelta; ULONG64 KernelTimeDeltaMin; ULONG64 KernelTimeDeltaMax; ULONG64 KernelTimeDeltaDiff;\n    ULONG64 UserTime; ULONG64 UserTimeMin; ULONG64 UserTimeMax; ULONG64 UserTimeDiff;\n    ULONG64 UserTimeDelta; ULONG64 UserTimeDeltaMin; ULONG64 UserTimeDeltaMax; ULONG64 UserTimeDeltaDiff;\n    KPRIORITY BasePriority; KPRIORITY BasePriorityMin; KPRIORITY BasePriorityMax; KPRIORITY BasePriorityDiff;\n\n    ULONG_PTR PagefileUsage; ULONG_PTR PagefileUsageMin; ULONG_PTR PagefileUsageMax; ULONG_PTR PagefileUsageDiff;\n    ULONG_PTR PagefileDelta; ULONG_PTR PagefileDeltaMin; ULONG_PTR PagefileDeltaMax; ULONG_PTR PagefileDeltaDiff;\n    ULONG64 PeakPagefileUsage; ULONG64 PeakPagefileUsageMin; ULONG64 PeakPagefileUsageMax; ULONG64 PeakPagefileUsageDiff;\n    ULONG64 VirtualSize; ULONG64 VirtualSizeMin; ULONG64 VirtualSizeMax; ULONG64 VirtualSizeDiff;\n    ULONG64 PeakVirtualSize; ULONG64 PeakVirtualSizeMin; ULONG64 PeakVirtualSizeMax; ULONG64 PeakVirtualSizeDiff;\n    ULONG64 PageFaultCount; ULONG64 PageFaultCountMin; ULONG64 PageFaultCountMax; ULONG64 PageFaultCountDiff;\n    ULONG64 PageFaultsDelta; ULONG64 PageFaultsDeltaMin; ULONG64 PageFaultsDeltaMax; ULONG64 PageFaultsDeltaDiff;\n    ULONG64 HardFaultCount; ULONG64 HardFaultCountMin; ULONG64 HardFaultCountMax; ULONG64 HardFaultCountDiff;\n    ULONG64 HardFaultsDelta; ULONG64 HardFaultsDeltaMin; ULONG64 HardFaultsDeltaMax; ULONG64 HardFaultsDeltaDiff;\n    ULONG64 WorkingSetSize; ULONG64 WorkingSetSizeMin; ULONG64 WorkingSetSizeMax; ULONG64 WorkingSetSizeDiff;\n    ULONG64 PeakWorkingSetSize; ULONG64 PeakWorkingSetSizeMin; ULONG64 PeakWorkingSetSizeMax; ULONG64 PeakWorkingSetSizeDiff;\n\n    ULONG64 QuotaPagedPoolUsage; ULONG64 QuotaPagedPoolUsageMin; ULONG64 QuotaPagedPoolUsageMax; ULONG64 QuotaPagedPoolUsageDiff;\n    ULONG64 QuotaPeakPagedPoolUsage; ULONG64 QuotaPeakPagedPoolUsageMin; ULONG64 QuotaPeakPagedPoolUsageMax; ULONG64 QuotaPeakPagedPoolUsageDiff;\n    ULONG64 QuotaNonPagedPoolUsage; ULONG64 QuotaNonPagedPoolUsageMin; ULONG64 QuotaNonPagedPoolUsageMax; ULONG64 QuotaNonPagedPoolUsageDiff;\n    ULONG64 QuotaPeakNonPagedPoolUsage; ULONG64 QuotaPeakNonPagedPoolUsageMin; ULONG64 QuotaPeakNonPagedPoolUsageMax; ULONG64 QuotaPeakNonPagedPoolUsageDiff;\n\n    ULONG64 NumberOfPrivatePages; ULONG64 NumberOfPrivatePagesMin; ULONG64 NumberOfPrivatePagesMax; ULONG64 NumberOfPrivatePagesDiff;\n    ULONG64 NumberOfShareablePages; ULONG64 NumberOfShareablePagesMin; ULONG64 NumberOfShareablePagesMax; ULONG64 NumberOfShareablePagesDiff;\n    ULONG64 NumberOfSharedPages; ULONG64 NumberOfSharedPagesMin; ULONG64 NumberOfSharedPagesMax; ULONG64 NumberOfSharedPagesDiff;\n    ULONG64 SharedCommitUsage; ULONG64 SharedCommitUsageMin; ULONG64 SharedCommitUsageMax; ULONG64 SharedCommitUsageDiff;\n    ULONG64 PrivateCommitUsage; ULONG64 PrivateCommitUsageMin; ULONG64 PrivateCommitUsageMax; ULONG64 PrivateCommitUsageDiff;\n    ULONG64 PeakPrivateCommitUsage; ULONG64 PeakPrivateCommitUsageMin; ULONG64 PeakPrivateCommitUsageMax; ULONG64 PeakPrivateCommitUsageDiff;\n\n    ULONG64 ReadOperationCount; ULONG64 ReadOperationCountMin; ULONG64 ReadOperationCountMax; ULONG64 ReadOperationCountDiff;\n    ULONG64 IoReadCountDelta; ULONG64 IoReadCountDeltaMin; ULONG64 IoReadCountDeltaMax; ULONG64 IoReadCountDeltaDiff;\n    ULONG64 ReadTransferCount; ULONG64 ReadTransferCountMin; ULONG64 ReadTransferCountMax; ULONG64 ReadTransferCountDiff;\n    ULONG64 IoReadDelta; ULONG64 IoReadDeltaMin; ULONG64 IoReadDeltaMax; ULONG64 IoReadDeltaDiff;\n\n    ULONG64 WriteOperationCount; ULONG64 WriteOperationCountMin; ULONG64 WriteOperationCountMax; ULONG64 WriteOperationCountDiff;\n    ULONG64 IoWriteCountDelta; ULONG64 IoWriteCountDeltaMin; ULONG64 IoWriteCountDeltaMax; ULONG64 IoWriteCountDeltaDiff;\n    ULONG64 WriteTransferCount; ULONG64 WriteTransferCountMin; ULONG64 WriteTransferCountMax; ULONG64 WriteTransferCountDiff;\n    ULONG64 IoWriteDelta; ULONG64 IoWriteDeltaMin; ULONG64 IoWriteDeltaMax; ULONG64 IoWriteDeltaDiff;\n\n    ULONG64 OtherOperationCount; ULONG64 OtherOperationCountMin; ULONG64 OtherOperationCountMax; ULONG64 OtherOperationCountDiff;\n    ULONG64 IoOtherCountDelta; ULONG64 IoOtherCountDeltaMin; ULONG64 IoOtherCountDeltaMax; ULONG64 IoOtherCountDeltaDiff;\n    ULONG64 OtherTransferCount; ULONG64 OtherTransferCountMin; ULONG64 OtherTransferCountMax; ULONG64 OtherTransferCountDiff;\n    ULONG64 IoOtherDelta; ULONG64 IoOtherDeltaMin; ULONG64 IoOtherDeltaMax; ULONG64 IoOtherDeltaDiff;\n\n    ULONG64 IoTotal; ULONG64 IoTotalMin; ULONG64 IoTotalMax; ULONG64 IoTotalDiff;\n    ULONG64 IoTotalDelta; ULONG64 IoTotalDeltaMin; ULONG64 IoTotalDeltaMax; ULONG64 IoTotalDeltaDiff;\n\n} PH_STATISTICS_CONTEXT, *PPH_STATISTICS_CONTEXT;\n\n#define WM_PH_PERFORMANCE_UPDATE (WM_APP + 241)\n\ntypedef struct _PH_PERFORMANCE_CONTEXT\n{\n    PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;\n\n    HWND WindowHandle;\n    BOOLEAN Enabled;\n    LONG WindowDpi;\n\n    PH_GRAPH_STATE CpuGraphState;\n    PH_GRAPH_STATE PrivateGraphState;\n    PH_GRAPH_STATE IoGraphState;\n\n    HWND CpuGraphHandle;\n    HWND PrivateGraphHandle;\n    HWND IoGraphHandle;\n\n    HWND CpuGroupBox;\n    HWND PrivateBytesGroupBox;\n    HWND IoGroupBox;\n} PH_PERFORMANCE_CONTEXT, *PPH_PERFORMANCE_CONTEXT;\n\ntypedef struct _PH_ENVIRONMENT_ITEM\n{\n    PPH_STRING Name;\n    PPH_STRING Value;\n} PH_ENVIRONMENT_ITEM, *PPH_ENVIRONMENT_ITEM;\n\ntypedef struct _PH_ENVIRONMENT_CONTEXT\n{\n    HWND WindowHandle;\n    HWND TreeNewHandle;\n    HWND SearchWindowHandle;\n    HFONT TreeNewFont;\n\n    BOOLEAN EnableStateHighlighting;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Reserved : 1;\n            ULONG HideProcessEnvironment : 1;\n            ULONG HideUserEnvironment : 1;\n            ULONG HideSystemEnvironment : 1;\n            ULONG HighlightProcessEnvironment : 1;\n            ULONG HighlightUserEnvironment : 1;\n            ULONG HighlightSystemEnvironment : 1;\n            ULONG HideCmdTypeEnvironment : 1;\n            ULONG HighlightCmdEnvironment : 1;\n            ULONG Spare : 23;\n        };\n    };\n\n    PPH_PROCESS_ITEM ProcessItem;\n    ULONG_PTR SearchMatchHandle;\n    PPH_STRING StatusMessage;\n\n    PPH_LIST NodeList;\n    PPH_LIST NodeRootList;\n    PPH_HASHTABLE NodeHashtable;\n    PPH_TN_FILTER_ENTRY TreeFilterEntry;\n    ULONG TreeNewSortColumn;\n    PH_TN_FILTER_SUPPORT TreeFilterSupport;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PH_CM_MANAGER Cm;\n\n    PH_ARRAY Items;\n} PH_ENVIRONMENT_CONTEXT, *PPH_ENVIRONMENT_CONTEXT;\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/procprv.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2016-2023\n *\n */\n\n#ifndef PH_PROCPRV_H\n#define PH_PROCPRV_H\n\n#define PH_RECORD_MAX_USAGE\n\nextern PPH_OBJECT_TYPE PhProcessItemType;\nextern PPH_LIST PhProcessRecordList;\nextern PH_QUEUED_LOCK PhProcessRecordListLock;\n\nextern ULONG PhStatisticsSampleCount;\nextern BOOLEAN PhEnablePurgeProcessRecords;\nextern BOOLEAN PhEnableCycleCpuUsage;\nextern BOOLEAN PhEnableInterruptCpuUsage;\nextern BOOLEAN PhEnablePackageIconSupport;\n\ntypedef enum _PH_PROCESS_PROVIDER_FLAG\n{\n    PH_PROCESS_PROVIDER_FLAG_WSCOUNTERS = 0x1,\n    PH_PROCESS_PROVIDER_FLAG_GDIUSERHANDLES = 0x2,\n    PH_PROCESS_PROVIDER_FLAG_IOPAGEPRIORITY = 0x4,\n    PH_PROCESS_PROVIDER_FLAG_WINDOW = 0x8,\n    PH_PROCESS_PROVIDER_FLAG_DEPSTATUS = 0x10,\n    PH_PROCESS_PROVIDER_FLAG_TOKEN = 0x20,\n    PH_PROCESS_PROVIDER_FLAG_OSCONTEXT = 0x40,\n    PH_PROCESS_PROVIDER_FLAG_QUOTALIMITS = 0x80,\n    PH_PROCESS_PROVIDER_FLAG_IMAGE = 0x100,\n    PH_PROCESS_PROVIDER_FLAG_APPID = 0x200,\n    PH_PROCESS_PROVIDER_FLAG_DPIAWARENESS = 0x400,\n    PH_PROCESS_PROVIDER_FLAG_FILEATTRIBUTES = 0x800,\n    PH_PROCESS_PROVIDER_FLAG_DESKTOPINFO = 0x1000,\n    PH_PROCESS_PROVIDER_FLAG_USERNAME = 0x2000,\n    PH_PROCESS_PROVIDER_FLAG_CRITICAL = 0x4000,\n    PH_PROCESS_PROVIDER_FLAG_ERRORMODE = 0x8000,\n    PH_PROCESS_PROVIDER_FLAG_CODEPAGE = 0x10000,\n    PH_PROCESS_PROVIDER_FLAG_POWERTHROTTLING = 0x20000,\n    PH_PROCESS_PROVIDER_FLAG_PRIORITYBOOST = 0x40000,\n    PH_PROCESS_PROVIDER_FLAG_CFGUARD = 0x80000,\n    PH_PROCESS_PROVIDER_FLAG_CET = 0x100000,\n    PH_PROCESS_PROVIDER_FLAG_AVERAGE = 0x200000,\n} PH_PROCESS_PROVIDER_FLAG;\n\nextern ULONG PhProcessProviderFlagsMask;\n\nextern PVOID PhProcessInformation; // only can be used if running on same thread as process provider\nextern ULONG PhProcessInformationSequenceNumber;\nextern SYSTEM_PERFORMANCE_INFORMATION PhPerfInformation;\nextern PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuInformation;\nextern SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuTotals;\nextern ULONG PhTotalProcesses;\nextern ULONG PhTotalThreads;\nextern ULONG PhTotalHandles;\nextern ULONG PhTotalCpuQueueLength;\n\nextern ULONG64 PhCpuTotalCycleDelta;\nextern PSYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION PhCpuIdleCycleTime; // cycle time for Idle\nextern PSYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION PhCpuSystemCycleTime; // cycle time for DPCs and Interrupts\nextern PH_UINT64_DELTA PhCpuIdleCycleDelta;\nextern PH_UINT64_DELTA PhCpuSystemCycleDelta;\n\nextern FLOAT PhCpuKernelUsage;\nextern FLOAT PhCpuUserUsage;\nextern PFLOAT PhCpusKernelUsage;\nextern PFLOAT PhCpusUserUsage;\n\nextern PH_UINT64_DELTA PhCpuKernelDelta;\nextern PH_UINT64_DELTA PhCpuUserDelta;\nextern PH_UINT64_DELTA PhCpuIdleDelta;\n\nextern PPH_UINT64_DELTA PhCpusKernelDelta;\nextern PPH_UINT64_DELTA PhCpusUserDelta;\nextern PPH_UINT64_DELTA PhCpusIdleDelta;\n\nextern PH_UINT64_DELTA PhIoReadDelta;\nextern PH_UINT64_DELTA PhIoWriteDelta;\nextern PH_UINT64_DELTA PhIoOtherDelta;\n\nextern BOOLEAN PhProcessStatisticsInitialized;\n\nextern PH_CIRCULAR_BUFFER_FLOAT PhCpuKernelHistory;\nextern PH_CIRCULAR_BUFFER_FLOAT PhCpuUserHistory;\n//extern PH_CIRCULAR_BUFFER_FLOAT PhCpuOtherHistory;\n\nextern PPH_CIRCULAR_BUFFER_FLOAT PhCpusKernelHistory;\nextern PPH_CIRCULAR_BUFFER_FLOAT PhCpusUserHistory;\n//extern PPH_CIRCULAR_BUFFER_FLOAT PhCpusOtherHistory;\n\nextern PH_CIRCULAR_BUFFER_ULONG64 PhIoReadHistory;\nextern PH_CIRCULAR_BUFFER_ULONG64 PhIoWriteHistory;\nextern PH_CIRCULAR_BUFFER_ULONG64 PhIoOtherHistory;\n\nextern PH_CIRCULAR_BUFFER_ULONG PhCommitHistory;\nextern PH_CIRCULAR_BUFFER_ULONG PhPhysicalHistory;\n\nextern PH_CIRCULAR_BUFFER_ULONG PhMaxCpuHistory;\nextern PH_CIRCULAR_BUFFER_ULONG PhMaxIoHistory;\n#ifdef PH_RECORD_MAX_USAGE\nextern PH_CIRCULAR_BUFFER_FLOAT PhMaxCpuUsageHistory;\nextern PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoReadOtherHistory;\nextern PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoWriteHistory;\n#endif\n\n// begin_phapppub\n// DPCs, Interrupts and System Idle Process are not real.\n// Non-\"real\" processes can never be opened.\n#define PH_IS_REAL_PROCESS_ID(ProcessId) ((LONG_PTR)(ProcessId) > 0)\n\n// DPCs and Interrupts are fake, but System Idle Process is not.\n#define PH_IS_FAKE_PROCESS_ID(ProcessId) ((LONG_PTR)(ProcessId) < 0)\n\n// The process item has been removed.\n#define PH_PROCESS_ITEM_REMOVED 0x1\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_PROCESS_RECORD *PPH_PROCESS_RECORD;\n\ntypedef struct _PH_IMAGELIST_ITEM\n{\n    PPH_STRING FileName;\n    ULONG LargeIconIndex;\n    ULONG SmallIconIndex;\n} PH_IMAGELIST_ITEM, *PPH_IMAGELIST_ITEM;\n\ntypedef struct _PH_PROCESS_ITEM\n{\n    PH_HASH_ENTRY HashEntry;\n    ULONG State;\n    PPH_PROCESS_RECORD Record;\n\n    // Basic\n\n    HANDLE ProcessId;\n    HANDLE ParentProcessId;\n    PPH_STRING ProcessName;\n    ULONG SessionId;\n    LARGE_INTEGER CreateTime;\n\n    // Handles\n\n    HANDLE QueryHandle;\n\n    // Parameters\n\n    PPH_STRING FileName;\n    PPH_STRING CommandLine;\n\n    // File\n\n    ULONG_PTR SmallIconIndex;\n    ULONG_PTR LargeIconIndex;\n    PH_IMAGE_VERSION_INFO VersionInfo;\n\n    // Security\n\n    PSID Sid;\n    TOKEN_ELEVATION_TYPE ElevationType;\n    PH_INTEGRITY_LEVEL IntegrityLevel;\n    PPH_STRINGREF IntegrityString;\n    PS_PROTECTION Protection;\n\n    // Other\n\n    HANDLE ConsoleHostProcessId;\n    ULONGLONG ProcessStartKey;\n    ULONGLONG CreateInterruptTime;\n    ULONGLONG SessionCreateTime;\n    ULONG ImageChecksum;\n    ULONG ImageTimeStamp;\n\n    // Signature, Packed\n\n    ULONG VerifyResult;\n    PPH_STRING VerifySignerName;\n    ULONG ImportFunctions;\n    ULONG ImportModules;\n\n    // Flags\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG UpdateIsDotNet : 1;\n            ULONG IsBeingDebugged : 1;\n            ULONG IsDotNet : 1;\n            ULONG IsElevated : 1;\n            ULONG IsInJob : 1;\n            ULONG IsInSignificantJob : 1;\n            ULONG IsPacked : 1;\n            ULONG IsHandleValid : 1;\n            ULONG IsSuspended : 1;\n            ULONG IsWow64Process : 1;\n            ULONG IsImmersive : 1;\n            ULONG IsPartiallySuspended : 1;\n            ULONG IsProtectedHandle : 1;\n            ULONG IsProtectedProcess : 1;\n            ULONG IsSecureProcess : 1;\n            ULONG IsSubsystemProcess : 1;\n            ULONG IsPackagedProcess : 1;\n            ULONG IsBackgroundProcess : 1;\n            ULONG IsCrossSessionProcess : 1;\n            ULONG IsSnapshotProcess : 1;\n            ULONG IsFrozenProcess : 1;\n            ULONG IsUIAccessEnabled : 1;\n            ULONG IsControlFlowGuardEnabled : 1;\n            ULONG IsCetEnabled : 1;\n            ULONG IsXfgEnabled : 1;\n            ULONG IsXfgAuditEnabled : 1;\n            ULONG IsPowerThrottling : 1;\n            ULONG IsSystemProcess : 1;\n            ULONG IsSecureSystem : 1;\n            ULONG Spare : 3;\n        };\n    };\n\n    // Misc.\n\n    volatile LONG JustProcessed;\n    PH_EVENT Stage1Event;\n\n    PPH_POINTER_LIST ServiceList;\n    PH_QUEUED_LOCK ServiceListLock;\n\n    WCHAR ProcessIdString[PH_INT32_STR_LEN_1];\n    WCHAR ProcessIdHexString[PH_PTR_STR_LEN_1];\n    //WCHAR ParentProcessIdString[PH_INT32_STR_LEN_1];\n    //WCHAR SessionIdString[PH_INT32_STR_LEN_1];\n\n    // Dynamic\n\n    KPRIORITY BasePriority;\n    union\n    {\n        KAFFINITY AffinityMaskSingle; // Single processor group\n        PKAFFINITY AffinityMaskGroups; // Multiple processor groups * PhSystemProcessorInformation.NumberOfProcessorGroups\n    };\n    ULONG AffinityPopulationCount;\n    ULONG PriorityClass;\n    LARGE_INTEGER KernelTime;\n    LARGE_INTEGER UserTime;\n    ULONG NumberOfHandles;\n    ULONG NumberOfThreads;\n\n    FLOAT CpuUsage; // Below Windows 7, sum of kernel and user CPU usage; above Windows 7, cycle-based CPU usage.\n    FLOAT CpuKernelUsage;\n    FLOAT CpuUserUsage;\n    FLOAT CpuAverageUsage;\n\n    PH_UINT64_DELTA CpuKernelDelta;\n    PH_UINT64_DELTA CpuUserDelta;\n    PH_UINT64_DELTA IoReadDelta;\n    PH_UINT64_DELTA IoWriteDelta;\n    PH_UINT64_DELTA IoOtherDelta;\n    PH_UINT64_DELTA IoReadCountDelta;\n    PH_UINT64_DELTA IoWriteCountDelta;\n    PH_UINT64_DELTA IoOtherCountDelta;\n    PH_UINT64_DELTA ContextSwitchesDelta;\n    PH_UINT32_DELTA PageFaultsDelta;\n    PH_UINT32_DELTA HardFaultsDelta;\n    PH_UINT64_DELTA CycleTimeDelta; // since WIN7\n\n    VM_COUNTERS_EX VmCounters;\n    IO_COUNTERS IoCounters;\n    ULONGLONG WorkingSetPrivateSize; // since VISTA\n    ULONG PeakNumberOfThreads; // since WIN7\n    ULONG HardFaultCount; // since WIN7\n\n    ULONG TimeSequenceNumber;\n    PH_CIRCULAR_BUFFER_FLOAT CpuKernelHistory;\n    PH_CIRCULAR_BUFFER_FLOAT CpuUserHistory;\n    PH_CIRCULAR_BUFFER_ULONG64 IoReadHistory;\n    PH_CIRCULAR_BUFFER_ULONG64 IoWriteHistory;\n    PH_CIRCULAR_BUFFER_ULONG64 IoOtherHistory;\n    PH_CIRCULAR_BUFFER_SIZE_T PrivateBytesHistory;\n    //PH_CIRCULAR_BUFFER_SIZE_T WorkingSetHistory;\n\n    // New fields\n    PH_UINTPTR_DELTA PrivateBytesDelta;\n    PPH_STRING PackageFullName;\n    PPH_STRING UserName;\n\n    PROCESS_DISK_COUNTERS DiskCounters;\n    PROCESS_NETWORK_COUNTERS NetworkCounters;\n    ULONGLONG ContextSwitches;\n\n    ULONGLONG ProcessSequenceNumber;\n    PH_KNOWN_PROCESS_TYPE KnownProcessType;\n    ULONG JobObjectId;\n    SIZE_T SharedCommitCharge;\n\n    PPH_IMAGELIST_ITEM IconEntry;\n\n    NTSTATUS ImageCoherencyStatus;\n    FLOAT ImageCoherency;\n\n    ULONG LxssProcessId;\n\n    HANDLE FreezeHandle;\n    PPEB PebBaseAddress;\n\n} PH_PROCESS_ITEM, *PPH_PROCESS_ITEM;\n// end_phapppub\n\n// begin_phapppub\n// The process itself is dead.\n#define PH_PROCESS_RECORD_DEAD 0x1\n// An extra reference has been added to the process record for the statistics system.\n#define PH_PROCESS_RECORD_STAT_REF 0x2\n\ntypedef struct _PH_PROCESS_RECORD\n{\n    LIST_ENTRY ListEntry;\n    LONG RefCount;\n    ULONG Flags;\n\n    HANDLE ProcessId;\n    HANDLE ParentProcessId;\n    ULONG SessionId;\n    ULONGLONG ProcessSequenceNumber;\n    LARGE_INTEGER CreateTime;\n    LARGE_INTEGER ExitTime;\n\n    PPH_STRING ProcessName;\n    PPH_STRING FileName;\n    PPH_STRING CommandLine;\n    /*PPH_STRING UserName;*/\n} PH_PROCESS_RECORD, *PPH_PROCESS_RECORD;\n// end_phapppub\n\nBOOLEAN PhProcessProviderInitialization(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhGetClientIdName(\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhGetClientIdNameEx(\n    _In_ PCLIENT_ID ClientId,\n    _In_opt_ PPH_STRING ProcessName\n    );\n// end_phapppub\n\nPPH_PROCESS_ITEM PhCreateProcessItem(\n    _In_ HANDLE ProcessId\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_PROCESS_ITEM\nNTAPI\nPhReferenceProcessItem(\n    _In_opt_ HANDLE ProcessId\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhEnumProcessItems(\n    _Out_opt_ PPH_PROCESS_ITEM **ProcessItems,\n    _Out_ PULONG NumberOfProcessItems\n    );\n// end_phapppub\n\ntypedef enum _VERIFY_RESULT VERIFY_RESULT;\ntypedef struct _PH_VERIFY_FILE_INFO *PPH_VERIFY_FILE_INFO;\n\nVERIFY_RESULT PhVerifyFileWithAdditionalCatalog(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _In_opt_ PPH_STRING PackageFullName,\n    _Out_opt_ PPH_STRING *SignerName\n    );\n\nVERIFY_RESULT PhVerifyFileCached(\n    _In_ PPH_STRING FileName,\n    _In_opt_ PPH_STRING PackageFullName,\n    _Out_opt_ PPH_STRING *SignerName,\n    _In_ BOOLEAN NativeFileName,\n    _In_ BOOLEAN CachedOnly\n    );\n\nVOID PhFlushVerifyCache(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\n_Success_(return)\nBOOLEAN\nNTAPI\nPhGetStatisticsTime(\n    _In_opt_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG Index,\n    _Out_ PLARGE_INTEGER Time\n    );\n\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhGetStatisticsTimeString(\n    _In_opt_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG Index\n    );\n// end_phapppub\n\nVOID PhFlushProcessQueryData(\n    VOID\n    );\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhProcessProviderUpdate(\n    _In_ PVOID Object\n    );\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhReferenceProcessRecord(\n    _In_ PPH_PROCESS_RECORD ProcessRecord\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhReferenceProcessRecordSafe(\n    _In_ PPH_PROCESS_RECORD ProcessRecord\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhReferenceProcessRecordForStatistics(\n    _In_ PPH_PROCESS_RECORD ProcessRecord\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhDereferenceProcessRecord(\n    _In_ PPH_PROCESS_RECORD ProcessRecord\n    );\n\nPHAPPAPI\nPPH_PROCESS_RECORD\nNTAPI\nPhFindProcessRecord(\n    _In_opt_ HANDLE ProcessId,\n    _In_ PLARGE_INTEGER Time\n    );\n// end_phapppub\n\nVOID PhPurgeProcessRecords(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_PROCESS_ITEM\nNTAPI\nPhReferenceProcessItemForParent(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\nPHAPPAPI\nPPH_PROCESS_ITEM\nNTAPI\nPhReferenceProcessItemForRecord(\n    _In_ PPH_PROCESS_RECORD Record\n    );\n// end_phapppub\n\nextern PPH_OBJECT_TYPE PhImageListItemType;\nextern HIMAGELIST PhProcessLargeImageList;\nextern HIMAGELIST PhProcessSmallImageList;\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhProcessImageListInitialization(\n    _In_ HWND WindowHandle,\n    _In_ LONG WindowDpi\n    );\n\nPHAPPAPI\nPPH_IMAGELIST_ITEM\nNTAPI\nPhImageListExtractIcon(\n    _In_ PPH_STRING FileName,\n    _In_ BOOLEAN NativeFileName,\n    _In_opt_ HANDLE ProcessId,\n    _In_opt_ PPH_STRING PackageFullName,\n    _In_ LONG SystemDpi\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhImageListFlushCache(\n    VOID\n    );\n\nPHAPPAPI\nHICON\nNTAPI\nPhGetImageListIcon(\n    _In_ ULONG_PTR Index,\n    _In_ BOOLEAN Large\n    );\n\nPHAPPAPI\nHIMAGELIST\nNTAPI\nPhGetProcessSmallImageList(\n    VOID\n    );\n\n// Note: Can only be called from same thread as process provider. (dmex)\n_Success_(return)\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhDuplicateProcessInformation(\n    _Outptr_ PPVOID ProcessInformation\n    );\n// end_phapppub\n\nPPH_PROCESS_ITEM\nNTAPI\nPhCreateProcessItemFromHandle(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN TerminatedProcess\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/proctree.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_PROCTREE_H\n#define PH_PROCTREE_H\n\n#include <phuisup.h>\n\n// Columns\n\n// Default columns should go first\n#define PHPRTLC_NAME 0\n#define PHPRTLC_PID 1\n#define PHPRTLC_CPU 2\n#define PHPRTLC_IOTOTALRATE 3\n#define PHPRTLC_PRIVATEBYTES 4\n#define PHPRTLC_USERNAME 5\n#define PHPRTLC_DESCRIPTION 6\n\n#define PHPRTLC_COMPANYNAME 7\n#define PHPRTLC_VERSION 8\n#define PHPRTLC_FILENAME 9\n#define PHPRTLC_COMMANDLINE 10\n#define PHPRTLC_PEAKPRIVATEBYTES 11\n#define PHPRTLC_WORKINGSET 12\n#define PHPRTLC_PEAKWORKINGSET 13\n#define PHPRTLC_PRIVATEWS 14\n#define PHPRTLC_SHAREDWS 15\n#define PHPRTLC_SHAREABLEWS 16\n#define PHPRTLC_VIRTUALSIZE 17\n#define PHPRTLC_PEAKVIRTUALSIZE 18\n#define PHPRTLC_PAGEFAULTS 19\n#define PHPRTLC_SESSIONID 20\n#define PHPRTLC_PRIORITYCLASS 21\n#define PHPRTLC_BASEPRIORITY 22\n\n#define PHPRTLC_THREADS 23\n#define PHPRTLC_HANDLES 24\n#define PHPRTLC_GDIHANDLES 25\n#define PHPRTLC_USERHANDLES 26\n#define PHPRTLC_IORORATE 27\n#define PHPRTLC_IOWRATE 28\n#define PHPRTLC_INTEGRITY 29\n#define PHPRTLC_IOPRIORITY 30\n#define PHPRTLC_PAGEPRIORITY 31\n#define PHPRTLC_STARTTIME 32\n#define PHPRTLC_TOTALCPUTIME 33\n#define PHPRTLC_KERNELCPUTIME 34\n#define PHPRTLC_USERCPUTIME 35\n#define PHPRTLC_VERIFICATIONSTATUS 36\n#define PHPRTLC_VERIFIEDSIGNER 37\n#define PHPRTLC_ASLR 38\n#define PHPRTLC_RELATIVESTARTTIME 39\n#define PHPRTLC_BITS 40\n#define PHPRTLC_ELEVATION 41\n#define PHPRTLC_WINDOWTITLE 42\n#define PHPRTLC_WINDOWSTATUS 43\n#define PHPRTLC_CYCLES 44\n#define PHPRTLC_CYCLESDELTA 45\n#define PHPRTLC_CPUHISTORY 46\n#define PHPRTLC_PRIVATEBYTESHISTORY 47\n#define PHPRTLC_IOHISTORY 48\n#define PHPRTLC_DEP 49\n#define PHPRTLC_VIRTUALIZED 50\n#define PHPRTLC_CONTEXTSWITCHES 51\n#define PHPRTLC_CONTEXTSWITCHESDELTA 52\n#define PHPRTLC_PAGEFAULTSDELTA 53\n\n#define PHPRTLC_IOREADS 54\n#define PHPRTLC_IOWRITES 55\n#define PHPRTLC_IOOTHER 56\n#define PHPRTLC_IOREADBYTES 57\n#define PHPRTLC_IOWRITEBYTES 58\n#define PHPRTLC_IOOTHERBYTES 59\n#define PHPRTLC_IOREADSDELTA 60\n#define PHPRTLC_IOWRITESDELTA 61\n#define PHPRTLC_IOOTHERDELTA 62\n\n#define PHPRTLC_OSCONTEXT 63\n#define PHPRTLC_PAGEDPOOL 64\n#define PHPRTLC_PEAKPAGEDPOOL 65\n#define PHPRTLC_NONPAGEDPOOL 66\n#define PHPRTLC_PEAKNONPAGEDPOOL 67\n#define PHPRTLC_MINIMUMWORKINGSET 68\n#define PHPRTLC_MAXIMUMWORKINGSET 69\n#define PHPRTLC_PRIVATEBYTESDELTA 70\n#define PHPRTLC_SUBSYSTEM 71\n#define PHPRTLC_PACKAGENAME 72\n#define PHPRTLC_APPID 73\n#define PHPRTLC_DPIAWARENESS 74\n#define PHPRTLC_CFGUARD 75\n#define PHPRTLC_TIMESTAMP 76\n#define PHPRTLC_FILEMODIFIEDTIME 77\n#define PHPRTLC_FILESIZE 78\n#define PHPRTLC_SUBPROCESSCOUNT 79\n#define PHPRTLC_JOBOBJECTID 80\n#define PHPRTLC_PROTECTION 81\n#define PHPRTLC_DESKTOP 82\n#define PHPRTLC_CRITICAL 83\n#define PHPRTLC_PIDHEX 84\n#define PHPRTLC_CPUCORECYCLES 85\n#define PHPRTLC_CET 86\n#define PHPRTLC_IMAGE_COHERENCY 87\n#define PHPRTLC_ERRORMODE 88\n#define PHPRTLC_CODEPAGE 89\n#define PHPRTLC_TIMELINE 90\n#define PHPRTLC_POWERTHROTTLING 91\n#define PHPRTLC_ARCHITECTURE 92\n#define PHPRTLC_PARENTPID 93\n#define PHPRTLC_PARENTCONSOLEPID 94\n#define PHPRTLC_COMMITSIZE 95\n#define PHPRTLC_PRIORITYBOOST 96\n#define PHPRTLC_CPUAVERAGE 97\n#define PHPRTLC_CPUKERNEL 98\n#define PHPRTLC_CPUUSER 99\n#define PHPRTLC_GRANTEDACCESS 100\n#define PHPRTLC_TLSBITMAPDELTA 101\n#define PHPRTLC_REFERENCEDELTA 102\n#define PHPRTLC_LXSSPID 103\n#define PHPRTLC_START_KEY 104\n#define PHPRTLC_MITIGATION_POLICIES 105\n#define PHPRTLC_SERVICES 106\n\n#define PHPRTLC_MAXIMUM 107\n#define PHPRTLC_IOGROUP_COUNT 9\n\n#define PHPN_WSCOUNTERS 0x1\n#define PHPN_GDIHANDLES 0x2\n#define PHPN_IOPAGEPRIORITY 0x4\n#define PHPN_WINDOW 0x8\n#define PHPN_DEPSTATUS 0x10\n#define PHPN_TOKEN 0x20\n#define PHPN_OSCONTEXT 0x40\n#define PHPN_QUOTALIMITS 0x80\n#define PHPN_IMAGE 0x100\n#define PHPN_APPID 0x200\n#define PHPN_DPIAWARENESS 0x400\n#define PHPN_FILEATTRIBUTES 0x800\n#define PHPN_DESKTOPINFO 0x1000\n#define PHPN_USERNAME 0x2000\n#define PHPN_CRITICAL 0x4000\n#define PHPN_ERRORMODE 0x8000\n#define PHPN_CODEPAGE 0x10000\n#define PHPN_POWERTHROTTLING 0x20000\n#define PHPN_MITIGATIONPOLICIES 0x40000\n#define PHPN_PRIORITYBOOST 0x80000\n#define PHPN_GRANTEDACCESS 0x100000\n#define PHPN_TLSBITMAPDELTA 0x200000\n#define PHPN_REFERENCEDELTA 0x400000\n#define PHPN_STARTKEY 0x800000\n#define PHPN_SERVICES 0x1000000\n#define PHPN_USERHANDLES 0x2000000\n\n// begin_phapppub\ntypedef struct _PH_PROCESS_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PH_HASH_ENTRY HashEntry;\n\n    PH_SH_STATE ShState;\n\n    HANDLE ProcessId;\n    PPH_PROCESS_ITEM ProcessItem;\n\n    struct _PH_PROCESS_NODE *Parent;\n    PPH_LIST Children;\n// end_phapppub\n\n    PH_STRINGREF TextCache[PHPRTLC_MAXIMUM];\n\n    // If the user has selected certain columns we need extra information that isn't retrieved by\n    // the process provider.\n    ULONG ValidMask;\n\n    // WS counters\n    PH_PROCESS_WS_COUNTERS WsCounters;\n    // GDI, USER handles\n    ULONG GdiHandles;\n    ULONG UserHandles;\n    // I/O, page priority\n    IO_PRIORITY_HINT IoPriority;\n    ULONG PagePriority;\n    // Window\n    HWND WindowHandle;\n    PPH_STRING WindowText;\n    // DEP status\n    ULONG DepStatus;\n\n    BOOLEAN WindowHung;\n    BOOLEAN VirtualizationAllowed;\n    BOOLEAN VirtualizationEnabled;\n    BOOLEAN BreakOnTerminationEnabled;\n    BOOLEAN PowerThrottling;\n    BOOLEAN PriorityBoost;\n\n    // OS Context\n    GUID OsContextGuid;\n    ULONG OsContextVersion;\n    // Quota limits\n    SIZE_T MinimumWorkingSetSize;\n    SIZE_T MaximumWorkingSetSize;\n    // Image\n    ULONG ImageTimeDateStamp;\n    USHORT ImageCharacteristics;\n    USHORT ImageMachine;\n    USHORT ImageSubsystem;\n    USHORT ImageDllCharacteristics;\n#ifdef _ARM64_\n    ULONG ImageCHPEVersion;\n#endif\n    USHORT Architecture;\n\n    // App ID\n    PPH_STRING AppIdText;\n    // DPI awareness\n    PH_PROCESS_DPI_AWARENESS DpiAwareness;\n    // File attributes\n    LARGE_INTEGER FileLastWriteTime;\n    LARGE_INTEGER FileEndOfFile;\n    // Code page\n    USHORT CodePage;\n    // TLS bitmap\n    USHORT TlsBitmapCount;\n    // Reference count\n    ULONG ReferenceCount;\n    // Start key\n    ULONGLONG ProcessStartKey;\n\n    PPH_STRING FileNameWin32;\n    ULONG ServerSiloId;\n\n    PPH_STRING TooltipText;\n    ULONG64 TooltipTextValidToTickCount;\n\n    // Text buffers\n    WCHAR CpuUsageText[PH_INT32_STR_LEN_1 + 3];\n    PPH_STRING IoTotalRateText;\n    PPH_STRING PrivateBytesText;\n    PPH_STRING PeakPrivateBytesText;\n    PPH_STRING WorkingSetText;\n    PPH_STRING PeakWorkingSetText;\n    PPH_STRING PrivateWsText;\n    PPH_STRING SharedWsText;\n    PPH_STRING ShareableWsText;\n    PPH_STRING VirtualSizeText;\n    PPH_STRING PeakVirtualSizeText;\n    PPH_STRING PageFaultsText;\n    PPH_STRING SessionIdText;\n    PPH_STRING BasePriorityText;\n    PPH_STRING ThreadsText;\n    PPH_STRING HandlesText;\n    PPH_STRING GdiHandlesText;\n    PPH_STRING UserHandlesText;\n    PPH_STRING IoRoRateText;\n    PPH_STRING IoWRateText;\n    PPH_STRING StartTimeText;\n    PPH_STRING TotalCpuTimeText;\n    PPH_STRING KernelCpuTimeText;\n    PPH_STRING UserCpuTimeText;\n    PPH_STRING RelativeStartTimeText;\n    PPH_STRING WindowTitleText;\n    PPH_STRING DepStatusText;\n    PPH_STRING CyclesText;\n    PPH_STRING CyclesDeltaText;\n    PPH_STRING ContextSwitchesText;\n    PPH_STRING ContextSwitchesDeltaText;\n    PPH_STRING PageFaultsDeltaText;\n    PPH_STRING IoGroupText[PHPRTLC_IOGROUP_COUNT];\n    PPH_STRING PagedPoolText;\n    PPH_STRING PeakPagedPoolText;\n    PPH_STRING NonPagedPoolText;\n    PPH_STRING PeakNonPagedPoolText;\n    PPH_STRING MinimumWorkingSetText;\n    PPH_STRING MaximumWorkingSetText;\n    PPH_STRING PrivateBytesDeltaText;\n    PPH_STRING TimeStampText;\n    PPH_STRING FileModifiedTimeText;\n    PPH_STRING FileSizeText;\n    PPH_STRING SubprocessCountText;\n    PPH_STRING JobObjectIdText;\n    PPH_STRING ProtectionText;\n    PPH_STRING DesktopInfoText;\n    PPH_STRING CpuCoreUsageText;\n    PPH_STRING ImageCoherencyText;\n    PPH_STRING ImageCoherencyStatusText;\n    PPH_STRING ErrorModeText;\n    PPH_STRING CodePageText;\n    PPH_STRING ParentPidText;\n    PPH_STRING ParentConsolePidText;\n    PPH_STRING SharedCommitText;\n    PPH_STRING CpuAverageText;\n    PPH_STRING CpuKernelText;\n    PPH_STRING CpuUserText;\n    PPH_STRING GrantedAccessText;\n    PPH_STRING TlsBitmapDeltaText;\n    PPH_STRING ReferenceCountText;\n    PPH_STRING LxssProcessIdText;\n    PPH_STRING ProcessStartKeyText;\n    PPH_STRING MitigationPoliciesText;\n    PPH_STRING ServicesText;\n    PPH_STRING ServerSiloText;\n\n    // Graph buffers\n    PH_GRAPH_BUFFERS CpuGraphBuffers;\n    PH_GRAPH_BUFFERS PrivateGraphBuffers;\n    PH_GRAPH_BUFFERS IoGraphBuffers;\n// begin_phapppub\n} PH_PROCESS_NODE, *PPH_PROCESS_NODE;\n// end_phapppub\n\nVOID PhProcessTreeListInitialization(\n    VOID\n    );\n\nVOID PhInitializeProcessTreeList(\n    _In_ HWND hwnd\n    );\n\nVOID PhLoadSettingsProcessTreeList(\n    VOID\n    );\n\nVOID PhSaveSettingsProcessTreeList(\n    VOID\n    );\n\nVOID PhLoadSettingsProcessTreeListEx(\n    _In_ PPH_STRING TreeListSettings,\n    _In_ PPH_STRING TreeSortSettings\n    );\n\nVOID PhSaveSettingsProcessTreeListEx(\n    _Out_ PPH_STRING *TreeListSettings,\n    _Out_ PPH_STRING *TreeSortSettings\n    );\n\nVOID PhReloadSettingsProcessTreeList(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_TN_FILTER_SUPPORT\nNTAPI\nPhGetFilterSupportProcessTreeList(\n    VOID\n    );\n// end_phapppub\n\nPPH_PROCESS_NODE PhAddProcessNode(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG RunId\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_PROCESS_NODE\nNTAPI\nPhFindProcessNode(\n    _In_ HANDLE ProcessId\n    );\n// end_phapppub\n\nVOID PhRemoveProcessNode(\n    _In_ PPH_PROCESS_NODE ProcessNode\n    );\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhUpdateProcessNode(\n    _In_ PPH_PROCESS_NODE ProcessNode\n    );\n// end_phapppub\n\nVOID PhTickProcessNodes(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_PROCESS_ITEM\nNTAPI\nPhGetSelectedProcessItem(\n    VOID\n    );\n\n_Success_(return)\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhGetSelectedProcessItems(\n    _Out_ PPH_PROCESS_ITEM **Processes,\n    _Out_ PULONG NumberOfProcesses\n    );\n\nPHAPPAPI\nPPH_PROCESS_NODE\nNTAPI\nPhGetSelectedProcessNode(\n    VOID\n    );\n\n_Success_(return)\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhGetSelectedProcessNodes(\n    _Out_ PPH_PROCESS_NODE** Nodes,\n    _Out_ PULONG NumberOfNodes\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhGetSelectedAndPropagateProcessItems(\n    _Out_ PPH_PROCESS_ITEM** Processes,\n    _Out_ PULONG NumberOfProcesses\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhDeselectAllProcessNodes(\n    VOID\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhExpandAllProcessNodes(\n    _In_ BOOLEAN Expand\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhInvalidateAllProcessNodes(\n    VOID\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhSelectAndEnsureVisibleProcessNode(\n    _In_ PPH_PROCESS_NODE ProcessNode\n    );\n// end_phapppub\n\nBOOLEAN PhSelectAndEnsureVisibleProcessNodes(\n    _In_ PPH_PROCESS_NODE *ProcessNodes,\n    _In_ ULONG NumberOfProcessNodes\n    );\n\nPPH_LIST PhGetProcessTreeListLines(\n    _In_ HWND TreeListHandle,\n    _In_ ULONG NumberOfNodes,\n    _In_ PPH_LIST RootNodes,\n    _In_ ULONG Mode\n    );\n\nVOID PhCopyProcessTree(\n    VOID\n    );\n\nVOID PhWriteProcessTree(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ ULONG Mode\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_LIST\nNTAPI\nPhDuplicateProcessNodeList(\n    VOID\n    );\n// end_phapppub\n\nNTSTATUS PhGetProcessItemFileNameWin32(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _Out_ PPH_STRING *FileNameWin32\n    );\n\n// begin_phapppub\ntypedef enum _PH_AGGREGATE_TYPE\n{\n    AggregateTypeFloat,\n    AggregateTypeInt32,\n    AggregateTypeInt64,\n    AggregateTypeIntPtr\n} PH_AGGREGATE_TYPE;\n\ntypedef enum _PH_AGGREGATE_LOCATION\n{\n    AggregateProcessItem,\n    AggregateProcessNode,\n} PH_AGGREGATE_LOCATION;\n\nPHAPPAPI\nVOID\nNTAPI\nPhAggregateProcessFieldIfNeeded(\n    _In_ PPH_PROCESS_NODE ProcessNode,\n    _In_ PH_AGGREGATE_TYPE Type,\n    _In_ PH_AGGREGATE_LOCATION Location,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T FieldOffset,\n    _Inout_ PVOID AggregatedValue\n    );\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/srvlist.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2024\n *\n */\n\n#ifndef PH_SRVLIST_H\n#define PH_SRVLIST_H\n\n#include <phuisup.h>\n\n// Columns\n\n#define PHSVTLC_NAME 0\n#define PHSVTLC_PID 1\n#define PHSVTLC_DISPLAYNAME 2\n#define PHSVTLC_TYPE 3\n#define PHSVTLC_STATUS 4\n#define PHSVTLC_STARTTYPE 5\n\n#define PHSVTLC_BINARYPATH 6\n#define PHSVTLC_ERRORCONTROL 7\n#define PHSVTLC_GROUP 8\n#define PHSVTLC_DESCRIPTION 9\n#define PHSVTLC_KEYMODIFIEDTIME 10\n#define PHSVTLC_VERIFICATIONSTATUS 11\n#define PHSVTLC_VERIFIEDSIGNER 12\n#define PHSVTLC_FILENAME 13\n#define PHSVTLC_TIMELINE 14\n#define PHSVTLC_EXITCODE 15\n\n#define PHSVTLC_MAXIMUM 16\n\n#define PHSN_CONFIG 0x1\n#define PHSN_DESCRIPTION 0x2\n#define PHSN_KEY 0x4\n\n// begin_phapppub\ntypedef struct _PH_SERVICE_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PH_SH_STATE ShState;\n\n    PPH_SERVICE_ITEM ServiceItem;\n\n    WCHAR StartTypeText[12 + 24 + 1];\n    // Config\n    PPH_STRING BinaryPath;\n    PPH_STRING LoadOrderGroup;\n    // Description\n    PPH_STRING Description;\n    // Key\n    LARGE_INTEGER KeyLastWriteTime;\n    PPH_STRING KeyModifiedTimeText;\n    // Exitcode\n    PPH_STRING ExitCodeText;\n// end_phapppub\n    PPH_STRING TooltipText;\n    ULONG ValidMask;\n    PH_STRINGREF TextCache[PHSVTLC_MAXIMUM];\n// begin_phapppub\n} PH_SERVICE_NODE, *PPH_SERVICE_NODE;\n// end_phapppub\n\nVOID PhServiceTreeListInitialization(\n    VOID\n    );\n\nVOID PhInitializeServiceTreeList(\n    _In_ HWND WindowHandle\n    );\n\nVOID PhLoadSettingsServiceTreeList(\n    VOID\n    );\n\nVOID PhSaveSettingsServiceTreeList(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_TN_FILTER_SUPPORT\nNTAPI\nPhGetFilterSupportServiceTreeList(\n    VOID\n    );\n// end_phapppub\n\nPPH_SERVICE_NODE PhAddServiceNode(\n    _In_ PPH_SERVICE_ITEM ServiceItem,\n    _In_ ULONG RunId\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_SERVICE_NODE\nNTAPI\nPhFindServiceNode(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    );\n// end_phapppub\n\nVOID PhRemoveServiceNode(\n    _In_ PPH_SERVICE_NODE ServiceNode\n    );\n\n// begin_phapppub\nPHAPPAPI\nVOID\nNTAPI\nPhUpdateServiceNode(\n    _In_ PPH_SERVICE_NODE ServiceNode\n    );\n// end_phapppub\n\nVOID PhTickServiceNodes(\n    VOID\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_SERVICE_ITEM\nNTAPI\nPhGetSelectedServiceItem(\n    VOID\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhGetSelectedServiceItems(\n    _Out_ PPH_SERVICE_ITEM **Services,\n    _Out_ PULONG NumberOfServices\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhDeselectAllServiceNodes(\n    VOID\n    );\n\nPHAPPAPI\nBOOLEAN\nNTAPI\nPhSelectAndEnsureVisibleServiceNode(\n    _In_ PPH_SERVICE_NODE ServiceNode\n    );\n// end_phapppub\n\nVOID PhCopyServiceList(\n    VOID\n    );\n\nVOID PhWriteServiceList(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ ULONG Mode\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/srvprv.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#ifndef PH_SRVPRV_H\n#define PH_SRVPRV_H\n\nextern PPH_OBJECT_TYPE PhServiceItemType;\nextern BOOLEAN PhEnableServiceNonPoll;\nextern BOOLEAN PhEnableServiceNonPollNotify;\nextern ULONG PhServiceNonPollFlushInterval;\n\n// begin_phapppub\ntypedef enum _VERIFY_RESULT VERIFY_RESULT;\ntypedef struct _PH_IMAGELIST_ITEM* PPH_IMAGELIST_ITEM;\n\ntypedef struct _PH_SERVICE_ITEM\n{\n    PH_STRINGREF Key; // points to Name\n    PPH_STRING Name;\n    PPH_STRING DisplayName;\n    PPH_STRING FileName;\n\n    PPH_IMAGELIST_ITEM IconEntry;\n    volatile LONG JustProcessed;\n\n    // State\n    ULONG Type;\n    ULONG State;\n    ULONG ControlsAccepted;\n    ULONG Flags; // e.g. SERVICE_RUNS_IN_SYSTEM_PROCESS\n    HANDLE ProcessId;\n\n    // Config\n    ULONG StartType;\n    ULONG ErrorControl;\n\n    // ExitCode\n    ULONG Win32ExitCode;\n    ULONG ServiceSpecificExitCode;\n\n    // Signature\n    VERIFY_RESULT VerifyResult;\n    PPH_STRING VerifySignerName;\n\n    WCHAR ProcessIdString[PH_INT32_STR_LEN_1];\n\n    // end_phapppub\n    union\n    {\n        BOOLEAN BitFlags;\n        struct\n        {\n            BOOLEAN DelayedStart : 1;\n            BOOLEAN HasTriggers : 1;\n            BOOLEAN PendingProcess : 1;\n            BOOLEAN NeedsConfigUpdate : 1;\n            BOOLEAN MicrosoftService : 1;\n            BOOLEAN Spare : 3;\n        };\n    };\n\n    PSC_NOTIFICATION_REGISTRATION NotifyPropertyRegistration;\n    PSC_NOTIFICATION_REGISTRATION NotifyStatusRegistration;\n    union\n    {\n        BOOLEAN NotifyFlags;\n        struct\n        {\n            BOOLEAN NotifyCreatedPropertyRegistration : 1;\n            BOOLEAN NotifyCreatedStatusRegistration : 1;\n            BOOLEAN NotifySpare : 6;\n        };\n    };\n// begin_phapppub\n} PH_SERVICE_ITEM, *PPH_SERVICE_ITEM;\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_SERVICE_MODIFIED_DATA\n{\n    PPH_SERVICE_ITEM ServiceItem;\n    PH_SERVICE_ITEM OldService;\n} PH_SERVICE_MODIFIED_DATA, *PPH_SERVICE_MODIFIED_DATA;\n\ntypedef enum _PH_SERVICE_CHANGE\n{\n    ServiceNone,\n    ServiceStarted,\n    ServiceContinued,\n    ServicePaused,\n    ServiceStopped,\n    ServiceModified,\n} PH_SERVICE_CHANGE, *PPH_SERVICE_CHANGE;\n// end_phapppub\n\nBOOLEAN PhServiceProviderInitialization(\n    VOID\n    );\n\nPPH_SERVICE_ITEM PhCreateServiceItem(\n    _In_opt_ LPENUM_SERVICE_STATUS_PROCESS Information\n    );\n\n// begin_phapppub\nPHAPPAPI\nPPH_SERVICE_ITEM\nNTAPI\nPhReferenceServiceItem(\n    _In_ PPH_STRINGREF Name\n    );\n\nFORCEINLINE\nPPH_SERVICE_ITEM\nNTAPI\nPhReferenceServiceItemZ(\n    _In_ PCWSTR Name\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRefLongHint(&name, Name);\n\n    return PhReferenceServiceItem(&name);\n}\n\n// end_phapppub\n\nVOID PhMarkNeedsConfigUpdateServiceItem(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    );\n\n// begin_phapppub\nPHAPPAPI\nPH_SERVICE_CHANGE\nNTAPI\nPhGetServiceChange(\n    _In_ PPH_SERVICE_MODIFIED_DATA Data\n    );\n// end_phapppub\n\nVOID PhUpdateProcessItemServices(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhServiceProviderUpdate(\n    _In_ PVOID Object\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/sysinfo.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_SYSINFO_H\n#define PH_SYSINFO_H\n\n// begin_phapppub\ntypedef enum _PH_SYSINFO_VIEW_TYPE\n{\n    SysInfoSummaryView,\n    SysInfoSectionView\n} PH_SYSINFO_VIEW_TYPE;\n\ntypedef _Function_class_(PH_SYSINFO_COLOR_SETUP_FUNCTION)\nVOID NTAPI PH_SYSINFO_COLOR_SETUP_FUNCTION(\n    _Out_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ COLORREF Color1,\n    _In_ COLORREF Color2,\n    _In_ LONG WindowDpi\n    );\ntypedef PH_SYSINFO_COLOR_SETUP_FUNCTION* PPH_SYSINFO_COLOR_SETUP_FUNCTION;\n\ntypedef struct _PH_SYSINFO_PARAMETERS\n{\n    HWND SysInfoWindowHandle;\n    HWND ContainerWindowHandle;\n\n    PPH_SYSINFO_COLOR_SETUP_FUNCTION ColorSetupFunction;\n\n    HFONT Font;\n    HFONT MediumFont;\n    HFONT LargeFont;\n    ULONG FontHeight;\n    ULONG FontAverageWidth;\n    ULONG MediumFontHeight;\n    ULONG MediumFontAverageWidth;\n    COLORREF GraphBackColor;\n    COLORREF PanelForeColor;\n\n    ULONG MinimumGraphHeight;\n    ULONG SectionViewGraphHeight;\n    LONG PanelWidth;\n    LONG WindowDpi;\n// end_phapppub\n\n    ULONG PanelPadding;\n    ULONG WindowPadding;\n    ULONG GraphPadding;\n    ULONG SmallGraphWidth;\n    ULONG SmallGraphPadding;\n    ULONG SeparatorWidth;\n    ULONG CpuPadding;\n    ULONG MemoryPadding;\n// begin_phapppub\n} PH_SYSINFO_PARAMETERS, *PPH_SYSINFO_PARAMETERS;\n\ntypedef enum _PH_SYSINFO_SECTION_MESSAGE\n{\n    SysInfoCreate,\n    SysInfoDestroy,\n    SysInfoTick,\n    SysInfoViewChanging, // PH_SYSINFO_VIEW_TYPE Parameter1, PPH_SYSINFO_SECTION Parameter2\n    SysInfoCreateDialog, // PPH_SYSINFO_CREATE_DIALOG Parameter1\n    SysInfoGraphGetDrawInfo, // PPH_GRAPH_DRAW_INFO Parameter1\n    SysInfoGraphGetTooltipText, // PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT Parameter1\n    SysInfoGraphDrawPanel, // PPH_SYSINFO_DRAW_PANEL Parameter1\n    SysInfoDpiChanged, // ULONG Parameter1\n    MaxSysInfoMessage\n} PH_SYSINFO_SECTION_MESSAGE;\n\ntypedef struct _PH_SYSINFO_SECTION *PPH_SYSINFO_SECTION;\n\ntypedef _Function_class_(PH_SYSINFO_SECTION_CALLBACK)\nBOOLEAN NTAPI PH_SYSINFO_SECTION_CALLBACK(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ PH_SYSINFO_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    );\ntypedef PH_SYSINFO_SECTION_CALLBACK* PPH_SYSINFO_SECTION_CALLBACK;\n\ntypedef struct _PH_SYSINFO_CREATE_DIALOG\n{\n    BOOLEAN CustomCreate;\n\n    // Parameters for default create\n    PVOID Instance;\n    PWSTR Template;\n    DLGPROC DialogProc;\n    PVOID Parameter;\n} PH_SYSINFO_CREATE_DIALOG, *PPH_SYSINFO_CREATE_DIALOG;\n\ntypedef struct _PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT\n{\n    ULONG Index;\n    PH_STRINGREF Text;\n} PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT, *PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT;\n\ntypedef struct _PH_SYSINFO_DRAW_PANEL\n{\n    HDC hdc;\n    RECT Rect;\n    BOOLEAN CustomDraw;\n\n    // Parameters for default draw\n    PPH_STRING Title;\n    PPH_STRING SubTitle;\n    PPH_STRING SubTitleOverflow;\n} PH_SYSINFO_DRAW_PANEL, *PPH_SYSINFO_DRAW_PANEL;\n// end_phapppub\n\n// begin_phapppub\ntypedef struct _PH_SYSINFO_SECTION\n{\n    // Public\n\n    // Initialization\n    PH_STRINGREF Name;\n    ULONG Flags;\n    PPH_SYSINFO_SECTION_CALLBACK Callback;\n    PVOID Context;\n\n    // State\n    HWND GraphHandle;\n    PH_GRAPH_STATE GraphState;\n    PPH_SYSINFO_PARAMETERS Parameters;\n\n// end_phapppub\n\n    // Private\n\n    struct\n    {\n        ULONG GraphHot : 1;\n        ULONG PanelHot : 1;\n        ULONG HasFocus : 1;\n        ULONG HideFocus : 1;\n        ULONG SpareFlags : 28;\n    };\n\n    HWND DialogHandle;\n    HWND PanelHandle;\n    ULONG PanelId;\n\n    WNDPROC GraphWindowProc;\n    WNDPROC PanelWindowProc;\n// begin_phapppub\n} PH_SYSINFO_SECTION, *PPH_SYSINFO_SECTION;\n// end_phapppub\n\nVOID PhSiNotifyChangeSettings(\n    VOID\n    );\n\n// begin_phapppub\n_Function_class_(PH_SYSINFO_COLOR_SETUP_FUNCTION)\nPHAPPAPI\nVOID\nNTAPI\nPhSiSetColorsGraphDrawInfo(\n    _Out_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ COLORREF Color1,\n    _In_ COLORREF Color2,\n    _In_ LONG WindowDpi\n    );\n\n_Function_class_(PH_GRAPH_LABEL_Y_FUNCTION)\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhSiSizeLabelYFunction(\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataIndex,\n    _In_ FLOAT Value,\n    _In_ FLOAT Parameter\n    );\n\n_Function_class_(PH_GRAPH_LABEL_Y_FUNCTION)\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhSiDoubleLabelYFunction(\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataIndex,\n    _In_ FLOAT Value,\n    _In_ FLOAT Parameter\n    );\n\n_Function_class_(PH_GRAPH_LABEL_Y_FUNCTION)\nPHAPPAPI\nPPH_STRING\nNTAPI\nPhSiUInt64LabelYFunction(\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataIndex,\n    _In_ FLOAT Value,\n    _In_ FLOAT Parameter\n    );\n\nPHAPPAPI\nVOID\nNTAPI\nPhShowSystemInformationDialog(\n    _In_opt_ PCWSTR SectionName\n    );\n// end_phapppub\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/sysinfop.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2016-2024\n *\n */\n\n#ifndef PH_SYSINFOP_H\n#define PH_SYSINFOP_H\n\n// Constants\n\n#define PH_SYSINFO_FADE_ADD 50\n#define PH_SYSINFO_PANEL_PADDING 3\n#define PH_SYSINFO_WINDOW_PADDING 7\n#define PH_SYSINFO_GRAPH_PADDING 4\n#define PH_SYSINFO_SMALL_GRAPH_WIDTH 48\n#define PH_SYSINFO_SMALL_GRAPH_PADDING 5\n#define PH_SYSINFO_SEPARATOR_WIDTH 2\n\n#define PH_SYSINFO_CPU_PADDING 5\n#define PH_SYSINFO_MEMORY_PADDING 3\n\n#define SI_MSG_SYSINFO_FIRST (WM_APP + 150)\n#define SI_MSG_SYSINFO_ACTIVATE (WM_APP + 150)\n#define SI_MSG_SYSINFO_UPDATE (WM_APP + 151)\n#define SI_MSG_SYSINFO_CHANGE_SETTINGS (WM_APP + 152)\n#define SI_MSG_SYSINFO_LAST (WM_APP + 152)\n\n// Thread & window\n\nextern HWND PhSipWindow;\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhSipSysInfoThreadStart(\n    _In_ PVOID Parameter\n    );\n\n_Function_class_(DLGPROC)\nINT_PTR CALLBACK PhSipSysInfoDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(DLGPROC)\nINT_PTR CALLBACK PhSipContainerDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n// Event handlers\n\nVOID PhSipOnInitDialog(\n    VOID\n    );\n\nVOID PhSipOnDestroy(\n    VOID\n    );\n\nVOID PhSipOnNcDestroy(\n    VOID\n    );\n\nBOOLEAN PhSipOnSysCommand(\n    _In_ ULONG Type,\n    _In_ LONG CursorScreenX,\n    _In_ LONG CursorScreenY\n    );\n\nVOID PhSipOnSize(\n    _In_ HWND WindowHandle,\n    _In_ UINT State,\n    _In_ LONG Width,\n    _In_ LONG Height\n    );\n\nVOID PhSipOnSizing(\n    _In_ ULONG Edge,\n    _In_ PRECT DragRectangle\n    );\n\nVOID PhSipOnThemeChanged(\n    VOID\n    );\n\nVOID PhSipOnCommand(\n    _In_ HWND HwndControl,\n    _In_ ULONG Id,\n    _In_ ULONG Code\n    );\n\n_Success_(return)\nBOOLEAN PhSipOnNotify(\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    );\n\nBOOLEAN PhSipOnDrawItem(\n    _In_ ULONG_PTR Id,\n    _In_ PDRAWITEMSTRUCT DrawItemStruct\n    );\n\nVOID PhSipOnUserMessage(\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    );\n\nULONG PhSipGetProcessorRelationshipIndex(\n    _In_ LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,\n    _In_ ULONG Index\n    );\n\n// Framework\n\nVOID PhSipRegisterDialog(\n    _In_ HWND DialogWindowHandle\n    );\n\nVOID PhSipUnregisterDialog(\n    _In_ HWND DialogWindowHandle\n    );\n\nVOID PhSipInitializeParameters(\n    VOID\n    );\n\nVOID PhSipDeleteParameters(\n    VOID\n    );\n\nVOID PhSipUpdateColorParameters(\n    VOID\n    );\n\n_Function_class_(PH_SYSINFO_CREATE_SECTION)\nPPH_SYSINFO_SECTION PhSipCreateSection(\n    _In_ PPH_SYSINFO_SECTION Template\n    );\n\nVOID PhSipDestroySection(\n    _In_ PPH_SYSINFO_SECTION Section\n    );\n\n_Function_class_(PH_SYSINFO_FIND_SECTION)\nPPH_SYSINFO_SECTION PhSipFindSection(\n    _In_ PPH_STRINGREF Name\n    );\n\nPPH_SYSINFO_SECTION PhSipCreateInternalSection(\n    _In_ PWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_SYSINFO_SECTION_CALLBACK Callback\n    );\n\nVOID PhSipDrawRestoreSummaryPanel(\n    _In_ PDRAWITEMSTRUCT DrawItemStruct\n    );\n\nVOID PhSipDrawSeparator(\n    _In_ PDRAWITEMSTRUCT DrawItemStruct\n    );\n\nVOID PhSipDrawPanel(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ HDC hdc,\n    _In_ PRECT Rect\n    );\n\nVOID PhSipDefaultDrawPanel(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ PPH_SYSINFO_DRAW_PANEL DrawPanel\n    );\n\nVOID PhSipLayoutSummaryView(\n    VOID\n    );\n\nVOID PhSipLayoutSectionView(\n    VOID\n    );\n\n_Function_class_(PH_SYSINFO_ENTER_SECTION_VIEW)\nVOID PhSipEnterSectionView(\n    _In_ PPH_SYSINFO_SECTION NewSection\n    );\n\nVOID PhSipEnterSectionViewInner(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ BOOLEAN FromSummaryView,\n    _Inout_ HDWP *DeferHandle,\n    _Inout_ HDWP *ContainerDeferHandle\n    );\n\n_Function_class_(PH_SYSINFO_RESTORE_SUMMARY_VIEW)\nVOID PhSipRestoreSummaryView(\n    VOID\n    );\n\nVOID PhSipCreateSectionDialog(\n    _In_ PPH_SYSINFO_SECTION Section\n    );\n\n_Function_class_(WNDPROC)\nLRESULT CALLBACK PhSipGraphHookWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(WNDPROC)\nLRESULT CALLBACK PhSipPanelHookWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nLRESULT CALLBACK PhSipRestorePanelHookWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n// Misc.\n\nVOID PhSipUpdateProcessorInformation(\n    VOID\n    );\n\nVOID PhSipUpdateInterruptInformation(\n    _Out_ PULONG64 DpcCount\n    );\n\nVOID PhSipUpdateProcessorFrequency(\n    VOID\n    );\n\nVOID PhSipUpdateTimerResolution(\n    VOID\n    );\n\nVOID PhSipUpdateProcessorPerformanceDistribution(\n    VOID\n    );\n\nVOID PhSipUpdateThemeData(\n    VOID\n    );\n\nVOID PhSipSaveWindowState(\n    VOID\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhSipSysInfoUpdateHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhSipSysInfoSettingsCallback(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    );\n\n// CPU section\n\n_Function_class_(PH_SYSINFO_SECTION_CALLBACK)\nBOOLEAN PhSipCpuSectionCallback(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ PH_SYSINFO_SECTION_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    );\n\nVOID PhSipInitializeCpuDialog(\n    VOID\n    );\n\nVOID PhSipUninitializeCpuDialog(\n    VOID\n    );\n\nVOID PhSipTickCpuDialog(\n    VOID\n    );\n\nINT_PTR CALLBACK PhSipCpuDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhSipCpuPanelDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhSipCreateCpuGraphs(\n    VOID\n    );\n\nVOID PhSipLayoutCpuGraphs(\n    VOID\n    );\n\nVOID PhSipSetOneGraphPerCpu(\n    VOID\n    );\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipCpuGraphCallback(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\nVOID PhSipUpdateCpuGraphs(\n    VOID\n    );\n\nVOID PhSipUpdateCpuPanel(\n    VOID\n    );\n\nPPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord(\n    _In_ LONG Index\n    );\n\nPPH_STRING PhSipGetMaxCpuString(\n    _In_ LONG Index\n    );\n\nPPH_STRING PhSipGetCpuBrandString(\n    VOID\n    );\n\n_Success_(return)\nBOOLEAN PhSipGetCpuFrequencyFromDistribution(\n    _Out_ DOUBLE *Frequency\n    );\n\nPCPH_STRINGREF PhGetHybridProcessorType(\n    _In_ ULONG ProcessorIndex\n    );\n\nBOOLEAN PhIsCoreParked(\n    _In_ ULONG ProcessorIndex\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI PhSipCpuSMBIOSWorkRoutine(\n    _In_ PVOID ThreadParameter\n    );\n\n// Memory section\n\n_Function_class_(PH_SYSINFO_SECTION_CALLBACK)\nBOOLEAN PhSipMemorySectionCallback(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ PH_SYSINFO_SECTION_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    );\n\nVOID PhSipInitializeMemoryDialog(\n    VOID\n    );\n\nVOID PhSipUninitializeMemoryDialog(\n    VOID\n    );\n\nVOID PhSipTickMemoryDialog(\n    VOID\n    );\n\nINT_PTR CALLBACK PhSipMemoryDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhSipMemoryPanelDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhSipCreateMemoryGraphs(\n    VOID\n    );\n\nVOID PhSipLayoutMemoryGraphs(\n    _In_ HWND hwnd\n    );\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipNotifyCommitGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipNotifyPhysicalGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\nVOID PhSipUpdateMemoryGraphs(\n    VOID\n    );\n\nVOID PhSipUpdateMemoryPanel(\n    VOID\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI PhSipLoadMmAddresses(\n    _In_ PVOID Parameter\n    );\n\nVOID PhSipGetPoolLimits(\n    _Out_ PSIZE_T Paged,\n    _Out_ PSIZE_T NonPaged\n    );\n\n_Success_(return)\nBOOLEAN PhSipGetMemoryCompressionLimits(\n    _Out_ FLOAT *CurrentCompressedMemory,\n    _Out_ FLOAT *TotalCompressedMemory,\n    _Out_ FLOAT *TotalSavedMemory\n    );\n\n// I/O section\n\n_Function_class_(PH_SYSINFO_SECTION_CALLBACK)\nBOOLEAN NTAPI PhSipIoSectionCallback(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ PH_SYSINFO_SECTION_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    );\n\nVOID PhSipInitializeIoDialog(\n    VOID\n    );\n\nVOID PhSipUninitializeIoDialog(\n    VOID\n    );\n\nVOID PhSipTickIoDialog(\n    VOID\n    );\n\nINT_PTR CALLBACK PhSipIoDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhSipIoPanelDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhSipCreateIoGraph(\n    VOID\n    );\n\nVOID PhSipLayoutIoGraphs(\n    _In_ HWND WindowHandle\n    );\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipNotifyIoReadGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipNotifyIoWriteGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipNotifyIoOtherGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\nVOID PhSipUpdateIoGraph(\n    VOID\n    );\n\nVOID PhSipUpdateIoPanel(\n    VOID\n    );\n\nPPH_PROCESS_RECORD PhSipReferenceMaxIoRecord(\n    _In_ LONG Index\n    );\n\nPPH_STRING PhSipGetMaxIoString(\n    _In_ LONG Index\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/thrdlist.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_THRDLIST_H\n#define PH_THRDLIST_H\n\n// Columns\n\ntypedef enum _PH_THREAD_TREELIST_COLUMN\n{\n    PH_THREAD_TREELIST_COLUMN_TID,\n    PH_THREAD_TREELIST_COLUMN_CPU,\n    PH_THREAD_TREELIST_COLUMN_CYCLESDELTA,\n    PH_THREAD_TREELIST_COLUMN_STARTADDRESSWIN32,\n    PH_THREAD_TREELIST_COLUMN_PRIORITYSYMBOLIC,\n    PH_THREAD_TREELIST_COLUMN_SERVICE,\n    PH_THREAD_TREELIST_COLUMN_NAME,\n    PH_THREAD_TREELIST_COLUMN_STARTED,\n    PH_THREAD_TREELIST_COLUMN_STARTMODULE,\n    PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHES,\n    PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHESDELTA,\n    PH_THREAD_TREELIST_COLUMN_PRIORITY,\n    PH_THREAD_TREELIST_COLUMN_BASEPRIORITY,\n    PH_THREAD_TREELIST_COLUMN_PAGEPRIORITY,\n    PH_THREAD_TREELIST_COLUMN_IOPRIORITY,\n    PH_THREAD_TREELIST_COLUMN_CYCLES,\n    PH_THREAD_TREELIST_COLUMN_STATE,\n    PH_THREAD_TREELIST_COLUMN_KERNELTIME,\n    PH_THREAD_TREELIST_COLUMN_USERTIME,\n    PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR,\n    PH_THREAD_TREELIST_COLUMN_CRITICAL,\n    PH_THREAD_TREELIST_COLUMN_TIDHEX,\n    PH_THREAD_TREELIST_COLUMN_CPUCORECYCLES,\n    PH_THREAD_TREELIST_COLUMN_TOKEN_STATE,\n    PH_THREAD_TREELIST_COLUMN_PENDINGIRP,\n    PH_THREAD_TREELIST_COLUMN_LASTSYSTEMCALL,\n    PH_THREAD_TREELIST_COLUMN_LASTSTATUSCODE,\n    PH_THREAD_TREELIST_COLUMN_TIMELINE,\n    PH_THREAD_TREELIST_COLUMN_APARTMENTTYPE,\n    PH_THREAD_TREELIST_COLUMN_APARTMENTFLAGS,\n    PH_THREAD_TREELIST_COLUMN_FIBER,\n    PH_THREAD_TREELIST_COLUMN_PRIORITYBOOST,\n    PH_THREAD_TREELIST_COLUMN_CPUUSER,\n    PH_THREAD_TREELIST_COLUMN_CPUKERNEL,\n    //PH_THREAD_TREELIST_COLUMN_CPUHISTORY,\n    PH_THREAD_TREELIST_COLUMN_STACKUSAGE,\n    PH_THREAD_TREELIST_COLUMN_WAITTIME,\n    PH_THREAD_TREELIST_COLUMN_IOREADS,\n    PH_THREAD_TREELIST_COLUMN_IOWRITES,\n    PH_THREAD_TREELIST_COLUMN_IOOTHER,\n    PH_THREAD_TREELIST_COLUMN_IOREADBYTES,\n    PH_THREAD_TREELIST_COLUMN_IOWRITEBYTES,\n    PH_THREAD_TREELIST_COLUMN_IOOTHERBYTES,\n    PH_THREAD_TREELIST_COLUMN_LXSSTID,\n    PH_THREAD_TREELIST_COLUMN_POWERTHROTTLING,\n    PH_THREAD_TREELIST_COLUMN_STARTADDRESS,\n    PH_THREAD_TREELIST_COLUMN_KSTACKUSAGE,\n    PH_THREAD_TREELIST_COLUMN_RPC,\n    PH_THREAD_TREELIST_COLUMN_ACTUALBASEPRIORITY,\n    PH_THREAD_TREELIST_COLUMN_MAXIMUM,\n} PH_THREAD_TREELIST_COLUMN;\n\ntypedef enum _PH_THREAD_TREELIST_MENUITEM\n{\n    PH_THREAD_TREELIST_MENUITEM_HIDE_SUSPENDED = 1,\n    PH_THREAD_TREELIST_MENUITEM_HIDE_GUITHREADS,\n    PH_THREAD_TREELIST_MENUITEM_HIDE_UNKNOWNSTARTADDRESS,\n    PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_SUSPENDED,\n    PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_GUITHREADS,\n    PH_THREAD_TREELIST_MENUITEM_SAVE, // Always last (dmex)\n    PH_THREAD_TREELIST_MENUITEM_MAXIMUM\n} PH_THREAD_TREELIST_MENUITEM;\n\ntypedef enum _PH_THREAD_TOKEN_STATE\n{\n    PH_THREAD_TOKEN_STATE_UNKNOWN,\n    PH_THREAD_TOKEN_STATE_NOT_PRESENT,\n    PH_THREAD_TOKEN_STATE_ANONYMOUS,\n    PH_THREAD_TOKEN_STATE_PRESENT\n} PH_THREAD_TOKEN_STATE;\n\n// begin_phapppub\ntypedef struct _PH_THREAD_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PH_SH_STATE ShState;\n\n    HANDLE ThreadId;\n    PPH_THREAD_ITEM ThreadItem;\n// end_phapppub\n\n    PH_STRINGREF TextCache[PH_THREAD_TREELIST_COLUMN_MAXIMUM];\n\n    ULONG ValidMask;\n\n    HANDLE ThreadContextHandle;\n    HANDLE ThreadReadVmHandle;\n    BOOLEAN ThreadContextHandleValid;\n    BOOLEAN ThreadReadVmHandleValid;\n    LONG IdealProcessorMask;\n\n    ULONG PagePriority;\n    IO_PRIORITY_HINT IoPriority;\n    BOOLEAN BreakOnTermination;\n    BOOLEAN PendingIrp;\n    BOOLEAN Fiber;\n    BOOLEAN PriorityBoost;\n    ULONG SuspendCount;\n    FLOAT StackUsageFloat;\n    ULONG_PTR StackUsage;\n    ULONG_PTR StackLimit;\n    FLOAT KernelStackUsageFloat;\n    ULONG_PTR KernelStackUsage;\n    ULONG_PTR KernelStackLimit;\n    PH_THREAD_TOKEN_STATE TokenState;\n    NTSTATUS LastSystemCallStatus;\n    THREAD_LAST_SYSCALL_INFORMATION LastSystemCall;\n    NTSTATUS LastStatusValue;\n    NTSTATUS LastStatusQueryStatus;\n    PH_APARTMENT_INFO ApartmentInfo;\n    BOOLEAN HasRpcState;\n\n    WCHAR CpuUsageText[PH_INT32_STR_LEN_1];\n    WCHAR CpuUserUsageText[PH_INT32_STR_LEN_1];\n    WCHAR CpuKernelUsageText[PH_INT32_STR_LEN_1];\n    PPH_STRING CyclesDeltaText; // used for Context Switches Delta as well\n    PPH_STRING ContextSwitchesDeltaText;\n    PPH_STRING StartAddressText;\n    PPH_STRING CreatedText;\n    PPH_STRING NameText;\n    PPH_STRING StateText;\n    PPH_STRING LastSystemCallText;\n    PPH_STRING LastErrorCodeText;\n    PPH_STRING ApartmentTypeText;\n    PPH_STRING ApartmentFlagsText;\n    PPH_STRING StackUsageText;\n    PPH_STRING KernelStackUsageText;\n    WCHAR ContextSwitchesText[PH_INT64_STR_LEN_1];\n    WCHAR PriorityText[PH_INT32_STR_LEN_1];\n    WCHAR BasePriorityText[PH_INT32_STR_LEN_1];\n    WCHAR ActualBasePriorityText[PH_INT32_STR_LEN_1];\n    WCHAR CyclesText[PH_INT64_STR_LEN_1];\n    PPH_STRING KernelTimeText;\n    PPH_STRING UserTimeText;\n    WCHAR IdealProcessorText[PH_INT32_STR_LEN + 1 + PH_INT32_STR_LEN + 1];\n    WCHAR ThreadIdHexText[PH_INT32_STR_LEN_1];\n    WCHAR CpuCoreUsageText[PH_INT32_STR_LEN_1];\n    PPH_STRING WaitTimeText;\n    PPH_STRING IoReads;\n    PPH_STRING IoWrites;\n    PPH_STRING IoOther;\n    PPH_STRING IoReadBytes;\n    PPH_STRING IoWriteBytes;\n    PPH_STRING IoOtherBytes;\n// begin_phapppub\n} PH_THREAD_NODE, *PPH_THREAD_NODE;\n// end_phapppub\n\ntypedef struct _PH_THREAD_LIST_CONTEXT\n{\n    HWND ParentWindowHandle;\n    HWND TreeNewHandle;\n    ULONG TreeNewSortColumn;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PH_CM_MANAGER Cm;\n\n    PPH_HASHTABLE NodeHashtable;\n    PPH_LIST NodeList;\n    PPH_POINTER_LIST NodeStateList;\n    PH_TN_FILTER_SUPPORT TreeFilterSupport;\n\n    HANDLE ProcessId;\n    LARGE_INTEGER ProcessCreateTime;\n\n    BOOLEAN EnableStateHighlighting;\n    BOOLEAN UseCycleTime;\n    BOOLEAN HasServices;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Reserved : 3;\n\n            ULONG HideSuspended : 1;\n            ULONG HideGuiThreads : 1;\n            ULONG HighlightSuspended : 1;\n            ULONG HighlightGuiThreads : 1;\n\n            ULONG Spare : 25;\n        };\n    };\n} PH_THREAD_LIST_CONTEXT, *PPH_THREAD_LIST_CONTEXT;\n\nVOID PhInitializeThreadList(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND TreeNewHandle,\n    _Out_ PPH_THREAD_LIST_CONTEXT Context\n    );\n\nVOID PhDeleteThreadList(\n    _In_ PPH_THREAD_LIST_CONTEXT Context\n    );\n\nVOID PhLoadSettingsThreadList(\n    _Inout_ PPH_THREAD_LIST_CONTEXT Context\n    );\n\nVOID PhSaveSettingsThreadList(\n    _Inout_ PPH_THREAD_LIST_CONTEXT Context\n    );\n\nVOID PhSetOptionsThreadList(\n    _Inout_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ ULONG Options\n    );\n\nPPH_THREAD_NODE PhAddThreadNode(\n    _Inout_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_ITEM ThreadItem,\n    _In_ BOOLEAN FirstRun\n    );\n\nPPH_THREAD_NODE PhFindThreadNode(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ HANDLE ThreadId\n    );\n\nVOID PhRemoveThreadNode(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    );\n\nVOID PhUpdateThreadNode(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    );\n\nVOID PhTickThreadNodes(\n    _In_ PPH_THREAD_LIST_CONTEXT Context\n    );\n\nPPH_THREAD_ITEM PhGetSelectedThreadItem(\n    _In_ PPH_THREAD_LIST_CONTEXT Context\n    );\n\nVOID PhGetSelectedThreadItems(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _Out_ PPH_THREAD_ITEM **Threads,\n    _Out_ PULONG NumberOfThreads\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/include/thrdprv.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef PH_THRDPRV_H\n#define PH_THRDPRV_H\n\nextern PPH_OBJECT_TYPE PhThreadProviderType;\nextern PPH_OBJECT_TYPE PhThreadItemType;\n\n// begin_phapppub\ntypedef struct _PH_THREAD_ITEM\n{\n    union\n    {\n        CLIENT_ID ClientId;\n        struct\n        {\n            HANDLE ProcessId;\n            HANDLE ThreadId;\n        };\n    };\n\n    LARGE_INTEGER CreateTime;\n    LARGE_INTEGER KernelTime;\n    LARGE_INTEGER UserTime;\n    PH_UINT64_DELTA CpuKernelDelta;\n    PH_UINT64_DELTA CpuUserDelta;\n    PH_UINT32_DELTA ContextSwitchesDelta;\n    PH_UINT64_DELTA CyclesDelta;\n\n    FLOAT CpuUsage;\n    FLOAT CpuKernelUsage;\n    FLOAT CpuUserUsage;\n\n    KPRIORITY Priority;\n    KPRIORITY BasePriority;\n    KPRIORITY ActualBasePriority; // KeSetActualBasePriorityThread (jxy-s)\n    union\n    {\n        KAFFINITY AffinityMaskSingle; // Single processor group\n        PKAFFINITY AffinityMaskGroups; // Multiple processor groups * PhSystemProcessorInformation.NumberOfProcessorGroups\n    };\n    ULONG AffinityPopulationCount;\n    ULONG WaitTime;\n    KTHREAD_STATE State;\n    KWAIT_REASON WaitReason;\n\n    HANDLE ThreadHandle;\n\n    PPH_STRING ServiceName;\n\n    PVOID StartAddressWin32;\n    PVOID StartAddress;\n\n    NTSTATUS ThreadHandleStatus;\n    NTSTATUS StartAddressStatus;\n\n    PPH_STRING StartAddressWin32String;\n    PPH_STRING StartAddressWin32FileName;\n    enum _PH_SYMBOL_RESOLVE_LEVEL StartAddressWin32ResolveLevel;\n\n    PPH_STRING StartAddressString;\n    PPH_STRING StartAddressFileName;\n    enum _PH_SYMBOL_RESOLVE_LEVEL StartAddressResolveLevel;\n\n    BOOLEAN IsGuiThread;\n    BOOLEAN JustResolved;\n    WCHAR ThreadIdString[PH_INT32_STR_LEN_1];\n    WCHAR ThreadIdHexString[PH_PTR_STR_LEN_1];\n    WCHAR LxssThreadIdString[PH_INT32_STR_LEN_1];\n\n    IO_COUNTERS IoCounters;\n\n    ULONG LxssThreadId;\n    BOOLEAN PowerThrottling;\n} PH_THREAD_ITEM, *PPH_THREAD_ITEM;\n\ntypedef enum _PH_KNOWN_PROCESS_TYPE PH_KNOWN_PROCESS_TYPE;\n\ntypedef struct _PH_THREAD_PROVIDER\n{\n    PPH_HASHTABLE ThreadHashtable;\n    PH_FAST_LOCK ThreadHashtableLock;\n    PH_CALLBACK ThreadAddedEvent;\n    PH_CALLBACK ThreadModifiedEvent;\n    PH_CALLBACK ThreadRemovedEvent;\n    PH_CALLBACK UpdatedEvent;\n    PH_CALLBACK LoadingStateChangedEvent;\n\n    HANDLE ProcessId;\n    HANDLE ProcessHandle;\n\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN HasServices : 1;\n            BOOLEAN HasServicesKnown : 1;\n            BOOLEAN Terminating : 1;\n            BOOLEAN Spare : 5;\n        };\n    };\n\n    struct _PH_SYMBOL_PROVIDER *SymbolProvider;\n\n    SLIST_HEADER QueryListHead;\n    PH_QUEUED_LOCK LoadSymbolsLock;\n    LONG SymbolsLoading;\n    ULONG64 RunId;\n    ULONG64 SymbolsLoadedRunId;\n} PH_THREAD_PROVIDER, *PPH_THREAD_PROVIDER;\n// end_phapppub\n\nPPH_THREAD_PROVIDER PhCreateThreadProvider(\n    _In_ HANDLE ProcessId\n    );\n\nVOID PhRegisterThreadProvider(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _Out_ PPH_CALLBACK_REGISTRATION CallbackRegistration\n    );\n\nVOID PhUnregisterThreadProvider(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _In_ PPH_CALLBACK_REGISTRATION CallbackRegistration\n    );\n\nVOID PhSetTerminatingThreadProvider(\n    _Inout_ PPH_THREAD_PROVIDER ThreadProvider\n    );\n\nVOID PhLoadSymbolsThreadProvider(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider\n    );\n\nPPH_THREAD_ITEM PhCreateThreadItem(\n    _In_ CLIENT_ID ClientId\n    );\n\nPPH_THREAD_ITEM PhReferenceThreadItem(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _In_ HANDLE ThreadId\n    );\n\nVOID PhDereferenceAllThreadItems(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider\n    );\n\nPCPH_STRINGREF PhGetBasePrioritySymbolicString(\n    _In_ KPRIORITY BasePriority\n    );\n\nVOID PhThreadProviderInitialUpdate(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider\n    );\n\n#endif\n"
  },
  {
    "path": "SystemInformer/infodlg.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2016-2023\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <settings.h>\n\ntypedef struct _PH_INFORMATION_CONTEXT\n{\n    PCWSTR String;\n    ULONG Flags;\n    PH_LAYOUT_MANAGER LayoutManager;\n    RECT MinimumSize;\n} PH_INFORMATION_CONTEXT, *PPH_INFORMATION_CONTEXT;\n\nstatic INT_PTR CALLBACK PhpInformationDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_INFORMATION_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_INFORMATION_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_INFORMATION_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(NULL, SETTING_INFORMATION_WINDOW_SIZE, hwndDlg);\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            context->MinimumSize = (RECT){ -1, -1, -1, -1 };\n\n            if (context->MinimumSize.left == -1)\n            {\n                RECT rect;\n\n                rect.left = 0;\n                rect.top = 0;\n                rect.right = 200;\n                rect.bottom = 140;\n                MapDialogRect(hwndDlg, &rect);\n                context->MinimumSize = rect;\n                context->MinimumSize.left = 0;\n            }\n\n            PhSetDialogItemText(hwndDlg, IDC_TEXT, context->String);\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveWindowPlacementToSetting(SETTING_INFORMATION_WINDOW_POSITION, SETTING_INFORMATION_WINDOW_SIZE, hwndDlg);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                EndDialog(hwndDlg, IDOK);\n                break;\n            case IDC_COPY:\n                {\n                    HWND editControl;\n                    LONG selStart;\n                    LONG selEnd;\n                    PH_STRINGREF string;\n\n                    editControl = GetDlgItem(hwndDlg, IDC_TEXT);\n                    SendMessage(editControl, EM_GETSEL, (WPARAM)&selStart, (LPARAM)&selEnd);\n\n                    if (selStart == selEnd)\n                    {\n                        // Select and copy the entire string.\n                        PhInitializeStringRefLongHint(&string, context->String);\n                        Edit_SetSel(editControl, 0, -1);\n                    }\n                    else\n                    {\n                        string.Buffer = PTR_ADD_OFFSET(context->String, selStart);\n                        string.Length = (selEnd - selStart) * sizeof(WCHAR);\n                    }\n\n                    PhSetClipboardString(hwndDlg, &string);\n\n                    PhSetDialogFocus(hwndDlg, editControl);\n                }\n                break;\n            case IDC_SAVE:\n                {\n                    static PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Text files (*.txt)\", L\"*.txt\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog;\n\n                    fileDialog = PhCreateSaveFileDialog();\n                    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n                    PhSetFileDialogFileName(fileDialog, L\"Information.txt\");\n\n                    if (PhShowFileDialog(hwndDlg, fileDialog))\n                    {\n                        NTSTATUS status;\n                        PPH_STRING fileName;\n                        PPH_FILE_STREAM fileStream;\n\n                        fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n\n                        if (NT_SUCCESS(status = PhCreateFileStream(\n                            &fileStream,\n                            fileName->Buffer,\n                            FILE_GENERIC_WRITE,\n                            FILE_SHARE_READ,\n                            FILE_OVERWRITE_IF,\n                            0\n                            )))\n                        {\n                            PH_STRINGREF string;\n\n                            PhWriteStringAsUtf8FileStream(fileStream, (PPH_STRINGREF)&PhUnicodeByteOrderMark);\n                            PhInitializeStringRefLongHint(&string, context->String);\n                            PhWriteStringAsUtf8FileStream(fileStream, &string);\n                            PhDereferenceObject(fileStream);\n                        }\n\n                        if (!NT_SUCCESS(status))\n                            PhShowStatus(hwndDlg, L\"Unable to create the file\", status, 0);\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhShowInformationDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR String,\n    _Reserved_ ULONG Flags\n    )\n{\n    PH_INFORMATION_CONTEXT context;\n\n    memset(&context, 0, sizeof(PH_INFORMATION_CONTEXT));\n    context.String = String;\n    context.Flags = Flags;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_INFORMATION),\n        ParentWindowHandle,\n        PhpInformationDlgProc,\n        &context\n        );\n}\n"
  },
  {
    "path": "SystemInformer/informer.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2024-2025\n *\n */\n#include <phapp.h>\n#include <phsettings.h>\n#include <phplug.h>\n#include <procprv.h>\n#include <kphuser.h>\n#include <kphcomms.h>\n#include <mapldr.h>\n\n#include <winsqlite/winsqlite3.h>\n\n#include <informer.h>\n\ntypedef struct _PH_INFORMER_DB_REAP\n{\n    ULONG64 ProcessStartKey;\n    ULONG64 MaxCount;\n    ULONG Seconds;\n} PH_INFORMER_DB_REAP, *PPH_INFORMER_DB_REAP;\n\ntypedef int SQLITE_APICALL sqlite3_open_v2_fn(\n  const char *filename,   /* Database filename (UTF-8) */\n  sqlite3 **ppDb,         /* OUT: SQLite db handle */\n  int flags,              /* Flags */\n  const char *zVfs        /* Name of VFS module to use */\n);\ntypedef int SQLITE_APICALL sqlite3_exec_fn(\n  sqlite3*,                                  /* An open database */\n  const char *sql,                           /* SQL to be evaluated */\n  int (SQLITE_CALLBACK *callback)(void*,int,char**,char**),  /* Callback function */\n  void *,                                    /* 1st argument to callback */\n  char **errmsg                              /* Error msg written here */\n);\ntypedef int SQLITE_APICALL sqlite3_create_function_v2_fn(\n  sqlite3 *db,\n  const char *zFunctionName,\n  int nArg,\n  int eTextRep,\n  void *pApp,\n  void (SQLITE_CALLBACK *xFunc)(sqlite3_context*,int,sqlite3_value**),\n  void (SQLITE_CALLBACK *xStep)(sqlite3_context*,int,sqlite3_value**),\n  void (SQLITE_CALLBACK *xFinal)(sqlite3_context*),\n  void(SQLITE_CALLBACK *xDestroy)(void*)\n);\ntypedef int SQLITE_APICALL sqlite3_prepare_v2_fn(\n  sqlite3 *db,            /* Database handle */\n  const char *zSql,       /* SQL statement, UTF-8 encoded */\n  int nByte,              /* Maximum length of zSql in bytes. */\n  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */\n  const char **pzTail     /* OUT: Pointer to unused portion of zSql */\n);\ntypedef int SQLITE_APICALL sqlite3_bind_int64_fn(sqlite3_stmt*, int, sqlite3_int64);\ntypedef int SQLITE_APICALL sqlite3_step_fn(sqlite3_stmt*);\ntypedef int SQLITE_APICALL sqlite3_reset_fn(sqlite3_stmt *pStmt);\ntypedef sqlite3_int64 SQLITE_APICALL sqlite3_value_int64_fn(sqlite3_value*);\ntypedef sqlite3_int64 SQLITE_APICALL sqlite3_column_int64_fn(sqlite3_stmt*, int iCol);\n\nstatic PH_CALLBACK_REGISTRATION PhpInformerProcessesUpdatedRegistration;\nstatic PH_CALLBACK_REGISTRATION PhpInformerProcessesRemovedRegistration;\n\nstatic PH_FREE_LIST PhpInformerReapFreeList;\nstatic PH_QUEUED_LOCK PhpInformerDatabaseLock = PH_QUEUED_LOCK_INIT;\nstatic sqlite3* PhpInformerDB = NULL;\nstatic sqlite3_stmt* PhpInformerDBInsert = NULL;\nstatic sqlite3_stmt* PhpInformerDBQueryCount = NULL;\nstatic sqlite3_stmt* PhpInformerDBReapMax = NULL;\nstatic sqlite3_stmt* PhpInformerDBReapTime = NULL;\nstatic sqlite3_stmt* PhpInformerDBReapProc = NULL;\nstatic sqlite3_stmt* PhpInformerDBQuery = NULL;\nstatic sqlite3_stmt* PhpInformerDBQueryProc = NULL;\n\nstatic sqlite3_open_v2_fn* sqlite3_open_v2_I = NULL;\nstatic sqlite3_exec_fn* sqlite3_exec_I = NULL;\nstatic sqlite3_create_function_v2_fn* sqlite3_create_function_v2_I = NULL;\nstatic sqlite3_prepare_v2_fn* sqlite3_prepare_v2_I = NULL;\nstatic sqlite3_bind_int64_fn* sqlite3_bind_int64_I = NULL;\nstatic sqlite3_step_fn* sqlite3_step_I = NULL;\nstatic sqlite3_reset_fn* sqlite3_reset_I = NULL;\nstatic sqlite3_value_int64_fn* sqlite3_value_int64_I = NULL;\nstatic sqlite3_column_int64_fn* sqlite3_column_int64_I = NULL;\n\nPH_CALLBACK_DECLARE(PhInformerCallback);\n\nVOID PhpInformerGetKeys(\n    _In_ PKPH_MESSAGE Message,\n    _Out_ PULONG64 ActorKey,\n    _Out_ PULONG64 TargetKey\n    )\n{\n    *ActorKey = ULONG64_MAX;\n    *TargetKey = ULONG64_MAX;\n\n    switch (Message->Header.MessageId)\n    {\n    case KphMsgProcessCreate:\n        *ActorKey = Message->Kernel.ProcessCreate.CreatingProcessStartKey;\n        *TargetKey = Message->Kernel.ProcessCreate.TargetProcessStartKey;\n        return;\n    case KphMsgProcessExit:\n        *ActorKey = Message->Kernel.ProcessExit.ProcessStartKey;\n        return;\n    case KphMsgThreadCreate:\n        *ActorKey = Message->Kernel.ThreadCreate.CreatingProcessStartKey;\n        *TargetKey = Message->Kernel.ThreadCreate.TargetProcessStartKey;\n        return;\n    case KphMsgThreadExecute:\n        *ActorKey = Message->Kernel.ThreadExecute.ProcessStartKey;\n        return;\n    case KphMsgThreadExit:\n        *ActorKey = Message->Kernel.ThreadExit.ProcessStartKey;\n        return;\n    case KphMsgImageLoad:\n        *ActorKey = Message->Kernel.ImageLoad.LoadingProcessStartKey;\n        *TargetKey = Message->Kernel.ImageLoad.TargetProcessStartKey;\n        return;\n    case KphMsgImageVerify:\n        *ActorKey = Message->Kernel.ImageVerify.ProcessStartKey;\n        return;\n    case KphMsgDebugPrint:\n        return;\n    default:\n        break;\n    }\n\n    if (Message->Header.MessageId >= KphMsgHandlePreCreateProcess &&\n        Message->Header.MessageId <= KphMsgHandlePostDuplicateDesktop)\n    {\n        *ActorKey = Message->Kernel.Handle.ContextProcessStartKey;\n        return;\n    }\n\n    if (Message->Header.MessageId >= KphMsgFilePreCreate &&\n        Message->Header.MessageId <= KphMsgFilePostVolumeDismount)\n    {\n        *ActorKey = Message->Kernel.File.ProcessStartKey;\n        return;\n    }\n\n    if (Message->Header.MessageId >= KphMsgRegPreDeleteKey &&\n        Message->Header.MessageId <= KphMsgRegPostSaveMergedKey)\n    {\n        *ActorKey = Message->Kernel.Reg.ProcessStartKey;\n        return;\n    }\n}\n\nULONG64 PhpInformerDatabaseQueryCountUnsafe(\n    VOID\n    )\n{\n    ULONG64 count = 0;\n\n    if (sqlite3_step_I(PhpInformerDBQueryCount) == SQLITE_ROW)\n        count = sqlite3_column_int64_I(PhpInformerDBQueryCount, 0);\n\n    sqlite3_reset_I(PhpInformerDBQueryCount);\n\n    return count;\n}\n\nVOID PhpInformerDatabaseInsert(\n    _In_ PKPH_MESSAGE Message\n    )\n{\n    if (PhpInformerDBInsert)\n    {\n        ULONG64 actorKey;\n        ULONG64 targetKey;\n\n        PhpInformerGetKeys(Message, &actorKey, &targetKey);\n\n        PhAcquireQueuedLockExclusive(&PhpInformerDatabaseLock);\n\n        sqlite3_bind_int64_I(PhpInformerDBInsert, 1, Message->Header.TimeStamp.QuadPart);\n        sqlite3_bind_int64_I(PhpInformerDBInsert, 2, actorKey);\n        sqlite3_bind_int64_I(PhpInformerDBInsert, 3, targetKey);\n        sqlite3_bind_int64_I(PhpInformerDBInsert, 4, (LONG64)(LONG_PTR)Message);\n        sqlite3_step_I(PhpInformerDBInsert);\n        sqlite3_reset_I(PhpInformerDBInsert);\n\n        PhReleaseQueuedLockExclusive(&PhpInformerDatabaseLock);\n    }\n}\n\nVOID PhpInformerDatabaseReap(\n    _In_ PPH_INFORMER_DB_REAP Reap\n    )\n{\n    LARGE_INTEGER systemTime;\n\n    PhAcquireQueuedLockExclusive(&PhpInformerDatabaseLock);\n\n    if (PhpInformerDBReapProc && Reap->ProcessStartKey)\n    {\n        sqlite3_bind_int64_I(PhpInformerDBReapProc, 1, Reap->ProcessStartKey);\n        sqlite3_step_I(PhpInformerDBReapProc);\n        sqlite3_reset_I(PhpInformerDBReapProc);\n    }\n\n    if (PhpInformerDBReapTime && Reap->Seconds)\n    {\n        KphMsgQuerySystemTime(&systemTime);\n        systemTime.QuadPart -= (LONG64)Reap->Seconds * 10000000;\n\n        sqlite3_bind_int64_I(PhpInformerDBReapTime, 1, systemTime.QuadPart);\n        sqlite3_step_I(PhpInformerDBReapTime);\n        sqlite3_reset_I(PhpInformerDBReapTime);\n    }\n\n    if (PhpInformerDBReapMax && Reap->MaxCount)\n    {\n        if (PhpInformerDatabaseQueryCountUnsafe() > Reap->MaxCount)\n        {\n            sqlite3_bind_int64_I(PhpInformerDBReapMax, 1, Reap->MaxCount);\n            sqlite3_step_I(PhpInformerDBReapMax);\n            sqlite3_reset_I(PhpInformerDBReapMax);\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&PhpInformerDatabaseLock);\n}\n\nPPH_LIST PhInformerDatabaseQuery(\n    _In_ ULONG64 ProcessStartKey,\n    _In_opt_ PLARGE_INTEGER TimeStamp\n    )\n{\n    LARGE_INTEGER timeStamp;\n    PPH_LIST messages;\n\n    messages = PhCreateList(10);\n\n    if (PhpInformerDBQuery && PhpInformerDBQueryProc)\n    {\n        if (TimeStamp)\n        {\n            timeStamp.QuadPart = TimeStamp->QuadPart;\n        }\n        else\n        {\n            timeStamp.QuadPart = 0;\n        }\n\n        PhAcquireQueuedLockExclusive(&PhpInformerDatabaseLock);\n\n        if (ProcessStartKey)\n        {\n            sqlite3_bind_int64_I(PhpInformerDBQueryProc, 1, ProcessStartKey);\n            sqlite3_bind_int64_I(PhpInformerDBQueryProc, 2, ProcessStartKey);\n            sqlite3_bind_int64_I(PhpInformerDBQueryProc, 3, timeStamp.QuadPart);\n\n            while (sqlite3_step_I(PhpInformerDBQueryProc) == SQLITE_ROW)\n            {\n                PKPH_MESSAGE message;\n\n                message = (PVOID)(LONG_PTR)sqlite3_column_int64_I(PhpInformerDBQueryProc, 0);\n\n                PhAddItemList(messages, PhReferenceObject(message));\n            }\n\n            sqlite3_reset_I(PhpInformerDBQueryProc);\n        }\n        else\n        {\n            sqlite3_bind_int64_I(PhpInformerDBQuery, 1, timeStamp.QuadPart);\n\n            while (sqlite3_step_I(PhpInformerDBQuery) == SQLITE_ROW)\n            {\n                PKPH_MESSAGE message;\n\n                message = (PVOID)(LONG_PTR)sqlite3_column_int64_I(PhpInformerDBQuery, 0);\n\n                PhAddItemList(messages, PhReferenceObject(message));\n            }\n\n            sqlite3_reset_I(PhpInformerDBQuery);\n        }\n\n        PhReleaseQueuedLockExclusive(&PhpInformerDatabaseLock);\n    }\n\n    return messages;\n}\n\nVOID PhpInformerDatabaseReferenceMessage(\n    sqlite3_context* Context,\n    INT Argc,\n    sqlite3_value** Argv\n    )\n{\n    PKPH_MESSAGE message;\n\n    message = (PVOID)(LONG_PTR)sqlite3_value_int64_I(Argv[0]);\n\n    PhReferenceObject(message);\n}\n\nVOID PhpInformerDatabaseDereferenceMessage(\n    sqlite3_context* Context,\n    INT Argc,\n    sqlite3_value** Argv\n    )\n{\n    PKPH_MESSAGE message;\n\n    message = (PVOID)(LONG_PTR)sqlite3_value_int64_I(Argv[0]);\n\n    PhDereferenceObject(message);\n}\n\nBOOLEAN PhpInfomerLoadSQLite(\n    VOID\n    )\n{\n    PVOID baseAddress;\n\n    if (baseAddress = PhLoadLibrary(L\"winsqlite3.dll\"))\n    {\n        sqlite3_open_v2_I = PhGetDllBaseProcedureAddress(baseAddress, \"sqlite3_open_v2\", 0);\n        sqlite3_exec_I = PhGetDllBaseProcedureAddress(baseAddress, \"sqlite3_exec\", 0);\n        sqlite3_create_function_v2_I = PhGetDllBaseProcedureAddress(baseAddress, \"sqlite3_create_function_v2\", 0);\n        sqlite3_prepare_v2_I = PhGetDllBaseProcedureAddress(baseAddress, \"sqlite3_prepare_v2\", 0);\n        sqlite3_bind_int64_I = PhGetDllBaseProcedureAddress(baseAddress, \"sqlite3_bind_int64\", 0);\n        sqlite3_step_I = PhGetDllBaseProcedureAddress(baseAddress, \"sqlite3_step\", 0);\n        sqlite3_reset_I = PhGetDllBaseProcedureAddress(baseAddress, \"sqlite3_reset\", 0);\n        sqlite3_value_int64_I = PhGetDllBaseProcedureAddress(baseAddress, \"sqlite3_value_int64\", 0);\n        sqlite3_column_int64_I = PhGetDllBaseProcedureAddress(baseAddress, \"sqlite3_column_int64\", 0);\n    }\n\n    return (\n        sqlite3_open_v2_I &&\n        sqlite3_exec_I &&\n        sqlite3_create_function_v2_I &&\n        sqlite3_prepare_v2_I &&\n        sqlite3_bind_int64_I &&\n        sqlite3_step_I &&\n        sqlite3_reset_I &&\n        sqlite3_value_int64_I &&\n        sqlite3_column_int64_I\n        );\n}\n\nVOID PhpInitializeInformerDatabase(\n    VOID\n    )\n{\n    if (!PhpInfomerLoadSQLite())\n        return;\n\n    if (sqlite3_open_v2_I(\n        \"informer\",\n        &PhpInformerDB,\n        SQLITE_OPEN_MEMORY | SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX,\n        NULL\n        ) == SQLITE_OK)\n    {\n        if (sqlite3_exec_I(\n            PhpInformerDB,\n            \"PRAGMA synchronous = OFF;\"\n            \"PRAGMA journal_mode = OFF;\"\n            \"DROP TABLE IF EXISTS messages;\"\n            \"CREATE TABLE messages(\"\n            \"id INTEGER PRIMARY KEY AUTOINCREMENT,\"\n            \"time_stamp INTEGER NOT NULL,\"\n            \"actor_key INTEGER NOT NULL,\"\n            \"target_key INTEGER NOT NULL,\"\n            \"message INTEGER NOT NULL\"\n            \");\",\n            NULL,\n            NULL,\n            NULL\n            ) == SQLITE_OK)\n        {\n            sqlite3_create_function_v2_I(\n                PhpInformerDB,\n                \"reference_message\",\n                1,\n                SQLITE_UTF8,\n                NULL,\n                PhpInformerDatabaseReferenceMessage,\n                NULL,\n                NULL,\n                NULL\n                );\n\n            sqlite3_create_function_v2_I(\n                PhpInformerDB,\n                \"dereference_message\",\n                1,\n                SQLITE_UTF8,\n                NULL,\n                PhpInformerDatabaseDereferenceMessage,\n                NULL,\n                NULL,\n                NULL\n                );\n\n            sqlite3_exec_I(\n                PhpInformerDB,\n                \"CREATE TRIGGER before_insert_messages \"\n                \"BEFORE INSERT ON messages \"\n                \"FOR EACH ROW \"\n                \"BEGIN \"\n                \"    SELECT reference_message(NEW.message); \"\n                \"END;\",\n                NULL,\n                NULL,\n                NULL\n                );\n\n            sqlite3_exec_I(\n                PhpInformerDB,\n                \"CREATE TRIGGER after_delete_messages \"\n                \"AFTER DELETE ON messages \"\n                \"FOR EACH ROW \"\n                \"BEGIN \"\n                \"    SELECT dereference_message(OLD.message); \"\n                \"END;\",\n                NULL,\n                NULL,\n                NULL\n                );\n\n            sqlite3_prepare_v2_I(\n                PhpInformerDB,\n                \"INSERT INTO messages(time_stamp, actor_key, target_key, message)\"\n                \"VALUES(?, ?, ?, ?);\",\n                -1,\n                &PhpInformerDBInsert,\n                NULL\n                );\n\n            sqlite3_prepare_v2_I(\n                PhpInformerDB,\n                \"SELECT COUNT(*) FROM messages;\",\n                -1,\n                &PhpInformerDBQueryCount,\n                NULL\n                );\n\n            sqlite3_prepare_v2_I(\n                PhpInformerDB,\n                \"DELETE FROM messages \"\n                \"WHERE id IN (\"\n                \"    SELECT id FROM messages \"\n                \"    ORDER BY id ASC \"\n                \"    LIMIT (SELECT COUNT(*) - ? FROM messages)\"\n                \");\",\n                -1,\n                &PhpInformerDBReapMax,\n                NULL\n                );\n\n            sqlite3_prepare_v2_I(\n                PhpInformerDB,\n                \"DELETE FROM messages \"\n                \"WHERE time_stamp < ?;\",\n                -1,\n                &PhpInformerDBReapTime,\n                NULL\n                );\n\n            sqlite3_prepare_v2_I(\n                PhpInformerDB,\n                \"DELETE FROM messages \"\n                \"WHERE actor_key = ?;\",\n                -1,\n                &PhpInformerDBReapProc,\n                NULL\n                );\n\n            sqlite3_prepare_v2_I(\n                PhpInformerDB,\n                \"SELECT message FROM messages \"\n                \"WHERE time_stamp >= ? \"\n                \"ORDER BY time_stamp ASC;\",\n                -1,\n                &PhpInformerDBQuery,\n                NULL\n                );\n\n            sqlite3_prepare_v2_I(\n                PhpInformerDB,\n                \"SELECT message FROM messages \"\n                \"WHERE (actor_key = ? OR target_key = ?) AND time_stamp >= ? \"\n                \"ORDER BY time_stamp ASC;\",\n                -1,\n                &PhpInformerDBQueryProc,\n                NULL\n                );\n        }\n    }\n}\n\nNTSTATUS PhInformerReply(\n    _Inout_ PPH_INFORMER_CONTEXT Context,\n    _In_ PKPH_MESSAGE ReplyMessage\n    )\n{\n    NTSTATUS status;\n\n    if (Context->Handled)\n        return STATUS_INVALID_PARAMETER_1;\n\n    if (NT_SUCCESS(status = KphCommsReplyMessage(Context->ReplyToken, ReplyMessage)))\n        Context->Handled = TRUE;\n\n    return status;\n}\n\nBOOLEAN PhInformerDispatch(\n    _In_ ULONG_PTR ReplyToken,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    PKPH_MESSAGE message;\n    PH_INFORMER_CONTEXT context;\n\n    message = KphCreateMessage(Message->Header.Size);\n    memcpy(message, Message, Message->Header.Size);\n\n    context.Message = message;\n    context.ReplyToken = ReplyToken;\n    context.Handled = FALSE;\n\n    PhpInformerDatabaseInsert(message);\n\n    PhInvokeCallback(&PhInformerCallback, &context);\n\n    PhDereferenceObject(message);\n\n    return context.Handled;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI PhpInformerReapWorkItemRoutine(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_INFORMER_DB_REAP reap = Parameter;\n\n    PhpInformerDatabaseReap(reap);\n\n    PhFreeToFreeList(&PhpInformerReapFreeList, reap);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhpInformerProcessUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    ULONG runCount = PtrToUlong(Parameter);\n    PPH_INFORMER_DB_REAP reap;\n\n    reap = PhAllocateFromFreeList(&PhpInformerReapFreeList);\n\n    //\n    // We cache the process monitor data for a lookback period so when a user\n    // desires to inspect real time activity for a process we can provide a\n    // reasonable amount of historical data. Here, reap the information that has\n    // expired from the configured lookback period. We also configure a cache\n    // limit which enforces a maximum on the total number of retained messages.\n    //\n\n    reap->ProcessStartKey = 0;\n    reap->MaxCount = PhProcessMonitorCacheLimit;\n    reap->Seconds = 0;\n\n    if (PhProcessMonitorLookback && runCount % PhProcessMonitorLookback == 0)\n        reap->Seconds = PhProcessMonitorLookback;\n\n    if (!NT_SUCCESS(PhQueueUserWorkItem(PhpInformerReapWorkItemRoutine, reap)))\n        PhFreeToFreeList(&PhpInformerReapFreeList, reap);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhpInformerProcessRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;\n    PPH_INFORMER_DB_REAP reap;\n\n    if (processItem->ProcessStartKey)\n    {\n        //\n        // This is opportunistic since the provider does not track short-lived\n        // processes. There is also no guarantee that more information about\n        // this process will be added to the database later by the asynchronous\n        // nature of processing informer data and the fact that the operating\n        // system generates activity for a process after it has \"exited\". That\n        // said, we know at this point that the user can no longer inspect the\n        // process to view activity associated with it so we might as well ask\n        // the database to reap what it can. Anything missed will be reaped by\n        // the periodic lookback reaper.\n        //\n\n        reap = PhAllocateFromFreeList(&PhpInformerReapFreeList);\n\n        reap->ProcessStartKey = processItem->ProcessStartKey;\n        reap->MaxCount = 0;\n        reap->Seconds = 0;\n\n        if (!NT_SUCCESS(PhQueueUserWorkItem(PhpInformerReapWorkItemRoutine, reap)))\n            PhFreeToFreeList(&PhpInformerReapFreeList, reap);\n    }\n}\n\nVOID PhInformerInitialize(\n    VOID\n    )\n{\n    PhInitializeFreeList(&PhpInformerReapFreeList, sizeof(PH_INFORMER_DB_REAP), 16);\n\n    if (!PhEnableProcessMonitor)\n        return;\n\n    PhpInitializeInformerDatabase();\n\n    PhRegisterCallback(\n        PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n        PhpInformerProcessUpdatedHandler,\n        NULL,\n        &PhpInformerProcessesUpdatedRegistration\n        );\n\n    PhRegisterCallback(\n        PhGetGeneralCallback(GeneralCallbackProcessProviderRemovedEvent),\n        PhpInformerProcessRemovedHandler,\n        NULL,\n        &PhpInformerProcessesRemovedRegistration\n        );\n}\n\nVOID PhInformerActivate(\n    VOID\n    )\n{\n    KPH_INFORMER_SETTINGS settings;\n    KPH_INFORMER_CLIENT_SETTINGS client;\n\n    memset(&settings, 0, sizeof(settings));\n    settings.Policy[KPH_INFORMER_INDEX(RequiredStateFailure)] = (KPH_RATE_LIMIT_POLICY)KPH_RATE_LIMIT_UNLIMITED;\n    KphSetInformerProcessSettings(NtCurrentProcess(), &settings);\n\n    if (!PhEnableProcessMonitor)\n    {\n        KphSetInformerSettings(&settings);\n        return;\n    }\n\n    memset(&settings, 0, sizeof(settings));\n    settings.Options.Flags = ULONG_MAX;\n    settings.Options.EnableStackTraces = FALSE;\n    settings.Options.EnableProcessCreateReply = FALSE;\n    settings.Options.FileEnablePreCreateReply = FALSE;\n    settings.Options.FileEnablePostCreateReply = FALSE;\n    settings.Options.FileEnablePostFileNames = FALSE;\n    settings.Options.FileEnableIoControlBuffers = FALSE;\n    settings.Options.FileEnableFsControlBuffers = FALSE;\n    settings.Options.FileEnableDirControlBuffers = FALSE;\n    settings.Options.RegEnablePostObjectNames = FALSE;\n    settings.Options.RegEnablePostValueNames = FALSE;\n    settings.Options.RegEnableValueBuffers = FALSE;\n\n    for (ULONG i = 0; i < KPH_INFORMER_COUNT; i++)\n        settings.Policy[i] = (KPH_RATE_LIMIT_POLICY)KPH_RATE_LIMIT_UNLIMITED;\n\n    settings.Policy[KPH_INFORMER_INDEX(DebugPrint)] = (KPH_RATE_LIMIT_POLICY)KPH_RATE_LIMIT_DENY_ALL;\n\n    KphSetInformerSettings(&settings);\n\n    memset(&client, 0, sizeof(client));\n    PhTimeoutFromMilliseconds(&client.MessageTimeouts.AsyncTimeout, 3000);\n    PhTimeoutFromMilliseconds(&client.MessageTimeouts.DefaultTimeout, 3000);\n    PhTimeoutFromMilliseconds(&client.MessageTimeouts.ProcessCreateTimeout, 3000);\n    PhTimeoutFromMilliseconds(&client.MessageTimeouts.FilePreCreateTimeout, 3000);\n    PhTimeoutFromMilliseconds(&client.MessageTimeouts.FilePostCreateTimeout, 3000);\n    //client.AsyncQueuePolicy = (KPH_RATE_LIMIT_POLICY)KPH_RATE_LIMIT_PER_SEC(1000, 30000);\n    client.AsyncQueuePolicy = (KPH_RATE_LIMIT_POLICY)KPH_RATE_LIMIT_DENY_ALL;\n    for (ULONG i = 0; i < KPH_INFORMER_COUNT; i++)\n        client.InformerPolicy[i] = (KPH_RATE_LIMIT_POLICY)KPH_RATE_LIMIT_UNLIMITED;\n\n    KphSetInformerClientSettings(&client);\n}\n"
  },
  {
    "path": "SystemInformer/itemtips.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n\n#include <settings.h>\n#include <svcsup.h>\n#include <verify.h>\n\n#include <phplug.h>\n#include <phsettings.h>\n#include <procprv.h>\n#include <srvprv.h>\n\n#include <taskschd.h>\n\nVOID PhpFillUmdfDrivers(\n    _In_ PPH_PROCESS_ITEM Process,\n    _Inout_ PPH_STRING_BUILDER Drivers\n    );\n\nVOID PhpFillRunningTasks(\n    _In_ PPH_PROCESS_ITEM Process,\n    _Inout_ PPH_STRING_BUILDER Tasks\n    );\n\nVOID PhpFillWmiProviderHost(\n    _In_ PPH_PROCESS_ITEM Process,\n    _Inout_ PPH_STRING_BUILDER Providers\n    );\n\nextern PPH_STRING PhQueryWmiHostProcessString( // prpgwmi.c\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _Inout_ PPH_STRING_BUILDER Providers\n    );\nextern BOOLEAN PhpShouldShowImageCoherency(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ BOOLEAN CheckThreshold\n    );\n\nstatic CONST PH_STRINGREF StandardIndent = PH_STRINGREF_INIT(L\"    \");\n\nVOID PhpAppendStringWithLineBreaks(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PPH_STRINGREF String,\n    _In_ ULONG CharactersPerLine,\n    _In_opt_ PPH_STRINGREF IndentAfterFirstLine\n    )\n{\n    PH_STRINGREF line;\n    SIZE_T bytesPerLine;\n    BOOLEAN afterFirstLine;\n    SIZE_T bytesToAppend;\n\n    line = *String;\n    bytesPerLine = CharactersPerLine * sizeof(WCHAR);\n    afterFirstLine = FALSE;\n\n    while (line.Length != 0)\n    {\n        bytesToAppend = line.Length;\n\n        if (bytesToAppend > bytesPerLine)\n            bytesToAppend = bytesPerLine;\n\n        if (afterFirstLine)\n        {\n            PhAppendCharStringBuilder(StringBuilder, L'\\n');\n\n            if (IndentAfterFirstLine)\n                PhAppendStringBuilder(StringBuilder, IndentAfterFirstLine);\n        }\n\n        PhAppendStringBuilderEx(StringBuilder, line.Buffer, bytesToAppend);\n        afterFirstLine = TRUE;\n        PhSkipStringRef(&line, bytesToAppend);\n    }\n}\n\nstatic int __cdecl ServiceForTooltipCompare(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)elem1;\n    PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)elem2;\n\n    return PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE);\n}\n\nPPH_STRING PhGetProcessTooltipText(\n    _In_ PPH_PROCESS_ITEM Process,\n    _Out_opt_ PULONG64 ValidToTickCount\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    ULONG validForMs = 60 * 60 * 1000; // 1 hour\n    PPH_STRING tempString;\n    PPH_STRING fileName;\n\n    PhInitializeStringBuilder(&stringBuilder, 200);\n\n    // Command line\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_COMMAND_LINE_TOOLTIPS) && Process->CommandLine)\n    {\n        tempString = PhEllipsisString(Process->CommandLine, 100 * 10);\n\n        // This is necessary because the tooltip control seems to use some kind of O(n^9999) word-wrapping\n        // algorithm.\n        PhpAppendStringWithLineBreaks(&stringBuilder, &tempString->sr, 100, NULL);\n        PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n\n        PhDereferenceObject(tempString);\n    }\n\n    // File information\n\n    fileName = Process->FileName ? PhGetFileName(Process->FileName) : NULL;\n\n    if (fileName)\n    {\n        tempString = PhFormatImageVersionInfo(\n            fileName,\n            &Process->VersionInfo,\n            &StandardIndent,\n            0\n            );\n\n        if (!PhIsNullOrEmptyString(tempString))\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"File:\\n\");\n            PhAppendStringBuilder(&stringBuilder, &tempString->sr);\n            PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n        }\n\n        if (tempString)\n            PhDereferenceObject(tempString);\n        PhDereferenceObject(fileName);\n    }\n\n    // Known command line information\n\n    if (Process->CommandLine && Process->QueryHandle)\n    {\n        PH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine;\n\n        if (Process->KnownProcessType != UnknownProcessType && PhaGetProcessKnownCommandLine(\n            Process->CommandLine,\n            Process->KnownProcessType,\n            &knownCommandLine\n            ))\n        {\n            switch (Process->KnownProcessType & KnownProcessTypeMask)\n            {\n            case ServiceHostProcessType:\n                PhAppendStringBuilder2(&stringBuilder, L\"Service group name:\\n    \");\n                PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ServiceHost.GroupName->sr);\n                PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n                break;\n            case RunDllAsAppProcessType:\n                {\n                    PH_IMAGE_VERSION_INFO versionInfo;\n\n                    if (NT_SUCCESS(PhInitializeImageVersionInfo(\n                        &versionInfo,\n                        knownCommandLine.RunDllAsApp.FileName->Buffer\n                        )))\n                    {\n                        tempString = PhFormatImageVersionInfo(\n                            knownCommandLine.RunDllAsApp.FileName,\n                            &versionInfo,\n                            &StandardIndent,\n                            0\n                            );\n\n                        if (!PhIsNullOrEmptyString(tempString))\n                        {\n                            PhAppendStringBuilder2(&stringBuilder, L\"Run DLL target file:\\n\");\n                            PhAppendStringBuilder(&stringBuilder, &tempString->sr);\n                            PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n                        }\n\n                        if (tempString)\n                            PhDereferenceObject(tempString);\n\n                        PhDeleteImageVersionInfo(&versionInfo);\n                    }\n                }\n                break;\n            case ComSurrogateProcessType:\n                {\n                    PH_IMAGE_VERSION_INFO versionInfo;\n                    PPH_STRING guidString;\n\n                    PhAppendStringBuilder2(&stringBuilder, L\"COM target:\\n\");\n\n                    if (knownCommandLine.ComSurrogate.Name)\n                    {\n                        PhAppendStringBuilder(&stringBuilder, &StandardIndent);\n                        PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ComSurrogate.Name->sr);\n                        PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n                    }\n\n                    if (guidString = PhFormatGuid(&knownCommandLine.ComSurrogate.Guid))\n                    {\n                        PhAppendStringBuilder(&stringBuilder, &StandardIndent);\n                        PhAppendStringBuilder(&stringBuilder, &guidString->sr);\n                        PhDereferenceObject(guidString);\n                        PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n                    }\n\n                    if (knownCommandLine.ComSurrogate.FileName && NT_SUCCESS(PhInitializeImageVersionInfo(\n                        &versionInfo,\n                        knownCommandLine.ComSurrogate.FileName->Buffer\n                        )))\n                    {\n                        tempString = PhFormatImageVersionInfo(\n                            knownCommandLine.ComSurrogate.FileName,\n                            &versionInfo,\n                            &StandardIndent,\n                            0\n                            );\n\n                        if (!PhIsNullOrEmptyString(tempString))\n                        {\n                            PhAppendStringBuilder2(&stringBuilder, L\"COM target file:\\n\");\n                            PhAppendStringBuilder(&stringBuilder, &tempString->sr);\n                            PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n                        }\n\n                        if (tempString)\n                            PhDereferenceObject(tempString);\n\n                        PhDeleteImageVersionInfo(&versionInfo);\n                    }\n                }\n                break;\n            }\n        }\n    }\n\n    // Services\n\n    if (Process->ServiceList && Process->ServiceList->Count != 0)\n    {\n        ULONG enumerationKey = 0;\n        PPH_SERVICE_ITEM serviceItem;\n        PPH_LIST serviceList;\n        ULONG i;\n\n        // Copy the service list into our own list so we can sort it.\n\n        serviceList = PhCreateList(Process->ServiceList->Count);\n\n        PhAcquireQueuedLockShared(&Process->ServiceListLock);\n\n        while (PhEnumPointerList(\n            Process->ServiceList,\n            &enumerationKey,\n            &serviceItem\n            ))\n        {\n            PhReferenceObject(serviceItem);\n            PhAddItemList(serviceList, serviceItem);\n        }\n\n        PhReleaseQueuedLockShared(&Process->ServiceListLock);\n\n        qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForTooltipCompare);\n\n        PhAppendStringBuilder2(&stringBuilder, L\"Services:\\n\");\n\n        // Add the services.\n        for (i = 0; i < serviceList->Count; i++)\n        {\n            serviceItem = serviceList->Items[i];\n\n            PhAppendStringBuilder(&stringBuilder, &StandardIndent);\n            PhAppendStringBuilder(&stringBuilder, &serviceItem->Name->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\" (\");\n            PhAppendStringBuilder(&stringBuilder, &serviceItem->DisplayName->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\")\\n\");\n        }\n\n        PhDereferenceObjects(serviceList->Items, serviceList->Count);\n        PhDereferenceObject(serviceList);\n    }\n\n    // Tasks, Drivers\n    switch (Process->KnownProcessType & KnownProcessTypeMask)\n    {\n    case TaskHostProcessType:\n        {\n            PH_STRING_BUILDER tasks;\n\n            PhInitializeStringBuilder(&tasks, 40);\n\n            PhpFillRunningTasks(Process, &tasks);\n\n            if (tasks.String->Length != 0)\n            {\n                PhAppendStringBuilder2(&stringBuilder, L\"Tasks:\\n\");\n                PhAppendStringBuilder(&stringBuilder, &tasks.String->sr);\n            }\n\n            PhDeleteStringBuilder(&tasks);\n        }\n        break;\n    case UmdfHostProcessType:\n        {\n            PH_STRING_BUILDER drivers;\n\n            PhInitializeStringBuilder(&drivers, 40);\n\n            PhpFillUmdfDrivers(Process, &drivers);\n\n            if (drivers.String->Length != 0)\n            {\n                PhAppendStringBuilder2(&stringBuilder, L\"Drivers:\\n\");\n                PhAppendStringBuilder(&stringBuilder, &drivers.String->sr);\n            }\n\n            PhDeleteStringBuilder(&drivers);\n\n            validForMs = 10 * 1000; // 10 seconds\n        }\n        break;\n    //case EdgeProcessType:\n    //    {\n    //        PH_STRING_BUILDER container;\n    //\n    //        PhInitializeStringBuilder(&container, 40);\n    //\n    //        PhpFillMicrosoftEdge(Process, &container);\n    //\n    //        if (container.String->Length != 0)\n    //        {\n    //            PhAppendStringBuilder2(&stringBuilder, L\"Edge:\\n\");\n    //            PhAppendStringBuilder(&stringBuilder, &container.String->sr);\n    //        }\n    //\n    //        PhDeleteStringBuilder(&container);\n    //    }\n    //    break;\n    case WmiProviderHostType:\n        {\n            PH_STRING_BUILDER provider;\n\n            PhInitializeStringBuilder(&provider, 40);\n\n            PhpFillWmiProviderHost(Process, &provider);\n\n            if (provider.String->Length != 0)\n            {\n                PhAppendStringBuilder2(&stringBuilder, L\"WMI Providers:\\n\");\n                PhAppendStringBuilder(&stringBuilder, &provider.String->sr);\n            }\n\n            PhDeleteStringBuilder(&provider);\n\n            validForMs = 10 * 1000; // 10 seconds\n        }\n        break;\n    }\n\n    // Plugin\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText;\n\n        getTooltipText.Parameter = Process;\n        getTooltipText.StringBuilder = &stringBuilder;\n        getTooltipText.ValidForMs = validForMs;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), &getTooltipText);\n        validForMs = getTooltipText.ValidForMs;\n    }\n\n    // Notes\n\n    {\n        PH_STRING_BUILDER notes;\n\n        PhInitializeStringBuilder(&notes, 40);\n\n        if (Process->FileName)\n        {\n            if (Process->VerifyResult == VrTrusted)\n            {\n                if (!PhIsNullOrEmptyString(Process->VerifySignerName))\n                    PhAppendFormatStringBuilder(&notes, L\"    Signer: %s\\n\", Process->VerifySignerName->Buffer);\n                else\n                    PhAppendStringBuilder2(&notes, L\"    Signed.\\n\");\n            }\n            else if (Process->VerifyResult == VrUnknown)\n            {\n                // Nothing\n            }\n            else if (Process->VerifyResult != VrNoSignature)\n            {\n                PhAppendStringBuilder2(&notes, L\"    Signature invalid.\\n\");\n            }\n        }\n\n        if (Process->IsPacked)\n        {\n            PhAppendFormatStringBuilder(\n                &notes,\n                L\"    Image is probably packed (%lu %ls over %lu %ls).\\n\",\n                Process->ImportFunctions,\n                Process->ImportFunctions == 1 ? L\"import\" : L\"imports\",\n                Process->ImportModules,\n                Process->ImportModules == 1 ? L\"module\" : L\"modules\"\n                );\n        }\n\n        if (PhEnableImageCoherencySupport && PhpShouldShowImageCoherency(Process, TRUE))\n        {\n            PhAppendFormatStringBuilder(\n                &notes,\n                L\"    Low image coherency: %.2f%%\\n\",\n                (Process->ImageCoherency * 100.0f)\n                );\n        }\n\n        if ((ULONG_PTR)Process->ConsoleHostProcessId & ~3)\n        {\n            CLIENT_ID clientId;\n            PWSTR description;\n            PPH_STRING clientIdString;\n\n            clientId.UniqueProcess = (HANDLE)((ULONG_PTR)Process->ConsoleHostProcessId & ~3);\n            clientId.UniqueThread = NULL;\n\n            if ((ULONG_PTR)Process->ConsoleHostProcessId & 2)\n                description = L\"Console application\";\n            else\n                description = L\"Console host\";\n\n            clientIdString = PhGetClientIdName(&clientId);\n            PhAppendFormatStringBuilder(&notes, L\"    %s: %s\\n\", description, clientIdString->Buffer);\n            PhDereferenceObject(clientIdString);\n        }\n\n        if (Process->PackageFullName)\n        {\n            PhAppendFormatStringBuilder(&notes, L\"    Package name: %s\\n\", Process->PackageFullName->Buffer);\n        }\n\n        if (notes.String->Length != 0)\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"Notes:\\n\");\n            PhAppendStringBuilder(&stringBuilder, &notes.String->sr);\n        }\n\n        PhDeleteStringBuilder(&notes);\n        PhInitializeStringBuilder(&notes, 40);\n\n        if (Process->IsSystemProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is a system process (TCB).\\n\");\n        if (Process->IsBeingDebugged)\n            PhAppendStringBuilder2(&notes, L\"    Process is being debugged.\\n\");\n        if (Process->IsSuspended)\n            PhAppendStringBuilder2(&notes, L\"    Process is suspended.\\n\");\n        if (Process->IsFrozenProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is in deep freeze (suspended).\\n\");\n        if (Process->IsDotNet)\n            PhAppendStringBuilder2(&notes, L\"    Process is managed (.NET).\\n\");\n        if (Process->IsElevated)\n        {\n            if (Process->ElevationType == TokenElevationTypeDefault)\n                PhAppendStringBuilder2(&notes, L\"    Process is default elevated.\\n\");\n            else if (Process->ElevationType == TokenElevationTypeFull)\n                PhAppendStringBuilder2(&notes, L\"    Process is full elevated.\\n\");\n            else if (Process->ElevationType == TokenElevationTypeLimited)\n                PhAppendStringBuilder2(&notes, L\"    Process is limited elevated.\\n\");\n            else\n                PhAppendStringBuilder2(&notes, L\"    Process is elevated.\\n\");\n        }\n        if (Process->IsUIAccessEnabled)\n            PhAppendStringBuilder2(&notes, L\"    Process is UIAccess.\\n\");\n        if (Process->IsImmersive)\n            PhAppendStringBuilder2(&notes, L\"    Process is a Modern UI app.\\n\");\n        if (Process->IsInJob)\n            PhAppendStringBuilder2(&notes, L\"    Process is in a job.\\n\");\n        if (Process->IsWow64Process)\n            PhAppendStringBuilder2(&notes, L\"    Process is 32-bit (WOW64).\\n\");\n        if (Process->IsProtectedProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is a protected process (PP/PPL).\\n\");\n        if (Process->IsSecureProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is a secure isolated process (IUM).\\n\");\n        if (Process->IsSecureProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is a secure virtualization process (HVCI).\\n\");\n        if (Process->IsSubsystemProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is a subsystem process.\\n\");\n        if (Process->IsPackagedProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is a packaged process.\\n\");\n        if (Process->IsBackgroundProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is a background process.\\n\");\n        if (Process->IsCrossSessionProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is a cross session process.\\n\");\n        //\n        // TODO(jxy-s) Find a way to identify reflected processes maybe initial\n        // thread start address (RtlpProcessReflectionStartup)?\n        //\n        //if (Process->IsReflectedProcess)\n        //    PhAppendStringBuilder2(&notes, L\"    Process is a reflected process.\\n\");\n        //\n        // TODO(jxy-s) Find a way to identify cloned processes. This is distinct\n        // from snapshot process since it is created with an initial thread. The\n        // PEB address and some initial TEB content is likely to be the same as\n        // the process it originated from.\n        //\n        //if (Process->IsClonedProcess)\n        //    PhAppendStringBuilder2(&notes, L\"    Process is a cloned process.\\n\");\n        if (Process->IsSnapshotProcess)\n            PhAppendStringBuilder2(&notes, L\"    Process is a snapshot process.\\n\");\n        if (Process->IsPowerThrottling)\n            PhAppendStringBuilder2(&notes, L\"    Process is power throttling (efficiency).\\n\");\n\n        if (notes.String->Length != 0)\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"Flags:\\n\");\n            PhAppendStringBuilder(&stringBuilder, &notes.String->sr);\n        }\n\n        PhDeleteStringBuilder(&notes);\n    }\n\n    if (ValidToTickCount)\n        *ValidToTickCount = NtGetTickCount64() + validForMs;\n\n    // Remove the trailing newline.\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nVOID PhpFillUmdfDrivers(\n    _In_ PPH_PROCESS_ITEM Process,\n    _Inout_ PPH_STRING_BUILDER Drivers\n    )\n{\n    static CONST PH_STRINGREF activeDevices = PH_STRINGREF_INIT(L\"ACTIVE_DEVICES\");\n    static CONST PH_STRINGREF currentControlSetEnum = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Enum\\\\\");\n    HANDLE processHandle;\n    PVOID environment;\n    ULONG environmentLength;\n    ULONG enumerationKey;\n    PH_ENVIRONMENT_VARIABLE variable;\n\n    if (!NT_SUCCESS(PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n        Process->ProcessId\n        )))\n        return;\n\n    if (NT_SUCCESS(PhGetProcessEnvironment(\n        processHandle,\n        !!Process->IsWow64Process,\n        &environment,\n        &environmentLength\n        )))\n    {\n        enumerationKey = 0;\n\n        while (NT_SUCCESS(PhEnumProcessEnvironmentVariables(\n            environment,\n            environmentLength,\n            &enumerationKey,\n            &variable\n            )))\n        {\n            PH_STRINGREF part;\n            PH_STRINGREF remainingPart;\n\n            if (!PhEqualStringRef(&variable.Name, &activeDevices, TRUE))\n                continue;\n\n            remainingPart = variable.Value;\n\n            while (remainingPart.Length != 0)\n            {\n                PhSplitStringRefAtChar(&remainingPart, L';', &part, &remainingPart);\n\n                if (part.Length != 0)\n                {\n                    HANDLE driverKeyHandle;\n                    PPH_STRING driverKeyPath;\n\n                    driverKeyPath = PhConcatStringRef2(&currentControlSetEnum, &part);\n\n                    if (NT_SUCCESS(PhOpenKey(\n                        &driverKeyHandle,\n                        KEY_READ,\n                        PH_KEY_LOCAL_MACHINE,\n                        &driverKeyPath->sr,\n                        0\n                        )))\n                    {\n                        PPH_STRING deviceDesc;\n                        PH_STRINGREF deviceName;\n                        PPH_STRING hardwareId;\n\n                        if (deviceDesc = PhQueryRegistryStringZ(driverKeyHandle, L\"DeviceDesc\"))\n                        {\n                            PH_STRINGREF firstPart;\n                            PH_STRINGREF secondPart;\n\n                            if (PhSplitStringRefAtLastChar(&deviceDesc->sr, L';', &firstPart, &secondPart))\n                                deviceName = secondPart;\n                            else\n                                deviceName = deviceDesc->sr;\n                        }\n                        else\n                        {\n                            PhInitializeStringRef(&deviceName, L\"Unknown Device\");\n                        }\n\n                        PhAppendStringBuilder(Drivers, &StandardIndent);\n                        PhAppendStringBuilder(Drivers, &deviceName);\n\n                        if (hardwareId = PhQueryRegistryStringZ(driverKeyHandle, L\"HardwareID\"))\n                        {\n                            PhTrimToNullTerminatorString(hardwareId);\n\n                            if (hardwareId->Length != 0)\n                            {\n                                PhAppendStringBuilder2(Drivers, L\" (\");\n                                PhAppendStringBuilder(Drivers, &hardwareId->sr);\n                                PhAppendCharStringBuilder(Drivers, L')');\n                            }\n                        }\n\n                        PhAppendCharStringBuilder(Drivers, L'\\n');\n\n                        PhClearReference(&hardwareId);\n                        PhClearReference(&deviceDesc);\n                        NtClose(driverKeyHandle);\n                    }\n\n                    PhDereferenceObject(driverKeyPath);\n                }\n            }\n\n            break;\n        }\n\n        PhFreePage(environment);\n    }\n\n    NtClose(processHandle);\n}\n\nVOID PhpFillRunningTasks(\n    _In_ PPH_PROCESS_ITEM Process,\n    _Inout_ PPH_STRING_BUILDER Tasks\n    )\n{\n    ITaskService *taskService = NULL;\n\n    if (SUCCEEDED(PhGetClassObject(\n        L\"taskschd.dll\",\n        &CLSID_TaskScheduler,\n        &IID_ITaskService,\n        &taskService\n        )))\n    {\n        VARIANT empty = { 0 };\n\n        if (SUCCEEDED(ITaskService_Connect(taskService, empty, empty, empty, empty)))\n        {\n            IRunningTaskCollection *runningTasks;\n\n            if (SUCCEEDED(ITaskService_GetRunningTasks(\n                taskService,\n                TASK_ENUM_HIDDEN,\n                &runningTasks\n                )))\n            {\n                LONG count;\n                LONG i;\n                VARIANT index;\n\n                if (SUCCEEDED(IRunningTaskCollection_get_Count(runningTasks, &count)))\n                {\n                    for (i = 1; i <= count; i++) // collections are 1-based\n                    {\n                        IRunningTask *runningTask;\n\n                        V_VT(&index) = VT_INT;\n                        V_I4(&index) = i;\n\n                        if (SUCCEEDED(IRunningTaskCollection_get_Item(runningTasks, index, &runningTask)))\n                        {\n                            ULONG pid;\n                            BSTR action = NULL;\n                            BSTR path = NULL;\n\n                            if (\n                                SUCCEEDED(IRunningTask_get_EnginePID(runningTask, &pid)) &&\n                                pid == HandleToUlong(Process->ProcessId)\n                                )\n                            {\n                                IRunningTask_get_CurrentAction(runningTask, &action);\n                                IRunningTask_get_Path(runningTask, &path);\n\n                                PhAppendStringBuilder(Tasks, &StandardIndent);\n                                PhAppendStringBuilder2(Tasks, action ? action : L\"Unknown action\");\n                                PhAppendStringBuilder2(Tasks, L\" (\");\n                                PhAppendStringBuilder2(Tasks, path ? path : L\"Unknown path\");\n                                PhAppendStringBuilder2(Tasks, L\")\\n\");\n\n                                if (action)\n                                    SysFreeString(action);\n                                if (path)\n                                    SysFreeString(path);\n                            }\n\n                            IRunningTask_Release(runningTask);\n                        }\n                    }\n                }\n\n                IRunningTaskCollection_Release(runningTasks);\n            }\n        }\n\n        ITaskService_Release(taskService);\n    }\n}\n\n//VOID PhpFillMicrosoftEdge(\n//    _In_ PPH_PROCESS_ITEM Process,\n//    _Inout_ PPH_STRING_BUILDER Containers\n//    )\n//{\n//    HANDLE tokenHandle;\n//    PSID appContainerInfo;\n//    PPH_STRING appContainerSid = NULL;\n//\n//    if (NT_SUCCESS(PhOpenProcessToken(\n//        Process->QueryHandle,\n//        TOKEN_QUERY,\n//        &tokenHandle\n//        )))\n//    {\n//        if (NT_SUCCESS(PhGetTokenAppContainerSid(tokenHandle, &appContainerInfo)))\n//        {\n//            appContainerSid = PhSidToStringSid(appContainerInfo);\n//            PhFree(appContainerInfo);\n//        }\n//    }\n//\n//    if (appContainerSid)\n//    {\n//        static PH_STRINGREF managerSid = PH_STRINGREF_INIT(L\"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194\");\n//        static PH_STRINGREF extensionsSid = PH_STRINGREF_INIT(L\"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-1206159417-1570029349-2913729690-1184509225\");\n//        static PH_STRINGREF serviceUiSid = PH_STRINGREF_INIT(L\"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-3513710562-3729412521-1863153555-1462103995\");\n//        static PH_STRINGREF chakraJitSid = PH_STRINGREF_INIT(L\"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-1821068571-1793888307-623627345-1529106238\");\n//        static PH_STRINGREF flashSid = PH_STRINGREF_INIT(L\"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-3859068477-1314311106-1651661491-1685393560\");\n//        static PH_STRINGREF backgroundTabPool1Sid = PH_STRINGREF_INIT(L\"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-4256926629-1688279915-2739229046-3928706915\");\n//        static PH_STRINGREF backgroundTabPool2Sid = PH_STRINGREF_INIT(L\"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-2385269614-3243675-834220592-3047885450\");\n//        static PH_STRINGREF backgroundTabPool3Sid = PH_STRINGREF_INIT(L\"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-355265979-2879959831-980936148-1241729999\");\n//\n//        if (PhEqualStringRef(&appContainerSid->sr, &managerSid, FALSE))\n//        {\n//            PhAppendStringBuilder2(Containers, L\"    Microsoft Edge Manager\\n\");\n//        }\n//        else if (PhEqualStringRef(&appContainerSid->sr, &extensionsSid, FALSE))\n//        {\n//            PhAppendStringBuilder2(Containers, L\"    Browser Extensions\\n\");\n//        }\n//        else if (PhEqualStringRef(&appContainerSid->sr, &serviceUiSid, FALSE))\n//        {\n//            PhAppendStringBuilder2(Containers, L\"    User Interface Service\\n\");\n//        }\n//        else if (PhEqualStringRef(&appContainerSid->sr, &chakraJitSid, FALSE))\n//        {\n//            PhAppendStringBuilder2(Containers, L\"    Chakra Jit Compiler\\n\");\n//        }\n//        else if (PhEqualStringRef(&appContainerSid->sr, &flashSid, FALSE))\n//        {\n//            PhAppendStringBuilder2(Containers, L\"    Adobe Flash Player\\n\");\n//        }\n//        else if (\n//            PhEqualStringRef(&appContainerSid->sr, &backgroundTabPool1Sid, FALSE) ||\n//            PhEqualStringRef(&appContainerSid->sr, &backgroundTabPool2Sid, FALSE) ||\n//            PhEqualStringRef(&appContainerSid->sr, &backgroundTabPool3Sid, FALSE)\n//            )\n//        {\n//            PhAppendStringBuilder2(Containers, L\"    Background Tab Pool\\n\");\n//        }\n//\n//        PhDereferenceObject(appContainerSid);\n//    }\n//}\n\nVOID PhpFillWmiProviderHost(\n    _In_ PPH_PROCESS_ITEM Process,\n    _Inout_ PPH_STRING_BUILDER Providers\n    )\n{\n    if (PhGetIntegerSetting(SETTING_WMI_PROVIDER_ENABLE_TOOLTIP_SUPPORT))\n    {\n        PhQueryWmiHostProcessString(Process, Providers);\n    }\n}\n\nPPH_STRING PhGetServiceTooltipText(\n    _In_ PPH_SERVICE_ITEM Service\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    SC_HANDLE serviceHandle;\n\n    PhInitializeStringBuilder(&stringBuilder, 200);\n\n    if (NT_SUCCESS(PhOpenService(&serviceHandle, SERVICE_QUERY_CONFIG, PhGetString(Service->Name))))\n    {\n        PPH_STRING fileName;\n        PPH_STRING description;\n\n        // File information\n\n        if (NT_SUCCESS(PhGetServiceHandleFileName(serviceHandle, &Service->Name->sr, &fileName)))\n        {\n            PH_IMAGE_VERSION_INFO versionInfo;\n            PPH_STRING versionInfoText;\n\n            if (NT_SUCCESS(PhInitializeImageVersionInfo(\n                &versionInfo,\n                fileName->Buffer\n                )))\n            {\n                versionInfoText = PhFormatImageVersionInfo(\n                    fileName,\n                    &versionInfo,\n                    &StandardIndent,\n                    0\n                    );\n\n                if (!PhIsNullOrEmptyString(versionInfoText))\n                {\n                    PhAppendStringBuilder2(&stringBuilder, L\"File:\\n\");\n                    PhAppendStringBuilder(&stringBuilder, &versionInfoText->sr);\n                    PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n                }\n\n                PhClearReference(&versionInfoText);\n                PhDeleteImageVersionInfo(&versionInfo);\n            }\n\n            PhDereferenceObject(fileName);\n        }\n\n        // Description\n\n        if (description = PhGetServiceDescription(serviceHandle))\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"Description:\\n    \");\n            PhAppendStringBuilder(&stringBuilder, &description->sr);\n            PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n            PhDereferenceObject(description);\n        }\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    // Remove the trailing newline.\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n"
  },
  {
    "path": "SystemInformer/jobprp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2018-2019\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <procprv.h>\n\n#include <emenu.h>\n#include <hndlinfo.h>\n#include <secedit.h>\n#include <settings.h>\n#include <phsettings.h>\n\n#define MSG_UPDATE (WM_APP + 1)\n\ntypedef struct _JOB_PAGE_CONTEXT\n{\n    PPH_OPEN_OBJECT OpenObject;\n    PPH_CLOSE_OBJECT CloseObject;\n    PVOID Context;\n    DLGPROC HookProc;\n    PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;\n} JOB_PAGE_CONTEXT, *PJOB_PAGE_CONTEXT;\n\nINT CALLBACK PhpJobPropPageProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ LPPROPSHEETPAGE ppsp\n    );\n\nINT_PTR CALLBACK PhpJobPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhpShowJobAdvancedProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PJOB_PAGE_CONTEXT Context\n    );\n\nINT_PTR CALLBACK PhpJobStatisticsPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT CALLBACK PhpJobStatisticsSheetProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowJobProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context,\n    _In_opt_ PCWSTR Title\n    )\n{\n    PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };\n    HPROPSHEETPAGE pages[1];\n\n    propSheetHeader.dwFlags =\n        PSH_NOAPPLYNOW |\n        PSH_NOCONTEXTHELP |\n        PSH_PROPTITLE;\n    propSheetHeader.hInstance = PhInstanceHandle;\n    propSheetHeader.hwndParent = ParentWindowHandle;\n    propSheetHeader.pszCaption = Title ? Title : L\"Job\";\n    propSheetHeader.nPages = 1;\n    propSheetHeader.nStartPage = 0;\n    propSheetHeader.phpage = pages;\n\n    pages[0] = PhCreateJobPage(OpenObject, CloseObject, Context, NULL);\n\n    PhModalPropertySheet(&propSheetHeader);\n}\n\nHPROPSHEETPAGE PhCreateJobPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context,\n    _In_opt_ DLGPROC HookProc\n    )\n{\n    HPROPSHEETPAGE propSheetPageHandle;\n    PROPSHEETPAGE propSheetPage;\n    PJOB_PAGE_CONTEXT jobPageContext;\n\n    jobPageContext = PhCreateAlloc(sizeof(JOB_PAGE_CONTEXT));\n    memset(jobPageContext, 0, sizeof(JOB_PAGE_CONTEXT));\n    jobPageContext->OpenObject = OpenObject;\n    jobPageContext->CloseObject = CloseObject;\n    jobPageContext->Context = Context;\n    jobPageContext->HookProc = HookProc;\n\n    memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));\n    propSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propSheetPage.dwFlags = PSP_USECALLBACK;\n    propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJJOB);\n    propSheetPage.hInstance = PhInstanceHandle;\n    propSheetPage.pfnDlgProc = PhpJobPageProc;\n    propSheetPage.lParam = (LPARAM)jobPageContext;\n    propSheetPage.pfnCallback = PhpJobPropPageProc;\n\n    propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);\n    // CreatePropertySheetPage would have sent PSPCB_ADDREF (below),\n    // which would have added a reference.\n    PhDereferenceObject(jobPageContext);\n\n    return propSheetPageHandle;\n}\n\nINT CALLBACK PhpJobPropPageProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ LPPROPSHEETPAGE ppsp\n    )\n{\n    PJOB_PAGE_CONTEXT jobPageContext;\n\n    jobPageContext = (PJOB_PAGE_CONTEXT)ppsp->lParam;\n\n    if (uMsg == PSPCB_ADDREF)\n    {\n        PhReferenceObject(jobPageContext);\n    }\n    else if (uMsg == PSPCB_RELEASE)\n    {\n        PhDereferenceObject(jobPageContext);\n    }\n\n    return 1;\n}\n\nFORCEINLINE PJOB_PAGE_CONTEXT PhpJobPageHeader(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    return PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 1);\n}\n\nstatic VOID PhpAddLimit(\n    _In_ HWND Handle,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Value\n    )\n{\n    LONG lvItemIndex;\n\n    lvItemIndex = PhAddListViewItem(Handle, MAXINT, Name, NULL);\n    PhSetListViewSubItem(Handle, lvItemIndex, 1, Value);\n}\n\nstatic VOID PhpAddJobProcesses(\n    _In_ HWND hwndDlg,\n    _In_ HANDLE JobHandle\n    )\n{\n    PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList;\n    HWND processesLv;\n\n    processesLv = GetDlgItem(hwndDlg, IDC_PROCESSES);\n\n    if (NT_SUCCESS(PhGetJobProcessIdList(JobHandle, &processIdList)))\n    {\n        ULONG i;\n        CLIENT_ID clientId;\n        PPH_STRING name;\n\n        clientId.UniqueThread = NULL;\n\n        for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++)\n        {\n            clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i];\n            name = PH_AUTO(PhGetClientIdName(&clientId));\n\n            PhAddListViewItem(processesLv, MAXINT, PhGetString(name), NULL);\n        }\n\n        PhFree(processIdList);\n    }\n}\n\nINT_PTR CALLBACK PhpJobPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PJOB_PAGE_CONTEXT jobPageContext;\n\n    jobPageContext = PhpJobPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!jobPageContext)\n        return FALSE;\n\n    if (jobPageContext->HookProc)\n    {\n        if (jobPageContext->HookProc(hwndDlg, uMsg, wParam, lParam))\n            return TRUE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HANDLE jobHandle;\n            HWND processesLv;\n            HWND limitsLv;\n\n            processesLv = GetDlgItem(hwndDlg, IDC_PROCESSES);\n            limitsLv = GetDlgItem(hwndDlg, IDC_LIMITS);\n            PhSetListViewStyle(processesLv, FALSE, TRUE);\n            PhSetListViewStyle(limitsLv, FALSE, TRUE);\n            PhSetControlTheme(processesLv, L\"explorer\");\n            PhSetControlTheme(limitsLv, L\"explorer\");\n            PhSetExtendedListView(processesLv);\n            PhSetExtendedListView(limitsLv);\n\n            PhAddListViewColumn(processesLv, 0, 0, 0, LVCFMT_LEFT, 240, L\"Name\");\n            PhAddListViewColumn(limitsLv, 0, 0, 0, LVCFMT_LEFT, 120, L\"Name\");\n            PhAddListViewColumn(limitsLv, 1, 1, 1, LVCFMT_LEFT, 160, L\"Value\");\n            PhLoadListViewColumnsFromSetting(SETTING_JOB_LIST_VIEW_COLUMNS, limitsLv);\n\n            PhSetDialogItemText(hwndDlg, IDC_NAME, L\"Unknown\");\n\n            if (NT_SUCCESS(jobPageContext->OpenObject(\n                &jobHandle,\n                JOB_OBJECT_QUERY,\n                jobPageContext->Context\n                )))\n            {\n                PPH_STRING jobObjectName = NULL;\n                JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimits;\n                JOBOBJECT_BASIC_UI_RESTRICTIONS basicUiRestrictions;\n\n                // Name\n\n                PhGetHandleInformation(\n                    NtCurrentProcess(),\n                    jobHandle,\n                    ULONG_MAX,\n                    NULL,\n                    NULL,\n                    NULL,\n                    &jobObjectName\n                    );\n                PH_AUTO(jobObjectName);\n\n                if (jobObjectName && jobObjectName->Length == 0)\n                    jobObjectName = NULL;\n\n                PhSetDialogItemText(hwndDlg, IDC_NAME, PhGetStringOrDefault(jobObjectName, L\"(unnamed job)\"));\n\n                // Processes\n                PhpAddJobProcesses(hwndDlg, jobHandle);\n\n                // Limits\n\n                if (NT_SUCCESS(PhGetJobExtendedLimits(jobHandle, &extendedLimits)))\n                {\n                    ULONG flags = extendedLimits.BasicLimitInformation.LimitFlags;\n\n                    if (flags & JOB_OBJECT_LIMIT_ACTIVE_PROCESS)\n                    {\n                        WCHAR value[PH_INT32_STR_LEN_1];\n                        PhPrintUInt32(value, extendedLimits.BasicLimitInformation.ActiveProcessLimit);\n                        PhpAddLimit(limitsLv, L\"Active processes\", value);\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_AFFINITY)\n                    {\n                        WCHAR value[PH_PTR_STR_LEN_1];\n                        PhPrintPointer(value, (PVOID)extendedLimits.BasicLimitInformation.Affinity);\n                        PhpAddLimit(limitsLv, L\"Affinity\", value);\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_BREAKAWAY_OK)\n                    {\n                        PhpAddLimit(limitsLv, L\"Breakaway OK\", L\"Enabled\");\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION)\n                    {\n                        PhpAddLimit(limitsLv, L\"Die on unhandled exception\", L\"Enabled\");\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_JOB_MEMORY)\n                    {\n                        PPH_STRING value = PhaFormatSize(extendedLimits.JobMemoryLimit, ULONG_MAX);\n                        PhpAddLimit(limitsLv, L\"Job memory\", value->Buffer);\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_JOB_TIME)\n                    {\n                        WCHAR value[PH_TIMESPAN_STR_LEN_1];\n                        PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerJobUserTimeLimit.QuadPart,\n                            PH_TIMESPAN_DHMS);\n                        PhpAddLimit(limitsLv, L\"Job time\", value);\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE)\n                    {\n                        PhpAddLimit(limitsLv, L\"Kill on job close\", L\"Enabled\");\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_PRIORITY_CLASS)\n                    {\n                        PCPH_STRINGREF value;\n\n                        if (value = PhGetProcessPriorityClassString(extendedLimits.BasicLimitInformation.PriorityClass))\n                        {\n                            PhpAddLimit(limitsLv, L\"Priority class\", value->Buffer);\n                        }\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_PROCESS_MEMORY)\n                    {\n                        PPH_STRING value = PhaFormatSize(extendedLimits.ProcessMemoryLimit, ULONG_MAX);\n                        PhpAddLimit(limitsLv, L\"Process memory\", value->Buffer);\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_PROCESS_TIME)\n                    {\n                        WCHAR value[PH_TIMESPAN_STR_LEN_1];\n                        PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart,\n                            PH_TIMESPAN_DHMS);\n                        PhpAddLimit(limitsLv, L\"Process time\", value);\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_SCHEDULING_CLASS)\n                    {\n                        WCHAR value[PH_INT32_STR_LEN_1];\n                        PhPrintUInt32(value, extendedLimits.BasicLimitInformation.SchedulingClass);\n                        PhpAddLimit(limitsLv, L\"Scheduling class\", value);\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)\n                    {\n                        PhpAddLimit(limitsLv, L\"Silent breakaway OK\", L\"Enabled\");\n                    }\n\n                    if (flags & JOB_OBJECT_LIMIT_WORKINGSET)\n                    {\n                        PPH_STRING value;\n\n                        value = PhaFormatSize(extendedLimits.BasicLimitInformation.MinimumWorkingSetSize, ULONG_MAX);\n                        PhpAddLimit(limitsLv, L\"Working set minimum\", value->Buffer);\n\n                        value = PhaFormatSize(extendedLimits.BasicLimitInformation.MaximumWorkingSetSize, ULONG_MAX);\n                        PhpAddLimit(limitsLv, L\"Working set maximum\", value->Buffer);\n                    }\n                }\n\n                if (NT_SUCCESS(PhGetJobBasicUiRestrictions(jobHandle, &basicUiRestrictions)))\n                {\n                    ULONG flags = basicUiRestrictions.UIRestrictionsClass;\n\n                    if (flags & JOB_OBJECT_UILIMIT_DESKTOP)\n                        PhpAddLimit(limitsLv, L\"Desktop\", L\"Limited\");\n                    if (flags & JOB_OBJECT_UILIMIT_DISPLAYSETTINGS)\n                        PhpAddLimit(limitsLv, L\"Display settings\", L\"Limited\");\n                    if (flags & JOB_OBJECT_UILIMIT_EXITWINDOWS)\n                        PhpAddLimit(limitsLv, L\"Exit windows\", L\"Limited\");\n                    if (flags & JOB_OBJECT_UILIMIT_GLOBALATOMS)\n                        PhpAddLimit(limitsLv, L\"Global atoms\", L\"Limited\");\n                    if (flags & JOB_OBJECT_UILIMIT_HANDLES)\n                        PhpAddLimit(limitsLv, L\"Handles\", L\"Limited\");\n                    if (flags & JOB_OBJECT_UILIMIT_READCLIPBOARD)\n                        PhpAddLimit(limitsLv, L\"Read clipboard\", L\"Limited\");\n                    if (flags & JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS)\n                        PhpAddLimit(limitsLv, L\"System parameters\", L\"Limited\");\n                    if (flags & JOB_OBJECT_UILIMIT_WRITECLIPBOARD)\n                        PhpAddLimit(limitsLv, L\"Write clipboard\", L\"Limited\");\n                }\n\n                NtClose(jobHandle);\n            }\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        PhSaveListViewColumnsToSetting(SETTING_JOB_LIST_VIEW_COLUMNS, GetDlgItem(hwndDlg, IDC_LIMITS));\n        break;\n    case WM_SHOWWINDOW:\n        {\n            ExtendedListView_SetColumnWidth(GetDlgItem(hwndDlg, IDC_PROCESSES), 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_TERMINATE:\n                {\n                    if (PhShowConfirmMessage(\n                        hwndDlg,\n                        L\"terminate\",\n                        L\"the job\",\n                        L\"Terminating a job will terminate all processes assigned to it.\",\n                        TRUE\n                        ))\n                    {\n                        NTSTATUS status;\n                        HANDLE jobHandle;\n\n                        if (NT_SUCCESS(status = jobPageContext->OpenObject(\n                            &jobHandle,\n                            JOB_OBJECT_TERMINATE,\n                            jobPageContext->Context\n                            )))\n                        {\n                            status = NtTerminateJobObject(jobHandle, STATUS_SUCCESS);\n                            NtClose(jobHandle);\n                        }\n\n                        if (!NT_SUCCESS(status))\n                            PhShowStatus(hwndDlg, L\"Unable to terminate the job\", status, 0);\n                    }\n                }\n                break;\n            case IDC_ADD:\n                {\n                    NTSTATUS status;\n                    HANDLE processId;\n                    HANDLE processHandle;\n                    HANDLE jobHandle;\n\n                    while (PhShowChooseProcessDialog(\n                        hwndDlg,\n                        L\"Select a process to add to the job permanently.\",\n                        &processId\n                        ))\n                    {\n                        if (NT_SUCCESS(status = PhOpenProcess(\n                            &processHandle,\n                            PROCESS_TERMINATE | PROCESS_SET_QUOTA,\n                            processId\n                            )))\n                        {\n                            if (NT_SUCCESS(status = jobPageContext->OpenObject(\n                                &jobHandle,\n                                JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_QUERY,\n                                jobPageContext->Context\n                                )))\n                            {\n                                status = NtAssignProcessToJobObject(jobHandle, processHandle);\n\n                                if (NT_SUCCESS(status))\n                                {\n                                    ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_PROCESSES));\n                                    PhpAddJobProcesses(hwndDlg, jobHandle);\n                                }\n\n                                NtClose(jobHandle);\n                            }\n\n                            NtClose(processHandle);\n                        }\n\n                        if (NT_SUCCESS(status))\n                            break;\n                        else\n                            PhShowStatus(hwndDlg, L\"Unable to add the process to the job\", status, 0);\n                    }\n                }\n                break;\n            case IDC_ADVANCED:\n                {\n                    PhpShowJobAdvancedProperties(hwndDlg, jobPageContext);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_PROCESSES));\n                return TRUE;\n            }\n\n            PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_PROCESSES), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);\n            PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_LIMITS), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);\n        }\n        break;\n    case WM_SIZE:\n        {\n            ExtendedListView_SetColumnWidth(GetDlgItem(hwndDlg, IDC_PROCESSES), 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            HWND listViewHandle = NULL;\n\n            if ((HWND)wParam == GetDlgItem(hwndDlg, IDC_PROCESSES))\n                listViewHandle = GetDlgItem(hwndDlg, IDC_PROCESSES);\n            else if ((HWND)wParam == GetDlgItem(hwndDlg, IDC_LIMITS))\n                listViewHandle = GetDlgItem(hwndDlg, IDC_LIMITS);\n\n            if (listViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID *listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(listViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(listViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, listViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(listViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhpShowJobAdvancedProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PJOB_PAGE_CONTEXT Context\n    )\n{\n    PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };\n    HPROPSHEETPAGE pages[2];\n    PROPSHEETPAGE statisticsPage;\n\n    propSheetHeader.dwFlags =\n        PSH_NOAPPLYNOW |\n        PSH_NOCONTEXTHELP |\n        PSH_PROPTITLE |\n        PSH_USECALLBACK;\n    propSheetHeader.hInstance = PhInstanceHandle;\n    propSheetHeader.hwndParent = ParentWindowHandle;\n    propSheetHeader.pszCaption = L\"Job\";\n    propSheetHeader.nPages = 2;\n    propSheetHeader.nStartPage = 0;\n    propSheetHeader.phpage = pages;\n    propSheetHeader.pfnCallback = PhpJobStatisticsSheetProc;\n\n    // General\n\n    memset(&statisticsPage, 0, sizeof(PROPSHEETPAGE));\n    statisticsPage.dwSize = sizeof(PROPSHEETPAGE);\n    statisticsPage.pszTemplate = MAKEINTRESOURCE(IDD_JOBSTATISTICS);\n    statisticsPage.hInstance = PhInstanceHandle;\n    statisticsPage.pfnDlgProc = PhpJobStatisticsPageProc;\n    statisticsPage.lParam = (LPARAM)Context;\n    pages[0] = CreatePropertySheetPage(&statisticsPage);\n\n    // Security\n\n    pages[1] = PhCreateSecurityPage(\n        L\"Job\",\n        L\"Job\",\n        Context->OpenObject,\n        NULL,\n        Context->Context\n        );\n\n    PhModalPropertySheet(&propSheetHeader);\n}\n\nstatic VOID PhpRefreshJobStatisticsInfo(\n    _In_ HWND hwndDlg,\n    _In_ PJOB_PAGE_CONTEXT Context\n    )\n{\n    HANDLE jobHandle = NULL;\n    JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION basicAndIo;\n    JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimitInfo;\n\n    Context->OpenObject(\n        &jobHandle,\n        JOB_OBJECT_QUERY,\n        Context->Context\n        );\n\n    if (jobHandle && NT_SUCCESS(PhGetJobBasicAndIoAccounting(\n        jobHandle,\n        &basicAndIo\n        )))\n    {\n        WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1];\n\n        PhSetDialogItemValue(hwndDlg, IDC_ZACTIVEPROCESSES_V, basicAndIo.BasicInfo.ActiveProcesses, FALSE);\n        PhSetDialogItemValue(hwndDlg, IDC_ZTOTALPROCESSES_V, basicAndIo.BasicInfo.TotalProcesses, FALSE);\n        PhSetDialogItemValue(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, basicAndIo.BasicInfo.TotalTerminatedProcesses, FALSE);\n\n        PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalUserTime.QuadPart, PH_TIMESPAN_HMSM);\n        PhSetDialogItemText(hwndDlg, IDC_ZUSERTIME_V, timeSpan);\n        PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalKernelTime.QuadPart, PH_TIMESPAN_HMSM);\n        PhSetDialogItemText(hwndDlg, IDC_ZKERNELTIME_V, timeSpan);\n        PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalUserTime.QuadPart, PH_TIMESPAN_HMSM);\n        PhSetDialogItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, timeSpan);\n        PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalKernelTime.QuadPart, PH_TIMESPAN_HMSM);\n        PhSetDialogItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, timeSpan);\n\n        PhSetDialogItemText(hwndDlg, IDC_ZPAGEFAULTS_V, PhaFormatUInt64(basicAndIo.BasicInfo.TotalPageFaultCount, TRUE)->Buffer);\n\n        PhSetDialogItemText(hwndDlg, IDC_ZIOREADS_V, PhaFormatUInt64(basicAndIo.IoInfo.ReadOperationCount, TRUE)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZIOREADBYTES_V, PhaFormatSize(basicAndIo.IoInfo.ReadTransferCount, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZIOWRITES_V, PhaFormatUInt64(basicAndIo.IoInfo.WriteOperationCount, TRUE)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, PhaFormatSize(basicAndIo.IoInfo.WriteTransferCount, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZIOOTHER_V, PhaFormatUInt64(basicAndIo.IoInfo.OtherOperationCount, TRUE)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, PhaFormatSize(basicAndIo.IoInfo.OtherTransferCount, ULONG_MAX)->Buffer);\n    }\n    else\n    {\n        PhSetDialogItemText(hwndDlg, IDC_ZACTIVEPROCESSES_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZTOTALPROCESSES_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, L\"Unknown\");\n\n        PhSetDialogItemText(hwndDlg, IDC_ZUSERTIME_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZKERNELTIME_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, L\"Unknown\");\n\n        PhSetDialogItemText(hwndDlg, IDC_ZPAGEFAULTS_V, L\"Unknown\");\n\n        PhSetDialogItemText(hwndDlg, IDC_ZIOREADS_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZIOREADBYTES_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZIOWRITES_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZIOOTHER_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, L\"Unknown\");\n    }\n\n    if (jobHandle && NT_SUCCESS(PhGetJobExtendedLimits(\n        jobHandle,\n        &extendedLimitInfo\n        )))\n    {\n        PhSetDialogItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakProcessMemoryUsed, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakJobMemoryUsed, ULONG_MAX)->Buffer);\n    }\n    else\n    {\n        PhSetDialogItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, L\"Unknown\");\n    }\n\n    if (jobHandle)\n        NtClose(jobHandle);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ProcessesUpdatedCallback(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    PostMessage(Context, MSG_UPDATE, 0, 0);\n}\n\nINT_PTR CALLBACK PhpJobStatisticsPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PJOB_PAGE_CONTEXT jobPageContext;\n\n    jobPageContext = PhpJobPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!jobPageContext)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); // HACK\n\n            PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n                ProcessesUpdatedCallback,\n                hwndDlg,\n                &jobPageContext->ProcessesUpdatedRegistration\n                );\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhUnregisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n                &jobPageContext->ProcessesUpdatedRegistration\n                );\n        }\n        break;\n    case MSG_UPDATE:\n        {\n            PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nINT CALLBACK PhpJobStatisticsSheetProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ LPARAM lParam\n    )\n{\n    if (uMsg == PSCB_INITIALIZED && PhEnableThemeSupport)\n    {\n        PhInitializeWindowTheme(hwndDlg, TRUE);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "SystemInformer/kdump.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2019-2022\n *\n */\n\n#include <phapp.h>\n\ntypedef struct _PH_LIVE_DUMP_CONFIG\n{\n    HWND WindowHandle;\n    PPH_STRING FileName;\n    NTSTATUS LastStatus;\n    BOOLEAN KernelDumpActive;\n    PH_LIVE_DUMP_OPTIONS Options;\n    HANDLE FileHandle;\n    HANDLE EventHandle;\n} PH_LIVE_DUMP_CONFIG, *PPH_LIVE_DUMP_CONFIG;\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpCreateLiveKernelDump(\n    _In_ PPH_LIVE_DUMP_CONFIG Context\n    )\n{\n    NTSTATUS status;\n    SYSDBG_LIVEDUMP_CONTROL liveDumpControl;\n    SYSDBG_LIVEDUMP_CONTROL_FLAGS flags;\n    SYSDBG_LIVEDUMP_CONTROL_ADDPAGES pages;\n    SYSDBG_LIVEDUMP_SELECTIVE_CONTROL selective;\n    ULONG length;\n\n    memset(&liveDumpControl, 0, sizeof(SYSDBG_LIVEDUMP_CONTROL));\n    memset(&flags, 0, sizeof(SYSDBG_LIVEDUMP_CONTROL_FLAGS));\n    memset(&pages, 0, sizeof(SYSDBG_LIVEDUMP_CONTROL_ADDPAGES));\n    memset(&selective, 0, sizeof(SYSDBG_LIVEDUMP_SELECTIVE_CONTROL));\n\n    if (Context->Options.UseDumpStorageStack)\n        flags.UseDumpStorageStack = TRUE;\n    if (Context->Options.CompressMemoryPages)\n        flags.CompressMemoryPagesData = TRUE;\n    if (Context->Options.IncludeUserSpaceMemory)\n        flags.IncludeUserSpaceMemoryPages = TRUE;\n    if (Context->Options.IncludeHypervisorPages)\n        pages.HypervisorPages = TRUE;\n    if (Context->Options.IncludeNonEssentialHypervisorPages)\n        pages.NonEssentialHypervisorPages = TRUE;\n\n    if (Context->Options.OnlyKernelThreadStacks)\n    {\n        liveDumpControl.Version = SYSDBG_LIVEDUMP_CONTROL_VERSION_2;\n        flags.SelectiveDump = TRUE;\n        length = sizeof(SYSDBG_LIVEDUMP_CONTROL);\n\n        selective.Version = SYSDBG_LIVEDUMP_SELECTIVE_CONTROL_VERSION;\n        selective.Size = sizeof(SYSDBG_LIVEDUMP_SELECTIVE_CONTROL);\n        selective.ThreadKernelStacks = TRUE;\n\n        liveDumpControl.SelectiveControl = &selective;\n    }\n    else\n    {\n        liveDumpControl.Version = SYSDBG_LIVEDUMP_CONTROL_VERSION_1;\n        length = sizeof(SYSDBG_LIVEDUMP_CONTROL_V1);\n    }\n\n    liveDumpControl.DumpFileHandle = Context->FileHandle;\n    liveDumpControl.CancelEventHandle = Context->EventHandle;\n    liveDumpControl.Flags = flags;\n    liveDumpControl.AddPagesControl = pages;\n\n    status = NtSystemDebugControl(\n        SysDbgGetLiveKernelDump,\n        &liveDumpControl,\n        length,\n        NULL,\n        0,\n        NULL\n        );\n\n    Context->LastStatus = status;\n    Context->KernelDumpActive = FALSE;\n\n    PostMessage(Context->WindowHandle, TDM_CLICK_BUTTON, IDIGNORE, 0);\n\n    return status;\n}\n\nHRESULT CALLBACK PhpLiveDumpPageCallbackProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR dwRefData\n    )\n{\n    return S_OK;\n}\n\nHRESULT CALLBACK PhpLiveDumpProgressDialogCallbackProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR dwRefData\n    )\n{\n    PPH_LIVE_DUMP_CONFIG context = (PPH_LIVE_DUMP_CONFIG)dwRefData;\n\n    switch (uMsg)\n    {\n    case TDN_DIALOG_CONSTRUCTED:\n        {\n            SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n            SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n\n            context->WindowHandle = hwndDlg;\n            context->KernelDumpActive = TRUE;\n            context->LastStatus = STATUS_SUCCESS;\n\n            PhCreateEvent(\n                &context->EventHandle,\n                EVENT_ALL_ACCESS,\n                SynchronizationEvent,\n                FALSE\n                );\n\n            PhCreateThread2(PhpCreateLiveKernelDump, context);\n        }\n        break;\n    case TDN_TIMER:\n        {\n            LARGE_INTEGER fileSize;\n\n            if (NT_SUCCESS(PhGetFileSize(context->FileHandle, &fileSize)))\n            {\n                PH_FORMAT format[2];\n                WCHAR string[MAX_PATH];\n\n                if (fileSize.QuadPart)\n                {\n                    PhInitFormatS(&format[0], L\"Size: \");\n                    PhInitFormatSize(&format[1], fileSize.QuadPart);\n\n                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), string, sizeof(string), NULL))\n                    {\n                        SendMessage(context->WindowHandle, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)string);\n                    }\n                }\n                else\n                {\n                    PhInitFormatS(&format[0], L\"Initializing...\");\n\n                    if (PhFormatToBuffer(format, 1, string, sizeof(string), NULL))\n                    {\n                        SendMessage(context->WindowHandle, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)string);\n                    }\n                }\n            }\n            else\n            {\n                SendMessage(context->WindowHandle, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)L\" \");\n            }\n        }\n        break;\n    case TDN_BUTTON_CLICKED:\n        {\n            ULONG buttonId = (ULONG)wParam;\n\n            if (buttonId == IDIGNORE)\n            {\n                PPH_STRING statusMessage = NULL;\n                TASKDIALOGCONFIG config;\n\n                if (context->FileHandle)\n                {\n                    if (!NT_SUCCESS(context->LastStatus))\n                        PhSetFileDelete(context->FileHandle);\n\n                    NtClose(context->FileHandle);\n                    context->FileHandle = NULL;\n                }\n\n                memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n                config.cbSize = sizeof(TASKDIALOGCONFIG);\n\n                if (NT_SUCCESS(context->LastStatus))\n                {\n                    config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED;\n                    config.hMainIcon = PhGetApplicationIcon(FALSE);\n                    config.dwCommonButtons = TDCBF_CLOSE_BUTTON;\n                    config.pfCallback = PhpLiveDumpPageCallbackProc;\n                    config.lpCallbackData = (LONG_PTR)context;\n                    config.pszWindowTitle = PhApplicationName;\n                    config.pszMainInstruction = L\"Live kernel dump has been created.\";\n                    config.pszContent = PhGetString(context->FileName);\n                }\n                else\n                {\n                    config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED;\n                    config.hMainIcon = PhGetApplicationIcon(FALSE);\n                    config.dwCommonButtons = TDCBF_CLOSE_BUTTON;\n                    config.pfCallback = PhpLiveDumpPageCallbackProc;\n                    config.lpCallbackData = (LONG_PTR)context;\n                    config.pszWindowTitle = PhApplicationName;\n                    config.pszMainInstruction = L\"Unable to save the live kernel dump.\";\n\n                    statusMessage = PhGetStatusMessage(context->LastStatus, 0);\n                    config.pszContent = PhGetString(statusMessage);\n                }\n\n                PhTaskDialogNavigatePage(context->WindowHandle, &config);\n\n                if (statusMessage)\n                    PhDereferenceObject(statusMessage);\n\n                return S_FALSE;\n            }\n\n            if (context->KernelDumpActive)\n            {\n                if (context->EventHandle)\n                    NtSetEvent(context->EventHandle, NULL);\n\n                return S_FALSE;\n            }\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpLiveDumpTaskDialogThread(\n    _In_ PVOID ThreadParameter\n    )\n{\n    PPH_LIVE_DUMP_CONFIG context = (PPH_LIVE_DUMP_CONFIG)ThreadParameter;\n    NTSTATUS status;\n    TASKDIALOGCONFIG config;\n\n    status = PhCreateFileWin32(\n        &context->FileHandle,\n        PhGetString(context->FileName),\n        FILE_ALL_ACCESS,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(NULL, L\"Unable to save the live kernel dump.\", status, 0);\n        return status;\n    }\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CALLBACK_TIMER | TDF_CAN_BE_MINIMIZED;\n    config.hMainIcon = PhGetApplicationIcon(FALSE);\n    config.dwCommonButtons = TDCBF_CANCEL_BUTTON;\n    config.pfCallback = PhpLiveDumpProgressDialogCallbackProc;\n    config.lpCallbackData = (LONG_PTR)context;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainInstruction = L\"Processing live kernel dump...\";\n    config.pszContent = L\" \";\n    config.cxWidth = 200;\n\n    PhShowTaskDialog(&config, NULL, NULL, NULL);\n\n    if (context->EventHandle)\n        NtClose(context->EventHandle);\n    if (context->FileName)\n        PhDereferenceObject(context->FileName);\n\n    PhFree(context);\n\n    return STATUS_SUCCESS;\n}\n\nPPH_STRING PhpLiveDumpFileDialogFileName(\n    _In_ HWND WindowHandle\n    )\n{\n    static PH_FILETYPE_FILTER filters[] =\n    {\n        { L\"Dump files (*.dmp)\", L\"*.dmp\" },\n        { L\"All files (*.*)\", L\"*.*\" }\n    };\n    PPH_STRING fileName = NULL;\n    PVOID fileDialog;\n    LARGE_INTEGER time;\n    SYSTEMTIME systemTime;\n    PPH_STRING dateString;\n    PPH_STRING timeString;\n    PPH_STRING suggestedFileName;\n\n    PhQuerySystemTime(&time);\n    PhLargeIntegerToLocalSystemTime(&systemTime, &time);\n    dateString = PH_AUTO_T(PH_STRING, PhFormatDate(&systemTime, L\"yyyy-MM-dd\"));\n    timeString = PH_AUTO_T(PH_STRING, PhFormatTime(&systemTime, L\"HH-mm-ss\"));\n    suggestedFileName = PH_AUTO_T(PH_STRING, PhFormatString(\n        L\"%s_%s_%s.dmp\",\n        L\"kerneldump\",\n        PhGetString(dateString),\n        PhGetString(timeString)\n        ));\n\n    if (fileDialog = PhCreateSaveFileDialog())\n    {\n        PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters));\n        PhSetFileDialogFileName(fileDialog, PhGetString(suggestedFileName));\n        PhSetFileDialogOptions(fileDialog, PH_FILEDIALOG_DONTADDTORECENT);\n\n        if (PhShowFileDialog(WindowHandle, fileDialog))\n        {\n            fileName = PhGetFileDialogFileName(fileDialog);\n        }\n\n        PhFreeFileDialog(fileDialog);\n    }\n\n    return fileName;\n}\n\nVOID PhUiCreateLiveDump(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_LIVE_DUMP_OPTIONS Options\n    )\n{\n    PPH_LIVE_DUMP_CONFIG dumpConfig;\n\n    dumpConfig = PhAllocateZero(sizeof(PH_LIVE_DUMP_CONFIG));\n    dumpConfig->Options = *Options;\n    dumpConfig->FileName = PhpLiveDumpFileDialogFileName(ParentWindowHandle);\n\n    if (!PhIsNullOrEmptyString(dumpConfig->FileName))\n    {\n        PhCreateThread2(PhpLiveDumpTaskDialogThread, dumpConfig);\n    }\n    else\n    {\n        if (dumpConfig->FileName)\n            PhDereferenceObject(dumpConfig->FileName);\n        PhFree(dumpConfig);\n    }\n}\n\nINT_PTR CALLBACK PhpLiveDumpDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhCenterWindow(hwndDlg, NULL);\n\n            if (!PhGetOwnTokenAttributes().Elevated)\n            {\n                Button_SetElevationRequiredState(GetDlgItem(hwndDlg, IDOK), TRUE);\n            }\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    PH_LIVE_DUMP_OPTIONS options;\n\n                    if (!PhGetOwnTokenAttributes().Elevated)\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to create live kernel dump.\", 0, ERROR_ELEVATION_REQUIRED);\n                        break;\n                    }\n\n                    memset(&options, 0, sizeof(PH_LIVE_DUMP_OPTIONS));\n\n                    options.CompressMemoryPages = Button_GetCheck(GetDlgItem(hwndDlg, IDC_COMPRESS)) == BST_CHECKED;\n                    options.IncludeUserSpaceMemory = Button_GetCheck(GetDlgItem(hwndDlg, IDC_USERMODE)) == BST_CHECKED;\n                    options.IncludeHypervisorPages = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HYPERVISOR)) == BST_CHECKED;\n                    options.OnlyKernelThreadStacks = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ONLYKERNELTHREADSTACKS)) == BST_CHECKED;\n                    options.UseDumpStorageStack = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DUMPSTACK)) == BST_CHECKED;\n                    options.IncludeNonEssentialHypervisorPages = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HYPERVISORNONESSENTIAL)) == BST_CHECKED;\n\n                    PhUiCreateLiveDump(hwndDlg, &options);\n\n                    EndDialog(hwndDlg, IDCANCEL);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhShowLiveDumpDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_LIVEDUMP),\n        ParentWindowHandle,\n        PhpLiveDumpDlgProc,\n        NULL\n        );\n}\n"
  },
  {
    "path": "SystemInformer/ksidbg.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023\n *\n */\n\n#include <phapp.h>\n#include <kphuser.h>\n#include <kphcomms.h>\n#include <kphmsgdyn.h>\n#include <informer.h>\n#include <dpfilter.h>\n\n#include <trace.h>\n\n#ifdef DEBUG\n\ntypedef _Function_class_(KSI_DEBUG_LOG_GET_LOG_STRING)\nPPH_STRING KSI_DEBUG_LOG_GET_LOG_STRING(\n    _In_ PCKPH_MESSAGE Message\n    );\ntypedef KSI_DEBUG_LOG_GET_LOG_STRING* PKSI_DEBUG_LOG_GET_LOG_STRING;\n\ntypedef struct _KSI_DEBUG_LOG_DEF\n{\n    PH_STRINGREF Name;\n    PKSI_DEBUG_LOG_GET_LOG_STRING GetLogString;\n} SI_DEBUG_LOG_DEF, *PSI_DEBUG_LOG_DEF;\n\nstatic BOOLEAN KsiDebugLogEnabled = FALSE;\nstatic PH_FAST_LOCK KsiDebugLogFileStreamLock = PH_FAST_LOCK_INIT;\nstatic PPH_FILE_STREAM KsiDebugLogFileStream = NULL;\nstatic CONST PH_STRINGREF KsiDebugLogSuffix = PH_STRINGREF_INIT(L\"\\\\Desktop\\\\ksidbg.log\");\n\nstatic BOOLEAN KsiDebugRawEnabled = FALSE;\nstatic PH_FAST_LOCK KsiDebugRawFileStreamLock = PH_FAST_LOCK_INIT;\nstatic PPH_FILE_STREAM KsiDebugRawFileStream = NULL;\nstatic CONST PH_STRINGREF KsiDebugRawSuffix = PH_STRINGREF_INIT(L\"\\\\Desktop\\\\ksidbg.bin\");\n\nstatic PH_CALLBACK_REGISTRATION KsiDebugMessageRegistration = { NULL };\n\nPPH_STRING KsiDebugLogProcessCreate(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING fileName;\n    UNICODE_STRING commandLine;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldFileName, &fileName);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldCommandLine, &commandLine);\n\n    return PhFormatString(\n        L\"%04x:%04x:%016llx created process %lu (%016llx)%ls(parent %lu (%016llx)) \\\"%wZ\\\" \\\"%wZ\\\"\",\n        HandleToUlong(Message->Kernel.ProcessCreate.CreatingClientId.UniqueProcess),\n        HandleToUlong(Message->Kernel.ProcessCreate.CreatingClientId.UniqueThread),\n        Message->Kernel.ProcessCreate.CreatingProcessStartKey,\n        HandleToUlong(Message->Kernel.ProcessCreate.TargetProcessId),\n        Message->Kernel.ProcessCreate.TargetProcessStartKey,\n        Message->Kernel.ProcessCreate.IsSubsystemProcess ? L\" subsystem process \" : L\" \",\n        HandleToUlong(Message->Kernel.ProcessCreate.ParentProcessId),\n        Message->Kernel.ProcessCreate.ParentProcessStartKey,\n        &fileName,\n        &commandLine\n        );\n}\n\nPPH_STRING KsiDebugLogProcessExit(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    PPH_STRING result;\n    PPH_STRING statusMessage;\n\n    statusMessage = PhGetStatusMessage(Message->Kernel.ProcessExit.ExitStatus, 0);\n\n    result = PhFormatString(\n        L\"%04x:%04x:%016llx process exited with %ls (0x%08x)\",\n        HandleToUlong(Message->Kernel.ProcessExit.ClientId.UniqueProcess),\n        HandleToUlong(Message->Kernel.ProcessExit.ClientId.UniqueThread),\n        Message->Kernel.ProcessExit.ProcessStartKey,\n        PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n        Message->Kernel.ProcessExit.ExitStatus\n        );\n\n    PhMoveReference(&statusMessage, NULL);\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogThreadCreate(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    return PhFormatString(\n        L\"%04x:%04x:%016llx thread %lu created in process %lu (%016llx)\",\n        HandleToUlong(Message->Kernel.ThreadCreate.CreatingClientId.UniqueProcess),\n        HandleToUlong(Message->Kernel.ThreadCreate.CreatingClientId.UniqueThread),\n        Message->Kernel.ThreadCreate.CreatingProcessStartKey,\n        HandleToUlong(Message->Kernel.ThreadCreate.TargetClientId.UniqueThread),\n        HandleToUlong(Message->Kernel.ThreadCreate.TargetClientId.UniqueProcess),\n        Message->Kernel.ThreadCreate.TargetProcessStartKey\n        );\n}\n\nPPH_STRING KsiDebugLogThreadExecute(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    return PhFormatString(\n        L\"%04x:%04x:%016llx thread beginning execution\",\n        HandleToUlong(Message->Kernel.ThreadExecute.ClientId.UniqueThread),\n        HandleToUlong(Message->Kernel.ThreadExecute.ClientId.UniqueProcess),\n        Message->Kernel.ThreadExecute.ProcessStartKey\n        );\n}\n\nPPH_STRING KsiDebugLogThreadExit(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    PPH_STRING result;\n    PPH_STRING statusMessage;\n\n    statusMessage = PhGetStatusMessage(Message->Kernel.ThreadExit.ExitStatus, 0);\n\n    result = PhFormatString(\n        L\"%04x:%04x:%016llx thread exited with %ls (0x%08x)\",\n        HandleToUlong(Message->Kernel.ThreadExit.ClientId.UniqueThread),\n        HandleToUlong(Message->Kernel.ThreadExit.ClientId.UniqueProcess),\n        Message->Kernel.ThreadExit.ProcessStartKey,\n        PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n        Message->Kernel.ThreadExit.ExitStatus\n        );\n\n    PhMoveReference(&statusMessage, NULL);\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogImageLoad(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING fileName;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldFileName, &fileName);\n\n    return PhFormatString(\n        L\"%04x:%04x:%016llx image \\\"%wZ\\\" loaded into process %lu (%016llx) at %p\",\n        HandleToUlong(Message->Kernel.ImageLoad.LoadingClientId.UniqueProcess),\n        HandleToUlong(Message->Kernel.ImageLoad.LoadingClientId.UniqueThread),\n        Message->Kernel.ImageLoad.LoadingProcessStartKey,\n        &fileName,\n        HandleToUlong(Message->Kernel.ImageLoad.TargetProcessId),\n        Message->Kernel.ImageLoad.TargetProcessStartKey,\n        Message->Kernel.ImageLoad.ImageBase\n        );\n}\n\nPPH_STRING KsiDebugLogDebugPrint(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    ANSI_STRING output;\n\n    KphMsgDynGetAnsiString(Message, KphMsgFieldOutput, &output);\n\n    while (output.Length > 0)\n    {\n        CHAR c = output.Buffer[output.Length - 1];\n        if (c != '\\r' && c != '\\n')\n            break;\n        output.Length--;\n    }\n\n    return PhFormatString(\n        L\"%04x:%04x 0x%08x 0x%08x\\r\\n%hZ\",\n        HandleToUlong(Message->Kernel.DebugPrint.ContextClientId.UniqueProcess),\n        HandleToUlong(Message->Kernel.DebugPrint.ContextClientId.UniqueThread),\n        Message->Kernel.DebugPrint.ComponentId,\n        Message->Kernel.DebugPrint.Level,\n        &output\n        );\n}\n\nPPH_STRING KsiDebugLogHandleProcess(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    PPH_STRING result;\n\n    if (Message->Kernel.Handle.PostOperation)\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.Handle.Post.ReturnStatus, 0);\n\n        if (Message->Kernel.Handle.Duplicate)\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu granted 0x%08x (desired 0x%08x, original 0x%08x) to process %lu (duplicate %lu -> %lu) %llu %llu %ls (0x%08x)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Post.GrantedAccess,\n                Message->Kernel.Handle.Post.DesiredAccess,\n                Message->Kernel.Handle.Post.OriginalDesiredAccess,\n                HandleToUlong(Message->Kernel.Handle.Post.Duplicate.Process.ProcessId),\n                HandleToUlong(Message->Kernel.Handle.Post.Duplicate.SourceProcessId),\n                HandleToUlong(Message->Kernel.Handle.Post.Duplicate.TargetProcessId),\n                Message->Kernel.Handle.Post.PreSequence,\n                (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Handle.Post.PreTimeStamp.QuadPart),\n                PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n                Message->Kernel.Handle.Post.ReturnStatus\n                );\n        }\n        else\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu granted 0x%08x (desired 0x%08x, original 0x%08x) to process %lu %llu %llu %ls (0x%08x)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Post.GrantedAccess,\n                Message->Kernel.Handle.Post.DesiredAccess,\n                Message->Kernel.Handle.Post.OriginalDesiredAccess,\n                HandleToUlong(Message->Kernel.Handle.Post.Create.Process.ProcessId),\n                Message->Kernel.Handle.Post.PreSequence,\n                (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Handle.Post.PreTimeStamp.QuadPart),\n                PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n                Message->Kernel.Handle.Post.ReturnStatus\n                );\n        }\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        if (Message->Kernel.Handle.Duplicate)\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p desires 0x%08x (original 0x%08x) to process %lu (duplicate %lu -> %lu)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Pre.DesiredAccess,\n                Message->Kernel.Handle.Pre.OriginalDesiredAccess,\n                HandleToUlong(Message->Kernel.Handle.Pre.Duplicate.Process.ProcessId),\n                HandleToUlong(Message->Kernel.Handle.Pre.Duplicate.SourceProcessId),\n                HandleToUlong(Message->Kernel.Handle.Pre.Duplicate.TargetProcessId)\n                );\n        }\n        else\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p desires 0x%08x (original 0x%08x) to process %lu\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Pre.DesiredAccess,\n                Message->Kernel.Handle.Pre.OriginalDesiredAccess,\n                HandleToUlong(Message->Kernel.Handle.Pre.Create.Process.ProcessId)\n                );\n        }\n    }\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogHandleThread(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    PPH_STRING result;\n\n    if (Message->Kernel.Handle.PostOperation)\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.Handle.Post.ReturnStatus, 0);\n\n        if (Message->Kernel.Handle.Duplicate)\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu granted 0x%08x (desired 0x%08x, original 0x%08x) to thread %lu (process %lu, duplicate %lu -> %lu) %llu %llu %ls (0x%08x)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Post.GrantedAccess,\n                Message->Kernel.Handle.Post.DesiredAccess,\n                Message->Kernel.Handle.Post.OriginalDesiredAccess,\n                HandleToUlong(Message->Kernel.Handle.Post.Duplicate.Thread.ClientId.UniqueThread),\n                HandleToUlong(Message->Kernel.Handle.Post.Duplicate.Thread.ClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.Post.Duplicate.SourceProcessId),\n                HandleToUlong(Message->Kernel.Handle.Post.Duplicate.TargetProcessId),\n                Message->Kernel.Handle.Post.PreSequence,\n                (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Handle.Post.PreTimeStamp.QuadPart),\n                PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n                Message->Kernel.Handle.Post.ReturnStatus\n                );\n        }\n        else\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu granted 0x%08x (desired 0x%08x, original 0x%08x) to thread %lu (process %lu) %llu %llu %ls (0x%08x)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Post.GrantedAccess,\n                Message->Kernel.Handle.Post.DesiredAccess,\n                Message->Kernel.Handle.Post.OriginalDesiredAccess,\n                HandleToUlong(Message->Kernel.Handle.Post.Create.Thread.ClientId.UniqueThread),\n                HandleToUlong(Message->Kernel.Handle.Post.Create.Thread.ClientId.UniqueProcess),\n                Message->Kernel.Handle.Post.PreSequence,\n                (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Handle.Post.PreTimeStamp.QuadPart),\n                PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n                Message->Kernel.Handle.Post.ReturnStatus\n                );\n        }\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        if (Message->Kernel.Handle.Duplicate)\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu desires 0x%08x (original 0x%08x) to thread %lu (process %lu, duplicate %lu -> %lu)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Pre.DesiredAccess,\n                Message->Kernel.Handle.Pre.OriginalDesiredAccess,\n                HandleToUlong(Message->Kernel.Handle.Pre.Duplicate.Thread.ClientId.UniqueThread),\n                HandleToUlong(Message->Kernel.Handle.Pre.Duplicate.Thread.ClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.Pre.Duplicate.SourceProcessId),\n                HandleToUlong(Message->Kernel.Handle.Pre.Duplicate.TargetProcessId)\n                );\n        }\n        else\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu desires 0x%08x (original 0x%08x) to thread %lu (process %lu)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Pre.DesiredAccess,\n                Message->Kernel.Handle.Pre.OriginalDesiredAccess,\n                HandleToUlong(Message->Kernel.Handle.Pre.Create.Thread.ClientId.UniqueThread),\n                HandleToUlong(Message->Kernel.Handle.Pre.Create.Thread.ClientId.UniqueProcess)\n                );\n        }\n    }\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogHandleDesktop(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    PPH_STRING result;\n    UNICODE_STRING objectName;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldObjectName, &objectName);\n\n    if (Message->Kernel.Handle.PostOperation)\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.Handle.Post.ReturnStatus, 0);\n\n        if (Message->Kernel.Handle.Duplicate)\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu granted 0x%08x (desired 0x%08x, original 0x%08x) to desktop \\\"%wZ\\\" (duplicate %lu -> %lu) %llu %llu %ls (0x%08x)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Post.GrantedAccess,\n                Message->Kernel.Handle.Post.DesiredAccess,\n                Message->Kernel.Handle.Post.OriginalDesiredAccess,\n                &objectName,\n                HandleToUlong(Message->Kernel.Handle.Post.Duplicate.SourceProcessId),\n                HandleToUlong(Message->Kernel.Handle.Post.Duplicate.TargetProcessId),\n                Message->Kernel.Handle.Post.PreSequence,\n                (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Handle.Post.PreTimeStamp.QuadPart),\n                PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n                Message->Kernel.Handle.Post.ReturnStatus\n                );\n        }\n        else\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu granted 0x%08x (desired 0x%08x, original 0x%08x) to desktop \\\"%wZ\\\" %llu %llu %ls (0x%08x)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Post.GrantedAccess,\n                Message->Kernel.Handle.Post.DesiredAccess,\n                Message->Kernel.Handle.Post.OriginalDesiredAccess,\n                &objectName,\n                Message->Kernel.Handle.Post.PreSequence,\n                (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Handle.Post.PreTimeStamp.QuadPart),\n                PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n                Message->Kernel.Handle.Post.ReturnStatus\n                );\n        }\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        if (Message->Kernel.Handle.Duplicate)\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu desires 0x%08x (original 0x%08x) to desktop \\\"%wZ\\\" (duplicate %lu -> %lu)\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Pre.DesiredAccess,\n                Message->Kernel.Handle.Pre.OriginalDesiredAccess,\n                &objectName,\n                HandleToUlong(Message->Kernel.Handle.Pre.Duplicate.SourceProcessId),\n                HandleToUlong(Message->Kernel.Handle.Pre.Duplicate.TargetProcessId)\n                );\n        }\n        else\n        {\n            result = PhFormatString(\n                L\"%04x:%04x:%016llx %c %p %llu desires 0x%08x (original 0x%08x) to desktop \\\"%wZ\\\"\",\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueProcess),\n                HandleToUlong(Message->Kernel.Handle.ContextClientId.UniqueThread),\n                Message->Kernel.Handle.ContextProcessStartKey,\n                (Message->Kernel.Handle.KernelHandle ? 'K' : 'U'),\n                Message->Kernel.Handle.Object,\n                Message->Kernel.Handle.Sequence,\n                Message->Kernel.Handle.Pre.DesiredAccess,\n                Message->Kernel.Handle.Pre.OriginalDesiredAccess,\n                &objectName\n                );\n        }\n    }\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogRequiredStateFailure(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    return PhFormatString(\n        L\"%04x:%04x required state failure, message %lu, state 0x%08x, required 0x%08x\",\n        HandleToUlong(Message->Kernel.RequiredStateFailure.ClientId.UniqueProcess),\n        HandleToUlong(Message->Kernel.RequiredStateFailure.ClientId.UniqueThread),\n        (ULONG)Message->Kernel.RequiredStateFailure.MessageId,\n        Message->Kernel.RequiredStateFailure.ClientState,\n        Message->Kernel.RequiredStateFailure.RequiredState\n        );\n}\n\nPPH_STRING KsiDebugLogFileCommon(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING fileName;\n    PPH_STRING result;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldFileName, &fileName);\n\n    if (FlagOn(Message->Kernel.File.FltFlags, FLTFL_CALLBACK_DATA_POST_OPERATION))\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.File.Post.IoStatus.Status, 0);\n\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %lu %p %llu \\\"%wZ\\\" %llu %llu %ls (0x%08x)\",\n            HandleToUlong(Message->Kernel.File.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.File.ClientId.UniqueThread),\n            Message->Kernel.File.ProcessStartKey,\n            (ULONG)Message->Kernel.File.Irql,\n            Message->Kernel.File.FileObject,\n            Message->Kernel.File.Sequence,\n            &fileName,\n            (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.File.Post.PreTimeStamp.QuadPart),\n            Message->Kernel.File.Post.PreSequence,\n            PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n            Message->Kernel.File.Post.IoStatus.Status\n            );\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %lu %p %llu \\\"%wZ\\\"\",\n            HandleToUlong(Message->Kernel.File.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.File.ClientId.UniqueThread),\n            Message->Kernel.File.ProcessStartKey,\n            (ULONG)Message->Kernel.File.Irql,\n            Message->Kernel.File.FileObject,\n            Message->Kernel.File.Sequence,\n            &fileName\n            );\n    }\n\n    if (Message->Kernel.File.IsPagingFile)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", paging file\"));\n\n    if (Message->Kernel.File.IsSystemPagingFile)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", system paging file\"));\n\n    if (Message->Kernel.File.OriginRemote)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", remote origin\"));\n\n    if (Message->Kernel.File.IgnoringSharing)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", ignoring sharing\"));\n\n    if (Message->Kernel.File.InStackFileObject)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", in stack file object\"));\n\n    if (Message->Kernel.File.DeletePending)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", delete pending\"));\n\n    if (!Message->Kernel.File.SharedRead && !Message->Kernel.File.SharedWrite && !Message->Kernel.File.SharedDelete)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", opened exclusively\"));\n\n    if (Message->Kernel.File.Busy)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", busy\"));\n\n    if (Message->Kernel.File.Waiters)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", waiters\"));\n\n    if (Message->Kernel.File.OplockKeyContext.Version)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", oplock key\"));\n\n    if (Message->Kernel.File.Transaction)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", transaction\"));\n\n    if (Message->Kernel.File.DataSectionObject)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", data section\"));\n\n    if (Message->Kernel.File.ImageSectionObject)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", image section\"));\n\n    if (Message->Kernel.File.OpenedAsCopySource)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", copy source\"));\n\n    if (Message->Kernel.File.OpenedAsCopyDestination)\n        PhMoveReference(&result, PhConcatStringRefZ(&result->sr, L\", copy destination\"));\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogRegCommon(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING objectName;\n    PPH_STRING result;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldObjectName, &objectName);\n\n    if (Message->Kernel.Reg.PostOperation)\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.Reg.Post.Status, 0);\n\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" %llu %llu %ls (0x%08x)\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName,\n            (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Reg.Post.PreTimeStamp.QuadPart),\n            Message->Kernel.Reg.Post.PreSequence,\n            PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n            Message->Kernel.Reg.Post.Status\n            );\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\"\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName\n            );\n    }\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogRegCommonWithValue(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING objectName;\n    UNICODE_STRING valueName;\n    PPH_STRING result;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldObjectName, &objectName);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldValueName, &valueName);\n\n    if (Message->Kernel.Reg.PostOperation)\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.Reg.Post.Status, 0);\n\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" \\\"%wZ\\\" %llu %llu %ls (0x%08x)\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName,\n            &valueName,\n            (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Reg.Post.PreTimeStamp.QuadPart),\n            Message->Kernel.Reg.Post.PreSequence,\n            PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n            Message->Kernel.Reg.Post.Status\n            );\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" \\\"%wZ\\\"\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName,\n            &valueName\n            );\n    }\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogRegCommonWithMultipleValues(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING objectName;\n    UNICODE_STRING valueNames;\n    PPH_STRING values;\n    PPH_STRING result;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldObjectName, &objectName);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldMultipleValueNames, &valueNames);\n\n    values = NULL;\n    if (valueNames.Length)\n    {\n        PH_STRING_BUILDER stringBuilder;\n\n        PhInitializeStringBuilder(&stringBuilder, 100);\n\n        for (;;)\n        {\n            PH_STRINGREF sr;\n\n            PhInitializeStringRef(&sr, valueNames.Buffer);\n\n            if (!sr.Length)\n            {\n                break;\n            }\n\n            PhAppendStringBuilder2(&stringBuilder, L\"\\\"\");\n            PhAppendStringBuilder(&stringBuilder, &sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\\", \");\n\n            valueNames.Buffer = PTR_ADD_OFFSET(valueNames.Buffer, sr.Length + sizeof(WCHAR));\n            valueNames.Length -= (USHORT)(sr.Length + sizeof(WCHAR));\n            valueNames.MaximumLength -= (USHORT)(sr.Length + sizeof(WCHAR));\n        }\n\n        if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n            PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n        values = PhFinalStringBuilderString(&stringBuilder);\n    }\n\n    if (Message->Kernel.Reg.PostOperation)\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.Reg.Post.Status, 0);\n\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" %ls %llu %llu %ls (0x%08x)\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName,\n            PhGetStringOrDefault(values, L\"NULL\"),\n            (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Reg.Post.PreTimeStamp.QuadPart),\n            Message->Kernel.Reg.Post.PreSequence,\n            PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n            Message->Kernel.Reg.Post.Status\n            );\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" %ls\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName,\n            PhGetStringOrDefault(values, L\"NULL\")\n            );\n    }\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogRegSaveRestoreKey(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING objectName;\n    UNICODE_STRING fileName;\n    PPH_STRING result;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldObjectName, &objectName);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldFileName, &fileName);\n\n    if (Message->Kernel.Reg.PostOperation)\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.Reg.Post.Status, 0);\n\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" \\\"%wZ\\\" %llu %llu %ls (0x%08x)\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName,\n            &fileName,\n            (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Reg.Post.PreTimeStamp.QuadPart),\n            Message->Kernel.Reg.Post.PreSequence,\n            PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n            Message->Kernel.Reg.Post.Status\n            );\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" \\\"%wZ\\\"\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName,\n            &fileName\n            );\n    }\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogRegReplaceKey(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING objectName;\n    UNICODE_STRING fileName;\n    UNICODE_STRING destFileName;\n    PPH_STRING result;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldObjectName, &objectName);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldFileName, &fileName);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldDestinationFileName, &destFileName);\n\n    if (Message->Kernel.Reg.PostOperation)\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.Reg.Post.Status, 0);\n\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" -> \\\"%wZ\\\" -> \\\"%wZ\\\" %llu %llu %ls (0x%08x)\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &fileName,\n            &objectName,\n            &destFileName,\n            (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Reg.Post.PreTimeStamp.QuadPart),\n            Message->Kernel.Reg.Post.PreSequence,\n            PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n            Message->Kernel.Reg.Post.Status\n            );\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" -> \\\"%wZ\\\" -> \\\"%wZ\\\"\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &fileName,\n            &objectName,\n            &destFileName\n            );\n    }\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogSaveMergedKey(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING objectName;\n    UNICODE_STRING otherObjectName;\n    UNICODE_STRING fileName;\n    PPH_STRING result;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldObjectName, &objectName);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldOtherObjectName, &otherObjectName);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldFileName, &fileName);\n\n    if (Message->Kernel.Reg.PostOperation)\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Message->Kernel.Reg.Post.Status, 0);\n\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" + \\\"%wZ\\\" -> \\\"%wZ\\\" %llu %llu %ls (0x%08x)\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName,\n            &otherObjectName,\n            &fileName,\n            (ULONG64)(Message->Header.TimeStamp.QuadPart - Message->Kernel.Reg.Post.PreTimeStamp.QuadPart),\n            Message->Kernel.Reg.Post.PreSequence,\n            PhGetStringOrDefault(statusMessage, L\"UNKNOWN\"),\n            Message->Kernel.Reg.Post.Status\n            );\n\n        PhClearReference(&statusMessage);\n    }\n    else\n    {\n        result = PhFormatString(\n            L\"%04x:%04x:%016llx %c %p %llu \\\"%wZ\\\" + \\\"%wZ\\\" -> \\\"%wZ\\\"\",\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueProcess),\n            HandleToUlong(Message->Kernel.Reg.ClientId.UniqueThread),\n            Message->Kernel.Reg.ProcessStartKey,\n            (Message->Kernel.Reg.PreviousMode ? 'U' : 'K'),\n            Message->Kernel.Reg.Object,\n            Message->Kernel.Reg.Sequence,\n            &objectName,\n            &otherObjectName,\n            &fileName\n            );\n    }\n\n    return result;\n}\n\nPPH_STRING KsiDebugLogImageVerify(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    PPH_STRING result;\n    UNICODE_STRING fileName;\n    UNICODE_STRING registryPath;\n    UNICODE_STRING certificatePublisher;\n    UNICODE_STRING certificateIssuer;\n    KPHM_SIZED_BUFFER imageHash;\n    KPHM_SIZED_BUFFER thumbprint;\n    PPH_STRING imageHashString;\n    PPH_STRING thumbprintString;\n\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldFileName, &fileName);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldRegistryPath, &registryPath);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldCertificatePublisher, &certificatePublisher);\n    KphMsgDynGetUnicodeString(Message, KphMsgFieldCertificateIssuer, &certificateIssuer);\n    KphMsgDynGetSizedBuffer(Message, KphMsgFieldHash, &imageHash);\n    KphMsgDynGetSizedBuffer(Message, KphMsgFieldCertificateThumbprint, &thumbprint);\n\n    imageHashString = PhBufferToHexString(imageHash.Buffer, imageHash.Size);\n    thumbprintString = PhBufferToHexString(thumbprint.Buffer, thumbprint.Size);\n\n    result = PhFormatString(\n        L\"%04x:%04x:%016llx %lu %lu 0x%08x %lu %lu \\\"%wZ\\\" %ls \\\"%wZ\\\" \\\"%wZ\\\" \\\"%wZ\\\" %ls\",\n        HandleToUlong(Message->Kernel.ImageVerify.ClientId.UniqueProcess),\n        HandleToUlong(Message->Kernel.ImageVerify.ClientId.UniqueThread),\n        Message->Kernel.ImageVerify.ProcessStartKey,\n        Message->Kernel.ImageVerify.ImageType,\n        Message->Kernel.ImageVerify.Classification,\n        Message->Kernel.ImageVerify.ImageFlags,\n        Message->Kernel.ImageVerify.ImageHashAlgorithm,\n        Message->Kernel.ImageVerify.ThumbprintHashAlgorithm,\n        &fileName,\n        PhGetString(imageHashString),\n        &registryPath,\n        &certificatePublisher,\n        &certificateIssuer,\n        PhGetString(thumbprintString)\n        );\n\n    PhDereferenceObject(imageHashString);\n    PhDereferenceObject(thumbprintString);\n\n    return result;\n}\n\nstatic SI_DEBUG_LOG_DEF KsiDebugLogDefs[] =\n{\n    { PH_STRINGREF_INIT(L\"ProcessCreate        \"), KsiDebugLogProcessCreate },\n    { PH_STRINGREF_INIT(L\"ProcessExit          \"), KsiDebugLogProcessExit },\n    { PH_STRINGREF_INIT(L\"ThreadCreate         \"), KsiDebugLogThreadCreate },\n    { PH_STRINGREF_INIT(L\"ThreadExecute        \"), KsiDebugLogThreadExecute },\n    { PH_STRINGREF_INIT(L\"ThreadExit           \"), KsiDebugLogThreadExit },\n    { PH_STRINGREF_INIT(L\"ImageLoad            \"), KsiDebugLogImageLoad },\n    { PH_STRINGREF_INIT(L\"DebugPrint           \"), KsiDebugLogDebugPrint },\n    { PH_STRINGREF_INIT(L\"HandlePreCreateProc  \"), KsiDebugLogHandleProcess },\n    { PH_STRINGREF_INIT(L\"HandlePostCreateProc \"), KsiDebugLogHandleProcess },\n    { PH_STRINGREF_INIT(L\"HandlePreDupeProc    \"), KsiDebugLogHandleProcess },\n    { PH_STRINGREF_INIT(L\"HandlePostDupeProc   \"), KsiDebugLogHandleProcess },\n    { PH_STRINGREF_INIT(L\"HandlePreCreateThrd  \"), KsiDebugLogHandleThread },\n    { PH_STRINGREF_INIT(L\"HandlePostCreateThrd \"), KsiDebugLogHandleThread },\n    { PH_STRINGREF_INIT(L\"HandlePreDupeThrd    \"), KsiDebugLogHandleThread },\n    { PH_STRINGREF_INIT(L\"HandlePostDupeThrd   \"), KsiDebugLogHandleThread },\n    { PH_STRINGREF_INIT(L\"HandlePreCreateDskp  \"), KsiDebugLogHandleDesktop },\n    { PH_STRINGREF_INIT(L\"HandlePostCreateDskp \"), KsiDebugLogHandleDesktop },\n    { PH_STRINGREF_INIT(L\"HandlePreDupeDskp    \"), KsiDebugLogHandleDesktop },\n    { PH_STRINGREF_INIT(L\"HandlePostDupeDskp   \"), KsiDebugLogHandleDesktop },\n    { PH_STRINGREF_INIT(L\"ReqiredStateFailure  \"), KsiDebugLogRequiredStateFailure },\n    { PH_STRINGREF_INIT(L\"PreCreate            \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostCreate           \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreCreateNamedPipe   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostCreateNamedPipe  \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreClose             \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostClose            \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreRead              \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostRead             \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreWrite             \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostWrite            \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreQueryInfo         \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostQueryInfo        \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreSetInfo           \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostSetInfo          \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreQueryEa           \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostQueryEa          \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreSetEa             \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostSetEa            \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreFlushBuffs        \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostFlushBuffs       \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreQueryVolumeInfo   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostQueryVolumeInfo  \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreSetVolumeInfo     \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostSetVolumeInfo    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreDirControl        \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostDirControl       \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreFileSystemCtrl    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostFileSystemCtrl   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreDeviceCtrl        \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostDeviceCtrl       \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreItrnlDeviceCtrl   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PosItrnlDeviceCtrl   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreShutdown          \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostShutdown         \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreLockCtrl          \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostLockCtrl         \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreCleanup           \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostCleanup          \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreCreateMailslot    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostCreateMailslot   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreQuerySecurity     \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostQuerySecurity    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreSetSecurity       \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostSetSecurity      \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PrePower             \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostPower            \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreSystemCtrl        \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostSystemCtrl       \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreDeviceChange      \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostDeviceChange     \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreQueryQuota        \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostQueryQuota       \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreSetQuota          \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostSetQuota         \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PrePnp               \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostPnp              \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreAcqForSecSync     \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostAcqForSecSync    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreRelForSecSync     \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostRelForSecSync    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreAcqForModWrite    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostAcqForModWrite   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreRelForModWrite    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostRelForModWrite   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreAcqForCcFlush     \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostAcqForCcFlush    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreRelForCcFlush     \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostRelForCcFlush    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreQueryOpen         \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostQueryOpen        \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreFastIoCheck       \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostFastIoCheck      \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreNetworkQueryOpen  \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostNetworkQueryOpen \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreMdlRead           \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostMdlRead          \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreMdlReadComplete   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostMdlReadComplete  \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PrePrepareMdlWrite   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostPrepareMdlWrite  \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreMdlWriteComplete  \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostMdlWriteComplete \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreVolumeMount       \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostVolumeMount      \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PreVolumeDismount    \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"PostVolumeDismount   \"), KsiDebugLogFileCommon },\n    { PH_STRINGREF_INIT(L\"RegPreDeleteKey      \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostDeleteKey     \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreSetValueKey    \"), KsiDebugLogRegCommonWithValue },\n    { PH_STRINGREF_INIT(L\"RegPostSetValueKey   \"), KsiDebugLogRegCommonWithValue },\n    { PH_STRINGREF_INIT(L\"RegPreDeleteValueKey \"), KsiDebugLogRegCommonWithValue },\n    { PH_STRINGREF_INIT(L\"RegPostDeleteValueKey\"), KsiDebugLogRegCommonWithValue },\n    { PH_STRINGREF_INIT(L\"RegPreSetInfoKey     \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostSetInfoKey    \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreRenameKey      \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostRenameKey     \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreEnumKey        \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostEnumKey       \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreEnumValueKey   \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostEnumValueKey  \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreQueryKey       \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostQueryKey      \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreQueryValueKey  \"), KsiDebugLogRegCommonWithValue },\n    { PH_STRINGREF_INIT(L\"RegPostQueryValueKey \"), KsiDebugLogRegCommonWithValue },\n    { PH_STRINGREF_INIT(L\"RegPreQueryMValueKey \"), KsiDebugLogRegCommonWithMultipleValues },\n    { PH_STRINGREF_INIT(L\"RegPostQueryMValueKey\"), KsiDebugLogRegCommonWithMultipleValues },\n    { PH_STRINGREF_INIT(L\"RegPreKeyHandleClose \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostKeyHandleClose\"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreCreateKey      \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostCreateKey     \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreOpenKey        \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostOpenKey       \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreFlushKey       \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostFlushKey      \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreLoadKey        \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostLoadKey       \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreUnLoadKey      \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostUnLoadKey     \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreQueryKeySec    \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostQueryKeySec   \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreSetKeySec      \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostSetKeySec     \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreRestoreKey     \"), KsiDebugLogRegSaveRestoreKey },\n    { PH_STRINGREF_INIT(L\"RegPostRestoreKey    \"), KsiDebugLogRegSaveRestoreKey },\n    { PH_STRINGREF_INIT(L\"RegPreSaveKey        \"), KsiDebugLogRegSaveRestoreKey },\n    { PH_STRINGREF_INIT(L\"RegPostSaveKey       \"), KsiDebugLogRegSaveRestoreKey },\n    { PH_STRINGREF_INIT(L\"RegPreReplaceKey     \"), KsiDebugLogRegReplaceKey },\n    { PH_STRINGREF_INIT(L\"RegPostReplaceKey    \"), KsiDebugLogRegReplaceKey },\n    { PH_STRINGREF_INIT(L\"RegPreQueryKeyName   \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPostQueryKeyName  \"), KsiDebugLogRegCommon },\n    { PH_STRINGREF_INIT(L\"RegPreSaveMergedKey  \"), KsiDebugLogSaveMergedKey },\n    { PH_STRINGREF_INIT(L\"RegPostSaveMergedKey \"), KsiDebugLogSaveMergedKey },\n    { PH_STRINGREF_INIT(L\"ImageVerify          \"), KsiDebugLogImageVerify },\n};\nC_ASSERT((RTL_NUMBER_OF(KsiDebugLogDefs) + (MaxKphMsgClientAllowed + 1)) == MaxKphMsg);\n\nPPH_STRING KsiDebugLogGetTimeString(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    PPH_STRING result;\n    SYSTEMTIME systemTime;\n    PPH_STRING date;\n    PPH_STRING time;\n\n    PhLargeIntegerToSystemTime(&systemTime, (PLARGE_INTEGER)&Message->Header.TimeStamp);\n\n    date = PhFormatDate(&systemTime, L\"yyyy-MM-dd \");\n    time = PhFormatTime(&systemTime, L\"hh':'mm':'ss tt\");\n\n    result = PhConcatStringRef2(&date->sr, &time->sr);\n\n    PhDereferenceObject(time);\n    PhDereferenceObject(date);\n\n    return result;\n}\n\nBOOLEAN KsiDebugLogSkip(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    UNICODE_STRING fileName;\n\n    if (NT_SUCCESS(KphMsgDynGetUnicodeString(Message, KphMsgFieldFileName, &fileName)))\n    {\n        PH_STRINGREF sr;\n\n        PhUnicodeStringToStringRef(&fileName, &sr);\n\n        if (PhEndsWithStringRef(&sr, &KsiDebugLogSuffix, TRUE))\n            return TRUE;\n        if (PhEndsWithStringRef(&sr, &KsiDebugRawSuffix, TRUE))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID KsiDebugLogMessageLog(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    ULONG index;\n    PPH_STRING time;\n    PPH_STRING log;\n    PH_FORMAT format[7];\n    PPH_STRING line;\n    KPHM_STACK_TRACE stack;\n\n    if (!KsiDebugLogFileStream || KsiDebugLogSkip(Message))\n        return;\n\n    assert(Message->Header.MessageId > MaxKphMsgClientAllowed);\n    assert(Message->Header.MessageId < MaxKphMsg);\n\n    index = (Message->Header.MessageId - (MaxKphMsgClientAllowed + 1));\n\n    assert(index < RTL_NUMBER_OF(KsiDebugLogDefs));\n\n    time = KsiDebugLogGetTimeString(Message);\n\n    if (KsiDebugLogDefs[index].GetLogString)\n        log = KsiDebugLogDefs[index].GetLogString(Message);\n    else\n        log = PhReferenceEmptyString();\n\n    PhInitFormatC(&format[0], L'[');\n    PhInitFormatSR(&format[1], time->sr);\n    PhInitFormatS(&format[2], L\" - \");\n    PhInitFormatSR(&format[3], KsiDebugLogDefs[index].Name);\n    PhInitFormatS(&format[4], L\"] \");\n    PhInitFormatSR(&format[5], log->sr);\n    PhInitFormatS(&format[6], L\"\\r\\n\");\n\n    line = PhFormat(format, RTL_NUMBER_OF(format), 32);\n\n    if (NT_SUCCESS(KphMsgDynGetStackTrace(Message, KphMsgFieldStackTrace, &stack)))\n    {\n        PH_STRING_BUILDER stringBuilder;\n        WCHAR buffer[PH_PTR_STR_LEN_1];\n\n        PhInitializeStringBuilder(&stringBuilder, line->Length + 100);\n\n        PhAppendStringBuilder(&stringBuilder, &line->sr);\n\n        for (ULONG i = 0; i < stack.Count; i++)\n        {\n            // TODO(jxy-s) resolve symbols\n            PhPrintPointerPadZeros(buffer, stack.Frames[i]);\n            PhAppendStringBuilder2(&stringBuilder, buffer);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n        }\n\n        PhMoveReference(&line, PhFinalStringBuilderString(&stringBuilder));\n    }\n\n    PhAcquireFastLockExclusive(&KsiDebugLogFileStreamLock);\n    PhWriteStringAsUtf8FileStream(KsiDebugLogFileStream, &line->sr);\n    PhReleaseFastLockExclusive(&KsiDebugLogFileStreamLock);\n\n    PhDereferenceObject(line);\n    PhDereferenceObject(log);\n    PhDereferenceObject(time);\n}\n\nVOID KsiDebugLogMessageRaw(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    if (!KsiDebugRawFileStream || KsiDebugLogSkip(Message))\n        return;\n\n    PhAcquireFastLockExclusive(&KsiDebugRawFileStreamLock);\n    PhWriteFileStream(KsiDebugRawFileStream, (PVOID)Message, Message->Header.Size);\n    PhReleaseFastLockExclusive(&KsiDebugRawFileStreamLock);\n}\n\nvolatile ULONG64 KsiMessagesReceived = 0;\nvolatile ULONG64 KsiBytesReceived = 0;\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI KsiDebugLogMessageCallback(\n    _In_ PPH_INFORMER_CONTEXT Informer,\n    _In_opt_ PVOID Context\n    )\n{\n    KsiDebugLogMessageRaw(Informer->Message);\n    KsiDebugLogMessageLog(Informer->Message);\n\n    InterlockedIncrementRelease64(&KsiMessagesReceived);\n    InterlockedAddRelease64(&KsiBytesReceived, Informer->Message->Header.Size);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI KsiDebugMonitorRoutine(\n    _In_ PVOID Parameter\n    )\n{\n    ULONG64 lastMessagesReceived = 0;\n    ULONG64 lastBytesReceived = 0;\n    KPH_INFORMER_CLIENT_STATS lastStats;\n\n    memset(&lastStats, 0, sizeof(lastStats));\n\n    for (NOTHING; NOTHING; PhDelayExecution(1000))\n    {\n        ULONG64 messagesReceived;\n        ULONG64 bytesReceived;\n        KPH_INFORMER_CLIENT_STATS stats;\n\n        messagesReceived = ReadULong64Acquire(&KsiMessagesReceived);\n        bytesReceived = ReadULong64Acquire(&KsiBytesReceived);\n        KphGetInformerClientStats(&stats);\n\n        if (lastMessagesReceived)\n        {\n            ULONG64 bytesDiff = (bytesReceived - lastBytesReceived);\n            ULONG64 messagesDiff = (messagesReceived - lastMessagesReceived);\n            ULONG64 droppedDiff = (stats.AsyncQueueRateLimit.Dropped - lastStats.AsyncQueueRateLimit.Dropped);\n            PPH_STRING size;\n\n            size = PhFormatSize(bytesDiff, ULONG_MAX);\n\n            PhTrace(\"KSI: B:%ls M:%llu D:%llu\", PhGetString(size), messagesDiff, droppedDiff);\n\n            PhDereferenceObject(size);\n        }\n\n        lastMessagesReceived = messagesReceived;\n        lastBytesReceived = bytesReceived;\n        lastStats = stats;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nVOID KsiDebugLogInitialize(\n    VOID\n    )\n{\n    PPH_STRING desktopPath;\n    PPH_STRING fileName;\n\n    desktopPath =  PhExpandEnvironmentStringsZ(L\"\\\\??\\\\%USERPROFILE%\");\n\n    if (KsiDebugLogEnabled)\n    {\n        fileName = PhConcatStringRef2(&desktopPath->sr, &KsiDebugLogSuffix);\n        if (fileName)\n        {\n            if (!NT_SUCCESS(PhCreateFileStream(\n                &KsiDebugLogFileStream,\n                PhGetString(fileName),\n                FILE_GENERIC_WRITE,\n                FILE_SHARE_READ | FILE_SHARE_WRITE,\n                FILE_OVERWRITE_IF,\n                0\n                )))\n            {\n                KsiDebugLogFileStream = NULL;\n            }\n\n            PhDereferenceObject(fileName);\n        }\n    }\n\n    if (KsiDebugRawEnabled)\n    {\n        fileName = PhConcatStringRef2(&desktopPath->sr, &KsiDebugRawSuffix);\n        if (fileName)\n        {\n            if (!NT_SUCCESS(PhCreateFileStream(\n                &KsiDebugRawFileStream,\n                PhGetString(fileName),\n                FILE_GENERIC_WRITE,\n                FILE_SHARE_READ | FILE_SHARE_WRITE,\n                FILE_OVERWRITE_IF,\n                0\n                )))\n            {\n                KsiDebugRawFileStream = NULL;\n            }\n\n            PhDereferenceObject(fileName);\n        }\n    }\n\n    if (KsiDebugLogFileStream || KsiDebugRawFileStream)\n    {\n        KPH_INFORMER_SETTINGS settings;\n\n        PhCreateThread2(KsiDebugMonitorRoutine, NULL);\n\n        PhRegisterCallback(\n            &PhInformerCallback,\n            KsiDebugLogMessageCallback,\n            NULL,\n            &KsiDebugMessageRegistration\n            );\n\n        if (NT_SUCCESS(KphGetInformerSettings(&settings)))\n        {\n            if (settings.Policy[KPH_INFORMER_INDEX(DebugPrint)].TokensPerPeriod)\n            {\n                NtSetDebugFilterState(ULONG_MAX, ULONG_MAX, TRUE);\n                for (DPFLTR_TYPE i = 0; i <= DPFLTR_ENDOFTABLE_ID; i++)\n                    NtSetDebugFilterState(i, ULONG_MAX, TRUE);\n            }\n        }\n    }\n}\n\nVOID KsiDebugLogFinalize(\n    VOID\n    )\n{\n    ULONG64 messagesRecieved;\n    ULONG64 bytesReceived;\n\n    if (KsiDebugLogFileStream || KsiDebugRawFileStream)\n    {\n        PhUnregisterCallback(&PhInformerCallback, &KsiDebugMessageRegistration);\n    }\n    PhClearReference(&KsiDebugRawFileStream);\n    PhClearReference(&KsiDebugLogFileStream);\n\n    messagesRecieved = ReadULong64Acquire(&KsiMessagesReceived);\n    if (messagesRecieved)\n    {\n        bytesReceived = ReadULong64Acquire(&KsiBytesReceived);\n\n        PhShowMessage2(\n            NULL,\n            MB_OK,\n            IDI_INFORMATION,\n            L\"Debug Log Finalize\",\n            L\"%llu messages totaling %.4f GB\",\n            messagesRecieved,\n            (FLOAT)bytesReceived / (1024 * 1024 * 1024)\n            );\n    }\n}\n\n#endif\n"
  },
  {
    "path": "SystemInformer/ksisup.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2024\n *     dmex    2022-2026\n *\n */\n\n#include <phapp.h>\n#include <kphuser.h>\n#include <kphcomms.h>\n#include <kphdyndata.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <json.h>\n#include <mapimg.h>\n#include <phappres.h>\n#include <sistatus.h>\n#include <informer.h>\n#include <phsvccl.h>\n#include <svcsup.h>\n\n#include <ksisup.h>\n\ntypedef struct _KSI_SUPPORT_DATA\n{\n    USHORT Class;\n    USHORT Machine;\n    ULONG TimeDateStamp;\n    ULONG SizeOfImage;\n} KSI_SUPPORT_DATA, *PKSI_SUPPORT_DATA;\n\n#if defined(KSI_ONLINE_PLATFORM_SUPPORT)\ntypedef struct _KSI_KERNEL_SUPPORT_CHECK_CONTEXT\n{\n    HWND WindowHandle;\n    HWND TaskDialogHandle;\n    KSI_SUPPORT_DATA SupportData;\n    BOOLEAN IsCanaryChannel;\n    volatile BOOLEAN CheckComplete;\n    volatile BOOLEAN IsSupported;\n} KSI_KERNEL_SUPPORT_CHECK_CONTEXT, *PKSI_KERNEL_SUPPORT_CHECK_CONTEXT;\n\nVOID KsiShowKernelSupportCheckDialog(\n    _In_opt_ HWND WindowHandle\n    );\n#endif\n\nstatic CONST PH_STRINGREF DriverExtension = PH_STRINGREF_INIT(L\".sys\");\nstatic PPH_STRING KsiKernelVersion = NULL;\nstatic KSI_SUPPORT_DATA KsiSupportData = { MAXWORD, 0, 0, 0 };\nstatic PPH_STRING KsiSupportString = NULL;\n// N.B. These are necessary for consistency between load and unload.\nstatic BOOLEAN KsiEnableLoadNative = FALSE;\nstatic BOOLEAN KsiEnableLoadFilter = FALSE;\nstatic PPH_STRING KsiServiceName = NULL;\nstatic PPH_STRING KsiFileName = NULL;\nstatic PPH_STRING KsiObjectName = NULL;\n\n#ifdef DEBUG\n//#define KSI_DEBUG_DELAY_SPLASHSCREEN 1\n\nextern // ksidbg.c\nVOID KsiDebugLogInitialize(\n    VOID\n    );\n\nextern // ksidbg.c\nVOID KsiDebugLogFinalize(\n    VOID\n    );\n#endif\n\n/**\n * Get the kernel file name for the running system.\n * \\return PPH_STRING The kernel file name, or NULL on failure.\n */\nPPH_STRING KsiGetKernelFileName(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PPH_STRING KsiKernelFileName = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        KsiKernelFileName = PhGetKernelFileName();\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (KsiKernelFileName)\n        return PhReferenceObject(KsiKernelFileName);\n\n    return NULL;\n}\n\n/**\n * Maps the WindowsVersion enum to a human readable string.\n * \\return PCWSTR The human readable string for the Windows version.\n */\nPCWSTR KsiGetWindowsVersionString(\n    VOID\n    )\n{\n    switch (WindowsVersion)\n    {\n    case WINDOWS_7:\n        return L\"Windows 7\";\n    case WINDOWS_8:\n        return L\"Windows 8\";\n    case WINDOWS_8_1:\n        return L\"Windows 8.1\";\n    case WINDOWS_10:\n        return L\"Windows 10 RTM\";\n    case WINDOWS_10_TH2:\n        return L\"Windows 10 TH2\";\n    case WINDOWS_10_RS1:\n        return L\"Windows 10 RS1\";\n    case WINDOWS_10_RS2:\n        return L\"Windows 10 RS2\";\n    case WINDOWS_10_RS3:\n        return L\"Windows 10 RS3\";\n    case WINDOWS_10_RS4:\n        return L\"Windows 10 RS4\";\n    case WINDOWS_10_RS5:\n        return L\"Windows 10 RS5\";\n    case WINDOWS_10_19H1:\n        return L\"Windows 10 19H1\";\n    case WINDOWS_10_19H2:\n        return L\"Windows 10 19H2\";\n    case WINDOWS_10_20H1:\n        return L\"Windows 10 20H1\";\n    case WINDOWS_10_20H2:\n        return L\"Windows 10 20H2\";\n    case WINDOWS_10_21H1:\n        return L\"Windows 10 21H1\";\n    case WINDOWS_10_21H2:\n        return L\"Windows 10 21H2\";\n    case WINDOWS_10_22H2:\n        return L\"Windows 10 22H2\";\n    case WINDOWS_11:\n        return L\"Windows 11\";\n    case WINDOWS_11_22H2:\n        return L\"Windows 11 22H2\";\n    case WINDOWS_11_23H2:\n        return L\"Windows 11 23H2\";\n    case WINDOWS_11_24H2:\n        return L\"Windows 11 24H2\";\n    case WINDOWS_11_25H2:\n        return L\"Windows 11 25H2\";\n    case WINDOWS_11_26H1:\n        return L\"Windows 11 26H1\";\n    case WINDOWS_NEW:\n        return L\"Windows Insider Preview\";\n    }\n\n    static_assert(WINDOWS_MAX == WINDOWS_11_26H1, \"KsiGetWindowsVersionString must include all versions\");\n\n    return L\"Windows\";\n}\n\n/**\n * Return a formatted Windows build string derived from PhOsVersion.\n * \\return PPH_STRING The formatted Windows build string \"Major.Minor.Build\".\n */\nPPH_STRING KsiGetWindowsBuildString(\n    VOID\n    )\n{\n    PH_FORMAT format[5];\n\n    PhInitFormatU(&format[0], PhOsVersion.MajorVersion);\n    PhInitFormatC(&format[1], L'.');\n    PhInitFormatU(&format[2], PhOsVersion.MinorVersion);\n    PhInitFormatC(&format[3], L'.');\n    PhInitFormatU(&format[4], PhOsVersion.BuildNumber);\n\n    return PhFormat(format, RTL_NUMBER_OF(format), 0);\n}\n\n/**\n * Get the kernel file version string cached from the kernel image.\n *\n * This uses an init-once pattern to load and cache the `FileVersion` field\n * from the kernel image's version resource. The returned `PPH_STRING` is a\n * referenced object and must be dereferenced by the caller.\n * \\return Referenced PPH_STRING containing the kernel file version, or NULL.\n */\nPPH_STRING KsiGetKernelVersionString(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PPH_STRING fileName;\n        PH_IMAGE_VERSION_INFO versionInfo;\n\n        if (fileName = KsiGetKernelFileName())\n        {\n            if (NT_SUCCESS(PhInitializeImageVersionInfoEx(&versionInfo, &fileName->sr, FALSE)))\n            {\n                KsiKernelVersion = versionInfo.FileVersion;\n\n                versionInfo.FileVersion = NULL;\n                PhDeleteImageVersionInfo(&versionInfo);\n            }\n\n            PhDereferenceObject(fileName);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (KsiKernelVersion)\n        return PhReferenceObject(KsiKernelVersion);\n\n    return NULL;\n}\n\n/**\n * Populate `SupportData` with kernel image attributes useful for dynamic configuration lookup.\n *\n * This function caches the support data on first call and returns the cached\n * structure on subsequent calls. It uses the kernel filename to inspect the\n * mapped image headers and derives the class, machine, timestamp and size of\n * image used for compatibility lookups.\n * \\param[out] SupportData Pointer to KSI_SUPPORT_DATA that receives the result.\n */\nVOID KsiGetKernelSupportData(\n    _Out_ PKSI_SUPPORT_DATA SupportData\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PPH_STRING fileName;\n        PH_MAPPED_IMAGE mappedImage;\n\n        if (fileName = KsiGetKernelFileName())\n        {\n            if (PhEndsWithString2(fileName, L\"ntoskrnl.exe\", TRUE))\n                KsiSupportData.Class = KPH_DYN_CLASS_NTOSKRNL;\n            else if (PhEndsWithString2(fileName, L\"ntkrla57.exe\", TRUE))\n                KsiSupportData.Class = KPH_DYN_CLASS_NTKRLA57;\n\n            if (NT_SUCCESS(PhLoadMappedImageHeaderPageSize(&fileName->sr, NULL, &mappedImage)))\n            {\n                KsiSupportData.Machine = mappedImage.NtHeaders->FileHeader.Machine;\n                KsiSupportData.TimeDateStamp = mappedImage.NtHeaders->FileHeader.TimeDateStamp;\n                KsiSupportData.SizeOfImage = mappedImage.NtHeaders->OptionalHeader.SizeOfImage;\n\n                PhUnloadMappedImage(&mappedImage);\n            }\n\n            PhDereferenceObject(fileName);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    *SupportData = KsiSupportData;\n}\n\n/**\n * Get a formatted support string that uniquely identifies the kernel image for dynamic data matching.\n *\n * The returned object is a referenced `PPH_STRING` and must be dereferenced by\n * the caller. The string format is \"%02x-%04x-%08x-%08x\".\n * \\return Referenced `PPH_STRING` containing the kernel support string.\n */\nPPH_STRING KsiGetKernelSupportString(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        KSI_SUPPORT_DATA supportData;\n\n        KsiGetKernelSupportData(&supportData);\n\n        KsiSupportString = PhFormatString(\n            L\"%02x-%04x-%08x-%08x\",\n            (BYTE)supportData.Class,\n            supportData.Machine,\n            supportData.TimeDateStamp,\n            supportData.SizeOfImage\n            );\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return PhReferenceObject(KsiSupportString);\n}\n\n/**\n * Show the user a one-time warning if the process does not have full\n * expected kernel protection capabilities.\n *\n * This function checks global settings and the current process state to\n * determine whether to show a descriptive message. If the user dismisses and\n * checks \"don't show again\" the global warning flag is disabled and persisted.\n */\nVOID PhShowKsiStatus(\n    VOID\n    )\n{\n    KPH_PROCESS_STATE processState;\n\n    if (!PhEnableKsiWarnings || PhStartupParameters.PhSvc)\n        return;\n\n    processState = KphGetCurrentProcessState();\n\n    if ((processState != 0) &&\n        (processState & KPH_PROCESS_STATE_MAXIMUM) != KPH_PROCESS_STATE_MAXIMUM)\n    {\n        PPH_STRING infoString;\n        PH_STRING_BUILDER stringBuilder;\n\n        PhInitializeStringBuilder(&stringBuilder, 100);\n\n        if (!BooleanFlagOn(processState, KPH_PROCESS_SECURELY_CREATED))\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"    - not securely created\\r\\n\");\n        }\n        if (!BooleanFlagOn(processState, KPH_PROCESS_VERIFIED_PROCESS))\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"    - unverified primary image\\r\\n\");\n        }\n        if (!BooleanFlagOn(processState, KPH_PROCESS_PROTECTED_PROCESS))\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"    - inactive protections\\r\\n\");\n        }\n        if (!BooleanFlagOn(processState, KPH_PROCESS_NO_UNTRUSTED_IMAGES))\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"    - unsigned images (likely an unsigned plugin)\\r\\n\");\n        }\n        if (!BooleanFlagOn(processState, KPH_PROCESS_NOT_BEING_DEBUGGED))\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"    - process is being debugged\\r\\n\");\n        }\n        if (!BooleanFlagOn(processState, KPH_PROCESS_CREATE_NOTIFICATION))\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"    - no create notification\\r\\n\");\n        }\n        if ((processState & KPH_PROCESS_STATE_MINIMUM) != KPH_PROCESS_STATE_MINIMUM)\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"    - tampered primary image\\r\\n\");\n        }\n\n        if (PhEndsWithString2(stringBuilder.String, L\"\\r\\n\", FALSE))\n            PhRemoveEndStringBuilder(&stringBuilder, 2);\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\\r\\n\"); // String interning optimization (dmex)\n        PhAppendStringBuilder2(&stringBuilder, L\"You will be unable to use more advanced features, view details about system processes or terminate malicious software.\");\n        infoString = PhFinalStringBuilderString(&stringBuilder);\n\n        PhShowKsiMessageEx(\n            NULL,\n            TD_SHIELD_ERROR_ICON,\n            0,\n            FALSE,\n            L\"Access to the kernel driver is restricted.\",\n            L\"%s\",\n            PhGetString(infoString)\n            );\n\n        PhDereferenceObject(infoString);\n    }\n}\n\n/**\n * Build a long-form diagnostic string containing application and kernel\n * state and an optional formatted message.\n *\n * This helper assembles version, kernel, and process state information along\n * with the provided format and arguments. The returned `PPH_STRING` is a\n * referenced object that the caller must free via PhDereferenceObject().\n *\n * \\param[in] Status NTSTATUS associated with the message (0 if none).\n * \\param[in] Force If TRUE the message will be shown even if warnings are\n *                  disabled; used to control UI behaviour in callers.\n * \\param[in] Format Printf-style format string for the primary message body.\n * \\param[in] ArgPtr va_list of arguments for the Format.\n * \\return Referenced `PPH_STRING` containing the assembled message.\n */\nPPH_STRING PhpGetKsiMessage(\n    _In_opt_ NTSTATUS Status,\n    _In_ BOOLEAN Force,\n    _In_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    PPH_STRING buildString;\n    PPH_STRING versionString;\n    PPH_STRING kernelVersion;\n    PPH_STRING errorMessage;\n    PH_STRING_BUILDER stringBuilder;\n    PPH_STRING supportString;\n    PPH_STRING messageString;\n    ULONG processState;\n\n    buildString = KsiGetWindowsBuildString();\n    versionString = PhGetApplicationVersionString(FALSE);\n    kernelVersion = KsiGetKernelVersionString();\n    errorMessage = NULL;\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n    PhAppendFormatStringBuilder_V(&stringBuilder, Format, ArgPtr);\n    PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\\r\\n\");\n\n    if (Status != 0)\n    {\n        if (!(errorMessage = PhGetStatusMessage(Status, 0)))\n            errorMessage = PhGetStatusMessage(0, Status);\n\n        if (errorMessage)\n        {\n            PH_STRINGREF firstPart;\n            PH_STRINGREF secondPart;\n\n            // sanitize format specifiers\n\n            secondPart = errorMessage->sr;\n            while (PhSplitStringRefAtChar(&secondPart, L'%', &firstPart, &secondPart))\n            {\n                PhAppendStringBuilder(&stringBuilder, &firstPart);\n                PhAppendStringBuilder2(&stringBuilder, L\"%%\");\n            }\n\n            PhAppendStringBuilder(&stringBuilder, &firstPart);\n        }\n        else\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"Unknown error.\");\n        }\n\n        PhAppendFormatStringBuilder(&stringBuilder, L\" (0x%08x)\", Status);\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\\r\\n\");\n    }\n\n    PhAppendFormatStringBuilder(\n        &stringBuilder,\n        L\"%ls %ls\\r\\n\",\n        KsiGetWindowsVersionString(),\n        PhGetString(buildString)\n        );\n\n    PhAppendStringBuilder2(&stringBuilder, L\"Windows Kernel \");\n    PhAppendStringBuilder2(&stringBuilder, PhGetStringOrDefault(kernelVersion, L\"Unknown\"));\n    PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    PhAppendStringBuilder(&stringBuilder, &versionString->sr);\n    PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n\n    processState = KphGetCurrentProcessState();\n    if (processState != 0)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Process State \");\n        PhAppendFormatStringBuilder(&stringBuilder, L\"0x%08x\", processState);\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    }\n\n    if (!PhEnableKsiWarnings)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Driver warnings are disabled.\");\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    }\n\n    supportString = KsiGetKernelSupportString();\n    PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    PhAppendStringBuilder(&stringBuilder, &supportString->sr);\n    PhDereferenceObject(supportString);\n\n    messageString = PhFinalStringBuilderString(&stringBuilder);\n\n    PhClearReference(&errorMessage);\n    PhClearReference(&kernelVersion);\n    PhClearReference(&versionString);\n    PhClearReference(&buildString);\n\n    return messageString;\n}\n\n#if defined(KSI_ONLINE_PLATFORM_SUPPORT)\nPPH_STRING PhpGetKsiMessage2(\n    _In_opt_ NTSTATUS Status,\n    _In_ BOOLEAN Force,\n    _In_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    PPH_STRING buildString;\n    PPH_STRING versionString;\n    PPH_STRING kernelVersion;\n    PPH_STRING errorMessage;\n    PH_STRING_BUILDER stringBuilder;\n    PPH_STRING supportString;\n    PPH_STRING messageString;\n    ULONG processState;\n\n    buildString = KsiGetWindowsBuildString();\n    versionString = PhGetApplicationVersionString(FALSE);\n    kernelVersion = KsiGetKernelVersionString();\n    errorMessage = NULL;\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n\n    if (Status != 0)\n    {\n        if (!(errorMessage = PhGetStatusMessage(Status, 0)))\n            errorMessage = PhGetStatusMessage(0, Status);\n\n        if (errorMessage)\n        {\n            PH_STRINGREF firstPart;\n            PH_STRINGREF secondPart;\n\n            // sanitize format specifiers\n\n            secondPart = errorMessage->sr;\n            while (PhSplitStringRefAtChar(&secondPart, L'%', &firstPart, &secondPart))\n            {\n                PhAppendStringBuilder(&stringBuilder, &firstPart);\n                PhAppendStringBuilder2(&stringBuilder, L\"%%\");\n            }\n\n            PhAppendStringBuilder(&stringBuilder, &firstPart);\n        }\n        else\n        {\n            PhAppendStringBuilder2(&stringBuilder, L\"Unknown error.\");\n        }\n\n        PhAppendFormatStringBuilder(&stringBuilder, L\" (0x%08x)\", Status);\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\\r\\n\");\n    }\n\n    PhAppendFormatStringBuilder(\n        &stringBuilder,\n        L\"%ls %ls\\r\\n\",\n        KsiGetWindowsVersionString(),\n        PhGetString(buildString)\n        );\n\n    PhAppendStringBuilder2(&stringBuilder, L\"Windows Kernel \");\n    PhAppendStringBuilder2(&stringBuilder, PhGetStringOrDefault(kernelVersion, L\"Unknown\"));\n    PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    PhAppendStringBuilder(&stringBuilder, &versionString->sr);\n    PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n\n    processState = KphGetCurrentProcessState();\n    if (processState != 0)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Process State \");\n        PhAppendFormatStringBuilder(&stringBuilder, L\"0x%08x\", processState);\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    }\n\n    if (!PhEnableKsiWarnings)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Driver warnings are disabled.\");\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    }\n\n    supportString = KsiGetKernelSupportString();\n    PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    PhAppendStringBuilder(&stringBuilder, &supportString->sr);\n    PhDereferenceObject(supportString);\n\n    PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\\r\\n\");\n    PhAppendFormatStringBuilder_V(&stringBuilder, Format, ArgPtr);\n\n    messageString = PhFinalStringBuilderString(&stringBuilder);\n\n    PhClearReference(&errorMessage);\n    PhClearReference(&kernelVersion);\n    PhClearReference(&versionString);\n    PhClearReference(&buildString);\n\n    return messageString;\n}\n#endif\n\n/**\n * Show the composed kernel message to the user either one-time or\n * forced, depending on parameters.\n *\n * This wrapper uses PhpGetKsiMessage to build a detailed message string and\n * displays it using the appropriate PhShowMessage* helper. If the user opts to\n * suppress future warnings the global setting is cleared and persisted.\n *\n * \\param[in] WindowHandle Parent window handle for UI.\n * \\param[in] Buttons Task dialog button flags (e.g., TD_OK_BUTTON).\n * \\param[in] Icon Icon resource id/name for the task dialog.\n * \\param[in] Status Optional NTSTATUS to include in the message.\n * \\param[in] Force Show a modal message; otherwise one-time message.\n * \\param[in] Title Title to display in the dialog.\n * \\param[in] Format Printf-style format string for the message.\n * \\param[in] ArgPtr va_list of arguments for Format.\n * \\return LONG result of the dialog interaction (e.g., IDOK, IDYES, IDNO).\n */\nLONG PhpShowKsiMessage(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ NTSTATUS Status,\n    _In_ BOOLEAN Force,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    LONG result;\n    PPH_STRING errorMessage;\n\n    if (!Force && !PhEnableKsiWarnings || PhStartupParameters.PhSvc)\n        return INT_ERROR;\n\n    errorMessage = PhpGetKsiMessage(Status, Force, Format, ArgPtr);\n\n    if (Force)\n    {\n        result = PhShowMessage2(\n            WindowHandle,\n            Buttons,\n            Icon,\n            Title,\n            PhGetString(errorMessage)\n            );\n    }\n    else\n    {\n        BOOLEAN checked;\n\n        if (Status != STATUS_SUCCESS)\n        {\n            LONG bufferLength;\n            WCHAR buffer[0x100];\n\n            bufferLength = _snwprintf(\n                buffer,\n                ARRAYSIZE(buffer) - sizeof(UNICODE_NULL),\n                L\"%s (0x%08x)\",\n                Title,\n                Status\n                );\n            buffer[bufferLength] = UNICODE_NULL;\n\n            result = PhShowMessageOneTime2(\n                WindowHandle,\n                Buttons,\n                Icon,\n                buffer,\n                &checked,\n                PhGetString(errorMessage)\n                );\n        }\n        else\n        {\n            result = PhShowMessageOneTime2(\n                WindowHandle,\n                Buttons,\n                Icon,\n                Title,\n                &checked,\n                PhGetString(errorMessage)\n                );\n        }\n\n        if (checked)\n        {\n            PhEnableKsiWarnings = FALSE;\n            PhSetIntegerSetting(SETTING_KSI_ENABLE_WARNINGS, FALSE);\n        }\n    }\n\n    PhClearReference(&errorMessage);\n\n    return result;\n}\n\n/**\n * Public wrapper to build a message string via va-args.\n *\n * Convenience wrapper around PhpGetKsiMessage that accepts variable arguments.\n * Caller receives a referenced `PPH_STRING` and must dereference it.\n *\n * \\param[in] Status Optional NTSTATUS.\n * \\param[in] Force See PhpGetKsiMessage.\n * \\param[in] Format Printf-style format string.\n * \\return Referenced `PPH_STRING` with the assembled message.\n */\nPPH_STRING PhGetKsiMessage(\n    _In_opt_ NTSTATUS Status,\n    _In_ BOOLEAN Force,\n    _In_ PCWSTR Format,\n    ...\n    )\n{\n    PPH_STRING message;\n    va_list argptr;\n\n    va_start(argptr, Format);\n    message = PhpGetKsiMessage(Status, Force, Format, argptr);\n    va_end(argptr);\n\n    return message;\n}\n\n/**\n * Public wrapper to display a message to the user with va-args.\n *\n * Calls PhpShowKsiMessage with variable argument list and returns dialog result.\n */\nLONG PhShowKsiMessage2(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ NTSTATUS Status,\n    _In_ BOOLEAN Force,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    )\n{\n    LONG result;\n    va_list argptr;\n\n    va_start(argptr, Format);\n    result = PhpShowKsiMessage(WindowHandle, Buttons, Icon, Status, Force, Title, Format, argptr);\n    va_end(argptr);\n\n    return result;\n }\n\n/**\n * Convenience function to show an informational message (OK) with va-args.\n *\n * This variant always uses TD_OK_BUTTON and forwards to PhpShowKsiMessage.\n */\nVOID PhShowKsiMessageEx(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ NTSTATUS Status,\n    _In_ BOOLEAN Force,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Format);\n    PhpShowKsiMessage(WindowHandle, TD_OK_BUTTON, Icon, Status, Force, Title, Format, argptr);\n    va_end(argptr);\n}\n\n/**\n * Convenience function to show a forced OK message (no status, forced).\n *\n * Calls PhpShowKsiMessage forcing the message to be shown and using TD_OK_BUTTON.\n */\nVOID PhShowKsiMessage(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR Icon,\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Format);\n    PhpShowKsiMessage(WindowHandle, TD_OK_BUTTON, Icon, 0, TRUE, Title, Format, argptr);\n    va_end(argptr);\n}\n\n/**\n * Create a randomized alphanumeric name with the given prefix.\n *\n * Generates an 8-12 character random alpha string and concatenates it to the\n * provided prefix producing a new referenced `PPH_STRING` returned via `Name`.\n *\n * \\param[in] Prefix Wide string prefix to prepend.\n * \\param[out] Name Receives referenced `PPH_STRING` containing the new name.\n */\nVOID KsiCreateRandomizedName(\n    _In_ PCWSTR Prefix,\n    _Out_ PPH_STRING* Name,\n    _In_ BOOLEAN Numeric\n    )\n{\n    ULONG length;\n    WCHAR buffer[13];\n\n    length = (PhGenerateRandomNumber64() % 6) + 8; // 8-12 characters\n\n    if (Numeric)\n        PhGenerateRandomNumericString(buffer, length);\n    else\n        PhGenerateRandomAlphaString(buffer, length);\n\n    *Name = PhConcatStrings2(Prefix, buffer);\n}\n\n/**\n * Creates and connects to the System Informer service.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS KsiSvcConnectToServer(\n    VOID\n    )\n{\n    NTSTATUS status;\n    PPH_STRING serviceName;\n    PPH_STRING fileName;\n    PPH_STRING commandLine;\n    SC_HANDLE serviceHandle;\n    PPH_STRING portName;\n    UNICODE_STRING portNameUs;\n    ULONG attempts;\n\n    if (!(fileName = PhGetApplicationFileNameWin32()))\n        return STATUS_UNSUCCESSFUL;\n\n    KsiCreateRandomizedName(L\"SystemInformer_\", &serviceName, FALSE);\n\n    commandLine = PhFormatString(\n        L\"\\\"%s\\\" -ras \\\"%s\\\"\",\n        fileName->Buffer,\n        PhGetString(serviceName)\n        );\n\n    status = PhCreateService(\n        &serviceHandle,\n        PhGetString(serviceName),\n        PhGetString(serviceName),\n        SERVICE_ALL_ACCESS,\n        SERVICE_WIN32_OWN_PROCESS,\n        SERVICE_DEMAND_START,\n        SERVICE_ERROR_IGNORE,\n        PhGetString(commandLine),\n        L\"LocalSystem\",\n        L\"\"\n        );\n\n    PhDereferenceObject(commandLine);\n    PhDereferenceObject(fileName);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhStartService(serviceHandle, 0, NULL);\n    PhDeleteService(serviceHandle);\n\n    portName = PhConcatStrings2(L\"\\\\BaseNamedObjects\\\\\", PhGetString(serviceName));\n    PhStringRefToUnicodeString(&portName->sr, &portNameUs);\n    attempts = 50;\n\n    // Try to connect several times because the server may take\n    // a while to initialize.\n    do\n    {\n        status = PhSvcConnectToServer(&portNameUs, 0);\n\n        if (NT_SUCCESS(status))\n            break;\n\n        PhDelayExecution(100);\n\n    } while (--attempts != 0);\n\n    PhDereferenceObject(portName);\n\n    PhCloseServiceHandle(serviceHandle);\n\n    return status;\n}\n\n/**\n * Restart the current process with optional additional command-line parameters\n * and process mitigation attributes set.\n *\n * The function obtains the current process command-line, appends the supplied\n * `AdditionalCommandLine` (if any), and creates a new process using\n * PhCreateProcessWin32Ex with hardened mitigation attributes where supported.\n *\n * \\param[in] AdditionalCommandLine Optional additional commandline to append.\n * \\return NTSTATUS of the attempted create; on success the current process\n *         exits via PhExitApplication(STATUS_SUCCESS) after successful spawn.\n */\nNTSTATUS PhRestartSelf(\n    _In_ PCPH_STRINGREF AdditionalCommandLine\n    )\n{\n    static ULONG64 mitigationFlags[] =\n    {\n#ifdef DEBUG\n        0, 0\n#else\n        (PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON |\n         PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON |\n         PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON |\n         PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON |\n         PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON |\n         PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON),\n        (PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON |\n         PROCESS_CREATION_MITIGATION_POLICY2_STRICT_CONTROL_FLOW_GUARD_ALWAYS_ON |\n         // PROCESS_CREATION_MITIGATION_POLICY2_BLOCK_NON_CET_BINARIES_ALWAYS_ON |\n         // PROCESS_CREATION_MITIGATION_POLICY2_XTENDED_CONTROL_FLOW_GUARD_ALWAYS_ON |\n         PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON)\n#endif\n    };\n    NTSTATUS status;\n    PPROC_THREAD_ATTRIBUTE_LIST attributeList = NULL;\n    PH_STRINGREF commandlineSr;\n    PPH_STRING commandline;\n    STARTUPINFOEX startupInfo;\n\n    status = PhGetProcessCommandLineStringRef(&commandlineSr);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    commandline = PhConcatStringRef2(\n        &commandlineSr,\n        AdditionalCommandLine\n        );\n\n    status = KsiSvcConnectToServer();\n    if (NT_SUCCESS(status))\n    {\n        status = PhSvcCallCreateProcessForKsi(PhGetString(commandline), mitigationFlags);\n        PhSvcDisconnectFromServer();\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        PhExitApplication(STATUS_SUCCESS);\n    }\n\n#ifndef DEBUG\n    status = PhInitializeProcThreadAttributeList(&attributeList, 1);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (WindowsVersion >= WINDOWS_10_22H2)\n    {\n        status = PhUpdateProcThreadAttribute(\n            attributeList,\n            PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,\n            mitigationFlags,\n            sizeof(ULONG64) * 2\n            );\n    }\n    else\n    {\n        status = PhUpdateProcThreadAttribute(\n            attributeList,\n            PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,\n            mitigationFlags,\n            sizeof(ULONG64) * 1\n            );\n    }\n#endif\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    memset(&startupInfo, 0, sizeof(STARTUPINFOEX));\n    startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX);\n    startupInfo.lpAttributeList = attributeList;\n\n    status = PhCreateProcessWin32Ex(\n        NULL,\n        PhGetString(commandline),\n        NULL,\n        NULL,\n        &startupInfo,\n        PH_CREATE_PROCESS_DEFAULT_ERROR_MODE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO,\n        NULL,\n        NULL,\n        NULL,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PhExitApplication(STATUS_SUCCESS);\n    }\n\n    if (attributeList)\n        PhDeleteProcThreadAttributeList(attributeList);\n\n    PhDereferenceObject(commandline);\n\n    return status;\n}\n\n/**\n * Obtain the configured KSI service name, falling back to default.\n *\n * \\return Referenced `PPH_STRING` containing the service name.\n */\nPPH_STRING PhGetKsiServiceName(\n    VOID\n    )\n{\n    PPH_STRING string;\n\n    string = PhGetStringSetting(SETTING_KSI_SERVICE_NAME);\n\n    if (PhIsNullOrEmptyString(string))\n    {\n        PhClearReference(&string);\n        string = PhCreateString(KPH_SERVICE_NAME);\n    }\n\n    return string;\n}\n\n/**\n * KPH communication callback used by KsiConnect configuration.\n *\n * The callback forwards the message to the informer dispatch and also,\n * when appropriate, forces a KPH cached required-state refresh when a\n * RequiredStateFailure message relates to the current process.\n *\n * \\param[in] ReplyToken Opaque reply token from KphComms.\n * \\param[in] Message Pointer to the KPH message to process.\n * \\return BOOLEAN value expected by KPH_COMMS_CALLBACK (TRUE/ FALSE).\n */\n_Function_class_(KPH_COMMS_CALLBACK)\nBOOLEAN KsiCommsCallback(\n    _In_ ULONG_PTR ReplyToken,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    if (Message->Header.MessageId == KphMsgRequiredStateFailure &&\n        Message->Kernel.RequiredStateFailure.ClientId.UniqueProcess == NtCurrentProcessId())\n    {\n        // force the cached value to be updated\n        KphLevelEx(FALSE);\n    }\n\n    return PhInformerDispatch(ReplyToken, Message);\n}\n\n/**\n * Read a configuration file located in the application directory.\n *\n * This opens and reads the entire file into a buffer allocated by the Ph\n * memory allocator. The caller receives ownership of `*Data` and must free it\n * via PhFree(). On success `*Length` receives the byte length of the buffer.\n *\n * \\param[in] FileName File name relative to application directory.\n * \\param[out] Data Receives pointer to allocated buffer with file contents.\n * \\param[out] Length Receives buffer length in bytes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS KsiReadConfiguration(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_ PBYTE* Data,\n    _Out_ PULONG Length\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName;\n    HANDLE fileHandle;\n\n    *Data = NULL;\n    *Length = 0;\n\n    if (fileName = PhGetApplicationDirectoryFileName(FileName, TRUE))\n    {\n        status = PhCreateFile(\n            &fileHandle,\n            &fileName->sr,\n            FILE_GENERIC_READ,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhGetFileData(fileHandle, Data, Length);\n            NtClose(fileHandle);\n        }\n\n        PhDereferenceObject(fileName);\n    }\n    else\n    {\n        status = STATUS_NO_SUCH_FILE;\n    }\n\n    return status;\n}\n\n/**\n * Validate dynamic configuration blob against the current kernel version.\n *\n * Performs a lookup using KphDynDataLookup matching the runtime kernel support\n * data (class, machine, timestamp, size) to ensure the provided dynamic\n * configuration applies to this kernel.\n *\n * \\param[in] DynData Pointer to dynamic configuration buffer.\n * \\param[in] DynDataLength Buffer length in bytes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS KsiValidateDynamicConfiguration(\n    _In_ PBYTE DynData,\n    _In_ ULONG DynDataLength\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName;\n    KSI_SUPPORT_DATA supportData;\n\n    if (fileName = KsiGetKernelFileName())\n    {\n        KsiGetKernelSupportData(&supportData);\n\n        status = KphDynDataLookup(\n            (PKPH_DYN_CONFIG)DynData,\n            DynDataLength,\n            supportData.Class,\n            supportData.Machine,\n            supportData.TimeDateStamp,\n            supportData.SizeOfImage,\n            NULL,\n            NULL\n            );\n\n        PhDereferenceObject(fileName);\n    }\n    else\n    {\n        status = STATUS_NO_SUCH_FILE;\n    }\n\n    return status;\n}\n\n/**\n * Retrieve the dynamic configuration and its signature.\n *\n * This routine attempts to read a local `ksidyn.bin` and `ksidyn.sig` files,\n * validate the dynamic configuration for the current kernel and return both\n * the data and signature buffers to the caller. Caller owns the returned\n * buffers and must free them using PhFree().\n *\n * \\param[out] DynData Receives pointer to allocated dynamic data buffer.\n * \\param[out] DynDataLength Receives the length of the dynamic data buffer.\n * \\param[out] Signature Receives pointer to allocated signature buffer.\n * \\param[out] SignatureLength Receives length of the signature buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS KsiGetDynData(\n    _Out_ PBYTE* DynData,\n    _Out_ PULONG DynDataLength,\n    _Out_ PBYTE* Signature,\n    _Out_ PULONG SignatureLength\n    )\n{\n    static CONST PH_STRINGREF dataFileName = PH_STRINGREF_INIT(L\"ksidyn.bin\");\n    static CONST PH_STRINGREF sigFileName = PH_STRINGREF_INIT(L\"ksidyn.sig\");\n    NTSTATUS status;\n    PBYTE data = NULL;\n    ULONG dataLength;\n    PBYTE sig = NULL;\n    ULONG sigLength;\n\n    // TODO download dynamic data from server\n\n    *DynData = NULL;\n    *DynDataLength = 0;\n    *Signature = NULL;\n    *SignatureLength = 0;\n\n    status = KsiReadConfiguration(&dataFileName, &data, &dataLength);\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = KsiValidateDynamicConfiguration(data, dataLength);\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = KsiReadConfiguration(&sigFileName, &sig, &sigLength);\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (!sigLength)\n    {\n        status = STATUS_SI_DYNDATA_INVALID_SIGNATURE;\n        goto CleanupExit;\n    }\n\n    *DynDataLength = dataLength;\n    *DynData = data;\n    data = NULL;\n\n    *SignatureLength = sigLength;\n    *Signature = sig;\n    sig = NULL;\n\n    status = STATUS_SUCCESS;\n\nCleanupExit:\n    if (data)\n        PhFree(data);\n    if (sig)\n        PhFree(sig);\n\n    return status;\n}\n\n/**\n * Retrieves and activates dynamic configuration data.\n *\n * \\param[in] WindowHandle Optional parent window for UI prompts.\n * \\param[in] Level Current KPH level.\n */\nVOID KsiActivateDynData(\n    _In_opt_ HWND WindowHandle,\n    _In_ KPH_LEVEL Level\n    )\n{\n    NTSTATUS status;\n    BOOLEAN showMessage;\n    PBYTE dynData = NULL;\n    ULONG dynDataLength;\n    PBYTE signature = NULL;\n    ULONG signatureLength;\n\n    showMessage = (Level < KphLevelHigh);\n\n    status = KsiGetDynData(\n        &dynData,\n        &dynDataLength,\n        &signature,\n        &signatureLength\n        );\n\n    if (!showMessage)\n    {\n        NOTHING;\n    }\n    else if (status == STATUS_SI_DYNDATA_UNSUPPORTED_KERNEL)\n    {\n#if defined(KSI_ONLINE_PLATFORM_SUPPORT)\n        KsiShowKernelSupportCheckDialog(WindowHandle);\n#else\n        if (PhGetPhReleaseChannel() < PhCanaryChannel)\n        {\n            PhShowKsiMessageEx(\n                WindowHandle,\n                TD_WARNING_ICON,\n                0,\n                FALSE,\n                L\"Reduced driver functionality\",\n                L\"The kernel driver is not yet supported on this kernel \"\n                L\"version. For the latest kernel support switch to the Canary \"\n                L\"update channel (Help > Check for updates > Canary > Check).\"\n                );\n        }\n        else\n        {\n            PhShowKsiMessageEx(\n                WindowHandle,\n                TD_WARNING_ICON,\n                0,\n                FALSE,\n                L\"Reduced driver functionality\",\n                L\"The kernel driver is not yet supported on this kernel \"\n                L\"version. Request support by submitting a GitHub issue with \"\n                L\"the Windows Kernel version.\"\n                );\n        }\n#endif\n    }\n    else if (status == STATUS_NO_SUCH_FILE)\n    {\n        PhShowKsiMessageEx(\n            WindowHandle,\n            TD_WARNING_ICON,\n            0,\n            FALSE,\n            L\"Reduced driver functionality\",\n            L\"The dynamic configuration was not found.\"\n            );\n    }\n    else if (!NT_SUCCESS(status))\n    {\n        PhShowKsiMessageEx(\n            WindowHandle,\n            TD_WARNING_ICON,\n            status,\n            FALSE,\n            L\"Reduced driver functionality\",\n            L\"Failed to access the dynamic configuration.\"\n            );\n    }\n\n    if (dynData && signature)\n    {\n        status = KphActivateDynData(dynData,\n                                    dynDataLength,\n                                    signature,\n                                    signatureLength);\n        if (showMessage && !NT_SUCCESS(status))\n        {\n            PhShowKsiMessageEx(\n                WindowHandle,\n                TD_WARNING_ICON,\n                status,\n                FALSE,\n                L\"Reduced driver functionality\",\n                L\"Failed to activate the dynamic configuration.\"\n                );\n        }\n    }\n\n    if (signature)\n        PhFree(signature);\n    if (dynData)\n        PhFree(dynData);\n}\n\n/**\n * Determine the on-disk kernel driver filename for the current application context.\n *\n * \\return Referenced `PPH_STRING` containing the full driver filename.\n */\nPPH_STRING PhGetKsiFileName(\n    VOID\n    )\n{\n    PPH_STRING applicationDirectory;\n    PPH_STRING fileName;\n\n#if defined(PH_BUILD_MSIX)\n    PH_FORMAT format[4];\n    PhInitFormatS(&format[0], L\"\\\\Drivers\");\n    PhInitFormatS(&format[1], L\"\\\\SystemInformer\");\n    PhInitFormatS(&format[2], L\"\\\\SystemInformer\");\n    PhInitFormatSR(&format[3], DriverExtension);\n    fileName = PhFormat(format, RTL_NUMBER_OF(format), MAX_PATH);\n    applicationDirectory = PhGetSystemDirectoryWin32(&fileName->sr);\n    PhDereferenceObject(fileName);\n#else\n    fileName = PhGetApplicationFileNameWin32();\n    applicationDirectory = PhGetBaseNameChangeExtension(&fileName->sr, &DriverExtension);\n    PhDereferenceObject(fileName);\n#endif\n\n    return applicationDirectory;\n}\n\n/**\n * Get a temporary directory suitable for creating temporary files.\n *\n * Returns a referenced `PPH_STRING` representing the temporary directory\n * for the running application context.\n */\nPPH_STRING PhGetTemporaryKsiDirectory(\n    VOID\n    )\n{\n    PPH_STRING applicationDirectory;\n\n#if defined(PH_BUILD_MSIX)\n    applicationDirectory = PhGetLocalAppDataDirectoryZ(L\"temp-drivers\\\\\", FALSE);\n#else\n    applicationDirectory = PhGetApplicationDirectoryFileNameZ(L\"temp-drivers\\\\\", FALSE);\n#endif\n\n    return applicationDirectory;\n}\n\n/**\n * Create a temporary copy of a driver file in the specified temporary directory.\n *\n * The function generates a filename based on the current system time, ensures\n * the directory exists and copies `FileName` into `TempDirectory`. On success\n * returns a referenced `PPH_STRING` in `*TempFileName` (caller owns reference).\n *\n * \\param[in] FileName Existing driver filename to copy.\n * \\param[in] TempDirectory Directory to create the temporary file in.\n * \\param[out] TempFileName Receives referenced `PPH_STRING` of the created file.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS KsiCreateTemporaryDriverFile(\n    _In_ PPH_STRING FileName,\n    _In_ PPH_STRING TempDirectory,\n    _Out_ PPH_STRING* TempFileName\n    )\n{\n    NTSTATUS status;\n    PH_FORMAT format[4];\n    PPH_STRING tempFileName;\n    LARGE_INTEGER timeStamp;\n\n    *TempFileName = NULL;\n\n    PhQuerySystemTime(&timeStamp);\n\n    PhInitFormatSR(&format[0], TempDirectory->sr);\n    PhInitFormatS(&format[1], L\"SystemInformer\");\n    PhInitFormatI64X(&format[2], timeStamp.QuadPart);\n    PhInitFormatSR(&format[3], DriverExtension);\n\n    tempFileName = PhFormat(format, RTL_NUMBER_OF(format), MAX_PATH);\n\n    if (NT_SUCCESS(status = PhCreateDirectoryWin32(&TempDirectory->sr)))\n    {\n        if (NT_SUCCESS(status = PhCopyFileWin32(PhGetString(FileName), PhGetString(tempFileName), TRUE)))\n        {\n            *TempFileName = tempFileName;\n            tempFileName = NULL;\n        }\n    }\n\n    PhClearReference(&tempFileName);\n\n    return status;\n}\n\n/**\n * Connect to the kernel driver using the configured dynamic configuration.\n *\n * This function orchestrates reading dynamic configuration, validating it,\n * ensuring the driver file exists, and attempting connection with multiple\n * fallback strategies (temporary copy, service, NtLoadDriver etc...).\n *\n * \\param[in] WindowHandle Optional parent window for UI prompts.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS KsiConnect(\n    _In_opt_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n    PPH_STRING ksiFileName = NULL;\n    KPH_CONFIG_PARAMETERS config = { 0 };\n    PPH_STRING objectName = NULL;\n    PPH_STRING portName = NULL;\n    PPH_STRING altitude = NULL;\n    PPH_STRING systemProcessName = NULL;\n    PPH_STRING tempDriverDir = NULL;\n    KPH_LEVEL level;\n\n    if (tempDriverDir = PhGetTemporaryKsiDirectory())\n    {\n        PhDeleteDirectoryWin32(&tempDriverDir->sr);\n    }\n\n    if (!PhDoesFileExistWin32(PhGetString(KsiFileName)))\n    {\n        PhShowKsiMessageEx(\n            WindowHandle,\n            TD_SHIELD_ERROR_ICON,\n            0,\n            FALSE,\n            L\"Unable to load kernel driver\",\n            L\"The kernel driver was not found.\"\n            );\n        status = STATUS_NOT_FOUND;\n        goto CleanupExit;\n    }\n\n    if (PhIsNullOrEmptyString(portName = PhGetStringSetting(SETTING_KSI_PORT_NAME)))\n        PhClearReference(&portName);\n    if (PhIsNullOrEmptyString(altitude = PhGetStringSetting(SETTING_KSI_ALTITUDE)))\n        PhClearReference(&altitude);\n    if (PhIsNullOrEmptyString(systemProcessName = PhGetStringSetting(SETTING_KSI_SYSTEM_PROCESS_NAME)))\n        PhClearReference(&systemProcessName);\n\n    config.FileName = &KsiFileName->sr;\n    config.ServiceName = &KsiServiceName->sr;\n    config.ObjectName = &KsiObjectName->sr;\n    config.PortName = (portName ? &portName->sr : NULL);\n    config.Altitude = (altitude ? &altitude->sr : NULL);\n    config.SystemProcessName = (systemProcessName ? &systemProcessName->sr : NULL);\n    config.FsSupportedFeatures = 0;\n    if (!!PhGetIntegerSetting(SETTING_KSI_ENABLE_FS_FEATURE_OFFLOAD_READ))\n        SetFlag(config.FsSupportedFeatures, SUPPORTED_FS_FEATURES_OFFLOAD_READ);\n    if (!!PhGetIntegerSetting(SETTING_KSI_ENABLE_FS_FEATURE_OFFLOAD_WRITE))\n        SetFlag(config.FsSupportedFeatures, SUPPORTED_FS_FEATURES_OFFLOAD_WRITE);\n    if (!!PhGetIntegerSetting(SETTING_KSI_ENABLE_FS_FEATURE_QUERY_OPEN))\n        SetFlag(config.FsSupportedFeatures, SUPPORTED_FS_FEATURES_QUERY_OPEN);\n    if (!!PhGetIntegerSetting(SETTING_KSI_ENABLE_FS_FEATURE_BYPASS_IO))\n        SetFlag(config.FsSupportedFeatures, SUPPORTED_FS_FEATURES_BYPASS_IO);\n    config.Flags.Flags = 0;\n    config.Flags.DisableImageLoadProtection = !!PhGetIntegerSetting(SETTING_KSI_DISABLE_IMAGE_LOAD_PROTECTION);\n    config.Flags.RandomizedPoolTag = !!PhGetIntegerSetting(SETTING_KSI_RANDOMIZED_POOL_TAG);\n    config.Flags.DynDataNoEmbedded = !!PhGetIntegerSetting(SETTING_KSI_DYN_DATA_NO_EMBEDDED);\n    config.Flags.DisableSystemProcess = !!PhGetIntegerSetting(SETTING_KSI_DISABLE_SYSTEM_PROCESS);\n    config.Flags.DisableThreadNames = !!PhGetIntegerSetting(SETTING_KSI_DISABLE_THREAD_NAMES);\n    config.EnableNativeLoad = KsiEnableLoadNative;\n    config.EnableFilterLoad = KsiEnableLoadFilter;\n    config.RingBufferLength = PhGetIntegerSetting(SETTING_KSI_RING_BUFFER_LENGTH);\n    config.Callback = KsiCommsCallback;\n\n    status = KphConnect(&config);\n\n    if (status == STATUS_NO_SUCH_FILE)\n    {\n        PPH_STRING tempFileName;\n\n        //\n        // N.B. We know the driver file exists from the check above. This\n        // error indicates that the kernel driver is still mapped but\n        // unloaded.\n        //\n        // The chain of calls and resulting return status is this:\n        // IopLoadDriver\n        // -> MmLoadSystemImage -> STATUS_IMAGE_ALREADY_LOADED\n        // -> ObOpenObjectByName -> STATUS_OBJECT_NAME_NOT_FOUND\n        // -> STATUS_DRIVER_FAILED_PRIOR_UNLOAD -> STATUS_NO_SUCH_FILE\n        //\n        // The driver object has been made temporary and the underlying\n        // section will be unmapped by the kernel when it is safe to do so.\n        // This generally happens when the pinned module is holding the\n        // driver in memory until some code finishes executing. This can\n        // also happen if another misbehaving driver is leaking or holding\n        // a reference to the driver object.\n        //\n        // To continue to provide a good user experience, we will attempt copy\n        // the driver to another file and load it again. First, try to use an\n        // existing temporary driver file, if one exists.\n        //\n\n        tempFileName = PhGetStringSetting(SETTING_KSI_PREVIOUS_TEMPORARY_DRIVER_FILE);\n        if (tempFileName)\n        {\n            if (PhDoesFileExistWin32(PhGetString(tempFileName)))\n            {\n                config.FileName = &tempFileName->sr;\n\n                status = KphConnect(&config);\n            }\n\n            PhMoveReference(&KsiFileName, tempFileName);\n        }\n\n        if (!NT_SUCCESS(status) && tempDriverDir)\n        {\n            if (NT_SUCCESS(status = KsiCreateTemporaryDriverFile(ksiFileName, tempDriverDir, &tempFileName)))\n            {\n                PhSetStringSetting(SETTING_KSI_PREVIOUS_TEMPORARY_DRIVER_FILE, PhGetString(tempFileName));\n\n                config.FileName = &tempFileName->sr;\n\n                status = KphConnect(&config);\n\n                PhMoveReference(&KsiFileName, tempFileName);\n            }\n        }\n    }\n\n    if (status == STATUS_SI_KSIDLL_VERSION_MISMATCH)\n    {\n        PhShowKsiMessageEx(\n            NULL,\n            TD_SHIELD_ERROR_ICON,\n            STATUS_SI_KSIDLL_VERSION_MISMATCH,\n            FALSE,\n            L\"Unable to load kernel driver\",\n            L\"The last System Informer update requires a reboot.\"\n            );\n            goto CleanupExit;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PPH_STRING randomServiceName;\n        PPH_STRING randomPortName;\n        PPH_STRING randomObjectName;\n        PPH_STRING randomAltitude;\n\n        //\n        // Malware might be blocking the driver load. Offer the user a chance\n        // to try again with a different method.\n        //\n        if (PhShowKsiMessage2(\n            WindowHandle,\n            TD_YES_BUTTON | TD_NO_BUTTON,\n            TD_SHIELD_ERROR_ICON,\n            status,\n            FALSE,\n            L\"Unable to load kernel driver\",\n            L\"Try again with alternate driver load method?\"\n            ) != IDYES)\n        {\n            goto CleanupExit;\n        }\n\n        KsiCreateRandomizedName(L\"\", &randomServiceName, FALSE);\n        KsiCreateRandomizedName(L\"\\\\\", &randomPortName, FALSE);\n        KsiCreateRandomizedName(L\"\\\\Driver\\\\\", &randomObjectName, FALSE);\n        KsiCreateRandomizedName(L\"385210.5\", &randomAltitude, TRUE);\n\n        config.EnableNativeLoad = TRUE;\n        config.EnableFilterLoad = FALSE;\n        config.ServiceName = &randomServiceName->sr;\n        config.PortName = &randomPortName->sr;\n        config.ObjectName = &randomObjectName->sr;\n        config.Altitude = &randomAltitude->sr;\n\n        PhMoveReference(&KsiServiceName, PhReferenceObject(randomServiceName));\n        PhMoveReference(&KsiObjectName, PhReferenceObject(randomObjectName));\n        KsiEnableLoadNative = TRUE;\n        KsiEnableLoadFilter = FALSE;\n\n        status = KphConnect(&config);\n\n        if (NT_SUCCESS(status))\n        {\n            //\n            // N.B. These settings **must** be persisted to allow subsequent\n            // clients to successfully connect or unload the natively loaded\n            // driver.\n            //\n            PhSetIntegerSetting(SETTING_KSI_ENABLE_LOAD_NATIVE, TRUE);\n            PhSetIntegerSetting(SETTING_KSI_ENABLE_LOAD_FILTER, FALSE);\n            PhSetStringSetting2(SETTING_KSI_SERVICE_NAME, &randomServiceName->sr);\n            PhSetStringSetting2(SETTING_KSI_PORT_NAME, &randomPortName->sr);\n            PhSetStringSetting2(SETTING_KSI_OBJECT_NAME, &randomObjectName->sr);\n            PhSetStringSetting2(SETTING_KSI_ALTITUDE, &randomAltitude->sr);\n\n            PhSaveSettings2(PhSettingsFileName);\n\n            PhShowKsiMessage(\n                WindowHandle,\n                TD_INFORMATION_ICON,\n                L\"Kernel driver loaded\",\n                L\"The kernel driver was successfully loaded using an alternate \"\n                L\"method. The settings used to load the driver have been saved. \"\n                L\"You can revert these settings in the advanced options.\"\n                );\n        }\n\n        PhDereferenceObject(randomServiceName);\n        PhDereferenceObject(randomPortName);\n        PhDereferenceObject(randomObjectName);\n        PhDereferenceObject(randomAltitude);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowKsiMessageEx(\n            WindowHandle,\n            TD_SHIELD_ERROR_ICON,\n            status,\n            FALSE,\n            L\"Unable to load kernel driver\",\n            L\"Unable to load the kernel driver service.\"\n            );\n        goto CleanupExit;\n    }\n\n    level = KphLevelEx(FALSE);\n\n    KsiActivateDynData(WindowHandle, level);\n\n    if (!NtCurrentPeb()->BeingDebugged && (level != KphLevelMax))\n    {\n        if ((level == KphLevelHigh) &&\n            !PhStartupParameters.KphStartupMax)\n        {\n            static CONST PH_STRINGREF commandline = PH_STRINGREF_INIT(L\" -kx\");\n            status = PhRestartSelf(&commandline);\n        }\n\n        if ((level < KphLevelHigh) &&\n            !PhStartupParameters.KphStartupMax &&\n            !PhStartupParameters.KphStartupHigh)\n        {\n            static CONST PH_STRINGREF commandline = PH_STRINGREF_INIT(L\" -kh\");\n            status = PhRestartSelf(&commandline);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhShowKsiMessageEx(\n                WindowHandle,\n                TD_ERROR_ICON,\n                status,\n                FALSE,\n                L\"Unable to load kernel driver\",\n                L\"Unable to restart.\"\n                );\n            goto CleanupExit;\n        }\n    }\n\n    if (level == KphLevelMax)\n    {\n        ACCESS_MASK process = 0;\n        ACCESS_MASK thread = 0;\n\n        if (PhGetIntegerSetting(SETTING_KSI_ENABLE_UNLOAD_PROTECTION))\n            KphAcquireDriverUnloadProtection(NULL, NULL);\n\n        switch (PhGetIntegerSetting(SETTING_KSI_CLIENT_PROCESS_PROTECTION_LEVEL))\n        {\n        case 2:\n            process |= (PROCESS_VM_READ | PROCESS_QUERY_INFORMATION);\n            thread |= (THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION);\n            __fallthrough;\n        case 1:\n            process |= (PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME);\n            thread |= (THREAD_TERMINATE | THREAD_SUSPEND_RESUME | THREAD_RESUME);\n            __fallthrough;\n        case 0:\n        default:\n            break;\n        }\n\n        if (process != 0 || thread != 0)\n            KphStripProtectedProcessMasks(NtCurrentProcess(), process, thread);\n    }\n\n    PhInformerActivate();\n\n    status = STATUS_SUCCESS;\n\nCleanupExit:\n\n    PhClearReference(&objectName);\n    PhClearReference(&portName);\n    PhClearReference(&altitude);\n    PhClearReference(&ksiFileName);\n    PhClearReference(&tempDriverDir);\n\n#ifdef DEBUG\n    KsiDebugLogInitialize();\n#endif\n\n    return status;\n}\n\n/**\n * Thread callback routine that initializes KSI and notifies the originating window.\n * \\param[in] CallbackContext Optional HWND passed as a void*; if provided\n * the routine sends TDM_CLICK_BUTTON to the window when initialization completes.\n * \\return NTSTATUS Successful or errant status.\n */\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS KsiInitializeCallbackThread(\n    _In_opt_ PVOID CallbackContext\n    )\n{\n#ifdef KSI_DEBUG_DELAY_SPLASHSCREEN\n    if (CallbackContext) PhDelayExecution(1000);\n#endif\n\n    KsiConnect(CallbackContext);\n\n    if (CallbackContext)\n    {\n        SendMessage(CallbackContext, TDM_CLICK_BUTTON, IDOK, 0);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Dialog callback invoked by the splash screen TaskDialogIndirect.\n *\n * Handles creation notification by spawning the initialization thread and\n * updates marquee/timer UI. Also handles cancel button to abort the dialog.\n *\n * \\param[in] WindowHandle HWND of the task dialog.\n * \\param[in] Notification Task dialog notification code.\n * \\param[in] wParam Notification-specific parameter.\n * \\param[in] lParam Notification-specific parameter.\n * \\param[in] Context User defined context pointer (unused).\n * \\return HRESULT S_OK to continue default processing, S_FALSE to abort dialog.\n */\nstatic HRESULT CALLBACK KsiSplashScreenDialogCallbackProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT Notification,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR Context\n    )\n{\n    switch (Notification)\n    {\n    case TDN_CREATED:\n        {\n            NTSTATUS status;\n            HANDLE threadHandle;\n\n            SendMessage(WindowHandle, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n            SendMessage(WindowHandle, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n\n            if (NT_SUCCESS(status = PhCreateThreadEx(\n                &threadHandle,\n                KsiInitializeCallbackThread,\n                WindowHandle\n                )))\n            {\n                NtClose(threadHandle);\n            }\n            else\n            {\n                PhShowStatus(WindowHandle, L\"Unable to create the window.\", status, 0);\n            }\n        }\n        break;\n    case TDN_BUTTON_CLICKED:\n        {\n            INT buttonId = (INT)wParam;\n\n            if (buttonId == IDCANCEL)\n            {\n                return S_FALSE;\n            }\n        }\n        break;\n    case TDN_TIMER:\n        {\n            ULONG ticks = (ULONG)wParam;\n            PPH_STRING timeSpan = PhFormatUInt64(ticks, TRUE);\n            PhMoveReference(&timeSpan, PhConcatStringRefZ(&timeSpan->sr, L\" ms...\"));\n            SendMessage(WindowHandle, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)timeSpan->Buffer);\n            PhDereferenceObject(timeSpan);\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\n/**\n * Display a splash screen while the kernel driver initializes.\n *\n * This function configures and invokes a TaskDialogIndirect with a marquee\n * progress bar and callback to spawn the initialization thread.\n */\nVOID KsiShowInitializingSplashScreen(\n    VOID\n    )\n{\n    TASKDIALOGCONFIG config;\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_USE_HICON_MAIN | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CAN_BE_MINIMIZED | TDF_CALLBACK_TIMER;\n    config.dwCommonButtons = TDCBF_CANCEL_BUTTON;\n    config.hMainIcon = PhGetApplicationIcon(FALSE);\n    config.pfCallback = KsiSplashScreenDialogCallbackProc;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainInstruction = L\"Initializing System Informer kernel driver...\";\n    config.pszContent = L\"0 ms...\";\n    config.cxWidth = 200;\n\n    TaskDialogIndirect(&config, NULL, NULL, NULL);\n}\n\n/**\n * Initialize the KSI subsystem for the application.\n *\n * Checks preconditions (elevation, OS version, architecture, old leftover\n * files) and then initializes underlying Kph and informer subsystems. If the\n * splash-screen setting is enabled the initialization will be done asynchronously\n * with a UI; otherwise initialization is performed synchronously.\n */\nVOID PhInitializeKsi(\n    VOID\n    )\n{\n    if (!PhGetOwnTokenAttributes().Elevated)\n        return;\n\n    if (WindowsVersion < WINDOWS_10)\n    {\n        PhShowKsiMessageEx(\n            NULL,\n            TD_SHIELD_ERROR_ICON,\n            0,\n            FALSE,\n            L\"Unable to load kernel driver\",\n            L\"The kernel driver is not supported on this Windows version, the \"\n            L\"minimum supported version is Windows 10.\"\n            );\n        return;\n    }\n\n    if (PhIsExecutingInWow64())\n    {\n        PhShowKsiMessageEx(\n            NULL,\n            TD_SHIELD_ERROR_ICON,\n            0,\n            FALSE,\n            L\"Unable to load kernel driver\",\n            L\"The kernel driver is not supported under Wow64, use the native \"\n            \"binary instead.\"\n            );\n        return;\n    }\n\n    if (USER_SHARED_DATA->NativeProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64 &&\n        USER_SHARED_DATA->NativeProcessorArchitecture != PROCESSOR_ARCHITECTURE_ARM64)\n    {\n        PhShowKsiMessageEx(\n            NULL,\n            TD_SHIELD_ERROR_ICON,\n            0,\n            FALSE,\n            L\"Unable to load kernel driver\",\n            L\"The kernel driver is not supported on this architecture.\"\n            );\n        return;\n    }\n\n    KphInitialize();\n    PhInformerInitialize();\n\n    KsiFileName = PhGetKsiFileName();\n    KsiServiceName = PhGetKsiServiceName();\n    if (PhIsNullOrEmptyString(KsiObjectName = PhGetStringSetting(SETTING_KSI_OBJECT_NAME)))\n        PhMoveReference(&KsiObjectName, PhCreateString(KPH_OBJECT_NAME));\n    KsiEnableLoadNative = !!PhGetIntegerSetting(SETTING_KSI_ENABLE_LOAD_NATIVE);\n    KsiEnableLoadFilter = !!PhGetIntegerSetting(SETTING_KSI_ENABLE_LOAD_FILTER);\n\n    if (PhGetIntegerSetting(SETTING_KSI_ENABLE_SPLASH_SCREEN))\n        KsiShowInitializingSplashScreen();\n    else\n        KsiInitializeCallbackThread(NULL);\n}\n\n/**\n * Cleanup KSI subsystems and optionally unload the driver on exit.\n *\n * If the communications channel is connected this will stop communications and,\n * depending on settings and client count, attempt to stop and unload the\n * driver service. Returns the NTSTATUS of the unload operation when attempted.\n * \\return STATUS_SUCCESS when no unload required or unload succeeded, otherwise\n *         an NTSTATUS indicating the error encountered during service stop.\n */\nNTSTATUS PhCleanupKsi(\n    VOID\n    )\n{\n    NTSTATUS status;\n    KPH_CONFIG_PARAMETERS config = { 0 };\n    BOOLEAN shouldUnload;\n\n    if (!KphCommsIsConnected())\n        return STATUS_SUCCESS;\n\n    if (PhGetIntegerSetting(SETTING_KSI_ENABLE_UNLOAD_PROTECTION))\n        KphReleaseDriverUnloadProtection(NULL, NULL);\n\n    //\n    // N.B. Portable mode doesn't use the updater which will unload the driver\n    // on upgrades. In portable mode updates happen by the user so we should\n    // always unload the driver on exit. It also really doesn't make sense to\n    // keep the driver loaded in a portable configuration.\n    //\n    if (PhPortableEnabled || PhGetIntegerSetting(SETTING_KSI_UNLOAD_ON_EXIT))\n    {\n        ULONG clientCount;\n\n        if (!NT_SUCCESS(status = KphGetConnectedClientCount(&clientCount)))\n            return status;\n\n        shouldUnload = (clientCount == 1);\n    }\n    else\n    {\n        shouldUnload = FALSE;\n    }\n\n    KphCommsStop();\n#ifdef DEBUG\n    KsiDebugLogFinalize();\n#endif\n\n    if (!shouldUnload)\n        return STATUS_SUCCESS;\n\n    config.FileName = &KsiFileName->sr;\n    config.ServiceName = &KsiServiceName->sr;\n    config.ObjectName = &KsiObjectName->sr;\n    config.EnableNativeLoad = KsiEnableLoadNative;\n    config.EnableFilterLoad = KsiEnableLoadFilter;\n    status = KphServiceStop(&config);\n\n    return status;\n}\n\n/**\n * Parse a hex-encoded JSON settings blob to extract KSI settings.\n *\n * The function decodes the hex string stored in `KsiSettingsBlob`, parses the\n * JSON and extracts \"KsiDirectory\" and \"KsiServiceName\" entries. If both are\n * present the function sets `*Directory` and `*ServiceName` to referenced\n * strings that the caller must dereference.\n *\n * \\param[in] KsiSettingsBlob Hex-encoded buffer stored as a PPH_STRING.\n * \\param[out] Directory Receives referenced `PPH_STRING` of the directory.\n * \\param[out] ServiceName Receives referenced `PPH_STRING` of the service name.\n * \\return TRUE if both values were found and returned, FALSE otherwise.\n */\n_Success_(return)\nBOOLEAN PhParseKsiSettingsBlob(\n    _In_ PPH_STRING KsiSettingsBlob,\n    _Out_ PPH_STRING* Directory,\n    _Out_ PPH_STRING* ServiceName\n    )\n{\n    PPH_STRING directory = NULL;\n    PPH_STRING serviceName = NULL;\n    PSTR string;\n    ULONG stringLength;\n    PPH_BYTES value;\n    PVOID object;\n\n    stringLength = (ULONG)KsiSettingsBlob->Length / sizeof(WCHAR) / 2;\n    string = PhAllocateZero(stringLength + sizeof(UNICODE_NULL));\n\n    if (PhHexStringToBufferEx(&KsiSettingsBlob->sr, stringLength, string))\n    {\n        value = PhCreateBytesEx(string, stringLength);\n\n        if (NT_SUCCESS(PhCreateJsonParserEx(&object, value, FALSE)))\n        {\n            directory = PhGetJsonValueAsString(object, \"KsiDirectory\");\n            serviceName = PhGetJsonValueAsString(object, \"KsiServiceName\");\n            PhFreeJsonObject(object);\n        }\n\n        PhDereferenceObject(value);\n    }\n\n    PhFree(string);\n\n    if (!PhIsNullOrEmptyString(directory) &&\n        !PhIsNullOrEmptyString(serviceName))\n    {\n        *Directory = directory;\n        *ServiceName = serviceName;\n        return TRUE;\n    }\n\n    PhClearReference(&serviceName);\n    PhClearReference(&directory);\n    return FALSE;\n}\n\n// Note: Exported from appsup.h (dmex)\n/**\n * Create a small configuration blob containing the KSI directory and service name.\n *\n * This helper constructs a JSON object containing the current `KsiDirectory`\n * and `KsiServiceName`, converts it to a UTF-8 JSON string, and returns the\n * value encoded as a hex string `PPH_STRING`. The returned string is a\n * referenced object and the caller must free it.\n * \\return Referenced `PPH_STRING` containing the hex-encoded JSON settings.\n */\nPVOID PhCreateKsiSettingsBlob(\n    VOID\n    )\n{\n    PVOID object;\n    PPH_BYTES value;\n    PPH_STRING string;\n    PPH_STRING directory;\n    PPH_STRING serviceName;\n\n    object = PhCreateJsonObject();\n\n#if defined(PH_BUILD_MSIX)\n    PPH_STRING fileName;\n    PH_FORMAT format[4];\n    PhInitFormatS(&format[0], L\"\\\\Drivers\");\n    PhInitFormatS(&format[1], L\"\\\\SystemInformer\");\n    fileName = PhFormat(format, RTL_NUMBER_OF(format), MAX_PATH);\n    directory = PhGetSystemDirectoryWin32(&fileName->sr);\n    PhDereferenceObject(fileName);\n#else\n    directory = PhGetApplicationDirectoryWin32();\n#endif\n    value = PhConvertStringToUtf8(directory);\n    PhAddJsonObject2(object, \"KsiDirectory\", value->Buffer, value->Length);\n    PhDereferenceObject(value);\n    PhDereferenceObject(directory);\n\n    serviceName = PhGetKsiServiceName();\n    value = PhConvertStringToUtf8(serviceName);\n    PhAddJsonObject2(object, \"KsiServiceName\", value->Buffer, value->Length);\n    PhDereferenceObject(value);\n    PhDereferenceObject(serviceName);\n\n    value = PhGetJsonArrayString(object, FALSE);\n    string = PhBufferToHexString((PUCHAR)value->Buffer, (ULONG)value->Length);\n    PhDereferenceObject(value);\n\n    PhFreeJsonObject(object);\n\n    return string;\n}\n\n/**\n * Measures latency of the KPH driver using its performance counter interface.\n *\n * If the current KSI level is below KphLevelLow, the function sets all output\n * values to zero and returns STATUS_UNSUCCESSFUL. Otherwise it queries the KPH\n * performance counter and measures timestamps before and after the kernel call\n * to compute:\n *\n *  - Duration:     Total round-trip time (local wall clock)\n *  - DurationDown: Time spent entering the kernel (downstream)\n *  - DurationUp:   Time spent returning from the kernel (upstream)\n *\n * \\param[out] Duration      Total measured duration.\n * \\param[out] DurationDown  Time spent sending the request to the kernel.\n * \\param[out] DurationUp    Time spent recieving the response from the kernel.\n * \\return NTSTATUS from KphQueryPerformanceCounter, or STATUS_UNSUCCESSFUL.\n * \\remarks Use this function when you need a kernel-reported high-resolution\n * timebase to measure or correlate user/kernel timing.\n */\nNTSTATUS PhQueryKphCounters(\n    _Out_ PULONG64 Duration,\n    _Out_ PULONG64 DurationDown,\n    _Out_ PULONG64 DurationUp\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER performanceCounterStart;\n    LARGE_INTEGER performanceCounterStop;\n    LARGE_INTEGER performanceCounter;\n    ULONG64 performanceCounterDuration;\n    ULONG64 performanceCounterDown;\n    ULONG64 performanceCounterUp;\n\n    if (KsiLevel() < KphLevelLow)\n    {\n        *Duration = 0;\n        *DurationDown = 0;\n        *DurationUp = 0;\n        status = STATUS_UNSUCCESSFUL;\n    }\n    else\n    {\n        PhQueryPerformanceCounter(&performanceCounterStart);\n        status = KphQueryPerformanceCounter(&performanceCounter, NULL);\n        PhQueryPerformanceCounter(&performanceCounterStop);\n\n        performanceCounterDuration = performanceCounterStop.QuadPart - performanceCounterStart.QuadPart;\n        performanceCounterDown = performanceCounter.QuadPart - performanceCounterStart.QuadPart;\n        performanceCounterUp = performanceCounterStop.QuadPart - performanceCounter.QuadPart;\n\n        *Duration = performanceCounterDuration;\n        *DurationDown = performanceCounterDown;\n        *DurationUp = performanceCounterUp;\n    }\n\n    return status;\n}\n\n#if defined(KSI_ONLINE_PLATFORM_SUPPORT)\nPPH_STRING KsiCreateBuildString(\n    VOID\n    )\n{\n    static const PH_STRINGREF versionHeader = PH_STRINGREF_INIT(L\"KsiBuild: \");\n    ULONG majorVersion;\n    ULONG minorVersion;\n    ULONG buildVersion;\n    ULONG revisionVersion;\n    SIZE_T returnLength;\n    PH_FORMAT format[8];\n    WCHAR formatBuffer[260];\n\n    PhGetPhVersionNumbers(&majorVersion, &minorVersion, &buildVersion, &revisionVersion);\n    PhInitFormatSR(&format[0], versionHeader);\n    PhInitFormatU(&format[1], majorVersion);\n    PhInitFormatC(&format[2], L'.');\n    PhInitFormatU(&format[3], minorVersion);\n    PhInitFormatC(&format[4], L'.');\n    PhInitFormatU(&format[5], buildVersion);\n    PhInitFormatC(&format[6], L'.');\n    PhInitFormatU(&format[7], revisionVersion);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), &returnLength))\n    {\n        PH_STRINGREF stringFormat;\n\n        stringFormat.Buffer = formatBuffer;\n        stringFormat.Length = returnLength - sizeof(UNICODE_NULL);\n\n        return PhCreateString2(&stringFormat);\n    }\n    else\n    {\n        return PhFormat(format, RTL_NUMBER_OF(format), 0);\n    }\n}\n\nNTSTATUS KsiCreatePlatformSupportInformation(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_ PUSHORT ImageMachine,\n    _Out_ PULONG TimeDateStamp,\n    _Out_ PULONG SizeOfImage,\n    _Out_writes_bytes_to_(OutputLength, *ReturnLength) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    USHORT imageMachine;\n    ULONG imageDateStamp;\n    ULONG imageSizeOfImage;\n    PH_MAPPED_IMAGE mappedImage;\n    LARGE_INTEGER fileSize;\n    PH_HASH_CONTEXT hashContext;\n    ULONG64 bytesRemaining;\n    ULONG numberOfBytesRead;\n    ULONG bufferLength;\n    PBYTE buffer;\n    UCHAR hash[PH_HASH_SHA256_LENGTH];\n\n    status = PhCreateFile(\n        &fileHandle,\n        FileName,\n        FILE_GENERIC_READ,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetFileSize(fileHandle, &fileSize);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhInitializeHash(&hashContext, Sha256HashAlgorithm);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    bufferLength = PAGE_SIZE * 2;\n    buffer = PhAllocateSafe(bufferLength);\n\n    if (!buffer)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto CleanupExit;\n    }\n\n    bytesRemaining = (ULONG64)fileSize.QuadPart;\n\n    while (bytesRemaining)\n    {\n        status = PhReadFile(\n            fileHandle,\n            buffer,\n            bufferLength,\n            NULL,\n            &numberOfBytesRead\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        status = PhUpdateHash(\n            &hashContext,\n            buffer,\n            numberOfBytesRead\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        bytesRemaining -= numberOfBytesRead;\n    }\n\n    PhFree(buffer);\n\n    status = PhFinalHash(\n        &hashContext,\n        hash,\n        sizeof(hash),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (!PhBufferToHexStringBuffer(\n        hash,\n        sizeof(hash),\n        FALSE,\n        OutputBuffer,\n        OutputLength,\n        ReturnLength\n        ))\n    {\n        status = STATUS_FAIL_CHECK;\n        goto CleanupExit;\n    }\n\n    status = PhLoadMappedImageHeaderPageSize(\n        NULL,\n        fileHandle,\n        &mappedImage\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    __try\n    {\n        imageMachine = mappedImage.NtHeaders->FileHeader.Machine;\n        imageDateStamp = mappedImage.NtHeaders->FileHeader.TimeDateStamp;\n        imageSizeOfImage = mappedImage.NtHeaders->OptionalHeader.SizeOfImage;\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n    }\n\n    PhUnloadMappedImage(&mappedImage);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (NT_SUCCESS(status))\n    {\n        *ImageMachine = imageMachine;\n        *TimeDateStamp = imageDateStamp;\n        *SizeOfImage = imageSizeOfImage;\n\n        NtClose(fileHandle);\n        return STATUS_SUCCESS;\n    }\n\nCleanupExit:\n    NtClose(fileHandle);\n    return status;\n}\n\ntypedef struct _KSI_PLATFORM_BUILD_ENTRY\n{\n    USHORT Class;\n    PH_STRINGREF FileName;\n} KSI_PLATFORM_BUILD_ENTRY, *PKSI_PLATFORM_BUILD_ENTRY;\n\nPPH_STRING KsiCreatePlatformBuildString(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF platformHeader = PH_STRINGREF_INIT(L\"KsiPlatformSupport: \");\n    static CONST KSI_PLATFORM_BUILD_ENTRY platformFiles[] =\n    {\n        { KPH_DYN_CLASS_NTOSKRNL, PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\ntoskrnl.exe\") },\n        { KPH_DYN_CLASS_NTKRLA57, PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\ntkrla57.exe\") },\n        { KPH_DYN_CLASS_LXCORE,   PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\drivers\\\\lxcore.sys\") },\n    };\n\n    PH_STRING_BUILDER stringBuilder;\n\n    PhInitializeStringBuilder(&stringBuilder, 30);\n    PhAppendStringBuilder(&stringBuilder, &platformHeader);\n    PhAppendStringBuilder2(&stringBuilder, L\"{\\\"version\\\":1,\");\n    PhAppendStringBuilder2(&stringBuilder, L\"\\\"files\\\":[\");\n\n    for (ULONG i = 0; i < RTL_NUMBER_OF(platformFiles); i++)\n    {\n        USHORT imageMachine;\n        ULONG timeDateStamp;\n        ULONG sizeOfImage;\n        SIZE_T outputLength = 0;\n        WCHAR outputBuffer[PH_HASH_SHA256_LENGTH * 2 + 1];\n\n        if (NT_SUCCESS(KsiCreatePlatformSupportInformation(\n            &platformFiles[i].FileName,\n            &imageMachine,\n            &timeDateStamp,\n            &sizeOfImage,\n            outputBuffer,\n            sizeof(outputBuffer),\n            &outputLength\n            )))\n        {\n            PPH_STRING string;\n            PH_STRINGREF hashString;\n            PH_FORMAT format[11];\n\n            hashString.Buffer = outputBuffer;\n            hashString.Length = outputLength;\n\n            PhInitFormatS(&format[0], L\"{\\\"hash\\\":\\\"\");\n            PhInitFormatSR(&format[1], hashString);\n            PhInitFormatS(&format[2], L\"\\\",\\\"file\\\":\");\n            PhInitFormatU(&format[3], platformFiles[i].Class);\n            PhInitFormatS(&format[4], L\",\\\"machine\\\":\");\n            PhInitFormatU(&format[5], imageMachine);\n            PhInitFormatS(&format[6], L\",\\\"timestamp\\\":\");\n            PhInitFormatU(&format[7], timeDateStamp);\n            PhInitFormatS(&format[8], L\",\\\"size\\\":\");\n            PhInitFormatU(&format[9], sizeOfImage);\n            PhInitFormatS(&format[10], L\"},\");\n\n            string = PhFormat(format, RTL_NUMBER_OF(format), 10);\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhDereferenceObject(string);\n        }\n    }\n\n    if (PhEndsWithString2(stringBuilder.String, L\",\", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    PhAppendStringBuilder2(&stringBuilder, L\"]}\");\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nPPH_STRING KsiCreateUpdateWindowsString(\n    VOID\n    )\n{\n    PPH_STRING buildString = NULL;\n    PPH_STRING fileName;\n    PVOID imageBase;\n    ULONG imageSize;\n    PVOID versionInfo;\n\n    if (NT_SUCCESS(PhGetKernelFileNameEx(&fileName, &imageBase, &imageSize)))\n    {\n        if (NT_SUCCESS(PhGetFileVersionInfoEx(&fileName->sr, &versionInfo)))\n        {\n            VS_FIXEDFILEINFO* rootBlock;\n\n            if (rootBlock = PhGetFileVersionFixedInfo(versionInfo))\n            {\n                PH_FORMAT format[5];\n\n                PhInitFormatS(&format[0], L\"KsiOsBuild: \");\n                PhInitFormatU(&format[1], HIWORD(rootBlock->dwFileVersionLS));\n                PhInitFormatC(&format[2], '.');\n                PhInitFormatU(&format[3], LOWORD(rootBlock->dwFileVersionLS));\n                PhInitFormatS(&format[4], PhIsExecutingInWow64() ? L\"_64\" : L\"_32\");\n\n                buildString = PhFormat(format, RTL_NUMBER_OF(format), 0);\n            }\n\n            PhFree(versionInfo);\n        }\n\n        PhDereferenceObject(fileName);\n    }\n\n    return buildString;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS KsiCheckKernelSupportThread(\n    _In_ PVOID Parameter\n    )\n{\n    PKSI_KERNEL_SUPPORT_CHECK_CONTEXT context = Parameter;\n    NTSTATUS status;\n    PPH_HTTP_CONTEXT httpContext = NULL;\n    PPH_STRING xmlData = NULL;\n    PPH_STRING searchString = NULL;\n\n    if (!NT_SUCCESS(status = PhHttpInitialize(&httpContext)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhHttpConnect(httpContext, L\"systeminformer.io\", PH_HTTP_DEFAULT_HTTPS_PORT)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhHttpBeginRequest(httpContext, L\"POST\", L\"/ksiver\", PH_HTTP_FLAG_SECURE)))\n        goto CleanupExit;\n\n    {\n        PPH_STRING buildStringHeader;\n        PPH_STRING updateStringHeader;\n        PPH_STRING platformStringHeader;\n\n        if (buildStringHeader = KsiCreateBuildString())\n        {\n            PhHttpAddRequestHeadersSR(httpContext, &buildStringHeader->sr);\n            PhDereferenceObject(buildStringHeader);\n        }\n\n        if (updateStringHeader = KsiCreateUpdateWindowsString())\n        {\n            PhHttpAddRequestHeadersSR(httpContext, &updateStringHeader->sr);\n            PhDereferenceObject(updateStringHeader);\n        }\n\n        if (platformStringHeader = KsiCreatePlatformBuildString())\n        {\n            PhHttpAddRequestHeadersSR(httpContext, &platformStringHeader->sr);\n            PhDereferenceObject(platformStringHeader);\n        }\n    }\n\n    if (!NT_SUCCESS(status = PhHttpSendRequest(httpContext, NULL, 0, NULL, 0, 0)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhHttpReceiveResponse(httpContext)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhHttpQueryResponseStatus(httpContext)))\n        goto CleanupExit;\n\n    WriteBooleanRelease(&context->IsSupported, TRUE);\n\nCleanupExit:\n    if (searchString)\n        PhDereferenceObject(searchString);\n    if (xmlData)\n        PhDereferenceObject(xmlData);\n    if (httpContext)\n        PhHttpDestroy(httpContext);\n\n    WriteBooleanRelease(&context->CheckComplete, TRUE);\n\n    return STATUS_SUCCESS;\n}\n\nHRESULT CALLBACK KsiKernelSupportCheckDialogCallbackProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR dwRefData\n    )\n{\n    PKSI_KERNEL_SUPPORT_CHECK_CONTEXT context = (PKSI_KERNEL_SUPPORT_CHECK_CONTEXT)dwRefData;\n\n    switch (uMsg)\n    {\n    case TDN_CREATED:\n        {\n            context->TaskDialogHandle = hwndDlg;\n\n            SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n            SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n\n            PhCreateThread2(KsiCheckKernelSupportThread, context);\n        }\n        break;\n    case TDN_DESTROYED:\n        {\n            context->TaskDialogHandle = NULL;\n        }\n        break;\n    case TDN_TIMER:\n        {\n            if (ReadBooleanAcquire(&context->CheckComplete))\n            {\n                WriteBooleanRelease(&context->CheckComplete, TRUE);\n\n                TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) };\n                config.hwndParent = context->WindowHandle;\n                config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW;\n                config.dwCommonButtons = TDCBF_OK_BUTTON;\n                config.pszWindowTitle = PhApplicationName;\n                config.pszMainIcon = TD_SHIELD_WARNING_ICON;\n                config.cxWidth = 200;\n\n                if (ReadBooleanAcquire(&context->IsSupported))\n                {\n                    config.pszMainInstruction = L\"Platform support pending review.\";\n                    config.pszContent = L\"Your kernel version is pending review on the development branch. \"\n                        L\"Your kernel will be supported in the next build!\";\n                }\n                else\n                {\n                    if (context->IsCanaryChannel)\n                    {\n                        config.pszMainInstruction = L\"Kernel version not supported\";\n                        config.pszContent = L\"This kernel version is not yet supported. \"\n                            L\"Your kernel version is pending review review on the development branch.\";\n                    }\n                    else\n                    {\n                        config.pszMainInstruction = L\"Kernel version not supported\";\n                        config.pszContent = L\"This kernel version is not yet supported. \"\n                            L\"For the latest kernel support switch to the Canary update channel \"\n                            L\"(Help > Check for updates > Canary > Check).\";\n                    }\n                }\n\n                PhTaskDialogNavigatePage(hwndDlg, &config);\n            }\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\nVOID KsiShowKernelSupportCheckDialog(\n    _In_opt_ HWND WindowHandle\n    )\n{\n    KSI_KERNEL_SUPPORT_CHECK_CONTEXT context = { 0 };\n    PPH_STRING statusMessage;\n\n    statusMessage = PhpGetKsiMessage2(\n        STATUS_SI_DYNDATA_UNSUPPORTED_KERNEL,\n        FALSE,\n        L\"Checking for pending platform update...\",\n        NULL\n        );\n\n    context.WindowHandle = WindowHandle;\n    context.IsCanaryChannel = (PhGetPhReleaseChannel() >= PhCanaryChannel);\n    KsiGetKernelSupportData(&context.SupportData);\n\n    TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) };\n    config.hwndParent = WindowHandle;\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_SHOW_PROGRESS_BAR | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_CALLBACK_TIMER;\n    config.dwCommonButtons = TDCBF_CANCEL_BUTTON;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainIcon = TD_SHIELD_WARNING_ICON;\n    config.pszMainInstruction = L\"Checking for pending platform update...\";\n    config.pszContent = PhGetString(statusMessage);\n    config.lpCallbackData = (LONG_PTR)&context;\n    config.pfCallback = KsiKernelSupportCheckDialogCallbackProc;\n    config.cxWidth = 200;\n\n    PhShowTaskDialog(&config, NULL, NULL, NULL);\n}\n#endif\n"
  },
  {
    "path": "SystemInformer/ksyscall.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2019-2023\n *\n */\n\n#include <phapp.h>\n#include <mapimg.h>\n\n#define NTOS_SERVICE_INDEX 0\n#define WIN32K_SERVICE_INDEX 1\n\ntypedef union _NT_SYSTEMCALL_NUMBER\n{\n    USHORT SystemCallNumber;\n    struct\n    {\n        USHORT SystemCallIndex : 12;\n        USHORT SystemServiceIndex : 4;\n    };\n} NT_SYSTEMCALL_NUMBER, *PNT_SYSTEMCALL_NUMBER;\n\ntypedef struct _PH_SYSCALL_NAME_ENTRY\n{\n    ULONG_PTR Address;\n    PPH_STRING Name;\n} PH_SYSCALL_NAME_ENTRY, *PPH_SYSCALL_NAME_ENTRY;\n\nstatic int __cdecl PhpSystemCallListIndexSort(\n    _In_ void* Context,\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_SYSCALL_NAME_ENTRY entry1 = *(PPH_SYSCALL_NAME_ENTRY*)elem1;\n    PPH_SYSCALL_NAME_ENTRY entry2 = *(PPH_SYSCALL_NAME_ENTRY*)elem2;\n\n    return uintptrcmp(entry1->Address, entry2->Address);\n}\n\nVOID PhGenerateSyscallLists(\n    _Out_ PPH_LIST* NtdllSystemCallList,\n    _Out_ PPH_LIST* Win32kSystemCallList\n    )\n{\n    static CONST PH_STRINGREF ntdllFileName = PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\ntdll.dll\");\n    static CONST PH_STRINGREF win32kFileName = PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\win32k.sys\");\n    static CONST PH_STRINGREF win32uFileName = PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\win32u.dll\");\n    PPH_LIST ntdllSystemCallList = NULL;\n    PPH_LIST win32kSystemCallList = NULL;\n    PH_MAPPED_IMAGE mappedImage;\n    PH_MAPPED_IMAGE_EXPORTS exports;\n    PH_MAPPED_IMAGE_EXPORT_ENTRY exportEntry;\n    PH_MAPPED_IMAGE_EXPORT_FUNCTION exportFunction;\n\n    if (NT_SUCCESS(PhLoadMappedImageEx(&ntdllFileName, NULL, &mappedImage)))\n    {\n        if (NT_SUCCESS(PhGetMappedImageExports(&exports, &mappedImage)))\n        {\n            PPH_LIST list = PhCreateList(exports.NumberOfEntries);\n\n            for (ULONG i = 0; i < exports.NumberOfEntries; i++)\n            {\n                if (NT_SUCCESS(PhGetMappedImageExportEntry(&exports, i, &exportEntry)))\n                {\n                    if (!(exportEntry.Name && strncmp(exportEntry.Name, \"Zw\", 2) == 0))\n                        continue;\n\n                    if (NT_SUCCESS(PhGetMappedImageExportFunction(&exports, NULL, exportEntry.Ordinal, &exportFunction)))\n                    {\n                        PPH_SYSCALL_NAME_ENTRY entry;\n\n                        entry = PhAllocate(sizeof(PH_SYSCALL_NAME_ENTRY));\n                        entry->Address = (ULONG_PTR)exportFunction.Function;\n                        entry->Name = PhZeroExtendToUtf16(exportEntry.Name);\n                        entry->Name->Buffer[0] = L'N';\n                        entry->Name->Buffer[1] = L't';\n\n                        PhAddItemList(list, entry);\n                    }\n                }\n            }\n\n            qsort_s(list->Items, list->Count, sizeof(PVOID), PhpSystemCallListIndexSort, NULL);\n\n            if (list->Count)\n            {\n                ntdllSystemCallList = PhCreateList(list->Count);\n\n                for (ULONG i = 0; i < list->Count; i++)\n                {\n                    PPH_SYSCALL_NAME_ENTRY entry = list->Items[i];\n                    PhAddItemList(ntdllSystemCallList, entry->Name);\n                    PhFree(entry);\n                }\n            }\n\n            PhDereferenceObject(list);\n        }\n\n        PhUnloadMappedImage(&mappedImage);\n    }\n\n    if (WindowsVersion >= WINDOWS_10_20H1)\n    {\n        if (NT_SUCCESS(PhLoadMappedImageEx(&win32kFileName, NULL, &mappedImage)))\n        {\n            if (NT_SUCCESS(PhGetMappedImageExports(&exports, &mappedImage)))\n            {\n                PPH_LIST list = PhCreateList(exports.NumberOfEntries);\n\n                for (ULONG i = 0; i < exports.NumberOfEntries; i++)\n                {\n                    if (NT_SUCCESS(PhGetMappedImageExportEntry(&exports, i, &exportEntry)))\n                    {\n                        if (!(exportEntry.Name && strncmp(exportEntry.Name, \"__win32kstub_\", 13) == 0))\n                            continue;\n\n                        if (NT_SUCCESS(PhGetMappedImageExportFunction(&exports, NULL, exportEntry.Ordinal, &exportFunction)))\n                        {\n                            PPH_SYSCALL_NAME_ENTRY entry;\n\n                            entry = PhAllocate(sizeof(PH_SYSCALL_NAME_ENTRY));\n                            entry->Address = (ULONG_PTR)exportFunction.Function;\n                            entry->Name = PhZeroExtendToUtf16(exportEntry.Name);\n                            PhSkipStringRef(&entry->Name->sr, 13 * sizeof(WCHAR));\n\n                            PhAddItemList(list, entry);\n                        }\n                    }\n                }\n\n                qsort_s(list->Items, list->Count, sizeof(PVOID), PhpSystemCallListIndexSort, NULL);\n\n                if (list->Count)\n                {\n                    win32kSystemCallList = PhCreateList(list->Count);\n\n                    for (ULONG i = 0; i < list->Count; i++)\n                    {\n                        PPH_SYSCALL_NAME_ENTRY entry = list->Items[i];\n                        PhAddItemList(win32kSystemCallList, entry->Name);\n                        PhFree(entry);\n                    }\n                }\n\n                PhDereferenceObject(list);\n            }\n\n            PhUnloadMappedImage(&mappedImage);\n        }\n    }\n    else\n    {\n        if (NT_SUCCESS(PhLoadMappedImageEx(&win32uFileName, NULL, &mappedImage)))\n        {\n            if (NT_SUCCESS(PhGetMappedImageExports(&exports, &mappedImage)))\n            {\n                PPH_LIST list = PhCreateList(exports.NumberOfEntries);\n\n                for (ULONG i = 0; i < exports.NumberOfEntries; i++)\n                {\n                    if (NT_SUCCESS(PhGetMappedImageExportEntry(&exports, i, &exportEntry)))\n                    {\n                        if (!(exportEntry.Name && strncmp(exportEntry.Name, \"Nt\", 2) == 0))\n                            continue;\n\n                        if (NT_SUCCESS(PhGetMappedImageExportFunction(&exports, NULL, exportEntry.Ordinal, &exportFunction)))\n                        {\n                            PPH_SYSCALL_NAME_ENTRY entry;\n\n                            entry = PhAllocate(sizeof(PH_SYSCALL_NAME_ENTRY));\n                            entry->Address = (ULONG_PTR)exportFunction.Function;\n                            entry->Name = PhZeroExtendToUtf16(exportEntry.Name);\n\n                            // NOTE: When system calls are deleted from win32k.sys the win32u.dll interface gets\n                            // replaced with stubs that call RaiseFailFastException. This breaks the sorting via\n                            // RVA based on exports since these exports still exist so we have to check the prologue. (dmex)\n                            if (WindowsVersion >= WINDOWS_10_21H1)\n                            {\n                                PBYTE exportAddress;\n\n                                if (exportAddress = PhMappedImageRvaToVa(&mappedImage, PtrToUlong(exportFunction.Function), NULL))\n                                {\n                                    PNT_SYSTEMCALL_NUMBER systemCallEntry = NULL;\n\n                                #ifdef _WIN64\n                                    const BYTE prologue[4] = { 0x4C, 0x8B, 0xD1, 0xB8 };\n\n                                    if (RtlEqualMemory(exportAddress, prologue, sizeof(prologue)))\n                                    {\n                                        systemCallEntry = PTR_ADD_OFFSET(exportAddress, sizeof(prologue));\n                                    }\n                                #else\n                                    const BYTE prologue[1] = { 0xB8 };\n\n                                    if (RtlEqualMemory(exportAddress, prologue, sizeof(prologue)))\n                                    {\n                                        systemCallEntry = PTR_ADD_OFFSET(exportAddress, sizeof(prologue));\n                                    }\n                                #endif\n\n                                    if (systemCallEntry && systemCallEntry->SystemServiceIndex == WIN32K_SERVICE_INDEX)\n                                    {\n                                        entry->Address = systemCallEntry->SystemCallIndex;\n                                        PhAddItemList(list, entry);\n                                    }\n                                }\n                            }\n                            else\n                            {\n                                PhAddItemList(list, entry);\n                            }\n                        }\n                    }\n                }\n\n                qsort_s(list->Items, list->Count, sizeof(PVOID), PhpSystemCallListIndexSort, NULL);\n\n                if (list->Count)\n                {\n                    win32kSystemCallList = PhCreateList(list->Count);\n\n                    for (ULONG i = 0; i < list->Count; i++)\n                    {\n                        PPH_SYSCALL_NAME_ENTRY entry = list->Items[i];\n                        PhAddItemList(win32kSystemCallList, entry->Name);\n                        PhFree(entry);\n                    }\n                }\n\n                PhDereferenceObject(list);\n            }\n\n            PhUnloadMappedImage(&mappedImage);\n        }\n    }\n\n    *NtdllSystemCallList = ntdllSystemCallList;\n    *Win32kSystemCallList = win32kSystemCallList;\n}\n\nPPH_STRING PhGetSystemCallNumberName(\n    _In_ USHORT SystemCallNumber\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PPH_LIST ntdllSystemCallList = NULL;\n    static PPH_LIST win32kSystemCallList = NULL;\n    PNT_SYSTEMCALL_NUMBER systemCallEntry = (PNT_SYSTEMCALL_NUMBER)&SystemCallNumber;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhGenerateSyscallLists(&ntdllSystemCallList, &win32kSystemCallList);\n        PhEndInitOnce(&initOnce);\n    }\n\n    switch (systemCallEntry->SystemServiceIndex)\n    {\n    case NTOS_SERVICE_INDEX:\n        {\n            if (ntdllSystemCallList && systemCallEntry->SystemCallIndex <= ntdllSystemCallList->Count)\n            {\n                PPH_STRING entry = ntdllSystemCallList->Items[systemCallEntry->SystemCallIndex];\n\n                return PhReferenceObject(entry);\n            }\n        }\n        break;\n    case WIN32K_SERVICE_INDEX:\n        {\n            if (win32kSystemCallList && systemCallEntry->SystemCallIndex <= win32kSystemCallList->Count)\n            {\n                PPH_STRING entry = win32kSystemCallList->Items[systemCallEntry->SystemCallIndex];\n\n                return PhReferenceObject(entry);\n            }\n        }\n        break;\n    }\n\n    return NULL;\n}\n"
  },
  {
    "path": "SystemInformer/log.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2016-2021\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <settings.h>\n#include <phsettings.h>\n\nPH_CIRCULAR_BUFFER_PVOID PhLogBuffer;\n\nVOID PhLogInitialization(\n    VOID\n    )\n{\n    ULONG entries;\n\n    entries = PhGetIntegerSetting(SETTING_LOG_ENTRIES);\n    if (entries > 0x1000) entries = 0x1000;\n    PhInitializeCircularBuffer_PVOID(&PhLogBuffer, entries);\n    memset(PhLogBuffer.Data, 0, sizeof(PVOID) * PhLogBuffer.Size);\n}\n\nPPH_LOG_ENTRY PhpCreateLogEntry(\n    _In_ UCHAR Type\n    )\n{\n    PPH_LOG_ENTRY entry;\n\n    entry = PhAllocate(sizeof(PH_LOG_ENTRY));\n    memset(entry, 0, sizeof(PH_LOG_ENTRY));\n\n    entry->Type = Type;\n    PhQuerySystemTime(&entry->Time);\n\n    return entry;\n}\n\nVOID PhpFreeLogEntry(\n    _In_ _Post_invalid_ PPH_LOG_ENTRY Entry\n    )\n{\n    if (Entry->Type >= PH_LOG_ENTRY_PROCESS_FIRST && Entry->Type <= PH_LOG_ENTRY_PROCESS_LAST)\n    {\n        PhDereferenceObject(Entry->Process.Name);\n        if (Entry->Process.ParentName) PhDereferenceObject(Entry->Process.ParentName);\n    }\n    else if (Entry->Type >= PH_LOG_ENTRY_SERVICE_FIRST && Entry->Type <= PH_LOG_ENTRY_SERVICE_LAST)\n    {\n        PhDereferenceObject(Entry->Service.Name);\n        PhDereferenceObject(Entry->Service.DisplayName);\n    }\n    else if (Entry->Type == PH_LOG_ENTRY_MESSAGE)\n    {\n        PhDereferenceObject(Entry->Message);\n    }\n\n    PhFree(Entry);\n}\n\nPPH_LOG_ENTRY PhpCreateProcessLogEntry(\n    _In_ UCHAR Type,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_STRING Name,\n    _In_opt_ HANDLE ParentProcessId,\n    _In_opt_ PPH_STRING ParentName,\n    _In_opt_ ULONG Status\n    )\n{\n    PPH_LOG_ENTRY entry;\n\n    entry = PhpCreateLogEntry(Type);\n    entry->Process.ProcessId = ProcessId;\n    PhReferenceObject(Name);\n    entry->Process.Name = Name;\n\n    entry->Process.ParentProcessId = ParentProcessId;\n\n    if (!PhIsNullOrEmptyString(ParentName))\n    {\n        PhReferenceObject(ParentName);\n        entry->Process.ParentName = ParentName;\n    }\n\n    entry->Process.ExitStatus = Status;\n\n    return entry;\n}\n\nPPH_LOG_ENTRY PhpCreateServiceLogEntry(\n    _In_ UCHAR Type,\n    _In_ PPH_STRING Name,\n    _In_ PPH_STRING DisplayName\n    )\n{\n    PPH_LOG_ENTRY entry;\n\n    entry = PhpCreateLogEntry(Type);\n    PhReferenceObject(Name);\n    entry->Service.Name = Name;\n    PhReferenceObject(DisplayName);\n    entry->Service.DisplayName = DisplayName;\n\n    return entry;\n}\n\nPPH_LOG_ENTRY PhpCreateDeviceLogEntry(\n    _In_ UCHAR Type,\n    _In_ PPH_STRING Classification,\n    _In_ PPH_STRING Name\n    )\n{\n    PPH_LOG_ENTRY entry;\n\n    entry = PhpCreateLogEntry(Type);\n    PhReferenceObject(Classification);\n    entry->Device.Classification = Classification;\n    PhReferenceObject(Name);\n    entry->Device.Name = Name;\n\n    return entry;\n}\n\nPPH_LOG_ENTRY PhpCreateMessageLogEntry(\n    _In_ UCHAR Type,\n    _In_ PPH_STRING Message\n    )\n{\n    PPH_LOG_ENTRY entry;\n\n    entry = PhpCreateLogEntry(Type);\n    PhReferenceObject(Message);\n    entry->Message = Message;\n\n    return entry;\n}\n\nVOID PhpLogEntry(\n    _In_ PPH_LOG_ENTRY Entry\n    )\n{\n    PPH_LOG_ENTRY oldEntry;\n\n    oldEntry = PhAddItemCircularBuffer2_PVOID(&PhLogBuffer, Entry);\n\n    if (oldEntry)\n        PhpFreeLogEntry(oldEntry);\n\n    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), Entry);\n}\n\nVOID PhClearLogEntries(\n    VOID\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < PhLogBuffer.Size; i++)\n    {\n        if (PhLogBuffer.Data[i])\n            PhpFreeLogEntry(PhLogBuffer.Data[i]);\n    }\n\n    PhClearCircularBuffer_PVOID(&PhLogBuffer);\n    memset(PhLogBuffer.Data, 0, sizeof(PVOID) * PhLogBuffer.Size);\n}\n\nVOID PhLogProcessEntry(\n    _In_ UCHAR Type,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_STRING Name,\n    _In_opt_ HANDLE ParentProcessId,\n    _In_opt_ PPH_STRING ParentName,\n    _In_opt_ ULONG Status\n    )\n{\n    PhpLogEntry(PhpCreateProcessLogEntry(Type, ProcessId, Name, ParentProcessId, ParentName, Status));\n}\n\nVOID PhLogServiceEntry(\n    _In_ UCHAR Type,\n    _In_ PPH_STRING Name,\n    _In_ PPH_STRING DisplayName\n    )\n{\n    PhpLogEntry(PhpCreateServiceLogEntry(Type, Name, DisplayName));\n}\n\nVOID PhLogDeviceEntry(\n    _In_ UCHAR Type,\n    _In_ PPH_STRING Classification,\n    _In_ PPH_STRING Name\n    )\n{\n    PhpLogEntry(PhpCreateDeviceLogEntry(Type, Classification, Name));\n}\n\nVOID PhLogMessageEntry(\n    _In_ UCHAR Type,\n    _In_ PPH_STRING Message\n    )\n{\n    PhpLogEntry(PhpCreateMessageLogEntry(Type, Message));\n}\n\nPPH_STRING PhpFormatLogEntryToBuffer(\n    _In_ PPH_FORMAT Format,\n    _In_ ULONG Count\n    )\n{\n    SIZE_T formatLength;\n    WCHAR formatBuffer[0x80];\n\n    if (PhFormatToBuffer(\n        Format,\n        Count,\n        formatBuffer,\n        sizeof(formatBuffer),\n        &formatLength\n        ))\n    {\n        PH_STRINGREF text;\n\n        text.Length = formatLength - sizeof(UNICODE_NULL);\n        text.Buffer = formatBuffer;\n\n        return PhCreateString2(&text);\n    }\n\n    return PhFormat(Format, Count, 0x80);\n}\n\nPPH_STRING PhFormatLogEntry(\n    _In_ PPH_LOG_ENTRY Entry\n    )\n{\n    switch (Entry->Type)\n    {\n    case PH_LOG_ENTRY_PROCESS_CREATE:\n        {\n            PH_FORMAT format[8];\n\n            // Process created: %s (%lu) started by %s (%lu)\n            //PhInitFormatS(&format[0], L\"Process created: \");\n            PhInitFormatSR(&format[0], Entry->Process.Name->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatU(&format[2], HandleToUlong(Entry->Process.ProcessId));\n            PhInitFormatS(&format[3], L\") started by \");\n            if (Entry->Process.ParentName)\n                PhInitFormatSR(&format[4], Entry->Process.ParentName->sr);\n            else\n                PhInitFormatS(&format[4], L\"Unknown process\");\n            PhInitFormatS(&format[5], L\" (\");\n            PhInitFormatU(&format[6], HandleToUlong(Entry->Process.ParentProcessId));\n            PhInitFormatC(&format[7], L')');\n\n            //return PhFormatString(\n            //    L\"Process created: %s (%lu) started by %s (%lu)\",\n            //    Entry->Process.Name->Buffer,\n            //    HandleToUlong(Entry->Process.ProcessId),\n            //    PhGetStringOrDefault(Entry->Process.ParentName, L\"Unknown process\"),\n            //    HandleToUlong(Entry->Process.ParentProcessId)\n            //    );\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_PROCESS_DELETE:\n        {\n            PH_FORMAT format[5];\n\n            // Process terminated: %s (%lu); exit status 0x%x\n            //PhInitFormatS(&format[0], L\"Process terminated: \");\n            PhInitFormatSR(&format[0], Entry->Process.Name->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatU(&format[2], HandleToUlong(Entry->Process.ProcessId));\n            PhInitFormatS(&format[3], L\"); exit status \");\n            PhInitFormatX(&format[4], Entry->Process.ExitStatus);\n\n            //return PhFormatString(\n            //    L\"Process terminated: %s (%lu); exit status 0x%x\",\n            //    Entry->Process.Name->Buffer,\n            //    HandleToUlong(Entry->Process.ProcessId),\n            //    Entry->Process.ExitStatus\n            //    );\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_SERVICE_CREATE:\n        {\n            PH_FORMAT format[4];\n\n            // Service created: %s (%s)\n            //PhInitFormatS(&format[0], L\"Service created: \");\n            PhInitFormatSR(&format[0], Entry->Service.Name->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatSR(&format[2], Entry->Service.DisplayName->sr);\n            PhInitFormatC(&format[3], L')');\n\n            //return PhFormatString(\n            //    L\"Service created: %s (%s)\",\n            //    Entry->Service.Name->Buffer,\n            //    Entry->Service.DisplayName->Buffer\n            //    );\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_SERVICE_DELETE:\n        {\n            PH_FORMAT format[4];\n\n            // Service deleted: %s (%s)\n            //PhInitFormatS(&format[0], L\"Service deleted: \");\n            PhInitFormatSR(&format[0], Entry->Service.Name->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatSR(&format[2], Entry->Service.DisplayName->sr);\n            PhInitFormatC(&format[3], L')');\n\n            //return PhFormatString(\n            //    L\"Service deleted: %s (%s)\",\n            //    Entry->Service.Name->Buffer,\n            //    Entry->Service.DisplayName->Buffer\n            //    );\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_SERVICE_START:\n        {\n            PH_FORMAT format[4];\n\n            // Service started: %s (%s)\n            //PhInitFormatS(&format[0], L\"Service started: \");\n            PhInitFormatSR(&format[0], Entry->Service.Name->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatSR(&format[2], Entry->Service.DisplayName->sr);\n            PhInitFormatC(&format[3], L')');\n\n            //return PhFormatString(\n            //    L\"Service started: %s (%s)\",\n            //    Entry->Service.Name->Buffer,\n            //    Entry->Service.DisplayName->Buffer\n            //    );\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_SERVICE_STOP:\n        {\n            PH_FORMAT format[4];\n\n            // Service stopped: %s (%s)\n            //PhInitFormatS(&format[0], L\"Service stopped: \");\n            PhInitFormatSR(&format[0], Entry->Service.Name->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatSR(&format[2], Entry->Service.DisplayName->sr);\n            PhInitFormatC(&format[3], L')');\n\n            //return PhFormatString(\n            //    L\"Service stopped: %s (%s)\",\n            //    Entry->Service.Name->Buffer,\n            //    Entry->Service.DisplayName->Buffer\n            //    );\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_SERVICE_CONTINUE:\n        {\n            PH_FORMAT format[4];\n\n            // Service continued: %s (%s)\n            //PhInitFormatS(&format[0], L\"Service continued: \");\n            PhInitFormatSR(&format[0], Entry->Service.Name->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatSR(&format[2], Entry->Service.DisplayName->sr);\n            PhInitFormatC(&format[3], L')');\n\n            //return PhFormatString(\n            //    L\"Service continued: %s (%s)\",\n            //    Entry->Service.Name->Buffer,\n            //    Entry->Service.DisplayName->Buffer\n            //    );\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_SERVICE_PAUSE:\n        {\n            PH_FORMAT format[4];\n\n            // Service paused: %s (%s)\n            //PhInitFormatS(&format[0], L\"Service paused: \");\n            PhInitFormatSR(&format[0], Entry->Service.Name->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatSR(&format[2], Entry->Service.DisplayName->sr);\n            PhInitFormatC(&format[3], L')');\n\n            //return PhFormatString(\n            //    L\"Service paused: %s (%s)\",\n            //    Entry->Service.Name->Buffer,\n            //    Entry->Service.DisplayName->Buffer\n            //    );\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_SERVICE_MODIFIED:\n        {\n            PH_FORMAT format[4];\n\n            // Service modified: %s (%s)\n            //PhInitFormatS(&format[0], L\"Service modified: \");\n            PhInitFormatSR(&format[0], Entry->Service.Name->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatSR(&format[2], Entry->Service.DisplayName->sr);\n            PhInitFormatC(&format[3], L')');\n\n            //return PhFormatString(\n            //    L\"Service modified: %s (%s)\",\n            //    Entry->Service.Name->Buffer,\n            //    Entry->Service.DisplayName->Buffer\n            //    );\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_DEVICE_REMOVED:\n        {\n            PH_FORMAT format[4];\n\n            //PhInitFormatS(&format[0], L\"Device removed: \");\n            PhInitFormatSR(&format[0], Entry->Device.Classification->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatSR(&format[2], Entry->Device.Name->sr);\n            PhInitFormatC(&format[3], L')');\n\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_DEVICE_ARRIVED:\n        {\n            PH_FORMAT format[4];\n\n            //PhInitFormatS(&format[0], L\"Device arrived: \");\n            PhInitFormatSR(&format[0], Entry->Device.Classification->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatSR(&format[2], Entry->Device.Name->sr);\n            PhInitFormatC(&format[3], L')');\n\n            return PhpFormatLogEntryToBuffer(format, RTL_NUMBER_OF(format));\n        }\n    case PH_LOG_ENTRY_MESSAGE:\n        PhReferenceObject(Entry->Message);\n        return Entry->Message;\n    default:\n        return PhReferenceEmptyString();\n    }\n}\n\nstatic CONST PH_KEY_VALUE_PAIR PhpLogEntryTypePairs[] =\n{\n    SIP(SREF(L\"Unknown\"), 0),\n    SIP(SREF(L\"Process created\"), PH_LOG_ENTRY_PROCESS_CREATE),\n    SIP(SREF(L\"Process terminated\"), PH_LOG_ENTRY_PROCESS_DELETE),\n    SIP(SREF(L\"Service created\"), PH_LOG_ENTRY_SERVICE_CREATE),\n    SIP(SREF(L\"Service terminated\"), PH_LOG_ENTRY_SERVICE_DELETE),\n    SIP(SREF(L\"Service started\"), PH_LOG_ENTRY_SERVICE_START),\n    SIP(SREF(L\"Service terminated\"), PH_LOG_ENTRY_SERVICE_STOP),\n    SIP(SREF(L\"Service continued\"), PH_LOG_ENTRY_SERVICE_CONTINUE),\n    SIP(SREF(L\"Service paused\"), PH_LOG_ENTRY_SERVICE_PAUSE),\n    SIP(SREF(L\"Service modified\"), PH_LOG_ENTRY_SERVICE_MODIFIED),\n    SIP(SREF(L\"Device removed\"), PH_LOG_ENTRY_DEVICE_REMOVED),\n    SIP(SREF(L\"Device arrived\"), PH_LOG_ENTRY_DEVICE_ARRIVED)\n};\n\nPCPH_STRINGREF PhFormatLogType(\n    _In_ PPH_LOG_ENTRY Entry\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        PhpLogEntryTypePairs,\n        sizeof(PhpLogEntryTypePairs),\n        Entry->Type,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return NULL;\n}\n"
  },
  {
    "path": "SystemInformer/logwnd.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2014-2023\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <mainwnd.h>\n#include <emenu.h>\n\n#define WM_PH_LOG_UPDATED (WM_APP + 300)\n\nINT_PTR CALLBACK PhpLogDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nHWND PhLogWindowHandle = NULL;\nstatic PH_LAYOUT_MANAGER WindowLayoutManager;\nstatic RECT MinimumSize;\nstatic HWND AutoScrollHandle;\nstatic HWND ListViewHandle;\nstatic PPH_LISTVIEW_CONTEXT ListViewContext;\nstatic ULONG ListViewCount;\nstatic PH_CALLBACK_REGISTRATION LoggedRegistration;\nstatic BOOLEAN ListViewStateInitializing = FALSE;\nstatic BOOLEAN ListViewAutoScroll = FALSE;\n\nVOID PhShowLogDialog(\n    VOID\n    )\n{\n    if (!PhLogWindowHandle)\n    {\n        PhLogWindowHandle = PhCreateDialog(\n            PhInstanceHandle,\n            MAKEINTRESOURCE(IDD_LOG),\n            NULL,\n            PhpLogDlgProc,\n            NULL\n            );\n        PhRegisterDialog(PhLogWindowHandle);\n        ShowWindow(PhLogWindowHandle, SW_SHOW);\n    }\n\n    if (IsMinimized(PhLogWindowHandle))\n        ShowWindow(PhLogWindowHandle, SW_RESTORE);\n    else\n        SetForegroundWindow(PhLogWindowHandle);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI LoggedCallback(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    if (PhLogWindowHandle)\n    {\n        PostMessage(PhLogWindowHandle, WM_PH_LOG_UPDATED, 0, 0);\n    }\n}\n\nstatic VOID PhpUpdateLogList(\n    VOID\n    )\n{\n    ListViewCount = PhLogBuffer.Count;\n    PhListView_SetItemCount(ListViewContext, ListViewCount, LVSICF_NOSCROLL);\n\n    if (ListViewCount >= 2 && ReadBooleanAcquire(&ListViewAutoScroll))\n    {\n        BOOLEAN itemVisible;\n\n        if (PhListView_IsItemVisible(ListViewContext, ListViewCount - 1, &itemVisible) && !itemVisible)\n        {\n            PhListView_EnsureItemVisible(ListViewContext, ListViewCount - 1, FALSE);\n        }\n    }\n}\n\nstatic PPH_STRING PhpGetStringForSelectedLogEntries(\n    _In_ BOOLEAN All\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    ULONG i;\n\n    if (ListViewCount == 0)\n        return PhReferenceEmptyString();\n\n    PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n    i = ListViewCount - 1;\n\n    while (TRUE)\n    {\n        PPH_LOG_ENTRY entry;\n        SYSTEMTIME systemTime;\n        PCPH_STRINGREF string;\n        PPH_STRING temp;\n        ULONG itemState;\n\n        if (!All)\n        {\n            // The list view displays the items in reverse order...\n            if (!PhListView_GetItemState(ListViewContext, ListViewCount - i - 1, LVIS_SELECTED, &itemState) && FlagOn(itemState, LVIS_SELECTED))\n            {\n                goto ContinueLoop;\n            }\n        }\n\n        entry = PhGetItemCircularBuffer_PVOID(&PhLogBuffer, i);\n\n        if (!entry)\n            goto ContinueLoop;\n\n        PhLargeIntegerToLocalSystemTime(&systemTime, &entry->Time);\n        temp = PhFormatDateTime(&systemTime);\n        PhAppendStringBuilder(&stringBuilder, &temp->sr);\n        PhDereferenceObject(temp);\n        PhAppendStringBuilder2(&stringBuilder, L\": \");\n\n        string = PhFormatLogType(entry);\n        PhAppendStringBuilder(&stringBuilder, string);\n        PhAppendStringBuilder2(&stringBuilder, L\" \");\n        temp = PhFormatLogEntry(entry);\n        PhAppendStringBuilder(&stringBuilder, &temp->sr);\n        PhDereferenceObject(temp);\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n\nContinueLoop:\n\n        if (i == 0)\n            break;\n\n        i--;\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nINT_PTR CALLBACK PhpLogDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            AutoScrollHandle = GetDlgItem(hwndDlg, IDC_AUTOSCROLL);\n            ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            ListViewContext = PhListView_Initialize(ListViewHandle);\n\n            PhSetListViewStyle(ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(ListViewHandle, L\"explorer\");\n            PhSetExtendedListView(ListViewHandle);\n            PhListView_AddColumn(ListViewContext, 0, 0, 0, LVCFMT_LEFT, 140, L\"Time\");\n            PhListView_AddColumn(ListViewContext, 1, 1, 1, LVCFMT_LEFT, 140, L\"Type\");\n            PhListView_AddColumn(ListViewContext, 2, 2, 2, LVCFMT_LEFT, 260, L\"Message\");\n            PhLoadListViewColumnsFromSetting(SETTING_LOG_LIST_VIEW_COLUMNS, ListViewHandle);\n\n            PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, AutoScrollHandle, NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_CLEAR), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);\n\n            MinimumSize.left = 0;\n            MinimumSize.top = 0;\n            MinimumSize.right = 290;\n            MinimumSize.bottom = 150;\n            MapDialogRect(hwndDlg, &MinimumSize);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_LOG_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_LOG_WINDOW_POSITION, SETTING_LOG_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, PhMainWndHandle);\n\n            ListViewStateInitializing = TRUE;\n            WriteBooleanRelease(&ListViewAutoScroll, TRUE);\n            Button_SetCheck(AutoScrollHandle, BST_CHECKED);\n            ListViewStateInitializing = FALSE;\n\n            PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), LoggedCallback, NULL, &LoggedRegistration);\n            PhpUpdateLogList();\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveListViewColumnsToSetting(SETTING_LOG_LIST_VIEW_COLUMNS, ListViewHandle);\n            PhSaveWindowPlacementToSetting(SETTING_LOG_WINDOW_POSITION, SETTING_LOG_WINDOW_SIZE, hwndDlg);\n\n            PhDeleteLayoutManager(&WindowLayoutManager);\n\n            PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), &LoggedRegistration);\n            PhUnregisterDialog(PhLogWindowHandle);\n            PhLogWindowHandle = NULL;\n\n            PhListView_Destroy(ListViewContext);\n            ListViewContext = NULL;\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                DestroyWindow(hwndDlg);\n                break;\n            case IDC_CLEAR:\n                {\n                    PhClearLogEntries();\n                    PhpUpdateLogList();\n                }\n                break;\n            case IDC_COPY:\n                {\n                    PPH_STRING string;\n                    ULONG selectedCount = 0;\n\n                    if (!PhListView_GetSelectedCount(ListViewContext, &selectedCount))\n                        break;\n\n                    if (selectedCount == 0)\n                    {\n                        // User didn't select anything, so copy all items.\n                        string = PhpGetStringForSelectedLogEntries(TRUE);\n                        PhListView_SetStateAllItems(ListViewContext, LVIS_SELECTED, LVIS_SELECTED);\n                    }\n                    else\n                    {\n                        string = PhpGetStringForSelectedLogEntries(FALSE);\n                    }\n\n                    PhSetClipboardString(hwndDlg, &string->sr);\n                    PhDereferenceObject(string);\n                }\n                break;\n            case IDC_SAVE:\n                {\n                    static PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Text files (*.txt)\", L\"*.txt\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog;\n\n                    fileDialog = PhCreateSaveFileDialog();\n\n                    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n                    PhSetFileDialogFileName(fileDialog, L\"System Informer Log.txt\");\n\n                    if (PhShowFileDialog(hwndDlg, fileDialog))\n                    {\n                        NTSTATUS status;\n                        PPH_STRING fileName;\n                        PPH_FILE_STREAM fileStream;\n                        PPH_STRING string;\n\n                        fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n\n                        if (NT_SUCCESS(status = PhCreateFileStream(\n                            &fileStream,\n                            fileName->Buffer,\n                            FILE_GENERIC_WRITE,\n                            FILE_SHARE_READ,\n                            FILE_OVERWRITE_IF,\n                            0\n                            )))\n                        {\n                            PhWriteStringAsUtf8FileStream(fileStream, (PPH_STRINGREF)&PhUnicodeByteOrderMark);\n                            PhWritePhTextHeader(fileStream);\n\n                            string = PhpGetStringForSelectedLogEntries(TRUE);\n                            PhWriteStringAsUtf8FileStreamEx(fileStream, string->Buffer, string->Length);\n                            PhDereferenceObject(string);\n\n                            PhDereferenceObject(fileStream);\n                        }\n\n                        if (!NT_SUCCESS(status))\n                            PhShowStatus(hwndDlg, L\"Unable to create the file\", status, 0);\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            case IDC_AUTOSCROLL:\n                {\n                    WriteBooleanRelease(&ListViewAutoScroll, Button_GetCheck(AutoScrollHandle) == BST_CHECKED);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case LVN_GETDISPINFO:\n                {\n                    NMLVDISPINFO *dispInfo = (NMLVDISPINFO *)header;\n                    PPH_LOG_ENTRY entry;\n\n                    entry = PhGetItemCircularBuffer_PVOID(&PhLogBuffer, ListViewCount - dispInfo->item.iItem - 1);\n\n                    if (dispInfo->item.iSubItem == 0)\n                    {\n                        if (FlagOn(dispInfo->item.mask, LVIF_TEXT))\n                        {\n                            SYSTEMTIME systemTime;\n                            PPH_STRING dateTime;\n\n                            PhLargeIntegerToLocalSystemTime(&systemTime, &entry->Time);\n                            dateTime = PhFormatDateTime(&systemTime);\n                            wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, dateTime->Buffer, _TRUNCATE);\n                            PhDereferenceObject(dateTime);\n                        }\n                    }\n                    else if (dispInfo->item.iSubItem == 1)\n                    {\n                        if (FlagOn(dispInfo->item.mask, LVIF_TEXT))\n                        {\n                            PCPH_STRINGREF string;\n\n                            string = PhFormatLogType(entry);\n                            wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, string->Buffer, _TRUNCATE);\n                        }\n                    }\n                    else if (dispInfo->item.iSubItem == 2)\n                    {\n                        if (FlagOn(dispInfo->item.mask, LVIF_TEXT))\n                        {\n                            PPH_STRING string;\n\n                            string = PhFormatLogEntry(entry);\n                            wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, string->Buffer, _TRUNCATE);\n                            PhDereferenceObject(string);\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&WindowLayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&WindowLayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&WindowLayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);\n        }\n        break;\n    case WM_PH_LOG_UPDATED:\n        {\n            PhpUpdateLogList();\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID* listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                PhCopyListView(ListViewHandle);\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/main.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <colorbox.h>\n#include <hexedit.h>\n#include <hndlinfo.h>\n#include <objbase.h>\n\n#include <extmgri.h>\n#include <mainwnd.h>\n#include <mainwndp.h>\n#include <netprv.h>\n#include <phsettings.h>\n#include <phsvc.h>\n#include <procprv.h>\n#include <devprv.h>\n#include <notifico.h>\n\n#include <ksisup.h>\n#include <settings.h>\n#include <srvprv.h>\n\n#include <trace.h>\n\nBOOLEAN PhPluginsEnabled = FALSE;\nBOOLEAN PhPortableEnabled = FALSE;\nPPH_STRING PhSettingsFileName = NULL;\nPH_STARTUP_PARAMETERS PhStartupParameters = { .UpdateChannel = PhInvalidChannel };\nPH_PROVIDER_THREAD PhPrimaryProviderThread;\nPH_PROVIDER_THREAD PhSecondaryProviderThread;\nPH_PROVIDER_THREAD PhTertiaryProviderThread;\nRTL_ATOM PhTreeWindowAtom = RTL_ATOM_INVALID_ATOM;\nRTL_ATOM PhGraphWindowAtom = RTL_ATOM_INVALID_ATOM;\nRTL_ATOM PhHexEditWindowAtom = RTL_ATOM_INVALID_ATOM;\nRTL_ATOM PhColorBoxWindowAtom = RTL_ATOM_INVALID_ATOM;\nstatic PPH_LIST DialogList = NULL;\nstatic PPH_LIST FilterList = NULL;\nstatic PH_AUTO_POOL BaseAutoPool;\n\nINT WINAPI wWinMain(\n    _In_ HINSTANCE Instance,\n    _In_opt_ HINSTANCE PrevInstance,\n    _In_ PWSTR CmdLine,\n    _In_ INT CmdShow\n    )\n{\n    LONG result;\n#ifdef DEBUG\n    PHP_BASE_THREAD_DBG dbg;\n#endif\n\n    if (!NT_SUCCESS(PhInitializePhLib(L\"System Informer\")))\n        return 1;\n    if (!NT_SUCCESS(PhInitializeDirectoryPolicy()))\n        return 1;\n    if (!NT_SUCCESS(PhInitializeExceptionPolicy()))\n        return 1;\n    if (!NT_SUCCESS(PhInitializeExecutionPolicy()))\n        return 1;\n    if (!NT_SUCCESS(PhInitializeNamespacePolicy()))\n        return 1;\n    if (!NT_SUCCESS(PhInitializeComPolicy()))\n        return 1;\n\n    PhpProcessStartupParameters();\n    PhpEnablePrivileges();\n\n    if (PhStartupParameters.RunAsServiceMode)\n    {\n        PhExitApplication(PhRunAsServiceStart(PhStartupParameters.RunAsServiceMode));\n    }\n\n    PhGuiSupportInitialization();\n\n    PhInitializeAppSettings();\n    PhInitializeCallbacks();\n\n    if (PhStartupParameters.Debug)\n    {\n        PhShowDebugConsole();\n    }\n\n    PhInitializePreviousInstance();\n\n    PhInitializeCallbacks();\n\n    if (PhEnableKsiSupport &&\n        !PhStartupParameters.ShowOptions)\n    {\n        PhInitializeKsi();\n    }\n\n#ifdef DEBUG\n    dbg.ClientId = NtCurrentTeb()->ClientId;\n    dbg.StartAddress = wWinMain;\n    dbg.Parameter = NULL;\n    InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry);\n    PhTlsSetValue(PhDbgThreadDbgTlsIndex, &dbg);\n#endif\n\n    PhInitializeAutoPool(&BaseAutoPool);\n\n    PhInitializeSuperclassControls();\n    PhInitializeCommonControls();\n\n    PhInitializeAppSystem();\n    PhEmInitialization();\n\n    if (PhStartupParameters.ShowOptions)\n    {\n        PhShowOptionsDialog(PhStartupParameters.WindowHandle);\n        PhExitApplication(STATUS_SUCCESS);\n    }\n\n    if (PhPluginsEnabled && !PhStartupParameters.NoPlugins)\n    {\n        PhLoadPlugins();\n    }\n\n    // N.B. Must be called after loading plugins since we set Microsoft signed only.\n    if (!NT_SUCCESS(PhInitializeMitigationPolicy()))\n        return 1;\n\n    if (PhStartupParameters.PhSvc)\n    {\n        MSG message;\n\n        // Turn the feedback cursor off.\n        PostMessage(NULL, WM_NULL, 0, 0);\n        GetMessage(&message, NULL, 0, 0);\n\n        PhExitApplication(PhSvcMain(NULL, NULL));\n    }\n\n#ifndef DEBUG\n    if (PhIsExecutingInWow64())\n    {\n        PhShowWarning2(\n            NULL,\n            L\"Warning.\",\n            L\"%s\",\n            L\"You are attempting to run the 32-bit version of System Informer on 64-bit Windows. \"\n            L\"Most features will not work correctly.\\n\\n\"\n            L\"Please run the 64-bit version of System Informer instead.\"\n            );\n        PhExitApplication(STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT);\n    }\n#endif\n\n    // Set the default timer resolution.\n    {\n        if (WindowsVersion >= WINDOWS_11_24H2)\n        {\n            PhSetProcessPowerThrottlingState(\n                NtCurrentProcess(),\n                POWER_THROTTLING_PROCESS_IGNORE_TIMER_RESOLUTION,\n                0  // Disable synthetic timer resolution.\n                );\n        }\n    }\n\n    // Set the default priority.\n    {\n        UCHAR priorityClass = PROCESS_PRIORITY_CLASS_HIGH;\n\n        if (PhStartupParameters.PriorityClass != 0)\n            priorityClass = (UCHAR)PhStartupParameters.PriorityClass;\n\n        PhSetProcessPriorityClass(NtCurrentProcess(), priorityClass);\n    }\n\n    if (PhEnableKsiSupport)\n    {\n        PhShowKsiStatus();\n    }\n\n    if (!PhMainWndInitialization(CmdShow))\n    {\n        PhShowStatus(NULL, L\"Unable to create the window.\", 0, ERROR_OUTOFMEMORY);\n        return 1;\n    }\n\n    PhEnableTerminationPolicy(TRUE);\n\n    PhDrainAutoPool(&BaseAutoPool);\n\n    result = PhMainMessageLoop();\n\n    PhEnableTerminationPolicy(FALSE);\n\n    if (PhEnableKsiSupport)\n    {\n        PhCleanupKsi();\n    }\n\n    PhExitApplication(result);\n    return result;\n}\n\n/**\n * The main message loop for System Informer.\n *\n * Processes Windows messages for the main window, dialogs, and registered message loop filters.\n * Handles accelerator keys, dialog messages, and dispatches messages to the appropriate handlers.\n * Drains the auto pool after each message to manage memory efficiently.\n * \\return The exit code of the application, typically the wParam of the WM_QUIT message.\n */\nLONG PhMainMessageLoop(\n    VOID\n    )\n{\n    BOOL result;\n    MSG message;\n    HACCEL acceleratorTable;\n\n    acceleratorTable = LoadAccelerators(NtCurrentImageBase(), MAKEINTRESOURCE(IDR_MAINWND_ACCEL));\n\n    while (result = GetMessage(&message, NULL, 0, 0))\n    {\n        BOOLEAN processed = FALSE;\n        ULONG i;\n\n        if (result == -1)\n            return 1;\n\n        if (FilterList)\n        {\n            for (i = 0; i < FilterList->Count; i++)\n            {\n                PPH_MESSAGE_LOOP_FILTER_ENTRY entry = FilterList->Items[i];\n\n                if (entry->Filter(&message, entry->Context))\n                {\n                    processed = TRUE;\n                    break;\n                }\n            }\n        }\n\n        if (!processed)\n        {\n            if (\n                message.hwnd == PhMainWndHandle ||\n                IsChild(PhMainWndHandle, message.hwnd)\n                )\n            {\n                if (TranslateAccelerator(PhMainWndHandle, acceleratorTable, &message))\n                    processed = TRUE;\n            }\n\n            if (DialogList)\n            {\n                for (i = 0; i < DialogList->Count; i++)\n                {\n                    if (IsDialogMessage((HWND)DialogList->Items[i], &message))\n                    {\n                        processed = TRUE;\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (!processed)\n        {\n            TranslateMessage(&message);\n            DispatchMessage(&message);\n        }\n\n        PhDrainAutoPool(&BaseAutoPool);\n    }\n\n    return (LONG)message.wParam;\n}\n\n/**\n * Registers a dialog window handle with the application's dialog list.\n *\n * This function adds the specified dialog window handle to the internal list of dialogs\n * managed by the application. This allows the main message loop to recognize and process\n * messages for the dialog, enabling features such as keyboard navigation and message routing.\n *\n * \\param DialogWindowHandle The handle to the dialog window to register.\n * \\remarks Registered dialogs are processed in the main message loop for dialog-specific messages.\n */\nVOID PhRegisterDialog(\n    _In_ HWND DialogWindowHandle\n    )\n{\n    if (!DialogList)\n        DialogList = PhCreateList(2);\n\n    PhAddItemList(DialogList, (PVOID)DialogWindowHandle);\n}\n\n/**\n * Unregisters a dialog window handle from the application's dialog list.\n *\n * This function removes the specified dialog window handle from the internal list of dialogs\n * managed by the application. This ensures that the main message loop no longer processes\n * messages for the dialog, disabling features such as keyboard navigation and message routing\n * for the unregistered dialog.\n *\n * \\param DialogWindowHandle The handle to the dialog window to unregister.\n * \\remarks Unregistered dialogs are no longer processed in the main message loop for dialog-specific messages.\n */\nVOID PhUnregisterDialog(\n    _In_ HWND DialogWindowHandle\n    )\n{\n    ULONG indexOfDialog;\n\n    if (!DialogList)\n        return;\n\n    indexOfDialog = PhFindItemList(DialogList, (PVOID)DialogWindowHandle);\n\n    if (indexOfDialog != ULONG_MAX)\n        PhRemoveItemList(DialogList, indexOfDialog);\n}\n\n/**\n * Registers a message loop filter with the application's message loop.\n *\n * This function adds a custom filter to the internal list of message loop filters.\n * Each filter is a callback that can intercept and process Windows messages before\n * they are handled by the main window or dialogs. Filters are useful for implementing\n * global hotkeys, custom message handling, or preprocessing messages.\n *\n * \\param Filter The filter callback function to register.\n * \\param Context Optional context pointer passed to the filter callback.\n * \\return A pointer to the filter entry, which can be used to unregister the filter later.\n * \\remarks The filter will be called for each message in the main message loop.\n */\nPPH_MESSAGE_LOOP_FILTER_ENTRY PhRegisterMessageLoopFilter(\n    _In_ PPH_MESSAGE_LOOP_FILTER Filter,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MESSAGE_LOOP_FILTER_ENTRY entry;\n\n    if (!FilterList)\n        FilterList = PhCreateList(2);\n\n    entry = PhAllocate(sizeof(PH_MESSAGE_LOOP_FILTER_ENTRY));\n    entry->Filter = Filter;\n    entry->Context = Context;\n    PhAddItemList(FilterList, entry);\n\n    return entry;\n}\n\n/**\n * Unregisters a message loop filter from the application's message loop.\n *\n * This function removes a previously registered message loop filter, ensuring\n * it no longer receives messages from the main message loop.\n *\n * \\param FilterEntry The filter entry returned by PhRegisterMessageLoopFilter.\n * \\remarks The filter entry is freed after removal.\n */\nVOID PhUnregisterMessageLoopFilter(\n    _In_ PPH_MESSAGE_LOOP_FILTER_ENTRY FilterEntry\n    )\n{\n    ULONG indexOfFilter;\n\n    if (!FilterList)\n        return;\n\n    indexOfFilter = PhFindItemList(FilterList, FilterEntry);\n\n    if (indexOfFilter != ULONG_MAX)\n        PhRemoveItemList(FilterList, indexOfFilter);\n\n    PhFree(FilterEntry);\n}\n\n/**\n * Context structure for tracking a previous main window instance.\n *\n * Used during enumeration of windows to identify and interact with a previous\n * instance of the application, based on process ID and window class name.\n */\ntypedef struct _PHP_PREVIOUS_MAIN_WINDOW_CONTEXT\n{\n    HANDLE ProcessId;\n    PPH_STRING WindowName;\n} PHP_PREVIOUS_MAIN_WINDOW_CONTEXT, *PPHP_PREVIOUS_MAIN_WINDOW_CONTEXT;\n\n/**\n * Callback function for enumerating windows to find a previous instance.\n *\n * Checks if the given window belongs to the specified process and matches the\n * expected window class name. If found, attempts to activate and bring the window\n * to the foreground.\n *\n * \\param WindowHandle The handle to the window being enumerated.\n * \\param Context Pointer to a PHP_PREVIOUS_MAIN_WINDOW_CONTEXT structure.\n * \\return FALSE if the previous instance window was found and activated; TRUE to continue enumeration.\n */\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nstatic BOOLEAN CALLBACK PhPreviousInstanceWindowEnumProc(\n    _In_ HWND WindowHandle,\n    _In_ PVOID Context\n    )\n{\n    PPHP_PREVIOUS_MAIN_WINDOW_CONTEXT context = (PPHP_PREVIOUS_MAIN_WINDOW_CONTEXT)Context;\n    CLIENT_ID clientId;\n\n    if (!NT_SUCCESS(PhGetWindowClientId(WindowHandle, &clientId)))\n        return TRUE;\n\n    if (clientId.UniqueProcess == context->ProcessId)\n    {\n        WCHAR className[256];\n\n        if (GetClassName(WindowHandle, className, RTL_NUMBER_OF(className)))\n        {\n            if (PhEqualStringZ(className, PhGetString(context->WindowName), FALSE))\n            {\n                ULONG_PTR result = 0;\n\n                PhTrace(\n                    \"Found previous instance window: %ls (%p)\",\n                    className,\n                    WindowHandle\n                    );\n\n                SendMessageTimeout(\n                    WindowHandle,\n                    WM_PH_ACTIVATE,\n                    PhStartupParameters.SelectPid,\n                    0,\n                    SMTO_ABORTIFHUNG | SMTO_BLOCK,\n                    5000,\n                    &result\n                    );\n\n                if (result == PH_ACTIVATE_REPLY)\n                {\n                    if (!IsWindowVisible(WindowHandle))\n                    {\n                        ShowWindow(WindowHandle, SW_SHOW);\n                    }\n\n                    if (IsIconic(WindowHandle))\n                    {\n                        ShowWindow(WindowHandle, SW_RESTORE);\n                    }\n\n                    if (!SetForegroundWindow(WindowHandle))\n                    {\n                        PhBringWindowToTop(WindowHandle);\n                    }\n\n                    PhExitApplication(STATUS_SUCCESS);\n                    return FALSE;\n                }\n            }\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Brings a previous instance of the application to the foreground.\n *\n * This function attempts to locate the main window of a previous instance of the\n * application (by process ID and window class name), and brings it to the foreground.\n * It performs several checks to ensure the process is in the same session and owned\n * by the same user. The search is retried multiple times to handle race conditions.\n * \\param ProcessId The process ID of the previous instance.\n */\nstatic VOID PhForegroundPreviousInstance(\n    _In_ HANDLE ProcessId\n    )\n{\n    PHP_PREVIOUS_MAIN_WINDOW_CONTEXT context;\n    HANDLE processHandle = NULL;\n    HANDLE tokenHandle = NULL;\n    PH_TOKEN_USER tokenUser;\n    ULONG sessionId = 0;\n    ULONG attempts = 0;\n\n    PhTraceFuncEnter(\"Foreground previous instance: %lu\", HandleToUlong(ProcessId));\n\n    memset(&context, 0, sizeof(PHP_PREVIOUS_MAIN_WINDOW_CONTEXT));\n    context.ProcessId = ProcessId;\n    context.WindowName = PhGetStringSetting(SETTING_MAIN_WINDOW_CLASS_NAME);\n\n    if (PhIsNullOrEmptyString(context.WindowName))\n        goto CleanupExit;\n    if (!NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessId)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(PhGetProcessSessionId(processHandle, &sessionId)))\n        goto CleanupExit;\n    if (NtCurrentPeb()->SessionId != sessionId)\n        goto CleanupExit;\n    if (!NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser)))\n        goto CleanupExit;\n    if (!PhEqualSid(tokenUser.User.Sid, PhGetOwnTokenAttributes().TokenSid))\n        goto CleanupExit;\n\n    // Try to locate the window a few times because some users reported that it might not yet have been created. (dmex)\n    do\n    {\n        PhEnumWindowsEx(NULL, PhPreviousInstanceWindowEnumProc, &context);\n        PhDelayExecution(500);\n    } while (++attempts < 10);\n\nCleanupExit:\n\n    if (tokenHandle)\n    {\n        NtClose(tokenHandle);\n    }\n\n    if (processHandle)\n    {\n        NtClose(processHandle);\n    }\n\n    PhClearReference(&context.WindowName);\n\n    PhTraceFuncExit(\n        \"Foreground previous instance: %lu (%lu attempts)\",\n        HandleToUlong(ProcessId),\n        attempts\n        );\n}\n\n/**\n * Initializes previous instance detection and activation logic.\n *\n * This function enforces single-instance behavior and handles elevation scenarios.\n * If only one instance is allowed, it attempts to activate a previous instance.\n * If elevation is required, it runs the application as administrator and activates\n * the previous instance if necessary.\n */\nVOID PhInitializePreviousInstance(\n    VOID\n    )\n{\n    if (PhGetIntegerSetting(SETTING_ALLOW_ONLY_ONE_INSTANCE) &&\n        !PhStartupParameters.NewInstance &&\n        !PhStartupParameters.ShowOptions &&\n        !PhStartupParameters.PhSvc &&\n        !PhStartupParameters.KphStartupHigh &&\n        !PhStartupParameters.KphStartupMax)\n    {\n        PhActivatePreviousInstance();\n    }\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_START_AS_ADMIN) &&\n        !PhStartupParameters.NewInstance &&\n        !PhStartupParameters.ShowOptions &&\n        !PhStartupParameters.PhSvc)\n    {\n        if (PhGetOwnTokenAttributes().Elevated)\n        {\n            if (PhGetIntegerSetting(SETTING_ENABLE_START_AS_ADMIN_ALWAYS_ON_TOP))\n            {\n                if (NT_SUCCESS(PhRunAsAdminTaskUIAccess()))\n                {\n                    PhActivatePreviousInstance();\n                    PhExitApplication(STATUS_SUCCESS);\n                }\n            }\n        }\n        else\n        {\n            if (SUCCEEDED(PhRunAsAdminTask(&SI_RUNAS_ADMIN_TASK_NAME)))\n            {\n                PhActivatePreviousInstance();\n                PhExitApplication(STATUS_SUCCESS);\n            }\n        }\n    }\n}\n\n/**\n * Callback for enumerating namespace objects to find previous instances.\n *\n * This function is called for each object in the namespace directory. It looks for\n * mutant objects and, if found, checks if they belong to a different process.\n * If so, it attempts to bring the previous instance to the foreground.\n *\n * \\param RootDirectory The root directory handle.\n * \\param Name The name of the object.\n * \\param TypeName The type name of the object.\n * \\param Context Optional context pointer.\n * \\return STATUS_NO_MORE_ENTRIES if a previous instance\n * was found and activated; otherwise STATUS_SUCCESS.\n */\n_Function_class_(PH_ENUM_DIRECTORY_OBJECTS)\nNTSTATUS NTAPI PhpPreviousInstancesCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PPH_STRINGREF Name,\n    _In_ PPH_STRINGREF TypeName,\n    _In_ PVOID Context\n    )\n{\n    MUTANT_OWNER_INFORMATION objectInfo;\n    HANDLE objectHandle;\n\n    if (!PhStartsWithStringRef2(Name, L\"SiMutant_\", FALSE))\n        return STATUS_NAME_TOO_LONG;\n\n    if (NT_SUCCESS(PhOpenMutant(\n        &objectHandle,\n        MUTANT_QUERY_STATE,\n        RootDirectory,\n        Name\n        )))\n    {\n        if (NT_SUCCESS(PhGetMutantOwnerInformation(\n            objectHandle,\n            &objectInfo\n            )))\n        {\n            if (objectInfo.ClientId.UniqueProcess != NtCurrentProcessId())\n            {\n                PhForegroundPreviousInstance(objectInfo.ClientId.UniqueProcess);\n\n                NtClose(objectHandle);\n                return STATUS_NO_MORE_ENTRIES;\n            }\n        }\n\n        NtClose(objectHandle);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Activates a previous instance of the application if one exists.\n *\n * This function enumerates namespace objects to find a mutant object representing\n * a previous instance. If found, it brings the previous instance's window to the\n * foreground and exits the current process.\n */\nVOID PhActivatePreviousInstance(\n    VOID\n    )\n{\n    NTSTATUS status;\n    //HANDLE fileHandle;\n    //PPH_STRING applicationFileName;\n\n    PhTraceFuncEnter(\"Activate previous instance\");\n\n    status = PhEnumDirectoryObjects(PhGetNamespaceHandle(), PhpPreviousInstancesCallback, NULL);\n\n    //if (applicationFileName = PhGetApplicationFileName())\n    //{\n    //    if (NT_SUCCESS(status = PhOpenFile(\n    //        &fileHandle,\n    //        &applicationFileName->sr,\n    //        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n    //        NULL,\n    //        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n    //        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n    //        NULL\n    //        )))\n    //\n    //    {\n    //        PFILE_PROCESS_IDS_USING_FILE_INFORMATION processIds;\n    //\n    //        if (NT_SUCCESS(status = PhGetProcessIdsUsingFile(\n    //            fileHandle,\n    //            &processIds\n    //            )))\n    //\n    //        {\n    //            for (ULONG i = 0; i < processIds->NumberOfProcessIdsInList; i++)\n    //            {\n    //                HANDLE processId = processIds->ProcessIdList[i];\n    //                PPH_STRING fileName;\n    //\n    //                if (processId == NtCurrentProcessId())\n    //                    continue;\n    //\n    //                if (NT_SUCCESS(status = PhGetProcessImageFileNameByProcessId(processId, &fileName)))\n    //                {\n    //                    if (PhEqualString(applicationFileName, fileName, TRUE))\n    //                    {\n    //                        PhForegroundPreviousInstance(processId);\n    //                    }\n    //\n    //                    PhDereferenceObject(fileName);\n    //                }\n    //            }\n    //\n    //            PhFree(processIds);\n    //        }\n    //\n    //        NtClose(fileHandle);\n    //    }\n    //\n    //    PhDereferenceObject(applicationFileName);\n    //}\n\n    PhTraceFuncExit(\"Activate previous instance: %!STATUS!\", status);\n}\n\n/**\n * Initializes common controls and custom controls used by the application.\n *\n * This function registers standard Windows common controls and initializes\n * custom controls such as tree views, graphs, hex editors, and color boxes.\n * It must be called before creating windows that use these controls.\n */\nVOID PhInitializeCommonControls(\n    VOID\n    )\n{\n    INITCOMMONCONTROLSEX icex;\n\n    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);\n    icex.dwICC =\n        ICC_LISTVIEW_CLASSES |\n        ICC_TREEVIEW_CLASSES |\n        ICC_BAR_CLASSES |\n        ICC_TAB_CLASSES |\n        ICC_PROGRESS_CLASS |\n        ICC_COOL_CLASSES |\n        ICC_STANDARD_CLASSES |\n        ICC_LINK_CLASS\n        ;\n\n    InitCommonControlsEx(&icex);\n\n    PhTreeWindowAtom = PhTreeNewInitialization();\n    PhGraphWindowAtom = PhGraphControlInitialization();\n    PhHexEditWindowAtom = PhHexEditInitialization();\n    PhColorBoxWindowAtom = PhColorBoxInitialization();\n}\n\n/**\n * Ensures the current working directory is set to the application's directory.\n *\n * This function checks if the process's current directory matches the application's\n * directory. If not, it sets the current directory to the application's directory.\n */\nNTSTATUS PhInitializeDirectoryPolicy(\n    VOID\n    )\n{\n    PPH_STRING applicationDirectory;\n    UNICODE_STRING applicationDirectoryUs;\n    PH_STRINGREF currentDirectory;\n\n    if (!(applicationDirectory = PhGetApplicationDirectoryWin32()))\n        return STATUS_UNSUCCESSFUL;\n\n    PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath, &currentDirectory);\n\n    if (PhEqualStringRef(&applicationDirectory->sr, &currentDirectory, TRUE))\n    {\n        PhDereferenceObject(applicationDirectory);\n        return STATUS_SUCCESS;\n    }\n\n    if (!PhStringRefToUnicodeString(&applicationDirectory->sr, &applicationDirectoryUs))\n    {\n        PhDereferenceObject(applicationDirectory);\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    if (!NT_SUCCESS(RtlSetCurrentDirectory_U(&applicationDirectoryUs)))\n    {\n        PhDereferenceObject(applicationDirectory);\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    PhDereferenceObject(applicationDirectory);\n    return STATUS_SUCCESS;\n}\n\n#pragma region Error Reporting\n#include <symprv.h>\n#include <winsta.h>\n\ntypedef enum _PH_TRIAGE_DUMP_TYPE\n{\n    PhTriageDumpTypeMinimal,\n    PhTriageDumpTypeNormal,\n    PhTriageDumpTypeFull,\n} PH_TRIAGE_DUMP_TYPE;\n\n/**\n * Creates a crash dump file for an unhandled exception.\n *\n * \\param ExceptionInfo Pointer to the exception information.\n * \\param DumpType The type of dump to create (minimal, normal, or full).\n */\nVOID PhpCreateUnhandledExceptionCrashDump(\n    _In_ PEXCEPTION_POINTERS ExceptionInfo,\n    _In_ PH_TRIAGE_DUMP_TYPE DumpType\n    )\n{\n    HANDLE fileHandle;\n    PPH_STRING directory;\n    PPH_STRING fileName;\n    WCHAR alphastring[16] = L\"\";\n\n    PhGenerateRandomAlphaString(alphastring, RTL_NUMBER_OF(alphastring));\n    directory = PhExpandEnvironmentStringsZ(L\"\\\\??\\\\%USERPROFILE%\\\\Desktop\\\\\");\n    fileName = PhConcatStrings(5, PhGetString(directory), L\"SystemInformer\", L\"_DumpFile_\", alphastring, L\".dmp\");\n    PhCreateDirectoryFullPath(&fileName->sr);\n\n    if (NT_SUCCESS(PhCreateFile(\n        &fileHandle,\n        &fileName->sr,\n        FILE_GENERIC_WRITE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_WRITE,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        )))\n    {\n        MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;\n        ULONG dumpType = PhTriageDumpTypeMinimal;\n\n        exceptionInfo.ThreadId = HandleToUlong(NtCurrentThreadId());\n        exceptionInfo.ExceptionPointers = ExceptionInfo;\n        exceptionInfo.ClientPointers = TRUE;\n\n        switch (DumpType)\n        {\n        case PhTriageDumpTypeMinimal:\n            dumpType =\n                MiniDumpWithDataSegs |\n                MiniDumpWithUnloadedModules |\n                MiniDumpWithProcessThreadData |\n                MiniDumpWithThreadInfo |\n                MiniDumpIgnoreInaccessibleMemory;\n            break;\n        case PhTriageDumpTypeNormal:\n            dumpType =\n                MiniDumpWithDataSegs |\n                MiniDumpWithHandleData |\n                MiniDumpScanMemory |\n                MiniDumpWithUnloadedModules |\n                MiniDumpWithProcessThreadData |\n                MiniDumpWithFullMemoryInfo |\n                MiniDumpWithThreadInfo |\n                MiniDumpIgnoreInaccessibleMemory |\n                MiniDumpWithTokenInformation;\n            break;\n        case PhTriageDumpTypeFull:\n            dumpType =\n                MiniDumpWithDataSegs |\n                MiniDumpWithFullMemory |\n                MiniDumpWithHandleData |\n                MiniDumpWithUnloadedModules |\n                MiniDumpWithIndirectlyReferencedMemory |\n                MiniDumpWithProcessThreadData |\n                MiniDumpWithFullMemoryInfo |\n                MiniDumpWithThreadInfo |\n                MiniDumpIgnoreInaccessibleMemory |\n                MiniDumpWithTokenInformation |\n                MiniDumpWithAvxXStateContext;\n            break;\n        }\n\n        PhWriteMiniDumpProcess(\n            NtCurrentProcess(),\n            NtCurrentProcessId(),\n            fileHandle,\n            dumpType,\n            &exceptionInfo,\n            NULL,\n            NULL\n            );\n\n        NtClose(fileHandle);\n    }\n\n    PhDereferenceObject(fileName);\n    PhDereferenceObject(directory);\n}\n\nstatic LPTOP_LEVEL_EXCEPTION_FILTER PhpPreviousUnhandledExceptionFilter = NULL;\n\n/**\n * Unhandled exception filter callback for System Informer.\n *\n * This function is called when an unhandled exception occurs. It presents the user\n * with options to create a crash dump, restart, ignore, or exit. It also generates\n * a crash dump file on the desktop if requested.\n * \\param ExceptionInfo Pointer to the exception information.\n * \\return An exception disposition value.\n */\nLONG CALLBACK PhpUnhandledExceptionCallback(\n    _In_ PEXCEPTION_POINTERS ExceptionInfo\n    )\n{\n    PPH_STRING errorMessage;\n    PPH_STRING message;\n    LONG result;\n\n    // Let the debugger handle the exception. (dmex)\n    if (PhIsDebuggerPresent())\n    {\n        // Remove this return to debug the exception callback. (dmex)\n        return EXCEPTION_CONTINUE_SEARCH;\n    }\n\n    if (NT_SUCCESS(PhIsInteractiveUserSession()))\n    {\n        TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) };\n        TASKDIALOG_BUTTON buttons[6] =\n        {\n            { 101, L\"Full\\nA complete dump of the process, rarely needed most of the time.\" },\n            { 102, L\"Normal\\nFor most purposes, this dump file is the most useful.\" },\n            { 103, L\"Minimal\\nA very limited dump with limited data.\" },\n            { 104, L\"Restart\\nRestart the application.\" }, // and hope it doesn't crash again.\";\n            { 105, L\"Ignore\" },  // \\nTry ignore the exception and continue.\";\n            { 106, L\"Exit\" }, // \\nTerminate the program.\";\n        };\n\n        if (NT_NTWIN32(ExceptionInfo->ExceptionRecord->ExceptionCode))\n            errorMessage = PhGetStatusMessage(0, PhNtStatusToDosError(ExceptionInfo->ExceptionRecord->ExceptionCode));\n        else\n            errorMessage = PhGetStatusMessage(ExceptionInfo->ExceptionRecord->ExceptionCode, 0);\n\n        message = PhFormatString(\n            L\"0x%08X (%s)\",\n            ExceptionInfo->ExceptionRecord->ExceptionCode,\n            PhGetStringOrEmpty(errorMessage)\n            );\n\n        config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_USE_COMMAND_LINKS | TDF_EXPAND_FOOTER_AREA;\n        config.pszWindowTitle = PhApplicationName;\n        config.pszMainIcon = TD_ERROR_ICON;\n        config.pszMainInstruction = L\"System Informer has crashed :(\";\n        config.cButtons = RTL_NUMBER_OF(buttons);\n        config.pButtons = buttons;\n        config.nDefaultButton = 106;\n        config.cxWidth = 250;\n        config.pszContent = PhGetString(message);\n#ifdef DEBUG\n        config.pszExpandedInformation = PhGetString(PhGetStacktraceAsString());\n#endif\n\n        if (PhShowTaskDialog(&config, &result, NULL, NULL))\n        {\n            switch (result)\n            {\n            case 101:\n                PhpCreateUnhandledExceptionCrashDump(ExceptionInfo, PhTriageDumpTypeFull);\n                break;\n            case 102:\n                PhpCreateUnhandledExceptionCrashDump(ExceptionInfo, PhTriageDumpTypeNormal);\n                break;\n            case 103:\n                PhpCreateUnhandledExceptionCrashDump(ExceptionInfo, PhTriageDumpTypeMinimal);\n                break;\n            case 104:\n                {\n                    PhShellProcessHacker(\n                        NULL,\n                        NULL,\n                        SW_SHOW,\n                        PH_SHELL_EXECUTE_DEFAULT,\n                        PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY,\n                        0,\n                        NULL\n                        );\n                }\n                break;\n            case 105:\n                {\n                    return EXCEPTION_CONTINUE_EXECUTION;\n                }\n                break;\n            }\n        }\n        else\n        {\n            if (PhShowMessage(\n                NULL,\n                MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2,\n                L\"System Informer has crashed :(\\r\\n\\r\\n%s\",\n                L\"Do you want to create a minidump on the Desktop?\"\n                ) == IDYES)\n            {\n                PhpCreateUnhandledExceptionCrashDump(ExceptionInfo, PhTriageDumpTypeMinimal);\n            }\n        }\n    }\n    else\n    {\n        ULONG response;\n        PPH_STRING title;\n\n        if (NT_NTWIN32(ExceptionInfo->ExceptionRecord->ExceptionCode))\n            errorMessage = PhGetStatusMessage(0, PhNtStatusToDosError(ExceptionInfo->ExceptionRecord->ExceptionCode));\n        else\n            errorMessage = PhGetStatusMessage(ExceptionInfo->ExceptionRecord->ExceptionCode, 0);\n\n        title = PhCreateString(L\"System Informer has crashed :(\");\n#ifdef DEBUG\n        message = PhFormatString(\n            L\"%s\\r\\n0x%08X (%s)\\r\\n%s\",\n            PhGetStringOrEmpty(title),\n            ExceptionInfo->ExceptionRecord->ExceptionCode,\n            PhGetStringOrEmpty(errorMessage),\n            PhGetString(PhGetStacktraceAsString())\n            );\n#else\n        message = PhFormatString(\n            L\"%s\\r\\n0x%08X (%s)\\r\\n%s\",\n            PhGetStringOrEmpty(title),\n            ExceptionInfo->ExceptionRecord->ExceptionCode,\n            PhGetStringOrEmpty(errorMessage)\n            );\n#endif\n        if (WinStationSendMessageW(\n            SERVERNAME_CURRENT,\n            USER_SHARED_DATA->ActiveConsoleId, // RtlGetActiveConsoleId\n            title->Buffer,\n            (ULONG)title->Length,\n            message->Buffer,\n            (ULONG)message->Length,\n            MB_OKCANCEL | MB_ICONERROR,\n            30,\n            &response,\n            FALSE\n            ))\n        {\n#ifdef DEBUG\n            if (response == IDOK)\n            {\n                PhpCreateUnhandledExceptionCrashDump(ExceptionInfo, PhTriageDumpTypeFull);\n            }\n#endif\n        }\n    }\n\n    return PhpPreviousUnhandledExceptionFilter(ExceptionInfo);\n}\n#pragma endregion\n\n/**\n * Initializes the exception policy for the current process.\n *\n * This function configures the process error mode to suppress critical error dialogs\n * and disables the Windows error reporting dialog for unhandled exceptions. It also\n * installs a custom unhandled exception filter to handle application crashes, generate\n * crash dumps, and present user-friendly dialogs or messages.\n */\nNTSTATUS PhInitializeExceptionPolicy(\n    VOID\n    )\n{\n#if PHNT_MINIMAL_ERRORMODE\n    ULONG errorMode;\n\n    if (NT_SUCCESS(PhGetProcessErrorMode(NtCurrentProcess(), &errorMode)))\n    {\n        ClearFlag(errorMode, SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);\n        PhSetProcessErrorMode(NtCurrentProcess(), errorMode);\n    }\n#else\n    PhSetProcessErrorMode(NtCurrentProcess(), 0);\n#endif\n    PhpPreviousUnhandledExceptionFilter = SetUnhandledExceptionFilter(PhpUnhandledExceptionCallback);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Initializes the namespace policy for the current process.\n *\n * This function creates a named mutant object in the process's namespace to enforce\n * single-instance behavior and activate previous instances of System Informer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhInitializeNamespacePolicy(\n    VOID\n    )\n{\n    HANDLE mutantHandle;\n    SIZE_T returnLength;\n    WCHAR formatBuffer[PH_INT64_STR_LEN_1];\n    OBJECT_ATTRIBUTES objectAttributes;\n    UNICODE_STRING objectName;\n    PH_STRINGREF objectNameSr;\n    PH_FORMAT format[2];\n\n    PhInitFormatS(&format[0], L\"SiMutant_\");\n    PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId()));\n\n    if (!PhFormatToBuffer(\n        format,\n        RTL_NUMBER_OF(format),\n        formatBuffer,\n        sizeof(formatBuffer),\n        &returnLength\n        ))\n    {\n        return STATUS_BUFFER_TOO_SMALL;\n    }\n\n    objectNameSr.Length = returnLength - sizeof(UNICODE_NULL);\n    objectNameSr.Buffer = formatBuffer;\n\n    if (!PhStringRefToUnicodeString(&objectNameSr, &objectName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        PhGetNamespaceHandle(),\n        NULL\n        );\n\n    NtCreateMutant(\n        &mutantHandle,\n        MUTANT_QUERY_STATE,\n        &objectAttributes,\n        TRUE\n        );\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Initializes the default COM options for the current process.\n *\n * If PH_COM_SVC is defined, it configures global COM options and sets a custom security descriptor\n * that allows access to authenticated users, local system, and administrators. Otherwise, it simply\n * initializes COM with apartment threading and disables OLE1 DDE.\n */\nNTSTATUS PhInitializeComPolicy(\n    VOID\n    )\n{\n#ifdef PH_COM_SVC\n    #include <cguid.h>\n    IGlobalOptions* globalOptions;\n    UCHAR securityDescriptorBuffer[SECURITY_DESCRIPTOR_MIN_LENGTH + 0x300];\n    PSECURITY_DESCRIPTOR securityDescriptor = (PSECURITY_DESCRIPTOR)securityDescriptorBuffer;\n    PSID administratorsSid = PhSeAdministratorsSid();\n    ULONG securityDescriptorAllocationLength;\n    PACL dacl;\n\n    if (!SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)))\n        return TRUE; // Continue without COM support. (dmex)\n\n    if (SUCCEEDED(PhGetClassObject(L\"combase.dll\", &CLSID_GlobalOptions, &IID_IGlobalOptions, &globalOptions)))\n    {\n        #define COMGLB_PROPERTIES_EXPLICIT_WINSTA_DESKTOP COMGLB_PROPERTIES_RESERVED1\n        #define COMGLB_PROCESS_MITIGATION_POLICY_BLOB COMGLB_PROPERTIES_RESERVED2\n        #define COMGLB_ENABLE_AGILE_OOP_PROXIES COMGLB_RESERVED1\n        #define COMGLB_ENABLE_WAKE_ON_RPC_SUPPRESSION COMGLB_RESERVED2\n        #define COMGLB_ADD_RESTRICTEDCODE_SID_TO_COM_CALLPERMISSIONS COMGLB_RESERVED3\n        #define HKLM_ONLY_CLASSIC_COM_CATALOG COMGLB_RESERVED5\n\n        IGlobalOptions_Set(globalOptions, COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE_ANY);\n        IGlobalOptions_Set(globalOptions, COMGLB_RO_SETTINGS, COMGLB_FAST_RUNDOWN | COMGLB_ENABLE_AGILE_OOP_PROXIES | HKLM_ONLY_CLASSIC_COM_CATALOG);\n        IGlobalOptions_Release(globalOptions);\n    }\n\n    securityDescriptorAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH +\n        (ULONG)sizeof(ACL) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        PhLengthSid(&PhSeAuthenticatedUserSid) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        PhLengthSid(&PhSeLocalSystemSid) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        PhLengthSid(&administratorsSid);\n\n    dacl = PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH);\n    PhCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n    PhCreateAcl(dacl, securityDescriptorAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION);\n    PhAddAccessAllowedAce(dacl, ACL_REVISION, FILE_READ_DATA | FILE_WRITE_DATA, &PhSeAuthenticatedUserSid);\n    PhAddAccessAllowedAce(dacl, ACL_REVISION, FILE_READ_DATA | FILE_WRITE_DATA, &PhSeLocalSystemSid);\n    PhAddAccessAllowedAce(dacl, ACL_REVISION, FILE_READ_DATA | FILE_WRITE_DATA, administratorsSid);\n    PhSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE);\n    PhSetGroupSecurityDescriptor(securityDescriptor, administratorsSid, FALSE);\n    PhSetOwnerSecurityDescriptor(securityDescriptor, administratorsSid, FALSE);\n\n    if (!SUCCEEDED(CoInitializeSecurity(\n        securityDescriptor,\n        UINT_MAX,\n        NULL,\n        NULL,\n        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,\n        RPC_C_IMP_LEVEL_IDENTIFY,\n        NULL,\n        EOAC_NONE,\n        NULL\n        )))\n    {\n        NOTHING;\n    }\n\n#ifdef DEBUG\n    assert(RtlValidSecurityDescriptor(securityDescriptor));\n    assert(securityDescriptorAllocationLength < sizeof(securityDescriptorBuffer));\n    assert(RtlLengthSecurityDescriptor(securityDescriptor) < sizeof(securityDescriptorBuffer));\n#endif\n\n    return TRUE;\n#else\n    if (!SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)))\n        NOTHING;\n\n    return STATUS_SUCCESS;\n#endif\n}\n\n/**\n * Initializes the execution policy for System Informer.\n *\n * This function checks if the Shift key is held down during startup. If so, it attempts\n * to launch Task Manager (`taskmgr.exe`) instead of System Informer.\n * This provides a quick way for users to access Task Manager if needed, for example,\n * if System Informer is set as the default Task Manager replacement and the user\n * wants to access the original Task Manager without changing settings.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhInitializeExecutionPolicy(\n    VOID\n    )\n{\n    // Note: GetAsyncKeyState queries the global keyboard bitmask without kernel transitions, blocking,\n    // handles, events or messages etc... The bitmask is also independent of any message loop or window.\n    // We can call it extremely early but only the high bit (0x8000) of the key state is valid without a message loop.\n\n    if (GetAsyncKeyState(VK_SHIFT) & 0x8000)\n    {\n        if (NT_SUCCESS(PhShellExecuteEx(NULL, L\"taskmgr.exe\", NULL, NULL, SW_SHOW, 0, 0, NULL)))\n        {\n            PhExitApplication(STATUS_SUCCESS);\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Initializes the mitigation policies for the current process.\n *\n * This function configures process-level mitigations to prevent crashes by third party software. *\n * The function uses the Native API to set the mitigation policy. If the operating system does not\n * support the required mitigation policies, the function performs no action and returns success.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhInitializeMitigationPolicy(\n    VOID\n    )\n{\n#if defined(PH_BUILD_API)\n    if (WindowsVersion >= WINDOWS_10)\n    {\n        PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;\n\n        //policyInfo.Policy = ProcessDynamicCodePolicy;\n        //policyInfo.DynamicCodePolicy.Flags = 0;\n        //policyInfo.DynamicCodePolicy.ProhibitDynamicCode = TRUE;\n        //NtSetInformationProcess(NtCurrentProcess(), ProcessMitigationPolicy, &policyInfo, sizeof(PROCESS_MITIGATION_POLICY_INFORMATION));\n\n        policyInfo.Policy = ProcessExtensionPointDisablePolicy;\n        policyInfo.ExtensionPointDisablePolicy.Flags = 0;\n        policyInfo.ExtensionPointDisablePolicy.DisableExtensionPoints = TRUE;\n        NtSetInformationProcess(NtCurrentProcess(), ProcessMitigationPolicy, &policyInfo, sizeof(PROCESS_MITIGATION_POLICY_INFORMATION));\n\n        policyInfo.Policy = ProcessSignaturePolicy;\n        policyInfo.SignaturePolicy.Flags = 0;\n        policyInfo.SignaturePolicy.MicrosoftSignedOnly = TRUE;\n        NtSetInformationProcess(NtCurrentProcess(), ProcessMitigationPolicy, &policyInfo, sizeof(PROCESS_MITIGATION_POLICY_INFORMATION));\n\n        //policyInfo.Policy = ProcessRedirectionTrustPolicy;\n        //policyInfo.RedirectionTrustPolicy.Flags = 0;\n        //policyInfo.RedirectionTrustPolicy.EnforceRedirectionTrust = TRUE;\n        //NtSetInformationProcess(NtCurrentProcess(), ProcessMitigationPolicy, &policyInfo, sizeof(PROCESS_MITIGATION_POLICY_INFORMATION));\n    }\n#endif\n    return STATUS_SUCCESS;\n}\n\n/**\n * Initializes a temporary desktop policy for process isolation or UI testing.\n *\n * This function creates a new random desktop, switches the current thread and input\n * to that desktop, and launches a new instance of System Informer on it. After the\n * child process exits, it restores the original desktop and cleans up resources.\n *\n * \\remarks The function is typically used for scenarios where process isolation or UI testing\n * is required on a separate desktop, such as security testing or debugging.\n */\nVOID PhInitializeDesktopPolicy(\n    VOID\n    )\n{\n    NTSTATUS status;\n    HDESK desktopHandle;\n    WCHAR alphastring[16] = L\"\";\n\n    PhGenerateRandomAlphaString(alphastring, RTL_NUMBER_OF(alphastring));\n\n    if (desktopHandle = CreateDesktop(\n        alphastring,\n        NULL,\n        NULL,\n        0,\n        DESKTOP_CREATEWINDOW,\n        NULL\n        ))\n    {\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        HANDLE processHandle;\n        HDESK processDesktop;\n\n        processDesktop = GetThreadDesktop(HandleToUlong(NtCurrentThreadId()));\n\n        SetThreadDesktop(desktopHandle);\n        SwitchDesktop(desktopHandle);\n\n        if (NT_SUCCESS(PhShellProcessHacker(\n            NULL,\n            NULL,\n            SW_SHOW,\n            PH_SHELL_EXECUTE_DEFAULT,\n            PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY,\n            0,\n            &processHandle\n            )))\n        {\n            PhWaitForSingleObject(processHandle, INFINITE);\n            NtClose(processHandle);\n        }\n\n        SwitchDesktop(processDesktop);\n        SetThreadDesktop(processDesktop);\n\n        CloseDesktop(desktopHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(NULL, L\"Unable to initialize desktop policy.\", status, 0);\n    }\n\n    PhExitApplication(status);\n}\n\n/**\n * Enables or disables the process break-on-termination policy.\n *\n * This function configures the process to trigger a system critical break if it is terminated,\n * based on the specified flag. When enabled, the process is protected from termination by\n * non-privileged users, and the system will generate a critical error if the process is killed.\n * This is typically used to prevent accidental or unauthorized termination of critical processes.\n * The function only applies the policy if the current process is running with elevated privileges\n * and the \"Enable Break On Termination\" setting is enabled.\n * \\param Enabled TRUE to enable the break-on-termination policy; FALSE to disable it.\n */\nVOID PhEnableTerminationPolicy(\n    _In_ BOOLEAN Enabled\n    )\n{\n    if (PhGetOwnTokenAttributes().Elevated && PhGetIntegerSetting(SETTING_ENABLE_BREAK_ON_TERMINATION))\n    {\n        NTSTATUS status;\n\n        status = PhSetProcessBreakOnTermination(\n            NtCurrentProcess(),\n            Enabled\n            );\n\n        if (Enabled)\n            SetFlag(NtCurrentPeb()->NtGlobalFlag, FLG_ENABLE_SYSTEM_CRIT_BREAKS);\n        else\n            ClearFlag(NtCurrentPeb()->NtGlobalFlag, FLG_ENABLE_SYSTEM_CRIT_BREAKS);\n\n        if (!NT_SUCCESS(status))\n        {\n            PhShowStatus(NULL, L\"Unable to configure termination policy.\", status, 0);\n        }\n    }\n}\n\n/**\n * Initializes the timer policy for the system.\n *\n * This function sets up and configures the timer policy that will be used\n * throughout the System Informer application for timing operations and measurements.\n */\nNTSTATUS PhInitializeTimerPolicy(\n    VOID\n    )\n{\n    static BOOL timerSuppression = FALSE;\n\n    SetUserObjectInformation(NtCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, &timerSuppression, sizeof(BOOL));\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Initializes the application system.\n * \n * This function performs the necessary initialization of the System Informer\n * application system, setting up core components and resources required for\n * the application to function properly.\n */\nNTSTATUS PhInitializeAppSystem(\n    VOID\n    )\n{\n    if (!PhProcessProviderInitialization())\n        return STATUS_UNSUCCESSFUL;\n    if (!PhServiceProviderInitialization())\n        return STATUS_UNSUCCESSFUL;\n    if (!PhNetworkProviderInitialization())\n        return STATUS_UNSUCCESSFUL;\n\n    PhSetHandleClientIdFunction(PhGetClientIdName);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Initializes the application settings.\n *\n * This function sets up and initializes all application-level settings,\n * including user preferences, configuration values, and default parameters\n * required for the System Informer application to function properly.\n */\nVOID PhInitializeAppSettings(\n    VOID\n    )\n{\n    PhSettingsInitialization();\n    PhAddDefaultSettings();\n\n    if (!PhStartupParameters.NoSettings)\n    {\n        // There are three possible locations for the settings file:\n        // 1. The file name given in the command line.\n        // 2. A file named SystemInformer.exe.settings.json in the program directory. (This changes\n        //    based on the executable file name.)\n        // 3. The default location.\n        NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;\n        PPH_STRING settingsPath = NULL;\n        PPH_STRING basePath = NULL;\n\n        // 1. File specified in command line\n        if (PhStartupParameters.SettingsFileName)\n        {\n            if (PhDetermineDosPathNameType(&PhStartupParameters.SettingsFileName->sr) == RtlPathTypeRooted)\n            {\n                PhSetReference(&PhSettingsFileName, PhStartupParameters.SettingsFileName);\n            }\n            else\n            {\n                PPH_STRING settingsFileName;\n\n                // Get an absolute path now.\n                if (NT_SUCCESS(PhGetFullPath(PhGetString(PhStartupParameters.SettingsFileName), &settingsFileName, NULL)))\n                {\n                    PhMoveReference(&settingsFileName, PhDosPathNameToNtPathName(&settingsFileName->sr));\n\n                    if (!PhIsNullOrEmptyString(settingsFileName))\n                    {\n                        PhMoveReference(&PhSettingsFileName, settingsFileName);\n                    }\n                }\n            }\n\n            if (PhSettingsFileName)\n            {\n                status = PhLoadSettings(&PhSettingsFileName->sr);\n            }\n        }\n\n        // 2. Default locations (AppData)\n        if (PhIsNullOrEmptyString(PhSettingsFileName) || !NT_SUCCESS(status))\n        {\n            status = PhLoadSettingsAutoDetect(NULL, L\"settings\", &settingsPath, NULL, &PhPortableEnabled);\n\n            if (NT_SUCCESS(status) || status == STATUS_OBJECT_NAME_NOT_FOUND)\n            {\n                PhMoveReference(&PhSettingsFileName, settingsPath);\n            }\n        }\n\n        // Handle errors\n        if (status == STATUS_FILE_CORRUPT_ERROR)\n        {\n            if (PhShowMessage2(\n                NULL,\n                TD_YES_BUTTON | TD_NO_BUTTON,\n                TD_WARNING_ICON,\n                L\"System Informer's settings file is corrupt. Do you want to reset it?\",\n                L\"If you select No, the settings system will not function properly.\"\n                ) == IDYES)\n            {\n                if (PhSettingsFileName)\n                    PhResetSettingsFile(&PhSettingsFileName->sr);\n            }\n            else\n            {\n                PhDereferenceObject(PhSettingsFileName);\n                PhSettingsFileName = NULL;\n            }\n        }\n        else if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND)\n        {\n            PhShowStatus(NULL, L\"Unable to load the settings file.\", status, 0);\n        }\n    }\n\n    PhUpdateCachedSettings();\n\n    //PhSettingsInitialization();\n    //PhAddDefaultSettings();\n\n    //if (!PhStartupParameters.NoSettings)\n    //{\n    //    // There are three possible locations for the settings file:\n    //    // 1. The file name given in the command line.\n    //    // 2. A file named SystemInformer.exe.settings.json in the program directory. (This changes\n    //    //    based on the executable file name.)\n    //    // 3. The default location.\n\n    //    // 1. File specified in command line\n    //    if (PhStartupParameters.SettingsFileName)\n    //    {\n    //        if (PhDetermineDosPathNameType(&PhStartupParameters.SettingsFileName->sr) == RtlPathTypeRooted)\n    //        {\n    //            PhSetReference(&PhSettingsFileName, PhStartupParameters.SettingsFileName);\n    //        }\n    //        else\n    //        {\n    //            PPH_STRING settingsFileName;\n\n    //            // Get an absolute path now.\n    //            if (NT_SUCCESS(PhGetFullPath(PhGetString(PhStartupParameters.SettingsFileName), &settingsFileName, NULL)))\n    //            {\n    //                PhMoveReference(&settingsFileName, PhDosPathNameToNtPathName(&settingsFileName->sr));\n\n    //                if (!PhIsNullOrEmptyString(settingsFileName))\n    //                {\n    //                    PhMoveReference(&PhSettingsFileName, settingsFileName);\n    //                }\n    //            }\n    //        }\n    //    }\n\n    //    // 2. File in program directory (portable mode)\n    //    if (PhIsNullOrEmptyString(PhSettingsFileName))\n    //    {\n    //        PPH_STRING settingsFileName;\n\n    //        // Try .settings.json first\n    //        if (settingsFileName = PhGetApplicationFileNameZ(L\".settings.json\"))\n    //        {\n    //            if (PhDoesFileExist(&settingsFileName->sr))\n    //            {\n    //                PhMoveReference(&PhSettingsFileName, settingsFileName);\n    //                PhPortableEnabled = TRUE;\n    //            }\n    //            else\n    //            {\n    //                PhDereferenceObject(settingsFileName);\n\n    //                // Try .settings.xml (legacy)\n    //                if (settingsFileName = PhGetApplicationFileNameZ(L\".settings.xml\"))\n    //                {\n    //                    if (PhDoesFileExist(&settingsFileName->sr))\n    //                    {\n    //                        PPH_STRING jsonFileName = PhGetBaseNameChangeExtensionZ(&settingsFileName->sr, L\".json\");\n\n    //                        // Convert XML to JSON\n    //                        NTSTATUS convertStatus = PhConvertSettingsXmlToJson(\n    //                            &settingsFileName->sr,\n    //                            &jsonFileName->sr\n    //                            );\n\n    //                        if (NT_SUCCESS(convertStatus))\n    //                        {\n    //                            PhMoveReference(&PhSettingsFileName, jsonFileName);\n    //                            PhPortableEnabled = TRUE;\n    //                        }\n    //                        else\n    //                        {\n    //                            PhShowStatus(NULL, L\"Unable to convert settings to json format.\", convertStatus, 0);\n    //                            PhDereferenceObject(jsonFileName);\n    //                        }\n    //                    }\n    //                    else\n    //                    {\n    //                        PhDereferenceObject(settingsFileName);\n    //                    }\n    //                }\n    //            }\n    //        }\n    //    }\n\n    //    // 3. Default location\n    //    if (PhIsNullOrEmptyString(PhSettingsFileName))\n    //    {\n    //        PhSettingsFileName = PhGetKnownLocationZ(PH_FOLDERID_RoamingAppData, L\"\\\\SystemInformer\\\\settings.json\", TRUE);\n    //    }\n\n    //    if (!PhIsNullOrEmptyString(PhSettingsFileName))\n    //    {\n    //        NTSTATUS status;\n\n    //        status = PhLoadSettings(&PhSettingsFileName->sr);\n\n    //        // If JSON file not found, try to convert from XML\n    //        if (status == STATUS_OBJECT_NAME_NOT_FOUND)\n    //        {\n    //            PPH_STRING xmlFileName = PhGetBaseNameChangeExtensionZ(&PhSettingsFileName->sr, L\".xml\");\n\n    //            if (!PhIsNullOrEmptyString(xmlFileName))\n    //            {\n    //                if (PhDoesFileExist(&xmlFileName->sr))\n    //                {\n    //                    // Convert XML to JSON\n    //                    NTSTATUS convertStatus = PhConvertSettingsXmlToJson(\n    //                        &xmlFileName->sr,\n    //                        &PhSettingsFileName->sr\n    //                        );\n\n    //                    if (NT_SUCCESS(convertStatus))\n    //                    {\n    //                        // Retry loading from newly created JSON file\n    //                        status = PhLoadSettings(&PhSettingsFileName->sr);\n    //                    }\n    //                    else\n    //                    {\n    //                        PhShowStatus(NULL, L\"Unable to convert settings to json format.\", convertStatus, 0);\n    //                    }\n    //                }\n\n    //                PhDereferenceObject(xmlFileName);\n    //            }\n    //        }\n\n    //        // If we didn't find the file, it will be created. Otherwise,\n    //        // there was probably a parsing error and we don't want to\n    //        // change anything.\n    //        if (status == STATUS_FILE_CORRUPT_ERROR)\n    //        {\n    //            if (PhShowMessage2(\n    //                NULL,\n    //                TD_YES_BUTTON | TD_NO_BUTTON,\n    //                TD_WARNING_ICON,\n    //                L\"System Informer's settings file is corrupt. Do you want to reset it?\",\n    //                L\"If you select No, the settings system will not function properly.\"\n    //                ) == IDYES)\n    //            {\n    //                PhResetSettingsFile(&PhSettingsFileName->sr);\n    //            }\n    //            else\n    //            {\n    //                // Pretend we don't have a settings file, the user can resolve the issue\n    //                // in this case without resetting the user(s) settings or customization to defaults.\n    //                PhDereferenceObject(PhSettingsFileName);\n    //                PhSettingsFileName = NULL;\n    //            }\n    //        }\n    //        else if (!NT_SUCCESS(status))\n    //        {\n    //            PhShowStatus(NULL, L\"Unable to load the settings file.\", status, 0);\n    //        }\n    //    }\n    //}\n\n    //PhUpdateCachedSettings();\n\n    // Apply basic global settings.\n    PhPluginsEnabled = !!PhGetIntegerSetting(SETTING_ENABLE_PLUGINS);\n    PhMaxSizeUnit = PhGetIntegerSetting(SETTING_MAX_SIZE_UNIT);\n    PhMaxPrecisionUnit = (USHORT)PhGetIntegerSetting(SETTING_MAX_PRECISION_UNIT);\n    PhMaxPrecisionLimit = 1.0f;\n    for (ULONG i = 0; i < PhMaxPrecisionUnit; i++)\n        PhMaxPrecisionLimit /= 10;\n    PhEnableWindowText = !!PhGetIntegerSetting(SETTING_ENABLE_WINDOW_TEXT);\n\n    PhEnableThemeSupport = !!PhGetIntegerSetting(SETTING_ENABLE_THEME_SUPPORT);\n    PhThemeWindowForegroundColor = PhGetIntegerSetting(SETTING_THEME_WINDOW_FOREGROUND_COLOR);\n    PhThemeWindowBackgroundColor = PhGetIntegerSetting(SETTING_THEME_WINDOW_BACKGROUND_COLOR);\n    PhThemeWindowBackground2Color = PhGetIntegerSetting(SETTING_THEME_WINDOW_BACKGROUND2_COLOR);\n    PhThemeWindowHighlightColor = PhGetIntegerSetting(SETTING_THEME_WINDOW_HIGHLIGHT_COLOR);\n    PhThemeWindowHighlight2Color = PhGetIntegerSetting(SETTING_THEME_WINDOW_HIGHLIGHT2_COLOR);\n    PhThemeWindowTextColor = PhGetIntegerSetting(SETTING_THEME_WINDOW_TEXT_COLOR);\n    PhEnableThemeAcrylicSupport = WindowsVersion >= WINDOWS_11 && !!PhGetIntegerSetting(SETTING_ENABLE_THEME_ACRYLIC_SUPPORT);\n    PhEnableThemeAcrylicWindowSupport = WindowsVersion >= WINDOWS_11 && !!PhGetIntegerSetting(SETTING_ENABLE_THEME_ACRYLIC_WINDOW_SUPPORT);\n    PhEnableThemeNativeButtons = !!PhGetIntegerSetting(SETTING_ENABLE_THEME_NATIVE_BUTTONS);\n    PhEnableThemeListviewBorder = !!PhGetIntegerSetting(SETTING_TREE_LIST_BORDER_ENABLE);\n    PhEnableDeferredLayout = !!PhGetIntegerSetting(SETTING_ENABLE_DEFERRED_LAYOUT);\n    PhEnableServiceNonPoll = !!PhGetIntegerSetting(SETTING_ENABLE_SERVICE_NON_POLL);\n    PhEnableServiceNonPollNotify = !!PhGetIntegerSetting(SETTING_ENABLE_SERVICE_NON_POLL_NOTIFY);\n    PhServiceNonPollFlushInterval = PhGetIntegerSetting(SETTING_NON_POLL_FLUSH_INTERVAL);\n    PhEnableKsiSupport = !!PhGetIntegerSetting(SETTING_KSI_ENABLE) && !PhStartupParameters.NoKph && !PhIsExecutingInWow64();\n    PhEnableKsiWarnings = !!PhGetIntegerSetting(SETTING_KSI_ENABLE_WARNINGS);\n    PhFontQuality = PhGetFontQualitySetting(PhGetIntegerSetting(SETTING_FONT_QUALITY));\n\n    if (PhGetIntegerSetting(SETTING_SAMPLE_COUNT_AUTOMATIC))\n    {\n        ULONG sampleCount;\n\n        sampleCount = (PhGetSystemMetrics(SM_CXVIRTUALSCREEN, 0) + 1) / 2;\n\n        if (sampleCount > 4096)\n            sampleCount = 4096;\n\n        PhSetIntegerSetting(SETTING_SAMPLE_COUNT, sampleCount);\n    }\n\n    if (PhStartupParameters.UpdateChannel != PhInvalidChannel)\n    {\n        PhSetIntegerSetting(SETTING_RELEASE_CHANNEL, PhStartupParameters.UpdateChannel);\n    }\n\n    if (PhStartupParameters.ShowHidden && !PhNfIconsEnabled())\n    {\n        // HACK(jxy-s) The default used to be that system tray icons where enabled, this keeps the\n        // old behavior for automation workflows. If the user specified \"-hide\" then they want to\n        // start the program hidden to the system tray and not show any main window. If there are no\n        // system tray icons enabled then we need to enable them so the behavior is consistent.\n        PhSetStringSetting(SETTING_ICON_SETTINGS, L\"2|1\");\n    }\n}\n\ntypedef enum _PH_COMMAND_ARG\n{\n    PH_ARG_NONE,\n    PH_ARG_SETTINGS,\n    PH_ARG_NOSETTINGS,\n    PH_ARG_SHOWVISIBLE,\n    PH_ARG_SHOWHIDDEN,\n    PH_ARG_RUNASSERVICEMODE,\n    PH_ARG_NOKPH,\n    PH_ARG_DEBUG,\n    PH_ARG_HWND,\n    PH_ARG_POINT,\n    PH_ARG_SHOWOPTIONS,\n    PH_ARG_PHSVC,\n    PH_ARG_NOPLUGINS,\n    PH_ARG_NEWINSTANCE,\n    PH_ARG_ELEVATE,\n    PH_ARG_SILENT,\n    PH_ARG_HELP,\n    PH_ARG_SELECTPID,\n    PH_ARG_PRIORITY,\n    PH_ARG_PLUGIN,\n    PH_ARG_SELECTTAB,\n    PH_ARG_SYSINFO,\n    PH_ARG_KPHSTARTUPHIGH,\n    PH_ARG_KPHSTARTUPMAX,\n    PH_ARG_CHANNEL,\n} PH_COMMAND_ARG;\n\n/**\n * Callback function for processing command line options.\n *\n * This function is invoked for each parsed command line option during application startup.\n * It updates the global PhStartupParameters structure and related state based on the provided\n * option and value. Supported options include settings file path, visibility, debug mode,\n * privilege elevation, plugin parameters, process priority, and more.\n *\n * \\param Option Pointer to the command line option structure, or NULL for non-option arguments.\n * \\param Value Optional value associated with the option, or NULL if not applicable.\n * \\param Context Optional context pointer (unused).\n * \\return TRUE to continue processing further options, or FALSE to stop.\n */\n_Function_class_(PH_COMMAND_LINE_CALLBACK)\nBOOLEAN NTAPI PhpCommandLineOptionCallback(\n    _In_opt_ PCPH_COMMAND_LINE_OPTION Option,\n    _In_opt_ PPH_STRING Value,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG64 integer;\n\n    if (Option)\n    {\n        switch (Option->Id)\n        {\n        case PH_ARG_SETTINGS:\n            PhSwapReference(&PhStartupParameters.SettingsFileName, Value);\n            break;\n        case PH_ARG_NOSETTINGS:\n            PhStartupParameters.NoSettings = TRUE;\n            break;\n        case PH_ARG_SHOWVISIBLE:\n            PhStartupParameters.ShowVisible = TRUE;\n            break;\n        case PH_ARG_SHOWHIDDEN:\n            PhStartupParameters.ShowHidden = TRUE;\n            break;\n        case PH_ARG_RUNASSERVICEMODE:\n            PhSwapReference(&PhStartupParameters.RunAsServiceMode, Value);\n            break;\n        case PH_ARG_NOKPH:\n            PhStartupParameters.NoKph = TRUE;\n            break;\n        case PH_ARG_DEBUG:\n            PhStartupParameters.Debug = TRUE;\n            break;\n        case PH_ARG_HWND:\n            if (Value && PhStringToInteger64(&Value->sr, 16, &integer))\n                PhStartupParameters.WindowHandle = (HWND)(ULONG_PTR)integer;\n            break;\n        case PH_ARG_POINT:\n            {\n                PH_STRINGREF xString;\n                PH_STRINGREF yString;\n\n                if (Value && PhSplitStringRefAtChar(&Value->sr, L',', &xString, &yString))\n                {\n                    LONG64 x;\n                    LONG64 y;\n\n                    if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y))\n                    {\n                        PhStartupParameters.Point.x = (LONG)x;\n                        PhStartupParameters.Point.y = (LONG)y;\n                    }\n                }\n            }\n            break;\n        case PH_ARG_SHOWOPTIONS:\n            PhStartupParameters.ShowOptions = TRUE;\n            break;\n        case PH_ARG_PHSVC:\n            PhStartupParameters.PhSvc = TRUE;\n            break;\n        case PH_ARG_NOPLUGINS:\n            PhStartupParameters.NoPlugins = TRUE;\n            break;\n        case PH_ARG_NEWINSTANCE:\n            PhStartupParameters.NewInstance = TRUE;\n            break;\n        case PH_ARG_ELEVATE:\n            PhStartupParameters.Elevate = TRUE;\n            break;\n        case PH_ARG_SILENT:\n            PhStartupParameters.Silent = TRUE;\n            break;\n        case PH_ARG_HELP:\n            PhStartupParameters.Help = TRUE;\n            break;\n        case PH_ARG_SELECTPID:\n            if (Value && PhStringToInteger64(&Value->sr, 0, &integer))\n                PhStartupParameters.SelectPid = (ULONG)integer;\n            break;\n        case PH_ARG_PRIORITY:\n            if (Value && PhEqualString2(Value, L\"r\", TRUE))\n                PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME;\n            else if (Value && PhEqualString2(Value, L\"h\", TRUE))\n                PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;\n            else if (Value && PhEqualString2(Value, L\"n\", TRUE))\n                PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;\n            else if (Value && PhEqualString2(Value, L\"l\", TRUE))\n                PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;\n            break;\n        case PH_ARG_PLUGIN:\n            if (!PhStartupParameters.PluginParameters)\n                PhStartupParameters.PluginParameters = PhCreateList(3);\n            if (Value)\n                PhAddItemList(PhStartupParameters.PluginParameters, PhReferenceObject(Value));\n            break;\n        case PH_ARG_SELECTTAB:\n            PhSwapReference(&PhStartupParameters.SelectTab, Value);\n            break;\n        case PH_ARG_SYSINFO:\n            PhSwapReference(&PhStartupParameters.SysInfo, Value ? Value : PhReferenceEmptyString());\n            break;\n        case PH_ARG_KPHSTARTUPHIGH:\n            PhStartupParameters.KphStartupHigh = TRUE;\n            break;\n        case PH_ARG_KPHSTARTUPMAX:\n            PhStartupParameters.KphStartupMax = TRUE;\n            break;\n        case PH_ARG_CHANNEL:\n            {\n                if (Value && PhEqualString2(Value, L\"release\", FALSE))\n                    PhStartupParameters.UpdateChannel = PhReleaseChannel;\n                else if (Value && PhEqualString2(Value, L\"preview\", FALSE))\n                    PhStartupParameters.UpdateChannel = PhPreviewChannel;\n                else if (Value && PhEqualString2(Value, L\"canary\", FALSE))\n                    PhStartupParameters.UpdateChannel = PhCanaryChannel;\n                else if (Value && PhEqualString2(Value, L\"developer\", FALSE))\n                    PhStartupParameters.UpdateChannel = PhDeveloperChannel;\n            }\n            break;\n        }\n    }\n    else\n    {\n        PPH_STRING upperValue = NULL;\n\n        if (Value)\n            upperValue = PhUpperString(Value);\n\n        if (upperValue)\n        {\n            if (PhFindStringInString(upperValue, 0, L\"TASKMGR.EXE\") != SIZE_MAX)\n            {\n                // User probably has System Informer replacing Task Manager. Force\n                // the main window to start visible.\n                PhStartupParameters.ShowVisible = TRUE;\n            }\n\n            PhDereferenceObject(upperValue);\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Parses and processes the application's startup parameters from the command line.\n *\n * This function defines and processes all supported command line options for System Informer.\n * It updates the global PhStartupParameters structure based on the parsed arguments, enabling\n * or disabling features, setting file paths, and configuring application behavior.\n */\nVOID PhpProcessStartupParameters(\n    VOID\n    )\n{\n    CONST PH_COMMAND_LINE_OPTION options[] =\n    {\n        { PH_ARG_SETTINGS, L\"settings\", MandatoryArgumentType },\n        { PH_ARG_NOSETTINGS, L\"nosettings\", NoArgumentType },\n        { PH_ARG_SHOWVISIBLE, L\"v\", NoArgumentType },\n        { PH_ARG_SHOWHIDDEN, L\"hide\", NoArgumentType },\n        { PH_ARG_RUNASSERVICEMODE, L\"ras\", MandatoryArgumentType },\n        { PH_ARG_NOKPH, L\"nokph\", NoArgumentType },\n        { PH_ARG_DEBUG, L\"debug\", NoArgumentType },\n        { PH_ARG_HWND, L\"hwnd\", MandatoryArgumentType },\n        { PH_ARG_POINT, L\"point\", MandatoryArgumentType },\n        { PH_ARG_SHOWOPTIONS, L\"showoptions\", NoArgumentType },\n        { PH_ARG_PHSVC, L\"phsvc\", NoArgumentType },\n        { PH_ARG_NOPLUGINS, L\"noplugins\", NoArgumentType },\n        { PH_ARG_NEWINSTANCE, L\"newinstance\", NoArgumentType },\n        { PH_ARG_ELEVATE, L\"elevate\", NoArgumentType },\n        { PH_ARG_SILENT, L\"s\", NoArgumentType },\n        { PH_ARG_HELP, L\"help\", NoArgumentType },\n        { PH_ARG_SELECTPID, L\"selectpid\", MandatoryArgumentType },\n        { PH_ARG_PRIORITY, L\"priority\", MandatoryArgumentType },\n        { PH_ARG_PLUGIN, L\"plugin\", MandatoryArgumentType },\n        { PH_ARG_SELECTTAB, L\"selecttab\", MandatoryArgumentType },\n        { PH_ARG_SYSINFO, L\"sysinfo\", OptionalArgumentType },\n        { PH_ARG_KPHSTARTUPHIGH, L\"kh\", NoArgumentType },\n        { PH_ARG_KPHSTARTUPMAX, L\"kx\", NoArgumentType },\n        { PH_ARG_CHANNEL, L\"channel\", MandatoryArgumentType },\n    };\n    PH_STRINGREF commandLine;\n\n    PhGetProcessCommandLineStringRef(&commandLine);\n\n    if (!PhParseCommandLine(\n        &commandLine,\n        options,\n        RTL_NUMBER_OF(options),\n        PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS | PH_COMMAND_LINE_IGNORE_FIRST_PART,\n        PhpCommandLineOptionCallback,\n        NULL\n        ) || PhStartupParameters.Help)\n    {\n        PhShowInformation2(\n            NULL,\n            L\"Command line options:\",\n            L\"%s\",\n            L\"-debug\\n\"\n            L\"-elevate\\n\"\n            L\"-help\\n\"\n            L\"-hide\\n\"\n            L\"-newinstance\\n\"\n            L\"-nokph\\n\"\n            L\"-noplugins\\n\"\n            L\"-nosettings\\n\"\n            L\"-plugin pluginname:value\\n\"\n            L\"-priority r|h|n|l\\n\"\n            L\"-s\\n\"\n            L\"-selectpid pid-to-select\\n\"\n            L\"-selecttab name-of-tab-to-select\\n\"\n            L\"-settings filename\\n\"\n            L\"-sysinfo [section-name]\\n\"\n            L\"-channel [channel-name]\\n\"\n            L\"-v\"\n            );\n\n        PhExitApplication(STATUS_SUCCESS);\n    }\n\n    if (PhStartupParameters.Elevate && !PhGetOwnTokenAttributes().Elevated)\n    {\n        PhShellProcessHacker(\n            NULL,\n            NULL,\n            SW_SHOW,\n            PH_SHELL_EXECUTE_ADMIN,\n            PH_SHELL_APP_PROPAGATE_PARAMETERS,\n            0,\n            NULL\n            );\n        PhExitApplication(STATUS_SUCCESS);\n    }\n}\n\n/**\n * Enables a set of privileges for the current process token.\n *\n * \\remarks This function is called during application startup to ensure\n * the process has the necessary rights for system-level operations.\n * If the process lacks sufficient rights to adjust privileges, the function\n * will silently fail and continue.\n */\nVOID PhpEnablePrivileges(\n    VOID\n    )\n{\n    HANDLE tokenHandle;\n\n    if (NT_SUCCESS(PhOpenProcessToken(\n        NtCurrentProcess(),\n        TOKEN_ADJUST_PRIVILEGES,\n        &tokenHandle\n        )))\n    {\n        const LUID_AND_ATTRIBUTES privileges[] =\n        {\n            { RtlConvertUlongToLuid(SE_DEBUG_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_INC_BASE_PRIORITY_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_INC_WORKING_SET_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_LOAD_DRIVER_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_PROF_SINGLE_PROCESS_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_BACKUP_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_RESTORE_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_SHUTDOWN_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_TAKE_OWNERSHIP_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_SECURITY_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n        };\n        UCHAR privilegesBuffer[FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(privileges)];\n        PTOKEN_PRIVILEGES tokenPrivileges;\n\n        tokenPrivileges = (PTOKEN_PRIVILEGES)privilegesBuffer;\n        tokenPrivileges->PrivilegeCount = RTL_NUMBER_OF(privileges);\n        memcpy(tokenPrivileges->Privileges, privileges, sizeof(privileges));\n\n        NtAdjustPrivilegesToken(\n            tokenHandle,\n            FALSE,\n            tokenPrivileges,\n            0,\n            NULL,\n            NULL\n            );\n\n        NtClose(tokenHandle);\n    }\n}\n"
  },
  {
    "path": "SystemInformer/mainwnd.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <mainwnd.h>\n\n#include <cpysave.h>\n#include <emenu.h>\n#include <hndlinfo.h>\n#include <kphuser.h>\n#include <lsasup.h>\n#include <svcsup.h>\n#include <workqueue.h>\n#include <phsettings.h>\n\n#include <actions.h>\n#include <colsetmgr.h>\n#include <memsrch.h>\n#include <netlist.h>\n#include <netprv.h>\n#include <notifico.h>\n#include <phconsole.h>\n#include <phplug.h>\n#include <phsvccl.h>\n#include <procprv.h>\n#include <proctree.h>\n#include <secedit.h>\n#include <settings.h>\n#include <srvlist.h>\n#include <srvprv.h>\n\n#include <mainwndp.h>\n\ntypedef struct _PH_MWP_KPH\n{\n    KPH_LEVEL Level;\n    BOOLEAN DynDataActive;\n} PH_MWP_KPH, *PPH_MWP_KPH;\n\nHWND PhMainWndHandle = NULL;\nBOOLEAN PhMainWndExiting = FALSE;\nBOOLEAN PhMainWndEarlyExit = FALSE;\nWNDPROC PhMainWndProc = PhMwpWndProc;\nPH_MWP_KPH PhMainWndKph = { KphLevelNone, FALSE };\n\nPH_PROVIDER_REGISTRATION PhMwpProcessProviderRegistration;\nPH_PROVIDER_REGISTRATION PhMwpServiceProviderRegistration;\nPH_PROVIDER_REGISTRATION PhMwpNetworkProviderRegistration;\nBOOLEAN PhMwpUpdateAutomatically = TRUE;\n\nULONG PhMwpNotifyIconNotifyMask = 0;\nULONG PhMwpLastNotificationType = 0;\nPH_MWP_NOTIFICATION_DETAILS PhMwpLastNotificationDetails;\n\nstatic BOOLEAN AlwaysOnTop = FALSE;\nstatic BOOLEAN NeedsMaximize = FALSE;\nstatic BOOLEAN DelayedLoadCompleted = FALSE;\nstatic PH_CALLBACK_DECLARE(LayoutPaddingCallback);\nstatic RECT LayoutPadding = { 0, 0, 0, 0 };\nstatic BOOLEAN LayoutPaddingValid = TRUE;\nstatic LONG LayoutWindowDpi = 96;\nstatic LONG LayoutBorderSize = 0;\n\nstatic HWND TabControlHandle = NULL;\nstatic PPH_LIST PageList = NULL;\nstatic PPH_MAIN_TAB_PAGE CurrentPage = NULL;\nstatic LONG OldTabIndex = 0;\n\nstatic HMENU SubMenuHandles[5];\nstatic PPH_EMENU SubMenuObjects[5];\nstatic ULONG SelectedUserSessionId = ULONG_MAX;\n\n/**\n * Initializes the main window and data providers.\n *\n * \\param ShowCommand The initial show command (e.g., SW_SHOW, SW_HIDE, SW_MAXIMIZE).\n * \\return TRUE if initialization succeeded, FALSE otherwise.\n * \\remarks Delayed initialization tasks are queued for execution after the window is shown.\n */\nBOOLEAN PhMainWndInitialization(\n    _In_ LONG ShowCommand\n    )\n{\n    RTL_ATOM windowAtom;\n    PH_RECTANGLE windowRectangle;\n    RECT windowRect;\n    LONG windowDpi;\n\n    // Set FirstRun default settings.\n\n    if (PhGetIntegerSetting(SETTING_FIRST_RUN))\n        PhSetIntegerSetting(SETTING_FIRST_RUN, FALSE);\n\n    // Initialize the window class.\n\n    if ((windowAtom = PhMwpInitializeWindowClass()) == INVALID_ATOM)\n        return FALSE;\n\n    // Initialize the window size and position.\n\n    memset(&windowRectangle, 0, sizeof(PH_RECTANGLE));\n    windowRectangle.Position = PhGetIntegerPairSetting(SETTING_MAIN_WINDOW_POSITION);\n    PhRectangleToRect(&windowRect, &windowRectangle);\n    windowDpi = PhGetMonitorDpi(NULL, &windowRect);\n    windowRectangle.Size = PhGetScalableIntegerPairSetting(SETTING_MAIN_WINDOW_SIZE, TRUE, windowDpi)->Pair;\n    PhAdjustRectangleToWorkingArea(NULL, &windowRectangle);\n\n    // Initialize the window.\n\n    PhMainWndHandle = CreateWindow(\n        MAKEINTATOM(windowAtom),\n        NULL,\n        WS_OVERLAPPEDWINDOW | (PhEnableDeferredLayout ? 0 : WS_CLIPCHILDREN),\n        windowRectangle.Left,\n        windowRectangle.Top,\n        windowRectangle.Width,\n        windowRectangle.Height,\n        NULL,\n        NULL,\n        NULL,\n        NULL\n        );\n\n    if (!PhMainWndHandle)\n        return FALSE;\n\n    // Initialize window metrics.\n    PhMwpInitializeMetrics(PhMainWndHandle, 0);\n\n    // Initialize window controls.\n    PhMwpInitializeControls(PhMainWndHandle);\n\n    // Initialize window fonts.\n    PhMwpOnSettingChange(PhMainWndHandle, 0, NULL);\n\n    // Initialize window settings.\n    PhMwpLoadSettings(PhMainWndHandle);\n\n    // Initialize window theme.\n    PhInitializeWindowTheme(PhMainWndHandle, PhEnableThemeSupport);\n\n    // Initialize window menu.\n    PhMwpInitializeMainMenu(PhMainWndHandle);\n\n    // Initialize providers.\n    PhMwpInitializeProviders();\n\n    // Perform window layout.\n    PhMwpSelectionChangedTabControl(INT_ERROR);\n\n    // Perform main window showing.\n    PhMwpShowWindow(ShowCommand);\n\n    // Queue delayed init functions.\n    PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhMwpLoadStage1Worker, PhMainWndHandle);\n\n    return TRUE;\n}\n\n/**\n * Window procedure for the main window.\n *\n * \\param WindowHandle Handle to the window.\n * \\param uMsg Message identifier.\n * \\param wParam First message parameter.\n * \\param lParam Second message parameter.\n * \\return LRESULT Message result.\n */\nLRESULT CALLBACK PhMwpWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (WindowMessage)\n    {\n    case WM_DESTROY:\n        {\n            PhMwpOnDestroy(WindowHandle);\n        }\n        break;\n    case WM_ENDSESSION:\n        {\n            PhMwpOnEndSession(WindowHandle, !!wParam, (ULONG)lParam);\n        }\n        break;\n    case WM_SETTINGCHANGE:\n        {\n            PhMwpOnSettingChange(WindowHandle, (ULONG)wParam, (PWSTR)lParam);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            PhMwpOnCommand(WindowHandle, GET_WM_COMMAND_ID(wParam, lParam));\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PhMwpOnShowWindow(WindowHandle, !!wParam, (ULONG)lParam);\n        }\n        break;\n    case WM_SYSCOMMAND:\n        {\n            if (PhMwpOnSysCommand(WindowHandle, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))\n                return 0;\n        }\n        break;\n    case WM_MENUCOMMAND:\n        {\n            PhMwpOnMenuCommand(WindowHandle, (ULONG)wParam, (HMENU)lParam);\n        }\n        break;\n    case WM_INITMENUPOPUP:\n        {\n            PhMwpOnInitMenuPopup(WindowHandle, (HMENU)wParam, LOWORD(lParam), !!HIWORD(lParam));\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhMwpOnSize(WindowHandle, (UINT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhMwpOnSizing((ULONG)wParam, (PRECT)lParam);\n        }\n        break;\n    case WM_SETFOCUS:\n        {\n            PhMwpOnSetFocus(WindowHandle);\n        }\n        break;\n    case WM_TIMER:\n        {\n            PhMwpOnTimer(WindowHandle, wParam, lParam);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LRESULT result;\n\n            if (PhMwpOnNotify((NMHDR *)lParam, &result))\n                return result;\n        }\n        break;\n    case WM_DEVICECHANGE:\n        {\n            PhMwpOnDeviceChanged(WindowHandle, wParam, lParam);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhMwpOnDpiChanged(WindowHandle, LOWORD(wParam));\n        }\n        break;\n    case WM_NCPAINT:\n    case WM_NCACTIVATE:\n        {\n            if (WindowsVersion >= WINDOWS_10 && !PhEnableThemeSupport)\n            {\n                LRESULT result = DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n                PhWindowThemeMainMenuBorder(WindowHandle);\n                return result;\n            }\n        }\n        break;\n    }\n\n    if (WindowMessage >= WM_PH_FIRST && WindowMessage <= WM_PH_LAST)\n    {\n        return PhMwpOnUserMessage(WindowHandle, WindowMessage, wParam, lParam);\n    }\n\n    return DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n}\n\n/**\n * Registers the main window class for the main window.\n *\n * \\return The atom for the registered window class, or INVALID_ATOM on failure.\n */\nRTL_ATOM PhMwpInitializeWindowClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex;\n    PPH_STRING className;\n\n    memset(&wcex, 0, sizeof(WNDCLASSEX));\n    wcex.cbSize = sizeof(WNDCLASSEX);\n    wcex.lpfnWndProc = PhMainWndProc;\n    wcex.hInstance = NtCurrentImageBase();\n    className = PhaGetStringSetting(SETTING_MAIN_WINDOW_CLASS_NAME);\n    wcex.lpszClassName = PhGetStringOrDefault(className, SETTING_MAIN_WINDOW_CLASS_NAME);\n    wcex.hCursor = PhLoadCursor(NULL, IDC_ARROW);\n\n    if (PhEnableWindowText)\n    {\n        wcex.hIcon = PhGetApplicationIcon(FALSE);\n        wcex.hIconSm = PhGetApplicationIcon(TRUE);\n    }\n\n    return RegisterClassEx(&wcex);\n}\n\n/**\n * Builds the main window title based on application name, user, privilege level, and elevation.\n *\n * \\return A string containing the window title, or NULL if window text is disabled.\n */\nPPH_STRING PhMwpInitializeWindowTitle(\n    VOID\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    PPH_STRING currentUserName;\n\n    if (!PhEnableWindowText)\n    {\n        PhApplicationName = L\" \";\n        return NULL;\n    }\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n    PhAppendStringBuilder2(&stringBuilder, PhApplicationName);\n\n    if (currentUserName = PhGetSidFullName(PhGetOwnTokenAttributes().TokenSid, TRUE, NULL))\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\" [\");\n        PhAppendStringBuilder(&stringBuilder, &currentUserName->sr);\n        PhAppendCharStringBuilder(&stringBuilder, L']');\n        PhDereferenceObject(currentUserName);\n    }\n\n    switch (PhMainWndKph.Level)\n    {\n    case KphLevelMax:\n        PhAppendStringBuilder2(&stringBuilder, L\"++\");\n        break;\n    case KphLevelHigh:\n        PhAppendStringBuilder2(&stringBuilder, L\"+\");\n        break;\n    case KphLevelMed:\n        PhAppendStringBuilder2(&stringBuilder, L\"~\");\n        break;\n    case KphLevelLow:\n        PhAppendStringBuilder2(&stringBuilder, L\"-\");\n        break;\n    case KphLevelMin:\n        PhAppendStringBuilder2(&stringBuilder, L\"--\");\n        break;\n    }\n\n    if (PhMainWndKph.Level && !PhMainWndKph.DynDataActive)\n        PhAppendStringBuilder2(&stringBuilder, L\" (RF)\"); // RF = Reduced Functionality\n\n    if (PhGetOwnTokenAttributes().ElevationType == TokenElevationTypeFull)\n        PhAppendStringBuilder2(&stringBuilder, L\" (Administrator)\");\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n/**\n * Initializes provider threads for processes, services, and network.\n */\nVOID PhMwpInitializeProviders(\n    VOID\n    )\n{\n    if (PhCsUpdateInterval == 0)\n    {\n        PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM);\n    }\n\n    // See PhMwpLoadStage1Worker for more details.\n\n    PhInitializeProviderThread(&PhPrimaryProviderThread, PhCsUpdateInterval);\n    PhInitializeProviderThread(&PhSecondaryProviderThread, PhCsUpdateInterval);\n    PhInitializeProviderThread(&PhTertiaryProviderThread, PhCsUpdateInterval);\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_HIGH_RESOLUTION_PROVIDER_TIMER))\n    {\n        PhSetHighResolutionProvider(&PhPrimaryProviderThread, TRUE);\n        PhSetHighResolutionProvider(&PhSecondaryProviderThread, TRUE);\n        PhSetHighResolutionProvider(&PhTertiaryProviderThread, TRUE);\n    }\n\n    PhRegisterProvider(&PhPrimaryProviderThread, PhProcessProviderUpdate, NULL, &PhMwpProcessProviderRegistration);\n    PhRegisterProvider(&PhSecondaryProviderThread, PhServiceProviderUpdate, NULL, &PhMwpServiceProviderRegistration);\n    PhRegisterProvider(&PhSecondaryProviderThread, PhNetworkProviderUpdate, NULL, &PhMwpNetworkProviderRegistration);\n\n    PhSetEnabledProvider(&PhMwpProcessProviderRegistration, TRUE);\n    PhSetEnabledProvider(&PhMwpServiceProviderRegistration, TRUE);\n\n    PhStartProviderThread(&PhPrimaryProviderThread);\n    PhStartProviderThread(&PhSecondaryProviderThread);\n    PhStartProviderThread(&PhTertiaryProviderThread);\n}\n\n/**\n * Shows the main window, Handles startup parameters, tab selection, system info dialog, and window state.\n *\n * \\param ShowCommand The show command (e.g., SW_SHOW, SW_HIDE, SW_MAXIMIZE).\n */\nVOID PhMwpShowWindow(\n    _In_ LONG ShowCommand\n    )\n{\n    if ((PhStartupParameters.ShowHidden || PhGetIntegerSetting(SETTING_START_HIDDEN)) && PhNfIconsEnabled())\n        ShowCommand = SW_HIDE;\n    if (PhStartupParameters.ShowVisible)\n        ShowCommand = SW_SHOW;\n\n    if (PhGetIntegerSetting(SETTING_MAIN_WINDOW_STATE) == SW_MAXIMIZE)\n    {\n        if (ShowCommand != SW_HIDE)\n        {\n            ShowCommand = SW_MAXIMIZE;\n        }\n        else\n        {\n            // We can't maximize it while having it hidden. Set it as pending.\n            NeedsMaximize = TRUE;\n        }\n    }\n\n    if (PhPluginsEnabled)\n    {\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainWindowShowing), LongToPtr(ShowCommand));\n    }\n\n    if (PhStartupParameters.SelectTab)\n    {\n        PPH_MAIN_TAB_PAGE page;\n\n        if (page = PhMwpFindPage(&PhStartupParameters.SelectTab->sr))\n        {\n            PhMwpSelectPage(page->Index);\n        }\n    }\n    else\n    {\n        if (PhGetIntegerSetting(SETTING_MAIN_WINDOW_TAB_RESTORE_ENABLED))\n        {\n            PhMwpSelectPage(PhGetIntegerSetting(SETTING_MAIN_WINDOW_TAB_RESTORE_INDEX));\n        }\n    }\n\n    if (PhStartupParameters.SysInfo)\n    {\n        PhShowSystemInformationDialog(PhGetString(PhStartupParameters.SysInfo));\n    }\n\n    if (ShowCommand != SW_HIDE)\n    {\n        ShowWindow(PhMainWndHandle, ShowCommand);\n        UpdateWindow(PhMainWndHandle);\n\n        if (!SetForegroundWindow(PhMainWndHandle))\n        {\n            PhBringWindowToTop(PhMainWndHandle);\n        }\n    }\n\n    if (PhGetIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED))\n    {\n        PhPinMiniInformation(MiniInfoManualPinType, 1, 0, PH_MINIINFO_LOAD_POSITION, NULL, NULL);\n    }\n}\n\n/**\n * Applies the update interval to all provider threads.\n *\n * \\param Interval The update interval in milliseconds.\n */\nVOID PhMwpApplyUpdateInterval(\n    _In_ ULONG Interval\n    )\n{\n    PhSetIntervalProviderThread(&PhPrimaryProviderThread, Interval);\n    PhSetIntervalProviderThread(&PhSecondaryProviderThread, Interval);\n    PhSetIntervalProviderThread(&PhTertiaryProviderThread, Interval);\n}\n\n/**\n * Initializes window metrics such as DPI and border size.\n *\n * \\param WindowHandle Handle to the window.\n * \\param WindowDpi The DPI value for the window.\n */\nVOID PhMwpInitializeMetrics(\n    _In_ HWND WindowHandle,\n    _In_ LONG WindowDpi\n    )\n{\n    LayoutWindowDpi = PhGetWindowDpi(WindowHandle);\n    LayoutBorderSize = PhGetSystemMetrics(SM_CXBORDER, LayoutWindowDpi);\n\n    PhProcessImageListInitialization(WindowHandle, LayoutWindowDpi);\n}\n\n/**\n * Initializes controls for the main window, including tab and tree views.\n *\n * \\param WindowHandle Handle to the window.\n */\nVOID PhMwpInitializeControls(\n    _In_ HWND WindowHandle\n    )\n{\n    ULONG thinRows;\n    ULONG treelistBorder;\n    ULONG treelistCustomColors;\n    ULONG treelistCustomHeaderDraw;\n    ULONG treelistCustomDragReorder;\n    PH_TREENEW_CREATEPARAMS treelistCreateParams = { sizeof(PH_TREENEW_CREATEPARAMS) };\n\n    thinRows = PhGetIntegerSetting(SETTING_THIN_ROWS) ? TN_STYLE_THIN_ROWS : 0;\n    treelistBorder = (PhGetIntegerSetting(SETTING_TREE_LIST_BORDER_ENABLE) && !PhEnableThemeSupport) ? WS_BORDER : 0;\n    treelistCustomColors = PhGetIntegerSetting(SETTING_TREE_LIST_CUSTOM_COLORS_ENABLE) ? TN_STYLE_CUSTOM_COLORS : 0;\n    treelistCustomHeaderDraw = PhGetIntegerSetting(SETTING_TREE_LIST_ENABLE_HEADER_TOTALS) ? TN_STYLE_CUSTOM_HEADERDRAW : 0;\n    treelistCustomDragReorder = PhGetIntegerSetting(SETTING_TREE_LIST_ENABLE_DRAG_REORDER) ? TN_STYLE_DRAG_REORDER_ROWS : 0;\n\n    if (treelistCustomColors)\n    {\n        treelistCreateParams.TextColor = PhGetIntegerSetting(SETTING_TREE_LIST_CUSTOM_COLOR_TEXT);\n        treelistCreateParams.FocusColor = PhGetIntegerSetting(SETTING_TREE_LIST_CUSTOM_COLOR_FOCUS);\n        treelistCreateParams.SelectionColor = PhGetIntegerSetting(SETTING_TREE_LIST_CUSTOM_COLOR_SELECTION);\n    }\n\n    if (PhGetIntegerSetting(SETTING_TREE_LIST_CUSTOM_ROW_SIZE))\n    {\n        treelistCreateParams.RowHeight = PhGetIntegerSetting(SETTING_TREE_LIST_CUSTOM_ROW_SIZE);\n    }\n\n    TabControlHandle = PhCreateWindow(\n        WC_TABCONTROL,\n        NULL,\n        WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | TCS_MULTILINE,\n        0,\n        0,\n        0,\n        0,\n        WindowHandle,\n        NULL,\n        NULL,\n        NULL\n        );\n\n    PhMwpProcessTreeNewHandle = PhCreateWindow(\n        MAKEINTATOM(PhTreeWindowAtom),\n        NULL,\n        WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | TN_STYLE_ANIMATE_DIVIDER |\n        thinRows | treelistBorder | treelistCustomColors | treelistCustomHeaderDraw | treelistCustomDragReorder,\n        0,\n        0,\n        0,\n        0,\n        WindowHandle,\n        NULL,\n        NULL,\n        &treelistCreateParams\n        );\n\n    PhMwpServiceTreeNewHandle = PhCreateWindow(\n        MAKEINTATOM(PhTreeWindowAtom),\n        NULL,\n        WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows | treelistBorder | treelistCustomColors,\n        0,\n        0,\n        0,\n        0,\n        WindowHandle,\n        NULL,\n        NULL,\n        &treelistCreateParams\n        );\n\n    PhMwpNetworkTreeNewHandle = PhCreateWindow(\n        MAKEINTATOM(PhTreeWindowAtom),\n        NULL,\n        WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows | treelistBorder | treelistCustomColors,\n        0,\n        0,\n        0,\n        0,\n        WindowHandle,\n        NULL,\n        NULL,\n        &treelistCreateParams\n        );\n\n    PageList = PhCreateList(10);\n\n    PhMwpCreateInternalPage(L\"Processes\", 0, PhMwpProcessesPageCallback);\n    PhProcessTreeListInitialization();\n    PhInitializeProcessTreeList(PhMwpProcessTreeNewHandle);\n\n    PhMwpCreateInternalPage(L\"Services\", 0, PhMwpServicesPageCallback);\n    PhServiceTreeListInitialization();\n    PhInitializeServiceTreeList(PhMwpServiceTreeNewHandle);\n\n    PhMwpCreateInternalPage(L\"Network\", 0, PhMwpNetworkPageCallback);\n    PhNetworkTreeListInitialization();\n    PhInitializeNetworkTreeList(PhMwpNetworkTreeNewHandle);\n\n    CurrentPage = PageList->Items[0];\n}\n\n/**\n * Worker routine for delayed stage 1 initialization.\n *\n * Performs additional initialization tasks after the main window is shown.\n *\n * \\param Parameter The window handle.\n * \\return NTSTATUS Successful or errant status.\n */\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhMwpLoadStage1Worker(\n    _In_ PVOID Parameter\n    )\n{\n    // Initialize window title (dmex)\n    {\n        PPH_STRING windowTitle;\n\n        PhMainWndKph.Level = KphLevelEx(FALSE);\n        if (!NT_SUCCESS(KphIsDynDataActive(&PhMainWndKph.DynDataActive)))\n            PhMainWndKph.DynDataActive = FALSE;\n\n        if (windowTitle = PhMwpInitializeWindowTitle())\n        {\n            PhSetWindowText((HWND)Parameter, PhGetString(windowTitle));\n            PhDereferenceObject(windowTitle);\n        }\n    }\n\n    // If the update interval is too large, the user might have to wait a while before seeing some types of\n    // process-related data. We force an update by boosting the provider shortly after the program\n    // starts up to make things appear more quickly.\n\n    if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM)\n    {\n        PhBoostProvider(&PhMwpProcessProviderRegistration, NULL);\n        PhBoostProvider(&PhMwpServiceProviderRegistration, NULL);\n    }\n\n    PhNfLoadStage2();\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_LAST_PROCESS_SHUTDOWN))\n    {\n        // Make sure we get closed late in the shutdown process.\n        // This is needed for the shutdown cancel debugging scenario included with Task Manager.\n        // Note: Windows excludes system binaries from the shutdown dialog while not excluding\n        // programs registered for late shutdown, so when services delay shutdown they won't be shown\n        // to the user while we are shown and this has caused some users to blame us instead. (dmex)\n\n        PhSetProcessShutdownParameters(0x1, SHUTDOWN_NORETRY);\n    }\n\n    // Allow WM_PH_ACTIVATE to pass through UIPI. (wj32)\n    if (PhGetOwnTokenAttributes().Elevated)\n    {\n        ChangeWindowMessageFilterEx((HWND)Parameter, WM_PH_ACTIVATE, MSGFLT_ADD, NULL);\n    }\n\n    // N.B. Devices tab is handled by the HardwareDevices plug-in. The provider is managed internally\n    // such that we can handle notifications and dispatch them to other plug-ins. Here we initialize\n    // only the device notifications. (jxy-s).\n    PhMwpInitializeDeviceNotifications();\n\n    DelayedLoadCompleted = TRUE;\n    //PostMessage((HWND)Parameter, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Handles cleanup and shutdown when the main window is destroyed.\n *\n * \\param WindowHandle Handle to the main window being destroyed.\n */\nVOID PhMwpOnDestroy(\n    _In_ HWND WindowHandle\n    )\n{\n    PhMainWndExiting = TRUE;\n\n    // Notify pages and plugins that we are shutting down.\n\n    PhMwpNotifyAllPages(MainTabPageUpdateAutomaticallyChanged, UlongToPtr(FALSE), NULL); // disable providers (dmex)\n    PhMwpNotifyAllPages(MainTabPageDestroy, NULL, NULL);\n\n    if (PhPluginsEnabled)\n        PhUnloadPlugins(FALSE);\n\n    if (!PhMainWndEarlyExit)\n        PhMwpSaveSettings(WindowHandle);\n\n    PhNfUninitialization();\n\n    PostQuitMessage(0);\n}\n\n/**\n * Handles the end session event for the main window.\n *\n * This function is called when the system is ending the current session,\n * such as during shutdown or user logoff. It allows the application to\n * perform any necessary cleanup or state saving before the session ends.\n *\n * \\param WindowHandle Handle to the window receiving the end session event.\n * \\param SessionEnding TRUE if the session is ending, FALSE otherwise.\n * \\param Reason Reason code for the session end (e.g., shutdown, logoff).\n */\nVOID PhMwpOnEndSession(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN SessionEnding,\n    _In_ ULONG Reason\n    )\n{\n    if (!SessionEnding)\n        return;\n\n    PhMainWndExiting = TRUE;\n\n    // Notify pages and plugins that we are shutting down.\n    // This callback must only perform the bare minimum cleanup. (dmex)\n\n    PhMwpNotifyAllPages(MainTabPageUpdateAutomaticallyChanged, UlongToPtr(FALSE), NULL); // disable providers (dmex)\n\n    if (PhPluginsEnabled)\n        PhUnloadPlugins(TRUE);\n\n    PhMwpSaveSettings(WindowHandle);\n\n    PhExitApplication(STATUS_SUCCESS);\n}\n\n/**\n * Handles changes to system or application settings.\n *\n * \\param WindowHandle Handle to the window receiving the setting change notification.\n * \\param Action Optional action code specifying the type of setting change.\n * \\param Metric Optional string specifying the particular metric or setting that changed.\n */\nVOID PhMwpOnSettingChange(\n    _In_ HWND WindowHandle,\n    _In_opt_ ULONG Action,\n    _In_opt_ PCWSTR Metric\n    )\n{\n    {\n        HFONT oldFont = PhApplicationFont;\n        PhApplicationFont = PhInitializeFont(LayoutWindowDpi);\n        if (oldFont) DeleteFont(oldFont);\n    }\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_MONOSPACE_FONT))\n    {\n        HFONT oldFont = PhMonospaceFont;\n        PhMonospaceFont = PhInitializeMonospaceFont(LayoutWindowDpi);\n        if (oldFont) DeleteFont(oldFont);\n    }\n\n    if (Action == 0 && Metric)\n    {\n        // Reload dark theme metrics\n\n        //if (PhEqualStringZ(Metric, L\"ImmersiveColorSet\", TRUE))\n        //{\n        //    NOTHING;\n        //}\n    }\n\n    //if (Action == SPI_SETNONCLIENTMETRICS && Metric && PhEqualStringZ(Metric, L\"WindowMetrics\", TRUE))\n    //{\n    //    // Reload non-client metrics\n    //}\n}\n\n/**\n * Opens a handle to the Service Control Manager (SCM) on the local computer.\n *\n * \\param Handle Pointer to a variable that receives the SCM handle.\n * \\param DesiredAccess Access mask specifying the desired access rights to the SCM.\n * \\param Context Optional context parameter (can be NULL).\n * \\return NTSTATUS Successful or errant status.\n */\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenServiceControlManager(\n    _Inout_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    SC_HANDLE serviceHandle;\n\n    if (serviceHandle = OpenSCManager(NULL, NULL, DesiredAccess))\n    {\n        *Handle = serviceHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Closes a handle to the Service Control Manager.\n *\n * \\param Handle Optional handle to the Service Control Manager to be closed.\n * \\param Release Indicates whether to release associated resources.\n * \\param Context Optional context pointer for additional information.\n * \\return NTSTATUS Successful or errant status.\n */\n_Function_class_(PH_CLOSE_OBJECT)\nstatic NTSTATUS PhpCloseServiceControlManager(\n    _In_opt_ HANDLE Handle,\n    _In_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle)\n        PhCloseServiceHandle(Handle);\n    return STATUS_SUCCESS;\n}\n\n/**\n * Opens a dummy security handle used for permission editing operations.\n *\n * \\param Handle Receives the dummy handle value (implementation-defined).\n * \\param DesiredAccess Requested access mask (unused for dummy handle).\n * \\param Context Optional context pointer (unused).\n * \\return NTSTATUS status code indicating success or failure.\n */\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenSecurityDummyHandle(\n    _Inout_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    return STATUS_SUCCESS;\n}\n\n/**\n * Returns a dummy handle representing COM Access Permissions.\n *\n * This helper is used when displaying or editing COM permissions where a real\n * handle is not required.\n *\\param Handle Receives a value representing access permissions (SD_ACCESSPERMISSIONS).\n *\\param DesiredAccess Requested access mask (unused).\n *\\param Context Optional context pointer (unused).\n *\\return NTSTATUS success code.\n */\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenComDummyAccessPermissionsHandle(\n    _Inout_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    *Handle = (HANDLE)SD_ACCESSPERMISSIONS;\n    return STATUS_SUCCESS;\n}\n\n/**\n * Returns a dummy handle representing COM Access Restrictions.\n *\n * Used when displaying or editing COM access restriction ACLs.\n *\\param Handle Receives a value representing access restrictions (SD_ACCESSRESTRICTIONS).\n *\\param DesiredAccess Requested access mask (unused).\n *\\param Context Optional context pointer (unused).\n *\\return NTSTATUS success code.\n */\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenComDummyAccessRestrictionsHandle(\n    _Inout_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    *Handle = (HANDLE)SD_ACCESSRESTRICTIONS;\n    return STATUS_SUCCESS;\n}\n\n/**\n * Returns a dummy handle representing COM Launch Permissions.\n *\n * This is a convenience helper used when editing COM launch permissions in\n * UI dialogs where a real object handle is not necessary.\n *\\param Handle Receives a value representing launch permissions (SD_LAUNCHPERMISSIONS).\n *\\param DesiredAccess Requested access mask (unused).\n *\\param Context Optional context pointer (unused).\n *\\return NTSTATUS success code.\n */\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenComDummyLaunchPermissionsHandle(\n    _Inout_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    *Handle = (HANDLE)SD_LAUNCHPERMISSIONS;\n    return STATUS_SUCCESS;\n}\n\n/**\n * Returns a dummy handle representing COM Launch Restrictions.\n *\n * Used by the UI when presenting COM launch restriction settings without\n * requiring an actual system handle.\n *\\param Handle Receives a value representing launch restrictions (SD_LAUNCHRESTRICTIONS).\n *\\param DesiredAccess Requested access mask (unused).\n *\\param Context Optional context pointer (unused).\n *\\return NTSTATUS success code.\n */\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenComDummyLaunchRestrictionsHandle(\n    _Inout_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    *Handle = (HANDLE)SD_LAUNCHRESTRICTIONS;\n    return STATUS_SUCCESS;\n}\n\n/**\n * Opens the current window desktop (\"Default\") and returns a handle.\n *\n * \\param Handle Receives the desktop handle on success.\n * \\param DesiredAccess Requested access mask for the desktop.\n * \\param Context Optional context pointer (unused).\n * \\return NTSTATUS success or error code.\n */\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenSecurityDesktopHandle(\n    _Inout_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    HDESK desktopHandle;\n\n    if (desktopHandle = OpenDesktop(\n        L\"Default\",\n        0,\n        FALSE,\n        MAXIMUM_ALLOWED\n        ))\n    {\n        *Handle = desktopHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n/**\n * Closes a desktop handle previously opened by PhpOpenSecurityDesktopHandle.\n *\n * \\param Handle The desktop handle to close (may be NULL).\n * \\param Release Reserved; indicates whether associated resources should be released.\n * \\param Context Optional context pointer (unused).\n * \\return NTSTATUS success code.\n */\n_Function_class_(PH_CLOSE_OBJECT)\nstatic NTSTATUS PhpCloseSecurityDesktopHandle(\n    _In_opt_ HANDLE Handle,\n    _In_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle)\n        CloseDesktop(Handle);\n    return STATUS_SUCCESS;\n}\n\n/**\n * Opens the interactive window station and returns a handle.\n *\n * \\param Handle Receives the window station handle on success.\n * \\param DesiredAccess Requested access mask for the window station.\n * \\param Context Optional context pointer (unused).\n * \\return NTSTATUS success or error code.\n */\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenSecurityStationHandle(\n    _Inout_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    HWINSTA stationHandle;\n\n    if (stationHandle = OpenWindowStation(\n        L\"WinSta0\",\n        FALSE,\n        MAXIMUM_ALLOWED\n        ))\n    {\n        *Handle = stationHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n/**\n * Closes a window station handle previously opened by PhpOpenSecurityStationHandle.\n *\n * \\param Handle The window station handle to close (may be NULL).\n * \\param Release Reserved; indicates whether associated resources should be released.\n * \\param Context Optional context pointer (unused).\n * \\return NTSTATUS success code.\n */\n_Function_class_(PH_CLOSE_OBJECT)\nstatic NTSTATUS PhpCloseSecurityStationHandle(\n    _In_opt_ HANDLE Handle,\n    _In_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle)\n        CloseWindowStation(Handle);\n    return STATUS_SUCCESS;\n}\n\n/**\n * Handles the dump command for a process in the main window.\n *\n * \\param WindowHandle Handle to the window receiving the command.\n * \\param Id Identifier of the command.\n * \\param ProcessItem Pointer to the process item to be dumped.\n */\nstatic VOID PhpMwpOnDumpCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    if (ProcessItem->ProcessId == SYSTEM_PROCESS_ID)\n    {\n        PH_LIVE_DUMP_OPTIONS options;\n\n        if (Id == ID_PROCESS_DUMP_CUSTOM)\n        {\n            PhShowLiveDumpDialog(WindowHandle);\n            return;\n        }\n\n        memset(&options, 0, sizeof(PH_LIVE_DUMP_OPTIONS));\n\n        options.UseDumpStorageStack = TRUE;\n        options.CompressMemoryPages = TRUE;\n\n        switch (Id)\n        {\n        case ID_PROCESS_DUMP_MINIMAL:\n            options.OnlyKernelThreadStacks = TRUE;\n            break;\n        default: case ID_PROCESS_DUMP_NORMAL:\n            break;\n        case ID_PROCESS_DUMP_FULL:\n            options.IncludeHypervisorPages = TRUE;\n            options.IncludeNonEssentialHypervisorPages = TRUE;\n            break;\n        }\n\n        PhUiCreateLiveDump(WindowHandle, &options);\n    }\n    else\n    {\n        ULONG dumpType;\n\n        if (Id == ID_PROCESS_DUMP_CUSTOM)\n        {\n            PhShowCreateDumpFileProcessDialog(WindowHandle, ProcessItem);\n            return;\n        }\n\n        switch (Id)\n        {\n        case ID_PROCESS_DUMP_MINIMAL:\n            dumpType =\n                MiniDumpWithDataSegs |\n                MiniDumpWithUnloadedModules |\n                MiniDumpWithThreadInfo |\n                MiniDumpIgnoreInaccessibleMemory;\n            break;\n        case ID_PROCESS_DUMP_LIMITED:\n            dumpType =\n                MiniDumpWithFullMemory |\n                MiniDumpWithUnloadedModules |\n                MiniDumpWithFullMemoryInfo |\n                MiniDumpWithThreadInfo |\n                MiniDumpIgnoreInaccessibleMemory;\n        default: case ID_PROCESS_DUMP_NORMAL:\n            // task manager uses these flags (wj32)\n            dumpType =\n                MiniDumpWithFullMemory |\n                MiniDumpWithHandleData |\n                MiniDumpWithUnloadedModules |\n                MiniDumpWithFullMemoryInfo |\n                MiniDumpWithThreadInfo |\n                MiniDumpIgnoreInaccessibleMemory |\n                MiniDumpWithIptTrace;\n            break;\n        case ID_PROCESS_DUMP_FULL:\n            dumpType =\n                MiniDumpWithDataSegs |\n                MiniDumpWithFullMemory |\n                MiniDumpWithHandleData |\n                MiniDumpWithUnloadedModules |\n                MiniDumpWithIndirectlyReferencedMemory |\n                MiniDumpWithProcessThreadData |\n                MiniDumpWithPrivateReadWriteMemory |\n                MiniDumpWithFullMemoryInfo |\n                MiniDumpWithCodeSegs |\n                MiniDumpWithFullAuxiliaryState |\n                MiniDumpWithPrivateWriteCopyMemory |\n                MiniDumpIgnoreInaccessibleMemory |\n                MiniDumpWithTokenInformation |\n                MiniDumpWithModuleHeaders |\n                MiniDumpWithAvxXStateContext |\n                MiniDumpWithIptTrace;\n            break;\n        }\n\n        PhUiCreateDumpFileProcess(WindowHandle, ProcessItem, dumpType);\n    }\n}\n\n/**\n * Handles command messages for the main window.\n *\n * \\param WindowHandle Handle to the main window receiving the command.\n * \\param Id Identifier of the command to process.\n */\nVOID PhMwpOnCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id\n    )\n{\n    switch (Id)\n    {\n    case ID_ESC_EXIT:\n        {\n            if (PhGetIntegerSetting(SETTING_HIDE_ON_CLOSE))\n            {\n                if (PhNfIconsEnabled())\n                    ShowWindow(WindowHandle, SW_HIDE);\n            }\n            else if (PhGetIntegerSetting(SETTING_CLOSE_ON_ESCAPE))\n            {\n                SystemInformer_Destroy();\n            }\n        }\n        break;\n    case ID_HACKER_RUN:\n        {\n            PhShowRunFileDialog(WindowHandle);\n        }\n        break;\n    case ID_HACKER_RUNAS:\n        {\n            PhShowRunAsDialog(WindowHandle, NULL);\n        }\n        break;\n    case ID_HACKER_RUNASPACKAGE:\n        {\n            PhShowRunAsPackageDialog(WindowHandle);\n        }\n        break;\n    case ID_HACKER_SHOWDETAILSFORALLPROCESSES:\n        {\n            SystemInformer_PrepareForEarlyShutdown();\n\n            if (NT_SUCCESS(PhShellProcessHacker(\n                WindowHandle,\n                L\"-v -newinstance\",\n                SW_SHOW,\n                PH_SHELL_EXECUTE_ADMIN,\n                PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY,\n                0,\n                NULL\n                )))\n            {\n                SystemInformer_Destroy();\n            }\n            else\n            {\n                SystemInformer_CancelEarlyShutdown();\n            }\n        }\n        break;\n    case ID_HACKER_SAVE:\n        {\n            static PH_FILETYPE_FILTER filters[] =\n            {\n                { L\"Text files (*.txt;*.log)\", L\"*.txt;*.log\" },\n                { L\"Comma-separated values (*.csv)\", L\"*.csv\" },\n                { L\"All files (*.*)\", L\"*.*\" }\n            };\n            PVOID fileDialog = PhCreateSaveFileDialog();\n            PH_FORMAT format[3];\n\n            PhInitFormatS(&format[0], L\"System Informer \");\n            PhInitFormatSR(&format[1], CurrentPage->Name);\n            PhInitFormatS(&format[2], L\".txt\");\n\n            PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n            PhSetFileDialogFileName(fileDialog, PH_AUTO_T(PH_STRING, PhFormat(format, 3, 60))->Buffer);\n\n            if (PhShowFileDialog(WindowHandle, fileDialog))\n            {\n                NTSTATUS status;\n                PPH_STRING fileName;\n                ULONG filterIndex;\n                PPH_FILE_STREAM fileStream;\n\n                fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n                filterIndex = PhGetFileDialogFilterIndex(fileDialog);\n\n                if (NT_SUCCESS(status = PhCreateFileStream(\n                    &fileStream,\n                    fileName->Buffer,\n                    FILE_GENERIC_WRITE,\n                    FILE_SHARE_READ,\n                    FILE_OVERWRITE_IF,\n                    0\n                    )))\n                {\n                    ULONG mode;\n                    PH_MAIN_TAB_PAGE_EXPORT_CONTENT exportContent;\n\n                    if (filterIndex == 2)\n                        mode = PH_EXPORT_MODE_CSV;\n                    else\n                        mode = PH_EXPORT_MODE_TABS;\n\n                    PhWriteStringAsUtf8FileStream(fileStream, (PPH_STRINGREF)&PhUnicodeByteOrderMark);\n\n                    if (mode != PH_EXPORT_MODE_CSV)\n                    {\n                        PhWritePhTextHeader(fileStream);\n                    }\n\n                    exportContent.FileStream = fileStream;\n                    exportContent.Mode = mode;\n                    CurrentPage->Callback(CurrentPage, MainTabPageExportContent, &exportContent, NULL);\n\n                    PhDereferenceObject(fileStream);\n                }\n\n                if (!NT_SUCCESS(status))\n                    PhShowStatus(WindowHandle, L\"Unable to create the file\", status, 0);\n            }\n\n            PhFreeFileDialog(fileDialog);\n        }\n        break;\n    case ID_HACKER_FINDHANDLESORDLLS:\n        {\n            PhShowFindObjectsDialog(WindowHandle);\n        }\n        break;\n    case ID_HACKER_OPTIONS:\n        {\n            PhShowOptionsDialog(WindowHandle);\n        }\n        break;\n    case ID_COMPUTER_LOCK:\n    case ID_COMPUTER_LOGOFF:\n    case ID_COMPUTER_SLEEP:\n    case ID_COMPUTER_HIBERNATE:\n    case ID_COMPUTER_RESTART:\n    case ID_COMPUTER_RESTARTADVOPTIONS:\n    case ID_COMPUTER_RESTARTBOOTOPTIONS:\n    case ID_COMPUTER_RESTARTFWOPTIONS:\n    case ID_COMPUTER_SHUTDOWN:\n    case ID_COMPUTER_SHUTDOWNHYBRID:\n    case ID_COMPUTER_RESTART_NATIVE:\n    case ID_COMPUTER_SHUTDOWN_NATIVE:\n    case ID_COMPUTER_RESTART_CRITICAL:\n    case ID_COMPUTER_SHUTDOWN_CRITICAL:\n    case ID_COMPUTER_RESTART_UPDATE:\n    case ID_COMPUTER_SHUTDOWN_UPDATE:\n    case ID_COMPUTER_RESTARTWDOSCAN:\n        PhMwpExecuteComputerCommand(WindowHandle, Id);\n        break;\n    case ID_HACKER_EXIT:\n        SystemInformer_Destroy();\n        break;\n    case ID_VIEW_SYSTEMINFORMATION:\n        PhShowSystemInformationDialog(NULL);\n        break;\n    case ID_NOTIFICATIONS_ENABLEALL:\n    case ID_NOTIFICATIONS_DISABLEALL:\n    case ID_NOTIFICATIONS_NEWPROCESSES:\n    case ID_NOTIFICATIONS_TERMINATEDPROCESSES:\n    case ID_NOTIFICATIONS_NEWSERVICES:\n    case ID_NOTIFICATIONS_STARTEDSERVICES:\n    case ID_NOTIFICATIONS_STOPPEDSERVICES:\n    case ID_NOTIFICATIONS_DELETEDSERVICES:\n    case ID_NOTIFICATIONS_MODIFIEDSERVICES:\n    case ID_NOTIFICATIONS_ARRIVEDDEVICES:\n    case ID_NOTIFICATIONS_REMOVEDDEVICES:\n        {\n            PhMwpExecuteNotificationMenuCommand(WindowHandle, Id);\n        }\n        break;\n    case ID_NOTIFICATIONS_RESETPERSISTLAYOUT:\n    case ID_NOTIFICATIONS_ENABLEDELAYSTART:\n    case ID_NOTIFICATIONS_ENABLEPERSISTLAYOUT:\n    case ID_NOTIFICATIONS_ENABLETRANSPARENTICONS:\n    case ID_NOTIFICATIONS_ENABLESINGLECLICKICONS:\n        {\n            PhMwpExecuteNotificationSettingsMenuCommand(WindowHandle, Id);\n        }\n        break;\n    case ID_VIEW_COLLAPSEALL:\n        {\n            PhExpandAllProcessNodes(FALSE);\n        }\n        break;\n    case ID_VIEW_EXPANDALL:\n        {\n            PhExpandAllProcessNodes(TRUE);\n        }\n        break;\n    case ID_VIEW_HIDEPROCESSESFROMOTHERUSERS:\n        {\n            PhMwpToggleCurrentUserProcessTreeFilter();\n        }\n        break;\n    case ID_VIEW_HIDESIGNEDPROCESSES:\n        {\n            PhMwpToggleSignedProcessTreeFilter(WindowHandle);\n        }\n        break;\n    case ID_VIEW_HIDEMICROSOFTPROCESSES:\n        {\n            PhMwpToggleMicrosoftProcessTreeFilter();\n        }\n        break;\n    case ID_VIEW_SCROLLTONEWPROCESSES:\n        {\n            PH_SET_INTEGER_CACHED_SETTING(ScrollToNewProcesses, !PhCsScrollToNewProcesses);\n        }\n        break;\n    case ID_VIEW_SORTCHILDPROCESSES:\n        {\n            PH_SET_INTEGER_CACHED_SETTING(SortChildProcesses, !PhCsSortChildProcesses);\n        }\n        break;\n    case ID_VIEW_SORTROOTPROCESSES:\n        {\n            PH_SET_INTEGER_CACHED_SETTING(SortRootProcesses, !PhCsSortRootProcesses);\n        }\n        break;\n    case ID_VIEW_SHOWCPUBELOW001:\n        {\n            PH_SET_INTEGER_CACHED_SETTING(ShowCpuBelow001, !PhCsShowCpuBelow001);\n            PhInvalidateAllProcessNodes();\n        }\n        break;\n    case ID_VIEW_HIDEDRIVERSERVICES:\n        {\n            PhMwpToggleDriverServiceTreeFilter();\n        }\n        break;\n    case ID_VIEW_HIDEMICROSOFTSERVICES:\n        {\n            PhMwpToggleMicrosoftServiceTreeFilter();\n        }\n        break;\n    case ID_VIEW_HIDEWAITINGCONNECTIONS:\n        {\n            PhMwpToggleNetworkWaitingConnectionTreeFilter();\n        }\n        break;\n    case ID_VIEW_ALWAYSONTOP:\n        {\n            AlwaysOnTop = !AlwaysOnTop;\n            SetWindowPos(WindowHandle, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\n                0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);\n            PhSetIntegerSetting(SETTING_MAIN_WINDOW_ALWAYS_ON_TOP, AlwaysOnTop);\n\n            PhWindowNotifyTopMostEvent(AlwaysOnTop);\n        }\n        break;\n    case ID_OPACITY_10:\n    case ID_OPACITY_20:\n    case ID_OPACITY_30:\n    case ID_OPACITY_40:\n    case ID_OPACITY_50:\n    case ID_OPACITY_60:\n    case ID_OPACITY_70:\n    case ID_OPACITY_80:\n    case ID_OPACITY_90:\n    case ID_OPACITY_OPAQUE:\n        {\n            ULONG opacity;\n\n            opacity = PH_ID_TO_OPACITY(Id);\n            PhSetIntegerSetting(SETTING_MAIN_WINDOW_OPACITY, opacity);\n            PhSetWindowOpacity(WindowHandle, opacity);\n        }\n        break;\n    case ID_VIEW_REFRESH:\n        {\n            PhBoostProvider(&PhMwpProcessProviderRegistration, NULL);\n            PhBoostProvider(&PhMwpServiceProviderRegistration, NULL);\n\n            // Note: Don't boost the network provider unless it's currently enabled. (dmex)\n            if (PhGetEnabledProvider(&PhMwpNetworkProviderRegistration))\n            {\n                PhBoostProvider(&PhMwpNetworkProviderRegistration, NULL);\n            }\n        }\n        break;\n    case ID_UPDATEINTERVAL_FAST:\n    case ID_UPDATEINTERVAL_NORMAL:\n    case ID_UPDATEINTERVAL_BELOWNORMAL:\n    case ID_UPDATEINTERVAL_SLOW:\n    case ID_UPDATEINTERVAL_VERYSLOW:\n        {\n            ULONG interval;\n\n            switch (Id)\n            {\n            case ID_UPDATEINTERVAL_FAST:\n                interval = 500;\n                break;\n            case ID_UPDATEINTERVAL_NORMAL:\n                interval = 1000;\n                break;\n            case ID_UPDATEINTERVAL_BELOWNORMAL:\n                interval = 2000;\n                break;\n            case ID_UPDATEINTERVAL_SLOW:\n                interval = 5000;\n                break;\n            case ID_UPDATEINTERVAL_VERYSLOW:\n                interval = 10000;\n                break;\n            default:\n                interval = 1000;\n                break;\n            }\n\n            PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval);\n            PhMwpApplyUpdateInterval(interval);\n        }\n        break;\n    case ID_VIEW_UPDATEAUTOMATICALLY:\n        {\n            PhMwpUpdateAutomatically = !PhMwpUpdateAutomatically;\n\n            PhMwpNotifyAllPages(MainTabPageUpdateAutomaticallyChanged, UlongToPtr(PhMwpUpdateAutomatically), NULL);\n\n            if (PhPluginsEnabled)\n            {\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackUpdateAutomatically), UlongToPtr(PhMwpUpdateAutomatically));\n            }\n        }\n        break;\n    case ID_TOOLS_USER_LIST:\n        {\n            PhShowUserListDialog(WindowHandle);\n        }\n        break;\n    case ID_TOOLS_THREADSTACKS:\n        {\n            PhShowThreadStacksDialog(WindowHandle);\n        }\n        break;\n    case ID_TOOLS_CREATESERVICE:\n        {\n            PhShowCreateServiceDialog(WindowHandle);\n        }\n        break;\n    case ID_TOOLS_ZOMBIEPROCESSES:\n        {\n            PhShowZombieProcessesDialog();\n        }\n        break;\n    case ID_TOOLS_INSPECTEXECUTABLEFILE:\n        {\n            static PH_FILETYPE_FILTER filters[] =\n            {\n                { L\"Executable files (*.exe;*.dll;*.com;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.mui;*.mun;*.efi;*.pdb)\", L\"*.exe;*.dll;*.com;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.mui;*.mun;*.efi;*.pdb\" },\n                { L\"All files (*.*)\", L\"*.*\" }\n            };\n            PVOID fileDialog = PhCreateOpenFileDialog();\n\n            PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters));\n            PhSetFileDialogOptions(fileDialog, PH_FILEDIALOG_NOPATHVALIDATE | PH_FILEDIALOG_DONTADDTORECENT);\n\n            if (PhShowFileDialog(WindowHandle, fileDialog))\n            {\n                PhShellExecuteUserString(\n                    WindowHandle,\n                    SETTING_PROGRAM_INSPECT_EXECUTABLES,\n                    PH_AUTO_T(PH_STRING, PhGetFileDialogFileName(fileDialog))->Buffer,\n                    FALSE,\n                    L\"Make sure the PE Viewer executable file is present.\"\n                    );\n            }\n\n            PhFreeFileDialog(fileDialog);\n        }\n        break;\n    case ID_TOOLS_PAGEFILES:\n        {\n            PhShowPagefilesDialog(WindowHandle);\n        }\n        break;\n    case ID_TOOLS_LIVEDUMP:\n        {\n            PhShowLiveDumpDialog(WindowHandle);\n        }\n        break;\n    case ID_TOOLS_STARTTASKMANAGER:\n        {\n            extern BOOLEAN PhpIsDefaultTaskManager(VOID); // options.c (dmex)\n            PPH_STRING taskmgrFileName;\n            PWSTR taskmgrCommandLine;\n\n            taskmgrFileName = PH_AUTO(PhGetSystemDirectoryWin32Z(L\"\\\\taskmgr.exe\"));\n            taskmgrCommandLine = PhGetIntegerSetting(SETTING_TASKMGR_WINDOW_STATE) ? L\" -d\" : NULL;\n\n            if (!PhpIsDefaultTaskManager() && PhGetIntegerSetting(SETTING_ENABLE_SHELL_EXECUTE_SKIP_IFEO_DEBUGGER))\n            {\n                PhShellExecuteEx(\n                    WindowHandle,\n                    PhGetString(taskmgrFileName),\n                    taskmgrCommandLine,\n                    NULL,\n                    SW_SHOW,\n                    0,\n                    0,\n                    NULL\n                    );\n            }\n            else\n            {\n                if (WindowsVersion >= WINDOWS_8 && !PhGetOwnTokenAttributes().Elevated)\n                {\n                    if (PhUiConnectToPhSvc(WindowHandle, FALSE))\n                    {\n                        PhSvcCallCreateProcessIgnoreIfeoDebugger(PhGetString(taskmgrFileName), taskmgrCommandLine);\n                        PhUiDisconnectFromPhSvc();\n                    }\n                }\n                else\n                {\n                    PhCreateProcessIgnoreIfeoDebugger(PhGetString(taskmgrFileName), taskmgrCommandLine);\n                }\n            }\n        }\n        break;\n    case ID_TOOLS_STARTRESOURCEMONITOR:\n        {\n            PPH_STRING perfmonFileName;\n\n            perfmonFileName = PH_AUTO(PhGetSystemDirectoryWin32Z(L\"\\\\perfmon.exe\"));\n\n            if (PhGetIntegerSetting(SETTING_ENABLE_SHELL_EXECUTE_SKIP_IFEO_DEBUGGER))\n            {\n                PhShellExecuteEx(\n                    WindowHandle,\n                    PhGetString(perfmonFileName),\n                    L\" /res\",\n                    NULL,\n                    SW_SHOW,\n                    0,\n                    0,\n                    NULL\n                    );\n            }\n            else\n            {\n                if (!PhGetOwnTokenAttributes().Elevated)\n                {\n                    if (PhUiConnectToPhSvc(WindowHandle, FALSE))\n                    {\n                        PhSvcCallCreateProcessIgnoreIfeoDebugger(PhGetString(perfmonFileName), L\" /res\");\n                        PhUiDisconnectFromPhSvc();\n                    }\n                }\n                else\n                {\n                    PhCreateProcessIgnoreIfeoDebugger(PhGetString(perfmonFileName), L\" /res\");\n                }\n            }\n        }\n        break;\n    case ID_TOOLS_SHUTDOWNWSLPROCESSES:\n        {\n            NTSTATUS status;\n            PPH_STRING perfmonFileName;\n\n            perfmonFileName = PH_AUTO(PhGetSystemDirectoryWin32Z(L\"\\\\wsl.exe\"));\n\n            status = PhShellExecuteEx(\n                WindowHandle,\n                PhGetString(perfmonFileName),\n                L\" --shutdown\",\n                NULL,\n                SW_SHOW,\n                0,\n                0,\n                NULL\n                );\n\n            if (!NT_SUCCESS(status))\n            {\n                PhShowStatus(WindowHandle, L\"Unable to shutdown WSL instances.\", status, 0);\n            }\n        }\n        break;\n    case ID_TOOLS_SCM_PERMISSIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"Service Control Manager\",\n                L\"SCManager\",\n                PhpOpenServiceControlManager,\n                PhpCloseServiceControlManager,\n                NULL\n                );\n        }\n        break;\n    case ID_TOOLS_PWR_PERMISSIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"Current Power Scheme\",\n                L\"PowerDefault\",\n                PhpOpenSecurityDummyHandle,\n                NULL,\n                NULL\n                );\n        }\n        break;\n    case ID_TOOLS_RDP_PERMISSIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"Terminal Server Listener\",\n                L\"RdpDefault\",\n                PhpOpenSecurityDummyHandle,\n                NULL,\n                NULL\n                );\n        }\n        break;\n    case ID_TOOLS_COM_ACCESS_PERMISSIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"COM Access Permissions\",\n                L\"ComAccess\",\n                PhpOpenComDummyAccessPermissionsHandle,\n                NULL,\n                NULL\n                );\n        }\n        break;\n    case ID_TOOLS_COM_ACCESS_RESTRICTIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"COM Access Restrictions\",\n                L\"ComAccess\",\n                PhpOpenComDummyAccessRestrictionsHandle,\n                NULL,\n                NULL\n                );\n        }\n        break;\n    case ID_TOOLS_COM_LAUNCH_PERMISSIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"COM Launch Permissions\",\n                L\"ComLaunch\",\n                PhpOpenComDummyLaunchPermissionsHandle,\n                NULL,\n                NULL\n                );\n        }\n        break;\n    case ID_TOOLS_COM_LAUNCH_RESTRICTIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"COM Launch Restrictions\",\n                L\"ComLaunch\",\n                PhpOpenComDummyLaunchRestrictionsHandle,\n                NULL,\n                NULL\n                );\n        }\n        break;\n    case ID_TOOLS_WMI_PERMISSIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"WMI Root Namespace\",\n                L\"WmiDefault\",\n                PhpOpenSecurityDummyHandle,\n                NULL,\n                NULL\n                );\n        }\n        break;\n    case ID_TOOLS_DESKTOP_PERMISSIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"Current Window Desktop\",\n                L\"Desktop\",\n                PhpOpenSecurityDesktopHandle,\n                PhpCloseSecurityDesktopHandle,\n                NULL\n                );\n        }\n        break;\n    case ID_TOOLS_STATION_PERMISSIONS:\n        {\n            PhEditSecurity(\n                NULL,\n                L\"Current Window Station\",\n                L\"WindowStation\",\n                PhpOpenSecurityStationHandle,\n                PhpCloseSecurityStationHandle,\n                NULL\n                );\n        }\n        break;\n    case ID_USER_CONNECT:\n        {\n            PhUiConnectSession(WindowHandle, SelectedUserSessionId);\n        }\n        break;\n    case ID_USER_DISCONNECT:\n        {\n            PhUiDisconnectSession(WindowHandle, SelectedUserSessionId);\n        }\n        break;\n    case ID_USER_LOGOFF:\n        {\n            PhUiLogoffSession(WindowHandle, SelectedUserSessionId);\n        }\n        break;\n    case ID_USER_REMOTECONTROL:\n        {\n            PhShowSessionShadowDialog(WindowHandle, SelectedUserSessionId);\n        }\n        break;\n    case ID_USER_SENDMESSAGE:\n        {\n            PhShowSessionSendMessageDialog(WindowHandle, SelectedUserSessionId);\n        }\n        break;\n    case ID_USER_PROPERTIES:\n        {\n            PhShowSessionProperties(WindowHandle, SelectedUserSessionId);\n        }\n        break;\n    case ID_HELP_LOG:\n        {\n            PhShowLogDialog();\n        }\n        break;\n    case ID_HELP_DONATE:\n        {\n            //PhShellExecute(WindowHandle, L\"https://sourceforge.net/project/project_donations.php?group_id=242527\", NULL);\n        }\n        break;\n    case ID_HELP_DEBUGCONSOLE:\n        {\n            PhShowDebugConsole();\n        }\n        break;\n    case ID_HELP_ABOUT:\n        {\n            PhShowAboutDialog(WindowHandle);\n        }\n        break;\n    case ID_PROCESS_TERMINATE:\n        {\n            PPH_PROCESS_ITEM *processes;\n            ULONG numberOfProcesses;\n\n            if (PhGetSelectedProcessItems(&processes, &numberOfProcesses))\n            {\n                PhReferenceObjects(processes, numberOfProcesses);\n\n                if (PhUiTerminateProcesses(WindowHandle, processes, numberOfProcesses))\n                    PhDeselectAllProcessNodes();\n\n                PhDereferenceObjects(processes, numberOfProcesses);\n                PhFree(processes);\n            }\n        }\n        break;\n    case ID_PROCESS_TERMINATETREE:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n\n                if (PhUiTerminateTreeProcess(WindowHandle, processItem))\n                    PhDeselectAllProcessNodes();\n\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_SUSPEND:\n        {\n            PPH_PROCESS_ITEM *processes;\n            ULONG numberOfProcesses;\n\n            if (PhGetSelectedProcessItems(&processes, &numberOfProcesses))\n            {\n                PhReferenceObjects(processes, numberOfProcesses);\n                PhUiSuspendProcesses(WindowHandle, processes, numberOfProcesses);\n                PhDereferenceObjects(processes, numberOfProcesses);\n                PhFree(processes);\n            }\n        }\n        break;\n    case ID_PROCESS_SUSPENDTREE:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiSuspendTreeProcess(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_RESUME:\n        {\n            PPH_PROCESS_ITEM *processes;\n            ULONG numberOfProcesses;\n\n            if (PhGetSelectedProcessItems(&processes, &numberOfProcesses))\n            {\n                PhReferenceObjects(processes, numberOfProcesses);\n                PhUiResumeProcesses(WindowHandle, processes, numberOfProcesses);\n                PhDereferenceObjects(processes, numberOfProcesses);\n                PhFree(processes);\n            }\n        }\n        break;\n    case ID_PROCESS_RESUMETREE:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiResumeTreeProcess(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_FREEZE:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiFreezeTreeProcess(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_THAW:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiThawTreeProcess(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_RESTART:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n\n                // Note: The current process is a special case (dmex)\n                if (processItem->ProcessId == NtCurrentProcessId())\n                {\n                    SystemInformer_PrepareForEarlyShutdown();\n\n                    if (NT_SUCCESS(PhShellProcessHacker(\n                        WindowHandle,\n                        NULL,\n                        SW_SHOW,\n                        PH_SHELL_EXECUTE_DEFAULT,\n                        PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY,\n                        0,\n                        NULL\n                        )))\n                    {\n                        SystemInformer_Destroy();\n                    }\n                    else\n                    {\n                        SystemInformer_CancelEarlyShutdown();\n                    }\n                }\n                else\n                {\n                    if (PhUiRestartProcess(WindowHandle, processItem))\n                    {\n                        PhDeselectAllProcessNodes();\n                    }\n                }\n\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_DUMP_MINIMAL:\n    case ID_PROCESS_DUMP_LIMITED:\n    case ID_PROCESS_DUMP_NORMAL:\n    case ID_PROCESS_DUMP_FULL:\n    case ID_PROCESS_DUMP_CUSTOM:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhpMwpOnDumpCommand(WindowHandle, Id, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_DEBUG:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiDebugProcess(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_VIRTUALIZATION:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiSetVirtualizationProcess(\n                    WindowHandle,\n                    processItem,\n                    !PhMwpSelectedProcessVirtualizationEnabled\n                    );\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_AFFINITY:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhShowProcessAffinityDialog(WindowHandle, processItem, NULL);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_ACTIVITY:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiSetActivityModeration(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_SETCRITICAL:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiSetCriticalProcess(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_DETACHFROMDEBUGGER:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiDetachFromDebuggerProcess(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_GDIHANDLES:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhShowGdiHandlesDialog(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_HEAPS:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhShowProcessHeapsDialog(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_LOCKS:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhShowProcessLocksDialog(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_PAGEPRIORITY_VERYLOW:\n    case ID_PAGEPRIORITY_LOW:\n    case ID_PAGEPRIORITY_MEDIUM:\n    case ID_PAGEPRIORITY_BELOWNORMAL:\n    case ID_PAGEPRIORITY_NORMAL:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                ULONG pagePriority;\n\n                switch (Id)\n                {\n                    case ID_PAGEPRIORITY_VERYLOW:\n                        pagePriority = MEMORY_PRIORITY_VERY_LOW;\n                        break;\n                    case ID_PAGEPRIORITY_LOW:\n                        pagePriority = MEMORY_PRIORITY_LOW;\n                        break;\n                    case ID_PAGEPRIORITY_MEDIUM:\n                        pagePriority = MEMORY_PRIORITY_MEDIUM;\n                        break;\n                    case ID_PAGEPRIORITY_BELOWNORMAL:\n                        pagePriority = MEMORY_PRIORITY_BELOW_NORMAL;\n                        break;\n                    case ID_PAGEPRIORITY_NORMAL:\n                        pagePriority = MEMORY_PRIORITY_NORMAL;\n                        break;\n                }\n\n                PhReferenceObject(processItem);\n                PhUiSetPagePriorityProcess(WindowHandle, processItem, pagePriority);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_REDUCEWORKINGSET:\n        {\n            PPH_PROCESS_ITEM *processes;\n            ULONG numberOfProcesses;\n\n            if (PhGetSelectedProcessItems(&processes, &numberOfProcesses))\n            {\n                PhReferenceObjects(processes, numberOfProcesses);\n                PhUiReduceWorkingSetProcesses(WindowHandle, processes, numberOfProcesses);\n                PhDereferenceObjects(processes, numberOfProcesses);\n                PhFree(processes);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_RUNAS:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                //PPH_STRING fileNameWin32;\n                //\n                //fileNameWin32 = PhGetFileName(processItem->FileName);\n                //\n                //if (!PhIsNullOrEmptyString(fileNameWin32))\n                //{\n                //    PhSetStringSetting2(SETTING_RUN_AS_PROGRAM, &fileNameWin32->sr);\n                //    PhDereferenceObject(fileNameWin32);\n                //\n                //    PhShowRunAsDialog(WindowHandle, NULL);\n                //}\n                //else\n                //{\n                //    PhShowStatus(WindowHandle, L\"Unable to locate the file.\", STATUS_NOT_FOUND, 0);\n                //}\n\n                PhShowRunAsDialog(WindowHandle, NULL);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_RUNASTHISUSER:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhShowRunAsDialog(WindowHandle, processItem->ProcessId);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_PAGESMODIFIED:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhShowImagePageModifiedDialog(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_FLUSHHEAPS:\n        {\n            PPH_PROCESS_ITEM* processes;\n            ULONG numberOfProcesses;\n\n            if (PhGetSelectedProcessItems(&processes, &numberOfProcesses))\n            {\n                PhReferenceObjects(processes, numberOfProcesses);\n                PhUiFlushHeapProcesses(WindowHandle, processes, numberOfProcesses);\n                PhDereferenceObjects(processes, numberOfProcesses);\n                PhFree(processes);\n            }\n        }\n        break;\n    case ID_PRIORITY_REALTIME:\n    case ID_PRIORITY_HIGH:\n    case ID_PRIORITY_ABOVENORMAL:\n    case ID_PRIORITY_NORMAL:\n    case ID_PRIORITY_BELOWNORMAL:\n    case ID_PRIORITY_IDLE:\n        {\n            PPH_PROCESS_ITEM *processes;\n            ULONG numberOfProcesses;\n\n            if (PhGetSelectedProcessItems(&processes, &numberOfProcesses))\n            {\n                PhReferenceObjects(processes, numberOfProcesses);\n                PhMwpExecuteProcessPriorityClassCommand(WindowHandle, Id, processes, numberOfProcesses);\n                PhDereferenceObjects(processes, numberOfProcesses);\n                PhFree(processes);\n            }\n        }\n        break;\n    case ID_IOPRIORITY_VERYLOW:\n    case ID_IOPRIORITY_LOW:\n    case ID_IOPRIORITY_NORMAL:\n    case ID_IOPRIORITY_HIGH:\n        {\n            PPH_PROCESS_ITEM *processes;\n            ULONG numberOfProcesses;\n\n            if (PhGetSelectedProcessItems(&processes, &numberOfProcesses))\n            {\n                PhReferenceObjects(processes, numberOfProcesses);\n                PhMwpExecuteProcessIoPriorityCommand(WindowHandle, Id, processes, numberOfProcesses);\n                PhDereferenceObjects(processes, numberOfProcesses);\n                PhFree(processes);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_ECOMODE:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiSetEcoModeProcess(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_MISCELLANEOUS_EXECUTIONREQUIRED:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhReferenceObject(processItem);\n                PhUiSetExecutionRequiredProcess(WindowHandle, processItem);\n                PhDereferenceObject(processItem);\n            }\n        }\n        break;\n    case ID_WINDOW_BRINGTOFRONT:\n        {\n            if (IsWindow(PhMwpSelectedProcessWindowHandle))\n            {\n                WINDOWPLACEMENT placement = { sizeof(placement) };\n\n                GetWindowPlacement(PhMwpSelectedProcessWindowHandle, &placement);\n\n                if (placement.showCmd == SW_MINIMIZE)\n                    ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_RESTORE);\n                else\n                    ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_SHOW);\n\n                SetForegroundWindow(PhMwpSelectedProcessWindowHandle);\n            }\n        }\n        break;\n    case ID_WINDOW_RESTORE:\n        {\n            if (IsWindow(PhMwpSelectedProcessWindowHandle))\n            {\n                ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_RESTORE);\n            }\n        }\n        break;\n    case ID_WINDOW_MINIMIZE:\n        {\n            if (IsWindow(PhMwpSelectedProcessWindowHandle))\n            {\n                ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_MINIMIZE);\n            }\n        }\n        break;\n    case ID_WINDOW_MAXIMIZE:\n        {\n            if (IsWindow(PhMwpSelectedProcessWindowHandle))\n            {\n                ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_MAXIMIZE);\n            }\n        }\n        break;\n    case ID_WINDOW_CLOSE:\n        {\n            if (IsWindow(PhMwpSelectedProcessWindowHandle))\n            {\n                NTSTATUS status;\n\n                status = PhTerminateWindow(PhMwpSelectedProcessWindowHandle, TRUE);\n                //PostMessage(PhMwpSelectedProcessWindowHandle, WM_CLOSE, 0, 0);\n\n                if (!NT_SUCCESS(status))\n                {\n                    PhShowStatus(WindowHandle, L\"Unable to close the window.\", status, 0);\n                }\n            }\n        }\n        break;\n    case ID_PROCESS_OPENFILELOCATION:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                NTSTATUS status;\n                PPH_STRING fileName;\n\n                status = PhGetProcessItemFileNameWin32(processItem, &fileName);\n\n                if (NT_SUCCESS(status))\n                {\n                    PhShellExecuteUserString(\n                        WindowHandle,\n                        SETTING_FILE_BROWSE_EXECUTABLE,\n                        PhGetString(fileName),\n                        FALSE,\n                        L\"Make sure the Explorer executable file is present.\"\n                        );\n\n                    PhDereferenceObject(fileName);\n                }\n                else\n                {\n                    PhShowStatus(WindowHandle, L\"Unable to locate the file.\", status, 0);\n                }\n            }\n        }\n        break;\n    case ID_PROCESS_SEARCHONLINE:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                PhSearchOnlineString(WindowHandle, PhGetString(processItem->ProcessName));\n            }\n        }\n        break;\n    case ID_PROCESS_PROPERTIES:\n        {\n            PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();\n\n            if (processItem)\n            {\n                // No reference needed; no messages pumped.\n                PhMwpShowProcessProperties(processItem);\n            }\n        }\n        break;\n    case ID_PROCESS_COPY:\n        {\n            PhCopyProcessTree();\n        }\n        break;\n    case ID_SERVICE_GOTOPROCESS:\n        {\n            PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem();\n            PPH_PROCESS_NODE processNode;\n\n            if (serviceItem)\n            {\n                if (processNode = PhFindProcessNode(serviceItem->ProcessId))\n                {\n                    PhMwpSelectPage(PhMwpProcessesPage->Index);\n                    SetFocus(PhMwpProcessTreeNewHandle);\n                    PhSelectAndEnsureVisibleProcessNode(processNode);\n                }\n                else\n                {\n                    PhShowStatus(WindowHandle, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n                }\n            }\n        }\n        break;\n    case ID_SERVICE_START:\n        {\n            PPH_SERVICE_ITEM* serviceItems;\n            ULONG numberOfServiceItems;\n\n            PhGetSelectedServiceItems(&serviceItems, &numberOfServiceItems);\n            PhReferenceObjects(serviceItems, numberOfServiceItems);\n            PhUiStartServices(WindowHandle, serviceItems, numberOfServiceItems);\n            PhDereferenceObjects(serviceItems, numberOfServiceItems);\n            PhFree(serviceItems);\n        }\n        break;\n    case ID_SERVICE_CONTINUE:\n        {\n            PPH_SERVICE_ITEM* serviceItems;\n            ULONG numberOfServiceItems;\n\n            PhGetSelectedServiceItems(&serviceItems, &numberOfServiceItems);\n            PhReferenceObjects(serviceItems, numberOfServiceItems);\n            PhUiContinueServices(WindowHandle, serviceItems, numberOfServiceItems);\n            PhDereferenceObjects(serviceItems, numberOfServiceItems);\n            PhFree(serviceItems);\n        }\n        break;\n    case ID_SERVICE_PAUSE:\n        {\n            PPH_SERVICE_ITEM* serviceItems;\n            ULONG numberOfServiceItems;\n\n            PhGetSelectedServiceItems(&serviceItems, &numberOfServiceItems);\n            PhReferenceObjects(serviceItems, numberOfServiceItems);\n            PhUiPauseServices(WindowHandle, serviceItems, numberOfServiceItems);\n            PhDereferenceObjects(serviceItems, numberOfServiceItems);\n            PhFree(serviceItems);\n        }\n        break;\n    case ID_SERVICE_STOP:\n        {\n            PPH_SERVICE_ITEM* serviceItems;\n            ULONG numberOfServiceItems;\n\n            PhGetSelectedServiceItems(&serviceItems, &numberOfServiceItems);\n            PhReferenceObjects(serviceItems, numberOfServiceItems);\n            PhUiStopServices(WindowHandle, serviceItems, numberOfServiceItems);\n            PhDereferenceObjects(serviceItems, numberOfServiceItems);\n            PhFree(serviceItems);\n        }\n        break;\n    case ID_SERVICE_DELETE:\n        {\n            PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem();\n\n            if (serviceItem)\n            {\n                PhReferenceObject(serviceItem);\n\n                if (PhUiDeleteService(WindowHandle, serviceItem))\n                    PhDeselectAllServiceNodes();\n\n                PhDereferenceObject(serviceItem);\n            }\n        }\n        break;\n    case ID_SERVICE_OPENKEY:\n        {\n            PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem();\n\n            if (serviceItem)\n            {\n                HANDLE keyHandle;\n\n                if (NT_SUCCESS(PhOpenServiceKey(\n                    &keyHandle,\n                    KEY_READ,\n                    &serviceItem->Name->sr\n                    )))\n                {\n                    PPH_STRING hklmServiceKeyName;\n\n                    if (NT_SUCCESS(PhQueryObjectName(keyHandle, &hklmServiceKeyName)))\n                    {\n                        PhMoveReference(&hklmServiceKeyName, PhFormatNativeKeyName(hklmServiceKeyName));\n\n                        PhShellOpenKey2(WindowHandle, hklmServiceKeyName);\n\n                        PhDereferenceObject(hklmServiceKeyName);\n                    }\n                    else\n                    {\n                        PhShowStatus(WindowHandle, L\"The service does not exist.\", STATUS_OBJECT_NAME_NOT_FOUND, 0);\n                    }\n\n                    NtClose(keyHandle);\n                }\n                else\n                {\n                    PhShowStatus(WindowHandle, L\"The service does not exist.\", STATUS_OBJECT_NAME_NOT_FOUND, 0);\n                }\n            }\n        }\n        break;\n    case ID_SERVICE_OPENFILELOCATION:\n        {\n            PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem();\n            NTSTATUS status;\n            SC_HANDLE serviceHandle;\n            PPH_STRING fileName;\n\n            if (serviceItem)\n            {\n                status = PhOpenService(&serviceHandle, SERVICE_QUERY_CONFIG, PhGetString(serviceItem->Name));\n\n                if (NT_SUCCESS(status))\n                {\n                    status = PhGetServiceHandleFileName(serviceHandle, &serviceItem->Name->sr, &fileName);\n\n                    if (NT_SUCCESS(status))\n                    {\n                        PhShellExecuteUserString(\n                            WindowHandle,\n                            SETTING_FILE_BROWSE_EXECUTABLE,\n                            fileName->Buffer,\n                            FALSE,\n                            L\"Make sure the Explorer executable file is present.\"\n                            );\n                        PhDereferenceObject(fileName);\n                    }\n                    else\n                    {\n                        PhShowStatus(WindowHandle, L\"Unable to locate the file.\", status, 0);\n                    }\n\n                    PhCloseServiceHandle(serviceHandle);\n                }\n                else\n                {\n                    PhShowStatus(WindowHandle, L\"Unable to locate the file.\", status, 0);\n                }\n            }\n        }\n        break;\n    case ID_SERVICE_PROPERTIES:\n        {\n            PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem();\n\n            if (serviceItem)\n            {\n                // The object relies on the list view reference, which could\n                // disappear if we don't reference the object here.\n                PhReferenceObject(serviceItem);\n                PhShowServiceProperties(WindowHandle, serviceItem);\n                PhDereferenceObject(serviceItem);\n            }\n        }\n        break;\n    case ID_SERVICE_COPY:\n        {\n            PhCopyServiceList();\n        }\n        break;\n    case ID_NETWORK_GOTOPROCESS:\n        {\n            PPH_NETWORK_ITEM networkItem = PhGetSelectedNetworkItem();\n            PPH_PROCESS_NODE processNode;\n\n            if (networkItem)\n            {\n                if (processNode = PhFindProcessNode(networkItem->ProcessId))\n                {\n                    PhMwpSelectPage(PhMwpProcessesPage->Index);\n                    SetFocus(PhMwpProcessTreeNewHandle);\n                    PhSelectAndEnsureVisibleProcessNode(processNode);\n                }\n                else\n                {\n                    PhShowStatus(WindowHandle, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n                }\n            }\n        }\n        break;\n    case ID_NETWORK_GOTOSERVICE:\n        {\n            PPH_NETWORK_ITEM networkItem = PhGetSelectedNetworkItem();\n            PPH_SERVICE_ITEM serviceItem;\n\n            if (networkItem && networkItem->OwnerName)\n            {\n                if (serviceItem = PhReferenceServiceItem(&networkItem->OwnerName->sr))\n                {\n                    PhMwpSelectPage(PhMwpServicesPage->Index);\n                    SetFocus(PhMwpServiceTreeNewHandle);\n                    SystemInformer_SelectServiceItem(serviceItem);\n\n                    PhDereferenceObject(serviceItem);\n                }\n                else\n                {\n                    PhShowStatus(WindowHandle, L\"The service does not exist.\", STATUS_INVALID_CID, 0);\n                }\n            }\n        }\n        break;\n    case ID_NETWORK_CLOSE:\n        {\n            PPH_NETWORK_ITEM *networkItems;\n            ULONG numberOfNetworkItems;\n\n            PhGetSelectedNetworkItems(&networkItems, &numberOfNetworkItems);\n            PhReferenceObjects(networkItems, numberOfNetworkItems);\n\n            if (PhUiCloseConnections(WindowHandle, networkItems, numberOfNetworkItems))\n                PhDeselectAllNetworkNodes();\n\n            PhDereferenceObjects(networkItems, numberOfNetworkItems);\n            PhFree(networkItems);\n        }\n        break;\n    case ID_NETWORK_COPY:\n        {\n            PhCopyNetworkList();\n        }\n        break;\n    case ID_TAB_NEXT:\n        {\n            ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle);\n\n            if (selectedIndex != PageList->Count - 1)\n                selectedIndex++;\n            else\n                selectedIndex = 0;\n\n            PhMwpSelectPage(selectedIndex);\n        }\n        break;\n    case ID_TAB_PREV:\n        {\n            ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle);\n\n            if (selectedIndex != 0)\n                selectedIndex--;\n            else\n                selectedIndex = PageList->Count - 1;\n\n            PhMwpSelectPage(selectedIndex);\n        }\n        break;\n    }\n}\n\n/**\n * Handles the ShowWindow event for the main window.\n *\n * \\param WindowHandle Handle to the window receiving the event.\n * \\param Showing Indicates whether the window is being shown (TRUE) or hidden (FALSE).\n * \\param State Specifies the state of the window (e.g., minimized, maximized, normal).\n */\nVOID PhMwpOnShowWindow(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN Showing,\n    _In_ ULONG State\n    )\n{\n    if (NeedsMaximize)\n    {\n        ShowWindow(WindowHandle, SW_MAXIMIZE);\n        NeedsMaximize = FALSE;\n    }\n}\n\n/**\n * Handles system command messages for the main window.\n *\n * \\param WindowHandle Handle to the window receiving the system command.\n * \\param Type The type of system command (e.g., SC_CLOSE, SC_MINIMIZE).\n * \\param CursorScreenX The X coordinate of the cursor in screen coordinates.\n * \\param CursorScreenY The Y coordinate of the cursor in screen coordinates.\n * \\return TRUE if the system command was handled; otherwise, FALSE.\n */\nBOOLEAN PhMwpOnSysCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Type,\n    _In_ LONG CursorScreenX,\n    _In_ LONG CursorScreenY\n    )\n{\n    switch (Type)\n    {\n    case SC_CLOSE:\n        {\n            if (PhGetIntegerSetting(SETTING_HIDE_ON_CLOSE) && PhNfIconsEnabled())\n            {\n                ShowWindow(WindowHandle, SW_HIDE);\n                return TRUE;\n            }\n        }\n        break;\n    case SC_MINIMIZE:\n        {\n            // Save the current window state because we may not have a chance to later.\n            PhMwpSaveWindowState(WindowHandle);\n\n            if (PhGetIntegerSetting(SETTING_HIDE_ON_MINIMIZE) && PhNfIconsEnabled())\n            {\n                ShowWindow(WindowHandle, SW_HIDE);\n                return TRUE;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n * Handles menu command events for the main window.\n *\n * \\param WindowHandle Handle to the window receiving the menu command.\n * \\param Index The index of the selected menu item.\n * \\param Menu Handle to the menu from which the command originated.\n */\nVOID PhMwpOnMenuCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Index,\n    _In_ HMENU Menu\n    )\n{\n    MENUITEMINFO menuItemInfo;\n\n    memset(&menuItemInfo, 0, sizeof(MENUITEMINFO));\n    menuItemInfo.cbSize = sizeof(MENUITEMINFO);\n    menuItemInfo.fMask = MIIM_ID | MIIM_DATA;\n\n    if (GetMenuItemInfo(Menu, Index, TRUE, &menuItemInfo))\n    {\n        PhMwpDispatchMenuCommand(\n            WindowHandle,\n            menuItemInfo.wID,\n            menuItemInfo.dwItemData\n            );\n    }\n}\n\n/**\n * Handles the initialization of a menu popup.\n *\n * This function is called when a menu popup is about to be displayed. It allows for\n * customization of the menu items based on the current state of the application.\n *\n * \\param WindowHandle Handle to the window associated with the menu.\n * \\param Menu Handle to the menu being initialized.\n * \\param Index The zero-based index of the menu in the menu bar.\n * \\param IsWindowMenu TRUE if the menu is a window menu; otherwise, FALSE.\n */\nVOID PhMwpOnInitMenuPopup(\n    _In_ HWND WindowHandle,\n    _In_ HMENU Menu,\n    _In_ ULONG Index,\n    _In_ BOOLEAN IsWindowMenu\n    )\n{\n    ULONG i;\n    BOOLEAN found;\n    PPH_EMENU menu;\n\n    found = FALSE;\n\n    for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HMENU); i++)\n    {\n        if (Menu == SubMenuHandles[i])\n        {\n            found = TRUE;\n            break;\n        }\n    }\n\n    if (!found)\n        return;\n\n    // Delete all items in this submenu.\n    PhDeleteHMenu(Menu);\n\n    // Delete the previous EMENU for this submenu.\n    if (SubMenuObjects[Index])\n        PhDestroyEMenu(SubMenuObjects[Index]);\n\n    // Make sure the menu style is set correctly.\n    PhSetHMenuStyle(Menu, TRUE);\n\n    menu = PhpCreateMainMenu(Index);\n    PhMwpInitializeSubMenu(WindowHandle, menu, Index);\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_MENU_INFORMATION pluginMenuInfo;\n\n        PhPluginInitializeMenuInfo(&pluginMenuInfo, menu, WindowHandle, PH_PLUGIN_MENU_DISALLOW_HOOKS);\n        pluginMenuInfo.u.MainMenu.SubMenuIndex = Index;\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), &pluginMenuInfo);\n    }\n\n    PhEMenuToHMenu2(Menu, menu, 0, NULL);\n    SubMenuObjects[Index] = menu;\n}\n\n/**\n * Handles the WM_SIZE message for the main window.\n *\n * This function is called when the main window is resized. It processes the new size and state,\n * allowing the application to adjust its layout or controls accordingly.\n *\n * \\param WindowHandle Handle to the window receiving the resize event.\n * \\param State Specifies the type of resizing (e.g., SIZE_MINIMIZED, SIZE_MAXIMIZED, SIZE_RESTORED).\n * \\param Width The new width of the client area, in pixels.\n * \\param Height The new height of the client area, in pixels.\n */\nVOID PhMwpOnSize(\n    _In_ HWND WindowHandle,\n    _In_ UINT State,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    //if (!(Width && Height))\n    //    return;\n\n    if (State != SIZE_MINIMIZED)\n    {\n        HDWP deferHandle;\n\n        deferHandle = BeginDeferWindowPos(2);\n        PhMwpLayout(&deferHandle);\n        EndDeferWindowPos(deferHandle);\n    }\n}\n\n/**\n * Handles the window sizing event.\n *\n * \\param Edge The edge of the window being resized (e.g., left, right, top, bottom).\n * \\param DragRectangle Pointer to a RECT structure that specifies the new size and position.\n */\nVOID PhMwpOnSizing(\n    _In_ ULONG Edge,\n    _In_ PRECT DragRectangle\n    )\n{\n    PhResizingMinimumSize(DragRectangle, Edge, 400, 175);\n}\n\n/**\n * Handles the WM_SETFOCUS message for the main window.\n *\n * \\param WindowHandle Handle to the window that received focus.\n */\nVOID PhMwpOnSetFocus(\n    _In_ HWND WindowHandle\n    )\n{\n    // Update the window focus.\n\n    if (CurrentPage->WindowHandle)\n    {\n        SetFocus(CurrentPage->WindowHandle);\n    }\n\n    // Update the window status.\n\n    {\n        PH_MWP_KPH kph;\n        PPH_STRING windowTitle;\n\n        kph.Level = KphLevelEx(FALSE);\n        if (!NT_SUCCESS(KphIsDynDataActive(&kph.DynDataActive)))\n            kph.DynDataActive = FALSE;\n\n        if (DelayedLoadCompleted &&\n            (PhMainWndKph.Level != kph.Level ||\n             PhMainWndKph.DynDataActive != kph.DynDataActive))\n        {\n            PhMainWndKph = kph;\n\n            if (windowTitle = PhMwpInitializeWindowTitle())\n            {\n                PhSetWindowText(WindowHandle, PhGetString(windowTitle));\n                PhDereferenceObject(windowTitle);\n            }\n        }\n    }\n}\n\n/**\n * Handles timer events for the main window.\n *\n * \\param WindowHandle Handle to the window receiving the timer event.\n * \\param wParam The timer identifier.\n * \\param lParam Additional message information (unused).\n */\nVOID PhMwpOnTimer(\n    _In_ HWND WindowHandle,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    LONG timerId = (LONG)(ULONG_PTR)wParam;\n    TIMERPROC timerProc = (TIMERPROC)lParam;\n}\n\n/**\n * Handles notification messages for the main window.\n *\n * \\param Header Pointer to an NMHDR structure containing notification information.\n * \\param Result Pointer to a variable that receives the result of the notification processing.\n * \\return Returns TRUE if the notification was handled successfully, otherwise FALSE.\n */\n_Success_(return)\nBOOLEAN PhMwpOnNotify(\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    )\n{\n    if (Header->hwndFrom == TabControlHandle)\n    {\n        PhMwpNotifyTabControl(Header);\n    }\n\n    return FALSE;\n}\n\n/**\n * Handles device change notifications for the main window.\n *\n * This function is called when the system detects a change in the device configuration,\n * such as when a device is added or removed. It processes the WM_DEVICECHANGE message\n * and performs any necessary updates or actions in response to the change.\n *\n * \\param WindowHandle Handle to the window receiving the device change notification.\n * \\param wParam Additional message information. Specifies the event that occurred.\n * \\param lParam Additional message information. Pointer to a structure with event-specific data.\n */\nVOID PhMwpOnDeviceChanged(\n    _In_ HWND WindowHandle,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (wParam)\n    {\n    case DBT_DEVICEARRIVAL: // Drive letter added\n    //case DBT_DEVICEREMOVECOMPLETE: // Drive letter removed\n        {\n            PDEV_BROADCAST_HDR deviceBroadcast = (PDEV_BROADCAST_HDR)lParam;\n\n            if (deviceBroadcast->dbch_devicetype == DBT_DEVTYP_VOLUME)\n            {\n                PhUpdateDosDevicePrefixes();\n            }\n        }\n        break;\n    }\n\n    if (PhPluginsEnabled)\n    {\n        MSG message;\n\n        memset(&message, 0, sizeof(MSG));\n        message.hwnd = WindowHandle;\n        message.message = WM_DEVICECHANGE;\n        message.wParam = wParam;\n        message.lParam = lParam;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), &message);\n    }\n}\n\n/**\n * Handles the DPI change event for the specified window.\n *\n * \\param WindowHandle Handle to the window whose DPI has changed.\n * \\param WindowDpi The new DPI value for the window.\n */\nVOID PhMwpOnDpiChanged(\n    _In_ HWND WindowHandle,\n    _In_ LONG WindowDpi\n    )\n{\n    PhGuiSupportUpdateSystemMetrics(WindowHandle, WindowDpi);\n\n    PhMwpInitializeMetrics(WindowHandle, WindowDpi);\n\n    if (PhEnableWindowText)\n        PhSetApplicationWindowIconEx(WindowHandle, LayoutWindowDpi);\n\n    PhMwpOnSettingChange(WindowHandle, 0, NULL);\n\n    PhMwpInvokeUpdateWindowFont(NULL);\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_MONOSPACE_FONT))\n        PhMwpInvokeUpdateWindowFontMonospace(WindowHandle, NULL);\n\n    PhMwpNotifyAllPages(MainTabPageDpiChanged, NULL, NULL);\n\n    if (PhPluginsEnabled)\n    {\n        MSG message;\n\n        memset(&message, 0, sizeof(MSG));\n        message.hwnd = WindowHandle;\n        message.message = WM_DPICHANGED;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), &message);\n    }\n\n    InvalidateRect(WindowHandle, NULL, TRUE);\n}\n\n/**\n * Handles custom user messages sent to the main window.\n *\n * \\param WindowHandle Handle to the window receiving the message.\n * \\param Message The user-defined message identifier.\n * \\param WParam Additional message-specific information.\n * \\param LParam Additional message-specific information.\n * \\return The result of message processing (LRESULT).\n */\nLRESULT PhMwpOnUserMessage(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    )\n{\n    switch (Message)\n    {\n    case WM_PH_ACTIVATE:\n        {\n            if (!PhMainWndEarlyExit && !PhMainWndExiting)\n            {\n                if (WParam != 0)\n                {\n                    PPH_PROCESS_NODE processNode;\n\n                    if (processNode = PhFindProcessNode((HANDLE)WParam))\n                        PhSelectAndEnsureVisibleProcessNode(processNode);\n                }\n\n                if (!IsWindowVisible(WindowHandle))\n                {\n                    ShowWindow(WindowHandle, SW_SHOW);\n                }\n\n                if (IsMinimized(WindowHandle))\n                {\n                    ShowWindow(WindowHandle, SW_RESTORE);\n                }\n\n                return PH_ACTIVATE_REPLY;\n            }\n            else\n            {\n                return 0;\n            }\n        }\n        break;\n    case WM_PH_NOTIFY_ICON_MESSAGE:\n        {\n            PhNfForwardMessage(WindowHandle, WParam, LParam);\n        }\n        break;\n    case WM_PH_DESTROY:\n        {\n            DestroyWindow(PhMainWndHandle);\n        }\n        break;\n    case WM_PH_PREPARE_FOR_EARLY_SHUTDOWN:\n        {\n            PhMwpInvokePrepareEarlyExit(PhMainWndHandle);\n        }\n        break;\n    case WM_PH_SAVE_ALL_SETTINGS:\n        {\n            PhMwpSaveSettings(PhMainWndHandle);\n        }\n        break;\n    case WM_PH_SHOW_PROPERTIES:\n        {\n            PhMwpShowProcessProperties((PPH_PROCESS_ITEM)LParam);\n        }\n        break;\n    case WM_PH_ACTIVATE_WINDOW:\n        {\n            BOOLEAN visibility = (BOOLEAN)(ULONG_PTR)LParam;\n\n            PhMwpInvokeActivateWindow(visibility);\n        }\n        break;\n    case WM_PH_SELECT_NODE:\n        {\n            switch ((ULONG)WParam)\n            {\n            case 1:\n                PhMwpInvokeSelectTabPage((PVOID)LParam);\n                break;\n            case 2:\n                PhSelectAndEnsureVisibleProcessNode((PVOID)LParam);\n                break;\n            case 3:\n                PhMwpInvokeSelectServiceItem((PVOID)LParam);\n                break;\n            case 4:\n                PhMwpInvokeSelectNetworkItem((PVOID)LParam);\n                break;\n            }\n        }\n        break;\n    case WM_PH_SHOW_EDITOR:\n        {\n            PPH_SHOW_MEMORY_EDITOR showMemoryEditor = (PPH_SHOW_MEMORY_EDITOR)WParam;\n\n            PhShowMemoryEditorDialog(\n                showMemoryEditor->OwnerWindow,\n                showMemoryEditor->ProcessId,\n                showMemoryEditor->BaseAddress,\n                showMemoryEditor->RegionSize,\n                showMemoryEditor->SelectOffset,\n                showMemoryEditor->SelectLength,\n                showMemoryEditor->Title,\n                showMemoryEditor->Flags\n                );\n            PhClearReference(&showMemoryEditor->Title);\n            PhFree(showMemoryEditor);\n        }\n        break;\n    case WM_PH_SHOW_RESULT:\n        {\n            PPH_SHOW_MEMORY_RESULTS showMemoryResults = (PPH_SHOW_MEMORY_RESULTS)WParam;\n\n            PhShowMemoryResultsDialog(\n                showMemoryResults->ProcessId,\n                showMemoryResults->Results\n                );\n            PhDereferenceMemoryResults(\n                (PPH_MEMORY_RESULT*)showMemoryResults->Results->Items,\n                showMemoryResults->Results->Count\n                );\n            PhDereferenceObject(showMemoryResults->Results);\n            PhFree(showMemoryResults);\n        }\n        break;\n    case WM_PH_INVOKE:\n        {\n            PhProcessInvokeQueue();\n            InterlockedExchange(&PhMainThreadInvokePending, 0);\n        }\n        break;\n    case WM_PH_UPDATE_FONT:\n        {\n            PhMwpInvokeUpdateWindowFont((PVOID)LParam);\n        }\n        break;\n    }\n\n    return 0;\n}\n\n/**\n * Loads the main window settings for the application.\n *\n * \\param WindowHandle Handle to the main window for which settings are to be loaded.\n */\nVOID PhMwpLoadSettings(\n    _In_ HWND WindowHandle\n    )\n{\n    ULONG opacity;\n\n    opacity = PhGetIntegerSetting(SETTING_MAIN_WINDOW_OPACITY);\n    PhStatisticsSampleCount = PhGetIntegerSetting(SETTING_SAMPLE_COUNT);\n    PhEnablePurgeProcessRecords = !PhGetIntegerSetting(SETTING_NO_PURGE_PROCESS_RECORDS);\n    PhEnableCycleCpuUsage = !!PhGetIntegerSetting(SETTING_ENABLE_CYCLE_CPU_USAGE);\n    PhEnableNetworkBoundConnections = !!PhGetIntegerSetting(SETTING_ENABLE_NETWORK_BOUND_CONNECTIONS);\n    PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(SETTING_ENABLE_NETWORK_RESOLVE);\n    PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(SETTING_ENABLE_STAGE2);\n    PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(SETTING_ENABLE_SERVICE_STAGE2);\n    PhEnableTooltipSupport = !!PhGetIntegerSetting(SETTING_ENABLE_TOOLTIP_SUPPORT);\n    PhEnableImageCoherencySupport = !!PhGetIntegerSetting(SETTING_ENABLE_IMAGE_COHERENCY_SUPPORT);\n    PhEnableLinuxSubsystemSupport = !!PhGetIntegerSetting(SETTING_ENABLE_LINUX_SUBSYSTEM_SUPPORT);\n    PhEnablePackageIconSupport = !!PhGetIntegerSetting(SETTING_ENABLE_PACKAGE_ICON_SUPPORT);\n    PhEnableSecurityAdvancedDialog = !!PhGetIntegerSetting(SETTING_ENABLE_SECURITY_ADVANCED_DIALOG);\n    PhEnableProcessHandlePnPDeviceNameSupport = !!PhGetIntegerSetting(SETTING_ENABLE_PROCESS_HANDLE_PNP_DEVICE_NAME_SUPPORT);\n    PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(SETTING_ICON_NOTIFY_MASK);\n\n    if (PhGetIntegerSetting(SETTING_MAIN_WINDOW_ALWAYS_ON_TOP))\n    {\n        AlwaysOnTop = TRUE;\n        SetWindowPos(WindowHandle, HWND_TOPMOST, 0, 0, 0, 0,\n            SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);\n    }\n\n    if (opacity != 0)\n        PhSetWindowOpacity(WindowHandle, opacity);\n\n    PhMwpInvokeUpdateWindowFont(NULL);\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_MONOSPACE_FONT))\n    {\n        PhMwpInvokeUpdateWindowFontMonospace(WindowHandle, NULL);\n    }\n\n    PhNfLoadStage1();\n\n    PhMwpNotifyAllPages(MainTabPageLoadSettings, NULL, NULL);\n\n    PhLogInitialization();\n}\n\n/**\n * Saves the current settings of the main window.\n *\n * \\param WindowHandle Handle to the main window whose settings are to be saved.\n */\nVOID PhMwpSaveSettings(\n    _In_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n\n    PhMwpNotifyAllPages(MainTabPageSaveSettings, NULL, NULL);\n\n    PhSaveWindowPlacementToSetting(SETTING_MAIN_WINDOW_POSITION, SETTING_MAIN_WINDOW_SIZE, WindowHandle);\n    PhMwpSaveWindowState(WindowHandle);\n\n    if (PhIsNullOrEmptyString(PhSettingsFileName))\n        status = PhSaveSettings(NULL);\n    else\n        status = PhSaveSettings(&PhSettingsFileName->sr);\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(NULL, L\"Unable to save application settings.\", status, 0);\n    }\n}\n\n/**\n * Saves the current state of the main window.\n * \\param WindowHandle Handle to the window whose state is to be saved.\n */\nVOID PhMwpSaveWindowState(\n    _In_ HWND WindowHandle\n    )\n{\n    WINDOWPLACEMENT placement = { sizeof(placement) };\n\n    GetWindowPlacement(WindowHandle, &placement);\n\n    if (placement.showCmd == SW_NORMAL)\n        PhSetIntegerSetting(SETTING_MAIN_WINDOW_STATE, SW_NORMAL);\n    else if (placement.showCmd == SW_MAXIMIZE)\n        PhSetIntegerSetting(SETTING_MAIN_WINDOW_STATE, SW_MAXIMIZE);\n}\n\n/**\n * Updates the layout padding for the main window.\n *\n * This function recalculates and applies the necessary padding values\n * to the main window layout, ensuring proper spacing and alignment\n * of UI elements. It should be called whenever the window layout\n * or padding requirements change.\n */\nVOID PhMwpUpdateLayoutPadding(\n    VOID\n    )\n{\n    PH_LAYOUT_PADDING_DATA data;\n\n    memset(&data, 0, sizeof(PH_LAYOUT_PADDING_DATA));\n    PhInvokeCallback(&LayoutPaddingCallback, &data);\n\n    LayoutPadding = data.Padding;\n}\n\n/**\n * Applies padding to the specified rectangle.\n *\n * \\param Rect A pointer to a RECT structure that will be modified to include the specified padding.\n * \\param Padding A pointer to a RECT structure specifying the padding to apply (left, top, right, bottom).\n */\nVOID PhMwpApplyLayoutPadding(\n    _Inout_ PRECT Rect,\n    _In_ PRECT Padding\n    )\n{\n    Rect->left += Padding->left;\n    Rect->top += Padding->top;\n    Rect->right -= Padding->right;\n    Rect->bottom -= Padding->bottom;\n}\n\n/**\n * Adjusts the layout of the main window using a deferred window positioning handle.\n *\n * \\param DeferHandle A pointer to an HDWP handle used for batching window position changes.\n */\nVOID PhMwpLayout(\n    _Inout_ HDWP *DeferHandle\n    )\n{\n    RECT rect;\n\n    // Resize the tab control.\n    // Don't defer the resize. The tab control doesn't repaint properly.\n\n    if (!LayoutPaddingValid)\n    {\n        PhMwpUpdateLayoutPadding();\n        LayoutPaddingValid = TRUE;\n    }\n\n    if (!PhGetClientRect(PhMainWndHandle, &rect))\n        return;\n\n    PhMwpApplyLayoutPadding(&rect, &LayoutPadding);\n\n    if (PhEnableDeferredLayout)\n    {\n        *DeferHandle = DeferWindowPos(\n            *DeferHandle,\n            TabControlHandle,\n            HWND_BOTTOM,\n            rect.left,\n            rect.top,\n            rect.right - rect.left,\n            rect.bottom - rect.top,\n            SWP_NOACTIVATE | SWP_NOZORDER\n            );\n    }\n    else\n    {\n        SetWindowPos(\n            TabControlHandle,\n            NULL,\n            rect.left,\n            rect.top,\n            rect.right - rect.left,\n            rect.bottom - rect.top,\n            SWP_NOACTIVATE | SWP_NOZORDER\n            );\n        UpdateWindow(TabControlHandle);\n    }\n\n    PhMwpLayoutTabControl(DeferHandle);\n}\n\n/**\n * Sets up the computer menu for the main window.\n *\n * \\param Root Pointer to the root menu item to be configured.\n */\nVOID PhMwpSetupComputerMenu(\n    _In_ PPH_EMENU_ITEM Root\n    )\n{\n    PPH_EMENU_ITEM menuItem;\n\n    if (WindowsVersion < WINDOWS_8)\n    {\n        if (menuItem = PhFindEMenuItem(Root, PH_EMENU_FIND_DESCEND, NULL, ID_COMPUTER_RESTARTADVOPTIONS))\n            PhDestroyEMenuItem(menuItem);\n        if (menuItem = PhFindEMenuItem(Root, PH_EMENU_FIND_DESCEND, NULL, ID_COMPUTER_RESTARTBOOTOPTIONS))\n            PhDestroyEMenuItem(menuItem);\n        if (menuItem = PhFindEMenuItem(Root, PH_EMENU_FIND_DESCEND, NULL, ID_COMPUTER_SHUTDOWNHYBRID))\n            PhDestroyEMenuItem(menuItem);\n        if (menuItem = PhFindEMenuItem(Root, PH_EMENU_FIND_DESCEND, NULL, ID_COMPUTER_RESTARTFWDEVICE))\n            PhDestroyEMenuItem(menuItem);\n        if (menuItem = PhFindEMenuItem(Root, PH_EMENU_FIND_DESCEND, NULL, ID_COMPUTER_RESTARTBOOTDEVICE))\n            PhDestroyEMenuItem(menuItem);\n    }\n}\n\n/**\n * Executes a computer-related command based on the specified command ID.\n *\n * \\param WindowHandle Handle to the window that will receive any notifications or messages.\n * \\param Id Identifier of the computer command to execute.\n * \\return TRUE if the command was executed successfully, FALSE otherwise.\n */\nBOOLEAN PhMwpExecuteComputerCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id\n    )\n{\n    switch (Id)\n    {\n    case ID_COMPUTER_LOCK:\n        PhUiLockComputer(WindowHandle);\n        return TRUE;\n    case ID_COMPUTER_LOGOFF:\n        PhUiLogoffComputer(WindowHandle);\n        return TRUE;\n    case ID_COMPUTER_SLEEP:\n        PhUiSleepComputer(WindowHandle);\n        return TRUE;\n    case ID_COMPUTER_HIBERNATE:\n        PhUiHibernateComputer(WindowHandle);\n        return TRUE;\n    case ID_COMPUTER_RESTART:\n        PhUiRestartComputer(WindowHandle, PH_POWERACTION_TYPE_WIN32, 0);\n        return TRUE;\n    case ID_COMPUTER_RESTARTADVOPTIONS:\n        PhUiRestartComputer(WindowHandle, PH_POWERACTION_TYPE_ADVANCEDBOOT, 0);\n        return TRUE;\n    case ID_COMPUTER_RESTARTBOOTOPTIONS:\n        PhUiRestartComputer(WindowHandle, PH_POWERACTION_TYPE_WIN32, PH_SHUTDOWN_RESTART_BOOTOPTIONS);\n        return TRUE;\n    case ID_COMPUTER_RESTARTFWOPTIONS:\n        PhUiRestartComputer(WindowHandle, PH_POWERACTION_TYPE_FIRMWAREBOOT, 0);\n        return TRUE;\n    case ID_COMPUTER_SHUTDOWN:\n        PhUiShutdownComputer(WindowHandle, PH_POWERACTION_TYPE_WIN32, 0);\n        return TRUE;\n    case ID_COMPUTER_SHUTDOWNHYBRID:\n        PhUiShutdownComputer(WindowHandle, PH_POWERACTION_TYPE_WIN32, PH_SHUTDOWN_HYBRID);\n        return TRUE;\n    case ID_COMPUTER_RESTART_NATIVE:\n        PhUiRestartComputer(WindowHandle, PH_POWERACTION_TYPE_NATIVE, 0);\n        return TRUE;\n    case ID_COMPUTER_SHUTDOWN_NATIVE:\n        PhUiShutdownComputer(WindowHandle, PH_POWERACTION_TYPE_NATIVE, 0);\n        return TRUE;\n    case ID_COMPUTER_RESTART_CRITICAL:\n        PhUiRestartComputer(WindowHandle, PH_POWERACTION_TYPE_CRITICAL, 0);\n        return TRUE;\n    case ID_COMPUTER_SHUTDOWN_CRITICAL:\n        PhUiShutdownComputer(WindowHandle, PH_POWERACTION_TYPE_CRITICAL, 0);\n        return TRUE;\n    case ID_COMPUTER_RESTART_UPDATE:\n        PhUiRestartComputer(WindowHandle, PH_POWERACTION_TYPE_UPDATE, 0);\n        return TRUE;\n    case ID_COMPUTER_SHUTDOWN_UPDATE:\n        PhUiShutdownComputer(WindowHandle, PH_POWERACTION_TYPE_UPDATE, 0);\n        return TRUE;\n    case ID_COMPUTER_RESTARTWDOSCAN:\n        PhUiRestartComputer(WindowHandle, PH_POWERACTION_TYPE_WDOSCAN, 0);\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Determines whether the specified window is overlapped by other windows.\n *\n * \\param WindowHandle Handle to the window to check for overlap.\n * \\return TRUE if the window is overlapped by other windows; FALSE otherwise.\n */\nBOOLEAN PhMwpIsWindowOverlapped(\n    _In_ HWND WindowHandle\n    )\n{\n    RECT rectThisWindow = { 0 };\n    RECT rectOtherWindow = { 0 };\n    RECT rectIntersection = { 0 };\n    HWND windowHandle = WindowHandle;\n\n    if (!PhGetWindowRect(WindowHandle, &rectThisWindow))\n        return FALSE;\n\n    while ((windowHandle = GetWindow(windowHandle, GW_HWNDPREV)) && windowHandle != WindowHandle)\n    {\n        if (!(PhGetWindowStyle(windowHandle) & WS_VISIBLE))\n            continue;\n\n        if (!PhGetWindowRect(windowHandle, &rectOtherWindow))\n            continue;\n\n        if (!(PhGetWindowStyleEx(windowHandle) & WS_EX_TOPMOST) &&\n            IntersectRect(&rectIntersection, &rectThisWindow, &rectOtherWindow))\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Activates the specified window.\n *\n * \\param WindowHandle Handle to the window to be activated.\n * \\param Toggle If TRUE, toggles the activation state; if FALSE, activates the window without toggling.\n */\nVOID PhMwpActivateWindow(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN Toggle\n    )\n{\n    if (IsMinimized(WindowHandle))\n    {\n        ShowWindow(WindowHandle, SW_RESTORE);\n        SetForegroundWindow(WindowHandle);\n    }\n    else if (IsWindowVisible(WindowHandle))\n    {\n        if (Toggle && !PhMwpIsWindowOverlapped(WindowHandle))\n            ShowWindow(WindowHandle, SW_HIDE);\n        else\n            SetForegroundWindow(WindowHandle);\n    }\n    else\n    {\n        ShowWindow(WindowHandle, SW_SHOW);\n        SetForegroundWindow(WindowHandle);\n    }\n}\n\n/**\n * Creates a computer menu.\n *\n * \\param DelayLoadMenu Specifies whether the menu should be loaded with a delay.\n * \\return A pointer to the created PPH_EMENU structure.\n */\nPPH_EMENU PhpCreateComputerMenu(\n    _In_ BOOLEAN DelayLoadMenu\n    )\n{\n    PPH_EMENU_ITEM menuItem;\n\n    menuItem = PhCreateEMenuItem(0, 0, L\"&Computer\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_LOCK, L\"&Lock\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_LOGOFF, L\"Log o&ff\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_SLEEP, L\"&Sleep\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_HIBERNATE, L\"&Hibernate\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_RESTART_UPDATE, L\"Update and restart\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_SHUTDOWN_UPDATE, L\"Update and shut down\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_RESTART, L\"R&estart\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(PhGetOwnTokenAttributes().Elevated ? 0 : PH_EMENU_DISABLED, ID_COMPUTER_RESTARTADVOPTIONS, L\"Restart to advanced options\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_RESTARTBOOTOPTIONS, L\"Restart to boot options\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(PhGetOwnTokenAttributes().Elevated ? 0 : PH_EMENU_DISABLED, ID_COMPUTER_RESTARTFWOPTIONS, L\"Restart to firmware options\", NULL, NULL), ULONG_MAX);\n    if (PhGetIntegerSetting(SETTING_ENABLE_SHUTDOWN_BOOT_MENU))\n    {\n        PVOID bootApplicationMenu = PhUiCreateComputerBootDeviceMenu(DelayLoadMenu);\n        if (WindowsVersion >= WINDOWS_10 && PhGetOwnTokenAttributes().Elevated)\n            PhInsertEMenuItem(bootApplicationMenu, PhCreateEMenuItem(0, ID_COMPUTER_RESTARTWDOSCAN, L\"Windows Defender Offline Scan\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, bootApplicationMenu, ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhUiCreateComputerFirmwareDeviceMenu(DelayLoadMenu), ULONG_MAX);\n    }\n    PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_SHUTDOWN, L\"Shu&t down\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_SHUTDOWNHYBRID, L\"H&ybrid shut down\", NULL, NULL), ULONG_MAX);\n    if (PhGetIntegerSetting(SETTING_ENABLE_SHUTDOWN_CRITICAL_MENU))\n    {\n        PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_RESTART_NATIVE, L\"R&estart (Native)\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_SHUTDOWN_NATIVE, L\"Shu&t down (Native)\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_RESTART_CRITICAL, L\"R&estart (Critical)\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_COMPUTER_SHUTDOWN_CRITICAL, L\"Shu&t down (Critical)\", NULL, NULL), ULONG_MAX);\n    }\n\n    return menuItem;\n}\n\n/**\n * Creates the system menu for the application.\n *\n * \\param HackerMenu A pointer to the base menu structure to be used for creating the system menu.\n * \\param DelayLoadMenu If TRUE, the menu will be loaded with a delay; if FALSE, it will be loaded immediately.\n * \\return A pointer to the newly created system menu (PPH_EMENU).\n */\nPPH_EMENU PhpCreateSystemMenu(\n    _In_ PPH_EMENU HackerMenu,\n    _In_ BOOLEAN DelayLoadMenu\n    )\n{\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuItem(0, ID_HACKER_RUN, L\"&Run...\\bCtrl+R\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuItem(0, ID_HACKER_RUNAS, L\"Run &as...\\bCtrl+Shift+R\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuItem(0, ID_HACKER_RUNASPACKAGE, L\"Run as &package...\\bCtrl+Shift+P\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuItem(0, ID_HACKER_SHOWDETAILSFORALLPROCESSES, L\"Show &details for all processes\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuItem(0, ID_HACKER_SAVE, L\"&Save...\\bCtrl+S\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuItem(0, ID_HACKER_FINDHANDLESORDLLS, L\"&Find handles or DLLs...\\bCtrl+F\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuItem(0, ID_HACKER_OPTIONS, L\"&Options...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhpCreateComputerMenu(DelayLoadMenu), ULONG_MAX);\n    PhInsertEMenuItem(HackerMenu, PhCreateEMenuItem(0, ID_HACKER_EXIT, L\"E&xit\", NULL, NULL), ULONG_MAX);\n\n    return HackerMenu;\n}\n\n/**\n * Creates and initializes a view menu.\n *\n * \\param ViewMenu A pointer to an existing PPH_EMENU structure representing the view menu to be created or modified.\n * \\return A pointer to the newly created or updated PPH_EMENU structure.\n */\nPPH_EMENU PhpCreateViewMenu(\n    _In_ PPH_EMENU ViewMenu\n    )\n{\n    PPH_EMENU_ITEM menuItem;\n\n    PhInsertEMenuItem(ViewMenu, PhCreateEMenuItem(0, ID_VIEW_SYSTEMINFORMATION, L\"System &information\\bCtrl+I\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ViewMenu, PhCreateEMenuItem(0, ID_VIEW_TRAYICONS, L\"&Tray icons\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ViewMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(ViewMenu, PhCreateEMenuItem(0, ID_VIEW_SECTIONPLACEHOLDER, L\"<section placeholder>\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ViewMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(ViewMenu, PhCreateEMenuItem(0, ID_VIEW_ALWAYSONTOP, L\"&Always on top\", NULL, NULL), ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, 0, L\"&Opacity\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_10, L\"&10%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_20, L\"&20%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_30, L\"&30%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_40, L\"&40%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_50, L\"&50%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_60, L\"&60%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_70, L\"&70%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_80, L\"&80%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_90, L\"&90%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_OPAQUE, L\"&Opaque\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ViewMenu, menuItem, ULONG_MAX);\n\n    PhInsertEMenuItem(ViewMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(ViewMenu, PhCreateEMenuItem(0, ID_VIEW_REFRESH, L\"&Refresh\\bF5\", NULL, NULL), ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, 0, L\"Refresh i&nterval\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_UPDATEINTERVAL_FAST, L\"&Fast (0.5s)\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_UPDATEINTERVAL_NORMAL, L\"&Normal (1s)\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_UPDATEINTERVAL_BELOWNORMAL, L\"&Below normal (2s)\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_UPDATEINTERVAL_SLOW, L\"&Slow (5s)\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_UPDATEINTERVAL_VERYSLOW, L\"&Very slow (10s)\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ViewMenu, menuItem, ULONG_MAX);\n\n    PhInsertEMenuItem(ViewMenu, PhCreateEMenuItem(0, ID_VIEW_UPDATEAUTOMATICALLY, L\"Refresh a&utomatically\\bF6\", NULL, NULL), ULONG_MAX);\n\n    return ViewMenu;\n}\n\n/**\n * Creates or initializes the Tools menu.\n *\n * \\param ToolsMenu A pointer to an existing PPH_EMENU structure representing the Tools menu.\n * \\return A pointer to the created or modified PPH_EMENU structure.\n */\nPPH_EMENU PhpCreateToolsMenu(\n    _In_ PPH_EMENU ToolsMenu\n    )\n{\n    PPH_EMENU_ITEM menuItem;\n\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuItem(0, ID_TOOLS_CREATESERVICE, L\"&Create service...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuItem(0, ID_TOOLS_LIVEDUMP, L\"&Create live dump...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuItem(0, ID_TOOLS_INSPECTEXECUTABLEFILE, L\"Inspect e&xecutable file...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuItem(0, ID_TOOLS_THREADSTACKS, L\"&Search thread stacks\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuItem(0, ID_TOOLS_ZOMBIEPROCESSES, L\"&Zombie processes\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuItem(0, ID_TOOLS_PAGEFILES, L\"&Pagefiles\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuItem(0, ID_TOOLS_STARTTASKMANAGER, L\"Start &Task Manager\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuItem(0, ID_TOOLS_STARTRESOURCEMONITOR, L\"Start &Resource Monitor\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuItem(0, ID_TOOLS_SHUTDOWNWSLPROCESSES, L\"T&erminate WSL processes\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, 0, L\"&Permissions\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_PWR_PERMISSIONS, L\"Current Power Scheme\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_SCM_PERMISSIONS, L\"Service Control Manager\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_RDP_PERMISSIONS, L\"Terminal Server Listener\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_WMI_PERMISSIONS, L\"WMI Root Namespace\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_COM_ACCESS_PERMISSIONS, L\"COM Access Permissions\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_COM_ACCESS_RESTRICTIONS, L\"COM Access Restrictions\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_COM_LAUNCH_PERMISSIONS, L\"COM Launch Permissions\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_COM_LAUNCH_RESTRICTIONS, L\"COM Launch Restrictions\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_DESKTOP_PERMISSIONS, L\"Current Window Desktop\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_TOOLS_STATION_PERMISSIONS, L\"Current Window Station\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(ToolsMenu, menuItem, ULONG_MAX);\n\n    return ToolsMenu;\n}\n\n/**\n * Creates or initializes a users menu.\n *\n * \\param UsersMenu Pointer to an existing PPH_EMENU structure to be used or modified.\n * \\param DelayLoadMenu If TRUE, the menu will be loaded with a delay; if FALSE, it will be loaded immediately.\n * \\return Pointer to the created or initialized PPH_EMENU structure representing the users menu.\n */\nPPH_EMENU PhpCreateUsersMenu(\n    _In_ PPH_EMENU UsersMenu,\n    _In_ BOOLEAN DelayLoadMenu\n    )\n{\n    if (DelayLoadMenu)\n    {\n        // Insert a dummy menu so we're able to receive menu events and delay load winsta.dll functions. (dmex)\n        PhInsertEMenuItem(UsersMenu, PhCreateEMenuItem(0, USHRT_MAX, L\" \", NULL, NULL), ULONG_MAX);\n        return UsersMenu;\n    }\n\n    PhUiCreateSessionMenu(UsersMenu);\n\n    PhInsertEMenuItem(UsersMenu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(UsersMenu, PhCreateEMenuItem(PhGetOwnTokenAttributes().Elevated ? 0 : PH_EMENU_DISABLED, ID_TOOLS_USER_LIST, L\"User list...\", NULL, NULL), ULONG_MAX);\n\n    return UsersMenu;\n}\n\n/**\n * Creates or initializes a Help menu.\n *\n * \\param HelpMenu A pointer to a PPH_EMENU structure representing the Help menu to be created or initialized.\n * \\return A pointer to the created or initialized PPH_EMENU structure.\n */\nPPH_EMENU PhpCreateHelpMenu(\n    _In_ PPH_EMENU HelpMenu\n    )\n{\n    PhInsertEMenuItem(HelpMenu, PhCreateEMenuItem(0, ID_HELP_LOG, L\"&Log\\bCtrl+L\", NULL, NULL), ULONG_MAX);\n    //PhInsertEMenuItem(HelpMenu, PhCreateEMenuItem(0, ID_HELP_DONATE, L\"&Donate\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(HelpMenu, PhCreateEMenuItem(0, ID_HELP_DEBUGCONSOLE, L\"Debu&g console\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(HelpMenu, PhCreateEMenuItem(0, ID_HELP_ABOUT, L\"&About\", NULL, NULL), ULONG_MAX);\n\n    return HelpMenu;\n}\n\n/**\n * Creates the main menu for the application.\n *\n * \\param SubMenuIndex The index of the submenu to be created or selected.\n * \\return A pointer to the created PPH_EMENU structure representing the main menu.\n */\nPPH_EMENU PhpCreateMainMenu(\n    _In_ ULONG SubMenuIndex\n    )\n{\n    PPH_EMENU menu = PhCreateEMenu();\n\n    switch (SubMenuIndex)\n    {\n    case PH_MENU_ITEM_LOCATION_SYSTEM:\n        return PhpCreateSystemMenu(menu, FALSE);\n    case PH_MENU_ITEM_LOCATION_VIEW:\n        return PhpCreateViewMenu(menu);\n    case PH_MENU_ITEM_LOCATION_TOOLS:\n        return PhpCreateToolsMenu(menu);\n    case PH_MENU_ITEM_LOCATION_USERS:\n        return PhpCreateUsersMenu(menu, FALSE);\n    case PH_MENU_ITEM_LOCATION_HELP:\n        return PhpCreateHelpMenu(menu);\n    case ULONG_MAX:\n        {\n            PPH_EMENU_ITEM menuItem;\n            menu->Flags |= PH_EMENU_MAINMENU;\n\n            menuItem = PhCreateEMenuItem(PH_EMENU_MAINMENU, PH_MENU_ITEM_LOCATION_SYSTEM, L\"&System\", NULL, NULL);\n            // Insert an empty menuitem so we're able to delay load the submenu. (dmex)\n            PhInsertEMenuItem(menuItem, PhCreateEMenuItemEmpty(), ULONG_MAX);\n            PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n            //PhInsertEMenuItem(menu, PhpCreateSystemMenu(menuItem, TRUE), ULONG_MAX);\n\n            menuItem = PhCreateEMenuItem(PH_EMENU_MAINMENU, PH_MENU_ITEM_LOCATION_VIEW, L\"&View\", NULL, NULL);\n            // Insert an empty menuitem so we're able to delay load the submenu. (dmex)\n            PhInsertEMenuItem(menuItem, PhCreateEMenuItemEmpty(), ULONG_MAX);\n            PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n            //PhInsertEMenuItem(menu, PhpCreateViewMenu(menuItem), ULONG_MAX);\n\n            menuItem = PhCreateEMenuItem(PH_EMENU_MAINMENU, PH_MENU_ITEM_LOCATION_TOOLS, L\"&Tools\", NULL, NULL);\n            // Insert an empty menuitem so we're able to delay load the submenu. (dmex)\n            PhInsertEMenuItem(menuItem, PhCreateEMenuItemEmpty(), ULONG_MAX);\n            PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n            //PhInsertEMenuItem(menu, PhpCreateToolsMenu(menuItem), ULONG_MAX);\n\n            menuItem = PhCreateEMenuItem(PH_EMENU_MAINMENU, PH_MENU_ITEM_LOCATION_USERS, L\"&Users\", NULL, NULL);\n            // Insert an empty menuitem so we're able to delay load the submenu. (dmex)\n            PhInsertEMenuItem(menuItem, PhCreateEMenuItemEmpty(), ULONG_MAX);\n            PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n            //PhInsertEMenuItem(menu, PhpCreateUsersMenu(menuItem, TRUE), ULONG_MAX);\n\n            menuItem = PhCreateEMenuItem(PH_EMENU_MAINMENU, PH_MENU_ITEM_LOCATION_HELP, L\"&Help\", NULL, NULL);\n            // Insert an empty menuitem so we're able to delay load the submenu. (dmex)\n            PhInsertEMenuItem(menuItem, PhCreateEMenuItemEmpty(), ULONG_MAX);\n            PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n            //PhInsertEMenuItem(menu, PhpCreateHelpMenu(menuItem), ULONG_MAX);\n        }\n        break;\n    }\n\n    return menu;\n}\n\n/**\n * Initializes the main menu for the specified window.\n *\n * \\param WindowHandle Handle to the window for which the main menu is to be initialized.\n */\nVOID PhMwpInitializeMainMenu(\n    _In_ HWND WindowHandle\n    )\n{\n    HMENU menuHandle;\n\n    // Initialize the menu.\n\n    if (!(menuHandle = CreateMenu()))\n        return;\n\n    PhEMenuToHMenu2(menuHandle, PhpCreateMainMenu(ULONG_MAX), 0, NULL);\n    PhInitializeWindowThemeMainMenu(menuHandle);\n    PhSetHMenuNotify(menuHandle);\n    SetMenu(WindowHandle, menuHandle);\n\n    // Initialize the submenu.\n\n    for (LONG i = 0; i < RTL_NUMBER_OF(SubMenuHandles); i++)\n    {\n        SubMenuHandles[i] = GetSubMenu(menuHandle, i);\n    }\n}\n\n/**\n * Dispatches a menu command based on the provided parameters.\n *\n * \\param WindowHandle Handle to the window receiving the menu command.\n * \\param ItemId Identifier of the menu item.\n * \\param ItemData Additional data associated with the menu item.\n */\nVOID PhMwpDispatchMenuCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG ItemId,\n    _In_ ULONG_PTR ItemData\n    )\n{\n    switch (ItemId)\n    {\n    case ID_PLUGIN_MENU_ITEM:\n        {\n            PPH_EMENU_ITEM menuItem;\n            PH_PLUGIN_MENU_INFORMATION menuInfo;\n\n            menuItem = (PPH_EMENU_ITEM)ItemData;\n\n            if (menuItem)\n            {\n                PhPluginInitializeMenuInfo(&menuInfo, NULL, WindowHandle, 0);\n                PhPluginTriggerEMenuItem(&menuInfo, menuItem);\n            }\n\n            return;\n        }\n        break;\n    case ID_TRAYICONS_REGISTERED:\n        {\n            PPH_EMENU_ITEM menuItem;\n\n            menuItem = (PPH_EMENU_ITEM)ItemData;\n\n            if (menuItem)\n            {\n                PPH_NF_ICON icon;\n\n                icon = menuItem->Context;\n                PhNfSetVisibleIcon(icon, !(icon->Flags & PH_NF_ICON_ENABLED));\n                PhNfSaveSettings();\n            }\n\n            return;\n        }\n        break;\n    case ID_USER_CONNECT:\n    case ID_USER_DISCONNECT:\n    case ID_USER_LOGOFF:\n    case ID_USER_REMOTECONTROL:\n    case ID_USER_SENDMESSAGE:\n    case ID_USER_PROPERTIES:\n        {\n            PPH_EMENU_ITEM menuItem;\n\n            menuItem = (PPH_EMENU_ITEM)ItemData;\n\n            if (menuItem && menuItem->Parent)\n            {\n                SelectedUserSessionId = PtrToUlong(menuItem->Parent->Context);\n            }\n        }\n        break;\n    case ID_VIEW_ORGANIZECOLUMNSETS:\n        {\n            PhShowColumnSetEditorDialog(WindowHandle, SETTING_PROCESS_TREE_COLUMN_SET_CONFIG);\n        }\n        return;\n    case ID_VIEW_SAVECOLUMNSET:\n        {\n            PPH_EMENU_ITEM menuItem;\n            PPH_STRING columnSetName = NULL;\n\n            menuItem = (PPH_EMENU_ITEM)ItemData;\n\n            while (PhaChoiceDialog(\n                WindowHandle,\n                L\"Column Set Name\",\n                L\"Enter a name for this column set:\",\n                NULL,\n                0,\n                NULL,\n                PH_CHOICE_DIALOG_USER_CHOICE,\n                &columnSetName,\n                NULL,\n                NULL\n                ))\n            {\n                if (!PhIsNullOrEmptyString(columnSetName))\n                    break;\n            }\n\n            if (!PhIsNullOrEmptyString(columnSetName))\n            {\n                PPH_STRING treeSettings;\n                PPH_STRING sortSettings;\n\n                // Query the current column configuration.\n                PhSaveSettingsProcessTreeListEx(&treeSettings, &sortSettings);\n                // Create the column set for this column configuration.\n                PhSaveSettingsColumnSet(SETTING_PROCESS_TREE_COLUMN_SET_CONFIG, columnSetName, treeSettings, sortSettings);\n\n                PhDereferenceObject(treeSettings);\n                PhDereferenceObject(sortSettings);\n            }\n        }\n        return;\n    case ID_VIEW_LOADCOLUMNSET:\n        {\n            PPH_EMENU_ITEM menuItem;\n            PPH_STRING columnSetName;\n            PPH_STRING treeSettings;\n            PPH_STRING sortSettings;\n\n            menuItem = (PPH_EMENU_ITEM)ItemData;\n            columnSetName = PhCreateString(menuItem->Text);\n\n            // Query the selected column set.\n            if (PhLoadSettingsColumnSet(SETTING_PROCESS_TREE_COLUMN_SET_CONFIG, columnSetName, &treeSettings, &sortSettings))\n            {\n                // Load the column configuration from the selected column set.\n                PhLoadSettingsProcessTreeListEx(treeSettings, sortSettings);\n\n                PhDereferenceObject(treeSettings);\n                PhDereferenceObject(sortSettings);\n            }\n\n            PhDereferenceObject(columnSetName);\n        }\n        return;\n    case ID_COMPUTER_RESTARTBOOTDEVICE:\n        {\n            PPH_EMENU_ITEM menuItem = (PPH_EMENU_ITEM)ItemData;\n\n            PhUiHandleComputerBootApplicationMenu(WindowHandle, PtrToUlong(menuItem->Context));\n        }\n        return;\n    case ID_COMPUTER_RESTARTFWDEVICE:\n        {\n            PPH_EMENU_ITEM menuItem = (PPH_EMENU_ITEM)ItemData;\n\n            PhUiHandleComputerFirmwareApplicationMenu(WindowHandle, PtrToUlong(menuItem->Context));\n        }\n        return;\n    }\n\n    SendMessage(WindowHandle, WM_COMMAND, ItemId, 0);\n}\n\n/**\n * Creates and returns a notification menu for the system tray or notification area.\n * \\return A pointer to a PPH_EMENU structure representing the created notification menu.\n */\nPPH_EMENU PhpCreateNotificationMenu(\n    VOID\n    )\n{\n    PPH_EMENU_ITEM menuItem;\n    ULONG i;\n    ULONG id = ULONG_MAX;\n\n    menuItem = PhCreateEMenuItem(0, 0, L\"N&otifications\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_ENABLEALL, L\"&Enable all\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_DISABLEALL, L\"&Disable all\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_NEWPROCESSES, L\"New &processes\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_TERMINATEDPROCESSES, L\"T&erminated processes\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_NEWSERVICES, L\"New &services\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_STARTEDSERVICES, L\"St&arted services\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_STOPPEDSERVICES, L\"St&opped services\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_DELETEDSERVICES, L\"&Deleted services\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_MODIFIEDSERVICES, L\"&Modified services\", NULL, NULL), ULONG_MAX);\n    if (WindowsVersion >= WINDOWS_10)\n    {\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_ARRIVEDDEVICES, L\"&Arrived devices\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_REMOVEDDEVICES, L\"&Removed devices\", NULL, NULL), ULONG_MAX);\n    }\n\n    for (i = PH_NOTIFY_MINIMUM; i != PH_NOTIFY_MAXIMUM; i <<= 1)\n    {\n        if (PhMwpNotifyIconNotifyMask & i)\n        {\n            switch (i)\n            {\n            case PH_NOTIFY_PROCESS_CREATE:\n                id = ID_NOTIFICATIONS_NEWPROCESSES;\n                break;\n            case PH_NOTIFY_PROCESS_DELETE:\n                id = ID_NOTIFICATIONS_TERMINATEDPROCESSES;\n                break;\n            case PH_NOTIFY_SERVICE_CREATE:\n                id = ID_NOTIFICATIONS_NEWSERVICES;\n                break;\n            case PH_NOTIFY_SERVICE_DELETE:\n                id = ID_NOTIFICATIONS_DELETEDSERVICES;\n                break;\n            case PH_NOTIFY_SERVICE_START:\n                id = ID_NOTIFICATIONS_STARTEDSERVICES;\n                break;\n            case PH_NOTIFY_SERVICE_STOP:\n                id = ID_NOTIFICATIONS_STOPPEDSERVICES;\n                break;\n            case PH_NOTIFY_SERVICE_MODIFIED:\n                id = ID_NOTIFICATIONS_MODIFIEDSERVICES;\n                break;\n            case PH_NOTIFY_DEVICE_ARRIVED:\n                id = ID_NOTIFICATIONS_ARRIVEDDEVICES;\n                break;\n            case PH_NOTIFY_DEVICE_REMOVED:\n                id = ID_NOTIFICATIONS_REMOVEDDEVICES;\n                break;\n            }\n\n            PhSetFlagsEMenuItem(menuItem, id, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n        }\n    }\n\n    return menuItem;\n}\n\nBOOLEAN PhMwpExecuteNotificationMenuCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id\n    )\n{\n    switch (Id)\n    {\n    case ID_NOTIFICATIONS_ENABLEALL:\n        SetFlag(PhMwpNotifyIconNotifyMask, PH_NOTIFY_VALID_MASK);\n        PhSetIntegerSetting(SETTING_ICON_NOTIFY_MASK, PhMwpNotifyIconNotifyMask);\n        return TRUE;\n    case ID_NOTIFICATIONS_DISABLEALL:\n        ClearFlag(PhMwpNotifyIconNotifyMask, PH_NOTIFY_VALID_MASK);\n        PhSetIntegerSetting(SETTING_ICON_NOTIFY_MASK, PhMwpNotifyIconNotifyMask);\n        return TRUE;\n    case ID_NOTIFICATIONS_NEWPROCESSES:\n    case ID_NOTIFICATIONS_TERMINATEDPROCESSES:\n    case ID_NOTIFICATIONS_NEWSERVICES:\n    case ID_NOTIFICATIONS_STARTEDSERVICES:\n    case ID_NOTIFICATIONS_STOPPEDSERVICES:\n    case ID_NOTIFICATIONS_DELETEDSERVICES:\n    case ID_NOTIFICATIONS_MODIFIEDSERVICES:\n    case ID_NOTIFICATIONS_ARRIVEDDEVICES:\n    case ID_NOTIFICATIONS_REMOVEDDEVICES:\n        {\n            ULONG bit = 0;\n\n            switch (Id)\n            {\n            case ID_NOTIFICATIONS_NEWPROCESSES:\n                bit = PH_NOTIFY_PROCESS_CREATE;\n                break;\n            case ID_NOTIFICATIONS_TERMINATEDPROCESSES:\n                bit = PH_NOTIFY_PROCESS_DELETE;\n                break;\n            case ID_NOTIFICATIONS_NEWSERVICES:\n                bit = PH_NOTIFY_SERVICE_CREATE;\n                break;\n            case ID_NOTIFICATIONS_STARTEDSERVICES:\n                bit = PH_NOTIFY_SERVICE_START;\n                break;\n            case ID_NOTIFICATIONS_STOPPEDSERVICES:\n                bit = PH_NOTIFY_SERVICE_STOP;\n                break;\n            case ID_NOTIFICATIONS_DELETEDSERVICES:\n                bit = PH_NOTIFY_SERVICE_DELETE;\n                break;\n            case ID_NOTIFICATIONS_MODIFIEDSERVICES:\n                bit = PH_NOTIFY_SERVICE_MODIFIED;\n                break;\n            case ID_NOTIFICATIONS_ARRIVEDDEVICES:\n                bit = PH_NOTIFY_DEVICE_ARRIVED;\n                break;\n            case ID_NOTIFICATIONS_REMOVEDDEVICES:\n                bit = PH_NOTIFY_DEVICE_REMOVED;\n                break;\n            }\n\n            PhMwpNotifyIconNotifyMask ^= bit;\n            PhSetIntegerSetting(SETTING_ICON_NOTIFY_MASK, PhMwpNotifyIconNotifyMask);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Creates and returns a notification settings menu.\n * \\return A pointer to a PPH_EMENU structure representing the notification settings menu.\n */\nPPH_EMENU PhpCreateNotificationSettingsMenu(\n    VOID\n    )\n{\n    PPH_EMENU_ITEM menuItem;\n\n    menuItem = PhCreateEMenuItem(0, 0, L\"Settings\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_ENABLEDELAYSTART, L\"Enable initialization delay\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_ENABLEPERSISTLAYOUT, L\"Enable persistent layout\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_ENABLETRANSPARENTICONS, L\"Enable transparent icons\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_ENABLESINGLECLICKICONS, L\"Enable single click icons\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_NOTIFICATIONS_RESETPERSISTLAYOUT, L\"Reset persistent layout\", NULL, NULL), ULONG_MAX);\n\n    if (PhGetIntegerSetting(SETTING_ICON_TRAY_LAZY_START_DELAY))\n    {\n        PhSetFlagsEMenuItem(menuItem, ID_NOTIFICATIONS_ENABLEDELAYSTART, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n    }\n\n    if (PhGetIntegerSetting(SETTING_ICON_TRAY_PERSIST_GUID_ENABLED))\n    {\n        PhSetFlagsEMenuItem(menuItem, ID_NOTIFICATIONS_ENABLEPERSISTLAYOUT, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n    }\n\n    if (PhGetIntegerSetting(SETTING_ICON_TRANSPARENCY_ENABLED))\n    {\n        PhSetFlagsEMenuItem(menuItem, ID_NOTIFICATIONS_ENABLETRANSPARENTICONS, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n    }\n\n    if (PhGetIntegerSetting(SETTING_ICON_SINGLE_CLICK))\n    {\n        PhSetFlagsEMenuItem(menuItem, ID_NOTIFICATIONS_ENABLESINGLECLICKICONS, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n    }\n\n    return menuItem;\n}\n\n/**\n * Executes a command from the notification settings menu.\n *\n * \\param WindowHandle Handle to the window that receives the command.\n * \\param Id Identifier of the notification menu command to execute.\n * \\return TRUE if the command was executed successfully, FALSE otherwise.\n */\nBOOLEAN PhMwpExecuteNotificationSettingsMenuCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id\n    )\n{\n    switch (Id)\n    {\n    case ID_NOTIFICATIONS_RESETPERSISTLAYOUT:\n        {\n            EXTERN_C VOID PhNfLoadGuids(VOID);\n\n            PhSetStringSetting(SETTING_ICON_TRAY_GUIDS, L\"\");\n\n            PhNfLoadGuids();\n\n            PhShowOptionsRestartRequired(WindowHandle);\n        }\n        return TRUE;\n    case ID_NOTIFICATIONS_ENABLEDELAYSTART:\n        {\n            BOOLEAN lazyTrayIconStartDelayEnabled = !!PhGetIntegerSetting(SETTING_ICON_TRAY_LAZY_START_DELAY);\n\n            PhSetIntegerSetting(SETTING_ICON_TRAY_LAZY_START_DELAY, !lazyTrayIconStartDelayEnabled);\n\n            PhShowOptionsRestartRequired(WindowHandle);\n        }\n        return TRUE;\n    case ID_NOTIFICATIONS_ENABLEPERSISTLAYOUT:\n        {\n            BOOLEAN persistentTrayIconLayoutEnabled = !!PhGetIntegerSetting(SETTING_ICON_TRAY_PERSIST_GUID_ENABLED);\n\n            PhSetIntegerSetting(SETTING_ICON_TRAY_PERSIST_GUID_ENABLED, !persistentTrayIconLayoutEnabled);\n\n            PhShowOptionsRestartRequired(WindowHandle);\n        }\n        return TRUE;\n    case ID_NOTIFICATIONS_ENABLETRANSPARENTICONS:\n        {\n            BOOLEAN transparentTrayIconsEnabled = !!PhGetIntegerSetting(SETTING_ICON_TRANSPARENCY_ENABLED);\n\n            EXTERN_C BOOLEAN PhNfTransparencyEnabled;\n            PhNfTransparencyEnabled = !transparentTrayIconsEnabled;\n\n            PhSetIntegerSetting(SETTING_ICON_TRANSPARENCY_ENABLED, !transparentTrayIconsEnabled);\n\n            PhShowOptionsRestartRequired(WindowHandle);\n        }\n        return TRUE;\n    case ID_NOTIFICATIONS_ENABLESINGLECLICKICONS:\n        {\n            BOOLEAN singleClickTrayIconsEnabled = !!PhGetIntegerSetting(SETTING_ICON_SINGLE_CLICK);\n\n            PhSetIntegerSetting(SETTING_ICON_SINGLE_CLICK, !singleClickTrayIconsEnabled);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Creates and returns a pointer to an icon menu.\n * \\return Pointer to the created PPH_EMENU structure representing the icon menu.\n */\nPPH_EMENU PhpCreateIconMenu(\n    VOID\n    )\n{\n    PPH_EMENU menu;\n\n    menu = PhCreateEMenu();\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_ICON_SHOWHIDEPROCESSHACKER, L\"&Show/Hide System Informer\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_ICON_SYSTEMINFORMATION, L\"System &information\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhpCreateNotificationMenu(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhpCreateNotificationSettingsMenu(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESSES_DUMMY, L\"&Processes\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhpCreateComputerMenu(FALSE), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_ICON_EXIT, L\"E&xit\", NULL, NULL), ULONG_MAX);\n\n    return menu;\n}\n\n/**\n * Initializes a submenu in the main window.\n *\n * \\param WindowHandle Handle to the window that owns the menu.\n * \\param Menu Pointer to the menu structure to be initialized.\n * \\param Index Index specifying which submenu to initialize.\n */\nVOID PhMwpInitializeSubMenu(\n    _In_ HWND WindowHandle,\n    _In_ PPH_EMENU Menu,\n    _In_ ULONG Index\n    )\n{\n    PPH_EMENU_ITEM menuItem;\n\n    if (Index == PH_MENU_ITEM_LOCATION_SYSTEM)\n    {\n        if (WindowsVersion < WINDOWS_10)\n        {\n            if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_RUNASPACKAGE))\n                PhDestroyEMenuItem(menuItem);\n        }\n\n        if (PhGetOwnTokenAttributes().Elevated)\n        {\n            if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_RUNASADMINISTRATOR))\n                PhDestroyEMenuItem(menuItem);\n            if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_SHOWDETAILSFORALLPROCESSES))\n                PhDestroyEMenuItem(menuItem);\n        }\n        else\n        {\n            if (PhGetIntegerSetting(SETTING_ENABLE_BITMAP_SUPPORT))\n            {\n                HBITMAP shieldBitmap;\n\n                if (shieldBitmap = PhGetShieldBitmap(LayoutWindowDpi, PhSmallIconSize.X, PhSmallIconSize.Y))\n                {\n                    if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_SHOWDETAILSFORALLPROCESSES))\n                        menuItem->Bitmap = shieldBitmap;\n                }\n            }\n        }\n\n        PhMwpSetupComputerMenu(Menu);\n    }\n    else if (Index == PH_MENU_ITEM_LOCATION_VIEW)\n    {\n        PPH_EMENU_ITEM trayIconsMenuItem;\n        ULONG id = ULONG_MAX;\n        ULONG placeholderIndex = ULONG_MAX;\n\n        if (trayIconsMenuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, ID_VIEW_TRAYICONS))\n        {\n            // Add menu items for the registered tray icons.\n\n            PhInsertEMenuItem(trayIconsMenuItem, PhpCreateNotificationMenu(), ULONG_MAX);\n            PhInsertEMenuItem(trayIconsMenuItem, PhpCreateNotificationSettingsMenu(), ULONG_MAX);\n            PhInsertEMenuItem(trayIconsMenuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n\n            for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n            {\n                PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n                menuItem = PhCreateEMenuItem(0, ID_TRAYICONS_REGISTERED, icon->Text, NULL, icon);\n                PhInsertEMenuItem(trayIconsMenuItem, menuItem, ULONG_MAX);\n\n                // Update the text and check marks on the menu items.\n\n                if (icon->Flags & PH_NF_ICON_ENABLED)\n                {\n                    menuItem->Flags |= PH_EMENU_CHECKED;\n                }\n\n                if (icon->Flags & PH_NF_ICON_UNAVAILABLE)\n                {\n                    PPH_STRING newText;\n\n                    newText = PhaConcatStrings2(icon->Text, L\" (Unavailable)\");\n                    PhModifyEMenuItem(menuItem, PH_EMENU_MODIFY_TEXT, PH_EMENU_TEXT_OWNED,\n                        PhAllocateCopy(newText->Buffer, newText->Length + sizeof(WCHAR)), NULL);\n                }\n            }\n        }\n\n        if (menuItem = PhFindEMenuItemEx(Menu, 0, NULL, ID_VIEW_SECTIONPLACEHOLDER, NULL, &placeholderIndex))\n        {\n            PhDestroyEMenuItem(menuItem);\n            PhMwpInitializeSectionMenuItems(Menu, placeholderIndex);\n        }\n\n        if (AlwaysOnTop && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_ALWAYSONTOP)))\n            menuItem->Flags |= PH_EMENU_CHECKED;\n\n        id = PH_OPACITY_TO_ID(PhGetIntegerSetting(SETTING_MAIN_WINDOW_OPACITY));\n\n        if (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id))\n            menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK;\n\n        switch (PhGetIntegerSetting(SETTING_UPDATE_INTERVAL))\n        {\n        case 500:\n            id = ID_UPDATEINTERVAL_FAST;\n            break;\n        case 1000:\n            id = ID_UPDATEINTERVAL_NORMAL;\n            break;\n        case 2000:\n            id = ID_UPDATEINTERVAL_BELOWNORMAL;\n            break;\n        case 5000:\n            id = ID_UPDATEINTERVAL_SLOW;\n            break;\n        case 10000:\n            id = ID_UPDATEINTERVAL_VERYSLOW;\n            break;\n        default:\n            id = ULONG_MAX;\n            break;\n        }\n\n        if (id != ULONG_MAX && (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id)))\n            menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK;\n\n        if (PhMwpUpdateAutomatically && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_UPDATEAUTOMATICALLY)))\n            menuItem->Flags |= PH_EMENU_CHECKED;\n    }\n    else if (Index == PH_MENU_ITEM_LOCATION_TOOLS)\n    {\n        if (WindowsVersion < WINDOWS_8_1)\n        {\n            if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_LIVEDUMP))\n                PhDestroyEMenuItem(menuItem);\n        }\n\n        if (PhGetIntegerSetting(SETTING_ENABLE_BITMAP_SUPPORT))\n        {\n            HBITMAP shieldBitmap;\n\n            if (shieldBitmap = PhGetShieldBitmap(LayoutWindowDpi, PhSmallIconSize.X, PhSmallIconSize.Y))\n            {\n                if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_STARTTASKMANAGER))\n                    menuItem->Bitmap = shieldBitmap;\n                if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_STARTRESOURCEMONITOR))\n                    menuItem->Bitmap = shieldBitmap;\n            }\n        }\n    }\n}\n\n/**\n * Initializes section-related menu items in the specified menu.\n *\n * \\param Menu Pointer to the menu structure where section items will be added.\n * \\param StartIndex The starting index in the menu where section items should be inserted.\n */\nVOID PhMwpInitializeSectionMenuItems(\n    _In_ PPH_EMENU Menu,\n    _In_ ULONG StartIndex\n    )\n{\n    BOOLEAN removeSeparator = TRUE;\n    PH_MAIN_TAB_PAGE_MENU_INFORMATION menuInfo;\n\n    menuInfo.Menu = Menu;\n    menuInfo.StartIndex = StartIndex;\n\n    for (ULONG i = PageList->Count; i > 0; i--)\n    {\n        PPH_MAIN_TAB_PAGE page = PageList->Items[i - 1];\n\n        if (page->Callback(CurrentPage, MainTabPageInitializeSectionMenuItems, &menuInfo, NULL))\n            removeSeparator = FALSE;\n    }\n\n    if (removeSeparator)\n        PhRemoveEMenuItem(Menu, NULL, StartIndex);\n}\n\n/**\n * Adjusts the layout of the tab control in the main window by updating the deferred window positioning handle.\n * \\param DeferHandle Pointer to a handle used for deferred window positioning (HDWP).\n */\nVOID PhMwpLayoutTabControl(\n    _Inout_ HDWP *DeferHandle\n    )\n{\n    RECT clientRect;\n    RECT tabRect;\n\n    if (!LayoutPaddingValid)\n    {\n        PhMwpUpdateLayoutPadding();\n        LayoutPaddingValid = TRUE;\n    }\n\n    if (!PhGetClientRect(PhMainWndHandle, &clientRect))\n        return;\n\n    PhMwpApplyLayoutPadding(&clientRect, &LayoutPadding);\n    tabRect = clientRect;\n    TabCtrl_AdjustRect(TabControlHandle, FALSE, &tabRect);\n\n    if (CurrentPage && CurrentPage->WindowHandle)\n    {\n        // Remove the tabctrl padding (dmex)\n        *DeferHandle = DeferWindowPos(\n            *DeferHandle,\n            CurrentPage->WindowHandle,\n            HWND_TOP,\n            clientRect.left,\n            tabRect.top - LayoutBorderSize,\n            clientRect.right - clientRect.left,\n            (tabRect.bottom - tabRect.top) + (clientRect.bottom - tabRect.bottom),\n            SWP_NOACTIVATE | SWP_NOZORDER\n            );\n    }\n}\n\n/**\n * Handles notifications from a tab control.\n * \\param Header Pointer to an NMHDR structure containing information about the notification.\n */\nVOID PhMwpNotifyTabControl(\n    _In_ NMHDR *Header\n    )\n{\n    if (Header->code == TCN_SELCHANGING)\n    {\n        OldTabIndex = TabCtrl_GetCurSel(TabControlHandle);\n    }\n    else if (Header->code == TCN_SELCHANGE)\n    {\n        PhMwpSelectionChangedTabControl(OldTabIndex);\n    }\n}\n\n/**\n * Called when the selection in a tab control has changed.\n * \\param OldIndex The index of the previously selected tab.\n */\nVOID PhMwpSelectionChangedTabControl(\n    _In_ LONG OldIndex\n    )\n{\n    LONG selectedIndex;\n    HDWP deferHandle;\n    ULONG i;\n\n    selectedIndex = TabCtrl_GetCurSel(TabControlHandle);\n\n    if (selectedIndex == OldIndex)\n        return;\n\n    deferHandle = BeginDeferWindowPos(3);\n\n    for (i = 0; i < PageList->Count; i++)\n    {\n        PPH_MAIN_TAB_PAGE page = PageList->Items[i];\n\n        page->Selected = page->Index == selectedIndex;\n\n        if (page->Index == selectedIndex)\n        {\n            CurrentPage = page;\n\n            // Create the tab page window if it doesn't exist. (wj32)\n            if (!page->WindowHandle && !page->CreateWindowCalled)\n            {\n                if (page->Callback(page, MainTabPageCreateWindow, &page->WindowHandle, PhMainWndHandle))\n                    page->CreateWindowCalled = TRUE;\n\n                if (page->WindowHandle)\n                    BringWindowToTop(page->WindowHandle);\n                if (PhTreeWindowFont)\n                    page->Callback(page, MainTabPageFontChanged, PhTreeWindowFont, NULL);\n            }\n\n            page->Callback(page, MainTabPageSelected, UlongToPtr(TRUE), NULL);\n\n            if (page->WindowHandle)\n            {\n                deferHandle = DeferWindowPos(deferHandle, page->WindowHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY);\n                SetFocus(page->WindowHandle);\n            }\n        }\n        else if (page->Index == OldIndex)\n        {\n            page->Callback(page, MainTabPageSelected, UlongToPtr(FALSE), NULL);\n\n            if (page->WindowHandle)\n            {\n                deferHandle = DeferWindowPos(deferHandle, page->WindowHandle, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY);\n            }\n        }\n    }\n\n    PhMwpLayoutTabControl(&deferHandle);\n\n    EndDeferWindowPos(deferHandle);\n\n    if (OldIndex != INT_ERROR && PhGetIntegerSetting(SETTING_MAIN_WINDOW_TAB_RESTORE_ENABLED) && IsWindowVisible(TabControlHandle))\n    {\n        PhSetIntegerSetting(SETTING_MAIN_WINDOW_TAB_RESTORE_INDEX, selectedIndex);\n    }\n\n    if (PhPluginsEnabled)\n    {\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainWindowTabChanged), LongToPtr(selectedIndex));\n    }\n}\n\n/**\n * Creates a new main tab page based on the specified template.\n *\n * \\param Template Pointer to a PPH_MAIN_TAB_PAGE structure that serves as the template for the new page.\n * \\return Pointer to the newly created PPH_MAIN_TAB_PAGE structure.\n */\nPPH_MAIN_TAB_PAGE PhMwpCreatePage(\n    _In_ PPH_MAIN_TAB_PAGE Template\n    )\n{\n    PPH_MAIN_TAB_PAGE page;\n    PPH_STRING name;\n    //HDWP deferHandle;\n\n    page = PhAllocateZero(sizeof(PH_MAIN_TAB_PAGE));\n    page->Name = Template->Name;\n    page->Flags = Template->Flags;\n    page->Callback = Template->Callback;\n    page->Context = Template->Context;\n\n    PhAddItemList(PageList, page);\n\n    name = PhCreateString2(&page->Name);\n    page->Index = PhAddTabControlTab(TabControlHandle, MAXINT, name->Buffer);\n    PhDereferenceObject(name);\n\n    page->Callback(page, MainTabPageCreate, NULL, NULL);\n\n    // The tab control might need multiple lines, so we need to refresh the layout.\n    //deferHandle = BeginDeferWindowPos(1);\n    //PhMwpLayoutTabControl(&deferHandle);\n    //EndDeferWindowPos(deferHandle);\n\n    return page;\n}\n\n/**\n * Selects a page in the main window by its index.\n * \\param Index The zero-based index of the page to select.\n */\nVOID PhMwpSelectPage(\n    _In_ ULONG Index\n    )\n{\n    LONG oldIndex;\n\n    oldIndex = TabCtrl_GetCurSel(TabControlHandle);\n    TabCtrl_SetCurSel(TabControlHandle, Index);\n    PhMwpSelectionChangedTabControl(oldIndex);\n}\n\n/**\n * Finds a main tab page by its name.\n *\n * \\param Name A pointer to a PPH_STRINGREF structure containing the name of the page to find.\n * \\return A pointer to the PPH_MAIN_TAB_PAGE structure if found, otherwise NULL.\n */\nPPH_MAIN_TAB_PAGE PhMwpFindPage(\n    _In_ PPH_STRINGREF Name\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < PageList->Count; i++)\n    {\n        PPH_MAIN_TAB_PAGE page = PageList->Items[i];\n\n        if (PhEqualStringRef(&page->Name, Name, TRUE))\n            return page;\n    }\n\n    return NULL;\n}\n\n/**\n * Creates an internal main tab page.\n *\n * \\param Name The name of the tab page.\n * \\param Flags Flags that specify options for the tab page.\n * \\param Callback Pointer to a callback function for the tab page.\n * \\return A pointer to the newly created PPH_MAIN_TAB_PAGE structure, or NULL on failure.\n */\nPPH_MAIN_TAB_PAGE PhMwpCreateInternalPage(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_MAIN_TAB_PAGE_CALLBACK Callback\n    )\n{\n    PH_MAIN_TAB_PAGE page;\n\n    memset(&page, 0, sizeof(PH_MAIN_TAB_PAGE));\n    PhInitializeStringRefLongHint(&page.Name, Name);\n    page.Flags = Flags;\n    page.Callback = Callback;\n\n    return PhMwpCreatePage(&page);\n}\n\n/**\n * Notifies all main tab pages of a specified message.\n *\n * \\param Message The message to send to all main tab pages.\n * \\param Parameter1 Optional parameter to pass with the message.\n * \\param Parameter2 Optional parameter to pass with the message.\n */\nVOID PhMwpNotifyAllPages(\n    _In_ PH_MAIN_TAB_PAGE_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    )\n{\n    ULONG i;\n    PPH_MAIN_TAB_PAGE page;\n\n    if (PageList)\n    {\n        for (i = 0; i < PageList->Count; i++)\n        {\n            page = PageList->Items[i];\n            page->Callback(page, Message, Parameter1, Parameter2);\n        }\n    }\n}\n\n/**\n * Comparison routine that orders processes by CPU usage (descending).\n *\n * \\param elem1 Pointer to the first element (pointer to PPH_PROCESS_ITEM).\n * \\param elem2 Pointer to the second element (pointer to PPH_PROCESS_ITEM).\n * \\return Negative, zero, or positive value for qsort-style comparison.\n */\nstatic int __cdecl IconProcessesCpuUsageCompare(\n    _In_ void const* elem1,\n    _In_ void const* elem2\n    )\n{\n    PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1;\n    PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2;\n\n    return -singlecmp(processItem1->CpuUsage, processItem2->CpuUsage);\n}\n\n/**\n * Comparison routine that orders processes by their (case-insensitive) name.\n *\n * \\param elem1 Pointer to the first element (pointer to PPH_PROCESS_ITEM).\n * \\param elem2 Pointer to the second element (pointer to PPH_PROCESS_ITEM).\n * \\return Negative, zero, or positive value for qsort-style comparison.\n */\nstatic int __cdecl IconProcessesNameCompare(\n    _In_ void const* elem1,\n    _In_ void const* elem2\n    )\n{\n    PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1;\n    PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2;\n\n    return PhCompareString(processItem1->ProcessName, processItem2->ProcessName, TRUE);\n}\n\n/**\n * Adds the mini-process submenu items (priority, I/O priority, actions) for a process.\n *\n * \\param Menu The parent EMENU item to which process items will be appended.\n * \\param ProcessId The process identifier for which menu entries are created.\n */\nVOID PhAddMiniProcessMenuItems(\n    _Inout_ PPH_EMENU_ITEM Menu,\n    _In_ HANDLE ProcessId\n    )\n{\n    PPH_EMENU_ITEM priorityMenu;\n    PPH_EMENU_ITEM ioPriorityMenu = NULL;\n    PPH_PROCESS_ITEM processItem;\n    BOOLEAN isSuspended = FALSE;\n    BOOLEAN isPartiallySuspended = TRUE;\n\n    // Priority\n\n    priorityMenu = PhCreateEMenuItem(0, ID_PROCESS_PRIORITYCLASS, L\"&Priority class\", NULL, ProcessId);\n\n    PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L\"&Real time\", NULL, ProcessId), ULONG_MAX);\n    PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L\"&High\", NULL, ProcessId), ULONG_MAX);\n    PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L\"&Above normal\", NULL, ProcessId), ULONG_MAX);\n    PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L\"&Normal\", NULL, ProcessId), ULONG_MAX);\n    PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L\"&Below normal\", NULL, ProcessId), ULONG_MAX);\n    PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L\"&Idle\", NULL, ProcessId), ULONG_MAX);\n\n    // I/O priority\n\n    ioPriorityMenu = PhCreateEMenuItem(0, ID_PROCESS_IOPRIORITY, L\"&I/O priority\", NULL, ProcessId);\n\n    PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L\"&High\", NULL, ProcessId), ULONG_MAX);\n    PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L\"&Normal\", NULL, ProcessId), ULONG_MAX);\n    PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L\"&Low\", NULL, ProcessId), ULONG_MAX);\n    PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L\"&Very low\", NULL, ProcessId), ULONG_MAX);\n\n    // Menu\n\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATE, L\"T&erminate\", NULL, ProcessId), ULONG_MAX);\n\n    if (processItem = PhReferenceProcessItem(ProcessId))\n    {\n        isSuspended = (BOOLEAN)processItem->IsSuspended;\n        isPartiallySuspended = (BOOLEAN)processItem->IsPartiallySuspended;\n        PhDereferenceObject(processItem);\n    }\n\n    if (!isSuspended)\n        PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPEND, L\"&Suspend\", NULL, ProcessId), ULONG_MAX);\n    if (isSuspended || isPartiallySuspended)\n        PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_RESUME, L\"Res&ume\", NULL, ProcessId), ULONG_MAX);\n\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_RESTART, L\"Res&tart\", NULL, ProcessId), ULONG_MAX);\n\n    PhInsertEMenuItem(Menu, priorityMenu, ULONG_MAX);\n\n    if (ioPriorityMenu)\n        PhInsertEMenuItem(Menu, ioPriorityMenu, ULONG_MAX);\n\n    PhMwpSetProcessMenuPriorityChecks(Menu, ProcessId, TRUE, TRUE, FALSE);\n\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_PROPERTIES, L\"P&roperties\", NULL, ProcessId), ULONG_MAX);\n}\n\n/**\n * Handles a menu item event for the mini-info-window.\n *\n * \\param MenuItem Pointer to a PH_EMENU_ITEM structure representing the selected menu item.\n * \\return Returns TRUE if the menu item was handled successfully, otherwise FALSE.\n */\nBOOLEAN PhHandleMiniProcessMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem\n    )\n{\n    switch (MenuItem->Id)\n    {\n    case ID_PROCESS_TERMINATE:\n    case ID_PROCESS_SUSPEND:\n    case ID_PROCESS_RESUME:\n    case ID_PROCESS_RESTART:\n    case ID_PROCESS_PROPERTIES:\n        {\n            HANDLE processId = MenuItem->Context;\n            PPH_PROCESS_ITEM processItem;\n\n            if (processItem = PhReferenceProcessItem(processId))\n            {\n                switch (MenuItem->Id)\n                {\n                case ID_PROCESS_TERMINATE:\n                    PhUiTerminateProcesses(PhMainWndHandle, &processItem, 1);\n                    break;\n                case ID_PROCESS_SUSPEND:\n                    PhUiSuspendProcesses(PhMainWndHandle, &processItem, 1);\n                    break;\n                case ID_PROCESS_RESUME:\n                    PhUiResumeProcesses(PhMainWndHandle, &processItem, 1);\n                    break;\n                case ID_PROCESS_RESTART:\n                    PhUiRestartProcess(PhMainWndHandle, processItem);\n                    break;\n                case ID_PROCESS_PROPERTIES:\n                    SystemInformer_ShowProcessProperties(processItem);\n                    break;\n                }\n\n                PhDereferenceObject(processItem);\n            }\n            else\n            {\n                PhShowStatus(PhMainWndHandle, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n            }\n        }\n        break;\n    case ID_PRIORITY_REALTIME:\n    case ID_PRIORITY_HIGH:\n    case ID_PRIORITY_ABOVENORMAL:\n    case ID_PRIORITY_NORMAL:\n    case ID_PRIORITY_BELOWNORMAL:\n    case ID_PRIORITY_IDLE:\n        {\n            HANDLE processId = MenuItem->Context;\n            PPH_PROCESS_ITEM processItem;\n\n            if (processItem = PhReferenceProcessItem(processId))\n            {\n                PhMwpExecuteProcessPriorityClassCommand(PhMainWndHandle, MenuItem->Id, &processItem, 1);\n                PhDereferenceObject(processItem);\n            }\n            else\n            {\n                PhShowStatus(PhMainWndHandle, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n            }\n        }\n        break;\n    case ID_IOPRIORITY_HIGH:\n    case ID_IOPRIORITY_NORMAL:\n    case ID_IOPRIORITY_LOW:\n    case ID_IOPRIORITY_VERYLOW:\n        {\n            HANDLE processId = MenuItem->Context;\n            PPH_PROCESS_ITEM processItem;\n\n            if (processItem = PhReferenceProcessItem(processId))\n            {\n                PhMwpExecuteProcessIoPriorityCommand(PhMainWndHandle, MenuItem->Id, &processItem, 1);\n                PhDereferenceObject(processItem);\n            }\n            else\n            {\n                PhShowStatus(PhMainWndHandle, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n * Adds a specified number of icon processes to the given menu.\n *\n * \\param Menu Pointer to the menu item where icon processes will be added.\n * \\param NumberOfProcesses The number of icon processes to add.\n */\nVOID PhMwpAddIconProcesses(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    ULONG i;\n    PPH_PROCESS_ITEM *processItems;\n    ULONG numberOfProcessItems;\n    PPH_LIST processList;\n    PPH_PROCESS_ITEM processItem;\n\n    PhEnumProcessItems(&processItems, &numberOfProcessItems);\n    processList = PhCreateList(numberOfProcessItems);\n    PhAddItemsList(processList, processItems, numberOfProcessItems);\n\n    // Remove non-real processes.\n    for (i = 0; i < processList->Count; i++)\n    {\n        processItem = processList->Items[i];\n\n        if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId))\n        {\n            PhRemoveItemList(processList, i);\n            i--;\n        }\n    }\n\n    // Remove processes with zero CPU usage and those running as other users.\n    for (i = 0; i < processList->Count && processList->Count > NumberOfProcesses; i++)\n    {\n        processItem = processList->Items[i];\n\n        if (\n            processItem->CpuUsage == 0 ||\n            (processItem->Sid && !PhEqualSid(processItem->Sid, PhGetOwnTokenAttributes().TokenSid))\n            )\n        {\n            PhRemoveItemList(processList, i);\n            i--;\n        }\n    }\n\n    // Sort the processes by CPU usage and remove the extra processes at the end of the list.\n    qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesCpuUsageCompare);\n\n    if (processList->Count > NumberOfProcesses)\n    {\n        PhRemoveItemsList(processList, NumberOfProcesses, processList->Count - NumberOfProcesses);\n    }\n\n    // Lastly, sort by name.\n    qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesNameCompare);\n\n    // Delete all menu items.\n    PhRemoveAllEMenuItems(Menu);\n\n    // Add the processes.\n\n    for (i = 0; i < processList->Count; i++)\n    {\n        PPH_EMENU_ITEM subMenu;\n        HBITMAP iconBitmap = NULL;\n        CLIENT_ID clientId;\n        PPH_STRING clientIdName;\n        PPH_STRING escapedName;\n        HICON icon;\n\n        processItem = processList->Items[i];\n\n        // Process\n\n        clientId.UniqueProcess = processItem->ProcessId;\n        clientId.UniqueThread = NULL;\n\n        clientIdName = PH_AUTO(PhGetClientIdName(&clientId));\n        escapedName = PH_AUTO(PhEscapeStringForMenuPrefix(&clientIdName->sr));\n\n        subMenu = PhCreateEMenuItem(\n            0,\n            0,\n            escapedName->Buffer,\n            NULL,\n            processItem->ProcessId\n            );\n\n        if (icon = PhGetImageListIcon(processItem->SmallIconIndex, FALSE))\n        {\n            iconBitmap = PhIconToBitmap(icon, PhSmallIconSize.X, PhSmallIconSize.Y);\n            DestroyIcon(icon);\n        }\n\n        subMenu->Bitmap = iconBitmap;\n        subMenu->Flags |= PH_EMENU_BITMAP_OWNED; // automatically destroy the bitmap when necessary\n\n        PhAddMiniProcessMenuItems(subMenu, processItem->ProcessId);\n        PhInsertEMenuItem(Menu, subMenu, ULONG_MAX);\n    }\n\n    PhDereferenceObject(processList);\n    PhDereferenceObjects(processItems, numberOfProcessItems);\n    PhFree(processItems);\n}\n\n/**\n * Displays the context menu for the application's icon at the specified location.\n *\n * \\param WindowHandle Handle to the window that owns the icon.\n * \\param Location Screen coordinates where the context menu should appear.\n */\nVOID PhShowIconContextMenu(\n    _In_ HWND WindowHandle,\n    _In_ PPOINT Location\n    )\n{\n    PPH_EMENU menu;\n    PPH_EMENU_ITEM item;\n    PH_PLUGIN_MENU_INFORMATION menuInfo;\n    ULONG numberOfProcesses;\n\n    // This function seems to be called recursively under some circumstances.\n    // To reproduce:\n    // 1. Hold right mouse button on tray icon, then left click.\n    // 2. Make the menu disappear by clicking on the menu then clicking somewhere else.\n    // So, don't store any global state or bad things will happen.\n\n    menu = PhpCreateIconMenu();\n\n    // Add processes to the menu.\n\n    numberOfProcesses = PhGetIntegerSetting(SETTING_ICON_PROCESSES);\n    item = PhFindEMenuItem(menu, 0, 0, ID_PROCESSES_DUMMY);\n\n    if (item)\n        PhMwpAddIconProcesses(item, numberOfProcesses);\n\n    // Fix up the Computer menu.\n    PhMwpSetupComputerMenu(menu);\n\n    // Give plugins a chance to modify the menu.\n\n    if (PhPluginsEnabled)\n    {\n        PhPluginInitializeMenuInfo(&menuInfo, menu, WindowHandle, 0);\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackIconMenuInitializing), &menuInfo);\n    }\n\n    SetForegroundWindow(WindowHandle); // window must be foregrounded so menu will disappear properly (wj32)\n    item = PhShowEMenu(\n        menu,\n        WindowHandle,\n        PH_EMENU_SHOW_LEFTRIGHT,\n        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n        Location->x,\n        Location->y\n        );\n\n    if (item)\n    {\n        BOOLEAN handled = FALSE;\n\n        if (PhPluginsEnabled && !handled)\n            handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n        if (!handled)\n            handled = PhHandleMiniProcessMenuItem(item);\n\n        if (!handled)\n            handled = PhMwpExecuteComputerCommand(WindowHandle, item->Id);\n\n        if (!handled)\n            handled = PhMwpExecuteNotificationMenuCommand(WindowHandle, item->Id);\n\n        if (!handled)\n            handled = PhMwpExecuteNotificationSettingsMenuCommand(WindowHandle, item->Id);\n\n        if (!handled)\n        {\n            switch (item->Id)\n            {\n            case ID_ICON_SHOWHIDEPROCESSHACKER:\n                SystemInformer_ToggleVisible(FALSE);\n                break;\n            case ID_ICON_SYSTEMINFORMATION:\n                SendMessage(WindowHandle, WM_COMMAND, ID_VIEW_SYSTEMINFORMATION, 0);\n                break;\n            case ID_ICON_EXIT:\n                SendMessage(WindowHandle, WM_COMMAND, ID_HACKER_EXIT, 0);\n                break;\n            }\n        }\n    }\n\n    PhDestroyEMenu(menu);\n}\n\n/**\n * Displays a simple notification balloon from the tray icon.\n *\n * \\param Title The title text of the notification.\n * \\param Text The body text of the notification.\n */\nVOID PhShowIconNotification(\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Text\n    )\n{\n    PhNfShowBalloonTip(Title, Text, 10);\n}\n\n/**\n * Displays an extended notification from the tray icon with callback support.\n *\n * \\param Title The title text of the notification.\n * \\param Text The body text of the notification.\n * \\param Timeout Duration (seconds) before the notification is dismissed.\n * \\param Callback Optional callback invoked when the notification is dismissed.\n * \\param Context Context pointer passed to the callback.\n * \\return HRESULT result code.\n */\nHRESULT PhShowIconNotificationEx(\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Text,\n    _In_ ULONG Timeout,\n    _In_opt_ PPH_TOAST_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    return PhNfShowBalloonTipEx(Title, Text, Timeout, Callback, Context);\n}\n\n/**\n * Shows detailed information related to the last tray icon notification.\n *\n * This function inspects the last notification type and opens the appropriate\n * UI (process/service) to display details.\n */\nVOID PhShowDetailsForIconNotification(\n    VOID\n    )\n{\n    switch (PhMwpLastNotificationType)\n    {\n    case PH_NOTIFY_PROCESS_CREATE:\n        {\n            PPH_PROCESS_NODE processNode;\n\n            if (processNode = PhFindProcessNode(PhMwpLastNotificationDetails.ProcessId))\n            {\n                SystemInformer_SelectTabPage(PhMwpProcessesPage->Index);\n                SystemInformer_SelectProcessNode(processNode);\n                SystemInformer_ToggleVisible(TRUE);\n            }\n            else\n            {\n                PhShowStatus(PhMainWndHandle, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n            }\n        }\n        break;\n    case PH_NOTIFY_SERVICE_CREATE:\n    case PH_NOTIFY_SERVICE_START:\n    case PH_NOTIFY_SERVICE_STOP:\n        {\n            PPH_SERVICE_ITEM serviceItem;\n\n            if (PhMwpLastNotificationDetails.ServiceName &&\n                (serviceItem = PhReferenceServiceItem(&PhMwpLastNotificationDetails.ServiceName->sr)))\n            {\n                SystemInformer_SelectTabPage(PhMwpServicesPage->Index);\n                SystemInformer_SelectServiceItem(serviceItem);\n                SystemInformer_ToggleVisible(TRUE);\n\n                PhDereferenceObject(serviceItem);\n            }\n            else\n            {\n                PhShowStatus(PhMainWndHandle, L\"The service does not exist.\", STATUS_INVALID_CID, 0);\n            }\n        }\n        break;\n    }\n}\n\n/**\n * Clears stored information about the last tray icon notification.\n *\n * Frees any referenced strings and resets the notification type/state.\n */\nVOID PhMwpClearLastNotificationDetails(\n    VOID\n    )\n{\n    switch (PhMwpLastNotificationType)\n    {\n    case PH_NOTIFY_SERVICE_CREATE:\n    case PH_NOTIFY_SERVICE_START:\n    case PH_NOTIFY_SERVICE_STOP:\n        PhClearReference(&PhMwpLastNotificationDetails.ServiceName);\n        break;\n    }\n\n    PhMwpLastNotificationType = 0;\n    memset(&PhMwpLastNotificationDetails, 0, sizeof(PhMwpLastNotificationDetails));\n}\n\n// Window plugin extensions (dmex)\n\n/**\n * Invokes the memory editor dialog from a worker or plugin context.\n *\n * \\param Parameter Pointer to a PPH_SHOW_MEMORY_EDITOR structure (ownership transferred).\n */\nVOID PhMwpInvokeShowMemoryEditorDialog(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_SHOW_MEMORY_EDITOR showMemoryEditor = (PPH_SHOW_MEMORY_EDITOR)Parameter;\n\n    PhShowMemoryEditorDialog(\n        showMemoryEditor->OwnerWindow,\n        showMemoryEditor->ProcessId,\n        showMemoryEditor->BaseAddress,\n        showMemoryEditor->RegionSize,\n        showMemoryEditor->SelectOffset,\n        showMemoryEditor->SelectLength,\n        showMemoryEditor->Title,\n        showMemoryEditor->Flags\n        );\n    PhClearReference(&showMemoryEditor->Title);\n    PhFree(showMemoryEditor);\n}\n\n/**\n * Invokes the memory results dialog from a worker or plugin context.\n *\n * \\param Parameter Pointer to a PPH_SHOW_MEMORY_RESULTS structure (ownership transferred).\n */\nVOID PhMwpInvokeShowMemoryResultsDialog(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_SHOW_MEMORY_RESULTS showMemoryResults = (PPH_SHOW_MEMORY_RESULTS)Parameter;\n\n    PhShowMemoryResultsDialog(\n        showMemoryResults->ProcessId,\n        showMemoryResults->Results\n        );\n    PhDereferenceMemoryResults(\n        (PPH_MEMORY_RESULT*)showMemoryResults->Results->Items,\n        showMemoryResults->Results->Count\n        );\n    PhDereferenceObject(showMemoryResults->Results);\n    PhFree(showMemoryResults);\n}\n\n/**\n * Updates the main window font based on saved settings and applies it to controls.\n *\n * \\param Parameter Optional parameter (unused).\n */\nVOID PhMwpInvokeUpdateWindowFont(\n    _In_opt_ PVOID Parameter\n    )\n{\n    HFONT oldFont = PhTreeWindowFont;\n    HFONT newFont;\n    PPH_STRING fontHexString;\n    LOGFONT font;\n\n    fontHexString = PhaGetStringSetting(SETTING_FONT);\n\n    if (\n        fontHexString->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT) &&\n        PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)&font)\n        )\n    {\n        if (!(newFont = CreateFontIndirect(&font)))\n            return;\n    }\n    else\n    {\n        if (!(newFont = PhCreateIconTitleFont(LayoutWindowDpi)))\n            return;\n    }\n\n    PhTreeWindowFont = newFont;\n    SetWindowFont(TabControlHandle, PhTreeWindowFont, TRUE);\n    PhMwpNotifyAllPages(MainTabPageFontChanged, newFont, NULL);\n\n    if (oldFont) DeleteFont(oldFont);\n}\n\n/**\n * Updates the monospace font used by the UI, based on saved settings.\n *\n * \\param WindowHandle Optional window handle associated with the update (unused in most callers).\n * \\param Parameter Optional parameter (unused).\n */\nVOID PhMwpInvokeUpdateWindowFontMonospace(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID Parameter\n    )\n{\n    HFONT oldFont = PhMonospaceFont;\n    HFONT newFont;\n    PPH_STRING fontHexString;\n    LOGFONT font;\n\n    fontHexString = PhaGetStringSetting(SETTING_FONT_MONOSPACE);\n\n    if (\n        fontHexString->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT) &&\n        PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)&font)\n        )\n    {\n        if (!(newFont = CreateFontIndirect(&font)))\n            return;\n    }\n    else\n    {\n        PhMonospaceFont = PhInitializeMonospaceFont(LayoutWindowDpi);\n        if (oldFont) DeleteFont(oldFont);\n        return;\n    }\n\n    PhMonospaceFont = newFont;\n    if (oldFont) DeleteFont(oldFont);\n}\n\n/**\n * Prepares the application for an early exit by saving settings and marking state.\n *\n * \\param WindowHandle The main window handle used when saving state.\n */\nVOID PhMwpInvokePrepareEarlyExit(\n    _In_ HWND WindowHandle\n    )\n{\n    PhMwpSaveSettings(WindowHandle);\n    PhMainWndEarlyExit = TRUE;\n}\n\n/**\n * Invokes activation (or toggling) of the main window.\n *\n * \\param Toggle If TRUE, toggle visibility when appropriate; otherwise ensure window is active.\n */\nVOID PhMwpInvokeActivateWindow(\n    _In_ BOOLEAN Toggle\n    )\n{\n    PhMwpActivateWindow(PhMainWndHandle, Toggle);\n}\n\n/**\n * Invokes selection of a main tab page on the UI thread.\n *\n * \\param Parameter Tab index encoded as ULONG via PtrToUlong.\n */\nVOID PhMwpInvokeSelectTabPage(\n    _In_ PVOID Parameter\n    )\n{\n    ULONG index = PtrToUlong(Parameter);\n\n    PhMwpSelectPage(index);\n\n    if (CurrentPage->WindowHandle)\n        SetFocus(CurrentPage->WindowHandle);\n}\n\n/**\n * Invokes selection of a service item in the services list (posted to main thread).\n *\n * \\param ServiceItem Pointer to the service item to select.\n */\nVOID PhMwpInvokeSelectServiceItem(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    PPH_SERVICE_NODE serviceNode;\n\n    PhMwpNeedServiceTreeList();\n\n    // For compatibility, LParam is a service item, not node.\n    if (serviceNode = PhFindServiceNode(ServiceItem))\n    {\n        PhSelectAndEnsureVisibleServiceNode(serviceNode);\n    }\n}\n\n/**\n * Invokes selection of a network item in the network list (posted to main thread).\n *\n * \\param NetworkItem Pointer to the network item to select.\n */\nVOID PhMwpInvokeSelectNetworkItem(\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    )\n{\n    PPH_NETWORK_NODE networkNode;\n\n    PhMwpNeedNetworkTreeList();\n\n    // For compatibility, LParam is a network item, not node.\n    if (networkNode = PhFindNetworkNode(NetworkItem))\n    {\n        PhSelectAndEnsureVisibleNetworkNode(networkNode);\n    }\n}\n\n/**\n * Sends a plugin notification event to registered plugin callbacks.\n *\n * \\param Type Notification event type.\n * \\param Parameter Additional event-specific parameter.\n * \\return TRUE if the event was handled by a plugin, otherwise FALSE.\n */\nBOOLEAN PhMwpPluginNotifyEvent(\n    _In_ ULONG Type,\n    _In_ PVOID Parameter\n    )\n{\n    PH_PLUGIN_NOTIFY_EVENT notifyEvent;\n\n    notifyEvent.Type = Type;\n    notifyEvent.Handled = FALSE;\n    notifyEvent.Parameter = Parameter;\n\n    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNotifyEvent), &notifyEvent);\n\n    return notifyEvent.Handled;\n}\n\n//\n// \n// \n\nSLIST_HEADER PhMainThreadInvokeQueue;\nPH_FREE_LIST PhMainThreadInvokeQueueFreeList;\nvolatile LONG PhMainThreadInvokePending = 0;\n\n/**\n * Queues a command to be executed on the application's main (UI) thread.\n *\n * \\param Command Function pointer (VOID (NTAPI*)(PVOID)) to invoke on the main thread.\n * \\param Parameter Parameter to pass to the invoked function.\n * \\return NTSTATUS status code (always STATUS_SUCCESS on queueing).\n */\nNTSTATUS PhInvokeOnMainThread(\n    _In_opt_ PVOID Command,\n    _In_opt_ PVOID Parameter\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_INVOKE_ENTRY entry;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeSListHead(&PhMainThreadInvokeQueue);\n        PhInitializeFreeList(&PhMainThreadInvokeQueueFreeList, sizeof(PH_INVOKE_ENTRY), 5);\n        PhEndInitOnce(&initOnce);\n    }\n\n    entry = PhAllocateFromFreeList(&PhMainThreadInvokeQueueFreeList);\n    entry->Command = Command;\n    entry->Parameter = Parameter;\n    //entry->ThreadId = NtCurrentThreadId();\n    //entry->SubmitTime = NtGetTickCount64();\n\n    RtlInterlockedPushEntrySList(&PhMainThreadInvokeQueue, &entry->ListEntry);\n\n    // Only post WM_PH_INVOKE if no message is currently pending.\n    // This prevents flooding the message queue with redundant messages while\n    // still ensuring the queue is processed (one message drains all items).\n    if (InterlockedCompareExchange(&PhMainThreadInvokePending, 1, 0) == 0)\n    {\n        PostMessage(PhMainWndHandle, WM_PH_INVOKE, 0, 0);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Processes and dispatches all pending main-thread invoke queue entries.\n *\n * This function is called on the main/UI thread to execute callbacks queued\n * via PhInvokeOnMainThread.\n */\nVOID PhProcessInvokeQueue(\n    VOID\n    )\n{\n    PSLIST_ENTRY listEntry;\n    PPH_INVOKE_ENTRY entry;\n\n    while ((listEntry = RtlInterlockedPopEntrySList(&PhMainThreadInvokeQueue)))\n    {\n        entry = CONTAINING_RECORD(listEntry, PH_INVOKE_ENTRY, ListEntry);\n\n        {\n            VOID (NTAPI* function)(PVOID);\n\n            function = entry->Command;\n            function(entry->Parameter);\n        }\n\n        //PH_PLUGIN_INVOKE_EVENT event;\n        //\n        //memset(&event, 0, sizeof(PH_PLUGIN_INVOKE_EVENT));\n        //event.Id = entry->Command;\n        //event.Parameter = entry->Parameter;\n        //\n        //PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainWindowThread), &event);\n\n        PhFreeToFreeList(&PhMainThreadInvokeQueueFreeList, entry);\n    }\n}\n\n// Exports for plugin support (dmex)\n\n/**\n * Plugin-facing helper to invoke main window callbacks or perform window operations.\n *\n * \\param Event The callback/event type to perform.\n * \\param wparam First parameter (meaning depends on Event).\n * \\param lparam Second parameter (meaning depends on Event).\n * \\return Optional result depending on Event; NULL if none.\n */\nPVOID PhPluginInvokeWindowCallback(\n    _In_ PH_MAINWINDOW_CALLBACK_TYPE Event,\n    _In_opt_ PVOID wparam,\n    _In_opt_ PVOID lparam\n    )\n{\n    switch (Event)\n    {\n    case PH_MAINWINDOW_CALLBACK_TYPE_DESTROY:\n        {\n            SendMessage(PhMainWndHandle, WM_PH_DESTROY, 0, 0);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SHOW_PROPERTIES:\n        {\n            SendMessage(PhMainWndHandle, WM_PH_SHOW_PROPERTIES, 0, (LPARAM)lparam);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SAVE_ALL_SETTINGS:\n        {\n            SendMessage(PhMainWndHandle, WM_PH_SAVE_ALL_SETTINGS, 0, 0);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_PREPARE_FOR_EARLY_SHUTDOWN:\n        {\n            SendMessage(PhMainWndHandle, WM_PH_PREPARE_FOR_EARLY_SHUTDOWN, 0, 0);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_CANCEL_EARLY_SHUTDOWN:\n        {\n            PhMainWndEarlyExit = FALSE;\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_TOGGLE_VISIBLE:\n        {\n            BOOLEAN visibility = !(BOOLEAN)(ULONG_PTR)wparam;\n\n            SendMessage(PhMainWndHandle, WM_PH_ACTIVATE_WINDOW, 0, (LPARAM)visibility);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_ICON_CLICK:\n        {\n            BOOLEAN visibility = !!PhGetIntegerSetting(SETTING_ICON_TOGGLES_VISIBILITY);\n\n            SendMessage(PhMainWndHandle, WM_PH_ACTIVATE_WINDOW, 0, (LPARAM)visibility);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SHOW_MEMORY_EDITOR:\n        {\n            PPH_SHOW_MEMORY_EDITOR showMemoryEditor = (PPH_SHOW_MEMORY_EDITOR)lparam;\n\n            PostMessage(PhMainWndHandle, WM_PH_SHOW_EDITOR, (WPARAM)showMemoryEditor, 0);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SHOW_MEMORY_RESULTS:\n        {\n            PPH_SHOW_MEMORY_RESULTS showMemoryResults = (PPH_SHOW_MEMORY_RESULTS)lparam;\n\n            PostMessage(PhMainWndHandle, WM_PH_SHOW_RESULT, (WPARAM)showMemoryResults, 0);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SELECT_TAB_PAGE:\n        {\n            SendMessage(PhMainWndHandle, WM_PH_SELECT_NODE, (WPARAM)1, (LPARAM)lparam);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_GET_CALLBACK_LAYOUT_PADDING:\n        {\n            return (PVOID)&LayoutPaddingCallback;\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_INVALIDATE_LAYOUT_PADDING:\n        {\n            LayoutPaddingValid = FALSE;\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SELECT_PROCESS_NODE:\n        {\n            SendMessage(PhMainWndHandle, WM_PH_SELECT_NODE, (WPARAM)2, (LPARAM)lparam);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SELECT_SERVICE_ITEM:\n        {\n            SendMessage(PhMainWndHandle, WM_PH_SELECT_NODE, (WPARAM)3, (LPARAM)lparam);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SELECT_NETWORK_ITEM:\n        {\n            SendMessage(PhMainWndHandle, WM_PH_SELECT_NODE, (WPARAM)4, (LPARAM)lparam);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_UPDATE_FONT:\n        {\n            SendMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, (LPARAM)lparam);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_GET_FONT:\n        {\n            return PhTreeWindowFont; // (PVOID)GetWindowFont(PhMwpProcessTreeNewHandle);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_INVOKE:\n        {\n            PhInvokeOnMainThread((PVOID)(ULONG_PTR)lparam, (PVOID)wparam);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_REFRESH:\n        {\n            SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_REFRESH, 0);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_CREATE_TAB_PAGE:\n        {\n            return NULL; //(PVOID)SendMessage(PhMainWndHandle, WM_PH_CALLBACK, (WPARAM)lparam, (LPARAM)PhMwpCreatePage);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_GET_UPDATE_AUTOMATICALLY:\n        {\n            return (PVOID)UlongToPtr(PhMwpUpdateAutomatically);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SET_UPDATE_AUTOMATICALLY:\n        {\n            BOOLEAN updateAutomatically = !!(BOOLEAN)(ULONG_PTR)wparam;\n\n            if (updateAutomatically != PhMwpUpdateAutomatically)\n            {\n                SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_UPDATEAUTOMATICALLY, 0);\n            }\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_WINDOW_BASE:\n        {\n            return (PVOID)NtCurrentImageBase();\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_GETWINDOW_PROCEDURE:\n        {\n            return (PVOID)PhMwpWndProc; // (WNDPROC)GetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SETWINDOW_PROCEDURE:\n        {\n            PhMainWndProc = (WNDPROC)wparam; // (WNDPROC)GetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_WINDOW_HANDLE:\n        {\n            return (PVOID)PhMainWndHandle;\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_VERSION:\n        {\n            return UlongToPtr(WindowsVersion);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_PORTABLE:\n        {\n            return (PVOID)UlongToPtr(PhPortableEnabled);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_WINDOWDPI:\n        {\n            return (PVOID)UlongToPtr(LayoutWindowDpi);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_WINDOWNAME:\n        {\n            return (PVOID)PhApplicationName;\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_GET_MAIN_MENU:\n        {\n            return (PVOID)PhpCreateMainMenu(ULONG_MAX);\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_GET_MAIN_SUBMENU:\n        {\n            PPH_EMENU menu;\n\n            menu = PhpCreateMainMenu(PtrToUlong(wparam));\n            PhMwpInitializeSubMenu(PhMainWndHandle, menu, PtrToUlong(wparam));\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_MENU_INFORMATION pluginMenuInfo;\n\n                PhPluginInitializeMenuInfo(&pluginMenuInfo, menu, PhMainWndHandle, PH_PLUGIN_MENU_DISALLOW_HOOKS);\n                pluginMenuInfo.u.MainMenu.SubMenuIndex = PtrToUlong(wparam);\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), &pluginMenuInfo);\n            }\n\n            return (PVOID)menu;\n        }\n        break;\n    case PH_MAINWINDOW_CALLBACK_TYPE_SET_MAIN_SUBCMD:\n        {\n            PhMwpDispatchMenuCommand(PhMainWndHandle, PtrToUlong(wparam), (ULONG_PTR)lparam);\n        }\n        break;\n    }\n\n    return NULL;\n}\n\n/**\n * Creates a main tab page on behalf of a plugin.\n *\n * \\param Page Pointer to a PH_MAIN_TAB_PAGE template structure describing the page.\n * \\return Pointer to the newly created PPH_MAIN_TAB_PAGE.\n */\nPVOID PhPluginCreateTabPage(\n    _In_ PVOID Page\n    )\n{\n    return PhMwpCreatePage(Page);\n}\n"
  },
  {
    "path": "SystemInformer/mdump.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2016-2023\n *\n */\n\n#include <phapp.h>\n#include <appresolver.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <dbghelp.h>\n#include <symprv.h>\n\n#include <actions.h>\n#include <phsvccl.h>\n#include <procprv.h>\n\n#define WM_PH_MINIDUMP_STATUS_UPDATE (WM_APP + 301)\n#define WM_PH_MINIDUMP_COMPLETED (WM_APP + 302)\n#define WM_PH_MINIDUMP_ERROR (WM_APP + 303)\n\ntypedef struct _PH_PROCESS_MINIDUMP_CONTEXT\n{\n    HWND WindowHandle;\n    HWND ParentWindowHandle;\n\n    HANDLE ProcessId;\n    PPH_PROCESS_ITEM ProcessItem;\n    PPH_STRING FileName;\n    PPH_STRING ErrorMessage;\n    ULONG DumpType;\n\n    HANDLE ProcessHandle;\n    HANDLE FileHandle;\n    HANDLE KernelFileHandle;\n\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN IsWow64Process : 1;\n            BOOLEAN IsProcessSnapshot : 1;\n            BOOLEAN Stop : 1;\n            BOOLEAN Succeeded : 1;\n            BOOLEAN EnableProcessSnapshot : 1;\n            BOOLEAN EnableKernelSnapshot : 1;\n            BOOLEAN Spare : 2;\n        };\n    };\n\n    ULONG64 LastTickCount;\n    WNDPROC DefaultTaskDialogWindowProc;\n} PH_PROCESS_MINIDUMP_CONTEXT, *PPH_PROCESS_MINIDUMP_CONTEXT;\n\nINT_PTR CALLBACK PhpProcessMiniDumpDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpProcessMiniDumpTaskDialogThread(\n    _In_ PVOID ThreadParameter\n    );\n\nPH_INITONCE PhpProcessMiniDumpContextTypeInitOnce = PH_INITONCE_INIT;\nPPH_OBJECT_TYPE PhpProcessMiniDumpContextType = NULL;\n\nPPH_STRING PhpProcessMiniDumpGetFileName(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    static PH_FILETYPE_FILTER filters[] =\n    {\n        { L\"Dump files (*.dmp)\", L\"*.dmp\" },\n        { L\"All files (*.*)\", L\"*.*\" }\n    };\n    PPH_STRING fileName = NULL;\n    PVOID fileDialog;\n    LARGE_INTEGER time;\n    SYSTEMTIME systemTime;\n    PPH_STRING dateString;\n    PPH_STRING timeString;\n    PPH_STRING suggestedFileName;\n\n    PhQuerySystemTime(&time);\n    PhLargeIntegerToLocalSystemTime(&systemTime, &time);\n    dateString = PH_AUTO_T(PH_STRING, PhFormatDate(&systemTime, L\"yyyy-MM-dd\"));\n    timeString = PH_AUTO_T(PH_STRING, PhFormatTime(&systemTime, L\"HH-mm-ss\"));\n    suggestedFileName = PH_AUTO_T(PH_STRING, PhFormatString(\n        L\"%s_%s_%s.dmp\",\n        PhGetString(ProcessItem->ProcessName),\n        PhGetString(dateString),\n        PhGetString(timeString)\n        ));\n\n    if (fileDialog = PhCreateSaveFileDialog())\n    {\n        PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters));\n        PhSetFileDialogFileName(fileDialog, PhGetString(suggestedFileName));\n        PhSetFileDialogOptions(fileDialog, PH_FILEDIALOG_DONTADDTORECENT);\n\n        if (PhShowFileDialog(WindowHandle, fileDialog))\n        {\n            fileName = PhGetFileDialogFileName(fileDialog);\n        }\n\n        PhFreeFileDialog(fileDialog);\n    }\n\n    return fileName;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpProcessMiniDumpContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_PROCESS_MINIDUMP_CONTEXT context = Object;\n\n    if (context->KernelFileHandle)\n    {\n        LARGE_INTEGER fileSize;\n\n        if (NT_SUCCESS(PhGetFileSize(context->KernelFileHandle, &fileSize)))\n        {\n            if (fileSize.QuadPart == 0)\n            {\n                PhSetFileDelete(context->KernelFileHandle);\n            }\n        }\n\n        NtClose(context->KernelFileHandle);\n    }\n\n    if (context->FileHandle)\n        NtClose(context->FileHandle);\n    if (context->ProcessHandle)\n        NtClose(context->ProcessHandle);\n    if (context->FileName)\n        PhDereferenceObject(context->FileName);\n    if (context->ErrorMessage)\n        PhDereferenceObject(context->ErrorMessage);\n    if (context->ProcessItem)\n        PhDereferenceObject(context->ProcessItem);\n}\n\nPPH_PROCESS_MINIDUMP_CONTEXT PhpCreateProcessMiniDumpContext(\n    VOID\n    )\n{\n    PPH_PROCESS_MINIDUMP_CONTEXT context;\n\n    if (PhBeginInitOnce(&PhpProcessMiniDumpContextTypeInitOnce))\n    {\n        PhpProcessMiniDumpContextType = PhCreateObjectType(L\"ProcessMiniDumpContextObjectType\", 0, PhpProcessMiniDumpContextDeleteProcedure);\n        PhEndInitOnce(&PhpProcessMiniDumpContextTypeInitOnce);\n    }\n\n    context = PhCreateObject(sizeof(PH_PROCESS_MINIDUMP_CONTEXT), PhpProcessMiniDumpContextType);\n    memset(context, 0, sizeof(PH_PROCESS_MINIDUMP_CONTEXT));\n\n    return context;\n}\n\nVOID PhUiCreateDumpFileProcess(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ MINIDUMP_TYPE DumpType\n    )\n{\n    static ACCESS_MASK processAccess[] =\n    {\n        PROCESS_ALL_ACCESS,\n        PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE | PROCESS_VM_READ,\n        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n        PROCESS_QUERY_INFORMATION\n    };\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    PPH_PROCESS_MINIDUMP_CONTEXT context;\n    PPH_STRING fileName;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n\n    fileName = PhpProcessMiniDumpGetFileName(WindowHandle, ProcessItem);\n\n    if (PhIsNullOrEmptyString(fileName))\n        return;\n\n    context = PhpCreateProcessMiniDumpContext();\n    context->EnableProcessSnapshot = !!PhGetIntegerSetting(SETTING_ENABLE_MINIDUMP_SNAPSHOT);\n    context->EnableKernelSnapshot = !!PhGetIntegerSetting(SETTING_ENABLE_MINIDUMP_KERNEL_MINIDUMP);\n    context->ParentWindowHandle = WindowHandle;\n    context->ProcessId = ProcessItem->ProcessId;\n    context->ProcessItem = PhReferenceObject(ProcessItem);\n    context->FileName = fileName;\n    context->DumpType = DumpType;\n\n    for (ULONG i = 0; i < RTL_NUMBER_OF(processAccess); i++)\n    {\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &context->ProcessHandle,\n            processAccess[i],\n            context->ProcessId\n            )))\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to open the process\", status, 0);\n        PhDereferenceObject(context);\n        return;\n    }\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(context->ProcessHandle, &isWow64);\n    context->IsWow64Process = !!isWow64;\n#endif\n\n    status = PhCreateFileWin32(\n        &context->FileHandle,\n        PhGetString(fileName),\n        FILE_GENERIC_WRITE | DELETE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_DELETE,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to access the dump file\", status, 0);\n        PhDereferenceObject(context);\n        return;\n    }\n\n    PhCreateThread2(PhpProcessMiniDumpTaskDialogThread, context);\n\n    //PhDialogBox(\n    //    PhInstanceHandle,\n    //    MAKEINTRESOURCE(IDD_PROGRESS),\n    //    NULL,\n    //    PhpProcessMiniDumpDlgProc,\n    //    context\n    //    );\n}\n\nstatic BOOL CALLBACK PhpProcessMiniDumpCallback(\n    _Inout_ PVOID CallbackParam,\n    _In_ PMINIDUMP_CALLBACK_INPUT CallbackInput,\n    _Inout_ PMINIDUMP_CALLBACK_OUTPUT CallbackOutput\n    )\n{\n    PPH_PROCESS_MINIDUMP_CONTEXT context = CallbackParam;\n    PPH_STRING message = NULL;\n\n    // Don't try to send status updates if we're creating a dump of the current process.\n    if (context->ProcessId == NtCurrentProcessId())\n        return TRUE;\n\n    // MiniDumpWriteDump seems to get bored of calling the callback\n    // after it begins dumping the process handles. The code is\n    // still here in case they fix this problem in the future.\n\n    switch (CallbackInput->CallbackType)\n    {\n    case CancelCallback:\n        {\n            if (context->Stop)\n                CallbackOutput->Cancel = TRUE;\n\n            CallbackOutput->CheckCancel = TRUE;\n        }\n        break;\n    case IsProcessSnapshotCallback:\n        {\n            if (context->EnableProcessSnapshot && context->IsProcessSnapshot)\n                CallbackOutput->Status = S_FALSE;\n        }\n        break;\n    //case VmStartCallback:\n    //    {\n    //        CallbackOutput->Status = S_FALSE;\n    //    }\n    //    break;\n    //case IncludeVmRegionCallback:\n    //    {\n    //        CallbackOutput->Continue = TRUE;\n    //    }\n    //    break;\n    case ReadMemoryFailureCallback:\n        {\n            CallbackOutput->Status = S_OK;\n        }\n        break;\n    case ModuleCallback:\n        {\n            PH_FORMAT format[3];\n            PPH_STRING baseName = NULL;\n\n            if (CallbackInput->Module.FullPath)\n            {\n                if (baseName = PhCreateString(CallbackInput->Module.FullPath))\n                {\n                    PhMoveReference(&baseName, PhGetBaseName(baseName));\n                    PhMoveReference(&baseName, PhEllipsisStringPath(baseName, 10));\n                }\n            }\n\n            // Processing module %s...\n            PhInitFormatS(&format[0], L\"Processing module \");\n            if (baseName)\n                PhInitFormatSR(&format[1], baseName->sr);\n            else\n                PhInitFormatS(&format[1], L\"\");\n            PhInitFormatS(&format[2], L\"...\");\n\n            message = PhFormat(format, RTL_NUMBER_OF(format), 0);\n            PhClearReference(&baseName);\n        }\n        break;\n    case ThreadCallback:\n    case ThreadExCallback:\n        {\n            PH_FORMAT format[3];\n\n            // Processing thread %lu...\n            PhInitFormatS(&format[0], L\"Processing thread \");\n            PhInitFormatU(&format[1], CallbackInput->Thread.ThreadId);\n            PhInitFormatS(&format[2], L\"...\");\n\n            message = PhFormat(format, RTL_NUMBER_OF(format), 0);\n        }\n        break;\n    case IncludeVmRegionCallback:\n        {\n            PH_FORMAT format[2];\n\n            //CallbackOutput->Continue = TRUE;\n\n            // Processing memory %lu...\n            PhInitFormatS(&format[0], L\"Processing memory regions\");\n            //PhInitFormatI64X(&format[1], CallbackOutput->VmRegion.BaseAddress);\n            PhInitFormatS(&format[1], L\"...\");\n\n            message = PhFormat(format, RTL_NUMBER_OF(format), 0);\n        }\n        break;\n    case WriteKernelMinidumpCallback:\n        {\n            static CONST PH_STRINGREF kernelDumpFileExt = PH_STRINGREF_INIT(L\".kernel.dmp\");\n            HANDLE kernelDumpFileHandle;\n            PPH_STRING kernelDumpFileName;\n\n            if (!context->EnableKernelSnapshot)\n                break;\n            if (!PhGetOwnTokenAttributes().Elevated)\n                break;\n\n            if (kernelDumpFileName = PhGetBaseNameChangeExtension(&context->FileName->sr, &kernelDumpFileExt))\n            {\n                if (NT_SUCCESS(PhCreateFileWin32(\n                    &kernelDumpFileHandle,\n                    PhGetString(kernelDumpFileName),\n                    FILE_GENERIC_WRITE | DELETE,\n                    FILE_ATTRIBUTE_NORMAL,\n                    0,\n                    FILE_OVERWRITE_IF,\n                    FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n                    )))\n                {\n                    context->KernelFileHandle = kernelDumpFileHandle;\n                    CallbackOutput->Handle = kernelDumpFileHandle;\n                }\n\n                PhDereferenceObject(kernelDumpFileName);\n            }\n        }\n        break;\n    case KernelMinidumpStatusCallback:\n        {\n            PH_FORMAT format[2];\n\n            if (!context->EnableKernelSnapshot)\n                break;\n\n            PhInitFormatS(&format[0], L\"Processing kernel minidump\");\n            PhInitFormatS(&format[1], L\"...\");\n\n            message = PhFormat(format, RTL_NUMBER_OF(format), 0);\n        }\n        break;\n    }\n\n    if (message)\n    {\n        SendMessage(context->WindowHandle, WM_PH_MINIDUMP_STATUS_UPDATE, 0, (LPARAM)message->Buffer);\n        PhDereferenceObject(message);\n    }\n\n    return TRUE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpProcessMiniDumpThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_PROCESS_MINIDUMP_CONTEXT context = Parameter;\n    MINIDUMP_CALLBACK_INFORMATION callbackInfo;\n    HANDLE processSnapshotHandle = NULL;\n    HANDLE packageTaskHandle = NULL;\n    HANDLE processHandle = NULL;\n    LONG status;\n\n    callbackInfo.CallbackRoutine = PhpProcessMiniDumpCallback;\n    callbackInfo.CallbackParam = context;\n\n#ifdef _WIN64\n    if (context->IsWow64Process)\n    {\n        if (PhUiConnectToPhSvcEx(NULL, Wow64PhSvcMode, FALSE))\n        {\n            if (NT_SUCCESS(status = PhSvcCallWriteMiniDumpProcess(\n                context->ProcessHandle,\n                context->ProcessId,\n                context->FileHandle,\n                context->DumpType\n                )))\n            {\n                context->Succeeded = TRUE;\n            }\n            else\n            {\n                SendMessage(context->WindowHandle, WM_PH_MINIDUMP_ERROR, 0, (LPARAM)PhNtStatusToDosError(status));\n            }\n\n            PhUiDisconnectFromPhSvc();\n\n            goto Completed;\n        }\n        else\n        {\n            if (PhShowMessage2(\n                context->WindowHandle,\n                TD_YES_BUTTON | TD_NO_BUTTON,\n                TD_WARNING_ICON,\n                L\"The 32-bit version of System Informer could not be located.\",\n                L\"A 64-bit dump will be created instead. Do you want to continue?\"\n                ) == IDNO)\n            {\n                goto Completed;\n            }\n        }\n    }\n#endif\n\n    if (context->ProcessItem->IsPackagedProcess)\n    {\n        // Set the task completion notification (based on taskmgr.exe) (dmex)\n        //PhAppResolverPackageStopSessionRedirection(context->ProcessItem->PackageFullName);\n        PhAppResolverBeginCrashDumpTaskByHandle(context->ProcessHandle, &packageTaskHandle);\n    }\n\n    if (context->EnableKernelSnapshot)\n    {\n        if (!PhGetOwnTokenAttributes().Elevated)\n        {\n            PhShowWarning2(\n                context->WindowHandle,\n                L\"Unable to create kernel minidump.\",\n                L\"%s\",\n                L\"Kernel minidump of processes require administrative privileges. \"\n                L\"Make sure System Informer is running with administrative privileges.\"\n                );\n        }\n    }\n    else\n    {\n        if (context->EnableProcessSnapshot && context->ProcessId != NtCurrentProcessId()) // Don't use snapshots for the current process (dmex)\n        {\n            HANDLE snapshotHandle;\n\n            if (NT_SUCCESS(PhCreateProcessSnapshot(\n                &snapshotHandle,\n                context->ProcessHandle\n                )))\n            {\n                processSnapshotHandle = snapshotHandle;\n                context->IsProcessSnapshot = TRUE;\n            }\n        }\n    }\n\n    if (context->EnableProcessSnapshot && context->IsProcessSnapshot && processSnapshotHandle)\n        processHandle = processSnapshotHandle;\n    else\n        processHandle = context->ProcessHandle;\n\n    status = PhWriteMiniDumpProcess(\n        processHandle,\n        context->ProcessId,\n        context->FileHandle,\n        context->DumpType,\n        NULL,\n        NULL,\n        &callbackInfo\n        );\n\n    if (HR_SUCCESS(status))\n    {\n        context->Succeeded = TRUE;\n    }\n    else\n    {\n        SendMessage(context->WindowHandle, WM_PH_MINIDUMP_ERROR, 0, (LPARAM)status);\n    }\n\n    if (processSnapshotHandle)\n        PhFreeProcessSnapshot(processSnapshotHandle, context->ProcessHandle);\n    if (packageTaskHandle)\n        PhAppResolverEndCrashDumpTask(packageTaskHandle);\n\n#ifdef _WIN64\nCompleted:\n#endif\n    if (context->Succeeded)\n    {\n        SendMessage(context->WindowHandle, WM_PH_MINIDUMP_COMPLETED, 0, 0);\n    }\n    else\n    {\n        PhSetFileDelete(context->FileHandle);\n    }\n\n    PhDereferenceObject(context);\n\n    return STATUS_SUCCESS;\n}\n\nINT_PTR CALLBACK PhpProcessMiniDumpDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PROCESS_MINIDUMP_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_PROCESS_MINIDUMP_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n            PhCenterWindow(hwndDlg, context->ParentWindowHandle);\n\n            PhSetWindowText(hwndDlg, L\"Creating the dump file...\");\n            PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, L\"Creating the dump file...\");\n            PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE);\n            SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75);\n\n            PhReferenceObject(context);\n            PhCreateThread2(PhpProcessMiniDumpThreadStart, context);\n\n            PhSetTimer(hwndDlg, PH_WINDOW_TIMER_DEFAULT, 500, NULL);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhKillTimer(hwndDlg, PH_WINDOW_TIMER_DEFAULT);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDereferenceObject(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                {\n                    EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);\n                    context->Stop = TRUE;\n                }\n                break;\n            }\n        }\n        break;\n    case WM_TIMER:\n        {\n            if (wParam == PH_WINDOW_TIMER_DEFAULT)\n            {\n                ULONG64 currentTickCount;\n\n                currentTickCount = NtGetTickCount64();\n\n                if (currentTickCount - context->LastTickCount >= 2000)\n                {\n                    // No status message update for 2 seconds.\n\n                    PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, L\"Creating the dump file...\");\n\n                    context->LastTickCount = currentTickCount;\n                }\n            }\n        }\n        break;\n    case WM_PH_MINIDUMP_STATUS_UPDATE:\n        PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, (PWSTR)lParam);\n        context->LastTickCount = NtGetTickCount64();\n        break;\n    case WM_PH_MINIDUMP_ERROR:\n        PhShowStatus(hwndDlg, L\"Unable to create the minidump\", 0, (ULONG)lParam);\n        break;\n    case WM_PH_MINIDUMP_COMPLETED:\n        EndDialog(hwndDlg, IDOK);\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nHRESULT CALLBACK PhpProcessMiniDumpErrorPageCallbackProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR dwRefData\n    )\n{\n    return S_OK;\n}\n\nLRESULT CALLBACK PhpProcessMiniDumpTaskDialogSubclassProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PROCESS_MINIDUMP_CONTEXT context;\n    WNDPROC oldWndProc;\n\n    if (!(context = PhGetWindowContext(hwndDlg, 0xF)))\n        return 0;\n\n    oldWndProc = context->DefaultTaskDialogWindowProc;\n\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            PhSetWindowProcedure(hwndDlg, oldWndProc);\n            PhRemoveWindowContext(hwndDlg, 0xF);\n        }\n        break;\n    case WM_PH_MINIDUMP_STATUS_UPDATE:\n        {\n            SendMessage(hwndDlg, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, lParam);\n            context->LastTickCount = NtGetTickCount64();\n        }\n        break;\n    case WM_PH_MINIDUMP_ERROR:\n        {\n            TASKDIALOGCONFIG config;\n            PPH_STRING statusMessage;\n\n            if (context->Stop)\n            {\n                SendMessage(hwndDlg, TDM_CLICK_BUTTON, IDOK, 0);\n                break;\n            }\n\n            if (statusMessage = PhGetStatusMessage(0, (ULONG)lParam))\n            {\n                PhMoveReference(&context->ErrorMessage, statusMessage);\n            }\n\n            memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n            config.cbSize = sizeof(TASKDIALOGCONFIG);\n            config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED;\n            config.hMainIcon = PhGetApplicationIcon(FALSE);\n            config.dwCommonButtons = TDCBF_CLOSE_BUTTON;\n            config.pfCallback = PhpProcessMiniDumpErrorPageCallbackProc;\n            config.lpCallbackData = (LONG_PTR)context;\n            config.pszWindowTitle = PhApplicationName;\n            config.pszMainInstruction = L\"Unable to create the minidump.\";\n            config.pszContent = PhGetStringOrDefault(context->ErrorMessage, L\"Unknown error.\");\n\n            PhTaskDialogNavigatePage(context->WindowHandle, &config);\n        }\n        break;\n    case WM_PH_MINIDUMP_COMPLETED:\n        SendMessage(hwndDlg, TDM_CLICK_BUTTON, IDOK, 0);\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam);\n}\n\nHRESULT CALLBACK PhpProcessMiniDumpTaskDialogCallbackProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR dwRefData\n    )\n{\n    PPH_PROCESS_MINIDUMP_CONTEXT context = (PPH_PROCESS_MINIDUMP_CONTEXT)dwRefData;\n\n    switch (uMsg)\n    {\n    case TDN_DIALOG_CONSTRUCTED:\n        {\n            context->WindowHandle = hwndDlg;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n            PhCenterWindow(hwndDlg, context->ParentWindowHandle);\n\n            context->DefaultTaskDialogWindowProc = PhGetWindowProcedure(hwndDlg);\n            PhSetWindowContext(hwndDlg, 0xF, context);\n            PhSetWindowProcedure(hwndDlg, PhpProcessMiniDumpTaskDialogSubclassProc);\n\n            SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n            SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n\n            PhReferenceObject(context);\n            PhCreateThread2(PhpProcessMiniDumpThreadStart, context);\n        }\n        break;\n    case TDN_TIMER:\n        {\n            ULONG64 currentTickCount;\n\n            currentTickCount = NtGetTickCount64();\n\n            if (currentTickCount - context->LastTickCount >= 2000)\n            {\n                // No status message update for 2 seconds.\n\n                //SendMessage(hwndDlg, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)L\"Creating the minidump file...\");\n\n                context->LastTickCount = currentTickCount;\n            }\n        }\n        break;\n    case TDN_BUTTON_CLICKED:\n        {\n            ULONG buttonId = (ULONG)wParam;\n\n            if (buttonId == IDCANCEL)\n            {\n                context->Stop = TRUE;\n                SendMessage(hwndDlg, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)L\"Cancelling...\");\n                return S_FALSE;\n            }\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpProcessMiniDumpTaskDialogThread(\n    _In_ PVOID ThreadParameter\n    )\n{\n    PPH_PROCESS_MINIDUMP_CONTEXT context = (PPH_PROCESS_MINIDUMP_CONTEXT)ThreadParameter;\n    TASKDIALOGCONFIG config;\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CALLBACK_TIMER | TDF_CAN_BE_MINIMIZED;\n    config.hMainIcon = PhGetApplicationIcon(FALSE);\n    config.dwCommonButtons = TDCBF_CANCEL_BUTTON;\n    config.pfCallback = PhpProcessMiniDumpTaskDialogCallbackProc;\n    config.lpCallbackData = (LONG_PTR)context;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainInstruction = L\"Creating the minidump file...\";\n    config.pszContent = L\"Creating the minidump file...\";\n    config.cxWidth = 200;\n\n    PhShowTaskDialog(&config, NULL, NULL, NULL);\n\n    PhDereferenceObject(context);\n\n    return STATUS_SUCCESS;\n}\n\ntypedef struct _PH_MINIDUMP_OPTION_ENTRY\n{\n    ULONG Id;\n    MINIDUMP_TYPE Type;\n} PH_MINIDUMP_OPTION_ENTRY, *PPH_MINIDUMP_OPTION_ENTRY;\n\nINT_PTR CALLBACK PhpProcDumpDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    static CONST PH_MINIDUMP_OPTION_ENTRY options[] =\n    {\n        { IDC_MINIDUMP_NORMAL, MiniDumpNormal },\n        { IDC_MINIDUMP_WITH_DATA_SEGS, MiniDumpWithDataSegs },\n        { IDC_MINIDUMP_WITH_FULL_MEM, MiniDumpWithFullMemory },\n        { IDC_MINIDUMP_WITH_HANDLE_DATA, MiniDumpWithHandleData },\n        { IDC_MINIDUMP_FILTER_MEMORY, MiniDumpFilterMemory },\n        { IDC_MINIDUMP_SCAN_MEMORY, MiniDumpScanMemory },\n        { IDC_MINIDUMP_WITH_UNLOADED_MODULES, MiniDumpWithUnloadedModules },\n        { IDC_MINIDUMP_WITH_INDIRECT_REFERENCED_MEM, MiniDumpWithIndirectlyReferencedMemory },\n        { IDC_MINIDUMP_FILTER_MODULE_PATHS, MiniDumpFilterModulePaths },\n        { IDC_MINIDUMP_WITH_PROC_THRD_DATA, MiniDumpWithProcessThreadData },\n        { IDC_MINIDUMP_WITH_PRIVATE_RW_MEM, MiniDumpWithPrivateReadWriteMemory },\n        { IDC_MINIDUMP_WITHOUT_OPTIONAL_DATA, MiniDumpWithoutOptionalData },\n        { IDC_MINIDUMP_WITH_FULL_MEM_INFO, MiniDumpWithFullMemoryInfo },\n        { IDC_MINIDUMP_WITH_THRD_INFO, MiniDumpWithThreadInfo },\n        { IDC_MINIDUMP_WITH_CODE_SEGS, MiniDumpWithCodeSegs },\n        { IDC_MINIDUMP_WITHOUT_AUXILIARY_STATE, MiniDumpWithoutAuxiliaryState },\n        { IDC_MINIDUMP_WITH_FULL_AUXILIARY_STATE, MiniDumpWithFullAuxiliaryState },\n        { IDC_MINIDUMP_WITH_PRIVATE_WRITE_COPY_MEM, MiniDumpWithPrivateWriteCopyMemory },\n        { IDC_MINIDUMP_IGNORE_INACCESSIBLE_MEM, MiniDumpIgnoreInaccessibleMemory },\n        { IDC_MINIDUMP_WITH_TOKEN_INFO, MiniDumpWithTokenInformation },\n        { IDC_MINIDUMP_WITH_MODULE_HEADERS, MiniDumpWithModuleHeaders },\n        { IDC_MINIDUMP_FILTER_TRIAGE, MiniDumpFilterTriage },\n        { IDC_MINIDUMP_WITH_AVXX_STATE_CONTEXT, MiniDumpWithAvxXStateContext },\n        { IDC_MINIDUMP_WITH_IPT_TRACE, MiniDumpWithIptTrace },\n        { IDC_MINIDUMP_SCAN_INACCESSIBLE_PARTIAL_PAGES, MiniDumpScanInaccessiblePartialPages },\n        { IDC_MINIDUMP_FILTER_WRITE_COMBINE_MEM, MiniDumpFilterWriteCombinedMemory },\n    };\n    PPH_PROCESS_ITEM processItem;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        processItem = (PPH_PROCESS_ITEM)lParam;\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, processItem);\n    }\n    else\n    {\n        processItem = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhCenterWindow(hwndDlg, NULL);\n\n            Button_SetCheck(GetDlgItem(hwndDlg, IDC_MINIDUMP_NORMAL), BST_CHECKED);\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    MINIDUMP_TYPE dumpType;\n\n                    dumpType = 0;\n\n                    for (ULONG i = 0; i < RTL_NUMBER_OF(options); i++)\n                    {\n                        if (Button_GetCheck(GetDlgItem(hwndDlg, options[i].Id)) == BST_CHECKED)\n                            dumpType |= options[i].Type;\n                    }\n\n                    PhUiCreateDumpFileProcess(hwndDlg, processItem, dumpType);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhShowCreateDumpFileProcessDialog(\n    _In_ HWND WindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_PROCDUMP),\n        WindowHandle,\n        PhpProcDumpDlgProc,\n        ProcessItem\n        );\n}\n"
  },
  {
    "path": "SystemInformer/memedit.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#include <phapp.h>\n#include <hexedit.h>\n\n#include <procprv.h>\n#include <settings.h>\n#include <phsettings.h>\n\n#define WM_PH_SELECT_OFFSET (WM_APP + 300)\n\ntypedef struct _MEMORY_EDITOR_CONTEXT\n{\n    PH_AVL_LINKS Links;\n    union\n    {\n        struct\n        {\n            HANDLE ProcessId;\n            PVOID BaseAddress;\n            SIZE_T RegionSize;\n        };\n        ULONG_PTR Key[3];\n    };\n\n    HWND WindowHandle;\n    HWND OwnerHandle;\n    HWND HexEditHandle;\n    PH_LAYOUT_MANAGER LayoutManager;\n\n    PUCHAR Buffer;\n    ULONG SelectOffset;\n    PPH_STRING Title;\n    ULONG Flags;\n\n    BOOLEAN LoadCompleted;\n} MEMORY_EDITOR_CONTEXT, *PMEMORY_EDITOR_CONTEXT;\n\nINT NTAPI PhpMemoryEditorCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    );\n\nINT_PTR CALLBACK PhpMemoryEditorDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nPH_AVL_TREE PhMemoryEditorSet = PH_AVL_TREE_INIT(PhpMemoryEditorCompareFunction);\nstatic RECT MinimumSize = { -1, -1, -1, -1 };\n\nVOID PhShowMemoryEditorDialog(\n    _In_ HWND OwnerWindow,\n    _In_ HANDLE ProcessId,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize,\n    _In_ ULONG SelectOffset,\n    _In_ ULONG SelectLength,\n    _In_opt_ PPH_STRING Title,\n    _In_ ULONG Flags\n    )\n{\n    PMEMORY_EDITOR_CONTEXT context;\n    MEMORY_EDITOR_CONTEXT lookupContext;\n    PPH_AVL_LINKS links;\n\n    lookupContext.ProcessId = ProcessId;\n    lookupContext.BaseAddress = BaseAddress;\n    lookupContext.RegionSize = RegionSize;\n\n    links = PhFindElementAvlTree(&PhMemoryEditorSet, &lookupContext.Links);\n\n    if (!links)\n    {\n        NTSTATUS status;\n        PVOID buffer;\n\n        if (RegionSize > 1024ULL * 1024ULL * 1024ULL) // 1 GB\n        {\n            PhShowStatus(OwnerWindow, L\"Unable to edit the memory region.\", 0, MEM_E_INVALID_SIZE);\n            return;\n        }\n\n        status = PhAllocateVirtualMemory(NtCurrentProcess(), &buffer, RegionSize, MEM_COMMIT, PAGE_READWRITE);\n\n        if (!NT_SUCCESS(status))\n        {\n            PhShowStatus(OwnerWindow, L\"Unable to edit the memory region.\", status, 0);\n            return;\n        }\n\n        {\n            HANDLE processHandle;\n\n            status = PhOpenProcess(\n                &processHandle,\n                PROCESS_VM_READ,\n                ProcessId\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhReadVirtualMemory(\n                    processHandle,\n                    BaseAddress,\n                    buffer,\n                    RegionSize,\n                    NULL\n                    );\n\n                NtClose(processHandle);\n\n                if (!NT_SUCCESS(status))\n                {\n                    PhShowStatus(OwnerWindow, L\"Unable to read memory\", status, 0);\n                    return;\n                }\n            }\n            else\n            {\n                PhShowStatus(OwnerWindow, L\"Unable to open the process\", status, 0);\n                return;\n            }\n        }\n\n        context = PhAllocateZero(sizeof(MEMORY_EDITOR_CONTEXT));\n        context->OwnerHandle = OwnerWindow;\n        context->ProcessId = ProcessId;\n        context->BaseAddress = BaseAddress;\n        context->RegionSize = RegionSize;\n        context->SelectOffset = SelectOffset;\n        PhSwapReference(&context->Title, Title);\n        context->Flags = Flags;\n        context->Buffer = buffer;\n\n        context->WindowHandle = PhCreateDialog(\n            PhInstanceHandle,\n            MAKEINTRESOURCE(IDD_MEMEDIT),\n            NULL,\n            PhpMemoryEditorDlgProc,\n            context\n            );\n\n        if (!context->LoadCompleted)\n        {\n            DestroyWindow(context->WindowHandle);\n            return;\n        }\n\n        if (SelectOffset != ULONG_MAX)\n            PostMessage(context->WindowHandle, WM_PH_SELECT_OFFSET, SelectOffset, SelectLength);\n\n        PhRegisterDialog(context->WindowHandle);\n        PhAddElementAvlTree(&PhMemoryEditorSet, &context->Links);\n\n        ShowWindow(context->WindowHandle, SW_SHOW);\n        SetForegroundWindow(context->WindowHandle);\n    }\n    else\n    {\n        context = CONTAINING_RECORD(links, MEMORY_EDITOR_CONTEXT, Links);\n\n        if (IsMinimized(context->WindowHandle))\n            ShowWindow(context->WindowHandle, SW_RESTORE);\n        else\n            SetForegroundWindow(context->WindowHandle);\n\n        if (SelectOffset != ULONG_MAX)\n            PostMessage(context->WindowHandle, WM_PH_SELECT_OFFSET, SelectOffset, SelectLength);\n\n        // Just in case.\n        if ((Flags & PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION) && ProcessId == NtCurrentProcessId())\n            PhUnmapViewOfSection(NtCurrentProcess(), BaseAddress);\n    }\n}\n\nINT NTAPI PhpMemoryEditorCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    )\n{\n    PMEMORY_EDITOR_CONTEXT context1 = CONTAINING_RECORD(Links1, MEMORY_EDITOR_CONTEXT, Links);\n    PMEMORY_EDITOR_CONTEXT context2 = CONTAINING_RECORD(Links2, MEMORY_EDITOR_CONTEXT, Links);\n\n    return memcmp(context1->Key, context2->Key, sizeof(context1->Key));\n}\n\nINT_PTR CALLBACK PhpMemoryEditorDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PMEMORY_EDITOR_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PMEMORY_EDITOR_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            if (context->Title)\n            {\n                PhSetWindowText(hwndDlg, context->Title->Buffer);\n            }\n            else\n            {\n                PPH_PROCESS_ITEM processItem;\n\n                if (processItem = PhReferenceProcessItem(context->ProcessId))\n                {\n                    PhSetWindowText(hwndDlg, PhaFormatString(L\"%s (%u) (0x%Ix - 0x%Ix)\",\n                        processItem->ProcessName->Buffer, HandleToUlong(context->ProcessId),\n                        (ULONG_PTR)context->BaseAddress, (ULONG_PTR)context->BaseAddress + context->RegionSize)->Buffer);\n                    PhDereferenceObject(processItem);\n                }\n            }\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_BYTESPERROW), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_GOTO), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_WRITE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REREAD), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);\n\n            if (MinimumSize.left == -1)\n            {\n                RECT rect;\n\n                rect.left = 0;\n                rect.top = 0;\n                rect.right = 290;\n                rect.bottom = 140;\n                MapDialogRect(hwndDlg, &rect);\n                MinimumSize = rect;\n                MinimumSize.left = 0;\n            }\n\n            context->HexEditHandle = GetDlgItem(hwndDlg, IDC_MEMORY);\n            PhAddLayoutItem(&context->LayoutManager, context->HexEditHandle, NULL, PH_ANCHOR_ALL);\n            HexEdit_SetBuffer(context->HexEditHandle, context->Buffer, (ULONG)context->RegionSize);\n\n            {\n                PH_RECTANGLE windowRectangle = { 0 };\n\n                windowRectangle.Position = PhGetIntegerPairSetting(SETTING_MEM_EDIT_POSITION);\n\n                if (windowRectangle.Position.X == 0)\n                {\n                    PhCenterWindow(hwndDlg, context->OwnerHandle);\n                }\n                else\n                {\n                    RECT rect;\n                    LONG dpiValue;\n\n                    PhRectangleToRect(&rect, &windowRectangle);\n                    dpiValue = PhGetMonitorDpi(NULL, &rect);\n\n                    windowRectangle.Size = PhGetScalableIntegerPairSetting(SETTING_MEM_EDIT_SIZE, TRUE, dpiValue)->Pair;\n                    PhAdjustRectangleToWorkingArea(NULL, &windowRectangle);\n\n                    MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top,\n                        windowRectangle.Width, windowRectangle.Height, FALSE);\n\n                    // Implement cascading by saving an offsetted rectangle.\n                    windowRectangle.Left += 20;\n                    windowRectangle.Top += 20;\n\n                    PhSetIntegerPairSetting(SETTING_MEM_EDIT_POSITION, windowRectangle.Position);\n                    PhSetScalableIntegerPairSetting2(SETTING_MEM_EDIT_SIZE, windowRectangle.Size, dpiValue);\n                }\n            }\n\n            {\n                PWSTR bytesPerRowStrings[7];\n                ULONG i;\n                ULONG bytesPerRow;\n\n                for (i = 0; i < sizeof(bytesPerRowStrings) / sizeof(PWSTR); i++)\n                    bytesPerRowStrings[i] = PhaFormatString(L\"%u bytes per row\", 1 << (2 + i))->Buffer;\n\n                PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_BYTESPERROW),\n                    bytesPerRowStrings, sizeof(bytesPerRowStrings) / sizeof(PWSTR));\n\n                bytesPerRow = PhGetIntegerSetting(SETTING_MEM_EDIT_BYTES_PER_ROW);\n\n                if (bytesPerRow >= 4)\n                {\n                    HexEdit_SetBytesPerRow(context->HexEditHandle, bytesPerRow);\n                    PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_BYTESPERROW),\n                        PhaFormatString(L\"%u bytes per row\", bytesPerRow)->Buffer, FALSE);\n                }\n            }\n\n            PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(SETTING_ENABLE_THEME_SUPPORT));\n\n            context->LoadCompleted = TRUE;\n        }\n        break;\n    case WM_DESTROY:\n        {\n            if (context->LoadCompleted)\n            {\n                PhSaveWindowPlacementToSetting(SETTING_MEM_EDIT_POSITION, SETTING_MEM_EDIT_SIZE, hwndDlg);\n                PhRemoveElementAvlTree(&PhMemoryEditorSet, &context->Links);\n                PhUnregisterDialog(hwndDlg);\n            }\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            if (context->Buffer) PhFreePage(context->Buffer);\n            PhClearReference(&context->Title);\n\n            if ((context->Flags & PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION) && context->ProcessId == NtCurrentProcessId())\n                PhUnmapViewOfSection(NtCurrentProcess(), context->BaseAddress);\n\n            PhFree(context);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PhSetDialogFocus(hwndDlg, context->HexEditHandle);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                DestroyWindow(hwndDlg);\n                break;\n            case IDC_SAVE:\n                {\n                    static PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Binary files (*.bin)\", L\"*.bin\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog;\n                    PPH_PROCESS_ITEM processItem;\n\n                    fileDialog = PhCreateSaveFileDialog();\n\n                    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n\n                    if (!context->Title && (processItem = PhReferenceProcessItem(context->ProcessId)))\n                    {\n                        PhSetFileDialogFileName(fileDialog,\n                            PhaFormatString(L\"%s_0x%Ix-0x%Ix.bin\", processItem->ProcessName->Buffer,\n                            context->BaseAddress, context->RegionSize)->Buffer);\n                        PhDereferenceObject(processItem);\n                    }\n                    else\n                    {\n                        PhSetFileDialogFileName(fileDialog, L\"Memory.bin\");\n                    }\n\n                    if (PhShowFileDialog(hwndDlg, fileDialog))\n                    {\n                        NTSTATUS status;\n                        PPH_STRING fileName;\n                        PPH_FILE_STREAM fileStream;\n\n                        fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n\n                        if (NT_SUCCESS(status = PhCreateFileStream(\n                            &fileStream,\n                            fileName->Buffer,\n                            FILE_GENERIC_WRITE,\n                            FILE_SHARE_READ,\n                            FILE_OVERWRITE_IF,\n                            0\n                            )))\n                        {\n                            status = PhWriteFileStream(fileStream, context->Buffer, (ULONG)context->RegionSize);\n                            PhDereferenceObject(fileStream);\n                        }\n\n                        if (!NT_SUCCESS(status))\n                            PhShowStatus(hwndDlg, L\"Unable to create the file\", status, 0);\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            case IDC_GOTO:\n                {\n                    PPH_STRING selectedChoice = NULL;\n\n                    while (PhaChoiceDialog(\n                        hwndDlg,\n                        L\"Go to Offset\",\n                        L\"Enter an offset:\",\n                        NULL,\n                        0,\n                        NULL,\n                        PH_CHOICE_DIALOG_USER_CHOICE,\n                        &selectedChoice,\n                        NULL,\n                        SETTING_MEM_EDIT_GOTO_CHOICES\n                        ))\n                    {\n                        ULONG64 offset;\n\n                        if (selectedChoice->Length == 0)\n                            continue;\n\n                        if (PhStringToInteger64(&selectedChoice->sr, 0, &offset))\n                        {\n                            if (offset >= context->RegionSize)\n                            {\n                                PhShowStatus(hwndDlg, L\"Unable to edit the memory region.\", 0, MEM_E_INVALID_SIZE);\n                                continue;\n                            }\n\n                            PhSetDialogFocus(hwndDlg, context->HexEditHandle);\n                            HexEdit_SetSel(context->HexEditHandle, (LONG)offset, (LONG)offset);\n                            break;\n                        }\n                    }\n                }\n                break;\n            case IDC_WRITE:\n                {\n                    NTSTATUS status;\n\n                    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) && !PhShowConfirmMessage(\n                        hwndDlg,\n                        L\"write\",\n                        L\"process memory\",\n                        L\"Some programs may restrict access or ban your account when editing the memory of the process.\",\n                        FALSE\n                        ))\n                    {\n                        break;\n                    }\n\n                    {\n                        HANDLE processHandle;\n\n                        status = PhOpenProcess(\n                            &processHandle,\n                            PROCESS_VM_READ | PROCESS_VM_WRITE,\n                            context->ProcessId\n                            );\n\n                        if (NT_SUCCESS(status))\n                        {\n                            status = PhWriteVirtualMemory(\n                                processHandle,\n                                context->BaseAddress,\n                                context->Buffer,\n                                context->RegionSize,\n                                NULL\n                                );\n\n                            NtClose(processHandle);\n\n                            if (!NT_SUCCESS(status))\n                            {\n                                PhShowStatus(hwndDlg, L\"Unable to write memory\", status, 0);\n                            }\n                        }\n                        else\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to open the process\", status, 0);\n                        }\n                    }\n                }\n                break;\n            case IDC_REREAD:\n                {\n                    NTSTATUS status;\n                    HANDLE processHandle;\n\n                    status = PhOpenProcess(\n                        &processHandle,\n                        PROCESS_VM_READ,\n                        context->ProcessId\n                        );\n\n                    if (NT_SUCCESS(status))\n                    {\n                        status = PhReadVirtualMemory(\n                            processHandle,\n                            context->BaseAddress,\n                            context->Buffer,\n                            context->RegionSize,\n                            NULL\n                            );\n\n                        NtClose(processHandle);\n\n                        if (!NT_SUCCESS(status))\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to read memory\", status, 0);\n                        }\n                    }\n                    else\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to open the process\", status, 0);\n                    }\n\n                    InvalidateRect(context->HexEditHandle, NULL, TRUE);\n                }\n                break;\n            case IDC_BYTESPERROW:\n                if (HIWORD(wParam) == CBN_SELCHANGE)\n                {\n                    PPH_STRING bytesPerRowString = PhaGetDlgItemText(hwndDlg, IDC_BYTESPERROW);\n                    PH_STRINGREF firstPart;\n                    PH_STRINGREF secondPart;\n                    ULONG64 bytesPerRow64;\n\n                    if (PhSplitStringRefAtChar(&bytesPerRowString->sr, L' ', &firstPart, &secondPart))\n                    {\n                        if (PhStringToInteger64(&firstPart, 10, &bytesPerRow64))\n                        {\n                            PhSetIntegerSetting(SETTING_MEM_EDIT_BYTES_PER_ROW, (ULONG)bytesPerRow64);\n                            HexEdit_SetBytesPerRow(context->HexEditHandle, (ULONG)bytesPerRow64);\n                            PhSetDialogFocus(hwndDlg, context->HexEditHandle);\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);\n        }\n        break;\n    case WM_PH_SELECT_OFFSET:\n        {\n            HexEdit_SetEditMode(context->HexEditHandle, EDIT_ASCII);\n            HexEdit_SetSel(context->HexEditHandle, (ULONG)wParam, PtrToUlong(PTR_ADD_OFFSET(wParam, lParam)));\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/memlist.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <memlist.h>\n\n#include <emenu.h>\n\n#include <extmgri.h>\n#include <memprv.h>\n#include <settings.h>\n#include <phsettings.h>\n\nVOID PhpClearMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context\n    );\n\nVOID PhpDestroyMemoryNode(\n    _In_ PPH_MEMORY_NODE MemoryNode\n    );\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpMemoryTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    );\n\nBOOLEAN NTAPI PhpMemoryTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\nVOID PhInitializeMemoryList(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND TreeNewHandle,\n    _Out_ PPH_MEMORY_LIST_CONTEXT Context\n    )\n{\n    BOOLEAN enableMonospaceFont = !!PhGetIntegerSetting(SETTING_ENABLE_MONOSPACE_FONT);\n\n    memset(Context, 0, sizeof(PH_MEMORY_LIST_CONTEXT));\n    Context->AllocationBaseNodeList = PhCreateList(100);\n    Context->RegionNodeList = PhCreateList(400);\n    Context->ParentWindowHandle = ParentWindowHandle;\n    Context->TreeNewHandle = TreeNewHandle;\n\n    PhSetControlTheme(TreeNewHandle, L\"explorer\");\n    TreeNew_SetRedraw(TreeNewHandle, FALSE);\n    TreeNew_SetCallback(TreeNewHandle, PhpMemoryTreeNewCallback, Context);\n\n    // Default columns\n    PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_BASEADDRESS, TRUE, L\"Base address\", 120, PH_ALIGN_LEFT | (enableMonospaceFont ? PH_ALIGN_MONOSPACE_FONT : 0), -2, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_TYPE, TRUE, L\"Type\", 90, PH_ALIGN_LEFT, 0, 0);\n    PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_SIZE, TRUE, L\"Size\", 80, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_PROTECTION, TRUE, L\"Protection\", 60, PH_ALIGN_LEFT, 2, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_USE, TRUE, L\"Use\", 200, PH_ALIGN_LEFT, 3, 0);\n    PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_TOTALWS, TRUE, L\"Total WS\", 80, PH_ALIGN_RIGHT, 4, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_PRIVATEWS, TRUE, L\"Private WS\", 80, PH_ALIGN_RIGHT, 5, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_SHAREABLEWS, TRUE, L\"Shareable WS\", 80, PH_ALIGN_RIGHT, 6, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_SHAREDWS, TRUE, L\"Shared WS\", 80, PH_ALIGN_RIGHT, 7, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_LOCKEDWS, TRUE, L\"Locked WS\", 80, PH_ALIGN_RIGHT, 8, DT_RIGHT, TRUE);\n    // Customizable columns\n    PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_COMMITTED, FALSE, L\"Committed\", 80, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_PRIVATE, FALSE, L\"Private\", 80, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_SIGNING_LEVEL, FALSE, L\"Signing level\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_ORIGINAL_PROTECTION, FALSE, L\"Original protection\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_ORIGINAL_PAGES, FALSE, L\"Original pages\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_REGIONTYPE, FALSE, L\"Region type\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_PRIORITY, FALSE, L\"Priority\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n\n    PhCmInitializeManager(&Context->Cm, TreeNewHandle, PHMMTLC_MAXIMUM, PhpMemoryTreeNewPostSortFunction);\n    PhInitializeTreeNewFilterSupport(&Context->AllocationTreeFilterSupport, TreeNewHandle, Context->AllocationBaseNodeList);\n    PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, TreeNewHandle, Context->RegionNodeList);\n\n    TreeNew_SetTriState(TreeNewHandle, TRUE);\n    TreeNew_SetRedraw(TreeNewHandle, TRUE);\n}\n\nVOID PhpClearMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Context->AllocationBaseNodeList->Count; i++)\n        PhpDestroyMemoryNode(Context->AllocationBaseNodeList->Items[i]);\n    for (i = 0; i < Context->RegionNodeList->Count; i++)\n        PhpDestroyMemoryNode(Context->RegionNodeList->Items[i]);\n\n    PhClearList(Context->AllocationBaseNodeList);\n    PhClearList(Context->RegionNodeList);\n}\n\nVOID PhDeleteMemoryList(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    )\n{\n    PhDeleteTreeNewFilterSupport(&Context->AllocationTreeFilterSupport);\n    PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport);\n    PhCmDeleteManager(&Context->Cm);\n\n    PhpClearMemoryList(Context);\n\n    PhDereferenceObject(Context->AllocationBaseNodeList);\n    PhDereferenceObject(Context->RegionNodeList);\n}\n\nVOID PhLoadSettingsMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context\n    )\n{\n    ULONG flags;\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    flags = PhGetIntegerSetting(SETTING_MEMORY_LIST_FLAGS);\n    settings = PhGetStringSetting(SETTING_MEMORY_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_MEMORY_TREE_LIST_SORT);\n\n    Context->Flags = flags;\n    PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSaveSettingsMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings);\n\n    PhSetIntegerSetting(SETTING_MEMORY_LIST_FLAGS, Context->Flags);\n    PhSetStringSetting2(SETTING_MEMORY_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_MEMORY_TREE_LIST_SORT, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSetOptionsMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ ULONG Options\n    )\n{\n    switch (Options)\n    {\n    case PH_MEMORY_FLAGS_FREE_OPTION:\n        Context->HideFreeRegions = !Context->HideFreeRegions;\n        break;\n    case PH_MEMORY_FLAGS_RESERVED_OPTION:\n        Context->HideReservedRegions = !Context->HideReservedRegions;\n        break;\n    case PH_MEMORY_FLAGS_PRIVATE_OPTION:\n        Context->HighlightPrivatePages = !Context->HighlightPrivatePages;\n        break;\n    case PH_MEMORY_FLAGS_SYSTEM_OPTION:\n        Context->HighlightSystemPages = !Context->HighlightSystemPages;\n        break;\n    case PH_MEMORY_FLAGS_CFG_OPTION:\n        Context->HighlightCfgPages = !Context->HighlightCfgPages;\n        break;\n    case PH_MEMORY_FLAGS_EXECUTE_OPTION:\n        Context->HighlightExecutePages = !Context->HighlightExecutePages;\n        break;\n    case PH_MEMORY_FLAGS_GUARD_OPTION:\n        Context->HideGuardRegions = !Context->HideGuardRegions;\n        break;\n    case PH_MEMORY_FLAGS_ZERO_PAD_ADDRESSES:\n        Context->ZeroPadAddresses = !Context->ZeroPadAddresses;\n        break;\n    }\n}\n\nVOID PhpDestroyMemoryNode(\n    _In_ PPH_MEMORY_NODE MemoryNode\n    )\n{\n    PhEmCallObjectOperation(EmMemoryNodeType, MemoryNode, EmObjectDelete);\n\n    if (MemoryNode->SizeText)\n        PhDereferenceObject(MemoryNode->SizeText);\n    if (MemoryNode->UseText)\n        PhDereferenceObject(MemoryNode->UseText);\n    if (MemoryNode->TotalWsText)\n        PhDereferenceObject(MemoryNode->TotalWsText);\n    if (MemoryNode->PrivateWsText)\n        PhDereferenceObject(MemoryNode->PrivateWsText);\n    if (MemoryNode->ShareableWsText)\n        PhDereferenceObject(MemoryNode->ShareableWsText);\n    if (MemoryNode->SharedWsText)\n        PhDereferenceObject(MemoryNode->SharedWsText);\n    if (MemoryNode->LockedWsText)\n        PhDereferenceObject(MemoryNode->LockedWsText);\n    if (MemoryNode->CommittedText)\n        PhDereferenceObject(MemoryNode->CommittedText);\n    if (MemoryNode->PrivateText)\n        PhDereferenceObject(MemoryNode->PrivateText);\n    if (MemoryNode->RegionTypeText)\n        PhDereferenceObject(MemoryNode->RegionTypeText);\n    if (MemoryNode->PriorityText)\n        PhDereferenceObject(MemoryNode->PriorityText);\n    if (MemoryNode->Children)\n        PhDereferenceObject(MemoryNode->Children);\n\n    PhDereferenceObject(MemoryNode->MemoryItem);\n\n    PhFree(MemoryNode);\n}\n\nPPH_MEMORY_NODE PhpAddAllocationBaseNode(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ PVOID AllocationBase\n    )\n{\n    PPH_MEMORY_NODE memoryNode;\n    PPH_MEMORY_ITEM memoryItem;\n\n    memoryNode = PhAllocate(PhEmGetObjectSize(EmMemoryNodeType, sizeof(PH_MEMORY_NODE)));\n    memset(memoryNode, 0, sizeof(PH_MEMORY_NODE));\n    PhInitializeTreeNewNode(&memoryNode->Node);\n    memoryNode->Node.Expanded = FALSE;\n\n    memoryNode->IsAllocationBase = TRUE;\n    memoryItem = PhCreateMemoryItem();\n    memoryNode->MemoryItem = memoryItem;\n    memoryItem->BaseAddress = AllocationBase;\n    memoryItem->AllocationBase = AllocationBase;\n\n    if (Context->ZeroPadAddresses)\n        PhPrintPointerPadZeros(memoryItem->BaseAddressString, memoryItem->BaseAddress);\n    else\n        PhPrintPointer(memoryItem->BaseAddressString, memoryItem->BaseAddress);\n\n    memoryNode->Children = PhCreateList(1);\n\n    memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);\n    memoryNode->Node.TextCache = memoryNode->TextCache;\n    memoryNode->Node.TextCacheSize = PHMMTLC_MAXIMUM;\n\n    PhAddItemList(Context->AllocationBaseNodeList, memoryNode);\n\n    if (Context->AllocationTreeFilterSupport.FilterList)\n        memoryNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->AllocationTreeFilterSupport, &memoryNode->Node);\n\n    PhEmCallObjectOperation(EmMemoryNodeType, memoryNode, EmObjectCreate);\n\n    return memoryNode;\n}\n\nPPH_MEMORY_NODE PhpAddRegionNode(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ PPH_MEMORY_ITEM MemoryItem\n    )\n{\n    PPH_MEMORY_NODE memoryNode;\n\n    memoryNode = PhAllocate(PhEmGetObjectSize(EmMemoryNodeType, sizeof(PH_MEMORY_NODE)));\n    memset(memoryNode, 0, sizeof(PH_MEMORY_NODE));\n    PhInitializeTreeNewNode(&memoryNode->Node);\n\n    memoryNode->IsAllocationBase = FALSE;\n    memoryNode->MemoryItem = MemoryItem;\n    PhReferenceObject(MemoryItem);\n\n    memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);\n    memoryNode->Node.TextCache = memoryNode->TextCache;\n    memoryNode->Node.TextCacheSize = PHMMTLC_MAXIMUM;\n\n    PhAddItemList(Context->RegionNodeList, memoryNode);\n\n    if (Context->TreeFilterSupport.FilterList)\n        memoryNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &memoryNode->Node);\n\n    PhEmCallObjectOperation(EmMemoryNodeType, memoryNode, EmObjectCreate);\n\n    return memoryNode;\n}\n\nVOID PhpCopyMemoryRegionTypeInfo(\n    _In_ PPH_MEMORY_ITEM Source,\n    _Inout_ PPH_MEMORY_ITEM Destination\n    )\n{\n    if (Destination->RegionType == CustomRegion)\n        PhClearReference(&Destination->u.Custom.Text);\n    else if (Destination->RegionType == MappedFileRegion)\n        PhClearReference(&Destination->u.MappedFile.FileName);\n\n    Destination->RegionTypeEx = Source->RegionTypeEx;\n    Destination->RegionType = Source->RegionType;\n    Destination->u = Source->u;\n\n    if (Destination->RegionType == CustomRegion)\n        PhReferenceObject(Destination->u.Custom.Text);\n    else if (Destination->RegionType == MappedFileRegion)\n        PhReferenceObject(Destination->u.MappedFile.FileName);\n}\n\nVOID PhReplaceMemoryList(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_opt_ PPH_MEMORY_ITEM_LIST List\n    )\n{\n    PLIST_ENTRY listEntry;\n    PPH_MEMORY_NODE allocationBaseNode = NULL;\n\n    PhpClearMemoryList(Context);\n\n    if (!List)\n    {\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n        return;\n    }\n\n    for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink)\n    {\n        PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry);\n        PPH_MEMORY_NODE memoryNode;\n\n        if (memoryItem->AllocationBaseItem == memoryItem)\n            allocationBaseNode = PhpAddAllocationBaseNode(Context, memoryItem->AllocationBase);\n\n        memoryNode = PhpAddRegionNode(Context, memoryItem);\n\n        if (Context->HideFreeRegions && (memoryItem->State & MEM_FREE))\n            memoryNode->Node.Visible = FALSE;\n        if (Context->HideGuardRegions && (memoryItem->Protect & PAGE_GUARD))\n            memoryNode->Node.Visible = FALSE;\n\n        if (allocationBaseNode && memoryItem->AllocationBase == allocationBaseNode->MemoryItem->BaseAddress)\n        {\n            if (!(memoryItem->State & MEM_FREE))\n            {\n                memoryNode->Parent = allocationBaseNode;\n                PhAddItemList(allocationBaseNode->Children, memoryNode);\n            }\n\n            // Aggregate various statistics.\n            allocationBaseNode->MemoryItem->RegionSize += memoryItem->RegionSize;\n            allocationBaseNode->MemoryItem->CommittedSize += memoryItem->CommittedSize;\n            allocationBaseNode->MemoryItem->PrivateSize += memoryItem->PrivateSize;\n            allocationBaseNode->MemoryItem->TotalWorkingSetPages += memoryItem->TotalWorkingSetPages;\n            allocationBaseNode->MemoryItem->PrivateWorkingSetPages += memoryItem->PrivateWorkingSetPages;\n            allocationBaseNode->MemoryItem->SharedWorkingSetPages += memoryItem->SharedWorkingSetPages;\n            allocationBaseNode->MemoryItem->ShareableWorkingSetPages += memoryItem->ShareableWorkingSetPages;\n            allocationBaseNode->MemoryItem->LockedWorkingSetPages += memoryItem->LockedWorkingSetPages;\n\n            if (memoryItem->AllocationBaseItem == memoryItem)\n            {\n                allocationBaseNode->MemoryItem->Protect = memoryItem->AllocationProtect;\n                allocationBaseNode->MemoryItem->State = memoryItem->State;\n                allocationBaseNode->MemoryItem->Type = memoryItem->Type;\n\n                PhGetMemoryProtectionString(allocationBaseNode->MemoryItem->Protect, allocationBaseNode->ProtectionText);\n                //PhGetMemoryProtectionString(allocationBaseNode->MemoryItem->AllocationProtect, allocationBaseNode->OriginalProtectionText);\n\n                if (memoryItem->RegionType != CustomRegion || memoryItem->u.Custom.PropertyOfAllocationBase)\n                    PhpCopyMemoryRegionTypeInfo(memoryItem, allocationBaseNode->MemoryItem);\n\n                if (Context->HideFreeRegions && (allocationBaseNode->MemoryItem->State & MEM_FREE))\n                    allocationBaseNode->Node.Visible = FALSE;\n                if (Context->HideGuardRegions && (allocationBaseNode->MemoryItem->State & PAGE_GUARD))\n                    allocationBaseNode->Node.Visible = FALSE;\n            }\n            else\n            {\n                if (memoryItem->RegionType == UnknownRegion)\n                    PhpCopyMemoryRegionTypeInfo(allocationBaseNode->MemoryItem, memoryItem);\n            }\n        }\n\n        PhGetMemoryProtectionString(memoryItem->Protect, memoryNode->ProtectionText);\n        PhGetMemoryProtectionString(memoryItem->AllocationProtect, memoryNode->OriginalProtectionText);\n    }\n\n    PhApplyTreeNewFilters(&Context->AllocationTreeFilterSupport);\n    PhApplyTreeNewFilters(&Context->TreeFilterSupport);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhRemoveMemoryNode(\n    _Inout_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ PPH_MEMORY_ITEM_LIST List,\n    _In_ PPH_MEMORY_NODE MemoryNode\n    )\n{\n    ULONG index;\n\n    // Remove from list and cleanup.\n\n    PhRemoveElementAvlTree(&List->Set, &MemoryNode->MemoryItem->Links);\n    RemoveEntryList(&MemoryNode->MemoryItem->ListEntry);\n\n    if ((index = PhFindItemList(Context->RegionNodeList, MemoryNode)) != ULONG_MAX)\n        PhRemoveItemList(Context->RegionNodeList, index);\n\n    if (MemoryNode->MemoryItem->AllocationBaseItem == MemoryNode->MemoryItem)\n    {\n        if ((index = PhFindItemList(Context->AllocationBaseNodeList, MemoryNode->Parent)) != ULONG_MAX)\n            PhRemoveItemList(Context->AllocationBaseNodeList, index);\n    }\n\n    PhpDestroyMemoryNode(MemoryNode);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhUpdateMemoryNode(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ PPH_MEMORY_NODE MemoryNode\n    )\n{\n    PhGetMemoryProtectionString(MemoryNode->MemoryItem->Protect, MemoryNode->ProtectionText);\n    PhGetMemoryProtectionString(MemoryNode->MemoryItem->AllocationProtect, MemoryNode->OriginalProtectionText);\n    memset(MemoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);\n    TreeNew_InvalidateNode(Context->TreeNewHandle, &MemoryNode->Node);\n}\n\nVOID PhInvalidateAllMemoryNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Context->AllocationBaseNodeList->Count; i++)\n    {\n        PPH_MEMORY_NODE memoryNode = Context->AllocationBaseNodeList->Items[i];\n\n        memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);\n        TreeNew_InvalidateNode(Context->TreeNewHandle, &memoryNode->Node);\n    }\n\n    for (i = 0; i < Context->RegionNodeList->Count; i++)\n    {\n        PPH_MEMORY_NODE memoryNode = Context->RegionNodeList->Items[i];\n\n        memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);\n        TreeNew_InvalidateNode(Context->TreeNewHandle, &memoryNode->Node);\n    }\n\n    InvalidateRect(Context->TreeNewHandle, NULL, FALSE);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhInvalidateAllMemoryBaseAddressNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Context->AllocationBaseNodeList->Count; i++)\n    {\n        PPH_MEMORY_NODE memoryNode = Context->AllocationBaseNodeList->Items[i];\n\n        if (Context->ZeroPadAddresses)\n            PhPrintPointerPadZeros(memoryNode->MemoryItem->BaseAddressString, memoryNode->MemoryItem->BaseAddress);\n        else\n            PhPrintPointer(memoryNode->MemoryItem->BaseAddressString, memoryNode->MemoryItem->BaseAddress);\n\n        memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);\n        //TreeNew_InvalidateNode(Context->TreeNewHandle, &memoryNode->Node);\n    }\n\n    for (i = 0; i < Context->RegionNodeList->Count; i++)\n    {\n        PPH_MEMORY_NODE memoryNode = Context->RegionNodeList->Items[i];\n\n        if (Context->ZeroPadAddresses)\n            PhPrintPointerPadZeros(memoryNode->MemoryItem->BaseAddressString, memoryNode->MemoryItem->BaseAddress);\n        else\n            PhPrintPointer(memoryNode->MemoryItem->BaseAddressString, memoryNode->MemoryItem->BaseAddress);\n\n        memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);\n        //TreeNew_InvalidateNode(Context->TreeNewHandle, &memoryNode->Node);\n    }\n\n    InvalidateRect(Context->TreeNewHandle, NULL, FALSE);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhExpandAllMemoryNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context,\n    _In_ BOOLEAN Expand\n    )\n{\n    ULONG i;\n    BOOLEAN needsRestructure = FALSE;\n\n    for (i = 0; i < Context->AllocationBaseNodeList->Count; i++)\n    {\n        PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i];\n\n        if (node->Node.Expanded != Expand)\n        {\n            node->Node.Expanded = Expand;\n            needsRestructure = TRUE;\n        }\n    }\n\n    for (i = 0; i < Context->RegionNodeList->Count; i++)\n    {\n        PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i];\n\n        if (node->Node.Expanded != Expand)\n        {\n            node->Node.Expanded = Expand;\n            needsRestructure = TRUE;\n        }\n    }\n\n    if (needsRestructure)\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nextern PCWSTR PhGetProcessHeapClassText(\n    _In_ ULONG HeapClass\n    );\n\nPPH_STRING PhGetMemoryRegionUseText(\n    _In_ PPH_MEMORY_ITEM MemoryItem\n    )\n{\n    PH_MEMORY_REGION_TYPE type = MemoryItem->RegionType;\n\n    switch (type)\n    {\n    case UnknownRegion:\n        return NULL;\n    case CustomRegion:\n        PhReferenceObject(MemoryItem->u.Custom.Text);\n        return MemoryItem->u.Custom.Text;\n    case UnusableRegion:\n        return NULL;\n    case MappedFileRegion:\n        PhReferenceObject(MemoryItem->u.MappedFile.FileName);\n        return MemoryItem->u.MappedFile.FileName;\n    case UserSharedDataRegion:\n        return PhCreateString(L\"USER_SHARED_DATA\");\n    case HypervisorSharedDataRegion:\n        return PhCreateString(L\"HYPERVISOR_SHARED_DATA\");\n    case PebRegion:\n    case Peb32Region:\n        return PhFormatString(L\"PEB%s\", type == Peb32Region ? L\" 32-bit\" : L\"\");\n    case TebRegion:\n    case Teb32Region:\n        return PhFormatString(L\"TEB%s (thread %lu)\",\n            type == Teb32Region ? L\" 32-bit\" : L\"\", HandleToUlong(MemoryItem->u.Teb.ThreadId));\n    case StackRegion:\n    case Stack32Region:\n        return PhFormatString(L\"Stack%s (thread %lu)\",\n            type == Stack32Region ? L\" 32-bit\" : L\"\", HandleToUlong(MemoryItem->u.Stack.ThreadId));\n    case HeapRegion:\n    case Heap32Region:\n        return PhFormatString(L\"%s%s (ID %lu)\",\n            MemoryItem->u.Heap.ClassValid ? PhGetProcessHeapClassText(MemoryItem->u.Heap.Class) : L\"Heap\",\n            type == Heap32Region ? L\" 32-bit\" : L\"\", (ULONG)MemoryItem->u.Heap.Index + 1);\n    case HeapSegmentRegion:\n    case HeapSegment32Region:\n        return PhFormatString(L\"%s Segment%s (ID %lu)\",\n            MemoryItem->u.HeapSegment.HeapItem->u.Heap.ClassValid ? PhGetProcessHeapClassText(MemoryItem->u.HeapSegment.HeapItem->u.Heap.Class) : L\"Heap\",\n            type == HeapSegment32Region ? L\" 32-bit\" : L\"\", (ULONG)MemoryItem->u.HeapSegment.HeapItem->u.Heap.Index + 1);\n    case CfgBitmapRegion:\n    case CfgBitmap32Region:\n        return PhFormatString(L\"CFG Bitmap%s\",\n            type == CfgBitmap32Region ? L\" 32-bit\" : L\"\");\n    case ApiSetMapRegion:\n        return PhFormatString(L\"ApiSetMap\");\n    case ReadOnlySharedMemoryRegion:\n        return PhFormatString(L\"CSR shared memory\");\n    case CodePageDataRegion:\n        return PhFormatString(L\"CodePage data\");\n    case GdiSharedHandleTableRegion:\n        return PhFormatString(L\"GDI shared handle table\");\n    case ShimDataRegion:\n        return PhFormatString(L\"Shim data\");\n    case ActivationContextDataRegion:\n        switch (MemoryItem->u.ActivationContextData.Type)\n        {\n        case ProcessActivationContext:\n            return PhFormatString(L\"Process activation context data\");\n        case SystemActivationContext:\n            return PhFormatString(L\"System activation context data\");\n        default:\n            return PhFormatString(L\"Activation context data\");\n        }\n    case WerRegistrationDataRegion:\n        return PhFormatString(L\"WER registration data\");\n    case SiloSharedDataRegion:\n        return PhFormatString(L\"Silo shared data\");\n    case TelemetryCoverageRegion:\n        return PhFormatString(L\"Telemetry coverage map\");\n    case ProcessParametersRegion:\n        return PhFormatString(L\"USER_PROCESS_PARAMETERS\");\n    case LeapSecondDataRegion:\n        return PhFormatString(L\"LEAP_SECOND_DATA\");\n    case DesktopHeapRegion:\n        return PhFormatString(L\"Desktop heap\");\n    default:\n        return NULL;\n    }\n}\n\nVOID PhpUpdateMemoryNodeUseText(\n    _Inout_ PPH_MEMORY_NODE MemoryNode\n    )\n{\n    if (!MemoryNode->UseText)\n        MemoryNode->UseText = PhGetMemoryRegionUseText(MemoryNode->MemoryItem);\n}\n\nVOID PhpUpdateMemoryRegionTypeExText(\n    _Inout_ PPH_MEMORY_NODE MemoryNode\n    )\n{\n    if (MemoryNode->IsAllocationBase)\n        return;\n\n    if (!MemoryNode->RegionTypeText)\n        MemoryNode->RegionTypeText = PhGetMemoryRegionTypeExString(MemoryNode->MemoryItem);\n}\n\nPPH_STRING PhpFormatSizeIfNonZero(\n    _In_ ULONG64 Size\n    )\n{\n    if (Size != 0)\n        return PhFormatSize(Size, ULONG_MAX);\n    else\n        return NULL;\n}\n\n#define SORT_FUNCTION(Column) PhpMemoryTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpMemoryTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_MEMORY_NODE node1 = *(PPH_MEMORY_NODE *)_elem1; \\\n    PPH_MEMORY_NODE node2 = *(PPH_MEMORY_NODE *)_elem2; \\\n    PPH_MEMORY_ITEM memoryItem1 = node1->MemoryItem; \\\n    PPH_MEMORY_ITEM memoryItem2 = node2->MemoryItem; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress); \\\n    \\\n    return PhModifySort(sortResult, ((PPH_MEMORY_LIST_CONTEXT)_context)->TreeNewSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpMemoryTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    if (Result == 0)\n        Result = uintptrcmp((ULONG_PTR)((PPH_MEMORY_NODE)Node1)->MemoryItem->BaseAddress, (ULONG_PTR)((PPH_MEMORY_NODE)Node2)->MemoryItem->BaseAddress);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(BaseAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Type)\n{\n    sortResult = uintcmp(memoryItem1->Type | memoryItem1->State, memoryItem2->Type | memoryItem2->State);\n\n    if (sortResult == 0)\n        sortResult = intcmp(memoryItem1->RegionType, memoryItem2->RegionType);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Size)\n{\n    sortResult = uintptrcmp(memoryItem1->RegionSize, memoryItem2->RegionSize);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Protection)\n{\n    sortResult = PhCompareStringZ(node1->ProtectionText, node2->ProtectionText, FALSE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Use)\n{\n    PhpUpdateMemoryNodeUseText(node1);\n    PhpUpdateMemoryNodeUseText(node2);\n    sortResult = PhCompareStringWithNull(node1->UseText, node2->UseText, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(TotalWs)\n{\n    sortResult = uintptrcmp(memoryItem1->TotalWorkingSetPages, memoryItem2->TotalWorkingSetPages);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PrivateWs)\n{\n    sortResult = uintptrcmp(memoryItem1->PrivateWorkingSetPages, memoryItem2->PrivateWorkingSetPages);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ShareableWs)\n{\n    sortResult = uintptrcmp(memoryItem1->ShareableWorkingSetPages, memoryItem2->ShareableWorkingSetPages);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(SharedWs)\n{\n    sortResult = uintptrcmp(memoryItem1->SharedWorkingSetPages, memoryItem2->SharedWorkingSetPages);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LockedWs)\n{\n    sortResult = uintptrcmp(memoryItem1->LockedWorkingSetPages, memoryItem2->LockedWorkingSetPages);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Committed)\n{\n    sortResult = uintptrcmp(memoryItem1->CommittedSize, memoryItem2->CommittedSize);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Private)\n{\n    sortResult = uintptrcmp(memoryItem1->PrivateSize, memoryItem2->PrivateSize);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(SigningLevel)\n{\n    sortResult = shortcmp(\n        memoryItem1->RegionType == MappedFileRegion && memoryItem1->u.MappedFile.SigningLevelValid ? memoryItem1->u.MappedFile.SigningLevel : -1,\n        memoryItem2->RegionType == MappedFileRegion && memoryItem2->u.MappedFile.SigningLevelValid ? memoryItem2->u.MappedFile.SigningLevel : -1\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(OriginalProtection)\n{\n    sortResult = PhCompareStringZ(node1->OriginalProtectionText, node2->OriginalProtectionText, FALSE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(OriginalPages)\n{\n    FLOAT modified1 = memoryItem1->SharedOriginalPages ? (memoryItem1->SharedOriginalPages / (memoryItem1->RegionSize / PAGE_SIZE) * 100.f) : 0.0f;\n    FLOAT modified2 = memoryItem2->SharedOriginalPages ? (memoryItem2->SharedOriginalPages / (memoryItem2->RegionSize / PAGE_SIZE) * 100.f) : 0.0f;\n\n    sortResult = singlecmp(modified1, modified2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(RegionType)\n{\n    PhpUpdateMemoryRegionTypeExText(node1);\n    PhpUpdateMemoryRegionTypeExText(node2);\n    sortResult = PhCompareStringWithNull(node1->RegionTypeText, node2->RegionTypeText, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Priority)\n{\n    sortResult = uintptrcmp(memoryItem1->Priority, memoryItem2->Priority);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpMemoryTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_MEMORY_LIST_CONTEXT context = Context;\n    PPH_MEMORY_NODE node;\n\n    if (PhCmForwardMessage(WindowHandle, Message, Parameter1, Parameter2, &context->Cm))\n        return TRUE;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_MEMORY_NODE)getChildren->Node;\n\n            if (context->TreeNewSortOrder == NoSortOrder)\n            {\n                if (!node)\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)context->AllocationBaseNodeList->Items;\n                    getChildren->NumberOfChildren = context->AllocationBaseNodeList->Count;\n                }\n                else\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;\n                    getChildren->NumberOfChildren = node->Children->Count;\n                }\n            }\n            else\n            {\n                if (!node)\n                {\n                    static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                    {\n                        SORT_FUNCTION(BaseAddress),\n                        SORT_FUNCTION(Type),\n                        SORT_FUNCTION(Size),\n                        SORT_FUNCTION(Protection),\n                        SORT_FUNCTION(Use),\n                        SORT_FUNCTION(TotalWs),\n                        SORT_FUNCTION(PrivateWs),\n                        SORT_FUNCTION(ShareableWs),\n                        SORT_FUNCTION(SharedWs),\n                        SORT_FUNCTION(LockedWs),\n                        SORT_FUNCTION(Committed),\n                        SORT_FUNCTION(Private),\n                        SORT_FUNCTION(SigningLevel),\n                        SORT_FUNCTION(OriginalProtection),\n                        SORT_FUNCTION(OriginalPages),\n                        SORT_FUNCTION(RegionType),\n                        SORT_FUNCTION(Priority),\n                    };\n                    _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                    static_assert(RTL_NUMBER_OF(sortFunctions) == PHMMTLC_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                    if (!PhCmForwardSort(\n                        (PPH_TREENEW_NODE *)context->RegionNodeList->Items,\n                        context->RegionNodeList->Count,\n                        context->TreeNewSortColumn,\n                        context->TreeNewSortOrder,\n                        &context->Cm\n                        ))\n                    {\n                        if (context->TreeNewSortColumn < PHMMTLC_MAXIMUM)\n                            sortFunction = sortFunctions[context->TreeNewSortColumn];\n                        else\n                            sortFunction = NULL;\n                    }\n                    else\n                    {\n                        sortFunction = NULL;\n                    }\n\n                    if (sortFunction)\n                    {\n                        qsort_s(context->RegionNodeList->Items, context->RegionNodeList->Count, sizeof(PVOID), sortFunction, context);\n                    }\n\n                    getChildren->Children = (PPH_TREENEW_NODE *)context->RegionNodeList->Items;\n                    getChildren->NumberOfChildren = context->RegionNodeList->Count;\n                }\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n            node = (PPH_MEMORY_NODE)isLeaf->Node;\n\n            if (context->TreeNewSortOrder == NoSortOrder)\n                isLeaf->IsLeaf = !node->Children || node->Children->Count == 0;\n            else\n                isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            PPH_MEMORY_ITEM memoryItem;\n\n            node = (PPH_MEMORY_NODE)getCellText->Node;\n            memoryItem = node->MemoryItem;\n\n            switch (getCellText->Id)\n            {\n            case PHMMTLC_BASEADDRESS:\n                PhInitializeStringRefLongHint(&getCellText->Text, memoryItem->BaseAddressString);\n                break;\n            case PHMMTLC_TYPE:\n                {\n                    if (FlagOn(memoryItem->State, MEM_FREE))\n                    {\n                        if (memoryItem->RegionType == UnusableRegion)\n                            PhInitializeStringRef(&getCellText->Text, L\"Free (Unusable)\");\n                        else\n                            PhInitializeStringRef(&getCellText->Text, L\"Free\");\n                    }\n                    else if (node->IsAllocationBase)\n                    {\n                        PCPH_STRINGREF string;\n\n                        if (string = PhGetMemoryTypeString(memoryItem->Type))\n                        {\n                            getCellText->Text.Length = string->Length;\n                            getCellText->Text.Buffer = string->Buffer;\n                        }\n                        else\n                        {\n                            PhInitializeEmptyStringRef(&getCellText->Text);\n                        }\n                    }\n                    else\n                    {\n                        PH_FORMAT format[3];\n                        SIZE_T returnLength;\n\n                        PhInitFormatSR(&format[0], *PhGetMemoryTypeString(memoryItem->Type));\n                        PhInitFormatS(&format[1], L\": \");\n                        PhInitFormatSR(&format[2], *PhGetMemoryStateString(memoryItem->State));\n\n                        if (PhFormatToBuffer(format, 3, node->TypeText, sizeof(node->TypeText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->TypeText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                }\n                break;\n            case PHMMTLC_SIZE:\n                {\n                    PhMoveReference(&node->SizeText, PhFormatSize(memoryItem->RegionSize, ULONG_MAX));\n                    getCellText->Text = PhGetStringRef(node->SizeText);\n                }\n                break;\n            case PHMMTLC_PROTECTION:\n                {\n                    if (node->ProtectionText[0] != UNICODE_NULL)\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->ProtectionText);\n                }\n                break;\n            case PHMMTLC_USE:\n                {\n                    PhpUpdateMemoryNodeUseText(node);\n                    getCellText->Text = PhGetStringRef(node->UseText);\n                }\n                break;\n            case PHMMTLC_TOTALWS:\n                {\n                    PhMoveReference(&node->TotalWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->TotalWorkingSetPages * PAGE_SIZE));\n                    getCellText->Text = PhGetStringRef(node->TotalWsText);\n                }\n                break;\n            case PHMMTLC_PRIVATEWS:\n                {\n                    PhMoveReference(&node->PrivateWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->PrivateWorkingSetPages * PAGE_SIZE));\n                    getCellText->Text = PhGetStringRef(node->PrivateWsText);\n                }\n                break;\n            case PHMMTLC_SHAREABLEWS:\n                {\n                    PhMoveReference(&node->ShareableWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->ShareableWorkingSetPages * PAGE_SIZE));\n                    getCellText->Text = PhGetStringRef(node->ShareableWsText);\n                }\n                break;\n            case PHMMTLC_SHAREDWS:\n                {\n                    PhMoveReference(&node->SharedWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->SharedWorkingSetPages * PAGE_SIZE));\n                    getCellText->Text = PhGetStringRef(node->SharedWsText);\n                }\n                break;\n            case PHMMTLC_LOCKEDWS:\n                {\n                    PhMoveReference(&node->LockedWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->LockedWorkingSetPages * PAGE_SIZE));\n                    getCellText->Text = PhGetStringRef(node->LockedWsText);\n                }\n                break;\n            case PHMMTLC_COMMITTED:\n                {\n                    PhMoveReference(&node->CommittedText, PhpFormatSizeIfNonZero(memoryItem->CommittedSize));\n                    getCellText->Text = PhGetStringRef(node->CommittedText);\n                }\n                break;\n            case PHMMTLC_PRIVATE:\n                {\n                    PhMoveReference(&node->PrivateText, PhpFormatSizeIfNonZero(memoryItem->PrivateSize));\n                    getCellText->Text = PhGetStringRef(node->PrivateText);\n                }\n                break;\n            case PHMMTLC_SIGNING_LEVEL:\n                {\n                    if (memoryItem->RegionType == MappedFileRegion && memoryItem->u.MappedFile.SigningLevelValid)\n                    {\n                        PCPH_STRINGREF string;\n\n                        if (string = PhGetSigningLevelString(memoryItem->u.MappedFile.SigningLevel))\n                        {\n                            getCellText->Text.Length = string->Length;\n                            getCellText->Text.Buffer = string->Buffer;\n                        }\n                    }\n                }\n                break;\n            case PHMMTLC_ORIGINAL_PROTECTION:\n                {\n                    if (node->OriginalProtectionText[0] != UNICODE_NULL)\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->OriginalProtectionText);\n                }\n                break;\n            case PHMMTLC_ORIGINAL_PAGES:\n                {\n                    if (node->IsAllocationBase)\n                        break;\n\n                    if (memoryItem->State & MEM_COMMIT && (memoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))\n                    {\n                        SIZE_T count = memoryItem->SharedOriginalPages;\n                        SIZE_T modified = (memoryItem->RegionSize / PAGE_SIZE) - count;\n                        PH_FORMAT format[4];\n\n                        PhInitFormatF(&format[0], count ? (count / (memoryItem->RegionSize / PAGE_SIZE) * 100) : 0.f, 2);\n\n                        if (modified)\n                        {\n                            PhInitFormatS(&format[1], L\"% (\");\n                            PhInitFormatI64U(&format[2], modified);\n                            PhInitFormatS(&format[3], L\")\");\n                            PhMoveReference(&node->OriginalPagesText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                        }\n                        else\n                        {\n                            PhInitFormatS(&format[1], L\"%\");\n                            PhMoveReference(&node->OriginalPagesText, PhFormat(format, 2, 0));\n                        }\n\n                        getCellText->Text = PhGetStringRef(node->OriginalPagesText);\n                    }\n                }\n                break;\n            case PHMMTLC_REGIONTYPE:\n                {\n                    PhpUpdateMemoryRegionTypeExText(node);\n                    getCellText->Text = PhGetStringRef(node->RegionTypeText);\n                }\n                break;\n            case PHMMTLC_PRIORITY:\n                {\n                    if (memoryItem->Priority != 0)\n                    {\n                        PH_FORMAT format[4];\n\n                        PhInitFormatSR(&format[0], *PhGetMemoryPagePriorityString((ULONG)memoryItem->Priority));\n                        PhInitFormatS(&format[1], L\" (\");\n                        PhInitFormatU(&format[2], (ULONG)memoryItem->Priority);\n                        PhInitFormatS(&format[3], L\")\");\n\n                        PhMoveReference(&node->PriorityText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                        getCellText->Text = PhGetStringRef(node->PriorityText);\n                    }\n                }\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            PPH_MEMORY_ITEM memoryItem;\n\n            node = (PPH_MEMORY_NODE)getNodeColor->Node;\n            memoryItem = node->MemoryItem;\n\n            if (!memoryItem)\n                NOTHING;\n            else if (\n                context->HighlightExecutePages && (\n                memoryItem->Protect & PAGE_EXECUTE ||\n                memoryItem->Protect & PAGE_EXECUTE_READ ||\n                memoryItem->Protect & PAGE_EXECUTE_READWRITE ||\n                memoryItem->Protect & PAGE_EXECUTE_WRITECOPY\n                ))\n            {\n                getNodeColor->BackColor = PhCsColorPacked;\n            }\n            else if (\n                context->HighlightCfgPages && (\n                memoryItem->RegionType == CfgBitmapRegion ||\n                memoryItem->RegionType == CfgBitmap32Region\n                ))\n            {\n                getNodeColor->BackColor = PhCsColorElevatedProcesses;\n            }\n            else if (\n                context->HighlightSystemPages && (\n                memoryItem->Type & SEC_IMAGE\n                ))\n            {\n                getNodeColor->BackColor = PhCsColorSystemProcesses;\n            }\n            else if (context->HighlightPrivatePages && memoryItem->Type & MEM_PRIVATE)\n            {\n                getNodeColor->BackColor = PhCsColorOwnProcesses;\n            }\n            //else if (\n            //    memoryItem->RegionType == StackRegion || memoryItem->RegionType == Stack32Region ||\n            //    memoryItem->RegionType == HeapRegion || memoryItem->RegionType == Heap32Region ||\n            //    memoryItem->RegionType == HeapSegmentRegion || memoryItem->RegionType == HeapSegment32Region\n            //    ((memoryItem->Protect & PAGE_EXECUTE_WRITECOPY || memoryItem->Protect & PAGE_EXECUTE_READWRITE ||\n            //    memoryItem->Protect & PAGE_READWRITE) && !(memoryItem->Type & SEC_IMAGE))\n            //    )\n            //{\n            //    getNodeColor->BackColor = PhCsColorElevatedProcesses;\n            //}\n            //else if (memoryItem->Type & SEC_IMAGE)\n            //    getNodeColor->BackColor = PhCsColorImmersiveProcesses;\n\n            getNodeColor->Flags = TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_COPY, 0);\n                break;\n            case VK_RETURN:\n                SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_READWRITEMEMORY, 0);\n                break;\n            case VK_F5:\n                SendMessage(context->ParentWindowHandle, WM_COMMAND, IDC_REFRESH, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = 0;\n            data.DefaultSortOrder = NoSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1;\n            node = (PPH_MEMORY_NODE)mouseEvent->Node;\n\n            if (node && node->IsAllocationBase)\n                TreeNew_SetNodeExpanded(WindowHandle, node, !node->Node.Expanded);\n            else\n                SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_READWRITEMEMORY, 0);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n\n            SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu);\n        }\n        return TRUE;\n    case TreeNewGetDialogCode:\n        {\n            PULONG code = Parameter2;\n\n            if (PtrToUlong(Parameter1) == VK_RETURN)\n            {\n                *code = DLGC_WANTMESSAGE;\n                return TRUE;\n            }\n        }\n        return FALSE;\n    }\n\n    return FALSE;\n}\n\nPPH_MEMORY_NODE PhGetSelectedMemoryNode(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    if (Context->TreeNewSortOrder == NoSortOrder)\n    {\n        for (i = 0; i < Context->AllocationBaseNodeList->Count; i++)\n        {\n            PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i];\n\n            if (node->Node.Selected)\n                return node;\n        }\n    }\n\n    for (i = 0; i < Context->RegionNodeList->Count; i++)\n    {\n        PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i];\n\n        if (node->Node.Selected)\n            return node;\n    }\n\n    return NULL;\n}\n\nVOID PhGetSelectedMemoryNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context,\n    _Out_ PPH_MEMORY_NODE **MemoryNodes,\n    _Out_ PULONG NumberOfMemoryNodes\n    )\n{\n    PH_ARRAY array;\n    ULONG i;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    if (Context->TreeNewSortOrder == NoSortOrder)\n    {\n        for (i = 0; i < Context->AllocationBaseNodeList->Count; i++)\n        {\n            PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i];\n\n            if (node->Node.Selected)\n                PhAddItemArray(&array, &node);\n        }\n    }\n\n    for (i = 0; i < Context->RegionNodeList->Count; i++)\n    {\n        PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i];\n\n        if (node->Node.Selected)\n            PhAddItemArray(&array, &node);\n    }\n\n    *NumberOfMemoryNodes = (ULONG)PhFinalArrayCount(&array);\n    *MemoryNodes = PhFinalArrayItems(&array);\n}\n\nVOID PhDeselectAllMemoryNodes(\n    _In_ PPH_MEMORY_LIST_CONTEXT Context\n    )\n{\n    TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1);\n}\n"
  },
  {
    "path": "SystemInformer/memlists.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *     dmex    2017-2024\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <emenu.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <actions.h>\n#include <phsvccl.h>\n#include <kphuser.h>\n#include <ksisup.h>\n\n#define MSG_UPDATE (WM_APP + 1)\n\nINT_PTR CALLBACK PhpMemoryListsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nHWND PhMemoryListsWindowHandle = NULL;\nstatic VOID (NTAPI *UnregisterDialogFunction)(HWND);\nstatic PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;\n\nVOID PhShowMemoryListsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_opt_ VOID (NTAPI *RegisterDialog)(HWND),\n    _In_opt_ VOID (NTAPI *UnregisterDialog)(HWND)\n    )\n{\n    if (!PhMemoryListsWindowHandle)\n    {\n        PhMemoryListsWindowHandle = PhCreateDialog(\n            PhInstanceHandle,\n            MAKEINTRESOURCE(IDD_MEMLISTS),\n            ParentWindowHandle,\n            PhpMemoryListsDlgProc,\n            NULL\n            );\n\n        if (RegisterDialog)\n            RegisterDialog(PhMemoryListsWindowHandle);\n        UnregisterDialogFunction = UnregisterDialog;\n    }\n\n    if (!IsWindowVisible(PhMemoryListsWindowHandle))\n        ShowWindow(PhMemoryListsWindowHandle, SW_SHOW);\n    else if (IsMinimized(PhMemoryListsWindowHandle))\n        ShowWindow(PhMemoryListsWindowHandle, SW_RESTORE);\n    else\n        SetForegroundWindow(PhMemoryListsWindowHandle);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ProcessesUpdatedCallback(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    if (PhMemoryListsWindowHandle)\n    {\n        PostMessage(PhMemoryListsWindowHandle, MSG_UPDATE, 0, 0);\n    }\n}\n\nstatic VOID PhpUpdateMemoryListInfo(\n    _In_ HWND hwndDlg\n    )\n{\n    SYSTEM_MEMORY_LIST_INFORMATION memoryListInfo;\n\n    if (NT_SUCCESS(NtQuerySystemInformation(\n        SystemMemoryListInformation,\n        &memoryListInfo,\n        sizeof(SYSTEM_MEMORY_LIST_INFORMATION),\n        NULL\n        )))\n    {\n        ULONG_PTR standbyPageCount;\n        ULONG_PTR repurposedPageCount;\n        ULONG i;\n\n        standbyPageCount = 0;\n        repurposedPageCount = 0;\n\n        for (i = 0; i < 8; i++)\n        {\n            standbyPageCount += memoryListInfo.PageCountByPriority[i];\n            repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i];\n        }\n\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTBAD_V, PhaFormatSize((ULONG64)memoryListInfo.BadPageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, PhaFormatSize((ULONG64)repurposedPageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[0] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[1] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[2] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[3] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[4] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[5] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[6] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[7] * PAGE_SIZE, ULONG_MAX)->Buffer);\n\n        if (WindowsVersion >= WINDOWS_8)\n            PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, ULONG_MAX)->Buffer);\n        else\n            PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L\"N/A\");\n    }\n    else\n    {\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTZEROED_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTFREE_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIED_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTBAD_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, L\"Unknown\");\n        PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, L\"Unknown\");\n    }\n}\n\ntypedef\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID\nNTAPI\nPH_MEMORY_LIST_COMMAND_CALLBACK(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    );\ntypedef PH_MEMORY_LIST_COMMAND_CALLBACK *PPH_MEMORY_LIST_COMMAND_CALLBACK;\n\nPPH_STRING PhpCreateCommandStatusString(\n    _In_ PCWSTR Message,\n    _In_ NTSTATUS Status\n    )\n{\n    PPH_STRING string;\n    PPH_STRING statusString;\n\n    if (statusString = PhGetStatusMessage(Status, 0))\n    {\n        PH_FORMAT format[3];\n\n        PhInitFormatS(&format[0], Message);\n        PhInitFormatC(&format[1], L' ');\n        PhInitFormatSR(&format[2], statusString->sr);\n\n        string = PhFormat(format, RTL_NUMBER_OF(format), 10);\n\n        PhDereferenceObject(statusString);\n    }\n    else\n    {\n        string = PhCreateString(Message);\n    }\n\n    return string;\n}\n\nNTSTATUS PhpMemoryListCommandCommon(\n    _In_ HWND ParentWindow,\n    _In_ SYSTEM_MEMORY_LIST_COMMAND Command\n    )\n{\n    NTSTATUS status;\n\n    PhSetCursor(PhLoadCursor(NULL, IDC_WAIT));\n    status = NtSetSystemInformation(\n        SystemMemoryListInformation,\n        &Command,\n        sizeof(SYSTEM_MEMORY_LIST_COMMAND)\n        );\n    PhSetCursor(PhLoadCursor(NULL, IDC_ARROW));\n\n    if (status == STATUS_PRIVILEGE_NOT_HELD)\n    {\n        if (!PhGetOwnTokenAttributes().Elevated)\n        {\n            if (PhUiConnectToPhSvc(ParentWindow, FALSE))\n            {\n                PhSetCursor(PhLoadCursor(NULL, IDC_WAIT));\n                status = PhSvcCallIssueMemoryListCommand(Command);\n                PhSetCursor(PhLoadCursor(NULL, IDC_ARROW));\n                PhUiDisconnectFromPhSvc();\n            }\n            else\n            {\n                // User cancelled elevation.\n                status = STATUS_SUCCESS;\n            }\n        }\n    }\n\n    return status;\n}\n\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID NTAPI PhpEmptyWorkingSetsCommand(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    )\n{\n    NTSTATUS status;\n\n    status = PhpMemoryListCommandCommon(ParentWindow, MemoryEmptyWorkingSets);\n\n    if (NT_SUCCESS(status))\n        *Message = PhCreateString(L\"Working sets emptied.\");\n    else\n        *Message = PhpCreateCommandStatusString(L\"Unable to empty working sets.\", status);\n}\n\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID NTAPI PhpFlushModifiedListCommand(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    )\n{\n    NTSTATUS status;\n\n    status = PhpMemoryListCommandCommon(ParentWindow, MemoryFlushModifiedList);\n\n    if (NT_SUCCESS(status))\n        *Message = PhCreateString(L\"Modified page lists emptied.\");\n    else\n        *Message = PhpCreateCommandStatusString(L\"Unable to empty modified page lists.\", status);\n}\n\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID NTAPI PhpPurgeStandbyListCommand(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    )\n{\n    NTSTATUS status;\n\n    status = PhpMemoryListCommandCommon(ParentWindow, MemoryPurgeStandbyList);\n\n    if (NT_SUCCESS(status))\n        *Message = PhCreateString(L\"Standby lists emptied.\");\n    else\n        *Message = PhpCreateCommandStatusString(L\"Unable to empty standby lists.\", status);\n}\n\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID NTAPI PhpPurgeLowPriorityStandbyListCommand(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    )\n{\n    NTSTATUS status;\n\n    status = PhpMemoryListCommandCommon(ParentWindow, MemoryPurgeLowPriorityStandbyList);\n\n    if (NT_SUCCESS(status))\n        *Message = PhCreateString(L\"Priority 0 standby list emptied.\");\n    else\n        *Message = PhpCreateCommandStatusString(L\"Unable to empty priority 0 standby list.\", status);\n}\n\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID NTAPI PhpCombineMemoryListsCommand(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    )\n{\n    NTSTATUS status;\n    MEMORY_COMBINE_INFORMATION_EX combineInfo = { 0 };\n\n    PhSetCursor(PhLoadCursor(NULL, IDC_WAIT));\n    status = NtSetSystemInformation(\n        SystemCombinePhysicalMemoryInformation,\n        &combineInfo,\n        sizeof(MEMORY_COMBINE_INFORMATION_EX)\n        );\n    PhSetCursor(PhLoadCursor(NULL, IDC_ARROW));\n\n    if (NT_SUCCESS(status))\n    {\n        PH_FORMAT format[5];\n\n        // Memory pages combined: %s (%llu pages)\n        PhInitFormatS(&format[0], L\"Memory pages combined: \");\n        PhInitFormatSize(&format[1], combineInfo.PagesCombined * PAGE_SIZE);\n        PhInitFormatS(&format[2], L\" (\");\n        PhInitFormatI64U(&format[3], combineInfo.PagesCombined);\n        PhInitFormatS(&format[4], L\" pages)\");\n\n        *Message = PhFormat(format, RTL_NUMBER_OF(format), 0);\n    }\n    else\n    {\n        *Message = PhpCreateCommandStatusString(L\"Unable to combine memory pages.\", status);\n    }\n}\n\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID NTAPI PhpEmptyCompressionStoreCommand(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    )\n{\n    NTSTATUS status;\n\n    if (KsiLevel() < KphLevelMax)\n    {\n        PhShowKsiNotConnected(\n            ParentWindow,\n            L\"Emptying the compression store requires a connection to the kernel driver.\"\n            );\n\n        *Message = NULL;\n        return;\n    }\n\n    PhSetCursor(PhLoadCursor(NULL, IDC_WAIT));\n    status = KphSystemControl(\n        KphSystemControlEmptyCompressionStore,\n        NULL,\n        0\n        );\n    PhSetCursor(PhLoadCursor(NULL, IDC_ARROW));\n\n    if (NT_SUCCESS(status))\n        *Message = PhCreateString(L\"Compression stores emptied.\");\n    else\n        *Message = PhpCreateCommandStatusString(L\"Unable to empty compression stores.\", status);\n}\n\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID NTAPI PhpEmptyRegistryCacheCommand(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    )\n{\n    NTSTATUS status;\n\n    PhSetCursor(PhLoadCursor(NULL, IDC_WAIT));\n    status = NtSetSystemInformation(SystemRegistryReconciliationInformation, NULL, 0);\n    PhSetCursor(PhLoadCursor(NULL, IDC_ARROW));\n\n    if (NT_SUCCESS(status))\n        *Message = PhCreateString(L\"Registry cache emptied.\");\n    else\n        *Message = PhpCreateCommandStatusString(L\"Unable to empty registry cache.\", status);\n}\n\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID NTAPI PhpEmptySystemFileCacheCommand(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    )\n{\n    NTSTATUS status;\n    SYSTEM_FILECACHE_INFORMATION cacheInfo = { 0 };\n\n    PhAdjustPrivilege(NULL, SE_INCREASE_QUOTA_PRIVILEGE, TRUE);\n\n    PhGetSystemFileCacheSize(&cacheInfo);\n\n    PhSetCursor(PhLoadCursor(NULL, IDC_WAIT));\n    status = PhSetSystemFileCacheSize(\n        MAXSIZE_T,\n        MAXSIZE_T,\n        0\n        );\n    PhSetCursor(PhLoadCursor(NULL, IDC_ARROW));\n\n    if (NT_SUCCESS(status))\n    {\n        PH_FORMAT format[5];\n\n        // System file cache emptied: %s (%llu pages)\n        PhInitFormatS(&format[0], L\"System file cache emptied: \");\n        PhInitFormatSize(&format[1], cacheInfo.CurrentSize);\n        PhInitFormatS(&format[2], L\" (\");\n        PhInitFormatI64U(&format[3], cacheInfo.CurrentSize / PAGE_SIZE);\n        PhInitFormatS(&format[4], L\" pages)\");\n\n        *Message = PhFormat(format, RTL_NUMBER_OF(format), 0);\n    }\n    else\n    {\n        *Message = PhpCreateCommandStatusString(L\"Unable to empty system file cache.\", status);\n    }\n}\n\n_Function_class_(PH_MEMORY_LIST_COMMAND_CALLBACK)\nVOID NTAPI PhpFlushModifiedFileCacheCommand(\n    _In_ HWND ParentWindow,\n    _Out_ PPH_STRING* Message\n    )\n{\n    NTSTATUS status;\n\n    PhSetCursor(PhLoadCursor(NULL, IDC_WAIT));\n    status = PhFlushVolumeCache();\n    PhSetCursor(PhLoadCursor(NULL, IDC_ARROW));\n\n    if (NT_SUCCESS(status))\n        *Message = PhCreateString(L\"Volume file cache flushed to disk.\");\n    else\n        *Message = PhpCreateCommandStatusString(L\"Unable to flush volume file cache.\", status);\n}\n\ntypedef struct _PH_MEMORY_LIST_COMMAND_ENTRY\n{\n    PPH_MEMORY_LIST_COMMAND_CALLBACK Callback;\n    PH_STRINGREF WorkingMessage;\n} PH_MEMORY_LIST_COMMAND_ENTRY, *PPH_MEMORY_LIST_COMMAND_ENTRY;\n\nstatic const PH_MEMORY_LIST_COMMAND_ENTRY PhMemoryListCommands[] =\n{\n    { PhpCombineMemoryListsCommand, PH_STRINGREF_INIT(L\"Combining memory pages...\") },\n    { PhpEmptyCompressionStoreCommand, PH_STRINGREF_INIT(L\"Emptying compression store...\") },\n    { PhpEmptySystemFileCacheCommand, PH_STRINGREF_INIT(L\"Emptying system file cache ...\") },\n    { PhpEmptyRegistryCacheCommand, PH_STRINGREF_INIT(L\"Emptying registry cache...\") },\n    { PhpEmptyWorkingSetsCommand, PH_STRINGREF_INIT(L\"Emptying working sets...\") },\n    { PhpFlushModifiedListCommand, PH_STRINGREF_INIT(L\"Emptying modified page list...\") },\n    { PhpFlushModifiedFileCacheCommand, PH_STRINGREF_INIT(L\"Emptying modified file cache...\") },\n    { PhpPurgeStandbyListCommand, PH_STRINGREF_INIT(L\"Emptying standby list...\") },\n    { PhpPurgeLowPriorityStandbyListCommand, PH_STRINGREF_INIT(L\"Emptying priority 0 standby list...\") },\n};\n\ntypedef struct _PH_MEMORY_LIST_COMMAND_CONTEXT\n{\n    HWND WindowHandle;\n    HANDLE ThreadHandle;\n    BOOLEAN Cancel;\n    BOOLEAN Completed;\n    PH_QUEUED_LOCK MessageLock;\n    PPH_STRING Message;\n    ULONG CommandsComplete;\n    ULONG CommandsCount;\n    PH_MEMORY_LIST_COMMAND_ENTRY Commands[RTL_NUMBER_OF(PhMemoryListCommands)];\n} PH_MEMORY_LIST_COMMAND_CONTEXT, *PPH_MEMORY_LIST_COMMAND_CONTEXT;\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI PhMemoryListCommandThread(\n    _In_ PVOID ThreadParameter\n    )\n{\n    static const PH_STRINGREF lineBreak = PH_STRINGREF_INIT(L\"\\r\\n\");\n    PPH_MEMORY_LIST_COMMAND_CONTEXT context = ThreadParameter;\n\n    for (ULONG i = 0; i < context->CommandsCount; i++)\n    {\n        PPH_MEMORY_LIST_COMMAND_ENTRY entry;\n        PPH_STRING message = NULL;\n\n        entry = &context->Commands[i];\n\n        if (context->Cancel)\n            break;\n\n        PhAcquireQueuedLockExclusive(&context->MessageLock);\n        if (context->Message)\n            PhMoveReference(&context->Message, PhConcatStringRef3(&context->Message->sr, &lineBreak, &entry->WorkingMessage));\n        else\n            context->Message = PhCreateString2(&entry->WorkingMessage);\n        PhReleaseQueuedLockExclusive(&context->MessageLock);\n\n        entry->Callback(context->WindowHandle, &message);\n        context->CommandsComplete++;\n\n        if (message)\n        {\n            PhAcquireQueuedLockExclusive(&context->MessageLock);\n            PhMoveReference(&context->Message, PhConcatStringRef3(&context->Message->sr, &lineBreak, &message->sr));\n            PhReleaseQueuedLockExclusive(&context->MessageLock);\n            PhDereferenceObject(message);\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nHRESULT CALLBACK PhMemoryListCommandDialogCallbackProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT Notification,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR Context\n    )\n{\n    PPH_MEMORY_LIST_COMMAND_CONTEXT context = (PPH_MEMORY_LIST_COMMAND_CONTEXT)Context;\n\n    switch (Notification)\n    {\n    case TDN_CREATED:\n        {\n            NTSTATUS status;\n            HANDLE threadHandle;\n\n            context->WindowHandle = WindowHandle;\n            PhInitializeQueuedLock(&context->MessageLock);\n\n            SendMessage(WindowHandle, TDM_ENABLE_BUTTON, IDCLOSE, FALSE);\n\n            if (context->CommandsCount == 1)\n            {\n                SendMessage(WindowHandle, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n                SendMessage(WindowHandle, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n            }\n\n            if (NT_SUCCESS(status = PhCreateThreadEx(\n                &threadHandle,\n                PhMemoryListCommandThread,\n                context\n                )))\n            {\n                context->ThreadHandle = threadHandle;\n            }\n            else\n            {\n                PhShowStatus(WindowHandle, L\"Unable to create the window.\", status, 0);\n            }\n        }\n        break;\n    case TDN_BUTTON_CLICKED:\n        {\n            if ((INT)wParam == IDCANCEL)\n            {\n                context->Cancel = TRUE;\n                SendMessage(WindowHandle, TDM_ENABLE_BUTTON, IDCANCEL, FALSE);\n            }\n        }\n        break;\n    case TDN_TIMER:\n        {\n            PPH_STRING string;\n\n            if (context->Completed)\n                break;\n\n            PhAcquireQueuedLockExclusive(&context->MessageLock);\n            string = context->Message ? PhReferenceObject(context->Message) : NULL;\n            PhReleaseQueuedLockExclusive(&context->MessageLock);\n\n            if (string)\n            {\n                SendMessage(WindowHandle, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)string->Buffer);\n                PhDereferenceObject(string);\n            }\n\n            if (context->CommandsComplete == context->CommandsCount)\n            {\n                if (context->CommandsCount == 1)\n                {\n                    SendMessage(WindowHandle, TDM_SET_MARQUEE_PROGRESS_BAR, FALSE, 0);\n                    SendMessage(WindowHandle, TDM_SET_PROGRESS_BAR_MARQUEE, FALSE, 0);\n                }\n\n                SendMessage(WindowHandle, TDM_SET_PROGRESS_BAR_POS, (WPARAM)100, 0);\n\n                SendMessage(WindowHandle, TDM_ENABLE_BUTTON, IDCLOSE, TRUE);\n                SendMessage(WindowHandle, TDM_ENABLE_BUTTON, IDCANCEL, FALSE);\n\n                context->Completed = TRUE;\n            }\n            else if (context->CommandsCount > 1)\n            {\n                FLOAT progress = (FLOAT)(context->CommandsComplete + 1) / context->CommandsCount;\n                SendMessage(WindowHandle, TDM_SET_PROGRESS_BAR_POS, (WPARAM)(progress * 100), 0);\n            }\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\nVOID PhMemoryListCommandDialog(\n    _In_ HWND PrentWindow,\n    _In_ PPH_MEMORY_LIST_COMMAND_CONTEXT Context\n    )\n{\n    TASKDIALOGCONFIG config;\n    PPH_MEMORY_LIST_COMMAND_CONTEXT context;\n\n    context = PhAllocateCopy(Context, sizeof(PH_MEMORY_LIST_COMMAND_CONTEXT));\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_USE_HICON_MAIN | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SHOW_PROGRESS_BAR | TDF_CAN_BE_MINIMIZED | TDF_CALLBACK_TIMER;\n    config.dwCommonButtons = TDCBF_CLOSE_BUTTON | TDCBF_CANCEL_BUTTON;\n    config.hMainIcon = PhGetApplicationIcon(FALSE);\n    config.pfCallback = PhMemoryListCommandDialogCallbackProc;\n    config.hwndParent = PrentWindow;\n    config.lpCallbackData = (LONG_PTR)context;\n    config.pszWindowTitle = PhApplicationName;\n    if (context->CommandsCount > 1)\n        config.pszMainInstruction = L\"Executing memory commands...\";\n    else\n        config.pszMainInstruction = L\"Executing memory command...\";\n    config.pszContent = L\" \";\n    config.cxWidth = 200;\n\n    TaskDialogIndirect(&config, NULL, NULL, NULL);\n\n    if (context->ThreadHandle)\n        NtWaitForSingleObject(context->ThreadHandle, FALSE, NULL);\n\n    PhClearReference(&context->Message);\n\n    PhFree(context);\n}\n\nVOID PhShowMemoryListCommand(\n    _In_ HWND ParentWindow,\n    _In_ HWND ButtonWindow,\n    _In_ BOOLEAN ShowTopAlign\n    )\n{\n    PPH_EMENU menu;\n    RECT buttonRect = { 0 };\n    PPH_EMENU_ITEM selectedItem;\n\n    menu = PhCreateEMenu();\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 0, L\"&Combine memory pages\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L\"Empty &compression cache\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 2, L\"Empty system &file cache\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 3, L\"Empty &registry cache\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 4, L\"Empty &working sets\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 5, L\"Empty &modified page list\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 6, L\"Empty &modified file cache\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 7, L\"Empty &standby list\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 8, L\"Empty &priority 0 standby list\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, RTL_NUMBER_OF(PhMemoryListCommands), L\"Empty &all\", NULL, NULL), ULONG_MAX);\n\n    if (ShowTopAlign)\n    {\n        PhGetWindowRect(ButtonWindow, &buttonRect);\n        selectedItem = PhShowEMenu(\n            menu,\n            ParentWindow,\n            PH_EMENU_SHOW_LEFTRIGHT,\n            PH_ALIGN_LEFT | PH_ALIGN_BOTTOM,\n            buttonRect.left,\n            buttonRect.top\n            );\n    }\n    else\n    {\n        POINT point;\n\n        PhGetClientRect(ButtonWindow, &buttonRect);\n        point.x = 0;\n        point.y = buttonRect.bottom;\n        ClientToScreen(ButtonWindow, &point);\n\n        selectedItem = PhShowEMenu(\n            menu,\n            ParentWindow,\n            PH_EMENU_SHOW_LEFTRIGHT,\n            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n            point.x,\n            point.y\n            );\n    }\n\n    if (selectedItem)\n    {\n        PH_MEMORY_LIST_COMMAND_CONTEXT context;\n\n        memset(&context, 0, sizeof(PH_MEMORY_LIST_COMMAND_CONTEXT));\n\n        if (selectedItem->Id < RTL_NUMBER_OF(PhMemoryListCommands))\n        {\n            context.CommandsCount = 1;\n            context.Commands[0] = PhMemoryListCommands[selectedItem->Id];\n            PhMemoryListCommandDialog(ParentWindow, &context);\n        }\n        else if (!PhGetOwnTokenAttributes().Elevated)\n        {\n            PhShowStatus(ParentWindow, L\"Unable to empty the memory list.\", 0, ERROR_ELEVATION_REQUIRED);\n        }\n        else\n        {\n            context.CommandsCount = RTL_NUMBER_OF(PhMemoryListCommands);\n            memcpy(\n                context.Commands,\n                PhMemoryListCommands,\n                sizeof(PH_MEMORY_LIST_COMMAND_ENTRY) * context.CommandsCount\n                );\n            PhMemoryListCommandDialog(ParentWindow, &context);\n        }\n    }\n\n    PhDestroyEMenu(menu);\n}\n\nINT_PTR CALLBACK PhpMemoryListsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhAdjustPrivilege(NULL, SE_PROF_SINGLE_PROCESS_PRIVILEGE, TRUE);\n\n            PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration);\n            PhpUpdateMemoryListInfo(hwndDlg);\n\n            PhLoadWindowPlacementFromSetting(SETTING_MEMORY_LISTS_WINDOW_POSITION, NULL, hwndDlg);\n            PhRegisterDialog(hwndDlg);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhUnregisterDialog(hwndDlg);\n            PhSaveWindowPlacementToSetting(SETTING_MEMORY_LISTS_WINDOW_POSITION, NULL, hwndDlg);\n\n            PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedRegistration);\n\n            if (UnregisterDialogFunction)\n                UnregisterDialogFunction(hwndDlg);\n            PhMemoryListsWindowHandle = NULL;\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                DestroyWindow(hwndDlg);\n                break;\n            case IDC_EMPTY:\n                {\n                    PhShowMemoryListCommand(hwndDlg, GET_WM_COMMAND_HWND(wParam, lParam), FALSE);\n                }\n                break;\n            }\n        }\n        break;\n    case MSG_UPDATE:\n        {\n            PhpUpdateMemoryListInfo(hwndDlg);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/memmod.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2023\n *\n */\n\n#include <phapp.h>\n#include <procprv.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <emenu.h>\n#include <symprv.h>\n#include <workqueue.h>\n\ntypedef struct _PH_IMAGE_MODIFIED_DIALOG_CONTEXT\n{\n    LONG RefCount;\n\n    HWND WindowHandle;\n    HWND StatusHandle;\n    HWND ListViewHandle;\n    HWND ParentWindowHandle;\n    PPH_PROCESS_ITEM ProcessItem;\n    PH_LAYOUT_MANAGER LayoutManager;\n\n    BOOLEAN Destroying;\n\n    HANDLE ProcessHandle;\n    ULONG ImageQueryFailures;\n    PPH_LIST ImageAddressList;\n    PPH_LIST PageTamperingList;\n\n    PH_INITONCE SymbolProviderInitOnce;\n    PPH_SYMBOL_PROVIDER SymbolProvider;\n    SINGLE_LIST_ENTRY ResultListHead;\n    PH_QUEUED_LOCK ResultListLock;\n    PH_CALLBACK_REGISTRATION SymbolProviderEventRegistration;\n} PH_IMAGE_MODIFIED_DIALOG_CONTEXT, *PPH_IMAGE_MODIFIED_DIALOG_CONTEXT;\n\ntypedef struct _PH_IMAGE_MAPPED_BASE_ENTRY\n{\n    PVOID ImageBase;\n    SIZE_T SizeOfImage;\n    PPH_STRING FileName;\n} PH_IMAGE_MAPPED_BASE_ENTRY, *PPH_IMAGE_MAPPED_BASE_ENTRY;\n\ntypedef struct _PH_IMAGE_MAPPED_FAILURE_ENTRY\n{\n    PVOID BaseAddress;\n    SIZE_T SizeOfImage;\n    PVOID VirtualAddress;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Valid : 1;\n            ULONG Unused : 31;\n        };\n    };\n} PH_IMAGE_MAPPED_FAILURE_ENTRY, *PPH_IMAGE_MAPPED_FAILURE_ENTRY;\n\n_Function_class_(PH_ENUM_MEMORY_CALLBACK)\nNTSTATUS NTAPI PhEnumImagesForTamperingCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PMEMORY_BASIC_INFORMATION BasicInformation,\n    _In_ PVOID Context\n    )\n{\n    PPH_IMAGE_MODIFIED_DIALOG_CONTEXT context = Context;\n\n    if (\n        BasicInformation->Type == MEM_IMAGE &&\n        BasicInformation->AllocationBase == BasicInformation->BaseAddress\n        )\n    {\n        PVOID imageBase;\n        SIZE_T imageSize;\n\n        if (NT_SUCCESS(PhGetProcessMappedImageBaseFromAddress(\n            ProcessHandle,\n            BasicInformation->BaseAddress,\n            &imageBase,\n            &imageSize\n            )))\n        {\n            BOOLEAN found = FALSE;\n\n            for (ULONG i = 0; i < context->ImageAddressList->Count; i++)\n            {\n                PPH_IMAGE_MAPPED_BASE_ENTRY entry = context->ImageAddressList->Items[i];\n\n                if (entry->ImageBase == imageBase)\n                {\n                    found = TRUE;\n                    break;\n                }\n            }\n\n            if (!found)\n            {\n                PPH_IMAGE_MAPPED_BASE_ENTRY entry;\n                PPH_STRING fileName;\n\n                entry = PhAllocateZero(sizeof(PH_IMAGE_MAPPED_BASE_ENTRY));\n                entry->ImageBase = imageBase;\n                entry->SizeOfImage = imageSize;\n\n                if (NT_SUCCESS(PhGetProcessMappedFileName(ProcessHandle, entry->ImageBase, &fileName)))\n                {\n                    entry->FileName = fileName;\n                }\n\n                PhAddItemList(context->ImageAddressList, entry);\n            }\n        }\n        else\n        {\n            context->ImageQueryFailures++;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PH_ENUM_MEMORY_ATTRIBUTE_CALLBACK)\nNTSTATUS NTAPI PhpEnumVirtualMemoryAttributesCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T SizeOfImage,\n    _In_ ULONG_PTR NumberOfEntries,\n    _In_ PMEMORY_WORKING_SET_EX_INFORMATION Blocks,\n    _In_ PVOID Context\n    )\n{\n    PPH_IMAGE_MODIFIED_DIALOG_CONTEXT context = Context;\n\n    for (ULONG_PTR i = 0; i < NumberOfEntries; i++)\n    {\n        PMEMORY_WORKING_SET_EX_INFORMATION page = &Blocks[i];\n        PMEMORY_WORKING_SET_EX_BLOCK block = &page->VirtualAttributes;\n\n        if (!block->SharedOriginal)\n        {\n            PPH_IMAGE_MAPPED_FAILURE_ENTRY entry;\n\n            entry = PhAllocateZero(sizeof(PH_IMAGE_MAPPED_FAILURE_ENTRY));\n            entry->BaseAddress = BaseAddress;\n            entry->SizeOfImage = SizeOfImage;\n            entry->VirtualAddress = page->VirtualAddress;\n            entry->Valid = !!block->Valid;\n\n            PhAddItemList(context->PageTamperingList, entry);\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\ntypedef struct _SYMBOL_LOOKUP_RESULT\n{\n    SINGLE_LIST_ENTRY ListEntry;\n    PPH_IMAGE_MODIFIED_DIALOG_CONTEXT Context;\n    PVOID Address;\n    PPH_STRING Symbol;\n    PPH_STRING FileName;\n} SYMBOL_LOOKUP_RESULT, *PSYMBOL_LOOKUP_RESULT;\n\nVOID PhpCleanupPageModifiedLists(\n    _In_ PPH_IMAGE_MODIFIED_DIALOG_CONTEXT Context\n    )\n{\n    PSINGLE_LIST_ENTRY listEntry;\n\n    if (Context->ImageAddressList)\n    {\n        for (ULONG i = 0; i < Context->ImageAddressList->Count; i++)\n        {\n            PPH_IMAGE_MAPPED_BASE_ENTRY entry = Context->ImageAddressList->Items[i];\n            PhClearReference(&entry->FileName);\n            PhFree(entry);\n        }\n        PhClearReference(&Context->ImageAddressList);\n    }\n\n    if (Context->PageTamperingList)\n    {\n        for (ULONG i = 0; i < Context->PageTamperingList->Count; i++)\n            PhFree(Context->PageTamperingList->Items[i]);\n        PhClearReference(&Context->PageTamperingList);\n    }\n\n    // Free all unused results.\n\n    PhAcquireQueuedLockExclusive(&Context->ResultListLock);\n\n    listEntry = Context->ResultListHead.Next;\n\n    while (listEntry)\n    {\n        PSYMBOL_LOOKUP_RESULT result;\n\n        result = CONTAINING_RECORD(listEntry, SYMBOL_LOOKUP_RESULT, ListEntry);\n        listEntry = listEntry->Next;\n\n        PhClearReference(&result->Symbol);\n        PhClearReference(&result->FileName);\n\n        PhFree(result);\n    }\n\n    PhReleaseQueuedLockExclusive(&Context->ResultListLock);\n}\n\nVOID PhpLimitedSymbolReferenceContext(\n    _In_ PPH_IMAGE_MODIFIED_DIALOG_CONTEXT Context\n    )\n{\n    _InterlockedIncrement(&Context->RefCount);\n}\n\nVOID PhpLimitedSymbolDereferenceContext(\n    _In_ PPH_IMAGE_MODIFIED_DIALOG_CONTEXT Context\n    )\n{\n    if (_InterlockedDecrement(&Context->RefCount) == 0)\n    {\n        if (Context->SymbolProvider)\n            PhDereferenceObject(Context->SymbolProvider);\n        if (Context->ProcessHandle)\n            NtClose(Context->ProcessHandle);\n\n        PhpCleanupPageModifiedLists(Context);\n\n        PhDereferenceObject(Context->ProcessItem);\n\n        PhFree(Context);\n    }\n}\n\nstatic NTSTATUS PhpLimitedSymbolProviderLookupFunction(\n    _In_ PVOID Parameter\n    )\n{\n    PSYMBOL_LOOKUP_RESULT result = Parameter;\n\n    if (PhBeginInitOnce(&result->Context->SymbolProviderInitOnce))\n    {\n        PhLoadSymbolProviderOptions(result->Context->SymbolProvider);\n        PhLoadModulesForVirtualSymbolProvider(\n            result->Context->SymbolProvider,\n            result->Context->ProcessItem->ProcessId,\n            NULL\n            );\n\n        for (ULONG i = 0; i < result->Context->ImageAddressList->Count; i++)\n        {\n            PPH_IMAGE_MAPPED_BASE_ENTRY entry = result->Context->ImageAddressList->Items[i];\n\n            if (entry->FileName)\n            {\n                PhLoadFileNameSymbolProvider(\n                    result->Context->SymbolProvider,\n                    entry->FileName,\n                    entry->ImageBase,\n                    (ULONG)entry->SizeOfImage\n                    );\n            }\n            else\n            {\n                result->Context->ImageQueryFailures++;\n            }\n        }\n\n        PhEndInitOnce(&result->Context->SymbolProviderInitOnce);\n    }\n\n    if (result->Context->Destroying)\n    {\n        PhpLimitedSymbolDereferenceContext(result->Context);\n        PhFree(result);\n        return STATUS_SUCCESS;\n    }\n\n    result->Symbol = PhGetSymbolFromAddress(\n        result->Context->SymbolProvider,\n        result->Address,\n        NULL,\n        &result->FileName,\n        NULL,\n        NULL\n        );\n\n    // Fail if we don't have a symbol.\n    if (!result->Symbol)\n    {\n        PhpLimitedSymbolDereferenceContext(result->Context);\n        PhFree(result);\n        return STATUS_SUCCESS;\n    }\n\n    PhAcquireQueuedLockExclusive(&result->Context->ResultListLock);\n    PushEntryList(&result->Context->ResultListHead, &result->ListEntry);\n    PhReleaseQueuedLockExclusive(&result->Context->ResultListLock);\n    PhpLimitedSymbolDereferenceContext(result->Context);\n\n    return STATUS_SUCCESS;\n}\n\nstatic VOID PhpLimitedSymbolProviderQueueSymbolLookup(\n    _In_ PPH_IMAGE_MODIFIED_DIALOG_CONTEXT Context,\n    _In_ PVOID Address\n    )\n{\n    PSYMBOL_LOOKUP_RESULT result;\n\n    if (!Context->SymbolProvider)\n    {\n        Context->SymbolProvider = PhCreateSymbolProvider(NULL);\n    }\n\n    result = PhAllocateZero(sizeof(SYMBOL_LOOKUP_RESULT));\n    result->Context = Context;\n    result->Address = Address;\n    PhpLimitedSymbolReferenceContext(Context);\n\n    PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpLimitedSymbolProviderLookupFunction, result);\n}\n\nstatic VOID PhpProcessSymbolLookupResults(\n    _In_ PPH_IMAGE_MODIFIED_DIALOG_CONTEXT Context\n    )\n{\n    PSINGLE_LIST_ENTRY listEntry;\n\n    // Remove all results.\n    PhAcquireQueuedLockExclusive(&Context->ResultListLock);\n    listEntry = Context->ResultListHead.Next;\n    Context->ResultListHead.Next = NULL;\n    PhReleaseQueuedLockExclusive(&Context->ResultListLock);\n\n    // Update the list view with the results.\n    while (listEntry)\n    {\n        PSYMBOL_LOOKUP_RESULT result;\n        INT lvItemIndex;\n\n        result = CONTAINING_RECORD(listEntry, SYMBOL_LOOKUP_RESULT, ListEntry);\n        listEntry = listEntry->Next;\n\n        lvItemIndex = PhFindListViewItemByParam(Context->ListViewHandle, INT_ERROR, result->Address);\n\n        if (lvItemIndex != INT_ERROR)\n        {\n            PhSetListViewSubItem(\n                Context->ListViewHandle,\n                lvItemIndex,\n                5,\n                PhGetString(result->Symbol)\n                );\n        }\n\n        PhDereferenceObject(result->Symbol);\n        PhFree(result);\n    }\n}\n\n// Get a basic symbol name (module+offset).\nstatic PPH_STRING PhpLimitedSymbolProviderGetBasicSymbol(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address\n    )\n{\n    PVOID modBase;\n    PPH_STRING fileName = NULL;\n    PPH_STRING baseName = NULL;\n    PPH_STRING symbol;\n\n    modBase = PhGetModuleFromAddress(SymbolProvider, Address, &fileName);\n\n    if (!fileName)\n    {\n        symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR));\n        PhPrintPointer(symbol->Buffer, Address);\n        PhTrimToNullTerminatorString(symbol);\n    }\n    else\n    {\n        PH_FORMAT format[3];\n\n        baseName = PhGetBaseName(fileName);\n\n        PhInitFormatSR(&format[0], baseName->sr);\n        PhInitFormatS(&format[1], L\"+0x\");\n        PhInitFormatIX(&format[2], (ULONG_PTR)Address - (ULONG_PTR)modBase);\n\n        symbol = PhFormat(format, 3, baseName->Length + 6 + 32);\n    }\n\n    if (fileName)\n        PhDereferenceObject(fileName);\n    if (baseName)\n        PhDereferenceObject(baseName);\n\n    return symbol;\n}\n\nNTSTATUS PhCheckProcessImagesForTampering(\n    _In_ PPH_IMAGE_MODIFIED_DIALOG_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n\n    Context->ImageAddressList = PhCreateList(20);\n    Context->PageTamperingList = PhCreateList(20);\n\n    status = PhEnumVirtualMemory(\n        Context->ProcessHandle,\n        PhEnumImagesForTamperingCallback,\n        Context\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    for (ULONG i = 0; i < Context->ImageAddressList->Count; i++)\n    {\n        PPH_IMAGE_MAPPED_BASE_ENTRY entry = Context->ImageAddressList->Items[i];\n\n        status = PhEnumVirtualMemoryAttributes( // PhCheckImagePagesForTampering\n            Context->ProcessHandle,\n            entry->ImageBase,\n            entry->SizeOfImage,\n            PhpEnumVirtualMemoryAttributesCallback,\n            Context\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            Context->ImageQueryFailures++;\n        }\n    }\n\n    for (ULONG i = 0; i < Context->PageTamperingList->Count; i++)\n    {\n        PPH_IMAGE_MAPPED_FAILURE_ENTRY entry = Context->PageTamperingList->Items[i];\n        WCHAR value[PH_INT64_STR_LEN_1];\n        INT lvItemIndex;\n\n        PhPrintUInt32(value, i + 1);\n        lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, value, entry->VirtualAddress);\n\n        for (ULONG j = 0; j < Context->ImageAddressList->Count; j++)\n        {\n            PPH_IMAGE_MAPPED_BASE_ENTRY image = Context->ImageAddressList->Items[j];\n\n            if (\n                !PhIsNullOrEmptyString(image->FileName) &&\n                image->ImageBase == entry->BaseAddress &&\n                image->SizeOfImage == entry->SizeOfImage\n                )\n            {\n                PPH_STRING fileNameWin32 = PhGetFileName(image->FileName);\n                PhMoveReference(&fileNameWin32, PhGetBaseName(fileNameWin32));\n                PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, PhGetString(fileNameWin32));\n                PhDereferenceObject(fileNameWin32);\n                break;\n            }\n        }\n\n        PhPrintPointer(value, entry->BaseAddress);\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, value);\n        PhPrintPointer(value, PTR_SUB_OFFSET(entry->VirtualAddress, entry->BaseAddress));\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 3, value);\n        PhPrintPointer(value, entry->VirtualAddress);\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 4, value);\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 5, L\"Resolving symbols...\");\n        PhpLimitedSymbolProviderQueueSymbolLookup(Context, entry->VirtualAddress);\n    }\n\n    PhpProcessSymbolLookupResults(Context);\n\n    return status;\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhPageModifiedSymbolProviderEventCallback(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n)\n{\n    PPH_SYMBOL_EVENT_DATA event = Parameter;\n    PPH_IMAGE_MODIFIED_DIALOG_CONTEXT context = Context;\n    PPH_STRING statusMessage = NULL;\n\n    switch (event->EventType)\n    {\n    case PH_SYMBOL_EVENT_TYPE_LOAD_START:\n        statusMessage = PhReferenceObject(event->EventMessage);\n        break;\n    case PH_SYMBOL_EVENT_TYPE_LOAD_END:\n        statusMessage = PhReferenceEmptyString();\n        break;\n    case PH_SYMBOL_EVENT_TYPE_PROGRESS:\n        statusMessage = PhReferenceObject(event->EventMessage);\n        break;\n    }\n\n    if (statusMessage)\n    {\n        PhSetWindowText(context->StatusHandle, PhGetStringOrEmpty(statusMessage));\n        PhDereferenceObject(statusMessage);\n    }\n}\n\nINT_PTR CALLBACK PhPageModifiedDlgProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_IMAGE_MODIFIED_DIALOG_CONTEXT context = NULL;\n\n    if (WindowMessage == WM_INITDIALOG)\n    {\n        context = (PPH_IMAGE_MODIFIED_DIALOG_CONTEXT)lParam;\n\n        PhSetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (WindowMessage)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = WindowHandle;\n            context->ListViewHandle = GetDlgItem(WindowHandle, IDC_LIST);\n            context->StatusHandle = GetDlgItem(WindowHandle, IDC_STATE);\n\n            PhSetApplicationWindowIcon(WindowHandle);\n\n            PhSetListViewStyle(context->ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 50, L\"Index\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 100, L\"File\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 100, L\"ImageBase\");\n            PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 100, L\"Offset\");\n            PhAddListViewColumn(context->ListViewHandle, 4, 4, 4, LVCFMT_LEFT, 100, L\"Address\");\n            PhAddListViewColumn(context->ListViewHandle, 5, 5, 5, LVCFMT_LEFT, 100, L\"Symbol\");\n            PhSetExtendedListView(context->ListViewHandle);\n            PhLoadListViewColumnsFromSetting(SETTING_MEMORY_MODIFIED_LIST_VIEW_COLUMNS, context->ListViewHandle);\n            PhLoadListViewSortColumnsFromSetting(SETTING_MEMORY_MODIFIED_LIST_VIEW_SORT, context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, WindowHandle);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, context->StatusHandle, NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(WindowHandle, IDC_REFRESH), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(WindowHandle, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_MEMORY_MODIFIED_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_MEMORY_MODIFIED_WINDOW_POSITION, SETTING_MEMORY_MODIFIED_WINDOW_SIZE, WindowHandle);\n            else\n                PhCenterWindow(WindowHandle, context->ParentWindowHandle);\n\n            {\n                PPH_STRING windowTitle;\n\n                windowTitle = PhGetWindowText(WindowHandle);\n                PhMoveReference(&windowTitle, PhFormatString(\n                    L\"%s: %s (%lu)\",\n                    PhGetStringOrEmpty(windowTitle),\n                    PhGetStringOrEmpty(context->ProcessItem->ProcessName),\n                    HandleToUlong(context->ProcessItem->ProcessId)\n                    ));\n\n                PhSetWindowText(WindowHandle, PhGetStringOrEmpty(windowTitle));\n                PhDereferenceObject(windowTitle);\n            }\n\n            PhSetTimer(WindowHandle, PH_WINDOW_TIMER_DEFAULT, 1000, NULL);\n\n            PhInitializeWindowTheme(WindowHandle, PhEnableThemeSupport);\n\n            {\n                NTSTATUS status;\n\n                status = PhCheckProcessImagesForTampering(context);\n\n                if (!NT_SUCCESS(status))\n                {\n                    PhShowStatus(context->ParentWindowHandle, L\"Unable to perform the scan\", status, 0);\n                    EndDialog(WindowHandle, IDCANCEL);\n                }\n            }\n\n            PhSetWindowText(context->StatusHandle, L\"\");\n            PhRegisterCallback(\n                &PhSymbolEventCallback,\n                PhPageModifiedSymbolProviderEventCallback,\n                context,\n                &context->SymbolProviderEventRegistration\n                );\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveListViewSortColumnsToSetting(SETTING_MEMORY_MODIFIED_LIST_VIEW_SORT, context->ListViewHandle);\n            PhSaveListViewColumnsToSetting(SETTING_MEMORY_MODIFIED_LIST_VIEW_COLUMNS, context->ListViewHandle);\n            PhSaveWindowPlacementToSetting(SETTING_MEMORY_MODIFIED_WINDOW_POSITION, SETTING_MEMORY_MODIFIED_WINDOW_SIZE, WindowHandle);\n\n            context->Destroying = TRUE;\n\n            PhKillTimer(WindowHandle, PH_WINDOW_TIMER_DEFAULT);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhpLimitedSymbolDereferenceContext(context);\n\n            PhUnregisterCallback(\n                &PhSymbolEventCallback,\n                &context->SymbolProviderEventRegistration\n                );\n\n            PhRemoveWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_TIMER:\n        {\n            switch (wParam)\n            {\n            case PH_WINDOW_TIMER_DEFAULT:\n                PhpProcessSymbolLookupResults(context);\n                break;\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                DestroyWindow(WindowHandle);\n                break;\n            case IDC_REFRESH:\n                {\n                    ExtendedListView_SetRedraw(context->ListViewHandle, FALSE);\n                    ListView_DeleteAllItems(context->ListViewHandle);\n                    ExtendedListView_SetRedraw(context->ListViewHandle, TRUE);\n\n                    PhpCleanupPageModifiedLists(context);\n\n                    {\n                        NTSTATUS status;\n\n                        status = PhCheckProcessImagesForTampering(context);\n\n                        if (!NT_SUCCESS(status))\n                        {\n                            PhShowStatus(WindowHandle, L\"Unable to perform the scan\", status, 0);\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID* listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        WindowHandle,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        if (!PhHandleCopyListViewEMenuItem(item))\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                PhCopyListView(context->ListViewHandle);\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhShowImagePageModifiedDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_IMAGE_MODIFIED_DIALOG_CONTEXT context;\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION,\n        ProcessItem->ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to open the process.\", status, 0);\n        return;\n    }\n\n    context = PhAllocateZero(sizeof(PH_IMAGE_MODIFIED_DIALOG_CONTEXT));\n    context->RefCount = 1;\n    context->ProcessItem = PhReferenceObject(ProcessItem);\n    context->ParentWindowHandle = ParentWindowHandle;\n    context->ProcessHandle = processHandle;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_MODIFIEDPAGES),\n        NULL,\n        PhPageModifiedDlgProc,\n        context\n        );\n}\n"
  },
  {
    "path": "SystemInformer/memprot.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *\n */\n\n#include <phapp.h>\n#include <memprv.h>\n#include <procprv.h>\n\ntypedef struct _MEMORY_PROTECT_CONTEXT\n{\n    PPH_PROCESS_ITEM ProcessItem;\n    PPH_MEMORY_ITEM MemoryItem;\n} MEMORY_PROTECT_CONTEXT, *PMEMORY_PROTECT_CONTEXT;\n\nINT_PTR CALLBACK PhpMemoryProtectDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowMemoryProtectDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_MEMORY_ITEM MemoryItem\n    )\n{\n    MEMORY_PROTECT_CONTEXT context;\n\n    context.ProcessItem = ProcessItem;\n    context.MemoryItem = MemoryItem;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_MEMPROTECT),\n        ParentWindowHandle,\n        PhpMemoryProtectDlgProc,\n        &context\n        );\n}\n\nINT_PTR CALLBACK PhpMemoryProtectDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, (PVOID)lParam);\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhSetDialogItemText(hwndDlg, IDC_INTRO,\n                L\"Possible values:\\r\\n\"\n                L\"\\r\\n\"\n                L\"0x01 - PAGE_NOACCESS\\r\\n\"\n                L\"0x02 - PAGE_READONLY\\r\\n\"\n                L\"0x04 - PAGE_READWRITE\\r\\n\"\n                L\"0x08 - PAGE_WRITECOPY\\r\\n\"\n                L\"0x10 - PAGE_EXECUTE\\r\\n\"\n                L\"0x20 - PAGE_EXECUTE_READ\\r\\n\"\n                L\"0x40 - PAGE_EXECUTE_READWRITE\\r\\n\"\n                L\"0x80 - PAGE_EXECUTE_WRITECOPY\\r\\n\"\n                L\"Modifiers:\\r\\n\"\n                L\"0x100 - PAGE_GUARD\\r\\n\"\n                L\"0x200 - PAGE_NOCACHE\\r\\n\"\n                L\"0x400 - PAGE_WRITECOMBINE\\r\\n\"\n                );\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_VALUE));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    NTSTATUS status;\n                    PMEMORY_PROTECT_CONTEXT context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n                    HANDLE processHandle;\n                    ULONG64 protect;\n\n                    PhStringToUInt64(&PhaGetDlgItemText(hwndDlg, IDC_VALUE)->sr, 0, &protect);\n\n                    if (NT_SUCCESS(status = PhOpenProcess(\n                        &processHandle,\n                        PROCESS_VM_OPERATION,\n                        context->ProcessItem->ProcessId\n                        )))\n                    {\n                        PVOID baseAddress;\n                        SIZE_T regionSize;\n                        ULONG oldProtect;\n\n                        baseAddress = context->MemoryItem->BaseAddress;\n                        regionSize = context->MemoryItem->RegionSize;\n\n                        status = PhProtectVirtualMemory(\n                            processHandle,\n                            baseAddress,\n                            regionSize,\n                            (ULONG)protect,\n                            &oldProtect\n                            );\n\n                        if (NT_SUCCESS(status))\n                            context->MemoryItem->Protect = (ULONG)protect;\n\n                        NtClose(processHandle);\n                    }\n\n                    if (NT_SUCCESS(status))\n                    {\n                        EndDialog(hwndDlg, IDOK);\n                    }\n                    else\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to change memory protection\", status, 0);\n                        PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_VALUE));\n                        Edit_SetSel(GetDlgItem(hwndDlg, IDC_VALUE), 0, -1);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/memprv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <memprv.h>\n#include <heapstruct.h>\n#include <settings.h>\n#include <phsettings.h>\n\n#define MAX_HEAPS 1000\n#define WS_REQUEST_COUNT (PAGE_SIZE / sizeof(MEMORY_WORKING_SET_EX_INFORMATION))\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpMemoryItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nPPH_OBJECT_TYPE PhMemoryItemType = NULL;\n\nVOID PhGetMemoryProtectionString(\n    _In_ ULONG Protection,\n    _Inout_z_ PWSTR String\n    )\n{\n    PWSTR string;\n    PH_STRINGREF base;\n\n    if (!Protection)\n    {\n        String[0] = UNICODE_NULL;\n        return;\n    }\n\n    if (Protection & PAGE_NOACCESS)\n        PhInitializeStringRef(&base, L\"NA\");\n    else if (Protection & PAGE_READONLY)\n        PhInitializeStringRef(&base, L\"R\");\n    else if (Protection & PAGE_READWRITE)\n        PhInitializeStringRef(&base, L\"RW\");\n    else if (Protection & PAGE_WRITECOPY)\n        PhInitializeStringRef(&base, L\"WC\");\n    else if (Protection & PAGE_EXECUTE)\n        PhInitializeStringRef(&base, L\"X\");\n    else if (Protection & PAGE_EXECUTE_READ)\n        PhInitializeStringRef(&base, L\"RX\");\n    else if (Protection & PAGE_EXECUTE_READWRITE)\n        PhInitializeStringRef(&base, L\"RWX\");\n    else if (Protection & PAGE_EXECUTE_WRITECOPY)\n        PhInitializeStringRef(&base, L\"WCX\");\n    else\n        PhInitializeStringRef(&base, L\"?\");\n\n    string = String;\n\n    memcpy(string, base.Buffer, base.Length);\n    string += base.Length / sizeof(WCHAR);\n\n    if (Protection & PAGE_GUARD)\n    {\n        memcpy(string, L\"+G\", 2 * sizeof(WCHAR));\n        string += 2;\n    }\n\n    if (Protection & PAGE_NOCACHE)\n    {\n        memcpy(string, L\"+NC\", 3 * sizeof(WCHAR));\n        string += 3;\n    }\n\n    if (Protection & PAGE_WRITECOMBINE)\n    {\n        memcpy(string, L\"+WCM\", 4 * sizeof(WCHAR));\n        string += 4;\n    }\n\n    *string = UNICODE_NULL;\n}\n\nPCPH_STRINGREF PhGetMemoryStateString(\n    _In_ ULONG State\n    )\n{\n    static CONST PH_STRINGREF MemoryStateString[] =\n    {\n        PH_STRINGREF_INIT(L\"Unknown\"),\n        PH_STRINGREF_INIT(L\"Commit\"),\n        PH_STRINGREF_INIT(L\"Reserved\"),\n        PH_STRINGREF_INIT(L\"Free\"),\n    };\n\n    if (FlagOn(State, MEM_COMMIT))\n        return &MemoryStateString[1];\n    else if (FlagOn(State, MEM_RESERVE))\n        return &MemoryStateString[2];\n    else if (FlagOn(State, MEM_FREE))\n        return &MemoryStateString[3];\n    else\n        return &MemoryStateString[0];\n}\n\nPCPH_STRINGREF PhGetMemoryTypeString(\n    _In_ ULONG Type\n    )\n{\n    static CONST PH_STRINGREF MemoryTypeString[] =\n    {\n        PH_STRINGREF_INIT(L\"Unknown\"),\n        PH_STRINGREF_INIT(L\"Private\"),\n        PH_STRINGREF_INIT(L\"Mapped\"),\n        PH_STRINGREF_INIT(L\"Image\"),\n    };\n\n    if (FlagOn(Type, MEM_PRIVATE))\n        return &MemoryTypeString[1];\n    else if (FlagOn(Type, MEM_MAPPED))\n        return &MemoryTypeString[2];\n    else if (FlagOn(Type, MEM_IMAGE))\n        return &MemoryTypeString[3];\n    else\n        return &MemoryTypeString[0];\n}\n\nstatic CONST PH_KEY_VALUE_PAIR SigningLevelString[] =\n{\n    SIP(SREF(L\"Unchecked\"), SE_SIGNING_LEVEL_UNCHECKED),\n    SIP(SREF(L\"Unsigned\"), SE_SIGNING_LEVEL_UNSIGNED),\n    SIP(SREF(L\"Enterprise\"), SE_SIGNING_LEVEL_ENTERPRISE),\n    SIP(SREF(L\"Developer\"), SE_SIGNING_LEVEL_DEVELOPER),\n    SIP(SREF(L\"Authenticode\"), SE_SIGNING_LEVEL_AUTHENTICODE),\n    SIP(SREF(L\"Custom 2\"), SE_SIGNING_LEVEL_CUSTOM_2),\n    SIP(SREF(L\"StoreApp\"), SE_SIGNING_LEVEL_STORE),\n    SIP(SREF(L\"Antimalware\"), SE_SIGNING_LEVEL_ANTIMALWARE),\n    SIP(SREF(L\"Microsoft\"), SE_SIGNING_LEVEL_MICROSOFT),\n    SIP(SREF(L\"Custom 4\"), SE_SIGNING_LEVEL_CUSTOM_4),\n    SIP(SREF(L\"Custom 5\"), SE_SIGNING_LEVEL_CUSTOM_5),\n    SIP(SREF(L\"CodeGen\"), SE_SIGNING_LEVEL_DYNAMIC_CODEGEN),\n    SIP(SREF(L\"Windows\"), SE_SIGNING_LEVEL_WINDOWS),\n    SIP(SREF(L\"Custom 7\"), SE_SIGNING_LEVEL_CUSTOM_7),\n    SIP(SREF(L\"WinTcb\"), SE_SIGNING_LEVEL_WINDOWS_TCB),\n    SIP(SREF(L\"Custom 6\"), SE_SIGNING_LEVEL_CUSTOM_6)\n};\n\nstatic_assert(ARRAYSIZE(SigningLevelString) == SE_SIGNING_LEVEL_CUSTOM_6 + 1, \"SigningLevelString must equal SE_SIGNING_LEVEL_MAX\");\n\nPCPH_STRINGREF PhGetSigningLevelString(\n    _In_ SE_SIGNING_LEVEL SigningLevel\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        SigningLevelString,\n        sizeof(SigningLevelString),\n        SigningLevel,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return NULL;\n}\n\nstatic CONST PH_KEY_VALUE_PAIR MemoryPriorityString[] =\n{\n    SIP(SREF(L\"Lowest\"), MEMORY_PRIORITY_LOWEST),\n    SIP(SREF(L\"Very low\"), MEMORY_PRIORITY_VERY_LOW),\n    SIP(SREF(L\"Low\"), MEMORY_PRIORITY_LOW),\n    SIP(SREF(L\"Medium\"), MEMORY_PRIORITY_MEDIUM),\n    SIP(SREF(L\"Below normal\"), MEMORY_PRIORITY_BELOW_NORMAL),\n    SIP(SREF(L\"Normal\"), MEMORY_PRIORITY_NORMAL),\n    SIP(SREF(L\"Above normal\"), MEMORY_PRIORITY_ABOVE_NORMAL),\n    SIP(SREF(L\"High\"), MEMORY_PRIORITY_HIGH),\n};\n\nstatic_assert(ARRAYSIZE(MemoryPriorityString) == MEMORY_PRIORITY_HIGH + 1, \"MemoryPriorityString must equal MEMORY_PRIORITY_HIGH\");\n\nPCPH_STRINGREF PhGetMemoryPagePriorityString(\n    _In_ ULONG PagePriority\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        MemoryPriorityString,\n        sizeof(MemoryPriorityString),\n        PagePriority,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return NULL;\n}\n\nPPH_STRING PhGetMemoryRegionTypeExString(\n    _In_ PPH_MEMORY_ITEM MemoryItem\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    WCHAR pointer[PH_PTR_STR_LEN_1];\n\n    if (!MemoryItem->RegionTypeEx)\n        return NULL;\n\n    PhInitializeStringBuilder(&stringBuilder, 0x50);\n\n    if (MemoryItem->Private)\n        PhAppendStringBuilder2(&stringBuilder, L\"Private, \");\n    if (MemoryItem->MappedDataFile)\n        PhAppendStringBuilder2(&stringBuilder, L\"MappedDataFile, \");\n    if (MemoryItem->MappedImage)\n        PhAppendStringBuilder2(&stringBuilder, L\"MappedImage, \");\n    if (MemoryItem->MappedPageFile)\n        PhAppendStringBuilder2(&stringBuilder, L\"MappedPageFile, \");\n    if (MemoryItem->MappedPhysical)\n        PhAppendStringBuilder2(&stringBuilder, L\"MappedPhysical, \");\n    if (MemoryItem->DirectMapped)\n        PhAppendStringBuilder2(&stringBuilder, L\"DirectMapped, \");\n    if (MemoryItem->SoftwareEnclave)\n        PhAppendStringBuilder2(&stringBuilder, L\"Software enclave, \");\n    if (MemoryItem->PageSize64K)\n        PhAppendStringBuilder2(&stringBuilder, L\"PageSize64K, \");\n    if (MemoryItem->PlaceholderReservation)\n        PhAppendStringBuilder2(&stringBuilder, L\"Placeholder, \");\n    if (MemoryItem->MappedAwe)\n        PhAppendStringBuilder2(&stringBuilder, L\"Mapped AWE, \");\n    if (MemoryItem->MappedWriteWatch)\n        PhAppendStringBuilder2(&stringBuilder, L\"MappedWriteWatch, \");\n    if (MemoryItem->PageSizeLarge)\n        PhAppendStringBuilder2(&stringBuilder, L\"PageSizeLarge, \");\n    if (MemoryItem->PageSizeHuge)\n        PhAppendStringBuilder2(&stringBuilder, L\"PageSizeHuge, \");\n\n    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhPrintPointer(pointer, UlongToPtr(MemoryItem->RegionTypeEx));\n    PhAppendFormatStringBuilder(&stringBuilder, L\" (%s)\", pointer);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nPPH_MEMORY_ITEM PhCreateMemoryItem(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_MEMORY_ITEM memoryItem;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhMemoryItemType = PhCreateObjectType(L\"MemoryItem\", 0, PhpMemoryItemDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    memoryItem = PhCreateObject(sizeof(PH_MEMORY_ITEM), PhMemoryItemType);\n    memset(memoryItem, 0, sizeof(PH_MEMORY_ITEM));\n\n    return memoryItem;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpMemoryItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_MEMORY_ITEM memoryItem = Object;\n\n    switch (memoryItem->RegionType)\n    {\n    case CustomRegion:\n        PhClearReference(&memoryItem->u.Custom.Text);\n        break;\n    case MappedFileRegion:\n        PhClearReference(&memoryItem->u.MappedFile.FileName);\n        break;\n    }\n}\n\n_Function_class_(PH_AVL_TREE_COMPARE_FUNCTION)\nstatic LONG NTAPI PhpMemoryItemCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    )\n{\n    PPH_MEMORY_ITEM memoryItem1 = CONTAINING_RECORD(Links1, PH_MEMORY_ITEM, Links);\n    PPH_MEMORY_ITEM memoryItem2 = CONTAINING_RECORD(Links2, PH_MEMORY_ITEM, Links);\n\n    return uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress);\n}\n\nVOID PhDeleteMemoryItemList(\n    _In_ PPH_MEMORY_ITEM_LIST List\n    )\n{\n    PLIST_ENTRY listEntry;\n    PPH_MEMORY_ITEM memoryItem;\n\n    listEntry = List->ListHead.Flink;\n\n    while (listEntry != &List->ListHead)\n    {\n        memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry);\n        listEntry = listEntry->Flink;\n\n        PhDereferenceObject(memoryItem);\n    }\n}\n\nPPH_MEMORY_ITEM PhLookupMemoryItemList(\n    _In_ PPH_MEMORY_ITEM_LIST List,\n    _In_ PVOID Address\n    )\n{\n    PH_MEMORY_ITEM lookupMemoryItem;\n    PPH_AVL_LINKS links;\n    PPH_MEMORY_ITEM memoryItem;\n\n    // Do an approximate search on the set to locate the memory item with the largest\n    // base address that is still smaller than the given address.\n    lookupMemoryItem.BaseAddress = Address;\n    links = PhUpperDualBoundElementAvlTree(&List->Set, &lookupMemoryItem.Links);\n\n    if (links)\n    {\n        memoryItem = CONTAINING_RECORD(links, PH_MEMORY_ITEM, Links);\n\n        if ((ULONG_PTR)Address < (ULONG_PTR)memoryItem->BaseAddress + memoryItem->RegionSize)\n            return memoryItem;\n    }\n\n    return NULL;\n}\n\n// Split an existing memory item at the specified address and return the new item starting at Address.\n// The original item is shrunk to end just before Address. The new item inherits metadata and will be\n// inserted directly after the original in both the list and AVL tree. (dmex)\nstatic PPH_MEMORY_ITEM PhpSplitMemoryItem(\n    _In_ PPH_MEMORY_ITEM_LIST List,\n    _Inout_ PPH_MEMORY_ITEM MemoryItem,\n    _In_ PVOID Address\n    )\n{\n    PPH_MEMORY_ITEM newItem;\n    ULONG_PTR addr = (ULONG_PTR)Address;\n    ULONG_PTR start = (ULONG_PTR)MemoryItem->BaseAddress;\n    ULONG_PTR end = start + MemoryItem->RegionSize;\n\n    if (addr <= start || addr >= end)\n        return NULL;\n\n    // Copy region info\n    newItem = PhCreateMemoryItem();\n    newItem->BasicInfo = MemoryItem->BasicInfo;\n    newItem->BaseAddress = (PVOID)addr;\n    newItem->BasicInfo.BaseAddress = (PVOID)addr;\n    newItem->RegionSize = end - addr;\n    newItem->BasicInfo.RegionSize = newItem->RegionSize;\n    PhPrintPointer(newItem->BaseAddressString, newItem->BaseAddress);\n\n    // Adjust current region size.\n    SIZE_T originalRegionSize = MemoryItem->RegionSize;\n    MemoryItem->RegionSize = addr - start;\n    MemoryItem->BasicInfo.RegionSize = MemoryItem->RegionSize;\n\n    if (MemoryItem->CommittedSize == originalRegionSize)\n    {\n        newItem->CommittedSize = newItem->RegionSize;\n        MemoryItem->CommittedSize = MemoryItem->RegionSize;\n    }\n    if (MemoryItem->PrivateSize == originalRegionSize && (MemoryItem->Type & MEM_PRIVATE))\n    {\n        newItem->PrivateSize = newItem->RegionSize;\n        MemoryItem->PrivateSize = MemoryItem->RegionSize;\n    }\n\n    newItem->AllocationBase = MemoryItem->AllocationBase;\n    newItem->AllocationBaseItem = MemoryItem->AllocationBaseItem;\n\n    newItem->Type = MemoryItem->Type;\n    newItem->State = MemoryItem->State;\n    newItem->AllocationProtect = MemoryItem->AllocationProtect;\n    newItem->Protect = MemoryItem->Protect;\n    newItem->Valid = FALSE;\n    newItem->Bad = FALSE;\n    newItem->RegionTypeEx = MemoryItem->RegionTypeEx;\n\n    PhAddElementAvlTree(&List->Set, &newItem->Links);\n\n    newItem->ListEntry.Flink = MemoryItem->ListEntry.Flink;\n    newItem->ListEntry.Blink = &MemoryItem->ListEntry;\n    MemoryItem->ListEntry.Flink->Blink = &newItem->ListEntry;\n    MemoryItem->ListEntry.Flink = &newItem->ListEntry;\n\n    return newItem;\n}\n\nPPH_MEMORY_ITEM PhpSetMemoryRegionType(\n    _In_ PPH_MEMORY_ITEM_LIST List,\n    _In_ PVOID Address,\n    _In_ BOOLEAN GoToAllocationBase,\n    _In_ PH_MEMORY_REGION_TYPE RegionType\n    )\n{\n    PPH_MEMORY_ITEM memoryItem;\n\n    memoryItem = PhLookupMemoryItemList(List, Address);\n\n    if (!memoryItem)\n        return NULL;\n\n    if (GoToAllocationBase && memoryItem->AllocationBaseItem)\n        memoryItem = memoryItem->AllocationBaseItem;\n\n    // If we are tagging a sub-region inside an already tagged region, split it first.\n    if (!GoToAllocationBase && memoryItem->RegionType != UnknownRegion && memoryItem->BaseAddress != Address)\n    {\n        PPH_MEMORY_ITEM newItem = PhpSplitMemoryItem(List, memoryItem, Address);\n        if (newItem)\n        {\n            newItem->RegionType = RegionType;\n            return newItem;\n        }\n        return NULL; // Could not split; don't overwrite existing tag.\n    }\n\n    // If region is Unknown but the address is interior and we don't want allocation base, split so the tag is precise.\n    if (!GoToAllocationBase && memoryItem->RegionType == UnknownRegion && memoryItem->BaseAddress != Address)\n    {\n        PPH_MEMORY_ITEM newItem = PhpSplitMemoryItem(List, memoryItem, Address);\n        if (newItem)\n            memoryItem = newItem; // Tag the new split item below.\n    }\n\n    if (memoryItem->RegionType != UnknownRegion)\n        return NULL;\n\n    memoryItem->RegionType = RegionType;\n\n    return memoryItem;\n}\n\nVOID PhpUpdateHeapRegions(\n    _In_ PPH_MEMORY_ITEM_LIST List\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle = NULL;\n    HANDLE clientProcessId = List->ProcessId;\n    PROCESS_REFLECTION_INFORMATION reflectionInfo = { 0 };\n    PRTL_DEBUG_INFORMATION debugBuffer = NULL;\n    PPH_PROCESS_DEBUG_HEAP_INFORMATION heapDebugInfo = NULL;\n    HANDLE powerRequestHandle = NULL;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_LIMITED_INFORMATION |\n        PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE,\n        List->ProcessId\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (WindowsVersion >= WINDOWS_10)\n            PhCreateExecutionRequiredRequest(processHandle, &powerRequestHandle);\n\n        if (PhGetIntegerSetting(SETTING_ENABLE_HEAP_REFLECTION))\n        {\n            status = PhCreateProcessReflection(\n                &reflectionInfo,\n                processHandle\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                clientProcessId = reflectionInfo.ReflectionClientId.UniqueProcess;\n            }\n        }\n    }\n\n    for (ULONG i = 0x10000; ; i *= 2) // based on PhQueryProcessHeapInformation (ge0rdi)\n    {\n        if (!(debugBuffer = RtlCreateQueryDebugBuffer(i, FALSE)))\n        {\n            status = STATUS_UNSUCCESSFUL;\n            break;\n        }\n\n        status = RtlQueryProcessDebugInformation(\n            clientProcessId,\n            RTL_QUERY_PROCESS_HEAP_SUMMARY | RTL_QUERY_PROCESS_HEAP_SEGMENTS | RTL_QUERY_PROCESS_NONINVASIVE,\n            debugBuffer\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            RtlDestroyQueryDebugBuffer(debugBuffer);\n            debugBuffer = NULL;\n        }\n\n        if (NT_SUCCESS(status) || status != STATUS_NO_MEMORY)\n            break;\n\n        if (2 * i <= i)\n            break;\n    }\n\n    PhFreeProcessReflection(&reflectionInfo);\n\n    if (processHandle)\n        NtClose(processHandle);\n\n    if (powerRequestHandle)\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n\n    if (!NT_SUCCESS(status))\n        return;\n\n    if (!debugBuffer->Heaps)\n    {\n        RtlDestroyQueryDebugBuffer(debugBuffer);\n        return;\n    }\n\n    if (WindowsVersion > WINDOWS_11)\n    {\n        heapDebugInfo = PhAllocateZero(sizeof(PH_PROCESS_DEBUG_HEAP_INFORMATION) + ((PRTL_PROCESS_HEAPS_V2)debugBuffer->Heaps)->NumberOfHeaps * sizeof(PH_PROCESS_DEBUG_HEAP_ENTRY));\n        heapDebugInfo->NumberOfHeaps = ((PRTL_PROCESS_HEAPS_V2)debugBuffer->Heaps)->NumberOfHeaps;\n    }\n    else\n    {\n        heapDebugInfo = PhAllocateZero(sizeof(PH_PROCESS_DEBUG_HEAP_INFORMATION) + ((PRTL_PROCESS_HEAPS_V1)debugBuffer->Heaps)->NumberOfHeaps * sizeof(PH_PROCESS_DEBUG_HEAP_ENTRY));\n        heapDebugInfo->NumberOfHeaps = ((PRTL_PROCESS_HEAPS_V1)debugBuffer->Heaps)->NumberOfHeaps;\n    }\n\n    for (ULONG i = 0; i < heapDebugInfo->NumberOfHeaps; i++)\n    {\n        RTL_HEAP_INFORMATION_V2 heapInfo = { 0 };\n        PPH_MEMORY_ITEM heapMemoryItem;\n\n        if (WindowsVersion > WINDOWS_11)\n        {\n            heapInfo = ((PRTL_PROCESS_HEAPS_V2)debugBuffer->Heaps)->Heaps[i];\n        }\n        else\n        {\n            RTL_HEAP_INFORMATION_V1 heapInfoV1 = ((PRTL_PROCESS_HEAPS_V1)debugBuffer->Heaps)->Heaps[i];\n            heapInfo.NumberOfEntries = heapInfoV1.NumberOfEntries;\n            heapInfo.Entries = heapInfoV1.Entries;\n            heapInfo.BytesCommitted = heapInfoV1.BytesCommitted;\n            heapInfo.Flags = heapInfoV1.Flags;\n            heapInfo.BaseAddress = heapInfoV1.BaseAddress;\n        }\n\n        if (!heapInfo.BaseAddress)\n            continue;\n\n        if (heapMemoryItem = PhpSetMemoryRegionType(List, heapInfo.BaseAddress, TRUE, HeapRegion))\n        {\n            heapMemoryItem->u.Heap.Index = i;\n\n            for (ULONG j = 0; j < heapInfo.NumberOfEntries; j++)\n            {\n                PRTL_HEAP_ENTRY heapEntry = &heapInfo.Entries[j];\n\n                if (heapEntry->Flags & RTL_HEAP_SEGMENT)\n                {\n                    PVOID blockAddress = heapEntry->u.s2.FirstBlock;\n\n                    PPH_MEMORY_ITEM memoryItem = PhLookupMemoryItemList(List, blockAddress);\n\n                    if (memoryItem && memoryItem->BaseAddress == blockAddress && memoryItem->RegionType == UnknownRegion)\n                    {\n                        memoryItem->RegionType = HeapSegmentRegion;\n                        memoryItem->u.HeapSegment.HeapItem = heapMemoryItem;\n                    }\n                }\n            }\n        }\n    }\n\n    RtlDestroyQueryDebugBuffer(debugBuffer);\n}\n\nNTSTATUS PhpUpdateMemoryRegionTypes(\n    _In_ PPH_MEMORY_ITEM_LIST List,\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n    ULONG i;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n    PPH_MEMORY_ITEM memoryItem;\n    PLIST_ENTRY listEntry;\n\n    if (!NT_SUCCESS(status = PhEnumProcessesEx(&processes, SystemExtendedProcessInformation)))\n        return status;\n\n    process = PhFindProcessInformation(processes, List->ProcessId);\n\n    if (!process)\n    {\n        PhFree(processes);\n        return STATUS_NOT_FOUND;\n    }\n\n    // USER_SHARED_DATA\n    PhpSetMemoryRegionType(List, USER_SHARED_DATA, TRUE, UserSharedDataRegion);\n\n    // HYPERVISOR_SHARED_DATA\n    if (WindowsVersion >= WINDOWS_10_RS4)\n    {\n        static PSYSTEM_HYPERVISOR_USER_SHARED_DATA hypervisorSharedUserData = NULL;\n        static PH_INITONCE hypervisorSharedUserInitOnce = PH_INITONCE_INIT;\n\n        if (PhBeginInitOnce(&hypervisorSharedUserInitOnce))\n        {\n            PhGetSystemHypervisorSharedPageInformation(&hypervisorSharedUserData);\n            PhEndInitOnce(&hypervisorSharedUserInitOnce);\n        }\n\n        if (hypervisorSharedUserData)\n        {\n            PhpSetMemoryRegionType(List, hypervisorSharedUserData, TRUE, HypervisorSharedDataRegion);\n        }\n    }\n\n    // PEB, heap\n    {\n        ULONG numberOfHeaps;\n        PVOID processPeb;\n        PVOID processHeapsPtr;\n        PVOID *processHeaps;\n        PVOID apiSetMap;\n        PVOID processParameters;\n        PVOID readOnlySharedMemory;\n        PVOID codePageData;\n        PVOID gdiSharedHandleTable;\n        PVOID shimData;\n        PVOID activationContextData;\n        PVOID defaultActivationContextData;\n        PVOID werRegistrationData;\n        PVOID siloSharedData;\n        PVOID telemetryCoverageData;\n        PVOID leapSecondData;\n#ifdef _WIN64\n        PVOID processPeb32;\n        ULONG processHeapsPtr32;\n        ULONG *processHeaps32;\n        ULONG apiSetMap32;\n        ULONG processParameters32;\n        ULONG readOnlySharedMemory32;\n        ULONG codePageData32;\n        ULONG gdiSharedHandleTable32;\n        ULONG shimData32;\n        ULONG activationContextData32;\n        ULONG defaultActivationContextData32;\n        ULONG werRegistrationData32;\n        ULONG siloSharedData32;\n        ULONG telemetryCoverageData32;\n        ULONG leapSecondData32;\n#endif\n        if (PhGetIntegerSetting(SETTING_ENABLE_HEAP_MEMORY_TAGGING))\n        {\n            PhpUpdateHeapRegions(List);\n        }\n\n        if (NT_SUCCESS(PhGetProcessPeb(ProcessHandle, &processPeb)))\n        {\n            // Windows 10 RS2 and above 'added TEB/PEB sub-VAD segments' (dmex)\n            PhpSetMemoryRegionType(List, processPeb, WindowsVersion < WINDOWS_10_RS2 ? TRUE : FALSE, PebRegion);\n\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, UFIELD_OFFSET(PEB, NumberOfHeaps)),\n                &numberOfHeaps,\n                sizeof(ULONG),\n                NULL\n                )) && numberOfHeaps > 0 && numberOfHeaps < MAX_HEAPS)\n            {\n                processHeaps = PhAllocate(numberOfHeaps * sizeof(PVOID));\n\n                if (\n                    NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, PTR_ADD_OFFSET(processPeb, UFIELD_OFFSET(PEB, ProcessHeaps)), &processHeapsPtr, sizeof(PVOID), NULL)) &&\n                    NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, processHeapsPtr, processHeaps, numberOfHeaps * sizeof(PVOID), NULL))\n                    )\n                {\n                    for (i = 0; i < numberOfHeaps; i++)\n                    {\n                        if (memoryItem = PhpSetMemoryRegionType(List, processHeaps[i], TRUE, HeapRegion))\n                        {\n                            PH_ANY_HEAP buffer;\n\n                            memoryItem->u.Heap.Index = i;\n\n                            // Try to read heap class from the header\n                            if (NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, processHeaps[i], &buffer, sizeof(buffer), NULL)))\n                            {\n                                if (WindowsVersion >= WINDOWS_8)\n                                {\n                                    if (buffer.Heap.Signature == HEAP_SIGNATURE)\n                                    {\n                                        memoryItem->u.Heap.ClassValid = TRUE;\n                                        memoryItem->u.Heap.Class = buffer.Heap.Flags & HEAP_CLASS_MASK;\n                                    }\n                                    else if (buffer.Heap32.Signature == HEAP_SIGNATURE)\n                                    {\n                                        memoryItem->u.Heap.ClassValid = TRUE;\n                                        memoryItem->u.Heap.Class = buffer.Heap32.Flags & HEAP_CLASS_MASK;\n                                    }\n                                    else if (WindowsVersion >= WINDOWS_8_1)\n                                    {\n                                        // Windows 8.1 and above can use segment heaps\n                                        if (buffer.SegmentHeap.Signature == SEGMENT_HEAP_SIGNATURE)\n                                        {\n                                            memoryItem->u.Heap.ClassValid = TRUE;\n                                            memoryItem->u.Heap.Class = buffer.SegmentHeap.GlobalFlags & HEAP_CLASS_MASK;\n                                        }\n                                        else if (buffer.SegmentHeap32.Signature == SEGMENT_HEAP_SIGNATURE)\n                                        {\n                                            memoryItem->u.Heap.ClassValid = TRUE;\n                                            memoryItem->u.Heap.Class = buffer.SegmentHeap32.GlobalFlags & HEAP_CLASS_MASK;\n                                        }\n                                    }\n                                }\n                                else\n                                {\n                                    if (buffer.HeapOld.Signature == HEAP_SIGNATURE)\n                                    {\n                                        memoryItem->u.Heap.ClassValid = TRUE;\n                                        memoryItem->u.Heap.Class = buffer.HeapOld.Flags & HEAP_CLASS_MASK;\n                                    }\n                                    else if (buffer.HeapOld32.Signature == HEAP_SIGNATURE)\n                                    {\n                                        memoryItem->u.Heap.ClassValid = TRUE;\n                                        memoryItem->u.Heap.Class = buffer.HeapOld32.Flags & HEAP_CLASS_MASK;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n\n                PhFree(processHeaps);\n            }\n\n            // RTL_USER_PROCESS_PARAMETERS\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, ProcessParameters)),\n                &processParameters,\n                sizeof(PVOID),\n                NULL\n                )) && processParameters)\n            {\n                PhpSetMemoryRegionType(List, processParameters, TRUE, ProcessParametersRegion);\n            }\n\n            // ApiSet schema map\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, ApiSetMap)),\n                &apiSetMap,\n                sizeof(PVOID),\n                NULL\n                )) && apiSetMap)\n            {\n                PhpSetMemoryRegionType(List, apiSetMap, TRUE, ApiSetMapRegion);\n            }\n\n            // CSR shared memory\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, ReadOnlySharedMemoryBase)),\n                &readOnlySharedMemory,\n                sizeof(PVOID),\n                NULL\n                )) && readOnlySharedMemory)\n            {\n                PhpSetMemoryRegionType(List, readOnlySharedMemory, TRUE, ReadOnlySharedMemoryRegion);\n            }\n\n            // CodePage data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, AnsiCodePageData)),\n                &codePageData,\n                sizeof(PVOID),\n                NULL\n                )) && codePageData)\n            {\n                PhpSetMemoryRegionType(List, codePageData, TRUE, CodePageDataRegion);\n            }\n\n            // GDI shared handle table\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, GdiSharedHandleTable)),\n                &gdiSharedHandleTable,\n                sizeof(PVOID),\n                NULL\n                )) && gdiSharedHandleTable)\n            {\n                PhpSetMemoryRegionType(List, gdiSharedHandleTable, TRUE, GdiSharedHandleTableRegion);\n            }\n\n            // Shim data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, pShimData)),\n                &shimData,\n                sizeof(PVOID),\n                NULL\n                )) && shimData)\n            {\n                PhpSetMemoryRegionType(List, shimData, TRUE, ShimDataRegion);\n            }\n\n            // Process activation context data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, ActivationContextData)),\n                &activationContextData,\n                sizeof(PVOID),\n                NULL\n                )) && activationContextData)\n            {\n                if (memoryItem = PhpSetMemoryRegionType(List, activationContextData, TRUE, ActivationContextDataRegion))\n                {\n                    memoryItem->u.ActivationContextData.Type = ProcessActivationContext;\n                }\n            }\n\n            // System-default activation context data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, SystemDefaultActivationContextData)),\n                &defaultActivationContextData,\n                sizeof(PVOID),\n                NULL\n                )) && defaultActivationContextData)\n            {\n                if (memoryItem = PhpSetMemoryRegionType(List, defaultActivationContextData, TRUE, ActivationContextDataRegion))\n                {\n                    memoryItem->u.ActivationContextData.Type = SystemActivationContext;\n                }\n            }\n\n            // WER registration data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, WerRegistrationData)),\n                &werRegistrationData,\n                sizeof(PVOID),\n                NULL\n                )) && werRegistrationData)\n            {\n                PhpSetMemoryRegionType(List, werRegistrationData, TRUE, WerRegistrationDataRegion);\n            }\n\n            // Silo shared data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, SharedData)),\n                &siloSharedData,\n                sizeof(PVOID),\n                NULL\n                )) && siloSharedData)\n            {\n                PhpSetMemoryRegionType(List, siloSharedData, TRUE, SiloSharedDataRegion);\n            }\n\n            // Telemetry coverage map\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, FIELD_OFFSET(PEB, TelemetryCoverageHeader)),\n                &telemetryCoverageData,\n                sizeof(PVOID),\n                NULL\n                )) && telemetryCoverageData)\n            {\n                PhpSetMemoryRegionType(List, telemetryCoverageData, TRUE, TelemetryCoverageRegion);\n            }\n\n            // Leap second data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb, UFIELD_OFFSET(PEB, LeapSecondData)),\n                &leapSecondData,\n                sizeof(PVOID),\n                NULL\n                )) && leapSecondData)\n            {\n                PhpSetMemoryRegionType(List, leapSecondData, TRUE, LeapSecondDataRegion);\n            }\n        }\n#ifdef _WIN64\n\n        if (NT_SUCCESS(PhGetProcessPeb32(ProcessHandle, &processPeb32)))\n        {\n            isWow64 = TRUE;\n            PhpSetMemoryRegionType(List, processPeb32, TRUE, Peb32Region);\n\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, NumberOfHeaps)),\n                &numberOfHeaps,\n                sizeof(ULONG),\n                NULL\n                )) && numberOfHeaps < MAX_HEAPS)\n            {\n                processHeaps32 = PhAllocate(numberOfHeaps * sizeof(ULONG));\n\n                if (\n                    NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, ProcessHeaps)), &processHeapsPtr32, sizeof(ULONG), NULL)) &&\n                    NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, UlongToPtr(processHeapsPtr32), processHeaps32, numberOfHeaps * sizeof(ULONG), NULL))\n                    )\n                {\n                    for (i = 0; i < numberOfHeaps; i++)\n                    {\n                        if (memoryItem = PhpSetMemoryRegionType(List, UlongToPtr(processHeaps32[i]), TRUE, Heap32Region))\n                            memoryItem->u.Heap.Index = i;\n                    }\n                }\n\n                PhFree(processHeaps32);\n            }\n\n            // RTL_USER_PROCESS_PARAMETERS\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, FIELD_OFFSET(PEB32, ProcessParameters)),\n                &processParameters32,\n                sizeof(ULONG),\n                NULL\n                )) && processParameters32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(processParameters32), TRUE, ProcessParametersRegion);\n            }\n\n            // ApiSet schema map\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, ApiSetMap)),\n                &apiSetMap32,\n                sizeof(ULONG),\n                NULL\n                )) && apiSetMap32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(apiSetMap32), TRUE, ApiSetMapRegion);\n            }\n\n            // CSR shared memory\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, ReadOnlySharedMemoryBase)),\n                &readOnlySharedMemory32,\n                sizeof(ULONG),\n                NULL\n                )) && readOnlySharedMemory32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(readOnlySharedMemory32), TRUE, ReadOnlySharedMemoryRegion);\n            }\n\n            // CodePage data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, AnsiCodePageData)),\n                &codePageData32,\n                sizeof(ULONG),\n                NULL\n                )) && codePageData32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(codePageData32), TRUE, CodePageDataRegion);\n            }\n\n            // GDI shared handle table\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, GdiSharedHandleTable)),\n                &gdiSharedHandleTable32,\n                sizeof(ULONG),\n                NULL\n                )) && gdiSharedHandleTable32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(gdiSharedHandleTable32), TRUE, GdiSharedHandleTableRegion);\n            }\n\n            // Shim data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, pShimData)),\n                &shimData32,\n                sizeof(ULONG),\n                NULL\n                )) && shimData32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(shimData32), TRUE, ShimDataRegion);\n            }\n\n            // Process activation context data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, ActivationContextData)),\n                &activationContextData32,\n                sizeof(ULONG),\n                NULL\n                )) && activationContextData32)\n            {\n                if (memoryItem = PhpSetMemoryRegionType(List, UlongToPtr(activationContextData32), TRUE, ActivationContextDataRegion))\n                {\n                    memoryItem->u.ActivationContextData.Type = ProcessActivationContext;\n                }\n            }\n\n            // System-default activation context data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, SystemDefaultActivationContextData)),\n                &defaultActivationContextData32,\n                sizeof(ULONG),\n                NULL\n                )) && defaultActivationContextData32)\n            {\n                if (memoryItem = PhpSetMemoryRegionType(List, UlongToPtr(defaultActivationContextData32), TRUE, ActivationContextDataRegion))\n                {\n                    memoryItem->u.ActivationContextData.Type = SystemActivationContext;\n                }\n            }\n\n            // WER registration data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, WerRegistrationData)),\n                &werRegistrationData32,\n                sizeof(ULONG),\n                NULL\n                )) && werRegistrationData32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(werRegistrationData32), TRUE, WerRegistrationDataRegion);\n            }\n\n            // Silo shared data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, SharedData)),\n                &siloSharedData32,\n                sizeof(ULONG),\n                NULL\n                )) && siloSharedData32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(siloSharedData32), TRUE, SiloSharedDataRegion);\n            }\n\n            // Telemetry coverage map\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, TelemetryCoverageHeader)),\n                &telemetryCoverageData32,\n                sizeof(ULONG),\n                NULL\n                )) && telemetryCoverageData32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(telemetryCoverageData32), TRUE, TelemetryCoverageRegion);\n            }\n\n            // Leap second data\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(processPeb32, UFIELD_OFFSET(PEB32, LeapSecondData)),\n                &leapSecondData32,\n                sizeof(ULONG),\n                NULL\n                )) && leapSecondData32)\n            {\n                PhpSetMemoryRegionType(List, UlongToPtr(leapSecondData32), TRUE, LeapSecondDataRegion);\n            }\n        }\n#endif\n    }\n\n    // TEB, stack, desktop heap\n    for (i = 0; i < process->NumberOfThreads; i++)\n    {\n        PSYSTEM_EXTENDED_THREAD_INFORMATION thread = (PSYSTEM_EXTENDED_THREAD_INFORMATION)process->Threads + i;\n\n        if (thread->TebBaseAddress)\n        {\n            NT_TIB ntTib;\n            PVOID desktopInfo;\n            SIZE_T bytesRead;\n\n            // HACK: Windows 10 RS2 and above 'added TEB/PEB sub-VAD segments' and we need to tag individual sections.\n            if (memoryItem = PhpSetMemoryRegionType(List, thread->TebBaseAddress, WindowsVersion < WINDOWS_10_RS2 ? TRUE : FALSE, TebRegion))\n                memoryItem->u.Teb.ThreadId = thread->ThreadInfo.ClientId.UniqueThread;\n\n            if (NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, thread->TebBaseAddress, &ntTib, sizeof(NT_TIB), &bytesRead)) &&\n                bytesRead == sizeof(NT_TIB))\n            {\n                if ((ULONG_PTR)ntTib.StackLimit < (ULONG_PTR)ntTib.StackBase)\n                {\n                    if (memoryItem = PhpSetMemoryRegionType(List, ntTib.StackLimit, TRUE, StackRegion))\n                        memoryItem->u.Stack.ThreadId = thread->ThreadInfo.ClientId.UniqueThread;\n                }\n#ifdef _WIN64\n\n                if (isWow64 && ntTib.ExceptionList)\n                {\n                    ULONG teb32 = PtrToUlong(ntTib.ExceptionList);\n                    NT_TIB32 ntTib32;\n\n                    // 64-bit and 32-bit TEBs usually share the same memory region, so don't do anything for the 32-bit\n                    // TEB.\n\n                    if (NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, UlongToPtr(teb32), &ntTib32, sizeof(NT_TIB32), &bytesRead)) &&\n                        bytesRead == sizeof(NT_TIB32))\n                    {\n                        if (ntTib32.StackLimit < ntTib32.StackBase)\n                        {\n                            if (memoryItem = PhpSetMemoryRegionType(List, UlongToPtr(ntTib32.StackLimit), TRUE, Stack32Region))\n                                memoryItem->u.Stack.ThreadId = thread->ThreadInfo.ClientId.UniqueThread;\n                        }\n                    }\n                }\n#endif\n            }\n\n            // TEB->Win32ClientInfo.DesktopBase (which nowadays is a pointer to the start of the desktop heap)\n            // used to be called ClientDelta before RS2 and used to store the difference between the kernel and\n            // the user mappings of the desktop heap. TEB->Win32ClientInfo.DeskInfo, on the other hand, has\n            // always been a pointer to a structure on the desktop heap. (diversenok)\n\n            // Desktop heap\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(thread->TebBaseAddress, FIELD_OFFSET(TEB, Win32ClientInfo.DeskInfo)),\n                &desktopInfo,\n                sizeof(PVOID),\n                NULL\n                )) && desktopInfo)\n            {\n                PhpSetMemoryRegionType(List, desktopInfo, TRUE, DesktopHeapRegion);\n            }\n        }\n    }\n\n    // Mapped file, heap segment, unusable\n    for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink)\n    {\n        memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry);\n\n        if (memoryItem->RegionType != UnknownRegion)\n            continue;\n\n        if (FlagOn(memoryItem->Type, MEM_MAPPED | MEM_IMAGE) && memoryItem->AllocationBaseItem == memoryItem)\n        {\n            MEMORY_IMAGE_INFORMATION imageInfo;\n            PPH_STRING fileName;\n\n            if (FlagOn(memoryItem->Type, MEM_IMAGE))\n            {\n                if (NT_SUCCESS(PhGetProcessMappedImageInformation(ProcessHandle, memoryItem->BaseAddress, &imageInfo)))\n                {\n                    memoryItem->u.MappedFile.SigningLevelValid = TRUE;\n                    memoryItem->u.MappedFile.SigningLevel = (SE_SIGNING_LEVEL)imageInfo.ImageSigningLevel;\n                }\n            }\n\n            if (NT_SUCCESS(PhGetProcessMappedFileName(ProcessHandle, memoryItem->BaseAddress, &fileName)))\n            {\n                PPH_STRING newFileName = PhResolveDevicePrefix(&fileName->sr);\n\n                if (newFileName)\n                    PhMoveReference(&fileName, newFileName);\n\n                memoryItem->RegionType = MappedFileRegion;\n                memoryItem->u.MappedFile.FileName = fileName;\n                continue;\n            }\n        }\n\n        if (FlagOn(memoryItem->State, MEM_COMMIT) && memoryItem->Valid && !memoryItem->Bad)\n        {\n            UCHAR buffer[HEAP_SEGMENT_MAX_SIZE];\n\n            if (NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, memoryItem->BaseAddress, buffer, sizeof(buffer), NULL)))\n            {\n                PVOID candidateHeap = NULL;\n                ULONG candidateHeap32 = 0;\n                PPH_MEMORY_ITEM heapMemoryItem;\n                PHEAP_SEGMENT heapSegment = (PHEAP_SEGMENT)buffer;\n                PHEAP_SEGMENT32 heapSegment32 = (PHEAP_SEGMENT32)buffer;\n\n                if (heapSegment->SegmentSignature == HEAP_SEGMENT_SIGNATURE)\n                    candidateHeap = heapSegment->Heap;\n                if (heapSegment32->SegmentSignature == HEAP_SEGMENT_SIGNATURE)\n                    candidateHeap32 = heapSegment32->Heap;\n\n                if (candidateHeap)\n                {\n                    heapMemoryItem = PhLookupMemoryItemList(List, candidateHeap);\n\n                    if (heapMemoryItem && heapMemoryItem->BaseAddress == candidateHeap &&\n                        heapMemoryItem->RegionType == HeapRegion)\n                    {\n                        memoryItem->RegionType = HeapSegmentRegion;\n                        memoryItem->u.HeapSegment.HeapItem = heapMemoryItem;\n                        continue;\n                    }\n                }\n                else if (candidateHeap32)\n                {\n                    heapMemoryItem = PhLookupMemoryItemList(List, UlongToPtr(candidateHeap32));\n\n                    if (heapMemoryItem && heapMemoryItem->BaseAddress == UlongToPtr(candidateHeap32) &&\n                        heapMemoryItem->RegionType == Heap32Region)\n                    {\n                        memoryItem->RegionType = HeapSegment32Region;\n                        memoryItem->u.HeapSegment.HeapItem = heapMemoryItem;\n                        continue;\n                    }\n                }\n            }\n        }\n\n        if (FlagOn(memoryItem->Type, MEM_MAPPED) &&\n            memoryItem->AllocationProtect == PAGE_READONLY &&\n            memoryItem->AllocationBaseItem == memoryItem)\n        {\n            ACTIVATION_CONTEXT_DATA buffer;\n\n            if (NT_SUCCESS(PhReadVirtualMemory(ProcessHandle, memoryItem->BaseAddress, &buffer, sizeof(buffer), NULL)))\n            {\n                if (buffer.Magic == ACTIVATION_CONTEXT_DATA_MAGIC)\n                {\n                    memoryItem->RegionType = ActivationContextDataRegion;\n                    memoryItem->u.ActivationContextData.Type = CustomActivationContext;\n                    continue;\n                }\n            }\n        }\n    }\n\n#ifdef _WIN64\n\n    PS_SYSTEM_DLL_INIT_BLOCK ldrInitBlock;\n    PPH_MEMORY_ITEM cfgBitmapMemoryItem;\n\n    status = PhGetProcessSystemDllInitBlock(ProcessHandle, &ldrInitBlock);\n\n    if (NT_SUCCESS(status))\n    {\n        if (RTL_CONTAINS_FIELD(&ldrInitBlock, ldrInitBlock.Size, CfgBitMap) &&\n            ldrInitBlock.CfgBitMap && (cfgBitmapMemoryItem = PhLookupMemoryItemList(List, (PVOID)ldrInitBlock.CfgBitMap)))\n        {\n            listEntry = &cfgBitmapMemoryItem->ListEntry;\n            memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry);\n\n            while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem)\n            {\n                // lucasg: We could do a finer tagging since each MEM_COMMIT memory\n                // map is the CFG bitmap of a loaded module. However that might be\n                // brittle to changes made by Windows dev teams.\n                memoryItem->RegionType = CfgBitmapRegion;\n\n                listEntry = listEntry->Flink;\n                memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry);\n            }\n        }\n\n        // Note: Wow64 processes on 64bit also have CfgBitmap regions.\n        if (RTL_CONTAINS_FIELD(&ldrInitBlock, ldrInitBlock.Size, Wow64CfgBitMap) &&\n            isWow64 && ldrInitBlock.Wow64CfgBitMap && (cfgBitmapMemoryItem = PhLookupMemoryItemList(List, (PVOID)ldrInitBlock.Wow64CfgBitMap)))\n        {\n            listEntry = &cfgBitmapMemoryItem->ListEntry;\n            memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry);\n\n            while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem)\n            {\n                memoryItem->RegionType = CfgBitmap32Region;\n\n                listEntry = listEntry->Flink;\n                memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry);\n            }\n        }\n    }\n#endif\n\n    PhFree(processes);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhpUpdateMemoryWsCounters(\n    _In_ PPH_MEMORY_ITEM_LIST List,\n    _In_ HANDLE ProcessHandle\n    )\n{\n    PLIST_ENTRY listEntry;\n    PMEMORY_WORKING_SET_EX_INFORMATION info;\n\n    info = PhAllocatePage(WS_REQUEST_COUNT * sizeof(MEMORY_WORKING_SET_EX_INFORMATION), NULL);\n\n    if (!info)\n        return STATUS_NO_MEMORY;\n\n    for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink)\n    {\n        PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry);\n        ULONG_PTR virtualAddress;\n        SIZE_T remainingPages;\n        SIZE_T requestPages;\n        SIZE_T i;\n\n        if (!(memoryItem->State & MEM_COMMIT))\n            continue;\n\n        virtualAddress = (ULONG_PTR)memoryItem->BaseAddress;\n        remainingPages = memoryItem->RegionSize / PAGE_SIZE;\n\n        while (remainingPages != 0)\n        {\n            requestPages = min(remainingPages, WS_REQUEST_COUNT);\n\n            for (i = 0; i < requestPages; i++)\n            {\n                info[i].VirtualAddress = (PVOID)virtualAddress;\n                virtualAddress += PAGE_SIZE;\n            }\n\n            if (NT_SUCCESS(NtQueryVirtualMemory(\n                ProcessHandle,\n                NULL,\n                MemoryWorkingSetExInformation,\n                info,\n                requestPages * sizeof(MEMORY_WORKING_SET_EX_INFORMATION),\n                NULL\n                )))\n            {\n                for (i = 0; i < requestPages; i++)\n                {\n                    PMEMORY_WORKING_SET_EX_BLOCK block = &info[i].VirtualAttributes;\n\n                    if (block->Valid)\n                    {\n                        memoryItem->TotalWorkingSetPages++;\n\n                        if (block->ShareCount > 1)\n                            memoryItem->SharedWorkingSetPages++;\n                        if (block->ShareCount == 0)\n                            memoryItem->PrivateWorkingSetPages++;\n                        if (block->Shared)\n                            memoryItem->ShareableWorkingSetPages++;\n                        if (block->Locked)\n                            memoryItem->LockedWorkingSetPages++;\n\n                        if (memoryItem->Type & (MEM_MAPPED | MEM_IMAGE) && block->SharedOriginal)\n                            memoryItem->SharedOriginalPages++;\n                        if (block->Priority > memoryItem->Priority)\n                            memoryItem->Priority = block->Priority;\n                    }\n                    else\n                    {\n                        if (memoryItem->Type & (MEM_MAPPED | MEM_IMAGE) && block->Invalid.SharedOriginal)\n                            memoryItem->SharedOriginalPages++;\n\n                        // VMMap does this, but is it correct? (dmex)\n                        if (block->Invalid.Shared)\n                            memoryItem->ShareableWorkingSetPages++;\n                    }\n                }\n            }\n\n            remainingPages -= requestPages;\n        }\n    }\n\n    PhFreePage(info);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhpUpdateMemoryWsCountersOld(\n    _In_ PPH_MEMORY_ITEM_LIST List,\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    PMEMORY_WORKING_SET_INFORMATION info;\n    PPH_MEMORY_ITEM memoryItem = NULL;\n    ULONG_PTR i;\n\n    if (!NT_SUCCESS(status = PhGetProcessWorkingSetInformation(ProcessHandle, &info)))\n        return status;\n\n    for (i = 0; i < info->NumberOfEntries; i++)\n    {\n        PMEMORY_WORKING_SET_BLOCK block = &info->WorkingSetInfo[i];\n        ULONG_PTR virtualAddress = block->VirtualPage * PAGE_SIZE;\n\n        if (!memoryItem || virtualAddress < (ULONG_PTR)memoryItem->BaseAddress ||\n            virtualAddress >= (ULONG_PTR)memoryItem->BaseAddress + memoryItem->RegionSize)\n        {\n            memoryItem = PhLookupMemoryItemList(List, (PVOID)virtualAddress);\n        }\n\n        if (memoryItem)\n        {\n            memoryItem->TotalWorkingSetPages++;\n\n            if (block->ShareCount > 1)\n                memoryItem->SharedWorkingSetPages++;\n            if (block->ShareCount == 0)\n                memoryItem->PrivateWorkingSetPages++;\n            if (block->Shared)\n                memoryItem->ShareableWorkingSetPages++;\n        }\n    }\n\n    PhFree(info);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhQueryMemoryItemList(\n    _In_ HANDLE ProcessId,\n    _In_ ULONG Flags,\n    _Out_ PPH_MEMORY_ITEM_LIST List\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    ULONG_PTR allocationGranularity;\n    PVOID baseAddress = (PVOID)0;\n    MEMORY_BASIC_INFORMATION basicInfo;\n    PPH_MEMORY_ITEM allocationBaseItem = NULL;\n    PPH_MEMORY_ITEM previousMemoryItem = NULL;\n\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n        ProcessId\n        )))\n    {\n        if (!NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            ProcessId\n            )))\n        {\n            return status;\n        }\n    }\n\n    List->ProcessId = ProcessId;\n    PhInitializeAvlTree(&List->Set, PhpMemoryItemCompareFunction);\n    InitializeListHead(&List->ListHead);\n\n    allocationGranularity = PhSystemBasicInformation.AllocationGranularity;\n\n    while (NT_SUCCESS(NtQueryVirtualMemory(\n        processHandle,\n        baseAddress,\n        MemoryBasicInformation,\n        &basicInfo,\n        sizeof(MEMORY_BASIC_INFORMATION),\n        NULL\n        )))\n    {\n        PPH_MEMORY_ITEM memoryItem;\n\n        if (basicInfo.State & MEM_FREE)\n        {\n            if (Flags & PH_QUERY_MEMORY_IGNORE_FREE)\n                goto ContinueLoop;\n\n            basicInfo.AllocationBase = basicInfo.BaseAddress;\n        }\n\n        memoryItem = PhCreateMemoryItem();\n        memoryItem->BasicInfo = basicInfo;\n\n        if (basicInfo.AllocationBase == basicInfo.BaseAddress)\n            allocationBaseItem = memoryItem;\n        if (allocationBaseItem && basicInfo.AllocationBase == allocationBaseItem->BaseAddress)\n            memoryItem->AllocationBaseItem = allocationBaseItem;\n\n        if (Flags & PH_QUERY_MEMORY_ZERO_PAD_ADDRESSES)\n            PhPrintPointerPadZeros(memoryItem->BaseAddressString, memoryItem->BasicInfo.BaseAddress);\n        else\n            PhPrintPointer(memoryItem->BaseAddressString, memoryItem->BasicInfo.BaseAddress);\n\n        if (basicInfo.State & MEM_COMMIT)\n        {\n            memoryItem->CommittedSize = memoryItem->RegionSize;\n\n            if (basicInfo.Type & MEM_PRIVATE)\n                memoryItem->PrivateSize = memoryItem->RegionSize;\n        }\n\n        if (!FlagOn(basicInfo.State, MEM_FREE))\n        {\n            MEMORY_WORKING_SET_EX_INFORMATION pageInfo;\n\n            static_assert(HEAP_SEGMENT_MAX_SIZE < PAGE_SIZE, \"Update query attributes for additional pages\");\n\n            // Query the attributes for the first page (dmex)\n\n            memset(&pageInfo, 0, sizeof(MEMORY_WORKING_SET_EX_INFORMATION));\n            pageInfo.VirtualAddress = baseAddress;\n\n            if (NT_SUCCESS(NtQueryVirtualMemory(\n                processHandle,\n                NULL,\n                MemoryWorkingSetExInformation,\n                &pageInfo,\n                sizeof(MEMORY_WORKING_SET_EX_INFORMATION),\n                NULL\n                )))\n            {\n                PMEMORY_WORKING_SET_EX_BLOCK block = &pageInfo.VirtualAttributes;\n\n                memoryItem->Valid = !!block->Valid;\n                memoryItem->Bad = !!block->Bad;\n            }\n\n            if (WindowsVersion > WINDOWS_8)\n            {\n                MEMORY_REGION_INFORMATION regionInfo;\n\n                // Query the region (dmex)\n\n                memset(&regionInfo, 0, sizeof(MEMORY_REGION_INFORMATION));\n\n                if (NT_SUCCESS(NtQueryVirtualMemory(\n                    processHandle,\n                    baseAddress,\n                    MemoryRegionInformationEx,\n                    &regionInfo,\n                    sizeof(MEMORY_REGION_INFORMATION),\n                    NULL\n                    )))\n                {\n                    memoryItem->RegionTypeEx = regionInfo.RegionType;\n                    //memoryItem->RegionSize = regionInfo.RegionSize;\n                    //memoryItem->CommittedSize = regionInfo.CommitSize;\n                }\n            }\n        }\n\n        PhAddElementAvlTree(&List->Set, &memoryItem->Links);\n        InsertTailList(&List->ListHead, &memoryItem->ListEntry);\n\n        if (basicInfo.State & MEM_FREE)\n        {\n            if ((ULONG_PTR)basicInfo.BaseAddress & (allocationGranularity - 1))\n            {\n                ULONG_PTR nextAllocationBase;\n                ULONG_PTR potentialUnusableSize;\n\n                // Split this free region into an unusable and a (possibly empty) usable region.\n\n                nextAllocationBase = ALIGN_UP_BY(basicInfo.BaseAddress, allocationGranularity);\n                potentialUnusableSize = nextAllocationBase - (ULONG_PTR)basicInfo.BaseAddress;\n\n                memoryItem->RegionType = UnusableRegion;\n\n                // VMMap does this, but is it correct?\n                //if (previousMemoryItem && (previousMemoryItem->State & MEM_COMMIT))\n                //    memoryItem->CommittedSize = min(potentialUnusableSize, basicInfo.RegionSize);\n\n                if (nextAllocationBase < (ULONG_PTR)basicInfo.BaseAddress + basicInfo.RegionSize)\n                {\n                    PPH_MEMORY_ITEM otherMemoryItem;\n\n                    memoryItem->RegionSize = potentialUnusableSize;\n\n                    otherMemoryItem = PhCreateMemoryItem();\n                    otherMemoryItem->BasicInfo = basicInfo;\n                    otherMemoryItem->BaseAddress = (PVOID)nextAllocationBase;\n                    otherMemoryItem->AllocationBase = otherMemoryItem->BaseAddress;\n                    otherMemoryItem->RegionSize = basicInfo.RegionSize - potentialUnusableSize;\n                    otherMemoryItem->AllocationBaseItem = otherMemoryItem;\n\n                    if (Flags & PH_QUERY_MEMORY_ZERO_PAD_ADDRESSES)\n                        PhPrintPointerPadZeros(otherMemoryItem->BaseAddressString, otherMemoryItem->BasicInfo.BaseAddress);\n                    else\n                        PhPrintPointer(otherMemoryItem->BaseAddressString, otherMemoryItem->BasicInfo.BaseAddress);\n\n                    PhAddElementAvlTree(&List->Set, &otherMemoryItem->Links);\n                    InsertTailList(&List->ListHead, &otherMemoryItem->ListEntry);\n\n                    previousMemoryItem = otherMemoryItem;\n                    goto ContinueLoop;\n                }\n            }\n        }\n\n        previousMemoryItem = memoryItem;\n\nContinueLoop:\n        baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize);\n    }\n\n    if (Flags & PH_QUERY_MEMORY_REGION_TYPE)\n        PhpUpdateMemoryRegionTypes(List, processHandle);\n\n    if (Flags & PH_QUERY_MEMORY_WS_COUNTERS)\n        PhpUpdateMemoryWsCounters(List, processHandle);\n\n    NtClose(processHandle);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "SystemInformer/memrslt.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <emenu.h>\n#include <mainwnd.h>\n#include <memsrch.h>\n#include <procprv.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <thirdparty.h>\n\n#define FILTER_CONTAINS 1\n#define FILTER_CONTAINS_IGNORECASE 2\n#define FILTER_REGEX 3\n#define FILTER_REGEX_IGNORECASE 4\n\ntypedef struct _MEMORY_RESULTS_CONTEXT\n{\n    HANDLE ProcessId;\n    PPH_LIST Results;\n\n    PH_LAYOUT_MANAGER LayoutManager;\n} MEMORY_RESULTS_CONTEXT, *PMEMORY_RESULTS_CONTEXT;\n\nstatic RECT MinimumSize = { -1, -1, -1, -1 };\n\nstatic PPH_STRING PhpGetStringForSelectedResults(\n    _In_ HWND ListViewHandle,\n    _In_ PPH_LIST Results,\n    _In_ BOOLEAN All\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n\n    PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n    for (ULONG i = 0; i < Results->Count; i++)\n    {\n        PPH_MEMORY_RESULT result;\n        WCHAR value[PH_PTR_STR_LEN_1];\n\n        if (!All)\n        {\n            if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED))\n                continue;\n        }\n\n        result = Results->Items[i];\n\n        PhPrintPointer(value, result->Address);\n        PhAppendFormatStringBuilder(\n            &stringBuilder,\n            L\"%s (%lu): %s\\r\\n\",\n            value,\n            (ULONG)result->Length,\n            result->Display.Buffer ? result->Display.Buffer : L\"\"\n            );\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nstatic VOID FilterResults(\n    _In_ HWND hwndDlg,\n    _In_ PMEMORY_RESULTS_CONTEXT Context,\n    _In_ ULONG Type\n    )\n{\n    PPH_STRING selectedChoice = NULL;\n    PPH_LIST results;\n    pcre2_code *compiledExpression;\n    pcre2_match_data *matchData;\n\n    results = Context->Results;\n\n    PhSetCursor(PhLoadCursor(NULL, IDC_WAIT));\n\n    while (PhaChoiceDialog(\n        hwndDlg,\n        L\"Filter\",\n        L\"Enter the filter pattern:\",\n        NULL,\n        0,\n        NULL,\n        PH_CHOICE_DIALOG_USER_CHOICE,\n        &selectedChoice,\n        NULL,\n        SETTING_MEM_FILTER_CHOICES\n        ))\n    {\n        PPH_LIST newResults = NULL;\n        ULONG i;\n\n        if (Type == FILTER_CONTAINS || Type == FILTER_CONTAINS_IGNORECASE)\n        {\n            newResults = PhCreateList(1024);\n\n            if (Type == FILTER_CONTAINS)\n            {\n                for (i = 0; i < results->Count; i++)\n                {\n                    PPH_MEMORY_RESULT result = results->Items[i];\n\n                    if (wcsstr(result->Display.Buffer, selectedChoice->Buffer))\n                    {\n                        PhReferenceMemoryResult(result);\n                        PhAddItemList(newResults, result);\n                    }\n                }\n            }\n            else\n            {\n                PPH_STRING upperChoice;\n\n                upperChoice = PhaUpperString(selectedChoice);\n\n                for (i = 0; i < results->Count; i++)\n                {\n                    PPH_MEMORY_RESULT result = results->Items[i];\n                    PWSTR upperDisplay;\n\n                    upperDisplay = PhAllocateForMemorySearch(result->Display.Length + sizeof(WCHAR));\n                    // Copy the null terminator as well.\n                    memcpy(upperDisplay, result->Display.Buffer, result->Display.Length + sizeof(WCHAR));\n\n                    _wcsupr(upperDisplay);\n\n                    if (wcsstr(upperDisplay, upperChoice->Buffer))\n                    {\n                        PhReferenceMemoryResult(result);\n                        PhAddItemList(newResults, result);\n                    }\n\n                    PhFreeForMemorySearch(upperDisplay);\n                }\n            }\n        }\n        else if (Type == FILTER_REGEX || Type == FILTER_REGEX_IGNORECASE)\n        {\n            int errorCode;\n            PCRE2_SIZE errorOffset;\n\n            compiledExpression = pcre2_compile(\n                selectedChoice->Buffer,\n                selectedChoice->Length / sizeof(WCHAR),\n                (Type == FILTER_REGEX_IGNORECASE ? PCRE2_CASELESS : 0) | PCRE2_DOTALL,\n                &errorCode,\n                &errorOffset,\n                NULL\n                );\n\n            if (!compiledExpression)\n            {\n                PhShowError2(hwndDlg, L\"Unable to compile the regular expression.\",\n                    L\"\\\"%s\\\" at position %zu.\",\n                    PhGetStringOrDefault(PH_AUTO(PhPcre2GetErrorMessage(errorCode)), L\"Unknown error\"),\n                    errorOffset\n                    );\n                continue;\n            }\n\n            matchData = pcre2_match_data_create_from_pattern(compiledExpression, NULL);\n\n            newResults = PhCreateList(1024);\n\n            for (i = 0; i < results->Count; i++)\n            {\n                PPH_MEMORY_RESULT result = results->Items[i];\n\n                if (pcre2_match(\n                    compiledExpression,\n                    result->Display.Buffer,\n                    result->Display.Length / sizeof(WCHAR),\n                    0,\n                    0,\n                    matchData,\n                    NULL\n                    ) >= 0)\n                {\n                    PhReferenceMemoryResult(result);\n                    PhAddItemList(newResults, result);\n                }\n            }\n\n            pcre2_match_data_free(matchData);\n            pcre2_code_free(compiledExpression);\n        }\n\n        if (newResults)\n        {\n            PhShowMemoryResultsDialog(Context->ProcessId, newResults);\n            PhDereferenceMemoryResults((PPH_MEMORY_RESULT *)newResults->Items, newResults->Count);\n            PhDereferenceObject(newResults);\n            break;\n        }\n    }\n\n    PhSetCursor(PhLoadCursor(NULL, IDC_ARROW));\n}\n\nINT_PTR CALLBACK PhpMemoryResultsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PMEMORY_RESULTS_CONTEXT context;\n\n    if (uMsg != WM_INITDIALOG)\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n    else\n    {\n        context = (PMEMORY_RESULTS_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HWND lvHandle;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhRegisterDialog(hwndDlg);\n\n            {\n                PPH_PROCESS_ITEM processItem;\n\n                if (processItem = PhReferenceProcessItem(context->ProcessId))\n                {\n                    PhSetWindowText(hwndDlg, PhaFormatString(L\"Results - %s (%u)\",\n                        processItem->ProcessName->Buffer, HandleToUlong(processItem->ProcessId))->Buffer);\n                    PhDereferenceObject(processItem);\n                }\n            }\n\n            lvHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            PhSetListViewStyle(lvHandle, TRUE, TRUE);\n            PhSetControlTheme(lvHandle, L\"explorer\");\n            PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L\"Address\");\n            PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 120, L\"Base Address\");\n            PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L\"Length\");\n            PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 200, L\"Result\");\n            PhSetExtendedListView(lvHandle);\n\n            PhLoadListViewColumnsFromSetting(SETTING_MEM_RESULTS_LIST_VIEW_COLUMNS, lvHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);\n\n            if (MinimumSize.left == -1)\n            {\n                RECT rect;\n\n                rect.left = 0;\n                rect.top = 0;\n                rect.right = 250;\n                rect.bottom = 180;\n                MapDialogRect(hwndDlg, &rect);\n                MinimumSize = rect;\n                MinimumSize.left = 0;\n            }\n\n            ListView_SetItemCount(lvHandle, context->Results->Count);\n\n            PhSetDialogItemText(hwndDlg, IDC_INTRO, PhaFormatString(L\"%s results.\",\n                PhaFormatUInt64(context->Results->Count, TRUE)->Buffer)->Buffer);\n\n            {\n                PH_RECTANGLE windowRectangle = {0};\n                RECT rect;\n                LONG dpiValue;\n\n                windowRectangle.Position = PhGetIntegerPairSetting(SETTING_MEM_RESULTS_POSITION);\n                PhRectangleToRect(&rect, &windowRectangle);\n                dpiValue = PhGetMonitorDpi(NULL, &rect);\n                windowRectangle.Size = PhGetScalableIntegerPairSetting(SETTING_MEM_RESULTS_SIZE, TRUE, dpiValue)->Pair;\n                PhAdjustRectangleToWorkingArea(NULL, &windowRectangle);\n\n                MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top,\n                    windowRectangle.Width, windowRectangle.Height, FALSE);\n\n                // Implement cascading by saving an offsetted rectangle.\n                windowRectangle.Left += 20;\n                windowRectangle.Top += 20;\n\n                PhSetIntegerPairSetting(SETTING_MEM_RESULTS_POSITION, windowRectangle.Position);\n                PhSetScalableIntegerPairSetting2(SETTING_MEM_RESULTS_SIZE, windowRectangle.Size, dpiValue);\n            }\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveWindowPlacementToSetting(SETTING_MEM_RESULTS_POSITION, SETTING_MEM_RESULTS_SIZE, hwndDlg);\n            PhSaveListViewColumnsToSetting(SETTING_MEM_RESULTS_LIST_VIEW_COLUMNS, GetDlgItem(hwndDlg, IDC_LIST));\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n            PhUnregisterDialog(hwndDlg);\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDereferenceMemoryResults((PPH_MEMORY_RESULT *)context->Results->Items, context->Results->Count);\n            PhDereferenceObject(context->Results);\n            PhFree(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                DestroyWindow(hwndDlg);\n                break;\n            case IDC_COPY:\n                {\n                    HWND lvHandle;\n                    PPH_STRING string;\n                    ULONG selectedCount;\n\n                    lvHandle = GetDlgItem(hwndDlg, IDC_LIST);\n                    selectedCount = ListView_GetSelectedCount(lvHandle);\n\n                    if (selectedCount == 0)\n                    {\n                        // User didn't select anything, so copy all items.\n                        string = PhpGetStringForSelectedResults(lvHandle, context->Results, TRUE);\n                        PhSetStateAllListViewItems(lvHandle, LVIS_SELECTED, LVIS_SELECTED);\n                    }\n                    else\n                    {\n                        string = PhpGetStringForSelectedResults(lvHandle, context->Results, FALSE);\n                    }\n\n                    PhSetClipboardString(hwndDlg, &string->sr);\n                    PhDereferenceObject(string);\n\n                    PhSetDialogFocus(hwndDlg, lvHandle);\n                }\n                break;\n            case IDC_SAVE:\n                {\n                    static PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Text files (*.txt)\", L\"*.txt\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog;\n\n                    fileDialog = PhCreateSaveFileDialog();\n                    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n                    PhSetFileDialogFileName(fileDialog, L\"Search results.txt\");\n\n                    if (PhShowFileDialog(hwndDlg, fileDialog))\n                    {\n                        NTSTATUS status;\n                        PPH_STRING fileName;\n                        PPH_FILE_STREAM fileStream;\n                        PPH_STRING string;\n\n                        fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n\n                        if (NT_SUCCESS(status = PhCreateFileStream(\n                            &fileStream,\n                            fileName->Buffer,\n                            FILE_GENERIC_WRITE,\n                            FILE_SHARE_READ,\n                            FILE_OVERWRITE_IF,\n                            0\n                            )))\n                        {\n                            PhWriteStringAsUtf8FileStream(fileStream, (PPH_STRINGREF)&PhUnicodeByteOrderMark);\n                            PhWritePhTextHeader(fileStream);\n\n                            string = PhpGetStringForSelectedResults(GetDlgItem(hwndDlg, IDC_LIST), context->Results, TRUE);\n                            PhWriteStringAsUtf8FileStreamEx(fileStream, string->Buffer, string->Length);\n                            PhDereferenceObject(string);\n\n                            PhDereferenceObject(fileStream);\n                        }\n\n                        if (!NT_SUCCESS(status))\n                            PhShowStatus(hwndDlg, L\"Unable to create the file\", status, 0);\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            case IDC_FILTER:\n                {\n                    PPH_EMENU menu;\n                    RECT buttonRect;\n                    POINT point;\n                    PPH_EMENU_ITEM selectedItem;\n                    ULONG filterType = 0;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_FILTER_CONTAINS, L\"Contains...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_FILTER_CONTAINS_CASEINSENSITIVE, L\"Contains (case-insensitive)...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_FILTER_REGEX, L\"Regex...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_FILTER_REGEX_CASEINSENSITIVE, L\"Regex (case-insensitive)...\", NULL, NULL), ULONG_MAX);\n\n                    if (!PhGetClientRect(GetDlgItem(hwndDlg, IDC_FILTER), &buttonRect))\n                        break;\n\n                    point.x = 0;\n                    point.y = buttonRect.bottom;\n\n                    ClientToScreen(GetDlgItem(hwndDlg, IDC_FILTER), &point);\n                    selectedItem = PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y);\n\n                    if (selectedItem)\n                    {\n                        switch (selectedItem->Id)\n                        {\n                        case ID_FILTER_CONTAINS:\n                            filterType = FILTER_CONTAINS;\n                            break;\n                        case ID_FILTER_CONTAINS_CASEINSENSITIVE:\n                            filterType = FILTER_CONTAINS_IGNORECASE;\n                            break;\n                        case ID_FILTER_REGEX:\n                            filterType = FILTER_REGEX;\n                            break;\n                        case ID_FILTER_REGEX_CASEINSENSITIVE:\n                            filterType = FILTER_REGEX_IGNORECASE;\n                            break;\n                        }\n                    }\n\n                    if (filterType != 0)\n                        FilterResults(hwndDlg, context, filterType);\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n            HWND lvHandle;\n\n            lvHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            PhHandleListViewNotifyForCopy(lParam, lvHandle);\n\n            switch (header->code)\n            {\n            case LVN_GETDISPINFO:\n                {\n                    NMLVDISPINFO *dispInfo = (NMLVDISPINFO *)header;\n\n                    if (dispInfo->item.mask & LVIF_TEXT)\n                    {\n                        PPH_MEMORY_RESULT result = context->Results->Items[dispInfo->item.iItem];\n\n                        switch (dispInfo->item.iSubItem)\n                        {\n                        case 0:\n                            {\n                                WCHAR addressString[PH_PTR_STR_LEN_1];\n\n                                PhPrintPointer(addressString, result->Address);\n                                wcsncpy_s(\n                                    dispInfo->item.pszText,\n                                    dispInfo->item.cchTextMax,\n                                    addressString,\n                                    _TRUNCATE\n                                    );\n                            }\n                            break;\n                        case 1:\n                            {\n                                WCHAR baseAddressString[PH_PTR_STR_LEN_1];\n\n                                PhPrintPointer(baseAddressString, result->BaseAddress);\n                                wcsncpy_s(\n                                    dispInfo->item.pszText,\n                                    dispInfo->item.cchTextMax,\n                                    baseAddressString,\n                                    _TRUNCATE\n                                    );\n                            }\n                            break;\n                        case 2:\n                            {\n                                WCHAR lengthString[PH_INT32_STR_LEN_1];\n\n                                PhPrintUInt32(lengthString, (ULONG)result->Length);\n                                wcsncpy_s(\n                                    dispInfo->item.pszText,\n                                    dispInfo->item.cchTextMax,\n                                    lengthString,\n                                    _TRUNCATE\n                                    );\n                            }\n                            break;\n                        case 3:\n                            wcsncpy_s(\n                                dispInfo->item.pszText,\n                                dispInfo->item.cchTextMax,\n                                result->Display.Buffer,\n                                _TRUNCATE\n                                );\n                            break;\n                        }\n                    }\n                }\n                break;\n            case NM_DBLCLK:\n                {\n                    if (header->hwndFrom == lvHandle)\n                    {\n                        INT index;\n\n                        if ((index = PhFindListViewItemByFlags(lvHandle, INT_ERROR, LVNI_SELECTED)) != INT_ERROR)\n                        {\n                            NTSTATUS status;\n                            PPH_MEMORY_RESULT result = context->Results->Items[index];\n                            HANDLE processHandle;\n                            MEMORY_BASIC_INFORMATION basicInfo;\n                            PPH_SHOW_MEMORY_EDITOR showMemoryEditor;\n\n                            if (NT_SUCCESS(status = PhOpenProcess(\n                                &processHandle,\n                                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n                                context->ProcessId\n                                )))\n                            {\n                                if (NT_SUCCESS(status = NtQueryVirtualMemory(\n                                    processHandle,\n                                    result->Address,\n                                    MemoryBasicInformation,\n                                    &basicInfo,\n                                    sizeof(MEMORY_BASIC_INFORMATION),\n                                    NULL\n                                    )))\n                                {\n                                    showMemoryEditor = PhAllocateZero(sizeof(PH_SHOW_MEMORY_EDITOR));\n                                    showMemoryEditor->ProcessId = context->ProcessId;\n                                    showMemoryEditor->BaseAddress = basicInfo.BaseAddress;\n                                    showMemoryEditor->RegionSize = basicInfo.RegionSize;\n                                    showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)result->Address - (ULONG_PTR)basicInfo.BaseAddress);\n                                    showMemoryEditor->SelectLength = (ULONG)result->Length;\n\n                                    SystemInformer_ShowMemoryEditor(showMemoryEditor);\n                                }\n\n                                NtClose(processHandle);\n                            }\n\n                            if (!NT_SUCCESS(status))\n                                PhShowStatus(hwndDlg, L\"Unable to edit memory\", status, 0);\n                        }\n                    }\n                }\n                break;\n            case NM_RCLICK:\n                {\n                    if (header->hwndFrom == lvHandle)\n                    {\n                        POINT position;\n                        PPH_EMENU menu;\n                        PPH_EMENU_ITEM selectedItem;\n\n                        if (!PhGetMessagePos(&position))\n                            break;\n\n                        menu = PhCreateEMenu();\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_READWRITEMEMORY, L\"Read/Write memory\", NULL, NULL), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"Copy\", NULL, NULL), ULONG_MAX);\n                        PhInsertCopyListViewEMenuItem(menu, IDC_COPY, lvHandle);\n\n                        selectedItem = PhShowEMenu(\n                            menu,\n                            hwndDlg,\n                            PH_EMENU_SHOW_LEFTRIGHT,\n                            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                            position.x,\n                            position.y\n                            );\n\n                        if (selectedItem)\n                        {\n                            if (!PhHandleCopyListViewEMenuItem(selectedItem))\n                            {\n                                switch (selectedItem->Id)\n                                {\n                                case ID_MEMORY_READWRITEMEMORY:\n                                    {\n                                        INT index;\n\n                                        if ((index = PhFindListViewItemByFlags(lvHandle, INT_ERROR, LVNI_SELECTED)) != INT_ERROR)\n                                        {\n                                            NTSTATUS status;\n                                            PPH_MEMORY_RESULT result = context->Results->Items[index];\n                                            HANDLE processHandle;\n                                            MEMORY_BASIC_INFORMATION basicInfo;\n                                            PPH_SHOW_MEMORY_EDITOR showMemoryEditor;\n\n                                            if (NT_SUCCESS(status = PhOpenProcess(\n                                                &processHandle,\n                                                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n                                                context->ProcessId\n                                                )))\n                                            {\n                                                if (NT_SUCCESS(status = NtQueryVirtualMemory(\n                                                    processHandle,\n                                                    result->Address,\n                                                    MemoryBasicInformation,\n                                                    &basicInfo,\n                                                    sizeof(MEMORY_BASIC_INFORMATION),\n                                                    NULL\n                                                    )))\n                                                {\n                                                    showMemoryEditor = PhAllocateZero(sizeof(PH_SHOW_MEMORY_EDITOR));\n                                                    showMemoryEditor->ProcessId = context->ProcessId;\n                                                    showMemoryEditor->BaseAddress = basicInfo.BaseAddress;\n                                                    showMemoryEditor->RegionSize = basicInfo.RegionSize;\n                                                    showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)result->Address - (ULONG_PTR)basicInfo.BaseAddress);\n                                                    showMemoryEditor->SelectLength = (ULONG)result->Length;\n\n                                                    SystemInformer_ShowMemoryEditor(showMemoryEditor);\n                                                }\n\n                                                NtClose(processHandle);\n                                            }\n\n                                            if (!NT_SUCCESS(status))\n                                                PhShowStatus(hwndDlg, L\"Unable to edit memory\", status, 0);\n                                        }\n                                    }\n                                    break;\n                                case IDC_COPY:\n                                    {\n                                        PPH_STRING string;\n                                        ULONG selectedCount;\n\n                                        selectedCount = ListView_GetSelectedCount(lvHandle);\n\n                                        if (selectedCount == 0)\n                                        {\n                                            // User didn't select anything, so copy all items.\n                                            string = PhpGetStringForSelectedResults(lvHandle, context->Results, TRUE);\n                                            PhSetStateAllListViewItems(lvHandle, LVIS_SELECTED, LVIS_SELECTED);\n                                        }\n                                        else\n                                        {\n                                            string = PhpGetStringForSelectedResults(lvHandle, context->Results, FALSE);\n                                        }\n\n                                        PhSetClipboardString(hwndDlg, &string->sr);\n                                        PhDereferenceObject(string);\n\n                                        PhSetDialogFocus(hwndDlg, lvHandle);\n                                    }\n                                    break;\n                                }\n                            }\n                        }\n\n                        PhDestroyEMenu(menu);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhShowMemoryResultsDialog(\n    _In_ HANDLE ProcessId,\n    _In_ PPH_LIST Results\n    )\n{\n    HWND windowHandle;\n    PMEMORY_RESULTS_CONTEXT context;\n    ULONG i;\n\n    context = PhAllocateZero(sizeof(MEMORY_RESULTS_CONTEXT));\n    context->ProcessId = ProcessId;\n    context->Results = Results;\n\n    PhReferenceObject(Results);\n\n    for (i = 0; i < Results->Count; i++)\n        PhReferenceMemoryResult(Results->Items[i]);\n\n    windowHandle = PhCreateDialog(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_MEMRESULTS),\n        NULL,\n        PhpMemoryResultsDlgProc,\n        context\n        );\n    ShowWindow(windowHandle, SW_SHOW);\n    SetForegroundWindow(windowHandle);\n}\n"
  },
  {
    "path": "SystemInformer/memsrch.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <emenu.h>\n#include <mainwnd.h>\n#include <memsrch.h>\n#include <memprv.h>\n#include <procprv.h>\n#include <settings.h>\n#include <strsrch.h>\n#include <colmgr.h>\n#include <cpysave.h>\n\n#define WM_PH_MEMORY_STATUS_UPDATE (WM_APP + 301)\n\n#define PH_SEARCH_UPDATE 1\n#define PH_SEARCH_COMPLETED 2\n\ntypedef struct _MEMORY_STRING_CONTEXT\n{\n    HANDLE ProcessId;\n    HANDLE ProcessHandle;\n    ULONG MinimumLength;\n\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN DetectUnicode : 1;\n            BOOLEAN Private : 1;\n            BOOLEAN Image : 1;\n            BOOLEAN Mapped : 1;\n            BOOLEAN EnableCloseDialog : 1;\n            BOOLEAN ExtendedUnicode : 1;\n            BOOLEAN Spare : 2;\n        };\n    };\n\n    HWND ParentWindowHandle;\n    HWND WindowHandle;\n    WNDPROC DefaultWindowProc;\n    PH_MEMORY_STRING_OPTIONS Options;\n    PPH_LIST Results;\n} MEMORY_STRING_CONTEXT, *PMEMORY_STRING_CONTEXT;\n\ntypedef struct _MEMORY_STRING_SEARCH_CONTEXT\n{\n    PPH_MEMORY_SEARCH_OPTIONS Options;\n    HANDLE ProcessHandle;\n    ULONG TypeMask;\n    BOOLEAN DetectUnicode;\n\n    MEMORY_BASIC_INFORMATION BasicInfo;\n    PVOID CurrentReadAddress;\n    PVOID NextReadAddress;\n    SIZE_T ReadRemaning;\n    PBYTE Buffer;\n    SIZE_T BufferSize;\n} MEMORY_STRING_SEARCH_CONTEXT, *PMEMORY_STRING_SEARCH_CONTEXT;\n\nINT_PTR CALLBACK PhpMemoryStringDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nBOOLEAN PhpShowMemoryStringProgressDialog(\n    _In_ PMEMORY_STRING_CONTEXT Context\n    );\n\nBOOLEAN PhpShowMemoryStringDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_opt_ PPH_LIST PrevNodeList\n    );\n\nPVOID PhMemorySearchHeap = NULL;\nLONG PhMemorySearchHeapRefCount = 0;\nPH_QUEUED_LOCK PhMemorySearchHeapLock = PH_QUEUED_LOCK_INIT;\n\nPVOID PhAllocateForMemorySearch(\n    _In_ SIZE_T Size\n    )\n{\n    PVOID memory;\n\n    PhAcquireQueuedLockExclusive(&PhMemorySearchHeapLock);\n\n    if (!PhMemorySearchHeap)\n    {\n        assert(PhMemorySearchHeapRefCount == 0);\n        PhMemorySearchHeap = RtlCreateHeap(\n            HEAP_GROWABLE | HEAP_CLASS_1,\n            NULL,\n            8192 * 1024, // 8 MB\n            2048 * 1024, // 2 MB\n            NULL,\n            NULL\n            );\n    }\n\n    if (PhMemorySearchHeap)\n    {\n        const ULONG defaultHeapCompatibilityMode = HEAP_COMPATIBILITY_MODE_LFH;\n        RtlSetHeapInformation(\n            PhMemorySearchHeap,\n            HeapCompatibilityInformation,\n            &defaultHeapCompatibilityMode,\n            sizeof(ULONG)\n            );\n\n        // Don't use HEAP_NO_SERIALIZE - it's very slow on Vista and above.\n        memory = RtlAllocateHeap(PhMemorySearchHeap, 0, Size);\n\n        if (memory)\n            PhMemorySearchHeapRefCount++;\n    }\n    else\n    {\n        memory = NULL;\n    }\n\n    PhReleaseQueuedLockExclusive(&PhMemorySearchHeapLock);\n\n    return memory;\n}\n\nVOID PhFreeForMemorySearch(\n    _In_ _Post_invalid_ PVOID Memory\n    )\n{\n    PhAcquireQueuedLockExclusive(&PhMemorySearchHeapLock);\n\n    RtlFreeHeap(PhMemorySearchHeap, 0, Memory);\n\n    if (--PhMemorySearchHeapRefCount == 0)\n    {\n        RtlDestroyHeap(PhMemorySearchHeap);\n        PhMemorySearchHeap = NULL;\n    }\n\n    PhReleaseQueuedLockExclusive(&PhMemorySearchHeapLock);\n}\n\nPVOID PhCreateMemoryResult(\n    _In_ PVOID Address,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T Length\n    )\n{\n    PPH_MEMORY_RESULT result;\n\n    result = PhAllocateForMemorySearch(sizeof(PH_MEMORY_RESULT));\n\n    if (!result)\n        return NULL;\n\n    result->RefCount = 1;\n    result->Address = Address;\n    result->BaseAddress = BaseAddress;\n    result->Length = Length;\n    result->Display.Length = 0;\n    result->Display.Buffer = NULL;\n\n    return result;\n}\n\nVOID PhReferenceMemoryResult(\n    _In_ PPH_MEMORY_RESULT Result\n    )\n{\n    _InterlockedIncrement(&Result->RefCount);\n}\n\nVOID PhDereferenceMemoryResult(\n    _In_ PPH_MEMORY_RESULT Result\n    )\n{\n    if (_InterlockedDecrement(&Result->RefCount) == 0)\n    {\n        if (Result->Display.Buffer)\n            PhFreeForMemorySearch(Result->Display.Buffer);\n\n        PhFreeForMemorySearch(Result);\n    }\n}\n\nVOID PhDereferenceMemoryResults(\n    _In_reads_(NumberOfResults) PPH_MEMORY_RESULT *Results,\n    _In_ ULONG NumberOfResults\n    )\n{\n    for (ULONG i = 0; i < NumberOfResults; i++)\n        PhDereferenceMemoryResult(Results[i]);\n}\n\n_Function_class_(PH_STRING_SEARCH_NEXT_BUFFER)\n_Must_inspect_result_\nNTSTATUS NTAPI PhpMemoryStringSearchNextBuffer(\n    _Inout_bytecount_(*Length) PVOID* Buffer,\n    _Out_ PSIZE_T Length,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PMEMORY_STRING_SEARCH_CONTEXT context;\n\n    assert(Context);\n\n    context = Context;\n\n    *Buffer = NULL;\n    *Length = 0;\n\n    if (context->ReadRemaning)\n        goto ReadMemory;\n\n    while (NT_SUCCESS(status = NtQueryVirtualMemory(\n        context->ProcessHandle,\n        PTR_ADD_OFFSET(context->BasicInfo.BaseAddress, context->BasicInfo.RegionSize),\n        MemoryBasicInformation,\n        &context->BasicInfo,\n        sizeof(MEMORY_BASIC_INFORMATION),\n        NULL\n        )))\n    {\n        SIZE_T length;\n\n        if (context->Options->Cancel)\n            break;\n        if (context->BasicInfo.State != MEM_COMMIT)\n            continue;\n        if (FlagOn(context->BasicInfo.Protect, PAGE_NOACCESS | PAGE_GUARD))\n            continue;\n        if (!FlagOn(context->BasicInfo.Type, context->TypeMask))\n            continue;\n\n        context->NextReadAddress = context->BasicInfo.BaseAddress;\n        context->ReadRemaning = context->BasicInfo.RegionSize;\n\n        // Don't allocate a huge buffer (16 MiB max)\n        length = min(context->BasicInfo.RegionSize, 16 * 1024 * 1024);\n\n        if (length > context->BufferSize)\n        {\n            context->Buffer = PhReAllocate(context->Buffer, length);\n            context->BufferSize = length;\n        }\n\n        if (context->ReadRemaning)\n        {\nReadMemory:\n            context->CurrentReadAddress = context->NextReadAddress;\n            length = min(context->ReadRemaning, context->BufferSize);\n\n            if (NT_SUCCESS(status = PhReadVirtualMemory(\n                context->ProcessHandle,\n                context->CurrentReadAddress,\n                context->Buffer,\n                length,\n                &length\n                )))\n            {\n                *Buffer = context->Buffer;\n                *Length = length;\n                context->ReadRemaning -= length;\n                context->NextReadAddress = PTR_ADD_OFFSET(context->NextReadAddress, length);\n                break;\n            }\n        }\n\n        context->NextReadAddress = NULL;\n        context->ReadRemaning = 0;\n    }\n\n    return status;\n}\n\n_Function_class_(PH_STRING_SEARCH_CALLBACK)\nBOOLEAN NTAPI PhpMemoryStringSearchCallback(\n    _In_ PPH_STRING_SEARCH_RESULT Result,\n    _In_opt_ PVOID Context\n    )\n{\n    PMEMORY_STRING_SEARCH_CONTEXT context = Context;\n    PPH_MEMORY_RESULT result;\n\n    assert(context);\n\n    if (!context->DetectUnicode && Result->Unicode)\n        return context->Options->Cancel;\n\n    result = PhCreateMemoryResult(PTR_ADD_OFFSET(context->CurrentReadAddress, PTR_SUB_OFFSET(Result->Address, context->Buffer)), context->BasicInfo.BaseAddress, Result->Length);\n\n    result->Display.Buffer = PhAllocateForMemorySearch(Result->String->Length + sizeof(WCHAR));\n    memcpy(result->Display.Buffer, Result->String->Buffer, Result->String->Length);\n    result->Display.Buffer[Result->String->Length / sizeof(WCHAR)] = UNICODE_NULL;\n    result->Display.Length = Result->String->Length;\n\n    context->Options->Callback(result, context->Options->Context);\n\n    return context->Options->Cancel;\n}\n\nVOID PhSearchMemoryString(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_MEMORY_STRING_OPTIONS Options\n    )\n{\n    MEMORY_STRING_SEARCH_CONTEXT context;\n\n    memset(&context, 0, sizeof(MEMORY_STRING_SEARCH_CONTEXT));\n\n    context.Options = &Options->Header;\n    context.ProcessHandle = ProcessHandle;\n    context.TypeMask = Options->MemoryTypeMask;\n    context.DetectUnicode = Options->DetectUnicode;\n\n    PhSearchStrings(\n        Options->MinimumLength,\n        Options->ExtendedUnicode,\n        PhpMemoryStringSearchNextBuffer,\n        PhpMemoryStringSearchCallback,\n        &context\n        );\n}\n\nVOID PhShowMemoryStringDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    MEMORY_STRING_CONTEXT context;\n\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n        ProcessItem->ProcessId\n        )))\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to open the process\", status, 0);\n        return;\n    }\n\n    memset(&context, 0, sizeof(MEMORY_STRING_CONTEXT));\n    context.ParentWindowHandle = ParentWindowHandle;\n    context.ProcessId = ProcessItem->ProcessId;\n    context.ProcessHandle = processHandle;\n\n    if (PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_MEMSTRING),\n        ParentWindowHandle,\n        PhpMemoryStringDlgProc,\n        &context\n        ) != IDOK)\n    {\n        NtClose(processHandle);\n        return;\n    }\n\n    context.Results = PhCreateList(1024);\n\n    if (PhpShowMemoryStringProgressDialog(&context))\n    {\n        PPH_SHOW_MEMORY_RESULTS showMemoryResults;\n\n        showMemoryResults = PhAllocate(sizeof(PH_SHOW_MEMORY_RESULTS));\n        showMemoryResults->ProcessId = ProcessItem->ProcessId;\n        showMemoryResults->Results = context.Results;\n\n        PhReferenceObject(context.Results);\n        SystemInformer_ShowMemoryResults(showMemoryResults);\n    }\n\n    PhDereferenceObject(context.Results);\n    NtClose(processHandle);\n}\n\nINT_PTR CALLBACK PhpMemoryStringDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PMEMORY_STRING_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PMEMORY_STRING_CONTEXT)lParam;\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhSetDialogItemText(hwndDlg, IDC_MINIMUMLENGTH, L\"10\");\n\n            Button_SetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE), BST_CHECKED);\n            Button_SetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE), BST_CHECKED);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    ULONG64 minimumLength = 10;\n\n                    PhStringToInteger64(&PhaGetDlgItemText(hwndDlg, IDC_MINIMUMLENGTH)->sr, 0, &minimumLength);\n\n                    if (minimumLength < 4)\n                    {\n                        PhShowError2(hwndDlg, L\"Unable to search for strings.\", L\"%s\", L\"The minimum length must be at least 4.\");\n                        break;\n                    }\n\n                    context->MinimumLength = (ULONG)minimumLength;\n                    context->DetectUnicode = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE)) == BST_CHECKED;\n                    context->ExtendedUnicode = Button_GetCheck(GetDlgItem(hwndDlg, IDC_EXTENDEDUNICODE)) == BST_CHECKED;\n                    context->Private = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE)) == BST_CHECKED;\n                    context->Image = Button_GetCheck(GetDlgItem(hwndDlg, IDC_IMAGE)) == BST_CHECKED;\n                    context->Mapped = Button_GetCheck(GetDlgItem(hwndDlg, IDC_MAPPED)) == BST_CHECKED;\n\n                    EndDialog(hwndDlg, IDOK);\n                }\n                break;\n            case IDC_DETECTUNICODE:\n                {\n                    if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE)) == BST_UNCHECKED)\n                    {\n                        Button_SetCheck(GetDlgItem(hwndDlg, IDC_EXTENDEDUNICODE), BST_UNCHECKED);\n                        Button_Enable(GetDlgItem(hwndDlg, IDC_EXTENDEDUNICODE), FALSE);\n                    }\n                    else\n                    {\n                        Button_Enable(GetDlgItem(hwndDlg, IDC_EXTENDEDUNICODE), TRUE);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nstatic VOID NTAPI PhpMemoryStringResultCallback(\n    _In_ _Assume_refs_(1) PPH_MEMORY_RESULT Result,\n    _In_opt_ PVOID Context\n    )\n{\n    PMEMORY_STRING_CONTEXT context = Context;\n\n    if (context)\n        PhAddItemList(context->Results, Result);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpMemoryStringThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PMEMORY_STRING_CONTEXT context = Parameter;\n\n    context->Options.Header.Callback = PhpMemoryStringResultCallback;\n    context->Options.Header.Context = context;\n    context->Options.MinimumLength = context->MinimumLength;\n    context->Options.DetectUnicode = context->DetectUnicode;\n    context->Options.ExtendedUnicode = context->ExtendedUnicode;\n\n    if (context->Private)\n        context->Options.MemoryTypeMask |= MEM_PRIVATE;\n    if (context->Image)\n        context->Options.MemoryTypeMask |= MEM_IMAGE;\n    if (context->Mapped)\n        context->Options.MemoryTypeMask |= MEM_MAPPED;\n\n    PhSearchMemoryString(context->ProcessHandle, &context->Options);\n\n    SendMessage(\n        context->WindowHandle,\n        WM_PH_MEMORY_STATUS_UPDATE,\n        PH_SEARCH_COMPLETED,\n        0\n        );\n\n    return STATUS_SUCCESS;\n}\n\nLRESULT CALLBACK PhpMemoryStringTaskDialogSubclassProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PMEMORY_STRING_CONTEXT context;\n    WNDPROC oldWndProc;\n\n    if (!(context = PhGetWindowContext(hwndDlg, 0xF)))\n        return 0;\n\n    oldWndProc = context->DefaultWindowProc;\n\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            PhSetWindowProcedure(hwndDlg, oldWndProc);\n            PhRemoveWindowContext(hwndDlg, 0xF);\n        }\n        break;\n    case WM_PH_MEMORY_STATUS_UPDATE:\n        {\n            switch (wParam)\n            {\n            case PH_SEARCH_COMPLETED:\n                {\n                    context->EnableCloseDialog = TRUE;\n                    SendMessage(hwndDlg, TDM_CLICK_BUTTON, IDOK, 0);\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam);\n}\n\nHRESULT CALLBACK PhpMemoryStringTaskDialogCallback(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR dwRefData\n    )\n{\n    PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)dwRefData;\n\n    switch (uMsg)\n    {\n    case TDN_CREATED:\n        {\n            context->WindowHandle = hwndDlg;\n\n            // Create the Taskdialog icons.\n            PhSetApplicationWindowIcon(hwndDlg);\n            SendMessage(hwndDlg, TDM_UPDATE_ICON, TDIE_ICON_MAIN, (LPARAM)PhGetApplicationIcon(FALSE));\n\n            // Set the progress state.\n            SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n            SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n\n            // Subclass the Taskdialog.\n            context->DefaultWindowProc = PhGetWindowProcedure(hwndDlg);\n            PhSetWindowContext(hwndDlg, 0xF, context);\n            PhSetWindowProcedure(hwndDlg, PhpMemoryStringTaskDialogSubclassProc);\n\n            // Create the search thread.\n            PhCreateThread2(PhpMemoryStringThreadStart, context);\n        }\n        break;\n    case TDN_BUTTON_CLICKED:\n        {\n            if ((INT)wParam == IDCANCEL)\n                context->Options.Header.Cancel = TRUE;\n\n            if (!context->EnableCloseDialog)\n                return S_FALSE;\n        }\n        break;\n    case TDN_TIMER:\n        {\n            PPH_STRING numberText;\n            PPH_STRING progressText;\n\n            numberText = PhFormatUInt64(context->Results->Count, TRUE);\n            progressText = PhFormatString(L\"%s strings found...\", numberText->Buffer);\n\n            SendMessage(hwndDlg, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)progressText->Buffer);\n\n            PhDereferenceObject(progressText);\n            PhDereferenceObject(numberText);\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\nBOOLEAN PhpShowMemoryStringProgressDialog(\n    _In_ PMEMORY_STRING_CONTEXT Context\n    )\n{\n    TASKDIALOGCONFIG config;\n    INT result = 0;\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CALLBACK_TIMER;\n    config.dwCommonButtons = TDCBF_CANCEL_BUTTON;\n    config.pfCallback = PhpMemoryStringTaskDialogCallback;\n    config.lpCallbackData = (LONG_PTR)Context;\n    config.hwndParent = Context->ParentWindowHandle;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainInstruction = L\"Searching memory strings...\";\n    config.pszContent = L\" \";\n    config.cxWidth = 200;\n\n    if (SUCCEEDED(TaskDialogIndirect(&config, &result, NULL, NULL)) && result == IDOK)\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/memsrcht.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2024\n *\n */\n\n#include <phapp.h>\n#include <emenu.h>\n#include <mainwnd.h>\n#include <memsrch.h>\n#include <memprv.h>\n#include <procprv.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <strsrch.h>\n#include <colmgr.h>\n#include <cpysave.h>\n\n#define WM_PH_MEMSEARCH_SHOWMENU    (WM_USER + 3000)\n#define WM_PH_MEMSEARCH_FINISHED    (WM_USER + 3001)\n\n#define PH_MEMSEARCH_STATE_STOPPED   0\n#define PH_MEMSEARCH_STATE_SEARCHING 1\n#define PH_MEMSEARCH_STATE_FINISHED  2\n\nstatic CONST PH_STRINGREF EmptyStringsText = PH_STRINGREF_INIT(L\"There are no strings to display.\");\nstatic CONST PH_STRINGREF LoadingStringsText = PH_STRINGREF_INIT(L\"Loading strings...\");\n\ntypedef struct _PH_MEMSTRINGS_SETTINGS\n{\n    ULONG MinimumLength;\n\n    union\n    {\n        struct\n        {\n            ULONG Ansi : 1;\n            ULONG Unicode : 1;\n            ULONG ExtendedCharSet : 1;\n            ULONG Private : 1;\n            ULONG Image : 1;\n            ULONG Mapped : 1;\n            ULONG ZeroPadAddresses : 1;\n            ULONG Spare : 25;\n        };\n\n        ULONG Flags;\n    };\n} PH_MEMSTRINGS_SETTINGS, *PPH_MEMSTRINGS_SETTINGS;\n\ntypedef struct _PH_MEMSTRINGS_CONTEXT\n{\n    PPH_PROCESS_ITEM ProcessItem;\n    HANDLE ProcessHandle;\n    BOOLEAN UseClone;\n    HANDLE CloneHandle;\n\n    HWND WindowHandle;\n    HWND TreeNewHandle;\n    HWND MessageHandle;\n    HWND SearchHandle;\n    HWND FilterHandle;\n    RECT MinimumSize;\n    ULONG_PTR SearchMatchHandle;\n    PH_LAYOUT_MANAGER LayoutManager;\n    PH_TN_FILTER_SUPPORT FilterSupport;\n    PH_CM_MANAGER Cm;\n    ULONG TreeNewSortColumn;\n    PH_SORT_ORDER TreeNewSortOrder;\n    ULONG StringsCount;\n    PPH_LIST NodeList;\n    BOOLEAN BackOffActive;\n    ULONG BackOffSearchMatchRequests;\n    ULONG BackOffSearchMatchChecked;\n\n    ULONG State;\n    BOOLEAN StopSearch;\n    HANDLE SearchThreadHandle;\n    ULONG SearchResultsAddIndex;\n    PPH_LIST SearchResults;\n    PH_QUEUED_LOCK SearchResultsLock;\n    PPH_LIST PrevNodeList;\n\n    PH_MEMSTRINGS_SETTINGS Settings;\n} PH_MEMSTRINGS_CONTEXT, *PPH_MEMSTRINGS_CONTEXT;\n\ntypedef enum _PH_MEMSTRINGS_TREE_COLUMN_ITEM\n{\n    PH_MEMSTRINGS_TREE_COLUMN_ITEM_INDEX,\n    PH_MEMSTRINGS_TREE_COLUMN_ITEM_BASE_ADDRESS,\n    PH_MEMSTRINGS_TREE_COLUMN_ITEM_ADDRESS,\n    PH_MEMSTRINGS_TREE_COLUMN_ITEM_TYPE,\n    PH_MEMSTRINGS_TREE_COLUMN_ITEM_LENGTH,\n    PH_MEMSTRINGS_TREE_COLUMN_ITEM_STRING,\n    PH_MEMSTRINGS_TREE_COLUMN_ITEM_PROTECTION,\n    PH_MEMSTRINGS_TREE_COLUMN_ITEM_MEMORY_TYPE,\n    PH_MEMSTRINGS_TREE_COLUMN_ITEM_MAXIMUM\n} PH_MEMSTRINGS_TREE_COLUMN_ITEM;\n\ntypedef struct _PH_MEMSTRINGS_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    ULONG Index;\n    BOOLEAN Unicode;\n    PVOID BaseAddress;\n    PVOID Address;\n    PPH_STRING String;\n    ULONG Protection;\n    ULONG MemoryType;\n\n    WCHAR IndexString[PH_INT64_STR_LEN_1];\n    WCHAR BaseAddressString[PH_PTR_STR_LEN_1];\n    WCHAR AddressString[PH_PTR_STR_LEN_1];\n    WCHAR LengthString[PH_INT64_STR_LEN_1];\n    WCHAR ProtectionText[17];\n\n    PH_STRINGREF TextCache[PH_MEMSTRINGS_TREE_COLUMN_ITEM_MAXIMUM];\n} PH_MEMSTRINGS_NODE, *PPH_MEMSTRINGS_NODE;\n\ntypedef struct _PH_MEMSTRINGS_SEARCH_CONTEXT\n{\n    PPH_MEMSTRINGS_CONTEXT TreeContext;\n    ULONG TypeMask;\n    MEMORY_BASIC_INFORMATION BasicInfo;\n    PVOID CurrentReadAddress;\n    PVOID NextReadAddress;\n    SIZE_T ReadRemaning;\n    PBYTE Buffer;\n    SIZE_T BufferSize;\n} PH_MEMSTRINGS_SEARCH_CONTEXT, *PPH_MEMSTRINGS_SEARCH_CONTEXT;\n\nBOOLEAN PhpShowMemoryStringTreeDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_opt_ PPH_LIST PrevNodeList,\n    _In_ BOOLEAN UseClone\n    );\n\nVOID PhpShowMemoryEditor(\n    PPH_MEMSTRINGS_CONTEXT context,\n    PPH_MEMSTRINGS_NODE node\n    );\n\n_Function_class_(PH_STRING_SEARCH_NEXT_BUFFER)\n_Must_inspect_result_\nNTSTATUS NTAPI PhpMemoryStringSearchTreeNextBuffer(\n    _Inout_bytecount_(*Length) PVOID* Buffer,\n    _Out_ PSIZE_T Length,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    HANDLE handle;\n    PPH_MEMSTRINGS_SEARCH_CONTEXT context;\n\n    assert(Context);\n\n    context = Context;\n\n    if (context->TreeContext->UseClone)\n        handle = context->TreeContext->CloneHandle;\n    else\n        handle = context->TreeContext->ProcessHandle;\n\n    *Buffer = NULL;\n    *Length = 0;\n\n    if (context->ReadRemaning)\n        goto ReadMemory;\n\n    while (NT_SUCCESS(status = NtQueryVirtualMemory(\n        handle,\n        PTR_ADD_OFFSET(context->BasicInfo.BaseAddress, context->BasicInfo.RegionSize),\n        MemoryBasicInformation,\n        &context->BasicInfo,\n        sizeof(MEMORY_BASIC_INFORMATION),\n        NULL\n        )))\n    {\n        SIZE_T length;\n\n        if (context->TreeContext->StopSearch)\n            break;\n        if (context->BasicInfo.State != MEM_COMMIT)\n            continue;\n        if (FlagOn(context->BasicInfo.Protect, PAGE_NOACCESS | PAGE_GUARD))\n            continue;\n        if (!FlagOn(context->BasicInfo.Type, context->TypeMask))\n            continue;\n\n        context->NextReadAddress = context->BasicInfo.BaseAddress;\n        context->ReadRemaning = context->BasicInfo.RegionSize;\n\n        // Don't allocate a huge buffer (16 MiB max)\n        length = min(context->BasicInfo.RegionSize, 16 * 1024 * 1024);\n\n        if (length > context->BufferSize)\n        {\n            context->Buffer = PhReAllocate(context->Buffer, length);\n            context->BufferSize = length;\n        }\n\n        if (context->ReadRemaning)\n        {\nReadMemory:\n            context->CurrentReadAddress = context->NextReadAddress;\n            length = min(context->ReadRemaning, context->BufferSize);\n\n            assert(context->Buffer);\n\n            if (NT_SUCCESS(status = PhReadVirtualMemory(\n                handle,\n                context->CurrentReadAddress,\n                context->Buffer,\n                length,\n                &length\n                )))\n            {\n                *Buffer = context->Buffer;\n                *Length = length;\n                context->ReadRemaning -= length;\n                context->NextReadAddress = PTR_ADD_OFFSET(context->NextReadAddress, length);\n                break;\n            }\n        }\n\n        context->NextReadAddress = NULL;\n        context->ReadRemaning = 0;\n    }\n\n    return status;\n}\n\n_Function_class_(PH_STRING_SEARCH_CALLBACK)\nBOOLEAN NTAPI PhpMemoryStringSearchTreeCallback(\n    _In_ PPH_STRING_SEARCH_RESULT Result,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MEMSTRINGS_SEARCH_CONTEXT context;\n    PPH_MEMSTRINGS_CONTEXT treeContext;\n    PPH_MEMSTRINGS_NODE node;\n\n    assert(Context);\n\n    context = Context;\n    treeContext = context->TreeContext;\n\n    node = PhAllocateZero(sizeof(PH_MEMSTRINGS_NODE));\n\n    node->Index = ++treeContext->StringsCount;\n    PhPrintUInt64(node->IndexString, node->Index);\n\n    node->BaseAddress = context->BasicInfo.BaseAddress;\n    node->Address = PTR_ADD_OFFSET(context->CurrentReadAddress, PTR_SUB_OFFSET(Result->Address, context->Buffer));\n\n    if (context->TreeContext->Settings.ZeroPadAddresses)\n    {\n        PhPrintPointerPadZeros(node->BaseAddressString, node->BaseAddress);\n        PhPrintPointerPadZeros(node->AddressString, node->Address);\n    }\n    else\n    {\n        PhPrintPointer(node->BaseAddressString, node->BaseAddress);\n        PhPrintPointer(node->AddressString, node->Address);\n    }\n\n    node->Unicode = Result->Unicode;\n    node->String = PhReferenceObject(Result->String);\n    PhPrintUInt64(node->LengthString, node->String->Length / 2);\n\n    node->Protection = context->BasicInfo.Protect;\n    PhGetMemoryProtectionString(node->Protection, node->ProtectionText);\n    node->MemoryType = context->BasicInfo.Type;\n\n    PhAcquireQueuedLockExclusive(&treeContext->SearchResultsLock);\n    PhAddItemList(treeContext->SearchResults, node);\n    PhReleaseQueuedLockExclusive(&treeContext->SearchResultsLock);\n\n    return !!treeContext->StopSearch;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpMemorySearchStringsThread(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context\n    )\n{\n    PH_MEMSTRINGS_SEARCH_CONTEXT context;\n\n    memset(&context, 0, sizeof(context));\n\n    context.TreeContext = Context;\n\n    context.TypeMask = 0;\n    if (Context->Settings.Private)\n        SetFlag(context.TypeMask, MEM_PRIVATE);\n    if (Context->Settings.Image)\n        SetFlag(context.TypeMask, MEM_IMAGE);\n    if (Context->Settings.Mapped)\n        SetFlag(context.TypeMask, MEM_MAPPED);\n\n    if (context.TypeMask)\n    {\n        PhSearchStrings(\n            Context->Settings.MinimumLength,\n            !!Context->Settings.ExtendedCharSet,\n            PhpMemoryStringSearchTreeNextBuffer,\n            PhpMemoryStringSearchTreeCallback,\n            &context\n            );\n    }\n\n    if (context.Buffer)\n        PhFree(context.Buffer);\n\n    if (!Context->StopSearch)\n        PostMessage(Context->WindowHandle, WM_PH_MEMSEARCH_FINISHED, 0, 0);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpMemoryStringsCheckBackOff(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context\n    )\n{\n    // Once we reach a very large number of strings back off the updates to the\n    // list and searching else the user input and interface can lag.\n    //\n    // N.B. The updated timer effectively induces a (timer value * 2) on search\n    // filtering updates. Logic elsewhere will check on the delay for the user\n    // to stop typing. Then the next timer trigger the search will be updated\n    // based on the current user input.\n    if (Context->NodeList->Count >= 150000)\n    {\n        Context->BackOffActive = TRUE;\n        PhSetTimer(Context->WindowHandle, PH_WINDOW_TIMER_DEFAULT, 250, NULL);\n    }\n    else if (Context->NodeList->Count >= 500000)\n    {\n        Context->BackOffActive = TRUE;\n        PhSetTimer(Context->WindowHandle, PH_WINDOW_TIMER_DEFAULT, 400, NULL);\n    }\n}\n\nVOID PhpMemoryStringsAddTreeNode(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context,\n    _In_ PPH_MEMSTRINGS_NODE Entry\n    )\n{\n    PhInitializeTreeNewNode(&Entry->Node);\n\n    memset(Entry->TextCache, 0, sizeof(PH_STRINGREF) * PH_MEMSTRINGS_TREE_COLUMN_ITEM_MAXIMUM);\n    Entry->Node.TextCache = Entry->TextCache;\n    Entry->Node.TextCacheSize = PH_MEMSTRINGS_TREE_COLUMN_ITEM_MAXIMUM;\n\n    PhAddItemList(Context->NodeList, Entry);\n\n    if (Context->FilterSupport.NodeList)\n    {\n        Entry->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &Entry->Node);\n    }\n}\n\nVOID PhpAddPendingMemoryStringsNodes(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context\n    )\n{\n    ULONG i;\n    BOOLEAN needsFullUpdate = FALSE;\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n\n    PhAcquireQueuedLockExclusive(&Context->SearchResultsLock);\n\n    for (i = Context->SearchResultsAddIndex; i < Context->SearchResults->Count; i++)\n    {\n        PhpMemoryStringsAddTreeNode(Context, Context->SearchResults->Items[i]);\n        needsFullUpdate = TRUE;\n    }\n    Context->SearchResultsAddIndex = i;\n\n    PhReleaseQueuedLockExclusive(&Context->SearchResultsLock);\n\n    PhpMemoryStringsCheckBackOff(Context);\n\n    if (needsFullUpdate)\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n}\n\nVOID PhpLoadSettingsMemoryStrings(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhGetStringSetting(SETTING_MEM_STRINGS_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_MEM_STRINGS_TREE_LIST_SORT);\n    Context->Settings.Flags = PhGetIntegerSetting(SETTING_MEM_STRINGS_TREE_LIST_FLAGS);\n    Context->Settings.MinimumLength = PhGetIntegerSetting(SETTING_MEM_STRINGS_MINIMUM_LENGTH);\n\n    PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhpSaveSettingsMemoryStrings(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings);\n\n    PhSetIntegerSetting(SETTING_MEM_STRINGS_MINIMUM_LENGTH, Context->Settings.MinimumLength);\n    PhSetIntegerSetting(SETTING_MEM_STRINGS_TREE_LIST_FLAGS, Context->Settings.Flags);\n    PhSetStringSetting2(SETTING_MEM_STRINGS_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_MEM_STRINGS_TREE_LIST_SORT, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhpInvalidateMemoryStringsAddresses(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MEMSTRINGS_NODE node = (PPH_MEMSTRINGS_NODE)Context->NodeList->Items[i];\n\n        if (Context->Settings.ZeroPadAddresses)\n        {\n            PhPrintPointerPadZeros(node->BaseAddressString, node->BaseAddress);\n            PhPrintPointerPadZeros(node->AddressString, node->Address);\n        }\n        else\n        {\n            PhPrintPointer(node->BaseAddressString, node->BaseAddress);\n            PhPrintPointer(node->AddressString, node->Address);\n        }\n\n        memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PH_MEMSTRINGS_TREE_COLUMN_ITEM_MAXIMUM);\n    }\n\n    InvalidateRect(Context->TreeNewHandle, NULL, FALSE);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nBOOLEAN PhpGetSelectedMemoryStringsNodes(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context,\n    _Out_ PPH_MEMSTRINGS_NODE** Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MEMSTRINGS_NODE node = (PPH_MEMSTRINGS_NODE)Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n            PhAddItemList(list, node);\n    }\n\n    if (list->Count)\n    {\n        *Nodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    *Nodes = NULL;\n    *NumberOfNodes = 0;\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\nVOID PhpCopyFilteredMemoryStringsNodes(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context,\n    _Out_ PPH_LIST* NodeList\n    )\n{\n    PPH_LIST list = PhCreateList(10);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MEMSTRINGS_NODE node = (PPH_MEMSTRINGS_NODE)Context->NodeList->Items[i];\n\n        if (node->Node.Visible)\n        {\n            PPH_MEMSTRINGS_NODE cloned;\n\n            cloned = PhAllocateCopy(node, sizeof(PH_MEMSTRINGS_NODE));\n            PhReferenceObject(cloned->String);\n            PhAddItemList(list, cloned);\n        }\n    }\n\n    *NodeList = list;\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhpMemoryStringsTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MEMSTRINGS_CONTEXT context = Context;\n    PPH_MEMSTRINGS_NODE node = (PPH_MEMSTRINGS_NODE)Node;\n\n    assert(Context);\n\n    if (!context->Settings.Ansi && !node->Unicode)\n        return FALSE;\n    if (!context->Settings.Unicode && node->Unicode)\n        return FALSE;\n\n    if (!context->SearchMatchHandle)\n        return TRUE;\n\n    return PhSearchControlMatch(context->SearchMatchHandle, &node->String->sr);\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PvpStringsSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MEMSTRINGS_CONTEXT context = Context;\n\n    assert(context);\n\n    context->SearchMatchHandle = MatchHandle;\n\n    if (context->BackOffActive)\n        context->BackOffSearchMatchRequests++;\n    else\n        PhApplyTreeNewFilters(&context->FilterSupport);\n}\n\nVOID PhpDeleteMemoryStringsNodeList(\n    _In_ PPH_LIST NodeList\n    )\n{\n    for (ULONG i = 0; i < NodeList->Count; i++)\n    {\n        PPH_MEMSTRINGS_NODE node = (PPH_MEMSTRINGS_NODE)NodeList->Items[i];\n\n        PhClearReference(&node->String);\n        PhFree(node);\n    }\n}\n\nVOID PhpDeleteMemoryStringsTree(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context\n    )\n{\n    Context->StopSearch = TRUE;\n    if (Context->SearchThreadHandle)\n    {\n        NtWaitForSingleObject(Context->SearchThreadHandle, FALSE, NULL);\n        NtClose(Context->SearchThreadHandle);\n        Context->SearchThreadHandle = NULL;\n    }\n    Context->StopSearch = FALSE;\n\n    if (Context->CloneHandle)\n    {\n        NtTerminateProcess(Context->CloneHandle, STATUS_PROCESS_CLONED);\n        NtClose(Context->CloneHandle);\n        Context->CloneHandle = NULL;\n    }\n\n    PhpAddPendingMemoryStringsNodes(Context);\n\n    PhpDeleteMemoryStringsNodeList(Context->NodeList);\n\n    PhDeleteTreeNewFilterSupport(&Context->FilterSupport);\n\n    PhClearReference(&Context->NodeList);\n    PhClearReference(&Context->SearchResults);\n    Context->SearchResultsAddIndex = 0;\n    Context->StringsCount = 0;\n}\n\nVOID PhpSearchMemoryStrings(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context\n    )\n{\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n\n    PhpDeleteMemoryStringsTree(Context);\n\n    Context->NodeList = PhCreateList(100);\n    Context->SearchResults = PhCreateList(100);\n\n    PhInitializeTreeNewFilterSupport(&Context->FilterSupport, Context->TreeNewHandle, Context->NodeList);\n    PhAddTreeNewFilter(&Context->FilterSupport, PhpMemoryStringsTreeFilterCallback, Context);\n\n    TreeNew_SetEmptyText(Context->TreeNewHandle, &LoadingStringsText, 0);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n\n    if (Context->UseClone)\n    {\n        NTSTATUS status;\n\n        if (!NT_SUCCESS(status = PhCreateProcessClone(\n            &Context->CloneHandle,\n            Context->ProcessItem->ProcessId\n            )))\n        {\n            PhShowStatus(Context->WindowHandle, L\"Unable to clone the process\", status, 0);\n            return;\n        }\n    }\n\n    Context->State = PH_MEMSEARCH_STATE_SEARCHING;\n    EnableWindow(Context->FilterHandle, FALSE);\n\n    PhCreateThreadEx(&Context->SearchThreadHandle, PhpMemorySearchStringsThread, Context);\n}\n\n#define SORT_FUNCTION(Column) PvpStringsTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PvpStringsTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_MEMSTRINGS_NODE node1 = *(PPH_MEMSTRINGS_NODE *)_elem1; \\\n    PPH_MEMSTRINGS_NODE node2 = *(PPH_MEMSTRINGS_NODE *)_elem2; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintcmp(node1->Index, node2->Index); \\\n    \\\n    return PhModifySort(sortResult, ((PPH_MEMSTRINGS_CONTEXT)_context)->TreeNewSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpMemoryStringsTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    if (Result == 0)\n        Result = uintptrcmp((ULONG_PTR)((PPH_MEMSTRINGS_NODE)Node1)->Index, (ULONG_PTR)((PPH_MEMSTRINGS_NODE)Node2)->Index);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(Index)\n{\n    NOTHING;\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(BaseAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->BaseAddress, (ULONG_PTR)node2->BaseAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Address)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->Address, (ULONG_PTR)node2->Address);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Type)\n{\n    sortResult = uintcmp(node1->Unicode, node2->Unicode);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Length)\n{\n    sortResult = uintptrcmp(node1->String->Length, node2->String->Length);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(String)\n{\n    sortResult = PhCompareString(node1->String, node2->String, FALSE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Protection)\n{\n    sortResult = uintcmp(node1->Protection, node2->Protection);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(MemoryType)\n{\n    sortResult = uintcmp(node1->MemoryType, node2->MemoryType);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpMemoryStringsTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_MEMSTRINGS_CONTEXT context = Context;\n    PPH_MEMSTRINGS_NODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_MEMSTRINGS_NODE)getChildren->Node;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(Index),\n                    SORT_FUNCTION(BaseAddress),\n                    SORT_FUNCTION(Address),\n                    SORT_FUNCTION(Type),\n                    SORT_FUNCTION(Length),\n                    SORT_FUNCTION(String),\n                    SORT_FUNCTION(Protection),\n                    SORT_FUNCTION(MemoryType),\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PH_MEMSTRINGS_TREE_COLUMN_ITEM_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (context->TreeNewSortColumn < PH_MEMSTRINGS_TREE_COLUMN_ITEM_MAXIMUM)\n                    sortFunction = sortFunctions[context->TreeNewSortColumn];\n                else\n                    sortFunction = NULL;\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1;\n            node = (PPH_MEMSTRINGS_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1;\n            node = (PPH_MEMSTRINGS_NODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case PH_MEMSTRINGS_TREE_COLUMN_ITEM_INDEX:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->IndexString);\n                break;\n            case PH_MEMSTRINGS_TREE_COLUMN_ITEM_BASE_ADDRESS:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->BaseAddressString);\n                break;\n            case PH_MEMSTRINGS_TREE_COLUMN_ITEM_ADDRESS:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->AddressString);\n                break;\n            case PH_MEMSTRINGS_TREE_COLUMN_ITEM_PROTECTION:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->ProtectionText);\n                break;\n            case PH_MEMSTRINGS_TREE_COLUMN_ITEM_MEMORY_TYPE:\n                getCellText->Text = *PhGetMemoryTypeString(node->MemoryType);\n                break;\n            case PH_MEMSTRINGS_TREE_COLUMN_ITEM_TYPE:\n                PhInitializeStringRef(&getCellText->Text, node->Unicode ? L\"Unicode\" : L\"ANSI\");\n                break;\n            case PH_MEMSTRINGS_TREE_COLUMN_ITEM_LENGTH:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->LengthString);\n                break;\n            case PH_MEMSTRINGS_TREE_COLUMN_ITEM_STRING:\n                getCellText->Text = node->String->sr;\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = (PPH_TREENEW_GET_NODE_COLOR)Parameter1;\n            node = (PPH_MEMSTRINGS_NODE)getNodeColor->Node;\n\n            getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                {\n                    if (GetKeyState(VK_CONTROL) < 0)\n                    {\n                        PPH_STRING text;\n\n                        text = PhGetTreeNewText(WindowHandle, 0);\n                        PhSetClipboardString(WindowHandle, &text->sr);\n                        PhDereferenceObject(text);\n                    }\n                }\n                break;\n            case 'A':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    TreeNew_SelectRange(context->TreeNewHandle, 0, -1);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewNodeExpanding:\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1;\n            node = (PPH_MEMSTRINGS_NODE)mouseEvent->Node;\n\n            PhpShowMemoryEditor(context, node);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n\n            SendMessage(context->WindowHandle, WM_PH_MEMSEARCH_SHOWMENU, 0, (LPARAM)contextMenu);\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = 0;\n            data.DefaultSortOrder = AscendingSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpInitializeMemoryStringsTree(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HWND TreeNewHandle\n    )\n{\n    BOOLEAN enableMonospaceFont = !!PhGetIntegerSetting(SETTING_ENABLE_MONOSPACE_FONT);\n\n    Context->WindowHandle = WindowHandle;\n    Context->TreeNewHandle = TreeNewHandle;\n\n    Context->NodeList = PhCreateList(1);\n    Context->SearchResults = PhCreateList(1);\n\n    PhSetControlTheme(TreeNewHandle, L\"explorer\");\n\n    TreeNew_SetCallback(TreeNewHandle, PhpMemoryStringsTreeNewCallback, Context);\n    TreeNew_SetRedraw(TreeNewHandle, FALSE);\n\n    PhAddTreeNewColumnEx2(TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_INDEX, TRUE, L\"#\", 40, PH_ALIGN_LEFT, PH_MEMSTRINGS_TREE_COLUMN_ITEM_INDEX, 0, 0);\n    PhAddTreeNewColumnEx2(TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_BASE_ADDRESS, TRUE, L\"Base address\", 80, PH_ALIGN_LEFT | (enableMonospaceFont ? PH_ALIGN_MONOSPACE_FONT : 0), PH_MEMSTRINGS_TREE_COLUMN_ITEM_BASE_ADDRESS, 0, 0);\n    PhAddTreeNewColumnEx2(TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_ADDRESS, TRUE, L\"Address\", 80, PH_ALIGN_LEFT | (enableMonospaceFont ? PH_ALIGN_MONOSPACE_FONT : 0), PH_MEMSTRINGS_TREE_COLUMN_ITEM_ADDRESS, 0, 0);\n    PhAddTreeNewColumnEx2(TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_TYPE, TRUE, L\"Type\", 80, PH_ALIGN_LEFT, PH_MEMSTRINGS_TREE_COLUMN_ITEM_TYPE, 0, 0);\n    PhAddTreeNewColumnEx2(TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_LENGTH, TRUE, L\"Length\", 80, PH_ALIGN_LEFT, PH_MEMSTRINGS_TREE_COLUMN_ITEM_LENGTH, 0, 0);\n    PhAddTreeNewColumnEx2(TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_STRING, TRUE, L\"String\", 600, PH_ALIGN_LEFT, PH_MEMSTRINGS_TREE_COLUMN_ITEM_STRING, 0, 0);\n    PhAddTreeNewColumnEx2(TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_PROTECTION, FALSE, L\"Protection\", 80, PH_ALIGN_LEFT, PH_MEMSTRINGS_TREE_COLUMN_ITEM_PROTECTION, 0, 0);\n    PhAddTreeNewColumnEx2(TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_MEMORY_TYPE, FALSE, L\"Memory type\", 80, PH_ALIGN_LEFT, PH_MEMSTRINGS_TREE_COLUMN_ITEM_MEMORY_TYPE, 0, 0);\n\n    TreeNew_SetRedraw(TreeNewHandle, TRUE);\n    TreeNew_SetSort(TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_INDEX, AscendingSortOrder);\n\n    PhCmInitializeManager(&Context->Cm, TreeNewHandle, PH_MEMSTRINGS_TREE_COLUMN_ITEM_MAXIMUM, PhpMemoryStringsTreeNewPostSortFunction);\n\n    PhpLoadSettingsMemoryStrings(Context);\n}\n\nINT_PTR CALLBACK PhpMemoryStringsMinimumLengthDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n)\n{\n    PULONG length;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        length = (PULONG)lParam;\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, length);\n    }\n    else\n    {\n        length = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!length)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            WCHAR lengthString[PH_INT32_STR_LEN_1];\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhPrintUInt32(lengthString, *length);\n\n            PhSetDialogItemText(hwndDlg, IDC_MINIMUMLENGTH, lengthString);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    ULONG64 minimumLength;\n\n                    PhStringToInteger64(&PhaGetDlgItemText(hwndDlg, IDC_MINIMUMLENGTH)->sr, 0, &minimumLength);\n\n                    if (!minimumLength || minimumLength > MAXULONG32)\n                    {\n                        PhShowError2(hwndDlg, L\"Unable to update the length.\", L\"%s\", L\"The minimum length is invalid.\");\n                        break;\n                    }\n\n                    *length = (ULONG)minimumLength;\n                    EndDialog(hwndDlg, IDOK);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nULONG PhpMemoryStringsMinimumLengthDialog(\n    _In_ HWND WindowHandle,\n    _In_ ULONG CurrentMinimumLength\n)\n{\n    ULONG length;\n\n    length = CurrentMinimumLength;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_MEMSTRINGSMINLEN),\n        WindowHandle,\n        PhpMemoryStringsMinimumLengthDlgProc,\n        &length\n        );\n\n    return length;\n}\n\nVOID PhpMemoryStringsSetWindowTitle(\n    _In_ PPH_MEMSTRINGS_CONTEXT Context\n    )\n{\n    HICON icon;\n    PPH_STRING title;\n    CLIENT_ID clientId;\n\n    if (Context->ProcessItem->IconEntry && Context->ProcessItem->IconEntry->SmallIconIndex)\n    {\n        icon = PhGetImageListIcon(Context->ProcessItem->IconEntry->SmallIconIndex, FALSE);\n        if (icon)\n            PhSetWindowIcon(Context->WindowHandle, icon, NULL, TRUE);\n    }\n\n    clientId.UniqueProcess = Context->ProcessItem->ProcessId;\n    clientId.UniqueThread = NULL;\n    title = PhaConcatStrings2(PhGetStringOrEmpty(PH_AUTO(PhGetClientIdName(&clientId))), L\" Strings\");\n    SetWindowTextW(Context->WindowHandle, title->Buffer);\n}\n\nVOID PhpShowMemoryEditor(\n    PPH_MEMSTRINGS_CONTEXT context,\n    PPH_MEMSTRINGS_NODE node\n    )\n{\n    NTSTATUS status;\n    MEMORY_BASIC_INFORMATION basicInfo;\n    PPH_SHOW_MEMORY_EDITOR showMemoryEditor;\n    PVOID address;\n    SIZE_T length;\n\n    address = node->Address;\n    if (node->Unicode)\n        length = node->String->Length;\n    else\n        length = node->String->Length / 2;\n\n    if (NT_SUCCESS(status = NtQueryVirtualMemory(\n        context->ProcessHandle,\n        address,\n        MemoryBasicInformation,\n        &basicInfo,\n        sizeof(basicInfo),\n        NULL\n        )))\n    {\n        showMemoryEditor = PhAllocateZero(sizeof(PH_SHOW_MEMORY_EDITOR));\n        showMemoryEditor->ProcessId = context->ProcessItem->ProcessId;\n        showMemoryEditor->BaseAddress = basicInfo.BaseAddress;\n        showMemoryEditor->RegionSize = basicInfo.RegionSize;\n        showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)address - (ULONG_PTR)basicInfo.BaseAddress);\n        showMemoryEditor->SelectLength = (ULONG)length;\n\n        SystemInformer_ShowMemoryEditor(showMemoryEditor);\n    }\n    else\n    {\n        PhShowStatus(context->WindowHandle, L\"Unable to edit memory\", status, 0);\n    }\n}\n\nINT_PTR CALLBACK PhpMemoryStringsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_MEMSTRINGS_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_MEMSTRINGS_CONTEXT)lParam;\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->MessageHandle = GetDlgItem(hwndDlg, IDC_MESSAGE);\n            context->SearchHandle = GetDlgItem(hwndDlg, IDC_SEARCH);\n            context->FilterHandle = GetDlgItem(hwndDlg, IDC_FILTER);\n\n            PhpMemoryStringsSetWindowTitle(context);\n            PhRegisterDialog(hwndDlg);\n\n            PhCreateSearchControl(\n                hwndDlg,\n                context->SearchHandle,\n                L\"Search Strings (Ctrl+K)\",\n                PvpStringsSearchControlCallback,\n                context\n                );\n\n            PhpInitializeMemoryStringsTree(context, hwndDlg, GetDlgItem(hwndDlg, IDC_TREELIST));\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->SearchHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, context->MessageHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n\n            context->MinimumSize.left = 0;\n            context->MinimumSize.top = 0;\n            context->MinimumSize.right = 300;\n            context->MinimumSize.bottom = 100;\n            MapDialogRect(hwndDlg, &context->MinimumSize);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_MEM_STRINGS_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_MEM_STRINGS_WINDOW_POSITION, SETTING_MEM_STRINGS_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, PhMainWndHandle);\n\n            PhSetTimer(hwndDlg, PH_WINDOW_TIMER_DEFAULT, 200, NULL);\n\n            if (context->PrevNodeList)\n            {\n                PhInitializeTreeNewFilterSupport(&context->FilterSupport, context->TreeNewHandle, context->NodeList);\n                PhAddTreeNewFilter(&context->FilterSupport, PhpMemoryStringsTreeFilterCallback, context);\n\n                PhMoveReference(&context->SearchResults, context->PrevNodeList);\n                context->StringsCount = context->PrevNodeList->Count;\n                context->State = PH_MEMSEARCH_STATE_FINISHED;\n                EnableWindow(context->FilterHandle, FALSE);\n\n                PhpMemoryStringsCheckBackOff(context);\n            }\n            else\n            {\n                PhpSearchMemoryStrings(context);\n            }\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhpSaveSettingsMemoryStrings(context);\n            PhpDeleteMemoryStringsTree(context);\n\n            PhSaveWindowPlacementToSetting(SETTING_MEM_STRINGS_WINDOW_POSITION, SETTING_MEM_STRINGS_WINDOW_SIZE, hwndDlg);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDereferenceObject(context->ProcessItem);\n            NtClose(context->ProcessHandle);\n            PhFree(context);\n\n            PostQuitMessage(0);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)context->TreeNewHandle);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_PH_MEMSEARCH_FINISHED:\n        {\n            PhpAddPendingMemoryStringsNodes(context);\n\n            context->State = PH_MEMSEARCH_STATE_FINISHED;\n\n            TreeNew_SetEmptyText(context->TreeNewHandle, &EmptyStringsText, 0);\n\n            TreeNew_NodesStructured(context->TreeNewHandle);\n        }\n        break;\n    case WM_TIMER:\n        {\n            if (context->State != PH_MEMSEARCH_STATE_STOPPED)\n            {\n                PPH_STRING message;\n                PH_FORMAT format[3];\n                ULONG count = 0;\n\n                PhpAddPendingMemoryStringsNodes(context);\n\n                if (context->State == PH_MEMSEARCH_STATE_SEARCHING)\n                    PhInitFormatS(&format[count++], L\"Searching... \");\n\n                PhInitFormatU(&format[count++], context->StringsCount);\n                PhInitFormatS(&format[count++], L\" strings\");\n\n                message = PhFormat(format, count, 80);\n\n                SetWindowText(context->MessageHandle, message->Buffer);\n\n                PhDereferenceObject(message);\n\n                if (context->State == PH_MEMSEARCH_STATE_FINISHED)\n                {\n                    context->State = PH_MEMSEARCH_STATE_STOPPED;\n                    EnableWindow(context->FilterHandle, TRUE);\n                }\n            }\n\n            if (context->BackOffActive && context->BackOffSearchMatchRequests)\n            {\n                if (context->BackOffSearchMatchChecked == context->BackOffSearchMatchRequests)\n                {\n                    context->BackOffSearchMatchRequests = 0;\n                    context->BackOffSearchMatchChecked = 0;\n                    PhApplyTreeNewFilters(&context->FilterSupport);\n                    TreeNew_NodesStructured(context->TreeNewHandle);\n                }\n                else\n                {\n                    // User still typing...\n                    context->BackOffSearchMatchChecked = context->BackOffSearchMatchRequests;\n                }\n            }\n        }\n        break;\n    case WM_PH_MEMSEARCH_SHOWMENU:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM selectedItem;\n            PPH_MEMSTRINGS_NODE* stringsNodes = NULL;\n            ULONG numberOfNodes = 0;\n\n            if (!PhpGetSelectedMemoryStringsNodes(context, &stringsNodes, &numberOfNodes))\n                break;\n\n            if (numberOfNodes != 0)\n            {\n                PPH_EMENU_ITEM readWrite;\n\n                menu = PhCreateEMenu();\n\n                readWrite = PhCreateEMenuItem(0, IDC_SHOW, L\"Read/Write memory\", NULL, NULL);\n                readWrite->Flags |= PH_EMENU_DEFAULT;\n                PhInsertEMenuItem(menu, readWrite, ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"Copy\", NULL, NULL), ULONG_MAX);\n                PhInsertCopyCellEMenuItem(menu, IDC_COPY, context->TreeNewHandle, contextMenuEvent->Column);\n\n                if (numberOfNodes != 1)\n                    readWrite->Flags |= PH_EMENU_DISABLED;\n\n                selectedItem = PhShowEMenu(\n                    menu,\n                    hwndDlg,\n                    PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                    PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                    contextMenuEvent->Location.x,\n                    contextMenuEvent->Location.y\n                    );\n\n                if (selectedItem && selectedItem->Id != ULONG_MAX && !PhHandleCopyCellEMenuItem(selectedItem))\n                {\n                    switch (selectedItem->Id)\n                    {\n                    case IDC_SHOW:\n                        {\n                            assert(numberOfNodes == 1);\n\n                            PhpShowMemoryEditor(context, stringsNodes[0]);\n                        }\n                        break;\n                    case IDC_COPY:\n                        {\n                            PPH_STRING text;\n\n                            text = PhGetTreeNewText(context->TreeNewHandle, 0);\n                            PhSetClipboardString(context->TreeNewHandle, &text->sr);\n                            PhDereferenceObject(text);\n                        }\n                        break;\n                    }\n                }\n\n                PhDestroyEMenu(menu);\n                PhFree(stringsNodes);\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                DestroyWindow(hwndDlg);\n                break;\n            case IDC_SETTINGS:\n                {\n                    RECT rect;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM selectedItem;\n                    PPH_EMENU_ITEM ansi;\n                    PPH_EMENU_ITEM unicode;\n                    PPH_EMENU_ITEM extendedUnicode;\n                    PPH_EMENU_ITEM private;\n                    PPH_EMENU_ITEM image;\n                    PPH_EMENU_ITEM mapped;\n                    PPH_EMENU_ITEM minimumLength;\n                    PPH_EMENU_ITEM zeroPad;\n                    PPH_EMENU_ITEM refresh;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_SETTINGS), &rect))\n                        break;\n\n                    ansi = PhCreateEMenuItem(0, 1, L\"ANSI\", NULL, NULL);\n                    unicode = PhCreateEMenuItem(0, 2, L\"Unicode\", NULL, NULL);\n                    extendedUnicode = PhCreateEMenuItem(0, 3, L\"Extended character set\", NULL, NULL);\n                    private = PhCreateEMenuItem(0, 4, L\"Private\", NULL, NULL);\n                    image = PhCreateEMenuItem(0, 5, L\"Image\", NULL, NULL);\n                    mapped = PhCreateEMenuItem(0, 6, L\"Mapped\", NULL, NULL);\n                    minimumLength = PhCreateEMenuItem(0, 7, L\"Minimum length...\", NULL, NULL);\n                    zeroPad = PhCreateEMenuItem(0, 8, L\"Zero pad addresses\", NULL, NULL);\n                    refresh = PhCreateEMenuItem(0, 9, L\"Refresh\\bF5\", NULL, NULL);\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, ansi, ULONG_MAX);\n                    PhInsertEMenuItem(menu, unicode, ULONG_MAX);\n                    PhInsertEMenuItem(menu, extendedUnicode, ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, private, ULONG_MAX);\n                    PhInsertEMenuItem(menu, image, ULONG_MAX);\n                    PhInsertEMenuItem(menu, mapped, ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, minimumLength, ULONG_MAX);\n                    PhInsertEMenuItem(menu, zeroPad, ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, refresh, ULONG_MAX);\n\n                    if (context->Settings.Ansi)\n                        ansi->Flags |= PH_EMENU_CHECKED;\n                    if (context->Settings.Unicode)\n                        unicode->Flags |= PH_EMENU_CHECKED;\n                    if (context->Settings.ExtendedCharSet)\n                        extendedUnicode->Flags |= PH_EMENU_CHECKED;\n                    if (context->Settings.Private)\n                        private->Flags |= PH_EMENU_CHECKED;\n                    if (context->Settings.Image)\n                        image->Flags |= PH_EMENU_CHECKED;\n                    if (context->Settings.Mapped)\n                        mapped->Flags |= PH_EMENU_CHECKED;\n                    if (context->Settings.ZeroPadAddresses)\n                        zeroPad->Flags |= PH_EMENU_CHECKED;\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        rect.left,\n                        rect.bottom\n                        );\n\n                    if (selectedItem && selectedItem->Id != ULONG_MAX)\n                    {\n                        if (selectedItem == ansi)\n                        {\n                            context->Settings.Ansi = !context->Settings.Ansi;\n                            PhpSaveSettingsMemoryStrings(context);\n                            PhApplyTreeNewFilters(&context->FilterSupport);\n                        }\n                        else if (selectedItem == unicode)\n                        {\n                            context->Settings.Unicode = !context->Settings.Unicode;\n                            PhpSaveSettingsMemoryStrings(context);\n                            PhApplyTreeNewFilters(&context->FilterSupport);\n                        }\n                        else if (selectedItem == extendedUnicode)\n                        {\n                            context->Settings.ExtendedCharSet = !context->Settings.ExtendedCharSet;\n                            PhpSaveSettingsMemoryStrings(context);\n                            PhpSearchMemoryStrings(context);\n                        }\n                        else if (selectedItem == private)\n                        {\n                            context->Settings.Private = !context->Settings.Private;\n                            PhpSaveSettingsMemoryStrings(context);\n                            PhpSearchMemoryStrings(context);\n                        }\n                        else if (selectedItem == image)\n                        {\n                            context->Settings.Image = !context->Settings.Image;\n                            PhpSaveSettingsMemoryStrings(context);\n                            PhpSearchMemoryStrings(context);\n                        }\n                        else if (selectedItem == mapped)\n                        {\n                            context->Settings.Mapped = !context->Settings.Mapped;\n                            PhpSaveSettingsMemoryStrings(context);\n                            PhpSearchMemoryStrings(context);\n                        }\n                        else if (selectedItem == minimumLength)\n                        {\n                            ULONG length = PhpMemoryStringsMinimumLengthDialog(hwndDlg, context->Settings.MinimumLength);\n                            if (length != context->Settings.MinimumLength)\n                            {\n                                context->Settings.MinimumLength = length;\n                                PhpSaveSettingsMemoryStrings(context);\n                                PhpSearchMemoryStrings(context);\n                            }\n                        }\n                        else if (selectedItem == zeroPad)\n                        {\n                            context->Settings.ZeroPadAddresses = !context->Settings.ZeroPadAddresses;\n                            PhpSaveSettingsMemoryStrings(context);\n                            PhpInvalidateMemoryStringsAddresses(context);\n                        }\n                        else if (selectedItem == refresh)\n                        {\n                            PhpSearchMemoryStrings(context);\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            case IDC_FILTER:\n                {\n                    PPH_LIST nodeList;\n\n                    PhpCopyFilteredMemoryStringsNodes(context, &nodeList);\n\n                    if (!PhpShowMemoryStringTreeDialog(\n                        hwndDlg,\n                        context->ProcessItem,\n                        nodeList,\n                        context->UseClone\n                        ))\n                    {\n                        PhpDeleteMemoryStringsNodeList(nodeList);\n                        PhDereferenceObject(nodeList);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            switch (wParam)\n            {\n            case VK_F5:\n                PhpSearchMemoryStrings(context);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n    case WM_CTLCOLORDLG:\n    case WM_CTLCOLORSTATIC:\n    case WM_CTLCOLORLISTBOX:\n        {\n            SetBkMode((HDC)wParam, TRANSPARENT);\n            SetTextColor((HDC)wParam, RGB(0, 0, 0));\n            SetDCBrushColor((HDC)wParam, RGB(255, 255, 255));\n            return (INT_PTR)GetStockBrush(DC_BRUSH);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI PhpShowMemoryStringDialogThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    HWND windowHandle;\n    BOOL result;\n    MSG message;\n    PH_AUTO_POOL autoPool;\n\n    PhInitializeAutoPool(&autoPool);\n\n    windowHandle = PhCreateDialog(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_MEMSTRINGS),\n        NULL,\n        PhpMemoryStringsDlgProc,\n        Parameter\n        );\n\n    ShowWindow(windowHandle, SW_SHOW);\n    SetForegroundWindow(windowHandle);\n\n    while (result = GetMessage(&message, NULL, 0, 0))\n    {\n        if (result == INT_ERROR)\n            break;\n\n        if (!IsDialogMessage(windowHandle, &message))\n        {\n            TranslateMessage(&message);\n            DispatchMessage(&message);\n        }\n\n        PhDrainAutoPool(&autoPool);\n    }\n\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n\nBOOLEAN PhpShowMemoryStringTreeDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_opt_ PPH_LIST PrevNodeList,\n    _In_ BOOLEAN UseClone\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    PPH_MEMSTRINGS_CONTEXT context;\n\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n        ProcessItem->ProcessId\n        )))\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to open the process\", status, 0);\n        return FALSE;\n    }\n\n    context = PhAllocateZero(sizeof(PH_MEMSTRINGS_CONTEXT));\n    context->ProcessItem = PhReferenceObject(ProcessItem);\n    context->ProcessHandle = processHandle;\n    context->UseClone = UseClone;\n    context->PrevNodeList = PrevNodeList;\n\n    if (!NT_SUCCESS(status = PhCreateThread2(PhpShowMemoryStringDialogThreadStart, context)))\n    {\n        PhDereferenceObject(context->ProcessItem);\n        NtClose(context->ProcessHandle);\n        PhFree(context);\n\n        PhShowStatus(ParentWindowHandle, L\"Unable to create the window.\", status, 0);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nVOID PhShowMemoryStringTreeDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PhpShowMemoryStringTreeDialog(\n        ParentWindowHandle,\n        ProcessItem,\n        NULL,\n        ProcessItem->ProcessId == NtCurrentProcessId()\n        );\n}\n"
  },
  {
    "path": "SystemInformer/miniinfo.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <miniinfo.h>\n#include <miniinfop.h>\n\n#include <actions.h>\n#include <mainwnd.h>\n#include <notifico.h>\n#include <phplug.h>\n#include <procprv.h>\n#include <proctree.h>\n\n#include <emenu.h>\n#include <settings.h>\n#include <phsettings.h>\n\nstatic HWND PhMipContainerWindow = NULL;\nstatic POINT PhMipSourcePoint;\nstatic LONG PhMipPinCounts[MaxMiniInfoPinType];\nstatic LONG PhMipMaxPinCounts[] =\n{\n    1, // MiniInfoManualPinType\n    1, // MiniInfoIconPinType\n    1, // MiniInfoActivePinType\n    1, // MiniInfoHoverPinType\n    1, // MiniInfoChildControlPinType\n};\nC_ASSERT(sizeof(PhMipMaxPinCounts) / sizeof(LONG) == MaxMiniInfoPinType);\nstatic LONG PhMipDelayedPinAdjustments[MaxMiniInfoPinType];\nstatic PPH_MESSAGE_LOOP_FILTER_ENTRY PhMipMessageLoopFilterEntry;\nstatic HWND PhMipLastTrackedWindow;\nstatic HWND PhMipLastNcTrackedWindow;\nstatic ULONG PhMipRefreshAutomatically;\nstatic BOOLEAN PhMipPinned;\n\nstatic HWND PhMipWindow = NULL;\nstatic HWND PhMipLayoutWindow = NULL;\nstatic PH_LAYOUT_MANAGER PhMipLayoutManager;\nstatic RECT MinimumSize;\nstatic PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;\nstatic CONST PH_STRINGREF DownArrowPrefix = PH_STRINGREF_INIT(L\"\\u25be \");\n\nstatic PPH_LIST SectionList;\nstatic PH_MINIINFO_PARAMETERS CurrentParameters;\nstatic PPH_MINIINFO_SECTION CurrentSection;\n\nVOID PhPinMiniInformation(\n    _In_ PH_MINIINFO_PIN_TYPE PinType,\n    _In_ LONG PinCount,\n    _In_opt_ ULONG PinDelayMs,\n    _In_ ULONG Flags,\n    _In_opt_ PCWSTR SectionName,\n    _In_opt_ PPOINT SourcePoint\n    )\n{\n    PH_MIP_ADJUST_PIN_RESULT adjustPinResult;\n\n    if (PinDelayMs && PinCount < 0)\n    {\n        PhMipDelayedPinAdjustments[PinType] = PinCount;\n\n        if (PhMipContainerWindow)\n        {\n            PhSetTimer(PhMipContainerWindow, (UINT_PTR)MIP_TIMER_PIN_FIRST + PinType, PinDelayMs, NULL);\n        }\n        return;\n    }\n    else\n    {\n        PhMipDelayedPinAdjustments[PinType] = 0;\n\n        if (PhMipContainerWindow)\n        {\n            PhKillTimer(PhMipContainerWindow, (UINT_PTR)MIP_TIMER_PIN_FIRST + PinType);\n        }\n    }\n\n    adjustPinResult = PhMipAdjustPin(PinType, PinCount);\n\n    if (adjustPinResult == ShowAdjustPinResult)\n    {\n        PH_RECTANGLE windowRectangle;\n        ULONG opacity;\n\n        if (SourcePoint)\n            PhMipSourcePoint = *SourcePoint;\n\n        if (!PhMipContainerWindow)\n        {\n            RTL_ATOM windowAtom;\n\n            if ((windowAtom = PhMipContainerInitializeWindowClass()) == INVALID_ATOM)\n                return;\n\n            PhMipContainerWindow = PhCreateWindowEx(\n                MAKEINTATOM(windowAtom),\n                NULL,\n                WS_BORDER | WS_THICKFRAME | WS_POPUP,\n                WS_EX_TOOLWINDOW,\n                0,\n                0,\n                400,\n                400,\n                NULL,\n                NULL,\n                NULL,\n                NULL\n                );\n\n            PhMipWindow = PhCreateDialog(\n                PhInstanceHandle,\n                MAKEINTRESOURCE(IDD_MINIINFO),\n                PhMipContainerWindow,\n                PhMipMiniInfoDialogProc,\n                NULL\n                );\n            ShowWindow(PhMipWindow, SW_SHOW);\n\n            if (PhGetIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED))\n                PhMipSetPinned(TRUE, TRUE);\n\n            PhMipRefreshAutomatically = PhGetIntegerSetting(SETTING_MINI_INFO_WINDOW_REFRESH_AUTOMATICALLY);\n\n            opacity = PhGetIntegerSetting(SETTING_MINI_INFO_WINDOW_OPACITY);\n\n            if (opacity != 0)\n                PhSetWindowOpacity(PhMipContainerWindow, opacity);\n\n            MinimumSize.left = 0;\n            MinimumSize.top = 0;\n            MinimumSize.right = 210;\n            MinimumSize.bottom = 60;\n            MapDialogRect(PhMipWindow, &MinimumSize);\n        }\n\n        if (!(Flags & PH_MINIINFO_LOAD_POSITION))\n        {\n            PhMipCalculateWindowRectangle(&PhMipSourcePoint, &windowRectangle);\n            SetWindowPos(\n                PhMipContainerWindow,\n                HWND_TOPMOST,\n                windowRectangle.Left,\n                windowRectangle.Top,\n                windowRectangle.Width,\n                windowRectangle.Height,\n                SWP_NOACTIVATE\n                );\n        }\n        else\n        {\n            PhLoadWindowPlacementFromSetting(SETTING_MINI_INFO_WINDOW_POSITION, SETTING_MINI_INFO_WINDOW_SIZE, PhMipContainerWindow);\n            SetWindowPos(PhMipContainerWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);\n        }\n\n        PhInitializeWindowTheme(PhMipContainerWindow, PhEnableThemeSupport);\n\n        ShowWindow(PhMipContainerWindow, (Flags & PH_MINIINFO_ACTIVATE_WINDOW) ? SW_SHOW : SW_SHOWNOACTIVATE);\n    }\n    else if (adjustPinResult == HideAdjustPinResult)\n    {\n        if (PhMipContainerWindow)\n            ShowWindow(PhMipContainerWindow, SW_HIDE);\n    }\n    else\n    {\n        if ((Flags & PH_MINIINFO_ACTIVATE_WINDOW) && PhMipContainerWindow && IsWindowVisible(PhMipContainerWindow))\n            SetActiveWindow(PhMipContainerWindow);\n    }\n\n    if ((Flags & PH_MINIINFO_ACTIVATE_WINDOW) && PhMipContainerWindow)\n        SetForegroundWindow(PhMipContainerWindow);\n\n    if (SectionName && (!PhMipPinned || !(Flags & PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED)))\n    {\n        PH_STRINGREF sectionName;\n        PPH_MINIINFO_SECTION section;\n\n        PhInitializeStringRefLongHint(&sectionName, SectionName);\n\n        if (section = PhMipFindSection(&sectionName))\n            PhMipChangeSection(section);\n    }\n}\n\nLRESULT CALLBACK PhMipContainerWndProc(\n    _In_ HWND hWnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_SHOWWINDOW:\n        {\n            PhMipContainerOnShowWindow(!!wParam, (ULONG)lParam);\n        }\n        break;\n    case WM_ACTIVATE:\n        {\n            PhMipContainerOnActivate(GET_WM_COMMAND_ID(wParam, lParam), !!HIWORD(wParam));\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhMipContainerOnSize();\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhMipContainerOnSizing((ULONG)wParam, (PRECT)lParam);\n        }\n        break;\n    case WM_EXITSIZEMOVE:\n        {\n            PhMipContainerOnExitSizeMove();\n        }\n        break;\n    case WM_CLOSE:\n        {\n            // Hide, don't close.\n            ShowWindow(hWnd, SW_HIDE);\n        }\n        return TRUE;\n    case WM_ERASEBKGND:\n        {\n            if (PhMipContainerOnEraseBkgnd((HDC)wParam))\n                return TRUE;\n        }\n        break;\n    case WM_TIMER:\n        {\n            PhMipContainerOnTimer((ULONG)wParam);\n        }\n        break;\n    }\n\n    return DefWindowProc(hWnd, uMsg, wParam, lParam);\n}\n\nINT_PTR CALLBACK PhMipMiniInfoDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhMipWindow = hwndDlg;\n            PhMipLayoutWindow = GetDlgItem(hwndDlg, IDC_LAYOUT);\n            PhMipOnInitDialog();\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PhMipOnShowWindow(!!wParam, (ULONG)lParam);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            PhMipOnCommand(GET_WM_COMMAND_ID(wParam, lParam), HIWORD(wParam));\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LRESULT result;\n\n            if (PhMipOnNotify((NMHDR *)lParam, &result))\n            {\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, result);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n    case WM_CTLCOLORDLG:\n    case WM_CTLCOLORSTATIC:\n        {\n            HBRUSH brush;\n\n            if (PhMipOnCtlColorXxx(uMsg, (HWND)lParam, (HDC)wParam, &brush))\n                return (INT_PTR)brush;\n        }\n        break;\n    case WM_DRAWITEM:\n        {\n            if (PhMipOnDrawItem(wParam, (DRAWITEMSTRUCT *)lParam))\n                return TRUE;\n        }\n        break;\n    }\n\n    if (uMsg >= MIP_MSG_FIRST && uMsg <= MIP_MSG_LAST)\n    {\n        PhMipOnUserMessage(uMsg, wParam, lParam);\n    }\n\n    return FALSE;\n}\n\nRTL_ATOM PhMipContainerInitializeWindowClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex;\n    PPH_STRING name;\n\n    memset(&wcex, 0, sizeof(WNDCLASSEX));\n    wcex.cbSize = sizeof(WNDCLASSEX);\n    wcex.style = CS_DBLCLKS | CS_GLOBALCLASS;\n    wcex.lpfnWndProc = PhMipContainerWndProc;\n    wcex.cbClsExtra = 0;\n    wcex.cbWndExtra = sizeof(PVOID);\n    wcex.hInstance = NtCurrentImageBase();\n    wcex.hCursor = PhLoadCursor(NULL, IDC_ARROW);\n    name = PhaGetStringSetting(SETTING_MINI_INFO_CONTAINER_CLASS_NAME);\n    wcex.lpszClassName = PhGetStringOrDefault(name, SETTING_MINI_INFO_CONTAINER_CLASS_NAME);\n\n    return RegisterClassEx(&wcex);\n}\n\nVOID PhMipContainerOnShowWindow(\n    _In_ BOOLEAN Showing,\n    _In_ ULONG State\n    )\n{\n    ULONG i;\n    PPH_MINIINFO_SECTION section;\n\n    if (Showing)\n    {\n        PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0);\n\n        PhMipMessageLoopFilterEntry = PhRegisterMessageLoopFilter(PhMipMessageLoopFilter, NULL);\n\n        PhRegisterCallback(\n            PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n            PhMipUpdateHandler,\n            NULL,\n            &ProcessesUpdatedRegistration\n            );\n    }\n    else\n    {\n        for (i = 0; i < MaxMiniInfoPinType; i++)\n            PhMipPinCounts[i] = 0;\n\n        Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PINWINDOW), BST_UNCHECKED);\n        PhMipSetPinned(FALSE, TRUE);\n        PhSetIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED, FALSE);\n\n        PhUnregisterCallback(\n            PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n            &ProcessesUpdatedRegistration\n            );\n\n        if (PhMipMessageLoopFilterEntry)\n        {\n            PhUnregisterMessageLoopFilter(PhMipMessageLoopFilterEntry);\n            PhMipMessageLoopFilterEntry = NULL;\n        }\n\n        PhSaveWindowPlacementToSetting(SETTING_MINI_INFO_WINDOW_POSITION, SETTING_MINI_INFO_WINDOW_SIZE, PhMipContainerWindow);\n    }\n\n    if (SectionList)\n    {\n        for (i = 0; i < SectionList->Count; i++)\n        {\n            section = SectionList->Items[i];\n            section->Callback(section, MiniInfoShowing, UlongToPtr(Showing), NULL);\n        }\n    }\n}\n\nVOID PhMipContainerOnActivate(\n    _In_ ULONG Type,\n    _In_ BOOLEAN Minimized\n    )\n{\n    if (Type == WA_ACTIVE || Type == WA_CLICKACTIVE)\n    {\n        PhPinMiniInformation(MiniInfoActivePinType, 1, 0, 0, NULL, NULL);\n    }\n    else if (Type == WA_INACTIVE)\n    {\n        PhPinMiniInformation(MiniInfoActivePinType, -1, 0, 0, NULL, NULL);\n    }\n}\n\nVOID PhMipContainerOnSize(\n    VOID\n    )\n{\n    if (PhMipWindow)\n    {\n        InvalidateRect(PhMipContainerWindow, NULL, FALSE);\n        PhMipLayout();\n    }\n}\n\nVOID PhMipContainerOnSizing(\n    _In_ ULONG Edge,\n    _In_ PRECT DragRectangle\n    )\n{\n    PhResizingMinimumSize(DragRectangle, Edge, MinimumSize.right, MinimumSize.bottom);\n}\n\nVOID PhMipContainerOnExitSizeMove(\n    VOID\n    )\n{\n    PhSaveWindowPlacementToSetting(SETTING_MINI_INFO_WINDOW_POSITION, SETTING_MINI_INFO_WINDOW_SIZE, PhMipContainerWindow);\n}\n\nBOOLEAN PhMipContainerOnEraseBkgnd(\n    _In_ HDC hdc\n    )\n{\n    return FALSE;\n}\n\nVOID PhMipContainerOnTimer(\n    _In_ ULONG Id\n    )\n{\n    if (Id >= MIP_TIMER_PIN_FIRST && Id <= MIP_TIMER_PIN_LAST)\n    {\n        PH_MINIINFO_PIN_TYPE pinType = Id - MIP_TIMER_PIN_FIRST;\n\n        // PhPinMiniInformation kills the timer for us.\n        PhPinMiniInformation(pinType, PhMipDelayedPinAdjustments[pinType], 0, 0, NULL, NULL);\n    }\n}\n\nVOID PhMipOnInitDialog(\n    VOID\n    )\n{\n    HICON cog;\n    HICON pin;\n    LONG dpiValue;\n    HWND sectionWindow;\n    WNDPROC oldWndProc;\n\n    dpiValue = PhGetWindowDpi(PhMipWindow);\n    sectionWindow = GetDlgItem(PhMipWindow, IDC_SECTION);\n\n    cog = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_COG), dpiValue);\n    SET_BUTTON_ICON(PhMipWindow, IDC_OPTIONS, cog);\n\n    pin = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PIN), dpiValue);\n    SET_BUTTON_ICON(PhMipWindow, IDC_PINWINDOW, pin);\n\n    PhInitializeLayoutManager(&PhMipLayoutManager, PhMipWindow);\n    PhAddLayoutItem(&PhMipLayoutManager, PhMipLayoutWindow, NULL, PH_ANCHOR_ALL);\n    PhAddLayoutItem(&PhMipLayoutManager, sectionWindow, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE);\n    PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_OPTIONS), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n    PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_PINWINDOW), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n    Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PINWINDOW), !!PhGetIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED));\n\n    // Subclass the window procedure.\n    oldWndProc = PhGetWindowProcedure(sectionWindow);\n    PhSetWindowContext(sectionWindow, 0xF, oldWndProc);\n    PhSetWindowProcedure(sectionWindow, PhMipSectionControlHookWndProc);\n}\n\nVOID PhMipOnShowWindow(\n    _In_ BOOLEAN Showing,\n    _In_ ULONG State\n    )\n{\n    if (SectionList)\n        return;\n\n    SectionList = PhCreateList(8);\n    PhMipInitializeParameters();\n\n    SetWindowFont(GetDlgItem(PhMipWindow, IDC_SECTION), CurrentParameters.MediumFont, FALSE);\n\n    PhMipCreateInternalListSection(L\"CPU\", 0, PhMipCpuListSectionCallback);\n    PhMipCreateInternalListSection(L\"Commit charge\", 0, PhMipCommitListSectionCallback);\n    PhMipCreateInternalListSection(L\"Physical memory\", 0, PhMipPhysicalListSectionCallback);\n    PhMipCreateInternalListSection(L\"I/O\", 0, PhMipIoListSectionCallback);\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_MINIINFO_POINTERS pointers;\n\n        pointers.WindowHandle = PhMipContainerWindow;\n        pointers.CreateSection = PhMipCreateSection;\n        pointers.FindSection = PhMipFindSection;\n        pointers.CreateListSection = PhMipCreateListSection;\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMiniInformationInitializing), &pointers);\n    }\n\n    PhMipChangeSection(SectionList->Items[0]);\n}\n\nVOID PhMipOnCommand(\n    _In_ ULONG Id,\n    _In_ ULONG Code\n    )\n{\n    switch (Id)\n    {\n    case IDC_SECTION:\n        {\n            switch (Code)\n            {\n            case STN_CLICKED:\n                PhMipShowSectionMenu();\n                break;\n            }\n        }\n        break;\n    case IDC_OPTIONS:\n        PhMipShowOptionsMenu();\n        break;\n    case IDC_PINWINDOW:\n        {\n            BOOLEAN pinned;\n\n            pinned = Button_GetCheck(GetDlgItem(PhMipWindow, IDC_PINWINDOW)) == BST_CHECKED;\n            PhPinMiniInformation(MiniInfoManualPinType, pinned ? 1 : -1, 0, 0, NULL, NULL);\n            PhMipSetPinned(pinned, TRUE);\n            PhSetIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED, pinned);\n        }\n        break;\n    }\n}\n\n_Success_(return)\nBOOLEAN PhMipOnNotify(\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    )\n{\n    return FALSE;\n}\n\n_Success_(return)\nBOOLEAN PhMipOnCtlColorXxx(\n    _In_ ULONG Message,\n    _In_ HWND WindowHandle,\n    _In_ HDC hdc,\n    _Out_ HBRUSH *Brush\n    )\n{\n    return FALSE;\n}\n\nBOOLEAN PhMipOnDrawItem(\n    _In_ ULONG_PTR Id,\n    _In_ DRAWITEMSTRUCT *DrawItemStruct\n    )\n{\n    return FALSE;\n}\n\nVOID PhMipOnUserMessage(\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    )\n{\n    switch (Message)\n    {\n    case MIP_MSG_UPDATE:\n        {\n            ULONG i;\n            PPH_MINIINFO_SECTION section;\n\n            if (SectionList)\n            {\n                for (i = 0; i < SectionList->Count; i++)\n                {\n                    section = SectionList->Items[i];\n                    section->Callback(section, MiniInfoTick, NULL, NULL);\n                }\n            }\n        }\n        break;\n    }\n}\n\nBOOLEAN PhMipMessageLoopFilter(\n    _In_ PMSG Message,\n    _In_ PVOID Context\n    )\n{\n    if (Message->hwnd == PhMipContainerWindow || IsChild(PhMipContainerWindow, Message->hwnd))\n    {\n        if (Message->message == WM_MOUSEMOVE || Message->message == WM_NCMOUSEMOVE)\n        {\n            TRACKMOUSEEVENT trackMouseEvent;\n\n            trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);\n            trackMouseEvent.dwFlags = TME_LEAVE | (Message->message == WM_NCMOUSEMOVE ? TME_NONCLIENT : 0);\n            trackMouseEvent.hwndTrack = Message->hwnd;\n            trackMouseEvent.dwHoverTime = 0;\n            TrackMouseEvent(&trackMouseEvent);\n\n            if (Message->message == WM_MOUSEMOVE)\n                PhMipLastTrackedWindow = Message->hwnd;\n            else\n                PhMipLastNcTrackedWindow = Message->hwnd;\n\n            PhPinMiniInformation(MiniInfoHoverPinType, 1, 0, 0, NULL, NULL);\n        }\n        else if (Message->message == WM_MOUSELEAVE && Message->hwnd == PhMipLastTrackedWindow)\n        {\n            PhPinMiniInformation(MiniInfoHoverPinType, -1, MIP_UNPIN_HOVER_DELAY, 0, NULL, NULL);\n        }\n        else if (Message->message == WM_NCMOUSELEAVE && Message->hwnd == PhMipLastNcTrackedWindow)\n        {\n            PhPinMiniInformation(MiniInfoHoverPinType, -1, MIP_UNPIN_HOVER_DELAY, 0, NULL, NULL);\n        }\n        else if (Message->message == WM_KEYDOWN)\n        {\n            switch (Message->wParam)\n            {\n            case VK_F5:\n                PhMipRefresh();\n                break;\n            case VK_F6:\n            case VK_PAUSE:\n                PhMipToggleRefreshAutomatically();\n                break;\n            }\n        }\n    }\n\n    return FALSE;\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMipUpdateHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    if (PhMipRefreshAutomatically & MIP_REFRESH_AUTOMATICALLY_FLAG(PhMipPinned))\n        PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0);\n}\n\nPH_MIP_ADJUST_PIN_RESULT PhMipAdjustPin(\n    _In_ PH_MINIINFO_PIN_TYPE PinType,\n    _In_ LONG PinCount\n    )\n{\n    LONG oldTotalPinCount;\n    LONG oldPinCount;\n    LONG newPinCount;\n    ULONG i;\n\n    oldTotalPinCount = 0;\n\n    for (i = 0; i < MaxMiniInfoPinType; i++)\n        oldTotalPinCount += PhMipPinCounts[i];\n\n    oldPinCount = PhMipPinCounts[PinType];\n    newPinCount = max(oldPinCount + PinCount, 0);\n    newPinCount = min(newPinCount, PhMipMaxPinCounts[PinType]);\n    PhMipPinCounts[PinType] = newPinCount;\n\n    if (oldTotalPinCount == 0 && newPinCount > oldPinCount)\n        return ShowAdjustPinResult;\n    else if (oldTotalPinCount > 0 && oldTotalPinCount - oldPinCount + newPinCount == 0)\n        return HideAdjustPinResult;\n    else\n        return NoAdjustPinResult;\n}\n\nVOID PhMipCalculateWindowRectangle(\n    _In_ PPOINT SourcePoint,\n    _Out_ PPH_RECTANGLE WindowRectangle\n    )\n{\n    RECT windowRect;\n    PH_RECTANGLE windowRectangle;\n    PH_RECTANGLE point;\n    MONITORINFO monitorInfo = { sizeof(monitorInfo) };\n\n    PhLoadWindowPlacementFromSetting(NULL, SETTING_MINI_INFO_WINDOW_SIZE, PhMipContainerWindow);\n    PhGetWindowRect(PhMipContainerWindow, &windowRect);\n    SendMessage(PhMipContainerWindow, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&windowRect); // Adjust for the minimum size.\n    PhRectToRectangle(&windowRectangle, &windowRect);\n\n    point.Left = SourcePoint->x;\n    point.Top = SourcePoint->y;\n    point.Width = 0;\n    point.Height = 0;\n    PhCenterRectangle(&windowRectangle, &point);\n\n    if (GetMonitorInfo(\n        MonitorFromPoint(*SourcePoint, MONITOR_DEFAULTTOPRIMARY),\n        &monitorInfo\n        ))\n    {\n        PH_RECTANGLE bounds;\n\n        if (RtlEqualMemory(&monitorInfo.rcWork, &monitorInfo.rcMonitor, sizeof(RECT)))\n        {\n            HWND trayWindow;\n            RECT taskbarRect;\n\n            // The taskbar probably has auto-hide enabled. We need to adjust for that.\n\n            if ((trayWindow = FindWindow(L\"Shell_TrayWnd\", NULL)) &&\n                GetMonitorInfo(MonitorFromWindow(trayWindow, MONITOR_DEFAULTTOPRIMARY), &monitorInfo) && // Just in case\n                PhGetWindowRect(trayWindow, &taskbarRect))\n            {\n                LONG monitorMidX = (monitorInfo.rcMonitor.left + monitorInfo.rcMonitor.right) / 2;\n                LONG monitorMidY = (monitorInfo.rcMonitor.top + monitorInfo.rcMonitor.bottom) / 2;\n\n                if (taskbarRect.right < monitorMidX)\n                {\n                    // Left\n                    monitorInfo.rcWork.left += taskbarRect.right - taskbarRect.left;\n                }\n                else if (taskbarRect.bottom < monitorMidY)\n                {\n                    // Top\n                    monitorInfo.rcWork.top += taskbarRect.bottom - taskbarRect.top;\n                }\n                else if (taskbarRect.left > monitorMidX)\n                {\n                    // Right\n                    monitorInfo.rcWork.right -= taskbarRect.right - taskbarRect.left;\n                }\n                else if (taskbarRect.top > monitorMidY)\n                {\n                    // Bottom\n                    monitorInfo.rcWork.bottom -= taskbarRect.bottom - taskbarRect.top;\n                }\n            }\n        }\n\n        PhRectToRectangle(&bounds, &monitorInfo.rcWork);\n        PhAdjustRectangleToBounds(&windowRectangle, &bounds);\n    }\n\n    *WindowRectangle = windowRectangle;\n}\n\nVOID PhMipInitializeParameters(\n    VOID\n    )\n{\n    LOGFONT logFont;\n    HDC hdc;\n    TEXTMETRIC textMetrics;\n    HFONT originalFont;\n    LONG dpiValue;\n\n    memset(&CurrentParameters, 0, sizeof(PH_MINIINFO_PARAMETERS));\n\n    CurrentParameters.ContainerWindowHandle = PhMipContainerWindow;\n    CurrentParameters.MiniInfoWindowHandle = PhMipWindow;\n\n    dpiValue = PhGetWindowDpi(PhMipWindow);\n\n    if (PhGetSystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, dpiValue))\n    {\n        CurrentParameters.Font = CreateFontIndirect(&logFont);\n    }\n    else\n    {\n        CurrentParameters.Font = PhApplicationFont;\n        GetObject(PhApplicationFont, sizeof(LOGFONT), &logFont);\n    }\n\n    hdc = GetDC(PhMipWindow);\n\n    logFont.lfHeight -= PhMultiplyDivide(2, dpiValue, 72);\n    CurrentParameters.MediumFont = CreateFontIndirect(&logFont);\n\n    originalFont = SelectFont(hdc, CurrentParameters.Font);\n    GetTextMetrics(hdc, &textMetrics);\n    CurrentParameters.FontHeight = textMetrics.tmHeight;\n    CurrentParameters.FontAverageWidth = textMetrics.tmAveCharWidth;\n\n    SelectFont(hdc, CurrentParameters.MediumFont);\n    GetTextMetrics(hdc, &textMetrics);\n    CurrentParameters.MediumFontHeight = textMetrics.tmHeight;\n    CurrentParameters.MediumFontAverageWidth = textMetrics.tmAveCharWidth;\n\n    CurrentParameters.SetSectionText = PhMipSetSectionText;\n\n    SelectFont(hdc, originalFont);\n    ReleaseDC(PhMipWindow, hdc);\n}\n\n_Function_class_(PH_MINIINFO_CREATE_SECTION)\nPPH_MINIINFO_SECTION PhMipCreateSection(\n    _In_ PPH_MINIINFO_SECTION Template\n    )\n{\n    PPH_MINIINFO_SECTION section;\n\n    section = PhAllocateZero(sizeof(PH_MINIINFO_SECTION));\n    section->Name = Template->Name;\n    section->Flags = Template->Flags;\n    section->Callback = Template->Callback;\n    section->Context = Template->Context;\n    section->Parameters = &CurrentParameters;\n\n    PhAddItemList(SectionList, section);\n\n    section->Callback(section, MiniInfoCreate, NULL, NULL);\n\n    return section;\n}\n\nVOID PhMipDestroySection(\n    _In_ PPH_MINIINFO_SECTION Section\n    )\n{\n    Section->Callback(Section, MiniInfoDestroy, NULL, NULL);\n\n    PhClearReference(&Section->Text);\n    PhFree(Section);\n}\n\n_Function_class_(PH_MINIINFO_FIND_SECTION)\nPPH_MINIINFO_SECTION PhMipFindSection(\n    _In_ PPH_STRINGREF Name\n    )\n{\n    ULONG i;\n    PPH_MINIINFO_SECTION section;\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n\n        if (PhEqualStringRef(&section->Name, Name, TRUE))\n            return section;\n    }\n\n    return NULL;\n}\n\nPPH_MINIINFO_SECTION PhMipCreateInternalSection(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_MINIINFO_SECTION_CALLBACK Callback\n    )\n{\n    PH_MINIINFO_SECTION section;\n\n    memset(&section, 0, sizeof(PH_MINIINFO_SECTION));\n    PhInitializeStringRefLongHint(&section.Name, Name);\n    section.Flags = Flags;\n    section.Callback = Callback;\n\n    return PhMipCreateSection(&section);\n}\n\nVOID PhMipCreateSectionDialog(\n    _In_ PPH_MINIINFO_SECTION Section\n    )\n{\n    PH_MINIINFO_CREATE_DIALOG createDialog;\n\n    memset(&createDialog, 0, sizeof(PH_MINIINFO_CREATE_DIALOG));\n\n    if (Section->Callback(Section, MiniInfoCreateDialog, &createDialog, NULL))\n    {\n        if (!createDialog.CustomCreate)\n        {\n            Section->DialogHandle = PhCreateDialogFromTemplate(\n                PhMipWindow,\n                DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD,\n                createDialog.Instance,\n                createDialog.Template,\n                createDialog.DialogProc,\n                createDialog.Parameter\n                );\n\n            PhInitializeWindowTheme(Section->DialogHandle, PhEnableThemeSupport);\n        }\n    }\n}\n\nVOID PhMipChangeSection(\n    _In_ PPH_MINIINFO_SECTION NewSection\n    )\n{\n    PPH_MINIINFO_SECTION oldSection;\n\n    if (NewSection == CurrentSection)\n        return;\n\n    oldSection = CurrentSection;\n    CurrentSection = NewSection;\n\n    if (oldSection)\n    {\n        oldSection->Callback(oldSection, MiniInfoSectionChanging, CurrentSection, NULL);\n\n        if (oldSection->DialogHandle)\n            ShowWindow(oldSection->DialogHandle, SW_HIDE);\n    }\n\n    if (!NewSection->DialogHandle)\n        PhMipCreateSectionDialog(NewSection);\n    if (NewSection->DialogHandle)\n        ShowWindow(NewSection->DialogHandle, SW_SHOW);\n\n    PhMipUpdateSectionText(NewSection);\n    PhMipLayout();\n\n    NewSection->Callback(NewSection, MiniInfoTick, NULL, NULL);\n}\n\nVOID PhMipSetSectionText(\n    _In_ struct _PH_MINIINFO_SECTION *Section,\n    _In_opt_ PPH_STRING Text\n    )\n{\n    PhSwapReference(&Section->Text, Text);\n\n    if (Section == CurrentSection)\n        PhMipUpdateSectionText(Section);\n}\n\nVOID PhMipUpdateSectionText(\n    _In_ PPH_MINIINFO_SECTION Section\n    )\n{\n    if (Section->Text)\n    {\n        PhSetDialogItemText(PhMipWindow, IDC_SECTION,\n            PH_AUTO_T(PH_STRING, PhConcatStringRef2(&DownArrowPrefix, &Section->Text->sr))->Buffer);\n    }\n    else\n    {\n        PhSetDialogItemText(PhMipWindow, IDC_SECTION,\n            PH_AUTO_T(PH_STRING, PhConcatStringRef2(&DownArrowPrefix, &Section->Name))->Buffer);\n    }\n}\n\nVOID PhMipLayout(\n    VOID\n    )\n{\n    RECT clientRect;\n    RECT windowRect;\n\n    if (!PhGetClientRect(PhMipContainerWindow, &clientRect))\n        return;\n\n    MoveWindow(\n        PhMipWindow,\n        clientRect.left, clientRect.top,\n        clientRect.right - clientRect.left, clientRect.bottom - clientRect.top,\n        FALSE\n        );\n\n    PhLayoutManagerLayout(&PhMipLayoutManager);\n\n    if (!PhGetWindowRect(PhMipLayoutWindow, &windowRect))\n        return;\n\n    MapWindowRect(NULL, PhMipWindow, &windowRect);\n\n    if (CurrentSection && CurrentSection->DialogHandle)\n    {\n        if (CurrentSection->Flags & PH_MINIINFO_SECTION_NO_UPPER_MARGINS)\n        {\n            windowRect.left = 0;\n            windowRect.top = 0;\n            windowRect.right = clientRect.right;\n        }\n        else\n        {\n            LONG leftDistance = windowRect.left - clientRect.left;\n            LONG rightDistance = clientRect.right - windowRect.right;\n            LONG minDistance;\n\n            if (leftDistance != rightDistance)\n            {\n                // HACK: Enforce symmetry. Sometimes these are off by a pixel.\n                minDistance = min(leftDistance, rightDistance);\n                windowRect.left = clientRect.left + minDistance;\n                windowRect.right = clientRect.right - minDistance;\n            }\n        }\n\n        MoveWindow(\n            CurrentSection->DialogHandle,\n            windowRect.left, windowRect.top,\n            windowRect.right - windowRect.left, windowRect.bottom - windowRect.top,\n            TRUE\n            );\n    }\n\n    //GetWindowRect(GetDlgItem(PhMipWindow, IDC_PINWINDOW), &windowRect);\n    //MapWindowPoints(NULL, PhMipWindow, (POINT *)&rect, 2);\n}\n\nVOID PhMipBeginChildControlPin(\n    VOID\n    )\n{\n    PhPinMiniInformation(MiniInfoChildControlPinType, 1, 0, 0, NULL, NULL);\n}\n\nVOID PhMipEndChildControlPin(\n    VOID\n    )\n{\n    PhPinMiniInformation(MiniInfoChildControlPinType, -1, MIP_UNPIN_CHILD_CONTROL_DELAY, 0, NULL, NULL);\n    PostMessage(PhMipWindow, WM_MOUSEMOVE, 0, 0); // Re-evaluate hover pin\n}\n\nVOID PhMipRefresh(\n    VOID\n    )\n{\n    if (PhMipPinned)\n        SystemInformer_Refresh();\n\n    PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0);\n}\n\nVOID PhMipToggleRefreshAutomatically(\n    VOID\n    )\n{\n    PhMipRefreshAutomatically ^= MIP_REFRESH_AUTOMATICALLY_FLAG(PhMipPinned);\n    PhSetIntegerSetting(SETTING_MINI_INFO_WINDOW_REFRESH_AUTOMATICALLY, PhMipRefreshAutomatically);\n}\n\nVOID PhMipSetPinned(\n    _In_ BOOLEAN Pinned,\n    _In_ BOOLEAN Update\n    )\n{\n    if (Update)\n    {\n        PhSetWindowStyle(PhMipContainerWindow, WS_DLGFRAME | WS_SYSMENU, Pinned ? (WS_DLGFRAME | WS_SYSMENU) : 0);\n        SetWindowPos(PhMipContainerWindow, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);\n    }\n\n    PhMipPinned = Pinned;\n\n    PhNfNotifyMiniInfoPinned(Pinned);\n}\n\nVOID PhMipShowSectionMenu(\n    VOID\n    )\n{\n    PPH_EMENU menu;\n    ULONG i;\n    PPH_MINIINFO_SECTION section;\n    PPH_EMENU_ITEM menuItem;\n    POINT point;\n\n    PhMipBeginChildControlPin();\n    menu = PhCreateEMenu();\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n        menuItem = PhCreateEMenuItem(\n            (section == CurrentSection ? (PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK) : 0),\n            0,\n            PH_AUTO_T(PH_STRING, PhCreateString2(&section->Name))->Buffer,\n            NULL,\n            section\n            );\n        PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n    }\n\n    GetCursorPos(&point);\n    menuItem = PhShowEMenu(menu, PhMipWindow, PH_EMENU_SHOW_LEFTRIGHT,\n        PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y);\n\n    if (menuItem)\n    {\n        PhMipChangeSection(menuItem->Context);\n    }\n\n    PhDestroyEMenu(menu);\n    PhMipEndChildControlPin();\n}\n\nPPH_EMENU PhpMipCreateMenu(\n    VOID\n    )\n{\n    PPH_EMENU menu;\n    PPH_EMENU_ITEM menuItem;\n\n    menu = PhCreateEMenu();\n    menuItem = PhCreateEMenuItem(0, 0, L\"&Opacity\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_10, L\"10%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_20, L\"20%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_30, L\"30%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_40, L\"40%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_50, L\"50%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_60, L\"60%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_70, L\"70%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_80, L\"80%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_90, L\"90%\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_OPACITY_OPAQUE, L\"Opaque\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MINIINFO_REFRESH, L\"&Refresh\\bF5\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MINIINFO_REFRESHAUTOMATICALLY, L\"Refresh a&utomatically\\bF6\", NULL, NULL), ULONG_MAX);\n\n    return menu;\n}\n\nVOID PhMipShowOptionsMenu(\n    VOID\n    )\n{\n    PPH_EMENU menu;\n    PPH_EMENU_ITEM menuItem;\n    ULONG id;\n    RECT rect;\n\n    PhMipBeginChildControlPin();\n\n    // Menu\n\n    menu = PhpMipCreateMenu();\n\n    // Opacity\n\n    id = PH_OPACITY_TO_ID(PhGetIntegerSetting(SETTING_MINI_INFO_WINDOW_OPACITY));\n\n    if (menuItem = PhFindEMenuItem(menu, PH_EMENU_FIND_DESCEND, NULL, id))\n        menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK;\n\n    // Refresh Automatically\n\n    if (PhMipRefreshAutomatically & MIP_REFRESH_AUTOMATICALLY_FLAG(PhMipPinned))\n        PhSetFlagsEMenuItem(menu, ID_MINIINFO_REFRESHAUTOMATICALLY, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n\n    // Show the menu.\n\n    PhGetWindowRect(GetDlgItem(PhMipWindow, IDC_OPTIONS), &rect);\n    menuItem = PhShowEMenu(menu, PhMipWindow, PH_EMENU_SHOW_LEFTRIGHT,\n        PH_ALIGN_LEFT | PH_ALIGN_BOTTOM, rect.left, rect.top);\n\n    if (menuItem)\n    {\n        switch (menuItem->Id)\n        {\n        case ID_OPACITY_10:\n        case ID_OPACITY_20:\n        case ID_OPACITY_30:\n        case ID_OPACITY_40:\n        case ID_OPACITY_50:\n        case ID_OPACITY_60:\n        case ID_OPACITY_70:\n        case ID_OPACITY_80:\n        case ID_OPACITY_90:\n        case ID_OPACITY_OPAQUE:\n            {\n                ULONG opacity;\n\n                opacity = PH_ID_TO_OPACITY(menuItem->Id);\n                PhSetIntegerSetting(SETTING_MINI_INFO_WINDOW_OPACITY, opacity);\n                PhSetWindowOpacity(PhMipContainerWindow, opacity);\n            }\n            break;\n        case ID_MINIINFO_REFRESH:\n            PhMipRefresh();\n            break;\n        case ID_MINIINFO_REFRESHAUTOMATICALLY:\n            PhMipToggleRefreshAutomatically();\n            break;\n        }\n    }\n\n    PhDestroyEMenu(menu);\n    PhMipEndChildControlPin();\n}\n\nLRESULT CALLBACK PhMipSectionControlHookWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    WNDPROC oldWndProc;\n\n    if (!(oldWndProc = PhGetWindowContext(WindowHandle, 0xF)))\n        return DefWindowProc(WindowHandle, uMsg, wParam, lParam);\n\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            PhSetWindowProcedure(WindowHandle, oldWndProc);\n            PhRemoveWindowContext(WindowHandle, 0xF);\n        }\n        break;\n    case WM_SETCURSOR:\n        {\n            PhSetCursor(PhLoadCursor(NULL, IDC_HAND));\n        }\n        return TRUE;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n}\n\nPPH_MINIINFO_LIST_SECTION PhMipCreateListSection(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_MINIINFO_LIST_SECTION Template\n    )\n{\n    PPH_MINIINFO_LIST_SECTION listSection;\n    PH_MINIINFO_SECTION section;\n\n    listSection = PhAllocateZero(sizeof(PH_MINIINFO_LIST_SECTION));\n    listSection->Context = Template->Context;\n    listSection->Callback = Template->Callback;\n\n    memset(&section, 0, sizeof(PH_MINIINFO_SECTION));\n    PhInitializeStringRefLongHint(&section.Name, Name);\n    section.Flags = PH_MINIINFO_SECTION_NO_UPPER_MARGINS;\n    section.Callback = PhMipListSectionCallback;\n    section.Context = listSection;\n    listSection->Section = PhMipCreateSection(&section);\n\n    return listSection;\n}\n\nPPH_MINIINFO_LIST_SECTION PhMipCreateInternalListSection(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_MINIINFO_LIST_SECTION_CALLBACK Callback\n    )\n{\n    PH_MINIINFO_LIST_SECTION listSection;\n\n    memset(&listSection, 0, sizeof(PH_MINIINFO_LIST_SECTION));\n    listSection.Callback = Callback;\n\n    return PhMipCreateListSection(Name, Flags, &listSection);\n}\n\nBOOLEAN PhMipListSectionCallback(\n    _In_ PPH_MINIINFO_SECTION Section,\n    _In_ PH_MINIINFO_SECTION_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    )\n{\n    PPH_MINIINFO_LIST_SECTION listSection = Section->Context;\n\n    switch (Message)\n    {\n    case MiniInfoCreate:\n        {\n            listSection->NodeList = PhCreateList(2);\n            listSection->Callback(listSection, MiListSectionCreate, NULL, NULL);\n        }\n        break;\n    case MiniInfoDestroy:\n        {\n            listSection->Callback(listSection, MiListSectionDestroy, NULL, NULL);\n\n            PhMipClearListSection(listSection);\n            PhDereferenceObject(listSection->NodeList);\n            PhFree(listSection);\n        }\n        break;\n    case MiniInfoTick:\n        if (listSection->SuspendUpdate == 0)\n            PhMipTickListSection(listSection);\n        break;\n    case MiniInfoShowing:\n        {\n            listSection->Callback(listSection, MiListSectionShowing, Parameter1, Parameter2);\n\n            if (!Parameter1) // Showing\n            {\n                // We don't want to hold process item references while the mini info window\n                // is hidden.\n                PhMipClearListSection(listSection);\n\n                if (listSection->TreeNewHandle)\n                {\n                    TreeNew_NodesStructured(listSection->TreeNewHandle);\n                }\n            }\n        }\n        break;\n    case MiniInfoCreateDialog:\n        {\n            PPH_MINIINFO_CREATE_DIALOG createDialog = Parameter1;\n\n            createDialog->Instance = PhInstanceHandle;\n            createDialog->Template = MAKEINTRESOURCE(IDD_MINIINFO_LIST);\n            createDialog->DialogProc = PhMipListSectionDialogProc;\n            createDialog->Parameter = listSection;\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nINT_PTR CALLBACK PhMipListSectionDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_MINIINFO_LIST_SECTION listSection;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        listSection = (PPH_MINIINFO_LIST_SECTION)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, listSection);\n    }\n    else\n    {\n        listSection = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!listSection)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_LAYOUT_ITEM layoutItem;\n\n            listSection->DialogHandle = hwndDlg;\n            listSection->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            PhInitializeLayoutManager(&listSection->LayoutManager, hwndDlg);\n            layoutItem = PhAddLayoutItem(&listSection->LayoutManager, listSection->TreeNewHandle, NULL, PH_ANCHOR_ALL);\n\n            // Use negative margins to maximize our use of the window area.\n            layoutItem->Margin.left = -1;\n            layoutItem->Margin.top = -1;\n            layoutItem->Margin.right = -1;\n\n            PhSetControlTheme(listSection->TreeNewHandle, L\"explorer\");\n            TreeNew_SetRedraw(listSection->TreeNewHandle, FALSE);\n            TreeNew_SetCallback(listSection->TreeNewHandle, PhMipListSectionTreeNewCallback, listSection);\n            TreeNew_SetRowHeight(listSection->TreeNewHandle, PhMipCalculateRowHeight(hwndDlg));\n            PhAddTreeNewColumnEx2(listSection->TreeNewHandle, MIP_SINGLE_COLUMN_ID, TRUE, L\"Process\", 1,\n                PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_CUSTOMDRAW);\n            TreeNew_SetRedraw(listSection->TreeNewHandle, TRUE);\n\n            listSection->Callback(listSection, MiListSectionDialogCreated, hwndDlg, NULL);\n            PhMipTickListSection(listSection);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDeleteLayoutManager(&listSection->LayoutManager);\n\n            listSection->TreeNewHandle = NULL;\n            listSection->DialogHandle = NULL;\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&listSection->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&listSection->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&listSection->LayoutManager);\n\n            TreeNew_AutoSizeColumn(listSection->TreeNewHandle, MIP_SINGLE_COLUMN_ID, TN_AUTOSIZE_REMAINING_SPACE);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhMipListSectionSortFunction(\n    _In_ PPH_LIST List,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MINIINFO_LIST_SECTION listSection = Context;\n    PH_MINIINFO_LIST_SECTION_SORT_LIST sortList;\n\n    if (!listSection)\n        return;\n\n    sortList.List = List;\n    listSection->Callback(listSection, MiListSectionSortProcessList, &sortList, NULL);\n}\n\nVOID PhMipTickListSection(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection\n    )\n{\n    ULONG i;\n    PPH_MIP_GROUP_NODE node;\n    PH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData;\n\n    PhMipClearListSection(ListSection);\n\n    ListSection->ProcessGroupList = PhCreateProcessGroupList(\n        PhMipListSectionSortFunction,\n        ListSection,\n        MIP_MAX_PROCESS_GROUPS,\n        0\n        );\n\n    if (!ListSection->ProcessGroupList)\n        return;\n\n    for (i = 0; i < ListSection->ProcessGroupList->Count; i++)\n    {\n        node = PhMipAddGroupNode(ListSection, ListSection->ProcessGroupList->Items[i]);\n\n        if (node->RepresentativeProcessId == ListSection->SelectedRepresentativeProcessId &&\n            node->RepresentativeCreateTime.QuadPart == ListSection->SelectedRepresentativeCreateTime.QuadPart)\n        {\n            node->Node.Selected = TRUE;\n        }\n\n        assignSortData.ProcessGroup = node->ProcessGroup;\n        assignSortData.SortData = &node->SortData;\n        ListSection->Callback(ListSection, MiListSectionAssignSortData, &assignSortData, NULL);\n    }\n\n    if (ListSection->TreeNewHandle)\n    {\n        TreeNew_NodesStructured(ListSection->TreeNewHandle);\n        TreeNew_AutoSizeColumn(ListSection->TreeNewHandle, MIP_SINGLE_COLUMN_ID, TN_AUTOSIZE_REMAINING_SPACE);\n    }\n\n    ListSection->Callback(ListSection, MiListSectionTick, NULL, NULL);\n}\n\nVOID PhMipClearListSection(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection\n    )\n{\n    if (ListSection->ProcessGroupList)\n    {\n        PhFreeProcessGroupList(ListSection->ProcessGroupList);\n        ListSection->ProcessGroupList = NULL;\n    }\n\n    for (ULONG i = 0; i < ListSection->NodeList->Count; i++)\n        PhMipDestroyGroupNode(ListSection->NodeList->Items[i]);\n\n    PhClearList(ListSection->NodeList);\n\n    PhDereferenceObject(ListSection->NodeList);\n    ListSection->NodeList = PhCreateList(2);\n}\n\nLONG PhMipCalculateRowHeight(\n    _In_ HWND WindowHandle\n    )\n{\n    LONG iconHeight;\n    LONG titleAndSubtitleHeight;\n    LONG dpiValue;\n\n    dpiValue = PhGetWindowDpi(WindowHandle);\n\n    iconHeight = PhGetDpi(MIP_ICON_PADDING + MIP_CELL_PADDING, dpiValue) + PhGetSystemMetrics(SM_CXICON, dpiValue);\n    titleAndSubtitleHeight =\n        PhGetDpi(MIP_CELL_PADDING, dpiValue) * 2 + CurrentParameters.FontHeight + PhGetDpi(MIP_INNER_PADDING, dpiValue) + CurrentParameters.FontHeight;\n\n    return max(iconHeight, titleAndSubtitleHeight);\n}\n\nPPH_MIP_GROUP_NODE PhMipAddGroupNode(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PPH_PROCESS_GROUP ProcessGroup\n    )\n{\n    PPH_MIP_GROUP_NODE node;\n\n    node = PhAllocate(sizeof(PH_MIP_GROUP_NODE));\n    memset(node, 0, sizeof(PH_MIP_GROUP_NODE));\n\n    PhInitializeTreeNewNode(&node->Node);\n    node->ProcessGroup = ProcessGroup;\n    node->RepresentativeProcessId = ProcessGroup->Representative->ProcessId;\n    node->RepresentativeCreateTime = ProcessGroup->Representative->CreateTime;\n    node->RepresentativeIsHung = ProcessGroup->WindowHandle && IsHungAppWindow(ProcessGroup->WindowHandle);\n\n    if (node->RepresentativeIsHung)\n    {\n        // Make sure this is a real hung window, not a ghost window.\n        if (PhHungWindowFromGhostWindow(ProcessGroup->WindowHandle))\n            node->RepresentativeIsHung = FALSE;\n    }\n\n    if (FlagOn(ProcessGroup->Representative->State, PH_PROCESS_ITEM_REMOVED))\n    {\n        node->RepresentativeIsTerminated = TRUE;\n    }\n\n    PhAddItemList(ListSection->NodeList, node);\n\n    return node;\n}\n\nVOID PhMipDestroyGroupNode(\n    _In_ PPH_MIP_GROUP_NODE Node\n    )\n{\n    PhClearReference(&Node->TooltipText);\n    PhFree(Node);\n}\n\nBOOLEAN PhMipListSectionTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MINIINFO_LIST_SECTION listSection = Context;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            PH_MINIINFO_LIST_SECTION_SORT_LIST sortList;\n\n            if (!getChildren->Node)\n            {\n                getChildren->Children = (PPH_TREENEW_NODE *)listSection->NodeList->Items;\n                getChildren->NumberOfChildren = listSection->NodeList->Count;\n\n                sortList.List = listSection->NodeList;\n                listSection->Callback(listSection, MiListSectionSortGroupList, &sortList, NULL);\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewCustomDraw:\n        {\n            PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;\n            PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)customDraw->Node;\n            PPH_PROCESS_ITEM processItem = node->ProcessGroup->Representative;\n            HDC hdc = customDraw->Dc;\n            RECT rect = customDraw->CellRect;\n            ULONG baseTextFlags = DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE;\n            HICON icon;\n            COLORREF originalTextColor;\n            RECT topRect;\n            RECT bottomRect;\n            PH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText;\n            ULONG usageTextTopWidth = 0;\n            ULONG usageTextBottomWidth = 0;\n            PH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT getTitleText;\n            LONG dpiValue;\n            LONG width;\n            LONG height;\n            LONG iconPadding;\n            LONG cellPadding;\n\n            dpiValue = PhGetWindowDpi(WindowHandle);\n\n            width = PhGetSystemMetrics(SM_CXICON, dpiValue);\n            height = PhGetSystemMetrics(SM_CYICON, dpiValue);\n\n            iconPadding = PhGetDpi(MIP_ICON_PADDING, dpiValue);\n            cellPadding = PhGetDpi(MIP_CELL_PADDING, dpiValue);\n\n            rect.left += iconPadding;\n            rect.top += iconPadding;\n            rect.right -= cellPadding;\n            rect.bottom -= cellPadding;\n\n            icon = PhGetImageListIcon(processItem->LargeIconIndex, TRUE);\n            DrawIconEx(hdc, rect.left, rect.top, icon, width, height, 0, NULL, DI_NORMAL);\n            DestroyIcon(icon);\n\n            rect.left += (cellPadding - iconPadding) + width + cellPadding;\n            rect.top += cellPadding - iconPadding;\n            SelectFont(hdc, CurrentParameters.Font);\n\n            // This color changes depending on whether the node is selected, etc.\n            originalTextColor = GetTextColor(hdc);\n\n            // Usage text\n\n            topRect = rect;\n            topRect.bottom = topRect.top + CurrentParameters.FontHeight;\n            bottomRect = rect;\n            bottomRect.top = bottomRect.bottom - CurrentParameters.FontHeight;\n\n            getUsageText.ProcessGroup = node->ProcessGroup;\n            getUsageText.SortData = &node->SortData;\n            getUsageText.Line1 = NULL;\n            getUsageText.Line2 = NULL;\n            getUsageText.Line1Color = originalTextColor;\n            getUsageText.Line2Color = originalTextColor;\n\n            if (listSection->Callback(listSection, MiListSectionGetUsageText, &getUsageText, NULL))\n            {\n                PH_STRINGREF text;\n                RECT textRect;\n                SIZE textSize;\n\n                // Top\n                text = PhGetStringRef(getUsageText.Line1);\n                GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize);\n                usageTextTopWidth = textSize.cx;\n                textRect = topRect;\n                textRect.left = textRect.right - textSize.cx;\n                SetTextColor(hdc, getUsageText.Line1Color);\n                DrawText(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textRect, baseTextFlags | DT_RIGHT);\n                PhClearReference(&getUsageText.Line1);\n\n                // Bottom\n                text = PhGetStringRef(getUsageText.Line2);\n                GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize);\n                usageTextBottomWidth = textSize.cx;\n                textRect = bottomRect;\n                textRect.left = textRect.right - textSize.cx;\n                SetTextColor(hdc, getUsageText.Line2Color);\n                DrawText(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textRect, baseTextFlags | DT_RIGHT);\n                PhClearReference(&getUsageText.Line2);\n            }\n\n            // Title, subtitle\n\n            getTitleText.ProcessGroup = node->ProcessGroup;\n            getTitleText.SortData = &node->SortData;\n\n            if (!PhIsNullOrEmptyString(processItem->VersionInfo.FileDescription))\n                PhSetReference(&getTitleText.Title, processItem->VersionInfo.FileDescription);\n            else\n                PhSetReference(&getTitleText.Title, processItem->ProcessName);\n\n            if (node->ProcessGroup->Processes->Count == 1)\n            {\n                PhSetReference(&getTitleText.Subtitle, processItem->ProcessName);\n            }\n            else\n            {\n                getTitleText.Subtitle = PhFormatString(\n                    L\"%s (%u processes)\",\n                    processItem->ProcessName->Buffer,\n                    node->ProcessGroup->Processes->Count\n                    );\n            }\n\n            getTitleText.TitleColor = originalTextColor;\n            getTitleText.SubtitleColor = GetSysColor(COLOR_GRAYTEXT);\n\n            // Special text for hung windows\n            if (node->RepresentativeIsHung)\n            {\n                static CONST PH_STRINGREF hungPrefix = PH_STRINGREF_INIT(L\"(Not responding) \");\n\n                PhMoveReference(&getTitleText.Title, PhConcatStringRef2(&hungPrefix, &getTitleText.Title->sr));\n                getTitleText.TitleColor = RGB(0xff, 0x00, 0x00);\n            }\n\n            if (node->RepresentativeIsTerminated)\n            {\n                static CONST PH_STRINGREF terminatedPrefix = PH_STRINGREF_INIT(L\"(Terminated) \");\n\n                PhMoveReference(&getTitleText.Title, PhConcatStringRef2(&terminatedPrefix, &getTitleText.Title->sr));\n                getTitleText.TitleColor = RGB(0xA9, 0xA9, 0xA9);\n            }\n\n            listSection->Callback(listSection, MiListSectionGetTitleText, &getTitleText, NULL);\n\n            if (!PhIsNullOrEmptyString(getTitleText.Title))\n            {\n                RECT textRect;\n\n                textRect = topRect;\n                textRect.right -= usageTextTopWidth + MIP_INNER_PADDING;\n                SetTextColor(hdc, getTitleText.TitleColor);\n                DrawText(\n                    hdc,\n                    getTitleText.Title->Buffer,\n                    (ULONG)getTitleText.Title->Length / sizeof(WCHAR),\n                    &textRect,\n                    baseTextFlags | DT_END_ELLIPSIS\n                    );\n            }\n\n            if (!PhIsNullOrEmptyString(getTitleText.Subtitle))\n            {\n                RECT textRect;\n\n                textRect = bottomRect;\n                textRect.right -= usageTextBottomWidth + MIP_INNER_PADDING;\n                SetTextColor(hdc, getTitleText.SubtitleColor);\n                DrawText(\n                    hdc,\n                    getTitleText.Subtitle->Buffer,\n                    (ULONG)getTitleText.Subtitle->Length / sizeof(WCHAR),\n                    &textRect,\n                    baseTextFlags | DT_END_ELLIPSIS\n                    );\n            }\n\n            PhClearReference(&getTitleText.Title);\n            PhClearReference(&getTitleText.Subtitle);\n        }\n        return TRUE;\n    case TreeNewGetCellTooltip:\n        {\n            PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;\n            PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)getCellTooltip->Node;\n\n            // This is useless most of the time because the tooltip doesn't display unless the window is active.\n            // TODO: Find a way to make the tooltip display all the time.\n\n            if (!node->TooltipText)\n                node->TooltipText = PhMipGetGroupNodeTooltip(listSection, node);\n\n            if (!PhIsNullOrEmptyString(node->TooltipText))\n            {\n                getCellTooltip->Text = node->TooltipText->sr;\n                getCellTooltip->Unfolding = FALSE;\n                getCellTooltip->MaximumWidth = ULONG_MAX;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case TreeNewSelectionChanged:\n        {\n            ULONG i;\n            PPH_MIP_GROUP_NODE node;\n\n            listSection->SelectedRepresentativeProcessId = NULL;\n            listSection->SelectedRepresentativeCreateTime.QuadPart = 0;\n\n            for (i = 0; i < listSection->NodeList->Count; i++)\n            {\n                node = listSection->NodeList->Items[i];\n\n                if (node->Node.Selected)\n                {\n                    listSection->SelectedRepresentativeProcessId = node->RepresentativeProcessId;\n                    listSection->SelectedRepresentativeCreateTime = node->RepresentativeCreateTime;\n                    break;\n                }\n            }\n        }\n        break;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            listSection->SuspendUpdate++;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case VK_DELETE:\n                {\n                    PPH_MIP_GROUP_NODE node;\n                    PPH_PROCESS_ITEM processItem;\n                    BOOLEAN pinned;\n\n                    // Prevent the window from changing visibility while displaying a modal dialog. (dmex)\n                    {\n                        pinned = TRUE;\n                        PhPinMiniInformation(MiniInfoManualPinType, pinned ? 1 : -1, 0, 0, NULL, NULL);\n                        PhMipSetPinned(pinned, FALSE);\n                        PhSetIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED, pinned);\n                    }\n\n                    if (node = PhMipGetSelectedGroupNode(listSection))\n                    {\n                        processItem = node->ProcessGroup->Representative;\n\n                        PhReferenceObject(processItem);\n                        PhUiTerminateProcesses(listSection->DialogHandle, &processItem, 1);\n                        PhDereferenceObject(processItem);\n                    }\n\n                    SetFocus(listSection->TreeNewHandle);\n                    //SystemInformer_Refresh();\n                    //PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0);\n\n                    {\n                        pinned = FALSE;\n                        PhPinMiniInformation(MiniInfoManualPinType, pinned ? 1 : -1, 0, 0, NULL, NULL);\n                        PhMipSetPinned(pinned, FALSE);\n                        PhSetIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED, pinned);\n                    }\n                }\n                break;\n            case VK_RETURN:\n                {\n                    PPH_MIP_GROUP_NODE node;\n                    BOOLEAN pinned;\n\n                    // Prevent the window from changing visibility while displaying a modal dialog. (dmex)\n                    {\n                        pinned = TRUE;\n                        PhPinMiniInformation(MiniInfoManualPinType, pinned ? 1 : -1, 0, 0, NULL, NULL);\n                        PhMipSetPinned(pinned, FALSE);\n                        PhSetIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED, pinned);\n                    }\n\n                    if (node = PhMipGetSelectedGroupNode(listSection))\n                    {\n                        if (GetKeyState(VK_CONTROL) >= 0)\n                        {\n                            PhMipHandleListSectionCommand(listSection, node->ProcessGroup, ID_PROCESS_GOTOPROCESS);\n                        }\n                        else\n                        {\n                            if (node->ProcessGroup->Representative->FileName)\n                            {\n                                PhShellExecuteUserString(\n                                    listSection->DialogHandle,\n                                    SETTING_FILE_BROWSE_EXECUTABLE,\n                                    node->ProcessGroup->Representative->FileName->Buffer,\n                                    FALSE,\n                                    L\"Make sure the Explorer executable file is present.\"\n                                    );\n                            }\n                        }\n                    }\n\n                    SetFocus(listSection->TreeNewHandle);\n                    //SystemInformer_Refresh();\n                    //PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0);\n\n                    {\n                        pinned = FALSE;\n                        PhPinMiniInformation(MiniInfoManualPinType, pinned ? 1 : -1, 0, 0, NULL, NULL);\n                        PhMipSetPinned(pinned, FALSE);\n                        PhSetIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED, pinned);\n                    }\n                }\n                break;\n            }\n\n            listSection->SuspendUpdate--;\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1;\n            PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)mouseEvent->Node;\n\n            if (node)\n            {\n                listSection->SuspendUpdate++;\n                PhMipHandleListSectionCommand(listSection, node->ProcessGroup, ID_PROCESS_GOTOPROCESS);\n                listSection->SuspendUpdate--;\n            }\n        }\n        break;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n\n            // Prevent the node list from being updated (otherwise any nodes we're using might be destroyed while we're\n            // in a modal message loop).\n            listSection->SuspendUpdate++;\n            PhMipBeginChildControlPin();\n            PhMipShowListSectionContextMenu(listSection, contextMenu);\n            PhMipEndChildControlPin();\n            listSection->SuspendUpdate--;\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nPPH_STRING PhMipGetGroupNodeTooltip(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PPH_MIP_GROUP_NODE Node\n    )\n{\n    PH_STRING_BUILDER sb;\n\n    PhInitializeStringBuilder(&sb, 100);\n\n    // TODO\n\n    return PhFinalStringBuilderString(&sb);\n}\n\nPPH_MIP_GROUP_NODE PhMipGetSelectedGroupNode(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection\n    )\n{\n    ULONG i;\n    PPH_MIP_GROUP_NODE node;\n\n    for (i = 0; i < ListSection->NodeList->Count; i++)\n    {\n        node = ListSection->NodeList->Items[i];\n\n        if (node->Node.Selected)\n            return node;\n    }\n\n    return NULL;\n}\n\nVOID PhMipShowListSectionContextMenu(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    )\n{\n    PPH_MIP_GROUP_NODE selectedNode;\n    PPH_EMENU menu;\n    PPH_EMENU_ITEM item;\n    PH_MINIINFO_LIST_SECTION_MENU_INFORMATION menuInfo;\n    PH_PLUGIN_MENU_INFORMATION pluginMenuInfo;\n\n    selectedNode = PhMipGetSelectedGroupNode(ListSection);\n\n    if (!selectedNode)\n        return;\n\n    menu = PhCreateEMenu();\n    // TODO: If there are multiple processes, then create submenus for each process.\n    PhAddMiniProcessMenuItems(menu, ListSection->SelectedRepresentativeProcessId);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_GOTOPROCESS, L\"&Go to process\", NULL, NULL), ULONG_MAX);\n    PhSetFlagsEMenuItem(menu, ID_PROCESS_GOTOPROCESS, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n\n    if (selectedNode->ProcessGroup->Processes->Count != 1)\n    {\n        if (item = PhFindEMenuItem(menu, 0, NULL, ID_PROCESS_GOTOPROCESS))\n            PhModifyEMenuItem(item, PH_EMENU_MODIFY_TEXT, 0, L\"&Go to processes\", NULL);\n    }\n\n    memset(&menuInfo, 0, sizeof(PH_MINIINFO_LIST_SECTION_MENU_INFORMATION));\n    menuInfo.ProcessGroup = selectedNode->ProcessGroup;\n    menuInfo.SortData = &selectedNode->SortData;\n    menuInfo.ContextMenu = ContextMenu;\n    ListSection->Callback(ListSection, MiListSectionInitializeContextMenu, &menuInfo, NULL);\n\n    if (PhPluginsEnabled)\n    {\n        PhPluginInitializeMenuInfo(&pluginMenuInfo, menu, ListSection->DialogHandle, 0);\n        pluginMenuInfo.Menu = menu;\n        pluginMenuInfo.OwnerWindow = PhMipWindow;\n        pluginMenuInfo.u.MiListSection.SectionName = &ListSection->Section->Name;\n        pluginMenuInfo.u.MiListSection.ProcessGroup = selectedNode->ProcessGroup;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMiListSectionMenuInitializing), &pluginMenuInfo);\n    }\n\n    item = PhShowEMenu(\n        menu,\n        PhMipWindow,\n        PH_EMENU_SHOW_LEFTRIGHT,\n        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n        ContextMenu->Location.x,\n        ContextMenu->Location.y\n        );\n\n    if (item)\n    {\n        BOOLEAN handled = FALSE;\n\n        if (!handled && PhPluginsEnabled)\n            handled = PhPluginTriggerEMenuItem(&pluginMenuInfo, item);\n\n        if (!handled)\n        {\n            menuInfo.SelectedItem = item;\n            handled = ListSection->Callback(ListSection, MiListSectionHandleContextMenu, &menuInfo, NULL);\n        }\n\n        if (!handled)\n            PhHandleMiniProcessMenuItem(item);\n\n        if (!handled)\n            PhMipHandleListSectionCommand(ListSection, selectedNode->ProcessGroup, item->Id);\n    }\n\n    PhDestroyEMenu(menu);\n}\n\nVOID PhMipHandleListSectionCommand(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PPH_PROCESS_GROUP ProcessGroup,\n    _In_ ULONG Id\n    )\n{\n    switch (Id)\n    {\n    case ID_PROCESS_GOTOPROCESS:\n        {\n            PPH_LIST nodes;\n            ULONG i;\n            BOOLEAN invalid;\n\n            nodes = PhCreateList(ProcessGroup->Processes->Count);\n\n            for (i = 0; i < ProcessGroup->Processes->Count; i++)\n            {\n                PPH_PROCESS_NODE node;\n\n                if (node = PhFindProcessNode(((PPH_PROCESS_ITEM)ProcessGroup->Processes->Items[i])->ProcessId))\n                    PhAddItemList(nodes, node);\n            }\n\n            invalid = ProcessGroup->Processes->Count == 1 && nodes->Count == 0;\n\n            PhPinMiniInformation(MiniInfoIconPinType, -1, 0, 0, NULL, NULL);\n            PhPinMiniInformation(MiniInfoActivePinType, -1, 0, 0, NULL, NULL);\n            PhPinMiniInformation(MiniInfoHoverPinType, -1, 0, 0, NULL, NULL);\n\n            SystemInformer_ToggleVisible(TRUE);\n            SystemInformer_SelectTabPage(0);\n            PhSelectAndEnsureVisibleProcessNodes((PPH_PROCESS_NODE*)nodes->Items, nodes->Count);\n            PhDereferenceObject(nodes);\n\n            if (invalid)\n            {\n                PhShowStatus(PhMainWndHandle, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n            }\n        }\n        break;\n    }\n}\n\nBOOLEAN PhMipCpuListSectionCallback(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case MiListSectionTick:\n        {\n            PH_FORMAT format[3];\n\n            // CPU    %.2f%%\n            PhInitFormatS(&format[0], L\"CPU    \");\n            PhInitFormatF(&format[1], (PhCpuUserUsage + PhCpuKernelUsage) * 100, PhMaxPrecisionUnit);\n            PhInitFormatC(&format[2], L'%');\n\n            ListSection->Section->Parameters->SetSectionText(ListSection->Section,\n                PH_AUTO(PhFormat(format, RTL_NUMBER_OF(format), 16)));\n        }\n        break;\n    case MiListSectionSortProcessList:\n        {\n            PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;\n\n            if (!sortList)\n                break;\n\n            qsort(sortList->List->Items, sortList->List->Count,\n                sizeof(PPH_PROCESS_NODE), PhMipCpuListSectionProcessCompareFunction);\n        }\n        return TRUE;\n    case MiListSectionAssignSortData:\n        {\n            PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;\n            PPH_LIST processes;\n            FLOAT cpuUsage;\n            ULONG i;\n\n            if (!assignSortData)\n                break;\n\n            processes = assignSortData->ProcessGroup->Processes;\n            cpuUsage = 0;\n\n            for (i = 0; i < processes->Count; i++)\n                cpuUsage += ((PPH_PROCESS_ITEM)processes->Items[i])->CpuUsage;\n\n            *(PFLOAT)assignSortData->SortData->UserData = cpuUsage;\n        }\n        return TRUE;\n    case MiListSectionSortGroupList:\n        {\n            PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;\n\n            if (!sortList)\n                break;\n\n            qsort(sortList->List->Items, sortList->List->Count,\n                sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipCpuListSectionNodeCompareFunction);\n        }\n        return TRUE;\n    case MiListSectionGetUsageText:\n        {\n            PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;\n            PPH_LIST processes;\n            FLOAT cpuUsage;\n            PPH_STRING cpuUsageText;\n            PH_FORMAT format[3];\n\n            if (!getUsageText)\n                break;\n\n            processes = getUsageText->ProcessGroup->Processes;\n            cpuUsage = *(PFLOAT)getUsageText->SortData->UserData * 100;\n\n            if (cpuUsage >= PhMaxPrecisionLimit)\n            {\n                // %.2f%%\n                PhInitFormatF(&format[0], cpuUsage, PhMaxPrecisionUnit);\n                PhInitFormatC(&format[1], L'%');\n\n                cpuUsageText = PhFormat(format, 2, 16);\n            }\n            else if (cpuUsage != 0)\n            {\n                PhInitFormatS(&format[0], L\"< \");\n                PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n                PhInitFormatC(&format[2], L'%');\n\n                cpuUsageText = PhFormat(format, 3, 16);\n            }\n            else\n                cpuUsageText = NULL;\n\n            PhMoveReference(&getUsageText->Line1, cpuUsageText);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nint __cdecl PhMipCpuListSectionProcessCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    int result;\n    PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;\n    PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;\n\n    result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage);\n\n    if (result == 0)\n        result = uint64cmp(node2->ProcessItem->UserTime.QuadPart, node1->ProcessItem->UserTime.QuadPart);\n\n    return result;\n}\n\nint __cdecl PhMipCpuListSectionNodeCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;\n\n    return singlecmp(*(PFLOAT)data2->UserData, *(PFLOAT)data1->UserData);\n}\n\nBOOLEAN PhMipCommitListSectionCallback(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case MiListSectionTick:\n        {\n            FLOAT commitFraction = (FLOAT)PhPerfInformation.CommittedPages / PhPerfInformation.CommitLimit;\n            PH_FORMAT format[5];\n\n            PhInitFormatS(&format[0], L\"Commit    \");\n            PhInitFormatSize(&format[1], UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE));\n            PhInitFormatS(&format[2], L\" (\");\n            PhInitFormatF(&format[3], commitFraction * 100, PhMaxPrecisionUnit);\n            PhInitFormatS(&format[4], L\"%)\");\n\n            ListSection->Section->Parameters->SetSectionText(ListSection->Section,\n                PH_AUTO(PhFormat(format, RTL_NUMBER_OF(format), 96)));\n        }\n        break;\n    case MiListSectionSortProcessList:\n        {\n            PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;\n\n            if (!sortList)\n                break;\n\n            qsort(sortList->List->Items, sortList->List->Count,\n                sizeof(PPH_PROCESS_NODE), PhMipCommitListSectionProcessCompareFunction);\n        }\n        return TRUE;\n    case MiListSectionAssignSortData:\n        {\n            PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;\n            PPH_LIST processes;\n            ULONG64 privateBytes;\n            ULONG i;\n\n            if (!assignSortData)\n                break;\n\n            processes = assignSortData->ProcessGroup->Processes;\n            privateBytes = 0;\n\n            for (i = 0; i < processes->Count; i++)\n                privateBytes += ((PPH_PROCESS_ITEM)processes->Items[i])->VmCounters.PagefileUsage;\n\n            *(PULONG64)assignSortData->SortData->UserData = privateBytes;\n        }\n        return TRUE;\n    case MiListSectionSortGroupList:\n        {\n            PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;\n\n            if (!sortList)\n                break;\n\n            qsort(sortList->List->Items, sortList->List->Count,\n                sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipCommitListSectionNodeCompareFunction);\n        }\n        return TRUE;\n    case MiListSectionGetUsageText:\n        {\n            PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;\n            PPH_LIST processes;\n            ULONG64 privateBytes;\n\n            if (!getUsageText)\n                break;\n\n            processes = getUsageText->ProcessGroup->Processes;\n            privateBytes = *(PULONG64)getUsageText->SortData->UserData;\n\n            PhMoveReference(&getUsageText->Line1, PhFormatSize(privateBytes, ULONG_MAX));\n            PhMoveReference(&getUsageText->Line2, PhCreateString(L\"Private bytes\"));\n            getUsageText->Line2Color = GetSysColor(COLOR_GRAYTEXT);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nint __cdecl PhMipCommitListSectionProcessCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;\n    PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;\n\n    return uintptrcmp(node2->ProcessItem->VmCounters.PagefileUsage, node1->ProcessItem->VmCounters.PagefileUsage);\n}\n\nint __cdecl PhMipCommitListSectionNodeCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;\n\n    return uint64cmp(*(PULONG64)data2->UserData, *(PULONG64)data1->UserData);\n}\n\nBOOLEAN PhMipPhysicalListSectionCallback(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case MiListSectionTick:\n        {\n            ULONG_PTR physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages;\n            FLOAT physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages;\n            FLOAT physicalPercent = physicalFraction * 100;\n            PH_FORMAT format[5];\n\n            PhInitFormatS(&format[0], L\"Physical    \");\n            PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE));\n            PhInitFormatS(&format[2], L\" (\");\n            PhInitFormatF(&format[3], physicalPercent, PhMaxPrecisionUnit);\n            PhInitFormatS(&format[4], L\"%)\");\n\n            ListSection->Section->Parameters->SetSectionText(ListSection->Section,\n                PH_AUTO(PhFormat(format, RTL_NUMBER_OF(format), 96)));\n        }\n        break;\n    case MiListSectionSortProcessList:\n        {\n            PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;\n\n            if (!sortList)\n                break;\n\n            qsort(sortList->List->Items, sortList->List->Count,\n                sizeof(PPH_PROCESS_NODE), PhMipPhysicalListSectionProcessCompareFunction);\n        }\n        return TRUE;\n    case MiListSectionAssignSortData:\n        {\n            PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;\n            PPH_LIST processes;\n            ULONG64 workingSet;\n            ULONG i;\n\n            if (!assignSortData)\n                break;\n\n            processes = assignSortData->ProcessGroup->Processes;\n            workingSet = 0;\n\n            for (i = 0; i < processes->Count; i++)\n                workingSet += ((PPH_PROCESS_ITEM)processes->Items[i])->VmCounters.WorkingSetSize;\n\n            *(PULONG64)assignSortData->SortData->UserData = workingSet;\n        }\n        return TRUE;\n    case MiListSectionSortGroupList:\n        {\n            PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;\n\n            if (!sortList)\n                break;\n\n            qsort(sortList->List->Items, sortList->List->Count,\n                sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipPhysicalListSectionNodeCompareFunction);\n        }\n        return TRUE;\n    case MiListSectionGetUsageText:\n        {\n            PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;\n            PPH_LIST processes;\n            ULONG64 privateBytes;\n\n            if (!getUsageText)\n                break;\n\n            processes = getUsageText->ProcessGroup->Processes;\n            privateBytes = *(PULONG64)getUsageText->SortData->UserData;\n\n            PhMoveReference(&getUsageText->Line1, PhFormatSize(privateBytes, ULONG_MAX));\n            PhMoveReference(&getUsageText->Line2, PhCreateString(L\"Working set\"));\n            getUsageText->Line2Color = GetSysColor(COLOR_GRAYTEXT);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nint __cdecl PhMipPhysicalListSectionProcessCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;\n    PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;\n\n    return uintptrcmp(node2->ProcessItem->VmCounters.WorkingSetSize, node1->ProcessItem->VmCounters.WorkingSetSize);\n}\n\nint __cdecl PhMipPhysicalListSectionNodeCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;\n\n    return uint64cmp(*(PULONG64)data2->UserData, *(PULONG64)data1->UserData);\n}\n\nBOOLEAN PhMipIoListSectionCallback(\n    _In_ PPH_MINIINFO_LIST_SECTION ListSection,\n    _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case MiListSectionTick:\n        {\n            PH_FORMAT format[6];\n\n            PhInitFormatS(&format[0], L\"I/O    R: \");\n            PhInitFormatSizeWithPrecision(&format[1], PhIoReadDelta.Delta, 0);\n            PhInitFormatS(&format[2], L\"  W: \");\n            PhInitFormatSizeWithPrecision(&format[3], PhIoWriteDelta.Delta, 0);\n            PhInitFormatS(&format[4], L\"  O: \");\n            PhInitFormatSizeWithPrecision(&format[5], PhIoOtherDelta.Delta, 0);\n\n            ListSection->Section->Parameters->SetSectionText(ListSection->Section,\n                PH_AUTO(PhFormat(format, RTL_NUMBER_OF(format), 80)));\n        }\n        break;\n    case MiListSectionSortProcessList:\n        {\n            PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;\n\n            if (!sortList)\n                break;\n\n            qsort(sortList->List->Items, sortList->List->Count,\n                sizeof(PPH_PROCESS_NODE), PhMipIoListSectionProcessCompareFunction);\n        }\n        return TRUE;\n    case MiListSectionAssignSortData:\n        {\n            PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;\n            PPH_LIST processes;\n            ULONG64 ioReadOtherDelta;\n            ULONG64 ioWriteDelta;\n            ULONG i;\n\n            if (!assignSortData)\n                break;\n\n            processes = assignSortData->ProcessGroup->Processes;\n            ioReadOtherDelta = 0;\n            ioWriteDelta = 0;\n\n            for (i = 0; i < processes->Count; i++)\n            {\n                PPH_PROCESS_ITEM processItem = processes->Items[i];\n                ioReadOtherDelta += processItem->IoReadDelta.Delta;\n                ioWriteDelta += processItem->IoWriteDelta.Delta;\n                ioReadOtherDelta += processItem->IoOtherDelta.Delta;\n            }\n\n            assignSortData->SortData->UserData[0] = ioReadOtherDelta;\n            assignSortData->SortData->UserData[1] = ioWriteDelta;\n        }\n        return TRUE;\n    case MiListSectionSortGroupList:\n        {\n            PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;\n\n            if (!sortList)\n                break;\n\n            qsort(sortList->List->Items, sortList->List->Count,\n                sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipIoListSectionNodeCompareFunction);\n        }\n        return TRUE;\n    case MiListSectionGetUsageText:\n        {\n            PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;\n            PPH_LIST processes;\n            ULONG64 ioReadOtherDelta;\n            ULONG64 ioWriteDelta;\n            PH_FORMAT format[1];\n\n            if (!getUsageText)\n                break;\n\n            processes = getUsageText->ProcessGroup->Processes;\n            ioReadOtherDelta = getUsageText->SortData->UserData[0];\n            ioWriteDelta = getUsageText->SortData->UserData[1];\n\n            PhInitFormatSize(&format[0], ioReadOtherDelta + ioWriteDelta);\n            PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16));\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nint __cdecl PhMipIoListSectionProcessCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    int result;\n    PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;\n    PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;\n    ULONG64 delta1 = node1->ProcessItem->IoReadDelta.Delta + node1->ProcessItem->IoWriteDelta.Delta + node1->ProcessItem->IoOtherDelta.Delta;\n    ULONG64 delta2 = node2->ProcessItem->IoReadDelta.Delta + node2->ProcessItem->IoWriteDelta.Delta + node2->ProcessItem->IoOtherDelta.Delta;\n    ULONG64 value1 = node1->ProcessItem->IoReadDelta.Value + node1->ProcessItem->IoWriteDelta.Value + node1->ProcessItem->IoOtherDelta.Value;\n    ULONG64 value2 = node2->ProcessItem->IoReadDelta.Value + node2->ProcessItem->IoWriteDelta.Value + node2->ProcessItem->IoOtherDelta.Value;\n\n    result = uint64cmp(delta2, delta1);\n\n    if (result == 0)\n        result = uint64cmp(value2, value1);\n\n    return result;\n}\n\nint __cdecl PhMipIoListSectionNodeCompareFunction(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;\n    PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;\n\n    return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]);\n}\n"
  },
  {
    "path": "SystemInformer/modlist.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <modlist.h>\n\n#include <emenu.h>\n#include <settings.h>\n#include <verify.h>\n\n#include <extmgri.h>\n#include <modprv.h>\n#include <svcsup.h>\n#include <phsettings.h>\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpModuleNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpModuleNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\nVOID PhpDestroyModuleNode(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_NODE ModuleNode\n    );\n\nVOID PhpRemoveModuleNode(\n    _In_ PPH_MODULE_NODE ModuleNode,\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    );\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpModuleTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    );\n\nBOOLEAN NTAPI PhpModuleTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\nVOID PhInitializeModuleList(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND TreeNewHandle,\n    _Out_ PPH_MODULE_LIST_CONTEXT Context\n    )\n{\n    BOOLEAN enableMonospaceFont = !!PhGetIntegerSetting(SETTING_ENABLE_MONOSPACE_FONT);\n\n    memset(Context, 0, sizeof(PH_MODULE_LIST_CONTEXT));\n    Context->EnableStateHighlighting = TRUE;\n\n    Context->NodeHashtable = PhCreateHashtable(\n        sizeof(PPH_MODULE_NODE),\n        PhpModuleNodeHashtableEqualFunction,\n        PhpModuleNodeHashtableHashFunction,\n        100\n        );\n    Context->NodeList = PhCreateList(100);\n    Context->NodeRootList = PhCreateList(2);\n\n    Context->ParentWindowHandle = ParentWindowHandle;\n    Context->TreeNewHandle = TreeNewHandle;\n\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n    TreeNew_SetCallback(Context->TreeNewHandle, PhpModuleTreeNewCallback, Context);\n\n    // Default columns\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_NAME, TRUE, L\"Name\", 100, PH_ALIGN_LEFT, -2, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_BASEADDRESS, TRUE, L\"Base address\", 80, PH_ALIGN_LEFT | (enableMonospaceFont ? PH_ALIGN_MONOSPACE_FONT : 0), 0, 0);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_SIZE, TRUE, L\"Size\", 60, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_DESCRIPTION, TRUE, L\"Description\", 160, PH_ALIGN_LEFT, 2, 0);\n    // Available columns\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_COMPANYNAME, FALSE, L\"Company name\", 180, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERSION, FALSE, L\"Version\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_FILENAME, FALSE, L\"File name\", 180, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_TYPE, FALSE, L\"Type\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_LOADCOUNT, FALSE, L\"Load count\", 40, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERIFICATIONSTATUS, FALSE, L\"Verification status\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERIFIEDSIGNER, FALSE, L\"Verified signer\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ASLR, FALSE, L\"ASLR\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_TIMESTAMP, FALSE, L\"Time stamp\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_CFGUARD, FALSE, L\"CF Guard\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_LOADTIME, FALSE, L\"Load time\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_LOADREASON, FALSE, L\"Load reason\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_FILEMODIFIEDTIME, FALSE, L\"File modified time\", 140, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_FILESIZE, FALSE, L\"File size\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ENTRYPOINT, FALSE, L\"Entry point\", 70, PH_ALIGN_RIGHT | (enableMonospaceFont ? PH_ALIGN_MONOSPACE_FONT : 0), ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_PARENTBASEADDRESS, FALSE, L\"Parent base address\", 70, PH_ALIGN_RIGHT | (enableMonospaceFont ? PH_ALIGN_MONOSPACE_FONT : 0), ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_CET, FALSE, L\"CET\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_COHERENCY, FALSE, L\"Image coherency\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx2(Context->TreeNewHandle, PHMOTLC_TIMELINE, FALSE, L\"Timeline\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_ORIGINALNAME, FALSE, L\"Original name\", 200, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_SERVICE, FALSE, L\"Service\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_ENCLAVE_TYPE, FALSE, L\"Enclave type\", 40, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ENCLAVE_BASE_ADDRESS, FALSE, L\"Enclave base address\", 80, PH_ALIGN_LEFT | (enableMonospaceFont ? PH_ALIGN_MONOSPACE_FONT : 0), ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ENCLAVE_SIZE, FALSE, L\"Enclave size\", 80, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ARCHITECTURE, FALSE, L\"Architecture\", 80, PH_ALIGN_LEFT, ULONG_MAX, DT_RIGHT, TRUE);\n\n    PhCmInitializeManager(&Context->Cm, Context->TreeNewHandle, PHMOTLC_MAXIMUM, PhpModuleTreeNewPostSortFunction);\n    PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList);\n\n    TreeNew_SetTriState(Context->TreeNewHandle, TRUE);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n}\n\nVOID PhDeleteModuleList(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport);\n\n    PhCmDeleteManager(&Context->Cm);\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n        PhpDestroyModuleNode(Context, Context->NodeList->Items[i]);\n\n    PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n    PhDereferenceObject(Context->NodeRootList);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpModuleNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_MODULE_NODE moduleNode1 = *(PPH_MODULE_NODE *)Entry1;\n    PPH_MODULE_NODE moduleNode2 = *(PPH_MODULE_NODE *)Entry2;\n\n    return moduleNode1->ModuleItem == moduleNode2->ModuleItem;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpModuleNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashIntPtr((ULONG_PTR)(*(PPH_MODULE_NODE *)Entry)->ModuleItem);\n}\n\nVOID PhLoadSettingsModuleList(\n    _Inout_ PPH_MODULE_LIST_CONTEXT Context\n    )\n{\n    ULONG flags;\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    flags = PhGetIntegerSetting(SETTING_MODULE_TREE_LIST_FLAGS);\n    settings = PhGetStringSetting(SETTING_MODULE_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_MODULE_TREE_LIST_SORT);\n\n    Context->Flags = flags;\n    PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSaveSettingsModuleList(\n    _Inout_ PPH_MODULE_LIST_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings);\n\n    PhSetIntegerSetting(SETTING_MODULE_TREE_LIST_FLAGS, Context->Flags);\n    PhSetStringSetting2(SETTING_MODULE_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_MODULE_TREE_LIST_SORT, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSetOptionsModuleList(\n    _Inout_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ ULONG Options\n    )\n{\n    switch (Options)\n    {\n    case PH_MODULE_FLAGS_DYNAMIC_OPTION:\n        Context->HideDynamicModules = !Context->HideDynamicModules;\n        break;\n    case PH_MODULE_FLAGS_MAPPED_OPTION:\n        Context->HideMappedModules = !Context->HideMappedModules;\n        break;\n    case PH_MODULE_FLAGS_STATIC_OPTION:\n        Context->HideStaticModules = !Context->HideStaticModules;\n        break;\n    case PH_MODULE_FLAGS_SIGNED_OPTION:\n        Context->HideSignedModules = !Context->HideSignedModules;\n        break;\n    case PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION:\n        Context->HighlightUntrustedModules = !Context->HighlightUntrustedModules;\n        break;\n    case PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION:\n        Context->HighlightDotNetModules = !Context->HighlightDotNetModules;\n        break;\n    case PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION:\n        Context->HighlightImmersiveModules = !Context->HighlightImmersiveModules;\n        break;\n    case PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION:\n        Context->HighlightRelocatedModules = !Context->HighlightRelocatedModules;\n        break;\n    case PH_MODULE_FLAGS_SYSTEM_OPTION:\n        Context->HideSystemModules = !Context->HideSystemModules;\n        break;\n    case PH_MODULE_FLAGS_HIGHLIGHT_SYSTEM_OPTION:\n        Context->HighlightSystemModules = !Context->HighlightSystemModules;\n        break;\n    case PH_MODULE_FLAGS_LOWIMAGECOHERENCY_OPTION:\n        Context->HideLowImageCoherency = !Context->HideLowImageCoherency;\n        break;\n    case PH_MODULE_FLAGS_HIGHLIGHT_LOWIMAGECOHERENCY_OPTION:\n        Context->HighlightLowImageCoherency = !Context->HighlightLowImageCoherency;\n        break;\n    case PH_MODULE_FLAGS_IMAGEKNOWNDLL_OPTION:\n        Context->HideImageKnownDll = !Context->HideImageKnownDll;\n        break;\n    case PH_MODULE_FLAGS_HIGHLIGHT_IMAGEKNOWNDLL:\n        Context->HighlightImageKnownDll = !Context->HighlightImageKnownDll;\n        break;\n    case PH_MODULE_FLAGS_ZERO_PAD_ADDRESSES:\n        Context->ZeroPadAddresses = !Context->ZeroPadAddresses;\n        break;\n    }\n}\n\nPPH_MODULE_NODE PhCreateModuleNode(\n    _Inout_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_ITEM ModuleItem,\n    _In_ ULONG RunId\n    )\n{\n    PPH_MODULE_NODE moduleNode;\n\n    moduleNode = PhAllocate(PhEmGetObjectSize(EmModuleNodeType, sizeof(PH_MODULE_NODE)));\n    memset(moduleNode, 0, sizeof(PH_MODULE_NODE));\n    PhInitializeTreeNewNode(&moduleNode->Node);\n\n    moduleNode->Children = PhCreateList(1);\n\n    if (Context->EnableStateHighlighting && RunId != 1)\n    {\n        PhChangeShStateTn(\n            &moduleNode->Node,\n            &moduleNode->ShState,\n            &Context->NodeStateList,\n            NewItemState,\n            PhCsColorNew,\n            NULL\n            );\n    }\n\n    moduleNode->ModuleItem = PhReferenceObject(ModuleItem);\n\n    memset(moduleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM);\n    moduleNode->Node.TextCache = moduleNode->TextCache;\n    moduleNode->Node.TextCacheSize = PHMOTLC_MAXIMUM;\n\n    PhAddEntryHashtable(Context->NodeHashtable, &moduleNode);\n    PhAddItemList(Context->NodeList, moduleNode);\n\n    if (Context->TreeFilterSupport.FilterList)\n        moduleNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &moduleNode->Node);\n\n    PhEmCallObjectOperation(EmModuleNodeType, moduleNode, EmObjectCreate);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    return moduleNode;\n}\n\nPPH_MODULE_NODE PhAddModuleNode(\n    _Inout_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_ITEM ModuleItem,\n    _In_ ULONG RunId\n    )\n{\n    PPH_MODULE_NODE moduleNode;\n    PPH_MODULE_NODE parentNode;\n    ULONG i;\n\n    moduleNode = PhCreateModuleNode(Context, ModuleItem, RunId);\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        parentNode = Context->NodeList->Items[i];\n\n        if (parentNode != moduleNode && parentNode->ModuleItem->BaseAddress == ModuleItem->ParentBaseAddress)\n        {\n            moduleNode->Parent = parentNode;\n            PhAddItemList(parentNode->Children, moduleNode);\n            break;\n        }\n    }\n\n    if (!moduleNode->Parent)\n    {\n        moduleNode->Node.Expanded = TRUE;\n        PhAddItemList(Context->NodeRootList, moduleNode);\n    }\n\n    return moduleNode;\n}\n\nPPH_MODULE_NODE PhFindModuleNode(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_ITEM ModuleItem\n    )\n{\n    PH_MODULE_NODE lookupModuleNode;\n    PPH_MODULE_NODE lookupModuleNodePtr = &lookupModuleNode;\n    PPH_MODULE_NODE *moduleNode;\n\n    lookupModuleNode.ModuleItem = ModuleItem;\n\n    moduleNode = (PPH_MODULE_NODE *)PhFindEntryHashtable(\n        Context->NodeHashtable,\n        &lookupModuleNodePtr\n        );\n\n    if (moduleNode)\n        return *moduleNode;\n    else\n        return NULL;\n}\n\nVOID PhRemoveModuleNode(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_NODE ModuleNode\n    )\n{\n    // Remove from the hashtable here to avoid problems in case the key is re-used.\n    PhRemoveEntryHashtable(Context->NodeHashtable, &ModuleNode);\n\n    if (Context->EnableStateHighlighting)\n    {\n        PhChangeShStateTn(\n            &ModuleNode->Node,\n            &ModuleNode->ShState,\n            &Context->NodeStateList,\n            RemovingItemState,\n            PhCsColorRemoved,\n            Context->TreeNewHandle\n            );\n    }\n    else\n    {\n        PhpRemoveModuleNode(ModuleNode, Context);\n    }\n}\n\nVOID PhpDestroyModuleNode(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_NODE ModuleNode\n    )\n{\n    ULONG index;\n\n    PhEmCallObjectOperation(EmModuleNodeType, ModuleNode, EmObjectDelete);\n\n    if (ModuleNode->Parent)\n    {\n        // Remove the node from its parent.\n\n        if ((index = PhFindItemList(ModuleNode->Parent->Children, ModuleNode)) != ULONG_MAX)\n            PhRemoveItemList(ModuleNode->Parent->Children, index);\n    }\n    else\n    {\n        // Remove the node from the root list.\n\n        if ((index = PhFindItemList(Context->NodeRootList, ModuleNode)) != ULONG_MAX)\n            PhRemoveItemList(Context->NodeRootList, index);\n    }\n\n    // Move the node's children to the root list.\n    for (index = 0; index < ModuleNode->Children->Count; index++)\n    {\n        PPH_MODULE_NODE node = ModuleNode->Children->Items[index];\n\n        node->Parent = NULL;\n        PhAddItemList(Context->NodeRootList, node);\n    }\n\n    PhClearReference(&ModuleNode->TooltipText);\n\n    if (ModuleNode->FileNameWin32) PhDereferenceObject(ModuleNode->FileNameWin32);\n    if (ModuleNode->SizeText) PhDereferenceObject(ModuleNode->SizeText);\n    if (ModuleNode->TimeStampText) PhDereferenceObject(ModuleNode->TimeStampText);\n    if (ModuleNode->LoadTimeText) PhDereferenceObject(ModuleNode->LoadTimeText);\n    if (ModuleNode->FileModifiedTimeText) PhDereferenceObject(ModuleNode->FileModifiedTimeText);\n    if (ModuleNode->FileSizeText) PhDereferenceObject(ModuleNode->FileSizeText);\n    if (ModuleNode->ImageCoherencyText) PhDereferenceObject(ModuleNode->ImageCoherencyText);\n    if (ModuleNode->ServiceText) PhDereferenceObject(ModuleNode->ServiceText);\n    if (ModuleNode->EnclaveSizeText) PhDereferenceObject(ModuleNode->EnclaveSizeText);\n\n    PhDereferenceObject(ModuleNode->ModuleItem);\n\n    PhFree(ModuleNode);\n}\n\nVOID PhpRemoveModuleNode(\n    _In_ PPH_MODULE_NODE ModuleNode,\n    _In_ PPH_MODULE_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after ModuleNode\n    )\n{\n    ULONG index;\n\n    // Remove from list and cleanup.\n\n    if ((index = PhFindItemList(Context->NodeList, ModuleNode)) != ULONG_MAX)\n        PhRemoveItemList(Context->NodeList, index);\n\n    PhpDestroyModuleNode(Context, ModuleNode);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhUpdateModuleNode(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ PPH_MODULE_NODE ModuleNode\n    )\n{\n    memset(ModuleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM);\n    PhClearReference(&ModuleNode->TooltipText);\n\n    ModuleNode->ValidMask = 0;\n    PhInvalidateTreeNewNode(&ModuleNode->Node, TN_CACHE_COLOR);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhInvalidateAllModuleNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MODULE_NODE moduleNode = Context->NodeList->Items[i];\n\n        memset(moduleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM);\n        moduleNode->ValidMask = 0;\n        PhInvalidateTreeNewNode(&moduleNode->Node, TN_CACHE_COLOR | TN_CACHE_FONT);\n    }\n\n    InvalidateRect(Context->TreeNewHandle, NULL, FALSE);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhInvalidateAllModuleBaseAddressNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MODULE_NODE moduleNode = Context->NodeList->Items[i];\n\n        if (Context->ZeroPadAddresses)\n        {\n            PhPrintPointerPadZeros(moduleNode->ModuleItem->BaseAddressString, moduleNode->ModuleItem->BaseAddress);\n            PhPrintPointerPadZeros(moduleNode->ModuleItem->EntryPointAddressString, moduleNode->ModuleItem->EntryPoint);\n            PhPrintPointerPadZeros(moduleNode->ModuleItem->ParentBaseAddressString, moduleNode->ModuleItem->ParentBaseAddress);\n            PhPrintPointerPadZeros(moduleNode->ModuleItem->EnclaveBaseAddressString, moduleNode->ModuleItem->EnclaveBaseAddress);\n        }\n        else\n        {\n            PhPrintPointer(moduleNode->ModuleItem->BaseAddressString, moduleNode->ModuleItem->BaseAddress);\n            PhPrintPointer(moduleNode->ModuleItem->EntryPointAddressString, moduleNode->ModuleItem->EntryPoint);\n            PhPrintPointer(moduleNode->ModuleItem->ParentBaseAddressString, moduleNode->ModuleItem->ParentBaseAddress);\n            PhPrintPointer(moduleNode->ModuleItem->EnclaveBaseAddressString, moduleNode->ModuleItem->EnclaveBaseAddress);\n        }\n\n        memset(moduleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM);\n        moduleNode->ValidMask = 0;\n        PhInvalidateTreeNewNode(&moduleNode->Node, TN_CACHE_COLOR);\n    }\n\n    InvalidateRect(Context->TreeNewHandle, NULL, FALSE);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhExpandAllModuleNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _In_ BOOLEAN Expand\n    )\n{\n    ULONG i;\n    BOOLEAN needsRestructure = FALSE;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MODULE_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Expanded != Expand)\n        {\n            node->Node.Expanded = Expand;\n            needsRestructure = TRUE;\n        }\n    }\n\n    if (needsRestructure)\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhTickModuleNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    )\n{\n    PH_TICK_SH_STATE_TN(PH_MODULE_NODE, ShState, Context->NodeStateList, PhpRemoveModuleNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context);\n}\n\n#define SORT_FUNCTION(Column) PhpModuleTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpModuleTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_MODULE_LIST_CONTEXT context = ((PPH_MODULE_LIST_CONTEXT)_context); \\\n    PPH_MODULE_NODE node1 = *(PPH_MODULE_NODE *)_elem1; \\\n    PPH_MODULE_NODE node2 = *(PPH_MODULE_NODE *)_elem2; \\\n    PPH_MODULE_ITEM moduleItem1 = node1->ModuleItem; \\\n    PPH_MODULE_ITEM moduleItem2 = node2->ModuleItem; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)moduleItem1->BaseAddress, (ULONG_PTR)moduleItem2->BaseAddress); \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)moduleItem1->EnclaveBaseAddress, (ULONG_PTR)moduleItem2->EnclaveBaseAddress); \\\n    if (sortResult == 0) \\\n        sortResult = PhCompareStringWithNullSortOrder(moduleItem1->FileName, moduleItem2->FileName, context->TreeNewSortOrder, FALSE); \\\n    \\\n    return PhModifySort(sortResult, context->TreeNewSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpModuleTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    if (Result == 0)\n        Result = uintptrcmp((ULONG_PTR)((PPH_MODULE_NODE)Node1)->ModuleItem->BaseAddress, (ULONG_PTR)((PPH_MODULE_NODE)Node2)->ModuleItem->BaseAddress);\n    if (Result == 0)\n        Result = uintptrcmp((ULONG_PTR)((PPH_MODULE_NODE)Node1)->ModuleItem->EnclaveBaseAddress, (ULONG_PTR)((PPH_MODULE_NODE)Node2)->ModuleItem->EnclaveBaseAddress);\n    if (Result == 0)\n        Result = PhCompareStringWithNullSortOrder(((PPH_MODULE_NODE)Node1)->ModuleItem->FileName, ((PPH_MODULE_NODE)Node2)->ModuleItem->FileName, SortOrder, FALSE);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(TriState)\n{\n    if (moduleItem1->IsFirst)\n    {\n        sortResult = -1;\n    }\n    else if (moduleItem2->IsFirst)\n    {\n        sortResult = 1;\n    }\n    else\n    {\n        sortResult = PhCompareStringWithNullSortOrder(moduleItem1->Name, moduleItem2->Name, context->TreeNewSortOrder, TRUE); // fall back to sorting by name\n    }\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareStringWithNullSortOrder(moduleItem1->Name, moduleItem2->Name, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(BaseAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)moduleItem1->BaseAddress, (ULONG_PTR)moduleItem2->BaseAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Size)\n{\n    sortResult = uintcmp(moduleItem1->Size, moduleItem2->Size);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Description)\n{\n    sortResult = PhCompareStringWithNullSortOrder(moduleItem1->VersionInfo.FileDescription, moduleItem2->VersionInfo.FileDescription, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CompanyName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(moduleItem1->VersionInfo.CompanyName, moduleItem2->VersionInfo.CompanyName, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Version)\n{\n    sortResult = PhCompareStringWithNullSortOrder(moduleItem1->VersionInfo.FileVersion, moduleItem2->VersionInfo.FileVersion, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(moduleItem1->FileName, moduleItem2->FileName, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Type)\n{\n    sortResult = uintcmp(moduleItem1->Type, moduleItem2->Type);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LoadCount)\n{\n    sortResult = uintcmp(moduleItem1->LoadCount, moduleItem2->LoadCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(VerificationStatus)\n{\n    sortResult = intcmp(moduleItem1->VerifyResult, moduleItem2->VerifyResult);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(VerifiedSigner)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        moduleItem1->VerifySignerName,\n        moduleItem2->VerifySignerName,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Aslr)\n{\n    sortResult = intcmp(\n        moduleItem1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE,\n        moduleItem2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(TimeStamp)\n{\n    sortResult = uintcmp(moduleItem1->ImageTimeDateStamp, moduleItem2->ImageTimeDateStamp);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CfGuard)\n{\n    // prefer XFG over CFG\n    sortResult = uintcmp(\n        moduleItem1->GuardFlags & IMAGE_GUARD_XFG_ENABLED,\n        moduleItem2->GuardFlags & IMAGE_GUARD_XFG_ENABLED\n        );\n\n    if (sortResult == 0)\n    {\n        sortResult = uintcmp(\n            moduleItem1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF,\n            moduleItem2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF\n            );\n    }\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LoadTime)\n{\n    sortResult = uint64cmp(moduleItem1->LoadTime.QuadPart, moduleItem2->LoadTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LoadReason)\n{\n    sortResult = uintcmp(moduleItem1->LoadReason, moduleItem2->LoadReason);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileModifiedTime)\n{\n    sortResult = int64cmp(moduleItem1->FileLastWriteTime.QuadPart, moduleItem2->FileLastWriteTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileSize)\n{\n    sortResult = int64cmp(moduleItem1->FileEndOfFile.QuadPart, moduleItem2->FileEndOfFile.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(EntryPoint)\n{\n    sortResult = uintptrcmp((ULONG_PTR)moduleItem1->EntryPoint, (ULONG_PTR)moduleItem2->EntryPoint);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ParentBaseAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)moduleItem1->ParentBaseAddress, (ULONG_PTR)moduleItem2->ParentBaseAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Cet)\n{\n    sortResult = uintcmp(\n        moduleItem1->ImageDllCharacteristicsEx & IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT,\n        moduleItem2->ImageDllCharacteristicsEx & IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ImageCoherency)\n{\n    sortResult = singlecmp(moduleItem1->ImageCoherency, moduleItem2->ImageCoherency);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(OriginalName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(moduleItem1->FileName, moduleItem2->FileName, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ServiceName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->ServiceText, node2->ServiceText, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(EnclaveType)\n{\n    sortResult = uintcmp(moduleItem1->EnclaveType, moduleItem2->EnclaveType);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(EnclaveBaseAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)moduleItem1->EnclaveBaseAddress, (ULONG_PTR)moduleItem2->EnclaveBaseAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(EnclaveSize)\n{\n    sortResult = uintptrcmp((ULONG_PTR)moduleItem1->EnclaveSize, (ULONG_PTR)moduleItem2->EnclaveSize);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Architecture)\n{\n    sortResult = uintcmp(moduleItem1->ImageMachine, moduleItem2->ImageMachine);\n    if (sortResult == 0)\n        sortResult = uintcmp(moduleItem1->ImageCHPEVersion, moduleItem2->ImageCHPEVersion);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpModuleTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_MODULE_LIST_CONTEXT context = Context;\n    PPH_MODULE_NODE node;\n\n    if (PhCmForwardMessage(WindowHandle, Message, Parameter1, Parameter2, &context->Cm))\n        return TRUE;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_MODULE_NODE)getChildren->Node;\n\n            if (context->TreeNewSortOrder == NoSortOrder)\n            {\n                if (!node)\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)context->NodeRootList->Items;\n                    getChildren->NumberOfChildren = context->NodeRootList->Count;\n                }\n                else\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;\n                    getChildren->NumberOfChildren = node->Children->Count;\n                }\n\n                qsort_s(getChildren->Children, getChildren->NumberOfChildren, sizeof(PVOID), SORT_FUNCTION(TriState), context);\n            }\n            else\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(Name),\n                    SORT_FUNCTION(BaseAddress),\n                    SORT_FUNCTION(Size),\n                    SORT_FUNCTION(Description),\n                    SORT_FUNCTION(CompanyName),\n                    SORT_FUNCTION(Version),\n                    SORT_FUNCTION(FileName),\n                    SORT_FUNCTION(Type),\n                    SORT_FUNCTION(LoadCount),\n                    SORT_FUNCTION(VerificationStatus),\n                    SORT_FUNCTION(VerifiedSigner),\n                    SORT_FUNCTION(Aslr),\n                    SORT_FUNCTION(TimeStamp),\n                    SORT_FUNCTION(CfGuard),\n                    SORT_FUNCTION(LoadTime),\n                    SORT_FUNCTION(LoadReason),\n                    SORT_FUNCTION(FileModifiedTime),\n                    SORT_FUNCTION(FileSize),\n                    SORT_FUNCTION(EntryPoint),\n                    SORT_FUNCTION(ParentBaseAddress),\n                    SORT_FUNCTION(Cet),\n                    SORT_FUNCTION(ImageCoherency),\n                    SORT_FUNCTION(LoadTime), // Timeline\n                    SORT_FUNCTION(OriginalName),\n                    SORT_FUNCTION(ServiceName),\n                    SORT_FUNCTION(EnclaveType),\n                    SORT_FUNCTION(EnclaveBaseAddress),\n                    SORT_FUNCTION(EnclaveSize),\n                    SORT_FUNCTION(Architecture),\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PHMOTLC_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (context->TreeNewSortOrder == NoSortOrder)\n                {\n                    sortFunction = SORT_FUNCTION(TriState);\n                }\n                else\n                {\n                    if (!PhCmForwardSort(\n                        (PPH_TREENEW_NODE *)context->NodeList->Items,\n                        context->NodeList->Count,\n                        context->TreeNewSortColumn,\n                        context->TreeNewSortOrder,\n                        &context->Cm\n                        ))\n                    {\n                        if (context->TreeNewSortColumn < PHMOTLC_MAXIMUM)\n                            sortFunction = sortFunctions[context->TreeNewSortColumn];\n                        else\n                            sortFunction = NULL;\n                    }\n                    else\n                    {\n                        sortFunction = NULL;\n                    }\n                }\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n            node = (PPH_MODULE_NODE)isLeaf->Node;\n\n            if (context->TreeNewSortOrder == NoSortOrder)\n                isLeaf->IsLeaf = node->Children->Count == 0;\n            else\n                isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            PPH_MODULE_ITEM moduleItem;\n\n            node = (PPH_MODULE_NODE)getCellText->Node;\n            moduleItem = node->ModuleItem;\n\n            switch (getCellText->Id)\n            {\n            case PHMOTLC_NAME:\n                {\n                    getCellText->Text = PhGetStringRef(moduleItem->Name);\n                }\n                break;\n            case PHMOTLC_BASEADDRESS:\n                {\n                    PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->BaseAddressString);\n                }\n                break;\n            case PHMOTLC_SIZE:\n                {\n                    PhMoveReference(&node->SizeText, PhFormatSize(moduleItem->Size, ULONG_MAX));\n                    getCellText->Text = PhGetStringRef(node->SizeText);\n                }\n                break;\n            case PHMOTLC_DESCRIPTION:\n                getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.FileDescription);\n                break;\n            case PHMOTLC_COMPANYNAME:\n                getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.CompanyName);\n                break;\n            case PHMOTLC_VERSION:\n                getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.FileVersion);\n                break;\n            case PHMOTLC_FILENAME:\n                {\n                    if (PhIsNullOrEmptyString(node->FileNameWin32))\n                    {\n                        PhMoveReference(&node->FileNameWin32, PhGetFileName(moduleItem->FileName));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->FileNameWin32);\n                }\n                break;\n            case PHMOTLC_TYPE:\n                {\n                    PCPH_STRINGREF string;\n\n                    if (string = PhGetModuleTypeName(moduleItem->Type))\n                    {\n                        getCellText->Text.Buffer = string->Buffer;\n                        getCellText->Text.Length = string->Length;\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHMOTLC_LOADCOUNT:\n                {\n                    if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE ||\n                        moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE)\n                    {\n                        if (moduleItem->LoadCount != USHRT_MAX)\n                        {\n                            PhPrintUInt32(node->LoadCountText, moduleItem->LoadCount);\n                            PhInitializeStringRefLongHint(&getCellText->Text, node->LoadCountText);\n                        }\n                        else\n                        {\n                            PhInitializeStringRef(&getCellText->Text, L\"Static\");\n                        }\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHMOTLC_VERIFICATIONSTATUS:\n                {\n                    if (PhEnableProcessQueryStage2)\n                    {\n                        if (moduleItem->Type != PH_MODULE_TYPE_ELF_MAPPED_IMAGE)\n                            getCellText->Text = PhVerifyResultToStringRef(moduleItem->VerifyResult);\n                        else\n                            PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                    else\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Image digital signature support disabled.\");\n                    }\n                }\n                break;\n            case PHMOTLC_VERIFIEDSIGNER:\n                {\n                    if (PhEnableProcessQueryStage2)\n                        getCellText->Text = PhGetStringRef(moduleItem->VerifySignerName);\n                    else\n                        PhInitializeStringRef(&getCellText->Text, L\"Image digital signature support disabled.\");\n                }\n                break;\n            case PHMOTLC_ASLR:\n                {\n                    if (FlagOn(moduleItem->ImageDllCharacteristics, IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE))\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"ASLR\");\n                    }\n                }\n                break;\n            case PHMOTLC_TIMESTAMP:\n                {\n                    LARGE_INTEGER time;\n                    SYSTEMTIME systemTime;\n\n                    if (moduleItem->ImageTimeDateStamp != 0)\n                    {\n                        PhSecondsSince1970ToTime(moduleItem->ImageTimeDateStamp, &time);\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &time);\n                        PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = node->TimeStampText->sr;\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHMOTLC_CFGUARD:\n                {\n                    if (FlagOn(moduleItem->ImageDllCharacteristics, IMAGE_DLLCHARACTERISTICS_GUARD_CF))\n                    {\n                        if (FlagOn(moduleItem->GuardFlags, IMAGE_GUARD_XFG_ENABLED))\n                            PhInitializeStringRef(&getCellText->Text, L\"XF Guard\");\n                        else\n                            PhInitializeStringRef(&getCellText->Text, L\"CF Guard\");\n                    }\n                }\n                break;\n            case PHMOTLC_LOADTIME:\n                {\n                    SYSTEMTIME systemTime;\n\n                    if (moduleItem->LoadTime.QuadPart != 0)\n                    {\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &moduleItem->LoadTime);\n                        PhMoveReference(&node->LoadTimeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = node->LoadTimeText->sr;\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHMOTLC_LOADREASON:\n                {\n                    if (moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Dynamic\");\n                    }\n                    else if (moduleItem->Type == PH_MODULE_TYPE_MODULE ||\n                             moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE ||\n                             moduleItem->Type == PH_MODULE_TYPE_ENCLAVE_MODULE)\n                    {\n                        PCPH_STRINGREF string;\n\n                        if (string = PhGetModuleLoadReasonTypeName(moduleItem->LoadReason))\n                        {\n                            getCellText->Text.Buffer = string->Buffer;\n                            getCellText->Text.Length = string->Length;\n                        }\n                        else\n                        {\n                            PhInitializeEmptyStringRef(&getCellText->Text);\n                        }\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHMOTLC_FILEMODIFIEDTIME:\n                {\n                    if (moduleItem->FileLastWriteTime.QuadPart != 0 && moduleItem->FileLastWriteTime.QuadPart != -1)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &moduleItem->FileLastWriteTime);\n                        PhMoveReference(&node->FileModifiedTimeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = node->FileModifiedTimeText->sr;\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHMOTLC_FILESIZE:\n                {\n                    if (moduleItem->FileEndOfFile.QuadPart != 0 && moduleItem->FileEndOfFile.QuadPart != -1)\n                    {\n                        PhMoveReference(&node->FileSizeText, PhFormatSize(moduleItem->FileEndOfFile.QuadPart, ULONG_MAX));\n                        getCellText->Text = PhGetStringRef(node->FileSizeText);\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHMOTLC_ENTRYPOINT:\n                {\n                    if (moduleItem->EntryPoint)\n                    {\n                        PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->EntryPointAddressString);\n                    }\n                }\n                break;\n            case PHMOTLC_PARENTBASEADDRESS:\n                {\n                    if (moduleItem->ParentBaseAddress)\n                    {\n                        PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->ParentBaseAddressString);\n                    }\n                }\n                break;\n            case PHMOTLC_CET:\n                {\n                    if (FlagOn(moduleItem->ImageDllCharacteristicsEx, IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT))\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"CET\");\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHMOTLC_COHERENCY:\n                {\n                    if (!PhEnableImageCoherencySupport)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Image coherency support is disabled.\");\n                        break;\n                    }\n\n                    if (moduleItem->Type == PH_MODULE_TYPE_MODULE ||\n                        moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE ||\n                        moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE ||\n                        moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE)\n                    {\n                        PH_FORMAT format[2];\n\n                        if (moduleItem->ImageCoherencyStatus == LONG_MAX)\n                            break;\n\n                        if (moduleItem->ImageCoherencyStatus == STATUS_PENDING)\n                        {\n                            PhInitializeStringRef(&getCellText->Text, L\"Scanning....\");\n                            break;\n                        }\n\n                        if (!PhShouldShowModuleCoherency(moduleItem, FALSE))\n                        {\n                            if (moduleItem->ImageCoherencyStatus != STATUS_SUCCESS)\n                            {\n                                PhMoveReference(&node->ImageCoherencyText, PhGetStatusMessage(moduleItem->ImageCoherencyStatus, 0));\n                                getCellText->Text = PhGetStringRef(node->ImageCoherencyText);\n                            }\n                            break;\n                        }\n\n                        if (moduleItem->ImageCoherency == 1.0f)\n                        {\n                            PhInitializeStringRef(&getCellText->Text, L\"100%\");\n                            break;\n                        }\n                        if (moduleItem->ImageCoherency > 0.9999f)\n                        {\n                            PhInitializeStringRef(&getCellText->Text, L\">99.99%\");\n                            break;\n                        }\n\n                        PhInitFormatF(&format[0], moduleItem->ImageCoherency * 100.0f, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[1], L\"%\");\n\n                        PhMoveReference(&node->ImageCoherencyText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                        getCellText->Text = PhGetStringRef(node->ImageCoherencyText);\n                    }\n                }\n                break;\n            case PHMOTLC_ORIGINALNAME:\n                {\n                    getCellText->Text = PhGetStringRef(moduleItem->FileName);\n                }\n                break;\n            case PHMOTLC_SERVICE:\n                {\n                    if (PhIsNullOrEmptyString(node->FileNameWin32))\n                    {\n                        PhMoveReference(&node->FileNameWin32, PhGetFileName(moduleItem->FileName));\n                    }\n\n                    if (node->FileNameWin32 && context->HasServices)\n                    {\n                        PhMoveReference(&node->ServiceText, PhGetServiceNameForModuleReference(\n                            context->ProcessId,\n                            PhGetString(node->FileNameWin32)\n                            ));\n                        getCellText->Text = PhGetStringRef(node->ServiceText);\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHMOTLC_ENCLAVE_TYPE:\n                {\n                    if (moduleItem->EnclaveBaseAddress)\n                    {\n                        PCPH_STRINGREF string;\n\n                        if (string = PhGetModuleEnclaveTypeName(moduleItem->EnclaveType))\n                        {\n                            getCellText->Text.Buffer = string->Buffer;\n                            getCellText->Text.Length = string->Length;\n                        }\n                        else\n                        {\n                            PhInitializeEmptyStringRef(&getCellText->Text);\n                        }\n                    }\n                }\n                break;\n            case PHMOTLC_ENCLAVE_BASE_ADDRESS:\n                {\n                    if (moduleItem->EnclaveBaseAddress)\n                    {\n                        PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->EnclaveBaseAddressString);\n                    }\n                }\n                break;\n            case PHMOTLC_ENCLAVE_SIZE:\n                {\n                    if (moduleItem->EnclaveBaseAddress)\n                    {\n                        if (PhIsNullOrEmptyString(node->EnclaveSizeText))\n                        {\n                            PhMoveReference(&node->EnclaveSizeText, PhFormatSize(moduleItem->EnclaveSize, ULONG_MAX));\n                        }\n\n                        getCellText->Text = PhGetStringRef(node->EnclaveSizeText);\n                    }\n                }\n                break;\n            case PHMOTLC_ARCHITECTURE:\n                {\n                    // We read the remote process memory for ImageMachine when possible. For\n                    // ARM64X/CHPE the OS will fix up the image header in the process, this\n                    // should generally reflect the module machine correctly (unless we can't\n                    // read the remote process address space).\n                    switch (node->ModuleItem->ImageMachine)\n                    {\n                    case IMAGE_FILE_MACHINE_I386:\n                        PhInitializeStringRef(&getCellText->Text, node->ModuleItem->ImageCHPEVersion ? L\"x86 (CHPE)\" : L\"x86\");\n                        break;\n                    case IMAGE_FILE_MACHINE_AMD64:\n                        PhInitializeStringRef(&getCellText->Text, node->ModuleItem->ImageCHPEVersion ? L\"x64 (ARM64X)\" : L\"x64\");\n                        break;\n                    case IMAGE_FILE_MACHINE_ARMNT:\n                        PhInitializeStringRef(&getCellText->Text, L\"ARM\");\n                        break;\n                    case IMAGE_FILE_MACHINE_ARM64:\n                        PhInitializeStringRef(&getCellText->Text, node->ModuleItem->ImageCHPEVersion ? L\"ARM64 (ARM64X)\" : L\"ARM64\");\n                        break;\n                    default:\n                        break;\n                    }\n                }\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            PPH_MODULE_ITEM moduleItem;\n\n            node = (PPH_MODULE_NODE)getNodeColor->Node;\n            moduleItem = node->ModuleItem;\n\n            if (!moduleItem)\n                ; // Dummy\n            else if (PhEnableProcessQueryStage2 &&\n                context->HighlightUntrustedModules &&\n                PH_VERIFY_UNTRUSTED(moduleItem->VerifyResult) &&\n                (moduleItem->Type == PH_MODULE_TYPE_MODULE ||\n                moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE ||\n                moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE ||\n                moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE))\n            {\n                getNodeColor->BackColor = PhCsColorUnknown;\n            }\n            else if (PhEnableImageCoherencySupport && context->HighlightLowImageCoherency && PhShouldShowModuleCoherency(moduleItem, TRUE))\n                getNodeColor->BackColor = PhCsColorLowImageCoherency;\n            else if (context->HighlightDotNetModules && FlagOn(moduleItem->Flags, LDRP_COR_IMAGE))\n                getNodeColor->BackColor = PhCsColorDotNet;\n            else if (context->HighlightImmersiveModules && FlagOn(moduleItem->ImageDllCharacteristics, IMAGE_DLLCHARACTERISTICS_APPCONTAINER))\n                getNodeColor->BackColor = PhCsColorImmersiveProcesses;\n            else if (context->HighlightRelocatedModules && moduleItem->ImageNotAtBase)\n                getNodeColor->BackColor = PhCsColorRelocatedModules;\n            else if (context->HighlightImageKnownDll && moduleItem->ImageKnownDll)\n                getNodeColor->BackColor = PhCsColorElevatedProcesses;\n            else if (PhEnableProcessQueryStage2 &&\n                context->HighlightSystemModules &&\n                moduleItem->VerifyResult == VrTrusted &&\n                PhEqualStringRef2(&moduleItem->VerifySignerName->sr, L\"Microsoft Windows\", TRUE)\n                )\n            {\n                getNodeColor->BackColor = PhCsColorSystemProcesses;\n            }\n\n            getNodeColor->Flags = TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewGetNodeFont:\n        {\n            PPH_TREENEW_GET_NODE_FONT getNodeFont = Parameter1;\n            node = (PPH_MODULE_NODE)getNodeFont->Node;\n\n            // Make the executable file module item bold.\n            if (node->ModuleItem->IsFirst)\n            {\n                getNodeFont->Font = context->BoldFont ? context->BoldFont : NULL;\n                getNodeFont->Flags = TN_CACHE;\n                return TRUE;\n            }\n        }\n        break;\n    case TreeNewGetCellTooltip:\n        {\n            PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;\n            node = (PPH_MODULE_NODE)getCellTooltip->Node;\n\n            if (getCellTooltip->Column->Id != 0)\n                return FALSE;\n\n            if (!node->TooltipText)\n            {\n                if (PhIsNullOrEmptyString(node->FileNameWin32))\n                {\n                    PhMoveReference(&node->FileNameWin32, PhGetFileName(node->ModuleItem->FileName));\n                }\n\n                node->TooltipText = PhFormatImageVersionInfo(\n                    node->FileNameWin32,\n                    &node->ModuleItem->VersionInfo,\n                    NULL,\n                    0\n                    );\n\n                // Make sure we don't try to create the tooltip text again.\n                if (!node->TooltipText)\n                    node->TooltipText = PhReferenceEmptyString();\n            }\n\n            if (!PhIsNullOrEmptyString(node->TooltipText))\n            {\n                getCellTooltip->Text = node->TooltipText->sr;\n                getCellTooltip->Unfolding = FALSE;\n                getCellTooltip->Font = NULL; // use default font\n                getCellTooltip->MaximumWidth = 550;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case TreeNewCustomDraw:\n        {\n            PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;\n            PPH_MODULE_ITEM moduleItem;\n            RECT rect;\n\n            node = (PPH_MODULE_NODE)customDraw->Node;\n            moduleItem = node->ModuleItem;\n            rect = customDraw->CellRect;\n\n            if (rect.right - rect.left <= 1)\n                break; // nothing to draw\n\n            switch (customDraw->Column->Id)\n            {\n            case PHMOTLC_TIMELINE:\n                {\n                    if (moduleItem->LoadTime.QuadPart == 0)\n                        break; // nothing to draw\n\n                    PhCustomDrawTreeTimeLine(\n                        customDraw->Dc,\n                        &customDraw->CellRect,\n                        PhEnableThemeSupport ? PH_DRAW_TIMELINE_DARKTHEME : 0,\n                        &context->ProcessCreateTime,\n                        &moduleItem->LoadTime\n                        );\n                }\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_COPY, 0);\n                break;\n            case VK_DELETE:\n                SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_UNLOAD, 0);\n                break;\n            case VK_RETURN:\n                if (GetKeyState(VK_CONTROL) >= 0)\n                    SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_PROPERTIES, 0);\n                else\n                    SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_OPENFILELOCATION, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = 0;\n            data.DefaultSortOrder = NoSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_PROPERTIES, 0);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n\n            SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu);\n        }\n        return TRUE;\n    case TreeNewGetDialogCode:\n        {\n            PULONG code = Parameter2;\n\n            if (PtrToUlong(Parameter1) == VK_RETURN)\n            {\n                *code = DLGC_WANTMESSAGE;\n                return TRUE;\n            }\n        }\n        return FALSE;\n    }\n\n    return FALSE;\n}\n\nPPH_MODULE_ITEM PhGetSelectedModuleItem(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    )\n{\n    PPH_MODULE_ITEM moduleItem = NULL;\n    ULONG i;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MODULE_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            moduleItem = node->ModuleItem;\n            break;\n        }\n    }\n\n    return moduleItem;\n}\n\nVOID PhGetSelectedModuleItems(\n    _In_ PPH_MODULE_LIST_CONTEXT Context,\n    _Out_ PPH_MODULE_ITEM **Modules,\n    _Out_ PULONG NumberOfModules\n    )\n{\n    PH_ARRAY array;\n    ULONG i;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MODULE_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n            PhAddItemArray(&array, &node->ModuleItem);\n    }\n\n    *NumberOfModules = (ULONG)PhFinalArrayCount(&array);\n    *Modules = PhFinalArrayItems(&array);\n}\n\nVOID PhDeselectAllModuleNodes(\n    _In_ PPH_MODULE_LIST_CONTEXT Context\n    )\n{\n    TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1);\n}\n\n// Copied from proctree.c (dmex)\nconst FLOAT LowImageCoherencyThreshold = 0.5f;\n\nBOOLEAN PhShouldShowModuleCoherency(\n    _In_ PPH_MODULE_ITEM ModuleItem,\n    _In_ BOOLEAN CheckThreshold\n    )\n{\n    if (PhCsImageCoherencyScanLevel == 0)\n    {\n        //\n        // The advanced option for the image coherency scan level is 0.\n        // This disables the scanning and we should not show the image\n        // coherency.\n        //\n        return FALSE;\n    }\n\n    if (ModuleItem->ImageCoherencyStatus == STATUS_PENDING ||\n        ModuleItem->ImageCoherencyStatus == LONG_MAX ||\n        PhIsNullOrEmptyString(ModuleItem->FileName))\n    {\n        //\n        // The image coherency status is pending, uninitialized, or we don't\n        // have a file name for the module. We have not completed/attempted\n        // the calculation yet, don't show the coherency.\n        //\n        return FALSE;\n    }\n\n    if (!(ModuleItem->Type == PH_MODULE_TYPE_MODULE ||\n        ModuleItem->Type == PH_MODULE_TYPE_WOW64_MODULE ||\n        ModuleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE ||\n        ModuleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE))\n    {\n        //\n        // We special case these modules types and opt not to show/calculate\n        // the coherency for them.\n        //\n        return FALSE;\n    }\n\n    if (NT_SUCCESS(ModuleItem->ImageCoherencyStatus) ||\n        ModuleItem->ImageCoherencyStatus == STATUS_INVALID_IMAGE_NOT_MZ ||\n        ModuleItem->ImageCoherencyStatus == STATUS_INVALID_IMAGE_FORMAT ||\n        ModuleItem->ImageCoherencyStatus == STATUS_INVALID_IMAGE_HASH ||\n        ModuleItem->ImageCoherencyStatus == STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT)\n    {\n        //\n        // The coherency status is a success code or a known \"valid\" error\n        // from the coherency calculation (PhGetProcessModuleImageCoherency).\n        // We should show the coherency value.\n        //\n\n        if (CheckThreshold)\n        {\n            //\n            // A threshold check is requested. This is generally used for\n            // checking if we should highlight an entry. If the coherency\n            // is below a given threshold return true. Otherwise false.\n            //\n            if (ModuleItem->ImageCoherency <= LowImageCoherencyThreshold)\n            {\n                return TRUE;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n\n        //\n        // No special handling, return true.\n        //\n        return TRUE;\n    }\n\n    //\n    // Any other error NTSTATUS we don't show the coherency value, we'll\n    // show the reason why we failed the calculation (a string representation\n    // of the status code).\n    //\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/modprv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <modprv.h>\n\n#include <mapimg.h>\n#include <kphuser.h>\n#include <workqueue.h>\n\n#include <extmgri.h>\n#include <procprv.h>\n#include <phsettings.h>\n\n#include <symprv.h>\n#include <appsup.h>\n#include <mapldr.h>\n\ntypedef struct _PH_MODULE_QUERY_DATA\n{\n    SLIST_ENTRY ListEntry;\n    PPH_MODULE_PROVIDER ModuleProvider;\n    PPH_MODULE_ITEM ModuleItem;\n\n    VERIFY_RESULT VerifyResult;\n    PPH_STRING VerifySignerName;\n    ULONG ImageFlags;\n    ULONG GuardFlags;\n    BOOLEAN ImageKnownDll;\n\n    NTSTATUS ImageCoherencyStatus;\n    FLOAT ImageCoherency;\n} PH_MODULE_QUERY_DATA, *PPH_MODULE_QUERY_DATA;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpModuleProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpModuleItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PhpModuleHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpModuleHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhModuleEnclaveListInitialize(\n    _In_ PVOID ThreadParameter\n    );\n\nNTSTATUS PhEnumGenericEnclaveModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID Context\n    );\n\nPPH_OBJECT_TYPE PhModuleProviderType = NULL;\nPPH_OBJECT_TYPE PhModuleItemType = NULL;\nPVOID PhLdrEnclaveList = NULL;\n\nPPH_MODULE_PROVIDER PhCreateModuleProvider(\n    _In_ HANDLE ProcessId\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_MODULE_PROVIDER moduleProvider;\n    PPH_PROCESS_ITEM processItem;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhModuleProviderType = PhCreateObjectType(L\"ModuleProvider\", 0, PhpModuleProviderDeleteProcedure);\n        PhModuleItemType = PhCreateObjectType(L\"ModuleItem\", 0, PhpModuleItemDeleteProcedure);\n\n        if (WindowsVersion >= WINDOWS_10)\n        {\n            PhQueueUserWorkItem(PhModuleEnclaveListInitialize, NULL);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    moduleProvider = PhCreateObject(\n        PhEmGetObjectSize(EmModuleProviderType, sizeof(PH_MODULE_PROVIDER)),\n        PhModuleProviderType\n        );\n    memset(moduleProvider, 0, sizeof(PH_MODULE_PROVIDER));\n\n    moduleProvider->ModuleHashtable = PhCreateHashtable(\n        sizeof(PPH_MODULE_ITEM),\n        PhpModuleHashtableEqualFunction,\n        PhpModuleHashtableHashFunction,\n        20\n        );\n    PhInitializeFastLock(&moduleProvider->ModuleHashtableLock);\n\n    PhInitializeCallback(&moduleProvider->ModuleAddedEvent);\n    PhInitializeCallback(&moduleProvider->ModuleModifiedEvent);\n    PhInitializeCallback(&moduleProvider->ModuleRemovedEvent);\n    PhInitializeCallback(&moduleProvider->UpdatedEvent);\n\n    moduleProvider->ProcessId = ProcessId;\n    moduleProvider->ProcessHandle = NULL;\n    moduleProvider->ProcessFileName = NULL;\n    moduleProvider->PackageFullName = NULL;\n    moduleProvider->RunStatus = STATUS_SUCCESS;\n\n    if (PH_IS_REAL_PROCESS_ID(ProcessId))\n    {\n        static const ACCESS_MASK accesses[] =\n        {\n            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, // Try to get a handle with query information + vm read access. (wj32)\n            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, // Try to get a handle with query limited information + vm read access. (wj32)\n            PROCESS_QUERY_LIMITED_INFORMATION, // Try to get a handle with query limited information (required for WSL) (dmex)\n        };\n\n        // It doesn't matter if we can't get a process handle.\n\n        for (ULONG i = 0; i < RTL_NUMBER_OF(accesses); i++)\n        {\n            moduleProvider->RunStatus = PhOpenProcess(\n                &moduleProvider->ProcessHandle,\n                accesses[i],\n                ProcessId\n                );\n\n            if (NT_SUCCESS(moduleProvider->RunStatus))\n            {\n                moduleProvider->IsHandleValid = TRUE;\n                break;\n            }\n        }\n    }\n\n    if (processItem = PhReferenceProcessItem(ProcessId))\n    {\n        PhSetReference(&moduleProvider->ProcessFileName, processItem->FileName);\n        PhSetReference(&moduleProvider->PackageFullName, processItem->PackageFullName);\n        moduleProvider->IsSubsystemProcess = !!processItem->IsSubsystemProcess;\n        PhDereferenceObject(processItem);\n    }\n\n    if (WindowsVersion >= WINDOWS_8_1 && moduleProvider->ProcessHandle)\n    {\n        BOOLEAN cfguardEnabled;\n\n        if (NT_SUCCESS(PhGetProcessIsCFGuardEnabled(moduleProvider->ProcessHandle, &cfguardEnabled)))\n        {\n            moduleProvider->ControlFlowGuardEnabled = cfguardEnabled;\n        }\n    }\n\n    if (WindowsVersion >= WINDOWS_10_20H1 && moduleProvider->ProcessHandle)\n    {\n        if (moduleProvider->ProcessId == SYSTEM_PROCESS_ID)\n        {\n            SYSTEM_SHADOW_STACK_INFORMATION shadowStackInformation;\n\n            if (NT_SUCCESS(PhGetSystemShadowStackInformation(&shadowStackInformation)))\n            {\n                moduleProvider->CetEnabled = !!shadowStackInformation.KernelCetEnabled;\n                moduleProvider->CetStrictModeEnabled = TRUE; // Kernel CET is always strict (TheEragon)\n            }\n        }\n        else\n        {\n            BOOLEAN cetEnabled;\n            BOOLEAN cetStrictModeEnabled;\n\n            if (NT_SUCCESS(PhGetProcessIsCetEnabled(moduleProvider->ProcessHandle, &cetEnabled, &cetStrictModeEnabled)))\n            {\n                moduleProvider->CetEnabled = cetEnabled;\n                moduleProvider->CetStrictModeEnabled = cetStrictModeEnabled;\n            }\n        }\n    }\n\n    switch (PhCsImageCoherencyScanLevel)\n    {\n    case 1:\n        moduleProvider->ImageCoherencyScanLevel = PhImageCoherencyQuick;\n        break;\n    case 2:\n        moduleProvider->ImageCoherencyScanLevel = PhImageCoherencyNormal;\n        break;\n    case 3:\n    default:\n        moduleProvider->ImageCoherencyScanLevel = PhImageCoherencyFull;\n        break;\n    case 4:\n        moduleProvider->ImageCoherencyScanLevel = PhImageCoherencySharedOriginal;\n        break;\n    }\n\n    PhInitializeSListHead(&moduleProvider->QueryListHead);\n\n    PhEmCallObjectOperation(EmModuleProviderType, moduleProvider, EmObjectCreate);\n\n    return moduleProvider;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpModuleProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_MODULE_PROVIDER moduleProvider = (PPH_MODULE_PROVIDER)Object;\n\n    PhEmCallObjectOperation(EmModuleProviderType, moduleProvider, EmObjectDelete);\n\n    // Dereference all module items (we referenced them\n    // when we added them to the hashtable).\n    PhDereferenceAllModuleItems(moduleProvider);\n\n    PhDereferenceObject(moduleProvider->ModuleHashtable);\n    PhDeleteFastLock(&moduleProvider->ModuleHashtableLock);\n    PhDeleteCallback(&moduleProvider->ModuleAddedEvent);\n    PhDeleteCallback(&moduleProvider->ModuleModifiedEvent);\n    PhDeleteCallback(&moduleProvider->ModuleRemovedEvent);\n    PhDeleteCallback(&moduleProvider->UpdatedEvent);\n\n    // Destroy all queue items.\n    {\n        PSLIST_ENTRY entry;\n        PPH_MODULE_QUERY_DATA data;\n\n        entry = RtlInterlockedFlushSList(&moduleProvider->QueryListHead);\n\n        while (entry)\n        {\n            data = CONTAINING_RECORD(entry, PH_MODULE_QUERY_DATA, ListEntry);\n            entry = entry->Next;\n\n            if (data->VerifySignerName) PhDereferenceObject(data->VerifySignerName);\n            PhDereferenceObject(data->ModuleItem);\n            PhFree(data);\n        }\n    }\n\n    if (moduleProvider->ProcessFileName) PhDereferenceObject(moduleProvider->ProcessFileName);\n    if (moduleProvider->PackageFullName) PhDereferenceObject(moduleProvider->PackageFullName);\n    if (moduleProvider->ProcessHandle) NtClose(moduleProvider->ProcessHandle);\n}\n\nPPH_MODULE_ITEM PhCreateModuleItem(\n    VOID\n    )\n{\n    PPH_MODULE_ITEM moduleItem;\n\n    moduleItem = PhCreateObject(\n        PhEmGetObjectSize(EmModuleItemType, sizeof(PH_MODULE_ITEM)),\n        PhModuleItemType\n        );\n    memset(moduleItem, 0, sizeof(PH_MODULE_ITEM));\n    PhEmCallObjectOperation(EmModuleItemType, moduleItem, EmObjectCreate);\n\n    //\n    // Initialize ImageCoherencyStatus to STATUS_PENDING this notes that the\n    // image coherency hasn't been done yet. This prevents the module items\n    // from being noted as \"Low Image Coherency\" or being highlighted until\n    // the analysis runs. See: PhShouldShowModuleCoherency\n    //\n    moduleItem->ImageCoherencyStatus = STATUS_PENDING;\n\n    return moduleItem;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpModuleItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)Object;\n\n    PhEmCallObjectOperation(EmModuleItemType, moduleItem, EmObjectDelete);\n\n    if (moduleItem->Name) PhDereferenceObject(moduleItem->Name);\n    if (moduleItem->FileName) PhDereferenceObject(moduleItem->FileName);\n    if (moduleItem->VerifySignerName) PhDereferenceObject(moduleItem->VerifySignerName);\n    PhDeleteImageVersionInfo(&moduleItem->VersionInfo);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PhpModuleHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_MODULE_ITEM entry1 = *(PPH_MODULE_ITEM *)Entry1;\n    PPH_MODULE_ITEM entry2 = *(PPH_MODULE_ITEM *)Entry2;\n\n    if (entry1->FileName && entry2->FileName)\n    {\n        return ((entry1->BaseAddress == entry2->BaseAddress) &&\n                (entry1->EnclaveBaseAddress == entry2->EnclaveBaseAddress) &&\n                PhEqualString(entry1->FileName, entry2->FileName, FALSE));\n    }\n    else\n    {\n        return ((entry1->BaseAddress == entry2->BaseAddress) &&\n                (entry1->EnclaveBaseAddress == entry2->EnclaveBaseAddress));\n    }\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpModuleHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_MODULE_ITEM entry = *(PPH_MODULE_ITEM *)Entry;\n    ULONG baseAddressHash = PhHashIntPtr((ULONG_PTR)entry->BaseAddress);\n    ULONG enclaveBaseAddressHash = PhHashIntPtr((ULONG_PTR)entry->EnclaveBaseAddress);\n\n    return baseAddressHash ^ (enclaveBaseAddressHash << 1);\n}\n\nPPH_MODULE_ITEM PhReferenceModuleItemEx(\n    _In_ PPH_MODULE_PROVIDER ModuleProvider,\n    _In_ PVOID BaseAddress,\n    _In_opt_ PVOID EnclaveBaseAddress,\n    _In_opt_ PPH_STRING FileName\n    )\n{\n    PH_MODULE_ITEM lookupModuleItem;\n    PPH_MODULE_ITEM lookupModuleItemPtr = &lookupModuleItem;\n    PPH_MODULE_ITEM *moduleItemPtr;\n    PPH_MODULE_ITEM moduleItem;\n\n    lookupModuleItem.BaseAddress = BaseAddress;\n    lookupModuleItem.EnclaveBaseAddress = EnclaveBaseAddress;\n    lookupModuleItem.FileName = FileName;\n\n    PhAcquireFastLockShared(&ModuleProvider->ModuleHashtableLock);\n\n    moduleItemPtr = (PPH_MODULE_ITEM *)PhFindEntryHashtable(\n        ModuleProvider->ModuleHashtable,\n        &lookupModuleItemPtr\n        );\n\n    if (moduleItemPtr)\n    {\n        moduleItem = *moduleItemPtr;\n        PhReferenceObject(moduleItem);\n    }\n    else\n    {\n        moduleItem = NULL;\n    }\n\n    PhReleaseFastLockShared(&ModuleProvider->ModuleHashtableLock);\n\n    return moduleItem;\n}\n\nPPH_MODULE_ITEM PhReferenceModuleItem(\n    _In_ PPH_MODULE_PROVIDER ModuleProvider,\n    _In_ PVOID BaseAddress\n    )\n{\n    return PhReferenceModuleItemEx(\n        ModuleProvider,\n        BaseAddress,\n        NULL,\n        NULL\n        );\n}\n\nVOID PhDereferenceAllModuleItems(\n    _In_ PPH_MODULE_PROVIDER ModuleProvider\n    )\n{\n    ULONG enumerationKey = 0;\n    PPH_MODULE_ITEM *moduleItem;\n\n    PhAcquireFastLockExclusive(&ModuleProvider->ModuleHashtableLock);\n\n    while (PhEnumHashtable(ModuleProvider->ModuleHashtable, (PVOID *)&moduleItem, &enumerationKey))\n    {\n        PhDereferenceObject(*moduleItem);\n    }\n\n    PhReleaseFastLockExclusive(&ModuleProvider->ModuleHashtableLock);\n}\n\nVOID PhpRemoveModuleItem(\n    _In_ PPH_MODULE_PROVIDER ModuleProvider,\n    _In_ PPH_MODULE_ITEM ModuleItem\n    )\n{\n    PhRemoveEntryHashtable(ModuleProvider->ModuleHashtable, &ModuleItem);\n    PhDereferenceObject(ModuleItem);\n}\n\n_Function_class_(PH_READ_VIRTUAL_MEMORY_CALLBACK)\nstatic NTSTATUS PhModuleItemReadVirtualMemoryCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)Context;\n    if (!moduleItem) return STATUS_INVALID_PARAMETER_6;\n\n    if (moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE)\n        return KphReadVirtualMemory(ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead);\n    return PhReadVirtualMemory(ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpModuleQueryWorker(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_MODULE_QUERY_DATA data = (PPH_MODULE_QUERY_DATA)Parameter;\n    PPH_MODULE_PROVIDER moduleProvider = data->ModuleProvider;\n    PPH_MODULE_ITEM moduleItem = data->ModuleItem;\n\n    if (PhEnableProcessQueryStage2)\n    {\n        data->VerifyResult = PhVerifyFileCached(\n            moduleItem->FileName,\n            moduleProvider->PackageFullName,\n            &data->VerifySignerName,\n            TRUE,\n            FALSE\n            );\n    }\n\n    if (moduleProvider->IsHandleValid && !moduleProvider->IsSubsystemProcess)\n    {\n        if (\n            moduleItem->Type == PH_MODULE_TYPE_MODULE ||\n            moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE ||\n            moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE ||\n            moduleItem->Type == PH_MODULE_TYPE_ENCLAVE_MODULE ||\n            (moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE &&\n            (KsiLevel() == KphLevelMax)))\n        {\n            PH_REMOTE_MAPPED_IMAGE remoteMappedImage;\n\n            PhInitializeRemoteMappedImage(\n                &remoteMappedImage,\n                PhModuleItemReadVirtualMemoryCallback,\n                moduleItem\n                );\n\n            // Note:\n            // On Windows 7 the LDRP_IMAGE_NOT_AT_BASE flag doesn't appear to be used\n            // anymore. Instead we'll check ImageBase in the image headers. We read this in\n            // from the process' memory because:\n            //\n            // 1. It (should be) faster than opening the file and mapping it in, and\n            // 2. It contains the correct original image base relocated by ASLR, if present.\n\n            if (NT_SUCCESS(PhLoadRemoteMappedImage(\n                &remoteMappedImage,\n                moduleProvider->ProcessHandle,\n                moduleItem->BaseAddress,\n                moduleItem->Size\n                )))\n            {\n                PIMAGE_DATA_DIRECTORY dataDirectory;\n                PVOID imageBase = 0;\n                ULONG entryPoint = 0;\n                ULONG debugEntryLength;\n                PVOID debugEntry;\n\n                __try\n                {\n                    if (remoteMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n                    {\n                        PIMAGE_OPTIONAL_HEADER32 optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&remoteMappedImage.NtHeaders32->OptionalHeader;\n\n                        imageBase = UlongToPtr(optionalHeader->ImageBase);\n                        entryPoint = optionalHeader->AddressOfEntryPoint;\n                        moduleItem->ImageDllCharacteristics = optionalHeader->DllCharacteristics;\n                        moduleItem->ImageMachine = remoteMappedImage.NtHeaders32->FileHeader.Machine;\n                        moduleItem->ImageTimeDateStamp = remoteMappedImage.NtHeaders32->FileHeader.TimeDateStamp;\n                        moduleItem->ImageCharacteristics = remoteMappedImage.NtHeaders32->FileHeader.Characteristics;\n                    }\n                    else if (remoteMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n                    {\n                        PIMAGE_OPTIONAL_HEADER64 optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&remoteMappedImage.NtHeaders64->OptionalHeader;\n\n                        imageBase = (PVOID)optionalHeader->ImageBase;\n                        entryPoint = optionalHeader->AddressOfEntryPoint;\n                        moduleItem->ImageDllCharacteristics = optionalHeader->DllCharacteristics;\n                        moduleItem->ImageMachine = remoteMappedImage.NtHeaders64->FileHeader.Machine;\n                        moduleItem->ImageTimeDateStamp = remoteMappedImage.NtHeaders64->FileHeader.TimeDateStamp;\n                        moduleItem->ImageCharacteristics = remoteMappedImage.NtHeaders64->FileHeader.Characteristics;\n                    }\n\n                    if (moduleItem->BaseAddress != imageBase)\n                        moduleItem->ImageNotAtBase = TRUE;\n\n                    if (entryPoint != 0)\n                        moduleItem->EntryPoint = PTR_ADD_OFFSET(moduleItem->BaseAddress, entryPoint);\n\n                    if (NT_SUCCESS(PhGetRemoteMappedImageDataEntry(\n                        &remoteMappedImage,\n                        IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,\n                        &dataDirectory\n                        )))\n                    {\n                        SetFlag(data->ImageFlags, LDRP_COR_IMAGE);\n                    }\n\n                    if (moduleProvider->CetEnabled && NT_SUCCESS(PhGetRemoteMappedImageDebugEntryByType(\n                        &remoteMappedImage,\n                        IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS,\n                        &debugEntryLength,\n                        &debugEntry\n                        )))\n                    {\n                        ULONG characteristics = ULONG_MAX;\n\n                        if (debugEntryLength == sizeof(ULONG))\n                            characteristics = *(PULONG)debugEntry;\n\n                        if (characteristics != ULONG_MAX)\n                            moduleItem->ImageDllCharacteristicsEx = characteristics;\n\n                        PhFreePage(debugEntry);\n                    }\n\n                    if (!NT_SUCCESS(PhGetRemoteMappedImageCHPEVersion(\n                        &remoteMappedImage,\n                        &moduleItem->ImageCHPEVersion\n                        )))\n                    {\n                        moduleItem->ImageCHPEVersion = 0;\n                    }\n\n                    if (!NT_SUCCESS(PhGetRemoteMappedImageGuardFlags(\n                        &remoteMappedImage,\n                        &moduleItem->GuardFlags\n                        )))\n                    {\n                        moduleItem->GuardFlags = 0;\n                    }\n                }\n                __except (EXCEPTION_EXECUTE_HANDLER)\n                {\n                    NOTHING;\n                }\n\n                PhUnloadRemoteMappedImage(&remoteMappedImage);\n            }\n            else\n            {\n                PH_MAPPED_IMAGE mappedImage;\n\n                // Query the file since we're unable to query memory. (dmex)\n\n                if (NT_SUCCESS(PhLoadMappedImageEx(&data->ModuleItem->FileName->sr, NULL, &mappedImage)))\n                {\n                    ULONG entryPoint = 0;\n                    USHORT characteristics = 0;\n                    PIMAGE_DATA_DIRECTORY dataDirectory;\n                    PH_MAPPED_IMAGE_CFG cfgConfig = { NULL };\n\n                    __try\n                    {\n                        moduleItem->ImageMachine = mappedImage.NtHeaders->FileHeader.Machine;\n                        moduleItem->ImageCHPEVersion = PhGetMappedImageCHPEVersion(&mappedImage);\n\n                        if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n                        {\n                            PIMAGE_OPTIONAL_HEADER32 optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders32->OptionalHeader;\n\n                            entryPoint = optionalHeader->AddressOfEntryPoint;\n                            characteristics = optionalHeader->DllCharacteristics;\n                        }\n                        else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n                        {\n                            PIMAGE_OPTIONAL_HEADER64 optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders64->OptionalHeader;\n\n                            entryPoint = optionalHeader->AddressOfEntryPoint;\n                            characteristics = optionalHeader->DllCharacteristics;\n                        }\n\n                        if (entryPoint != 0)\n                            moduleItem->EntryPoint = PTR_ADD_OFFSET(moduleItem->BaseAddress, entryPoint);\n\n                        if (characteristics != 0)\n                            moduleItem->ImageDllCharacteristics = characteristics;\n\n                        if (NT_SUCCESS(PhGetMappedImageDataDirectory(\n                            &mappedImage,\n                            IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,\n                            &dataDirectory\n                            )))\n                        {\n                            SetFlag(data->ImageFlags, LDRP_COR_IMAGE);\n                        }\n\n                        if (NT_SUCCESS(PhGetMappedImageCfg(&cfgConfig, &mappedImage)))\n                        {\n                            data->GuardFlags = cfgConfig.GuardFlags;\n                        }\n                    }\n                    __except (EXCEPTION_EXECUTE_HANDLER)\n                    {\n                        NOTHING;\n                    }\n\n                    PhUnloadMappedImage(&mappedImage);\n                }\n            }\n        }\n\n        // Remove CF Guard flag when CFG mitigation is not enabled for the process.\n        if (!moduleProvider->ControlFlowGuardEnabled)\n            ClearFlag(moduleItem->ImageDllCharacteristics, IMAGE_DLLCHARACTERISTICS_GUARD_CF);\n\n        // Add CET flag when strict mode is enabled for the process.\n        if (moduleProvider->CetStrictModeEnabled)\n            SetFlag(moduleItem->ImageDllCharacteristicsEx, IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT);\n\n        // Remove CET flag when CET is not enabled for the process.\n        if (!moduleProvider->CetEnabled)\n            ClearFlag(moduleItem->ImageDllCharacteristicsEx, IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT);\n    }\n\n    if (PhEnableImageCoherencySupport && moduleProvider->IsHandleValid && !data->ModuleProvider->IsSubsystemProcess)\n    {\n        if (data->ModuleItem->Type == PH_MODULE_TYPE_MODULE ||\n            data->ModuleItem->Type == PH_MODULE_TYPE_WOW64_MODULE ||\n            data->ModuleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE ||\n            data->ModuleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE)\n        {\n            if (data->ModuleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE && (KsiLevel() < KphLevelMax))\n            {\n                // The driver wasn't available or we failed verification preventing\n                // us from checking driver coherency. Pass a special value so we\n                // don't highlight incorrect entries by default. (dmex)\n                data->ImageCoherencyStatus = LONG_MAX;\n            }\n            else\n            {\n                data->ImageCoherencyStatus = PhGetProcessModuleImageCoherency(\n                    data->ModuleItem->FileName,\n                    data->ModuleProvider->ProcessHandle,\n                    data->ModuleItem->BaseAddress,\n                    data->ModuleItem->Size,\n                    data->ModuleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE,\n                    data->ModuleProvider->ImageCoherencyScanLevel,\n                    &data->ImageCoherency\n                    );\n            }\n        }\n    }\n\n    if (data->ModuleItem->FileName)\n    {\n        data->ImageKnownDll = PhIsKnownDllFileName(data->ModuleItem->FileName);\n    }\n\n    RtlInterlockedPushEntrySList(&data->ModuleProvider->QueryListHead, &data->ListEntry);\n\n    PhDereferenceObject(data->ModuleProvider);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpQueueModuleQuery(\n    _In_ PPH_MODULE_PROVIDER ModuleProvider,\n    _In_ PPH_MODULE_ITEM ModuleItem\n    )\n{\n    PPH_MODULE_QUERY_DATA data;\n    PH_WORK_QUEUE_ENVIRONMENT environment;\n\n    data = PhAllocate(sizeof(PH_MODULE_QUERY_DATA));\n    memset(data, 0, sizeof(PH_MODULE_QUERY_DATA));\n    data->ModuleProvider = ModuleProvider;\n    data->ModuleItem = ModuleItem;\n\n    PhReferenceObject(ModuleProvider);\n    PhReferenceObject(ModuleItem);\n\n    PhInitializeWorkQueueEnvironment(&environment);\n    environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL;\n    environment.IoPriority = IoPriorityLow;\n    environment.PagePriority = MEMORY_PRIORITY_LOW;\n\n    PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpModuleQueryWorker, data, NULL, &environment);\n}\n\n_Function_class_(PH_ENUM_GENERIC_MODULES_CALLBACK)\nstatic BOOLEAN NTAPI PhpEnumModulesCallback(\n    _In_ PPH_MODULE_INFO Module,\n    _In_ PVOID Context\n    )\n{\n    PPH_MODULE_INFO copy;\n\n    copy = PhAllocateCopy(Module, sizeof(PH_MODULE_INFO));\n\n    PhReferenceObject(copy->Name);\n    PhReferenceObject(copy->FileName);\n\n    PhAddItemList((PPH_LIST)Context, copy);\n\n    return TRUE;\n}\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhModuleProviderUpdate(\n    _In_ PVOID Object\n    )\n{\n    PPH_MODULE_PROVIDER moduleProvider = (PPH_MODULE_PROVIDER)Object;\n    PPH_LIST modules;\n    ULONG i;\n\n    // If we didn't get a handle when we created the provider,\n    // abort (unless this is the System process - in that case\n    // we don't need a handle).\n    if (!moduleProvider->ProcessHandle && moduleProvider->ProcessId != SYSTEM_PROCESS_ID)\n        goto UpdateExit;\n\n    modules = PhCreateList(100);\n\n    moduleProvider->RunStatus = PhEnumGenericModules(\n        moduleProvider->ProcessId,\n        moduleProvider->ProcessHandle,\n        PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES,\n        PhpEnumModulesCallback,\n        modules\n        );\n\n    PhEnumGenericEnclaveModules(\n        moduleProvider->ProcessHandle,\n        modules\n        );\n\n    // Look for removed modules.\n    {\n        PPH_LIST modulesToRemove = NULL;\n        ULONG enumerationKey = 0;\n        PPH_MODULE_ITEM *moduleItem;\n\n        while (PhEnumHashtable(moduleProvider->ModuleHashtable, (PVOID *)&moduleItem, &enumerationKey))\n        {\n            BOOLEAN found = FALSE;\n\n            // Check if the module still exists.\n            for (i = 0; i < modules->Count; i++)\n            {\n                PPH_MODULE_INFO module = modules->Items[i];\n\n                if ((*moduleItem)->BaseAddress == module->BaseAddress &&\n                    (*moduleItem)->EnclaveBaseAddress == module->EnclaveBaseAddress &&\n                    PhEqualString((*moduleItem)->FileName, module->FileName, FALSE))\n                {\n                    found = TRUE;\n                    break;\n                }\n            }\n\n            if (!found)\n            {\n                // Raise the module removed event.\n                PhInvokeCallback(&moduleProvider->ModuleRemovedEvent, *moduleItem);\n\n                if (!modulesToRemove)\n                    modulesToRemove = PhCreateList(2);\n\n                PhAddItemList(modulesToRemove, *moduleItem);\n            }\n        }\n\n        if (modulesToRemove)\n        {\n            PhAcquireFastLockExclusive(&moduleProvider->ModuleHashtableLock);\n\n            for (i = 0; i < modulesToRemove->Count; i++)\n            {\n                PhpRemoveModuleItem(\n                    moduleProvider,\n                    (PPH_MODULE_ITEM)modulesToRemove->Items[i]\n                    );\n            }\n\n            PhReleaseFastLockExclusive(&moduleProvider->ModuleHashtableLock);\n            PhDereferenceObject(modulesToRemove);\n        }\n    }\n\n    // Go through the queued thread query data.\n    {\n        PSLIST_ENTRY entry;\n        PPH_MODULE_QUERY_DATA data;\n\n        entry = RtlInterlockedFlushSList(&moduleProvider->QueryListHead);\n\n        while (entry)\n        {\n            data = CONTAINING_RECORD(entry, PH_MODULE_QUERY_DATA, ListEntry);\n            entry = entry->Next;\n\n            data->ModuleItem->VerifyResult = data->VerifyResult;\n            data->ModuleItem->VerifySignerName = data->VerifySignerName;\n            data->ModuleItem->Flags |= data->ImageFlags;\n            data->ModuleItem->GuardFlags = data->GuardFlags;\n            data->ModuleItem->ImageCoherencyStatus = data->ImageCoherencyStatus;\n            data->ModuleItem->ImageCoherency = data->ImageCoherency;\n            data->ModuleItem->ImageKnownDll = data->ImageKnownDll;\n\n            data->ModuleItem->JustProcessed = TRUE;\n\n            PhDereferenceObject(data->ModuleItem);\n            PhFree(data);\n        }\n    }\n\n    // Look for new modules.\n    for (i = 0; i < modules->Count; i++)\n    {\n        PPH_MODULE_INFO module = modules->Items[i];\n        PPH_MODULE_ITEM moduleItem;\n        FILE_NETWORK_OPEN_INFORMATION networkOpenInfo;\n\n        moduleItem = PhReferenceModuleItemEx(\n            moduleProvider,\n            module->BaseAddress,\n            module->EnclaveBaseAddress,\n            module->FileName\n            );\n\n        if (!moduleItem)\n        {\n            PhReferenceObject(module->Name);\n            PhReferenceObject(module->FileName);\n\n            moduleItem = PhCreateModuleItem();\n            moduleItem->BaseAddress = module->BaseAddress;\n            moduleItem->EntryPoint = module->EntryPoint;\n            moduleItem->Size = module->Size;\n            moduleItem->Flags = module->Flags;\n            moduleItem->Type = module->Type;\n            moduleItem->LoadReason = module->LoadReason;\n            moduleItem->LoadCount = module->LoadCount;\n            moduleItem->LoadTime = module->LoadTime;\n            moduleItem->Name = module->Name;\n            moduleItem->FileName = module->FileName;\n            moduleItem->ParentBaseAddress = module->ParentBaseAddress;\n            moduleItem->EnclaveType = module->EnclaveType;\n            moduleItem->EnclaveBaseAddress = module->EnclaveBaseAddress;\n            moduleItem->EnclaveSize = module->EnclaveSize;\n\n            if (module->OriginalBaseAddress && module->OriginalBaseAddress != module->BaseAddress)\n                moduleItem->ImageNotAtBase = TRUE;\n\n            if (moduleProvider->ZeroPadAddresses)\n            {\n                PhPrintPointerPadZeros(moduleItem->BaseAddressString, moduleItem->BaseAddress);\n                PhPrintPointerPadZeros(moduleItem->EntryPointAddressString, moduleItem->EntryPoint);\n                PhPrintPointerPadZeros(moduleItem->ParentBaseAddressString, moduleItem->ParentBaseAddress);\n                PhPrintPointerPadZeros(moduleItem->EnclaveBaseAddressString, moduleItem->EnclaveBaseAddress);\n            }\n            else\n            {\n                PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress);\n                PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint);\n                PhPrintPointer(moduleItem->ParentBaseAddressString, moduleItem->ParentBaseAddress);\n                PhPrintPointer(moduleItem->EnclaveBaseAddressString, moduleItem->EnclaveBaseAddress);\n            }\n\n            PhInitializeImageVersionInfoEx(&moduleItem->VersionInfo, &moduleItem->FileName->sr, !!PhCsEnableVersionSupport);\n\n            if (moduleProvider->IsSubsystemProcess)\n            {\n                // HACK: Update the module type. (TODO: Move into PhEnumGenericModules) (dmex)\n                moduleItem->Type = PH_MODULE_TYPE_ELF_MAPPED_IMAGE;\n            }\n            else\n            {\n                // Fix up the load count. If this is not an ordinary DLL or kernel module, set the load count to 0.\n                if (moduleItem->Type != PH_MODULE_TYPE_MODULE &&\n                    moduleItem->Type != PH_MODULE_TYPE_WOW64_MODULE &&\n                    moduleItem->Type != PH_MODULE_TYPE_KERNEL_MODULE)\n                {\n                    moduleItem->LoadCount = 0;\n                }\n            }\n\n            if (!moduleProvider->HaveFirst)\n            {\n                if (WindowsVersion < WINDOWS_8)\n                {\n                    moduleItem->IsFirst = i == 0;\n                    moduleProvider->HaveFirst = TRUE;\n                }\n                else\n                {\n                    // Windows loads the PE image first and WSL loads the ELF image last (dmex)\n                    if (moduleProvider->ProcessFileName && PhEqualString(moduleProvider->ProcessFileName, moduleItem->FileName, FALSE))\n                    {\n                        moduleItem->IsFirst = TRUE;\n                        moduleProvider->HaveFirst = TRUE;\n                    }\n                }\n            }\n\n            if (NT_SUCCESS(PhQueryFullAttributesFile(&moduleItem->FileName->sr, &networkOpenInfo)))\n            {\n                moduleItem->FileLastWriteTime = networkOpenInfo.LastWriteTime;\n                moduleItem->FileEndOfFile = networkOpenInfo.EndOfFile;\n            }\n\n            if (moduleItem->Type != PH_MODULE_TYPE_ELF_MAPPED_IMAGE)\n            {\n                // See if the file has already been verified; if not, queue for verification.\n                moduleItem->VerifyResult = PhVerifyFileCached(moduleItem->FileName, NULL, &moduleItem->VerifySignerName, TRUE, TRUE);\n\n                //if (moduleItem->VerifyResult == VrUnknown) // (dmex)\n                PhpQueueModuleQuery(moduleProvider, moduleItem);\n            }\n\n            // Add the module item to the hashtable.\n            PhAcquireFastLockExclusive(&moduleProvider->ModuleHashtableLock);\n            PhAddEntryHashtable(moduleProvider->ModuleHashtable, &moduleItem);\n            PhReleaseFastLockExclusive(&moduleProvider->ModuleHashtableLock);\n\n            // Raise the module added event.\n            PhInvokeCallback(&moduleProvider->ModuleAddedEvent, moduleItem);\n        }\n        else\n        {\n            BOOLEAN modified = FALSE;\n\n            if (moduleItem->JustProcessed)\n                modified = TRUE;\n\n            moduleItem->JustProcessed = FALSE;\n\n            if (moduleItem->LoadCount != module->LoadCount)\n            {\n                moduleItem->LoadCount = module->LoadCount;\n                modified = TRUE;\n            }\n\n            if (NT_SUCCESS(PhQueryFullAttributesFile(&moduleItem->FileName->sr, &networkOpenInfo)))\n            {\n                if (moduleItem->FileLastWriteTime.QuadPart != networkOpenInfo.LastWriteTime.QuadPart)\n                {\n                    moduleItem->FileLastWriteTime.QuadPart = networkOpenInfo.LastWriteTime.QuadPart;\n                    modified = TRUE;\n                }\n\n                if (moduleItem->FileEndOfFile.QuadPart != networkOpenInfo.EndOfFile.QuadPart)\n                {\n                    moduleItem->FileEndOfFile.QuadPart = networkOpenInfo.EndOfFile.QuadPart;\n                    modified = TRUE;\n                }\n            }\n            else\n            {\n                if (moduleItem->FileLastWriteTime.QuadPart != 0)\n                {\n                    moduleItem->FileLastWriteTime.QuadPart = 0;\n                    modified = TRUE;\n                }\n\n                if (moduleItem->FileEndOfFile.QuadPart != 0)\n                {\n                    moduleItem->FileEndOfFile.QuadPart = 0;\n                    modified = TRUE;\n                }\n            }\n\n            if (modified)\n                PhInvokeCallback(&moduleProvider->ModuleModifiedEvent, moduleItem);\n\n            PhDereferenceObject(moduleItem);\n        }\n    }\n\n    if (!moduleProvider->HaveFirst) // Some processes don't have a primary image (e.g. System/Registry/Secure System) (dmex)\n        moduleProvider->HaveFirst = TRUE;\n\n    // Free the modules list.\n\n    for (i = 0; i < modules->Count; i++)\n    {\n        PPH_MODULE_INFO module = modules->Items[i];\n\n        PhDereferenceObject(module->Name);\n        PhDereferenceObject(module->FileName);\n        PhFree(module);\n    }\n\n    PhDereferenceObject(modules);\n\nUpdateExit:\n    PhInvokeCallback(&moduleProvider->UpdatedEvent, NULL);\n}\n\nstatic CONST PH_KEY_VALUE_PAIR PhModuleTypePairs[] =\n{\n    SIP(SREF(L\"Unknown\"), PH_MODULE_TYPE_UNKNOWN),\n    SIP(SREF(L\"DLL\"), PH_MODULE_TYPE_MODULE),\n    SIP(SREF(L\"Mapped file\"), PH_MODULE_TYPE_MAPPED_FILE),\n    SIP(SREF(L\"WOW64 DLL\"), PH_MODULE_TYPE_WOW64_MODULE),\n    SIP(SREF(L\"Kernel module\"), PH_MODULE_TYPE_KERNEL_MODULE),\n    SIP(SREF(L\"Mapped image\"), PH_MODULE_TYPE_MAPPED_IMAGE),\n    SIP(SREF(L\"Mapped image\"), PH_MODULE_TYPE_ELF_MAPPED_IMAGE),\n    SIP(SREF(L\"Enclave module\"), PH_MODULE_TYPE_ENCLAVE_MODULE),\n};\n\nPCPH_STRINGREF PhGetModuleTypeName(\n    _In_ ULONG ModuleType\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        PhModuleTypePairs,\n        sizeof(PhModuleTypePairs),\n        ModuleType,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return NULL;\n}\n\nstatic CONST PH_KEY_VALUE_PAIR PhModuleLoadReasonTypePairs[] =\n{\n    SIP(SREF(L\"Static dependency\"), LoadReasonStaticDependency),\n    SIP(SREF(L\"Static forwarder dependency\"), LoadReasonStaticForwarderDependency),\n    SIP(SREF(L\"Dynamic forwarder dependency\"), LoadReasonDynamicForwarderDependency),\n    SIP(SREF(L\"Delay load dependency\"), LoadReasonDelayloadDependency),\n    SIP(SREF(L\"Dynamic\"), LoadReasonDynamicLoad),\n    SIP(SREF(L\"As image\"), LoadReasonAsImageLoad),\n    SIP(SREF(L\"As data\"), LoadReasonAsDataLoad),\n    SIP(SREF(L\"Enclave primary\"), LoadReasonEnclavePrimary),\n    SIP(SREF(L\"Enclave dependency\"), LoadReasonEnclaveDependency),\n    SIP(SREF(L\"Patch image\"), LoadReasonPatchImage),\n    SIP(SREF(L\"Unknown\"), LoadReasonUnknown),\n};\n\nPCPH_STRINGREF PhGetModuleLoadReasonTypeName(\n    _In_ USHORT LoadReason\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        PhModuleLoadReasonTypePairs,\n        sizeof(PhModuleLoadReasonTypePairs),\n        LoadReason,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return (PCPH_STRINGREF)PhModuleLoadReasonTypePairs[10].Key;\n}\n\nstatic CONST PH_KEY_VALUE_PAIR PhModuleEnclaveTypePairs[] =\n{\n    SIP(SREF(L\"Unknown\"), 0),\n    SIP(SREF(L\"SGX\"), ENCLAVE_TYPE_SGX),\n    SIP(SREF(L\"SGX2\"), ENCLAVE_TYPE_SGX2),\n    SIP(SREF(L\"VBS\"), ENCLAVE_TYPE_VBS)\n};\n\nPCPH_STRINGREF PhGetModuleEnclaveTypeName(\n    _In_ ULONG EnclaveType\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhFindStringRefSiKeyValuePairs(\n        PhModuleEnclaveTypePairs,\n        sizeof(PhModuleEnclaveTypePairs),\n        EnclaveType,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return NULL;\n}\n\nstatic VOID PhModuleAddEnclaveModule(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_SOFTWARE_ENCLAVE Enclave,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _In_ USHORT LoadOrderIndex,\n    _Inout_ PPH_LIST Modules\n    )\n{\n    PPH_MODULE_INFO info;\n\n    info = PhAllocateZero(sizeof(PH_MODULE_INFO));\n\n    if (!NT_SUCCESS(PhGetProcessLdrTableEntryNames(\n        ProcessHandle,\n        Entry,\n        &info->Name,\n        &info->FileName\n        )))\n    {\n        info->Name = PhReferenceEmptyString();\n        info->FileName = PhReferenceEmptyString();\n    }\n\n    info->Type = PH_MODULE_TYPE_ENCLAVE_MODULE;\n    info->BaseAddress = Entry->DllBase;\n    info->ParentBaseAddress = Entry->ParentDllBase;\n    info->OriginalBaseAddress = (PVOID)Entry->OriginalBase;\n    info->Size = Entry->SizeOfImage;\n    info->EntryPoint = Entry->EntryPoint;\n    info->Flags = Entry->Flags;\n    info->LoadOrderIndex = LoadOrderIndex;\n    info->LoadCount = USHRT_MAX;\n    info->LoadReason = (USHORT)Entry->LoadReason;\n    info->LoadTime = Entry->LoadTime;\n    info->EnclaveType = Enclave->EnclaveType;\n    info->EnclaveBaseAddress = Enclave->BaseAddress;\n    info->EnclaveSize = Enclave->Size;\n\n    PhAddItemList(Modules, info);\n}\n\ntypedef struct _PHP_ENUM_ENCLAVE_MODULES_CONTEXT\n{\n    PPH_LIST Modules;\n    USHORT LoadOrderIndex;\n} PHP_ENUM_ENCLAVE_MODULES_CONTEXT, *PPHP_ENUM_ENCLAVE_MODULES_CONTEXT;\n\nstatic BOOLEAN NTAPI PhModuleEnumEnclaveModulesCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_SOFTWARE_ENCLAVE Enclave,\n    _In_ PVOID EntryAddress,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _In_ PVOID Context\n    )\n{\n    PPHP_ENUM_ENCLAVE_MODULES_CONTEXT context;\n\n    context = (PPHP_ENUM_ENCLAVE_MODULES_CONTEXT)Context;\n\n    PhModuleAddEnclaveModule(\n        ProcessHandle,\n        Enclave,\n        Entry,\n        context->LoadOrderIndex++,\n        context->Modules\n        );\n\n    return TRUE;\n}\n\nstatic BOOLEAN NTAPI PhModuleEnumEnclavesCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID EnclaveAddress,\n    _In_ PLDR_SOFTWARE_ENCLAVE Enclave,\n    _In_ PVOID Context\n    )\n{\n    PHP_ENUM_ENCLAVE_MODULES_CONTEXT context;\n\n    context.Modules = (PPH_LIST)Context;\n    context.LoadOrderIndex = 0;\n\n    PhEnumProcessEnclaveModules(\n        ProcessHandle,\n        EnclaveAddress,\n        Enclave,\n        PhModuleEnumEnclaveModulesCallback,\n        &context\n        );\n\n    return TRUE;\n}\n\nNTSTATUS PhEnumGenericEnclaveModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PVOID ntLdrEnclaveList;\n\n    if (ntLdrEnclaveList = ReadPointerAcquire(&PhLdrEnclaveList))\n    {\n        status = PhEnumProcessEnclaves(\n            ProcessHandle,\n            ntLdrEnclaveList,\n            PhModuleEnumEnclavesCallback,\n            Context\n            );\n    }\n    else\n    {\n        status = STATUS_PROCEDURE_NOT_FOUND;\n    }\n\n    return status;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhModuleEnclaveListInitialize(\n    _In_ PVOID ThreadParameter\n    )\n{\n    PPH_SYMBOL_PROVIDER symbolProvider;\n    PH_SYMBOL_INFORMATION symbolInfo;\n    PVOID baseAddress;\n    ULONG sizeOfImage;\n    PPH_STRING fileName;\n\n    symbolProvider = PhCreateSymbolProvider(NULL);\n    PhLoadSymbolProviderOptions(symbolProvider);\n\n    if (PhGetLoaderEntryDataZ(L\"ntdll.dll\", &baseAddress, &sizeOfImage, &fileName))\n    {\n        PhLoadModuleSymbolProvider(symbolProvider, fileName, baseAddress, sizeOfImage);\n        PhDereferenceObject(fileName);\n    }\n\n    if (PhGetSymbolFromName(symbolProvider, L\"LdrpEnclaveList\", &symbolInfo))\n    {\n        InterlockedExchangePointer(&PhLdrEnclaveList, (PLIST_ENTRY)symbolInfo.Address);\n    }\n\n    PhDereferenceObject(symbolProvider);\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "SystemInformer/mtgndlg.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2016-2023\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <procmtgn.h>\n\ntypedef struct _MITIGATION_POLICY_ENTRY\n{\n    BOOLEAN NonStandard;\n    PPH_STRING ShortDescription;\n    PPH_STRING LongDescription;\n} MITIGATION_POLICY_ENTRY, *PMITIGATION_POLICY_ENTRY;\n\ntypedef struct _MITIGATION_POLICY_CONTEXT\n{\n    HWND ListViewHandle;\n    PS_SYSTEM_DLL_INIT_BLOCK SystemDllInitBlock;\n    MITIGATION_POLICY_ENTRY Entries[MaxProcessMitigationPolicy];\n} MITIGATION_POLICY_CONTEXT, *PMITIGATION_POLICY_CONTEXT;\n\nINT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowProcessMitigationPolicyDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION information;\n    MITIGATION_POLICY_CONTEXT context;\n    PROCESS_MITIGATION_POLICY policy;\n    PPH_STRING shortDescription;\n    PPH_STRING longDescription;\n\n    memset(&context, 0, sizeof(MITIGATION_POLICY_CONTEXT));\n    memset(&context.Entries, 0, sizeof(context.Entries));\n\n    // Try to get a handle with query information + vm read access.\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n        ProcessId\n        )))\n    {\n        // Try to get a handle with query information.\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_INFORMATION,\n            ProcessId\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        PS_SYSTEM_DLL_INIT_BLOCK dllInitBlock;\n\n        if (NT_SUCCESS(PhGetProcessSystemDllInitBlock(processHandle, &dllInitBlock)))\n        {\n            context.SystemDllInitBlock = dllInitBlock;\n        }\n\n        if (NT_SUCCESS(PhGetProcessMitigationPolicyAllInformation(processHandle, &information)))\n        {\n            for (policy = 0; policy < MaxProcessMitigationPolicy; policy++)\n            {\n                if (information.Pointers[policy] && PhDescribeProcessMitigationPolicy(\n                    policy,\n                    information.Pointers[policy],\n                    &shortDescription,\n                    &longDescription\n                    ))\n                {\n                    context.Entries[policy].ShortDescription = shortDescription;\n                    context.Entries[policy].LongDescription = longDescription;\n                }\n            }\n\n            // HACK: Show System process CET mitigations (dmex)\n            if (ProcessId == SYSTEM_PROCESS_ID)\n            {\n                SYSTEM_SHADOW_STACK_INFORMATION shadowStackInformation;\n\n                if (NT_SUCCESS(PhGetSystemShadowStackInformation(&shadowStackInformation)))\n                {\n                    PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policyData;\n\n                    memset(&policyData, 0, sizeof(PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY));\n                    policyData.EnableUserShadowStack = shadowStackInformation.KernelCetEnabled;\n                    policyData.EnableUserShadowStackStrictMode = shadowStackInformation.KernelCetEnabled;\n                    policyData.AuditUserShadowStack = shadowStackInformation.KernelCetAuditModeEnabled;\n\n                    if (PhDescribeProcessMitigationPolicy(\n                        ProcessUserShadowStackPolicy,\n                        &policyData,\n                        &shortDescription,\n                        &longDescription\n                        ))\n                    {\n                        context.Entries[ProcessUserShadowStackPolicy].ShortDescription = shortDescription;\n                        context.Entries[ProcessUserShadowStackPolicy].LongDescription = longDescription;\n                    }\n                }\n            }\n\n            PhDialogBox(\n                PhInstanceHandle,\n                MAKEINTRESOURCE(IDD_MITIGATION),\n                ParentWindowHandle,\n                PhpProcessMitigationPolicyDlgProc,\n                &context\n                );\n\n            for (policy = 0; policy < MaxProcessMitigationPolicy; policy++)\n            {\n                PhClearReference(&context.Entries[policy].ShortDescription);\n                PhClearReference(&context.Entries[policy].LongDescription);\n            }\n        }\n\n        NtClose(processHandle);\n    }\n    else\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to open the process.\", status, 0);\n    }\n}\n\nINT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PMITIGATION_POLICY_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PMITIGATION_POLICY_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n        if (uMsg == WM_DESTROY)\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n    }\n\n    if (context == NULL)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HWND lvHandle;\n            PROCESS_MITIGATION_POLICY policy;\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n            context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            PhSetListViewStyle(lvHandle, FALSE, TRUE);\n            PhSetControlTheme(lvHandle, L\"explorer\");\n            PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 350, L\"Policy\");\n            PhSetExtendedListView(lvHandle);\n\n            for (policy = 0; policy < MaxProcessMitigationPolicy; policy++)\n            {\n                PMITIGATION_POLICY_ENTRY entry = &context->Entries[policy];\n\n                if (!entry->ShortDescription)\n                    continue;\n\n                PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry);\n            }\n\n            if (RTL_CONTAINS_FIELD(&context->SystemDllInitBlock, context->SystemDllInitBlock.Size, MitigationOptionsMap))\n            {\n                // TODO: Windows doesn't propagate these flags into the MitigationOptionsMap array. (dmex)\n                //if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON)\n                //{\n                //    PMITIGATION_POLICY_ENTRY entry;\n                //\n                //    entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY));\n                //    entry->NonStandard = TRUE;\n                //    entry->ShortDescription = PhCreateString(L\"Loader Integrity\");\n                //    entry->LongDescription = PhCreateString(L\"OS signing levels for dependent module loads are enabled.\");\n                //\n                //    PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry);\n                //}\n\n                //if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON)\n                //{\n                //    PMITIGATION_POLICY_ENTRY entry;\n                //\n                //    entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY));\n                //    entry->NonStandard = TRUE;\n                //    entry->ShortDescription = PhCreateString(L\"Module Tampering\");\n                //    entry->LongDescription = PhCreateString(L\"Module Tampering protection is enabled.\");\n                //\n                //    PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry);\n                //}\n\n                if (context->SystemDllInitBlock.MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON)\n                {\n                    PMITIGATION_POLICY_ENTRY entry;\n\n                    entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY));\n                    entry->NonStandard = TRUE;\n                    entry->ShortDescription = PhCreateString(L\"Indirect branch prediction\");\n                    entry->LongDescription = PhCreateString(L\"Protects against sibling hardware threads (hyperthreads) from interfering with indirect branch predictions.\");\n\n                    PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry);\n                }\n\n                if (context->SystemDllInitBlock.MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_ALLOW_DOWNGRADE_DYNAMIC_CODE_POLICY_ALWAYS_ON)\n                {\n                    PMITIGATION_POLICY_ENTRY entry;\n\n                    entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY));\n                    entry->NonStandard = TRUE;\n                    entry->ShortDescription = PhCreateString(L\"Dynamic code (downgrade)\");\n                    entry->LongDescription = PhCreateString(L\"Allows a broker to downgrade the dynamic code policy for a process.\");\n\n                    PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry);\n                }\n\n                if (context->SystemDllInitBlock.MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_SPECULATIVE_STORE_BYPASS_DISABLE_ALWAYS_ON)\n                {\n                    PMITIGATION_POLICY_ENTRY entry;\n\n                    entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY));\n                    entry->NonStandard = TRUE;\n                    entry->ShortDescription = PhCreateString(L\"Speculative store bypass\");\n                    entry->LongDescription = PhCreateString(L\"Disables spectre mitigations for the process.\");\n\n                    PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry);\n                }\n            }\n\n            ExtendedListView_SortItems(lvHandle);\n            ExtendedListView_SetColumnWidth(lvHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n            ListView_SetItemState(lvHandle, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);\n\n            PhSetDialogFocus(hwndDlg, lvHandle);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            INT index = INT_ERROR;\n\n            while ((index = PhFindListViewItemByFlags(\n                context->ListViewHandle,\n                index,\n                LVNI_ALL\n                )) != INT_ERROR)\n            {\n                PMITIGATION_POLICY_ENTRY entry;\n\n                if (PhGetListViewItemParam(context->ListViewHandle, index, &entry))\n                {\n                    if (entry->NonStandard)\n                    {\n                        PhClearReference(&entry->ShortDescription);\n                        PhClearReference(&entry->LongDescription);\n                        PhFree(entry);\n                    }\n                }\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                EndDialog(hwndDlg, IDOK);\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n            HWND lvHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            switch (header->code)\n            {\n            case LVN_ITEMCHANGED:\n                {\n                    if (header->hwndFrom == lvHandle)\n                    {\n                        PWSTR description;\n\n                        if (ListView_GetSelectedCount(lvHandle) == 1)\n                            description = ((PMITIGATION_POLICY_ENTRY)PhGetSelectedListViewItemParam(lvHandle))->LongDescription->Buffer;\n                        else\n                            description = L\"\";\n\n                        PhSetDialogItemText(hwndDlg, IDC_DESCRIPTION, description);\n                    }\n                }\n                break;\n            }\n\n            PhHandleListViewNotifyForCopy(lParam, lvHandle);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/mwpgdev.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023\n *\n */\n\n#include <phapp.h>\n#include <devprv.h>\n#include <settings.h>\n#include <phsettings.h>\n\n#include <phplug.h>\n#include <mainwnd.h>\n#include <mainwndp.h>\n#include <devguid.h>\n\nstatic PH_CALLBACK_REGISTRATION PhpDeviceNotifyRegistration = { 0 };\nstatic CONST PH_STRINGREF PhpDeviceString = PH_STRINGREF_INIT(L\"Device\");\n\nBOOLEAN PhpShouldNotifyForDevice(\n    _In_ PPH_DEVICE_ITEM Item,\n    _In_ ULONG Type\n    )\n{\n    if (Item->ChildrenCount)\n        return FALSE;\n\n    if (IsEqualGUID(&Item->ClassGuid, &GUID_DEVCLASS_HIDCLASS))\n        return FALSE;\n\n    if (PhPluginsEnabled && PhMwpPluginNotifyEvent(Type, Item))\n        return FALSE;\n\n    return TRUE;\n}\n\nPPH_STRING PhpNotifyDeviceGetString(\n    _In_ PPH_DEVICE_ITEM Node,\n    _In_ PH_DEVICE_PROPERTY_CLASS Class,\n    _In_ BOOLEAN TrimDevice\n    )\n{\n    PH_STRINGREF sr;\n    PPH_STRING string;\n\n    string = PhGetDeviceProperty(Node, Class)->AsString;\n    if (PhIsNullOrEmptyString(string))\n        return NULL;\n\n    sr = string->sr;\n\n    if (TrimDevice && PhEndsWithStringRef(&sr, &PhpDeviceString, TRUE))\n        sr.Length -= PhpDeviceString.Length;\n\n    return PhCreateString2(&sr);\n}\n\nVOID PhpNotifyForDevice(\n    _In_ PPH_DEVICE_ITEM Item,\n    _In_ ULONG Type\n    )\n{\n    PPH_STRING classification;\n    PPH_STRING name;\n    PPH_STRING title;\n\n    classification = PhpNotifyDeviceGetString(Item, PhDevicePropertyClass, TRUE);\n    if (!classification)\n        classification = PhCreateString(L\"Unclassified\");\n\n    name = PhpNotifyDeviceGetString(Item, PhDevicePropertyName, FALSE);\n    if (!name)\n        name = PhCreateString(L\"Unnamed\");\n\n    if (Type == PH_NOTIFY_DEVICE_REMOVED)\n    {\n        PhLogDeviceEntry(PH_LOG_ENTRY_DEVICE_REMOVED, classification, name);\n        title = PhConcatStringRefZ(&classification->sr, L\" Device Removed\");\n    }\n    else\n    {\n        PhLogDeviceEntry(PH_LOG_ENTRY_DEVICE_ARRIVED, classification, name);\n        title = PhConcatStringRefZ(&classification->sr, L\" Device Arrived\");\n    }\n\n    if ((PhMwpNotifyIconNotifyMask & Type))\n        PhShowIconNotification(PhGetString(title), PhGetString(name));\n\n    PhDereferenceObject(title);\n    PhDereferenceObject(name);\n    PhDereferenceObject(classification);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhpDeviceProviderCallbackHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    ULONG type = 0;\n    PPH_DEVICE_NOTIFY notify = Parameter;\n    PPH_DEVICE_TREE tree;\n    PPH_DEVICE_ITEM item;\n\n    if (notify->Action == PhDeviceNotifyInstanceStarted)\n        type = PH_NOTIFY_DEVICE_ARRIVED;\n    else if (notify->Action == PhDeviceNotifyInstanceRemoved)\n        type = PH_NOTIFY_DEVICE_REMOVED;\n    else\n        return;\n\n    if (tree = PhReferenceDeviceTree())\n    {\n        item = PhLookupDeviceItem(tree, &notify->DeviceInstance.InstanceId->sr);\n        if (item && PhpShouldNotifyForDevice(item, type))\n        {\n            PhpNotifyForDevice(item, type);\n        }\n\n        PhClearReference(&tree);\n    }\n}\n\nVOID PhMwpInitializeDeviceNotifications(\n    VOID\n    )\n{\n    if (!PhGetIntegerSetting(SETTING_ENABLE_DEVICE_NOTIFY_SUPPORT)) // EnableDeviceNotificationSupport\n        return;\n\n    if (!PhDeviceProviderInitialization())\n        return;\n\n    PhRegisterCallback(\n        PhGetGeneralCallback(GeneralCallbackDeviceNotificationEvent),\n        PhpDeviceProviderCallbackHandler,\n        NULL,\n        &PhpDeviceNotifyRegistration\n        );\n}\n"
  },
  {
    "path": "SystemInformer/mwpgnet.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <mainwnd.h>\n#include <emenu.h>\n\n#include <netlist.h>\n#include <netprv.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <mainwndp.h>\n\nPPH_MAIN_TAB_PAGE PhMwpNetworkPage;\nHWND PhMwpNetworkTreeNewHandle;\nPH_PROVIDER_EVENT_QUEUE PhMwpNetworkEventQueue;\n\nstatic PH_CALLBACK_REGISTRATION NetworkItemAddedRegistration;\nstatic PH_CALLBACK_REGISTRATION NetworkItemModifiedRegistration;\nstatic PH_CALLBACK_REGISTRATION NetworkItemRemovedRegistration;\nstatic PH_CALLBACK_REGISTRATION NetworkItemsUpdatedRegistration;\n\nstatic BOOLEAN NetworkFirstTime = TRUE;\nstatic BOOLEAN NetworkTreeListLoaded = FALSE;\nstatic PPH_TN_FILTER_ENTRY NetworkFilterEntry = NULL;\n\n_Function_class_(PH_MAIN_TAB_PAGE_CALLBACK)\nBOOLEAN PhMwpNetworkPageCallback(\n    _In_ PPH_MAIN_TAB_PAGE Page,\n    _In_ PH_MAIN_TAB_PAGE_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case MainTabPageCreate:\n        {\n            PhMwpNetworkPage = Page;\n\n            PhInitializeProviderEventQueue(&PhMwpNetworkEventQueue, 100);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackNetworkProviderAddedEvent),\n                PhMwpNetworkItemAddedHandler,\n                NULL,\n                &NetworkItemAddedRegistration\n                );\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackNetworkProviderModifiedEvent),\n                PhMwpNetworkItemModifiedHandler,\n                NULL,\n                &NetworkItemModifiedRegistration\n                );\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackNetworkProviderRemovedEvent),\n                PhMwpNetworkItemRemovedHandler,\n                NULL,\n                &NetworkItemRemovedRegistration\n                );\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdatedEvent),\n                PhMwpNetworkItemsUpdatedHandler,\n                NULL,\n                &NetworkItemsUpdatedRegistration\n                );\n        }\n        break;\n    case MainTabPageCreateWindow:\n        {\n            if (Parameter1)\n            {\n                *(HWND*)Parameter1 = PhMwpNetworkTreeNewHandle;\n            }\n        }\n        return TRUE;\n    case MainTabPageSelected:\n        {\n            BOOLEAN selected = (BOOLEAN)PtrToUlong(Parameter1);\n\n            if (selected)\n            {\n                PhMwpNeedNetworkTreeList();\n\n                PhSetEnabledProvider(&PhMwpNetworkProviderRegistration, PhMwpUpdateAutomatically);\n\n                if (PhMwpUpdateAutomatically || NetworkFirstTime)\n                {\n                    PhBoostProvider(&PhMwpNetworkProviderRegistration, NULL);\n                    NetworkFirstTime = FALSE;\n                }\n            }\n            else\n            {\n                PhSetEnabledProvider(&PhMwpNetworkProviderRegistration, FALSE);\n            }\n        }\n        break;\n    case MainTabPageInitializeSectionMenuItems:\n        {\n            PPH_MAIN_TAB_PAGE_MENU_INFORMATION menuInfo = Parameter1;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM menuItem;\n\n            menu = PhCreateEMenuItem(0, 0, L\"Network\", NULL, NULL);\n            PhInsertEMenuItem(menuInfo->Menu, menu, menuInfo->StartIndex);\n\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEWAITINGCONNECTIONS, L\"&Hide waiting connections\", NULL, NULL), ULONG_MAX);\n\n            if (NetworkFilterEntry && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_HIDEWAITINGCONNECTIONS)))\n                menuItem->Flags |= PH_EMENU_CHECKED;\n        }\n        return TRUE;\n    case MainTabPageLoadSettings:\n        {\n            if (PhGetIntegerSetting(SETTING_HIDE_WAITING_CONNECTIONS))\n                NetworkFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportNetworkTreeList(), PhMwpNetworkTreeFilter, NULL);\n        }\n        return TRUE;\n    case MainTabPageSaveSettings:\n        {\n            if (NetworkTreeListLoaded)\n                PhSaveSettingsNetworkTreeList();\n        }\n        return TRUE;\n    case MainTabPageExportContent:\n        {\n            PPH_MAIN_TAB_PAGE_EXPORT_CONTENT exportContent = Parameter1;\n\n            PhWriteNetworkList(exportContent->FileStream, exportContent->Mode);\n        }\n        return TRUE;\n    case MainTabPageFontChanged:\n        {\n            HFONT font = (HFONT)Parameter1;\n\n            SetWindowFont(PhMwpNetworkTreeNewHandle, font, TRUE);\n        }\n        break;\n    case MainTabPageUpdateAutomaticallyChanged:\n        {\n            BOOLEAN updateAutomatically = (BOOLEAN)PtrToUlong(Parameter1);\n\n            if (PhMwpNetworkPage->Selected)\n                PhSetEnabledProvider(&PhMwpNetworkProviderRegistration, updateAutomatically);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhMwpNeedNetworkTreeList(\n    VOID\n    )\n{\n    if (!NetworkTreeListLoaded)\n    {\n        NetworkTreeListLoaded = TRUE;\n\n        PhLoadSettingsNetworkTreeList();\n    }\n}\n\nVOID PhMwpToggleNetworkWaitingConnectionTreeFilter(\n    VOID\n    )\n{\n    if (NetworkFilterEntry)\n    {\n        PhRemoveTreeNewFilter(PhGetFilterSupportNetworkTreeList(), NetworkFilterEntry);\n        NetworkFilterEntry = NULL;\n    }\n    else\n    {\n        NetworkFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportNetworkTreeList(), PhMwpNetworkTreeFilter, NULL);\n    }\n\n    PhApplyTreeNewFilters(PhGetFilterSupportNetworkTreeList());\n\n    PhSetIntegerSetting(SETTING_HIDE_WAITING_CONNECTIONS, !!NetworkFilterEntry);\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpNetworkTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)Node;\n\n    if (!networkNode->NetworkItem->ProcessId)\n        return FALSE;\n    if (networkNode->NetworkItem->State == MIB_TCP_STATE_CLOSE_WAIT)\n        return FALSE;\n\n    return TRUE;\n}\n\nVOID PhMwpInitializeNetworkMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ PPH_NETWORK_ITEM *NetworkItems,\n    _In_ ULONG NumberOfNetworkItems\n    )\n{\n    //ULONG i;\n    PPH_EMENU_ITEM item;\n\n    if (NumberOfNetworkItems == 0)\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n    }\n    else if (NumberOfNetworkItems == 1)\n    {\n        if (!NetworkItems[0]->ProcessId)\n            PhEnableEMenuItem(Menu, ID_NETWORK_GOTOPROCESS, FALSE);\n    }\n    else\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n        PhEnableEMenuItem(Menu, ID_NETWORK_CLOSE, TRUE);\n        PhEnableEMenuItem(Menu, ID_NETWORK_COPY, TRUE);\n    }\n\n    // Go to Service\n    if (NumberOfNetworkItems != 1 || !NetworkItems[0]->OwnerName)\n    {\n        if (item = PhFindEMenuItem(Menu, 0, NULL, ID_NETWORK_GOTOSERVICE))\n            PhDestroyEMenuItem(item);\n    }\n\n    // Close\n    //if (NumberOfNetworkItems != 0)\n    //{\n    //    BOOLEAN closeOk = TRUE;\n    //\n    //    for (i = 0; i < NumberOfNetworkItems; i++)\n    //    {\n    //        if (\n    //            NetworkItems[i]->ProtocolType != PH_NETWORK_PROTOCOL_TCP4 ||\n    //            NetworkItems[i]->State != MIB_TCP_STATE_ESTAB\n    //            )\n    //        {\n    //            closeOk = FALSE;\n    //            break;\n    //        }\n    //    }\n    //\n    //    if (!closeOk)\n    //        PhEnableEMenuItem(Menu, ID_NETWORK_CLOSE, FALSE);\n    //}\n}\n\nVOID PhShowNetworkContextMenu(\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    )\n{\n    PH_PLUGIN_MENU_INFORMATION menuInfo;\n    PPH_NETWORK_ITEM *networkItems;\n    ULONG numberOfNetworkItems;\n\n    PhGetSelectedNetworkItems(&networkItems, &numberOfNetworkItems);\n\n    if (numberOfNetworkItems != 0)\n    {\n        PPH_EMENU menu;\n        PPH_EMENU_ITEM item;\n\n        menu = PhCreateEMenu();\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_NETWORK_GOTOPROCESS, L\"&Go to process\\bEnter\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_NETWORK_GOTOSERVICE, L\"Go to service\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_NETWORK_CLOSE, L\"C&lose\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_NETWORK_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n        PhSetFlagsEMenuItem(menu, ID_NETWORK_GOTOPROCESS, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n        PhMwpInitializeNetworkMenu(menu, networkItems, numberOfNetworkItems);\n        PhInsertCopyCellEMenuItem(menu, ID_NETWORK_COPY, PhMwpNetworkTreeNewHandle, ContextMenu->Column);\n\n        if (PhPluginsEnabled)\n        {\n            PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, 0);\n            menuInfo.u.Network.NetworkItems = networkItems;\n            menuInfo.u.Network.NumberOfNetworkItems = numberOfNetworkItems;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkMenuInitializing), &menuInfo);\n        }\n\n        item = PhShowEMenu(\n            menu,\n            PhMainWndHandle,\n            PH_EMENU_SHOW_LEFTRIGHT,\n            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n            ContextMenu->Location.x,\n            ContextMenu->Location.y\n            );\n\n        if (item)\n        {\n            BOOLEAN handled = FALSE;\n\n            handled = PhHandleCopyCellEMenuItem(item);\n\n            if (!handled && PhPluginsEnabled)\n                handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n            if (!handled)\n                SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0);\n        }\n\n        PhDestroyEMenu(menu);\n    }\n\n    PhFree(networkItems);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpNetworkItemAddedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter;\n\n    PhReferenceObject(networkItem);\n    PhPushProviderEventQueue(&PhMwpNetworkEventQueue, ProviderAddedEvent, Parameter, PhGetRunIdProvider(&PhMwpNetworkProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpNetworkItemModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter;\n\n    PhPushProviderEventQueue(&PhMwpNetworkEventQueue, ProviderModifiedEvent, Parameter, PhGetRunIdProvider(&PhMwpNetworkProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpNetworkItemRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter;\n\n    PhPushProviderEventQueue(&PhMwpNetworkEventQueue, ProviderRemovedEvent, Parameter, PhGetRunIdProvider(&PhMwpNetworkProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpNetworkItemsUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    SystemInformer_Invoke(PhMwpOnNetworkItemsUpdated, PhGetRunIdProvider(&PhMwpProcessProviderRegistration));\n}\n\nVOID PhMwpOnNetworkItemsUpdated(\n    _In_ ULONG RunId\n    )\n{\n    PPH_PROVIDER_EVENT events;\n    ULONG count;\n    ULONG i;\n\n    events = PhFlushProviderEventQueue(&PhMwpNetworkEventQueue, RunId, &count);\n\n    if (events)\n    {\n        TreeNew_SetRedraw(PhMwpNetworkTreeNewHandle, FALSE);\n\n        for (i = 0; i < count; i++)\n        {\n            PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]);\n            PPH_NETWORK_ITEM networkItem = PH_PROVIDER_EVENT_OBJECT(events[i]);\n\n            switch (type)\n            {\n            case ProviderAddedEvent:\n                PhAddNetworkNode(networkItem, events[i].RunId);\n                PhDereferenceObject(networkItem);\n                break;\n            case ProviderModifiedEvent:\n                PhUpdateNetworkNode(PhFindNetworkNode(networkItem));\n                break;\n            case ProviderRemovedEvent:\n                PhRemoveNetworkNode(PhFindNetworkNode(networkItem));\n                break;\n            }\n        }\n\n        PhFree(events);\n    }\n\n    PhTickNetworkNodes();\n\n    if (count != 0)\n        TreeNew_SetRedraw(PhMwpNetworkTreeNewHandle, TRUE);\n}\n"
  },
  {
    "path": "SystemInformer/mwpgproc.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <mainwnd.h>\n\n#include <emenu.h>\n#include <verify.h>\n#include <phsettings.h>\n\n#include <actions.h>\n#include <colsetmgr.h>\n#include <phplug.h>\n#include <procprp.h>\n#include <procprv.h>\n#include <proctree.h>\n#include <settings.h>\n\n#include <mainwndp.h>\n\nPPH_MAIN_TAB_PAGE PhMwpProcessesPage;\nHWND PhMwpProcessTreeNewHandle;\nHWND PhMwpSelectedProcessWindowHandle;\nBOOLEAN PhMwpSelectedProcessVirtualizationEnabled;\nPH_PROVIDER_EVENT_QUEUE PhMwpProcessEventQueue;\n\nstatic PH_CALLBACK_REGISTRATION ProcessAddedRegistration;\nstatic PH_CALLBACK_REGISTRATION ProcessModifiedRegistration;\nstatic PH_CALLBACK_REGISTRATION ProcessRemovedRegistration;\nstatic PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;\n\nstatic ULONG NeedsSelectPid = 0;\nstatic ULONG ProcessEndToScrollTo = 0;\nstatic PPH_PROCESS_NODE ProcessToScrollTo = NULL;\nstatic PPH_TN_FILTER_ENTRY CurrentUserFilterEntry = NULL;\nstatic PPH_TN_FILTER_ENTRY SignedFilterEntry = NULL;\nstatic PPH_TN_FILTER_ENTRY MicrosoftSignedFilterEntry = NULL;\n\n_Function_class_(PH_MAIN_TAB_PAGE_CALLBACK)\nBOOLEAN PhMwpProcessesPageCallback(\n    _In_ PPH_MAIN_TAB_PAGE Page,\n    _In_ PH_MAIN_TAB_PAGE_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case MainTabPageCreate:\n        {\n            PhMwpProcessesPage = Page;\n\n            PhInitializeProviderEventQueue(&PhMwpProcessEventQueue, 100);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderAddedEvent),\n                PhMwpProcessAddedHandler,\n                NULL,\n                &ProcessAddedRegistration\n                );\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderModifiedEvent),\n                PhMwpProcessModifiedHandler,\n                NULL,\n                &ProcessModifiedRegistration\n                );\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderRemovedEvent),\n                PhMwpProcessRemovedHandler,\n                NULL,\n                &ProcessRemovedRegistration\n                );\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n                PhMwpProcessesUpdatedHandler,\n                NULL,\n                &ProcessesUpdatedRegistration\n                );\n\n            NeedsSelectPid = PhStartupParameters.SelectPid;\n        }\n        break;\n    case MainTabPageCreateWindow:\n        {\n            *(HWND *)Parameter1 = PhMwpProcessTreeNewHandle;\n        }\n        return TRUE;\n    case MainTabPageInitializeSectionMenuItems:\n        {\n            PPH_MAIN_TAB_PAGE_MENU_INFORMATION menuInfo = Parameter1;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM menuItem;\n            PPH_EMENU_ITEM columnSetMenuItem;\n\n            menu = PhCreateEMenuItem(0, 0, L\"Processes\", NULL, NULL);\n            PhInsertEMenuItem(menuInfo->Menu, menu, menuInfo->StartIndex);\n\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_COLLAPSEALL, L\"&Collapse all\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_EXPANDALL, L\"&Expand all\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS, L\"&Hide processes from other users\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDESIGNEDPROCESSES, L\"Hide si&gned processes\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEMICROSOFTPROCESSES, L\"Hide &system processes\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SCROLLTONEWPROCESSES, L\"Scrol&l to new processes\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SORTCHILDPROCESSES, L\"Sort &child processes\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SORTROOTPROCESSES, L\"Sort &root processes\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SHOWCPUBELOW001, L\"Show CPU &below 0.01\", NULL, NULL), ULONG_MAX);\n\n            if (PhGetIntegerSetting(SETTING_HIDE_OTHER_USER_PROCESSES) && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS)))\n                menuItem->Flags |= PH_EMENU_CHECKED;\n            if (PhGetIntegerSetting(SETTING_HIDE_SIGNED_PROCESSES) && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_HIDESIGNEDPROCESSES)))\n                menuItem->Flags |= PH_EMENU_CHECKED;\n            if (PhGetIntegerSetting(SETTING_HIDE_MICROSOFT_PROCESSES) && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_HIDEMICROSOFTPROCESSES)))\n                menuItem->Flags |= PH_EMENU_CHECKED;\n            if (PhCsScrollToNewProcesses && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_SCROLLTONEWPROCESSES)))\n                menuItem->Flags |= PH_EMENU_CHECKED;\n            if (PhCsSortChildProcesses && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_SORTCHILDPROCESSES)))\n                menuItem->Flags |= PH_EMENU_CHECKED;\n            if (PhCsSortRootProcesses && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_SORTROOTPROCESSES)))\n                menuItem->Flags |= PH_EMENU_CHECKED;\n\n            if (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_SHOWCPUBELOW001))\n            {\n                if (PhEnableCycleCpuUsage)\n                {\n                    if (PhCsShowCpuBelow001)\n                        menuItem->Flags |= PH_EMENU_CHECKED;\n                }\n                else\n                {\n                    menuItem->Flags |= PH_EMENU_DISABLED;\n                }\n            }\n\n            PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n            PhInsertEMenuItem(menu, menuItem = PhCreateEMenuItem(0, ID_VIEW_ORGANIZECOLUMNSETS, L\"Organi&ze column sets...\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SAVECOLUMNSET, L\"Sa&ve column set...\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, columnSetMenuItem = PhCreateEMenuItem(0, 0, L\"Loa&d column set\", NULL, NULL), ULONG_MAX);\n\n            // Add column set sub menu entries.\n            {\n                ULONG index;\n                PPH_LIST columnSetList;\n\n                columnSetList = PhInitializeColumnSetList(SETTING_PROCESS_TREE_COLUMN_SET_CONFIG);\n\n                if (!columnSetList->Count)\n                {\n                    menuItem->Flags |= PH_EMENU_DISABLED;\n                    columnSetMenuItem->Flags |= PH_EMENU_DISABLED;\n                }\n                else\n                {\n                    for (index = 0; index < columnSetList->Count; index++)\n                    {\n                        PPH_COLUMN_SET_ENTRY entry = columnSetList->Items[index];\n\n                        menuItem = PhCreateEMenuItem(PH_EMENU_TEXT_OWNED, ID_VIEW_LOADCOLUMNSET,\n                            PhAllocateCopy(entry->Name->Buffer, entry->Name->Length + sizeof(UNICODE_NULL)), NULL, NULL);\n                        PhInsertEMenuItem(columnSetMenuItem, menuItem, ULONG_MAX);\n                    }\n                }\n\n                PhDeleteColumnSetList(columnSetList);\n            }\n        }\n        return TRUE;\n    case MainTabPageLoadSettings:\n        {\n            PhLoadSettingsProcessTreeList();\n\n            if (PhGetIntegerSetting(SETTING_HIDE_OTHER_USER_PROCESSES))\n                CurrentUserFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), PhMwpCurrentUserProcessTreeFilter, NULL);\n\n            if (PhGetIntegerSetting(SETTING_HIDE_SIGNED_PROCESSES))\n                SignedFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), PhMwpSignedProcessTreeFilter, NULL);\n\n            if (PhGetIntegerSetting(SETTING_HIDE_MICROSOFT_PROCESSES))\n                MicrosoftSignedFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), PhMwpMicrosoftProcessTreeFilter, NULL);\n        }\n        return TRUE;\n    case MainTabPageSaveSettings:\n        {\n            PhSaveSettingsProcessTreeList();\n        }\n        return TRUE;\n    case MainTabPageExportContent:\n        {\n            PPH_MAIN_TAB_PAGE_EXPORT_CONTENT exportContent = Parameter1;\n\n            PhWriteProcessTree(exportContent->FileStream, exportContent->Mode);\n        }\n        return TRUE;\n    case MainTabPageFontChanged:\n        {\n            HFONT font = (HFONT)Parameter1;\n\n            SetWindowFont(PhMwpProcessTreeNewHandle, font, TRUE);\n        }\n        break;\n    case MainTabPageUpdateAutomaticallyChanged:\n        {\n            BOOLEAN updateAutomatically = (BOOLEAN)PtrToUlong(Parameter1);\n\n            PhSetEnabledProvider(&PhMwpProcessProviderRegistration, updateAutomatically);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhMwpShowProcessProperties(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_PROCESS_PROPCONTEXT propContext;\n\n    propContext = PhCreateProcessPropContext(\n        NULL,\n        ProcessItem\n        );\n\n    if (propContext)\n    {\n        PhShowProcessProperties(propContext);\n        PhDereferenceObject(propContext);\n    }\n}\n\nVOID PhMwpToggleCurrentUserProcessTreeFilter(\n    VOID\n    )\n{\n    if (!CurrentUserFilterEntry)\n    {\n        CurrentUserFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), PhMwpCurrentUserProcessTreeFilter, NULL);\n    }\n    else\n    {\n        PhRemoveTreeNewFilter(PhGetFilterSupportProcessTreeList(), CurrentUserFilterEntry);\n        CurrentUserFilterEntry = NULL;\n\n        // Expand the nodes to ensure that they will be visible to the user. (dmex)\n        PhExpandAllProcessNodes(TRUE);\n        PhDeselectAllProcessNodes();\n    }\n\n    PhApplyTreeNewFilters(PhGetFilterSupportProcessTreeList());\n\n    PhSetIntegerSetting(SETTING_HIDE_OTHER_USER_PROCESSES, !!CurrentUserFilterEntry);\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpCurrentUserProcessTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node;\n\n    if (!processNode->ProcessItem->Sid)\n        return FALSE;\n\n    if (!PhEqualSid(processNode->ProcessItem->Sid, PhGetOwnTokenAttributes().TokenSid))\n        return FALSE;\n\n    return TRUE;\n}\n\nVOID PhMwpToggleSignedProcessTreeFilter(\n    _In_ HWND WindowHandle\n    )\n{\n    if (!SignedFilterEntry)\n    {\n        if (!PhEnableProcessQueryStage2)\n        {\n            PhShowInformation2(\n                WindowHandle,\n                NULL,\n                L\"This filter cannot function because digital signature checking is not enabled.\\r\\n%s\",\n                L\"Enable it in Options > General and restart System Informer.\"\n                );\n            return;\n        }\n\n        SignedFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), PhMwpSignedProcessTreeFilter, NULL);\n    }\n    else\n    {\n        PhRemoveTreeNewFilter(PhGetFilterSupportProcessTreeList(), SignedFilterEntry);\n        SignedFilterEntry = NULL;\n\n        // Expand the nodes to ensure that they will be visible to the user. (dmex)\n        PhExpandAllProcessNodes(TRUE);\n        PhDeselectAllProcessNodes();\n    }\n\n    PhApplyTreeNewFilters(PhGetFilterSupportProcessTreeList());\n\n    PhSetIntegerSetting(SETTING_HIDE_SIGNED_PROCESSES, !!SignedFilterEntry);\n}\n\nVOID PhMwpToggleMicrosoftProcessTreeFilter(\n    VOID\n    )\n{\n    if (!MicrosoftSignedFilterEntry)\n    {\n        MicrosoftSignedFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), PhMwpMicrosoftProcessTreeFilter, NULL);\n    }\n    else\n    {\n        PhRemoveTreeNewFilter(PhGetFilterSupportProcessTreeList(), MicrosoftSignedFilterEntry);\n        MicrosoftSignedFilterEntry = NULL;\n\n        // Expand the nodes to ensure that they will be visible to the user. (dmex)\n        PhExpandAllProcessNodes(TRUE);\n        PhDeselectAllProcessNodes();\n    }\n\n    PhApplyTreeNewFilters(PhGetFilterSupportProcessTreeList());\n\n    PhSetIntegerSetting(SETTING_HIDE_MICROSOFT_PROCESSES, !!MicrosoftSignedFilterEntry);\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpSignedProcessTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node;\n\n    if (processNode->ProcessItem->VerifyResult == VrTrusted)\n        return FALSE;\n\n    return TRUE;\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpMicrosoftProcessTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node;\n\n    if (PhEnableProcessQueryStage2)\n    {\n        if (!PhIsNullOrEmptyString(processNode->ProcessItem->VerifySignerName))\n        {\n            static CONST PH_STRINGREF microsoftSignerNameSr = PH_STRINGREF_INIT(L\"Microsoft Windows\");\n\n            if (PhEqualStringRef(&processNode->ProcessItem->VerifySignerName->sr, &microsoftSignerNameSr, TRUE))\n                return FALSE;\n        }\n    }\n    else\n    {\n        if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.CompanyName))\n        {\n            static CONST PH_STRINGREF microsoftCompanyNameSr = PH_STRINGREF_INIT(L\"Microsoft\");\n\n            if (PhStartsWithStringRef(&processNode->ProcessItem->VersionInfo.CompanyName->sr, &microsoftCompanyNameSr, TRUE))\n                return FALSE;\n        }\n    }\n\n    return TRUE;\n}\n\nBOOLEAN PhMwpExecuteProcessPriorityClassCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    ULONG priorityClass;\n\n    switch (Id)\n    {\n    case ID_PRIORITY_REALTIME:\n        priorityClass = PROCESS_PRIORITY_CLASS_REALTIME;\n        break;\n    case ID_PRIORITY_HIGH:\n        priorityClass = PROCESS_PRIORITY_CLASS_HIGH;\n        break;\n    case ID_PRIORITY_ABOVENORMAL:\n        priorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;\n        break;\n    case ID_PRIORITY_NORMAL:\n        priorityClass = PROCESS_PRIORITY_CLASS_NORMAL;\n        break;\n    case ID_PRIORITY_BELOWNORMAL:\n        priorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;\n        break;\n    case ID_PRIORITY_IDLE:\n        priorityClass = PROCESS_PRIORITY_CLASS_IDLE;\n        break;\n    default:\n        return FALSE;\n    }\n\n    PhUiSetPriorityClassProcesses(WindowHandle, Processes, NumberOfProcesses, priorityClass);\n\n    return TRUE;\n}\n\nBOOLEAN PhMwpExecuteProcessIoPriorityCommand(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    IO_PRIORITY_HINT ioPriority;\n\n    switch (Id)\n    {\n    case ID_IOPRIORITY_VERYLOW:\n        ioPriority = IoPriorityVeryLow;\n        break;\n    case ID_IOPRIORITY_LOW:\n        ioPriority = IoPriorityLow;\n        break;\n    case ID_IOPRIORITY_NORMAL:\n        ioPriority = IoPriorityNormal;\n        break;\n    case ID_IOPRIORITY_HIGH:\n        ioPriority = IoPriorityHigh;\n        break;\n    default:\n        return FALSE;\n    }\n\n    PhUiSetIoPriorityProcesses(WindowHandle, Processes, NumberOfProcesses, ioPriority);\n\n    return TRUE;\n}\n\nVOID PhMwpSetProcessMenuPriorityChecks(\n    _In_ PPH_EMENU Menu,\n    _In_opt_ HANDLE ProcessId,\n    _In_ BOOLEAN SetPriority,\n    _In_ BOOLEAN SetIoPriority,\n    _In_ BOOLEAN SetPagePriority\n    )\n{\n    HANDLE processHandle;\n    UCHAR priorityClass = PROCESS_PRIORITY_CLASS_UNKNOWN;\n    IO_PRIORITY_HINT ioPriority = ULONG_MAX;\n    ULONG pagePriority = ULONG_MAX;\n    ULONG id = 0;\n\n    if (NT_SUCCESS(PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        ProcessId\n        )))\n    {\n        if (SetPriority)\n        {\n            if (!NT_SUCCESS(PhGetProcessPriorityClass(\n                processHandle,\n                &priorityClass\n                )))\n            {\n                priorityClass = PROCESS_PRIORITY_CLASS_UNKNOWN;\n            }\n        }\n\n        if (SetIoPriority)\n        {\n            if (!NT_SUCCESS(PhGetProcessIoPriority(\n                processHandle,\n                &ioPriority\n                )))\n            {\n                ioPriority = ULONG_MAX;\n            }\n        }\n\n        if (SetPagePriority)\n        {\n            if (!NT_SUCCESS(PhGetProcessPagePriority(\n                processHandle,\n                &pagePriority\n                )))\n            {\n                pagePriority = ULONG_MAX;\n            }\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (SetPriority && priorityClass != PROCESS_PRIORITY_CLASS_UNKNOWN)\n    {\n        switch (priorityClass)\n        {\n        case PROCESS_PRIORITY_CLASS_REALTIME:\n            id = ID_PRIORITY_REALTIME;\n            break;\n        case PROCESS_PRIORITY_CLASS_HIGH:\n            id = ID_PRIORITY_HIGH;\n            break;\n        case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL:\n            id = ID_PRIORITY_ABOVENORMAL;\n            break;\n        case PROCESS_PRIORITY_CLASS_NORMAL:\n            id = ID_PRIORITY_NORMAL;\n            break;\n        case PROCESS_PRIORITY_CLASS_BELOW_NORMAL:\n            id = ID_PRIORITY_BELOWNORMAL;\n            break;\n        case PROCESS_PRIORITY_CLASS_IDLE:\n            id = ID_PRIORITY_IDLE;\n            break;\n        }\n\n        if (id != 0)\n        {\n            PhSetFlagsEMenuItem(Menu, id,\n                PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,\n                PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);\n        }\n    }\n\n    if (SetIoPriority && ioPriority != ULONG_MAX)\n    {\n        id = 0;\n\n        switch (ioPriority)\n        {\n        case IoPriorityVeryLow:\n            id = ID_IOPRIORITY_VERYLOW;\n            break;\n        case IoPriorityLow:\n            id = ID_IOPRIORITY_LOW;\n            break;\n        case IoPriorityNormal:\n            id = ID_IOPRIORITY_NORMAL;\n            break;\n        case IoPriorityHigh:\n            id = ID_IOPRIORITY_HIGH;\n            break;\n        }\n\n        if (id != 0)\n        {\n            PhSetFlagsEMenuItem(Menu, id,\n                PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,\n                PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);\n        }\n    }\n\n    if (SetPagePriority && pagePriority != ULONG_MAX)\n    {\n        id = 0;\n\n        switch (pagePriority)\n        {\n        case MEMORY_PRIORITY_VERY_LOW:\n            id = ID_PAGEPRIORITY_VERYLOW;\n            break;\n        case MEMORY_PRIORITY_LOW:\n            id = ID_PAGEPRIORITY_LOW;\n            break;\n        case MEMORY_PRIORITY_MEDIUM:\n            id = ID_PAGEPRIORITY_MEDIUM;\n            break;\n        case MEMORY_PRIORITY_BELOW_NORMAL:\n            id = ID_PAGEPRIORITY_BELOWNORMAL;\n            break;\n        case MEMORY_PRIORITY_NORMAL:\n            id = ID_PAGEPRIORITY_NORMAL;\n            break;\n        }\n\n        if (id != 0)\n        {\n            PhSetFlagsEMenuItem(Menu, id,\n                PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,\n                PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);\n        }\n    }\n}\n\nVOID PhMwpInitializeProcessMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ PPH_PROCESS_ITEM *Processes,\n    _In_ ULONG NumberOfProcesses\n    )\n{\n    PPH_EMENU_ITEM item;\n\n    if (NumberOfProcesses == 0)\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n    }\n    else if (NumberOfProcesses == 1)\n    {\n        // All menu items are enabled by default.\n\n        // If the user selected a fake process, disable all but a few menu items.\n        if (\n            PH_IS_FAKE_PROCESS_ID(Processes[0]->ProcessId) ||\n            Processes[0]->ProcessId == SYSTEM_IDLE_PROCESS_ID\n            //Processes[0]->ProcessId == SYSTEM_PROCESS_ID // (dmex)\n            )\n        {\n            PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n            PhEnableEMenuItem(Menu, ID_PROCESS_PROPERTIES, TRUE);\n            PhEnableEMenuItem(Menu, ID_PROCESS_SEARCHONLINE, TRUE);\n\n            // Enable the Miscellaneous menu item but disable its children.\n            if (item = PhFindEMenuItem(Menu, 0, 0, ID_PROCESS_MISCELLANEOUS))\n            {\n                PhSetEnabledEMenuItem(item, TRUE);\n                PhSetFlagsAllEMenuItems(item, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n            }\n        }\n\n        // Disable the restart menu for service host processes. (dmex)\n        if (\n            Processes[0]->ServiceList &&\n            Processes[0]->ServiceList->Count != 0\n            )\n        {\n            PhEnableEMenuItem(Menu, ID_PROCESS_RESTART, FALSE);\n        }\n\n        if (\n            PhIsNullOrEmptyString(Processes[0]->FileName) ||\n            !PhDoesFileExist(&Processes[0]->FileName->sr)\n            )\n        {\n            PhEnableEMenuItem(Menu, ID_PROCESS_OPENFILELOCATION, FALSE);\n        }\n\n        // Critical\n        if (Processes[0]->QueryHandle)\n        {\n            BOOLEAN breakOnTermination;\n\n            if (NT_SUCCESS(PhGetProcessBreakOnTermination(\n                Processes[0]->QueryHandle,\n                &breakOnTermination\n                )))\n            {\n                if (breakOnTermination)\n                {\n                    PhSetFlagsEMenuItem(Menu, ID_MISCELLANEOUS_SETCRITICAL, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n                }\n            }\n        }\n\n        // Disable Terminate/Suspend/Resume tree when the process has no children.\n        {\n            PPH_PROCESS_NODE node = PhFindProcessNode(Processes[0]->ProcessId);\n\n            if (node && !(node->Children && node->Children->Count))\n            {\n                PhEnableEMenuItem(Menu, ID_PROCESS_TERMINATETREE, FALSE);\n                PhEnableEMenuItem(Menu, ID_PROCESS_SUSPENDTREE, FALSE);\n                PhEnableEMenuItem(Menu, ID_PROCESS_RESUMETREE, FALSE);\n            }\n        }\n\n        // Eco mode\n        if (WindowsVersion < WINDOWS_10_RS4)\n        {\n            PhEnableEMenuItem(Menu, ID_MISCELLANEOUS_ECOMODE, FALSE);\n        }\n        else\n        {\n            if (Processes[0]->QueryHandle)\n            {\n                POWER_THROTTLING_PROCESS_STATE powerThrottlingState;\n\n                if (NT_SUCCESS(PhGetProcessPowerThrottlingState(\n                    Processes[0]->QueryHandle,\n                    &powerThrottlingState\n                    )))\n                {\n                    if (\n                        powerThrottlingState.ControlMask & POWER_THROTTLING_PROCESS_EXECUTION_SPEED &&\n                        powerThrottlingState.StateMask & POWER_THROTTLING_PROCESS_EXECUTION_SPEED\n                        )\n                    {\n                        PhSetFlagsEMenuItem(Menu, ID_MISCELLANEOUS_ECOMODE, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n                    }\n                }\n            }\n        }\n\n        // Execution Required requests\n        if (WindowsVersion < WINDOWS_8)\n        {\n            PhEnableEMenuItem(Menu, ID_MISCELLANEOUS_EXECUTIONREQUIRED, FALSE);\n        }\n        else\n        {\n            if (PhIsProcessExecutionRequired(Processes[0]->ProcessId))\n            {\n                PhSetFlagsEMenuItem(Menu, ID_MISCELLANEOUS_EXECUTIONREQUIRED, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n            }\n        }\n\n        if (WindowsVersion < WINDOWS_11)\n        {\n            if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_FREEZE))\n                PhDestroyEMenuItem(item);\n            if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_THAW))\n                PhDestroyEMenuItem(item);\n        }\n    }\n    else\n    {\n        ULONG menuItemsMultiEnabled[] =\n        {\n            ID_PROCESS_TERMINATE,\n            ID_PROCESS_SUSPEND,\n            ID_PROCESS_RESUME,\n            //ID_PROCESS_THAW,\n            //ID_PROCESS_FREEZE,\n            ID_MISCELLANEOUS_REDUCEWORKINGSET,\n            ID_PROCESS_COPY\n        };\n        ULONG i;\n\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n\n        // Enable the Miscellaneous menu item but disable its children.\n        if (item = PhFindEMenuItem(Menu, 0, 0, ID_PROCESS_MISCELLANEOUS))\n        {\n            item->Flags &= ~PH_EMENU_DISABLED;\n            PhSetFlagsAllEMenuItems(item, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n        }\n\n        // Enable the Priority menu item.\n        if (item = PhFindEMenuItem(Menu, 0, 0, ID_PROCESS_PRIORITYCLASS))\n            item->Flags &= ~PH_EMENU_DISABLED;\n\n        // Enable the I/O Priority menu item.\n        if (item = PhFindEMenuItem(Menu, 0, 0, ID_PROCESS_IOPRIORITY))\n            item->Flags &= ~PH_EMENU_DISABLED;\n\n        // These menu items are capable of manipulating\n        // multiple processes.\n        for (i = 0; i < sizeof(menuItemsMultiEnabled) / sizeof(ULONG); i++)\n        {\n            PhSetFlagsEMenuItem(Menu, menuItemsMultiEnabled[i], PH_EMENU_DISABLED, 0);\n        }\n    }\n\n    // Suspend/Resume\n    if (NumberOfProcesses == 1)\n    {\n        if (Processes[0]->IsSuspended)\n        {\n            if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_SUSPEND))\n                PhDestroyEMenuItem(item);\n            if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_SUSPENDTREE))\n                PhDestroyEMenuItem(item);\n        }\n        else\n        {\n            if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_RESUME))\n                PhDestroyEMenuItem(item);\n            if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_RESUMETREE))\n                PhDestroyEMenuItem(item);\n        }\n\n        if (WindowsVersion >= WINDOWS_11 && PH_IS_REAL_PROCESS_ID(Processes[0]->ProcessId))\n        {\n            if (!PhIsNullOrInvalidHandle(Processes[0]->FreezeHandle))\n            {\n                if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_FREEZE))\n                    PhDestroyEMenuItem(item);\n            }\n            else\n            {\n                if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_THAW))\n                    PhDestroyEMenuItem(item);\n            }\n        }\n    }\n\n    // Virtualization\n    if (NumberOfProcesses == 1)\n    {\n        HANDLE tokenHandle;\n        BOOLEAN allowed = FALSE;\n        BOOLEAN enabled = FALSE;\n\n        if (Processes[0]->QueryHandle)\n        {\n            if (NT_SUCCESS(PhOpenProcessToken(\n                Processes[0]->QueryHandle,\n                TOKEN_QUERY,\n                &tokenHandle\n                )))\n            {\n                PhGetTokenIsVirtualizationAllowed(tokenHandle, &allowed);\n                PhGetTokenIsVirtualizationEnabled(tokenHandle, &enabled);\n                PhMwpSelectedProcessVirtualizationEnabled = enabled;\n\n                NtClose(tokenHandle);\n            }\n        }\n\n        if (!allowed)\n            PhSetFlagsEMenuItem(Menu, ID_PROCESS_VIRTUALIZATION, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n        else if (enabled)\n            PhSetFlagsEMenuItem(Menu, ID_PROCESS_VIRTUALIZATION, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n    }\n\n    // Priority\n    if (NumberOfProcesses == 1)\n    {\n        PhMwpSetProcessMenuPriorityChecks(Menu, Processes[0]->ProcessId, TRUE, TRUE, TRUE);\n    }\n\n    item = PhFindEMenuItem(Menu, 0, 0, ID_PROCESS_WINDOW);\n\n    if (item)\n    {\n        // Window menu\n        if (NumberOfProcesses == 1)\n        {\n            // Get a handle to the process' top-level window (if any).\n            PhMwpSelectedProcessWindowHandle = PhGetProcessMainWindow(Processes[0]->ProcessId, Processes[0]->QueryHandle);\n\n            if (!PhMwpSelectedProcessWindowHandle)\n                item->Flags |= PH_EMENU_DISABLED;\n\n            if (PhMwpSelectedProcessWindowHandle)\n            {\n                WINDOWPLACEMENT placement = { sizeof(placement) };\n\n                GetWindowPlacement(PhMwpSelectedProcessWindowHandle, &placement);\n\n                if (placement.showCmd == SW_MINIMIZE)\n                    PhEnableEMenuItem(item, ID_WINDOW_MINIMIZE, FALSE);\n                else if (placement.showCmd == SW_MAXIMIZE)\n                    PhEnableEMenuItem(item, ID_WINDOW_MAXIMIZE, FALSE);\n                else if (placement.showCmd == SW_NORMAL)\n                    PhEnableEMenuItem(item, ID_WINDOW_RESTORE, FALSE);\n            }\n        }\n        else\n        {\n            item->Flags |= PH_EMENU_DISABLED;\n        }\n    }\n}\n\nPPH_EMENU PhpCreateProcessMenu(\n    _In_ BOOLEAN SystemProcess\n    )\n{\n    PPH_EMENU menu;\n    PPH_EMENU_ITEM menuItem;\n\n    menu = PhCreateEMenu();\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATE, L\"T&erminate\\bDel\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATETREE, L\"Terminate tree\\bShift+Del\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPEND, L\"&Suspend\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPENDTREE, L\"Suspend tree\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_RESUME, L\"Res&ume\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_RESUMETREE, L\"Resume tree\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_FREEZE, L\"Freeze\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_THAW, L\"Thaw\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_RESTART, L\"Res&tart\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n\n    if (SystemProcess)\n    {\n        PPH_EMENU kernelMinimal;\n\n        menuItem = PhCreateEMenuItem(0, ID_PROCESS_CREATEDUMPFILE, L\"Create live kernel dump fi&le\", NULL, NULL);\n        PhInsertEMenuItem(menuItem, kernelMinimal = PhCreateEMenuItem(0, ID_PROCESS_DUMP_MINIMAL, L\"&Minimal...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_NORMAL, L\"&Normal...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_FULL, L\"&Full...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_CUSTOM, L\"&Custom...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n        if (!PhGetOwnTokenAttributes().Elevated)\n        {\n            menuItem->Flags |= PH_EMENU_DISABLED;\n        }\n        else if (WindowsVersion < WINDOWS_11)\n        {\n            // Minimal only captures thread stacks, not supported before Windows 11\n            PhSetDisabledEMenuItem(kernelMinimal);\n        }\n    }\n    else\n    {\n        menuItem = PhCreateEMenuItem(0, ID_PROCESS_CREATEDUMPFILE, L\"Create dump fi&le\", NULL, NULL);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_MINIMAL, L\"&Minimal...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_LIMITED, L\"&Limited...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_NORMAL, L\"&Normal...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_FULL, L\"&Full...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_CUSTOM, L\"&Custom...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n    }\n\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_DEBUG, L\"De&bug\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_AFFINITY, L\"&Affinity\", NULL, NULL), ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, ID_PROCESS_PRIORITYCLASS, L\"&Priority\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L\"&Real time\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L\"&High\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L\"&Above normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L\"&Normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L\"&Below normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L\"&Idle\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, ID_PROCESS_IOPRIORITY, L\"&I/O priority\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L\"&High\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L\"&Normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L\"&Low\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L\"&Very low\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, ID_PROCESS_PAGEPRIORITY, L\"Pa&ge priority\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_NORMAL, L\"&Normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_BELOWNORMAL, L\"&Below normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_MEDIUM, L\"&Medium\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_LOW, L\"&Low\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_VERYLOW, L\"&Very low\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, ID_PROCESS_MISCELLANEOUS, L\"&Miscellaneous\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_ACTIVITY, L\"Activity moderation\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_SETCRITICAL, L\"&Critical\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_DETACHFROMDEBUGGER, L\"&Detach from debugger\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_ECOMODE, L\"Efficiency mode\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_EXECUTIONREQUIRED, L\"Execution required\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_GDIHANDLES, L\"GDI &handles...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_HEAPS, L\"Heaps...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_LOCKS, L\"Locks...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_FLUSHHEAPS, L\"Flush heaps\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_PAGESMODIFIED, L\"Modified pages...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_REDUCEWORKINGSET, L\"Reduce working &set\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_RUNAS, L\"&Run as...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_RUNASTHISUSER, L\"Run &as this user...\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_VIRTUALIZATION, L\"Virtuali&zation\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, ID_PROCESS_WINDOW, L\"&Window\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_WINDOW_BRINGTOFRONT, L\"Bring to &front\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_WINDOW_RESTORE, L\"&Restore\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_WINDOW_MINIMIZE, L\"M&inimize\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_WINDOW_MAXIMIZE, L\"M&aximize\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_WINDOW_CLOSE, L\"&Close\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_SEARCHONLINE, L\"Search &online\\bCtrl+M\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_OPENFILELOCATION, L\"Open &file location\\bCtrl+Enter\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_PROPERTIES, L\"P&roperties\\bEnter\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n\n    return menu;\n}\n\nVOID PhShowProcessContextMenu(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    )\n{\n    PH_PLUGIN_MENU_INFORMATION menuInfo;\n    PPH_PROCESS_ITEM *processes;\n    ULONG numberOfProcesses;\n\n    if (PhGetSelectedProcessItems(&processes, &numberOfProcesses))\n    {\n        PPH_EMENU menu;\n        PPH_EMENU_ITEM item;\n\n        if (numberOfProcesses == 1 && processes[0]->ProcessId == SYSTEM_PROCESS_ID)\n            menu = PhpCreateProcessMenu(TRUE);\n        else\n            menu = PhpCreateProcessMenu(FALSE);\n\n        PhSetFlagsEMenuItem(menu, ID_PROCESS_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n\n        PhMwpInitializeProcessMenu(menu, processes, numberOfProcesses);\n        PhInsertCopyCellEMenuItem(menu, ID_PROCESS_COPY, PhMwpProcessTreeNewHandle, ContextMenu->Column);\n\n        if (PhPluginsEnabled)\n        {\n            PhPluginInitializeMenuInfo(&menuInfo, menu, WindowHandle, 0);\n            menuInfo.u.Process.Processes = processes;\n            menuInfo.u.Process.NumberOfProcesses = numberOfProcesses;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), &menuInfo);\n        }\n\n        item = PhShowEMenu(\n            menu,\n            WindowHandle,\n            PH_EMENU_SHOW_LEFTRIGHT,\n            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n            ContextMenu->Location.x,\n            ContextMenu->Location.y\n            );\n\n        if (item)\n        {\n            BOOLEAN handled = FALSE;\n\n            handled = PhHandleCopyCellEMenuItem(item);\n\n            if (!handled && PhPluginsEnabled)\n                handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n            if (!handled)\n                SendMessage(WindowHandle, WM_COMMAND, item->Id, 0);\n        }\n\n        PhDestroyEMenu(menu);\n\n        PhFree(processes);\n    }\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpProcessAddedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;\n\n    // Reference the process item so it doesn't get deleted before\n    // we handle the event in the main thread.\n    PhReferenceObject(processItem);\n    PhPushProviderEventQueue(&PhMwpProcessEventQueue, ProviderAddedEvent, Parameter, PhGetRunIdProvider(&PhMwpProcessProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpProcessModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;\n\n    PhPushProviderEventQueue(&PhMwpProcessEventQueue, ProviderModifiedEvent, Parameter, PhGetRunIdProvider(&PhMwpProcessProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpProcessRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;\n\n    // We already have a reference to the process item, so we don't need to\n    // reference it here.\n    PhPushProviderEventQueue(&PhMwpProcessEventQueue, ProviderRemovedEvent, Parameter, PhGetRunIdProvider(&PhMwpProcessProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpProcessesUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    SystemInformer_Invoke(PhMwpOnProcessesUpdated, PhGetRunIdProvider(&PhMwpProcessProviderRegistration));\n}\n\nVOID PhMwpOnProcessAdded(\n    _In_ _Assume_refs_(1) PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG RunId\n    )\n{\n    PPH_PROCESS_NODE processNode;\n\n    processNode = PhAddProcessNode(ProcessItem, RunId);\n\n    if (RunId != 1)\n    {\n        PPH_PROCESS_ITEM parentProcess;\n        HANDLE parentProcessId = NULL;\n        PPH_STRING parentName = NULL;\n\n        if (parentProcess = PhReferenceProcessItemForParent(ProcessItem))\n        {\n            parentProcessId = parentProcess->ProcessId;\n            parentName = parentProcess->ProcessName;\n        }\n\n        PhLogProcessEntry(\n            PH_LOG_ENTRY_PROCESS_CREATE,\n            ProcessItem->ProcessId,\n            ProcessItem->ProcessName,\n            parentProcessId,\n            parentName,\n            0\n            );\n\n        if (PhMwpNotifyIconNotifyMask & PH_NOTIFY_PROCESS_CREATE)\n        {\n            if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_PROCESS_CREATE, ProcessItem))\n            {\n                PH_FORMAT format[9];\n                WCHAR formatBuffer[260];\n\n                PhMwpClearLastNotificationDetails();\n                PhMwpLastNotificationType = PH_NOTIFY_PROCESS_CREATE;\n                PhMwpLastNotificationDetails.ProcessId = ProcessItem->ProcessId;\n\n                // The process %s (%lu) was created by %s (%lu)\n                PhInitFormatS(&format[0], L\"The process \");\n                PhInitFormatSR(&format[1], ProcessItem->ProcessName->sr);\n                PhInitFormatS(&format[2], L\" (\");\n                PhInitFormatU(&format[3], HandleToUlong(ProcessItem->ProcessId));\n                PhInitFormatS(&format[4], L\") was created by \");\n                PhInitFormatS(&format[5], PhGetStringOrDefault(parentName, L\"Unknown process\")); // todo: SR type (dmex)\n                PhInitFormatS(&format[6], L\" (\");\n                PhInitFormatU(&format[7], HandleToUlong(ProcessItem->ParentProcessId));\n                PhInitFormatC(&format[8], L')');\n\n                if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n                {\n                    PhShowIconNotification(L\"Process Created\", formatBuffer);\n                }\n                else\n                {\n                    PhShowIconNotification(L\"Process Created\",\n                        PH_AUTO_T(PH_STRING, PhFormat(format, RTL_NUMBER_OF(format), 0))->Buffer);\n                }\n            }\n        }\n\n        if (parentProcess)\n            PhDereferenceObject(parentProcess);\n\n        if (PhCsScrollToNewProcesses)\n            ProcessToScrollTo = processNode;\n    }\n    else\n    {\n        if (NeedsSelectPid != 0)\n        {\n            if (processNode->ProcessId == UlongToHandle(NeedsSelectPid))\n                ProcessToScrollTo = processNode;\n        }\n    }\n\n    // PhCreateProcessNode has its own reference.\n    PhDereferenceObject(ProcessItem);\n}\n\nVOID PhMwpOnProcessModified(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PhUpdateProcessNode(PhFindProcessNode(ProcessItem->ProcessId));\n\n    if (SignedFilterEntry || MicrosoftSignedFilterEntry) // HACK: Invalidate filters when modified (dmex)\n        PhApplyTreeNewFilters(PhGetFilterSupportProcessTreeList());\n}\n\nVOID PhMwpOnProcessRemoved(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_PROCESS_NODE processNode;\n    ULONG processNodeIndex = 0;\n    ULONG exitStatus = 0;\n\n    if (ProcessItem->QueryHandle)\n    {\n        PROCESS_BASIC_INFORMATION basicInfo;\n\n        if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessItem->QueryHandle, &basicInfo)))\n        {\n            exitStatus = basicInfo.ExitStatus;\n        }\n    }\n\n    PhLogProcessEntry(PH_LOG_ENTRY_PROCESS_DELETE, ProcessItem->ProcessId, ProcessItem->ProcessName, NULL, NULL, exitStatus);\n\n    if (PhMwpNotifyIconNotifyMask & PH_NOTIFY_PROCESS_DELETE)\n    {\n        if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_PROCESS_DELETE, ProcessItem))\n        {\n            PH_FORMAT format[6];\n            WCHAR formatBuffer[260];\n\n            PhMwpClearLastNotificationDetails();\n            PhMwpLastNotificationType = PH_NOTIFY_PROCESS_DELETE;\n            PhMwpLastNotificationDetails.ProcessId = ProcessItem->ProcessId;\n\n            // The process %s (%lu) was terminated with status 0x%x\n            PhInitFormatS(&format[0], L\"The process \");\n            PhInitFormatSR(&format[1], ProcessItem->ProcessName->sr);\n            PhInitFormatS(&format[2], L\" (\");\n            PhInitFormatU(&format[3], HandleToUlong(ProcessItem->ProcessId));\n            PhInitFormatS(&format[4], L\") was terminated with status 0x\");\n            PhInitFormatX(&format[5], exitStatus);\n\n            if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n            {\n                PhShowIconNotification(L\"Process Terminated\", formatBuffer);\n            }\n            else\n            {\n                PhShowIconNotification(L\"Process Terminated\",\n                    PH_AUTO_T(PH_STRING, PhFormat(format, RTL_NUMBER_OF(format), 0))->Buffer);\n            }\n        }\n    }\n\n    processNode = PhFindProcessNode(ProcessItem->ProcessId);\n    processNodeIndex = processNode->Node.Index;\n    PhRemoveProcessNode(processNode);\n\n    if (ProcessToScrollTo == processNode) // shouldn't happen, but just in case\n        ProcessToScrollTo = NULL;\n\n    if (PhCsScrollToRemovedProcesses)\n    {\n        ProcessEndToScrollTo = processNodeIndex;\n    }\n}\n\nVOID PhMwpOnProcessesUpdated(\n    _In_ ULONG RunId\n    )\n{\n    PPH_PROVIDER_EVENT events;\n    ULONG count;\n    ULONG i;\n\n    events = PhFlushProviderEventQueue(&PhMwpProcessEventQueue, RunId, &count);\n\n    if (events)\n    {\n        TreeNew_SetRedraw(PhMwpProcessTreeNewHandle, FALSE);\n\n        for (i = 0; i < count; i++)\n        {\n            PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]);\n            PPH_PROCESS_ITEM processItem = PH_PROVIDER_EVENT_OBJECT(events[i]);\n\n            switch (type)\n            {\n            case ProviderAddedEvent:\n                PhMwpOnProcessAdded(processItem, events[i].RunId);\n                break;\n            case ProviderModifiedEvent:\n                PhMwpOnProcessModified(processItem);\n                break;\n            case ProviderRemovedEvent:\n                PhMwpOnProcessRemoved(processItem);\n                break;\n            }\n        }\n\n        PhFree(events);\n    }\n\n    // The modified notification is only sent for special cases.\n    // We have to invalidate the text on each update.\n    PhTickProcessNodes();\n\n    if (count != 0)\n    {\n        TreeNew_SetRedraw(PhMwpProcessTreeNewHandle, TRUE);\n    }\n\n    if (PhPluginsEnabled)\n    {\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessesUpdated), UlongToPtr(RunId));\n    }\n\n    if (NeedsSelectPid != 0)\n    {\n        if (ProcessToScrollTo)\n        {\n            PhSelectAndEnsureVisibleProcessNode(ProcessToScrollTo);\n            ProcessToScrollTo = NULL;\n        }\n\n        NeedsSelectPid = 0;\n    }\n\n    if (ProcessToScrollTo)\n    {\n        TreeNew_EnsureVisible(PhMwpProcessTreeNewHandle, &ProcessToScrollTo->Node);\n        ProcessToScrollTo = NULL;\n    }\n\n    if (ProcessEndToScrollTo)\n    {\n        count = TreeNew_GetFlatNodeCount(PhMwpProcessTreeNewHandle);\n\n        if (ProcessEndToScrollTo > count)\n            ProcessEndToScrollTo = count;\n\n        TreeNew_EnsureVisibleIndex(PhMwpProcessTreeNewHandle, ProcessEndToScrollTo);\n        ProcessEndToScrollTo = 0;\n    }\n}\n"
  },
  {
    "path": "SystemInformer/mwpgsrv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <emenu.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <settings.h>\n#include <srvlist.h>\n#include <srvprv.h>\n\n#include <mainwnd.h>\n#include <mainwndp.h>\n\nPPH_MAIN_TAB_PAGE PhMwpServicesPage;\nHWND PhMwpServiceTreeNewHandle;\nPH_PROVIDER_EVENT_QUEUE PhMwpServiceEventQueue;\n\nstatic PH_CALLBACK_REGISTRATION ServiceAddedRegistration;\nstatic PH_CALLBACK_REGISTRATION ServiceModifiedRegistration;\nstatic PH_CALLBACK_REGISTRATION ServiceRemovedRegistration;\nstatic PH_CALLBACK_REGISTRATION ServicesUpdatedRegistration;\n\nstatic BOOLEAN ServiceTreeListLoaded = FALSE;\nstatic PPH_TN_FILTER_ENTRY DriverFilterEntry = NULL;\nstatic PPH_TN_FILTER_ENTRY MicrosoftFilterEntry = NULL;\n\n_Function_class_(PH_MAIN_TAB_PAGE_CALLBACK)\nBOOLEAN PhMwpServicesPageCallback(\n    _In_ PPH_MAIN_TAB_PAGE Page,\n    _In_ PH_MAIN_TAB_PAGE_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case MainTabPageCreate:\n        {\n            PhMwpServicesPage = Page;\n\n            PhInitializeProviderEventQueue(&PhMwpServiceEventQueue, 100);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackServiceProviderAddedEvent),\n                PhMwpServiceAddedHandler,\n                NULL,\n                &ServiceAddedRegistration\n                );\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent),\n                PhMwpServiceModifiedHandler,\n                NULL,\n                &ServiceModifiedRegistration\n                );\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackServiceProviderRemovedEvent),\n                PhMwpServiceRemovedHandler,\n                NULL,\n                &ServiceRemovedRegistration\n                );\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackServiceProviderUpdatedEvent),\n                PhMwpServicesUpdatedHandler,\n                NULL,\n                &ServicesUpdatedRegistration\n                );\n        }\n        break;\n    case MainTabPageCreateWindow:\n        {\n            if (Parameter1)\n            {\n                *(HWND*)Parameter1 = PhMwpServiceTreeNewHandle;\n            }\n        }\n        return TRUE;\n    case MainTabPageSelected:\n        {\n            BOOLEAN selected = (BOOLEAN)PtrToUlong(Parameter1);\n\n            if (selected)\n                PhMwpNeedServiceTreeList();\n        }\n        break;\n    case MainTabPageInitializeSectionMenuItems:\n        {\n            PPH_MAIN_TAB_PAGE_MENU_INFORMATION menuInfo = Parameter1;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM menuItem;\n\n            menu = PhCreateEMenuItem(0, 0, L\"Services\", NULL, NULL);\n            PhInsertEMenuItem(menuInfo->Menu, menu, menuInfo->StartIndex);\n\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEMICROSOFTSERVICES, L\"Hide default services\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEDRIVERSERVICES, L\"&Hide driver services\", NULL, NULL), ULONG_MAX);\n\n            if (DriverFilterEntry && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_HIDEDRIVERSERVICES)))\n                menuItem->Flags |= PH_EMENU_CHECKED;\n            if (MicrosoftFilterEntry && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_HIDEMICROSOFTSERVICES)))\n                menuItem->Flags |= PH_EMENU_CHECKED;\n        }\n        return TRUE;\n    case MainTabPageLoadSettings:\n        {\n            if (PhGetIntegerSetting(SETTING_HIDE_DRIVER_SERVICES))\n                DriverFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), PhMwpDriverServiceTreeFilter, NULL);\n            if (PhGetIntegerSetting(SETTING_HIDE_DEFAULT_SERVICES))\n                MicrosoftFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), PhMwpMicrosoftServiceTreeFilter, NULL);\n        }\n        return TRUE;\n    case MainTabPageSaveSettings:\n        {\n            if (ServiceTreeListLoaded)\n                PhSaveSettingsServiceTreeList();\n        }\n        return TRUE;\n    case MainTabPageExportContent:\n        {\n            PPH_MAIN_TAB_PAGE_EXPORT_CONTENT exportContent = Parameter1;\n\n            PhWriteServiceList(exportContent->FileStream, exportContent->Mode);\n        }\n        return TRUE;\n    case MainTabPageFontChanged:\n        {\n            HFONT font = (HFONT)Parameter1;\n\n            SetWindowFont(PhMwpServiceTreeNewHandle, font, TRUE);\n        }\n        break;\n    case MainTabPageUpdateAutomaticallyChanged:\n        {\n            BOOLEAN updateAutomatically = (BOOLEAN)PtrToUlong(Parameter1);\n\n            PhSetEnabledProvider(&PhMwpServiceProviderRegistration, updateAutomatically);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhMwpNeedServiceTreeList(\n    VOID\n    )\n{\n    if (!ServiceTreeListLoaded)\n    {\n        ServiceTreeListLoaded = TRUE;\n        PhLoadSettingsServiceTreeList();\n    }\n}\n\nVOID PhMwpToggleDriverServiceTreeFilter(\n    VOID\n    )\n{\n    if (!DriverFilterEntry)\n    {\n        DriverFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), PhMwpDriverServiceTreeFilter, NULL);\n    }\n    else\n    {\n        PhRemoveTreeNewFilter(PhGetFilterSupportServiceTreeList(), DriverFilterEntry);\n        DriverFilterEntry = NULL;\n    }\n\n    PhApplyTreeNewFilters(PhGetFilterSupportServiceTreeList());\n\n    PhSetIntegerSetting(SETTING_HIDE_DRIVER_SERVICES, !!DriverFilterEntry);\n}\n\nVOID PhMwpToggleMicrosoftServiceTreeFilter(\n    VOID\n    )\n{\n    if (MicrosoftFilterEntry)\n    {\n        PhRemoveTreeNewFilter(PhGetFilterSupportServiceTreeList(), MicrosoftFilterEntry);\n        MicrosoftFilterEntry = NULL;\n    }\n    else\n    {\n        MicrosoftFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), PhMwpMicrosoftServiceTreeFilter, NULL);\n    }\n\n    PhApplyTreeNewFilters(PhGetFilterSupportServiceTreeList());\n\n    PhSetIntegerSetting(SETTING_HIDE_DEFAULT_SERVICES, !!MicrosoftFilterEntry);\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpDriverServiceTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_SERVICE_NODE serviceNode = (PPH_SERVICE_NODE)Node;\n\n    if (FlagOn(serviceNode->ServiceItem->Type, SERVICE_DRIVER))\n        return FALSE;\n\n    return TRUE;\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhMwpMicrosoftServiceTreeFilter(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_SERVICE_NODE serviceNode = (PPH_SERVICE_NODE)Node;\n\n    if (serviceNode->ServiceItem->MicrosoftService)\n        return FALSE;\n\n    return TRUE;\n}\n\nVOID PhMwpInitializeServiceMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ PPH_SERVICE_ITEM *Services,\n    _In_ ULONG NumberOfServices\n    )\n{\n    if (NumberOfServices == 0)\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n    }\n    else if (NumberOfServices == 1)\n    {\n        if (!Services[0]->ProcessId)\n            PhEnableEMenuItem(Menu, ID_SERVICE_GOTOPROCESS, FALSE);\n    }\n    else\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n        PhEnableEMenuItem(Menu, ID_SERVICE_START, TRUE);\n        PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, TRUE);\n        PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, TRUE);\n        PhEnableEMenuItem(Menu, ID_SERVICE_STOP, TRUE);\n        PhEnableEMenuItem(Menu, ID_SERVICE_COPY, TRUE);\n    }\n\n    if (NumberOfServices == 1)\n    {\n        switch (Services[0]->State)\n        {\n        case SERVICE_RUNNING:\n            {\n                PhEnableEMenuItem(Menu, ID_SERVICE_START, FALSE);\n                PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE);\n                PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FlagOn(Services[0]->ControlsAccepted, SERVICE_ACCEPT_PAUSE_CONTINUE));\n                PhEnableEMenuItem(Menu, ID_SERVICE_STOP, FlagOn(Services[0]->ControlsAccepted, SERVICE_ACCEPT_STOP));\n            }\n            break;\n        case SERVICE_PAUSED:\n            {\n                PhEnableEMenuItem(Menu, ID_SERVICE_START, FALSE);\n                PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FlagOn(Services[0]->ControlsAccepted, SERVICE_ACCEPT_PAUSE_CONTINUE));\n                PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FALSE);\n                PhEnableEMenuItem(Menu, ID_SERVICE_STOP, FlagOn(Services[0]->ControlsAccepted, SERVICE_ACCEPT_STOP));\n            }\n            break;\n        case SERVICE_STOPPED:\n            {\n                PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE);\n                PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FALSE);\n                PhEnableEMenuItem(Menu, ID_SERVICE_STOP, FALSE);\n            }\n            break;\n        case SERVICE_START_PENDING:\n        case SERVICE_CONTINUE_PENDING:\n        case SERVICE_PAUSE_PENDING:\n        case SERVICE_STOP_PENDING:\n            {\n                PhEnableEMenuItem(Menu, ID_SERVICE_START, FALSE);\n                PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE);\n                PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FALSE);\n                PhEnableEMenuItem(Menu, ID_SERVICE_STOP, FALSE);\n            }\n            break;\n        }\n\n        if (!FlagOn(Services[0]->ControlsAccepted, SERVICE_ACCEPT_PAUSE_CONTINUE))\n        {\n            PPH_EMENU_ITEM item;\n\n            if (item = PhFindEMenuItem(Menu, 0, NULL, ID_SERVICE_CONTINUE))\n                PhDestroyEMenuItem(item);\n            if (item = PhFindEMenuItem(Menu, 0, NULL, ID_SERVICE_PAUSE))\n                PhDestroyEMenuItem(item);\n        }\n    }\n}\n\nVOID PhShowServiceContextMenu(\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    )\n{\n    PH_PLUGIN_MENU_INFORMATION menuInfo;\n    PPH_SERVICE_ITEM *services;\n    ULONG numberOfServices;\n\n    PhGetSelectedServiceItems(&services, &numberOfServices);\n\n    if (numberOfServices != 0)\n    {\n        PPH_EMENU menu;\n        PPH_EMENU_ITEM item;\n\n        menu = PhCreateEMenu();\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_START, L\"&Start\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_CONTINUE, L\"C&ontinue\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_PAUSE, L\"&Pause\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_STOP, L\"S&top\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_DELETE, L\"&Delete\\bDel\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_GOTOPROCESS, L\"&Go to process\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_OPENKEY, L\"Open &key\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_OPENFILELOCATION, L\"Open &file location\\bCtrl+Enter\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_PROPERTIES, L\"P&roperties\\bEnter\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SERVICE_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n        PhSetFlagsEMenuItem(menu, ID_SERVICE_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n        PhMwpInitializeServiceMenu(menu, services, numberOfServices);\n        PhInsertCopyCellEMenuItem(menu, ID_SERVICE_COPY, PhMwpServiceTreeNewHandle, ContextMenu->Column);\n\n        if (PhPluginsEnabled)\n        {\n            PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, 0);\n            menuInfo.u.Service.Services = services;\n            menuInfo.u.Service.NumberOfServices = numberOfServices;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing), &menuInfo);\n        }\n\n        item = PhShowEMenu(\n            menu,\n            PhMainWndHandle,\n            PH_EMENU_SHOW_LEFTRIGHT,\n            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n            ContextMenu->Location.x,\n            ContextMenu->Location.y\n            );\n\n        if (item)\n        {\n            BOOLEAN handled = FALSE;\n\n            handled = PhHandleCopyCellEMenuItem(item);\n\n            if (!handled && PhPluginsEnabled)\n                handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n            if (!handled)\n                SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0);\n        }\n\n        PhDestroyEMenu(menu);\n    }\n\n    PhFree(services);\n}\n\nVOID PhServiceListInsertContextMenu(\n    _In_ HWND ParentWindow,\n    _In_ PPH_EMENU Menu,\n    _In_ PPH_SERVICE_ITEM* Services,\n    _In_ ULONG NumberOfServices\n    )\n{\n    PH_PLUGIN_MENU_INFORMATION menuInfo;\n\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_START, L\"&Start\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_CONTINUE, L\"C&ontinue\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_PAUSE, L\"&Pause\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_STOP, L\"S&top\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_DELETE, L\"&Delete\\bDel\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_GOTOPROCESS, L\"&Go to process\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_OPENKEY, L\"Open &key\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_OPENFILELOCATION, L\"Open &file location\\bCtrl+Enter\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_PROPERTIES, L\"P&roperties\\bEnter\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_SERVICE_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n    PhSetFlagsEMenuItem(Menu, ID_SERVICE_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n    PhMwpInitializeServiceMenu(Menu, Services, NumberOfServices);\n\n    if (PhPluginsEnabled)\n    {\n        PhPluginInitializeMenuInfo(&menuInfo, Menu, ParentWindow, 0);\n        menuInfo.u.Service.Services = Services;\n        menuInfo.u.Service.NumberOfServices = NumberOfServices;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing), &menuInfo);\n    }\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpServiceAddedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter;\n\n    PhReferenceObject(serviceItem);\n    PhPushProviderEventQueue(&PhMwpServiceEventQueue, ProviderAddedEvent, Parameter, PhGetRunIdProvider(&PhMwpServiceProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpServiceModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)Parameter;\n    PPH_SERVICE_MODIFIED_DATA copy;\n\n    copy = PhAllocateCopy(serviceModifiedData, sizeof(PH_SERVICE_MODIFIED_DATA));\n\n    PhPushProviderEventQueue(&PhMwpServiceEventQueue, ProviderModifiedEvent, copy, PhGetRunIdProvider(&PhMwpServiceProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpServiceRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter;\n\n    PhPushProviderEventQueue(&PhMwpServiceEventQueue, ProviderRemovedEvent, Parameter, PhGetRunIdProvider(&PhMwpServiceProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhMwpServicesUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    SystemInformer_Invoke(PhMwpOnServicesUpdated, PhGetRunIdProvider(&PhMwpServiceProviderRegistration));\n}\n\nVOID PhMwpOnServiceAdded(\n    _In_ _Assume_refs_(1) PPH_SERVICE_ITEM ServiceItem,\n    _In_ ULONG RunId\n    )\n{\n    PPH_SERVICE_NODE serviceNode;\n\n    serviceNode = PhAddServiceNode(ServiceItem, RunId);\n    // ServiceItem dereferenced below\n\n    if (RunId != 1)\n    {\n        PhLogServiceEntry(PH_LOG_ENTRY_SERVICE_CREATE, ServiceItem->Name, ServiceItem->DisplayName);\n\n        if (FlagOn(PhMwpNotifyIconNotifyMask, PH_NOTIFY_SERVICE_CREATE))\n        {\n            if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_SERVICE_CREATE, ServiceItem))\n            {\n                PH_FORMAT format[5];\n                WCHAR formatBuffer[260];\n\n                PhMwpClearLastNotificationDetails();\n                PhMwpLastNotificationType = PH_NOTIFY_SERVICE_CREATE;\n                PhSwapReference(&PhMwpLastNotificationDetails.ServiceName, ServiceItem->Name);\n\n                // The service %s (%s) has been created.\n                PhInitFormatS(&format[0], L\"The service \");\n                PhInitFormatSR(&format[1], ServiceItem->Name->sr);\n                PhInitFormatS(&format[2], L\" (\");\n                PhInitFormatSR(&format[3], ServiceItem->DisplayName->sr);\n                PhInitFormatS(&format[4], L\") was created\");\n\n                if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n                {\n                    PhShowIconNotification(L\"Service Created\", formatBuffer);\n                }\n                else\n                {\n                    PhShowIconNotification(L\"Service Created\",\n                        PH_AUTO_T(PH_STRING, PhFormat(format, RTL_NUMBER_OF(format), 0))->Buffer);\n                }\n            }\n        }\n    }\n\n    PhDereferenceObject(ServiceItem);\n}\n\nVOID PhMwpOnServiceModified(\n    _In_ PPH_SERVICE_MODIFIED_DATA ServiceModifiedData,\n    _In_ ULONG RunId\n    )\n{\n    PH_SERVICE_CHANGE serviceChange;\n    UCHAR logEntryType;\n\n    PhUpdateServiceNode(PhFindServiceNode(ServiceModifiedData->ServiceItem));\n\n    serviceChange = PhGetServiceChange(ServiceModifiedData);\n\n    switch (serviceChange)\n    {\n    case ServiceStarted:\n        logEntryType = PH_LOG_ENTRY_SERVICE_START;\n        break;\n    case ServiceStopped:\n        logEntryType = PH_LOG_ENTRY_SERVICE_STOP;\n        break;\n    case ServiceContinued:\n        logEntryType = PH_LOG_ENTRY_SERVICE_CONTINUE;\n        break;\n    case ServicePaused:\n        logEntryType = PH_LOG_ENTRY_SERVICE_PAUSE;\n        break;\n    case ServiceModified:\n        logEntryType = PH_LOG_ENTRY_SERVICE_MODIFIED;\n        break;\n    default:\n        logEntryType = 0;\n        break;\n    }\n\n    if (logEntryType != 0)\n        PhLogServiceEntry(logEntryType, ServiceModifiedData->ServiceItem->Name, ServiceModifiedData->ServiceItem->DisplayName);\n\n    if (FlagOn(PhMwpNotifyIconNotifyMask, PH_NOTIFY_SERVICE_START | PH_NOTIFY_SERVICE_STOP | PH_NOTIFY_SERVICE_MODIFIED))\n    {\n        PPH_SERVICE_ITEM serviceItem;\n\n        serviceItem = ServiceModifiedData->ServiceItem;\n\n        if (serviceChange == ServiceStarted && FlagOn(PhMwpNotifyIconNotifyMask, PH_NOTIFY_SERVICE_START))\n        {\n            if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_SERVICE_START, serviceItem))\n            {\n                PH_FORMAT format[5];\n                WCHAR formatBuffer[260];\n\n                PhMwpClearLastNotificationDetails();\n                PhMwpLastNotificationType = PH_NOTIFY_SERVICE_START;\n                PhSwapReference(&PhMwpLastNotificationDetails.ServiceName, serviceItem->Name);\n\n                // The service %s (%s) has been started.\n                PhInitFormatS(&format[0], L\"The service \");\n                PhInitFormatSR(&format[1], serviceItem->Name->sr);\n                PhInitFormatS(&format[2], L\" (\");\n                PhInitFormatSR(&format[3], serviceItem->DisplayName->sr);\n                PhInitFormatS(&format[4], L\") was started\");\n\n                if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n                {\n                    PhShowIconNotification(L\"Service Started\", formatBuffer);\n                }\n                else\n                {\n                    PhShowIconNotification(L\"Service Started\",\n                        PH_AUTO_T(PH_STRING, PhFormat(format, RTL_NUMBER_OF(format), 0))->Buffer);\n                }\n            }\n        }\n        else if (serviceChange == ServiceStopped && FlagOn(PhMwpNotifyIconNotifyMask, PH_NOTIFY_SERVICE_STOP))\n        {\n            if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_SERVICE_STOP, serviceItem))\n            {\n                PH_FORMAT format[5];\n                WCHAR formatBuffer[260];\n\n                PhMwpClearLastNotificationDetails();\n                PhMwpLastNotificationType = PH_NOTIFY_SERVICE_STOP;\n                PhSwapReference(&PhMwpLastNotificationDetails.ServiceName, serviceItem->Name);\n\n                // The service %s (%s) has been stopped.\n                PhInitFormatS(&format[0], L\"The service \");\n                PhInitFormatSR(&format[1], serviceItem->Name->sr);\n                PhInitFormatS(&format[2], L\" (\");\n                PhInitFormatSR(&format[3], serviceItem->DisplayName->sr);\n                PhInitFormatS(&format[4], L\") was stopped\");\n\n                if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n                {\n                    PhShowIconNotification(L\"Service Stopped\", formatBuffer);\n                }\n                else\n                {\n                    PhShowIconNotification(L\"Service Stopped\",\n                        PH_AUTO_T(PH_STRING, PhFormat(format, RTL_NUMBER_OF(format), 0))->Buffer);\n                }\n            }\n        }\n        else if (serviceChange == ServiceModified && FlagOn(PhMwpNotifyIconNotifyMask, PH_NOTIFY_SERVICE_MODIFIED))\n        {\n            if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_SERVICE_MODIFIED, serviceItem))\n            {\n                PH_FORMAT format[5];\n                WCHAR formatBuffer[260];\n\n                PhMwpClearLastNotificationDetails();\n                PhMwpLastNotificationType = PH_NOTIFY_SERVICE_MODIFIED;\n                PhSwapReference(&PhMwpLastNotificationDetails.ServiceName, serviceItem->Name);\n\n                // The service %s (%s) has been modified.\n                PhInitFormatS(&format[0], L\"The service \");\n                PhInitFormatSR(&format[1], serviceItem->Name->sr);\n                PhInitFormatS(&format[2], L\" (\");\n                PhInitFormatSR(&format[3], serviceItem->DisplayName->sr);\n                PhInitFormatS(&format[4], L\") was modified\");\n\n                if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n                {\n                    PhShowIconNotification(L\"Service Modified\", formatBuffer);\n                }\n                else\n                {\n                    PhShowIconNotification(L\"Service Modified\",\n                        PH_AUTO_T(PH_STRING, PhFormat(format, RTL_NUMBER_OF(format), 0))->Buffer);\n                }\n            }\n        }\n    }\n\n    PhFree(ServiceModifiedData);\n}\n\nVOID PhMwpOnServiceRemoved(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    PhLogServiceEntry(PH_LOG_ENTRY_SERVICE_DELETE, ServiceItem->Name, ServiceItem->DisplayName);\n\n    if (FlagOn(PhMwpNotifyIconNotifyMask, PH_NOTIFY_SERVICE_DELETE))\n    {\n        if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_SERVICE_DELETE, ServiceItem))\n        {\n            PH_FORMAT format[5];\n            WCHAR formatBuffer[260];\n\n            PhMwpClearLastNotificationDetails();\n            PhMwpLastNotificationType = PH_NOTIFY_SERVICE_DELETE;\n            PhSwapReference(&PhMwpLastNotificationDetails.ServiceName, ServiceItem->Name);\n\n            // The service %s (%s) has been deleted.\n            PhInitFormatS(&format[0], L\"The service \");\n            PhInitFormatSR(&format[1], ServiceItem->Name->sr);\n            PhInitFormatS(&format[2], L\" (\");\n            PhInitFormatSR(&format[3], ServiceItem->DisplayName->sr);\n            PhInitFormatS(&format[4], L\") was deleted\");\n\n            if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n            {\n                PhShowIconNotification(L\"Service Deleted\", formatBuffer);\n            }\n            else\n            {\n                PhShowIconNotification(L\"Service Deleted\",\n                    PH_AUTO_T(PH_STRING, PhFormat(format, RTL_NUMBER_OF(format), 0))->Buffer);\n            }\n        }\n    }\n\n    PhRemoveServiceNode(PhFindServiceNode(ServiceItem));\n}\n\nVOID PhMwpOnServicesUpdated(\n    _In_ ULONG RunId\n    )\n{\n    PPH_PROVIDER_EVENT events;\n    ULONG count;\n    ULONG i;\n\n    events = PhFlushProviderEventQueue(&PhMwpServiceEventQueue, RunId, &count);\n\n    if (events)\n    {\n        TreeNew_SetRedraw(PhMwpServiceTreeNewHandle, FALSE);\n\n        for (i = 0; i < count; i++)\n        {\n            PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]);\n            PPH_SERVICE_ITEM serviceItem = PH_PROVIDER_EVENT_OBJECT(events[i]);\n\n            switch (type)\n            {\n            case ProviderAddedEvent:\n                PhMwpOnServiceAdded(serviceItem, events[i].RunId);\n                break;\n            case ProviderModifiedEvent:\n                PhMwpOnServiceModified((PPH_SERVICE_MODIFIED_DATA)serviceItem, events[i].RunId);\n                break;\n            case ProviderRemovedEvent:\n                PhMwpOnServiceRemoved(serviceItem);\n                break;\n            }\n        }\n\n        PhFree(events);\n    }\n\n    PhTickServiceNodes();\n\n    if (DriverFilterEntry || MicrosoftFilterEntry)\n        PhApplyTreeNewFilters(PhGetFilterSupportServiceTreeList());\n\n    if (count != 0)\n        TreeNew_SetRedraw(PhMwpServiceTreeNewHandle, TRUE);\n}\n"
  },
  {
    "path": "SystemInformer/netlist.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2015\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <phuisup.h>\n#include <netlist.h>\n\n#include <cpysave.h>\n#include <emenu.h>\n#include <settings.h>\n\n#include <colmgr.h>\n#include <extmgri.h>\n#include <mainwnd.h>\n#include <netprv.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <procprv.h>\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpNetworkNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpNetworkNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\nVOID PhpRemoveNetworkNode(\n    _In_ PPH_NETWORK_NODE NetworkNode,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpNetworkTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    );\n\nBOOLEAN NTAPI PhpNetworkTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhpUpdateNetworkItemProcessName(\n    _In_ PPH_NETWORK_ITEM NetworkItem,\n    _In_ PPH_NETWORK_NODE NetworkNode\n    );\n\nVOID PhpUpdateNetworkItemProcessId(\n    _In_ PPH_NETWORK_ITEM NetworkItem,\n    _In_ PPH_NETWORK_NODE NetworkNode\n    );\n\nstatic HWND NetworkTreeListHandle;\nstatic ULONG NetworkTreeListSortColumn;\nstatic PH_SORT_ORDER NetworkTreeListSortOrder;\nstatic PH_CM_MANAGER NetworkTreeListCm;\n\nstatic PPH_HASHTABLE NetworkNodeHashtable; // hashtable of all nodes\nstatic PPH_LIST NetworkNodeList; // list of all nodes\nstatic ULONG64 NextUniqueId = 0;\n\nBOOLEAN PhNetworkTreeListStateHighlighting = TRUE;\nstatic PPH_POINTER_LIST NetworkNodeStateList = NULL; // list of nodes which need to be processed\n\nstatic PH_TN_FILTER_SUPPORT FilterSupport;\n\nVOID PhNetworkTreeListInitialization(\n    VOID\n    )\n{\n    NetworkNodeHashtable = PhCreateHashtable(\n        sizeof(PPH_NETWORK_NODE),\n        PhpNetworkNodeHashtableEqualFunction,\n        PhpNetworkNodeHashtableHashFunction,\n        100\n        );\n    NetworkNodeList = PhCreateList(100);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpNetworkNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_NETWORK_NODE networkNode1 = *(PPH_NETWORK_NODE *)Entry1;\n    PPH_NETWORK_NODE networkNode2 = *(PPH_NETWORK_NODE *)Entry2;\n\n    return networkNode1->NetworkItem == networkNode2->NetworkItem;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpNetworkNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashIntPtr((ULONG_PTR)(*(PPH_NETWORK_NODE *)Entry)->NetworkItem);\n}\n\nVOID PhInitializeNetworkTreeList(\n    _In_ HWND TreeNewHandle\n    )\n{\n    NetworkTreeListHandle = TreeNewHandle;\n    PhSetControlTheme(NetworkTreeListHandle, L\"explorer\");\n\n    TreeNew_SetRedraw(TreeNewHandle, FALSE);\n    TreeNew_SetCallback(TreeNewHandle, PhpNetworkTreeNewCallback, NULL);\n    TreeNew_SetImageList(TreeNewHandle, PhProcessSmallImageList);\n\n    // Default columns\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_PROCESS, TRUE, L\"Name\", 100, PH_ALIGN_LEFT, 0, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_PID, TRUE, L\"PID\", 50, PH_ALIGN_RIGHT, 1, DT_RIGHT);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_LOCALADDRESS, TRUE, L\"Local address\", 120, PH_ALIGN_LEFT, 2, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_LOCALPORT, TRUE, L\"Local port\", 50, PH_ALIGN_RIGHT, 3, DT_RIGHT);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_REMOTEADDRESS, TRUE, L\"Remote address\", 120, PH_ALIGN_LEFT, 4, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_REMOTEPORT, TRUE, L\"Remote port\", 50, PH_ALIGN_RIGHT, 5, DT_RIGHT);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_PROTOCOL, TRUE, L\"Protocol\", 45, PH_ALIGN_LEFT, 6, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_STATE, TRUE, L\"State\", 70, PH_ALIGN_LEFT, 7, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_OWNER, TRUE, L\"Owner\", 80, PH_ALIGN_LEFT, 8, 0);\n\n    PhAddTreeNewColumnEx(TreeNewHandle, PHNETLC_TIMESTAMP, FALSE, L\"Time stamp\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_LOCALHOSTNAME, FALSE, L\"Local hostname\", 120, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_REMOTEHOSTNAME, FALSE, L\"Remote hostname\", 120, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx2(TreeNewHandle, PHNETLC_TIMELINE, FALSE, L\"Timeline\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING);\n    PhAddTreeNewColumn(TreeNewHandle, PHNETLC_HV_SERVICE, FALSE, L\"Hyper-V service\", 120, PH_ALIGN_LEFT, ULONG_MAX, 0);\n\n    PhCmInitializeManager(&NetworkTreeListCm, TreeNewHandle, PHNETLC_MAXIMUM, PhpNetworkTreeNewPostSortFunction);\n    PhInitializeTreeNewFilterSupport(&FilterSupport, TreeNewHandle, NetworkNodeList);\n\n    TreeNew_SetTriState(TreeNewHandle, TRUE);\n    TreeNew_SetRedraw(TreeNewHandle, TRUE);\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n        treeNewInfo.TreeNewHandle = TreeNewHandle;\n        treeNewInfo.CmData = &NetworkTreeListCm;\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), &treeNewInfo);\n    }\n}\n\nVOID PhLoadSettingsNetworkTreeUpdateMask(\n    VOID\n    )\n{\n    PH_TREENEW_COLUMN column;\n    BOOLEAN current;\n\n    current = BooleanFlagOn(PhNetworkProviderFlagsMask, PH_NETWORK_PROVIDER_FLAG_HOSTNAME);\n\n    if (\n        (TreeNew_GetColumn(NetworkTreeListHandle, PHNETLC_LOCALHOSTNAME, &column) && column.Visible) ||\n        (TreeNew_GetColumn(NetworkTreeListHandle, PHNETLC_REMOTEHOSTNAME, &column) && column.Visible)\n        )\n    {\n        SetFlag(PhNetworkProviderFlagsMask, PH_NETWORK_PROVIDER_FLAG_HOSTNAME);\n    }\n    else\n    {\n        ClearFlag(PhNetworkProviderFlagsMask, PH_NETWORK_PROVIDER_FLAG_HOSTNAME);\n    }\n\n    if (NextUniqueId != 0 && current != BooleanFlagOn(PhNetworkProviderFlagsMask, PH_NETWORK_PROVIDER_FLAG_HOSTNAME))\n    {\n        PhInvalidateAllNetworkNodesHostnames();\n    }\n}\n\nVOID PhLoadSettingsNetworkTreeList(\n    VOID\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhGetStringSetting(SETTING_NETWORK_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_NETWORK_TREE_LIST_SORT);\n    PhCmLoadSettingsEx(NetworkTreeListHandle, &NetworkTreeListCm, 0, &settings->sr, &sortSettings->sr);\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_INSTANT_TOOLTIPS))\n        SendMessage(TreeNew_GetTooltips(NetworkTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0);\n    else\n        SendMessage(TreeNew_GetTooltips(NetworkTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);\n\n    PhLoadSettingsNetworkTreeUpdateMask();\n}\n\nVOID PhSaveSettingsNetworkTreeList(\n    VOID\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(NetworkTreeListHandle, &NetworkTreeListCm, 0, &sortSettings);\n    PhSetStringSetting2(SETTING_NETWORK_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_NETWORK_TREE_LIST_SORT, &sortSettings->sr);\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhReloadSettingsNetworkTreeList(\n    VOID\n    )\n{\n    if (PhGetIntegerSetting(SETTING_ENABLE_INSTANT_TOOLTIPS))\n        SendMessage(TreeNew_GetTooltips(NetworkTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0);\n    else\n        SendMessage(TreeNew_GetTooltips(NetworkTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);\n\n    PhLoadSettingsNetworkTreeUpdateMask();\n}\n\nPPH_TN_FILTER_SUPPORT PhGetFilterSupportNetworkTreeList(\n    VOID\n    )\n{\n    return &FilterSupport;\n}\n\nPPH_NETWORK_NODE PhAddNetworkNode(\n    _In_ PPH_NETWORK_ITEM NetworkItem,\n    _In_ ULONG RunId\n    )\n{\n    PPH_NETWORK_NODE networkNode;\n\n    networkNode = PhAllocate(PhEmGetObjectSize(EmNetworkNodeType, sizeof(PH_NETWORK_NODE)));\n    memset(networkNode, 0, sizeof(PH_NETWORK_NODE));\n    PhInitializeTreeNewNode(&networkNode->Node);\n\n    if (PhNetworkTreeListStateHighlighting && RunId != 1)\n    {\n        PhChangeShStateTn(\n            &networkNode->Node,\n            &networkNode->ShState,\n            &NetworkNodeStateList,\n            NewItemState,\n            PhCsColorNew,\n            NULL\n            );\n    }\n\n    networkNode->NetworkItem = NetworkItem;\n    PhReferenceObject(NetworkItem);\n    networkNode->UniqueId = ++NextUniqueId; // used to stabilize sorting\n\n    memset(networkNode->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM);\n    networkNode->Node.TextCache = networkNode->TextCache;\n    networkNode->Node.TextCacheSize = PHNETLC_MAXIMUM;\n\n    PhpUpdateNetworkItemProcessName(NetworkItem, networkNode);\n    PhpUpdateNetworkItemProcessId(NetworkItem, networkNode);\n\n    PhAddEntryHashtable(NetworkNodeHashtable, &networkNode);\n    PhAddItemList(NetworkNodeList, networkNode);\n\n    if (FilterSupport.NodeList)\n        networkNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &networkNode->Node);\n\n    PhEmCallObjectOperation(EmNetworkNodeType, networkNode, EmObjectCreate);\n\n    TreeNew_NodesStructured(NetworkTreeListHandle);\n\n    return networkNode;\n}\n\nPPH_NETWORK_NODE PhFindNetworkNode(\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    )\n{\n    PH_NETWORK_NODE lookupNetworkNode;\n    PPH_NETWORK_NODE lookupNetworkNodePtr = &lookupNetworkNode;\n    PPH_NETWORK_NODE *networkNode;\n\n    lookupNetworkNode.NetworkItem = NetworkItem;\n\n    networkNode = (PPH_NETWORK_NODE *)PhFindEntryHashtable(\n        NetworkNodeHashtable,\n        &lookupNetworkNodePtr\n        );\n\n    if (networkNode)\n        return *networkNode;\n    else\n        return NULL;\n}\n\nVOID PhRemoveNetworkNode(\n    _In_ PPH_NETWORK_NODE NetworkNode\n    )\n{\n    // Remove from the hashtable here to avoid problems in case the key is re-used.\n    PhRemoveEntryHashtable(NetworkNodeHashtable, &NetworkNode);\n\n    if (PhNetworkTreeListStateHighlighting)\n    {\n        PhChangeShStateTn(\n            &NetworkNode->Node,\n            &NetworkNode->ShState,\n            &NetworkNodeStateList,\n            RemovingItemState,\n            PhCsColorRemoved,\n            NetworkTreeListHandle\n            );\n    }\n    else\n    {\n        PhpRemoveNetworkNode(NetworkNode, NULL);\n    }\n}\n\nVOID PhpRemoveNetworkNode(\n    _In_ PPH_NETWORK_NODE NetworkNode,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG index;\n\n    PhEmCallObjectOperation(EmNetworkNodeType, NetworkNode, EmObjectDelete);\n\n    // Remove from list and cleanup.\n\n    if ((index = PhFindItemList(NetworkNodeList, NetworkNode)) != ULONG_MAX)\n        PhRemoveItemList(NetworkNodeList, index);\n\n    if (NetworkNode->ProcessNameText) PhDereferenceObject(NetworkNode->ProcessNameText);\n    if (NetworkNode->TimeStampText) PhDereferenceObject(NetworkNode->TimeStampText);\n    if (NetworkNode->TooltipText) PhDereferenceObject(NetworkNode->TooltipText);\n\n    PhDereferenceObject(NetworkNode->NetworkItem);\n\n    PhFree(NetworkNode);\n\n    TreeNew_NodesStructured(NetworkTreeListHandle);\n}\n\nVOID PhUpdateNetworkNode(\n    _In_ PPH_NETWORK_NODE NetworkNode\n    )\n{\n    memset(NetworkNode->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM);\n    PhClearReference(&NetworkNode->TooltipText);\n\n    PhInvalidateTreeNewNode(&NetworkNode->Node, TN_CACHE_ICON);\n    TreeNew_InvalidateNode(NetworkTreeListHandle, &NetworkNode->Node);\n}\n\nVOID PhTickNetworkNodes(\n    VOID\n    )\n{\n    if (NetworkTreeListSortOrder != NoSortOrder)\n    {\n        // Sorting is on, but it's not one of our columns. Force a rebuild. (If it was one of our\n        // columns, the restructure would have been handled in PhUpdateNetworkNode.)\n        TreeNew_NodesStructured(NetworkTreeListHandle);\n    }\n\n    PH_TICK_SH_STATE_TN(PH_NETWORK_NODE, ShState, NetworkNodeStateList, PhpRemoveNetworkNode, PhCsHighlightingDuration, NetworkTreeListHandle, TRUE, NULL, NULL);\n}\n\n#define SORT_FUNCTION(Column) PhpNetworkTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpNetworkTreeNewCompare##Column( \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_NETWORK_NODE node1 = *(PPH_NETWORK_NODE *)_elem1; \\\n    PPH_NETWORK_NODE node2 = *(PPH_NETWORK_NODE *)_elem2; \\\n    PPH_NETWORK_ITEM networkItem1 = node1->NetworkItem; \\\n    PPH_NETWORK_ITEM networkItem2 = node2->NetworkItem; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uint64cmp(node1->UniqueId, node2->UniqueId); \\\n    \\\n    return PhModifySort(sortResult, NetworkTreeListSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpNetworkTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    if (Result == 0)\n        Result = uint64cmp(((PPH_NETWORK_NODE)Node1)->UniqueId, ((PPH_NETWORK_NODE)Node2)->UniqueId);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(Process)\n{\n    sortResult = PhCompareString(node1->ProcessNameText, node2->ProcessNameText, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Pid)\n{\n    sortResult = intptrcmp((LONG_PTR)networkItem1->ProcessId, (LONG_PTR)networkItem2->ProcessId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LocalAddress)\n{\n    SOCKADDR_IN6 localAddress1;\n    SOCKADDR_IN6 localAddress2;\n    SCOPE_ID scopeId1;\n    SCOPE_ID scopeId2;\n\n    memset(&localAddress1, 0, sizeof(SOCKADDR_IN6)); // memset for zero padding (dmex)\n    memset(&localAddress2, 0, sizeof(SOCKADDR_IN6));\n\n    if (networkItem1->LocalEndpoint.Address.Type == PH_NETWORK_TYPE_IPV4)\n    {\n        localAddress1.sin6_family = AF_INET6;\n        IN6_SET_ADDR_V4COMPAT(&localAddress1.sin6_addr, &networkItem1->LocalEndpoint.Address.InAddr);\n        IN4_UNCANONICALIZE_SCOPE_ID(&networkItem1->LocalEndpoint.Address.InAddr, &localAddress1.sin6_scope_struct);\n        //IN6ADDR_SETV4MAPPED(&localAddress1, &networkItem1->LocalEndpoint.Address.InAddr, (SCOPE_ID)SCOPEID_UNSPECIFIED_INIT, 0);\n    }\n    else if (networkItem1->LocalEndpoint.Address.Type == PH_NETWORK_TYPE_IPV6)\n    {\n        scopeId1.Value = networkItem1->LocalScopeId;\n        IN6ADDR_SETSOCKADDR(&localAddress1, &networkItem1->LocalEndpoint.Address.In6Addr, scopeId1, 0);\n    }\n\n    if (networkItem2->LocalEndpoint.Address.Type == PH_NETWORK_TYPE_IPV4)\n    {\n        localAddress2.sin6_family = AF_INET6;\n        IN6_SET_ADDR_V4COMPAT(&localAddress2.sin6_addr, &networkItem2->LocalEndpoint.Address.InAddr);\n        IN4_UNCANONICALIZE_SCOPE_ID(&networkItem2->LocalEndpoint.Address.InAddr, &localAddress2.sin6_scope_struct);\n        //IN6ADDR_SETV4MAPPED(&localAddress2, &networkItem2->LocalEndpoint.Address.InAddr, (SCOPE_ID)SCOPEID_UNSPECIFIED_INIT, 0);\n    }\n    else if (networkItem2->LocalEndpoint.Address.Type == PH_NETWORK_TYPE_IPV6)\n    {\n        scopeId2.Value = networkItem2->LocalScopeId;\n        IN6ADDR_SETSOCKADDR(&localAddress2, &networkItem2->LocalEndpoint.Address.In6Addr, scopeId2, 0);\n    }\n\n    sortResult = memcmp(&localAddress1, &localAddress2, sizeof(SOCKADDR_IN6));\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LocalHostname)\n{\n    sortResult = PhCompareStringWithNullSortOrder(networkItem1->LocalHostString, networkItem2->LocalHostString, NetworkTreeListSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LocalPort)\n{\n    sortResult = uintcmp(networkItem1->LocalEndpoint.Port, networkItem2->LocalEndpoint.Port);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(RemoteAddress)\n{\n    SOCKADDR_IN6 remoteAddress1;\n    SOCKADDR_IN6 remoteAddress2;\n    SCOPE_ID scopeId1;\n    SCOPE_ID scopeId2;\n\n    memset(&remoteAddress1, 0, sizeof(SOCKADDR_IN6)); // memset for zero padding (dmex)\n    memset(&remoteAddress2, 0, sizeof(SOCKADDR_IN6));\n\n    if (networkItem1->RemoteEndpoint.Address.Type == PH_NETWORK_TYPE_IPV4)\n    {\n        remoteAddress1.sin6_family = AF_INET6;\n        IN6_SET_ADDR_V4COMPAT(&remoteAddress1.sin6_addr, &networkItem1->RemoteEndpoint.Address.InAddr);\n        IN4_UNCANONICALIZE_SCOPE_ID(&networkItem1->RemoteEndpoint.Address.InAddr, &remoteAddress1.sin6_scope_struct);\n        //IN6ADDR_SETV4MAPPED(&remoteAddress1, &networkItem1->RemoteEndpoint.Address.InAddr, (SCOPE_ID)SCOPEID_UNSPECIFIED_INIT, 0);\n    }\n    else if (networkItem1->RemoteEndpoint.Address.Type == PH_NETWORK_TYPE_IPV6)\n    {\n        scopeId1.Value = networkItem1->RemoteScopeId;\n        IN6ADDR_SETSOCKADDR(&remoteAddress1, &networkItem1->RemoteEndpoint.Address.In6Addr, scopeId1, 0);\n    }\n\n    if (networkItem2->RemoteEndpoint.Address.Type == PH_NETWORK_TYPE_IPV4)\n    {\n        remoteAddress2.sin6_family = AF_INET6;\n        IN6_SET_ADDR_V4COMPAT(&remoteAddress2.sin6_addr, &networkItem2->RemoteEndpoint.Address.InAddr);\n        IN4_UNCANONICALIZE_SCOPE_ID(&networkItem2->RemoteEndpoint.Address.InAddr, &remoteAddress2.sin6_scope_struct);\n        //IN6ADDR_SETV4MAPPED(&remoteAddress2, &networkItem2->RemoteEndpoint.Address.InAddr, (SCOPE_ID)SCOPEID_UNSPECIFIED_INIT, 0);\n    }\n    else if (networkItem2->RemoteEndpoint.Address.Type == PH_NETWORK_TYPE_IPV6)\n    {\n        scopeId2.Value = networkItem2->RemoteScopeId;\n        IN6ADDR_SETSOCKADDR(&remoteAddress2, &networkItem2->RemoteEndpoint.Address.In6Addr, scopeId2, 0);\n    }\n\n    sortResult = memcmp(&remoteAddress1, &remoteAddress2, sizeof(SOCKADDR_IN6));\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(RemoteHostname)\n{\n    sortResult = PhCompareStringWithNullSortOrder(networkItem1->RemoteHostString, networkItem2->RemoteHostString, NetworkTreeListSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(RemotePort)\n{\n    sortResult = uintcmp(networkItem1->RemoteEndpoint.Port, networkItem2->RemoteEndpoint.Port);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Protocol)\n{\n    sortResult = uintcmp(networkItem1->ProtocolType, networkItem2->ProtocolType);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(State)\n{\n    sortResult = uintcmp(networkItem1->State, networkItem2->State);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Owner)\n{\n    sortResult = PhCompareStringWithNullSortOrder(networkItem1->OwnerName, networkItem2->OwnerName, NetworkTreeListSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(TimeStamp)\n{\n    sortResult = uint64cmp(networkItem1->CreateTime.QuadPart, networkItem2->CreateTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(HvService)\n{\n    sortResult = PhCompareStringWithNullSortOrder(networkItem1->HvService, networkItem2->HvService, NetworkTreeListSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpNetworkTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_NETWORK_NODE node;\n\n    if (PhCmForwardMessage(WindowHandle, Message, Parameter1, Parameter2, &NetworkTreeListCm))\n        return TRUE;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtNonSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(Process),\n                    SORT_FUNCTION(Pid),\n                    SORT_FUNCTION(LocalAddress),\n                    SORT_FUNCTION(LocalPort),\n                    SORT_FUNCTION(RemoteAddress),\n                    SORT_FUNCTION(RemotePort),\n                    SORT_FUNCTION(Protocol),\n                    SORT_FUNCTION(State),\n                    SORT_FUNCTION(Owner),\n                    SORT_FUNCTION(TimeStamp),\n                    SORT_FUNCTION(LocalHostname),\n                    SORT_FUNCTION(RemoteHostname),\n                    SORT_FUNCTION(TimeStamp),\n                    SORT_FUNCTION(HvService),\n                };\n                _CoreCrtNonSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PHNETLC_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (!PhCmForwardSort(\n                    (PPH_TREENEW_NODE *)NetworkNodeList->Items,\n                    NetworkNodeList->Count,\n                    NetworkTreeListSortColumn,\n                    NetworkTreeListSortOrder,\n                    &NetworkTreeListCm\n                    ))\n                {\n                    if (NetworkTreeListSortColumn < PHNETLC_MAXIMUM)\n                        sortFunction = sortFunctions[NetworkTreeListSortColumn];\n                    else\n                        sortFunction = NULL;\n\n                    if (sortFunction)\n                    {\n                        qsort(NetworkNodeList->Items, NetworkNodeList->Count, sizeof(PVOID), sortFunction);\n                    }\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)NetworkNodeList->Items;\n                getChildren->NumberOfChildren = NetworkNodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            PPH_NETWORK_ITEM networkItem;\n\n            node = (PPH_NETWORK_NODE)getCellText->Node;\n            networkItem = node->NetworkItem;\n\n            switch (getCellText->Id)\n            {\n            case PHNETLC_PROCESS:\n                {\n                    getCellText->Text = PhGetStringRef(node->ProcessNameText);\n                }\n                break;\n            case PHNETLC_PID:\n                {\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->ProcessIdString);\n                }\n                break;\n            case PHNETLC_LOCALADDRESS:\n                {\n                    getCellText->Text = PhGetStringRef(networkItem->LocalAddressString);\n                }\n                break;\n            case PHNETLC_LOCALHOSTNAME:\n                {\n                    if (networkItem->LocalHostnameResolved)\n                        getCellText->Text = PhGetStringRef(networkItem->LocalHostString);\n                    else\n                        PhInitializeStringRef(&getCellText->Text, L\"Resolving....\");\n                }\n                break;\n            case PHNETLC_LOCALPORT:\n                {\n                    PhInitializeStringRefLongHint(&getCellText->Text, networkItem->LocalPortString);\n                }\n                break;\n            case PHNETLC_REMOTEADDRESS:\n                {\n                    getCellText->Text = PhGetStringRef(networkItem->RemoteAddressString);\n                }\n                break;\n            case PHNETLC_REMOTEHOSTNAME:\n                {\n                    if (networkItem->RemoteHostnameResolved)\n                        getCellText->Text = PhGetStringRef(networkItem->RemoteHostString);\n                    else\n                        PhInitializeStringRef(&getCellText->Text, L\"Resolving....\");\n                }\n                break;\n            case PHNETLC_REMOTEPORT:\n                {\n                    PhInitializeStringRefLongHint(&getCellText->Text, networkItem->RemotePortString);\n                }\n                break;\n            case PHNETLC_PROTOCOL:\n                {\n                    PCPH_STRINGREF protocolType;\n\n                    if (protocolType = PhGetProtocolTypeName(networkItem->ProtocolType))\n                    {\n                        getCellText->Text.Buffer = protocolType->Buffer;\n                        getCellText->Text.Length = protocolType->Length;\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHNETLC_STATE:\n                {\n                    if (FlagOn(networkItem->ProtocolType, PH_PROTOCOL_TYPE_TCP))\n                    {\n                        PCPH_STRINGREF stateName;\n\n                        if (stateName = PhGetTcpStateName(networkItem->State))\n                        {\n                            getCellText->Text.Buffer = stateName->Buffer;\n                            getCellText->Text.Length = stateName->Length;\n                        }\n                        else\n                        {\n                            PhInitializeEmptyStringRef(&getCellText->Text);\n                        }\n                    }\n                    else if (networkItem->ProtocolType == PH_NETWORK_PROTOCOL_HYPERV)\n                    {\n                        if (networkItem->State)\n                        {\n                            PhInitializeStringRef(&getCellText->Text, L\"Connected\");\n                        }\n                        else\n                        {\n                            PhInitializeStringRef(&getCellText->Text, L\"Listen\");\n                        }\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHNETLC_OWNER:\n                getCellText->Text = PhGetStringRef(networkItem->OwnerName);\n                break;\n            case PHNETLC_TIMESTAMP:\n                {\n                    SYSTEMTIME systemTime;\n\n                    if (networkItem->CreateTime.QuadPart != 0)\n                    {\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &networkItem->CreateTime);\n                        PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = node->TimeStampText->sr;\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PHNETLC_HV_SERVICE:\n                getCellText->Text = PhGetStringRef(networkItem->HvService);\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeIcon:\n        {\n            PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1;\n\n            node = (PPH_NETWORK_NODE)getNodeIcon->Node;\n            getNodeIcon->Icon = (HICON)(ULONG_PTR)node->NetworkItem->ProcessIconIndex;\n            //getNodeIcon->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetCellTooltip:\n        {\n            PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;\n            PPH_PROCESS_ITEM processItem;\n\n            node = (PPH_NETWORK_NODE)getCellTooltip->Node;\n\n            if (getCellTooltip->Column->Id != 0)\n                return FALSE;\n\n            if (!node->TooltipText)\n            {\n                if (processItem = PhReferenceProcessItem(node->NetworkItem->ProcessId))\n                {\n                    node->TooltipText = PhGetProcessTooltipText(processItem, NULL);\n                    PhDereferenceObject(processItem);\n                }\n            }\n\n            if (!PhIsNullOrEmptyString(node->TooltipText))\n            {\n                getCellTooltip->Text = PhGetStringRef(node->TooltipText);\n                getCellTooltip->Unfolding = FALSE;\n                getCellTooltip->MaximumWidth = ULONG_MAX;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case TreeNewCustomDraw:\n        {\n            PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;\n            PPH_NETWORK_ITEM networkItem;\n            RECT rect;\n\n            node = (PPH_NETWORK_NODE)customDraw->Node;\n            networkItem = node->NetworkItem;\n            rect = customDraw->CellRect;\n\n            if (rect.right - rect.left <= 1)\n                break; // nothing to draw\n\n            switch (customDraw->Column->Id)\n            {\n            case PHNETLC_TIMELINE:\n                {\n                    if (networkItem->CreateTime.QuadPart == 0)\n                        break; // nothing to draw\n\n                    PhCustomDrawTreeTimeLine(\n                        customDraw->Dc,\n                        &customDraw->CellRect,\n                        PhEnableThemeSupport ? PH_DRAW_TIMELINE_DARKTHEME : 0,\n                        NULL,\n                        &networkItem->CreateTime\n                        );\n                }\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            NetworkTreeListSortColumn = sorting->SortColumn;\n            NetworkTreeListSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_COPY, 0);\n                break;\n            case VK_RETURN:\n                SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            memset(&data, 0, sizeof(PH_TN_COLUMN_MENU_DATA));\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = PHNETLC_PROCESS;\n            data.DefaultSortOrder = AscendingSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(\n                data.Menu,\n                WindowHandle,\n                PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                data.MouseEvent->ScreenLocation.x,\n                data.MouseEvent->ScreenLocation.y\n                );\n\n            PhHandleTreeNewColumnMenu(&data);\n\n            if (data.Selection)\n            {\n                if (data.Selection->Id == PH_TN_COLUMN_MENU_HIDE_COLUMN_ID ||\n                    data.Selection->Id == PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID)\n                {\n                    // TODO: Reset flags for enabled/disabled columns. (dmex)\n                    PhReloadSettingsNetworkTreeList();\n                }\n            }\n\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n\n            PhShowNetworkContextMenu(contextMenu);\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            node = (PPH_NETWORK_NODE)getNodeColor->Node;\n\n            if (!node->NetworkItem)\n            {\n                NOTHING;\n            }\n            else if (!node->NetworkItem->ProcessId)\n            {\n                NOTHING;\n            }\n            else if (PhCsUseColorPacked && node->NetworkItem->UnknownProcess)\n            {\n                getNodeColor->BackColor = PhCsColorPacked;\n            }\n            else if (PhCsUseColorPicoProcesses && node->NetworkItem->SubsystemProcess)\n            {\n                getNodeColor->BackColor = PhCsColorPicoProcesses;\n            }\n\n            getNodeColor->Flags |= TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpUpdateNetworkItemProcessName(\n    _In_ PPH_NETWORK_ITEM NetworkItem,\n    _In_ PPH_NETWORK_NODE NetworkNode\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static CONST PH_STRINGREF processNameUnknown = PH_STRINGREF_INIT(L\"Unknown process\");\n    static CONST PH_STRINGREF processNameWaiting = PH_STRINGREF_INIT(L\"Waiting connections\");\n    static PPH_STRING cachedNameUnknown = NULL;\n    static PPH_STRING cachedNameWaiting = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        cachedNameUnknown = PhCreateString2(&processNameUnknown);\n        cachedNameWaiting = PhCreateString2(&processNameWaiting);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (NetworkItem->ProcessId)\n    {\n        if (NetworkItem->ProcessName)\n            PhSetReference(&NetworkNode->ProcessNameText, NetworkItem->ProcessName);\n        else\n            PhSetReference(&NetworkNode->ProcessNameText, cachedNameUnknown);\n    }\n    else\n    {\n        PhSetReference(&NetworkNode->ProcessNameText, cachedNameWaiting);\n    }\n}\n\nVOID PhpUpdateNetworkItemProcessId(\n    _In_ PPH_NETWORK_ITEM NetworkItem,\n    _In_ PPH_NETWORK_NODE NetworkNode\n    )\n{\n    if (NetworkItem->ProcessId)\n    {\n        if (NetworkItem->ProcessItem)\n        {\n            memcpy(\n                NetworkNode->ProcessIdString,\n                NetworkItem->ProcessItem->ProcessIdString,\n                sizeof(NetworkNode->ProcessIdString)\n                );\n        }\n        else\n        {\n            PhPrintUInt32(NetworkNode->ProcessIdString, HandleToUlong(NetworkItem->ProcessId));\n        }\n    }\n    else\n    {\n        PhPrintUInt32(NetworkNode->ProcessIdString, HandleToUlong(SYSTEM_PROCESS_ID));\n    }\n}\n\nPPH_NETWORK_ITEM PhGetSelectedNetworkItem(\n    VOID\n    )\n{\n    PPH_NETWORK_ITEM networkItem = NULL;\n    ULONG i;\n\n    for (i = 0; i < NetworkNodeList->Count; i++)\n    {\n        PPH_NETWORK_NODE node = NetworkNodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            networkItem = node->NetworkItem;\n            break;\n        }\n    }\n\n    return networkItem;\n}\n\nVOID PhGetSelectedNetworkItems(\n    _Out_ PPH_NETWORK_ITEM **NetworkItems,\n    _Out_ PULONG NumberOfNetworkItems\n    )\n{\n    PH_ARRAY array;\n    ULONG i;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    for (i = 0; i < NetworkNodeList->Count; i++)\n    {\n        PPH_NETWORK_NODE node = NetworkNodeList->Items[i];\n\n        if (node->Node.Selected)\n            PhAddItemArray(&array, &node->NetworkItem);\n    }\n\n    *NumberOfNetworkItems = (ULONG)PhFinalArrayCount(&array);\n    *NetworkItems = PhFinalArrayItems(&array);\n}\n\nVOID PhDeselectAllNetworkNodes(\n    VOID\n    )\n{\n    TreeNew_DeselectRange(NetworkTreeListHandle, 0, -1);\n}\n\nBOOLEAN PhSelectAndEnsureVisibleNetworkNode(\n    _In_ PPH_NETWORK_NODE NetworkNode\n    )\n{\n    PhDeselectAllNetworkNodes();\n\n    if (NetworkNode->Node.Visible)\n    {\n        TreeNew_FocusMarkSelectNode(NetworkTreeListHandle, &NetworkNode->Node);\n        return TRUE;\n    }\n    else\n    {\n        PhShowInformation2(\n            PhMainWndHandle,\n            L\"Unable to perform the operation.\",\n            L\"%s\",\n            L\"This node cannot be displayed because it is currently hidden by your active filter settings or preferences.\"\n            );\n        return FALSE;\n    }\n}\n\nVOID PhInvalidateAllNetworkNodes(\n    VOID\n    )\n{\n    for (ULONG i = 0; i < NetworkNodeList->Count; i++)\n    {\n        PPH_NETWORK_NODE node = NetworkNodeList->Items[i];\n\n        memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM);\n        PhInvalidateTreeNewNode(&node->Node, TN_CACHE_COLOR);\n    }\n\n    InvalidateRect(NetworkTreeListHandle, NULL, FALSE);\n}\n\nVOID PhInvalidateAllNetworkNodesHostnames(\n    VOID\n    )\n{\n    PhFlushNetworkItemResolveCache();\n\n    for (ULONG i = 0; i < NetworkNodeList->Count; i++)\n    {\n        PPH_NETWORK_NODE node = NetworkNodeList->Items[i];\n\n        node->NetworkItem->InvalidateHostname = TRUE;\n\n        memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM);\n        PhInvalidateTreeNewNode(&node->Node, TN_CACHE_COLOR);\n    }\n\n    //PPH_NETWORK_ITEM* networkItems;\n    //ULONG numberOfNetworkItems;\n    //\n    //PhEnumNetworkItems(&networkItems, &numberOfNetworkItems);\n    //\n    //for (ULONG j = 0; j < numberOfNetworkItems; j++)\n    //{\n    //    PPH_NETWORK_ITEM networkItem = networkItems[j];\n    //\n    //    networkItem->InvalidateHostname = TRUE;\n    //}\n    //\n    //PhDereferenceObjects(networkItems, numberOfNetworkItems);\n    //PhFree(networkItems);\n}\n\nVOID PhCopyNetworkList(\n    VOID\n    )\n{\n    PPH_STRING text;\n\n    text = PhGetTreeNewText(NetworkTreeListHandle, 0);\n    PhSetClipboardString(NetworkTreeListHandle, &text->sr);\n    PhDereferenceObject(text);\n}\n\nVOID PhWriteNetworkList(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ ULONG Mode\n    )\n{\n    PPH_LIST lines;\n    ULONG i;\n\n    lines = PhGetGenericTreeNewLines(NetworkTreeListHandle, Mode);\n\n    for (i = 0; i < lines->Count; i++)\n    {\n        PPH_STRING line;\n\n        line = lines->Items[i];\n        PhWriteStringAsUtf8FileStream(FileStream, &line->sr);\n        PhDereferenceObject(line);\n        PhWriteStringAsUtf8FileStream2(FileStream, L\"\\r\\n\");\n    }\n\n    PhDereferenceObject(lines);\n}\n\nPPH_LIST PhDuplicateNetworkNodeList(\n    VOID\n    )\n{\n    PPH_LIST newList;\n\n    newList = PhCreateList(NetworkNodeList->Count);\n    PhInsertItemsList(newList, 0, NetworkNodeList->Items, NetworkNodeList->Count);\n\n    return newList;\n}\n"
  },
  {
    "path": "SystemInformer/netprv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     evilpie 2010\n *     dmex    2016-2023\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <extmgri.h>\n#include <mapldr.h>\n#include <netprv.h>\n#include <procprv.h>\n#include <svcsup.h>\n#include <workqueue.h>\n#include <hvsocketcontrol.h>\n\n#include <trace.h>\n\ntypedef struct _PH_NETWORK_CONNECTION\n{\n    ULONG ProtocolType;\n    PH_IP_ENDPOINT LocalEndpoint;\n    PH_IP_ENDPOINT RemoteEndpoint;\n    MIB_TCP_STATE State;\n    HANDLE ProcessId;\n    LARGE_INTEGER CreateTime;\n    ULONGLONG OwnerInfo[PH_NETWORK_OWNER_INFO_SIZE];\n    ULONG LocalScopeId; // Ipv6\n    ULONG RemoteScopeId; // Ipv6\n} PH_NETWORK_CONNECTION, *PPH_NETWORK_CONNECTION;\n\ntypedef struct _PH_NETWORK_ITEM_QUERY_DATA\n{\n    SLIST_ENTRY ListEntry;\n    PPH_NETWORK_ITEM NetworkItem;\n\n    PH_IP_ADDRESS Address;\n    BOOLEAN Remote;\n    PPH_STRING HostString;\n} PH_NETWORK_ITEM_QUERY_DATA, *PPH_NETWORK_ITEM_QUERY_DATA;\n\ntypedef struct _PHP_RESOLVE_CACHE_ITEM\n{\n    PH_IP_ADDRESS Address;\n    PPH_STRING HostString;\n} PHP_RESOLVE_CACHE_ITEM, *PPHP_RESOLVE_CACHE_ITEM;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpNetworkItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpNetworkHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpNetworkHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpResolveCacheHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpResolveCacheHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\nBOOLEAN PhGetNetworkConnections(\n    _Out_ PPH_NETWORK_CONNECTION *Connections,\n    _Out_ PULONG NumberOfConnections\n    );\n\nPPH_OBJECT_TYPE PhNetworkItemType = NULL;\nPPH_HASHTABLE PhNetworkHashtable = NULL;\nPH_QUEUED_LOCK PhNetworkHashtableLock = PH_QUEUED_LOCK_INIT;\n\nPH_INITONCE PhNetworkProviderWorkQueueInitOnce = PH_INITONCE_INIT;\nPH_WORK_QUEUE PhNetworkProviderWorkQueue;\nSLIST_HEADER PhNetworkItemQueryListHead;\n\nBOOLEAN PhEnableNetworkProviderResolve = TRUE;\nBOOLEAN PhEnableNetworkBoundConnections = TRUE;\nULONG PhNetworkProviderFlagsMask = 0;\nstatic PPH_HASHTABLE PhpResolveCacheHashtable = NULL;\nstatic PH_QUEUED_LOCK PhpResolveCacheHashtableLock = PH_QUEUED_LOCK_INIT;\n\nstatic BOOLEAN NetworkImportDone = FALSE;\nstatic _GetExtendedTcpTable GetExtendedTcpTable_I = NULL;\nstatic _GetExtendedUdpTable GetExtendedUdpTable_I = NULL;\nstatic _InternalGetBoundTcpEndpointTable GetBoundTcpEndpointTable_I = NULL;\nstatic _InternalGetBoundTcp6EndpointTable GetBoundTcp6EndpointTable_I = NULL;\n\nBOOLEAN PhNetworkProviderInitialization(\n    VOID\n    )\n{\n    PhNetworkItemType = PhCreateObjectType(L\"NetworkItem\", 0, PhpNetworkItemDeleteProcedure);\n    PhNetworkHashtable = PhCreateHashtable(\n        sizeof(PPH_NETWORK_ITEM),\n        PhpNetworkHashtableEqualFunction,\n        PhpNetworkHashtableHashFunction,\n        40\n        );\n\n    PhInitializeSListHead(&PhNetworkItemQueryListHead);\n\n    PhpResolveCacheHashtable = PhCreateHashtable(\n        sizeof(PPHP_RESOLVE_CACHE_ITEM),\n        PhpResolveCacheHashtableEqualFunction,\n        PhpResolveCacheHashtableHashFunction,\n        20\n        );\n\n    return TRUE;\n}\n\nPPH_NETWORK_ITEM PhCreateNetworkItem(\n    VOID\n    )\n{\n    PPH_NETWORK_ITEM networkItem;\n\n    networkItem = PhCreateObject(\n        PhEmGetObjectSize(EmNetworkItemType, sizeof(PH_NETWORK_ITEM)),\n        PhNetworkItemType\n        );\n    memset(networkItem, 0, sizeof(PH_NETWORK_ITEM));\n    PhEmCallObjectOperation(EmNetworkItemType, networkItem, EmObjectCreate);\n\n    return networkItem;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpNetworkItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Object;\n\n    PhEmCallObjectOperation(EmNetworkItemType, networkItem, EmObjectDelete);\n\n    if (networkItem->LocalAddressString)\n        PhDereferenceObject(networkItem->LocalAddressString);\n    if (networkItem->RemoteAddressString)\n        PhDereferenceObject(networkItem->RemoteAddressString);\n    if (networkItem->ProcessName)\n        PhDereferenceObject(networkItem->ProcessName);\n    if (networkItem->OwnerName)\n        PhDereferenceObject(networkItem->OwnerName);\n    if (networkItem->LocalHostString)\n        PhDereferenceObject(networkItem->LocalHostString);\n    if (networkItem->RemoteHostString)\n        PhDereferenceObject(networkItem->RemoteHostString);\n    if (networkItem->HvService)\n        PhDereferenceObject(networkItem->HvService);\n\n    // NOTE: Dereferencing the ProcessItem will destroy the NetworkItem->ProcessIcon handle.\n    if (networkItem->ProcessItem)\n        PhDereferenceObject(networkItem->ProcessItem);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpNetworkHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_NETWORK_ITEM networkItem1 = *(PPH_NETWORK_ITEM *)Entry1;\n    PPH_NETWORK_ITEM networkItem2 = *(PPH_NETWORK_ITEM *)Entry2;\n\n    return\n        networkItem1->ProtocolType == networkItem2->ProtocolType &&\n        PhEqualIpEndpoint(&networkItem1->LocalEndpoint, &networkItem2->LocalEndpoint) &&\n        PhEqualIpEndpoint(&networkItem1->RemoteEndpoint, &networkItem2->RemoteEndpoint) &&\n        networkItem1->ProcessId == networkItem2->ProcessId;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpNetworkHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_NETWORK_ITEM networkItem = *(PPH_NETWORK_ITEM *)Entry;\n\n    return\n        networkItem->ProtocolType ^\n        PhHashIpEndpoint(&networkItem->LocalEndpoint) ^\n        PhHashIpEndpoint(&networkItem->RemoteEndpoint) ^\n        (HandleToUlong(networkItem->ProcessId) / 4);\n}\n\nPPH_NETWORK_ITEM PhReferenceNetworkItem(\n    _In_ ULONG ProtocolType,\n    _In_ PPH_IP_ENDPOINT LocalEndpoint,\n    _In_ PPH_IP_ENDPOINT RemoteEndpoint,\n    _In_ HANDLE ProcessId\n    )\n{\n    PH_NETWORK_ITEM lookupNetworkItem;\n    PPH_NETWORK_ITEM lookupNetworkItemPtr = &lookupNetworkItem;\n    PPH_NETWORK_ITEM *networkItemPtr;\n    PPH_NETWORK_ITEM networkItem;\n\n    lookupNetworkItem.ProtocolType = ProtocolType;\n    lookupNetworkItem.LocalEndpoint = *LocalEndpoint;\n    lookupNetworkItem.RemoteEndpoint = *RemoteEndpoint;\n    lookupNetworkItem.ProcessId = ProcessId;\n\n    PhAcquireQueuedLockShared(&PhNetworkHashtableLock);\n\n    networkItemPtr = (PPH_NETWORK_ITEM *)PhFindEntryHashtable(\n        PhNetworkHashtable,\n        &lookupNetworkItemPtr\n        );\n\n    if (networkItemPtr)\n    {\n        networkItem = *networkItemPtr;\n        PhReferenceObject(networkItem);\n    }\n    else\n    {\n        networkItem = NULL;\n    }\n\n    PhReleaseQueuedLockShared(&PhNetworkHashtableLock);\n\n    return networkItem;\n}\n\n/**\n * Enumerates the network items.\n *\n * \\param NetworkItems A variable which receives an array of pointers to network items. You must\n * free the buffer with PhFree() when you no longer need it.\n * \\param NumberOfNetworkItems A variable which receives the number of network items returned in\n * \\a ProcessItems.\n */\nVOID PhEnumNetworkItems(\n    _Out_opt_ PPH_NETWORK_ITEM **NetworkItems,\n    _Out_ PULONG NumberOfNetworkItems\n    )\n{\n    PPH_NETWORK_ITEM* networkItems;\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_NETWORK_ITEM* networkItem;\n    ULONG numberOfNetworkItems;\n    ULONG count = 0;\n\n    PhAcquireQueuedLockShared(&PhNetworkHashtableLock);\n\n    PhBeginEnumHashtable(PhNetworkHashtable, &enumContext);\n\n    while (networkItem = PhNextEnumHashtable(&enumContext))\n    {\n        count++;\n    }\n\n    if (count == 0)\n    {\n        PhReleaseQueuedLockShared(&PhNetworkHashtableLock);\n\n        if (NetworkItems) *NetworkItems = NULL;\n        *NumberOfNetworkItems = count;\n        return;\n    }\n\n    numberOfNetworkItems = count;\n    networkItems = PhAllocate(sizeof(PPH_NETWORK_ITEM) * numberOfNetworkItems);\n    count = 0;\n\n    PhBeginEnumHashtable(PhNetworkHashtable, &enumContext);\n\n    while (networkItem = PhNextEnumHashtable(&enumContext))\n    {\n        PhReferenceObject((*networkItem));\n        networkItems[count++] = (*networkItem);\n    }\n\n    PhReleaseQueuedLockShared(&PhNetworkHashtableLock);\n\n    *NetworkItems = networkItems;\n    *NumberOfNetworkItems = numberOfNetworkItems;\n}\n\nVOID PhEnumNetworkItemsByProcessId(\n    _In_opt_ HANDLE ProcessId,\n    _Out_opt_ PPH_NETWORK_ITEM** NetworkItems,\n    _Out_ PULONG NumberOfNetworkItems\n    )\n{\n    PPH_NETWORK_ITEM* networkItems;\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_NETWORK_ITEM* networkItem;\n    ULONG numberOfNetworkItems;\n    ULONG count = 0;\n\n    PhAcquireQueuedLockShared(&PhNetworkHashtableLock);\n\n    PhBeginEnumHashtable(PhNetworkHashtable, &enumContext);\n\n    while (networkItem = PhNextEnumHashtable(&enumContext))\n    {\n        if ((*networkItem)->ProcessId == ProcessId)\n        {\n            count++;\n        }\n    }\n\n    if (count == 0)\n    {\n        PhReleaseQueuedLockShared(&PhNetworkHashtableLock);\n\n        if (NetworkItems) *NetworkItems = NULL;\n        *NumberOfNetworkItems = count;\n        return;\n    }\n\n    numberOfNetworkItems = count;\n    networkItems = PhAllocate(sizeof(PPH_NETWORK_ITEM) * numberOfNetworkItems);\n    count = 0;\n\n    PhBeginEnumHashtable(PhNetworkHashtable, &enumContext);\n\n    while (networkItem = PhNextEnumHashtable(&enumContext))\n    {\n        if ((*networkItem)->ProcessId == ProcessId)\n        {\n            PhReferenceObject((*networkItem));\n            networkItems[count++] = (*networkItem);\n        }\n    }\n\n    PhReleaseQueuedLockShared(&PhNetworkHashtableLock);\n\n    *NetworkItems = networkItems;\n    *NumberOfNetworkItems = numberOfNetworkItems;\n}\n\nVOID PhpRemoveNetworkItem(\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    )\n{\n    PhRemoveEntryHashtable(PhNetworkHashtable, &NetworkItem);\n    PhDereferenceObject(NetworkItem);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PhpResolveCacheHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPHP_RESOLVE_CACHE_ITEM cacheItem1 = *(PPHP_RESOLVE_CACHE_ITEM *)Entry1;\n    PPHP_RESOLVE_CACHE_ITEM cacheItem2 = *(PPHP_RESOLVE_CACHE_ITEM *)Entry2;\n\n    return PhEqualIpAddress(&cacheItem1->Address, &cacheItem2->Address);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpResolveCacheHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPHP_RESOLVE_CACHE_ITEM cacheItem = *(PPHP_RESOLVE_CACHE_ITEM *)Entry;\n\n    return PhHashIpAddress(&cacheItem->Address);\n}\n\nPPHP_RESOLVE_CACHE_ITEM PhpLookupResolveCacheItem(\n    _In_ PPH_IP_ADDRESS Address\n    )\n{\n    PHP_RESOLVE_CACHE_ITEM lookupCacheItem;\n    PPHP_RESOLVE_CACHE_ITEM lookupCacheItemPtr = &lookupCacheItem;\n    PPHP_RESOLVE_CACHE_ITEM *cacheItemPtr;\n\n    // Construct a temporary cache item for the lookup.\n    lookupCacheItem.Address = *Address;\n\n    cacheItemPtr = (PPHP_RESOLVE_CACHE_ITEM *)PhFindEntryHashtable(\n        PhpResolveCacheHashtable,\n        &lookupCacheItemPtr\n        );\n\n    if (cacheItemPtr)\n        return *cacheItemPtr;\n    else\n        return NULL;\n}\n\n//PPH_STRING PhGetHostNameFromAddress(\n//    _In_ PPH_IP_ADDRESS Address\n//    )\n//{\n//    SOCKADDR_IN ipv4Address;\n//    SOCKADDR_IN6 ipv6Address;\n//    PSOCKADDR address;\n//    socklen_t length;\n//    PPH_STRING hostName;\n//\n//    if (Address->Type == PH_NETWORK_TYPE_IPV4)\n//    {\n//        ipv4Address.sin_family = AF_INET;\n//        ipv4Address.sin_port = 0;\n//        ipv4Address.sin_addr = Address->InAddr;\n//        address = (PSOCKADDR)&ipv4Address;\n//        length = sizeof(ipv4Address);\n//    }\n//    else if (Address->Type == PH_NETWORK_TYPE_IPV6)\n//    {\n//        ipv6Address.sin6_family = AF_INET6;\n//        ipv6Address.sin6_port = 0;\n//        ipv6Address.sin6_flowinfo = 0;\n//        ipv6Address.sin6_addr = Address->In6Addr;\n//        ipv6Address.sin6_scope_id = 0;\n//        address = (PSOCKADDR)&ipv6Address;\n//        length = sizeof(ipv6Address);\n//    }\n//    else\n//    {\n//        return NULL;\n//    }\n//\n//    hostName = PhCreateStringEx(NULL, 128);\n//\n//    if (GetNameInfo(\n//        address,\n//        length,\n//        hostName->Buffer,\n//        (ULONG)hostName->Length / sizeof(WCHAR) + 1,\n//        NULL,\n//        0,\n//        NI_NAMEREQD\n//        ) != 0)\n//    {\n//        // Try with the maximum host name size.\n//        PhDereferenceObject(hostName);\n//        hostName = PhCreateStringEx(NULL, NI_MAXHOST * sizeof(WCHAR));\n//\n//        if (GetNameInfo(\n//            address,\n//            length,\n//            hostName->Buffer,\n//            (ULONG)hostName->Length / sizeof(WCHAR) + 1,\n//            NULL,\n//            0,\n//            NI_NAMEREQD\n//            ) != 0)\n//        {\n//            PhDereferenceObject(hostName);\n//\n//            return NULL;\n//        }\n//    }\n//\n//    PhTrimToNullTerminatorString(hostName);\n//\n//    return hostName;\n//}\n\nPPH_STRING PhpGetDnsReverseNameFromAddress(\n    _In_ PPH_IP_ADDRESS Address\n    )\n{\n#define IP4_REVERSE_DOMAIN_STRING_LENGTH (IP4_ADDRESS_STRING_LENGTH + sizeof(DNS_IP4_REVERSE_DOMAIN_STRING_W) + 1)\n#define IP6_REVERSE_DOMAIN_STRING_LENGTH (IP6_ADDRESS_STRING_LENGTH + sizeof(DNS_IP6_REVERSE_DOMAIN_STRING_W) + 1)\n\n    switch (Address->Type)\n    {\n    case PH_NETWORK_TYPE_IPV4:\n        {\n            static CONST PH_STRINGREF reverseLookupDomainNameSr = PH_STRINGREF_INIT(DNS_IP4_REVERSE_DOMAIN_STRING);\n            PH_FORMAT format[9];\n            SIZE_T returnLength;\n            WCHAR reverseNameBuffer[IP4_REVERSE_DOMAIN_STRING_LENGTH];\n\n            PhInitFormatU(&format[0], Address->InAddr.s_impno);\n            PhInitFormatC(&format[1], L'.');\n            PhInitFormatU(&format[2], Address->InAddr.s_lh);\n            PhInitFormatC(&format[3], L'.');\n            PhInitFormatU(&format[4], Address->InAddr.s_host);\n            PhInitFormatC(&format[5], L'.');\n            PhInitFormatU(&format[6], Address->InAddr.s_net);\n            PhInitFormatC(&format[7], L'.');\n            PhInitFormatSR(&format[8], reverseLookupDomainNameSr);\n\n            if (PhFormatToBuffer(\n                format,\n                RTL_NUMBER_OF(format),\n                reverseNameBuffer,\n                sizeof(reverseNameBuffer),\n                &returnLength\n                ))\n            {\n                PH_STRINGREF reverseNameString;\n\n                reverseNameString.Buffer = reverseNameBuffer;\n                reverseNameString.Length = returnLength - sizeof(UNICODE_NULL);\n\n                return PhCreateString2(&reverseNameString);\n            }\n            else\n            {\n                return PhFormat(format, RTL_NUMBER_OF(format), IP4_REVERSE_DOMAIN_STRING_LENGTH);\n            }\n        }\n        break;\n    case PH_NETWORK_TYPE_IPV6:\n        {\n            static CONST PH_STRINGREF reverseLookupDomainNameSr = PH_STRINGREF_INIT(DNS_IP6_REVERSE_DOMAIN_STRING);\n            PH_STRING_BUILDER stringBuilder;\n\n            // DNS_MAX_IP6_REVERSE_NAME_LENGTH\n            PhInitializeStringBuilder(&stringBuilder, IP6_REVERSE_DOMAIN_STRING_LENGTH);\n\n            for (LONG i = sizeof(IN6_ADDR) - 1; i >= 0; i--)\n            {\n                PH_FORMAT format[4];\n                SIZE_T returnLength;\n                WCHAR reverseNameBuffer[PH_INT64_STR_LEN_1];\n\n                PhInitFormatX(&format[0], Address->In6Addr.s6_addr[i] & 0xF);\n                PhInitFormatC(&format[1], L'.');\n                PhInitFormatX(&format[2], (Address->In6Addr.s6_addr[i] >> 4) & 0xF);\n                PhInitFormatC(&format[3], L'.');\n\n                if (PhFormatToBuffer(\n                    format,\n                    RTL_NUMBER_OF(format),\n                    reverseNameBuffer,\n                    sizeof(reverseNameBuffer),\n                    &returnLength\n                    ))\n                {\n                    PH_STRINGREF reverseNameString;\n\n                    reverseNameString.Buffer = reverseNameBuffer;\n                    reverseNameString.Length = returnLength - sizeof(UNICODE_NULL);\n\n                    PhAppendStringBuilder(&stringBuilder, &reverseNameString);\n                }\n                else\n                {\n                    PhAppendFormatStringBuilder(\n                        &stringBuilder,\n                        L\"%hhx.%hhx.\",\n                        Address->In6Addr.s6_addr[i] & 0xF,\n                        (Address->In6Addr.s6_addr[i] >> 4) & 0xF\n                        );\n                }\n            }\n\n            PhAppendStringBuilder(&stringBuilder, &reverseLookupDomainNameSr);\n\n            return PhFinalStringBuilderString(&stringBuilder);\n        }\n        break;\n    }\n\n    return NULL;\n}\n\nPPH_STRING PhGetHostNameFromAddressEx(\n    _In_ PPH_IP_ADDRESS Address\n    )\n{\n    BOOLEAN dnsLocalQuery = FALSE;\n    PPH_STRING dnsHostNameString = NULL;\n    PPH_STRING dnsReverseNameString = NULL;\n    PDNS_RECORD dnsRecordList;\n\n    switch (Address->Type)\n    {\n    case PH_NETWORK_TYPE_IPV4:\n        {\n            if (IN4_IS_ADDR_UNSPECIFIED(&Address->InAddr))\n                return NULL;\n\n            if (IN4_IS_ADDR_LOOPBACK(&Address->InAddr) ||\n                IN4_IS_ADDR_BROADCAST(&Address->InAddr) ||\n                IN4_IS_ADDR_MULTICAST(&Address->InAddr) ||\n                IN4_IS_ADDR_LINKLOCAL(&Address->InAddr) ||\n                IN4_IS_ADDR_MC_LINKLOCAL(&Address->InAddr) ||\n                IN4_IS_ADDR_RFC1918(&Address->InAddr))\n            {\n                dnsLocalQuery = TRUE;\n            }\n\n            dnsReverseNameString = PhDnsReverseLookupNameFromAddress(PH_NETWORK_TYPE_IPV4, &Address->InAddr);\n        }\n        break;\n    case PH_NETWORK_TYPE_IPV6:\n        {\n            if (IN6_IS_ADDR_UNSPECIFIED(&Address->In6Addr))\n                return NULL;\n\n            if (IN6_IS_ADDR_LOOPBACK(&Address->In6Addr) ||\n                IN6_IS_ADDR_MULTICAST(&Address->In6Addr) ||\n                IN6_IS_ADDR_LINKLOCAL(&Address->In6Addr) ||\n                IN6_IS_ADDR_MC_LINKLOCAL(&Address->In6Addr))\n            {\n                dnsLocalQuery = TRUE;\n            }\n\n            dnsReverseNameString = PhDnsReverseLookupNameFromAddress(PH_NETWORK_TYPE_IPV6, &Address->In6Addr);\n        }\n        break;\n    case PH_NETWORK_TYPE_HYPERV:\n        return PhHvSocketGetVmName(&Address->HvAddr);\n    }\n\n    if (PhIsNullOrEmptyString(dnsReverseNameString))\n        return NULL;\n\n    if (!!PhCsEnableNetworkResolveDoH && !dnsLocalQuery)\n    {\n        dnsRecordList = PhDnsQuery(\n            NULL,\n            dnsReverseNameString->Buffer,\n            DNS_TYPE_PTR\n            );\n    }\n    else\n    {\n        dnsRecordList = PhDnsQuery2(\n            NULL,\n            dnsReverseNameString->Buffer,\n            DNS_TYPE_PTR,\n            DNS_QUERY_NO_HOSTS_FILE // DNS_QUERY_BYPASS_CACHE\n            );\n    }\n\n    if (dnsRecordList)\n    {\n        for (PDNS_RECORD dnsRecord = dnsRecordList; dnsRecord; dnsRecord = dnsRecord->pNext)\n        {\n            if (dnsRecord->wType == DNS_TYPE_PTR)\n            {\n                dnsHostNameString = PhCreateString(dnsRecord->Data.PTR.pNameHost); // Return the first result (dmex)\n                break;\n            }\n        }\n\n        PhDnsFree(dnsRecordList);\n    }\n\n    PhDereferenceObject(dnsReverseNameString);\n\n    return dnsHostNameString;\n}\n\nVOID PhFlushNetworkItemResolveCache(\n    VOID\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPHP_RESOLVE_CACHE_ITEM* entry;\n\n    if (!PhpResolveCacheHashtable)\n        return;\n\n    PhAcquireQueuedLockExclusive(&PhpResolveCacheHashtableLock);\n\n    PhBeginEnumHashtable(PhpResolveCacheHashtable, &enumContext);\n\n    while (entry = PhNextEnumHashtable(&enumContext))\n    {\n        if ((*entry)->HostString)\n        {\n            PhDereferenceObject((*entry)->HostString);\n        }\n\n        PhFree((*entry));\n    }\n\n    PhDereferenceObject(PhpResolveCacheHashtable);\n    PhpResolveCacheHashtable = PhCreateHashtable(\n        sizeof(PPHP_RESOLVE_CACHE_ITEM),\n        PhpResolveCacheHashtableEqualFunction,\n        PhpResolveCacheHashtableHashFunction,\n        20\n        );\n\n    PhReleaseQueuedLockExclusive(&PhpResolveCacheHashtableLock);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpNetworkItemQueryWorker(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_NETWORK_ITEM_QUERY_DATA data = (PPH_NETWORK_ITEM_QUERY_DATA)Parameter;\n    PPH_STRING hostString;\n    PPHP_RESOLVE_CACHE_ITEM cacheItem;\n\n    // Last minute check of the cache.\n\n    PhAcquireQueuedLockShared(&PhpResolveCacheHashtableLock);\n    cacheItem = PhpLookupResolveCacheItem(&data->Address);\n    PhReleaseQueuedLockShared(&PhpResolveCacheHashtableLock);\n\n    if (!cacheItem)\n    {\n        hostString = PhGetHostNameFromAddressEx(&data->Address);\n\n        if (hostString)\n        {\n            data->HostString = hostString;\n\n            // Update the cache.\n\n            PhAcquireQueuedLockExclusive(&PhpResolveCacheHashtableLock);\n\n            cacheItem = PhpLookupResolveCacheItem(&data->Address);\n\n            if (!cacheItem)\n            {\n                cacheItem = PhAllocate(sizeof(PHP_RESOLVE_CACHE_ITEM));\n                cacheItem->Address = data->Address;\n                cacheItem->HostString = hostString;\n                PhReferenceObject(hostString);\n\n                PhAddEntryHashtable(PhpResolveCacheHashtable, &cacheItem);\n            }\n\n            PhReleaseQueuedLockExclusive(&PhpResolveCacheHashtableLock);\n        }\n    }\n    else\n    {\n        PhReferenceObject(cacheItem->HostString);\n        data->HostString = cacheItem->HostString;\n    }\n\n    RtlInterlockedPushEntrySList(&PhNetworkItemQueryListHead, &data->ListEntry);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpQueueNetworkItemQuery(\n    _In_ PPH_NETWORK_ITEM NetworkItem,\n    _In_ BOOLEAN Remote\n    )\n{\n    PPH_NETWORK_ITEM_QUERY_DATA data;\n\n    if (!PhEnableNetworkProviderResolve)\n    {\n        if (Remote)\n            NetworkItem->RemoteHostnameResolved = TRUE;\n        else\n            NetworkItem->LocalHostnameResolved = TRUE;\n        return;\n    }\n\n    data = PhAllocateZero(sizeof(PH_NETWORK_ITEM_QUERY_DATA));\n    data->NetworkItem = NetworkItem;\n    data->Remote = Remote;\n\n    if (Remote)\n        data->Address = NetworkItem->RemoteEndpoint.Address;\n    else\n        data->Address = NetworkItem->LocalEndpoint.Address;\n\n    PhReferenceObject(NetworkItem);\n\n    if (PhBeginInitOnce(&PhNetworkProviderWorkQueueInitOnce))\n    {\n        PhInitializeWorkQueue(&PhNetworkProviderWorkQueue, 0, 3, 500);\n        PhEndInitOnce(&PhNetworkProviderWorkQueueInitOnce);\n    }\n\n    PhQueueItemWorkQueue(&PhNetworkProviderWorkQueue, PhpNetworkItemQueryWorker, data);\n}\n\nVOID PhNetworkItemResolveHostname(\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    )\n{\n    PPHP_RESOLVE_CACHE_ITEM cacheItem;\n\n    if (!FlagOn(PhNetworkProviderFlagsMask, PH_NETWORK_PROVIDER_FLAG_HOSTNAME))\n        return;\n\n    // Local\n\n    if (!PhIsNullIpAddress(&NetworkItem->LocalEndpoint.Address))\n    {\n        PhAcquireQueuedLockShared(&PhpResolveCacheHashtableLock);\n        cacheItem = PhpLookupResolveCacheItem(&NetworkItem->LocalEndpoint.Address);\n        PhReleaseQueuedLockShared(&PhpResolveCacheHashtableLock);\n\n        if (cacheItem)\n        {\n            PhReferenceObject(cacheItem->HostString);\n            NetworkItem->LocalHostString = cacheItem->HostString;\n            NetworkItem->LocalHostnameResolved = TRUE;\n        }\n        else\n        {\n            PhpQueueNetworkItemQuery(NetworkItem, FALSE);\n        }\n    }\n    else\n    {\n        NetworkItem->LocalHostnameResolved = TRUE;\n    }\n\n    // Remote\n\n    if (!PhIsNullIpAddress(&NetworkItem->RemoteEndpoint.Address))\n    {\n        PhAcquireQueuedLockShared(&PhpResolveCacheHashtableLock);\n        cacheItem = PhpLookupResolveCacheItem(&NetworkItem->RemoteEndpoint.Address);\n        PhReleaseQueuedLockShared(&PhpResolveCacheHashtableLock);\n\n        if (cacheItem)\n        {\n            PhReferenceObject(cacheItem->HostString);\n            NetworkItem->RemoteHostString = cacheItem->HostString;\n            NetworkItem->RemoteHostnameResolved = TRUE;\n        }\n        else\n        {\n            PhpQueueNetworkItemQuery(NetworkItem, TRUE);\n        }\n    }\n    else\n    {\n        NetworkItem->RemoteHostnameResolved = TRUE;\n    }\n}\n\nVOID PhNetworkItemInvalidateHostname(\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    )\n{\n    if (NetworkItem->LocalHostString)\n    {\n        PhDereferenceObject(NetworkItem->LocalHostString);\n        NetworkItem->LocalHostString = NULL;\n    }\n\n    if (NetworkItem->RemoteHostString)\n    {\n        PhDereferenceObject(NetworkItem->RemoteHostString);\n        NetworkItem->RemoteHostString = NULL;\n    }\n\n    NetworkItem->LocalHostnameResolved = FALSE;\n    NetworkItem->RemoteHostnameResolved = FALSE;\n\n    PhNetworkItemResolveHostname(NetworkItem);\n}\n\nVOID PhpUpdateNetworkItemOwner(\n    _In_ PPH_NETWORK_ITEM NetworkItem,\n    _In_ ULONGLONG ServiceTag\n    )\n{\n    if (ServiceTag)\n    {\n        PPH_STRING serviceName;\n\n        serviceName = PhGetServiceNameFromTag(NetworkItem->ProcessId, (PVOID)ServiceTag);\n\n        if (serviceName)\n            PhMoveReference(&NetworkItem->OwnerName, serviceName);\n    }\n}\n\nVOID PhFlushNetworkQueryData(\n    VOID\n    )\n{\n    PSLIST_ENTRY entry;\n    PPH_NETWORK_ITEM_QUERY_DATA data;\n\n    if (!FlagOn(PhNetworkProviderFlagsMask, PH_NETWORK_PROVIDER_FLAG_HOSTNAME))\n        return;\n    //if (!RtlFirstEntrySList(&PhNetworkItemQueryListHead))\n    //    return;\n\n    entry = RtlInterlockedFlushSList(&PhNetworkItemQueryListHead);\n\n    while (entry)\n    {\n        data = CONTAINING_RECORD(entry, PH_NETWORK_ITEM_QUERY_DATA, ListEntry);\n        entry = entry->Next;\n\n        if (data->Remote)\n        {\n            PhMoveReference(&data->NetworkItem->RemoteHostString, data->HostString);\n            data->NetworkItem->RemoteHostnameResolved = TRUE;\n        }\n        else\n        {\n            PhMoveReference(&data->NetworkItem->LocalHostString, data->HostString);\n            data->NetworkItem->LocalHostnameResolved = TRUE;\n        }\n\n        InterlockedExchange(&data->NetworkItem->JustResolved, TRUE);\n\n        PhDereferenceObject(data->NetworkItem);\n        PhFree(data);\n    }\n}\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhNetworkProviderUpdate(\n    _In_ PVOID Object\n    )\n{\n    static ULONG runCount = 0;\n    PPH_NETWORK_CONNECTION connections;\n    ULONG numberOfConnections;\n    ULONG i;\n\n    PhTraceFuncEnter(\"Network provider run count: %lu\", runCount);\n\n    if (!NetworkImportDone)\n    {\n        PVOID iphlpapi;\n\n        if (iphlpapi = PhLoadLibrary(L\"iphlpapi.dll\"))\n        {\n            GetExtendedTcpTable_I = PhGetDllBaseProcedureAddress(iphlpapi, \"GetExtendedTcpTable\", 0);\n            GetExtendedUdpTable_I = PhGetDllBaseProcedureAddress(iphlpapi, \"GetExtendedUdpTable\", 0);\n            GetBoundTcpEndpointTable_I = PhGetDllBaseProcedureAddress(iphlpapi, \"InternalGetBoundTcpEndpointTable\", 0);\n            GetBoundTcp6EndpointTable_I = PhGetDllBaseProcedureAddress(iphlpapi, \"InternalGetBoundTcp6EndpointTable\", 0);\n        }\n\n        NetworkImportDone = TRUE;\n    }\n\n    if (!PhGetNetworkConnections(&connections, &numberOfConnections))\n    {\n        PhTraceFuncExit(\"Failed to get network connections: %lu\", runCount);\n        return;\n    }\n\n    // Look for closed connections.\n    {\n        PPH_LIST connectionsToRemove = NULL;\n        PH_HASHTABLE_ENUM_CONTEXT enumContext;\n        PPH_NETWORK_ITEM *networkItem;\n\n        PhBeginEnumHashtable(PhNetworkHashtable, &enumContext);\n\n        while (networkItem = PhNextEnumHashtable(&enumContext))\n        {\n            BOOLEAN found = FALSE;\n\n            for (i = 0; i < numberOfConnections; i++)\n            {\n                if (\n                    (*networkItem)->ProtocolType == connections[i].ProtocolType &&\n                    PhEqualIpEndpoint(&(*networkItem)->LocalEndpoint, &connections[i].LocalEndpoint) &&\n                    PhEqualIpEndpoint(&(*networkItem)->RemoteEndpoint, &connections[i].RemoteEndpoint) &&\n                    (*networkItem)->ProcessId == connections[i].ProcessId &&\n                    (*networkItem)->CreateTime.QuadPart == connections[i].CreateTime.QuadPart\n                    )\n                {\n                    found = TRUE;\n                    break;\n                }\n            }\n\n            if (!found)\n            {\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderRemovedEvent), *networkItem);\n\n                if (!connectionsToRemove)\n                    connectionsToRemove = PhCreateList(2);\n\n                PhAddItemList(connectionsToRemove, *networkItem);\n            }\n        }\n\n        if (connectionsToRemove)\n        {\n            PhAcquireQueuedLockExclusive(&PhNetworkHashtableLock);\n\n            for (i = 0; i < connectionsToRemove->Count; i++)\n            {\n                PhpRemoveNetworkItem(connectionsToRemove->Items[i]);\n            }\n\n            PhReleaseQueuedLockExclusive(&PhNetworkHashtableLock);\n            PhDereferenceObject(connectionsToRemove);\n        }\n    }\n\n    // Go through the queued network item query data.\n    PhFlushNetworkQueryData();\n\n    // Look for new network connections and update existing ones.\n    for (i = 0; i < numberOfConnections; i++)\n    {\n        PPH_NETWORK_ITEM networkItem;\n\n        // Try to find the connection in our hashtable.\n        networkItem = PhReferenceNetworkItem(\n            connections[i].ProtocolType,\n            &connections[i].LocalEndpoint,\n            &connections[i].RemoteEndpoint,\n            connections[i].ProcessId\n            );\n\n        if (!networkItem)\n        {\n            PPH_PROCESS_ITEM processItem;\n\n            // Network item not found, create it.\n\n            networkItem = PhCreateNetworkItem();\n\n            // Fill in basic information.\n            networkItem->ProtocolType = connections[i].ProtocolType;\n            networkItem->LocalEndpoint = connections[i].LocalEndpoint;\n            networkItem->RemoteEndpoint = connections[i].RemoteEndpoint;\n            networkItem->State = connections[i].State;\n            networkItem->ProcessId = connections[i].ProcessId;\n            networkItem->CreateTime = connections[i].CreateTime;\n            networkItem->LocalScopeId = connections[i].LocalScopeId;\n            networkItem->RemoteScopeId = connections[i].RemoteScopeId;\n            PhpUpdateNetworkItemOwner(networkItem, connections[i].OwnerInfo[0]);\n\n            // Format various strings.\n\n            switch (networkItem->LocalEndpoint.Address.Type)\n            {\n            case PH_NETWORK_TYPE_IPV4:\n                {\n                    WCHAR localAddressString[IP4_ADDRESS_STRING_LENGTH];\n                    ULONG localAddressStringLength = RTL_NUMBER_OF(localAddressString);\n\n                    if (NT_SUCCESS(RtlIpv4AddressToStringEx(\n                        &networkItem->LocalEndpoint.Address.InAddr,\n                        0,\n                        localAddressString,\n                        &localAddressStringLength\n                        )))\n                    {\n                        networkItem->LocalAddressString = PhCreateStringEx(\n                            localAddressString,\n                            (localAddressStringLength - 1) * sizeof(WCHAR)\n                            );\n                    }\n                }\n                break;\n            case PH_NETWORK_TYPE_IPV6:\n                {\n                    WCHAR localAddressString[IP6_ADDRESS_STRING_LENGTH];\n                    ULONG localAddressStringLength = RTL_NUMBER_OF(localAddressString);\n\n                    if (NT_SUCCESS(RtlIpv6AddressToStringEx(\n                        &networkItem->LocalEndpoint.Address.In6Addr,\n                        networkItem->LocalScopeId,\n                        0,\n                        localAddressString,\n                        &localAddressStringLength\n                        )))\n                    {\n                        networkItem->LocalAddressString = PhCreateStringEx(\n                            localAddressString,\n                            (localAddressStringLength - 1) * sizeof(WCHAR)\n                            );\n                    }\n                }\n                break;\n            case PH_NETWORK_TYPE_HYPERV:\n                {\n                    networkItem->LocalAddressString = PhHvSocketAddressString(\n                        &networkItem->LocalEndpoint.Address.HvAddr\n                        );\n                    networkItem->HvService = PhHvSocketGetServiceName(\n                        &networkItem->LocalEndpoint.Address.HvAddr\n                        );\n                }\n                break;\n            }\n\n            switch (networkItem->RemoteEndpoint.Address.Type)\n            {\n            case PH_NETWORK_TYPE_IPV4:\n                {\n                    if (!PhIsNullIpAddress(&networkItem->RemoteEndpoint.Address))\n                    {\n                        WCHAR remoteAddressString[IP4_ADDRESS_STRING_LENGTH];\n                        ULONG remoteAddressStringLength = RTL_NUMBER_OF(remoteAddressString);\n\n                        if (NT_SUCCESS(RtlIpv4AddressToStringEx(\n                            &networkItem->RemoteEndpoint.Address.InAddr,\n                            0,\n                            remoteAddressString,\n                            &remoteAddressStringLength\n                            )))\n                        {\n                            networkItem->RemoteAddressString = PhCreateStringEx(\n                                remoteAddressString,\n                                (remoteAddressStringLength - 1) * sizeof(WCHAR)\n                                );\n                        }\n                    }\n                }\n                break;\n            case PH_NETWORK_TYPE_IPV6:\n                {\n                    if (!PhIsNullIpAddress(&networkItem->RemoteEndpoint.Address))\n                    {\n                        WCHAR remoteAddressString[IP6_ADDRESS_STRING_LENGTH];\n                        ULONG remoteAddressStringLength = RTL_NUMBER_OF(remoteAddressString);\n\n                        if (NT_SUCCESS(RtlIpv6AddressToStringEx(\n                            &networkItem->RemoteEndpoint.Address.In6Addr,\n                            networkItem->RemoteScopeId,\n                            0,\n                            remoteAddressString,\n                            &remoteAddressStringLength\n                            )))\n                        {\n                            networkItem->RemoteAddressString = PhCreateStringEx(\n                                remoteAddressString,\n                                (remoteAddressStringLength - 1) * sizeof(WCHAR)\n                                );\n                        }\n                    }\n                }\n                break;\n            case PH_NETWORK_TYPE_HYPERV:\n                {\n                    networkItem->RemoteAddressString = PhHvSocketAddressString(\n                        &networkItem->RemoteEndpoint.Address.HvAddr\n                        );\n                }\n                break;\n            }\n\n            if (networkItem->LocalEndpoint.Port != 0)\n                PhPrintUInt32(networkItem->LocalPortString, networkItem->LocalEndpoint.Port);\n            if (networkItem->RemoteEndpoint.Port != 0)\n                PhPrintUInt32(networkItem->RemotePortString, networkItem->RemoteEndpoint.Port);\n\n            // Get host names.\n            PhNetworkItemResolveHostname(networkItem);\n\n            // Get process information.\n            if (processItem = PhReferenceProcessItem(networkItem->ProcessId))\n            {\n                networkItem->ProcessItem = processItem;\n                PhSetReference(&networkItem->ProcessName, processItem->ProcessName);\n                networkItem->SubsystemProcess = !!processItem->IsSubsystemProcess;\n\n                if (PhTestEvent(&processItem->Stage1Event))\n                {\n                    networkItem->ProcessIconIndex = processItem->SmallIconIndex;\n                    networkItem->ProcessIconValid = TRUE;\n                }\n\n                // NOTE: We dereference processItem in PhpNetworkItemDeleteProcedure. (dmex)\n            }\n            else\n            {\n                HANDLE processHandle;\n                PPH_STRING fileName;\n                PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n\n                // HACK HACK HACK\n                // WSL subsystem processes (e.g. apache/nginx) create sockets, clone/fork themselves, duplicate the socket into the child process and then terminate.\n                // The socket handle remains valid and in-use by the child process BUT the socket continues returning the PID of the exited process???\n                // Fixing this causes a major performance problem; If we have 100,000 sockets then on previous versions of Windows we would only need 2 system calls maximum\n                // (for the process list) to identify the owner of every socket but now we need to make 4 system calls for every_last_socket totaling 400,000 system calls... great. (dmex)\n                if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, networkItem->ProcessId)))\n                {\n                    if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo)))\n                    {\n                        networkItem->SubsystemProcess = !!basicInfo.IsSubsystemProcess;\n                    }\n\n                    if (NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName)))\n                    {\n                        PhMoveReference(&networkItem->ProcessName, PhGetBaseName(fileName));\n                    }\n\n                    NtClose(processHandle);\n                }\n\n                networkItem->UnknownProcess = TRUE;\n            }\n\n            // Add the network item to the hashtable.\n            PhAcquireQueuedLockExclusive(&PhNetworkHashtableLock);\n            PhAddEntryHashtable(PhNetworkHashtable, &networkItem);\n            PhReleaseQueuedLockExclusive(&PhNetworkHashtableLock);\n\n            // Raise the network item added event.\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderAddedEvent), networkItem);\n        }\n        else\n        {\n            BOOLEAN modified = FALSE;\n\n            if (InterlockedExchange(&networkItem->JustResolved, 0) != 0)\n                modified = TRUE;\n\n            if (networkItem->State != connections[i].State)\n            {\n                networkItem->State = connections[i].State;\n                modified = TRUE;\n            }\n\n            if (!networkItem->ProcessItem)\n            {\n                networkItem->ProcessItem = PhReferenceProcessItem(networkItem->ProcessId);\n                // NOTE: We dereference processItem in PhpNetworkItemDeleteProcedure. (dmex)\n            }\n\n            if (networkItem->ProcessItem)\n            {\n                if (PhIsNullOrEmptyString(networkItem->ProcessName))\n                {\n                    PhSetReference(&networkItem->ProcessName, &networkItem->ProcessItem->ProcessName);\n                    modified = TRUE;\n                }\n\n                if (!networkItem->ProcessIconValid && PhTestEvent(&networkItem->ProcessItem->Stage1Event))\n                {\n                    networkItem->ProcessIconIndex = networkItem->ProcessItem->SmallIconIndex;\n                    networkItem->ProcessIconValid = TRUE;\n                    modified = TRUE;\n                }\n            }\n\n            if (networkItem->InvalidateHostname)\n            {\n                networkItem->InvalidateHostname = FALSE;\n\n                PhNetworkItemInvalidateHostname(networkItem);\n\n                modified = TRUE;\n            }\n\n            if (modified)\n            {\n                // Raise the network item modified event.\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderModifiedEvent), networkItem);\n            }\n\n            PhDereferenceObject(networkItem);\n        }\n    }\n\n    PhFree(connections);\n\n    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdatedEvent), UlongToPtr(runCount));\n\n    PhTraceFuncExit(\"Network provider run count: %lu\", runCount);\n\n    runCount++;\n}\n\n#ifdef _WIN64\nPHVSOCKET_LISTENERS PhpGetHvSocketListeners(\n    _In_ HANDLE SystemHandle,\n    _In_ const GUID* VmId\n    )\n{\n    NTSTATUS status;\n    ULONG length;\n    PHVSOCKET_LISTENERS listeners;\n\n    length = PAGE_SIZE;\n    listeners = PhAllocate(length);\n\n    for (;;)\n    {\n        status = PhHvSocketGetListeners(SystemHandle, VmId, listeners, length, &length);\n        if (status != STATUS_BUFFER_TOO_SMALL)\n        {\n            break;\n        }\n\n        length *= 2;\n        listeners = PhReAllocate(listeners, length);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(listeners);\n        listeners = NULL;\n    }\n\n    return listeners;\n}\n\nPHVSOCKET_CONNECTIONS PhpGetHvSocketConnections(\n    _In_ HANDLE SystemHandle,\n    _In_ const GUID* VmId\n    )\n{\n    NTSTATUS status;\n    ULONG length;\n    PHVSOCKET_CONNECTIONS connections;\n\n    length = PAGE_SIZE;\n    connections = PhAllocate(length);\n\n    for (;;)\n    {\n        status = PhHvSocketGetConnections(SystemHandle, VmId, connections, length, &length);\n        if (status != STATUS_BUFFER_TOO_SMALL || length == 0)\n        {\n            break;\n        }\n\n        length *= 2;\n        connections = PhReAllocate(connections, length);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(connections);\n        connections = NULL;\n    }\n\n    return connections;\n}\n\nVOID PhpCollectHvSocket(\n    _In_ PGUID VmIds,\n    _In_ SIZE_T Count,\n    _Out_ PHVSOCKET_LISTENERS* Listeners,\n    _Out_ PHVSOCKET_CONNECTIONS* Connections\n    )\n{\n    HANDLE systemHandle;\n    PHVSOCKET_LISTENERS listeners;\n    PHVSOCKET_CONNECTIONS connections;\n    ULONG listenersCount;\n    ULONG connectionsCount;\n    PPH_LIST listenersList;\n    PPH_LIST connectionsList;\n\n    if (!NT_SUCCESS(PhHvSocketOpenSystemControl(&systemHandle, NULL)))\n    {\n        *Listeners = NULL;\n        *Connections = NULL;\n        return;\n    }\n\n    listenersCount = 0;\n    connectionsCount = 0;\n    listenersList = PhCreateList(1);\n    connectionsList = PhCreateList(1);\n\n    for (ULONG i = 0; i < Count; i++)\n    {\n        if (listeners = PhpGetHvSocketListeners(systemHandle, &VmIds[i]))\n        {\n            PhAddItemList(listenersList, listeners);\n            listenersCount += listeners->Count;\n        }\n\n        if (connections = PhpGetHvSocketConnections(systemHandle, &VmIds[i]))\n        {\n            PhAddItemList(connectionsList, connections);\n            connectionsCount += connections->Count;\n        }\n    }\n\n    listeners = NULL;\n    connections = NULL;\n\n    if (listenersCount)\n    {\n        listeners = PhAllocate(\n            RTL_SIZEOF_THROUGH_FIELD(HVSOCKET_LISTENERS, Listener) +\n            (sizeof(HVSOCKET_LISTENER) * listenersCount)\n            );\n        listeners->Count = 0;\n    }\n\n    for (ULONG i = 0; i < listenersList->Count; i++)\n    {\n        PHVSOCKET_LISTENERS l;\n\n        l = listenersList->Items[i];\n\n        if (listeners)\n        {\n            RtlCopyMemory(\n                &listeners->Listener[listeners->Count],\n                l->Listener,\n                sizeof(HVSOCKET_LISTENER) * l->Count\n                );\n\n            listeners->Count += l->Count;\n        }\n\n        PhFree(l);\n    }\n\n    if (connectionsCount)\n    {\n        connections = PhAllocate(\n            RTL_SIZEOF_THROUGH_FIELD(HVSOCKET_CONNECTIONS, Connection) +\n            (sizeof(HVSOCKET_CONNECTION) * connectionsCount)\n            );\n        connections->Count = 0;\n    }\n\n    for (ULONG i = 0; i < connectionsList->Count; i++)\n    {\n        PHVSOCKET_CONNECTIONS c;\n\n        c = connectionsList->Items[i];\n\n        if (connections)\n        {\n            RtlCopyMemory(\n                &connections->Connection[connections->Count],\n                c->Connection,\n                sizeof(HVSOCKET_CONNECTION) * c->Count\n                );\n\n            connections->Count += c->Count;\n        }\n\n        PhFree(c);\n    }\n\n    PhDereferenceObject(listenersList);\n    PhDereferenceObject(connectionsList);\n\n    *Listeners = listeners;\n    *Connections = connections;\n\n    NtClose(systemHandle);\n}\n\nstatic BOOLEAN NTAPI PhpHvEnumComputeSystemCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PKEY_BASIC_INFORMATION Information,\n    _In_ PVOID Context\n    )\n{\n    PPH_ARRAY guidArray = Context;\n    PH_STRINGREF name;\n    PH_FORMAT format[3];\n    PPH_STRING string;\n    GUID guid;\n\n    name.Buffer = Information->Name;\n    name.Length = Information->NameLength;\n\n    PhInitFormatC(&format[0], L'{');\n    PhInitFormatSR(&format[1], name);\n    PhInitFormatC(&format[2], L'}');\n\n    string = PhFormat(format, 3, 10);\n\n    if (NT_SUCCESS(PhStringToGuid(&string->sr, &guid)))\n        PhAddItemArray(guidArray, &guid);\n\n    PhDereferenceObject(string);\n\n    return TRUE;\n}\n\nVOID PhpGetHvSocket(\n    _Out_ PHVSOCKET_LISTENERS* Listeners,\n    _Out_ PHVSOCKET_CONNECTIONS* Connections\n)\n{\n    static const PH_STRINGREF hvComputeSystemKey = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\HostComputeService\\\\VolatileStore\\\\ComputeSystem\");\n    PH_ARRAY guidArray;\n    HANDLE keyHandle;\n\n    PhInitializeArray(&guidArray, sizeof(GUID), 10);\n    PhAddItemArray(&guidArray, (PVOID)&HV_GUID_WILDCARD);\n    PhAddItemArray(&guidArray, (PVOID)&HV_GUID_BROADCAST);\n    PhAddItemArray(&guidArray, (PVOID)&HV_GUID_CHILDREN);\n    PhAddItemArray(&guidArray, (PVOID)&HV_GUID_LOOPBACK);\n    PhAddItemArray(&guidArray, (PVOID)&HV_GUID_PARENT);\n    PhAddItemArray(&guidArray, (PVOID)&HV_GUID_SILOHOST);\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_ENUMERATE_SUB_KEYS,\n        PH_KEY_LOCAL_MACHINE,\n        &hvComputeSystemKey,\n        0\n        )))\n    {\n        PhEnumerateKey(keyHandle, KeyBasicInformation, PhpHvEnumComputeSystemCallback, &guidArray);\n        NtClose(keyHandle);\n    }\n\n    PhpCollectHvSocket(\n        PhFinalArrayItems(&guidArray),\n        PhFinalArrayCount(&guidArray),\n        Listeners,\n        Connections\n        );\n\n    PhDeleteArray(&guidArray);\n}\n#endif // _WIN64\n\n_Success_(return)\nBOOLEAN PhGetNetworkConnections(\n    _Out_ PPH_NETWORK_CONNECTION *Connections,\n    _Out_ PULONG NumberOfConnections\n    )\n{\n    PVOID table;\n    ULONG tableSize;\n    PMIB_TCPTABLE_OWNER_MODULE tcp4Table;\n    PMIB_TCP6TABLE_OWNER_MODULE tcp6Table;\n    PMIB_UDPTABLE_OWNER_MODULE udp4Table;\n    PMIB_UDP6TABLE_OWNER_MODULE udp6Table;\n    PMIB_TCPTABLE2 boundTcpTable;\n    PMIB_TCP6TABLE2 boundTcp6Table;\n#ifdef _WIN64\n    PHVSOCKET_LISTENERS hvListeners;\n    PHVSOCKET_CONNECTIONS hvConnections;\n#endif\n    ULONG i;\n    ULONG count = 0;\n    ULONG index = 0;\n    PPH_NETWORK_CONNECTION connections;\n\n    // TCP IPv4\n\n    tableSize = 0;\n    GetExtendedTcpTable_I(NULL, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0);\n    table = PhAllocate(tableSize);\n\n    if (GetExtendedTcpTable_I(table, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) == NO_ERROR)\n    {\n        tcp4Table = table;\n        count += tcp4Table->dwNumEntries;\n    }\n    else\n    {\n        PhFree(table);\n        tcp4Table = NULL;\n    }\n\n    // TCP IPv6\n\n    tableSize = 0;\n    GetExtendedTcpTable_I(NULL, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0);\n    table = PhAllocate(tableSize);\n\n    if (GetExtendedTcpTable_I(table, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == NO_ERROR)\n    {\n        tcp6Table = table;\n        count += tcp6Table->dwNumEntries;\n    }\n    else\n    {\n        PhFree(table);\n        tcp6Table = NULL;\n    }\n\n    // UDP IPv4\n\n    tableSize = 0;\n    GetExtendedUdpTable_I(NULL, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_MODULE, 0);\n    table = PhAllocate(tableSize);\n\n    if (GetExtendedUdpTable_I(table, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_MODULE, 0) == NO_ERROR)\n    {\n        udp4Table = table;\n        count += udp4Table->dwNumEntries;\n    }\n    else\n    {\n        PhFree(table);\n        udp4Table = NULL;\n    }\n\n    // UDP IPv6\n\n    tableSize = 0;\n    GetExtendedUdpTable_I(NULL, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0);\n    table = PhAllocate(tableSize);\n\n    if (GetExtendedUdpTable_I(table, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0) == NO_ERROR)\n    {\n        udp6Table = table;\n        count += udp6Table->dwNumEntries;\n    }\n    else\n    {\n        PhFree(table);\n        udp6Table = NULL;\n    }\n\n#ifdef _WIN64\n    // Hyper-V\n    PhpGetHvSocket(&hvListeners, &hvConnections);\n    if (hvListeners)\n    {\n        count += hvListeners->Count;\n    }\n    if (hvConnections)\n    {\n        count += hvConnections->Count;\n    }\n#endif\n\n    if (PhEnableNetworkBoundConnections && WindowsVersion >= WINDOWS_10_RS5 && GetBoundTcpEndpointTable_I && GetBoundTcp6EndpointTable_I)\n    {\n        // Bound TCP IPv4\n\n        if (GetBoundTcpEndpointTable_I(&table, PhHeapHandle, 0) == NO_ERROR)\n        {\n            boundTcpTable = table;\n            count += boundTcpTable->dwNumEntries;\n        }\n        else\n        {\n            boundTcpTable = NULL;\n        }\n\n        // Bound TCP IPv6\n\n        if (GetBoundTcp6EndpointTable_I(&table, PhHeapHandle, 0) == NO_ERROR)\n        {\n            boundTcp6Table = table;\n            count += boundTcp6Table->dwNumEntries;\n        }\n        else\n        {\n            boundTcp6Table = NULL;\n        }\n    }\n    else\n    {\n        boundTcpTable = NULL;\n        boundTcp6Table = NULL;\n    }\n\n    connections = PhAllocate(sizeof(PH_NETWORK_CONNECTION) * count);\n    memset(connections, 0, sizeof(PH_NETWORK_CONNECTION) * count);\n\n    if (tcp4Table)\n    {\n        for (i = 0; i < tcp4Table->dwNumEntries; i++)\n        {\n            connections[index].ProtocolType = PH_NETWORK_PROTOCOL_TCP4;\n\n            connections[index].LocalEndpoint.Address.Type = PH_NETWORK_TYPE_IPV4;\n            memcpy(connections[index].LocalEndpoint.Address.Ipv4, &tcp4Table->table[i].dwLocalAddr, sizeof(IN_ADDR));\n            connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)tcp4Table->table[i].dwLocalPort);\n\n            connections[index].RemoteEndpoint.Address.Type = PH_NETWORK_TYPE_IPV4;\n            memcpy(connections[index].RemoteEndpoint.Address.Ipv4, &tcp4Table->table[i].dwRemoteAddr, sizeof(IN_ADDR));\n            connections[index].RemoteEndpoint.Port = _byteswap_ushort((USHORT)tcp4Table->table[i].dwRemotePort);\n\n            connections[index].State = tcp4Table->table[i].dwState;\n            connections[index].ProcessId = UlongToHandle(tcp4Table->table[i].dwOwningPid);\n            connections[index].CreateTime = tcp4Table->table[i].liCreateTimestamp;\n            memcpy(\n                connections[index].OwnerInfo,\n                tcp4Table->table[i].OwningModuleInfo,\n                sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE)\n                );\n\n            index++;\n        }\n\n        PhFree(tcp4Table);\n    }\n\n    if (tcp6Table)\n    {\n        for (i = 0; i < tcp6Table->dwNumEntries; i++)\n        {\n            connections[index].ProtocolType = PH_NETWORK_PROTOCOL_TCP6;\n\n            connections[index].LocalEndpoint.Address.Type = PH_NETWORK_TYPE_IPV6;\n            memcpy(connections[index].LocalEndpoint.Address.Ipv6, tcp6Table->table[i].ucLocalAddr, 16);\n            connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)tcp6Table->table[i].dwLocalPort);\n\n            connections[index].RemoteEndpoint.Address.Type = PH_NETWORK_TYPE_IPV6;\n            memcpy(connections[index].RemoteEndpoint.Address.Ipv6, tcp6Table->table[i].ucRemoteAddr, 16);\n            connections[index].RemoteEndpoint.Port = _byteswap_ushort((USHORT)tcp6Table->table[i].dwRemotePort);\n\n            connections[index].State = tcp6Table->table[i].dwState;\n            connections[index].ProcessId = UlongToHandle(tcp6Table->table[i].dwOwningPid);\n            connections[index].CreateTime = tcp6Table->table[i].liCreateTimestamp;\n            memcpy(\n                connections[index].OwnerInfo,\n                tcp6Table->table[i].OwningModuleInfo,\n                sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE)\n                );\n\n            connections[index].LocalScopeId = tcp6Table->table[i].dwLocalScopeId;\n            connections[index].RemoteScopeId = tcp6Table->table[i].dwRemoteScopeId;\n\n            index++;\n        }\n\n        PhFree(tcp6Table);\n    }\n\n    if (udp4Table)\n    {\n        for (i = 0; i < udp4Table->dwNumEntries; i++)\n        {\n            connections[index].ProtocolType = PH_NETWORK_PROTOCOL_UDP4;\n\n            connections[index].LocalEndpoint.Address.Type = PH_NETWORK_TYPE_IPV4;\n            memcpy(connections[index].LocalEndpoint.Address.Ipv4, &udp4Table->table[i].dwLocalAddr, sizeof(IN_ADDR));\n            connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)udp4Table->table[i].dwLocalPort);\n\n            connections[index].RemoteEndpoint.Address.Type = 0;\n\n            connections[index].State = 0;\n            connections[index].ProcessId = UlongToHandle(udp4Table->table[i].dwOwningPid);\n            connections[index].CreateTime = udp4Table->table[i].liCreateTimestamp;\n            memcpy(\n                connections[index].OwnerInfo,\n                udp4Table->table[i].OwningModuleInfo,\n                sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE)\n                );\n\n            index++;\n        }\n\n        PhFree(udp4Table);\n    }\n\n    if (udp6Table)\n    {\n        for (i = 0; i < udp6Table->dwNumEntries; i++)\n        {\n            connections[index].ProtocolType = PH_NETWORK_PROTOCOL_UDP6;\n\n            connections[index].LocalEndpoint.Address.Type = PH_NETWORK_TYPE_IPV6;\n            memcpy(connections[index].LocalEndpoint.Address.Ipv6, udp6Table->table[i].ucLocalAddr, sizeof(IN6_ADDR));\n            connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)udp6Table->table[i].dwLocalPort);\n\n            connections[index].RemoteEndpoint.Address.Type = 0;\n\n            connections[index].State = 0;\n            connections[index].ProcessId = UlongToHandle(udp6Table->table[i].dwOwningPid);\n            connections[index].CreateTime = udp6Table->table[i].liCreateTimestamp;\n            memcpy(\n                connections[index].OwnerInfo,\n                udp6Table->table[i].OwningModuleInfo,\n                sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE)\n                );\n\n            connections[index].LocalScopeId = udp6Table->table[i].dwLocalScopeId;\n            connections[index].RemoteScopeId = 0;\n\n            index++;\n        }\n\n        PhFree(udp6Table);\n    }\n\n    if (PhEnableNetworkBoundConnections && WindowsVersion >= WINDOWS_10_RS5)\n    {\n        if (boundTcpTable)\n        {\n            for (i = 0; i < boundTcpTable->dwNumEntries; i++)\n            {\n                connections[index].ProtocolType = PH_NETWORK_PROTOCOL_TCP4;\n\n                connections[index].LocalEndpoint.Address.Type = PH_NETWORK_TYPE_IPV4;\n                memcpy(connections[index].LocalEndpoint.Address.Ipv4, &boundTcpTable->table[i].dwLocalAddr, sizeof(IN_ADDR));\n                connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)boundTcpTable->table[i].dwLocalPort);\n\n                connections[index].RemoteEndpoint.Address.Type = PH_NETWORK_TYPE_IPV4;\n                memcpy(connections[index].RemoteEndpoint.Address.Ipv4, &boundTcpTable->table[i].dwRemoteAddr, sizeof(IN_ADDR));\n                connections[index].RemoteEndpoint.Port = _byteswap_ushort((USHORT)boundTcpTable->table[i].dwRemotePort);\n\n                connections[index].State = boundTcpTable->table[i].dwState;\n                connections[index].ProcessId = UlongToHandle(boundTcpTable->table[i].dwOwningPid);\n\n                index++;\n            }\n\n            RtlFreeHeap(PhHeapHandle, 0, boundTcpTable);\n        }\n\n        if (boundTcp6Table)\n        {\n            for (i = 0; i < boundTcp6Table->dwNumEntries; i++)\n            {\n                connections[index].ProtocolType = PH_NETWORK_PROTOCOL_TCP6;\n\n                connections[index].LocalEndpoint.Address.Type = PH_NETWORK_TYPE_IPV6;\n                memcpy(connections[index].LocalEndpoint.Address.Ipv6, boundTcp6Table->table[i].LocalAddr.s6_addr, sizeof(IN6_ADDR));\n                connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)boundTcp6Table->table[i].dwLocalPort);\n\n                connections[index].RemoteEndpoint.Address.Type = PH_NETWORK_TYPE_IPV6;\n                memcpy(connections[index].RemoteEndpoint.Address.Ipv6, boundTcp6Table->table[i].RemoteAddr.s6_addr, sizeof(IN6_ADDR));\n                connections[index].RemoteEndpoint.Port = _byteswap_ushort((USHORT)boundTcp6Table->table[i].dwRemotePort);\n\n                connections[index].State = boundTcp6Table->table[i].State;\n                connections[index].ProcessId = UlongToHandle(boundTcp6Table->table[i].dwOwningPid);\n\n                connections[index].LocalScopeId = boundTcp6Table->table[i].dwLocalScopeId;\n                connections[index].RemoteScopeId = boundTcp6Table->table[i].dwRemoteScopeId;\n\n                index++;\n            }\n\n            RtlFreeHeap(PhHeapHandle, 0, boundTcp6Table);\n        }\n    }\n\n#ifdef _WIN64\n    if (hvListeners)\n    {\n        for (i = 0; i < hvListeners->Count; i++)\n        {\n            connections[index].ProtocolType = PH_NETWORK_PROTOCOL_HYPERV;\n\n            connections[index].LocalEndpoint.Address.Type = PH_NETWORK_TYPE_HYPERV;\n            connections[index].LocalEndpoint.Address.HvAddr = hvListeners->Listener[i].ServiceId;\n\n            if (PhHvSocketIsVSockTemplate(&connections[index].LocalEndpoint.Address.HvAddr))\n                connections[index].LocalEndpoint.Port = hvListeners->Listener[i].Port;\n            else\n                connections[index].LocalEndpoint.Port = 0;\n\n            connections[index].RemoteEndpoint.Address.Type = PH_NETWORK_TYPE_HYPERV;\n            connections[index].RemoteEndpoint.Address.HvAddr = hvListeners->Listener[i].VmId;\n\n            connections[index].ProcessId = UlongToHandle(hvListeners->Listener[i].ProcessId);\n            connections[index].CreateTime = hvListeners->Listener[i].TimeStamp;\n\n            connections[index].State = 0; // HACK\n\n            index++;\n        }\n\n        PhFree(hvListeners);\n    }\n\n    if (hvConnections)\n    {\n        for (i = 0; i < hvConnections->Count; i++)\n        {\n            connections[index].ProtocolType = PH_NETWORK_PROTOCOL_HYPERV;\n\n            connections[index].LocalEndpoint.Address.Type = PH_NETWORK_TYPE_HYPERV;\n            connections[index].LocalEndpoint.Address.HvAddr = hvConnections->Connection[i].ServiceId;\n\n            if (PhHvSocketIsVSockTemplate(&connections[index].LocalEndpoint.Address.HvAddr))\n                connections[index].LocalEndpoint.Port = hvConnections->Connection[i].Port;\n            else\n                connections[index].LocalEndpoint.Port = 0;\n\n            connections[index].RemoteEndpoint.Address.Type = PH_NETWORK_TYPE_HYPERV;\n            connections[index].RemoteEndpoint.Address.HvAddr = hvConnections->Connection[i].VmId;\n\n            connections[index].ProcessId = UlongToHandle(hvConnections->Connection[i].ProcessId);\n            connections[index].CreateTime = hvConnections->Connection[i].TimeStamp;\n\n            connections[index].State = 1; // HACK\n\n            index++;\n        }\n\n        PhFree(hvConnections);\n    }\n#endif\n\n    *NumberOfConnections = count;\n    *Connections = connections;\n\n    return TRUE;\n}\n\nstatic CONST PH_KEY_VALUE_PAIR PhProtocolTypeStrings[] =\n{\n    SIP(SREF(L\"Unknown\"), 0),\n    SIP(SREF(L\"TCP\"), PH_NETWORK_PROTOCOL_TCP4),\n    SIP(SREF(L\"TCP6\"), PH_NETWORK_PROTOCOL_TCP6),\n    SIP(SREF(L\"UDP\"), PH_NETWORK_PROTOCOL_UDP4),\n    SIP(SREF(L\"UDP6\"), PH_NETWORK_PROTOCOL_UDP6),\n    SIP(SREF(L\"HYPERV\"), PH_NETWORK_PROTOCOL_HYPERV),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR PhTcpStateStrings[] =\n{\n    SIP(SREF(L\"Unknown\"), 0),\n    SIP(SREF(L\"Closed\"), MIB_TCP_STATE_CLOSED),\n    SIP(SREF(L\"Listen\"), MIB_TCP_STATE_LISTEN),\n    SIP(SREF(L\"SYN sent\"), MIB_TCP_STATE_SYN_SENT),\n    SIP(SREF(L\"SYN received\"), MIB_TCP_STATE_SYN_RCVD),\n    SIP(SREF(L\"Established\"), MIB_TCP_STATE_ESTAB),\n    SIP(SREF(L\"FIN wait 1\"), MIB_TCP_STATE_FIN_WAIT1),\n    SIP(SREF(L\"FIN wait 2\"), MIB_TCP_STATE_FIN_WAIT2),\n    SIP(SREF(L\"Close wait\"), MIB_TCP_STATE_CLOSE_WAIT),\n    SIP(SREF(L\"Closing\"), MIB_TCP_STATE_CLOSING),\n    SIP(SREF(L\"Last ACK\"), MIB_TCP_STATE_LAST_ACK),\n    SIP(SREF(L\"Time wait\"), MIB_TCP_STATE_TIME_WAIT),\n    SIP(SREF(L\"Delete TCB\"), MIB_TCP_STATE_DELETE_TCB),\n    SIP(SREF(L\"Bound\"), MIB_TCP_STATE_RESERVED),\n};\n\nPCPH_STRINGREF PhGetProtocolTypeName(\n    _In_ ULONG ProtocolType\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhFindStringRefSiKeyValuePairs(\n        PhProtocolTypeStrings,\n        sizeof(PhProtocolTypeStrings),\n        ProtocolType,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return PhProtocolTypeStrings[0].Key;\n}\n\nPCPH_STRINGREF PhGetTcpStateName(\n    _In_ ULONG State\n    )\n{\n    switch (State)\n    {\n    case MIB_TCP_STATE_CLOSED:\n    case MIB_TCP_STATE_LISTEN:\n    case MIB_TCP_STATE_SYN_SENT:\n    case MIB_TCP_STATE_SYN_RCVD:\n    case MIB_TCP_STATE_ESTAB:\n    case MIB_TCP_STATE_FIN_WAIT1:\n    case MIB_TCP_STATE_FIN_WAIT2:\n    case MIB_TCP_STATE_CLOSE_WAIT:\n    case MIB_TCP_STATE_CLOSING:\n    case MIB_TCP_STATE_LAST_ACK:\n    case MIB_TCP_STATE_TIME_WAIT:\n    case MIB_TCP_STATE_DELETE_TCB:\n        return PhTcpStateStrings[State].Key;\n    case MIB_TCP_STATE_RESERVED:\n        return PhTcpStateStrings[13].Key;\n    }\n\n    // TODO: We can't index the string from MIB_TCP_STATE_RESERVED (dmex)\n    //if (PhIndexStringRefSiKeyValuePairs(\n    //    PhTcpStateStrings,\n    //    sizeof(PhTcpStateStrings),\n    //    State,\n    //    &string\n    //    ))\n    //{\n    //    return string;\n    //}\n\n    return PhTcpStateStrings[0].Key;\n}\n"
  },
  {
    "path": "SystemInformer/netstk.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *\n */\n\n#include <phapp.h>\n#include <symprv.h>\n#include <netprv.h>\n\ntypedef struct NETWORK_STACK_CONTEXT\n{\n    HWND ListViewHandle;\n    PH_LAYOUT_MANAGER LayoutManager;\n    PPH_NETWORK_ITEM NetworkItem;\n    PPH_SYMBOL_PROVIDER SymbolProvider;\n    HANDLE LoadingProcessId;\n} NETWORK_STACK_CONTEXT, *PNETWORK_STACK_CONTEXT;\n\nINT_PTR CALLBACK PhpNetworkStackDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nstatic RECT MinimumSize = { -1, -1, -1, -1 };\n\nstatic BOOLEAN LoadSymbolsEnumGenericModulesCallback(\n    _In_ PPH_MODULE_INFO Module,\n    _In_opt_ PVOID Context\n    )\n{\n    PNETWORK_STACK_CONTEXT context = Context;\n    PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider;\n\n    // If we're loading kernel module symbols for a process other than\n    // System, ignore modules which are in user space. This may happen\n    // in Windows 7.\n    if (\n        context->LoadingProcessId == SYSTEM_PROCESS_ID &&\n        context->NetworkItem->ProcessId != SYSTEM_PROCESS_ID &&\n        (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress\n        )\n        return TRUE;\n\n    PhLoadModuleSymbolProvider(\n        symbolProvider,\n        Module->FileName,\n        (ULONG64)Module->BaseAddress,\n        Module->Size\n        );\n\n    return TRUE;\n}\n\nVOID PhShowNetworkStackDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    )\n{\n    NETWORK_STACK_CONTEXT networkStackContext;\n\n    networkStackContext.NetworkItem = NetworkItem;\n    networkStackContext.SymbolProvider = PhCreateSymbolProvider(NetworkItem->ProcessId);\n\n    if (networkStackContext.SymbolProvider->IsRealHandle)\n    {\n        // Load symbols for the process.\n        networkStackContext.LoadingProcessId = NetworkItem->ProcessId;\n        PhEnumGenericModules(\n            NetworkItem->ProcessId,\n            networkStackContext.SymbolProvider->ProcessHandle,\n            0,\n            LoadSymbolsEnumGenericModulesCallback,\n            &networkStackContext\n            );\n        // Load symbols for kernel-mode.\n        networkStackContext.LoadingProcessId = SYSTEM_PROCESS_ID;\n        PhEnumGenericModules(\n            SYSTEM_PROCESS_ID,\n            NULL,\n            0,\n            LoadSymbolsEnumGenericModulesCallback,\n            &networkStackContext\n            );\n    }\n    else\n    {\n        PhDereferenceObject(networkStackContext.SymbolProvider);\n        PhShowError(ParentWindowHandle, L\"%s\", L\"Unable to open the process.\");\n        return;\n    }\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_NETSTACK),\n        ParentWindowHandle,\n        PhpNetworkStackDlgProc,\n        &networkStackContext\n        );\n\n    PhDereferenceObject(networkStackContext.SymbolProvider);\n}\n\nINT_PTR CALLBACK PhpNetworkStackDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PNETWORK_STACK_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PNETWORK_STACK_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n        if (uMsg == WM_DESTROY)\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HWND lvHandle;\n            PVOID address;\n            ULONG i;\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 350, L\"Name\");\n            PhSetListViewStyle(lvHandle, FALSE, TRUE);\n            PhSetControlTheme(lvHandle, L\"explorer\");\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, lvHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            if (MinimumSize.left == -1)\n            {\n                RECT rect;\n\n                rect.left = 0;\n                rect.top = 0;\n                rect.right = 190;\n                rect.bottom = 120;\n                MapDialogRect(hwndDlg, &rect);\n                MinimumSize = rect;\n                MinimumSize.left = 0;\n            }\n\n            for (i = 0; i < PH_NETWORK_OWNER_INFO_SIZE; i++)\n            {\n                PPH_STRING name;\n\n                address = *(PVOID *)&context->NetworkItem->OwnerInfo[i];\n\n                if ((ULONG_PTR)address < PAGE_SIZE) // stop at an invalid address\n                    break;\n\n                name = PhGetSymbolFromAddress(\n                    context->SymbolProvider,\n                    (ULONG64)address,\n                    NULL,\n                    NULL,\n                    NULL,\n                    NULL\n                    );\n                PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL);\n                PhDereferenceObject(name);\n            }\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL: // Esc and X button to close\n            case IDOK:\n                EndDialog(hwndDlg, IDOK);\n                break;\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/netsup.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2025\n *\n */\n\n#include <phapp.h>\n#include <mapldr.h>\n#include <netprv.h>\n\nCONST NPI_MODULEID NPI_MS_IPV4_MODULEID = { 2, MIT_GUID, .Guid = { 0xeb004a00, 0x9b1a, 0x11d4, { 0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xbc } } };\nCONST NPI_MODULEID NPI_MS_IPV6_MODULEID = { 2, MIT_GUID, .Guid = { 0xeb004a01, 0x9b1a, 0x11d4, { 0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xbc } } };\nCONST NPI_MODULEID NPI_MS_UDP_MODULEID = { 2, MIT_GUID, .Guid = { 0xeb004a02, 0x9b1a, 0x11d4, { 0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xbc } } };\nCONST NPI_MODULEID NPI_MS_TCP_MODULEID = { 2, MIT_GUID, .Guid = { 0xeb004a03, 0x9b1a, 0x11d4, { 0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xbc } } };\nCONST NPI_MODULEID NPI_MS_NDIS_MODULEID = { 2, MIT_GUID, .Guid = { 0xeb004a11, 0x9b1a, 0x11d4, { 0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xbc } } };\nCONST NPI_MODULEID NPI_MS_FL6T_MODULEID = { 2, MIT_GUID, .Guid = { 0xeb004a1C, 0x9b1a, 0x11d4, { 0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xbc } } }; // Teredo\n\ntypedef enum _NSI_STORE\n{\n    NsiPersistent,\n    NsiActive,\n    NsiBoth,\n    NsiCurrent,\n    NsiBootFirmwareTable\n} NSI_STORE;\n\ntypedef enum _NSI_SET_ACTION\n{\n    NsiSetDefault = 0,\n    NsiSetCreateOnly = 1,\n    NsiSetCreateOrSet = 2,\n    NsiSetDelete = 3,\n    NsiSetReset = 4,\n    NsiSetClear = 5,\n    NsiSetCreateOrSetWithReference = 6,\n    NsiSetDeleteWithReference = 7,\n} NSI_SET_ACTION;\n\ntypedef enum _NSI_TCP_INFORMATION_CLASS\n{\n    NsiTcpTableOwnerPidAll = 3, // NSI_TCP_ALL_TABLE // TCP_TABLE_OWNER_PID_ALL and TCP_TABLE_OWNER_MODULE_ALL\n    NsiTcpTableOwnerPidAllConnected = 4, // NSI_TCP_ESTAB_TABLE // TCP_TABLE_OWNER_PID_CONNECTIONS and TCP_TABLE_OWNER_MODULE_CONNECTIONS\n    NsiTcpTableOwnerPidAllListener = 5, // NSI_TCP_LISTEN_TABLE // TCP_TABLE_OWNER_PID_LISTENER and TCP_TABLE_OWNER_MODULE_LISTENER\n\n    //NsiTcpConnectionTable, // TCP_TABLE_OWNER_PID_ALL and TCP_TABLE_OWNER_MODULE_ALL\n    //NsiTcpListenerTable, // TCP_TABLE_OWNER_PID_LISTENER and TCP_TABLE_OWNER_MODULE_LISTENER\n    //NsiTcpStats, // MIB_TCPSTATS\n    //NsiTcp6ConnectionTable, // TCP_TABLE_OWNER_PID_ALL and TCP_TABLE_OWNER_MODULE_ALL (IPv6)\n    //NsiTcp6ListenerTable, // TCP_TABLE_OWNER_PID_LISTENER and TCP_TABLE_OWNER_MODULE_LISTENER (IPv6)\n    //NsiTcp6Stats, // MIB_TCP6STATS\n    //NsiTcpGlobalStats, // MIB_TCPSTATS_EX\n    //NsiTcp6GlobalStats, // MIB_TCP6STATS_EX\n    //NsiTcpConnectionTableEx, // TCP_TABLE_OWNER_PID_CONNECTIONS and TCP_TABLE_OWNER_MODULE_CONNECTIONS\n    //NsiTcp6ConnectionTableEx, // TCP_TABLE_OWNER_PID_CONNECTIONS and TCP_TABLE_OWNER_MODULE_CONNECTIONS (IPv6)\n    //NsiTcpFineGrainStats, // MIB_TCPSTATS_FINE\n    //NsiTcp6FineGrainStats, // MIB_TCP6STATS_FINE\n    //NsiTcpConnectionOffloadState, // TCP_OFFLOAD_STATE\n    //NsiTcp6ConnectionOffloadState, // TCP_OFFLOAD_STATE (IPv6)\n    //NsiTcpConnectionOffloadParameters, // TCP_OFFLOAD_PARAMETERS\n    //NsiTcp6ConnectionOffloadParameters, // TCP_OFFLOAD_PARAMETERS (IPv6)\n\n    NsiTcpSetIfEntry = 16, // input: NSI_SET_TCP_ENTRY\n\n    //NsiTcpCongestionProvider, // TCP_CONGESTION_PROVIDER\n    //NsiTcpCongestionProviderEx, // TCP_CONGESTION_PROVIDER_EX\n    //NsiTcpMaxConnections, // ULONG\n    //NsiTcpMaxHalfOpenConnections, // ULONG\n    //NsiTcpConnectionOffloadStateEx, // TCP_OFFLOAD_STATE_EX\n    //NsiTcp6ConnectionOffloadStateEx, // TCP_OFFLOAD_STATE_EX (IPv6)\n    //NsiTcpMaxInfoClass\n} NSI_TCP_INFORMATION_CLASS;\n\n//typedef enum _NSI_UDP_INFORMATION_CLASS\n//{\n//    NsiUdpEndpointTable, // UDP_TABLE_OWNER_PID\n//    NsiUdp6EndpointTable, // UDP6_TABLE_OWNER_PID\n//    NsiUdpStats, // MIB_UDPSTATS\n//    NsiUdp6Stats, // MIB_UDP6STATS\n//    NsiUdpGlobalStats, // MIB_UDPSTATS_EX\n//    NsiUdp6GlobalStats, // MIB_UDP6STATS_EX\n//    NsiUdpMaxInfoClass\n//} NSI_UDP_INFORMATION_CLASS;\n\ntypedef enum _NSI_IF_INFORMATION_CLASS\n{\n    NsiInterfaceLuidToGuid = 0,\n    NsiInterfaceGuidToLuid = 1,\n    NsiInterfaceIndexToLuid = 2,\n    //NsiInterfaceMaxInfoClass\n} NSI_IF_INFORMATION_CLASS;\n\ntypedef struct _NSI_SET_TCP_ENTRY\n{\n    union\n    {\n        union\n        {\n            SOCKADDR_IN LocalTcpEntryIpV4;\n            SOCKADDR_IN6 LocalTcpEntryIpV6;\n        };\n        struct\n        {\n            ADDRESS_FAMILY LocalFamily;\n            USHORT LocalPort;\n            IN_ADDR LocalAddressIPv4;\n            IN6_ADDR LocalAddressIPv6;\n            ULONG LocalScopeID;\n        };\n    };\n    union\n    {\n        union\n        {\n            SOCKADDR_IN RemoteTcpEntryIpV4;\n            SOCKADDR_IN6 RemoteTcpEntryIpV6;\n        };\n        struct\n        {\n            ADDRESS_FAMILY RemoteFamily;\n            USHORT RemotePort;\n            IN_ADDR RemoteAddressIPv4;\n            IN6_ADDR RemoteAddressIPv6;\n            ULONG RemoteScopeID;\n        };\n    };\n} NSI_SET_TCP_ENTRY, *PNSI_SET_TCP_ENTRY;\n\n#if defined(PH_INLINE_NSI)\nNTSYSAPI\nNTSTATUS\nNTAPI\nNsiGetParameter(\n    _In_ NSI_STORE Store,\n    _In_ PNPI_MODULEID Module,\n    _In_ ULONG Class,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _In_ ULONG InputControlCode,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _In_ ULONG OutputControlCode\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nNsiSetAllParameters(\n    _In_ NSI_STORE Store,\n    _In_ NSI_SET_ACTION Action,\n    _In_ PNPI_MODULEID Module,\n    _In_ ULONG Class,\n    _In_ PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _In_ PVOID OptionalBuffer,\n    _In_ ULONG OptionalBufferLength\n    );\n#else\n\n#define NSI_DEVICE_NAME L\"\\\\Device\\\\Nsi\"\n\n#define IOCTL_NSI_GET_PARAMETER \\\n    CTL_CODE(FILE_DEVICE_NETWORK, 0x1, METHOD_NEITHER, FILE_ANY_ACCESS)    // 0x120007\n\n#define IOCTL_NSI_SET_ALL_PARAMETERS \\\n    CTL_CODE(FILE_DEVICE_NETWORK, 0x4, METHOD_NEITHER, FILE_ANY_ACCESS)    // 0x120013\n\n#define IOCTL_NSI_GET_ALL_PARAMETERS \\\n    CTL_CODE(FILE_DEVICE_NETWORK, 0x6, METHOD_NEITHER, FILE_ANY_ACCESS)    // 0x12001B\n\ntypedef struct _NSI_IOCTL_GET_PARAMETER\n{\n    ULONGLONG Zero0;\n    ULONGLONG Zero1;\n    PNPI_MODULEID Module;\n    ULONG Class;\n    ULONG Reserved0;\n    NSI_STORE Store;\n    NSI_SET_ACTION Action;\n    PVOID InputBuffer;\n    ULONG InputBufferLength;\n    ULONG Reserved1;\n    ULONG InputControlCode;\n    ULONG Reserved2;\n    PVOID OutputBuffer;\n    ULONG OutputBufferLength;\n    ULONG Reserved3;\n} NSI_IOCTL_GET_PARAMETER, *PNSI_IOCTL_GET_PARAMETER;\n\ntypedef struct _NSI_IOCTL_SET_ALL_PARAMETERS\n{\n    ULONGLONG Zero0;\n    ULONGLONG Zero1;\n    PNPI_MODULEID Module;\n    ULONG Class;\n    ULONG Reserved0;\n    NSI_STORE Store;\n    NSI_SET_ACTION Action;\n    PVOID InputBuffer;\n    ULONG InputBufferLength;\n    ULONG Reserved1;\n    PVOID OutputBuffer;\n    ULONG OutputBufferLength;\n    ULONG Reserved2;\n} NSI_IOCTL_SET_ALL_PARAMETERS, *PNSI_IOCTL_SET_ALL_PARAMETERS;\n#endif\n\nNTSTATUS PhNsiGetParameter(\n    _In_ NSI_STORE Store,\n    _In_ PNPI_MODULEID Module,\n    _In_ ULONG Class,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _In_ ULONG InputControlCode,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    )\n{\n#if defined(PH_INLINE_NSI)\n    static typeof(&NsiGetParameter) NsiGetParameter_I = NULL;\n\n    if (!NsiGetParameter_I)\n    {\n        PVOID baseAddress;\n        if (baseAddress = PhLoadLibrary(L\"nsi.dll\"))\n        {\n            NsiGetParameter_I = PhGetDllBaseProcedureAddress(baseAddress, \"NsiGetParameter\", 0);\n        }\n    }\n\n    if (!NsiGetParameter_I)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    return NsiGetParameter_I(\n        Store,\n        Module,\n        Class,\n        InputBuffer,\n        InputBufferLength,\n        InputControlCode,\n        OutputBuffer,\n        OutputBufferLength,\n        0\n        );\n#else\n    NTSTATUS status;\n    HANDLE deviceHandle;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n    NSI_IOCTL_GET_PARAMETER nsiGetParameter;\n\n    RtlInitUnicodeString(&objectName, NSI_DEVICE_NAME);\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &deviceHandle,\n        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        &objectAttributes,\n        &ioStatusBlock,\n        NULL,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    RtlZeroMemory(&nsiGetParameter, sizeof(nsiGetParameter));\n    nsiGetParameter.Module = Module;\n    nsiGetParameter.Class = Class;\n    nsiGetParameter.Store = Store;\n    nsiGetParameter.InputBuffer = InputBuffer;\n    nsiGetParameter.InputBufferLength = InputBufferLength;\n    nsiGetParameter.InputControlCode = InputControlCode;\n    nsiGetParameter.OutputBuffer = OutputBuffer;\n    nsiGetParameter.OutputBufferLength = OutputBufferLength;\n\n    status = NtDeviceIoControlFile(\n        deviceHandle,\n        NULL,\n        NULL,\n        NULL,\n        &ioStatusBlock,\n        IOCTL_NSI_GET_PARAMETER,\n        &nsiGetParameter,\n        sizeof(nsiGetParameter),\n        &nsiGetParameter,\n        sizeof(nsiGetParameter)\n        );\n\n    NtClose(deviceHandle);\n\n    return status;\n#endif\n}\n\nNTSTATUS PhNsiSetAllParameters(\n    _In_ NSI_STORE Store,\n    _In_ NSI_SET_ACTION Action,\n    _In_ PNPI_MODULEID Module,\n    _In_ ULONG Class,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    )\n{\n#if defined(PH_INLINE_NSI)\n    static typeof(&NsiSetAllParameters) NsiSetAllParameters_I = NULL;\n\n    if (!NsiSetAllParameters_I)\n    {\n        PVOID baseAddress;\n        if (baseAddress = PhLoadLibrary(L\"nsi.dll\"))\n        {\n            NsiSetAllParameters_I = PhGetDllBaseProcedureAddress(baseAddress, \"NsiSetAllParameters\", 0);\n        }\n    }\n\n    if (!NsiSetAllParameters_I)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    return NsiSetAllParameters_I(\n        Store,\n        Action,\n        Module,\n        Class,\n        InputBuffer,\n        InputBufferLength,\n        OutputBuffer,\n        OutputBufferLength\n        );\n#else\n    NTSTATUS status;\n    HANDLE deviceHandle;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n    NSI_IOCTL_SET_ALL_PARAMETERS nsiSetAllParameters;\n\n    RtlInitUnicodeString(&objectName, NSI_DEVICE_NAME);\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &deviceHandle,\n        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        &objectAttributes,\n        &ioStatusBlock,\n        NULL,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    RtlZeroMemory(&nsiSetAllParameters, sizeof(nsiSetAllParameters));\n    nsiSetAllParameters.Module = Module;\n    nsiSetAllParameters.Class = Class;\n    nsiSetAllParameters.Store = Store;\n    nsiSetAllParameters.Action = Action;\n    nsiSetAllParameters.InputBuffer = InputBuffer;\n    nsiSetAllParameters.InputBufferLength = InputBufferLength;\n    nsiSetAllParameters.OutputBuffer = OutputBuffer;\n    nsiSetAllParameters.OutputBufferLength = OutputBufferLength;\n\n    status = NtDeviceIoControlFile(\n        deviceHandle,\n        NULL,\n        NULL,\n        NULL,\n        &ioStatusBlock,\n        IOCTL_NSI_SET_ALL_PARAMETERS,\n        &nsiSetAllParameters,\n        sizeof(nsiSetAllParameters),\n        &nsiSetAllParameters,\n        sizeof(nsiSetAllParameters)\n        );\n\n    NtClose(deviceHandle);\n\n    return status;\n#endif\n}\n\nNTSTATUS PhSetTcpEntry(\n    _In_ PPH_NETWORK_ITEM NetworkItem\n    )\n{\n    NTSTATUS status;\n    NSI_SET_TCP_ENTRY NsiSetTcpEntryData;\n\n    RtlZeroMemory(&NsiSetTcpEntryData, sizeof(NsiSetTcpEntryData));\n\n    if (NetworkItem->ProtocolType == PH_NETWORK_PROTOCOL_TCP4)\n    {\n        NsiSetTcpEntryData.LocalFamily = AF_INET;\n        NsiSetTcpEntryData.LocalPort = _byteswap_ushort((USHORT)NetworkItem->LocalEndpoint.Port);\n        memcpy(&NsiSetTcpEntryData.LocalAddressIPv4, &NetworkItem->LocalEndpoint.Address.InAddr, sizeof(NsiSetTcpEntryData.LocalAddressIPv4));\n\n        NsiSetTcpEntryData.RemoteFamily = AF_INET;\n        NsiSetTcpEntryData.RemotePort = _byteswap_ushort((USHORT)NetworkItem->RemoteEndpoint.Port);\n        memcpy(&NsiSetTcpEntryData.RemoteAddressIPv4, &NetworkItem->RemoteEndpoint.Address.InAddr, sizeof(NsiSetTcpEntryData.LocalAddressIPv4));\n    }\n    else if (NetworkItem->ProtocolType == PH_NETWORK_PROTOCOL_TCP6)\n    {\n        NsiSetTcpEntryData.LocalFamily = AF_INET6;\n        NsiSetTcpEntryData.LocalPort = _byteswap_ushort((USHORT)NetworkItem->LocalEndpoint.Port);\n        memcpy(&NsiSetTcpEntryData.LocalAddressIPv6, &NetworkItem->LocalEndpoint.Address.In6Addr, sizeof(NsiSetTcpEntryData.LocalAddressIPv6));\n        NsiSetTcpEntryData.LocalScopeID = NetworkItem->LocalScopeId;\n\n        NsiSetTcpEntryData.RemoteFamily = AF_INET6;\n        NsiSetTcpEntryData.RemotePort = _byteswap_ushort((USHORT)NetworkItem->RemoteEndpoint.Port);\n        memcpy(&NsiSetTcpEntryData.RemoteAddressIPv6, &NetworkItem->RemoteEndpoint.Address.In6Addr, sizeof(NsiSetTcpEntryData.RemoteAddressIPv6));\n        NsiSetTcpEntryData.RemoteScopeID = NetworkItem->RemoteScopeId;\n    }\n\n    status = PhNsiSetAllParameters(\n        NsiActive,\n        NsiSetCreateOrSet,\n        &NPI_MS_TCP_MODULEID,\n        NsiTcpSetIfEntry,\n        &NsiSetTcpEntryData,\n        sizeof(NSI_SET_TCP_ENTRY),\n        NULL,\n        0\n        );\n\n    return status;\n}\n\nNTSTATUS PhConvertInterfaceIndexToLuid(\n    _In_ NET_IFINDEX InterfaceIndex,\n    _Out_ PNET_LUID InterfaceLuid\n    )\n{\n    NET_IFINDEX index = InterfaceIndex;\n\n    return PhNsiGetParameter(\n        NsiActive,\n        &NPI_MS_NDIS_MODULEID,\n        NsiInterfaceIndexToLuid,\n        &index,\n        sizeof(NET_IFINDEX),\n        2,\n        InterfaceLuid,\n        sizeof(NET_LUID)\n        );\n}\n"
  },
  {
    "path": "SystemInformer/notifico.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2024\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n\n#include <shellapi.h>\n\n#include <mainwnd.h>\n#include <phplug.h>\n#include <procprv.h>\n#include <settings.h>\n#include <appresolver.h>\n\n#include <mainwndp.h>\n#include <notifico.h>\n#include <notificop.h>\n#include <notiftoast.h>\n\nBOOLEAN PhNfMiniInfoEnabled = FALSE;\nBOOLEAN PhNfMiniInfoPinned = FALSE;\nBOOLEAN PhNfTransparencyEnabled = FALSE;\nBOOLEAN PhNfPersistTrayIconPositionEnabled = FALSE;\nPPH_LIST PhTrayIconItemList = NULL;\n\nPH_NF_POINTERS PhNfpPointers;\nPH_CALLBACK_REGISTRATION PhNfpProcessesUpdatedRegistration;\nPH_NF_BITMAP PhNfpDefaultBitmapContext = { 0 };\nPH_NF_BITMAP PhNfpBlackBitmapContext = { 0 };\nHBITMAP PhNfpBlackBitmap = NULL;\nHICON PhNfpBlackIcon = NULL;\nHICON PhNfAppTrayIcon = NULL;\nHFONT PhNfTrayIconFont = NULL;\nGUID PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_MAXIMUM];\n\nstatic POINT IconClickLocation;\nstatic PH_NF_MSG_SHOWMINIINFOSECTION_DATA IconClickShowMiniInfoSectionData;\nstatic BOOLEAN IconClickUpDueToDown = FALSE;\nstatic BOOLEAN IconDisableHover = FALSE;\nstatic HANDLE PhpTrayIconThreadHandle = NULL;\nstatic HANDLE PhpTrayIconEventHandle = NULL;\n#ifdef PH_NF_ENABLE_WORKQUEUE\nstatic SLIST_HEADER PhpTrayIconWorkQueueListHead;\n#endif\nstatic ULONG PopupIconIndex = ULONG_MAX; // Win11 workaround (dmex)\nstatic PPH_NF_ICON PopupRegisteredIcon = NULL; // Win11 workaround (dmex)\n\nVOID PhNfLoadStage1(\n    VOID\n    )\n{\n    PhTrayIconItemList = PhCreateList(20);\n\n    PhNfpPointers.BeginBitmap = PhNfpBeginBitmap;\n#ifdef PH_NF_ENABLE_WORKQUEUE\n    PhInitializeSListHead(&PhpTrayIconWorkQueueListHead);\n#endif\n}\n\nVOID PhNfLoadSettings(\n    VOID\n    )\n{\n    PPH_STRING settingsString;\n    PH_STRINGREF remaining;\n\n    settingsString = PhGetStringSetting(SETTING_ICON_SETTINGS);\n\n    if (PhIsNullOrEmptyString(settingsString))\n        return;\n\n    remaining = PhGetStringRef(settingsString);\n\n    while (remaining.Length != 0)\n    {\n        PH_STRINGREF idPart;\n        PH_STRINGREF flagsPart;\n        PH_STRINGREF pluginNamePart;\n        ULONG64 idInteger;\n        ULONG64 flagsInteger;\n\n        PhSplitStringRefAtChar(&remaining, L'|', &idPart, &remaining);\n        PhSplitStringRefAtChar(&remaining, L'|', &flagsPart, &remaining);\n        PhSplitStringRefAtChar(&remaining, L'|', &pluginNamePart, &remaining);\n\n        if (!PhStringToUInt64(&idPart, 10, &idInteger))\n            break;\n        if (!PhStringToUInt64(&flagsPart, 10, &flagsInteger))\n            break;\n\n        if (flagsInteger)\n        {\n            PPH_NF_ICON icon;\n\n            if (pluginNamePart.Length)\n            {\n                if (icon = PhNfFindIcon(&pluginNamePart, (ULONG)idInteger))\n                {\n                    RtlInterlockedSetBits(&icon->Flags, PH_NF_ICON_ENABLED);\n                }\n            }\n            else\n            {\n                if (icon = PhNfGetIconById((ULONG)idInteger))\n                {\n                    RtlInterlockedSetBits(&icon->Flags, PH_NF_ICON_ENABLED);\n                }\n            }\n        }\n    }\n\n    PhDereferenceObject(settingsString);\n}\n\nVOID PhNfSaveSettings(\n    VOID\n    )\n{\n    PPH_STRING settingsString;\n    PH_STRING_BUILDER iconListBuilder;\n\n    PhInitializeStringBuilder(&iconListBuilder, 200);\n\n    for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    {\n        PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n        if (BooleanFlagOn(icon->Flags, PH_NF_ICON_ENABLED))\n        {\n            PH_FORMAT format[6];\n            SIZE_T returnLength;\n            WCHAR buffer[PH_INT64_STR_LEN_1];\n\n            // %lu|%lu|%s|\n            PhInitFormatU(&format[0], icon->SubId);\n            PhInitFormatC(&format[1], L'|');\n            PhInitFormatU(&format[2], TRUE);\n            PhInitFormatC(&format[3], L'|');\n            if (icon->Plugin)\n                PhInitFormatSR(&format[4], icon->Plugin->Name);\n            else\n                PhInitFormatS(&format[4], L\"\");\n            PhInitFormatC(&format[5], L'|');\n\n            if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n            {\n                PhAppendStringBuilderEx(&iconListBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n            }\n            else\n            {\n                PhAppendFormatStringBuilder(\n                    &iconListBuilder,\n                    L\"%lu|%lu|%s|\",\n                    icon->SubId,\n                    TRUE,\n                    icon->Plugin ? PhGetStringRefZ(&icon->Plugin->Name) : L\"\"\n                    );\n            }\n        }\n    }\n\n    if (iconListBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&iconListBuilder, 1);\n\n    settingsString = PhFinalStringBuilderString(&iconListBuilder);\n    PhSetStringSetting2(SETTING_ICON_SETTINGS, &settingsString->sr);\n    PhDereferenceObject(settingsString);\n}\n\nVOID PhNfLoadGuids(\n    VOID\n    )\n{\n    PPH_STRING settingsString;\n    PH_STRINGREF remaining;\n    ULONG i;\n\n    settingsString = PhGetStringSetting(SETTING_ICON_TRAY_GUIDS);\n\n    if (PhIsNullOrEmptyString(settingsString))\n    {\n        PH_STRING_BUILDER iconListBuilder;\n        PPH_STRING iconGuid;\n\n        PhInitializeStringBuilder(&iconListBuilder, 100);\n\n        for (i = 0; i < RTL_NUMBER_OF(PhNfpTrayIconItemGuids); i++)\n        {\n            PhGenerateGuid(&PhNfpTrayIconItemGuids[i]);\n\n            if (iconGuid = PhFormatGuid(&PhNfpTrayIconItemGuids[i]))\n            {\n                PhAppendFormatStringBuilder(\n                    &iconListBuilder,\n                    L\"%s|\",\n                    iconGuid->Buffer\n                    );\n                PhDereferenceObject(iconGuid);\n            }\n        }\n\n        if (iconListBuilder.String->Length != 0)\n            PhRemoveEndStringBuilder(&iconListBuilder, 1);\n\n        PhMoveReference(&settingsString, PhFinalStringBuilderString(&iconListBuilder));\n        PhSetStringSetting2(SETTING_ICON_TRAY_GUIDS, &settingsString->sr);\n        PhDereferenceObject(settingsString);\n    }\n    else\n    {\n        remaining = PhGetStringRef(settingsString);\n\n        for (i = 0; i < RTL_NUMBER_OF(PhNfpTrayIconItemGuids); i++)\n        {\n            PH_STRINGREF guidPart;\n            GUID guid;\n\n            if (remaining.Length == 0)\n                continue;\n\n            PhSplitStringRefAtChar(&remaining, L'|', &guidPart, &remaining);\n\n            if (guidPart.Length == 0)\n                continue;\n\n            if (!NT_SUCCESS(PhStringToGuid(&guidPart, &guid)))\n                PhGenerateGuid(&PhNfpTrayIconItemGuids[i]);\n            else\n                PhNfpTrayIconItemGuids[i] = guid;\n        }\n\n        PhDereferenceObject(settingsString);\n    }\n}\n\nVOID PhNfCreateIconThreadDelayed(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_NF_ICON staticIcon = NULL;\n    ULONG iconCount = 0;\n\n    for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    {\n        PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n        if (!BooleanFlagOn(icon->Flags, PH_NF_ICON_ENABLED))\n            continue;\n\n        if (icon->SubId == PH_TRAY_ICON_ID_PLAIN_ICON)\n            staticIcon = icon;\n\n        iconCount++;\n    }\n\n    if (iconCount && PhBeginInitOnce(&initOnce))\n    {\n        if (NT_SUCCESS(PhCreateEvent(\n            &PhpTrayIconEventHandle,\n            EVENT_ALL_ACCESS,\n            SynchronizationEvent,\n            !PhGetIntegerSetting(SETTING_ICON_TRAY_LAZY_START_DELAY)\n            )))\n        {\n            // Set the event when the only icon is the static icon. (dmex)\n            if (iconCount == 1 && staticIcon)\n            {\n                NtSetEvent(PhpTrayIconEventHandle, NULL);\n            }\n\n            // Use a separate thread so we don't block the main GUI or\n            // the provider threads when explorer is not responding. (dmex)\n            if (NT_SUCCESS(PhCreateThreadEx(&PhpTrayIconThreadHandle, PhNfpTrayIconUpdateThread, NULL)))\n            {\n                NtClose(PhpTrayIconThreadHandle);\n                PhpTrayIconThreadHandle = NULL;\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n}\n\nPPH_NF_ICON PhNfRegisterIcon(\n    _In_opt_ PPH_PLUGIN Plugin,\n    _In_ ULONG Id,\n    _In_ GUID Guid,\n    _In_opt_ PVOID Context,\n    _In_ PCWSTR Text,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback,\n    _In_opt_ PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback\n    )\n{\n    PPH_NF_ICON icon;\n\n    icon = PhAllocateZero(sizeof(PH_NF_ICON));\n    icon->Plugin = Plugin;\n    icon->SubId = Id;\n    icon->Context = Context;\n    icon->Pointers = &PhNfpPointers;\n    icon->Text = Text;\n    icon->Flags = Flags;\n    icon->UpdateCallback = UpdateCallback;\n    icon->MessageCallback = MessageCallback;\n    icon->TextCache = PhReferenceEmptyString();\n    icon->IconId = PhTrayIconItemList->Count + 1; // HACK\n    icon->IconGuid = Guid;\n\n    PhAddItemList(PhTrayIconItemList, icon);\n\n    return icon;\n}\n\nPPH_NF_ICON PhNfPluginRegisterIcon(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ ULONG SubId,\n    _In_ GUID Guid,\n    _In_opt_ PVOID Context,\n    _In_ PCWSTR Text,\n    _In_ ULONG Flags,\n    _In_ PPH_NF_ICON_REGISTRATION_DATA RegistrationData\n    )\n{\n    return PhNfRegisterIcon(\n        Plugin,\n        SubId,\n        Guid,\n        Context,\n        Text,\n        Flags,\n        RegistrationData->UpdateCallback,\n        RegistrationData->MessageCallback\n        );\n}\n\nVOID PhNfLoadStage2(\n    VOID\n    )\n{\n    PhNfMiniInfoEnabled = !!PhGetIntegerSetting(SETTING_MINI_INFO_WINDOW_ENABLED);\n    PhNfTransparencyEnabled = !!PhGetIntegerSetting(SETTING_ICON_TRANSPARENCY_ENABLED);\n    PhNfPersistTrayIconPositionEnabled = !!PhGetIntegerSetting(SETTING_ICON_TRAY_PERSIST_GUID_ENABLED);\n\n    if (PhNfPersistTrayIconPositionEnabled)\n    {\n        PhNfLoadGuids();\n    }\n\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_USAGE, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_CPU_USAGE], NULL, L\"CPU &usage\", 0, PhNfpCpuUsageIconUpdateCallback, NULL);\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_HISTORY, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_CPU_HISTORY], NULL, L\"CPU &history\", 0, PhNfpCpuHistoryIconUpdateCallback, NULL);\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_HISTORY, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_IO_HISTORY], NULL, L\"&I/O history\", 0, PhNfpIoHistoryIconUpdateCallback, NULL);\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_HISTORY, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_COMMIT_HISTORY], NULL, L\"&Commit charge history\", 0, PhNfpCommitHistoryIconUpdateCallback, NULL);\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_HISTORY, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_PHYSICAL_HISTORY], NULL, L\"&Physical memory history\", 0, PhNfpPhysicalHistoryIconUpdateCallback, NULL);\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_TEXT, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_CPU_TEXT], NULL, L\"CPU usage (text)\", 0, PhNfpCpuUsageTextIconUpdateCallback, NULL);\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_TEXT, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_IO_TEXT], NULL, L\"IO usage (text)\", 0, PhNfpIoUsageTextIconUpdateCallback, NULL);\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_TEXT, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_COMMIT_TEXT], NULL, L\"Commit usage (text)\", 0, PhNfpCommitTextIconUpdateCallback, NULL);\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_TEXT, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_PHYSICAL_TEXT], NULL, L\"Physical usage (text)\", 0, PhNfpPhysicalUsageTextIconUpdateCallback, NULL);\n    PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PLAIN_ICON, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_PLAIN_ICON], NULL, L\"System Informer icon (static)\", 0, PhNfpPlainIconUpdateCallback, NULL);\n\n    if (PhPluginsEnabled)\n    {\n        PH_TRAY_ICON_POINTERS pointers;\n\n        pointers.RegisterTrayIcon = (PPH_REGISTER_TRAY_ICON)PhNfPluginRegisterIcon;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackTrayIconsInitializing), &pointers);\n    }\n\n    // Load tray icon settings.\n    PhNfLoadSettings();\n\n    //for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    //{\n    //    PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n    //\n    //    if (!BooleanFlagOn(icon->Flags, PH_NF_ICON_ENABLED))\n    //        continue;\n    //\n    //    PhNfpAddNotifyIcon(icon);\n    //}\n\n    PhNfCreateIconThreadDelayed();\n\n    PhRegisterCallback(\n        PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n        PhNfpProcessesUpdatedHandler,\n        NULL,\n        &PhNfpProcessesUpdatedRegistration\n        );\n}\n\nVOID PhNfUninitialization(\n    VOID\n    )\n{\n#ifdef PH_NF_ENABLE_WORKQUEUE\n    //LARGE_INTEGER timeout;\n\n    if (PhpTrayIconEventHandle)\n        NtSetEvent(PhpTrayIconEventHandle, NULL);\n#endif\n\n    // Remove all icons to prevent them hanging around after we exit.\n\n    for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    {\n        PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n        if (RtlInterlockedClearBits(&icon->Flags, PH_NF_ICON_ENABLED) == PH_NF_ICON_ENABLED)\n        {\n            PhNfpRemoveNotifyIcon(icon);\n        }\n    }\n\n//#ifdef PH_NF_ENABLE_WORKQUEUE\n//    if (PhpTrayIconThreadHandle)\n//    {\n//        NtWaitForSingleObject(PhpTrayIconThreadHandle, FALSE, PhTimeoutFromMilliseconds(&timeout, 1000));\n//    }\n//#endif\n}\n\nVOID PhNfForwardMessage(\n    _In_ HWND WindowHandle,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    )\n{\n    ULONG iconIndex = HIWORD(LParam);\n    PPH_NF_ICON registeredIcon = NULL;\n\n    if (iconIndex == 0)\n        return;\n\n    for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    {\n        PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n        if (icon->IconId == iconIndex)\n        {\n            registeredIcon = icon;\n            break;\n        }\n    }\n\n    if (!registeredIcon)\n        return;\n\n    if (registeredIcon->MessageCallback)\n    {\n        if (registeredIcon->MessageCallback(\n            registeredIcon,\n            WParam,\n            LParam,\n            registeredIcon->Context\n            ))\n        {\n            return;\n        }\n    }\n\n    switch (LOWORD(LParam))\n    {\n    case WM_LBUTTONDOWN:\n        {\n            if (PhGetIntegerSetting(SETTING_ICON_SINGLE_CLICK))\n            {\n                SystemInformer_IconClick();\n                PhNfpDisableHover();\n            }\n            else\n            {\n                IconClickUpDueToDown = TRUE;\n            }\n        }\n        break;\n    case WM_LBUTTONUP:\n        {\n            if (!PhGetIntegerSetting(SETTING_ICON_SINGLE_CLICK) && PhNfMiniInfoEnabled && IconClickUpDueToDown)\n            {\n                PH_NF_MSG_SHOWMINIINFOSECTION_DATA showMiniInfoSectionData;\n\n                if (PhNfpGetShowMiniInfoSectionData(iconIndex, registeredIcon, &showMiniInfoSectionData))\n                {\n                    GetCursorPos(&IconClickLocation);\n\n                    if (IconClickShowMiniInfoSectionData.SectionName)\n                    {\n                        PhFree(IconClickShowMiniInfoSectionData.SectionName);\n                        IconClickShowMiniInfoSectionData.SectionName = NULL;\n                    }\n\n                    if (showMiniInfoSectionData.SectionName)\n                    {\n                        IconClickShowMiniInfoSectionData.SectionName = PhDuplicateStringZ(showMiniInfoSectionData.SectionName);\n                    }\n\n                    PhSetTimer(WindowHandle, TIMER_ICON_CLICK_ACTIVATE, GetDoubleClickTime() + NFP_ICON_CLICK_ACTIVATE_DELAY, PhNfpIconClickActivateTimerProc);\n                }\n                else\n                {\n                    PhKillTimer(WindowHandle, TIMER_ICON_CLICK_ACTIVATE);\n                }\n            }\n        }\n        break;\n    case WM_LBUTTONDBLCLK:\n        {\n            if (!PhGetIntegerSetting(SETTING_ICON_SINGLE_CLICK))\n            {\n                if (PhNfMiniInfoEnabled)\n                {\n                    // We will get another WM_LBUTTONUP message corresponding to the double-click,\n                    // and we need to make sure that it doesn't start the activation timer again.\n                    PhKillTimer(WindowHandle, TIMER_ICON_CLICK_ACTIVATE);\n                    IconClickUpDueToDown = FALSE;\n                    PhNfpDisableHover();\n                }\n\n                SystemInformer_IconClick();\n            }\n        }\n        break;\n    case WM_RBUTTONUP:\n    case WM_CONTEXTMENU:\n        {\n            POINT location;\n\n            if (!PhGetIntegerSetting(SETTING_ICON_SINGLE_CLICK) && PhNfMiniInfoEnabled)\n                PhKillTimer(WindowHandle, TIMER_ICON_CLICK_ACTIVATE);\n\n            PhNfpIconDisablePopupHoverWin11Workaround();\n\n            PhPinMiniInformation(MiniInfoIconPinType, -1, 0, 0, NULL, NULL);\n            GetCursorPos(&location);\n            PhShowIconContextMenu(WindowHandle, &location);\n        }\n        break;\n    case NIN_KEYSELECT:\n        {\n            // HACK: explorer seems to send two NIN_KEYSELECT messages when the user selects the icon and presses ENTER.\n            if (GetForegroundWindow() != WindowHandle)\n                SystemInformer_IconClick();\n        }\n        break;\n    case NIN_BALLOONUSERCLICK:\n        {\n            if (!PhGetIntegerSetting(SETTING_ICON_IGNORE_BALLOON_CLICK))\n                PhShowDetailsForIconNotification();\n        }\n        break;\n    case NIN_POPUPOPEN:\n        {\n            if (WindowsVersion >= WINDOWS_11_22H2)\n            {\n                // NIN_POPUPOPEN is sent when the user hovers the cursor over an icon BUT Windows 11 either blocks the notification\n                // or ignores the hover time and displays the popup instantly. We try and workaround the missing hover time by using\n                // a timer to delay the popup for 1 second. If we get a NIN_POPUPCLOSE then cancel the timer and the popup.\n                // Note: We only workaround the missing hover time not the blocked/missing NIN_POPUPOPEN notifications. If we want to workaround\n                // the broken NIN_POPUPOPEN notifications on Win11 the tray icons also send WM_MOUSEMOSE and before NIN_POPUPOPEN existed\n                // XP applications would compare the cursor position in a timer callback to show or hide the popup. (dmex)\n\n                PopupIconIndex = iconIndex;\n                PopupRegisteredIcon = registeredIcon;\n\n                PhSetTimer(PhMainWndHandle, TIMER_ICON_POPUPOPEN, NFP_ICON_RESTORE_HOVER_DELAY, PhNfpIconShowPopupHoverTimerProc);\n            }\n            else\n            {\n                PH_NF_MSG_SHOWMINIINFOSECTION_DATA showMiniInfoSectionData;\n                POINT location;\n\n                if (PhNfMiniInfoEnabled && !IconDisableHover && PhNfpGetShowMiniInfoSectionData(iconIndex, registeredIcon, &showMiniInfoSectionData))\n                {\n                    GetCursorPos(&location);\n                    PhPinMiniInformation(MiniInfoIconPinType, 1, 0, PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED,\n                        showMiniInfoSectionData.SectionName, &location);\n                }\n            }\n        }\n        break;\n    case NIN_POPUPCLOSE:\n        {\n            PhNfpIconDisablePopupHoverWin11Workaround();\n\n            PhPinMiniInformation(MiniInfoIconPinType, -1, 350, 0, NULL, NULL);\n        }\n        break;\n    }\n}\n\nVOID PhNfSetVisibleIcon(\n    _In_ PPH_NF_ICON Icon,\n    _In_ BOOLEAN Visible\n    )\n{\n    if (Visible)\n    {\n        RtlInterlockedSetBits(&Icon->Flags, PH_NF_ICON_ENABLED);\n\n#ifndef PH_NF_ENABLE_WORKQUEUE\n        PhNfpAddNotifyIcon(Icon);\n#else\n        PPH_NF_WORKQUEUE_DATA data;\n\n        data = PhAllocateZero(sizeof(PH_NF_WORKQUEUE_DATA));\n        data->Add = TRUE;\n        data->Icon = Icon;\n\n        RtlInterlockedPushEntrySList(&PhpTrayIconWorkQueueListHead, &data->ListEntry);\n#endif\n    }\n    else\n    {\n        RtlInterlockedClearBits(&Icon->Flags, PH_NF_ICON_ENABLED);\n\n#ifndef PH_NF_ENABLE_WORKQUEUE\n        PhNfpRemoveNotifyIcon(Icon);\n#else\n        PPH_NF_WORKQUEUE_DATA data;\n\n        data = PhAllocateZero(sizeof(PH_NF_WORKQUEUE_DATA));\n        data->Delete = TRUE;\n        data->Icon = Icon;\n\n        RtlInterlockedPushEntrySList(&PhpTrayIconWorkQueueListHead, &data->ListEntry);\n#endif\n    }\n#ifdef PH_NF_ENABLE_WORKQUEUE\n    PhNfCreateIconThreadDelayed();\n\n    if (PhpTrayIconEventHandle)\n        NtSetEvent(PhpTrayIconEventHandle, NULL);\n#endif\n}\n\nVOID NTAPI PhpToastCallback(\n    _In_ HRESULT Result,\n    _In_ PH_TOAST_REASON Reason,\n    _In_ PVOID Context\n    )\n{\n    if (Reason == PhToastReasonActivated)\n        PhShowDetailsForIconNotification();\n}\n\nHRESULT PhpShowToastNotification(\n    _In_ PPH_STRING Title,\n    _In_ PPH_STRING Text,\n    _In_ ULONG Timeout,\n    _In_opt_ PPH_TOAST_CALLBACK ToastCallback,\n    _In_opt_ PVOID Context,\n    _In_opt_ BOOLEAN Force\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PPH_STRING iconFileName = NULL;\n    PH_STRINGREF iconAppId = PH_STRINGREF_INIT(L\"\");\n    PPH_STRING processAppId = NULL;\n    HRESULT result;\n    PPH_STRING toastXml;\n    PH_FORMAT format[7];\n\n    if (!Force && !PhGetIntegerSetting(SETTING_TOAST_NOTIFY_ENABLED))\n        return E_FAIL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        iconFileName = PhGetApplicationDirectoryFileNameZ(L\"Resources\\\\icon.png\", FALSE);\n\n        if (!PhDoesFileExistWin32(PhGetString(iconFileName)))\n            PhClearReference(&iconFileName);\n\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!iconFileName)\n        return E_FAIL;\n\n    if (HR_SUCCESS(PhAppResolverGetAppIdForProcess(NtCurrentProcessId(), &processAppId)))\n        iconAppId = processAppId->sr;\n    else\n    {\n        if (HR_SUCCESS(PhAppResolverGetAppIdForWindow(PhMainWndHandle, &processAppId)))\n            iconAppId = processAppId->sr;\n        else\n        {\n            PhInitializeStringRefLongHint(&iconAppId, PhApplicationName);\n        }\n    }\n\n    result = PhInitializeToastRuntime();\n    if (HR_FAILED(result))\n        return result;\n\n    //toastXml = PhFormatString(\n    //    L\"<toast>\\r\\n\"\n    //    L\"    <visual>\\r\\n\"\n    //    L\"       <binding template=\\\"ToastImageAndText02\\\">\\r\\n\"\n    //    L\"            <image id=\\\"1\\\" src=\\\"%s\\\" alt=\\\"red graphic\\\"/>\\r\\n\"\n    //    L\"            <text id=\\\"1\\\">%ls</text>\\r\\n\"\n    //    L\"            <text id=\\\"2\\\">%ls</text>\\r\\n\"\n    //    L\"        </binding>\\r\\n\"\n    //    L\"    </visual>\\r\\n\"\n    //    L\"</toast>\",\n    //    PhGetString(iconFileName),\n    //    Title,\n    //    Text\n    //    );\n\n    PhInitFormatS(&format[0], L\"<toast><visual><binding template=\\\"ToastImageAndText02\\\"><image id=\\\"1\\\" src=\\\"\");\n    PhInitFormatSR(&format[1], iconFileName->sr);\n    PhInitFormatS(&format[2], L\"\\\" alt=\\\"red graphic\\\"/><text id=\\\"1\\\">\");\n    PhInitFormatSR(&format[3], Title->sr);\n    PhInitFormatS(&format[4], L\"</text><text id=\\\"2\\\">\");\n    PhInitFormatSR(&format[5], Text->sr);\n    PhInitFormatS(&format[6], L\"</text></binding></visual></toast>\");\n    toastXml = PhFormat(format, RTL_NUMBER_OF(format), 0);\n\n    result = PhShowToastStringRef(\n        &iconAppId,\n        &toastXml->sr,\n        Timeout * 1000,\n        ToastCallback,\n        Context\n        );\n\n    PhClearReference(&toastXml);\n    PhClearReference(&processAppId);\n\n    return result;\n}\n\nBOOLEAN PhNfpShowBalloonTip(\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Text,\n    _In_ ULONG Timeout\n    )\n{\n    NOTIFYICONDATA notifyIcon;\n    PPH_NF_ICON registeredIcon = NULL;\n\n    for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    {\n        PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n        if (!BooleanFlagOn(icon->Flags, PH_NF_ICON_ENABLED))\n            continue;\n\n        registeredIcon = icon;\n        break;\n    }\n\n    if (!registeredIcon)\n        return FALSE;\n\n    memset(&notifyIcon, 0, sizeof(NOTIFYICONDATA));\n    notifyIcon.cbSize = sizeof(NOTIFYICONDATA);\n    notifyIcon.uFlags = NIF_INFO;\n    notifyIcon.hWnd = PhMainWndHandle;\n    notifyIcon.uID = registeredIcon->IconId;\n\n    if (PhNfPersistTrayIconPositionEnabled)\n    {\n        SetFlag(notifyIcon.uFlags, NIF_GUID);\n        notifyIcon.guidItem = registeredIcon->IconGuid;\n    }\n\n    wcsncpy_s(notifyIcon.szInfoTitle, RTL_NUMBER_OF(notifyIcon.szInfoTitle), Title, _TRUNCATE);\n    wcsncpy_s(notifyIcon.szInfo, RTL_NUMBER_OF(notifyIcon.szInfo), Text, _TRUNCATE);\n    notifyIcon.uTimeout = Timeout;\n\n    if (PhGetIntegerSetting(SETTING_ICON_BALLOON_SHOW_ICON) || WindowsVersion < WINDOWS_11)\n        SetFlag(notifyIcon.dwInfoFlags, NIIF_INFO);\n    if (PhGetIntegerSetting(SETTING_ICON_BALLOON_MUTE_SOUND))\n        SetFlag(notifyIcon.dwInfoFlags, NIIF_NOSOUND);\n\n    PhShellNotifyIcon(NIM_MODIFY, &notifyIcon);\n\n    return TRUE;\n}\n\nBOOLEAN PhNfShowBalloonTip(\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Text,\n    _In_ ULONG Timeout\n    )\n{\n    if (!PhNfIconsEnabled())\n    {\n        return FALSE;\n    }\n\n#ifndef PH_NF_ENABLE_WORKQUEUE\n    return PhNfpShowBalloonTip(Title, Text, Timeout);\n#else\n    PPH_NF_WORKQUEUE_DATA data;\n\n    data = PhAllocateZero(sizeof(PH_NF_WORKQUEUE_DATA));\n    data->ShowBalloon = TRUE;\n    data->BalloonTitle = Title ? PhCreateString(Title) : NULL;\n    data->BalloonText = Text ? PhCreateString(Text) : NULL;\n    data->BalloonTimeout = Timeout;\n\n    RtlInterlockedPushEntrySList(&PhpTrayIconWorkQueueListHead, &data->ListEntry);\n#endif\n    return TRUE;\n}\n\nHRESULT PhNfShowBalloonTipEx(\n    _In_ PCWSTR Title,\n    _In_ PCWSTR Text,\n    _In_ ULONG Timeout,\n    _In_opt_ PPH_TOAST_CALLBACK ToastCallback,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_STRING BalloonTitle;\n    PPH_STRING BalloonText;\n\n    BalloonTitle = Title ? PhCreateString(Title) : NULL;\n    BalloonText = Text ? PhCreateString(Text) : NULL;\n\n    return PhpShowToastNotification(\n        BalloonTitle,\n        BalloonText,\n        Timeout,\n        ToastCallback,\n        Context,\n        TRUE\n        );\n}\n\nHICON PhNfBitmapToIcon(\n    _In_ HBITMAP Bitmap\n    )\n{\n    HICON iconHandle;\n    HBITMAP mask;\n    ICONINFO iconInfo;\n\n    // Create a monochrome mask bitmap for the icon.\n    {\n        BITMAP bitmapInfo;\n\n        memset(&bitmapInfo, 0, sizeof(BITMAP));\n\n        if (GetObject(Bitmap, sizeof(BITMAP), &bitmapInfo) == 0)\n            return NULL;\n\n        if (!(mask = CreateBitmap(bitmapInfo.bmWidth, bitmapInfo.bmHeight, 1, 1, NULL)))\n            return NULL;\n    }\n\n    memset(&iconInfo, 0, sizeof(ICONINFO));\n    iconInfo.fIcon = TRUE;\n    iconInfo.xHotspot = 0;\n    iconInfo.yHotspot = 0;\n    iconInfo.hbmMask = mask;\n    iconInfo.hbmColor = Bitmap;\n\n    iconHandle = CreateIconIndirect(&iconInfo);\n    DeleteBitmap(mask);\n\n    return iconHandle;\n}\n\nPPH_NF_ICON PhNfGetIconById(\n    _In_ ULONG SubId\n    )\n{\n    for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    {\n        PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n        if (icon->SubId == SubId)\n            return icon;\n    }\n\n    return NULL;\n}\n\nPPH_NF_ICON PhNfFindIcon(\n    _In_ PPH_STRINGREF PluginName,\n    _In_ ULONG SubId\n    )\n{\n    for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    {\n        PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n        if (icon->Plugin)\n        {\n            if (icon->SubId == SubId &&\n                PhEqualStringRef(PluginName, &icon->Plugin->Name, TRUE))\n            {\n                return icon;\n            }\n        }\n    }\n\n    return NULL;\n}\n\nBOOLEAN PhNfIconsEnabled(\n    VOID\n    )\n{\n    // Note: We can't check the list because delayed initialization (dmex)\n    //BOOLEAN enabled = FALSE;\n    //\n    //for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    //{\n    //    PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n    //\n    //    if (BooleanFlagOn(icon->Flags, PH_NF_ICON_ENABLED))\n    //    {\n    //        enabled = TRUE;\n    //        break;\n    //    }\n    //}\n    //\n    //return enabled;\n\n    PPH_STRING settingsString;\n\n    settingsString = PhGetStringSetting(SETTING_ICON_SETTINGS);\n\n    if (PhIsNullOrEmptyString(settingsString))\n    {\n        PhClearReference(&settingsString);\n        return FALSE;\n    }\n\n    PhClearReference(&settingsString);\n    return TRUE;\n}\n\nVOID PhNfNotifyMiniInfoPinned(\n    _In_ BOOLEAN Pinned\n    )\n{\n    if (PhNfMiniInfoPinned != Pinned)\n    {\n        PhNfMiniInfoPinned = Pinned;\n\n        // Go through every icon and set/clear the NIF_SHOWTIP flag depending on whether the mini info window is\n        // pinned. If it's pinned then we want to show normal tooltips, because the section doesn't change\n        // automatically when the cursor hovers over an icon.\n\n        for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n        {\n            PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n            if (!BooleanFlagOn(icon->Flags, PH_NF_ICON_ENABLED))\n                continue;\n\n            PhNfpModifyNotifyIcon(icon, NIF_TIP, icon->TextCache, NULL);\n        }\n    }\n}\n\nHICON PhNfGetApplicationIcon(\n    _In_opt_ LONG DpiValue\n    )\n{\n    if (DpiValue != 0 && PhNfAppTrayIcon)\n    {\n        DestroyIcon(PhNfAppTrayIcon);\n        PhNfAppTrayIcon = NULL;\n    }\n\n    if (!PhNfAppTrayIcon)\n    {\n        if (DpiValue == 0)\n        {\n            DpiValue = PhGetTaskbarDpi();\n        }\n\n        PhNfAppTrayIcon = PhGetApplicationIconEx(FALSE, DpiValue);\n    }\n\n    return PhNfAppTrayIcon;\n}\n\nHICON PhNfpGetBlackIcon(\n    VOID\n    )\n{\n    if (!PhNfpBlackIcon)\n    {\n        ULONG width;\n        ULONG height;\n        PVOID bits;\n        HDC hdc;\n        HBITMAP mask;\n        HBITMAP oldBitmap;\n        ICONINFO iconInfo;\n\n        PhNfpBeginBitmap2(&PhNfpBlackBitmapContext, &width, &height, &PhNfpBlackBitmap, &bits, &hdc, &oldBitmap);\n        memset(bits, PhNfTransparencyEnabled ? 1 : 0, width * height * sizeof(RGBQUAD));\n\n        // Create a monochrome mask bitmap for the icon.\n        if (!(mask = CreateBitmap(width, height, 1, 1, NULL)))\n            return NULL;\n        \n        iconInfo.fIcon = TRUE;\n        iconInfo.xHotspot = 0;\n        iconInfo.yHotspot = 0;\n        iconInfo.hbmMask = mask;\n        iconInfo.hbmColor = PhNfpBlackBitmap;\n        PhNfpBlackIcon = CreateIconIndirect(&iconInfo);\n\n        SelectBitmap(hdc, oldBitmap);\n        DeleteBitmap(mask);\n    }\n\n    return PhNfpBlackIcon;\n}\n\n#define COLORREF_TO_BITS(Color) (_byteswap_ulong(Color) >> 8)\n\nVOID PhDrawTrayIconText(\n    _In_ HDC hdc,\n    _In_ PVOID Bits,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text\n    )\n{\n    PULONG bits = Bits;\n    LONG width = DrawInfo->Width;\n    LONG height = DrawInfo->Height;\n    LONG numberOfPixels = width * height;\n    ULONG flags = DrawInfo->Flags;\n    HFONT oldFont = NULL;\n    SIZE textSize;\n    PH_RECTANGLE boxRectangle;\n    PH_RECTANGLE textRectangle;\n\n    if (DrawInfo->BackColor == 0)\n    {\n        memset(bits, 0, numberOfPixels * sizeof(RGBQUAD));\n    }\n    else\n    {\n        PhFillMemoryUlong(bits, COLORREF_TO_BITS(DrawInfo->BackColor), numberOfPixels);\n    }\n\n    if (DrawInfo->TextFont)\n        oldFont = SelectFont(hdc, DrawInfo->TextFont);\n\n    DrawInfo->Text = *Text;\n    GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / sizeof(WCHAR), &textSize);\n\n    // Calculate the box rectangle.\n\n    boxRectangle.Width = textSize.cx;\n    boxRectangle.Height = textSize.cy;\n    boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / (LONG)sizeof(WCHAR);\n    boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / (LONG)sizeof(WCHAR);\n\n    // Calculate the text rectangle.\n\n    textRectangle.Left = boxRectangle.Left;\n    textRectangle.Top = boxRectangle.Top;\n    textRectangle.Width = textSize.cx;\n    textRectangle.Height = textSize.cy;\n\n    // Save the rectangles.\n    PhRectangleToRect(&DrawInfo->TextRect, &textRectangle);\n    PhRectangleToRect(&DrawInfo->TextBoxRect, &boxRectangle);\n\n    SetBkMode(hdc, TRANSPARENT);\n\n    // Fill in the text box.\n    //SetDCBrushColor(hdc, DrawInfo->TextBoxColor);\n    //FillRect(hdc, &DrawInfo->TextBoxRect, GetStockBrush(DC_BRUSH));\n\n    // Draw the text.\n    SetTextColor(hdc, DrawInfo->TextColor);\n\n    DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / sizeof(WCHAR), &DrawInfo->TextRect, DT_NOCLIP | DT_SINGLELINE);\n\n    if (oldFont)\n        SelectFont(hdc, oldFont);\n}\n\nHFONT PhNfGetTrayIconFont(\n    _In_opt_ LONG DpiValue\n    )\n{\n    if (DpiValue != 0 && PhNfTrayIconFont)\n    {\n        DeleteFont(PhNfTrayIconFont);\n        PhNfTrayIconFont = NULL;\n    }\n\n    if (!PhNfTrayIconFont)\n    {\n        if (DpiValue == 0)\n        {\n            DpiValue = PhGetTaskbarDpi();\n        }\n\n        PhNfTrayIconFont = CreateFont(\n            PhGetDpi(-11, DpiValue),\n            0,\n            0,\n            0,\n            FW_NORMAL,\n            FALSE,\n            FALSE,\n            FALSE,\n            ANSI_CHARSET,\n            OUT_DEFAULT_PRECIS,\n            CLIP_DEFAULT_PRECIS,\n            ANTIALIASED_QUALITY,\n            DEFAULT_PITCH,\n            L\"Tahoma\"\n            );\n    }\n\n    return PhNfTrayIconFont;\n}\n\nBOOLEAN PhNfpAddNotifyIcon(\n    _In_ PPH_NF_ICON Icon\n    )\n{\n    NOTIFYICONDATA notifyIcon;\n\n    if (PhMainWndExiting)\n        return FALSE;\n\n    memset(&notifyIcon, 0, sizeof(NOTIFYICONDATA));\n    notifyIcon.cbSize = sizeof(NOTIFYICONDATA);\n    notifyIcon.hWnd = PhMainWndHandle;\n    notifyIcon.uID = Icon->IconId;\n    notifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;\n    notifyIcon.uCallbackMessage = WM_PH_NOTIFY_ICON_MESSAGE;\n\n    if (PhNfPersistTrayIconPositionEnabled)\n    {\n        SetFlag(notifyIcon.uFlags, NIF_GUID);\n        notifyIcon.guidItem = Icon->IconGuid;\n    }\n\n    wcsncpy_s(\n        notifyIcon.szTip, RTL_NUMBER_OF(notifyIcon.szTip),\n        PhGetStringOrDefault(Icon->TextCache, PhApplicationName),\n        _TRUNCATE\n        );\n    //notifyIcon.hIcon = PhNfpGetBlackIcon();\n    notifyIcon.hIcon = PhGetApplicationIcon(TRUE); // Fixes GH#1845 (dmex)\n\n    if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || FlagOn(Icon->Flags, PH_NF_ICON_NOSHOW_MINIINFO))\n        SetFlag(notifyIcon.uFlags, NIF_SHOWTIP);\n\n    PhShellNotifyIcon(NIM_ADD, &notifyIcon);\n    notifyIcon.uVersion = NOTIFYICON_VERSION_4;\n    PhShellNotifyIcon(NIM_SETVERSION, &notifyIcon);\n\n    return TRUE;\n}\n\nBOOLEAN PhNfpRemoveNotifyIcon(\n    _In_ PPH_NF_ICON Icon\n    )\n{\n    NOTIFYICONDATA notifyIcon;\n\n    memset(&notifyIcon, 0, sizeof(NOTIFYICONDATA));\n    notifyIcon.cbSize = sizeof(NOTIFYICONDATA);\n    notifyIcon.hWnd = PhMainWndHandle;\n    notifyIcon.uID = Icon->IconId;\n\n    if (PhNfPersistTrayIconPositionEnabled)\n    {\n        SetFlag(notifyIcon.uFlags, NIF_GUID);\n        notifyIcon.guidItem = Icon->IconGuid;\n    }\n\n    PhShellNotifyIcon(NIM_DELETE, &notifyIcon);\n\n    return TRUE;\n}\n\nBOOLEAN PhNfpModifyNotifyIcon(\n    _In_ PPH_NF_ICON Icon,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_STRING Text,\n    _In_opt_ HICON IconHandle\n    )\n{\n    NOTIFYICONDATA notifyIcon;\n\n    if (PhMainWndExiting)\n        return FALSE;\n    if (BooleanFlagOn(Icon->Flags, PH_NF_ICON_UNAVAILABLE))\n        return FALSE;\n\n    memset(&notifyIcon, 0, sizeof(NOTIFYICONDATA));\n    notifyIcon.cbSize = sizeof(NOTIFYICONDATA);\n    notifyIcon.uFlags = Flags;\n    notifyIcon.hWnd = PhMainWndHandle;\n    notifyIcon.uID = Icon->IconId;\n    notifyIcon.hIcon = IconHandle;\n\n    if (PhNfPersistTrayIconPositionEnabled)\n    {\n        SetFlag(notifyIcon.uFlags, NIF_GUID);\n        notifyIcon.guidItem = Icon->IconGuid;\n    }\n\n    if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || FlagOn(Icon->Flags, PH_NF_ICON_NOSHOW_MINIINFO))\n        SetFlag(notifyIcon.uFlags, NIF_SHOWTIP);\n\n    if (FlagOn(Flags, NIF_TIP))\n    {\n        PhSwapReference(&Icon->TextCache, Text);\n        wcsncpy_s(notifyIcon.szTip, RTL_NUMBER_OF(notifyIcon.szTip), PhGetStringOrDefault(Text, PhApplicationName), _TRUNCATE);\n    }\n\n    if (!PhShellNotifyIcon(NIM_MODIFY, &notifyIcon))\n    {\n        // Explorer probably died and we lost our icon. Try to add the icon, and try again.\n        PhNfpAddNotifyIcon(Icon);\n        PhShellNotifyIcon(NIM_MODIFY, &notifyIcon);\n    }\n\n    return TRUE;\n}\n\n//BOOLEAN PhNfpGetNotifyIconRect(\n//    _In_ ULONG Id,\n//    _In_opt_ PPH_RECTANGLE IconRectangle\n//    )\n//{\n//    NOTIFYICONIDENTIFIER notifyIconId = { sizeof(NOTIFYICONIDENTIFIER) };\n//    PPH_NF_ICON icon;\n//    RECT notifyRect;\n//\n//    if (PhMainWndExiting)\n//        return FALSE;\n//    if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE))\n//        return FALSE;\n//\n//    notifyIconId.hWnd = PhMainWndHandle;\n//    notifyIconId.uID = Id;\n//\n//    if (SUCCEEDED(Shell_NotifyIconGetRect(&notifyIconId, &notifyRect)))\n//    {\n//        *IconRectangle = PhRectToRectangle(notifyRect);\n//        return TRUE;\n//    }\n//\n//    return FALSE;\n//}\n\n#ifdef PH_NF_ENABLE_WORKQUEUE\nVOID PhNfTrayIconFlushWorkQueueData(\n    VOID\n    )\n{\n    PSLIST_ENTRY entry;\n    PPH_NF_WORKQUEUE_DATA data;\n\n    entry = RtlInterlockedFlushSList(&PhpTrayIconWorkQueueListHead);\n\n    while (entry)\n    {\n        data = CONTAINING_RECORD(entry, PH_NF_WORKQUEUE_DATA, ListEntry);\n        entry = entry->Next;\n\n        if (PhMainWndExiting)\n            break;\n\n        if (data->Add)\n        {\n            PhNfpAddNotifyIcon(data->Icon);\n        }\n\n        if (data->Delete)\n        {\n            PhNfpRemoveNotifyIcon(data->Icon);\n        }\n\n        if (data->ShowBalloon)\n        {\n            if (!HR_SUCCESS(PhpShowToastNotification(\n                data->BalloonTitle,\n                data->BalloonText,\n                data->BalloonTimeout,\n                PhpToastCallback,\n                NULL,\n                FALSE\n                )))\n            {\n                PhNfpShowBalloonTip(\n                    PhGetString(data->BalloonTitle),\n                    PhGetString(data->BalloonText),\n                    data->BalloonTimeout\n                    );\n            }\n\n            PhClearReference(&data->BalloonTitle);\n            PhClearReference(&data->BalloonText);\n        }\n\n        PhFree(data);\n    }\n}\n#endif\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhNfpTrayIconUpdateThread(\n    _In_opt_ PVOID Context\n    )\n{\n    PhSetThreadName(NtCurrentThread(), L\"TrayIconUpdateThread\");\n\n    for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    {\n        PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n        if (!BooleanFlagOn(icon->Flags, PH_NF_ICON_ENABLED))\n            continue;\n\n        PhNfpAddNotifyIcon(icon);\n    }\n\n    while (TRUE)\n    {\n        if (PhMainWndExiting)\n            break;\n\n        if (!(PhpTrayIconEventHandle && PhNfIconsEnabled()))\n        {\n            PhDelayExecution(1000);\n            continue;\n        }\n\n        if (NT_SUCCESS(NtWaitForSingleObject(PhpTrayIconEventHandle, FALSE, NULL)))\n        {\n#ifdef PH_NF_ENABLE_WORKQUEUE\n            PhNfTrayIconFlushWorkQueueData();\n#endif\n            for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n            {\n                PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n                if (!BooleanFlagOn(icon->Flags, PH_NF_ICON_ENABLED))\n                    continue;\n\n                if (PhMainWndExiting)\n                    break;\n\n                PhNfpUpdateRegisteredIcon(icon);\n            }\n        }\n    }\n\n#ifdef PH_NF_ENABLE_WORKQUEUE\n    // Remove all icons to prevent them hanging around after we exit.\n\n    for (ULONG i = 0; i < PhTrayIconItemList->Count; i++)\n    {\n        PPH_NF_ICON icon = PhTrayIconItemList->Items[i];\n\n        if (RtlInterlockedClearBits(&icon->Flags, PH_NF_ICON_ENABLED) == PH_NF_ICON_ENABLED)\n        {\n            PhNfpRemoveNotifyIcon(icon);\n        }\n    }\n#endif\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhNfpProcessesUpdatedHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG runCount = PtrToUlong(Parameter);\n\n    // Update the icons on a separate thread so we don't block the main window\n    // or provider threads when explorer is not responding. (dmex)\n\n    if (runCount < 3)\n        return;\n\n    if (PhpTrayIconEventHandle)// && PhNfIconsEnabled())\n    {\n        NtSetEvent(PhpTrayIconEventHandle, NULL);\n    }\n}\n\nVOID PhNfpUpdateRegisteredIcon(\n    _In_ PPH_NF_ICON Icon\n    )\n{\n    PVOID newIconOrBitmap;\n    ULONG updateFlags;\n    PPH_STRING newText;\n    HICON newIcon;\n    ULONG flags;\n\n    if (!Icon->UpdateCallback)\n        return;\n\n    newIconOrBitmap = NULL;\n    newText = NULL;\n    newIcon = NULL;\n    flags = 0;\n\n    Icon->UpdateCallback(\n        Icon,\n        &newIconOrBitmap,\n        &updateFlags,\n        &newText,\n        Icon->Context\n        );\n\n    if (newIconOrBitmap)\n    {\n        if (FlagOn(updateFlags, PH_NF_UPDATE_IS_BITMAP))\n            newIcon = PhNfBitmapToIcon(newIconOrBitmap);\n        else\n            newIcon = newIconOrBitmap;\n\n        SetFlag(flags, NIF_ICON);\n    }\n\n    if (newText)\n        SetFlag(flags, NIF_TIP);\n\n    if (flags != 0)\n        PhNfpModifyNotifyIcon(Icon, flags, newText, newIcon);\n\n    if (newIcon && FlagOn(updateFlags, PH_NF_UPDATE_IS_BITMAP))\n        DestroyIcon(newIcon);\n\n    if (newIconOrBitmap && FlagOn(updateFlags, PH_NF_UPDATE_DESTROY_RESOURCE))\n    {\n        if (FlagOn(updateFlags, PH_NF_UPDATE_IS_BITMAP))\n            DeleteBitmap(newIconOrBitmap);\n        else\n            DestroyIcon(newIconOrBitmap);\n    }\n\n    if (newText)\n        PhDereferenceObject(newText);\n}\n\n_Function_class_(PH_NF_BEGIN_BITMAP)\nVOID PhNfpBeginBitmap(\n    _Out_ PULONG Width,\n    _Out_ PULONG Height,\n    _Out_ HBITMAP *Bitmap,\n    _Out_opt_ PVOID *Bits,\n    _Out_ HDC *Hdc,\n    _Out_ HBITMAP *OldBitmap\n    )\n{\n    PhNfpBeginBitmap2(&PhNfpDefaultBitmapContext, Width, Height, Bitmap, Bits, Hdc, OldBitmap);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpBeginBitmap2(\n    _Inout_ PPH_NF_BITMAP Context,\n    _Out_ PULONG Width,\n    _Out_ PULONG Height,\n    _Out_ HBITMAP *Bitmap,\n    _Out_opt_ PVOID *Bits,\n    _Out_ HDC *Hdc,\n    _Out_ HBITMAP *OldBitmap\n    )\n{\n    LONG dpiValue = PhGetTaskbarDpi();\n\n    // Initialize and cache the current system metrics. (dmex)\n\n    if (Context->TaskbarDpi == 0 || Context->TaskbarDpi != dpiValue)\n    {\n        Context->Width = PhGetSystemMetrics(SM_CXSMICON, dpiValue);\n        Context->Height = PhGetSystemMetrics(SM_CXSMICON, dpiValue);\n\n        // Re-initialize fonts with updated DPI (only when there's an existing handle). (dmex)\n        //PhNfGetTrayIconFont(dpiValue);\n        //PhNfGetApplicationIcon(dpiValue);\n    }\n\n    // Cleanup existing resources when the DPI changes so we're able to re-initialize with updated DPI. (dmex)\n\n    if (Context->TaskbarDpi != 0 && Context->TaskbarDpi != dpiValue)\n    {\n        if (PhNfpBlackIcon)\n        {\n            DestroyIcon(PhNfpBlackIcon);\n            PhNfpBlackIcon = NULL;\n        }\n\n        if (Context->Hdc)\n        {\n            DeleteDC(Context->Hdc);\n            Context->Hdc = NULL;\n        }\n\n        if (Context->Bitmap)\n        {\n            DeleteBitmap(Context->Bitmap);\n            Context->Bitmap = NULL;\n        }\n\n        Context->Initialized = FALSE;\n    }\n\n    if (!Context->Initialized)\n    {\n        BITMAPINFO bitmapInfo;\n\n        memset(&bitmapInfo, 0, sizeof(BITMAPINFO));\n        bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n        bitmapInfo.bmiHeader.biPlanes = 1;\n        bitmapInfo.bmiHeader.biCompression = BI_RGB;\n        bitmapInfo.bmiHeader.biWidth = Context->Width;\n        bitmapInfo.bmiHeader.biHeight = Context->Height;\n        bitmapInfo.bmiHeader.biBitCount = 32;\n\n        Context->Hdc = CreateCompatibleDC(NULL);\n        Context->Bitmap = CreateDIBSection(Context->Hdc, &bitmapInfo, DIB_RGB_COLORS, &Context->Bits, NULL, 0);\n\n        Context->TaskbarDpi = dpiValue;\n        Context->Initialized = TRUE;\n    }\n\n    *Width = Context->Width;\n    *Height = Context->Height;\n    *Bitmap = Context->Bitmap;\n    if (Bits) *Bits = Context->Bits;\n    *Hdc = Context->Hdc;\n    if (Context->Bitmap) *OldBitmap = SelectBitmap(Context->Hdc, Context->Bitmap);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCpuHistoryIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_GRAPH_DRAW_INFO drawInfo =\n    {\n        16,\n        16,\n        PH_GRAPH_USE_LINE_2,\n        2,\n        RGB(0x00, 0x00, 0x00),\n        16,\n        NULL,\n        NULL,\n        0,\n        0,\n        0,\n        0\n    };\n    ULONG maxDataCount;\n    ULONG lineDataCount;\n    PFLOAT lineData1;\n    PFLOAT lineData2;\n    HBITMAP bitmap;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    HANDLE maxCpuProcessId;\n    PPH_PROCESS_ITEM maxCpuProcessItem;\n    PH_FORMAT format[8];\n\n    // Icon\n\n    Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);\n    maxDataCount = drawInfo.Width / 2 + 1;\n    lineData1 = _malloca(maxDataCount * sizeof(FLOAT));\n    lineData2 = _malloca(maxDataCount * sizeof(FLOAT));\n\n    if (!(lineData1 && lineData2))\n        return;\n\n    lineDataCount = min(maxDataCount, PhCpuKernelHistory.Count);\n    PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory, lineData1, lineDataCount);\n    PhCopyCircularBuffer_FLOAT(&PhCpuUserHistory, lineData2, lineDataCount);\n\n    drawInfo.LineDataCount = lineDataCount;\n    drawInfo.LineData1 = lineData1;\n    drawInfo.LineData2 = lineData2;\n    drawInfo.LineColor1 = PhCsColorCpuKernel;\n    drawInfo.LineColor2 = PhCsColorCpuUser;\n    drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorCpuKernel);\n    drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorCpuUser);\n    PhDrawGraphDirect(hdc, bits, &drawInfo);\n\n    if (PhNfTransparencyEnabled)\n    {\n        PhBitmapSetAlpha(bits, drawInfo.Width, drawInfo.Height);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    *NewIconOrBitmap = bitmap;\n    *Flags = PH_NF_UPDATE_IS_BITMAP;\n\n    // Text\n\n    if (PhMaxCpuHistory.Count != 0)\n        maxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0));\n    else\n        maxCpuProcessId = NULL;\n\n    if (maxCpuProcessId)\n        maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId);\n    else\n        maxCpuProcessItem = NULL;\n\n    PhInitFormatS(&format[0], L\"CPU history: \");\n    PhInitFormatF(&format[1], (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhMaxPrecisionUnit);\n    PhInitFormatC(&format[2], '%');\n\n    if (maxCpuProcessItem)\n    {\n        PhInitFormatC(&format[3], '\\n');\n        PhInitFormatSR(&format[4], maxCpuProcessItem->ProcessName->sr);\n        PhInitFormatS(&format[5], L\": \");\n        PhInitFormatF(&format[6], maxCpuProcessItem->CpuUsage * 100, PhMaxPrecisionUnit);\n        PhInitFormatC(&format[7], '%');\n    }\n\n    *NewText = PhFormat(format, maxCpuProcessItem ? 8 : 3, 0);\n    if (maxCpuProcessItem) PhDereferenceObject(maxCpuProcessItem);\n\n    _freea(lineData2);\n    _freea(lineData1);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpIoHistoryIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_GRAPH_DRAW_INFO drawInfo =\n    {\n        16,\n        16,\n        PH_GRAPH_USE_LINE_2,\n        2,\n        RGB(0x00, 0x00, 0x00),\n        16,\n        NULL,\n        NULL,\n        0,\n        0,\n        0,\n        0\n    };\n    ULONG maxDataCount;\n    ULONG lineDataCount;\n    PFLOAT lineData1;\n    PFLOAT lineData2;\n    FLOAT max;\n    ULONG i;\n    HBITMAP bitmap;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    HANDLE maxIoProcessId;\n    PPH_PROCESS_ITEM maxIoProcessItem;\n    PH_FORMAT format[8];\n\n    // Icon\n\n    Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);\n    maxDataCount = drawInfo.Width / 2 + 1;\n    lineData1 = _malloca(maxDataCount * sizeof(FLOAT));\n    lineData2 = _malloca(maxDataCount * sizeof(FLOAT));\n\n    if (!(lineData1 && lineData2))\n        return;\n\n    lineDataCount = min(maxDataCount, PhIoReadHistory.Count);\n    max = 1024 * 1024; // minimum scaling of 1 MB.\n\n    for (i = 0; i < lineDataCount; i++)\n    {\n        lineData1[i] =\n            (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i) +\n            (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i);\n        lineData2[i] =\n            (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i);\n\n        if (max < lineData1[i] + lineData2[i])\n            max = lineData1[i] + lineData2[i];\n    }\n\n    PhDivideSinglesBySingle(lineData1, max, lineDataCount);\n    PhDivideSinglesBySingle(lineData2, max, lineDataCount);\n\n    drawInfo.LineDataCount = lineDataCount;\n    drawInfo.LineData1 = lineData1;\n    drawInfo.LineData2 = lineData2;\n    drawInfo.LineColor1 = PhCsColorIoReadOther;\n    drawInfo.LineColor2 = PhCsColorIoWrite;\n    drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorIoReadOther);\n    drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorIoWrite);\n    PhDrawGraphDirect(hdc, bits, &drawInfo);\n\n    if (PhNfTransparencyEnabled)\n    {\n        PhBitmapSetAlpha(bits, drawInfo.Width, drawInfo.Height);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    *NewIconOrBitmap = bitmap;\n    *Flags = PH_NF_UPDATE_IS_BITMAP;\n\n    // Text\n\n    if (PhMaxIoHistory.Count != 0)\n        maxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0));\n    else\n        maxIoProcessId = NULL;\n\n    if (maxIoProcessId)\n        maxIoProcessItem = PhReferenceProcessItem(maxIoProcessId);\n    else\n        maxIoProcessItem = NULL;\n\n    PhInitFormatS(&format[0], L\"I/O\\nR: \");\n    PhInitFormatSize(&format[1], PhIoReadDelta.Delta);\n    PhInitFormatS(&format[2], L\"\\nW: \");\n    PhInitFormatSize(&format[3], PhIoWriteDelta.Delta);\n    PhInitFormatS(&format[4], L\"\\nO: \");\n    PhInitFormatSize(&format[5], PhIoOtherDelta.Delta);\n\n    if (maxIoProcessItem)\n    {\n        PhInitFormatC(&format[6], '\\n');\n        PhInitFormatSR(&format[7], maxIoProcessItem->ProcessName->sr);\n    }\n\n    *NewText = PhFormat(format, maxIoProcessItem ? 8 : 6, 0);\n    if (maxIoProcessItem) PhDereferenceObject(maxIoProcessItem);\n\n    _freea(lineData2);\n    _freea(lineData1);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCommitHistoryIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_GRAPH_DRAW_INFO drawInfo =\n    {\n        16,\n        16,\n        0,\n        2,\n        RGB(0x00, 0x00, 0x00),\n        16,\n        NULL,\n        NULL,\n        0,\n        0,\n        0,\n        0\n    };\n    ULONG maxDataCount;\n    ULONG lineDataCount;\n    PFLOAT lineData1;\n    ULONG i;\n    HBITMAP bitmap;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    FLOAT commitFraction;\n    PH_FORMAT format[5];\n\n    // Icon\n\n    Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);\n    maxDataCount = drawInfo.Width / 2 + 1;\n    lineData1 = _malloca(maxDataCount * sizeof(FLOAT));\n\n    if (!lineData1)\n        return;\n\n    lineDataCount = min(maxDataCount, PhCommitHistory.Count);\n\n    for (i = 0; i < lineDataCount; i++)\n        lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i);\n\n    PhDivideSinglesBySingle(lineData1, (FLOAT)PhPerfInformation.CommitLimit, lineDataCount);\n\n    drawInfo.LineDataCount = lineDataCount;\n    drawInfo.LineData1 = lineData1;\n    drawInfo.LineColor1 = PhCsColorPrivate;\n    drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorPrivate);\n    PhDrawGraphDirect(hdc, bits, &drawInfo);\n\n    if (PhNfTransparencyEnabled)\n    {\n        PhBitmapSetAlpha(bits, drawInfo.Width, drawInfo.Height);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    *NewIconOrBitmap = bitmap;\n    *Flags = PH_NF_UPDATE_IS_BITMAP;\n\n    // Text\n\n    commitFraction = (FLOAT)PhPerfInformation.CommittedPages / (FLOAT)PhPerfInformation.CommitLimit;\n\n    PhInitFormatS(&format[0], L\"Commit: \");\n    PhInitFormatSize(&format[1], UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE));\n    PhInitFormatS(&format[2], L\" (\");\n    PhInitFormatF(&format[3], commitFraction * 100, PhMaxPrecisionUnit);\n    PhInitFormatS(&format[4], L\"%)\");\n\n    *NewText = PhFormat(format, 5, 0);\n\n    _freea(lineData1);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpPhysicalHistoryIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_GRAPH_DRAW_INFO drawInfo =\n    {\n        16,\n        16,\n        0,\n        2,\n        RGB(0x00, 0x00, 0x00),\n        16,\n        NULL,\n        NULL,\n        0,\n        0,\n        0,\n        0\n    };\n    ULONG maxDataCount;\n    ULONG lineDataCount;\n    PFLOAT lineData1;\n    ULONG i;\n    HBITMAP bitmap;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    ULONG_PTR physicalUsage;\n    FLOAT physicalFraction;\n    PH_FORMAT format[5];\n\n    // Icon\n\n    Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);\n    maxDataCount = drawInfo.Width / 2 + 1;\n    lineData1 = _malloca(maxDataCount * sizeof(FLOAT));\n\n    if (!lineData1)\n        return;\n\n    lineDataCount = min(maxDataCount, PhPhysicalHistory.Count);\n\n    for (i = 0; i < lineDataCount; i++)\n        lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i);\n\n    PhDivideSinglesBySingle(lineData1, (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, lineDataCount);\n\n    drawInfo.LineDataCount = lineDataCount;\n    drawInfo.LineData1 = lineData1;\n    drawInfo.LineColor1 = PhCsColorPhysical;\n    drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorPhysical);\n    PhDrawGraphDirect(hdc, bits, &drawInfo);\n\n    if (PhNfTransparencyEnabled)\n    {\n        PhBitmapSetAlpha(bits, drawInfo.Width, drawInfo.Height);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    *NewIconOrBitmap = bitmap;\n    *Flags = PH_NF_UPDATE_IS_BITMAP;\n\n    // Text\n\n    physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages;\n    physicalFraction = (FLOAT)physicalUsage / (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages;\n\n    PhInitFormatS(&format[0], L\"Physical memory: \");\n    PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE));\n    PhInitFormatS(&format[2], L\" (\");\n    PhInitFormatF(&format[3], physicalFraction * 100, PhMaxPrecisionUnit);\n    PhInitFormatS(&format[4], L\"%)\");\n\n    *NewText = PhFormat(format, 5, 0);\n\n    _freea(lineData1);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCpuUsageIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    LONG width;\n    LONG height;\n    HBITMAP bitmap;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    PH_FORMAT format[5];\n    HANDLE maxCpuProcessId;\n    PPH_PROCESS_ITEM maxCpuProcessItem;\n    PPH_STRING maxCpuText = NULL;\n\n    // Icon\n\n    Icon->Pointers->BeginBitmap(&width, &height, &bitmap, &bits, &hdc, &oldBitmap);\n\n    // This stuff is copied from CpuUsageIcon.cs (PH 1.x).\n    {\n        COLORREF kColor = PhCsColorCpuKernel;\n        COLORREF uColor = PhCsColorCpuUser;\n        COLORREF kbColor = PhHalveColorBrightness(PhCsColorCpuKernel);\n        COLORREF ubColor = PhHalveColorBrightness(PhCsColorCpuUser);\n        FLOAT k = PhCpuKernelUsage;\n        FLOAT u = PhCpuUserUsage;\n        LONG kl = (LONG)(k * height);\n        LONG ul = (LONG)(u * height);\n        RECT rect;\n        HBRUSH dcBrush;\n        HPEN dcPen;\n        POINT points[2];\n\n        dcBrush = PhGetStockBrush(DC_BRUSH);\n        dcPen = PhGetStockPen(DC_PEN);\n        rect.left = 0;\n        rect.top = 0;\n        rect.right = width;\n        rect.bottom = height;\n        SetDCBrushColor(hdc, RGB(0x00, 0x00, 0x00));\n        FillRect(hdc, &rect, dcBrush);\n\n        // Draw the base line.\n        if (kl + ul == 0)\n        {\n            SelectPen(hdc, dcPen);\n            SetDCPenColor(hdc, uColor);\n            points[0].x = 0;\n            points[0].y = height - 1;\n            points[1].x = width;\n            points[1].y = height - 1;\n            Polyline(hdc, points, 2);\n        }\n        else\n        {\n            rect.left = 0;\n            rect.top = height - ul - kl;\n            rect.right = width;\n            rect.bottom = height - kl;\n            SetDCBrushColor(hdc, ubColor);\n            FillRect(hdc, &rect, dcBrush);\n\n            points[0].x = 0;\n            points[0].y = height - 1 - ul - kl;\n            if (points[0].y < 0) points[0].y = 0;\n            points[1].x = width;\n            points[1].y = points[0].y;\n            SelectPen(hdc, dcPen);\n            SetDCPenColor(hdc, uColor);\n            Polyline(hdc, points, 2);\n\n            if (kl != 0)\n            {\n                rect.left = 0;\n                rect.top = height - kl;\n                rect.right = width;\n                rect.bottom = height;\n                SetDCBrushColor(hdc, kbColor);\n                FillRect(hdc, &rect, dcBrush);\n\n                points[0].x = 0;\n                points[0].y = height - 1 - kl;\n                if (points[0].y < 0) points[0].y = 0;\n                points[1].x = width;\n                points[1].y = points[0].y;\n                SelectPen(hdc, dcPen);\n                SetDCPenColor(hdc, kColor);\n                Polyline(hdc, points, 2);\n            }\n        }\n    }\n\n    if (PhNfTransparencyEnabled)\n    {\n        PhBitmapSetAlpha(bits, width, height);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    *NewIconOrBitmap = bitmap;\n    *Flags = PH_NF_UPDATE_IS_BITMAP;\n\n    // Text\n\n    if (PhMaxCpuHistory.Count != 0)\n        maxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0));\n    else\n        maxCpuProcessId = NULL;\n\n    if (maxCpuProcessId)\n    {\n        if (maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId))\n        {\n            // \\n%s: %.2f%%\n            PhInitFormatC(&format[0], L'\\n');\n            PhInitFormatSR(&format[1], maxCpuProcessItem->ProcessName->sr);\n            PhInitFormatS(&format[2], L\": \");\n            PhInitFormatF(&format[3], maxCpuProcessItem->CpuUsage * 100.f, PhMaxPrecisionUnit);\n            PhInitFormatC(&format[4], L'%');\n\n            maxCpuText = PhFormat(format, 5, 0);\n            //maxCpuText = PhFormatString(\n            //    L\"\\n%s: %.2f%%\",\n            //    maxCpuProcessItem->ProcessName->Buffer,\n            //    maxCpuProcessItem->CpuUsage * 100\n            //    );\n            PhDereferenceObject(maxCpuProcessItem);\n        }\n    }\n\n    PhInitFormatS(&format[0], L\"CPU usage: \");\n    PhInitFormatF(&format[1], (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhMaxPrecisionUnit);\n    PhInitFormatC(&format[2], L'%');\n    if (maxCpuText) PhInitFormatSR(&format[3], maxCpuText->sr);\n    else PhInitFormatC(&format[3], L' ');\n\n    *NewText = PhFormat(format, 4, 0);\n    //*NewText = PhFormatString(L\"CPU usage: %.2f%%%s\", (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhGetStringOrEmpty(maxCpuText));\n    if (maxCpuText) PhDereferenceObject(maxCpuText);\n}\n\n// Text icons\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCpuUsageTextIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_GRAPH_DRAW_INFO drawInfo =\n    {\n        16,\n        16,\n        0,\n        2,\n        RGB(0x00, 0x00, 0x00),\n        16,\n        NULL,\n        NULL,\n        0,\n        0,\n        0,\n        0\n    };\n    HBITMAP bitmap;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    PH_FORMAT format[5];\n    HANDLE maxCpuProcessId;\n    PPH_PROCESS_ITEM maxCpuProcessItem;\n    PPH_STRING maxCpuText = NULL;\n    PPH_STRING text;\n\n    // Icon\n\n    Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);\n\n    PhInitFormatF(&format[0], (PhCpuKernelUsage + PhCpuUserUsage) * 100.f, 0);\n    text = PhFormat(format, 1, 0);\n\n    drawInfo.TextFont = PhNfGetTrayIconFont(0);\n    drawInfo.TextColor = PhCsColorCpuKernel;\n    PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr);\n    PhDereferenceObject(text);\n\n    if (PhNfTransparencyEnabled)\n    {\n        PhBitmapSetAlpha(bits, drawInfo.Width, drawInfo.Height);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    *NewIconOrBitmap = bitmap;\n    *Flags = PH_NF_UPDATE_IS_BITMAP;\n\n    // Text\n\n    if (PhMaxCpuHistory.Count != 0)\n        maxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0));\n    else\n        maxCpuProcessId = NULL;\n\n    if (maxCpuProcessId)\n    {\n        if (maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId))\n        {\n            PhInitFormatC(&format[0], L'\\n');\n            PhInitFormatSR(&format[1], maxCpuProcessItem->ProcessName->sr);\n            PhInitFormatS(&format[2], L\": \");\n            PhInitFormatF(&format[3], maxCpuProcessItem->CpuUsage * 100.f, PhMaxPrecisionUnit);\n            PhInitFormatC(&format[4], L'%');\n\n            maxCpuText = PhFormat(format, 5, 0);\n            //maxCpuText = PhFormatString(\n            //    L\"\\n%s: %.2f%%\",\n            //    maxCpuProcessItem->ProcessName->Buffer,\n            //    maxCpuProcessItem->CpuUsage * 100\n            //    );\n            PhDereferenceObject(maxCpuProcessItem);\n        }\n    }\n\n    PhInitFormatS(&format[0], L\"CPU usage: \");\n    PhInitFormatF(&format[1], (PhCpuKernelUsage + PhCpuUserUsage) * 100.f, PhMaxPrecisionUnit);\n    PhInitFormatC(&format[2], L'%');\n    if (maxCpuText) PhInitFormatSR(&format[3], maxCpuText->sr);\n    else PhInitFormatC(&format[3], L' ');\n\n    *NewText = PhFormat(format, 4, 0);\n    //*NewText = PhFormatString(L\"CPU usage: %.2f%%%s\", (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhGetStringOrEmpty(maxCpuText));\n    if (maxCpuText) PhDereferenceObject(maxCpuText);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpIoUsageTextIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_GRAPH_DRAW_INFO drawInfo =\n    {\n        16,\n        16,\n        0,\n        0,\n        RGB(0x00, 0x00, 0x00),\n        0,\n        NULL,\n        NULL,\n        0,\n        0,\n        0,\n        0\n    };\n    HBITMAP bitmap;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    HANDLE maxIoProcessId;\n    PPH_PROCESS_ITEM maxIoProcessItem;\n    PH_FORMAT format[8];\n    PPH_STRING text;\n    SIZE_T returnLength;\n    WCHAR buffer[PH_INT64_STR_LEN_1];\n    static ULONG64 maxValue = UInt32x32To64(100000, 1024); // minimum scaling of 100 MB.\n\n    // TODO: Reset maxValue every X amount of time.\n\n    // Icon\n\n    Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);\n    drawInfo.TextFont = PhNfGetTrayIconFont(0);\n    drawInfo.TextColor = PhCsColorIoReadOther;\n\n    if (maxValue < (PhIoReadDelta.Delta + PhIoWriteDelta.Delta + PhIoOtherDelta.Delta))\n        maxValue = (PhIoReadDelta.Delta + PhIoWriteDelta.Delta + PhIoOtherDelta.Delta);\n\n    PhInitFormatF(&format[0], (PhIoReadDelta.Delta + PhIoWriteDelta.Delta + PhIoOtherDelta.Delta) / maxValue * 100.f, 0);\n\n    if (PhFormatToBuffer(format, 1, buffer, sizeof(buffer), &returnLength))\n    {\n        PH_STRINGREF string;\n\n        string.Buffer = buffer;\n        string.Length = returnLength - sizeof(UNICODE_NULL);\n\n        PhDrawTrayIconText(hdc, bits, &drawInfo, &string);\n    }\n    else\n    {\n        text = PhFormat(format, 1, 0);\n        PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr);\n        PhDereferenceObject(text);\n    }\n\n    if (PhNfTransparencyEnabled)\n    {\n        PhBitmapSetAlpha(bits, drawInfo.Width, drawInfo.Height);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    *NewIconOrBitmap = bitmap;\n    *Flags = PH_NF_UPDATE_IS_BITMAP;\n\n    // Text\n\n    if (PhMaxIoHistory.Count != 0)\n        maxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0));\n    else\n        maxIoProcessId = NULL;\n\n    if (maxIoProcessId)\n        maxIoProcessItem = PhReferenceProcessItem(maxIoProcessId);\n    else\n        maxIoProcessItem = NULL;\n\n    PhInitFormatS(&format[0], L\"I/O\\nR: \");\n    PhInitFormatSize(&format[1], PhIoReadDelta.Delta);\n    PhInitFormatS(&format[2], L\"\\nW: \");\n    PhInitFormatSize(&format[3], PhIoWriteDelta.Delta);\n    PhInitFormatS(&format[4], L\"\\nO: \");\n    PhInitFormatSize(&format[5], PhIoOtherDelta.Delta);\n\n    if (maxIoProcessItem)\n    {\n        PhInitFormatC(&format[6], '\\n');\n        PhInitFormatSR(&format[7], maxIoProcessItem->ProcessName->sr);\n    }\n\n    *NewText = PhFormat(format, maxIoProcessItem ? 8 : 6, 128);\n    if (maxIoProcessItem) PhDereferenceObject(maxIoProcessItem);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpCommitTextIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_GRAPH_DRAW_INFO drawInfo =\n    {\n        16,\n        16,\n        0,\n        0,\n        RGB(0x00, 0x00, 0x00),\n        0,\n        NULL,\n        NULL,\n        0,\n        0,\n        0,\n        0\n    };\n    HBITMAP bitmap;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    FLOAT commitFraction;\n    PH_FORMAT format[5];\n    PPH_STRING text;\n    SIZE_T returnLength;\n    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n    commitFraction = (FLOAT)PhPerfInformation.CommittedPages / PhPerfInformation.CommitLimit * 100.f;\n\n    // Icon\n\n    Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);\n    drawInfo.TextFont = PhNfGetTrayIconFont(0);\n    drawInfo.TextColor = PhCsColorPrivate;\n\n    PhInitFormatF(&format[0], commitFraction, 0);\n\n    if (PhFormatToBuffer(format, 1, buffer, sizeof(buffer), &returnLength))\n    {\n        PH_STRINGREF string;\n\n        string.Buffer = buffer;\n        string.Length = returnLength - sizeof(UNICODE_NULL);\n\n        PhDrawTrayIconText(hdc, bits, &drawInfo, &string);\n    }\n    else\n    {\n        text = PhFormat(format, 1, 0);\n        PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr);\n        PhDereferenceObject(text);\n    }\n\n    if (PhNfTransparencyEnabled)\n    {\n        PhBitmapSetAlpha(bits, drawInfo.Width, drawInfo.Height);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    *NewIconOrBitmap = bitmap;\n    *Flags = PH_NF_UPDATE_IS_BITMAP;\n\n    // Text\n\n    PhInitFormatS(&format[0], L\"Commit: \");\n    PhInitFormatSize(&format[1], UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE));\n    PhInitFormatS(&format[2], L\" (\");\n    PhInitFormatF(&format[3], commitFraction, PhMaxPrecisionUnit);\n    PhInitFormatS(&format[4], L\"%)\");\n\n    *NewText = PhFormat(format, 5, 0);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpPhysicalUsageTextIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_GRAPH_DRAW_INFO drawInfo =\n    {\n        16,\n        16,\n        0,\n        0,\n        RGB(0x00, 0x00, 0x00),\n        0,\n        NULL,\n        NULL,\n        0,\n        0,\n        0,\n        0\n    };\n    HBITMAP bitmap;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    ULONG_PTR physicalUsage;\n    FLOAT physicalFraction;\n    PH_FORMAT format[5];\n    PPH_STRING text;\n    SIZE_T returnLength;\n    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n    // Icon\n\n    Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);\n    drawInfo.TextFont = PhNfGetTrayIconFont(0);\n    drawInfo.TextColor = PhCsColorPhysical;\n\n    physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages;\n    physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages;\n\n    PhInitFormatF(&format[0], physicalFraction * 100.f, 0);\n\n    if (PhFormatToBuffer(format, 1, buffer, sizeof(buffer), &returnLength))\n    {\n        PH_STRINGREF string;\n\n        string.Buffer = buffer;\n        string.Length = returnLength - sizeof(UNICODE_NULL);\n\n        PhDrawTrayIconText(hdc, bits, &drawInfo, &string);\n    }\n    else\n    {\n        text = PhFormat(format, 1, 0);\n        PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr);\n        PhDereferenceObject(text);\n    }\n\n    if (PhNfTransparencyEnabled)\n    {\n        PhBitmapSetAlpha(bits, drawInfo.Width, drawInfo.Height);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    *NewIconOrBitmap = bitmap;\n    *Flags = PH_NF_UPDATE_IS_BITMAP;\n\n    // Text\n\n    PhInitFormatS(&format[0], L\"Physical memory: \");\n    PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE));\n    PhInitFormatS(&format[2], L\" (\");\n    PhInitFormatF(&format[3], physicalFraction * 100.f, PhMaxPrecisionUnit);\n    PhInitFormatS(&format[4], L\"%)\");\n\n    *NewText = PhFormat(format, 5, 96);\n    *NewText = PhFormat(format, 5, 0);\n}\n\n_Function_class_(PH_NF_ICON_UPDATE_CALLBACK)\nVOID PhNfpPlainIconUpdateCallback(\n    _In_ PPH_NF_ICON Icon,\n    _Out_ PVOID *NewIconOrBitmap,\n    _Out_ PULONG Flags,\n    _Out_ PPH_STRING *NewText,\n    _In_opt_ PVOID Context\n    )\n{\n    static PPH_STRING string = NULL;\n\n    if (!string)\n    {\n        PH_STRINGREF text = PH_STRINGREF_INIT(L\"System Informer\");\n        string = PhCreateString2(&text);\n    }\n\n    *NewIconOrBitmap = PhNfGetApplicationIcon(0);\n    *NewText = PhReferenceObject(string);\n    *Flags = 0;\n}\n\n_Success_(return)\nBOOLEAN PhNfpGetShowMiniInfoSectionData(\n    _In_ ULONG IconIndex,\n    _In_ PPH_NF_ICON RegisteredIcon,\n    _Out_ PPH_NF_MSG_SHOWMINIINFOSECTION_DATA Data\n    )\n{\n    BOOLEAN showMiniInfo = FALSE;\n\n    if (RegisteredIcon && RegisteredIcon->MessageCallback)\n    {\n        Data->SectionName = NULL;\n\n        if (!FlagOn(RegisteredIcon->Flags, PH_NF_ICON_NOSHOW_MINIINFO))\n        {\n            if (RegisteredIcon->MessageCallback)\n            {\n                RegisteredIcon->MessageCallback(\n                    RegisteredIcon,\n                    (ULONG_PTR)Data,\n                    MAKELPARAM(PH_NF_MSG_SHOWMINIINFOSECTION, 0),\n                    RegisteredIcon->Context\n                    );\n            }\n\n            showMiniInfo = TRUE;\n        }\n    }\n    else\n    {\n        showMiniInfo = TRUE;\n\n        switch (IconIndex)\n        {\n        case PH_TRAY_ICON_ID_CPU_HISTORY:\n        case PH_TRAY_ICON_ID_CPU_USAGE:\n        case PH_TRAY_ICON_ID_CPU_TEXT:\n        case PH_TRAY_ICON_ID_PLAIN_ICON:\n            Data->SectionName = L\"CPU\";\n            break;\n        case PH_TRAY_ICON_ID_IO_HISTORY:\n        case PH_TRAY_ICON_ID_IO_TEXT:\n            Data->SectionName = L\"I/O\";\n            break;\n        case PH_TRAY_ICON_ID_COMMIT_HISTORY:\n        case PH_TRAY_ICON_ID_COMMIT_TEXT:\n            Data->SectionName = L\"Commit charge\";\n            break;\n        case PH_TRAY_ICON_ID_PHYSICAL_HISTORY:\n        case PH_TRAY_ICON_ID_PHYSICAL_TEXT:\n            Data->SectionName = L\"Physical memory\";\n            break;\n        default:\n            showMiniInfo = FALSE;\n            break;\n        }\n    }\n\n    return showMiniInfo;\n}\n\nVOID PhNfpIconClickActivateTimerProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ UINT_PTR idEvent,\n    _In_ ULONG dwTime\n    )\n{\n    PhPinMiniInformation(MiniInfoActivePinType, 1, 0,\n        PH_MINIINFO_ACTIVATE_WINDOW | PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED,\n        IconClickShowMiniInfoSectionData.SectionName, &IconClickLocation);\n    PhKillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE);\n}\n\nVOID PhNfpDisableHover(\n    VOID\n    )\n{\n    IconDisableHover = TRUE;\n    PhSetTimer(PhMainWndHandle, TIMER_ICON_RESTORE_HOVER, NFP_ICON_RESTORE_HOVER_DELAY, PhNfpIconRestoreHoverTimerProc);\n}\n\nVOID PhNfpIconRestoreHoverTimerProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ UINT_PTR idEvent,\n    _In_ ULONG dwTime\n    )\n{\n    IconDisableHover = FALSE;\n    PhKillTimer(PhMainWndHandle, TIMER_ICON_RESTORE_HOVER);\n}\n\nVOID PhNfpIconDisablePopupHoverWin11Workaround(\n    VOID\n    )\n{\n    if (WindowsVersion >= WINDOWS_11_22H2)\n    {\n        PopupIconIndex = ULONG_MAX;\n        PopupRegisteredIcon = NULL;\n\n        PhKillTimer(PhMainWndHandle, TIMER_ICON_POPUPOPEN);\n    }\n}\n\nVOID PhNfpIconShowPopupHoverTimerProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ UINT_PTR idEvent,\n    _In_ ULONG dwTime\n    )\n{\n    PH_NF_MSG_SHOWMINIINFOSECTION_DATA showMiniInfoSectionData;\n    POINT location;\n\n    if (\n        PhNfMiniInfoEnabled && !IconDisableHover &&\n        PopupIconIndex != ULONG_MAX && PopupRegisteredIcon &&\n        PhNfpGetShowMiniInfoSectionData(PopupIconIndex, PopupRegisteredIcon, &showMiniInfoSectionData)\n        )\n    {\n        GetCursorPos(&location);\n        PhPinMiniInformation(MiniInfoIconPinType, 1, 0, PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED,\n            showMiniInfoSectionData.SectionName, &location);\n    }\n}\n"
  },
  {
    "path": "SystemInformer/notiftoast.cpp",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2021\n *\n */\n\n#include <phapp.h>\n#include <mapldr.h>\n#include <appresolver.h>\n\n#include <mainwnd.h>\n#include <notifico.h>\n#include <notiftoast.h>\n\n#include <wrl.h>\n#include <roapi.h>\n#include <windows.foundation.h>\n#include <windows.ui.core.h>\n\n#include <atomic>\n#include <memory>\n\n#ifndef RETURN_IF_FAILED\n#define RETURN_IF_FAILED(_HR_) do { const auto __hr = _HR_; if (HR_FAILED(__hr)) { return __hr; }} while (false)\n#endif\n\nusing namespace Microsoft::WRL;\nusing namespace Microsoft::WRL::Wrappers;\nusing namespace ABI::Windows::Foundation;\nusing namespace ABI::Windows::UI::Notifications;\nusing namespace ABI::Windows::Data::Xml::Dom;\n\nnamespace PH\n{\n    /*!\n        @brief Simple template wrapper around PhGetModuleProcAddress\n\n        @tparam T - Function pointer type.\n\n        @param[out] FunctionPointer - On success set to the address of the\n         function.\n        @param[in] Module - Module name to look up the function from.\n        @param[in] Function - Function name.\n\n        @return True when the function pointer container the address of the\n         function, false otherwise.\n    */\n    template <typename T>\n    bool GetModuleProcAddress(\n        _Out_ T* FunctionPointer,\n        _In_ const wchar_t* Module,\n        _In_ const char* Function\n        )\n    {\n        *FunctionPointer = static_cast<T>(PhGetModuleProcAddress(Module, Function));\n        return (*FunctionPointer != nullptr);\n    }\n\n    /*!\n        @brief Wrapper around RoGetActivationFactory to make it a little less clunky to use.\n\n        @details PhActivateToastRuntime must be called prior to this else the function returns\n         R_NOTIMPL.\n\n        @tparam I - Interface to retrieve.\n        @tparam t_SizeDestName - Length of the name string to use.\n        @tparam t_SizeDestClass - Length of the class string to use.\n\n        @param[in] ActivatableClassId - Activatable class ID to look up the interface from.\n        @param[out] Interface - On success, set to a referenced interface of type T.\n\n        @return Appropriate result status.\n    */\n    template <typename I, size_t t_SizeDestName, size_t t_SizeDestClass>\n    _Must_inspect_result_\n    HRESULT RoGetActivationFactory(\n        _In_ wchar_t const (&DllName)[t_SizeDestName],\n        _In_ wchar_t const (&ActivatableClassId)[t_SizeDestClass],\n        _COM_Outptr_ I** Interface\n        )\n    {\n        HRESULT hr = PhGetActivationFactory(\n                                      DllName,\n                                      ActivatableClassId,\n                                      __uuidof(I),\n                                      reinterpret_cast<void**>(Interface)\n                                      );\n        if (HR_FAILED(hr))\n        {\n            *Interface = nullptr;\n        }\n        return hr;\n    }\n\n    using IToastActivatedHandler = ITypedEventHandler<ToastNotification*, IInspectable*>;\n    using IToastDismissedHandler = ITypedEventHandler<ToastNotification*, ToastDismissedEventArgs*>;\n    using IToastFailedHandler = ITypedEventHandler<ToastNotification*, ToastFailedEventArgs*>;\n\n    /*!\n        @brief System Informer toast event handler, this class implements the\n         handler interfaces for IToastNotification and store the callback\n         and context from the C interface.\n    */\n    class ToastEventHandler final : public RuntimeClass<RuntimeClassFlags<ClassicCom>,\n                                                  IToastActivatedHandler,\n                                                  IToastDismissedHandler,\n                                                  IToastFailedHandler>\n    {\n    public:\n\n        HRESULT RuntimeClassInitialize(\n            PPH_TOAST_CALLBACK ToastCallback,\n            PVOID Context\n            )\n        {\n            m_ToastCallback = ToastCallback;\n            m_Context = Context;\n            return S_OK;\n        }\n\n        HRESULT STDMETHODCALLTYPE Invoke(\n            _In_ IToastNotification* Sender,\n            _In_ IInspectable* Args\n            ) override;\n\n        HRESULT STDMETHODCALLTYPE Invoke(\n            _In_ IToastNotification* Sender,\n            _In_ IToastDismissedEventArgs* Args\n            ) override;\n\n        HRESULT STDMETHODCALLTYPE Invoke(\n            _In_ IToastNotification* Sender,\n            _In_ IToastFailedEventArgs* Args\n            ) override;\n\n        void SetActivatedToken(const EventRegistrationToken& Token)\n        {\n            m_ActivatedToken = Token;\n        }\n\n        void SetDismissedToken(const EventRegistrationToken& Token)\n        {\n            m_DismissedToken = Token;\n        }\n\n        void SetFailedToken(const EventRegistrationToken& Token)\n        {\n            m_FailedToken = Token;\n        }\n\n    private:\n\n        PPH_TOAST_CALLBACK m_ToastCallback{ nullptr };\n        PVOID m_Context{ nullptr };\n\n        EventRegistrationToken m_ActivatedToken{};\n        EventRegistrationToken m_DismissedToken{};\n        EventRegistrationToken m_FailedToken{};\n\n    };\n\n    /*!\n        @brief System Informer toast object.\n    */\n    class Toast\n    {\n    public:\n\n        ~Toast() = default;\n\n        Toast() = default;\n\n        _Must_inspect_result_\n        HRESULT Initialize(\n            _In_ PPH_STRINGREF ApplicationId,\n            _In_ PPH_STRINGREF ToastXml,\n            _In_opt_ ULONG TimeoutMilliseconds,\n            _In_opt_ PPH_TOAST_CALLBACK ToastCallback,\n            _In_opt_ PVOID Context\n            );\n\n        [[nodiscard]]\n        HRESULT Show() const;\n\n    private:\n\n        ComPtr<IToastNotifier> m_Notifier{ nullptr };\n        ComPtr<IToastNotification> m_Toast{ nullptr };\n\n    };\n}\n\n_Must_inspect_result_\nHRESULT PH::Toast::Initialize(\n    _In_ PPH_STRINGREF ApplicationId,\n    _In_ PPH_STRINGREF ToastXml,\n    _In_opt_ ULONG TimeoutMilliseconds,\n    _In_opt_ PPH_TOAST_CALLBACK ToastCallback,\n    _In_opt_ PVOID Context\n    )\n{\n    HSTRING_REFERENCE stringAppIdRef;\n    HSTRING_REFERENCE stringToastXmlRef;\n\n    ComPtr<IToastNotificationManagerStatics> manager;\n    RETURN_IF_FAILED(PH::RoGetActivationFactory<IToastNotificationManagerStatics>(\n        L\"WpnApps.dll\",\n        L\"Windows.UI.Notifications.ToastNotificationManager\",\n        &manager));\n\n    ComPtr<IToastNotificationFactory> factory;\n    RETURN_IF_FAILED(PH::RoGetActivationFactory<IToastNotificationFactory>(\n        L\"WpnApps.dll\",\n        L\"Windows.UI.Notifications.ToastNotification\",\n        &factory));\n\n    ComPtr<IToastNotifier> notifier;\n    RETURN_IF_FAILED(PhCreateWindowsRuntimeStringRef(ApplicationId, &stringAppIdRef));\n    RETURN_IF_FAILED(manager->CreateToastNotifierWithId(HSTRING_FROM_STRING(stringAppIdRef), &notifier));\n\n    //\n    // Couldn't find a nice way to just create a IXmlDocument... There is\n    // probably a way to but I guess I'm lazy. I'm just going to grab a\n    // template one from the manager interface then overwrite it with the\n    // input.\n    //\n    ComPtr<IXmlDocument> xmlDocument;\n    RETURN_IF_FAILED(manager->GetTemplateContent(\n        ToastTemplateType::ToastTemplateType_ToastImageAndText02,\n        &xmlDocument));\n\n    //\n    // The IXmlDocument we get here implements IXmlDocumentIO thankfully so\n    // just query for it, we'll replace the content using this interface.\n    //\n    ComPtr<IXmlDocumentIO> xmlIo;\n    RETURN_IF_FAILED(xmlDocument.As(&xmlIo));\n\n    //\n    // Load the supplied XML, if it's invalid this will return an error.\n    //\n    // Note, if it's valid XAML but you include an image file that is not\n    // found we will end up returning success but the callback will never\n    // get invoked. So if you allocated the context through to the C interface\n    // it will leak... We could solve this by requiring a context cleanup\n    // callback from the C interface. Honestly, that's kind of overkill, don't\n    // include an image that can't be found.\n    //\n    RETURN_IF_FAILED(PhCreateWindowsRuntimeStringRef(ToastXml, &stringToastXmlRef));\n    RETURN_IF_FAILED(xmlIo->LoadXml(HSTRING_FROM_STRING(stringToastXmlRef)));\n\n    ComPtr<IToastNotification> toast;\n    RETURN_IF_FAILED(factory->CreateToastNotification(xmlDocument.Get(), &toast));\n\n    if (TimeoutMilliseconds > 0)\n    {\n        //\n        // We have a timeout, set it.\n        //\n        ComPtr<IPropertyValueStatics> propertyStats;\n        RETURN_IF_FAILED(PH::RoGetActivationFactory<IPropertyValueStatics>(\n            L\"WinTypes.dll\",\n            L\"Windows.Foundation.PropertyValue\",\n            &propertyStats));\n\n        LARGE_INTEGER sysTime;\n        PhQuerySystemTime(&sysTime);\n\n        sysTime.QuadPart += UInt32x32To64(TimeoutMilliseconds, PH_TIMEOUT_MS);\n\n        DateTime time;\n        time.UniversalTime = sysTime.QuadPart;\n\n        ComPtr<IInspectable> inspectable;\n        RETURN_IF_FAILED(propertyStats->CreateDateTime(time, &inspectable));\n\n        ComPtr<IReference<DateTime>> dateTime;\n        RETURN_IF_FAILED(inspectable.As(&dateTime));\n\n        RETURN_IF_FAILED(toast->put_ExpirationTime(dateTime.Get()));\n    }\n\n    if (ToastCallback)\n    {\n        //\n        // We have a timeout callback. Create the handler with the callback\n        // and context, then shove it into the toast notification.\n        //\n        ComPtr<PH::ToastEventHandler> callbacks;\n        ComPtr<PH::IToastActivatedHandler> activatedNotif;\n        ComPtr<PH::IToastDismissedHandler> dismissedNotif;\n        ComPtr<PH::IToastFailedHandler> failedNotif;\n\n        RETURN_IF_FAILED(MakeAndInitialize<PH::ToastEventHandler>(\n            &callbacks,\n            ToastCallback,\n            Context));\n\n        RETURN_IF_FAILED(callbacks.As(&activatedNotif));\n        RETURN_IF_FAILED(callbacks.As(&dismissedNotif));\n        RETURN_IF_FAILED(callbacks.As(&failedNotif));\n\n        EventRegistrationToken token;\n\n        RETURN_IF_FAILED(toast->add_Activated(activatedNotif.Get(), &token));\n        callbacks->SetActivatedToken(token);\n\n        RETURN_IF_FAILED(toast->add_Dismissed(dismissedNotif.Get(), &token));\n        callbacks->SetDismissedToken(token);\n\n        RETURN_IF_FAILED(toast->add_Failed(failedNotif.Get(), &token));\n        callbacks->SetFailedToken(token);\n    }\n\n    m_Notifier = notifier;\n    m_Toast = toast;\n\n    return S_OK;\n}\n\nHRESULT PH::Toast::Show() const\n{\n    if ((m_Notifier == nullptr) || (m_Toast == nullptr))\n    {\n        return E_NOT_VALID_STATE;\n    }\n    return m_Notifier->Show(m_Toast.Get());\n}\n\nHRESULT STDMETHODCALLTYPE PH::ToastEventHandler::Invoke(\n    _In_ IToastNotification* Sender,\n    _In_ IToastDismissedEventArgs* Args\n    )\n{\n    PH_TOAST_REASON phReason = PhToastReasonUnknown;\n    ToastDismissalReason reason;\n    HRESULT result;\n\n    result = Args->get_Reason(&reason);\n\n    if (HR_SUCCESS(result))\n    {\n        switch (reason)\n        {\n        case ToastDismissalReason_UserCanceled:\n            phReason = PhToastReasonUserCanceled;\n            break;\n        case ToastDismissalReason_ApplicationHidden:\n            phReason = PhToastReasonApplicationHidden;\n            break;\n        case ToastDismissalReason_TimedOut:\n            phReason = PhToastReasonTimedOut;\n            break;\n        }\n    }\n\n    m_ToastCallback(result, phReason, m_Context);\n\n    //\n    // Without this the ref is never decremented and the runtime leaks...\n    // We fire to the callback once anyway, so remove the callback from\n    // processing.\n    //\n    Sender->remove_Dismissed(m_DismissedToken);\n    Sender->remove_Activated(m_ActivatedToken);\n    Sender->remove_Failed(m_FailedToken);\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PH::ToastEventHandler::Invoke(\n    _In_ IToastNotification* Sender,\n    _In_ IInspectable* Args\n    )\n{\n    m_ToastCallback(S_OK, PhToastReasonActivated, m_Context);\n\n    //\n    // Without this the ref is never decremented and the runtime leaks...\n    // We fire to the callback once anyway, so remove the callback from\n    // processing.\n    //\n    Sender->remove_Dismissed(m_DismissedToken);\n    Sender->remove_Activated(m_ActivatedToken);\n    Sender->remove_Failed(m_FailedToken);\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PH::ToastEventHandler::Invoke(\n    _In_ IToastNotification* Sender,\n    _In_ IToastFailedEventArgs* Args\n    )\n{\n    HRESULT err;\n    HRESULT hr = Args->get_ErrorCode(&err);\n    if (HR_FAILED(hr))\n    {\n        //\n        // You wut? I doubt this could realistically fail... if so give\n        // the callback this error, I guess...\n        //\n        err = hr;\n    }\n\n    m_ToastCallback(err, PhToastReasonError, m_Context);\n\n    //\n    // Without this the ref is never decremented and the runtime leaks...\n    // We fire to the callback once anyway, so remove the callback from\n    // processing.\n    //\n    Sender->remove_Dismissed(m_DismissedToken);\n    Sender->remove_Activated(m_ActivatedToken);\n    Sender->remove_Failed(m_FailedToken);\n    return S_OK;\n}\n\n/*!\n    @brief Initializes the required functionality for toast notifications.\n\n    @details Each successful call to PhInitializeToastRuntime should be paired with a call to\n     PhUninitializeToastRuntime (including S_FALSE). This function must be called prior to a call\n     to PhShowToast. Generally, this should be called once during start of the process.\n\n    @return Appropriate result status. On success (including S_FALSE) this call must be paired\n     with a call to PhUninitializeToastRuntime.\n*/\n_Must_inspect_result_\nHRESULT PhInitializeToastRuntime()\n{\n//    HRESULT res;\n//\n//    res = g_RoInitialize(RO_INIT_MULTITHREADED);\n//    if (res == RPC_E_CHANGED_MODE)\n//        res = g_RoInitialize(RO_INIT_SINGLETHREADED);\n//    if (res == S_FALSE) // already initialized\n//        res = S_OK;\n//\n//    return res;\n    return S_OK;\n}\n\n/*!\n    @brief This is a wrapper to call RoUninitialize. This should only be called when\n     PhInitializeToastRuntime return a success (including S_FALSE).\n*/\nVOID PhUninitializeToastRuntime()\n{\n    //if (g_RoInitialize)\n    //{\n    //    g_RoUninitialize();\n    //}\n}\n\n/*!\n    @brief Shows a toast notification.\n\n    @details PhInitializeToastRuntime must be called prior. This is an asynchronous operation. If\n     the caller supplies a context and the function returns a success, the context is owned by the\n     toast object, any allocated memory should be freed when the toast callback is invoked. On\n     failure, the caller should free any memory allocated for the toast callback context, callback\n     will not be invoked. Note, if you ToastXml is valid but contains something like an image\n     that can't be located by the runtime this function will still return success, don't write . See comments\n     in PH::Toast::Initialize.\n\n    @code\n            hr = PhShowToast(L\"System Informer\",\n                             L\"<toast>\"\n                             L\"    <visual>\"\n                             L\"       <binding template=\\\"ToastImageAndText02\\\">\"\n                             L\"            <image id=\\\"1\\\" src=\\\".\\\\ToastImage.png\\\" alt=\\\"red graphic\\\"/>\"\n                             L\"            <text id=\\\"1\\\">Example Title</text>\"\n                             L\"            <text id=\\\"2\\\">This is an example toast notification, hello world!</text>\"\n                             L\"        </binding>\"\n                             L\"    </visual>\"\n                             L\"</toast>\",\n                             30 * 1000,\n                             ToastCallback,\n                             NULL);\n    @endcode\n\n    @param[in] ApplicationId - Name for the application showing the toast.\n    @param[in] ToastXml - XAML formatted \\<toast\\> to display.\n    @param[in] TimeoutMilliseconds - Optional, when elapsed the toast is considered timed out. If\n     0 is passed the default system defined timeout for toast notifications is used..\n    @param[in] ToastCallback - Optional, if supplied the toast registers handlers for toast\n     interaction and the callback is invoked with the relevant PH_TOAST_REASON.\n    @param[in] Context - Option, context passed to the toast notification callback.\n\n    @return Appropriate result status. On S_OK the toast is dispatched and the callback\n     will be invoked when the interaction occurs. On failure the callback will not be invoked\n     the caller should free any context.\n*/\n_Must_inspect_result_\nHRESULT PhShowToastStringRef(\n    _In_ PPH_STRINGREF ApplicationId,\n    _In_ PPH_STRINGREF ToastXml,\n    _In_opt_ ULONG TimeoutMilliseconds,\n    _In_opt_ PPH_TOAST_CALLBACK ToastCallback,\n    _In_opt_ PVOID Context\n    )\n{\n    auto toast = std::make_unique<PH::Toast>();\n\n    RETURN_IF_FAILED(toast->Initialize(ApplicationId,\n                                       ToastXml,\n                                       TimeoutMilliseconds,\n                                       ToastCallback,\n                                       Context));\n    return toast->Show();\n}\n\n_Must_inspect_result_\nHRESULT PhShowToast(\n    _In_ PCWSTR ApplicationId,\n    _In_ PCWSTR ToastXml,\n    _In_opt_ ULONG TimeoutMilliseconds,\n    _In_opt_ PPH_TOAST_CALLBACK ToastCallback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_STRINGREF applicationIdStringRef;\n    PH_STRINGREF toastXmlStringRef;\n\n    PhInitializeStringRefLongHint(&applicationIdStringRef, ApplicationId);\n    PhInitializeStringRefLongHint(&toastXmlStringRef, ToastXml);\n\n    return PhShowToastStringRef(&applicationIdStringRef,\n                                &toastXmlStringRef,\n                                TimeoutMilliseconds,\n                                ToastCallback,\n                                Context);\n}\n"
  },
  {
    "path": "SystemInformer/ntobjprp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <kphuser.h>\n#include <ksisup.h>\n#include <hndlinfo.h>\n#include <emenu.h>\n#include <mainwnd.h>\n#include <procprv.h>\n#include <phafd.h>\n\ntypedef struct _COMMON_PAGE_CONTEXT\n{\n    PPH_OPEN_OBJECT OpenObject;\n    PPH_CLOSE_OBJECT CloseObject;\n    PVOID Context;\n} COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT;\n\nHPROPSHEETPAGE PhpCommonCreatePage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context,\n    _In_ PCWSTR Template,\n    _In_ DLGPROC DlgProc\n    );\n\nINT CALLBACK PhpCommonPropPageProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ LPPROPSHEETPAGE ppsp\n    );\n\nINT_PTR CALLBACK PhpEventPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpEventPairPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpSemaphorePageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpTimerPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpAfdSocketPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nHPROPSHEETPAGE PhpCommonCreatePage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context,\n    _In_ PCWSTR Template,\n    _In_ DLGPROC DlgProc\n    )\n{\n    HPROPSHEETPAGE propSheetPageHandle;\n    PROPSHEETPAGE propSheetPage;\n    PCOMMON_PAGE_CONTEXT pageContext;\n\n    pageContext = PhCreateAlloc(sizeof(COMMON_PAGE_CONTEXT));\n    memset(pageContext, 0, sizeof(COMMON_PAGE_CONTEXT));\n    pageContext->OpenObject = OpenObject;\n    pageContext->CloseObject = CloseObject;\n    pageContext->Context = Context;\n\n    memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));\n    propSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propSheetPage.dwFlags = PSP_USECALLBACK;\n    propSheetPage.pszTemplate = Template;\n    propSheetPage.hInstance = NtCurrentImageBase();\n    propSheetPage.pfnDlgProc = DlgProc;\n    propSheetPage.lParam = (LPARAM)pageContext;\n    propSheetPage.pfnCallback = PhpCommonPropPageProc;\n\n    propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);\n    // CreatePropertySheetPage would have sent PSPCB_ADDREF (below),\n    // which would have added a reference.\n    PhDereferenceObject(pageContext);\n\n    return propSheetPageHandle;\n}\n\nINT CALLBACK PhpCommonPropPageProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ LPPROPSHEETPAGE ppsp\n    )\n{\n    PCOMMON_PAGE_CONTEXT pageContext;\n\n    pageContext = (PCOMMON_PAGE_CONTEXT)ppsp->lParam;\n\n    if (uMsg == PSPCB_ADDREF)\n    {\n        PhReferenceObject(pageContext);\n    }\n    else if (uMsg == PSPCB_RELEASE)\n    {\n        PhDereferenceObject(pageContext);\n    }\n\n    return 1;\n}\n\nFORCEINLINE PCOMMON_PAGE_CONTEXT PhpCommonPageHeader(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    return PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 2);\n}\n\nHPROPSHEETPAGE PhCreateEventPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    )\n{\n    return PhpCommonCreatePage(\n        OpenObject,\n        CloseObject,\n        Context,\n        MAKEINTRESOURCE(IDD_OBJEVENT),\n        PhpEventPageProc\n        );\n}\n\nstatic VOID PhpRefreshEventPageInfo(\n    _In_ HWND hwndDlg,\n    _In_ PCOMMON_PAGE_CONTEXT PageContext\n    )\n{\n    HANDLE eventHandle;\n\n    if (NT_SUCCESS(PageContext->OpenObject(\n        &eventHandle,\n        EVENT_QUERY_STATE,\n        PageContext->Context\n        )))\n    {\n        EVENT_BASIC_INFORMATION basicInfo;\n        PWSTR eventType = L\"Unknown\";\n        PWSTR eventState = L\"Unknown\";\n\n        if (NT_SUCCESS(PhGetEventBasicInformation(eventHandle, &basicInfo)))\n        {\n            switch (basicInfo.EventType)\n            {\n            case NotificationEvent:\n                eventType = L\"Notification\";\n                break;\n            case SynchronizationEvent:\n                eventType = L\"Synchronization\";\n                break;\n            }\n\n            eventState = basicInfo.EventState > 0 ? L\"True\" : L\"False\";\n        }\n\n        PhSetDialogItemText(hwndDlg, IDC_TYPE, eventType);\n        PhSetDialogItemText(hwndDlg, IDC_SIGNALED, eventState);\n\n        NtClose(eventHandle);\n    }\n}\n\nINT_PTR CALLBACK PhpEventPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PCOMMON_PAGE_CONTEXT pageContext;\n\n    pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!pageContext)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhpRefreshEventPageInfo(hwndDlg, pageContext);\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_SET:\n            case IDC_RESET:\n            case IDC_PULSE:\n                {\n                    NTSTATUS status;\n                    HANDLE eventHandle;\n\n                    if (NT_SUCCESS(status = pageContext->OpenObject(\n                        &eventHandle,\n                        EVENT_MODIFY_STATE,\n                        pageContext->Context\n                        )))\n                    {\n                        switch (GET_WM_COMMAND_ID(wParam, lParam))\n                        {\n                        case IDC_SET:\n                            NtSetEvent(eventHandle, NULL);\n                            break;\n                        case IDC_RESET:\n                            NtResetEvent(eventHandle, NULL);\n                            break;\n                        case IDC_PULSE:\n                            NtPulseEvent(eventHandle, NULL);\n                            break;\n                        }\n\n                        NtClose(eventHandle);\n                    }\n\n                    PhpRefreshEventPageInfo(hwndDlg, pageContext);\n\n                    if (!NT_SUCCESS(status))\n                        PhShowStatus(hwndDlg, L\"Unable to open the event\", status, 0);\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nHPROPSHEETPAGE PhCreateEventPairPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    )\n{\n    return PhpCommonCreatePage(\n        OpenObject,\n        CloseObject,\n        Context,\n        MAKEINTRESOURCE(IDD_OBJEVENTPAIR),\n        PhpEventPairPageProc\n        );\n}\n\nINT_PTR CALLBACK PhpEventPairPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PCOMMON_PAGE_CONTEXT pageContext;\n\n    pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!pageContext)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            // Nothing\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_SETLOW:\n            case IDC_SETHIGH:\n                {\n                    NTSTATUS status;\n                    HANDLE eventPairHandle;\n\n                    if (NT_SUCCESS(status = pageContext->OpenObject(\n                        &eventPairHandle,\n                        EVENT_PAIR_ALL_ACCESS,\n                        pageContext->Context\n                        )))\n                    {\n                        switch (GET_WM_COMMAND_ID(wParam, lParam))\n                        {\n                        case IDC_SETLOW:\n                            NtSetLowEventPair(eventPairHandle);\n                            break;\n                        case IDC_SETHIGH:\n                            NtSetHighEventPair(eventPairHandle);\n                            break;\n                        }\n\n                        NtClose(eventPairHandle);\n                    }\n\n                    if (!NT_SUCCESS(status))\n                        PhShowStatus(hwndDlg, L\"Unable to open the event pair\", status, 0);\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nHPROPSHEETPAGE PhCreateSemaphorePage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    )\n{\n    return PhpCommonCreatePage(\n        OpenObject,\n        CloseObject,\n        Context,\n        MAKEINTRESOURCE(IDD_OBJSEMAPHORE),\n        PhpSemaphorePageProc\n        );\n}\n\nstatic VOID PhpRefreshSemaphorePageInfo(\n    _In_ HWND hwndDlg,\n    _In_ PCOMMON_PAGE_CONTEXT PageContext\n    )\n{\n    HANDLE semaphoreHandle;\n\n    if (NT_SUCCESS(PageContext->OpenObject(\n        &semaphoreHandle,\n        SEMAPHORE_QUERY_STATE,\n        PageContext->Context\n        )))\n    {\n        SEMAPHORE_BASIC_INFORMATION basicInfo;\n\n        if (NT_SUCCESS(PhGetSemaphoreBasicInformation(semaphoreHandle, &basicInfo)))\n        {\n            PhSetDialogItemValue(hwndDlg, IDC_CURRENTCOUNT, basicInfo.CurrentCount, TRUE);\n            PhSetDialogItemValue(hwndDlg, IDC_MAXIMUMCOUNT, basicInfo.MaximumCount, TRUE);\n        }\n        else\n        {\n            PhSetDialogItemText(hwndDlg, IDC_CURRENTCOUNT, L\"Unknown\");\n            PhSetDialogItemText(hwndDlg, IDC_MAXIMUMCOUNT, L\"Unknown\");\n        }\n\n        NtClose(semaphoreHandle);\n    }\n}\n\nINT_PTR CALLBACK PhpSemaphorePageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PCOMMON_PAGE_CONTEXT pageContext;\n\n    pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!pageContext)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhpRefreshSemaphorePageInfo(hwndDlg, pageContext);\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_ACQUIRE:\n            case IDC_RELEASE:\n                {\n                    NTSTATUS status;\n                    HANDLE semaphoreHandle;\n\n                    if (NT_SUCCESS(status = pageContext->OpenObject(\n                        &semaphoreHandle,\n                        GET_WM_COMMAND_ID(wParam, lParam) == IDC_ACQUIRE ? SYNCHRONIZE : SEMAPHORE_MODIFY_STATE,\n                        pageContext->Context\n                        )))\n                    {\n                        switch (GET_WM_COMMAND_ID(wParam, lParam))\n                        {\n                        case IDC_ACQUIRE:\n                            {\n                                LARGE_INTEGER timeout;\n\n                                timeout.QuadPart = 0;\n                                NtWaitForSingleObject(semaphoreHandle, FALSE, &timeout);\n                            }\n                            break;\n                        case IDC_RELEASE:\n                            NtReleaseSemaphore(semaphoreHandle, 1, NULL);\n                            break;\n                        }\n\n                        NtClose(semaphoreHandle);\n                    }\n\n                    PhpRefreshSemaphorePageInfo(hwndDlg, pageContext);\n\n                    if (!NT_SUCCESS(status))\n                        PhShowStatus(hwndDlg, L\"Unable to open the semaphore\", status, 0);\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nHPROPSHEETPAGE PhCreateTimerPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    )\n{\n    return PhpCommonCreatePage(\n        OpenObject,\n        CloseObject,\n        Context,\n        MAKEINTRESOURCE(IDD_OBJTIMER),\n        PhpTimerPageProc\n        );\n}\n\nstatic VOID PhpRefreshTimerPageInfo(\n    _In_ HWND hwndDlg,\n    _In_ PCOMMON_PAGE_CONTEXT PageContext\n    )\n{\n    HANDLE timerHandle;\n\n    if (NT_SUCCESS(PageContext->OpenObject(\n        &timerHandle,\n        TIMER_QUERY_STATE,\n        PageContext->Context\n        )))\n    {\n        TIMER_BASIC_INFORMATION basicInfo;\n\n        if (NT_SUCCESS(PhGetTimerBasicInformation(timerHandle, &basicInfo)))\n        {\n            PhSetDialogItemText(hwndDlg, IDC_SIGNALED, basicInfo.TimerState ? L\"True\" : L\"False\");\n        }\n        else\n        {\n            PhSetDialogItemText(hwndDlg, IDC_SIGNALED, L\"Unknown\");\n        }\n\n        NtClose(timerHandle);\n    }\n}\n\nINT_PTR CALLBACK PhpTimerPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PCOMMON_PAGE_CONTEXT pageContext;\n\n    pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!pageContext)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhpRefreshTimerPageInfo(hwndDlg, pageContext);\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_CANCEL:\n                {\n                    NTSTATUS status;\n                    HANDLE timerHandle;\n\n                    if (NT_SUCCESS(status = pageContext->OpenObject(\n                        &timerHandle,\n                        TIMER_MODIFY_STATE,\n                        pageContext->Context\n                        )))\n                    {\n                        switch (GET_WM_COMMAND_ID(wParam, lParam))\n                        {\n                        case IDC_CANCEL:\n                            NtCancelTimer(timerHandle, NULL);\n                            break;\n                        }\n\n                        NtClose(timerHandle);\n                    }\n\n                    PhpRefreshTimerPageInfo(hwndDlg, pageContext);\n\n                    if (!NT_SUCCESS(status))\n                        PhShowStatus(hwndDlg, L\"Unable to open the timer\", status, 0);\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\ntypedef struct _MAPPINGS_PAGE_CONTEXT\n{\n    HANDLE ProcessId;\n    HANDLE SectionHandle;\n    DLGPROC HookProc;\n    HWND WindowHandle;\n    HWND ListViewHandle;\n    PKPH_SECTION_MAPPINGS_INFORMATION SectionInfo;\n\n} MAPPINGS_PAGE_CONTEXT, *PMAPPINGS_PAGE_CONTEXT;\n\nVOID PhpEnumerateMappingsEntries(\n    _In_ PMAPPINGS_PAGE_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    CLIENT_ID clientId;\n\n    if (KsiLevel() < KphLevelMed)\n    {\n        PPH_STRING statusText;\n        HWND statusWindow;\n\n        statusWindow = GetDlgItem(Context->WindowHandle, IDC_TEXT);\n        ShowWindow(Context->ListViewHandle, SW_HIDE);\n        ShowWindow(statusWindow, SW_SHOW);\n\n        statusText = PhGetKsiNotConnectedString(\n            L\"Viewing active mappings requires a connection to the kernel driver.\"\n            );\n        PhSetWindowText(statusWindow, PhGetString(statusText));\n        //SendMessage(statusWindow, EM_SETSEL, (WPARAM)-1, (LPARAM)-1);\n        PhSetDialogFocus(GetParent(Context->WindowHandle), GetDlgItem(GetParent(Context->WindowHandle), IDCANCEL));\n        PhDereferenceObject(statusText);\n\n        return;\n    }\n\n    clientId.UniqueProcess = Context->ProcessId;\n    clientId.UniqueThread = NULL;\n\n    status = KphOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, &clientId);\n\n    if (!NT_SUCCESS(status))\n        return;\n\n    status = KphQueryObjectSectionMappingsInfo(\n        processHandle,\n        Context->SectionHandle,\n        &Context->SectionInfo\n        );\n\n    NtClose(processHandle);\n\n    if (!NT_SUCCESS(status))\n        return;\n\n    for (ULONG i = 0; i < Context->SectionInfo->NumberOfMappings; i++)\n    {\n        PKPH_SECTION_MAP_ENTRY info = &Context->SectionInfo->Mappings[i];\n        INT lvItemIndex;\n        WCHAR value[PH_INT64_STR_LEN_1];\n\n        if (info->ViewMapType == VIEW_MAP_TYPE_PROCESS)\n        {\n            PPH_STRING string = NULL;\n\n            clientId.UniqueProcess = info->ProcessId;\n            clientId.UniqueThread = NULL;\n\n            string = PhStdGetClientIdName(&clientId);\n            lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, string->Buffer, info);\n            PhDereferenceObject(string);\n        }\n        else if (info->ViewMapType == VIEW_MAP_TYPE_SESSION)\n        {\n            lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, L\"Session\", info);\n        }\n        else if (info->ViewMapType == VIEW_MAP_TYPE_SYSTEM_CACHE)\n        {\n            lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, L\"System\", info);\n        }\n        else\n        {\n            lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, L\"Unknown\", info);\n        }\n\n        PhPrintPointer(value, info->StartVa);\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, value);\n\n        PhPrintPointer(value, info->EndVa);\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, value);\n\n        PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 3, PhaFormatSize((ULONG64)info->EndVa - (ULONG64)info->StartVa, ULONG_MAX)->Buffer);\n    }\n}\n\nVOID PhpShowProcessForMapping(\n    _In_ HWND hwndDlg,\n    _In_ PKPH_SECTION_MAP_ENTRY Entry\n)\n{\n    PPH_PROCESS_ITEM processItem;\n\n    assert(Entry->ViewMapType == VIEW_MAP_TYPE_PROCESS);\n    if (processItem = PhReferenceProcessItem(Entry->ProcessId))\n    {\n        //\n        // TODO would like this to show the process properties\n        // memory tab and select the info->StartVa\n        //\n        SystemInformer_ShowProcessProperties(processItem);\n        PhDereferenceObject(processItem);\n    }\n    else\n    {\n        PhShowStatus(hwndDlg, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n    }\n}\n\nINT_PTR CALLBACK PhpMappingsPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PMAPPINGS_PAGE_CONTEXT context;\n\n    context = PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 3);\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            PhSetListViewStyle(context->ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 140, L\"View\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 100, L\"Start\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 100, L\"End\");\n            PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_RIGHT, 60, L\"Size\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            PhpEnumerateMappingsEntries(context);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            if (context->SectionInfo)\n                PhFree(context->SectionInfo);\n\n            PhFree(context);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            PKPH_SECTION_MAP_ENTRY info = NULL;\n\n            if (ListView_GetSelectedCount(context->ListViewHandle) == 1)\n                info = PhGetSelectedListViewItemParam(context->ListViewHandle);\n\n            POINT point;\n            PPH_EMENU menu;\n            PPH_EMENU item;\n\n            point.x = GET_X_LPARAM(lParam);\n            point.y = GET_Y_LPARAM(lParam);\n\n            if (point.x == -1 && point.y == -1)\n                PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n            menu = PhCreateEMenu();\n            if (info && info->ViewMapType == VIEW_MAP_TYPE_PROCESS)\n            {\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L\"&Go to process\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n            }\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n            PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n            item = PhShowEMenu(\n                menu,\n                hwndDlg,\n                PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                point.x,\n                point.y\n                );\n\n            if (item && item->Id != ULONG_MAX && !PhHandleCopyListViewEMenuItem(item))\n            {\n                switch (item->Id)\n                {\n                case IDC_COPY:\n                    {\n                        PhCopyListView(context->ListViewHandle);\n                    }\n                    break;\n                case 1:\n                    {\n                        assert(info);\n                        PhpShowProcessForMapping(hwndDlg, info);\n                    }\n                    break;\n                }\n\n                PhDestroyEMenu(menu);\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nHPROPSHEETPAGE PhCreateMappingsPage(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE SectionHandle\n    )\n{\n    HPROPSHEETPAGE propSheetPageHandle;\n    PROPSHEETPAGE propSheetPage;\n    PMAPPINGS_PAGE_CONTEXT mappingsPageContext;\n\n    mappingsPageContext = PhAllocateZero(sizeof(MAPPINGS_PAGE_CONTEXT));\n    mappingsPageContext->ProcessId = ProcessId;\n    mappingsPageContext->SectionHandle = SectionHandle;\n\n    memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));\n    propSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propSheetPage.dwFlags = PSP_DEFAULT;\n    propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJMAPPINGS);\n    propSheetPage.hInstance = NtCurrentImageBase();\n    propSheetPage.pfnDlgProc = PhpMappingsPageProc;\n    propSheetPage.lParam = (LPARAM)mappingsPageContext;\n\n    propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);\n\n    return propSheetPageHandle;\n}\n\ntypedef struct _PHP_AFD_SOCKET_PAGE_CONTEXT\n{\n    HANDLE ProcessId;\n    HANDLE HandleValue;\n    HWND ListViewHandle;\n    PPH_LISTVIEW_CONTEXT ListViewContext;\n    PH_LAYOUT_MANAGER LayoutManager;\n} PHP_AFD_SOCKET_PAGE_CONTEXT, *PPHP_AFD_SOCKET_PAGE_CONTEXT;\n\ntypedef enum _PHP_AFD_SOCKET_GROUP\n{\n    PH_AFD_SOCKET_GROUP_SHARED,\n    PH_AFD_SOCKET_GROUP_ADDRESSES,\n    PH_AFD_SOCKET_GROUP_INFOCLASS,\n    PH_AFD_SOCKET_GROUP_TDI,\n    PH_AFD_SOCKET_GROUP_SO,\n    PH_AFD_SOCKET_GROUP_IP,\n    PH_AFD_SOCKET_GROUP_TCP,\n    PH_AFD_SOCKET_GROUP_TCP_INFO,\n    PH_AFD_SOCKET_GROUP_UDP,\n    PH_AFD_SOCKET_GROUP_HVSOCKET,\n} PHP_AFD_SOCKET_GROUP;\n\ntypedef enum _PHP_AFD_SOCKET_ITEM\n{\n    PH_AFD_SOCKET_ITEM_STATE,\n    PH_AFD_SOCKET_ITEM_TYPE,\n    PH_AFD_SOCKET_ITEM_ADDRESS_FAMILY,\n    PH_AFD_SOCKET_ITEM_PROTOCOL,\n    PH_AFD_SOCKET_ITEM_CATALOG_ENTRY_ID,\n    PH_AFD_SOCKET_ITEM_PROVIDER_ID,\n    PH_AFD_SOCKET_ITEM_PROVIDER_FLAGS,\n    PH_AFD_SOCKET_ITEM_SERVICE_FLAGS,\n    PH_AFD_SOCKET_ITEM_SEND_TIMEOUT,\n    PH_AFD_SOCKET_ITEM_RECEIVE_TIMEOUT,\n    PH_AFD_SOCKET_ITEM_SEND_BUFFER_SIZE,\n    PH_AFD_SOCKET_ITEM_RECEIVE_BUFFER_SIZE,\n    PH_AFD_SOCKET_ITEM_CREATION_FLAGS,\n    PH_AFD_SOCKET_ITEM_FLAGS,\n\n    PH_AFD_SOCKET_ITEM_ADDRESS,\n    PH_AFD_SOCKET_ITEM_REMOTE_ADDRESS,\n\n    PH_AFD_SOCKET_ITEM_CONNECT_TIME,\n    PH_AFD_SOCKET_ITEM_DELIVERY_AVAILABLE,\n    PH_AFD_SOCKET_ITEM_PENDED_RECEIVE_REQUESTS,\n    PH_AFD_SOCKET_ITEM_SENDS_PENDING,\n    PH_AFD_SOCKET_ITEM_RECEIVE_WINDOW_SIZE,\n    PH_AFD_SOCKET_ITEM_SEND_WINDOW_SIZE,\n    PH_AFD_SOCKET_ITEM_MAX_SEND_SIZE,\n    PH_AFD_SOCKET_ITEM_GROUP_ID,\n    PH_AFD_SOCKET_ITEM_GROUP_TYPE,\n\n    PH_AFD_SOCKET_ITEM_TDI_ADDRESS_DEVICE,\n    PH_AFD_SOCKET_ITEM_TDI_CONNECTION_DEVICE,\n\n    PH_AFD_SOCKET_ITEM_SO_REUSEADDR,\n    PH_AFD_SOCKET_ITEM_SO_KEEPALIVE,\n    PH_AFD_SOCKET_ITEM_SO_DONTROUTE,\n    PH_AFD_SOCKET_ITEM_SO_BROADCAST,\n    PH_AFD_SOCKET_ITEM_SO_OOBINLINE,\n    PH_AFD_SOCKET_ITEM_SO_RCVBUF,\n    PH_AFD_SOCKET_ITEM_SO_MAX_MSG_SIZE,\n    PH_AFD_SOCKET_ITEM_SO_CONDITIONAL_ACCEPT,\n    PH_AFD_SOCKET_ITEM_SO_PAUSE_ACCEPT,\n    PH_AFD_SOCKET_ITEM_SO_COMPARTMENT_ID,\n    PH_AFD_SOCKET_ITEM_SO_RANDOMIZE_PORT,\n    PH_AFD_SOCKET_ITEM_SO_PORT_SCALABILITY,\n    PH_AFD_SOCKET_ITEM_SO_REUSE_UNICASTPORT,\n    PH_AFD_SOCKET_ITEM_SO_EXCLUSIVEADDRUSE,\n\n    PH_AFD_SOCKET_ITEM_IP_HDRINCL,\n    PH_AFD_SOCKET_ITEM_IP_TOS,\n    PH_AFD_SOCKET_ITEM_IP_TTL,\n    PH_AFD_SOCKET_ITEM_IP_MULTICAST_IF,\n    PH_AFD_SOCKET_ITEM_IP_MULTICAST_TTL,\n    PH_AFD_SOCKET_ITEM_IP_MULTICAST_LOOP,\n    PH_AFD_SOCKET_ITEM_IP_DONTFRAGMENT,\n    PH_AFD_SOCKET_ITEM_IP_PKTINFO,\n    PH_AFD_SOCKET_ITEM_IP_RECVTTL,\n    PH_AFD_SOCKET_ITEM_IP_RECEIVE_BROADCAST,\n    PH_AFD_SOCKET_ITEM_IP_PROTECTION_LEVEL,\n    PH_AFD_SOCKET_ITEM_IP_RECVIF,\n    PH_AFD_SOCKET_ITEM_IP_RECVDSTADDR,\n    PH_AFD_SOCKET_ITEM_IP_V6ONLY,\n    PH_AFD_SOCKET_ITEM_IP_IFLIST,\n    PH_AFD_SOCKET_ITEM_IP_UNICAST_IF,\n    PH_AFD_SOCKET_ITEM_IP_RECVRTHDR,\n    PH_AFD_SOCKET_ITEM_IP_RECVTOS,\n    PH_AFD_SOCKET_ITEM_IP_ORIGINAL_ARRIVAL_IF,\n    PH_AFD_SOCKET_ITEM_IP_RECVECN,\n    PH_AFD_SOCKET_ITEM_IP_PKTINFO_EX,\n    PH_AFD_SOCKET_ITEM_IP_WFP_REDIRECT_RECORDS,\n    PH_AFD_SOCKET_ITEM_IP_WFP_REDIRECT_CONTEXT,\n    PH_AFD_SOCKET_ITEM_IP_MTU_DISCOVER,\n    PH_AFD_SOCKET_ITEM_IP_MTU,\n    PH_AFD_SOCKET_ITEM_IP_RECVERR,\n    PH_AFD_SOCKET_ITEM_IP_USER_MTU,\n\n    PH_AFD_SOCKET_ITEM_TCP_NODELAY,\n    PH_AFD_SOCKET_ITEM_TCP_EXPEDITED,\n    PH_AFD_SOCKET_ITEM_TCP_KEEPALIVE,\n    PH_AFD_SOCKET_ITEM_TCP_MAXSEG,\n    PH_AFD_SOCKET_ITEM_TCP_MAXRT,\n    PH_AFD_SOCKET_ITEM_TCP_STDURG,\n    PH_AFD_SOCKET_ITEM_TCP_NOURG,\n    PH_AFD_SOCKET_ITEM_TCP_ATMARK,\n    PH_AFD_SOCKET_ITEM_TCP_NOSYNRETRIES,\n    PH_AFD_SOCKET_ITEM_TCP_TIMESTAMPS,\n    PH_AFD_SOCKET_ITEM_TCP_CONGESTION_ALGORITHM,\n    PH_AFD_SOCKET_ITEM_TCP_DELAY_FIN_ACK,\n    PH_AFD_SOCKET_ITEM_TCP_MAXRTMS,\n    PH_AFD_SOCKET_ITEM_TCP_FASTOPEN,\n    PH_AFD_SOCKET_ITEM_TCP_KEEPCNT,\n    PH_AFD_SOCKET_ITEM_TCP_KEEPINTVL,\n    PH_AFD_SOCKET_ITEM_TCP_FAIL_CONNECT_ON_ICMP_ERROR,\n\n    PH_AFD_SOCKET_ITEM_TCP_INFO_STATE,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_MSS,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_CONNECTION_TIME,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_TIMESTAMPS_ENABLED,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_RTT,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_MINRTT,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_IN_FLIGHT,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_WINDOW,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_SEND_WINDOW,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVE_WINDOW,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVE_BUFFER,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_OUT,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_IN,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_REORDERED,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_RETRANSMITTED,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_FAST_RETRANSMIT,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_DUPLICATE_ACKS_IN,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_TIMEOUT_EPISODES,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_SYN_RETRANSMITS,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVER_LIMITED_TRANSITIONS,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVER_LIMITED_TIME,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVER_LIMITED_BYTES,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_LIMITED_TRANSITIONS,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_LIMITED_TIME,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_LIMITED_BYTES,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_SENDER_LIMITED_TRANSITIONS,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_SENDER_LIMITED_TIME,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_SENDER_LIMITED_BYTES,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_OUT_OF_ORDER_PACKETS,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_ECN_NEGOTIATED,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_ECE_ACKS_IN,\n    PH_AFD_SOCKET_ITEM_TCP_INFO_PTO_EPISODES,\n\n    PH_AFD_SOCKET_ITEM_UDP_NOCHECKSUM,\n    PH_AFD_SOCKET_ITEM_UDP_SEND_MSG_SIZE,\n    PH_AFD_SOCKET_ITEM_UDP_RECV_MAX_COALESCED_SIZE,\n\n    PH_AFD_SOCKET_ITEM_HVSOCKET_CONNECT_TIMEOUT,\n    PH_AFD_SOCKET_ITEM_HVSOCKET_CONTAINER_PASSTHRU,\n    PH_AFD_SOCKET_ITEM_HVSOCKET_CONNECTED_SUSPEND,\n    PH_AFD_SOCKET_ITEM_HVSOCKET_HIGH_VTL,\n} PHP_AFD_SOCKET_ITEM;\n\nVOID PhAddSocketListViewItem(\n    _In_ PPHP_AFD_SOCKET_PAGE_CONTEXT Context,\n    _In_ LONG GroupId,\n    _In_ LONG Index,\n    _In_ PCWSTR Text\n    )\n{\n    PhListView_AddGroupItem(Context->ListViewContext, GroupId, Index, Text, UlongToPtr(Index));\n}\n\nVOID PhSetSocketListViewItem(\n    _In_ PPHP_AFD_SOCKET_PAGE_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ PCWSTR Text\n    )\n{\n    LONG index = PhFindListViewItemByParam(Context->ListViewHandle, INT_ERROR, UlongToPtr(Index));\n\n    if (index != INT_ERROR)\n    {\n        PhListView_SetSubItem(Context->ListViewContext, index, 1, Text);\n    }\n}\n\nVOID PhSetSocketListViewItemBoolean(\n    _In_ PPHP_AFD_SOCKET_PAGE_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ ULONG Value\n    )\n{\n    PhSetSocketListViewItem(Context, Index, Value ? L\"True\" : L\"False\");\n}\n\nVOID PhSetSocketListViewItemBytes(\n    _In_ PPHP_AFD_SOCKET_PAGE_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ ULONG64 Value\n    )\n{\n    PPH_STRING itemString;\n\n    itemString = PhFormatSize(Value, -1);\n    PhSetSocketListViewItem(Context, Index, PhGetString(itemString));\n    PhDereferenceObject(itemString);\n}\n\nVOID PhSetSocketListViewItemDecimal(\n    _In_ PPHP_AFD_SOCKET_PAGE_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ ULONG Value\n    )\n{\n    PPH_STRING itemString;\n\n    itemString = PhFormatString(L\"%d\", Value);\n    PhSetSocketListViewItem(Context, Index, PhGetString(itemString));\n    PhDereferenceObject(itemString);\n}\n\nVOID PhSetSocketListViewItemTimeSpan(\n    _In_ PPHP_AFD_SOCKET_PAGE_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ ULONG64 TimeSpan\n    )\n{\n    PPH_STRING itemString;\n\n    if (TimeSpan == 0)\n    {\n        PhSetSocketListViewItem(Context, Index, L\"None\");\n        return;\n    }\n\n    itemString = PhFormatTimeSpanRelative(TimeSpan);\n    PhSetSocketListViewItem(Context, Index, PhGetString(itemString));\n    PhDereferenceObject(itemString);\n}\n\nVOID PhSetSocketListViewItemTimeAgo(\n    _In_ PPHP_AFD_SOCKET_PAGE_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ ULONG64 Duration\n)\n{\n    LARGE_INTEGER absoluteTime;\n    SYSTEMTIME absoluteTimeFields;\n    PPH_STRING absoluteTimeString;\n    PPH_STRING relativeTimeString;\n    PPH_STRING itemString;\n\n    PhQuerySystemTime(&absoluteTime);\n    absoluteTime.QuadPart -= Duration;\n    PhLargeIntegerToLocalSystemTime(&absoluteTimeFields, &absoluteTime);\n\n    relativeTimeString = PhFormatTimeSpanRelative(Duration);\n    absoluteTimeString = PhFormatDateTime(&absoluteTimeFields);\n    itemString = PhFormatString(L\"%s ago (%s)\", PhGetString(relativeTimeString), PhGetString(absoluteTimeString));\n    PhDereferenceObject(relativeTimeString);\n    PhDereferenceObject(absoluteTimeString);\n\n    PhSetSocketListViewItem(Context, Index, PhGetString(itemString));\n    PhDereferenceObject(itemString);\n}\n\nHPROPSHEETPAGE PhCreateAfdSocketPage(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE HandleValue\n    )\n{\n    HPROPSHEETPAGE propSheetPageHandle;\n    PROPSHEETPAGE propSheetPage;\n    PPHP_AFD_SOCKET_PAGE_CONTEXT socketPageContext;\n\n    socketPageContext = PhAllocateZero(sizeof(PHP_AFD_SOCKET_PAGE_CONTEXT));\n    socketPageContext->ProcessId = ProcessId;\n    socketPageContext->HandleValue = HandleValue;\n\n    memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));\n    propSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propSheetPage.dwFlags = PSP_DEFAULT;\n    propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJAFDSOCKET);\n    propSheetPage.hInstance = NtCurrentImageBase();\n    propSheetPage.pfnDlgProc = PhpAfdSocketPageProc;\n    propSheetPage.lParam = (LPARAM)socketPageContext;\n\n    propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);\n\n    return propSheetPageHandle;\n}\n\nstatic VOID PhpRefreshAfdSocketPageInfo(\n    _In_ PPHP_AFD_SOCKET_PAGE_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    HANDLE socketHandle = NULL;\n    PPH_STRING itemString;\n    SOCK_SHARED_INFO sharedInfo;\n    AFD_INFORMATION simpleInfo;\n    ULONG optionValue;\n    TCP_INFO_v2 tcpInfo;\n    ULONG tcpInfoVersion;\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_DUP_HANDLE,\n        Context->ProcessId\n        )))\n    {\n        status = NtDuplicateObject(\n            processHandle,\n            Context->HandleValue,\n            NtCurrentProcess(),\n            &socketHandle,\n            0,\n            0,\n            DUPLICATE_SAME_ACCESS\n            );\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n        return;\n\n    //\n    // Shared Winsock context\n    //\n\n    if (NT_SUCCESS(PhAfdQuerySharedInfo(socketHandle, &sharedInfo)))\n    {\n        // State\n        itemString = PhAfdFormatSocketState(sharedInfo.State);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_STATE, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n\n        // Type\n        itemString = PhAfdFormatSocketType(sharedInfo.SocketType);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_TYPE, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n\n        // Address family\n        itemString = PhAfdFormatAddressFamily(sharedInfo.AddressFamily);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_ADDRESS_FAMILY, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n\n        // Protocol\n        itemString = PhAfdFormatProtocol(sharedInfo.AddressFamily, sharedInfo.Protocol);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_PROTOCOL, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n\n        // Catalog entry ID\n        PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_CATALOG_ENTRY_ID, sharedInfo.CatalogEntryId);\n\n        // Provider ID\n        itemString = PhFormatGuid(&sharedInfo.ProviderId);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_PROVIDER_ID, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n\n        // Provider flags\n        itemString = PhAfdFormatProviderFlags(sharedInfo.ProviderFlags);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_PROVIDER_FLAGS, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n\n        // Service flags\n        itemString = PhAfdFormatServiceFlags(sharedInfo.ServiceFlags1);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_SERVICE_FLAGS, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n\n        // Send timeout\n        switch (sharedInfo.SendTimeout)\n        {\n        case 0:\n            PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_SEND_TIMEOUT, L\"Unlimited\");\n            break;\n        default:\n            PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_SEND_TIMEOUT, PH_TICKS_PER_MS * sharedInfo.SendTimeout);\n        }\n\n        // Receive timeout\n        switch (sharedInfo.ReceiveTimeout)\n        {\n        case 0:\n            PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_RECEIVE_TIMEOUT, L\"Unlimited\");\n            break;\n        default:\n            PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_RECEIVE_TIMEOUT, PH_TICKS_PER_MS * sharedInfo.ReceiveTimeout);\n        }\n\n        // Send buffer size\n        PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_SEND_BUFFER_SIZE, sharedInfo.SendBufferSize);\n\n        // Receive buffer size\n        PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_RECEIVE_BUFFER_SIZE, sharedInfo.ReceiveBufferSize);\n\n        // Creation flags\n        itemString = PhAfdFormatCreationFlags(sharedInfo.CreationFlags);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_CREATION_FLAGS, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n\n        // Flags\n        itemString = PhAfdFormatSharedInfoFlags(&sharedInfo);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_FLAGS, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n    }\n\n    //\n    // Addresses\n    //\n\n    // Address\n    if (NT_SUCCESS(PhAfdQueryFormatAddress(socketHandle, FALSE, &itemString, 0)))\n    {\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_ADDRESS, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n    }\n\n    // Remote address\n    if (NT_SUCCESS(PhAfdQueryFormatAddress(socketHandle, TRUE, &itemString, 0)))\n    {\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_REMOTE_ADDRESS, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n    }\n\n    //\n    // AFD info classes\n    //\n\n    // Connect time\n    if (NT_SUCCESS(PhAfdQuerySimpleInfo(socketHandle, AFD_CONNECT_TIME, &simpleInfo)))\n    {\n        switch (simpleInfo.Information.Ulong)\n        {\n        case ULONG_MAX:\n            PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_CONNECT_TIME, L\"N/A (not connected)\");\n            break;\n        default:\n            PhSetSocketListViewItemTimeAgo(Context, PH_AFD_SOCKET_ITEM_CONNECT_TIME, PH_TICKS_PER_SEC * simpleInfo.Information.Ulong);\n        }\n    }\n\n    if (NT_SUCCESS(PhAfdQuerySimpleInfo(socketHandle, AFD_DELIVERY_STATUS, &simpleInfo)))\n    {\n        // Delivery available\n        PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_DELIVERY_AVAILABLE, simpleInfo.Information.DeliveryStatus.DeliveryAvailable);\n\n        // Pendeding recveives\n        PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_PENDED_RECEIVE_REQUESTS, simpleInfo.Information.DeliveryStatus.PendedReceiveRequests);\n    }\n\n    // Pending sends\n    if (NT_SUCCESS(PhAfdQuerySimpleInfo(socketHandle, AFD_SENDS_PENDING, &simpleInfo)))\n    {\n        PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_SENDS_PENDING, simpleInfo.Information.Ulong);\n    }\n\n    // Receive window size\n    if (NT_SUCCESS(PhAfdQuerySimpleInfo(socketHandle, AFD_RECEIVE_WINDOW_SIZE, &simpleInfo)))\n    {\n        PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_RECEIVE_WINDOW_SIZE, simpleInfo.Information.Ulong);\n    }\n\n    // Send window size\n    if (NT_SUCCESS(PhAfdQuerySimpleInfo(socketHandle, AFD_SEND_WINDOW_SIZE, &simpleInfo)))\n    {\n        PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_SEND_WINDOW_SIZE, simpleInfo.Information.Ulong);\n    }\n\n    // Maximum send size\n    if (NT_SUCCESS(PhAfdQuerySimpleInfo(socketHandle, AFD_MAX_SEND_SIZE, &simpleInfo)))\n    {\n        PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_MAX_SEND_SIZE, simpleInfo.Information.Ulong);\n    }\n\n    if (NT_SUCCESS(PhAfdQuerySimpleInfo(socketHandle, AFD_GROUP_ID_AND_TYPE, &simpleInfo)))\n    {\n        // Group ID\n        PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_GROUP_ID, simpleInfo.Information.GroupInfo.GroupID);\n\n        // Group type\n        itemString = PhAfdFormatGroupType(simpleInfo.Information.GroupInfo.GroupType);\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_GROUP_TYPE, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n    }\n\n    //\n    // TDI devices\n    //\n\n    // TDI address device\n    if (NT_SUCCESS(PhAfdQueryFormatTdiDeviceName(socketHandle, AFD_QUERY_ADDRESS_HANDLE, &itemString)))\n    {\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_TDI_ADDRESS_DEVICE, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n    }\n\n    // TDI connection device\n    if (NT_SUCCESS(PhAfdQueryFormatTdiDeviceName(socketHandle, AFD_QUERY_CONNECTION_HANDLE, &itemString)))\n    {\n        PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_TDI_CONNECTION_DEVICE, PhGetString(itemString));\n        PhDereferenceObject(itemString);\n    }\n\n    // HACK: hvsocket.sys has a bug that makes connected Hyper-V sockets return\n    // STATUS_SUCCESS for all option-querying request. We detect it by issuing a\n    // deliberately invalid query. If it succeeds, we know we've hit the bug and\n    // cannot display any meaningful option information about the socket. (diversenok)\n\n    if (!NT_SUCCESS(PhAfdQueryOption(socketHandle, 0xDEAD, 0xDEAD, &optionValue)))\n    {\n        //\n        // Socket-level options\n        //\n\n        // Reuse address\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_REUSEADDR, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_REUSEADDR, optionValue);\n        }\n\n        // Keep alive\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_KEEPALIVE, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_KEEPALIVE, optionValue);\n        }\n\n        // Don't route\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_DONTROUTE, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_DONTROUTE, optionValue);\n        }\n\n        // Broadcast\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_BROADCAST, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_BROADCAST, optionValue);\n        }\n\n        // OOB in line\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_OOBINLINE, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_OOBINLINE, optionValue);\n        }\n\n        // Receive buffer size\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_RCVBUF, &optionValue)))\n        {\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_SO_RCVBUF, optionValue);\n        }\n\n        // Maximum message size\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_MAX_MSG_SIZE, &optionValue)))\n        {\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_SO_MAX_MSG_SIZE, optionValue);\n        }\n\n        // Conditional accept\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_CONDITIONAL_ACCEPT, optionValue);\n        }\n\n        // Pause accept\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_PAUSE_ACCEPT, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_PAUSE_ACCEPT, optionValue);\n        }\n\n        // Compartment ID\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_COMPARTMENT_ID, &optionValue)))\n        {\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_SO_COMPARTMENT_ID, optionValue);\n        }\n\n        // Randomize port\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_RANDOMIZE_PORT, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_RANDOMIZE_PORT, optionValue);\n        }\n\n        // Port scalability\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_PORT_SCALABILITY, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_PORT_SCALABILITY, optionValue);\n        }\n\n        // Reuse unicast port\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_REUSE_UNICASTPORT, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_REUSE_UNICASTPORT, optionValue);\n        }\n\n        // Exclusive address use\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_SO_EXCLUSIVEADDRUSE, optionValue);\n        }\n\n        //\n        // IP-level options\n        //\n\n        // Header included\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_HDRINCL, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_HDRINCL, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_HDRINCL, optionValue);\n        }\n\n        // Type-of-service\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_TOS, &optionValue)))\n        {\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_IP_TOS, optionValue);\n        }\n\n        // Unicast TTL\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_TTL, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &optionValue)))\n        {\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_IP_TTL, optionValue);\n        }\n\n        // Multicast interface\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_MULTICAST_IF, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_MULTICAST_IF, &optionValue)))\n        {\n            itemString = PhAfdFormatInterfaceOption(optionValue);\n            PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_IP_MULTICAST_IF, PhGetString(itemString));\n            PhDereferenceObject(itemString);\n        }\n\n        // Multicast TTL\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_MULTICAST_TTL, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &optionValue)))\n        {\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_IP_MULTICAST_TTL, optionValue);\n        }\n\n        // Multicast loopback\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_MULTICAST_LOOP, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_MULTICAST_LOOP, optionValue);\n        }\n\n        // Don't fragment\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_DONTFRAGMENT, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_DONTFRAG, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_DONTFRAGMENT, optionValue);\n        }\n\n        // Receive packet info\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_PKTINFO, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_PKTINFO, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_PKTINFO, optionValue);\n        }\n\n        // Receive TTL\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_RECVTTL, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IP_HOPLIMIT, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_RECVTTL, optionValue);\n        }\n\n        // Broadcast reception\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_RECEIVE_BROADCAST, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_RECEIVE_BROADCAST, optionValue);\n        }\n\n        // IPv6 protection level\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &optionValue)))\n        {\n            itemString = PhAfdFormatProtectionLevel(optionValue);\n            PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_IP_PROTECTION_LEVEL, PhGetString(itemString));\n            PhDereferenceObject(itemString);\n        }\n\n        // Receive arrival interface\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_RECVIF, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_RECVIF, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_RECVIF, optionValue);\n        }\n\n        // Receive destination address\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_RECVDSTADDR, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_RECVDSTADDR, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_RECVDSTADDR, optionValue);\n        }\n\n        // IPv6-only\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_V6ONLY, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_V6ONLY, optionValue);\n        }\n\n        // Interface list\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_IFLIST, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_IFLIST, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_IFLIST, optionValue);\n        }\n\n        // Unicast interface\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_UNICAST_IF, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_UNICAST_IF, &optionValue)))\n        {\n            itemString = PhAfdFormatInterfaceOption(optionValue);\n            PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_IP_UNICAST_IF, PhGetString(itemString));\n            PhDereferenceObject(itemString);\n        }\n\n        // Receive routing header\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_RECVRTHDR, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_RECVRTHDR, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_RECVRTHDR, optionValue);\n        }\n\n        // Receive type-of-service\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_RECVTCLASS, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_RECVTCLASS, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_RECVTOS, optionValue);\n        }\n\n        // Original arrival interface\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_ORIGINAL_ARRIVAL_IF, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_ORIGINAL_ARRIVAL_IF, optionValue);\n        }\n\n        // Receive ECN\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_RECVECN, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_RECVECN, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_RECVECN, optionValue);\n        }\n\n        // Receive extended packet info\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_PKTINFO_EX, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_PKTINFO_EX, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_PKTINFO_EX, optionValue);\n        }\n\n        // WFP redirect records\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_WFP_REDIRECT_RECORDS, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_WFP_REDIRECT_RECORDS, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_WFP_REDIRECT_RECORDS, optionValue);\n        }\n\n        // WFP redirect context\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_WFP_REDIRECT_CONTEXT, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_WFP_REDIRECT_CONTEXT, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_WFP_REDIRECT_CONTEXT, optionValue);\n        }\n\n        // MTU discovery\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_MTU_DISCOVER, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &optionValue)))\n        {\n            itemString = PhAfdFormatMtuDiscoveryMode(optionValue);\n            PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_IP_MTU_DISCOVER, PhGetString(itemString));\n            PhDereferenceObject(itemString);\n        }\n\n        // Path MTU\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_MTU, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_MTU, &optionValue)))\n        {\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_IP_MTU, optionValue);\n        }\n\n        // Receive ICMP errors\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_RECVERR, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_RECVERR, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_IP_RECVERR, optionValue);\n        }\n\n        // Upper MTU bound\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IP, IP_USER_MTU, &optionValue)) ||\n            NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_IPV6, IPV6_USER_MTU, &optionValue)))\n        {\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_IP_USER_MTU, optionValue);\n        }\n\n        //\n        // TCP-level options\n        //\n\n        // No delay\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_NODELAY, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_NODELAY, optionValue);\n        }\n\n        // Expedited data\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_EXPEDITED_1122, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_EXPEDITED, optionValue);\n        }\n\n        // Keep alive\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_KEEPALIVE, &optionValue)))\n        {\n            PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_TCP_KEEPALIVE, PH_TICKS_PER_SEC * optionValue);\n        }\n\n        // Maximum segment size\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_MAXSEG, &optionValue)))\n        {\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_MAXSEG, optionValue);\n        }\n\n        // Retry timeout\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_MAXRT, &optionValue)))\n        {\n            switch (optionValue)\n            {\n            case ULONG_MAX:\n                PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_TCP_MAXRT, L\"Unlimited\");\n                break;\n            default:\n                PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_TCP_MAXRT, PH_TICKS_PER_SEC * optionValue);\n            }\n        }\n\n        // URG interpretation\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_STDURG, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_STDURG, optionValue);\n        }\n\n        // No URG\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_NOURG, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_NOURG, optionValue);\n        }\n\n        // At mark\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_ATMARK, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_ATMARK, optionValue);\n        }\n\n        // No SYN retries\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_NOSYNRETRIES, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_NOSYNRETRIES, optionValue);\n        }\n\n        // Timestamps\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_TIMESTAMPS, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_TIMESTAMPS, optionValue);\n        }\n\n        // Congestion algorithm\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_CONGESTION_ALGORITHM, &optionValue)))\n        {\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_CONGESTION_ALGORITHM, optionValue);\n        }\n\n        // Delay FIN ACK\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_DELAY_FIN_ACK, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_DELAY_FIN_ACK, optionValue);\n        }\n\n        // Retry timeout (precise)\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_MAXRTMS, &optionValue)))\n        {\n            switch (optionValue)\n            {\n            case ULONG_MAX:\n                PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_TCP_MAXRTMS, L\"Unlimited\");\n                break;\n            default:\n                PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_TCP_MAXRTMS, PH_TICKS_PER_MS * optionValue);\n            }\n        }\n\n        // Fast open\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_FASTOPEN, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_FASTOPEN, optionValue);\n        }\n\n        // Keep alive count\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_KEEPCNT, &optionValue)))\n        {\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_KEEPCNT, optionValue);\n        }\n\n        // Keep alive interval\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_KEEPINTVL, &optionValue)))\n        {\n            PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_TCP_KEEPINTVL, PH_TICKS_PER_SEC * optionValue);\n        }\n\n        // Fail on ICMP error\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_TCP, TCP_FAIL_CONNECT_ON_ICMP_ERROR, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_FAIL_CONNECT_ON_ICMP_ERROR, optionValue);\n        }\n\n        //\n        // TCP information\n        //\n\n        if (NT_SUCCESS(PhAfdQueryTcpInfo(socketHandle, &tcpInfo, &tcpInfoVersion)))\n        {\n            // TCP state\n            itemString = PhAfdFormatTcpState(tcpInfo.State);\n            PhSetSocketListViewItem(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_STATE, PhGetString(itemString));\n            PhDereferenceObject(itemString);\n\n            // Maximum segment size\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_MSS, tcpInfo.Mss);\n\n            // Connection time\n            PhSetSocketListViewItemTimeAgo(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_CONNECTION_TIME, PH_TICKS_PER_MS * tcpInfo.ConnectionTimeMs);\n\n            // Timestamps enabled\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_TIMESTAMPS_ENABLED, tcpInfo.TimestampsEnabled);\n\n            // Estimated round-trip\n            PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_RTT, RTL_TICKS_PER_MICROSEC * tcpInfo.RttUs);\n\n            // Minimal round-trip\n            PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_MINRTT, RTL_TICKS_PER_MICROSEC * tcpInfo.MinRttUs);\n\n            // Bytes in flight\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_IN_FLIGHT, tcpInfo.BytesInFlight);\n\n            // Congestion window\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_WINDOW, tcpInfo.Cwnd);\n\n            // Send window\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_SEND_WINDOW, tcpInfo.SndWnd);\n\n            // Receive window\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVE_WINDOW, tcpInfo.RcvWnd);\n\n            // Receive buffer\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVE_BUFFER, tcpInfo.RcvBuf);\n\n            // Bytes sent\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_OUT, tcpInfo.BytesOut);\n\n            // Bytes received\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_IN, tcpInfo.BytesIn);\n\n            // Bytes reordered\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_REORDERED, tcpInfo.BytesReordered);\n\n            // Bytes retransmitted\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_RETRANSMITTED, tcpInfo.BytesRetrans);\n\n            // Fast retransmits\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_FAST_RETRANSMIT, tcpInfo.FastRetrans);\n\n            // Duplicate ACKs\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_DUPLICATE_ACKS_IN, tcpInfo.DupAcksIn);\n\n            // Timeout episodes\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_TIMEOUT_EPISODES, tcpInfo.TimeoutEpisodes);\n\n            // SYN retransmits\n            PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_SYN_RETRANSMITS, tcpInfo.SynRetrans);\n\n            if (tcpInfoVersion >= 1)\n            {\n                // Receiver-limited episodes\n                PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVER_LIMITED_TRANSITIONS, tcpInfo.SndLimTransRwin);\n\n                // Receiver-limited time\n                PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVER_LIMITED_TIME, PH_TICKS_PER_MS * tcpInfo.SndLimTimeRwin);\n\n                // Receiver-limited bytes\n                PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVER_LIMITED_BYTES, tcpInfo.SndLimBytesRwin);\n\n                // Congestion-limited episodes\n                PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_LIMITED_TRANSITIONS, tcpInfo.SndLimTransCwnd);\n\n                // Congestion-limited time\n                PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_LIMITED_TIME, PH_TICKS_PER_MS * tcpInfo.SndLimTimeCwnd);\n\n                // Congestion-limited bytes\n                PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_LIMITED_BYTES, tcpInfo.SndLimBytesCwnd);\n\n                // Sender-limited episodes\n                PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_SENDER_LIMITED_TRANSITIONS, tcpInfo.SndLimTransSnd);\n\n                // Sender-limited time\n                PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_SENDER_LIMITED_TIME, PH_TICKS_PER_MS * tcpInfo.SndLimTimeSnd);\n\n                // Sender-limited bytes\n                PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_SENDER_LIMITED_BYTES, tcpInfo.SndLimBytesSnd);\n            }\n\n            if (tcpInfoVersion >= 2)\n            {\n                // Out-of-order packets\n                PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_OUT_OF_ORDER_PACKETS, tcpInfo.OutOfOrderPktsIn);\n\n                // ECN negotiated\n                PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_ECN_NEGOTIATED, tcpInfo.EcnNegotiated);\n\n                // ECE ACKs\n                PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_ECE_ACKS_IN, tcpInfo.EceAcksIn);\n\n                // Probe timeout episodes\n                PhSetSocketListViewItemDecimal(Context, PH_AFD_SOCKET_ITEM_TCP_INFO_PTO_EPISODES, tcpInfo.PtoEpisodes);\n            }\n        }\n\n        //\n        // UDP-level options\n        //\n\n        // No checksum\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_UDP, UDP_NOCHECKSUM, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_UDP_NOCHECKSUM, optionValue);\n        }\n\n        // Maximum message size\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_UDP, UDP_SEND_MSG_SIZE, &optionValue)))\n        {\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_UDP_SEND_MSG_SIZE, optionValue);\n        }\n\n        // Maximum coalesced size\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, IPPROTO_UDP, UDP_RECV_MAX_COALESCED_SIZE, &optionValue)))\n        {\n            PhSetSocketListViewItemBytes(Context, PH_AFD_SOCKET_ITEM_UDP_RECV_MAX_COALESCED_SIZE, optionValue);\n        }\n\n        //\n        // Hyper-V-level options\n        //\n\n        // Connect timeout\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, HV_PROTOCOL_RAW, HVSOCKET_CONNECT_TIMEOUT, &optionValue)))\n        {\n            PhSetSocketListViewItemTimeSpan(Context, PH_AFD_SOCKET_ITEM_HVSOCKET_CONNECT_TIMEOUT, PH_TICKS_PER_MS * optionValue);\n        }\n\n        // Container passthru\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, HV_PROTOCOL_RAW, HVSOCKET_CONTAINER_PASSTHRU, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_HVSOCKET_CONTAINER_PASSTHRU, optionValue);\n        }\n\n        // Connected suspend\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, HV_PROTOCOL_RAW, HVSOCKET_CONNECTED_SUSPEND, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_HVSOCKET_CONNECTED_SUSPEND, optionValue);\n        }\n\n        // High VTL\n        if (NT_SUCCESS(PhAfdQueryOption(socketHandle, HV_PROTOCOL_RAW, HVSOCKET_HIGH_VTL, &optionValue)))\n        {\n            PhSetSocketListViewItemBoolean(Context, PH_AFD_SOCKET_ITEM_HVSOCKET_HIGH_VTL, optionValue);\n        }\n    }\n\n    NtClose(socketHandle);\n}\n\nINT_PTR CALLBACK PhpAfdSocketPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_AFD_SOCKET_PAGE_CONTEXT context;\n\n    context = PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 4);\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            context->ListViewContext = PhListView_Initialize(context->ListViewHandle);\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhSetExtendedListView(context->ListViewHandle);\n            PhListView_AddColumn(context->ListViewContext, 0, 0, 0, LVCFMT_LEFT, 145, L\"Name\");\n            PhListView_AddColumn(context->ListViewContext, 1, 1, 1, LVCFMT_LEFT, 225, L\"Value\");\n            PhListView_EnableGroupView(context->ListViewContext, TRUE);\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_SHARED, L\"Shared Winsock context\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_STATE, L\"Socket state\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_TYPE, L\"Socket type\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_ADDRESS_FAMILY, L\"Address family\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_PROTOCOL, L\"Protocol\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_CATALOG_ENTRY_ID, L\"Catalog entry ID\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_PROVIDER_ID, L\"Provider ID\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_PROVIDER_FLAGS, L\"Provider flags\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_SERVICE_FLAGS, L\"Service flags\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_SEND_TIMEOUT, L\"Send timeout\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_RECEIVE_TIMEOUT, L\"Receive timeout\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_SEND_BUFFER_SIZE, L\"Send buffer size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_RECEIVE_BUFFER_SIZE, L\"Receive buffer size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_CREATION_FLAGS, L\"Creation flags\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SHARED, PH_AFD_SOCKET_ITEM_FLAGS, L\"Flags\");\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_ADDRESSES, L\"Addresses\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_ADDRESSES, PH_AFD_SOCKET_ITEM_ADDRESS, L\"Local address\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_ADDRESSES, PH_AFD_SOCKET_ITEM_REMOTE_ADDRESS, L\"Remote address\");\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_INFOCLASS, L\"AFD info classes\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_INFOCLASS, PH_AFD_SOCKET_ITEM_CONNECT_TIME, L\"Connect time\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_INFOCLASS, PH_AFD_SOCKET_ITEM_DELIVERY_AVAILABLE, L\"Delivery available\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_INFOCLASS, PH_AFD_SOCKET_ITEM_PENDED_RECEIVE_REQUESTS, L\"Pending receive requests\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_INFOCLASS, PH_AFD_SOCKET_ITEM_SENDS_PENDING, L\"Pending sends\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_INFOCLASS, PH_AFD_SOCKET_ITEM_RECEIVE_WINDOW_SIZE, L\"Receive window size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_INFOCLASS, PH_AFD_SOCKET_ITEM_SEND_WINDOW_SIZE, L\"Send window size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_INFOCLASS, PH_AFD_SOCKET_ITEM_MAX_SEND_SIZE, L\"Maximum send size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_INFOCLASS, PH_AFD_SOCKET_ITEM_GROUP_ID, L\"Group ID\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_INFOCLASS, PH_AFD_SOCKET_ITEM_GROUP_TYPE, L\"Group type\");\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_TDI, L\"TDI devices\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TDI, PH_AFD_SOCKET_ITEM_TDI_ADDRESS_DEVICE, L\"TDI address device\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TDI, PH_AFD_SOCKET_ITEM_TDI_CONNECTION_DEVICE, L\"TDI connection device\");\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_SO, L\"Socket-level options\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_REUSEADDR, L\"Reuse address\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_KEEPALIVE, L\"Keep alive\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_DONTROUTE, L\"Don't route\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_BROADCAST, L\"Broadcast\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_OOBINLINE, L\"OOB in line\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_RCVBUF, L\"Receive buffer size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_MAX_MSG_SIZE, L\"Maximum message size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_PAUSE_ACCEPT, L\"Pause accept\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_COMPARTMENT_ID, L\"Compartment ID\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_RANDOMIZE_PORT, L\"Randomize port\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_PORT_SCALABILITY, L\"Port scalability\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_REUSE_UNICASTPORT, L\"Reuse unicast port\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_SO, PH_AFD_SOCKET_ITEM_SO_EXCLUSIVEADDRUSE, L\"Exclusive address use\");\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_IP, L\"IP-level options\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_HDRINCL, L\"Header included\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_TOS, L\"Type-of-service\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_TTL, L\"Unicast TTL\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_MULTICAST_IF, L\"Multicast interface\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_MULTICAST_TTL, L\"Multicast TTL\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_MULTICAST_LOOP, L\"Multicast loopback\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_DONTFRAGMENT, L\"Don't fragment\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_PKTINFO, L\"Receive packet info\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_RECVTTL, L\"Receive TTL\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_RECEIVE_BROADCAST, L\"Broadcast reception\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_PROTECTION_LEVEL, L\"IPv6 protection level\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_RECVIF, L\"Receive arrival interface\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_RECVDSTADDR, L\"Receive dest. address\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_V6ONLY, L\"IPv6-only\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_IFLIST, L\"Interface list\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_UNICAST_IF, L\"Unicast interface\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_RECVRTHDR, L\"Receive routing header\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_RECVTOS, L\"Receive type-of-service\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_ORIGINAL_ARRIVAL_IF, L\"Original arrival interface\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_RECVECN, L\"Receive ECN\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_PKTINFO_EX, L\"Recveive ext. packet info\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_WFP_REDIRECT_RECORDS, L\"WFP redirect records\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_WFP_REDIRECT_CONTEXT, L\"WFP redirect context\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_MTU_DISCOVER, L\"MTU discovery\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_MTU, L\"Path MTU\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_RECVERR, L\"Receive ICMP errors\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_IP, PH_AFD_SOCKET_ITEM_IP_USER_MTU, L\"Upper MTU bound\");\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_TCP, L\"TCP-level options\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_NODELAY, L\"No delay\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_EXPEDITED, L\"Expedited data\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_KEEPALIVE, L\"Keep alive\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_MAXSEG, L\"Maximum segment size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_MAXRT, L\"Retry timeout\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_STDURG, L\"URG interpretation\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_NOURG, L\"No URG\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_ATMARK, L\"At mark\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_NOSYNRETRIES, L\"No SYN retries\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_TIMESTAMPS, L\"Timestamps\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_CONGESTION_ALGORITHM, L\"Congestion algorithm\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_DELAY_FIN_ACK, L\"Delay FIN ACK\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_MAXRTMS, L\"Retry timeout (precise)\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_FASTOPEN, L\"Fast open\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_KEEPCNT, L\"Keep alive count\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_KEEPINTVL, L\"Keep alive interval\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP, PH_AFD_SOCKET_ITEM_TCP_FAIL_CONNECT_ON_ICMP_ERROR, L\"Fail on ICMP error\");\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_TCP_INFO, L\"TCP information\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_STATE, L\"TCP state\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_MSS, L\"Maximum segment size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_CONNECTION_TIME, L\"Connection time\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_TIMESTAMPS_ENABLED, L\"Timestamps enabled\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_RTT, L\"Estimated round-trip\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_MINRTT, L\"Minimal round-trip\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_IN_FLIGHT, L\"Bytes in flight\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_WINDOW, L\"Congestion window\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_SEND_WINDOW, L\"Send window\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVE_WINDOW, L\"Receive window\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVE_BUFFER, L\"Receive buffer\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_OUT, L\"Bytes sent\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_IN, L\"Bytes received\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_REORDERED, L\"Bytes reordered\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_BYTES_RETRANSMITTED, L\"Bytes retransmitted\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_FAST_RETRANSMIT, L\"Fast retransmits\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_DUPLICATE_ACKS_IN, L\"Duplicate ACKs\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_TIMEOUT_EPISODES, L\"Timeout episodes\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_SYN_RETRANSMITS, L\"SYN retransmits\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVER_LIMITED_TRANSITIONS, L\"Receiver-limited episodes\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVER_LIMITED_TIME, L\"Receiver-limited time\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_RECEIVER_LIMITED_BYTES, L\"Receiver-limited bytes\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_LIMITED_TRANSITIONS, L\"Congestion-limited episodes\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_LIMITED_TIME, L\"Congestion-limited time\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_CONGESTION_LIMITED_BYTES, L\"Congestion-limited bytes\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_SENDER_LIMITED_TRANSITIONS, L\"Sender-limited episodes\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_SENDER_LIMITED_TIME, L\"Sender-limited time\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_SENDER_LIMITED_BYTES, L\"Sender-limited bytes\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_OUT_OF_ORDER_PACKETS, L\"Out-of-order packets\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_ECN_NEGOTIATED, L\"ECN negotiated\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_ECE_ACKS_IN, L\"ECE ACKs\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_TCP_INFO, PH_AFD_SOCKET_ITEM_TCP_INFO_PTO_EPISODES, L\"Probe timeout episodes\");\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_UDP, L\"UDP-level options\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_UDP, PH_AFD_SOCKET_ITEM_UDP_NOCHECKSUM, L\"No checksum\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_UDP, PH_AFD_SOCKET_ITEM_UDP_SEND_MSG_SIZE, L\"Maximum message size\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_UDP, PH_AFD_SOCKET_ITEM_UDP_RECV_MAX_COALESCED_SIZE, L\"Maximum coalesced size\");\n\n            PhListView_AddGroup(context->ListViewContext, PH_AFD_SOCKET_GROUP_HVSOCKET, L\"Hyper-V-level options\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_HVSOCKET, PH_AFD_SOCKET_ITEM_HVSOCKET_CONNECT_TIMEOUT, L\"Connect timeout\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_HVSOCKET, PH_AFD_SOCKET_ITEM_HVSOCKET_CONTAINER_PASSTHRU, L\"Container passthru\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_HVSOCKET, PH_AFD_SOCKET_ITEM_HVSOCKET_CONNECTED_SUSPEND, L\"Connected suspend\");\n            PhAddSocketListViewItem(context, PH_AFD_SOCKET_GROUP_HVSOCKET, PH_AFD_SOCKET_ITEM_HVSOCKET_HIGH_VTL, L\"High VTL\");\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n\n            PhpRefreshAfdSocketPageInfo(context);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDeleteLayoutManager(&context->LayoutManager);\n            PhListView_Destroy(context->ListViewContext);\n\n            PhFree(context);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n            ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID *listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        if (!PhHandleCopyListViewEMenuItem(item))\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                PhCopyListView(context->ListViewHandle);\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/options.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n\n#include <commdlg.h>\n#include <colmgr.h>\n#include <colorbox.h>\n#include <cpysave.h>\n#include <settings.h>\n#include <emenu.h>\n\n#include <mainwnd.h>\n#include <notifico.h>\n#include <proctree.h>\n#include <phplug.h>\n#include <phsettings.h>\n\n#define WM_PH_CHILD_EXIT (WM_APP + 301)\n\nINT_PTR CALLBACK PhpOptionsGeneralDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpOptionsAdvancedDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpOptionsHighlightingDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpOptionsGraphsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhOptionsDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhOptionsDestroySection(\n    _In_ PPH_OPTIONS_SECTION Section\n    );\n\n_Function_class_(PH_OPTIONS_ENTER_SECTION_VIEW)\nVOID PhOptionsEnterSectionView(\n    _In_ PPH_OPTIONS_SECTION NewSection\n    );\n\nVOID PhOptionsLayoutSectionView(\n    VOID\n    );\n\nVOID PhOptionsEnterSectionViewInner(\n    _In_ PPH_OPTIONS_SECTION Section,\n    _Inout_ HDWP *ContainerDeferHandle\n    );\n\nVOID PhOptionsCreateSectionDialog(\n    _In_ PPH_OPTIONS_SECTION Section\n    );\n\n_Function_class_(PH_OPTIONS_FIND_SECTION)\nPPH_OPTIONS_SECTION PhOptionsFindSection(\n    _In_ PCPH_STRINGREF Name\n    );\n\nVOID PhOptionsOnSize(\n    VOID\n    );\n\n_Function_class_(PH_OPTIONS_CREATE_SECTION)\nPPH_OPTIONS_SECTION PhOptionsCreateSection(\n    _In_ PCWSTR Name,\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_ DLGPROC DialogProc,\n    _In_opt_ PVOID Parameter\n    );\n\nPPH_OPTIONS_SECTION PhOptionsCreateSectionAdvanced(\n    _In_ PCWSTR Name,\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_ DLGPROC DialogProc,\n    _In_opt_ PVOID Parameter\n    );\n\nBOOLEAN PhpIsDefaultTaskManager(\n    VOID\n    );\n\nVOID PhpSetDefaultTaskManager(\n    _In_ HWND ParentWindowHandle\n    );\n\nstatic HWND PhOptionsWindowHandle = NULL;\nstatic PH_LAYOUT_MANAGER WindowLayoutManager;\n\nstatic PPH_LIST SectionList = NULL;\nstatic PPH_OPTIONS_SECTION CurrentSection = NULL;\nstatic HWND OptionsTreeControl = NULL;\nstatic HWND ContainerControl = NULL;\n\n// All\nstatic BOOLEAN RestartRequired = FALSE;\n\n// General\nstatic BOOLEAN GeneralListViewStateInitializing = FALSE;\nstatic CONST PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\");\nstatic BOOLEAN CurrentUserRunPresent = FALSE;\nstatic HFONT CurrentFontInstance = NULL;\nstatic HFONT CurrentFontMonospaceInstance = NULL;\nstatic PPH_STRING NewFontSelection = NULL;\nstatic PPH_STRING NewFontMonospaceSelection = NULL;\n\n// Advanced\nstatic CONST PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Image File Execution Options\\\\taskmgr.exe\");\nstatic PPH_STRING OldTaskMgrDebugger = NULL;\nstatic HWND WindowHandleForElevate = NULL;\n\n// Highlighting\nstatic HWND HighlightingListViewHandle = NULL;\n\nVOID PhShowOptionsDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    if (PhStartupParameters.ShowOptions)\n    {\n        PhpSetDefaultTaskManager(ParentWindowHandle);\n    }\n    else\n    {\n        if (!PhOptionsWindowHandle)\n        {\n            PhOptionsWindowHandle = PhCreateDialog(\n                PhInstanceHandle,\n                MAKEINTRESOURCE(IDD_OPTIONS),\n                NULL,\n                PhOptionsDialogProc,\n                NULL\n                );\n\n            PhRegisterDialog(PhOptionsWindowHandle);\n            ShowWindow(PhOptionsWindowHandle, SW_SHOW);\n        }\n\n        if (IsMinimized(PhOptionsWindowHandle))\n            ShowWindow(PhOptionsWindowHandle, SW_RESTORE);\n        else\n            SetForegroundWindow(PhOptionsWindowHandle);\n    }\n}\n\nstatic HTREEITEM PhpTreeViewInsertItem(\n    _In_opt_ HTREEITEM HandleInsertAfter,\n    _In_ PCWSTR Text,\n    _In_ PVOID Context\n    )\n{\n    TV_INSERTSTRUCT insert;\n\n    memset(&insert, 0, sizeof(TV_INSERTSTRUCT));\n\n    insert.hParent = TVI_ROOT;\n    insert.hInsertAfter = HandleInsertAfter;\n    insert.item.mask = TVIF_TEXT | TVIF_PARAM;\n    insert.item.pszText = (PWSTR)Text;\n    insert.item.lParam = (LPARAM)Context;\n\n    return TreeView_InsertItem(OptionsTreeControl, &insert);\n}\n\nstatic VOID PhpOptionsShowHideTreeViewItem(\n    _In_ BOOLEAN Hide\n    )\n{\n    static CONST PH_STRINGREF generalName = PH_STRINGREF_INIT(L\"General\");\n    static CONST PH_STRINGREF advancedName = PH_STRINGREF_INIT(L\"Advanced\");\n\n    if (Hide)\n    {\n        PPH_OPTIONS_SECTION advancedSection;\n\n        if (advancedSection = PhOptionsFindSection(&advancedName))\n        {\n            if (advancedSection->TreeItemHandle)\n            {\n                TreeView_DeleteItem(OptionsTreeControl, advancedSection->TreeItemHandle);\n                advancedSection->TreeItemHandle = NULL;\n            }\n        }\n    }\n    else\n    {\n        PPH_OPTIONS_SECTION generalSection;\n        PPH_OPTIONS_SECTION advancedSection;\n\n        generalSection = PhOptionsFindSection(&generalName);\n        advancedSection = PhOptionsFindSection(&advancedName);\n\n        if (generalSection && advancedSection && !advancedSection->TreeItemHandle)\n        {\n            advancedSection->TreeItemHandle = PhpTreeViewInsertItem(\n                generalSection->TreeItemHandle,\n                advancedName.Buffer,\n                advancedSection\n                );\n        }\n    }\n}\n\nVOID PhpAdvancedPageSave(\n    _In_ HWND hwndDlg\n    );\n\nVOID PhpAdvancedPageLoad(\n    _In_ HWND hwndDlg,\n    _In_ BOOLEAN ReloadOnly\n    );\n\nstatic VOID PhReloadGeneralSection(\n    VOID\n    )\n{\n    static PH_STRINGREF generalName = PH_STRINGREF_INIT(L\"General\");\n\n    GeneralListViewStateInitializing = TRUE;\n    PhpAdvancedPageLoad(PhOptionsFindSection(&generalName)->DialogHandle, TRUE);\n    GeneralListViewStateInitializing = FALSE;\n}\n\nstatic VOID PhpOptionsSetImageList(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN Treeview\n    )\n{\n    HIMAGELIST imageListHandle;\n    LONG dpiValue = PhGetWindowDpi(WindowHandle);\n\n    if (Treeview)\n        imageListHandle = TreeView_GetImageList(WindowHandle, TVSIL_NORMAL);\n    else\n        imageListHandle = ListView_GetImageList(WindowHandle, LVSIL_SMALL);\n\n    if (imageListHandle)\n    {\n        PhImageListSetIconSize(imageListHandle, 2, PhGetDpi(24, dpiValue));\n\n        if (Treeview)\n            TreeView_SetImageList(WindowHandle, imageListHandle, TVSIL_NORMAL);\n        else\n            ListView_SetImageList(WindowHandle, imageListHandle, LVSIL_SMALL);\n    }\n    else\n    {\n        if (imageListHandle = PhImageListCreate(2, PhGetDpi(24, dpiValue), ILC_MASK | ILC_COLOR32, 1, 1))\n        {\n            if (Treeview)\n                TreeView_SetImageList(WindowHandle, imageListHandle, TVSIL_NORMAL);\n            else\n                ListView_SetImageList(WindowHandle, imageListHandle, LVSIL_SMALL);\n        }\n    }\n}\n\nINT_PTR CALLBACK PhOptionsDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            OptionsTreeControl = GetDlgItem(hwndDlg, IDC_SECTIONTREE);\n            ContainerControl = GetDlgItem(hwndDlg, IDD_CONTAINER);\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhpOptionsSetImageList(OptionsTreeControl, TRUE);\n\n            //PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_SEPARATOR), SS_OWNERDRAW, SS_OWNERDRAW);\n            PhSetControlTheme(OptionsTreeControl, L\"explorer\");\n            TreeView_SetExtendedStyle(OptionsTreeControl, TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER);\n            TreeView_SetBkColor(OptionsTreeControl, GetSysColor(COLOR_3DFACE));\n\n            PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg);\n            PhAddLayoutItem(&WindowLayoutManager, OptionsTreeControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM);\n            //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SEPARATOR), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, ContainerControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_RESET), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_CLEANUP), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL);\n\n            if (PhEnableThemeSupport) // TODO: fix options dialog theme (dmex)\n                PhInitializeWindowTheme(hwndDlg, TRUE);\n\n            {\n                PPH_OPTIONS_SECTION section;\n\n                SectionList = PhCreateList(8);\n                CurrentSection = NULL;\n\n                section = PhOptionsCreateSection(L\"General\", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGENERAL), PhpOptionsGeneralDlgProc, NULL);\n                PhOptionsCreateSectionAdvanced(L\"Advanced\", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL);\n                PhOptionsCreateSection(L\"Highlighting\", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING), PhpOptionsHighlightingDlgProc, NULL);\n                PhOptionsCreateSection(L\"Graphs\", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGRAPHS), PhpOptionsGraphsDlgProc, NULL);\n                PhOptionsCreateSection(L\"Plugins\", PhInstanceHandle, MAKEINTRESOURCE(IDD_PLUGINS), PhPluginsDlgProc, NULL);\n\n                if (PhPluginsEnabled)\n                {\n                    PH_PLUGIN_OPTIONS_POINTERS pointers;\n\n                    pointers.WindowHandle = hwndDlg;\n                    pointers.CreateSection = PhOptionsCreateSection;\n                    pointers.FindSection = PhOptionsFindSection;\n                    pointers.EnterSectionView = PhOptionsEnterSectionView;\n\n                    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), &pointers);\n                }\n\n                TreeView_SelectItem(OptionsTreeControl, section->TreeItemHandle);\n                SetFocus(OptionsTreeControl);\n                //PhOptionsEnterSectionView(section);\n                PhOptionsOnSize();\n            }\n\n            if (PhValidWindowPlacementFromSetting(SETTING_OPTIONS_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_OPTIONS_WINDOW_POSITION, SETTING_OPTIONS_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, PhMainWndHandle);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            ULONG i;\n            PPH_OPTIONS_SECTION section;\n\n            PhSaveWindowPlacementToSetting(SETTING_OPTIONS_WINDOW_POSITION, SETTING_OPTIONS_WINDOW_SIZE, hwndDlg);\n\n            PhDeleteLayoutManager(&WindowLayoutManager);\n\n            for (i = 0; i < SectionList->Count; i++)\n            {\n                section = SectionList->Items[i];\n\n                if (PhEqualStringRef2(&section->Name, L\"General\", TRUE))\n                {\n                    PhpAdvancedPageSave(section->DialogHandle);\n                }\n\n                PhOptionsDestroySection(section);\n            }\n\n            PhDereferenceObject(SectionList);\n            SectionList = NULL;\n\n            PhUnregisterWindowCallback(hwndDlg);\n\n            PhUnregisterDialog(PhOptionsWindowHandle);\n            PhOptionsWindowHandle = NULL;\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhpOptionsSetImageList(OptionsTreeControl, TRUE);\n            PhLayoutManagerUpdate(&WindowLayoutManager, LOWORD(wParam));\n            PhOptionsOnSize();\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhOptionsOnSize();\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                {\n                    DestroyWindow(hwndDlg);\n                }\n                break;\n            case IDC_RESET:\n                {\n                    if (PhShowMessage2(\n                        hwndDlg,\n                        TD_YES_BUTTON | TD_NO_BUTTON,\n                        TD_WARNING_ICON,\n                        L\"Do you want to reset all settings and restart System Informer?\",\n                        L\"\"\n                        ) == IDYES)\n                    {\n                        SystemInformer_PrepareForEarlyShutdown();\n\n                        PhResetSettings(PhMainWndHandle);\n                        PhSaveSettings2(PhSettingsFileName);\n\n                        if (NT_SUCCESS(PhShellProcessHacker(\n                            PhMainWndHandle,\n                            L\"-v -newinstance\",\n                            SW_SHOW,\n                            PH_SHELL_EXECUTE_DEFAULT,\n                            PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY,\n                            0,\n                            NULL\n                            )))\n                        {\n                            SystemInformer_Destroy();\n                        }\n                        else\n                        {\n                            SystemInformer_CancelEarlyShutdown();\n                        }\n                    }\n                }\n                break;\n            case IDC_CLEANUP:\n                {\n                    if (PhShowMessage2(\n                        hwndDlg,\n                        TD_YES_BUTTON | TD_NO_BUTTON,\n                        TD_INFORMATION_ICON,\n                        L\"Do you want to clean up unused settings?\",\n                        L\"\"\n                        ) == IDYES)\n                    {\n                        PhClearIgnoredSettings();\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DRAWITEM:\n        {\n            PDRAWITEMSTRUCT drawInfo = (PDRAWITEMSTRUCT)lParam;\n\n            //if (drawInfo->CtlID == IDC_SEPARATOR)\n            //{\n            //    RECT rect;\n            //\n            //    rect = drawInfo->rcItem;\n            //    rect.right = 2;\n            //\n            //    if (PhEnableThemeSupport)\n            //    {\n            //        switch (PhCsGraphColorMode)\n            //        {\n            //        case 0: // New colors\n            //            {\n            //                FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT));\n            //                rect.left += 1;\n            //                FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DSHADOW));\n            //            }\n            //            break;\n            //        case 1: // Old colors\n            //            {\n            //                SetDCBrushColor(drawInfo->hDC, RGB(0, 0, 0));\n            //                FillRect(drawInfo->hDC, &rect, PhGetStockBrush(DC_BRUSH));\n            //            }\n            //            break;\n            //        }\n            //    }\n            //    else\n            //    {\n            //        FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT));\n            //        rect.left += 1;\n            //        FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DSHADOW));\n            //    }\n            //\n            //    return TRUE;\n            //}\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case TVN_SELCHANGED:\n                {\n                    LPNMTREEVIEW treeview = (LPNMTREEVIEW)lParam;\n                    PPH_OPTIONS_SECTION section = (PPH_OPTIONS_SECTION)treeview->itemNew.lParam;\n\n                    if (section)\n                    {\n                        PhOptionsEnterSectionView(section);\n                    }\n                }\n                break;\n            case NM_SETCURSOR:\n                {\n                    if (header->hwndFrom == OptionsTreeControl)\n                    {\n                        PhSetCursor(PhLoadArrowCursor());\n\n                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);\n                        return TRUE;\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhOptionsOnSize(\n    VOID\n    )\n{\n    PhLayoutManagerLayout(&WindowLayoutManager);\n\n    if (SectionList && SectionList->Count != 0)\n    {\n        PhOptionsLayoutSectionView();\n    }\n}\n\n_Function_class_(PH_OPTIONS_CREATE_SECTION)\nPPH_OPTIONS_SECTION PhOptionsCreateSection(\n    _In_ PCWSTR Name,\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_ DLGPROC DialogProc,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PPH_OPTIONS_SECTION section;\n\n    section = PhAllocateZero(sizeof(PH_OPTIONS_SECTION));\n    PhInitializeStringRefLongHint(&section->Name, Name);\n    section->Instance = Instance;\n    section->Template = Template;\n    section->DialogProc = DialogProc;\n    section->Parameter = Parameter;\n    section->TreeItemHandle = PhpTreeViewInsertItem(TVI_LAST, Name, section);\n\n    PhAddItemList(SectionList, section);\n\n    return section;\n}\n\nPPH_OPTIONS_SECTION PhOptionsCreateSectionAdvanced(\n    _In_ PCWSTR Name,\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_ DLGPROC DialogProc,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PPH_OPTIONS_SECTION section;\n\n    section = PhAllocateZero(sizeof(PH_OPTIONS_SECTION));\n    PhInitializeStringRefLongHint(&section->Name, Name);\n    section->Instance = Instance;\n    section->Template = Template;\n    section->DialogProc = DialogProc;\n    section->Parameter = Parameter;\n\n    PhAddItemList(SectionList, section);\n\n    return section;\n}\n\nVOID PhOptionsDestroySection(\n    _In_ PPH_OPTIONS_SECTION Section\n    )\n{\n    PhFree(Section);\n}\n\n_Function_class_(PH_OPTIONS_FIND_SECTION)\nPPH_OPTIONS_SECTION PhOptionsFindSection(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    ULONG i;\n    PPH_OPTIONS_SECTION section;\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n\n        if (PhEqualStringRef(&section->Name, Name, TRUE))\n            return section;\n    }\n\n    return NULL;\n}\n\nVOID PhOptionsLayoutSectionView(\n    VOID\n    )\n{\n    if (CurrentSection && CurrentSection->DialogHandle)\n    {\n        RECT clientRect;\n\n        if (!PhGetClientRect(ContainerControl, &clientRect))\n            return;\n\n        SetWindowPos(\n            CurrentSection->DialogHandle,\n            NULL,\n            0,\n            0,\n            clientRect.right - clientRect.left,\n            clientRect.bottom - clientRect.top,\n            SWP_NOACTIVATE | SWP_NOZORDER\n            );\n    }\n}\n\n_Function_class_(PH_OPTIONS_ENTER_SECTION_VIEW)\nVOID PhOptionsEnterSectionView(\n    _In_ PPH_OPTIONS_SECTION NewSection\n    )\n{\n    ULONG i;\n    PPH_OPTIONS_SECTION section;\n    PPH_OPTIONS_SECTION oldSection;\n    HDWP containerDeferHandle;\n\n    if (CurrentSection == NewSection)\n        return;\n\n    oldSection = CurrentSection;\n    CurrentSection = NewSection;\n\n    containerDeferHandle = BeginDeferWindowPos(SectionList->Count);\n\n    PhOptionsEnterSectionViewInner(NewSection, &containerDeferHandle);\n    PhOptionsLayoutSectionView();\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n\n        if (section != NewSection)\n            PhOptionsEnterSectionViewInner(section, &containerDeferHandle);\n    }\n\n    EndDeferWindowPos(containerDeferHandle);\n\n    if (NewSection->DialogHandle)\n        RedrawWindow(NewSection->DialogHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);\n}\n\nVOID PhOptionsEnterSectionViewInner(\n    _In_ PPH_OPTIONS_SECTION Section,\n    _Inout_ HDWP *ContainerDeferHandle\n    )\n{\n    if (Section == CurrentSection && !Section->DialogHandle)\n        PhOptionsCreateSectionDialog(Section);\n\n    if (Section->DialogHandle)\n    {\n        if (Section == CurrentSection)\n            *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY | SWP_NOREDRAW);\n        else\n            *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY | SWP_NOREDRAW);\n    }\n}\n\nVOID PhOptionsCreateSectionDialog(\n    _In_ PPH_OPTIONS_SECTION Section\n    )\n{\n    Section->DialogHandle = PhCreateDialogFromTemplate(\n        ContainerControl,\n        DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD,\n        Section->Instance,\n        Section->Template,\n        Section->DialogProc,\n        Section->Parameter\n        );\n\n    PhInitializeWindowTheme(Section->DialogHandle, PhEnableThemeSupport);\n}\n\n#define SetDlgItemCheckForSetting(hwndDlg, Id, Name) \\\n    Button_SetCheck(GetDlgItem(hwndDlg, Id), PhGetIntegerSetting(Name) ? BST_CHECKED : BST_UNCHECKED)\n#define SetSettingForDlgItemCheck(hwndDlg, Id, Name) \\\n    PhSetIntegerSetting(Name, Button_GetCheck(GetDlgItem(hwndDlg, Id)) == BST_CHECKED)\n#define SetSettingForDlgItemCheckRestartRequired(hwndDlg, Id, Name) \\\n{ \\\n    BOOLEAN __oldValue = !!PhGetIntegerSetting(Name); \\\n    BOOLEAN __newValue = Button_GetCheck(GetDlgItem(hwndDlg, Id)) == BST_CHECKED; \\\n    if (__newValue != __oldValue) \\\n        RestartRequired = TRUE; \\\n    PhSetIntegerSetting(Name, __newValue); \\\n}\n\n#define SetLvItemCheckForSetting(ListViewHandle, Index, Name) \\\n    ListView_SetCheckState(ListViewHandle, Index, !!PhGetIntegerSetting(Name));\n#define SetSettingForLvItemCheck(ListViewHandle, Index, Name) \\\n    PhSetIntegerSetting(Name, ListView_GetCheckState(ListViewHandle, Index) == BST_CHECKED)\n#define SetSettingForLvItemCheckRestartRequired(ListViewHandle, Index, Name) \\\n{ \\\n    BOOLEAN __oldValue = !!PhGetIntegerSetting(Name); \\\n    BOOLEAN __newValue = ListView_GetCheckState(ListViewHandle, Index) == BST_CHECKED; \\\n    if (__newValue != __oldValue) \\\n        RestartRequired = TRUE; \\\n    PhSetIntegerSetting(Name, __newValue); \\\n}\n\n_Success_(return)\nstatic BOOLEAN GetCurrentFont(\n    _Out_ PLOGFONT Font\n    )\n{\n    BOOLEAN result;\n    PPH_STRING fontHexString;\n\n    if (NewFontSelection)\n        fontHexString = NewFontSelection;\n    else\n        fontHexString = PhaGetStringSetting(SETTING_FONT);\n\n    if (fontHexString->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT))\n        result = PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)Font);\n    else\n        result = FALSE;\n\n    return result;\n}\n\n_Success_(return)\nstatic BOOLEAN GetCurrentFontMonospace(\n    _Out_ PLOGFONT Font\n    )\n{\n    BOOLEAN result;\n    PPH_STRING fontHexString;\n\n    if (NewFontMonospaceSelection)\n        fontHexString = NewFontMonospaceSelection;\n    else\n        fontHexString = PhaGetStringSetting(SETTING_FONT_MONOSPACE);\n\n    if (fontHexString->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT))\n        result = PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)Font);\n    else\n        result = FALSE;\n\n    return result;\n}\n\ntypedef struct _PHP_HKURUN_ENTRY\n{\n    PPH_STRING Value;\n    //PPH_STRING Name;\n} PHP_HKURUN_ENTRY, *PPHP_HKURUN_ENTRY;\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nBOOLEAN NTAPI PhpReadCurrentRunCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PKEY_VALUE_FULL_INFORMATION Information,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Context && Information->Type == REG_SZ)\n    {\n        PHP_HKURUN_ENTRY entry;\n\n        if (Information->DataLength > sizeof(UNICODE_NULL))\n            entry.Value = PhCreateStringEx(PTR_ADD_OFFSET(Information, Information->DataOffset), Information->DataLength);\n        else\n            entry.Value = PhReferenceEmptyString();\n\n        //entry.Name = PhCreateStringEx(Information->Name, Information->NameLength);\n\n        PhAddItemArray(Context, &entry);\n    }\n\n    return TRUE;\n}\n\nstatic VOID ReadCurrentUserRun(\n    VOID\n    )\n{\n    HANDLE keyHandle;\n\n    CurrentUserRunPresent = FALSE;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_CURRENT_USER,\n        &CurrentUserRunKeyName,\n        0\n        )))\n    {\n        PH_ARRAY keyEntryArray;\n\n        PhInitializeArray(&keyEntryArray, sizeof(PHP_HKURUN_ENTRY), 20);\n        PhEnumerateValueKey(keyHandle, KeyValueFullInformation, PhpReadCurrentRunCallback, &keyEntryArray);\n\n        for (SIZE_T i = 0; i < PhFinalArrayCount(&keyEntryArray); i++)\n        {\n            PPHP_HKURUN_ENTRY entry = PhItemArray(&keyEntryArray, i);\n            PH_STRINGREF fileName;\n            PH_STRINGREF arguments;\n            PPH_STRING fullFileName;\n            PPH_STRING applicationFileName;\n\n            if (PhParseCommandLineFuzzy(&entry->Value->sr, &fileName, &arguments, &fullFileName))\n            {\n                if (applicationFileName = PhGetApplicationFileNameWin32())\n                {\n                    PhMoveReference(&applicationFileName, PhGetBaseName(applicationFileName));\n\n                    if (fullFileName && PhEndsWithString(fullFileName, applicationFileName, TRUE))\n                    {\n                        CurrentUserRunPresent = TRUE;\n                    }\n\n                    PhDereferenceObject(applicationFileName);\n                }\n\n                if (fullFileName) PhDereferenceObject(fullFileName);\n            }\n\n            PhDereferenceObject(entry->Value);\n        }\n\n        PhDeleteArray(&keyEntryArray);\n\n        NtClose(keyHandle);\n    }\n}\n\nstatic VOID WriteCurrentUserRun(\n    _In_ BOOLEAN Present,\n    _In_ BOOLEAN StartHidden\n    )\n{\n    HANDLE keyHandle;\n\n    if (CurrentUserRunPresent == Present)\n        return;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_WRITE,\n        PH_KEY_CURRENT_USER,\n        &CurrentUserRunKeyName,\n        0\n        )))\n    {\n        static CONST PH_STRINGREF valueName = PH_STRINGREF_INIT(L\"System Informer\");\n        static CONST PH_STRINGREF separator = PH_STRINGREF_INIT(L\"\\\"\");\n\n        if (Present)\n        {\n            PPH_STRING value;\n            PPH_STRING fileName;\n\n            if (fileName = PhGetApplicationFileNameWin32())\n            {\n                value = PH_AUTO(PhConcatStringRef3(&separator, &fileName->sr, &separator));\n\n                if (StartHidden)\n                    value = PH_AUTO(PhConcatStringRefZ(&value->sr, L\" -hide\"));\n\n                PhSetValueKey(\n                    keyHandle,\n                    &valueName,\n                    REG_SZ,\n                    value->Buffer,\n                    (ULONG)value->Length + sizeof(UNICODE_NULL)\n                    );\n\n                PhDereferenceObject(fileName);\n            }\n        }\n        else\n        {\n            PhDeleteValueKey(keyHandle, &valueName);\n        }\n\n        NtClose(keyHandle);\n    }\n}\n\nstatic BOOLEAN PathMatchesPh(\n    _In_ PPH_STRING Path\n    )\n{\n    BOOLEAN match = FALSE;\n    PPH_STRING fileName;\n\n    if (!(fileName = PhGetApplicationFileNameWin32()))\n        return FALSE;\n\n    if (PhEqualString(OldTaskMgrDebugger, fileName, TRUE))\n    {\n        match = TRUE;\n    }\n    // Allow for a quoted value.\n    else if (\n        OldTaskMgrDebugger->Length == fileName->Length + 4 &&\n        OldTaskMgrDebugger->Buffer[0] == L'\"' &&\n        OldTaskMgrDebugger->Buffer[OldTaskMgrDebugger->Length / sizeof(WCHAR) - 1] == L'\"'\n        )\n    {\n        PH_STRINGREF partInside;\n\n        partInside.Buffer = &OldTaskMgrDebugger->Buffer[1];\n        partInside.Length = OldTaskMgrDebugger->Length - 2 * sizeof(WCHAR);\n\n        if (PhEqualStringRef(&partInside, &fileName->sr, TRUE))\n            match = TRUE;\n    }\n\n    PhDereferenceObject(fileName);\n\n    return match;\n}\n\nBOOLEAN PhpIsDefaultTaskManager(\n    VOID\n    )\n{\n    HANDLE taskmgrKeyHandle;\n    BOOLEAN alreadyReplaced = FALSE;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &taskmgrKeyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &TaskMgrImageOptionsKeyName,\n        0\n        )))\n    {\n        PhClearReference(&OldTaskMgrDebugger);\n\n        if (OldTaskMgrDebugger = PhQueryRegistryStringZ(taskmgrKeyHandle, L\"Debugger\"))\n        {\n            alreadyReplaced = PathMatchesPh(OldTaskMgrDebugger);\n        }\n\n        NtClose(taskmgrKeyHandle);\n    }\n\n    return alreadyReplaced;\n}\n\nVOID PhpSetDefaultTaskManager(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    PWSTR message;\n\n    if (PhpIsDefaultTaskManager())\n    {\n        message = L\"Do you want to restore the default Windows Task Manager?\";\n    }\n    else\n    {\n        message = L\"Do you want to make System Informer the default Windows Task Manager?\";\n\n        // Warn the user when we're not installed into secure location. (dmex)\n        if (!PhShowOptionsDefaultInstallLocation(ParentWindowHandle, L\"Changing the default Task Manager\"))\n        {\n            return;\n        }\n    }\n\n    if (PhShowMessage2(\n        ParentWindowHandle,\n        TD_YES_BUTTON | TD_NO_BUTTON,\n        TD_INFORMATION_ICON,\n        L\"\",\n        message\n        ) == IDYES)\n    {\n        NTSTATUS status;\n        HANDLE taskmgrKeyHandle;\n\n        status = PhCreateKey(\n            &taskmgrKeyHandle,\n            KEY_READ | KEY_WRITE,\n            PH_KEY_LOCAL_MACHINE,\n            &TaskMgrImageOptionsKeyName,\n            OBJ_OPENIF,\n            0,\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            static CONST PH_STRINGREF valueName = PH_STRINGREF_INIT(L\"Debugger\");\n            static CONST PH_STRINGREF separator = PH_STRINGREF_INIT(L\"\\\"\");\n\n            if (PhpIsDefaultTaskManager())\n            {\n                status = PhDeleteValueKey(taskmgrKeyHandle, &valueName);\n            }\n            else\n            {\n                PPH_STRING quotedFileName;\n                PPH_STRING applicationFileName;\n\n                if (applicationFileName = PhGetApplicationFileNameWin32())\n                {\n                    quotedFileName = PH_AUTO(PhConcatStringRef3(&separator, &applicationFileName->sr, &separator));\n\n                    status = PhSetValueKey(\n                        taskmgrKeyHandle,\n                        &valueName,\n                        REG_SZ,\n                        quotedFileName->Buffer,\n                        (ULONG)quotedFileName->Length + sizeof(UNICODE_NULL)\n                        );\n\n                    PhDereferenceObject(applicationFileName);\n                }\n            }\n\n            NtClose(taskmgrKeyHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n            PhShowStatus(ParentWindowHandle, L\"Unable to replace Task Manager\", status, 0);\n\n        //PhSaveSettings2(PhSettingsFileName);\n    }\n}\n\n//BOOLEAN PhpIsExploitProtectionEnabled(\n//    VOID\n//    )\n//{\n//    BOOLEAN enabled = FALSE;\n//    HANDLE keyHandle;\n//    PPH_STRING directory = NULL;\n//    PPH_STRING fileName = NULL;\n//    PPH_STRING keyName;\n//\n//    PhMoveReference(&directory, PhCreateString2(&TaskMgrImageOptionsKeyName));\n//    PhMoveReference(&directory, PhGetBaseDirectory(directory));\n//    PhMoveReference(&fileName, PhGetApplicationFileNameWin32());\n//    PhMoveReference(&fileName, PhGetBaseName(fileName));\n//    keyName = PhConcatStringRef3(&directory->sr, &PhNtPathSeparatorString, &fileName->sr);\n//\n//    if (NT_SUCCESS(PhOpenKey(\n//        &keyHandle,\n//        KEY_READ,\n//        PH_KEY_LOCAL_MACHINE,\n//        &keyName->sr,\n//        0\n//        )))\n//    {\n//        PH_STRINGREF valueName;\n//        PKEY_VALUE_PARTIAL_INFORMATION buffer;\n//\n//        enabled = !(PhQueryRegistryUlong64(keyHandle, L\"MitigationOptions\") == ULLONG_MAX);\n//        PhInitializeStringRef(&valueName, L\"MitigationOptions\");\n//\n//        if (NT_SUCCESS(PhQueryValueKey(keyHandle, &valueName, KeyValuePartialInformation, &buffer)))\n//        {\n//            if (buffer->Type == REG_BINARY && buffer->DataLength)\n//            {\n//                enabled = TRUE;\n//            }\n//\n//            PhFree(buffer);\n//        }\n//\n//        NtClose(keyHandle);\n//    }\n//\n//    PhDereferenceObject(keyName);\n//    PhDereferenceObject(fileName);\n//    PhDereferenceObject(directory);\n//\n//    return enabled;\n//}\n//\n//NTSTATUS PhpSetExploitProtectionEnabled(\n//    _In_ BOOLEAN Enabled)\n//{\n//    static PH_STRINGREF replacementToken = PH_STRINGREF_INIT(L\"Software\\\\\");\n//    static PH_STRINGREF wow6432Token = PH_STRINGREF_INIT(L\"Software\\\\WOW6432Node\\\\\");\n//    static PH_STRINGREF valueName = PH_STRINGREF_INIT(L\"MitigationOptions\");\n//    NTSTATUS status = STATUS_UNSUCCESSFUL;\n//    HANDLE keyHandle;\n//    PPH_STRING directory;\n//    PPH_STRING fileName;\n//    PPH_STRING keyName;\n//\n//    directory = PhCreateString2(&TaskMgrImageOptionsKeyName);\n//    PhMoveReference(&directory, PhGetBaseDirectory(directory));\n//    fileName = PhGetApplicationFileNameWin32();\n//    PhMoveReference(&fileName, PhGetBaseName(fileName));\n//    keyName = PhConcatStringRef3(&directory->sr, &PhNtPathSeparatorString, &fileName->sr);\n//\n//    //if (Enabled)\n//    //{\n//    //    status = PhCreateKey(\n//    //        &keyHandle,\n//    //        KEY_WRITE,\n//    //        PH_KEY_LOCAL_MACHINE,\n//    //        &keyName->sr,\n//    //        OBJ_OPENIF,\n//    //        0,\n//    //        NULL\n//    //        );\n//    //\n//    //    if (NT_SUCCESS(status))\n//    //    {\n//    //        status = PhSetValueKey(keyHandle, &valueName, REG_QWORD, &(ULONG64)\n//    //        {\n//    //            PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON |\n//    //            PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON |\n//    //            PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON |\n//    //            PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON |\n//    //            PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON |\n//    //            PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON |\n//    //            PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON |\n//    //            PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON |\n//    //            PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON |\n//    //            PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON,\n//    //        }, sizeof(ULONG64));\n//    //\n//    //        NtClose(keyHandle);\n//    //    }\n//    //}\n//    //else\n//    {\n//        status = PhOpenKey(\n//            &keyHandle,\n//            KEY_WRITE,\n//            PH_KEY_LOCAL_MACHINE,\n//            &keyName->sr,\n//            OBJ_OPENIF\n//            );\n//\n//        if (NT_SUCCESS(status))\n//        {\n//            status = PhDeleteValueKey(keyHandle, &valueName);\n//            NtClose(keyHandle);\n//        }\n//\n//        if (status == STATUS_OBJECT_NAME_NOT_FOUND)\n//            status = STATUS_SUCCESS;\n//\n//#ifdef _WIN64\n//        if (NT_SUCCESS(status))\n//        {\n//            PH_STRINGREF stringBefore;\n//            PH_STRINGREF stringAfter;\n//\n//            if (PhSplitStringRefAtString(&keyName->sr, &replacementToken, TRUE, &stringBefore, &stringAfter))\n//            {\n//                PhMoveReference(&keyName, PhConcatStringRef3(&stringBefore, &wow6432Token, &stringAfter));\n//\n//                status = PhOpenKey(\n//                    &keyHandle,\n//                    DELETE,\n//                    PH_KEY_LOCAL_MACHINE,\n//                    &keyName->sr,\n//                    OBJ_OPENIF\n//                    );\n//\n//                if (NT_SUCCESS(status))\n//                {\n//                    status = NtDeleteKey(keyHandle);\n//                    NtClose(keyHandle);\n//                }\n//            }\n//        }\n//#endif\n//    }\n//\n//    if (status == STATUS_OBJECT_NAME_NOT_FOUND)\n//        status = STATUS_SUCCESS;\n//\n//    PhDereferenceObject(keyName);\n//    PhDereferenceObject(fileName);\n//    PhDereferenceObject(directory);\n//\n//    return status;\n//}\n\nNTSTATUS PhpSetSilentProcessNotifyEnabled(\n    _In_ BOOLEAN Enabled)\n{\n    static CONST PH_STRINGREF processExitKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\SilentProcessExit\");\n    static CONST PH_STRINGREF valueModeName = PH_STRINGREF_INIT(L\"ReportingMode\");\n    static ULONG valueMode = 4;\n    //static CONST PH_STRINGREF valueSelfName = PH_STRINGREF_INIT(L\"IgnoreSelfExits\");\n    //static ULONG valueSelf = 1;\n    //static CONST PH_STRINGREF valueMonitorName = PH_STRINGREF_INIT(L\"MonitorProcess\");\n    static CONST PH_STRINGREF valueGlobalName = PH_STRINGREF_INIT(L\"GlobalFlag\");\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    HANDLE keyDirectoryHandle = NULL;\n    HANDLE keyFilenameHandle = NULL;\n    PPH_STRING filename;\n    PPH_STRING baseName;\n\n    filename = PH_AUTO(PhGetApplicationFileNameWin32());\n    baseName = PH_AUTO(PhGetBaseName(filename));\n\n    if (Enabled)\n    {\n        status = PhCreateKey(\n            &keyDirectoryHandle,\n            KEY_WRITE,\n            PH_KEY_LOCAL_MACHINE,\n            &processExitKeyName,\n            OBJ_OPENIF,\n            0,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhCreateKey(\n            &keyFilenameHandle,\n            KEY_WRITE,\n            keyDirectoryHandle,\n            &baseName->sr,\n            OBJ_OPENIF,\n            0,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhSetValueKey(\n            keyFilenameHandle,\n            &valueModeName,\n            REG_DWORD,\n            &valueMode,\n            sizeof(ULONG)\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        //PhSetValueKey(keyFilenameHandle, &valueSelfName, REG_DWORD, &valueSelf, sizeof(ULONG));\n        //PhSetValueKey(keyFilenameHandle, &valueMonitorName, REG_SZ, filename->Buffer, (ULONG)filename->Length + sizeof(UNICODE_NULL));\n\n        if (NT_SUCCESS(status))\n        {\n            HANDLE keyHandle;\n            PPH_STRING directory;\n            PPH_STRING fileName;\n            PPH_STRING keyName;\n\n            directory = PH_AUTO(PhCreateString2(&TaskMgrImageOptionsKeyName));\n            directory = PH_AUTO(PhGetBaseDirectory(directory));\n            fileName = PH_AUTO(PhGetApplicationFileNameWin32());\n            fileName = PH_AUTO(PhGetBaseName(fileName));\n            keyName = PH_AUTO(PhConcatStringRef3(&directory->sr, &PhNtPathSeparatorString, &fileName->sr));\n\n            status = PhCreateKey(\n                &keyHandle,\n                KEY_WRITE,\n                PH_KEY_LOCAL_MACHINE,\n                &keyName->sr,\n                OBJ_OPENIF,\n                0,\n                NULL\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                ULONG globalFlags = PhQueryRegistryUlongZ(keyHandle, L\"GlobalFlag\");\n\n                if (globalFlags == ULONG_MAX) globalFlags = 0;\n                globalFlags = globalFlags | FLG_MONITOR_SILENT_PROCESS_EXIT;\n\n                status = PhSetValueKey(keyHandle, &valueGlobalName, REG_DWORD, &globalFlags, sizeof(ULONG));\n                NtClose(keyHandle);\n            }\n        }\n    }\n    else\n    {\n        if (NT_SUCCESS(PhOpenKey(\n            &keyDirectoryHandle,\n            DELETE,\n            PH_KEY_LOCAL_MACHINE,\n            &processExitKeyName,\n            0\n            )))\n        {\n            if (NT_SUCCESS(PhOpenKey(\n                &keyFilenameHandle,\n                DELETE,\n                keyDirectoryHandle,\n                &baseName->sr,\n                0\n                )))\n            {\n                NtDeleteKey(keyFilenameHandle);\n            }\n        }\n\n        {\n            HANDLE keyHandle;\n            PPH_STRING directory;\n            PPH_STRING fileName;\n            PPH_STRING keyName;\n\n            directory = PH_AUTO(PhCreateString2(&TaskMgrImageOptionsKeyName));\n            directory = PH_AUTO(PhGetBaseDirectory(directory));\n            fileName = PH_AUTO(PhGetApplicationFileNameWin32());\n            fileName = PH_AUTO(PhGetBaseName(fileName));\n            keyName = PH_AUTO(PhConcatStringRef3(&directory->sr, &PhNtPathSeparatorString, &fileName->sr));\n\n            status = PhOpenKey(\n                &keyHandle,\n                KEY_WRITE,\n                PH_KEY_LOCAL_MACHINE,\n                &keyName->sr,\n                0\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhDeleteValueKey(keyHandle, &valueGlobalName);\n                NtClose(keyHandle);\n            }\n        }\n    }\n\nCleanupExit:\n    if (keyDirectoryHandle)\n        NtClose(keyDirectoryHandle);\n    if (keyFilenameHandle)\n        NtClose(keyFilenameHandle);\n\n    return status;\n}\n\nVOID PhpRefreshTaskManagerState(\n    _In_ HWND WindowHandle\n    )\n{\n    if (!PhGetOwnTokenAttributes().Elevated)\n    {\n        Button_SetElevationRequiredState(GetDlgItem(WindowHandle, IDC_REPLACETASKMANAGER), TRUE);\n    }\n\n    if (PhpIsDefaultTaskManager())\n    {\n        PhSetWindowText(GetDlgItem(WindowHandle, IDC_DEFSTATE), L\"System Informer is the default Task Manager:\");\n        PhSetWindowText(GetDlgItem(WindowHandle, IDC_REPLACETASKMANAGER), L\"Restore default...\");\n    }\n    else\n    {\n        PhSetWindowText(GetDlgItem(WindowHandle, IDC_DEFSTATE), L\"System Informer is not the default Task Manager:\");\n        PhSetWindowText(GetDlgItem(WindowHandle, IDC_REPLACETASKMANAGER), L\"Make default...\");\n    }\n}\n\ntypedef enum _PHP_OPTIONS_INDEX\n{\n    PHP_OPTIONS_INDEX_SINGLE_INSTANCE,\n    PHP_OPTIONS_INDEX_HIDE_WHENCLOSED,\n    PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED,\n    PHP_OPTIONS_INDEX_START_ATLOGON,\n    PHP_OPTIONS_INDEX_START_HIDDEN,\n    PHP_OPTIONS_INDEX_ENABLE_WARNINGS,\n    PHP_OPTIONS_INDEX_ENABLE_DRIVER,\n    PHP_OPTIONS_INDEX_ENABLE_MONOSPACE,\n    PHP_OPTIONS_INDEX_ENABLE_PLUGINS,\n    PHP_OPTIONS_INDEX_ENABLE_AVX_EXTENSIONS,\n    PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS,\n    PHP_OPTIONS_INDEX_ENABLE_COLUMN_HEADER_TOTALS,\n    PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE,\n    PHP_OPTIONS_INDEX_ENABLE_LOW_LATENCY_MODE,\n    PHP_OPTIONS_INDEX_ENABLE_GRAPH_SCALING,\n    PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW,\n    PHP_OPTIONS_INDEX_ENABLE_MEMSTRINGS_TREE,\n    PHP_OPTIONS_INDEX_ENABLE_LASTTAB_SUPPORT,\n    PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT,\n    PHP_OPTIONS_INDEX_ENABLE_START_ASADMIN,\n    PHP_OPTIONS_INDEX_ENABLE_STREAM_MODE,\n    PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE,\n    PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE_DOH,\n    PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS,\n    PHP_OPTIONS_INDEX_ENABLE_IMAGE_COHERENCY,\n    PHP_OPTIONS_INDEX_ENABLE_STAGE2,\n    PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2,\n    PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK,\n    PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY,\n    PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE,\n    PHP_OPTIONS_INDEX_PROCESS_MONITOR,\n    PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS\n} PHP_OPTIONS_GENERAL_INDEX;\n\nstatic VOID PhpAdvancedPageLoad(\n    _In_ HWND hwndDlg,\n    _In_ BOOLEAN ReloadOnly\n    )\n{\n    HWND listViewHandle;\n\n    listViewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS);\n\n    PhSetDialogItemValue(hwndDlg, IDC_SAMPLECOUNT, PhGetIntegerSetting(SETTING_SAMPLE_COUNT), FALSE);\n    SetDlgItemCheckForSetting(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, SETTING_SAMPLE_COUNT_AUTOMATIC);\n\n    if (PhGetIntegerSetting(SETTING_SAMPLE_COUNT_AUTOMATIC))\n        EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE);\n\n    if (!ReloadOnly)\n    {\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L\"Allow only one instance\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L\"Hide when closed\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, L\"Hide when minimized\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON, L\"Start when I log on\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, L\"Start hidden\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L\"Enable warnings\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L\"Enable kernel-mode driver\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MONOSPACE, L\"Enable monospace fonts\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L\"Enable plugins\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L\"Enable undecorated symbols\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_AVX_EXTENSIONS, L\"Enable AVX extensions (experimental)\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_COLUMN_HEADER_TOTALS, L\"Enable column header totals (experimental)\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L\"Enable cycle-based CPU usage\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LOW_LATENCY_MODE, L\"Enable low-latency mode (experimental)\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_GRAPH_SCALING, L\"Enable fixed graph scaling (experimental)\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, L\"Enable tray information window\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MEMSTRINGS_TREE, L\"Enable new memory strings dialog\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LASTTAB_SUPPORT, L\"Remember last selected window\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, L\"Enable theme support (experimental)\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_START_ASADMIN, L\"Enable start as admin (experimental)\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STREAM_MODE, L\"Enable streamer mode (disable window capture) (experimental)\", NULL);\n        //PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LINUX_SUPPORT, L\"Enable Windows subsystem for Linux support\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L\"Resolve network addresses\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE_DOH, L\"Resolve DNS over HTTPS (DoH)\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L\"Show tooltips instantly\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_IMAGE_COHERENCY, L\"Check images for coherency\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L\"Check images for digital signatures\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, L\"Check services for digital signatures\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L\"Single-click tray icons\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L\"Icon click toggles visibility\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L\"Include usage of collapsed processes\", NULL);\n        if (WindowsVersion >= WINDOWS_10)\n            PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_PROCESS_MONITOR, L\"Enable process monitor (experimental)\", NULL);\n        PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, L\"Show advanced options\", NULL);\n    }\n\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, SETTING_ALLOW_ONLY_ONE_INSTANCE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, SETTING_HIDE_ON_CLOSE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, SETTING_HIDE_ON_MINIMIZE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, SETTING_START_HIDDEN);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, SETTING_MINI_INFO_WINDOW_ENABLED);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MEMSTRINGS_TREE, SETTING_ENABLE_MEM_STRINGS_TREE_DIALOG);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LASTTAB_SUPPORT, SETTING_MAIN_WINDOW_TAB_RESTORE_ENABLED);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, SETTING_KSI_ENABLE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, SETTING_ENABLE_WARNINGS);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, SETTING_ENABLE_PLUGINS);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, SETTING_DBGHELP_UNDECORATE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_AVX_EXTENSIONS, SETTING_ENABLE_AVX_SUPPORT);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_COLUMN_HEADER_TOTALS, SETTING_TREE_LIST_ENABLE_HEADER_TOTALS);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_GRAPH_SCALING, SETTING_ENABLE_GRAPH_MAX_SCALE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, SETTING_ENABLE_CYCLE_CPU_USAGE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LOW_LATENCY_MODE, SETTING_ENABLE_HIGH_RESOLUTION_PROVIDER_TIMER);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, SETTING_ENABLE_THEME_SUPPORT);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_START_ASADMIN, SETTING_ENABLE_START_AS_ADMIN);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STREAM_MODE, SETTING_ENABLE_STREAMER_MODE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MONOSPACE, SETTING_ENABLE_MONOSPACE_FONT);\n    //SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LINUX_SUPPORT, SETTING_ENABLE_LINUX_SUBSYSTEM_SUPPORT);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, SETTING_ENABLE_NETWORK_RESOLVE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE_DOH, SETTING_ENABLE_NETWORK_RESOLVE_DOH);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, SETTING_ENABLE_INSTANT_TOOLTIPS);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_IMAGE_COHERENCY, SETTING_ENABLE_IMAGE_COHERENCY_SUPPORT);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, SETTING_ENABLE_STAGE2);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, SETTING_ENABLE_SERVICE_STAGE2);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, SETTING_ICON_SINGLE_CLICK);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, SETTING_ICON_TOGGLES_VISIBILITY);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, SETTING_PROPAGATE_CPU_USAGE);\n    SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, SETTING_ENABLE_ADVANCED_OPTIONS);\n    if (WindowsVersion >= WINDOWS_10)\n        SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_PROCESS_MONITOR, SETTING_ENABLE_PROCESS_MONITOR);\n\n    if (CurrentUserRunPresent)\n        ListView_SetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON, TRUE);\n    if (PhGetIntegerSetting(SETTING_ENABLE_ADVANCED_OPTIONS))\n        PhpOptionsShowHideTreeViewItem(FALSE);\n}\n\nstatic VOID PhpOptionsNotifyChangeCallback(\n    _In_ PVOID Context\n    )\n{\n    PhUpdateCachedSettings();\n    SystemInformer_SaveAllSettings();\n    PhInvalidateAllProcessNodes();\n    PhReloadSettingsProcessTreeList();\n    PhSiNotifyChangeSettings();\n\n    //PhReInitializeWindowTheme(PhMainWndHandle);\n\n    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackSettingsUpdated), NULL);\n\n    if (RestartRequired)\n    {\n        if (PhShowMessage2(\n            PhMainWndHandle,\n            TD_YES_BUTTON | TD_NO_BUTTON,\n            TD_INFORMATION_ICON,\n            L\"One or more options you have changed requires a restart of System Informer.\",\n            L\"Do you want to restart System Informer now?\"\n            ) == IDYES)\n        {\n            SystemInformer_PrepareForEarlyShutdown();\n\n            if (NT_SUCCESS(PhShellProcessHacker(\n                PhMainWndHandle,\n                L\"-v -newinstance\",\n                SW_SHOW,\n                PH_SHELL_EXECUTE_DEFAULT,\n                PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY,\n                0,\n                NULL\n                )))\n            {\n                SystemInformer_Destroy();\n            }\n            else\n            {\n                SystemInformer_CancelEarlyShutdown();\n            }\n        }\n    }\n}\n\nVOID PhShowOptionsRestartRequired(\n    _In_ HWND WindowHandle\n    )\n{\n    if (PhShowMessage2(\n        PhMainWndHandle,\n        TD_YES_BUTTON | TD_NO_BUTTON,\n        TD_INFORMATION_ICON,\n        L\"One or more options you have changed requires a restart of System Informer.\",\n        L\"Do you want to restart System Informer now?\"\n        ) == IDYES)\n    {\n        SystemInformer_PrepareForEarlyShutdown();\n\n        if (NT_SUCCESS(PhShellProcessHacker(\n            WindowHandle,\n            L\"-v -newinstance\",\n            SW_SHOW,\n            PH_SHELL_EXECUTE_DEFAULT,\n            PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY,\n            0,\n            NULL\n            )))\n        {\n            SystemInformer_Destroy();\n        }\n        else\n        {\n            SystemInformer_CancelEarlyShutdown();\n        }\n    }\n}\n\nBOOLEAN PhShowOptionsDefaultInstallLocation(\n    _In_ HWND ParentWindowHandle,\n    _In_ PCWSTR Message\n    )\n{\n    RTL_ELEVATION_FLAGS flags;\n\n    // Warn the user when we're not installed into secure location. (dmex)\n    if (NT_SUCCESS(RtlQueryElevationFlags(&flags)) && flags.ElevationEnabled)\n    {\n        PPH_STRING applicationFileName;\n        PPH_STRING programFilesPath;\n\n        if (applicationFileName = PhGetApplicationFileNameWin32())\n        {\n            if (programFilesPath = PhExpandEnvironmentStringsZ(L\"%ProgramFiles%\\\\\"))\n            {\n                if (!PhStartsWithString(applicationFileName, programFilesPath, TRUE))\n                {\n                    if (PhShowMessage2(\n                        ParentWindowHandle,\n                        TD_YES_BUTTON | TD_NO_BUTTON,\n                        TD_WARNING_ICON,\n                        L\"WARNING: You have not installed System Informer into a secure location.\",\n                        L\"%s is not recommended when running System Informer from outside a secure location (e.g. Program Files).\\r\\n\\r\\nAre you sure you want to continue?\",\n                        Message\n                        ) == IDNO)\n                    {\n                        PhDereferenceObject(programFilesPath);\n                        PhDereferenceObject(applicationFileName);\n                        return FALSE;\n                    }\n                }\n\n                PhDereferenceObject(programFilesPath);\n            }\n\n            PhDereferenceObject(applicationFileName);\n        }\n    }\n\n    return TRUE;\n}\n\nstatic VOID PhpAdvancedPageSave(\n    _In_ HWND hwndDlg\n    )\n{\n    HWND listViewHandle;\n    ULONG sampleCount;\n\n    listViewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS);\n    sampleCount = PhGetDialogItemValue(hwndDlg, IDC_SAMPLECOUNT);\n\n    SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, SETTING_SAMPLE_COUNT_AUTOMATIC);\n\n    if (sampleCount == 0)\n        sampleCount = 1;\n\n    if (sampleCount != PhGetIntegerSetting(SETTING_SAMPLE_COUNT))\n        RestartRequired = TRUE;\n\n    PhSetIntegerSetting(SETTING_SAMPLE_COUNT, sampleCount);\n    PhSetStringSetting2(SETTING_SEARCH_ENGINE, &PhaGetDlgItemText(hwndDlg, IDC_SEARCHENGINE)->sr);\n    PhSetStringSetting2(SETTING_PROGRAM_INSPECT_EXECUTABLES, &PhaGetDlgItemText(hwndDlg, IDC_PEVIEWER)->sr);\n    PhSetIntegerSetting(SETTING_MAX_SIZE_UNIT, PhMaxSizeUnit = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT)));\n    PhSetIntegerSetting(SETTING_ICON_PROCESSES, PhGetDialogItemValue(hwndDlg, IDC_ICONPROCESSES));\n\n    if (!PhEqualString(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH), PhaGetStringSetting(SETTING_DBGHELP_SEARCH_PATH), TRUE))\n    {\n        PhSetStringSetting2(SETTING_DBGHELP_SEARCH_PATH, &PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr);\n        RestartRequired = TRUE;\n    }\n\n    // When changing driver enabled setting, it only makes sense to require a restart if we're\n    // already elevated. If we're not elevated and asked to restart, we would not connect to the\n    // driver and the user has to elevate (restart) again anyway. (jxy-s)\n    if (PhGetOwnTokenAttributes().Elevated)\n    {\n        SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, SETTING_KSI_ENABLE);\n    }\n    else\n    {\n        SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, SETTING_KSI_ENABLE);\n    }\n\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, SETTING_ALLOW_ONLY_ONE_INSTANCE);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, SETTING_HIDE_ON_CLOSE);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, SETTING_HIDE_ON_MINIMIZE);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, SETTING_START_HIDDEN);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, SETTING_MINI_INFO_WINDOW_ENABLED);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MEMSTRINGS_TREE, SETTING_ENABLE_MEM_STRINGS_TREE_DIALOG);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LASTTAB_SUPPORT, SETTING_MAIN_WINDOW_TAB_RESTORE_ENABLED);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, SETTING_ENABLE_WARNINGS);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, SETTING_ENABLE_PLUGINS);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, SETTING_DBGHELP_UNDECORATE);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_AVX_EXTENSIONS, SETTING_ENABLE_AVX_SUPPORT);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_COLUMN_HEADER_TOTALS, SETTING_TREE_LIST_ENABLE_HEADER_TOTALS);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_GRAPH_SCALING, SETTING_ENABLE_GRAPH_MAX_SCALE);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, SETTING_ENABLE_CYCLE_CPU_USAGE);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LOW_LATENCY_MODE, SETTING_ENABLE_HIGH_RESOLUTION_PROVIDER_TIMER);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, SETTING_ENABLE_THEME_SUPPORT);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_START_ASADMIN, SETTING_ENABLE_START_AS_ADMIN);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STREAM_MODE, SETTING_ENABLE_STREAMER_MODE);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MONOSPACE, SETTING_ENABLE_MONOSPACE_FONT);\n    //SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LINUX_SUPPORT, SETTING_ENABLE_LINUX_SUBSYSTEM_SUPPORT);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, SETTING_ENABLE_NETWORK_RESOLVE);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE_DOH, SETTING_ENABLE_NETWORK_RESOLVE_DOH);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, SETTING_ENABLE_INSTANT_TOOLTIPS);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_IMAGE_COHERENCY, SETTING_ENABLE_IMAGE_COHERENCY_SUPPORT);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, SETTING_ENABLE_STAGE2);\n    SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, SETTING_ENABLE_SERVICE_STAGE2);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, SETTING_ICON_SINGLE_CLICK);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, SETTING_ICON_TOGGLES_VISIBILITY);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, SETTING_PROPAGATE_CPU_USAGE);\n    SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, SETTING_ENABLE_ADVANCED_OPTIONS);\n    if (WindowsVersion >= WINDOWS_10)\n        SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_PROCESS_MONITOR, SETTING_ENABLE_PROCESS_MONITOR);\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_THEME_SUPPORT)) // PhGetIntegerSetting required (dmex)\n    {\n        PhSetIntegerSetting(SETTING_GRAPH_COLOR_MODE, 1); // HACK switch to dark theme. (dmex)\n    }\n\n    WriteCurrentUserRun(\n        ListView_GetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON) == BST_CHECKED,\n        ListView_GetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN) == BST_CHECKED\n        );\n\n    SystemInformer_Invoke(PhpOptionsNotifyChangeCallback, NULL);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhpElevateAdvancedThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_STRING arguments;\n\n    arguments = Parameter;\n    PhShellProcessHacker(\n        WindowHandleForElevate,\n        arguments->Buffer,\n        SW_SHOW,\n        PH_SHELL_EXECUTE_ADMIN,\n        PH_SHELL_APP_PROPAGATE_PARAMETERS,\n        INFINITE,\n        NULL\n        );\n    PhDereferenceObject(arguments);\n\n    PostMessage(WindowHandleForElevate, WM_PH_CHILD_EXIT, 0, 0);\n\n    return STATUS_SUCCESS;\n}\n\nUINT_PTR CALLBACK PhpChooseFontDlgHookProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhCenterWindow(hwndDlg, PhOptionsWindowHandle);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nINT_PTR CALLBACK PhpOptionsGeneralDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    static PH_LAYOUT_MANAGER LayoutManager;\n    static HWND ListViewHandle = NULL;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HWND comboBoxHandle;\n            ULONG i;\n            LOGFONT font;\n\n            comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT);\n            ListViewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS);\n\n            PhpOptionsSetImageList(ListViewHandle, FALSE);\n\n            PhInitializeLayoutManager(&LayoutManager, hwndDlg);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHENGINE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_PEVIEWER), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&LayoutManager, ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DBGHELPSEARCHPATH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n\n            PhSetListViewStyle(ListViewHandle, FALSE, TRUE);\n            ListView_SetExtendedListViewStyleEx(ListViewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);\n            PhSetControlTheme(ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L\"Name\");\n            PhSetExtendedListView(ListViewHandle);\n\n            for (i = 0; i < RTL_NUMBER_OF(PhSizeUnitNames); i++)\n                ComboBox_AddString(comboBoxHandle, PhSizeUnitNames[i]);\n\n            if (PhMaxSizeUnit != ULONG_MAX)\n                ComboBox_SetCurSel(comboBoxHandle, PhMaxSizeUnit);\n            else\n                ComboBox_SetCurSel(comboBoxHandle, RTL_NUMBER_OF(PhSizeUnitNames) - 1);\n\n            PhSetDialogItemText(hwndDlg, IDC_SEARCHENGINE, PhaGetStringSetting(SETTING_SEARCH_ENGINE)->Buffer);\n            PhSetDialogItemText(hwndDlg, IDC_PEVIEWER, PhaGetStringSetting(SETTING_PROGRAM_INSPECT_EXECUTABLES)->Buffer);\n            PhSetDialogItemValue(hwndDlg, IDC_ICONPROCESSES, PhGetIntegerSetting(SETTING_ICON_PROCESSES), FALSE);\n            PhSetDialogItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(SETTING_DBGHELP_SEARCH_PATH)->Buffer);\n\n            ReadCurrentUserRun();\n\n            // Set the font of the button for a nice preview.\n            if (GetCurrentFont(&font))\n            {\n                CurrentFontInstance = CreateFontIndirect(&font);\n\n                if (CurrentFontInstance)\n                {\n                    SetWindowFont(OptionsTreeControl, CurrentFontInstance, TRUE); // HACK\n                    SetWindowFont(ListViewHandle, CurrentFontInstance, TRUE);\n                    SetWindowFont(GetDlgItem(hwndDlg, IDC_FONT), CurrentFontInstance, TRUE);\n                }\n            }\n\n            if (GetCurrentFontMonospace(&font))\n            {\n                CurrentFontMonospaceInstance = CreateFontIndirect(&font);\n\n                if (CurrentFontMonospaceInstance)\n                {\n                    SetWindowFont(GetDlgItem(hwndDlg, IDC_FONTMONOSPACE), CurrentFontMonospaceInstance, TRUE);\n                }\n            }\n\n            GeneralListViewStateInitializing = TRUE;\n            PhpAdvancedPageLoad(hwndDlg, FALSE);\n            PhpRefreshTaskManagerState(hwndDlg);\n            GeneralListViewStateInitializing = FALSE;\n        }\n        break;\n    case WM_DESTROY:\n        {\n            if (NewFontSelection)\n            {\n                PhSetStringSetting2(SETTING_FONT, &NewFontSelection->sr);\n            }\n\n            if (NewFontMonospaceSelection)\n            {\n                PhSetStringSetting2(SETTING_FONT_MONOSPACE, &NewFontMonospaceSelection->sr);\n            }\n\n            if (NewFontSelection || NewFontMonospaceSelection)\n            {\n                SystemInformer_UpdateFont();\n            }\n\n            if (CurrentFontInstance)\n                DeleteFont(CurrentFontInstance);\n\n            if (CurrentFontMonospaceInstance)\n                DeleteFont(CurrentFontMonospaceInstance);\n\n            PhClearReference(&NewFontSelection);\n            PhClearReference(&NewFontMonospaceSelection);\n            PhClearReference(&OldTaskMgrDebugger);\n\n            PhDeleteLayoutManager(&LayoutManager);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            PhLayoutManagerUpdate(&LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&LayoutManager);\n\n            PhpOptionsSetImageList(ListViewHandle, FALSE);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_FONT:\n                {\n                    LOGFONT font;\n                    CHOOSEFONT chooseFont;\n\n                    if (!GetCurrentFont(&font))\n                    {\n                        // Can't get LOGFONT from the existing setting, probably\n                        // because the user hasn't ever chosen a font before.\n                        // Set the font to something familiar.\n                        GetObject(SystemInformer_GetFont(), sizeof(LOGFONT), &font);\n                    }\n\n                    memset(&chooseFont, 0, sizeof(CHOOSEFONT));\n                    chooseFont.lStructSize = sizeof(CHOOSEFONT);\n                    chooseFont.hwndOwner = hwndDlg;\n                    chooseFont.lpfnHook = PhpChooseFontDlgHookProc;\n                    chooseFont.lpLogFont = &font;\n                    chooseFont.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK | CF_SCREENFONTS;\n\n                    if (ChooseFont(&chooseFont))\n                    {\n                        PhMoveReference(&NewFontSelection, PhBufferToHexString((PUCHAR)&font, sizeof(LOGFONT)));\n\n                        // Update the button's font.\n                        if (CurrentFontInstance) DeleteFont(CurrentFontInstance);\n                        CurrentFontInstance = CreateFontIndirect(&font);\n\n                        SetWindowFont(OptionsTreeControl, CurrentFontInstance, TRUE); // HACK\n                        SetWindowFont(GetDlgItem(hwndDlg, IDC_SETTINGS), CurrentFontInstance, TRUE);\n                        SetWindowFont(GetDlgItem(hwndDlg, IDC_FONT), CurrentFontInstance, TRUE);\n\n                        // Re-add the listview items for the new font (dmex)\n                        GeneralListViewStateInitializing = TRUE;\n                        ExtendedListView_SetRedraw(ListViewHandle, FALSE);\n                        ListView_DeleteAllItems(ListViewHandle);\n                        PhpAdvancedPageLoad(hwndDlg, FALSE);\n                        ExtendedListView_SetRedraw(ListViewHandle, TRUE);\n                        GeneralListViewStateInitializing = FALSE;\n\n                        RestartRequired = TRUE; // HACK: Fix ToolStatus plugin toolbar resize on font change\n                    }\n                }\n                break;\n            case IDC_FONTMONOSPACE:\n                {\n                    LOGFONT font;\n                    CHOOSEFONT chooseFont;\n\n                    if (!GetCurrentFontMonospace(&font))\n                    {\n                        // Can't get LOGFONT from the existing setting, probably\n                        // because the user hasn't ever chosen a font before.\n                        // Set the font to something familiar.\n                        //GetObject(SystemInformer_GetFont(), sizeof(LOGFONT), &font);\n                        GetObject(PhMonospaceFont, sizeof(LOGFONT), &font);\n                    }\n\n                    memset(&chooseFont, 0, sizeof(CHOOSEFONT));\n                    chooseFont.lStructSize = sizeof(CHOOSEFONT);\n                    chooseFont.hwndOwner = hwndDlg;\n                    chooseFont.lpfnHook = PhpChooseFontDlgHookProc;\n                    chooseFont.lpLogFont = &font;\n                    chooseFont.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK | CF_SCREENFONTS | CF_FIXEDPITCHONLY;\n\n                    if (ChooseFont(&chooseFont))\n                    {\n                        PhMoveReference(&NewFontMonospaceSelection, PhBufferToHexString((PUCHAR)&font, sizeof(LOGFONT)));\n\n                        // Update the button's font.\n                        if (CurrentFontMonospaceInstance) DeleteFont(CurrentFontMonospaceInstance);\n                        CurrentFontMonospaceInstance = CreateFontIndirect(&font);\n\n                        SetWindowFont(GetDlgItem(hwndDlg, IDC_FONTMONOSPACE), CurrentFontMonospaceInstance, TRUE);\n\n                        // Re-add the listview items for the new font (dmex)\n                        GeneralListViewStateInitializing = TRUE;\n                        ExtendedListView_SetRedraw(ListViewHandle, FALSE);\n                        ListView_DeleteAllItems(ListViewHandle);\n                        PhpAdvancedPageLoad(hwndDlg, FALSE);\n                        ExtendedListView_SetRedraw(ListViewHandle, TRUE);\n                        GeneralListViewStateInitializing = FALSE;\n\n                        RestartRequired = TRUE; // HACK: Fix ToolStatus plugin toolbar resize on font change\n                    }\n                }\n                break;\n            case IDC_REPLACETASKMANAGER:\n                {\n                    WindowHandleForElevate = hwndDlg;\n\n                    PhCreateThread2(PhpElevateAdvancedThreadStart, PhFormatString(\n                        L\"-showoptions -hwnd %Ix\",\n                        (ULONG_PTR)PhOptionsWindowHandle // GetParent(GetParent(hwndDlg))\n                        ));\n                }\n                break;\n            case IDC_SAMPLECOUNTAUTOMATIC:\n                {\n                    EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), Button_GetCheck(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC)) != BST_CHECKED);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_PH_CHILD_EXIT:\n        {\n            PhpRefreshTaskManagerState(hwndDlg);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&LayoutManager);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case NM_CLICK:\n            case NM_DBLCLK:\n                {\n                    LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header;\n                    LVHITTESTINFO lvHitInfo;\n\n                    lvHitInfo.pt = itemActivate->ptAction;\n\n                    if (ListView_HitTest(ListViewHandle, &lvHitInfo) != -1)\n                    {\n                        // Ignore click notifications for the listview checkbox region.\n                        if (!(lvHitInfo.flags & LVHT_ONITEMSTATEICON))\n                        {\n                            BOOLEAN itemChecked;\n\n                            // Emulate the checkbox control label click behavior and check/uncheck the checkbox when the listview item is clicked.\n                            itemChecked = ListView_GetCheckState(ListViewHandle, itemActivate->iItem) == BST_CHECKED;\n                            ListView_SetCheckState(ListViewHandle, itemActivate->iItem, !itemChecked);\n                        }\n                    }\n                }\n                break;\n            case LVN_ITEMCHANGING:\n                {\n                    LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam;\n\n                    if (listView->uChanged & LVIF_STATE)\n                    {\n                        if (GeneralListViewStateInitializing)\n                            break;\n\n                        switch (listView->uNewState & LVIS_STATEIMAGEMASK)\n                        {\n                        case INDEXTOSTATEIMAGEMASK(2): // checked\n                            {\n                                switch (listView->iItem)\n                                {\n                                case PHP_OPTIONS_INDEX_HIDE_WHENCLOSED:\n                                case PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED:\n                                case PHP_OPTIONS_INDEX_START_HIDDEN:\n                                    {\n                                        if (!PhNfIconsEnabled())\n                                        {\n                                            PhShowInformation2(\n                                                PhOptionsWindowHandle,\n                                                L\"Unable to configure this option.\",\n                                                L\"%s\",\n                                                L\"You need to enable at minimum one tray icon (View menu > Tray Icons) before enabling the hide option.\"\n                                                );\n                                            SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);\n                                            return TRUE;\n                                        }\n                                    }\n                                    break;\n                                case PHP_OPTIONS_INDEX_ENABLE_START_ASADMIN:\n                                    {\n                                        PPH_STRING applicationFileName;\n\n                                        if (!PhGetOwnTokenAttributes().Elevated)\n                                        {\n                                            PhShowInformation2(\n                                                PhOptionsWindowHandle,\n                                                L\"Unable to enable option start as admin.\",\n                                                L\"%s\",\n                                                L\"You need to enable this option with administrative privileges.\"\n                                                );\n\n                                            SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);\n                                            return TRUE;\n                                        }\n\n                                        if (applicationFileName = PhGetApplicationFileNameWin32())\n                                        {\n                                            static const PH_STRINGREF separator = PH_STRINGREF_INIT(L\"\\\"\");\n                                            HRESULT status;\n                                            PPH_STRING quotedFileName;\n\n                                            if (!PhShowOptionsDefaultInstallLocation(PhOptionsWindowHandle, L\"Enabling the 'start as admin' option\"))\n                                            {\n                                                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);\n                                                return TRUE;\n                                            }\n\n                                            quotedFileName = PH_AUTO(PhConcatStringRef3(\n                                                &separator,\n                                                &applicationFileName->sr,\n                                                &separator\n                                                ));\n\n                                            status = PhCreateAdminTask(\n                                                &SI_RUNAS_ADMIN_TASK_NAME,\n                                                &quotedFileName->sr\n                                                );\n\n                                            if (FAILED(status))\n                                            {\n                                                PhShowStatus(\n                                                    PhOptionsWindowHandle,\n                                                    L\"Unable to enable start as admin.\",\n                                                    0,\n                                                    HRESULT_CODE(status)\n                                                    );\n\n                                                PhDereferenceObject(applicationFileName);\n                                                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);\n                                                return TRUE;\n                                            }\n\n                                            PhDereferenceObject(applicationFileName);\n                                        }\n                                    }\n                                    break;\n                                }\n                            }\n                            break;\n                        }\n                    }\n                }\n                break;\n            case LVN_ITEMCHANGED:\n                {\n                    LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam;\n\n                    if (listView->uChanged & LVIF_STATE)\n                    {\n                        if (GeneralListViewStateInitializing)\n                            break;\n\n                        switch (listView->uNewState & LVIS_STATEIMAGEMASK)\n                        {\n                        case INDEXTOSTATEIMAGEMASK(2): // checked\n                            {\n                                switch (listView->iItem)\n                                {\n                                case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS:\n                                    {\n                                        PhSetIntegerSetting(SETTING_ENABLE_ADVANCED_OPTIONS, TRUE);\n                                        PhpOptionsShowHideTreeViewItem(FALSE);\n                                    }\n                                    break;\n                                case PHP_OPTIONS_INDEX_ENABLE_START_ASADMIN:\n                                    break;\n                                }\n                            }\n                            break;\n                        case INDEXTOSTATEIMAGEMASK(1): // unchecked\n                            {\n                                switch (listView->iItem)\n                                {\n                                case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS:\n                                    {\n                                        PhSetIntegerSetting(SETTING_ENABLE_ADVANCED_OPTIONS, FALSE);\n                                        PhpOptionsShowHideTreeViewItem(TRUE);\n                                    }\n                                    break;\n                                case PHP_OPTIONS_INDEX_ENABLE_START_ASADMIN:\n                                    {\n                                        if (PhGetIntegerSetting(SETTING_ENABLE_START_AS_ADMIN))\n                                        {\n                                            PhDeleteAdminTask(&SI_RUNAS_ADMIN_TASK_NAME);\n                                        }\n                                    }\n                                    break;\n                                }\n                            }\n                            break;\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    //case WM_CTLCOLORSTATIC:\n    //    {\n    //        static HFONT BoldFont = NULL; // leak\n    //        HWND control = (HWND)lParam;\n    //        HDC hdc = (HDC)wParam;\n    //\n    //        if (GetDlgCtrlID(control) == IDC_DEFSTATE)\n    //        {\n    //            if (!BoldFont)\n    //                BoldFont = PhDuplicateFontWithNewWeight(GetWindowFont(control), FW_BOLD);\n    //\n    //            SetBkMode(hdc, TRANSPARENT);\n    //\n    //            if (!PhpIsDefaultTaskManager())\n    //            {\n    //                SelectFont(hdc, BoldFont);\n    //            }\n    //        }\n    //    }\n    //    break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nstatic INT_PTR CALLBACK PhpOptionsAdvancedEditDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    static PH_LAYOUT_MANAGER LayoutManager;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_SETTING setting = (PPH_SETTING)lParam;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhSetWindowText(hwndDlg, L\"Setting Editor\");\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, setting);\n\n            PhInitializeLayoutManager(&LayoutManager, hwndDlg);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_NAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_VALUE), NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            PhSetDialogItemText(hwndDlg, IDC_NAME, setting->Name.Buffer);\n            PhSetDialogItemText(hwndDlg, IDC_VALUE, PH_AUTO_T(PH_STRING, PhSettingToString(setting->Type, setting))->Buffer);\n\n            EnableWindow(GetDlgItem(hwndDlg, IDC_NAME), FALSE);\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDCANCEL));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDeleteLayoutManager(&LayoutManager);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            PhLayoutManagerUpdate(&LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&LayoutManager);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    PPH_SETTING setting = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n                    PPH_STRING settingValue = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_VALUE)));\n\n                    if (!PhSettingFromString(\n                        setting->Type,\n                        &settingValue->sr,\n                        settingValue,\n                        setting\n                        ))\n                    {\n                        PhSettingFromString(\n                            setting->Type,\n                            &setting->DefaultValue,\n                            NULL,\n                            setting\n                            );\n                    }\n\n                    PhReloadGeneralSection();\n\n                    EndDialog(hwndDlg, IDOK);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\n#pragma region Plugin TreeList\n\n#define WM_PH_OPTIONS_ADVANCED (WM_APP + 451)\n\ntypedef struct _PH_OPTIONS_ADVANCED_CONTEXT\n{\n    PH_LAYOUT_MANAGER LayoutManager;\n\n    HWND WindowHandle;\n    HWND TreeNewHandle;\n    HWND SearchBoxHandle;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG HideModified : 1;\n            ULONG HideDefault : 1;\n            ULONG HighlightModified : 1;\n            ULONG HighlightDefault : 1;\n            ULONG Spare : 28;\n        };\n    };\n\n    ULONG TreeNewSortColumn;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PH_TN_FILTER_SUPPORT TreeFilterSupport;\n    PPH_TN_FILTER_ENTRY TreeFilterEntry;\n    PPH_HASHTABLE NodeHashtable;\n    PPH_LIST NodeList;\n    ULONG_PTR SearchMatchHandle;\n} PH_OPTIONS_ADVANCED_CONTEXT, *PPH_OPTIONS_ADVANCED_CONTEXT;\n\ntypedef enum _PH_OPTIONS_ADVANCED_TREE_ITEM_MENU\n{\n    PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIDE_MODIFIED = 1,\n    PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIDE_DEFAULT,\n    PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIGHLIGHT_MODIFIED,\n    PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIGHLIGHT_DEFAULT,\n} PH_OPTIONS_ADVANCED_ITEM_MENU;\n\ntypedef enum _PH_OPTIONS_ADVANCED_COLUMN_ITEM\n{\n    PH_OPTIONS_ADVANCED_COLUMN_ITEM_NAME,\n    PH_OPTIONS_ADVANCED_COLUMN_ITEM_TYPE,\n    PH_OPTIONS_ADVANCED_COLUMN_ITEM_VALUE,\n    PH_OPTIONS_ADVANCED_COLUMN_ITEM_DEFAULT,\n    PH_OPTIONS_ADVANCED_COLUMN_ITEM_MAXIMUM\n} PH_OPTIONS_ADVANCED_COLUMN_ITEM;\n\ntypedef struct _PH_OPTIONS_ADVANCED_ROOT_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PH_SETTING_TYPE Type;\n    PPH_SETTING Setting;\n    PPH_STRING Name;\n    PPH_STRING ValueString;\n    PPH_STRING DefaultString;\n\n    PH_STRINGREF TextCache[PH_OPTIONS_ADVANCED_COLUMN_ITEM_MAXIMUM];\n} PH_OPTIONS_ADVANCED_ROOT_NODE, *PPH_OPTIONS_ADVANCED_ROOT_NODE;\n\n\n#define SORT_FUNCTION(Column) OptionsAdvancedTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static long __cdecl OptionsAdvancedTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_OPTIONS_ADVANCED_ROOT_NODE node1 = *(PPH_OPTIONS_ADVANCED_ROOT_NODE*)_elem1; \\\n    PPH_OPTIONS_ADVANCED_ROOT_NODE node2 = *(PPH_OPTIONS_ADVANCED_ROOT_NODE*)_elem2; \\\n    LONG sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \\\n    \\\n    return PhModifySort(sortResult, ((PPH_OPTIONS_ADVANCED_CONTEXT)_context)->TreeNewSortOrder); \\\n}\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareString(node1->Name, node2->Name, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Type)\n{\n    sortResult = uintcmp(node1->Type, node2->Type);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Value)\n{\n    sortResult = PhCompareString(node1->ValueString, node2->ValueString, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Default)\n{\n    sortResult = PhCompareString(node1->DefaultString, node2->DefaultString, TRUE);\n}\nEND_SORT_FUNCTION\n\nVOID OptionsAdvancedLoadSettingsTreeList(\n    _Inout_ PPH_OPTIONS_ADVANCED_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhGetStringSetting(SETTING_OPTIONS_WINDOW_ADVANCED_COLUMNS);\n    Context->Flags = PhGetIntegerSetting(SETTING_OPTIONS_WINDOW_ADVANCED_FLAGS);\n    PhCmLoadSettings(Context->TreeNewHandle, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\nVOID OptionsAdvancedSaveSettingsTreeList(\n    _Inout_ PPH_OPTIONS_ADVANCED_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhCmSaveSettings(Context->TreeNewHandle);\n    PhSetStringSetting2(SETTING_OPTIONS_WINDOW_ADVANCED_COLUMNS, &settings->sr);\n    PhSetIntegerSetting(SETTING_OPTIONS_WINDOW_ADVANCED_FLAGS, Context->Flags);\n    PhDereferenceObject(settings);\n}\n\nVOID OptionsAdvancedSetOptionsTreeList(\n    _Inout_ PPH_OPTIONS_ADVANCED_CONTEXT Context,\n    _In_ ULONG Options\n    )\n{\n    switch (Options)\n    {\n    case PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIDE_MODIFIED:\n        Context->HideModified = !Context->HideModified;\n        break;\n    case PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIDE_DEFAULT:\n        Context->HideDefault = !Context->HideDefault;\n        break;\n    case PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIGHLIGHT_MODIFIED:\n        Context->HighlightModified = !Context->HighlightModified;\n        break;\n    case PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIGHLIGHT_DEFAULT:\n        Context->HighlightDefault = !Context->HighlightDefault;\n        break;\n    }\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN OptionsAdvancedNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_OPTIONS_ADVANCED_ROOT_NODE node1 = *(PPH_OPTIONS_ADVANCED_ROOT_NODE*)Entry1;\n    PPH_OPTIONS_ADVANCED_ROOT_NODE node2 = *(PPH_OPTIONS_ADVANCED_ROOT_NODE*)Entry2;\n\n    return PhEqualStringRef(&node1->Name->sr, &node2->Name->sr, TRUE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG OptionsAdvancedNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashStringRefEx(&(*(PPH_OPTIONS_ADVANCED_ROOT_NODE*)Entry)->Name->sr, TRUE, PH_STRING_HASH_X65599);\n}\n\nVOID DestroyOptionsAdvancedNode(\n    _In_ PPH_OPTIONS_ADVANCED_ROOT_NODE Node\n    )\n{\n    PhClearReference(&Node->Name);\n    PhClearReference(&Node->ValueString);\n    PhClearReference(&Node->DefaultString);\n\n    PhFree(Node);\n}\n\nPPH_OPTIONS_ADVANCED_ROOT_NODE AddOptionsAdvancedNode(\n    _Inout_ PPH_OPTIONS_ADVANCED_CONTEXT Context,\n    _In_ PPH_SETTING Setting\n    )\n{\n    PPH_OPTIONS_ADVANCED_ROOT_NODE node;\n\n    node = PhAllocate(sizeof(PH_OPTIONS_ADVANCED_ROOT_NODE));\n    memset(node, 0, sizeof(PH_OPTIONS_ADVANCED_ROOT_NODE));\n\n    PhInitializeTreeNewNode(&node->Node);\n\n    memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PH_OPTIONS_ADVANCED_COLUMN_ITEM_MAXIMUM);\n    node->Node.TextCache = node->TextCache;\n    node->Node.TextCacheSize = PH_OPTIONS_ADVANCED_COLUMN_ITEM_MAXIMUM;\n\n    node->Setting = Setting;\n    node->Type = Setting->Type;\n    node->Name = PhCreateString2(&Setting->Name);\n    node->ValueString = PhSettingToString(Setting->Type, Setting);\n    node->DefaultString = PhCreateString2(&Setting->DefaultValue);\n\n    PhAddEntryHashtable(Context->NodeHashtable, &node);\n    PhAddItemList(Context->NodeList, node);\n\n    if (Context->TreeFilterSupport.FilterList)\n        node->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &node->Node);\n\n    return node;\n}\n\nPPH_OPTIONS_ADVANCED_ROOT_NODE FindOptionsAdvancedNode(\n    _In_ PPH_OPTIONS_ADVANCED_CONTEXT Context,\n    _In_ PPH_STRING Name\n    )\n{\n    PH_OPTIONS_ADVANCED_ROOT_NODE lookupPluginsNode;\n    PPH_OPTIONS_ADVANCED_ROOT_NODE lookupPluginsNodePtr = &lookupPluginsNode;\n    PPH_OPTIONS_ADVANCED_ROOT_NODE* pluginsNode;\n\n    lookupPluginsNode.Name = Name;\n\n    pluginsNode = (PPH_OPTIONS_ADVANCED_ROOT_NODE*)PhFindEntryHashtable(\n        Context->NodeHashtable,\n        &lookupPluginsNodePtr\n        );\n\n    if (pluginsNode)\n        return *pluginsNode;\n    else\n        return NULL;\n}\n\nVOID RemoveOptionsAdvancedNode(\n    _In_ PPH_OPTIONS_ADVANCED_CONTEXT Context,\n    _In_ PPH_OPTIONS_ADVANCED_ROOT_NODE Node\n    )\n{\n    ULONG index = 0;\n\n    PhRemoveEntryHashtable(Context->NodeHashtable, &Node);\n\n    if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX)\n    {\n        PhRemoveItemList(Context->NodeList, index);\n    }\n\n    DestroyOptionsAdvancedNode(Node);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID UpdateOptionsAdvancedNode(\n    _In_ PPH_OPTIONS_ADVANCED_CONTEXT Context,\n    _In_ PPH_OPTIONS_ADVANCED_ROOT_NODE Node\n    )\n{\n    memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * PH_OPTIONS_ADVANCED_COLUMN_ITEM_MAXIMUM);\n\n    PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nBOOLEAN NTAPI OptionsAdvancedTreeNewCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_OPTIONS_ADVANCED_CONTEXT context = Context;\n    PPH_OPTIONS_ADVANCED_ROOT_NODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_OPTIONS_ADVANCED_ROOT_NODE)getChildren->Node;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(Name),\n                    SORT_FUNCTION(Type),\n                    SORT_FUNCTION(Value),\n                    SORT_FUNCTION(Default),\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                if (context->TreeNewSortColumn < PH_OPTIONS_ADVANCED_COLUMN_ITEM_MAXIMUM)\n                    sortFunction = sortFunctions[context->TreeNewSortColumn];\n                else\n                    sortFunction = NULL;\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE*)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1;\n            node = (PPH_OPTIONS_ADVANCED_ROOT_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1;\n            node = (PPH_OPTIONS_ADVANCED_ROOT_NODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case PH_OPTIONS_ADVANCED_COLUMN_ITEM_NAME:\n                getCellText->Text = PhGetStringRef(node->Name);\n                break;\n            case PH_OPTIONS_ADVANCED_COLUMN_ITEM_TYPE:\n                {\n                    switch (node->Type)\n                    {\n                    case StringSettingType:\n                        PhInitializeStringRef(&getCellText->Text, L\"String\");\n                        break;\n                    case IntegerSettingType:\n                        PhInitializeStringRef(&getCellText->Text, L\"Integer\");\n                        break;\n                    case IntegerPairSettingType:\n                        PhInitializeStringRef(&getCellText->Text, L\"IntegerPair\");\n                        break;\n                    case ScalableIntegerPairSettingType:\n                        PhInitializeStringRef(&getCellText->Text, L\"ScalableIntegerPair\");\n                        break;\n                    }\n                }\n                break;\n            case PH_OPTIONS_ADVANCED_COLUMN_ITEM_VALUE:\n                getCellText->Text = PhGetStringRef(node->ValueString);\n                break;\n            case PH_OPTIONS_ADVANCED_COLUMN_ITEM_DEFAULT:\n                getCellText->Text = PhGetStringRef(node->DefaultString);\n                break;\n            default:\n                return FALSE;\n            }\n\n            //getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            node = (PPH_OPTIONS_ADVANCED_ROOT_NODE)getNodeColor->Node;\n\n            switch (node->Type)\n            {\n            case StringSettingType:\n            case IntegerPairSettingType:\n            case ScalableIntegerPairSettingType:\n                {\n                    if (PhEqualString(node->DefaultString, node->ValueString, TRUE))\n                    {\n                        if (context->HighlightDefault)\n                        {\n                            getNodeColor->BackColor = PhCsColorServiceProcesses;\n                        }\n                    }\n                    else\n                    {\n                        if (context->HighlightModified)\n                        {\n                            getNodeColor->BackColor = PhCsColorSystemProcesses;\n                        }\n                    }\n                }\n                break;\n            case IntegerSettingType:\n                {\n                    ULONG64 integer;\n\n                    if (PhStringToInteger64(&node->DefaultString->sr, 16, &integer))\n                    {\n                        if (node->Setting->u.Integer == (ULONG)integer)\n                        {\n                            if (context->HighlightDefault)\n                            {\n                                getNodeColor->BackColor = PhCsColorServiceProcesses;\n                            }\n                        }\n                        else\n                        {\n                            if (context->HighlightModified)\n                            {\n                                getNodeColor->BackColor = PhCsColorSystemProcesses;\n                            }\n                        }\n                    }\n                }\n                break;\n            }\n\n            getNodeColor->Flags = TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(hwnd);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->WindowHandle, WM_COMMAND, IDC_COPY, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1;\n\n            SendMessage(context->WindowHandle, WM_COMMAND, WM_PH_OPTIONS_ADVANCED, (LPARAM)mouseEvent);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1;\n\n            SendMessage(context->WindowHandle, WM_CONTEXTMENU, (WPARAM)hwnd, (LPARAM)contextMenuEvent);\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = hwnd;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = 0;\n            data.DefaultSortOrder = AscendingSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID ClearOptionsAdvancedTree(\n    _In_ PPH_OPTIONS_ADVANCED_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        DestroyOptionsAdvancedNode(Context->NodeList->Items[i]);\n\n    PhClearHashtable(Context->NodeHashtable);\n    PhClearList(Context->NodeList);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nPPH_OPTIONS_ADVANCED_ROOT_NODE GetSelectedOptionsAdvancedNode(\n    _In_ PPH_OPTIONS_ADVANCED_CONTEXT Context\n    )\n{\n    PPH_OPTIONS_ADVANCED_ROOT_NODE optionsNode = NULL;\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        optionsNode = Context->NodeList->Items[i];\n\n        if (optionsNode->Node.Selected)\n            return optionsNode;\n    }\n\n    return NULL;\n}\n\n_Success_(return)\nBOOLEAN GetSelectedOptionsAdvancedNodes(\n    _In_ PPH_OPTIONS_ADVANCED_CONTEXT Context,\n    _Out_ PPH_OPTIONS_ADVANCED_ROOT_NODE** Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_OPTIONS_ADVANCED_ROOT_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            PhAddItemList(list, node);\n        }\n    }\n\n    if (list->Count)\n    {\n        *Nodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\nVOID InitializeOptionsAdvancedTree(\n    _Inout_ PPH_OPTIONS_ADVANCED_CONTEXT Context\n    )\n{\n    Context->NodeList = PhCreateList(100);\n    Context->NodeHashtable = PhCreateHashtable(\n        sizeof(PPH_OPTIONS_ADVANCED_ROOT_NODE),\n        OptionsAdvancedNodeHashtableEqualFunction,\n        OptionsAdvancedNodeHashtableHashFunction,\n        100\n        );\n\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n    TreeNew_SetCallback(Context->TreeNewHandle, OptionsAdvancedTreeNewCallback, Context);\n\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PH_OPTIONS_ADVANCED_COLUMN_ITEM_NAME, TRUE, L\"Name\", 200, PH_ALIGN_LEFT, 0, 0, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PH_OPTIONS_ADVANCED_COLUMN_ITEM_TYPE, TRUE, L\"Type\", 100, PH_ALIGN_LEFT, 1, 0, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PH_OPTIONS_ADVANCED_COLUMN_ITEM_VALUE, TRUE, L\"Value\", 200, PH_ALIGN_LEFT, 2, 0, TRUE);\n    PhAddTreeNewColumnEx(Context->TreeNewHandle, PH_OPTIONS_ADVANCED_COLUMN_ITEM_DEFAULT, TRUE, L\"Default\", 200, PH_ALIGN_LEFT, 3, 0, TRUE);\n\n    PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList);\n\n    TreeNew_SetTriState(Context->TreeNewHandle, TRUE);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n\n    OptionsAdvancedLoadSettingsTreeList(Context);\n}\n\nVOID DeleteOptionsAdvancedTree(\n    _In_ PPH_OPTIONS_ADVANCED_CONTEXT Context\n    )\n{\n    PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport);\n\n    OptionsAdvancedSaveSettingsTreeList(Context);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        DestroyOptionsAdvancedNode(Context->NodeList->Items[i]);\n\n    PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n}\n\n#pragma endregion\n\n_Function_class_(PH_SETTINGS_ENUM_CALLBACK)\nstatic BOOLEAN PhpOptionsSettingsCallback(\n    _In_ PPH_SETTING Setting,\n    _In_ PVOID Context\n    )\n{\n    PPH_OPTIONS_ADVANCED_CONTEXT context = Context;\n\n    AddOptionsAdvancedNode(context, Setting);\n    return TRUE;\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhpOptionsAdvancedTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PVOID Context\n    )\n{\n    PPH_OPTIONS_ADVANCED_ROOT_NODE node = (PPH_OPTIONS_ADVANCED_ROOT_NODE)Node;\n    PPH_OPTIONS_ADVANCED_CONTEXT context = Context;\n\n    if (context->HideModified)\n    {\n        switch (node->Type)\n        {\n        case StringSettingType:\n        case IntegerPairSettingType:\n        case ScalableIntegerPairSettingType:\n            {\n                if (PhEqualString(node->DefaultString, node->ValueString, TRUE))\n                {\n                    if (context->HideDefault)\n                    {\n                        return FALSE;\n                    }\n                }\n                else\n                {\n                    if (context->HideModified)\n                    {\n                        return FALSE;\n                    }\n                }\n            }\n            break;\n        case IntegerSettingType:\n            {\n                ULONG64 integer;\n\n                if (PhStringToInteger64(&node->DefaultString->sr, 16, &integer))\n                {\n                    if (node->Setting->u.Integer == (ULONG)integer)\n                    {\n                        if (context->HideDefault)\n                        {\n                            return FALSE;\n                        }\n                    }\n                    else\n                    {\n                        if (context->HideModified)\n                        {\n                            return FALSE;\n                        }\n                    }\n                }\n            }\n            break;\n        }\n    }\n\n    if (context->HideDefault)\n    {\n        switch (node->Type)\n        {\n        case StringSettingType:\n        case IntegerPairSettingType:\n        case ScalableIntegerPairSettingType:\n            {\n                if (PhEqualString(node->DefaultString, node->ValueString, TRUE))\n                {\n                    if (context->HideDefault)\n                    {\n                        return FALSE;\n                    }\n                }\n                else\n                {\n                    if (context->HideModified)\n                    {\n                        return FALSE;\n                    }\n                }\n            }\n            break;\n        case IntegerSettingType:\n            {\n                ULONG64 integer;\n\n                if (PhStringToInteger64(&node->DefaultString->sr, 16, &integer))\n                {\n                    if (node->Setting->u.Integer == (ULONG)integer)\n                    {\n                        if (context->HideDefault)\n                        {\n                            return FALSE;\n                        }\n                    }\n                    else\n                    {\n                        if (context->HideModified)\n                        {\n                            return FALSE;\n                        }\n                    }\n                }\n            }\n            break;\n        }\n    }\n\n    if (!context->SearchMatchHandle)\n        return TRUE;\n\n    if (PhSearchControlMatch(context->SearchMatchHandle, &node->Name->sr))\n        return TRUE;\n    if (PhSearchControlMatch(context->SearchMatchHandle, &node->DefaultString->sr))\n        return TRUE;\n    if (PhSearchControlMatch(context->SearchMatchHandle, &node->ValueString->sr))\n        return TRUE;\n\n    return FALSE;\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhpOptionsAdvancedSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_OPTIONS_ADVANCED_CONTEXT context = Context;\n\n    assert(context);\n\n    context->SearchMatchHandle = MatchHandle;\n\n    if (!context->SearchMatchHandle)\n    {\n        // Expand the nodes?\n    }\n\n    PhApplyTreeNewFilters(&context->TreeFilterSupport);\n}\n\nINT_PTR CALLBACK PhpOptionsAdvancedDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_OPTIONS_ADVANCED_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocateZero(sizeof(PH_OPTIONS_ADVANCED_CONTEXT));\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS);\n            context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCH);\n\n            PhCreateSearchControl(\n                hwndDlg,\n                context->SearchBoxHandle,\n                L\"Search settings...\",\n                PhpOptionsAdvancedSearchControlCallback,\n                context\n                );\n\n            InitializeOptionsAdvancedTree(context);\n            context->TreeFilterEntry = PhAddTreeNewFilter(&context->TreeFilterSupport, PhpOptionsAdvancedTreeFilterCallback, context);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->SearchBoxHandle, NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL);\n\n            PhEnumSettings(PhpOptionsSettingsCallback, context);\n            TreeNew_NodesStructured(context->TreeNewHandle);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhRemoveTreeNewFilter(&context->TreeFilterSupport, context->TreeFilterEntry);\n            DeleteOptionsAdvancedTree(context);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDOK:\n            case IDCANCEL:\n                {\n                    DestroyWindow(hwndDlg);\n                }\n                break;\n            case IDC_FILTEROPTIONS:\n                {\n                    RECT rect;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM hidemodifiedMenuItem;\n                    PPH_EMENU_ITEM hidedefaultMenuItem;\n                    PPH_EMENU_ITEM highlightmodifiedMenuItem;\n                    PPH_EMENU_ITEM highlightdefaultMenuItem;\n                    PPH_EMENU_ITEM selectedItem;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect))\n                        break;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, hidemodifiedMenuItem = PhCreateEMenuItem(0, PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIDE_MODIFIED, L\"Hide modified\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, hidedefaultMenuItem = PhCreateEMenuItem(0, PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIDE_DEFAULT, L\"Hide default\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, highlightmodifiedMenuItem = PhCreateEMenuItem(0, PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIGHLIGHT_MODIFIED, L\"Highlight modified\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, highlightdefaultMenuItem = PhCreateEMenuItem(0, PH_OPTIONS_ADVANCED_TREE_ITEM_MENU_HIGHLIGHT_DEFAULT, L\"Highlight default\", NULL, NULL), ULONG_MAX);\n\n                    if (context->HideModified)\n                        hidemodifiedMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HideDefault)\n                        hidedefaultMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightModified)\n                        highlightmodifiedMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightDefault)\n                        highlightdefaultMenuItem->Flags |= PH_EMENU_CHECKED;\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        rect.left,\n                        rect.bottom\n                        );\n\n                    if (selectedItem && selectedItem->Id)\n                    {\n                        OptionsAdvancedSetOptionsTreeList(context, selectedItem->Id);\n\n                        PhApplyTreeNewFilters(&context->TreeFilterSupport);\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            case IDC_REFRESH:\n                {\n                    ClearOptionsAdvancedTree(context);\n                    PhEnumSettings(PhpOptionsSettingsCallback, context);\n                    TreeNew_NodesStructured(context->TreeNewHandle);\n\n                    PhApplyTreeNewFilters(&context->TreeFilterSupport);\n                }\n                break;\n            case WM_PH_OPTIONS_ADVANCED:\n                {\n                    PPH_OPTIONS_ADVANCED_ROOT_NODE node;\n\n                    if (node = GetSelectedOptionsAdvancedNode(context))\n                    {\n                        PhDialogBox(\n                            PhInstanceHandle,\n                            MAKEINTRESOURCE(IDD_EDITENV),\n                            hwndDlg,\n                            PhpOptionsAdvancedEditDlgProc,\n                            node->Setting\n                            );\n\n                        PhMoveReference(\n                            &node->ValueString,\n                            PhSettingToString(node->Setting->Type, node->Setting)\n                            );\n\n                        TreeNew_NodesStructured(context->TreeNewHandle);\n                    }\n                }\n                break;\n            case IDC_COPY:\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(context->TreeNewHandle, 0);\n                    PhSetClipboardString(context->TreeNewHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            case IDC_RESET:\n                {\n                    PPH_OPTIONS_ADVANCED_ROOT_NODE* nodes;\n                    ULONG numberOfNodes;\n                    if (!GetSelectedOptionsAdvancedNodes(context, &nodes, &numberOfNodes))\n                        break;\n                    for (ULONG i = 0; i < numberOfNodes; i++)\n                    {\n                        PhSettingFromString(\n                            nodes[i]->Setting->Type,\n                            &nodes[i]->Setting->DefaultValue,\n                            NULL,\n                            nodes[i]->Setting\n                            );\n                        PhMoveReference(\n                            &nodes[i]->ValueString,\n                            PhSettingToString(nodes[i]->Setting->Type, nodes[i]->Setting)\n                            );\n                    }\n                    TreeNew_NodesStructured(context->TreeNewHandle);\n                    PhApplyTreeNewFilters(&context->TreeFilterSupport);\n\n                    PhReloadGeneralSection();\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->TreeNewHandle)\n            {\n                PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam;\n                PPH_OPTIONS_ADVANCED_ROOT_NODE* nodes;\n                ULONG numberOfNodes;\n\n                if (!GetSelectedOptionsAdvancedNodes(context, &nodes, &numberOfNodes))\n                    break;\n\n                if (numberOfNodes != 0)\n                {\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM item;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_RESET, L\"&Reset\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyCellEMenuItem(menu, IDC_COPY, context->TreeNewHandle, contextMenuEvent->Column);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        contextMenuEvent->Location.x,\n                        contextMenuEvent->Location.y\n                        );\n\n                    if (item)\n                    {\n                        if (!PhHandleCopyCellEMenuItem(item))\n                        {\n                            SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(nodes);\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            REFLECT_MESSAGE_DLG(hwndDlg, context->TreeNewHandle, uMsg, wParam, lParam);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\ntypedef struct _COLOR_ITEM\n{\n    PCWSTR SettingName;\n    PCWSTR UseSettingName;\n    PCWSTR Name;\n    PCWSTR Description;\n\n    BOOLEAN CurrentUse;\n    COLORREF CurrentColor;\n} COLOR_ITEM, *PCOLOR_ITEM;\n\n#define COLOR_ITEM(SettingName, Name, Description) { SettingName, L\"Use\" SettingName, Name, Description }\n\nstatic COLOR_ITEM ColorItems[] =\n{\n    COLOR_ITEM(SETTING_COLOR_OWN_PROCESSES, L\"Own processes\", L\"Processes running under the same user account as System Informer.\"),\n    COLOR_ITEM(SETTING_COLOR_SYSTEM_PROCESSES, L\"System processes\", L\"Processes running under the NT AUTHORITY\\\\SYSTEM user account.\"),\n    COLOR_ITEM(SETTING_COLOR_SERVICE_PROCESSES, L\"Service processes\", L\"Processes which host one or more services.\"),\n    COLOR_ITEM(SETTING_COLOR_BACKGROUND_PROCESSES, L\"Background processes\", L\"Processes with a background scheduling priority.\"),\n    COLOR_ITEM(SETTING_COLOR_JOB_PROCESSES, L\"Job processes\", L\"Processes associated with a job.\"),\n#ifdef _WIN64\n    COLOR_ITEM(SETTING_COLOR_WOW64_PROCESSES, L\"32-bit processes\", L\"Processes running under WOW64, i.e. 32-bit.\"),\n#endif\n    COLOR_ITEM(SETTING_COLOR_DEBUGGED_PROCESSES, L\"Debugged processes\", L\"Processes that are currently being debugged.\"),\n    COLOR_ITEM(SETTING_COLOR_ELEVATED_PROCESSES, L\"Elevated processes\", L\"Processes with full privileges on a system with UAC enabled.\"),\n    COLOR_ITEM(SETTING_COLOR_UI_ACCESS_PROCESSES, L\"UIAccess processes\", L\"Processes with UIAccess privileges.\"),\n    COLOR_ITEM(SETTING_COLOR_PICO_PROCESSES, L\"Pico processes\", L\"Processes that belong to the Windows subsystem for Linux.\"),\n    COLOR_ITEM(SETTING_COLOR_IMMERSIVE_PROCESSES, L\"Immersive processes and DLLs\", L\"Processes and DLLs that belong to a Modern UI app.\"),\n    COLOR_ITEM(SETTING_COLOR_SUSPENDED, L\"Suspended processes and threads\", L\"Processes and threads that are suspended from execution.\"),\n    COLOR_ITEM(SETTING_COLOR_PARTIALLY_SUSPENDED, L\"Partially suspended processes and threads\", L\"Processes and threads that are partially suspended from execution.\"),\n    COLOR_ITEM(SETTING_COLOR_DOT_NET, L\".NET processes and DLLs\", L\".NET (i.e. managed) processes and DLLs.\"),\n    COLOR_ITEM(SETTING_COLOR_PACKED, L\"Packed processes\", L\"Executables are sometimes \\\"packed\\\" to reduce their size.\"),\n    COLOR_ITEM(SETTING_COLOR_LOW_IMAGE_COHERENCY, L\"Low process image coherency\", L\"The image file backing the process has low coherency when compared to the mapped image.\"),\n    COLOR_ITEM(SETTING_COLOR_GUI_THREADS, L\"GUI threads\", L\"Threads that have made at least one GUI-related system call.\"),\n    COLOR_ITEM(SETTING_COLOR_RELOCATED_MODULES, L\"Relocated DLLs\", L\"DLLs that were not loaded at their preferred image bases.\"),\n    COLOR_ITEM(SETTING_COLOR_PROTECTED_HANDLES, L\"Protected handles\", L\"Handles that are protected from being closed.\"),\n    COLOR_ITEM(SETTING_COLOR_PROTECTED_PROCESS, L\"Protected processes\", L\"Processes with built-in protection levels.\"),\n    COLOR_ITEM(SETTING_COLOR_INHERIT_HANDLES, L\"Inheritable handles\", L\"Handles that can be inherited by child processes.\"),\n    COLOR_ITEM(SETTING_COLOR_HANDLE_FILTERED, L\"Filtered processes\", L\"Processes that are protected by handle object callbacks.\"),\n    COLOR_ITEM(SETTING_COLOR_UNKNOWN, L\"Untrusted DLLs and Services\", L\"Services and DLLs which are not digitally signed.\"),\n    COLOR_ITEM(SETTING_COLOR_SERVICE_DISABLED, L\"Disabled Services\", L\"Services which have been disabled.\"),\n    //COLOR_ITEM(SETTING_COLOR_SERVICE_STOP, L\"Stopped Services\", L\"Services that are not running.\")\n    COLOR_ITEM(SETTING_COLOR_EFFICIENCY_MODE, L\"Power efficiency\", L\"Processes and threads with power efficiency.\"),\n};\n\nCOLORREF NTAPI PhpColorItemColorFunction(\n    _In_ INT Index,\n    _In_ PVOID Param,\n    _In_opt_ PVOID Context\n    )\n{\n    PCOLOR_ITEM item = Param;\n\n    return item->CurrentColor;\n}\n\nUINT_PTR CALLBACK PhpColorDlgHookProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhCenterWindow(hwndDlg, PhOptionsWindowHandle);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nINT_PTR CALLBACK PhpOptionsHighlightingDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    static PH_LAYOUT_MANAGER LayoutManager;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            // Highlighting Duration\n            PhSetDialogItemValue(hwndDlg, IDC_HIGHLIGHTINGDURATION, PhCsHighlightingDuration, FALSE);\n\n            // New Objects\n            ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS), PhCsColorNew);\n            ColorBox_ThemeSupport(GetDlgItem(hwndDlg, IDC_NEWOBJECTS), PhEnableThemeSupport);\n\n            // Removed Objects\n            ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS), PhCsColorRemoved);\n            ColorBox_ThemeSupport(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS), PhEnableThemeSupport);\n\n            // Highlighting\n            HighlightingListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            PhSetListViewStyle(HighlightingListViewHandle, FALSE, TRUE);\n            ListView_SetExtendedListViewStyleEx(HighlightingListViewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);\n            PhAddListViewColumn(HighlightingListViewHandle, 0, 0, 0, LVCFMT_LEFT, 240, L\"Name\");\n            PhSetExtendedListView(HighlightingListViewHandle);\n            ExtendedListView_SetItemColorFunction(HighlightingListViewHandle, PhpColorItemColorFunction);\n\n            for (ULONG i = 0; i < RTL_NUMBER_OF(ColorItems); i++)\n            {\n                INT lvItemIndex;\n\n                lvItemIndex = PhAddListViewItem(HighlightingListViewHandle, MAXINT, ColorItems[i].Name, &ColorItems[i]);\n                ColorItems[i].CurrentColor = PhGetIntegerSetting(ColorItems[i].SettingName);\n                ColorItems[i].CurrentUse = !!PhGetIntegerSetting(ColorItems[i].UseSettingName);\n                ListView_SetCheckState(HighlightingListViewHandle, lvItemIndex, ColorItems[i].CurrentUse);\n            }\n\n            PhInitializeLayoutManager(&LayoutManager, hwndDlg);\n            PhAddLayoutItem(&LayoutManager, HighlightingListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_INFO), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT | PH_LAYOUT_FORCE_INVALIDATE);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_ENABLEALL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DISABLEALL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PH_SET_INTEGER_CACHED_SETTING(HighlightingDuration, PhGetDialogItemValue(hwndDlg, IDC_HIGHLIGHTINGDURATION));\n            PH_SET_INTEGER_CACHED_SETTING(ColorNew, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS)));\n            PH_SET_INTEGER_CACHED_SETTING(ColorRemoved, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS)));\n\n            for (ULONG i = 0; i < RTL_NUMBER_OF(ColorItems); i++)\n            {\n                ColorItems[i].CurrentUse = !!ListView_GetCheckState(HighlightingListViewHandle, i);\n                PhSetIntegerSetting(ColorItems[i].SettingName, ColorItems[i].CurrentColor);\n                PhSetIntegerSetting(ColorItems[i].UseSettingName, ColorItems[i].CurrentUse);\n            }\n\n            PhDeleteLayoutManager(&LayoutManager);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            PhLayoutManagerUpdate(&LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&LayoutManager);\n\n            ExtendedListView_SetColumnWidth(HighlightingListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_ENABLEALL:\n                {\n                    for (ULONG i = 0; i < RTL_NUMBER_OF(ColorItems); i++)\n                        ListView_SetCheckState(HighlightingListViewHandle, i, TRUE);\n                }\n                break;\n            case IDC_DISABLEALL:\n                {\n                    for (ULONG i = 0; i < RTL_NUMBER_OF(ColorItems); i++)\n                        ListView_SetCheckState(HighlightingListViewHandle, i, FALSE);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case NM_DBLCLK:\n                {\n                    if (header->hwndFrom == HighlightingListViewHandle)\n                    {\n                        PCOLOR_ITEM item;\n\n                        if (item = PhGetSelectedListViewItemParam(HighlightingListViewHandle))\n                        {\n                            CHOOSECOLOR chooseColor;\n                            COLORREF customColors[16] = { 0 };\n\n                            PhLoadCustomColorList(SETTING_OPTIONS_CUSTOM_COLOR_LIST, customColors, RTL_NUMBER_OF(customColors));\n\n                            memset(&chooseColor, 0, sizeof(CHOOSECOLOR));\n                            chooseColor.lStructSize = sizeof(CHOOSECOLOR);\n                            chooseColor.hwndOwner = hwndDlg;\n                            chooseColor.rgbResult = item->CurrentColor;\n                            chooseColor.lpCustColors = customColors;\n                            chooseColor.lpfnHook = PhpColorDlgHookProc;\n                            chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK | CC_RGBINIT;\n\n                            if (ChooseColor(&chooseColor))\n                            {\n                                item->CurrentColor = chooseColor.rgbResult;\n                                InvalidateRect(HighlightingListViewHandle, NULL, TRUE);\n                            }\n\n                            PhSaveCustomColorList(SETTING_OPTIONS_CUSTOM_COLOR_LIST, customColors, RTL_NUMBER_OF(customColors));\n\n                            ListView_SetItemState(HighlightingListViewHandle, -1, 0, LVIS_SELECTED);\n                        }\n                    }\n                }\n                break;\n            case LVN_GETINFOTIP:\n                {\n                    if (header->hwndFrom == HighlightingListViewHandle)\n                    {\n                        NMLVGETINFOTIP *getInfoTip = (NMLVGETINFOTIP *)lParam;\n                        PH_STRINGREF tip;\n\n                        PhInitializeStringRefLongHint(&tip, ColorItems[getInfoTip->iItem].Description);\n                        PhCopyListViewInfoTip(getInfoTip, &tip);\n                    }\n                }\n                break;\n            }\n\n            REFLECT_MESSAGE_DLG(hwndDlg, HighlightingListViewHandle, uMsg, wParam, lParam);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == HighlightingListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PCOLOR_ITEM ColorItem;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(HighlightingListViewHandle, &point);\n\n                if (ColorItem = PhGetSelectedListViewItemParam(HighlightingListViewHandle))\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_RESET, L\"&Reset\", NULL, NULL), ULONG_MAX);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item && item->Id == IDC_RESET)\n                    {\n                        PH_STRINGREF SettingName;\n                        PH_STRINGREF UseSettingName;\n                        PPH_SETTING Color;\n                        PPH_SETTING UseColor;\n\n                        PhInitializeStringRef(&SettingName, ColorItem->SettingName);\n                        PhInitializeStringRef(&UseSettingName, ColorItem->UseSettingName);\n                        Color = PhGetSetting(&SettingName);\n                        UseColor = PhGetSetting(&UseSettingName);\n\n                        PhSettingFromString(Color->Type, &Color->DefaultValue, NULL, Color);\n                        PhSettingFromString(UseColor->Type, &UseColor->DefaultValue, NULL, UseColor);\n\n                        ColorItem->CurrentColor = Color->u.Integer;\n                        ColorItem->CurrentUse = !!UseColor->u.Integer;\n\n                        INT index = PhFindListViewItemByParam(HighlightingListViewHandle, INT_ERROR, ColorItem);\n                        ListView_SetCheckState(HighlightingListViewHandle, index, ColorItem->CurrentUse);\n                        ListView_SetItemState(HighlightingListViewHandle, index, 0, LVIS_SELECTED);\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n            }\n            else if ((HWND)wParam == GetDlgItem(hwndDlg, IDC_NEWOBJECTS) || (HWND)wParam == GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS))\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                menu = PhCreateEMenu();\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_RESET, L\"&Reset\", NULL, NULL), ULONG_MAX);\n\n                item = PhShowEMenu(\n                    menu,\n                    hwndDlg,\n                    PH_EMENU_SHOW_LEFTRIGHT,\n                    PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                    point.x,\n                    point.y\n                    );\n\n                if (item && item->Id == IDC_RESET)\n                {\n                    PH_STRINGREF SettingName;\n                    PPH_SETTING Color;\n                    BOOLEAN setNew = (HWND)wParam == GetDlgItem(hwndDlg, IDC_NEWOBJECTS);\n\n                    PhInitializeStringRef(&SettingName, setNew ? SETTING_COLOR_NEW : SETTING_COLOR_REMOVED);\n                    Color = PhGetSetting(&SettingName);\n\n                    PhSettingFromString(Color->Type, &Color->DefaultValue, NULL, Color);\n\n                    ColorBox_SetColor(GetDlgItem(hwndDlg, setNew ? IDC_NEWOBJECTS : IDC_REMOVEDOBJECTS), Color->u.Integer);\n                    InvalidateRect(GetDlgItem(hwndDlg, setNew ? IDC_NEWOBJECTS : IDC_REMOVEDOBJECTS), NULL, TRUE);\n                }\n\n                PhDestroyEMenu(menu);\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nstatic COLOR_ITEM PhpOptionsGraphColorItems[] =\n{\n    COLOR_ITEM(SETTING_COLOR_CPU_KERNEL, L\"CPU kernel\", L\"CPU kernel\"),\n    COLOR_ITEM(SETTING_COLOR_CPU_USER, L\"CPU user\", L\"CPU user\"),\n    COLOR_ITEM(SETTING_COLOR_IO_READ_OTHER, L\"I/O R+O\", L\"I/O R+O\"),\n    COLOR_ITEM(SETTING_COLOR_IO_WRITE, L\"I/O W\", L\"I/O W\"),\n    COLOR_ITEM(SETTING_COLOR_PRIVATE, L\"Private bytes\", L\"Private bytes\"),\n    COLOR_ITEM(SETTING_COLOR_PHYSICAL, L\"Physical memory\", L\"Physical memory\"),\n    COLOR_ITEM(SETTING_COLOR_POWER_USAGE, L\"Power usage\", L\"Power usage\"),\n    COLOR_ITEM(SETTING_COLOR_TEMPERATURE, L\"Temperature\", L\"Temperature\"),\n    COLOR_ITEM(SETTING_COLOR_FAN_RPM, L\"Fan RPM\", L\"Fan RPM\"),\n};\nstatic HWND PhpGraphListViewHandle = NULL;\n\nINT_PTR CALLBACK PhpOptionsGraphsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    static PH_LAYOUT_MANAGER LayoutManager;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            // Show Text\n            SetDlgItemCheckForSetting(hwndDlg, IDC_SHOWTEXT, SETTING_GRAPH_SHOW_TEXT);\n            SetDlgItemCheckForSetting(hwndDlg, IDC_USEOLDCOLORS, SETTING_GRAPH_COLOR_MODE);\n            SetDlgItemCheckForSetting(hwndDlg, IDC_SHOWCOMMITINSUMMARY, SETTING_SHOW_COMMIT_IN_SUMMARY);\n\n            // Highlighting\n            PhpGraphListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            PhSetListViewStyle(PhpGraphListViewHandle, FALSE, TRUE);\n            PhAddListViewColumn(PhpGraphListViewHandle, 0, 0, 0, LVCFMT_LEFT, 240, L\"Name\");\n            PhSetExtendedListView(PhpGraphListViewHandle);\n            ExtendedListView_SetItemColorFunction(PhpGraphListViewHandle, PhpColorItemColorFunction);\n\n            for (ULONG i = 0; i < RTL_NUMBER_OF(PhpOptionsGraphColorItems); i++)\n            {\n                INT lvItemIndex = PhAddListViewItem(PhpGraphListViewHandle, MAXINT, PhpOptionsGraphColorItems[i].Name, &PhpOptionsGraphColorItems[i]);\n                PhpOptionsGraphColorItems[i].CurrentColor = PhGetIntegerSetting(PhpOptionsGraphColorItems[i].SettingName);\n            }\n\n            PhInitializeLayoutManager(&LayoutManager, hwndDlg);\n            PhAddLayoutItem(&LayoutManager, PhpGraphListViewHandle, NULL, PH_ANCHOR_ALL);\n\n            if (PhGetIntegerSetting(SETTING_GRAPH_COLOR_MODE))\n                EnableWindow(PhpGraphListViewHandle, TRUE);\n            else if (PhEnableThemeSupport)\n            {\n                ShowWindow(PhpGraphListViewHandle, SW_HIDE);\n                EnableWindow(PhpGraphListViewHandle, TRUE);\n            }\n        }\n        break;\n    case WM_DESTROY:\n        {\n            SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWTEXT, SETTING_GRAPH_SHOW_TEXT);\n            SetSettingForDlgItemCheck(hwndDlg, IDC_USEOLDCOLORS, SETTING_GRAPH_COLOR_MODE);\n            SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWCOMMITINSUMMARY, SETTING_SHOW_COMMIT_IN_SUMMARY);\n\n            for (ULONG i = 0; i < RTL_NUMBER_OF(PhpOptionsGraphColorItems); i++)\n            {\n                PhSetIntegerSetting(PhpOptionsGraphColorItems[i].SettingName, PhpOptionsGraphColorItems[i].CurrentColor);\n            }\n\n            PhDeleteLayoutManager(&LayoutManager);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            PhLayoutManagerUpdate(&LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&LayoutManager);\n\n            ExtendedListView_SetColumnWidth(PhpGraphListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_USEOLDCOLORS:\n                {\n                    ListView_SetItemState(PhpGraphListViewHandle, -1, 0, LVIS_SELECTED); // deselect all items\n\n                    if (PhEnableThemeSupport)\n                        ShowWindow(PhpGraphListViewHandle, Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED ? SW_SHOW : SW_HIDE);\n                    else\n                        EnableWindow(PhpGraphListViewHandle, Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case NM_DBLCLK:\n                {\n                    if (header->hwndFrom == PhpGraphListViewHandle)\n                    {\n                        PCOLOR_ITEM item;\n\n                        if (item = PhGetSelectedListViewItemParam(PhpGraphListViewHandle))\n                        {\n                            CHOOSECOLOR chooseColor;\n                            COLORREF customColors[16] = { 0 };\n\n                            PhLoadCustomColorList(SETTING_OPTIONS_CUSTOM_COLOR_LIST, customColors, RTL_NUMBER_OF(customColors));\n\n                            memset(&chooseColor, 0, sizeof(CHOOSECOLOR));\n                            chooseColor.lStructSize = sizeof(CHOOSECOLOR);\n                            chooseColor.hwndOwner = hwndDlg;\n                            chooseColor.rgbResult = item->CurrentColor;\n                            chooseColor.lpCustColors = customColors;\n                            chooseColor.lpfnHook = PhpColorDlgHookProc;\n                            chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK | CC_RGBINIT;\n\n                            if (ChooseColor(&chooseColor))\n                            {\n                                item->CurrentColor = chooseColor.rgbResult;\n                                InvalidateRect(PhpGraphListViewHandle, NULL, TRUE);\n                            }\n\n                            PhSaveCustomColorList(SETTING_OPTIONS_CUSTOM_COLOR_LIST, customColors, RTL_NUMBER_OF(customColors));\n\n                            ListView_SetItemState(PhpGraphListViewHandle, -1, 0, LVIS_SELECTED);\n                        }\n                    }\n                }\n                break;\n            case LVN_GETINFOTIP:\n                {\n                    if (header->hwndFrom == PhpGraphListViewHandle)\n                    {\n                        NMLVGETINFOTIP* getInfoTip = (NMLVGETINFOTIP*)lParam;\n                        PH_STRINGREF tip;\n\n                        PhInitializeStringRefLongHint(&tip, ColorItems[getInfoTip->iItem].Description);\n                        PhCopyListViewInfoTip(getInfoTip, &tip);\n                    }\n                }\n                break;\n            }\n\n            if (IsWindowEnabled(PhpGraphListViewHandle)) // HACK: Move to WM_COMMAND (dmex)\n            {\n                REFLECT_MESSAGE_DLG(hwndDlg, PhpGraphListViewHandle, uMsg, wParam, lParam);\n            }\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == PhpGraphListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PCOLOR_ITEM ColorItem;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(PhpGraphListViewHandle, &point);\n\n                if (ColorItem = PhGetSelectedListViewItemParam(PhpGraphListViewHandle))\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_RESET, L\"&Reset\", NULL, NULL), ULONG_MAX);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item && item->Id == IDC_RESET)\n                    {\n                        PH_STRINGREF SettingName;\n                        PPH_SETTING Color;\n\n                        PhInitializeStringRef(&SettingName, ColorItem->SettingName);\n                        Color = PhGetSetting(&SettingName);\n\n                        PhSettingFromString(Color->Type, &Color->DefaultValue, NULL, Color);\n\n                        ColorItem->CurrentColor = Color->u.Integer;\n\n                        ListView_SetItemState(PhpGraphListViewHandle, -1, 0, LVIS_SELECTED);\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/pagfiles.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2020-2023\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <settings.h>\n#include <emenu.h>\n\nHWND PhPageFileWindowHandle = NULL;\n\ntypedef struct _PHP_PAGEFILE_PROPERTIES_CONTEXT\n{\n    HWND WindowHandle;\n    HWND ListViewHandle;\n    PH_LAYOUT_MANAGER LayoutManager;\n} PHP_PAGEFILE_PROPERTIES_CONTEXT, *PPHP_PAGEFILE_PROPERTIES_CONTEXT;\n\nINT_PTR CALLBACK PhpPagefilesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowPagefilesDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    if (!PhPageFileWindowHandle)\n    {\n        PhPageFileWindowHandle = PhCreateDialog(\n            NtCurrentImageBase(),\n            MAKEINTRESOURCE(IDD_PAGEFILES),\n            PhCsForceNoParent ? NULL : ParentWindowHandle,\n            PhpPagefilesDlgProc,\n            NULL\n            );\n        PhRegisterDialog(PhPageFileWindowHandle);\n        ShowWindow(PhPageFileWindowHandle, SW_SHOW);\n    }\n\n    if (IsMinimized(PhPageFileWindowHandle))\n        ShowWindow(PhPageFileWindowHandle, SW_RESTORE);\n    else\n        SetForegroundWindow(PhPageFileWindowHandle);\n}\n\nVOID PhpAddPagefileItems(\n    _In_ HWND ListViewHandle,\n    _In_ PVOID Pagefiles\n    )\n{\n    PSYSTEM_PAGEFILE_INFORMATION pagefile;\n\n    pagefile = PH_FIRST_PAGEFILE(Pagefiles);\n\n    while (pagefile)\n    {\n        INT lvItemIndex;\n        PPH_STRING fileName;\n        PPH_STRING newFileName;\n        PPH_STRING usage;\n\n        fileName = PhCreateStringFromUnicodeString(&pagefile->PageFileName);\n        newFileName = PhGetFileName(fileName);\n        PhDereferenceObject(fileName);\n\n        lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, newFileName->Buffer, NULL);\n        PhDereferenceObject(newFileName);\n\n        // Usage\n        usage = PhFormatSize(UInt32x32To64(pagefile->TotalInUse, PAGE_SIZE), ULONG_MAX);\n        PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, usage->Buffer);\n        PhDereferenceObject(usage);\n\n        // Peak usage\n        usage = PhFormatSize(UInt32x32To64(pagefile->PeakUsage, PAGE_SIZE), ULONG_MAX);\n        PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, usage->Buffer);\n        PhDereferenceObject(usage);\n\n        // Total\n        usage = PhFormatSize(UInt32x32To64(pagefile->TotalSize, PAGE_SIZE), ULONG_MAX);\n        PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, usage->Buffer);\n        PhDereferenceObject(usage);\n\n        pagefile = PH_NEXT_PAGEFILE(pagefile);\n    }\n}\n\nVOID PhpAddPagefileItemsEx(\n    _In_ HWND ListViewHandle,\n    _In_ PVOID Pagefiles\n    )\n{\n    PSYSTEM_PAGEFILE_INFORMATION_EX pagefile;\n\n    pagefile = PH_FIRST_PAGEFILE_EX(Pagefiles);\n\n    while (pagefile)\n    {\n        INT lvItemIndex;\n        PPH_STRING fileName;\n        PPH_STRING newFileName;\n        PPH_STRING usage;\n\n        fileName = PhCreateStringFromUnicodeString(&pagefile->Info.PageFileName);\n        newFileName = PhGetFileName(fileName);\n        PhDereferenceObject(fileName);\n\n        lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, newFileName->Buffer, NULL);\n        PhDereferenceObject(newFileName);\n\n        // Usage\n        usage = PhFormatSize(UInt32x32To64(pagefile->Info.TotalInUse, PAGE_SIZE), ULONG_MAX);\n        PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, usage->Buffer);\n        PhDereferenceObject(usage);\n\n        // Peak usage\n        usage = PhFormatSize(UInt32x32To64(pagefile->Info.PeakUsage, PAGE_SIZE), ULONG_MAX);\n        PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, usage->Buffer);\n        PhDereferenceObject(usage);\n\n        // Total\n        usage = PhFormatSize(UInt32x32To64(pagefile->Info.TotalSize, PAGE_SIZE), ULONG_MAX);\n        PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, usage->Buffer);\n        PhDereferenceObject(usage);\n\n        // Minimum\n        usage = PhFormatSize(UInt32x32To64(pagefile->MinimumSize, PAGE_SIZE), ULONG_MAX);\n        PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, usage->Buffer);\n        PhDereferenceObject(usage);\n\n        // Maximum\n        usage = PhFormatSize(UInt32x32To64(pagefile->MaximumSize, PAGE_SIZE), ULONG_MAX);\n        PhSetListViewSubItem(ListViewHandle, lvItemIndex, 5, usage->Buffer);\n        PhDereferenceObject(usage);\n\n        pagefile = PH_NEXT_PAGEFILE_EX(pagefile);\n    }\n}\n\nINT_PTR CALLBACK PhpPagefilesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_PAGEFILE_PROPERTIES_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocateZero(sizeof(PHP_PAGEFILE_PROPERTIES_CONTEXT));\n        context->WindowHandle = hwndDlg;\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            NTSTATUS status;\n            PVOID pagefiles;\n\n            context->WindowHandle = hwndDlg;\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 120, L\"File name\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 100, L\"Usage\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 100, L\"Peak usage\");\n            PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 100, L\"Total\");\n\n            if (WindowsVersion > WINDOWS_8)\n            {\n                PhAddListViewColumn(context->ListViewHandle, 4, 4, 4, LVCFMT_LEFT, 100, L\"Minimum\");\n                PhAddListViewColumn(context->ListViewHandle, 5, 5, 5, LVCFMT_LEFT, 100, L\"Maximum\");\n            }\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhLoadListViewColumnsFromSetting(SETTING_PAGE_FILE_LIST_VIEW_COLUMNS, context->ListViewHandle);\n\n            ExtendedListView_SetRedraw(context->ListViewHandle, FALSE);\n            ListView_DeleteAllItems(context->ListViewHandle);\n\n            if (WindowsVersion > WINDOWS_8)\n            {\n                if (NT_SUCCESS(status = PhEnumPagefilesEx(&pagefiles)))\n                {\n                    PhpAddPagefileItemsEx(context->ListViewHandle, pagefiles);\n                    PhFree(pagefiles);\n                }\n            }\n            else\n            {\n                if (NT_SUCCESS(status = PhEnumPagefiles(&pagefiles)))\n                {\n                    PhpAddPagefileItems(context->ListViewHandle, pagefiles);\n                    PhFree(pagefiles);\n                }\n            }\n\n            ExtendedListView_SetRedraw(context->ListViewHandle, TRUE);\n\n            if (!NT_SUCCESS(status))\n            {\n                PhShowStatus(hwndDlg, L\"Unable to query pagefile information.\", status, 0);\n                DestroyWindow(hwndDlg);\n            }\n\n            if (PhValidWindowPlacementFromSetting(SETTING_PAGE_FILE_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_PAGE_FILE_WINDOW_POSITION, SETTING_PAGE_FILE_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveListViewColumnsToSetting(SETTING_PAGE_FILE_LIST_VIEW_COLUMNS, context->ListViewHandle);\n            PhSaveWindowPlacementToSetting(SETTING_PAGE_FILE_WINDOW_POSITION, SETTING_PAGE_FILE_WINDOW_SIZE, hwndDlg);\n\n            PhUnregisterDialog(PhPageFileWindowHandle);\n            PhPageFileWindowHandle = NULL;\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n            PhFree(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                DestroyWindow(hwndDlg);\n                break;\n            case IDC_REFRESH:\n                {\n                    NTSTATUS status;\n                    PVOID pagefiles;\n\n                    ExtendedListView_SetRedraw(context->ListViewHandle, FALSE);\n                    ListView_DeleteAllItems(context->ListViewHandle);\n\n                    if (WindowsVersion > WINDOWS_8)\n                    {\n                        if (NT_SUCCESS(status = PhEnumPagefilesEx(&pagefiles)))\n                        {\n                            PhpAddPagefileItemsEx(context->ListViewHandle, pagefiles);\n                            PhFree(pagefiles);\n                        }\n                    }\n                    else\n                    {\n                        if (NT_SUCCESS(status = PhEnumPagefiles(&pagefiles)))\n                        {\n                            PhpAddPagefileItems(context->ListViewHandle, pagefiles);\n                            PhFree(pagefiles);\n                        }\n                    }\n\n                    ExtendedListView_SetRedraw(context->ListViewHandle, TRUE);\n\n                    if (!NT_SUCCESS(status))\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to query pagefile information.\", status, 0);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID* listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                PhCopyListView(context->ListViewHandle);\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/phsvc/clapi.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2015\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <phsvccl.h>\n\nHANDLE PhSvcClPortHandle = NULL;\nPVOID PhSvcClPortHeap = NULL;\nHANDLE PhSvcClServerProcessId = NULL;\n\nNTSTATUS PhSvcConnectToServer(\n    _In_ PUNICODE_STRING PortName,\n    _In_opt_ SIZE_T PortSectionSize\n    )\n{\n    NTSTATUS status;\n    HANDLE sectionHandle;\n    LARGE_INTEGER sectionSize;\n    PORT_VIEW clientView;\n    REMOTE_PORT_VIEW serverView;\n    SECURITY_QUALITY_OF_SERVICE securityQos;\n    ULONG maxMessageLength;\n    PHSVC_API_CONNECTINFO connectInfo;\n    ULONG connectInfoLength;\n\n    if (PhSvcClPortHandle)\n        return STATUS_ADDRESS_ALREADY_EXISTS;\n\n    if (PortSectionSize == 0)\n        PortSectionSize = UInt32x32To64(8, 1024 * 1024); // 8 MB\n\n    sectionSize.QuadPart = PortSectionSize;\n\n    // Create the port section and connect to the port.\n\n    status = PhCreateSection(\n        &sectionHandle,\n        SECTION_ALL_ACCESS,\n        &sectionSize,\n        PAGE_READWRITE,\n        SEC_COMMIT,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    clientView.Length = sizeof(PORT_VIEW);\n    clientView.SectionHandle = sectionHandle;\n    clientView.SectionOffset = 0;\n    clientView.ViewSize = PortSectionSize;\n    clientView.ViewBase = NULL;\n    clientView.ViewRemoteBase = NULL;\n\n    serverView.Length = sizeof(REMOTE_PORT_VIEW);\n    serverView.ViewSize = 0;\n    serverView.ViewBase = NULL;\n\n    securityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);\n    securityQos.ImpersonationLevel = SecurityImpersonation;\n    securityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;\n    securityQos.EffectiveOnly = TRUE;\n\n    connectInfoLength = sizeof(PHSVC_API_CONNECTINFO);\n    connectInfo.ServerProcessId = 0;\n\n    status = NtConnectPort(\n        &PhSvcClPortHandle,\n        PortName,\n        &securityQos,\n        &clientView,\n        &serverView,\n        &maxMessageLength,\n        &connectInfo,\n        &connectInfoLength\n        );\n    NtClose(sectionHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhSvcClServerProcessId = UlongToHandle(connectInfo.ServerProcessId);\n\n    //\n    // Create the port heap.\n    //\n\n    PhSvcClPortHeap = RtlCreateHeap(\n        HEAP_CLASS_1,\n        clientView.ViewBase,\n        clientView.ViewSize,\n        PAGE_SIZE,\n        NULL,\n        NULL\n        );\n\n    if (!PhSvcClPortHeap)\n    {\n        NtClose(PhSvcClPortHandle);\n        return STATUS_INSUFFICIENT_RESOURCES;\n    }\n\n    //\n    // Enable the low-fragmentation heap (LFH).\n    //\n\n    const ULONG defaultHeapCompatibilityMode = HEAP_COMPATIBILITY_MODE_LFH;\n    RtlSetHeapInformation(\n        PhSvcClPortHeap,\n        HeapCompatibilityInformation,\n        &defaultHeapCompatibilityMode,\n        sizeof(ULONG)\n        );\n\n    return status;\n}\n\nVOID PhSvcDisconnectFromServer(\n    VOID\n    )\n{\n    if (PhSvcClPortHeap)\n    {\n        RtlDestroyHeap(PhSvcClPortHeap);\n        PhSvcClPortHeap = NULL;\n    }\n\n    if (PhSvcClPortHandle)\n    {\n        NtClose(PhSvcClPortHandle);\n        PhSvcClPortHandle = NULL;\n    }\n\n    PhSvcClServerProcessId = 0;\n}\n\n_Success_(return != NULL)\nPVOID PhSvcpAllocateHeap(\n    _In_ SIZE_T Size,\n    _Out_ PULONG Offset\n    )\n{\n    PVOID memory;\n\n    if (!PhSvcClPortHeap)\n        return NULL;\n\n    memory = RtlAllocateHeap(PhSvcClPortHeap, HEAP_ZERO_MEMORY, Size);\n\n    if (!memory)\n        return NULL;\n\n    *Offset = PtrToUlong(PTR_SUB_OFFSET(memory, PhSvcClPortHeap));\n\n    return memory;\n}\n\nVOID PhSvcpFreeHeap(\n    _In_ PVOID Memory\n    )\n{\n    if (!PhSvcClPortHeap)\n        return;\n\n    RtlFreeHeap(PhSvcClPortHeap, 0, Memory);\n}\n\n_Success_(return != NULL)\nPVOID PhSvcpCreateString(\n    _In_opt_ PCWSTR String,\n    _In_ SIZE_T Length,\n    _Out_ PPH_RELATIVE_STRINGREF StringRef\n    )\n{\n    PVOID memory;\n    SIZE_T length;\n    ULONG offset;\n\n    if (Length != SIZE_MAX)\n        length = Length;\n    else\n        length = PhCountStringZ(String) * sizeof(WCHAR);\n\n    if (length > ULONG_MAX)\n        return NULL;\n\n    memory = PhSvcpAllocateHeap(length, &offset);\n\n    if (!memory)\n        return NULL;\n\n    if (String)\n        memcpy(memory, String, length);\n\n    StringRef->Length = (ULONG)length;\n    StringRef->Offset = offset;\n\n    return memory;\n}\n\nNTSTATUS PhSvcpCallServer(\n    _Inout_ PPHSVC_API_MSG Message\n    )\n{\n    NTSTATUS status;\n\n    Message->h.u1.s1.DataLength = sizeof(PHSVC_API_MSG) - FIELD_OFFSET(PHSVC_API_MSG, p);\n    Message->h.u1.s1.TotalLength = sizeof(PHSVC_API_MSG);\n    Message->h.u2.ZeroInit = 0;\n\n    status = NtRequestWaitReplyPort(PhSvcClPortHandle, &Message->h, &Message->h);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    return Message->p.ReturnStatus;\n}\n\nNTSTATUS PhSvcCallPlugin(\n    _In_ PPH_STRINGREF ApiId,\n    _In_reads_bytes_opt_(InLength) PVOID InBuffer,\n    _In_ ULONG InLength,\n    _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer,\n    _In_ ULONG OutLength\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID apiId = NULL;\n\n    memset(&m, 0, sizeof(PHSVC_API_MSG));\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n    if (InLength > sizeof(m.p.u.Plugin.i.Data))\n        return STATUS_BUFFER_OVERFLOW;\n\n    m.p.ApiNumber = PhSvcPluginApiNumber;\n\n    if (!(apiId = PhSvcpCreateString(ApiId->Buffer, ApiId->Length, &m.p.u.Plugin.i.ApiId)))\n        return STATUS_NO_MEMORY;\n\n    if (InLength != 0)\n        memcpy(m.p.u.Plugin.i.Data, InBuffer, InLength);\n\n    status = PhSvcpCallServer(&m);\n\n    if (OutLength != 0)\n        memcpy(OutBuffer, m.p.u.Plugin.o.Data, min(OutLength, sizeof(m.p.u.Plugin.o.Data)));\n\n    if (apiId)\n        PhSvcpFreeHeap(apiId);\n\n    return status;\n}\n\nNTSTATUS PhSvcpCallExecuteRunAsCommand(\n    _In_ PHSVC_API_NUMBER ApiNumber,\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID userName = NULL;\n    PVOID password = NULL;\n    ULONG passwordLength = 0;\n    PVOID currentDirectory = NULL;\n    PVOID commandLine = NULL;\n    PVOID fileName = NULL;\n    PVOID desktopName = NULL;\n    PVOID serviceName = NULL;\n\n    memset(&m, 0, sizeof(PHSVC_API_MSG));\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = ApiNumber;\n\n    m.p.u.ExecuteRunAsCommand.i.ProcessId = Parameters->ProcessId;\n    m.p.u.ExecuteRunAsCommand.i.LogonType = Parameters->LogonType;\n    m.p.u.ExecuteRunAsCommand.i.SessionId = Parameters->SessionId;\n    m.p.u.ExecuteRunAsCommand.i.UseLinkedToken = Parameters->UseLinkedToken;\n    m.p.u.ExecuteRunAsCommand.i.CreateSuspendedProcess = Parameters->CreateSuspendedProcess;\n    m.p.u.ExecuteRunAsCommand.i.CreateUIAccessProcess = Parameters->CreateUIAccessProcess;\n    m.p.u.ExecuteRunAsCommand.i.WindowHandle = Parameters->WindowHandle;\n\n    status = STATUS_NO_MEMORY;\n\n    if (Parameters->UserName && !(userName = PhSvcpCreateString(Parameters->UserName, SIZE_MAX, &m.p.u.ExecuteRunAsCommand.i.UserName)))\n        goto CleanupExit;\n\n    if (Parameters->Password)\n    {\n        if (!(password = PhSvcpCreateString(Parameters->Password, SIZE_MAX, &m.p.u.ExecuteRunAsCommand.i.Password)))\n            goto CleanupExit;\n\n        passwordLength = m.p.u.ExecuteRunAsCommand.i.Password.Length;\n    }\n\n    if (Parameters->CurrentDirectory && !(currentDirectory = PhSvcpCreateString(Parameters->CurrentDirectory, SIZE_MAX, &m.p.u.ExecuteRunAsCommand.i.CurrentDirectory)))\n        goto CleanupExit;\n    if (Parameters->CommandLine && !(commandLine = PhSvcpCreateString(Parameters->CommandLine, SIZE_MAX, &m.p.u.ExecuteRunAsCommand.i.CommandLine)))\n        goto CleanupExit;\n    if (Parameters->FileName && !(fileName = PhSvcpCreateString(Parameters->FileName, SIZE_MAX, &m.p.u.ExecuteRunAsCommand.i.FileName)))\n        goto CleanupExit;\n    if (Parameters->DesktopName && !(desktopName = PhSvcpCreateString(Parameters->DesktopName, SIZE_MAX, &m.p.u.ExecuteRunAsCommand.i.DesktopName)))\n        goto CleanupExit;\n    if (Parameters->ServiceName && !(serviceName = PhSvcpCreateString(Parameters->ServiceName, SIZE_MAX, &m.p.u.ExecuteRunAsCommand.i.ServiceName)))\n        goto CleanupExit;\n\n    status = PhSvcpCallServer(&m);\n\nCleanupExit:\n    if (serviceName) PhSvcpFreeHeap(serviceName);\n    if (desktopName) PhSvcpFreeHeap(desktopName);\n    if (fileName) PhSvcpFreeHeap(fileName);\n    if (commandLine) PhSvcpFreeHeap(commandLine);\n    if (currentDirectory) PhSvcpFreeHeap(currentDirectory);\n\n    if (password)\n    {\n        RtlSecureZeroMemory(password, passwordLength);\n        PhSvcpFreeHeap(password);\n    }\n\n    if (userName) PhSvcpFreeHeap(userName);\n\n    return status;\n}\n\nNTSTATUS PhSvcCallExecuteRunAsCommand(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    )\n{\n    return PhSvcpCallExecuteRunAsCommand(PhSvcExecuteRunAsCommandApiNumber, Parameters);\n}\n\nNTSTATUS PhSvcCallUnloadDriver(\n    _In_opt_ PVOID BaseAddress,\n    _In_opt_ PCWSTR Name,\n    _In_opt_ PCWSTR FileName\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID name = NULL;\n\n    memset(&m, 0, sizeof(PHSVC_API_MSG));\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcUnloadDriverApiNumber;\n    m.p.u.UnloadDriver.i.BaseAddress = BaseAddress;\n\n    if (Name)\n    {\n        name = PhSvcpCreateString(Name, SIZE_MAX, &m.p.u.UnloadDriver.i.Name);\n\n        if (!name)\n            return STATUS_NO_MEMORY;\n    }\n\n    if (FileName)\n    {\n        name = PhSvcpCreateString(FileName, SIZE_MAX, &m.p.u.UnloadDriver.i.FileName);\n\n        if (!name)\n            return STATUS_NO_MEMORY;\n    }\n\n    status = PhSvcpCallServer(&m);\n\n    if (name)\n        PhSvcpFreeHeap(name);\n\n    return status;\n}\n\nNTSTATUS PhSvcCallControlProcess(\n    _In_opt_ HANDLE ProcessId,\n    _In_ PHSVC_API_CONTROLPROCESS_COMMAND Command,\n    _In_ ULONG Argument\n    )\n{\n    PHSVC_API_MSG m;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcControlProcessApiNumber;\n    m.p.u.ControlProcess.i.ProcessId = ProcessId;\n    m.p.u.ControlProcess.i.Command = Command;\n    m.p.u.ControlProcess.i.Argument = Argument;\n\n    return PhSvcpCallServer(&m);\n}\n\nNTSTATUS PhSvcCallControlService(\n    _In_ PCWSTR ServiceName,\n    _In_ PHSVC_API_CONTROLSERVICE_COMMAND Command\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID serviceName;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcControlServiceApiNumber;\n\n    serviceName = PhSvcpCreateString(ServiceName, SIZE_MAX, &m.p.u.ControlService.i.ServiceName);\n    m.p.u.ControlService.i.Command = Command;\n\n    if (serviceName)\n    {\n        status = PhSvcpCallServer(&m);\n    }\n    else\n    {\n        status = STATUS_NO_MEMORY;\n    }\n\n    if (serviceName)\n        PhSvcpFreeHeap(serviceName);\n\n    return status;\n}\n\nNTSTATUS PhSvcCallCreateService(\n    _In_ PCWSTR ServiceName,\n    _In_opt_ PCWSTR DisplayName,\n    _In_ ULONG ServiceType,\n    _In_ ULONG StartType,\n    _In_ ULONG ErrorControl,\n    _In_opt_ PCWSTR BinaryPathName,\n    _In_opt_ PCWSTR LoadOrderGroup,\n    _Out_opt_ PULONG TagId,\n    _In_opt_ PCWSTR Dependencies,\n    _In_opt_ PCWSTR ServiceStartName,\n    _In_opt_ PCWSTR Password\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID serviceName = NULL;\n    PVOID displayName = NULL;\n    PVOID binaryPathName = NULL;\n    PVOID loadOrderGroup = NULL;\n    PVOID dependencies = NULL;\n    PVOID serviceStartName = NULL;\n    PVOID password = NULL;\n    ULONG passwordLength = 0;\n\n    memset(&m, 0, sizeof(PHSVC_API_MSG));\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcCreateServiceApiNumber;\n\n    m.p.u.CreateService.i.ServiceType = ServiceType;\n    m.p.u.CreateService.i.StartType = StartType;\n    m.p.u.CreateService.i.ErrorControl = ErrorControl;\n    m.p.u.CreateService.i.TagIdSpecified = TagId != NULL;\n\n    status = STATUS_NO_MEMORY;\n\n    if (!(serviceName = PhSvcpCreateString(ServiceName, SIZE_MAX, &m.p.u.CreateService.i.ServiceName)))\n        goto CleanupExit;\n    if (DisplayName && !(displayName = PhSvcpCreateString(DisplayName, SIZE_MAX, &m.p.u.CreateService.i.DisplayName)))\n        goto CleanupExit;\n    if (BinaryPathName && !(binaryPathName = PhSvcpCreateString(BinaryPathName, SIZE_MAX, &m.p.u.CreateService.i.BinaryPathName)))\n        goto CleanupExit;\n    if (LoadOrderGroup && !(loadOrderGroup = PhSvcpCreateString(LoadOrderGroup, SIZE_MAX, &m.p.u.CreateService.i.LoadOrderGroup)))\n        goto CleanupExit;\n\n    if (Dependencies)\n    {\n        SIZE_T dependenciesLength;\n        SIZE_T partCount;\n        PCWSTR part;\n\n        dependenciesLength = sizeof(WCHAR);\n        part = Dependencies;\n\n        do\n        {\n            partCount = PhCountStringZ(part) + 1;\n            part += partCount;\n            dependenciesLength += partCount * sizeof(WCHAR);\n        } while (partCount != 1); // stop at empty dependency part\n\n        if (!(dependencies = PhSvcpCreateString(Dependencies, dependenciesLength, &m.p.u.CreateService.i.Dependencies)))\n            goto CleanupExit;\n    }\n\n    if (ServiceStartName && !(serviceStartName = PhSvcpCreateString(ServiceStartName, SIZE_MAX, &m.p.u.CreateService.i.ServiceStartName)))\n        goto CleanupExit;\n\n    if (Password)\n    {\n        if (!(password = PhSvcpCreateString(Password, SIZE_MAX, &m.p.u.CreateService.i.Password)))\n            goto CleanupExit;\n\n        passwordLength = m.p.u.CreateService.i.Password.Length;\n    }\n\n    status = PhSvcpCallServer(&m);\n\n    if (NT_SUCCESS(status))\n    {\n        if (TagId)\n            *TagId = m.p.u.CreateService.o.TagId;\n    }\n\nCleanupExit:\n    if (password)\n    {\n        RtlSecureZeroMemory(password, passwordLength);\n        PhSvcpFreeHeap(password);\n    }\n\n    if (serviceStartName) PhSvcpFreeHeap(serviceStartName);\n    if (dependencies) PhSvcpFreeHeap(dependencies);\n    if (loadOrderGroup) PhSvcpFreeHeap(loadOrderGroup);\n    if (binaryPathName) PhSvcpFreeHeap(binaryPathName);\n    if (displayName) PhSvcpFreeHeap(displayName);\n    if (serviceName) PhSvcpFreeHeap(serviceName);\n\n    return status;\n}\n\nNTSTATUS PhSvcCallChangeServiceConfig(\n    _In_ PCWSTR ServiceName,\n    _In_ ULONG ServiceType,\n    _In_ ULONG StartType,\n    _In_ ULONG ErrorControl,\n    _In_opt_ PCWSTR BinaryPathName,\n    _In_opt_ PCWSTR LoadOrderGroup,\n    _Out_opt_ PULONG TagId,\n    _In_opt_ PCWSTR Dependencies,\n    _In_opt_ PCWSTR ServiceStartName,\n    _In_opt_ PCWSTR Password,\n    _In_opt_ PCWSTR DisplayName\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID serviceName = NULL;\n    PVOID binaryPathName = NULL;\n    PVOID loadOrderGroup = NULL;\n    PVOID dependencies = NULL;\n    PVOID serviceStartName = NULL;\n    PVOID password = NULL;\n    ULONG passwordLength = 0;\n    PVOID displayName = NULL;\n\n    memset(&m, 0, sizeof(PHSVC_API_MSG));\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcChangeServiceConfigApiNumber;\n\n    m.p.u.ChangeServiceConfig.i.ServiceType = ServiceType;\n    m.p.u.ChangeServiceConfig.i.StartType = StartType;\n    m.p.u.ChangeServiceConfig.i.ErrorControl = ErrorControl;\n    m.p.u.ChangeServiceConfig.i.TagIdSpecified = TagId != NULL;\n\n    status = STATUS_NO_MEMORY;\n\n    if (!(serviceName = PhSvcpCreateString(ServiceName, SIZE_MAX, &m.p.u.ChangeServiceConfig.i.ServiceName)))\n        goto CleanupExit;\n    if (BinaryPathName && !(binaryPathName = PhSvcpCreateString(BinaryPathName, SIZE_MAX, &m.p.u.ChangeServiceConfig.i.BinaryPathName)))\n        goto CleanupExit;\n    if (LoadOrderGroup && !(loadOrderGroup = PhSvcpCreateString(LoadOrderGroup, SIZE_MAX, &m.p.u.ChangeServiceConfig.i.LoadOrderGroup)))\n        goto CleanupExit;\n\n    if (Dependencies)\n    {\n        SIZE_T dependenciesLength;\n        SIZE_T partCount;\n        PCWSTR part;\n\n        dependenciesLength = sizeof(WCHAR);\n        part = Dependencies;\n\n        do\n        {\n            partCount = PhCountStringZ(part) + 1;\n            part += partCount;\n            dependenciesLength += partCount * sizeof(WCHAR);\n        } while (partCount != 1); // stop at empty dependency part\n\n        if (!(dependencies = PhSvcpCreateString(Dependencies, dependenciesLength, &m.p.u.ChangeServiceConfig.i.Dependencies)))\n            goto CleanupExit;\n    }\n\n    if (ServiceStartName && !(serviceStartName = PhSvcpCreateString(ServiceStartName, SIZE_MAX, &m.p.u.ChangeServiceConfig.i.ServiceStartName)))\n        goto CleanupExit;\n\n    if (Password)\n    {\n        if (!(password = PhSvcpCreateString(Password, SIZE_MAX, &m.p.u.ChangeServiceConfig.i.Password)))\n            goto CleanupExit;\n\n        passwordLength = m.p.u.ChangeServiceConfig.i.Password.Length;\n    }\n\n    if (DisplayName && !(displayName = PhSvcpCreateString(DisplayName, SIZE_MAX, &m.p.u.ChangeServiceConfig.i.DisplayName)))\n        goto CleanupExit;\n\n    status = PhSvcpCallServer(&m);\n\n    if (NT_SUCCESS(status))\n    {\n        if (TagId)\n            *TagId = m.p.u.ChangeServiceConfig.o.TagId;\n    }\n\nCleanupExit:\n    if (displayName) PhSvcpFreeHeap(displayName);\n\n    if (password)\n    {\n        RtlSecureZeroMemory(password, passwordLength);\n        PhSvcpFreeHeap(password);\n    }\n\n    if (serviceStartName) PhSvcpFreeHeap(serviceStartName);\n    if (dependencies) PhSvcpFreeHeap(dependencies);\n    if (loadOrderGroup) PhSvcpFreeHeap(loadOrderGroup);\n    if (binaryPathName) PhSvcpFreeHeap(binaryPathName);\n    if (serviceName) PhSvcpFreeHeap(serviceName);\n\n    return status;\n}\n\nPVOID PhSvcpPackRoot(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ PVOID Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    return PhAppendBytesBuilderEx(BytesBuilder, Buffer, Length, sizeof(ULONG_PTR), NULL);\n}\n\nVOID PhSvcpPackBuffer_V(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _Inout_ PVOID *PointerInBytesBuilder,\n    _In_ SIZE_T Length,\n    _In_ SIZE_T Alignment,\n    _In_ ULONG NumberOfPointersToRebase,\n    _In_ va_list ArgPtr\n    )\n{\n    va_list argptr;\n    ULONG_PTR oldBase;\n    SIZE_T oldLength;\n    ULONG_PTR newBase;\n    SIZE_T offset;\n    ULONG i;\n    PVOID *pointer;\n\n    oldBase = (ULONG_PTR)BytesBuilder->Bytes->Buffer;\n    oldLength = BytesBuilder->Bytes->Length;\n    assert((ULONG_PTR)PointerInBytesBuilder >= oldBase && (ULONG_PTR)PointerInBytesBuilder + sizeof(PVOID) <= oldBase + oldLength);\n\n    if (!*PointerInBytesBuilder)\n        return;\n\n    PhAppendBytesBuilderEx(BytesBuilder, *PointerInBytesBuilder, Length, Alignment, &offset);\n    newBase = (ULONG_PTR)BytesBuilder->Bytes->Buffer;\n\n    PointerInBytesBuilder = (PVOID *)((ULONG_PTR)PointerInBytesBuilder - oldBase + newBase);\n    *PointerInBytesBuilder = (PVOID)offset;\n\n    argptr = ArgPtr;\n\n    for (i = 0; i < NumberOfPointersToRebase; i++)\n    {\n        pointer = va_arg(argptr, PVOID *);\n        assert(!*pointer || ((ULONG_PTR)*pointer >= oldBase && (ULONG_PTR)*pointer + sizeof(PVOID) <= oldBase + oldLength));\n\n        if (*pointer)\n            *pointer = (PVOID)((ULONG_PTR)*pointer - oldBase + newBase);\n    }\n}\n\nVOID PhSvcpPackBuffer(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _Inout_ PVOID *PointerInBytesBuilder,\n    _In_ SIZE_T Length,\n    _In_ SIZE_T Alignment,\n    _In_ ULONG NumberOfPointersToRebase,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, NumberOfPointersToRebase);\n    PhSvcpPackBuffer_V(BytesBuilder, PointerInBytesBuilder, Length, Alignment, NumberOfPointersToRebase, argptr);\n    va_end(argptr);\n}\n\nSIZE_T PhSvcpBufferLengthStringZ(\n    _In_opt_ PCWSTR String,\n    _In_ BOOLEAN Multi\n    )\n{\n    SIZE_T length = 0;\n\n    if (String)\n    {\n        if (Multi)\n        {\n            PCWSTR part = String;\n            SIZE_T partCount;\n\n            while (TRUE)\n            {\n                partCount = PhCountStringZ(part);\n                length += (partCount + 1) * sizeof(WCHAR);\n\n                if (partCount == 0)\n                    break;\n\n                part += partCount + 1;\n            }\n        }\n        else\n        {\n            length = (PhCountStringZ(String) + 1) * sizeof(WCHAR);\n        }\n    }\n\n    return length;\n}\n\nNTSTATUS PhSvcCallChangeServiceConfig2(\n    _In_ PCWSTR ServiceName,\n    _In_ ULONG InfoLevel,\n    _In_ PVOID Info\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID serviceName = NULL;\n    PVOID info = NULL;\n    PH_BYTES_BUILDER bb;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcChangeServiceConfig2ApiNumber;\n\n    m.p.u.ChangeServiceConfig2.i.InfoLevel = InfoLevel;\n\n    if (serviceName = PhSvcpCreateString(ServiceName, SIZE_MAX, &m.p.u.ChangeServiceConfig2.i.ServiceName))\n    {\n        switch (InfoLevel)\n        {\n        case SERVICE_CONFIG_FAILURE_ACTIONS:\n            {\n                LPSERVICE_FAILURE_ACTIONS failureActions = Info;\n                LPSERVICE_FAILURE_ACTIONS packedFailureActions;\n\n                PhInitializeBytesBuilder(&bb, 200);\n                packedFailureActions = PhSvcpPackRoot(&bb, failureActions, sizeof(SERVICE_FAILURE_ACTIONS));\n                PhSvcpPackBuffer(&bb, &packedFailureActions->lpRebootMsg, PhSvcpBufferLengthStringZ(failureActions->lpRebootMsg, FALSE), sizeof(WCHAR),\n                    1, &packedFailureActions);\n                PhSvcpPackBuffer(&bb, &packedFailureActions->lpCommand, PhSvcpBufferLengthStringZ(failureActions->lpCommand, FALSE), sizeof(WCHAR),\n                    1, &packedFailureActions);\n\n                if (failureActions->cActions != 0 && failureActions->lpsaActions)\n                {\n                    PhSvcpPackBuffer(&bb, &packedFailureActions->lpsaActions, failureActions->cActions * sizeof(SC_ACTION), __alignof(SC_ACTION),\n                        1, &packedFailureActions);\n                }\n\n                info = PhSvcpCreateString((PCWSTR)bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info);\n                PhDeleteBytesBuilder(&bb);\n            }\n            break;\n        case SERVICE_CONFIG_DELAYED_AUTO_START_INFO:\n            info = PhSvcpCreateString(Info, sizeof(SERVICE_DELAYED_AUTO_START_INFO), &m.p.u.ChangeServiceConfig2.i.Info);\n            break;\n        case SERVICE_CONFIG_FAILURE_ACTIONS_FLAG:\n            info = PhSvcpCreateString(Info, sizeof(SERVICE_FAILURE_ACTIONS_FLAG), &m.p.u.ChangeServiceConfig2.i.Info);\n            break;\n        case SERVICE_CONFIG_SERVICE_SID_INFO:\n            info = PhSvcpCreateString(Info, sizeof(SERVICE_SID_INFO), &m.p.u.ChangeServiceConfig2.i.Info);\n            break;\n        case SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO:\n            {\n                LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo = Info;\n                LPSERVICE_REQUIRED_PRIVILEGES_INFO packedRequiredPrivilegesInfo;\n\n                PhInitializeBytesBuilder(&bb, 100);\n                packedRequiredPrivilegesInfo = PhSvcpPackRoot(&bb, requiredPrivilegesInfo, sizeof(SERVICE_REQUIRED_PRIVILEGES_INFO));\n                PhSvcpPackBuffer(&bb, &packedRequiredPrivilegesInfo->pmszRequiredPrivileges, PhSvcpBufferLengthStringZ(requiredPrivilegesInfo->pmszRequiredPrivileges, TRUE), sizeof(WCHAR),\n                    1, &packedRequiredPrivilegesInfo);\n\n                info = PhSvcpCreateString((PCWSTR)bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info);\n                PhDeleteBytesBuilder(&bb);\n            }\n            break;\n        case SERVICE_CONFIG_PRESHUTDOWN_INFO:\n            info = PhSvcpCreateString(Info, sizeof(SERVICE_PRESHUTDOWN_INFO), &m.p.u.ChangeServiceConfig2.i.Info);\n            break;\n        case SERVICE_CONFIG_TRIGGER_INFO:\n            {\n                PSERVICE_TRIGGER_INFO triggerInfo = Info;\n                PSERVICE_TRIGGER_INFO packedTriggerInfo;\n                ULONG i;\n                PSERVICE_TRIGGER packedTrigger;\n                ULONG j;\n                PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM packedDataItem;\n                ULONG alignment;\n\n                PhInitializeBytesBuilder(&bb, 400);\n                packedTriggerInfo = PhSvcpPackRoot(&bb, triggerInfo, sizeof(SERVICE_TRIGGER_INFO));\n\n                if (triggerInfo->cTriggers != 0 && triggerInfo->pTriggers)\n                {\n                    PhSvcpPackBuffer(&bb, &packedTriggerInfo->pTriggers, triggerInfo->cTriggers * sizeof(SERVICE_TRIGGER), __alignof(SERVICE_TRIGGER),\n                        1, &packedTriggerInfo);\n\n                    for (i = 0; i < triggerInfo->cTriggers; i++)\n                    {\n                        packedTrigger = PhOffsetBytesBuilder(&bb, (SIZE_T)packedTriggerInfo->pTriggers + i * sizeof(SERVICE_TRIGGER));\n\n                        PhSvcpPackBuffer(&bb, &packedTrigger->pTriggerSubtype, sizeof(GUID), __alignof(GUID),\n                            2, &packedTriggerInfo, &packedTrigger);\n\n                        if (packedTrigger->cDataItems != 0 && packedTrigger->pDataItems)\n                        {\n                            PhSvcpPackBuffer(&bb, &packedTrigger->pDataItems, packedTrigger->cDataItems * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), __alignof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM),\n                                2, &packedTriggerInfo, &packedTrigger);\n\n                            for (j = 0; j < packedTrigger->cDataItems; j++)\n                            {\n                                packedDataItem = PhOffsetBytesBuilder(&bb, (SIZE_T)packedTrigger->pDataItems + j * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM));\n                                alignment = 1;\n\n                                switch (packedDataItem->dwDataType)\n                                {\n                                case SERVICE_TRIGGER_DATA_TYPE_BINARY:\n                                case SERVICE_TRIGGER_DATA_TYPE_LEVEL:\n                                    alignment = sizeof(CHAR);\n                                    break;\n                                case SERVICE_TRIGGER_DATA_TYPE_STRING:\n                                    alignment = sizeof(WCHAR);\n                                    break;\n                                case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY:\n                                case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL:\n                                    alignment = sizeof(ULONG64);\n                                    break;\n                                }\n\n                                PhSvcpPackBuffer(&bb, &packedDataItem->pData, packedDataItem->cbData, alignment,\n                                    3, &packedTriggerInfo, &packedTrigger, &packedDataItem);\n                            }\n                        }\n                    }\n                }\n\n                info = PhSvcpCreateString((PCWSTR)bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info);\n                PhDeleteBytesBuilder(&bb);\n            }\n            break;\n        case SERVICE_CONFIG_LAUNCH_PROTECTED:\n            info = PhSvcpCreateString(Info, sizeof(SERVICE_LAUNCH_PROTECTED_INFO), &m.p.u.ChangeServiceConfig2.i.Info);\n            break;\n        default:\n            status = STATUS_INVALID_PARAMETER;\n            break;\n        }\n    }\n\n    if (serviceName && info)\n    {\n        status = PhSvcpCallServer(&m);\n    }\n    else\n    {\n        status = STATUS_NO_MEMORY;\n    }\n\n    if (info)\n        PhSvcpFreeHeap(info);\n    if (serviceName)\n        PhSvcpFreeHeap(serviceName);\n\n    return status;\n}\n\nNTSTATUS PhSvcCallSetTcpEntry(\n    _In_ PVOID TcpRow\n    )\n{\n    PHSVC_API_MSG m;\n    struct\n    {\n        ULONG dwState;\n        ULONG dwLocalAddr;\n        ULONG dwLocalPort;\n        ULONG dwRemoteAddr;\n        ULONG dwRemotePort;\n    } *tcpRow = TcpRow;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcSetTcpEntryApiNumber;\n\n    m.p.u.SetTcpEntry.i.State = tcpRow->dwState;\n    m.p.u.SetTcpEntry.i.LocalAddress = tcpRow->dwLocalAddr;\n    m.p.u.SetTcpEntry.i.LocalPort = tcpRow->dwLocalPort;\n    m.p.u.SetTcpEntry.i.RemoteAddress = tcpRow->dwRemoteAddr;\n    m.p.u.SetTcpEntry.i.RemotePort = tcpRow->dwRemotePort;\n\n    return PhSvcpCallServer(&m);\n}\n\nNTSTATUS PhSvcCallControlThread(\n    _In_ HANDLE ThreadId,\n    _In_ PHSVC_API_CONTROLTHREAD_COMMAND Command,\n    _In_ ULONG Argument\n    )\n{\n    PHSVC_API_MSG m;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcControlThreadApiNumber;\n    m.p.u.ControlThread.i.ThreadId = ThreadId;\n    m.p.u.ControlThread.i.Command = Command;\n    m.p.u.ControlThread.i.Argument = Argument;\n\n    return PhSvcpCallServer(&m);\n}\n\nNTSTATUS PhSvcCallAddAccountRight(\n    _In_ PSID AccountSid,\n    _In_ PUNICODE_STRING UserRight\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID accountSid = NULL;\n    PVOID userRight = NULL;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcAddAccountRightApiNumber;\n\n    status = STATUS_NO_MEMORY;\n\n    if (!(accountSid = PhSvcpCreateString(AccountSid, PhLengthSid(AccountSid), &m.p.u.AddAccountRight.i.AccountSid)))\n        goto CleanupExit;\n    if (!(userRight = PhSvcpCreateString(UserRight->Buffer, UserRight->Length, &m.p.u.AddAccountRight.i.UserRight)))\n        goto CleanupExit;\n\n    status = PhSvcpCallServer(&m);\n\nCleanupExit:\n    if (userRight) PhSvcpFreeHeap(userRight);\n    if (accountSid) PhSvcpFreeHeap(accountSid);\n\n    return status;\n}\n\nNTSTATUS PhSvcCallInvokeRunAsService(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    )\n{\n    return PhSvcpCallExecuteRunAsCommand(PhSvcInvokeRunAsServiceApiNumber, Parameters);\n}\n\nNTSTATUS PhSvcCallIssueMemoryListCommand(\n    _In_ SYSTEM_MEMORY_LIST_COMMAND Command\n    )\n{\n    PHSVC_API_MSG m;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcIssueMemoryListCommandApiNumber;\n    m.p.u.IssueMemoryListCommand.i.Command = Command;\n\n    return PhSvcpCallServer(&m);\n}\n\nNTSTATUS PhSvcCallPostMessage(\n    _In_opt_ HWND hWnd,\n    _In_ UINT Msg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PHSVC_API_MSG m;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcPostMessageApiNumber;\n    m.p.u.PostMessage.i.hWnd = hWnd;\n    m.p.u.PostMessage.i.Msg = Msg;\n    m.p.u.PostMessage.i.wParam = wParam;\n    m.p.u.PostMessage.i.lParam = lParam;\n\n    return PhSvcpCallServer(&m);\n}\n\nNTSTATUS PhSvcCallSendMessage(\n    _In_opt_ HWND hWnd,\n    _In_ UINT Msg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PHSVC_API_MSG m;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcSendMessageApiNumber;\n    m.p.u.PostMessage.i.hWnd = hWnd;\n    m.p.u.PostMessage.i.Msg = Msg;\n    m.p.u.PostMessage.i.wParam = wParam;\n    m.p.u.PostMessage.i.lParam = lParam;\n\n    return PhSvcpCallServer(&m);\n}\n\nNTSTATUS PhSvcCallCreateProcessIgnoreIfeoDebugger(\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR CommandLine\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID fileName = NULL;\n    PVOID commandLine = NULL;\n\n    memset(&m, 0, sizeof(PHSVC_API_MSG));\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    m.p.ApiNumber = PhSvcCreateProcessIgnoreIfeoDebuggerApiNumber;\n    fileName = PhSvcpCreateString(FileName, SIZE_MAX, &m.p.u.CreateProcessIgnoreIfeoDebugger.i.FileName);\n\n    if (!fileName)\n        return STATUS_NO_MEMORY;\n\n    if (CommandLine)\n    {\n        commandLine = PhSvcpCreateString(CommandLine, SIZE_MAX, &m.p.u.CreateProcessIgnoreIfeoDebugger.i.CommandLine);\n\n        if (!commandLine)\n            return STATUS_NO_MEMORY;\n    }\n\n    status = PhSvcpCallServer(&m);\n\n    if (commandLine)\n        PhSvcpFreeHeap(commandLine);\n    if (fileName)\n        PhSvcpFreeHeap(fileName);\n\n    return status;\n}\n\n_Success_(return != NULL)\nPSECURITY_DESCRIPTOR PhpAbsoluteToSelfRelativeSD(\n    _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,\n    _Out_ PULONG BufferSize\n    )\n{\n    NTSTATUS status;\n    ULONG bufferSize = 0;\n    PSECURITY_DESCRIPTOR selfRelativeSecurityDescriptor;\n\n    status = RtlAbsoluteToSelfRelativeSD(AbsoluteSecurityDescriptor, NULL, &bufferSize);\n\n    if (status != STATUS_BUFFER_TOO_SMALL)\n        return NULL;\n\n    selfRelativeSecurityDescriptor = PhAllocate(bufferSize);\n    status = RtlAbsoluteToSelfRelativeSD(AbsoluteSecurityDescriptor, selfRelativeSecurityDescriptor, &bufferSize);\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(selfRelativeSecurityDescriptor);\n        return NULL;\n    }\n\n    *BufferSize = bufferSize;\n\n    return selfRelativeSecurityDescriptor;\n}\n\nNTSTATUS PhSvcCallSetServiceSecurity(\n    _In_ PCWSTR ServiceName,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PSECURITY_DESCRIPTOR selfRelativeSecurityDescriptor = NULL;\n    ULONG bufferSize;\n    PVOID serviceName = NULL;\n    PVOID copiedSelfRelativeSecurityDescriptor = NULL;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    selfRelativeSecurityDescriptor = PhpAbsoluteToSelfRelativeSD(SecurityDescriptor, &bufferSize);\n\n    if (!selfRelativeSecurityDescriptor)\n    {\n        status = STATUS_BAD_DESCRIPTOR_FORMAT;\n        goto CleanupExit;\n    }\n\n    m.p.ApiNumber = PhSvcSetServiceSecurityApiNumber;\n    m.p.u.SetServiceSecurity.i.SecurityInformation = SecurityInformation;\n    status = STATUS_NO_MEMORY;\n\n    if (!(serviceName = PhSvcpCreateString(ServiceName, SIZE_MAX, &m.p.u.SetServiceSecurity.i.ServiceName)))\n        goto CleanupExit;\n    if (!(copiedSelfRelativeSecurityDescriptor = PhSvcpCreateString(selfRelativeSecurityDescriptor, bufferSize, &m.p.u.SetServiceSecurity.i.SecurityDescriptor)))\n        goto CleanupExit;\n\n    status = PhSvcpCallServer(&m);\n\nCleanupExit:\n    if (selfRelativeSecurityDescriptor) PhFree(selfRelativeSecurityDescriptor);\n    if (serviceName) PhSvcpFreeHeap(serviceName);\n    if (copiedSelfRelativeSecurityDescriptor) PhSvcpFreeHeap(copiedSelfRelativeSecurityDescriptor);\n\n    return status;\n}\n\nNTSTATUS PhSvcCallWriteMiniDumpProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG DumpType\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    HANDLE serverHandle = NULL;\n    HANDLE remoteProcessHandle = NULL;\n    HANDLE remoteFileHandle = NULL;\n\n    memset(&m, 0, sizeof(PHSVC_API_MSG));\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    // For typical uses of this function, the client has more privileges than the server.\n    // We therefore duplicate our handles into the server's process.\n\n    m.p.ApiNumber = PhSvcWriteMiniDumpProcessApiNumber;\n\n    status = PhOpenProcess(\n        &serverHandle,\n        PROCESS_DUP_HANDLE,\n        PhSvcClServerProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtDuplicateObject(\n        NtCurrentProcess(),\n        ProcessHandle,\n        serverHandle,\n        &remoteProcessHandle,\n        0,\n        0,\n        DUPLICATE_SAME_ACCESS\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtDuplicateObject(\n        NtCurrentProcess(),\n        FileHandle,\n        serverHandle,\n        &remoteFileHandle,\n        FILE_GENERIC_WRITE,\n        0,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    m.p.u.WriteMiniDumpProcess.i.LocalProcessHandle = HandleToUlong(remoteProcessHandle);\n    m.p.u.WriteMiniDumpProcess.i.ProcessId = HandleToUlong(ProcessId);\n    m.p.u.WriteMiniDumpProcess.i.LocalFileHandle = HandleToUlong(remoteFileHandle);\n    m.p.u.WriteMiniDumpProcess.i.DumpType = DumpType;\n\n    status = PhSvcpCallServer(&m);\n\nCleanupExit:\n    if (serverHandle)\n    {\n        if (remoteProcessHandle)\n            NtDuplicateObject(serverHandle, remoteProcessHandle, NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);\n        if (remoteFileHandle)\n            NtDuplicateObject(serverHandle, remoteFileHandle, NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);\n\n        NtClose(serverHandle);\n    }\n\n    return status;\n}\n\nNTSTATUS PhSvcCallQueryProcessHeapInformation(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING* HeapInformation\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    ULONG bufferSize;\n    PVOID buffer;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    memset(&m, 0, sizeof(PHSVC_API_MSG));\n    m.p.ApiNumber = PhSvcQueryProcessDebugInformationApiNumber;\n    m.p.u.QueryProcessHeap.i.ProcessId = HandleToUlong(ProcessId);\n\n    bufferSize = 0x1000;\n\n    if (!(buffer = PhSvcpCreateString(NULL, bufferSize, &m.p.u.QueryProcessHeap.i.Data)))\n        return STATUS_FAIL_CHECK;\n\n    status = PhSvcpCallServer(&m);\n\n    if (status == STATUS_BUFFER_OVERFLOW)\n    {\n        PhSvcpFreeHeap(buffer);\n        bufferSize = m.p.u.QueryProcessHeap.o.DataLength;\n\n        if (!(buffer = PhSvcpCreateString(NULL, bufferSize, &m.p.u.QueryProcessHeap.i.Data)))\n            return STATUS_FAIL_CHECK;\n\n        status = PhSvcpCallServer(&m);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (HeapInformation)\n            *HeapInformation = PhCreateStringEx(buffer, m.p.u.QueryProcessHeap.o.DataLength);\n    }\n\n    PhSvcpFreeHeap(buffer);\n\n    return status;\n}\n\nNTSTATUS PhSvcCallCreateProcessForKsi(\n    _In_ PCWSTR CommandLine,\n    _In_ ULONG64 MitigationFlags[2]\n    )\n{\n    NTSTATUS status;\n    PHSVC_API_MSG m;\n    PVOID commandLine;\n\n    if (!PhSvcClPortHandle)\n        return STATUS_PORT_DISCONNECTED;\n\n    memset(&m, 0, sizeof(PHSVC_API_MSG));\n    m.p.ApiNumber = PhSvcCreateProcessForKsi;\n\n    if (!(commandLine = PhSvcpCreateString(CommandLine, SIZE_MAX, &m.p.u.CreateProcessForKsi.i.CommandLine)))\n        return STATUS_NO_MEMORY;\n\n    m.p.u.CreateProcessForKsi.i.MitigationFlags[0] = MitigationFlags[0];\n    m.p.u.CreateProcessForKsi.i.MitigationFlags[1] = MitigationFlags[1];\n\n    status = PhSvcpCallServer(&m);\n\n    PhSvcpFreeHeap(commandLine);\n\n    return status;\n}\n"
  },
  {
    "path": "SystemInformer/phsvc/svcapi.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2015\n *     dmex    2019-2023\n *\n */\n\n#include <phapp.h>\n#include <phsvc.h>\n#include <extmgri.h>\n#include <lsasup.h>\n#include <mapldr.h>\n#include <phplug.h>\n#include <secedit.h>\n#include <svcsup.h>\n\n#include <accctrl.h>\n#include <dbghelp.h>\n#include <symprv.h>\n\ntypedef struct _PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS\n{\n    PPH_STRING UserName;\n    PPH_STRING Password;\n    PPH_STRING CurrentDirectory;\n    PPH_STRING CommandLine;\n    PPH_STRING FileName;\n    PPH_STRING DesktopName;\n    PPH_STRING ServiceName;\n} PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS, *PPHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS;\n\nstatic CONST PPHSVC_API_PROCEDURE PhSvcApiCallTable[] =\n{\n    PhSvcApiPlugin,\n    PhSvcApiExecuteRunAsCommand,\n    PhSvcApiUnloadDriver,\n    PhSvcApiControlProcess,\n    PhSvcApiControlService,\n    PhSvcApiCreateService,\n    PhSvcApiChangeServiceConfig,\n    PhSvcApiChangeServiceConfig2,\n    PhSvcApiSetTcpEntry,\n    PhSvcApiControlThread,\n    PhSvcApiAddAccountRight,\n    PhSvcApiInvokeRunAsService,\n    PhSvcApiIssueMemoryListCommand,\n    PhSvcApiPostMessage,\n    PhSvcApiSendMessage,\n    PhSvcApiCreateProcessIgnoreIfeoDebugger,\n    PhSvcApiSetServiceSecurity,\n    PhSvcApiWriteMiniDumpProcess,\n    PhSvcApiQueryProcessHeapInformation,\n    PhSvcApiCreateProcessForKsi,\n};\nstatic_assert(RTL_NUMBER_OF(PhSvcApiCallTable) == PhSvcMaximumApiNumber - 1, \"SvcApiCallTable must equal MaximumApiNumber\");\n\nNTSTATUS PhSvcApiInitialization(\n    VOID\n    )\n{\n    return STATUS_SUCCESS;\n}\n\nVOID PhSvcDispatchApiCall(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload,\n    _Out_ PHANDLE ReplyPortHandle\n    )\n{\n    NTSTATUS status;\n\n    if (\n        Payload->ApiNumber == 0 ||\n        (ULONG)Payload->ApiNumber >= (ULONG)PhSvcMaximumApiNumber ||\n        !PhSvcApiCallTable[Payload->ApiNumber - 1]\n        )\n    {\n        Payload->ReturnStatus = STATUS_INVALID_SYSTEM_SERVICE;\n        *ReplyPortHandle = Client->PortHandle;\n        return;\n    }\n\n    status = PhSvcApiCallTable[Payload->ApiNumber - 1](Client, Payload);\n    Payload->ReturnStatus = status;\n\n    *ReplyPortHandle = Client->PortHandle;\n}\n\nPVOID PhSvcValidateString(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ ULONG Alignment\n    )\n{\n    PPHSVC_CLIENT client = PhSvcGetCurrentClient();\n    PVOID address;\n\n    address = PTR_ADD_OFFSET(client->ClientViewBase, String->Offset);\n\n    if ((ULONG_PTR)address + String->Length < (ULONG_PTR)address ||\n        (ULONG_PTR)address < (ULONG_PTR)client->ClientViewBase ||\n        (ULONG_PTR)address + String->Length > (ULONG_PTR)client->ClientViewLimit)\n    {\n        return NULL;\n    }\n\n    if ((ULONG_PTR)address & (Alignment - 1))\n    {\n        return NULL;\n    }\n\n    return address;\n}\n\n_Function_class_(PHSVC_SERVER_PROBE_BUFFER)\nNTSTATUS PhSvcProbeBuffer(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ ULONG Alignment,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PVOID *Pointer\n    )\n{\n    PVOID address;\n\n    if (String->Offset != 0)\n    {\n        address = PhSvcValidateString(String, Alignment);\n\n        if (!address)\n            return STATUS_ACCESS_VIOLATION;\n\n        *Pointer = address;\n    }\n    else\n    {\n        if (!AllowNull)\n            return STATUS_ACCESS_VIOLATION;\n\n        *Pointer = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PHSVC_SERVER_CAPTURE_BUFFER)\nNTSTATUS PhSvcCaptureBuffer(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PVOID *CapturedBuffer\n    )\n{\n    PVOID address;\n    PVOID buffer;\n\n    if (String->Offset != 0)\n    {\n        address = PhSvcValidateString(String, 1);\n\n        if (!address)\n            return STATUS_ACCESS_VIOLATION;\n\n        buffer = PhAllocateSafe(String->Length);\n\n        if (!buffer)\n            return STATUS_NO_MEMORY;\n\n        memcpy(buffer, address, String->Length);\n        *CapturedBuffer = buffer;\n    }\n    else\n    {\n        if (!AllowNull)\n            return STATUS_ACCESS_VIOLATION;\n\n        *CapturedBuffer = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSvcCaptureString(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PPH_STRING *CapturedString\n    )\n{\n    PVOID address;\n\n    if (String->Length & 1)\n        return STATUS_INVALID_BUFFER_SIZE;\n    if (String->Length > 0xfffe)\n        return STATUS_INVALID_BUFFER_SIZE;\n\n    if (String->Offset != 0)\n    {\n        address = PhSvcValidateString(String, sizeof(WCHAR));\n\n        if (!address)\n            return STATUS_ACCESS_VIOLATION;\n\n        if (String->Length != 0)\n            *CapturedString = PhCreateStringEx(address, String->Length);\n        else\n            *CapturedString = PhReferenceEmptyString();\n    }\n    else\n    {\n        if (!AllowNull)\n            return STATUS_ACCESS_VIOLATION;\n\n        *CapturedString = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSvcCaptureSid(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _Out_ PSID *CapturedSid\n    )\n{\n    NTSTATUS status;\n    PSID sid;\n\n    if (!NT_SUCCESS(status = PhSvcCaptureBuffer(String, AllowNull, &sid)))\n        return status;\n\n    if (sid)\n    {\n        if (String->Length < UFIELD_OFFSET(struct _SID, IdentifierAuthority) ||\n            String->Length < PhLengthRequiredSid(((struct _SID *)sid)->SubAuthorityCount) ||\n            !PhValidSid(sid))\n        {\n            PhFree(sid);\n            return STATUS_INVALID_SID;\n        }\n\n        *CapturedSid = sid;\n    }\n    else\n    {\n        *CapturedSid = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSvcCaptureSecurityDescriptor(\n    _In_ PPH_RELATIVE_STRINGREF String,\n    _In_ BOOLEAN AllowNull,\n    _In_ SECURITY_INFORMATION RequiredInformation,\n    _Out_ PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    ULONG bufferSize;\n\n    if (!NT_SUCCESS(status = PhSvcCaptureBuffer(String, AllowNull, &securityDescriptor)))\n        return status;\n\n    if (securityDescriptor)\n    {\n        if (!RtlValidRelativeSecurityDescriptor(securityDescriptor, String->Length, RequiredInformation))\n        {\n            PhFree(securityDescriptor);\n            return STATUS_INVALID_SECURITY_DESCR;\n        }\n\n        bufferSize = String->Length;\n        status = RtlSelfRelativeToAbsoluteSD2(securityDescriptor, &bufferSize);\n\n        if (status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PVOID newBuffer;\n\n            newBuffer = PhAllocate(bufferSize);\n            memcpy(newBuffer, securityDescriptor, String->Length);\n            PhFree(securityDescriptor);\n            securityDescriptor = newBuffer;\n\n            status = RtlSelfRelativeToAbsoluteSD2(securityDescriptor, &bufferSize);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhFree(securityDescriptor);\n            return status;\n        }\n\n        *CapturedSecurityDescriptor = securityDescriptor;\n    }\n    else\n    {\n        *CapturedSecurityDescriptor = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSvcApiDefault(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    return STATUS_NOT_IMPLEMENTED;\n}\n\n_Function_class_(PHSVC_API_PROCEDURE)\nNTSTATUS PhSvcApiPlugin(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PPH_STRING apiId;\n    PPH_PLUGIN plugin;\n    PH_STRINGREF pluginName;\n    PH_PLUGIN_PHSVC_REQUEST request;\n\n    if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.Plugin.i.ApiId, FALSE, &apiId)))\n    {\n        PH_AUTO(apiId);\n\n        if (PhPluginsEnabled &&\n            PhEmParseCompoundId(&apiId->sr, &pluginName, &request.SubId) &&\n            (plugin = PhFindPlugin2(&pluginName)))\n        {\n            request.ReturnStatus = STATUS_NOT_IMPLEMENTED;\n            request.InBuffer = Payload->u.Plugin.i.Data;\n            request.InLength = sizeof(Payload->u.Plugin.i.Data);\n            request.OutBuffer = Payload->u.Plugin.o.Data;\n            request.OutLength = sizeof(Payload->u.Plugin.o.Data);\n\n            request.ProbeBuffer = PhSvcProbeBuffer;\n            request.CaptureBuffer = PhSvcCaptureBuffer;\n            request.CaptureString = PhSvcCaptureString;\n\n            PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackPhSvcRequest), &request);\n            status = request.ReturnStatus;\n        }\n        else\n        {\n            status = STATUS_NOT_FOUND;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhSvcpCaptureRunAsServiceParameters(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload,\n    _Out_ PPH_RUNAS_SERVICE_PARAMETERS Parameters,\n    _Out_ PPHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS CapturedParameters\n    )\n{\n    NTSTATUS status;\n\n    memset(CapturedParameters, 0, sizeof(PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS));\n\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.UserName, TRUE, &CapturedParameters->UserName)))\n        return status;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.Password, TRUE, &CapturedParameters->Password)))\n        return status;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.CurrentDirectory, TRUE, &CapturedParameters->CurrentDirectory)))\n        return status;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.CommandLine, TRUE, &CapturedParameters->CommandLine)))\n        return status;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.FileName, TRUE, &CapturedParameters->FileName)))\n        return status;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.DesktopName, TRUE, &CapturedParameters->DesktopName)))\n        return status;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.ServiceName, TRUE, &CapturedParameters->ServiceName)))\n        return status;\n\n    Parameters->ProcessId = Payload->u.ExecuteRunAsCommand.i.ProcessId;\n    Parameters->UserName = PhGetString(CapturedParameters->UserName);\n    Parameters->Password = PhGetString(CapturedParameters->Password);\n    Parameters->LogonType = Payload->u.ExecuteRunAsCommand.i.LogonType;\n    Parameters->SessionId = Payload->u.ExecuteRunAsCommand.i.SessionId;\n    Parameters->CurrentDirectory = PhGetString(CapturedParameters->CurrentDirectory);\n    Parameters->CommandLine = PhGetString(CapturedParameters->CommandLine);\n    Parameters->FileName = PhGetString(CapturedParameters->FileName);\n    Parameters->DesktopName = PhGetString(CapturedParameters->DesktopName);\n    Parameters->UseLinkedToken = Payload->u.ExecuteRunAsCommand.i.UseLinkedToken;\n    Parameters->ServiceName = PhGetString(CapturedParameters->ServiceName);\n    Parameters->CreateSuspendedProcess = Payload->u.ExecuteRunAsCommand.i.CreateSuspendedProcess;\n    Parameters->CreateUIAccessProcess = Payload->u.ExecuteRunAsCommand.i.CreateUIAccessProcess;\n    Parameters->WindowHandle = Payload->u.ExecuteRunAsCommand.i.WindowHandle;\n\n    return status;\n}\n\nVOID PhSvcpReleaseRunAsServiceParameters(\n    _In_ PPHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS CapturedParameters\n    )\n{\n    if (CapturedParameters->UserName)\n        PhDereferenceObject(CapturedParameters->UserName);\n\n    if (CapturedParameters->Password)\n    {\n        RtlSecureZeroMemory(CapturedParameters->Password->Buffer, CapturedParameters->Password->Length);\n        PhDereferenceObject(CapturedParameters->Password);\n    }\n\n    if (CapturedParameters->CurrentDirectory)\n        PhDereferenceObject(CapturedParameters->CurrentDirectory);\n    if (CapturedParameters->CommandLine)\n        PhDereferenceObject(CapturedParameters->CommandLine);\n    if (CapturedParameters->FileName)\n        PhDereferenceObject(CapturedParameters->FileName);\n    if (CapturedParameters->DesktopName)\n        PhDereferenceObject(CapturedParameters->DesktopName);\n    if (CapturedParameters->ServiceName)\n        PhDereferenceObject(CapturedParameters->ServiceName);\n}\n\nNTSTATUS PhSvcpValidateRunAsServiceParameters(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    )\n{\n    if ((!Parameters->UserName || !Parameters->Password) && !Parameters->ProcessId)\n        return STATUS_INVALID_PARAMETER_MIX;\n    if (!Parameters->FileName && !Parameters->CommandLine)\n        return STATUS_INVALID_PARAMETER_MIX;\n    if (!Parameters->ServiceName)\n        return STATUS_INVALID_PARAMETER;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSvcApiExecuteRunAsCommand(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PH_RUNAS_SERVICE_PARAMETERS parameters;\n    PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS capturedParameters;\n\n    if (NT_SUCCESS(status = PhSvcpCaptureRunAsServiceParameters(Client, Payload, &parameters, &capturedParameters)))\n    {\n        if (NT_SUCCESS(status = PhSvcpValidateRunAsServiceParameters(&parameters)))\n        {\n            status = PhExecuteRunAsCommand(&parameters);\n        }\n    }\n\n    PhSvcpReleaseRunAsServiceParameters(&capturedParameters);\n\n    return status;\n}\n\nNTSTATUS PhSvcApiUnloadDriver(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PPH_STRING name;\n    PPH_STRING file;\n\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.UnloadDriver.i.Name, TRUE, &name)))\n        return status;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.UnloadDriver.i.FileName, TRUE, &file)))\n        return status;\n\n    if (!(PhIsNullOrEmptyString(name) && PhIsNullOrEmptyString(file)))\n    {\n        status = PhUnloadDriver(Payload->u.UnloadDriver.i.BaseAddress, &name->sr, &file->sr);\n    }\n    else\n    {\n        status = STATUS_DATA_ERROR;\n    }\n\n    PhClearReference(&name);\n    PhClearReference(&file);\n\n    return status;\n}\n\nNTSTATUS PhSvcApiControlProcess(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    HANDLE processId;\n    HANDLE processHandle;\n\n    processId = Payload->u.ControlProcess.i.ProcessId;\n\n    switch (Payload->u.ControlProcess.i.Command)\n    {\n    case PhSvcControlProcessTerminate:\n        if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_TERMINATE, processId)))\n        {\n            status = PhTerminateProcess(processHandle, 1); // see notes in PhUiTerminateProcesses\n\n            if (status == STATUS_SUCCESS || status == STATUS_PROCESS_IS_TERMINATING)\n                PhTerminateProcess(processHandle, DBG_TERMINATE_PROCESS); // debug terminate (dmex)\n\n            NtClose(processHandle);\n        }\n        break;\n    case PhSvcControlProcessSuspend:\n        if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SUSPEND_RESUME, processId)))\n        {\n            status = NtSuspendProcess(processHandle);\n            NtClose(processHandle);\n        }\n        break;\n    case PhSvcControlProcessResume:\n        if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SUSPEND_RESUME, processId)))\n        {\n            status = NtResumeProcess(processHandle);\n            NtClose(processHandle);\n        }\n        break;\n    case PhSvcControlProcessPriority:\n        if (processId != SYSTEM_PROCESS_ID)\n        {\n            if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SET_INFORMATION, processId)))\n            {\n                UCHAR priorityClass;\n\n                priorityClass = (UCHAR)Payload->u.ControlProcess.i.Argument;\n                status = PhSetProcessPriorityClass(processHandle, priorityClass);\n\n                NtClose(processHandle);\n            }\n        }\n        else\n        {\n            status = STATUS_UNSUCCESSFUL;\n        }\n        break;\n    case PhSvcControlProcessIoPriority:\n        if (processId != SYSTEM_PROCESS_ID)\n        {\n            if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SET_INFORMATION, processId)))\n            {\n                status = PhSetProcessIoPriority(processHandle, Payload->u.ControlProcess.i.Argument);\n                NtClose(processHandle);\n            }\n        }\n        else\n        {\n            status = STATUS_UNSUCCESSFUL;\n        }\n        break;\n    default:\n        status = STATUS_INVALID_PARAMETER;\n        break;\n    }\n\n    return status;\n}\n\nNTSTATUS PhSvcApiControlService(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PPH_STRING serviceName;\n    SC_HANDLE serviceHandle;\n\n    if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ControlService.i.ServiceName, FALSE, &serviceName)))\n    {\n        switch (Payload->u.ControlService.i.Command)\n        {\n        case PhSvcControlServiceStart:\n            {\n                if (NT_SUCCESS(status = PhOpenService(\n                    &serviceHandle,\n                    SERVICE_START,\n                    PhGetString(serviceName)\n                    )))\n                {\n                    status = PhStartService(serviceHandle, 0, NULL);\n\n                    PhCloseServiceHandle(serviceHandle);\n                }\n            }\n            break;\n        case PhSvcControlServiceContinue:\n            {\n                if (NT_SUCCESS(status = PhOpenService(\n                    &serviceHandle,\n                    SERVICE_PAUSE_CONTINUE,\n                    PhGetString(serviceName)\n                    )))\n                {\n                    status = PhContinueService(serviceHandle);\n\n                    PhCloseServiceHandle(serviceHandle);\n                }\n            }\n            break;\n        case PhSvcControlServicePause:\n            {\n                if (NT_SUCCESS(status = PhOpenService(\n                    &serviceHandle,\n                    SERVICE_PAUSE_CONTINUE,\n                    PhGetString(serviceName)\n                    )))\n                {\n                    status = PhPauseService(serviceHandle);\n\n                    PhCloseServiceHandle(serviceHandle);\n                }\n            }\n            break;\n        case PhSvcControlServiceStop:\n            {\n                if (NT_SUCCESS(status = PhOpenService(\n                    &serviceHandle,\n                    SERVICE_STOP,\n                    PhGetString(serviceName)\n                    )))\n                {\n                    status = PhStopService(serviceHandle);\n\n                    PhCloseServiceHandle(serviceHandle);\n                }\n            }\n            break;\n        case PhSvcControlServiceDelete:\n            {\n                if (NT_SUCCESS(status = PhOpenService(\n                    &serviceHandle,\n                    DELETE,\n                    PhGetString(serviceName)\n                    )))\n                {\n                    status = PhDeleteService(serviceHandle);\n\n                    PhCloseServiceHandle(serviceHandle);\n                }\n            }\n            break;\n        case PhSvcControlServiceRestart:\n            {\n                if (NT_SUCCESS(status = PhOpenService(\n                    &serviceHandle,\n                    SERVICE_QUERY_STATUS | SERVICE_STOP | SERVICE_START,\n                    PhGetString(serviceName)\n                    )))\n                {\n                    status = PhStopService(serviceHandle);\n\n                    if (NT_SUCCESS(status))\n                    {\n                        status = PhWaitForServiceStatus(\n                            serviceHandle,\n                            SERVICE_STOPPED,\n                            60 * 1000\n                            );\n\n                        if (NT_SUCCESS(status))\n                        {\n                            status = PhStartService(\n                                serviceHandle,\n                                0,\n                                NULL\n                                );\n\n                            if (NT_SUCCESS(status))\n                            {\n                                status = PhWaitForServiceStatus(\n                                    serviceHandle,\n                                    SERVICE_RUNNING,\n                                    60 * 1000\n                                    );\n                            }\n                        }\n                    }\n\n                    PhCloseServiceHandle(serviceHandle);\n                }\n            }\n            break;\n        default:\n            status = STATUS_INVALID_PARAMETER;\n            break;\n        }\n\n        PhDereferenceObject(serviceName);\n    }\n\n    return status;\n}\n\nNTSTATUS PhSvcApiCreateService(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PPH_STRING serviceName = NULL;\n    PPH_STRING displayName = NULL;\n    PPH_STRING binaryPathName = NULL;\n    PPH_STRING loadOrderGroup = NULL;\n    PPH_STRING dependencies = NULL;\n    PPH_STRING serviceStartName = NULL;\n    PPH_STRING password = NULL;\n    ULONG tagId = 0;\n    SC_HANDLE scManagerHandle;\n    SC_HANDLE serviceHandle;\n\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.ServiceName, FALSE, &serviceName)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.DisplayName, TRUE, &displayName)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.BinaryPathName, TRUE, &binaryPathName)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.LoadOrderGroup, TRUE, &loadOrderGroup)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.Dependencies, TRUE, &dependencies)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.ServiceStartName, TRUE, &serviceStartName)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.Password, TRUE, &password)))\n        goto CleanupExit;\n\n    if (scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE))\n    {\n        if (serviceHandle = CreateService(\n            scManagerHandle,\n            serviceName->Buffer,\n            PhGetString(displayName),\n            SERVICE_CHANGE_CONFIG,\n            Payload->u.CreateService.i.ServiceType,\n            Payload->u.CreateService.i.StartType,\n            Payload->u.CreateService.i.ErrorControl,\n            PhGetString(binaryPathName),\n            PhGetString(loadOrderGroup),\n            Payload->u.CreateService.i.TagIdSpecified ? &tagId : NULL,\n            PhGetString(dependencies),\n            PhGetString(serviceStartName),\n            PhGetString(password)\n            ))\n        {\n            Payload->u.CreateService.o.TagId = tagId;\n            PhCloseServiceHandle(serviceHandle);\n        }\n        else\n        {\n            status = PhGetLastWin32ErrorAsNtStatus();\n        }\n\n        PhCloseServiceHandle(scManagerHandle);\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\nCleanupExit:\n    if (password)\n    {\n        RtlSecureZeroMemory(password->Buffer, password->Length);\n        PhDereferenceObject(password);\n    }\n\n    PhClearReference(&serviceStartName);\n    PhClearReference(&dependencies);\n    PhClearReference(&loadOrderGroup);\n    PhClearReference(&binaryPathName);\n    PhClearReference(&displayName);\n    PhClearReference(&serviceName);\n\n    return status;\n}\n\nNTSTATUS PhSvcApiChangeServiceConfig(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PPH_STRING serviceName = NULL;\n    PPH_STRING binaryPathName = NULL;\n    PPH_STRING loadOrderGroup = NULL;\n    PPH_STRING dependencies = NULL;\n    PPH_STRING serviceStartName = NULL;\n    PPH_STRING password = NULL;\n    PPH_STRING displayName = NULL;\n    ULONG tagId = 0;\n    SC_HANDLE serviceHandle;\n\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.ServiceName, FALSE, &serviceName)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.BinaryPathName, TRUE, &binaryPathName)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.LoadOrderGroup, TRUE, &loadOrderGroup)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.Dependencies, TRUE, &dependencies)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.ServiceStartName, TRUE, &serviceStartName)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.Password, TRUE, &password)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.DisplayName, TRUE, &displayName)))\n        goto CleanupExit;\n\n    status = PhOpenService(&serviceHandle, SERVICE_CHANGE_CONFIG, PhGetString(serviceName));\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhChangeServiceConfig(\n            serviceHandle,\n            Payload->u.ChangeServiceConfig.i.ServiceType,\n            Payload->u.ChangeServiceConfig.i.StartType,\n            Payload->u.ChangeServiceConfig.i.ErrorControl,\n            PhGetString(binaryPathName),\n            PhGetString(loadOrderGroup),\n            Payload->u.ChangeServiceConfig.i.TagIdSpecified ? &tagId : NULL,\n            PhGetString(dependencies),\n            PhGetString(serviceStartName),\n            PhGetString(password),\n            PhGetString(displayName)\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            Payload->u.ChangeServiceConfig.o.TagId = tagId;\n        }\n\n        PhCloseServiceHandle(serviceHandle);\n    }\n\nCleanupExit:\n    PhClearReference(&displayName);\n\n    if (password)\n    {\n        RtlSecureZeroMemory(password->Buffer, password->Length);\n        PhDereferenceObject(password);\n    }\n\n    PhClearReference(&serviceStartName);\n    PhClearReference(&dependencies);\n    PhClearReference(&loadOrderGroup);\n    PhClearReference(&binaryPathName);\n    PhClearReference(&serviceName);\n\n    return status;\n}\n\nNTSTATUS PhSvcpUnpackRoot(\n    _In_ PPH_RELATIVE_STRINGREF PackedData,\n    _In_ PVOID CapturedBuffer,\n    _In_ SIZE_T Length,\n    _Out_ PVOID *ValidatedBuffer\n    )\n{\n    if (Length > PackedData->Length)\n        return STATUS_ACCESS_VIOLATION;\n\n    *ValidatedBuffer = CapturedBuffer;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSvcpUnpackBuffer(\n    _In_ PPH_RELATIVE_STRINGREF PackedData,\n    _In_ PVOID CapturedBuffer,\n    _In_ PVOID *OffsetInBuffer,\n    _In_ SIZE_T Length,\n    _In_ ULONG Alignment,\n    _In_ BOOLEAN AllowNull\n    )\n{\n    SIZE_T offset;\n\n    offset = (SIZE_T)*OffsetInBuffer;\n\n    if (offset == 0)\n    {\n        if (AllowNull)\n            return STATUS_SUCCESS;\n        else\n            return STATUS_ACCESS_VIOLATION;\n    }\n\n    if (offset + Length < offset)\n        return STATUS_ACCESS_VIOLATION;\n    if (offset + Length > PackedData->Length)\n        return STATUS_ACCESS_VIOLATION;\n    if (offset & (Alignment - 1))\n        return STATUS_DATATYPE_MISALIGNMENT;\n\n    *OffsetInBuffer = PTR_ADD_OFFSET(CapturedBuffer, offset);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSvcpUnpackStringZ(\n    _In_ PPH_RELATIVE_STRINGREF PackedData,\n    _In_ PVOID CapturedBuffer,\n    _In_ PVOID *OffsetInBuffer,\n    _In_ BOOLEAN Multi,\n    _In_ BOOLEAN AllowNull\n    )\n{\n    SIZE_T offset;\n    PWCHAR start;\n    PWCHAR end;\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF firstPart;\n\n    offset = (SIZE_T)*OffsetInBuffer;\n\n    if (offset == 0)\n    {\n        if (AllowNull)\n            return STATUS_SUCCESS;\n        else\n            return STATUS_ACCESS_VIOLATION;\n    }\n\n    if (offset >= PackedData->Length)\n        return STATUS_ACCESS_VIOLATION;\n    if (offset & 1)\n        return STATUS_DATATYPE_MISALIGNMENT;\n\n    start = (PWCHAR)PTR_ADD_OFFSET(CapturedBuffer, offset);\n    end = (PWCHAR)PTR_ADD_OFFSET(CapturedBuffer, (PackedData->Length & -2));\n    remainingPart.Buffer = start;\n    remainingPart.Length = (end - start) * sizeof(WCHAR);\n\n    if (Multi)\n    {\n        SIZE_T validatedLength = 0;\n\n        while (PhSplitStringRefAtChar(&remainingPart, UNICODE_NULL, &firstPart, &remainingPart))\n        {\n            validatedLength += firstPart.Length + sizeof(WCHAR);\n\n            if (firstPart.Length == 0)\n            {\n                *OffsetInBuffer = start;\n\n                return STATUS_SUCCESS;\n            }\n        }\n    }\n    else\n    {\n        if (PhSplitStringRefAtChar(&remainingPart, UNICODE_NULL, &firstPart, &remainingPart))\n        {\n            *OffsetInBuffer = start;\n\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return STATUS_ACCESS_VIOLATION;\n}\n\nNTSTATUS PhSvcApiChangeServiceConfig2(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PPH_STRING serviceName = NULL;\n    PVOID info = NULL;\n    SC_HANDLE serviceHandle;\n    PH_RELATIVE_STRINGREF packedData;\n    PVOID unpackedInfo = NULL;\n    ACCESS_MASK desiredAccess = SERVICE_CHANGE_CONFIG;\n\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig2.i.ServiceName, FALSE, &serviceName)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureBuffer(&Payload->u.ChangeServiceConfig2.i.Info, FALSE, &info)))\n        goto CleanupExit;\n\n    packedData = Payload->u.ChangeServiceConfig2.i.Info;\n\n    switch (Payload->u.ChangeServiceConfig2.i.InfoLevel)\n    {\n    case SERVICE_CONFIG_FAILURE_ACTIONS:\n        {\n            LPSERVICE_FAILURE_ACTIONS failureActions;\n\n            if (!NT_SUCCESS(status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_FAILURE_ACTIONS), &failureActions)))\n                goto CleanupExit;\n            if (!NT_SUCCESS(status = PhSvcpUnpackStringZ(&packedData, info, &failureActions->lpRebootMsg, FALSE, TRUE)))\n                goto CleanupExit;\n            if (!NT_SUCCESS(status = PhSvcpUnpackStringZ(&packedData, info, &failureActions->lpCommand, FALSE, TRUE)))\n                goto CleanupExit;\n            if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &failureActions->lpsaActions, failureActions->cActions * sizeof(SC_ACTION), __alignof(SC_ACTION), TRUE)))\n                goto CleanupExit;\n\n            if (failureActions->lpsaActions)\n            {\n                ULONG i;\n\n                for (i = 0; i < failureActions->cActions; i++)\n                {\n                    if (failureActions->lpsaActions[i].Type == SC_ACTION_RESTART)\n                    {\n                        desiredAccess |= SERVICE_START;\n                        break;\n                    }\n                }\n            }\n\n            unpackedInfo = failureActions;\n        }\n        break;\n    case SERVICE_CONFIG_DELAYED_AUTO_START_INFO:\n        status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_DELAYED_AUTO_START_INFO), &unpackedInfo);\n        break;\n    case SERVICE_CONFIG_FAILURE_ACTIONS_FLAG:\n        status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_FAILURE_ACTIONS_FLAG), &unpackedInfo);\n        break;\n    case SERVICE_CONFIG_SERVICE_SID_INFO:\n        status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_SID_INFO), &unpackedInfo);\n        break;\n    case SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO:\n        {\n            LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo;\n\n            if (!NT_SUCCESS(status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_REQUIRED_PRIVILEGES_INFO), &requiredPrivilegesInfo)))\n                goto CleanupExit;\n            if (!NT_SUCCESS(status = PhSvcpUnpackStringZ(&packedData, info, &requiredPrivilegesInfo->pmszRequiredPrivileges, TRUE, FALSE)))\n                goto CleanupExit;\n\n            unpackedInfo = requiredPrivilegesInfo;\n        }\n        break;\n    case SERVICE_CONFIG_PRESHUTDOWN_INFO:\n        status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_PRESHUTDOWN_INFO), &unpackedInfo);\n        break;\n    case SERVICE_CONFIG_TRIGGER_INFO:\n        {\n            PSERVICE_TRIGGER_INFO triggerInfo;\n            ULONG i;\n            PSERVICE_TRIGGER trigger;\n            ULONG j;\n            PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM dataItem;\n            ULONG alignment;\n\n            if (!NT_SUCCESS(status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_TRIGGER_INFO), &triggerInfo)))\n                goto CleanupExit;\n            if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &triggerInfo->pTriggers, triggerInfo->cTriggers * sizeof(SERVICE_TRIGGER), __alignof(SERVICE_TRIGGER), TRUE)))\n                goto CleanupExit;\n\n            if (triggerInfo->pTriggers)\n            {\n                for (i = 0; i < triggerInfo->cTriggers; i++)\n                {\n                    trigger = &triggerInfo->pTriggers[i];\n\n                    if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &trigger->pTriggerSubtype, sizeof(GUID), __alignof(GUID), TRUE)))\n                        goto CleanupExit;\n                    if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &trigger->pDataItems, trigger->cDataItems * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), __alignof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), TRUE)))\n                        goto CleanupExit;\n\n                    if (trigger->pDataItems)\n                    {\n                        for (j = 0; j < trigger->cDataItems; j++)\n                        {\n                            dataItem = &trigger->pDataItems[j];\n                            alignment = 1;\n\n                            switch (dataItem->dwDataType)\n                            {\n                            case SERVICE_TRIGGER_DATA_TYPE_BINARY:\n                            case SERVICE_TRIGGER_DATA_TYPE_LEVEL:\n                                alignment = sizeof(CHAR);\n                                break;\n                            case SERVICE_TRIGGER_DATA_TYPE_STRING:\n                                alignment = sizeof(WCHAR);\n                                break;\n                            case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY:\n                            case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL:\n                                alignment = sizeof(ULONG64);\n                                break;\n                            }\n\n                            if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &dataItem->pData, dataItem->cbData, alignment, FALSE)))\n                                goto CleanupExit;\n                        }\n                    }\n                }\n            }\n\n            unpackedInfo = triggerInfo;\n        }\n        break;\n    case SERVICE_CONFIG_LAUNCH_PROTECTED:\n        status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_LAUNCH_PROTECTED_INFO), &unpackedInfo);\n        break;\n    default:\n        status = STATUS_INVALID_PARAMETER;\n        break;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        assert(unpackedInfo);\n\n        status = PhOpenService(&serviceHandle, desiredAccess, PhGetString(serviceName));\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhChangeServiceConfig2(\n                serviceHandle,\n                Payload->u.ChangeServiceConfig2.i.InfoLevel,\n                unpackedInfo\n                );\n\n            PhCloseServiceHandle(serviceHandle);\n        }\n    }\n\nCleanupExit:\n    if (info)\n        PhFree(info);\n    if (serviceName)\n        PhDereferenceObject(serviceName);\n\n    return status;\n}\n\nNTSTATUS PhSvcApiSetTcpEntry(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    static PVOID setTcpEntry = NULL;\n\n    ULONG (__stdcall *localSetTcpEntry)(PVOID TcpRow);\n    struct\n    {\n        ULONG dwState;\n        ULONG dwLocalAddr;\n        ULONG dwLocalPort;\n        ULONG dwRemoteAddr;\n        ULONG dwRemotePort;\n    } tcpRow;\n    ULONG result;\n\n    localSetTcpEntry = ReadPointerAcquire(&setTcpEntry);\n\n    if (!localSetTcpEntry)\n    {\n        PVOID iphlpapiModule;\n\n        iphlpapiModule = PhLoadLibrary(L\"iphlpapi.dll\");\n\n        if (iphlpapiModule)\n        {\n            localSetTcpEntry = PhGetDllBaseProcedureAddress(iphlpapiModule, \"SetTcpEntry\", 0);\n\n            if (localSetTcpEntry)\n            {\n                if (_InterlockedExchangePointer(&setTcpEntry, localSetTcpEntry) != NULL)\n                {\n                    // Another thread got the address of SetTcpEntry already.\n                    // Decrement the reference count of iphlpapi.dll.\n                    PhFreeLibrary(iphlpapiModule);\n                }\n            }\n        }\n    }\n\n    if (!localSetTcpEntry)\n        return STATUS_NOT_SUPPORTED;\n\n    tcpRow.dwState = Payload->u.SetTcpEntry.i.State;\n    tcpRow.dwLocalAddr = Payload->u.SetTcpEntry.i.LocalAddress;\n    tcpRow.dwLocalPort = Payload->u.SetTcpEntry.i.LocalPort;\n    tcpRow.dwRemoteAddr = Payload->u.SetTcpEntry.i.RemoteAddress;\n    tcpRow.dwRemotePort = Payload->u.SetTcpEntry.i.RemotePort;\n    result = localSetTcpEntry(&tcpRow);\n\n    return PhDosErrorToNtStatus(result);\n}\n\nNTSTATUS PhSvcApiControlThread(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    HANDLE threadId;\n    HANDLE threadHandle;\n\n    threadId = Payload->u.ControlThread.i.ThreadId;\n\n    switch (Payload->u.ControlThread.i.Command)\n    {\n    case PhSvcControlThreadTerminate:\n        if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_TERMINATE, threadId)))\n        {\n            status = PhTerminateThread(threadHandle, STATUS_SUCCESS);\n            NtClose(threadHandle);\n        }\n        break;\n    case PhSvcControlThreadSuspend:\n        if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, threadId)))\n        {\n            status = NtSuspendThread(threadHandle, NULL);\n            NtClose(threadHandle);\n        }\n        break;\n    case PhSvcControlThreadResume:\n        if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, threadId)))\n        {\n            status = NtResumeThread(threadHandle, NULL);\n            NtClose(threadHandle);\n        }\n        break;\n    case PhSvcControlThreadIoPriority:\n        if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SET_INFORMATION, threadId)))\n        {\n            status = PhSetThreadIoPriority(threadHandle, Payload->u.ControlThread.i.Argument);\n            NtClose(threadHandle);\n        }\n        break;\n    default:\n        status = STATUS_INVALID_PARAMETER;\n        break;\n    }\n\n    return status;\n}\n\nNTSTATUS PhSvcApiAddAccountRight(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PSID accountSid;\n    PPH_STRING userRight;\n    LSA_HANDLE policyHandle;\n    UNICODE_STRING userRightUs;\n\n    if (NT_SUCCESS(status = PhSvcCaptureSid(&Payload->u.AddAccountRight.i.AccountSid, FALSE, &accountSid)))\n    {\n        if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.AddAccountRight.i.UserRight, FALSE, &userRight)))\n        {\n            PH_AUTO(userRight);\n\n            if (NT_SUCCESS(status = PhOpenLsaPolicy(&policyHandle, POLICY_LOOKUP_NAMES | POLICY_CREATE_ACCOUNT, NULL)))\n            {\n                PhStringRefToUnicodeString(&userRight->sr, &userRightUs);\n                status = LsaAddAccountRights(policyHandle, accountSid, &userRightUs, 1);\n                LsaClose(policyHandle);\n            }\n        }\n\n        PhFree(accountSid);\n    }\n\n    return status;\n}\n\nNTSTATUS PhSvcApiInvokeRunAsService(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PH_RUNAS_SERVICE_PARAMETERS parameters;\n    PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS capturedParameters;\n\n    if (NT_SUCCESS(status = PhSvcpCaptureRunAsServiceParameters(Client, Payload, &parameters, &capturedParameters)))\n    {\n        if (NT_SUCCESS(status = PhSvcpValidateRunAsServiceParameters(&parameters)))\n        {\n            status = PhInvokeRunAsService(&parameters);\n        }\n    }\n\n    PhSvcpReleaseRunAsServiceParameters(&capturedParameters);\n\n    return status;\n}\n\nNTSTATUS PhSvcApiIssueMemoryListCommand(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n\n    status = NtSetSystemInformation(\n        SystemMemoryListInformation,\n        &Payload->u.IssueMemoryListCommand.i.Command,\n        sizeof(SYSTEM_MEMORY_LIST_COMMAND)\n        );\n\n    return status;\n}\n\nNTSTATUS PhSvcApiPostMessage(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    if (PostMessage(\n        Payload->u.PostMessage.i.hWnd,\n        Payload->u.PostMessage.i.Msg,\n        Payload->u.PostMessage.i.wParam,\n        Payload->u.PostMessage.i.lParam\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        return PhGetLastWin32ErrorAsNtStatus();\n    }\n}\n\nNTSTATUS PhSvcApiSendMessage(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    ULONG_PTR result = 0;\n\n    if (PhSendMessageTimeout(\n        Payload->u.PostMessage.i.hWnd,\n        Payload->u.PostMessage.i.Msg,\n        Payload->u.PostMessage.i.wParam,\n        Payload->u.PostMessage.i.lParam,\n        5000,\n        &result\n        ) && result > 0)\n    {\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        return STATUS_UNSUCCESSFUL;\n    }\n}\n\nNTSTATUS PhSvcApiCreateProcessIgnoreIfeoDebugger(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName = NULL;\n    PPH_STRING commandLine = NULL;\n\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateProcessIgnoreIfeoDebugger.i.FileName, FALSE, &fileName)))\n        goto CleanupExit;\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateProcessIgnoreIfeoDebugger.i.CommandLine, TRUE, &commandLine)))\n        goto CleanupExit;\n\n    if (!PhCreateProcessIgnoreIfeoDebugger(PhGetString(fileName), PhGetString(commandLine)))\n        status = STATUS_UNSUCCESSFUL;\n\nCleanupExit:\n    if (fileName)\n        PhDereferenceObject(fileName);\n    if (commandLine)\n        PhDereferenceObject(commandLine);\n\n    return status;\n}\n\nNTSTATUS PhSvcApiSetServiceSecurity(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PPH_STRING serviceName;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    ACCESS_MASK desiredAccess;\n    SC_HANDLE serviceHandle;\n\n    if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.SetServiceSecurity.i.ServiceName, FALSE, &serviceName)))\n    {\n        PH_AUTO(serviceName);\n\n        if (NT_SUCCESS(status = PhSvcCaptureSecurityDescriptor(&Payload->u.SetServiceSecurity.i.SecurityDescriptor, FALSE, 0, &securityDescriptor)))\n        {\n            desiredAccess = 0;\n\n            if ((Payload->u.SetServiceSecurity.i.SecurityInformation & OWNER_SECURITY_INFORMATION) ||\n                (Payload->u.SetServiceSecurity.i.SecurityInformation & GROUP_SECURITY_INFORMATION))\n            {\n                desiredAccess |= WRITE_OWNER;\n            }\n\n            if (Payload->u.SetServiceSecurity.i.SecurityInformation & DACL_SECURITY_INFORMATION)\n            {\n                desiredAccess |= WRITE_DAC;\n            }\n\n            if (Payload->u.SetServiceSecurity.i.SecurityInformation & SACL_SECURITY_INFORMATION)\n            {\n                desiredAccess |= ACCESS_SYSTEM_SECURITY;\n            }\n\n            status = PhOpenService(&serviceHandle, desiredAccess, PhGetString(serviceName));\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhSetSeObjectSecurity(\n                    serviceHandle,\n                    SE_SERVICE,\n                    Payload->u.SetServiceSecurity.i.SecurityInformation,\n                    securityDescriptor\n                    );\n                PhCloseServiceHandle(serviceHandle);\n            }\n\n            PhFree(securityDescriptor);\n        }\n    }\n\n    return status;\n}\n\nstatic BOOL CALLBACK PhpProcessMiniDumpCallback(\n    _In_ PVOID CallbackParam,\n    _In_ const PMINIDUMP_CALLBACK_INPUT CallbackInput,\n    _Inout_ PMINIDUMP_CALLBACK_OUTPUT CallbackOutput\n    )\n{\n    switch (CallbackInput->CallbackType)\n    {\n    case IsProcessSnapshotCallback:\n        if (CallbackParam)\n            CallbackOutput->Status = S_FALSE;\n        break;\n    case ReadMemoryFailureCallback:\n        CallbackOutput->Status = S_OK;\n        break;\n    }\n\n    return TRUE;\n}\n\nNTSTATUS PhSvcApiWriteMiniDumpProcess(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    MINIDUMP_CALLBACK_INFORMATION callbackInfo;\n    HANDLE processHandle = UlongToHandle(Payload->u.WriteMiniDumpProcess.i.LocalProcessHandle);\n    ULONG processDumpType = Payload->u.WriteMiniDumpProcess.i.DumpType;\n    HRESULT status = E_UNEXPECTED;\n    HANDLE snapshotHandle = NULL;\n\n    if (NT_SUCCESS(PhCreateProcessSnapshot(&snapshotHandle, processHandle)))\n    {\n        processDumpType =\n            MiniDumpWithFullMemory |\n            MiniDumpWithHandleData |\n            MiniDumpWithUnloadedModules |\n            MiniDumpWithFullMemoryInfo |\n            MiniDumpWithThreadInfo |\n            MiniDumpIgnoreInaccessibleMemory |\n            MiniDumpWithIptTrace;\n    }\n\n    memset(&callbackInfo, 0, sizeof(callbackInfo));\n    callbackInfo.CallbackRoutine = PhpProcessMiniDumpCallback;\n    callbackInfo.CallbackParam = snapshotHandle;\n\n    status = PhWriteMiniDumpProcess(\n        snapshotHandle ? snapshotHandle : processHandle,\n        UlongToHandle(Payload->u.WriteMiniDumpProcess.i.ProcessId),\n        UlongToHandle(Payload->u.WriteMiniDumpProcess.i.LocalFileHandle),\n        processDumpType,\n        NULL,\n        NULL,\n        &callbackInfo\n        );\n\n    if (HR_SUCCESS(status))\n    {\n        if (snapshotHandle)\n        {\n            PhFreeProcessSnapshot(snapshotHandle, processHandle);\n        }\n\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        if (snapshotHandle)\n        {\n            PhFreeProcessSnapshot(snapshotHandle, processHandle);\n        }\n\n        if (status == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))\n            return STATUS_INVALID_PARAMETER;\n        else\n            return STATUS_UNSUCCESSFUL;\n    }\n}\n\nNTSTATUS PhSvcApiQueryProcessHeapInformation(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PVOID dataBuffer;\n    PPH_PROCESS_DEBUG_HEAP_INFORMATION heapInfo;\n    PPH_STRING heapInfoHexBuffer;\n\n    if (!NT_SUCCESS(status = PhSvcProbeBuffer(&Payload->u.QueryProcessHeap.i.Data, sizeof(WCHAR), FALSE, &dataBuffer)))\n        return status;\n\n    if (!NT_SUCCESS(status = PhQueryProcessHeapInformation(UlongToHandle(Payload->u.QueryProcessHeap.i.ProcessId), &heapInfo)))\n        return status;\n\n    heapInfoHexBuffer = PhBufferToHexString(\n        (PUCHAR)heapInfo,\n        sizeof(PH_PROCESS_DEBUG_HEAP_INFORMATION) + heapInfo->NumberOfHeaps * sizeof(PH_PROCESS_DEBUG_HEAP_ENTRY)\n        );\n\n    if (Payload->u.QueryProcessHeap.i.Data.Length < heapInfoHexBuffer->Length)\n    {\n        status = STATUS_BUFFER_OVERFLOW;\n        goto CleanupExit;\n    }\n\n    memcpy(dataBuffer, heapInfoHexBuffer->Buffer, min(heapInfoHexBuffer->Length, Payload->u.QueryProcessHeap.i.Data.Length));\n    Payload->u.QueryProcessHeap.o.DataLength = (ULONG)heapInfoHexBuffer->Length;\n\nCleanupExit:\n    if (heapInfoHexBuffer)\n        PhDereferenceObject(heapInfoHexBuffer);\n    if (heapInfo)\n        PhFree(heapInfo);\n\n    return status;\n}\n\nNTSTATUS PhSvcApiCreateProcessForKsi(\n    _In_ PPHSVC_CLIENT Client,\n    _Inout_ PPHSVC_API_PAYLOAD Payload\n    )\n{\n    NTSTATUS status;\n    PPH_STRING commandLine = NULL;\n    PPROC_THREAD_ATTRIBUTE_LIST attributeList = NULL;\n    STARTUPINFOEX startupInfoEx;\n    HANDLE processHandle = NULL;\n    HANDLE tokenHandle = NULL;\n    PVOID environment = NULL;\n\n    if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateProcessForKsi.i.CommandLine, TRUE, &commandLine)))\n        goto CleanupExit;\n\n    if (Payload->u.CreateProcessForKsi.i.MitigationFlags[0] || Payload->u.CreateProcessForKsi.i.MitigationFlags[1])\n    {\n        status = PhInitializeProcThreadAttributeList(&attributeList, 1);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        if (WindowsVersion >= WINDOWS_10_22H2)\n        {\n            status = PhUpdateProcThreadAttribute(\n                attributeList,\n                PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,\n                Payload->u.CreateProcessForKsi.i.MitigationFlags,\n                sizeof(ULONG64) * 2\n                );\n        }\n        else\n        {\n            status = PhUpdateProcThreadAttribute(\n                attributeList,\n                PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,\n                Payload->u.CreateProcessForKsi.i.MitigationFlags,\n                sizeof(ULONG64) * 1\n                );\n        }\n    }\n\n    memset(&startupInfoEx, 0, sizeof(STARTUPINFOEX));\n    startupInfoEx.StartupInfo.cb = sizeof(STARTUPINFOEX);\n    startupInfoEx.lpAttributeList = attributeList;\n\n    // ClientId is verified to be System Informer, see: PhSvcHandleConnectionRequest\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        Client->ClientId.UniqueProcess\n        )))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhOpenProcessToken(\n        processHandle,\n        TOKEN_ALL_ACCESS,\n        &tokenHandle\n        )))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhCreateEnvironmentBlock(&environment, tokenHandle, FALSE)))\n        goto CleanupExit;\n\n    status = PhCreateProcessWin32Ex(\n        NULL,\n        PhGetString(commandLine),\n        environment,\n        NULL,\n        &startupInfoEx,\n        (PH_CREATE_PROCESS_DEFAULT_ERROR_MODE |\n         PH_CREATE_PROCESS_EXTENDED_STARTUPINFO |\n         PH_CREATE_PROCESS_UNICODE_ENVIRONMENT),\n        tokenHandle,\n        NULL,\n        NULL,\n        NULL\n        );\n\nCleanupExit:\n\n    if (environment)\n        PhDestroyEnvironmentBlock(environment);\n\n    if (tokenHandle)\n        NtClose(tokenHandle);\n\n    if (processHandle)\n        NtClose(processHandle);\n\n    if (attributeList)\n        PhDeleteProcThreadAttributeList(attributeList);\n\n    PhClearReference(&commandLine);\n\n    return status;\n}\n"
  },
  {
    "path": "SystemInformer/phsvc/svcapiport.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2015\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <phsvc.h>\n#include <verify.h>\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhSvcApiRequestThreadStart(\n    _In_ PVOID Parameter\n    );\n\nextern HANDLE PhSvcTimeoutStandbyEventHandle;\nextern HANDLE PhSvcTimeoutCancelEventHandle;\n\nULONG PhSvcApiThreadContextTlsIndex;\nHANDLE PhSvcApiPortHandle;\nvolatile LONG PhSvcApiNumberOfClients = 0;\n\nNTSTATUS PhSvcApiPortInitialization(\n    _In_ PUNICODE_STRING PortName\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    ULONG sdAllocationLength;\n    PSID administratorsSid;\n    PACL dacl;\n    ULONG i;\n\n    // Create the API port.\n\n    administratorsSid = PhSeAdministratorsSid();\n\n    sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH +\n        (ULONG)sizeof(ACL) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        PhLengthSid(administratorsSid) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        PhLengthSid((PSID)&PhSeEveryoneSid);\n\n    securityDescriptor = PhAllocateZero(sdAllocationLength);\n    dacl = (PACL)PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH);\n\n    PhCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n    PhCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION);\n    PhAddAccessAllowedAce(dacl, ACL_REVISION, PORT_ALL_ACCESS, administratorsSid);\n    PhAddAccessAllowedAce(dacl, ACL_REVISION, PORT_CONNECT, (PSID)&PhSeEveryoneSid);\n    PhSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE);\n    assert(RtlValidSecurityDescriptor(securityDescriptor));\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        PortName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        securityDescriptor\n        );\n\n    status = NtCreatePort(\n        &PhSvcApiPortHandle,\n        &objectAttributes,\n        sizeof(PHSVC_API_CONNECTINFO),\n        PhIsExecutingInWow64() ? sizeof(PHSVC_API_MSG64) : sizeof(PHSVC_API_MSG),\n        0\n        );\n    PhFree(securityDescriptor);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Start the API threads.\n\n    PhSvcApiThreadContextTlsIndex = PhTlsAlloc();\n\n    if (PhSvcApiThreadContextTlsIndex == TLS_OUT_OF_INDEXES)\n        return STATUS_NO_MEMORY;\n\n    for (i = 0; i < 2; i++)\n    {\n        PhCreateThread2(PhSvcApiRequestThreadStart, NULL);\n    }\n\n    return status;\n}\n\nPPHSVC_THREAD_CONTEXT PhSvcGetCurrentThreadContext(\n    VOID\n    )\n{\n    return (PPHSVC_THREAD_CONTEXT)PhTlsGetValue(PhSvcApiThreadContextTlsIndex);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhSvcApiRequestThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PH_AUTO_POOL autoPool;\n    NTSTATUS status;\n    PHSVC_THREAD_CONTEXT threadContext;\n    HANDLE portHandle;\n    PVOID portContext;\n    SIZE_T messageSize;\n    PPORT_MESSAGE receiveMessage;\n    PPORT_MESSAGE replyMessage;\n    CSHORT messageType;\n    PPHSVC_CLIENT client;\n    PPHSVC_API_PAYLOAD payload;\n\n    PhInitializeAutoPool(&autoPool);\n\n    threadContext.CurrentClient = NULL;\n    threadContext.OldClient = NULL;\n\n    status = PhTlsSetValue(PhSvcApiThreadContextTlsIndex, &threadContext);\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDeleteAutoPool(&autoPool);\n        return status;\n    }\n\n    portHandle = PhSvcApiPortHandle;\n    messageSize = PhIsExecutingInWow64() ? sizeof(PHSVC_API_MSG64) : sizeof(PHSVC_API_MSG);\n    receiveMessage = PhAllocatePageZero(messageSize);\n    replyMessage = NULL;\n\n    if (!receiveMessage)\n    {\n        PhDeleteAutoPool(&autoPool);\n        return STATUS_NO_MEMORY;\n    }\n\n    while (TRUE)\n    {\n        status = NtReplyWaitReceivePort(\n            portHandle,\n            &portContext,\n            replyMessage,\n            receiveMessage\n            );\n\n        portHandle = PhSvcApiPortHandle;\n        replyMessage = NULL;\n\n        if (!NT_SUCCESS(status))\n        {\n            // Client probably died.\n            continue;\n        }\n\n        messageType = receiveMessage->u2.s2.Type;\n\n        if (messageType == LPC_CONNECTION_REQUEST)\n        {\n            PhSvcHandleConnectionRequest(receiveMessage);\n            continue;\n        }\n\n        if (!portContext)\n            continue;\n\n        client = portContext;\n        threadContext.CurrentClient = client;\n        PhWaitForEvent(&client->ReadyEvent, NULL);\n\n        if (messageType == LPC_REQUEST)\n        {\n            if (PhIsExecutingInWow64())\n                payload = &((PPHSVC_API_MSG64)receiveMessage)->p;\n            else\n                payload = &((PPHSVC_API_MSG)receiveMessage)->p;\n\n            PhSvcDispatchApiCall(client, payload, &portHandle);\n            replyMessage = receiveMessage;\n        }\n        else if (messageType == LPC_PORT_CLOSED)\n        {\n            PhDereferenceObject(client);\n\n            if (_InterlockedDecrement(&PhSvcApiNumberOfClients) == 0)\n            {\n                NtSetEvent(PhSvcTimeoutStandbyEventHandle, NULL);\n            }\n        }\n\n        assert(!threadContext.OldClient);\n        PhDrainAutoPool(&autoPool);\n    }\n\n    PhDeleteAutoPool(&autoPool);\n}\n\nBOOLEAN PhSvcHandleVerify(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    BOOLEAN status = FALSE;\n    HANDLE fileHandle;\n\n    if (NT_SUCCESS(PhCreateFile(\n        &fileHandle,\n        FileName,\n        FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE | DELETE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        )))\n    {\n        VERIFY_RESULT result;\n        PH_VERIFY_FILE_INFO info;\n\n        memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO));\n        info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS;\n        info.FileHandle = fileHandle;\n\n        if (NT_SUCCESS(PhVerifyFileEx(&info, &result, NULL, NULL)))\n        {\n            if (result == VrTrusted)\n            {\n                status = TRUE;\n            }\n        }\n\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\nVOID PhSvcHandleConnectionRequest(\n    _In_ PPORT_MESSAGE PortMessage\n    )\n{\n    NTSTATUS status;\n    PPHSVC_API_MSG message;\n    PPHSVC_API_MSG64 message64;\n    CLIENT_ID clientId;\n    PPHSVC_CLIENT client;\n    HANDLE portHandle;\n    REMOTE_PORT_VIEW clientView;\n    REMOTE_PORT_VIEW64 clientView64;\n    PREMOTE_PORT_VIEW actualClientView;\n\n    message = (PPHSVC_API_MSG)PortMessage;\n    message64 = (PPHSVC_API_MSG64)PortMessage;\n\n    if (PhIsExecutingInWow64())\n    {\n        clientId.UniqueProcess = (HANDLE)message64->h.ClientId.UniqueProcess;\n        clientId.UniqueThread = (HANDLE)message64->h.ClientId.UniqueThread;\n\n#if defined(PH_BUILD_API)\n        PPH_STRING remoteFileName;\n\n        remoteFileName = NULL;\n        PhGetProcessImageFileNameByProcessId(clientId.UniqueProcess, &remoteFileName);\n        PH_AUTO(remoteFileName);\n\n        if (PhIsNullOrEmptyString(remoteFileName) || !PhSvcHandleVerify(&remoteFileName->sr))\n        {\n            NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL);\n            return;\n        }\n#endif // PH_BUILD_API\n    }\n    else\n    {\n        clientId = message->h.ClientId;\n\n#if defined(DEBUG) || defined(PH_BUILD_API)\n        PPH_STRING remoteFileName;\n#endif\n#if defined(DEBUG)\n        PPH_STRING referenceFileName;\n\n        // Make sure that the remote process is System Informer and not some other program.\n\n        referenceFileName = NULL;\n        PhGetProcessImageFileNameByProcessId(NtCurrentProcessId(), &referenceFileName);\n        PH_AUTO(referenceFileName);\n\n        remoteFileName = NULL;\n        PhGetProcessImageFileNameByProcessId(clientId.UniqueProcess, &remoteFileName);\n        PH_AUTO(remoteFileName);\n\n        if (PhIsNullOrEmptyString(referenceFileName) || PhIsNullOrEmptyString(remoteFileName) || !PhEqualString(referenceFileName, remoteFileName, FALSE))\n        {\n            NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL);\n            return;\n        }\n#endif // DEBUG\n#if defined(PH_BUILD_API)\n        remoteFileName = NULL;\n        clientId = message->h.ClientId;\n        PhGetProcessImageFileNameByProcessId(clientId.UniqueProcess, &remoteFileName);\n        PH_AUTO(remoteFileName);\n\n        if (PhIsNullOrEmptyString(remoteFileName) || !PhSvcHandleVerify(&remoteFileName->sr))\n        {\n            NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL);\n            return;\n        }\n#endif // PH_BUILD_API\n    }\n\n    client = PhSvcCreateClient(&clientId);\n\n    if (!client)\n    {\n        NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL);\n        return;\n    }\n\n    if (PhIsExecutingInWow64())\n    {\n        message64->p.ConnectInfo.ServerProcessId = HandleToUlong(NtCurrentProcessId());\n\n        memset(&clientView64, 0, sizeof(REMOTE_PORT_VIEW64));\n        clientView64.Length = sizeof(REMOTE_PORT_VIEW64);\n        clientView64.ViewSize = 0;\n        clientView64.ViewBase = 0;\n        actualClientView = (PREMOTE_PORT_VIEW)&clientView64;\n    }\n    else\n    {\n        message->p.ConnectInfo.ServerProcessId = HandleToUlong(NtCurrentProcessId());\n\n        memset(&clientView, 0, sizeof(REMOTE_PORT_VIEW));\n        clientView.Length = sizeof(REMOTE_PORT_VIEW);\n        clientView.ViewSize = 0;\n        clientView.ViewBase = NULL;\n        actualClientView = &clientView;\n    }\n\n    status = NtAcceptConnectPort(\n        &portHandle,\n        client,\n        PortMessage,\n        TRUE,\n        NULL,\n        actualClientView\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(client);\n        return;\n    }\n\n    // IMPORTANT: Since Vista, NtCompleteConnectPort does not do anything and simply returns STATUS_SUCCESS.\n    // We will call it anyway (for completeness), but we need to use an event to ensure that other threads don't try\n    // to process requests before we have finished setting up the client object.\n\n    client->PortHandle = portHandle;\n\n    if (PhIsExecutingInWow64())\n    {\n        client->ClientViewBase = (PVOID)clientView64.ViewBase;\n        client->ClientViewLimit = PTR_ADD_OFFSET(clientView64.ViewBase, clientView64.ViewSize);\n    }\n    else\n    {\n        client->ClientViewBase = clientView.ViewBase;\n        client->ClientViewLimit = PTR_ADD_OFFSET(clientView.ViewBase, clientView.ViewSize);\n    }\n\n    //NtCompleteConnectPort(portHandle); // (dmex)\n    PhSetEvent(&client->ReadyEvent);\n\n    if (_InterlockedIncrement(&PhSvcApiNumberOfClients) == 1)\n    {\n        NtSetEvent(PhSvcTimeoutCancelEventHandle, NULL);\n    }\n}\n"
  },
  {
    "path": "SystemInformer/phsvc/svcclient.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2015\n *\n */\n\n#include <phapp.h>\n#include <phsvc.h>\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhSvcpClientDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nPPH_OBJECT_TYPE PhSvcClientType = NULL;\nRTL_STATIC_LIST_HEAD(PhSvcClientListHead);\nPH_QUEUED_LOCK PhSvcClientListLock = PH_QUEUED_LOCK_INIT;\n\nPPHSVC_CLIENT PhSvcCreateClient(\n    _In_opt_ PCLIENT_ID ClientId\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPHSVC_CLIENT client;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhSvcClientType = PhCreateObjectType(L\"PhSvcClient\", 0, PhSvcpClientDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    client = PhCreateObject(sizeof(PHSVC_CLIENT), PhSvcClientType);\n    memset(client, 0, sizeof(PHSVC_CLIENT));\n    PhInitializeEvent(&client->ReadyEvent);\n\n    if (ClientId)\n        client->ClientId = *ClientId;\n\n    PhAcquireQueuedLockExclusive(&PhSvcClientListLock);\n    InsertTailList(&PhSvcClientListHead, &client->ListEntry);\n    PhReleaseQueuedLockExclusive(&PhSvcClientListLock);\n\n    return client;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhSvcpClientDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPHSVC_CLIENT client = Object;\n\n    PhAcquireQueuedLockExclusive(&PhSvcClientListLock);\n    RemoveEntryList(&client->ListEntry);\n    PhReleaseQueuedLockExclusive(&PhSvcClientListLock);\n\n    if (client->PortHandle)\n        NtClose(client->PortHandle);\n}\n\nPPHSVC_CLIENT PhSvcReferenceClientByClientId(\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    PLIST_ENTRY listEntry;\n    PPHSVC_CLIENT client = NULL;\n\n    PhAcquireQueuedLockShared(&PhSvcClientListLock);\n\n    listEntry = PhSvcClientListHead.Flink;\n\n    while (listEntry != &PhSvcClientListHead)\n    {\n        client = CONTAINING_RECORD(listEntry, PHSVC_CLIENT, ListEntry);\n\n        if (ClientId->UniqueThread)\n        {\n            if (\n                client->ClientId.UniqueProcess == ClientId->UniqueProcess &&\n                client->ClientId.UniqueThread == ClientId->UniqueThread\n                )\n            {\n                break;\n            }\n        }\n        else\n        {\n            if (client->ClientId.UniqueProcess == ClientId->UniqueProcess)\n                break;\n        }\n\n        client = NULL;\n\n        listEntry = listEntry->Flink;\n    }\n\n    if (client)\n    {\n        if (!PhReferenceObjectSafe(client))\n            client = NULL;\n    }\n\n    PhReleaseQueuedLockShared(&PhSvcClientListLock);\n\n    return client;\n}\n\nPPHSVC_CLIENT PhSvcGetCurrentClient(\n    VOID\n    )\n{\n    return PhSvcGetCurrentThreadContext()->CurrentClient;\n}\n\nBOOLEAN PhSvcAttachClient(\n    _In_ PPHSVC_CLIENT Client\n    )\n{\n    PPHSVC_THREAD_CONTEXT threadContext = PhSvcGetCurrentThreadContext();\n\n    if (threadContext->OldClient)\n        return FALSE;\n\n    PhReferenceObject(Client);\n    threadContext->OldClient = threadContext->CurrentClient;\n    threadContext->CurrentClient = Client;\n\n    return TRUE;\n}\n\nVOID PhSvcDetachClient(\n    _In_ PPHSVC_CLIENT Client\n    )\n{\n    PPHSVC_THREAD_CONTEXT threadContext = PhSvcGetCurrentThreadContext();\n\n    PhDereferenceObject(threadContext->CurrentClient);\n    threadContext->CurrentClient = threadContext->OldClient;\n    threadContext->OldClient = NULL;\n}\n"
  },
  {
    "path": "SystemInformer/phsvc/svcmain.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011\n *     dmex    2018\n *\n */\n\n#include <phapp.h>\n#include <phsvc.h>\n\nHANDLE PhSvcTimeoutStandbyEventHandle = NULL;\nHANDLE PhSvcTimeoutCancelEventHandle = NULL;\n\nNTSTATUS PhSvcMain(\n    _In_opt_ PPH_STRING PortName,\n    _Inout_opt_ PPHSVC_STOP Stop\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING portName;\n    LARGE_INTEGER timeout;\n\n    if (PortName)\n    {\n        PhStringRefToUnicodeString(&PortName->sr, &portName);\n    }\n    else\n    {\n        if (PhIsExecutingInWow64())\n            RtlInitUnicodeString(&portName, PHSVC_WOW64_PORT_NAME);\n        else\n            RtlInitUnicodeString(&portName, PHSVC_PORT_NAME);\n    }\n\n    if (!NT_SUCCESS(status = PhSvcApiPortInitialization(&portName)))\n        return status;\n\n    if (!NT_SUCCESS(status = PhCreateEvent(&PhSvcTimeoutStandbyEventHandle, EVENT_ALL_ACCESS, SynchronizationEvent, TRUE)))\n        return status;\n\n    if (!NT_SUCCESS(status = PhCreateEvent(&PhSvcTimeoutCancelEventHandle, EVENT_ALL_ACCESS, SynchronizationEvent, FALSE)))\n    {\n        NtClose(PhSvcTimeoutStandbyEventHandle);\n        return status;\n    }\n\n    if (Stop)\n    {\n        Stop->Event1 = PhSvcTimeoutStandbyEventHandle;\n        Stop->Event2 = PhSvcTimeoutCancelEventHandle;\n        MemoryBarrier();\n\n        if (Stop->Stop)\n            return STATUS_SUCCESS;\n    }\n\n    while (TRUE)\n    {\n        NtWaitForSingleObject(PhSvcTimeoutStandbyEventHandle, FALSE, NULL);\n\n        if (Stop && Stop->Stop)\n            break;\n\n        status = NtWaitForSingleObject(PhSvcTimeoutCancelEventHandle, FALSE, PhTimeoutFromMilliseconds(&timeout, 10 * 1000));\n\n        if (Stop && Stop->Stop)\n            break;\n        if (status == STATUS_TIMEOUT)\n            break;\n\n        // A client connected, so we wait on the standby event again.\n    }\n\n    return status;\n}\n\nVOID PhSvcStop(\n    _Inout_ PPHSVC_STOP Stop\n    )\n{\n    Stop->Stop = TRUE;\n\n    if (Stop->Event1)\n        NtSetEvent(Stop->Event1, NULL);\n    if (Stop->Event2)\n        NtSetEvent(Stop->Event2, NULL);\n}\n"
  },
  {
    "path": "SystemInformer/plugin.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2024\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <colmgr.h>\n#include <emenu.h>\n#include <extmgri.h>\n#include <phsvccl.h>\n#include <procprv.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <mapldr.h>\n\n#include <trace.h>\n\ntypedef struct _PHP_PLUGIN_LOAD_ERROR\n{\n    PPH_STRING FileName;\n    PPH_STRING ErrorMessage;\n} PHP_PLUGIN_LOAD_ERROR, *PPHP_PLUGIN_LOAD_ERROR;\n\ntypedef struct _PHP_PLUGIN_MENU_HOOK\n{\n    PPH_PLUGIN Plugin;\n    PVOID Context;\n} PHP_PLUGIN_MENU_HOOK, *PPHP_PLUGIN_MENU_HOOK;\n\ntypedef struct _PH_LOADPLUGIN_CONTEXT\n{\n    BOOLEAN LoadNative;\n    BOOLEAN LoadDefault;\n\n    PPH_STRING PluginsDirectory;\n    PPH_LIST LoadErrors;\n} PH_LOADPLUGIN_CONTEXT, *PPH_LOADPLUGIN_CONTEXT;\n\nLONG NTAPI PhpPluginsCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    );\n\nNTSTATUS PhLoadPlugin(\n    _In_ PCPH_STRINGREF FileName\n    );\n\nVOID PhLoadPluginErrorMessage(\n    _In_ PPH_LOADPLUGIN_CONTEXT Context,\n    _In_ PPH_STRING FileName,\n    _In_ NTSTATUS Status\n    );\n\nVOID PhInvokeCallbackForAllPlugins(\n    _In_ PH_PLUGIN_CALLBACK Callback,\n    _In_opt_ PVOID Parameters\n    );\n\nVOID PhpExecuteCallbackForAllPlugins(\n    _In_ PH_PLUGIN_CALLBACK Callback,\n    _In_ BOOLEAN StartupParameters\n    );\n\nPH_AVL_TREE PhPluginsByName = PH_AVL_TREE_INIT(PhpPluginsCompareFunction);\nstatic PH_CALLBACK GeneralCallbacks[GeneralCallbackMaximum];\nstatic ULONG NextPluginId = IDPLUGINS + 1;\nstatic CONST PH_STRINGREF DefaultPluginName[] =\n{\n    PH_STRINGREF_INIT(L\"DotNetTools.dll\"),\n    PH_STRINGREF_INIT(L\"ExtendedNotifications.dll\"),\n    PH_STRINGREF_INIT(L\"ExtendedServices.dll\"),\n    PH_STRINGREF_INIT(L\"ExtendedTools.dll\"),\n    PH_STRINGREF_INIT(L\"HardwareDevices.dll\"),\n    PH_STRINGREF_INIT(L\"NetworkTools.dll\"),\n    PH_STRINGREF_INIT(L\"OnlineChecks.dll\"),\n    PH_STRINGREF_INIT(L\"ToolStatus.dll\"),\n    PH_STRINGREF_INIT(L\"Updater.dll\"),\n    PH_STRINGREF_INIT(L\"UserNotes.dll\"),\n    PH_STRINGREF_INIT(L\"WindowExplorer.dll\"),\n};\n\nLONG NTAPI PhpPluginsCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    )\n{\n    PPH_PLUGIN plugin1 = CONTAINING_RECORD(Links1, PH_PLUGIN, Links);\n    PPH_PLUGIN plugin2 = CONTAINING_RECORD(Links2, PH_PLUGIN, Links);\n\n    return PhCompareStringRef(&plugin1->Name, &plugin2->Name, FALSE);\n}\n\n_Success_(return)\nBOOLEAN PhpLocateDisabledPlugin(\n    _In_ PPH_STRING List,\n    _In_ PCPH_STRINGREF BaseName,\n    _Out_opt_ PULONG_PTR FoundIndex\n    )\n{\n    PH_STRINGREF namePart;\n    PH_STRINGREF remainingPart;\n\n    remainingPart = PhGetStringRef(List);\n\n    while (remainingPart.Length != 0)\n    {\n        PhSplitStringRefAtChar(&remainingPart, L'|', &namePart, &remainingPart);\n\n        if (PhEqualStringRef(&namePart, BaseName, TRUE))\n        {\n            if (FoundIndex)\n                *FoundIndex = (ULONG_PTR)(namePart.Buffer - List->Buffer);\n\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhIsPluginDisabled(\n    _In_ PCPH_STRINGREF BaseName\n    )\n{\n    BOOLEAN found;\n    PPH_STRING disabled;\n\n    disabled = PhGetStringSetting(SETTING_DISABLED_PLUGINS);\n    found = PhpLocateDisabledPlugin(disabled, BaseName, NULL);\n    PhDereferenceObject(disabled);\n\n    return found;\n}\n\nVOID PhSetPluginDisabled(\n    _In_ PCPH_STRINGREF BaseName,\n    _In_ BOOLEAN Disable\n    )\n{\n    BOOLEAN found;\n    PPH_STRING disabled;\n    ULONG_PTR foundIndex;\n    PPH_STRING newDisabled;\n\n    disabled = PhGetStringSetting(SETTING_DISABLED_PLUGINS);\n    found = PhpLocateDisabledPlugin(disabled, BaseName, &foundIndex);\n\n    if (Disable && !found)\n    {\n        // We need to add the plugin to the disabled list.\n\n        if (disabled->Length != 0)\n        {\n            // We have other disabled plugins. Append a pipe character followed by the plugin name.\n            newDisabled = PhCreateStringEx(NULL, disabled->Length + sizeof(WCHAR) + BaseName->Length);\n            memcpy(newDisabled->Buffer, disabled->Buffer, disabled->Length);\n            newDisabled->Buffer[disabled->Length / sizeof(WCHAR)] = L'|';\n            memcpy(&newDisabled->Buffer[disabled->Length / sizeof(WCHAR) + 1], BaseName->Buffer, BaseName->Length);\n            PhSetStringSetting2(SETTING_DISABLED_PLUGINS, &newDisabled->sr);\n            PhDereferenceObject(newDisabled);\n        }\n        else\n        {\n            // This is the first disabled plugin.\n            PhSetStringSetting2(SETTING_DISABLED_PLUGINS, BaseName);\n        }\n    }\n    else if (!Disable && found)\n    {\n        SIZE_T removeCount;\n\n        // We need to remove the plugin from the disabled list.\n\n        removeCount = BaseName->Length / sizeof(WCHAR);\n\n        if (foundIndex + BaseName->Length / sizeof(WCHAR) < disabled->Length / sizeof(WCHAR))\n        {\n            // Remove the following pipe character as well.\n            removeCount++;\n        }\n        else if (foundIndex != 0)\n        {\n            // Remove the preceding pipe character as well.\n            foundIndex--;\n            removeCount++;\n        }\n\n        newDisabled = PhCreateStringEx(NULL, disabled->Length - removeCount * sizeof(WCHAR));\n        memmove(newDisabled->Buffer, disabled->Buffer, foundIndex * sizeof(WCHAR));\n        memmove(&newDisabled->Buffer[foundIndex], &disabled->Buffer[foundIndex + removeCount],\n            disabled->Length - removeCount * sizeof(WCHAR) - foundIndex * sizeof(WCHAR));\n        PhSetStringSetting2(SETTING_DISABLED_PLUGINS, &newDisabled->sr);\n        PhDereferenceObject(newDisabled);\n    }\n\n    PhDereferenceObject(disabled);\n}\n\n//PPH_STRING PhGetPluginDirectoryPath(\n//    _In_ BOOLEAN NativeFileName\n//    )\n//{\n//    static CONST PH_STRINGREF pluginsDirectory = PH_STRINGREF_INIT(L\"plugins\\\\\");\n//\n//    return PhGetApplicationDirectoryFileName(&pluginsDirectory, NativeFileName);\n//}\n//\n//PPH_STRING PhpGetPluginDirectoryPath(\n//    VOID\n//    )\n//{\n//    static PPH_STRING cachedPluginDirectory = NULL;\n//    PPH_STRING pluginsDirectory;\n//    SIZE_T returnLength;\n//    WCHAR pluginsDirectoryName[MAX_PATH];\n//    PH_FORMAT format[3];\n//\n//    if (pluginsDirectory = InterlockedCompareExchangePointer(\n//        &cachedPluginDirectory,\n//        NULL,\n//        NULL\n//        ))\n//    {\n//        return PhReferenceObject(pluginsDirectory);\n//    }\n//\n//    pluginsDirectory = PhGetStringSetting(L\"PluginsDirectory\");\n//\n//    if (RtlDetermineDosPathNameType_U(pluginsDirectory->Buffer) == RtlPathTypeRelative)\n//    {\n//        PPH_STRING applicationDirectory;\n//\n//        if (applicationDirectory = PhGetApplicationDirectoryWin32())\n//        {\n//            PH_STRINGREF pluginsDirectoryNameSr;\n//\n//            // Not absolute. Make sure it is.\n//            PhInitFormatSR(&format[0], applicationDirectory->sr);\n//            PhInitFormatSR(&format[1], pluginsDirectory->sr);\n//            PhInitFormatC(&format[2], OBJ_NAME_PATH_SEPARATOR);\n//\n//            if (PhFormatToBuffer(\n//                format,\n//                RTL_NUMBER_OF(format),\n//                pluginsDirectoryName,\n//                sizeof(pluginsDirectoryName),\n//                &returnLength\n//                ))\n//            {\n//                pluginsDirectoryNameSr.Buffer = pluginsDirectoryName;\n//                pluginsDirectoryNameSr.Length = returnLength - sizeof(UNICODE_NULL);\n//\n//                PhMoveReference(&pluginsDirectory, PhCreateString2(&pluginsDirectoryNameSr));\n//            }\n//\n//            PhDereferenceObject(applicationDirectory);\n//        }\n//    }\n//\n//    if (!InterlockedCompareExchangePointer(\n//        &cachedPluginDirectory,\n//        pluginsDirectory,\n//        NULL\n//        ))\n//    {\n//        PhReferenceObject(pluginsDirectory);\n//    }\n//\n//    return pluginsDirectory;\n//}\n\n_Function_class_(PH_ENUM_DIRECTORY_FILE)\nstatic BOOLEAN EnumPluginsDirectoryCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PVOID Information,\n    _In_opt_ PVOID Context\n    )\n{\n    PFILE_NAMES_INFORMATION fileNamesInfo = (PFILE_NAMES_INFORMATION)Information;\n    PPH_LOADPLUGIN_CONTEXT context = (PPH_LOADPLUGIN_CONTEXT)Context;\n    NTSTATUS status;\n    PPH_STRING fileName;\n    PH_STRINGREF baseName;\n\n    baseName.Buffer = fileNamesInfo->FileName;\n    baseName.Length = fileNamesInfo->FileNameLength;\n\n    if (!PhIsPluginDisabled(&baseName))\n    {\n        if (context->LoadNative)\n        {\n            status = PhLoadPluginImage(&baseName, RootDirectory, NULL);\n        }\n        else\n        {\n            if (fileName = PhConcatStringRef2(&context->PluginsDirectory->sr, &baseName))\n            {\n                status = PhLoadPlugin(&fileName->sr);\n\n                PhDereferenceObject(fileName);\n            }\n            else\n            {\n                status = STATUS_NO_MEMORY;\n            }\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            fileName = PhCreateString2(&baseName);\n            PhLoadPluginErrorMessage(context, fileName, status);\n            PhDereferenceObject(fileName);\n        }\n    }\n\n    return TRUE;\n}\n\nVOID PhpShowPluginErrorMessage(\n    _Inout_ PPH_LIST PluginLoadErrors\n    )\n{\n    TASKDIALOGCONFIG config;\n    PH_STRING_BUILDER stringBuilder;\n    PPHP_PLUGIN_LOAD_ERROR loadError;\n    PPH_STRING baseName;\n    INT result;\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n\n    for (ULONG i = 0; i < PluginLoadErrors->Count; i++)\n    {\n        loadError = PluginLoadErrors->Items[i];\n        baseName = PhGetBaseName(loadError->FileName);\n\n        PhAppendFormatStringBuilder(\n            &stringBuilder,\n            L\"%s: %s\\n\",\n            baseName->Buffer,\n            PhGetStringOrDefault(loadError->ErrorMessage, L\"An unknown error occurred.\")\n            );\n\n        PhDereferenceObject(baseName);\n    }\n\n    if (PhEndsWithStringRef2(&stringBuilder.String->sr, L\"\\n\", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION;\n    config.dwCommonButtons = TDCBF_OK_BUTTON;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainIcon = TD_INFORMATION_ICON;\n    config.pszMainInstruction = L\"Unable to load the following plugin(s)\";\n    config.pszContent = PhGetString(PhFinalStringBuilderString(&stringBuilder));\n    config.nDefaultButton = IDOK;\n\n    if (PhShowTaskDialog(\n        &config,\n        &result,\n        NULL,\n        NULL\n        ))\n    {\n        //switch (result)\n        //{\n        //case IDNO:\n        //    for (i = 0; i < pluginLoadErrors->Count; i++)\n        //    {\n        //        loadError = pluginLoadErrors->Items[i];\n        //        baseName = PhGetBaseName(loadError->FileName);\n        //        PhSetPluginDisabled(&baseName->sr, TRUE);\n        //        PhDereferenceObject(baseName);\n        //    }\n        //    break;\n        //case IDYES:\n        //    for (i = 0; i < pluginLoadErrors->Count; i++)\n        //    {\n        //        loadError = pluginLoadErrors->Items[i];\n        //        PhDeleteFileWin32(loadError->FileName->Buffer);\n        //    }\n        //    break;\n        //}\n    }\n\n    PhDeleteStringBuilder(&stringBuilder);\n}\n\nNTSTATUS PhLoadPluginsEnumDirectory(\n    _In_ PPH_STRINGREF PluginsDirectory,\n    _In_ PPH_LOADPLUGIN_CONTEXT Context\n    )\n{\n    static CONST PH_STRINGREF pluginsSearchPattern = PH_STRINGREF_INIT(L\"*.dll\");\n    NTSTATUS status;\n    HANDLE directoryHandle;\n\n    if (Context->LoadNative)\n    {\n        status = PhCreateFile(\n            &directoryHandle,\n            PluginsDirectory,\n            FILE_LIST_DIRECTORY | SYNCHRONIZE,\n            FILE_ATTRIBUTE_DIRECTORY,\n            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n    }\n    else\n    {\n        status = PhCreateFileWin32(\n            &directoryHandle,\n            PhGetStringRefZ(PluginsDirectory),\n            FILE_LIST_DIRECTORY | SYNCHRONIZE,\n            FILE_ATTRIBUTE_DIRECTORY,\n            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhEnumDirectoryFileEx(\n        directoryHandle,\n        FileNamesInformation,\n        FALSE,\n        &pluginsSearchPattern,\n        EnumPluginsDirectoryCallback,\n        Context\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        status = PhEnumDirectoryFileEx(\n            directoryHandle,\n            FileNamesInformation,\n            TRUE,\n            &pluginsSearchPattern,\n            EnumPluginsDirectoryCallback,\n            Context\n            );\n    }\n\n    NtClose(directoryHandle);\n\n    return status;\n}\n\n/**\n * Loads plugins from the default plugins directory.\n */\nVOID PhLoadPlugins(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF pluginsDirectory = PH_STRINGREF_INIT(L\"plugins\\\\\");\n    NTSTATUS status;\n    BOOLEAN pluginLoadNative;\n    BOOLEAN pluginLoadDefault;\n    PPH_STRING pluginFileName;\n    PPH_STRING pluginDirectoryPath;\n    PH_LOADPLUGIN_CONTEXT pluginLoadContext;\n\n    pluginLoadNative = !!PhGetIntegerSetting(SETTING_ENABLE_PLUGINS_NATIVE);\n    pluginLoadDefault = !!PhGetIntegerSetting(SETTING_ENABLE_DEFAULT_SAFE_PLUGINS);\n    pluginDirectoryPath = PhGetApplicationDirectoryFileName(&pluginsDirectory, pluginLoadNative);\n\n    if (PhIsNullOrEmptyString(pluginDirectoryPath))\n        return;\n\n    memset(&pluginLoadContext, 0, sizeof(PH_LOADPLUGIN_CONTEXT));\n    pluginLoadContext.LoadNative = pluginLoadNative;\n    pluginLoadContext.LoadDefault = pluginLoadDefault;\n    pluginLoadContext.PluginsDirectory = pluginDirectoryPath;\n\n    if (pluginLoadDefault)\n    {\n        if (pluginLoadNative)\n        {\n            HANDLE directoryHandle;\n\n            status = PhCreateFile(\n                &directoryHandle,\n                &pluginDirectoryPath->sr,\n                FILE_LIST_DIRECTORY | SYNCHRONIZE,\n                FILE_ATTRIBUTE_DIRECTORY,\n                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n                FILE_OPEN,\n                FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                for (ULONG i = 0; i < RTL_NUMBER_OF(DefaultPluginName); i++)\n                {\n                    if (PhIsPluginDisabled(&DefaultPluginName[i]))\n                        continue;\n\n                    status = PhLoadPluginImage(&DefaultPluginName[i], directoryHandle, NULL);\n\n                    if (!NT_SUCCESS(status))\n                    {\n                        pluginFileName = PhCreateString2(&DefaultPluginName[i]);\n                        PhLoadPluginErrorMessage(&pluginLoadContext, pluginFileName, status);\n                        PhDereferenceObject(pluginFileName);\n                    }\n                }\n\n                NtClose(directoryHandle);\n            }\n        }\n        else\n        {\n            for (ULONG i = 0; i < RTL_NUMBER_OF(DefaultPluginName); i++)\n            {\n                if (PhIsPluginDisabled(&DefaultPluginName[i]))\n                    continue;\n\n                if (pluginFileName = PhConcatStringRef2(&pluginDirectoryPath->sr, &DefaultPluginName[i]))\n                {\n                    status = PhLoadPlugin(&pluginFileName->sr);\n\n                    if (!NT_SUCCESS(status))\n                    {\n                        PhLoadPluginErrorMessage(&pluginLoadContext, pluginFileName, status);\n                    }\n\n                    PhDereferenceObject(pluginFileName);\n                }\n            }\n        }\n    }\n    else\n    {\n        // Load non-default plugins\n\n        PhLoadPluginsEnumDirectory(&pluginDirectoryPath->sr, &pluginLoadContext);\n    }\n\n    // Handle load errors.\n    // In certain startup modes we want to ignore all plugin load errors.\n    if (\n        pluginLoadContext.LoadErrors &&\n        pluginLoadContext.LoadErrors->Count != 0 &&\n        PhGetIntegerSetting(SETTING_SHOW_PLUGIN_LOAD_ERRORS) &&\n        !PhStartupParameters.PhSvc\n        )\n    {\n        PhpShowPluginErrorMessage(pluginLoadContext.LoadErrors);\n    }\n\n    // When we loaded settings before, we didn't know about plugin settings, so they\n    // went into the ignored settings list. Now that they've had a chance to add\n    // settings, we should scan the ignored settings list and move the settings to\n    // the right places.\n    PhConvertIgnoredSettings();\n\n    PhpExecuteCallbackForAllPlugins(PluginCallbackLoad, TRUE);\n\n    if (pluginLoadContext.LoadErrors)\n    {\n        for (ULONG i = 0; i < pluginLoadContext.LoadErrors->Count; i++)\n        {\n            PPHP_PLUGIN_LOAD_ERROR loadError;\n\n            loadError = pluginLoadContext.LoadErrors->Items[i];\n\n            if (loadError->FileName)\n                PhDereferenceObject(loadError->FileName);\n            if (loadError->ErrorMessage)\n                PhDereferenceObject(loadError->ErrorMessage);\n\n            PhFree(loadError);\n        }\n\n        PhDereferenceObject(pluginLoadContext.LoadErrors);\n    }\n\n    PhDereferenceObject(pluginDirectoryPath);\n}\n\n/**\n * Notifies all plugins that the program is shutting down.\n * \n * \\param SessionEnding TRUE if the user ends the Windows session by logging off\n * or shutting down the operating system. otherwise, FALSE.\n */\nVOID PhUnloadPlugins(\n    _In_ BOOLEAN SessionEnding\n    )\n{\n    PhInvokeCallbackForAllPlugins(PluginCallbackUnload, UlongToPtr(SessionEnding));\n}\n\n/**\n * Loads a plugin.\n *\n * \\param FileName The file name of the plugin.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhLoadPlugin(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n\n    if (LoadLibraryEx(PhGetStringRefZ(FileName), NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    return status;\n}\n\nVOID PhLoadPluginErrorMessage(\n    _In_ PPH_LOADPLUGIN_CONTEXT Context,\n    _In_ PPH_STRING FileName,\n    _In_ NTSTATUS Status\n    )\n{\n    PPHP_PLUGIN_LOAD_ERROR loadError;\n    PPH_STRING errorMessage;\n\n    loadError = PhAllocateZero(sizeof(PHP_PLUGIN_LOAD_ERROR));\n    PhSetReference(&loadError->FileName, FileName);\n\n    if (errorMessage = PhGetNtMessage(Status))\n    {\n        PhSetReference(&loadError->ErrorMessage, errorMessage);\n        PhDereferenceObject(errorMessage);\n    }\n\n    if (!Context->LoadErrors)\n    {\n        Context->LoadErrors = PhCreateList(1);\n    }\n\n    if (Context->LoadErrors)\n    {\n        PhAddItemList(Context->LoadErrors, loadError);\n    }\n}\n\nVOID PhInvokeCallbackForAllPlugins(\n    _In_ PH_PLUGIN_CALLBACK Callback,\n    _In_opt_ PVOID Parameters\n    )\n{\n    PPH_AVL_LINKS links;\n\n    for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links))\n    {\n        PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links);\n\n        PhInvokeCallback(PhGetPluginCallback(plugin, Callback), Parameters);\n    }\n}\n\nVOID PhpExecuteCallbackForAllPlugins(\n    _In_ PH_PLUGIN_CALLBACK Callback,\n    _In_ BOOLEAN StartupParameters\n    )\n{\n    PPH_AVL_LINKS links;\n\n    for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links))\n    {\n        PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links);\n        PPH_LIST parameters = NULL;\n\n        // Find relevant startup parameters for this plugin.\n        if (StartupParameters && PhStartupParameters.PluginParameters)\n        {\n            ULONG i;\n\n            for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++)\n            {\n                PPH_STRING string = PhStartupParameters.PluginParameters->Items[i];\n                PH_STRINGREF pluginName;\n                PH_STRINGREF parameter;\n\n                if (PhSplitStringRefAtChar(&string->sr, L':', &pluginName, &parameter) &&\n                    PhEqualStringRef(&pluginName, &plugin->Name, FALSE) &&\n                    parameter.Length != 0)\n                {\n                    if (!parameters)\n                        parameters = PhCreateList(3);\n\n                    if (parameters)\n                        PhAddItemList(parameters, PhCreateString2(&parameter));\n                }\n            }\n        }\n\n        PhInvokeCallback(PhGetPluginCallback(plugin, Callback), parameters);\n\n        if (parameters)\n        {\n            PhDereferenceObjects(parameters->Items, parameters->Count);\n            PhDereferenceObject(parameters);\n        }\n    }\n}\n\n/**\n * Validate the plugin name contains only valid characters.\n * Valid characters are alphanumeric characters, spaces, dots, and underscores.\n *\n * \\param Name A pointer to a PH_STRINGREF structure that contains the plugin name to validate.\n * \\return TRUE if the name is valid; otherwise, FALSE.\n */\nBOOLEAN PhpValidatePluginName(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    SIZE_T i;\n    PWSTR buffer;\n    SIZE_T count;\n\n    buffer = Name->Buffer;\n    count = Name->Length / sizeof(WCHAR);\n\n    for (i = 0; i < count; i++)\n    {\n        if (!iswalnum(buffer[i]) && buffer[i] != L' ' && buffer[i] != L'.' && buffer[i] != L'_')\n        {\n            return FALSE;\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Registers a plugin with the host.\n *\n * \\param Name A unique identifier for the plugin. The function fails\n * if another plugin has already been registered with the same name. The\n * name must only contain alphanumeric characters, spaces, dots and\n * underscores.\n * \\param DllBase The base address of the plugin DLL. This is passed\n * to the DllMain function.\n * \\param Information A variable which receives a pointer to the\n * plugin's additional information block. This should be filled in after\n * the function returns.\n * \\return A pointer to the plugin instance structure, or NULL if the\n * function failed.\n */\nPPH_PLUGIN PhRegisterPluginByName(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PVOID DllBase,\n    _Out_opt_ PPH_PLUGIN_INFORMATION *Information\n    )\n{\n    PPH_PLUGIN plugin;\n    PPH_AVL_LINKS existingLinks;\n    ULONG i;\n\n    PhTraceInfo(\"%ls plugin registering\", PhGetStringRefZ(Name));\n\n    if (!PhpValidatePluginName(Name))\n        return NULL;\n\n    plugin = PhAllocateZero(sizeof(PH_PLUGIN));\n    plugin->Name = *Name;\n    plugin->DllBase = DllBase;\n\n    existingLinks = PhAddElementAvlTree(&PhPluginsByName, &plugin->Links);\n\n    if (existingLinks)\n    {\n        // Another plugin has already been registered with the same name.\n        PhFree(plugin);\n        return NULL;\n    }\n\n    for (i = 0; i < PluginCallbackMaximum; i++)\n        PhInitializeCallback(&plugin->Callbacks[i]);\n\n    PhEmInitializeAppContext(&plugin->AppContext, Name);\n\n    if (Information)\n        *Information = &plugin->Information;\n\n    return plugin;\n}\n\n/**\n * Locates a plugin instance structure.\n *\n * \\param Name The name of the plugin.\n * \\return A plugin instance structure, or NULL if the plugin was not found.\n */\nPPH_PLUGIN PhFindPlugin2(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    PPH_AVL_LINKS links;\n    PH_PLUGIN lookupPlugin;\n\n    lookupPlugin.Name = *Name;\n    links = PhFindElementAvlTree(&PhPluginsByName, &lookupPlugin.Links);\n\n    if (links)\n        return CONTAINING_RECORD(links, PH_PLUGIN, Links);\n    else\n        return NULL;\n}\n\n/**\n * Gets a pointer to a plugin's additional information block.\n *\n * \\param Name The name of the plugin.\n * \\param Version The version of the interface.\n * \\return The plugin's internal interface.\n */\nPVOID PhGetPluginInterface(\n    _In_ PCPH_STRINGREF Name,\n    _In_opt_ ULONG Version\n    )\n{\n    PPH_PLUGIN plugin;\n    PVOID iface;\n\n    if (plugin = PhFindPlugin2(Name))\n    {\n        if (!(iface = PhGetPluginInformation(plugin)->Interface))\n            return NULL;\n\n        if (Version == 0)\n        {\n            return iface;\n        }\n\n        struct\n        {\n            ULONG Version;\n        } *Interface = iface;\n\n        if (Interface->Version >= Version)\n        {\n            return iface;\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Gets a pointer to a plugin's additional information block.\n *\n * \\param Plugin The plugin instance structure.\n * \\return The plugin's additional information block.\n */\nPPH_PLUGIN_INFORMATION PhGetPluginInformation(\n    _In_ PPH_PLUGIN Plugin\n    )\n{\n    return &Plugin->Information;\n}\n\n/**\n * Retrieves a pointer to a plugin callback.\n *\n * \\param Plugin A plugin instance structure.\n * \\param Callback The type of callback.\n * \\remarks The program invokes plugin callbacks for notifications\n * specific to a plugin.\n */\nPPH_CALLBACK PhGetPluginCallback(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PH_PLUGIN_CALLBACK Callback\n    )\n{\n    if (Callback >= PluginCallbackMaximum)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    return &Plugin->Callbacks[Callback];\n}\n\nVOID PhInitializeCallbacks(\n    VOID\n    )\n{\n    for (ULONG i = 0; i < GeneralCallbackMaximum; i++)\n        PhInitializeCallback(&GeneralCallbacks[i]);\n}\n\n/**\n * Retrieves a pointer to a general callback.\n *\n * \\param Callback The type of callback.\n * \\remarks The program invokes general callbacks for system-wide\n * notifications.\n */\nPPH_CALLBACK PhGetGeneralCallback(\n    _In_ PH_GENERAL_CALLBACK Callback\n    )\n{\n    if (Callback >= GeneralCallbackMaximum)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    return &GeneralCallbacks[Callback];\n}\n\n/**\n * Reserves unique GUI identifiers.\n *\n * \\param Count The number of identifiers to reserve.\n *\n * \\return The start of the reserved range.\n *\n * \\remarks The identifiers reserved by this function are\n * guaranteed to be unique throughout the program.\n */\nULONG PhPluginReserveIds(\n    _In_ ULONG Count\n    )\n{\n    ULONG nextPluginId;\n\n    nextPluginId = NextPluginId;\n    NextPluginId += Count;\n\n    return nextPluginId;\n}\n\n/**\n * Retrieves current system statistics.\n */\nVOID PhPluginGetSystemStatistics(\n    _Out_ PPH_PLUGIN_SYSTEM_STATISTICS Statistics\n    )\n{\n    if (!PhProcessStatisticsInitialized)\n    {\n        memset(Statistics, 0, sizeof(PH_PLUGIN_SYSTEM_STATISTICS));\n        return;\n    }\n\n    Statistics->Performance = &PhPerfInformation;\n\n    Statistics->NumberOfProcesses = PhTotalProcesses;\n    Statistics->NumberOfThreads = PhTotalThreads;\n    Statistics->NumberOfHandles = PhTotalHandles;\n\n    Statistics->CpuKernelUsage = PhCpuKernelUsage;\n    Statistics->CpuUserUsage = PhCpuUserUsage;\n\n    Statistics->IoReadDelta = PhIoReadDelta;\n    Statistics->IoWriteDelta = PhIoWriteDelta;\n    Statistics->IoOtherDelta = PhIoOtherDelta;\n\n    Statistics->CommitPages = PhGetItemCircularBuffer_ULONG(&PhCommitHistory, 0);\n    Statistics->PhysicalPages = PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, 0);\n\n    Statistics->MaxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0));\n    Statistics->MaxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0));\n\n    Statistics->CpuKernelHistory = &PhCpuKernelHistory;\n    Statistics->CpuUserHistory = &PhCpuUserHistory;\n    Statistics->CpusKernelHistory = &PhCpusKernelHistory;\n    Statistics->CpusUserHistory = &PhCpusUserHistory;\n    Statistics->IoReadHistory = &PhIoReadHistory;\n    Statistics->IoWriteHistory = &PhIoWriteHistory;\n    Statistics->IoOtherHistory = &PhIoOtherHistory;\n    Statistics->CommitHistory = &PhCommitHistory;\n    Statistics->PhysicalHistory = &PhPhysicalHistory;\n    Statistics->MaxCpuHistory = &PhMaxCpuHistory;\n    Statistics->MaxIoHistory = &PhMaxIoHistory;\n#ifdef PH_RECORD_MAX_USAGE\n    Statistics->MaxCpuUsageHistory = &PhMaxCpuUsageHistory;\n    Statistics->MaxIoReadOtherHistory = &PhMaxIoReadOtherHistory;\n    Statistics->MaxIoWriteHistory = &PhMaxIoWriteHistory;\n#else\n    Statistics->MaxCpuUsageHistory = NULL;\n    Statistics->MaxIoReadOtherHistory = NULL;\n    Statistics->MaxIoWriteHistory = NULL;\n#endif\n}\n\n_Function_class_(PH_EMENU_ITEM_DELETE_FUNCTION)\nstatic VOID NTAPI PhpPluginEMenuItemDeleteFunction(\n    _In_ PPH_EMENU_ITEM Item\n    )\n{\n    PPH_PLUGIN_MENU_ITEM pluginMenuItem;\n\n    pluginMenuItem = Item->Context;\n\n    if (pluginMenuItem->DeleteFunction)\n        pluginMenuItem->DeleteFunction(pluginMenuItem);\n\n    PhFree(pluginMenuItem);\n}\n\n/**\n * Creates a menu item.\n *\n * \\param Plugin A plugin instance structure.\n * \\param Flags A combination of flags.\n * \\param Id An identifier for the menu item. This should be unique\n * within the plugin.\n * \\param Text The text of the menu item.\n * \\param Context A user-defined value for the menu item.\n *\n * \\return A menu item object. This can then be inserted into another\n * menu using PhInsertEMenuItem().\n *\n * \\remarks The \\ref PluginCallbackMenuItem callback is invoked when\n * the menu item is chosen, and the \\ref PH_PLUGIN_MENU_ITEM structure\n * will contain the \\a Id and \\a Context values passed to this function.\n */\nPPH_EMENU_ITEM PhPluginCreateEMenuItem(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ ULONG Flags,\n    _In_ ULONG Id,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_PLUGIN_MENU_ITEM pluginMenuItem;\n    PPH_EMENU_ITEM item;\n\n    pluginMenuItem = PhAllocateZero(sizeof(PH_PLUGIN_MENU_ITEM));\n    pluginMenuItem->Plugin = Plugin;\n    pluginMenuItem->Id = Id;\n    pluginMenuItem->Context = Context;\n\n    item = PhCreateEMenuItem(Flags, ID_PLUGIN_MENU_ITEM, Text, NULL, pluginMenuItem);\n    item->DeleteFunction = PhpPluginEMenuItemDeleteFunction;\n\n    return item;\n}\n\n/**\n * Adds a menu hook.\n *\n * \\param MenuInfo The plugin menu information structure.\n * \\param Plugin A plugin instance structure.\n * \\param Context A user-defined value that is later accessible from the callback.\n *\n * \\remarks The \\ref PluginCallbackMenuHook callback is invoked when any menu item\n * from the menu is chosen.\n */\nBOOLEAN PhPluginAddMenuHook(\n    _Inout_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,\n    _In_ PPH_PLUGIN Plugin,\n    _In_opt_ PVOID Context\n    )\n{\n    PPHP_PLUGIN_MENU_HOOK hook;\n\n    if (MenuInfo->Flags & PH_PLUGIN_MENU_DISALLOW_HOOKS)\n        return FALSE;\n\n    if (!MenuInfo->PluginHookList)\n        MenuInfo->PluginHookList = PH_AUTO(PhCreateList(2));\n\n    hook = PH_AUTO(PhCreateAlloc(sizeof(PHP_PLUGIN_MENU_HOOK)));\n    hook->Plugin = Plugin;\n    hook->Context = Context;\n    PhAddItemList(MenuInfo->PluginHookList, hook);\n\n    return TRUE;\n}\n\n/**\n * Initializes a plugin menu information structure.\n *\n * \\param MenuInfo The structure to initialize.\n * \\param Menu The menu being shown.\n * \\param OwnerWindow The window that owns the menu.\n * \\param Flags Additional flags.\n *\n * \\remarks This function is reserved for internal use.\n */\nVOID PhPluginInitializeMenuInfo(\n    _Out_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,\n    _In_opt_ PPH_EMENU Menu,\n    _In_ HWND OwnerWindow,\n    _In_ ULONG Flags\n    )\n{\n    memset(MenuInfo, 0, sizeof(PH_PLUGIN_MENU_INFORMATION));\n    MenuInfo->Menu = Menu;\n    MenuInfo->OwnerWindow = OwnerWindow;\n    MenuInfo->Flags = Flags;\n}\n\n/**\n * Triggers a plugin menu item.\n *\n * \\param MenuInfo The plugin menu information structure.\n * \\param Item The menu item chosen by the user.\n *\n * \\remarks This function is reserved for internal use.\n */\nBOOLEAN PhPluginTriggerEMenuItem(\n    _In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,\n    _In_ PPH_EMENU_ITEM Item\n    )\n{\n    PPH_PLUGIN_MENU_ITEM pluginMenuItem;\n    ULONG i;\n    PPHP_PLUGIN_MENU_HOOK hook;\n    PH_PLUGIN_MENU_HOOK_INFORMATION menuHookInfo;\n\n    if (MenuInfo->PluginHookList)\n    {\n        for (i = 0; i < MenuInfo->PluginHookList->Count; i++)\n        {\n            hook = MenuInfo->PluginHookList->Items[i];\n            menuHookInfo.MenuInfo = MenuInfo;\n            menuHookInfo.SelectedItem = Item;\n            menuHookInfo.Context = hook->Context;\n            menuHookInfo.Handled = FALSE;\n            PhInvokeCallback(PhGetPluginCallback(hook->Plugin, PluginCallbackMenuHook), &menuHookInfo);\n\n            if (menuHookInfo.Handled)\n                return TRUE;\n        }\n    }\n\n    if (Item->Id != ID_PLUGIN_MENU_ITEM)\n        return FALSE;\n\n    pluginMenuItem = Item->Context;\n\n    pluginMenuItem->OwnerWindow = MenuInfo->OwnerWindow;\n\n    PhInvokeCallback(PhGetPluginCallback(pluginMenuItem->Plugin, PluginCallbackMenuItem), pluginMenuItem);\n\n    return TRUE;\n}\n\n/**\n * Adds a column to a tree new control.\n *\n * \\param Plugin A plugin instance structure.\n * \\param CmData The CmData value from the \\ref PH_PLUGIN_TREENEW_INFORMATION\n * structure.\n * \\param Column The column properties.\n * \\param SubId An identifier for the column. This should be unique within the\n * plugin.\n * \\param Context A user-defined value.\n * \\param SortFunction The sort function for the column.\n */\nBOOLEAN PhPluginAddTreeNewColumn(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PVOID CmData,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG SubId,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction\n    )\n{\n    return !!PhCmCreateColumn(\n        CmData,\n        Column,\n        Plugin,\n        SubId,\n        Context,\n        SortFunction\n        );\n}\n\n/**\n * Sets the object extension size and callbacks for an object type.\n *\n * \\param Plugin A plugin instance structure.\n * \\param ObjectType The type of object for which the extension is being registered.\n * \\param ExtensionSize The size of the extension, in bytes.\n * \\param CreateCallback The object creation callback.\n * \\param DeleteCallback The object deletion callback.\n */\nVOID PhPluginSetObjectExtension(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PH_EM_OBJECT_TYPE ObjectType,\n    _In_ ULONG ExtensionSize,\n    _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback,\n    _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback\n    )\n{\n    PhEmSetObjectExtension(\n        &Plugin->AppContext,\n        ObjectType,\n        ExtensionSize,\n        CreateCallback,\n        DeleteCallback\n        );\n}\n\n/**\n * Gets the object extension for an object.\n *\n * \\param Plugin A plugin instance structure.\n * \\param Object The object.\n * \\param ObjectType The type of object for which an extension has been registered.\n */\nPVOID PhPluginGetObjectExtension(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PVOID Object,\n    _In_ PH_EM_OBJECT_TYPE ObjectType\n    )\n{\n    return PhEmGetObjectExtension(\n        &Plugin->AppContext,\n        ObjectType,\n        Object\n        );\n}\n\n/**\n * Allows a plugin to receive all treenew messages, not just column-related ones.\n *\n * \\param Plugin A plugin instance structure.\n * \\param CmData The CmData value from the \\ref PH_PLUGIN_TREENEW_INFORMATION\n * structure.\n */\nVOID PhPluginEnableTreeNewNotify(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ PVOID CmData\n    )\n{\n    PhCmSetNotifyPlugin(CmData, Plugin);\n}\n\nNTSTATUS PhPluginQueryPhSvc(\n    _Out_ PPH_PLUGIN_PHSVC_CLIENT Client\n    )\n{\n    if (!PhSvcClServerProcessId)\n        return STATUS_INVALID_CID;\n\n    Client->ServerProcessId = PhSvcClServerProcessId;\n    Client->FreeHeap = PhSvcpFreeHeap;\n    Client->CreateString = PhSvcpCreateString;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhPluginCallPhSvc(\n    _In_ PPH_PLUGIN Plugin,\n    _In_ ULONG SubId,\n    _In_reads_bytes_opt_(InLength) PVOID InBuffer,\n    _In_ ULONG InLength,\n    _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer,\n    _In_ ULONG OutLength\n    )\n{\n    NTSTATUS status;\n    PPH_STRING apiId;\n    PH_FORMAT format[4];\n\n    PhInitFormatC(&format[0], L'+');\n    PhInitFormatSR(&format[1], Plugin->Name);\n    PhInitFormatC(&format[2], L'+');\n    PhInitFormatU(&format[3], SubId);\n    apiId = PhFormat(format, 4, 50);\n\n    status = PhSvcCallPlugin(&apiId->sr, InBuffer, InLength, OutBuffer, OutLength);\n    PhDereferenceObject(apiId);\n\n    return status;\n}\n\nPPH_STRING PhGetPluginName(\n    _In_ PPH_PLUGIN Plugin\n    )\n{\n    return PhCreateString2(&Plugin->Name);\n}\n\nPPH_STRING PhGetPluginFileName(\n    _In_ PPH_PLUGIN Plugin\n    )\n{\n    PPH_STRING fileName = NULL;\n\n    if (!NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), Plugin->DllBase, &fileName)))\n        return NULL;\n\n    return fileName;\n}\n\nVOID PhEnumeratePlugins(\n    _In_ PPH_PLUGIN_ENUMERATE Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_AVL_LINKS links;\n\n    for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links))\n    {\n        PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links);\n\n        if (!NT_SUCCESS(Callback(plugin, Context)))\n            break;\n    }\n}\n"
  },
  {
    "path": "SystemInformer/plugman.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <emenu.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <colmgr.h>\n#include <phplug.h>\n\n#define WM_PH_PLUGINS_SHOWPROPERTIES (WM_APP + 401)\n\ntypedef struct _PH_PLUGMAN_CONTEXT\n{\n    HWND WindowHandle;\n    HWND TreeNewHandle;\n    HFONT NormalFontHandle;\n    HFONT TitleFontHandle;\n    ULONG TreeNewSortColumn;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PPH_HASHTABLE NodeHashtable;\n    PPH_LIST NodeList;\n    PH_LAYOUT_MANAGER LayoutManager;\n} PH_PLUGMAN_CONTEXT, *PPH_PLUGMAN_CONTEXT;\n\ntypedef enum _PH_PLUGIN_TREE_ITEM_MENU\n{\n    PH_PLUGIN_TREE_ITEM_MENU_UNINSTALL,\n    PH_PLUGIN_TREE_ITEM_MENU_DISABLE,\n    PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES\n} PH_PLUGIN_TREE_ITEM_MENU;\n\ntypedef enum _PH_PLUGIN_TREE_COLUMN_ITEM\n{\n    PH_PLUGIN_TREE_COLUMN_ITEM_NAME,\n    PH_PLUGIN_TREE_COLUMN_ITEM_VERSION,\n    PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM\n} PH_PLUGIN_TREE_COLUMN_ITEM;\n\ntypedef struct _PH_PLUGIN_TREE_ROOT_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    BOOLEAN PluginOptions;\n    PPH_PLUGIN PluginInstance;\n\n    PPH_STRING InternalName;\n    PPH_STRING Name;\n    PPH_STRING Version;\n    PPH_STRING Description;\n\n    PH_STRINGREF TextCache[PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM];\n} PH_PLUGIN_TREE_ROOT_NODE, *PPH_PLUGIN_TREE_ROOT_NODE;\n\nINT_PTR CALLBACK PhpPluginPropertiesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nULONG PhpDisabledPluginsCount(\n    VOID\n    );\n\nINT_PTR CALLBACK PhpPluginsDisabledDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n#pragma region Plugin TreeList\n\n#define SORT_FUNCTION(Column) PluginsTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PluginsTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_PLUGIN_TREE_ROOT_NODE node1 = *(PPH_PLUGIN_TREE_ROOT_NODE*)_elem1; \\\n    PPH_PLUGIN_TREE_ROOT_NODE node2 = *(PPH_PLUGIN_TREE_ROOT_NODE*)_elem2; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \\\n    \\\n    return PhModifySort(sortResult, ((PPH_PLUGMAN_CONTEXT)_context)->TreeNewSortOrder); \\\n}\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareStringWithNull(node1->Name, node2->Name, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Version)\n{\n    sortResult = PhCompareStringWithNull(node1->Version, node2->Version, TRUE);\n}\nEND_SORT_FUNCTION\n\nVOID PluginsLoadSettingsTreeList(\n    _Inout_ PPH_PLUGMAN_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhGetStringSetting(SETTING_PLUGIN_MANAGER_TREE_LIST_COLUMNS);\n    PhCmLoadSettings(Context->TreeNewHandle, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\nVOID PluginsSaveSettingsTreeList(\n    _Inout_ PPH_PLUGMAN_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhCmSaveSettings(Context->TreeNewHandle);\n    PhSetStringSetting2(SETTING_PLUGIN_MANAGER_TREE_LIST_COLUMNS, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PluginsNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_PLUGIN_TREE_ROOT_NODE node1 = *(PPH_PLUGIN_TREE_ROOT_NODE *)Entry1;\n    PPH_PLUGIN_TREE_ROOT_NODE node2 = *(PPH_PLUGIN_TREE_ROOT_NODE *)Entry2;\n\n    return PhEqualString(node1->InternalName, node2->InternalName, TRUE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PluginsNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashStringRef(&(*(PPH_PLUGIN_TREE_ROOT_NODE*)Entry)->InternalName->sr, TRUE);\n}\n\nVOID DestroyPluginsNode(\n    _In_ PPH_PLUGIN_TREE_ROOT_NODE Node\n    )\n{\n    PhClearReference(&Node->InternalName);\n    PhClearReference(&Node->Name);\n    PhClearReference(&Node->Version);\n    PhClearReference(&Node->Description);\n\n    PhFree(Node);\n}\n\nPPH_PLUGIN_TREE_ROOT_NODE AddPluginsNode(\n    _Inout_ PPH_PLUGMAN_CONTEXT Context,\n    _In_ PPH_PLUGIN Plugin\n    )\n{\n    PPH_PLUGIN_TREE_ROOT_NODE pluginNode;\n    PH_IMAGE_VERSION_INFO versionInfo;\n    PPH_STRING fileName;\n\n    pluginNode = PhAllocate(sizeof(PH_PLUGIN_TREE_ROOT_NODE));\n    memset(pluginNode, 0, sizeof(PH_PLUGIN_TREE_ROOT_NODE));\n\n    PhInitializeTreeNewNode(&pluginNode->Node);\n\n    memset(pluginNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM);\n    pluginNode->Node.TextCache = pluginNode->TextCache;\n    pluginNode->Node.TextCacheSize = PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM;\n\n    pluginNode->PluginInstance = Plugin;\n    pluginNode->PluginOptions = Plugin->Information.HasOptions;\n    pluginNode->InternalName = PhCreateString2(&Plugin->Name);\n    if (Plugin->Information.DisplayName)\n        pluginNode->Name = PhCreateString(Plugin->Information.DisplayName);\n    if (Plugin->Information.Description)\n        pluginNode->Description = PhCreateString(Plugin->Information.Description);\n\n    if (fileName = PhGetPluginFileName(Plugin))\n    {\n        if (NT_SUCCESS(PhInitializeImageVersionInfoEx(&versionInfo, &fileName->sr, FALSE)))\n        {\n            pluginNode->Version = PhReferenceObject(versionInfo.FileVersion);\n            PhDeleteImageVersionInfo(&versionInfo);\n        }\n\n        PhDereferenceObject(fileName);\n    }\n\n    PhAddEntryHashtable(Context->NodeHashtable, &pluginNode);\n    PhAddItemList(Context->NodeList, pluginNode);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    return pluginNode;\n}\n\nPPH_PLUGIN_TREE_ROOT_NODE FindPluginsNode(\n    _In_ PPH_PLUGMAN_CONTEXT Context,\n    _In_ PPH_STRING InternalName\n    )\n{\n    PH_PLUGIN_TREE_ROOT_NODE lookupPluginsNode;\n    PPH_PLUGIN_TREE_ROOT_NODE lookupPluginsNodePtr = &lookupPluginsNode;\n    PPH_PLUGIN_TREE_ROOT_NODE *pluginsNode;\n\n    lookupPluginsNode.InternalName = InternalName;\n\n    pluginsNode = (PPH_PLUGIN_TREE_ROOT_NODE*)PhFindEntryHashtable(\n        Context->NodeHashtable,\n        &lookupPluginsNodePtr\n        );\n\n    if (pluginsNode)\n        return *pluginsNode;\n    else\n        return NULL;\n}\n\nVOID RemovePluginsNode(\n    _In_ PPH_PLUGMAN_CONTEXT Context,\n    _In_ PPH_PLUGIN_TREE_ROOT_NODE Node\n    )\n{\n    ULONG index = 0;\n\n    PhRemoveEntryHashtable(Context->NodeHashtable, &Node);\n\n    if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX)\n    {\n        PhRemoveItemList(Context->NodeList, index);\n    }\n\n    DestroyPluginsNode(Node);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID UpdatePluginsNode(\n    _In_ PPH_PLUGMAN_CONTEXT Context,\n    _In_ PPH_PLUGIN_TREE_ROOT_NODE Node\n    )\n{\n    memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM);\n\n    PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nBOOLEAN NTAPI PluginsTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_PLUGMAN_CONTEXT context = Context;\n    PPH_PLUGIN_TREE_ROOT_NODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_PLUGIN_TREE_ROOT_NODE)getChildren->Node;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(Name),\n                    //SORT_FUNCTION(Author),\n                    SORT_FUNCTION(Version)\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (context->TreeNewSortColumn < PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM)\n                    sortFunction = sortFunctions[context->TreeNewSortColumn];\n                else\n                    sortFunction = NULL;\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1;\n            node = (PPH_PLUGIN_TREE_ROOT_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1;\n            node = (PPH_PLUGIN_TREE_ROOT_NODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case PH_PLUGIN_TREE_COLUMN_ITEM_NAME:\n                getCellText->Text = PhGetStringRef(node->Name);\n                break;\n            case PH_PLUGIN_TREE_COLUMN_ITEM_VERSION:\n                getCellText->Text = PhGetStringRef(node->Version);\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            node = (PPH_PLUGIN_TREE_ROOT_NODE)getNodeColor->Node;\n\n            getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_COPY, 0);\n                break;\n            case VK_DELETE:\n                SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_CLOSE, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1;\n\n            SendMessage(context->WindowHandle, WM_COMMAND, WM_PH_PLUGINS_SHOWPROPERTIES, (LPARAM)mouseEvent);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1;\n\n            SendMessage(context->WindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenuEvent);\n        }\n        return TRUE;\n    //case TreeNewHeaderRightClick:\n    //    {\n    //        PH_TN_COLUMN_MENU_DATA data;\n    //\n    //        data.TreeNewHandle = WindowHandle;\n    //        data.MouseEvent = Parameter1;\n    //        data.DefaultSortColumn = 0;\n    //        data.DefaultSortOrder = AscendingSortOrder;\n    //        PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n    //\n    //        data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT,\n    //            PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n    //        PhHandleTreeNewColumnMenu(&data);\n    //        PhDeleteTreeNewColumnMenu(&data);\n    //    }\n    //    return TRUE;\n    case TreeNewCustomDraw:\n        {\n            PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;\n            RECT rect;\n\n            rect = customDraw->CellRect;\n            node = (PPH_PLUGIN_TREE_ROOT_NODE)customDraw->Node;\n\n            switch (customDraw->Column->Id)\n            {\n            case PH_PLUGIN_TREE_COLUMN_ITEM_NAME:\n                {\n                    PH_STRINGREF text;\n                    SIZE nameSize;\n                    SIZE textSize;\n                    LONG dpiValue;\n\n                    dpiValue = PhGetWindowDpi(WindowHandle);\n\n                    rect.left += PhGetDpi(15, dpiValue);\n                    rect.top += PhGetDpi(5, dpiValue);\n                    rect.right -= PhGetDpi(5, dpiValue);\n                    rect.bottom -= PhGetDpi(8, dpiValue);\n\n                    // top\n                    if (PhEnableThemeSupport)\n                        SetTextColor(customDraw->Dc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                    else\n                        SetTextColor(customDraw->Dc, RGB(0x0, 0x0, 0x0));\n\n                    SelectFont(customDraw->Dc, context->TitleFontHandle);\n                    text = PhIsNullOrEmptyString(node->Name) ? PhGetStringRef(node->InternalName) : PhGetStringRef(node->Name);\n                    GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &nameSize);\n                    DrawText(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &rect, DT_TOP | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE);\n\n                    // bottom\n                    if (PhEnableThemeSupport)\n                        SetTextColor(customDraw->Dc, RGB(0x90, 0x90, 0x90));\n                    else\n                        SetTextColor(customDraw->Dc, RGB(0x64, 0x64, 0x64));\n\n                    SelectFont(customDraw->Dc, context->NormalFontHandle);\n                    text = PhGetStringRef(node->Description);\n                    GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize);\n                    DrawText(\n                        customDraw->Dc,\n                        text.Buffer,\n                        (ULONG)text.Length / sizeof(WCHAR),\n                        &rect,\n                        DT_BOTTOM | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE\n                        );\n                }\n                break;\n            }\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID ClearPluginsTree(\n    _In_ PPH_PLUGMAN_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        DestroyPluginsNode(Context->NodeList->Items[i]);\n\n    PhClearHashtable(Context->NodeHashtable);\n    PhClearList(Context->NodeList);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nPPH_PLUGIN_TREE_ROOT_NODE GetSelectedPluginsNode(\n    _In_ PPH_PLUGMAN_CONTEXT Context\n    )\n{\n    PPH_PLUGIN_TREE_ROOT_NODE pluginNode = NULL;\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        pluginNode = Context->NodeList->Items[i];\n\n        if (pluginNode->Node.Selected)\n            return pluginNode;\n    }\n\n    return NULL;\n}\n\n_Success_(return)\nBOOLEAN GetSelectedPluginsNodes(\n    _In_ PPH_PLUGMAN_CONTEXT Context,\n    _Out_ PPH_PLUGIN_TREE_ROOT_NODE **Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_PLUGIN_TREE_ROOT_NODE node = (PPH_PLUGIN_TREE_ROOT_NODE)Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            PhAddItemList(list, node);\n        }\n    }\n\n    if (list->Count)\n    {\n        *Nodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\nVOID InitializePluginsTree(\n    _Inout_ PPH_PLUGMAN_CONTEXT Context\n    )\n{\n    LONG dpiValue;\n\n    dpiValue = PhGetWindowDpi(Context->WindowHandle);\n\n    Context->NodeList = PhCreateList(20);\n    Context->NodeHashtable = PhCreateHashtable(\n        sizeof(PPH_PLUGIN_TREE_ROOT_NODE),\n        PluginsNodeHashtableEqualFunction,\n        PluginsNodeHashtableHashFunction,\n        20\n        );\n\n    Context->NormalFontHandle = PhCreateCommonFont(-10, FW_NORMAL, NULL, dpiValue);\n    Context->TitleFontHandle = PhCreateCommonFont(-14, FW_BOLD, NULL, dpiValue);\n\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n\n    TreeNew_SetCallback(Context->TreeNewHandle, PluginsTreeNewCallback, Context);\n    TreeNew_SetRowHeight(Context->TreeNewHandle, PhGetDpi(48, dpiValue));\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n\n    PhAddTreeNewColumnEx2(Context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TRUE, L\"Plugin\", 80, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_CUSTOMDRAW);\n    //PhAddTreeNewColumnEx2(Context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_AUTHOR, TRUE, L\"Author\", 80, PH_ALIGN_LEFT, 1, 0, 0);\n    //PhAddTreeNewColumnEx2(Context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_VERSION, TRUE, L\"Version\", 80, PH_ALIGN_CENTER, 2, DT_CENTER, 0);\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n\n    TreeNew_SetTriState(Context->TreeNewHandle, TRUE);\n\n    PluginsLoadSettingsTreeList(Context);\n}\n\nVOID DeletePluginsTree(\n    _In_ PPH_PLUGMAN_CONTEXT Context\n    )\n{\n    if (Context->TitleFontHandle)\n        DeleteFont(Context->TitleFontHandle);\n    if (Context->NormalFontHandle)\n        DeleteFont(Context->NormalFontHandle);\n\n    PluginsSaveSettingsTreeList(Context);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        DestroyPluginsNode(Context->NodeList->Items[i]);\n\n    PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n}\n\n#pragma endregion\n\nPPH_STRING PhpGetPluginBaseName(\n    _In_ PPH_PLUGIN Plugin\n    )\n{\n    PPH_STRING fileName;\n    PPH_STRING baseName;\n\n    if (fileName = PhGetPluginFileName(Plugin))\n    {\n        PH_STRINGREF pathNamePart;\n        PH_STRINGREF baseNamePart;\n\n        if (PhSplitStringRefAtLastChar(&fileName->sr, OBJ_NAME_PATH_SEPARATOR, &pathNamePart, &baseNamePart))\n        {\n            baseName = PhCreateString2(&baseNamePart);\n            PhDereferenceObject(fileName);\n            return baseName;\n        }\n\n        baseName = PhCreateString2(&Plugin->Name);\n        PhDereferenceObject(fileName);\n        return baseName;\n    }\n    else\n    {\n        // Fake disabled plugin.\n        baseName = PhCreateString2(&Plugin->Name);\n        return baseName;\n    }\n}\n\n_Function_class_(PH_PLUGIN_ENUMERATE)\nNTSTATUS NTAPI PhpEnumeratePluginCallback(\n    _In_ PPH_PLUGIN Information,\n    _In_ PVOID Context\n    )\n{\n    PPH_STRING pluginBaseName;\n\n    pluginBaseName = PhpGetPluginBaseName(Information);\n\n    if (!PhIsPluginDisabled(&pluginBaseName->sr))\n    {\n        AddPluginsNode(Context, Information);\n    }\n\n    PhDereferenceObject(pluginBaseName);\n    return STATUS_SUCCESS;\n}\n\nINT_PTR CALLBACK PhPluginsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PLUGMAN_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocateZero(sizeof(PH_PLUGMAN_CONTEXT));\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_PLUGINTREE);\n\n            InitializePluginsTree(context);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_INSTRUCTION), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_DISABLED), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n\n            PhEnumeratePlugins(PhpEnumeratePluginCallback, context);\n            TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE);\n            PhSetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L\"Disabled Plugins (%lu)\", PhpDisabledPluginsCount())->Buffer);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            DeletePluginsTree(context);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhFree(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_DISABLED:\n                {\n                    PhDialogBox(\n                        NtCurrentImageBase(),\n                        MAKEINTRESOURCE(IDD_PLUGINSDISABLED),\n                        hwndDlg,\n                        PhpPluginsDisabledDlgProc,\n                        NULL\n                        );\n\n                    ClearPluginsTree(context);\n                    PhEnumeratePlugins(PhpEnumeratePluginCallback, context);\n                    TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE);\n                    PhSetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L\"Disabled Plugins (%lu)\", PhpDisabledPluginsCount())->Buffer);\n                }\n                break;\n            case ID_SHOWCONTEXTMENU:\n                {\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM selectedItem;\n                    //PPH_EMENU_ITEM uninstallItem;\n                    PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam;\n                    PPH_PLUGIN_TREE_ROOT_NODE selectedNode = (PPH_PLUGIN_TREE_ROOT_NODE)contextMenuEvent->Node;\n\n                    if (!selectedNode)\n                        break;\n\n                    menu = PhCreateEMenu();\n                    //PhInsertEMenuItem(menu, uninstallItem = PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_UNINSTALL, L\"Uninstall\", NULL, NULL), ULONG_MAX);\n                    //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_DISABLE, L\"Disable\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES, L\"Properties\", NULL, NULL), ULONG_MAX);\n\n                    //if (!PhGetOwnTokenAttributes().Elevated)\n                    //{\n                    //    HBITMAP shieldBitmap;\n                    //\n                    //    if (shieldBitmap = PhGetShieldBitmap())\n                    //        uninstallItem->Bitmap = shieldBitmap;\n                    //}\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        contextMenuEvent->Location.x,\n                        contextMenuEvent->Location.y\n                        );\n\n                    if (selectedItem && selectedItem->Id != ULONG_MAX)\n                    {\n                        switch (selectedItem->Id)\n                        {\n                        case PH_PLUGIN_TREE_ITEM_MENU_UNINSTALL:\n                            {\n                                //if (PhShowConfirmMessage(\n                                //    hwndDlg,\n                                //    L\"Uninstall\",\n                                //    PhGetString(selectedNode->Name),\n                                //    L\"Changes may require a restart to take effect...\",\n                                //    TRUE\n                                //    ))\n                                //{\n                                //\n                                //}\n                            }\n                            break;\n                        case PH_PLUGIN_TREE_ITEM_MENU_DISABLE:\n                            {\n                                PPH_STRING baseName = PhpGetPluginBaseName(selectedNode->PluginInstance);\n\n                                PhSetPluginDisabled(&baseName->sr, TRUE);\n\n                                RemovePluginsNode(context, selectedNode);\n\n                                PhSetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L\"Disabled Plugins (%lu)\", PhpDisabledPluginsCount())->Buffer);\n\n                                PhDereferenceObject(baseName);\n                            }\n                            break;\n                        case PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES:\n                            {\n                                PhDialogBox(\n                                    NtCurrentImageBase(),\n                                    MAKEINTRESOURCE(IDD_PLUGINPROPERTIES),\n                                    hwndDlg,\n                                    PhpPluginPropertiesDlgProc,\n                                    selectedNode->PluginInstance\n                                    );\n                            }\n                            break;\n                        }\n                    }\n                }\n                break;\n            case WM_PH_PLUGINS_SHOWPROPERTIES:\n                {\n                    PPH_TREENEW_MOUSE_EVENT mouseEvent = (PPH_TREENEW_MOUSE_EVENT)lParam;\n                    PPH_PLUGIN_TREE_ROOT_NODE selectedNode = (PPH_PLUGIN_TREE_ROOT_NODE)mouseEvent->Node;\n\n                    if (!selectedNode)\n                        break;\n\n                    PhDialogBox(\n                        NtCurrentImageBase(),\n                        MAKEINTRESOURCE(IDD_PLUGINPROPERTIES),\n                        hwndDlg,\n                        PhpPluginPropertiesDlgProc,\n                        selectedNode->PluginInstance\n                        );\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n            TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\n//NTSTATUS PhpPluginsDialogThreadStart(\n//    _In_ PVOID Parameter\n//    )\n//{\n//    BOOL result;\n//    MSG message;\n//    PH_AUTO_POOL autoPool;\n//\n//    PhInitializeAutoPool(&autoPool);\n//\n//    PhPluginsWindowHandle = PhCreateDialog(\n//        PhInstanceHandle,\n//        MAKEINTRESOURCE(IDD_PLUGINS),\n//        NULL,\n//        PhPluginsDlgProc,\n//        NULL\n//        );\n//\n//    PhSetEvent(&PhPluginsInitializedEvent);\n//\n//    while (result = GetMessage(&message, NULL, 0, 0))\n//    {\n//        if (result == -1)\n//            break;\n//\n//        if (!IsDialogMessage(PhPluginsWindowHandle, &message))\n//        {\n//            TranslateMessage(&message);\n//            DispatchMessage(&message);\n//        }\n//\n//        PhDrainAutoPool(&autoPool);\n//    }\n//\n//    PhDeleteAutoPool(&autoPool);\n//    PhResetEvent(&PhPluginsInitializedEvent);\n//\n//    if (PhPluginsThreadHandle)\n//    {\n//        NtClose(PhPluginsThreadHandle);\n//        PhPluginsThreadHandle = NULL;\n//    }\n//\n//    return STATUS_SUCCESS;\n//}\n//\n//VOID PhShowPluginsDialog(\n//    _In_ HWND ParentWindowHandle\n//    )\n//{\n//    if (PhPluginsEnabled)\n//    {\n//        if (!PhPluginsThreadHandle)\n//        {\n//            if (!NT_SUCCESS(PhCreateThreadEx(&PhPluginsThreadHandle, PhpPluginsDialogThreadStart, NULL)))\n//            {\n//                PhShowError(PhMainWndHandle, L\"%s\", L\"Unable to create the window.\");\n//                return;\n//            }\n//\n//            PhWaitForEvent(&PhPluginsInitializedEvent, NULL);\n//        }\n//\n//        PostMessage(PhPluginsWindowHandle, WM_PH_PLUGINS_SHOWDIALOG, 0, 0);\n//    }\n//    else\n//    {\n//        PhShowInformation2(\n//            ParentWindowHandle,\n//            L\"Plugins are not enabled.\",\n//            L\"%s\",\n//            L\"To use plugins enable them in Options and restart System Informer.\"\n//            );\n//    }\n//}\n\nVOID PhpRefreshPluginDetails(\n    _In_ HWND hwndDlg,\n    _In_ PPH_PLUGIN SelectedPlugin\n    )\n{\n    PPH_STRING fileName = NULL;\n    PPH_STRING baseName = NULL;\n    PH_IMAGE_VERSION_INFO versionInfo;\n\n    if (fileName = PhGetPluginFileName(SelectedPlugin))\n        baseName = PH_AUTO(PhGetBaseName(fileName));\n\n    PhSetDialogItemText(hwndDlg, IDC_NAME, SelectedPlugin->Information.DisplayName ? SelectedPlugin->Information.DisplayName : L\"(unnamed)\");\n    PhSetDialogItemText(hwndDlg, IDC_INTERNALNAME, SelectedPlugin->Name.Buffer);\n    PhSetDialogItemText(hwndDlg, IDC_AUTHOR, SelectedPlugin->Information.Author);\n    PhSetDialogItemText(hwndDlg, IDC_FILENAME, PhGetStringOrEmpty(baseName));\n    PhSetDialogItemText(hwndDlg, IDC_DESCRIPTION, SelectedPlugin->Information.Description);\n    PhSetDialogItemText(hwndDlg, IDC_URL, SelectedPlugin->Information.Url);\n\n    if (fileName && NT_SUCCESS(PhInitializeImageVersionInfoEx(&versionInfo, &fileName->sr, FALSE)))\n    {\n        PhSetDialogItemText(hwndDlg, IDC_VERSION, PhGetStringOrDefault(versionInfo.FileVersion, L\"Unknown\"));\n        PhDeleteImageVersionInfo(&versionInfo);\n    }\n    else\n    {\n        PhSetDialogItemText(hwndDlg, IDC_VERSION, L\"Unknown\");\n    }\n\n    ShowWindow(GetDlgItem(hwndDlg, IDC_OPENURL), SelectedPlugin->Information.Url ? SW_SHOW : SW_HIDE);\n    EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), SelectedPlugin->Information.HasOptions);\n\n    PhClearReference(&fileName);\n}\n\nINT_PTR CALLBACK PhpPluginPropertiesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PLUGIN selectedPlugin = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        selectedPlugin = (PPH_PLUGIN)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, selectedPlugin);\n    }\n    else\n    {\n        selectedPlugin = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n        if (uMsg == WM_DESTROY)\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n    }\n\n    if (selectedPlugin == NULL)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhpRefreshPluginDetails(hwndDlg, selectedPlugin);\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                EndDialog(hwndDlg, IDOK);\n                break;\n            case IDC_OPTIONS:\n                {\n                    PhInvokeCallback(PhGetPluginCallback(selectedPlugin, PluginCallbackShowOptions), hwndDlg);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case NM_CLICK:\n                {\n                    if (header->hwndFrom == GetDlgItem(hwndDlg, IDC_OPENURL))\n                    {\n                        PhShellExecute(hwndDlg, selectedPlugin->Information.Url, NULL);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\ntypedef struct _PLUGIN_DISABLED_CONTEXT\n{\n    PH_QUEUED_LOCK ListLock;\n    HWND DialogHandle;\n    HWND ListViewHandle;\n} PLUGIN_DISABLED_CONTEXT, *PPLUGIN_DISABLED_CONTEXT;\n\nVOID PhpAddDisabledPlugins(\n    _In_ PPLUGIN_DISABLED_CONTEXT Context\n    )\n{\n    PPH_STRING disabled;\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF part;\n    PPH_STRING displayText;\n    INT lvItemIndex;\n\n    disabled = PhGetStringSetting(SETTING_DISABLED_PLUGINS);\n    remainingPart = disabled->sr;\n\n    while (remainingPart.Length)\n    {\n        PhSplitStringRefAtChar(&remainingPart, L'|', &part, &remainingPart);\n\n        if (part.Length)\n        {\n            displayText = PhCreateString2(&part);\n\n            PhAcquireQueuedLockExclusive(&Context->ListLock);\n            lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, PhGetString(displayText), displayText);\n            PhReleaseQueuedLockExclusive(&Context->ListLock);\n\n            ListView_SetCheckState(Context->ListViewHandle, lvItemIndex, TRUE);\n        }\n    }\n\n    PhDereferenceObject(disabled);\n}\n\nULONG PhpDisabledPluginsCount(\n    VOID\n    )\n{\n    PPH_STRING disabled;\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF part;\n    ULONG count = 0;\n\n    disabled = PhGetStringSetting(SETTING_DISABLED_PLUGINS);\n    remainingPart = disabled->sr;\n\n    while (remainingPart.Length)\n    {\n        PhSplitStringRefAtChar(&remainingPart, L'|', &part, &remainingPart);\n\n        if (part.Length)\n            count++;\n    }\n\n    PhDereferenceObject(disabled);\n\n    return count;\n}\n\nINT_PTR CALLBACK PhpPluginsDisabledDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPLUGIN_DISABLED_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocate(sizeof(PLUGIN_DISABLED_CONTEXT));\n        memset(context, 0, sizeof(PLUGIN_DISABLED_CONTEXT));\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n        if (uMsg == WM_DESTROY)\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n            PhFree(context);\n            context = NULL;\n        }\n    }\n\n    if (context == NULL)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->DialogHandle = hwndDlg;\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST_DISABLED);\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            ListView_SetExtendedListViewStyleEx(context->ListViewHandle,\n                LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER,\n                LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 400, L\"Property\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            PhpAddDisabledPlugins(context);\n            ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                EndDialog(hwndDlg, IDOK);\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            if (header->code == LVN_ITEMCHANGED)\n            {\n                LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam;\n\n                if (!PhTryAcquireReleaseQueuedLockExclusive(&context->ListLock))\n                    break;\n\n                if (listView->uChanged & LVIF_STATE)\n                {\n                    switch (listView->uNewState & LVIS_STATEIMAGEMASK)\n                    {\n                    case INDEXTOSTATEIMAGEMASK(2): // checked\n                        {\n                            PPH_STRING param = (PPH_STRING)listView->lParam;\n\n                            PhSetPluginDisabled(&param->sr, TRUE);\n                        }\n                        break;\n                    case INDEXTOSTATEIMAGEMASK(1): // unchecked\n                        {\n                            PPH_STRING param = (PPH_STRING)listView->lParam;\n\n                            PhSetPluginDisabled(&param->sr, FALSE);\n                        }\n                        break;\n                    }\n                }\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/procgrp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015\n *\n */\n\n#include <phapp.h>\n#include <procgrp.h>\n\n#include <procprv.h>\n#include <proctree.h>\n\ntypedef struct _PHP_PROCESS_DATA\n{\n    PPH_PROCESS_NODE Process;\n    LIST_ENTRY ListEntry;\n    HWND WindowHandle;\n} PHP_PROCESS_DATA, *PPHP_PROCESS_DATA;\n\nPPH_LIST PhpCreateProcessDataList(\n    _In_ PPH_LIST Processes\n    )\n{\n    PPH_LIST processDataList;\n    ULONG i;\n\n    processDataList = PhCreateList(Processes->Count);\n\n    for (i = 0; i < Processes->Count; i++)\n    {\n        PPH_PROCESS_NODE process = Processes->Items[i];\n        PPHP_PROCESS_DATA processData;\n\n        if (PH_IS_FAKE_PROCESS_ID(process->ProcessId) || process->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n            continue;\n\n        processData = PhAllocate(sizeof(PHP_PROCESS_DATA));\n        memset(processData, 0, sizeof(PHP_PROCESS_DATA));\n        processData->Process = process;\n        PhAddItemList(processDataList, processData);\n    }\n\n    return processDataList;\n}\n\nVOID PhpDestroyProcessDataList(\n    _In_ PPH_LIST List\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < List->Count; i++)\n    {\n        PPHP_PROCESS_DATA processData = List->Items[i];\n        PhFree(processData);\n    }\n\n    PhDereferenceObject(List);\n}\n\nVOID PhpProcessDataListToLinkedList(\n    _In_ PPH_LIST List,\n    _Out_ PLIST_ENTRY ListHead\n    )\n{\n    ULONG i;\n\n    InitializeListHead(ListHead);\n\n    for (i = 0; i < List->Count; i++)\n    {\n        PPHP_PROCESS_DATA processData = List->Items[i];\n        InsertTailList(ListHead, &processData->ListEntry);\n    }\n}\n\nVOID PhpProcessDataListToHashtable(\n    _In_ PPH_LIST List,\n    _Out_ PPH_HASHTABLE *Hashtable\n    )\n{\n    PPH_HASHTABLE hashtable;\n    ULONG i;\n\n    hashtable = PhCreateSimpleHashtable(List->Count);\n\n    for (i = 0; i < List->Count; i++)\n    {\n        PPHP_PROCESS_DATA processData = List->Items[i];\n        PhAddItemSimpleHashtable(hashtable, processData->Process->ProcessId, processData);\n    }\n\n    *Hashtable = hashtable;\n}\n\ntypedef struct _QUERY_WINDOWS_CONTEXT\n{\n    PPH_HASHTABLE ProcessDataHashtable;\n} QUERY_WINDOWS_CONTEXT, *PQUERY_WINDOWS_CONTEXT;\n\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nBOOLEAN CALLBACK PhpQueryWindowsEnumWindowsProc(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PQUERY_WINDOWS_CONTEXT context = (PQUERY_WINDOWS_CONTEXT)Context;\n    CLIENT_ID clientId;\n    PPHP_PROCESS_DATA processData;\n    HWND parentWindow;\n\n    if (!IsWindowVisible(WindowHandle))\n        return TRUE;\n    if (!NT_SUCCESS(PhGetWindowClientId(WindowHandle, &clientId)))\n        return TRUE;\n\n    processData = PhFindItemSimpleHashtable2(context->ProcessDataHashtable, clientId.UniqueProcess);\n\n    if (!processData || processData->WindowHandle)\n        return TRUE;\n\n    parentWindow = GetParent(WindowHandle);\n\n    if (!(parentWindow && IsWindowVisible(parentWindow)) && // Skip windows with a visible parent\n        PhGetWindowTextEx(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0) // Skip windows with no title\n    {\n        processData->WindowHandle = WindowHandle;\n    }\n\n    return TRUE;\n}\n\nPPH_STRING PhpGetRelevantFileName(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG Flags\n    )\n{\n    if (Flags & PH_GROUP_PROCESSES_FILE_PATH)\n        return ProcessItem->FileName;\n    else\n        return ProcessItem->ProcessName;\n}\n\nBOOLEAN PhpEqualFileNameAndUserName(\n    _In_ PPH_STRING FileName,\n    _In_ PSID UserSid,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG Flags\n    )\n{\n    PPH_STRING otherFileName;\n    PSID otherUserSid;\n\n    otherFileName = PhpGetRelevantFileName(ProcessItem, Flags);\n    otherUserSid = ProcessItem->Sid;\n\n    return\n        otherFileName && PhEqualString(otherFileName, FileName, TRUE) &&\n        otherUserSid && PhEqualSid(otherUserSid, UserSid);\n}\n\nPPHP_PROCESS_DATA PhpFindGroupRoot(\n    _In_ PPHP_PROCESS_DATA ProcessData,\n    _In_ PPH_HASHTABLE ProcessDataHashtable,\n    _In_ ULONG Flags\n    )\n{\n    PPH_PROCESS_NODE root;\n    PPHP_PROCESS_DATA rootProcessData;\n    PPH_PROCESS_NODE parent;\n    PPHP_PROCESS_DATA processData;\n    PPH_STRING fileName;\n    PPH_STRING userSid;\n\n    root = ProcessData->Process;\n    rootProcessData = ProcessData;\n    fileName = PhpGetRelevantFileName(ProcessData->Process->ProcessItem, Flags);\n    userSid = ProcessData->Process->ProcessItem->Sid;\n\n    if (ProcessData->WindowHandle)\n        return rootProcessData;\n\n    while (parent = root->Parent)\n    {\n        if ((processData = PhFindItemSimpleHashtable2(ProcessDataHashtable, parent->ProcessId)) &&\n            PhpEqualFileNameAndUserName(fileName, userSid, parent->ProcessItem, Flags))\n        {\n            root = parent;\n            rootProcessData = processData;\n\n            if (processData->WindowHandle)\n                break;\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    return rootProcessData;\n}\n\nVOID PhpAddGroupMember(\n    _In_ PPHP_PROCESS_DATA ProcessData,\n    _Inout_ PPH_LIST List\n    )\n{\n    PhReferenceObject(ProcessData->Process->ProcessItem);\n    PhAddItemList(List, ProcessData->Process->ProcessItem);\n    RemoveEntryList(&ProcessData->ListEntry);\n}\n\nVOID PhpAddGroupMembersFromRoot(\n    _In_ PPHP_PROCESS_DATA ProcessData,\n    _Inout_ PPH_LIST List,\n    _In_ PPH_HASHTABLE ProcessDataHashtable,\n    _In_ ULONG Flags\n    )\n{\n    PPH_STRING fileName;\n    PSID userSid;\n    ULONG i;\n\n    PhpAddGroupMember(ProcessData, List);\n    fileName = PhpGetRelevantFileName(ProcessData->Process->ProcessItem, Flags);\n    userSid = ProcessData->Process->ProcessItem->Sid;\n\n    for (i = 0; i < ProcessData->Process->Children->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessData->Process->Children->Items[i];\n        PPHP_PROCESS_DATA processData;\n\n        if ((processData = PhFindItemSimpleHashtable2(ProcessDataHashtable, node->ProcessId)) &&\n            PhpEqualFileNameAndUserName(fileName, userSid, node->ProcessItem, Flags) &&\n            node->ProcessItem->Sid && PhEqualSid(node->ProcessItem->Sid, userSid) &&\n            !processData->WindowHandle)\n        {\n            PhpAddGroupMembersFromRoot(processData, List, ProcessDataHashtable, Flags);\n        }\n    }\n}\n\nPPH_LIST PhCreateProcessGroupList(\n    _In_opt_ PPH_SORT_LIST_FUNCTION SortListFunction,\n    _In_opt_ PVOID Context,\n    _In_ ULONG MaximumGroups,\n    _In_ ULONG Flags\n    )\n{\n    PPH_LIST processList;\n    PPH_LIST processDataList;\n    LIST_ENTRY processDataListHead; // We will be removing things from this list as we group processes together\n    PPH_HASHTABLE processDataHashtable; // Process ID to process data hashtable\n    QUERY_WINDOWS_CONTEXT queryWindowsContext;\n    PPH_LIST processGroupList;\n\n    // We group together processes that share a common ancestor and have the same file name, where\n    // the ancestor must have a visible window and all other processes in the group do not have a\n    // visible window. All processes in the group must have the same user name. All ancestors up to\n    // the lowest common ancestor must have the same file name and user name.\n    //\n    // The current algorithm is greedy and may not detect groups that have many processes, each with\n    // a small usage amount.\n\n    processList = PhDuplicateProcessNodeList();\n\n    if (SortListFunction)\n        SortListFunction(processList, Context);\n\n    processDataList = PhpCreateProcessDataList(processList);\n    PhDereferenceObject(processList);\n    PhpProcessDataListToLinkedList(processDataList, &processDataListHead);\n    PhpProcessDataListToHashtable(processDataList, &processDataHashtable);\n\n    queryWindowsContext.ProcessDataHashtable = processDataHashtable;\n    PhEnumChildWindows(NULL, PhpQueryWindowsEnumWindowsProc, &queryWindowsContext);\n\n    processGroupList = PhCreateList(10);\n\n    while (processDataListHead.Flink != &processDataListHead && processGroupList->Count < MaximumGroups)\n    {\n        PPHP_PROCESS_DATA processData = CONTAINING_RECORD(processDataListHead.Flink, PHP_PROCESS_DATA, ListEntry);\n        PPH_PROCESS_GROUP processGroup;\n        PPH_STRING fileName;\n        PSID userSid;\n\n        processGroup = PhAllocateZero(sizeof(PH_PROCESS_GROUP));\n        processGroup->Processes = PhCreateList(4);\n        fileName = PhpGetRelevantFileName(processData->Process->ProcessItem, Flags);\n        userSid = processData->Process->ProcessItem->Sid;\n\n        if (PhIsNullOrEmptyString(fileName) || !PhValidSid(userSid) || (Flags & PH_GROUP_PROCESSES_DONT_GROUP))\n        {\n            processGroup->Representative = processData->Process->ProcessItem;\n            PhpAddGroupMember(processData, processGroup->Processes);\n        }\n        else\n        {\n            processData = PhpFindGroupRoot(processData, processDataHashtable, Flags);\n            processGroup->Representative = processData->Process->ProcessItem;\n            PhpAddGroupMembersFromRoot(processData, processGroup->Processes, processDataHashtable, Flags);\n        }\n\n        processGroup->WindowHandle = processData->WindowHandle;\n\n        PhAddItemList(processGroupList, processGroup);\n    }\n\n    PhDereferenceObject(processDataHashtable);\n    PhpDestroyProcessDataList(processDataList);\n\n    return processGroupList;\n}\n\nVOID PhFreeProcessGroupList(\n    _In_ PPH_LIST List\n    )\n{\n    for (ULONG i = 0; i < List->Count; i++)\n    {\n        PPH_PROCESS_GROUP processGroup = List->Items[i];\n\n        PhDereferenceObjects(processGroup->Processes->Items, processGroup->Processes->Count);\n        PhClearReference(&processGroup->Processes);\n        PhFree(processGroup);\n    }\n\n    PhClearList(List);\n    PhDereferenceObject(List);\n}\n"
  },
  {
    "path": "SystemInformer/procmtgn.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <procmtgn.h>\n\nNTSTATUS PhpCopyProcessMitigationPolicy(\n    _Inout_ PNTSTATUS Status,\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESS_MITIGATION_POLICY Policy,\n    _In_ SIZE_T Offset,\n    _In_ SIZE_T Size,\n    _Out_writes_bytes_(Size) PVOID Destination\n    )\n{\n    NTSTATUS status;\n    PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;\n\n    policyInfo.Policy = Policy;\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessMitigationPolicy,\n        &policyInfo,\n        sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        if (*Status == STATUS_NONE_MAPPED)\n            *Status = status;\n        return status;\n    }\n\n    memcpy(Destination, PTR_ADD_OFFSET(&policyInfo, Offset), Size);\n    *Status = STATUS_SUCCESS;\n\n    return status;\n}\n\nNTSTATUS PhGetProcessMitigationPolicyAllInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION Information\n    )\n{\n    NTSTATUS status = STATUS_NONE_MAPPED;\n    NTSTATUS subStatus;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n    ULONG depStatus;\n\n    memset(Information, 0, sizeof(PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION));\n\n#ifdef _WIN64\n    if (NT_SUCCESS(subStatus = PhGetProcessIsWow64(ProcessHandle, &isWow64)) && !isWow64)\n    {\n        depStatus = PH_PROCESS_DEP_ENABLED | PH_PROCESS_DEP_PERMANENT;\n    }\n    else\n    {\n#endif\n        subStatus = PhGetProcessDepStatus(ProcessHandle, &depStatus);\n#ifdef _WIN64\n    }\n#endif\n\n    if (NT_SUCCESS(subStatus))\n    {\n        status = STATUS_SUCCESS;\n        Information->DEPPolicy.Enable = !!(depStatus & PH_PROCESS_DEP_ENABLED);\n        Information->DEPPolicy.DisableAtlThunkEmulation = !!(depStatus & PH_PROCESS_DEP_ATL_THUNK_EMULATION_DISABLED);\n        Information->DEPPolicy.Permanent = !!(depStatus & PH_PROCESS_DEP_PERMANENT);\n        Information->Pointers[ProcessDEPPolicy] = &Information->DEPPolicy;\n    }\n    else if (status == STATUS_NONE_MAPPED)\n    {\n        status = subStatus;\n    }\n\n#define COPY_PROCESS_MITIGATION_POLICY(PolicyName, StructName) \\\n    if (NT_SUCCESS(PhpCopyProcessMitigationPolicy(&status, ProcessHandle, Process##PolicyName##Policy, \\\n        UFIELD_OFFSET(PROCESS_MITIGATION_POLICY_INFORMATION, PolicyName##Policy), \\\n        sizeof(StructName), \\\n        &Information->PolicyName##Policy))) \\\n    { \\\n        Information->Pointers[Process##PolicyName##Policy] = &Information->PolicyName##Policy; \\\n    }\n\n    COPY_PROCESS_MITIGATION_POLICY(ASLR, PROCESS_MITIGATION_ASLR_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(DynamicCode, PROCESS_MITIGATION_DYNAMIC_CODE_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(StrictHandleCheck, PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(SystemCallDisable, PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(ExtensionPointDisable, PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(ControlFlowGuard, PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(Signature, PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(FontDisable, PROCESS_MITIGATION_FONT_DISABLE_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(ImageLoad, PROCESS_MITIGATION_IMAGE_LOAD_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(SystemCallFilter, PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY); // REDSTONE3\n    COPY_PROCESS_MITIGATION_POLICY(PayloadRestriction, PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(ChildProcess, PROCESS_MITIGATION_CHILD_PROCESS_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(SideChannelIsolation, PROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY); // 19H1\n    COPY_PROCESS_MITIGATION_POLICY(UserShadowStack, PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY); // 20H1\n    COPY_PROCESS_MITIGATION_POLICY(RedirectionTrust, PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY); // 22H1\n    COPY_PROCESS_MITIGATION_POLICY(UserPointerAuth, PROCESS_MITIGATION_USER_POINTER_AUTH_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(SEHOP, PROCESS_MITIGATION_SEHOP_POLICY);\n    COPY_PROCESS_MITIGATION_POLICY(ActivationContextTrust, PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY2);\n\n    return status;\n}\n\n_Success_(return)\nBOOLEAN PhDescribeProcessMitigationPolicy(\n    _In_ PROCESS_MITIGATION_POLICY Policy,\n    _In_ PVOID Data,\n    _Out_opt_ PPH_STRING *ShortDescription,\n    _Out_opt_ PPH_STRING *LongDescription\n    )\n{\n    BOOLEAN result = FALSE;\n    PH_STRING_BUILDER sb;\n\n    switch (Policy)\n    {\n    case ProcessDEPPolicy:\n        {\n            PPROCESS_MITIGATION_DEP_POLICY data = Data;\n\n            if (data->Enable)\n            {\n                if (ShortDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 20);\n                    PhAppendStringBuilder2(&sb, L\"DEP\");\n                    if (data->Permanent) PhAppendStringBuilder2(&sb, L\" (permanent)\");\n                    *ShortDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                if (LongDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 50);\n                    PhAppendFormatStringBuilder(&sb, L\"Data Execution Prevention (DEP) is%s enabled for this process.\\r\\n\", data->Permanent ? L\" permanently\" : L\"\");\n                    if (data->DisableAtlThunkEmulation) PhAppendStringBuilder2(&sb, L\"ATL thunk emulation is disabled.\\r\\n\");\n                    *LongDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessASLRPolicy:\n        {\n            PPROCESS_MITIGATION_ASLR_POLICY data = Data;\n\n            if (data->EnableBottomUpRandomization || data->EnableForceRelocateImages || data->EnableHighEntropy)\n            {\n                if (ShortDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 20);\n                    PhAppendStringBuilder2(&sb, L\"ASLR\");\n\n                    if (data->EnableHighEntropy || data->EnableForceRelocateImages)\n                    {\n                        PhAppendStringBuilder2(&sb, L\" (\");\n                        if (data->EnableHighEntropy) PhAppendStringBuilder2(&sb, L\"high entropy, \");\n                        if (data->EnableForceRelocateImages) PhAppendStringBuilder2(&sb, L\"force relocate, \");\n                        if (data->DisallowStrippedImages) PhAppendStringBuilder2(&sb, L\"disallow stripped, \");\n                        if (PhEndsWithStringRef2(&sb.String->sr, L\", \", FALSE)) PhRemoveEndStringBuilder(&sb, 2);\n                        PhAppendCharStringBuilder(&sb, L')');\n                    }\n\n                    *ShortDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                if (LongDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 100);\n                    PhAppendStringBuilder2(&sb, L\"Address Space Layout Randomization is enabled for this process.\\r\\n\");\n                    if (data->EnableHighEntropy) PhAppendStringBuilder2(&sb, L\"High entropy randomization is enabled.\\r\\n\");\n                    if (data->EnableForceRelocateImages) PhAppendStringBuilder2(&sb, L\"All images are being forcibly relocated (regardless of whether they support ASLR).\\r\\n\");\n                    if (data->DisallowStrippedImages) PhAppendStringBuilder2(&sb, L\"Images with stripped relocation data are disallowed.\\r\\n\");\n                    *LongDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessDynamicCodePolicy:\n        {\n            PPROCESS_MITIGATION_DYNAMIC_CODE_POLICY data = Data;\n\n            if (data->ProhibitDynamicCode)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Dynamic code prohibited\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Dynamically loaded code is not allowed to execute.\\r\\n\");\n\n                result = TRUE;\n            }\n\n            if (data->AllowThreadOptOut)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Dynamic code prohibited (per-thread)\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Allows individual threads to opt out of the restrictions on dynamic code generation.\\r\\n\");\n\n                result = TRUE;\n            }\n\n            if (data->AllowRemoteDowngrade)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Dynamic code downgradable\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Allow non-AppContainer processes to modify all of the dynamic code settings for the calling process, including relaxing dynamic code restrictions after they have been set.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessStrictHandleCheckPolicy:\n        {\n            PPROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY data = Data;\n\n            if (data->RaiseExceptionOnInvalidHandleReference)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Strict handle checks\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"An exception is raised when an invalid handle is used by the process.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessSystemCallDisablePolicy:\n        {\n            PPROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY data = Data;\n\n            if (data->DisallowWin32kSystemCalls)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Win32k system calls disabled\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Win32k (GDI/USER) system calls are not allowed.\\r\\n\");\n\n                result = TRUE;\n            }\n\n            if (data->AuditDisallowWin32kSystemCalls)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Win32k system calls (Audit)\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Win32k (GDI/USER) system calls will trigger an ETW event.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessExtensionPointDisablePolicy:\n        {\n            PPROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY data = Data;\n\n            if (data->DisableExtensionPoints)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Extension points disabled\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Legacy extension point DLLs cannot be loaded into the process. NOTE: Processes with uiAccess=true will automatically bypass this policy and inject legacy extension point DLLs regardless.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessControlFlowGuardPolicy:\n        {\n            PPROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY data = Data;\n\n            if (data->EnableControlFlowGuard)\n            {\n                if (ShortDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 50);\n                    if (data->StrictMode) PhAppendStringBuilder2(&sb, L\"Strict \");\n\n#if !defined(NTDDI_WIN10_CO) || (NTDDI_VERSION < NTDDI_WIN10_CO)\n                    if (_bittest((const PLONG)&data->Flags, 4))\n#else\n                    if (data->EnableXfgAuditMode)\n#endif\n                        PhAppendStringBuilder2(&sb, L\"Audit \");\n\n                #if !defined(NTDDI_WIN10_CO) || (NTDDI_VERSION < NTDDI_WIN10_CO)\n                    PhAppendStringBuilder2(&sb, _bittest((const PLONG)&data->Flags, 3) ? L\"XF Guard\" : L\"CF Guard\");\n                #else\n                    PhAppendStringBuilder2(&sb, data->EnableXfg ? L\"XF Guard\" : L\"CF Guard\");\n                #endif\n\n                    *ShortDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                if (LongDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 100);\n\n                #if !defined(NTDDI_WIN10_CO) || (NTDDI_VERSION < NTDDI_WIN10_CO)\n                    if (_bittest((const PLONG)&data->Flags, 3))\n                #else\n                    if (data->EnableXfg)\n                #endif\n                    {\n                        PhAppendStringBuilder2(&sb, L\"Extended Control Flow Guard (XFG) is enabled for the process.\\r\\n\");\n\n                        if (data->EnableXfgAuditMode) PhAppendStringBuilder2(&sb, L\"Audit XFG : XFG is running in audit mode.\\r\\n\");\n                        if (data->StrictMode) PhAppendStringBuilder2(&sb, L\"Strict XFG : only XFG modules can be loaded.\\r\\n\");\n                        if (data->EnableExportSuppression) PhAppendStringBuilder2(&sb, L\"Dll Exports can be marked as XFG invalid targets.\\r\\n\");\n                    }\n                    else\n                    {\n                        PhAppendStringBuilder2(&sb, L\"Control Flow Guard (CFG) is enabled for the process.\\r\\n\");\n\n                        if (data->StrictMode) PhAppendStringBuilder2(&sb, L\"Strict CFG : only CFG modules can be loaded.\\r\\n\");\n                        if (data->EnableExportSuppression) PhAppendStringBuilder2(&sb, L\"Dll Exports can be marked as CFG invalid targets.\\r\\n\");\n                    }\n\n                    *LongDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessSignaturePolicy:\n        {\n            PPROCESS_MITIGATION_BINARY_SIGNATURE_POLICY data = Data;\n\n            if (data->MicrosoftSignedOnly || data->StoreSignedOnly)\n            {\n                if (ShortDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 50);\n                    PhAppendStringBuilder2(&sb, L\"Signatures restricted (\");\n                    if (data->MicrosoftSignedOnly) PhAppendStringBuilder2(&sb, L\"Microsoft only, \");\n                    if (data->StoreSignedOnly) PhAppendStringBuilder2(&sb, L\"Store only, \");\n                    if (PhEndsWithStringRef2(&sb.String->sr, L\", \", FALSE)) PhRemoveEndStringBuilder(&sb, 2);\n                    PhAppendCharStringBuilder(&sb, L')');\n\n                    *ShortDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                if (LongDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 100);\n                    PhAppendStringBuilder2(&sb, L\"Image signature restrictions are enabled for this process.\\r\\n\");\n                    if (data->MicrosoftSignedOnly) PhAppendStringBuilder2(&sb, L\"Only Microsoft signatures are allowed.\\r\\n\");\n                    if (data->StoreSignedOnly) PhAppendStringBuilder2(&sb, L\"Only Windows Store signatures are allowed.\\r\\n\");\n                    if (data->MitigationOptIn) PhAppendStringBuilder2(&sb, L\"This is an opt-in restriction.\\r\\n\");\n                    *LongDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessFontDisablePolicy:\n        {\n            PPROCESS_MITIGATION_FONT_DISABLE_POLICY data = Data;\n\n            if (data->DisableNonSystemFonts)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Non-system fonts disabled\");\n\n                if (LongDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 100);\n                    PhAppendStringBuilder2(&sb, L\"Non-system fonts cannot be used in this process.\\r\\n\");\n                    if (data->AuditNonSystemFontLoading) PhAppendStringBuilder2(&sb, L\"Loading a non-system font in this process will trigger an ETW event.\\r\\n\");\n                    *LongDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessImageLoadPolicy:\n        {\n            PPROCESS_MITIGATION_IMAGE_LOAD_POLICY data = Data;\n\n            if (data->NoRemoteImages || data->NoLowMandatoryLabelImages)\n            {\n                if (ShortDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 50);\n                    PhAppendStringBuilder2(&sb, L\"Images restricted (\");\n                    if (data->NoRemoteImages) PhAppendStringBuilder2(&sb, L\"remote images, \");\n                    if (data->NoLowMandatoryLabelImages) PhAppendStringBuilder2(&sb, L\"low mandatory label images, \");\n                    if (PhEndsWithStringRef2(&sb.String->sr, L\", \", FALSE)) PhRemoveEndStringBuilder(&sb, 2);\n                    PhAppendCharStringBuilder(&sb, L')');\n\n                    *ShortDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                if (LongDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 50);\n                    if (data->NoRemoteImages) PhAppendStringBuilder2(&sb, L\"Remotely located images cannot be loaded into the process.\\r\\n\");\n                    if (data->NoLowMandatoryLabelImages) PhAppendStringBuilder2(&sb, L\"Images with a Low mandatory label cannot be loaded into the process.\\r\\n\");\n\n                    *LongDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                result = TRUE;\n            }\n\n            if (data->PreferSystem32Images)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Prefer system32 images\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Forces images to load from the System32 folder in which Windows is installed first, then from the application directory before the standard DLL search order.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessSystemCallFilterPolicy:\n        {\n            PPROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY data = Data;\n\n            if (data->FilterId)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"System call filtering\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"System call filtering is active.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessPayloadRestrictionPolicy:\n        {\n            PPROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY data = Data;\n\n            if (data->EnableExportAddressFilter || data->EnableExportAddressFilterPlus ||\n                data->EnableImportAddressFilter || data->EnableRopStackPivot ||\n                data->EnableRopCallerCheck || data->EnableRopSimExec)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Payload restrictions\");\n\n                if (LongDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 100);\n                    PhAppendStringBuilder2(&sb, L\"Payload restrictions are enabled for this process.\\r\\n\");\n                    if (data->EnableExportAddressFilter) PhAppendStringBuilder2(&sb, L\"Export Address Filtering is enabled.\\r\\n\");\n                    if (data->EnableExportAddressFilterPlus) PhAppendStringBuilder2(&sb, L\"Export Address Filtering (Plus) is enabled.\\r\\n\");\n                    if (data->EnableImportAddressFilter) PhAppendStringBuilder2(&sb, L\"Import Address Filtering is enabled.\\r\\n\");\n                    if (data->EnableRopStackPivot) PhAppendStringBuilder2(&sb, L\"StackPivot is enabled.\\r\\n\");\n                    if (data->EnableRopCallerCheck) PhAppendStringBuilder2(&sb, L\"CallerCheck is enabled.\\r\\n\");\n                    if (data->EnableRopSimExec) PhAppendStringBuilder2(&sb, L\"SimExec is enabled.\\r\\n\");\n                    *LongDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessChildProcessPolicy:\n        {\n            PPROCESS_MITIGATION_CHILD_PROCESS_POLICY data = Data;\n\n            if (data->NoChildProcessCreation)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Child process creation disabled\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Child processes cannot be created by this process.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessSideChannelIsolationPolicy:\n        {\n            PPROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY data = Data;\n\n            if (data->SmtBranchTargetIsolation)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"SMT-thread branch target isolation\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Branch target pollution cross-SMT-thread in user mode is enabled.\\r\\n\");\n\n                result = TRUE;\n            }\n\n            if (data->IsolateSecurityDomain)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Distinct security domain\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Isolated security domain is enabled.\\r\\n\");\n\n                result = TRUE;\n            }\n\n            if (data->DisablePageCombine)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Restricted page combining\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Disables all page combining for this process.\\r\\n\");\n\n                result = TRUE;\n            }\n\n            if (data->SpeculativeStoreBypassDisable)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Memory disambiguation (SSBD)\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Memory disambiguation is enabled for this process.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessUserShadowStackPolicy:\n        {\n            PPROCESS_MITIGATION_USER_SHADOW_STACK_POLICY data = Data;\n\n            if (data->EnableUserShadowStack || data->AuditUserShadowStack)\n            {\n                if (ShortDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 50);\n\n                    if (data->AuditUserShadowStack)\n                        PhAppendStringBuilder2(&sb, L\"Audit \");\n\n                    if (data->EnableUserShadowStackStrictMode)\n                        PhAppendStringBuilder2(&sb, L\"Strict \");\n\n                    PhAppendStringBuilder2(&sb, L\"Stack protection\");\n\n                    *ShortDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                if (LongDescription)\n                {\n                    PhInitializeStringBuilder(&sb, 100);\n\n                    PhAppendStringBuilder2(&sb, L\"The CPU verifies function return addresses at runtime by employing a hardware-enforced shadow stack.\\r\\n\");\n\n                    if (data->AuditUserShadowStack)\n                        PhAppendStringBuilder2(&sb, L\"Audit Stack protection : log ROP failures to event log.\\r\\n\");\n\n                    if (data->EnableUserShadowStackStrictMode)\n                        PhAppendStringBuilder2(&sb, L\"Strict Stack protection : any detected ROP will cause the process to terminate.\\r\\n\");\n\n                    if (data->AuditSetContextIpValidation)\n                        PhAppendStringBuilder2(&sb, L\"Audit Set Context IP validation : log modifications of context IP to event log.\\r\\n\");\n\n                    if (data->SetContextIpValidation)\n                        PhAppendStringBuilder2(&sb, L\"Set Context IP validation : any detected modification of context IP will cause the process to terminate.\\r\\n\");\n\n                    if (data->AuditBlockNonCetBinaries)\n                        PhAppendStringBuilder2(&sb, L\"Audit Block non CET binaries : log attempts to load binaries without CET support.\\r\\n\");\n\n                    if (data->BlockNonCetBinaries)\n                        PhAppendStringBuilder2(&sb, L\"Block binaries without CET support\\r\\n\");\n\n                    if (data->BlockNonCetBinariesNonEhcont)\n                        PhAppendStringBuilder2(&sb, L\"Block binaries without CET support or without EH continuation metadata.\\r\\n\");\n\n                    *LongDescription = PhFinalStringBuilderString(&sb);\n                }\n\n                result = TRUE;\n            }\n        }\n        break;\ncase ProcessRedirectionTrustPolicy:\n{\n    PPROCESS_MITIGATION_REDIRECTION_TRUST_POLICY data = Data;\n\n    // Ensure data is not NULL\n    if (data)\n    {\n        // Handle Enforce Redirection Trust Policy\n        if (data->EnforceRedirectionTrust && data->AuditRedirectionTrust)\n        {\n            if (ShortDescription)\n                *ShortDescription = PhCreateString(L\"Junction redirection protection / Audit\");\n\n            if (LongDescription)\n                *LongDescription = PhCreateString(L\"Prevents the process from following filesystem junctions created by non-admin users and logs the attempt.\\r\\nLogs attempts by the process to follow filesystem junctions created by non-admin users.\\r\\n\");\n\n            result = TRUE;\n        }\n        else if (data->EnforceRedirectionTrust)\n        {\n            if (ShortDescription)\n                *ShortDescription = PhCreateString(L\"Junction redirection protection\");\n\n            if (LongDescription)\n                *LongDescription = PhCreateString(L\"Prevents the process from following filesystem junctions created by non-admin users and logs the attempt.\\r\\n\");\n\n            result = TRUE;\n        }\n        else if (data->AuditRedirectionTrust)\n        {\n            if (ShortDescription)\n                *ShortDescription = PhCreateString(L\"Junction redirection protection (Audit)\");\n\n            if (LongDescription)\n                *LongDescription = PhCreateString(L\"Logs attempts by the process to follow filesystem junctions created by non-admin users.\\r\\n\");\n\n            result = TRUE;\n        }\n    }\n}\nbreak;\n    case ProcessUserPointerAuthPolicy:\n        {\n            PPROCESS_MITIGATION_USER_POINTER_AUTH_POLICY data = Data;\n\n            if (data->EnablePointerAuthUserIp)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"ARM pointer authentication\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"Pointer authentication (PAC) prevents unexpected changes to pointers.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    case ProcessSEHOPPolicy:\n        {\n            PPROCESS_MITIGATION_SEHOP_POLICY data = Data;\n\n            if (data->EnableSehop)\n            {\n                if (ShortDescription)\n                    *ShortDescription = PhCreateString(L\"Structured exception handling overwrite protection (SEHOP)\");\n\n                if (LongDescription)\n                    *LongDescription = PhCreateString(L\"SEHOP prevents Structured Exception Handler (SEH) overwrites.\\r\\n\");\n\n                result = TRUE;\n            }\n        }\n        break;\n    default:\n        result = FALSE;\n    }\n\n    return result;\n}\n"
  },
  {
    "path": "SystemInformer/procprp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2016-2026\n *\n */\n\n#include <phapp.h>\n#include <procprp.h>\n#include <procprpp.h>\n#include <proctree.h>\n\n#include <mapldr.h>\n#include <kphuser.h>\n#include <settings.h>\n#include <secedit.h>\n#include <emenu.h>\n\n#include <actions.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <procprv.h>\n#include <mainwnd.h>\n#include <mainwndp.h>\n\nPPH_OBJECT_TYPE PhpProcessPropContextType = NULL;\nPPH_OBJECT_TYPE PhpProcessPropPageContextType = NULL;\nPPH_OBJECT_TYPE PhpProcessPropPageWaitContextType = NULL;\nPH_STRINGREF PhProcessPropPageLoadingText = PH_STRINGREF_INIT(L\"Loading...\");\nstatic RECT MinimumSize = { -1, -1, -1, -1 };\nSLIST_HEADER WaitContextQueryListHead;\n\nPPH_PROCESS_PROPCONTEXT PhCreateProcessPropContext(\n    _In_opt_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_PROCESS_PROPCONTEXT propContext;\n    PROPSHEETHEADER propSheetHeader;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhpProcessPropContextType = PhCreateObjectType(L\"ProcessPropContext\", 0, PhpProcessPropContextDeleteProcedure);\n        PhpProcessPropPageContextType = PhCreateObjectType(L\"ProcessPropPageContext\", 0, PhpProcessPropPageContextDeleteProcedure);\n        PhpProcessPropPageWaitContextType = PhCreateObjectType(L\"ProcessPropPageWaitContext\", 0, PhpProcessPropPageWaitContextDeleteProcedure);\n        PhInitializeSListHead(&WaitContextQueryListHead);\n        PhEndInitOnce(&initOnce);\n    }\n\n    propContext = PhCreateObjectZero(sizeof(PH_PROCESS_PROPCONTEXT), PhpProcessPropContextType);\n    propContext->PropSheetPages = PhAllocateZero(sizeof(HPROPSHEETPAGE) * PH_PROCESS_PROPCONTEXT_MAXPAGES);\n\n    if (!PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId))\n    {\n        PH_FORMAT format[4];\n\n        PhInitFormatSR(&format[0], ProcessItem->ProcessName->sr);\n        PhInitFormatS(&format[1], L\" (\");\n        PhInitFormatU(&format[2], HandleToUlong(ProcessItem->ProcessId));\n        PhInitFormatC(&format[3], L')');\n\n        propContext->Title = PhFormat(format, RTL_NUMBER_OF(format), 64);\n    }\n    else\n    {\n        PhSetReference(&propContext->Title, ProcessItem->ProcessName);\n    }\n\n    memset(&propSheetHeader, 0, sizeof(PROPSHEETHEADER));\n    propSheetHeader.dwSize = sizeof(PROPSHEETHEADER);\n    propSheetHeader.dwFlags =\n        PSH_MODELESS |\n        PSH_NOAPPLYNOW |\n        PSH_NOCONTEXTHELP |\n        PSH_PROPTITLE |\n        PSH_USECALLBACK |\n        PSH_USEHICON;\n    propSheetHeader.hInstance = PhInstanceHandle;\n    propSheetHeader.hwndParent = ParentWindowHandle;\n    propSheetHeader.hIcon = PhGetImageListIcon(ProcessItem->SmallIconIndex, FALSE);\n    propSheetHeader.pszCaption = PhGetString(propContext->Title);\n    propSheetHeader.pfnCallback = PhpPropSheetProc;\n\n    propSheetHeader.nPages = 0;\n    propSheetHeader.nStartPage = 0;\n    propSheetHeader.phpage = propContext->PropSheetPages;\n\n    if (PhCsForceNoParent)\n        propSheetHeader.hwndParent = NULL;\n\n    memcpy(&propContext->PropSheetHeader, &propSheetHeader, sizeof(PROPSHEETHEADER));\n\n    PhSetReference(&propContext->ProcessItem, ProcessItem);\n\n    return propContext;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpProcessPropContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_PROCESS_PROPCONTEXT propContext = (PPH_PROCESS_PROPCONTEXT)Object;\n\n    PhFree(propContext->PropSheetPages);\n    PhDereferenceObject(propContext->Title);\n    PhDereferenceObject(propContext->ProcessItem);\n}\n\nVOID PhRefreshProcessPropContext(\n    _Inout_ PPH_PROCESS_PROPCONTEXT PropContext\n    )\n{\n    PropContext->PropSheetHeader.hIcon = PhGetImageListIcon(PropContext->ProcessItem->SmallIconIndex, FALSE);\n}\n\nVOID PhSetSelectThreadIdProcessPropContext(\n    _Inout_ PPH_PROCESS_PROPCONTEXT PropContext,\n    _In_ HANDLE ThreadId\n    )\n{\n    PropContext->SelectThreadId = ThreadId;\n}\n\nINT CALLBACK PhpPropSheetProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ LPARAM lParam\n    )\n{\n#define PROPSHEET_ADD_STYLE (WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME);\n\n    switch (uMsg)\n    {\n    case PSCB_PRECREATE:\n        {\n            if (lParam)\n            {\n                if (((DLGTEMPLATEEX *)lParam)->signature == USHRT_MAX)\n                {\n                    ((DLGTEMPLATEEX *)lParam)->style |= PROPSHEET_ADD_STYLE;\n                }\n                else\n                {\n                    ((DLGTEMPLATE *)lParam)->style |= PROPSHEET_ADD_STYLE;\n                }\n            }\n        }\n        break;\n    case PSCB_INITIALIZED:\n        {\n            PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;\n\n            propSheetContext = PhAllocate(sizeof(PH_PROCESS_PROPSHEETCONTEXT));\n            memset(propSheetContext, 0, sizeof(PH_PROCESS_PROPSHEETCONTEXT));\n\n            PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg);\n            PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, propSheetContext);\n\n            propSheetContext->PropSheetWindowHookProc = PhGetWindowProcedure(hwndDlg);\n            PhSetWindowContext(hwndDlg, 0xF, propSheetContext);\n            PhSetWindowProcedure(hwndDlg, PhpPropSheetWndProc);\n\n            if (PhEnableThemeSupport) // NOTE: Required for compatibility. (dmex)\n                PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n\n            PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL);\n\n            if (MinimumSize.left == -1)\n            {\n                RECT rect;\n\n                rect.left = 0;\n                rect.top = 0;\n                rect.right = 290;\n                rect.bottom = 320;\n                MapDialogRect(hwndDlg, &rect);\n                MinimumSize = rect;\n                MinimumSize.left = 0;\n            }\n\n            PhSetTimer(hwndDlg, 2000, 2000, NULL);\n        }\n        break;\n    }\n\n    return 0;\n}\n\nPPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext(\n    _In_ HWND WindowHandle\n    )\n{\n    return PhGetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n}\n\nLRESULT CALLBACK PhpPropSheetWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;\n    WNDPROC oldWndProc;\n\n    propSheetContext = PhGetWindowContext(WindowHandle, 0xF);\n\n    if (!propSheetContext)\n        return 0;\n\n    oldWndProc = propSheetContext->PropSheetWindowHookProc;\n\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            HWND tabControl;\n            TCITEM tabItem;\n            WCHAR text[128] = L\"\";\n\n            PhKillTimer(WindowHandle, 2000);\n\n            // Save the window position and size.\n\n            PhSaveWindowPlacementToSetting(SETTING_PROC_PROP_POSITION, SETTING_PROC_PROP_SIZE, WindowHandle);\n\n            // Save the selected tab.\n\n            tabControl = PropSheet_GetTabControl(WindowHandle);\n\n            tabItem.mask = TCIF_TEXT;\n            tabItem.pszText = text;\n            tabItem.cchTextMax = RTL_NUMBER_OF(text) - 1;\n\n            if (TabCtrl_GetItem(tabControl, TabCtrl_GetCurSel(tabControl), &tabItem))\n            {\n                PhSetStringSetting(SETTING_PROC_PROP_PAGE, text);\n            }\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            PhUnregisterWindowCallback(WindowHandle);\n\n            PhSetWindowProcedure(WindowHandle, oldWndProc);\n            PhRemoveWindowContext(WindowHandle, 0xF);\n\n            PhDeleteLayoutManager(&propSheetContext->LayoutManager);\n            PhRemoveWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhFree(propSheetContext);\n        }\n        break;\n    case WM_SYSCOMMAND:\n        {\n            // Note: Clicking the X on the taskbar window thumbnail preview doesn't close modeless property sheets\n            // when there are more than 1 window and the window doesn't have focus. (dmex)\n            switch (wParam & 0xFFF0)\n            {\n            case SC_CLOSE:\n                {\n                    PostQuitMessage(0);\n                    //SetWindowLongPtr(WindowHandle, DWLP_MSGRESULT, TRUE);\n                    //return TRUE;\n                }\n                break;\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDOK:\n                // Prevent the OK button from working (even though\n                // it's already hidden). This prevents the Enter\n                // key from closing the dialog box.\n                return 0;\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            if (!IsMinimized(WindowHandle))\n            {\n                PhLayoutManagerLayout(&propSheetContext->LayoutManager);\n            }\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);\n        }\n        break;\n    case WM_TIMER:\n        {\n            UINT id = (UINT)wParam;\n\n            if (id == 2000)\n            {\n                PhpFlushProcessPropSheetWaitContextData();\n            }\n        }\n        break;\n    case PSM_ISDIALOGMESSAGE:\n        {\n            PMSG dialog = (PMSG)lParam;\n\n            if (dialog->message == WM_KEYDOWN)\n            {\n                switch (dialog->wParam)\n                {\n                case VK_F5:\n                    SystemInformer_Refresh();\n                    break;\n                case VK_F6:\n                case VK_PAUSE:\n                    SystemInformer_SetUpdateAutomatically(!SystemInformer_GetUpdateAutomatically());\n                    break;\n                }\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            USHORT newDpi = HIWORD(wParam);\n            PRECT CONST newRect = (PRECT)lParam;\n\n            CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n\n            PhLayoutManagerUpdate(&propSheetContext->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&propSheetContext->LayoutManager);\n\n            {\n                SetWindowPos(\n                    WindowHandle,\n                    NULL,\n                    newRect->left,\n                    newRect->top,\n                    newRect->right - newRect->left,\n                    newRect->bottom - newRect->top,\n                    SWP_NOZORDER | SWP_NOACTIVATE\n                    );\n            }\n\n            {\n                RECT rect;\n\n                rect.left = 0;\n                rect.top = 0;\n                rect.right = 290;\n                rect.bottom = 320;\n                MapDialogRect(WindowHandle, &rect);\n                MinimumSize = rect;\n                MinimumSize.left = 0;\n            }\n\n            return 0;\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n}\n\n_Function_class_(PH_OPEN_OBJECT)\nNTSTATUS PhOptionsButtonGeneralOpenProcess(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Context)\n    {\n        return PhOpenProcess(Handle, DesiredAccess, (HANDLE)Context);\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n_Function_class_(PH_CLOSE_OBJECT)\nNTSTATUS PhOptionsButtonGeneralCloseHandle(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle)\n    {\n        NtClose(Handle);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nLRESULT CALLBACK PhpOptionsButtonWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;\n    WNDPROC oldWndProc;\n\n    if (!(propSheetContext = PhGetWindowContext(WindowHandle, SCHAR_MAX)))\n        return DefWindowProc(WindowHandle, uMsg, wParam, lParam);\n\n    oldWndProc = propSheetContext->OldOptionsButtonWndProc;\n\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, SCHAR_MAX);\n            PhSetWindowProcedure(WindowHandle, oldWndProc);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            if (GET_WM_COMMAND_HWND(wParam, lParam) == propSheetContext->OptionsButtonWindowHandle)\n            {\n                RECT rect;\n                PPH_EMENU menu;\n                PPH_EMENU_ITEM selectedItem;\n                PPH_EMENU_ITEM menuItem;\n                HWND pageWindow;\n                LPPROPSHEETPAGE propSheetPage;\n                PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n                PPH_PROCESS_PROPCONTEXT propContext;\n\n                if (!(pageWindow = PropSheet_GetCurrentPageHwnd(WindowHandle)))\n                    break;\n                if (!(propSheetPage = PhGetWindowContext(pageWindow, PH_WINDOW_CONTEXT_DEFAULT)))\n                    break;\n                if (!(propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam))\n                    break;\n                if (!(propContext = propPageContext->PropContext))\n                    break;\n                if (!PhGetWindowRect(propSheetContext->OptionsButtonWindowHandle, &rect))\n                    break;\n\n                menu = PhCreateEMenu();\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATE, L\"T&erminate\\bDel\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATETREE, L\"Terminate tree\\bShift+Del\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPEND, L\"&Suspend\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPENDTREE, L\"Suspend tree\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_RESUME, L\"Res&ume\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_RESUMETREE, L\"Resume tree\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_FREEZE, L\"Freeze\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_THAW, L\"Thaw\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_RESTART, L\"Res&tart\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n\n                if (propContext->ProcessItem->ProcessId == SYSTEM_PROCESS_ID)\n                {\n                    PPH_EMENU_ITEM kernelMinimal;\n\n                    menuItem = PhCreateEMenuItem(0, ID_PROCESS_CREATEDUMPFILE, L\"Create live kernel dump fi&le\", NULL, NULL);\n                    PhInsertEMenuItem(menuItem, kernelMinimal = PhCreateEMenuItem(0, ID_PROCESS_DUMP_MINIMAL, L\"&Minimal...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_NORMAL, L\"&Normal...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_FULL, L\"&Full...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_CUSTOM, L\"&Custom...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n                    if (!PhGetOwnTokenAttributes().Elevated)\n                    {\n                        menuItem->Flags |= PH_EMENU_DISABLED;\n                    }\n                    else if (WindowsVersion < WINDOWS_11)\n                    {\n                        // Minimal only captures thread stacks, not supported before Windows 11\n                        PhSetDisabledEMenuItem(kernelMinimal);\n                    }\n                }\n                else\n                {\n                    menuItem = PhCreateEMenuItem(0, ID_PROCESS_CREATEDUMPFILE, L\"Create dump fi&le\", NULL, NULL);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_MINIMAL, L\"&Minimal...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_LIMITED, L\"&Limited...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_NORMAL, L\"&Normal...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_FULL, L\"&Full...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_DUMP_CUSTOM, L\"&Custom...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n                }\n\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_DEBUG, L\"De&bug\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_AFFINITY, L\"&Affinity\", NULL, NULL), ULONG_MAX);\n\n                menuItem = PhCreateEMenuItem(0, ID_PROCESS_PRIORITYCLASS, L\"&Priority\", NULL, NULL);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L\"&Real time\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L\"&High\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L\"&Above normal\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L\"&Normal\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L\"&Below normal\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L\"&Idle\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n                menuItem = PhCreateEMenuItem(0, ID_PROCESS_IOPRIORITY, L\"&I/O priority\", NULL, NULL);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L\"&High\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L\"&Normal\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L\"&Low\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L\"&Very low\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n                menuItem = PhCreateEMenuItem(0, ID_PROCESS_PAGEPRIORITY, L\"Pa&ge priority\", NULL, NULL);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_NORMAL, L\"&Normal\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_BELOWNORMAL, L\"&Below normal\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_MEDIUM, L\"&Medium\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_LOW, L\"&Low\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_VERYLOW, L\"&Very low\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n                menuItem = PhCreateEMenuItem(0, ID_PROCESS_MISCELLANEOUS, L\"&Miscellaneous\", NULL, NULL);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_ACTIVITY, L\"Activity moderation\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_SETCRITICAL, L\"&Critical\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_DETACHFROMDEBUGGER, L\"&Detach from debugger\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_ECOMODE, L\"Efficiency mode\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_EXECUTIONREQUIRED, L\"Execution required\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_GDIHANDLES, L\"GDI &handles...\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_HEAPS, L\"Heaps...\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_LOCKS, L\"Locks...\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_FLUSHHEAPS, L\"Flush heaps\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_PAGESMODIFIED, L\"Modified pages...\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_REDUCEWORKINGSET, L\"Reduce working &set\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_RUNAS, L\"&Run as...\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_MISCELLANEOUS_RUNASTHISUSER, L\"Run &as this user...\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PROCESS_VIRTUALIZATION, L\"Virtuali&zation\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n                PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_SEARCHONLINE, L\"Search &online\\bCtrl+M\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PROCESS_OPENFILELOCATION, L\"Open &file location\\bCtrl+Enter\", NULL, NULL), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_HANDLE_SECURITY, L\"Security\", NULL, NULL), ULONG_MAX);\n\n                PhMwpInitializeProcessMenu(menu, &propContext->ProcessItem, 1);\n\n                selectedItem = PhShowEMenu(\n                    menu,\n                    WindowHandle,\n                    PH_EMENU_SHOW_LEFTRIGHT,\n                    PH_ALIGN_LEFT | PH_ALIGN_BOTTOM,\n                    rect.left,\n                    rect.top\n                    );\n\n                if (selectedItem && selectedItem->Id)\n                {\n                    PPH_PROCESS_ITEM processItem = propContext->ProcessItem;\n                    \n                    PhReferenceObject(processItem);\n                    \n                    switch (selectedItem->Id)\n                    {\n                    case ID_PROCESS_TERMINATE:\n                        PhUiTerminateProcesses(WindowHandle, &processItem, 1);\n                        break;\n                    case ID_PROCESS_TERMINATETREE:\n                        PhUiTerminateTreeProcess(WindowHandle, processItem);\n                        break;\n                    case ID_PROCESS_SUSPEND:\n                        PhUiSuspendProcesses(WindowHandle, &processItem, 1);\n                        break;\n                    case ID_PROCESS_SUSPENDTREE:\n                        PhUiSuspendTreeProcess(WindowHandle, processItem);\n                        break;\n                    case ID_PROCESS_RESUME:\n                        PhUiResumeProcesses(WindowHandle, &processItem, 1);\n                        break;\n                    case ID_PROCESS_RESUMETREE:\n                        PhUiResumeTreeProcess(WindowHandle, processItem);\n                        break;\n                    case ID_PROCESS_FREEZE:\n                        PhUiFreezeTreeProcess(WindowHandle, processItem);\n                        break;\n                    case ID_PROCESS_THAW:\n                        PhUiThawTreeProcess(WindowHandle, processItem);\n                        break;\n                    case ID_PROCESS_RESTART:\n                        PhUiRestartProcess(WindowHandle, processItem);\n                        break;\n                    case ID_PROCESS_AFFINITY:\n                        PhShowProcessAffinityDialog(WindowHandle, processItem, NULL);\n                        break;\n                    case ID_PRIORITY_REALTIME:\n                    case ID_PRIORITY_HIGH:\n                    case ID_PRIORITY_ABOVENORMAL:\n                    case ID_PRIORITY_NORMAL:\n                    case ID_PRIORITY_BELOWNORMAL:\n                    case ID_PRIORITY_IDLE:\n                        PhMwpExecuteProcessPriorityClassCommand(WindowHandle, selectedItem->Id, &processItem, 1);\n                        break;\n                    case ID_IOPRIORITY_VERYLOW:\n                    case ID_IOPRIORITY_LOW:\n                    case ID_IOPRIORITY_NORMAL:\n                    case ID_IOPRIORITY_HIGH:\n                        PhMwpExecuteProcessIoPriorityCommand(WindowHandle, selectedItem->Id, &processItem, 1);\n                        break;\n                    case ID_PAGEPRIORITY_VERYLOW:\n                    case ID_PAGEPRIORITY_LOW:\n                    case ID_PAGEPRIORITY_MEDIUM:\n                    case ID_PAGEPRIORITY_BELOWNORMAL:\n                    case ID_PAGEPRIORITY_NORMAL:\n                        {\n                            ULONG pagePriority;\n\n                            switch (selectedItem->Id)\n                            {\n                            case ID_PAGEPRIORITY_VERYLOW:\n                                pagePriority = MEMORY_PRIORITY_VERY_LOW;\n                                break;\n                            case ID_PAGEPRIORITY_LOW:\n                                pagePriority = MEMORY_PRIORITY_LOW;\n                                break;\n                            case ID_PAGEPRIORITY_MEDIUM:\n                                pagePriority = MEMORY_PRIORITY_MEDIUM;\n                                break;\n                            case ID_PAGEPRIORITY_BELOWNORMAL:\n                                pagePriority = MEMORY_PRIORITY_BELOW_NORMAL;\n                                break;\n                            case ID_PAGEPRIORITY_NORMAL:\n                                pagePriority = MEMORY_PRIORITY_NORMAL;\n                                break;\n                            }\n\n                            PhUiSetPagePriorityProcess(WindowHandle, processItem, pagePriority);\n                        }\n                        break;\n                    case ID_MISCELLANEOUS_ACTIVITY:\n                        PhUiSetActivityModeration(WindowHandle, processItem);\n                        break;\n                    case ID_MISCELLANEOUS_SETCRITICAL:\n                        PhUiSetCriticalProcess(WindowHandle, processItem);\n                        break;\n                    case ID_MISCELLANEOUS_DETACHFROMDEBUGGER:\n                        PhUiDetachFromDebuggerProcess(WindowHandle, processItem);\n                        break;\n                    case ID_MISCELLANEOUS_ECOMODE:\n                        PhUiSetEcoModeProcess(WindowHandle, processItem);\n                        break;\n                    case ID_MISCELLANEOUS_EXECUTIONREQUIRED:\n                        PhUiSetExecutionRequiredProcess(WindowHandle, processItem);\n                        break;\n                    case ID_MISCELLANEOUS_GDIHANDLES:\n                        PhShowGdiHandlesDialog(WindowHandle, processItem);\n                        break;\n                    case ID_MISCELLANEOUS_HEAPS:\n                        PhShowProcessHeapsDialog(WindowHandle, processItem);\n                        break;\n                    case ID_MISCELLANEOUS_LOCKS:\n                        PhShowProcessLocksDialog(WindowHandle, processItem);\n                        break;\n                    case ID_MISCELLANEOUS_REDUCEWORKINGSET:\n                        PhUiReduceWorkingSetProcesses(WindowHandle, &processItem, 1);\n                        break;\n                    case ID_MISCELLANEOUS_RUNAS:\n                        PhShowRunAsDialog(WindowHandle, NULL);\n                        break;\n                    case ID_MISCELLANEOUS_RUNASTHISUSER:\n                        PhShowRunAsDialog(WindowHandle, processItem->ProcessId);\n                        break;\n                    case ID_MISCELLANEOUS_FLUSHHEAPS:\n                        PhUiFlushHeapProcesses(WindowHandle, &processItem, 1);\n                        break;\n                    case ID_PROCESS_DUMP_MINIMAL:\n                    case ID_PROCESS_DUMP_LIMITED:\n                    case ID_PROCESS_DUMP_NORMAL:\n                    case ID_PROCESS_DUMP_FULL:\n                    case ID_PROCESS_DUMP_CUSTOM:\n                        PhUiCreateDumpFileProcess(WindowHandle, processItem, selectedItem->Id);\n                        break;\n                    case ID_PROCESS_DEBUG:\n                        PhUiDebugProcess(WindowHandle, processItem);\n                        break;\n                    case ID_PROCESS_SEARCHONLINE:\n                        PhSearchOnlineString(WindowHandle, processItem->ProcessName->Buffer);\n                        break;\n                    case ID_PROCESS_OPENFILELOCATION:\n                        {\n                            NTSTATUS status;\n                            PPH_STRING fileName;\n\n                            status = PhGetProcessItemFileNameWin32(processItem, &fileName);\n\n                            if (NT_SUCCESS(status))\n                            {\n                                PhShellExecuteUserString(\n                                    WindowHandle,\n                                    SETTING_FILE_BROWSE_EXECUTABLE,\n                                    PhGetString(fileName),\n                                    FALSE,\n                                    L\"Make sure the Explorer executable file is present.\"\n                                    );\n\n                                PhDereferenceObject(fileName);\n                            }\n                            else\n                            {\n                                PhShowStatus(WindowHandle, L\"Unable to locate the file.\", status, 0);\n                            }\n                        }\n                        break;\n                    case ID_HANDLE_SECURITY:\n                        {\n                            PhEditSecurity(\n                                PhCsForceNoParent ? NULL : pageWindow,\n                                PhGetStringOrEmpty(propContext->ProcessItem->ProcessName),\n                                L\"Process\",\n                                PhOptionsButtonGeneralOpenProcess,\n                                PhOptionsButtonGeneralCloseHandle,\n                                propContext->ProcessItem->ProcessId\n                                );\n                        }\n                        break;\n                    }\n                    \n                    PhDereferenceObject(processItem);\n                }\n\n                PhDestroyEMenu(menu);\n            }\n            //else if (GET_WM_COMMAND_HWND(wParam, lParam) == propSheetContext->PermissionsButtonWindowHandle)\n            //{\n            //    HWND pageWindow;\n            //    LPPROPSHEETPAGE propSheetPage;\n            //    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n            //    PPH_PROCESS_PROPCONTEXT propContext;\n            //\n            //    if (!(pageWindow = PropSheet_GetCurrentPageHwnd(WindowHandle)))\n            //        break;\n            //    if (!(propSheetPage = PhGetWindowContext(pageWindow, PH_WINDOW_CONTEXT_DEFAULT)))\n            //        break;\n            //    if (!(propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam))\n            //        break;\n            //    if (!(propContext = propPageContext->PropContext))\n            //        break;\n            //\n            //    NOTHING;\n            //}\n        }\n        break;\n    case WM_PH_UPDATE_DIALOG:\n        {\n            if (propSheetContext->ButtonsLabelWindowHandle)\n            {\n                static CONST PH_STRINGREF text = PH_STRINGREF_INIT(L\"Protection\");\n                static CONST PH_STRINGREF seperator = PH_STRINGREF_INIT(L\": \");\n                static CONST PH_STRINGREF natext = PH_STRINGREF_INIT(L\"N/A\");\n                HWND pageWindow;\n                LPPROPSHEETPAGE propSheetPage;\n                PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n                PPH_PROCESS_PROPCONTEXT propContext;\n\n                if (!(pageWindow = PropSheet_GetCurrentPageHwnd(WindowHandle)))\n                    break;\n                if (!(propSheetPage = PhGetWindowContext(pageWindow, PH_WINDOW_CONTEXT_DEFAULT)))\n                    break;\n                if (!(propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam))\n                    break;\n                if (!(propContext = propPageContext->PropContext))\n                    break;\n\n                PPH_STRING string = PhGetProcessProtectionString(propContext->ProcessItem->Protection, (BOOLEAN)propContext->ProcessItem->IsSecureProcess);\n\n                if (string)\n                {\n                    PhMoveReference(&string, PhConcatStringRef3(&text, &seperator, &string->sr));\n                }\n                else\n                {\n                    PhMoveReference(&string, PhConcatStringRef3(&text, &seperator, &natext));\n                }\n\n                PhSetWindowText(propSheetContext->ButtonsLabelWindowHandle, string->Buffer);\n                PhClearReference(&string);\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n}\n\nVOID PhpCreateProcessPropButtons(\n    _In_ PPH_PROCESS_PROPSHEETCONTEXT PropSheetContext,\n    _In_ HWND PropSheetWindow\n    )\n{\n    if (!PropSheetContext->OptionsButtonWindowHandle)\n    {\n        RECT clientRect;\n        RECT rect;\n        LONG buttonWidth;\n        LONG buttonHeight;\n        LONG buttonSpacing = 6;\n        LONG labelWidth = 250;\n        HFONT windowFont;\n\n        windowFont = GetWindowFont(GetDlgItem(PropSheetWindow, IDCANCEL));\n\n        PropSheetContext->OldOptionsButtonWndProc = PhGetWindowProcedure(PropSheetWindow);\n        PhSetWindowContext(PropSheetWindow, SCHAR_MAX, PropSheetContext);\n        PhSetWindowProcedure(PropSheetWindow, PhpOptionsButtonWndProc);\n\n        PhGetClientRect(PropSheetWindow, &clientRect);\n        PhGetWindowRect(GetDlgItem(PropSheetWindow, IDCANCEL), &rect);\n        MapWindowRect(NULL, PropSheetWindow, &rect);\n\n        buttonWidth = rect.right - rect.left;\n        buttonHeight = rect.bottom - rect.top;\n\n        // Create the Options button\n        PropSheetContext->OptionsButtonWindowHandle = CreateWindowEx(\n            WS_EX_NOPARENTNOTIFY,\n            WC_BUTTON,\n            L\"Options\",\n            WS_CHILD | WS_VISIBLE | WS_TABSTOP,\n            clientRect.right - rect.right,\n            rect.top,\n            buttonWidth,\n            buttonHeight,\n            PropSheetWindow,\n            NULL,\n            PhInstanceHandle,\n            NULL\n            );\n        SetWindowFont(PropSheetContext->OptionsButtonWindowHandle, windowFont, TRUE);\n\n        // Create the Permissions button\n        //PropSheetContext->PermissionsButtonWindowHandle = CreateWindowEx(\n        //    WS_EX_NOPARENTNOTIFY,\n        //    WC_BUTTON,\n        //    L\"Permissions\",\n        //    WS_CHILD | WS_VISIBLE | WS_TABSTOP,\n        //    clientRect.right - rect.right + buttonWidth + buttonSpacing,\n        //    rect.top,\n        //    buttonWidth,\n        //    buttonHeight,\n        //    PropSheetWindow,\n        //    NULL,\n        //    PhInstanceHandle,\n        //    NULL\n        //    );\n        //SetWindowFont(PropSheetContext->PermissionsButtonWindowHandle, windowFont, TRUE);\n\n        // Create the label\n        PropSheetContext->ButtonsLabelWindowHandle = CreateWindowEx(\n            WS_EX_NOPARENTNOTIFY,\n            WC_STATIC,\n            L\"Protection\",\n            WS_CHILD | WS_VISIBLE | SS_LEFT,\n            clientRect.right - rect.right + (buttonWidth + buttonSpacing) + 5,\n            rect.top + 7,\n            labelWidth,\n            buttonHeight,\n            PropSheetWindow,\n            NULL,\n            PhInstanceHandle,\n            NULL\n            );\n        SetWindowFont(PropSheetContext->ButtonsLabelWindowHandle, windowFont, TRUE);\n\n        PostMessage(PropSheetWindow, WM_PH_UPDATE_DIALOG, 0, 0);\n    }\n}\n\nBOOLEAN PhpInitializePropSheetLayoutStage1(\n    _In_ PPH_PROCESS_PROPSHEETCONTEXT Context,\n    _In_ HWND WindowHandle\n    )\n{\n    if (!Context->LayoutInitialized)\n    {\n        HWND tabControlHandle;\n        PPH_LAYOUT_ITEM tabControlItem;\n        PPH_LAYOUT_ITEM tabPageItem;\n\n        tabControlHandle = PropSheet_GetTabControl(WindowHandle);\n        tabControlItem = PhAddLayoutItem(&Context->LayoutManager, tabControlHandle, NULL, PH_ANCHOR_ALL | PH_LAYOUT_IMMEDIATE_RESIZE);\n        tabPageItem = PhAddLayoutItem(&Context->LayoutManager, tabControlHandle, NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control\n        PhAddLayoutItem(&Context->LayoutManager, GetDlgItem(WindowHandle, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n        // Create and add the buttons to the layout\n        PhpCreateProcessPropButtons(Context, WindowHandle);\n        PhAddLayoutItem(&Context->LayoutManager, Context->OptionsButtonWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n        PhAddLayoutItem(&Context->LayoutManager, Context->ButtonsLabelWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n        //PhAddLayoutItem(&Context->LayoutManager, Context->PermissionsButtonWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n\n        // Hide the OK button.\n        ShowWindow(GetDlgItem(WindowHandle, IDOK), SW_HIDE);\n        // Set the Cancel button's text to \"Close\".\n        PhSetDialogItemText(WindowHandle, IDCANCEL, L\"Close\");\n\n        Context->TabPageItem = tabPageItem;\n        Context->LayoutInitialized = TRUE;\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpInitializePropSheetLayoutStage2(\n    _In_ HWND WindowHandle\n    )\n{\n    PH_RECTANGLE windowRectangle = {0};\n    RECT rect;\n    LONG dpiValue;\n\n    PhLoadWindowPlacementFromSetting(SETTING_PROC_PROP_POSITION, SETTING_PROC_PROP_SIZE, WindowHandle);\n\n    windowRectangle.Position = PhGetIntegerPairSetting(SETTING_PROC_PROP_POSITION);\n    PhRectangleToRect(&rect, &windowRectangle);\n    dpiValue = PhGetMonitorDpi(NULL, &rect);\n    windowRectangle.Size = PhGetScalableIntegerPairSetting(SETTING_PROC_PROP_SIZE, TRUE, dpiValue)->Pair;\n\n    if (windowRectangle.Size.X < MinimumSize.right)\n        windowRectangle.Size.X = MinimumSize.right;\n    if (windowRectangle.Size.Y < MinimumSize.bottom)\n        windowRectangle.Size.Y = MinimumSize.bottom;\n\n    PhAdjustRectangleToWorkingArea(NULL, &windowRectangle);\n\n    // Implement cascading by saving an offsetted rectangle.\n    windowRectangle.Left += 20;\n    windowRectangle.Top += 20;\n    PhSetIntegerPairSetting(SETTING_PROC_PROP_POSITION, windowRectangle.Position);\n}\n\nBOOLEAN PhAddProcessPropPage(\n    _Inout_ PPH_PROCESS_PROPCONTEXT PropContext,\n    _In_ _Assume_refs_(1) PPH_PROCESS_PROPPAGECONTEXT PropPageContext\n    )\n{\n    HPROPSHEETPAGE propSheetPageHandle;\n\n    if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES)\n        return FALSE;\n\n    propSheetPageHandle = CreatePropertySheetPage(\n        &PropPageContext->PropSheetPage\n        );\n    // CreatePropertySheetPage would have sent PSPCB_ADDREF,\n    // which would have added a reference.\n    PhDereferenceObject(PropPageContext);\n\n    PhSetReference(&PropPageContext->PropContext, PropContext);\n\n    PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = propSheetPageHandle;\n    PropContext->PropSheetHeader.nPages++;\n\n    return TRUE;\n}\n\nBOOLEAN PhAddProcessPropPage2(\n    _Inout_ PPH_PROCESS_PROPCONTEXT PropContext,\n    _In_ HPROPSHEETPAGE PropSheetPageHandle\n    )\n{\n    if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES)\n        return FALSE;\n\n    PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = PropSheetPageHandle;\n    PropContext->PropSheetHeader.nPages++;\n\n    return TRUE;\n}\n\nPPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContext(\n    _In_ LPCWSTR Template,\n    _In_ DLGPROC DlgProc,\n    _In_opt_ PVOID Context\n    )\n{\n    return PhCreateProcessPropPageContextEx(PhInstanceHandle, Template, DlgProc, Context);\n}\n\nPPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContextEx(\n    _In_opt_ PVOID InstanceHandle,\n    _In_ LPCWSTR Template,\n    _In_ DLGPROC DlgProc,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n\n    propPageContext = PhCreateObjectZero(sizeof(PH_PROCESS_PROPPAGECONTEXT), PhpProcessPropPageContextType);\n    propPageContext->PropSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propPageContext->PropSheetPage.dwFlags = PSP_USECALLBACK;\n    propPageContext->PropSheetPage.hInstance = InstanceHandle;\n    propPageContext->PropSheetPage.pszTemplate = Template;\n    propPageContext->PropSheetPage.pfnDlgProc = DlgProc;\n    propPageContext->PropSheetPage.lParam = (LPARAM)propPageContext;\n    propPageContext->PropSheetPage.pfnCallback = PhpStandardPropPageProc;\n\n    propPageContext->Context = Context;\n\n    return propPageContext;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpProcessPropPageContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)Object;\n\n    if (propPageContext->PropContext)\n        PhDereferenceObject(propPageContext->PropContext);\n}\n\nUINT CALLBACK PhpStandardPropPageProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ LPPROPSHEETPAGE ppsp\n    )\n{\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n\n    propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)ppsp->lParam;\n\n    if (uMsg == PSPCB_ADDREF)\n        PhReferenceObject(propPageContext);\n    else if (uMsg == PSPCB_RELEASE)\n        PhDereferenceObject(propPageContext);\n\n    return 1;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpProcessPropPageWaitContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_PROCESS_WAITPROPCONTEXT context = (PPH_PROCESS_WAITPROPCONTEXT)Object;\n\n    PhpFlushProcessPropSheetWaitContextData();\n\n    if (context->ProcessWaitHandle)\n    {\n        RtlDeregisterWaitEx(context->ProcessWaitHandle, RTL_WAITER_DEREGISTER_WAIT_FOR_COMPLETION);\n        context->ProcessWaitHandle = NULL;\n    }\n\n    if (context->ProcessHandle)\n    {\n        NtClose(context->ProcessHandle);\n        context->ProcessHandle = NULL;\n    }\n\n    if (context->ProcessItem)\n    {\n        PhDereferenceObject(context->ProcessItem);\n        context->ProcessItem = NULL;\n    }\n}\n\nVOID PhpCreateProcessPropSheetWaitContext(\n    _In_ PPH_PROCESS_PROPCONTEXT PropContext,\n    _In_ HWND WindowHandle\n    )\n{\n    PPH_PROCESS_ITEM processItem = PropContext->ProcessItem;\n    PPH_PROCESS_WAITPROPCONTEXT waitContext;\n    HANDLE processHandle;\n\n    if (!processItem->QueryHandle || processItem->ProcessId == NtCurrentProcessId())\n        return;\n\n    if (!NT_SUCCESS(PhOpenProcess(\n        &processHandle,\n        SYNCHRONIZE,\n        processItem->ProcessId\n        )))\n    {\n        return;\n    }\n\n    waitContext = PhCreateObjectZero(sizeof(PH_PROCESS_WAITPROPCONTEXT), PhpProcessPropPageWaitContextType);\n    waitContext->ProcessItem = PhReferenceObject(processItem);\n    waitContext->PropSheetWindowHandle = GetParent(WindowHandle);\n    waitContext->ProcessHandle = processHandle;\n\n    if (NT_SUCCESS(RtlRegisterWait(\n        &waitContext->ProcessWaitHandle,\n        processHandle,\n        PhpProcessPropertiesWaitCallback,\n        waitContext,\n        INFINITE,\n        WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD\n        )))\n    {\n        PropContext->ProcessWaitContext = waitContext;\n    }\n    else\n    {\n        PhDereferenceObject(waitContext->ProcessItem);\n        waitContext->ProcessItem = NULL;\n\n        NtClose(waitContext->ProcessHandle);\n        waitContext->ProcessHandle = NULL;\n\n        PhDereferenceObject(waitContext);\n    }\n}\n\nVOID PhpFlushProcessPropSheetWaitContextData(\n    VOID\n    )\n{\n    PSLIST_ENTRY entry = NULL;\n    PPH_PROCESS_WAITPROPCONTEXT data;\n    PROCESS_BASIC_INFORMATION basicInfo;\n\n    //if (!PhQueryDepthSList(&WaitContextQueryListHead))\n    //    return;\n    //if (!RtlFirstEntrySList(&WaitContextQueryListHead))\n    //    return;\n\n    entry = RtlInterlockedFlushSList(&WaitContextQueryListHead);\n\n    while (entry)\n    {\n        data = CONTAINING_RECORD(entry, PH_PROCESS_WAITPROPCONTEXT, ListEntry);\n        entry = entry->Next;\n\n        if (NT_SUCCESS(PhGetProcessBasicInformation(data->ProcessItem->QueryHandle, &basicInfo)))\n        {\n            PPH_STRING statusMessage = NULL;\n            PPH_STRING errorMessage;\n            PH_FORMAT format[5];\n\n            PhInitFormatSR(&format[0], data->ProcessItem->ProcessName->sr);\n            PhInitFormatS(&format[1], L\" (\");\n            PhInitFormatU(&format[2], HandleToUlong(data->ProcessItem->ProcessId));\n\n            if (basicInfo.ExitStatus < STATUS_WAIT_1 || basicInfo.ExitStatus > STATUS_WAIT_63)\n            {\n                if (errorMessage = PhGetStatusMessage(basicInfo.ExitStatus, 0))\n                {\n                    PhInitFormatS(&format[3], L\") exited with \");\n                    PhInitFormatSR(&format[4], errorMessage->sr);\n\n                    statusMessage = PhFormat(format, RTL_NUMBER_OF(format), 0);\n                    PhDereferenceObject(errorMessage);\n                }\n            }\n\n            if (PhIsNullOrEmptyString(statusMessage))\n            {\n                PhInitFormatS(&format[3], L\") exited with 0x\");\n                PhInitFormatX(&format[4], basicInfo.ExitStatus);\n                //format[4].Type |= FormatPadZeros; format[4].Width = 8;\n                statusMessage = PhFormat(format, RTL_NUMBER_OF(format), 0);\n            }\n\n            if (statusMessage)\n            {\n                PhSetWindowText(data->PropSheetWindowHandle, PhGetString(statusMessage));\n                PhDereferenceObject(statusMessage);\n            }\n        }\n\n        //PostMessage(data->PropSheetWindowHandle, WM_PH_PROPPAGE_EXITSTATUS, 0, (LPARAM)data);\n    }\n}\n\n_Function_class_(WAIT_CALLBACK_ROUTINE)\nVOID NTAPI PhpProcessPropertiesWaitCallback(\n    _In_ PVOID Context,\n    _In_ BOOLEAN TimerOrWaitFired\n    )\n{\n    PPH_PROCESS_WAITPROPCONTEXT waitContext = Context;\n\n    // This avoids blocking the workqueue and avoids converting the workqueue to GUI threads. (dmex)\n    RtlInterlockedPushEntrySList(&WaitContextQueryListHead, &waitContext->ListEntry);\n}\n\n_Success_(return)\nBOOLEAN PhPropPageDlgProcHeader(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ LPARAM lParam,\n    _Out_opt_ LPPROPSHEETPAGE *PropSheetPage,\n    _Out_opt_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext,\n    _Out_opt_ PPH_PROCESS_ITEM *ProcessItem\n    )\n{\n    LPPROPSHEETPAGE propSheetPage;\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        PPH_PROCESS_PROPCONTEXT propContext;\n\n        propSheetPage = (LPPROPSHEETPAGE)lParam;\n        propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam;\n        propContext = propPageContext->PropContext;\n\n        if (!propContext->WaitInitialized)\n        {\n            PhpCreateProcessPropSheetWaitContext(propContext, hwndDlg);\n            propContext->WaitInitialized = TRUE;\n        }\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, propSheetPage);\n    }\n    else\n    {\n        propSheetPage = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!propSheetPage)\n        return FALSE;\n\n    propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam;\n\n    if (PropSheetPage)\n        *PropSheetPage = propSheetPage;\n    if (PropPageContext)\n        *PropPageContext = propPageContext;\n    if (ProcessItem)\n        *ProcessItem = propPageContext->PropContext->ProcessItem;\n\n    if (uMsg == WM_NCDESTROY)\n    {\n        PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n        if (propPageContext->PropContext->ProcessWaitContext)\n        {\n            PhDereferenceObject(propPageContext->PropContext->ProcessWaitContext);\n            propPageContext->PropContext->ProcessWaitContext = NULL;\n        }\n    }\n\n    return TRUE;\n}\n\n#ifdef DEBUG\nstatic VOID ASSERT_DIALOGRECT(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ SHORT Width,\n    _In_ USHORT Height\n    )\n{\n    PDLGTEMPLATEEX dialogTemplate = NULL;\n\n    PhLoadResource(DllBase, Name, RT_DIALOG, NULL, &dialogTemplate);\n\n    assert(dialogTemplate && dialogTemplate->cx == Width && dialogTemplate->cy == Height);\n}\n#endif\n\nPPH_LAYOUT_ITEM PhAddPropPageLayoutItem(\n    _In_ HWND WindowHandle,\n    _In_ HWND Handle,\n    _In_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor\n    )\n{\n    HWND parent;\n    PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;\n    PPH_LAYOUT_MANAGER layoutManager;\n    PPH_LAYOUT_ITEM realParentItem;\n    BOOLEAN doLayoutStage2;\n    PPH_LAYOUT_ITEM item;\n\n    parent = GetParent(WindowHandle);\n    propSheetContext = PhpGetPropSheetContext(parent);\n    layoutManager = &propSheetContext->LayoutManager;\n\n    doLayoutStage2 = PhpInitializePropSheetLayoutStage1(propSheetContext, parent);\n\n    if (ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT)\n        realParentItem = ParentItem;\n    else\n        realParentItem = propSheetContext->TabPageItem;\n\n    // Use the HACK if the control is a direct child of the dialog.\n    if (ParentItem && ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT &&\n        // We detect if ParentItem is the layout item for the dialog\n        // by looking at its parent.\n        (ParentItem->ParentItem == &layoutManager->RootItem ||\n        (ParentItem->ParentItem->Anchor & PH_LAYOUT_TAB_CONTROL)))\n    {\n        RECT dialogRect;\n        RECT dialogSize;\n        RECT margin;\n\n#ifdef DEBUG\n        ASSERT_DIALOGRECT(PhInstanceHandle, MAKEINTRESOURCE(IDD_PROCGENERAL), 260, 260);\n#endif\n        // MAKE SURE THESE NUMBERS ARE CORRECT.\n        dialogSize.right = 260;\n        dialogSize.bottom = 260;\n        MapDialogRect(WindowHandle, &dialogSize);\n\n        // Get the original dialog rectangle.\n        PhGetWindowRect(WindowHandle, &dialogRect);\n        dialogRect.right = dialogRect.left + dialogSize.right;\n        dialogRect.bottom = dialogRect.top + dialogSize.bottom;\n\n        // Calculate the margin from the original rectangle.\n        PhGetWindowRect(Handle, &margin);\n        PhMapRect(&margin, &margin, &dialogRect);\n        PhConvertRect(&margin, &dialogRect);\n\n        item = PhAddLayoutItemEx(layoutManager, Handle, realParentItem, Anchor, &margin);\n    }\n    else\n    {\n        item = PhAddLayoutItem(layoutManager, Handle, realParentItem, Anchor);\n    }\n\n    if (doLayoutStage2)\n        PhpInitializePropSheetLayoutStage2(parent);\n\n    return item;\n}\n\nVOID PhDoPropPageLayout(\n    _In_ HWND WindowHandle\n    )\n{\n    HWND parent;\n    PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;\n\n    parent = GetParent(WindowHandle);\n    propSheetContext = PhpGetPropSheetContext(parent);\n    PhLayoutManagerLayout(&propSheetContext->LayoutManager);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpProcessPropertiesThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_PROCESS_PROPCONTEXT PropContext = (PPH_PROCESS_PROPCONTEXT)Parameter;\n    PPH_PROCESS_PROPPAGECONTEXT newPage;\n    PPH_STRING startPage;\n\n    PhInitializeAutoPool(&autoPool);\n\n    // Wait for stage 1 to be processed.\n    PhWaitForEvent(&PropContext->ProcessItem->Stage1Event, NULL);\n    // Refresh the icon which may have been updated due to\n    // stage 1.\n    PhRefreshProcessPropContext(PropContext);\n\n    // Add the pages...\n\n    // General\n    newPage = PhCreateProcessPropPageContext(\n        MAKEINTRESOURCE(IDD_PROCGENERAL),\n        PhpProcessGeneralDlgProc,\n        NULL\n        );\n    PhAddProcessPropPage(PropContext, newPage);\n\n    // Statistics\n    newPage = PhCreateProcessPropPageContext(\n        MAKEINTRESOURCE(IDD_PROCSTATISTICS),\n        PhpProcessStatisticsDlgProc,\n        NULL\n        );\n    PhAddProcessPropPage(PropContext, newPage);\n\n    // Performance\n    newPage = PhCreateProcessPropPageContext(\n        MAKEINTRESOURCE(IDD_PROCPERFORMANCE),\n        PhpProcessPerformanceDlgProc,\n        NULL\n        );\n    PhAddProcessPropPage(PropContext, newPage);\n\n    // Threads\n    newPage = PhCreateProcessPropPageContext(\n        MAKEINTRESOURCE(IDD_PROCTHREADS),\n        PhpProcessThreadsDlgProc,\n        NULL\n        );\n    PhAddProcessPropPage(PropContext, newPage);\n\n    // Token\n    PhAddProcessPropPage2(\n        PropContext,\n        PhCreateTokenPage(PhpOpenProcessTokenForPage, PhpCloseProcessTokenForPage, PropContext->ProcessItem->ProcessId, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessTokenHookProc)\n        );\n\n    // Modules\n    newPage = PhCreateProcessPropPageContext(\n        MAKEINTRESOURCE(IDD_PROCMODULES),\n        PhpProcessModulesDlgProc,\n        NULL\n        );\n    PhAddProcessPropPage(PropContext, newPage);\n\n    // Memory\n    newPage = PhCreateProcessPropPageContext(\n        MAKEINTRESOURCE(IDD_PROCMEMORY),\n        PhpProcessMemoryDlgProc,\n        NULL\n        );\n    PhAddProcessPropPage(PropContext, newPage);\n\n    // Environment\n    newPage = PhCreateProcessPropPageContext(\n        MAKEINTRESOURCE(IDD_PROCENVIRONMENT),\n        PhpProcessEnvironmentDlgProc,\n        NULL\n        );\n    PhAddProcessPropPage(PropContext, newPage);\n\n    // Handles\n    newPage = PhCreateProcessPropPageContext(\n        MAKEINTRESOURCE(IDD_PROCHANDLES),\n        PhpProcessHandlesDlgProc,\n        NULL\n        );\n    PhAddProcessPropPage(PropContext, newPage);\n\n    // Job\n    if (\n        PropContext->ProcessItem->IsInJob &&\n        // There's no way the job page can function without KPH since it needs\n        // to open a handle to the job.\n        (KsiLevel() >= KphLevelMed)\n        )\n    {\n        PhAddProcessPropPage2(\n            PropContext,\n            PhCreateJobPage(PhpOpenProcessJobForPage, PhpCloseProcessJobForPage, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessJobHookProc)\n            );\n    }\n\n    // Services\n    if (PropContext->ProcessItem->ServiceList && PropContext->ProcessItem->ServiceList->Count != 0)\n    {\n        newPage = PhCreateProcessPropPageContext(\n            MAKEINTRESOURCE(IDD_PROCSERVICES),\n            PhpProcessServicesDlgProc,\n            NULL\n            );\n        PhAddProcessPropPage(PropContext, newPage);\n    }\n\n    // WMI Provider Host\n    // Note: The Winmgmt service has WMI providers but doesn't get tagged with WmiProviderHostType. (dmex)\n    if (\n        (PropContext->ProcessItem->KnownProcessType & KnownProcessTypeMask) == WmiProviderHostType ||\n        (PropContext->ProcessItem->KnownProcessType & KnownProcessTypeMask) == ServiceHostProcessType\n        )\n    {\n        newPage = PhCreateProcessPropPageContext(\n            MAKEINTRESOURCE(IDD_PROCWMIPROVIDERS),\n            PhpProcessWmiProvidersDlgProc,\n            NULL\n            );\n        PhAddProcessPropPage(PropContext, newPage);\n    }\n\n#ifdef _M_IX86\n    if ((PropContext->ProcessItem->KnownProcessType & KnownProcessTypeMask) == NtVdmHostProcessType)\n    {\n        newPage = PhCreateProcessPropPageContext(\n            MAKEINTRESOURCE(IDD_PROCVDMHOST),\n            PhpProcessVdmHostProcessDlgProc,\n            NULL\n            );\n        PhAddProcessPropPage(PropContext, newPage);\n    }\n#endif\n\n    // Plugin-supplied pages\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_PROCESS_PROPCONTEXT pluginProcessPropContext;\n\n        pluginProcessPropContext.PropContext = PropContext;\n        pluginProcessPropContext.ProcessItem = PropContext->ProcessItem;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), &pluginProcessPropContext);\n    }\n\n    // Create the property sheet\n\n    if (PropContext->SelectThreadId)\n    {\n        PhSetStringSetting(SETTING_PROC_PROP_PAGE, L\"Threads\");\n    }\n\n    startPage = PhGetStringSetting(SETTING_PROC_PROP_PAGE);\n    PropContext->PropSheetHeader.dwFlags |= PSH_USEPSTARTPAGE;\n    PropContext->PropSheetHeader.pStartPage = PhGetString(startPage);\n\n    PhModalPropertySheet(&PropContext->PropSheetHeader);\n\n    PhDereferenceObject(startPage);\n    PhDereferenceObject(PropContext);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhShowProcessProperties(\n    _In_ PPH_PROCESS_PROPCONTEXT Context\n    )\n{\n    PhReferenceObject(Context);\n    PhCreateThread2(PhpProcessPropertiesThreadStart, Context);\n}\n"
  },
  {
    "path": "SystemInformer/procprv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *     jxy-s   2020-2021\n *\n */\n\n/*\n * This provider module handles the collection of process information and system-wide statistics. A\n * list of all running processes is kept and periodically scanned to detect new and terminated\n * processes.\n *\n * The retrieval of certain information is delayed in order to improve performance. This includes\n * things such as file icons, version information, digital signature verification, and packed\n * executable detection. These requests are handed to worker threads which then post back\n * information to a S-list.\n *\n * Also contained in this module is the storage of process records, which contain static information\n * about processes. Unlike process items which are removed as soon as their corresponding process\n * exits, process records remain as long as they are needed by the statistics system, and more\n * specifically the max. CPU and I/O history buffers. In PH 1.x, a new formatted string was created\n * at each update containing information about the maximum-usage process within that interval. Here\n * we use a much more storage-efficient method, where the raw maximum-usage PIDs are stored for each\n * interval, and the process record list is searched when the name of a process is needed.\n *\n * The process record list is stored as a list of records sorted by process creation time. If two or\n * more processes have the same creation time, they are added to a doubly-linked list. This\n * structure allows for fast searching in the typical scenario where we know the PID of a process\n * and a specific time in which the process was running. In this case a binary search is used and\n * then the list is traversed backwards until the process is found. Binary search is similarly used\n * for insertion and removal.\n *\n * On Windows 7 and above, CPU usage can be calculated from cycle time. However, cycle time cannot\n * be split into kernel/user components, and cycle time is not available for DPCs and Interrupts\n * separately (only a \"system\" cycle time).\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <procprv.h>\n\n#include <appresolver.h>\n#include <hndlinfo.h>\n#include <kphuser.h>\n#include <lsasup.h>\n#include <workqueue.h>\n\n#include <extmgri.h>\n#include <phplug.h>\n#include <srvprv.h>\n\n#include <trace.h>\n\n#define PROCESS_ID_BUCKETS 64\n#define PROCESS_ID_TO_BUCKET_INDEX(ProcessId) ((HandleToUlong(ProcessId) / 4) & (PROCESS_ID_BUCKETS - 1))\n\ntypedef struct _PH_PROCESS_QUERY_DATA\n{\n    SLIST_ENTRY ListEntry;\n    ULONG Stage;\n    PPH_PROCESS_ITEM ProcessItem;\n} PH_PROCESS_QUERY_DATA, *PPH_PROCESS_QUERY_DATA;\n\ntypedef struct _PH_PROCESS_QUERY_S1_DATA\n{\n    PH_PROCESS_QUERY_DATA Header;\n\n    PPH_STRING CommandLine;\n\n    PPH_IMAGELIST_ITEM IconEntry;\n    PH_IMAGE_VERSION_INFO VersionInfo;\n\n    HANDLE ConsoleHostProcessId;\n    PPH_STRING UserName;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG IsDotNet : 1;\n            ULONG Spare1 : 1;\n            ULONG IsInJob : 1;\n            ULONG IsInSignificantJob : 1;\n            ULONG IsBeingDebugged : 1;\n            ULONG IsImmersive : 1;\n            ULONG IsFilteredHandle : 1;\n            ULONG PowerThrottling : 1;\n            ULONG Spare : 24;\n        };\n    };\n\n} PH_PROCESS_QUERY_S1_DATA, *PPH_PROCESS_QUERY_S1_DATA;\n\ntypedef struct _PH_PROCESS_QUERY_S2_DATA\n{\n    PH_PROCESS_QUERY_DATA Header;\n\n    VERIFY_RESULT VerifyResult;\n    PPH_STRING VerifySignerName;\n\n    BOOLEAN IsPacked;\n    ULONG ImportFunctions;\n    ULONG ImportModules;\n    PH_IMAGE_VERSION_INFO VersionInfo; // LXSS only\n\n    NTSTATUS ImageCoherencyStatus;\n    FLOAT ImageCoherency;\n} PH_PROCESS_QUERY_S2_DATA, *PPH_PROCESS_QUERY_S2_DATA;\n\ntypedef struct _PH_SID_FULL_NAME_CACHE_ENTRY\n{\n    PCSID Sid;\n    PPH_STRING FullName;\n} PH_SID_FULL_NAME_CACHE_ENTRY, *PPH_SID_FULL_NAME_CACHE_ENTRY;\n\ntypedef struct _PH_SID_RESOLVE_QUEUE_ENTRY\n{\n    PSID Sid;\n    ULONG SidLength;\n} PH_SID_RESOLVE_QUEUE_ENTRY, *PPH_SID_RESOLVE_QUEUE_ENTRY;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpProcessItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nVOID PhpQueueProcessQueryStage1(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\nVOID PhpQueueProcessQueryStage2(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\nPPH_PROCESS_RECORD PhpCreateProcessRecord(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    );\n\nVOID PhpAddProcessRecord(\n    _Inout_ PPH_PROCESS_RECORD ProcessRecord\n    );\n\nVOID PhpRemoveProcessRecord(\n    _Inout_ PPH_PROCESS_RECORD ProcessRecord\n    );\n\nPPH_STRING PhpGetSidFullNameCached(\n    _In_ PCSID Sid\n    );\n\nPPH_STRING PhpGetSidFullNameCachedSlow(\n    _In_ PSID Sid\n    );\n\nVOID PhpQueueSidForBulkResolution(\n    _In_ PSID Sid\n    );\n\nVOID PhpBulkResolveSidsToCache(\n    _In_ PSID* Sids,\n    _In_ ULONG Count\n    );\n\nVOID PhpProcessBulkSidResolution(\n    VOID\n    );\n\nVOID PhpRemoveProcessRecord(\n    _Inout_ PPH_PROCESS_RECORD ProcessRecord\n    );\n\nPPH_OBJECT_TYPE PhProcessItemType = NULL;\n\nPPH_HASH_ENTRY PhProcessHashSet[256] = PH_HASH_SET_INIT;\nULONG PhProcessHashSetCount = 0;\nPH_QUEUED_LOCK PhProcessHashSetLock = PH_QUEUED_LOCK_INIT;\n\nSLIST_HEADER PhProcessQueryDataListHead;\n\nPPH_LIST PhProcessRecordList = NULL;\nPH_QUEUED_LOCK PhProcessRecordListLock = PH_QUEUED_LOCK_INIT;\n\nstatic PPH_HASHTABLE PhpSidFullNameCacheHashtable = NULL;\nstatic PPH_HASHTABLE PhpSidResolveQueue = NULL;\nstatic PH_QUEUED_LOCK PhpSidResolveQueueLock = PH_QUEUED_LOCK_INIT;\n\nULONG PhStatisticsSampleCount = 512;\nBOOLEAN PhEnableProcessExtension = TRUE;\nBOOLEAN PhEnablePurgeProcessRecords = TRUE;\nBOOLEAN PhEnableCycleCpuUsage = TRUE;\nBOOLEAN PhEnablePackageIconSupport = FALSE;\nULONG PhProcessProviderFlagsMask = 0;\nLONG PhProcessImageListWindowDpi = 96;\n\nPVOID PhProcessInformation = NULL; // only can be used if running on same thread as process provider\nSYSTEM_PERFORMANCE_INFORMATION PhPerfInformation;\nPSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuInformation = NULL;\nSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuTotals;\nULONG PhTotalProcesses = 0;\nULONG PhTotalThreads = 0;\nULONG PhTotalHandles = 0;\nULONG PhTotalCpuQueueLength = 0;\n\nUCHAR PhDpcsProcessInformationBuffer[sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)] = { 0 }; // HACK (dmex)\nUCHAR PhInterruptsProcessInformationBuffer[sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)] = { 0 };\nPSYSTEM_PROCESS_INFORMATION PhDpcsProcessInformation = (PSYSTEM_PROCESS_INFORMATION)PhDpcsProcessInformationBuffer;\nPSYSTEM_PROCESS_INFORMATION PhInterruptsProcessInformation = (PSYSTEM_PROCESS_INFORMATION)PhInterruptsProcessInformationBuffer;\n\nULONG64 PhCpuTotalCycleDelta = 0; // real cycle time delta for this period\nPSYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION PhCpuIdleCycleTime = NULL; // cycle time for Idle\nPSYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION PhCpuSystemCycleTime = NULL; // cycle time for DPCs and Interrupts\nPH_UINT64_DELTA PhCpuIdleCycleDelta;\nPH_UINT64_DELTA PhCpuSystemCycleDelta;\n//PPH_UINT64_DELTA PhCpusIdleCycleDelta;\n\nFLOAT PhCpuKernelUsage = 0.0f;\nFLOAT PhCpuUserUsage = 0.0f;\nPFLOAT PhCpusKernelUsage = NULL;\nPFLOAT PhCpusUserUsage = NULL;\n\nPH_UINT64_DELTA PhCpuKernelDelta;\nPH_UINT64_DELTA PhCpuUserDelta;\nPH_UINT64_DELTA PhCpuIdleDelta;\n\nPPH_UINT64_DELTA PhCpusKernelDelta = NULL;\nPPH_UINT64_DELTA PhCpusUserDelta = NULL;\nPPH_UINT64_DELTA PhCpusIdleDelta = NULL;\n\nPH_UINT64_DELTA PhIoReadDelta;\nPH_UINT64_DELTA PhIoWriteDelta;\nPH_UINT64_DELTA PhIoOtherDelta;\n\nBOOLEAN PhProcessStatisticsInitialized = FALSE;\nstatic ULONG PhTimeSequenceNumber = 0;\nstatic PH_CIRCULAR_BUFFER_ULONG PhTimeHistory;\n\nPH_CIRCULAR_BUFFER_FLOAT PhCpuKernelHistory;\nPH_CIRCULAR_BUFFER_FLOAT PhCpuUserHistory;\n//PH_CIRCULAR_BUFFER_FLOAT PhCpuOtherHistory;\n\nPPH_CIRCULAR_BUFFER_FLOAT PhCpusKernelHistory;\nPPH_CIRCULAR_BUFFER_FLOAT PhCpusUserHistory;\n//PPH_CIRCULAR_BUFFER_FLOAT PhCpusOtherHistory;\n\nPH_CIRCULAR_BUFFER_ULONG64 PhIoReadHistory;\nPH_CIRCULAR_BUFFER_ULONG64 PhIoWriteHistory;\nPH_CIRCULAR_BUFFER_ULONG64 PhIoOtherHistory;\n\nPH_CIRCULAR_BUFFER_ULONG PhCommitHistory;\nPH_CIRCULAR_BUFFER_ULONG PhPhysicalHistory;\n\nPH_CIRCULAR_BUFFER_ULONG PhMaxCpuHistory; // ID of max. CPU process\nPH_CIRCULAR_BUFFER_ULONG PhMaxIoHistory; // ID of max. I/O process\n#ifdef PH_RECORD_MAX_USAGE\nPH_CIRCULAR_BUFFER_FLOAT PhMaxCpuUsageHistory;\nPH_CIRCULAR_BUFFER_ULONG64 PhMaxIoReadOtherHistory;\nPH_CIRCULAR_BUFFER_ULONG64 PhMaxIoWriteHistory;\n#endif\n\nBOOLEAN PhProcessProviderInitialization(\n    VOID\n    )\n{\n    PFLOAT usageBuffer;\n    PPH_UINT64_DELTA deltaBuffer;\n    PPH_CIRCULAR_BUFFER_FLOAT historyBuffer;\n\n    PhProcessItemType = PhCreateObjectType(L\"ProcessItem\", 0, PhpProcessItemDeleteProcedure);\n\n    PhProcessRecordList = PhCreateList(512);\n\n    PhEnableProcessExtension = WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64();\n\n    PhInitializeSListHead(&PhProcessQueryDataListHead);\n\n    RtlInitUnicodeString(&PhDpcsProcessInformation->ImageName, L\"DPCs\");\n    PhDpcsProcessInformation->UniqueProcessId = DPCS_PROCESS_ID;\n    PhDpcsProcessInformation->InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID;\n\n    RtlInitUnicodeString(&PhInterruptsProcessInformation->ImageName, L\"Interrupts\");\n    PhInterruptsProcessInformation->UniqueProcessId = INTERRUPTS_PROCESS_ID;\n    PhInterruptsProcessInformation->InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID;\n\n    PhCpuInformation = PhAllocateZero(\n        sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) *\n        PhSystemProcessorInformation.NumberOfProcessors\n        );\n    PhCpuIdleCycleTime = PhAllocateZero(\n        sizeof(SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION) *\n        PhSystemProcessorInformation.NumberOfProcessors\n        );\n    PhCpuSystemCycleTime = PhAllocateZero(\n        sizeof(SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION) *\n        PhSystemProcessorInformation.NumberOfProcessors\n        );\n\n    usageBuffer = PhAllocateZero(\n        sizeof(FLOAT) *\n        PhSystemProcessorInformation.NumberOfProcessors *\n        2\n        );\n    deltaBuffer = PhAllocateZero(\n        sizeof(PH_UINT64_DELTA) *\n        PhSystemProcessorInformation.NumberOfProcessors *\n        3 // 4 for PhCpusIdleCycleDelta\n        );\n    historyBuffer = PhAllocateZero(\n        sizeof(PH_CIRCULAR_BUFFER_FLOAT) *\n        PhSystemProcessorInformation.NumberOfProcessors *\n        2\n        );\n\n    PhCpusKernelUsage = usageBuffer;\n    PhCpusUserUsage = PhCpusKernelUsage + PhSystemProcessorInformation.NumberOfProcessors;\n\n    PhCpusKernelDelta = deltaBuffer;\n    PhCpusUserDelta = PhCpusKernelDelta + PhSystemProcessorInformation.NumberOfProcessors;\n    PhCpusIdleDelta = PhCpusUserDelta + PhSystemProcessorInformation.NumberOfProcessors;\n    //PhCpusIdleCycleDelta = PhCpusIdleDelta + PhGetSystemInformation.NumberOfProcessors;\n\n    PhCpusKernelHistory = historyBuffer;\n    PhCpusUserHistory = PhCpusKernelHistory + PhSystemProcessorInformation.NumberOfProcessors;\n\n    return TRUE;\n}\n\nPPH_STRING PhGetClientIdName(\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    return PhGetClientIdNameEx(ClientId, NULL);\n}\n\nPPH_STRING PhGetClientIdNameEx(\n    _In_ PCLIENT_ID ClientId,\n    _In_opt_ PPH_STRING ProcessName\n    )\n{\n    PPH_STRING name;\n    PPH_PROCESS_ITEM processItem = NULL;\n\n    // Lookup the name in the process snapshot if necessary\n    if (PhIsNullOrEmptyString(ProcessName))\n    {\n        processItem = PhReferenceProcessItem(ClientId->UniqueProcess);\n\n        if (processItem)\n            ProcessName = processItem->ProcessName;\n    }\n\n    name = PhStdGetClientIdNameEx(ClientId, ProcessName);\n\n    if (processItem)\n        PhDereferenceObject(processItem);\n\n    return name;\n}\n\n/**\n * Creates a process item.\n */\nPPH_PROCESS_ITEM PhCreateProcessItem(\n    _In_ HANDLE ProcessId\n    )\n{\n    PPH_PROCESS_ITEM processItem;\n\n    processItem = PhCreateObject(\n        PhEmGetObjectSize(EmProcessItemType, sizeof(PH_PROCESS_ITEM)),\n        PhProcessItemType\n        );\n    memset(processItem, 0, sizeof(PH_PROCESS_ITEM));\n    PhInitializeEvent(&processItem->Stage1Event);\n    PhInitializeQueuedLock(&processItem->ServiceListLock);\n\n    processItem->ProcessId = ProcessId;\n\n    // Create the statistics buffers.\n    PhInitializeCircularBuffer_FLOAT(&processItem->CpuKernelHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_FLOAT(&processItem->CpuUserHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG64(&processItem->IoReadHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG64(&processItem->IoWriteHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG64(&processItem->IoOtherHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, PhStatisticsSampleCount);\n    //PhInitializeCircularBuffer_SIZE_T(&processItem->WorkingSetHistory, PhStatisticsSampleCount);\n\n    //\n    // Initialize ImageCoherencyStatus to STATUS_PENDING and prevent items\n    // from being noted as \"Low Image Coherency\" or highlighted until the\n    // analysis runs. See: PhpShouldShowImageCoherency (jxy-s)\n    //\n    processItem->ImageCoherencyStatus = STATUS_PENDING;\n\n    //\n    // Notify object operations of object creation. Note: This must be the last\n    // call after all other methods, otherwise extensions that rely on the\n    // object being initialized might crash or have undefined behavior. (dmex)\n    //\n    PhEmCallObjectOperation(EmProcessItemType, processItem, EmObjectCreate);\n\n    return processItem;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpProcessItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Object;\n    ULONG i;\n\n    PhEmCallObjectOperation(EmProcessItemType, processItem, EmObjectDelete);\n\n    PhDeleteCircularBuffer_FLOAT(&processItem->CpuKernelHistory);\n    PhDeleteCircularBuffer_FLOAT(&processItem->CpuUserHistory);\n    PhDeleteCircularBuffer_ULONG64(&processItem->IoReadHistory);\n    PhDeleteCircularBuffer_ULONG64(&processItem->IoWriteHistory);\n    PhDeleteCircularBuffer_ULONG64(&processItem->IoOtherHistory);\n    PhDeleteCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory);\n    //PhDeleteCircularBuffer_SIZE_T(&processItem->WorkingSetHistory);\n\n    if (processItem->ServiceList)\n    {\n        PPH_SERVICE_ITEM serviceItem;\n\n        i = 0;\n\n        while (PhEnumPointerList(processItem->ServiceList, &i, &serviceItem))\n            PhDereferenceObject(serviceItem);\n\n        PhDereferenceObject(processItem->ServiceList);\n    }\n\n    if (processItem->ProcessName) PhDereferenceObject(processItem->ProcessName);\n    if (processItem->FileName) PhDereferenceObject(processItem->FileName);\n    if (processItem->CommandLine) PhDereferenceObject(processItem->CommandLine);\n    PhDeleteImageVersionInfo(&processItem->VersionInfo);\n    if (processItem->Sid) PhFree(processItem->Sid);\n    if (processItem->VerifySignerName) PhDereferenceObject(processItem->VerifySignerName);\n    if (processItem->PackageFullName) PhDereferenceObject(processItem->PackageFullName);\n    if (processItem->UserName) PhDereferenceObject(processItem->UserName);\n\n    if (!PhSystemProcessorInformation.SingleProcessorGroup)\n    {\n        if (processItem->AffinityMaskGroups) PhFree(processItem->AffinityMaskGroups);\n    }\n\n    if (processItem->FreezeHandle) NtClose(processItem->FreezeHandle);\n    if (processItem->QueryHandle) NtClose(processItem->QueryHandle);\n\n    if (processItem->Record) PhDereferenceProcessRecord(processItem->Record);\n    if (processItem->IconEntry) PhDereferenceObject(processItem->IconEntry);\n}\n\nFORCEINLINE BOOLEAN PhCompareProcessItem(\n    _In_ PPH_PROCESS_ITEM Value1,\n    _In_ PPH_PROCESS_ITEM Value2\n    )\n{\n    return Value1->ProcessId == Value2->ProcessId;\n}\n\nFORCEINLINE ULONG PhHashProcessItem(\n    _In_ PPH_PROCESS_ITEM Value\n    )\n{\n    return HandleToUlong(Value->ProcessId) / 4;\n}\n\n/**\n * Finds a process item in the hash set.\n *\n * \\param ProcessId The process ID of the process item.\n *\n * \\remarks The hash set must be locked before calling this function. The reference count of the\n * found process item is not incremented.\n */\nPPH_PROCESS_ITEM PhpLookupProcessItem(\n    _In_opt_ HANDLE ProcessId\n    )\n{\n    PH_PROCESS_ITEM lookupProcessItem;\n    PPH_HASH_ENTRY entry;\n    PPH_PROCESS_ITEM processItem;\n\n    lookupProcessItem.ProcessId = ProcessId;\n    entry = PhFindEntryHashSet(\n        PhProcessHashSet,\n        PH_HASH_SET_SIZE(PhProcessHashSet),\n        PhHashProcessItem(&lookupProcessItem)\n        );\n\n    for (; entry; entry = entry->Next)\n    {\n        processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry);\n\n        if (PhCompareProcessItem(&lookupProcessItem, processItem))\n            return processItem;\n    }\n\n    return NULL;\n}\n\n/**\n * Finds and references a process item.\n *\n * \\param ProcessId The process ID of the process item.\n *\n * \\return The found process item.\n */\nPPH_PROCESS_ITEM PhReferenceProcessItem(\n    _In_opt_ HANDLE ProcessId\n    )\n{\n    PPH_PROCESS_ITEM processItem;\n\n    PhAcquireQueuedLockShared(&PhProcessHashSetLock);\n\n    processItem = PhpLookupProcessItem(ProcessId);\n\n    if (processItem)\n        PhReferenceObject(processItem);\n\n    PhReleaseQueuedLockShared(&PhProcessHashSetLock);\n\n    return processItem;\n}\n\n/**\n * Enumerates the process items.\n *\n * \\param ProcessItems A variable which receives an array of pointers to process items. You must\n * free the buffer with PhFree() when you no longer need it.\n * \\param NumberOfProcessItems A variable which receives the number of process items returned in\n * \\a ProcessItems.\n */\nVOID PhEnumProcessItems(\n    _Out_opt_ PPH_PROCESS_ITEM **ProcessItems,\n    _Out_ PULONG NumberOfProcessItems\n    )\n{\n    PPH_PROCESS_ITEM *processItems;\n    ULONG numberOfProcessItems;\n    ULONG count = 0;\n    ULONG i;\n    PPH_HASH_ENTRY entry;\n    PPH_PROCESS_ITEM processItem;\n\n    if (!ProcessItems)\n    {\n        *NumberOfProcessItems = PhProcessHashSetCount;\n        return;\n    }\n\n    PhAcquireQueuedLockShared(&PhProcessHashSetLock);\n\n    numberOfProcessItems = PhProcessHashSetCount;\n    processItems = PhAllocate(sizeof(PPH_PROCESS_ITEM) * numberOfProcessItems);\n\n    for (i = 0; i < PH_HASH_SET_SIZE(PhProcessHashSet); i++)\n    {\n        for (entry = PhProcessHashSet[i]; entry; entry = entry->Next)\n        {\n            processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry);\n            PhReferenceObject(processItem);\n            processItems[count++] = processItem;\n        }\n    }\n\n    PhReleaseQueuedLockShared(&PhProcessHashSetLock);\n\n    *ProcessItems = processItems;\n    *NumberOfProcessItems = numberOfProcessItems;\n}\n\nVOID PhpAddProcessItem(\n    _In_ _Assume_refs_(1) PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PhTrace(\n        \"Adding process item: %ls (%lu)\",\n        PhGetString(ProcessItem->ProcessName),\n        HandleToUlong(ProcessItem->ProcessId)\n        );\n\n    PhAddEntryHashSet(\n        PhProcessHashSet,\n        PH_HASH_SET_SIZE(PhProcessHashSet),\n        &ProcessItem->HashEntry,\n        PhHashProcessItem(ProcessItem)\n        );\n    PhProcessHashSetCount++;\n}\n\nVOID PhpRemoveProcessItem(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PhTrace(\n        \"Removing process item: %ls (%lu)\",\n        PhGetString(ProcessItem->ProcessName),\n        HandleToUlong(ProcessItem->ProcessId)\n        );\n\n    PhRemoveEntryHashSet(PhProcessHashSet, PH_HASH_SET_SIZE(PhProcessHashSet), &ProcessItem->HashEntry);\n    PhProcessHashSetCount--;\n    PhDereferenceObject(ProcessItem);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nstatic BOOLEAN PhpSidFullNameCacheHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_SID_FULL_NAME_CACHE_ENTRY entry1 = Entry1;\n    PPH_SID_FULL_NAME_CACHE_ENTRY entry2 = Entry2;\n\n    return PhEqualSid(entry1->Sid, entry2->Sid);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nstatic ULONG PhpSidFullNameCacheHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_SID_FULL_NAME_CACHE_ENTRY entry = Entry;\n\n    return PhHashBytes((PUCHAR)entry->Sid, PhLengthSid(entry->Sid));\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nstatic BOOLEAN PhpSidResolveQueueHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_SID_RESOLVE_QUEUE_ENTRY entry1 = Entry1;\n    PPH_SID_RESOLVE_QUEUE_ENTRY entry2 = Entry2;\n\n    return PhEqualSid(entry1->Sid, entry2->Sid);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nstatic ULONG PhpSidResolveQueueHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_SID_RESOLVE_QUEUE_ENTRY entry = Entry;\n\n    return PhHashBytes((PUCHAR)entry->Sid, PhLengthSid(entry->Sid));\n}\n\nVOID PhpQueueSidForBulkResolution(\n    _In_ PSID Sid\n    )\n{\n    PH_SID_RESOLVE_QUEUE_ENTRY lookupEntry;\n    PPH_SID_RESOLVE_QUEUE_ENTRY entry;\n\n    PhAcquireQueuedLockExclusive(&PhpSidResolveQueueLock);\n\n    if (!PhpSidResolveQueue)\n    {\n        PhpSidResolveQueue = PhCreateHashtable(\n            sizeof(PH_SID_RESOLVE_QUEUE_ENTRY),\n            PhpSidResolveQueueHashtableEqualFunction,\n            PhpSidResolveQueueHashtableHashFunction,\n            64\n            );\n    }\n\n    lookupEntry.Sid = Sid;\n    entry = PhFindEntryHashtable(PhpSidResolveQueue, &lookupEntry);\n\n    if (!entry)\n    {\n        PH_SID_RESOLVE_QUEUE_ENTRY newEntry;\n\n        newEntry.SidLength = PhLengthSid(Sid);\n        newEntry.Sid = PhAllocateCopy(Sid, newEntry.SidLength);\n\n        PhAddEntryHashtable(PhpSidResolveQueue, &newEntry);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhpSidResolveQueueLock);\n}\n\nVOID PhpBulkResolveSidsToCache(\n    _In_ PSID* Sids,\n    _In_ ULONG Count\n    )\n{\n    NTSTATUS status;\n    PPH_STRING* fullNames = NULL;\n\n    if (Count == 0)\n        return;\n\n    status = PhLookupSids(\n        Count,\n        Sids,\n        &fullNames\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (!PhpSidFullNameCacheHashtable)\n        {\n            PhpSidFullNameCacheHashtable = PhCreateHashtable(\n                sizeof(PH_SID_FULL_NAME_CACHE_ENTRY),\n                PhpSidFullNameCacheHashtableEqualFunction,\n                PhpSidFullNameCacheHashtableHashFunction,\n                128\n                );\n        }\n\n        for (ULONG i = 0; i < Count; i++)\n        {\n            if (fullNames[i])\n            {\n                PH_SID_FULL_NAME_CACHE_ENTRY newEntry;\n\n                newEntry.Sid = PhAllocateCopy(Sids[i], PhLengthSid(Sids[i]));\n                newEntry.FullName = fullNames[i];\n                PhAddEntryHashtable(PhpSidFullNameCacheHashtable, &newEntry);\n            }\n        }\n\n        PhFree(fullNames);\n    }\n}\n\nVOID PhpProcessBulkSidResolution(\n    VOID\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SID_RESOLVE_QUEUE_ENTRY entry;\n    PPH_LIST sidArray = NULL;\n    ULONG sidCount = 0;\n\n    PhAcquireQueuedLockExclusive(&PhpSidResolveQueueLock);\n\n    if (!PhpSidResolveQueue || PhpSidResolveQueue->Count == 0)\n    {\n        PhReleaseQueuedLockExclusive(&PhpSidResolveQueueLock);\n        return;\n    }\n\n    sidCount = PhpSidResolveQueue->Count;\n    sidArray = PhCreateList(sidCount);\n\n    PhBeginEnumHashtable(PhpSidResolveQueue, &enumContext);\n\n    while (entry = PhNextEnumHashtable(&enumContext))\n    {\n        PhAddItemList(sidArray, entry->Sid);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhpSidResolveQueueLock);\n\n    PhpBulkResolveSidsToCache(sidArray->Items, sidCount);\n\n    PhAcquireQueuedLockExclusive(&PhpSidResolveQueueLock);\n\n    PhBeginEnumHashtable(PhpSidResolveQueue, &enumContext);\n\n    while (entry = PhNextEnumHashtable(&enumContext))\n    {\n        PhFree(entry->Sid);\n    }\n\n    PhClearHashtable(PhpSidResolveQueue);\n    PhReleaseQueuedLockExclusive(&PhpSidResolveQueueLock);\n\n    PhDereferenceObject(sidArray);\n}\n\nPPH_STRING PhpGetSidFullNameCachedSlow(\n    _In_ PSID Sid\n    )\n{\n    PPH_STRING fullName;\n    PH_SID_FULL_NAME_CACHE_ENTRY newEntry;\n\n    if (PhpSidFullNameCacheHashtable)\n    {\n        PPH_SID_FULL_NAME_CACHE_ENTRY entry;\n        PH_SID_FULL_NAME_CACHE_ENTRY lookupEntry;\n\n        lookupEntry.Sid = Sid;\n        entry = PhFindEntryHashtable(PhpSidFullNameCacheHashtable, &lookupEntry);\n\n        if (entry)\n            return PhReferenceObject(entry->FullName);\n    }\n\n    fullName = PhGetSidFullName(Sid, TRUE, NULL);\n\n    if (!fullName)\n        return NULL;\n\n    if (!PhpSidFullNameCacheHashtable)\n    {\n        PhpSidFullNameCacheHashtable = PhCreateHashtable(\n            sizeof(PH_SID_FULL_NAME_CACHE_ENTRY),\n            PhpSidFullNameCacheHashtableEqualFunction,\n            PhpSidFullNameCacheHashtableHashFunction,\n            16\n            );\n    }\n\n    newEntry.Sid = PhAllocateCopy(Sid, PhLengthSid(Sid));\n    newEntry.FullName = PhReferenceObject(fullName);\n    PhAddEntryHashtable(PhpSidFullNameCacheHashtable, &newEntry);\n\n    return fullName;\n}\n\nPPH_STRING PhpGetSidFullNameCached(\n    _In_ PCSID Sid\n    )\n{\n    if (PhpSidFullNameCacheHashtable)\n    {\n        PPH_SID_FULL_NAME_CACHE_ENTRY entry;\n        PH_SID_FULL_NAME_CACHE_ENTRY lookupEntry;\n\n        lookupEntry.Sid = Sid;\n        entry = PhFindEntryHashtable(PhpSidFullNameCacheHashtable, &lookupEntry);\n\n        if (entry)\n            return PhReferenceObject(entry->FullName);\n    }\n\n    return NULL;\n}\n\nVOID PhpFlushSidFullNameCache(\n    VOID\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SID_FULL_NAME_CACHE_ENTRY entry;\n\n    if (!PhpSidFullNameCacheHashtable)\n        return;\n\n    PhBeginEnumHashtable(PhpSidFullNameCacheHashtable, &enumContext);\n\n    while (entry = PhNextEnumHashtable(&enumContext))\n    {\n        PhFree((PVOID)entry->Sid);\n        PhDereferenceObject(entry->FullName);\n    }\n\n    PhClearReference(&PhpSidFullNameCacheHashtable);\n}\n\nVOID PhpProcessQueryStage1(\n    _Inout_ PPH_PROCESS_QUERY_S1_DATA Data\n    )\n{\n    NTSTATUS status;\n    PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem;\n    HANDLE processId = processItem->ProcessId;\n    HANDLE processHandleLimited = processItem->QueryHandle;\n\n    PhTrace(\n        \"Process query stage 1: %ls (%lu)\",\n        PhGetString(processItem->ProcessName),\n        HandleToUlong(processId)\n        );\n\n    // Version info\n    if (!processItem->IsSubsystemProcess)\n    {\n        if (!PhIsNullOrEmptyString(processItem->FileName))\n        {\n            Data->IconEntry = PhImageListExtractIcon(\n                processItem->FileName,\n                TRUE,\n                processItem->ProcessId,\n                processItem->PackageFullName,\n                PhProcessImageListWindowDpi\n                );\n\n            PhInitializeImageVersionInfoCached(\n                &Data->VersionInfo,\n                processItem->FileName,\n                FALSE,\n                !!PhCsEnableVersionSupport\n                );\n        }\n\n        if (PhEnableCycleCpuUsage && processId == INTERRUPTS_PROCESS_ID)\n        {\n            static CONST PH_STRINGREF descriptionText = PH_STRINGREF_INIT(L\"Interrupts and DPCs\");\n            PhMoveReference(&Data->VersionInfo.FileDescription, PhCreateString2(&descriptionText));\n        }\n    }\n\n    // Command line, .NET\n    if (processHandleLimited && !processItem->IsSubsystemProcess)\n    {\n        BOOLEAN isDotNet = FALSE;\n        HANDLE processHandle = NULL;\n        ULONG processQueryFlags = 0;\n\n        if (WindowsVersion >= WINDOWS_8_1)\n        {\n            processHandle = processHandleLimited;\n            processQueryFlags |= PH_CLR_USE_SECTION_CHECK;\n            status = STATUS_SUCCESS;\n        }\n        else\n        {\n            status = PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n                processId\n                );\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            PPH_STRING commandLine;\n\n            if (NT_SUCCESS(PhGetProcessCommandLine(processHandle, &commandLine)))\n            {\n                // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows\n                // can't display them, we'll replace them with spaces.\n                for (SIZE_T i = 0; i < commandLine->Length / sizeof(WCHAR); i++)\n                {\n                    if (commandLine->Buffer[i] == UNICODE_NULL)\n                        commandLine->Buffer[i] = L' ';\n                }\n\n                Data->CommandLine = commandLine;\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            PhGetProcessIsDotNetEx(\n                processId,\n                processHandle,\n#ifdef _WIN64\n                processQueryFlags | PH_CLR_NO_WOW64_CHECK | (processItem->IsWow64Process ? PH_CLR_KNOWN_IS_WOW64 : 0),\n#else\n                processQueryFlags,\n#endif\n                &isDotNet,\n                NULL\n                );\n            Data->IsDotNet = isDotNet;\n        }\n\n        if (!(processQueryFlags & PH_CLR_USE_SECTION_CHECK) && processHandle)\n            NtClose(processHandle);\n    }\n\n    // Job\n    if (processHandleLimited)\n    {\n        if (KsiLevel() >= KphLevelMed)\n        {\n            HANDLE jobHandle = NULL;\n\n            status = KphOpenProcessJob(\n                processHandleLimited,\n                JOB_OBJECT_QUERY,\n                &jobHandle\n                );\n\n            if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB)\n            {\n                JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimits;\n\n                Data->IsInJob = TRUE;\n\n                // Process Explorer only recognizes processes as being in jobs if they don't have\n                // the silent-breakaway-OK limit as their only limit. Emulate this behaviour.\n                if (NT_SUCCESS(PhGetJobBasicLimits(jobHandle, &basicLimits)))\n                {\n                    Data->IsInSignificantJob =\n                        basicLimits.LimitFlags != JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;\n                }\n            }\n\n            if (jobHandle)\n                NtClose(jobHandle);\n        }\n        else\n        {\n            // KSystemInformer is not available. We can determine if the process is in a job, but we\n            // can't get a handle to the job.\n\n            status = NtIsProcessInJob(processHandleLimited, NULL);\n\n            if (NT_SUCCESS(status))\n                Data->IsInJob = status == STATUS_PROCESS_IN_JOB;\n        }\n    }\n\n    // Console host process\n    if (processHandleLimited)\n    {\n        PhGetProcessConsoleHostProcessId(processHandleLimited, &Data->ConsoleHostProcessId);\n    }\n\n    // Immersive\n    if (processHandleLimited && WindowsVersion >= WINDOWS_8 && processItem->IsPackagedProcess)\n    {\n        Data->IsImmersive = !!PhIsImmersiveProcess(processHandleLimited);\n    }\n\n    // Filtered\n    if (processHandleLimited && processItem->IsHandleValid)\n    {\n        OBJECT_BASIC_INFORMATION basicInfo;\n\n        if (NT_SUCCESS(PhQueryObjectBasicInformation(processHandleLimited, &basicInfo)))\n        {\n            if (!RtlAreAllAccessesGranted(basicInfo.GrantedAccess, PROCESS_QUERY_INFORMATION))\n                Data->IsFilteredHandle = TRUE;\n        }\n        else\n        {\n            Data->IsFilteredHandle = TRUE;\n        }\n    }\n\n    // Debugged\n    if (\n        processHandleLimited &&\n        !processItem->IsSubsystemProcess &&\n        !Data->IsFilteredHandle && // Don't query the debug object if the handle was filtered (dmex)\n        processItem->ProcessId != SYSTEM_PROCESS_ID // Ignore the system process on 20H2 (dmex)\n        )\n    {\n        BOOLEAN isBeingDebugged;\n\n        if (NT_SUCCESS(PhGetProcessIsBeingDebugged(processHandleLimited, &isBeingDebugged)))\n        {\n            Data->IsBeingDebugged = isBeingDebugged;\n        }\n    }\n\n    // Process Throttling State\n    {\n        if (processHandleLimited && !processItem->IsSubsystemProcess)\n        {\n            POWER_THROTTLING_PROCESS_STATE powerThrottlingState;\n\n            if (NT_SUCCESS(PhGetProcessPowerThrottlingState(processHandleLimited, &powerThrottlingState)))\n            {\n                if (FlagOn(powerThrottlingState.ControlMask, POWER_THROTTLING_PROCESS_EXECUTION_SPEED) &&\n                    FlagOn(powerThrottlingState.StateMask, POWER_THROTTLING_PROCESS_EXECUTION_SPEED))\n                {\n                    Data->PowerThrottling = TRUE;\n                }\n\n                if (FlagOn(powerThrottlingState.ControlMask, POWER_THROTTLING_PROCESS_DELAYTIMERS) &&\n                    FlagOn(powerThrottlingState.StateMask, POWER_THROTTLING_PROCESS_DELAYTIMERS))\n                {\n                    Data->PowerThrottling = TRUE;\n                }\n\n                if (FlagOn(powerThrottlingState.ControlMask, POWER_THROTTLING_PROCESS_IGNORE_TIMER_RESOLUTION) &&\n                    FlagOn(powerThrottlingState.StateMask, POWER_THROTTLING_PROCESS_IGNORE_TIMER_RESOLUTION))\n                {\n                    Data->PowerThrottling = TRUE;\n                }\n            }\n        }\n    }\n}\n\nVOID PhpProcessQueryStage2(\n    _Inout_ PPH_PROCESS_QUERY_S2_DATA Data\n    )\n{\n    PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem;\n\n    PhTrace(\n        \"Process query stage 2: %ls (%lu)\",\n        PhGetString(processItem->ProcessName),\n        HandleToUlong(processItem->ProcessId)\n        );\n\n    if (PhEnableProcessQueryStage2 && processItem->FileName && !processItem->IsSubsystemProcess)\n    {\n        NTSTATUS status;\n\n        Data->VerifyResult = PhVerifyFileCached(\n            processItem->FileName,\n            processItem->PackageFullName,\n            &Data->VerifySignerName,\n            TRUE,\n            FALSE\n            );\n\n        status = PhIsExecutablePacked(\n            processItem->FileName,\n            &Data->IsPacked,\n            &Data->ImportModules,\n            &Data->ImportFunctions\n            );\n\n        // If we got an image-related error, the image is packed.\n        if (\n            status == STATUS_INVALID_IMAGE_NOT_MZ ||\n            status == STATUS_INVALID_IMAGE_FORMAT ||\n            status == STATUS_ACCESS_VIOLATION\n            )\n        {\n            Data->IsPacked = TRUE;\n            Data->ImportModules = ULONG_MAX;\n            Data->ImportFunctions = ULONG_MAX;\n        }\n    }\n\n    if (PhEnableImageCoherencySupport && processItem->FileName && !processItem->IsSubsystemProcess)\n    {\n        if (PhCsImageCoherencyScanLevel == 0)\n        {\n            //\n            // If the user changes the configuration from 0 to >0 they will\n            // need to re-run stage 2 analysis otherwise all images will show\n            // low coherency.\n            // [ENHANCEMENT] re-run stage 2 when this advanced option changes\n            //\n            processItem->ImageCoherencyStatus = STATUS_SUCCESS;\n        }\n        else\n        {\n            PH_IMAGE_COHERENCY_SCAN_TYPE type;\n\n            switch (PhCsImageCoherencyScanLevel)\n            {\n            case 1:\n                type = PhImageCoherencyQuick;\n                break;\n            case 2:\n                type = PhImageCoherencyNormal;\n                break;\n            case 3:\n            default:\n                type = PhImageCoherencyFull;\n                break;\n            case 4:\n                type = PhImageCoherencySharedOriginal;\n                break;\n            }\n\n            Data->ImageCoherencyStatus = PhGetProcessImageCoherency(\n                processItem->FileName,\n                processItem->ProcessId,\n                type,\n                &Data->ImageCoherency\n                );\n        }\n    }\n\n    if (PhEnableLinuxSubsystemSupport && processItem->FileName && processItem->IsSubsystemProcess)\n    {\n        PhInitializeImageVersionInfoCached(&Data->VersionInfo, processItem->FileName, TRUE, !!PhCsEnableVersionSupport);\n    }\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpProcessQueryStage1Worker(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;\n    PPH_PROCESS_QUERY_S1_DATA data;\n\n    data = PhAllocateZero(sizeof(PH_PROCESS_QUERY_S1_DATA));\n    data->Header.Stage = 1;\n    data->Header.ProcessItem = processItem;\n\n    PhpProcessQueryStage1(data);\n\n    RtlInterlockedPushEntrySList(&PhProcessQueryDataListHead, &data->Header.ListEntry);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpProcessQueryStage2Worker(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;\n    PPH_PROCESS_QUERY_S2_DATA data;\n\n    data = PhAllocateZero(sizeof(PH_PROCESS_QUERY_S2_DATA));\n    data->Header.Stage = 2;\n    data->Header.ProcessItem = processItem;\n\n    PhpProcessQueryStage2(data);\n\n    RtlInterlockedPushEntrySList(&PhProcessQueryDataListHead, &data->Header.ListEntry);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpQueueProcessQueryStage1(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PH_WORK_QUEUE_ENVIRONMENT environment;\n\n    // Ref: dereferenced when the provider update function removes the item from the queue.\n    PhReferenceObject(ProcessItem);\n\n    PhInitializeWorkQueueEnvironment(&environment);\n    environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL;\n    environment.IoPriority = IoPriorityLow;\n    environment.PagePriority = MEMORY_PRIORITY_LOW;\n\n    PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage1Worker, ProcessItem, NULL, &environment);\n}\n\nVOID PhpQueueProcessQueryStage2(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PH_WORK_QUEUE_ENVIRONMENT environment;\n\n    PhReferenceObject(ProcessItem);\n\n    PhInitializeWorkQueueEnvironment(&environment);\n    environment.BasePriority = THREAD_PRIORITY_LOWEST;\n    environment.IoPriority = IoPriorityVeryLow;\n    environment.PagePriority = MEMORY_PRIORITY_VERY_LOW;\n\n    PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage2Worker, ProcessItem, NULL, &environment);\n}\n\nVOID PhpFillProcessItemStage1(\n    _In_ PPH_PROCESS_QUERY_S1_DATA Data\n    )\n{\n    PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem;\n\n    processItem->CommandLine = Data->CommandLine;\n    if (Data->IconEntry)\n    {\n        processItem->SmallIconIndex = Data->IconEntry->SmallIconIndex;\n        processItem->LargeIconIndex = Data->IconEntry->LargeIconIndex;\n    }\n    processItem->IconEntry = Data->IconEntry;\n    memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO));\n    processItem->ConsoleHostProcessId = Data->ConsoleHostProcessId;\n    processItem->IsDotNet = Data->IsDotNet;\n    processItem->IsInJob = Data->IsInJob;\n    processItem->IsInSignificantJob = Data->IsInSignificantJob;\n    processItem->IsBeingDebugged = Data->IsBeingDebugged;\n    processItem->IsImmersive = Data->IsImmersive;\n    processItem->IsProtectedHandle = Data->IsFilteredHandle;\n    processItem->IsPowerThrottling = Data->PowerThrottling;\n\n    PhSwapReference(&processItem->Record->CommandLine, processItem->CommandLine);\n\n    // Note: We might have referenced the cached username so don't overwrite the previous data. (dmex)\n    if (!processItem->UserName)\n        processItem->UserName = Data->UserName;\n    else if (Data->UserName)\n        PhDereferenceObject(Data->UserName);\n\n    // Note: Queue stage 2 processing after filling stage1 process data.\n    if (\n        PhEnableProcessQueryStage2 ||\n        PhEnableImageCoherencySupport ||\n        PhEnableLinuxSubsystemSupport\n        )\n    {\n        PhpQueueProcessQueryStage2(processItem);\n    }\n}\n\nVOID PhpFillProcessItemStage2(\n    _In_ PPH_PROCESS_QUERY_S2_DATA Data\n    )\n{\n    PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem;\n\n    processItem->VerifyResult = Data->VerifyResult;\n    processItem->VerifySignerName = Data->VerifySignerName;\n    processItem->IsPacked = Data->IsPacked;\n    processItem->ImportFunctions = Data->ImportFunctions;\n    processItem->ImportModules = Data->ImportModules;\n\n    processItem->ImageCoherencyStatus = Data->ImageCoherencyStatus;\n    processItem->ImageCoherency = Data->ImageCoherency;\n\n    // Note: We query Win32 processes in stage1 so don't overwrite the previous data. (dmex)\n    if (processItem->IsSubsystemProcess)\n    {\n        memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO));\n    }\n}\n\nVOID PhpFillProcessItemExtension(\n    _Inout_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PSYSTEM_PROCESS_INFORMATION Process\n    )\n{\n    PSYSTEM_PROCESS_INFORMATION_EXTENSION processExtension;\n\n    if (!PhEnableProcessExtension)\n        return;\n\n    processExtension = PH_PROCESS_EXTENSION(Process);\n\n    ProcessItem->DiskCounters = processExtension->DiskCounters;\n    ProcessItem->ContextSwitches = processExtension->ContextSwitches;\n    ProcessItem->JobObjectId = processExtension->JobObjectId;\n    ProcessItem->SharedCommitCharge = processExtension->SharedCommitCharge;\n    ProcessItem->ProcessSequenceNumber = processExtension->ProcessSequenceNumber;\n    ProcessItem->IsSystemProcess = processExtension->Classification != SystemProcessClassificationNormal;\n    ProcessItem->IsSecureSystem = processExtension->Classification == SystemProcessClassificationSecureSystem;\n}\n\nVOID PhpFillProcessItem(\n    _Inout_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PSYSTEM_PROCESS_INFORMATION Process\n    )\n{\n    ProcessItem->ParentProcessId = Process->InheritedFromUniqueProcessId;\n    ProcessItem->SessionId = Process->SessionId;\n    ProcessItem->CreateTime = Process->CreateTime;\n    ProcessItem->IntegrityLevel.Level = MAXUSHORT;\n\n    if (ProcessItem->ProcessId != SYSTEM_IDLE_PROCESS_ID)\n        ProcessItem->ProcessName = PhCreateStringFromUnicodeString(&Process->ImageName);\n    else\n        ProcessItem->ProcessName = PhCreateStringFromUnicodeString(&SYSTEM_IDLE_PROCESS_NAME);\n\n    if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId))\n    {\n        PhPrintUInt32(ProcessItem->ProcessIdString, HandleToUlong(ProcessItem->ProcessId));\n        PhPrintUInt32IX(ProcessItem->ProcessIdHexString, HandleToUlong(ProcessItem->ProcessId));\n        //PhPrintUInt32(ProcessItem->ParentProcessIdString, HandleToUlong(ProcessItem->ParentProcessId));\n        //PhPrintUInt32(ProcessItem->SessionIdString, ProcessItem->SessionId);\n    }\n\n    // Open a handle to the process for later usage.\n    if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId))\n    {\n        if (NT_SUCCESS(PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_INFORMATION, ProcessItem->ProcessId)))\n        {\n            ProcessItem->IsHandleValid = TRUE;\n        }\n\n        if (!ProcessItem->QueryHandle)\n        {\n            PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessItem->ProcessId);\n        }\n    }\n\n    // Process basic information\n    {\n        PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n\n        if (ProcessItem->QueryHandle && NT_SUCCESS(PhGetProcessExtendedBasicInformation(ProcessItem->QueryHandle, &basicInfo)))\n        {\n            ProcessItem->PebBaseAddress = basicInfo.PebBaseAddress;\n            ProcessItem->IsProtectedProcess = basicInfo.IsProtectedProcess;\n            ProcessItem->IsSecureProcess = basicInfo.IsSecureProcess;\n            ProcessItem->IsSubsystemProcess = basicInfo.IsSubsystemProcess;\n            ProcessItem->IsWow64Process = basicInfo.IsWow64Process;\n            ProcessItem->IsPackagedProcess = basicInfo.IsStronglyNamed;\n            ProcessItem->IsCrossSessionProcess = basicInfo.IsCrossSessionCreate;\n            ProcessItem->IsFrozenProcess = basicInfo.IsFrozen;\n            ProcessItem->IsBackgroundProcess = basicInfo.IsBackground;\n        }\n    }\n\n    // Affinity\n    {\n        if (PhSystemProcessorInformation.SingleProcessorGroup)\n        {\n            KAFFINITY affinityMask;\n\n            if (ProcessItem->QueryHandle && NT_SUCCESS(PhGetProcessAffinityMask(ProcessItem->QueryHandle, &affinityMask)))\n            {\n                ProcessItem->AffinityMaskSingle = affinityMask;\n                ProcessItem->AffinityPopulationCount = PhCountBitsUlongPtr(ProcessItem->AffinityMaskSingle);\n            }\n            else\n            {\n                ProcessItem->AffinityMaskSingle = PhSystemProcessorInformation.ActiveProcessorsAffinityMasks[0];\n                ProcessItem->AffinityPopulationCount = PhCountBitsUlongPtr(ProcessItem->AffinityMaskSingle);\n            }\n        }\n        else\n        {\n            GROUP_AFFINITY affinity;\n\n            ProcessItem->AffinityMaskGroups = PhAllocateZero(sizeof(KAFFINITY) * PhSystemProcessorInformation.NumberOfProcessorGroups);\n\n            for (USHORT i = 0; i < PhSystemProcessorInformation.NumberOfProcessorGroups; i++)\n            {\n                RtlZeroMemory(&affinity, sizeof(GROUP_AFFINITY));\n                affinity.Group = i;\n\n                if (ProcessItem->QueryHandle && NT_SUCCESS(PhGetProcessGroupAffinity(ProcessItem->QueryHandle, &affinity)))\n                    ProcessItem->AffinityMaskGroups[i] = affinity.Mask;\n                else\n                    ProcessItem->AffinityMaskGroups[i] = PhSystemProcessorInformation.ActiveProcessorsAffinityMasks[i];\n\n                ProcessItem->AffinityPopulationCount += PhCountBitsUlongPtr(ProcessItem->AffinityMaskGroups[i]);\n            }\n        }\n    }\n\n    // Process information\n    {\n        // If we're dealing with System (PID 4), we need to get the\n        // kernel file name. Otherwise, get the image file name. (wj32)\n\n        if (ProcessItem->ProcessId == SYSTEM_PROCESS_ID)\n        {\n            ProcessItem->FileName = PhGetKernelFileName();\n        }\n        else if (ProcessItem->IsSecureSystem)\n        {\n            ProcessItem->FileName = PhGetSecureKernelFileName();\n        }\n        else\n        {\n            if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId))\n            {\n                PPH_STRING fileName;\n\n                if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessItem->ProcessId, &fileName)))\n                {\n                    ProcessItem->FileName = fileName;\n                }\n\n                //if (ProcessItem->QueryHandle)\n                //{\n                //    if (NT_SUCCESS(PhGetProcessImageFileName(ProcessItem->QueryHandle, &fileName)))\n                //        ProcessItem->FileName = fileName;\n                //    if (NT_SUCCESS(PhGetProcessImageFileNameWin32(ProcessItem->QueryHandle, &fileName)))\n                //        ProcessItem->FileNameWin32 = fileName;\n                //}\n            }\n        }\n    }\n\n    // Token information\n    {\n        HANDLE tokenHandle;\n\n        if (ProcessItem->QueryHandle && NT_SUCCESS(PhOpenProcessToken(\n            ProcessItem->QueryHandle,\n            TOKEN_QUERY,\n            &tokenHandle\n            )))\n        {\n            PH_TOKEN_USER tokenUser;\n            TOKEN_ELEVATION_TYPE elevationType;\n            BOOLEAN isElevated;\n            BOOLEAN tokenIsUIAccessEnabled;\n            PH_INTEGRITY_LEVEL integrityLevel;\n            PPH_STRINGREF integrityString;\n            PPH_STRING packageFullName;\n\n            // User\n            if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser)))\n            {\n                ProcessItem->Sid = PhAllocateCopy(tokenUser.User.Sid, PhLengthSid(tokenUser.User.Sid));\n                ProcessItem->UserName = PhpGetSidFullNameCached(tokenUser.User.Sid);\n            }\n\n            // Elevation\n            if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType)))\n            {\n                ProcessItem->ElevationType = elevationType;\n            }\n\n            if (NT_SUCCESS(PhGetTokenElevation(tokenHandle, &isElevated)))\n            {\n                ProcessItem->IsElevated = isElevated;\n            }\n\n            // Integrity\n            if (NT_SUCCESS(PhGetTokenIntegrityLevelEx(tokenHandle, &integrityLevel, &integrityString)))\n            {\n                ProcessItem->IntegrityLevel = integrityLevel;\n                ProcessItem->IntegrityString = integrityString;\n            }\n\n            // UIAccess\n            if (NT_SUCCESS(PhGetTokenUIAccess(tokenHandle, &tokenIsUIAccessEnabled)))\n            {\n                ProcessItem->IsUIAccessEnabled = !!tokenIsUIAccessEnabled;\n            }\n\n            // Package name\n            if (\n                WindowsVersion >= WINDOWS_8 && ProcessItem->IsPackagedProcess &&\n                NT_SUCCESS(PhGetTokenPackageFullName(tokenHandle, &packageFullName))\n                )\n            {\n                ProcessItem->PackageFullName = packageFullName;\n            }\n\n            NtClose(tokenHandle);\n        }\n    }\n    // Token information\n    {\n        if (ProcessItem->ProcessId == SYSTEM_IDLE_PROCESS_ID ||\n            ProcessItem->ProcessId == SYSTEM_PROCESS_ID)\n        {\n            if (!ProcessItem->Sid)\n                ProcessItem->Sid = PhAllocateCopy((PSID)&PhSeLocalSystemSid, PhLengthSid(&PhSeLocalSystemSid));\n            if (!ProcessItem->UserName)\n                ProcessItem->UserName = PhpGetSidFullNameCached(&PhSeLocalSystemSid);\n\n            ProcessItem->IsSystemProcess = TRUE;\n        }\n    }\n\n    // Extended Process Information\n    if (WindowsVersion >= WINDOWS_10 && ProcessItem->QueryHandle)\n    {\n        PPROCESS_TELEMETRY_ID_INFORMATION telemetryInfo;\n        ULONG telemetryInfoLength;\n\n        if (NT_SUCCESS(PhGetProcessTelemetryIdInformation(ProcessItem->QueryHandle, &telemetryInfo, &telemetryInfoLength)))\n        {\n            SIZE_T UserSidLength = telemetryInfo->ImagePathOffset - telemetryInfo->UserSidOffset;\n            PSID UserSidBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->UserSidOffset);\n            SIZE_T ImagePathLength = telemetryInfo->PackageNameOffset - telemetryInfo->ImagePathOffset;\n            PWSTR ImagePathBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->ImagePathOffset);\n            SIZE_T PackageNameLength = telemetryInfo->RelativeAppNameOffset - telemetryInfo->PackageNameOffset;\n            PWSTR PackageNameBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->PackageNameOffset);\n            SIZE_T RelativeAppNameLength = telemetryInfo->CommandLineOffset - telemetryInfo->RelativeAppNameOffset;\n            PWSTR RelativeAppNameBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->RelativeAppNameOffset);\n            SIZE_T CommandLineLength = telemetryInfoLength - telemetryInfo->CommandLineOffset;\n            PWSTR CommandLineBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->CommandLineOffset);\n\n            ProcessItem->ProcessStartKey = telemetryInfo->ProcessStartKey;\n            ProcessItem->CreateInterruptTime = telemetryInfo->CreateInterruptTime;\n            ProcessItem->ProcessSequenceNumber = telemetryInfo->ProcessSequenceNumber;\n            ProcessItem->SessionCreateTime = telemetryInfo->SessionCreateTime;\n            ProcessItem->ImageChecksum = telemetryInfo->ImageChecksum;\n            ProcessItem->ImageTimeStamp = telemetryInfo->ImageTimeDateStamp;\n\n            if (!ProcessItem->Sid && PhValidSid(UserSidBuffer))\n            {\n                ProcessItem->Sid = PhAllocateCopy(UserSidBuffer, UserSidLength);\n                ProcessItem->UserName = PhpGetSidFullNameCached(UserSidBuffer);\n            }\n\n            if (PhIsNullOrEmptyString(ProcessItem->FileName) && ImagePathLength > sizeof(UNICODE_NULL))\n            {\n                ProcessItem->FileName = PhCreateStringEx(ImagePathBuffer, ImagePathLength - sizeof(UNICODE_NULL));\n            }\n\n            if (PhIsNullOrEmptyString(ProcessItem->PackageFullName) && PackageNameLength > sizeof(UNICODE_NULL))\n            {\n                ProcessItem->PackageFullName = PhCreateStringEx(PackageNameBuffer, PackageNameLength - sizeof(UNICODE_NULL));\n            }\n\n            if (PhIsNullOrEmptyString(ProcessItem->CommandLine) && CommandLineLength > sizeof(UNICODE_NULL))\n            {\n                PH_STRINGREF commandLine;\n\n                commandLine.Buffer = CommandLineBuffer;\n                commandLine.Length = CommandLineLength - sizeof(UNICODE_NULL);\n\n                // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows\n                // can't display them, we'll replace them with spaces. (wj32)\n                for (SIZE_T i = 0; i < commandLine.Length / sizeof(WCHAR); i++)\n                {\n                    if (commandLine.Buffer[i] == UNICODE_NULL)\n                        commandLine.Buffer[i] = L' ';\n                }\n\n                ProcessItem->CommandLine = PhCreateString2(&commandLine);\n            }\n        }\n    }\n\n    // Known Process Type\n    if (ProcessItem->FileName)\n    {\n        ProcessItem->KnownProcessType = PhGetProcessKnownTypeEx(\n            ProcessItem->ProcessId,\n            ProcessItem->FileName\n            );\n    }\n\n    // Protection\n    {\n        if (WindowsVersion >= WINDOWS_8_1)\n        {\n            if (ProcessItem->QueryHandle)\n            {\n                PS_PROTECTION protection;\n\n                if (NT_SUCCESS(PhGetProcessProtection(ProcessItem->QueryHandle, &protection)))\n                {\n                    ProcessItem->Protection.Level = protection.Level;\n                }\n            }\n            else\n            {\n                // System, DPCs, Interrupts and Idle processes are always protected. (dmex)\n                if (PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId) || ProcessItem->IsSystemProcess)\n                {\n                    ProcessItem->Protection.Level = PsProtectedValue(PsProtectedSignerWinSystem, FALSE, PsProtectedTypeProtected);\n                    ProcessItem->IsProtectedProcess = ProcessItem->IsSecureProcess = ProcessItem->IsSystemProcess = TRUE;\n                }\n            }\n        }\n    }\n\n    // Control Flow Guard\n    if (WindowsVersion >= WINDOWS_8_1 && ProcessItem->QueryHandle && FlagOn(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_CFGUARD))\n    {\n        BOOLEAN cfguardEnabled;\n\n        if (NT_SUCCESS(PhGetProcessIsCFGuardEnabled(ProcessItem->QueryHandle, &cfguardEnabled)))\n        {\n            ProcessItem->IsControlFlowGuardEnabled = cfguardEnabled;\n        }\n\n        if (WindowsVersion >= WINDOWS_11)\n        {\n            BOOLEAN xfguardEnabled;\n            BOOLEAN xfguardAuditEnabled;\n\n            if (NT_SUCCESS(PhGetProcessIsXFGuardEnabled(ProcessItem->QueryHandle, &xfguardEnabled, &xfguardAuditEnabled)))\n            {\n                ProcessItem->IsXfgEnabled = xfguardEnabled;\n                ProcessItem->IsXfgAuditEnabled = xfguardAuditEnabled;\n            }\n        }\n    }\n\n    // CET\n    if (WindowsVersion >= WINDOWS_10_20H1 && FlagOn(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_CET))\n    {\n        if (ProcessItem->ProcessId == SYSTEM_PROCESS_ID)\n        {\n            SYSTEM_SHADOW_STACK_INFORMATION shadowStackInformation;\n\n            if (NT_SUCCESS(PhGetSystemShadowStackInformation(&shadowStackInformation)))\n            {\n                ProcessItem->IsCetEnabled = shadowStackInformation.KernelCetEnabled; // Kernel CET is always strict (TheEragon)\n            }\n        }\n        else\n        {\n            if (ProcessItem->QueryHandle)\n            {\n                BOOLEAN cetEnabled;\n                BOOLEAN cetStrictModeEnabled;\n\n                if (NT_SUCCESS(PhGetProcessIsCetEnabled(ProcessItem->QueryHandle, &cetEnabled, &cetStrictModeEnabled)))\n                {\n                    ProcessItem->IsCetEnabled = cetEnabled;\n                }\n            }\n        }\n    }\n\n    // WSL\n    if (WindowsVersion >= WINDOWS_10_22H2 && ProcessItem->QueryHandle)\n    {\n        if (ProcessItem->IsSubsystemProcess && KsiLevel() >= KphLevelMed)\n        {\n            ULONG lxssProcessId;\n\n            if (NT_SUCCESS(KphQueryInformationProcess(\n                ProcessItem->QueryHandle,\n                KphProcessWSLProcessId,\n                &lxssProcessId,\n                sizeof(ULONG),\n                NULL\n                )))\n            {\n                ProcessItem->LxssProcessId = lxssProcessId;\n            }\n        }\n    }\n\n    //\n    // Snapshot processes are created via NtCreateProcessEx by providing null or\n    // empty object attributes and a parent process handle for what process to\n    // snapshot. They are normally used when inspecting or dumping a process\n    // address space.\n    //\n    // These processes do not have an initial thread and can never have a thread\n    // created within them. They will have a PEB from the originating process.\n    // The PEB check ensures we do not incorrectly designate processes that are\n    // actually valid container processes such as \"Secure System\". (jxy-s)\n    //\n    if (Process->NumberOfThreads == 0 && ProcessItem->PebBaseAddress)\n    {\n        ProcessItem->IsSnapshotProcess = TRUE;\n\n        if (ProcessItem->QueryHandle)\n        {\n            //\n            // Snapshot processes will not terminate if we have a handle open.\n            // Close it here or else process objects will leak. (wj32, jxy-s)\n            //\n            NtClose(ProcessItem->QueryHandle);\n            ProcessItem->QueryHandle = NULL;\n        }\n    }\n}\n\nVOID PhpUpdateDynamicInfoProcessItem(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PSYSTEM_PROCESS_INFORMATION Process\n    )\n{\n    ProcessItem->BasePriority = Process->BasePriority;\n\n    if (ProcessItem->QueryHandle)\n    {\n        UCHAR priorityClass;\n\n        if (NT_SUCCESS(PhGetProcessPriorityClass(ProcessItem->QueryHandle, &priorityClass)))\n        {\n            ProcessItem->PriorityClass = priorityClass;\n        }\n\n        if (WindowsVersion >= WINDOWS_11_24H2)\n        {\n            PROCESS_NETWORK_COUNTERS networkCounters;\n\n            if (NT_SUCCESS(PhGetProcessNetworkIoCounters(ProcessItem->QueryHandle, &networkCounters)))\n            {\n                ProcessItem->NetworkCounters = networkCounters;\n            }\n        }\n    }\n    else\n    {\n        ProcessItem->PriorityClass = PROCESS_PRIORITY_CLASS_UNKNOWN;\n    }\n\n    ProcessItem->KernelTime = Process->KernelTime;\n    ProcessItem->UserTime = Process->UserTime;\n    ProcessItem->NumberOfHandles = Process->HandleCount;\n    ProcessItem->NumberOfThreads = Process->NumberOfThreads;\n    ProcessItem->WorkingSetPrivateSize = Process->WorkingSetPrivateSize;\n    ProcessItem->PeakNumberOfThreads = Process->NumberOfThreadsHighWatermark;\n    ProcessItem->HardFaultCount = Process->HardFaultCount;\n\n    // Update VM and I/O counters.\n    ProcessItem->VmCounters = *(PVM_COUNTERS_EX)&Process->PeakVirtualSize;\n    ProcessItem->IoCounters = *(PIO_COUNTERS)&Process->ReadOperationCount;\n}\n\nVOID PhpUpdatePerfInformation(\n    VOID\n    )\n{\n    if (!NT_SUCCESS(NtQuerySystemInformation(\n        SystemPerformanceInformation,\n        &PhPerfInformation,\n        sizeof(SYSTEM_PERFORMANCE_INFORMATION),\n        NULL\n        )))\n    {\n        memset(&PhPerfInformation, 0, sizeof(SYSTEM_PERFORMANCE_INFORMATION));\n    }\n\n    PhUpdateDelta(&PhIoReadDelta, PhPerfInformation.IoReadTransferCount.QuadPart);\n    PhUpdateDelta(&PhIoWriteDelta, PhPerfInformation.IoWriteTransferCount.QuadPart);\n    PhUpdateDelta(&PhIoOtherDelta, PhPerfInformation.IoOtherTransferCount.QuadPart);\n}\n\nVOID PhpUpdateCpuInformation(\n    _In_ BOOLEAN SetCpuUsage,\n    _Out_ PULONG64 TotalTime\n    )\n{\n    ULONG i;\n    ULONG64 totalTime;\n\n    if (PhSystemProcessorInformation.SingleProcessorGroup)\n    {\n        if (!NT_SUCCESS(NtQuerySystemInformation(\n            SystemProcessorPerformanceInformation,\n            PhCpuInformation,\n            sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * PhSystemProcessorInformation.NumberOfProcessors,\n            NULL\n            )))\n        {\n            memset(\n                PhCpuInformation,\n                0,\n                sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * PhSystemProcessorInformation.NumberOfProcessors\n                );\n        }\n    }\n    else\n    {\n        USHORT processorCount = 0;\n\n        for (USHORT processorGroup = 0; processorGroup < PhSystemProcessorInformation.NumberOfProcessorGroups; processorGroup++)\n        {\n            USHORT activeProcessorCount = PhGetActiveProcessorCount(processorGroup);\n\n            if (!NT_SUCCESS(NtQuerySystemInformationEx(\n                SystemProcessorPerformanceInformation,\n                &processorGroup,\n                sizeof(USHORT),\n                PTR_ADD_OFFSET(PhCpuInformation, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * processorCount),\n                sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * activeProcessorCount,\n                NULL\n                )))\n            {\n                memset(\n                    PTR_ADD_OFFSET(PhCpuInformation, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * processorCount),\n                    0,\n                    sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * activeProcessorCount\n                    );\n            }\n\n            processorCount += activeProcessorCount;\n        }\n    }\n\n    // Zero the CPU totals.\n    memset(&PhCpuTotals, 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));\n\n    for (i = 0; i < PhSystemProcessorInformation.NumberOfProcessors; i++)\n    {\n        PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuInfo = &PhCpuInformation[i];\n\n        // KernelTime includes IdleTime.\n        cpuInfo->KernelTime.QuadPart -= cpuInfo->IdleTime.QuadPart;\n\n        PhCpuTotals.DpcTime.QuadPart += cpuInfo->DpcTime.QuadPart;\n        PhCpuTotals.IdleTime.QuadPart += cpuInfo->IdleTime.QuadPart;\n        PhCpuTotals.InterruptCount += cpuInfo->InterruptCount;\n        PhCpuTotals.InterruptTime.QuadPart += cpuInfo->InterruptTime.QuadPart;\n        PhCpuTotals.KernelTime.QuadPart += cpuInfo->KernelTime.QuadPart;\n        PhCpuTotals.UserTime.QuadPart += cpuInfo->UserTime.QuadPart;\n\n        PhUpdateDelta(&PhCpusKernelDelta[i], cpuInfo->KernelTime.QuadPart);\n        PhUpdateDelta(&PhCpusUserDelta[i], cpuInfo->UserTime.QuadPart);\n        PhUpdateDelta(&PhCpusIdleDelta[i], cpuInfo->IdleTime.QuadPart);\n\n        if (SetCpuUsage)\n        {\n            totalTime = PhCpusKernelDelta[i].Delta + PhCpusUserDelta[i].Delta + PhCpusIdleDelta[i].Delta;\n\n            if (totalTime != 0)\n            {\n                PhCpusKernelUsage[i] = (FLOAT)PhCpusKernelDelta[i].Delta / totalTime;\n                PhCpusUserUsage[i] = (FLOAT)PhCpusUserDelta[i].Delta / totalTime;\n            }\n            else\n            {\n                PhCpusKernelUsage[i] = 0.0f;\n                PhCpusUserUsage[i] = 0.0f;\n            }\n        }\n    }\n\n    PhUpdateDelta(&PhCpuKernelDelta, PhCpuTotals.KernelTime.QuadPart);\n    PhUpdateDelta(&PhCpuUserDelta, PhCpuTotals.UserTime.QuadPart);\n    PhUpdateDelta(&PhCpuIdleDelta, PhCpuTotals.IdleTime.QuadPart);\n\n    totalTime = PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta;\n\n    if (SetCpuUsage)\n    {\n        if (totalTime != 0)\n        {\n            PhCpuKernelUsage = (FLOAT)PhCpuKernelDelta.Delta / totalTime;\n            PhCpuUserUsage = (FLOAT)PhCpuUserDelta.Delta / totalTime;\n        }\n        else\n        {\n            PhCpuKernelUsage = 0.0f;\n            PhCpuUserUsage = 0.0f;\n        }\n    }\n\n    *TotalTime = totalTime;\n}\n\nVOID PhpUpdateCpuCycleInformation(\n    _Out_ PULONG64 IdleCycleTime\n    )\n{\n    ULONG i;\n    ULONG64 total;\n\n    // Idle\n\n    // We need to query this separately because the idle cycle time in SYSTEM_PROCESS_INFORMATION\n    // doesn't give us data for individual processors.\n\n    if (PhSystemProcessorInformation.SingleProcessorGroup)\n    {\n        if (!NT_SUCCESS(NtQuerySystemInformation(\n            SystemProcessorIdleCycleTimeInformation,\n            PhCpuIdleCycleTime,\n            sizeof(SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION) * PhSystemProcessorInformation.NumberOfProcessors,\n            NULL\n            )))\n        {\n            memset(\n                PhCpuIdleCycleTime,\n                0,\n                sizeof(SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION) * PhSystemProcessorInformation.NumberOfProcessors\n                );\n        }\n    }\n    else\n    {\n        USHORT processorCount = 0;\n\n        for (USHORT processorGroup = 0; processorGroup < PhSystemProcessorInformation.NumberOfProcessorGroups; processorGroup++)\n        {\n            USHORT activeProcessorCount = PhGetActiveProcessorCount(processorGroup);\n\n            if (!NT_SUCCESS(NtQuerySystemInformationEx(\n                SystemProcessorIdleCycleTimeInformation,\n                &processorGroup,\n                sizeof(USHORT),\n                PTR_ADD_OFFSET(PhCpuIdleCycleTime, sizeof(SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION) * processorCount),\n                sizeof(SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION) * activeProcessorCount,\n                NULL\n                )))\n            {\n                memset(\n                    PTR_ADD_OFFSET(PhCpuIdleCycleTime, sizeof(SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION) * processorCount),\n                    0,\n                    sizeof(SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION) * activeProcessorCount\n                    );\n            }\n\n            processorCount += activeProcessorCount;\n        }\n    }\n\n    total = 0;\n\n    for (i = 0; i < PhSystemProcessorInformation.NumberOfProcessors; i++)\n    {\n        //PhUpdateDelta(&PhCpusIdleCycleDelta[i], PhCpuIdleCycleTime[i].CycleTime);\n        total += PhCpuIdleCycleTime[i].CycleTime;\n    }\n\n    PhUpdateDelta(&PhCpuIdleCycleDelta, total);\n    *IdleCycleTime = PhCpuIdleCycleDelta.Delta;\n\n    // System\n\n    if (PhSystemProcessorInformation.SingleProcessorGroup)\n    {\n        if (!NT_SUCCESS(NtQuerySystemInformation(\n            SystemProcessorCycleTimeInformation,\n            PhCpuSystemCycleTime,\n            sizeof(SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION) * PhSystemProcessorInformation.NumberOfProcessors,\n            NULL\n            )))\n        {\n            memset(\n                PhCpuSystemCycleTime,\n                0,\n                sizeof(SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION) * PhSystemProcessorInformation.NumberOfProcessors\n                );\n        }\n    }\n    else\n    {\n        USHORT processorCount = 0;\n\n        for (USHORT processorGroup = 0; processorGroup < PhSystemProcessorInformation.NumberOfProcessorGroups; processorGroup++)\n        {\n            USHORT activeProcessorCount = PhGetActiveProcessorCount(processorGroup);\n\n            if (!NT_SUCCESS(NtQuerySystemInformationEx(\n                SystemProcessorCycleTimeInformation,\n                &processorGroup,\n                sizeof(USHORT),\n                PTR_ADD_OFFSET(PhCpuSystemCycleTime, sizeof(SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION) * processorCount),\n                sizeof(SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION) * activeProcessorCount,\n                NULL\n                )))\n            {\n                memset(\n                    PTR_ADD_OFFSET(PhCpuSystemCycleTime, sizeof(SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION) * processorCount),\n                    0,\n                    sizeof(SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION) * activeProcessorCount\n                    );\n            }\n\n            processorCount += activeProcessorCount;\n        }\n    }\n\n    total = 0;\n\n    for (i = 0; i < PhSystemProcessorInformation.NumberOfProcessors; i++)\n    {\n        total += PhCpuSystemCycleTime[i].CycleTime;\n    }\n\n    PhUpdateDelta(&PhCpuSystemCycleDelta, total);\n}\n\nVOID PhpUpdateCpuCycleUsageInformation(\n    _In_ ULONG64 TotalCycleTime,\n    _In_ ULONG64 IdleCycleTime\n    )\n{\n    ULONG i;\n    FLOAT baseCpuUsage;\n    ULONG64 totalTimeDelta;\n    ULONG64 totalTime;\n\n    // Cycle time is not only lacking for kernel/user components, but also for individual\n    // processors. We can get the total idle cycle time for individual processors but\n    // without knowing the total cycle time for individual processors, this information\n    // is useless.\n    //\n    // We'll start by calculating the total CPU usage, then we'll calculate the kernel/user\n    // components. In the event that the corresponding CPU time deltas are zero, we'll split\n    // the CPU usage evenly across the kernel/user components. CPU usage for individual\n    // processors is left untouched, because it's too difficult to provide an estimate.\n    //\n    // Let I_1, I_2, ..., I_n be the idle cycle times and T_1, T_2, ..., T_n be the\n    // total cycle times. Let I'_1, I'_2, ..., I'_n be the idle CPU times and T'_1, T'_2, ...,\n    // T'_n be the total CPU times.\n    // We know all I'_n, T'_n and I_n, but we only know sigma(T). The \"real\" total CPU usage is\n    // sigma(I)/sigma(T), and the \"real\" individual CPU usage is I_n/T_n. The problem is that\n    // we don't know T_n; we only know sigma(T). Hence we need to find values i_1, i_2, ..., i_n\n    // and t_1, t_2, ..., t_n such that:\n    // sigma(i)/sigma(t) ~= sigma(I)/sigma(T), and\n    // i_n/t_n ~= I_n/T_n\n    //\n    // Solution 1: Set i_n = I_n and t_n = sigma(T)*T'_n/sigma(T'). Then:\n    // sigma(i)/sigma(t) = sigma(I)/(sigma(T)*sigma(T')/sigma(T')) = sigma(I)/sigma(T), and\n    // i_n/t_n = I_n/T'_n*sigma(T')/sigma(T) ~= I_n/T_n since I_n/T'_n ~= I_n/T_n and sigma(T')/sigma(T) ~= 1.\n    // However, it is not guaranteed that i_n/t_n <= 1, which may lead to CPU usages over 100% being displayed.\n    //\n    // Solution 2: Set i_n = I'_n and t_n = T'_n. Then:\n    // sigma(i)/sigma(t) = sigma(I')/sigma(T') ~= sigma(I)/sigma(T) since I'_n ~= I_n and T'_n ~= T_n.\n    // i_n/t_n = I'_n/T'_n ~= I_n/T_n as above.\n    // Not scaling at all is currently the best solution, since it's fast, simple and guarantees that i_n/t_n <= 1.\n\n    baseCpuUsage = 1 - (FLOAT)IdleCycleTime / TotalCycleTime;\n    totalTimeDelta = PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta;\n\n    if (totalTimeDelta != 0)\n    {\n        PhCpuKernelUsage = baseCpuUsage * ((FLOAT)PhCpuKernelDelta.Delta / totalTimeDelta);\n        PhCpuUserUsage = baseCpuUsage * ((FLOAT)PhCpuUserDelta.Delta / totalTimeDelta);\n    }\n    else\n    {\n        PhCpuKernelUsage = baseCpuUsage / 2;\n        PhCpuUserUsage = baseCpuUsage / 2;\n    }\n\n    for (i = 0; i < PhSystemProcessorInformation.NumberOfProcessors; i++)\n    {\n        totalTime = PhCpusKernelDelta[i].Delta + PhCpusUserDelta[i].Delta + PhCpusIdleDelta[i].Delta;\n\n        if (totalTime != 0)\n        {\n            PhCpusKernelUsage[i] = (FLOAT)PhCpusKernelDelta[i].Delta / totalTime;\n            PhCpusUserUsage[i] = (FLOAT)PhCpusUserDelta[i].Delta / totalTime;\n        }\n        else\n        {\n            PhCpusKernelUsage[i] = 0;\n            PhCpusUserUsage[i] = 0;\n        }\n    }\n}\n\nVOID PhpInitializeProcessStatistics(\n    VOID\n    )\n{\n    ULONG i;\n\n    PhInitializeCircularBuffer_ULONG(&PhTimeHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_FLOAT(&PhCpuKernelHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_FLOAT(&PhCpuUserHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG64(&PhIoReadHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG64(&PhIoWriteHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG64(&PhIoOtherHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG(&PhCommitHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG(&PhPhysicalHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG(&PhMaxCpuHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG(&PhMaxIoHistory, PhStatisticsSampleCount);\n#ifdef PH_RECORD_MAX_USAGE\n    PhInitializeCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, PhStatisticsSampleCount);\n    PhInitializeCircularBuffer_ULONG64(&PhMaxIoWriteHistory, PhStatisticsSampleCount);\n#endif\n\n    for (i = 0; i < PhSystemProcessorInformation.NumberOfProcessors; i++)\n    {\n        PhInitializeCircularBuffer_FLOAT(&PhCpusKernelHistory[i], PhStatisticsSampleCount);\n        PhInitializeCircularBuffer_FLOAT(&PhCpusUserHistory[i], PhStatisticsSampleCount);\n    }\n}\n\nVOID PhpUpdateSystemHistory(\n    VOID\n    )\n{\n    ULONG i;\n    LARGE_INTEGER systemTime;\n    ULONG secondsSince1980;\n\n    // CPU\n    PhAddItemCircularBuffer_FLOAT(&PhCpuKernelHistory, PhCpuKernelUsage);\n    PhAddItemCircularBuffer_FLOAT(&PhCpuUserHistory, PhCpuUserUsage);\n\n    // CPUs\n    for (i = 0; i < PhSystemProcessorInformation.NumberOfProcessors; i++)\n    {\n        PhAddItemCircularBuffer_FLOAT(&PhCpusKernelHistory[i], PhCpusKernelUsage[i]);\n        PhAddItemCircularBuffer_FLOAT(&PhCpusUserHistory[i], PhCpusUserUsage[i]);\n    }\n\n    // I/O\n    PhAddItemCircularBuffer_ULONG64(&PhIoReadHistory, PhIoReadDelta.Delta);\n    PhAddItemCircularBuffer_ULONG64(&PhIoWriteHistory, PhIoWriteDelta.Delta);\n    PhAddItemCircularBuffer_ULONG64(&PhIoOtherHistory, PhIoOtherDelta.Delta);\n\n    // Memory\n    PhAddItemCircularBuffer_ULONG(&PhCommitHistory, PhPerfInformation.CommittedPages);\n    PhAddItemCircularBuffer_ULONG(&PhPhysicalHistory,\n        PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages\n        );\n\n    // Time\n    PhQuerySystemTime(&systemTime);\n    PhTimeToSecondsSince1980(&systemTime, &secondsSince1980);\n    PhAddItemCircularBuffer_ULONG(&PhTimeHistory, secondsSince1980);\n}\n\n/**\n * Retrieves a time value recorded by the statistics system.\n *\n * \\param ProcessItem A process item to synchronize with, or NULL if no synchronization is\n * necessary.\n * \\param Index The history index.\n * \\param Time A variable which receives the time at \\a Index.\n *\n * \\return TRUE if the function succeeded, otherwise FALSE if \\a ProcessItem was specified and\n * \\a Index is too far into the past for that process item.\n */\n_Success_(return)\nBOOLEAN PhGetStatisticsTime(\n    _In_opt_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG Index,\n    _Out_ PLARGE_INTEGER Time\n    )\n{\n    ULONG secondsSince1980;\n    ULONG index;\n    LARGE_INTEGER time;\n\n    if (ProcessItem)\n    {\n        // The sequence number is used to synchronize statistics when a process exits, since that\n        // process' history is not updated anymore.\n        index = PhTimeSequenceNumber - ProcessItem->TimeSequenceNumber + Index;\n\n        if (index >= PhTimeHistory.Count)\n        {\n            // The data point is too far into the past.\n            return FALSE;\n        }\n    }\n    else\n    {\n        // Assume the index is valid.\n        index = Index;\n    }\n\n    secondsSince1980 = PhGetItemCircularBuffer_ULONG(&PhTimeHistory, index);\n    PhSecondsSince1980ToTime(secondsSince1980, &time);\n\n    *Time = time;\n\n    return TRUE;\n}\n\nPPH_STRING PhGetStatisticsTimeString(\n    _In_opt_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG Index\n    )\n{\n    LARGE_INTEGER time;\n    SYSTEMTIME systemTime;\n\n    if (PhGetStatisticsTime(ProcessItem, Index, &time))\n    {\n        PhLargeIntegerToLocalSystemTime(&systemTime, &time);\n\n        return PhFormatDateTime(&systemTime);\n    }\n    else\n    {\n        return PhCreateString(L\"Unknown time\");\n    }\n}\n\nVOID PhFlushProcessQueryData(\n    VOID\n    )\n{\n    PSLIST_ENTRY entry;\n    PPH_PROCESS_QUERY_DATA data;\n\n    //if (!RtlFirstEntrySList(&PhProcessQueryDataListHead))\n    //    return;\n\n    entry = RtlInterlockedFlushSList(&PhProcessQueryDataListHead);\n\n    while (entry)\n    {\n        data = CONTAINING_RECORD(entry, PH_PROCESS_QUERY_DATA, ListEntry);\n        entry = entry->Next;\n\n        if (data->Stage == 1)\n        {\n            PhpFillProcessItemStage1((PPH_PROCESS_QUERY_S1_DATA)data);\n            PhSetEvent(&data->ProcessItem->Stage1Event);\n        }\n        else if (data->Stage == 2)\n        {\n            PhpFillProcessItemStage2((PPH_PROCESS_QUERY_S2_DATA)data);\n        }\n\n        InterlockedExchange(&data->ProcessItem->JustProcessed, TRUE);\n\n        PhDereferenceObject(data->ProcessItem);\n        PhFree(data);\n    }\n}\n\nVOID PhpGetProcessThreadInformation(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PSYSTEM_PROCESS_INFORMATION Process,\n    _Out_opt_ PBOOLEAN IsSuspended,\n    _Out_opt_ PBOOLEAN IsPartiallySuspended,\n    _Out_opt_ PULONG64 ContextSwitches,\n    _Out_opt_ PULONG ProcessorQueueLength\n    )\n{\n    ULONG i;\n    BOOLEAN isSuspended;\n    BOOLEAN isPartiallySuspended;\n    ULONG64 contextSwitches;\n    ULONG processorQueueLength;\n    ULONG suspendedCount;\n    ULONG workqueueCount;\n\n    isSuspended = FALSE;\n    isPartiallySuspended = FALSE;\n    contextSwitches = 0;\n    processorQueueLength = 0;\n    suspendedCount = 0;\n    workqueueCount = 0;\n\n    for (i = 0; i < Process->NumberOfThreads; i++)\n    {\n        PSYSTEM_THREAD_INFORMATION thread = &Process->Threads[i];\n\n        switch (thread->ThreadState)\n        {\n        case Ready:\n            processorQueueLength++;\n            break;\n        case Waiting:\n            {\n                switch (thread->WaitReason)\n                {\n                case Suspended:\n                    suspendedCount++;\n                    break;\n                case WrQueue:\n                    workqueueCount++;\n                    break;\n                }\n            }\n            break;\n        }\n\n        contextSwitches += thread->ContextSwitches;\n    }\n\n    if (PH_IS_REAL_PROCESS_ID(Process->UniqueProcessId) && !ProcessItem->IsSystemProcess)\n    {\n        if (suspendedCount)\n        {\n            if (\n                suspendedCount == Process->NumberOfThreads ||\n                (suspendedCount + workqueueCount) == Process->NumberOfThreads  // (NumberOfThreads - workQueueLength)\n                )\n            {\n                isSuspended = TRUE;\n            }\n            else\n            {\n                isPartiallySuspended = TRUE;\n            }\n        }\n    }\n\n    if (IsSuspended)\n        *IsSuspended = isSuspended;\n    if (IsPartiallySuspended)\n        *IsPartiallySuspended = isPartiallySuspended;\n    if (ContextSwitches)\n        *ContextSwitches = contextSwitches;\n    if (ProcessorQueueLength)\n        *ProcessorQueueLength = processorQueueLength;\n}\n\n/**\n * Computes CPU utilization percentage from processor cycles during a measurement interval, normalized by a scaling factor using the number of logical processors.\n *\n * Cycles = ProcessorCycleCounterStop - ProcessorCycleCounterStart\n * Cycles per Tick = Cycles / PerformanceCounterTickDelta\n * Normalized Cycles per Tick = (Cycles / PerformanceCounterTickDelta) / LogicalProcessorCount\n * CPU Usage % = DeltaCycles / (DeltaTicks x LogicalProcessorCount) x 100\n *\n * \\param ProcessorCycleCountStart The number of CPU cycles at the start of the measurement interval.\n * \\param ProcessorCycleCountStop The number of CPU cycles at the end of the measurement interval. Must be greater than ProcessorCycleCounterStart for a valid calculation.\n * \\param PerformanceCounterDelta The elapsed ticks from a high-resolution performance counter (e.g., QueryPerformanceCounter) during the measurement interval, in performance counter ticks.\n * \\param NumberOfProcessors The number of logical processors in the system, used to normalize the usage percentage.\n * \\return The utilization percentage of processor cycles during the interval.\n * \\remarks This method is used by Windows Task Manager to estimate CPU usage from TSC deltas.\n */\nDOUBLE PhComputeCpuUtilizationPercentFromCycles(\n    _In_ ULONGLONG ProcessorCycleCounterStart,\n    _In_ ULONGLONG ProcessorCycleCounterStop,\n    _In_ LONGLONG PerformanceCounterDelta,\n    _In_ ULONG LogicalProcessorCount\n    )\n{\n    if (ProcessorCycleCounterStop <= ProcessorCycleCounterStart ||\n        PerformanceCounterDelta == 0 || LogicalProcessorCount == 0)\n    {\n        return 0.0;\n    }\n\n    const DOUBLE DeltaCycles = (DOUBLE)(ProcessorCycleCounterStop - ProcessorCycleCounterStart);\n    const DOUBLE DeltaTicks = (DOUBLE)PerformanceCounterDelta;\n\n    const DOUBLE CyclesPerQpcTick = DeltaCycles / DeltaTicks;\n    const DOUBLE UtilizationPercent = (CyclesPerQpcTick / (DOUBLE)LogicalProcessorCount) * 100.0;\n\n    return UtilizationPercent;\n}\n\n/*\n * Computes CPU utilization percentage from processor cycles during a measurement interval, normalized by logical processors and calibrated by counter frequencies.\n *\n * Utilization% = ObservedCycles / (ElapsedSeconds * CycleCounterFrequencyHz * LogicalProcessorCount) * 100\n *\n * \\param ProcessorCycleCountStart The number of CPU cycles at the start of the measurement interval.\n * \\param ProcessorCycleCountStop The number of CPU cycles at the end of the measurement interval. Must be greater than ProcessorCycleCounterStart for a valid calculation.\n * \\param PerformanceCounterDelta The elapsed ticks from a high-resolution performance counter (e.g., QueryPerformanceCounter) during the measurement interval, in performance counter ticks.\n * \\param NumberOfProcessors The number of logical processors in the system, used to normalize the usage percentage.\n * \\return The precise utilization percentage of processor cycles during the interval.\n * \\remarks This method produces a true CPU utilization percentage by incorporating counter frequencies.\n * \\remarks ProcessorCycleCounterFrequency must correspond to the SAME source as ProcessorCycleCounterStart/Stop.\n * If cycles are from TSC, pass TSC frequency. If cycles are from a PMU (e.g., Unhalted Core Cycles), pass that\n * counter's effective frequency at 100%, not the invariant TSC frequency.\n */\nDOUBLE PhComputeCpuUtilizationPercentFromCyclesPrecise(\n    _In_ ULONGLONG ProcessorCycleCounterStart,\n    _In_ ULONGLONG ProcessorCycleCounterStop,\n    _In_ ULONGLONG ProcessorCycleCounterFrequency,\n    _In_ LONGLONG  PerformanceCounterDelta,\n    _In_ ULONGLONG PerformanceCounterFrequency,\n    _In_ ULONG LogicalProcessorCount\n    )\n{\n    if (ProcessorCycleCounterStop <= ProcessorCycleCounterStart || PerformanceCounterDelta <= 0 ||\n        PerformanceCounterFrequency == 0 || ProcessorCycleCounterFrequency == 0 || LogicalProcessorCount == 0)\n    {\n        return 0.0;\n    }\n\n    const DOUBLE ObservedCycles = (DOUBLE)(ProcessorCycleCounterStop - ProcessorCycleCounterStart);\n    const DOUBLE ElapsedSeconds = (DOUBLE)PerformanceCounterDelta / (DOUBLE)PerformanceCounterFrequency;\n    const DOUBLE CapacityCycles = ElapsedSeconds * (DOUBLE)ProcessorCycleCounterFrequency * (DOUBLE)LogicalProcessorCount;\n\n    if (!(CapacityCycles > 0.0))\n        return 0.0;\n\n    const DOUBLE UtilizationPercent = (ObservedCycles / CapacityCycles) * 100.0;\n\n    return UtilizationPercent;\n}\n\n#ifdef _ARM64_\nVOID PhpEstimateIdleCyclesForARM(\n    _Inout_ PULONG64 TotalCycles,\n    _Inout_ PULONG64 IdleCycles\n    )\n{\n    // EXPERIMENTAL (jxy-s)\n    //\n    // Update (2024-09-29) - 24H2 is now estimating the cycle counts for idle threads in the kernel\n    // making this routine obsolete. However, this means that the idle thread cycle counts returned\n    // from the kernel is not a reflection of the actual CPU effort of the idle threads. In other\n    // words the idle threads now represent the percentage of the CPU *not* being used by other\n    // processes, as it does on other architectures. The kernel has also broadly changed the cycle\n    // accounting across the entire system to no longer use PMCCNTR_EL0 and instead it uses\n    // KeQueryPerformanceCounter. This means it is currently impossible to represent the cycle\n    // accounting in a way best suited for the ARM architecture. The kernel appears to have opted\n    // for more consistency between architectures instead of accuracy for ARM.\n    //\n    assert(WindowsVersion < WINDOWS_11_24H2);\n\n    //\n    // The kernel uses PMCCNTR_EL0 for CycleTime in threads and the processor control blocks.\n    // Here is a snippet from ntoskrnl!KiIdleLoop:\n    /*\n00000001`404f45a0 d53b9d0b mrs         x11,PMCCNTR_EL0    // x11 gets current cycle count\n00000001`404f45a4 f947a668 ldr         x8,[x19,#0xF48]    // x8 gets _KPRCB.StartCycles\n00000001`404f45a8 cb08016a sub         x10,x11,x8         // x10 gets relative cycles from StartCycle to current cycle count\n00000001`404f45ac f94026a9 ldr         x9,[x21,#0x48]     // x9 gets _KPRCB.IdleThread.CycleTime\n00000001`404f45b0 8b0a0128 add         x8,x9,x10          // x8 gets idle thread cycle time (x9) plus cycle increment (x10)\n00000001`404f45b4 f90026a8 str         x8,[x21,#0x48]     // stores new idle thread cycle time in _KPRCB.IdleThread.CycleTime\n00000001`404f45b8 f907a66b str         x11,[x19,#0xF48]   // stores the last cycle time fetch in the _KPRCB.StartCycles\n    */\n    // The idle logic in the HAL is here:\n    /*\nntoskrnl!HalProcessorIdle:\n00000001`4048fbf0 d503237f pacibsp\n00000001`4048fbf4 a9bf7bfd stp         fp,lr,[sp,#-0x10]!\n00000001`4048fbf8 910003fd mov         fp,sp\n00000001`4048fbfc 940013df bl          ntoskrnl!HalpTimerResetProfileAdjustment (00000001`40494b78)\n00000001`4048fc00 d5033f9f dsb         sy\n00000001`4048fc04 d503207f wfi\n00000001`4048fc08 a8c17bfd ldp         fp,lr,[sp],#0x10\n00000001`4048fc0c d50323ff autibsp\n00000001`4048fc10 d65f03c0 ret\n    */\n    // This dictates that the CPU should enter WFI (Wait For Interrupt) mode. In this mode the\n    // CPU clock is disabled and the PMCCNTR register is not being updated, from the docs:\n    /*\nAll counters are subject to any changes in clock frequency, including clock stopping caused by\nthe WFI and WFE instructions. This means that it is CONSTRAINED UNPREDICTABLE regardless of whether\nPMCCNTR_EL0 continues to increment when clocks are stopped by WFI and WFE instructions.\n    */\n    // Arguably, the kernel is doing the right thing here, the idle threads are taking less cycle\n    // time and the KTHREAD reflects this accurately. However, due to the way cycle-based CPU\n    // usage is implemented for other architectures it assumes on the idle thread cycles are\n    // the cycles *not* spent using the CPU, this assumption is incorrect for ARM.\n    //\n    // The most accurate representation of the utilization of the CPU for ARM would show\n    // the idle process CPU usage *below* what is \"not being used\" by other processes. Since\n    // this would indicate the idle thread being in the WFI state and not using CPU cycles.\n    // For cycle-based CPU to make sense for ARM, we need a way to get or estimate the amount\n    // of cycles the CPU would have used by the idle threads if WFI was mode was not entered.\n    //\n    // This experimental estimate achieves that. It will show the idle process utilization\n    // accurately (given the estimate and what the kernel tracks/reports), and generally retain\n    // the cycle-based CPU benefits. Arguably, we are in some capacity reverting to the\n    // time-based CPU usage calculation by relying on the time to generate the estimate, but\n    // again it comes with the benefit of more realistically reporting the idle threads given\n    // what is tracked/reported by the kernel.\n    //\n    // let x = Unknown Idle Cycles\n    // let y = \"Total\" Cycles (missing idle cycles)\n    // let a = Time Idle\n    // let b = Time Kernel\n    // let c = Time User\n    //\n    // x / (y + x) = CycleUsage\n    // a / (a + b + c) = TimeUsage\n    //\n    // Assume: CycleUsage ~= TimeUsage\n    // Then:  x / (y + x) ~= a / (a + b + c)\n    //\n    // We know y, a, b, and c. So we need to solve for x.\n    //\n    // x / (y + x) ~= a / (a + b + c)\n    //\n    // x ~= a * (y + x) / (a + b + c)\n    // x * (a + b + c) ~= a * (y + x)\n    // x * (a + b + c) ~= (a * y) + (a * x)\n    // x * (a + b + c) - (a * x) ~= (a * y)\n    // x * ((a + b + c) - a) ~= (a * y)\n    // x ~= (a * y) / ((a + b + c) - a)\n    //\n    // x ~= (a * y) / (b + c)\n    //\n    ULONG64 delta = PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta;\n    if (delta != 0)\n        *IdleCycles = (PhCpuIdleCycleDelta.Delta * *TotalCycles) / delta;\n    else\n        *IdleCycles = (PhCpuIdleCycleDelta.Delta * *TotalCycles);\n\n    // We still need to add in the idle cycle time to the \"total\" since it wasn't complete yet.\n    *TotalCycles += *IdleCycles;\n}\n#endif\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhProcessProviderUpdate(\n    _In_ PVOID Object\n    )\n{\n    static ULONG runCount = 0;\n    static PSYSTEM_PROCESS_INFORMATION pidBuckets[PROCESS_ID_BUCKETS];\n\n    // Note about locking:\n    //\n    // Since this is the only function that is allowed to modify the process hashtable, locking is\n    // not needed for shared accesses. However, exclusive accesses need locking.\n\n    NTSTATUS status;\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n    ULONG bucketIndex;\n\n    ULONG64 sysTotalTime; // total time for this update period\n    ULONG64 sysTotalCycleTime = 0; // total cycle time for this update period\n    ULONG64 sysIdleCycleTime = 0; // total idle cycle time for this update period\n    FLOAT maxCpuValue = 0;\n    PPH_PROCESS_ITEM maxCpuProcessItem = NULL;\n    ULONG64 maxIoValue = 0;\n    PPH_PROCESS_ITEM maxIoProcessItem = NULL;\n\n    // Pre-update tasks\n\n    PhTraceFuncEnter(\"Process provider run count: %lu\", runCount);\n\n    if (runCount > 0)\n    {\n        PhpProcessBulkSidResolution();\n    }\n\n    if (runCount % 512 == 0) // yes, a very long time\n    {\n        if (PhEnablePurgeProcessRecords)\n            PhPurgeProcessRecords();\n\n        PhpFlushSidFullNameCache();\n\n        PhImageListFlushCache();\n\n        PhFlushImageVersionInfoCache();\n\n        PhFlushVerifyCache();\n    }\n\n    if (!PhProcessStatisticsInitialized)\n    {\n        PhpInitializeProcessStatistics();\n        PhProcessStatisticsInitialized = TRUE;\n    }\n\n    PhpUpdatePerfInformation();\n\n    if (PhEnableCycleCpuUsage)\n    {\n        PhpUpdateCpuInformation(FALSE, &sysTotalTime);\n        PhpUpdateCpuCycleInformation(&sysIdleCycleTime);\n    }\n    else\n    {\n        PhpUpdateCpuInformation(TRUE, &sysTotalTime);\n    }\n\n    if (runCount != 0)\n    {\n        PhTimeSequenceNumber++;\n    }\n\n    // Get the process list.\n\n    PhTotalProcesses = 0;\n    PhTotalThreads = 0;\n    PhTotalHandles = 0;\n    PhTotalCpuQueueLength = 0;\n\n    if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))\n    {\n        PhTraceFuncExit(\"Failed to enumerate processes: %lu %!STATUS!\", runCount, status);\n        return;\n    }\n\n    // Notes on cycle-based CPU usage:\n    //\n    // Cycle-based CPU usage is a bit tricky to calculate because we cannot get the total number of\n    // cycles consumed by all processes since system startup - we can only get total number of\n    // cycles per process. This means there are two ways to calculate the system-wide cycle time\n    // delta:\n    //\n    // 1. Each update, sum the cycle times of all processes, and calculate the system-wide delta\n    //    from this. Process Explorer seems to do this.\n    // 2. Each update, calculate the cycle time delta for each individual process, and sum these\n    //    deltas to create the system-wide delta. We use this here.\n    //\n    // The first method is simpler but has a problem when a process exits and its cycle time is no\n    // longer counted in the system-wide total. This may cause the delta to be negative and all\n    // other calculations to become invalid. Process Explorer simply ignored this fact and treated\n    // the system-wide delta as unsigned (and therefore huge when negative), leading to all CPU\n    // usages being displayed as \"< 0.01\".\n    //\n    // The second method is used here, but the adjustments must be done before the main new/modified\n    // pass. We need take into account new, existing and terminated processes.\n\n    // Create the PID hash set. This contains the process information structures returned by\n    // PhEnumProcesses, distinct from the process item hash set. Note that we use the\n    // UniqueProcessKey field as the next node pointer to avoid having to allocate extra memory.\n\n    memset(pidBuckets, 0, sizeof(pidBuckets));\n\n    process = PH_FIRST_PROCESS(processes);\n\n    do\n    {\n        PhTotalProcesses++;\n        PhTotalThreads += process->NumberOfThreads;\n        PhTotalHandles += process->HandleCount;\n\n        if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID)\n        {\n            process->CycleTime = PhCpuIdleCycleDelta.Value;\n            process->KernelTime = PhCpuTotals.IdleTime;\n        }\n\n        bucketIndex = PROCESS_ID_TO_BUCKET_INDEX(process->UniqueProcessId);\n        process->UniqueProcessKey = (ULONG_PTR)pidBuckets[bucketIndex];\n        pidBuckets[bucketIndex] = process;\n\n#ifdef _ARM64_ // see: PhpEstimateIdleCyclesForARM (jxy-s)\n        if (PhEnableCycleCpuUsage && (WindowsVersion >= WINDOWS_11_24H2 || process->UniqueProcessId != SYSTEM_IDLE_PROCESS_ID))\n#else\n        if (PhEnableCycleCpuUsage)\n#endif\n        {\n            PPH_PROCESS_ITEM processItem;\n\n            if (PhEnableProcessExtension)\n            {\n                if ((processItem = PhpLookupProcessItem(process->UniqueProcessId)) && processItem->ProcessSequenceNumber == PH_PROCESS_EXTENSION(process)->ProcessSequenceNumber)\n                    sysTotalCycleTime += process->CycleTime - processItem->CycleTimeDelta.Value; // existing process\n                else\n                    sysTotalCycleTime += process->CycleTime; // new process\n            }\n            else\n            {\n                if ((processItem = PhpLookupProcessItem(process->UniqueProcessId)) && processItem->CreateTime.QuadPart == process->CreateTime.QuadPart)\n                    sysTotalCycleTime += process->CycleTime - processItem->CycleTimeDelta.Value; // existing process\n                else\n                    sysTotalCycleTime += process->CycleTime; // new process\n            }\n        }\n    } while (process = PH_NEXT_PROCESS(process));\n\n    // Add the fake processes to the PID list.\n    //\n    // On Windows 7 the two fake processes are merged into \"Interrupts\" since we can only get cycle\n    // time information both DPCs and Interrupts combined.\n\n    if (PhEnableCycleCpuUsage)\n    {\n        PhInterruptsProcessInformation->KernelTime.QuadPart = PhCpuTotals.DpcTime.QuadPart + PhCpuTotals.InterruptTime.QuadPart;\n        PhInterruptsProcessInformation->CycleTime = PhCpuSystemCycleDelta.Value;\n        sysTotalCycleTime += PhCpuSystemCycleDelta.Delta;\n    }\n    else\n    {\n        PhDpcsProcessInformation->KernelTime = PhCpuTotals.DpcTime;\n        PhInterruptsProcessInformation->KernelTime = PhCpuTotals.InterruptTime;\n    }\n\n    // Look for dead processes.\n    {\n        PPH_LIST processesToRemove = NULL;\n        ULONG i;\n        PPH_HASH_ENTRY entry;\n        PPH_PROCESS_ITEM processItem;\n        PSYSTEM_PROCESS_INFORMATION processEntry;\n\n        for (i = 0; i < PH_HASH_SET_SIZE(PhProcessHashSet); i++)\n        {\n            for (entry = PhProcessHashSet[i]; entry; entry = entry->Next)\n            {\n                BOOLEAN processRemoved = FALSE;\n\n                processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry);\n\n                // Check if the process still exists. Note that we take into account PID re-use by\n                // checking CreateTime as well.\n\n                if (processItem->ProcessId == DPCS_PROCESS_ID)\n                {\n                    processEntry = PhDpcsProcessInformation;\n                }\n                else if (processItem->ProcessId == INTERRUPTS_PROCESS_ID)\n                {\n                    processEntry = PhInterruptsProcessInformation;\n                }\n                else\n                {\n                    processEntry = pidBuckets[PROCESS_ID_TO_BUCKET_INDEX(processItem->ProcessId)];\n\n                    while (processEntry && processEntry->UniqueProcessId != processItem->ProcessId)\n                        processEntry = (PSYSTEM_PROCESS_INFORMATION)processEntry->UniqueProcessKey;\n                }\n\n                if (PhEnableProcessExtension)\n                {\n                    if (!processEntry || PH_PROCESS_EXTENSION(processEntry)->ProcessSequenceNumber != processItem->ProcessSequenceNumber)\n                        processRemoved = TRUE;\n                }\n                else\n                {\n                    if (!processEntry || processEntry->CreateTime.QuadPart != processItem->CreateTime.QuadPart)\n                        processRemoved = TRUE;\n                }\n\n                if (processRemoved)\n                {\n                    LARGE_INTEGER exitTime;\n\n                    processItem->State |= PH_PROCESS_ITEM_REMOVED;\n                    exitTime.QuadPart = 0;\n\n                    if (processItem->QueryHandle)\n                    {\n                        KERNEL_USER_TIMES times;\n                        ULONG64 finalCycleTime;\n\n                        if (NT_SUCCESS(PhGetProcessTimes(processItem->QueryHandle, &times)))\n                        {\n                            exitTime = times.ExitTime;\n                        }\n\n                        if (PhEnableCycleCpuUsage)\n                        {\n                            if (NT_SUCCESS(PhGetProcessCycleTime(processItem->QueryHandle, &finalCycleTime)))\n                            {\n                                // Adjust deltas for the terminated process because this doesn't get\n                                // picked up anywhere else.\n                                //\n                                // Note that if we don't have sufficient access to the process, the\n                                // worst that will happen is that the CPU usages of other processes\n                                // will get inflated. (See above; if we were using the first\n                                // technique, we could get negative deltas, which is much worse.)\n                                sysTotalCycleTime += finalCycleTime - processItem->CycleTimeDelta.Value;\n                            }\n                        }\n                    }\n\n                    // If we don't have a valid exit time, use the current time.\n                    if (exitTime.QuadPart == 0)\n                        PhQuerySystemTime(&exitTime);\n\n                    processItem->Record->Flags |= PH_PROCESS_RECORD_DEAD;\n                    processItem->Record->ExitTime = exitTime;\n\n                    // Raise the process removed event.\n                    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderRemovedEvent), processItem);\n\n                    if (!processesToRemove)\n                        processesToRemove = PhCreateList(2);\n\n                    ASSUME_ASSERT(processesToRemove);\n                    PhAddItemList(processesToRemove, processItem);\n                }\n            }\n        }\n\n        // Lock only if we have something to do.\n        if (processesToRemove)\n        {\n            PhAcquireQueuedLockExclusive(&PhProcessHashSetLock);\n\n            for (i = 0; i < processesToRemove->Count; i++)\n            {\n                PhpRemoveProcessItem((PPH_PROCESS_ITEM)processesToRemove->Items[i]);\n            }\n\n            PhReleaseQueuedLockExclusive(&PhProcessHashSetLock);\n            PhDereferenceObject(processesToRemove);\n        }\n    }\n\n#ifdef _ARM64_\n    if (PhEnableCycleCpuUsage && WindowsVersion < WINDOWS_11_24H2)\n        PhpEstimateIdleCyclesForARM(&sysTotalCycleTime, &sysIdleCycleTime);\n#endif\n\n    // Go through the queued process query data.\n    PhFlushProcessQueryData();\n\n    if (sysTotalTime == 0)\n        sysTotalTime = ULONG64_MAX; // max. value\n    if (sysTotalCycleTime == 0)\n        sysTotalCycleTime = ULONG64_MAX;\n\n    PhCpuTotalCycleDelta = sysTotalCycleTime;\n\n    // Look for new processes and update existing ones.\n    process = PH_FIRST_PROCESS(processes);\n\n    while (process)\n    {\n        PPH_PROCESS_ITEM processItem;\n\n        processItem = PhpLookupProcessItem(process->UniqueProcessId);\n\n        if (!processItem)\n        {\n            PPH_PROCESS_RECORD processRecord;\n            BOOLEAN isSuspended;\n            BOOLEAN isPartiallySuspended;\n            ULONG64 contextSwitches;\n            ULONG processorQueueLength;\n\n            // Create the process item and fill in basic information.\n            processItem = PhCreateProcessItem(process->UniqueProcessId);\n            PhpFillProcessItemExtension(processItem, process);\n            PhpFillProcessItem(processItem, process);\n            processItem->TimeSequenceNumber = PhTimeSequenceNumber;\n\n            processRecord = PhpCreateProcessRecord(processItem);\n            PhpAddProcessRecord(processRecord);\n            processItem->Record = processRecord;\n\n            PhpUpdateDynamicInfoProcessItem(processItem, process);\n            PhpGetProcessThreadInformation(processItem, process, &isSuspended, &isPartiallySuspended, &contextSwitches, &processorQueueLength);\n            PhTotalCpuQueueLength += processorQueueLength;\n\n            // Initialize the deltas.\n            PhUpdateDelta(&processItem->CpuKernelDelta, process->KernelTime.QuadPart);\n            PhUpdateDelta(&processItem->CpuUserDelta, process->UserTime.QuadPart);\n            PhUpdateDelta(&processItem->IoReadDelta, process->ReadTransferCount.QuadPart);\n            PhUpdateDelta(&processItem->IoWriteDelta, process->WriteTransferCount.QuadPart);\n            PhUpdateDelta(&processItem->IoOtherDelta, process->OtherTransferCount.QuadPart);\n            PhUpdateDelta(&processItem->IoReadCountDelta, process->ReadOperationCount.QuadPart);\n            PhUpdateDelta(&processItem->IoWriteCountDelta, process->WriteOperationCount.QuadPart);\n            PhUpdateDelta(&processItem->IoOtherCountDelta, process->OtherOperationCount.QuadPart);\n            PhUpdateDelta(&processItem->ContextSwitchesDelta, PhEnableProcessExtension ? processItem->ContextSwitches : contextSwitches);\n            PhUpdateDelta(&processItem->PageFaultsDelta, process->PageFaultCount);\n            PhUpdateDelta(&processItem->HardFaultsDelta, process->HardFaultCount);\n            PhUpdateDelta(&processItem->CycleTimeDelta, process->CycleTime);\n            PhUpdateDelta(&processItem->PrivateBytesDelta, process->PagefileUsage);\n\n            processItem->IsSuspended = isSuspended;\n            processItem->IsPartiallySuspended = isPartiallySuspended;\n\n            // If this is the first run of the provider, queue the\n            // process query tasks. Otherwise, perform stage 1\n            // processing now and queue stage 2 processing.\n            if (runCount > 0)\n            {\n                PH_PROCESS_QUERY_S1_DATA data;\n\n                memset(&data, 0, sizeof(PH_PROCESS_QUERY_S1_DATA));\n                data.Header.Stage = 1;\n                data.Header.ProcessItem = processItem;\n                PhpProcessQueryStage1(&data);\n                PhpFillProcessItemStage1(&data);\n                PhSetEvent(&processItem->Stage1Event);\n            }\n            else\n            {\n                PhpQueueProcessQueryStage1(processItem);\n            }\n\n            // Add pending service items to the process item.\n            PhUpdateProcessItemServices(processItem);\n\n            // Add the process item to the hashtable.\n            PhAcquireQueuedLockExclusive(&PhProcessHashSetLock);\n            PhpAddProcessItem(processItem);\n            PhReleaseQueuedLockExclusive(&PhProcessHashSetLock);\n\n            // Raise the process added event.\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderAddedEvent), processItem);\n\n            // (Ref: for the process item being in the hashtable.)\n            // Instead of referencing then dereferencing we simply don't do anything.\n            // Dereferenced in PhpRemoveProcessItem.\n        }\n        else\n        {\n            BOOLEAN modified = FALSE;\n            BOOLEAN isSuspended;\n            BOOLEAN isPartiallySuspended;\n            ULONG64 contextSwitches;\n            ULONG processorQueueLength;\n            FLOAT newCpuUsage;\n            FLOAT kernelCpuUsage;\n            FLOAT userCpuUsage;\n\n            PhpUpdateDynamicInfoProcessItem(processItem, process);\n            PhpGetProcessThreadInformation(processItem, process, &isSuspended, &isPartiallySuspended, &contextSwitches, &processorQueueLength);\n            PhpFillProcessItemExtension(processItem, process);\n            PhTotalCpuQueueLength += processorQueueLength;\n\n            // Update the deltas.\n            PhUpdateDelta(&processItem->CpuKernelDelta, process->KernelTime.QuadPart);\n            PhUpdateDelta(&processItem->CpuUserDelta, process->UserTime.QuadPart);\n            PhUpdateDelta(&processItem->IoReadDelta, process->ReadTransferCount.QuadPart);\n            PhUpdateDelta(&processItem->IoWriteDelta, process->WriteTransferCount.QuadPart);\n            PhUpdateDelta(&processItem->IoOtherDelta, process->OtherTransferCount.QuadPart);\n            PhUpdateDelta(&processItem->IoReadCountDelta, process->ReadOperationCount.QuadPart);\n            PhUpdateDelta(&processItem->IoWriteCountDelta, process->WriteOperationCount.QuadPart);\n            PhUpdateDelta(&processItem->IoOtherCountDelta, process->OtherOperationCount.QuadPart);\n            PhUpdateDelta(&processItem->ContextSwitchesDelta, PhEnableProcessExtension ? processItem->ContextSwitches : contextSwitches);\n            PhUpdateDelta(&processItem->PageFaultsDelta, process->PageFaultCount);\n            PhUpdateDelta(&processItem->HardFaultsDelta, process->HardFaultCount);\n            PhUpdateDelta(&processItem->CycleTimeDelta, process->CycleTime);\n            PhUpdateDelta(&processItem->PrivateBytesDelta, process->PagefileUsage);\n\n            processItem->TimeSequenceNumber++;\n            PhAddItemCircularBuffer_ULONG64(&processItem->IoReadHistory, processItem->IoReadDelta.Delta);\n            PhAddItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, processItem->IoWriteDelta.Delta);\n            PhAddItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, processItem->IoOtherDelta.Delta);\n\n            PhAddItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, processItem->VmCounters.PagefileUsage);\n            //PhAddItemCircularBuffer_SIZE_T(&processItem->WorkingSetHistory, processItem->VmCounters.WorkingSetSize);\n\n            if (InterlockedExchange(&processItem->JustProcessed, 0) != 0)\n                modified = TRUE;\n\n            if (PhEnableCycleCpuUsage)\n            {\n                ULONG64 totalDelta;\n\n                newCpuUsage = (FLOAT)processItem->CycleTimeDelta.Delta / sysTotalCycleTime;\n\n                // Calculate the kernel/user CPU usage based on the kernel/user time. If the kernel\n                // and user deltas are both zero, we'll just have to use an estimate. Currently, we\n                // split the CPU usage evenly across the kernel and user components, except when the\n                // total user time is zero, in which case we assign it all to the kernel component.\n\n                totalDelta = processItem->CpuKernelDelta.Delta + processItem->CpuUserDelta.Delta;\n\n                if (totalDelta != 0)\n                {\n                    kernelCpuUsage = newCpuUsage * ((FLOAT)processItem->CpuKernelDelta.Delta / totalDelta);\n                    userCpuUsage = newCpuUsage * ((FLOAT)processItem->CpuUserDelta.Delta / totalDelta);\n                }\n                else\n                {\n                    if (processItem->UserTime.QuadPart != 0)\n                    {\n                        kernelCpuUsage = newCpuUsage / 2;\n                        userCpuUsage = newCpuUsage / 2;\n                    }\n                    else\n                    {\n                        kernelCpuUsage = newCpuUsage;\n                        userCpuUsage = 0;\n                    }\n                }\n            }\n            else\n            {\n                kernelCpuUsage = (FLOAT)processItem->CpuKernelDelta.Delta / sysTotalTime;\n                userCpuUsage = (FLOAT)processItem->CpuUserDelta.Delta / sysTotalTime;\n                newCpuUsage = kernelCpuUsage + userCpuUsage;\n            }\n\n            processItem->CpuUsage = newCpuUsage;\n            processItem->CpuKernelUsage = kernelCpuUsage;\n            processItem->CpuUserUsage = userCpuUsage;\n\n            PhAddItemCircularBuffer_FLOAT(&processItem->CpuKernelHistory, kernelCpuUsage);\n            PhAddItemCircularBuffer_FLOAT(&processItem->CpuUserHistory, userCpuUsage);\n\n            // Process basic information\n            {\n                PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n\n                if (processItem->QueryHandle && NT_SUCCESS(PhGetProcessExtendedBasicInformation(processItem->QueryHandle, &basicInfo)))\n                {\n                    if (processItem->IsProtectedProcess != basicInfo.IsProtectedProcess)\n                    {\n                        processItem->IsProtectedProcess = basicInfo.IsProtectedProcess;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsSecureProcess != basicInfo.IsSecureProcess)\n                    {\n                        processItem->IsSecureProcess = basicInfo.IsSecureProcess;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsSubsystemProcess != basicInfo.IsSubsystemProcess)\n                    {\n                        processItem->IsSubsystemProcess = basicInfo.IsSubsystemProcess;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsWow64Process != basicInfo.IsWow64Process)\n                    {\n                        processItem->IsWow64Process = basicInfo.IsWow64Process;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsPackagedProcess != basicInfo.IsStronglyNamed)\n                    {\n                        processItem->IsPackagedProcess = basicInfo.IsStronglyNamed;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsCrossSessionProcess != basicInfo.IsCrossSessionCreate)\n                    {\n                        processItem->IsCrossSessionProcess = basicInfo.IsCrossSessionCreate;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsFrozenProcess != basicInfo.IsFrozen)\n                    {\n                        processItem->IsFrozenProcess = basicInfo.IsFrozen;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsBackgroundProcess != basicInfo.IsBackground)\n                    {\n                        processItem->IsBackgroundProcess = basicInfo.IsBackground;\n                        modified = TRUE;\n                    }\n                }\n                else\n                {\n                    if (processItem->IsProtectedProcess)\n                    {\n                        processItem->IsProtectedProcess = FALSE;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsSecureProcess)\n                    {\n                        processItem->IsSecureProcess = FALSE;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsSubsystemProcess)\n                    {\n                        processItem->IsSubsystemProcess = FALSE;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsWow64Process)\n                    {\n                        processItem->IsWow64Process = FALSE;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsPackagedProcess)\n                    {\n                        processItem->IsPackagedProcess = FALSE;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsCrossSessionProcess)\n                    {\n                        processItem->IsCrossSessionProcess = FALSE;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsFrozenProcess)\n                    {\n                        processItem->IsFrozenProcess = FALSE;\n                        modified = TRUE;\n                    }\n                    if (processItem->IsBackgroundProcess)\n                    {\n                        processItem->IsBackgroundProcess = FALSE;\n                        modified = TRUE;\n                    }\n                }\n            }\n\n            // Affinity, usually not frequently changed, do so lazily.\n            if (runCount % 5 == 0)\n            {\n                ULONG affinityPopulationCount = 0;\n\n                if (PhSystemProcessorInformation.SingleProcessorGroup)\n                {\n                    KAFFINITY affinityMask;\n\n                    if (processItem->QueryHandle && NT_SUCCESS(PhGetProcessAffinityMask(processItem->QueryHandle, &affinityMask)))\n                    {\n                        processItem->AffinityMaskSingle = affinityMask;\n                        affinityPopulationCount = PhCountBitsUlongPtr(processItem->AffinityMaskSingle);\n                    }\n                    else\n                    {\n                        processItem->AffinityMaskSingle = PhSystemProcessorInformation.ActiveProcessorsAffinityMasks[0];\n                        affinityPopulationCount = PhCountBitsUlongPtr(processItem->AffinityMaskSingle);\n                    }\n                }\n                else\n                {\n                    for (USHORT i = 0; i < PhSystemProcessorInformation.NumberOfProcessorGroups; i++)\n                    {\n                        GROUP_AFFINITY affinity;\n\n                        RtlZeroMemory(&affinity, sizeof(GROUP_AFFINITY));\n                        affinity.Group = i;\n\n                        if (processItem->QueryHandle && NT_SUCCESS(PhGetProcessGroupAffinity(processItem->QueryHandle, &affinity)))\n                            processItem->AffinityMaskGroups[i] = affinity.Mask;\n                        else\n                            processItem->AffinityMaskGroups[i] = PhSystemProcessorInformation.ActiveProcessorsAffinityMasks[i];\n\n                        affinityPopulationCount += PhCountBitsUlongPtr(processItem->AffinityMaskGroups[i]);\n                    }\n                }\n\n                if (processItem->AffinityPopulationCount != affinityPopulationCount)\n                {\n                    processItem->AffinityPopulationCount = affinityPopulationCount;\n                    modified = TRUE;\n                }\n            }\n\n            // Average\n            if (FlagOn(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_AVERAGE))\n            {\n                FLOAT value = 0.0f;\n\n                for (ULONG i = 0; i < processItem->CpuKernelHistory.Count; i++)\n                {\n                    value += PhGetItemCircularBuffer_FLOAT(&processItem->CpuKernelHistory, i) +\n                        PhGetItemCircularBuffer_FLOAT(&processItem->CpuUserHistory, i);\n                }\n\n                if (processItem->CpuKernelHistory.Count)\n                    processItem->CpuAverageUsage = (FLOAT)value / (FLOAT)processItem->CpuKernelHistory.Count;\n                else\n                    processItem->CpuAverageUsage = 0.0f;\n            }\n\n            // Max. values\n\n            if (processItem->ProcessId)\n            {\n                if (maxCpuValue < newCpuUsage)\n                {\n                    maxCpuValue = newCpuUsage;\n                    maxCpuProcessItem = processItem;\n                }\n\n                // I/O for Other is not included because it is too generic.\n                if (maxIoValue < processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta)\n                {\n                    maxIoValue = processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta;\n                    maxIoProcessItem = processItem;\n                }\n            }\n\n            // Token information\n            if (\n                processItem->QueryHandle &&\n                processItem->ProcessId != SYSTEM_PROCESS_ID // System token can't be opened on XP (wj32)\n                )\n            {\n                HANDLE tokenHandle;\n\n                if (NT_SUCCESS(PhOpenProcessToken(\n                    processItem->QueryHandle,\n                    TOKEN_QUERY,\n                    &tokenHandle\n                    )))\n                {\n                    PH_TOKEN_USER tokenUser;\n                    //BOOLEAN isElevated;\n                    //TOKEN_ELEVATION_TYPE elevationType;\n                    PH_INTEGRITY_LEVEL integrityLevel;\n                    PPH_STRINGREF integrityString;\n\n                    if (FlagOn(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_USERNAME))\n                    {\n                        // User\n                        if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser)))\n                        {\n                            if (!processItem->Sid || !PhEqualSid(processItem->Sid, tokenUser.User.Sid))\n                            {\n                                PSID processSid;\n\n                                // HACK (dmex)\n                                processSid = processItem->Sid;\n                                processItem->Sid = PhAllocateCopy(tokenUser.User.Sid, PhLengthSid(tokenUser.User.Sid));\n                                if (processSid) PhFree(processSid);\n\n                                if (processItem->Sid)\n                                {\n                                    PPH_STRING resolvedName;\n\n                                    // Try cache\n                                    if (resolvedName = PhpGetSidFullNameCached(processItem->Sid))\n                                    {\n                                        PhMoveReference(&processItem->UserName, resolvedName);\n                                    }\n                                    else\n                                    {\n                                        // Queue for bulk resolution\n                                        PhpQueueSidForBulkResolution(processItem->Sid);\n                                    }\n                                }\n\n                                modified = TRUE;\n                            }\n                            else\n                            {\n                                if (processItem->Sid && PhIsNullOrEmptyString(processItem->UserName))\n                                {\n                                    PPH_STRING resolvedName;\n\n                                    // Try cache\n                                    if (resolvedName = PhpGetSidFullNameCached(processItem->Sid))\n                                    {\n                                        PhMoveReference(&processItem->UserName, resolvedName);\n                                        modified = TRUE;\n                                    }\n                                    else\n                                    {\n                                        // Queue for bulk resolution\n                                        PhpQueueSidForBulkResolution(processItem->Sid);\n                                    }\n                                }\n                            }\n                        }\n                    }\n\n                    // Elevation\n\n                    //if (NT_SUCCESS(PhGetTokenElevation(tokenHandle, &isElevated)))\n                    //{\n                    //    if (processItem->IsElevated != isElevated)\n                    //    {\n                    //        processItem->IsElevated = isElevated;\n                    //        modified = TRUE;\n                    //    }\n                    //}\n                    //\n                    //if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType)))\n                    //{\n                    //    if (processItem->ElevationType != elevationType)\n                    //    {\n                    //        processItem->ElevationType = elevationType;\n                    //        modified = TRUE;\n                    //    }\n                    //}\n\n                    // Integrity\n                    if (NT_SUCCESS(PhGetTokenIntegrityLevelEx(tokenHandle, &integrityLevel, &integrityString)))\n                    {\n                        if (processItem->IntegrityLevel.Level != integrityLevel.Level)\n                        {\n                            processItem->IntegrityLevel = integrityLevel;\n                            processItem->IntegrityString = integrityString;\n                            modified = TRUE;\n                        }\n                    }\n\n                    NtClose(tokenHandle);\n                }\n            }\n            else\n            {\n                if (FlagOn(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_USERNAME))\n                {\n                    if (processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID ||\n                        processItem->ProcessId == SYSTEM_PROCESS_ID)\n                    {\n                        if (PhIsNullOrEmptyString(processItem->UserName))\n                        {\n                            PPH_STRING resolvedName;\n\n                            // Try cache or fallback to slow lookup\n                            if (resolvedName = PhpGetSidFullNameCached((PSID)&PhSeLocalSystemSid))\n                            {\n                                PhMoveReference(&processItem->UserName, resolvedName);\n                            }\n                            else\n                            {\n                                PhMoveReference(&processItem->UserName, PhpGetSidFullNameCachedSlow((PSID)&PhSeLocalSystemSid));\n                            }\n\n                            modified = TRUE;\n                        }\n                    }\n                }\n            }\n\n            // Control Flow Guard\n            if (WindowsVersion >= WINDOWS_8_1 && processItem->QueryHandle && FlagOn(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_CFGUARD))\n            {\n                BOOLEAN cfguardEnabled;\n\n                if (NT_SUCCESS(PhGetProcessIsCFGuardEnabled(processItem->QueryHandle, &cfguardEnabled)))\n                {\n                    if (processItem->IsControlFlowGuardEnabled != cfguardEnabled)\n                    {\n                        processItem->IsControlFlowGuardEnabled = cfguardEnabled;\n                        modified = TRUE;\n                    }\n                }\n\n                if (WindowsVersion >= WINDOWS_11)\n                {\n                    BOOLEAN xfguardEnabled;\n                    BOOLEAN xfguardAuditEnabled;\n\n                    if (NT_SUCCESS(PhGetProcessIsXFGuardEnabled(processItem->QueryHandle, &xfguardEnabled, &xfguardAuditEnabled)))\n                    {\n                        if (processItem->IsXfgEnabled != xfguardEnabled)\n                        {\n                            processItem->IsXfgEnabled = xfguardEnabled;\n                            modified = TRUE;\n                        }\n\n                        if (processItem->IsXfgAuditEnabled != xfguardAuditEnabled)\n                        {\n                            processItem->IsXfgAuditEnabled = xfguardAuditEnabled;\n                            modified = TRUE;\n                        }\n                    }\n                }\n            }\n\n            // CET\n            if (WindowsVersion >= WINDOWS_10_20H1 && FlagOn(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_CET))\n            {\n                if (processItem->ProcessId == SYSTEM_PROCESS_ID)\n                {\n                    SYSTEM_SHADOW_STACK_INFORMATION shadowStackInformation;\n\n                    if (NT_SUCCESS(PhGetSystemShadowStackInformation(&shadowStackInformation)))\n                    {\n                        if (processItem->IsCetEnabled != shadowStackInformation.KernelCetEnabled)\n                        {\n                            processItem->IsCetEnabled = shadowStackInformation.KernelCetEnabled;\n                            modified = TRUE;\n                        }\n                    }\n                }\n                else\n                {\n                    if (processItem->QueryHandle)\n                    {\n                        BOOLEAN cetEnabled;\n                        BOOLEAN cetStrictModeEnabled;\n\n                        if (NT_SUCCESS(PhGetProcessIsCetEnabled(processItem->QueryHandle, &cetEnabled, &cetStrictModeEnabled)))\n                        {\n                            if (processItem->IsCetEnabled != cetEnabled)\n                            {\n                                processItem->IsCetEnabled = cetEnabled;\n                                modified = TRUE;\n                            }\n                        }\n                    }\n                }\n            }\n\n            // Job\n            if (processItem->QueryHandle)\n            {\n                BOOLEAN isInSignificantJob = FALSE;\n                BOOLEAN isInJob = FALSE;\n\n                if (KsiLevel() >= KphLevelMed)\n                {\n                    HANDLE jobHandle = NULL;\n\n                    status = KphOpenProcessJob(\n                        processItem->QueryHandle,\n                        JOB_OBJECT_QUERY,\n                        &jobHandle\n                        );\n\n                    if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB)\n                    {\n                        JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimits;\n\n                        isInJob = TRUE;\n\n                        if (NT_SUCCESS(PhGetJobBasicLimits(jobHandle, &basicLimits)))\n                        {\n                            isInSignificantJob = basicLimits.LimitFlags != JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;\n                        }\n                    }\n\n                    if (jobHandle)\n                        NtClose(jobHandle);\n                }\n                else\n                {\n                    status = NtIsProcessInJob(processItem->QueryHandle, NULL);\n\n                    if (NT_SUCCESS(status))\n                        isInJob = status == STATUS_PROCESS_IN_JOB;\n                }\n\n                if (processItem->IsInSignificantJob != isInSignificantJob)\n                {\n                    processItem->IsInSignificantJob = isInSignificantJob;\n                    modified = TRUE;\n                }\n\n                if (processItem->IsInJob != isInJob)\n                {\n                    processItem->IsInJob = isInJob;\n                    modified = TRUE;\n                }\n            }\n\n            // Debugged\n            if (\n                processItem->QueryHandle &&\n                !processItem->IsSubsystemProcess &&\n                !processItem->IsProtectedHandle && // Don't query the debug object if the handle was filtered (dmex)\n                processItem->ProcessId != SYSTEM_PROCESS_ID // Ignore the system process on 20H2 (dmex)\n                )\n            {\n                BOOLEAN isBeingDebugged = FALSE;\n\n                PhGetProcessIsBeingDebugged(processItem->QueryHandle, &isBeingDebugged);\n\n                if (processItem->IsBeingDebugged != isBeingDebugged)\n                {\n                    processItem->IsBeingDebugged = isBeingDebugged;\n                    modified = TRUE;\n                }\n            }\n\n            // Process Throttling State\n            {\n                BOOLEAN isPowerThrottling = FALSE;\n\n                if (processItem->QueryHandle && !processItem->IsSubsystemProcess)\n                {\n                    POWER_THROTTLING_PROCESS_STATE powerThrottlingState;\n\n                    if (NT_SUCCESS(PhGetProcessPowerThrottlingState(processItem->QueryHandle, &powerThrottlingState)))\n                    {\n                        if (FlagOn(powerThrottlingState.ControlMask, POWER_THROTTLING_PROCESS_EXECUTION_SPEED) &&\n                            FlagOn(powerThrottlingState.StateMask, POWER_THROTTLING_PROCESS_EXECUTION_SPEED))\n                        {\n                            isPowerThrottling = TRUE;\n                        }\n\n                        if (FlagOn(powerThrottlingState.ControlMask, POWER_THROTTLING_PROCESS_DELAYTIMERS) &&\n                            FlagOn(powerThrottlingState.StateMask, POWER_THROTTLING_PROCESS_DELAYTIMERS))\n                        {\n                            isPowerThrottling = TRUE;\n                        }\n\n                        if (FlagOn(powerThrottlingState.ControlMask, POWER_THROTTLING_PROCESS_IGNORE_TIMER_RESOLUTION) &&\n                            FlagOn(powerThrottlingState.StateMask, POWER_THROTTLING_PROCESS_IGNORE_TIMER_RESOLUTION))\n                        {\n                            isPowerThrottling = TRUE;\n                        }\n                    }\n                }\n\n                if (processItem->IsPowerThrottling != isPowerThrottling)\n                {\n                    processItem->IsPowerThrottling = isPowerThrottling;\n                    modified = TRUE;\n                }\n            }\n\n            // Suspended\n            if (processItem->IsSuspended != isSuspended)\n            {\n                processItem->IsSuspended = isSuspended;\n                modified = TRUE;\n            }\n\n            if (PhCsUseColorPartiallySuspended) // HACK // Don't invalidate for partially suspended unless enabled (dmex)\n            {\n                if (processItem->IsPartiallySuspended != isPartiallySuspended)\n                {\n                    processItem->IsPartiallySuspended = isPartiallySuspended;\n                    modified = TRUE;\n                }\n            }\n            else\n            {\n                processItem->IsPartiallySuspended = isPartiallySuspended;\n            }\n\n            // .NET\n            if (processItem->UpdateIsDotNet)\n            {\n                BOOLEAN isDotNet;\n                ULONG flags = 0;\n\n                if (NT_SUCCESS(PhGetProcessIsDotNetEx(processItem->ProcessId, NULL, 0, &isDotNet, &flags)))\n                {\n                    processItem->IsDotNet = isDotNet;\n                    modified = TRUE;\n                }\n\n                processItem->UpdateIsDotNet = FALSE;\n            }\n\n            // Immersive\n            // if (processItem->QueryHandle && WindowsVersion >= WINDOWS_8 && !processItem->IsSubsystemProcess)\n            // {\n            //     BOOLEAN isImmersive;\n            //\n            //     isImmersive = PhIsImmersiveProcess(processItem->QueryHandle);\n            //\n            //     if (processItem->IsImmersive != isImmersive)\n            //     {\n            //         processItem->IsImmersive = isImmersive;\n            //         modified = TRUE;\n            //     }\n            // }\n\n            if (processItem->QueryHandle && processItem->IsHandleValid)\n            {\n                OBJECT_BASIC_INFORMATION basicInfo;\n                BOOLEAN filteredHandle = FALSE;\n\n                if (NT_SUCCESS(PhQueryObjectBasicInformation(processItem->QueryHandle, &basicInfo)))\n                {\n                    if (!RtlAreAllAccessesGranted(basicInfo.GrantedAccess, PROCESS_QUERY_INFORMATION))\n                    {\n                        filteredHandle = TRUE;\n                    }\n                }\n                else\n                {\n                    filteredHandle = TRUE;\n                }\n\n                if (processItem->IsProtectedHandle != filteredHandle)\n                {\n                    processItem->IsProtectedHandle = filteredHandle;\n                    modified = TRUE;\n                }\n            }\n\n            if (modified)\n            {\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderModifiedEvent), processItem);\n            }\n\n            // No reference added by PhpLookupProcessItem.\n        }\n\n        // Trick ourselves into thinking that the fake processes\n        // are on the list.\n        if (process == PhInterruptsProcessInformation)\n        {\n            process = NULL;\n        }\n        else if (process == PhDpcsProcessInformation)\n        {\n            process = PhInterruptsProcessInformation;\n        }\n        else\n        {\n            process = PH_NEXT_PROCESS(process);\n\n            if (process == NULL)\n            {\n                if (PhEnableCycleCpuUsage)\n                    process = PhInterruptsProcessInformation;\n                else\n                    process = PhDpcsProcessInformation;\n            }\n        }\n    }\n\n    if (PhProcessInformation)\n        PhFree(PhProcessInformation);\n\n    PhProcessInformation = processes;\n\n    // History cannot be updated on the first run because the deltas are invalid. For example, the\n    // I/O \"deltas\" will be huge because they are currently the raw accumulated values.\n    if (runCount != 0)\n    {\n        if (PhEnableCycleCpuUsage)\n            PhpUpdateCpuCycleUsageInformation(sysTotalCycleTime, sysIdleCycleTime);\n\n        PhpUpdateSystemHistory();\n\n        // Note that we need to add a reference to the records of these processes, to make it\n        // possible for others to get the name of a max. CPU or I/O process.\n\n        if (maxCpuProcessItem)\n        {\n            PhAddItemCircularBuffer_ULONG(&PhMaxCpuHistory, HandleToUlong(maxCpuProcessItem->ProcessId));\n#ifdef PH_RECORD_MAX_USAGE\n            PhAddItemCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, maxCpuProcessItem->CpuUsage);\n#endif\n\n            if (!(maxCpuProcessItem->Record->Flags & PH_PROCESS_RECORD_STAT_REF))\n            {\n                PhReferenceProcessRecord(maxCpuProcessItem->Record);\n                maxCpuProcessItem->Record->Flags |= PH_PROCESS_RECORD_STAT_REF;\n            }\n        }\n        else\n        {\n            PhAddItemCircularBuffer_ULONG(&PhMaxCpuHistory, PtrToUlong(NULL));\n#ifdef PH_RECORD_MAX_USAGE\n            PhAddItemCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, 0);\n#endif\n        }\n\n        if (maxIoProcessItem)\n        {\n            PhAddItemCircularBuffer_ULONG(&PhMaxIoHistory, HandleToUlong(maxIoProcessItem->ProcessId));\n#ifdef PH_RECORD_MAX_USAGE\n            PhAddItemCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory,\n                maxIoProcessItem->IoReadDelta.Delta + maxIoProcessItem->IoOtherDelta.Delta);\n            PhAddItemCircularBuffer_ULONG64(&PhMaxIoWriteHistory, maxIoProcessItem->IoWriteDelta.Delta);\n#endif\n\n            if (!(maxIoProcessItem->Record->Flags & PH_PROCESS_RECORD_STAT_REF))\n            {\n                PhReferenceProcessRecord(maxIoProcessItem->Record);\n                maxIoProcessItem->Record->Flags |= PH_PROCESS_RECORD_STAT_REF;\n            }\n        }\n        else\n        {\n            PhAddItemCircularBuffer_ULONG(&PhMaxIoHistory, PtrToUlong(NULL));\n#ifdef PH_RECORD_MAX_USAGE\n            PhAddItemCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, 0);\n            PhAddItemCircularBuffer_ULONG64(&PhMaxIoWriteHistory, 0);\n#endif\n        }\n    }\n\n    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), UlongToPtr(runCount));\n\n    PhTraceFuncExit(\"Process provider run count: %lu\", runCount);\n\n    runCount++;\n}\n\nPPH_PROCESS_RECORD PhpCreateProcessRecord(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_PROCESS_RECORD processRecord;\n\n    processRecord = PhAllocate(sizeof(PH_PROCESS_RECORD));\n    memset(processRecord, 0, sizeof(PH_PROCESS_RECORD));\n\n    InitializeListHead(&processRecord->ListEntry);\n    processRecord->RefCount = 1;\n\n    processRecord->ProcessId = ProcessItem->ProcessId;\n    processRecord->ParentProcessId = ProcessItem->ParentProcessId;\n    processRecord->SessionId = ProcessItem->SessionId;\n    processRecord->ProcessSequenceNumber = ProcessItem->ProcessSequenceNumber;\n    processRecord->CreateTime = ProcessItem->CreateTime;\n\n    PhSetReference(&processRecord->ProcessName, ProcessItem->ProcessName);\n    PhSetReference(&processRecord->FileName, ProcessItem->FileName);\n    PhSetReference(&processRecord->CommandLine, ProcessItem->CommandLine);\n    //PhSetReference(&processRecord->UserName, ProcessItem->UserName);\n\n    return processRecord;\n}\n\nPPH_PROCESS_RECORD PhpSearchProcessRecordList(\n    _In_ PLARGE_INTEGER Time,\n    _Out_opt_ PULONG Index,\n    _Out_opt_ PULONG InsertIndex\n    )\n{\n    PPH_PROCESS_RECORD processRecord;\n    LONG low;\n    LONG high;\n    LONG i;\n    BOOLEAN found = FALSE;\n    INT comparison;\n\n    if (PhProcessRecordList->Count == 0)\n    {\n        if (Index)\n            *Index = 0;\n        if (InsertIndex)\n            *InsertIndex = 0;\n\n        return NULL;\n    }\n\n    low = 0;\n    high = PhProcessRecordList->Count - 1;\n\n    // Do a binary search.\n    do\n    {\n        i = (low + high) / 2;\n        processRecord = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i];\n\n        comparison = uint64cmp(Time->QuadPart, processRecord->CreateTime.QuadPart);\n\n        if (comparison == 0)\n        {\n            found = TRUE;\n            break;\n        }\n        else if (comparison < 0)\n        {\n            high = i - 1;\n        }\n        else\n        {\n            low = i + 1;\n        }\n    } while (low <= high);\n\n    if (Index)\n        *Index = i;\n\n    if (found)\n    {\n        if (InsertIndex)\n            *InsertIndex = 0;\n\n        return processRecord;\n    }\n    else\n    {\n        if (InsertIndex)\n            *InsertIndex = i + (comparison > 0);\n\n        return NULL;\n    }\n}\n\nVOID PhpAddProcessRecord(\n    _Inout_ PPH_PROCESS_RECORD ProcessRecord\n    )\n{\n    PPH_PROCESS_RECORD processRecord;\n    ULONG insertIndex;\n\n    PhAcquireQueuedLockExclusive(&PhProcessRecordListLock);\n\n    processRecord = PhpSearchProcessRecordList(&ProcessRecord->CreateTime, NULL, &insertIndex);\n\n    if (!processRecord)\n    {\n        // Insert the process record, keeping the list sorted.\n        PhInsertItemList(PhProcessRecordList, insertIndex, ProcessRecord);\n    }\n    else\n    {\n        // Link the process record with the existing one that we found.\n        InsertTailList(&processRecord->ListEntry, &ProcessRecord->ListEntry);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhProcessRecordListLock);\n}\n\nVOID PhpRemoveProcessRecord(\n    _Inout_ PPH_PROCESS_RECORD ProcessRecord\n    )\n{\n    ULONG i;\n    PPH_PROCESS_RECORD headProcessRecord;\n\n    PhAcquireQueuedLockExclusive(&PhProcessRecordListLock);\n\n    headProcessRecord = PhpSearchProcessRecordList(&ProcessRecord->CreateTime, &i, NULL);\n    assert(headProcessRecord);\n\n    // Unlink the record from the list.\n    RemoveEntryList(&ProcessRecord->ListEntry);\n\n    if (ProcessRecord == headProcessRecord)\n    {\n        // Remove the slot completely, or choose a new head record.\n        if (IsListEmpty(&headProcessRecord->ListEntry))\n            PhRemoveItemList(PhProcessRecordList, i);\n        else\n            PhProcessRecordList->Items[i] = CONTAINING_RECORD(headProcessRecord->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhProcessRecordListLock);\n}\n\nVOID PhReferenceProcessRecord(\n    _In_ PPH_PROCESS_RECORD ProcessRecord\n    )\n{\n    _InterlockedIncrement(&ProcessRecord->RefCount);\n}\n\nBOOLEAN PhReferenceProcessRecordSafe(\n    _In_ PPH_PROCESS_RECORD ProcessRecord\n    )\n{\n    return _InterlockedIncrementNoZero(&ProcessRecord->RefCount);\n}\n\nVOID PhReferenceProcessRecordForStatistics(\n    _In_ PPH_PROCESS_RECORD ProcessRecord\n    )\n{\n    if (!(ProcessRecord->Flags & PH_PROCESS_RECORD_STAT_REF))\n    {\n        PhReferenceProcessRecord(ProcessRecord);\n        ProcessRecord->Flags |= PH_PROCESS_RECORD_STAT_REF;\n    }\n}\n\nVOID PhDereferenceProcessRecord(\n    _In_ PPH_PROCESS_RECORD ProcessRecord\n    )\n{\n    if (_InterlockedDecrement(&ProcessRecord->RefCount) == 0)\n    {\n        PhpRemoveProcessRecord(ProcessRecord);\n\n        PhDereferenceObject(ProcessRecord->ProcessName);\n        if (ProcessRecord->FileName) PhDereferenceObject(ProcessRecord->FileName);\n        if (ProcessRecord->CommandLine) PhDereferenceObject(ProcessRecord->CommandLine);\n        /*if (ProcessRecord->UserName) PhDereferenceObject(ProcessRecord->UserName);*/\n        PhFree(ProcessRecord);\n    }\n}\n\nPPH_PROCESS_RECORD PhpFindProcessRecord(\n    _In_ PPH_PROCESS_RECORD ProcessRecord,\n    _In_ HANDLE ProcessId\n    )\n{\n    PPH_PROCESS_RECORD startProcessRecord;\n\n    startProcessRecord = ProcessRecord;\n\n    do\n    {\n        if (ProcessRecord->ProcessId == ProcessId)\n            return ProcessRecord;\n\n        ProcessRecord = CONTAINING_RECORD(ProcessRecord->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry);\n    } while (ProcessRecord != startProcessRecord);\n\n    return NULL;\n}\n\n/**\n * Finds a process record.\n *\n * \\param ProcessId The ID of the process.\n * \\param Time A time in which the process was active.\n *\n * \\return The newest record older than \\a Time, or NULL\n * if the record could not be found. You must call\n * PhDereferenceProcessRecord() when you no longer need\n * the record.\n */\nPPH_PROCESS_RECORD PhFindProcessRecord(\n    _In_opt_ HANDLE ProcessId,\n    _In_ PLARGE_INTEGER Time\n    )\n{\n    PPH_PROCESS_RECORD processRecord;\n    ULONG i;\n    BOOLEAN found;\n\n    if (PhProcessRecordList->Count == 0)\n        return NULL;\n\n    PhAcquireQueuedLockShared(&PhProcessRecordListLock);\n\n    processRecord = PhpSearchProcessRecordList(Time, &i, NULL);\n\n    if (!processRecord)\n    {\n        // This is expected. Now we search backwards to find the newest matching element older than\n        // the given time.\n\n        found = FALSE;\n\n        while (TRUE)\n        {\n            processRecord = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i];\n\n            if (processRecord->CreateTime.QuadPart < Time->QuadPart)\n            {\n                if (ProcessId)\n                {\n                    processRecord = PhpFindProcessRecord(processRecord, ProcessId);\n\n                    if (processRecord)\n                        found = TRUE;\n                }\n                else\n                {\n                    found = TRUE;\n                }\n\n                if (found)\n                    break;\n            }\n\n            if (i == 0)\n                break;\n\n            i--;\n        }\n    }\n    else\n    {\n        if (ProcessId)\n        {\n            processRecord = PhpFindProcessRecord(processRecord, ProcessId);\n\n            if (processRecord)\n                found = TRUE;\n            else\n                found = FALSE;\n        }\n        else\n        {\n            found = TRUE;\n        }\n    }\n\n    if (found)\n    {\n        // The record might have had its last reference just cleared but it hasn't been removed from\n        // the list yet.\n        if (!PhReferenceProcessRecordSafe(processRecord))\n            found = FALSE;\n    }\n\n    PhReleaseQueuedLockShared(&PhProcessRecordListLock);\n\n    if (found)\n        return processRecord;\n    else\n        return NULL;\n}\n\n/**\n * Deletes unused process records.\n */\nVOID PhPurgeProcessRecords(\n    VOID\n    )\n{\n    PPH_PROCESS_RECORD processRecord;\n    PPH_PROCESS_RECORD startProcessRecord;\n    ULONG i;\n    LARGE_INTEGER threshold;\n    PPH_LIST derefList = NULL;\n\n    if (PhProcessRecordList->Count == 0)\n        return;\n\n    // Get the oldest statistics time.\n    PhGetStatisticsTime(NULL, PhTimeHistory.Count - 1, &threshold);\n\n    PhAcquireQueuedLockShared(&PhProcessRecordListLock);\n\n    for (i = 0; i < PhProcessRecordList->Count; i++)\n    {\n        processRecord = PhProcessRecordList->Items[i];\n        startProcessRecord = processRecord;\n\n        do\n        {\n            ULONG requiredFlags;\n\n            requiredFlags = PH_PROCESS_RECORD_DEAD | PH_PROCESS_RECORD_STAT_REF;\n\n            if ((processRecord->Flags & requiredFlags) == requiredFlags)\n            {\n                // Check if the process exit time is before the oldest statistics time. If so we can\n                // dereference the process record.\n                if (processRecord->ExitTime.QuadPart < threshold.QuadPart)\n                {\n                    // Clear the stat ref bit; this is to make sure we don't try to dereference the\n                    // record twice (e.g. if someone else currently holds a reference to the record\n                    // and it doesn't get removed immediately).\n                    processRecord->Flags &= ~PH_PROCESS_RECORD_STAT_REF;\n\n                    if (!derefList)\n                        derefList = PhCreateList(2);\n\n                    if (derefList)\n                    {\n                        PhAddItemList(derefList, processRecord);\n                    }\n                }\n            }\n\n            processRecord = CONTAINING_RECORD(processRecord->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry);\n        } while (processRecord != startProcessRecord);\n    }\n\n    PhReleaseQueuedLockShared(&PhProcessRecordListLock);\n\n    if (derefList)\n    {\n        for (i = 0; i < derefList->Count; i++)\n        {\n            PhDereferenceProcessRecord(derefList->Items[i]);\n        }\n\n        PhDereferenceObject(derefList);\n    }\n}\n\nPPH_PROCESS_ITEM PhReferenceProcessItemForParent(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_PROCESS_ITEM parentProcessItem;\n\n    if (ProcessItem->ParentProcessId == ProcessItem->ProcessId) // for cases where the parent PID = PID (e.g. System Idle Process)\n        return NULL;\n\n    PhAcquireQueuedLockShared(&PhProcessHashSetLock);\n\n    parentProcessItem = PhpLookupProcessItem(ProcessItem->ParentProcessId);\n\n    if (PhEnableProcessExtension)\n    {\n        // We make sure that the process item we found is actually the parent process - its sequence number\n        // must not be higher than the supplied sequence.\n        if (parentProcessItem && parentProcessItem->ProcessSequenceNumber <= ProcessItem->ProcessSequenceNumber)\n            PhReferenceObject(parentProcessItem);\n        else\n            parentProcessItem = NULL;\n    }\n    else\n    {\n        // We make sure that the process item we found is actually the parent process - its start time\n        // must not be larger than the supplied time.\n        if (parentProcessItem && parentProcessItem->CreateTime.QuadPart <= ProcessItem->CreateTime.QuadPart)\n            PhReferenceObject(parentProcessItem);\n        else\n            parentProcessItem = NULL;\n    }\n\n    PhReleaseQueuedLockShared(&PhProcessHashSetLock);\n\n    return parentProcessItem;\n}\n\nPPH_PROCESS_ITEM PhReferenceProcessItemForRecord(\n    _In_ PPH_PROCESS_RECORD Record\n    )\n{\n    PPH_PROCESS_ITEM processItem;\n\n    PhAcquireQueuedLockShared(&PhProcessHashSetLock);\n\n    processItem = PhpLookupProcessItem(Record->ProcessId);\n\n    if (PhEnableProcessExtension)\n    {\n        if (processItem && processItem->ProcessSequenceNumber == Record->ProcessSequenceNumber)\n            PhReferenceObject(processItem);\n        else\n            processItem = NULL;\n    }\n    else\n    {\n        if (processItem && processItem->CreateTime.QuadPart == Record->CreateTime.QuadPart)\n            PhReferenceObject(processItem);\n        else\n            processItem = NULL;\n    }\n\n    PhReleaseQueuedLockShared(&PhProcessHashSetLock);\n\n    return processItem;\n}\n\nPPH_HASHTABLE PhImageListCacheHashtable = NULL;\nPH_QUEUED_LOCK PhImageListCacheHashtableLock = PH_QUEUED_LOCK_INIT;\nHIMAGELIST PhProcessLargeImageList = NULL;\nHIMAGELIST PhProcessSmallImageList = NULL;\nPPH_OBJECT_TYPE PhImageListItemType = NULL;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpImageListItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_IMAGELIST_ITEM entry = (PPH_IMAGELIST_ITEM)Object;\n    // TODO: Remove TN_CACHE from TreeNewGetNodeIcon so we're\n    // able to sync the updated image index after ImageList_Remove. (dmex)\n    //ULONG LargeIconIndex = entry->LargeIconIndex;\n    //ULONG SmallIconIndex = entry->SmallIconIndex;\n    //PPH_PROCESS_ITEM* processes;\n    //ULONG numberOfProcesses;\n    //\n    //PhEnumProcessItems(&processes, &numberOfProcesses);\n    //\n    //for (ULONG i = 0; i < numberOfProcesses; i++)\n    //{\n    //    PPH_PROCESS_ITEM process = processes[i];\n    //\n    //    if (\n    //        process->LargeIconIndex > LargeIconIndex &&\n    //        process->SmallIconIndex > SmallIconIndex\n    //        )\n    //    {\n    //        process->LargeIconIndex -= 1;\n    //        process->SmallIconIndex -= 1;\n    //    }\n    //}\n    //\n    //PhFree(processes);\n    //\n    //ImageList_Remove(PhProcessLargeImageList, LargeIconIndex);\n    //ImageList_Remove(PhProcessSmallImageList, SmallIconIndex);\n    //\n    PhDereferenceObject(entry->FileName);\n}\n\nVOID PhProcessImageListInitialization(\n    _In_ HWND WindowHandle,\n    _In_ LONG WindowDpi\n    )\n{\n    HICON iconSmall;\n    HICON iconLarge;\n    PPH_LIST fileNames = NULL;\n\n    PhAcquireQueuedLockExclusive(&PhImageListCacheHashtableLock);\n\n    if (!PhImageListItemType)\n        PhImageListItemType = PhCreateObjectType(L\"ImageListItem\", 0, PhpImageListItemDeleteProcedure);\n\n    PhProcessImageListWindowDpi = WindowDpi;\n\n    {\n        PH_HASHTABLE_ENUM_CONTEXT enumContext;\n        PPH_IMAGELIST_ITEM* entry;\n\n        if (PhImageListCacheHashtable)\n        {\n            fileNames = PhCreateList(PhImageListCacheHashtable->Count);\n\n            PhBeginEnumHashtable(PhImageListCacheHashtable, &enumContext);\n\n            while (entry = PhNextEnumHashtable(&enumContext))\n            {\n                PPH_IMAGELIST_ITEM item = *entry;\n                PhAddItemList(fileNames, PhReferenceObject(item->FileName));\n                PhDereferenceObject(item);\n            }\n\n            PhDereferenceObject(PhImageListCacheHashtable);\n            PhImageListCacheHashtable = NULL;\n        }\n    }\n\n    if (PhProcessLargeImageList)\n    {\n        PhImageListSetIconSize(\n            PhProcessLargeImageList,\n            PhGetSystemMetrics(SM_CXICON, PhProcessImageListWindowDpi),\n            PhGetSystemMetrics(SM_CYICON, PhProcessImageListWindowDpi)\n            );\n    }\n    else\n    {\n        PhProcessLargeImageList = PhImageListCreate(\n            PhGetSystemMetrics(SM_CXICON, PhProcessImageListWindowDpi),\n            PhGetSystemMetrics(SM_CYICON, PhProcessImageListWindowDpi),\n            ILC_MASK | ILC_COLOR32,\n            100,\n            100);\n    }\n\n    if (PhProcessSmallImageList)\n    {\n        PhImageListSetIconSize(\n            PhProcessSmallImageList,\n            PhGetSystemMetrics(SM_CXSMICON, PhProcessImageListWindowDpi),\n            PhGetSystemMetrics(SM_CYSMICON, PhProcessImageListWindowDpi)\n            );\n    }\n    else\n    {\n        PhProcessSmallImageList = PhImageListCreate(\n            PhGetSystemMetrics(SM_CXSMICON, PhProcessImageListWindowDpi),\n            PhGetSystemMetrics(SM_CYSMICON, PhProcessImageListWindowDpi),\n            ILC_MASK | ILC_COLOR32,\n            100,\n            100);\n    }\n\n    //PhImageListSetBkColor(PhProcessLargeImageList, CLR_NONE);\n    //PhImageListSetBkColor(PhProcessSmallImageList, CLR_NONE);\n\n    PhGetStockApplicationIcon(&iconSmall, &iconLarge);\n    PhImageListAddIcon(PhProcessLargeImageList, iconLarge);\n    PhImageListAddIcon(PhProcessSmallImageList, iconSmall);\n\n    iconLarge = PhLoadIcon(PhInstanceHandle, MAKEINTRESOURCE(IDI_COG), PH_LOAD_ICON_SIZE_LARGE, 0, 0, PhProcessImageListWindowDpi);\n    iconSmall = PhLoadIcon(PhInstanceHandle, MAKEINTRESOURCE(IDI_COG), PH_LOAD_ICON_SIZE_SMALL, 0, 0, PhProcessImageListWindowDpi);\n    PhImageListAddIcon(PhProcessLargeImageList, iconLarge);\n    PhImageListAddIcon(PhProcessSmallImageList, iconSmall);\n    DestroyIcon(iconLarge);\n    DestroyIcon(iconSmall);\n\n    if (fileNames)\n    {\n        for (ULONG i = 0; i < fileNames->Count; i++)\n        {\n            PPH_STRING filename = fileNames->Items[i];\n            PPH_IMAGELIST_ITEM iconEntry;\n\n            PhReleaseQueuedLockExclusive(&PhImageListCacheHashtableLock);\n\n            iconEntry = PhImageListExtractIcon(filename, TRUE, 0, NULL, PhProcessImageListWindowDpi);\n\n            PhAcquireQueuedLockExclusive(&PhImageListCacheHashtableLock);\n\n            if (iconEntry)\n            {\n                PPH_PROCESS_ITEM* processes;\n                ULONG numberOfProcesses;\n\n                PhEnumProcessItems(&processes, &numberOfProcesses);\n\n                for (ULONG j = 0; j < numberOfProcesses; j++)\n                {\n                    PPH_PROCESS_ITEM process = processes[j];\n\n                    if (process->FileName && PhEqualString(process->FileName, filename, FALSE))\n                    {\n                        process->IconEntry = PhReferenceObject(iconEntry);\n                        process->SmallIconIndex = iconEntry->SmallIconIndex;\n                        process->LargeIconIndex = iconEntry->LargeIconIndex;\n                    }\n                }\n\n                PhDereferenceObjects(processes, numberOfProcesses);\n                PhFree(processes);\n\n                PhDereferenceObject(iconEntry);\n            }\n        }\n\n        PhDereferenceObjects(fileNames->Items, fileNames->Count);\n        PhDereferenceObject(fileNames);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhImageListCacheHashtableLock);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhImageListCacheHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_IMAGELIST_ITEM entry1 = *(PPH_IMAGELIST_ITEM*)Entry1;\n    PPH_IMAGELIST_ITEM entry2 = *(PPH_IMAGELIST_ITEM*)Entry2;\n\n    return PhEqualStringRef(&entry1->FileName->sr, &entry2->FileName->sr, FALSE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhImageListCacheHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_IMAGELIST_ITEM entry = *(PPH_IMAGELIST_ITEM*)Entry;\n\n    return PhHashStringRefEx(&entry->FileName->sr, FALSE, PH_STRING_HASH_XXH32);\n}\n\nPPH_IMAGELIST_ITEM PhImageListExtractIcon(\n    _In_ PPH_STRING FileName,\n    _In_ BOOLEAN NativeFileName,\n    _In_opt_ HANDLE ProcessId,\n    _In_opt_ PPH_STRING PackageFullName,\n    _In_ LONG SystemDpi\n    )\n{\n    HICON largeIcon = NULL;\n    HICON smallIcon = NULL;\n    PPH_IMAGELIST_ITEM newentry;\n\n    PhAcquireQueuedLockShared(&PhImageListCacheHashtableLock);\n\n    if (PhImageListCacheHashtable)\n    {\n        PH_IMAGELIST_ITEM lookupEntry;\n        PPH_IMAGELIST_ITEM lookupEntryPtr = &lookupEntry;\n        PPH_IMAGELIST_ITEM* entry;\n\n        lookupEntry.FileName = FileName;\n\n        entry = (PPH_IMAGELIST_ITEM*)PhFindEntryHashtable(PhImageListCacheHashtable, &lookupEntryPtr);\n\n        if (entry)\n        {\n            PPH_IMAGELIST_ITEM foundEntry = *entry;\n\n            PhReferenceObject(foundEntry);\n\n            PhReleaseQueuedLockShared(&PhImageListCacheHashtableLock);\n\n            return foundEntry;\n        }\n    }\n\n    PhReleaseQueuedLockShared(&PhImageListCacheHashtableLock);\n\n    if (PhEnablePackageIconSupport && ProcessId && PackageFullName)\n    {\n        if (!PhAppResolverGetPackageIcon(\n            ProcessId,\n            PackageFullName,\n            &largeIcon,\n            &smallIcon,\n            SystemDpi\n            ))\n        {\n            PhExtractIconEx(\n                &FileName->sr,\n                NativeFileName,\n                0,\n                PhGetSystemMetrics(SM_CXICON, SystemDpi),\n                PhGetSystemMetrics(SM_CYICON, SystemDpi),\n                PhGetSystemMetrics(SM_CXSMICON, SystemDpi),\n                PhGetSystemMetrics(SM_CYSMICON, SystemDpi),\n                &largeIcon,\n                &smallIcon\n                );\n        }\n    }\n    else\n    {\n        PhExtractIconEx(\n            &FileName->sr,\n            NativeFileName,\n            0,\n            PhGetSystemMetrics(SM_CXICON, SystemDpi),\n            PhGetSystemMetrics(SM_CYICON, SystemDpi),\n            PhGetSystemMetrics(SM_CXSMICON, SystemDpi),\n            PhGetSystemMetrics(SM_CYSMICON, SystemDpi),\n            &largeIcon,\n            &smallIcon\n            );\n    }\n\n    PhAcquireQueuedLockExclusive(&PhImageListCacheHashtableLock);\n\n    if (!PhImageListCacheHashtable)\n    {\n        PhImageListCacheHashtable = PhCreateHashtable(\n            sizeof(PPH_IMAGELIST_ITEM),\n            PhImageListCacheHashtableEqualFunction,\n            PhImageListCacheHashtableHashFunction,\n            32\n            );\n    }\n\n    newentry = PhCreateObject(sizeof(PH_IMAGELIST_ITEM), PhImageListItemType);\n    newentry->FileName = PhReferenceObject(FileName);\n\n    if (largeIcon && smallIcon)\n    {\n        newentry->LargeIconIndex = PhImageListAddIcon(PhProcessLargeImageList, largeIcon);\n        newentry->SmallIconIndex = PhImageListAddIcon(PhProcessSmallImageList, smallIcon);\n    }\n    else\n    {\n        newentry->LargeIconIndex = 0;\n        newentry->SmallIconIndex = 0;\n    }\n\n    PhReferenceObject(newentry);\n    PhAddEntryHashtable(PhImageListCacheHashtable, &newentry);\n\n    PhReleaseQueuedLockExclusive(&PhImageListCacheHashtableLock);\n\n    if (smallIcon)\n        DestroyIcon(smallIcon);\n    if (largeIcon)\n        DestroyIcon(smallIcon);\n\n    return newentry;\n}\n\nVOID PhImageListFlushCache(\n    VOID\n    )\n{\n    //PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    //PPH_IMAGELIST_ITEM* entry;\n    //\n    //if (!PhImageListCacheHashtable)\n    //    return;\n    //\n    //PhAcquireQueuedLockExclusive(&PhImageListCacheHashtableLock);\n    //\n    //PhBeginEnumHashtable(PhImageListCacheHashtable, &enumContext);\n    //\n    //while (entry = PhNextEnumHashtable(&enumContext))\n    //{\n    //    PPH_IMAGELIST_ITEM item = *entry;\n    //\n    //    PhDereferenceObject(item);\n    //}\n    //\n    //PhClearReference(&PhImageListCacheHashtable);\n    //PhImageListCacheHashtable = PhCreateHashtable(\n    //    sizeof(PPH_IMAGELIST_ITEM),\n    //    PhImageListCacheHashtableEqualFunction,\n    //    PhImageListCacheHashtableHashFunction,\n    //    32\n    //    );\n    //\n    //PhReleaseQueuedLockExclusive(&PhImageListCacheHashtableLock);\n}\n\nVOID PhDrawProcessIcon(\n    _In_ HDC hdc,\n    _In_ PRECT rect,\n    _In_ ULONG Index,\n    _In_ BOOLEAN Large)\n{\n    if (Large)\n    {\n        if (PhProcessLargeImageList)\n        {\n            PhImageListDrawIcon(\n                PhProcessLargeImageList,\n                Index,\n                hdc,\n                rect->left,\n                rect->top,\n                ILD_NORMAL | ILD_TRANSPARENT,\n                FALSE\n                );\n        }\n    }\n    else\n    {\n        if (PhProcessSmallImageList)\n        {\n            PhImageListDrawIcon(\n                PhProcessSmallImageList,\n                Index,\n                hdc,\n                rect->left,\n                rect->top,\n                ILD_NORMAL | ILD_TRANSPARENT,\n                FALSE\n                );\n        }\n    }\n}\n\nHICON PhGetImageListIcon(\n    _In_ ULONG_PTR Index,\n    _In_ BOOLEAN Large\n    )\n{\n    if (Large)\n    {\n        if (PhProcessLargeImageList)\n        {\n            return PhImageListGetIcon(\n                PhProcessLargeImageList,\n                (ULONG)Index,\n                ILD_NORMAL | ILD_TRANSPARENT\n                );\n        }\n    }\n    else\n    {\n        if (PhProcessSmallImageList)\n        {\n            return PhImageListGetIcon(\n                PhProcessSmallImageList,\n                (ULONG)Index,\n                ILD_NORMAL | ILD_TRANSPARENT\n                );\n        }\n    }\n\n    return NULL;\n}\n\nHIMAGELIST PhGetProcessSmallImageList(\n    VOID)\n{\n    return PhProcessSmallImageList;\n}\n\n_Success_(return)\nBOOLEAN PhDuplicateProcessInformation(\n    _Outptr_ PPVOID ProcessInformation\n    )\n{\n    SIZE_T infoLength;\n\n    if (!PhProcessInformation)\n        return FALSE;\n\n    infoLength = PhSizeHeap(PhProcessInformation);\n\n    if (!infoLength)\n        return FALSE;\n\n    *ProcessInformation = PhAllocateCopy(PhProcessInformation, infoLength);\n\n    return TRUE;\n}\n\nPPH_PROCESS_ITEM PhCreateProcessItemFromHandle(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN TerminatedProcess\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName;\n    PPH_PROCESS_ITEM processItem;\n    PPH_PROCESS_ITEM idleProcessItem;\n    PROCESS_BASIC_INFORMATION basicInfo;\n    PROCESS_HANDLE_INFORMATION handleInfo;\n    KERNEL_USER_TIMES times;\n    UCHAR priorityClass;\n\n    if (processItem = PhReferenceProcessItem(ProcessId))\n        return processItem;\n\n    processItem = PhCreateProcessItem(ProcessId);\n    processItem->QueryHandle = ProcessHandle;\n\n    if (TerminatedProcess)\n    {\n        SetFlag(processItem->State, PH_PROCESS_ITEM_REMOVED);\n    }\n\n    // We need a process record. Just use the record of System Idle Process.\n    if (idleProcessItem = PhReferenceProcessItem(SYSTEM_IDLE_PROCESS_ID))\n    {\n        processItem->Record = idleProcessItem->Record;\n        PhReferenceProcessRecord(processItem->Record);\n    }\n    else\n    {\n        assert(idleProcessItem);\n        PhDereferenceObject(processItem);\n        return NULL;\n    }\n\n    // Set up the file name and process name.\n\n    if (NT_SUCCESS(PhGetProcessImageFileName(processItem->QueryHandle, &fileName)))\n    {\n        processItem->FileName = fileName;\n    }\n\n    if (processItem->FileName)\n        processItem->ProcessName = PhGetBaseName(processItem->FileName);\n    else\n        processItem->ProcessName = PhCreateString(L\"Unknown\");\n\n    // Basic process information and not-so-dynamic information.\n\n    {\n        if (NT_SUCCESS(PhGetProcessBasicInformation(processItem->QueryHandle, &basicInfo)))\n        {\n            processItem->ParentProcessId = basicInfo.InheritedFromUniqueProcessId;\n            processItem->BasePriority = basicInfo.BasePriority;\n        }\n\n        PhGetProcessSessionId(processItem->QueryHandle, &processItem->SessionId);\n\n        //PhPrintUInt32(processItem->ParentProcessIdString, HandleToUlong(processItem->ParentProcessId));\n        //PhPrintUInt32(processItem->SessionIdString, processItem->SessionId);\n\n        if (NT_SUCCESS(PhGetProcessTimes(processItem->QueryHandle, &times)))\n        {\n            processItem->CreateTime = times.CreateTime;\n            processItem->KernelTime = times.KernelTime;\n            processItem->UserTime = times.UserTime;\n        }\n\n        // TODO: Token information?\n\n        if (NT_SUCCESS(PhGetProcessPriorityClass(processItem->QueryHandle, &priorityClass)))\n        {\n            processItem->PriorityClass = priorityClass;\n        }\n\n        if (NT_SUCCESS(PhGetProcessHandleCount(processItem->QueryHandle, &handleInfo)))\n        {\n            processItem->NumberOfHandles = handleInfo.HandleCount;\n        }\n    }\n\n    //\n    // Extended process information\n    //\n\n    if (WindowsVersion >= WINDOWS_10)\n    {\n        PPROCESS_TELEMETRY_ID_INFORMATION telemetryInfo;\n        ULONG telemetryInfoLength;\n\n        if (NT_SUCCESS(PhGetProcessTelemetryIdInformation(processItem->QueryHandle, &telemetryInfo, &telemetryInfoLength)))\n        {\n            SIZE_T UserSidLength = telemetryInfo->ImagePathOffset - telemetryInfo->UserSidOffset;\n            PSID UserSidBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->UserSidOffset);\n            SIZE_T ImagePathLength = telemetryInfo->PackageNameOffset - telemetryInfo->ImagePathOffset;\n            PWSTR ImagePathBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->ImagePathOffset);\n            SIZE_T PackageNameLength = telemetryInfo->RelativeAppNameOffset - telemetryInfo->PackageNameOffset;\n            PWSTR PackageNameBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->PackageNameOffset);\n            SIZE_T RelativeAppNameLength = telemetryInfo->CommandLineOffset - telemetryInfo->RelativeAppNameOffset;\n            PWSTR RelativeAppNameBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->RelativeAppNameOffset);\n            SIZE_T CommandLineLength = telemetryInfoLength - telemetryInfo->CommandLineOffset;\n            PWSTR CommandLineBuffer = PTR_ADD_OFFSET(telemetryInfo, telemetryInfo->CommandLineOffset);\n\n            processItem->ProcessStartKey = telemetryInfo->ProcessStartKey;\n            processItem->CreateInterruptTime = telemetryInfo->CreateInterruptTime;\n            processItem->ProcessSequenceNumber = telemetryInfo->ProcessSequenceNumber;\n            processItem->SessionCreateTime = telemetryInfo->SessionCreateTime;\n            processItem->ImageChecksum = telemetryInfo->ImageChecksum;\n            processItem->ImageTimeStamp = telemetryInfo->ImageTimeDateStamp;\n\n            if (!processItem->Sid && PhValidSid(UserSidBuffer))\n            {\n                processItem->Sid = PhAllocateCopy(UserSidBuffer, UserSidLength);\n                processItem->UserName = PhpGetSidFullNameCached(UserSidBuffer);\n            }\n\n            if (PhIsNullOrEmptyString(processItem->FileName) && ImagePathLength > sizeof(UNICODE_NULL))\n            {\n                processItem->FileName = PhCreateStringEx(ImagePathBuffer, ImagePathLength - sizeof(UNICODE_NULL));\n            }\n\n            if (PhIsNullOrEmptyString(processItem->PackageFullName) && PackageNameLength > sizeof(UNICODE_NULL))\n            {\n                processItem->PackageFullName = PhCreateStringEx(PackageNameBuffer, PackageNameLength - sizeof(UNICODE_NULL));\n            }\n\n            if (PhIsNullOrEmptyString(processItem->CommandLine) && CommandLineLength > sizeof(UNICODE_NULL))\n            {\n                processItem->CommandLine = PhCreateStringEx(CommandLineBuffer, CommandLineLength - sizeof(UNICODE_NULL));\n            }\n        }\n    }\n\n    // Stage 1\n    // Some copy and paste magic here...\n\n    if (processItem->FileName)\n    {\n        // Small icon, large icon.\n        if (processItem->IconEntry = PhImageListExtractIcon(processItem->FileName, TRUE, processItem->ProcessId, processItem->PackageFullName, PhProcessImageListWindowDpi))\n        {\n            processItem->SmallIconIndex = processItem->IconEntry->SmallIconIndex;\n            processItem->LargeIconIndex = processItem->IconEntry->LargeIconIndex;\n        }\n\n        // Version info.\n        PhInitializeImageVersionInfoEx(&processItem->VersionInfo, &processItem->FileName->sr, !!PhCsEnableVersionSupport);\n    }\n\n    // Command line\n\n    if (PhIsNullOrEmptyString(processItem->CommandLine))\n    {\n        PPH_STRING commandLine;\n        SIZE_T i;\n\n        if (NT_SUCCESS(status = PhGetProcessCommandLine(processItem->QueryHandle, &commandLine)))\n        {\n            // Some command lines (e.g. from taskeng.exe) have nulls in them.\n            // Since Windows can't display them, we'll replace them with\n            // spaces.\n            for (i = 0; i < commandLine->Length / sizeof(WCHAR); i++)\n            {\n                if (commandLine->Buffer[i] == UNICODE_NULL)\n                    commandLine->Buffer[i] = ' ';\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            processItem->CommandLine = commandLine;\n        }\n    }\n\n    PhSetEvent(&processItem->Stage1Event);\n\n    return processItem;\n}\n"
  },
  {
    "path": "SystemInformer/procrec.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2020-2023\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <mainwnd.h>\n#include <procprv.h>\n\ntypedef struct _PROCESS_RECORD_CONTEXT\n{\n    PPH_PROCESS_RECORD Record;\n    HICON FileIcon;\n} PROCESS_RECORD_CONTEXT, *PPROCESS_RECORD_CONTEXT;\n\nINT_PTR CALLBACK PhpProcessRecordDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowProcessRecordDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_RECORD Record\n    )\n{\n    PROCESS_RECORD_CONTEXT context;\n\n    memset(&context, 0, sizeof(PROCESS_RECORD_CONTEXT));\n    context.Record = Record;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_PROCRECORD),\n        ParentWindowHandle,\n        PhpProcessRecordDlgProc,\n        &context\n        );\n}\n\nPPH_STRING PhpaGetRelativeTimeString(\n    _In_ PLARGE_INTEGER Time\n    )\n{\n    LARGE_INTEGER time;\n    LARGE_INTEGER currentTime;\n    SYSTEMTIME timeFields;\n    PPH_STRING timeRelativeString;\n    PPH_STRING timeString;\n\n    time = *Time;\n    PhQuerySystemTime(&currentTime);\n    timeRelativeString = PH_AUTO(PhFormatTimeSpanRelative(currentTime.QuadPart - time.QuadPart));\n\n    PhLargeIntegerToLocalSystemTime(&timeFields, &time);\n    timeString = PhaFormatDateTime(&timeFields);\n\n    return PhaFormatString(L\"%s ago (%s)\", timeRelativeString->Buffer, timeString->Buffer);\n}\n\nINT_PTR CALLBACK PhpProcessRecordDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPROCESS_RECORD_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPROCESS_RECORD_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_STRING fileName = NULL;\n            PH_IMAGE_VERSION_INFO versionInfo;\n            BOOLEAN versionInfoInitialized;\n            PPH_STRING processNameString;\n            PPH_PROCESS_ITEM processItem;\n            LONG dpiValue;\n\n            if (!PH_IS_FAKE_PROCESS_ID(context->Record->ProcessId))\n            {\n                processNameString = PhaFormatString(L\"%s (%u)\",\n                    context->Record->ProcessName->Buffer, HandleToUlong(context->Record->ProcessId));\n            }\n            else\n            {\n                processNameString = context->Record->ProcessName;\n            }\n\n            if (context->Record->FileName)\n                fileName = PhGetFileName(context->Record->FileName);\n            if (!fileName)\n                fileName = context->Record->FileName;\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));\n            PhSetWindowText(hwndDlg, processNameString->Buffer);\n\n            PhSetDialogItemText(hwndDlg, IDC_PROCESSNAME, processNameString->Buffer);\n\n            if (processItem = PhReferenceProcessItemForRecord(context->Record))\n            {\n                PPH_PROCESS_ITEM parentProcess;\n\n                if (parentProcess = PhReferenceProcessItemForParent(processItem))\n                {\n                    CLIENT_ID clientId;\n\n                    clientId.UniqueProcess = parentProcess->ProcessId;\n                    clientId.UniqueThread = NULL;\n\n                    PhSetDialogItemText(hwndDlg, IDC_PARENT,\n                        PH_AUTO_T(PH_STRING, PhGetClientIdNameEx(&clientId, parentProcess->ProcessName))->Buffer);\n\n                    PhDereferenceObject(parentProcess);\n                }\n                else\n                {\n                    PhSetDialogItemText(hwndDlg, IDC_PARENT, PhaFormatString(L\"Non-existent process (%u)\",\n                        HandleToUlong(context->Record->ParentProcessId))->Buffer);\n                }\n\n                PhDereferenceObject(processItem);\n            }\n            else\n            {\n                PhSetDialogItemText(hwndDlg, IDC_PARENT, PhaFormatString(L\"Unknown process (%u)\",\n                    HandleToUlong(context->Record->ParentProcessId))->Buffer);\n\n                EnableWindow(GetDlgItem(hwndDlg, IDC_PROPERTIES), FALSE);\n            }\n\n            memset(&versionInfo, 0, sizeof(PH_IMAGE_VERSION_INFO));\n            versionInfoInitialized = FALSE;\n\n            if (fileName)\n            {\n                PhExtractIcon(\n                    fileName->Buffer,\n                    &context->FileIcon,\n                    NULL\n                    );\n\n                if (NT_SUCCESS(PhInitializeImageVersionInfo(&versionInfo, fileName->Buffer)))\n                {\n                    versionInfoInitialized = TRUE;\n                }\n            }\n\n            if (context->FileIcon)\n            {\n                SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)context->FileIcon, 0);\n            }\n            else\n            {\n                HICON largeIcon;\n\n                PhGetStockApplicationIcon(NULL, &largeIcon);\n                SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)largeIcon, 0);\n            }\n\n            dpiValue = PhGetWindowDpi(hwndDlg);\n\n            SendMessage(GetDlgItem(hwndDlg, IDC_OPENFILENAME), BM_SETIMAGE, IMAGE_ICON,\n                (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_FOLDER), dpiValue));\n\n            PhSetDialogItemText(hwndDlg, IDC_NAME, PhGetStringOrDefault(versionInfo.FileDescription, L\"N/A\"));\n            PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME, PhGetStringOrDefault(versionInfo.CompanyName, L\"N/A\"));\n            PhSetDialogItemText(hwndDlg, IDC_VERSION, PhGetStringOrDefault(versionInfo.FileVersion, L\"N/A\"));\n            PhSetDialogItemText(hwndDlg, IDC_FILENAME, PhGetStringOrDefault(fileName, L\"N/A\"));\n\n            if (versionInfoInitialized)\n                PhDeleteImageVersionInfo(&versionInfo);\n\n            if (!fileName)\n                EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE);\n\n            PhSetDialogItemText(hwndDlg, IDC_CMDLINE, PhGetStringOrDefault(context->Record->CommandLine, L\"N/A\"));\n\n            if (context->Record->CreateTime.QuadPart != 0)\n                PhSetDialogItemText(hwndDlg, IDC_STARTED, PhpaGetRelativeTimeString(&context->Record->CreateTime)->Buffer);\n            else\n                PhSetDialogItemText(hwndDlg, IDC_STARTED, L\"N/A\");\n\n            if (context->Record->ExitTime.QuadPart != 0)\n                PhSetDialogItemText(hwndDlg, IDC_TERMINATED, PhpaGetRelativeTimeString(&context->Record->ExitTime)->Buffer);\n            else\n                PhSetDialogItemText(hwndDlg, IDC_TERMINATED, L\"N/A\");\n\n            PhSetDialogItemValue(hwndDlg, IDC_SESSIONID, context->Record->SessionId, FALSE);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n\n            if (fileName && fileName != context->Record->FileName)\n                PhDereferenceObject(fileName);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            if (context->FileIcon)\n                DestroyIcon(context->FileIcon);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                {\n                    EndDialog(hwndDlg, IDOK);\n                }\n                break;\n            case IDC_OPENFILENAME:\n                {\n                    if (context->Record->FileName)\n                    {\n                        PhShellExecuteUserString(\n                            hwndDlg,\n                            SETTING_FILE_BROWSE_EXECUTABLE,\n                            context->Record->FileName->Buffer,\n                            FALSE,\n                            L\"Make sure the Explorer executable file is present.\"\n                            );\n                    }\n                }\n                break;\n            case IDC_PROPERTIES:\n                {\n                    PPH_PROCESS_ITEM processItem;\n\n                    if (processItem = PhReferenceProcessItemForRecord(context->Record))\n                    {\n                        SystemInformer_ShowProcessProperties(processItem);\n                        PhDereferenceObject(processItem);\n                    }\n                    else\n                    {\n                        PhShowError2(\n                            hwndDlg,\n                            L\"Unable to show the process properties.\",\n                            L\"%s\",\n                            L\"The process has already terminated; only the process record is available.\"\n                            );\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/proctree.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2016-2023\n *     jxy-s   2021\n *\n */\n\n/*\n * The process tree list manages a list of tree nodes and handles callback events generated by the\n * underlying treenew control. Retrieval of certain types of process information is also performed\n * here, on the GUI thread (see PH_PROCESS_NODE.ValidMask). This is done for columns that require\n * data not supplied by the process provider.\n */\n\n#include <phapp.h>\n#include <proctree.h>\n\n#include <appresolver.h>\n#include <cpysave.h>\n#include <emenu.h>\n#include <hndlinfo.h>\n#include <kphuser.h>\n#include <mapimg.h>\n#include <secedit.h>\n#include <settings.h>\n#include <verify.h>\n\n#include <colmgr.h>\n#include <extmgri.h>\n#include <mainwnd.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <procprv.h>\n#include <procmtgn.h>\n#include <srvprv.h>\n\nVOID PhpRemoveProcessNode(\n    _In_ PPH_PROCESS_NODE ProcessNode,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpProcessTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    );\n\nBOOLEAN NTAPI PhpProcessTreeNewCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    );\n\nBOOLEAN PhpShouldShowImageCoherency(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ BOOLEAN CheckThreshold\n    );\n\nstatic HWND ProcessTreeListHandle;\nstatic ULONG ProcessTreeListSortColumn;\nstatic PH_SORT_ORDER ProcessTreeListSortOrder;\nstatic PH_CM_MANAGER ProcessTreeListCm;\n\nstatic PPH_HASH_ENTRY ProcessNodeHashSet[256] = PH_HASH_SET_INIT; // hashtable of all nodes\nstatic PPH_LIST ProcessNodeList; // list of all nodes, used when sorting is enabled\nstatic PPH_LIST ProcessNodeRootList; // list of root nodes\nstatic PH_TN_FILTER_SUPPORT FilterSupport;\n\nCONST BOOLEAN PhProcessTreeListStateHighlighting = TRUE;\nstatic PPH_POINTER_LIST ProcessNodeStateList = NULL; // list of nodes which need to be processed\nstatic ULONG PhProcessTreeColumnHeaderCacheLength = 0;\nstatic PVOID PhProcessTreeColumnHeaderCache = NULL;\nstatic ULONG PhProcessTreeColumnHeaderTextCacheLength = 0;\nstatic PVOID PhProcessTreeColumnHeaderTextCache = NULL;\n\nstatic HDC GraphContext = NULL;\nstatic LONG GraphContextWidth = 0;\nstatic LONG GraphContextHeight = 0;\nstatic HBITMAP GraphOldBitmap = NULL;\nstatic HBITMAP GraphBitmap = NULL;\nstatic PVOID GraphBits = NULL;\n\n/**\n * Initializes the process tree list.\n *\n * This function sets up any necessary data structures or state required\n * for displaying or managing the process tree within the application.\n */\nVOID PhProcessTreeListInitialization(\n    VOID\n    )\n{\n    ProcessNodeList = PhCreateList(40);\n    ProcessNodeRootList = PhCreateList(10);\n}\n\nVOID PhInitializeProcessTreeList(\n    _In_ HWND hwnd\n    )\n{\n    ProcessTreeListHandle = hwnd;\n    PhSetControlTheme(ProcessTreeListHandle, L\"explorer\");\n\n    TreeNew_SetRedraw(hwnd, FALSE);\n    TreeNew_SetExtendedFlags(hwnd, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT);\n    TreeNew_SetCallback(hwnd, PhpProcessTreeNewCallback, NULL);\n    TreeNew_SetImageList(hwnd, PhProcessSmallImageList);\n    TreeNew_SetMaxId(hwnd, PHPRTLC_MAXIMUM - 1);\n\n    // Default columns\n    PhAddTreeNewColumn(hwnd, PHPRTLC_NAME, TRUE, L\"Name\", 200, PH_ALIGN_LEFT, (PhGetIntegerSetting(SETTING_PROCESS_TREE_LIST_NAME_DEFAULT) ? TN_COLUMN_FIXED : 0), 0); // HACK (dmex)\n    PhAddTreeNewColumn(hwnd, PHPRTLC_PID, TRUE, L\"PID\", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CPU, TRUE, L\"CPU\", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOTOTALRATE, TRUE, L\"I/O total rate\", 70, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTES, TRUE, L\"Private bytes\", 70, PH_ALIGN_RIGHT, 3, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_USERNAME, TRUE, L\"User name\", 140, PH_ALIGN_LEFT, 4, DT_PATH_ELLIPSIS);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_DESCRIPTION, TRUE, L\"Description\", 180, PH_ALIGN_LEFT, 5, 0);\n\n    // Customizable columns (1)\n    PhAddTreeNewColumn(hwnd, PHPRTLC_COMPANYNAME, FALSE, L\"Company name\", 180, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_VERSION, FALSE, L\"Version\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_FILENAME, FALSE, L\"File name\", 180, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_COMMANDLINE, FALSE, L\"Command line\", 180, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPRIVATEBYTES, FALSE, L\"Peak private bytes\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_WORKINGSET, FALSE, L\"Working set\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKWORKINGSET, FALSE, L\"Peak working set\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEWS, FALSE, L\"Private WS\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREDWS, FALSE, L\"Shared WS\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREABLEWS, FALSE, L\"Shareable WS\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALSIZE, FALSE, L\"Virtual size\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKVIRTUALSIZE, FALSE, L\"Peak virtual size\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTS, FALSE, L\"Page faults\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_SESSIONID, FALSE, L\"Session ID\", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIORITYCLASS, FALSE, L\"Priority class\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_BASEPRIORITY, FALSE, L\"Base priority\", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n\n    // Customizable columns (2)\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_THREADS, FALSE, L\"Threads\", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_HANDLES, FALSE, L\"Handles\", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_GDIHANDLES, FALSE, L\"GDI handles\", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERHANDLES, FALSE, L\"USER handles\", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IORORATE, FALSE, L\"I/O read+other rate\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRATE, FALSE, L\"I/O write rate\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_INTEGRITY, FALSE, L\"Integrity\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOPRIORITY, FALSE, L\"I/O priority\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEPRIORITY, FALSE, L\"Page priority\", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_STARTTIME, FALSE, L\"Start time\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_TOTALCPUTIME, FALSE, L\"Total CPU time\", 90, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_KERNELCPUTIME, FALSE, L\"Kernel CPU time\", 90, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERCPUTIME, FALSE, L\"User CPU time\", 90, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFICATIONSTATUS, FALSE, L\"Verification status\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFIEDSIGNER, FALSE, L\"Verified signer\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_ASLR, FALSE, L\"ASLR\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_RELATIVESTARTTIME, FALSE, L\"Relative start time\", 180, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_BITS, FALSE, L\"Bits\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_ELEVATION, FALSE, L\"Elevation\", 60, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_WINDOWTITLE, FALSE, L\"Window title\", 120, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_WINDOWSTATUS, FALSE, L\"Window status\", 60, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLES, FALSE, L\"Cycles\", 110, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLESDELTA, FALSE, L\"Cycles delta\", 90, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx2(hwnd, PHPRTLC_CPUHISTORY, FALSE, L\"CPU history\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING);\n    PhAddTreeNewColumnEx2(hwnd, PHPRTLC_PRIVATEBYTESHISTORY, FALSE, L\"Private bytes history\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING);\n    PhAddTreeNewColumnEx2(hwnd, PHPRTLC_IOHISTORY, FALSE, L\"I/O history\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_DEP, FALSE, L\"DEP\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALIZED, FALSE, L\"Virtualized\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHES, FALSE, L\"Context switches\", 100, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHESDELTA, FALSE, L\"Context switches delta\", 80, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTSDELTA, FALSE, L\"Page faults delta\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n\n    // I/O group columns\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADS, FALSE, L\"I/O reads\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITES, FALSE, L\"I/O writes\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHER, FALSE, L\"I/O other\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADBYTES, FALSE, L\"I/O read bytes\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITEBYTES, FALSE, L\"I/O write bytes\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERBYTES, FALSE, L\"I/O other bytes\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADSDELTA, FALSE, L\"I/O reads delta\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITESDELTA, FALSE, L\"I/O writes delta\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERDELTA, FALSE, L\"I/O other delta\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n\n    // Customizable columns (3)\n    PhAddTreeNewColumn(hwnd, PHPRTLC_OSCONTEXT, FALSE, L\"OS context\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEDPOOL, FALSE, L\"Paged pool\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPAGEDPOOL, FALSE, L\"Peak paged pool\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_NONPAGEDPOOL, FALSE, L\"Non-paged pool\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKNONPAGEDPOOL, FALSE, L\"Peak non-paged pool\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_MINIMUMWORKINGSET, FALSE, L\"Minimum working set\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_MAXIMUMWORKINGSET, FALSE, L\"Maximum working set\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTESDELTA, FALSE, L\"Private bytes delta\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_SUBSYSTEM, FALSE, L\"Subsystem\", 110, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_PACKAGENAME, FALSE, L\"Package name\", 160, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_APPID, FALSE, L\"App ID\", 160, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_DPIAWARENESS, FALSE, L\"DPI awareness\", 110, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CFGUARD, FALSE, L\"CF Guard\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_TIMESTAMP, FALSE, L\"Time stamp\", 140, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILEMODIFIEDTIME, FALSE, L\"File modified time\", 140, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILESIZE, FALSE, L\"File size\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_SUBPROCESSCOUNT, FALSE, L\"Subprocesses\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_JOBOBJECTID, FALSE, L\"Job Object ID\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PROTECTION, FALSE, L\"Protection\", 105, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_DESKTOP, FALSE, L\"Desktop\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CRITICAL, FALSE, L\"Critical\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PIDHEX, FALSE, L\"PID (Hex)\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CPUCORECYCLES, FALSE, L\"CPU (relative)\", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CET, FALSE, L\"CET\", 45, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_IMAGE_COHERENCY, FALSE, L\"Image coherency\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_ERRORMODE, FALSE, L\"Error mode\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CODEPAGE, FALSE, L\"Code page\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx2(hwnd, PHPRTLC_TIMELINE, FALSE, L\"Timeline\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_POWERTHROTTLING, FALSE, L\"Power throttling\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_ARCHITECTURE, FALSE, L\"Architecture\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_PARENTPID, FALSE, L\"Parent PID\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_PARENTCONSOLEPID, FALSE, L\"Parent console PID\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_COMMITSIZE, FALSE, L\"Shared commit\", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIORITYBOOST, FALSE, L\"Priority boost\", 45, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CPUAVERAGE, FALSE, L\"CPU (average)\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CPUKERNEL, FALSE, L\"CPU (kernel)\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_CPUUSER, FALSE, L\"CPU (user)\", 50, PH_ALIGN_LEFT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_GRANTEDACCESS, FALSE, L\"Granted access (symbolic)\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_TLSBITMAPDELTA, FALSE, L\"Thread local storage\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHPRTLC_REFERENCEDELTA, FALSE, L\"References\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_LXSSPID, FALSE, L\"PID (LXSS)\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_START_KEY, FALSE, L\"Start key\", 120, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_MITIGATION_POLICIES, FALSE, L\"Mitigation policies\", 180, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHPRTLC_SERVICES, FALSE, L\"Services\", 180, PH_ALIGN_LEFT, ULONG_MAX, 0);\n\n    PhCmInitializeManager(&ProcessTreeListCm, hwnd, PHPRTLC_MAXIMUM, PhpProcessTreeNewPostSortFunction);\n    PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, ProcessNodeList);\n\n    TreeNew_SetTriState(hwnd, TRUE);\n    TreeNew_SetRedraw(hwnd, TRUE);\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n        treeNewInfo.TreeNewHandle = hwnd;\n        treeNewInfo.CmData = &ProcessTreeListCm;\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), &treeNewInfo);\n    }\n}\n\nVOID PhInitializeProcessTreeColumnHeaderCache(\n    VOID\n    )\n{\n    PH_TREENEW_SET_HEADER_CACHE processTreeColumnHeaderCache;\n    ULONG columnCount = TreeNew_GetColumnCount(ProcessTreeListHandle);\n\n    // TODO: This creates a text cache for all columns wasting space since\n    // only some provide header text support. We should switch to the same treenode\n    // caching where nodes provide the cache instead of the control. (dmex)\n\n    PhProcessTreeColumnHeaderCacheLength = columnCount * sizeof(PH_STRINGREF);\n    PhProcessTreeColumnHeaderCache = PhAllocateZero(PhProcessTreeColumnHeaderCacheLength);\n\n    PhProcessTreeColumnHeaderTextCacheLength = columnCount * (PH_TREENEW_HEADER_TEXT_SIZE_MAX * sizeof(WCHAR));\n    PhProcessTreeColumnHeaderTextCache = PhAllocateZero(PhProcessTreeColumnHeaderTextCacheLength);\n\n    processTreeColumnHeaderCache.HeaderTreeColumnMax = columnCount;\n    processTreeColumnHeaderCache.HeaderTreeColumnStringCache = PhProcessTreeColumnHeaderCache;\n    processTreeColumnHeaderCache.HeaderTreeColumnTextCache = PhProcessTreeColumnHeaderTextCache;\n    TreeNew_SetColumnTextCache(ProcessTreeListHandle, &processTreeColumnHeaderCache);\n}\n\nVOID PhLoadSettingsProcessTreeUpdateMask(\n    VOID\n    )\n{\n#ifdef PH_TREELIST_COLUMN_ARRAY\n    PH_TREENEW_COLUMN column;\n\n    if (TreeNew_GetColumn(ProcessTreeListHandle, PHPRTLC_USERNAME, &column) && column.Visible)\n        SetFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_AVERAGE);\n    else\n        ClearFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_AVERAGE);\n#else\n    ULONG columnVisible[4] =\n    {\n        PHPRTLC_USERNAME,\n        PHPRTLC_CFGUARD,\n        PHPRTLC_CET,\n        PHPRTLC_CPUAVERAGE\n    };\n\n    if (!TreeNew_GetVisibleColumnArray(ProcessTreeListHandle, RTL_NUMBER_OF(columnVisible), columnVisible))\n        return;\n\n    if (columnVisible[0])\n        SetFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_USERNAME);\n    else\n        ClearFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_USERNAME);\n\n    if (columnVisible[1])\n        SetFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_CFGUARD);\n    else\n        ClearFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_CFGUARD);\n\n    if (columnVisible[2])\n        SetFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_CET);\n    else\n        ClearFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_CET);\n\n    if (columnVisible[3])\n        SetFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_AVERAGE);\n    else\n        ClearFlag(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_AVERAGE);\n#endif\n\n    PhInitializeProcessTreeColumnHeaderCache();\n}\n\nVOID PhLoadSettingsProcessTreeList(\n    VOID\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhGetStringSetting(SETTING_PROCESS_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_PROCESS_TREE_LIST_SORT);\n    PhCmLoadSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &settings->sr, &sortSettings->sr);\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_INSTANT_TOOLTIPS))\n        SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0);\n    else\n        SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);\n\n    PhLoadSettingsProcessTreeUpdateMask();\n}\n\nVOID PhSaveSettingsProcessTreeList(\n    VOID\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &sortSettings);\n    PhSetStringSetting2(SETTING_PROCESS_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_PROCESS_TREE_LIST_SORT, &sortSettings->sr);\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhLoadSettingsProcessTreeListEx(\n    _In_ PPH_STRING TreeListSettings,\n    _In_ PPH_STRING TreeSortSettings\n    )\n{\n    PhCmLoadSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &TreeListSettings->sr, &TreeSortSettings->sr);\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_INSTANT_TOOLTIPS))\n        SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0);\n    else\n        SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);\n\n    PhLoadSettingsProcessTreeUpdateMask();\n}\n\nVOID PhSaveSettingsProcessTreeListEx(\n    _Out_ PPH_STRING *TreeListSettings,\n    _Out_ PPH_STRING *TreeSortSettings\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &sortSettings);\n\n    *TreeListSettings = settings;\n    *TreeSortSettings = sortSettings;\n}\n\nVOID PhReloadSettingsProcessTreeList(\n    VOID\n    )\n{\n    if (PhGetIntegerSetting(SETTING_ENABLE_INSTANT_TOOLTIPS))\n        SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0);\n    else\n        SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);\n\n    PhLoadSettingsProcessTreeUpdateMask();\n}\n\nPPH_TN_FILTER_SUPPORT PhGetFilterSupportProcessTreeList(\n    VOID\n    )\n{\n    return &FilterSupport;\n}\n\nFORCEINLINE BOOLEAN PhCompareProcessNode(\n    _In_ PPH_PROCESS_NODE Value1,\n    _In_ PPH_PROCESS_NODE Value2\n    )\n{\n    return Value1->ProcessId == Value2->ProcessId;\n}\n\nFORCEINLINE ULONG PhHashProcessNode(\n    _In_ PPH_PROCESS_NODE Value\n    )\n{\n    return HandleToUlong(Value->ProcessId) / 4;\n}\n\nFORCEINLINE BOOLEAN PhpValidateParentProcessNode(\n    _In_ PPH_PROCESS_NODE Child,\n    _In_ PPH_PROCESS_NODE Parent\n    )\n{\n    if (WindowsVersion >= WINDOWS_10_RS3)\n    {\n        return PH_IS_FAKE_PROCESS_ID(Child->ProcessId) ||\n            Parent->ProcessItem->ProcessSequenceNumber <= Child->ProcessItem->ProcessSequenceNumber;\n    }\n    else\n    {\n        return PH_IS_FAKE_PROCESS_ID(Child->ProcessId) ||\n            Parent->ProcessItem->CreateTime.QuadPart <= Child->ProcessItem->CreateTime.QuadPart;\n    }\n}\n\nPPH_PROCESS_NODE PhAddProcessNode(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ ULONG RunId\n    )\n{\n    PPH_PROCESS_NODE processNode;\n    PPH_PROCESS_NODE parentNode;\n    ULONG i;\n\n    processNode = PhAllocate(PhEmGetObjectSize(EmProcessNodeType, sizeof(PH_PROCESS_NODE)));\n    memset(processNode, 0, sizeof(PH_PROCESS_NODE));\n    PhInitializeTreeNewNode(&processNode->Node);\n\n    if (PhProcessTreeListStateHighlighting && RunId != 1)\n    {\n        PhChangeShStateTn(\n            &processNode->Node,\n            &processNode->ShState,\n            &ProcessNodeStateList,\n            NewItemState,\n            PhCsColorNew,\n            NULL\n            );\n    }\n\n    processNode->ProcessId = ProcessItem->ProcessId;\n    processNode->ProcessItem = ProcessItem;\n    PhReferenceObject(ProcessItem);\n\n    memset(processNode->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM);\n    processNode->Node.TextCache = processNode->TextCache;\n    processNode->Node.TextCacheSize = PHPRTLC_MAXIMUM;\n\n    processNode->Children = PhCreateList(1);\n\n    // Find this process' parent and add the process to it if we found it.\n    if (\n        (parentNode = PhFindProcessNode(ProcessItem->ParentProcessId)) &&\n        PhpValidateParentProcessNode(processNode, parentNode)\n        )\n    {\n        PhAddItemList(parentNode->Children, processNode);\n        processNode->Parent = parentNode;\n    }\n    else\n    {\n        // No parent, add to root list.\n        processNode->Parent = NULL;\n        PhAddItemList(ProcessNodeRootList, processNode);\n    }\n\n    // Find this process' children and move them to this node.\n\n    for (i = 0; i < ProcessNodeRootList->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNodeRootList->Items[i];\n\n        if (\n            node != processNode && // for cases where the parent PID = PID (e.g. System Idle Process)\n            node->ProcessItem->ParentProcessId == ProcessItem->ProcessId &&\n            PhpValidateParentProcessNode(node, processNode)\n            )\n        {\n            node->Parent = processNode;\n            PhAddItemList(processNode->Children, node);\n        }\n    }\n\n    for (i = 0; i < processNode->Children->Count; i++)\n    {\n        PhRemoveItemList(\n            ProcessNodeRootList,\n            PhFindItemList(ProcessNodeRootList, processNode->Children->Items[i])\n            );\n    }\n\n    PhAddEntryHashSet(\n        ProcessNodeHashSet,\n        PH_HASH_SET_SIZE(ProcessNodeHashSet),\n        &processNode->HashEntry,\n        PhHashProcessNode(processNode)\n        );\n    PhAddItemList(ProcessNodeList, processNode);\n\n    if (FilterSupport.FilterList)\n        processNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &processNode->Node);\n\n    PhEmCallObjectOperation(EmProcessNodeType, processNode, EmObjectCreate);\n\n    TreeNew_NodesStructured(ProcessTreeListHandle);\n\n    return processNode;\n}\n\nPPH_PROCESS_NODE PhFindProcessNode(\n    _In_ HANDLE ProcessId\n    )\n{\n    PH_PROCESS_NODE lookupNode;\n    PPH_HASH_ENTRY entry;\n    PPH_PROCESS_NODE node;\n\n    lookupNode.ProcessId = ProcessId;\n    entry = PhFindEntryHashSet(\n        ProcessNodeHashSet,\n        PH_HASH_SET_SIZE(ProcessNodeHashSet),\n        PhHashProcessNode(&lookupNode)\n        );\n\n    for (; entry; entry = entry->Next)\n    {\n        node = CONTAINING_RECORD(entry, PH_PROCESS_NODE, HashEntry);\n\n        if (PhCompareProcessNode(&lookupNode, node))\n            return node;\n    }\n\n    return NULL;\n}\n\nVOID PhRemoveProcessNode(\n    _In_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    // Remove from the hashtable here to avoid problems in case the key is re-used.\n    PhRemoveEntryHashSet(ProcessNodeHashSet, PH_HASH_SET_SIZE(ProcessNodeHashSet), &ProcessNode->HashEntry);\n\n    if (PhProcessTreeListStateHighlighting)\n    {\n        PhChangeShStateTn(\n            &ProcessNode->Node,\n            &ProcessNode->ShState,\n            &ProcessNodeStateList,\n            RemovingItemState,\n            PhCsColorRemoved,\n            ProcessTreeListHandle\n            );\n    }\n    else\n    {\n        PhpRemoveProcessNode(ProcessNode, NULL);\n    }\n}\n\nVOID PhpRemoveProcessNode(\n    _In_ PPH_PROCESS_NODE ProcessNode,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG index;\n    ULONG i;\n\n    PhEmCallObjectOperation(EmProcessNodeType, ProcessNode, EmObjectDelete);\n\n    if (ProcessNode->Parent)\n    {\n        // Remove the node from its parent.\n\n        if ((index = PhFindItemList(ProcessNode->Parent->Children, ProcessNode)) != ULONG_MAX)\n            PhRemoveItemList(ProcessNode->Parent->Children, index);\n    }\n    else\n    {\n        // Remove the node from the root list.\n\n        if ((index = PhFindItemList(ProcessNodeRootList, ProcessNode)) != ULONG_MAX)\n            PhRemoveItemList(ProcessNodeRootList, index);\n    }\n\n    // Move the node's children to the root list.\n    for (i = 0; i < ProcessNode->Children->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNode->Children->Items[i];\n\n        node->Parent = NULL;\n        PhAddItemList(ProcessNodeRootList, node);\n    }\n\n    // Remove from list and cleanup.\n\n    if ((index = PhFindItemList(ProcessNodeList, ProcessNode)) != ULONG_MAX)\n        PhRemoveItemList(ProcessNodeList, index);\n\n    PhDereferenceObject(ProcessNode->Children);\n\n    PhClearReference(&ProcessNode->WindowText);\n    PhClearReference(&ProcessNode->AppIdText);\n\n    PhClearReference(&ProcessNode->TooltipText);\n    PhClearReference(&ProcessNode->FileNameWin32);\n\n    PhClearReference(&ProcessNode->IoTotalRateText);\n    PhClearReference(&ProcessNode->PrivateBytesText);\n    PhClearReference(&ProcessNode->PeakPrivateBytesText);\n    PhClearReference(&ProcessNode->WorkingSetText);\n    PhClearReference(&ProcessNode->PeakWorkingSetText);\n    PhClearReference(&ProcessNode->PrivateWsText);\n    PhClearReference(&ProcessNode->SharedWsText);\n    PhClearReference(&ProcessNode->ShareableWsText);\n    PhClearReference(&ProcessNode->VirtualSizeText);\n    PhClearReference(&ProcessNode->PeakVirtualSizeText);\n    PhClearReference(&ProcessNode->PageFaultsText);\n    PhClearReference(&ProcessNode->SessionIdText);\n    PhClearReference(&ProcessNode->BasePriorityText);\n    PhClearReference(&ProcessNode->ThreadsText);\n    PhClearReference(&ProcessNode->HandlesText);\n    PhClearReference(&ProcessNode->GdiHandlesText);\n    PhClearReference(&ProcessNode->UserHandlesText);\n    PhClearReference(&ProcessNode->IoRoRateText);\n    PhClearReference(&ProcessNode->IoWRateText);\n    PhClearReference(&ProcessNode->StartTimeText);\n    PhClearReference(&ProcessNode->TotalCpuTimeText);\n    PhClearReference(&ProcessNode->KernelCpuTimeText);\n    PhClearReference(&ProcessNode->UserCpuTimeText);\n    PhClearReference(&ProcessNode->RelativeStartTimeText);\n    PhClearReference(&ProcessNode->WindowTitleText);\n    PhClearReference(&ProcessNode->DepStatusText);\n    PhClearReference(&ProcessNode->CyclesText);\n    PhClearReference(&ProcessNode->CyclesDeltaText);\n    PhClearReference(&ProcessNode->ContextSwitchesText);\n    PhClearReference(&ProcessNode->ContextSwitchesDeltaText);\n    PhClearReference(&ProcessNode->PageFaultsDeltaText);\n\n    for (i = 0; i < PHPRTLC_IOGROUP_COUNT; i++)\n        PhClearReference(&ProcessNode->IoGroupText[i]);\n\n    PhClearReference(&ProcessNode->PagedPoolText);\n    PhClearReference(&ProcessNode->PeakPagedPoolText);\n    PhClearReference(&ProcessNode->NonPagedPoolText);\n    PhClearReference(&ProcessNode->PeakNonPagedPoolText);\n    PhClearReference(&ProcessNode->MinimumWorkingSetText);\n    PhClearReference(&ProcessNode->MaximumWorkingSetText);\n    PhClearReference(&ProcessNode->PrivateBytesDeltaText);\n    PhClearReference(&ProcessNode->TimeStampText);\n    PhClearReference(&ProcessNode->FileModifiedTimeText);\n    PhClearReference(&ProcessNode->FileSizeText);\n    PhClearReference(&ProcessNode->SubprocessCountText);\n    PhClearReference(&ProcessNode->JobObjectIdText);\n    PhClearReference(&ProcessNode->ProtectionText);\n    PhClearReference(&ProcessNode->DesktopInfoText);\n    PhClearReference(&ProcessNode->CpuCoreUsageText);\n    PhClearReference(&ProcessNode->ImageCoherencyText);\n    PhClearReference(&ProcessNode->ImageCoherencyStatusText);\n    PhClearReference(&ProcessNode->ErrorModeText);\n    PhClearReference(&ProcessNode->CodePageText);\n    PhClearReference(&ProcessNode->ParentPidText);\n    PhClearReference(&ProcessNode->ParentConsolePidText);\n    PhClearReference(&ProcessNode->SharedCommitText);\n    PhClearReference(&ProcessNode->CpuAverageText);\n    PhClearReference(&ProcessNode->CpuKernelText);\n    PhClearReference(&ProcessNode->CpuUserText);\n    PhClearReference(&ProcessNode->GrantedAccessText);\n    PhClearReference(&ProcessNode->TlsBitmapDeltaText);\n    PhClearReference(&ProcessNode->ReferenceCountText);\n    PhClearReference(&ProcessNode->LxssProcessIdText);\n    PhClearReference(&ProcessNode->ProcessStartKeyText);\n    PhClearReference(&ProcessNode->MitigationPoliciesText);\n    PhClearReference(&ProcessNode->ServicesText);\n\n    PhDeleteGraphBuffers(&ProcessNode->CpuGraphBuffers);\n    PhDeleteGraphBuffers(&ProcessNode->PrivateGraphBuffers);\n    PhDeleteGraphBuffers(&ProcessNode->IoGraphBuffers);\n\n    PhDereferenceObject(ProcessNode->ProcessItem);\n\n    PhFree(ProcessNode);\n\n    TreeNew_NodesStructured(ProcessTreeListHandle);\n}\n\nVOID PhUpdateProcessNode(\n    _In_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    memset(ProcessNode->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM);\n\n    PhClearReference(&ProcessNode->TooltipText);\n\n    PhInvalidateTreeNewNode(&ProcessNode->Node, TN_CACHE_COLOR | TN_CACHE_ICON);\n    TreeNew_InvalidateNode(ProcessTreeListHandle, &ProcessNode->Node);\n}\n\nVOID PhTickProcessNodes(\n    VOID\n    )\n{\n    ULONG i;\n    PH_TREENEW_VIEW_PARTS viewParts;\n    BOOLEAN fullyInvalidated;\n    RECT rect;\n\n    // Header text invalidation (dmex)\n\n    if (PhProcessTreeColumnHeaderCache)\n    {\n        memset(PhProcessTreeColumnHeaderCache, 0, PhProcessTreeColumnHeaderCacheLength);\n    }\n\n    // Node text invalidation, node updates\n\n    for (i = 0; i < ProcessNodeList->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNodeList->Items[i];\n\n        // The name and PID never change, so we don't invalidate that.\n        memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2));\n        node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID | PHPN_DESKTOPINFO | PHPN_CODEPAGE | PHPN_GRANTEDACCESS; // Items that always remain valid\n\n        // The DPI awareness defaults to unaware if not set or declared in the manifest in which case\n        // it can be changed once, so we can only be sure that it won't be changed again if it is different\n        // from Unaware (poizan42).\n        if (node->DpiAwareness != PH_PROCESS_DPI_AWARENESS_UNAWARE + 1)\n            node->ValidMask &= ~PHPN_DPIAWARENESS;\n\n        // Invalidate graph buffers.\n        node->CpuGraphBuffers.Valid = FALSE;\n        node->PrivateGraphBuffers.Valid = FALSE;\n        node->IoGraphBuffers.Valid = FALSE;\n    }\n\n    fullyInvalidated = FALSE;\n\n    if (PhCsSortRootProcesses || PhCsSortChildProcesses || ProcessTreeListSortOrder != NoSortOrder)\n    {\n        // Force a rebuild to sort the items.\n        TreeNew_NodesStructured(ProcessTreeListHandle);\n        fullyInvalidated = TRUE;\n    }\n\n    // State highlighting\n    PH_TICK_SH_STATE_TN(PH_PROCESS_NODE, ShState, ProcessNodeStateList, PhpRemoveProcessNode, PhCsHighlightingDuration, ProcessTreeListHandle, TRUE, &fullyInvalidated, NULL);\n\n    if (ProcessTreeListHandle && !fullyInvalidated)\n    {\n        // The first column doesn't need to be invalidated because the process name never changes, and\n        // icon changes are handled by the modified event. This small optimization can save more than\n        // 10 million cycles per update (on my machine). (wj32)\n        TreeNew_GetViewParts(ProcessTreeListHandle, &viewParts);\n        rect.left = viewParts.NormalLeft;\n        rect.top = viewParts.HeaderHeight;\n        rect.right = viewParts.ClientRect.right - viewParts.VScrollWidth;\n        rect.bottom = viewParts.ClientRect.bottom;\n\n        // Excluding the first column causes some visual tearing of the client area while scrolling the window\n        // because the region is excluded from the initial repainting, then included and painted a half second later\n        // by scrolling the window. Don't exclude the region during scrolling events, simply invalidate the entire window.\n        // This prevents multiple paint events accumulating in the update region, if the treelist repaints\n        // the client area then our InvalidateRect is a noop and we avoid the visual tearing. (dmex)\n\n        if (viewParts.ScrollTickCount > 2000)\n            InvalidateRect(ProcessTreeListHandle, &rect, FALSE);\n        else\n            InvalidateRect(ProcessTreeListHandle, NULL, FALSE);\n    }\n}\n\nstatic VOID PhpNeedGraphContext(\n    _In_ HDC hdc,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    // If we already have a graph context and it's the right size, then return immediately.\n    if (GraphContextWidth == Width && GraphContextHeight == Height)\n        return;\n\n    if (GraphContext)\n    {\n        // The original bitmap must be selected back into the context, otherwise\n        // the bitmap can't be deleted. (wj32)\n        if (GraphOldBitmap)\n        {\n            SelectBitmap(GraphContext, GraphOldBitmap);\n            GraphOldBitmap = NULL;\n        }\n\n        if (GraphBitmap)\n        {\n            DeleteBitmap(GraphBitmap);\n            GraphBitmap = NULL;\n        }\n\n        DeleteDC(GraphContext);\n        GraphContext = NULL;\n    }\n\n    GraphContextWidth = Width;\n    GraphContextHeight = Height;\n\n    GraphContext = CreateCompatibleDC(hdc);\n    if (!GraphContext)\n        return;\n    GraphBitmap = PhCreateDIBSection(hdc, PHBF_DIB, Width, Height, &GraphBits);\n    if (!GraphBitmap)\n        return;\n    GraphOldBitmap = SelectBitmap(GraphContext, GraphBitmap);\n}\n\n_Success_(return)\nstatic BOOLEAN PhpFormatInt32GroupDigits(\n    _In_ ULONG Value,\n    _Out_writes_bytes_(BufferLength) PWCHAR Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PPH_STRINGREF String\n    )\n{\n    PH_FORMAT format;\n    SIZE_T returnLength;\n\n    PhInitFormatU(&format, Value);\n    format.Type |= FormatGroupDigits;\n\n    if (PhFormatToBuffer(&format, 1, Buffer, BufferLength, &returnLength))\n    {\n        if (String)\n        {\n            String->Buffer = Buffer;\n            String->Length = returnLength - sizeof(UNICODE_NULL);\n        }\n\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\nFORCEINLINE VOID PhpAccumulateField(\n    _Inout_ PVOID Accumulator,\n    _In_ PVOID Value,\n    _In_ PH_AGGREGATE_TYPE Type\n    )\n{\n    switch (Type)\n    {\n    case AggregateTypeFloat:\n        *(PFLOAT)Accumulator += *(PFLOAT)Value;\n        break;\n    case AggregateTypeInt32:\n        *(PULONG)Accumulator += *(PULONG)Value;\n        break;\n    case AggregateTypeInt64:\n        *(PULONG64)Accumulator += *(PULONG64)Value;\n        break;\n    case AggregateTypeIntPtr:\n        *(PULONG_PTR)Accumulator += *(PULONG_PTR)Value;\n        break;\n    }\n}\n\nstatic VOID PhpAggregateField(\n    _In_ PPH_PROCESS_NODE ProcessNode,\n    _In_ PH_AGGREGATE_TYPE Type,\n    _In_ PH_AGGREGATE_LOCATION Location,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T FieldOffset,\n    _Inout_ PVOID AggregatedValue\n    )\n{\n    ULONG i;\n    ULONG_PTR offset;\n\n    PhpAccumulateField(AggregatedValue, PTR_ADD_OFFSET(BaseAddress, FieldOffset), Type);\n\n    switch (Location)\n    {\n    case AggregateProcessItem:\n        offset = (ULONG_PTR)BaseAddress - (ULONG_PTR)ProcessNode->ProcessItem;\n        break;\n    case AggregateProcessNode:\n        offset = (ULONG_PTR)BaseAddress - (ULONG_PTR)ProcessNode;\n        break;\n    default:\n        PhRaiseStatus(STATUS_INVALID_PARAMETER);\n    }\n\n    for (i = 0; i < ProcessNode->Children->Count; i++)\n    {\n        PPH_PROCESS_NODE node;\n        PVOID baseAddress;\n\n        node = ProcessNode->Children->Items[i];\n\n        switch (Location)\n        {\n        case AggregateProcessItem:\n            baseAddress = PTR_ADD_OFFSET(node->ProcessItem, offset);\n            break;\n        case AggregateProcessNode:\n            baseAddress = PTR_ADD_OFFSET(node, offset);\n            break;\n        DEFAULT_UNREACHABLE;\n        }\n\n        PhpAggregateField(node, Type, Location, baseAddress, FieldOffset, AggregatedValue);\n    }\n}\n\nVOID PhAggregateProcessFieldIfNeeded(\n    _In_ PPH_PROCESS_NODE ProcessNode,\n    _In_ PH_AGGREGATE_TYPE Type,\n    _In_ PH_AGGREGATE_LOCATION Location,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T FieldOffset,\n    _Inout_ PVOID AggregatedValue\n    )\n{\n    if (!PhCsPropagateCpuUsage || ProcessNode->Node.Expanded || (!PhCsSortChildProcesses && ProcessTreeListSortOrder != NoSortOrder))\n    {\n        PhpAccumulateField(AggregatedValue, PTR_ADD_OFFSET(BaseAddress, FieldOffset), Type);\n    }\n    else\n    {\n        PhpAggregateField(ProcessNode, Type, Location, BaseAddress, FieldOffset, AggregatedValue);\n    }\n}\n\nstatic VOID PhpAggregateFieldIfNeeded(\n    _In_ PPH_PROCESS_NODE ProcessNode,\n    _In_ PH_AGGREGATE_TYPE Type,\n    _In_ PH_AGGREGATE_LOCATION Location,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T FieldOffset,\n    _Inout_ PVOID AggregatedValue\n    )\n{\n    PhAggregateProcessFieldIfNeeded(ProcessNode, Type, Location, BaseAddress, FieldOffset, AggregatedValue);\n}\n\nstatic VOID PhpAggregateFieldTotal(\n    _In_ PPH_PROCESS_NODE ProcessNode,\n    _In_ PH_AGGREGATE_TYPE Type,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T FieldOffset,\n    _Inout_ PVOID AggregatedValue\n    )\n{\n    PhpAccumulateField(AggregatedValue, PTR_ADD_OFFSET(BaseAddress, FieldOffset), Type);\n}\n\nstatic VOID PhpUpdateProcessNodeWsCounters(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_WSCOUNTERS))\n    {\n        BOOLEAN success = FALSE;\n\n        if (\n            ProcessNode->ProcessItem->QueryHandle &&\n            PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessItem->ProcessId) &&\n            ProcessNode->ProcessItem->IsHandleValid // PROCESS_QUERY_INFORMATION\n            )\n        {\n            if (NT_SUCCESS(PhGetProcessWsCounters(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->WsCounters)))\n                success = TRUE;\n        }\n\n        if (!success)\n            memset(&ProcessNode->WsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS));\n\n        SetFlag(ProcessNode->ValidMask, PHPN_WSCOUNTERS);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeGdiHandles(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_GDIHANDLES))\n    {\n        if (ProcessNode->ProcessId == SYSTEM_PROCESS_ID)\n        {\n            if (!NT_SUCCESS(PhGetSessionGuiResources(GR_GDIOBJECTS, &ProcessNode->GdiHandles)))\n                ProcessNode->GdiHandles = 0;\n        }\n        else if (ProcessNode->ProcessItem->QueryHandle)\n        {\n            if (!NT_SUCCESS(PhGetProcessGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_GDIOBJECTS, &ProcessNode->GdiHandles)))\n                ProcessNode->GdiHandles = 0;\n        }\n        else\n        {\n            ProcessNode->GdiHandles = 0;\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_GDIHANDLES);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeUserHandles(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_USERHANDLES))\n    {\n        if (ProcessNode->ProcessId == SYSTEM_PROCESS_ID)\n        {\n            if (!NT_SUCCESS(PhGetSessionGuiResources(GR_USEROBJECTS, &ProcessNode->UserHandles)))\n                ProcessNode->UserHandles = 0;\n        }\n        else if (ProcessNode->ProcessItem->QueryHandle)\n        {\n            if (!NT_SUCCESS(PhGetProcessGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_USEROBJECTS, &ProcessNode->UserHandles)))\n                ProcessNode->UserHandles = 0;\n        }\n        else\n        {\n            ProcessNode->UserHandles = 0;\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_USERHANDLES);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeIoPagePriority(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_IOPAGEPRIORITY))\n    {\n        if (ProcessNode->ProcessItem->QueryHandle)\n        {\n            if (!NT_SUCCESS(PhGetProcessIoPriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->IoPriority)))\n                ProcessNode->IoPriority = ULONG_MAX;\n            if (!NT_SUCCESS(PhGetProcessPagePriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->PagePriority)))\n                ProcessNode->PagePriority = ULONG_MAX;\n        }\n        else\n        {\n            ProcessNode->IoPriority = ULONG_MAX;\n            ProcessNode->PagePriority = ULONG_MAX;\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_IOPAGEPRIORITY);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeWindow(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_WINDOW))\n    {\n        PhClearReference(&ProcessNode->WindowText);\n\n        if (ProcessNode->ProcessItem->QueryHandle && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            if (!ProcessNode->WindowHandle)\n            {\n                ProcessNode->WindowHandle = PhGetProcessMainWindow(\n                    ProcessNode->ProcessId,\n                    ProcessNode->ProcessItem->QueryHandle\n                    );\n            }\n\n            if (ProcessNode->WindowHandle)\n            {\n                PhGetWindowTextEx(\n                    ProcessNode->WindowHandle,\n                    PH_GET_WINDOW_TEXT_INTERNAL,\n                    &ProcessNode->WindowText\n                    );\n\n                ProcessNode->WindowHung = !!PhIsHungAppWindow(ProcessNode->WindowHandle);\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_WINDOW);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeDepStatus(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_DEPSTATUS))\n    {\n        ULONG depStatus = 0;\n\n#ifdef _WIN64\n        if (\n            ProcessNode->ProcessItem->QueryHandle &&\n            PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessItem->ProcessId) &&\n            ProcessNode->ProcessItem->IsWow64Process &&\n            ProcessNode->ProcessItem->IsHandleValid // PROCESS_QUERY_INFORMATION\n            )\n#else\n        if (PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessItem->ProcessId) && ProcessNode->ProcessItem->QueryHandle)\n#endif\n        {\n            PhGetProcessDepStatus(ProcessNode->ProcessItem->QueryHandle, &depStatus);\n        }\n        else\n        {\n            if (ProcessNode->ProcessItem->QueryHandle)\n            {\n                depStatus = PH_PROCESS_DEP_ENABLED | PH_PROCESS_DEP_PERMANENT;\n            }\n        }\n\n        ProcessNode->DepStatus = depStatus;\n\n        SetFlag(ProcessNode->ValidMask, PHPN_DEPSTATUS);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeToken(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_TOKEN))\n    {\n        HANDLE tokenHandle;\n\n        ProcessNode->VirtualizationAllowed = FALSE;\n        ProcessNode->VirtualizationEnabled = FALSE;\n\n        if (ProcessNode->ProcessItem->QueryHandle)\n        {\n            if (NT_SUCCESS(PhOpenProcessToken(\n                ProcessNode->ProcessItem->QueryHandle,\n                TOKEN_QUERY,\n                &tokenHandle\n                )))\n            {\n                if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &ProcessNode->VirtualizationAllowed)) &&\n                    ProcessNode->VirtualizationAllowed)\n                {\n                    if (!NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &ProcessNode->VirtualizationEnabled)))\n                    {\n                        ProcessNode->VirtualizationAllowed = FALSE; // display N/A on error\n                    }\n                }\n\n                NtClose(tokenHandle);\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_TOKEN);\n    }\n}\n\nstatic VOID PhpUpdateProcessOsContext(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_OSCONTEXT))\n    {\n        HANDLE processHandle;\n\n        if (PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessItem->ProcessId) && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessNode->ProcessId)))\n            {\n                if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid)))\n                {\n                    if (IsEqualGUID(&ProcessNode->OsContextGuid, &WIN10_CONTEXT_GUID))\n                        ProcessNode->OsContextVersion = WINDOWS_10;\n                    else if (IsEqualGUID(&ProcessNode->OsContextGuid, &WINBLUE_CONTEXT_GUID))\n                        ProcessNode->OsContextVersion = WINDOWS_8_1;\n                    else if (IsEqualGUID(&ProcessNode->OsContextGuid, &WIN8_CONTEXT_GUID))\n                        ProcessNode->OsContextVersion = WINDOWS_8;\n                    else if (IsEqualGUID(&ProcessNode->OsContextGuid, &WIN7_CONTEXT_GUID))\n                        ProcessNode->OsContextVersion = WINDOWS_7;\n                    else if (IsEqualGUID(&ProcessNode->OsContextGuid, &VISTA_CONTEXT_GUID))\n                        ProcessNode->OsContextVersion = WINDOWS_VISTA;\n                    else if (IsEqualGUID(&ProcessNode->OsContextGuid, &XP_CONTEXT_GUID))\n                        ProcessNode->OsContextVersion = WINDOWS_XP;\n                }\n\n                NtClose(processHandle);\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_OSCONTEXT);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeQuotaLimits(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_QUOTALIMITS))\n    {\n        QUOTA_LIMITS quotaLimits;\n\n        if (ProcessNode->ProcessItem->QueryHandle && NT_SUCCESS(PhGetProcessQuotaLimits(\n            ProcessNode->ProcessItem->QueryHandle,\n            &quotaLimits\n            )))\n        {\n            ProcessNode->MinimumWorkingSetSize = quotaLimits.MinimumWorkingSetSize;\n            ProcessNode->MaximumWorkingSetSize = quotaLimits.MaximumWorkingSetSize;\n        }\n        else\n        {\n            ProcessNode->MinimumWorkingSetSize = 0;\n            ProcessNode->MaximumWorkingSetSize = 0;\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_QUOTALIMITS);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeImage(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_IMAGE))\n    {\n        ProcessNode->Architecture = IMAGE_FILE_MACHINE_UNKNOWN;\n        ProcessNode->ImageMachine = IMAGE_FILE_MACHINE_UNKNOWN;\n        ProcessNode->ImageSubsystem = IMAGE_SUBSYSTEM_UNKNOWN;\n\n        if (ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            ProcessNode->ImageSubsystem = IMAGE_SUBSYSTEM_POSIX_CUI;\n        }\n        else if (ProcessNode->ProcessItem->FileName)\n        {\n            PH_MAPPED_IMAGE mappedImage;\n\n#ifdef _ARM64_\n            if (NT_SUCCESS(PhLoadMappedImageEx(&ProcessNode->ProcessItem->FileName->sr, NULL, &mappedImage)))\n#else\n            if (NT_SUCCESS(PhLoadMappedImageHeaderPageSize(&ProcessNode->ProcessItem->FileName->sr, NULL, &mappedImage)))\n#endif\n            {\n                ProcessNode->ImageMachine = mappedImage.NtHeaders->FileHeader.Machine;\n                ProcessNode->ImageTimeDateStamp = mappedImage.NtHeaders->FileHeader.TimeDateStamp;\n                ProcessNode->ImageCharacteristics = mappedImage.NtHeaders->FileHeader.Characteristics;\n\n                if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n                {\n                    ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->Subsystem;\n                    ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics;\n                }\n                else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n                {\n                    ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->Subsystem;\n                    ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics;\n                }\n\n#ifdef _ARM64_\n                if (ProcessNode->ImageMachine == IMAGE_FILE_MACHINE_AMD64 || ProcessNode->ImageMachine == IMAGE_FILE_MACHINE_ARM64)\n                    ProcessNode->ImageCHPEVersion = PhGetMappedImageCHPEVersion(&mappedImage);\n#endif\n\n                PhUnloadMappedImage(&mappedImage);\n            }\n        }\n\n        if (ProcessNode->ProcessItem->QueryHandle)\n        {\n            USHORT processArchitecture;\n\n            if (NT_SUCCESS(PhGetProcessArchitecture(ProcessNode->ProcessItem->QueryHandle, &processArchitecture)))\n            {\n                ProcessNode->Architecture = processArchitecture;\n            }\n        }\n\n        //if (PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessItem->ProcessId))\n        //{\n        //    HANDLE processHandle;\n        //    PVOID imageBaseAddress;\n        //    PH_REMOTE_MAPPED_IMAGE mappedImage;\n        //\n        //    if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessNode->ProcessId)))\n        //    {\n        //        if (NT_SUCCESS(PhGetProcessImageBaseAddress(processHandle, &imageBaseAddress)))\n        //        {\n        //            if (NT_SUCCESS(PhLoadRemoteMappedImage(processHandle, imageBaseAddress, &mappedImage)))\n        //            {\n        //                ProcessNode->ImageTimeDateStamp = mappedImage.NtHeaders->FileHeader.TimeDateStamp;\n        //                ProcessNode->ImageCharacteristics = mappedImage.NtHeaders->FileHeader.Characteristics;\n        //\n        //                if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n        //                {\n        //                    ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->Subsystem;\n        //                    ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics;\n        //                }\n        //                else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n        //                {\n        //                    ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->Subsystem;\n        //                    ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics;\n        //                }\n        //\n        //                PhUnloadRemoteMappedImage(&mappedImage);\n        //            }\n        //        }\n        //\n        //        NtClose(processHandle);\n        //    }\n        //}\n\n        SetFlag(ProcessNode->ValidMask, PHPN_IMAGE);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeAppId(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_APPID))\n    {\n        ULONG windowFlags;\n        PPH_STRING applicationUserModelId;\n\n        PhClearReference(&ProcessNode->AppIdText);\n\n        if (\n            PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessItem->ProcessId) &&\n            HR_SUCCESS(PhAppResolverGetAppIdForProcess(ProcessNode->ProcessId, &applicationUserModelId))\n            )\n        {\n            ProcessNode->AppIdText = applicationUserModelId;\n        }\n        else\n        {\n            if (ProcessNode->ProcessItem->QueryHandle && !ProcessNode->ProcessItem->IsSubsystemProcess)\n            {\n                if (NT_SUCCESS(PhGetProcessWindowTitle(\n                    ProcessNode->ProcessItem->QueryHandle,\n                    &windowFlags,\n                    &applicationUserModelId\n                    )))\n                {\n                    if (windowFlags & STARTF_TITLEISAPPID)\n                        ProcessNode->AppIdText = applicationUserModelId;\n                    else\n                        PhDereferenceObject(applicationUserModelId);\n                }\n\n                //if (WindowsVersion >= WINDOWS_8 && ProcessNode->ProcessItem->IsImmersive)\n                //{\n                //    HANDLE tokenHandle;\n                //\n                //    if (NT_SUCCESS(PhOpenProcessToken(\n                //        ProcessNode->ProcessItem->QueryHandle,\n                //        TOKEN_QUERY,\n                //        &tokenHandle\n                //        )))\n                //    {\n                //        ProcessNode->AppIdText = PhGetTokenPackageApplicationUserModelId(tokenHandle);\n                //        NtClose(tokenHandle);\n                //    }\n                //}\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_APPID);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeDpiAwareness(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_DPIAWARENESS))\n    {\n        if (ProcessNode->ProcessItem->QueryHandle && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            PH_PROCESS_DPI_AWARENESS dpiAwareness;\n\n            if (PhGetProcessDpiAwareness(ProcessNode->ProcessItem->QueryHandle, &dpiAwareness))\n                ProcessNode->DpiAwareness = dpiAwareness + 1;\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_DPIAWARENESS);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeFileAttributes(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_FILEATTRIBUTES))\n    {\n        FILE_NETWORK_OPEN_INFORMATION networkOpenInfo;\n\n        if (ProcessNode->ProcessItem->FileName && NT_SUCCESS(PhQueryFullAttributesFile(\n            &ProcessNode->ProcessItem->FileName->sr,\n            &networkOpenInfo\n            )))\n        {\n            ProcessNode->FileLastWriteTime = networkOpenInfo.LastWriteTime;\n            ProcessNode->FileEndOfFile = networkOpenInfo.EndOfFile;\n        }\n        else\n        {\n            ProcessNode->FileLastWriteTime.QuadPart = 0;\n            ProcessNode->FileEndOfFile.QuadPart = 0;\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_FILEATTRIBUTES);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeDesktopInfo(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_DESKTOPINFO))\n    {\n        HANDLE processHandle;\n\n        PhClearReference(&ProcessNode->DesktopInfoText);\n\n        if (PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessId) && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            if (NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n                ProcessNode->ProcessId\n                )))\n            {\n                PPH_STRING desktopinfo;\n\n                if (NT_SUCCESS(PhGetProcessDesktopInfo(processHandle, &desktopinfo)))\n                {\n                    ProcessNode->DesktopInfoText = desktopinfo;\n                }\n\n                NtClose(processHandle);\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_DESKTOPINFO);\n    }\n}\n\nstatic VOID PhpUpdateProcessBreakOnTermination(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_CRITICAL))\n    {\n        ProcessNode->BreakOnTerminationEnabled = FALSE;\n\n        if (ProcessNode->ProcessItem->QueryHandle && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            BOOLEAN breakOnTermination;\n\n            if (NT_SUCCESS(PhGetProcessBreakOnTermination(\n                ProcessNode->ProcessItem->QueryHandle,\n                &breakOnTermination\n                )))\n            {\n                ProcessNode->BreakOnTerminationEnabled = breakOnTermination;\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_CRITICAL);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeErrorMode(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_ERRORMODE))\n    {\n        PhClearReference(&ProcessNode->ErrorModeText);\n\n        if (ProcessNode->ProcessItem->QueryHandle && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            ULONG errorMode;\n\n            if (NT_SUCCESS(PhGetProcessErrorMode(\n                ProcessNode->ProcessItem->QueryHandle,\n                &errorMode\n                )) && errorMode > 0)\n            {\n                PH_STRING_BUILDER stringBuilder;\n                WCHAR pointer[PH_PTR_STR_LEN_1];\n\n                PhInitializeStringBuilder(&stringBuilder, 0x50);\n\n                if (errorMode & SEM_FAILCRITICALERRORS)\n                {\n                    PhAppendStringBuilder2(&stringBuilder, L\"Fail critical, \");\n                }\n\n                if (errorMode & SEM_NOGPFAULTERRORBOX)\n                {\n                    PhAppendStringBuilder2(&stringBuilder, L\"GP faults, \");\n                }\n\n                if (errorMode & SEM_NOALIGNMENTFAULTEXCEPT)\n                {\n                    PhAppendStringBuilder2(&stringBuilder, L\"Alignment faults, \");\n                }\n\n                if (errorMode & SEM_NOOPENFILEERRORBOX)\n                {\n                    PhAppendStringBuilder2(&stringBuilder, L\"Openfile faults, \");\n                }\n\n                if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n                    PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n                PhPrintPointer(pointer, UlongToPtr(errorMode));\n                PhAppendFormatStringBuilder(&stringBuilder, L\" (%s)\", pointer);\n\n                ProcessNode->ErrorModeText = PhFinalStringBuilderString(&stringBuilder);\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_ERRORMODE);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeCodePage(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_CODEPAGE))\n    {\n        if (PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessId) && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            HANDLE processHandle;\n\n            if (NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n                ProcessNode->ProcessId\n                )))\n            {\n                USHORT codePage;\n\n                if (NT_SUCCESS(PhGetProcessCodePage(processHandle, &codePage)))\n                {\n                    ProcessNode->CodePage = codePage;\n                }\n\n                NtClose(processHandle);\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_CODEPAGE);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodePowerThrottling(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_POWERTHROTTLING))\n    {\n        ProcessNode->PowerThrottling = FALSE;\n\n        if (ProcessNode->ProcessItem->QueryHandle && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            POWER_THROTTLING_PROCESS_STATE powerThrottlingState;\n\n            if (NT_SUCCESS(PhGetProcessPowerThrottlingState(ProcessNode->ProcessItem->QueryHandle, &powerThrottlingState)))\n            {\n                if (powerThrottlingState.ControlMask & POWER_THROTTLING_PROCESS_EXECUTION_SPEED &&\n                    powerThrottlingState.StateMask & POWER_THROTTLING_PROCESS_EXECUTION_SPEED)\n                {\n                    ProcessNode->PowerThrottling = TRUE;\n                }\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_POWERTHROTTLING);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodePriorityBoost(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_PRIORITYBOOST))\n    {\n        ProcessNode->PriorityBoost = FALSE;\n\n        if (ProcessNode->ProcessItem->QueryHandle && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            BOOLEAN priorityBoostDisabled;\n\n            if (NT_SUCCESS(PhGetProcessPriorityBoost(ProcessNode->ProcessItem->QueryHandle, &priorityBoostDisabled)))\n            {\n                ProcessNode->PriorityBoost = !priorityBoostDisabled;\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_PRIORITYBOOST);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeGrantedAccess(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_GRANTEDACCESS))\n    {\n        PhClearReference(&ProcessNode->GrantedAccessText);\n\n        if (PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessId))\n        {\n            NTSTATUS status;\n            HANDLE processHandle;\n            ACCESS_MASK processAccess;\n\n            if (ProcessNode->ProcessItem->IsProtectedProcess && ProcessNode->ProcessItem->Protection.Type == PsProtectedTypeProtectedLight)\n                processAccess = PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_LIMITED_INFORMATION;\n            else if (ProcessNode->ProcessItem->IsProtectedProcess && ProcessNode->ProcessItem->Protection.Type == PsProtectedTypeProtected)\n                processAccess = PROCESS_QUERY_LIMITED_INFORMATION;\n            else if (ProcessNode->ProcessItem->IsSubsystemProcess && KsiLevel() != KphLevelMax)\n                processAccess = PROCESS_QUERY_LIMITED_INFORMATION;\n            else\n                processAccess = MAXIMUM_ALLOWED;\n\n            status = PhOpenProcess(\n                &processHandle,\n                processAccess,\n                ProcessNode->ProcessId\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                OBJECT_BASIC_INFORMATION basicInfo;\n\n                status = PhQueryObjectBasicInformation(processHandle, &basicInfo);\n\n                if (NT_SUCCESS(status))\n                {\n                    PPH_ACCESS_ENTRY accessEntries;\n                    ULONG numberOfAccessEntries;\n\n                    if (PhGetAccessEntries(L\"Process\", &accessEntries, &numberOfAccessEntries))\n                    {\n                        ProcessNode->GrantedAccessText = PhGetAccessString(basicInfo.GrantedAccess, accessEntries, numberOfAccessEntries);\n                        PhFree(accessEntries);\n                    }\n\n                    if (ProcessNode->GrantedAccessText)\n                    {\n                        WCHAR grantedAccessString[PH_PTR_STR_LEN_1];\n                        PhPrintPointer(grantedAccessString, UlongToPtr(basicInfo.GrantedAccess));\n                        PhMoveReference(&ProcessNode->GrantedAccessText, PhFormatString(\n                            L\"%s (%s)\",\n                            PhGetString(ProcessNode->GrantedAccessText),\n                            grantedAccessString\n                            ));\n                    }\n                }\n\n                NtClose(processHandle);\n            }\n\n            if (!NT_SUCCESS(status))\n            {\n                PhMoveReference(&ProcessNode->GrantedAccessText, PhGetStatusMessage(status, 0));\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_GRANTEDACCESS);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeTlsBitmapDelta(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_TLSBITMAPDELTA))\n    {\n        if (PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessId) && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            HANDLE processHandle;\n\n            if (NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n                ProcessNode->ProcessId\n                )))\n            {\n                ULONG bitmapCount;\n                ULONG bitmapExpansionCount;\n\n                if (NT_SUCCESS(PhGetProcessTlsBitMapCounters(processHandle, &bitmapCount, &bitmapExpansionCount)))\n                {\n                    ProcessNode->TlsBitmapCount = (USHORT)(bitmapCount + bitmapExpansionCount);\n                }\n\n                NtClose(processHandle);\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_TLSBITMAPDELTA);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeObjectReferences(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_REFERENCEDELTA))\n    {\n        if (PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessId))\n        {\n            ProcessNode->ReferenceCount = 0;\n\n            if (ProcessNode->ProcessItem->QueryHandle)\n            {\n                OBJECT_BASIC_INFORMATION basicInfo;\n\n                if (NT_SUCCESS(PhQueryObjectBasicInformation(ProcessNode->ProcessItem->QueryHandle, &basicInfo)))\n                {\n                    ProcessNode->ReferenceCount = basicInfo.HandleCount;\n                }\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_REFERENCEDELTA);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeStartKey(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_STARTKEY))\n    {\n        ProcessNode->ProcessStartKey = 0;\n\n        if (ProcessNode->ProcessItem->QueryHandle)\n        {\n            ULONGLONG processStartKey;\n\n            if (NT_SUCCESS(PhGetProcessStartKey(ProcessNode->ProcessItem->QueryHandle, &processStartKey)))\n            {\n                PH_FORMAT format[2];\n\n                PhInitFormatS(&format[0], L\"0x\");\n                PhInitFormatI64X(&format[1], processStartKey);\n                PhMoveReference(&ProcessNode->ProcessStartKeyText, PhFormat(format, 2, 0));\n                ProcessNode->ProcessStartKey = processStartKey;\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_STARTKEY);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeMitigationPolicies(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_MITIGATIONPOLICIES))\n    {\n        PhClearReference(&ProcessNode->MitigationPoliciesText);\n\n        if (ProcessNode->ProcessItem->QueryHandle && !ProcessNode->ProcessItem->IsSubsystemProcess)\n        {\n            NTSTATUS status;\n            PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION information;\n\n            status = PhGetProcessMitigationPolicyAllInformation(ProcessNode->ProcessItem->QueryHandle, &information);\n\n            if (NT_SUCCESS(status))\n            {\n                PH_STRING_BUILDER sb;\n                PROCESS_MITIGATION_POLICY policy;\n                PPH_STRING shortDescription;\n\n                PhInitializeStringBuilder(&sb, 100);\n\n                for (policy = 0; policy < MaxProcessMitigationPolicy; policy++)\n                {\n                    if (information.Pointers[policy] && PhDescribeProcessMitigationPolicy(\n                        policy,\n                        information.Pointers[policy],\n                        &shortDescription,\n                        NULL\n                        ))\n                    {\n                        PhAppendStringBuilder(&sb, &shortDescription->sr);\n                        PhAppendStringBuilder2(&sb, L\"; \");\n                        PhDereferenceObject(shortDescription);\n                    }\n                }\n\n                // HACK: Show System process CET mitigation (dmex)\n                if (ProcessNode->ProcessItem->ProcessId == SYSTEM_PROCESS_ID)\n                {\n                    SYSTEM_SHADOW_STACK_INFORMATION shadowStackInformation;\n\n                    if (NT_SUCCESS(PhGetSystemShadowStackInformation(&shadowStackInformation)))\n                    {\n                        PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policyData;\n\n                        memset(&policyData, 0, sizeof(PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY));\n                        policyData.EnableUserShadowStack = shadowStackInformation.KernelCetEnabled;\n                        policyData.EnableUserShadowStackStrictMode = shadowStackInformation.KernelCetEnabled;\n                        policyData.AuditUserShadowStack = shadowStackInformation.KernelCetAuditModeEnabled;\n\n                        if (PhDescribeProcessMitigationPolicy(\n                            ProcessUserShadowStackPolicy,\n                            &policyData,\n                            &shortDescription,\n                            NULL\n                            ))\n                        {\n                            PhAppendStringBuilder(&sb, &shortDescription->sr);\n                            PhAppendStringBuilder2(&sb, L\"; \");\n                            PhDereferenceObject(shortDescription);\n                        }\n                    }\n                }\n\n                if (sb.String->Length != 0)\n                    PhRemoveEndStringBuilder(&sb, 2);\n\n                ProcessNode->MitigationPoliciesText = PhFinalStringBuilderString(&sb);\n            }\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_MITIGATIONPOLICIES);\n    }\n}\n\nstatic VOID PhpUpdateProcessNodeServices(\n    _Inout_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    if (!FlagOn(ProcessNode->ValidMask, PHPN_SERVICES))\n    {\n        PhClearReference(&ProcessNode->ServicesText);\n\n        if (ProcessNode->ProcessItem->ServiceList && ProcessNode->ProcessItem->ServiceList->Count != 0)\n        {\n            ULONG enumerationKey = 0;\n            PPH_SERVICE_ITEM serviceItem;\n            PH_STRING_BUILDER stringBuilder;\n\n            PhAcquireQueuedLockShared(&ProcessNode->ProcessItem->ServiceListLock);\n\n            PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n            while (PhEnumPointerList(\n                ProcessNode->ProcessItem->ServiceList,\n                &enumerationKey,\n                &serviceItem\n                ))\n            {\n                PhAppendStringBuilder(&stringBuilder, &serviceItem->Name->sr);\n                PhAppendStringBuilder2(&stringBuilder, L\", \");\n                //PhAppendStringBuilder2(&stringBuilder, L\" (\");\n                //PhAppendStringBuilder(&stringBuilder, &serviceItem->DisplayName->sr);\n                //PhAppendStringBuilder2(&stringBuilder, L\"), \");\n            }\n\n            if (stringBuilder.String->Length != 0)\n                PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n            ProcessNode->ServicesText = PhFinalStringBuilderString(&stringBuilder);\n\n            PhReleaseQueuedLockShared(&ProcessNode->ProcessItem->ServiceListLock);\n        }\n\n        SetFlag(ProcessNode->ValidMask, PHPN_SERVICES);\n    }\n}\n\n#define SORT_FUNCTION(Column) PhpProcessTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpProcessTreeNewCompare##Column( \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)_elem1; \\\n    PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)_elem2; \\\n    PPH_PROCESS_ITEM processItem1 = node1->ProcessItem; \\\n    PPH_PROCESS_ITEM processItem2 = node2->ProcessItem; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId); \\\n    \\\n    return PhModifySort(sortResult, ProcessTreeListSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpProcessTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    if (Result == 0)\n        Result = intptrcmp((LONG_PTR)((PPH_PROCESS_NODE)Node1)->ProcessItem->ProcessId, (LONG_PTR)((PPH_PROCESS_NODE)Node2)->ProcessItem->ProcessId);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        processItem1->ProcessName,\n        processItem2->ProcessName,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Pid)\n{\n    // Use signed int so DPCs and Interrupts are placed above System Idle Process.\n    sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Cpu)\n{\n    FLOAT number1 = 0;\n    FLOAT number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeFloat, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUsage), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeFloat, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUsage), &number2);\n\n    sortResult = singlecmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoTotalRate)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number1);\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number1);\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number1);\n\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number2);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number2);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PrivateBytes)\n{\n    ULONG_PTR number1 = 0;\n    ULONG_PTR number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PagefileUsage), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeIntPtr, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PagefileUsage), &number2);\n\n    sortResult = uintptrcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(UserName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        processItem1->UserName,\n        processItem2->UserName,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Description)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        processItem1->VersionInfo.FileDescription,\n        processItem2->VersionInfo.FileDescription,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CompanyName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        processItem1->VersionInfo.CompanyName,\n        processItem2->VersionInfo.CompanyName,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Version)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        processItem1->VersionInfo.FileVersion,\n        processItem2->VersionInfo.FileVersion,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        processItem1->FileName,\n        processItem2->FileName,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CommandLine)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        processItem1->CommandLine,\n        processItem2->CommandLine,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PeakPrivateBytes)\n{\n    sortResult = uintptrcmp(processItem1->VmCounters.PeakPagefileUsage, processItem2->VmCounters.PeakPagefileUsage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(WorkingSet)\n{\n    ULONG_PTR number1 = 0;\n    ULONG_PTR number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.WorkingSetSize), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeIntPtr, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.WorkingSetSize), &number2);\n\n\n    sortResult = uintptrcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PeakWorkingSet)\n{\n    sortResult = uintptrcmp(processItem1->VmCounters.PeakWorkingSetSize, processItem2->VmCounters.PeakWorkingSetSize);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PrivateWs)\n{\n    ULONG_PTR number1 = 0;\n    ULONG_PTR number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, WorkingSetPrivateSize), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeIntPtr, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, WorkingSetPrivateSize), &number2);\n\n    sortResult = uintptrcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(SharedWs)\n{\n    PhpUpdateProcessNodeWsCounters(node1);\n    PhpUpdateProcessNodeWsCounters(node2);\n    sortResult = uintptrcmp(node1->WsCounters.NumberOfSharedPages, node2->WsCounters.NumberOfSharedPages);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ShareableWs)\n{\n    PhpUpdateProcessNodeWsCounters(node1);\n    PhpUpdateProcessNodeWsCounters(node2);\n    sortResult = uintptrcmp(node1->WsCounters.NumberOfShareablePages, node2->WsCounters.NumberOfShareablePages);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(VirtualSize)\n{\n    ULONG_PTR number1 = 0;\n    ULONG_PTR number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.VirtualSize), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeIntPtr, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.VirtualSize), &number2);\n\n    sortResult = uintptrcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PeakVirtualSize)\n{\n    sortResult = uintptrcmp(processItem1->VmCounters.PeakVirtualSize, processItem2->VmCounters.PeakVirtualSize);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PageFaults)\n{\n    ULONG number1 = 0;\n    ULONG number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt32, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PageFaultCount), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt32, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PageFaultCount), &number2);\n\n    sortResult = uintcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(SessionId)\n{\n    sortResult = uintcmp(processItem1->SessionId, processItem2->SessionId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(BasePriority)\n{\n    sortResult = intcmp(processItem1->BasePriority, processItem2->BasePriority);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Threads)\n{\n    ULONG number1 = 0;\n    ULONG number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt32, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfThreads), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt32, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfThreads), &number2);\n\n    sortResult = uintcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Handles)\n{\n    ULONG number1 = 0;\n    ULONG number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt32, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfHandles), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt32, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfHandles), &number2);\n\n    sortResult = uintcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(GdiHandles)\n{\n    ULONG number1 = 0;\n    ULONG number2 = 0;\n\n    PhpUpdateProcessNodeGdiHandles(node1);\n    PhpUpdateProcessNodeGdiHandles(node2);\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt32, AggregateProcessNode, node1, FIELD_OFFSET(PH_PROCESS_NODE, GdiHandles), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt32, AggregateProcessNode, node2, FIELD_OFFSET(PH_PROCESS_NODE, GdiHandles), &number2);\n\n    sortResult = uintcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(UserHandles)\n{\n    ULONG number1 = 0;\n    ULONG number2 = 0;\n\n    PhpUpdateProcessNodeUserHandles(node1);\n    PhpUpdateProcessNodeUserHandles(node2);\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt32, AggregateProcessNode, node1, FIELD_OFFSET(PH_PROCESS_NODE, UserHandles), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt32, AggregateProcessNode, node2, FIELD_OFFSET(PH_PROCESS_NODE, UserHandles), &number2);\n\n    sortResult = uintcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoRoRate)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number1);\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number1);\n\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number2);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoWRate)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Integrity)\n{\n    sortResult = uintcmp(processItem1->IntegrityLevel.Level, processItem2->IntegrityLevel.Level);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoPriority)\n{\n    sortResult = uintcmp(node1->IoPriority, node2->IoPriority);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PagePriority)\n{\n    sortResult = uintcmp(node1->PagePriority, node2->PagePriority);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StartTime)\n{\n    sortResult = int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(TotalCpuTime)\n{\n    sortResult = uint64cmp(\n        processItem1->KernelTime.QuadPart + processItem1->UserTime.QuadPart,\n        processItem2->KernelTime.QuadPart + processItem2->UserTime.QuadPart\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(KernelCpuTime)\n{\n    sortResult = uint64cmp(processItem1->KernelTime.QuadPart, processItem2->KernelTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(UserCpuTime)\n{\n    sortResult = uint64cmp(processItem1->UserTime.QuadPart, processItem2->UserTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(VerificationStatus)\n{\n    sortResult = uintcmp(processItem1->VerifyResult, processItem2->VerifyResult);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(VerifiedSigner)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        processItem1->VerifySignerName,\n        processItem2->VerifySignerName,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Aslr)\n{\n    PhpUpdateProcessNodeImage(node1);\n    PhpUpdateProcessNodeImage(node2);\n    sortResult = intcmp(\n        node1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE,\n        node2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(RelativeStartTime)\n{\n    sortResult = -int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Bits)\n{\n    sortResult = uintcmp(processItem1->IsWow64Process, processItem2->IsWow64Process);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Elevation)\n{\n    ULONG key1 = (ULONG)processItem1->ElevationType + (processItem1->IsElevated ? 4 : 0);\n    ULONG key2 = (ULONG)processItem2->ElevationType + (processItem2->IsElevated ? 4 : 0);\n\n    sortResult = uintcmp(key1, key2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(WindowTitle)\n{\n    PhpUpdateProcessNodeWindow(node1);\n    PhpUpdateProcessNodeWindow(node2);\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->WindowText,\n        node2->WindowText,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(WindowStatus)\n{\n    PhpUpdateProcessNodeWindow(node1);\n    PhpUpdateProcessNodeWindow(node2);\n    sortResult = ucharcmp(node1->WindowHung, node2->WindowHung);\n\n    // Make sure all processes with windows get grouped together.\n    if (sortResult == 0)\n        sortResult = intcmp(!!node1->WindowHandle, !!node2->WindowHandle);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Cycles)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CyclesDelta)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Delta), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Delta), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Dep)\n{\n    PhpUpdateProcessNodeDepStatus(node1);\n    PhpUpdateProcessNodeDepStatus(node2);\n    sortResult = uintcmp(node1->DepStatus, node2->DepStatus);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Virtualized)\n{\n    PhpUpdateProcessNodeToken(node1);\n    PhpUpdateProcessNodeToken(node2);\n    sortResult = ucharcmp(node1->VirtualizationEnabled, node2->VirtualizationEnabled);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ContextSwitches)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt32, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt32, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ContextSwitchesDelta)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt32, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Delta), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt32, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Delta), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PageFaultsDelta)\n{\n    ULONG number1 = 0;\n    ULONG number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt32, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, PageFaultsDelta.Delta), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt32, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, PageFaultsDelta.Delta), &number2);\n\n    sortResult = uintcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoReads)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoWrites)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoOther)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoReadBytes)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoWriteBytes)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoOtherBytes)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoReadsDelta)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoWritesDelta)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoOtherDelta)\n{\n    ULONG64 number1 = 0;\n    ULONG64 number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeInt64, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Value), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeInt64, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Value), &number2);\n\n    sortResult = uint64cmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(OsContext)\n{\n    PhpUpdateProcessOsContext(node1);\n    PhpUpdateProcessOsContext(node2);\n    sortResult = uintcmp(node1->OsContextVersion, node2->OsContextVersion);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PagedPool)\n{\n    ULONG_PTR number1 = 0;\n    ULONG_PTR number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaPagedPoolUsage), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeIntPtr, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaPagedPoolUsage), &number2);\n\n    sortResult = uintptrcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PeakPagedPool)\n{\n    sortResult = uintptrcmp(processItem1->VmCounters.QuotaPeakPagedPoolUsage, processItem2->VmCounters.QuotaPeakPagedPoolUsage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(NonPagedPool)\n{\n    ULONG_PTR number1 = 0;\n    ULONG_PTR number2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaNonPagedPoolUsage), &number1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeIntPtr, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaNonPagedPoolUsage), &number2);\n\n    sortResult = uintptrcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PeakNonPagedPool)\n{\n    sortResult = uintptrcmp(processItem1->VmCounters.QuotaPeakNonPagedPoolUsage, processItem2->VmCounters.QuotaPeakNonPagedPoolUsage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(MinimumWorkingSet)\n{\n    ULONG_PTR number1 = 0;\n    ULONG_PTR number2 = 0;\n\n    PhpUpdateProcessNodeQuotaLimits(node1);\n    PhpUpdateProcessNodeQuotaLimits(node2);\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessNode, node1, FIELD_OFFSET(PH_PROCESS_NODE, MinimumWorkingSetSize), &number1);\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessNode, node1, FIELD_OFFSET(PH_PROCESS_NODE, MinimumWorkingSetSize), &number1);\n\n    sortResult = uintptrcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(MaximumWorkingSet)\n{\n    ULONG_PTR number1 = 0;\n    ULONG_PTR number2 = 0;\n\n    PhpUpdateProcessNodeQuotaLimits(node1);\n    PhpUpdateProcessNodeQuotaLimits(node2);\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessNode, node1, FIELD_OFFSET(PH_PROCESS_NODE, MaximumWorkingSetSize), &number1);\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessNode, node1, FIELD_OFFSET(PH_PROCESS_NODE, MaximumWorkingSetSize), &number1);\n\n    sortResult = uintptrcmp(number1, number2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PrivateBytesDelta)\n{\n    LONG_PTR value1 = 0;\n    LONG_PTR value2 = 0;\n\n    PhpAggregateFieldIfNeeded(node1, AggregateTypeIntPtr, AggregateProcessItem, processItem1, FIELD_OFFSET(PH_PROCESS_ITEM, PrivateBytesDelta.Delta), &value1);\n    PhpAggregateFieldIfNeeded(node2, AggregateTypeIntPtr, AggregateProcessItem, processItem2, FIELD_OFFSET(PH_PROCESS_ITEM, PrivateBytesDelta.Delta), &value2);\n\n    // Ignore zero when sorting (dmex)\n    if (value1 != 0 && value2 != 0)\n    {\n        if (value1 > value2)\n            return -1;\n        else if (value1 < value2)\n            return 1;\n\n        return 0;\n    }\n    else if (value1 == 0)\n    {\n        return value2 == 0 ? 0 : (ProcessTreeListSortOrder == AscendingSortOrder ? -1 : 1);\n    }\n    else\n    {\n        return (ProcessTreeListSortOrder == AscendingSortOrder ? 1 : -1);\n    }\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Subsystem)\n{\n    PhpUpdateProcessNodeImage(node1);\n    PhpUpdateProcessNodeImage(node2);\n    sortResult = ushortcmp(node1->ImageSubsystem, node2->ImageSubsystem);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PackageName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        processItem1->PackageFullName,\n        processItem2->PackageFullName,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(AppId)\n{\n    PhpUpdateProcessNodeAppId(node1);\n    PhpUpdateProcessNodeAppId(node2);\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->AppIdText,\n        node2->AppIdText,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(DpiAwareness)\n{\n    PhpUpdateProcessNodeDpiAwareness(node1);\n    PhpUpdateProcessNodeDpiAwareness(node2);\n    sortResult = uintcmp(node1->DpiAwareness, node2->DpiAwareness);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CfGuard)\n{\n    // prefer XFG over CFG\n    sortResult = uintcmp(node1->ProcessItem->IsXfgEnabled, node2->ProcessItem->IsXfgEnabled);\n\n    if (sortResult == 0)\n    {\n        // prefer XFG audit over CFG\n        sortResult = uintcmp(node1->ProcessItem->IsXfgAuditEnabled, node2->ProcessItem->IsXfgAuditEnabled);\n\n        if (sortResult == 0)\n        {\n            sortResult = uintcmp(node1->ProcessItem->IsControlFlowGuardEnabled, node2->ProcessItem->IsControlFlowGuardEnabled);\n        }\n    }\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(TimeStamp)\n{\n    PhpUpdateProcessNodeImage(node1);\n    PhpUpdateProcessNodeImage(node2);\n    sortResult = uintcmp(node1->ImageTimeDateStamp, node2->ImageTimeDateStamp);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileModifiedTime)\n{\n    PhpUpdateProcessNodeFileAttributes(node1);\n    PhpUpdateProcessNodeFileAttributes(node2);\n    sortResult = int64cmp(node1->FileLastWriteTime.QuadPart, node2->FileLastWriteTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileSize)\n{\n    PhpUpdateProcessNodeFileAttributes(node1);\n    PhpUpdateProcessNodeFileAttributes(node2);\n    sortResult = int64cmp(node1->FileEndOfFile.QuadPart, node2->FileEndOfFile.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Subprocesses)\n{\n    sortResult = uint64cmp(node1->Children->Count, node2->Children->Count);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(JobObjectId)\n{\n    sortResult = uint64cmp(processItem1->JobObjectId, processItem2->JobObjectId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Protection)\n{\n    sortResult = ucharcmp((BOOLEAN)processItem1->IsSecureSystem, (BOOLEAN)processItem2->IsSecureSystem);\n    if (sortResult == 0)\n    {\n        sortResult = ucharcmp((BOOLEAN)processItem1->IsSecureProcess, (BOOLEAN)processItem2->IsSecureProcess);\n        if (sortResult == 0)\n        {\n            sortResult = ucharcmp((BOOLEAN)processItem1->IsProtectedProcess, (BOOLEAN)processItem2->IsProtectedProcess);\n            if (sortResult == 0)\n            {\n                sortResult = ucharcmp(processItem1->Protection.Level, processItem2->Protection.Level);\n            }\n        }\n    }\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(DesktopInfo)\n{\n    PhpUpdateProcessNodeDesktopInfo(node1);\n    PhpUpdateProcessNodeDesktopInfo(node2);\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->DesktopInfoText,\n        node2->DesktopInfoText,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Critical)\n{\n    PhpUpdateProcessBreakOnTermination(node1);\n    PhpUpdateProcessBreakOnTermination(node2);\n    sortResult = ucharcmp(node1->BreakOnTerminationEnabled, node2->BreakOnTerminationEnabled);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(HexPid)\n{\n    sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CpuCore)\n{\n    sortResult = singlecmp(processItem1->CpuUsage, processItem2->CpuUsage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Cet)\n{\n    sortResult = uintcmp(node1->ProcessItem->IsCetEnabled, node2->ProcessItem->IsCetEnabled);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ImageCoherency)\n{\n    sortResult = singlecmp(processItem1->ImageCoherency, processItem2->ImageCoherency);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Architecture)\n{\n    USHORT architecture1;\n    USHORT architecture2;\n\n    PhpUpdateProcessNodeImage(node1);\n    PhpUpdateProcessNodeImage(node2);\n\n    if (node1->Architecture != IMAGE_FILE_MACHINE_UNKNOWN)\n        architecture1 = node1->Architecture;\n    else\n        architecture1 = node1->ImageMachine;\n\n    if (node2->Architecture != IMAGE_FILE_MACHINE_UNKNOWN)\n        architecture2 = node2->Architecture;\n    else\n        architecture2 = node2->ImageMachine;\n\n    sortResult = ushortcmp(architecture1, architecture2);\n#ifdef _ARM64_\n    if (sortResult == 0)\n        sortResult = uintcmp(node1->ImageCHPEVersion, node2->ImageCHPEVersion);\n#endif\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ErrorMode)\n{\n    PhpUpdateProcessNodeErrorMode(node1);\n    PhpUpdateProcessNodeErrorMode(node2);\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->ErrorModeText,\n        node2->ErrorModeText,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CodePage)\n{\n    PhpUpdateProcessNodeCodePage(node1);\n    PhpUpdateProcessNodeCodePage(node2);\n\n    sortResult = ushortcmp(node1->CodePage, node2->CodePage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PowerThrottling)\n{\n    PhpUpdateProcessNodePowerThrottling(node1);\n    PhpUpdateProcessNodePowerThrottling(node2);\n    sortResult = ucharcmp(node1->PowerThrottling, node2->PowerThrottling);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ParentPid)\n{\n    sortResult = intptrcmp((LONG_PTR)processItem1->ParentProcessId, (LONG_PTR)processItem2->ParentProcessId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ParentConsolePid)\n{\n    sortResult = intptrcmp((LONG_PTR)processItem1->ConsoleHostProcessId, (LONG_PTR)processItem2->ConsoleHostProcessId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(SharedCommit)\n{\n    sortResult = uint64cmp(processItem1->SharedCommitCharge, processItem2->SharedCommitCharge);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PriorityBoost)\n{\n    PhpUpdateProcessNodePriorityBoost(node1);\n    PhpUpdateProcessNodePriorityBoost(node2);\n    sortResult = ucharcmp(node1->PriorityBoost, node2->PriorityBoost);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CpuAverage)\n{\n    sortResult = singlecmp(processItem1->CpuAverageUsage, processItem2->CpuAverageUsage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CpuKernel)\n{\n    sortResult = singlecmp(processItem1->CpuKernelUsage, processItem2->CpuKernelUsage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CpuUser)\n{\n    sortResult = singlecmp(processItem1->CpuUserUsage, processItem2->CpuUserUsage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(GrantedAccess)\n{\n    PhpUpdateProcessNodeGrantedAccess(node1);\n    PhpUpdateProcessNodeGrantedAccess(node2);\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->GrantedAccessText,\n        node2->GrantedAccessText,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(TlsBitmapDelta)\n{\n    PhpUpdateProcessNodeTlsBitmapDelta(node1);\n    PhpUpdateProcessNodeTlsBitmapDelta(node2);\n    sortResult = ushortcmp(node1->TlsBitmapCount, node2->TlsBitmapCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ReferenceDelta)\n{\n    PhpUpdateProcessNodeObjectReferences(node1);\n    PhpUpdateProcessNodeObjectReferences(node2);\n    sortResult = uintcmp(node1->ReferenceCount, node2->ReferenceCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LxssPid)\n{\n    sortResult = uintcmp(node1->ProcessItem->LxssProcessId, node2->ProcessItem->LxssProcessId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StartKey)\n{\n    PhpUpdateProcessNodeStartKey(node1);\n    PhpUpdateProcessNodeStartKey(node2);\n    sortResult = uint64cmp(node1->ProcessStartKey, node2->ProcessStartKey);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(MitigationPolicies)\n{\n    PhpUpdateProcessNodeMitigationPolicies(node1);\n    PhpUpdateProcessNodeMitigationPolicies(node2);\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->MitigationPoliciesText,\n        node2->MitigationPoliciesText,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Services)\n{\n    PhpUpdateProcessNodeServices(node1);\n    PhpUpdateProcessNodeServices(node2);\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->ServicesText,\n        node2->ServicesText,\n        ProcessTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpProcessTreeNewCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_PROCESS_NODE node;\n\n    if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &ProcessTreeListCm))\n        return TRUE;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            PPH_LIST sortList;\n            ULONG sortColumn;\n            PH_SORT_ORDER sortOrder;\n\n            node = (PPH_PROCESS_NODE)getChildren->Node;\n            sortList = NULL;\n            sortColumn = ProcessTreeListSortColumn;\n            sortOrder = ProcessTreeListSortOrder;\n\n            if (PhCsSortChildProcesses)\n            {\n                if (!node)\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)ProcessNodeRootList->Items;\n                    getChildren->NumberOfChildren = ProcessNodeRootList->Count;\n                    if (PhCsSortRootProcesses)\n                        sortList = ProcessNodeRootList;\n                }\n                else if (sortOrder == NoSortOrder)\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;\n                    getChildren->NumberOfChildren = node->Children->Count;\n                    sortList = node->Children;\n                    sortColumn = PHPRTLC_PID;\n                    sortOrder = AscendingSortOrder;\n                }\n                else\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;\n                    getChildren->NumberOfChildren = node->Children->Count;\n                    sortList = node->Children;\n                }\n            }\n            else\n            {\n                if (sortOrder == NoSortOrder)\n                {\n                    if (!node)\n                    {\n                        getChildren->Children = (PPH_TREENEW_NODE *)ProcessNodeRootList->Items;\n                        getChildren->NumberOfChildren = ProcessNodeRootList->Count;\n                        if (PhCsSortRootProcesses)\n                            sortList = ProcessNodeRootList;\n                    }\n                    else\n                    {\n                        getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;\n                        getChildren->NumberOfChildren = node->Children->Count;\n                    }\n                }\n                else if (!node)\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)ProcessNodeList->Items;\n                    getChildren->NumberOfChildren = ProcessNodeList->Count;\n                    sortList = ProcessNodeList;\n                }\n            }\n\n            if (sortList)\n            {\n                static PVOID sortFunctions[] =\n                {\n                    SORT_FUNCTION(Name),\n                    SORT_FUNCTION(Pid),\n                    SORT_FUNCTION(Cpu),\n                    SORT_FUNCTION(IoTotalRate),\n                    SORT_FUNCTION(PrivateBytes),\n                    SORT_FUNCTION(UserName),\n                    SORT_FUNCTION(Description),\n                    SORT_FUNCTION(CompanyName),\n                    SORT_FUNCTION(Version),\n                    SORT_FUNCTION(FileName),\n                    SORT_FUNCTION(CommandLine),\n                    SORT_FUNCTION(PeakPrivateBytes),\n                    SORT_FUNCTION(WorkingSet),\n                    SORT_FUNCTION(PeakWorkingSet),\n                    SORT_FUNCTION(PrivateWs),\n                    SORT_FUNCTION(SharedWs),\n                    SORT_FUNCTION(ShareableWs),\n                    SORT_FUNCTION(VirtualSize),\n                    SORT_FUNCTION(PeakVirtualSize),\n                    SORT_FUNCTION(PageFaults),\n                    SORT_FUNCTION(SessionId),\n                    SORT_FUNCTION(BasePriority), // Priority Class\n                    SORT_FUNCTION(BasePriority),\n                    SORT_FUNCTION(Threads),\n                    SORT_FUNCTION(Handles),\n                    SORT_FUNCTION(GdiHandles),\n                    SORT_FUNCTION(UserHandles),\n                    SORT_FUNCTION(IoRoRate),\n                    SORT_FUNCTION(IoWRate),\n                    SORT_FUNCTION(Integrity),\n                    SORT_FUNCTION(IoPriority),\n                    SORT_FUNCTION(PagePriority),\n                    SORT_FUNCTION(StartTime),\n                    SORT_FUNCTION(TotalCpuTime),\n                    SORT_FUNCTION(KernelCpuTime),\n                    SORT_FUNCTION(UserCpuTime),\n                    SORT_FUNCTION(VerificationStatus),\n                    SORT_FUNCTION(VerifiedSigner),\n                    SORT_FUNCTION(Aslr),\n                    SORT_FUNCTION(RelativeStartTime),\n                    SORT_FUNCTION(Bits),\n                    SORT_FUNCTION(Elevation),\n                    SORT_FUNCTION(WindowTitle),\n                    SORT_FUNCTION(WindowStatus),\n                    SORT_FUNCTION(Cycles),\n                    SORT_FUNCTION(CyclesDelta),\n                    SORT_FUNCTION(Cpu), // CPU History\n                    SORT_FUNCTION(PrivateBytes), // Private Bytes History\n                    SORT_FUNCTION(IoTotalRate), // I/O History\n                    SORT_FUNCTION(Dep),\n                    SORT_FUNCTION(Virtualized),\n                    SORT_FUNCTION(ContextSwitches),\n                    SORT_FUNCTION(ContextSwitchesDelta),\n                    SORT_FUNCTION(PageFaultsDelta),\n                    SORT_FUNCTION(IoReads),\n                    SORT_FUNCTION(IoWrites),\n                    SORT_FUNCTION(IoOther),\n                    SORT_FUNCTION(IoReadBytes),\n                    SORT_FUNCTION(IoWriteBytes),\n                    SORT_FUNCTION(IoOtherBytes),\n                    SORT_FUNCTION(IoReadsDelta),\n                    SORT_FUNCTION(IoWritesDelta),\n                    SORT_FUNCTION(IoOtherDelta),\n                    SORT_FUNCTION(OsContext),\n                    SORT_FUNCTION(PagedPool),\n                    SORT_FUNCTION(PeakPagedPool),\n                    SORT_FUNCTION(NonPagedPool),\n                    SORT_FUNCTION(PeakNonPagedPool),\n                    SORT_FUNCTION(MinimumWorkingSet),\n                    SORT_FUNCTION(MaximumWorkingSet),\n                    SORT_FUNCTION(PrivateBytesDelta),\n                    SORT_FUNCTION(Subsystem),\n                    SORT_FUNCTION(PackageName),\n                    SORT_FUNCTION(AppId),\n                    SORT_FUNCTION(DpiAwareness),\n                    SORT_FUNCTION(CfGuard),\n                    SORT_FUNCTION(TimeStamp),\n                    SORT_FUNCTION(FileModifiedTime),\n                    SORT_FUNCTION(FileSize),\n                    SORT_FUNCTION(Subprocesses),\n                    SORT_FUNCTION(JobObjectId),\n                    SORT_FUNCTION(Protection),\n                    SORT_FUNCTION(DesktopInfo),\n                    SORT_FUNCTION(Critical),\n                    SORT_FUNCTION(HexPid),\n                    SORT_FUNCTION(CpuCore),\n                    SORT_FUNCTION(Cet),\n                    SORT_FUNCTION(ImageCoherency),\n                    SORT_FUNCTION(ErrorMode),\n                    SORT_FUNCTION(CodePage),\n                    SORT_FUNCTION(StartTime), // Timeline\n                    SORT_FUNCTION(PowerThrottling),\n                    SORT_FUNCTION(Architecture),\n                    SORT_FUNCTION(ParentPid),\n                    SORT_FUNCTION(ParentConsolePid),\n                    SORT_FUNCTION(SharedCommit),\n                    SORT_FUNCTION(PriorityBoost),\n                    SORT_FUNCTION(CpuAverage),\n                    SORT_FUNCTION(CpuKernel),\n                    SORT_FUNCTION(CpuUser),\n                    SORT_FUNCTION(GrantedAccess),\n                    SORT_FUNCTION(TlsBitmapDelta),\n                    SORT_FUNCTION(ReferenceDelta),\n                    SORT_FUNCTION(LxssPid),\n                    SORT_FUNCTION(StartKey),\n                    SORT_FUNCTION(MitigationPolicies),\n                    SORT_FUNCTION(Services),\n                };\n                int (__cdecl *sortFunction)(const void *, const void *);\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PHPRTLC_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (!PhCmForwardSort(\n                    (PPH_TREENEW_NODE *)sortList->Items,\n                    sortList->Count,\n                    sortColumn,\n                    sortOrder,\n                    &ProcessTreeListCm\n                    ))\n                {\n                    if (sortColumn < PHPRTLC_MAXIMUM)\n                        sortFunction = sortFunctions[sortColumn];\n                    else\n                        sortFunction = NULL;\n\n                    if (sortFunction)\n                    {\n                        qsort(sortList->Items, sortList->Count, sizeof(PVOID), sortFunction);\n                    }\n                }\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n\n            node = (PPH_PROCESS_NODE)isLeaf->Node;\n\n            if (PhCsSortChildProcesses || ProcessTreeListSortOrder == NoSortOrder)\n                isLeaf->IsLeaf = node->Children->Count == 0;\n            else\n                isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            PPH_PROCESS_ITEM processItem;\n\n            node = (PPH_PROCESS_NODE)getCellText->Node;\n            processItem = node->ProcessItem;\n\n            switch (getCellText->Id)\n            {\n            case PHPRTLC_NAME:\n                getCellText->Text = PhGetStringRef(processItem->ProcessName);\n                break;\n            case PHPRTLC_PID:\n                {\n                    if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId))\n                    {\n                        PhInitializeStringRefLongHint(&getCellText->Text, processItem->ProcessIdString);\n                    }\n                }\n                break;\n            case PHPRTLC_CPU:\n                {\n                    FLOAT cpuUsage = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeFloat, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUsage), &cpuUsage);\n                    cpuUsage *= 100;\n\n                    if (cpuUsage >= PhMaxPrecisionLimit)\n                    {\n                        PH_FORMAT format;\n                        SIZE_T returnLength;\n\n                        PhInitFormatF(&format, cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); // minus null terminator\n                        }\n                    }\n                    else if (cpuUsage != 0 && PhCsShowCpuBelow001)\n                    {\n                        PH_FORMAT format[2];\n                        SIZE_T returnLength;\n\n                        PhInitFormatS(&format[0], L\"< \");\n                        PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(format, 2, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                }\n                break;\n            case PHPRTLC_IOTOTALRATE:\n                {\n                    ULONG64 number = 0;\n\n                    if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) // delta is wrong on first run of process provider\n                    {\n                        PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number);\n                        PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number);\n                        PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number);\n                        number *= 1000;\n                        number /= PhCsUpdateInterval;\n                    }\n\n                    if (number != 0)\n                    {\n                        PH_FORMAT format[2];\n\n                        PhInitFormatSize(&format[0], number);\n                        PhInitFormatS(&format[1], L\"/s\");\n\n                        PhMoveReference(&node->IoTotalRateText, PhFormat(format, 2, 0));\n                        getCellText->Text = node->IoTotalRateText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_PRIVATEBYTES:\n                {\n                    SIZE_T value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PagefileUsage), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->PrivateBytesText, PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = PhGetStringRef(node->PrivateBytesText);\n                    }\n                }\n                break;\n            case PHPRTLC_USERNAME:\n                {\n                    getCellText->Text = PhGetStringRef(processItem->UserName);\n                }\n                break;\n            case PHPRTLC_DESCRIPTION:\n                {\n                    getCellText->Text = PhGetStringRef(processItem->VersionInfo.FileDescription);\n                }\n                break;\n            case PHPRTLC_COMPANYNAME:\n                {\n                    getCellText->Text = PhGetStringRef(processItem->VersionInfo.CompanyName);\n                }\n                break;\n            case PHPRTLC_VERSION:\n                {\n                    getCellText->Text = PhGetStringRef(processItem->VersionInfo.FileVersion);\n                }\n                break;\n            case PHPRTLC_FILENAME:\n                {\n                    if (processItem->FileName)\n                    {\n                        PhMoveReference(&node->FileNameWin32, PhGetFileName(processItem->FileName));\n                    }\n\n                    if (node->FileNameWin32)\n                        getCellText->Text = PhGetStringRef(node->FileNameWin32);\n                    else\n                        getCellText->Text = PhGetStringRef(processItem->FileName);\n                }\n                break;\n            case PHPRTLC_COMMANDLINE:\n                {\n                    getCellText->Text = PhGetStringRef(processItem->CommandLine);\n                }\n                break;\n            case PHPRTLC_PEAKPRIVATEBYTES:\n                {\n                    if (processItem->VmCounters.PeakPagefileUsage != 0)\n                    {\n                        PhMoveReference(&node->PeakPrivateBytesText, PhFormatSize(processItem->VmCounters.PeakPagefileUsage, ULONG_MAX));\n                        getCellText->Text = node->PeakPrivateBytesText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_WORKINGSET:\n                {\n                    SIZE_T value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.WorkingSetSize), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->WorkingSetText, PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->WorkingSetText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_PEAKWORKINGSET:\n                {\n                    PhMoveReference(&node->PeakWorkingSetText, PhFormatSize(processItem->VmCounters.PeakWorkingSetSize, ULONG_MAX));\n                    getCellText->Text = node->PeakWorkingSetText->sr;\n                }\n                break;\n            case PHPRTLC_PRIVATEWS:\n                {\n                    SIZE_T value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, WorkingSetPrivateSize), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->PrivateWsText, PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->PrivateWsText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_SHAREDWS:\n                {\n                    PhpUpdateProcessNodeWsCounters(node);\n                    PhMoveReference(&node->SharedWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfSharedPages * PAGE_SIZE, ULONG_MAX));\n                    getCellText->Text = node->SharedWsText->sr;\n                }\n                break;\n            case PHPRTLC_SHAREABLEWS:\n                {\n                    PhpUpdateProcessNodeWsCounters(node);\n                    PhMoveReference(&node->ShareableWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfShareablePages * PAGE_SIZE, ULONG_MAX));\n                    getCellText->Text = node->ShareableWsText->sr;\n                }\n                break;\n            case PHPRTLC_VIRTUALSIZE:\n                {\n                    SIZE_T value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.VirtualSize), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->VirtualSizeText, PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->VirtualSizeText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_PEAKVIRTUALSIZE:\n                {\n                    PhMoveReference(&node->PeakVirtualSizeText, PhFormatSize(processItem->VmCounters.PeakVirtualSize, ULONG_MAX));\n                    getCellText->Text = node->PeakVirtualSizeText->sr;\n                }\n                break;\n            case PHPRTLC_PAGEFAULTS:\n                {\n                    ULONG value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PageFaultCount), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->PageFaultsText, PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->PageFaultsText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_SESSIONID:\n                {\n                    PhMoveReference(&node->SessionIdText, PhFormatUInt64(processItem->SessionId, TRUE));\n                    getCellText->Text = node->SessionIdText->sr;\n                }\n                break;\n            case PHPRTLC_PRIORITYCLASS:\n                {\n                    if (processItem->PriorityClass != PROCESS_PRIORITY_CLASS_UNKNOWN)\n                    {\n                        PCPH_STRINGREF string;\n\n                        if (string = PhGetProcessPriorityClassString(processItem->PriorityClass))\n                        {\n                            getCellText->Text.Length = string->Length;\n                            getCellText->Text.Buffer = string->Buffer;\n                        }\n                    }\n                }\n                break;\n            case PHPRTLC_BASEPRIORITY:\n                {\n                    PhMoveReference(&node->BasePriorityText, PhFormatUInt64(processItem->BasePriority, TRUE));\n                    getCellText->Text = node->BasePriorityText->sr;\n                }\n                break;\n            case PHPRTLC_THREADS:\n                {\n                    ULONG value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfThreads), &value);\n                    //PhpFormatInt32GroupDigits(value, node->ThreadsText, sizeof(node->ThreadsText), &getCellText->Text);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->ThreadsText, PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->ThreadsText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_HANDLES:\n                {\n                    ULONG value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfHandles), &value);\n                    //PhpFormatInt32GroupDigits(value, node->HandlesText, sizeof(node->HandlesText), &getCellText->Text);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->HandlesText, PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->HandlesText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_GDIHANDLES:\n                {\n                    ULONG value = 0;\n\n                    PhpUpdateProcessNodeGdiHandles(node);\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateProcessNode, node, FIELD_OFFSET(PH_PROCESS_NODE, GdiHandles), &value);\n                    //PhpFormatInt32GroupDigits(value, node->GdiHandlesText, sizeof(node->GdiHandlesText), &getCellText->Text);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->GdiHandlesText, PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->GdiHandlesText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_USERHANDLES:\n                {\n                    ULONG value = 0;\n\n                    PhpUpdateProcessNodeUserHandles(node);\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateProcessNode, node, FIELD_OFFSET(PH_PROCESS_NODE, UserHandles), &value);\n                    //PhpFormatInt32GroupDigits(value, node->UserHandlesText, sizeof(node->UserHandlesText), &getCellText->Text);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->UserHandlesText, PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->UserHandlesText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IORORATE:\n                {\n                    ULONG64 number = 0;\n\n                    if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value)\n                    {\n                        PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number);\n                        PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number);\n                        number *= 1000;\n                        number /= PhCsUpdateInterval;\n                    }\n\n                    if (number != 0)\n                    {\n                        PH_FORMAT format[2];\n\n                        PhInitFormatSize(&format[0], number);\n                        PhInitFormatS(&format[1], L\"/s\");\n                        PhMoveReference(&node->IoRoRateText, PhFormat(format, 2, 0));\n                        getCellText->Text = node->IoRoRateText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOWRATE:\n                {\n                    ULONG64 number = 0;\n\n                    if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value)\n                    {\n                        PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number);\n                        number *= 1000;\n                        number /= PhCsUpdateInterval;\n                    }\n\n                    if (number != 0)\n                    {\n                        PH_FORMAT format[2];\n\n                        PhInitFormatSize(&format[0], number);\n                        PhInitFormatS(&format[1], L\"/s\");\n                        PhMoveReference(&node->IoWRateText, PhFormat(format, 2, 0));\n                        getCellText->Text = node->IoWRateText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_INTEGRITY:\n                {\n                    if (processItem->IntegrityString)\n                    {\n                        getCellText->Text.Buffer = processItem->IntegrityString->Buffer;\n                        getCellText->Text.Length = processItem->IntegrityString->Length;\n                    }\n                    else\n                    {\n                        if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId) || processItem->ProcessId == SYSTEM_PROCESS_ID)\n                        {\n                            static CONST PH_STRINGREF integrityLevelSystemString = PH_STRINGREF_INIT(L\"System\");\n                            getCellText->Text.Buffer = integrityLevelSystemString.Buffer;\n                            getCellText->Text.Length = integrityLevelSystemString.Length;\n                        }\n                    }\n                }\n                break;\n            case PHPRTLC_IOPRIORITY:\n                {\n                    PhpUpdateProcessNodeIoPagePriority(node);\n\n                    if (node->IoPriority != ULONG_MAX && node->IoPriority >= IoPriorityVeryLow && node->IoPriority < MaxIoPriorityTypes)\n                    {\n                        const PH_STRINGREF ioPriority = PhIoPriorityHintNames[node->IoPriority];\n\n                        getCellText->Text.Buffer = ioPriority.Buffer;\n                        getCellText->Text.Length = ioPriority.Length;\n                    }\n                }\n                break;\n            case PHPRTLC_PAGEPRIORITY:\n                {\n                    PhpUpdateProcessNodeIoPagePriority(node);\n\n                    if (node->PagePriority != ULONG_MAX && node->PagePriority <= MEMORY_PRIORITY_NORMAL)\n                    {\n                        const PH_STRINGREF pagePriority = PhPagePriorityNames[node->PagePriority];\n\n                        getCellText->Text.Buffer = pagePriority.Buffer;\n                        getCellText->Text.Length = pagePriority.Length;\n                    }\n                }\n                break;\n            case PHPRTLC_STARTTIME:\n                {\n                    if (processItem->CreateTime.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &processItem->CreateTime);\n                        PhMoveReference(&node->StartTimeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = node->StartTimeText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_TOTALCPUTIME:\n                {\n                    SIZE_T returnLength;\n                    WCHAR totalCpuTimeText[PH_TIMESPAN_STR_LEN_1];\n\n                    if (PhPrintTimeSpanToBuffer(\n                        processItem->KernelTime.QuadPart + processItem->UserTime.QuadPart,\n                        PH_TIMESPAN_DHMSM,\n                        totalCpuTimeText,\n                        sizeof(totalCpuTimeText),\n                        &returnLength\n                        ))\n                    {\n                        PH_STRINGREF string =\n                        {\n                            .Buffer = totalCpuTimeText,\n                            .Length = returnLength - sizeof(UNICODE_NULL)\n                        };\n\n                        PhMoveReference(&node->TotalCpuTimeText, PhCreateString2(&string));\n                        getCellText->Text = node->TotalCpuTimeText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_KERNELCPUTIME:\n                {\n                    SIZE_T returnLength;\n                    WCHAR kernelCpuTimeText[PH_TIMESPAN_STR_LEN_1];\n\n                    if (PhPrintTimeSpanToBuffer(\n                        processItem->KernelTime.QuadPart,\n                        PH_TIMESPAN_DHMSM,\n                        kernelCpuTimeText,\n                        sizeof(kernelCpuTimeText),\n                        &returnLength\n                        ))\n                    {\n                        PH_STRINGREF string =\n                        {\n                            .Buffer = kernelCpuTimeText,\n                            .Length = returnLength - sizeof(UNICODE_NULL)\n                        };\n\n                        PhMoveReference(&node->KernelCpuTimeText, PhCreateString2(&string));\n                        getCellText->Text = node->KernelCpuTimeText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_USERCPUTIME:\n                {\n                    SIZE_T returnLength;\n                    WCHAR userCpuTimeText[PH_TIMESPAN_STR_LEN_1];\n\n                    if (PhPrintTimeSpanToBuffer(\n                        processItem->UserTime.QuadPart,\n                        PH_TIMESPAN_DHMSM,\n                        userCpuTimeText,\n                        sizeof(userCpuTimeText),\n                        &returnLength\n                        ))\n                    {\n                        PH_STRINGREF string =\n                        {\n                            .Buffer = userCpuTimeText,\n                            .Length = returnLength - sizeof(UNICODE_NULL)\n                        };\n\n                        PhMoveReference(&node->UserCpuTimeText, PhCreateString2(&string));\n                        getCellText->Text = node->UserCpuTimeText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_VERIFICATIONSTATUS:\n                {\n                    if (PhEnableProcessQueryStage2)\n                        getCellText->Text = PhVerifyResultToStringRef(processItem->VerifyResult);\n                    else\n                        PhInitializeStringRef(&getCellText->Text, L\"Image digital signature support disabled.\");\n                }\n                break;\n            case PHPRTLC_VERIFIEDSIGNER:\n                {\n                    if (PhEnableProcessQueryStage2)\n                        getCellText->Text = PhGetStringRef(processItem->VerifySignerName);\n                    else\n                        PhInitializeStringRef(&getCellText->Text, L\"Image digital signature support disabled.\");\n                }\n                break;\n            case PHPRTLC_ASLR:\n                {\n                    PhpUpdateProcessNodeImage(node);\n\n                    if (FlagOn(node->ImageDllCharacteristics, IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE))\n                        PhInitializeStringRef(&getCellText->Text, L\"ASLR\");\n                    else\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                }\n                break;\n            case PHPRTLC_RELATIVESTARTTIME:\n                {\n                    if (processItem->CreateTime.QuadPart != 0)\n                    {\n                        LARGE_INTEGER currentTime;\n\n                        PhQuerySystemTime(&currentTime);\n\n                        if (PhGetIntegerSetting(SETTING_ENABLE_SHORT_RELATIVE_START_TIME))\n                        {\n                            if (processItem->CreateTime.QuadPart < currentTime.QuadPart)\n                            {\n                                ULONG64 relativeCreateTime = currentTime.QuadPart - processItem->CreateTime.QuadPart;\n                                PhMoveReference(&node->RelativeStartTimeText, PhFormatTimeSpan(relativeCreateTime, PH_TIMESPAN_DHMS));\n                            }\n                            else\n                            {\n                                PhMoveReference(&node->RelativeStartTimeText, PhCreateString(L\"\\u221E\"));\n                            }\n                        }\n                        else\n                        {\n                            PPH_STRING startTimeString;\n\n                            if (processItem->CreateTime.QuadPart < currentTime.QuadPart)\n                            {\n                                startTimeString = PhFormatTimeSpanRelative(currentTime.QuadPart - processItem->CreateTime.QuadPart);\n                                PhMoveReference(&node->RelativeStartTimeText, PhConcatStringRefZ(&startTimeString->sr, L\" ago\"));\n                                PhDereferenceObject(startTimeString);\n                            }\n                            else\n                            {\n                                PhMoveReference(&node->RelativeStartTimeText, PhCreateString(L\"\\u221E\"));\n                            }\n                        }\n\n                        getCellText->Text = node->RelativeStartTimeText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_BITS:\n                {\n#ifdef _WIN64\n                    PhInitializeStringRef(&getCellText->Text, processItem->IsWow64Process ? L\"32\" : L\"64\");\n#else\n                    PhInitializeStringRef(&getCellText->Text, L\"32\");\n#endif\n                }\n                break;\n            case PHPRTLC_ELEVATION:\n                {\n                    PCPH_STRINGREF elevationType;\n\n                    if (PhGetElevationTypeString(!!processItem->IsElevated, processItem->ElevationType, &elevationType))\n                    {\n                        getCellText->Text.Buffer = elevationType->Buffer;\n                        getCellText->Text.Length = elevationType->Length;\n                    }\n                }\n                break;\n            case PHPRTLC_WINDOWTITLE:\n                {\n                    PhpUpdateProcessNodeWindow(node);\n                    PhSwapReference(&node->WindowTitleText, node->WindowText);\n                    getCellText->Text = PhGetStringRef(node->WindowTitleText);\n                }\n                break;\n            case PHPRTLC_WINDOWSTATUS:\n                {\n                    PhpUpdateProcessNodeWindow(node);\n\n                    if (node->WindowHandle)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, node->WindowHung ? L\"Not responding\" : L\"Running\");\n                    }\n                }\n                break;\n            case PHPRTLC_CYCLES:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Value), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->CyclesText, PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->CyclesText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_CYCLESDELTA:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Delta), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->CyclesDeltaText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_DEP:\n                {\n                    PH_STRING_BUILDER sb;\n\n                    PhpUpdateProcessNodeDepStatus(node);\n\n                    PhInitializeStringBuilder(&sb, 20);\n\n                    if (FlagOn(node->DepStatus, PH_PROCESS_DEP_ENABLED))\n                    {\n                        if (FlagOn(node->DepStatus, PH_PROCESS_DEP_PERMANENT))\n                            PhAppendStringBuilder2(&sb, L\"DEP (permanent), \");\n                        else\n                            PhAppendStringBuilder2(&sb, L\"DEP, \");\n                    }\n\n                    if (FlagOn(node->DepStatus, PH_PROCESS_DEP_ATL_THUNK_EMULATION_DISABLED))\n                        PhAppendStringBuilder2(&sb, L\"ATL emulation, \");\n                    if (FlagOn(node->DepStatus, PH_PROCESS_DEP_EXECUTE_ENABLED))\n                        PhAppendStringBuilder2(&sb, L\"Execute enabled, \");\n                    if (FlagOn(node->DepStatus, PH_PROCESS_DEP_IMAGE_ENABLED))\n                        PhAppendStringBuilder2(&sb, L\"Image enabled, \");\n                    if (FlagOn(node->DepStatus, PH_PROCESS_DEP_DISABLE_EXCEPTION_CHAIN))\n                        PhAppendStringBuilder2(&sb, L\"Chain disabled, \");\n\n                    if (PhEndsWithString2(sb.String, L\", \", FALSE))\n                        PhRemoveEndStringBuilder(&sb, 2);\n\n                    PhMoveReference(&node->DepStatusText, PhFinalStringBuilderString(&sb));\n                    getCellText->Text = node->DepStatusText->sr;\n                }\n                break;\n            case PHPRTLC_VIRTUALIZED:\n                {\n                    PhpUpdateProcessNodeToken(node);\n\n                    if (node->VirtualizationEnabled)\n                        PhInitializeStringRef(&getCellText->Text, L\"Virtualized\");\n                    else\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                }\n                break;\n            case PHPRTLC_CONTEXTSWITCHES:\n                {\n                    ULONG value = 0;\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Value), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->ContextSwitchesText, PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->ContextSwitchesText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_CONTEXTSWITCHESDELTA:\n                {\n                    if ((LONG)processItem->ContextSwitchesDelta.Delta >= 0) // the delta may be negative if a thread exits - just don't show anything\n                    {\n                        ULONG value = 0;\n                        PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Delta), &value);\n\n                        if (value != 0)\n                        {\n                            PhMoveReference(&node->ContextSwitchesDeltaText, PhFormatUInt64(value, TRUE));\n                            getCellText->Text = node->ContextSwitchesDeltaText->sr;\n                        }\n                    }\n                }\n                break;\n            case PHPRTLC_PAGEFAULTSDELTA:\n                {\n                    ULONG value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, PageFaultsDelta.Delta), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->PageFaultsDeltaText, PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->PageFaultsDeltaText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOREADS:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Value), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->IoGroupText[0], PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->IoGroupText[0]->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOWRITES:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Value), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->IoGroupText[1], PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->IoGroupText[1]->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOOTHER:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Value), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->IoGroupText[2], PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->IoGroupText[2]->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOREADBYTES:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Value), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->IoGroupText[3], PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->IoGroupText[3]->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOWRITEBYTES:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Value), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->IoGroupText[4], PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->IoGroupText[4]->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOOTHERBYTES:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Value), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->IoGroupText[5], PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->IoGroupText[5]->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOREADSDELTA:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Delta), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->IoGroupText[6], PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->IoGroupText[6]->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOWRITESDELTA:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Delta), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->IoGroupText[7], PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->IoGroupText[7]->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_IOOTHERDELTA:\n                {\n                    ULONG64 value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Delta), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->IoGroupText[8], PhFormatUInt64(value, TRUE));\n                        getCellText->Text = node->IoGroupText[8]->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_OSCONTEXT:\n                {\n                    PhpUpdateProcessOsContext(node);\n                    switch (node->OsContextVersion)\n                    {\n                    case WINDOWS_10:\n                        PhInitializeStringRef(&getCellText->Text, L\"Windows 10\");\n                        break;\n                    case WINDOWS_8_1:\n                        PhInitializeStringRef(&getCellText->Text, L\"Windows 8.1\");\n                        break;\n                    case WINDOWS_8:\n                        PhInitializeStringRef(&getCellText->Text, L\"Windows 8\");\n                        break;\n                    case WINDOWS_7:\n                        PhInitializeStringRef(&getCellText->Text, L\"Windows 7\");\n                        break;\n                    case WINDOWS_VISTA:\n                        PhInitializeStringRef(&getCellText->Text, L\"Windows Vista\");\n                        break;\n                    case WINDOWS_XP:\n                        PhInitializeStringRef(&getCellText->Text, L\"Windows XP\");\n                        break;\n                    }\n                }\n                break;\n            case PHPRTLC_PAGEDPOOL:\n                {\n                    SIZE_T value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaPagedPoolUsage), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->PagedPoolText, PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->PagedPoolText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_PEAKPAGEDPOOL:\n                {\n                    PhMoveReference(&node->PeakPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakPagedPoolUsage, ULONG_MAX));\n                    getCellText->Text = node->PeakPagedPoolText->sr;\n                }\n                break;\n            case PHPRTLC_NONPAGEDPOOL:\n                {\n                    SIZE_T value = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaNonPagedPoolUsage), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->NonPagedPoolText, PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->NonPagedPoolText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_PEAKNONPAGEDPOOL:\n                {\n                    if (processItem->VmCounters.QuotaPeakNonPagedPoolUsage != 0)\n                    {\n                        PhMoveReference(&node->PeakNonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakNonPagedPoolUsage, ULONG_MAX));\n                        getCellText->Text = node->PeakNonPagedPoolText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_MINIMUMWORKINGSET:\n                {\n                    SIZE_T value = 0;\n                    PhpUpdateProcessNodeQuotaLimits(node);\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateProcessNode, node, FIELD_OFFSET(PH_PROCESS_NODE, MinimumWorkingSetSize), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->MinimumWorkingSetText, PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->MinimumWorkingSetText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_MAXIMUMWORKINGSET:\n                {\n                    SIZE_T value = 0;\n                    PhpUpdateProcessNodeQuotaLimits(node);\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateProcessNode, node, FIELD_OFFSET(PH_PROCESS_NODE, MaximumWorkingSetSize), &value);\n\n                    if (value != 0)\n                    {\n                        PhMoveReference(&node->MaximumWorkingSetText, PhFormatSize(value, ULONG_MAX));\n                        getCellText->Text = node->MaximumWorkingSetText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_PRIVATEBYTESDELTA:\n                {\n                    LONG_PTR delta = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, PrivateBytesDelta.Delta), &delta);\n\n                    if (delta != 0)\n                    {\n                        PH_FORMAT format[2];\n\n                        if (delta > 0)\n                        {\n                            PhInitFormatC(&format[0], L'+');\n                        }\n                        else\n                        {\n                            PhInitFormatC(&format[0], L'-');\n                            delta = -delta;\n                        }\n\n                        format[1].Type = SizeFormatType | FormatUseRadix;\n                        format[1].Radix = (UCHAR)PhMaxSizeUnit;\n                        format[1].u.Size = delta;\n\n                        PhMoveReference(&node->PrivateBytesDeltaText, PhFormat(format, 2, 0));\n                        getCellText->Text = node->PrivateBytesDeltaText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_SUBSYSTEM:\n                {\n                    PhpUpdateProcessNodeImage(node);\n\n                    switch (node->ImageSubsystem)\n                    {\n                    case 0:\n                        break;\n                    case IMAGE_SUBSYSTEM_NATIVE:\n                        PhInitializeStringRef(&getCellText->Text, L\"Native\");\n                        break;\n                    case IMAGE_SUBSYSTEM_WINDOWS_GUI:\n                        PhInitializeStringRef(&getCellText->Text, L\"Windows\");\n                        break;\n                    case IMAGE_SUBSYSTEM_WINDOWS_CUI:\n                        PhInitializeStringRef(&getCellText->Text, L\"Console\");\n                        break;\n                    case IMAGE_SUBSYSTEM_OS2_CUI:\n                        PhInitializeStringRef(&getCellText->Text, L\"OS/2\");\n                        break;\n                    case IMAGE_SUBSYSTEM_POSIX_CUI:\n                        PhInitializeStringRef(&getCellText->Text, L\"POSIX\");\n                        break;\n                    default:\n                        PhInitializeStringRef(&getCellText->Text, L\"Unknown\");\n                        break;\n                    }\n                }\n                break;\n            case PHPRTLC_PACKAGENAME:\n                {\n                    getCellText->Text = PhGetStringRef(processItem->PackageFullName);\n                }\n                break;\n            case PHPRTLC_APPID:\n                {\n                    PhpUpdateProcessNodeAppId(node);\n                    getCellText->Text = PhGetStringRef(node->AppIdText);\n                }\n                break;\n            case PHPRTLC_DPIAWARENESS:\n                {\n                    PhpUpdateProcessNodeDpiAwareness(node);\n\n                    switch (node->DpiAwareness)\n                    {\n                    case PH_PROCESS_DPI_AWARENESS_UNAWARE + 1:\n                        PhInitializeStringRef(&getCellText->Text, L\"Unaware\");\n                        break;\n                    case PH_PROCESS_DPI_AWARENESS_SYSTEM_DPI_AWARE + 1:\n                        PhInitializeStringRef(&getCellText->Text, L\"System aware\");\n                        break;\n                    case PH_PROCESS_DPI_AWARENESS_PER_MONITOR_DPI_AWARE + 1:\n                        PhInitializeStringRef(&getCellText->Text, L\"Per-monitor aware\");\n                        break;\n                    case PH_PROCESS_DPI_AWARENESS_PER_MONITOR_AWARE_V2 + 1:\n                        PhInitializeStringRef(&getCellText->Text, L\"Per-monitor V2\");\n                        break;\n                    case PH_PROCESS_DPI_AWARENESS_UNAWARE_GDISCALED + 1:\n                        PhInitializeStringRef(&getCellText->Text, L\"Unaware (GDI scaled)\");\n                        break;\n                    }\n                }\n                break;\n            case PHPRTLC_CFGUARD:\n                {\n                    if (processItem->IsXfgAuditEnabled)\n                        PhInitializeStringRef(&getCellText->Text, L\"XF Guard (audit)\");\n                    else if (processItem->IsXfgEnabled)\n                        PhInitializeStringRef(&getCellText->Text, L\"XF Guard\");\n                    else if (processItem->IsControlFlowGuardEnabled)\n                        PhInitializeStringRef(&getCellText->Text, L\"CF Guard\");\n                    else\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                }\n                break;\n            case PHPRTLC_TIMESTAMP:\n                {\n                    PhpUpdateProcessNodeImage(node);\n\n                    if (node->ImageTimeDateStamp != 0)\n                    {\n                        LARGE_INTEGER time;\n                        SYSTEMTIME systemTime;\n\n                        PhSecondsSince1970ToTime(node->ImageTimeDateStamp, &time);\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &time);\n\n                        PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(node->TimeStampText);\n                    }\n                }\n                break;\n            case PHPRTLC_FILEMODIFIEDTIME:\n                {\n                    PhpUpdateProcessNodeFileAttributes(node);\n\n                    if (node->FileLastWriteTime.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &node->FileLastWriteTime);\n                        PhMoveReference(&node->FileModifiedTimeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(node->FileModifiedTimeText);\n                    }\n                }\n                break;\n            case PHPRTLC_FILESIZE:\n                {\n                    PhpUpdateProcessNodeFileAttributes(node);\n\n                    if (node->FileEndOfFile.QuadPart != 0)\n                    {\n                        PhMoveReference(&node->FileSizeText, PhFormatSize(node->FileEndOfFile.QuadPart, ULONG_MAX));\n                        getCellText->Text = PhGetStringRef(node->FileSizeText);\n                    }\n                }\n                break;\n            case PHPRTLC_SUBPROCESSCOUNT:\n                {\n                    if (node->Children && node->Children->Count != 0)\n                    {\n                        PhMoveReference(&node->SubprocessCountText, PhFormatUInt64(node->Children->Count, TRUE));\n                        getCellText->Text = PhGetStringRef(node->SubprocessCountText);\n                    }\n                }\n                break;\n            case PHPRTLC_JOBOBJECTID:\n                {\n                    if (processItem->JobObjectId != 0)\n                    {\n                        PhMoveReference(&node->JobObjectIdText, PhFormatUInt64(processItem->JobObjectId, TRUE));\n                        getCellText->Text = PhGetStringRef(node->JobObjectIdText);\n                    }\n                }\n                break;\n            case PHPRTLC_PROTECTION:\n                {\n                    if (processItem->Protection.Level ||\n                        processItem->IsSecureProcess ||\n                        processItem->IsProtectedProcess)\n                    {\n                        PhMoveReference(&node->ProtectionText, PhGetProcessProtectionString(\n                            processItem->Protection,\n                            (BOOLEAN)processItem->IsSecureProcess\n                            ));\n                        getCellText->Text = PhGetStringRef(node->ProtectionText);\n                    }\n                }\n                break;\n            case PHPRTLC_DESKTOP:\n                {\n                    PhpUpdateProcessNodeDesktopInfo(node);\n                    getCellText->Text = PhGetStringRef(node->DesktopInfoText);\n                }\n                break;\n            case PHPRTLC_CRITICAL:\n                {\n                    PhpUpdateProcessBreakOnTermination(node);\n\n                    if (node->BreakOnTerminationEnabled)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Critical\");\n                    }\n                }\n                break;\n            case PHPRTLC_PIDHEX:\n                {\n                    if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId))\n                    {\n                        PhInitializeStringRefLongHint(&getCellText->Text, processItem->ProcessIdHexString);\n                    }\n                }\n                break;\n            case PHPRTLC_CPUCORECYCLES:\n                {\n                    FLOAT cpuUsage = 0;\n\n                    PhpAggregateFieldIfNeeded(node, AggregateTypeFloat, AggregateProcessItem, processItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUsage), &cpuUsage);\n\n                    cpuUsage *= 100;\n                    cpuUsage *= processItem->AffinityPopulationCount;\n\n                    if (cpuUsage >= PhMaxPrecisionLimit)\n                    {\n                        PH_FORMAT format;\n\n                        PhInitFormatF(&format, cpuUsage, PhMaxPrecisionUnit);\n\n                        PhMoveReference(&node->CpuCoreUsageText, PhFormat(&format, 1, 0));\n                        getCellText->Text = node->CpuCoreUsageText->sr;\n                    }\n                    else if (cpuUsage != 0 && PhCsShowCpuBelow001)\n                    {\n                        PH_FORMAT format[2];\n\n                        PhInitFormatS(&format[0], L\"< \");\n                        PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n\n                        PhMoveReference(&node->CpuCoreUsageText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                        getCellText->Text = node->CpuCoreUsageText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_CET:\n                {\n                    if (processItem->IsCetEnabled)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"CET\");\n                    }\n                }\n                break;\n            case PHPRTLC_IMAGE_COHERENCY:\n                {\n                    PH_FORMAT format[2];\n\n                    if (!PhEnableImageCoherencySupport)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Image coherency support is disabled.\");\n                        break;\n                    }\n\n                    if (processItem->ImageCoherencyStatus == STATUS_PENDING)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Scanning....\");\n                        break;\n                    }\n\n                    if (!PhpShouldShowImageCoherency(processItem, FALSE))\n                    {\n                        if (processItem->ImageCoherencyStatus != STATUS_SUCCESS)\n                        {\n                            PhMoveReference(\n                                &node->ImageCoherencyStatusText,\n                                PhGetStatusMessage(processItem->ImageCoherencyStatus, 0)\n                                );\n                            getCellText->Text = PhGetStringRef(node->ImageCoherencyStatusText);\n                        }\n                        break;\n                    }\n\n                    if (processItem->ImageCoherency == 1.0f)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"100%\");\n                        break;\n                    }\n                    if (processItem->ImageCoherency > 0.9999f)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\">99.99%\");\n                        break;\n                    }\n\n                    PhInitFormatF(&format[0], (processItem->ImageCoherency * 100.f), PhMaxPrecisionUnit);\n                    PhInitFormatS(&format[1], L\"%\");\n\n                    PhMoveReference(&node->ImageCoherencyText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                    getCellText->Text = node->ImageCoherencyText->sr;\n                }\n                break;\n            case PHPRTLC_ERRORMODE:\n                {\n                    PhpUpdateProcessNodeErrorMode(node);\n                    getCellText->Text = PhGetStringRef(node->ErrorModeText);\n                }\n                break;\n            case PHPRTLC_CODEPAGE:\n                {\n                    PhpUpdateProcessNodeCodePage(node);\n\n                    if (node->CodePage != 0)\n                    {\n                        PhMoveReference(&node->CodePageText, PhFormatUInt64(node->CodePage, FALSE));\n                        getCellText->Text = node->CodePageText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_POWERTHROTTLING:\n                {\n                    PhpUpdateProcessNodePowerThrottling(node);\n\n                    if (node->PowerThrottling)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Yes\");\n                    }\n                }\n                break;\n            case PHPRTLC_ARCHITECTURE:\n                {\n                    PhpUpdateProcessNodeImage(node);\n\n                    // Use Architecture from PhGetProcessArchitecture if we have it, this supports\n                    // cases where the process is executing as a different architecture than the\n                    // image it was loaded from (ARM64X or .NET).\n                    if (node->Architecture != IMAGE_FILE_MACHINE_UNKNOWN)\n                    {\n                        switch (node->Architecture)\n                        {\n                        case IMAGE_FILE_MACHINE_I386:\n                            PhInitializeStringRef(&getCellText->Text, L\"x86\");\n                            break;\n                        case IMAGE_FILE_MACHINE_AMD64:\n#ifdef _ARM64_\n                            PhInitializeStringRef(&getCellText->Text, node->ImageCHPEVersion ? L\"x64 (ARM64X)\" : L\"x64\");\n#else\n                            PhInitializeStringRef(&getCellText->Text, L\"x64\");\n#endif\n                            break;\n                        case IMAGE_FILE_MACHINE_ARMNT:\n                            PhInitializeStringRef(&getCellText->Text, L\"ARM\");\n                            break;\n                        case IMAGE_FILE_MACHINE_ARM64:\n#ifdef _ARM64_\n                            PhInitializeStringRef(&getCellText->Text, node->ImageCHPEVersion ? L\"ARM64 (ARM64X)\" : L\"ARM64\");\n#else\n                            PhInitializeStringRef(&getCellText->Text, L\"ARM64\");\n#endif\n                            break;\n                        }\n                    }\n                    else\n                    {\n                        switch (node->ImageMachine)\n                        {\n                        case IMAGE_FILE_MACHINE_I386:\n                            PhInitializeStringRef(&getCellText->Text, L\"x86\");\n                            break;\n                        case IMAGE_FILE_MACHINE_AMD64:\n#ifdef _ARM64_\n                            PhInitializeStringRef(&getCellText->Text, node->ImageCHPEVersion ? L\"x64 (ARM64X)\" : L\"x64\");\n#else\n                            PhInitializeStringRef(&getCellText->Text, L\"x64\");\n#endif\n                            break;\n                        case IMAGE_FILE_MACHINE_ARMNT:\n                            PhInitializeStringRef(&getCellText->Text, L\"ARM\");\n                            break;\n                        case IMAGE_FILE_MACHINE_ARM64:\n#ifdef _ARM64_\n                            PhInitializeStringRef(&getCellText->Text, node->ImageCHPEVersion ? L\"ARM64 (ARM64X)\" : L\"ARM64\");\n#else\n                            PhInitializeStringRef(&getCellText->Text, L\"ARM64\");\n#endif\n                            break;\n                        }\n                    }\n                    break;\n                }\n                break;\n            case PHPRTLC_PARENTPID:\n                {\n                    if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId))\n                    {\n                        PH_FORMAT format;\n\n                        PhInitFormatU(&format, HandleToUlong(processItem->ParentProcessId));\n\n                        PhMoveReference(&node->ParentPidText, PhFormat(&format, 1, 0));\n                        getCellText->Text = node->ParentPidText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_PARENTCONSOLEPID:\n                {\n                    PH_FORMAT format;\n\n                    PhInitFormatU(&format, HandleToUlong((HANDLE)((ULONG_PTR)processItem->ConsoleHostProcessId & ~3)));\n\n                    PhMoveReference(&node->ParentConsolePidText, PhFormat(&format, 1, 0));\n                    getCellText->Text = node->ParentConsolePidText->sr;\n                }\n                break;\n            case PHPRTLC_COMMITSIZE:\n                {\n                    if (processItem->SharedCommitCharge != 0)\n                    {\n                        PhMoveReference(&node->SharedCommitText, PhFormatSize(processItem->SharedCommitCharge, ULONG_MAX));\n                        getCellText->Text = node->SharedCommitText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_PRIORITYBOOST:\n                {\n                    PhpUpdateProcessNodePriorityBoost(node);\n\n                    if (node->PriorityBoost)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Yes\");\n                    }\n                }\n                break;\n            case PHPRTLC_CPUAVERAGE:\n                {\n                    FLOAT cpuUsage;\n\n                    cpuUsage = processItem->CpuAverageUsage * 100;\n\n                    if (cpuUsage >= PhMaxPrecisionLimit)\n                    {\n                        PH_FORMAT format;\n\n                        PhInitFormatF(&format, cpuUsage, PhMaxPrecisionUnit);\n\n                        PhMoveReference(&node->CpuAverageText, PhFormat(&format, 1, 0));\n                        getCellText->Text = node->CpuAverageText->sr;\n                    }\n                    else if (cpuUsage != 0 && PhCsShowCpuBelow001)\n                    {\n                        PH_FORMAT format[2];\n\n                        PhInitFormatS(&format[0], L\"< \");\n                        PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n\n                        PhMoveReference(&node->CpuAverageText, PhFormat(format, 2, 0));\n                        getCellText->Text = node->CpuAverageText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_CPUKERNEL:\n                {\n                    FLOAT cpuUsage;\n\n                    cpuUsage = processItem->CpuKernelUsage * 100;\n\n                    if (cpuUsage >= PhMaxPrecisionLimit)\n                    {\n                        PH_FORMAT format;\n\n                        PhInitFormatF(&format, cpuUsage, PhMaxPrecisionUnit);\n\n                        PhMoveReference(&node->CpuKernelText, PhFormat(&format, 1, 0));\n                        getCellText->Text = node->CpuKernelText->sr;\n                    }\n                    else if (cpuUsage != 0 && PhCsShowCpuBelow001)\n                    {\n                        PH_FORMAT format[2];\n\n                        PhInitFormatS(&format[0], L\"< \");\n                        PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n\n                        PhMoveReference(&node->CpuKernelText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                        getCellText->Text = node->CpuKernelText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_CPUUSER:\n                {\n                    FLOAT cpuUsage;\n\n                    cpuUsage = processItem->CpuUserUsage * 100;\n\n                    if (cpuUsage >= PhMaxPrecisionLimit)\n                    {\n                        PH_FORMAT format;\n\n                        PhInitFormatF(&format, cpuUsage, PhMaxPrecisionUnit);\n\n                        PhMoveReference(&node->CpuUserText, PhFormat(&format, 1, 0));\n                        getCellText->Text = node->CpuUserText->sr;\n                    }\n                    else if (cpuUsage != 0 && PhCsShowCpuBelow001)\n                    {\n                        PH_FORMAT format[2];\n\n                        PhInitFormatS(&format[0], L\"< \");\n                        PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n\n                        PhMoveReference(&node->CpuUserText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                        getCellText->Text = node->CpuUserText->sr;\n                    }\n                }\n                break;\n            case PHPRTLC_GRANTEDACCESS:\n                {\n                    PhpUpdateProcessNodeGrantedAccess(node);\n                    getCellText->Text = PhGetStringRef(node->GrantedAccessText);\n                }\n                break;\n            case PHPRTLC_TLSBITMAPDELTA:\n                {\n                    PhpUpdateProcessNodeTlsBitmapDelta(node);\n\n                    if (node->TlsBitmapCount != 0)\n                    {\n                        if (node->TlsBitmapCount > TLS_MINIMUM_AVAILABLE)\n                        {\n                            PH_FORMAT format[8];\n\n                            // 64 (100%) | 1024 (100%)\n                            PhInitFormatU(&format[0], 64);\n                            PhInitFormatS(&format[1], L\" (\");\n                            PhInitFormatF(&format[2], 100.0f, 2);\n                            PhInitFormatS(&format[3], L\"%) | \");\n                            PhInitFormatU(&format[4], node->TlsBitmapCount - TLS_MINIMUM_AVAILABLE);\n                            PhInitFormatS(&format[5], L\" (\");\n                            PhInitFormatF(&format[6], (node->TlsBitmapCount - TLS_MINIMUM_AVAILABLE) * 100.f / TLS_EXPANSION_SLOTS, 2);\n                            PhInitFormatS(&format[7], L\"%)\");\n\n                            PhMoveReference(&node->TlsBitmapDeltaText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                        }\n                        else\n                        {\n                            PH_FORMAT format[8];\n\n                            // 64 (100%) | 0 (0%)\n                            PhInitFormatU(&format[0], node->TlsBitmapCount);\n                            PhInitFormatS(&format[1], L\" (\");\n                            PhInitFormatF(&format[2], node->TlsBitmapCount * 100.f / TLS_MINIMUM_AVAILABLE, 2);\n                            PhInitFormatS(&format[3], L\"%) | \");\n                            PhInitFormatU(&format[4], 0);\n                            PhInitFormatS(&format[5], L\" (\");\n                            PhInitFormatF(&format[6], 0.0f, 2);\n                            PhInitFormatS(&format[7], L\"%)\");\n\n                            PhMoveReference(&node->TlsBitmapDeltaText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                        }\n\n                        getCellText->Text = PhGetStringRef(node->TlsBitmapDeltaText);\n                    }\n                }\n                break;\n            case PHPRTLC_REFERENCEDELTA:\n                {\n                    PhpUpdateProcessNodeObjectReferences(node);\n\n                    if (node->ReferenceCount != 0)\n                    {\n                        PhMoveReference(&node->ReferenceCountText, PhFormatUInt64(node->ReferenceCount, FALSE));\n                        getCellText->Text = PhGetStringRef(node->ReferenceCountText);\n                    }\n                }\n                break;\n            case PHPRTLC_LXSSPID:\n                {\n                    if (processItem->LxssProcessId != 0)\n                    {\n                        PhMoveReference(&node->LxssProcessIdText, PhFormatUInt64(processItem->LxssProcessId, FALSE));\n                        getCellText->Text = PhGetStringRef(node->LxssProcessIdText);\n                    }\n                }\n                break;\n            case PHPRTLC_START_KEY:\n                {\n                    PhpUpdateProcessNodeStartKey(node);\n\n                    if (node->ProcessStartKey != 0)\n                    {\n                        getCellText->Text = PhGetStringRef(node->ProcessStartKeyText);\n                    }\n                }\n                break;\n            case PHPRTLC_MITIGATION_POLICIES:\n                {\n                    PhpUpdateProcessNodeMitigationPolicies(node);\n\n                    if (node->MitigationPoliciesText)\n                    {\n                        getCellText->Text = PhGetStringRef(node->MitigationPoliciesText);\n                    }\n                }\n                break;\n            case PHPRTLC_SERVICES:\n                {\n                    PhpUpdateProcessNodeServices(node);\n\n                    if (node->ServicesText)\n                    {\n                        getCellText->Text = PhGetStringRef(node->ServicesText);\n                    }\n                }\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            PPH_PROCESS_ITEM processItem;\n\n            node = (PPH_PROCESS_NODE)getNodeColor->Node;\n            processItem = node->ProcessItem;\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor;\n\n                getHighlightingColor.Parameter = processItem;\n                getHighlightingColor.BackColor = RGB(0xff, 0xff, 0xff);\n                getHighlightingColor.ForeColor = RGB(0x00, 0x00, 0x00);\n                getHighlightingColor.Handled = FALSE;\n                getHighlightingColor.Cache = FALSE;\n\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), &getHighlightingColor);\n\n                if (getHighlightingColor.Handled)\n                {\n                    getNodeColor->BackColor = getHighlightingColor.BackColor;\n                    getNodeColor->ForeColor = getHighlightingColor.ForeColor;\n\n                    if (!getNodeColor->ForeColor)\n                        getNodeColor->Flags |= TN_AUTO_FORECOLOR;\n\n                    if (getHighlightingColor.Cache)\n                        getNodeColor->Flags |= TN_CACHE;\n\n                    return TRUE;\n                }\n            }\n\n            getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR;\n\n            if (!processItem)\n                ; // Dummy\n            else if (PhCsUseColorDebuggedProcesses && processItem->IsBeingDebugged)\n                getNodeColor->BackColor = PhCsColorDebuggedProcesses;\n            else if (PhCsUseColorSuspended && (processItem->IsSuspended || processItem->IsFrozenProcess))\n                getNodeColor->BackColor = PhCsColorSuspended;\n            else if (PhCsUseColorPartiallySuspended && processItem->ProcessId != SYSTEM_PROCESS_ID && processItem->IsPartiallySuspended)\n                getNodeColor->BackColor = PhCsColorPartiallySuspended;\n            else if (PhCsUseColorEfficiencyMode && processItem->IsPowerThrottling)\n                getNodeColor->BackColor = PhCsColorEfficiencyMode;\n            else if (PhCsUseColorBackgroundProcesses && PhIsProcessBackground(processItem->PriorityClass))\n                getNodeColor->BackColor = PhCsColorBackgroundProcesses;\n            else if (PhCsUseColorLowImageCoherency && PhEnableImageCoherencySupport && PhpShouldShowImageCoherency(processItem, TRUE))\n                getNodeColor->BackColor = PhCsColorLowImageCoherency;\n            else if (PhCsUseColorPacked && processItem->IsPacked)\n                getNodeColor->BackColor = PhCsColorPacked;\n            else if (PhCsUseColorProtectedProcess && processItem->Protection.Level != 0 && processItem->Protection.Level != UCHAR_MAX)\n                getNodeColor->BackColor = PhCsColorProtectedProcess;\n            else if (PhCsUseColorHandleFiltered && (processItem->IsProtectedHandle || processItem->ProcessId == NtCurrentProcessId()))\n                getNodeColor->BackColor = PhCsColorHandleFiltered;\n            else if (PhCsUseColorElevatedProcesses && processItem->IsElevated && processItem->ElevationType == TokenElevationTypeFull)\n                getNodeColor->BackColor = PhCsColorElevatedProcesses;\n            else if (PhCsUseColorUIAccessProcesses && processItem->IsUIAccessEnabled)\n                getNodeColor->BackColor = PhCsColorUIAccessProcesses;\n            else if (PhCsUseColorPicoProcesses && processItem->IsSubsystemProcess)\n                getNodeColor->BackColor = PhCsColorPicoProcesses;\n            else if (PhCsUseColorImmersiveProcesses && processItem->IsImmersive)\n                getNodeColor->BackColor = PhCsColorImmersiveProcesses;\n            else if (PhCsUseColorDotNet && processItem->IsDotNet)\n                getNodeColor->BackColor = PhCsColorDotNet;\n            else if (PhCsUseColorWow64Processes && processItem->IsWow64Process)\n                getNodeColor->BackColor = PhCsColorWow64Processes;\n            else if (PhCsUseColorJobProcesses && processItem->IsInSignificantJob)\n                getNodeColor->BackColor = PhCsColorJobProcesses;\n            else if (\n                PhCsUseColorSystemProcesses &&\n                (processItem->IsSystemProcess ||\n                (processItem->Sid && PhEqualSid(processItem->Sid, (PSID)&PhSeLocalSystemSid)) ||\n                PH_IS_FAKE_PROCESS_ID(processItem->ProcessId) || processItem->ProcessId == SYSTEM_PROCESS_ID\n                ))\n                getNodeColor->BackColor = PhCsColorSystemProcesses;\n            else if (\n                PhCsUseColorOwnProcesses &&\n                processItem->Sid &&\n                PhEqualSid(processItem->Sid, PhGetOwnTokenAttributes().TokenSid)\n                )\n                getNodeColor->BackColor = PhCsColorOwnProcesses;\n            else if (\n                PhCsUseColorServiceProcesses &&\n                ((processItem->ServiceList && processItem->ServiceList->Count != 0) ||\n                (processItem->Sid && PhEqualSid(processItem->Sid, (PSID)&PhSeServiceSid)) ||\n                (processItem->Sid && PhEqualSid(processItem->Sid, (PSID)&PhSeLocalServiceSid)) ||\n                (processItem->Sid && PhEqualSid(processItem->Sid, (PSID)&PhSeNetworkServiceSid))\n                ))\n                getNodeColor->BackColor = PhCsColorServiceProcesses;\n        }\n        return TRUE;\n    case TreeNewGetNodeIcon:\n        {\n            PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1;\n\n            node = (PPH_PROCESS_NODE)getNodeIcon->Node;\n            getNodeIcon->Icon = (HICON)(ULONG_PTR)node->ProcessItem->SmallIconIndex;\n            //getNodeIcon->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetCellTooltip:\n        {\n            PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;\n            ULONG64 tickCount;\n\n            node = (PPH_PROCESS_NODE)getCellTooltip->Node;\n\n            if (getCellTooltip->Column->Id != 0)\n                return FALSE;\n\n            tickCount = NtGetTickCount64();\n\n            if ((LONG64)(node->TooltipTextValidToTickCount - tickCount) < 0)\n                PhClearReference(&node->TooltipText);\n\n            if (PhEnableTooltipSupport && !node->TooltipText)\n                node->TooltipText = PhGetProcessTooltipText(node->ProcessItem, &node->TooltipTextValidToTickCount);\n\n            if (!PhIsNullOrEmptyString(node->TooltipText))\n            {\n                getCellTooltip->Text = node->TooltipText->sr;\n                getCellTooltip->Unfolding = FALSE;\n                getCellTooltip->MaximumWidth = ULONG_MAX;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case TreeNewCustomDraw:\n        {\n            PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;\n            PPH_PROCESS_ITEM processItem;\n            RECT rect;\n            PH_GRAPH_DRAW_INFO drawInfo;\n\n            node = (PPH_PROCESS_NODE)customDraw->Node;\n            processItem = node->ProcessItem;\n            rect = customDraw->CellRect;\n\n            if (rect.right - rect.left <= 1)\n                break; // nothing to draw\n\n            // Generic graph pre-processing\n            switch (customDraw->Column->Id)\n            {\n            case PHPRTLC_CPUHISTORY:\n            case PHPRTLC_PRIVATEBYTESHISTORY:\n            case PHPRTLC_IOHISTORY:\n                memset(&drawInfo, 0, sizeof(PH_GRAPH_DRAW_INFO));\n                drawInfo.Width = rect.right - rect.left - 1; // leave a small gap\n                drawInfo.Height = rect.bottom - rect.top - 1; // leave a small gap\n                drawInfo.Step = 2;\n                drawInfo.BackColor = RGB(0x00, 0x00, 0x00);\n                break;\n            }\n\n            // Specific graph processing\n            switch (customDraw->Column->Id)\n            {\n            case PHPRTLC_CPUHISTORY:\n                {\n                    drawInfo.Flags = PH_GRAPH_USE_LINE_2;\n                    drawInfo.LineColor1 = PhCsColorCpuKernel;\n                    drawInfo.LineColor2 = PhCsColorCpuUser;\n                    drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorCpuKernel);\n                    drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorCpuUser);\n\n                    PhGetDrawInfoGraphBuffers(\n                        &node->CpuGraphBuffers,\n                        &drawInfo,\n                        processItem->CpuKernelHistory.Count\n                        );\n\n                    if (!node->CpuGraphBuffers.Valid)\n                    {\n                        PhCopyCircularBuffer_FLOAT(&processItem->CpuKernelHistory, node->CpuGraphBuffers.Data1, drawInfo.LineDataCount);\n                        PhCopyCircularBuffer_FLOAT(&processItem->CpuUserHistory, node->CpuGraphBuffers.Data2, drawInfo.LineDataCount);\n\n                        if (PhCsEnableGraphMaxScale)\n                        {\n                            FLOAT max = 0;\n\n                            if (PhCsEnableAvxSupport && drawInfo.LineDataCount > 128)\n                            {\n                                max = PhAddPlusMaxMemorySingles(\n                                    node->CpuGraphBuffers.Data1,\n                                    node->CpuGraphBuffers.Data2,\n                                    drawInfo.LineDataCount\n                                    );\n                            }\n                            else\n                            {\n                                for (ULONG i = 0; i < drawInfo.LineDataCount; i++)\n                                {\n                                    FLOAT data = node->CpuGraphBuffers.Data1[i] + node->CpuGraphBuffers.Data2[i];\n\n                                    if (max < data)\n                                        max = data;\n                                }\n                            }\n\n                            if (max != 0)\n                            {\n                                PhDivideSinglesBySingle(\n                                    node->CpuGraphBuffers.Data1,\n                                    max,\n                                    drawInfo.LineDataCount\n                                    );\n                                PhDivideSinglesBySingle(\n                                    node->CpuGraphBuffers.Data2,\n                                    max,\n                                    drawInfo.LineDataCount\n                                    );\n                            }\n                        }\n\n                        node->CpuGraphBuffers.Valid = TRUE;\n                    }\n                }\n                break;\n            case PHPRTLC_PRIVATEBYTESHISTORY:\n                {\n                    drawInfo.Flags = 0;\n                    drawInfo.LineColor1 = PhCsColorPrivate;\n                    drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorPrivate);\n\n                    PhGetDrawInfoGraphBuffers(\n                        &node->PrivateGraphBuffers,\n                        &drawInfo,\n                        processItem->PrivateBytesHistory.Count\n                        );\n\n                    if (!node->PrivateGraphBuffers.Valid)\n                    {\n                        FLOAT total;\n                        FLOAT max;\n\n                        for (ULONG i = 0; i < drawInfo.LineDataCount; i++)\n                        {\n                            node->PrivateGraphBuffers.Data1[i] =\n                                (FLOAT)PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, i);\n                        }\n\n                        // This makes it easier for the user to see what processes are hogging memory.\n                        // Scaling is still *not* consistent across all graphs.\n                        total = (FLOAT)PhPerfInformation.CommittedPages * PAGE_SIZE / 4; // divide by 4 to make the scaling a bit better\n                        max = (FLOAT)processItem->VmCounters.PeakPagefileUsage;\n\n                        if (max < total)\n                            max = total;\n\n                        if (max != 0)\n                        {\n                            // Scale the data.\n                            PhDivideSinglesBySingle(\n                                node->PrivateGraphBuffers.Data1,\n                                max,\n                                drawInfo.LineDataCount\n                                );\n                        }\n\n                        node->PrivateGraphBuffers.Valid = TRUE;\n                    }\n                }\n                break;\n            case PHPRTLC_IOHISTORY:\n                {\n                    drawInfo.Flags = PH_GRAPH_USE_LINE_2;\n                    drawInfo.LineColor1 = PhCsColorIoReadOther;\n                    drawInfo.LineColor2 = PhCsColorIoWrite;\n                    drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorIoReadOther);\n                    drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorIoWrite);\n\n                    PhGetDrawInfoGraphBuffers(\n                        &node->IoGraphBuffers,\n                        &drawInfo,\n                        processItem->IoReadHistory.Count\n                        );\n\n                    if (!node->IoGraphBuffers.Valid)\n                    {\n                        FLOAT total;\n                        FLOAT max = 0;\n\n                        for (ULONG i = 0; i < drawInfo.LineDataCount; i++)\n                        {\n                            FLOAT data1;\n                            FLOAT data2;\n\n                            node->IoGraphBuffers.Data1[i] = data1 =\n                                (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, i) +\n                                (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, i);\n                            node->IoGraphBuffers.Data2[i] = data2 =\n                                (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, i);\n\n                            if (max < data1 + data2)\n                                max = data1 + data2;\n                        }\n\n                        // Make the scaling a bit more consistent across the processes.\n                        // It does *not* scale all graphs using the same maximum.\n                        total = (FLOAT)(PhIoReadDelta.Delta + PhIoWriteDelta.Delta + PhIoOtherDelta.Delta);\n\n                        if (max < total)\n                            max = total;\n\n                        if (max != 0)\n                        {\n                            // Scale the data.\n\n                            PhDivideSinglesBySingle(\n                                node->IoGraphBuffers.Data1,\n                                max,\n                                drawInfo.LineDataCount\n                                );\n                            PhDivideSinglesBySingle(\n                                node->IoGraphBuffers.Data2,\n                                max,\n                                drawInfo.LineDataCount\n                                );\n                        }\n\n                        node->IoGraphBuffers.Valid = TRUE;\n                    }\n                }\n                break;\n            }\n\n            // Draw the graph.\n            switch (customDraw->Column->Id)\n            {\n            case PHPRTLC_CPUHISTORY:\n            case PHPRTLC_PRIVATEBYTESHISTORY:\n            case PHPRTLC_IOHISTORY:\n                PhpNeedGraphContext(customDraw->Dc, drawInfo.Width, drawInfo.Height);\n\n                if (GraphBits)\n                {\n                    PhDrawGraphDirect(GraphContext, GraphBits, &drawInfo);\n                    BitBlt(\n                        customDraw->Dc,\n                        rect.left,\n                        rect.top + 1, // + 1 for small gap\n                        drawInfo.Width,\n                        drawInfo.Height,\n                        GraphContext,\n                        0,\n                        0,\n                        SRCCOPY\n                        );\n                }\n\n                break;\n            case PHPRTLC_TIMELINE:\n                {\n                    if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId))\n                    {\n                        PhCustomDrawTreeTimeLine(\n                            customDraw->Dc,\n                            &customDraw->CellRect,\n                            PhEnableThemeSupport ? PH_DRAW_TIMELINE_DARKTHEME : 0,\n                            NULL,\n                            &processItem->CreateTime\n                            );\n                    }\n                    else\n                    {\n                        LARGE_INTEGER createTime;\n\n                        // DPCs, Interrupts and System Idle Process are always 100%\n                        createTime.QuadPart = 0;\n\n                        PhCustomDrawTreeTimeLine(\n                            customDraw->Dc,\n                            &customDraw->CellRect,\n                            PhEnableThemeSupport ? PH_DRAW_TIMELINE_DARKTHEME : 0,\n                            NULL,\n                            &createTime\n                            );\n                    }\n                }\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewColumnResized:\n        {\n            PPH_TREENEW_COLUMN column = Parameter1;\n            ULONG i;\n\n            if (column->Id == PHPRTLC_CPUHISTORY || column->Id == PHPRTLC_IOHISTORY || column->Id == PHPRTLC_PRIVATEBYTESHISTORY)\n            {\n                for (i = 0; i < ProcessNodeList->Count; i++)\n                {\n                    node = ProcessNodeList->Items[i];\n\n                    if (column->Id == PHPRTLC_CPUHISTORY)\n                        node->CpuGraphBuffers.Valid = FALSE;\n                    if (column->Id == PHPRTLC_IOHISTORY)\n                        node->IoGraphBuffers.Valid = FALSE;\n                    if (column->Id == PHPRTLC_PRIVATEBYTESHISTORY)\n                        node->PrivateGraphBuffers.Valid = FALSE;\n                }\n            }\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            ProcessTreeListSortColumn = sorting->SortColumn;\n            ProcessTreeListSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(hwnd);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_COPY, 0);\n                break;\n            case VK_DELETE:\n                if (GetKeyState(VK_SHIFT) >= 0)\n                    SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATE, 0);\n                else\n                    SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATETREE, 0);\n                break;\n            case VK_RETURN:\n                if (GetKeyState(VK_CONTROL) >= 0)\n                    SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0);\n                else\n                    SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_OPENFILELOCATION, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = hwnd;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = 0;\n            data.DefaultSortOrder = NoSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(\n                data.Menu,\n                hwnd,\n                PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                data.MouseEvent->ScreenLocation.x,\n                data.MouseEvent->ScreenLocation.y\n                );\n\n            PhHandleTreeNewColumnMenu(&data);\n\n            if (data.Selection)\n            {\n                if (data.Selection->Id == PH_TN_COLUMN_MENU_HIDE_COLUMN_ID ||\n                    data.Selection->Id == PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID)\n                {\n                    PhReloadSettingsProcessTreeList();\n                }\n            }\n\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n\n            PhShowProcessContextMenu(PhMainWndHandle, contextMenu);\n        }\n        return TRUE;\n    case TreeNewNodeExpanding:\n        {\n            node = Parameter1;\n\n            if (PhCsPropagateCpuUsage)\n                PhUpdateProcessNode(node);\n        }\n        return TRUE;\n    case TreeNewGetHeaderText:\n        {\n            PPH_TREENEW_GET_HEADER_TEXT getHeaderText = Parameter1;\n            PPH_TREENEW_COLUMN column = getHeaderText->Column;\n            SIZE_T returnLength;\n            FLOAT decimal = 0;\n            ULONG64 number = 0;\n\n            switch (column->Id)\n            {\n            case PHPRTLC_CPU:\n            case PHPRTLC_IOTOTALRATE:\n            case PHPRTLC_PRIVATEBYTES:\n            case PHPRTLC_PEAKPRIVATEBYTES:\n            case PHPRTLC_WORKINGSET:\n            case PHPRTLC_PEAKWORKINGSET:\n            case PHPRTLC_PRIVATEWS:\n            case PHPRTLC_VIRTUALSIZE:\n            case PHPRTLC_PEAKVIRTUALSIZE:\n            case PHPRTLC_PAGEFAULTS:\n            case PHPRTLC_THREADS:\n            case PHPRTLC_HANDLES:\n            case PHPRTLC_GDIHANDLES:\n            case PHPRTLC_USERHANDLES:\n            case PHPRTLC_IORORATE:\n            case PHPRTLC_IOWRATE:\n            case PHPRTLC_CYCLES:\n            case PHPRTLC_CYCLESDELTA:\n            case PHPRTLC_CONTEXTSWITCHES:\n            case PHPRTLC_CONTEXTSWITCHESDELTA:\n            case PHPRTLC_IOREADS:\n            case PHPRTLC_IOWRITES:\n            case PHPRTLC_IOOTHER:\n            case PHPRTLC_IOREADBYTES:\n            case PHPRTLC_IOWRITEBYTES:\n            case PHPRTLC_IOOTHERBYTES:\n            case PHPRTLC_IOREADSDELTA:\n            case PHPRTLC_IOWRITESDELTA:\n            case PHPRTLC_IOOTHERDELTA:\n            case PHPRTLC_PAGEDPOOL:\n            case PHPRTLC_PEAKPAGEDPOOL:\n            case PHPRTLC_NONPAGEDPOOL:\n            case PHPRTLC_PEAKNONPAGEDPOOL:\n            case PHPRTLC_PRIVATEBYTESDELTA:\n            case PHPRTLC_CPUCORECYCLES:\n            case PHPRTLC_COMMITSIZE:\n            case PHPRTLC_CPUAVERAGE:\n            case PHPRTLC_CPUKERNEL:\n            case PHPRTLC_CPUUSER:\n                break;\n            default:\n                return FALSE;\n            }\n\n            // NOTE: Windows Task Manager doesn't loop subitems when summing the totals but instead just returns the system totals.\n            // We should do the same for some columns like CPU when/if the below loop/aggregate fields becomes a performance issue. (dmex)\n\n            for (ULONG i = 0; i < ProcessNodeList->Count; i++)\n            {\n                node = ProcessNodeList->Items[i];\n\n                if (!node->Node.Visible)\n                    continue; // Skip filtered.\n                if (node->ProcessItem->State & PH_PROCESS_ITEM_REMOVED)\n                    continue; // Skip terminated.\n                if (!PhTestEvent(&node->ProcessItem->Stage1Event))\n                    continue; // Skip unprocessed.\n\n                switch (column->Id)\n                {\n                case PHPRTLC_CPU:\n                    {\n                        if (node->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n                            continue;\n\n                        PhpAggregateFieldTotal(node, AggregateTypeFloat, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUsage), &decimal);\n                    }\n                    break;\n                case PHPRTLC_IOTOTALRATE:\n                    {\n                        if (node->ProcessItem->IoReadDelta.Delta != node->ProcessItem->IoReadDelta.Value) // delta is wrong on first run of process provider\n                        {\n                            PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number);\n                            PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number);\n                            PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number);\n                        }\n                    }\n                    break;\n                case PHPRTLC_PRIVATEBYTES:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PagefileUsage), &number);\n                    break;\n                case PHPRTLC_PEAKPRIVATEBYTES:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PeakPagefileUsage), &number);\n                    break;\n                case PHPRTLC_WORKINGSET:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.WorkingSetSize), &number);\n                    break;\n                case PHPRTLC_PEAKWORKINGSET:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PeakWorkingSetSize), &number);\n                    break;\n                case PHPRTLC_PRIVATEWS:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, WorkingSetPrivateSize), &number);\n                    break;\n                //case PHPRTLC_SHAREDWS:\n                //    node->WsCounters.NumberOfSharedPages\n                //    break;\n                //case PHPRTLC_SHAREABLEWS:\n                //    node->WsCounters.NumberOfShareablePages\n                //    break;\n                case PHPRTLC_VIRTUALSIZE:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.VirtualSize), &number);\n                    break;\n                case PHPRTLC_PEAKVIRTUALSIZE:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PeakVirtualSize), &number);\n                    break;\n                case PHPRTLC_PAGEFAULTS:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt32, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PageFaultCount), &number);\n                    break;\n                case PHPRTLC_THREADS:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt32, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfThreads), &number);\n                    break;\n                case PHPRTLC_HANDLES:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt32, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfHandles), &number);\n                    break;\n                case PHPRTLC_GDIHANDLES:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt32, node, FIELD_OFFSET(PH_PROCESS_NODE, GdiHandles), &number);\n                    break;\n                case PHPRTLC_USERHANDLES:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt32, node, FIELD_OFFSET(PH_PROCESS_NODE, UserHandles), &number);\n                    break;\n                case PHPRTLC_IORORATE:\n                    {\n                        if (node->ProcessItem->IoReadDelta.Delta != node->ProcessItem->IoReadDelta.Value)\n                        {\n                            PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number);\n                            PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number);\n                        }\n                    }\n                    break;\n                case PHPRTLC_IOWRATE:\n                    {\n                        if (node->ProcessItem->IoReadDelta.Delta != node->ProcessItem->IoReadDelta.Value)\n                        {\n                            PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number);\n                        }\n                    }\n                    break;\n                case PHPRTLC_CYCLES:\n                    {\n                        if (node->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n                            continue;\n\n                        PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Value), &number);\n                    }\n                    break;\n                case PHPRTLC_CYCLESDELTA:\n                    {\n                        if (node->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n                            continue;\n\n                        PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Delta), &number);\n                    }\n                    break;\n                case PHPRTLC_CONTEXTSWITCHES:\n                    {\n                        if (node->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n                            continue;\n\n                        PhpAggregateFieldTotal(node, AggregateTypeInt32, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Value), &number);\n                    }\n                    break;\n                case PHPRTLC_CONTEXTSWITCHESDELTA:\n                    {\n                        if ((LONG)node->ProcessItem->ContextSwitchesDelta.Delta >= 0) // the delta may be negative if a thread exits - just don't show anything\n                        {\n                            PhpAggregateFieldTotal(node, AggregateTypeInt32, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Delta), &number);\n                        }\n                    }\n                    break;\n                case PHPRTLC_IOREADS:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Value), &number);\n                    break;\n                case PHPRTLC_IOWRITES:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Value), &number);\n                    break;\n                case PHPRTLC_IOOTHER:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Value), &number);\n                    break;\n                case PHPRTLC_IOREADBYTES:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Value), &number);\n                    break;\n                case PHPRTLC_IOWRITEBYTES:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Value), &number);\n                    break;\n                case PHPRTLC_IOOTHERBYTES:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Value), &number);\n                    break;\n                case PHPRTLC_IOREADSDELTA:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Delta), &number);\n                    break;\n                case PHPRTLC_IOWRITESDELTA:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Delta), &number);\n                    break;\n                case PHPRTLC_IOOTHERDELTA:\n                    PhpAggregateFieldTotal(node, AggregateTypeInt64, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Delta), &number);\n                    break;\n                case PHPRTLC_PAGEDPOOL:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaPagedPoolUsage), &number);\n                    break;\n                case PHPRTLC_PEAKPAGEDPOOL:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaPeakPagedPoolUsage), &number);\n                    break;\n                case PHPRTLC_NONPAGEDPOOL:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaNonPagedPoolUsage), &number);\n                    break;\n                case PHPRTLC_PEAKNONPAGEDPOOL:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaPeakNonPagedPoolUsage), &number);\n                    break;\n                case PHPRTLC_PRIVATEBYTESDELTA:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, PrivateBytesDelta.Delta), &number);\n                    break;\n                case PHPRTLC_CPUCORECYCLES:\n                    {\n                        if (node->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n                            continue;\n\n                        PhpAggregateFieldIfNeeded(node, AggregateTypeFloat, AggregateProcessItem, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUsage), &decimal);\n                    }\n                    break;\n                case PHPRTLC_COMMITSIZE:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, SharedCommitCharge), &number);\n                    break;\n                case PHPRTLC_CPUAVERAGE:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuAverageUsage), &number);\n                    break;\n                case PHPRTLC_CPUKERNEL:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuKernelUsage), &number);\n                    break;\n                case PHPRTLC_CPUUSER:\n                    PhpAggregateFieldTotal(node, AggregateTypeIntPtr, node->ProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUserUsage), &number);\n                    break;\n                }\n            }\n\n            switch (column->Id)\n            {\n            case PHPRTLC_CPU:\n                {\n                    PH_FORMAT format[2];\n\n                    if (decimal == 0.0)\n                        break;\n\n                    decimal *= 100;\n                    PhInitFormatF(&format[0], decimal, PhMaxPrecisionUnit);\n                    PhInitFormatC(&format[1], L'%');\n\n                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), getHeaderText->TextCache, getHeaderText->TextCacheSize, &returnLength))\n                    {\n                        getHeaderText->Text.Buffer = getHeaderText->TextCache;\n                        getHeaderText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                return TRUE;\n            case PHPRTLC_IOTOTALRATE:\n            case PHPRTLC_IORORATE:\n            case PHPRTLC_IOWRATE:\n                {\n                    PH_FORMAT format[2];\n\n                    if (number == 0)\n                        break;\n\n                    number *= 1000;\n                    number /= PhCsUpdateInterval;\n                    PhInitFormatSize(&format[0], number);\n                    PhInitFormatS(&format[1], L\"/s\");\n\n                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), getHeaderText->TextCache, getHeaderText->TextCacheSize, &returnLength))\n                    {\n                        getHeaderText->Text.Buffer = getHeaderText->TextCache;\n                        getHeaderText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                return TRUE;\n            case PHPRTLC_PEAKPRIVATEBYTES:\n            case PHPRTLC_PRIVATEBYTES:\n            case PHPRTLC_WORKINGSET:\n            case PHPRTLC_PEAKWORKINGSET:\n            case PHPRTLC_PRIVATEWS:\n            case PHPRTLC_VIRTUALSIZE:\n            case PHPRTLC_PEAKVIRTUALSIZE:\n            case PHPRTLC_IOREADBYTES:\n            case PHPRTLC_IOWRITEBYTES:\n            case PHPRTLC_IOOTHERBYTES:\n            case PHPRTLC_PAGEDPOOL:\n            case PHPRTLC_PEAKPAGEDPOOL:\n            case PHPRTLC_NONPAGEDPOOL:\n            case PHPRTLC_PEAKNONPAGEDPOOL:\n            case PHPRTLC_COMMITSIZE:\n                {\n                    PH_FORMAT format[1];\n\n                    if (number == 0)\n                        break;\n\n                    PhInitFormatSize(&format[0], number);\n\n                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), getHeaderText->TextCache, getHeaderText->TextCacheSize, &returnLength))\n                    {\n                        getHeaderText->Text.Buffer = getHeaderText->TextCache;\n                        getHeaderText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                return TRUE;\n            case PHPRTLC_PAGEFAULTS:\n            case PHPRTLC_THREADS:\n            case PHPRTLC_HANDLES:\n            case PHPRTLC_GDIHANDLES:\n            case PHPRTLC_USERHANDLES:\n            case PHPRTLC_CYCLES:\n            case PHPRTLC_CYCLESDELTA:\n            case PHPRTLC_CONTEXTSWITCHES:\n            case PHPRTLC_CONTEXTSWITCHESDELTA:\n            case PHPRTLC_IOREADS:\n            case PHPRTLC_IOWRITES:\n            case PHPRTLC_IOOTHER:\n            case PHPRTLC_IOREADSDELTA:\n            case PHPRTLC_IOWRITESDELTA:\n            case PHPRTLC_IOOTHERDELTA:\n                {\n                    PH_FORMAT format[1];\n\n                    if (number == 0)\n                        break;\n\n                    PhInitFormatI64UGroupDigits(&format[0], number);\n\n                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), getHeaderText->TextCache, getHeaderText->TextCacheSize, &returnLength))\n                    {\n                        getHeaderText->Text.Buffer = getHeaderText->TextCache;\n                        getHeaderText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                return TRUE;\n            case PHPRTLC_PRIVATEBYTESDELTA:\n                {\n                    if ((LONG_PTR)number != 0)\n                    {\n                        PH_FORMAT format[2];\n\n                        if ((LONG_PTR)number > 0)\n                        {\n                            PhInitFormatC(&format[0], L'+');\n                        }\n                        else\n                        {\n                            PhInitFormatC(&format[0], L'-');\n                            number = -(LONG_PTR)number;\n                        }\n\n                        format[1].Type = SizeFormatType | FormatUseRadix;\n                        format[1].Radix = (UCHAR)PhMaxSizeUnit;\n                        format[1].u.Size = (LONG_PTR)number;\n\n                        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), getHeaderText->TextCache, getHeaderText->TextCacheSize, &returnLength))\n                        {\n                            getHeaderText->Text.Buffer = getHeaderText->TextCache;\n                            getHeaderText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                }\n                return TRUE;\n            case PHPRTLC_CPUCORECYCLES:\n                {\n                    PH_FORMAT format[2];\n\n                    if (decimal == 0)\n                        break;\n\n                    decimal *= 100;\n                    decimal *= PhSystemProcessorInformation.NumberOfProcessors;\n\n                    PhInitFormatF(&format[0], decimal, PhMaxPrecisionUnit);\n                    PhInitFormatC(&format[1], L'%');\n\n                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), getHeaderText->TextCache, getHeaderText->TextCacheSize, &returnLength))\n                    {\n                        getHeaderText->Text.Buffer = getHeaderText->TextCache;\n                        getHeaderText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                return TRUE;\n            }\n        }\n        return FALSE;\n    case TreeNewMiddleClick:\n        {\n            PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1;\n            node = (PPH_PROCESS_NODE)mouseEvent->Node;\n\n            if (GetKeyState(VK_CONTROL) >= 0)\n            {\n                PhDeselectAllProcessNodes();\n            }\n\n            if (!node)\n                break;\n\n            if (PhCsSortChildProcesses || ProcessTreeListSortOrder == NoSortOrder)\n            {\n                // in NoSortOrder we select subtree (TheEragon)\n\n                // init last index to self, this way we select only the process if there are no children (TheEragon)\n                ULONG lastChildIndex = mouseEvent->Node->Index;\n                if (node->Children->Count)\n                {\n                    // get index of last child\n                    PPH_PROCESS_NODE lastChild = (PPH_PROCESS_NODE)node->Children->Items[node->Children->Count - 1];\n                    lastChildIndex = lastChild->Node.Index;\n                }\n\n                TreeNew_SelectRange(ProcessTreeListHandle, mouseEvent->Node->Index, lastChildIndex);\n            }\n            else\n            {\n                // in sorted order we select all processes with same name (TheEragon)\n\n                ULONG first = ULONG_MAX;\n                ULONG last = 0;\n\n                for (ULONG i = 0; i < ProcessNodeList->Count; i++)\n                {\n                    PPH_PROCESS_NODE item = ProcessNodeList->Items[i];\n\n                    if (PhEqualString(node->ProcessItem->ProcessName, item->ProcessItem->ProcessName, TRUE))\n                    {\n                        if (first > item->Node.Index)\n                            first = item->Node.Index;\n\n                        if (last < item->Node.Index)\n                            last = item->Node.Index;\n                    }\n                    else if (first != ULONG_MAX)\n                    {\n                        // select found range and reset indexes (TheEragon)\n                        TreeNew_SelectRange(ProcessTreeListHandle, first, last);\n\n                        first = ULONG_MAX;\n                        last = 0;\n                    }\n                }\n\n                // select last found range, if any (TheEragon)\n                if (first != ULONG_MAX)\n                    TreeNew_SelectRange(ProcessTreeListHandle, first, last);\n            }\n        }\n        return TRUE;\n    case TreeNewReorderBegin:\n        {\n            PPH_TREENEW_REORDER_EVENT reorderEvent = Parameter1;\n            node = (PPH_PROCESS_NODE)reorderEvent->Source;\n\n            reorderEvent->Allow = TRUE;\n        }\n        return TRUE;\n    case TreeNewReorderOver:\n        {\n            PPH_TREENEW_REORDER_EVENT reorderEvent = Parameter1;\n            node = (PPH_PROCESS_NODE)reorderEvent->Source;\n\n            reorderEvent->Allow = TRUE;\n        }\n        return TRUE;\n    case TreeNewReorderCommit:\n        {\n            PPH_TREENEW_REORDER_EVENT reorderEvent = Parameter1;\n            PPH_PROCESS_NODE sourceNode = (PPH_PROCESS_NODE)reorderEvent->Source;\n            PPH_PROCESS_NODE targetNode = (PPH_PROCESS_NODE)reorderEvent->Target;\n            BOOLEAN targetIsDescendant = FALSE;\n            ULONG oldIndex, newIndex;\n\n            if (sourceNode && targetNode)\n            {\n                PPH_PROCESS_NODE current = targetNode;\n                while (current)\n                {\n                    if (current == sourceNode)\n                    {\n                        targetIsDescendant = TRUE;\n                        break;\n                    }\n                    current = current->Parent;\n                }\n            }\n\n            // Remove sourceNode from its current parent or root list (dmex)\n            if (sourceNode->Parent)\n            {\n                oldIndex = PhFindItemList(sourceNode->Parent->Children, sourceNode);\n                if (oldIndex != ULONG_MAX)\n                    PhRemoveItemList(sourceNode->Parent->Children, oldIndex);\n            }\n            else\n            {\n                oldIndex = PhFindItemList(ProcessNodeRootList, sourceNode);\n                if (oldIndex != ULONG_MAX)\n                    PhRemoveItemList(ProcessNodeRootList, oldIndex);\n            }\n\n            if (targetNode && !targetIsDescendant)\n            {\n                BOOLEAN droppedIntoTargetAsChild = FALSE;\n\n                // If DropAfter is TRUE and the target is a parent (expanded or already has children),\n                // append as the last child of the target (instead of inserting after the parent). (dmex)\n                if (reorderEvent->DropAfter &&\n                    (targetNode->Node.Expanded || (targetNode->Children && targetNode->Children->Count > 0)))\n                {\n                    newIndex = targetNode->Children->Count;\n                    PhInsertItemList(targetNode->Children, newIndex, sourceNode);\n                    sourceNode->Parent = targetNode;\n                    droppedIntoTargetAsChild = TRUE;\n                }\n\n                if (!droppedIntoTargetAsChild)\n                {\n                    // Default behavior: insert as sibling before/after the target (dmex)\n                    if (targetNode->Parent)\n                    {\n                        // Insert as sibling in parent's children list\n                        PPH_PROCESS_NODE parent = targetNode->Parent;\n                        newIndex = PhFindItemList(parent->Children, targetNode);\n                        if (newIndex > parent->Children->Count)\n                            newIndex = parent->Children->Count;\n                        if (reorderEvent->DropAfter && newIndex < parent->Children->Count)\n                            newIndex++;\n                        PhInsertItemList(parent->Children, newIndex, sourceNode);\n                        sourceNode->Parent = parent;\n                    }\n                    else\n                    {\n                        // Insert as root node (sibling of target in root list) (dmex)\n                        newIndex = PhFindItemList(ProcessNodeRootList, targetNode);\n                        if (newIndex > ProcessNodeRootList->Count)\n                            newIndex = ProcessNodeRootList->Count;\n                        if (reorderEvent->DropAfter && newIndex < ProcessNodeRootList->Count)\n                            newIndex++;\n                        PhInsertItemList(ProcessNodeRootList, newIndex, sourceNode);\n                        sourceNode->Parent = NULL;\n                    }\n                }\n            }\n            else if (!targetNode)\n            {\n                // No target, insert at the end of the root list (dmex)\n                PhInsertItemList(ProcessNodeRootList, ProcessNodeRootList->Count, sourceNode);\n                sourceNode->Parent = NULL;\n            }\n            else\n            {\n                // Invalid move (would create a cycle) - restore original placement at end of root list. (dmex)\n                PhInsertItemList(ProcessNodeRootList, ProcessNodeRootList->Count, sourceNode);\n                sourceNode->Parent = NULL;\n            }\n\n            TreeNew_NodesStructured(hwnd);\n        }\n        return TRUE;\n    case TreeNewReorderCancel:\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nPPH_PROCESS_ITEM PhGetSelectedProcessItem(\n    VOID\n    )\n{\n    PPH_PROCESS_ITEM processItem = NULL;\n    ULONG i;\n\n    for (i = 0; i < ProcessNodeList->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            processItem = node->ProcessItem;\n            break;\n        }\n    }\n\n    return processItem;\n}\n\n_Success_(return)\nBOOLEAN PhGetSelectedProcessItems(\n    _Out_ PPH_PROCESS_ITEM **Processes,\n    _Out_ PULONG NumberOfProcesses\n    )\n{\n    PH_ARRAY array;\n    ULONG i;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    for (i = 0; i < ProcessNodeList->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNodeList->Items[i];\n\n        if (node->Node.Visible && node->Node.Selected)\n        {\n            PhAddItemArray(&array, &node->ProcessItem);\n        }\n    }\n\n    if (PhFinalArrayCount(&array))\n    {\n        *NumberOfProcesses = (ULONG)PhFinalArrayCount(&array);\n        *Processes = PhFinalArrayItems(&array);\n        return TRUE;\n    }\n    else\n    {\n        *NumberOfProcesses = 0;\n        *Processes = NULL;\n        PhDeleteArray(&array);\n        return FALSE;\n    }\n}\n\nPPH_PROCESS_NODE PhGetSelectedProcessNode(\n    VOID\n    )\n{\n    PPH_PROCESS_NODE processNode = NULL;\n    ULONG i;\n\n    for (i = 0; i < ProcessNodeList->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNodeList->Items[i];\n\n        if (node->Node.Visible && node->Node.Selected)\n        {\n            processNode = node;\n            break;\n        }\n    }\n\n    return processNode;\n}\n\n_Success_(return)\nBOOLEAN PhGetSelectedProcessNodes(\n    _Out_ PPH_PROCESS_NODE **Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PH_ARRAY array;\n    ULONG i;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    for (i = 0; i < ProcessNodeList->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNodeList->Items[i];\n\n        if (node->Node.Visible && node->Node.Selected)\n            PhAddItemArray(&array, &node);\n    }\n\n    if (PhFinalArrayCount(&array))\n    {\n        *NumberOfNodes = (ULONG)PhFinalArrayCount(&array);\n        *Nodes = PhFinalArrayItems(&array);\n        return TRUE;\n    }\n    else\n    {\n        *NumberOfNodes = 0;\n        *Nodes = NULL;\n        PhDeleteArray(&array);\n        return FALSE;\n    }\n}\n\n_Success_(return)\nBOOLEAN PhGetProcessItemServices(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _Out_ PPH_SERVICE_ITEM** Services,\n    _Out_ PULONG NumberOfServices\n    )\n{\n    PH_ARRAY array;\n    ULONG enumerationKey = 0;\n    PPH_SERVICE_ITEM serviceItem;\n\n    if (!(ProcessItem->ServiceList && ProcessItem->ServiceList->Count != 0))\n        return FALSE;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    PhAcquireQueuedLockShared(&ProcessItem->ServiceListLock);\n\n    while (PhEnumPointerList(\n        ProcessItem->ServiceList,\n        &enumerationKey,\n        &serviceItem\n        ))\n    {\n        PhReferenceObject(serviceItem);\n        PhAddItemArray(&array, &serviceItem);\n    }\n\n    PhReleaseQueuedLockShared(&ProcessItem->ServiceListLock);\n\n    *NumberOfServices = (ULONG)PhFinalArrayCount(&array);\n    *Services = PhFinalArrayItems(&array);\n    return TRUE;\n}\n\nstatic VOID PhpAddAndPropagateProcessItems(\n    _In_ PPH_ARRAY ProcessesArray,\n    _In_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    for (ULONG i = 0; i < ProcessNode->Children->Count; i++)\n    {\n        PPH_PROCESS_NODE child = ProcessNode->Children->Items[i];\n\n        if (child->Children)\n        {\n            PhpAddAndPropagateProcessItems(ProcessesArray, child);\n        }\n    }\n\n    PhAddItemArray(ProcessesArray, &ProcessNode->ProcessItem);\n}\n\nVOID PhGetSelectedAndPropagateProcessItems(\n    _Out_ PPH_PROCESS_ITEM **Processes,\n    _Out_ PULONG NumberOfProcesses\n    )\n{\n    PH_ARRAY array;\n    ULONG i;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    for (i = 0; i < ProcessNodeList->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNodeList->Items[i];\n\n        if (node->Node.Visible && node->Node.Selected)\n        {\n            if (PhCsPropagateCpuUsage && !node->Node.Expanded)\n            {\n                PhpAddAndPropagateProcessItems(&array, node);\n            }\n            else\n            {\n                PhAddItemArray(&array, &node->ProcessItem);\n            }\n        }\n    }\n\n    *NumberOfProcesses = (ULONG)PhFinalArrayCount(&array);\n    *Processes = PhFinalArrayItems(&array);\n}\n\nVOID PhDeselectAllProcessNodes(\n    VOID\n    )\n{\n    TreeNew_DeselectRange(ProcessTreeListHandle, 0, -1);\n}\n\nVOID PhExpandAllProcessNodes(\n    _In_ BOOLEAN Expand\n    )\n{\n    ULONG i;\n    BOOLEAN needsRestructure = FALSE;\n\n    for (i = 0; i < ProcessNodeList->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNodeList->Items[i];\n\n        if (node->Children->Count != 0 && node->Node.Expanded != Expand)\n        {\n            node->Node.Expanded = Expand;\n            needsRestructure = TRUE;\n        }\n    }\n\n    if (needsRestructure)\n        TreeNew_NodesStructured(ProcessTreeListHandle);\n}\n\nVOID PhInvalidateAllProcessNodes(\n    VOID\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < ProcessNodeList->Count; i++)\n    {\n        PPH_PROCESS_NODE node = ProcessNodeList->Items[i];\n\n        memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM);\n        PhInvalidateTreeNewNode(&node->Node, TN_CACHE_COLOR);\n        node->ValidMask = 0;\n\n        // Invalidate graph buffers.\n        node->CpuGraphBuffers.Valid = FALSE;\n        node->PrivateGraphBuffers.Valid = FALSE;\n        node->IoGraphBuffers.Valid = FALSE;\n    }\n\n    InvalidateRect(ProcessTreeListHandle, NULL, FALSE);\n}\n\nBOOLEAN PhSelectAndEnsureVisibleProcessNode(\n    _In_ PPH_PROCESS_NODE ProcessNode\n    )\n{\n    return PhSelectAndEnsureVisibleProcessNodes(&ProcessNode, 1);\n}\n\nBOOLEAN PhSelectAndEnsureVisibleProcessNodes(\n    _In_ PPH_PROCESS_NODE *ProcessNodes,\n    _In_ ULONG NumberOfProcessNodes\n    )\n{\n    ULONG i;\n    PPH_PROCESS_NODE leader = NULL;\n    PPH_PROCESS_NODE node;\n    BOOLEAN needsRestructure = FALSE;\n\n    PhDeselectAllProcessNodes();\n\n    for (i = 0; i < NumberOfProcessNodes; i++)\n    {\n        if (ProcessNodes[i]->Node.Visible)\n        {\n            leader = ProcessNodes[i];\n            break;\n        }\n    }\n\n    if (!leader)\n    {\n        PhShowInformation2(\n            PhMainWndHandle,\n            L\"Unable to perform the operation.\",\n            L\"%s\",\n            L\"This node cannot be displayed because it is currently hidden by your active filter settings or preferences.\"\n            );\n        return FALSE;\n    }\n\n    // Expand recursively upwards, and select the nodes.\n\n    for (i = 0; i < NumberOfProcessNodes; i++)\n    {\n        if (!ProcessNodes[i]->Node.Visible)\n            continue;\n\n        node = ProcessNodes[i]->Parent;\n\n        while (node)\n        {\n            if (!node->Node.Expanded)\n                needsRestructure = TRUE;\n\n            node->Node.Expanded = TRUE;\n            node = node->Parent;\n        }\n\n        ProcessNodes[i]->Node.Selected = TRUE;\n    }\n\n    if (needsRestructure)\n        TreeNew_NodesStructured(ProcessTreeListHandle);\n\n    TreeNew_FocusMarkSelectNode(ProcessTreeListHandle, &leader->Node);\n    return TRUE;\n}\n\nVOID PhpPopulateTableWithProcessNodes(\n    _In_ HWND TreeListHandle,\n    _In_ PPH_PROCESS_NODE Node,\n    _In_ ULONG Level,\n    _In_ PPH_STRING **Table,\n    _Inout_ PULONG Index,\n    _In_ PULONG DisplayToId,\n    _In_ ULONG Columns\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Columns; i++)\n    {\n        PH_TREENEW_GET_CELL_TEXT getCellText;\n        PPH_STRING text;\n\n        getCellText.Node = &Node->Node;\n        getCellText.Id = DisplayToId[i];\n        PhInitializeEmptyStringRef(&getCellText.Text);\n        TreeNew_GetCellText(TreeListHandle, &getCellText);\n\n        if (i != 0)\n        {\n            if (getCellText.Text.Length == 0)\n                text = PhReferenceEmptyString();\n            else\n                text = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length);\n        }\n        else\n        {\n            // If this is the first column in the row, add some indentation.\n            text = PhaCreateStringEx(\n                NULL,\n                getCellText.Text.Length + UInt32x32To64(Level, 2) * sizeof(WCHAR)\n                );\n            wmemset(text->Buffer, L' ', UInt32x32To64(Level, 2));\n            memcpy(&text->Buffer[UInt32x32To64(Level, 2)], getCellText.Text.Buffer, getCellText.Text.Length);\n        }\n\n        Table[*Index][i] = text;\n    }\n\n    (*Index)++;\n\n    // Process the children.\n    for (i = 0; i < Node->Children->Count; i++)\n    {\n        PhpPopulateTableWithProcessNodes(\n            TreeListHandle,\n            Node->Children->Items[i],\n            Level + 1,\n            Table,\n            Index,\n            DisplayToId,\n            Columns\n            );\n    }\n}\n\nPPH_LIST PhGetProcessTreeListLines(\n    _In_ HWND TreeListHandle,\n    _In_ ULONG NumberOfNodes,\n    _In_ PPH_LIST RootNodes,\n    _In_ ULONG Mode\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_LIST lines;\n    // The number of rows in the table (including +1 for the column headers).\n    ULONG rows;\n    // The number of columns.\n    ULONG columns;\n    // A column display index to ID map.\n    PULONG displayToId;\n    // A column display index to text map.\n    PWSTR *displayToText;\n    // The actual string table.\n    PPH_STRING **table;\n    ULONG i;\n    ULONG j;\n\n    // Use a local auto-pool to make memory management a bit less painful.\n    PhInitializeAutoPool(&autoPool);\n\n    rows = NumberOfNodes + 1;\n\n    // Create the display index to ID map.\n    PhMapDisplayIndexTreeNew(TreeListHandle, &displayToId, &displayToText, &columns);\n\n    PhaCreateTextTable(&table, rows, columns);\n\n    // Populate the first row with the column headers.\n    for (i = 0; i < columns; i++)\n    {\n        table[0][i] = PhaCreateString(displayToText[i]);\n    }\n\n    // Go through the nodes in the process tree and populate each cell of the table.\n\n    j = 1; // index starts at one because the first row contains the column headers.\n\n    for (i = 0; i < RootNodes->Count; i++)\n    {\n        PhpPopulateTableWithProcessNodes(\n            TreeListHandle,\n            RootNodes->Items[i],\n            0,\n            table,\n            &j,\n            displayToId,\n            columns\n            );\n    }\n\n    PhFree(displayToId);\n    PhFree(displayToText);\n\n    lines = PhaFormatTextTable(table, rows, columns, Mode);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return lines;\n}\n\nVOID PhCopyProcessTree(\n    VOID\n    )\n{\n    PPH_STRING text;\n\n    text = PhGetTreeNewText(ProcessTreeListHandle, 0);\n    PhSetClipboardString(ProcessTreeListHandle, &text->sr);\n    PhDereferenceObject(text);\n}\n\nVOID PhWriteProcessTree(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ ULONG Mode\n    )\n{\n    PPH_LIST lines;\n    ULONG i;\n\n    lines = PhGetProcessTreeListLines(\n        ProcessTreeListHandle,\n        ProcessNodeList->Count,\n        ProcessNodeRootList,\n        Mode\n        );\n\n    for (i = 0; i < lines->Count; i++)\n    {\n        PPH_STRING line;\n\n        line = lines->Items[i];\n        PhWriteStringAsUtf8FileStream(FileStream, &line->sr);\n        PhDereferenceObject(line);\n        PhWriteStringAsUtf8FileStream2(FileStream, L\"\\r\\n\");\n    }\n\n    PhDereferenceObject(lines);\n}\n\nPPH_LIST PhDuplicateProcessNodeList(\n    VOID\n    )\n{\n    PPH_LIST newList;\n\n    newList = PhCreateList(ProcessNodeList->Count);\n    PhInsertItemsList(newList, 0, ProcessNodeList->Items, ProcessNodeList->Count);\n\n    return newList;\n}\n\n/**\n * Determines if the process item should show the image coherency in the UI.\n *\n * \\param[in] ProcessItem - Process item to check.\n * \\param[in] CheckThreshold - If TRUE the image low coherency threshold is\n * checked, see: LowImageCoherencyThreshold.\n * \\return TRUE if the image coherency should be shown, FALSE otherwise.\n */\nBOOLEAN PhpShouldShowImageCoherency(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ BOOLEAN CheckThreshold\n    )\n{\n    const FLOAT LowImageCoherencyThreshold = 0.5f; /**< Limit for displaying \"low image coherency\" */\n\n    if (PhCsImageCoherencyScanLevel == 0)\n    {\n        //\n        // The advanced option for the image coherency scan level is 0.\n        // This disables the scanning and we should not show the image\n        // coherency.\n        //\n        return FALSE;\n    }\n\n    //\n    // If we haven't done the image coherency check yet, don't show. We\n    // initialize the process item with STATUS_PENDING to denote this.\n    // See: PhCreateProcessItem\n    //\n    if (ProcessItem->ImageCoherencyStatus == STATUS_PENDING)\n    {\n        return FALSE;\n    }\n\n    //\n    // Exclude the fake processes and system idle PID\n    //\n    if (!PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId))\n    {\n        return FALSE;\n    }\n\n    //\n    // Do not show if the process has no image file name (Secure System)\n    //\n    if (PhIsNullOrEmptyString(ProcessItem->FileName))\n    {\n        return FALSE;\n    }\n\n    //\n    // We don't do the coherency check if the created process is WSL\n    //\n    if (ProcessItem->IsSubsystemProcess)\n    {\n        return FALSE;\n    }\n\n    if (NT_SUCCESS(ProcessItem->ImageCoherencyStatus) ||\n        (ProcessItem->ImageCoherencyStatus == STATUS_INVALID_IMAGE_NOT_MZ) ||\n        (ProcessItem->ImageCoherencyStatus == STATUS_INVALID_IMAGE_FORMAT) ||\n        (ProcessItem->ImageCoherencyStatus == STATUS_INVALID_IMAGE_HASH) ||\n        (ProcessItem->ImageCoherencyStatus == STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT))\n    {\n        //\n        // The coherency status is a success code or a known \"valid\" error\n        // from the coherency calculation (PhGetProcessImageCoherency).\n        // We should show the coherency value.\n        //\n\n        if (CheckThreshold)\n        {\n            //\n            // A threshold check is requested. This is generally used for\n            // checking if we should highlight an entry. If the coherency\n            // is below a given threshold return true. Otherwise false.\n            //\n            if (ProcessItem->ImageCoherency <= LowImageCoherencyThreshold)\n            {\n                return TRUE;\n            }\n            else\n            {\n                return FALSE;\n            }\n\n        }\n\n        //\n        // No special handling, return true.\n        //\n        return TRUE;\n    }\n\n    //\n    // Any other error NTSTATUS we don't show the coherency value, we'll\n    // show the reason why we failed the calculation (a string representation\n    // of the status code).\n    //\n\n    return FALSE;\n}\n\n/**\n * Retrieves the Win32 file name of the process associated with the specified process item.\n *\n * \\param ProcessItem A pointer to a PPH_PROCESS_ITEM structure representing the process.\n * \\param FileNameWin32 A pointer to a variable that receives a pointer to a PPH_STRING containing the Win32 file name.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessItemFileNameWin32(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _Out_ PPH_STRING* FileNameWin32\n    )\n{\n    if (ProcessItem->QueryHandle)\n    {\n        PPH_STRING fileName;\n\n        if (NT_SUCCESS(PhGetProcessImageFileNameWin32(ProcessItem->QueryHandle, &fileName)))\n        {\n            *FileNameWin32 = fileName;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    if (ProcessItem->FileName)\n    {\n        *FileNameWin32 = PhGetFileName(ProcessItem->FileName);\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n"
  },
  {
    "path": "SystemInformer/prpgenv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2018-2023\n *\n */\n\n#include <phapp.h>\n#include <cpysave.h>\n#include <emenu.h>\n#include <settings.h>\n\n#include <apiimport.h>\n#include <phsettings.h>\n#include <procprp.h>\n#include <procprpp.h>\n#include <procprv.h>\n#include <wslsup.h>\n\ntypedef enum _ENVIRONMENT_TREE_MENU_ITEM\n{\n    ENVIRONMENT_TREE_MENU_ITEM_HIDE_PROCESS_TYPE = 1,\n    ENVIRONMENT_TREE_MENU_ITEM_HIDE_USER_TYPE,\n    ENVIRONMENT_TREE_MENU_ITEM_HIDE_SYSTEM_TYPE,\n    ENVIRONMENT_TREE_MENU_ITEM_HIDE_CMD_TYPE,\n    ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_PROCESS_TYPE,\n    ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_USER_TYPE,\n    ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_SYSTEM_TYPE,\n    ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_CMD_TYPE,\n    ENVIRONMENT_TREE_MENU_ITEM_NEW_ENVIRONMENT_VARIABLE,\n    ENVIRONMENT_TREE_MENU_ITEM_MAXIMUM\n} ENVIRONMENT_TREE_MENU_ITEM;\n\ntypedef enum _ENVIRONMENT_TREE_COLUMN_ITEM\n{\n    ENVIRONMENT_COLUMN_ITEM_NAME,\n    ENVIRONMENT_COLUMN_ITEM_VALUE,\n    ENVIRONMENT_COLUMN_ITEM_MAXIMUM\n} ENVIRONMENT_TREE_COLUMN_ITEM;\n\ntypedef enum _PROCESS_ENVIRONMENT_TREENODE_TYPE\n{\n    PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP = 0x1,\n    PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS = 0x2,\n    PROCESS_ENVIRONMENT_TREENODE_TYPE_USER = 0x4,\n    PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM = 0x8\n} PROCESS_ENVIRONMENT_TREENODE_TYPE;\n\ntypedef struct _PHP_PROCESS_ENVIRONMENT_TREENODE\n{\n    PH_TREENEW_NODE Node;\n    PH_STRINGREF TextCache[ENVIRONMENT_COLUMN_ITEM_MAXIMUM];\n\n    struct _PHP_PROCESS_ENVIRONMENT_TREENODE* Parent;\n    PPH_LIST Children;\n    BOOLEAN HasChildren;\n\n    ULONG Id;\n    PROCESS_ENVIRONMENT_TREENODE_TYPE Type;\n    PPH_STRING NameText;\n    PPH_STRING ValueText;\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN IsCmdVariable : 1;\n            BOOLEAN Spare : 7;\n        };\n    };\n} PHP_PROCESS_ENVIRONMENT_TREENODE, *PPHP_PROCESS_ENVIRONMENT_TREENODE;\n\nPPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentNode(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_opt_ PPHP_PROCESS_ENVIRONMENT_TREENODE ParentNode,\n    _In_ PROCESS_ENVIRONMENT_TREENODE_TYPE Type,\n    _In_ PPH_STRING Name,\n    _In_opt_ PPH_STRING Value\n    );\n\nPPHP_PROCESS_ENVIRONMENT_TREENODE PhpFindEnvironmentNode(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ PPH_STRING Name\n    );\n\nVOID PhpClearEnvironmentTree(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context\n    );\n\nPPHP_PROCESS_ENVIRONMENT_TREENODE PhpGetSelectedEnvironmentNode(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context\n    );\n\n_Success_(return)\nBOOLEAN PhpGetSelectedEnvironmentNodes(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _Out_ PPHP_PROCESS_ENVIRONMENT_TREENODE * *Nodes,\n    _Out_ PULONG NumberOfNodes\n    );\n\nBOOLEAN PhpHasSelectedEnvironmentGroupNode(\n    _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE* Nodes,\n    _In_ ULONG NumberOfNodes\n    );\n\n#define ID_ENV_EDIT 50001\n#define ID_ENV_DELETE 50002\n#define ID_ENV_COPY 50003\n\ntypedef struct _EDIT_ENV_DIALOG_CONTEXT\n{\n    PPH_PROCESS_ITEM ProcessItem;\n    PWSTR Name;\n    PWSTR Value;\n    BOOLEAN Refresh;\n    PH_LAYOUT_MANAGER LayoutManager;\n    RECT MinimumSize;\n} EDIT_ENV_DIALOG_CONTEXT, *PEDIT_ENV_DIALOG_CONTEXT;\n\nINT_PTR PhpShowEditEnvDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PWSTR Name,\n    _In_opt_ PWSTR Value,\n    _Out_opt_ PBOOLEAN Refresh\n    );\n\nINT_PTR CALLBACK PhpEditEnvDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhpClearEnvironmentItems(\n    _Inout_ PPH_ENVIRONMENT_CONTEXT Context\n    )\n{\n    SIZE_T i;\n    PPH_ENVIRONMENT_ITEM item;\n\n    for (i = 0; i < Context->Items.Count; i++)\n    {\n        item = PhItemArray(&Context->Items, i);\n\n        if (item->Name)\n            PhDereferenceObject(item->Name);\n        if (item->Value)\n            PhDereferenceObject(item->Value);\n    }\n\n    PhClearArray(&Context->Items);\n}\n\nVOID PhpSetEnvironmentListStatusMessage(\n    _Inout_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ NTSTATUS Status\n    )\n{\n    if (Context->ProcessItem->State & PH_PROCESS_ITEM_REMOVED || Status == STATUS_PARTIAL_COPY)\n    {\n        PhMoveReference(&Context->StatusMessage, PhCreateString(L\"There are no environment variables to display.\"));\n        TreeNew_SetEmptyText(Context->TreeNewHandle, &Context->StatusMessage->sr, 0);\n    }\n    else\n    {\n        PPH_STRING statusMessage;\n\n        statusMessage = PhGetStatusMessage(Status, 0);\n        PhMoveReference(&Context->StatusMessage, PhConcatStrings2(\n            L\"Unable to query environment information:\\n\",\n            PhGetStringOrDefault(statusMessage, L\"Unknown error.\")\n            ));\n        TreeNew_SetEmptyText(Context->TreeNewHandle, &Context->StatusMessage->sr, 0);\n        //TreeNew_NodesStructured(Context->TreeNewHandle);\n        PhClearReference(&statusMessage);\n    }\n}\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nBOOLEAN NTAPI PhEnumEnvironmentKeyValueCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PKEY_VALUE_FULL_INFORMATION Information,\n    _In_ PPH_ENVIRONMENT_CONTEXT Context\n    )\n{\n    if (Context && Information->Type == REG_SZ)\n    {\n        PH_ENVIRONMENT_ITEM entry;\n\n        entry.Name = PhCreateStringEx(Information->Name, Information->NameLength);\n        entry.Value = PhCreateStringEx(PTR_ADD_OFFSET(Information, Information->DataOffset), Information->DataLength);\n\n        PhAddItemArray(&Context->Items, &entry);\n    }\n\n    return TRUE;\n}\n\nVOID PhpRefreshEnvironmentList(\n    _Inout_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    NTSTATUS status;\n    PVOID environment;\n    ULONG environmentLength;\n    ULONG enumerationKey;\n    PH_ENVIRONMENT_VARIABLE variable;\n    PPH_ENVIRONMENT_ITEM item;\n    PPHP_PROCESS_ENVIRONMENT_TREENODE processRootNode;\n    PPHP_PROCESS_ENVIRONMENT_TREENODE userRootNode;\n    PPHP_PROCESS_ENVIRONMENT_TREENODE systemRootNode;\n    PVOID systemDefaultEnvironment = NULL;\n    PVOID userDefaultEnvironment = NULL;\n    SIZE_T i;\n\n    PhpClearEnvironmentTree(Context);\n    processRootNode = PhpAddEnvironmentNode(Context, NULL, PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP | PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS, PhaCreateString(L\"Process\"), NULL);\n    userRootNode = PhpAddEnvironmentNode(Context, NULL, PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP | PROCESS_ENVIRONMENT_TREENODE_TYPE_USER, PhaCreateString(L\"User\"), NULL);\n    systemRootNode = PhpAddEnvironmentNode(Context, NULL, PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP | PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM, PhaCreateString(L\"System\"), NULL);\n\n    if (ProcessItem->ProcessId == SYSTEM_PROCESS_ID)\n    {\n        static CONST PH_STRINGREF environmentKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Control\\\\Session Manager\\\\Environment\");\n        HANDLE keyHandle;\n\n        PhCreateEnvironmentBlock(&systemDefaultEnvironment, NULL, FALSE);\n\n        SIZE_T variableLength = 0;\n        PWSTR variableName = systemDefaultEnvironment;\n\n        while (*variableName)\n        {\n            variableLength += PhCountStringZ(variableName);\n            variableName += variableLength + 1;\n        }\n\n        enumerationKey = 0;\n\n        while (NT_SUCCESS(PhEnumProcessEnvironmentVariables(\n            systemDefaultEnvironment,\n            (ULONG)variableLength * sizeof(WCHAR),\n            &enumerationKey,\n            &variable\n            )))\n        {\n            PH_ENVIRONMENT_ITEM entry;\n\n            entry.Name = PhCreateString2(&variable.Name);\n            entry.Value = PhCreateString2(&variable.Value);\n\n            PhAddItemArray(&Context->Items, &entry);\n        }\n\n        status = PhOpenKey(\n            &keyHandle,\n            KEY_READ,\n            PH_KEY_LOCAL_MACHINE,\n            &environmentKeyName,\n            0\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhEnumerateValueKey(\n                keyHandle,\n                KeyValueFullInformation,\n                PhEnumEnvironmentKeyValueCallback,\n                Context\n                );\n            NtClose(keyHandle);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhpSetEnvironmentListStatusMessage(Context, status);\n            TreeNew_NodesStructured(Context->TreeNewHandle);\n            return;\n        }\n\n    }\n    else\n    {\n        HANDLE processHandle = NULL;\n\n        if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId))\n        {\n            status = PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n                ProcessItem->ProcessId\n                );\n        }\n        else\n        {\n            status = STATUS_INVALID_CID;\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhpSetEnvironmentListStatusMessage(Context, status);\n            TreeNew_NodesStructured(Context->TreeNewHandle);\n            return;\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            HANDLE tokenHandle;\n\n            PhCreateEnvironmentBlock(&systemDefaultEnvironment, NULL, FALSE);\n\n            if (NT_SUCCESS(PhOpenProcessToken(\n                processHandle,\n                TOKEN_QUERY | TOKEN_DUPLICATE,\n                &tokenHandle\n                )))\n            {\n                PhCreateEnvironmentBlock(&userDefaultEnvironment, tokenHandle, FALSE);\n                NtClose(tokenHandle);\n            }\n\n            status = PhGetProcessEnvironment(\n                processHandle,\n                !!ProcessItem->IsWow64Process,\n                &environment,\n                &environmentLength\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                enumerationKey = 0;\n\n                while (NT_SUCCESS(PhEnumProcessEnvironmentVariables(\n                    environment,\n                    environmentLength,\n                    &enumerationKey,\n                    &variable\n                    )))\n                {\n                    PH_ENVIRONMENT_ITEM entry;\n\n                    entry.Name = PhCreateString2(&variable.Name);\n                    entry.Value = PhCreateString2(&variable.Value);\n\n                    PhAddItemArray(&Context->Items, &entry);\n                }\n\n                PhFreePage(environment);\n            }\n            else\n            {\n                PhpSetEnvironmentListStatusMessage(Context, status);\n            }\n\n            NtClose(processHandle);\n        }\n    }\n\n    for (i = 0; i < Context->Items.Count; i++)\n    {\n        PPHP_PROCESS_ENVIRONMENT_TREENODE node;\n        PPHP_PROCESS_ENVIRONMENT_TREENODE parentNode;\n        PROCESS_ENVIRONMENT_TREENODE_TYPE nodeType;\n        PPH_STRING variableValue;\n\n        item = PhItemArray(&Context->Items, i);\n\n        if (!item->Name)\n            continue;\n\n        if (systemDefaultEnvironment && PhQueryEnvironmentVariable(\n            systemDefaultEnvironment,\n            &item->Name->sr,\n            NULL\n            ) == STATUS_BUFFER_TOO_SMALL)\n        {\n            nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM;\n            parentNode = systemRootNode;\n\n            if (NT_SUCCESS(PhQueryEnvironmentVariable(\n                systemDefaultEnvironment,\n                &item->Name->sr,\n                &variableValue\n                )))\n            {\n                if (!PhEqualString(variableValue, item->Value, FALSE))\n                {\n                    nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS;\n                    parentNode = processRootNode;\n                }\n\n                PhDereferenceObject(variableValue);\n            }\n        }\n        else if (userDefaultEnvironment && PhQueryEnvironmentVariable(\n            userDefaultEnvironment,\n            &item->Name->sr,\n            NULL\n            ) == STATUS_BUFFER_TOO_SMALL)\n        {\n            nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_USER;\n            parentNode = userRootNode;\n\n            if (NT_SUCCESS(PhQueryEnvironmentVariable(\n                userDefaultEnvironment,\n                &item->Name->sr,\n                &variableValue\n                )))\n            {\n                if (!PhEqualString(variableValue, item->Value, FALSE))\n                {\n                    nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS;\n                    parentNode = processRootNode;\n                }\n\n                PhDereferenceObject(variableValue);\n            }\n        }\n        else\n        {\n            nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS;\n            parentNode = processRootNode;\n        }\n\n        node = PhpAddEnvironmentNode(\n            Context,\n            parentNode,\n            nodeType,\n            item->Name,\n            item->Value\n            );\n\n        if (item->Name && item->Name->Buffer[0] == L'=') // HACK (dmex)\n        {\n            node->IsCmdVariable = TRUE;\n        }\n    }\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    if (systemDefaultEnvironment)\n        PhDestroyEnvironmentBlock(systemDefaultEnvironment);\n    if (userDefaultEnvironment)\n        PhDestroyEnvironmentBlock(userDefaultEnvironment);\n}\n\nVOID PhpRefreshWslEnvironmentList(\n    _Inout_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_STRING environment;\n    ULONG enumerationKey;\n    PH_ENVIRONMENT_VARIABLE variable;\n    PPH_ENVIRONMENT_ITEM item;\n    PPHP_PROCESS_ENVIRONMENT_TREENODE processRootNode;\n    SIZE_T i;\n\n    PhpClearEnvironmentTree(Context);\n    processRootNode = PhpAddEnvironmentNode(Context, NULL, PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP | PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS, PhaCreateString(L\"Process\"), NULL);\n    PhpAddEnvironmentNode(Context, NULL, PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP | PROCESS_ENVIRONMENT_TREENODE_TYPE_USER, PhaCreateString(L\"User\"), NULL);\n    PhpAddEnvironmentNode(Context, NULL, PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP | PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM, PhaCreateString(L\"System\"), NULL);\n\n    if (!ProcessItem->LxssProcessId)\n    {\n        PhpSetEnvironmentListStatusMessage(Context, STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT);\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n        return;\n    }\n\n    if (PhIsNullOrEmptyString(ProcessItem->FileName))\n    {\n        PhpSetEnvironmentListStatusMessage(Context, STATUS_OBJECT_NAME_INVALID);\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n        return;\n    }\n\n    if (!NT_SUCCESS(PhWslQueryDistroProcessEnvironment(\n        &ProcessItem->FileName->sr,\n        ProcessItem->LxssProcessId,\n        &environment\n        )))\n    {\n        PhpSetEnvironmentListStatusMessage(Context, STATUS_PARTIAL_COPY);\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n        return;\n    }\n\n    enumerationKey = 0;\n\n    while (NT_SUCCESS(PhEnumProcessEnvironmentVariables(\n        PhGetString(environment),\n        (ULONG)environment->Length,\n        &enumerationKey,\n        &variable\n        )))\n    {\n        PH_ENVIRONMENT_ITEM entry;\n\n        entry.Name = PhCreateString2(&variable.Name);\n        entry.Value = PhCreateString2(&variable.Value);\n\n        PhAddItemArray(&Context->Items, &entry);\n    }\n\n    for (i = 0; i < Context->Items.Count; i++)\n    {\n        item = PhItemArray(&Context->Items, i);\n\n        if (!item->Name)\n            continue;\n\n        PhpAddEnvironmentNode(\n            Context,\n            processRootNode,\n            PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS,\n            item->Name,\n            item->Value\n            );\n    }\n\n    PhApplyTreeNewFilters(&Context->TreeFilterSupport);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    PhClearReference(&environment);\n}\n\nNTSTATUS PhpEditDlgSetEnvironment(\n    _Inout_ PEDIT_ENV_DIALOG_CONTEXT Context,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_STRING Name,\n    _In_ PPH_STRING Value\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    HANDLE processHandle = NULL;\n    LARGE_INTEGER timeout;\n\n    // Windows 8 requires ALL_ACCESS for PLM execution requests. (dmex)\n    if (WindowsVersion >= WINDOWS_8 && WindowsVersion <= WINDOWS_8_1)\n    {\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_ALL_ACCESS,\n            ProcessItem->ProcessId\n            );\n    }\n\n    // Windows 10 and above require SET_LIMITED for PLM execution requests. (dmex)\n    if (!NT_SUCCESS(status))\n    {\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_LIMITED_INFORMATION |\n            PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |\n            PROCESS_VM_READ | PROCESS_VM_WRITE,\n            ProcessItem->ProcessId\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC);\n\n        // Delete the old environment variable if necessary.\n        if (!PhEqualStringZ(Context->Name, L\"\", FALSE) &&\n            !PhEqualString2(Name, Context->Name, FALSE))\n        {\n            PH_STRINGREF nameSr;\n\n            PhInitializeStringRefLongHint(&nameSr, Context->Name);\n            PhSetEnvironmentVariableRemote(\n                processHandle,\n                &nameSr,\n                NULL,\n                &timeout\n                );\n        }\n\n        status = PhSetEnvironmentVariableRemote(\n            processHandle,\n            &Name->sr,\n            &Value->sr,\n            &timeout\n            );\n\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\nNTSTATUS PhpEditDeleteEnvironment(\n    _Inout_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_STRING Name\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    HANDLE processHandle = NULL;\n    LARGE_INTEGER timeout;\n\n    // Windows 8 requires ALL_ACCESS for PLM execution requests. (dmex)\n    if (WindowsVersion >= WINDOWS_8 && WindowsVersion <= WINDOWS_8_1)\n    {\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_ALL_ACCESS,\n            ProcessItem->ProcessId\n            );\n    }\n\n    // Windows 10 and above require SET_LIMITED for PLM execution requests. (dmex)\n    if (!NT_SUCCESS(status))\n    {\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_LIMITED_INFORMATION |\n            PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |\n            PROCESS_VM_READ | PROCESS_VM_WRITE,\n            ProcessItem->ProcessId\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC);\n        status = PhSetEnvironmentVariableRemote(\n            processHandle,\n            &Name->sr,\n            NULL,\n            &timeout\n            );\n\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\nULONG_PTR CALLBACK PhpEditEnvSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ ULONG WindowMessage,\n    _In_ ULONG_PTR wParam,\n    _In_ ULONG_PTR lParam\n    )\n{\n    WNDPROC oldWndProc;\n\n    if (!(oldWndProc = PhGetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT)))\n        return FALSE;\n\n    switch (WindowMessage)\n    {\n    case WM_DESTROY:\n        {\n            PhSetWindowProcedure(WindowHandle, oldWndProc);\n            PhRemoveWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_GETDLGCODE:\n        {\n            if (wParam != VK_ESCAPE)\n            {\n                if (wParam == VK_RETURN)\n                {\n                    return DLGC_WANTMESSAGE;\n                }\n\n                return DLGC_WANTALLKEYS;\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n}\n\nINT_PTR CALLBACK PhpEditEnvDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PEDIT_ENV_DIALOG_CONTEXT context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PEDIT_ENV_DIALOG_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HWND windowhandle;\n\n            windowhandle = GetDlgItem(hwndDlg, IDC_VALUE);\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_NAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, windowhandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhLayoutManagerLayout(&context->LayoutManager);\n\n            context->MinimumSize.left = 0;\n            context->MinimumSize.top = 0;\n            context->MinimumSize.right = 200;\n            context->MinimumSize.bottom = 140;\n            MapDialogRect(hwndDlg, &context->MinimumSize);\n\n            PhSetDialogItemText(hwndDlg, IDC_NAME, context->Name);\n            PhSetDialogItemText(hwndDlg, IDC_VALUE, context->Value ? context->Value : L\"\");\n\n            PhSetWindowContext(windowhandle, PH_WINDOW_CONTEXT_DEFAULT, PhGetWindowProcedure(windowhandle));\n            PhSetWindowProcedure(windowhandle, (WNDPROC)PhpEditEnvSubclassProc);\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDCANCEL));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                {\n                    EndDialog(hwndDlg, IDCANCEL);\n                }\n                break;\n            case IDOK:\n                {\n                    NTSTATUS status = STATUS_UNSUCCESSFUL;\n                    PPH_STRING name;\n                    PPH_STRING value;\n\n                    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) && !PhShowConfirmMessage(\n                        hwndDlg,\n                        L\"edit\",\n                        L\"the selected environment variable\",\n                        L\"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.\",\n                        FALSE\n                        ))\n                    {\n                        break;\n                    }\n\n                    name = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_NAME)));\n                    value = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_VALUE)));\n\n                    if (!PhIsNullOrEmptyString(name))\n                    {\n                        if (!PhEqualString2(name, context->Name, FALSE) ||\n                            !context->Value || !PhEqualString2(value, context->Value, FALSE))\n                        {\n                            status = PhpEditDlgSetEnvironment(\n                                context,\n                                context->ProcessItem,\n                                name,\n                                value\n                                );\n\n                            if (!NT_SUCCESS(status))\n                            {\n                                PhShowStatus(hwndDlg, L\"Unable to set the environment variable.\", status, 0);\n                                break;\n                            }\n                            else if (status == STATUS_TIMEOUT)\n                            {\n                                PhShowStatus(hwndDlg, L\"Unable to delete the environment variable.\", 0, WAIT_TIMEOUT);\n                                break;\n                            }\n\n                            context->Refresh = TRUE;\n                        }\n\n                        EndDialog(hwndDlg, IDOK);\n                    }\n                }\n                break;\n            case IDC_NAME:\n                {\n                    if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE)\n                    {\n                        EnableWindow(GetDlgItem(hwndDlg, IDOK), PhGetWindowTextLength(GetDlgItem(hwndDlg, IDC_NAME)) > 0);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nINT_PTR PhpShowEditEnvDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PWSTR Name,\n    _In_opt_ PWSTR Value,\n    _Out_opt_ PBOOLEAN Refresh\n    )\n{\n    INT_PTR result;\n    EDIT_ENV_DIALOG_CONTEXT context;\n\n    memset(&context, 0, sizeof(EDIT_ENV_DIALOG_CONTEXT));\n    context.ProcessItem = ProcessItem;\n    context.Name = Name;\n    context.Value = Value;\n\n    result = PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_EDITENV),\n        ParentWindowHandle,\n        PhpEditEnvDlgProc,\n        &context\n        );\n\n    if (Refresh)\n        *Refresh = context.Refresh;\n\n    return result;\n}\n\nVOID PhpShowEnvironmentNodeContextMenu(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenuEvent\n    )\n{\n    PPHP_PROCESS_ENVIRONMENT_TREENODE* nodes;\n    ULONG numberOfNodes;\n    PPH_EMENU menu;\n    PPH_EMENU_ITEM selectedItem;\n\n    if (!PhpGetSelectedEnvironmentNodes(Context, &nodes, &numberOfNodes))\n        return;\n    if (numberOfNodes == 0)\n        return;\n\n    menu = PhCreateEMenu();\n    if (!PhpHasSelectedEnvironmentGroupNode(nodes, numberOfNodes))\n    {\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_ENV_EDIT, L\"Edit\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_ENV_DELETE, L\"Delete\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    }\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_ENV_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n    PhInsertCopyCellEMenuItem(menu, ID_ENV_COPY, Context->TreeNewHandle, ContextMenuEvent->Column);\n\n    selectedItem = PhShowEMenu(\n        menu,\n        Context->WindowHandle,\n        PH_EMENU_SHOW_LEFTRIGHT,\n        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n        ContextMenuEvent->Location.x,\n        ContextMenuEvent->Location.y\n        );\n\n    if (selectedItem && selectedItem->Id != ULONG_MAX)\n    {\n        if (!PhHandleCopyCellEMenuItem(selectedItem))\n        {\n            SendMessage(Context->WindowHandle, WM_COMMAND, selectedItem->Id, 0);\n        }\n    }\n\n    PhDestroyEMenu(menu);\n}\n\nVOID PhLoadSettingsEnvironmentList(\n    _Inout_ PPH_ENVIRONMENT_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhGetStringSetting(SETTING_ENVIRONMENT_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_ENVIRONMENT_TREE_LIST_SORT);\n    Context->Flags = PhGetIntegerSetting(SETTING_ENVIRONMENT_TREE_LIST_FLAGS);\n\n    PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSaveSettingsEnvironmentList(\n    _Inout_ PPH_ENVIRONMENT_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings);\n\n    PhSetIntegerSetting(SETTING_ENVIRONMENT_TREE_LIST_FLAGS, Context->Flags);\n    PhSetStringSetting2(SETTING_ENVIRONMENT_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_ENVIRONMENT_TREE_LIST_SORT, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSetOptionsEnvironmentList(\n    _Inout_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ ULONG Options\n    )\n{\n    switch (Options)\n    {\n    case ENVIRONMENT_TREE_MENU_ITEM_HIDE_PROCESS_TYPE:\n        Context->HideProcessEnvironment = !Context->HideProcessEnvironment;\n        break;\n    case ENVIRONMENT_TREE_MENU_ITEM_HIDE_USER_TYPE:\n        Context->HideUserEnvironment = !Context->HideUserEnvironment;\n        break;\n    case ENVIRONMENT_TREE_MENU_ITEM_HIDE_SYSTEM_TYPE:\n        Context->HideSystemEnvironment = !Context->HideSystemEnvironment;\n        break;\n    case ENVIRONMENT_TREE_MENU_ITEM_HIDE_CMD_TYPE:\n        Context->HideCmdTypeEnvironment = !Context->HideCmdTypeEnvironment;\n        break;\n    case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_PROCESS_TYPE:\n        Context->HighlightProcessEnvironment = !Context->HighlightProcessEnvironment;\n        break;\n    case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_USER_TYPE:\n        Context->HighlightUserEnvironment = !Context->HighlightUserEnvironment;\n        break;\n    case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_SYSTEM_TYPE:\n        Context->HighlightSystemEnvironment = !Context->HighlightSystemEnvironment;\n        break;\n    case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_CMD_TYPE:\n        Context->HighlightCmdEnvironment = !Context->HighlightCmdEnvironment;\n        break;\n    }\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpEnvironmentNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPHP_PROCESS_ENVIRONMENT_TREENODE node1 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE *)Entry1;\n    PPHP_PROCESS_ENVIRONMENT_TREENODE node2 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE *)Entry2;\n\n    return PhEqualStringRef(&node1->NameText->sr, &node2->NameText->sr, TRUE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpEnvironmentNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashStringRefEx(&(*(PPHP_PROCESS_ENVIRONMENT_TREENODE*)Entry)->NameText->sr, TRUE, PH_STRING_HASH_X65599);\n}\n\nVOID PhpDestroyEnvironmentNode(\n    _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE Node\n    )\n{\n    if (Node->NameText)\n        PhDereferenceObject(Node->NameText);\n    if (Node->ValueText)\n        PhDereferenceObject(Node->ValueText);\n\n    PhFree(Node);\n}\n\nPPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentNode(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_opt_ PPHP_PROCESS_ENVIRONMENT_TREENODE ParentNode,\n    _In_ PROCESS_ENVIRONMENT_TREENODE_TYPE Type,\n    _In_ PPH_STRING Name,\n    _In_opt_ PPH_STRING Value\n    )\n{\n    PPHP_PROCESS_ENVIRONMENT_TREENODE node;\n\n    node = PhAllocateZero(sizeof(PHP_PROCESS_ENVIRONMENT_TREENODE));\n    PhInitializeTreeNewNode(&node->Node);\n\n    memset(node->TextCache, 0, sizeof(PH_STRINGREF) * ENVIRONMENT_COLUMN_ITEM_MAXIMUM);\n    node->Node.TextCache = node->TextCache;\n    node->Node.TextCacheSize = ENVIRONMENT_COLUMN_ITEM_MAXIMUM;\n    node->Children = PhCreateList(1);\n\n    node->Type = Type;\n    PhSetReference(&node->NameText, Name);\n    if (Value) PhSetReference(&node->ValueText, Value);\n\n    PhAddEntryHashtable(Context->NodeHashtable, &node);\n    PhAddItemList(Context->NodeList, node);\n\n    //if (Context->TreeFilterSupport.FilterList)\n    //   node->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &node->Node);\n\n    if (ParentNode)\n    {\n        node->HasChildren = FALSE;\n\n        // This is a child node.\n        node->Parent = ParentNode;\n        PhAddItemList(ParentNode->Children, node);\n    }\n    else\n    {\n        node->HasChildren = TRUE;\n        node->Node.Expanded = TRUE;\n\n        // This is a root node.\n        PhAddItemList(Context->NodeRootList, node);\n    }\n\n    //TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    return node;\n}\n\nPPHP_PROCESS_ENVIRONMENT_TREENODE PhpFindEnvironmentNode(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ PPH_STRING Name\n    )\n{\n    PHP_PROCESS_ENVIRONMENT_TREENODE lookupEnvironmentNode;\n    PPHP_PROCESS_ENVIRONMENT_TREENODE lookupEnvironmentNodePtr = &lookupEnvironmentNode;\n    PPHP_PROCESS_ENVIRONMENT_TREENODE *environmentNode;\n\n    lookupEnvironmentNode.NameText = Name;\n\n    environmentNode = (PPHP_PROCESS_ENVIRONMENT_TREENODE*)PhFindEntryHashtable(\n        Context->NodeHashtable,\n        &lookupEnvironmentNodePtr\n        );\n\n    if (environmentNode)\n        return *environmentNode;\n    else\n        return NULL;\n}\n\nVOID PhpRemoveEnvironmentNode(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE Node\n    )\n{\n    ULONG index = 0;\n\n    // Remove from hashtable/list and cleanup.\n    PhRemoveEntryHashtable(Context->NodeHashtable, &Node);\n\n    if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX)\n    {\n        PhRemoveItemList(Context->NodeList, index);\n    }\n\n    PhpDestroyEnvironmentNode(Node);\n    //TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhpUpdateEnvironmentNode(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE Node\n    )\n{\n    memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * ENVIRONMENT_COLUMN_ITEM_MAXIMUM);\n\n    PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR);\n    //TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhpExpandAllEnvironmentNodes(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _In_ BOOLEAN Expand\n    )\n{\n    ULONG i;\n    BOOLEAN needsRestructure = FALSE;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MODULE_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Expanded != Expand)\n        {\n            node->Node.Expanded = Expand;\n            needsRestructure = TRUE;\n        }\n    }\n\n    if (needsRestructure)\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\n#define SORT_FUNCTION(Column) PhpEnvironmentTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpEnvironmentTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_ENVIRONMENT_CONTEXT context = (PPH_ENVIRONMENT_CONTEXT)_context; \\\n    PPHP_PROCESS_ENVIRONMENT_TREENODE node1 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE*)_elem1; \\\n    PPHP_PROCESS_ENVIRONMENT_TREENODE node2 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE*)_elem2; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n         sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \\\n    \\\n    return PhModifySort(sortResult, context->TreeNewSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpEnvironmentTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    if (Result == 0)\n        Result = uintcmp(((PPHP_PROCESS_ENVIRONMENT_TREENODE)Node1)->Node.Index, ((PPHP_PROCESS_ENVIRONMENT_TREENODE)Node2)->Node.Index);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->NameText, node2->NameText, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Value)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->ValueText, node2->ValueText, context->TreeNewSortOrder, FALSE);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpEnvironmentTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_ENVIRONMENT_CONTEXT context = Context;\n    PPHP_PROCESS_ENVIRONMENT_TREENODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)getChildren->Node;\n\n            if (context->TreeNewSortOrder == NoSortOrder)\n            {\n                if (!node)\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)context->NodeRootList->Items;\n                    getChildren->NumberOfChildren = context->NodeRootList->Count;\n                }\n                else\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;\n                    getChildren->NumberOfChildren = node->Children->Count;\n                }\n            }\n            else\n            {\n                if (!node)\n                {\n                    static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                    {\n                        SORT_FUNCTION(Name),\n                        SORT_FUNCTION(Value)\n                    };\n                    _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                    static_assert(RTL_NUMBER_OF(sortFunctions) == ENVIRONMENT_COLUMN_ITEM_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                    if (context->TreeNewSortColumn < ENVIRONMENT_COLUMN_ITEM_MAXIMUM)\n                        sortFunction = sortFunctions[context->TreeNewSortColumn];\n                    else\n                        sortFunction = NULL;\n\n                    if (sortFunction)\n                    {\n                        qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                    }\n\n                    getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                    getChildren->NumberOfChildren = context->NodeList->Count;\n                }\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n            node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)isLeaf->Node;\n\n            if (context->TreeNewSortOrder == NoSortOrder)\n                isLeaf->IsLeaf = !node->HasChildren;\n            else\n                isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1;\n            node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case ENVIRONMENT_COLUMN_ITEM_NAME:\n                getCellText->Text = PhGetStringRef(node->NameText);\n                break;\n            case ENVIRONMENT_COLUMN_ITEM_VALUE:\n                getCellText->Text = PhGetStringRef(node->ValueText);\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = (PPH_TREENEW_GET_NODE_COLOR)Parameter1;\n            node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)getNodeColor->Node;\n\n            //if (node->HasChildren)\n            //{\n            //    NOTHING;\n            //}\n            //else\n            {\n                if (context->HighlightCmdEnvironment && node->IsCmdVariable)\n                    getNodeColor->BackColor = PhCsColorDebuggedProcesses;\n                else if (context->HighlightProcessEnvironment && node->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS)\n                    getNodeColor->BackColor = PhCsColorServiceProcesses;\n                else if (context->HighlightUserEnvironment && node->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_USER)\n                    getNodeColor->BackColor = PhCsColorOwnProcesses;\n                else if (context->HighlightSystemEnvironment && node->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM)\n                    getNodeColor->BackColor = PhCsColorSystemProcesses;\n            }\n\n            getNodeColor->Flags = TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // HACK\n            if (context->TreeFilterSupport.FilterList)\n                PhApplyTreeNewFilters(&context->TreeFilterSupport);\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1;\n\n            if (!contextMenuEvent)\n                break;\n\n            PhpShowEnvironmentNodeContextMenu(context, contextMenuEvent);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->WindowHandle, WM_COMMAND, ID_ENV_COPY, 0);\n                break;\n            case VK_DELETE:\n                SendMessage(context->WindowHandle, WM_COMMAND, ID_ENV_DELETE, 0);\n                break;\n            case VK_RETURN:\n                SendMessage(context->WindowHandle, WM_COMMAND, ID_ENV_EDIT, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = 0;\n            data.DefaultSortOrder = NoSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(\n                data.Menu,\n                WindowHandle,\n                PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                data.MouseEvent->ScreenLocation.x,\n                data.MouseEvent->ScreenLocation.y\n                );\n\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            SendMessage(context->WindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, 0); // HACK\n        }\n        return TRUE;\n    case TreeNewGetDialogCode:\n        {\n            PULONG code = Parameter2;\n\n            if (PtrToUlong(Parameter1) == VK_RETURN)\n            {\n                *code = DLGC_WANTMESSAGE;\n                return TRUE;\n            }\n        }\n        return FALSE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpClearEnvironmentTree(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n        PhpDestroyEnvironmentNode(Context->NodeList->Items[i]);\n\n    PhClearHashtable(Context->NodeHashtable);\n    PhClearList(Context->NodeList);\n    PhClearList(Context->NodeRootList);\n\n    PhpClearEnvironmentItems(Context);\n    //TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nPPHP_PROCESS_ENVIRONMENT_TREENODE PhpGetSelectedEnvironmentNode(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context\n    )\n{\n    PPHP_PROCESS_ENVIRONMENT_TREENODE environmentNode = NULL;\n    ULONG i;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        environmentNode = Context->NodeList->Items[i];\n\n        if (environmentNode->Node.Selected)\n            return environmentNode;\n    }\n\n    return NULL;\n}\n\n_Success_(return)\nBOOLEAN PhpGetSelectedEnvironmentNodes(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context,\n    _Out_ PPHP_PROCESS_ENVIRONMENT_TREENODE **Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPHP_PROCESS_ENVIRONMENT_TREENODE node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            PhAddItemList(list, node);\n        }\n    }\n\n    if (list->Count)\n    {\n        *Nodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\nBOOLEAN PhpHasSelectedEnvironmentGroupNode(\n    _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE* Nodes,\n    _In_ ULONG NumberOfNodes\n    )\n{\n    for (ULONG i = 0; i < NumberOfNodes; i++)\n    {\n        if (Nodes[i]->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP)\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpInitializeEnvironmentTree(\n    _Inout_ PPH_ENVIRONMENT_CONTEXT Context\n    )\n{\n    Context->NodeList = PhCreateList(100);\n    Context->NodeRootList = PhCreateList(30);\n    Context->NodeHashtable = PhCreateHashtable(\n        sizeof(PPHP_PROCESS_ENVIRONMENT_TREENODE),\n        PhpEnvironmentNodeHashtableEqualFunction,\n        PhpEnvironmentNodeHashtableHashFunction,\n        100\n        );\n\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n    TreeNew_SetCallback(Context->TreeNewHandle, PhpEnvironmentTreeNewCallback, Context);\n    // Default columns\n    PhAddTreeNewColumn(Context->TreeNewHandle, ENVIRONMENT_COLUMN_ITEM_NAME, TRUE, L\"Name\", 250, PH_ALIGN_LEFT, 0, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, ENVIRONMENT_COLUMN_ITEM_VALUE, TRUE, L\"Value\", 250, PH_ALIGN_LEFT, 1, 0);\n    // Customizable columns\n    // ...\n    // Search filters\n    PhCmInitializeManager(&Context->Cm, Context->TreeNewHandle, PHMOTLC_MAXIMUM, PhpEnvironmentTreeNewPostSortFunction);\n    PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList);\n\n    TreeNew_SetTriState(Context->TreeNewHandle, TRUE);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n}\n\nVOID PhpDeleteEnvironmentTree(\n    _In_ PPH_ENVIRONMENT_CONTEXT Context\n    )\n{\n    PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PhpDestroyEnvironmentNode(Context->NodeList->Items[i]);\n    }\n\n    PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhpProcessEnvironmentTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PVOID Context\n    )\n{\n    PPH_ENVIRONMENT_CONTEXT context = Context;\n    PPHP_PROCESS_ENVIRONMENT_TREENODE environmentNode = (PPHP_PROCESS_ENVIRONMENT_TREENODE)Node;\n\n    if (!environmentNode->Parent && environmentNode->Children && environmentNode->Children->Count == 0)\n        return FALSE;\n    if (context->TreeNewSortOrder != NoSortOrder && environmentNode->HasChildren)\n        return FALSE;\n\n    if (context->HideProcessEnvironment && environmentNode->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS)\n        return FALSE;\n    if (context->HideUserEnvironment && environmentNode->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_USER)\n        return FALSE;\n    if (context->HideSystemEnvironment && environmentNode->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM)\n        return FALSE;\n    if (context->HideCmdTypeEnvironment && environmentNode->IsCmdVariable)\n        return FALSE;\n\n    if (!context->SearchMatchHandle)\n        return TRUE;\n\n    if (!PhIsNullOrEmptyString(environmentNode->NameText))\n    {\n        if (PhSearchControlMatch(context->SearchMatchHandle, &environmentNode->NameText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(environmentNode->ValueText))\n    {\n        if (PhSearchControlMatch(context->SearchMatchHandle, &environmentNode->ValueText->sr))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nstatic VOID NTAPI PhpProcessEnvironmentSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_ENVIRONMENT_CONTEXT context = Context;\n\n    assert(context);\n\n    context->SearchMatchHandle = MatchHandle;\n\n    // Expand any hidden nodes to make search results visible.\n    PhpExpandAllEnvironmentNodes(context, TRUE);\n\n    PhApplyTreeNewFilters(&context->TreeFilterSupport);\n}\n\nINT_PTR CALLBACK PhpProcessEnvironmentDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n    PPH_ENVIRONMENT_CONTEXT context;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &propPageContext, &processItem))\n    {\n        context = propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context = propPageContext->Context = PhAllocateZero(sizeof(PH_ENVIRONMENT_CONTEXT));\n            context->WindowHandle = hwndDlg;\n            context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            context->SearchWindowHandle = GetDlgItem(hwndDlg, IDC_SEARCH);\n            context->ProcessItem = processItem;\n\n            PhCreateSearchControl(\n                hwndDlg,\n                context->SearchWindowHandle,\n                L\"Search Environment (Ctrl+K)\",\n                PhpProcessEnvironmentSearchControlCallback,\n                context\n                );\n\n            Edit_SetSel(context->SearchWindowHandle, 0, -1);\n            PhpInitializeEnvironmentTree(context);\n\n            if (PhTreeWindowFont)\n            {\n                context->TreeNewFont = PhDuplicateFont(PhTreeWindowFont);\n                SetWindowFont(context->TreeNewHandle, context->TreeNewFont, FALSE);\n            }\n\n            PhInitializeArray(&context->Items, sizeof(PH_ENVIRONMENT_ITEM), 100);\n            context->TreeFilterEntry = PhAddTreeNewFilter(&context->TreeFilterSupport, PhpProcessEnvironmentTreeFilterCallback, context);\n\n            PhMoveReference(&context->StatusMessage, PhCreateString(L\"There are no environment variables to display.\"));\n            TreeNew_SetEmptyText(context->TreeNewHandle, &context->StatusMessage->sr, 0);\n            PhLoadSettingsEnvironmentList(context);\n\n            if (processItem->IsSubsystemProcess)\n            {\n                PhpRefreshWslEnvironmentList(context, processItem);\n            }\n            else\n            {\n                PhpRefreshEnvironmentList(context, processItem);\n            }\n\n            PhApplyTreeNewFilters(&context->TreeFilterSupport);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveTreeNewFilter(&context->TreeFilterSupport, context->TreeFilterEntry);\n\n            PhSaveSettingsEnvironmentList(context);\n            PhpDeleteEnvironmentTree(context);\n\n            PhpClearEnvironmentItems(context);\n            PhDeleteArray(&context->Items);\n            PhClearReference(&context->StatusMessage);\n\n            if (context->TreeNewFont)\n                DeleteFont(context->TreeNewFont);\n\n            PhFree(context);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, context->SearchWindowHandle, dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP);\n                PhAddPropPageLayoutItem(hwndDlg, context->TreeNewHandle, dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_OPTIONS:\n                {\n                    RECT rect;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM processMenuItem;\n                    PPH_EMENU_ITEM userMenuItem;\n                    PPH_EMENU_ITEM systemMenuItem;\n                    PPH_EMENU_ITEM cmdMenuItem;\n                    PPH_EMENU_ITEM highlightProcessMenuItem;\n                    PPH_EMENU_ITEM highlightUserMenuItem;\n                    PPH_EMENU_ITEM highlightSystemMenuItem;\n                    PPH_EMENU_ITEM highlightCmdMenuItem;\n                    PPH_EMENU_ITEM newProcessMenuItem;\n                    PPH_EMENU_ITEM selectedItem;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect))\n                        break;\n\n                    processMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_PROCESS_TYPE, L\"Hide process\", NULL, NULL);\n                    userMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_USER_TYPE, L\"Hide user\", NULL, NULL);\n                    systemMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_SYSTEM_TYPE, L\"Hide system\", NULL, NULL);\n                    cmdMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_CMD_TYPE, L\"Hide cmd\", NULL, NULL);\n                    highlightProcessMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_PROCESS_TYPE, L\"Highlight process\", NULL, NULL);\n                    highlightUserMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_USER_TYPE, L\"Highlight user\", NULL, NULL);\n                    highlightSystemMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_SYSTEM_TYPE, L\"Highlight system\", NULL, NULL);\n                    highlightCmdMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_CMD_TYPE, L\"Highlight cmd\", NULL, NULL);\n                    newProcessMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_NEW_ENVIRONMENT_VARIABLE, L\"New variable...\", NULL, NULL);\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, processMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, userMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, systemMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, cmdMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, highlightProcessMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, highlightUserMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, highlightSystemMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, highlightCmdMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, newProcessMenuItem, ULONG_MAX);\n\n                    if (context->HideProcessEnvironment)\n                        processMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HideUserEnvironment)\n                        userMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HideSystemEnvironment)\n                        systemMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HideCmdTypeEnvironment)\n                        cmdMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightProcessEnvironment)\n                        highlightProcessMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightUserEnvironment)\n                        highlightUserMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightSystemEnvironment)\n                        highlightSystemMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightCmdEnvironment)\n                        highlightCmdMenuItem->Flags |= PH_EMENU_CHECKED;\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        rect.left,\n                        rect.bottom\n                        );\n\n                    if (selectedItem && selectedItem->Id)\n                    {\n                        if (selectedItem->Id == ENVIRONMENT_TREE_MENU_ITEM_NEW_ENVIRONMENT_VARIABLE)\n                        {\n                            BOOLEAN refresh;\n\n                            if (PhpShowEditEnvDialog(hwndDlg, processItem, L\"\", NULL, &refresh) == IDOK && refresh)\n                            {\n                                if (processItem->IsSubsystemProcess)\n                                {\n                                    PhpRefreshWslEnvironmentList(context, processItem);\n                                }\n                                else\n                                {\n                                    PhpRefreshEnvironmentList(context, processItem);\n                                }\n                            }\n                        }\n                        else\n                        {\n                            PhSetOptionsEnvironmentList(context, selectedItem->Id);\n                            PhSaveSettingsEnvironmentList(context);\n                            PhApplyTreeNewFilters(&context->TreeFilterSupport);\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            case IDC_REFRESH:\n                {\n                    if (processItem->IsSubsystemProcess)\n                    {\n                        PhpRefreshWslEnvironmentList(context, processItem);\n                    }\n                    else\n                    {\n                        PhpRefreshEnvironmentList(context, processItem);\n                    }\n                }\n                break;\n            case ID_SHOWCONTEXTMENU:\n                {\n                    PPHP_PROCESS_ENVIRONMENT_TREENODE item = PhpGetSelectedEnvironmentNode(context);\n                    BOOLEAN refresh;\n\n                    if (!item || item->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP)\n                        break;\n\n                    if (PhpShowEditEnvDialog(\n                        hwndDlg,\n                        context->ProcessItem,\n                        item->NameText->Buffer,\n                        item->ValueText->Buffer,\n                        &refresh\n                        ) == IDOK && refresh)\n                    {\n                        if (processItem->IsSubsystemProcess)\n                        {\n                            PhpRefreshWslEnvironmentList(context, processItem);\n                        }\n                        else\n                        {\n                            PhpRefreshEnvironmentList(context, processItem);\n                        }\n                    }\n                }\n                break;\n            case ID_ENV_EDIT:\n                {\n                    PPHP_PROCESS_ENVIRONMENT_TREENODE item = PhpGetSelectedEnvironmentNode(context);\n                    BOOLEAN refresh;\n\n                    if (!item || item->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP)\n                        break;\n\n                    if (PhpShowEditEnvDialog(\n                        context->WindowHandle,\n                        context->ProcessItem,\n                        item->NameText->Buffer,\n                        item->ValueText->Buffer,\n                        &refresh\n                        ) == IDOK && refresh)\n                    {\n                        if (processItem->IsSubsystemProcess)\n                        {\n                            PhpRefreshWslEnvironmentList(context, processItem);\n                        }\n                        else\n                        {\n                            PhpRefreshEnvironmentList(context, processItem);\n                        }\n                    }\n                }\n                break;\n            case ID_ENV_DELETE:\n                {\n                    PPHP_PROCESS_ENVIRONMENT_TREENODE item = PhpGetSelectedEnvironmentNode(context);\n                    NTSTATUS status = STATUS_UNSUCCESSFUL;\n\n                    if (!item || item->Type & PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP)\n                        break;\n\n                    if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) && !PhShowConfirmMessage(\n                        context->WindowHandle,\n                        L\"delete\",\n                        L\"the selected environment variable\",\n                        L\"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.\",\n                        FALSE\n                        ))\n                    {\n                        break;\n                    }\n\n                    status = PhpEditDeleteEnvironment(\n                        context,\n                        context->ProcessItem,\n                        item->NameText\n                        );\n\n                    if (processItem->IsSubsystemProcess)\n                    {\n                        PhpRefreshWslEnvironmentList(context, processItem);\n                    }\n                    else\n                    {\n                        PhpRefreshEnvironmentList(context, processItem);\n                    }\n\n                    if (status == STATUS_TIMEOUT)\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to delete the environment variable.\", 0, WAIT_TIMEOUT);\n                    }\n                    else if (!NT_SUCCESS(status))\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to delete the environment variable.\", status, 0);\n                    }\n                }\n                break;\n            case ID_ENV_COPY:\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(context->TreeNewHandle, 0);\n                    PhSetClipboardString(context->TreeNewHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)context->TreeNewHandle);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            if (LOWORD(wParam) == 'K')\n            {\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    SetFocus(context->SearchWindowHandle);\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpggen.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2016-2023\n *\n */\n\n#include <phapp.h>\n#include <procprp.h>\n#include <procprpp.h>\n#include <phconsole.h>\n\n#include <emenu.h>\n#include <mapimg.h>\n#include <secedit.h>\n#include <verify.h>\n\n#include <actions.h>\n#include <mainwnd.h>\n#include <phsettings.h>\n#include <procmtgn.h>\n#include <procprv.h>\n#include <settings.h>\n\nstatic CONST PH_KEY_VALUE_PAIR PhProtectedTypeStrings[] =\n{\n    SIP(L\"None\", PsProtectedTypeNone),\n    SIP(L\"Light\", PsProtectedTypeProtectedLight),\n    SIP(L\"Full\", PsProtectedTypeProtected),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR PhProtectedSignerStrings[] =\n{\n    SIP(L\" \", PsProtectedSignerNone),\n    SIP(L\" (Authenticode)\", PsProtectedSignerAuthenticode),\n    SIP(L\" (CodeGen)\", PsProtectedSignerCodeGen),\n    SIP(L\" (Antimalware)\", PsProtectedSignerAntimalware),\n    SIP(L\" (Lsa)\", PsProtectedSignerLsa),\n    SIP(L\" (Windows)\", PsProtectedSignerWindows),\n    SIP(L\" (WinTcb)\", PsProtectedSignerWinTcb),\n    SIP(L\" (WinSystem)\", PsProtectedSignerWinSystem),\n    SIP(L\" (StoreApp)\", PsProtectedSignerApp),\n};\n\nPPH_STRING PhGetProcessItemProtectionText(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    if (ProcessItem->Protection.Level != UCHAR_MAX)\n    {\n        if (WindowsVersion >= WINDOWS_8_1)\n        {\n            PWSTR type = L\"Unknown\";\n            PWSTR signer = L\"\";\n\n            PhFindStringSiKeyValuePairs(PhProtectedTypeStrings, sizeof(PhProtectedTypeStrings), ProcessItem->Protection.Type, &type);\n            PhFindStringSiKeyValuePairs(PhProtectedSignerStrings, sizeof(PhProtectedSignerStrings), ProcessItem->Protection.Signer, &signer);\n\n            // Isolated User Mode (IUM) (dmex)\n            if (ProcessItem->Protection.Type == PsProtectedTypeNone && ProcessItem->IsSecureProcess)\n                return PhConcatStrings2(L\"Secure (IUM)\", signer);\n\n            return PhConcatStrings2(type, signer);\n        }\n        else\n        {\n            if (ProcessItem->IsSecureProcess)\n                return PhCreateString(L\"Secure (IUM)\");\n\n            if (ProcessItem->IsProtectedProcess)\n                return PhCreateString(L\"Yes\");\n\n            return PhCreateString(L\"None\");\n        }\n    }\n\n    return PhCreateString(L\"N/A\");\n}\n\nPPH_STRING PhGetProcessItemImageTypeText(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    USHORT architecture = IMAGE_FILE_MACHINE_UNKNOWN;\n    ULONG chpeVersion = 0;\n    PWSTR arch = L\"\";\n    PWSTR bits = L\"\";\n\n    if (ProcessItem->FileName)\n    {\n        PH_MAPPED_IMAGE mappedImage;\n\n#ifdef _ARM64_\n        if (NT_SUCCESS(PhLoadMappedImageEx(&ProcessItem->FileName->sr, NULL, &mappedImage)))\n        {\n            architecture = mappedImage.NtHeaders->FileHeader.Machine;\n            if (architecture == IMAGE_FILE_MACHINE_AMD64 || architecture == IMAGE_FILE_MACHINE_ARM64)\n                chpeVersion = PhGetMappedImageCHPEVersion(&mappedImage);\n            PhUnloadMappedImage(&mappedImage);\n        }\n#else\n        if (NT_SUCCESS(PhLoadMappedImageHeaderPageSize(&ProcessItem->FileName->sr, NULL, &mappedImage)))\n        {\n            architecture = mappedImage.NtHeaders->FileHeader.Machine;\n            PhUnloadMappedImage(&mappedImage);\n        }\n#endif\n    }\n\n    switch (architecture)\n    {\n    case IMAGE_FILE_MACHINE_I386:\n        arch = L\"i386 \";\n        break;\n    case IMAGE_FILE_MACHINE_AMD64:\n        arch = chpeVersion ? L\"AMD64 (ARM64X) \" : L\"AMD64 \";\n        break;\n    case IMAGE_FILE_MACHINE_ARMNT:\n        arch = L\"ARM \";\n        break;\n    case IMAGE_FILE_MACHINE_ARM64:\n        arch = chpeVersion ? L\"ARM64 (ARM64X) \" : L\"ARM64 \";\n        break;\n    default:\n        arch = L\"N/A \";\n    }\n\n#if _WIN64\n    bits = ProcessItem->IsWow64Process ? L\"(32-bit)\" : L\"(64-bit)\";\n#else\n    bits = L\"(32-bit)\";\n#endif\n\n    return PhConcatStrings2(arch, bits);\n}\n\n_Function_class_(PH_OPEN_OBJECT)\nNTSTATUS PhpProcessGeneralOpenProcess(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Context)\n        return PhOpenProcess(Handle, DesiredAccess, (HANDLE)Context);\n    return STATUS_UNSUCCESSFUL;\n}\n\n_Function_class_(PH_CLOSE_OBJECT)\nNTSTATUS PhpProcessGeneralCloseHandle(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle)\n        NtClose(Handle);\n    return STATUS_SUCCESS;\n}\n\nFORCEINLINE PWSTR PhpGetStringOrNa(\n    _In_opt_ _Maybenull_ PPH_STRING String\n    )\n{\n    if (String)\n        return String->Buffer;\n    else\n        return L\"N/A\";\n}\n\nVOID PhpUpdateProcessMitigationPolicies(\n    _In_ HWND hwndDlg,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION information;\n\n    PhSetDialogItemText(hwndDlg, IDC_MITIGATION, L\"N/A\");\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION,\n        ProcessItem->ProcessId\n        )))\n    {\n        if (NT_SUCCESS(status = PhGetProcessMitigationPolicyAllInformation(processHandle, &information)))\n        {\n            PH_STRING_BUILDER sb;\n            PROCESS_MITIGATION_POLICY policy;\n            PPH_STRING shortDescription;\n\n            PhInitializeStringBuilder(&sb, 100);\n\n            for (policy = 0; policy < MaxProcessMitigationPolicy; policy++)\n            {\n                if (information.Pointers[policy] && PhDescribeProcessMitigationPolicy(\n                    policy,\n                    information.Pointers[policy],\n                    &shortDescription,\n                    NULL\n                    ))\n                {\n                    PhAppendStringBuilder(&sb, &shortDescription->sr);\n                    PhAppendStringBuilder2(&sb, L\"; \");\n                    PhDereferenceObject(shortDescription);\n                }\n            }\n\n            // HACK: Show System process CET mitigation (dmex)\n            if (ProcessItem->ProcessId == SYSTEM_PROCESS_ID)\n            {\n                SYSTEM_SHADOW_STACK_INFORMATION shadowStackInformation;\n\n                if (NT_SUCCESS(PhGetSystemShadowStackInformation(&shadowStackInformation)))\n                {\n                    PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policyData;\n\n                    memset(&policyData, 0, sizeof(PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY));\n                    policyData.EnableUserShadowStack = shadowStackInformation.KernelCetEnabled;\n                    policyData.EnableUserShadowStackStrictMode = shadowStackInformation.KernelCetEnabled;\n                    policyData.AuditUserShadowStack = shadowStackInformation.KernelCetAuditModeEnabled;\n\n                    if (PhDescribeProcessMitigationPolicy(\n                        ProcessUserShadowStackPolicy,\n                        &policyData,\n                        &shortDescription,\n                        NULL\n                        ))\n                    {\n                        PhAppendStringBuilder(&sb, &shortDescription->sr);\n                        PhAppendStringBuilder2(&sb, L\"; \");\n                        PhDereferenceObject(shortDescription);\n                    }\n                }\n            }\n\n            if (sb.String->Length != 0)\n            {\n                PhRemoveEndStringBuilder(&sb, 2);\n                PhSetDialogItemText(hwndDlg, IDC_MITIGATION, PhFinalStringBuilderString(&sb)->Buffer);\n            }\n            else\n            {\n                PhSetDialogItemText(hwndDlg, IDC_MITIGATION, L\"None\");\n            }\n\n            PhDeleteStringBuilder(&sb);\n        }\n\n        NtClose(processHandle);\n    }\n\n    if (!NT_SUCCESS(status))\n        EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWMITIGATION), FALSE);\n}\n\ntypedef struct _PH_PROCGENERAL_CONTEXT\n{\n    HWND WindowHandle;\n    HWND StartedLabelHandle;\n    BOOLEAN Enabled;\n    HICON ProgramIcon;\n} PH_PROCGENERAL_CONTEXT, *PPH_PROCGENERAL_CONTEXT;\n\nVOID PphProcessGeneralDlgUpdateIcons(\n    _In_ HWND hwndDlg\n    )\n{\n    HICON folder;\n    HICON magnifier;\n    LONG dpiValue;\n\n    dpiValue = PhGetWindowDpi(hwndDlg);\n\n    folder = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_FOLDER), dpiValue);\n    magnifier = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_MAGNIFIER), dpiValue);\n\n    SET_BUTTON_ICON(IDC_INSPECT, magnifier);\n    SET_BUTTON_ICON(IDC_OPENFILENAME, folder);\n    SET_BUTTON_ICON(IDC_INSPECT2, magnifier);\n    SET_BUTTON_ICON(IDC_OPENFILENAME2, folder);\n    SET_BUTTON_ICON(IDC_VIEWCOMMANDLINE, magnifier);\n    SET_BUTTON_ICON(IDC_VIEWPARENTPROCESS, magnifier);\n}\n\nINT_PTR CALLBACK PhpProcessGeneralDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    LPPROPSHEETPAGE propSheetPage;\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n    PPH_PROCGENERAL_CONTEXT context;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))\n    {\n        context = (PPH_PROCGENERAL_CONTEXT)propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HANDLE processHandle = NULL;\n            PPH_STRING curDir = NULL;\n            PPH_PROCESS_ITEM parentProcess;\n            CLIENT_ID clientId;\n            PPH_STRING fileNameWin32 = NULL;\n\n            context = propPageContext->Context = PhAllocateZero(sizeof(PH_PROCGENERAL_CONTEXT));\n            context->WindowHandle = hwndDlg;\n            context->StartedLabelHandle = GetDlgItem(hwndDlg, IDC_STARTED);\n            context->Enabled = TRUE;\n\n            PphProcessGeneralDlgUpdateIcons(hwndDlg);\n\n            // File\n\n            context->ProgramIcon = PhGetImageListIcon(processItem->LargeIconIndex, TRUE);\n            Static_SetIcon(GetDlgItem(hwndDlg, IDC_FILEICON), context->ProgramIcon);\n\n            if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId))\n            {\n                PhSetDialogItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(processItem->VersionInfo.FileDescription));\n            }\n            else\n            {\n                PhSetDialogItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(processItem->ProcessName));\n            }\n\n            if (processItem->QueryHandle)\n            {\n                if (NT_SUCCESS(PhGetProcessImageFileNameWin32(processItem->QueryHandle, &fileNameWin32)))\n                {\n                    PH_AUTO(fileNameWin32);\n                }\n            }\n\n            if (PhIsNullOrEmptyString(fileNameWin32))\n            {\n                fileNameWin32 = processItem->FileName ? PhGetFileName(processItem->FileName) : NULL;\n                PH_AUTO(fileNameWin32);\n            }\n\n            PhSetDialogItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(processItem->VersionInfo.FileVersion));\n            PhSetDialogItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(fileNameWin32));\n            PhSetDialogItemText(hwndDlg, IDC_FILENAMEWIN32, PhpGetStringOrNa(processItem->FileName));\n\n            {\n                PPH_STRING inspectExecutables;\n\n                if (PhIsNullOrEmptyString(processItem->FileName))\n                {\n                    EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE);\n                    EnableWindow(GetDlgItem(hwndDlg, IDC_INSPECT), FALSE);\n                }\n                else\n                {\n                    if (!PhDoesFileExist(&processItem->FileName->sr))\n                    {\n                        EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE);\n                        EnableWindow(GetDlgItem(hwndDlg, IDC_INSPECT), FALSE);\n                    }\n                }\n\n                inspectExecutables = PhaGetStringSetting(SETTING_PROGRAM_INSPECT_EXECUTABLES);\n\n                if (PhIsNullOrEmptyString(inspectExecutables))\n                {\n                    EnableWindow(GetDlgItem(hwndDlg, IDC_INSPECT), FALSE);\n                }\n            }\n\n            if (processItem->VerifyResult == VrTrusted)\n            {\n                if (processItem->VerifySignerName)\n                {\n                    PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME_LINK,\n                        PhaFormatString(L\"<a>(Verified) %s</a>\", processItem->VerifySignerName->Buffer)->Buffer);\n                    ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME), SW_HIDE);\n                    ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), SW_SHOW);\n                }\n                else\n                {\n                    PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME,\n                        PhaConcatStrings2(\n                        L\"(Verified) \",\n                        PhGetStringOrEmpty(processItem->VersionInfo.CompanyName)\n                        )->Buffer);\n                }\n            }\n            else if (processItem->VerifyResult != VrUnknown)\n            {\n                PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME,\n                    PhaConcatStrings2(\n                    L\"(UNVERIFIED) \",\n                    PhGetStringOrEmpty(processItem->VersionInfo.CompanyName)\n                    )->Buffer);\n            }\n            else\n            {\n                PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME,\n                    PhpGetStringOrNa(processItem->VersionInfo.CompanyName));\n            }\n\n            // Command Line\n\n            PhSetDialogItemText(hwndDlg, IDC_CMDLINE, PhpGetStringOrNa(processItem->CommandLine));\n\n            if (!processItem->CommandLine)\n                EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWCOMMANDLINE), FALSE);\n\n            // Current Directory\n\n            if (NT_SUCCESS(PhOpenProcess(\n                &processHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n                processItem->ProcessId\n                )))\n            {\n                // Tell the function to get the WOW64 current directory, because that's the one that actually gets updated.\n                if (NT_SUCCESS(PhGetProcessCurrentDirectory(\n                    processHandle,\n                    !!processItem->IsWow64Process,\n                    &curDir\n                    )))\n                {\n                    PH_AUTO(curDir);\n                }\n\n                NtClose(processHandle);\n                processHandle = NULL;\n            }\n\n            PhSetDialogItemText(hwndDlg, IDC_CURDIR, PhpGetStringOrNa(curDir));\n\n            // Started\n\n            if (processItem->CreateTime.QuadPart != 0)\n            {\n                LARGE_INTEGER startTime;\n                LARGE_INTEGER currentTime;\n                SYSTEMTIME startTimeFields;\n                PPH_STRING startTimeRelativeString;\n                PPH_STRING startTimeString;\n\n                PhQuerySystemTime(&currentTime);\n\n                if (processItem->CreateTime.QuadPart < currentTime.QuadPart)\n                {\n                    startTime = processItem->CreateTime;\n                    startTimeRelativeString = PH_AUTO(PhFormatTimeSpanRelative(currentTime.QuadPart - startTime.QuadPart));\n\n                    PhLargeIntegerToLocalSystemTime(&startTimeFields, &startTime);\n                    startTimeString = PhaFormatDateTime(&startTimeFields);\n\n                    PhSetWindowText(context->StartedLabelHandle, PhaFormatString(\n                        L\"%s ago (%s)\",\n                        startTimeRelativeString->Buffer,\n                        startTimeString->Buffer\n                        )->Buffer);\n                }\n                else\n                {\n                    PhSetWindowText(context->StartedLabelHandle, L\"N/A\");\n                }\n            }\n            else\n            {\n                PhSetWindowText(context->StartedLabelHandle, L\"N/A\");\n            }\n\n            // Parent\n\n            if (parentProcess = PhReferenceProcessItemForParent(processItem))\n            {\n                clientId.UniqueProcess = parentProcess->ProcessId;\n                clientId.UniqueThread = NULL;\n\n                PhSetDialogItemText(hwndDlg, IDC_PARENTPROCESS,\n                    PH_AUTO_T(PH_STRING, PhGetClientIdNameEx(&clientId, parentProcess->ProcessName))->Buffer);\n\n                PhDereferenceObject(parentProcess);\n            }\n            else\n            {\n                if (processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n                {\n                    PhSetDialogItemText(hwndDlg, IDC_PARENTPROCESS, L\"N/A\");\n                }\n                else\n                {\n                    PhSetDialogItemText(hwndDlg, IDC_PARENTPROCESS, PhaFormatString(\n                        L\"Non-existent process (%lu)\", HandleToUlong(processItem->ParentProcessId))->Buffer);\n                }\n\n                EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWPARENTPROCESS), FALSE);\n            }\n\n            // Parent console\n\n            //if (NT_SUCCESS(PhGetProcessConsoleHostProcessId(processItem->QueryHandle, &consoleParentProcessId)))\n            //{\n            //    ProcessItem->ParentProcessId = consoleParentProcessId;\n            //    PhPrintUInt32(ProcessItem->ParentProcessIdString, HandleToUlong(consoleParentProcessId));\n            //}\n\n            if (parentProcess = PhReferenceProcessItem((HANDLE)((ULONG_PTR)processItem->ConsoleHostProcessId & ~3)))\n            {\n                if (parentProcess->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n                {\n                    PhSetDialogItemText(hwndDlg, IDC_PARENTCONSOLE, L\"N/A\");\n                }\n                else\n                {\n                    clientId.UniqueProcess = parentProcess->ProcessId;\n                    clientId.UniqueThread = NULL;\n\n                    PhSetDialogItemText(\n                        hwndDlg,\n                        IDC_PARENTCONSOLE,\n                        PH_AUTO_T(PH_STRING, PhGetClientIdNameEx(&clientId, parentProcess->ProcessName))->Buffer\n                        );\n                }\n\n                PhDereferenceObject(parentProcess);\n            }\n            else\n            {\n                PhSetDialogItemText(hwndDlg, IDC_PARENTCONSOLE, L\"N/A\");\n            }\n\n            // Mitigation policies\n\n            PhpUpdateProcessMitigationPolicies(hwndDlg, processItem);\n\n            // Protection\n\n            PPH_STRING string = PhGetProcessProtectionString(processItem->Protection, (BOOLEAN)processItem->IsSecureProcess);\n            PhSetDialogItemText(hwndDlg, IDC_PROTECTION, PhpGetStringOrNa(string));\n            PhClearReference(&string);\n\n            // Image type\n\n            PhSetDialogItemText(hwndDlg, IDC_PROCESSTYPETEXT, PH_AUTO_T(PH_STRING, PhGetProcessItemImageTypeText(processItem))->Buffer);\n\n            if (PhEnableThemeSupport)\n            {\n                PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n            }\n\n            PhSetTimer(hwndDlg, PH_WINDOW_TIMER_DEFAULT, 1000, NULL);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhKillTimer(hwndDlg, PH_WINDOW_TIMER_DEFAULT);\n\n            if (context->ProgramIcon)\n            {\n                DestroyIcon(context->ProgramIcon);\n            }\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            PhFree(context);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            PphProcessGeneralDlgUpdateIcons(hwndDlg);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VERSION), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILENAME), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSPECT), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENFILENAME), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILENAMEWIN32), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSPECT2), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENFILENAME2), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CMDLINE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWCOMMANDLINE), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CURDIR), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, context->StartedLabelHandle, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PARENTCONSOLE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PARENTPROCESS), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWPARENTPROCESS), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_MITIGATION), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWMITIGATION), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_TERMINATE), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PERMISSIONS), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESS), dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_INSPECT:\n            case IDC_INSPECT2:\n                {\n                    if (processItem->FileName)\n                    {\n                        if (\n                            !PhIsNullOrEmptyString(processItem->FileName) &&\n                            PhDoesFileExist(&processItem->FileName->sr)\n                            )\n                        {\n                            PhShellExecuteUserString(\n                                hwndDlg,\n                                SETTING_PROGRAM_INSPECT_EXECUTABLES,\n                                PhGetString(processItem->FileName),\n                                FALSE,\n                                L\"Make sure the PE Viewer executable file is present.\"\n                                );\n                        }\n                        else\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to locate the file.\", STATUS_NOT_FOUND, 0);\n                        }\n                    }\n                }\n                break;\n            case IDC_OPENFILENAME:\n            case IDC_OPENFILENAME2:\n                {\n                    if (processItem->FileName)\n                    {\n                        if (\n                            !PhIsNullOrEmptyString(processItem->FileName) &&\n                            PhDoesFileExist(&processItem->FileName->sr)\n                            )\n                        {\n                            PhShellExecuteUserString(\n                                hwndDlg,\n                                SETTING_FILE_BROWSE_EXECUTABLE,\n                                PhGetString(processItem->FileName),\n                                FALSE,\n                                L\"Make sure the Explorer executable file is present.\"\n                                );\n                        }\n                        else\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to locate the file.\", STATUS_NOT_FOUND, 0);\n                        }\n                    }\n                }\n                break;\n            case IDC_VIEWCOMMANDLINE:\n                {\n                    if (processItem->CommandLine)\n                    {\n                        PPH_STRING commandLineString;\n                        PPH_LIST commandLineList;\n\n                        if (commandLineList = PhCommandLineToList(PhGetString(processItem->CommandLine)))\n                        {\n                            PH_STRING_BUILDER sb;\n\n                            PhInitializeStringBuilder(&sb, 260);\n\n                            for (ULONG i = 0; i < commandLineList->Count; i++)\n                            {\n                                PhAppendFormatStringBuilder(&sb, L\"[%d] %s\\r\\n\\r\\n\", i, PhGetString(commandLineList->Items[i]));\n                            }\n\n                            PhAppendFormatStringBuilder(&sb, L\"[FULL] %s\\r\\n\", PhGetString(processItem->CommandLine));\n\n                            commandLineString = PhFinalStringBuilderString(&sb);\n\n                            PhDereferenceObjects(commandLineList->Items, commandLineList->Count);\n                            PhDereferenceObject(commandLineList);\n                        }\n                        else\n                        {\n                            commandLineString = PhReferenceObject(processItem->CommandLine);\n                        }\n\n                        PhShowInformationDialog(hwndDlg, PhGetString(commandLineString), 0);\n\n                        PhDereferenceObject(commandLineString);\n                    }\n                }\n                break;\n            case IDC_VIEWPARENTPROCESS:\n                {\n                    PPH_PROCESS_ITEM parentProcessItem;\n\n                    if (parentProcessItem = PhReferenceProcessItem(processItem->ParentProcessId))\n                    {\n                        SystemInformer_ShowProcessProperties(parentProcessItem);\n                        PhDereferenceObject(parentProcessItem);\n                    }\n                    else\n                    {\n                        PhShowStatus(hwndDlg, L\"The process does not exist.\", STATUS_NOT_FOUND, 0);\n                    }\n                }\n                break;\n            case IDC_VIEWMITIGATION:\n                {\n                    PhShowProcessMitigationPolicyDialog(hwndDlg, processItem->ProcessId);\n                }\n                break;\n            case IDC_TERMINATE:\n                {\n                    PhUiTerminateProcesses(\n                        hwndDlg,\n                        &processItem,\n                        1\n                        );\n                }\n                break;\n            case IDC_PERMISSIONS:\n                {\n                    PhEditSecurity(\n                        PhCsForceNoParent ? NULL : hwndDlg,\n                        PhGetStringOrEmpty(processItem->ProcessName),\n                        L\"Process\",\n                        PhpProcessGeneralOpenProcess,\n                        PhpProcessGeneralCloseHandle,\n                        processItem->ProcessId\n                        );\n                }\n                break;\n            case IDC_INTEGRITY:\n                {\n                    NTSTATUS status;\n                    HANDLE processHandle = NULL;\n                    ACCESS_MASK mandatoryPolicy = 0;\n                    PPH_EMENU_ITEM selectedItem;\n                    PPH_EMENU menu;\n                    RECT rect;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_INTEGRITY), &rect))\n                        break;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L\"No-Write-Up\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 2, L\"No-Read-Up\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 3, L\"No-Execute-Up\", NULL, NULL), ULONG_MAX);\n\n                    status = PhOpenProcess(\n                        &processHandle,\n                        READ_CONTROL | WRITE_OWNER,\n                        processItem->ProcessId\n                        );\n\n                    if (!NT_SUCCESS(status))\n                    {\n                        status = PhOpenProcess(\n                            &processHandle,\n                            READ_CONTROL,\n                            processItem->ProcessId\n                            );\n                    }\n\n                    if (NT_SUCCESS(status))\n                    {\n                        status = PhGetProcessMandatoryPolicy(processHandle, &mandatoryPolicy);\n\n                        if (NT_SUCCESS(status))\n                        {\n                            if (FlagOn(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP))\n                            {\n                                PhSetFlagsEMenuItem(menu, 1, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n                            }\n\n                            if (FlagOn(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_READ_UP))\n                            {\n                                PhSetFlagsEMenuItem(menu, 2, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n                            }\n\n                            if (FlagOn(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP))\n                            {\n                                PhSetFlagsEMenuItem(menu, 3, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n                            }\n                        }\n                    }\n\n                    if (!NT_SUCCESS(status))\n                    {\n                        for (ULONG i = 0; i < menu->Items->Count; i++)\n                        {\n                            PhSetDisabledEMenuItem(menu->Items->Items[i]);\n                        }\n                    }\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        rect.left,\n                        rect.bottom\n                        );\n\n                    if (selectedItem && selectedItem->Id != ULONG_MAX)\n                    {\n                        if (PhShowConfirmMessage(\n                            hwndDlg,\n                            L\"update\",\n                            L\"the integrity label\",\n                            L\"Altering the integrity label for a process may produce undesirable results, instability or data corruption.\",\n                            FALSE\n                            ))\n                        {\n                            switch (selectedItem->Id)\n                            {\n                            case 1:\n                                {\n                                    if (BooleanFlagOn(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP))\n                                        ClearFlag(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP);\n                                    else\n                                        SetFlag(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP);\n\n                                    status = PhSetProcessMandatoryPolicy(processHandle, mandatoryPolicy);\n                                }\n                                break;\n                            case 2:\n                                {\n                                    if (BooleanFlagOn(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_READ_UP))\n                                        ClearFlag(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_READ_UP);\n                                    else\n                                        SetFlag(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_READ_UP);\n\n                                    status = PhSetProcessMandatoryPolicy(processHandle, mandatoryPolicy);\n                                }\n                                break;\n                            case 3:\n                                {\n                                    if (BooleanFlagOn(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP))\n                                        ClearFlag(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP);\n                                    else\n                                        SetFlag(mandatoryPolicy, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP);\n\n                                    status = PhSetProcessMandatoryPolicy(processHandle, mandatoryPolicy);\n                                }\n                                break;\n                            }\n                        }\n\n                        if (!NT_SUCCESS(status))\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to set the integrity label\", status, 0);\n                        }\n                    }\n\n                    if (processHandle)\n                    {\n                        NtClose(processHandle);\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_SETACTIVE:\n                context->Enabled = TRUE;\n                break;\n            case PSN_KILLACTIVE:\n                context->Enabled = FALSE;\n                break;\n            case NM_CLICK:\n                {\n                    switch (header->idFrom)\n                    {\n                    case IDC_COMPANYNAME_LINK:\n                        {\n                            if (processItem->FileName)\n                            {\n                                NTSTATUS status;\n                                HANDLE fileHandle;\n\n                                status = PhCreateFile(\n                                    &fileHandle,\n                                    &processItem->FileName->sr,\n                                    FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n                                    FILE_ATTRIBUTE_NORMAL,\n                                    FILE_SHARE_READ | FILE_SHARE_DELETE,\n                                    FILE_OPEN,\n                                    FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n                                    );\n\n                                if (NT_SUCCESS(status))\n                                {\n                                    PH_VERIFY_FILE_INFO info;\n\n                                    memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO));\n                                    info.FileHandle = fileHandle;\n                                    info.Flags = PH_VERIFY_VIEW_PROPERTIES;\n                                    info.hWnd = hwndDlg;\n                                    PhVerifyFileWithAdditionalCatalog(\n                                        &info,\n                                        processItem->PackageFullName,\n                                        NULL\n                                        );\n\n                                    NtClose(fileHandle);\n                                }\n                                else\n                                {\n                                    PhShowStatus(hwndDlg, L\"Unable to perform the operation.\", status, 0);\n                                }\n                            }\n                        }\n                        break;\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_TIMER:\n        {\n            switch (wParam)\n            {\n            case PH_WINDOW_TIMER_DEFAULT:\n                {\n                    if (!(context->Enabled && GetFocus() != context->StartedLabelHandle))\n                        break;\n\n                    if (processItem->CreateTime.QuadPart != 0)\n                    {\n                        LARGE_INTEGER startTime;\n                        LARGE_INTEGER currentTime;\n                        SYSTEMTIME startTimeFields;\n                        PPH_STRING startTimeRelativeString;\n                        PPH_STRING startTimeString;\n\n                        PhQuerySystemTime(&currentTime);\n\n                        if (processItem->CreateTime.QuadPart < currentTime.QuadPart)\n                        {\n                            startTime = processItem->CreateTime;\n                            startTimeRelativeString = PH_AUTO(PhFormatTimeSpanRelative(currentTime.QuadPart - startTime.QuadPart));\n                            PhLargeIntegerToLocalSystemTime(&startTimeFields, &startTime);\n                            startTimeString = PhaFormatDateTime(&startTimeFields);\n\n                            PhSetWindowText(context->StartedLabelHandle, PhaFormatString(\n                                L\"%s ago (%s)\",\n                                PhGetString(startTimeRelativeString),\n                                PhGetString(startTimeString)\n                                )->Buffer);\n                        }\n                        else\n                        {\n                            PhSetWindowText(context->StartedLabelHandle, L\"\\u221E\");\n                        }\n                    }\n                    else\n                    {\n                        PhSetWindowText(context->StartedLabelHandle, L\"N/A\");\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpghndl.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <procprp.h>\n#include <procprpp.h>\n\n#include <cpysave.h>\n#include <emenu.h>\n#include <hndlinfo.h>\n#include <kphuser.h>\n#include <settings.h>\n\n#include <actions.h>\n#include <extmgri.h>\n#include <hndlmenu.h>\n#include <hndlprv.h>\n#include <mainwnd.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <procprv.h>\n#include <proctree.h>\n#include <secedit.h>\n\nstatic CONST PH_STRINGREF EmptyHandlesText = PH_STRINGREF_INIT(L\"There are no handles to display.\");\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI HandleAddedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;\n\n    // Parameter contains a pointer to the added handle item.\n    PhReferenceObject(Parameter);\n    PhPushProviderEventQueue(&handlesContext->EventQueue, ProviderAddedEvent, Parameter, PhGetRunIdProvider(&handlesContext->ProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI HandleModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;\n\n    PhPushProviderEventQueue(&handlesContext->EventQueue, ProviderModifiedEvent, Parameter, PhGetRunIdProvider(&handlesContext->ProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI HandleRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;\n\n    PhPushProviderEventQueue(&handlesContext->EventQueue, ProviderRemovedEvent, Parameter, PhGetRunIdProvider(&handlesContext->ProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI HandlesUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;\n\n    PostMessage(handlesContext->WindowHandle, WM_PH_HANDLES_UPDATED, PhGetRunIdProvider(&handlesContext->ProviderRegistration), 0);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI HandlesUpdateAutomaticallyHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;\n\n    PhSetEnabledProvider(&handlesContext->ProviderRegistration, (BOOLEAN)PtrToUlong(Parameter));\n}\n\nVOID PhpInitializeHandleMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_HANDLE_ITEM *Handles,\n    _In_ ULONG NumberOfHandles,\n    _Inout_ PPH_HANDLES_CONTEXT HandlesContext\n    )\n{\n    if (NumberOfHandles == 0)\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n    }\n    else if (NumberOfHandles == 1)\n    {\n        PH_HANDLE_ITEM_INFO info;\n\n        info.ProcessId = ProcessId;\n        info.Handle = Handles[0]->Handle;\n        info.TypeName = Handles[0]->TypeName;\n        info.BestObjectName = Handles[0]->BestObjectName;\n        PhInsertHandleObjectPropertiesEMenuItems(Menu, ID_HANDLE_PROPERTIES, TRUE, &info);\n    }\n    else\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n\n        PhEnableEMenuItem(Menu, ID_HANDLE_CLOSE, TRUE);\n        PhEnableEMenuItem(Menu, ID_HANDLE_COPY, TRUE);\n    }\n\n    // Protected, Inherit\n    if (NumberOfHandles == 1)\n    {\n        HandlesContext->SelectedHandleProtected = FALSE;\n        HandlesContext->SelectedHandleInherit = FALSE;\n\n        if (Handles[0]->Attributes & OBJ_PROTECT_CLOSE)\n        {\n            HandlesContext->SelectedHandleProtected = TRUE;\n            PhSetFlagsEMenuItem(Menu, ID_HANDLE_PROTECTED, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n        }\n\n        if (Handles[0]->Attributes & OBJ_INHERIT)\n        {\n            HandlesContext->SelectedHandleInherit = TRUE;\n            PhSetFlagsEMenuItem(Menu, ID_HANDLE_INHERIT, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n        }\n    }\n}\n\nVOID PhShowHandleContextMenu(\n    _In_ HWND hwndDlg,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_HANDLES_CONTEXT Context,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    )\n{\n    PPH_HANDLE_ITEM *handles;\n    ULONG numberOfHandles;\n\n    PhGetSelectedHandleItems(&Context->ListContext, &handles, &numberOfHandles);\n\n    if (numberOfHandles != 0)\n    {\n        PPH_EMENU menu;\n        PPH_EMENU_ITEM item;\n        PH_PLUGIN_MENU_INFORMATION menuInfo;\n\n        menu = PhCreateEMenu();\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_HANDLE_CLOSE, L\"C&lose\\bDel\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_HANDLE_PROTECTED, L\"&Protected\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_HANDLE_INHERIT, L\"&Inherit\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_HANDLE_SECURITY, L\"Secu&rity\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_HANDLE_PROPERTIES, L\"Prope&rties\\bEnter\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_HANDLE_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n        PhSetFlagsEMenuItem(menu, ID_HANDLE_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n        PhpInitializeHandleMenu(menu, ProcessItem->ProcessId, handles, numberOfHandles, Context);\n        PhInsertCopyCellEMenuItem(menu, ID_HANDLE_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);\n\n        if (PhPluginsEnabled)\n        {\n            PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);\n            menuInfo.u.Handle.ProcessId = ProcessItem->ProcessId;\n            menuInfo.u.Handle.Handles = handles;\n            menuInfo.u.Handle.NumberOfHandles = numberOfHandles;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandleMenuInitializing), &menuInfo);\n        }\n\n        item = PhShowEMenu(\n            menu,\n            hwndDlg,\n            PH_EMENU_SHOW_LEFTRIGHT,\n            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n            ContextMenu->Location.x,\n            ContextMenu->Location.y\n            );\n\n        if (item)\n        {\n            BOOLEAN handled = FALSE;\n\n            handled = PhHandleCopyCellEMenuItem(item);\n\n            if (!handled && PhPluginsEnabled)\n                handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n            if (!handled)\n                SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);\n        }\n\n        PhDestroyEMenu(menu);\n    }\n\n    PhFree(handles);\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhpHandleTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_HANDLES_CONTEXT handlesContext = Context;\n    PPH_HANDLE_NODE handleNode = (PPH_HANDLE_NODE)Node;\n    PPH_HANDLE_ITEM handleItem = handleNode->HandleItem;\n\n    if (handlesContext->ListContext.HideProtectedHandles && handleItem->Attributes & OBJ_PROTECT_CLOSE)\n        return FALSE;\n    if (handlesContext->ListContext.HideInheritHandles && handleItem->Attributes & OBJ_INHERIT)\n        return FALSE;\n    if (handlesContext->ListContext.HideUnnamedHandles && PhIsNullOrEmptyString(handleItem->BestObjectName))\n        return FALSE;\n\n    if (handlesContext->ListContext.HideEtwHandles)\n    {\n        static PH_INITONCE initOnce = PH_INITONCE_INIT;\n        static ULONG eventTraceTypeIndex = ULONG_MAX;\n\n        if (PhBeginInitOnce(&initOnce))\n        {\n            eventTraceTypeIndex = PhGetObjectTypeNumberZ(L\"EtwRegistration\");\n            PhEndInitOnce(&initOnce);\n        }\n\n        if (handleItem->TypeIndex == eventTraceTypeIndex)\n            return FALSE;\n    }\n\n    if (!handlesContext->SearchMatchHandle)\n        return TRUE;\n\n    // handle properties\n\n    if (PhSearchControlMatchPointer(handlesContext->SearchMatchHandle, handleItem->Handle))\n        return TRUE;\n\n    if (!PhIsNullOrEmptyString(handleItem->TypeName))\n    {\n        if (PhSearchControlMatch(handlesContext->SearchMatchHandle, &handleItem->TypeName->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(handleItem->ObjectName))\n    {\n        if (PhSearchControlMatch(handlesContext->SearchMatchHandle, &handleItem->ObjectName->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(handleItem->BestObjectName))\n    {\n        if (PhSearchControlMatch(handlesContext->SearchMatchHandle, &handleItem->BestObjectName->sr))\n            return TRUE;\n    }\n\n    if (handleItem->HandleString[0])\n    {\n        if (PhSearchControlMatchLongHintZ(handlesContext->SearchMatchHandle, handleItem->HandleString))\n            return TRUE;\n    }\n\n    if (handleItem->GrantedAccessString[0])\n    {\n        if (PhSearchControlMatchLongHintZ(handlesContext->SearchMatchHandle, handleItem->GrantedAccessString))\n            return TRUE;\n    }\n\n    if (handleItem->ObjectString[0])\n    {\n        if (PhSearchControlMatchLongHintZ(handlesContext->SearchMatchHandle, handleItem->ObjectString))\n            return TRUE;\n    }\n\n    if (handleNode->HandleItem->Attributes & OBJ_PROTECT_CLOSE && PhSearchControlMatchZ(handlesContext->SearchMatchHandle, L\"Protected\"))\n    {\n        return TRUE;\n    }\n    if (handleNode->HandleItem->Attributes & OBJ_INHERIT && PhSearchControlMatchZ(handlesContext->SearchMatchHandle, L\"Inherit\"))\n    {\n        return TRUE;\n    }\n\n    // node properties\n\n    if (!PhIsNullOrEmptyString(handleNode->GrantedAccessSymbolicText))\n    {\n        if (PhSearchControlMatch(handlesContext->SearchMatchHandle, &handleNode->GrantedAccessSymbolicText->sr))\n            return TRUE;\n    }\n\n    if (handleNode->FileShareAccessText[0])\n    {\n        if (PhSearchControlMatchLongHintZ(handlesContext->SearchMatchHandle, handleNode->FileShareAccessText))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\ntypedef struct _HANDLE_OPEN_CONTEXT\n{\n    HANDLE ProcessId;\n    PPH_HANDLE_ITEM HandleItem;\n} HANDLE_OPEN_CONTEXT, *PHANDLE_OPEN_CONTEXT;\n\n_Function_class_(PH_OPEN_OBJECT)\nNTSTATUS PhpProcessHandleOpenCallback(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PVOID Context\n    )\n{\n    PHANDLE_OPEN_CONTEXT context = Context;\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    *Handle = NULL;\n\n    if (KsiLevel() >= KphLevelMax)\n    {\n        // Try limited-information first when allowed by KSI.\n        if (NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            context->ProcessId\n            )))\n        {\n            status = NtDuplicateObject(\n                processHandle,\n                context->HandleItem->Handle,\n                NtCurrentProcess(),\n                Handle,\n                DesiredAccess,\n                0,\n                0\n                );\n            NtClose(processHandle);\n\n            if (NT_SUCCESS(status))\n                return status;\n        }\n    }\n\n    if (NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_DUP_HANDLE,\n        context->ProcessId\n        )))\n    {\n        status = NtDuplicateObject(\n            processHandle,\n            context->HandleItem->Handle,\n            NtCurrentProcess(),\n            Handle,\n            DesiredAccess,\n            0,\n            0\n            );\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\n_Function_class_(PH_CLOSE_OBJECT)\nNTSTATUS PhpProcessHandleCloseCallback(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    PHANDLE_OPEN_CONTEXT context = Context;\n\n    if (Handle)\n    {\n        NtClose(Handle);\n    }\n\n    if (Release && context)\n    {\n        PhDereferenceObject(context->HandleItem);\n        PhFree(context);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhpProcessHandlessSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_HANDLES_CONTEXT handlesContext = Context;\n\n    assert(handlesContext);\n\n    handlesContext->SearchMatchHandle = MatchHandle;\n\n    if (!handlesContext->SearchMatchHandle)\n    {\n        // Expand any hidden nodes to make search results visible.\n        PhExpandAllHandleNodes(&handlesContext->ListContext, TRUE);\n    }\n\n    PhApplyTreeNewFilters(&handlesContext->ListContext.TreeFilterSupport);\n}\n\nINT_PTR CALLBACK PhpProcessHandlesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n    PPH_HANDLES_CONTEXT handlesContext;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &propPageContext, &processItem))\n    {\n        handlesContext = propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            handlesContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmHandlesContextType, sizeof(PH_HANDLES_CONTEXT)));\n            memset(handlesContext, 0, sizeof(PH_HANDLES_CONTEXT));\n\n            handlesContext->WindowHandle = hwndDlg;\n            handlesContext->SearchWindowHandle = GetDlgItem(hwndDlg, IDC_HANDLESEARCH);\n            handlesContext->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            handlesContext->Provider = PhCreateHandleProvider(\n                processItem->ProcessId\n                );\n            PhRegisterProvider(\n                &PhTertiaryProviderThread,\n                PhHandleProviderUpdate,\n                handlesContext->Provider,\n                &handlesContext->ProviderRegistration\n                );\n            PhRegisterCallback(\n                &handlesContext->Provider->HandleAddedEvent,\n                HandleAddedHandler,\n                handlesContext,\n                &handlesContext->AddedEventRegistration\n                );\n            PhRegisterCallback(\n                &handlesContext->Provider->HandleModifiedEvent,\n                HandleModifiedHandler,\n                handlesContext,\n                &handlesContext->ModifiedEventRegistration\n                );\n            PhRegisterCallback(\n                &handlesContext->Provider->HandleRemovedEvent,\n                HandleRemovedHandler,\n                handlesContext,\n                &handlesContext->RemovedEventRegistration\n                );\n            PhRegisterCallback(\n                &handlesContext->Provider->HandleUpdatedEvent,\n                HandlesUpdatedHandler,\n                handlesContext,\n                &handlesContext->UpdatedEventRegistration\n                );\n\n            // Initialize the list.\n            PhInitializeHandleList(hwndDlg, handlesContext->TreeNewHandle, &handlesContext->ListContext);\n\n            if (PhTreeWindowFont)\n            {\n                handlesContext->TreeNewFont = PhDuplicateFont(PhTreeWindowFont);\n                SetWindowFont(handlesContext->TreeNewHandle, handlesContext->TreeNewFont, FALSE);\n            }\n\n            TreeNew_SetEmptyText(handlesContext->TreeNewHandle, &PhProcessPropPageLoadingText, 0);\n            PhInitializeProviderEventQueue(&handlesContext->EventQueue, 100);\n            handlesContext->LastRunStatus = -1;\n            handlesContext->ErrorMessage = NULL;\n            handlesContext->FilterEntry = PhAddTreeNewFilter(&handlesContext->ListContext.TreeFilterSupport, PhpHandleTreeFilterCallback, handlesContext);\n\n            PhCreateSearchControl(\n                hwndDlg,\n                handlesContext->SearchWindowHandle,\n                L\"Search Handles (Ctrl+K)\",\n                PhpProcessHandlessSearchControlCallback,\n                handlesContext\n                );\n\n            PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectCreate);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n                treeNewInfo.TreeNewHandle = handlesContext->TreeNewHandle;\n                treeNewInfo.CmData = &handlesContext->ListContext.Cm;\n                treeNewInfo.SystemContext = handlesContext;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandleTreeNewInitializing), &treeNewInfo);\n            }\n\n            PhLoadSettingsHandleList(&handlesContext->ListContext);\n\n            PhSetEnabledProvider(&handlesContext->ProviderRegistration, TRUE);\n            PhBoostProvider(&handlesContext->ProviderRegistration, NULL);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackUpdateAutomatically),\n                HandlesUpdateAutomaticallyHandler,\n                handlesContext,\n                &handlesContext->ChangedEventRegistration\n                );\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveTreeNewFilter(&handlesContext->ListContext.TreeFilterSupport, handlesContext->FilterEntry);\n\n            PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectDelete);\n\n            PhUnregisterCallback(\n                &handlesContext->Provider->HandleAddedEvent,\n                &handlesContext->AddedEventRegistration\n                );\n            PhUnregisterCallback(\n                &handlesContext->Provider->HandleModifiedEvent,\n                &handlesContext->ModifiedEventRegistration\n                );\n            PhUnregisterCallback(\n                &handlesContext->Provider->HandleRemovedEvent,\n                &handlesContext->RemovedEventRegistration\n                );\n            PhUnregisterCallback(\n                &handlesContext->Provider->HandleUpdatedEvent,\n                &handlesContext->UpdatedEventRegistration\n                );\n            PhUnregisterCallback(\n                PhGetGeneralCallback(GeneralCallbackUpdateAutomatically),\n                &handlesContext->ChangedEventRegistration\n                );\n\n            PhUnregisterProvider(&handlesContext->ProviderRegistration);\n            PhDereferenceObject(handlesContext->Provider);\n            PhDeleteProviderEventQueue(&handlesContext->EventQueue);\n\n            if (handlesContext->TreeNewFont)\n                DeleteFont(handlesContext->TreeNewFont);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n                treeNewInfo.TreeNewHandle = handlesContext->TreeNewHandle;\n                treeNewInfo.CmData = &handlesContext->ListContext.Cm;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandleTreeNewUninitializing), &treeNewInfo);\n            }\n\n            PhSaveSettingsHandleList(&handlesContext->ListContext);\n            PhDeleteHandleList(&handlesContext->ListContext);\n\n            PhFree(handlesContext);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, handlesContext->SearchWindowHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, handlesContext->TreeNewHandle, dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case ID_SHOWCONTEXTMENU:\n                {\n                    PhShowHandleContextMenu(hwndDlg, processItem, handlesContext, (PPH_TREENEW_CONTEXT_MENU)lParam);\n                }\n                break;\n            case ID_HANDLE_CLOSE:\n                {\n                    PPH_HANDLE_ITEM *handles;\n                    ULONG numberOfHandles;\n\n                    PhGetSelectedHandleItems(&handlesContext->ListContext, &handles, &numberOfHandles);\n                    PhReferenceObjects(handles, numberOfHandles);\n\n                    if (PhUiCloseHandles(hwndDlg, processItem->ProcessId, handles, numberOfHandles, !!lParam))\n                        PhDeselectAllHandleNodes(&handlesContext->ListContext);\n\n                    PhDereferenceObjects(handles, numberOfHandles);\n                    PhFree(handles);\n                }\n                break;\n            case ID_HANDLE_PROTECTED:\n            case ID_HANDLE_INHERIT:\n                {\n                    PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);\n\n                    if (handleItem)\n                    {\n                        ULONG attributes = 0;\n\n                        // Re-create the attributes.\n\n                        if (handlesContext->SelectedHandleProtected)\n                            attributes |= OBJ_PROTECT_CLOSE;\n                        if (handlesContext->SelectedHandleInherit)\n                            attributes |= OBJ_INHERIT;\n\n                        // Toggle the appropriate bit.\n\n                        if (GET_WM_COMMAND_ID(wParam, lParam) == ID_HANDLE_PROTECTED)\n                            attributes ^= OBJ_PROTECT_CLOSE;\n                        else if (GET_WM_COMMAND_ID(wParam, lParam) == ID_HANDLE_INHERIT)\n                            attributes ^= OBJ_INHERIT;\n\n                        PhReferenceObject(handleItem);\n                        PhUiSetAttributesHandle(hwndDlg, processItem->ProcessId, handleItem, attributes);\n                        PhDereferenceObject(handleItem);\n                    }\n                }\n                break;\n            case ID_HANDLE_SECURITY:\n                {\n                    PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);\n\n                    if (handleItem)\n                    {\n                        PHANDLE_OPEN_CONTEXT context;\n\n                        context = PhAllocateZero(sizeof(HANDLE_OPEN_CONTEXT));\n                        context->HandleItem = PhReferenceObject(handleItem);\n                        context->ProcessId = processItem->ProcessId;\n\n                        PhEditSecurity(\n                            PhCsForceNoParent ? NULL : hwndDlg,\n                            PhGetString(handleItem->ObjectName),\n                            PhGetString(handleItem->TypeName),\n                            PhpProcessHandleOpenCallback,\n                            PhpProcessHandleCloseCallback,\n                            context\n                            );\n                    }\n                }\n                break;\n            case ID_HANDLE_GOTOOWNINGPROCESS:\n                {\n                    PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);\n\n                    if (handleItem)\n                    {\n                        HANDLE processHandle;\n                        HANDLE objectHHandle;\n                        PPH_PROCESS_NODE processNode;\n                        NTSTATUS status;\n\n                        if (NT_SUCCESS(status = PhOpenProcess(\n                            &processHandle,\n                            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_DUP_HANDLE,\n                            handleItem->ProcessId\n                            )))\n                        {\n                            if (NT_SUCCESS(status = NtDuplicateObject(\n                                processHandle,\n                                handleItem->Handle,\n                                NtCurrentProcess(),\n                                &objectHHandle,\n                                PROCESS_QUERY_LIMITED_INFORMATION,\n                                0,\n                                0\n                                )))\n                            {\n                                PROCESS_BASIC_INFORMATION basicInfo;\n\n                                if (NT_SUCCESS(status = PhGetProcessBasicInformation(objectHHandle, &basicInfo)))\n                                {\n                                    if (processNode = PhFindProcessNode(basicInfo.UniqueProcessId))\n                                    {\n                                        SystemInformer_SelectTabPage(0);\n                                        SystemInformer_SelectProcessNode(processNode);\n                                        SystemInformer_ToggleVisible(TRUE);\n                                    }\n                                    else\n                                    {\n                                        PhShowStatus(hwndDlg, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n                                    }\n                                }\n\n                                NtClose(objectHHandle);\n                            }\n\n                            NtClose(processHandle);\n                        }\n\n                         if (!NT_SUCCESS(status))\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to query the process.\", status, 0);\n                        }\n                    }\n                }\n                break;\n            case ID_HANDLE_OBJECTPROPERTIES1:\n            case ID_HANDLE_OBJECTPROPERTIES2:\n                {\n                    PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);\n\n                    if (handleItem)\n                    {\n                        PH_HANDLE_ITEM_INFO info;\n\n                        info.ProcessId = processItem->ProcessId;\n                        info.Handle = handleItem->Handle;\n                        info.TypeName = handleItem->TypeName;\n                        info.BestObjectName = handleItem->BestObjectName;\n\n                        if (GET_WM_COMMAND_ID(wParam, lParam) == ID_HANDLE_OBJECTPROPERTIES1)\n                            PhShowHandleObjectProperties1(hwndDlg, &info);\n                        else\n                            PhShowHandleObjectProperties2(hwndDlg, &info);\n                    }\n                }\n                break;\n            case ID_HANDLE_PROPERTIES:\n                {\n                    PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);\n\n                    if (handleItem)\n                    {\n                        PhReferenceObject(handleItem);\n                        PhShowHandleProperties(hwndDlg, processItem->ProcessId, handleItem);\n                        PhDereferenceObject(handleItem);\n                    }\n                }\n                break;\n            case ID_HANDLE_COPY:\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(handlesContext->TreeNewHandle, 0);\n                    PhSetClipboardString(handlesContext->TreeNewHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            case IDC_OPTIONS:\n                {\n                    RECT rect;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM protectedMenuItem;\n                    PPH_EMENU_ITEM inheritMenuItem;\n                    PPH_EMENU_ITEM unnamedMenuItem;\n                    PPH_EMENU_ITEM etwMenuItem;\n                    PPH_EMENU_ITEM protectedHighlightMenuItem;\n                    PPH_EMENU_ITEM inheritHighlightMenuItem;\n                    PPH_EMENU_ITEM selectedItem;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect))\n                        break;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, protectedMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIDE_PROTECTED_HANDLES, L\"Hide protected handles\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, inheritMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIDE_INHERIT_HANDLES, L\"Hide inherit handles\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, unnamedMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIDE_UNNAMED_HANDLES, L\"Hide unnamed handles\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, etwMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIDE_ETW_HANDLES, L\"Hide etw handles\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, protectedHighlightMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIGHLIGHT_PROTECTED_HANDLES, L\"Highlight protected handles\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, inheritHighlightMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIGHLIGHT_INHERIT_HANDLES, L\"Highlight inherit handles\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HANDLESTATS, L\"Statistics\", NULL, NULL), ULONG_MAX);\n\n                    if (handlesContext->ListContext.HideProtectedHandles)\n                        protectedMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (handlesContext->ListContext.HideInheritHandles)\n                        inheritMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (handlesContext->ListContext.HideUnnamedHandles)\n                        unnamedMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (handlesContext->ListContext.HideEtwHandles)\n                        etwMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (PhCsUseColorProtectedHandles)\n                        protectedHighlightMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (PhCsUseColorInheritHandles)\n                        inheritHighlightMenuItem->Flags |= PH_EMENU_CHECKED;\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        rect.left,\n                        rect.bottom\n                        );\n\n                    if (selectedItem && selectedItem->Id)\n                    {\n                        if (selectedItem->Id == PH_HANDLE_TREE_MENUITEM_HIGHLIGHT_PROTECTED_HANDLES)\n                        {\n                            // HACK (dmex)\n                            PhSetIntegerSetting(SETTING_USE_COLOR_PROTECTED_HANDLES, !PhCsUseColorProtectedHandles);\n                            PhCsUseColorProtectedHandles = !PhCsUseColorProtectedHandles;\n                            TreeNew_NodesStructured(handlesContext->TreeNewHandle);\n                        }\n                        else if (selectedItem->Id == PH_HANDLE_TREE_MENUITEM_HIGHLIGHT_INHERIT_HANDLES)\n                        {\n                            // HACK (dmex)\n                            PhSetIntegerSetting(SETTING_USE_COLOR_INHERIT_HANDLES, !PhCsUseColorInheritHandles);\n                            PhCsUseColorInheritHandles = !PhCsUseColorInheritHandles;\n                            TreeNew_NodesStructured(handlesContext->TreeNewHandle);\n                        }\n                        else if (selectedItem->Id == PH_HANDLE_TREE_MENUITEM_HANDLESTATS)\n                        {\n                            PhShowHandleStatisticsDialog(hwndDlg, handlesContext->Provider->ProcessId);\n                        }\n                        else\n                        {\n                            PhSetOptionsHandleList(&handlesContext->ListContext, selectedItem->Id);\n                            PhSaveSettingsHandleList(&handlesContext->ListContext);\n                            PhApplyTreeNewFilters(&handlesContext->ListContext.TreeFilterSupport);\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_SETACTIVE:\n                PhSetEnabledProvider(&handlesContext->ProviderRegistration, TRUE);\n                break;\n            case PSN_KILLACTIVE:\n                PhSetEnabledProvider(&handlesContext->ProviderRegistration, FALSE);\n                break;\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)handlesContext->TreeNewHandle);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            if (LOWORD(wParam) == 'K')\n            {\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    SetFocus(handlesContext->SearchWindowHandle);\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    case WM_PH_HANDLES_UPDATED:\n        {\n            ULONG upToRunId = (ULONG)wParam;\n            PPH_PROVIDER_EVENT events;\n            ULONG count;\n            ULONG i;\n\n            events = PhFlushProviderEventQueue(&handlesContext->EventQueue, upToRunId, &count);\n\n            if (events)\n            {\n                TreeNew_SetRedraw(handlesContext->TreeNewHandle, FALSE);\n\n                for (i = 0; i < count; i++)\n                {\n                    PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]);\n                    PPH_HANDLE_ITEM handleItem = PH_PROVIDER_EVENT_OBJECT(events[i]);\n\n                    switch (type)\n                    {\n                    case ProviderAddedEvent:\n                        PhAddHandleNode(&handlesContext->ListContext, handleItem, events[i].RunId);\n                        PhDereferenceObject(handleItem);\n                        break;\n                    case ProviderModifiedEvent:\n                        PhUpdateHandleNode(&handlesContext->ListContext, PhFindHandleNode(&handlesContext->ListContext, handleItem->Handle));\n                        break;\n                    case ProviderRemovedEvent:\n                        PhRemoveHandleNode(&handlesContext->ListContext, PhFindHandleNode(&handlesContext->ListContext, handleItem->Handle));\n                        break;\n                    }\n                }\n\n                PhFree(events);\n            }\n\n            PhTickHandleNodes(&handlesContext->ListContext);\n\n            if (handlesContext->LastRunStatus != handlesContext->Provider->RunStatus)\n            {\n                NTSTATUS status;\n                PPH_STRING message;\n\n                status = handlesContext->Provider->RunStatus;\n                handlesContext->LastRunStatus = status;\n\n                if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId))\n                    status = STATUS_SUCCESS;\n\n                if (NT_SUCCESS(status))\n                {\n                    TreeNew_SetEmptyText(handlesContext->TreeNewHandle, &EmptyHandlesText, 0);\n                }\n                else\n                {\n                    message = PhGetStatusMessage(status, 0);\n                    PhMoveReference(&handlesContext->ErrorMessage, PhFormatString(L\"Unable to query handle information:\\n%s\", PhGetStringOrDefault(message, L\"Unknown error.\")));\n                    PhClearReference(&message);\n                    TreeNew_SetEmptyText(handlesContext->TreeNewHandle, &handlesContext->ErrorMessage->sr, 0);\n                }\n\n                InvalidateRect(handlesContext->TreeNewHandle, NULL, FALSE);\n            }\n\n            if (count != 0)\n            {\n                // Refresh the visible nodes.\n                PhApplyTreeNewFilters(&handlesContext->ListContext.TreeFilterSupport);\n\n                TreeNew_SetRedraw(handlesContext->TreeNewHandle, TRUE);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpgjob.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *\n */\n\n#include <phapp.h>\n#include <procprp.h>\n#include <kphuser.h>\n\n_Function_class_(PH_OPEN_OBJECT)\nNTSTATUS NTAPI PhpOpenProcessJobForPage(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    HANDLE jobHandle = NULL;\n\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        (HANDLE)Context\n        )))\n        return status;\n\n    status = KphOpenProcessJob(processHandle, DesiredAccess, &jobHandle);\n    NtClose(processHandle);\n\n    if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB && jobHandle)\n    {\n        *Handle = jobHandle;\n    }\n    else if (NT_SUCCESS(status))\n    {\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    return status;\n}\n\n_Function_class_(PH_CLOSE_OBJECT)\nNTSTATUS NTAPI PhpCloseProcessJobForPage(\n    _In_ HANDLE Handle,\n    _In_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    return NtClose(Handle);\n}\n\nINT_PTR CALLBACK PhpProcessJobHookProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            if (!PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT)) // LayoutInitialized\n            {\n                PPH_LAYOUT_ITEM dialogItem;\n\n                // This is a big violation of abstraction...\n\n                dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,\n                    PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME),\n                    dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_TERMINATE),\n                    dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESSES),\n                    dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADD),\n                    dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIMITS),\n                    dialogItem, PH_ANCHOR_ALL);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED),\n                    dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n                PhDoPropPageLayout(hwndDlg);\n\n                PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, UlongToPtr(TRUE));\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpgmem.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <procprp.h>\n#include <procprpp.h>\n#include <settings.h>\n#include <phsettings.h>\n\n#include <cpysave.h>\n#include <emenu.h>\n\n#include <actions.h>\n#include <extmgri.h>\n#include <mainwnd.h>\n#include <phplug.h>\n#include <procprv.h>\n\nstatic PPH_OBJECT_TYPE PhMemoryContextType = NULL;\nstatic PH_STRINGREF EmptyMemoryText = PH_STRINGREF_INIT(L\"There are no memory regions to display.\");\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpRefreshProcessMemoryThread(\n    _In_ PVOID Context\n    )\n{\n    PPH_MEMORY_CONTEXT memoryContext = Context;\n    ULONG flags = PH_QUERY_MEMORY_REGION_TYPE | PH_QUERY_MEMORY_WS_COUNTERS;\n    if (memoryContext->ListContext.ZeroPadAddresses)\n        flags |= PH_QUERY_MEMORY_ZERO_PAD_ADDRESSES;\n\n    if (PH_IS_REAL_PROCESS_ID(memoryContext->ProcessId))\n    {\n        memoryContext->LastRunStatus = PhQueryMemoryItemList(\n            memoryContext->ProcessId,\n            flags,\n            &memoryContext->MemoryItemList\n            );\n    }\n\n    if (NT_SUCCESS(memoryContext->LastRunStatus))\n    {\n        if (PhPluginsEnabled)\n        {\n            PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL control;\n\n            control.Type = PluginMemoryItemListInitialized;\n            control.u.Initialized.List = &memoryContext->MemoryItemList;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryItemListControl), &control);\n        }\n\n        memoryContext->MemoryItemListValid = TRUE;\n    }\n\n    PostMessage(memoryContext->WindowHandle, WM_PH_INVOKE, 0, 0);\n\n    PhDereferenceObject(memoryContext);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpRefreshProcessMemoryList(\n    _In_ PPH_PROCESS_PROPPAGECONTEXT PropPageContext\n    )\n{\n    PPH_MEMORY_CONTEXT memoryContext = PropPageContext->Context;\n\n    if (memoryContext->MemoryItemListValid)\n    {\n        PhDeleteMemoryItemList(&memoryContext->MemoryItemList);\n        memoryContext->MemoryItemListValid = FALSE;\n    }\n\n    PhReferenceObject(memoryContext);\n    PhCreateThread2(PhpRefreshProcessMemoryThread, memoryContext);\n}\n\nVOID PhpInitializeMemoryMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_MEMORY_NODE *MemoryNodes,\n    _In_ ULONG NumberOfMemoryNodes\n    )\n{\n    if (NumberOfMemoryNodes == 0)\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n    }\n    else if (NumberOfMemoryNodes == 1 && !MemoryNodes[0]->IsAllocationBase)\n    {\n        if (MemoryNodes[0]->MemoryItem->State & MEM_FREE)\n        {\n            PhEnableEMenuItem(Menu, ID_MEMORY_CHANGEPROTECTION, FALSE);\n            PhEnableEMenuItem(Menu, ID_MEMORY_FREE, FALSE);\n            PhEnableEMenuItem(Menu, ID_MEMORY_DECOMMIT, FALSE);\n        }\n        else if (MemoryNodes[0]->MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE))\n        {\n            PhEnableEMenuItem(Menu, ID_MEMORY_DECOMMIT, FALSE);\n        }\n    }\n    else\n    {\n        ULONG i;\n        ULONG numberOfAllocationBase = 0;\n\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n        PhEnableEMenuItem(Menu, ID_MEMORY_COPY, TRUE);\n\n        for (i = 0; i < NumberOfMemoryNodes; i++)\n        {\n            if (MemoryNodes[i]->IsAllocationBase)\n                numberOfAllocationBase++;\n        }\n\n        if (numberOfAllocationBase == 0 || numberOfAllocationBase == NumberOfMemoryNodes)\n            PhEnableEMenuItem(Menu, ID_MEMORY_SAVE, TRUE);\n    }\n}\n\nVOID PhShowMemoryContextMenu(\n    _In_ HWND hwndDlg,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_MEMORY_CONTEXT Context,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    )\n{\n    PPH_MEMORY_NODE *memoryNodes;\n    ULONG numberOfMemoryNodes;\n\n    PhGetSelectedMemoryNodes(&Context->ListContext, &memoryNodes, &numberOfMemoryNodes);\n\n    if (numberOfMemoryNodes != 0)\n    {\n        PPH_EMENU menu;\n        PPH_EMENU_ITEM item;\n        PH_PLUGIN_MENU_INFORMATION menuInfo;\n\n        menu = PhCreateEMenu();\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_READWRITEMEMORY, L\"&Read/Write memory...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_CHANGEPROTECTION, L\"Change &protection...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_EMPTYWORKINGSET, L\"&Empty working set...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_FREE, L\"&Free\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_DECOMMIT, L\"&Decommit\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_SAVE, L\"&Save...\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n        PhSetFlagsEMenuItem(menu, ID_MEMORY_READWRITEMEMORY, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n        PhpInitializeMemoryMenu(menu, ProcessItem->ProcessId, memoryNodes, numberOfMemoryNodes);\n        PhInsertCopyCellEMenuItem(menu, ID_MEMORY_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);\n\n        if (PhPluginsEnabled)\n        {\n            PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);\n            menuInfo.u.Memory.ProcessId = ProcessItem->ProcessId;\n            menuInfo.u.Memory.MemoryNodes = memoryNodes;\n            menuInfo.u.Memory.NumberOfMemoryNodes = numberOfMemoryNodes;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryMenuInitializing), &menuInfo);\n        }\n\n        item = PhShowEMenu(\n            menu,\n            hwndDlg,\n            PH_EMENU_SHOW_LEFTRIGHT,\n            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n            ContextMenu->Location.x,\n            ContextMenu->Location.y\n            );\n\n        if (item)\n        {\n            BOOLEAN handled = FALSE;\n\n            handled = PhHandleCopyCellEMenuItem(item);\n\n            if (!handled && PhPluginsEnabled)\n                handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n            if (!handled)\n                SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);\n        }\n\n        PhDestroyEMenu(menu);\n    }\n\n    PhFree(memoryNodes);\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhpMemoryTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MEMORY_CONTEXT memoryContext = Context;\n    PPH_MEMORY_NODE memoryNode = (PPH_MEMORY_NODE)Node;\n    PPH_MEMORY_ITEM memoryItem = memoryNode->MemoryItem;\n    PCPH_STRINGREF string;\n    PPH_STRING useText;\n\n    if (memoryContext->ListContext.HideFreeRegions && FlagOn(memoryItem->State, MEM_FREE))\n        return FALSE;\n    if (memoryContext->ListContext.HideGuardRegions && FlagOn(memoryItem->Protect, PAGE_GUARD))\n        return FALSE;\n\n    if (\n        memoryContext->ListContext.HideReservedRegions &&\n        (FlagOn(memoryItem->Type, MEM_PRIVATE) || FlagOn(memoryItem->Type, MEM_MAPPED) || FlagOn(memoryItem->Type, MEM_IMAGE)) &&\n        FlagOn(memoryItem->State, MEM_RESERVE) &&\n        memoryItem->AllocationBaseItem // Ignore root nodes\n        )\n    {\n        return FALSE;\n    }\n\n    if (!memoryContext->SearchMatchHandle)\n        return TRUE;\n\n    if (PhSearchControlMatchPointer(memoryContext->SearchMatchHandle, memoryNode->MemoryItem->AllocationBase))\n        return TRUE;\n\n    if (PhSearchControlMatchPointerRange(\n        memoryContext->SearchMatchHandle,\n        memoryNode->MemoryItem->AllocationBase,\n        memoryNode->MemoryItem->RegionSize\n        ))\n        return TRUE;\n\n    if (PhSearchControlMatchPointerRange(\n        memoryContext->SearchMatchHandle,\n        memoryNode->MemoryItem->BaseAddress,\n        memoryNode->MemoryItem->RegionSize\n        ))\n        return TRUE;\n\n    if (memoryItem->BaseAddressString[0])\n    {\n        if (PhSearchControlMatchLongHintZ(memoryContext->SearchMatchHandle, memoryItem->BaseAddressString))\n            return TRUE;\n    }\n\n    string = PhGetMemoryTypeString(memoryItem->Type);\n    if (string && string->Length)\n    {\n        if (PhSearchControlMatch(memoryContext->SearchMatchHandle, string))\n            return TRUE;\n    }\n\n    string = PhGetMemoryStateString(memoryItem->State);\n    if (string && string->Length)\n    {\n        if (PhSearchControlMatch(memoryContext->SearchMatchHandle, string))\n            return TRUE;\n    }\n\n    useText = PH_AUTO(PhGetMemoryRegionUseText(memoryItem));\n    if (!PhIsNullOrEmptyString(useText))\n    {\n        if (PhSearchControlMatch(memoryContext->SearchMatchHandle, &useText->sr))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpPopulateTableWithProcessMemoryNodes(\n    _In_ HWND TreeListHandle,\n    _In_ PPH_MEMORY_NODE Node,\n    _In_ ULONG Level,\n    _In_ PPH_STRING **Table,\n    _Inout_ PULONG Index,\n    _In_ PULONG DisplayToId,\n    _In_ ULONG Columns\n    )\n{\n    for (ULONG i = 0; i < Columns; i++)\n    {\n        PH_TREENEW_GET_CELL_TEXT getCellText;\n        PPH_STRING text;\n\n        getCellText.Node = &Node->Node;\n        getCellText.Id = DisplayToId[i];\n        PhInitializeEmptyStringRef(&getCellText.Text);\n        TreeNew_GetCellText(TreeListHandle, &getCellText);\n\n        if (i != 0)\n        {\n            if (getCellText.Text.Length == 0)\n                text = PhReferenceEmptyString();\n            else\n                text = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length);\n        }\n        else\n        {\n            // If this is the first column in the row, add some indentation.\n            text = PhaCreateStringEx(\n                NULL,\n                getCellText.Text.Length + UInt32x32To64(Level, 2) * sizeof(WCHAR)\n                );\n            wmemset(text->Buffer, L' ', UInt32x32To64(Level, 2));\n            memcpy(&text->Buffer[UInt32x32To64(Level, 2)], getCellText.Text.Buffer, getCellText.Text.Length);\n        }\n\n        Table[*Index][i] = text;\n    }\n\n    (*Index)++;\n\n    // Process the children.\n    if (!Node->Children)\n        return;\n\n    for (ULONG i = 0; i < Node->Children->Count; i++)\n    {\n        PhpPopulateTableWithProcessMemoryNodes(\n            TreeListHandle,\n            Node->Children->Items[i],\n            Level + 1,\n            Table,\n            Index,\n            DisplayToId,\n            Columns\n            );\n    }\n}\n\nPPH_LIST PhpGetProcessMemoryTreeListLines(\n    _In_ HWND TreeListHandle,\n    _In_ ULONG NumberOfNodes,\n    _In_ PPH_LIST RootNodes,\n    _In_ ULONG Mode\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_LIST lines;\n    // The number of rows in the table (including +1 for the column headers).\n    ULONG rows;\n    // The number of columns.\n    ULONG columns;\n    // A column display index to ID map.\n    PULONG displayToId;\n    // A column display index to text map.\n    PWSTR *displayToText;\n    // The actual string table.\n    PPH_STRING **table;\n    ULONG i;\n    ULONG j;\n\n    // Use a local auto-pool to make memory management a bit less painful.\n    PhInitializeAutoPool(&autoPool);\n\n    rows = NumberOfNodes + 1;\n\n    // Create the display index to ID map.\n    PhMapDisplayIndexTreeNew(TreeListHandle, &displayToId, &displayToText, &columns);\n\n    PhaCreateTextTable(&table, rows, columns);\n\n    // Populate the first row with the column headers.\n    for (i = 0; i < columns; i++)\n    {\n        table[0][i] = PhaCreateString(displayToText[i]);\n    }\n\n    // Go through the nodes in the process tree and populate each cell of the table.\n\n    j = 1; // index starts at one because the first row contains the column headers.\n\n    for (i = 0; i < RootNodes->Count; i++)\n    {\n        PhpPopulateTableWithProcessMemoryNodes(\n            TreeListHandle,\n            RootNodes->Items[i],\n            0,\n            table,\n            &j,\n            displayToId,\n            columns\n            );\n    }\n\n    PhFree(displayToId);\n    PhFree(displayToText);\n\n    lines = PhaFormatTextTable(table, rows, columns, Mode);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return lines;\n}\n\nVOID PhpProcessMemorySave(\n    _In_ PPH_MEMORY_CONTEXT MemoryContext\n    )\n{\n    static PH_FILETYPE_FILTER filters[] =\n    {\n        { L\"Text files (*.txt;*.log)\", L\"*.txt;*.log\" },\n        { L\"Comma-separated values (*.csv)\", L\"*.csv\" },\n        { L\"All files (*.*)\", L\"*.*\" }\n    };\n    PVOID fileDialog = PhCreateSaveFileDialog();\n    PH_FORMAT format[4];\n    PPH_PROCESS_ITEM processItem;\n\n    processItem = PhReferenceProcessItem(MemoryContext->ProcessId);\n    PhInitFormatS(&format[0], L\"System Informer (\");\n    PhInitFormatS(&format[1], processItem ? PhGetStringOrDefault(processItem->ProcessName, L\"Unknown process\") : L\"Unknown process\");\n    PhInitFormatS(&format[2], L\") Memory\");\n    PhInitFormatS(&format[3], L\".txt\");\n    if (processItem) PhDereferenceObject(processItem);\n\n    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n    PhSetFileDialogFileName(fileDialog, PH_AUTO_T(PH_STRING, PhFormat(format, 3, 60))->Buffer);\n\n    if (PhShowFileDialog(MemoryContext->WindowHandle, fileDialog))\n    {\n        NTSTATUS status;\n        PPH_STRING fileName;\n        ULONG filterIndex;\n        PPH_FILE_STREAM fileStream;\n\n        fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n        filterIndex = PhGetFileDialogFilterIndex(fileDialog);\n\n        if (NT_SUCCESS(status = PhCreateFileStream(\n            &fileStream,\n            fileName->Buffer,\n            FILE_GENERIC_WRITE,\n            FILE_SHARE_READ,\n            FILE_OVERWRITE_IF,\n            0\n            )))\n        {\n            ULONG mode;\n            PPH_LIST lines;\n\n            if (filterIndex == 2)\n                mode = PH_EXPORT_MODE_CSV;\n            else\n                mode = PH_EXPORT_MODE_TABS;\n\n            PhWriteStringAsUtf8FileStream(fileStream, (PPH_STRINGREF)&PhUnicodeByteOrderMark);\n\n            if (mode != PH_EXPORT_MODE_CSV)\n            {\n                PhWritePhTextHeader(fileStream);\n            }\n\n            lines = PhpGetProcessMemoryTreeListLines(\n                MemoryContext->TreeNewHandle,\n                MemoryContext->ListContext.RegionNodeList->Count,\n                MemoryContext->ListContext.RegionNodeList,\n                mode\n                );\n\n            for (ULONG i = 0; i < lines->Count; i++)\n            {\n                PPH_STRING line;\n\n                line = lines->Items[i];\n                PhWriteStringAsUtf8FileStream(fileStream, &line->sr);\n                PhDereferenceObject(line);\n                PhWriteStringAsUtf8FileStream2(fileStream, L\"\\r\\n\");\n            }\n\n            PhDereferenceObject(lines);\n            PhDereferenceObject(fileStream);\n        }\n\n        if (!NT_SUCCESS(status))\n            PhShowStatus(MemoryContext->WindowHandle, L\"Unable to create the file\", status, 0);\n    }\n\n    PhFreeFileDialog(fileDialog);\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpMemoryContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_MEMORY_CONTEXT memoryContext = (PPH_MEMORY_CONTEXT)Object;\n\n    PhDeleteMemoryList(&memoryContext->ListContext);\n\n    if (memoryContext->MemoryItemListValid)\n        PhDeleteMemoryItemList(&memoryContext->MemoryItemList);\n\n    PhClearReference(&memoryContext->ErrorMessage);\n}\n\nPPH_MEMORY_CONTEXT PhCreateMemoryContext(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_MEMORY_CONTEXT memoryContext;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhMemoryContextType = PhCreateObjectType(L\"ProcessMemoryContext\", 0, PhpMemoryContextDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    memoryContext = PhCreateObject(\n        PhEmGetObjectSize(EmMemoryContextType, sizeof(PH_MEMORY_CONTEXT)),\n        PhMemoryContextType\n        );\n    memset(memoryContext, 0, sizeof(PH_MEMORY_CONTEXT));\n\n    return memoryContext;\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhpProcessMemorySearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MEMORY_CONTEXT memoryContext = Context;\n\n    assert(memoryContext);\n\n    memoryContext->SearchMatchHandle = MatchHandle;\n\n    // Expand any hidden nodes to make search results visible.\n    PhExpandAllMemoryNodes(&memoryContext->ListContext, TRUE);\n\n    PhApplyTreeNewFilters(&memoryContext->ListContext.AllocationTreeFilterSupport);\n    PhApplyTreeNewFilters(&memoryContext->ListContext.TreeFilterSupport);\n}\n\nINT_PTR CALLBACK PhpProcessMemoryDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_MEMORY_CONTEXT memoryContext;\n    LPPROPSHEETPAGE propSheetPage;\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))\n    {\n        memoryContext = (PPH_MEMORY_CONTEXT)propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            memoryContext = propPageContext->Context = PhCreateMemoryContext();\n            memoryContext->WindowHandle = hwndDlg;\n            memoryContext->ProcessId = processItem->ProcessId;\n            memoryContext->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            memoryContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_SEARCH);\n            memoryContext->LastRunStatus = ULONG_MAX;\n            memoryContext->ErrorMessage = NULL;\n\n            // Initialize the list.\n            PhInitializeMemoryList(hwndDlg, memoryContext->TreeNewHandle, &memoryContext->ListContext);\n\n            if (PhTreeWindowFont)\n            {\n                memoryContext->TreeNewFont = PhDuplicateFont(PhTreeWindowFont);\n                SetWindowFont(memoryContext->TreeNewHandle, memoryContext->TreeNewFont, FALSE);\n            }\n\n            TreeNew_SetEmptyText(memoryContext->TreeNewHandle, &PhProcessPropPageLoadingText, 0);\n\n            memoryContext->AllocationFilterEntry = PhAddTreeNewFilter(&memoryContext->ListContext.AllocationTreeFilterSupport, PhpMemoryTreeFilterCallback, memoryContext);\n            memoryContext->FilterEntry = PhAddTreeNewFilter(&memoryContext->ListContext.TreeFilterSupport, PhpMemoryTreeFilterCallback, memoryContext);\n\n            PhCreateSearchControl(\n                hwndDlg,\n                memoryContext->SearchboxHandle,\n                L\"Search Memory (Ctrl+K)\",\n                PhpProcessMemorySearchControlCallback,\n                memoryContext\n                );\n\n            PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectCreate);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n                treeNewInfo.TreeNewHandle = memoryContext->TreeNewHandle;\n                treeNewInfo.CmData = &memoryContext->ListContext.Cm;\n                treeNewInfo.SystemContext = memoryContext;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryTreeNewInitializing), &treeNewInfo);\n            }\n\n            PhLoadSettingsMemoryList(&memoryContext->ListContext);\n\n            PhpRefreshProcessMemoryList(propPageContext);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveTreeNewFilter(&memoryContext->ListContext.TreeFilterSupport, memoryContext->FilterEntry);\n            PhRemoveTreeNewFilter(&memoryContext->ListContext.TreeFilterSupport, memoryContext->AllocationFilterEntry);\n\n            PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectDelete);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n                treeNewInfo.TreeNewHandle = memoryContext->TreeNewHandle;\n                treeNewInfo.CmData = &memoryContext->ListContext.Cm;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryTreeNewUninitializing), &treeNewInfo);\n            }\n\n            PhSaveSettingsMemoryList(&memoryContext->ListContext);\n\n            if (memoryContext->TreeNewFont)\n                DeleteFont(memoryContext->TreeNewFont);\n\n            PhDereferenceObject(memoryContext);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, memoryContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, memoryContext->ListContext.TreeNewHandle, dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case ID_SHOWCONTEXTMENU:\n                {\n                    PhShowMemoryContextMenu(hwndDlg, processItem, memoryContext, (PPH_TREENEW_CONTEXT_MENU)lParam);\n                }\n                break;\n            case ID_MEMORY_READWRITEMEMORY:\n                {\n                    PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);\n\n                    if (memoryNode && !memoryNode->IsAllocationBase)\n                    {\n                        PPH_SHOW_MEMORY_EDITOR showMemoryEditor;\n\n                        showMemoryEditor = PhAllocateZero(sizeof(PH_SHOW_MEMORY_EDITOR));\n                        showMemoryEditor->OwnerWindow = hwndDlg;\n                        showMemoryEditor->ProcessId = processItem->ProcessId;\n                        showMemoryEditor->BaseAddress = memoryNode->MemoryItem->BaseAddress;\n                        showMemoryEditor->RegionSize = memoryNode->MemoryItem->RegionSize;\n                        showMemoryEditor->SelectOffset = ULONG_MAX;\n                        showMemoryEditor->SelectLength = 0;\n\n                        SystemInformer_ShowMemoryEditor(showMemoryEditor);\n                    }\n                }\n                break;\n            case ID_MEMORY_SAVE:\n                {\n                    NTSTATUS status;\n                    HANDLE processHandle;\n                    PPH_MEMORY_NODE *memoryNodes;\n                    ULONG numberOfMemoryNodes;\n\n                    if (!NT_SUCCESS(status = PhOpenProcess(\n                        &processHandle,\n                        PROCESS_VM_READ,\n                        processItem->ProcessId\n                        )))\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to open the process\", status, 0);\n                        break;\n                    }\n\n                    PhGetSelectedMemoryNodes(&memoryContext->ListContext, &memoryNodes, &numberOfMemoryNodes);\n\n                    if (numberOfMemoryNodes != 0)\n                    {\n                        static PH_FILETYPE_FILTER filters[] =\n                        {\n                            { L\"Binary files (*.bin)\", L\"*.bin\" },\n                            { L\"All files (*.*)\", L\"*.*\" }\n                        };\n                        PVOID fileDialog;\n\n                        fileDialog = PhCreateSaveFileDialog();\n\n                        PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n                        PhSetFileDialogFileName(fileDialog, PhaConcatStrings2(processItem->ProcessName->Buffer, L\".bin\")->Buffer);\n\n                        if (PhShowFileDialog(hwndDlg, fileDialog))\n                        {\n                            PPH_STRING fileName;\n                            PPH_FILE_STREAM fileStream;\n                            PVOID buffer;\n                            ULONG i;\n                            ULONG_PTR offset;\n\n                            fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n\n                            if (NT_SUCCESS(status = PhCreateFileStream(\n                                &fileStream,\n                                fileName->Buffer,\n                                FILE_GENERIC_WRITE,\n                                FILE_SHARE_READ,\n                                FILE_OVERWRITE_IF,\n                                0\n                                )))\n                            {\n                                if (buffer = PhAllocatePage(PAGE_SIZE, NULL))\n                                {\n                                    // Go through each selected memory item and append the region contents\n                                    // to the file.\n                                    for (i = 0; i < numberOfMemoryNodes; i++)\n                                    {\n                                        PPH_MEMORY_NODE memoryNode = memoryNodes[i];\n                                        PPH_MEMORY_ITEM memoryItem = memoryNode->MemoryItem;\n\n                                        if (!memoryNode->IsAllocationBase && !(memoryItem->State & MEM_COMMIT))\n                                            continue;\n\n                                        for (offset = 0; offset < memoryItem->RegionSize; offset += PAGE_SIZE)\n                                        {\n                                            if (NT_SUCCESS(PhReadVirtualMemory(\n                                                processHandle,\n                                                PTR_ADD_OFFSET(memoryItem->BaseAddress, offset),\n                                                buffer,\n                                                PAGE_SIZE,\n                                                NULL\n                                                )))\n                                            {\n                                                PhWriteFileStream(fileStream, buffer, PAGE_SIZE);\n                                            }\n                                        }\n                                    }\n\n                                    PhFreePage(buffer);\n                                }\n\n                                PhDereferenceObject(fileStream);\n                            }\n\n                            if (!NT_SUCCESS(status))\n                                PhShowStatus(hwndDlg, L\"Unable to create the file\", status, 0);\n                        }\n\n                        PhFreeFileDialog(fileDialog);\n                    }\n\n                    PhFree(memoryNodes);\n                    NtClose(processHandle);\n                }\n                break;\n            case ID_MEMORY_CHANGEPROTECTION:\n                {\n                    PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);\n\n                    if (memoryNode)\n                    {\n                        PhReferenceObject(memoryNode->MemoryItem);\n\n                        PhShowMemoryProtectDialog(hwndDlg, processItem, memoryNode->MemoryItem);\n                        PhUpdateMemoryNode(&memoryContext->ListContext, memoryNode);\n\n                        PhDereferenceObject(memoryNode->MemoryItem);\n                    }\n                }\n                break;\n            case ID_MEMORY_FREE:\n                {\n                    PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);\n\n                    if (memoryNode)\n                    {\n                        PhReferenceObject(memoryNode->MemoryItem);\n\n                        if (PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, TRUE))\n                        {\n                            PhRemoveMemoryNode(&memoryContext->ListContext, &memoryContext->MemoryItemList, memoryNode);\n                        }\n\n                        PhDereferenceObject(memoryNode->MemoryItem);\n                    }\n                }\n                break;\n            case ID_MEMORY_DECOMMIT:\n                {\n                    PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);\n\n                    if (memoryNode)\n                    {\n                        PhReferenceObject(memoryNode->MemoryItem);\n\n                        if (PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, FALSE))\n                        {\n                            PhRemoveMemoryNode(&memoryContext->ListContext, &memoryContext->MemoryItemList, memoryNode);\n                        }\n\n                        PhDereferenceObject(memoryNode->MemoryItem);\n                    }\n                }\n                break;\n            case ID_MEMORY_EMPTYWORKINGSET:\n                {\n                    PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);\n\n                    if (memoryNode)\n                    {\n                        PhReferenceObject(memoryNode->MemoryItem);\n\n                        if (PhUiEmptyProcessMemoryWorkingSet(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem))\n                        {\n                            // Refresh counters or statistics.\n                        }\n\n                        PhDereferenceObject(memoryNode->MemoryItem);\n                    }\n                }\n                break;\n            case ID_MEMORY_COPY:\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(memoryContext->TreeNewHandle, 0);\n                    PhSetClipboardString(memoryContext->TreeNewHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            case IDC_REFRESH:\n                PhpRefreshProcessMemoryList(propPageContext);\n                break;\n            case IDC_FILTEROPTIONS:\n                {\n                    RECT rect;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM freeItem;\n                    PPH_EMENU_ITEM reservedItem;\n                    PPH_EMENU_ITEM guardItem;\n                    PPH_EMENU_ITEM privateItem;\n                    PPH_EMENU_ITEM systemItem;\n                    PPH_EMENU_ITEM cfgItem;\n                    PPH_EMENU_ITEM typeItem;\n                    PPH_EMENU_ITEM zeroPadItem;\n                    PPH_EMENU_ITEM selectedItem;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect))\n                        break;\n\n                    typedef enum _PH_MEMORY_FILTER_MENU_ITEM\n                    {\n                        PH_MEMORY_FILTER_MENU_HIDE_FREE = 1,\n                        PH_MEMORY_FILTER_MENU_HIDE_RESERVED,\n                        PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE,\n                        PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM,\n                        PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG,\n                        PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE,\n                        PH_MEMORY_FILTER_MENU_HIDE_GUARD,\n                        // Non-standard PH_MEMORY_FLAG options.\n                        PH_MEMORY_FILTER_MENU_READ_ADDRESS,\n                        PH_MEMORY_FILTER_MENU_HEAPS,\n                        PH_MEMORY_FILTER_MENU_MODIFIED,\n                        PH_MEMORY_FILTER_MENU_STRINGS,\n                        PH_MEMORY_FILTER_MENU_SAVE,\n                        PH_MEMORY_FILTER_MENU_ZERO_PAD_ADDRESSES\n                    } PH_MEMORY_FILTER_MENU_ITEM;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, freeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_FREE, L\"Hide free pages\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, reservedItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_RESERVED, L\"Hide reserved pages\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, guardItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_GUARD, L\"Hide guard pages\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, privateItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE, L\"Highlight private pages\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, systemItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM, L\"Highlight system pages\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, cfgItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG, L\"Highlight CFG pages\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, typeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE, L\"Highlight executable pages\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, zeroPadItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_ZERO_PAD_ADDRESSES, L\"Zero pad addresses\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_READ_ADDRESS, L\"Read/Write &address...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HEAPS, L\"Heaps...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_MODIFIED, L\"Modified...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_STRINGS, L\"Strings...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_SAVE, L\"Save...\", NULL, NULL), ULONG_MAX);\n\n                    if (memoryContext->ListContext.HideFreeRegions)\n                        freeItem->Flags |= PH_EMENU_CHECKED;\n                    if (memoryContext->ListContext.HideReservedRegions)\n                        reservedItem->Flags |= PH_EMENU_CHECKED;\n                    if (memoryContext->ListContext.HideGuardRegions)\n                        guardItem->Flags |= PH_EMENU_CHECKED;\n                    if (memoryContext->ListContext.HighlightPrivatePages)\n                        privateItem->Flags |= PH_EMENU_CHECKED;\n                    if (memoryContext->ListContext.HighlightSystemPages)\n                        systemItem->Flags |= PH_EMENU_CHECKED;\n                    if (memoryContext->ListContext.HighlightCfgPages)\n                        cfgItem->Flags |= PH_EMENU_CHECKED;\n                    if (memoryContext->ListContext.HighlightExecutePages)\n                        typeItem->Flags |= PH_EMENU_CHECKED;\n                    if (memoryContext->ListContext.ZeroPadAddresses)\n                        zeroPadItem->Flags |= PH_EMENU_CHECKED;\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        rect.left,\n                        rect.bottom\n                        );\n\n                    if (selectedItem && selectedItem->Id)\n                    {\n                        if (selectedItem->Id == PH_MEMORY_FILTER_MENU_HIDE_FREE ||\n                            selectedItem->Id == PH_MEMORY_FILTER_MENU_HIDE_RESERVED ||\n                            selectedItem->Id == PH_MEMORY_FILTER_MENU_HIDE_GUARD ||\n                            selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE ||\n                            selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM ||\n                            selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG ||\n                            selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE)\n                        {\n                            ULONG id = ULONG_MAX;\n\n                            switch (selectedItem->Id)\n                            {\n                            case PH_MEMORY_FILTER_MENU_HIDE_FREE:\n                                id = PH_MEMORY_FLAGS_FREE_OPTION;\n                                break;\n                            case PH_MEMORY_FILTER_MENU_HIDE_RESERVED:\n                                id = PH_MEMORY_FLAGS_RESERVED_OPTION;\n                                break;\n                            case PH_MEMORY_FILTER_MENU_HIDE_GUARD:\n                                id = PH_MEMORY_FLAGS_GUARD_OPTION;\n                                break;\n                            case PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE:\n                                id = PH_MEMORY_FLAGS_PRIVATE_OPTION;\n                                break;\n                            case PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM:\n                                id = PH_MEMORY_FLAGS_SYSTEM_OPTION;\n                                break;\n                            case PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG:\n                                id = PH_MEMORY_FLAGS_CFG_OPTION;\n                                break;\n                            case PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE:\n                                id = PH_MEMORY_FLAGS_EXECUTE_OPTION;\n                                break;\n                            }\n\n                            if (id != ULONG_MAX)\n                            {\n                                PhSetOptionsMemoryList(&memoryContext->ListContext, selectedItem->Id);\n                                PhSaveSettingsMemoryList(&memoryContext->ListContext);\n\n                                PhApplyTreeNewFilters(&memoryContext->ListContext.AllocationTreeFilterSupport);\n                                PhApplyTreeNewFilters(&memoryContext->ListContext.TreeFilterSupport);\n                            }\n                        }\n                        else if (selectedItem->Id == PH_MEMORY_FILTER_MENU_ZERO_PAD_ADDRESSES)\n                        {\n                            PhSetOptionsMemoryList(&memoryContext->ListContext, PH_MEMORY_FLAGS_ZERO_PAD_ADDRESSES);\n                            PhSaveSettingsMemoryList(&memoryContext->ListContext);\n\n                            PhInvalidateAllMemoryBaseAddressNodes(&memoryContext->ListContext);\n                        }\n                        else if (selectedItem->Id == PH_MEMORY_FILTER_MENU_HEAPS)\n                        {\n                            PhShowProcessHeapsDialog(hwndDlg, processItem);\n                        }\n                        else if (selectedItem->Id == PH_MEMORY_FILTER_MENU_MODIFIED)\n                        {\n                            PhShowImagePageModifiedDialog(hwndDlg, processItem);\n                        }\n                        else if (selectedItem->Id == PH_MEMORY_FILTER_MENU_STRINGS)\n                        {\n                            if (PhGetIntegerSetting(SETTING_ENABLE_MEM_STRINGS_TREE_DIALOG))\n                                PhShowMemoryStringTreeDialog(hwndDlg, processItem);\n                            else\n                                PhShowMemoryStringDialog(hwndDlg, processItem);\n                        }\n                        else if (selectedItem->Id == PH_MEMORY_FILTER_MENU_SAVE)\n                        {\n                            PhpProcessMemorySave(memoryContext);\n                        }\n                        else if (selectedItem->Id == PH_MEMORY_FILTER_MENU_READ_ADDRESS)\n                        {\n                            PPH_STRING selectedChoice = NULL;\n\n                            if (!memoryContext->MemoryItemListValid)\n                                break;\n\n                            while (PhaChoiceDialog(\n                                hwndDlg,\n                                L\"Read/Write Address\",\n                                L\"Enter an address:\",\n                                NULL,\n                                0,\n                                NULL,\n                                PH_CHOICE_DIALOG_USER_CHOICE,\n                                &selectedChoice,\n                                NULL,\n                                SETTING_MEMORY_READ_WRITE_ADDRESS_CHOICES\n                                ))\n                            {\n                                ULONG64 address64;\n                                PVOID address;\n\n                                if (selectedChoice->Length == 0)\n                                    continue;\n\n                                if (PhStringToInteger64(&selectedChoice->sr, 0, &address64))\n                                {\n                                    PPH_MEMORY_ITEM memoryItem;\n\n                                    address = (PVOID)address64;\n                                    memoryItem = PhLookupMemoryItemList(&memoryContext->MemoryItemList, address);\n\n                                    if (memoryItem)\n                                    {\n                                        PPH_SHOW_MEMORY_EDITOR showMemoryEditor;\n\n                                        showMemoryEditor = PhAllocateZero(sizeof(PH_SHOW_MEMORY_EDITOR));\n                                        showMemoryEditor->ProcessId = processItem->ProcessId;\n                                        showMemoryEditor->BaseAddress = memoryItem->BaseAddress;\n                                        showMemoryEditor->RegionSize = memoryItem->RegionSize;\n                                        showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)address - (ULONG_PTR)memoryItem->BaseAddress);\n                                        showMemoryEditor->SelectLength = 0;\n\n                                        SystemInformer_ShowMemoryEditor(showMemoryEditor);\n                                        break;\n                                    }\n                                    else\n                                    {\n                                        PhShowStatus(hwndDlg, L\"Unable to find the memory region for the selected address.\", STATUS_UNSUCCESSFUL, 0);\n                                    }\n                                }\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)memoryContext->TreeNewHandle);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            if (LOWORD(wParam) == 'K')\n            {\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    SetFocus(memoryContext->SearchboxHandle);\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    case WM_PH_INVOKE:\n        {\n            if (memoryContext->MemoryItemListValid)\n            {\n                TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &EmptyMemoryText, 0);\n\n                PhReplaceMemoryList(&memoryContext->ListContext, &memoryContext->MemoryItemList);\n            }\n            else if (memoryContext->LastRunStatus == ULONG_MAX)\n            {\n                TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &EmptyMemoryText, 0);\n                TreeNew_NodesStructured(memoryContext->ListContext.TreeNewHandle);\n            }\n            else\n            {\n                PPH_STRING message;\n\n                message = PhGetStatusMessage(memoryContext->LastRunStatus, 0);\n                PhMoveReference(&memoryContext->ErrorMessage, PhFormatString(L\"Unable to query memory information:\\n%s\", PhGetStringOrDefault(message, L\"Unknown error.\")));\n                TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &memoryContext->ErrorMessage->sr, 0);\n\n                PhReplaceMemoryList(&memoryContext->ListContext, NULL);\n\n                PhClearReference(&message);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpgmod.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <procprp.h>\n#include <procprpp.h>\n\n#include <cpysave.h>\n#include <emenu.h>\n\n#include <actions.h>\n#include <extmgri.h>\n#include <modprv.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <procprv.h>\n#include <settings.h>\n#include <verify.h>\n\nstatic CONST PH_STRINGREF EmptyModulesText = PH_STRINGREF_INIT(L\"There are no modules to display.\");\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ModuleAddedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;\n\n    // Parameter contains a pointer to the added module item.\n    PhReferenceObject(Parameter);\n    PhPushProviderEventQueue(&modulesContext->EventQueue, ProviderAddedEvent, Parameter, PhGetRunIdProvider(&modulesContext->ProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ModuleModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;\n\n    PhPushProviderEventQueue(&modulesContext->EventQueue, ProviderModifiedEvent, Parameter, PhGetRunIdProvider(&modulesContext->ProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ModuleRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;\n\n    PhPushProviderEventQueue(&modulesContext->EventQueue, ProviderRemovedEvent, Parameter, PhGetRunIdProvider(&modulesContext->ProviderRegistration));\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ModulesUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;\n\n    PostMessage(modulesContext->WindowHandle, WM_PH_MODULES_UPDATED, PhGetRunIdProvider(&modulesContext->ProviderRegistration), 0);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ModulesUpdateAutomaticallyHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;\n\n    PhSetEnabledProvider(&modulesContext->ProviderRegistration, (BOOLEAN)PtrToUlong(Parameter));\n}\n\nVOID PhpInitializeModuleMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_MODULE_ITEM *Modules,\n    _In_ ULONG NumberOfModules\n    )\n{\n    if (NumberOfModules == 0)\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n    }\n    else if (NumberOfModules == 1)\n    {\n        // Nothing\n    }\n    else\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n        PhEnableEMenuItem(Menu, ID_MODULE_COPY, TRUE);\n    }\n}\n\nVOID PhShowModuleContextMenu(\n    _In_ HWND hwndDlg,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_MODULES_CONTEXT Context,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    )\n{\n    PPH_MODULE_ITEM *modules;\n    ULONG numberOfModules;\n\n    PhGetSelectedModuleItems(&Context->ListContext, &modules, &numberOfModules);\n\n    if (numberOfModules != 0)\n    {\n        PPH_EMENU menu;\n        PPH_EMENU_ITEM item;\n        PH_PLUGIN_MENU_INFORMATION menuInfo;\n\n        menu = PhCreateEMenu();\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MODULE_UNLOAD, L\"&Unload\\bDel\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MODULE_OPENFILELOCATION, L\"Open &file location\\bCtrl+Enter\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MODULE_PROPERTIES, L\"P&roperties\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MODULE_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n        PhSetFlagsEMenuItem(menu, ID_MODULE_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n        PhpInitializeModuleMenu(menu, ProcessItem->ProcessId, modules, numberOfModules);\n        PhInsertCopyCellEMenuItem(menu, ID_MODULE_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);\n\n        if (PhPluginsEnabled)\n        {\n            PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);\n            menuInfo.u.Module.ProcessId = ProcessItem->ProcessId;\n            menuInfo.u.Module.Modules = modules;\n            menuInfo.u.Module.NumberOfModules = numberOfModules;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing), &menuInfo);\n        }\n\n        item = PhShowEMenu(\n            menu,\n            hwndDlg,\n            PH_EMENU_SHOW_LEFTRIGHT,\n            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n            ContextMenu->Location.x,\n            ContextMenu->Location.y\n            );\n\n        if (item)\n        {\n            BOOLEAN handled = FALSE;\n\n            handled = PhHandleCopyCellEMenuItem(item);\n\n            if (!handled && PhPluginsEnabled)\n                handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n            if (!handled)\n                SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);\n        }\n\n        PhDestroyEMenu(menu);\n    }\n\n    PhFree(modules);\n}\n\nBOOLEAN PhpModulesTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PPH_MODULES_CONTEXT Context\n    )\n{\n    PPH_MODULE_NODE moduleNode = (PPH_MODULE_NODE)Node;\n    PPH_MODULE_ITEM moduleItem = moduleNode->ModuleItem;\n\n    switch (moduleItem->LoadReason)\n    {\n    case LoadReasonStaticDependency:\n    case LoadReasonStaticForwarderDependency:\n        {\n            if (Context->ListContext.HideStaticModules)\n                return FALSE;\n        }\n        break;\n    case LoadReasonDynamicForwarderDependency:\n    case LoadReasonDynamicLoad:\n        {\n            if (Context->ListContext.HideDynamicModules)\n                return FALSE;\n        }\n        break;\n    }\n\n    switch (moduleItem->Type)\n    {\n    case PH_MODULE_TYPE_MAPPED_FILE:\n    case PH_MODULE_TYPE_MAPPED_IMAGE:\n        {\n            if (Context->ListContext.HideMappedModules)\n                return FALSE;\n        }\n        break;\n    }\n\n    if (Context->ListContext.HideSignedModules && moduleItem->VerifyResult == VrTrusted)\n        return FALSE;\n\n    if (\n        PhEnableImageCoherencySupport &&\n        Context->ListContext.HideLowImageCoherency &&\n        PhShouldShowModuleCoherency(moduleItem, TRUE)\n        )\n    {\n        return FALSE;\n    }\n\n    if (\n        PhEnableProcessQueryStage2 &&\n        Context->ListContext.HideSystemModules &&\n        moduleItem->VerifyResult == VrTrusted &&\n        PhEqualStringRef2(&moduleItem->VerifySignerName->sr, L\"Microsoft Windows\", TRUE)\n        )\n    {\n        return FALSE;\n    }\n\n    if (Context->ListContext.HideImageKnownDll && moduleItem->ImageKnownDll)\n        return FALSE;\n\n    if (!Context->SearchMatchHandle)\n        return TRUE;\n\n    // module node\n\n    if (!PhIsNullOrEmptyString(moduleNode->FileNameWin32))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleNode->FileNameWin32->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleNode->SizeText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleNode->SizeText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleNode->TimeStampText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleNode->TimeStampText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleNode->LoadTimeText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleNode->LoadTimeText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleNode->FileModifiedTimeText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleNode->FileModifiedTimeText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleNode->ImageCoherencyText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleNode->ImageCoherencyText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleNode->ServiceText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleNode->ServiceText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleNode->EnclaveSizeText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleNode->EnclaveSizeText->sr))\n            return TRUE;\n    }\n\n    // (dmex) TODO: Add search support for the following fields:\n    //ULONG Flags;\n    //ULONG Type;\n    //USHORT ImageCharacteristics;\n    //USHORT ImageDllCharacteristics;\n\n    // module properties\n\n    if (moduleItem->BaseAddressString[0])\n    {\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, moduleItem->BaseAddressString))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleItem->Name))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleItem->Name->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleItem->FileName))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleItem->FileName->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleItem->VersionInfo.CompanyName))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleItem->VersionInfo.CompanyName->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleItem->VersionInfo.FileDescription))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleItem->VersionInfo.FileDescription->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleItem->VersionInfo.FileVersion))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleItem->VersionInfo.FileVersion->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleItem->VersionInfo.ProductName))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleItem->VersionInfo.ProductName->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(moduleItem->VerifySignerName))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &moduleItem->VerifySignerName->sr))\n            return TRUE;\n    }\n\n    if (moduleItem->EntryPointAddressString[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, moduleItem->EntryPointAddressString))\n            return TRUE;\n    }\n\n    if (moduleItem->ParentBaseAddressString[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, moduleItem->ParentBaseAddressString))\n            return TRUE;\n    }\n\n    switch (moduleItem->LoadReason)\n    {\n    case LoadReasonStaticDependency:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Static dependency\"))\n            return TRUE;\n        break;\n    case LoadReasonStaticForwarderDependency:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Static forwarder dependency\"))\n            return TRUE;\n        break;\n    case LoadReasonDynamicForwarderDependency:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Dynamic forwarder dependency\"))\n            return TRUE;\n        break;\n    case LoadReasonDelayloadDependency:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Delay load dependency\"))\n            return TRUE;\n        break;\n    case LoadReasonDynamicLoad:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Dynamic\"))\n            return TRUE;\n        break;\n    case LoadReasonAsImageLoad:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Image\"))\n            return TRUE;\n        break;\n    case LoadReasonAsDataLoad:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Data\"))\n            return TRUE;\n        break;\n    }\n\n    switch (moduleItem->VerifyResult)\n    {\n    case VrNoSignature:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"No Signature\"))\n            return TRUE;\n        break;\n    case VrExpired:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Expired\"))\n            return TRUE;\n        break;\n    case VrRevoked:\n    case VrDistrust:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Revoked\"))\n            return TRUE;\n        break;\n    }\n\n    switch (moduleItem->VerifyResult)\n    {\n    case VrTrusted:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Trusted\"))\n            return TRUE;\n        break;\n    case VrNoSignature:\n    case VrExpired:\n    case VrRevoked:\n    case VrDistrust:\n    case VrUnknown:\n    case VrBadSignature:\n        if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"Bad\"))\n            return TRUE;\n        break;\n    }\n\n    if (moduleItem->EnclaveBaseAddress)\n    {\n        if (moduleItem->EnclaveBaseAddressString[0])\n        {\n            if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, moduleItem->EnclaveBaseAddressString))\n                return TRUE;\n        }\n\n        switch (moduleItem->EnclaveType)\n        {\n        case ENCLAVE_TYPE_SGX:\n            if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"SGX\"))\n                return TRUE;\n            break;\n        case ENCLAVE_TYPE_SGX2:\n            if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"SGX2\"))\n                return TRUE;\n            break;\n        case ENCLAVE_TYPE_VBS:\n            if (PhSearchControlMatchZ(Context->SearchMatchHandle, L\"VBS\"))\n                return TRUE;\n            break;\n        }\n    }\n\n    return FALSE;\n}\n\nVOID PhpPopulateTableWithProcessModuleNodes(\n    _In_ HWND TreeListHandle,\n    _In_ PPH_MODULE_NODE Node,\n    _In_ ULONG Level,\n    _In_ PPH_STRING **Table,\n    _Inout_ PULONG Index,\n    _In_ PULONG DisplayToId,\n    _In_ ULONG Columns\n    )\n{\n    for (ULONG i = 0; i < Columns; i++)\n    {\n        PH_TREENEW_GET_CELL_TEXT getCellText;\n        PPH_STRING text;\n\n        getCellText.Node = &Node->Node;\n        getCellText.Id = DisplayToId[i];\n        PhInitializeEmptyStringRef(&getCellText.Text);\n        TreeNew_GetCellText(TreeListHandle, &getCellText);\n\n        if (i != 0)\n        {\n            if (getCellText.Text.Length == 0)\n                text = PhReferenceEmptyString();\n            else\n                text = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length);\n        }\n        else\n        {\n            // If this is the first column in the row, add some indentation.\n            text = PhaCreateStringEx(\n                NULL,\n                getCellText.Text.Length + UInt32x32To64(Level, 2) * sizeof(WCHAR)\n                );\n            wmemset(text->Buffer, L' ', UInt32x32To64(Level, 2));\n            memcpy(&text->Buffer[UInt32x32To64(Level, 2)], getCellText.Text.Buffer, getCellText.Text.Length);\n        }\n\n        Table[*Index][i] = text;\n    }\n\n    (*Index)++;\n\n    // Process the children.\n    for (ULONG i = 0; i < Node->Children->Count; i++)\n    {\n        PhpPopulateTableWithProcessModuleNodes(\n            TreeListHandle,\n            Node->Children->Items[i],\n            Level + 1,\n            Table,\n            Index,\n            DisplayToId,\n            Columns\n            );\n    }\n}\n\nPPH_LIST PhpGetProcessModuleTreeListLines(\n    _In_ HWND TreeListHandle,\n    _In_ ULONG NumberOfNodes,\n    _In_ PPH_LIST RootNodes,\n    _In_ ULONG Mode\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_LIST lines;\n    // The number of rows in the table (including +1 for the column headers).\n    ULONG rows;\n    // The number of columns.\n    ULONG columns;\n    // A column display index to ID map.\n    PULONG displayToId;\n    // A column display index to text map.\n    PWSTR *displayToText;\n    // The actual string table.\n    PPH_STRING **table;\n    ULONG i;\n    ULONG j;\n\n    // Use a local auto-pool to make memory management a bit less painful.\n    PhInitializeAutoPool(&autoPool);\n\n    rows = NumberOfNodes + 1;\n\n    // Create the display index to ID map.\n    PhMapDisplayIndexTreeNew(TreeListHandle, &displayToId, &displayToText, &columns);\n\n    PhaCreateTextTable(&table, rows, columns);\n\n    // Populate the first row with the column headers.\n    for (i = 0; i < columns; i++)\n    {\n        table[0][i] = PhaCreateString(displayToText[i]);\n    }\n\n    // Go through the nodes in the process tree and populate each cell of the table.\n\n    j = 1; // index starts at one because the first row contains the column headers.\n\n    for (i = 0; i < RootNodes->Count; i++)\n    {\n        PhpPopulateTableWithProcessModuleNodes(\n            TreeListHandle,\n            RootNodes->Items[i],\n            0,\n            table,\n            &j,\n            displayToId,\n            columns\n            );\n    }\n\n    PhFree(displayToId);\n    PhFree(displayToText);\n\n    lines = PhaFormatTextTable(table, rows, columns, Mode);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return lines;\n}\n\nVOID PhpProcessModulesSave(\n    _In_ PPH_MODULES_CONTEXT ModulesContext\n    )\n{\n    static PH_FILETYPE_FILTER filters[] =\n    {\n        { L\"Text files (*.txt;*.log)\", L\"*.txt;*.log\" },\n        { L\"Comma-separated values (*.csv)\", L\"*.csv\" },\n        { L\"All files (*.*)\", L\"*.*\" }\n    };\n    PVOID fileDialog = PhCreateSaveFileDialog();\n    PH_FORMAT format[4];\n    PPH_PROCESS_ITEM processItem;\n\n    processItem = PhReferenceProcessItem(ModulesContext->Provider->ProcessId);\n    PhInitFormatS(&format[0], L\"System Informer (\");\n    PhInitFormatS(&format[1], processItem ? PhGetStringOrDefault(processItem->ProcessName, L\"Unknown process\") : L\"Unknown process\");\n    PhInitFormatS(&format[2], L\") Modules\");\n    PhInitFormatS(&format[3], L\".txt\");\n    if (processItem) PhDereferenceObject(processItem);\n\n    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n    PhSetFileDialogFileName(fileDialog, PH_AUTO_T(PH_STRING, PhFormat(format, 3, 60))->Buffer);\n\n    if (PhShowFileDialog(ModulesContext->WindowHandle, fileDialog))\n    {\n        NTSTATUS status;\n        PPH_STRING fileName;\n        ULONG filterIndex;\n        PPH_FILE_STREAM fileStream;\n\n        fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n        filterIndex = PhGetFileDialogFilterIndex(fileDialog);\n\n        if (NT_SUCCESS(status = PhCreateFileStream(\n            &fileStream,\n            fileName->Buffer,\n            FILE_GENERIC_WRITE,\n            FILE_SHARE_READ,\n            FILE_OVERWRITE_IF,\n            0\n            )))\n        {\n            ULONG mode;\n            PPH_LIST lines;\n\n            if (filterIndex == 2)\n                mode = PH_EXPORT_MODE_CSV;\n            else\n                mode = PH_EXPORT_MODE_TABS;\n\n            PhWriteStringAsUtf8FileStream(fileStream, (PPH_STRINGREF)&PhUnicodeByteOrderMark);\n\n            if (mode != PH_EXPORT_MODE_CSV)\n            {\n                PhWritePhTextHeader(fileStream);\n            }\n\n            lines = PhpGetProcessModuleTreeListLines(\n                ModulesContext->TreeNewHandle,\n                ModulesContext->ListContext.NodeList->Count,\n                ModulesContext->ListContext.NodeRootList,\n                mode\n                );\n\n            for (ULONG i = 0; i < lines->Count; i++)\n            {\n                PPH_STRING line;\n\n                line = lines->Items[i];\n                PhWriteStringAsUtf8FileStream(fileStream, &line->sr);\n                PhDereferenceObject(line);\n                PhWriteStringAsUtf8FileStream2(fileStream, L\"\\r\\n\");\n            }\n\n            PhDereferenceObject(lines);\n            PhDereferenceObject(fileStream);\n        }\n\n        if (!NT_SUCCESS(status))\n            PhShowStatus(ModulesContext->WindowHandle, L\"Unable to create the file\", status, 0);\n    }\n\n    PhFreeFileDialog(fileDialog);\n}\n\nVOID NTAPI PhpProcessModulesSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_MODULES_CONTEXT modulesContext = Context;\n\n    assert(modulesContext);\n\n    modulesContext->SearchMatchHandle = MatchHandle;\n\n    // Expand any hidden nodes to make search results visible.\n    PhExpandAllModuleNodes(&modulesContext->ListContext, TRUE);\n\n    PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport);\n}\n\nINT_PTR CALLBACK PhpProcessModulesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    LPPROPSHEETPAGE propSheetPage;\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n    PPH_MODULES_CONTEXT modulesContext;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))\n    {\n        modulesContext = (PPH_MODULES_CONTEXT)propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            modulesContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmModulesContextType, sizeof(PH_MODULES_CONTEXT)));\n            memset(modulesContext, 0, sizeof(PH_MODULES_CONTEXT));\n\n            modulesContext->WindowHandle = hwndDlg;\n            modulesContext->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            modulesContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_SEARCH);\n\n            modulesContext->Provider = PhCreateModuleProvider(\n                processItem->ProcessId\n                );\n            PhRegisterProvider(\n                &PhTertiaryProviderThread,\n                PhModuleProviderUpdate,\n                modulesContext->Provider,\n                &modulesContext->ProviderRegistration\n                );\n            PhRegisterCallback(\n                &modulesContext->Provider->ModuleAddedEvent,\n                ModuleAddedHandler,\n                modulesContext,\n                &modulesContext->AddedEventRegistration\n                );\n            PhRegisterCallback(\n                &modulesContext->Provider->ModuleModifiedEvent,\n                ModuleModifiedHandler,\n                modulesContext,\n                &modulesContext->ModifiedEventRegistration\n                );\n            PhRegisterCallback(\n                &modulesContext->Provider->ModuleRemovedEvent,\n                ModuleRemovedHandler,\n                modulesContext,\n                &modulesContext->RemovedEventRegistration\n                );\n            PhRegisterCallback(\n                &modulesContext->Provider->UpdatedEvent,\n                ModulesUpdatedHandler,\n                modulesContext,\n                &modulesContext->UpdatedEventRegistration\n                );\n\n            // Initialize the list.\n            PhInitializeModuleList(hwndDlg, modulesContext->TreeNewHandle, &modulesContext->ListContext);\n\n            if (PhTreeWindowFont)\n            {\n                modulesContext->TreeNewFont = PhDuplicateFont(PhTreeWindowFont);\n                SetWindowFont(modulesContext->TreeNewHandle, modulesContext->TreeNewFont, FALSE);\n            }\n\n            TreeNew_SetEmptyText(modulesContext->TreeNewHandle, &PhProcessPropPageLoadingText, 0);\n            PhInitializeProviderEventQueue(&modulesContext->EventQueue, 100);\n            modulesContext->LastRunStatus = -1;\n            modulesContext->ErrorMessage = NULL;\n            modulesContext->FilterEntry = PhAddTreeNewFilter(&modulesContext->ListContext.TreeFilterSupport, PhpModulesTreeFilterCallback, modulesContext);\n            // Initialize the CreateTime for the module timeline. (dmex)\n            modulesContext->ListContext.ProcessId = processItem->ProcessId;\n            modulesContext->ListContext.ProcessCreateTime = processItem->CreateTime;\n            modulesContext->ListContext.HasServices = processItem->ServiceList && processItem->ServiceList->Count != 0;\n            modulesContext->ListContext.BoldFont = PhDuplicateFontWithNewWeight(GetWindowFont(modulesContext->TreeNewHandle), FW_BOLD);\n\n            // Initialize the search box. (dmex)\n            PhCreateSearchControl(\n                hwndDlg,\n                modulesContext->SearchboxHandle,\n                L\"Search Modules (Ctrl+K)\",\n                PhpProcessModulesSearchControlCallback,\n                modulesContext\n                );\n\n            PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectCreate);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n                treeNewInfo.TreeNewHandle = modulesContext->TreeNewHandle;\n                treeNewInfo.CmData = &modulesContext->ListContext.Cm;\n                treeNewInfo.SystemContext = modulesContext;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackModuleTreeNewInitializing), &treeNewInfo);\n            }\n\n            PhLoadSettingsModuleList(&modulesContext->ListContext);\n\n            if (modulesContext->ListContext.ZeroPadAddresses)\n                modulesContext->Provider->ZeroPadAddresses = TRUE;\n\n            PhSetEnabledProvider(&modulesContext->ProviderRegistration, TRUE);\n            PhBoostProvider(&modulesContext->ProviderRegistration, NULL);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackUpdateAutomatically),\n                ModulesUpdateAutomaticallyHandler,\n                modulesContext,\n                &modulesContext->ChangedEventRegistration\n                );\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveTreeNewFilter(&modulesContext->ListContext.TreeFilterSupport, modulesContext->FilterEntry);\n\n            PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectDelete);\n\n            PhUnregisterCallback(\n                &modulesContext->Provider->ModuleAddedEvent,\n                &modulesContext->AddedEventRegistration\n                );\n            PhUnregisterCallback(\n                &modulesContext->Provider->ModuleModifiedEvent,\n                &modulesContext->ModifiedEventRegistration\n                );\n            PhUnregisterCallback(\n                &modulesContext->Provider->ModuleRemovedEvent,\n                &modulesContext->RemovedEventRegistration\n                );\n            PhUnregisterCallback(\n                &modulesContext->Provider->UpdatedEvent,\n                &modulesContext->UpdatedEventRegistration\n                );\n            PhUnregisterCallback(\n                PhGetGeneralCallback(GeneralCallbackUpdateAutomatically),\n                &modulesContext->ChangedEventRegistration\n                );\n\n            PhUnregisterProvider(&modulesContext->ProviderRegistration);\n            PhDereferenceObject(modulesContext->Provider);\n            PhDeleteProviderEventQueue(&modulesContext->EventQueue);\n\n            if (modulesContext->TreeNewFont)\n                DeleteFont(modulesContext->TreeNewFont);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n                treeNewInfo.TreeNewHandle = modulesContext->TreeNewHandle;\n                treeNewInfo.CmData = &modulesContext->ListContext.Cm;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackModuleTreeNewUninitializing), &treeNewInfo);\n            }\n\n            PhSaveSettingsModuleList(&modulesContext->ListContext);\n            PhDeleteModuleList(&modulesContext->ListContext);\n\n            if (modulesContext->ListContext.BoldFont)\n            {\n                DeleteFont(modulesContext->ListContext.BoldFont);\n            }\n\n            PhClearReference(&modulesContext->ErrorMessage);\n            PhFree(modulesContext);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, modulesContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, modulesContext->TreeNewHandle, dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            HFONT fontHandle = modulesContext->ListContext.BoldFont;\n            modulesContext->ListContext.BoldFont = PhDuplicateFontWithNewWeight(GetWindowFont(modulesContext->TreeNewHandle), FW_BOLD);\n            if (fontHandle) DeleteFont(fontHandle);\n\n            PhInvalidateAllModuleNodes(&modulesContext->ListContext);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (LOWORD(wParam))\n            {\n            case ID_SHOWCONTEXTMENU:\n                {\n                    PhShowModuleContextMenu(hwndDlg, processItem, modulesContext, (PPH_TREENEW_CONTEXT_MENU)lParam);\n                }\n                break;\n            case ID_MODULE_UNLOAD:\n                {\n                    PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);\n\n                    if (moduleItem)\n                    {\n                        PhReferenceObject(moduleItem);\n\n                        if (PhUiUnloadModule(hwndDlg, processItem->ProcessId, moduleItem))\n                            PhDeselectAllModuleNodes(&modulesContext->ListContext);\n\n                        PhDereferenceObject(moduleItem);\n                    }\n                }\n                break;\n            case ID_MODULE_OPENFILELOCATION:\n                {\n                    PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);\n\n                    if (moduleItem)\n                    {\n                        PPH_STRING fileNameWin32 = PH_AUTO(PhGetFileName(moduleItem->FileName));\n\n                        PhShellExecuteUserString(\n                            hwndDlg,\n                            SETTING_FILE_BROWSE_EXECUTABLE,\n                            PhGetString(fileNameWin32),\n                            FALSE,\n                            L\"Make sure the Explorer executable file is present.\"\n                            );\n                    }\n                }\n                break;\n            case ID_MODULE_PROPERTIES:\n                {\n                    PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);\n\n                    if (moduleItem)\n                    {\n                        PPH_STRING fileNameWin32 = PH_AUTO(PhGetFileName(moduleItem->FileName));\n\n                        PhShellExecuteUserString(\n                            hwndDlg,\n                            SETTING_PROGRAM_INSPECT_EXECUTABLES,\n                            PhGetString(fileNameWin32),\n                            FALSE,\n                            L\"Make sure the PE Viewer executable file is present.\"\n                            );\n                    }\n                }\n                break;\n            case ID_MODULE_COPY:\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(modulesContext->TreeNewHandle, 0);\n                    PhSetClipboardString(modulesContext->TreeNewHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            case IDC_FILTEROPTIONS:\n                {\n                    RECT rect;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM dynamicItem;\n                    PPH_EMENU_ITEM mappedItem;\n                    PPH_EMENU_ITEM staticItem;\n                    PPH_EMENU_ITEM verifiedItem;\n                    PPH_EMENU_ITEM systemItem;\n                    PPH_EMENU_ITEM coherencyItem;\n                    PPH_EMENU_ITEM knowndllsItem;\n                    PPH_EMENU_ITEM dotnetItem;\n                    PPH_EMENU_ITEM immersiveItem;\n                    PPH_EMENU_ITEM relocatedItem;\n                    PPH_EMENU_ITEM untrustedItem;\n                    PPH_EMENU_ITEM systemHighlightItem;\n                    PPH_EMENU_ITEM coherencyHighlightItem;\n                    PPH_EMENU_ITEM knowndllsHighlightItem;\n                    PPH_EMENU_ITEM zeroPadItem;\n                    PPH_EMENU_ITEM selectedItem;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect))\n                        break;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, dynamicItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_DYNAMIC_OPTION, L\"Hide dynamic\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, mappedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MAPPED_OPTION, L\"Hide mapped\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, staticItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_STATIC_OPTION, L\"Hide static\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, verifiedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_SIGNED_OPTION, L\"Hide verified\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, systemItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_SYSTEM_OPTION, L\"Hide system\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, coherencyItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_LOWIMAGECOHERENCY_OPTION, L\"Hide low image coherency\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, knowndllsItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_IMAGEKNOWNDLL_OPTION, L\"Hide knowndlls images\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, dotnetItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION, L\"Highlight .NET modules\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, immersiveItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION, L\"Highlight immersive modules\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, relocatedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION, L\"Highlight relocated modules\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, untrustedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION, L\"Highlight untrusted modules\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, systemHighlightItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_SYSTEM_OPTION, L\"Highlight system modules\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, coherencyHighlightItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_LOWIMAGECOHERENCY_OPTION, L\"Highlight low image coherency\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, knowndllsHighlightItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_IMAGEKNOWNDLL, L\"Highlight knowndlls images\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, zeroPadItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_ZERO_PAD_ADDRESSES, L\"Zero pad addresses\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MODULE_FLAGS_LOAD_MODULE_OPTION, L\"Load module...\", NULL, NULL), ULONG_MAX);\n                    //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    //PhInsertEMenuItem(menu, stringsItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MODULE_STRINGS_OPTION, L\"Strings...\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MODULE_FLAGS_SAVE_OPTION, L\"Save...\", NULL, NULL), ULONG_MAX);\n\n                    if (modulesContext->ListContext.HideDynamicModules)\n                        dynamicItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HideMappedModules)\n                        mappedItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HideStaticModules)\n                        staticItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HideSignedModules)\n                        verifiedItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HideSystemModules)\n                        systemItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HideLowImageCoherency)\n                        coherencyItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HideImageKnownDll)\n                        knowndllsItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HighlightDotNetModules)\n                        dotnetItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HighlightImmersiveModules)\n                        immersiveItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HighlightRelocatedModules)\n                        relocatedItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HighlightUntrustedModules)\n                        untrustedItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HighlightSystemModules)\n                        systemHighlightItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HighlightLowImageCoherency)\n                        coherencyHighlightItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.HighlightImageKnownDll)\n                        knowndllsHighlightItem->Flags |= PH_EMENU_CHECKED;\n                    if (modulesContext->ListContext.ZeroPadAddresses)\n                        zeroPadItem->Flags |= PH_EMENU_CHECKED;\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        rect.left,\n                        rect.bottom\n                        );\n\n                    if (selectedItem && selectedItem->Id)\n                    {\n                        if (selectedItem->Id == PH_MODULE_FLAGS_LOAD_MODULE_OPTION)\n                        {\n                            if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) && !PhShowConfirmMessage(\n                                hwndDlg,\n                                L\"load\",\n                                L\"a module\",\n                                L\"Some programs may restrict access or ban your account when loading modules into the process.\",\n                                FALSE\n                                ))\n                            {\n                                break;\n                            }\n\n                            PhReferenceObject(processItem);\n                            PhUiLoadDllProcess(hwndDlg, processItem);\n                            PhDereferenceObject(processItem);\n                        }\n                        else if (selectedItem->Id == PH_MODULE_FLAGS_MODULE_STRINGS_OPTION)\n                        {\n                            // TODO\n                        }\n                        else if (selectedItem->Id == PH_MODULE_FLAGS_SAVE_OPTION)\n                        {\n                            PhpProcessModulesSave(modulesContext);\n                        }\n                        else if (selectedItem->Id == PH_MODULE_FLAGS_ZERO_PAD_ADDRESSES)\n                        {\n                            PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id);\n                            PhSaveSettingsModuleList(&modulesContext->ListContext);\n\n                            PhInvalidateAllModuleBaseAddressNodes(&modulesContext->ListContext);\n                        }\n                        else\n                        {\n                            PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id);\n                            PhSaveSettingsModuleList(&modulesContext->ListContext);\n                            PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport);\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_SETACTIVE:\n                PhSetEnabledProvider(&modulesContext->ProviderRegistration, TRUE);\n                break;\n            case PSN_KILLACTIVE:\n                PhSetEnabledProvider(&modulesContext->ProviderRegistration, FALSE);\n                break;\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)modulesContext->TreeNewHandle);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            if (LOWORD(wParam) == 'K')\n            {\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    SetFocus(modulesContext->SearchboxHandle);\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    case WM_PH_MODULES_UPDATED:\n        {\n            ULONG upToRunId = (ULONG)wParam;\n            PPH_PROVIDER_EVENT events;\n            ULONG count;\n            ULONG i;\n\n            events = PhFlushProviderEventQueue(&modulesContext->EventQueue, upToRunId, &count);\n\n            if (events)\n            {\n                TreeNew_SetRedraw(modulesContext->TreeNewHandle, FALSE);\n\n                for (i = 0; i < count; i++)\n                {\n                    PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]);\n                    PPH_MODULE_ITEM moduleItem = PH_PROVIDER_EVENT_OBJECT(events[i]);\n\n                    switch (type)\n                    {\n                    case ProviderAddedEvent:\n                        PhAddModuleNode(&modulesContext->ListContext, moduleItem, events[i].RunId);\n                        PhDereferenceObject(moduleItem);\n                        break;\n                    case ProviderModifiedEvent:\n                        PhUpdateModuleNode(&modulesContext->ListContext, PhFindModuleNode(&modulesContext->ListContext, moduleItem));\n                        break;\n                    case ProviderRemovedEvent:\n                        PhRemoveModuleNode(&modulesContext->ListContext, PhFindModuleNode(&modulesContext->ListContext, moduleItem));\n                        break;\n                    }\n                }\n\n                PhFree(events);\n            }\n\n            PhTickModuleNodes(&modulesContext->ListContext);\n\n            if (count != 0)\n                TreeNew_SetRedraw(modulesContext->TreeNewHandle, TRUE);\n\n            // Refresh the visible nodes.\n            PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport);\n\n            if (modulesContext->LastRunStatus != modulesContext->Provider->RunStatus)\n            {\n                NTSTATUS status;\n                PPH_STRING message;\n\n                status = modulesContext->Provider->RunStatus;\n                modulesContext->LastRunStatus = status;\n\n                if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId))\n                    status = STATUS_SUCCESS;\n\n                if (NT_SUCCESS(status) || status == STATUS_PARTIAL_COPY) // partial when process exits (dmex)\n                {\n                    TreeNew_SetEmptyText(modulesContext->TreeNewHandle, &EmptyModulesText, 0);\n                }\n                else\n                {\n                    message = PhGetStatusMessage(status, 0);\n                    PhMoveReference(&modulesContext->ErrorMessage, PhFormatString(L\"Unable to query module information:\\n%s\", PhGetStringOrDefault(message, L\"Unknown error.\")));\n                    PhClearReference(&message);\n                    TreeNew_SetEmptyText(modulesContext->TreeNewHandle, &modulesContext->ErrorMessage->sr, 0);\n                }\n\n                InvalidateRect(modulesContext->TreeNewHandle, NULL, FALSE);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpgperf.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2019-2023\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <procprp.h>\n#include <procprpp.h>\n#include <procprv.h>\n#include <phsettings.h>\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhProcessPerformanceUpdateHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_PERFORMANCE_CONTEXT performanceContext = (PPH_PERFORMANCE_CONTEXT)Context;\n\n    if (performanceContext && performanceContext->Enabled)\n    {\n        PostMessage(performanceContext->WindowHandle, WM_PH_PERFORMANCE_UPDATE, 0, 0);\n    }\n}\n\nINT_PTR CALLBACK PhpProcessPerformanceDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    LPPROPSHEETPAGE propSheetPage;\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n    PPH_PERFORMANCE_CONTEXT performanceContext;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))\n    {\n        performanceContext = (PPH_PERFORMANCE_CONTEXT)propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            performanceContext = propPageContext->Context = PhAllocateZero(sizeof(PH_PERFORMANCE_CONTEXT));\n            performanceContext->WindowHandle = hwndDlg;\n            performanceContext->Enabled = TRUE;\n            performanceContext->WindowDpi = PhGetWindowDpi(hwndDlg);\n\n            // We have already set the group boxes to have WS_EX_TRANSPARENT to fix\n            // the drawing issue that arises when using WS_CLIPCHILDREN. However\n            // in removing the flicker from the graphs the group boxes will now flicker.\n            // It's a good tradeoff since no one stares at the group boxes.\n            PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN);\n\n            performanceContext->CpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPCPU);\n            performanceContext->PrivateBytesGroupBox = GetDlgItem(hwndDlg, IDC_GROUPPRIVATEBYTES);\n            performanceContext->IoGroupBox = GetDlgItem(hwndDlg, IDC_GROUPIO);\n\n            PhInitializeGraphState(&performanceContext->CpuGraphState);\n            PhInitializeGraphState(&performanceContext->PrivateGraphState);\n            PhInitializeGraphState(&performanceContext->IoGraphState);\n\n            performanceContext->CpuGraphHandle = GetDlgItem(hwndDlg, IDC_CPU);\n            PhSetWindowStyle(performanceContext->CpuGraphHandle, WS_BORDER, WS_BORDER);\n            Graph_SetTooltip(performanceContext->CpuGraphHandle, TRUE);\n            BringWindowToTop(performanceContext->CpuGraphHandle);\n\n            performanceContext->PrivateGraphHandle = GetDlgItem(hwndDlg, IDC_PRIVATEBYTES);\n            PhSetWindowStyle(performanceContext->PrivateGraphHandle, WS_BORDER, WS_BORDER);\n            Graph_SetTooltip(performanceContext->PrivateGraphHandle, TRUE);\n            BringWindowToTop(performanceContext->PrivateGraphHandle);\n\n            performanceContext->IoGraphHandle = GetDlgItem(hwndDlg, IDC_IO);\n            PhSetWindowStyle(performanceContext->IoGraphHandle, WS_BORDER, WS_BORDER);\n            Graph_SetTooltip(performanceContext->IoGraphHandle, TRUE);\n            BringWindowToTop(performanceContext->IoGraphHandle);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n                PhProcessPerformanceUpdateHandler,\n                performanceContext,\n                &performanceContext->ProcessesUpdatedRegistration\n                );\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhUnregisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n                &performanceContext->ProcessesUpdatedRegistration\n                );\n\n            PhDeleteGraphState(&performanceContext->CpuGraphState);\n            PhDeleteGraphState(&performanceContext->PrivateGraphState);\n            PhDeleteGraphState(&performanceContext->IoGraphState);\n\n            PhFree(performanceContext);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_SETACTIVE:\n                {\n                    performanceContext->Enabled = TRUE;\n\n                    performanceContext->CpuGraphState.Valid = FALSE;\n                    performanceContext->CpuGraphState.TooltipIndex = ULONG_MAX;\n                    performanceContext->PrivateGraphState.Valid = FALSE;\n                    performanceContext->PrivateGraphState.TooltipIndex = ULONG_MAX;\n                    performanceContext->IoGraphState.Valid = FALSE;\n                    performanceContext->IoGraphState.TooltipIndex = ULONG_MAX;\n\n                    if (performanceContext->CpuGraphHandle)\n                        Graph_Draw(performanceContext->CpuGraphHandle);\n                    if (performanceContext->PrivateGraphHandle)\n                        Graph_Draw(performanceContext->PrivateGraphHandle);\n                    if (performanceContext->IoGraphHandle)\n                        Graph_Draw(performanceContext->IoGraphHandle);\n                }\n                break;\n            case PSN_KILLACTIVE:\n                performanceContext->Enabled = FALSE;\n                break;\n            case GCN_GETDRAWINFO:\n                {\n                    PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header;\n                    PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;\n\n                    if (header->hwndFrom == performanceContext->CpuGraphHandle)\n                    {\n                        drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_USE_LINE_2 | (PhCsEnableGraphMaxText ? PH_GRAPH_LABEL_MAX_Y : 0);\n                        PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorCpuKernel, PhCsColorCpuUser, performanceContext->WindowDpi);\n\n                        PhGraphStateGetDrawInfo(\n                            &performanceContext->CpuGraphState,\n                            getDrawInfo,\n                            processItem->CpuKernelHistory.Count\n                            );\n\n                        if (!performanceContext->CpuGraphState.Valid)\n                        {\n                            PhCopyCircularBuffer_FLOAT(&processItem->CpuKernelHistory, performanceContext->CpuGraphState.Data1, drawInfo->LineDataCount);\n                            PhCopyCircularBuffer_FLOAT(&processItem->CpuUserHistory, performanceContext->CpuGraphState.Data2, drawInfo->LineDataCount);\n\n                            if (PhCsEnableGraphMaxScale)\n                            {\n                                FLOAT max = 0;\n\n                                if (PhCsEnableAvxSupport && drawInfo->LineDataCount > 128)\n                                {\n                                    max = PhAddPlusMaxMemorySingles(\n                                        performanceContext->CpuGraphState.Data1,\n                                        performanceContext->CpuGraphState.Data2,\n                                        drawInfo->LineDataCount\n                                        );\n                                }\n                                else\n                                {\n                                    for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                                    {\n                                        FLOAT data = performanceContext->CpuGraphState.Data1[i] +\n                                            performanceContext->CpuGraphState.Data2[i];\n\n                                        if (max < data)\n                                            max = data;\n                                    }\n                                }\n\n                                if (max != 0)\n                                {\n                                    PhDivideSinglesBySingle(\n                                        performanceContext->CpuGraphState.Data1,\n                                        max,\n                                        drawInfo->LineDataCount\n                                        );\n                                    PhDivideSinglesBySingle(\n                                        performanceContext->CpuGraphState.Data2,\n                                        max,\n                                        drawInfo->LineDataCount\n                                        );\n                                }\n\n                                drawInfo->LabelYFunction = PhSiDoubleLabelYFunction;\n                                drawInfo->LabelYFunctionParameter = max;\n                            }\n                            else\n                            {\n                                drawInfo->LabelYFunction = PhSiDoubleLabelYFunction;\n                                drawInfo->LabelYFunctionParameter = 1.0f;\n                            }\n\n                            performanceContext->CpuGraphState.Valid = TRUE;\n                        }\n\n                        if (PhCsGraphShowText)\n                        {\n                            HDC hdc;\n                            PH_FORMAT format[6];\n\n                            // %.2f%% (K: %.2f%%, U: %.2f%%)\n                            PhInitFormatF(&format[0], (processItem->CpuKernelUsage + processItem->CpuUserUsage) * 100.f, PhMaxPrecisionUnit);\n                            PhInitFormatS(&format[1], L\"% (K: \");\n                            PhInitFormatF(&format[2], processItem->CpuKernelUsage * 100.f, PhMaxPrecisionUnit);\n                            PhInitFormatS(&format[3], L\"%, U: \");\n                            PhInitFormatF(&format[4], processItem->CpuUserUsage * 100.f, PhMaxPrecisionUnit);\n                            PhInitFormatS(&format[5], L\"%)\");\n\n                            PhMoveReference(&performanceContext->CpuGraphState.Text, PhFormat(format, RTL_NUMBER_OF(format), 16));\n\n                            hdc = Graph_GetBufferedContext(performanceContext->CpuGraphHandle);\n                            PhSetGraphText(hdc, drawInfo, &performanceContext->CpuGraphState.Text->sr,\n                                &PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);\n                        }\n                        else\n                        {\n                            drawInfo->Text.Buffer = NULL;\n                        }\n                    }\n                    else if (header->hwndFrom == performanceContext->PrivateGraphHandle)\n                    {\n                        drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | (PhCsEnableGraphMaxText ? PH_GRAPH_LABEL_MAX_Y : 0);\n                        PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorPrivate, 0, performanceContext->WindowDpi);\n\n                        PhGraphStateGetDrawInfo(\n                            &performanceContext->PrivateGraphState,\n                            getDrawInfo,\n                            processItem->PrivateBytesHistory.Count\n                            );\n\n                        if (!performanceContext->PrivateGraphState.Valid)\n                        {\n                            FLOAT max = PhCsEnableGraphMaxScale ? 0.f : (FLOAT)processItem->VmCounters.PeakPagefileUsage;\n\n                            for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                            {\n                                FLOAT data = performanceContext->PrivateGraphState.Data1[i] =\n                                    (FLOAT)PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, i);\n\n                                if (max < data)\n                                    max = data;\n                            }\n\n                            if (max != 0)\n                            {\n                                // Scale the data.\n                                PhDivideSinglesBySingle(\n                                    performanceContext->PrivateGraphState.Data1,\n                                    max,\n                                    drawInfo->LineDataCount\n                                    );\n                            }\n\n                            drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                            drawInfo->LabelYFunctionParameter = max;\n\n                            performanceContext->PrivateGraphState.Valid = TRUE;\n                        }\n\n                        if (PhCsGraphShowText)\n                        {\n                            HDC hdc;\n                            PH_FORMAT format[1];\n\n                            PhInitFormatSize(&format[0], processItem->VmCounters.PagefileUsage);\n\n                            PhMoveReference(&performanceContext->PrivateGraphState.Text, PhFormat(format, RTL_NUMBER_OF(format), 0));\n\n                            hdc = Graph_GetBufferedContext(performanceContext->PrivateGraphHandle);\n                            PhSetGraphText(hdc, drawInfo, &performanceContext->PrivateGraphState.Text->sr,\n                                &PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);\n                        }\n                        else\n                        {\n                            drawInfo->Text.Buffer = NULL;\n                        }\n                    }\n                    else if (header->hwndFrom == performanceContext->IoGraphHandle)\n                    {\n                        drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;\n                        PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorIoReadOther, PhCsColorIoWrite, performanceContext->WindowDpi);\n\n                        PhGraphStateGetDrawInfo(\n                            &performanceContext->IoGraphState,\n                            getDrawInfo,\n                            processItem->IoReadHistory.Count\n                            );\n\n                        if (!performanceContext->IoGraphState.Valid)\n                        {\n                            ULONG i;\n                            FLOAT max = 0;\n\n                            for (i = 0; i < drawInfo->LineDataCount; i++)\n                            {\n                                FLOAT data1;\n                                FLOAT data2;\n\n                                performanceContext->IoGraphState.Data1[i] = data1 =\n                                    (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, i) +\n                                    (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, i);\n                                performanceContext->IoGraphState.Data2[i] = data2 =\n                                    (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, i);\n\n                                if (max < data1 + data2)\n                                    max = data1 + data2;\n                            }\n\n                            if (max != 0)\n                            {\n                                // Scale the data.\n\n                                PhDivideSinglesBySingle(\n                                    performanceContext->IoGraphState.Data1,\n                                    max,\n                                    drawInfo->LineDataCount\n                                    );\n                                PhDivideSinglesBySingle(\n                                    performanceContext->IoGraphState.Data2,\n                                    max,\n                                    drawInfo->LineDataCount\n                                    );\n                            }\n\n                            drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                            drawInfo->LabelYFunctionParameter = max;\n\n                            performanceContext->IoGraphState.Valid = TRUE;\n                        }\n\n                        if (PhCsGraphShowText)\n                        {\n                            HDC hdc;\n                            PH_FORMAT format[4];\n\n                            // R+O: %s, W: %s\n                            PhInitFormatS(&format[0], L\"R+O: \");\n                            PhInitFormatSize(&format[1], processItem->IoReadDelta.Delta + processItem->IoOtherDelta.Delta);\n                            PhInitFormatS(&format[2], L\", W: \");\n                            PhInitFormatSize(&format[3], processItem->IoWriteDelta.Delta);\n\n                            PhMoveReference(&performanceContext->IoGraphState.Text, PhFormat(format, RTL_NUMBER_OF(format), 64));\n\n                            hdc = Graph_GetBufferedContext(performanceContext->IoGraphHandle);\n                            PhSetGraphText(hdc, drawInfo, &performanceContext->IoGraphState.Text->sr,\n                                &PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);\n                        }\n                        else\n                        {\n                            drawInfo->Text.Buffer = NULL;\n                        }\n                    }\n                }\n                break;\n            case GCN_GETTOOLTIPTEXT:\n                {\n                    PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam;\n\n                    if (\n                        header->hwndFrom == performanceContext->CpuGraphHandle &&\n                        getTooltipText->Index < getTooltipText->TotalCount\n                        )\n                    {\n                        if (performanceContext->CpuGraphState.TooltipIndex != getTooltipText->Index)\n                        {\n                            FLOAT cpuKernel;\n                            FLOAT cpuUser;\n                            PH_FORMAT format[7];\n\n                            cpuKernel = PhGetItemCircularBuffer_FLOAT(&processItem->CpuKernelHistory, getTooltipText->Index);\n                            cpuUser = PhGetItemCircularBuffer_FLOAT(&processItem->CpuUserHistory, getTooltipText->Index);\n\n                            // %.2f%% (K: %.2f%%, U: %.2f%%)%s\\n%s\n                            PhInitFormatF(&format[0], (cpuKernel + cpuUser) * 100.f, PhMaxPrecisionUnit);\n                            PhInitFormatS(&format[1], L\"% (K: \");\n                            PhInitFormatF(&format[2], cpuKernel * 100.f, PhMaxPrecisionUnit);\n                            PhInitFormatS(&format[3], L\"%, U: \");\n                            PhInitFormatF(&format[4], cpuUser * 100.f, PhMaxPrecisionUnit);\n                            PhInitFormatS(&format[5], L\"%)\\n\");\n                            PhInitFormatSR(&format[6], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(processItem, getTooltipText->Index))->sr);\n\n                            PhMoveReference(&performanceContext->CpuGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 160));\n                        }\n\n                        getTooltipText->Text = performanceContext->CpuGraphState.TooltipText->sr;\n                    }\n                    else if (\n                        header->hwndFrom == performanceContext->PrivateGraphHandle &&\n                        getTooltipText->Index < getTooltipText->TotalCount\n                        )\n                    {\n                        if (performanceContext->PrivateGraphState.TooltipIndex != getTooltipText->Index)\n                        {\n                            SIZE_T privateBytes;\n                            PH_FORMAT format[3];\n\n                            privateBytes = PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, getTooltipText->Index);\n\n                            // %s\\n%s\n                            PhInitFormatSize(&format[0], privateBytes);\n                            PhInitFormatC(&format[1], L'\\n');\n                            PhInitFormatSR(&format[2], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(processItem, getTooltipText->Index))->sr);\n\n                            PhMoveReference(&performanceContext->PrivateGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 64));\n                        }\n\n                        getTooltipText->Text = performanceContext->PrivateGraphState.TooltipText->sr;\n                    }\n                    else if (\n                        header->hwndFrom == performanceContext->IoGraphHandle &&\n                        getTooltipText->Index < getTooltipText->TotalCount\n                        )\n                    {\n                        if (performanceContext->IoGraphState.TooltipIndex != getTooltipText->Index)\n                        {\n                            ULONG64 ioRead;\n                            ULONG64 ioWrite;\n                            ULONG64 ioOther;\n                            PH_FORMAT format[8];\n\n                            ioRead = PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, getTooltipText->Index);\n                            ioWrite = PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, getTooltipText->Index);\n                            ioOther = PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, getTooltipText->Index);\n\n                            // R: %s\\nW: %s\\nO: %s\\n%s\n                            PhInitFormatS(&format[0], L\"R: \");\n                            PhInitFormatSize(&format[1], ioRead);\n                            PhInitFormatS(&format[2], L\"\\nW: \");\n                            PhInitFormatSize(&format[3], ioWrite);\n                            PhInitFormatS(&format[4], L\"\\nO: \");\n                            PhInitFormatSize(&format[5], ioOther);\n                            PhInitFormatC(&format[6], L'\\n');\n                            PhInitFormatSR(&format[7], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(processItem, getTooltipText->Index))->sr);\n\n                            PhMoveReference(&performanceContext->IoGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 64));\n                        }\n\n                        getTooltipText->Text = performanceContext->IoGraphState.TooltipText->sr;\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            HDWP deferHandle;\n            RECT clientRect;\n            RECT margin;\n            RECT innerMargin;\n            LONG between;\n            LONG width;\n            LONG height;\n\n            margin.left = margin.top = margin.right = margin.bottom = PhGetDpi(13, performanceContext->WindowDpi);\n\n            innerMargin.top = PhGetDpi(20, performanceContext->WindowDpi);\n            innerMargin.left = innerMargin.right = innerMargin.bottom = PhGetDpi(10, performanceContext->WindowDpi);\n\n            between = PhGetDpi(3, performanceContext->WindowDpi);\n\n            performanceContext->CpuGraphState.Valid = FALSE;\n            performanceContext->CpuGraphState.TooltipIndex = ULONG_MAX;\n            performanceContext->PrivateGraphState.Valid = FALSE;\n            performanceContext->PrivateGraphState.TooltipIndex = ULONG_MAX;\n            performanceContext->IoGraphState.Valid = FALSE;\n            performanceContext->IoGraphState.TooltipIndex = ULONG_MAX;\n\n            if (!PhGetClientRect(hwndDlg, &clientRect))\n                break;\n\n            width = clientRect.right - margin.left - margin.right;\n            height = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3;\n\n            deferHandle = BeginDeferWindowPos(6);\n\n            deferHandle = DeferWindowPos(deferHandle, performanceContext->CpuGroupBox, NULL, margin.left, margin.top,\n                width, height, SWP_NOACTIVATE | SWP_NOZORDER);\n            deferHandle = DeferWindowPos(\n                deferHandle,\n                performanceContext->CpuGraphHandle,\n                NULL,\n                margin.left + innerMargin.left,\n                margin.top + innerMargin.top,\n                width - innerMargin.left - innerMargin.right,\n                height - innerMargin.top - innerMargin.bottom,\n                SWP_NOACTIVATE | SWP_NOZORDER\n                );\n\n            deferHandle = DeferWindowPos(deferHandle, performanceContext->PrivateBytesGroupBox, NULL, margin.left, margin.top + height + between,\n                width, height, SWP_NOACTIVATE | SWP_NOZORDER);\n            deferHandle = DeferWindowPos(\n                deferHandle,\n                performanceContext->PrivateGraphHandle,\n                NULL,\n                margin.left + innerMargin.left,\n                margin.top + height + between + innerMargin.top,\n                width - innerMargin.left - innerMargin.right,\n                height - innerMargin.top - innerMargin.bottom,\n                SWP_NOACTIVATE | SWP_NOZORDER\n                );\n\n            deferHandle = DeferWindowPos(deferHandle, performanceContext->IoGroupBox, NULL, margin.left, margin.top + (height + between) * 2,\n                width, height, SWP_NOACTIVATE | SWP_NOZORDER);\n            deferHandle = DeferWindowPos(\n                deferHandle,\n                performanceContext->IoGraphHandle,\n                NULL,\n                margin.left + innerMargin.left,\n                margin.top + (height + between) * 2 + innerMargin.top,\n                width - innerMargin.left - innerMargin.right,\n                height - innerMargin.top - innerMargin.bottom,\n                SWP_NOACTIVATE | SWP_NOZORDER\n                );\n\n            EndDeferWindowPos(deferHandle);\n        }\n        break;\n    case WM_PH_PERFORMANCE_UPDATE:\n        {\n            if (!(processItem->State & PH_PROCESS_ITEM_REMOVED))\n            {\n                performanceContext->CpuGraphState.Valid = FALSE;\n                Graph_Update(performanceContext->CpuGraphHandle);\n\n                performanceContext->PrivateGraphState.Valid = FALSE;\n                Graph_Update(performanceContext->PrivateGraphHandle);\n\n                performanceContext->IoGraphState.Valid = FALSE;\n                Graph_Update(performanceContext->IoGraphHandle);\n            }\n        }\n        break;\n    case WM_DPICHANGED_BEFOREPARENT:\n        {\n            performanceContext->WindowDpi = PhGetWindowDpi(hwndDlg);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpgsrv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <procprp.h>\n#include <procprv.h>\n\nstatic VOID PhpLayoutServiceListControl(\n    _In_ HWND hwndDlg,\n    _In_ HWND ServiceListHandle\n    )\n{\n    RECT rect;\n\n    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect))\n        return;\n\n    MapWindowRect(NULL, hwndDlg, &rect);\n\n    MoveWindow(\n        ServiceListHandle,\n        rect.left,\n        rect.top,\n        rect.right - rect.left,\n        rect.bottom - rect.top,\n        TRUE\n        );\n}\n\nINT_PTR CALLBACK PhpProcessServicesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n\n    if (!PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &propPageContext, &processItem))\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_SERVICE_ITEM *services;\n            ULONG numberOfServices;\n            ULONG i;\n            HWND serviceListHandle;\n\n            // Get a copy of the process' service list.\n\n            PhAcquireQueuedLockShared(&processItem->ServiceListLock);\n\n            numberOfServices = processItem->ServiceList->Count;\n            services = PhAllocate(numberOfServices * sizeof(PPH_SERVICE_ITEM));\n\n            {\n                ULONG enumerationKey = 0;\n                PPH_SERVICE_ITEM serviceItem;\n\n                i = 0;\n\n                while (PhEnumPointerList(processItem->ServiceList, &enumerationKey, &serviceItem))\n                {\n                    PhReferenceObject(serviceItem);\n                    services[i++] = serviceItem;\n                }\n            }\n\n            PhReleaseQueuedLockShared(&processItem->ServiceListLock);\n\n            serviceListHandle = PhCreateServiceListControl(\n                hwndDlg,\n                services,\n                numberOfServices\n                );\n            SendMessage(serviceListHandle, WM_PH_SET_LIST_VIEW_SETTINGS, 0, (LPARAM)SETTING_PROCESS_SERVICE_LIST_VIEW_COLUMNS);\n            ShowWindow(serviceListHandle, SW_SHOW);\n\n            propPageContext->Context = serviceListHandle;\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n\n                PhpLayoutServiceListControl(hwndDlg, (HWND)propPageContext->Context);\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhpLayoutServiceListControl(hwndDlg, (HWND)propPageContext->Context);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpgstat.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <phplug.h>\n#include <procprp.h>\n#include <procprpp.h>\n#include <procprv.h>\n\n#include <emenu.h>\n#include <settings.h>\n\ntypedef enum _PH_PROCESS_STATISTICS_CATEGORY\n{\n    PH_PROCESS_STATISTICS_CATEGORY_CPU,\n    PH_PROCESS_STATISTICS_CATEGORY_MEMORY,\n    PH_PROCESS_STATISTICS_CATEGORY_IO,\n    PH_PROCESS_STATISTICS_CATEGORY_OTHER,\n} PH_PROCESS_STATISTICS_CATEGORY;\n\ntypedef enum _PH_PROCESS_STATISTICS_INDEX\n{\n    PH_PROCESS_STATISTICS_INDEX_CPU,\n    PH_PROCESS_STATISTICS_INDEX_CPUUSER,\n    PH_PROCESS_STATISTICS_INDEX_CPUKERNEL,\n    PH_PROCESS_STATISTICS_INDEX_CPUAVERAGE,\n    PH_PROCESS_STATISTICS_INDEX_CPURELATIVE,\n    PH_PROCESS_STATISTICS_INDEX_CYCLES,\n    PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA,\n    PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES,\n    PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHESDELTA,\n    PH_PROCESS_STATISTICS_INDEX_KERNELTIME,\n    PH_PROCESS_STATISTICS_INDEX_KERNELDELTA,\n    PH_PROCESS_STATISTICS_INDEX_USERTIME,\n    PH_PROCESS_STATISTICS_INDEX_USERDELTA,\n    PH_PROCESS_STATISTICS_INDEX_TOTALTIME,\n    PH_PROCESS_STATISTICS_INDEX_TOTALDELTA,\n    PH_PROCESS_STATISTICS_INDEX_PRIORITY,\n\n    PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES,\n    PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA,\n    PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES,\n    PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE,\n    PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE,\n    PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS,\n    PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA,\n    PH_PROCESS_STATISTICS_INDEX_HARDFAULTS,\n    PH_PROCESS_STATISTICS_INDEX_HARDFAULTSDELTA,\n    PH_PROCESS_STATISTICS_INDEX_WORKINGSET,\n    PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET,\n    PH_PROCESS_STATISTICS_INDEX_PRIVATEWS,\n    PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS,\n    PH_PROCESS_STATISTICS_INDEX_SHAREDWS,\n    PH_PROCESS_STATISTICS_INDEX_SHAREDCOMMIT,\n    PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMIT,\n    PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATECOMMIT,\n    //PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMITLIMIT,\n    //PH_PROCESS_STATISTICS_INDEX_TOTALCOMMITLIMIT,\n    PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY,\n\n    PH_PROCESS_STATISTICS_INDEX_READS,\n    PH_PROCESS_STATISTICS_INDEX_READSDELTA,\n    PH_PROCESS_STATISTICS_INDEX_READBYTES,\n    PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA,\n    PH_PROCESS_STATISTICS_INDEX_WRITES,\n    PH_PROCESS_STATISTICS_INDEX_WRITESDELTA,\n    PH_PROCESS_STATISTICS_INDEX_WRITEBYTES,\n    PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA,\n    PH_PROCESS_STATISTICS_INDEX_OTHER,\n    PH_PROCESS_STATISTICS_INDEX_OTHERDELTA,\n    PH_PROCESS_STATISTICS_INDEX_OTHERBYTES,\n    PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA,\n    PH_PROCESS_STATISTICS_INDEX_IOTOTAL,\n    PH_PROCESS_STATISTICS_INDEX_IOTOTALDELTA,\n    PH_PROCESS_STATISTICS_INDEX_IOAVERAGE,\n    PH_PROCESS_STATISTICS_INDEX_IOPRIORITY,\n\n    PH_PROCESS_STATISTICS_INDEX_HANDLES,\n    PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES,\n    PH_PROCESS_STATISTICS_INDEX_GDIHANDLES,\n    PH_PROCESS_STATISTICS_INDEX_PEAKGDIHANDLES,\n    PH_PROCESS_STATISTICS_INDEX_USERHANDLES,\n    PH_PROCESS_STATISTICS_INDEX_PEAKUSERHANDLES,\n\n    PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL,\n    PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL,\n    PH_PROCESS_STATISTICS_INDEX_NONPAGED,\n    PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED,\n\n    PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME,\n    PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME,\n    PH_PROCESS_STATISTICS_INDEX_HANGCOUNT,\n    PH_PROCESS_STATISTICS_INDEX_GHOSTCOUNT,\n    PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES,\n    PH_PROCESS_STATISTICS_INDEX_MOUSE,\n    PH_PROCESS_STATISTICS_INDEX_KEYBOARD,\n\n    PH_PROCESS_STATISTICS_INDEX_MAX,\n} PH_PROCESS_STATISTICS_INDEX;\n\nVOID PhpUpdateStatisticsAddListViewGroups(\n    _In_ PPH_STATISTICS_CONTEXT Context\n    )\n{\n    PhListView_EnableGroupView(Context->ListViewContext, TRUE);\n\n    PhListView_AddGroup(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, L\"CPU\");\n    PhListView_AddGroup(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, L\"Memory\");\n    PhListView_AddGroup(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, L\"I/O\");\n    PhListView_AddGroup(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, L\"Other\");\n\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CPU, L\"CPU\", (PVOID)PH_PROCESS_STATISTICS_INDEX_CPU);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CPUUSER, L\"CPU (user)\", (PVOID)PH_PROCESS_STATISTICS_INDEX_CPUUSER);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CPUKERNEL, L\"CPU (kernel)\", (PVOID)PH_PROCESS_STATISTICS_INDEX_CPUKERNEL);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CPUAVERAGE, L\"CPU (average)\", (PVOID)PH_PROCESS_STATISTICS_INDEX_CPUAVERAGE);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CPURELATIVE, L\"CPU (relative)\", (PVOID)PH_PROCESS_STATISTICS_INDEX_CPURELATIVE);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CYCLES, L\"Cycles\", (PVOID)PH_PROCESS_STATISTICS_INDEX_CYCLES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA, L\"Cycles delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, L\"Context switches\", (PVOID)PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHESDELTA, L\"Context switches delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHESDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_KERNELTIME, L\"Kernel time\", (PVOID)PH_PROCESS_STATISTICS_INDEX_KERNELTIME);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_KERNELDELTA, L\"Kernel delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_KERNELDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_USERTIME, L\"User time\", (PVOID)PH_PROCESS_STATISTICS_INDEX_USERTIME);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_USERDELTA, L\"User delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_USERDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_TOTALTIME, L\"Total time\", (PVOID)PH_PROCESS_STATISTICS_INDEX_TOTALTIME);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_TOTALDELTA, L\"Total delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_TOTALDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_PRIORITY, L\"Priority\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PRIORITY);\n\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, L\"Private bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA, L\"Private bytes delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, L\"Peak private bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, L\"Virtual size\", (PVOID)PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, L\"Peak virtual size\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, L\"Page faults\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA, L\"Page faults delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_HARDFAULTS, L\"Hard faults\", (PVOID)PH_PROCESS_STATISTICS_INDEX_HARDFAULTS);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_HARDFAULTSDELTA, L\"Hard faults delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_HARDFAULTSDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, L\"Working set\", (PVOID)PH_PROCESS_STATISTICS_INDEX_WORKINGSET);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, L\"Peak working set\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, L\"Private WS\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PRIVATEWS);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, L\"Shareable WS\", (PVOID)PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREDWS, L\"Shared WS\", (PVOID)PH_PROCESS_STATISTICS_INDEX_SHAREDWS);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL, L\"Paged pool bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL, L\"Peak paged pool bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_NONPAGED, L\"Nonpaged pool bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_NONPAGED);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED, L\"Peak nonpaged pool bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREDCOMMIT, L\"Shared commit\", (PVOID)PH_PROCESS_STATISTICS_INDEX_SHAREDCOMMIT);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMIT, L\"Private commit\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMIT);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATECOMMIT, L\"Peak private commit\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATECOMMIT);\n    //PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMITLIMIT, L\"Private commit limit\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMITLIMIT);\n    //PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_TOTALCOMMITLIMIT, L\"Total commit limit\", (PVOID)PH_PROCESS_STATISTICS_INDEX_TOTALCOMMITLIMIT);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, L\"Page priority\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY);\n\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READS, L\"Reads\", (PVOID)PH_PROCESS_STATISTICS_INDEX_READS);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READSDELTA, L\"Reads delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_READSDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READBYTES, L\"Read bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_READBYTES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA, L\"Read bytes delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITES, L\"Writes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_WRITES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITESDELTA, L\"Writes delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_WRITESDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, L\"Write bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_WRITEBYTES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA, L\"Write bytes delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHER, L\"Other\", (PVOID)PH_PROCESS_STATISTICS_INDEX_OTHER);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERDELTA, L\"Other delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_OTHERDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, L\"Other bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_OTHERBYTES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA, L\"Other bytes delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_IOTOTAL, L\"Total bytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_IOTOTAL);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_IOTOTALDELTA, L\"Total bytes delta\", (PVOID)PH_PROCESS_STATISTICS_INDEX_IOTOTALDELTA);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_IOAVERAGE, L\"Total bytes (average)\", (PVOID)PH_PROCESS_STATISTICS_INDEX_IOAVERAGE);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, L\"I/O priority\", (PVOID)PH_PROCESS_STATISTICS_INDEX_IOPRIORITY);\n\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANDLES, L\"Handles\", (PVOID)PH_PROCESS_STATISTICS_INDEX_HANDLES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, L\"Peak handles\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, L\"GDI handles\", (PVOID)PH_PROCESS_STATISTICS_INDEX_GDIHANDLES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_PEAKGDIHANDLES, L\"Peak GDI handles\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PEAKGDIHANDLES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, L\"USER handles\", (PVOID)PH_PROCESS_STATISTICS_INDEX_USERHANDLES);\n    PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_PEAKUSERHANDLES, L\"Peak USER handles\", (PVOID)PH_PROCESS_STATISTICS_INDEX_PEAKUSERHANDLES);\n\n    if (WindowsVersion >= WINDOWS_10_RS3)\n    {\n        PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME, L\"Running time\", (PVOID)PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME);\n        PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME, L\"Suspended time\", (PVOID)PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME);\n        PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANGCOUNT, L\"Hang count\", (PVOID)PH_PROCESS_STATISTICS_INDEX_HANGCOUNT);\n        PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GHOSTCOUNT, L\"Ghost count\", (PVOID)PH_PROCESS_STATISTICS_INDEX_GHOSTCOUNT);\n        //PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_DISKREAD, L\"BytesRead\", NULL);\n        //PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_DISKWRITE, L\"BytesWritten\", NULL);\n        PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, L\"NetworkTxRxBytes\", (PVOID)PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES);\n        //PhListView_AddGroupItem(Context->ListViewContext, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, L\"MBBTxRxBytes\", NULL);\n    }\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_PROCESS_STATS_EVENT notifyEvent;\n\n        notifyEvent.Version = 0;\n        notifyEvent.Type = 1;\n        notifyEvent.ProcessItem = Context->ProcessItem;\n        notifyEvent.Parameter = Context->ListViewHandle;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessStatsNotifyEvent), &notifyEvent);\n    }\n}\n\nVOID PhpUpdateProcessStatisticDelta(\n    _In_ NMLVDISPINFO* Entry,\n    _In_ ULONG_PTR Delta\n    )\n{\n    LONG_PTR delta = (LONG_PTR)Delta;\n\n    if (delta != 0)\n    {\n        PPH_STRING value;\n        PH_FORMAT format[2];\n\n        if (delta > 0)\n        {\n            PhInitFormatC(&format[0], L'+');\n        }\n        else\n        {\n            PhInitFormatC(&format[0], L'-');\n            delta = -delta;\n        }\n\n        format[1].Type = SizeFormatType | FormatUseRadix;\n        format[1].Radix = (UCHAR)PhMaxSizeUnit;\n        format[1].u.Size = delta;\n\n        value = PhFormat(format, 2, 0);\n        wcsncpy_s(Entry->item.pszText, Entry->item.cchTextMax, value->Buffer, _TRUNCATE);\n        PhDereferenceObject(value);\n    }\n    else\n    {\n        wcsncpy_s(Entry->item.pszText, Entry->item.cchTextMax, L\"0\", _TRUNCATE);\n    }\n}\n\nVOID PhpUpdateProcessStatisticDeltaBytes(\n    _In_ NMLVDISPINFO* Entry,\n    _In_ PH_UINT64_DELTA DeltaBuffer\n    )\n{\n    ULONG64 number = 0;\n\n    if (DeltaBuffer.Delta != DeltaBuffer.Value)\n    {\n        number = DeltaBuffer.Delta;\n        number *= 1000;\n        number /= PhCsUpdateInterval;\n    }\n\n    if (number != 0)\n    {\n        PPH_STRING value;\n        PH_FORMAT format[2];\n\n        PhInitFormatSize(&format[0], number);\n        PhInitFormatS(&format[1], L\"/s\");\n\n        value = PhFormat(format, 2, 0);\n        wcsncpy_s(Entry->item.pszText, Entry->item.cchTextMax, value->Buffer, _TRUNCATE);\n        PhDereferenceObject(value);\n    }\n    else\n    {\n        wcsncpy_s(Entry->item.pszText, Entry->item.cchTextMax, L\"0\", _TRUNCATE);\n    }\n}\n\nVOID PH_PROCESS_STATISTICS_FORMAT_F(\n    _In_ NMLVDISPINFO* Entry,\n    _In_ FLOAT Value\n    )\n{\n    PH_FORMAT format[2];\n    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n    // %.2f%%\n    PhInitFormatF(&format[0], (Value), PhMaxPrecisionUnit);\n    PhInitFormatC(&format[1], L'%');\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), NULL))\n    {\n        wcsncpy_s(Entry->item.pszText, Entry->item.cchTextMax, buffer, _TRUNCATE);\n    }\n}\n\nVOID PH_PROCESS_STATISTICS_FORMAT_I64U(\n    _In_ NMLVDISPINFO* Entry,\n    _In_ ULONG64 Value\n    )\n{\n    PH_FORMAT format[1];\n    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n    PhInitFormatI64UGroupDigits(&format[0], Value);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), NULL))\n    {\n        wcsncpy_s(Entry->item.pszText, Entry->item.cchTextMax, buffer, _TRUNCATE);\n    }\n}\n\nVOID PH_PROCESS_STATISTICS_FORMAT_SIZE(\n    _In_ NMLVDISPINFO* Entry,\n    _In_ ULONG64 Value\n    )\n{\n    PH_FORMAT format[1];\n    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n    PhInitFormatSize(&format[0], Value);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), NULL))\n    {\n        wcsncpy_s(Entry->item.pszText, Entry->item.cchTextMax, buffer, _TRUNCATE);\n    }\n}\n\nVOID PH_PROCESS_STATISTICS_FORMAT_TIME(\n    _In_ NMLVDISPINFO* Entry,\n    _In_ ULONG64 Value\n    )\n{\n    WCHAR buffer[PH_TIMESPAN_STR_LEN_1] = L\"\";\n\n    if (PhPrintTimeSpanToBuffer(Value, PH_TIMESPAN_DHMSM, buffer, sizeof(buffer), NULL))\n    {\n        wcsncpy_s(Entry->item.pszText, Entry->item.cchTextMax, buffer, _TRUNCATE);\n    }\n}\n\n#define PH_PROCESS_STATISTICS_UPDATE_MINMAX(Minimum, Maximum, Difference, Value) \\\n    if ((Value) != 0 && ((Minimum) == 0 || (Value) < (Minimum))) \\\n    (Minimum) = (Value); \\\n    if ((Value) != 0 && ((Maximum) == 0 || (Value) > (Maximum))) \\\n        (Maximum) = (Value); \\\n    (Difference) = (Maximum)-(Minimum);\n\n#define PH_PROCESS_STATISTICS_UPDATE_INCREMENTALMINMAX(Context, Type, Last, Minimum, Maximum, NewValue) \\\n    if ((Last).Value) \\\n    { \\\n        Type delta = (NewValue) - (Last).Value; \\\n        if (delta != 0 && ((Minimum) == 0 || delta < (Minimum))) \\\n            (Minimum) = delta; \\\n        if (delta != 0 && ((Maximum) == 0 || delta > (Maximum))) \\\n            (Maximum) = delta; \\\n    } PhUpdateDelta(&(Last), (NewValue));\n\nVOID PhUpdateProcessStatisticsValue(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_STATISTICS_CONTEXT Context\n    )\n{\n    Context->CpuUsage = ProcessItem->CpuUsage * 100;\n    Context->CpuUsageUser = ProcessItem->CpuUserUsage * 100;\n    Context->CpuUsageKernel = ProcessItem->CpuKernelUsage * 100;\n\n    if (FlagOn(PhProcessProviderFlagsMask, PH_PROCESS_PROVIDER_FLAG_AVERAGE))\n    {\n        Context->CpuUsageAverage = ProcessItem->CpuAverageUsage * 100;\n    }\n    else\n    {\n        FLOAT cpuSumValue = 0;\n        FLOAT cpuAverageValue = 0;\n\n        for (ULONG i = 0; i < ProcessItem->CpuKernelHistory.Count; i++)\n        {\n            cpuSumValue += PhGetItemCircularBuffer_FLOAT(&ProcessItem->CpuKernelHistory, i) +\n                PhGetItemCircularBuffer_FLOAT(&ProcessItem->CpuUserHistory, i);\n        }\n\n        if (ProcessItem->CpuKernelHistory.Count)\n        {\n            cpuAverageValue = (FLOAT)cpuSumValue / ProcessItem->CpuKernelHistory.Count;\n        }\n\n        Context->CpuUsageAverage = cpuAverageValue * 100;\n    }\n\n    Context->CpuUsageRelative = (FLOAT)(ProcessItem->CpuUsage * 100) * ProcessItem->AffinityPopulationCount;\n\n    {\n        ULONG64 cycleTime;\n\n        if (ProcessItem->QueryHandle && NT_SUCCESS(PhGetProcessCycleTime(ProcessItem->QueryHandle, &cycleTime)))\n        {\n            Context->CycleTime = cycleTime;\n            Context->GotCycles = TRUE;\n        }\n        else\n        {\n            Context->CycleTime = 0;\n            Context->GotCycles = FALSE;\n        }\n    }\n\n    Context->CycleTimeDelta = ProcessItem->CycleTimeDelta.Delta;\n    Context->ContextSwitches = ProcessItem->ContextSwitches;\n    Context->ContextSwitchesDelta = ProcessItem->ContextSwitchesDelta.Delta;\n    Context->KernelTime = ProcessItem->KernelTime.QuadPart;\n    Context->KernelTimeDelta = ProcessItem->CpuKernelDelta.Delta;\n    Context->UserTime = ProcessItem->UserTime.QuadPart;\n    Context->UserTimeDelta = ProcessItem->CpuUserDelta.Delta;\n    Context->BasePriority = ProcessItem->BasePriority;\n\n    Context->PagefileUsage = ProcessItem->PrivateBytesDelta.Value; // ProcessItem->VmCounters.PagefileUsage\n    Context->PagefileDelta = ProcessItem->PrivateBytesDelta.Delta;\n    Context->PeakPagefileUsage = ProcessItem->VmCounters.PeakPagefileUsage;\n    Context->VirtualSize = ProcessItem->VmCounters.VirtualSize;\n    Context->PeakVirtualSize = ProcessItem->VmCounters.PeakVirtualSize;\n    Context->PageFaultCount = ProcessItem->PageFaultsDelta.Value; // ProcessItem->VmCounters.PageFaultCount\n    Context->PageFaultsDelta = ProcessItem->PageFaultsDelta.Delta;\n    Context->HardFaultCount = ProcessItem->HardFaultsDelta.Value; // ProcessItem->HardFaultCount\n    Context->HardFaultsDelta = ProcessItem->HardFaultsDelta.Delta;\n    Context->WorkingSetSize = ProcessItem->VmCounters.WorkingSetSize;\n    Context->PeakWorkingSetSize = ProcessItem->VmCounters.PeakWorkingSetSize;\n\n    {\n        PH_PROCESS_WS_COUNTERS wsCounters;\n        PROCESS_JOB_MEMORY_INFO appMemoryInfo;\n        PROCESS_EXTENDED_ENERGY_VALUES processExtendedValues;\n\n        if (Context->ProcessHandle && NT_SUCCESS(PhGetProcessWsCounters(Context->ProcessHandle, &wsCounters)))\n        {\n            Context->NumberOfPrivatePages = wsCounters.NumberOfPrivatePages * PAGE_SIZE;\n            Context->NumberOfShareablePages = wsCounters.NumberOfShareablePages * PAGE_SIZE;\n            Context->NumberOfSharedPages = wsCounters.NumberOfSharedPages * PAGE_SIZE;\n        }\n        else\n        {\n            Context->NumberOfPrivatePages = ProcessItem->WorkingSetPrivateSize;\n            Context->NumberOfShareablePages = 0;\n            Context->NumberOfSharedPages = 0;\n        }\n\n        if (Context->ProcessHandle && NT_SUCCESS(PhGetProcessAppMemoryInformation(Context->ProcessHandle, &appMemoryInfo)))\n        {\n            Context->SharedCommitUsage = appMemoryInfo.SharedCommitUsage;\n            Context->PrivateCommitUsage = appMemoryInfo.PrivateCommitUsage;\n            Context->PeakPrivateCommitUsage = appMemoryInfo.PeakPrivateCommitUsage;\n        }\n        else\n        {\n            Context->SharedCommitUsage = 0;\n            Context->PrivateCommitUsage = 0;\n            Context->PeakPrivateCommitUsage = 0;\n        }\n\n        if (Context->ProcessHandle && NT_SUCCESS(PhGetProcessEnergyValues(Context->ProcessHandle, &processExtendedValues)))\n        {\n            PhUpdateDelta(&Context->MouseDelta, processExtendedValues.Extension.MouseInput);\n            PhUpdateDelta(&Context->KeyboardDelta, processExtendedValues.Extension.KeyboardInput);\n        }\n        else\n        {\n            //PhUpdateDelta(&Context->MouseDelta, 0);\n            //PhUpdateDelta(&Context->KeyboardDelta, 0);\n        }\n    }\n\n    Context->QuotaPagedPoolUsage = ProcessItem->VmCounters.QuotaPagedPoolUsage;\n    Context->QuotaPeakPagedPoolUsage = ProcessItem->VmCounters.QuotaPeakPagedPoolUsage;\n    Context->QuotaNonPagedPoolUsage = ProcessItem->VmCounters.QuotaNonPagedPoolUsage;\n    Context->QuotaPeakNonPagedPoolUsage = ProcessItem->VmCounters.QuotaPeakNonPagedPoolUsage;\n\n    //wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->PrivateWs, L\"N/A\"), _TRUNCATE);\n    //wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->ShareableWs, L\"N/A\"), _TRUNCATE);\n    //wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->SharedWs, L\"N/A\"), _TRUNCATE);\n    //wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->SharedCommitUsage, L\"N/A\"), _TRUNCATE);\n    //wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->PrivateCommitUsage, L\"N/A\"), _TRUNCATE);\n    //wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->PeakPrivateCommitUsage, L\"N/A\"), _TRUNCATE);\n\n    Context->ReadOperationCount = ProcessItem->IoCounters.ReadOperationCount;\n    Context->IoReadCountDelta = ProcessItem->IoReadCountDelta.Delta;\n    Context->ReadTransferCount = ProcessItem->IoCounters.ReadTransferCount;\n    Context->IoReadDelta = ProcessItem->IoReadDelta.Delta;\n\n    Context->WriteOperationCount = ProcessItem->IoCounters.WriteOperationCount;\n    Context->IoWriteCountDelta = ProcessItem->IoWriteCountDelta.Delta;\n    Context->WriteTransferCount = ProcessItem->IoCounters.WriteTransferCount;\n    Context->IoWriteDelta = ProcessItem->IoWriteDelta.Delta;\n\n    Context->OtherOperationCount = ProcessItem->IoCounters.OtherOperationCount;\n    Context->IoOtherCountDelta = ProcessItem->IoOtherCountDelta.Delta;\n    Context->OtherTransferCount = ProcessItem->IoCounters.OtherTransferCount;\n    Context->IoOtherDelta = ProcessItem->IoOtherDelta.Delta;\n\n    Context->IoTotalDelta = ProcessItem->IoReadDelta.Value + ProcessItem->IoWriteDelta.Value + ProcessItem->IoOtherDelta.Value;\n}\n\nVOID PhUpdateProcessStatisticsMinMax(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_STATISTICS_CONTEXT Context\n    )\n{\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->CpuUsageMin, Context->CpuUsageMax, Context->CpuUsageDiff, Context->CpuUsage);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->CpuUsageUserMin, Context->CpuUsageUserMax, Context->CpuUsageUserDiff, Context->CpuUsageUser);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->CpuUsageKernelMin, Context->CpuUsageKernelMax, Context->CpuUsageKernelDiff, Context->CpuUsageKernel);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->CpuUsageAverageMin, Context->CpuUsageAverageMax, Context->CpuUsageAverageDiff, Context->CpuUsageAverage);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->CpuUsageRelativeMin, Context->CpuUsageRelativeMax, Context->CpuUsageRelativeDiff, Context->CpuUsageRelative);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->CycleTimeMin, Context->CycleTimeMax, Context->CycleTimeDiff, Context->CycleTime);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->CycleTimeDeltaMin, Context->CycleTimeDeltaMax, Context->CycleTimeDeltaDiff, Context->CycleTimeDelta);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->ContextSwitchesMin, Context->ContextSwitchesMax, Context->ContextSwitchesDiff, Context->ContextSwitches);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->ContextSwitchesDeltaMin, Context->ContextSwitchesDeltaMax, Context->ContextSwitchesDeltaDiff, Context->ContextSwitchesDelta);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->KernelTimeMin, Context->KernelTimeMax, Context->KernelTimeDiff, Context->KernelTime);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->KernelTimeDeltaMin, Context->KernelTimeDeltaMax, Context->KernelTimeDeltaDiff, Context->KernelTimeDelta);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->UserTimeMin, Context->UserTimeMax, Context->UserTimeDiff, Context->UserTime);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->UserTimeDeltaMin, Context->UserTimeDeltaMax, Context->UserTimeDeltaDiff, Context->UserTimeDelta);\n\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->QuotaPagedPoolUsageMin, Context->QuotaPagedPoolUsageMax, Context->QuotaPagedPoolUsageDiff, Context->QuotaPagedPoolUsage);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->QuotaPeakPagedPoolUsageMin, Context->QuotaPeakPagedPoolUsageMax, Context->QuotaPeakPagedPoolUsageDiff, Context->QuotaPeakPagedPoolUsage);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->QuotaNonPagedPoolUsageMin, Context->QuotaNonPagedPoolUsageMax, Context->QuotaNonPagedPoolUsageDiff, Context->QuotaNonPagedPoolUsage);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->QuotaPeakNonPagedPoolUsageMin, Context->QuotaPeakNonPagedPoolUsageMax, Context->QuotaPeakNonPagedPoolUsageDiff, Context->QuotaPeakNonPagedPoolUsage);\n\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->PagefileUsageMin, Context->PagefileUsageMax, Context->PagefileUsageDiff, Context->PagefileUsage);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->PagefileDeltaMin, Context->PagefileDeltaMax, Context->PagefileDeltaDiff, Context->PagefileDelta);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->PeakPagefileUsageMin, Context->PeakPagefileUsageMax, Context->PeakPagefileUsageDiff, Context->PeakPagefileUsage);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->VirtualSizeMin, Context->VirtualSizeMax, Context->VirtualSizeDiff, Context->VirtualSize);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->PeakVirtualSizeMin, Context->PeakVirtualSizeMax, Context->PeakVirtualSizeDiff, Context->PeakVirtualSize);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->PageFaultCountMin, Context->PageFaultCountMax, Context->PageFaultCountDiff, Context->PageFaultCount);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->PageFaultsDeltaMin, Context->PageFaultsDeltaMax, Context->PageFaultsDeltaDiff, Context->PageFaultsDelta);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->HardFaultCountMin, Context->HardFaultCountMax, Context->HardFaultCountDiff, Context->HardFaultCount);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->HardFaultsDeltaMin, Context->HardFaultsDeltaMax, Context->HardFaultsDeltaDiff, Context->HardFaultsDelta);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->WorkingSetSizeMin, Context->WorkingSetSizeMax, Context->WorkingSetSizeDiff, Context->WorkingSetSize);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->PeakWorkingSetSizeMin, Context->PeakWorkingSetSizeMax, Context->PeakWorkingSetSizeDiff, Context->PeakWorkingSetSize);\n\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->ReadOperationCountMin, Context->ReadOperationCountMax, Context->ReadOperationCountDiff, Context->ReadOperationCount);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->IoReadCountDeltaMin, Context->IoReadCountDeltaMax, Context->IoReadCountDeltaDiff, Context->IoReadCountDelta);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->ReadTransferCountMin, Context->ReadTransferCountMax, Context->ReadTransferCountDiff, Context->ReadTransferCount);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->IoReadDeltaMin, Context->IoReadDeltaMax, Context->IoReadDeltaDiff, Context->IoReadDelta);\n\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->WriteOperationCountMin, Context->WriteOperationCountMax, Context->WriteOperationCountDiff, Context->WriteOperationCount);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->IoWriteCountDeltaMin, Context->IoWriteCountDeltaMax, Context->IoWriteCountDeltaDiff, Context->IoWriteCountDelta);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->WriteTransferCountMin, Context->WriteTransferCountMax, Context->WriteTransferCountDiff, Context->WriteTransferCount);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->IoWriteDeltaMin, Context->IoWriteDeltaMax, Context->IoWriteDeltaDiff, Context->IoWriteDelta);\n\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->OtherOperationCountMin, Context->OtherOperationCountMax, Context->OtherOperationCountDiff, Context->OtherOperationCount);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->IoOtherCountDeltaMin, Context->IoOtherCountDeltaMax, Context->IoOtherCountDeltaDiff, Context->IoOtherCountDelta);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->OtherTransferCountMin, Context->OtherTransferCountMax, Context->OtherTransferCountDiff, Context->OtherTransferCount);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->IoOtherDeltaMin, Context->IoOtherDeltaMax, Context->IoOtherDeltaDiff, Context->IoOtherDelta);\n\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->IoTotalMin, Context->IoTotalMax, Context->IoTotalDiff, Context->IoTotal);\n    PH_PROCESS_STATISTICS_UPDATE_MINMAX(Context->IoTotalDeltaMin, Context->IoTotalDeltaMax, Context->IoTotalDeltaDiff, Context->IoTotalDelta);\n}\n\nVOID PhpUpdateProcessStatistics(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_STATISTICS_CONTEXT Context\n    )\n{\n    PhUpdateProcessStatisticsValue(ProcessItem, Context);\n    PhUpdateProcessStatisticsMinMax(ProcessItem, Context);\n\n    if (ProcessItem->ProcessId == SYSTEM_PROCESS_ID)\n    {\n        PROCESS_HANDLE_INFORMATION handleInfo;\n        PROCESS_UPTIME_INFORMATION uptimeInfo;\n        ULONG objects;\n\n        if (NT_SUCCESS(PhGetSessionGuiResources(GR_GDIOBJECTS, &objects))) // GDI handles\n        {\n            PhMoveReference(&Context->GdiHandles, PhFormatUInt64(objects, TRUE));\n        }\n\n        if (NT_SUCCESS(PhGetSessionGuiResources(GR_USEROBJECTS, &objects))) // USER handles\n        {\n            PhMoveReference(&Context->UserHandles, PhFormatUInt64(objects, TRUE));\n        }\n\n        if (NT_SUCCESS(PhGetSessionGuiResources(GR_GDIOBJECTS_PEAK, &objects))) // GDI handles (Peak)\n        {\n            PhMoveReference(&Context->PeakGdiHandles, PhFormatUInt64(objects, TRUE));\n        }\n\n        if (NT_SUCCESS(PhGetSessionGuiResources(GR_USEROBJECTS_PEAK, &objects))) // USER handles (Peak)\n        {\n            PhMoveReference(&Context->PeakUserHandles, PhFormatUInt64(objects, TRUE));\n        }\n\n        if (ProcessItem->QueryHandle)\n        {\n            if (NT_SUCCESS(PhGetProcessHandleCount(ProcessItem->QueryHandle, &handleInfo)))\n            {\n                // The HighWatermark changed on Windows 10 and doesn't track the peak handle count,\n                // instead the value is now the maximum count of the handle freelist which decreases\n                // when deallocating. So we'll track and cache the highest value where possible. (dmex)\n                if (handleInfo.HandleCountHighWatermark > Context->PeakHandleCount)\n                    Context->PeakHandleCount = handleInfo.HandleCountHighWatermark;\n\n                PhMoveReference(&Context->PeakHandles, PhFormatUInt64(Context->PeakHandleCount, TRUE));\n            }\n\n            PhGetProcessPagePriority(ProcessItem->QueryHandle, &Context->PagePriority);\n            PhGetProcessIoPriority(ProcessItem->QueryHandle, &Context->IoPriority);\n\n            if (WindowsVersion >= WINDOWS_10_RS3 && NT_SUCCESS(PhGetProcessUptime(ProcessItem->QueryHandle, &uptimeInfo)))\n            {\n                Context->RunningTime = uptimeInfo.Uptime;\n                Context->SuspendedTime = uptimeInfo.SuspendedTime;\n                Context->HangCount = uptimeInfo.HangCount;\n                Context->GhostCount = uptimeInfo.GhostCount;\n            }\n        }\n    }\n    else if (ProcessItem->QueryHandle)\n    {\n        PROCESS_HANDLE_INFORMATION handleInfo;\n        PROCESS_UPTIME_INFORMATION uptimeInfo;\n        ULONG objects;\n        ULONG objectsTotal;\n\n        if (NT_SUCCESS(PhGetProcessHandleCount(ProcessItem->QueryHandle, &handleInfo)))\n        {\n            // The HighWatermark changed on Windows 10 and doesn't track the peak handle count,\n            // instead the value is now the maximum count of the handle freelist which decreases\n            // when deallocating. So we'll track and cache the highest value where possible. (dmex)\n            if (handleInfo.HandleCountHighWatermark > Context->PeakHandleCount)\n                Context->PeakHandleCount = handleInfo.HandleCountHighWatermark;\n\n            PhMoveReference(&Context->PeakHandles, PhFormatUInt64(Context->PeakHandleCount, TRUE));\n        }\n\n        if (NT_SUCCESS(PhGetProcessGuiResources(ProcessItem->QueryHandle, GR_GDIOBJECTS, &objects))) // GDI handles\n        {\n            if (!NT_SUCCESS(PhGetSessionGuiResources(GR_GDIOBJECTS, &objectsTotal)))\n                objectsTotal = 1;\n\n            PPH_STRING string = PhFormatUInt64(objects, TRUE);\n            PhMoveReference(&string, PhFormatString(L\"%s (%.2f%%)\", PhGetString(string), (FLOAT)objects / (FLOAT)objectsTotal * 100.0f));\n            PhMoveReference(&Context->GdiHandles, string);\n        }\n\n        if (NT_SUCCESS(PhGetProcessGuiResources(ProcessItem->QueryHandle, GR_USEROBJECTS, &objects))) // USER handles\n        {\n            if (!NT_SUCCESS(PhGetSessionGuiResources(GR_USEROBJECTS, &objectsTotal)))\n                objectsTotal = 1;\n\n            PPH_STRING string = PhFormatUInt64(objects, TRUE);\n            PhMoveReference(&string, PhFormatString(L\"%s (%.2f%%)\", PhGetString(string), (FLOAT)objects / (FLOAT)objectsTotal * 100.0f));\n            PhMoveReference(&Context->UserHandles, string);\n        }\n\n        if (NT_SUCCESS(PhGetProcessGuiResources(ProcessItem->QueryHandle, GR_GDIOBJECTS_PEAK, &objects))) // GDI handles (Peak)\n        {\n            if (!NT_SUCCESS(PhGetSessionGuiResources(GR_GDIOBJECTS_PEAK, &objectsTotal)))\n                objectsTotal = 1;\n\n            PPH_STRING string = PhFormatUInt64(objects, TRUE);\n            PhMoveReference(&string, PhFormatString(L\"%s (%.2f%%)\", PhGetString(string), (FLOAT)objects / (FLOAT)objectsTotal * 100.0f));\n            PhMoveReference(&Context->PeakGdiHandles, string);\n        }\n\n        if (NT_SUCCESS(PhGetProcessGuiResources(ProcessItem->QueryHandle, GR_USEROBJECTS_PEAK, &objects))) // USER handles (Peak)\n        {\n            if (!NT_SUCCESS(PhGetSessionGuiResources(GR_USEROBJECTS_PEAK, &objectsTotal)))\n                objectsTotal = 1;\n\n            PPH_STRING string = PhFormatUInt64(objects, TRUE);\n            PhMoveReference(&string, PhFormatString(L\"%s (%.2f%%)\", PhGetString(string), (FLOAT)objects / (FLOAT)objectsTotal * 100.0f));\n            PhMoveReference(&Context->PeakUserHandles, string);\n        }\n\n        PhGetProcessPagePriority(ProcessItem->QueryHandle, &Context->PagePriority);\n        PhGetProcessIoPriority(ProcessItem->QueryHandle, &Context->IoPriority);\n\n        if (WindowsVersion >= WINDOWS_10_RS3 && NT_SUCCESS(PhGetProcessUptime(ProcessItem->QueryHandle, &uptimeInfo)))\n        {\n            Context->RunningTime = uptimeInfo.Uptime;\n            Context->SuspendedTime = uptimeInfo.SuspendedTime;\n            Context->HangCount = uptimeInfo.HangCount;\n            Context->GhostCount = uptimeInfo.GhostCount;\n        }\n    }\n\n    if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64())\n    {\n        PVOID processes;\n        PSYSTEM_PROCESS_INFORMATION processInfo;\n        PSYSTEM_PROCESS_INFORMATION_EXTENSION processExtension;\n\n        if (NT_SUCCESS(PhEnumProcesses(&processes)))\n        {\n            processInfo = PhFindProcessInformation(processes, ProcessItem->ProcessId);\n\n            if (processInfo && (processExtension = PH_PROCESS_EXTENSION(processInfo)))\n            {\n                //Context->ContextSwitches = processExtension->ContextSwitches;\n                Context->NetworkTxRxBytes = processExtension->EnergyValues.NetworkTxRxBytes;\n            }\n\n            PhFree(processes);\n        }\n    }\n\n    PhRedrawListViewItems(Context->ListViewHandle);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI PhpStatisticsUpdateHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_STATISTICS_CONTEXT statisticsContext = (PPH_STATISTICS_CONTEXT)Context;\n\n    if (statisticsContext->Enabled)\n    {\n        PostMessage(statisticsContext->WindowHandle, WM_PH_STATISTICS_UPDATE, 0, 0);\n    }\n}\n\nINT_PTR CALLBACK PhpProcessStatisticsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    LPPROPSHEETPAGE propSheetPage;\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n    PPH_STATISTICS_CONTEXT statisticsContext;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))\n    {\n        statisticsContext = (PPH_STATISTICS_CONTEXT)propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            statisticsContext = propPageContext->Context = PhAllocateZero(sizeof(PH_STATISTICS_CONTEXT));\n            statisticsContext->WindowHandle = hwndDlg;\n            statisticsContext->ListViewHandle = GetDlgItem(hwndDlg, IDC_STATISTICS_LIST);\n\n            if (PhTreeWindowFont)\n            {\n                statisticsContext->TreeNewFont = PhDuplicateFont(PhTreeWindowFont);\n                SetWindowFont(statisticsContext->ListViewHandle, statisticsContext->TreeNewFont, FALSE);\n            }\n\n            statisticsContext->ListViewContext = PhListView_Initialize(statisticsContext->ListViewHandle);\n            statisticsContext->ProcessItem = processItem;\n            statisticsContext->Enabled = TRUE;\n            statisticsContext->PagePriority = ULONG_MAX;\n            statisticsContext->IoPriority = LONG_MAX;\n\n            // Try to open a process handle with PROCESS_QUERY_INFORMATION access for WS information.\n            if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId))\n            {\n                PhOpenProcess(\n                    &statisticsContext->ProcessHandle,\n                    PROCESS_QUERY_INFORMATION,\n                    processItem->ProcessId\n                    );\n            }\n\n            PhSetListViewStyle(statisticsContext->ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(statisticsContext->ListViewHandle, L\"explorer\");\n            PhSetExtendedListView(statisticsContext->ListViewHandle);\n            PhListView_AddColumn(statisticsContext->ListViewContext, 0, 0, 0, LVCFMT_LEFT, 135, L\"Property\");\n            PhListView_AddColumn(statisticsContext->ListViewContext, 1, 1, 1, LVCFMT_LEFT, 150, L\"Value\");\n            PhListView_AddColumn(statisticsContext->ListViewContext, 2, 2, 2, LVCFMT_LEFT, 150, L\"Min\");\n            PhListView_AddColumn(statisticsContext->ListViewContext, 3, 3, 3, LVCFMT_LEFT, 150, L\"Max\");\n            PhListView_AddColumn(statisticsContext->ListViewContext, 4, 4, 4, LVCFMT_LEFT, 150, L\"Difference\");\n            ExtendedListView_SetTriState(statisticsContext->ListViewHandle, TRUE);\n            PhpUpdateStatisticsAddListViewGroups(statisticsContext);\n            PhLoadListViewColumnsFromSetting(SETTING_PROC_STAT_PROP_PAGE_GROUP_LIST_VIEW_COLUMNS, statisticsContext->ListViewHandle);\n            PhLoadListViewSortColumnsFromSetting(SETTING_PROC_STAT_PROP_PAGE_GROUP_LIST_VIEW_SORT, statisticsContext->ListViewHandle);\n            PhLoadListViewGroupStatesFromSetting(SETTING_PROC_STAT_PROP_PAGE_GROUP_STATES, statisticsContext->ListViewHandle);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n                PhpStatisticsUpdateHandler,\n                statisticsContext,\n                &statisticsContext->ProcessesUpdatedRegistration\n                );\n\n            PhpUpdateProcessStatistics(processItem, statisticsContext);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveListViewSortColumnsToSetting(SETTING_PROC_STAT_PROP_PAGE_GROUP_LIST_VIEW_SORT, statisticsContext->ListViewHandle);\n            PhSaveListViewColumnsToSetting(SETTING_PROC_STAT_PROP_PAGE_GROUP_LIST_VIEW_COLUMNS, statisticsContext->ListViewHandle);\n            PhSaveListViewGroupStatesToSetting(SETTING_PROC_STAT_PROP_PAGE_GROUP_STATES, statisticsContext->ListViewHandle);\n\n            PhUnregisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n                &statisticsContext->ProcessesUpdatedRegistration\n                );\n\n            if (statisticsContext->ListViewContext)\n            {\n                PhListView_Destroy(statisticsContext->ListViewContext);\n                statisticsContext->ListViewContext = NULL;\n            }\n\n            if (statisticsContext->TreeNewFont)\n                DeleteFont(statisticsContext->TreeNewFont);\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            if (statisticsContext->ProcessHandle)\n                NtClose(statisticsContext->ProcessHandle);\n\n            PhFree(statisticsContext);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, statisticsContext->ListViewHandle, dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n\n            //ExtendedListView_SetColumnWidth(statisticsContext->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            PhHandleListViewNotifyBehaviors(lParam, statisticsContext->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);\n\n            switch (header->code)\n            {\n            case PSN_SETACTIVE:\n                statisticsContext->Enabled = TRUE;\n                break;\n            case PSN_KILLACTIVE:\n                statisticsContext->Enabled = FALSE;\n                break;\n            case LVN_GETDISPINFO:\n                {\n                    NMLVDISPINFO* dispInfo = (NMLVDISPINFO*)header;\n\n                    if (dispInfo->item.iSubItem == 1)\n                    {\n                        if (FlagOn(dispInfo->item.mask, LVIF_TEXT))\n                        {\n                            switch (PtrToUlong((PVOID)dispInfo->item.lParam))\n                            {\n                            case PH_PROCESS_STATISTICS_INDEX_CPU:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsage);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUUSER:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageUser);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUKERNEL:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageKernel);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUAVERAGE:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageAverage);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPURELATIVE:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageRelative);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CYCLES:\n                                {\n                                    PH_FORMAT format[1];\n                                    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n                                    if (statisticsContext->GotCycles)\n                                    {\n                                        PhInitFormatI64UGroupDigits(&format[0], statisticsContext->CycleTime);\n                                    }\n                                    //else if (statisticsContext->CycleTimeDelta)\n                                    //{\n                                    //    PhInitFormatI64UGroupDigits(&format[0], statisticsContext->CycleTimeDelta);\n                                    //}\n                                    else\n                                    {\n                                        PhInitFormatS(&format[0], L\"N/A\");\n                                    }\n\n                                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), NULL))\n                                    {\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, buffer, _TRUNCATE);\n                                    }\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_KERNELTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->KernelTime);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_USERTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->UserTime);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_TOTALTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->KernelTime + statisticsContext->UserTime);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->CycleTimeDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ContextSwitches);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ContextSwitchesDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_KERNELDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->KernelTimeDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_USERDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->UserTimeDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_TOTALDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->KernelTimeDelta + statisticsContext->UserTimeDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIORITY:\n                                {\n                                    WCHAR priority[PH_INT32_STR_LEN_1] = L\"\";\n\n                                    PhPrintInt32(priority, statisticsContext->ProcessItem->BasePriority);\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, priority, _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ProcessItem->VmCounters.PagefileUsage);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA:\n                                PhpUpdateProcessStatisticDelta(dispInfo, statisticsContext->ProcessItem->PrivateBytesDelta.Delta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ProcessItem->VmCounters.PeakPagefileUsage);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ProcessItem->VmCounters.VirtualSize);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ProcessItem->VmCounters.PeakVirtualSize);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ProcessItem->VmCounters.PageFaultCount);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ProcessItem->PageFaultsDelta.Delta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HARDFAULTS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ProcessItem->HardFaultCount);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HARDFAULTSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ProcessItem->HardFaultsDelta.Delta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WORKINGSET:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ProcessItem->VmCounters.WorkingSetSize);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ProcessItem->VmCounters.PeakWorkingSetSize);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEWS:\n                                {\n                                    if (statisticsContext->NumberOfPrivatePages)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfPrivatePages);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS:\n                                {\n                                    if (statisticsContext->NumberOfShareablePages)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfShareablePages);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREDWS:\n                                {\n                                    if (statisticsContext->NumberOfSharedPages)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfSharedPages);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPagedPoolUsage);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPeakPagedPoolUsage);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_NONPAGED:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaNonPagedPoolUsage);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPeakNonPagedPoolUsage);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREDCOMMIT:\n                                {\n                                    if (statisticsContext->SharedCommitUsage)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->SharedCommitUsage);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMIT:\n                                {\n                                    if (statisticsContext->PrivateCommitUsage)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PrivateCommitUsage);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATECOMMIT:\n                                {\n                                    if (statisticsContext->PeakPrivateCommitUsage)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakPrivateCommitUsage);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY:\n                                {\n                                    if (statisticsContext->PagePriority != ULONG_MAX && statisticsContext->PagePriority <= MEMORY_PRIORITY_NORMAL)\n                                    {\n                                        const PH_STRINGREF pagePriority = PhPagePriorityNames[statisticsContext->PagePriority];\n\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, pagePriority.Buffer, _TRUNCATE);\n                                    }\n                                    else\n                                    {\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                    }\n                                }\n                                break;\n                                //case PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMITLIMIT:\n                                //    {\n                                //        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->PrivateCommitLimit, L\"N/A\"), _TRUNCATE);\n                                //    }\n                                //    break;\n                                //case PH_PROCESS_STATISTICS_INDEX_TOTALCOMMITLIMIT:\n                                //    {\n                                //        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->TotalCommitLimit, L\"N/A\"), _TRUNCATE);\n                                //    }\n                                //    break;\n                            case PH_PROCESS_STATISTICS_INDEX_READS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ReadOperationCount);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoReadCountDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ReadTransferCount);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoReadDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITES:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->WriteOperationCount);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoWriteCountDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->WriteTransferCount);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->IoWriteDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHER:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->OtherOperationCount);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoOtherCountDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->OtherTransferCount);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA:\n                                PhpUpdateProcessStatisticDeltaBytes(dispInfo, statisticsContext->ProcessItem->IoOtherDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOTOTAL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->IoTotalDelta);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOTOTALDELTA:\n                                {\n                                    PH_PROCESS_STATISTICS_FORMAT_SIZE(\n                                        dispInfo,\n                                        statisticsContext->ProcessItem->IoReadDelta.Delta +\n                                        statisticsContext->ProcessItem->IoWriteDelta.Delta +\n                                        statisticsContext->ProcessItem->IoOtherDelta.Delta\n                                        );\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOAVERAGE:\n                                {\n                                    PH_FORMAT format[2];\n                                    SIZE_T returnLength;\n                                    FLOAT cpuSumValue = 0;\n                                    FLOAT cpuAverageValue = 0;\n                                    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n                                    for (ULONG i = 0; i < statisticsContext->ProcessItem->IoReadHistory.Count; i++)\n                                    {\n                                        cpuSumValue += (FLOAT)PhGetItemCircularBuffer_ULONG64(&statisticsContext->ProcessItem->IoReadHistory, i) +\n                                            (FLOAT)PhGetItemCircularBuffer_ULONG64(&statisticsContext->ProcessItem->IoWriteHistory, i) +\n                                            (FLOAT)PhGetItemCircularBuffer_ULONG64(&statisticsContext->ProcessItem->IoOtherHistory, i);\n                                    }\n\n                                    if (statisticsContext->ProcessItem->IoReadHistory.Count)\n                                    {\n                                        cpuAverageValue = (FLOAT)cpuSumValue / statisticsContext->ProcessItem->IoReadHistory.Count;\n                                    }\n\n                                    PhInitFormatSize(&format[0], (ULONG64)cpuAverageValue);\n                                    PhInitFormatS(&format[1], L\"/s\");\n\n                                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n                                    {\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, buffer, _TRUNCATE);\n                                    }\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOPRIORITY:\n                                {\n                                    if (statisticsContext->IoPriority != LONG_MAX && statisticsContext->IoPriority >= IoPriorityVeryLow && statisticsContext->IoPriority <= MaxIoPriorityTypes)\n                                    {\n                                        const PH_STRINGREF ioPriority = PhIoPriorityHintNames[statisticsContext->IoPriority];\n\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, ioPriority.Buffer, _TRUNCATE);\n                                    }\n                                    else\n                                    {\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                    }\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HANDLES:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ProcessItem->NumberOfHandles);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES:\n                                {\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->PeakHandles, L\"N/A\"), _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_GDIHANDLES:\n                                {\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->GdiHandles, L\"N/A\"), _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKGDIHANDLES:\n                                {\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->PeakGdiHandles, L\"N/A\"), _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_USERHANDLES:\n                                {\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->UserHandles, L\"N/A\"), _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKUSERHANDLES:\n                                {\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, PhGetStringOrDefault(statisticsContext->PeakUserHandles, L\"N/A\"), _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME:\n                                {\n                                    WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1] = L\"\";\n\n                                    PhPrintTimeSpan(timeSpan, statisticsContext->RunningTime, PH_TIMESPAN_HMSM);\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, timeSpan, _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME:\n                                {\n                                    WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1] = L\"\";\n\n                                    PhPrintTimeSpan(timeSpan, statisticsContext->SuspendedTime, PH_TIMESPAN_HMSM);\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, timeSpan, _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HANGCOUNT:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->HangCount);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_GHOSTCOUNT:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->GhostCount);\n                                break;\n                                //case PH_PROCESS_STATISTICS_INDEX_DISKREAD:\n                                //    {\n                                //        PPH_STRING value;\n                                //\n                                //        if (!statisticsContext->ProcessExtension)\n                                //            break;\n                                //\n                                //        value = PhFormatUInt64(statisticsContext->ProcessExtension->DiskCounters.BytesRead, TRUE);\n                                //        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, value->Buffer, _TRUNCATE);\n                                //        PhDereferenceObject(value);\n                                //    }\n                                //    break;\n                                //case PH_PROCESS_STATISTICS_INDEX_DISKWRITE:\n                                //    {\n                                //        PPH_STRING value;\n                                //\n                                //        if (!statisticsContext->ProcessExtension)\n                                //            break;\n                                //\n                                //        value = PhFormatSize(statisticsContext->ProcessExtension->DiskCounters.BytesWritten, ULONG_MAX);\n                                //        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, value->Buffer, _TRUNCATE);\n                                //        PhDereferenceObject(value);\n                                //    }\n                                //    break;\n                            case PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NetworkTxRxBytes);\n                                break;\n                                //case PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES:\n                                //    {\n                                //        PPH_STRING value;\n                                //\n                                //        if (!statisticsContext->ProcessExtension)\n                                //            break;\n                                //\n                                //        value = PhFormatSize(statisticsContext->ProcessExtension->EnergyValues.MBBTxRxBytes, ULONG_MAX);\n                                //        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, value->Buffer, _TRUNCATE);\n                                //        PhDereferenceObject(value);\n                                //    }\n                                //    break;\n                            case PH_PROCESS_STATISTICS_INDEX_MOUSE:\n                                {\n                                    PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->MouseDelta.Value);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_KEYBOARD:\n                                {\n                                    PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->KeyboardDelta.Value);\n                                }\n                                break;\n                            default:\n                                {\n                                    if (PhPluginsEnabled)\n                                    {\n                                        PH_PLUGIN_PROCESS_STATS_EVENT notifyEvent;\n\n                                        notifyEvent.Version = 0;\n                                        notifyEvent.Type = 2;\n                                        notifyEvent.ProcessItem = statisticsContext->ProcessItem;\n                                        notifyEvent.Parameter = dispInfo;\n\n                                        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessStatsNotifyEvent), &notifyEvent);\n                                    }\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    if (FlagOn(dispInfo->item.mask, LVIF_TEXT))\n                    {\n                        if (dispInfo->item.iSubItem == 2)\n                        {\n                            switch (PtrToUlong((PVOID)dispInfo->item.lParam))\n                            {\n                            case PH_PROCESS_STATISTICS_INDEX_CPU:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUUSER:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageUserMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUKERNEL:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageKernelMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUAVERAGE:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageAverageMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPURELATIVE:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageRelativeMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CYCLES:\n                                {\n                                    PH_FORMAT format[1];\n                                    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n                                    if (statisticsContext->GotCycles)\n                                    {\n                                        PhInitFormatI64UGroupDigits(&format[0], statisticsContext->CycleTimeMin);\n                                    }\n                                    //else if (statisticsContext->CycleTimeDeltaMin)\n                                    //{\n                                    //    PhInitFormatI64UGroupDigits(&format[0], statisticsContext->CycleTimeDeltaMin);\n                                    //}\n                                    else\n                                    {\n                                        PhInitFormatS(&format[0], L\"N/A\");\n                                    }\n\n                                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), NULL))\n                                    {\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, buffer, _TRUNCATE);\n                                    }\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->CycleTimeDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ContextSwitchesMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ContextSwitchesDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_KERNELTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->KernelTimeMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_USERTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->UserTimeMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_TOTALTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->KernelTimeMin + statisticsContext->UserTimeMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_KERNELDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->KernelTimeDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_USERDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->UserTimeDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_TOTALDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->KernelTimeDeltaMin + statisticsContext->UserTimeDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIORITY:\n                                {\n                                    WCHAR priority[PH_INT32_STR_LEN_1] = L\"\";\n\n                                    PhPrintInt32(priority, statisticsContext->BasePriorityMin);\n\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, priority, _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PagefileUsageMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA:\n                                PhpUpdateProcessStatisticDelta(dispInfo, statisticsContext->PagefileDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakPagefileUsageMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->VirtualSizeMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakVirtualSizeMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->PageFaultCountMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->PageFaultsDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HARDFAULTS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->HardFaultCountMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HARDFAULTSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->HardFaultsDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WORKINGSET:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->WorkingSetSizeMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakWorkingSetSizeMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEWS:\n                                {\n                                    if (statisticsContext->NumberOfPrivatePagesMin)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfPrivatePagesMin);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS:\n                                {\n                                    if (statisticsContext->NumberOfShareablePagesMin)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfShareablePagesMin);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREDWS:\n                                {\n                                    if (statisticsContext->NumberOfSharedPagesMin)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfSharedPagesMin);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPagedPoolUsageMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPeakPagedPoolUsageMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_NONPAGED:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaNonPagedPoolUsageMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPeakNonPagedPoolUsageMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREDCOMMIT:\n                                {\n                                    if (statisticsContext->SharedCommitUsageMin)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->SharedCommitUsageMin);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMIT:\n                                {\n                                    if (statisticsContext->PrivateCommitUsageMin)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PrivateCommitUsageMin);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATECOMMIT:\n                                {\n                                    if (statisticsContext->PeakPrivateCommitUsageMin)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakPrivateCommitUsageMin);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY:\n                                {\n\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ReadOperationCountMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoReadCountDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ReadTransferCountMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoReadDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITES:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->WriteOperationCountMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoWriteCountDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->WriteTransferCountMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoWriteDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHER:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->OtherOperationCountMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoOtherCountDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->OtherTransferCountMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoOtherDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOTOTAL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->IoTotalDeltaMin);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOTOTALDELTA:\n                                {\n                                    PH_PROCESS_STATISTICS_FORMAT_SIZE(\n                                        dispInfo,\n                                        statisticsContext->ProcessItem->IoReadDelta.Delta +\n                                        statisticsContext->ProcessItem->IoWriteDelta.Delta +\n                                        statisticsContext->ProcessItem->IoOtherDelta.Delta\n                                    );\n                                }\n                                break;\n                            }\n                        }\n                        else if (dispInfo->item.iSubItem == 3)\n                        {\n                            switch (PtrToUlong((PVOID)dispInfo->item.lParam))\n                            {\n                            case PH_PROCESS_STATISTICS_INDEX_CPU:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUUSER:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageUserMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUKERNEL:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageKernelMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUAVERAGE:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageAverageMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPURELATIVE:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageRelativeMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CYCLES:\n                                {\n                                    PH_FORMAT format[1];\n                                    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n                                    if (statisticsContext->GotCycles)\n                                    {\n                                        PhInitFormatI64UGroupDigits(&format[0], statisticsContext->CycleTimeMax);\n                                    }\n                                    //else if (statisticsContext->CycleTimeDeltaMax)\n                                    //{\n                                    //    PhInitFormatI64UGroupDigits(&format[0], statisticsContext->CycleTimeDeltaMax);\n                                    //}\n                                    else\n                                    {\n                                        PhInitFormatS(&format[0], L\"N/A\");\n                                    }\n\n                                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), NULL))\n                                    {\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, buffer, _TRUNCATE);\n                                    }\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->CycleTimeDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ContextSwitchesMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ContextSwitchesDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_KERNELTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->KernelTimeMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_USERTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->UserTimeMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_TOTALTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->KernelTimeMax + statisticsContext->UserTimeMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_KERNELDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->KernelTimeDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_USERDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->UserTimeDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_TOTALDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->KernelTimeDeltaMax + statisticsContext->UserTimeDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIORITY:\n                                {\n                                    WCHAR priority[PH_INT32_STR_LEN_1] = L\"\";\n\n                                    PhPrintInt32(priority, statisticsContext->BasePriorityMax);\n\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, priority, _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PagefileUsageMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA:\n                                PhpUpdateProcessStatisticDelta(dispInfo, statisticsContext->PagefileDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakPagefileUsageMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->VirtualSizeMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakVirtualSizeMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->PageFaultCountMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->PageFaultsDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HARDFAULTS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->HardFaultCountMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HARDFAULTSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->HardFaultsDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WORKINGSET:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->WorkingSetSizeMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakWorkingSetSizeMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEWS:\n                                {\n                                    if (statisticsContext->NumberOfPrivatePagesMax)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfPrivatePagesMax);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS:\n                                {\n                                    if (statisticsContext->NumberOfShareablePagesMax)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfShareablePagesMax);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREDWS:\n                                {\n                                    if (statisticsContext->NumberOfSharedPagesMax)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfSharedPagesMax);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPagedPoolUsageMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPeakPagedPoolUsageMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_NONPAGED:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaNonPagedPoolUsageMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPeakNonPagedPoolUsageMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREDCOMMIT:\n                                {\n                                    if (statisticsContext->SharedCommitUsageMax)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->SharedCommitUsageMax);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMIT:\n                                {\n                                    if (statisticsContext->PrivateCommitUsageMax)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PrivateCommitUsageMax);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATECOMMIT:\n                                {\n                                    if (statisticsContext->PeakPrivateCommitUsageMax)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakPrivateCommitUsageMax);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY:\n                                {\n\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ReadOperationCountMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoReadCountDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ReadTransferCountMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoReadDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITES:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->WriteOperationCountMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoWriteCountDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->WriteTransferCountMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoWriteDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHER:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->OtherOperationCountMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoOtherCountDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->OtherTransferCountMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoOtherDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOTOTAL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->IoTotalDeltaMax);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOTOTALDELTA:\n                                break;\n                            }\n                        }\n                        else if (dispInfo->item.iSubItem == 4)\n                        {\n                            switch (PtrToUlong((PVOID)dispInfo->item.lParam))\n                            {\n                            case PH_PROCESS_STATISTICS_INDEX_CPU:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUUSER:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageUserDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUKERNEL:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageKernelDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPUAVERAGE:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageAverageDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CPURELATIVE:\n                                PH_PROCESS_STATISTICS_FORMAT_F(dispInfo, statisticsContext->CpuUsageRelativeDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CYCLES:\n                                {\n                                    PH_FORMAT format[1];\n                                    WCHAR buffer[PH_INT64_STR_LEN_1];\n\n                                    if (statisticsContext->GotCycles)\n                                    {\n                                        PhInitFormatI64UGroupDigits(&format[0], statisticsContext->CycleTimeDiff);\n                                    }\n                                    //else if (statisticsContext->CycleTimeDeltaDiff)\n                                    //{\n                                    //    PhInitFormatI64UGroupDigits(&format[0], statisticsContext->CycleTimeDeltaDiff);\n                                    //}\n                                    else\n                                    {\n                                        PhInitFormatS(&format[0], L\"N/A\");\n                                    }\n\n                                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), NULL))\n                                    {\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, buffer, _TRUNCATE);\n                                    }\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->CycleTimeDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ContextSwitchesDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ContextSwitchesDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_KERNELTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->KernelTimeDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_USERTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->UserTimeDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_TOTALTIME:\n                                PH_PROCESS_STATISTICS_FORMAT_TIME(dispInfo, statisticsContext->KernelTimeDiff + statisticsContext->UserTimeDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_KERNELDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->KernelTimeDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_USERDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->UserTimeDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_TOTALDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->KernelTimeDeltaDiff + statisticsContext->UserTimeDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIORITY:\n                                {\n                                    WCHAR priority[PH_INT32_STR_LEN_1] = L\"\";\n\n                                    PhPrintInt32(priority, statisticsContext->BasePriorityDiff);\n\n                                    wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, priority, _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PagefileUsageDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA:\n                                PhpUpdateProcessStatisticDelta(dispInfo, statisticsContext->PagefileDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakPagefileUsageDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->VirtualSizeDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakVirtualSizeDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->PageFaultCountDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->PageFaultsDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HARDFAULTS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->HardFaultCountDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_HARDFAULTSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->HardFaultsDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WORKINGSET:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->WorkingSetSizeDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakWorkingSetSizeDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATEWS:\n                                {\n                                    if (statisticsContext->NumberOfPrivatePagesDiff)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfPrivatePagesDiff);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS:\n                                {\n                                    if (statisticsContext->NumberOfShareablePagesDiff)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfShareablePagesDiff);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREDWS:\n                                {\n                                    if (statisticsContext->NumberOfSharedPagesDiff)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->NumberOfSharedPagesDiff);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPagedPoolUsageDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPeakPagedPoolUsageDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_NONPAGED:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaNonPagedPoolUsageDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->QuotaPeakNonPagedPoolUsageDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_SHAREDCOMMIT:\n                                {\n                                    if (statisticsContext->SharedCommitUsageDiff)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->SharedCommitUsageDiff);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PRIVATECOMMIT:\n                                {\n                                    if (statisticsContext->PrivateCommitUsageDiff)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PrivateCommitUsageDiff);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATECOMMIT:\n                                {\n                                    if (statisticsContext->PeakPrivateCommitUsageDiff)\n                                        PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->PeakPrivateCommitUsageDiff);\n                                    else\n                                        wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L\"N/A\", _TRUNCATE);\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY:\n                                {\n\n                                }\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READS:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->ReadOperationCountDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READSDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoReadCountDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->ReadTransferCountDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoReadDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITES:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->WriteOperationCountDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoWriteCountDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITEBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->WriteTransferCountDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoWriteDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHER:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->OtherOperationCountDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoOtherCountDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERBYTES:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->OtherTransferCountDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA:\n                                PH_PROCESS_STATISTICS_FORMAT_I64U(dispInfo, statisticsContext->IoOtherDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOTOTAL:\n                                PH_PROCESS_STATISTICS_FORMAT_SIZE(dispInfo, statisticsContext->IoTotalDeltaDiff);\n                                break;\n                            case PH_PROCESS_STATISTICS_INDEX_IOTOTALDELTA:\n                                break;\n                            }\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_PH_STATISTICS_UPDATE:\n        {\n            PhpUpdateProcessStatistics(processItem, statisticsContext);\n        }\n        break;\n    case WM_SIZE:\n        {\n            //ExtendedListView_SetColumnWidth(statisticsContext->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == statisticsContext->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID *listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint((HWND)wParam, &point);\n\n                PhGetSelectedListViewItemParams(statisticsContext->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, statisticsContext->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(statisticsContext->ListViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpgthrd.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2018-2023\n *\n */\n\n#include <phapp.h>\n#include <procprp.h>\n#include <procprpp.h>\n#include <cpysave.h>\n#include <emenu.h>\n#include <secedit.h>\n#include <settings.h>\n#include <symprv.h>\n\n#include <actions.h>\n#include <extmgri.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <procprv.h>\n#include <thrdprv.h>\n\nstatic PH_STRINGREF EmptyThreadsText = PH_STRINGREF_INIT(L\"There are no threads to display.\");\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ThreadAddedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;\n\n    // Parameter contains a pointer to the added thread item.\n    PhReferenceObject(Parameter);\n    PhPushProviderEventQueue(&threadsContext->EventQueue, ProviderAddedEvent, Parameter, (ULONG)threadsContext->Provider->RunId);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ThreadModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;\n\n    PhPushProviderEventQueue(&threadsContext->EventQueue, ProviderModifiedEvent, Parameter, (ULONG)threadsContext->Provider->RunId);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ThreadRemovedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;\n\n    PhPushProviderEventQueue(&threadsContext->EventQueue, ProviderRemovedEvent, Parameter, (ULONG)threadsContext->Provider->RunId);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ThreadsUpdatedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;\n\n    PostMessage(threadsContext->WindowHandle, WM_PH_THREADS_UPDATED, (ULONG)threadsContext->Provider->RunId, threadsContext->Provider->RunId == 1);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nstatic VOID NTAPI ThreadsLoadingStateChangedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;\n\n    //PostMessage(\n    //    threadsContext->ListContext.TreeNewHandle,\n    //    TNM_SETCURSOR,\n    //    0,\n    //    // Parameter contains TRUE if loading symbols\n    //    (LPARAM)(Parameter ? PhLoadCursor(NULL, IDC_APPSTARTING) : NULL)\n    //    );\n}\n\nVOID PhpInitializeThreadMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ HANDLE ProcessId,\n    _In_ PPH_THREAD_ITEM *Threads,\n    _In_ ULONG NumberOfThreads\n    )\n{\n    if (NumberOfThreads == 0)\n    {\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n    }\n    else if (NumberOfThreads == 1)\n    {\n        // All menu items are enabled by default.\n    }\n    else\n    {\n        ULONG menuItemsMultiEnabled[] =\n        {\n            ID_THREAD_TERMINATE,\n            ID_THREAD_SUSPEND,\n            ID_THREAD_RESUME,\n            ID_THREAD_COPY,\n            ID_THREAD_AFFINITY,\n        };\n        ULONG i;\n        PPH_EMENU_ITEM menuItem;\n\n        PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n\n        // These menu items are capable of manipulating\n        // multiple threads.\n        for (i = 0; i < sizeof(menuItemsMultiEnabled) / sizeof(ULONG); i++)\n        {\n            PhEnableEMenuItem(Menu, menuItemsMultiEnabled[i], TRUE);\n        }\n\n        if (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, L\"&Priority\", 0))\n        {\n            PhSetEnabledEMenuItem(menuItem, TRUE);\n        }\n    }\n\n    PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, FALSE);\n\n    // Critical\n    if (NumberOfThreads == 1)\n    {\n        HANDLE threadHandle;\n\n        if (NT_SUCCESS(PhOpenThread(\n            &threadHandle,\n            THREAD_QUERY_INFORMATION,\n            Threads[0]->ThreadId\n            )))\n        {\n            BOOLEAN breakOnTermination;\n\n            if (NT_SUCCESS(PhGetThreadBreakOnTermination(\n                threadHandle,\n                &breakOnTermination\n                )))\n            {\n                if (breakOnTermination)\n                {\n                    PhSetFlagsEMenuItem(Menu, ID_THREAD_CRITICAL, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n                }\n            }\n\n            NtClose(threadHandle);\n        }\n    }\n\n    // Priority\n    if (NumberOfThreads == 1)\n    {\n        HANDLE threadHandle;\n        KPRIORITY threadPriority = THREAD_PRIORITY_ERROR_RETURN;\n        IO_PRIORITY_HINT ioPriority = ULONG_MAX;\n        ULONG pagePriority = ULONG_MAX;\n        BOOLEAN threadPriorityBoost = FALSE;\n        ULONG id = 0;\n\n        if (NT_SUCCESS(PhOpenThread(\n            &threadHandle,\n            THREAD_QUERY_LIMITED_INFORMATION,\n            Threads[0]->ThreadId\n            )))\n        {\n            HANDLE tokenHandle;\n\n            PhGetThreadBasePriority(threadHandle, &threadPriority);\n            PhGetThreadIoPriority(threadHandle, &ioPriority);\n            PhGetThreadPagePriority(threadHandle, &pagePriority);\n            PhGetThreadPriorityBoost(threadHandle, &threadPriorityBoost);\n\n            if (NT_SUCCESS(PhOpenThreadToken(\n                threadHandle,\n                TOKEN_QUERY,\n                TRUE,\n                &tokenHandle\n                )))\n            {\n                PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, TRUE);\n                NtClose(tokenHandle);\n            }\n\n            NtClose(threadHandle);\n        }\n\n        // See PhGetBasePrioritySymbolicString\n        if (threadPriority == THREAD_PRIORITY_ERROR_RETURN)\n            NOTHING;\n        else if (threadPriority > LOW_REALTIME_PRIORITY)      // 16\n            NOTHING;\n        else if (threadPriority <= THREAD_BASE_PRIORITY_IDLE) // -15\n            id = ID_PRIORITY_IDLE;\n        else if (threadPriority < THREAD_BASE_PRIORITY_MIN)   // -2\n            NOTHING;\n        else if (threadPriority > THREAD_BASE_PRIORITY_MAX)   // 2\n            id = ID_PRIORITY_TIMECRITICAL;\n        else\n        {\n            switch (threadPriority)\n            {\n            case THREAD_PRIORITY_HIGHEST:                     // 2\n                id = ID_PRIORITY_HIGHEST;\n                break;\n            case THREAD_PRIORITY_ABOVE_NORMAL:                // 1\n                id = ID_PRIORITY_ABOVENORMAL;\n                break;\n            case THREAD_PRIORITY_NORMAL:                      // 0\n                id = ID_PRIORITY_NORMAL;\n                break;\n            case THREAD_PRIORITY_BELOW_NORMAL:                // -1\n                id = ID_PRIORITY_BELOWNORMAL;\n                break;\n            case THREAD_PRIORITY_LOWEST:                      // -2\n                id = ID_PRIORITY_LOWEST;\n                break;\n            DEFAULT_UNREACHABLE;\n            }\n        }\n\n        if (id != 0)\n        {\n            PhSetFlagsEMenuItem(Menu, id,\n                PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,\n                PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);\n        }\n\n        if (ioPriority != ULONG_MAX)\n        {\n            id = 0;\n\n            switch (ioPriority)\n            {\n            case IoPriorityVeryLow:\n                id = ID_IOPRIORITY_VERYLOW;\n                break;\n            case IoPriorityLow:\n                id = ID_IOPRIORITY_LOW;\n                break;\n            case IoPriorityNormal:\n                id = ID_IOPRIORITY_NORMAL;\n                break;\n            case IoPriorityHigh:\n                id = ID_IOPRIORITY_HIGH;\n                break;\n            }\n\n            if (id != 0)\n            {\n                PhSetFlagsEMenuItem(Menu, id,\n                    PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,\n                    PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);\n            }\n        }\n\n        if (pagePriority != ULONG_MAX)\n        {\n            id = 0;\n\n            switch (pagePriority)\n            {\n            case MEMORY_PRIORITY_VERY_LOW:\n                id = ID_PAGEPRIORITY_VERYLOW;\n                break;\n            case MEMORY_PRIORITY_LOW:\n                id = ID_PAGEPRIORITY_LOW;\n                break;\n            case MEMORY_PRIORITY_MEDIUM:\n                id = ID_PAGEPRIORITY_MEDIUM;\n                break;\n            case MEMORY_PRIORITY_BELOW_NORMAL:\n                id = ID_PAGEPRIORITY_BELOWNORMAL;\n                break;\n            case MEMORY_PRIORITY_NORMAL:\n                id = ID_PAGEPRIORITY_NORMAL;\n                break;\n            }\n\n            if (id != 0)\n            {\n                PhSetFlagsEMenuItem(Menu, id,\n                    PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,\n                    PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);\n            }\n        }\n\n        if (threadPriorityBoost)\n        {\n            PhSetFlagsEMenuItem(Menu, ID_THREAD_BOOST, PH_EMENU_CHECKED, PH_EMENU_CHECKED);\n        }\n    }\n}\n\nstatic NTSTATUS NTAPI PhpThreadPermissionsOpenThread(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Context)\n        return PhOpenThread(Handle, DesiredAccess, (HANDLE)Context);\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nstatic NTSTATUS PhpThreadPermissionsCloseHandle(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle) NtClose(Handle);\n    return STATUS_SUCCESS;\n}\n\nstatic NTSTATUS NTAPI PhpOpenThreadTokenObject(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Context)\n        return PhOpenThreadToken((HANDLE)Context, DesiredAccess, TRUE, Handle);\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nstatic NTSTATUS PhpCloseThreadTokenObject(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle) NtClose(Handle);\n    return STATUS_SUCCESS;\n}\n\nBOOLEAN PhpThreadTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PPH_THREADS_CONTEXT Context\n    )\n{\n    PPH_THREAD_NODE threadNode = (PPH_THREAD_NODE)Node;\n    PPH_THREAD_ITEM threadItem = threadNode->ThreadItem;\n\n    if (Context->ListContext.HideSuspended && threadItem->WaitReason == Suspended)\n        return FALSE;\n    if (Context->ListContext.HideGuiThreads && threadItem->IsGuiThread)\n        return FALSE;\n\n    if (!Context->SearchMatchHandle)\n        return TRUE;\n\n    // thread properties\n\n    if (threadItem->ThreadIdString[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, threadItem->ThreadIdString))\n            return TRUE;\n    }\n\n    if (threadItem->ThreadIdHexString[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, threadItem->ThreadIdHexString))\n            return TRUE;\n    }\n\n    if (threadItem->LxssThreadIdString[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, threadItem->LxssThreadIdString))\n            return TRUE;\n    }\n\n    if (threadNode->PriorityText[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, threadNode->PriorityText))\n            return TRUE;\n    }\n\n    if (threadNode->BasePriorityText[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, threadNode->BasePriorityText))\n            return TRUE;\n    }\n\n    if (threadNode->IdealProcessorText[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, threadNode->IdealProcessorText))\n            return TRUE;\n    }\n\n    if (threadNode->ThreadIdHexText[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, threadNode->ThreadIdHexText))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(threadNode->StartAddressText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &threadNode->StartAddressText->sr))\n            return TRUE;\n    }\n\n    if (threadItem->BasePriority != THREAD_PRIORITY_ERROR_RETURN)\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, PhGetBasePrioritySymbolicString(threadItem->BasePriority)))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(threadNode->CreatedText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &threadNode->CreatedText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(threadNode->NameText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &threadNode->NameText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(threadNode->StateText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &threadNode->StateText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(threadNode->LastSystemCallText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &threadNode->LastSystemCallText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(threadNode->LastErrorCodeText))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &threadNode->LastErrorCodeText->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(threadNode->ThreadItem->ServiceName))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &threadNode->ThreadItem->ServiceName->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(threadNode->ThreadItem->StartAddressWin32String))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &threadNode->ThreadItem->StartAddressWin32String->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(threadNode->ThreadItem->StartAddressWin32FileName))\n    {\n        if (PhSearchControlMatch(Context->SearchMatchHandle, &threadNode->ThreadItem->StartAddressWin32FileName->sr))\n            return TRUE;\n    }\n\n    if (threadNode->ActualBasePriorityText[0])\n    {\n        if (PhSearchControlMatchLongHintZ(Context->SearchMatchHandle, threadNode->ActualBasePriorityText))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nPPH_EMENU PhpCreateThreadMenu(\n    VOID\n    )\n{\n    PPH_EMENU menu;\n    PPH_EMENU_ITEM menuItem;\n\n    menu = PhCreateEMenu();\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_INSPECT, L\"&Inspect\\bEnter\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_TERMINATE, L\"T&erminate\\bDel\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_SUSPEND, L\"&Suspend\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_RESUME, L\"Res&ume\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_ANALYZE_WAIT, L\"Analy&ze\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_AFFINITY, L\"&Affinity\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_BOOST, L\"&Boost\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_CRITICAL, L\"Critical\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_PERMISSIONS, L\"Per&missions\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_TOKEN, L\"&Token\", NULL, NULL), ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, 0, L\"&Priority\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_TIMECRITICAL, L\"Time &critical\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_HIGHEST, L\"&Highest\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L\"&Above normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L\"&Normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L\"&Below normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_LOWEST, L\"&Lowest\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L\"&Idle\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, 0, L\"&I/O priority\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L\"&High\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L\"&Normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L\"&Low\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L\"&Very low\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n    menuItem = PhCreateEMenuItem(0, 0, L\"Pa&ge priority\", NULL, NULL);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_NORMAL, L\"&Normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_BELOWNORMAL, L\"&Below normal\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_MEDIUM, L\"&Medium\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_LOW, L\"&Low\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, ID_PAGEPRIORITY_VERYLOW, L\"&Very low\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, menuItem, ULONG_MAX);\n\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_THREAD_COPY, L\"&Copy\\bCtrl+C\", NULL, NULL), ULONG_MAX);\n\n    return menu;\n}\n\nVOID PhShowThreadContextMenu(\n    _In_ HWND hwndDlg,\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_THREADS_CONTEXT Context,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu\n    )\n{\n    PPH_THREAD_ITEM *threads;\n    ULONG numberOfThreads;\n\n    PhGetSelectedThreadItems(&Context->ListContext, &threads, &numberOfThreads);\n\n    if (numberOfThreads != 0)\n    {\n        PPH_EMENU menu;\n        PPH_EMENU_ITEM item;\n        PH_PLUGIN_MENU_INFORMATION menuInfo;\n\n        menu = PhpCreateThreadMenu();\n        PhSetFlagsEMenuItem(menu, ID_THREAD_INSPECT, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);\n\n        PhpInitializeThreadMenu(menu, ProcessItem->ProcessId, threads, numberOfThreads);\n        PhInsertCopyCellEMenuItem(menu, ID_THREAD_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);\n\n        if (PhPluginsEnabled)\n        {\n            PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);\n            menuInfo.u.Thread.ProcessId = ProcessItem->ProcessId;\n            menuInfo.u.Thread.Threads = threads;\n            menuInfo.u.Thread.NumberOfThreads = numberOfThreads;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing), &menuInfo);\n        }\n\n        item = PhShowEMenu(\n            menu,\n            hwndDlg,\n            PH_EMENU_SHOW_LEFTRIGHT,\n            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n            ContextMenu->Location.x,\n            ContextMenu->Location.y\n            );\n\n        if (item)\n        {\n            BOOLEAN handled = FALSE;\n\n            handled = PhHandleCopyCellEMenuItem(item);\n\n            if (!handled && PhPluginsEnabled)\n                handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n            if (!handled)\n                SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);\n        }\n\n        PhDestroyEMenu(menu);\n    }\n\n    PhFree(threads);\n}\n\nVOID PhpPopulateTableWithProcessThreadNodes(\n    _In_ HWND TreeListHandle,\n    _In_ PPH_THREAD_NODE Node,\n    _In_ ULONG Level,\n    _In_ PPH_STRING **Table,\n    _Inout_ PULONG Index,\n    _In_ PULONG DisplayToId,\n    _In_ ULONG Columns\n    )\n{\n    for (ULONG i = 0; i < Columns; i++)\n    {\n        PH_TREENEW_GET_CELL_TEXT getCellText;\n        PPH_STRING text;\n\n        getCellText.Node = &Node->Node;\n        getCellText.Id = DisplayToId[i];\n        PhInitializeEmptyStringRef(&getCellText.Text);\n        TreeNew_GetCellText(TreeListHandle, &getCellText);\n\n        if (i != 0)\n        {\n            if (getCellText.Text.Length == 0)\n                text = PhReferenceEmptyString();\n            else\n                text = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length);\n        }\n        else\n        {\n            // If this is the first column in the row, add some indentation.\n            text = PhaCreateStringEx(\n                NULL,\n                getCellText.Text.Length + UInt32x32To64(Level, 2) * sizeof(WCHAR)\n                );\n            wmemset(text->Buffer, L' ', UInt32x32To64(Level, 2));\n            memcpy(&text->Buffer[UInt32x32To64(Level, 2)], getCellText.Text.Buffer, getCellText.Text.Length);\n        }\n\n        Table[*Index][i] = text;\n    }\n\n    (*Index)++;\n}\n\nVOID PhExpandAllThreadNodes(\n    _In_ PPH_THREADS_CONTEXT ThreadsContext,\n    _In_ BOOLEAN Expand\n    )\n{\n    BOOLEAN needsRestructure = FALSE;\n\n    for (ULONG i = 0; i < ThreadsContext->ListContext.NodeList->Count; i++)\n    {\n        PPH_THREAD_NODE node = ThreadsContext->ListContext.NodeList->Items[i];\n\n        if (node->Node.Expanded != Expand)\n        {\n            node->Node.Expanded = Expand;\n            needsRestructure = TRUE;\n        }\n    }\n\n    if (needsRestructure)\n        TreeNew_NodesStructured(ThreadsContext->TreeNewHandle);\n}\n\nVOID PhInvalidateAllThreadNodes(\n    _In_ PPH_THREADS_CONTEXT ThreadsContext\n    )\n{\n    for (ULONG i = 0; i < ThreadsContext->ListContext.NodeList->Count; i++)\n    {\n        PPH_THREAD_NODE node = ThreadsContext->ListContext.NodeList->Items[i];\n\n        memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PH_THREAD_TREELIST_COLUMN_MAXIMUM);\n        PhInvalidateTreeNewNode(&node->Node, TN_CACHE_COLOR);\n        node->ValidMask = 0;\n    }\n\n    InvalidateRect(ThreadsContext->TreeNewHandle, NULL, FALSE);\n}\n\nstatic VOID PhDeselectAllThreadNodes(\n    _In_ PPH_THREAD_LIST_CONTEXT Context\n    )\n{\n    TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1);\n}\n\nVOID PhSelectAndEnsureVisibleThreadNodes(\n    _In_ PPH_THREADS_CONTEXT ThreadsContext,\n    _In_ PPH_THREAD_NODE *ThreadNodes,\n    _In_ ULONG NumberOfThreadNodes\n    )\n{\n    ULONG i;\n    PPH_THREAD_NODE leader = NULL;\n    PPH_THREAD_NODE node;\n    BOOLEAN needsRestructure = FALSE;\n\n    PhDeselectAllThreadNodes(&ThreadsContext->ListContext);\n\n    for (i = 0; i < NumberOfThreadNodes; i++)\n    {\n        if (ThreadNodes[i]->Node.Visible)\n        {\n            leader = ThreadNodes[i];\n            break;\n        }\n    }\n\n    if (!leader)\n        return;\n\n    for (i = 0; i < NumberOfThreadNodes; i++)\n    {\n        node = ThreadNodes[i];\n\n        if (!node->Node.Visible)\n            continue;\n\n        node->Node.Selected = TRUE;\n    }\n\n    if (needsRestructure)\n        TreeNew_NodesStructured(ThreadsContext->TreeNewHandle);\n\n    TreeNew_FocusMarkSelectNode(ThreadsContext->TreeNewHandle, &leader->Node);\n}\n\nVOID PhSelectAndEnsureVisibleThreadNode(\n    _In_ PPH_THREADS_CONTEXT ThreadsContext,\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    PhSelectAndEnsureVisibleThreadNodes(ThreadsContext, &ThreadNode, 1);\n}\n\nPPH_LIST PhpGetProcessThreadTreeListLines(\n    _In_ HWND TreeListHandle,\n    _In_ ULONG NumberOfNodes,\n    _In_ PPH_LIST RootNodes,\n    _In_ ULONG Mode\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_LIST lines;\n    // The number of rows in the table (including +1 for the column headers).\n    ULONG rows;\n    // The number of columns.\n    ULONG columns;\n    // A column display index to ID map.\n    PULONG displayToId;\n    // A column display index to text map.\n    PWSTR *displayToText;\n    // The actual string table.\n    PPH_STRING **table;\n    ULONG i;\n    ULONG j;\n\n    // Use a local auto-pool to make memory management a bit less painful.\n    PhInitializeAutoPool(&autoPool);\n\n    rows = NumberOfNodes + 1;\n\n    // Create the display index to ID map.\n    PhMapDisplayIndexTreeNew(TreeListHandle, &displayToId, &displayToText, &columns);\n\n    PhaCreateTextTable(&table, rows, columns);\n\n    // Populate the first row with the column headers.\n    for (i = 0; i < columns; i++)\n    {\n        table[0][i] = PhaCreateString(displayToText[i]);\n    }\n\n    // Go through the nodes in the process tree and populate each cell of the table.\n\n    j = 1; // index starts at one because the first row contains the column headers.\n\n    for (i = 0; i < RootNodes->Count; i++)\n    {\n        PhpPopulateTableWithProcessThreadNodes(\n            TreeListHandle,\n            RootNodes->Items[i],\n            0,\n            table,\n            &j,\n            displayToId,\n            columns\n            );\n    }\n\n    PhFree(displayToId);\n    PhFree(displayToText);\n\n    lines = PhaFormatTextTable(table, rows, columns, Mode);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return lines;\n}\n\nVOID PhpProcessThreadsSave(\n    _In_ PPH_THREADS_CONTEXT ThreadsContext\n    )\n{\n    static PH_FILETYPE_FILTER filters[] =\n    {\n        { L\"Text files (*.txt;*.log)\", L\"*.txt;*.log\" },\n        { L\"Comma-separated values (*.csv)\", L\"*.csv\" },\n        { L\"All files (*.*)\", L\"*.*\" }\n    };\n    PVOID fileDialog = PhCreateSaveFileDialog();\n    PH_FORMAT format[4];\n    PPH_PROCESS_ITEM processItem;\n\n    processItem = PhReferenceProcessItem(ThreadsContext->Provider->ProcessId);\n    PhInitFormatS(&format[0], L\"System Informer (\");\n    PhInitFormatS(&format[1], PhGetStringOrDefault(processItem->ProcessName, L\"Unknown process\"));\n    PhInitFormatS(&format[2], L\") Threads\");\n    PhInitFormatS(&format[3], L\".txt\");\n    if (processItem) PhDereferenceObject(processItem);\n\n    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n    PhSetFileDialogFileName(fileDialog, PH_AUTO_T(PH_STRING, PhFormat(format, 3, 60))->Buffer);\n\n    if (PhShowFileDialog(ThreadsContext->WindowHandle, fileDialog))\n    {\n        NTSTATUS status;\n        PPH_STRING fileName;\n        ULONG filterIndex;\n        PPH_FILE_STREAM fileStream;\n\n        fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));\n        filterIndex = PhGetFileDialogFilterIndex(fileDialog);\n\n        if (NT_SUCCESS(status = PhCreateFileStream(\n            &fileStream,\n            fileName->Buffer,\n            FILE_GENERIC_WRITE,\n            FILE_SHARE_READ,\n            FILE_OVERWRITE_IF,\n            0\n            )))\n        {\n            ULONG mode;\n            PPH_LIST lines;\n\n            if (filterIndex == 2)\n                mode = PH_EXPORT_MODE_CSV;\n            else\n                mode = PH_EXPORT_MODE_TABS;\n\n            PhWriteStringAsUtf8FileStream(fileStream, (PPH_STRINGREF)&PhUnicodeByteOrderMark);\n\n            if (mode != PH_EXPORT_MODE_CSV)\n            {\n                PhWritePhTextHeader(fileStream);\n            }\n\n            lines = PhpGetProcessThreadTreeListLines(\n                ThreadsContext->TreeNewHandle,\n                ThreadsContext->ListContext.NodeList->Count,\n                ThreadsContext->ListContext.NodeList,\n                mode\n                );\n\n            for (ULONG i = 0; i < lines->Count; i++)\n            {\n                PPH_STRING line;\n\n                line = lines->Items[i];\n                PhWriteStringAsUtf8FileStream(fileStream, &line->sr);\n                PhDereferenceObject(line);\n                PhWriteStringAsUtf8FileStream2(fileStream, L\"\\r\\n\");\n            }\n\n            PhDereferenceObject(lines);\n            PhDereferenceObject(fileStream);\n        }\n\n        if (!NT_SUCCESS(status))\n            PhShowStatus(ThreadsContext->WindowHandle, L\"Unable to create the file\", status, 0);\n    }\n\n    PhFreeFileDialog(fileDialog);\n}\n\nVOID PhpSymbolProviderEventCallbackThreadStatus(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_SYMBOL_EVENT_DATA event = Parameter;\n    PPH_THREADS_CONTEXT context = Context;\n    PPH_STRING statusMessage = NULL;\n\n    switch (event->EventType)\n    {\n    case PH_SYMBOL_EVENT_TYPE_LOAD_START:\n        statusMessage = PhReferenceObject(event->EventMessage);\n        break;\n    case PH_SYMBOL_EVENT_TYPE_LOAD_END:\n        statusMessage = PhReferenceEmptyString();\n        break;\n    case PH_SYMBOL_EVENT_TYPE_PROGRESS:\n        statusMessage = PhReferenceObject(event->EventMessage);\n        break;\n    }\n\n    if (statusMessage)\n    {\n        PhSetWindowText(context->StatusHandle, PhGetStringOrEmpty(statusMessage));\n        PhDereferenceObject(statusMessage);\n    }\n}\n\nVOID NTAPI PhpProcessThreadsSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_THREADS_CONTEXT threadsContext = Context;\n\n    assert(threadsContext);\n\n    threadsContext->SearchMatchHandle = MatchHandle;\n\n    PhApplyTreeNewFilters(&threadsContext->ListContext.TreeFilterSupport);\n}\n\nINT_PTR CALLBACK PhpProcessThreadsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    LPPROPSHEETPAGE propSheetPage;\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n    PPH_THREADS_CONTEXT threadsContext;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))\n    {\n        threadsContext = (PPH_THREADS_CONTEXT)propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            threadsContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmThreadsContextType, sizeof(PH_THREADS_CONTEXT)));\n            memset(threadsContext, 0, sizeof(PH_THREADS_CONTEXT));\n\n            threadsContext->WindowHandle = hwndDlg;\n            threadsContext->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            threadsContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_SEARCH);\n            threadsContext->StatusHandle = GetDlgItem(hwndDlg, IDC_STATE);\n\n            // The thread provider has a special registration mechanism.\n            threadsContext->Provider = PhCreateThreadProvider(\n                processItem->ProcessId\n                );\n            PhRegisterCallback(\n                &threadsContext->Provider->ThreadAddedEvent,\n                ThreadAddedHandler,\n                threadsContext,\n                &threadsContext->AddedEventRegistration\n                );\n            PhRegisterCallback(\n                &threadsContext->Provider->ThreadModifiedEvent,\n                ThreadModifiedHandler,\n                threadsContext,\n                &threadsContext->ModifiedEventRegistration\n                );\n            PhRegisterCallback(\n                &threadsContext->Provider->ThreadRemovedEvent,\n                ThreadRemovedHandler,\n                threadsContext,\n                &threadsContext->RemovedEventRegistration\n                );\n            PhRegisterCallback(\n                &threadsContext->Provider->UpdatedEvent,\n                ThreadsUpdatedHandler,\n                threadsContext,\n                &threadsContext->UpdatedEventRegistration\n                );\n            PhRegisterCallback(\n                &threadsContext->Provider->LoadingStateChangedEvent,\n                ThreadsLoadingStateChangedHandler,\n                threadsContext,\n                &threadsContext->LoadingStateChangedEventRegistration\n                );\n\n            // Initialize the list. (wj32)\n            PhInitializeThreadList(hwndDlg, threadsContext->TreeNewHandle, &threadsContext->ListContext);\n\n            if (PhTreeWindowFont)\n            {\n                threadsContext->TreeNewFont = PhDuplicateFont(PhTreeWindowFont);\n                SetWindowFont(threadsContext->TreeNewHandle, threadsContext->TreeNewFont, FALSE);\n            }\n\n            TreeNew_SetEmptyText(threadsContext->TreeNewHandle, &EmptyThreadsText, 0);\n            PhInitializeProviderEventQueue(&threadsContext->EventQueue, 100);\n            threadsContext->FilterEntry = PhAddTreeNewFilter(&threadsContext->ListContext.TreeFilterSupport, PhpThreadTreeFilterCallback, threadsContext);\n            threadsContext->ListContext.ProcessId = processItem->ProcessId;\n            threadsContext->ListContext.ProcessCreateTime = processItem->CreateTime;\n\n            // Initialize the search box. (dmex)\n            PhCreateSearchControl(\n                hwndDlg,\n                threadsContext->SearchboxHandle,\n                L\"Search Threads (Ctrl+K)\",\n                PhpProcessThreadsSearchControlCallback,\n                threadsContext\n                );\n\n            // Use Cycles instead of Context Switches on Vista and above, but only when we can\n            // open the process, since cycle time information requires sufficient access to the\n            // threads. (wj32)\n            {\n                HANDLE processHandle;\n\n                // We make a distinction between PROCESS_QUERY_INFORMATION and PROCESS_QUERY_LIMITED_INFORMATION since\n                // the latter can be used when opening audiodg.exe even though we can't access its threads using\n                // THREAD_QUERY_LIMITED_INFORMATION. (wj32)\n\n                if (processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n                {\n                    threadsContext->ListContext.UseCycleTime = TRUE;\n                }\n                else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, processItem->ProcessId)))\n                {\n                    threadsContext->ListContext.UseCycleTime = TRUE;\n                    NtClose(processHandle);\n                }\n                else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId)))\n                {\n                    threadsContext->ListContext.UseCycleTime = TRUE;\n\n                    // We can't use cycle time for protected processes (without KSystemInformer). (wj32)\n                    if (processItem->IsProtectedProcess)\n                    {\n                        // Windows 10 allows elevated processes to query cycle time for protected processes (dmex)\n                        if (WindowsVersion < WINDOWS_10 || !PhGetOwnTokenAttributes().Elevated)\n                        {\n                            threadsContext->ListContext.UseCycleTime = FALSE;\n                        }\n                    }\n\n                    NtClose(processHandle);\n                }\n            }\n\n            if (processItem->ServiceList && processItem->ServiceList->Count != 0)\n                threadsContext->ListContext.HasServices = TRUE;\n\n            PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectCreate);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n                treeNewInfo.TreeNewHandle = threadsContext->TreeNewHandle;\n                treeNewInfo.CmData = &threadsContext->ListContext.Cm;\n                treeNewInfo.SystemContext = threadsContext;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadTreeNewInitializing), &treeNewInfo);\n            }\n\n            PhLoadSettingsThreadList(&threadsContext->ListContext);\n\n            PhThreadProviderInitialUpdate(threadsContext->Provider);\n            PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration);\n\n            if (threadsContext->Provider->SymbolProvider)\n            {\n                PhRegisterCallback(\n                    &PhSymbolEventCallback,\n                    PhpSymbolProviderEventCallbackThreadStatus,\n                    threadsContext,\n                    &threadsContext->SymbolProviderEventRegistration\n                    );\n            }\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            if (threadsContext->Provider->SymbolProvider)\n            {\n                PhUnregisterCallback(\n                    &PhSymbolEventCallback,\n                    &threadsContext->SymbolProviderEventRegistration\n                    );\n            }\n\n            PhRemoveTreeNewFilter(&threadsContext->ListContext.TreeFilterSupport, threadsContext->FilterEntry);\n\n            PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectDelete);\n\n            PhUnregisterCallback(\n                &threadsContext->Provider->ThreadAddedEvent,\n                &threadsContext->AddedEventRegistration\n                );\n            PhUnregisterCallback(\n                &threadsContext->Provider->ThreadModifiedEvent,\n                &threadsContext->ModifiedEventRegistration\n                );\n            PhUnregisterCallback(\n                &threadsContext->Provider->ThreadRemovedEvent,\n                &threadsContext->RemovedEventRegistration\n                );\n            PhUnregisterCallback(\n                &threadsContext->Provider->UpdatedEvent,\n                &threadsContext->UpdatedEventRegistration\n                );\n            PhUnregisterCallback(\n                &threadsContext->Provider->LoadingStateChangedEvent,\n                &threadsContext->LoadingStateChangedEventRegistration\n                );\n            PhUnregisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration);\n            PhSetTerminatingThreadProvider(threadsContext->Provider);\n            PhDereferenceObject(threadsContext->Provider);\n            PhDeleteProviderEventQueue(&threadsContext->EventQueue);\n\n            if (threadsContext->TreeNewFont)\n                DeleteFont(threadsContext->TreeNewFont);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n                treeNewInfo.TreeNewHandle = threadsContext->TreeNewHandle;\n                treeNewInfo.CmData = &threadsContext->ListContext.Cm;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadTreeNewUninitializing), &treeNewInfo);\n            }\n\n            PhSaveSettingsThreadList(&threadsContext->ListContext);\n            PhDeleteThreadList(&threadsContext->ListContext);\n\n            PhFree(threadsContext);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, threadsContext->StatusHandle, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);\n                PhAddPropPageLayoutItem(hwndDlg, threadsContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, threadsContext->TreeNewHandle, dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case ID_SHOWCONTEXTMENU:\n                {\n                    PhShowThreadContextMenu(hwndDlg, processItem, threadsContext, (PPH_TREENEW_CONTEXT_MENU)lParam);\n                }\n                break;\n            case ID_THREAD_INSPECT:\n                {\n                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);\n\n                    if (threadItem)\n                    {\n                        PhReferenceObject(threadsContext->Provider);\n                        PhShowThreadStackDialog(\n                            hwndDlg,\n                            threadsContext->Provider->ProcessId,\n                            threadItem->ThreadId,\n                            threadsContext->Provider\n                            );\n                        PhDereferenceObject(threadsContext->Provider);\n                    }\n                }\n                break;\n            case ID_THREAD_TERMINATE:\n                {\n                    PPH_THREAD_ITEM *threads;\n                    ULONG numberOfThreads;\n\n                    PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);\n                    PhReferenceObjects(threads, numberOfThreads);\n\n                    if (PhUiTerminateThreads(hwndDlg, threads, numberOfThreads))\n                        PhDeselectAllThreadNodes(&threadsContext->ListContext);\n\n                    PhDereferenceObjects(threads, numberOfThreads);\n                    PhFree(threads);\n                }\n                break;\n            case ID_THREAD_SUSPEND:\n                {\n                    PPH_THREAD_ITEM *threads;\n                    ULONG numberOfThreads;\n\n                    PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);\n                    PhReferenceObjects(threads, numberOfThreads);\n                    PhUiSuspendThreads(hwndDlg, threads, numberOfThreads);\n                    PhDereferenceObjects(threads, numberOfThreads);\n                    PhFree(threads);\n                }\n                break;\n            case ID_THREAD_RESUME:\n                {\n                    PPH_THREAD_ITEM *threads;\n                    ULONG numberOfThreads;\n\n                    PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);\n                    PhReferenceObjects(threads, numberOfThreads);\n                    PhUiResumeThreads(hwndDlg, threads, numberOfThreads);\n                    PhDereferenceObjects(threads, numberOfThreads);\n                    PhFree(threads);\n                }\n                break;\n            case ID_THREAD_AFFINITY:\n                {\n                    ULONG numberOfThreads;\n                    PPH_THREAD_ITEM* threads;\n\n                    PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);\n                    PhReferenceObjects(threads, numberOfThreads);\n\n                    if (numberOfThreads == 1) // HACK\n                    {\n                        PhShowProcessAffinityDialog(hwndDlg, NULL, threads[0]);\n                    }\n                    else\n                    {\n                        PhShowThreadAffinityDialog(hwndDlg, threads, numberOfThreads);\n                    }\n\n                    PhDereferenceObjects(threads, numberOfThreads);\n                    PhFree(threads);\n                }\n                break;\n            case ID_THREAD_BOOST:\n                {\n                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);\n\n                    if (threadItem)\n                    {\n                        NTSTATUS status;\n                        HANDLE threadHandle;\n\n                        if (NT_SUCCESS(status = PhOpenThread(\n                            &threadHandle,\n                            THREAD_QUERY_LIMITED_INFORMATION,\n                            threadItem->ThreadId\n                            )))\n                        {\n                            BOOLEAN threadPriorityBoostDisabled = FALSE;\n                            ULONG numberOfThreads;\n                            PPH_THREAD_ITEM* threads;\n\n                            PhGetThreadPriorityBoost(threadHandle, &threadPriorityBoostDisabled);\n\n                            PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);\n                            PhReferenceObjects(threads, numberOfThreads);\n                            PhUiSetBoostPriorityThreads(hwndDlg, threads, numberOfThreads, !threadPriorityBoostDisabled);\n                            PhDereferenceObjects(threads, numberOfThreads);\n                            PhFree(threads);\n\n                            NtClose(threadHandle);\n                        }\n                        else\n                        {\n                            PhShowStatus(hwndDlg, PhaFormatString(\n                                L\"Unable to %s thread %lu\", // string pooling optimization (dmex)\n                                L\"set the boost priority of\",\n                                HandleToUlong(threadItem->ThreadId)\n                                )->Buffer, status, 0);\n                        }\n                    }\n                }\n                break;\n            case ID_THREAD_CRITICAL:\n                {\n                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);\n\n                    if (threadItem)\n                    {\n                        NTSTATUS status;\n                        HANDLE threadHandle;\n                        BOOLEAN breakOnTermination;\n\n                        status = PhOpenThread(\n                            &threadHandle,\n                            THREAD_QUERY_INFORMATION | THREAD_SET_INFORMATION,\n                            threadItem->ThreadId\n                            );\n\n                        if (NT_SUCCESS(status))\n                        {\n                            status = PhGetThreadBreakOnTermination(\n                                threadHandle,\n                                &breakOnTermination\n                                );\n\n                            if (NT_SUCCESS(status))\n                            {\n                                if (!breakOnTermination && (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                                    hwndDlg,\n                                    L\"enable\",\n                                    L\"critical status on the thread\",\n                                    L\"If the process ends, the operating system will shut down immediately.\",\n                                    TRUE\n                                    )))\n                                {\n                                    status = PhSetThreadBreakOnTermination(threadHandle, TRUE);\n                                }\n                                else if (breakOnTermination && (!PhGetIntegerSetting(SETTING_ENABLE_WARNINGS) || PhShowConfirmMessage(\n                                    hwndDlg,\n                                    L\"disable\",\n                                    L\"critical status on the thread\",\n                                    NULL,\n                                    FALSE\n                                    )))\n                                {\n                                    status = PhSetThreadBreakOnTermination(threadHandle, FALSE);\n                                }\n                            }\n\n                            NtClose(threadHandle);\n                        }\n\n                        if (!NT_SUCCESS(status))\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to change the thread critical status.\", status, 0);\n                        }\n                    }\n                }\n                break;\n            case ID_THREAD_PERMISSIONS:\n                {\n                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);\n\n                    if (threadItem)\n                    {\n                        PhEditSecurity(\n                            PhCsForceNoParent ? NULL : hwndDlg,\n                            PhaFormatString(L\"Thread %u\", HandleToUlong(threadItem->ThreadId))->Buffer,\n                            L\"Thread\",\n                            PhpThreadPermissionsOpenThread,\n                            PhpThreadPermissionsCloseHandle,\n                            threadItem->ThreadId\n                            );\n                    }\n                }\n                break;\n            case ID_THREAD_TOKEN:\n                {\n                    NTSTATUS status;\n                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);\n                    HANDLE threadHandle;\n\n                    if (threadItem)\n                    {\n                        if (NT_SUCCESS(status = PhOpenThread(\n                            &threadHandle,\n                            THREAD_QUERY_LIMITED_INFORMATION,\n                            threadItem->ThreadId\n                            )))\n                        {\n                            PhShowTokenProperties(\n                                hwndDlg,\n                                PhpOpenThreadTokenObject,\n                                PhpCloseThreadTokenObject,\n                                threadsContext->Provider->ProcessId,\n                                (PVOID)threadHandle,\n                                NULL\n                                );\n\n                            NtClose(threadHandle);\n                        }\n                        else\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to open the thread\", status, 0);\n                        }\n                    }\n                }\n                break;\n            case ID_ANALYZE_WAIT:\n                {\n                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);\n\n                    if (threadItem)\n                    {\n                        PhReferenceObject(threadsContext->Provider->SymbolProvider);\n                        PhUiAnalyzeWaitThread(\n                            hwndDlg,\n                            processItem->ProcessId,\n                            threadItem->ThreadId,\n                            threadsContext->Provider->SymbolProvider\n                            );\n                        PhDereferenceObject(threadsContext->Provider->SymbolProvider);\n                    }\n                }\n                break;\n            case ID_PRIORITY_TIMECRITICAL:\n            case ID_PRIORITY_HIGHEST:\n            case ID_PRIORITY_ABOVENORMAL:\n            case ID_PRIORITY_NORMAL:\n            case ID_PRIORITY_BELOWNORMAL:\n            case ID_PRIORITY_LOWEST:\n            case ID_PRIORITY_IDLE:\n                {\n                    LONG threadPriorityWin32 = LONG_MAX;\n\n                    switch (GET_WM_COMMAND_ID(wParam, lParam))\n                    {\n                    case ID_PRIORITY_TIMECRITICAL:\n                        threadPriorityWin32 = THREAD_PRIORITY_TIME_CRITICAL;\n                        break;\n                    case ID_PRIORITY_HIGHEST:\n                        threadPriorityWin32 = THREAD_PRIORITY_HIGHEST;\n                        break;\n                    case ID_PRIORITY_ABOVENORMAL:\n                        threadPriorityWin32 = THREAD_PRIORITY_ABOVE_NORMAL;\n                        break;\n                    case ID_PRIORITY_NORMAL:\n                        threadPriorityWin32 = THREAD_PRIORITY_NORMAL;\n                        break;\n                    case ID_PRIORITY_BELOWNORMAL:\n                        threadPriorityWin32 = THREAD_PRIORITY_BELOW_NORMAL;\n                        break;\n                    case ID_PRIORITY_LOWEST:\n                        threadPriorityWin32 = THREAD_PRIORITY_LOWEST;\n                        break;\n                    case ID_PRIORITY_IDLE:\n                        threadPriorityWin32 = THREAD_PRIORITY_IDLE;\n                        break;\n                    // TODO(jxy-s) Implement support for forcing thread to background\n                    // see KernelBase!SetThreadPriority THREAD_PRIORITY_BACKGROUND_BEGIN\n                    // calls NtSetInformationThread with ThreadActualBasePriority to force\n                    // the base priority increment below what is normally possible.\n                    }\n\n                    if (threadPriorityWin32 != LONG_MAX)\n                    {\n                        ULONG numberOfThreads;\n                        PPH_THREAD_ITEM* threads;\n\n                        PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);\n                        PhReferenceObjects(threads, numberOfThreads);\n                        PhUiSetPriorityThreads(hwndDlg, threads, numberOfThreads, threadPriorityWin32);\n                        PhDereferenceObjects(threads, numberOfThreads);\n                        PhFree(threads);\n                    }\n                }\n                break;\n            case ID_IOPRIORITY_VERYLOW:\n            case ID_IOPRIORITY_LOW:\n            case ID_IOPRIORITY_NORMAL:\n            case ID_IOPRIORITY_HIGH:\n                {\n                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);\n\n                    if (threadItem)\n                    {\n                        IO_PRIORITY_HINT ioPriority = ULONG_MAX;\n\n                        switch (GET_WM_COMMAND_ID(wParam, lParam))\n                        {\n                        case ID_IOPRIORITY_VERYLOW:\n                            ioPriority = IoPriorityVeryLow;\n                            break;\n                        case ID_IOPRIORITY_LOW:\n                            ioPriority = IoPriorityLow;\n                            break;\n                        case ID_IOPRIORITY_NORMAL:\n                            ioPriority = IoPriorityNormal;\n                            break;\n                        case ID_IOPRIORITY_HIGH:\n                            ioPriority = IoPriorityHigh;\n                            break;\n                        }\n\n                        if (ioPriority != ULONG_MAX)\n                        {\n                            PhReferenceObject(threadItem);\n                            PhUiSetIoPriorityThread(hwndDlg, threadItem, ioPriority);\n                            PhDereferenceObject(threadItem);\n                        }\n                    }\n                }\n                break;\n            case ID_PAGEPRIORITY_VERYLOW:\n            case ID_PAGEPRIORITY_LOW:\n            case ID_PAGEPRIORITY_MEDIUM:\n            case ID_PAGEPRIORITY_BELOWNORMAL:\n            case ID_PAGEPRIORITY_NORMAL:\n                {\n                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);\n\n                    if (threadItem)\n                    {\n                        ULONG pagePriority = ULONG_MAX;\n\n                        switch (GET_WM_COMMAND_ID(wParam, lParam))\n                        {\n                        case ID_PAGEPRIORITY_VERYLOW:\n                            pagePriority = MEMORY_PRIORITY_VERY_LOW;\n                            break;\n                        case ID_PAGEPRIORITY_LOW:\n                            pagePriority = MEMORY_PRIORITY_LOW;\n                            break;\n                        case ID_PAGEPRIORITY_MEDIUM:\n                            pagePriority = MEMORY_PRIORITY_MEDIUM;\n                            break;\n                        case ID_PAGEPRIORITY_BELOWNORMAL:\n                            pagePriority = MEMORY_PRIORITY_BELOW_NORMAL;\n                            break;\n                        case ID_PAGEPRIORITY_NORMAL:\n                            pagePriority = MEMORY_PRIORITY_NORMAL;\n                            break;\n                        }\n\n                        if (pagePriority != ULONG_MAX)\n                        {\n                            PhReferenceObject(threadItem);\n                            PhUiSetPagePriorityThread(hwndDlg, threadItem, pagePriority);\n                            PhDereferenceObject(threadItem);\n                        }\n                    }\n                }\n                break;\n            case ID_THREAD_COPY:\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(threadsContext->TreeNewHandle, 0);\n                    PhSetClipboardString(threadsContext->TreeNewHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            //case IDC_OPENSTARTMODULE:\n            //    {\n            //        PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);\n            //\n            //        if (threadItem && threadItem->StartAddressWin32FileName)\n            //        {\n            //            PhShellExecuteUserString(\n            //                hwndDlg,\n            //                SETTING_FILE_BROWSE_EXECUTABLE,\n            //                threadItem->StartAddressWin32FileName->Buffer,\n            //                FALSE,\n            //                L\"Make sure the Explorer executable file is present.\"\n            //                );\n            //        }\n            //    }\n            //    break;\n            case IDC_OPTIONS:\n                {\n                    RECT rect;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM hideSuspendedMenuItem;\n                    PPH_EMENU_ITEM hideGuiMenuItem;\n                    PPH_EMENU_ITEM highlightSuspendedMenuItem;\n                    PPH_EMENU_ITEM highlightGuiMenuItem;\n                    PPH_EMENU_ITEM saveMenuItem;\n                    PPH_EMENU_ITEM selectedItem;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect))\n                        break;\n\n                    hideSuspendedMenuItem = PhCreateEMenuItem(0, PH_THREAD_TREELIST_MENUITEM_HIDE_SUSPENDED, L\"Hide suspended\", NULL, NULL);\n                    hideGuiMenuItem = PhCreateEMenuItem(0, PH_THREAD_TREELIST_MENUITEM_HIDE_GUITHREADS, L\"Hide gui\", NULL, NULL);\n                    highlightSuspendedMenuItem = PhCreateEMenuItem(0, PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_SUSPENDED, L\"Highlight suspended\", NULL, NULL);\n                    highlightGuiMenuItem = PhCreateEMenuItem(0, PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_GUITHREADS, L\"Highlight gui\", NULL, NULL);\n                    saveMenuItem = PhCreateEMenuItem(0, PH_THREAD_TREELIST_MENUITEM_SAVE, L\"Save...\", NULL, NULL);\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, hideSuspendedMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, hideGuiMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, highlightSuspendedMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, highlightGuiMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, saveMenuItem, ULONG_MAX);\n\n                    if (threadsContext->ListContext.HideSuspended)\n                        hideSuspendedMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (threadsContext->ListContext.HideGuiThreads)\n                        hideGuiMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (threadsContext->ListContext.HighlightSuspended)\n                        highlightSuspendedMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (threadsContext->ListContext.HighlightGuiThreads)\n                        highlightGuiMenuItem->Flags |= PH_EMENU_CHECKED;\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        rect.left,\n                        rect.bottom\n                        );\n\n                    if (selectedItem && selectedItem->Id)\n                    {\n                        if (selectedItem->Id == PH_THREAD_TREELIST_MENUITEM_SAVE)\n                        {\n                            PhpProcessThreadsSave(threadsContext);\n                        }\n                        else\n                        {\n                            PhSetOptionsThreadList(&threadsContext->ListContext, selectedItem->Id);\n                            PhSaveSettingsThreadList(&threadsContext->ListContext);\n                            PhApplyTreeNewFilters(&threadsContext->ListContext.TreeFilterSupport);\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_SETACTIVE:\n                break;\n            case PSN_KILLACTIVE:\n                // Can't disable, it screws up the deltas.\n                break;\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)threadsContext->TreeNewHandle);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            if (LOWORD(wParam) == 'K')\n            {\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    SetFocus(threadsContext->SearchboxHandle);\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    case WM_PH_THREADS_UPDATED:\n        {\n            ULONG upToRunId = (ULONG)wParam;\n            BOOLEAN firstRun = !!lParam;\n            PPH_PROVIDER_EVENT events;\n            ULONG count;\n            ULONG i;\n\n            events = PhFlushProviderEventQueue(&threadsContext->EventQueue, upToRunId, &count);\n\n            if (events)\n            {\n                TreeNew_SetRedraw(threadsContext->TreeNewHandle, FALSE);\n\n                for (i = 0; i < count; i++)\n                {\n                    PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]);\n                    PPH_THREAD_ITEM threadItem = PH_PROVIDER_EVENT_OBJECT(events[i]);\n\n                    switch (type)\n                    {\n                    case ProviderAddedEvent:\n                        PhAddThreadNode(&threadsContext->ListContext, threadItem, firstRun);\n                        PhDereferenceObject(threadItem);\n                        break;\n                    case ProviderModifiedEvent:\n                        PhUpdateThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId));\n                        break;\n                    case ProviderRemovedEvent:\n                        PhRemoveThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId));\n                        break;\n                    }\n                }\n\n                PhFree(events);\n            }\n\n            PhTickThreadNodes(&threadsContext->ListContext);\n\n            // Refresh the visible nodes.\n            PhApplyTreeNewFilters(&threadsContext->ListContext.TreeFilterSupport);\n\n            if (count != 0)\n                TreeNew_SetRedraw(threadsContext->TreeNewHandle, TRUE);\n\n            if (propPageContext->PropContext->SelectThreadId)\n            {\n                PPH_THREAD_NODE threadNode;\n\n                if (threadNode = PhFindThreadNode(&threadsContext->ListContext, propPageContext->PropContext->SelectThreadId))\n                {\n                    if (threadNode->Node.Visible)\n                    {\n                        TreeNew_FocusMarkSelectNode(threadsContext->TreeNewHandle, &threadNode->Node);\n                    }\n                }\n\n                propPageContext->PropContext->SelectThreadId = NULL;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpgtok.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2018-2022\n *\n */\n\n#include <phapp.h>\n#include <procprp.h>\n#include <procprv.h>\n\n_Function_class_(PH_OPEN_OBJECT)\nNTSTATUS NTAPI PhpOpenProcessTokenForPage(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    if (!PH_IS_REAL_PROCESS_ID(Context))\n        return STATUS_UNSUCCESSFUL;\n\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        (HANDLE)Context\n        )))\n        return status;\n\n    if (!NT_SUCCESS(status = PhOpenProcessToken(\n        processHandle,\n        DesiredAccess | TOKEN_READ | TOKEN_ADJUST_DEFAULT | READ_CONTROL,\n        Handle\n        )))\n    {\n        if (!NT_SUCCESS(status = PhOpenProcessToken(\n            processHandle,\n            DesiredAccess | TOKEN_READ | TOKEN_ADJUST_DEFAULT,\n            Handle\n            )))\n        {\n            status = PhOpenProcessToken(\n                processHandle,\n                DesiredAccess,\n                Handle\n                );\n        }\n    }\n\n    NtClose(processHandle);\n\n    return status;\n}\n\n_Function_class_(PH_CLOSE_OBJECT)\nNTSTATUS PhpCloseProcessTokenForPage(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle) NtClose(Handle);\n    return STATUS_SUCCESS;\n}\n\nINT_PTR CALLBACK PhpProcessTokenHookProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            if (PhGetWindowContext(hwndDlg, 0xD))\n                PhRemoveWindowContext(hwndDlg, 0xD);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            if (!PhGetWindowContext(hwndDlg, 0xD)) // LayoutInitialized\n            {\n                PPH_LAYOUT_ITEM dialogItem;\n\n                // This is a big violation of abstraction...\n\n                dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USER), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USERSID), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIRTUALIZED), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS), dialogItem, PH_ANCHOR_ALL);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DEFAULTPERM), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PERMISSIONS), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n                PhDoPropPageLayout(hwndDlg);\n\n                PhSetWindowContext(hwndDlg, 0xD, UlongToPtr(TRUE));\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/prpgvdm.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2021-2023\n *\n */\n\n#ifdef _M_IX86\n#include <phapp.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <procprp.h>\n#include <procprv.h>\n#include <settings.h>\n#include <emenu.h>\n#include <mapldr.h>\n\n#include <vdmdbg.h>\n\n#define WM_PH_VDMDBG_UPDATE (WM_APP + 251)\n\ntypedef struct _PH_NTVDM_CONTEXT\n{\n    PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;\n    HWND WindowHandle;\n    HWND ListViewHandle;\n    BOOLEAN Enabled;\n    PPH_LIST VdmHostProcessList;\n} PH_NTVDM_CONTEXT, *PPH_NTVDM_CONTEXT;\n\ntypedef struct _PH_NTVDM_ENTRY\n{\n    ULONG ThreadId;\n    USHORT Mod16;\n    USHORT Task16;\n    PPH_STRING ModuleName;\n    PPH_STRING FileName;\n} PH_NTVDM_ENTRY, *PPH_NTVDM_ENTRY;\n\nstatic INT (WINAPI* VDMEnumTaskWOWEx_I)(\n    _In_ ULONG ProcessId,\n    _In_ TASKENUMPROCEX fp,\n    _In_ LPARAM lparam\n    ) = NULL;\nstatic BOOL (WINAPI* VDMTerminateTaskWOW_I)(\n    _In_ ULONG ProcessId,\n    _In_ USHORT TaskId\n    ) = NULL;\n\nPVOID PhpGetVdmDbgDllBase(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID imageBaseAddress = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PPH_STRING systemFileName;\n\n        if (systemFileName = PhGetSystemDirectoryWin32Z(L\"\\\\vdmdbg.dll\"))\n        {\n            if (!(imageBaseAddress = PhGetLoaderEntryDllBase(&systemFileName->sr, NULL)))\n                imageBaseAddress = PhLoadLibrary(PhGetString(systemFileName));\n\n            PhDereferenceObject(systemFileName);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return imageBaseAddress;\n}\n\nBOOL WINAPI PhpVDMEnumTaskWOWCallback(\n    _In_ ULONG ThreadId,\n    _In_ USHORT Mod16,\n    _In_ USHORT Task16,\n    _In_ PCSTR ModName,\n    _In_ PCSTR FileName,\n    _In_ LPARAM Context\n    )\n{\n    PPH_LIST vdmTaskList = (PPH_LIST)Context;\n    PPH_NTVDM_ENTRY entry;\n\n    entry = PhAllocateZero(sizeof(PH_NTVDM_ENTRY));\n    entry->ThreadId = ThreadId;\n    entry->Mod16 = Mod16;\n    entry->Task16 = Task16;\n    entry->ModuleName = PhZeroExtendToUtf16(ModName);\n    entry->FileName = PhZeroExtendToUtf16(FileName);\n\n    PhAddItemList(vdmTaskList, entry);\n\n    return FALSE;\n}\n\nPPH_LIST PhpQueryVdmHostProcess(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PPH_LIST vdmTaskList;\n\n    if (!VDMEnumTaskWOWEx_I)\n    {\n        PVOID imageBaseAddress;\n\n        if (imageBaseAddress = PhpGetVdmDbgDllBase())\n        {\n            VDMEnumTaskWOWEx_I = PhGetDllBaseProcedureAddress(imageBaseAddress, \"VDMEnumTaskWOWEx\", 0);\n        }\n    }\n\n    if (!VDMEnumTaskWOWEx_I)\n        return NULL;\n\n    vdmTaskList = PhCreateList(1);\n\n    VDMEnumTaskWOWEx_I(\n        HandleToUlong(ProcessItem->ProcessId),\n        PhpVDMEnumTaskWOWCallback,\n        (LPARAM)vdmTaskList\n        );\n\n    return vdmTaskList;\n}\n\n// This method is a rough equivalent to TerminateProcess() in Win32.\n// It should be avoided, if possible. It does not give the task a chance to cleanly exit, so data may be lost.\n// Unlike Win32, the WowExec is not guaranteed to clean up after a terminated task.\n// This can leave the VDM corrupt and unusable.\n// To terminate the task cleanly, send a WM_CLOSE to its top-level window.\nBOOLEAN PhpTerminateVdmTask(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ USHORT TaskId\n    )\n{\n    if (!VDMTerminateTaskWOW_I)\n    {\n        PVOID imageBaseAddress;\n\n        if (imageBaseAddress = PhpGetVdmDbgDllBase())\n        {\n            VDMTerminateTaskWOW_I = PhGetDllBaseProcedureAddress(imageBaseAddress, \"VDMTerminateTaskWOW\", 0);\n        }\n    }\n\n    if (!VDMTerminateTaskWOW_I)\n        return FALSE;\n\n    return !!VDMTerminateTaskWOW_I(HandleToUlong(ProcessItem->ProcessId), TaskId);\n}\n\nstatic VOID NTAPI PhpVdmHostProcessUpdateHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_NTVDM_CONTEXT context = (PPH_NTVDM_CONTEXT)Context;\n\n    if (context && context->Enabled)\n    {\n        PostMessage(context->WindowHandle, WM_PH_VDMDBG_UPDATE, 0, 0);\n    }\n}\n\nVOID PhpClearVdmHostProcessItems(\n    _Inout_ PPH_NTVDM_CONTEXT Context\n    )\n{\n    ULONG i;\n    PPH_NTVDM_ENTRY entry;\n\n    for (i = 0; i < Context->VdmHostProcessList->Count; i++)\n    {\n        entry = Context->VdmHostProcessList->Items[i];\n\n        if (entry->FileName)\n            PhDereferenceObject(entry->FileName);\n        if (entry->ModuleName)\n            PhDereferenceObject(entry->ModuleName);\n\n        PhFree(entry);\n    }\n\n    PhClearList(Context->VdmHostProcessList);\n}\n\nVOID PhpRefreshVdmHostProcess(\n    _In_ HWND hwndDlg,\n    _Inout_ PPH_NTVDM_CONTEXT Context,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PVOID selectedIndex;\n    PPH_LIST providerList;\n\n    ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE);\n\n    selectedIndex = PhGetSelectedListViewItemParam(Context->ListViewHandle);\n    ListView_DeleteAllItems(Context->ListViewHandle);\n    PhpClearVdmHostProcessItems(Context);\n\n    if (providerList = PhpQueryVdmHostProcess(ProcessItem))\n    {\n        for (ULONG i = 0; i < providerList->Count; i++)\n        {\n            PPH_NTVDM_ENTRY entry = providerList->Items[i];\n            INT lvItemIndex;\n\n            lvItemIndex = PhAddListViewItem(\n                Context->ListViewHandle,\n                MAXINT,\n                PhGetStringOrEmpty(entry->ModuleName),\n                UlongToPtr(Context->VdmHostProcessList->Count + 1)\n                );\n            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, PhGetStringOrEmpty(entry->FileName));\n            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, PhaFormatUInt64(entry->ThreadId, FALSE)->Buffer);\n            PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 3, PhaFormatUInt64(entry->Task16, FALSE)->Buffer);\n\n            PhAddItemList(Context->VdmHostProcessList, entry);\n        }\n\n        PhDereferenceObject(providerList);\n    }\n\n    if (selectedIndex)\n    {\n        ListView_SetItemState(Context->ListViewHandle, PtrToUlong(selectedIndex) - 1,\n            LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);\n        ListView_EnsureVisible(Context->ListViewHandle, PtrToUlong(selectedIndex) - 1, FALSE);\n    }\n\n    ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE);\n}\n\nINT_PTR CALLBACK PhpProcessVdmHostProcessDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    LPPROPSHEETPAGE propSheetPage;\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n    PPH_NTVDM_CONTEXT context;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))\n    {\n        context = (PPH_NTVDM_CONTEXT)propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context = propPageContext->Context = PhAllocateZero(sizeof(PH_NTVDM_CONTEXT));\n            context->WindowHandle = hwndDlg;\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            context->Enabled = TRUE;\n            context->VdmHostProcessList = PhCreateList(1);\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 140, L\"Module name\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 180, L\"File name\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 80, L\"Thread Id\");\n            PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 80, L\"Task Id\");\n            PhSetExtendedListView(context->ListViewHandle);\n            PhLoadListViewColumnsFromSetting(SETTING_VDM_HOST_LIST_VIEW_COLUMNS, context->ListViewHandle);\n\n            PhpRefreshVdmHostProcess(hwndDlg, context, processItem);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n                PhpVdmHostProcessUpdateHandler,\n                context,\n                &context->ProcessesUpdatedRegistration\n                );\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &context->ProcessesUpdatedRegistration);\n\n            PhSaveListViewColumnsToSetting(SETTING_VDM_HOST_LIST_VIEW_COLUMNS, context->ListViewHandle);\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            PhpClearVdmHostProcessItems(context);\n            PhDereferenceObject(context->VdmHostProcessList);\n\n            PhFree(context);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, context->ListViewHandle, dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_SETACTIVE:\n                context->Enabled = TRUE;\n                break;\n            case PSN_KILLACTIVE:\n                context->Enabled = FALSE;\n                break;\n            }\n\n            PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PVOID index;\n                PPH_EMENU_ITEM selectedItem;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                if (index = PhGetSelectedListViewItemParam(context->ListViewHandle))\n                {\n                    PPH_EMENU menu;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L\"Terminate\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 4, L\"Open &file location\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 5, L\"&Inspect\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n                    PhDestroyEMenu(menu);\n\n                    if (selectedItem && selectedItem->Id != ULONG_MAX)\n                    {\n                        PPH_NTVDM_ENTRY entry;\n                        BOOLEAN handled;\n\n                        handled = PhHandleCopyListViewEMenuItem(selectedItem);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (handled)\n                            break;\n\n                        entry = context->VdmHostProcessList->Items[PtrToUlong(index) - 1];\n\n                        switch (selectedItem->Id)\n                        {\n                        case 1:\n                            {\n                                if (!PhpTerminateVdmTask(processItem, entry->Task16))\n                                {\n                                    PhShowStatus(hwndDlg, L\"Unable to terminate the task.\", 0, PhGetLastError());\n                                }\n                            }\n                            break;\n                        case 4:\n                            {\n                                if (!PhIsNullOrEmptyString(entry->FileName) && PhDoesFileExistWin32(PhGetString(entry->FileName)))\n                                {\n                                    PhShellExecuteUserString(\n                                        hwndDlg,\n                                        SETTING_FILE_BROWSE_EXECUTABLE,\n                                        PhGetString(entry->FileName),\n                                        FALSE,\n                                        L\"Make sure the Explorer executable file is present.\"\n                                        );\n                                }\n                            }\n                            break;\n                        case 5:\n                            {\n                                if (!PhIsNullOrEmptyString(entry->FileName) && PhDoesFileExistWin32(PhGetString(entry->FileName)))\n                                {\n                                    PhShellExecuteUserString(\n                                        hwndDlg,\n                                        SETTING_PROGRAM_INSPECT_EXECUTABLES,\n                                        PhGetString(entry->FileName),\n                                        FALSE,\n                                        L\"Make sure the PE Viewer executable file is present.\"\n                                        );\n                                }\n                            }\n                            break;\n                        case IDC_COPY:\n                            {\n                                PhCopyListView(context->ListViewHandle);\n                            }\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n        break;\n    case WM_PH_VDMDBG_UPDATE:\n        {\n            PhpRefreshVdmHostProcess(hwndDlg, context, processItem);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n#endif\n"
  },
  {
    "path": "SystemInformer/prpgwmi.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <cpysave.h>\n#include <emenu.h>\n#include <secwmi.h>\n#include <settings.h>\n#include <mapldr.h>\n\n#include <phsettings.h>\n#include <procprp.h>\n#include <procprpp.h>\n#include <procprv.h>\n\n#include <wbemidl.h>\n\ntypedef struct _PH_PROCESS_WMI_CONTEXT\n{\n    HWND WindowHandle;\n    HWND TreeNewHandle;\n    HWND SearchWindowHandle;\n    HFONT TreeNewFont;\n\n    PPH_PROCESS_ITEM ProcessItem;\n    PPH_STRING DefaultNamespace;\n    ULONG_PTR  SearchMatchHandle;\n    PPH_STRING StatusMessage;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG HideDefaultNamespace : 1;\n            ULONG HighlightDefaultNamespace : 1;\n            ULONG Spare : 30;\n        };\n    };\n\n    PPH_LIST NodeList;\n    PPH_HASHTABLE NodeHashtable;\n    PPH_TN_FILTER_ENTRY TreeFilterEntry;\n    ULONG TreeNewSortColumn;\n    PH_TN_FILTER_SUPPORT TreeFilterSupport;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PH_CM_MANAGER Cm;\n} PH_PROCESS_WMI_CONTEXT, *PPH_PROCESS_WMI_CONTEXT;\n\ntypedef struct _PH_WMI_ENTRY\n{\n    //PPH_STRING InstancePath;\n    PPH_STRING RelativePath;\n    PPH_STRING ProviderName;\n    PPH_STRING ProviderNamespace;\n    PPH_STRING FileName;\n    PPH_STRING UserName;\n} PH_WMI_ENTRY, *PPH_WMI_ENTRY;\n\ntypedef enum _PROCESS_WMI_TREE_MENU_ITEM\n{\n    PROCESS_WMI_TREE_MENU_ITEM_HIDE_DEFAULT_NAMESPACE = 1,\n    PROCESS_WMI_TREE_MENU_ITEM_HIGHLIGHT_DEFAULT_NAMESPACE,\n    PROCESS_WMI_TREE_MENU_ITEM_MAXIMUM\n} WMI_TREE_MENU_ITEM;\n\ntypedef enum _PROCESS_WMI_TREE_COLUMN_ITEM\n{\n    PROCESS_WMI_COLUMN_ITEM_PROVIDER,\n    PROCESS_WMI_COLUMN_ITEM_NAMESPACE,\n    PROCESS_WMI_COLUMN_ITEM_FILENAME,\n    PROCESS_WMI_COLUMN_ITEM_USER,\n    PROCESS_WMI_COLUMN_ITEM_MAXIMUM\n} WMI_TREE_COLUMN_ITEM;\n\ntypedef struct _PHP_PROCESS_WMI_TREENODE\n{\n    PH_TREENEW_NODE Node;\n\n    ULONG Id;\n    PPH_WMI_ENTRY Provider;\n\n    PH_STRINGREF TextCache[PROCESS_WMI_COLUMN_ITEM_MAXIMUM];\n} PHP_PROCESS_WMI_TREENODE, *PPHP_PROCESS_WMI_TREENODE;\n\nPPHP_PROCESS_WMI_TREENODE PhpAddWmiProviderNode(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ PPH_WMI_ENTRY Entry\n    );\n\nPPHP_PROCESS_WMI_TREENODE PhpFindWmiProviderNode(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ PPH_STRING RelativePath\n    );\n\nVOID PhpClearWmiProviderTree(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context\n    );\n\nPPHP_PROCESS_WMI_TREENODE PhpGetSelectedWmiProviderNode(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context\n    );\n\n_Success_(return)\nBOOLEAN PhpGetSelectedWmiProviderNodes(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _Out_ PPHP_PROCESS_WMI_TREENODE * *Nodes,\n    _Out_ PULONG NumberOfNodes\n    );\n\nPVOID PhGetWmiUtilsDllBase(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID imageBaseAddress = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PPH_STRING fileName;\n\n        if (fileName = PhGetSystemDirectoryWin32Z(L\"\\\\wbem\\\\wmiutils.dll\"))\n        {\n            imageBaseAddress = PhLoadLibrary(PhGetString(fileName));\n            PhDereferenceObject(fileName);\n        }\n\n        {\n            typedef void (WINAPI* _SetOaNoCache)(void);\n            _SetOaNoCache SetOaNoCache_I;\n\n            if (SetOaNoCache_I = PhGetModuleProcAddress(L\"oleaut32.dll\", \"SetOaNoCache\"))\n            {\n                SetOaNoCache_I();\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return imageBaseAddress;\n}\n\nHRESULT PhpWmiProviderExecMethod(\n    _In_ PPH_STRINGREF Method,\n    _In_ PWSTR ProcessIdString,\n    _In_ PPH_WMI_ENTRY Entry\n    )\n{\n    static CONST PH_STRINGREF wbemResource = PH_STRINGREF_INIT(L\"Root\\\\CIMV2\");\n    static CONST PH_STRINGREF wbemLanguage = PH_STRINGREF_INIT(L\"WQL\");\n    HRESULT status;\n    PPH_STRING querySelectString = NULL;\n    BSTR wbemResourceString = NULL;\n    BSTR wbemLanguageString = NULL;\n    BSTR wbemQueryString = NULL;\n    IWbemLocator* wbemLocator = NULL;\n    IWbemServices* wbemServices = NULL;\n    IEnumWbemClassObject* wbemEnumerator = NULL;\n    IWbemClassObject* wbemClassObject;\n\n    status = PhGetWbemLocatorClass(\n        &wbemLocator\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    wbemResourceString = PhStringRefToBSTR(&wbemResource);\n    status = IWbemLocator_ConnectServer(\n        wbemLocator,\n        wbemResourceString,\n        NULL,\n        NULL,\n        NULL,\n        WBEM_FLAG_CONNECT_USE_MAX_WAIT,\n        NULL,\n        NULL,\n        &wbemServices\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = PhCoSetProxyBlanket(\n        (IUnknown*)wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    querySelectString = PhFormatString(\n        L\"%s %s %s %s %s %s = %s\",\n        L\"SELECT\",\n        L\"Namespace,Provider,User,__RELPATH\",\n        L\"FROM\",\n        L\"Msft_Providers\",\n        L\"WHERE\",\n        L\"HostProcessIdentifier\",\n        ProcessIdString\n        );\n\n    wbemLanguageString = PhStringRefToBSTR(&wbemLanguage);\n    wbemQueryString = PhStringRefToBSTR(&querySelectString->sr);\n\n    if (FAILED(status = IWbemServices_ExecQuery(\n        wbemServices,\n        wbemLanguageString,\n        wbemQueryString,\n        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,\n        NULL,\n        &wbemEnumerator\n        )))\n    {\n        goto CleanupExit;\n    }\n\n    while (TRUE)\n    {\n        PPH_STRING namespacePath = NULL;\n        PPH_STRING providerName = NULL;\n        PPH_STRING userName = NULL;\n        PPH_STRING relativePath = NULL;\n        ULONG count = 0;\n\n        IEnumWbemClassObject_Next(wbemEnumerator, WBEM_INFINITE, 1, &wbemClassObject, &count);\n\n        if (count == 0)\n            break;\n\n        namespacePath = PhGetWbemClassObjectString(wbemClassObject, L\"Namespace\");\n        providerName = PhGetWbemClassObjectString(wbemClassObject, L\"Provider\");\n        userName = PhGetWbemClassObjectString(wbemClassObject, L\"User\");\n        relativePath = PhGetWbemClassObjectString(wbemClassObject, L\"__RELPATH\");\n\n        if (namespacePath && providerName && userName && relativePath)\n        {\n            if (\n                PhEqualString(Entry->ProviderNamespace, namespacePath, FALSE) &&\n                PhEqualString(Entry->ProviderName, providerName, FALSE) &&\n                PhEqualString(Entry->UserName, userName, FALSE)\n                )\n            {\n                BSTR wbemPathString = PhStringRefToBSTR(&relativePath->sr);\n                BSTR wbemMethodString = PhStringRefToBSTR(Method);\n\n                status = IWbemServices_ExecMethod(\n                    wbemServices,\n                    wbemPathString,\n                    wbemMethodString,\n                    0,\n                    NULL,\n                    wbemClassObject,\n                    NULL,\n                    NULL\n                    );\n\n                SysFreeString(wbemMethodString);\n                SysFreeString(wbemPathString);\n            }\n        }\n\n        if (relativePath)\n            PhDereferenceObject(relativePath);\n        if (userName)\n            PhDereferenceObject(userName);\n        if (providerName)\n            PhDereferenceObject(providerName);\n        if (namespacePath)\n            PhDereferenceObject(namespacePath);\n\n        IWbemClassObject_Release(wbemClassObject);\n    }\n\nCleanupExit:\n    if (wbemQueryString)\n        SysFreeString(wbemQueryString);\n    if (wbemLanguageString)\n        SysFreeString(wbemLanguageString);\n    if (wbemResourceString)\n        SysFreeString(wbemResourceString);\n    if (querySelectString)\n        PhDereferenceObject(querySelectString);\n    if (wbemEnumerator)\n        IEnumWbemClassObject_Release(wbemEnumerator);\n    if (wbemServices)\n        IWbemServices_Release(wbemServices);\n    if (wbemLocator)\n        IWbemLocator_Release(wbemLocator);\n\n    return status;\n}\n\nHRESULT PhpQueryWmiProviderFileName(\n    _In_ PPH_STRING ProviderNameSpace,\n    _In_ PPH_STRING ProviderName,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    static CONST PH_STRINGREF wbemLanguage = PH_STRINGREF_INIT(L\"WQL\");\n    HRESULT status;\n    PPH_STRING fileName = NULL;\n    PPH_STRING clsidString = NULL;\n    PPH_STRING querySelectString = NULL;\n    BSTR wbemResourceString = NULL;\n    BSTR wbemLanguageString = NULL;\n    BSTR wbemQueryString = NULL;\n    IWbemLocator* wbemLocator = NULL;\n    IWbemServices* wbemServices = NULL;\n    IEnumWbemClassObject* wbemEnumerator = NULL;\n    IWbemClassObject *wbemClassObject = NULL;\n    ULONG count = 0;\n\n    status = PhGetWbemLocatorClass(\n        &wbemLocator\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    wbemResourceString = PhStringRefToBSTR(&ProviderNameSpace->sr);\n    status = IWbemLocator_ConnectServer(\n        wbemLocator,\n        wbemResourceString,\n        NULL,\n        NULL,\n        NULL,\n        WBEM_FLAG_CONNECT_USE_MAX_WAIT,\n        NULL,\n        NULL,\n        &wbemServices\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = PhCoSetProxyBlanket(\n        (IUnknown*)wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    querySelectString = PhFormatString(\n        L\"%s %s %s %s %s %s = '%s'\",\n        L\"SELECT\",\n        L\"clsid\",\n        L\"FROM\",\n        L\"__Win32Provider\",\n        L\"WHERE\",\n        L\"Name\",\n        PhGetString(ProviderName)\n        );\n\n    wbemLanguageString = PhStringRefToBSTR(&wbemLanguage);\n    wbemQueryString = PhStringRefToBSTR(&querySelectString->sr);\n\n    if (FAILED(status = IWbemServices_ExecQuery(\n        wbemServices,\n        wbemLanguageString,\n        wbemQueryString,\n        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,\n        NULL,\n        &wbemEnumerator\n        )))\n    {\n        goto CleanupExit;\n    }\n\n    if (SUCCEEDED(status = IEnumWbemClassObject_Next(\n        wbemEnumerator,\n        WBEM_INFINITE,\n        1,\n        &wbemClassObject,\n        &count\n        )))\n    {\n        clsidString = PhGetWbemClassObjectString(wbemClassObject, L\"CLSID\");\n        IWbemClassObject_Release(wbemClassObject);\n    }\n\n    // Lookup the GUID in the registry to determine the name and file name.\n\n    if (clsidString)\n    {\n        HANDLE keyHandle;\n        PPH_STRING keyPath;\n\n        keyPath = PhConcatStrings(\n            4,\n            L\"CLSID\\\\\",\n            PhGetString(clsidString),\n            L\"\\\\\",\n            L\"InprocServer32\"\n            );\n\n        if (SUCCEEDED(status = HRESULT_FROM_NT(PhOpenKey(\n            &keyHandle,\n            KEY_QUERY_VALUE,\n            PH_KEY_CLASSES_ROOT,\n            &keyPath->sr,\n            0\n            ))))\n        {\n            if (fileName = PhQueryRegistryString(keyHandle, NULL))\n            {\n                PPH_STRING expandedString;\n\n                if (expandedString = PhExpandEnvironmentStrings(&fileName->sr))\n                {\n                    PhMoveReference(&fileName, expandedString);\n                }\n            }\n\n            NtClose(keyHandle);\n        }\n\n        PhDereferenceObject(keyPath);\n    }\n\nCleanupExit:\n    if (wbemQueryString)\n        SysFreeString(wbemQueryString);\n    if (wbemLanguageString)\n        SysFreeString(wbemLanguageString);\n    if (wbemResourceString)\n        SysFreeString(wbemResourceString);\n    if (clsidString)\n        PhDereferenceObject(clsidString);\n    if (querySelectString)\n        PhDereferenceObject(querySelectString);\n    if (wbemEnumerator)\n        IEnumWbemClassObject_Release(wbemEnumerator);\n    if (wbemServices)\n        IWbemServices_Release(wbemServices);\n    if (wbemLocator)\n        IWbemLocator_Release(wbemLocator);\n\n    if (SUCCEEDED(status))\n    {\n        *FileName = fileName;\n    }\n\n    return status;\n}\n\nHRESULT PhpQueryWmiProviderHostProcess(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ LONG Timeout,\n    _Out_ PPH_LIST* ProviderList\n    )\n{\n    static CONST PH_STRINGREF wbemResource = PH_STRINGREF_INIT(L\"Root\\\\CIMV2\");\n    static CONST PH_STRINGREF wbemLanguage = PH_STRINGREF_INIT(L\"WQL\");\n    HRESULT status;\n    PPH_LIST providerList = NULL;\n    PPH_STRING querySelectString = NULL;\n    BSTR wbemResourceString = NULL;\n    BSTR wbemLanguageString = NULL;\n    BSTR wbemQueryString = NULL;\n    IWbemLocator* wbemLocator = NULL;\n    IWbemServices* wbemServices = NULL;\n    IEnumWbemClassObject* wbemEnumerator = NULL;\n    IWbemClassObject *wbemClassObject;\n\n    status = PhGetWbemLocatorClass(\n        &wbemLocator\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    wbemResourceString = PhStringRefToBSTR(&wbemResource);\n    status = IWbemLocator_ConnectServer(\n        wbemLocator,\n        wbemResourceString,\n        NULL,\n        NULL,\n        NULL,\n        WBEM_FLAG_CONNECT_USE_MAX_WAIT,\n        NULL,\n        NULL,\n        &wbemServices\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = PhCoSetProxyBlanket(\n        (IUnknown*)wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    querySelectString = PhFormatString(\n        L\"%s %s %s %s %s %s = %s\",\n        L\"SELECT\",\n        L\"Namespace,Provider,User,__RELPATH\",\n        L\"FROM\",\n        L\"Msft_Providers\",\n        L\"WHERE\",\n        L\"HostProcessIdentifier\",\n        ProcessItem->ProcessIdString\n        );\n\n    wbemLanguageString = PhStringRefToBSTR(&wbemLanguage);\n    wbemQueryString = PhStringRefToBSTR(&querySelectString->sr);\n\n    if (FAILED(status = IWbemServices_ExecQuery(\n        wbemServices,\n        wbemLanguageString,\n        wbemQueryString,\n        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,\n        NULL,\n        &wbemEnumerator\n        )))\n    {\n        goto CleanupExit;\n    }\n\n    providerList = PhCreateList(1);\n\n    while (TRUE)\n    {\n        ULONG count = 0;\n        PPH_WMI_ENTRY entry;\n\n        IEnumWbemClassObject_Next(wbemEnumerator, Timeout, 1, &wbemClassObject, &count);\n\n        if (count == 0)\n            break;\n\n        entry = PhAllocateZero(sizeof(PH_WMI_ENTRY));\n        entry->ProviderNamespace = PhGetWbemClassObjectString(wbemClassObject, L\"Namespace\");\n        entry->ProviderName = PhGetWbemClassObjectString(wbemClassObject, L\"Provider\");\n        entry->UserName = PhGetWbemClassObjectString(wbemClassObject, L\"User\");\n        //entry->InstancePath = PhGetWbemClassObjectString(wbemClassObject, L\"__PATH\");\n        entry->RelativePath = PhGetWbemClassObjectString(wbemClassObject, L\"__RELPATH\");\n        IWbemClassObject_Release(wbemClassObject);\n\n        if (entry->ProviderNamespace && entry->ProviderName)\n        {\n            PPH_STRING fileName = NULL;\n\n            if (SUCCEEDED(PhpQueryWmiProviderFileName(entry->ProviderNamespace, entry->ProviderName, &fileName)))\n            {\n                entry->FileName = fileName;\n            }\n        }\n\n        PhAddItemList(providerList, entry);\n    }\n\nCleanupExit:\n    if (wbemQueryString)\n        SysFreeString(wbemQueryString);\n    if (wbemLanguageString)\n        SysFreeString(wbemLanguageString);\n    if (wbemResourceString)\n        SysFreeString(wbemResourceString);\n    if (querySelectString)\n        PhDereferenceObject(querySelectString);\n    if (wbemEnumerator)\n        IEnumWbemClassObject_Release(wbemEnumerator);\n    if (wbemServices)\n        IWbemServices_Release(wbemServices);\n    if (wbemLocator)\n        IWbemLocator_Release(wbemLocator);\n\n    if (SUCCEEDED(status))\n    {\n        *ProviderList = providerList;\n    }\n\n    return status;\n}\n\nPPH_STRING PhpQueryWmiProviderStatistics(\n    _In_ PPH_WMI_ENTRY Entry\n    )\n{\n    static CONST PH_STRINGREF wbemResource = PH_STRINGREF_INIT(L\"Root\\\\CIMV2\");\n    HRESULT status;\n    PPH_STRING wbemProviderString = NULL;\n    BSTR wbemResourceString = NULL;\n    IWbemLocator* wbemLocator = NULL;\n    IWbemServices* wbemServices = NULL;\n    IEnumWbemClassObject* wbemEnumerator = NULL;\n    IWbemClassObject *wbemClassObject;\n\n    status = PhGetWbemLocatorClass(\n        &wbemLocator\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    wbemResourceString = PhStringRefToBSTR(&wbemResource);\n    status = IWbemLocator_ConnectServer(\n        wbemLocator,\n        wbemResourceString,\n        NULL,\n        NULL,\n        NULL,\n        WBEM_FLAG_CONNECT_USE_MAX_WAIT,\n        NULL,\n        NULL,\n        &wbemServices\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = PhCoSetProxyBlanket(\n        (IUnknown*)wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = IWbemServices_GetObject(\n        wbemServices,\n        PhGetString(Entry->RelativePath),\n        WBEM_FLAG_RETURN_WBEM_COMPLETE,\n        NULL,\n        &wbemClassObject,\n        NULL\n        );\n\n    if (SUCCEEDED(status))\n    {\n        PPH_STRING string;\n        PH_STRING_BUILDER stringBuilder;\n\n        PhInitializeStringBuilder(&stringBuilder, 0x100);\n        PhAppendFormatStringBuilder(&stringBuilder, L\"Statistics for %s: \\r\\n\\r\\n\", PhGetString(Entry->ProviderName));\n\n        // Note: Strings optimized for string pooling (dmex)\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_AccessCheck\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_AccessCheck\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_CancelQuery\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_CancelQuery\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_CreateClassEnumAsync\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_CreateClassEnumAsync\", L\" \\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_CreateInstanceEnumAsync\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_CreateInstanceEnumAsync\", L\" \\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_CreateRefreshableEnum\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_CreateRefreshableEnum\", L\" \\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_CreateRefreshableObject\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_CreateRefreshableObject\", L\" \\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_CreateRefresher\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_CreateRefresher\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_DeleteClassAsync\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_DeleteClassAsync\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_DeleteInstanceAsync\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_DeleteInstanceAsync\", L\" \\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_ExecMethodAsync\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_ExecMethodAsync\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_ExecQueryAsync\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_ExecQueryAsync\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_FindConsumer\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_FindConsumer\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_GetObjectAsync\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_GetObjectAsync\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_GetObjects\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_GetObjects\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_GetProperty\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_GetProperty\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_NewQuery\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_NewQuery\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_ProvideEvents\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_ProvideEvents\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_PutClassAsync\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_PutClassAsync\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_PutInstanceAsync\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_PutInstanceAsync\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_PutProperty\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_PutProperty\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_QueryInstances\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_QueryInstances\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_SetRegistrationObject\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_SetRegistrationObject\", L\" \\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_StopRefreshing\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_StopRefreshing\", L\" \\t\\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        if (string = PhGetWbemClassObjectString(wbemClassObject, L\"ProviderOperation_ValidateSubscription\"))\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%s:%s\", L\"ProviderOperation_ValidateSubscription\", L\" \\t\");\n            PhAppendStringBuilder(&stringBuilder, &string->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n            PhDereferenceObject(string);\n        }\n\n        IWbemClassObject_Release(wbemClassObject);\n\n        wbemProviderString = PhFinalStringBuilderString(&stringBuilder);\n    }\n\nCleanupExit:\n    if (wbemResourceString)\n        SysFreeString(wbemResourceString);\n    if (wbemEnumerator)\n        IEnumWbemClassObject_Release(wbemEnumerator);\n    if (wbemServices)\n        IWbemServices_Release(wbemServices);\n    if (wbemLocator)\n        IWbemLocator_Release(wbemLocator);\n\n    return wbemProviderString;\n}\n\nPPH_STRING PhpQueryWmiDefaultNamespace(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF wbemKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Wbem\\\\Scripting\");\n    PPH_STRING defaultNameSpace = NULL;\n    HANDLE keyHandle;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_QUERY_VALUE,\n        PH_KEY_LOCAL_MACHINE,\n        &wbemKeyName,\n        0\n        )))\n    {\n        defaultNameSpace = PhQueryRegistryStringZ(keyHandle, L\"Default Namespace\");\n        NtClose(keyHandle);\n    }\n\n    return defaultNameSpace;\n}\n\nVOID PhQueryWmiHostProcessString(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _Inout_ PPH_STRING_BUILDER Providers\n    )\n{\n    PPH_LIST providerList;\n\n    // Note: We use a timeout value of 1 to avoid deadlocks when\n    // the wmiprvse.exe process is suspended. Fixes GH#713 (dmex)\n\n    if (SUCCEEDED(PhpQueryWmiProviderHostProcess(ProcessItem, 1, &providerList)))\n    {\n        for (ULONG i = 0; i < providerList->Count; i++)\n        {\n            PPH_WMI_ENTRY entry = providerList->Items[i];\n\n            PhAppendFormatStringBuilder(\n                Providers,\n                L\"    %s (%s)\\n\",\n                PhGetStringOrEmpty(entry->ProviderName),\n                PhGetStringOrEmpty(entry->FileName)\n                );\n\n            //if (entry->InstancePath)\n            //    PhDereferenceObject(entry->InstancePath);\n            if (entry->RelativePath)\n                PhDereferenceObject(entry->RelativePath);\n            if (entry->ProviderName)\n                PhDereferenceObject(entry->ProviderName);\n            if (entry->ProviderNamespace)\n                PhDereferenceObject(entry->ProviderNamespace);\n            if (entry->FileName)\n                PhDereferenceObject(entry->FileName);\n            if (entry->UserName)\n                PhDereferenceObject(entry->UserName);\n\n            PhFree(entry);\n        }\n\n        PhDereferenceObject(providerList);\n    }\n}\n\nVOID PhpSetWmiProviderListStatusMessage(\n    _Inout_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ HRESULT Status\n    )\n{\n    PPH_STRING statusMessage;\n\n    statusMessage = PhGetStatusMessage(0, HRESULT_CODE(Status)); // HACK\n    PhMoveReference(&Context->StatusMessage, PhConcatStrings2(\n        L\"Unable to query provider information:\\n\",\n        PhGetStringOrDefault(statusMessage, L\"Unknown error.\")\n        ));\n    TreeNew_SetEmptyText(Context->TreeNewHandle, &Context->StatusMessage->sr, 0);\n    //TreeNew_NodesStructured(Context->TreeNewHandle);\n    PhClearReference(&statusMessage);\n}\n\nVOID PhpRefreshWmiProvidersList(\n    _Inout_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    HRESULT status;\n    PPH_LIST providerList;\n\n    PhpClearWmiProviderTree(Context);\n\n    // Note: We should use a timeout value of 1 to avoid deadlocks when the\n    // wmiprvse.exe process is suspended but infinite guarantees a result. (dmex)\n\n    status = PhpQueryWmiProviderHostProcess(\n        ProcessItem,\n        WBEM_INFINITE,\n        &providerList\n        );\n\n    if (SUCCEEDED(status))\n    {\n        for (ULONG i = 0; i < providerList->Count; i++)\n        {\n            PhpAddWmiProviderNode(Context, providerList->Items[i]);\n        }\n\n        PhDereferenceObject(providerList);\n    }\n    else\n    {\n        PhpSetWmiProviderListStatusMessage(Context, status);\n    }\n\n    PhApplyTreeNewFilters(&Context->TreeFilterSupport);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhpShowWmiProviderStatus(\n    _In_opt_ HWND hWnd,\n    _In_opt_ PWSTR Message,\n    _In_ HRESULT Win32Result\n    )\n{\n    PPH_STRING statusMessage;\n\n    statusMessage = PhGetMessage(\n        PhGetWmiUtilsDllBase(),\n        0xb,\n        PhGetUserDefaultLangID(),\n        Win32Result\n        );\n\n    if (PhIsNullOrEmptyString(statusMessage))\n    {\n        PhMoveReference(&statusMessage, PhGetStatusMessage(0, HRESULT_CODE(Win32Result)));\n    }\n\n    if (statusMessage)\n    {\n        if (Message)\n        {\n            PhShowError2(hWnd, Message, L\"%s\", PhGetString(statusMessage));\n        }\n        else\n        {\n            PhShowError2(hWnd, L\"Unable to perform the operation.\", L\"%s\", PhGetString(statusMessage));\n        }\n\n        PhDereferenceObject(statusMessage);\n    }\n    else\n    {\n        if (Message)\n        {\n            PhShowError2(hWnd, L\"Unable to perform the operation.\", L\"%s\", Message);\n        }\n        else\n        {\n            PhShowStatus(hWnd, L\"Unable to perform the operation.\", STATUS_UNSUCCESSFUL, 0);\n        }\n    }\n}\n\nVOID PhpShowWmiProviderNodeContextMenu(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ PPH_TREENEW_CONTEXT_MENU ContextMenuEvent\n    )\n{\n    PPHP_PROCESS_WMI_TREENODE* nodes;\n    ULONG numberOfNodes;\n    PPH_EMENU menu;\n    PPH_EMENU_ITEM selectedItem;\n\n    if (!PhpGetSelectedWmiProviderNodes(Context, &nodes, &numberOfNodes))\n        return;\n    if (numberOfNodes == 0)\n        return;\n\n    menu = PhCreateEMenu();\n\n    if (PhGetIntegerSetting(SETTING_WMI_PROVIDER_ENABLE_HIDDEN_MENU))\n    {\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L\"&Suspend\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 2, L\"Res&ume\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 3, L\"Un&load\", NULL, NULL), ULONG_MAX);\n        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    }\n\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 4, L\"&Inspect\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 5, L\"S&tatistics\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 6, L\"Open &file location\", NULL, NULL), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n    PhInsertCopyCellEMenuItem(menu, IDC_COPY, Context->TreeNewHandle, ContextMenuEvent->Column);\n\n    selectedItem = PhShowEMenu(\n        menu,\n        Context->WindowHandle,\n        PH_EMENU_SHOW_LEFTRIGHT,\n        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n        ContextMenuEvent->Location.x,\n        ContextMenuEvent->Location.y\n        );\n\n    if (selectedItem && selectedItem->Id != ULONG_MAX)\n    {\n        if (!PhHandleCopyCellEMenuItem(selectedItem))\n        {\n            switch (selectedItem->Id)\n            {\n            case 1:\n                {\n                    HRESULT status;\n\n                    status = PhpWmiProviderExecMethod(&(PH_STRINGREF)PH_STRINGREF_INIT(L\"Suspend\"), Context->ProcessItem->ProcessIdString, nodes[0]->Provider);\n\n                    if (FAILED(status))\n                    {\n                        PhpShowWmiProviderStatus(Context->WindowHandle, L\"Unable to perform the operation.\", status);\n                    }\n                }\n                break;\n            case 2:\n                {\n                    HRESULT status;\n\n                    status = PhpWmiProviderExecMethod(&(PH_STRINGREF)PH_STRINGREF_INIT(L\"Resume\"), Context->ProcessItem->ProcessIdString, nodes[0]->Provider);\n\n                    if (FAILED(status))\n                    {\n                        PhpShowWmiProviderStatus(Context->WindowHandle, L\"Unable to perform the operation.\", status);\n                    }\n                }\n                break;\n            case 3:\n                {\n                    HRESULT status;\n\n                    status = PhpWmiProviderExecMethod(&(PH_STRINGREF)PH_STRINGREF_INIT(L\"Unload\"), Context->ProcessItem->ProcessIdString, nodes[0]->Provider);\n\n                    if (FAILED(status))\n                    {\n                        PhpShowWmiProviderStatus(Context->WindowHandle, L\"Unable to perform the operation.\", status);\n                    }\n                }\n                break;\n            case 4:\n                {\n                    if (!PhIsNullOrEmptyString(nodes[0]->Provider->FileName) && PhDoesFileExistWin32(PhGetString(nodes[0]->Provider->FileName)))\n                    {\n                        PhShellExecuteUserString(\n                            Context->WindowHandle,\n                            SETTING_PROGRAM_INSPECT_EXECUTABLES,\n                            PhGetString(nodes[0]->Provider->FileName),\n                            FALSE,\n                            L\"Make sure the PE Viewer executable file is present.\"\n                            );\n                    }\n                }\n                break;\n            case 5:\n                {\n                    PPH_STRING string;\n\n                    if (string = PhpQueryWmiProviderStatistics(nodes[0]->Provider))\n                    {\n                        PhShowInformationDialog(Context->WindowHandle, PhGetString(string), 0);\n                        PhDereferenceObject(string);\n                    }\n                }\n                break;\n            case 6:\n                {\n                    if (!PhIsNullOrEmptyString(nodes[0]->Provider->FileName) && PhDoesFileExistWin32(PhGetString(nodes[0]->Provider->FileName)))\n                    {\n                        PhShellExecuteUserString(\n                            Context->WindowHandle,\n                            SETTING_FILE_BROWSE_EXECUTABLE,\n                            PhGetString(nodes[0]->Provider->FileName),\n                            FALSE,\n                            L\"Make sure the Explorer executable file is present.\"\n                            );\n                    }\n                }\n                break;\n            case IDC_COPY:\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(Context->TreeNewHandle, 0);\n                    PhSetClipboardString(Context->TreeNewHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            }\n        }\n    }\n\n    PhDestroyEMenu(menu);\n}\n\nVOID PhLoadSettingsWmiProviderList(\n    _Inout_ PPH_PROCESS_WMI_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhGetStringSetting(SETTING_WMI_PROVIDER_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_WMI_PROVIDER_TREE_LIST_SORT);\n    Context->Flags = PhGetIntegerSetting(SETTING_WMI_PROVIDER_TREE_LIST_FLAGS);\n\n    PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSaveSettingsWmiProviderList(\n    _Inout_ PPH_PROCESS_WMI_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings);\n\n    PhSetIntegerSetting(SETTING_WMI_PROVIDER_TREE_LIST_FLAGS, Context->Flags);\n    PhSetStringSetting2(SETTING_WMI_PROVIDER_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_WMI_PROVIDER_TREE_LIST_SORT, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSetOptionsWmiProviderList(\n    _Inout_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ ULONG Options\n    )\n{\n    switch (Options)\n    {\n    case PROCESS_WMI_TREE_MENU_ITEM_HIDE_DEFAULT_NAMESPACE:\n        Context->HideDefaultNamespace = !Context->HideDefaultNamespace;\n        break;\n    case PROCESS_WMI_TREE_MENU_ITEM_HIGHLIGHT_DEFAULT_NAMESPACE:\n        Context->HighlightDefaultNamespace = !Context->HighlightDefaultNamespace;\n        break;\n    }\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpWmiProviderNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPHP_PROCESS_WMI_TREENODE node1 = *(PPHP_PROCESS_WMI_TREENODE*)Entry1;\n    PPHP_PROCESS_WMI_TREENODE node2 = *(PPHP_PROCESS_WMI_TREENODE*)Entry2;\n\n    return PhEqualStringRef(&node1->Provider->RelativePath->sr, &node2->Provider->RelativePath->sr, TRUE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpWmiProviderNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashStringRefEx(&(*(PPHP_PROCESS_WMI_TREENODE*)Entry)->Provider->RelativePath->sr, TRUE, PH_STRING_HASH_X65599);\n}\n\nVOID PhpDestroyWmiProviderNode(\n    _In_ PPHP_PROCESS_WMI_TREENODE Node\n    )\n{\n    if (Node->Provider)\n    {\n        if (Node->Provider->RelativePath)\n            PhDereferenceObject(Node->Provider->RelativePath);\n        if (Node->Provider->ProviderName)\n            PhDereferenceObject(Node->Provider->ProviderName);\n        if (Node->Provider->ProviderNamespace)\n            PhDereferenceObject(Node->Provider->ProviderNamespace);\n        if (Node->Provider->FileName)\n            PhDereferenceObject(Node->Provider->FileName);\n        if (Node->Provider->UserName)\n            PhDereferenceObject(Node->Provider->UserName);\n\n        PhFree(Node->Provider);\n    }\n\n    PhFree(Node);\n}\n\nPPHP_PROCESS_WMI_TREENODE PhpAddWmiProviderNode(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ PPH_WMI_ENTRY Entry\n    )\n{\n    PPHP_PROCESS_WMI_TREENODE node;\n\n    node = PhAllocateZero(sizeof(PHP_PROCESS_WMI_TREENODE));\n    PhInitializeTreeNewNode(&node->Node);\n\n    memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PROCESS_WMI_COLUMN_ITEM_MAXIMUM);\n    node->Node.TextCache = node->TextCache;\n    node->Node.TextCacheSize = PROCESS_WMI_COLUMN_ITEM_MAXIMUM;\n    node->Provider = Entry;\n\n    PhAddEntryHashtable(Context->NodeHashtable, &node);\n    PhAddItemList(Context->NodeList, node);\n\n    if (Context->TreeFilterSupport.FilterList)\n        node->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &node->Node);\n\n    return node;\n}\n\nPPHP_PROCESS_WMI_TREENODE PhpFindWmiProviderNode(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ PPH_STRING RelativePath\n    )\n{\n    PHP_PROCESS_WMI_TREENODE lookupNode;\n    PPHP_PROCESS_WMI_TREENODE lookupNodePtr = &lookupNode;\n    PPHP_PROCESS_WMI_TREENODE *node;\n\n    lookupNode.Provider->RelativePath = RelativePath;\n\n    node = (PPHP_PROCESS_WMI_TREENODE*)PhFindEntryHashtable(\n        Context->NodeHashtable,\n        &lookupNodePtr\n        );\n\n    if (node)\n        return *node;\n    else\n        return NULL;\n}\n\nVOID PhpRemoveWmiProviderNode(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ PPHP_PROCESS_WMI_TREENODE Node\n    )\n{\n    ULONG index = 0;\n\n    PhRemoveEntryHashtable(Context->NodeHashtable, &Node);\n\n    if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX)\n    {\n        PhRemoveItemList(Context->NodeList, index);\n    }\n\n    PhpDestroyWmiProviderNode(Node);\n    //TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhpUpdateWmiProviderNode(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ PPHP_PROCESS_WMI_TREENODE Node\n    )\n{\n    memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * PROCESS_WMI_COLUMN_ITEM_MAXIMUM);\n\n    PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR);\n    //TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhpExpandAllWmiProviderNodes(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _In_ BOOLEAN Expand\n    )\n{\n    ULONG i;\n    BOOLEAN needsRestructure = FALSE;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_MODULE_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Expanded != Expand)\n        {\n            node->Node.Expanded = Expand;\n            needsRestructure = TRUE;\n        }\n    }\n\n    if (needsRestructure)\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\n#define SORT_FUNCTION(Column) PhpWmiProviderTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpWmiProviderTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPHP_PROCESS_WMI_TREENODE node1 = *(PPHP_PROCESS_WMI_TREENODE*)_elem1; \\\n    PPHP_PROCESS_WMI_TREENODE node2 = *(PPHP_PROCESS_WMI_TREENODE*)_elem2; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n         sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \\\n    \\\n    return PhModifySort(sortResult, ((PPH_PROCESS_WMI_CONTEXT)_context)->TreeNewSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpWmiProviderTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    if (Result == 0)\n        Result = uintptrcmp((ULONG_PTR)((PPHP_PROCESS_WMI_TREENODE)Node1)->Node.Index, (ULONG_PTR)((PPHP_PROCESS_WMI_TREENODE)Node2)->Node.Index);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(ProviderName)\n{\n    sortResult = PhCompareStringWithNull(node1->Provider->ProviderName, node2->Provider->ProviderName, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ProviderNamespace)\n{\n    sortResult = PhCompareStringWithNull(node1->Provider->ProviderNamespace, node2->Provider->ProviderNamespace, FALSE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileName)\n{\n    sortResult = PhCompareStringWithNull(node1->Provider->FileName, node2->Provider->FileName, FALSE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(UserName)\n{\n    sortResult = PhCompareStringWithNull(node1->Provider->UserName, node2->Provider->UserName, FALSE);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpWmiProviderTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_PROCESS_WMI_CONTEXT context = Context;\n    PPHP_PROCESS_WMI_TREENODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPHP_PROCESS_WMI_TREENODE)getChildren->Node;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(ProviderName),\n                    SORT_FUNCTION(ProviderNamespace),\n                    SORT_FUNCTION(FileName),\n                    SORT_FUNCTION(UserName),\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PROCESS_WMI_COLUMN_ITEM_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (context->TreeNewSortColumn < PROCESS_WMI_COLUMN_ITEM_MAXIMUM)\n                    sortFunction = sortFunctions[context->TreeNewSortColumn];\n                else\n                    sortFunction = NULL;\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE*)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n            node = (PPHP_PROCESS_WMI_TREENODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1;\n            node = (PPHP_PROCESS_WMI_TREENODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case PROCESS_WMI_COLUMN_ITEM_PROVIDER:\n                getCellText->Text = PhGetStringRef(node->Provider->ProviderName);\n                break;\n            case PROCESS_WMI_COLUMN_ITEM_NAMESPACE:\n                getCellText->Text = PhGetStringRef(node->Provider->ProviderNamespace);\n                break;\n            case PROCESS_WMI_COLUMN_ITEM_FILENAME:\n                getCellText->Text = PhGetStringRef(node->Provider->FileName);\n                break;\n            case PROCESS_WMI_COLUMN_ITEM_USER:\n                getCellText->Text = PhGetStringRef(node->Provider->UserName);\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = (PPH_TREENEW_GET_NODE_COLOR)Parameter1;\n            node = (PPHP_PROCESS_WMI_TREENODE)getNodeColor->Node;\n\n            if (\n                context->HighlightDefaultNamespace &&\n                context->DefaultNamespace &&\n                node->Provider->ProviderNamespace &&\n                PhEqualString(context->DefaultNamespace, node->Provider->ProviderNamespace, TRUE)\n                )\n            {\n                getNodeColor->BackColor = PhCsColorElevatedProcesses;\n            }\n\n            getNodeColor->Flags = TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // HACK\n            if (context->TreeFilterSupport.FilterList)\n                PhApplyTreeNewFilters(&context->TreeFilterSupport);\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1;\n\n            SendMessage(context->WindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenuEvent);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->WindowHandle, WM_COMMAND, IDC_COPY, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = PROCESS_WMI_COLUMN_ITEM_PROVIDER;\n            data.DefaultSortOrder = NoSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(\n                data.Menu,\n                WindowHandle,\n                PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                data.MouseEvent->ScreenLocation.x,\n                data.MouseEvent->ScreenLocation.y\n                );\n\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewGetDialogCode:\n        {\n            PULONG code = Parameter2;\n\n            if (PtrToUlong(Parameter1) == VK_RETURN)\n            {\n                *code = DLGC_WANTMESSAGE;\n                return TRUE;\n            }\n        }\n        return FALSE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpClearWmiProviderTree(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        PhpDestroyWmiProviderNode(Context->NodeList->Items[i]);\n\n    PhClearHashtable(Context->NodeHashtable);\n    PhClearList(Context->NodeList);\n\n    //TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nPPHP_PROCESS_WMI_TREENODE PhpGetSelectedWmiProviderNode(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context\n    )\n{\n    PPHP_PROCESS_WMI_TREENODE node = NULL;\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        node = Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n            return node;\n    }\n\n    return NULL;\n}\n\n_Success_(return)\nBOOLEAN PhpGetSelectedWmiProviderNodes(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context,\n    _Out_ PPHP_PROCESS_WMI_TREENODE **Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPHP_PROCESS_WMI_TREENODE node = (PPHP_PROCESS_WMI_TREENODE)Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            PhAddItemList(list, node);\n        }\n    }\n\n    if (list->Count)\n    {\n        *Nodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\nVOID PhpInitializeWmiProviderTree(\n    _Inout_ PPH_PROCESS_WMI_CONTEXT Context\n    )\n{\n    LONG dpiValue;\n\n    dpiValue = PhGetWindowDpi(Context->WindowHandle);\n\n    Context->NodeList = PhCreateList(10);\n    Context->NodeHashtable = PhCreateHashtable(\n        sizeof(PPHP_PROCESS_WMI_TREENODE),\n        PhpWmiProviderNodeHashtableEqualFunction,\n        PhpWmiProviderNodeHashtableHashFunction,\n        10\n        );\n\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n    TreeNew_SetCallback(Context->TreeNewHandle, PhpWmiProviderTreeNewCallback, Context);\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n\n    // Default columns\n    PhAddTreeNewColumn(Context->TreeNewHandle, PROCESS_WMI_COLUMN_ITEM_PROVIDER, TRUE, L\"Provider\", 140, PH_ALIGN_LEFT, 0, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PROCESS_WMI_COLUMN_ITEM_NAMESPACE, TRUE, L\"Namespace\", 180, PH_ALIGN_LEFT, 1, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PROCESS_WMI_COLUMN_ITEM_FILENAME, TRUE, L\"File name\", 260, PH_ALIGN_LEFT, 2, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PROCESS_WMI_COLUMN_ITEM_USER, TRUE, L\"User\", 80, PH_ALIGN_LEFT, 3, 0);\n\n    PhCmInitializeManager(&Context->Cm, Context->TreeNewHandle, PHMOTLC_MAXIMUM, PhpWmiProviderTreeNewPostSortFunction);\n    PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList);\n\n    TreeNew_SetTriState(Context->TreeNewHandle, TRUE);\n    TreeNew_SetSort(Context->TreeNewHandle, PROCESS_WMI_COLUMN_ITEM_PROVIDER, NoSortOrder);\n    TreeNew_SetRowHeight(Context->TreeNewHandle, PhGetDpi(22, dpiValue));\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n}\n\nVOID PhpDeleteWmiProviderTree(\n    _In_ PPH_PROCESS_WMI_CONTEXT Context\n    )\n{\n    PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PhpDestroyWmiProviderNode(Context->NodeList->Items[i]);\n    }\n\n    PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhpProcessWmiProviderTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_PROCESS_WMI_CONTEXT context = Context;\n    PPHP_PROCESS_WMI_TREENODE node = (PPHP_PROCESS_WMI_TREENODE)Node;\n\n    if (!context)\n        return FALSE;\n\n    if (\n        context->HideDefaultNamespace &&\n        context->DefaultNamespace &&\n        node->Provider->ProviderNamespace &&\n        PhEqualString(context->DefaultNamespace, node->Provider->ProviderNamespace, TRUE)\n        )\n    {\n        return FALSE;\n    }\n\n    if (!context->SearchMatchHandle)\n        return TRUE;\n\n    if (!PhIsNullOrEmptyString(node->Provider->ProviderName))\n    {\n        if (PhSearchControlMatch(context->SearchMatchHandle, &node->Provider->ProviderName->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(node->Provider->ProviderNamespace))\n    {\n        if (PhSearchControlMatch(context->SearchMatchHandle, &node->Provider->ProviderNamespace->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(node->Provider->FileName))\n    {\n        if (PhSearchControlMatch(context->SearchMatchHandle, &node->Provider->FileName->sr))\n            return TRUE;\n    }\n\n    if (!PhIsNullOrEmptyString(node->Provider->UserName))\n    {\n        if (PhSearchControlMatch(context->SearchMatchHandle, &node->Provider->UserName->sr))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhpProcessWmiProvidersSearchControlCallback(\n    _In_ ULONG_PTR MatcHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_PROCESS_WMI_CONTEXT context = Context;\n\n    assert(context);\n\n    context->SearchMatchHandle = MatcHandle;\n\n    // Expand any hidden nodes to make search results visible.\n    PhpExpandAllWmiProviderNodes(context, TRUE);\n\n    PhApplyTreeNewFilters(&context->TreeFilterSupport);\n}\n\nINT_PTR CALLBACK PhpProcessWmiProvidersDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_PROCESS_PROPPAGECONTEXT propPageContext;\n    PPH_PROCESS_ITEM processItem;\n    PPH_PROCESS_WMI_CONTEXT context;\n\n    if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &propPageContext, &processItem))\n    {\n        context = propPageContext->Context;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context = propPageContext->Context = PhAllocateZero(sizeof(PH_PROCESS_WMI_CONTEXT));\n            context->WindowHandle = hwndDlg;\n            context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n            context->SearchWindowHandle = GetDlgItem(hwndDlg, IDC_SEARCH);\n            context->ProcessItem = processItem;\n            context->DefaultNamespace = PhpQueryWmiDefaultNamespace();\n\n            PhCreateSearchControl(\n                hwndDlg,\n                context->SearchWindowHandle,\n                L\"Search WMI Providers (Ctrl+K)\",\n                PhpProcessWmiProvidersSearchControlCallback,\n                context\n                );\n            Edit_SetSel(context->SearchWindowHandle, 0, -1);\n            PhpInitializeWmiProviderTree(context);\n\n            if (PhTreeWindowFont)\n            {\n                context->TreeNewFont = PhDuplicateFont(PhTreeWindowFont);\n                SetWindowFont(context->TreeNewHandle, context->TreeNewFont, FALSE);\n            }\n\n            context->TreeFilterEntry = PhAddTreeNewFilter(&context->TreeFilterSupport, PhpProcessWmiProviderTreeFilterCallback, context);\n\n            PhMoveReference(&context->StatusMessage, PhCreateString(L\"There are no providers to display.\"));\n            TreeNew_SetEmptyText(context->TreeNewHandle, &context->StatusMessage->sr, 0);\n            PhLoadSettingsWmiProviderList(context);\n\n            PhpRefreshWmiProvidersList(context, processItem);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveTreeNewFilter(&context->TreeFilterSupport, context->TreeFilterEntry);\n\n            PhSaveSettingsWmiProviderList(context);\n            PhpDeleteWmiProviderTree(context);\n\n            if (context->StatusMessage)\n                PhDereferenceObject(context->StatusMessage);\n            if (context->DefaultNamespace)\n                PhDereferenceObject(context->DefaultNamespace);\n\n            if (context->TreeNewFont)\n                DeleteFont(context->TreeNewFont);\n\n            PhFree(context);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n             TreeNew_SetRowHeight(context->TreeNewHandle, PhGetDpi(22, LOWORD(wParam)));\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            PPH_LAYOUT_ITEM dialogItem;\n\n            if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))\n            {\n                PhAddPropPageLayoutItem(hwndDlg, context->SearchWindowHandle, dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP);\n                PhAddPropPageLayoutItem(hwndDlg, context->TreeNewHandle, dialogItem, PH_ANCHOR_ALL);\n                PhEndPropPageLayout(hwndDlg, propPageContext);\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case ID_SHOWCONTEXTMENU:\n                {\n                    PhpShowWmiProviderNodeContextMenu(context, (PPH_TREENEW_CONTEXT_MENU)lParam);\n                }\n                break;\n            case IDC_REFRESH:\n                {\n                    PhpRefreshWmiProvidersList(context, processItem);\n                }\n                break;\n            case IDC_OPTIONS:\n                {\n                    RECT rect;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM namespaceMenuItem;\n                    PPH_EMENU_ITEM highlightNamespaceMenuItem;\n                    PPH_EMENU_ITEM selectedItem;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect))\n                        break;\n\n                    namespaceMenuItem = PhCreateEMenuItem(0, PROCESS_WMI_TREE_MENU_ITEM_HIDE_DEFAULT_NAMESPACE, L\"Hide default namespace\", NULL, NULL);\n                    highlightNamespaceMenuItem = PhCreateEMenuItem(0, PROCESS_WMI_TREE_MENU_ITEM_HIGHLIGHT_DEFAULT_NAMESPACE, L\"Highlight default namespace\", NULL, NULL);\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, namespaceMenuItem, ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, highlightNamespaceMenuItem, ULONG_MAX);\n\n                    if (context->HideDefaultNamespace)\n                        namespaceMenuItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightDefaultNamespace)\n                        highlightNamespaceMenuItem->Flags |= PH_EMENU_CHECKED;\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        rect.left,\n                        rect.bottom\n                        );\n\n                    if (selectedItem && selectedItem->Id)\n                    {\n                        PhSetOptionsWmiProviderList(context, selectedItem->Id);\n                        PhSaveSettingsWmiProviderList(context);\n                        PhApplyTreeNewFilters(&context->TreeFilterSupport);\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)context->TreeNewHandle);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            if (LOWORD(wParam) == 'K')\n            {\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    SetFocus(context->SearchWindowHandle);\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by SystemInformer.rc\n//\n#define IDR_RT_MANIFEST                 1\n#define IDI_PROCESSHACKER               101\n#define IDR_MAINWND_ACCEL               102\n#define IDD_PROCGENERAL                 103\n#define IDD_PROCMODULES                 104\n#define IDD_PROCTHREADS                 105\n#define IDD_PROCHANDLES                 106\n#define IDD_PROCENVIRONMENT             107\n#define IDD_THRDSTACK                   108\n#define IDD_THRDSTACKS                  109\n#define IDD_USRLIST                     110\n#define IDC_CPU                         112\n#define IDC_PRIVATEBYTES                113\n#define IDC_IO                          114\n#define IDC_MEMORY                      120\n#define IDD_ABOUT                       121\n#define IDC_NEWOBJECTS                  121\n#define IDC_REMOVEDOBJECTS              122\n#define IDD_SRVLIST                     125\n#define IDD_SRVGENERAL                  126\n#define IDD_HNDLGENERAL                 128\n#define IDD_INFORMATION                 129\n#define IDD_FINDOBJECTS                 130\n#define IDD_OBJTOKEN                    131\n#define ID_PLUGIN_MENU_ITEM             131\n#define ID_CALLBACK_MENU_ITEM           132\n#define IDD_ZOMBIEPROCESSES             135\n#define ID_TRAYICONS_REGISTERED         135\n#define IDD_RUNAS                       136\n#define ID_COPY_CELL                    136\n#define IDD_PROGRESS                    137\n#define IDD_PAGEFILES                   138\n#define IDD_TOKGENERAL                  139\n#define IDD_TOKADVANCED                 140\n#define IDD_OBJJOB                      141\n#define IDD_OBJEVENT                    142\n#define IDD_OBJMUTANT                   143\n#define IDD_OBJSEMAPHORE                144\n#define IDD_OBJTIMER                    145\n#define IDD_JOBSTATISTICS               146\n#define IDD_OBJEVENTPAIR                147\n#define IDD_OBJSECTION                  148\n#define IDD_AFFINITY                    149\n#define IDD_SYSINFO                     150\n#define IDD_HNDLSECURITY                151\n#define IDD_EDITMESSAGE                 152\n#define IDD_SESSION                     153\n#define IDD_PROCMEMORY                  154\n#define IDD_CHOOSE                      155\n#define IDD_OPTGENERAL                  162\n#define IDD_OPTHIGHLIGHTING             163\n#define IDD_CHOOSECOLUMNS               166\n#define IDD_NETSTACK                    167\n#define IDD_CREATESERVICE               168\n#define IDD_PROCPERFORMANCE             169\n#define ID_SHOWCONTEXTMENU              169\n#define IDD_PROCSTATISTICS              170\n#define IDD_OPTADVANCED                 171\n#define IDD_GDIHANDLES                  175\n#define IDD_LOG                         178\n#define IDD_MEMEDIT                     180\n#define IDD_MEMPROTECT                  182\n#define IDD_MEMRESULTS                  183\n#define IDD_MEMSTRING                   185\n#define IDD_OPTGRAPHS                   186\n#define IDD_PLUGINS                     187\n#define IDD_PLUGINMANAGER               187\n#define IDD_HANDLESTATS                 188\n#define IDD_PROCRECORD                  189\n#define IDD_CHOOSEPROCESS               190\n#define IDD_PROCSERVICES                191\n#define IDI_PHAPPLICATION               191\n#define IDI_COG                         192\n#define IDD_SHADOWSESSION               193\n#define IDI_PHAPPLICATIONGO             194\n#define IDD_TOKCAPABILITIES             194\n#define IDI_COGGO                       195\n#define IDD_TOKATTRIBUTES               195\n#define IDD_SYSINFO_CPU                 196\n#define IDD_SYSINFO_CPUPANEL            197\n#define IDD_SYSINFO_MEMPANEL            198\n#define IDR_SYSINFO_ACCEL               198\n#define IDD_SYSINFO_MEM                 199\n#define IDD_SYSINFO_IO                  200\n#define IDD_SYSINFO_IOPANEL             201\n#define IDD_MEMLISTS                    202\n#define IDD_CONTAINER                   205\n#define IDD_MINIINFO                    207\n#define IDD_MINIINFO_LIST               210\n#define IDD_MITIGATION                  215\n#define IDD_TOKAPPPOLICY                216\n#define IDI_PIN                         216\n#define IDI_FOLDER                      217\n#define IDI_MAGNIFIER                   219\n#define IDD_EDITENV                     221\n#define IDB_SEARCH_ACTIVE               223\n#define IDB_SEARCH_INACTIVE             224\n#define IDB_SEARCH_ACTIVE_BMP           225\n#define IDB_SEARCH_INACTIVE_BMP         226\n#define IDD_OPTIONS                     227\n#define IDD_PLUGINPROPERTIES            228\n#define IDD_PLUGINSDISABLED             241\n#define IDD_PROCWMIPROVIDERS            242\n#define IDD_COLUMNSETS                  243\n#define ID_VIEW_TRAYICONS               244\n#define IDD_OBJFILE                     249\n#define IDD_RUNFILEDLG                  253\n#define IDD_LIVEDUMP                    254\n#define IDD_HEAPS                       255\n#define IDD_PROCDUMP                    256\n#define IDD_PROCVDMHOST                 257\n#define IDD_OPTSYMBOLS                  258\n#define IDD_OBJMAPPINGS                 258\n#define IDI_UACSHIELD                   261\n#define IDD_RUNPACKAGE                  263\n#define IDD_MODIFIEDPAGES               264\n#define IDB_SEARCH_ACTIVE_SMALL         265\n#define IDB_SEARCH_INACTIVE_SMALL       266\n#define IDB_SEARCH_REGEX_MODERN_DARK    267\n#define IDB_SEARCH_REGEX_MODERN_LIGHT   268\n#define IDB_SEARCH_CASE_MODERN_DARK     269\n#define IDB_SEARCH_CASE_MODERN_LIGHT    270\n#define IDB_SEARCH_ACTIVE_MODERN_DARK   271\n#define IDB_SEARCH_ACTIVE_MODERN_LIGHT  272\n#define IDB_SEARCH_INACTIVE_MODERN_DARK 273\n#define IDB_SEARCH_INACTIVE_MODERN_LIGHT 274\n#define IDD_INPUT                       275\n#define IDD_CHOOSENEW                   275\n#define IDD_MEMSTRINGSMINLEN            276\n#define IDD_MEMSTRINGS                  277\n#define IDD_HNDLAUDITING                278\n#define IDD_HNDLSECAUDIT                278\n#define IDC_TERMINATE                   1003\n#define IDC_FILEICON                    1005\n#define IDC_FILE                        1006\n#define IDC_PROCESS                     1007\n#define IDC_COMPANYNAME                 1009\n#define IDC_VERSION                     1010\n#define IDC_REFRESH                     1015\n#define IDC_PERMISSIONS                 1018\n#define IDC_FILENAME                    1020\n#define IDC_CMDLINE                     1021\n#define IDC_URL                         1021\n#define IDC_RUNSELECTED                 1021\n#define IDC_CURDIR                      1022\n#define IDC_STARTED                     1023\n#define IDC_ABOUT_NAME                  1024\n#define IDC_TERMINATED                  1024\n#define IDC_PARENTCONSOLE               1024\n#define IDC_PARENTPROCESS               1025\n#define IDC_MITIGATION                  1026\n#define IDC_PAUSE                       1027\n#define IDC_PROTECTION                  1027\n#define IDC_START                       1028\n#define IDC_FILENAMEWIN32               1028\n#define IDC_DESCRIPTION                 1029\n#define IDC_TYPE                        1032\n#define IDC_STARTTYPE                   1033\n#define IDC_ADDRESS                     1033\n#define IDC_IMPERSONATIONLEVEL          1033\n#define IDC_ERRORCONTROL                1034\n#define IDC_GRANTED_ACCESS              1034\n#define IDC_TOKENLUID                   1034\n#define IDC_GROUP                       1035\n#define IDC_AUTHENTICATIONLUID          1035\n#define IDC_BINARYPATH                  1036\n#define IDC_MEMORYUSED                  1036\n#define IDC_USERACCOUNT                 1037\n#define IDC_MEMORYAVAILABLE             1037\n#define IDC_PASSWORD                    1040\n#define IDC_PASSWORDCHECK               1041\n#define IDC_SERVICEDLL                  1042\n#define IDC_NAME                        1044\n#define IDC_REFERENCES                  1045\n#define IDC_INTERNALNAME                1045\n#define IDC_HANDLES                     1046\n#define IDC_AUTHOR                      1046\n#define IDC_PAGED                       1047\n#define IDC_PROCESSTYPETEXT             1047\n#define IDC_NONPAGED                    1048\n#define IDC_TEXT                        1048\n#define IDC_DIAGNOSTICS                 1049\n#define IDC_FILTER                      1050\n#define IDC_RESULTS                     1051\n#define IDC_USER                        1052\n#define IDC_USERSID                     1053\n#define IDC_ADVANCED                    1054\n#define IDC_OWNER                       1054\n#define IDC_GROUPS                      1055\n#define IDC_PRIMARYGROUP                1055\n#define IDC_VIRTUALIZATION              1056\n#define IDC_SESSIONID                   1057\n#define IDC_ELEVATED                    1058\n#define IDC_VIRTUALIZED                 1059\n#define IDC_SOURCENAME                  1059\n#define IDC_PROPERTIES                  1060\n#define IDC_SOURCELUID                  1060\n#define IDC_APPCONTAINERSID             1060\n#define IDC_LIST                        1061\n#define IDC_TOKENUSER                   1061\n#define IDC_UIACCESS                    1061\n#define IDC_TOKENSID                    1062\n#define IDC_PROCESSES                   1063\n#define IDC_SCAN                        1064\n#define IDC_SAVE                        1065\n#define IDC_METHOD                      1067\n#define IDC_INTRO                       1068\n#define IDC_PROGRAM                     1069\n#define IDC_BROWSE                      1070\n#define IDC_USERNAME                    1071\n#define IDC_SESSIONCOMBO                1072\n#define IDC_DESKTOPCOMBO                1073\n#define IDC_SESSIONS                    1074\n#define IDC_PROGRAMCOMBO                1074\n#define IDC_DESKTOPS                    1075\n#define IDC_PROGRESS                    1076\n#define IDC_PROGRESSTEXT                1077\n#define IDC_LINKEDTOKEN                 1079\n#define IDC_DISABLEALL                  1079\n#define IDC_MOVEUP                      1079\n#define IDC_CLEAR                       1079\n#define IDC_GOTO                        1079\n#define IDC_OPTIONS                     1079\n#define IDC_DETAILS                     1079\n#define IDC_ADD                         1079\n#define IDC_FONT                        1079\n#define IDC_INTEGRITY                   1079\n#define IDC_MORE                        1079\n#define IDC_VIEWMITIGATION              1080\n#define IDC_REPLACETASKMANAGER          1080\n#define IDC_RENAME                      1080\n#define IDC_VIEWPARENTPROCESS           1081\n#define IDC_OPENFILENAME                1082\n#define IDC_LIMITS                      1083\n#define IDC_OPENFILENAME2               1083\n#define IDC_SIGNALED                    1084\n#define IDC_SET                         1085\n#define IDC_RESET                       1086\n#define IDC_PULSE                       1087\n#define IDC_APPLY                       1087\n#define IDC_COUNT                       1088\n#define IDC_ABANDONED                   1089\n#define IDC_CURRENTCOUNT                1090\n#define IDC_MAXIMUMCOUNT                1091\n#define IDC_ACQUIRE                     1092\n#define IDC_RELEASE                     1093\n#define IDC_CANCEL                      1094\n#define IDC_OWNERLABEL                  1095\n#define IDC_SETLOW                      1096\n#define IDC_SETHIGH                     1097\n#define IDC_SIZE_                       1098\n#define IDC_CPU0                        1099\n#define IDC_CPU1                        1100\n#define IDC_CPU2                        1101\n#define IDC_CPU3                        1102\n#define IDC_CPU4                        1103\n#define IDC_CPU5                        1104\n#define IDC_CPU6                        1105\n#define IDC_CPU7                        1106\n#define IDC_CPU8                        1107\n#define IDC_TITLE                       1107\n#define IDC_CPU9                        1108\n#define IDC_CPU10                       1109\n#define IDC_TIMEOUT                     1109\n#define IDC_CPU11                       1110\n#define IDC_CPU12                       1111\n#define IDC_STATE                       1111\n#define IDC_CPU13                       1112\n#define IDC_CLIENTNAME                  1112\n#define IDC_CPU14                       1113\n#define IDC_CLIENTADDRESS               1113\n#define IDC_CPU15                       1114\n#define IDC_CLIENTDISPLAY               1114\n#define IDC_CPU16                       1115\n#define IDC_CHOICE                      1115\n#define IDC_CPU17                       1116\n#define IDC_OPTION                      1116\n#define IDC_CPU18                       1117\n#define IDC_CHOICEUSER                  1117\n#define IDC_CPU19                       1118\n#define IDC_HIDEUNNAMEDHANDLES          1118\n#define IDC_CPU20                       1119\n#define IDC_CPU21                       1120\n#define IDC_STARTMODULE                 1120\n#define IDC_CPU22                       1121\n#define IDC_OPENSTARTMODULE             1121\n#define IDC_CPU23                       1122\n#define IDC_KERNELTIME                  1122\n#define IDC_CPU24                       1123\n#define IDC_USERTIME                    1123\n#define IDC_CPU25                       1124\n#define IDC_CONTEXTSWITCHES             1124\n#define IDC_CPU26                       1125\n#define IDC_CYCLES                      1125\n#define IDC_CPU27                       1126\n#define IDC_PRIORITY                    1126\n#define IDC_CPU28                       1127\n#define IDC_BASEPRIORITY                1127\n#define IDC_CPU29                       1128\n#define IDC_IOPRIORITY                  1128\n#define IDC_CPU30                       1129\n#define IDC_PAGEPRIORITY                1129\n#define IDC_CPU31                       1130\n#define IDC_STATICBL1                   1130\n#define IDC_STATICBL2                   1131\n#define IDC_CPU32                       1131\n#define IDC_STATICBL3                   1132\n#define IDC_CPU33                       1132\n#define IDC_STATICBL4                   1133\n#define IDC_CPU34                       1133\n#define IDC_STATICBL5                   1134\n#define IDC_CPU35                       1134\n#define IDC_STATICBL6                   1135\n#define IDC_CPU36                       1135\n#define IDC_STATICBL7                   1136\n#define IDC_CPU37                       1136\n#define IDC_STATICBL8                   1137\n#define IDC_CPU38                       1137\n#define IDC_STATICBL9                   1138\n#define IDC_CPU39                       1138\n#define IDC_STATICBL10                  1139\n#define IDC_CPU40                       1139\n#define IDC_STATICBL11                  1140\n#define IDC_CPU41                       1140\n#define IDC_CHOICESIMPLE                1141\n#define IDC_CPU42                       1141\n#define IDC_MESSAGE                     1142\n#define IDC_CPU43                       1142\n#define IDC_SEARCHENGINE                1143\n#define IDC_CPU44                       1143\n#define IDC_MAXSIZEUNIT                 1144\n#define IDC_CPU45                       1144\n#define IDC_CPU46                       1145\n#define IDC_CPU47                       1146\n#define IDC_CPU48                       1147\n#define IDC_CPU49                       1148\n#define IDC_CPU50                       1149\n#define IDC_CPU51                       1150\n#define IDC_PEVIEWER                    1151\n#define IDC_CPU52                       1151\n#define IDC_CPU53                       1152\n#define IDC_CPU54                       1153\n#define IDC_CPU55                       1154\n#define IDC_HIGHLIGHTINGDURATION        1155\n#define IDC_CPU56                       1155\n#define IDC_CPU57                       1156\n#define IDC_ENABLEALL                   1157\n#define IDC_CPU58                       1157\n#define IDC_ZACTIVEPROCESSES_V          1158\n#define IDC_CPU59                       1158\n#define IDC_ZTOTALPROCESSES_V           1159\n#define IDC_CPU60                       1159\n#define IDC_ZTERMINATEDPROCESSES_V      1160\n#define IDC_CPU61                       1160\n#define IDC_ZUSERTIME_V                 1161\n#define IDC_CPU62                       1161\n#define IDC_ZKERNELTIME_V               1162\n#define IDC_CPU63                       1162\n#define IDC_ZUSERTIMEPERIOD_V           1163\n#define IDC_ZKERNELTIMEPERIOD_V         1164\n#define IDC_ZPAGEFAULTS_V               1165\n#define IDC_ZPEAKPROCESSUSAGE_V         1166\n#define IDC_ZPEAKJOBUSAGE_V             1167\n#define IDC_ZIOREADS_V                  1168\n#define IDC_ZIOREADBYTES_V              1169\n#define IDC_ZIOWRITES_V                 1170\n#define IDC_ZIOWRITEBYTES_V             1171\n#define IDC_ZIOOTHER_V                  1172\n#define IDC_ZIOOTHERBYTES_V             1173\n#define IDC_MOVEDOWN                    1176\n#define IDC_REMOVE                      1177\n#define IDC_DISPLAYNAME                 1179\n#define IDC_ZPRIORITY_V                 1181\n#define IDC_ZCYCLES_V                   1182\n#define IDC_ZTOTALTIME_V                1185\n#define IDC_ZPRIVATEBYTES_V             1186\n#define IDC_ZWORKINGSET_V               1187\n#define IDC_ZPEAKWORKINGSET_V           1188\n#define IDC_ZVIRTUALSIZE_V              1189\n#define IDC_ZPEAKVIRTUALSIZE_V          1190\n#define IDC_ZPEAKPRIVATEBYTES_V         1191\n#define IDC_ZPAGEPRIORITY_V             1192\n#define IDC_ZIOPRIORITY_V               1194\n#define IDC_ZHANDLES_V                  1195\n#define IDC_ZGDIHANDLES_V               1196\n#define IDC_ZOTHERDELTA_V               1196\n#define IDC_ZUSERHANDLES_V              1197\n#define IDC_ZOTHER_V                    1197\n#define IDC_GROUPCPU                    1198\n#define IDC_GROUPPRIVATEBYTES           1199\n#define IDC_GROUPIO                     1200\n#define IDC_UNDO                        1201\n#define IDC_ONEGRAPHPERCPU              1202\n#define IDC_ALWAYSONTOP                 1203\n#define IDC_PASTE                       1204\n#define IDC_CUT                         1205\n#define IDC_COPY                        1206\n#define IDC_INACTIVE                    1207\n#define IDC_ACTIVE                      1208\n#define IDC_SHOW                        1209\n#define IDC_HIDE                        1210\n#define IDC_AUTOSCROLL                  1215\n#define IDC_UNDECORATESYMBOLS           1216\n#define IDC_DBGHELPPATH                 1217\n#define IDC_DBGHELPSEARCHPATH           1218\n#define IDC_DESKTOP                     1221\n#define IDC_REREAD                      1224\n#define IDC_WRITE                       1225\n#define IDC_VALUE                       1230\n#define IDC_DELAYEDSTART                1234\n#define IDC_MINIMUMLENGTH               1236\n#define IDC_DETECTUNICODE               1237\n#define IDC_PRIVATE                     1238\n#define IDC_IMAGE                       1239\n#define IDC_MAPPED                      1240\n#define IDC_EXTENDEDUNICODE             1241\n#define IDC_SHOWTEXT                    1245\n#define IDC_ICONPROCESSES               1248\n#define IDC_CLEANUP                     1251\n#define IDC_TOGGLEELEVATION             1254\n#define IDC_TOGGLESUSPENDED             1255\n#define IDC_TRUSTEDINSTALLER            1255\n#define IDC_TOGGLEUIACCESS              1256\n#define IDC_PARENT                      1263\n#define IDC_PROCESSNAME                 1264\n#define IDC_SERVICES_LAYOUT             1266\n#define IDC_LINK_SF                     1267\n#define IDC_CREDITS                     1270\n#define IDC_LOGONTIME                   1272\n#define IDC_ZPEAKHANDLES_V              1273\n#define IDC_SHIFT                       1274\n#define IDC_USEOLDCOLORS                1274\n#define IDC_OPENURL                     1279\n#define IDC_COMPANYNAME_LINK            1279\n#define IDC_SAMPLECOUNT                 1280\n#define IDC_SAMPLECOUNTLABEL            1281\n#define IDC_VIRTUALKEY                  1283\n#define IDC_CTRL                        1284\n#define IDC_ALT                         1285\n#define IDC_CONNECTTIME                 1286\n#define IDC_DISCONNECTTIME              1287\n#define IDC_LASTINPUTTIME               1288\n#define IDC_ZPRIVATEWS_V                1289\n#define IDC_ZSHAREABLEWS_V              1290\n#define IDC_ZSHAREDWS_V                 1291\n#define IDC_IDEALPROCESSOR              1294\n#define IDC_STATICBL12                  1295\n#define IDC_BASICINFORMATION            1296\n#define IDC_INSTRUCTION                 1298\n#define IDC_CPUNAME                     1299\n#define IDC_LAYOUT                      1300\n#define IDC_UTILIZATION                 1301\n#define IDC_SPEED                       1302\n#define IDC_ZPROCESSES_V                1303\n#define IDC_ZTHREADS_V                  1304\n#define IDC_ZCONTEXTSWITCHESDELTA_V     1307\n#define IDC_ZINTERRUPTSDELTA_V          1308\n#define IDC_ZDPCSDELTA_V                1309\n#define IDC_ZSYSTEMCALLSDELTA_V         1310\n#define IDC_GRAPH_LAYOUT                1311\n#define IDC_ZCORES                      1311\n#define IDC_TOTALPHYSICAL               1312\n#define IDC_ZSOCKETS                    1312\n#define IDC_ZLOGICAL                    1313\n#define IDC_ZCOMMITCURRENT_V            1314\n#define IDC_ZLATENCY                    1314\n#define IDC_ZCOMMITPEAK_V               1315\n#define IDC_ZCOMMITLIMIT_V              1316\n#define IDC_ZPHYSICALCURRENT_V          1317\n#define IDC_ZPHYSICALTOTAL_V            1318\n#define IDC_ZPHYSICALCACHEWS_V          1319\n#define IDC_ZPHYSICALKERNELWS_V         1320\n#define IDC_ZPHYSICALDRIVERWS_V         1321\n#define IDC_ZPAGEDWORKINGSET_V          1322\n#define IDC_ZPAGEDVIRTUALSIZE_V         1323\n#define IDC_ZPAGEDLIMIT_V               1324\n#define IDC_ZPAGEDALLOCSDELTA_V         1325\n#define IDC_ZPAGEDFREESDELTA_V          1326\n#define IDC_ZNONPAGEDUSAGE_V            1327\n#define IDC_ZNONPAGEDLIMIT_V            1328\n#define IDC_ZNONPAGEDALLOCSDELTA_V      1329\n#define IDC_ZNONPAGEDFREESDELTA_V       1330\n#define IDC_ZPHYSICALRESERVED_V         1331\n#define IDC_ZLISTZEROED_V               1332\n#define IDC_ZLISTFREE_V                 1333\n#define IDC_ZLISTMODIFIED_V             1334\n#define IDC_ZLISTMODIFIEDNOWRITE_V      1335\n#define IDC_ZLISTSTANDBY_V              1337\n#define IDC_COMMIT_L                    1339\n#define IDC_PHYSICAL_L                  1340\n#define IDC_ZUPTIME_V                   1341\n#define IDC_ZOTHERBYTESDELTA_V          1342\n#define IDC_ZREADSDELTA_V               1343\n#define IDC_ZREADBYTESDELTA_V           1344\n#define IDC_ZWRITESDELTA_V              1345\n#define IDC_ZLISTSTANDBY0_V             1346\n#define IDC_ZWRITEBYTESDELTA_V          1346\n#define IDC_ZLISTSTANDBY1_V             1347\n#define IDC_ZREADS_V                    1347\n#define IDC_ZLISTSTANDBY2_V             1348\n#define IDC_ZREADBYTES_V                1348\n#define IDC_ZLISTSTANDBY3_V             1349\n#define IDC_ZWRITES_V                   1349\n#define IDC_ZLISTBAD_V                  1350\n#define IDC_ZWRITEBYTES_V               1350\n#define IDC_ZLISTREPURPOSED_V           1351\n#define IDC_ZOTHERBYTES_V               1351\n#define IDC_ZLISTREPURPOSED0_V          1352\n#define IDC_ZLISTREPURPOSED1_V          1353\n#define IDC_ZLISTREPURPOSED2_V          1354\n#define IDC_ZLISTREPURPOSED3_V          1355\n#define IDC_ZLISTREPURPOSED4_V          1356\n#define IDC_ZLISTREPURPOSED5_V          1357\n#define IDC_ZLISTREPURPOSED6_V          1358\n#define IDC_ZLISTREPURPOSED7_V          1359\n#define IDC_EMPTY                       1360\n#define IDC_SAMPLECOUNTAUTOMATIC        1361\n#define IDC_SHOWCOMMITINSUMMARY         1361\n#define IDC_ZLISTSTANDBY4_V             1364\n#define IDC_ZLISTSTANDBY5_V             1365\n#define IDC_SELECTALL                   1365\n#define IDC_ZLISTSTANDBY6_V             1366\n#define IDC_DESELECTALL                 1366\n#define IDC_ZLISTSTANDBY7_V             1367\n#define IDC_INSPECT                     1367\n#define IDC_ZPAGINGPAGEFAULTSDELTA_V    1368\n#define IDC_INSPECT2                    1368\n#define IDC_ZPAGINGPAGEREADSDELTA_V     1369\n#define IDC_BYTESPERROW                 1369\n#define IDC_ZPAGINGPAGEFILEWRITESDELTA_V 1370\n#define IDC_PINWINDOW                   1370\n#define IDC_ZPAGINGMAPPEDWRITESDELTA_V  1371\n#define IDC_ZMAPPEDREADIO               1372\n#define IDC_ZLISTMODIFIEDPAGEFILE_V     1373\n#define IDC_ZMAPPEDWRITEIO              1374\n#define IDC_SECTION                     1375\n#define IDC_REGEX                       1377\n#define IDC_DESCRIPTIONLABEL            1378\n#define IDC_IOREAD_L                    1378\n#define IDC_IOWRITE_L                   1379\n#define IDC_IOOTHER_L                   1380\n#define IDC_VIEWCOMMANDLINE             1381\n#define IDC_DELETE                      1382\n#define IDC_EDIT                        1383\n#define IDC_NEW                         1384\n#define IDC_HANDLESEARCH                1385\n#define IDC_SEARCH                      1387\n#define IDC_FILTEROPTIONS               1389\n#define IDC_FILTERTYPE                  1390\n#define IDC_TREELIST                    1391\n#define IDC_SECTIONTREE                 1393\n#define IDC_INFO                        1396\n#define IDC_DEFSTATE                    1398\n#define IDC_SETTINGS                    1399\n#define IDC_PLUGINTREE                  1400\n#define IDC_DISABLED                    1401\n#define IDC_LIST_DISABLED               1402\n#define IDC_COLUMNSETLIST               1403\n#define IDC_STATISTICS_LIST             1404\n#define IDC_FLUSH                       1406\n#define IDC_POSITION                    1407\n#define IDC_FILESIZE                    1408\n#define IDC_FILETYPE                    1409\n#define IDC_FILEMODE                    1410\n#define IDC_DEFAULTPERM                 1410\n#define IDC_DUMPSTACK                   1411\n#define IDC_COMPRESS                    1412\n#define IDC_USERMODE                    1413\n#define IDC_HYPERVISOR                  1414\n#define IDC_SIZESINBYTES                1415\n#define IDC_FONTMONOSPACE               1416\n#define IDC_ONLYKERNELTHREADSTACKS      1417\n#define IDC_HYPERVISORNONESSENTIAL      1418\n#define IDC_INPUT                       1419\n#define IDC_MINIDUMP_NORMAL                          1420\n#define IDC_MINIDUMP_WITH_DATA_SEGS                  1421\n#define IDC_MINIDUMP_WITH_FULL_MEM                   1422\n#define IDC_MINIDUMP_WITH_HANDLE_DATA                1423\n#define IDC_MINIDUMP_FILTER_MEMORY                   1424\n#define IDC_MINIDUMP_SCAN_MEMORY                     1425\n#define IDC_MINIDUMP_WITH_UNLOADED_MODULES           1426\n#define IDC_MINIDUMP_WITH_INDIRECT_REFERENCED_MEM    1427\n#define IDC_MINIDUMP_FILTER_MODULE_PATHS             1428\n#define IDC_MINIDUMP_WITH_PROC_THRD_DATA             1429\n#define IDC_MINIDUMP_WITH_PRIVATE_RW_MEM             1430\n#define IDC_MINIDUMP_WITHOUT_OPTIONAL_DATA           1431\n#define IDC_MINIDUMP_WITH_FULL_MEM_INFO              1432\n#define IDC_MINIDUMP_WITH_THRD_INFO                  1433\n#define IDC_MINIDUMP_WITH_CODE_SEGS                  1434\n#define IDC_MINIDUMP_WITHOUT_AUXILIARY_STATE         1435\n#define IDC_MINIDUMP_WITH_FULL_AUXILIARY_STATE       1436\n#define IDC_MINIDUMP_WITH_PRIVATE_WRITE_COPY_MEM     1437\n#define IDC_MINIDUMP_IGNORE_INACCESSIBLE_MEM         1438\n#define IDC_MINIDUMP_WITH_TOKEN_INFO                 1439\n#define IDC_MINIDUMP_WITH_MODULE_HEADERS             1440\n#define IDC_MINIDUMP_FILTER_TRIAGE                   1441\n#define IDC_MINIDUMP_WITH_AVXX_STATE_CONTEXT         1442\n#define IDC_MINIDUMP_WITH_IPT_TRACE                  1443\n#define IDC_MINIDUMP_SCAN_INACCESSIBLE_PARTIAL_PAGES 1444\n#define IDC_MINIDUMP_FILTER_WRITE_COMBINE_MEM        1445\n#define IDC_ZMEMSLOTS_V                 1446\n#define IDC_ZMEMFORMFACTOR_V            1447\n#define IDC_ZMEMTYPE_V                  1448\n#define IDC_ZMEMTECHNOLOGY_V            1449\n#define IDC_ZMEMSPEED_V                 1450\n#define IDC_ZL1CACHE_V                  1451\n#define IDC_ZL2CACHE_V                  1452\n#define IDC_ZL3CACHE_V                  1453\n#define ID_HACKER_EXIT                  40001\n#define ID_PROCESS_DUMP_MINIMAL         40002\n#define ID_PROCESS_DUMP_LIMITED         40003\n#define ID_PROCESS_DUMP_NORMAL          40004\n#define ID_PROCESS_DUMP_FULL            40005\n#define ID_PROCESS_PROPERTIES           40006\n#define ID_PROCESS_TERMINATE            40007\n#define ID_PROCESS_SUSPEND              40008\n#define ID_PROCESS_RESUME               40009\n#define ID_HACKER_SAVE                  40010\n#define ID_THREAD_TERMINATE             40011\n#define ID_THREAD_SUSPEND               40012\n#define ID_THREAD_RESUME                40013\n#define ID_THREAD_PERMISSIONS           40015\n#define ID_THREAD_TOKEN                 40016\n#define ID_ANALYZE_WAIT                 40018\n#define ID_PROCESS_DUMP_CUSTOM          40019\n#define ID_PRIORITY_TIMECRITICAL        40020\n#define ID_PRIORITY_HIGHEST             40021\n#define ID_PRIORITY_ABOVENORMAL         40022\n#define ID_PRIORITY_NORMAL              40023\n#define ID_PRIORITY_BELOWNORMAL         40024\n#define ID_PRIORITY_LOWEST              40025\n#define ID_PRIORITY_IDLE                40026\n#define ID_IOPRIORITY_VERYLOW           40028\n#define ID_IOPRIORITY_LOW               40029\n#define ID_IOPRIORITY_NORMAL            40030\n#define ID_IOPRIORITY_HIGH              40031\n#define ID_PROCESS_RESTART              40032\n#define ID_PROCESS_VIRTUALIZATION       40034\n#define ID_PROCESS_AFFINITY             40035\n#define ID_PROCESS_CREATEDUMPFILE       40036\n#define ID_PROCESS_PRIORITYCLASS        40037\n#define ID_MISCELLANEOUS_SETCRITICAL    40038\n#define ID_MISCELLANEOUS_DETACHFROMDEBUGGER 40039\n#define ID_PROCESS_IOPRIORITY           40040\n#define ID_PROCESS_MISCELLANEOUS        40041\n#define ID_PROCESS_WINDOW               40042\n#define ID_PROCESS_PAGEPRIORITY         40043\n#define ID_PRIORITY_REALTIME            40048\n#define ID_PRIORITY_HIGH                40049\n#define ID_MISCELLANEOUS_ACTIVITY       40050\n#define ID_MISCELLANEOUS_ECOMODE        40051\n#define ID_WINDOW_BRINGTOFRONT          40055\n#define ID_WINDOW_RESTORE               40056\n#define ID_WINDOW_MINIMIZE              40057\n#define ID_WINDOW_MAXIMIZE              40058\n#define ID_WINDOW_CLOSE                 40059\n#define ID_PROCESS_SEARCHONLINE         40060\n#define ID_HANDLE_CLOSE                 40061\n#define ID_HANDLE_PROTECTED             40062\n#define ID_HANDLE_INHERIT               40063\n#define ID_HANDLE_PROPERTIES            40064\n#define ID_HANDLE_SECURITY              40065\n#define ID_MODULE_UNLOAD                40066\n#define ID_MODULE_PROPERTIES            40068\n#define ID_PROCESS_TERMINATETREE        40069\n#define ID_PROCESS_SUSPENDTREE          40070\n#define ID_PROCESS_RESUMETREE           40071\n#define ID_THREAD_INSPECT               40075\n#define ID_HACKER_RUN                   40076\n#define ID_HACKER_RUNASADMINISTRATOR    40077\n#define ID_HACKER_RUNAS                 40078\n#define ID_HACKER_SHOWDETAILSFORALLPROCESSES 40079\n#define ID_HACKER_RUNASPACKAGE          40080\n#define ID_HACKER_FINDHANDLESORDLLS     40082\n#define ID_HACKER_OPTIONS               40083\n#define ID_PROCESS_FREEZE               40084\n#define ID_PROCESS_THAW                 40085\n#define ID_VIEW_SYSTEMINFORMATION       40091\n#define ID_TRAYICONS_CPUHISTORY         40093\n#define ID_TRAYICONS_CPUUSAGE           40094\n#define ID_TRAYICONS_COMMITHISTORY      40096\n#define ID_TRAYICONS_PHYSICALMEMORYHISTORY 40097\n#define ID_VIEW_REFRESH                 40098\n#define ID_TOOLS_USER_LIST              40099\n#define ID_TOOLS_THREADSTACKS           40100\n#define ID_TOOLS_CREATESERVICE          40101\n#define ID_TOOLS_ZOMBIEPROCESSES        40102\n#define ID_TOOLS_INSPECTEXECUTABLEFILE  40103\n#define ID_HELP_LOG                     40104\n#define ID_HELP_DONATE                  40105\n#define ID_HELP_ABOUT                   40106\n#define ID_SERVICE_GOTOPROCESS          40107\n#define ID_SERVICE_START                40108\n#define ID_SERVICE_CONTINUE             40109\n#define ID_SERVICE_PAUSE                40110\n#define ID_SERVICE_STOP                 40111\n#define ID_SERVICE_DELETE               40112\n#define ID_SERVICE_PROPERTIES           40113\n#define ID_SERVICE_OPENKEY              40114\n#define ID_PRIVILEGE_ENABLE             40116\n#define ID_PRIVILEGE_DISABLE            40117\n#define ID_PRIVILEGE_REMOVE             40118\n#define ID_OBJECT_CLOSE                 40119\n#define ID_OBJECT_PROPERTIES            40120\n#define ID_HELP_DEBUGCONSOLE            40122\n#define ID_TOOLS_PAGEFILES              40126\n#define ID_USER_DISCONNECT              40127\n#define ID_USER_LOGOFF                  40128\n#define ID_USER_SENDMESSAGE             40129\n#define ID_USER_PROPERTIES              40130\n#define ID_USERS_DUMMY                  40131\n#define ID_PROCESS_DEBUG                40133\n#define ID_USER_CONNECT                 40138\n#define ID_NETWORK_GOTOPROCESS          40139\n#define ID_NETWORK_CLOSE                40140\n#define ID_OPACITY_10                   40142\n#define ID_OPACITY_20                   40143\n#define ID_OPACITY_30                   40144\n#define ID_OPACITY_40                   40145\n#define ID_OPACITY_50                   40146\n#define ID_OPACITY_60                   40147\n#define ID_OPACITY_70                   40148\n#define ID_OPACITY_80                   40149\n#define ID_OPACITY_90                   40150\n#define ID_OPACITY_OPAQUE               40151\n#define ID_VIEW_ALWAYSONTOP             40153\n#define ID_UPDATEINTERVAL_FAST          40155\n#define ID_UPDATEINTERVAL_NORMAL        40156\n#define ID_UPDATEINTERVAL_BELOWNORMAL   40157\n#define ID_UPDATEINTERVAL_SLOW          40158\n#define ID_UPDATEINTERVAL_VERYSLOW      40159\n#define ID_COMPUTER_LOCK                40160\n#define ID_COMPUTER_LOGOFF              40161\n#define ID_COMPUTER_SLEEP               40162\n#define ID_COMPUTER_HIBERNATE           40163\n#define ID_COMPUTER_RESTART             40164\n#define ID_COMPUTER_SHUTDOWN            40165\n#define ID_COMPUTER_RESTART_NATIVE      40166\n#define ID_COMPUTER_SHUTDOWN_NATIVE     40167\n#define ID_COMPUTER_RESTART_CRITICAL    40168\n#define ID_COMPUTER_SHUTDOWN_CRITICAL   40169\n#define ID_COMPUTER_RESTART_UPDATE      40170\n#define ID_COMPUTER_SHUTDOWN_UPDATE     40171\n#define ID_TRAYICONS_IOHISTORY          40172\n#define ID_ICON_EXIT                    40173\n#define ID_ICON_SHOWHIDEPROCESSHACKER   40174\n#define ID_ICON_SYSTEMINFORMATION       40175\n#define ID_PROCESSES_DUMMY              40177\n#define ID_NOTIFICATIONS_ENABLEALL      40178\n#define ID_NOTIFICATIONS_DISABLEALL     40179\n#define ID_NOTIFICATIONS_NEWPROCESSES   40180\n#define ID_NOTIFICATIONS_TERMINATEDPROCESSES 40181\n#define ID_NOTIFICATIONS_NEWSERVICES    40182\n#define ID_NOTIFICATIONS_STARTEDSERVICES 40183\n#define ID_NOTIFICATIONS_STOPPEDSERVICES 40184\n#define ID_NOTIFICATIONS_DELETEDSERVICES 40185\n#define ID_NOTIFICATIONS_MODIFIEDSERVICES 40186\n#define ID_MISCELLANEOUS_LOCKS          40187\n#define ID_MISCELLANEOUS_GDIHANDLES     40188\n#define ID_MISCELLANEOUS_HEAPS          40189\n#define ID_ESC_EXIT                     40190\n#define ID_NOTIFICATIONS_ARRIVEDDEVICES 40191\n#define ID_NOTIFICATIONS_REMOVEDDEVICES 40192\n#define ID_PROCESS_COPY                 40194\n#define ID_THREAD_COPY                  40195\n#define ID_NETWORK_COPY                 40197\n#define ID_SERVICE_COPY                 40198\n#define ID_MODULE_COPY                  40199\n#define ID_HANDLE_COPY                  40200\n#define ID_OBJECT_COPY                  40201\n#define ID_MEMORY_SAVE                  40208\n#define ID_MEMORY_CHANGEPROTECTION      40209\n#define ID_MEMORY_FREE                  40210\n#define ID_MEMORY_DECOMMIT              40211\n#define ID_MEMORY_COPY                  40213\n#define ID_MEMORY_READWRITEMEMORY       40214\n#define ID_MEMORY_EMPTYWORKINGSET       40215\n#define ID_FILTER_CONTAINS              40216\n#define ID_FILTER_CONTAINS_CASEINSENSITIVE 40218\n#define ID_FILTER_REGEX                 40219\n#define ID_FILTER_REGEX_CASEINSENSITIVE 40221\n#define ID_TAB_NEXT                     40223\n#define ID_TAB_PREV                     40224\n#define ID_VIEW_COLLAPSEALL             40225\n#define ID_VIEW_EXPANDALL               40226\n#define ID_MISCELLANEOUS_RUNAS          40229\n#define ID_MISCELLANEOUS_RUNASTHISUSER  40230\n#define ID_MISCELLANEOUS_PAGESMODIFIED  40231\n#define ID_VIEW_HIDEPROCESSESFROMOTHERUSERS 40232\n#define ID_MISCELLANEOUS_FLUSHHEAPS     40233\n#define ID_THREAD_AFFINITY              40233\n#define ID_THREAD_BOOST                 40234\n#define ID_VIEW_HIDESIGNEDPROCESSES     40234\n#define ID_VIEW_UPDATEAUTOMATICALLY     40235\n#define ID_HACKER_RUNASLIMITEDUSER      40236\n#define ID_USER_REMOTECONTROL           40237\n#define ID_VIEW_HIDEMICROSOFTPROCESSES  40238\n#define ID_PAGEPRIORITY_NORMAL          40239\n#define ID_PAGEPRIORITY_BELOWNORMAL     40240\n#define ID_PAGEPRIORITY_MEDIUM          40241\n#define ID_PAGEPRIORITY_LOW             40242\n#define ID_PAGEPRIORITY_VERYLOW         40243\n#define ID_VIEW_SHOWCPUBELOW001         40246\n#define ID_MODULE_OPENFILELOCATION      40247\n#define ID_PROCESS_OPENFILELOCATION     40248\n#define ID_MISCELLANEOUS_REDUCEWORKINGSET 40249\n#define IDC_BACK                        40255\n#define ID_VIEW_ORGANIZECOLUMNSETS      40256\n#define ID_VIEW_SAVECOLUMNSET           40257\n#define ID_VIEW_LOADCOLUMNSET           40258\n#define ID_VIEW_SORTROOTPROCESSES       40262\n#define ID_DIGIT1                       40263\n#define ID_DIGIT2                       40264\n#define ID_DIGIT3                       40265\n#define ID_DIGIT4                       40266\n#define ID_DIGIT5                       40267\n#define ID_DIGIT6                       40268\n#define ID_DIGIT7                       40269\n#define ID_DIGIT8                       40270\n#define ID_DIGIT9                       40271\n#define ID_VIEW_HIDEWAITINGCONNECTIONS  40272\n#define ID_VIEW_HIDEDRIVERSERVICES      40273\n#define ID_VIEW_HIDEMICROSOFTSERVICES   40274\n#define ID_VIEW_SECTIONPLACEHOLDER      40274\n#define ID_VIEW_SCROLLTONEWPROCESSES    40275\n#define ID_VIEW_SORTCHILDPROCESSES      40276\n#define ID_TOOLS_STARTTASKMANAGER       40277\n#define ID_COMPUTER_SHUTDOWNHYBRID      40278\n#define ID_COMPUTER_RESTARTADVOPTIONS   40279\n#define ID_COMPUTER_RESTARTBOOTOPTIONS  40280\n#define ID_COMPUTER_RESTARTFWOPTIONS    40281\n#define ID_COMPUTER_RESTARTFWDEVICE     40282\n#define ID_HANDLE_OBJECTPROPERTIES1     40282\n#define ID_COMPUTER_RESTARTBOOTDEVICE   40283\n#define ID_HANDLE_OBJECTPROPERTIES2     40283\n#define ID_OBJECT_GOTOOWNINGPROCESS     40284\n#define ID_COMPUTER_RESTARTWDOSCAN      40284\n#define ID_NETWORK_GOTOSERVICE          40285\n#define ID_SERVICE_OPENFILELOCATION     40286\n#define ID_PROCESS_GOTOPROCESS          40287\n#define ID_MINIINFO_REFRESH             40288\n#define ID_MINIINFO_REFRESHAUTOMATICALLY 40289\n#define ID_TOOLS_STARTRESOURCEMONITOR   40290\n#define ID_TOOLS_SHUTDOWNWSLPROCESSES   40291\n#define ID_HANDLE_GOTOOWNINGPROCESS     40292\n#define IDC_MAXSCREEN                   40293\n#define ID_PRIVILEGE_RESET              40296\n#define ID_GROUP_ENABLE                 40297\n#define ID_THREAD_CRITICAL              40297\n#define ID_GROUP_DISABLE                40298\n#define ID_GROUP_RESET                  40299\n#define ID_TOOLS_SCM_PERMISSIONS        40300\n#define ID_TOOLS_RDP_PERMISSIONS        40301\n#define ID_TOOLS_PWR_PERMISSIONS        40302\n#define ID_TOOLS_WMI_PERMISSIONS        40303\n#define ID_TOOLS_DESKTOP_PERMISSIONS    40304\n#define ID_TOOLS_STATION_PERMISSIONS    40305\n#define ID_UIACCESS_REMOVE              40306\n#define ID_TOOLS_LIVEDUMP               40307\n#define ID_NOTIFICATIONS_ENABLEDELAYSTART 40308\n#define ID_NOTIFICATIONS_ENABLEPERSISTLAYOUT 40309\n#define ID_NOTIFICATIONS_RESETPERSISTLAYOUT 40310\n#define ID_NOTIFICATIONS_ENABLETRANSPARENTICONS 40311\n#define ID_NOTIFICATIONS_ENABLESINGLECLICKICONS 40312\n#define ID_MISCELLANEOUS_EXECUTIONREQUIRED 40313\n#define IDD_OBJAFDSOCKET                40314\n#define ID_TOOLS_COM_ACCESS_PERMISSIONS 40315\n#define ID_TOOLS_COM_ACCESS_RESTRICTIONS 40316\n#define ID_TOOLS_COM_LAUNCH_PERMISSIONS 40317\n#define ID_TOOLS_COM_LAUNCH_RESTRICTIONS 40318\n#define IDDYNAMIC                       50000\n#define IDPLUGINS                       55000\n\n// Next default values for new objects\n//\n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        273\n#define _APS_NEXT_COMMAND_VALUE         40298\n#define _APS_NEXT_CONTROL_VALUE         1418\n#define _APS_NEXT_SYMED_VALUE           170\n#endif\n#endif\n"
  },
  {
    "path": "SystemInformer/resources/capslist.txt",
    "content": "ID_CAP_ACCESSIBILITY_CLIENT\nID_CAP_ACCESS_FAMILY_NOTES_API\nID_CAP_ACCESS_REMINDER_IMAGES\nID_CAP_ACC_MGR_ADMIN\nID_CAP_ADAPTIVE_BRIGHTNESS_CONTROL\nID_CAP_ADVERTISING_CONFIG\nID_CAP_AIS_TOKEN_MANAGER\nID_CAP_APPCONTAINER_PACKAGE_CERTIFICATES\nID_CAP_APPOINTMENTS\nID_CAP_APPPREINSTALL_DIRECTORY\nID_CAP_APPPREINSTALL_EVENTS\nID_CAP_APPRESOLVER\nID_CAP_APPX_EXECUTION\nID_CAP_APP_STORE_PURCHASE_HISTORY\nID_CAP_AUDIO_CALLINJECTION\nID_CAP_AUDIO_CALLRECORDING\nID_CAP_AUDIO_EVENTSND\nID_CAP_AUDIO_INTERNAL\nID_CAP_AUDIO_ROUTING_CONTROLLER\nID_CAP_AUDIO_SETTINGS\nID_CAP_AUTHHOST\nID_CAP_BACKGROUND_EXECUTION_MANAGEMENT\nID_CAP_BACKGROUND_SETTINGS_MANAGEMENT\nID_CAP_BACKGROUND_WORKER\nID_CAP_BACKUPROAMRESTORE\nID_CAP_BARCODE_POS\nID_CAP_BASEOS_ANTI_THEFT\nID_CAP_BASEOS_UPDATEAPI\nID_CAP_BINGCLIENT_BINGCONFIGURATION\nID_CAP_BINGCLIENT_CA_INTERESTEXTRACTION\nID_CAP_BINGCLIENT_DDC\nID_CAP_BINGCLIENT_IDENTITY\nID_CAP_BINGCLIENT_OSS\nID_CAP_BINGCLIENT_SUGGESTSHIGHLIGHTS\nID_CAP_BINGCLIENT_TEE\nID_CAP_BLUETOOTH\nID_CAP_BLUETOOTH_ADMIN\nID_CAP_BMR2_MONITOR_SERVICE\nID_CAP_BMR_CONFIGURATION\nID_CAP_BMR_SYNC\nID_CAP_BROKER_NAVIGATION\nID_CAP_BROWSER_ACCESSIBILITY_SETTINGS\nID_CAP_BROWSER_FEATURE_CONTROL_KEYS\nID_CAP_BSS_AIM_INTERFACE\nID_CAP_BSS_NABSYNC_INTERFACE\nID_CAP_BSS_PUSH_INTERFACE\nID_CAP_BSS_REMINDER_INTERFACE\nID_CAP_BUILTIN_BASEPRIORITY\nID_CAP_BUILTIN_CREATEGLOBAL\nID_CAP_BUILTIN_CREATEPERMANENT\nID_CAP_BUILTIN_DEFAULT\nID_CAP_BUILTIN_IMPERSONATE\nID_CAP_BUILTIN_PROFILE\nID_CAP_BUILTIN_SETTIME\nID_CAP_BUILTIN_SHUTDOWN\nID_CAP_BUILTIN_SYMBOLICLINK\nID_CAP_BUILTIN_TCB\nID_CAP_BUTTONS\nID_CAP_CALLMESSAGING_FILTER\nID_CAP_CAMERA\nID_CAP_CA_ACTIONURI_TEST_EVENT\nID_CAP_CA_ADMIN\nID_CAP_CA_BACKGROUND_PROCESSOR\nID_CAP_CA_BACKGROUND_PROCESSOR_ADMIN\nID_CAP_CA_CONTEXT\nID_CAP_CA_DND_MANAGER\nID_CAP_CA_ENABLED\nID_CAP_CA_HISTORY\nID_CAP_CA_RULES\nID_CAP_CA_SIGNALS_GENERIC\nID_CAP_CA_SIGNALS_MANAGER\nID_CAP_CA_SIGNALS_MANAGER_ADMIN\nID_CAP_CA_UPLOAD_FOLDER\nID_CAP_CBS_API\nID_CAP_CDP_POLICY\nID_CAP_CELLUX_CONFIG_READ\nID_CAP_CELL_API_ADMIN\nID_CAP_CELL_API_COMMON\nID_CAP_CELL_API_LOCATION\nID_CAP_CELL_API_MESSAGING\nID_CAP_CELL_API_MODEMLOGGING\nID_CAP_CELL_API_OEM_PASSTHROUGH\nID_CAP_CELL_API_TELEPHONY\nID_CAP_CELL_API_UICC\nID_CAP_CELL_API_UICC_LOWLEVEL\nID_CAP_CELL_CELLMGR\nID_CAP_CELL_CMCSPWWAN_PLUS\nID_CAP_CELL_MSFT_UICC_DATASTORE\nID_CAP_CELL_OEM_UICC_DATASTORE\nID_CAP_CELL_RCSPRESENCE\nID_CAP_CELL_VIDEOTELEPHONY\nID_CAP_CELL_WNF\nID_CAP_CELL_WNF_ADMIN\nID_CAP_CELL_WNF_PII\nID_CAP_CHAMBER_PROFILE_CODE_INSTALLTEMP_RWD\nID_CAP_CHAMBER_PROFILE_CODE_NITEMP_RW\nID_CAP_CHAMBER_PROFILE_CODE_R\nID_CAP_CHAMBER_PROFILE_CODE_RW\nID_CAP_CHAMBER_PROFILE_DATA_LIVETILES_RWD\nID_CAP_CHAMBER_PROFILE_DATA_MEDIA_RWD\nID_CAP_CHAMBER_PROFILE_DATA_PLATFORMDATA_ALL\nID_CAP_CHAMBER_PROFILE_DATA_R\nID_CAP_CHAMBER_PROFILE_DATA_RW\nID_CAP_CHAMBER_PROFILE_DATA_SHELLCONTENT_R\nID_CAP_CHAMBER_PROFILE_DATA_SHELLCONTENT_RWD\nID_CAP_CLIPBOARD\nID_CAP_COMMANDCHANNEL\nID_CAP_COMMS_APPLICATIONS\nID_CAP_COMMS_COMMON\nID_CAP_COMMS_SERVICES\nID_CAP_COMMS_SETTINGS\nID_CAP_CONTACTS\nID_CAP_CONTENTSHARING\nID_CAP_CORE_SHELL\nID_CAP_CORTANA_RULES_DB\nID_CAP_CREATE_PROCESS_IN_CHAMBER\nID_CAP_CREDENTIAL_COLLECTION_UI\nID_CAP_CRITICAL_DATA\nID_CAP_CSP_BMR_PROVISION\nID_CAP_CSP_DMCLIENT\nID_CAP_CSP_FOUNDATION\nID_CAP_CSP_LOCATION\nID_CAP_CSP_MAIL\nID_CAP_CSP_NODECACHE\nID_CAP_CSP_OEM\nID_CAP_CSP_PHONE\nID_CAP_CSP_W4_APPLICATION\nID_CAP_CSP_WIFI_HOTSPOT\nID_CAP_DATACOLLECTION_ACTIVITY\nID_CAP_DATACOLLECTION_COLLECTOR\nID_CAP_DATACOLLECTION_RAWETW\nID_CAP_DATAPLANUSAGE\nID_CAP_DATAPLANUSAGE_ADMIN\nID_CAP_DCP\nID_CAP_DEBUG\nID_CAP_DEBUG_FOLDERS\nID_CAP_DEBUG_NAVIGATION\nID_CAP_DEVELOPERUNLOCK\nID_CAP_DEVELOPERUNLOCK_API\nID_CAP_DEVELOPERUNLOCK_CODEDUI\nID_CAP_DEVICE_LOCK\nID_CAP_DEVICE_LOCK_ADMIN\nID_CAP_DEVICE_MANAGEMENT\nID_CAP_DEVICE_MANAGEMENT_ADMIN\nID_CAP_DEVICE_MANAGEMENT_BOOTSTRAP\nID_CAP_DEVICE_MANAGEMENT_SECURITY_POLICIES\nID_CAP_DIAGNOSTIC_CLIENT\nID_CAP_DISPLAY_CONTROL\nID_CAP_DMCLIENT_APPMGMT\nID_CAP_DO_NOT_DISTURB\nID_CAP_DRIVE_MODE_ADMIN\nID_CAP_DUASVC\nID_CAP_DU_AGENT\nID_CAP_DU_CORE_API\nID_CAP_DU_CSP\nID_CAP_DU_MIGRATION_MANAGER_STATUS\nID_CAP_DU_MIGRATION_WNF_EVENTS\nID_CAP_DU_MIGRATOR_PROVISIONING_STATUS_MICROSOFT\nID_CAP_DU_MIGRATOR_PROVISIONING_STATUS_OEM\nID_CAP_DU_MIGRATOR_STATUS_MICROSOFT\nID_CAP_DU_MIGRATOR_STATUS_OEM\nID_CAP_DU_PROVISIONING\nID_CAP_DU_SHARED_DATA\nID_CAP_DU_USS\nID_CAP_DU_UX\nID_CAP_DU_UX_FEATURE_DISCOVERY\nID_CAP_EAS_CREDENTIALS\nID_CAP_EDM_CACHE_RWDELETE\nID_CAP_EDM_CACHE_WRITE\nID_CAP_ENDPOINTDISCOVERY\nID_CAP_ENROLLMENT\nID_CAP_ENROLLMENT_ADMIN\nID_CAP_ENROLLMENT_POLL\nID_CAP_ENROLLMENT_RENEW\nID_CAP_ENTERPRISERESOURCESTORE\nID_CAP_ENTERPRISE_AUTHENTICATION\nID_CAP_ENTERPRISE_ENROLLMENT\nID_CAP_ENTERPRISE_SERVICE\nID_CAP_ENTERPRISE_SHARED_DATA\nID_CAP_ETW_PROFILER\nID_CAP_EVERYONE\nID_CAP_EVERYONE_INROM\nID_CAP_EXTERNAL_DISPLAY\nID_CAP_FAILURE_REPORT_CONTENT_PROVIDER\nID_CAP_FINDMYPHONE\nID_CAP_FOREGROUND_TASK_MANAGER\nID_CAP_GAMERSERVICES\nID_CAP_GLOBALIZATION_SETTINGS\nID_CAP_HTTP_ACCEPT_LANGUAGE_HEADER\nID_CAP_ICS_RO\nID_CAP_ICS_RW\nID_CAP_IDENTITY_DEVICE\nID_CAP_IDENTITY_DEVICE_1ST_PARTY\nID_CAP_IDENTITY_USER\nID_CAP_IDENTITY_USER_1ST_PARTY\nID_CAP_IDM_IMAGE_CACHE\nID_CAP_IMMERSIVE_SHELL\nID_CAP_INPUT_CORE\nID_CAP_INPUT_FEATURES\nID_CAP_INPUT_INJECTION\nID_CAP_INPUT_LOCALES\nID_CAP_INPUT_SERVICE\nID_CAP_INSTALL_CERTIFICATES\nID_CAP_INTENTTEXTRACTION_OPTIN\nID_CAP_INTERNAL_DEPLOYMENT\nID_CAP_INTERNET_EXPLORER_BROWSER_HISTORY\nID_CAP_INTERNET_EXPLORER_DATA_OPTIMIZATION\nID_CAP_INTERNET_EXPLORER_FAVORITES\nID_CAP_INTERNET_EXPLORER_HKCU_WRITE\nID_CAP_INTERNET_EXPLORER_HKLM_SECURITY_SETTINGS\nID_CAP_INTERNET_EXPLORER_INTRANET_ZONE_SETTINGS\nID_CAP_INTERNET_EXPLORER_REMOTEDEBUGGING\nID_CAP_INTERNET_EXPLORER_ROAMING\nID_CAP_INTERNET_EXPLORER_SEARCH_PROVIDER_KEYS_HKCU\nID_CAP_INTEROPSERVICES\nID_CAP_ISV_CAMERA\nID_CAP_KEYBOARD\nID_CAP_KIDZONE_ADMIN\nID_CAP_KIDZONE_CUSTOMIZATION\nID_CAP_LANGUAGEUNDERSTANDING\nID_CAP_LASS_ADMIN\nID_CAP_LASS_REMOTELOCK\nID_CAP_LEGACY_VOICEMAIL_HANDLER\nID_CAP_LEXICONUPDATE\nID_CAP_LIVEID\nID_CAP_LIVETOKEN_WNF_EVENTS\nID_CAP_LOCATION\nID_CAP_LOCATION_ADMIN\nID_CAP_LOCATION_BTPOLICY\nID_CAP_LOCATION_GNSSDRIVER\nID_CAP_MAP\nID_CAP_MAP_ADMIN\nID_CAP_MAP_WRITE\nID_CAP_MEDIALIB\nID_CAP_MEDIALIB_AUDIO\nID_CAP_MEDIALIB_INT\nID_CAP_MEDIALIB_PHOTO\nID_CAP_MEDIALIB_PHOTO_FULL\nID_CAP_MEDIALIB_PLAYBACK\nID_CAP_MEDIALIB_VIDEO\nID_CAP_MEDIASERVICE_VOLUMELIMIT_INT\nID_CAP_MICMUTEPOLICY_BYPASS\nID_CAP_MICROPHONE\nID_CAP_MONITOR_NAVIGATION\nID_CAP_MOUSE\nID_CAP_MO_CLOUDMESSAGING\nID_CAP_MSS_BYTESTREAM_RPC\nID_CAP_MULTIMEDIA_ENCODER_HARDWARE\nID_CAP_MULTIVARIANT\nID_CAP_MULTIVARIANT_INSTALL_DATA\nID_CAP_NARRATOR_SETTINGS\nID_CAP_NATIVE_NETWORK_REPLACEMENT\nID_CAP_NAVIGATIONBAR_ADMIN\nID_CAP_NETWORKING\nID_CAP_NETWORKING_ADMIN\nID_CAP_NETWORKING_INTERNET_CLIENT\nID_CAP_NETWORKING_INTERNET_CLIENT_SERVER\nID_CAP_NETWORKING_PRIVATE_NETWORK_CLIENT_SERVER\nID_CAP_NETWORKING_VPN_ADMIN\nID_CAP_NETWORKING_VPN_PROVIDER\nID_CAP_NETWORKING_VPN_SERVICES\nID_CAP_NFC_ADMIN\nID_CAP_NOCENTER_SOUNDS\nID_CAP_NTSERVICES\nID_CAP_NVREAD\nID_CAP_NVREADWRITE\nID_CAP_O365_DISCOVERY\nID_CAP_OEMPUBLICDIRECTORY\nID_CAP_OEM_ADC\nID_CAP_OEM_CUSTOM\nID_CAP_OEM_DEPLOYMENT\nID_CAP_OFFICE_LAUNCH_URL\nID_CAP_OFFICE_MSDRM_HKCU\nID_CAP_ONENOTE_EVENTS\nID_CAP_OOBE_PRIVATE\nID_CAP_ORIENTATION_LOCK\nID_CAP_PEOPLE_EXTENSION\nID_CAP_PEOPLE_EXTENSION_IM\nID_CAP_PEOPLE_EXTENSION_MOBILE\nID_CAP_PERSONA\nID_CAP_PERSONAL_INFORMATION_IMPORT\nID_CAP_PHONEBROKER_INTERFACE\nID_CAP_PHONEDIALER\nID_CAP_PHONEPROVISIONER_DEVICEUPDATE\nID_CAP_PHONEPROVISIONER_EVENTS\nID_CAP_PHONE_2ND_PARTY\nID_CAP_PHONE_ADMIN\nID_CAP_PHONE_INTERNAL\nID_CAP_PHOTOS_SETTINGS_R\nID_CAP_PHOTOS_SETTINGS_RW\nID_CAP_PICKER_CONTRACT_UI\nID_CAP_PLATFORM_EXTENSIBILITY\nID_CAP_PLAYREADY\nID_CAP_PLAYREADY_ADMIN\nID_CAP_PM_1ST_PARTY\nID_CAP_PM_BSS\nID_CAP_PM_INSTALL\nID_CAP_POIDATASTORE\nID_CAP_POIDATASTORE_ADMIN\nID_CAP_POLICY_MANAGER\nID_CAP_POLICY_MANAGER_READONLY\nID_CAP_POWERNOTIF_USER\nID_CAP_PRESERVED_DATA\nID_CAP_PRIV_ABOUTCPL\nID_CAP_PRIV_ACCESSIBILITYCPL\nID_CAP_PRIV_ACCESSORIESCPL\nID_CAP_PRIV_ACCESSORYMGRSVC\nID_CAP_PRIV_ACCOUNTPROVSVC\nID_CAP_PRIV_ACTIONURIHOST\nID_CAP_PRIV_ADVERTISINGIDCPL\nID_CAP_PRIV_ALARMS\nID_CAP_PRIV_APHCHECK\nID_CAP_PRIV_APMUX\nID_CAP_PRIV_APPCORNER\nID_CAP_PRIV_APPPREINSTALLER\nID_CAP_PRIV_APPRESOLVERUI\nID_CAP_PRIV_APPSDATAMIGRATOR\nID_CAP_PRIV_APPXEXECUTIONSVC\nID_CAP_PRIV_AUTHHOST_MSA\nID_CAP_PRIV_AUTHHOST_WAB_A\nID_CAP_PRIV_AUTHHOST_WAB_B\nID_CAP_PRIV_AUTHHOST_WAB_C\nID_CAP_PRIV_AUTHHOST_WAB_ENTERPRISE\nID_CAP_PRIV_AUTHHOST_WAB_SSO\nID_CAP_PRIV_AUTHHOST_WAB_SSO_ENTERPRISE\nID_CAP_PRIV_AUTOTIMEUPDATE\nID_CAP_PRIV_BATTERYSAVERCPL\nID_CAP_PRIV_BLUETOOTHPBAPSVC\nID_CAP_PRIV_BMR2MONITORSVC\nID_CAP_PRIV_BMR2SCHEDULETRIGGER\nID_CAP_PRIV_BMRCPL\nID_CAP_PRIV_BMRSCHEDULETRIGGER\nID_CAP_PRIV_BRIGHTNESSCPL\nID_CAP_PRIV_BSSVC\nID_CAP_PRIV_BTAGSERVICE\nID_CAP_PRIV_BTCONNMGR\nID_CAP_PRIV_BTHAVCTPSVC\nID_CAP_PRIV_BTSERV\nID_CAP_PRIV_BTUXCPL\nID_CAP_PRIV_CALC7\nID_CAP_PRIV_CAPTURESVC\nID_CAP_PRIV_CASVCSHARED3\nID_CAP_PRIV_CELLMANAGER\nID_CAP_PRIV_CELLULARDATACOLLECTOR\nID_CAP_PRIV_CELLUX\nID_CAP_PRIV_CERTINSTALLER\nID_CAP_PRIV_CFMSVC\nID_CAP_PRIV_CGSVC\nID_CAP_PRIV_CLOUDSTORAGECPL\nID_CAP_PRIV_CMSERVICE\nID_CAP_PRIV_COMMANDCHANNEL\nID_CAP_PRIV_COMMSAPHOST\nID_CAP_PRIV_COMMSAPPLICATIONS\nID_CAP_PRIV_COMMSCERTINSTSVC\nID_CAP_PRIV_COMMSMESSAGESVC\nID_CAP_PRIV_COMMSMMSTRANSPORT\nID_CAP_PRIV_CONTACTSTOKENSVC\nID_CAP_PRIV_CONTENTSHARESVC\nID_CAP_PRIV_CONTENTSHARINGAPP\nID_CAP_PRIV_COREUIREGISTRAR\nID_CAP_PRIV_DACCERTINSTSVC\nID_CAP_PRIV_DATACOLLECTION\nID_CAP_PRIV_DATASENSESVC\nID_CAP_PRIV_DATASMART\nID_CAP_PRIV_DATETIMECPL\nID_CAP_PRIV_DCPSVC\nID_CAP_PRIV_DEBUGGERMUXNOTIFY\nID_CAP_PRIV_DIAGNOSTICSVC\nID_CAP_PRIV_DMCFGHOST\nID_CAP_PRIV_DMOMACPNETWMO\nID_CAP_PRIV_DMOMACPUSERMO\nID_CAP_PRIV_DMWAPPUSHSVC\nID_CAP_PRIV_DRIVINGMODEMANAGER\nID_CAP_PRIV_DRIVINGMODESETTINGS\nID_CAP_PRIV_DSSVC\nID_CAP_PRIV_DSTOKENCLEAN\nID_CAP_PRIV_DUACALLBACK\nID_CAP_PRIV_DUACLIENT\nID_CAP_PRIV_DUCLEANUPMIGRATOR\nID_CAP_PRIV_DUFEATUREDISCOVERY\nID_CAP_PRIV_DUMIGRATIONMANAGER\nID_CAP_PRIV_DUMIGRATIONPROVISIONERMICROSOFT\nID_CAP_PRIV_DUMIGRATIONPROVISIONEROEM\nID_CAP_PRIV_DUPOSTUPDATEUX\nID_CAP_PRIV_DUSTARTINGMIGRATOR\nID_CAP_PRIV_DUSVC\nID_CAP_PRIV_ENROLLMENTCLIENT\nID_CAP_PRIV_ENTAPPSERVICE\nID_CAP_PRIV_ENTERPRISEINSTALL\nID_CAP_PRIV_ENTERPRISEMGMSVC\nID_CAP_PRIV_ENTERPRISERING\nID_CAP_PRIV_ENTERPRISEVALIDATION\nID_CAP_PRIV_EXECMANSERVICE\nID_CAP_PRIV_FINDMYPHONE\nID_CAP_PRIV_FLYOUTDATAMIGRATOR\nID_CAP_PRIV_GROVELER\nID_CAP_PRIV_GWPCENROLLSVC\nID_CAP_PRIV_HFA\nID_CAP_PRIV_HOTSPOTHOST\nID_CAP_PRIV_HUBTILERESTOREHOST\nID_CAP_PRIV_ICSENTITLEMENTHOST\nID_CAP_PRIV_ICSSVC\nID_CAP_PRIV_INPUTSERVICE\nID_CAP_PRIV_INSTALLERWORKER\nID_CAP_PRIV_INTERNETEXPLORER\nID_CAP_PRIV_IPOVERUSB\nID_CAP_PRIV_KEYBOARDCPL\nID_CAP_PRIV_KIDZONECONFIGURATION\nID_CAP_PRIV_KIDZONECUSTOMIZATION\nID_CAP_PRIV_LASSCREDENTIALEXPIRATIONCHECK\nID_CAP_PRIV_LAUNCHAPPSVC\nID_CAP_PRIV_LEXICONUPDATE\nID_CAP_PRIV_LFSVC\nID_CAP_PRIV_LIVETOKEN\nID_CAP_PRIV_LOCATIONUXCPL\nID_CAP_PRIV_LOCKANDWALLPAPER\nID_CAP_PRIV_MEDIA\nID_CAP_PRIV_MEDIASERVICE\nID_CAP_PRIV_MIRRORCPL\nID_CAP_PRIV_MOBILEUI\nID_CAP_PRIV_MOSHOST\nID_CAP_PRIV_MSATICKETSVC\nID_CAP_PRIV_MSGIMTRANSPORT\nID_CAP_PRIV_MSGSMSTRANSPORT\nID_CAP_PRIV_MTP\nID_CAP_PRIV_MVPROVISIONHOST\nID_CAP_PRIV_MVUX\nID_CAP_PRIV_NABSYNC\nID_CAP_PRIV_NOCENTERSETTINGSCPL\nID_CAP_PRIV_NOTIFICATIONPLATFORMMIGRATOR\nID_CAP_PRIV_NOTIFSVC\nID_CAP_PRIV_OFFICE\nID_CAP_PRIV_OMADMCLIENT_ENTERPRISE\nID_CAP_PRIV_OMADMCLIENT_MOBILE_OPERATOR\nID_CAP_PRIV_OMADMPRC\nID_CAP_PRIV_OOBE\nID_CAP_PRIV_ORIENTSRV\nID_CAP_PRIV_PACMANSERVICE\nID_CAP_PRIV_PHONEAUDIOSRV\nID_CAP_PRIV_PHONEPROVISIONER\nID_CAP_PRIV_PHONEPROVISIONER_OEM\nID_CAP_PRIV_PHONESVCSG\nID_CAP_PRIV_PHOTOS\nID_CAP_PRIV_PHOTOSSVC\nID_CAP_PRIV_PIMIDXMAINT\nID_CAP_PRIV_PLACESSVC\nID_CAP_PRIV_POSTDUAPPMIGRATOR\nID_CAP_PRIV_POWERNOTIF\nID_CAP_PRIV_PROXIMITYSVC\nID_CAP_PRIV_PROXYSVC\nID_CAP_PRIV_REALWORLD-BINGCLIENT\nID_CAP_PRIV_REALWORLD-INTERESTEXTRACTION\nID_CAP_PRIV_REBOOTDEVICE\nID_CAP_PRIV_REGIONCPL\nID_CAP_PRIV_REMEMBER\nID_CAP_PRIV_RETAILDEMO\nID_CAP_PRIV_RETAILDEMOERROR\nID_CAP_PRIV_RETAILDEMOGLOB\nID_CAP_PRIV_RETAILDEMOUI\nID_CAP_PRIV_RILADAPTATION\nID_CAP_PRIV_RINGTONESANDSOUNDS\nID_CAP_PRIV_ROAMINGCPL\nID_CAP_PRIV_ROTATIONLOCKCPL\nID_CAP_PRIV_SAPISVR\nID_CAP_PRIV_SECMIGRATOR\nID_CAP_PRIV_SEMGRSVC\nID_CAP_PRIV_SETTINGS\nID_CAP_PRIV_SHELLDATAMIGRATOR\nID_CAP_PRIV_SIREPSVC\nID_CAP_PRIV_SOFTAPUX\nID_CAP_PRIV_SPEECHCPL\nID_CAP_PRIV_SPEECHUPDATE\nID_CAP_PRIV_START\nID_CAP_PRIV_STORAGESENSE\nID_CAP_PRIV_STORAGESVC\nID_CAP_PRIV_STOREDATAMIGRATOR\nID_CAP_PRIV_TASKSCHEDULERSVC\nID_CAP_PRIV_TELCPL\nID_CAP_PRIV_TELREPSVC\nID_CAP_PRIV_THEMECPL\nID_CAP_PRIV_TILEMIGRATOR\nID_CAP_PRIV_TIMEBROKER\nID_CAP_PRIV_UPDATEMGRSVC\nID_CAP_PRIV_USBCPL\nID_CAP_PRIV_USERDATASERVICE\nID_CAP_PRIV_USSREPORTING\nID_CAP_PRIV_UTKSERVICE\nID_CAP_PRIV_UTKUX\nID_CAP_PRIV_VPNUX\nID_CAP_PRIV_WALLET\nID_CAP_PRIV_WALLETSVC\nID_CAP_PRIV_WEHCSPHELPER\nID_CAP_PRIV_WEHSTART\nID_CAP_PRIV_WIFICONNSVC\nID_CAP_PRIV_WIFICPASSIST\nID_CAP_PRIV_WIFICPBROWSERUX\nID_CAP_PRIV_WIFIUDPTEST\nID_CAP_PRIV_WIFIUXBLUE\nID_CAP_PRIV_WLID2MSA\nID_CAP_PRIV_WPABSVC\nID_CAP_PRIV_WPNARRATOR\nID_CAP_PRIV_WPNCERTINSTSVC\nID_CAP_PRIV_WPTOOLS\nID_CAP_PRIV_WPTPMVSCMGRSVC\nID_CAP_PRIV_WPUITESTTOOLS\nID_CAP_PRIV_ZMEDIAQUEUESVC\nID_CAP_PRIV_ZMF\nID_CAP_PRIV_ZMF_SERVICE\nID_CAP_PROVISIONING_PACKAGE_API_ADMIN\nID_CAP_PROVISIONWPCERTIFICATE\nID_CAP_PROXIMITY\nID_CAP_PUBLIC_FOLDER_FULL\nID_CAP_PUBLISH_ALARM_STATE\nID_CAP_PUBLISH_OOBE_STATE\nID_CAP_PUSHROUTER\nID_CAP_PUSH_NOTIFICATION\nID_CAP_PUSH_SERVER\nID_CAP_QUICK_SETTINGS\nID_CAP_READGWPCERTIFICATE\nID_CAP_REBOOT_FLASHING_MODE\nID_CAP_REMEMBER_ADMIN\nID_CAP_REMEMBER_API\nID_CAP_REMOVABLE_STORAGE\nID_CAP_RESET_PHONE\nID_CAP_RESOURCE_MANAGER\nID_CAP_RETAILDEMO_BACKGROUNDIMAGE\nID_CAP_RETAILDEMO_CLIENT\nID_CAP_RETAILDEMO_GLOB_REGISTRY\nID_CAP_RETAILDEMO_OFFLINECONTENT\nID_CAP_RINGTONE_ADD\nID_CAP_ROAMING_CONFIGURATION\nID_CAP_ROTATION_MANAGER\nID_CAP_RUNTIME_CONFIG\nID_CAP_SCREENCAPTURE\nID_CAP_SCREEN_RECORDER\nID_CAP_SCREEN_RECORDER_BKG\nID_CAP_SEARCHMAPS_SHAREDCONFIG\nID_CAP_SEND_TO_ONENOTE\nID_CAP_SENSORS\nID_CAP_SETDEVICENAME\nID_CAP_SETTINGSYNC\nID_CAP_SETTINGSYNC_CONFIGURATION\nID_CAP_SETTINGS_MANAGEMENT_PROVIDER\nID_CAP_SHARED_OBJECT_DIRECTORY\nID_CAP_SHARED_USER_CERTIFICATES\nID_CAP_SHARE_DELEGATE\nID_CAP_SHELL_DEVICE_LOCK_UI_API\nID_CAP_SHELL_EXPERIENCE_COMPOSER\nID_CAP_SHELL_LAUNCH_SESSION\nID_CAP_SHELL_NAVIGATION\nID_CAP_SHELL_NOTIFICATION_CLIENT\nID_CAP_SHELL_NOTIFICATION_SETTINGS_DB\nID_CAP_SHELL_OEM_ADMIN\nID_CAP_SHELL_RESET_NAVIGATION\nID_CAP_SHELL_TEST_CLIENT\nID_CAP_SHOW_VOLUME_CONTROL\nID_CAP_SMS\nID_CAP_SMS_COMPANION\nID_CAP_SMS_INTERCEPT_AGENT\nID_CAP_SMS_INTERCEPT_RECIPIENT\nID_CAP_SOUND_CONTROL\nID_CAP_SPEECH_GRAMMARS\nID_CAP_SPEECH_RECOGNITION\nID_CAP_SPEECH_RECOGNITION_SYSTEM\nID_CAP_SPEECH_SETTINGS\nID_CAP_SPEECH_UPDATE\nID_CAP_SPLASH_CONFIG\nID_CAP_STARTMENU_CONFIG\nID_CAP_STARTMENU_WEBLINK_ICONS\nID_CAP_STORAGE_MANAGEMENT\nID_CAP_SUPPRESS_MSA_CONNECT_ARD\nID_CAP_SYNC_EXTENSION\nID_CAP_SYSTEMTRAY_ADMIN\nID_CAP_SYSTEM_ALLOC_WINDOWID\nID_CAP_SYSTEM_COMPOSITOR\nID_CAP_SYSTEM_COUNTERS\nID_CAP_SYSTEM_REGISTRAR\nID_CAP_SYSTEM_WAITCURSOR\nID_CAP_TELEMETRY_ADMIN\nID_CAP_TELEMETRY_CONFIGURE\nID_CAP_TELEMETRY_STUDY\nID_CAP_TEST_NAVIGATION\nID_CAP_TILERESTOREDATA\nID_CAP_TOUCH\nID_CAP_TOUCH_TEST\nID_CAP_TPM_VSCMANAGER\nID_CAP_TS_SCHEDULES_ALL\nID_CAP_USB\nID_CAP_USER_ACTIVITY\nID_CAP_USER_DATA_ACCOUNT_SETUP\nID_CAP_VIDEOSINK_INTERNAL\nID_CAP_VOICEMAIL\nID_CAP_VOIP\nID_CAP_VOIP_CALL_CONTROLLER\nID_CAP_VSTEST_INSTALL_FOLDER\nID_CAP_W32TIME_API\nID_CAP_WAB_RESOURCES\nID_CAP_WALLET\nID_CAP_WALLET_ADMIN\nID_CAP_WALLET_DEALS\nID_CAP_WALLET_PAYMENTINSTRUMENTS\nID_CAP_WALLET_SECUREELEMENT\nID_CAP_WALLPAPER_ADMIN\nID_CAP_WBOEXT\nID_CAP_WEBBROWSERCOMPONENT\nID_CAP_WEB_CREDENTIALS\nID_CAP_WIFI_ADMIN\nID_CAP_WIFI_BASIC\nID_CAP_WIFI_BROWSER\nID_CAP_WIFI_HOTSPOT_HOST\nID_CAP_WIFI_PROFILE_ADMIN\nID_CAP_WIFI_TILE_MANAGER\nID_CAP_WINDOW_MANAGEMENT_SYSTEM\nID_CAP_WPN_PLATFORM\nID_CAP_WPN_PLATFORM_REG_KEY\nID_CAP_WPTOOLS_INSTALL_FOLDER\nID_CAP_ZMFSERVICES\nID_CAP_ZTRACE\naccessoryManager\nactivateAsUser\nactivity\nactivityData\nactivitySystem\nallAppMods\nallJoyn\nallowElevation\nappBroadcast\nappBroadcastServices\nappBroadcastSettings\nappCaptureServices\nappCaptureSettings\nappDiagnostics\napplicationDefaults\napplicationDefaultsUserChoice\napplicationViewActivation\nappLicensing\nappManagementSystem\nappointments\nappointmentsSystem\naudioDeviceConfiguration\nautomatedAppLaunch\nbackgroundMediaPlayback\nbackgroundMediaRecording\nbackgroundSpatialPerception\nbackgroundVoIP\nbiometricSystem\nblockedChatMessages\nbluetooth\nbluetooth.genericAttributeProfile\nbluetooth.rfcomm\nbluetoothAdapter\nbluetoothDeviceSettings\nbluetoothDiagnostics\nbluetoothSync\nbootstrapNetworkConnection\nbroadFileSystemAccess\nbrowserAppList\nbrowserCredentials\ncameraProcessingExtension\ncapabilityAccessConsentDeviceSettings\ncellularData\ncellularDeviceControl\ncellularDeviceIdentity\ncellularMessaging\nchat\nchatSystem\nchildWebContent\nchromeInstallFiles\ncloudExperienceHost\ncloudStore\ncodeGeneration\ncomponentUiInWebContent\ncomPort\nconfirmAppClose\nconstrainedImpersonation\ncontacts\ncontactsSystem\ncontentDeliveryManagerSettings\ncontentRestrictions\ncoreShell\ncortanaPermissions\ncortanaSettings\ncortanaSpeechAccessory\ncortanaSurface\ncuratedTileCollections\ncustomInstallActions\ndateAndTimeDeviceSettings\ndependencyTarget\ndelegatedTokenRequests\ndeveloperSettings\ndevelopmentModeNetwork\ndeviceEncryptionManagement\ndeviceIdentityManagement\ndeviceLockManagement\ndeviceManagementAdministrator\ndeviceManagementDeclaredConfiguration\ndeviceManagementDeviceLockPolicies\ndeviceManagementDmAccount\ndeviceManagementEmailAccount\ndeviceManagementFoundation\ndeviceManagementRegistration\ndeviceManagementWapSecurityPolicies\ndevicePortalProvider\ndeviceProvisioningAdministrator\ndeviceUnlock\ndiagnostics\ndisplayDeviceSettings\ndocumentsLibrary\ndownloadsFolder\ndualSimTiles\nemail\nemailSystem\nenterpriseAuthentication\nenterpriseCloudSSO\nenterpriseDataPolicy\nenterpriseDeviceLockdown\neraApplication\nexclusiveResource\nexpandedResources\nextendedBackgroundTaskTime\nextendedExecutionBackgroundAudio\nextendedExecutionCritical\nextendedExecutionUnconstrained\nfeatureStagingInfo\nfeedbackLogCollection\nfirstSignInSettings\nflashPlayerSupport\nfullFileSystemAccess\ngameBarServices\ngameConfigStoreManagement\ngameList\ngameMonitor\ngamingContainerResources\ngazeInput\nglobalMediaControl\ngraphicsCapture\ngraphicsCaptureProgrammatic\ngraphicsCaptureWithoutBorder\nhardwareManagerMocks\nhevcPlayback\nhfxSystem\nhidTelephony\nholographicCompositor\nholographicCompositorSystem\nhumanInterfaceDevice\nhumanPresence\nimeSystem\nindexedContent\ninProcessMediaExtension\ninputForegroundObservation\ninputInjection\ninputInjectionBrokered\ninputObservation\ninputOverride\ninputSettings\ninputSuppression\ninternetClient\ninternetClientServer\ninteropServices\nisolatedWin32-accessToPublisherDirectory\nisolatedWin32-dotNetBreadcrumbStore\nisolatedWin32-print\nisolatedWin32-profilesRootMinimal\nisolatedWin32-promptForAccess\nisolatedWin32-shellExtensionContextMenu\nisolatedWin32-sysTrayIcon\nisolatedWin32-userProfileMinimal\nisolatedWin32-volumeRootMinimal\nkeyboardDeviceSettings\nkinectAudio\nkinectExpressions\nkinectFace\nkinectGamechat\nkinectRequired\nkinectVideo\nkinectVision\nlanguageAndRegionDeviceSettings\nlanguageSettings\nlearningModeLogging\nliveIdService\nlocalExperienceCumulativeInternal\nlocalExperienceInternal\nlocalSystemServices\nlocation\nlocationHistory\nlocationSystem\nlockScreenCreatives\nlowLevel\nlowLevelDevices\nlpacAppExperience\nlpacChromeInstallFiles\nlpacChromeNetworkSandbox\nlpacClipboard\nlpacCom\nlpacCryptoServices\nlpacDeviceAccess\nlpacEdgeWdagComms\nlpacEnterprisePolicyChangeNotifications\nlpacIdentityServices\nlpacIME\nlpacInstrumentation\nlpacMedia\nlpacMediaFoundationCdmData\nlpacPackageManagerOperation\nlpacPayments\nlpacPnPNotifications\nlpacPrinting\nlpacServicesManagement\nlpacSessionManagement\nlpacWebPlatform\nmediaFoundationCdmFiles\nmicrophone\nMicrosoft.appCategory.chatAgent_8wekyb3d8bbwe\nMicrosoft.cellularSARConfiguration_8wekyb3d8bbwe\nMicrosoft.classicAppCompat_8wekyb3d8bbwe\nMicrosoft.classicAppCompatElevated_8wekyb3d8bbwe\nMicrosoft.classicAppInstaller_8wekyb3d8bbwe\nMicrosoft.componentUiInWebContentGeneral_8wekyb3d8bbwe\nMicrosoft.coreAppActivation_8wekyb3d8bbwe\nMicrosoft.delegatedWebFeatures_8wekyb3d8bbwe\nMicrosoft.deployFullTrustOnHost_8wekyb3d8bbwe\nmicrosoft.eSIMManagement_8wekyb3d8bbwe\nMicrosoft.firmwareRead_cw5n1h2txyewy\nMicrosoft.firmwareWrite_cw5n1h2txyewy\nMicrosoft.mixedRealityExperience_8wekyb3d8bbwe\nMicrosoft.nonUserConfigurableStartupTasks_8wekyb3d8bbwe\nMicrosoft.notSupportedInCoreV1_8wekyb3d8bbwe\nMicrosoft.onDemandHotspotControl_8wekyb3d8bbwe\nmicrosoft.penFreControl_8wekyb3d8bbwe\nMicrosoft.requiresNonSMode_8wekyb3d8bbwe\nmicrosoft.secondaryAuthenticationFactorForLogon_8wekyb3d8bbwe\nMicrosoft.unsignedPackageManagement_8wekyb3d8bbwe\nMicrosoft.windowsInkInputPreferences_8wekyb3d8bbwe\nmicrosoftEdgeRemoteDebugging\nmixedRealityEnvironmentInternal\nmmsTransportSystem\nmodifiableApp\nmsaExtension\nmultiplaneOverlay\nmuma\nmusicLibrary\nnetworkConnectionManagerProvisioning\nnetworkDataPlanProvisioning\nnetworkDataUsageManagement\nnetworkDeviceAdminSettings\nnetworkDeviceSettings\nnetworkDiagnostics\nnetworkingVpnProvider\nnfcSystem\nnotificationsDeviceSettings\nobjects3D\noemDeployment\noemPublicDirectory\nofflineMapsManagement\noneProcessVoIP\noptical\npacJsWorker\npackageContents\npackageManagement\npackagePolicySystem\npackageQuery\npackageWriteRedirectionCompatibilityShim\npackagedServices\nperceptionMonitoring\nperceptionSensorsExperimental\nperceptionSystem\npermissiveLearningMode\npersonalizationDeviceSettings\nphoneCall\nphoneCallHistory\nphoneCallHistoryPublic\nphoneCallHistorySystem\nphoneCallSystem\nphoneLineTransportManagement\npicturesLibrary\npointOfService\npolarisService\npolicyManager\npowerDeviceSettings\npreemptiveCamera\npreviewHfx\npreviewInkWorkspace\npreviewPenWorkspace\npreviewStore\npreviewUiComposition\nprivateNetworkClientServer\nprojectionDeviceSettings\nprotectedApp\nproximity\nradios\nrecordedCallsFolder\nregionSettings\nregistryRead\nrelatedPackages\nremoteAutomationHost\nremoteFileAccess\nremotePassportAuthentication\nremoteSystem\nremovableStorage\nresetPhone\nrunFullTrust\nscreenDuplication\nsearchSettings\nsecondaryAuthenticationFactor\nsecureAssessment\nSecurity-System-Capability-dateAndTimeDeviceSettings\nsensors.custom\nserialCommunication\nsessionImpersonation\nsettingSyncConfiguration\nsharedMachineKeysCapability\nsharedUserCertificates\nshellDisplayManagement\nshellexperience\nshellExperience\nshellExperienceComposer\nslapiQueryLicenseValue\nsmbios\nsms\nsmsSend\nsmsSystem\nsmsTransportSystem\nspatialPerception\nstartScreenManagement\nstoreAppInstall\nstoreAppInstallation\nstoreConfiguration\nstoreLicenseManagement\nstoreOptionalPackageInstallManagement\nsystemAllocWindowID\nsystemDialog\nsystemDialogEmergency\nsystemManagement\nsystemRegistrar\ntargetedContent\ntargetedContentSubscription\nteamEditionDeviceCredential\nteamEditionExperience\nteamEditionView\ntelemetryData\nterminalPowerManagement\nthumbnailCache\ntimezone\nuiAccess\nuiAutomationCrossMachineHostingSystem\nuiAutomationSystem\nunvirtualizedResources\nunzipFile\nupdateAndSecurityDeviceSettings\nusb\nuserAccountInformation\nuserDataAccountSetup\nuserDataAccountsProvider\nuserDataSystem\nuserDataTasks\nuserDataTasksSystem\nuserManagementSystem\nuserNotificationListener\nuserOnboardingState\nuserPrincipalName\nuserSigninSupport\nuserSystemId\nuserWebAccounts\nvideosLibrary\nvisualElementsSystem\nvisualVoiceMail\nvmWorkerProcess\nvoipCall\nwalletSystem\nwebcam\nwebPlatformMediaExtension\nwiFiControl\nwifiData\nwiFiDirect\nwindowInfo\nwindowManagement\nwindowManagementSystem\nwindowsHelloCredentialAccess\nwindowsPerformanceCounters\nxboxAccessoryManagement\nxboxBroadcaster\nxboxGameSpeechWindow\nxboxLiveAuthenticationProvider\nxboxSystemApplicationClipQuery\nxboxTrackingStream\n"
  },
  {
    "path": "SystemInformer/resources/etwguids.txt",
    "content": "[{\"guid\":\"{7708f1bf-4c89-56d2-4ee5-9e18af837488}\",\"name\":\"Microsoft.Windows.TextInput.InputPersonalizationTraceLogging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{62a96bde-f419-50a7-23f4-b9ba78881a06}\",\"name\":\"Microsoft.Windows.TextInput.MathInputControl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aa63597d-db0e-53d9-a7d4-e74d1f7773e2}\",\"name\":\"Microsoft.Windows.TextInput.MathInputPanel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{03b97ec5-9c5a-5ccd-0882-c3f87cd51384}\",\"name\":\"Microsoft.Windows.Handwriting\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{40e698dd-15d2-5653-ed34-a597f09fac89}\",\"name\":\"Microsoft.Windows.Shell.LanguageModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{68396f5f-e685-5c1b-3181-a17cf8d96fa6}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.TouchKeyboard\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b76620c0-b616-59bf-39fe-4d9638fd184b}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.TextInputCanvasUI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{864c5689-9310-594c-5cef-000695f5ace8}\",\"name\":\"Microsoft.Windows.TextInput.LinguisticData\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dcef5411-1f98-5ee7-238b-5abd0e078e97}\",\"name\":\"Microsoft.Windows.Wil.FeatureLogging\",\"group\":\"\"},{\"guid\":\"{1cee38b7-233d-443d-b5c2-1d9b3674acc1}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.TextInputCanvas\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2e9264c6-401d-5780-853d-cc4311f28aae}\",\"name\":\"Microsoft.Windows.TextInput.InkLinguisticData\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{87812a22-2691-5a06-ff07-cb6d09f9004d}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.HandwritingSkin\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ebadf775-48aa-4bf3-8f8e-ec68d113c98e}\",\"name\":\"TextInput\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4b896120-2811-50f6-c240-3594f81ff90a}\",\"name\":\"Microsoft.Windows.Msinfo32\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eb7ec0f6-7f9f-4c64-bc1a-68b6c934dec5}\",\"name\":\"Microsoft.Windows.AddressBook\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4f50731a-89cf-4782-b3e0-dce8c90476ba}\",\"name\":\"Microsoft.CRTProvider\",\"group\":\"\"},{\"guid\":\"{0bca4784-8257-51a0-d9ec-24fe1fe4c90d}\",\"name\":\"Microsoft.Windows.App.Browser\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d1b249d-131b-468a-899b-fb0ad9551772}\",\"name\":\"TelemetryAssert\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e0b47cf8-e776-4ea7-9ec0-93a85b9a7a2b}\",\"name\":\"TelemetryAssertDiagTrack\",\"group\":\"\"},{\"guid\":\"{7af898d7-7e0e-518d-5f96-b1e79239484c}\",\"name\":\"Microsoft.Windows.Defender\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{39bd9805-3945-4878-aecc-096a23369f68}\",\"name\":\"Microsoft.Windows.SmartScreen\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{65a1b6fc-4c24-59c9-e3f3-ad11ac510b41}\",\"name\":\"Microsoft.Windows.Sense.Client\",\"group\":\"5ecb0bac-b930-47f5-a8a4-e8253529edb7\"},{\"guid\":\"{1dc742c2-0e76-5490-e1b5-8ddb4982ff77}\",\"name\":\"Microsoft.Windows.Sense.SensorHub\",\"group\":\"c5a3a379-e5b9-43da-9175-509abfce2cc7\"},{\"guid\":\"{c60418cc-7e07-400f-ae3b-d521c5dbd96f}\",\"name\":\"Microsoft.Windows.Sense.GeneratedETW\",\"group\":\"d0b1a44b-5ab3-4ff2-bb52-c2bb980ef8f3\"},{\"guid\":\"{cb2ff72d-d4e4-585d-33f9-f3a395c40be7}\",\"name\":\"Microsoft.Windows.Sense.CyberEvents\",\"group\":\"541dae91-cc3c-5807-b064-c2561c16d7e8\"},{\"guid\":\"{b3861234-4273-58c5-545b-8b3611343471}\",\"name\":\"Microsoft.Windows.Sense.CyberEvents\",\"group\":\"\"},{\"guid\":\"{450bba94-53ce-54e6-d150-9636aceafb86}\",\"name\":\"Microsoft.Windows.Sense.SenseIR\",\"group\":\"\"},{\"guid\":\"{bf4c9654-66d1-5720-7b51-d2ae226735ea}\",\"name\":\"Microsoft.Windows.ErrorHandling.Fallback\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f68c769c-cc20-502e-aee3-115c2eda66f7}\",\"name\":\"Microsoft.Windows.Sense.CollectionEtw\",\"group\":\"d0b1a44b-5ab3-4ff2-bb52-c2bb980ef8f3\"},{\"guid\":\"{6c9fdb6b-76f8-49db-a55b-c6cf12878bc5}\",\"name\":\"Microsoft.Windows.AddressBook\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c1b40cda-b118-4f7f-965c-9b0e3bd72b3a}\",\"name\":\"Microsoft.Windows.Cast.Dlna\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{babcd444-98ea-4279-b6f9-5fa01ac7e009}\",\"name\":\"Microsoft.Windows.WordPad\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4e552c41-40cd-4877-9b60-f243f9a855ab}\",\"name\":\"Microsoft.AAD.BrowserCore.Provider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b6e66cc9-07ab-535f-034f-92ae45d13f3f}\",\"name\":\"Microsoft.Windows.WinOCR.TiffFilter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ad05f58e-fc71-40be-9f09-f258111ba160}\",\"name\":\"DISMCLI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{92cf4545-bb71-4511-a96f-53657f8fb8d9}\",\"name\":\"DismWimProviderDll\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{78267204-1ef8-4199-8e25-3b42000c4b23}\",\"name\":\"Microsoft-Windows-FileSystem-WOF\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4e1bb61e-4170-4220-bb86-fb7bbd3c204b}\",\"name\":\"Microsoft.EdgeUpdate\",\"group\":\"\"},{\"guid\":\"{55242983-b884-47e1-a16a-226ba19bf55b}\",\"name\":\"SkypeMediaVideoTraceProvider\",\"group\":\"\"},{\"guid\":\"{c9ba2a84-d3ca-5e19-2bd6-776a0910cb9d}\",\"name\":\"Microsoft.Windows.Console.VirtualTerminal.Parser\",\"group\":\"\"},{\"guid\":\"{cc0d0409-850f-57b1-83fe-8deb4e1fb60a}\",\"name\":\"XPerfAddIn.PerfNT\",\"group\":\"\"},{\"guid\":\"{a5b9c423-4c21-45c8-8de3-1a59f60d107a}\",\"name\":\"Microsoft.Windows.DebuggingTools.Imagehlp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f2e3b31b-57b4-5003-4059-470d58646da4}\",\"name\":\"Microsoft.Windows.DebuggingTools.DebuggerEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{18608e62-a628-49d9-8c02-55972e097d24}\",\"name\":\"Microsoft.Windows.Compatibility.Asl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{836d9d37-46c1-41be-a956-09b88f964468}\",\"name\":\"Microsoft.Windows.Inventory.Core\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fe0ab4b4-19b6-485b-89bb-60fd931fdd56}\",\"name\":\"Microsoft.Windows.AppxPackaging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{51da93e5-a669-4ac5-bd75-78c1e1541671}\",\"name\":\"Microsoft.Windows.AppxPackaging.PerfLogger\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{950d4eda-1729-47cc-8f1e-d9ed5aa17642}\",\"name\":\"Windows.Ui.Xaml\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{72d164bf-fd64-4b2b-87a0-62dbcec9ae2a}\",\"name\":\"AccEventTool\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{72d164bf-fd64-4b2b-87a0-62dbcec9ae2a}\",\"name\":\"InspectTool\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9401b890-ed5c-493d-8efd-3f135d7dd797}\",\"name\":\"Microsoft.Xbox.ConnectedStorage.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5ba5444a-228a-58bb-b6e2-c78adf23828c}\",\"name\":\"Microsoft.Windows.SshClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{219bc9ac-db43-505d-4dff-507d357163a1}\",\"name\":\"Microsoft.Windows.Ssh\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f9bc6c5d-4b98-43b5-90a1-1d0c8f45bf5a}\",\"name\":\"XamlDiagnosticsProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{059a2460-1077-115e-bdeb-5221de48b9e4}\",\"name\":\"Microsoft.Windows.DriverStore.DriverPackage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bb10f74f-9f91-4a2a-a811-bdd9afcbfa4a}\",\"name\":\"Microsoft.Windows.DebuggingTools.PlmDebug\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e02b8f11-ae89-4f4c-9217-f9e8c3de2a07}\",\"name\":\"Microsoft.Windows.DebuggingTools.JsProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6ab187b2-799c-4755-a18d-e3b8f8004fbd}\",\"name\":\"Microsoft.Windows.TestExecution.EtwProcessor\",\"group\":\"\"},{\"guid\":\"{70d27130-f2f3-4365-b790-d31223254ef4}\",\"name\":\"Microsoft.OSGENG.Testing.TaefEngine\",\"group\":\"\"},{\"guid\":\"{a920691d-5131-4f34-96bb-1bc9ef264d92}\",\"name\":\"Microsoft.Windows.TestExecution.WexCommon\",\"group\":\"\"},{\"guid\":\"{9464ac97-5473-4241-91ff-3862c43ebe02}\",\"name\":\"Microsoft.Windows.TestExecution.WexCommunication\",\"group\":\"\"},{\"guid\":\"{40c4df8b-00a9-5159-62bc-9bbc5ee78a29}\",\"name\":\"Microsoft.Windows.TestExecution.WexLogger\",\"group\":\"\"},{\"guid\":\"{d0d4f082-7b52-5786-e87b-4bd77db6fff4}\",\"name\":\"Microsoft.Windows.Kits.DeviceFundamentals\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{703fcc13-b66f-5868-ddd9-e2db7f381ffb}\",\"name\":\"Microsoft.Windows.TlgAggregateInternal\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{af2ae1c8-cf6d-4268-8159-fcce3c2e67db}\",\"name\":\"TelemetryAssertDiagTrack\",\"group\":\"\"},{\"guid\":\"{23b76a75-ce4f-56ef-f903-c3a2d6ae3f6b}\",\"name\":\"Microsoft.Windows.Kernel.BootEnvironment\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ddd9464f-84f5-4536-9f80-03e9d3254e5b}\",\"name\":\"MicrosoftWindowsCodeIntegrityTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2e1eb30a-c39f-453f-b25f-74e14862f946}\",\"name\":\"MicrosoftWindowsCodeIntegrityAuditTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f943a83b-cbf3-5eb0-8059-b327ffdf70a5}\",\"name\":\"Microsoft.Windows.Analog.NUI.SpeechMicDiagnostic\",\"group\":\"\"},{\"guid\":\"{df8dab3f-b1c9-58d3-2ea1-4c08592bb71b}\",\"name\":\"Microsoft.Windows.Shell.Taskbar\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0e6f34b3-0637-55ab-f0bb-8b8fa83eda04}\",\"name\":\"Microsoft-Windows-Shell-CortanaProactive\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5f1e1b94-a9fe-57d8-abe7-d29a6df9e967}\",\"name\":\"Microsoft.Windows.Shell.Explorer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2c00a440-76de-4fe3-856f-00557535be83}\",\"name\":\"Microsoft.Windows.Shell.ControlCenter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{69693006-d82b-5b8f-4cab-490d3ff14106}\",\"name\":\"Microsoft.Windows.Shell.Desktop.SoftLandingAnaheimPromotion\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9954158f-eaa7-5afe-b990-df3cce23483a}\",\"name\":\"Microsoft.Windows.Desktop.Shell.SoftLanding\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{653fe5bd-e1d2-5d40-d93c-a551a97cd49a}\",\"name\":\"Microsoft.Windows.Desktop.Shell.NotificationArea\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{82a0f3c6-c4dc-54fb-f358-354c5026dc61}\",\"name\":\"Microsoft.Windows.Shell.StateCapture\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4bfe0fde-99d6-5630-8a47-da7bfaefd876}\",\"name\":\"Microsoft.Windows.Shell.NotificationCenter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7ca6a4dd-dae5-5fb7-ec8e-4a6c648fadf9}\",\"name\":\"Microsoft.Windows.ShellPlacements\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3d6120a6-0986-51c4-213a-e2975903051d}\",\"name\":\"Microsoft-Windows-Shell-Launcher\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{273c19b2-6643-5a58-6288-c336d3688b8d}\",\"name\":\"Microsoft.Windows.ShellExperienceDispatcher\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ee97cdc4-b095-5c70-6e37-a541eb74c2b5}\",\"name\":\"Microsoft.Windows.AppLifeCycle.UI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{34d3fca3-41f2-4498-b7a0-58708572b583}\",\"name\":\"Microsoft.Windows.Shell.TileBadgeProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{753436f5-735d-41fa-b4b7-d68579ac5582}\",\"name\":\"Microsoft.Windows.Licensing.IUI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a51097ad-c000-5ea3-bbd4-863addaedd23}\",\"name\":\"Microsoft.Windows.Desktop.Shell.ImmersiveIcons\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5afb7971-45e5-4d49-aaeb-1b04d39872cf}\",\"name\":\"Microsoft.Windows.MobilityExperience\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8cba0f81-8ad7-5395-2125-5703822c822a}\",\"name\":\"Microsoft.Windows.ContentDeliveryManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{397b9505-a6ba-5951-46ee-84b08fb14812}\",\"name\":\"Microsoft.Windows.Desktop.Shell.OOBEHealth\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{04d28e21-00aa-5228-cfd0-d70863aa5ce9}\",\"name\":\"Microsoft.Windows.Shell.Desktop.LogonFramework\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8e12dcd2-fe15-5af4-2a6a-e707d9dc7de5}\",\"name\":\"MicrosoftWindowsFileExplorer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2de4263a-8b3d-5824-1c83-6182d50c5356}\",\"name\":\"Microsoft.Windows.Shell.Desktop.LogonAnaheimPromotion\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f168d2fa-5642-58bb-361e-127980c64a1b}\",\"name\":\"Microsoft.Windows.Shell.OpenWith\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{58b09b7d-fd44-5a27-101d-5d2472a7bb42}\",\"name\":\"Microsoft.Windows.Shell.PrivacyConsentLogging\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{ffe467f7-4f51-4061-82be-c2ed8946a961}\",\"name\":\"Microsoft.Windows.Shell.CoCreateInstanceAsSystem\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a0e768af-d257-40cd-be2b-d019ea50c1bd}\",\"name\":\"Microsoft.Windows.Help\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b7afa6af-aaab-4f50-b7dc-b61d4ddbe34f}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.SettingsAppActivity\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ef00584a-2655-462c-bc24-e7de630e7fbf}\",\"name\":\"Microsoft.Windows.AppLifeCycle\",\"group\":\"\"},{\"guid\":\"{7940d73d-d0fc-5959-d4fe-255caf4c8a64}\",\"name\":\"Microsoft.Windows.Shell.RadialControllerMenu\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{271aebf7-e83b-580f-7525-5e9563fe161a}\",\"name\":\"Microsoft.Windows.AppMan.AppV\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e29eb67a-714d-4d58-a598-46dee87e620b}\",\"name\":\"Microsoft.Notepad\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b0f40491-9ea6-5fd5-ccb1-0ec63be8b674}\",\"name\":\"Microsoft.Windows.Shell.PrintDialog\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{464163b4-a2f3-5bc9-cf0f-fc55f1cb3f0b}\",\"name\":\"WindowsInternal.ComposableShell.Experiences.TaskFlow.Timeline\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{65ca0ac0-98af-4642-bd0e-c22cce6d5a0c}\",\"name\":\"Microsoft.Windows.ComposableShell.Experiences.DragDrop\",\"group\":\"\"},{\"guid\":\"{c7a697f6-69bc-5777-297f-1c77b8189f1c}\",\"name\":\"Microsoft.Windows.Shell.Switcher\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2791965a-1f38-4bb1-8530-46e655b0faa2}\",\"name\":\"Microsoft.Windows.ShellExperienceHost.BatteryFlyoutTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{05dc16d6-5fe6-4b7f-8864-2b300d7f207a}\",\"name\":\"Microsoft.Windows.ShellExperienceHost.BatteryFlyout\",\"group\":\"\"},{\"guid\":\"{cbc427d6-f93e-5bcf-3137-d22fe2305d1f}\",\"name\":\"Microsoft.Windows.Shell.ClockCalendar\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9f30c07c-57ce-5ec3-bb5e-476dd25c2742}\",\"name\":\"Microsoft-Windows-DevicesFlowUI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dae4b0d4-cc23-508b-f041-48e5097a0907}\",\"name\":\"Microsoft.Windows.Shell.InputDialTrace\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{75aac4ae-65a6-5166-57c7-6fc29eb7753b}\",\"name\":\"Microsoft.Windows.Shell.Insights\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f6148764-178d-4a19-b984-14b90f352c9c}\",\"name\":\"Microsoft.Windows.Shell.JumpView\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9493aaa3-34b7-5b53-daf1-cb9b80c7e772}\",\"name\":\"Microsoft.Windows.Shell.DesktopUvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d9370a15-0e6a-4dcb-a475-35340cc49bf3}\",\"name\":\"MicrosoftWindowsNetworkFlyout\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{90bbbabb-255b-4fe3-a06f-685a15e93a4c}\",\"name\":\"NetworkUX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0adaf93d-4c15-502d-449a-9445aae0d781}\",\"name\":\"Microsoft.Windows.PlatformExtensions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{85d89d49-96bc-4d5f-a3e6-3a363687a137}\",\"name\":\"Microsoft.Windows.Shell.PenWorkspaceTrace\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c6ba71ae-668c-5a9b-94f5-b2026280198a}\",\"name\":\"Microsoft.Windows.Shell.PenWorkspace\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{723d94e4-de55-46d4-bf9a-9d0e98d95775}\",\"name\":\"Microsoft.Windows.Shell.PenWorkspaceMoveBelowLock\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b4c55a0d-b40e-4dc4-b2b7-51184e19a8e2}\",\"name\":\"Microsoft.Windows.Shell.PenWorkspaceError\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{22e1bc8f-7da8-54ff-598a-379d6400c0c8}\",\"name\":\"Microsoft.Windows.Shell.PenWorkspaceSession\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e31e40d6-25c0-5ca4-d1c7-6a1037cda4f6}\",\"name\":\"Microsoft.Windows.Shell.People\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{569cf830-214c-5629-79a8-4e9b58ea24bc}\",\"name\":\"Microsoft.Windows.Shell.ShareUX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c6ba71ae-658c-5a9b-94f5-b2026290198a}\",\"name\":\"Microsoft.Windows.Desktop.Shell.QuickActions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{10522462-4b7c-5a67-3863-c71dfc264c83}\",\"name\":\"Microsoft.Apps.QuickConnect.Relationships\",\"group\":\"\"},{\"guid\":\"{93efa482-84a2-5a52-520c-3adcf4aa635d}\",\"name\":\"Microsoft.Windows.Apps.People.ContactCardData\",\"group\":\"\"},{\"guid\":\"{1b5e76ec-566e-5d08-9dfc-5ac8602bb1b7}\",\"name\":\"Microsoft.Windows.Shell.QuickConnect\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a9848367-c9fe-5b01-861e-94d350d016c8}\",\"name\":\"Microsoft.Windows.Shell.ScreenClipping\",\"group\":\"\"},{\"guid\":\"{c8416d9b-12d3-41f8-9a4c-c8d7033f4d30}\",\"name\":\"Microsoft-Windows-Shell-Launcher-Curation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{baa05370-7451-48d2-8f38-778380946ce9}\",\"name\":\"Microsoft.Windows.SharedStartModel.NotificationQueueManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4690f625-1ceb-402e-acef-db8f00f3a446}\",\"name\":\"Microsoft.Windows.Shell.TileControl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ce410840-f2d5-57f0-0e4b-cb833a32be88}\",\"name\":\"Microsoft.Windows.Shell.VirtualTouchpad\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45b1da9d-13a2-5b76-0bc9-9b4b784afe6a}\",\"name\":\"Microsoft.People.PeoplePicker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{80da39c2-20e0-558e-d91d-985405faaf42}\",\"name\":\"Microsoft.Windows.Apps.Models.ContactList\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ec1d179a-2636-59d2-c915-370b8a31143a}\",\"name\":\"Microsoft.People.Relevance\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9eba02af-a8ad-508e-2a59-525c55d2f975}\",\"name\":\"Microsoft.People.Relevance.QueryClient\",\"group\":\"\"},{\"guid\":\"{e27b8548-e13c-4821-bea4-bf1268e14448}\",\"name\":\"Microsoft.Windows.Compression.DeltaPackageExpander\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{53cb6537-bec2-5efe-054f-12441f10155d}\",\"name\":\"Mitigation360Telemetry\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{6a5ccfd4-cf02-5640-0b5f-d2e031258f16}\",\"name\":\"Microsoft.Windows.UpdateReserveManager\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{057597df-6fd8-438b-bf6d-190cbf0a914c}\",\"name\":\"Microsoft.Windows.Storage.StorageReserve\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4aeee6ec-cefe-4c43-b460-909bd707260c}\",\"name\":\"Update360Telemetry\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{f41b08b4-f479-55ce-1ebc-ee7a3bb757c4}\",\"name\":\"Microsoft.Windows.CbsLite\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{696ac247-4e85-42e8-b0d2-fec2475c76ad}\",\"name\":\"AdvancedInstallerPlatform\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{146273bc-a4bd-4565-ab02-63eb97a7eb20}\",\"name\":\"Microsoft.AAD.AuthHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{74d91ec4-4680-40d2-a213-45e2d2b95f50}\",\"name\":\"Microsoft.AAD.CloudAp.Provider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{724a3824-7387-449a-825e-b135f2ca4c57}\",\"name\":\"Microsoft.Windows.Shell.AADJCSP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bfed9100-35d7-45d4-bfea-6c1d341d4c6b}\",\"name\":\"Microsoft.AAD.TokenBrokerPlugin.Provider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7b1ae42d-b4f2-414d-9c97-913f19049964}\",\"name\":\"Microsoft.AAD.WamExtension\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5487f421-e4de-41d4-bff3-72a4d6584898}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.SettingHandlersSystem\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1915117c-a61c-54d4-6548-56cac6dbfede}\",\"name\":\"Microsoft.Windows.Shell.AboveLockActivationManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e58f5f9c-3abb-5fc1-5ae5-dbe956bdbd33}\",\"name\":\"Microsoft.Windows.Shell.AboveLockShellComponent\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{65bd0639-95d9-4bc3-812a-0465a91bcb67}\",\"name\":\"Microsoft.Windows.Shell.EaseOfAccess\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{79c43bcd-08ea-5914-1e38-9e3008863a0c}\",\"name\":\"Microsoft.Windows.Settings.Accessibility\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fcc174d3-8890-434a-812d-bded72ede356}\",\"name\":\"Microsoft.Windows.Unistack.FailureTrigger\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7ac5eb71-3c51-5089-1b4e-87a46bd6b4df}\",\"name\":\"Microsoft.Windows.OneSync.DiagWarning\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{37ec0f35-026e-5e7e-d3d4-80f32547bfff}\",\"name\":\"Microsoft.Windows.OneSync.DiagError\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b738411f-062a-505a-9ab3-df11c892082c}\",\"name\":\"Microsoft.Windows.OneSync.DiagCritical\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3c74c337-f6a0-575c-d1d9-549cdb2a64c5}\",\"name\":\"Microsoft.Windows.OneSync.AccountsRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8d687d51-6bc8-4896-9628-5ca67550697e}\",\"name\":\"Microsoft.Windows.AppCompat.ASGShim\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eb65a492-86c0-406a-bace-9912d595bd69}\",\"name\":\"Microsoft.Windows.BackgroundManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ac01ece8-0b79-5cdb-9615-1b6a4c5fc871}\",\"name\":\"Microsoft.Windows.Application.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f5647876-050d-4cf0-ba2f-c498b41c152a}\",\"name\":\"Microsoft.Windows.AppCompat.CompatTab\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3e136d0e-beca-59e4-2ccc-010f2426947c}\",\"name\":\"Microsoft.Windows.ControlPanel.HealthCenter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{88bcd62d-f7ae-45b7-b578-4bf2b8ab867b}\",\"name\":\"Microsoft-Windows-Shell-CortanaTrace\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cf7f94b3-08dc-5257-422f-497d7dc86ab3}\",\"name\":\"ActivationManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5526aed1-f6e5-5896-cbf0-27d9f59b6be7}\",\"name\":\"Microsoft.Windows.ApplicationModel.DesktopAppx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{afa71204-ca19-516e-3b0b-97016857d3d7}\",\"name\":\"Microsoft.Windows.OneSync.ActiveSyncEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bc44ffcd-964b-5b85-8662-0ba87edaf07a}\",\"name\":\"Microsoft.Windows.PerfLib\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b3e1c8a5-2552-4cfb-90ab-03d44f7e217c}\",\"name\":\"Microsoft.Windows.AgentActivationRuntime.AgentInfo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{07807c21-adcc-4884-a34d-3623c990f229}\",\"name\":\"Microsoft.Windows.AgentActivationRuntime.Settings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e4dda0af-d7b4-5d40-4174-4d0be05ae338}\",\"name\":\"Microsoft.Windows.AppMan.UEV\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{86d873db-e2ff-5de7-cbb1-92581b4e70a1}\",\"name\":\"Microsoft.Windows.AllJoyn.RouterService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7a01e7fb-b6a4-4585-b1a8-ea2094ecb4c5}\",\"name\":\"Microsoft.Antimalware.Scan.Interface\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{042ea214-830c-5979-86f5-28fd92c80f30}\",\"name\":\"Microsoft.Windows.OneSync.DiagTrace\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d853cf0f-d9fa-55f6-d916-2b3dbbae132a}\",\"name\":\"Microsoft.Windows.DynamicApi.Data\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e73d49d6-9eda-5059-74d1-b879b18cf9ae}\",\"name\":\"Microsoft.Windows.Print.APMon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bc2dab59-ac78-487a-903e-db3c343c0be3}\",\"name\":\"Microsoft.Windows.Print.WSDMon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6fb61ac3-3455-4da4-8313-c1a855ee64c5}\",\"name\":\"Microsoft.Windows.Print.IppMon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{acf1e4a7-9241-4fbf-9555-c27638434f8d}\",\"name\":\"Microsoft.Windows.Print.IppCommon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{49868e3d-77fb-5083-9e09-61e3f37e0309}\",\"name\":\"Microsoft.Windows.Print.HttpRest\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{44050ea2-419d-5526-923b-b038e0f1e715}\",\"name\":\"Microsoft.Windows.Print.CloudPrintHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fbfbd628-251d-551d-c4dd-c7820af723e4}\",\"name\":\"Microsoft.Windows.Print.IppAdapterCommon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6184bc1f-417e-4443-bcce-9f65bf844aa7}\",\"name\":\"Microsoft.Windows.Print.IppConfigConverter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8ccca27d-f1d8-4dda-b5dd-339aee937731}\",\"name\":\"Microsoft.Windows.Compatibility.Apphelp\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{40dbe1ab-6f3b-57cf-ee15-a1f3b1370ec6}\",\"name\":\"Microsoft.Windows.Compatibility.Encapsulation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0bc7f044-74be-445d-82e4-65c087118975}\",\"name\":\"Microsoft.Windows.AppModel.AppUriHandlerRegistrationVerifier\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{77fe4532-3f5c-5786-632b-fb3201bce29b}\",\"name\":\"Microsoft.Windows.Security.AppIdLogger\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c4588082-5072-4d81-bb2e-575950eaf2cb}\",\"name\":\"Microsoft.Windows.Security.AppIDSvcProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{be928fd4-50ba-57ca-b6b8-925dab19c3bf}\",\"name\":\"Microsoft.Windows.Security.LUA\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1c0ce30f-122d-5a39-2bef-b176b05d65e2}\",\"name\":\"Microsoft.Windows.Security.DeviceGuard\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{678e492b-5de1-50c5-7219-ae4aa7d6a141}\",\"name\":\"Microsoft-Windows-Desktop-ApplicationFrame\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{639c1a81-14a8-55bf-bb3f-800c3fa0581b}\",\"name\":\"Microsoft.Windows.Desktop.Shell.AppClosingTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b997e40d-0880-4ed6-b7df-84df3305fe2b}\",\"name\":\"Microsoft.Windows.Security.AppLockerCSP\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{cf84da43-f447-42de-ad48-4feeea03247d}\",\"name\":\"Microsoft.Windows.Security.EDPPolicyMgrApplockerTask\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fe762fb1-341a-4dd4-b399-be1868b3d918}\",\"name\":\"Microsoft.Windows.AppXDeploymentServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aa1b41d3-d193-4660-9b47-dd701ba55841}\",\"name\":\"Microsoft.Windows.AppxDeploymentFallback\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{746622e1-9381-4507-be68-2e6b55f81070}\",\"name\":\"Microsoft.Windows.StateRepository.Core\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{551ff9b3-0b7e-4408-b008-0068c8da2ff1}\",\"name\":\"Microsoft.Windows.StateRepository.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{582c6a21-f5b4-4e52-b592-0e8229bf1737}\",\"name\":\"Microsoft.Windows.AppMan.Shared.Logging\",\"group\":\"\"},{\"guid\":\"{a94f431e-5460-465f-bf2e-6245b56d6ce9}\",\"name\":\"Microsoft.Windows.UserDataAccess.AppointmentApis\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0a0a7808-8dda-4ba0-a656-b2c740ab9108}\",\"name\":\"Microsoft.Windows.UserDataAccess.UserDataApisBase\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{03a70c9d-084b-4905-b341-f6377e734858}\",\"name\":\"Microsoft.Windows.Appraiser.Instrumentation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dd17fa14-cda6-7191-9b61-37a28f7a10da}\",\"name\":\"Microsoft.Windows.Appraiser.General\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45d5ccd7-6e27-4318-82dd-69bd83a8f672}\",\"name\":\"Microsoft.Windows.Inventory.Indicators\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{71032084-57e9-4b2f-b367-28801de960ab}\",\"name\":\"PackageInfo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c567e5d7-a908-49c0-8c2c-a8dc3e8f0cf6}\",\"name\":\"Microsoft.Windows.ARS.Tiles\",\"group\":\"\"},{\"guid\":\"{39ddcb8d-ef82-5c84-89ca-09580bf0a947}\",\"name\":\"Microsoft-Windows-Shell-AppResolver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bc6a63f5-2da6-5394-8657-e7b5efad1315}\",\"name\":\"Microsoft.FamilySafety.Monitor\",\"group\":\"5ecb0bac-b930-47f5-a8a4-e8253529edb7\"},{\"guid\":\"{02db1e80-8296-5d13-91b2-3d6bdf0bc162}\",\"name\":\"Microsoft.FamilySafety\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d8f29c0d-526c-5148-2167-9be755ad812d}\",\"name\":\"Microsoft.FamilySafety.Dev\",\"group\":\"\"},{\"guid\":\"{6ecb0bf3-c4d3-52e5-81df-704c4a8686ac}\",\"name\":\"Microsoft.Windows.FamilySafety.Reliability\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{509d9518-eae5-4c53-ae47-271ba6b7ef53}\",\"name\":\"Microsoft.Windows.Memory\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{635d9d84-4106-4f3a-a5c2-7fda784ae6fc}\",\"name\":\"Microsoft.Windows.CpuTrigger\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c38b082f-bb3b-4eff-a29e-421194554038}\",\"name\":\"Microsoft.Windows.DiskTrigger\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f8d370cb-a3c9-54e9-c9cd-8cc49964a8f6}\",\"name\":\"Microsoft.Windows.Shell.AddRemovePrograms\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4dab1c21-6842-4376-b7aa-6629aa5e0d2c}\",\"name\":\"Microsoft.Windows.AppXAllUserStore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b89fa39d-0d71-41c6-ba55-effb40eb2098}\",\"name\":\"Microsoft.Windows.AppXDeploymentClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d9e5f8fb-06b1-4796-8fa8-abb07f4fc662}\",\"name\":\"Microsoft.Windows.AppXDeploymentExtensions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{67b0f5f8-7f9b-4716-b314-954df536e966}\",\"name\":\"Microsoft.Windows.Print.AppMon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{71eb58e7-a040-4c3d-9577-2d1c3289a065}\",\"name\":\"Microsoft.Windows.Shell.CentennialDefaultAssoc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a66a8706-ae1e-4a26-a15b-27d924c43063}\",\"name\":\"Microsoft.Windows.BackgroundAccessManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eee2c45d-a762-4930-a1ca-bb07f7bd10b6}\",\"name\":\"Microsoft.Windows.Networking.ModernApps.LoopbackAccess\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{98ccaad9-6464-48d7-9a66-c13718226668}\",\"name\":\"Microsoft.Windows.AppModel.Tiles\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f9f7f27c-5e5d-5273-468f-038e61965660}\",\"name\":\"Microsoft.Windows.AssignedAccess.Csp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{94097d3d-2a5a-5b8a-cdbd-194dd2e51a00}\",\"name\":\"Microsoft.Windows.AssignedAccess\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{355d4f62-3d5b-5372-213f-6d9d804c75df}\",\"name\":\"Microsoft.Windows.AssignedAccess.MdmAlert\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{72d164bf-fd64-4b2b-87a0-62dbcec9ae2a}\",\"name\":\"Microsoft.Windows.Narrator.Asimov\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{64788b34-e8e5-5664-af50-45afb294a1dc}\",\"name\":\"Microsoft.Windows.Audio.DeviceGraph\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2c2677bd-bc9a-5a88-4772-6f17de82b2c7}\",\"name\":\"Microsoft.Windows.Audio.AudioEngineUtil\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d375f14e-9624-5a18-f53e-5bce2043a97f}\",\"name\":\"Microsoft.Windows.Audio.CrossProcess\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9ac9593a-8e9e-5c4c-6407-43c56769851b}\",\"name\":\"Microsoft.Windows.Audio.Spatial.CrossProcess\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0e7e8596-d648-5c94-adbd-3d780faa58e8}\",\"name\":\"Microsoft.Windows.Audio.EndpointBuilder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ec6ede49-f40f-5f93-8651-a4edc18afe06}\",\"name\":\"Microsoft.Windows.Audio.EndpointCharacteristics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c9f9ecd3-6d24-46d8-b23f-37b53fa6447b}\",\"name\":\"Microsoft.Windows.Audio.Spatial.Metadata\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{030fa765-f1ae-448e-955b-44d76073e1dc}\",\"name\":\"Microsoft.Windows.Audio.License\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b223e190-8559-5089-47f7-282d429805fe}\",\"name\":\"Microsoft.Windows.AudioUnderstanding.Capture\",\"group\":\"\"},{\"guid\":\"{46df03df-beab-5f0b-7eb2-e471c1bea993}\",\"name\":\"Microsoft.Windows.Audio.Engine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3b11f303-2e4f-4856-9a63-1de8c1baebfb}\",\"name\":\"Microsoft.Windows.Audio.Spatial.Renderer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8d37b4a3-2c54-560f-7b2e-b992d023682a}\",\"name\":\"Microsoft.Windows.Audio.Pump\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{53cc8a8b-3182-5101-7405-8dfc7e5f313e}\",\"name\":\"Microsoft.Windows.MediaFoundation.CallStack\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fccfb92c-645c-56b2-6bc8-f58018445737}\",\"name\":\"Microsoft.Windows.Audio.AcousticEchoCancellation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f16d809a-f345-5246-a9ce-c530856782b9}\",\"name\":\"Microsoft.Windows.Analog.NUI.Audio\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{90492ff4-7bb3-5781-5bd5-7ba3e09568a7}\",\"name\":\"Microsoft.Windows.Audio.Processor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9d01d40c-b008-4770-a0ef-14d91395a423}\",\"name\":\"Microsoft.Windows.Media.Settings.Audio\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f0d933d3-6ff1-4de9-8f8d-7a4142c8faf9}\",\"name\":\"Microsoft.Windows.SystemSettings.AudioSettingsHandlers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{553ca39b-c608-566d-18ae-7b9a03a39acd}\",\"name\":\"Microsoft.Windows.Audio.KernelStreamingEndpoint\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6e7b1892-5288-5fe5-8f34-e3b0dc671fd2}\",\"name\":\"Microsoft.Windows.Audio.Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{767166e4-869c-5cc7-4f54-b13d12274111}\",\"name\":\"Microsoft.Windows.Audio.PolicyConfig\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f286958a-866b-4cb4-b442-bbe01acb0d30}\",\"name\":\"Microsoft.Windows.Audio.LoopbackMixer\",\"group\":\"\"},{\"guid\":\"{3d2b6366-47a4-5e10-6974-e5f7de0d3f28}\",\"name\":\"Microsoft.Windows.Audio.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2266b8d6-11dd-5bfe-d5f2-067e37b194b8}\",\"name\":\"Microsoft.Windows.Audio.Spatial.ResourceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9dd93434-0865-5629-c753-70c27ff40dc7}\",\"name\":\"Microsoft.Windows.Audio.Service.PolicyManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b1a37fe6-6431-56aa-33fd-cdb90c3b695e}\",\"name\":\"Microsoft.Windows.Security.WebAuth\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c3859e38-9269-4a33-af9c-bc7082c62930}\",\"name\":\"Microsoft.Windows.Shell.WebAuthBridge\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9a7b2945-e29a-5477-e857-794ae72a85d9}\",\"name\":\"Microsoft.Windows.AuthExt\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5a43f100-b5f3-53bf-6291-035b4f51f2f8}\",\"name\":\"Microsoft.Windows.Desktop.Shell.Authentication.AuthUI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8db3086d-116f-5bed-cfd5-9afda80d28ea}\",\"name\":\"Microsoft.OSG.OSS.CredProvFramework\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a3a38aaa-2521-4849-9b65-ae781b455984}\",\"name\":\"Microsoft.Windows.FileSystem.Chkdsk\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{31dbfd53-87c6-4370-afb0-7263cd9a49a8}\",\"name\":\"Microsoft.Windows.AutoTime.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{06ee5c69-51c7-5ebe-0c8f-a049cc071d3f}\",\"name\":\"Microsoft.Windows.BackupAndRoaming.AzureWilProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{885735da-efa7-4042-b9bc-195bdfa8b7e7}\",\"name\":\"Microsoft.Windows.BackupAndRoaming.AzureSyncEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{95ea8eb8-6f34-45bc-8fa3-bafeaf6c9915}\",\"name\":\"Microsoft.Windows.BackupAndRoaming.SyncEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{49b5ed52-d5a9-47a6-9bfb-4c6c6aa200ce}\",\"name\":\"Microsoft.Windows.BackupAndRoaming.Diagnostics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3c1be35c-79fd-55ec-2d51-2d7b19e1d377}\",\"name\":\"Microsoft.Windows.BackupAndRoaming.WilProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f0372af2-cc46-56c0-2bb9-db2e31b2423d}\",\"name\":\"Microsoft.Windows.Audio.BackgroundAudioPolicy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4efe0d37-de22-547a-8e83-cecf39daf889}\",\"name\":\"Microsoft.Windows.Provisioning.Plugin.Barcode\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ab74fbe2-37ef-48c4-b9ba-91ae7804a0b7}\",\"name\":\"Microsoft.Windows.Media.Capture\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b518d5bd-106c-4f6f-9b2f-1972f5968bdd}\",\"name\":\"Microsoft.Windows.Media.Capture.AppCaptureMetadataWriter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b2235af2-251a-4d6e-beb0-db27bd29eb45}\",\"name\":\"Microsoft.Windows.BcastDVR\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c77b0b58-fac1-5614-4523-86a46166ab49}\",\"name\":\"Microsoft.Windows.BootFileServicing\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{932a397d-97ed-50f9-29ab-051457f7af3e}\",\"name\":\"Microsoft.Windows.Desktop.LanguageBCP47\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f3a71a4b-6118-4257-8ccb-39a33ba059d4}\",\"name\":\"Microsoft.Windows.Security.BCrypt\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c106be38-921e-4100-880a-4a3b41b1c95f}\",\"name\":\"Microsoft.Windows.Security.BitLocker.CSP.State.Update\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1aa8a014-a347-4bdf-b21a-593f2ab62de8}\",\"name\":\"Microsoft.Windows.Security.BitLocker.EncryptionDelay\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{497abd62-6fdf-46c9-a972-9d68cb71c335}\",\"name\":\"Microsoft.Windows.Security.BitLocker.BcdUpdate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2c801909-d66e-4ae6-abb5-c92e19681aab}\",\"name\":\"BdeSvcTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5899bc23-6d04-4919-a3a3-5611c4dad2ab}\",\"name\":\"Microsoft.Windows.Security.BitLocker.KeyRolling.Engine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{00a85728-5a3d-4b9e-b24b-9a14cce5f322}\",\"name\":\"FveEnableLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ae48220d-cfeb-46dc-9d61-0b01e8ed0058}\",\"name\":\"Microsoft.Windows.Networking.BFE.SubLayer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{698b9d1f-e09e-4e7c-b97d-647bc6969bf2}\",\"name\":\"Microsoft.Windows.Networking.BFE.Provider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ec75076d-5e9c-4448-83f8-57870e2e7a6d}\",\"name\":\"Microsoft.Windows.Networking.BFE.Filter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f53a23be-ea7d-54ac-d7ab-dd541e945ae8}\",\"name\":\"Microsoft.Windows.Networking.BFE.Rundown\",\"group\":\"\"},{\"guid\":\"{db909c62-75e6-5440-fa0d-c303473cb35f}\",\"name\":\"Microsoft.Windows.Networking.BFE\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{386c9353-4a64-4fec-b360-7d832d775cde}\",\"name\":\"Microsoft.Windows.Shell.MTF.BingAutoSuggestionDS.Aggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d40c54dc-b476-53e2-5456-13d838d243e9}\",\"name\":\"Microsoft.Windows.Shell.MTF.BingAutoSuggestionDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{44ce5c1c-1693-4997-b700-ca1b696e4b54}\",\"name\":\"Microsoft.Windows.Shell.MTF.BingAutoSuggestionDS.Perf\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a1b5139a-6ff8-5136-90bb-d1ce46943037}\",\"name\":\"Microsoft.Windows.Shell.MTF.BingFilterDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5c027701-c399-4141-8899-2dc7acb56cec}\",\"name\":\"Microsoft.Windows.Shell.MTF.BingFilterDS.Aggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b9be465b-1e6b-5741-ccc8-74c6f96944c7}\",\"name\":\"Microsoft.Windows.Maps.Services.Copyright\",\"group\":\"\"},{\"guid\":\"{9dadd79b-d556-53f2-67c4-129fa62b7512}\",\"name\":\"Microsoft.Windows.Security.Biometrics.BioCredProv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9df19cfa-e122-5343-284b-f3945ccd65b2}\",\"name\":\"Microsoft.Windows.Security.Biometrics.Trustlet\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63b6c2d2-0440-44de-a674-aa51a251b123}\",\"name\":\"Microsoft.Windows.BrokerInfrastructure\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ecd5374a-5fd1-4fed-9f53-e38d4897abd4}\",\"name\":\"Microsoft.Windows.BackgroundManagerAggregated\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{42f0d420-f794-4d69-9369-6fd2387e157e}\",\"name\":\"Microsoft.Windows.BitLocker.CSPProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dbd4a8cd-17a1-46a1-9ec8-ce9e6d253a97}\",\"name\":\"Microsoft.Windows.RecEnv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cf00ce14-243a-572e-b740-b27009b128e3}\",\"name\":\"Microsoft.Windows.StartRepairCore\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{a2c85772-f6bc-5e43-7aeb-2f7db8a80b7f}\",\"name\":\"Microsoft.Windows.Kernel.BootTools\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6966fe51-e224-4baa-99bc-897b3ed3b823}\",\"name\":\"Microsoft.Windows.BrokerBase\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5e3f60ef-a60f-45a9-84ae-e224f761baa3}\",\"name\":\"Microsoft.Windows.HVSI.Manager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1d571ab7-c34d-41c5-b141-42d76317c7c5}\",\"name\":\"Microsoft.Windows.Bluetooth.Hfp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d951cb3f-2cba-4a1c-9436-6cf2e904dde8}\",\"name\":\"Microsoft.Windows.Bluetooth\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4e415226-9161-583e-161b-f0798225ff40}\",\"name\":\"Microsoft.Windows.WpdMtp.BthMtpContextHandler\",\"group\":\"\"},{\"guid\":\"{b2f2a380-149b-4a35-8016-cfe4a5a9b893}\",\"name\":\"MicrosoftWindowsNetworkLegacyUX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ed7432ee-0f83-5083-030b-39f66ba307c5}\",\"name\":\"Microsoft.Windows.Desktop.ScreenSaver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0905ca09-610e-401e-b650-2f212980b9e0}\",\"name\":\"MicrosoftCalculator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6990d440-4050-4975-8007-c166ddd0941d}\",\"name\":\"Microsoft.Windows.Bluetooth.CallControl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c50f8ea2-c7bb-5c95-164e-bb7f9cad095a}\",\"name\":\"Microsoft.Windows.CapabilityAccessManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{237b580a-2421-5bc2-1ac0-36f148384fa8}\",\"name\":\"Microsoft-Windows-Cast-Launcher\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e0be2aaa-b6c3-5f17-4e86-1cde27b51ac1}\",\"name\":\"Microsoft.Windows.ClipboardHistory.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a29339ad-b137-486c-a8f3-88c9738e5379}\",\"name\":\"Microsoft.Windows.ApplicationModel.DataTransfer.CloudClipboard\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3bbf44c9-f0b7-4f46-977b-b4536ca99b8d}\",\"name\":\"Microsoft.Windows.ApplicationModel.DataTransfer.CloudClipboard.Aggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ed6842ae-0e4b-4fd5-9a6a-1206dc8810f7}\",\"name\":\"Microsoft.Windows.ApplicationModel.DataTransfer.DataPackageSerializer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8aa41f62-e9cd-4291-bae1-94daa9a3ac26}\",\"name\":\"Microsoft.Windows.Graphics.Cdd\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dfa6e32a-095f-5f57-d025-0887d33507a1}\",\"name\":\"Microsoft.Windows.CDP.CDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5fe36556-c4cd-509a-8c3e-2a547ea568ae}\",\"name\":\"Microsoft.Windows.CDP.AFS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bc1826c8-369c-5b0b-4cd1-3c6ae5bfe2e7}\",\"name\":\"Microsoft.Windows.CDP.Aggr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9f4cc6dc-1bab-5772-0c71-a89954718d66}\",\"name\":\"Microsoft.Windows.CDP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{abb10a7f-67b4-480c-8834-8b049c428715}\",\"name\":\"Microsoft.Windows.CDP.Core\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a1ea5efc-402e-5285-3898-22a5acce1b76}\",\"name\":\"Microsoft.Windows.CDP.Core.Error\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a48e7274-bb8f-520d-7e6f-1737e9d68491}\",\"name\":\"Microsoft.Windows.System.RemoteSystem\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d229987f-edc3-5274-26bf-82be01d6d97e}\",\"name\":\"Microsoft.Windows.System.RemoteSystemSession\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{633383cb-d7a9-4964-876a-66b7dc98c0fe}\",\"name\":\"Microsoft.Windows.RemoteSystems.CDPRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{833e7812-d1e2-5172-66fd-4dd4b255a3bb}\",\"name\":\"Microsoft.Windows.ApplicationModel.UserActivities\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f06690ca-9325-5dcf-65bc-fc3164fa8acc}\",\"name\":\"Microsoft.Windows.Application.NearSharePlatform\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4a16abff-346d-56dc-fa87-eb1e29fe670a}\",\"name\":\"Microsoft.Windows.CDP.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{30ad9f59-ec19-54b2-4bdf-76dbfc7404a6}\",\"name\":\"Microsoft.Windows.CDP.Session\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ed1640e7-9dc0-45b5-a1ef-88b70cf1742c}\",\"name\":\"Microsoft.Windows.CDP.UserService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{41d006be-1a11-4121-a0eb-0ea2ae688044}\",\"name\":\"Microsoft.Windows.Cellcore.Cellularapinew\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{412f73f7-ebf9-466f-90e7-606accdbcd15}\",\"name\":\"Microsoft.Windows.UserDataAccess.Cemapi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7d265c9d-2276-4606-95f0-fd113c05065e}\",\"name\":\"Microsoft.Windows.Security.CertEnroll\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{483804c3-f8a7-5d61-bf21-2de8db1a4e53}\",\"name\":\"Microsoft.Windows.Security.SmartCards.CertPropSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e0d3ce46-1e48-42aa-a5e3-d0f18ec9a48b}\",\"name\":\"Microsoft.Windows.CellCore.Provisioning\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{02ad713f-20d4-414f-89d0-da5a6f3470a9}\",\"name\":\"Microsoft.Windows.Security.CFL.API\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fc7ba620-eb50-483d-97a0-72d8268a14b5}\",\"name\":\"Microsoft.Web.Platform.Chakra\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9b3000b4-3fa3-44ec-91b4-8903c331543e}\",\"name\":\"Microsoft.Windows.Licensing.ChangePK\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8fe8ebd4-0f51-5f91-9481-cd2cfefdf96e}\",\"name\":\"Microsoft.Windows.Desktop.Shell.Charmap\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e0a18f5c-07f3-4a44-b149-0f8f13ef6887}\",\"name\":\"Microsoft.Windows.ApplicationModel.Chat.ChatMessageBlocking\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6fdfa2fd-23c7-5152-1a51-618729d0e93d}\",\"name\":\"Microsoft.Windows.FileSystem.CloudFiles\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ce790967-ff23-464c-a976-1389674e3972}\",\"name\":\"Microsoft.Windows.CleanupMgr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3970f9cd-2c0c-4f11-b1cc-e3a1e9958833}\",\"name\":\"CleanPCCSPTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{28d62fb0-2131-41d6-84e8-e2325867964c}\",\"name\":\"Microsoft.Windows.AppModel.Clipboard\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ed0c10a5-5396-4a96-9ee3-6f4aa0d1120d}\",\"name\":\"Microsoft.ClipC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{466f3b39-9929-45e6-b891-d867bd20b738}\",\"name\":\"Microsoft.Windows.Licensing.UpgradeSubscription\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b94d76c5-9d56-454a-8d1b-6ca30898160e}\",\"name\":\"Microsoft.ClipSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cfbea673-bf20-4bd8-b595-29b82d43df39}\",\"name\":\"Microsoft.ClipUp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4266a3c6-72dc-4e46-8e7c-5a91a55b93b1}\",\"name\":\"Microsoft.Windows.Licensing.ClipWinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7fad10b2-2f44-5bb2-1fd5-65d92f9c7290}\",\"name\":\"Microsoft.Windows.Security.CloudAp.Critical\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bb8dd8e5-3650-5ca7-4fea-46f75f152414}\",\"name\":\"Microsoft.Windows.Security.CloudAp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aa02d1a4-72d8-5f50-d425-7402ea09253a}\",\"name\":\"Microsoft.Windows.Shell.CloudDomainJoin.Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8999952b-d9ca-491c-ab5b-6ad70835f0f2}\",\"name\":\"Microsoft.Windows.Shell.UnifiedEnrollment.Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5e586678-8171-5406-e113-c6fbd31535db}\",\"name\":\"Microsoft.Windows.Shell.CloudExperienceHostClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{99eb7b56-f3c6-558c-b9f6-09a33abb4c83}\",\"name\":\"Microsoft.Windows.Shell.CloudExperienceHost.Common\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2dbd0b99-c886-5c44-9fc2-7220ddf5aaf6}\",\"name\":\"Microsoft.Windows.Shell.ScalingCompat\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{05f02597-fe85-4e67-8542-69567ab8fd4f}\",\"name\":\"MSAClientTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f385e1a5-0346-5411-11a2-e8c8afe3b6ca}\",\"name\":\"Microsoft.Windows.Desktop.Shell.CloudExperienceHostSpeech\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ff91e668-f7be-577e-14a3-44d801cccfa0}\",\"name\":\"Microsoft.Windows.Shell.CloudExperienceHostCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3122168f-2432-45f0-b91c-3af363c14999}\",\"name\":\"ClusApiTraceLogProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3c94ea80-4530-40be-9b66-a79d8f60aa9b}\",\"name\":\"Microsoft.Windows.COM.ComTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1aff6089-e863-4d36-bdfd-3581f07440be}\",\"name\":\"CombaseTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c7e09e2a-c663-5399-af79-2fccd321d19a}\",\"name\":\"Microsoft.Windows.Com.PoFAggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f0558438-f56a-5987-47da-040ca75aef05}\",\"name\":\"Microsoft.Windows.WinRTClassActivation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dc749491-822a-4043-9789-2c68d3a477d9}\",\"name\":\"Microsoft.Windows.COM.MetadataBasedMarshaler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1fc037f9-b857-5bd2-cbd2-4d8c01b0d9d8}\",\"name\":\"Microsoft.Windows.Shell.CommonPrintDialog\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cc459d2f-f4bd-4e6c-901e-08bea752a7d3}\",\"name\":\"Microsoft.Windows.ComposableShell.Framework.Composer\",\"group\":\"\"},{\"guid\":\"{4cde77ee-0109-57d3-e6f0-86365c0cfdb3}\",\"name\":\"Microsoft.Windows.ComposableShell.Framework.Composer.DragDrop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{80ce50de-d264-4581-950d-abadeee0d340}\",\"name\":\"Microsoft.Windows.HyperV.Compute\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{86625c04-72e1-4d36-9c86-ca142fd0a946}\",\"name\":\"Microsoft.Windows.DeviceManagement.OmaDmApiProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f3b5bc3c-a182-4f7d-806d-070012d8d16d}\",\"name\":\"Microsoft.Windows.DeviceManagement.SessionManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0ec685cd-64e4-4375-92ad-4086b6af5f1d}\",\"name\":\"Microsoft.Windows.DeviceManagement.OmaDmClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{797c5746-634f-4c59-8ae9-93f900670dcc}\",\"name\":\"Microsoft.Windows.DeviceManagement.OMADMPRC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6b865228-defa-455a-9e25-27d71e8fe5fa}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.ResourceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6222f3f1-237e-4b0f-8d12-c20072d42197}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.ResourceManagerUnenrollHook\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e1a8d70d-11f0-420e-a170-29c6b686342d}\",\"name\":\"Microsoft.Windows.DeviceManagement.DmAccCsp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fe5a93cc-0b38-424a-83b0-3c3fe2acb8c9}\",\"name\":\"Microsoft.Windows.DeviceManagement.DevInfo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f5123688-4272-436c-afe1-f8dfa7ab39a8}\",\"name\":\"Microsoft.Windows.DeviceManagement.DevDetailCsp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{33466aa0-09a2-4c47-9b7b-1b8a4dc3a9c9}\",\"name\":\"Microsoft-Windows-DeviceManagement-W7NodeProcessor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f058515f-dbb8-4c0d-9e21-a6bc2c422eab}\",\"name\":\"Microsoft.Windows.DeviceManagement.SecurityPolicyCsp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5afba129-d6b7-4a6f-8fc0-b92ec134c86c}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.DeclaredConfiguration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ffdb0cfd-833c-4f16-ad3f-ec4be3cc1af5}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.PolicyManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{76fa08a3-6807-48db-855d-2c12702630ef}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.ConfigManagerHook\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0ba3fb88-9af5-4d80-b3b3-a94ac136b6c5}\",\"name\":\"Microsoft.Windows.DeviceManagement.ConfigManager2\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e74efd1a-b62d-4b83-ab00-66f4a166a2d3}\",\"name\":\"Microsoft.Windows.EMPS.Enrollment\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f9e3b648-9af1-4dc3-9a8e-bf42c0fbce9a}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.Enrollment\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c15421a9-1a99-474e-9e1b-f16ac98e173d}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.Dynamo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63bf67fd-7d57-4dea-987f-f26d1ed62691}\",\"name\":\"Microsoft.Windows.DeviceManagement.MDMWinsOverGPDictionary\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fe1ff234-1f09-50a8-d38d-c44fab43e818}\",\"name\":\"Microsoft.Windows.Console.Host\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{770aa552-671a-5e97-579b-151709ec0dbd}\",\"name\":\"Microsoft.Windows.Console.Launcher\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c9ba2a95-d3ca-5e19-2bd6-776a0910cb9d}\",\"name\":\"Microsoft.Windows.Console.Render.VtEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{de73b5e0-ebd8-5bf1-5f0a-eb2613358e9b}\",\"name\":\"Microsoft.Windows.PlatformExtensions.ConsentExperienceCommon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4ed93eb9-c197-582f-ada9-4939ec475c92}\",\"name\":\"Microsoft.Windows.DeviceConsentUX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6cb6fe45-2c1c-5d4c-b440-ff7aefe9f457}\",\"name\":\"Microsoft.Windows.ConsentUx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e34441d9-5bcf-4958-b787-3bf824f362d7}\",\"name\":\"Microsoft.Windows.Shell.CortanaSearch\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3f7fafe6-1dd2-4720-b75b-e3268a0e6120}\",\"name\":\"Microsoft.Windows.UserDataAccess.ContactApis\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6ee5d800-84e9-5917-a448-dcf4cb6096d8}\",\"name\":\"Microsoft.Windows.Shell.MTF.ContactHarvesterDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{67eb0417-9297-42ae-a1d9-98bfeb359059}\",\"name\":\"Microsoft.Windows.Containers.Library\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fd1c8ea7-81fb-5865-0291-2226d3c883ca}\",\"name\":\"Microsoft.Windows.ContentDeliveryManager.Utils.UnlockActionHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fadd8651-7b42-423f-b37d-3b98b9e81560}\",\"name\":\"Microsoft.Windows.DeviceManagement.SyncMLDpu\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{18f2ab69-92b9-47e4-b9db-b4ac2e4c7115}\",\"name\":\"Microsoft.Windows.DeviceManagement.WAPDpu\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{48dcc4b8-1a33-4625-b042-95ce02602863}\",\"name\":\"Microsoft.Windows.ComposableShell.CoreShell\",\"group\":\"\"},{\"guid\":\"{07f43d42-ac34-545b-338d-b5fde66f440d}\",\"name\":\"Microsoft.Windows.Shell.ProjectionManager.DisplayPickerHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5e282e7b-2134-4e30-a089-218cf7ddc553}\",\"name\":\"Microsoft.Windows.ComposableShell.Framework.CoreShellAPI.TerminalManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2c4c4cfc-bd5f-5171-3607-c54987b8e0a3}\",\"name\":\"Microsoft.Windows.ComposableShell.SessionManagement.Session\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0c8ef845-83f1-4a15-9988-6e1630db4d32}\",\"name\":\"Microsoft.Windows.ComposableShell.Core.CoreShellExtFramework\",\"group\":\"\"},{\"guid\":\"{3720dda7-caea-4af3-a138-375aafc3f1d6}\",\"name\":\"Microsoft.Windows.CoreUIComponents\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3fc749d8-ca25-5de0-2ca5-2fbd6c3612cb}\",\"name\":\"CortanaPersona\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8e6931a7-4c49-5fb7-a500-65b951d7652f}\",\"name\":\"Microsoft.Windows.Shell.CortanaPersonality\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1aea69ee-2cfc-5eb1-f1f6-18f99a528b11}\",\"name\":\"Microsoft-Windows-Shell-Cortana-IntentExtraction\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d221a3b-e981-4e91-ae7c-f1de3e7746ee}\",\"name\":\"Microsoft.Windows.Fundamentals.Partner.SystemInitiatedUserFeedback\",\"group\":\"5ecb0bac-b930-47f5-a8a4-e8253529edb7\"},{\"guid\":\"{ee818f02-698c-48be-8ff2-326c6dd34db1}\",\"name\":\"Microsoft.Windows.Fundamentals.SystemInitiatedUserFeedback\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{290437a7-8178-4f08-a567-583ced6a1d8a}\",\"name\":\"Microsoft.Windows.Fundamentals.UserInitiatedFeedback\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bd59a9a8-cafb-4503-845e-d85fb72ae2e1}\",\"name\":\"WindowsFlightingSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3bb1472f-46dc-5a12-4916-25706f703352}\",\"name\":\"Microsoft.Windows.CredDialogBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d30325be-5b5e-508c-d76a-2d5e5fe60a5c}\",\"name\":\"Microsoft.Windows.CredentialEnrollmentManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4c88af3d-5d47-458a-8624-515c122b7188}\",\"name\":\"Microsoft.Windows.OneCoreUap.Shell.Auth.CredUX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{55f422c8-0aa0-529d-95f5-8e69b6a29c98}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.SignInOptionsPage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{462a094c-fc89-4378-b250-de552c6872fd}\",\"name\":\"Microsoft.Windows.Shell.Auth.CredUIBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d9f478bb-0f85-4e9b-ae0c-9343f302f9ad}\",\"name\":\"Microsoft.Windows.Security.Cred2FAHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fb3cd94d-95ef-5a73-b35c-6c78451095ef}\",\"name\":\"Microsoft.Windows.CredProvDataModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a181320d-0993-4510-aece-690ff14512c2}\",\"name\":\"Microsoft.Windows.Security.CredHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f8523a36-f90b-553f-3dfa-5b84da6dae96}\",\"name\":\"Microsoft.Windows.Security.CandidateAccountManagerPolicy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dc3b5bcf-bf7b-42ce-803c-71af48f0f546}\",\"name\":\"Microsoft.Windows.CredProviders.PasswordProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3c430b0a-397a-4e1d-9a83-9c388405c00c}\",\"name\":\"Microsoft.Windows.Security.Certificates\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d7051a0-9c83-5e52-cf8f-0ecaf5d5f6fd}\",\"name\":\"Microsoft.Windows.Security.NGC.CryptNgc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{786396cd-2ff3-53d3-d1ca-43e41d9fb73b}\",\"name\":\"Microsoft.Windows.Security.CryptoWinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d4211df0-de55-11e4-be84-0024e814a5e2}\",\"name\":\"Microsoft.Windows.OfflineFiles\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{24241768-581f-4239-9994-ed874701a2f5}\",\"name\":\"CustomInstall\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b5a9b1f0-a9cb-41c8-87bd-e5878c6bf66d}\",\"name\":\"Microsoft.Windows.Security.CX.CredProv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7067398c-bae7-4191-bf16-c436de658baf}\",\"name\":\"Microsoft.Windows.Graphics.Direct2D\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{923330f1-00dc-4e4a-9cab-1dfb0af719f7}\",\"name\":\"Microsoft.Windows.Graphics.D3D10\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d704adfe-95cc-44f0-b98f-bb72677e55a9}\",\"name\":\"Microsoft.Windows.Graphics.D3D10Level9\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2f50c5d0-e25e-4f89-ab4a-31c63b518d7a}\",\"name\":\"Microsoft.Windows.Graphics.D3D12WARP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{77ab313b-93da-4aa5-a20f-9339ff5ae1e3}\",\"name\":\"Microsoft.Windows.Graphics.D3D10_1\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{86cc27ea-6f87-47f7-8b43-3473527d4a87}\",\"name\":\"Microsoft.Windows.Graphics.D3D11\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a0ab5aac-e0a4-4f10-83c6-31939c604fd9}\",\"name\":\"Microsoft.Windows.Graphics.D3D11On12\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ba8f81e9-adce-5d41-51df-bcc78df51081}\",\"name\":\"Microsoft.Windows.Graphics.D3D11SDKLayers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1f132a04-5c61-573f-d2ed-35a7e77c281c}\",\"name\":\"Microsoft.Windows.Graphics.D3D12Dred\",\"group\":\"\"},{\"guid\":\"{82fe78cc-ff52-4e2f-a7bb-5c90636d14ba}\",\"name\":\"Microsoft.Windows.Graphics.D3D12\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2fa581f7-7d27-5e1a-cd42-2f823376482d}\",\"name\":\"Microsoft.Windows.Graphics.D3D12SDKLayers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{125e88d9-1d91-5dd1-fbdf-34c1e67c00da}\",\"name\":\"Microsoft.Windows.Graphics.DirectXDatabaseHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b0f726cb-ca9c-4c11-b5b4-8c65aae214e9}\",\"name\":\"Microsoft.Windows.Graphics.D3D9\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c0c418c5-1f3c-4ee0-93a2-a0bb8f417f9a}\",\"name\":\"Microsoft.Windows.Graphics.D3D9ON12\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{88924b19-f26c-47b9-9539-cda8aa93c643}\",\"name\":\"MicrosoftWindowsShellVanNetworkUx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{714239f2-e296-5ae6-73e1-d44774265044}\",\"name\":\"Microsoft.Windows.Networking.Docking\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d5ca4bb-df8e-41bc-b554-8aeab241f206}\",\"name\":\"Microsoft.Windows.Print.DafIpp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bf3eac2a-65ca-5ecc-2076-e23c6420a687}\",\"name\":\"Microsoft.Windows.Print.DAFMCP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3c27a357-a925-4040-87e4-82e74ef8731e}\",\"name\":\"Microsoft.IoT.POS.DafProvider\",\"group\":\"\"},{\"guid\":\"{9f6d9c99-619c-4a03-80de-1172fbdb147e}\",\"name\":\"Microsoft.Windows.Print.DafProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{30965aee-2a17-4c9e-b1f0-7b0a0df530bb}\",\"name\":\"Microsoft.Windows.UPnP.DafProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e0636723-7994-4285-87bb-fa682a87531f}\",\"name\":\"Microsoft.Windows.WiProv.DafProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e4d412ab-4c22-49ef-83ca-eafb90768512}\",\"name\":\"Microsoft.Windows.WSD.DafProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6e146863-2aae-5fe7-89e0-a17ffae83a14}\",\"name\":\"Microsoft.Windows.WSD.WFD\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0879871c-e412-4c6a-87a6-74581b0afac5}\",\"name\":\"MicrosoftWindowsShellNetworkUX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ab4d9355-341e-435d-b3d2-4b0e46354e2c}\",\"name\":\"Microsoft.Windows.Das\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2383d505-afdd-4705-85c6-ceb91179929c}\",\"name\":\"Microsoft.Windows.DataExchange\",\"group\":\"\"},{\"guid\":\"{21f26f8c-36e3-4f01-8b35-3c1bd45c69b8}\",\"name\":\"Microsoft.Windows.DataExchange.DragDrop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ea893635-5ab7-562b-75a2-a22107d8058f}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.DataUsageHandlers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{94d6de7d-513b-5ebe-9cba-1faf26f6fda6}\",\"name\":\"Microsoft.Windows.OneSync.WebDavEngineProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9efcb348-d13c-4b3a-8ab1-869aab424c34}\",\"name\":\"Microsoft.Windows.Inventory.General\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{262cde7a-5c84-46cf-9420-94963791ef69}\",\"name\":\"Census\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b142eb8c-3426-11e7-b687-92ebcb67fe33}\",\"name\":\"FveDetectTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fb7fcbc6-7156-5a5b-eabd-0be47b14f453}\",\"name\":\"Microsoft.Windows.ApiTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5fb75eac-9f0b-550c-339f-fc21fde966cd}\",\"name\":\"InputCore\",\"group\":\"\"},{\"guid\":\"{93112de2-0aa3-4ed7-91e3-4264555220c1}\",\"name\":\"Microsoft.Windows.Dwm.DComp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a2fb673d-d90b-49f3-96e6-30d9babb7d31}\",\"name\":\"Microsoft.Windows.DeviceDirectoryClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a18828ed-9e14-598a-427d-23725d46ed04}\",\"name\":\"Microsoft.Windows.Shell.MTF.DynamicDictionaryDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a5ccf697-9bcd-4cb8-8083-be8facaf4280}\",\"name\":\"Microsoft.Windows.Shell.MTF.ContactDDDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f57021fb-b93d-59ba-4807-03397f6e89c3}\",\"name\":\"Microsoft-Windows-Graphics-DDisplay\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d479cbb9-0cf0-494c-b98f-684c33849782}\",\"name\":\"Microsoft.Windows.Graphics.DDRAW\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9f7780a0-cc4f-4bbd-b888-1c4c2ff78280}\",\"name\":\"Microsoft.Windows.Storage.Defrag\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aed4297d-5aa8-43ff-843d-a3a20672d9ae}\",\"name\":\"Microsoft.Windows.Deployment.OptionalFeaturesCSP\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{22111816-32de-5f2f-7260-2e7c4a7899ce}\",\"name\":\"Microsoft.Windows.Shell.Personalization.CSP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{451ceb17-c9c0-596d-78a3-df866a3867fb}\",\"name\":\"Microsoft.Windows.Desktop.DesktopShellHostExtensions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7123e686-8e52-5dd4-0313-ba3e74213984}\",\"name\":\"Microsoft.Windows.Holographic.DesktopView\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{60d6e217-d25b-504f-83d5-c2deb6a854e5}\",\"name\":\"Microsoft.Windows.Holographic.MixedRealityMode\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6cd9d548-4f28-5e7c-503d-86e3cd9db63d}\",\"name\":\"Microsoft.Windows.DeveloperPlatform.DeveloperOptions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8a36782f-4949-4980-ba6e-acadf0fe679a}\",\"name\":\"Microsoft.Windows.DeviceBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a5247bf8-45ad-554e-afdf-994fedf2ddef}\",\"name\":\"Microsoft.Windows.Shell.DeviceCenter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{78983c7d-917f-58da-e8d4-f393decf4ec0}\",\"name\":\"Microsoft.Windows.Security.DevCredClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{86d5fe65-0564-4618-b90b-e146049debf4}\",\"name\":\"Microsoft.Windows.Security.DevCredTask\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6e7d2591-6d94-5b84-02a1-c74c54de1719}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.MDMPush\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c280a7fd-e32e-4594-a073-c29658bea931}\",\"name\":\"Microsoft.Windows.DeviceManagement.CDNDownloader\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9d8f910a-17c3-5c99-d7ad-87f5021fb160}\",\"name\":\"Microsoft.Windows.Shell.ProximityConnect\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7955d36a-450b-5e2a-a079-95876bca450a}\",\"name\":\"Microsoft.Windows.Security.DevCredProv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a5247bf8-45ad-554e-afdf-994fedf2ddef}\",\"name\":\"Microsoft.Windows.Shell.DevicePairing\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ab11a476-79f6-5026-7d54-2e9b9e539a2d}\",\"name\":\"Microsoft.Windows.DeviceSetupManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{80a3bcff-2f89-4e33-aa39-73930ccba351}\",\"name\":\"Microsoft-Windows-DevicesFlowBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d7abca3e-b535-5d3d-1bd8-c958d320602e}\",\"name\":\"Microsoft-Windows-DevicesFlow-Connection\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cc8e3f7b-79a5-574c-19e3-84daa421645e}\",\"name\":\"Microsoft.Windows.Update.DeviceUpdateAgent\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{6a529040-a3b6-4b87-ad33-85793de42c95}\",\"name\":\"Microsoft.Windows.DeviceUpdateCenter.Csp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2e5950b2-1f5d-4a52-8d1f-4e656c915f57}\",\"name\":\"Microsoft.Windows.PNP.DeviceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{15a7a4f8-0072-4eab-abab-f98a4d666aed}\",\"name\":\"Microsoft.Windows.Networking.DHCP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3440e16d-c661-5dca-d41d-b05c08b0efbb}\",\"name\":\"Microsoft.Windows.Networking.DHCPv6\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{19d9d739-da0a-41a0-b97f-24ed27abc9fb}\",\"name\":\"Microsoft.DHD1\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0a3e80a6-75a7-53ab-12ad-e29648d69fb4}\",\"name\":\"Microsoft.DHD1.SequencedEventProcessor\",\"group\":\"\"},{\"guid\":\"{0504eb02-3a16-54e4-a2ff-3d85fa2f13e6}\",\"name\":\"Microsoft.Windows.Analog.HolographicDriverClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{092da0c3-6935-5a0c-4034-d9bddce5708f}\",\"name\":\"Microsoft.Windows.Analog.HolographicDriverClientContinuous\",\"group\":\"\"},{\"guid\":\"{fce08599-28a6-4874-9d54-3aa8ed5412fa}\",\"name\":\"Microsoft.System.Diagnostics.DiagnosticInvoker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45fcedc4-fdf6-4915-a7ed-985855bba40f}\",\"name\":\"Microsoft.Windows.DeviceManagement.DiagnosticLogCSP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{16c6ba99-2310-4237-9250-02eada41ceab}\",\"name\":\"Microsoft.DiagSvc.Engine.Telemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{319fdc69-a626-5289-be4d-1f508a8c9a3b}\",\"name\":\"Microsoft.Windows.Utc.WatchdogProvider\",\"group\":\"\"},{\"guid\":\"{1b9d8490-0675-4a63-8733-ba2a2ed24827}\",\"name\":\"Microsoft.Windows.TelemetryViewer\",\"group\":\"\"},{\"guid\":\"{306bbad7-3eab-4f5d-91ca-cf42d7699c2c}\",\"name\":\"Microsoft.Windows.Utc.ManagedHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{43ac453b-97cd-4b51-4376-db7c9bb963ac}\",\"name\":\"Microsoft.Windows.DiagTrack\",\"group\":\"\"},{\"guid\":\"{da995380-18dc-5612-a0db-161c5db2c2c1}\",\"name\":\"Microsoft.Windows.DiagTrack.XML\",\"group\":\"\"},{\"guid\":\"{dbf307fb-02e9-4935-b062-f63f05d58dc8}\",\"name\":\"Microsoft.Windows.Sentinels\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1f930301-f484-4e01-a8a7-264354c4b8e3}\",\"name\":\"Microsoft.Windows.Cast.Dial\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c31e3c2c-0867-5334-34af-93b3dfdee3b8}\",\"name\":\"Microsoft-Windows-Shell-DictationTrace\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9b89baa4-0253-5e71-26d5-182a4e690463}\",\"name\":\"Microsoft.Windows.TextInput.DictationManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{292ce2f8-099a-5710-ef2e-18921c50346f}\",\"name\":\"Microsoft.Windows.Analog.Speech\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63ec1c5f-7672-4db1-9db0-98a4531cc134}\",\"name\":\"Microsoft.Windows.DirectInput8\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b731656c-8c57-47c0-b21e-63c341841e3f}\",\"name\":\"Microsoft.Windows.AI.MachineLearning.Dml\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{21c69d00-5ac3-5d7a-fc1f-0bf37cbce500}\",\"name\":\"Microsoft.Windows.Graphics.DirectXDatabaseUpdater\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4d460463-66bc-45f5-9ed5-84ed88f15cdb}\",\"name\":\"Microsoft.Windows.Storage.DataIntegrityScan\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ead10f56-e9d4-4b29-a44f-c97299de5088}\",\"name\":\"Microsoft.Windows.Storage.DiskRaid\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{115e5164-6bc3-49f7-ab99-a91d6a4c9cee}\",\"name\":\"Microsoft.Windows.DiskSnapshot\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e1acab4c-f008-48de-965b-a2f1bd9e1fe0}\",\"name\":\"Microsoft.Windows.Dism.AppxProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{393f5655-4cba-40fd-9c19-1910b6965d01}\",\"name\":\"Microsoft.Windows.Sysprep\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b3854706-6d90-58a4-415d-d86cd54f35f5}\",\"name\":\"Microsoft-Windows-DispBroker-Desktop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9b6a7fe4-d8bc-503d-c1db-142892d7da9b}\",\"name\":\"Microsoft-Windows-DispBroker-DesktopSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d188b459-c26b-40ef-8ecc-009cc0ed6ed6}\",\"name\":\"Microsoft.Windows.Graphics.WindowsColorSystemGammaDiagnostics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2b1bbe78-bf8d-57c1-007a-e8628f64e8b3}\",\"name\":\"Microsoft-Windows-DispBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a3c04083-ce38-52ef-617f-a04362490425}\",\"name\":\"Microsoft.Windows.Shell.DesktopDisplaySettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7d76b731-d927-5737-81c5-ae3d3733c0ab}\",\"name\":\"OneCoreDisplayManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1d6a5020-c697-53bf-0f85-ae99be728db3}\",\"name\":\"Microsoft.Windows.Shell.Display\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e74efd1a-b62d-4b83-ab00-66f4a166a2d3}\",\"name\":\"Microsoft.EMPS.Enrollment\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d5a5b540-c580-4dee-8bb4-185e34aa00c5}\",\"name\":\"Microsoft.Windows.DeviceManagement.SCEP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d749112a-a5cf-4a2b-86b3-6abb29edd8e2}\",\"name\":\"Microsoft.Windows.Fundamentals.SiufDeployMgrClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0a8e17fd-ed19-4c54-a1e7-5a2829bf507f}\",\"name\":\"Microsoft.Windows.DeviceManagement.DmCmnUtils\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{12a9c970-7843-482a-9c1b-fd39d4f3533a}\",\"name\":\"Microsoft.Windows.HVSI.PolicyEvaluator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ff036693-0480-41dd-ac12-ed3c6a936a5f}\",\"name\":\"Microsoft.Windows.DeviceManagement.OmaCpClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{83afaf72-df00-4584-8f4c-aded166f72b1}\",\"name\":\"Microsoft.Windows.DeviceManagement.PushRouterProxy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{455fefe7-5b3d-485a-bcbb-d0f09a47d1ae}\",\"name\":\"Microsoft.Windows.DeviceManagement.PushRouterAuth\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0e316aa7-3b31-4d58-9b8b-10b3b2c0f2ed}\",\"name\":\"Microsoft.Windows.DeviceManagement.PushRouterCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a109a7c6-d975-46cc-b593-2b079b604e34}\",\"name\":\"Microsoft.Windows.DeviceManagement.ConfigManager2LockService\",\"group\":\"\"},{\"guid\":\"{ead10f56-e9d4-4b29-a44f-c97299de5086}\",\"name\":\"Microsoft.Windows.Storage.DiskManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8cc7d9c9-09af-45ca-86ce-4cecf680f2b7}\",\"name\":\"Microsoft-Windows-DeviceManagement-DmSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c37bb754-dc5c-45ad-9d00-a42cfcf137a8}\",\"name\":\"Microsoft.Windows.DeviceManagement.WmiCsp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9ca335ed-c0a6-4b4d-b084-9c9b5143aff0}\",\"name\":\"Microsoft.Windows.Networking.DNS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e0c75de2-8263-595f-cd27-04f99c135a45}\",\"name\":\"Microsoft-Windows-DockingControllerHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5828b13b-49ca-4017-9455-7e6c0c36eb6a}\",\"name\":\"Microsoft.Windows.MediaFoundation.DolbyAtmosDecoder\",\"group\":\"\"},{\"guid\":\"{cb729f91-4e9b-4698-a6c6-587faa6eaf4a}\",\"name\":\"Microsoft.Windows.Audio.DapEncoder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d1f8b4f-1d23-4f48-89fb-fb76e1be10bd}\",\"name\":\"Microsoft.Windows.Audio.MatEncoder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8933ec62-e2b1-449f-ab2e-9e8688b847fb}\",\"name\":\"domgmt\",\"group\":\"\"},{\"guid\":\"{efb251e4-d454-4a02-b126-7fbb9d3991c3}\",\"name\":\"dosvc\",\"group\":\"\"},{\"guid\":\"{f13cd440-a9b2-4d51-8b09-62dc6ad60194}\",\"name\":\"Microsoft.OSG.DU.DeliveryOptClient\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{9d2a53b2-1411-5c1c-d88c-f2bf057645bb}\",\"name\":\"Microsoft.Windows.Security.Dpapi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{27c42567-1daf-5166-7339-ea10942a0aa1}\",\"name\":\"Microsoft.Windows.PlatformExtensions.DragDropExperienceCommon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8e7bbeca-b5bb-5d8a-7089-1d2af3085cdc}\",\"name\":\"Microsoft.Windows.PlatformExtensions.DragDropExperienceDataExchange\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c42bbfdb-4140-4ada-81df-2b9a18ac6a7b}\",\"name\":\"Microsoft.Windows.Kernel.Acpi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{153db56c-64b0-50c1-7d97-8fe95de8bf45}\",\"name\":\"Microsoft.Windows.Kernel.Acpi.IrqArb\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aa3a221d-9a6f-4cf9-904e-897100ce8915}\",\"name\":\"Microsoft-Windows-AFD\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f3909f63-e473-4db7-b0f3-458b80b23843}\",\"name\":\"Microsoft.Windows.Socket.Afunix\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6895c41e-e36b-4a72-8ba3-df3255d17a55}\",\"name\":\"Microsoft.Windows.Processor.Driver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d82215e3-bddf-54fa-895b-685099453b1c}\",\"name\":\"Microsoft.Windows.BackgroundActivityModerator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bdf49c6c-ed22-442b-bf90-68cdd1808e2e}\",\"name\":\"Microsoft.Windows.Battery\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c3dc72b1-b3d9-4ca0-a066-d35241eeabbb}\",\"name\":\"Brcm\",\"group\":\"\"},{\"guid\":\"{8776ad1e-5022-4451-a566-f47e708b9075}\",\"name\":\"Microsoft.Windows.Bluetooth.BthA2dp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a8dd90af-85f0-40b1-b022-4f54961e8ae5}\",\"name\":\"Microsoft.Windows.Bluetooth.BthPort\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{07785021-a524-4ded-8137-8ab5c9390fa8}\",\"name\":\"TelemetryAssertDiagTrack_KM\",\"group\":\"\"},{\"guid\":\"{4caad201-c882-42c1-ae13-5408e834517b}\",\"name\":\"Microsoft.Windows.Power.CAD\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{592fd58a-ad33-4288-bf88-fb9039d9e391}\",\"name\":\"Microsoft-Windows-FileSystem-Cdfs\",\"group\":\"\"},{\"guid\":\"{29043218-3029-4be2-a6c1-b6763cecb3cc}\",\"name\":\"EventAggregation\",\"group\":\"\"},{\"guid\":\"{5590bf8b-9781-5d78-961f-5bb8b21fbaf6}\",\"name\":\"Microsoft.Windows.Storage.Classpnp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b4b126de-32fe-4591-9ac5-b0778d79a0e7}\",\"name\":\"Microsoft.ClipSp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cf38994b-91c9-4583-aca1-b5638ac732c4}\",\"name\":\"Microsoft.Windows.CmBatt\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{af2114e4-cb29-4a94-b24b-6a27bb43ed83}\",\"name\":\"Microsoft.Windows.Storage.Crashdmp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{60ae66d1-1c8c-5461-5284-fe74dd01096e}\",\"name\":\"Microsoft.Windows.DesktopActivityModerator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8cebf433-4842-449e-9fa0-99c6b14a7126}\",\"name\":\"Microsoft.Windows.Storage.SDBus\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8d8551e8-55df-4f9e-b8cc-c6ee1653f004}\",\"name\":\"Microsoft.Windows.Graphics.DriverDiagnosticsProgressions\",\"group\":\"\"},{\"guid\":\"{8d8551e7-55df-4f9e-b8cc-c6ee1653f004}\",\"name\":\"Microsoft.Windows.Graphics.DriverDiagnosticsNotifications\",\"group\":\"\"},{\"guid\":\"{deb96c0a-d2d9-5868-a5d5-50ee13513c8b}\",\"name\":\"Microsoft.Windows.Graphics.Display\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{221d444c-d07e-4fde-b425-15b746cf535b}\",\"name\":\"Microsoft.Windows.Graphics.DxgDiagnostics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c6998471-62cd-424d-a9a3-fe4c1fa378a4}\",\"name\":\"DxgKrnlTelemetry\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{705511ba-c1e6-41aa-8c36-daff03852409}\",\"name\":\"Microsoft.Windows.FileSystem.Exfat\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7a688f0e-f39b-4a7a-bbbb-066e2c1fcb04}\",\"name\":\"Microsoft.Windows.Security.EFS.EfsLib\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7b3b9d0a-ac64-4cbd-b658-e1ec8b4cb416}\",\"name\":\"Microsoft.Windows.EFS.EFSRPC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3d1d28b1-73f5-5937-3446-0de4df173ff5}\",\"name\":\"Microsoft.Windows.EDP.Enforcement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ced8d3d1-c760-49a7-a709-0de39da17de8}\",\"name\":\"Microsoft.Windows.FileSystem.Fat\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fd66a680-c052-4375-8cc9-225f923cef88}\",\"name\":\"Microsoft.Windows.FileSystem.FltMgr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1491f89f-c57d-4135-8e05-76f0f68124a8}\",\"name\":\"FveVolTraceLogProvKM\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{19aa5291-c1aa-4f3c-b0d5-1126f1faf3a5}\",\"name\":\"Microsoft.Windows.Networking.WFP.Kernel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{653880c0-4e64-56c1-5503-c1a609292702}\",\"name\":\"Microsoft.Windows.Audio.HdAudBus\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0575a639-1f8c-510e-8aaa-0af5e54229ab}\",\"name\":\"Microsoft.Windows.Bluetooth.HidBth\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b2a2afc4-fd0b-5a85-9eef-0ce26805cb02}\",\"name\":\"Microsoft.Windows.Input.HidClass\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b7651cf4-92fb-5e12-fd62-6dffda250e97}\",\"name\":\"Microsoft.Windows.Input.HidI2c\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bb34a62f-9160-4ae7-8d17-311006d248c9}\",\"name\":\"Microsoft.Windows.Input.HidSpi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eb16899e-ae38-517e-294d-b82dc8a04c74}\",\"name\":\"Microsoft.Windows.Input.HidUsb\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b1945e15-4933-460f-8103-aa611ddb663a}\",\"name\":\"Microsoft.OSG.Web.HTTPSys\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4f542162-e9cf-5eca-7f74-1fb63a59a6c2}\",\"name\":\"Microsoft.Windows.HyperV.GuestCrashDump\",\"group\":\"\"},{\"guid\":\"{6c5f119b-5b29-46a7-8e4a-282f8d935ae6}\",\"name\":\"Microsoft.Windows.HyperV.Hypervisor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f1c134a0-5523-5865-1aff-b9f82e911cc3}\",\"name\":\"Microsoft.Windows.HyperV.Hypervisor.Diagnostics\",\"group\":\"\"},{\"guid\":\"{b2ed3bdb-cd74-5b2c-f660-85079ca074b3}\",\"name\":\"Microsoft.Windows.HyperV.Socket\",\"group\":\"\"},{\"guid\":\"{ddb15654-924f-42de-8be1-2f8bf4946be1}\",\"name\":\"Microsoft.Windows.I8042Port\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9b82887e-0d74-4a2e-85ff-521f93c9d4a0}\",\"name\":\"IntelPepTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fa93663e-d1d9-5e9c-24a0-c2040a13062f}\",\"name\":\"Microsoft.Windows.IoRate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{084aa0de-35a2-57d4-21db-48c0514ca3ef}\",\"name\":\"Microsoft.Windows.Input.KbdClass\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{05fa9b62-4be5-4911-a12b-1303aa9c3a81}\",\"name\":\"Microsoft.Windows.Input.KbdHid\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dac64ab5-e0b2-46aa-9835-0ebd68f57024}\",\"name\":\"Microsoft.Windows.Net.ImsBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5bc69579-c5e2-4bc8-9a9b-b2795c6b9cbb}\",\"name\":\"Microsoft.Windows.Security.KsecSspi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a868cf57-6875-4ef9-8b42-c3cb590ca756}\",\"name\":\"Microsoft.Windows.Compatibility.Luafv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4f12d26c-64f3-5126-9306-3f16cbe62046}\",\"name\":\"mausbhost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{31463556-e3f6-4ddb-9ece-7bf5b8339c6f}\",\"name\":\"Microsoft.Windows.CellCore.MobileBroadband.WMBClass\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d6172801-3486-5dba-460b-73564ed30393}\",\"name\":\"Microsoft.Windows.Input.MouClass\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ee5c44b7-501a-5f89-a347-6629cb302a5f}\",\"name\":\"Microsoft.Windows.SMB.MRXSMB\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{52134415-75c1-4df9-9118-8b2bd00cc6e2}\",\"name\":\"Microsoft.Windows.SMB.MRXSMB20\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e2cdbc57-b2a5-570a-969b-ef80adc0b915}\",\"name\":\"Microsoft.Windows.Sec.Driver\",\"group\":\"5ecb0bac-b930-47f5-a8a4-e8253529edb7\"},{\"guid\":\"{cdead503-17f5-4a3e-b7ae-df8cc2902eb9}\",\"name\":\"Microsoft.Windows.NDIS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{11c5d8ad-756a-42c2-8087-eb1b4a72a846}\",\"name\":\"Microsoft-Windows-NdisImPlatformEventProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d1f8046b-db4e-48e1-a7a7-d5e03537e8e8}\",\"name\":\"Microsoft.Windows.RemoteAccess.Ndproxy\",\"group\":\"\"},{\"guid\":\"{828a1d06-71b8-5fc5-b237-28ae6aeac7c4}\",\"name\":\"Microsoft.Windows.Ndis.NetAdapterCx\",\"group\":\"\"},{\"guid\":\"{32723328-9a9f-5889-a637-bcc3f77c1324}\",\"name\":\"Microsoft.Windows.Ndis.NetAdapterCx.Translator\",\"group\":\"\"},{\"guid\":\"{5c7051bd-bedc-52df-b54e-f6f2706f346a}\",\"name\":\"Microsoft.Windows.Networking.WFP.Kfd\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{152fbe4b-c7ad-4f68-bada-a4fcc1464f6c}\",\"name\":\"Microsoft.Windows.Hyper-V.NetVsc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ffd1d811-6488-4d44-82af-c31d372609a9}\",\"name\":\"Microsoft.Windows.FileSystem.NTFS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{93f6b8d0-dd30-53db-e16c-8eb93c811cda}\",\"name\":\"Microsoft.Windows.Storage.Nvdimm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{24b4f621-1022-48ed-8b93-23fa02191d83}\",\"name\":\"Microsoft.Windows.Networking.Wlan.Nwifi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ab67b0f3-ae94-452d-b595-307667142420}\",\"name\":\"Microsoft.Windows.Storage.Partmgr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{69a770dd-1cdb-46c0-91c9-cd2a9b76e061}\",\"name\":\"PciTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d29624ca-200f-44bb-9471-13b01ea15b9e}\",\"name\":\"Microsoft.Windows.Pdc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9edc1e34-f571-4374-871c-b87cc742017b}\",\"name\":\"Microsoft.Windows.Power.SleepstudyHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{655f3490-f423-4868-a87c-7a23707b1550}\",\"name\":\"Microsoft.Windows.Storage.Pmem0101\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bebd6159-6f76-5a22-366a-7753c2a63c3c}\",\"name\":\"Microsoft.Windows.Audio.PortClass\",\"group\":\"\"},{\"guid\":\"{61d5c496-c69b-5b72-de0a-29248a17cace}\",\"name\":\"Microsoft.Windows.FileSystem.ReFS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5d364aaf-5b49-41a0-9e03-d3cb2aa2e03e}\",\"name\":\"Realtek.Trace.Provider\",\"group\":\"\"},{\"guid\":\"{c000f83a-fc96-4f70-82f9-cdd00abfe098}\",\"name\":\"Microsoft.Windows.Sdf.KmReflector\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{06917f71-ce18-4fb2-80cf-38ddedde08ed}\",\"name\":\"Microsoft.Windows.Storage.SDStor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2e38431e-4f09-5764-b81f-595fa176933f}\",\"name\":\"Microsoft.Windows.Oct.Driver\",\"group\":\"\"},{\"guid\":\"{a33cf311-4e09-4494-a7b8-182a5bec2e29}\",\"name\":\"Microsoft.Windows.Kernel.SleepStudyHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e7d0ad21-b086-406d-be46-a701a86a5f0a}\",\"name\":\"Microsoft.Windows.Storage.Spaceport\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{06ef64e5-ffa8-441c-bb2d-0c24f0c32d76}\",\"name\":\"Microsoft.Windows.Analog.SpatialGraphDriver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5f9080bf-b22c-47ea-8b76-1da0cf975419}\",\"name\":\"SpatialGraphFilterProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{771e7665-3e83-4475-8ae6-8f5384c41408}\",\"name\":\"Microsoft.Windows.SMB.SRV2\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cbf776fd-5b21-5fbc-e4cd-f19fe9acc193}\",\"name\":\"Microsoft.Windows.SMB.SRVADMIN\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4eeb8774-6c4c-492f-8f2f-5ee4721b7bf7}\",\"name\":\"Microsoft.Windows.Storage.Storport\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{61d3c72e-6b1b-454c-a34d-b39eb95b8d99}\",\"name\":\"Microsoft.Tpm.Tbs\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8f1ebc88-8917-5ee3-66d9-0570c60676be}\",\"name\":\"Microsoft.Windows.Networking.WFP.Ale\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2f07e2ee-15db-40f1-90ef-9d7ba282188a}\",\"name\":\"Microsoft-Windows-TCPIP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8b9b46ca-778f-5cc2-4255-3a6b1e69ae24}\",\"name\":\"Microsoft.Windows.Networking.WFP.IPsec\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{444943b7-3a0f-45c9-b7cb-d2a2de9eb852}\",\"name\":\"Microsoft.Windows.Networking.Tunnel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{11434984-9ab6-57f0-fc34-df79ea15c255}\",\"name\":\"Microsoft.Windows.UCM.ClassExtension\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3babe443-ebd4-4cce-80d7-20f880c7550e}\",\"name\":\"Microsoft.Windows.UCM.PolicyManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{227449e1-bddc-4e48-a31c-27523bd264f2}\",\"name\":\"Microsoft.Windows.FileSystem.Udfs\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{22eb0808-0b6c-5cd4-5511-6a77e6e73a93}\",\"name\":\"Microsoft.Windows.Security.Biometrics.Face.TelemetryProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63221d5a-4d00-4be3-9d38-de9aaf5d0258}\",\"name\":\"Microsoft.Windows.Security.Biometrics.Face.DiagnosticsProvider\",\"group\":\"\"},{\"guid\":\"{32a214f0-6d7f-4068-9085-862e1385c829}\",\"name\":\"Microsoft.Windows.HidTelephony\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{257d541d-16d8-433c-b421-9ae2255df475}\",\"name\":\"Microsoft.Windows.Bluetooth.Telephony.AsyncPhoneController\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4e5e33e9-ca19-5357-8628-06f39ea522f5}\",\"name\":\"Microsoft.Windows.Graphics.IddCx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6e6bacf6-5635-4670-bedf-93f55a822f4b}\",\"name\":\"Microsoft.Windows.Nfc.NfcCx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{13895bc5-e1f8-4144-9f24-4e48868f8220}\",\"name\":\"Microsoft.Windows.Pos.CX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7b7a87d4-6d7c-4c87-8e3d-29f31bff02b8}\",\"name\":\"Microsoft.Windows.Rdp.Graphics.RdpIdd\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0f0917eb-05ef-4416-87b1-0148718adfec}\",\"name\":\"Microsoft.Windows.Capture.USBVideo.Trustlet\",\"group\":\"\"},{\"guid\":\"{3e52e9c2-0a98-5568-5f7e-87169a98e035}\",\"name\":\"Microsoft.Windows.SensorsCx.ReadingNotificationSession\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8971e817-3247-579a-74fb-624214ec10b8}\",\"name\":\"Microsoft.Windows.Sensors.CX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{80863bfb-0974-45c1-88df-e4e9a4b2b7d4}\",\"name\":\"Microsoft.Windows.Capture.USBVideo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2f125292-522c-4ea9-fda1-1d4b8f45b992}\",\"name\":\"WindowsDriverVerifierXdv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1111450b-dacc-40a3-84ab-f7dba4a6e63a}\",\"name\":\"Microsoft.Windows.HyperV.VID\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5931d877-4860-4ee7-a95c-610a5f0d1407}\",\"name\":\"Microsoft-Windows-Hyper-V-VID\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{96c57851-af06-470f-8635-9c5e463e5f0c}\",\"name\":\"Microsoft.Windows.Storage.VolumeManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6e31f252-a41c-41d7-a9e2-3a20162247ec}\",\"name\":\"Microsoft.Windows.Containers.Wcifs\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{796f452c-2331-45df-9277-520f0788c90a}\",\"name\":\"Microsoft.Windows.Containers.Wcnfs\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ec044b58-3d13-4880-936f-7b67dfb3e056}\",\"name\":\"Microsoft.Wdf.KMDF.Fx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6c6d5103-b4ab-46b1-b4cf-7d330f4c81e6}\",\"name\":\"Microsoft.Wdf.KMDF.Ldr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1fb5ff90-a110-5110-3fa7-5e54b1e386fe}\",\"name\":\"Microsoft.Windows.WdiWiFi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{75441f26-c4ed-4585-90bd-1c7b9c6a55f7}\",\"name\":\"Microsoft.Windows.Networking.WfpLwfs\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f40af494-46c8-464a-bdac-47d9bd57e7d1}\",\"name\":\"Microsoft.Windows.Networking.Quic\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{78267204-1ef8-4199-8e25-3b42000c4b23}\",\"name\":\"Microsoft.Windows.FileSystem.WOF\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2f294903-5481-4aa0-b4ef-14784cc95ce6}\",\"name\":\"Microsoft.Windows.Xbox.GIP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{af09b0f9-ae02-4926-8a0f-e90d803063a8}\",\"name\":\"Microsoft.Windows.Security.Biometrics.Face.PerformanceProvider\",\"group\":\"\"},{\"guid\":\"{27acaa3c-09fe-5929-1466-dc5b0a189ffd}\",\"name\":\"Windows.Media.FaceAnalysis.Api\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9c38133f-6d73-42bf-b92b-3e5ad2d05967}\",\"name\":\"Windows.Media.FaceAnalysis.PerformanceProvider\",\"group\":\"\"},{\"guid\":\"{48cafa6c-73aa-499c-bdd8-c0d36f84813e}\",\"name\":\"Windows.Media.FaceAnalysis.ApiDiagnostics\",\"group\":\"\"},{\"guid\":\"{9eff7abc-d74e-4de6-ac46-2c777e467257}\",\"name\":\"Microsoft.IoT.PoS.IdTechMagneticStripeReader\",\"group\":\"\"},{\"guid\":\"{f5329024-efb9-4af7-9326-e3ee6dadc4f8}\",\"name\":\"Microsoft.IoT.PoS.MagtekMagneticStripeReader\",\"group\":\"\"},{\"guid\":\"{1f930302-f484-4e01-a8a7-264354c4b8e3}\",\"name\":\"Microsoft.Windows.Cast.MiracastLogging\",\"group\":\"\"},{\"guid\":\"{1f930301-f484-4e01-a8a7-264354c4b8e3}\",\"name\":\"Microsoft.Windows.Cast.Miracast\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f651b84-f358-4486-bf42-a8d60d911dc6}\",\"name\":\"RealtekWindowsWiFi\",\"group\":\"\"},{\"guid\":\"{95c32441-f1ff-4a9d-93ab-26a464a55051}\",\"name\":\"Microsoft.Windows.Print.PScript\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{15fc363b-e2b4-5e55-f1d3-3b0ff726203d}\",\"name\":\"Microsoft.Windows.Print.PCLmRenderFilter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ac521649-5ec6-5397-d1c5-749cbf5ea79b}\",\"name\":\"Microsoft.Windows.Print.RenderFilterCommon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63a87ca3-6662-4925-a0a8-f7bb94ef104e}\",\"name\":\"Microsoft.Windows.Print.PrintToPDF\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e98cb748-3d93-4719-8209-95e0bc46eec7}\",\"name\":\"Microsoft.Windows.Print.PwgRenderFilter\",\"group\":\"\"},{\"guid\":\"{92d9f30a-30dc-592b-b679-ddfa1ba899a5}\",\"name\":\"Microsoft.Windows.PrintCore.Performance\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{47f16003-0637-4d05-a9da-1fc40bbd0944}\",\"name\":\"Microsoft.Windows.Analog.PerceptionSimulation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fdcab703-6402-4959-b618-f5c3c279ef3d}\",\"name\":\"Microsoft.Windows.Print.PrintConfig\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fd6ec121-dc51-42fd-a559-ba984d345e2b}\",\"name\":\"Microsoft.Windows.Print.PrintDeviceCapabilities\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2974da9a-e1f3-5c5f-2abe-f7f20f6448bc}\",\"name\":\"Microsoft.Windows.Print.JScriptLib\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1c418091-59f2-529b-8ba6-da40facc1cf3}\",\"name\":\"Microsoft.OSG.IoT.Pos.RemoteDriver\",\"group\":\"\"},{\"guid\":\"{e00465de-86b7-5ef4-7a62-a6eed76ab1ba}\",\"name\":\"Microsoft.Windows.UEFI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{54dc5472-46e8-5f6d-c555-54eab87bccbf}\",\"name\":\"Microsoft.Windows.Audio.InboxEffects\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{84bf3402-c117-5308-1df5-370f5ff81bea}\",\"name\":\"Microsoft.Windows.Usage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{65af3014-367d-4645-b850-77fd014e262a}\",\"name\":\"Microsoft.Windows.WpdMtp.Driver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{539f3db6-e6f3-43c1-96c1-9e66816e12be}\",\"name\":\"Microsoft.Windows.Scan.WsdScanDriver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a23bd382-12ab-4f02-a0d7-273153f8b65a}\",\"name\":\"Microsoft.Windows.DriverInstall\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{42f9500f-081e-4e4a-9a45-9a7a30bf758f}\",\"name\":\"Microsoft.Windows.DesiredStateConfiguration.Native\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9d4b9c90-b835-595e-7125-ec72cbc9334e}\",\"name\":\"Microsoft.Windows.DirectX.DirectSound\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{acc49822-f0b2-49ff-bff2-1092384822b6}\",\"name\":\"Microsoft.CAndE.ADFabric.CDJ\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5aa2dc10-e0e7-4bb2-a186-d230d79442d7}\",\"name\":\"Microsoft.CAndE.ADFabric.CDJ.Recovery\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0c7964f6-0865-4847-b379-1b574381bcb7}\",\"name\":\"Microsoft.CAndE.ADFabric.AutoJoin\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7ae961f7-1262-48e2-b237-acba331cc970}\",\"name\":\"Microsoft.CAndE.ADFabric.CDJ.AzureSecureVMJoin\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{743dd30b-05c4-539e-b558-2ea080527271}\",\"name\":\"Microsoft.Windows.AppModel.DataSharingService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{69f50e3c-f7d3-4775-8010-9bce0279cddf}\",\"name\":\"Microsoft.Windows.DirectToUpdate\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{7b9fa392-c92c-5e63-59d9-2442d2304c7a}\",\"name\":\"Microsoft.Windows.Dui\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{afa03ad9-e63c-59d0-754c-f5a51b7fe33c}\",\"name\":\"Microsoft.Windows.DusmSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a295305a-b6fa-5023-7486-c04d7b745016}\",\"name\":\"Microsoft.Windows.Dwm.BlackScreenDiag\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{504665a2-31f7-4b2f-bf1b-9635312e8088}\",\"name\":\"Microsoft.Windows.Dwm.DwmApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2729be56-b41a-54be-8c2a-8da6127a8e38}\",\"name\":\"Microsoft.Windows.Dwm.Interaction\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1bf43430-9464-4b83-b7fb-e2638876aeef}\",\"name\":\"Microsoft.Windows.Dwm.DwmCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{289e2456-ee16-4c81-aaf1-7414d66ca0be}\",\"name\":\"WindowsDwmCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2bed2d8b-72d4-4d19-b0ac-dc27bf3b24ea}\",\"name\":\"WindowsDwmCoreTests\",\"group\":\"\"},{\"guid\":\"{2331d1f1-6b8e-42c5-897e-2ac4f98e53da}\",\"name\":\"WindowsDwmCoreInstrumentation\",\"group\":\"\"},{\"guid\":\"{2161bf9e-e2a6-4463-b9ab-12faa958d69b}\",\"name\":\"Microsoft.Windows.Analog.HydrogenCompositor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45ac0c12-fa92-4407-bc96-577642890490}\",\"name\":\"Microsoft.Windows.Dwm.DwmInit\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1a289bed-9134-4b49-9c10-4f98675cad08}\",\"name\":\"Microsoft.Windows.Dwm.DwmRedir\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0d481997-5998-51af-4ea5-afefe9651b0f}\",\"name\":\"Microsoft.Beihai.Core.Canvas\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9091cf64-70bb-42e0-a8a1-5c6913825ac4}\",\"name\":\"SpectreTraceLoggingProvider\",\"group\":\"\"},{\"guid\":\"{364e2beb-6efc-47dc-b8b1-49aae1d83922}\",\"name\":\"Microsoft.Windows.Graphics.DirectWrite\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8d89eda7-2638-483d-9448-1ad7730d9ced}\",\"name\":\"Microsoft.Windows.GraphicsTools.DXCAP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9fb51033-59f7-4b06-94f0-55b9a73a5b64}\",\"name\":\"Microsoft.Windows.GraphicsTools.DXCAPTUREREPLAY\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ae9a4436-3e16-40b8-b681-588211243dd6}\",\"name\":\"Microsoft.Windows.DxDiag\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{03bbe5b8-c788-4d0b-b47e-5b5731398a89}\",\"name\":\"Microsoft.Windows.Graphics.DXGI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{401b5439-6b0c-45cd-9c08-7080760bd043}\",\"name\":\"Microsoft.Windows.Graphics.DxilConv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d592c8f4-f305-58fe-d66d-e5d790040d87}\",\"name\":\"Microsoft.Windows.Shell.DeviceStage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{745976be-5e09-5c76-eabd-76c93c9212d2}\",\"name\":\"Microsoft.Windows.Networking.EAPPHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{06c071f2-6c59-5d55-6b31-1578dd063ddc}\",\"name\":\"EapCredEvents\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ff32ada1-5a4b-583c-889e-a3c027b201f5}\",\"name\":\"Microsoft.Web.Platform\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{903b9fe3-2cd2-5407-31ca-70c7ace9c26e}\",\"name\":\"Microsoft.Windows.App.Browser.Diagnostics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{90b23e32-d567-48e1-98d8-61e23bef47a9}\",\"name\":\"Microsoft.Windows.App.Browser.Aggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{843baf24-ed4d-479c-9e8b-520901959c89}\",\"name\":\"F12ToolsProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{98a91ff5-590f-58da-f5bf-357430d332ef}\",\"name\":\"Microsoft.Web.Platform.FetchDiagnostics\",\"group\":\"\"},{\"guid\":\"{a806a1b7-e64d-5394-0523-f01f0bd24387}\",\"name\":\"Microsoft.Windows.TextInput.SpellCheckerEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{692ef39c-05c6-532a-66ff-23d2ab729a21}\",\"name\":\"Microsoft.Windows.Licensing.ActivationUXLib\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0c017b8d-7629-4ad6-a268-578a14e9dd65}\",\"name\":\"Microsoft-Windows-Security-EFS-EDPAudit\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6af820a5-6e4f-4558-8d7d-f7d6a2ed7195}\",\"name\":\"Microsoft-Windows-Security-EFS-EDPAudit-CopyData\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{225d7337-6538-4c12-9418-b37c558c50f2}\",\"name\":\"Microsoft-Windows-Security-EFS-EDPAudit-ApplicationGenerated\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f14d881-64ea-449d-96d7-34e9c966082b}\",\"name\":\"Microsoft-Windows-Security-EFS-EDPAudit-ApplicationLearning\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e42598b4-b399-41cd-a67c-a6b1b6007e07}\",\"name\":\"EDPCleanupTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8f453ba5-f19e-531d-071b-72ba1c501406}\",\"name\":\"Microsoft.Windows.DeviceManagement.MdmPostProcessEvaluator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6be7190d-dba0-5e9c-8b69-c5a9aed40fb9}\",\"name\":\"Microsoft.Windows.DeviceManagement.EdpConfiguration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9efe4a6a-30bc-4b9c-9d06-f1f3b8e96adc}\",\"name\":\"Microsoft.Windows.Security.EdpPrecheck\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4e04241f-30f8-5111-a04e-df3c9c867433}\",\"name\":\"Microsoft.Windows.Security.Efs\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{04493774-364f-4ea2-84c0-83d477100c8c}\",\"name\":\"Microsoft.Windows.Security.BitLocker.EncryptionToast\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bec72367-4e13-539e-def4-4b2e04da48ce}\",\"name\":\"Microsoft.Windows.Print.EduPrintProv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{295b5bba-368e-4a3f-b393-2d0d250b1ad1}\",\"name\":\"Microsoft.Windows.EnergyEstimation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{99a714bf-74fe-4666-8f44-c1c7b85a570e}\",\"name\":\"Microsoft.Windows.SRUM.ProcessTag\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{82b5ad62-b453-481a-b838-ca1eeae6e472}\",\"name\":\"Microsoft.Windows.Security.EFS.EfsCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f4f0f15b-6af1-4a58-ad83-a7c21a36b5cc}\",\"name\":\"BitLockerMDMUI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{318bbc33-cdfd-42c0-b5e5-57ed92e8935f}\",\"name\":\"Microsoft.Windows.Security.EFS.EfsWrt\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ee3112cb-4b76-49eb-a73b-712ad05e18cb}\",\"name\":\"Microsoft.Windows.UserDataAccess.EmailApis\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4c252233-fed2-53ff-0f0e-062dc1b91cc3}\",\"name\":\"Microsoft.Windows.IoT.Client.ShellExtension\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e94614d1-95aa-4bd6-87f8-b6967917f7af}\",\"name\":\"Microsoft.Windows.Power.Battery\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{91f575cd-50ca-496a-97e0-11bc7f12c659}\",\"name\":\"Microsoft.Windows.Power.CpuUtilization\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cdef60fa-5777-4b02-9980-1e2c0df22635}\",\"name\":\"Microsoft.Windows.Power.DeviceProblems\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{79447bc9-0777-4626-b75d-68d37ec5c820}\",\"name\":\"Microsoft.Windows.Power.Device\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b87ceb6d-52b1-431b-a19d-e4e559de4d27}\",\"name\":\"Microsoft.Windows.Power.EnergyWizard\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ea44cfb5-807d-41c8-950c-3d24eabcc66e}\",\"name\":\"Microsoft.Windows.Power.PlatformCapabilities\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{16ff057d-f560-4a1a-9d98-b06ca200b934}\",\"name\":\"Microsoft.Windows.Power.PpmProfiles\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eedfe0d7-14c4-4370-ac5d-a97e3849b747}\",\"name\":\"Microsoft.Windows.Power.PowerPolicy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bcdfff62-2656-4c74-86c3-5605d3a0b634}\",\"name\":\"Microsoft.Windows.Power.PowerRequest\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3c85d27c-5154-47c9-9995-2f3f3671981d}\",\"name\":\"Microsoft.Windows.Power.SelectiveSuspend\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{30caae83-8eb3-4b59-b67e-e688f6f92e56}\",\"name\":\"Microsoft.Windows.Power.SleepStudy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{46a2d9fa-44da-4ef1-b987-1c95b4584d96}\",\"name\":\"Microsoft.Windows.Power.ScreenOnStudy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f67958f-7a9c-4dbc-9728-ad3c245646c6}\",\"name\":\"Microsoft.Windows.Power.SystemInformation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e3cb20a8-05cc-4e9d-ba36-0ee1b3c14dea}\",\"name\":\"Microsoft.Windows.Power.TimerResolution\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7073707a-0587-4e03-b31f-6443eb1acbcd}\",\"name\":\"Microsoft.Windows.SRUM.Telemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0e71a49b-ca69-5999-a395-626493eb0cbd}\",\"name\":\"Microsoft.Windows.EnterpriseModernAppManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{536d7120-a8a4-4a5f-b1f8-1735df9b78d0}\",\"name\":\"Microsoft.Windows.DeviceManagement.CertificateStore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0f77f82c-2a99-5ed3-eb66-98585f6f4a37}\",\"name\":\"Microsoft.Windows.Security.RemoteLockCsp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{36a529a2-7cba-4370-8c3d-d113f552b138}\",\"name\":\"Microsoft.Windows.DeviceManagement.DMClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{24a7f60e-e0cb-5bdc-99a5-0ba8e8c018bd}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.NodeCache\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{72b37bca-13de-4655-b603-1c745f4d8faf}\",\"name\":\"Microsoft.Windows.DeviceManagement.DeviceManageability\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9966e698-b74b-4ce2-be16-703ef0acaa30}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.FirstSyncStatus\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{16eaa7bb-5b6e-4615-bf44-b8195b5bf873}\",\"name\":\"Microsoft.Windows.EnterpriseDesktopAppManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2b6dbadc-ba94-4ba2-b12c-e4b15f73c15b}\",\"name\":\"Microsoft.Foundation.Diagnostics.ErrorDetails\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{02f42b1b-4b78-48ce-8cdf-d98f8b443b93}\",\"name\":\"Microsoft.Windows.ESENT.TraceLogging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{28e9d7c3-908a-5980-90cc-1581dd9d451d}\",\"name\":\"Microsoft.Windows.Desktop.Shell.EUDCEditor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1e2fc8ac-8d70-471b-89e9-fc2015acf49f}\",\"name\":\"Microsoft.Windows.Cellcore.MultiSIM.CSP\",\"group\":\"\"},{\"guid\":\"{612aa4d1-4c02-424c-ac7e-ee5307277ac8}\",\"name\":\"Microsoft.Windows.Cellcore.LPA.CSP\",\"group\":\"\"},{\"guid\":\"{209814d7-1019-4651-9aaf-794b1bca59d2}\",\"name\":\"Microsoft.Windows.MediaFoundation.EVROTA\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{072665fb-8953-5a85-931d-d06aeab3d109}\",\"name\":\"Microsoft.Windows.ProcessLifetimeManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e1fa35be-5192-5b1e-f23e-e2a38f6414b9}\",\"name\":\"Microsoft.Windows.FileExplorerPerf\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{08f5d47e-67d3-4ee0-8e0c-cbd309ab5d1b}\",\"name\":\"Microsoft.Windows.Shell.CloudFiles\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b87cf16b-0bf8-4492-a510-d5f59626b033}\",\"name\":\"Microsoft.Windows.FileExplorerErrorFallback\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{db8464e8-2a75-50cd-51d7-f712b52a9ba3}\",\"name\":\"Microsoft.Windows.F12.Chooser\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5002109a-ffdc-407e-8a6a-8d893f7d714f}\",\"name\":\"XperfCoreProvider\",\"group\":\"\"},{\"guid\":\"{e60019f0-b378-42b6-a185-515914d3228c}\",\"name\":\"Microsoft.Windows.Security.Biometrics.CredentialProvider.FaceDiag\",\"group\":\"\"},{\"guid\":\"{1d480c11-3870-4b19-9144-47a53cd973bd}\",\"name\":\"Microsoft.Windows.Security.Biometrics.CredentialProvider.Face\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9e339f5e-6d0e-5645-22a4-02d76deb3432}\",\"name\":\"Microsoft.Windows.Shell.Family.Authentication\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{833606fb-390d-5663-d604-5d8e18327bf2}\",\"name\":\"Microsoft.Windows.Shell.Family.Cache\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{750131fe-3dbf-5f00-69f7-20d77122bdae}\",\"name\":\"Microsoft.Windows.Shell.Family.Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{54a0f7de-80ee-48ac-a3c6-a7ef636c82ba}\",\"name\":\"Microsoft.Windows.Shell.Family.SyncEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cc79cf77-70d9-4082-9b52-23f3a3e92fe4}\",\"name\":\"Microsoft.Windows.WindowsErrorReporting\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1377561d-9312-452c-ad13-c4a1c9c906e0}\",\"name\":\"Microsoft.Windows.FaultReporting\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{64d9c122-76bd-5efd-a2f7-8f0cd5f7e74e}\",\"name\":\"Microsoft.Windows.FeatureExperiment\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{337b21e4-1d91-42f0-9e88-f77a7fcb045b}\",\"name\":\"Microsoft.Windows.FolderRedirection\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2beb7410-3174-4391-ab8b-cac210cfd6ac}\",\"name\":\"Microsoft.Windows.Security.DataProtection.FeClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{546c471c-759f-4edb-b4e7-9f91a1a752f1}\",\"name\":\"Microsoft-Windows-FileHistory-CatalogErrors\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9a39eabf-d3ef-48e9-8326-7175a4db7c73}\",\"name\":\"Microsoft-Windows-FileHistory-ConfigMgr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b2f4280f-936e-49a3-be64-5c0de42368ce}\",\"name\":\"Microsoft-Windows-OneBackup-TargetDiscovery\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8286677e-24b3-4ef4-a463-ff0efbc54771}\",\"name\":\"Microsoft.Windows.FileHistory.Engine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{572f10d1-d697-5616-4118-98ec535a9e3f}\",\"name\":\"Microsoft.Windows.FileHistory.ApiUsage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{08b15ce7-c9ff-5e64-0d16-66589573c50f}\",\"name\":\"Microsoft.Windows.Security.Fido\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c7c12137-338d-5e64-626f-338d51a1b35c}\",\"name\":\"Microsoft.Windows.Shell.MTF.FilterDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{225b3fed-0356-59d1-1f82-eed163299fa8}\",\"name\":\"Microsoft.Windows.Security.Biometrics.FingerprintCredential\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0998dfb7-59d7-4e82-92ce-8a83e7c0bb3e}\",\"name\":\"Microsoft.Windows.Firewall.API\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a288dc52-4074-4e21-842d-97db6e1e9052}\",\"name\":\"Microsoft.Windows.CTAC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9384638b-db04-57ed-af12-e492da02d5d6}\",\"name\":\"Microsoft.Windows.TextInput.FluencyDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8479f1a8-524e-5226-d27e-05636c12b837}\",\"name\":\"Microsoft.Windows.Desktop.Fonts.FontManagementSystem\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45896826-7c5e-5a91-763d-67db83540f1b}\",\"name\":\"Microsoft.Windows.Desktop.Shell.FontFolder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{37152864-4c08-5745-da4f-65a46a537347}\",\"name\":\"Microsoft.Windows.Fonts.FontSubsetting\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ec50b9c2-b123-4552-931f-c4826f70a67e}\",\"name\":\"Microsoft.Windows.MediaFoundation.FrameServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0a645885-cc18-4dec-ab0a-8aa890c13d3e}\",\"name\":\"FsIsoTracelogProvider\",\"group\":\"\"},{\"guid\":\"{e548a491-711c-4e50-b77d-e8a6e4397c36}\",\"name\":\"Microsoft.Windows.Das.Fd\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d0974663-5c08-408f-9445-35bb55075757}\",\"name\":\"FveAPILoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{00a85728-5a3d-4b9e-b24b-9a14cce5f322}\",\"name\":\"DESkyBackupProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{89467242-6dcd-4d99-a6ed-55d0c19eec09}\",\"name\":\"DEUITraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5c86354e-81c8-4138-96e0-f50301ff8648}\",\"name\":\"DEWizardTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c9e8f9ee-0333-43eb-90b5-d30bd5c5658f}\",\"name\":\"Microsoft.Windows.Networking.DefenderFirewall.CSP(Aggregate)\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e90cb4c0-c7b6-4f18-a53a-187934ad4b55}\",\"name\":\"Microsoft.Windows.Firewall.PolicyIoManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7e32a1c4-d502-5b7c-39e8-2b7b0b5f0424}\",\"name\":\"Microsoft.Windows.Networking.WFP.User\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bd79c6b5-7e6a-4084-a409-d9b8a872fa9b}\",\"name\":\"Microsoft.Windows.GameBarPresenceWriter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0f014207-837c-4862-8e6d-cc648083466e}\",\"name\":\"Microsoft.Xbox.GameChatTranscription\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2f669506-de7f-4807-9f05-61ac44ec3465}\",\"name\":\"ExpandedResourcesAPI\",\"group\":\"\"},{\"guid\":\"{95df1e7b-74e0-547f-1f87-dada00554433}\",\"name\":\"Microsoft.Windows.GameOverlay\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ed785a68-905d-4713-96f0-64c443cd9d19}\",\"name\":\"Microsoft.Windows.GameOverlayTracing\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cc78b5d4-24c2-4b47-833e-ea9729da1cd4}\",\"name\":\"XboxLiveGamingUI\",\"group\":\"\"},{\"guid\":\"{89dfbde8-86e8-489b-9867-eefdc5e8879b}\",\"name\":\"Microsoft.Geolocation.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a313af2b-a798-470e-9355-f535c3d45f94}\",\"name\":\"Microsoft.Geolocation.Verbose\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cb671458-ad15-40e8-a65a-753ea62d853a}\",\"name\":\"Microsoft.Geolocation.Api\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c1df9318-da0b-4cd1-92bf-59415e6454f7}\",\"name\":\"Microsoft.Windows.GroupPolicy.CSEs\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6fc72ed3-75da-4bc4-8365-c4228ceaedfe}\",\"name\":\"Microsoft.Windows.GroupPolicy.RegistryCSE\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9143e88c-3068-446d-8782-2848cf0034b7}\",\"name\":\"Microsoft.Windows.Graphics.GPM\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{99288295-d294-5e94-ca68-18e2fa6cc424}\",\"name\":\"Microsoft.Windows.Shell.GroupConverter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0f51c5a7-0e76-47a5-bede-7cf62c5822f6}\",\"name\":\"Microsoft.Windows.Kernel.HAL\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a935c211-645a-5f5a-4527-778da45bbba5}\",\"name\":\"Microsoft.Tpm.HealthAttestationCSP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8e38fc76-5593-4c1b-98b1-a13770b67d98}\",\"name\":\"Microsoft.Windows.Cast.HdcpHandler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{55a5dc53-e24e-5b53-5b52-ea83a0cc4e0c}\",\"name\":\"Microsoft.Windows.Heat.HeatCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{54225112-eaa1-5e29-c8f8-1cb9924d6049}\",\"name\":\"Microsoft.Windows.Heat.HeatCore.Test\",\"group\":\"\"},{\"guid\":\"{9211ac87-37d7-5868-092f-010437c37f40}\",\"name\":\"Microsoft.Windows.Heat.HeatCore.Perf\",\"group\":\"\"},{\"guid\":\"{3602a94a-b764-5eca-4257-286887531640}\",\"name\":\"Microsoft.Windows.Shell.AdvancedSharingSettingsCPL\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{24fd15bb-a367-42b2-9210-e39c6467bf3a}\",\"name\":\"Microsoft.Windows.Shell.Homegroup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{278491e2-da59-4053-acbf-d2043d476631}\",\"name\":\"Microsoft.Windows.HtmlHelp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b715ff40-adb2-4a51-a077-90b81d1e0e62}\",\"name\":\"Microsoft.Windows.Input.Hiddll\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e369227c-ee2f-42d0-9734-cec639966d99}\",\"name\":\"Microsoft.Windows.Analog.Compositor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c4d4d3fc-b8de-5cd2-a0cf-1dfdcc4997c4}\",\"name\":\"Microsoft.Cognition.MixedRealityCompositor.MetadataGenerator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{356e1338-04ad-420e-8b8a-a2eb678541cf}\",\"name\":\"Microsoft.Windows.Analog.SpectrumContinuous\",\"group\":\"\"},{\"guid\":\"{46fe483a-c057-49e3-9a3e-6661ae69d267}\",\"name\":\"Microsoft.Windows.HydrogenBaseTrace\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ac6a1be3-fe8c-4c86-a355-6249ca1dbd1d}\",\"name\":\"Microsoft.Windows.Hydrogen.Engine.NewRPC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eee90ccf-b5cf-5c29-eab2-e8e24257af70}\",\"name\":\"Microsoft.Windows.Hydrogen.ResourceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3a722c70-188c-575a-09e8-95068c764465}\",\"name\":\"Microsoft.Windows.Hydrogen.RuntimeProject\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{41258037-fd37-44dc-a4c5-3e814bf9bc08}\",\"name\":\"Microsoft.Windows.Hydrogen.Engine.NewBase\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5d83ff6d-8620-41bd-a209-83c28016db4c}\",\"name\":\"Microsoft.Windows.Hydrogen.Input\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4e8ad9d9-a447-4f60-add9-f88a79ae5d85}\",\"name\":\"Microsoft.Windows.Hydrogen.Common.Sound\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b0989218-f91b-5303-b8b8-6018bfcb25b7}\",\"name\":\"Microsoft.Windows.Hydrogen.Renderer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3f159176-af51-44f4-838f-b1268a925924}\",\"name\":\"Microsoft.Windows.Analog.HoloShell\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{43a82e4f-d4b5-5b44-90c0-4036b52f2b7f}\",\"name\":\"Microsoft.Windows.Holographic.OasisBenchmark\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{581071af-2a59-5892-e3ba-34ec806f78ef}\",\"name\":\"Microsoft.Windows.Holographic.HolographicExtensions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{155a4d3f-9e34-547a-16a5-5f25ecf07d3f}\",\"name\":\"Microsoft.Windows.Holographic.Coordinator\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{1666c918-7923-5cac-899c-f2b448e1a7a4}\",\"name\":\"Microsoft.Windows.Holographic.InputBanner\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fb9ca694-62b6-5e95-f1d4-fa9e239015e6}\",\"name\":\"Microsoft.Windows.Holographic.HolographicSessionTracker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5bcbfd6b-0337-56af-43ff-da8a1600fae7}\",\"name\":\"Microsoft.Windows.Holographic.ViewPorter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1f06148f-cdbf-5e07-7f82-4e4aa0f13b9e}\",\"name\":\"Microsoft.Windows.Holographic.CrossApartmentBarrier\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a329db5c-f4b7-5ce4-1fd8-f030503f517a}\",\"name\":\"Microsoft.Windows.Holographic.HolographicLoader\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4d4412bd-15ef-52c2-8fee-89fc2e1b0f67}\",\"name\":\"Microsoft.Windows.Holographic.SlatePositionGuardian\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e4c79dc8-f1d2-5475-4462-6d9908e61420}\",\"name\":\"Microsoft.Windows.Holographic.SlatePositionGuardianVerbose\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a5b43b76-8698-5fdd-5ed3-5416c5b56d16}\",\"name\":\"Microsoft.Windows.Holographic.VirtualMonitorPool\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{882ec52c-3421-5770-2e47-fa137064d029}\",\"name\":\"Microsoft.Windows.Holographic.Win32SlateActivationLog\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{69689644-337a-541b-c3f8-55bc750ef76e}\",\"name\":\"Microsoft.Windows.Holographic.Install\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d8c84585-1f65-5d5f-b0a4-bd4499f0812d}\",\"name\":\"Microsoft.Windows.Holographic.DesktopFodInstaller\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{05c32102-40e0-4b2b-b778-e5fd577c472b}\",\"name\":\"Microsoft.Windows.Analog.Spectrum\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c116a72f-3f96-4983-b83e-48f8168610a8}\",\"name\":\"Microsoft.Windows.Analog.HoloSHExtensionTracing\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c116a72f-3f96-4983-b83e-48f8168610a8}\",\"name\":\"Microsoft.Windows.Analog.HoloShellExtensions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2edb24b0-dab3-4b98-b843-c73cc2c729ee}\",\"name\":\"Microsoft.Windows.Analog.HoloShellTiles\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{201a54ec-f956-570a-c003-5f0ccde64705}\",\"name\":\"Microsoft-Windows-Shell-CriticalResultVerifier\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5d1e83a6-bbe3-4844-94c0-0347370b5208}\",\"name\":\"Microsoft.Windows.Analog.HoloSI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{52000e1d-a0d3-55cd-dd29-631ed05d560e}\",\"name\":\"Microsoft.Windows.Audio.HrtfApo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d1af2c40-3880-47c9-ade0-0fc1a909be08}\",\"name\":\"Microsoft.Windows.Audio.Spatial.Audio3D\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9b9cb5f6-76f7-5daa-cd46-536646cceb40}\",\"name\":\"Microsoft.Windows.AppModel.HttpsDataSource\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d7c4072e-0fe3-580c-7ea5-5367644777ba}\",\"name\":\"Microsoft.Windows.Appx.HttpsTransport\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6cba7043-bf35-5e8c-2a96-033ef9b3ceee}\",\"name\":\"Microsoft.Windows.Hydrogen.Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9f7e92de-9bd1-5b43-9cbd-e332a6ed01e6}\",\"name\":\"Microsoft.Windows.Hydrogen.RuntimeLoad\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6ecc4586-a9b8-421d-8678-4625026f82be}\",\"name\":\"Microsoft.Windows.HyperV.Heartbeat\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{85a7888c-4ef7-5c56-643f-fbd6dc10febe}\",\"name\":\"Microsoft.Windows.HyperV.KvpExchanges\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f83552c4-a4e8-50f7-b2d4-a9705c474490}\",\"name\":\"Microsoft.Windows.HyperV.TimeSync\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5d5a95bd-33f7-5997-f727-14dd1f1a93e4}\",\"name\":\"Microsoft-Windows-Shell-IdControl-Desktop-InMarket-8.1\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{23696c34-d5b3-52e0-739d-b52807876f13}\",\"name\":\"Microsoft.Windows.Shell.MTF.InputHistoryDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e7ba355a-ec20-5993-dd3b-9215e4d8a23c}\",\"name\":\"Microsoft.Windows.Networking.Ikeext\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{47a8ea0f-be9f-5a94-1586-5ded19d57c3d}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.JapaneseIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{99d75be6-d696-565a-1c56-25d65942b571}\",\"name\":\"Microsoft.Windows.Shell.MTF.LMDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2593bdf1-313b-5c29-355c-6065ba331797}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.ImeCommon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{54cedcd4-5f61-54b3-d8e2-dd26feae36b2}\",\"name\":\"Microsoft.Windows.Shell.MTF.DesktopInputHistoryDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b2576ddb-209b-52a9-a0d4-6f9386e15e2d}\",\"name\":\"Microsoft.Windows.Shell.MTF.JpnRankerDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ca8d5125-1b72-5208-5147-0d345b85bd11}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.KoreanIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{06404639-ec4f-56d8-f82e-49bf6ad1b96a}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.BopomofoIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e3905915-dd2b-5802-062b-85f03eb993d5}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.OldKoreanIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a703f75d-9c1d-59c0-6b0a-a1251f1c6c55}\",\"name\":\"Microsoft.Windows.DeskTop.TextInput.ModeIndicator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{68259fff-ce2b-4a91-8df0-9656cdb7a4d6}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.MSCand20\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a097d80a-cae1-5a27-bdea-58bd574c9901}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.CloudSuggestionFlyout\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d313c0d7-e20d-5ea5-45f9-82b42e3a77f2}\",\"name\":\"Microsoft.Windows.Security.SmartCards.TpmVscMgrServerImmersive\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{24c1e9bd-af57-4347-b26b-3af10b256475}\",\"name\":\"Microsoft.Web.Platform.IDBLegacyServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e7d88397-e955-534f-4caf-d57798656789}\",\"name\":\"Microsoft.Web.Platform.StorageServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f72e560-ef48-5597-9970-e83a697071ac}\",\"name\":\"Microsoft.Windows.Desktop.Shell.InputDll\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{83bda64c-a52c-4b37-8e61-086c22a4cd15}\",\"name\":\"Microsoft.Windows.InputStateManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{973c694b-79a6-480e-89a5-c8c20745d461}\",\"name\":\"Microsoft.OneCore.MinInput\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4b01be74-d810-5994-228e-ee8417be3468}\",\"name\":\"Microsoft.Windows.OneCore.MinInput\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dd62acb1-e73c-453b-b2f8-ac88f785466f}\",\"name\":\"Windows.UI.Input.Preview.Injection\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63bcb611-4446-564a-a4b3-7d65624589ef}\",\"name\":\"Microsoft.Windows.Input.InputService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4b7bd959-bfea-5953-583c-fb7bf825bc92}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.ChxEm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2e426d37-0f80-5235-94c4-3586b385f3d8}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.ChsIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ff5023d9-8341-5dfb-3c33-17a1ab76a426}\",\"name\":\"Microsoft.Windows.Shell.CandidateWindow\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2d66bb8d-2a6b-5a2d-a09c-4f57a1776bd1}\",\"name\":\"Microsoft.Windows.TextInput.ChsIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4b7bd959-bfea-5953-583c-fb7bf825bc92}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.ChtIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9006c590-4dc8-5df7-adbc-21bf29cd284f}\",\"name\":\"Microsoft.Windows.Shell.MTF.DeprecatedInputHistoryDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f61cc6b7-e935-5591-bb63-27b07edf1d7a}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.ImeSettingHandler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dc10c74c-f6d9-5656-d77d-ca9047620cb7}\",\"name\":\"Microsoft.Windows.TextInput.FlipProcessor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c2709ea3-ae58-5742-3c79-9c11f30145ac}\",\"name\":\"Microsoft.Windows.TextInput.SpellCheckingEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e941009c-7403-48ae-b5b3-df1fcaa62a60}\",\"name\":\"Microsoft.Windows.TextInput.LITE\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{50f52804-951b-5f4a-dbff-b3f131b6ab1a}\",\"name\":\"Microsoft.Windows.TextInput.JpnProcessor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c5aaed5a-4274-582f-9e34-6c39e00c5d3c}\",\"name\":\"Microsoft.Windows.TextInput.KorProcessor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4b8f790b-f6fc-5278-3d67-7d3250b936b7}\",\"name\":\"Microsoft.Windows.TextInput.VieProcessor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0730820b-b89b-59a2-e81e-a9338bb8759f}\",\"name\":\"Microsoft.Windows.Mobile.TextInput.ChsIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{327ed12c-fe8d-5c62-0f13-3f985c85ccf7}\",\"name\":\"Microsoft.Windows.Mobile.TextInput.ChtIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{05774fd1-2d2f-56fa-1b12-c8f7a231c486}\",\"name\":\"Microsoft.Windows.TextInput.DictationInputProcessor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{73ae0ec4-37fc-4b10-92c0-7f6d9d0539b9}\",\"name\":\"Microsoft.Windows.TextInput.ExpressiveInput\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{df4cf2e3-435c-4010-9e05-0f54287cdc31}\",\"name\":\"Microsoft.Windows.TextInput.InputSession\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{397fe846-4109-5a9b-f2eb-c1d3b72630fd}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.InputSwitch\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{03e60cf9-4fa0-5ddd-7452-1d05ce7d61bd}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.UIManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9bfa0c89-0339-4bd1-b631-e8cd1d909c41}\",\"name\":\"Microsoft.Windows.StoreAgent.Telemetry\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{7c109ac5-8971-4b39-aa88-ecf239827664}\",\"name\":\"Microsoft.Xbox.WinHttp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e8d3c0f1-e832-56b6-ba8b-99fb106b1390}\",\"name\":\"Microsoft.Windows.OneSync.InternetMailEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b7a67e9e-2118-5941-38a2-12a16fe4dfef}\",\"name\":\"Microsoft.Windows.OneSync.InternetMailCSP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9a9d6c4e-0c84-5401-7148-5d809fa78018}\",\"name\":\"Microsoft.Windows.Desktop.Shell.RegionOptions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cc3ada53-28c8-571e-d3a1-6e2a3a94978e}\",\"name\":\"Microsoft.Windows.IoT.Client.AssignedAccessLockdown\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{17b41d83-1719-4224-924f-067fd63c7511}\",\"name\":\"Microsoft.Windows.Shell.Cortana.IPELogging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{70f18147-06e6-497b-bbc4-58d60b4760e2}\",\"name\":\"Microsoft.Windows.Networking.Teredo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8f3c64a5-69c2-4cda-93cb-b1031e362b8f}\",\"name\":\"Microsoft.Windows.Networking.SharedAccess\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b5ee38bb-f738-4c2e-985e-b39f2660d86e}\",\"name\":\"Microsoft.Windows.Input.ControllerProcessor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3317c7e7-7c40-4275-9f7b-d539c10e19ba}\",\"name\":\"Microsoft.Windows.Analog.RawInputProviders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45a9f627-567d-449e-bc48-29ee4b2cd3a5}\",\"name\":\"Microsoft.Windows.Analog.RawInputProvidersContinuous\",\"group\":\"\"},{\"guid\":\"{e054d6d0-e9dd-4e99-a366-683078318a47}\",\"name\":\"Microsoft.Windows.Input.RawInputProviders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f903db44-149e-4b4e-afe1-2a1096f53dfa}\",\"name\":\"Microsoft.Windows.Analog.SpatialInteraction\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6ce8e4f2-fecb-4013-9d4d-be7f699d438d}\",\"name\":\"Microsoft.Windows.Analog.SpatialInteractionContinuous\",\"group\":\"\"},{\"guid\":\"{8a681f73-36de-5cd8-8833-dcc50fb7a329}\",\"name\":\"Windows.Shell.IsoBurn\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c3841390-5ecf-446a-b936-c8cfc28ad2d2}\",\"name\":\"Windows.Maps.Platform.JPMapControl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5a82ad4c-9894-50a8-2bc9-617a4c2bef2d}\",\"name\":\"Microsoft.Windows.Shell.MTF.JpnDecoderDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{989f6d5d-e45a-51eb-b02c-6c48b059f55a}\",\"name\":\"Microsoft.Windows.Shell.MTF.JpnServiceDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{80336d8c-073d-5b46-225c-b7674d0c20f2}\",\"name\":\"KernelDebuggerData\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8a4fc74e-b158-4fc1-a266-f7670c6aa75d}\",\"name\":\"Microsoft.Windows.Security.Kerberos\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e36c4458-ed80-4ad7-a8be-52dda1eb5f1c}\",\"name\":\"Microsoft.Windows.Base.Win32.Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{58e1853a-3c4e-4bba-9ff8-e1cd088d25a5}\",\"name\":\"Microsoft.Windows.Base.Win32.Job\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{70caa5b8-a8f0-408a-8b53-563bff7ff2ff}\",\"name\":\"Microsoft.Windows.NTVDM\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{05f95efe-7f75-49c7-a994-60a55cc09571}\",\"name\":\"Microsoft.Windows.Kernel.KernelBase\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f1ef270a-0d32-4352-ba52-dbab41e1d859}\",\"name\":\"Microsoft-Windows-AppModel-Runtime\",\"group\":\"\"},{\"guid\":\"{3c74afb9-8d82-44e3-b52c-365dbf48382a}\",\"name\":\"Microsoft.Windows.Kernel.Base\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{41b5f6e6-f53c-4645-a991-135c2011c074}\",\"name\":\"Microsoft.Windows.AppModel.StateManagerTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{34646397-1635-5d14-4d2c-2febdcccf5e9}\",\"name\":\"Microsoft.Windows.Security.NGC.KeyCredMgr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cf69df80-7690-41da-99c9-186e46860e7d}\",\"name\":\"Microsoft.Windows.Provisioning.Knobs.Core\",\"group\":\"\"},{\"guid\":\"{a9f17d57-43d6-498c-94e4-eb0e9e7e19c2}\",\"name\":\"Microsoft.Windows.Provisioning.Knobs.CSP\",\"group\":\"\"},{\"guid\":\"{8b48a132-cbd8-4786-82da-66a4360bcc85}\",\"name\":\"Microsoft.Windows.DShow.Ksproxy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a245f3c6-c600-5d61-6978-14299db0cb16}\",\"name\":\"Microsoft.Windows.Shell.LanguageComponentsInstaller\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b9c4496b-b9ba-584b-68f5-ca2a501afcdc}\",\"name\":\"Microsoft.Windows.Desktop.Shell.CBSWrappers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c3a7f381-6040-5d93-64e2-b89cf65ba4c3}\",\"name\":\"Microsoft.Windows.LanguageOverlay\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4d088be4-bebf-4fe7-aa25-ae1370543847}\",\"name\":\"Microsoft.Windows.LanguagePackDiskCleanup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{af9f58ec-0c04-4be9-9eb5-55ff6dbe72d7}\",\"name\":\"Microsoft.Windows.LicenseManager.Telemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{13020f14-3a73-4db1-8be0-679e16ce17c2}\",\"name\":\"Microsoft.Windows.Store.LicenseManager.UsageAudit\",\"group\":\"5ecb0bac-b930-47f5-a8a4-e8253529edb7\"},{\"guid\":\"{961d7772-0a35-4869-89ad-056fbfc0e51f}\",\"name\":\"Microsoft.Windows.LicensingCSP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{319ac5ba-43a9-495f-9905-8216cb896d17}\",\"name\":\"Microsoft.Windows.Licensing.OA3HWID\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8c67ac58-c137-4ee2-9944-23a0375a6847}\",\"name\":\"Microsoft.Windows.Licensing.LicensingUI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a4c7a3d8-ebce-466d-a9c6-08373fbfcfb8}\",\"name\":\"Microsoft.Windows.Licensing.LicensingPolicyManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0edfb871-acea-486f-8516-8457701198e0}\",\"name\":\"Microsoft.Windows.Licensing.Troubleshooter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{522dd632-a132-4ca6-b50a-62279034fd9b}\",\"name\":\"Microsoft.Windows.ShAcct\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ba4936a1-31db-4edc-89ce-9190e3c0653b}\",\"name\":\"Microsoft.Windows.Print.LocalSpooler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b7ec0bd7-597d-49f1-9d00-7b1f8ad1612f}\",\"name\":\"Microsoft.Windows.Print.MS3DLocalSpooler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7981fc8d-605e-4052-87a7-fe07ced4ebaf}\",\"name\":\"Microsoft.Windows.Print.SplLib\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{97b0ffcd-6217-567e-4fda-e5e0f7f6da54}\",\"name\":\"Microsoft.Windows.Print.DevmodeSizePatch\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f93acd0-1c1c-5637-8860-e38dc9dd1e69}\",\"name\":\"Microsoft.Windows.Location.Crowdsource\",\"group\":\"5ecb0bac-b930-47f5-a8a4-e8253529edb7\"},{\"guid\":\"{31f05ccd-99d9-5674-0e43-36e104f04d22}\",\"name\":\"Microsoft.Windows.Location.Uploader\",\"group\":\"5ecb0bac-b930-47f5-a8a4-e8253529edb7\"},{\"guid\":\"{b93d4107-dc22-5d11-c2e1-afba7a88d694}\",\"name\":\"Microsoft.Windows.Shell.Tracing.LockAppBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9ca921e3-25a4-5d34-39da-a59bd8bdf7a2}\",\"name\":\"Microsoft.Windows.Shell.LockAppBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2d710779-b24b-4adb-81ef-cd6ded5a9b2a}\",\"name\":\"Microsoft.Windows.Shell.LockScreenController\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{74cc4a0b-f577-5929-abcb-aa4bea374cb3}\",\"name\":\"Microsoft.Windows.Shell.LockAppHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{75816b5c-ecd1-4dbc-b38a-47a9646e60be}\",\"name\":\"Microsoft.Windows.Shell.LockScreenExperienceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2ca51213-29c5-564f-fd60-355148e8b47f}\",\"name\":\"Microsoft.Windows.Shell.SingleViewExperience\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{46a55c26-5759-5897-84f4-cbebd1134adc}\",\"name\":\"Microsoft.Windows.Shell.LockAppHostNoisy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1ef1b3bd-ba20-5fd6-68c1-beb652b5d0c2}\",\"name\":\"Microsoft.Windows.Shell.LockScreenContent\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3d14ca27-6eb2-4789-9b52-33ec88ecf5b0}\",\"name\":\"Microsoft.Windows.Shell.LockScreenData\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4f7c073a-65bf-5045-7651-cc53bb272db5}\",\"name\":\"Microsoft.Windows.LogonController\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3ec987dd-90e6-5877-ccb7-f27cdf6a976b}\",\"name\":\"Microsoft.Windows.LogonUI.WinlogonRPC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b45275fa-3b9c-40f2-aaad-10060f77f0c0}\",\"name\":\"Microsoft.Windows.Shell.CloudExperienceHost.DatVPrep\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{41d006bf-1a11-4122-a0eb-0ea2ae688045}\",\"name\":\"Microsoft.Windows.Cellcore.LPA.ServiceTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0ec00dbb-7b5f-5b8d-c1ff-641fc48e8729}\",\"name\":\"Microsoft.Windows.Cellcore.LPA.Service\",\"group\":\"\"},{\"guid\":\"{a4e69072-8572-4669-96b7-8db1520fc93a}\",\"name\":\"LsaIso TraceLogging Provider\",\"group\":\"\"},{\"guid\":\"{f2d27937-6aa6-4e52-bde2-aee097c9095e}\",\"name\":\"Microsoft.Windows.Security.BCryptIum\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{77811378-e885-4ac2-a580-bc86e4f1bc93}\",\"name\":\"Microsoft.Windows.Security.Ntlm\",\"group\":\"\"},{\"guid\":\"{4d9dfb91-4337-465a-a8b5-05a27d930d48}\",\"name\":\"Microsoft.Windows.Security.LsaSrv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{557d257b-180e-4aae-8f06-86c4e46e9d00}\",\"name\":\"LSM\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{da539211-d525-422a-8add-bcbe4367159c}\",\"name\":\"Microsoft.Windows.RemoteDesktop.RDSLSTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a5caeb9d-0457-5ec6-9fb0-ebc4436ae297}\",\"name\":\"Microsoft.Windows.Cellcore.LPA.Client\",\"group\":\"\"},{\"guid\":\"{22bcd1ea-be3d-4933-8a14-06a5a86b29e4}\",\"name\":\"Microsoft.Windows.Magnifier.Asimov\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aa70963a-d6ac-4802-92bb-63ae2d9fd2d0}\",\"name\":\"ManageBDETraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a078af5a-f530-5054-3028-597b53c15178}\",\"name\":\"Microsoft.Windows.Security.CodeIntegrityManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1b648321-3416-5266-7387-b58ed4a80d58}\",\"name\":\"Microsoft.Windows.Maps.Services.Bing\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7b62d85f-8df3-44a9-9bfa-17493ea7b72a}\",\"name\":\"Windows.Maps.Platform.MapControlCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8b57f962-881e-44f6-a4c1-08f3d268ce32}\",\"name\":\"Microsoft.Windows.Maps.MapEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{91d35613-d4e5-5939-03c5-31da88a791f9}\",\"name\":\"Microsoft.Windows.Shell.Mapi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a35ab2e2-a6cb-4b0f-8989-5c6f41e9708e}\",\"name\":\"Microsoft.Windows.Maps.BackgroundTransfer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3fbe2230-5b5b-5871-87f5-9b583e56b82f}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.Maps\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{767d1a28-b916-5b5e-9bec-5456c827edd5}\",\"name\":\"MbaeApiLogging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{46dc5dcf-095f-4157-abed-fd6ae23720e0}\",\"name\":\"Microsoft.Windows.Cellcore.Settings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4d9aa417-945d-40b5-8f4a-9ca69802f825}\",\"name\":\"Microsoft.Windows.CellCore.Provisioning.ParserTask\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f3d10d5a-8291-433d-9275-cdd0067a0022}\",\"name\":\"MBBSettingUX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{46dc5dcf-095f-4157-cded-fd6ae33720e0}\",\"name\":\"Microsoft.Windows.Cellcore.MBMediaManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{569a031f-3540-46e0-96d4-fb94164a99c7}\",\"name\":\"Microsoft.Windows.Cast.MiracastReceiver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{206ba7a1-88e8-4abb-b6b8-28937e82c72b}\",\"name\":\"Microsoft.Windows.MediaFoundation.HEIFReader\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{85e2da35-d4fe-5a85-0874-ed763688fd59}\",\"name\":\"Microsoft.Windows.MediaFoundation.MPEG4Source\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bf5f1ee5-5dc0-4836-9f23-889294c42a54}\",\"name\":\"Microsoft.Windows.DeviceManager.DiagnosticsTool\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8279ba28-466f-46ac-9bf5-27e97c2a4f95}\",\"name\":\"Microsoft.Windows.DeviceManagement.Migration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{870ac05a-7777-5c66-c3f0-c1f6b7129ef6}\",\"name\":\"Microsoft.Windows.Messaging.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{27df94e7-11d1-58e5-885d-f1969b998936}\",\"name\":\"Microsoft.Windows.MediaFoundation.ASFSource\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c715453b-5d50-4ed1-8304-2ffca01cbd00}\",\"name\":\"Microsoft.Windows.Capture.MFCaptureEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5100ef35-4747-4d3f-92a1-4ed6d661c3fb}\",\"name\":\"Microsoft.Windows.MediaFoundation.SAR\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8aef5633-dae7-43e9-bd1d-c620598e56d0}\",\"name\":\"Microsoft.Windows.MediaFoundation.UVC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{736ec865-856c-4c63-bd9d-15eb85634c42}\",\"name\":\"Microsoft.Windows.MediaFoundation.DeviceSource\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9ee22e19-9672-4625-a9ff-c2b711ad923f}\",\"name\":\"Microsoft.Windows.CameraDebug\",\"group\":\"\"},{\"guid\":\"{6ade59e8-a7c0-53d6-c3e0-8fe89759ca13}\",\"name\":\"Microsoft.Windows.MediaFoundation.MediaSession\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4d0b22c3-3b49-5af6-ba09-0a1cda1083c4}\",\"name\":\"Microsoft.Windows.MediaFoundation.MFDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{deb6de00-a0cb-5689-f9f9-f26cb3970205}\",\"name\":\"Microsoft.Windows.MediaFoundation.H264Encoder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8f7e7a5e-6559-4718-9a21-f833e25c2ad1}\",\"name\":\"Microsoft.Windows.DShow.MFproxy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c6f749c6-fbe8-5c8d-f3b1-aca1563d7be3}\",\"name\":\"Microsoft.Windows.MediaFoundation.MP3Source\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b5f30508-38bb-5033-4f81-7de7fe7c4369}\",\"name\":\"Microsoft.Windows.MediaFoundation.MSE\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3e72573a-5c5f-5ed8-d6f1-f1b44db1b81b}\",\"name\":\"Microsoft.Windows.MediaFoundation.MediaEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4f4ac2ca-3a70-5f37-3f2c-2cb11f16b596}\",\"name\":\"Microsoft.Windows.MediaFoundation.MKVSource\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{645a72a6-1657-53bb-d5e7-d6526033ef20}\",\"name\":\"Microsoft.Windows.MediaFoundation.SourceResolver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{905a29f8-4571-4926-9be1-cbffce287814}\",\"name\":\"Microsoft.Windows.MediaFoundation.ContentProtectionDevice\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fbdc4594-a4a9-5f04-af86-7bd18a7938b9}\",\"name\":\"Microsoft.Windows.MediaFoundation.CodecAppSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6b4e98da-b103-588e-d0db-c7a111582066}\",\"name\":\"Microsoft.Windows.MediaFoundation.TelemetrySession\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{86bf288b-fe8c-4174-98aa-0ea625a0bea6}\",\"name\":\"Microsoft.Windows.MediaFoundation.SourceReader\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ca1d0166-619f-4177-a6c5-6faae46b42ef}\",\"name\":\"Microsoft.Windows.MediaFoundation.SinkWriter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d4356983-5d0d-43c3-84bf-9d2288b7c46b}\",\"name\":\"Microsoft.Windows.MediaFoundation.SensorGroup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{603bc3ed-ad38-4d30-beb0-36721b0532fe}\",\"name\":\"Microsoft.Windows.MediaFoundation.AVISource\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d63aebf8-bec4-4e76-8f7c-9565792ac782}\",\"name\":\"Microsoft.Windows.MediaFoundation.OTA\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fc40bb95-722a-5366-9c5e-1a73d989faea}\",\"name\":\"Microsoft.Windows.MediaFoundation.SVR\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f10f4696-dd8a-40f0-90be-cd013d0db9c7}\",\"name\":\"Microsoft.Internal.Management.AutoPilot.Reset\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2aee48b8-f498-4f2e-a2a2-898665db5c3e}\",\"name\":\"Microsoft.Windows.Bluetooth.Gap\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cd40e783-2e71-5f1f-0618-d8bb43779841}\",\"name\":\"Microsoft.Windows.Bluetooth.GattInterface\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a43eaa00-d8fa-5b2a-afce-1b6dd39164f1}\",\"name\":\"Microsoft.Windows.Bluetooth.GattServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5e35e3be-9005-567f-e2c8-071b4f985b0a}\",\"name\":\"Microsoft.Windows.Bluetooth.GattClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fa5fd884-8804-4a36-98b8-70bfc46a9fa2}\",\"name\":\"Microsoft.Windows.Bluetooth.Proximity\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1adab660-a3f8-5f4a-276b-743d455464ee}\",\"name\":\"Microsoft.Windows.Bluetooth.LooselyCoupledDevices\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7bd2c7f4-6671-474e-bdfc-2d141a0b6b7e}\",\"name\":\"Microsoft.Windows.Bluetooth.QuickPair\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9eb494cd-1f06-5384-c8d8-98c3377fce89}\",\"name\":\"Microsoft.Windows.Bluetooth.Battery\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6e7c0f27-9cce-4d40-be33-5d2a6e8ac1d7}\",\"name\":\"Microsoft.Windows.Graphics.Display.DisplayEnhancementService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ae5c851e-b4b0-4f47-9d6a-2b2f02e39a5a}\",\"name\":\"Microsoft.Windows.Sensors.SensorService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5836994d-a677-53e7-1389-588ad1420cc5}\",\"name\":\"Microsoft.Windows.MicrosoftAccount.TBProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d758d01c-7402-5923-6a27-44bdcc59a5c5}\",\"name\":\"Microsoft.Windows.Print.ApMonPortMig\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6c9882ca-4e51-4151-80d6-5ce43f5de6f9}\",\"name\":\"Microsoft.Windows.AppMan.Migration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{af9fb9df-e373-4653-84ce-01d8857e79fd}\",\"name\":\"Microsoft.Windows.AppxMigrationPlugin\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e915be71-5b71-4085-aa94-c87eacfc9812}\",\"name\":\"Microsoft.Windows.Das.Migration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{59e1d975-a9fd-4346-89b4-393432554a1a}\",\"name\":\"Microsoft.Windows.Maps.Migration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{44e18db2-6cfd-4a07-8fe7-6073794c531a}\",\"name\":\"Microsoft.Windows.Search.Indexer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1153a52e-8d1c-4e78-b7e3-da3db836bc4c}\",\"name\":\"Microsoft.Windows.MigrationCore\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{4587e014-39e2-4150-9246-6264f9b719f2}\",\"name\":\"MigrationCoreTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c6f68dc2-8899-4011-b91f-817adad30372}\",\"name\":\"Microsoft.Windows.Networking.RAS.MediaManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7794a8f9-8482-4396-aa2c-2ab8ef51b6b0}\",\"name\":\"Microsoft.Windows.Networking.RAS.Manager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45902de3-6d95-4a35-a37e-862215252640}\",\"name\":\"Microsoft.Windows.Networking.VPNPlugin\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{79eebe3e-aab1-4639-94c8-05a1706a6417}\",\"name\":\"Microsoft.Windows.Networking.RAS.Dialer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{542f2110-2c0f-40d7-aa35-3309fe74b8ae}\",\"name\":\"Microsoft.Windows.Networking.VPNPlugin.Manager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aba0b84d-4ead-4dc0-84df-08d439679dec}\",\"name\":\"Microsoft.Windows.Cast.MiracastReceiverConnection\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9282168f-2432-45f0-b91c-3af363c149dd}\",\"name\":\"Microsoft.Windows.Storage.MiSpace\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{65ec0768-c3b4-4e64-8df8-690b3715eae4}\",\"name\":\"Microsoft.Windows.Storage.PmUtil\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{98a749a0-6ab8-473f-b063-cf91708967c0}\",\"name\":\"Microsoft.Windows.RecommendedTroubleshootingService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{08fd7da7-ef4e-4566-8852-9483e46167e7}\",\"name\":\"Microsoft.Windows.ExploitGuard.ExploitProtection\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a6ace3c3-f77c-4ccd-9251-3253574da413}\",\"name\":\"Microsoft.Windows.ImageMitigationPolicy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{964912bd-6dbc-45ed-bf5d-e3f1664f1227}\",\"name\":\"Microsoft.Windows.RecommendedTroubleshootingScanner\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9163b919-4ebc-4a39-ab6a-021eb17d8256}\",\"name\":\"Microsoft.Windows.Holographic.StageManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cae82c8b-0097-4c53-9d72-f56d14c1284f}\",\"name\":\"Microsoft.Windows.Shell.HolographicFirstRun\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{35deaa03-7bea-4c77-b07a-8f20d3dfd884}\",\"name\":\"Microsoft.Windows.Mirage.Capture.Pipeline\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{72e9b8d0-434d-4f50-9dcc-e6dfc9df2b63}\",\"name\":\"Microsoft.Windows.WinXrProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a076f707-4472-5083-d14f-826d0ef75c78}\",\"name\":\"Microsoft.Windows.Audio.MultimediaDevice\",\"group\":\"\"},{\"guid\":\"{367c9044-75e0-5320-cc3c-8a40ffc6b4f6}\",\"name\":\"Microsoft.Windows.Mapi.MMGA\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{202b7a5a-5a34-566e-c4dd-38bd60ea7aec}\",\"name\":\"Microsoft.Windows.Audio.MMSysCpl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{84f43c05-a677-41d6-a00e-c74d54fcb5c6}\",\"name\":\"Microsoft.Windows.Audio.MMSysCpl.APODiagnostics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aa6f6a10-8a13-417d-8799-52361684bd76}\",\"name\":\"Microsoft.Windows.ForegroundManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6eaa8566-66f9-5c32-c995-05cbb0b423ac}\",\"name\":\"Microsoft.Windows.LifetimeManager.AppStateTransition\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{59dd67cc-7ce1-52f8-cf74-fe8a257a2b6b}\",\"name\":\"Microsoft.Windows.Update.Orchestrator.Worker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f697aea-5499-5c54-ae6e-e1489d0a252f}\",\"name\":\"Microsoft.Windows.Update.Orchestrator.WuProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5eb60b36-6206-5538-e60a-0a7af8a1e59d}\",\"name\":\"Microsoft.Windows.Security.Mpr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1e81ad7a-603a-4c44-b3b6-c99bb22f13bf}\",\"name\":\"Microsoft.Windows.Networking.RAS.Routing.SSTP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{684d8f73-f09d-4163-8797-bc32201c94c1}\",\"name\":\"Microsoft.Windows.Networking.RAS.RASServer.AgileVPN\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{68f4bcbe-cfe7-4b57-8d58-f18b0145a5bb}\",\"name\":\"Microsoft.Windows.Networking.RAS.RASServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9fd2b528-8d3d-42d0-8fdf-5b1998004278}\",\"name\":\"Microsoft.Windows.Networking.RAS.Routing.BGP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{02f64aa0-ebba-4af8-bdf4-196224230dea}\",\"name\":\"Microsoft.Windows.Networking.RAS.RASServer.Ddm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d1bc9aff-2abf-4d71-9146-ecb2a986eb85}\",\"name\":\"Microsoft.Windows.Firewall\",\"group\":\"\"},{\"guid\":\"{d76203c4-8c1b-4e53-afab-c22865594f3f}\",\"name\":\"Microsoft.Windows.Firewall\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{07b7592c-a848-4520-89da-1ab26bc4629f}\",\"name\":\"Microsoft.Windows.Networking.EDP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{702bb771-f6f6-4b08-adaf-42abe09b4fd1}\",\"name\":\"Microsoft.Windows.Firewall.Aggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{19c13211-dec8-42d5-885a-c4cfa82ea1ed}\",\"name\":\"Microsoft.Windows.Mrt.Runtime\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{78f5cb32-81c4-476b-a93b-f5d90226ce9b}\",\"name\":\"Microsoft.Windows.Print.MS3DPrintShellExtension\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fc9c931e-ac21-5b7d-df8f-00d6bad5a055}\",\"name\":\"Microsoft.Windows.AllJoyn.MSAJApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4ed997f7-7c3c-5223-fae4-8234d198805c}\",\"name\":\"Microsoft.Windows.AllJoyn.MSAJDeprecated\",\"group\":\"\"},{\"guid\":\"{0410d3ad-d839-4a75-9698-e6a9b4121bdc}\",\"name\":\"Microsoft.Windows.Graphics.WindowsColorSystemDiagnostics\",\"group\":\"\"},{\"guid\":\"{10706d4f-ca0a-47aa-b093-5b5218a6308c}\",\"name\":\"Microsoft.Windows.Graphics.WindowsColorSystem\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1f869e8f-86a0-5e3d-b81b-1100a9a3e9ed}\",\"name\":\"Microsoft.Windows.Msconfig\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4f6a3c95-b86c-59f7-d8ed-d5b0b6a683d6}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.TextServiceFramework\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f7febf94-a5f7-464b-abbd-84a042681d00}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.ThreadInputManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{86df9ee3-15c5-589d-4355-17cc2371dae1}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.TabNavigation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{78eba95a-9f43-44b0-8391-6992cb068def}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.MsCtfIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{85b47a68-9cfa-58dc-2b4b-2f34c92b3f33}\",\"name\":\"Microsoft.Windows.Diagnostics.Troubleshooter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d1f34f0a-968b-4e6f-bb35-d818ecfebbab}\",\"name\":\"MsdtcTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6b0310a6-0ff4-47d2-a554-a1bb260f9617}\",\"name\":\"Microsoft.Windows.MediaFoundation.FlacDecoder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5936f777-a7a8-4460-91e1-b430d5aeeb7f}\",\"name\":\"Microsoft.Windows.Analog.SpeechAudio.IgneousOemDll\",\"group\":\"\"},{\"guid\":\"{0dac61c4-db90-49b5-a5a3-b25428fe20ef}\",\"name\":\"Microsoft.Windows.Shell.StreamLib\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1cba82b8-2b26-4d68-8447-1a3b85805b6a}\",\"name\":\"Microsoft.Windows.Darwin\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b229a04f-29db-496f-97aa-10fa9c5844ba}\",\"name\":\"Microsoft.Windows.Diagnostics.Resolver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{44484773-a039-5c4a-d95c-2c23f586497c}\",\"name\":\"Microsoft.Windows.MediaFoundation.MPEGDecoder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b71ee1de-b092-4737-a55f-ecdf2e70e6be}\",\"name\":\"Microsoft.Windows.MediaFoundation.H264Decoder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63e17c10-2d43-4c42-8fe3-8d8b63e46a6a}\",\"name\":\"Microsoft.Windows.MediaFoundation.OpusDecoder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f9c4d0a2-8a7d-4d66-8f88-5839d7adc35a}\",\"name\":\"Microsoft.Paint\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2aa2b8df-8a4e-52a7-8cc7-c72f28293393}\",\"name\":\"Microsoft.Windows.Capture.Photography\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9cac2d9b-e081-4ab7-8c3e-30d117bcef93}\",\"name\":\"Microsoft.Windows.MediaFoundation.RAWImageDecoder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{227c0c3b-d0fd-5d7c-6556-64ef86b2b065}\",\"name\":\"Microsoft.Windows.Globalization.Spelling\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c000e9ae-71f9-426e-a1c2-c78ff53284bf}\",\"name\":\"Microsoft.Windows.Search.Indexer.Aggregated\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{76de1e7b-74d9-585f-1f85-affa9242808c}\",\"name\":\"RDWin32ClientTelemetryProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{61dd194a-b8cb-4de5-a018-4c7f6f9e9988}\",\"name\":\"RDP.MSTSCTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{55184039-1cbe-4d35-9f9e-85d0075943df}\",\"name\":\"Microsoft.RDS.RADC.FeedSubscription\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{660cfa71-2a70-4e80-bdf3-f1424919d01c}\",\"name\":\"Microsoft.RDS.RdClient.Client.FeedSubscription\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a8f457b8-a2b8-56cc-f3f5-3c00430937bb}\",\"name\":\"RDP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8a633d91-8b07-4aae-9a00-d07e2afd29d6}\",\"name\":\"RDP.Transport\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d953b8d8-7ea7-44b1-9ef5-c34af653329d}\",\"name\":\"RDP.Graphics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{76de1e7b-74d5-575e-1f81-4ffe6a42777b}\",\"name\":\"RDWin32ClientAxTelemetryProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7756e5a6-21b2-4c40-855e-88cf2b13c7cb}\",\"name\":\"RDP.MSTSCAXTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{50134cdd-5fe1-4315-8c8d-50900921acce}\",\"name\":\"Microsoft.Windows.HVSI.RDP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{43471865-f3ee-5dcf-bf8b-193fcbbe0f37}\",\"name\":\"Microsoft.Windows.RemoteDesktopServices.RailPlugin\",\"group\":\"\"},{\"guid\":\"{c371b421-5986-5edc-75b8-bc21c0f8ee81}\",\"name\":\"Microsoft.Windows.MediaFoundation.VP9Redirect\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d5cc9846-9cd8-5306-dece-438825703e54}\",\"name\":\"Microsoft.Windows.MediaFoundation.XVP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9418ddd4-7689-5fbd-8ef1-0165d5a465f2}\",\"name\":\"Microsoft.Windows.Shell.MtcModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e84c7b24-903b-5eff-05b5-7006f2843ceb}\",\"name\":\"Microsoft.Windows.ShellActivationHelpers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{393ff4cc-f02d-5d0a-4180-b79bf8da529d}\",\"name\":\"Microsoft.Windows.Shell.MTF.Platform\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2d40087a-5ee9-569d-2c30-d2b248a24986}\",\"name\":\"Microsoft.Windows.TextInput.FuzzyDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d059a021-6947-44fb-976a-b18c9b73d1d8}\",\"name\":\"Microsoft.Windows.Update.Ux.MusNotification\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3076679b-a75c-4705-aaa4-836903b93875}\",\"name\":\"Microsoft.Windows.Update.Orchestrator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e77a560c-3696-4ac0-911c-545ceca6be3c}\",\"name\":\"Microsoft.Windows.Update.NotificationUx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ac7009a2-c62e-471e-ae10-da51e87873b3}\",\"name\":\"Microsoft.Windows.Update.Ux.NotifyIcon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cee50f59-e321-4691-9bb7-9b75494f6aab}\",\"name\":\"Microsoft.Windows.Update.Ux.MusUpdateSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2e1fdc26-4250-4850-82d8-2aef9eafa3b8}\",\"name\":\"Microsoft.Windows.Accessibility.NarratorHome\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c632d944-dddb-599f-a131-baf37bf22ef0}\",\"name\":\"Microsoft.Windows.Security.NaturalAuth.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{26b30c9e-d524-5a0c-8cf2-29989c8175f7}\",\"name\":\"Microsoft.Windows.Desktop.NaturalLanguage6\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63ac12d9-f21b-402d-bd67-8e415aa896aa}\",\"name\":\"Microsoft.Windows.Networking.NCA\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2ab7abe2-fd6b-49dd-931e-d3339832676a}\",\"name\":\"NcbService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e85be3ac-efac-4ef3-873b-7b96c0fe4bc2}\",\"name\":\"Microsoft.Windows.Shell.NcdAutoSetup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1701c7dc-045c-45c0-8cd6-4d42e3bbf387}\",\"name\":\"NCSI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6a586350-e749-49d6-a5b7-855290398c6b}\",\"name\":\"Microsoft.Windows.NDF.PushButtonReset\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2f3250c8-5d7e-5c11-2878-e2d179234c10}\",\"name\":\"Microsoft.Windows.Networking.NetCfgExe\",\"group\":\"\"},{\"guid\":\"{3c70d3e6-40c8-5875-67f3-ad429a730a44}\",\"name\":\"Microsoft.Windows.Diagnostics.Troubleshooter.Networking.NetCoreHC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3192497f-bb99-5aa1-10aa-680f4aa2eee2}\",\"name\":\"Microsoft.Windows.Diagnostics.Troubleshooter.Networking\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{29f455e5-659d-55c6-175b-0892a5ba91fe}\",\"name\":\"Microsoft.Windows.Networking.NetSetup.Inf\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8ee5c621-4160-5b85-8d78-0979b332de9e}\",\"name\":\"Microsoft.DotNet\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{30a1cf02-27aa-4ef7-b34c-59c36eaba123}\",\"name\":\"Microsoft.Windows.Shell.NetworkId\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9d9f8d9d-81f1-4173-a667-4c54a4831dba}\",\"name\":\"Microsoft.Windows.Shell.NetPlWiz\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ea289c62-8c36-4904-9726-15ecd282aed5}\",\"name\":\"Microsoft.Windows.NetworkListManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{819cf413-40ea-5e76-0bc1-b5f26ebf7075}\",\"name\":\"Microsoft.Windows.WiFiCloudStore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{205ce500-a543-56a2-7b6a-67ba089f67dc}\",\"name\":\"Microsoft.Windows.Networking.NetSetup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a111f1c3-5923-47c0-9a68-d0bafb577901}\",\"name\":\"Microsoft.Windows.Networking.NetworkSetup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a111f1cb-5923-47c0-9a68-d0bafb577901}\",\"name\":\"Microsoft.Windows.Networking.NetworkSetupShim\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a111f1cc-5923-47c0-9a68-d0bafb577901}\",\"name\":\"Microsoft.Windows.Networking.NetworkSetupSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ab7df27d-f8d1-546b-9ba0-1ecfe7b3fc3a}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.HandlersBase\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3eae2ac8-6b77-5d53-4e2c-7ad87c16259b}\",\"name\":\"Microsoft.Windows.OneSync.NetworkHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{339817cf-d7a8-4114-94b2-a240843d77ee}\",\"name\":\"Microsoft.Windows.NetworkUx.SettingsHandler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{46dc5dcf-096e-4157-abed-fd6ae23721e1}\",\"name\":\"Microsoft.Windows.Cell.SettingsHandler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3a245d5a-f00f-48f6-a94b-c51cdd290f18}\",\"name\":\"Microsoft-Windows-Desktop-Shell-SystemSettingsV2-Handlers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{40983cc0-15bb-4de7-b8c2-391c0528399c}\",\"name\":\"Microsoft.Windows.Provisioning.Plugin.NFC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45fc65fc-f770-5ad6-c9bf-683f122184a9}\",\"name\":\"Microsoft.Windows.Provisioning.PluginNFC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cac8d861-7b16-5b6b-5fc0-85014776bdac}\",\"name\":\"Microsoft.Windows.Security.NGC.CredProv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0aba6892-455b-551d-7da8-3a8f85225e1a}\",\"name\":\"Microsoft.Windows.Security.NGC.NgcCtnr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9df6a82d-5174-5ebf-842a-39947c48bf2a}\",\"name\":\"Microsoft.Windows.Security.NGC.NgcCtnrSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c0b2937d-e634-56a2-1451-7d678aa3bc53}\",\"name\":\"Microsoft.Windows.Security.Ngc.Truslet\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cdc6beb9-6d78-5138-d232-d951916ab98f}\",\"name\":\"Microsoft.Windows.Security.NGC.NgcIsoCtnr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b66b577f-ae49-5ccf-d2d7-8eb96bfd440c}\",\"name\":\"Microsoft.Windows.Security.NGC.KspSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3b9dbf69-e9f0-5389-d054-a94bc30e33f7}\",\"name\":\"Microsoft.Windows.Security.NGC.Local\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9b223f67-67a1-5b53-9126-4593fe81df25}\",\"name\":\"Microsoft.Windows.Security.NGC.KeyStaging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{89f392ff-ee7c-56a3-3f61-2d5b31a36935}\",\"name\":\"Microsoft.Windows.Security.NGC.CSP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9d4ca978-8a14-545e-c047-a45991f0e92f}\",\"name\":\"Microsoft.Windows.Security.NGC.Recovery\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c3feb5bf-1a8d-53f3-aaa8-44496392bf69}\",\"name\":\"Microsoft.Windows.Security.DevCredSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a7f923a4-8693-4876-92f4-4ff49791d3cf}\",\"name\":\"PenTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6ff5771a-f64e-473f-a2e8-4654c218ff3a}\",\"name\":\"NLA\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eb3540f2-1909-5d51-b72d-a3ecb0b9bf08}\",\"name\":\"Microsoft.Windows.Shell.NotificationController\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{487905a0-9830-4d41-ba68-e3325affa8c2}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.AumidNotifications\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f1f31e13-d7aa-438c-ab17-9e435309f5ef}\",\"name\":\"Microsoft-Windows-Shell-CortanaNotifications\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{883b9247-ab6e-5068-59bb-eeb519d551b6}\",\"name\":\"Microsoft.Windows.Shell.NowPlayingSessionManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c127316f-7e36-5489-189a-99e57a8e788d}\",\"name\":\"Microsoft-Windows-Explorer-ThumbnailMTC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7b52746e-241b-52c9-8f0b-4e5e25e54507}\",\"name\":\"Microsoft.Windows.Shell.BaseProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f9fdd5a0-85ea-46bd-a4ba-fbeec97c558c}\",\"name\":\"CentennialIssueTrackerTraceLogging\",\"group\":\"\"},{\"guid\":\"{a99b2eb4-5620-44f5-9b02-f9d2eebf2e96}\",\"name\":\"Microsoft.Windows.Kernel.LibLoader\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c0834da2-8abe-478f-848c-1da4cbe18daf}\",\"name\":\"Microsoft.Windows.Kernel.VsmEnclaveLoader\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{540dc156-e9d6-42dc-a225-29794149a495}\",\"name\":\"MuiResourceLoaderTraceLogging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{27a8fdf4-9b77-575b-be3b-e7163ef159bb}\",\"name\":\"Microsoft.Windows.Security.Capabilities\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f0cd5b06-08c0-5ce4-09c2-17ba421985a0}\",\"name\":\"Microsoft.Windows.Heap\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e9eaf418-0c07-464c-ad14-a7f353349a00}\",\"name\":\"Microsoft.Windows.Kernel.Registry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{252d9ecc-1c9f-4917-8760-f872a83bf018}\",\"name\":\"Microsoft.Windows.Containers.RegistryVirtualization\",\"group\":\"\"},{\"guid\":\"{73a33ab2-1966-4999-8add-868c41415269}\",\"name\":\"IumTelemetryProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a4d16fc5-d1cf-4d72-a055-25f3eb02a70e}\",\"name\":\"Microsoft.Windows.Kernel.LiveDump\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a9fdf37b-d72d-4051-a3cd-d422103ce079}\",\"name\":\"Microsoft.Windows.Kernel.SysEnv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c8bde9ff-f31f-59dc-6c27-ca37c516ada5}\",\"name\":\"Microsoft.Windows.Kernel.DeviceConfig\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{6c0ebbbb-c292-457d-9675-dfcc1c0d58b0}\",\"name\":\"Microsoft.Windows.Kernel.PnP\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{7e9e8b9c-406c-5d73-e566-0f50ea3ade3e}\",\"name\":\"Microsoft-Windows-Kernel-Mm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63bca7a1-77ec-4ea7-95d0-98d3f0c0ebf7}\",\"name\":\"Microsoft.Windows.Kernel.Power\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5e753e4d-2b0d-4451-b8f9-0f1253ca0b44}\",\"name\":\"Microsoft.Windows.Kernel.Ttm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c59673d8-b796-58df-fbf8-a70bad656dca}\",\"name\":\"Microsoft.Windows.Kernel.ProcessSubsystem\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{09a69a38-2680-4bfa-ad01-792ad63a4ff2}\",\"name\":\"Microsoft.Windows.Kernel.Security\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7614521c-4d0b-4341-bfc9-873082c0f1d3}\",\"name\":\"KernelGeneral\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2839ff94-8f12-4e1b-82e3-af7af77a450f}\",\"name\":\"KernelProcess\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1dd9b8c9-e078-4075-b9de-4e5125071a18}\",\"name\":\"MSTelCov\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{47122234-f9f1-54ea-acd0-514d58e00b7f}\",\"name\":\"WheaProvider\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{70cfefa3-edb1-5f09-aa78-047998973db4}\",\"name\":\"Microsoft.Windows.Print.ClassInstaller\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2446bc6d-2a96-5948-96ba-db27816dee43}\",\"name\":\"Microsoft.Windows.Shell.SharingWizard\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{59a3be04-f025-4585-acfc-34456b550813}\",\"name\":\"Microsoft.Windows.Shell.Edp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f01756f1-23c4-5663-6e27-5cb7e7942ad2}\",\"name\":\"Microsoft.Office.Deployment.OfficeCsp\",\"group\":\"\"},{\"guid\":\"{86613b65-e02d-4de7-bce3-21e902fd29f7}\",\"name\":\"OleClipboardAggregateTelemetryProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3e0e3a92-b00b-4456-9dee-f40aba77f00e}\",\"name\":\"Microsoft.Windows.OLE.Clipboard\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{60a245d2-73de-4604-9a9c-65ca7a964e8c}\",\"name\":\"Microsoft.Windows.OLE.DragDrop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{acca0101-ae51-4d60-a32a-552a6b1deabe}\",\"name\":\"Microsoft-Windows-DeviceManagement-OmaDmAgent\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0616f7dd-722a-4df1-b87a-414fa870d8b7}\",\"name\":\"Microsoft.Windows.ConnectionManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0db63167-77d2-441d-a793-6e09ba63213b}\",\"name\":\"Microsoft-Windows-OneBackup-BackupPage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ab0d8ef9-866d-4d39-b83f-453f3b8f6325}\",\"name\":\"Microsoft.Windows.Networking.OneX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5391f591-9ca5-5833-7c1d-ad0ddec652cd}\",\"name\":\"Microsoft.Windows.Desktop.Shell.MachineOOBE\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c88c00d7-79f4-4497-a643-83fcc9919feb}\",\"name\":\"MicrosoftWindowsNetworkVANUx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2cfa8474-fc39-51c6-c0ac-f08e5da70d91}\",\"name\":\"Microsoft.Windows.Shell.Desktop.FirstLogonAnim\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{41cdc74d-743f-40b4-aa86-0ad4bc36f48d}\",\"name\":\"Microsoft.Windows.Setup.SetupCleanupTask\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{acd8e438-4bfa-430e-90f6-969391cd6bad}\",\"name\":\"Microsoft.Windows.Setup.FastCleanUp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4b169449-0220-55f8-5c6b-ca7a796cf33a}\",\"name\":\"Microsoft.Windows.Shell.UserOOBE\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d960cb7-fb14-5ed4-95fd-4d157414ecdb}\",\"name\":\"Microsoft.Windows.Desktop.Shell.OOBEMonitor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{51c51397-43c4-5c86-645c-acbd5b2e1038}\",\"name\":\"Microsoft.Windows.Graphics.OpenGL\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dd838180-d462-534c-0e3a-336e653bbe84}\",\"name\":\"Microsoft.Windows.Accessibility.Osk\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1a63cde8-f2fe-497c-9624-5a1cd2e950a6}\",\"name\":\"Microsoft.Windows.PasswordEnrollmentManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{edb51732-0ab7-4b34-a37b-e88724c10e6e}\",\"name\":\"Microsoft.Windows.ExploitGuard.PayloadRestrictions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{511a5c98-b374-446e-9625-108624a3ccaa}\",\"name\":\"Microsoft.Windows.Compatibility.PCA\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{95abb8af-1790-48bd-85ac-5feed398dd9e}\",\"name\":\"Microsoft.Windows.PCA.Siuf\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{407c75ac-661f-4c74-a4b0-acdd9a643e42}\",\"name\":\"Microsoft.Windows.PCA.PushApphelp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{21c36b70-7cda-5bc2-09b3-92d7d0459faa}\",\"name\":\"Microsoft.Windows.Security.PlatformCryptoProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d428fa57-eb61-51ba-460e-d1a6f6b534b5}\",\"name\":\"MSFT_PCSVDeviceTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4b4bb6d4-e2f5-4ec9-9e14-5c55c24aebd1}\",\"name\":\"Microsoft.Windows.Networking.BranchCache\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{104d97cd-836b-5d83-835f-1f2a47ce02c5}\",\"name\":\"Microsoft.Windows.Analog.PerceptionSimulation.InputHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{22da0a2f-0ccd-4a16-b66b-1fde8362e11b}\",\"name\":\"Terminal-Services-TestCode\",\"group\":\"\"},{\"guid\":\"{6b5ecd17-6287-435f-9f5e-a47e2fc100b1}\",\"name\":\"Microsoft.Windows.Licensing.PhoneActivate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e08c85f4-c224-499d-b5b3-c1bce960f096}\",\"name\":\"Microsoft-Windows-Telephony-PhoneOm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7665d4fd-30eb-4ddc-9dc1-4ebab74ed98e}\",\"name\":\"Microsoft.Windows.Apps.CommsEnhancementRTProviders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b8020478-a6a8-42bb-9ede-b2d3ebf8da7c}\",\"name\":\"Microsoft.Windows.Apps.CallsRTProviders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d7afa934-92e9-4f14-98f2-62f2486c39fb}\",\"name\":\"Microsoft.Windows.Apps.PhoneProviders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1db8dad0-7ca6-4f18-b357-43bfdd8c9806}\",\"name\":\"Microsoft-Windows-Telephony-PhoneProviders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6892b716-cfea-4c82-9557-9c782e3f8c6c}\",\"name\":\"Microsoft.Windows.Apps.PhoneService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cbbbc22d-2efe-4eae-9af5-f9c6cf113670}\",\"name\":\"Microsoft-Windows-Telephony-PhoneService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cf82aecb-ffff-4049-bd5b-687734a5d519}\",\"name\":\"Microsoft.Windows.Apps.PhoneUtilsProviders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{04a490d4-84c6-4920-9c22-51c80825ff2c}\",\"name\":\"Microsoft-Windows-Telephony-PhoneUtil\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c306dbfe-1c7d-474a-98f6-4027ad1fb7ef}\",\"name\":\"Microsoft.Windows.Cast.Source\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2a3c1dcd-ddcb-41de-be16-e72df40ee8dd}\",\"name\":\"Microsoft.Windows.PrelaunchOptIn\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{521120e3-343e-42a2-bd71-a1b1ff655655}\",\"name\":\"Microsoft.Windows.Print.PmcSnap\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c0a23072-f5b1-4fd0-8e29-6b3d6a53a27b}\",\"name\":\"Microsoft.Windows.Das.Pnpx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{300284e3-9c2e-48bd-b281-5d80dd057068}\",\"name\":\"Microsoft.IoT.POS.BarcodeScannerProtocolProvider\",\"group\":\"\"},{\"guid\":\"{e3ac6ef2-620d-4ffd-bced-2ff0f4ec7ea6}\",\"name\":\"Microsoft.IoT.POS.CashDrawerProtocolProvider\",\"group\":\"\"},{\"guid\":\"{a1e769b6-694b-46d3-a804-3a5251d9527e}\",\"name\":\"Microsoft.IoT.POS.PrinterProtocolProvider\",\"group\":\"\"},{\"guid\":\"{64e05266-27b6-4f6b-ab9e-ab7cc9497089}\",\"name\":\"Microsoft.Windows.DeviceManagement.AdmxIngestion\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{981ea2ca-d29e-4ac4-a6c2-d4d3b13c400f}\",\"name\":\"Microsoft.Windows.WpdMtp.Api\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c3880ac9-4776-4776-b48d-0ae270f674ef}\",\"name\":\"PowerTroubleshooter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b5086f75-81ed-4487-8d0a-5e9114afc2e9}\",\"name\":\"Microsoft.Windows.Power.Troubleshooter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c1160d05-83a4-4285-b67a-cc3ba2e3e05f}\",\"name\":\"Microsoft.Windows.Power.PowercfgExe\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5e3a2768-2abc-5173-b92c-7e9b1cf94f00}\",\"name\":\"Microsoft.Windows.Shell.ControlPanel.PowerCpl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b793eafa-2323-429c-90d5-7628369be2cb}\",\"name\":\"Microsoft.Windows.LimitsManagement.Telemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{be5f8487-3a5d-4477-b0c2-020679b81e56}\",\"name\":\"Microsoft.Windows.Print.Workflow.Source\",\"group\":\"\"},{\"guid\":\"{fd6b6ae4-7563-550d-46a4-da9fe46cad57}\",\"name\":\"Microsoft-Windows-Print-Platform\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{82a4ba66-9b2a-44ac-a231-e9f719e1e471}\",\"name\":\"Microsoft.Windows.Print.Ui\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1bf554be-03c5-4f49-9b57-f3c0cbad589a}\",\"name\":\"Microsoft.Windows.Print.Workflow.Broker\",\"group\":\"\"},{\"guid\":\"{f69d3e6c-298b-466c-b84f-486e1f21e347}\",\"name\":\"Microsoft.Windows.Print.WorkFlowBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{92228b46-b5ea-5793-a5cb-7df7d97fa674}\",\"name\":\"Microsoft.Windows.Shell.PrintNotification\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9aed307f-a41d-40e7-9539-b8d2742578f6}\",\"name\":\"Microsoft.Windows.Shell.ProfAPI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{40654520-7460-5c90-3c10-e8b6c8b430c1}\",\"name\":\"Microsoft.Windows.ProfExt\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9891e0a7-f966-547f-eb21-d98616bf72ee}\",\"name\":\"Microsoft.Windows.Shell.UserProfiles\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9959adbd-b5ac-5758-3ffa-ee0da5b8fe4b}\",\"name\":\"Microsoft.Windows.ProfileService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7f1bd045-965d-4f47-b3a7-acdbcfb11ca6}\",\"name\":\"Microsoft.Windows.RoamingUserProfiles\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{32980f26-c8f5-5767-6b26-635b3fa83c61}\",\"name\":\"Microsoft.Windows.Shell.FileExplorer.Aggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b1642597-285e-560a-7f60-7e02f5da22c0}\",\"name\":\"Microsoft.Windows.Shell.Propsys\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3f220320-4c79-4e44-94ff-20b3ea0fe8a2}\",\"name\":\"Microsoft.Windows.ConnectionManager.Provisioning.Desktop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{42c60cea-0fe7-4541-a86b-9e11f95bd9bf}\",\"name\":\"Microsoft.Windows.Mobile.Provisioning.Datastore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a6a847b7-4429-49aa-bba6-2ad8c191ac8c}\",\"name\":\"Microsoft.Windows.Provisioning.Engine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0383d92c-2337-4f25-a0b5-a51767f04746}\",\"name\":\"Microsoft.Windows.Provisioning.Handlers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{00bb69fc-60bc-4502-9438-25608f375ccb}\",\"name\":\"Microsoft.Windows.Provisioning.CommandCsp\",\"group\":\"\"},{\"guid\":\"{16e12400-a2d8-44b7-9479-004568ec7819}\",\"name\":\"Microsoft.Windows.Provisioning.CSP\",\"group\":\"\"},{\"guid\":\"{26a5fa2c-2e24-4e93-83c8-8146b8fde527}\",\"name\":\"Microsoft.Windows.Autopilot.ForcedNetworkValue\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a630494a-2e71-4c50-89a4-0d6c09730e03}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.PackageProvisioning\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{08faccfa-125d-4ed6-b0b7-b4a1a912e693}\",\"name\":\"Microsoft.Windows.Provisioning.ProvLaunch\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a0af985e-83f9-4e1a-b658-338dcfe27893}\",\"name\":\"Microsoft.Windows.Provisioning.Migration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7f99598f-b2c1-4371-9911-63dee13b9eb1}\",\"name\":\"Microsoft.Windows.Provisioning.Operations\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b1f30020-8bc3-4888-bb1b-4dd681f24209}\",\"name\":\"Microsoft.Windows.Provisioning.Platform\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{55239d60-0eb6-495b-874e-15de5d5f9a70}\",\"name\":\"Microsoft.Windows.Provisioning.Plugin.Engine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{34ace569-6bc6-48e5-8e3a-96a6a720c9fb}\",\"name\":\"Microsoft.Windows.Provisioning.Sysprep\",\"group\":\"\"},{\"guid\":\"{2bf4b6ba-556e-4d05-8534-cafedf19fed8}\",\"name\":\"Microsoft.Windows.Provisioning.ProvTool\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{073c75a0-d07d-4203-9501-a91f2a239d55}\",\"name\":\"Microsoft.Windows.Networking.Proximity.Common\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0d770577-bb34-538f-9c4f-da99fb5df794}\",\"name\":\"Microsoft.Windows.Networking.Proximity.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f01f0926-8b2c-59e4-2c10-406613ca40e4}\",\"name\":\"Microsoft.Windows.Shell.Proximity\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4180c4f7-e238-5519-338f-ec214f0b49aa}\",\"name\":\"Microsoft.Windows.ResourceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f6a774e5-2fc7-5151-6220-e514f1f387b6}\",\"name\":\"Microsoft.Windows.HostActivityManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8215e965-d26e-548e-af0e-940c1f06f250}\",\"name\":\"Microsoft.Windows.CentralResourceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0001376b-930d-50cd-2b29-491ca938cd54}\",\"name\":\"Microsoft.Windows.ProcessStateManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{23218c03-d099-425a-8778-337a4ddc7ba9}\",\"name\":\"Microsoft.Windows.ProcessStateManager.Refcount\",\"group\":\"\"},{\"guid\":\"{f4b9ce38-744d-4916-b645-f1574e19bbaa}\",\"name\":\"Microsoft.Windows.PushToInstall\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c6f85d1f-fb7c-7520-dd4f-de67239f3d46}\",\"name\":\"Microsoft.Windows.WindowsToGo.Startup.Options\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{54bd41e0-189f-6f3b-b495-1e4aa4975198}\",\"name\":\"Microsoft.Windows.WindowsToGo.Creator.Tool\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1d99a835-42bc-5bef-a10b-caae0d54fd0f}\",\"name\":\"Microsoft.Windows.MediaFoundation.DVDNav\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e021c29e-7473-4952-b897-618c19a78a41}\",\"name\":\"Microsoft-Windows-BITS-Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9a010476-792d-57be-6af9-8de32164f021}\",\"name\":\"Microsoft.Windows.DirectShow.FilterGraph\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c7b89fc6-5c99-56f4-2b2e-c536b212904d}\",\"name\":\"QuickActionsDataModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b5a91f26-4c1e-5ad1-ecd2-9e49e349f773}\",\"name\":\"Microsoft.Windows.Shell.QuickActionsDataModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{91558f59-b78a-4994-8b64-8067b33bdd71}\",\"name\":\"Microsoft.RemoteAssistance\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7145abf9-99f5-4ccf-a2b6-c9b2e05ba8b3}\",\"name\":\"Microsoft.Windows.Shell.NotificationQuietHours\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{06c071f2-6c59-5d55-6b31-1578dd063ddc}\",\"name\":\"EAPRasTlsEvents\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{de441ffa-fafa-4495-977f-2e9d2509746d}\",\"name\":\"Microsoft-Windows-Sysmain-Prefetch\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ca341b3c-b9d2-4d0f-9bd3-d88183596db9}\",\"name\":\"RDP.ServerStack.Diagnostics\",\"group\":\"\"},{\"guid\":\"{78be48bd-5d52-4e39-823d-226cd5551f37}\",\"name\":\"RDP.ServerStack\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{20928097-faf7-47fb-9e7c-3a251f0936e8}\",\"name\":\"RDP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4a49afe3-776e-467a-aca0-71f9c6c8499f}\",\"name\":\"Microsoft.Windows.RemoteDesktop.RAIL.RdpInit\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dc1a94a6-0a1a-433e-b470-3c72353b7309}\",\"name\":\"Microsoft.Windows.RemoteDesktop.RAIL.Server.Diagnostics\",\"group\":\"\"},{\"guid\":\"{f115ddaf-e07e-4b15-9721-427134b41eba}\",\"name\":\"RDP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{39825ffa-f1b4-41b7-8221-20d4b8dbe57e}\",\"name\":\"Microsoft.Windows.RemoteDesktop.RAIL.RdpShell\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d2e990da-8504-4702-a5e5-367fc2f823bf}\",\"name\":\"AUInstallAgent\",\"group\":\"\"},{\"guid\":\"{9512fdbc-24e6-44fa-a8a3-af44d3447216}\",\"name\":\"RDP.Graphics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{37e6b6cc-3f66-5c13-b9f8-574cfb014a9e}\",\"name\":\"Microsoft.Windows.Audio.Client.Plugin\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4263c286-3c4f-56c8-3fe2-cc0331449b53}\",\"name\":\"Microsoft-Windows-Shell-RetailDemo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e305fb0f-da8e-52b5-a918-7a4f17a2531a}\",\"name\":\"Microsoft.Windows.Shell.DefaultAssoc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{04e7bad5-f665-4f6e-9678-80646a3201ad}\",\"name\":\"Microsoft.Windows.WinRE.Agent\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2c2e6508-9c83-4104-a93b-2336375f6932}\",\"name\":\"Microsoft.Windows.RecoveryDrive\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f9a81f79-369b-443c-9428-fc1dd98316f6}\",\"name\":\"Microsoft.Windows.FileSystem.ReFSUtil\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3ea8eaef-db33-4f2e-bb7c-ef7ad091a0f2}\",\"name\":\"Microsoft.Windows.Kernel.Registry.FromApp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{edf12a85-835b-4f0c-9391-e43cb0e4d94a}\",\"name\":\"Microsoft.Windows.RalmProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fe73c339-a194-4cef-8982-6ac1f094d6e4}\",\"name\":\"Microsoft.OSG.IoT.Pos.RemotePosWorker\",\"group\":\"\"},{\"guid\":\"{b55883e6-6c45-45c2-ab9d-800bb7b66b15}\",\"name\":\"Microsoft.Windows.Provisioning.Plugin.RemovableMedia\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{39aee73c-51b7-5af1-99f7-96d1e9f3bcad}\",\"name\":\"Microsoft.Windows.Shell.DeviceCenter.ContextHandlers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cfd95a4e-cd5b-4f57-9eeb-fe9683e8e407}\",\"name\":\"Microsoft.BitLocker.BDERepair\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8af7296e-f7e8-5c1a-24a5-169c7a7e52ce}\",\"name\":\"Microsoft.Windows.EnterpriseManagement.CSPReporting\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7339c7d7-8f99-4a30-a3b2-fec35ca17d56}\",\"name\":\"Microsoft.Windows.PBR\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1cfa8219-ba47-4030-8389-15ddbf02cbb7}\",\"name\":\"Microsoft.Windows.SystemReset\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{febc6d38-edbf-51a7-5e71-a42c0eefec21}\",\"name\":\"Microsoft.Windows.ResourceMapper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3d8e0e0a-54db-46d1-94ba-7ff7209d6a31}\",\"name\":\"Microsoft.Windows.AppEnergyManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8f621a24-8318-4288-9edd-3369d34d4ce9}\",\"name\":\"Microsoft.Windows.IUIRadioManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5dfe3ad2-b86c-5943-e324-3ebd1e18dcb6}\",\"name\":\"Microsoft.Windows.Security.SmartCards.TpmVscMgrServerRemote\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{076a2c5c-40e9-5a75-73b0-8d7697c282b2}\",\"name\":\"Microsoft.Windows.Security.Vault.RoamingSecurity\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ae94e5a2-1f4d-40b5-9caf-9af6e4f492c2}\",\"name\":\"RotMgrDll\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cc52107c-5ea2-42f9-bee4-e2cac90f3186}\",\"name\":\"Microsoft.Windows.Shell.MTF.RuleBasedDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d48533a7-98e4-566d-4956-12474e32a680}\",\"name\":\"RuntimeBrokerActivations\",\"group\":\"\"},{\"guid\":\"{0f1b810e-c19e-48b3-aa52-ee8e840b4f78}\",\"name\":\"Microsoft.Windows.Security.SmartCards.Bi\",\"group\":\"\"},{\"guid\":\"{179f04fd-cf7a-41a6-9587-a3d22d5e39b0}\",\"name\":\"Microsoft.Windows.Security.SmartCards.SCardSvr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1aebf134-2201-57b6-0edc-a6c064e52ba3}\",\"name\":\"Microsoft.Windows.Security.SmartCards.DeviceEnumSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{44492b72-a8e2-4f20-b0ae-f1d437657c92}\",\"name\":\"Microsoft.Windows.Security.Schannel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{10ff35f4-901f-493f-b272-67afb81008d4}\",\"name\":\"Microsoft.Windows.TaskScheduler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8439a2a8-49db-5541-9ad8-c59742126b03}\",\"name\":\"Microsoft.Windows.Security.SmartCards.Ksp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aa6715c6-f92b-54f7-0cd5-5ed813f0b7d2}\",\"name\":\"Microsoft.Windows.Shell.MTF.StaticDictionaryDS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dcb243d5-43e4-5b56-a4be-51ae916ab709}\",\"name\":\"Microsoft.Windows.SafeDocs.Engine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fbfc1d79-5d62-57cf-44a5-87d3b17fc434}\",\"name\":\"Microsoft.Windows.Storage.Win7Backup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ca967c75-04bf-40b5-9a16-98b5f9332a92}\",\"name\":\"Microsoft.Windows.Security.MitigationPolicy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b6fd710b-f783-4b1c-ab9c-c68099dcc0c7}\",\"name\":\"Microsoft.Windows.Security.IsolationApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b16d37f8-5c56-47ca-9ee0-7575347ebe5f}\",\"name\":\"Microsoft.Internal.Management.SecureAssessment.Logging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e6b5b34f-bd4d-5cdc-8346-ef4dc6cf1927}\",\"name\":\"Microsoft.Windows.Security.WSC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3a47280f-ef8d-41af-9288-64db7a9890d3}\",\"name\":\"Microsoft.Windows.Defender.SecurityHealthAgent\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d357dbe-57a2-5317-7970-19192e402ae6}\",\"name\":\"Microsoft.Windows.Defender.Shield\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7c5f5242-fc39-4bcb-bb09-3c210e2cfef4}\",\"name\":\"Microsoft.Windows.Security.SysTray\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dda1d007-6e0a-4fb6-83a3-996599b3826e}\",\"name\":\"Microsoft.Windows.Nfc.SEManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{59173412-04cd-5c92-8bed-5c16875e0fa4}\",\"name\":\"Microsoft.Windows.Payments\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0d08a156-7e7d-55b8-042b-e670378f2318}\",\"name\":\"Microsoft.Windows.Payments.MediatorService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0279b50e-52bd-4ed6-a7fd-b683d9cdf45d}\",\"name\":\"Microsoft-Windows-PerceptionSensorDataService-Verbose\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{85be49ea-38f1-4547-a604-80060202fb27}\",\"name\":\"Microsoft-Windows-PerceptionSensorDataService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{845678bb-25b7-4d81-a3ed-e9890ccfed9b}\",\"name\":\"Microsoft.Windows.Sensors.SensorsAPI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e5468423-a26c-5d0b-bbd5-24f8a8935c34}\",\"name\":\"Microsoft.Windows.Sensors.COMLayer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dd685aa3-9e8c-5e0c-819d-a3d24d221af1}\",\"name\":\"Microsoft.Windows.Sensors.NativeLayer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1936b710-e2e7-53f0-0035-9c44b816977e}\",\"name\":\"Microsoft.Windows.Sensors.App.ReadingNotificationSession\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4112d04d-3dd5-517b-8b1c-f4193ccf29bb}\",\"name\":\"Microsoft.Windows.Sensors.Desktop.AutoRotation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fa47059e-b524-4461-86c1-7fdaafa20f7d}\",\"name\":\"Microsoft.Windows.ServiceHealth\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b8ddcea7-b520-4909-bceb-e0170c9f0e99}\",\"name\":\"Microsoft.Windows.ServiceControlManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0bb8e5ca-316f-4b0f-9100-debbc6671308}\",\"name\":\"Microsoft.Wdf.UMDF.Dm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{59de359d-ec83-445c-9323-b75e2056d5a5}\",\"name\":\"SessionEnv\",\"group\":\"\"},{\"guid\":\"{fb1a70cc-be28-40c1-bd6a-47671538383a}\",\"name\":\"Microsoft.Windows.RemoteDesktop.CertManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{997fb36f-0208-4ed7-865b-e19816c3782d}\",\"name\":\"Microsoft.Windows.RemoteDesktop.SessionConfig\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d9f94c5a-94f8-4cd0-a054-a1ee67a2da6b}\",\"name\":\"Microsoft.Windows.RemoteDesktop.SessionHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{89d48904-939f-4177-aad4-2fdb26b8329f}\",\"name\":\"Microsoft.Windows.RemoteDesktop.RDSHFarm.UVhd\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c6fdd8e3-770b-4964-9f0c-227457146b49}\",\"name\":\"RDP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ae8ab061-654e-4d72-9f4b-c799ba919ec8}\",\"name\":\"sessionmsg\",\"group\":\"\"},{\"guid\":\"{047fb417-39e6-4b79-a52c-c436b60011ad}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.SettingsEnvironment\",\"group\":\"\"},{\"guid\":\"{e3446518-a6ee-4a30-b953-88a4455e2c53}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.SettingsEnvironment.Desktop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c3e10128-9491-5472-2863-d0dfae01460a}\",\"name\":\"Microsoft.PPI.Settings.SettingsEnvironment\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63461467-e5a3-4814-8123-01265f1c3a64}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.Extensibility\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{61bc3baa-c439-5e41-b843-9c2564ed57f6}\",\"name\":\"Microsoft.Windows.Analog.SystemSettingsHolographicProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3725b437-b9a6-411f-a47a-60c61cdf6d9f}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.AppExecutionAlias\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6c9f0ea4-39f0-411d-a3cf-6159f15d1918}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.BackgroundApps\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e04d85e2-56a2-5bb7-5dab-6f761366a4c2}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.BatterySaver.Desktop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c1e39d03-2172-4638-be89-0fb00978faea}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.CapabilityAccess\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a581b958-01d7-5b43-a776-365adf9fc460}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.ClosedCaptioningHandler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{56143dd6-ad65-4fb1-972c-6dfa2bef0916}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.BluetoothHandler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fc27cce8-72b0-5a6f-8fe3-22bfcfefd495}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.MediaRadioManagerSink\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{27d5ad5a-66c3-5df2-fc18-1f9f61d46abb}\",\"name\":\"Microsoft.Windows.Shell.BlueLightReduction\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{23cd8d50-ed49-5a0b-4562-65dff962d5f1}\",\"name\":\"Microsoft.Windows.Mobile.Shell.DisplaySettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d43920c8-d57d-4e58-9283-f0fddd4afdcb}\",\"name\":\"WindowsFlightingSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ec696ee4-fac7-4df4-9aaa-3862cb16eb4b}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.FontPreview\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8b71b3dd-db44-400d-ae29-b4be90b9deb3}\",\"name\":\"Microsoft.Windows.Xbox.NetworkTroubleshooter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9a35425e-61bc-4d68-8542-568a28963abe}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.AdvancedGraphics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d8a54c12-11e8-462b-bdd4-7ad5ccf676b6}\",\"name\":\"Microsoft.Windows.Analog.Shell.SystemSettings.Handlers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c442c41d-98c0-4a33-845d-902ed64f695b}\",\"name\":\"Microsoft.Windows.TextInput.ImeSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3bd9576d-203c-4b2d-8f1c-2a4574b3be78}\",\"name\":\"Microsoft.Windows.TextInput.ChsIme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a00d2097-96a9-4889-925e-1298e09460a0}\",\"name\":\"Microsoft.Windows.SystemSettings.SettingsHandlers.InkingTypingPrivacy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{adbb52ad-4e74-56c1-ecbe-cc4539ac4b2d}\",\"name\":\"Microsoft.Windows.SpeechPlatform.Settings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{17d6a222-af97-560b-6f18-389900d6ad1e}\",\"name\":\"Microsoft.Windows.Desktop.Shell.LanguagePackInstallSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e613a5d7-363e-5200-b311-02b426d8a73b}\",\"name\":\"Microsoft.Windows.Desktop.Shell.LanguageFeaturesOnDemandSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{33b3eaa6-d8dd-5096-8687-6f520d32fc9e}\",\"name\":\"Microsoft.Windows.Shell.NotificationSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e2a3ad70-42b5-452c-a113-20476e27e37c}\",\"name\":\"Microsoft.Windows.Desktop.Shell.SystemSettingsThreshold.Handlers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fb0a5f93-25eb-493a-a08b-b8cb0325deba}\",\"name\":\"Microsoft.Windows.Licensing.LicensingRegistration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2535e414-2453-44f0-a14d-87347cc72296}\",\"name\":\"Microsoft-Windows-EnterpriseManagement-PolicyManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a763f1f4-bda4-4738-8cb7-ea00f684b80e}\",\"name\":\"Microsoft.Windows.Desktop.TextInput.KeyboardSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1616dd48-db95-4796-a71f-b79485e1b962}\",\"name\":\"Microsoft.Windows.Analog.Speech.VoiceDownload\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4445fca2-f4ff-4469-9de4-5ac45f690249}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.SpeechPlatformSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{89956eca-39e2-598f-a8fa-8cb6382bd306}\",\"name\":\"Microsoft.Windows.Shell.ThemeSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6bee332c-7ddb-5ec2-dec4-91b8be7612f8}\",\"name\":\"Microsoft.Windows.Shell.PersonalizeSettingsTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a8fd7a5b-4323-4172-b85b-f5b78c3c0f9c}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.CorpDeviceManagementSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f323b60d-51ff-5c64-f7d1-f8149e2b3d81}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.Pen\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f84aa759-31d3-59bf-2c89-3748cf17fd7e}\",\"name\":\"Microsoft-Windows-Desktop-Shell-Windowing\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{42d3ead2-4c3d-4a27-a3a4-bd8bc73babc0}\",\"name\":\"Microsoft.Windows.Defender.PCSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cf652bd1-cf2a-5ae4-16a1-b293fa6381cf}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.RemoteDesktop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{571ac9d5-12fd-4438-b630-61fb26bbb0ac}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.BatterySaver\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{35a6b23c-c542-5414-bc49-b0f81b96a266}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.OneDriveBackup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8ff3b6ba-e06f-59b6-82c3-4cf8e3623322}\",\"name\":\"Microsoft-Windows-Shell-DisplaySettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a810c3ec-3fac-47de-9a75-9135c917ae7f}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.PrivacyHandler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ed9c68b1-12e1-4ae7-baab-2b167a66425a}\",\"name\":\"Microsoft.Windows.Shell.QuickActionSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{44f1a90c-4250-5bab-f09b-df45384c6951}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.RegionSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{912e9b77-ddd9-4a29-b141-57bd23981cce}\",\"name\":\"Microsoft.Windows.ErrorHandling.Fallback.SettingsHandlers_SharedExperiences\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{080e197d-7cc1-54a3-e889-27636425992a}\",\"name\":\"Microsoft.Windows.Shell.ShareUXSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{35437a7a-1330-4383-85e9-d596970932b0}\",\"name\":\"Microsoft.Windows.Settings.TelemetryPage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{db7bd825-b56f-48c4-8196-22bc145ddb08}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.SIUF\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8648e819-0883-4904-b730-d76d8498b521}\",\"name\":\"Microsoft.Windows.DeviceDelete\",\"group\":\"5ecb0bac-b930-47f5-a8a4-e8253529edb7\"},{\"guid\":\"{196cbdd6-30a9-5a27-827c-3df2debdb688}\",\"name\":\"Microsoft.Windows.SystemSettings.SettingsHandlers.SpeechPrivacy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ca68509f-ca73-462d-8ca6-39c1b5534ee1}\",\"name\":\"Microsoft.Windows.SystemSettings.SettingsHandlers.VoiceAgentActivation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{830a1f34-7797-4e31-9b75-c82056330051}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.StorageSense\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0ae9ad8e-d4d3-5486-f015-498e0b6860ef}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.UserPage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{80b3ff7a-bab0-4ed1-958c-e89a6d5557b3}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.WorkAccessHandlers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6e43b858-f3d9-5db1-0070-f99259784399}\",\"name\":\"Microsoft.Windows.Desktop.Shell.LanguageOptions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3d4b08aa-1df6-4549-b479-cf49b47cfcd3}\",\"name\":\"Microsoft-Windows-BackupAndRoaming-SyncHandlers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{278c595e-310c-5d49-0cca-546ce8745f9e}\",\"name\":\"Microsoft.Windows.Shell.SyncOperation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{40ba871e-4c49-41bc-a90c-753ff294f160}\",\"name\":\"Microsoft.Windows.BackupAndRoaming.SyncOperations\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{139299bb-9394-5058-dd33-9422e5903fc3}\",\"name\":\"Microsoft.Windows.SetupApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0e0fe12b-e926-44d2-8cf1-8a62a6d44036}\",\"name\":\"Microsoft.Windows.DriverStore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0049e0a6-9b4c-45e9-8d29-c500e7b8d3c4}\",\"name\":\"Microsoft.Windows.Setup.SetupClnPlugin\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3b7c742a-c2d7-5a46-ba41-0671001763db}\",\"name\":\"Microsoft.Windows.Oct.Broker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c688cf83-9945-5ff6-0e1e-1ff1f8a2ec9a}\",\"name\":\"Microsoft.Windows.Oct.Enclave\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e04eb256-d603-52d7-7adc-20fb4649e7bf}\",\"name\":\"Microsoft.Windows.Oct.Lpac\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7a53431e-04d5-5d14-72aa-b8e9714e77db}\",\"name\":\"Microsoft.Windows.SharedPC.SharedPCCSP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9d60ed7f-7714-4815-8fe8-1d9e8095fc5b}\",\"name\":\"Microsoft.Windows.Analog.SharingAndPersistence\",\"group\":\"\"},{\"guid\":\"{d95a57f7-0cbf-452e-a874-df7ddff55a51}\",\"name\":\"Microsoft.Windows.Analog.SurfaceReconStore\",\"group\":\"\"},{\"guid\":\"{16bbe284-cdd9-4a5a-953e-a59be6d222c2}\",\"name\":\"Microsoft.Windows.Analog.SpatialSharing\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8cde46fc-ca33-50ff-42b3-c64c1c731037}\",\"name\":\"Microsoft.Windows.Application.SharePlatform\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{810d9efb-88db-54ff-3703-9f5e54cc74fb}\",\"name\":\"Microsoft.Windows.Launcher.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{25756703-e23b-4647-a3cb-cb24d473c193}\",\"name\":\"Microsoft.Windows.Application.NearSharePlatform\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{76d1c1d6-4cee-5e0c-ee01-cd252eef4036}\",\"name\":\"Microsoft.Windows.Launcher.Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0c4c1871-8b0c-4577-9471-0b45454adf50}\",\"name\":\"Microsoft.Windows.Shell.SHCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{79172b48-631e-5d2c-9f04-1ad99f6e1046}\",\"name\":\"Microsoft.Windows.Desktop.Shell.Shell32\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{382b5e24-181e-417f-a8d6-2155f749e724}\",\"name\":\"Microsoft.Windows.ShellExecute\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4a9fe8c1-cde0-5f0a-f472-69b949097daf}\",\"name\":\"Microsoft.Windows.Shell.Desktop.IconLayout\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dc140d17-88f7-55d0-fcb1-068435d69c4b}\",\"name\":\"Microsoft.Windows.Shell.RunDialog\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8d07cb9d-ca74-44e4-b389-c7068a51393e}\",\"name\":\"Microsoft.Windows.Shell.IconCache\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{75d2b56f-3f9d-5b1c-0792-d243507f67ce}\",\"name\":\"Microsoft.Windows.Shell.PostBootReminder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{59a36fc6-225a-41bf-b1b4-b558a37798cd}\",\"name\":\"Microsoft.Windows.Shell.CoCreateInstanceAsSystemTaskServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6b2cb30d-2176-5de5-c0f5-65aedfbb1b1f}\",\"name\":\"Microsoft-Windows-Desktop-Shell-Personalization\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3ec39f17-6102-5c82-eb27-24a2d01672ff}\",\"name\":\"Microsoft.Windows.Shell.InfraCriticalFailure\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9399df73-403c-5d8f-70c7-25aa3184c6f3}\",\"name\":\"Microsoft.Windows.Shell.Libraries\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{44db9cfe-6db3-4a53-be9a-3057fa778b50}\",\"name\":\"Microsoft.Windows.Shell.FileExplorer.Banners\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{87c15c64-40a5-54b5-6283-5c35ee4574f8}\",\"name\":\"ShutdownDotExe\",\"group\":\"\"},{\"guid\":\"{bbc9a2c9-eeed-58d4-9483-6c87118f9ec6}\",\"name\":\"Microsoft-Windows-ShutdownUX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{354f4275-62b7-51b3-44c3-a1cb50ca4bc5}\",\"name\":\"Microsoft-Windows-WebServicesWizard-OPW\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d48679eb-8aa3-4138-be24-f1648c874e49}\",\"name\":\"SoftwareUpdateClientTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9906081d-e45a-4f41-a53f-2ac2e0225de1}\",\"name\":\"SIHTraceLogging\",\"group\":\"\"},{\"guid\":\"{0b7a6f19-47c4-454e-8c5c-e868d637e4d8}\",\"name\":\"WUTraceLogging\",\"group\":\"\"},{\"guid\":\"{3b3877a1-ae3b-54f1-0101-1e2424f6fcbb}\",\"name\":\"SIHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7b5367d6-ebeb-5e35-cc39-476f46842ddc}\",\"name\":\"Microsoft.Windows.Security.SmartCards.CredProv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b6f4ae91-7458-5c7f-0ca8-0c7838c7372c}\",\"name\":\"Microsoft.Windows.SMB.WMIProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d09ba4f-d4d0-49dd-8bdd-deb59a33dfa8}\",\"name\":\"Microsoft.Windows.Storage.SmpHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{46dc5dcf-095f-4157-aaee-dd6ae23720e0}\",\"name\":\"Microsoft.Windows.Cellcore.SmsRouter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{21063878-2959-42ea-a85a-0da1ab119c03}\",\"name\":\"Microsoft.Windows.Kernel.Smss.Telemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d947e748-4f27-5873-2d09-d027f5c13d11}\",\"name\":\"Microsoft.Windows.Audio.SndVolExe\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{988d3214-258a-5407-de36-b2e376de9590}\",\"name\":\"Microsoft.Windows.Shell.SystemTray.Volume\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{067a3a61-e60d-5614-7fe9-a25b3a4df183}\",\"name\":\"Microsoft.SnippingTool\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a9c7961e-96a0-4e3f-9066-7734a13101c1}\",\"name\":\"Microsoft.Windows.Storage.SpaceControl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0254f21f-4809-477e-ad36-c812a8c631a1}\",\"name\":\"Microsoft.Windows.Storage.Spaceman\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8610d647-7680-56eb-eebf-91ab889f2dc7}\",\"name\":\"Microsoft.Windows.Audio.SpatializerApo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bad49e08-45be-4e45-becf-29965aa7d967}\",\"name\":\"Microsoft.Windows.Analog.SpatialStore\",\"group\":\"\"},{\"guid\":\"{fbe1ed0a-6623-5251-70e3-9b6ccbfde8fe}\",\"name\":\"Microsoft.Windows.Analog.Spectrum.Activity\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{32bd5542-afcb-569e-4d02-ebe0e08bde8e}\",\"name\":\"Microsoft.Windows.Analog.Spectrum.TrackingDiagnostics\",\"group\":\"\"},{\"guid\":\"{96a898de-f347-55bf-0ccc-ae363e62c2cf}\",\"name\":\"Microsoft.Windows.Analog.SpatialJournal\",\"group\":\"\"},{\"guid\":\"{c0d0fe1d-53e4-5b98-71d7-c51fe5c10003}\",\"name\":\"Microsoft-Windows-Shell-CortanaNL\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c3c74ab1-e7fd-5210-ba29-df7355905351}\",\"name\":\"Microsoft.Windows.Shell.CortanaXDevice\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{94041064-dbc2-4668-a729-b7b82747a0c2}\",\"name\":\"Microsoft.Windows.Shell.CortanaReminders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{095549db-a97e-5db6-7540-510ebf851697}\",\"name\":\"Microsoft.Windows.Analog.Speech.CDPDeviceDisambiguation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f433b6cd-9505-5653-36c2-d88a43d980c4}\",\"name\":\"Microsoft.Windows.Analog.Speech.DeviceDisambiguation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ca176a4a-f27e-51f6-a0f6-8af13b973ef6}\",\"name\":\"Microsoft.Windows.Analog.NUI.SAPI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bc8b2c32-e484-5ee8-fe64-f7a94cbd4093}\",\"name\":\"SAPI.Perf\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2a8bc2a0-4cf9-5429-c90c-f5cd30dc6dd1}\",\"name\":\"Microsoft.Windows.Analog.Speech.RecognizerServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{07f283ce-2538-5e77-44d2-04212575a63d}\",\"name\":\"Microsoft.Windows.Analog.Speech.RecognizerClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e4c4b1db-812b-5e8d-3c9f-1b22eebc1191}\",\"name\":\"Microsoft.Windows.Analog.Speech.Activity\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1b5d7521-f0c0-5486-84be-4f0e53ce3e50}\",\"name\":\"Microsoft.Windows.Media.Speech\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d027bc7a-578a-5e9c-e8ec-a3bfcf578ec6}\",\"name\":\"Microsoft.Windows.Analog.Speech.GrammarServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d97a6378-85a9-507b-850e-902065ea9460}\",\"name\":\"Microsoft.Windows.Analog.Speech.OxygenOnline\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dafaf5dd-d4ba-5bd5-3e44-d0635b7f8f3f}\",\"name\":\"bing-speech\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7f02214a-4eb1-50e4-adff-62654d1e42f6}\",\"name\":\"Microsoft.Windows.Media.Speech.RemoteNaturalLanguage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f01d44cc-b0a2-57ac-f47b-32f3b2fca16d}\",\"name\":\"Microsoft.Windows.Analog.Speech.OneSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f65b3890-19ba-486e-a5f6-0378b356e0ce}\",\"name\":\"Microsoft.Windows.UserSpeechPreferences\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{96762235-2159-587d-da30-653f038f1d66}\",\"name\":\"Microsoft.Windows.Media.SpeechRecognition.SharedRuntime\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{760334d6-b026-527d-1f84-d6c957eb81d4}\",\"name\":\"Microsoft.Windows.TextInput.DictationCommands\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9ce214ea-6d38-5774-ce4d-9bedf62e4ff3}\",\"name\":\"Microsoft.Windows.Media.Speech.Settings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{663c59e1-bf59-55a4-fcdd-8c93569dcc5b}\",\"name\":\"Microsoft.Windows.Analog.Speech.VoiceEnabledShell\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{868702a6-6e88-4bf3-b1ae-1b9d0e5c2531}\",\"name\":\"Microsoft.Windows.Speech.Shell.DictationActivation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e8067960-862a-4370-8585-ee2b1bc4e7d6}\",\"name\":\"Microsoft.Windows.Print.Brm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b4d2914c-ff23-403b-babf-f0755fb060fe}\",\"name\":\"Microsoft.Windows.Print.SpoolerService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f4576912-c358-4374-a354-9040d45abcc1}\",\"name\":\"Microsoft.Windows.Licensing.Sppc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5d473d89-8be8-4ac9-a48a-8d2950c9820b}\",\"name\":\"Microsoft.Windows.Licensing.SppcExt\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8c8ebb7e-a4b7-4336-bddb-4a0aea0f535a}\",\"name\":\"Microsoft.Windows.Sysprep.PnP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0b0f7909-8154-4de2-bdc6-16467e3b2a7a}\",\"name\":\"Microsoft.Windows.Licensing.SppSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8f078bf2-1746-40ce-8a11-6c1fd97b16ec}\",\"name\":\"Microsoft.Windows.Licensing.SppSvc.WinAgent\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d535875-af13-46c2-a85f-a93caf2c5006}\",\"name\":\"Microsoft.Windows.Shell.SearchOptions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{045af240-9ba2-4daa-878a-0c641f2de5f0}\",\"name\":\"Microsoft.Windows.SRUM.ApiUsage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1c58b436-ed03-4184-8b7d-e761a817f345}\",\"name\":\"Microsoft.Windows.SrumSvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5423b552-86b5-5c32-ab1e-f7f70e8e8a47}\",\"name\":\"Microsoft.Windows.Audio.Service.SSDM\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a6d3c9ac-9128-522a-495a-1821191173c2}\",\"name\":\"Microsoft.Windows.Security.Sspicli\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f2cdc8a0-af2c-450f-9859-3251cce0d234}\",\"name\":\"WindowsInternal.Shell.UnifiedTile\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6054c188-3abb-52fc-f71e-2000ed278a2d}\",\"name\":\"Microsoft.Windows.ShellCommon.AppInstallation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1a554939-2d19-5b10-ceda-ee4dd6910d59}\",\"name\":\"Microsoft.Windows.ShellCommon.StartLayout\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6cfc5fc0-7e30-51e0-898b-57ac43152695}\",\"name\":\"Microsoft.Windows.Shell.DataStoreTransformers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c45c91e9-3750-5f9d-63c2-ec9d4991fcda}\",\"name\":\"Microsoft.Windows.Shell.CloudStore.Internal\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{66feb609-f4b6-4224-bf13-121f8a4829b4}\",\"name\":\"Microsoft.Windows.Start.SharedStartModel.Cache\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a331d81d-2f6f-50de-2461-a5530d0465d7}\",\"name\":\"Microsoft.Windows.Shell.DataStoreCache\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2d069757-4018-5cf0-e4a2-bf70a1a0183c}\",\"name\":\"Microsoft.Windows.Shell.MRTTransformer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45d87330-ffec-4a95-9f07-206a4452555d}\",\"name\":\"Microsoft.Windows.Start.ImageQueueManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{71b010ed-e0a3-4c1e-8be2-ba763939e6a0}\",\"name\":\"Microsoft.Windows.Scan.WiaComApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eb35548f-b147-5671-4a59-c008860735bf}\",\"name\":\"Microsoft.Windows.Scan.ClassInstaller\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9cd954e1-c547-52c4-50c7-1a3f5df69321}\",\"name\":\"Microsoft.Windows.Shell.SystemTray\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{32397015-9747-409c-98be-b3caa2233bd5}\",\"name\":\"Microsoft.Windows.DeviceUx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f4236699-b312-4a7a-923b-ad081afd7fbe}\",\"name\":\"Microsoft.Windows.Storage.StorageUsage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9282168f-2432-45f0-b91c-3af363c149dd}\",\"name\":\"Microsoft.Windows.Storage.StorageWMI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{88b892c2-fccd-4881-946a-032897f954b0}\",\"name\":\"SmpPassThru Trace Provider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aea3a1a8-ea43-4802-b750-2dd678910779}\",\"name\":\"Microsoft.Windows.Storage.StorageService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{778b9d2f-545b-47b0-98e9-28b9b8ca8c6a}\",\"name\":\"Microsoft.Windows.Storage.StorageHealth\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f5273e8b-490f-4008-9416-bc6c72aebfbc}\",\"name\":\"Microsoft.Windows.Storage.StorageDiskMonitor\",\"group\":\"\"},{\"guid\":\"{265551fa-4f81-4678-8afb-497821a795ca}\",\"name\":\"Microsoft.Windows.Storage.Cleanup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{06184c97-5201-480e-92af-3a3626c5b140}\",\"name\":\"Microsoft.Windows.SvchostTelemetryProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b8a83f1e-34c0-4e25-8310-44f46803940c}\",\"name\":\"Microsoft.Windows.Analog.SVF\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{509b009b-d8eb-4f7d-a12b-a23218bfca84}\",\"name\":\"Microsoft.Windows.OneSync.SyncController\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{59421743-e463-513c-497e-61d584e31710}\",\"name\":\"MicrosoftWindowsDeviceStageSync\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c703213f-16b2-4ed1-b654-4e7bb99b569f}\",\"name\":\"Microsoft.Windows.OneSync.SyncUtil\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8857cd15-8821-498e-9c38-de67f0e51e1a}\",\"name\":\"Microsoft.Windows.SystemEventsBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7765ec18-099f-424b-85f0-c639eb677de2}\",\"name\":\"Microsoft.Windows.CSystemEventsBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bcb6ba09-84a1-48a7-b1c2-42cb89f39007}\",\"name\":\"Microsoft.Windows.UserPresencePredictor.HistoryPredictor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0cec0fe2-9fb4-11e6-8679-480fcf549e24}\",\"name\":\"Microsoft.Windows.CleanPC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e6fcf13b-1ab7-4236-823b-0c0cf5c589d5}\",\"name\":\"Microsoft.Windows.Upgrade.Uninstall\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{2544ba03-ac8c-5025-957d-eb482095bc11}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.DataModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e3bfeaae-cb1d-5f12-e2e5-b9d2d7ca7bf0}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.Devices\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{62a9c2d5-8b5d-52f9-c99b-bcfc37b606c5}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.UserAccountsHandlers\",\"group\":\"\"},{\"guid\":\"{2e07964e-7d10-5d8e-761d-99b038f42bb6}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.AdminFlow\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a306fcf9-ad27-5c4d-f69a-22506ef908ad}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.RemoteDesktopAdminFlow\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3e8fb07b-3e10-5981-01a9-fbd924fd5436}\",\"name\":\"Microsoft.Windows.Shell.AssignedAccessSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{57d940ae-e2fc-55c3-f31b-253c5b172135}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.ManageUser\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e881df47-b77c-48c5-b321-1454b88fdd6b}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.ManageOrganization\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{068b0237-1f0a-593a-bc39-5155685f1bef}\",\"name\":\"Microsoft.PPI.Settings.AdminFlow\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6dd3a4c0-0119-5e7e-8678-76247cd32afc}\",\"name\":\"Microsoft.Windows.Holographic.Uninstall\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0ae92c9d-6960-566e-221f-5784660d04c3}\",\"name\":\"Microsoft.Windows.Fonts.FontEmbedding\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d6eac963-c24f-434d-be23-4aa21904148f}\",\"name\":\"Microsoft.Windows.UserDataAccess.TaskApis\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d87dc85e-1bb8-58b1-1c09-04b89c4cd06d}\",\"name\":\"Microsoft.Windows.Shell.TaskFlow.DataEngine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4586c77c-f490-5463-f715-465903978476}\",\"name\":\"Microsoft.Windows.Shell.TaskFlow.DataEngine.Aggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2e635d8e-1107-4555-9319-32eeb895aaae}\",\"name\":\"Microsoft.Windows.Taskmgr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7acf487e-104b-533e-f68a-a7e9b0431edb}\",\"name\":\"Microsoft.Windows.Security.TokenBroker.BrowserSSO\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{077b8c4a-e425-578d-f1ac-6fdf1220ff68}\",\"name\":\"Microsoft.Windows.Security.TokenBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{594bf743-ce2e-48ee-83ee-3d50a0add692}\",\"name\":\"Microsoft.Windows.AppModel.TileDataModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{088a803b-578d-41b1-9402-92b7ceb380c8}\",\"name\":\"Microsoft-Windows-Telephony-TelephonyInteractiveUser\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1ac684f9-187b-400f-9cec-3ec143cc6610}\",\"name\":\"Microsoft.Windows.Apps.TelephonyInteractiveUser\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5283d5f6-65b5-425f-a30b-f16c057d6b57}\",\"name\":\"Termsrv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f8c7b9d6-f389-4656-bc33-877616a01fe5}\",\"name\":\"TetheringService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{585cab4f-9351-436e-9d99-dc4b41a20de0}\",\"name\":\"PCTetheringStation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{64aa695c-9c53-58ad-2fe7-9358ab788507}\",\"name\":\"Microsoft.Windows.Shell.Desktop.Themes\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c11543b0-3a34-4f10-b50b-4ddb76ff2c6e}\",\"name\":\"Microsoft.Windows.Shell.ThumbnailCache\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6971cad2-d856-417f-b84d-383a6144fb11}\",\"name\":\"Microsoft.Windows.Storage.Tiering.Telemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0a9a90c8-9417-482d-b517-df1774c8f404}\",\"name\":\"Microsoft.Windows.TimeBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{feabe86d-d7a7-5e6d-9665-92819bc73768}\",\"name\":\"Microsoft.Windows.Desktop.Shell.TimeDateOptions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{13f3da1b-c22c-4cb1-8c77-ed37787953e9}\",\"name\":\"Microsoft.Windows.W32Time.Sync\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{27445658-7f9c-465c-a1e9-894c5cb6cd59}\",\"name\":\"Microsoft.Windows.Security.TokenBinding\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{470baa67-2d7f-4c9c-8bf4-b1b3226f7b17}\",\"name\":\"Microsoft.Tpm.ProvisioningTask\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3a8d6942-b034-48e2-b314-f69c2b4655a3}\",\"name\":\"Microsoft.Tpm.DebugTracing\",\"group\":\"\"},{\"guid\":\"{a935c211-645a-5f5a-4527-778da45bbba5}\",\"name\":\"Microsoft.Tpm.HealthAttestationCertificateTask\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8d9160d6-2bbe-5a07-45c9-bcea3a8f8e2c}\",\"name\":\"Microsoft.Windows.Security.SmartCards.TpmVscDll\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d89744af-d6b7-5f1d-39bc-0d9796449549}\",\"name\":\"Microsoft.Windows.Security.SmartCards.TpmVscMgrClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e8549ae1-cd73-5b5a-dc29-d1bc360e66ea}\",\"name\":\"Microsoft.Windows.Security.SmartCards.TpmVscMgrServerLocal\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2745a526-23f5-4ef1-b1eb-db8932d43330}\",\"name\":\"Microsoft.Windows.Security.TrustedSignal\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{89db9eac-5750-580c-39d6-6978396822dd}\",\"name\":\"Microsoft.Windows.TextInput.Gip\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d49f5fdd-c4ab-47bd-bd68-a9a8688a92ab}\",\"name\":\"Microsoft.Windows.TextInput.Gip.Perf\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6be754e7-f231-4db7-a9b6-3720f91a7ad2}\",\"name\":\"Microsoft.Windows.TextInput.Gip.LegacyBopomofo.Perf\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e5d358d3-8e39-5679-3f81-ea85a6397ff7}\",\"name\":\"Microsoft.Windows.TextInput.GipTypingStatistics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c0ac3923-5cb1-5e37-ef8f-ce84d60f1c74}\",\"name\":\"Microsoft.Windows.TSSessionUX\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9ed727c4-4ab6-4b66-92d7-2072e87c9124}\",\"name\":\"tssrvlic\",\"group\":\"\"},{\"guid\":\"{b6dc7658-6074-5509-926b-7d0ca235b8da}\",\"name\":\"EAPTtlsEvents\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6b70202e-8726-4134-964b-ead79143d203}\",\"name\":\"Microsoft.Windows.PreviousVersions.UI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bc71577f-76e9-583a-ecd6-62d0250d900f}\",\"name\":\"Microsoft.Windows.ProcessStateManager.AppLibrary\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{caa8cfe8-7cec-451e-b49f-6e60af56061e}\",\"name\":\"Microsoft.Windows.ComponentUI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{55e357f8-ef0d-5ffd-a4dd-50e3d8f707cb}\",\"name\":\"Microsoft.Windows.Desktop.Shell.CoreApplication.CoreApplicationView\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a9da4dcc-e78e-5ce7-4078-411a9928f082}\",\"name\":\"Microsoft.Windows.CoreApplication\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{55e357f8-ef0d-5ffd-a4dd-50e3d8f707cb}\",\"name\":\"Microsoft.Windows.Desktop.Shell.TwinApi.ApplicationView\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{31442aba-1fd2-5680-a7e1-87bfa73b43a8}\",\"name\":\"Microsoft.Windows.TWinAPI.MaterialProperties\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cf10565a-6a01-587b-3d6e-82f5f7e8d1fb}\",\"name\":\"Microsoft.Windows.Desktop.TwinApi.ProjectionManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{150d19f3-9557-5d5d-c24b-337ee2251ff6}\",\"name\":\"Microsoft.Windows.Application.ShareManagerApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{53e167d9-e368-4150-9563-4ed25700ccc7}\",\"name\":\"Microsoft.Windows.Shell.ExperienceHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1223ad99-9d25-4dd4-9402-b2e665fdce9d}\",\"name\":\"Microsoft.Windows.Shell.CortanaActionableInsights\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6924642c-34a3-5050-2915-053f31e18534}\",\"name\":\"Microsoft.Windows.Shell.CoreApplicationBridge\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1ee8ca37-11ae-4815-800e-58d6bae1fef9}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.SettingsPane\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fa386406-8e25-47f7-a03f-413635a55dc0}\",\"name\":\"TwinUITraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8149c640-2f6e-4f26-8cb7-9f9f8476bdab}\",\"name\":\"Microsoft.Windows.Storage.Pickers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b4b0f6fc-2f02-4a1a-9ef3-22ad06dea7b7}\",\"name\":\"Microsoft.Windows.Shell.ModernShare\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4e2b1375-f519-50a6-bfae-8c8a1a82d708}\",\"name\":\"Microsoft.Windows.Shell.BackgroundActivityModerator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8a1618e5-ae3a-41d6-a637-870ea619986a}\",\"name\":\"Microsoft.Windows.Shell.GameMode\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7b0c2561-285f-46bb-9229-09d11947ae28}\",\"name\":\"Microsoft.Windows.Desktop.Shell.AccessibilityDock\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c17f56cb-764e-5d2d-3b4e-0711ad368aaf}\",\"name\":\"Microsoft.Windows.Shell.ApplicationHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e3185da8-ecf4-4051-8bf1-8b6602e3577d}\",\"name\":\"Microsoft.Windows.Launcher.Desktop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1608b891-0406-5011-1238-3e93b292a6ef}\",\"name\":\"Microsoft.Windows.Shell.Autoplay\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a784a54d-0679-43e5-ab3b-0a45224c357a}\",\"name\":\"Microsoft.Windows.Desktop.Shell.TwinUI.BroadcastDVR\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{11edfcd0-4920-470f-8e6c-c66dbfe11e98}\",\"name\":\"Microsoft.Windows.Media.Capture\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{34581546-9f8e-45f4-b73c-1c0ac79f7b20}\",\"name\":\"Microsoft.Windows.Shell.PenWorkspace.ExperienceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1abbdeea-0cf0-46b1-8ec2-daad6f165f8f}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.HotKeyActivation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ed576cec-4ed0-4e09-9291-67ead252dde2}\",\"name\":\"Microsoft.Windows.Desktop.Shell.KeyboardOcclusionMitigation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d81f69fc-478d-4631-ad03-44046980bbfa}\",\"name\":\"MicrosoftWindowsTwinUISwitcher\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8bfe6b98-510e-478d-b868-142cd4dedc1a}\",\"name\":\"Windows.Internal.Shell.ModalExperience\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c7b31b56-af44-540c-15ed-eedc45663ece}\",\"name\":\"Microsoft.Windows.Shell.Chaining\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{158715e0-18df-56cb-1a2e-d29da8fb9973}\",\"name\":\"Microsoft.Windows.Desktop.Shell.MonitorManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{08194e35-5511-4c06-9008-8c2ce1fe6b52}\",\"name\":\"Microsoft.Windows.Shell.MSAWindowManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8911c0ab-6f93-4513-86d5-3de7175dd720}\",\"name\":\"Microsoft.Windows.Shell.NotesManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{69ecab7c-aa2d-5d2e-e85c-debcf6fc9016}\",\"name\":\"Microsoft.Windows.Desktop.OverrideScaling\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f71512b7-5d8e-41ee-aad8-4a6aebd29d4e}\",\"name\":\"Microsoft.Windows.Shell.InkWorkspaceHostedAppsManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3635a139-1289-567e-b0ef-71e7adf3adf2}\",\"name\":\"Microsoft.Windows.Shell.PlayToReceiverManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d2ff0031-cf02-500b-5898-8af98680cedb}\",\"name\":\"Microsoft.Windows.Shell.ProjectionManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e0a29dc1-075e-49be-b358-41624c99061d}\",\"name\":\"Microsoft.Windows.Desktop.Shell.TwinUI.QuietHoursService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4cd50c2c-1018-53d5-74a1-4214e0941c20}\",\"name\":\"Microsoft.Windows.Shell.ClickNote\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{50c2b532-05e6-4616-ae28-2a023fe55216}\",\"name\":\"Microsoft.Windows.Shell.PenSignalManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6ebac44e-6e02-44b9-9b82-e283d0e58521}\",\"name\":\"Microsoft.Windows.Store.StoreFrontHelperTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4fc2cbef-b755-5b53-94db-8d816ca8c9cd}\",\"name\":\"Microsoft.Windows.Shell.WindowMessageService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c0b1cbf9-f523-51c9-15b0-02351517daf8}\",\"name\":\"Microsoft-Windows-Explorer-MediaTransportControlsUI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cc997275-dd8f-5496-5534-35e51b9450e9}\",\"name\":\"Microsoft.Windows.Shell.Frame.Aggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{35d4a1fa-4036-40dc-a907-e330f3104e24}\",\"name\":\"Microsoft-Windows-Desktop-ApplicationManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8b5a39e9-7fc8-5ccb-18c9-d410973436a9}\",\"name\":\"Microsoft.Windows.Shell.TabShell\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{076a5fe9-e0f4-43dc-b246-9ea382b5c69f}\",\"name\":\"Microsoft.Windows.Desktop.Shell.ViewManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9eea5f6b-c98d-5c42-862b-2f07149d6331}\",\"name\":\"Microsoft.Windows.Desktop.Shell.FullScreenPositioner\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{36f33387-4ea8-4059-91b0-f01aedb820a2}\",\"name\":\"Microsoft.Windows.Shell.ShoulderTapExperienceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d3e36643-28fd-5ccd-99b7-3b13c721ee51}\",\"name\":\"Microsoft.Windows.Shell.StartMenu.Experience\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a0cf847c-39d3-5b2f-f2ef-9fe3a78818b2}\",\"name\":\"Microsoft.Windows.Shell.TouchpadControllerExperienceManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f1aeff7c-f56d-58e0-806f-a7733dc08637}\",\"name\":\"Microsoft.Windows.Shell.LockScreenService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{90daf745-441f-5ce8-8f21-b0ea9d6ea6d4}\",\"name\":\"Microsoft.Windows.Shell.PenWorkspaceBroker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e83c4d17-8009-5d9f-0cb4-53584ef324d9}\",\"name\":\"Microsoft.Windows.Desktop.Shell.PrivilegedOperations\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{467247af-d1bb-5ab6-b8c9-0b056bc16247}\",\"name\":\"Microsoft.Windows.Holographic.Positioner\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6ae72295-6082-555d-994a-c0f69276aca1}\",\"name\":\"Microsoft.Windows.Holographic.Win32BackedViewHostItem\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{813d08ca-6076-428b-bfe3-7258a067755a}\",\"name\":\"Microsoft.Windows.Shell.TabCompanion\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{15322370-3694-59f5-f979-0c7a918b81da}\",\"name\":\"Microsoft.Windows.Desktop.Shell.ViewManagerInterop\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5da629ce-0eb8-5967-329d-cd3892edb6bc}\",\"name\":\"Microsoft.Windows.Shell.XamlSwitcher\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c3af4b8a-c24f-56d4-ce67-def9f522a0dd}\",\"name\":\"Microsoft.Windows.Shell.TouchKeyboardExperience\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9bfec32d-7619-4994-a0eb-4c772392546c}\",\"name\":\"Microsoft.Windows.Shell.CustomShellHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e68dcb1e-228c-5737-10cb-3668a9d19a5c}\",\"name\":\"Microsoft.Windows.FamilySafety.AppUsage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bcce86fc-febd-4f2d-8e42-e277ba2b524c}\",\"name\":\"TzautoupdateProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0c24d94b-8305-4d60-9765-5affd5462872}\",\"name\":\"Microsoft.Windows.Udwm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c7a6e2fd-24f6-48fd-aad8-03ee14faf5ce}\",\"name\":\"Microsoft.Windows.Dwm.WindowFrame\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ffdb63bc-4194-5395-03d2-f8c9165e1b94}\",\"name\":\"Microsoft.Windows.Dwm.AnimationClock\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{53b7f054-68fd-5c77-b92d-e54340f38968}\",\"name\":\"UiaManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6e65c8fc-3cfe-412a-b793-d36d2185a831}\",\"name\":\"Microsoft.Windows.UIAutomation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a91b83dc-8f8d-533b-c174-1350400a3828}\",\"name\":\"Microsoft.Windows.Ribbon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{66ba1a86-43c6-41ac-955b-28b520db532a}\",\"name\":\"Microsoft.Windows.Kernel.Pdc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{55d407f6-b994-49f1-95e7-9a3e4b628f46}\",\"name\":\"Microsoft.Windows.PowerService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{845d84d3-8996-4508-8688-3fea3a426915}\",\"name\":\"Microsoft.Windows.Power.EnergyMeter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d50e07bd-fce3-5ad6-a715-cfc122637512}\",\"name\":\"Microsoft.Windows.Power.Dimming\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{68c97e16-c170-4c1b-bc4b-7cb3a5b04023}\",\"name\":\"Microsoft.Windows.Power.AdaptiveStandby\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4f56280a-220a-441e-84ee-c32e60be65c5}\",\"name\":\"Microsoft.Windows.Power.Toast\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0506a50c-1b17-486c-80d7-04f7e128e3cc}\",\"name\":\"Microsoft.Windows.Power.SleepStudy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cb76d769-a1ed-4fb1-98c3-266951610fd8}\",\"name\":\"Microsoft.Windows.UserDataAccess.Unistore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{969bfdc0-0a9e-550e-1b0b-0b8b3386ba7a}\",\"name\":\"Microsoft.Windows.UpdateNotificationPipeline\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9eaeed65-78d4-5bf1-16cc-9fda3efa8958}\",\"name\":\"Microsoft.Windows.UpdateCsp\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{f27df866-c85a-518e-f34a-dc6fddbcd0c9}\",\"name\":\"UpdateDeploymentProviderTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d6b029ac-41f1-5386-35e4-2de118c26ab6}\",\"name\":\"UpdateDeploymentProviderTracing\",\"group\":\"\"},{\"guid\":\"{46b13027-2dfd-46e1-832d-e41e2810e6e5}\",\"name\":\"Microsoft.Windows.Upfc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{09b30eb7-9d78-2d64-9274-62b0d5571130}\",\"name\":\"Microsoft.Windows.WindowsToGo\",\"group\":\"\"},{\"guid\":\"{0eb27784-7b75-4b98-90da-7f6bc2668d56}\",\"name\":\"MicrosoftUsbHidCeipProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3fc887c9-c23f-59cd-88b5-a6086f4bbc9e}\",\"name\":\"Microsoft.Windows.Print.USBMon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{15e77116-7ce1-4a0e-a2b5-4c458d9ad18c}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.Usb\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5f057942-9ba1-49f3-a80b-ea7bc27108c0}\",\"name\":\"Microsoft.Windows.SystemToast.Usb.Notification\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e0910e25-6fcc-4f32-8f5e-a42cf7acc5c3}\",\"name\":\"Microsoft.Windows.OneCoreTransforms\",\"group\":\"\"},{\"guid\":\"{f25bcd2e-2690-55dc-3bc4-07b65b1b41c9}\",\"name\":\"Microsoft.Windows.User32\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c2f1fb96-72f6-40ff-a504-fb0b70bdef24}\",\"name\":\"Microsoft.Windows.Shell.UserCpl.Cpls\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fe03fa65-4f8d-5008-f5d6-7a21eb5e3d23}\",\"name\":\"Microsoft.Windows.Shell.UserCpl.Taskflow\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{553ebe04-ceb2-47ee-b394-bb83b97de219}\",\"name\":\"Microsoft.Windows.UserDataAccess.UserDataAccounts\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{15773ad5-aa2f-422a-9129-4a83f4c19db0}\",\"name\":\"Microsoft.Windows.UserDataAccess.UserDataService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{519b3601-c289-44fb-b3e4-a05841d2790d}\",\"name\":\"Microsoft.CAndE.ADFabric.WinRT.NGC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d5ee9312-a511-4c0e-8b35-b6d980f6ba25}\",\"name\":\"Microsoft.Windows.Shell.Userenv\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5e85651d-3ff2-4733-b0a2-e83dfa96d757}\",\"name\":\"UserMgrSvcTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a198ad71-4f5e-4bc2-9a60-7cafb76f4e3c}\",\"name\":\"Microsoft.Windows.UserMgr.UserModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f0b53a1f-c7eb-41c3-8e61-cea11271858f}\",\"name\":\"Microsoft.Windows.Security.CandidateAccountManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a8b932c2-51ec-5c22-63fc-0115fd79b9e0}\",\"name\":\"Microsoft.Windows.Update.Orchestrator.Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{43ac453b-97cd-4b51-4376-db7c9bb963ac}\",\"name\":\"Microsoft.Windows.UtcDecoderHost\",\"group\":\"\"},{\"guid\":\"{55c509d7-c517-4078-98e8-6031326b2d6d}\",\"name\":\"Microsoft.Windows.UvcModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5162d6d9-3723-553e-a74c-7d8f986c5d3d}\",\"name\":\"Microsoft.Windows.Storage.Uwf\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{673cf800-208a-5327-3f4b-2be44a66627a}\",\"name\":\"Microsoft.Windows.UxTheme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d50a5002-97cb-46df-93c8-94ce03beed99}\",\"name\":\"Microsoft.Windows.Audio.Service.VAC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f3647e0d-cb56-4837-a268-981eb18a5b46}\",\"name\":\"Microsoft.Windows.Audio.ASA.PathFinder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f045463-a602-4891-b732-1b6572d54dbe}\",\"name\":\"Microsoft.Windows.Audio.Service.ASA.Triton\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f2c1ee5-1dfd-519b-2d55-702756f5964d}\",\"name\":\"Microsoft.Windows.Security.Vault.Cds\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6cb2326f-8998-539d-fd24-dffe22f9bca3}\",\"name\":\"Microsoft.Windows.Security.Vault.WebAccount\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e45534fa-fc44-5ee1-4472-7369a4d1ce36}\",\"name\":\"Microsoft.Windows.Security.Vault.Credentials\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a15c1ac4-a508-59ae-3158-275f96f30cb8}\",\"name\":\"Microsoft.Windows.Security.Vault.Roaming\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4ca869f9-d720-449f-a322-28d0d1763e50}\",\"name\":\"Microsoft.Windows.Security.Credlocker.Critical\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1b7da76e-0a98-4e71-a9a5-dfd0a5262c13}\",\"name\":\"Microsoft.Windows.Security.Credlocker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ead10f56-e9d4-4b29-a44f-c97299de5085}\",\"name\":\"Microsoft.Windows.Storage.VDS.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ead10f56-e9d4-4b29-a44f-c97299de5090}\",\"name\":\"Microsoft.Windows.Storage.VDS.BasicDisk\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9b698003-2db1-5618-d2e2-a7a137e494be}\",\"name\":\"Microsoft-Windows-Verifier\",\"group\":\"\"},{\"guid\":\"{a9bc635d-4b98-4327-90a1-1d0b8f45bf5a}\",\"name\":\"WindowsDriverVerifierUi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b95c2fff-e9de-4327-93b1-1d5b8445bf7e}\",\"name\":\"Microsoft.Windows.DriverVerifier.UiGui\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8e4a203f-3d8a-5e7c-15d5-d1c1f7cd1270}\",\"name\":\"Microsoft.Windows.Srum.VfuProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f2163a3-12a6-40fa-8719-8bf5b8c3840b}\",\"name\":\"Microsoft.Windows.Media.Settings.Video\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{719a808e-e4d8-55f1-1b63-5dd599d0030d}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.VideoPlaybackHandler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dcadf22a-dbc1-5e55-467b-1c7f36cc46cc}\",\"name\":\"Microsoft.Windows.TextInput.VocabRoamingHandler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b8efdc71-988b-50be-86bb-0f97b0a3a7c8}\",\"name\":\"Microsoft.Windows.Audio.VoiceActivationManager\",\"group\":\"\"},{\"guid\":\"{6fc36b25-61ac-5e62-b785-94b344e0702b}\",\"name\":\"Microsoft.Windows.Audio.VoiceActivationManager2\",\"group\":\"\"},{\"guid\":\"{6f63aefb-2229-5444-c3b1-519681ab0654}\",\"name\":\"Microsoft.Windows.Apps.VoipRTProviders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bd1a62ed-263b-4a66-a574-1f43c79c64be}\",\"name\":\"Microsoft-Windows-Telephony-VoipRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{efd89d89-6b12-4467-bbfa-8122c589e066}\",\"name\":\"Microsoft.Windows.Networking.VpnCsp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{13185d0b-b630-41fe-8489-9c6dd63d487d}\",\"name\":\"Microsoft.Windows.DxCapture.Trace\",\"group\":\"\"},{\"guid\":\"{9122168f-2432-45f0-b91c-3af363c149dd}\",\"name\":\"Microsoft.Windows.Storage.VSSTraceLogProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8ee3a3bf-9379-4dac-b376-038f498b19a4}\",\"name\":\"Microsoft.Windows.W32Time\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ec4ba041-1dfe-5f76-ef6d-0251da19d178}\",\"name\":\"Microsoft.Windows.WaaSAssessment\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{76ad4308-df7c-5f43-e668-fcea4fa1179d}\",\"name\":\"Microsoft.Windows.WaaSMedic\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{30d25124-a468-505c-de82-8411646eb8b5}\",\"name\":\"Microsoft.Windows.WaaSMedic.Local\",\"group\":\"\"},{\"guid\":\"{3c3e4665-d776-516b-4898-7c276dc36fc3}\",\"name\":\"Microsoft-Windows-Mobile-Shell-Wallet\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a76dba2c-9683-4ba7-8fe4-c82601e117bb}\",\"name\":\"Microsoft.Windows.DeviceManagement.WmiBridge\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ab84611c-2678-5cd7-d292-c940f9be6c6d}\",\"name\":\"Microsoft.Windows.AssignedAccess.Wmi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{81462b17-77ef-4541-a5dc-437d78893faa}\",\"name\":\"Microsoft.Windows.Print.Powershell\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3d091993-4dcf-426e-95c4-1c398ccfba04}\",\"name\":\"Microsoft.Windows.WMIC.UsageStats\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{864d2d93-276f-4a88-8bce-d8d174e39c4d}\",\"name\":\"Microsoft.Windows.SystemImageBackup.Engine\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{39a5aa08-031d-4777-a32d-ed386bf03470}\",\"name\":\"Microsoft.Windows.Security.Biometrics.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8ce2286c-3705-4a2a-8e36-134eae9ca147}\",\"name\":\"Microsoft.Windows.Containers.DynamicImage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b6a9c8ba-70de-42e4-88de-001a041b0768}\",\"name\":\"Microsoft.Windows.ConnectionManager.WcmApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2551390d-5927-5c84-6f0a-027a7e78d38d}\",\"name\":\"Microsoft.Windows.Containers.Storage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{08f93b14-1608-4a72-9cfa-457eecedbba7}\",\"name\":\"WebIo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{db5afa36-72be-5ee9-fb28-349ccdfc00ad}\",\"name\":\"Microsoft.Web.Platform.IDBServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{49d0c8d6-b62d-4dd3-a746-19f23dccd082}\",\"name\":\"Microsoft.Windows.App.Browser.Scenarios\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{68431dca-6bcf-5940-0c0b-aab1138dc054}\",\"name\":\"Microsoft.Windows.Shell.ControlPanel.ProblemReportsAndSolutions\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2b87e57e-7bd0-43a3-a278-02e62d59b2b1}\",\"name\":\"Microsoft.Windows.WERVertical\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{97945555-b04c-47c0-b399-e453d509a5f0}\",\"name\":\"Microsoft.Windows.WERSecureVertical\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3e0d88de-ae5c-438a-bb1c-c2e627f8aecb}\",\"name\":\"Microsoft.Windows.HangReporting\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{bf30465b-e93c-46fd-9cdf-f41c8904a01f}\",\"name\":\"EventLogEvents\",\"group\":\"\"},{\"guid\":\"{1248334e-ac1e-4c8e-b439-e619bd6d0a27}\",\"name\":\"EventLogActivityTracing\",\"group\":\"\"},{\"guid\":\"{359bb287-a373-4385-a69f-6a2f1bb6583b}\",\"name\":\"Microsoft.Windows.Networking.Wlan.Wfdprov\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d7387e51-2d09-56cb-7e90-2383a30dcdee}\",\"name\":\"Microsoft.Windows.Networking.WFDSConMgr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d48bd25-8b17-5235-b9f5-bf81f943fe74}\",\"name\":\"Microsoft.Windows.Shell.FaxScanApp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{91dfdc3a-0eda-40d4-8c40-6b2c20b3c4bd}\",\"name\":\"Microsoft.Windows.Scan.WiaAutomation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{357f3153-b5a1-43d7-a119-52ddfa837ccb}\",\"name\":\"Microsoft.Windows.Scan.WiaTwainCompat\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b9b6ce1a-9ce4-4ec8-8e0a-b6db33722c61}\",\"name\":\"Microsoft.Windows.Scan.WiaRpc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63760752-3037-421e-8858-f4e83a65da68}\",\"name\":\"Microsoft.Windows.Scan.WiaService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{99d849fb-d0e5-499d-91da-7081193a11b1}\",\"name\":\"WirelessDisplay\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8b7650e3-0bd4-458f-b678-34ac4e348b7c}\",\"name\":\"Microsoft.Windows.WiFiNetworkManager.HotSpotProvisioning\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7a0db36b-2dca-4b50-ab37-b4b15bf8dad7}\",\"name\":\"WiFiNetworkManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{68d02507-e1b0-4f0b-aa38-3453c19f757a}\",\"name\":\"Microsoft.Windows.WiFiNetworkManager.WiFiTask\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7e6b69b9-2aec-4fb3-9426-69a0f2b61a86}\",\"name\":\"Microsoft.Windows.Win32kBase.Input\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{72a4952f-db5c-4d90-8f9d-0ed3465b315e}\",\"name\":\"Win32kDeadzonePalmTelemetryProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ce20d1cc-faee-4ef6-9bf2-2837cef71258}\",\"name\":\"Win32kSyscallLogging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e75a83ec-ef30-4e3c-a5fb-1e7626e48f43}\",\"name\":\"Win32kPalmMetrics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{487d6e37-1b9d-46d3-a8fd-54ce8bdf8a53}\",\"name\":\"Win32kTraceLogging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aad8d3a1-0ce4-4c7e-bf32-15b2836659b7}\",\"name\":\"Microsoft.Windows.WER.MTT\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{de5a9d0a-c195-504d-0175-039ac1243837}\",\"name\":\"Microsoft.Windows.CoreMessaging.CoreMessagingK\",\"group\":\"\"},{\"guid\":\"{3ebcc356-dd7c-4ca7-8cd1-3c86c1fe14f5}\",\"name\":\"Win32kClipboardAggregateProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7b56217d-0850-4170-a032-58d76eed3a6a}\",\"name\":\"Microsoft.Windows.InkProcessor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{befe1a6f-c0e1-5083-bb46-0d608594a923}\",\"name\":\"Microsoft.Windows.SimpleHapticsCtrl\",\"group\":\"\"},{\"guid\":\"{3a97f069-0082-5b29-e2fc-e0d4773bd777}\",\"name\":\"Microsoft.Windows.InteractiveCtrl\",\"group\":\"\"},{\"guid\":\"{6485849f-3372-4d65-9187-3dc6b28c49cc}\",\"name\":\"Microsoft.Windows.Print.Win32spl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1b5106b1-7622-4740-ad81-d9c6ee74f124}\",\"name\":\"Microsoft.Windows.Security.Biometrics.Client\",\"group\":\"\"},{\"guid\":\"{4b8b1947-ae4d-54e2-826a-1aee78ef05b2}\",\"name\":\"Microsoft.Windows.WinBioDataModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fb7f6a77-48d9-5776-fb2e-e0a84d01d993}\",\"name\":\"Microsoft.Windows.Analog.NUI.Audio.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8a89bb02-e559-57dc-a64b-c12234b7572f}\",\"name\":\"Microsoft.Windows.Security.Biometrics.StorageAdapter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{beb1a719-40d1-54e5-c207-232d48ac6dea}\",\"name\":\"Microsoft.Windows.Security.Biometrics.VsmStorageAdapter\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6287d456-dcf1-46a6-b3c4-c57e9461d137}\",\"name\":\"Microsoft.Windows.WinCorLib.Usage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c11d96bf-1615-4d64-ada3-5803cdbac698}\",\"name\":\"Microsoft.Windows.Shell.Auth.CredUI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cf5838d7-9fdc-5907-a62c-abd41de9d862}\",\"name\":\"Microsoft.OneCore.WindowManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{687ae510-1c00-4108-a958-acfa78ecccd5}\",\"name\":\"Microsoft.Windows.Shell.AccountsControl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c6fe0c47-96ef-5d29-c249-c3cecc6f9930}\",\"name\":\"Microsoft.Windows.Shell.SyncPartnership.Api\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0f51cf13-b9db-47b8-9517-3521db0b2951}\",\"name\":\"Microsoft.Windows.Shell.AccountsControl.API\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bcad6aee-c08d-4f66-828c-4c43461a033d}\",\"name\":\"Microsoft.Windows.AI.MachineLearning\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3889f5d8-66b1-44d9-b52c-48ca283ac5d8}\",\"name\":\"Microsoft.Windows.DataPackage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eadb8f1b-577d-4d09-8104-b61a3d9036e5}\",\"name\":\"Microsoft.Windows.AppModelRuntimeWinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c5b9724a-38ef-47a0-b2dd-c8b1a4934c38}\",\"name\":\"StartupTask\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{96319132-2f52-5969-f14c-0d0a171b357a}\",\"name\":\"Microsoft.Windows.Shell.LockFrameworkUAP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dd2e708d-f725-5c93-d0d1-91c985457612}\",\"name\":\"Microsoft.Windows.ApplicationModel.Store.Telemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fba941fa-dbd7-4956-96ac-b999b2a0cd4a}\",\"name\":\"Microsoft.Windows.Cortana.Analog.BrokeredAPI\",\"group\":\"\"},{\"guid\":\"{bd0d25d5-698b-4c32-b13a-82827c28217d}\",\"name\":\"Microsoft.Windows.Cortana.PAL\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{94afb82b-3e13-586e-3bdb-64bb9628ff2f}\",\"name\":\"Windows.Data.Activities\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{79374c5b-f272-4bd8-99c2-5b6f53fa2ce1}\",\"name\":\"Windows.PdfApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f5c966d9-a294-5bc4-4bbe-3d37e9b4fe53}\",\"name\":\"Microsoft.Windows.AllJoyn.WinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c2b1f6c2-adcf-5fb7-dfc1-5ed87be9dfb3}\",\"name\":\"Microsoft.Windows.Devices.Haptics.Vibration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1964d316-5ec7-496f-82a8-a62c8b164b1a}\",\"name\":\"Microsoft.Windows.Devices.Lights\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1b136618-e32d-4b3d-839b-73ac494a33fd}\",\"name\":\"Microsoft.Windows.IoT.Devices\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{aadd3984-67ee-4354-94a1-18f762026c86}\",\"name\":\"Microsoft.Windows.Devices.Midi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e92355c0-41e4-4aed-8d67-df6b2058f090}\",\"name\":\"Microsoft-Windows-PerceptionRuntime-Verbose\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{add0de40-32b0-4b58-9d5e-938b2f5c1d1f}\",\"name\":\"Microsoft-Windows-PerceptionRuntime\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3c27a357-a925-4040-87e4-82e74ef8731e}\",\"name\":\"Microsoft.IoT.POS.DafDiscovery\",\"group\":\"\"},{\"guid\":\"{b069f900-e50f-487e-8bdc-63a6de76e993}\",\"name\":\"Microsoft.Windows.PointOfService.Api\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d76a5792-ec7e-4bba-9da0-daf32ee61c04}\",\"name\":\"Microsoft.OSG.IoT.PosRt.Api\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5ab780c8-6398-4497-aecc-cee44dba87d0}\",\"name\":\"Microsoft.Windows.Print.MS3DDeviceAPI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{df6dca70-9918-455f-86fe-983adc74fa0d}\",\"name\":\"Microsoft.Windows.Scan.Runtime\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{49d5f264-500b-54ec-0549-b61dbb42265d}\",\"name\":\"Microsoft.Windows.Sensors.WinRTLayer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8f9e3c95-12d4-07ff-c826-3be57c0bc90d}\",\"name\":\"Microsoft.Windows.Devices.SerialCommunication\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7ba6910b-016f-43e1-97de-8a0f761e7c23}\",\"name\":\"Microsoft.Windows.Security.SmartCards.WindowsDevicesSmartCardsDll\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{448ea390-e468-4973-9bbd-3caa4f031209}\",\"name\":\"Microsoft.Windows.Nfc.SmartCard\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3b36be75-d30a-4dca-ad28-d9d162e03a6a}\",\"name\":\"Microsoft.Windows.Power.RtApi\",\"group\":\"\"},{\"guid\":\"{221a8b88-4fb1-4d57-8027-3b148b43c8b9}\",\"name\":\"Windows.Gaming.Input\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dc54214a-50dd-486a-b176-abea2423b4d8}\",\"name\":\"Microsoft.Windows.Gaming.Preview.GamesEnumeration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2427eb68-ae18-445a-bb44-5be928a4b621}\",\"name\":\"Microsoft.Windows.GameBarApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e775a461-8a31-5f40-a05f-f014fc161eb4}\",\"name\":\"Microsoft.Windows.Globalization.Language\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{85e12ac1-9112-55d4-6469-58455c1126fd}\",\"name\":\"Microsoft.Windows.Shell.TextSuggestionApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{613e8728-f1cd-5604-c71c-32ab60d68b11}\",\"name\":\"Microsoft-Windows-Graphics-WinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{643b8711-d1fe-4daa-8c47-8d2118e2beae}\",\"name\":\"Microsoft.Windows.Print.MS3DPrintAPI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c6dba857-03f1-5c5b-350c-ef08dbd04572}\",\"name\":\"Microsoft.Windows.Shell.PrintManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{744372de-ba26-443b-ba10-712c1a041234}\",\"name\":\"Microsoft.Windows.Print.Workflow.API\",\"group\":\"\"},{\"guid\":\"{cae6f32b-2553-5c24-f999-e63dde138b9f}\",\"name\":\"Microsoft.Windows.Print.WorkFlowRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{15584c9b-7d86-5fe0-a123-4a0f438a82c0}\",\"name\":\"Microsoft.Windows.Shell.ServiceProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dce1d33d-853d-55d5-1a55-20ad7ca1d403}\",\"name\":\"Microsoft.Windows.AdaptiveCards.InternalRenderer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eb827eda-87da-59ae-35d0-b28b32815af0}\",\"name\":\"Microsoft.Windows.Shell.Desktop.CapturePickerItemProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7e9ced67-c799-5bdd-a487-e5eb6df70088}\",\"name\":\"Microsoft.Windows.Shell.CapturePicker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6d52b4f9-62b0-47dc-b4df-8229cf874503}\",\"name\":\"Windows.Internal.Feedback.Analog.BrokeredApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ec1cdef8-3813-41eb-9e19-7bbfe6c5a145}\",\"name\":\"HeadTracker\",\"group\":\"\"},{\"guid\":\"{f8056f5c-6c6f-4727-9f29-efdf39520c0f}\",\"name\":\"Microsoft.Windows.DeviceManagement.dmEnrollment\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{82add491-01d7-4b85-9ead-192c3caaca23}\",\"name\":\"Microsoft-Windows-Provisioning-API\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{99caa292-62e0-4e8a-889e-fe3a3b2ac2e8}\",\"name\":\"Microsoft.Windows.Management.ConfigurationSession\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{60f735be-c2f1-4b42-8b19-c48c8bf7f6a7}\",\"name\":\"Microsoft.Windows.Management.MdmSync\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5003f994-2f1d-51dc-20ca-653248c90a6a}\",\"name\":\"Microsoft.Windows.PlatformExtensions.DevicePickerExperience\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{26d3a140-5bf3-4079-b2dd-75072f83a5ba}\",\"name\":\"Microsoft.Windows.PlatformExtensions.MiracastBannerExperience\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6e3ac38e-955e-5467-492b-dc045c9743a9}\",\"name\":\"Microsoft.Windows.Internal.PredictionUnit\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{28715ca3-c574-50cb-9af0-b2ee8b3802ee}\",\"name\":\"Microsoft.Windows.Oct.Api\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{36f1d421-d446-43ae-8aa7-a4f85cb176d3}\",\"name\":\"Microsoft.Windows.UI.Shell.StartUI.WinRTHelpers\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c0f1d44d-efea-4cc3-a68b-d7a3af9ec850}\",\"name\":\"Microsoft.Windows.Shell.JumpView\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0071f61e-71ab-44e1-9d2d-95a46f3ba2be}\",\"name\":\"Microsoft.Windows.PlatformExtensions.AccountsControlExperience\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{659ec1b4-c023-5e54-9278-d922370ff05e}\",\"name\":\"Microsoft.Windows.Signals\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{17bc862c-6db8-49a7-945d-9f101535416f}\",\"name\":\"Microsoft.Windows.Management.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6263bde9-33ae-4c30-b2a1-ed90da5f2295}\",\"name\":\"Microsoft.Windows.Management.Autopilot\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0d641fb9-a0e3-42e3-9e9d-501d33a6fa79}\",\"name\":\"Microsoft.Windows.Media.Audio.AudioGraph\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8f8942e2-66b4-5650-8cf1-de723ca48565}\",\"name\":\"Microsoft.Windows.Audio.XAudio2.81\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3a2e5a5c-9cac-5e49-f93a-fbe76451b4ad}\",\"name\":\"Microsoft.Windows.MediaFoundation.BackgroundMediaPlayback\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e529e738-f09e-5226-9f15-b5ec2d9e80be}\",\"name\":\"Microsoft.Windows.Audio.Effects\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7cffb6e3-de5a-572a-9ece-998321af6e81}\",\"name\":\"Microsoft.Windows.MediaFoundation.MediaPlaylist\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{afbd9bfb-785c-515d-8ede-c31081bf8872}\",\"name\":\"Microsoft.Windows.MediaFoundation.MediaTranscode\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3ff44415-ee99-4f03-bc9e-e4a1d1833418}\",\"name\":\"Microsoft.Windows.MediaFoundation.MediaCapture\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1d988eb8-0133-5903-ae68-4d44ea8abb85}\",\"name\":\"Microsoft.Windows.MediaFoundation.AdaptiveMediaSource\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1123dc81-0423-4f27-bf57-6619e6bf85cc}\",\"name\":\"Microsoft.Windows.Media.Editing\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{de6d3d9e-418c-5a5d-e225-c826855cb99b}\",\"name\":\"Microsoft.Windows.Media.Import.PhotoImport\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7ceded3a-7359-5861-5b43-1959577103e4}\",\"name\":\"Microsoft.Windows.Smtc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6ee36d33-0d93-4098-8ff9-d8c5635abefd}\",\"name\":\"Microsoft.Windows.Mirage.MixedRealityCapture\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8f292689-91d4-5127-d122-8b637f9b671b}\",\"name\":\"Microsoft.Windows.WinOCR.OCR\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9af106fc-dc26-42e1-a0f1-0c538f78f553}\",\"name\":\"PlayReadyITA\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f84ceeac-399a-598b-bf51-903ed91d881c}\",\"name\":\"Microsoft.Windows.Media.SpeechRecognition.WinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{614f2573-da68-5a1b-c2c6-cba6de5de7f8}\",\"name\":\"Microsoft.Windows.Media.Speech.Internal.SoundController.WinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4331556e-1bcb-5b8f-1fb6-0896d9ab2afb}\",\"name\":\"Microsoft.Windows.Media.SpeechSynthesis.WinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{36947feb-9c1b-569e-1728-bfd47470bbbb}\",\"name\":\"Windows.Media.Speech.VoiceCommands.Telemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{46f27ed9-a8d6-5c0c-8c30-6e846b4c4e46}\",\"name\":\"Windows.ApplicationModel.VoiceCommands.VoiceCommandServiceConnection\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1f930301-f484-4e01-a8a7-264354c4b8e3}\",\"name\":\"Microsoft.Windows.Cast.Dlna\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d1e82114-4279-58b2-3e8c-4029990a68c6}\",\"name\":\"Microsoft.Windows.Analog.Perception.RenderingDiagnostics\",\"group\":\"\"},{\"guid\":\"{a94b7111-450d-598c-6aa3-6a7619e93e0d}\",\"name\":\"Microsoft.Windows.Analog.FloorFinder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{99c9988d-2185-5021-a21d-7a863b8a1a10}\",\"name\":\"Microsoft.Windows.Networking.BackgroundTransfer.BackgroundManagerPolicy\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f5fc3591-3651-415b-b8e0-ad0152089992}\",\"name\":\"Microsoft-Windows-Networking-BackgroundTransfer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5a8a94f3-249f-49f8-86d1-e6527c80622b}\",\"name\":\"Microsoft.Windows.NetworkInformation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5a5d74f5-4a16-4f3d-93a7-ad82c75de04f}\",\"name\":\"Microsoft.Windows.Cellcore.Lpa.WinRT\",\"group\":\"\"},{\"guid\":\"{7c970fc8-dae6-4b89-8bbf-294ee1c4a79d}\",\"name\":\"Microsoft.Windows.Networking.VPNPlugin.WinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5d466dd9-9294-5333-b680-eb4936c47c6e}\",\"name\":\"Microsoft.Windows.Payments.WinRT\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e6852bc9-a7b6-4127-ac15-8d5c50be9bd7}\",\"name\":\"Microsoft.Windows.PerceptionApi.Stub\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{36ff4c84-82a2-4b23-8ba5-a25cbdff3410}\",\"name\":\"Microsoft.Windows.Security.DevCredWinRt\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4b812e8e-9dfc-56fc-2dd2-68b683917260}\",\"name\":\"Microsoft.Windows.Security.CredentialPicker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{507c53ae-af42-5938-aede-4a9d908640ed}\",\"name\":\"Microsoft.Windows.Security.Credentials.UserConsentVerifier\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f0c781fb-3451-566e-121c-9020159a5306}\",\"name\":\"Microsoft.Windows.SharedPC.AccountManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e47d4689-eb07-4a9a-9c53-52b967c2b5bd}\",\"name\":\"Microsoft.Windows.AccountManager.UserModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{369f0950-bf83-53a7-b3f0-771a8926329d}\",\"name\":\"ServiceHostBuilder\",\"group\":\"\"},{\"guid\":\"{312326fa-036d-4888-bc77-c3de2ff9ae06}\",\"name\":\"Microsoft.Windows.StateRepository.Broker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a89336e8-e6cf-485c-9c6a-ddb6614f278a}\",\"name\":\"Microsoft.Windows.StateRepository.Client\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{80a49605-87cb-4480-be97-d6ccb3dde5f2}\",\"name\":\"Microsoft.Windows.StateRepository.Upgrade\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{bff15e13-81bf-45ee-8b16-7cfead00da86}\",\"name\":\"Microsoft-Windows-AppModel-State\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a40b455c-253c-4311-ac6d-6e667edccefc}\",\"name\":\"Microsoft.Windows.Shell.CloudFilesAggregate\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{372e8999-7d93-5961-0479-d472d9fe23f7}\",\"name\":\"Microsoft.Windows.HVSI.AppLauncher\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4294747d-ee30-5fa6-a82f-3467fdf6f30f}\",\"name\":\"Microsoft.Windows.HVSI.FileTrust\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f85b4793-1347-5620-7572-b79d5a28da82}\",\"name\":\"Microsoft.Windows.Shell.DataLayer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e0142d4f-9e39-5b3b-9deb-8b576025ff5e}\",\"name\":\"Microsoft.Windows.CentennialActivation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{346d1079-24e3-5e7d-b93b-1806e4774512}\",\"name\":\"Microsoft.Windows.WindowsStorageOneCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{783f30af-5514-51bc-5b99-5d33b678539b}\",\"name\":\"Microsoft.Windows.Shell.StorageSearch\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1a6e901d-124c-441c-8c8e-bf8c3ae2fe11}\",\"name\":\"Windows.System.Diagnostics.Telemetry.PlatformTelemetryClient\",\"group\":\"\"},{\"guid\":\"{bd0a6a9f-74cf-4117-85b9-dda5f3f73214}\",\"name\":\"Windows.System.Diagnostics.TraceReporting.PlatformDiagnosticActions\",\"group\":\"\"},{\"guid\":\"{767f708a-096b-4930-b518-313844360af7}\",\"name\":\"Windows.System.Profile.PlatformDiagnosticsAndUsageDataSettings\",\"group\":\"\"},{\"guid\":\"{1d0a3e07-4587-52a6-9802-b0e44c2e08a8}\",\"name\":\"Microsoft.Windows.System.SysAdmin\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{628cd108-ad48-4db0-b286-1a55a14022a7}\",\"name\":\"Windows.System.UserProfile.DiagnosticsSettings\",\"group\":\"\"},{\"guid\":\"{67c7cabc-6a86-4f15-ace8-596cb87f0a72}\",\"name\":\"Microsoft.Windows.Shell.AppDefaults.PackageIteratorWrapper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{140cb1cd-7160-4d9c-893e-b61ccdcee1c1}\",\"name\":\"Microsoft.Windows.Shell.SystemSettings.AppsForWebsites\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{df350158-0f8f-555d-7e4f-f1151ed14299}\",\"name\":\"Microsoft.Windows.BioFeedback\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{41ad72c3-469e-5fcf-cacf-e3d278856c08}\",\"name\":\"Microsoft.Windows.BlockedShutdown\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ab7e1fbf-4623-5160-7d97-83167cf2bd39}\",\"name\":\"Microsoft.Windows.Input.Windows_UI_Core_Textinput\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{24532ca4-409f-5d6c-3ded-e11946573f56}\",\"name\":\"Microsoft.Windows.CredUXController\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6526f614-834f-46a9-8f4f-fab6c211888d}\",\"name\":\"Windows.ApplicationModel.CoreWindow\",\"group\":\"\"},{\"guid\":\"{d5369bbd-87fb-490a-8480-12798a2d18fa}\",\"name\":\"Microsoft.Windows.UI.InteractiveObject\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ee818f02-698c-48be-8ff2-326c6dd34db5}\",\"name\":\"SystemInitiatedFeedbackLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2888e8eb-2e0d-40db-82de-cef312d84ed4}\",\"name\":\"Microsoft.Windows.Shell.WindowsUIImmersiveProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{239d82f3-77e1-541b-2cbc-50274c47b5f7}\",\"name\":\"Microsoft.Windows.Shell.BridgeWindow\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e49b2c1a-1ad0-505c-a11a-73dba0c60f50}\",\"name\":\"Microsoft.Windows.Shell.Theme\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f8e28969-b1df-57fa-23f6-42260c77135c}\",\"name\":\"Microsoft.Windows.ImageSanitization\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{46668d11-2db1-5756-2a4b-98fce8b0375f}\",\"name\":\"Microsoft.Windows.Shell.Windowing.LightDismiss\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9dc9156d-fbd5-5780-bd80-b1fd208442d6}\",\"name\":\"Windows.UI.Popups\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1941de80-2226-413b-afa4-164fd76914c1}\",\"name\":\"Microsoft.Windows.Desktop.Shell.WindowsUIImmersive.LockScreen\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d3f64994-cca2-4f97-8622-07d451397c09}\",\"name\":\"MicrosoftWindowsShellUserInfo\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{fcad1076-c04f-4482-9a03-b5a37be6712d}\",\"name\":\"InkAnalysisLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2d52a580-4664-556b-972f-afa5b3b9964e}\",\"name\":\"Microsoft.Windows.Ink.InkManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{63897ce1-289c-4fcc-aff8-cafff43eeaf2}\",\"name\":\"Microsoft.Windows.Ink.Eraser\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ee8fdba0-14d6-50ec-a17a-33f388f21065}\",\"name\":\"Microsoft.Windows.UI.Input.Inking.DirectInk\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{89c72269-fb41-5e41-a17a-6595df57dad4}\",\"name\":\"Microsoft.Windows.UI.Input.Inking.TraceLogging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ec63acb7-e6ab-4d0e-96f1-13456336a29c}\",\"name\":\"Microsoft.Windows.Ink.DirectInk.InkPresenterRuler\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{176cd9c5-c90c-5471-38ba-0eeb4f7e0bd0}\",\"name\":\"Microsoft.Windows.UI.Logon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a6c5c84d-c025-5997-0d82-e608d1abbbee}\",\"name\":\"Microsoft.Windows.CredentialProvider.PicturePassword\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a75a574d-b3bb-434a-8482-b8f160ae4345}\",\"name\":\"Microsoft.Windows.NetworkUXController\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5512152d-88f8-5f1e-ed9f-6412175a39dc}\",\"name\":\"Microsoft.Windows.UI.PicturePassword\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{afe0ae07-66a7-55bb-12ff-01116bc08c1b}\",\"name\":\"Windows.UI.Xaml.Controls.Debug\",\"group\":\"\"},{\"guid\":\"{f55f7011-988d-4674-a724-e01b39dc7af7}\",\"name\":\"Windows.UI.Xaml.Controls.Perf\",\"group\":\"\"},{\"guid\":\"{21e0ae07-56a7-55b5-12f9-011e6bc08ccb}\",\"name\":\"Windows.UI.Xaml.Controls\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{832fe0f9-2e6f-5ec4-0523-7aab0a32c936}\",\"name\":\"Microsoft.Windows.UI.XAML.Input\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ddab1a3b-aadc-5f95-964f-d227b08f13c2}\",\"name\":\"Microsoft.Windows.Ink.InkOnText\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a6f1ccb9-b6b7-40db-a3de-103ea1d38062}\",\"name\":\"Microsoft.Windows.Ink.InkSamplesData\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a9813670-eed8-4e92-a2ff-6583c6734c93}\",\"name\":\"Windows.UI.Xaml.InkControls\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8d5fa2c8-70d1-5495-8f4f-25ba174930bd}\",\"name\":\"Microsoft.Windows.DXaml.InkControls\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a9813670-eed8-4e92-a2ff-6583c6734c93}\",\"name\":\"Windows.UI.Xaml.Maps\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a9813670-eed8-4e92-a2ff-6583c6734c93}\",\"name\":\"Windows.UI.Xaml.Phone\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{91fa71ae-c399-5de0-de6f-5b728993ccf1}\",\"name\":\"Microsoft.Windows.XamlHostLogger\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b5361807-6783-4295-a34e-a714865cccee}\",\"name\":\"Microsoft.Windows.Web.HttpClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7c29709d-3c02-47fb-8a39-d8287522fadb}\",\"name\":\"Microsoft.Windows.Graphics.WindowsCodecs\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d24afecc-4f90-45f1-b384-d6f960745274}\",\"name\":\"Microsoft.Windows.CapImg\",\"group\":\"\"},{\"guid\":\"{3686a7c1-8c7a-442d-ae1c-b498470968c2}\",\"name\":\"Microsoft.Windows.HVSI.CSP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{096f44f8-082d-5f73-0bb4-07686ec7a7d2}\",\"name\":\"Microsoft.Windows.ComposableShell.Framework.ComposerFramework\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3ad911fa-ef91-520f-b592-f81445ff373b}\",\"name\":\"Microsoft.Windows.ComposableShell.Framework.ComposerFramework.HardwareManagement\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b781b9cc-9bcc-486c-a036-d7bf98040a6b}\",\"name\":\"Microsoft.Windows.Wpr.Wprc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b5651691-cba4-572d-af20-da83df3573db}\",\"name\":\"Microsoft.Windows.HypervisorPlatform.Tracing\",\"group\":\"\"},{\"guid\":\"{1a211ee8-52db-4af0-bb66-fb8c9f20b0e2}\",\"name\":\"Microsoft.OSG.Web.WinInet\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{98177d7f-7d3a-51ef-2d41-2414bb2c0bdb}\",\"name\":\"Microsoft.Windows.Security.Wininit\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9c09afa4-969d-535c-60db-43f0f6de257d}\",\"name\":\"Microsoft.InformaionProtection.RMS.MSIPC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b39b8cea-eaaa-5a74-5794-4948e222c663}\",\"name\":\"Microsoft.Windows.Security.Winlogon\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d766d9ff-112c-4dac-9247-241cf99d123f}\",\"name\":\"Microsoft.Windows.WinML\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c69cb70a-3133-4cca-ab0e-046848effcda}\",\"name\":\"Microsoft.Windows.Print.Winspool\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6035d7f9-6e24-44bf-b540-3ade030d001a}\",\"name\":\"Microsoft.Windows.Csrss.WinSrvExt\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d33e545f-59c3-423f-9051-6dc4983393a8}\",\"name\":\"winsta\",\"group\":\"\"},{\"guid\":\"{4e7add1a-6945-435a-82b6-612688ba9f57}\",\"name\":\"WinTypeTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b57f5bf8-9486-51f5-25d0-81e66ff5ea46}\",\"name\":\"Microsoft.Windows.MetadataResolution.NamespaceResolution\",\"group\":\"\"},{\"guid\":\"{ab9ebce4-fe7f-4dab-ace8-b28af18ec32d}\",\"name\":\"WlanMSM\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f4190f32-f96e-479c-a45d-d485cffe42e6}\",\"name\":\"Microsoft.Windows.Networking.Wlan.Msmsec\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0b9b891e-ff74-49ac-a582-4c58bdf12d8b}\",\"name\":\"Wlansvc\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4f28a611-e7f9-4fa6-8bf1-8698d06336e9}\",\"name\":\"Microsoft.Windows.WiFi.Diag\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9a2edb8f-5883-499f-aced-6e4b69d43ddf}\",\"name\":\"WldpTraceLoggingProvider\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{596426a4-3a6d-526c-5c63-7ca60db99f8f}\",\"name\":\"Microsoft.Windows.WindowsMediaPlayer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ed2c1ccc-a5ec-5cea-ef9a-88905c5d4950}\",\"name\":\"Microsoft.Windows.MediaFoundation.WMVDecoder\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c906ed7b-d3d9-435b-97cd-22f4e7445f2a}\",\"name\":\"Microsoft.Windows.WorkFolders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ebed161a-909d-4f6b-a368-a28ad2c00051}\",\"name\":\"Microsoft.Windows.OneSettingsClient\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0eb5d084-6594-56c7-3885-b8841baf9d48}\",\"name\":\"Microsoft.FamilySafety.UI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1c5db447-7734-42ad-a940-7365dabe0990}\",\"name\":\"Microsoft.FamilySafety.ActivityEvents\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{11c45211-19ed-589b-547e-0efd9ecedc6d}\",\"name\":\"Microsoft.Windows.FamilySafety.ScreenTime\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2d617ccf-25cb-5351-d434-82c4dfa19059}\",\"name\":\"Microsoft.FamilySafety.Sync\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f01e66c7-3939-5ee2-ddb3-399cfeead698}\",\"name\":\"Microsoft.Windows.Shell.Wpd\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2fdb1f25-8de1-4bc1-bac2-e445e5b38743}\",\"name\":\"Microsoft.Windows.Notifications.WpnApps\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1870fbb0-2247-44d8-bf46-b02130a8a477}\",\"name\":\"Microsoft.Windows.Notifications.WpnApis\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c8153845-2370-4820-b07e-416c7806e123}\",\"name\":\"Microsoft.Windows.TileDeveloperAPIsTelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b92d1ff0-92ec-444d-b7ec-c016f971c000}\",\"name\":\"Microsoft.Windows.Notifications.WpnCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0fffb788-b827-4730-ad87-f48da61795cd}\",\"name\":\"Microsoft.Windows.Notifications.WnsCP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ee845016-ebe1-41eb-be52-5e3ae58339f2}\",\"name\":\"WNSCP\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{833c9bbd-6422-59cb-83bb-c695934a0cf5}\",\"name\":\"Microsoft.Windows.PerProcessSystemDpi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d0f1a5c6-fc43-48ae-99bf-efb1c38be9d1}\",\"name\":\"Microsoft-Windows-Winsock2\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{29b47072-00ff-4d9d-852d-0eafc181a9a3}\",\"name\":\"Microsoft.Windows.WSD.WSDApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{35d62ec7-6419-4d8d-b314-a2441d169fb5}\",\"name\":\"Microsoft.Windows.WSD.WsdChngr\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a0c4a2e1-ef83-439e-92d6-0e40eabe8b34}\",\"name\":\"Microsoft.Windows.Storage.FileServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{49f59745-7f56-4082-a01a-83bc089d1add}\",\"name\":\"Microsoft.Windows.Health\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{97a22197-db89-42de-a77c-7501534729fe}\",\"name\":\"Microsoft.Wdf.Companion.Host\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{84a5010c-3fd1-499f-885f-7ccb03bfde8d}\",\"name\":\"Microsoft.Wdf.UMDF.Host\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{15de6eaf-ee08-4de7-9a1c-bc7534ab8465}\",\"name\":\"Microsoft.Wdf.UMDF.FxV1\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8ad60765-a021-4494-8594-9346970cf50f}\",\"name\":\"Microsoft.Wdf.UMDF.Fx\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ac865f6d-84b9-4ada-8e46-fd61eb7448da}\",\"name\":\"WWAHostTraceLogging\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{86b9d85c-edb3-4775-8192-fb78ba22cfc6}\",\"name\":\"Microsoft.Windows.CellCore.MobileBroadband.MBNApi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45b3ce29-106e-528d-878f-6b34d02e1fc8}\",\"name\":\"Microsoft-Windows-Desktop-Shell-WWAN-OOBE\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5a454db4-0839-4ee5-8157-1e54f6eef842}\",\"name\":\"Microsoft.Windows.CellCore.MobileBroadband.Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{af5c9658-6b92-4f83-8b6a-1447549fb878}\",\"name\":\"Microsoft.Xbox.AuthManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{57a77336-f39e-4fe3-9bd7-ab58696e5000}\",\"name\":\"Microsoft.Xbox.NetworkTransferManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{514775e1-fa95-459f-b6d4-b86ad1c5b49e}\",\"name\":\"Microsoft.Windows.Networking.XboxLive.SecureSockets\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1878b8a3-2425-417b-a0c8-7b567652d45c}\",\"name\":\"Microsoft.Windows.XInput1_4\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a36919e0-4940-4280-bdaf-446877fe5cbe}\",\"name\":\"Microsoft.XInputUap\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{095da8da-2182-5c9a-53cd-07eca93a04ef}\",\"name\":\"Microsoft.Windows.Print.XpsDocumentTargetPrint\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0a82e916-4637-4998-83bf-8b0f4792a7c9}\",\"name\":\"Microsoft.Windows.Print.XGC\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{ddf2cc14-a470-4449-ab03-f8b95fc8294b}\",\"name\":\"Microsoft.Windows.Print.XpsPrint\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f5ee7f70-d686-479e-a4dd-91433dbf301e}\",\"name\":\"Microsoft.Windows.Maps.ZTrace\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5c3e3aa8-3ba4-43cd-a7de-3bf5f70f9ca4}\",\"name\":\"Microsoft.Windows.Shell.TextInput.InputPanel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f917a1ee-0a04-5157-9a8b-9ba716e318cb}\",\"name\":\"Microsoft.Windows.ClipboardHistory.UI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{7afc2639-a7e9-5fb6-92f0-ef2fe1751103}\",\"name\":\"Microsoft.Windows.Shell.SyncPartnership\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6f0783ec-d7cd-4f82-bca8-1afb56792c77}\",\"name\":\"Microsoft.Windows.AsyncTextService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a55d5a23-1a5b-580a-2be5-d7188f43fae1}\",\"name\":\"Microsoft.Windows.Shell.BioEnrollment\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f2018623-63ac-5837-7cfb-f67ec5c39961}\",\"name\":\"Microsoft.Windows.Shell.CredDialogHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e7192f96-e81e-4212-af9f-fdebecaab722}\",\"name\":\"Microsoft.Windows.Input.GazeUITelemetry\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b2149bc3-9dfd-5866-92a7-b556b3a6aed0}\",\"name\":\"Microsoft.Windows.Shell.DefaultLockApp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cc8b5a2a-297c-5dfd-1eec-c7bcdec2f7ae}\",\"name\":\"Microsoft.Windows.Shell.MtcViewModel\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{425af0d6-253a-49e6-8e41-c7c9849bb397}\",\"name\":\"Microsoft.Windows.App.Browser.Analytics\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{8314a32f-6144-4909-949d-91c8bb9eed9e}\",\"name\":\"Windows.PdfReader\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3b47c115-3006-5621-8599-7c5d8b83a0ec}\",\"name\":\"Microsoft.Windows.Cast.MiracastReceiverXaml\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{367d1466-64fd-51c2-08d1-d6adaa782549}\",\"name\":\"Microsoft.Windows.Cast.MiracastReceiverApplication\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9fb2567b-3978-56f3-df3d-ac4c0a60e2a2}\",\"name\":\"Microsoft.Windows.Cast.MiracastReceiverCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{03eee74c-cacc-56b0-59c7-9e14f162a5d2}\",\"name\":\"Microsoft.Windows.Cast.MiracastReceiverProjection\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{c1ecefb7-e831-599c-582e-3ddb0b9c1f14}\",\"name\":\"Microsoft.Windows.Cast.MiracastIngestModule\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9e55bad3-bc33-5597-57f8-4405c0251507}\",\"name\":\"Microsoft.Windows.Cast.MiracastReceiverInputModule\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{cb205507-3a73-565d-1eea-4ad4fe1a0e22}\",\"name\":\"Microsoft.Windows.Projection.WiredTouchbackInputManager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2afc7cc8-54f1-5454-e893-053286f909be}\",\"name\":\"Microsoft.Windows.Cast.MiracastHidInputGenerator\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{32da0980-2f98-5ab9-f93b-67ce6b46a8b8}\",\"name\":\"Microsoft.Windows.Shell.AddSuggestedFoldersToLibraryDialog\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5d93d94b-7362-47ea-8824-63de1683fc4f}\",\"name\":\"Microsoft.Windows.Shell.AssignedAccessLockApp\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a5e3b77c-1a36-4f74-918e-9c928f7f0595}\",\"name\":\"Microsoft.Windows.Shell.Components.Calling\",\"group\":\"\"},{\"guid\":\"{a5347b8a-3c9c-4f07-9440-1e0c5cfcc9d0}\",\"name\":\"Microsoft-Windows-Telephony-CallingShellPresenters\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4be7b04b-179f-47cb-b6d9-b58ceef35be7}\",\"name\":\"Microsoft.Windows.Apps.PhoneShellUi\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d0034f5e-3686-5a74-dc48-5a22dd4f3d5b}\",\"name\":\"Microsoft.Windows.Shell.CloudExperienceHost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{236aa069-3998-5ebc-e1ab-255eae1d59c5}\",\"name\":\"Microsoft.Windows.FeatureConfiguration\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{dc78ea1d-0cc0-59fa-e062-0c4b810ea1cc}\",\"name\":\"Microsoft.Windows.WilFeatures\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1f61b204-c3df-5f16-8ab9-cfc8d1fdc5f5}\",\"name\":\"Microsoft.Windows.ContentManagementSDK\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{880e5d98-55d3-50c7-f8b7-b1feafdb7fd2}\",\"name\":\"Microsoft.Windows.AppTelemetryMetadata\",\"group\":\"\"},{\"guid\":\"{f4aafa99-9f2a-53e5-3b32-ad9fb178f27f}\",\"name\":\"Microsoft-Windows-Shell-CortanaSpeechPlatform\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{70400dee-6c5b-5209-4052-b9f8cf41b7d7}\",\"name\":\"Microsoft.Windows.ReactiveAgentFramework\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d8caafb9-7211-5dc8-7c1f-8027d50640ec}\",\"name\":\"Microsoft.Windows.Shell.CortanaSignals\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9b3fe00f-dac4-4437-a77b-de27b87046d4}\",\"name\":\"Microsoft.Windows.Shell.CortanaSettings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{32d301bb-dc0f-5c78-8787-6f9580648baa}\",\"name\":\"Microsoft-Windows-Shell-CortanaCSU\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4c330fff-c5a3-4fb2-9d06-8e6d17d870bb}\",\"name\":\"Microsoft.Windows.Shell.CortanaSpa\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{01848a9c-1c29-5ceb-18d3-b3dd1eb945f2}\",\"name\":\"Windows.Cortana.NlFacilities\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2aedc292-3fa5-472a-8eb4-33978d449853}\",\"name\":\"Microsoft.Windows.Shell.CortanaSync\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{92f43f71-2741-40b2-a566-70eebcf2d181}\",\"name\":\"Microsoft-Windows-Shell-CortanaValidation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1b501233-07e5-4ac3-b3eb-faed7dadd9dc}\",\"name\":\"Microsoft.Windows.Shell.CortanaBluetooth\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1fcc7068-9055-45c2-b98c-c2261e3b1518}\",\"name\":\"Microsoft.Windows.Shell.Cortana.PlacesServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6a94aa20-3a78-4af8-9960-97356365ff34}\",\"name\":\"Microsoft.Windows.Shell.Cortana.PlaceStore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6326ccfb-aa7e-4f3b-8a39-c7e350f8c85c}\",\"name\":\"Microsoft-Windows-Shell-CortanaVaReminders\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9ab51436-e5a1-54a9-6812-1117a46bc568}\",\"name\":\"Microsoft.Windows.Cortana.VoiceAgent.VoiceCommand\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{59b03bfe-81f7-5749-0e6a-1f7ad5a0de1a}\",\"name\":\"Microsoft.Windows.Shell.CortanaVaEmail\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2012017d-3386-5354-d5fd-9d311cfc3a5c}\",\"name\":\"Microsoft.Windows.Shell.CortanaInkNotes\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{6223d4a4-b778-47cd-964b-c9705edd36fb}\",\"name\":\"Microsoft.Windows.Shell.Cortana.Rules.WNS\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{e63d07ea-c8cf-4886-9798-a5b2309523ba}\",\"name\":\"Microsoft.Windows.Shell.CortanaPenLongPress\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{12b1f569-a6b1-5ceb-9f3b-b0d76f569f7f}\",\"name\":\"Microsoft.Windows.Audio.MicWizHelper\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5b7144a2-f0f6-4f99-a66d-fb2477e4cee6}\",\"name\":\"Microsoft.Windows.Shell.CortanaPlaces\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b9ca7b47-8bad-5693-9481-028527614d30}\",\"name\":\"Microsoft.Windows.Shell.CortanaNotebook\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{66f03b1f-1aec-5184-d349-a81761122be4}\",\"name\":\"Microsoft.Windows.Shell.CortanaHome\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{79216333-1203-4c7b-a9f8-a0a0b69502e2}\",\"name\":\"Microsoft.Windows.Shell.CortanaVaCaptureAndBroadcast\",\"group\":\"\"},{\"guid\":\"{ad0971eb-d60f-4071-a1d7-d08e34a16b4d}\",\"name\":\"Microsoft.Windows.Shell.CortanaVaGlobalShell\",\"group\":\"\"},{\"guid\":\"{4d7e4a1b-197b-42ea-bb14-ca022484286e}\",\"name\":\"Microsoft.Windows.Shell.CortanaVaMediaControl\",\"group\":\"\"},{\"guid\":\"{b66504df-e8df-43af-b316-ac60c23e3430}\",\"name\":\"Microsoft-TextEntityExtractor\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9c2be007-6b96-59cd-6af0-f35d12c81365}\",\"name\":\"Microsoft-Windows-Shell-CortanaVaStartMenu\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{d173c6af-d86c-5327-17b8-5dcc03543da5}\",\"name\":\"Microsoft.Windows.Mobile.Shell.FileExplorer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f401924c-6fb0-5abb-be79-b010fb9ba7d4}\",\"name\":\"Microsoft.Windows.Shell.FilePicker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4fab096b-c7c1-5e77-c136-7c57122d3163}\",\"name\":\"Microsoft.Windows.Defender.App\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2ab3a3cd-f771-4530-a065-a846d50a03b5}\",\"name\":\"Microsoft.Windows.Graphics.D3D8\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{3d7a8e5f-0b44-432c-a0ce-b92f585a2ffe}\",\"name\":\"Microsoft.Windows.Graphics.D3D7\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{f1c13488-91ac-4350-94de-5f060589c584}\",\"name\":\"Microsoft.Windows.Shell.LockScreenBoost\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{877ee62a-d19d-4ffd-8f85-6977f1f4cf2a}\",\"name\":\"Microsoft.OneDrive.Sync.Setup\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{561bf4f9-44e3-5408-d19d-11d5272b125a}\",\"name\":\"Microsoft.OneDrive.Sync.Client\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{f5168a2d-1104-466a-988a-def1a9ee2863}\",\"name\":\"Microsoft.Windows.TextInput.CandidateSearch\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{287f6c83-0e11-5bcf-1acd-18f7edb17672}\",\"name\":\"Microsoft.Windows.TextInput.ToolBar\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{99a78d84-d872-50ef-6e7d-10a65338ffd1}\",\"name\":\"Microsoft.Windows.Shell.InkLinguisticData\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{44fd5187-4cf5-42ed-a830-af0f1f63ece0}\",\"name\":\"Microsoft.Windows.Scan.InboxTwainDsm\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{45887188-0c92-491c-8754-1781a5f79573}\",\"name\":\"Microsoft.Windows.WinHlp32\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2ed5c5df-6026-4e25-9fb1-9a08701125f3}\",\"name\":\"Microsoft.Windows.HyperV.VMBus\",\"group\":\"\"},{\"guid\":\"{51ddfa29-d5c8-4803-be4b-2ecb715570fe}\",\"name\":\"Microsoft-Windows-Hyper-V-Worker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{a572eeb4-c3f7-5b0e-b669-bb200931d134}\",\"name\":\"Microsoft.Windows.HyperV.Worker.VmbusPipeIO\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{67dc0d66-3695-47c0-9642-33f76f7bd7ad}\",\"name\":\"Microsoft.Windows.Hyper-V.VmSwitch\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{2174371b-d5f6-422b-bfc4-bb6f97ddaa84}\",\"name\":\"Microsoft.Windows.HyperV.Storage\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{4ddf50d0-75de-4fbe-8f08-f8936638e7a1}\",\"name\":\"Microsoft.Windows.HyperV.Management\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{06c601b3-6957-4f8c-a15f-74875b24429d}\",\"name\":\"Microsoft.Windows.HyperV.Worker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5e01db5e-1944-5314-c040-c90b965ea3d3}\",\"name\":\"Microsoft.Windows.HyperV.Worker.MemoryManager\",\"group\":\"\"},{\"guid\":\"{7568b40b-dc66-5a30-55a1-d0ef61b56ac8}\",\"name\":\"Microsoft.Windows.HyperV.Worker.Intercepts\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{22267b1c-b979-5c81-9e24-0db386a62dd1}\",\"name\":\"Microsoft.Windows.Containers.Setup\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{35862f23-8c60-473f-a6a2-f1cf722d140c}\",\"name\":\"Microsoft.Windows.Containers.DisposableVM\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{74c975b8-6693-4aef-a440-13a4def639a6}\",\"name\":\"Microsoft.Windows.Containers.ImageWorker\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{9d911ddb-d45f-41c3-b766-d566d2655c4a}\",\"name\":\"Microsoft.Windows.Containers.Manager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{1c96fbdb-6ea8-4255-815d-a101ea589b14}\",\"name\":\"Microsoft.Windows.ShellLauncher\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0c885e0d-6eb6-476c-a048-2457eed3a5c1}\",\"name\":\"Microsoft-Windows-Host-Network-Service\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{106e9835-2e81-5341-fd84-ab263098e7d3}\",\"name\":\"Microsoft.Windows.HVSI.Settings\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{31a02453-ca69-48d4-a17e-97d08518f45c}\",\"name\":\"Microsoft.Windows.HVSI.ContainerService\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{73f342c6-2434-4b8b-82e3-41838ed29f72}\",\"name\":\"Microsoft.Windows.IIS.FTPServer\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{92c65170-4121-4246-9730-e37c1cc83dc2}\",\"name\":\"Microsoft.Windows.IIS.WebDAV\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{754e4536-6735-4194-be81-1374bd2e9b0d}\",\"name\":\"Microsoft.Windows.Subsystem.Adss\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0cd1c309-0878-4515-83db-749843b3f5c9}\",\"name\":\"Microsoft.Windows.Subsystem.LxCore\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{b99cdb5a-039c-5046-e672-1a0de0a40211}\",\"name\":\"Microsoft.Windows.Lxss.Manager\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{0451ab4f-f74d-4008-b491-eb2e5f5d8b89}\",\"name\":\"Microsoft.Windows.Lxss.Heartbeat\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{204ae8f0-42f7-4a13-97cd-b490927cb725}\",\"name\":\"Microsoft.Windows.VGPU.RDVGM\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{eb22bd6c-fa62-4bff-81c5-baf66338eafc}\",\"name\":\"Microsoft.Windows.BootFileServicingAI\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5e30c57a-8730-4809-945e-0d5df7aa58e5}\",\"name\":\"Microsoft.ClientLicensing.InheritedActivation\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{5fc48aed-2eb8-4cd4-9c87-54700c4b7b26}\",\"name\":\"CbsServicingProvider\",\"group\":\"c7de053a-0c2e-4a44-91a2-5222ec2ecdf1\"},{\"guid\":\"{163624ca-6de7-4614-a43f-dcffa869fb7b}\",\"name\":\"Microsoft.Windows.SMB.SRV\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"},{\"guid\":\"{535caa1e-5771-5888-887a-15eaab1580e1}\",\"name\":\"Microsoft.Windows.ComCtl\",\"group\":\"4f50731a-89cf-4782-b3e0-dce8c90476ba\"}]\n"
  },
  {
    "path": "SystemInformer/resources/pooltag.txt",
    "content": "//\n//    Copyright (C) Microsoft.  All rights reserved.\n//\nrem\nrem    Pooltag.txt\nrem\nrem    This file lists the tags used for pool allocations by kernel mode components\nrem    and drivers.\nrem\nrem    The file has the following format:\nrem       <PoolTag> - <binary-name> - <Description>\nrem\nrem    Pooltag.txt is installed with Debugging Tools for Windows (in %windbg%\\triage)\nrem    and with the Windows DDK (in %winddk%\\tools\\other\\platform\\poolmon, where\nrem    platform is amd64, i386, or arm).\nrem\n\n@GMM - <unknown>    - (Intel video driver) Memory manager\n@KCH - <unknown>    - (Intel video driver) Chipset specific service\n@MP  - <unknown>    - (Intel video driver) Miniport related memory\n@SB  - <unknown>    - (Intel video driver) Soft BIOS\n\n_ATI - <unknown>    - ATI video driver\n\n_LCD - monitor.sys  - Monitor PDO name buffer\n\n8042 - i8042prt.sys - PS/2 keyboard and mouse\n\nAdSv - vmsrvc.sys   - Virtual Machines Additions Service\nARPC - atmarpc.sys  - ATM ARP Client\nATMU - atmuni.sys   - ATM UNI Call Manager\nAtom - <unknown>    - Atom Tables\nAbos - <unknown>    - Abiosdsk\nAcdM - <unknown>    - TDI AcdObjectInfoG\nAcdN - <unknown>    - TDI AcdObjectInfoG\nAcpA - acpi.sys     - ACPI arbiter data\nAcpB - acpi.sys     - ACPI buffer data\nAcpD - acpi.sys     - ACPI device data\nAcpE - acpi.sys     - ACPI embedded controller data\nAcpF - acpi.sys     - ACPI interface data\nAcpg - acpi.sys     - ACPI GPE data\nAcpi - acpi.sys     - ACPI generic data\nAcpI - acpi.sys     - ACPI irp data\nAcpL - acpi.sys     - ACPI lock data\nAcpM - acpi.sys     - ACPI miscellaneous data\nAcpO - acpi.sys     - ACPI object data\nAcpP - acpi.sys     - ACPI power data\nAcpR - acpi.sys     - ACPI resource data\nAcpS - acpi.sys     - ACPI string data\nAcpt - acpi.sys     - ACPI table data\nAcpT - acpi.sys     - ACPI thermal data\nAcpX - acpi.sys     - ACPI translation data\nAdap - <unknown>    - Adapter objects\nAdbe - <unknown>    - Adobe's font driver\nADPT - acpipagr.sys - Processor Aggregator Driver\nAECi - <unknown>    - filter object interface for MS acoustic echo canceller\nAfd? - afd.sys      - AFD objects\nAfdA - afd.sys      -     Afd EA buffer\nAfdB - afd.sys      -     Afd data buffer\nAfdC - afd.sys      -     Afd connection structure\naFDC - afd.sys      -     Afd WSK client context\naFDT - afd.sys      -     Afd TL provider context\nAfdD - afd.sys      -     Afd debug data\nAfdE - afd.sys      -     Afd endpoint structure\nAfdF - afd.sys      -     Afd TransmitFile info\nAfdG - afd.sys      -     Afd group table\nAfdI - afd.sys      -     Afd TDI data\nAfdL - afd.sys      -     Afd local address buffer\nAfdP - afd.sys      -     Afd poll info\nAfdQ - afd.sys      -     Afd work queue item\nAfdR - afd.sys      -     Afd remote address buffer\nAfdS - afd.sys      -     Afd security info\nAfdT - afd.sys      -     Afd transport info\nAfdW - afd.sys      -     Afd work item\nAfdX - afd.sys      -     Afd context buffer\nAfda - afd.sys      -     Afd APC buffer (NT 3.51 only)\nAfdc - afd.sys      -     Afd connect data buffer\nAfdd - afd.sys      -     Afd disconnect data buffer\nAfdf - afd.sys      -     Afd TransmitFile debug data\nAfdh - afd.sys      -     Afd address list change buffer\nAfdi - afd.sys      -     Afd \"set inline mode\" buffer\nAfdl - afd.sys      -     Afd lookaside lists buffer\nAfdp - afd.sys      -     Afd transport IRP buffer\nAfdq - afd.sys      -     Afd routing query buffer\nAfdr - afd.sys      -     Afd ERESOURCE buffer\nAfdt - afd.sys      -     Afd transport address buffer\nAhca - ahcache.sys  -     Appcompat kernel cache pool tag\n\nAleD - tcpip.sys    -     ALE remote endpoint\nAla4 - tcpip.sys    -     ALE remote endpoint IPv4 address\nAla6 - tcpip.sys    -     ALE remote endpoint IPv6 address\nAlei - tcpip.sys    -     ALE arrival/nexthop interface cache\nAleU - tcpip.sys    -     ALE pend context\nAleE - tcpip.sys    -     ALE endpoint context\nAlLl - tcpip.sys    -     ALE remote endpoint LRU\nAlCi - tcpip.sys    -     ALE credential info\nAlSP - tcpip.sys    -     ALE secure socket policy\nAlPU - tcpip.sys    -     ALE secure socket policy update\nAlPi - tcpip.sys    -     ALE peer info\nAlP4 - tcpip.sys    -     ALE peer IPv4 address\nAlP6 - tcpip.sys    -     ALE peer IPv6 address\nAlPT - tcpip.sys    -     ALE peer target\nAlep - tcpip.sys    -     ALE process info\nAleS - tcpip.sys    -     ALE token info\nAleP - tcpip.sys    -     ALE process image path\nAleK - tcpip.sys    -     ALE audit\nAleA - tcpip.sys    -     ALE connection abort context\nAlDN - tcpip.sys    -     ALE endpoint delete notify\nAleW - tcpip.sys    -     ALE enum filter array\nAleN - tcpip.sys    -     ALE notify context\nAlSs - tcpip.sys    -     ALE socket security context\nAlPF - tcpip.sys    -     ALE policy filters\nAleL - tcpip.sys    -     ALE LRU\nAleI - tcpip.sys    -     ALE token ID\nAlP5 - tcpip.sys    -     ALE 5-tuple state\nAlE5 - tcpip.sys    -     ALE 5-tuple temp entry\n\nAric - tcpip.sys    -     ALE route inspection context\nAdnc - tcpip.sys    -     ALE endpoint deactivation notification context\nAcrc - tcpip.sys    -     ALE connect request inspection context\nAcrl - tcpip.sys    -     ALE connect redirect layer data\nAbrc - tcpip.sys    -     ALE bind request inspection context\nAbrl - tcpip.sys    -     ALE bind redirect layer data\nAlSm - tcpip.sys    -     ALE Secondary App Meta Data\n\nAfp  - <unknown>    - SFM File server\nAlCI - nt!alpc      - ALPC communication info\nAlEv - nt!alpc      - ALPC eventlog queue\nAlIn - nt!alpc      - ALPC Internal allocation\nAlHa - nt!alpc      - ALPC port handle table\nAlMs - nt!alpc      - ALPC message\nALPC - nt!alpc      - ALPC port objects\nAlRe - nt!alpc      - ALPC section region\nAlRr - nt!Alpc      - ALPC resource reserves\nAlSc - nt!alpc      - ALPC section\nAlSe - nt!alpc      - ALPC client security\nAlVi - nt!alpc      - ALPC view\nATmp - AppTag mount point\nATon - AppTag object name\nATub - AppTag user buffer\nATgb - AppTag guid buffer\nATac - AppTag ATR command buffer\nATdi - AppTag cliendata index buffer\nATdt - AppTag cliendata temp buffer\nATFb - AppTag file id buffer\n\nAml* - <unknown>    - ACPI AMLI Pooltags\nAPIC - pnpapic.sys  - I/O APIC Driver\nArbA - nt!arb       - ARBITER_ALLOCATION_STATE_TAG\nArbL - nt!arb       - ARBITER_ORDERING_LIST_TAG\nArbM - nt!arb       - ARBITER_MISC_TAG\nArbR - nt!arb       - ARBITER_RANGE_LIST_TAG\nArp? - <unknown>    - ATM ARP server objects, atmarps.sys\nArpA - <unknown>    -     AtmArpS address\nArpB - <unknown>    -     AtmArpS buffer space\nArpI - <unknown>    -     AtmArpS Interface structure\nArpK - <unknown>    -     AtmArpS ARP block\nArpM - <unknown>    -     AtmArpS MARS structure\nArpR - <unknown>    -     AtmArpS NDIS request\nArpS - <unknown>    -     AtmArpS SAP structure\nAsy1 - <unknown>    - ndis / ASYNC_IOCTX_TAG\nAsy2 - <unknown>    - ndis / ASYNC_INFO_TAG\nAsy3 - <unknown>    - ndis / ASYNC_ADAPTER_TAG\nAsy4 - <unknown>    - ndis / ASYNC_FRAME_TAG\nAtC  - <unknown>    - IDE disk configuration\nAtD  - <unknown>    - atdisk.c\nATIX - <unknown>    - WDM mini drivers for ATI tuner, xbar, etc.\nAtk  - <unknown>    - Appletalk transport\nAtmA - <unknown>    - Atoms\nAtmT - <unknown>    - Atom tables\nAtvE - cea_km.lib   - Event broker aggregation library.\nAuxL - <unknown>    - EXIFS Auxlist\n\nAzAp - HDAudio.sys  - HD Audio Class Driver (Datastore: audio path)\nAzAd - HDAudio.sys  - HD Audio Class Driver (AzPcAudDev)\nAzCd - HDAudio.sys  - HD Audio Class Driver (CodecVendor)\nAzCE - HDAudio.sys  - HD Audio Class Driver (CEAAudioRender)\nAzCm - HDAudio.sys  - HD Audio Class Driver (AzCommon)\nAzFg - HDAudio.sys  - HD Audio Class Driver (Audio Function Group)\nAzfg - HDAudio.sys  - HD Audio Class Driver (datastore: function group)\nAzJd - HDAudio.sys  - HD Audio Class Driver (JackDetector)\nAzMa - HDAudio.sys  - HD Audio Class Driver (Main)\nAzMi - HDAudio.sys  - HD Audio Class Driver (micin, MixedCapture)\nAzMu - HDAudio.sys  - HD Audio Class Driver (MuxedCapture)\nAzMx - HDAudio.sys  - HD Audio Class Driver (AzMixerport)\nAzLd - HDAudio.sys  - HD Audio Class Driver (Datastore: logical device)\nAzLi - HDAudio.sys  - HD Audio Class Driver (CDIn,AUXIn, linein)\nAzLg - HDAudio.sys  - HD Audio Class Driver (debug)\nAzLs - HDAudio.sys  - HD Audio Class Driver (DLTest)\nAzPd - HDAudio.sys  - HD Audio Class Driver (AzDma)\nAzPx - HDAudio.sys  - HD Audio Class Driver (AzPower)\nAzRr - HDAudio.sys  - HD Audio Class Driver (RedirectedRender)\nAzRR - HDAudio.sys  - HD Audio Class Driver (SpdifEmbeddedRender, SpdifOut, Headphone, HBDAout)\nAzSd - HDAudio.sys  - HD Audio Class Driver (subdevicegraph)\nAzSi - HDAudio.sys  - HD Audio Class Driver (SpdifIn)\nAzSt - HDAudio.sys  - HD Audio Class Driver (AzWaveCyclicStream, HdaWaveRTstream)\nAzTs - HDAudio.sys  - HD Audio Class Driver (TestSet1000, TestSet1001)\nAzUT - HDAudio.sys  - HD Audio Class Driver (TestSet0004)\nAzWd - HDAudio.sys  - HD Audio Class Driver (AzWidget)\nAzWp - HDAudio.sys  - HD Audio Class Driver (AzWaveport, HdaWaveRTminiport)\n\nBat? - <unknown>    - Battery Class drivers\nBatC - <unknown>    -     Composite battery driver\nBatM - <unknown>    -     Control method battery driver\nBatS - <unknown>    -     Smart battery driver\nBatt - <unknown>    -     Battery class driver\nBCSP - bthbcsp.sys  - Bluetooth BCSP minidriver\nBCDK - nt!init      - Kernel boot configuration data.\nBDD  - BasicDisplay.sys - Microsoft Basic Display Driver\nBIG  - nt!mm        - Large session pool allocations (ntos\\ex\\pool.c)\nBlCc - blkcache.sys - Block Cache Driver\nBmfd - <unknown>    - Font related stuff\nBT3C - bt3c.sys     - Bluetooth 3COM minidriver\nBT8x - <unknown>    - WDM mini drivers for Brooktree 848,829, etc.\nBTHP - bthport.sys  - Bluetooth port driver (generic)\nBthS - bthport.sys  - Bluetooth port driver (security)\nBTME - bthenum.sys  - Bluetooth enumerator\nBTMO - bthmodem.sys - Bluetooth modem\nBTPT - <unknown>    - Bluetooth transport protocol library\nBTSR - bthser.sys   - Bluetooth serial minidriver\nBTUR - bthuart.sys  - Bluetooth UART minidriver\nWPAD - BasicRender.sys - Basic Render Adapter\nWPDV - BasicRender.sys - Basic Render DX Device\nWPCT - BasicRender.sys - Basic Render DX Context\nWPAL - BasicRender.sys - Basic Render Allocation\nWPAO - BasicRender.sys - Basic Render Opened Allocation\nWPRC - BasicRender.sys - Basic Render Rectangles (for Present)\nBu*  - <unknown>    - burneng.sys from adaptec\n\nBvHI - netiobvt.sys - BVT HT Items\nBvHT - netiobvt.sys - BVT HT Tables\n\nCall - nt!ex        - kernel callback object signature\ncall - <unknown>    - debugging call tables\nCBRe - <unknown>    - CallbackRegistration\nCBSI - cbsi.sys     - Common Block Store\nCc   - nt!cc        - Cache Manager allocations (catch-all)\nCcAs - nt!cc        - Cache Manager Async cached read structure\nCcBc - nt!cc        - Cache Manager Bcb from pool\nCcBm - nt!cc        - Cache Manager Bitmap\nCcBn - nt!cc        - Cache Manager Bcb trim notification entry\nCcBr - nt!cc        - Cache Manager Bitmap range\nCcBz - nt!cc        - Cache Manager Bcb Zone\nCcDw - nt!cc        - Cache Manager Deferred Write\nCcEC - nt!cc        - Cache Manager External Cache tracking structure\nCcEv - nt!cc        - Cache Manager Event\nCcFn - nt!cc        - Cache Manager File name for popups\nCCFF - CCFFilter.sys - Cluster Client Failover Filter\nCcfx - nt!cc        - Cache Manager Registry value full info structure\nCcMb - nt!cc        - Cache Manager Mbcb\nCcNu - nt!cc        - Cache Manager NUMA structures\nCcOb - nt!cc        - Cache Manager Overlap Bcb\nCcPB - nt!ccpf      - Prefetcher trace buffer\nCcPC - nt!ccpf      - Prefetcher context\nCcPD - nt!ccpf      - Prefetcher trace dump\nCcPF - nt!ccpf      - Prefetcher file name\nCcPI - nt!ccpf      - Prefetcher intermediate table\nCcPL - nt!ccpf      - Prefetcher read list\nCcPM - nt!ccpf      - Prefetcher metadata\nCcPS - nt!ccpf      - Prefetcher scenario\nCcPT - nt!ccpf      - Prefetcher trace\nCcPV - nt!ccpf      - Prefetcher queried volumes\nCcPW - nt!ccpf      - Prefetcher workers\nCcPa - nt!ccpf      - Prefetcher async context\nCcPc - nt!cc        - Cache Manager Private Cache Map\nCcPf - nt!ccpf      - Prefetcher\nCcPh - nt!ccpf      - Prefetcher header preallocation\nCcPn - nt!ccpf      - Prefetcher name info\nCcPp - nt!ccpf      - Prefetcher instructions\nCcPq - nt!ccpf      - Prefetcher query buffer\nCcPr - nt!ccpf      - Cache Manager Partition structures\nCcPs - nt!ccpf      - Prefetcher section table\nCcPv - nt!ccpf      - Prefetcher volume info\nCcPw - nt!ccpf      - Prefetcher enable worker\nCcSc - nt!cc        - Cache Manager Shared Cache Map\nCcTe - nt!cc        - Cache Manager Telemetry allocation\nCcVa - nt!cc        - Cache Manager Initial array of Vacbs\nCcVl - nt!cc        - Cache Manager Vacb Level structures (large streams)\nCcVp - nt!cc        - Cache Manager Array of Vacb pointers for a cached stream\nCctX - <unknown>    - EXIFX FCB Commit CTX\nCcWq - nt!cc        - Cache Manager Work Queue Item\nCcWK - nt!cc        - Kernel Cache Manager lookaside list\nCcWk - nt!cc        - Kernel Cache Manager lookaside list\nCcWR - nt!cc        - Cache Manager Registry watch structure\nCcZe - nt!cc        - Cache Manager Buffer of Zeros\nCDmp - crashdmp.sys - Crashdump driver\nCdA  - <unknown>    - CdAudio filter driver\nCdcc - cdfs.sys     - CDFS Ccb\nCddn - cdfs.sys     - CDFS CdName in dirent\nCdee - cdfs.sys     - CDFS Search expression for enumeration\nCdfd - cdfs.sys     - CDFS Data Fcb\nCdfi - cdfs.sys     - CDFS Index Fcb\nCdfl - cdfs.sys     - CDFS Filelock\nCdFn - cdfs.sys     - CDFS Filename buffer\nCdfn - cdfs.sys     - CDFS Nonpaged Fcb\nCdfs - cdfs.sys     - CDFS General Allocation\nCdft - cdfs.sys     - CDFS Fcb Table entry\nCdgs - cdfs.sys     - CDFS Generated short name\nCdic - cdfs.sys     - CDFS Irp Context\nCdil - cdfs.sys     - CDFS Irp Context lite\nCdio - cdfs.sys     - CDFS Io context for async reads\nCdma - cdfs.sys     - CDFS Mcb array\nCdpe - cdfs.sys     - CDFS Prefix Entry\nCdPn - cdfs.sys     - CDFS CdName in path entry\nCdpn - cdfs.sys     - CDFS Prefix Entry name\nCdsp - cdfs.sys     - CDFS Buffer for spanning path table\nCdtc - cdfs.sys     - CDFS TOC\nCdun - cdfs.sys     - CDFS Buffer for upcased name\nCdvd - cdfs.sys     - CDFS Buffer for volume descriptor\nCdvp - cdfs.sys     - CDFS Vpb allocated in filesystem\nCIcr - ci.dll       - Code Integrity allocations for image integrity checking\nCIsc - ci.dll       - Code Integrity core dll\nCIha - ci.dll       - Code Integrity hashes\nCKRT - <multiple>   - Cluster Kernel RTL library\nCLb* - clusbflt.sys - Cluster block storage target driver\nCLB* - clusbflt.sys - Cluster block storage target driver\nCLd* - clusdflt.sys - Cluster disk filter driver\nClfA - clfs.sys     - CLFS Log container lookaside list\nClfB - clfs.sys     - CLFS Log base file lookaside list\nClfC - clfs.sys     - CLFS Log physical FCB lookaside list\nClfD - clfs.sys     - CLFS Log virtual FCB lookaside list\nClfE - clfs.sys     - CLFS Log CCB lookaside list\nClfF - clfs.sys     - CLFS Log flush element lookaside list\nClfG - clfs.sys     - CLFS Log I/O Request lookaside list\nClfH - clfs.sys     - CLFS Log I/O control block lookaside list\nClfI - clfs.sys     - CLFS Log marshal buffer lookaside list\nClfJ - clfs.sys     - CLFS Log MDL reference\nClfK - clfs.sys     - CLFS Log read completion element\nClfL - clfs.sys     - CLFS Log base file image (obsolete)\nClfN - clfs.sys     - CLFS Log base file lock\nClfO - clfs.sys     - CLFS Log zero page\nClfP - clfs.sys     - CLFS Log request state\nClfS - clfs.sys     - CLFS Log base file snapshot\nClfs - clfs.sys     - CLFS General buffer, or owner page lookaside list\nClNt - netft.sys    - NetFt\nClNw - netft.sys    - NetFt work items\nCM   - nt!cm        - Configuration Manager (registry)\nCmcD - hal.dll      - HAL CMC Driver Log\nCmcK - hal.dll      - HAL CMC Kernel Log\nCmcT - hal.dll      - HAL CMC temporary Log\nCMCa - nt!cm        - Configuration Manager Cache (registry)\nCMDc - nt!cm        - Configuration Manager Cache (registry)\nCMkb - nt!cm        - registry key control blocks\nCMpb - nt!cm        - registry post blocks\nCMnb - nt!cm        - registry notify blocks\nCMpe - nt!cm        - registry post events\nCMpa - nt!cm        - registry post apcs\nCMsb - nt!cm        - registry stash buffer\nCmVn - nt!cm        - captured value name\nCMVw - nt!cm        - registry mapped view of file\nCMVa - nt!cm        - value cache value tag\nCMVI - nt!cm        - value index cache tag\nCMSc - nt!cm        - security cache pooltag\nCMSb - nt!cm        - internal stash buffer pool tag\nCMNb - nt!cm        - Configuration Manager Name Tag\nCMIn - nt!cm        - Configuration Manager  Index Hint Tag\nCMDa - nt!cm        - value data cache pool tag\nCMAl - nt!cm        - internal registry memory allocator pool tag\nCMA1 - nt!cm        - Configuration Manager Audit Tag 1\nCMA2 - nt!cm        - Configuration Manager Audit Tag 2\nCMA3 - nt!cm        - Configuration Manager Audit Tag 3\nCMA4 - nt!cm        - Configuration Manager Audit Tag 4\nCMIx - nt!cm        - Configuration Manager Intent Lock Tag\nCMUw - nt!cm        - Configuration Manager Unit of Work Tag\nCMTr - nt!cm        - Configuration Manager Transaction Tag\nCMRm - nt!cm        - Configuration Manager Resource Manager Tag\nCM?? - nt!cm        - Internal Configuration manager allocations\nCngb - ksecdd.sys   - CNG kmode crypto pool tag\nCOMX - serial.sys   - serial driver allocations\nCont - <unknown>    - Contiguous physical memory allocations for device drivers\nCopW - <unknown>    - EXIFS CopyOnWrite\nCovr - nt!cov       - Code Coverage pool tag\nCpeD - hal.dll      - HAL CPE Driver Log\nCpeK - hal.dll      - HAL CMC Kernel Log\nCpeT - hal.dll      - HAL CPE temporary Log\nCPnp - classpnp.sys - ClassPnP transfer packets\nCrsp - ksecdd.sys   - CredSSP kernel mode client allocations\nCrtH - <unknown>    - EXIFS Create Header\nCryp - ksecdd.sys   - Crypto allocations\nCSdk - <unknown>    - Cluster Disk Filter driver\nCSnt - <unknown>    - Cluster Network driver\nCTE  - <unknown>    - Common transport environment (ntos\\inc\\cxport.h, used by tdi)\nCvli - <unknown>    - EXIFS Cached Volume Info\n\nD2d  - <unknown>    - Device Object to DosName rtns (ntos\\rtl\\dev2dos.c)\nD3Dd - <unknown>    - DX D3D driver (embedded in a display driver like s3mvirge.dll)\nD851 - <unknown>    - 8514a video driver\nDacl - <unknown>    - Temp allocations for object DACLs\nDamK - dam.sys      - Desktop Activity Moderator\nDati - <unknown>    - ati video driver\nDbCb - nt!dbg       - Debug Print Callbacks\nDbLo - <unknown>    - Debug logging\ndcam - <unknown>    - WDM mini driver for IEEE 1394 digital camera\n\nDcbA - msdcb.sys    - DCB application priority\nDcbC - msdcb.sys    - DCB NMR provider context\nDcbD - msdcb.sys    - DCB NDIS_QOS_CONFIGURATION\nDcbG - msdcb.sys    - DCB string data\nDcbI - msdcb.sys    - DCB interface context\nDcbL - msdcb.sys    - DCB LLDP buffer\nDcbP - msdcb.sys    - DCB NDIS port information\nDcbR - msdcb.sys    - DCB store change record\nDcbS - msdcb.sys    - DCB security object\nDcbU - msdcb.sys    - DCB UQOS_POLICY_DESCRIPTOR\nDcbX - msdcb.sys    - DCB general\n\nDcdd - cdd.dll      - Canonical display driver\nDcl  - <unknown>    - cirrus video driver\nDdk  - <unknown>    - Default for driver allocated memory (user's of ntddk.h)\nDevi - <unknown>    - Device objects\n\nDEag - devolume.sys - Drive extender disk set array: DEVolume!DEDiskSet *\nDEbo - devolume.sys - Drive extender bus opener context: DEVolume!DEBusOpenerContext\nDEbe - devolume.sys - Drive extender extends buffer\nDEbg - devolume.sys - Drive extender bus opener context global: DEVolume!DEBusOpenerContextGlobal\nDEbm - devolume.sys - Drive extender bitmap\nDEbu - devolume.sys - Drive extender generic buffer\nDEcl - devolume.sys - Drive extender delayed cleaner: DEVolume!DelayedCleaner\nDEct - devolume.sys - Drive extender chunk table\nDEda - devolume.sys - Drive extender disk array: DEVolume!DEDisk *\nDEdb - devolume.sys - Drive extender disk directory information\nDEdc - devolume.sys - Drive extender disk chunk: DEVolume!DiskChunk\nDEdg - devolume.sys - Drive extender disk globals: DEVolume!DEDiskGlobals\nDEdi - devolume.sys - Drive extender disk: DEVolume!DEDisk\nDEdm - devolume.sys - Drive extender disk mini chunk: DEVolume!DiskMiniChunk\nDEdn - devolume.sys - Drive extender disk identification info: DEVolume!DiskIdentificationInfo\nDEdr - devolume.sys - Drive extender device relations\nDEds - devolume.sys - Drive extender disk set: DEVolume!DEDiskSet\nDEdt - devolume.sys - Drive extender disk message: DEVolume!DE_DISK_MESSAGE\nDEdu - devolume.sys - Drive extender disk set message: DEVolume!DE_DISK_SET_MESSAGE\nDEdv - devolume.sys - Drive extender driver object: DEVolume!DEDriver\nDEea - devolume.sys - Drive extender expanding array: DEVolume!ExpandingAutoPointerArray<T>\nDEec - devolume.sys - Drive extender ECC Page: DEVolume!DeEccPage\nDEfg - devolume.sys - Drive extender filter: DEVolume!DEFilter\nDEga - devolume.sys - Drive extender guild array\nDEic - devolume.sys - Drive extender filter instance context\nDEip - devolume.sys - Drive extender IRP based logical to physical request: DEVolume!IrpBasedLogicalToPhysicalRequest\nDEir - devolume.sys - Drive extender IRP based read request: DEVolume!IrpBasedReadRequest\nDEiw - devolume.sys - Drive extender IRP based write request: DEVolume!IrpBasedWriteRequest\nDEla - devolume.sys - Drive extender log mini chunk array\nDElb - devolume.sys - Drive extender log buffer\nDEli - devolume.sys - Drive extender disk set id record: DEVolume!DiskSetIdentificationRecord\nDElm - devolume.sys - Drive extender log manager: DEVolume!LogManager\nDElp - devolume.sys - Drive extender logical to physical request: DEVolume!LogicalToPhysicalRequest\nDElr - devolume.sys - Drive extender log reader: DEVolume!LogReader\nDElv - devolume.sys - Drive extender disk set volume id record: DEVolume!VolumeIdentificationRecord\nDElw - devolume.sys - Drive extender log writer buffer: DEVolume!LogWriterBuffer\nDEmc - devolume.sys - Drive extender volume chunk init mapping manager: DEVolume!VolumeChunkInitializationMappingManager\nDEml - devolume.sys - Drive extender log mapping manager: DEVolume!LogMappingManager\nDEms - devolume.sys - Drive extender superblock mapping manager: DEVolume!SuperBlockMappingManager\nDEmv - devolume.sys - Drive extender volume mapping manager: DEVolume!VolumeMappingManager\nDEog - devolume.sys - Drive extender old GUID array\nDEpe - devolume.sys - Drive extender pingable event: DEVolume!PingableEvent\nDEpg - devolume.sys - Drive extender pingable object globals: DEVolume!PingableObjectGlobals\nDEpm - devolume.sys - Drive extender physical map: DEVolume!PhysicalMap\nDEqm - devolume.sys - Drive extender queued message: DEVolume!QueuedMessage\nDEra - devolume.sys - Drive extender disk event request\nDErb - devolume.sys - Drive extender become dirty request: DEVolume!VolumeChunk::BecomeDirtyRequest\nDErc - devolume.sys - Drive extender commit request: DEVolume!VolumeChunk::CommitRequest\nDErd - devolume.sys - Drive extender decommit request: DEVolume!VolumeChunk::DecommitRequest\nDEre - devolume.sys - Drive extender decommit all request: DEVolume!DiskSetVolume::DecommitAllRequest\nDErg - devolume.sys - Drive extender registry: DEVolume!DERegistry\nDErh - devolume.sys - Drive extender replicate chunk: DEVolume!ReplicateChunk\nDErl - devolume.sys - Drive extender long and notify request: DEVolume!DiskSetVolume::LogAndNotifyRequest\nDErm - devolume.sys - Drive extender range lock manager: DEVolume!RangeLockManager\nDErn - devolume.sys - Drive extender new epoch request: DEVolume!DEDiskSet::NewEpochRequest\nDEro - devolume.sys - Drive extender become out of date request: DEVolume!VolumeChunk::BecomeOutOfDateRequest\nDErp - devolume.sys - Drive extender replicator: DEVolume!Replicator\nDErr - devolume.sys - Drive extender read request: DEVolume!ReadRequest\nDErs - devolume.sys - Drive extender delete or shutdown request: DEVolume!DiskSetVolume::DeleteOrShutdownRequest\nDErt - devolume.sys - Drive extender start request: DEVolume!DEDiskSet::StartRequest\nDEru - devolume.sys - Drive extender shutdown request: DEVolume!DEDiskSet::ShutdownRequest\nDErv - devolume.sys - Drive extender repair volume request: DEVolume!DiskSetVolume::RepairVolumeDamageRequest\nDErw - devolume.sys - Drive extender read write target: DEVolume!ReadWriteTarget\nDErx - devolume.sys - Drive extender shutdown system request: DEVolume!DiskSetVolume::ShutdownRequest\nDEry - devolume.sys - Drive extender start or create request: DEVolume!DiskSetVolume::StartOrCreateRequest\nDErz - devolume.sys - Drive extender write super blocks request: DEVolume!DEDiskSet::WriteSuperBlocksRequest\nDEsb - devolume.sys - Drive extender super block buffer\nDEsd - devolume.sys - Drive extender disk set disk: DEVolume!DiskSetDisk\nDEsg - devolume.sys - Drive extender disk set globals: DEVolume!DEDiskSetGlobals\nDEsh - devolume.sys - Drive extender space holder operation: DEVolume!SpaceHolderOperation\nDEte - devolume.sys - Drive extender data error message: DEVolume!DE_DATA_ERROR_MESSAGE\nDEtr - devolume.sys - Drive extender trace message\nDEtn - devolume.sys - Drive extender range lock test node\nDEtx - devolume.sys - Drive extender range lock test\nDEts - devolume.sys - Drive extender splay tree test\nDEtw - devolume.sys - Drive extender trim worker pauser: DEVolume!AutoPauseTrimWorker\nDEub - devolume.sys - Drive extender unaligned EccPage temp buffer: DEVolume!DeEccPage\nDEus - devolume.sys - Drive extender unicode string\nDEva - devolume.sys - Drive extender volume chunk array: DEVolume!AutoVolumeChunkPtr *\nDEvc - devolume.sys - Drive extender volume chunk: DEVolume!VolumeChunk\nDEvg - devolume.sys - Drive extender volume globals: DEVolume!DEVolumeGlobals\nDEvh - devolume.sys - Drive extender volume device globals: DEVolume!DEVolumeDeviceGlobals\nDEvm - devolume.sys - Drive extender volume message: DEVolume!DE_VOLUME_MESSAGE\nDEvo - devolume.sys - Drive extender volume message: DEVolume!DEVolume\nDEvs - devolume.sys - Drive extender disk set volume: DEVolume!DiskSetVolume\nDEwi - devolume.sys - Drive extender work item: DEVolume!AutoWorkItem\nDEze - devolume.sys - Drive extender cluster of zeros\n\nDh 0 - <unknown>    - DirectDraw/3D default object\nDh 1 - <unknown>    - DirectDraw/3D DirectDraw object\nDh 2 - <unknown>    - DirectDraw/3D Surface object\nDh 3 - <unknown>    - DirectDraw/3D Direct3D context object\nDh 4 - <unknown>    - DirectDraw/3D VideoPort object\nDh 5 - <unknown>    - DirectDraw/3D MotionComp object\n\nDfb  - <unknown>    - framebuf video driver\nDfC? - dfsc.sys     - DFS Client allocations\nDfCa - dfsc.sys     - DFS Client PERUSERTABLE\nDfCb - dfsc.sys     - DFS Client REFCONTEXT\nDfCc - dfsc.sys     - DFS Client CONNECTION\nDfCd - dfsc.sys     - DFS Client CURRENTDC\nDfCe - dfsc.sys     - DFS Client CSCEA\nDfCf - dfsc.sys     - DFS Client FILENAME\nDfCg - dfsc.sys     - DFS Client PREFIXCACHE\nDfCh - dfsc.sys     - DFS Client HASH\nDfCi - dfsc.sys     - DFS Client INPUTBUFFER\nDfCj - dfsc.sys     - DFS Client REFERRALNAME\nDfCj - dfsc.sys     - DFS Client REWRITTENNAME\nDfCl - dfsc.sys     - DFS Client DCLIST\nDfCm - dfsc.sys     - DFS Client CMCONTEXT\nDfCn - dfsc.sys     - DFS Client DOMAINNAME\nDfCp - dfsc.sys     - DFS Client PATH\nDfCq - dfsc.sys     - DFS Client REGSTRING\nDfCr - dfsc.sys     - DFS Client REFERRAL\nDfCs - dfsc.sys     - DFS Client SHARENAME\nDfCt - dfsc.sys     - DFS Client TREECONNECT\nDfCu - dfsc.sys     - DFS Client USETABLE\nDfCv - dfsc.sys     - DFS Client SERVERNAME\nDfCw - dfsc.sys     - DFS Client TARGETINFO\nDfCx - dfsc.sys     - DFS Client CREDENTIALS\nDfCy - dfsc.sys     - DFS Client REMOTEENTRY\nDfCz - dfsc.sys     - DFS Client DOMAINREFERRAL\nDfs  - <unknown>    - Distributed File System\ndfsr - <unknown>    - RDBSS IRP allocation\nDfsm - <unknown>    - Eng event allocation (ENG_KEVENTALLOC,ENG_ALLOC) in ntgdi\\gre\ndFVE - dumpfve.sys  - Full Volume Encryption crash dump filter (Bitlocker Drive Encryption)\nDict - storport.sys - StorCreateDictionary storport!_STOR_DICTIONARY.Entries\nDire - <unknown>    - Directory objects\nDlck - <unknown>    - deadlock verifier (part of driver verifier) structures\nDlmp - <unknown>    - Video utility library for Vista display drivers\nDmga - <unknown>    - mga (matrox) video driver\nDmH? - <unknown>    - DirectMusic hardware synthesizer\nDmpS - dumpsvc.sys  - Crashdump Service Driver\nDmS? - <unknown>    - DirectMusic kernel software synthesizer\nDndt - <unknown>    - Device node\nDnod - <unknown>    - Device node structure\nDNSk - netio.sys    - DNS RPC Transactions\nDOPE - <unknown>    - Device Object Power Extension (po component)\nDpDc - FsDepends.sys - FsDepends Dependency Context Block\nDpDl - FsDepends.sys - FsDepends Dependency List Block\nDpPl - FsDepends.sys - FsDepends Parent Link Block\nDPrf - <unknown>    - Disk performance filter driver\nDPwr - nt!pnp       - PnP power management\nDprt - dxgkrnl.sys  - Video port for Vista display drivers\nDps5 - <unknown>    - NT5 PostScript printer driver\nDpsh - <unknown>    - Postcript driver heap memory\nDpsi - <unknown>    - psidisp video driver\nDpsm - <unknown>    - Postcript driver memory\nDqv  - <unknown>    - qv (qvision) video driver\nDpVc - FsDepends.sys - FsDepends Volume Context Block\nDrDr - rdpdr.sys    - Global object\nDrEx - rdpdr.sys    - Exchange object\nDrIC - rdpdr.sys    - I/O context object\nDriv - <unknown>    - Driver objects\nDrsd - <unknown>    - Rasdd Printer Driver Pool Tag.\nDtga - <unknown>    - tga video driver\nDump - <unknown>    - Bugcheck dump allocations\nDun5 - <unknown>    - NT5 Universal printer driver\nDUQD - mpsdrv.sys   - MPSDRV upcall user request\nDV?? - <unknown>    - RDR2 DAV MiniRedir Tags\nDVCx - <unknown>    - AsyncEngineContext, DAV MiniRedir\nDVEx - <unknown>    - Exchange, DAV MiniRedir\nDVFi - <unknown>    - FileInfo, DAV MiniRedir\nDVFn - <unknown>    - FileName, DAV MiniRedir\nDVRw - <unknown>    - ReadWrite, DAV MiniRedir\nDVSc - <unknown>    - SrvCall, DAV MiniRedir\nDVSh - <unknown>    - SharedHeap, DAV MiniRedir\n\nDvga - <unknown>    - vga 16 color video driver\nDvg2 - <unknown>    - vga 256 color video driver\nDvg6 - <unknown>    - vga 64K color video driver\nDvgr - <unknown>    - vga for risc video driver\nDW32 - <unknown>    - W32 video driver\nDwd  - <unknown>    - wd90c24a video driver\nDwp9 - <unknown>    - weitekp9 video driver\nDxga - <unknown>    - XGA video driver\n\nDxgK - dxgkrnl.sys  - Vista display driver support\n\nEfsm - <unknown>    - EFS driver\nEfsc - <unknown>    - EFS driver\n\nEfst - <unknown>    -  EXIFS FS Statistics\n\nEnvr - <unknown>    - Environment strings\n\nEQAn - tcpip.sys    - EQoS application name\nEQCc - tcpip.sys    - EQoS counters\nEQHb - tcpip.sys    - EQoS HKE binding\nEQHp - tcpip.sys    - EQoS HKE parameters\nEQOw - tcpip.sys    - EQoS policy owner\nEQPn - tcpip.sys    - EQoS policy net entry\nEQPp - tcpip.sys    - EQoS policy profile entry\nEQPs - tcpip.sys    - EQoS policy scratch data\nEQPt - tcpip.sys    - EQoS policy table\nEQQu - tcpip.sys    - EQoS flow unit\nEQSc - tcpip.sys    - EQoS pacer client\nEQSe - tcpip.sys    - EQoS QIM endpoint\nEQSp - tcpip.sys    - EQoS generic policy data\nEQSt - tcpip.sys    - EQoS policy trim scratch\nEQSx - tcpip.sys    - EQoS security object\nEQSy - tcpip.sys    - EQoS proxy data\nEQUn - tcpip.sys    - EQoS uQoS NPI client data\nEQUr - tcpip.sys    - EQoS URL string\nEQUp - tcpip.sys    - EQoS URL policy section\nEQUQ - tcpip.sys    - UQoS generic allocation\n\nErr  - <unknown>    - Error strings\n\nEtwa - nt!etw       - Etw server silo state\nEtwA - nt!etw       - Etw APC\nEtwb - nt!etw       - Etw provider tracking\nEtwB - nt!etw       - Etw Buffer\nEtwc - nt!etw       - Etw rundown reference counters\nEtwC - nt!etw       - Etw Realtime Consumer\nEtwd - nt!etw       - Etw Disallow List Entry\nEtwD - nt!etw       - Etw DataBlock\nEtwF - nt!etw       - Etw Filter\nEtwG - nt!etw       - Etw Guid\nEtwH - nt!etw       - Etw Private Handle Demuxing\nEtwi - nt!etw       - Etw IPT support\nEtwK - nt!etw       - Etw SoftRestart support\nEtwl - nt!etw       - Etw stack look-aside list entry\nEtwL - nt!etw       - Etw LoggerContext\nEtwm - nt!etw       - Etw BitMap\nEtwo - nt!etw       - Etw memory partition reference\nEtwO - nt!etw       - Etw memory partition MDL\nEtwp - nt!etw       - Etw TracingBlock\nEtwP - nt!etw       - Etw Pool\nEtwq - nt!etw       - Etw ReplyQueue\nEtwr - nt!etw       - Etw ReplyQueue entry\nEtwR - nt!etw       - Etw KM RegEntry\nEtws - nt!etw       - Etw stack cache\nEtwS - nt!etw       - Etw DataSource\nEtwt - nt!etw       - Etw temporary buffer\nEtwT - nt!etw       - Etw provider traits\nEtwU - nt!etw       - Etw Periodic Capture State\nEtwV - nt!etw       - Etw Coverage Sampling\nEtwW - nt!etw       - Etw WorkItem\nEtwx - nt!etw       - Etw LBR support\nEtwX - nt!etw       - Etw profiling support\nEtwZ - nt!etw       - Etw compression support\n\nEvel - <unknown>    - EFS file system filter driver lookaside list\nEven - <unknown>    - Event objects\nEvid - <unknown>    - Rtl Event ID's\nExWl - <unknown>    - Executive worker list entry\n\nFat  - fastfat.sys  - Fat File System allocations\nFatB - fastfat.sys  - Fat allocation bitmaps\nFatC - fastfat.sys  - Fat Ccbs\nFatD - fastfat.sys  - Fat pool dirents\nFatE - fastfat.sys  - Fat EResources\nFatF - fastfat.sys  - Fat Fcbs\nFatI - fastfat.sys  - Fat IrpContexts\nFatL - fastfat.sys  - Fat FAT entry lookup buffer on verify\nFatN - fastfat.sys  - Fat Nonpaged Fcbs\nFatO - fastfat.sys  - Fat I/O buffer\nFatP - fastfat.sys  - Fat output for query retrieval pointers (caller frees)\nFatQ - fastfat.sys  - Fat buffered user buffer\nFatR - fastfat.sys  - Fat repinned Bcb\nFatS - fastfat.sys  - Fat stashed Bpb\nFatT - fastfat.sys  - Fat directory allocation bitmaps\nFatV - fastfat.sys  - Fat Vcb stat bucket\nFatv - fastfat.sys  - Fat events\nFatW - fastfat.sys  - Fat FAT windowing structure\nFatX - fastfat.sys  - Fat IO contexts\nFatb - fastfat.sys  - Fat Bcb arrays\nFatd - fastfat.sys  - Fat EA data\nFate - fastfat.sys  - Fat EA set headers\nFatf - fastfat.sys  - Fat deferred flush contexts\nFati - fastfat.sys  - Fat IO run descriptor\nFatn - fastfat.sys  - Fat filename buffer\nFatr - fastfat.sys  - Fat verification-time rootdir snapshot\nFats - fastfat.sys  - Fat verification-time boot sector\nFatv - fastfat.sys  - Fat backpocket Vpb\nFatx - fastfat.sys  - Fat delayed close contexts\nFbCx - tcpip.sys    - Inet feature fallback contexts\n\nREM FsLib allocations. FsLib is a static library linked in both NTFS and ReFS\nFDEl - FsLib        - FsLib DAX Extent Array\nFDEd - FsLib        - FsLib DAX Extent Descriptor\nFDDb - FsLib        - FsLib DAX DSM Buffer\nFsIT - FsLib        - FsLib IO Trace\nFsLd - FsLib        - FsLib Livedump\n\nfboX - <unknown>    - EXIFS FOBXVF List\nFcbl - <unknown>    - EXIFS FCBlock\n\nFcon - nt!RtlpFc    - Feature Configuration Management\n\nFeiv - netio.sys    - WFP filter engine incoming values\nFecc - netio.sys    - WFP filter engine classify context\nFecf - netio.sys    - WFP filter engine callout context\n\nFile - <unknown>    - File objects\nFIcn - fileinfo.sys - FileInfo FS-filter Create Retry Path\nFIcp - fileinfo.sys - FileInfo FS-filter Extra Create Parameter\nFIcs - fileinfo.sys - FileInfo FS-filter Stream Context\nFIcv - fileinfo.sys - FileInfo FS-filter Volume Context\nFIOc - fileinfo.sys - FileInfo FS-filter Prefetch Open Context\nFIou - fileinfo.sys - FileInfo FS-filter User Open Context\nFIof - fileinfo.sys - FileInfo FS-filter File Object Context\nFIPc - fileinfo.sys - FileInfo FS-filter Prefetch Context\nFIvn - fileinfo.sys - FileInfo FS-filter Volume Name\nFIvp - fileinfo.sys - FileInfo FS-filter Volume Properties\n\nFlmC - tcpip.sys    - Framing Layer Client Contexts\nFlmP - tcpip.sys    - Framing Layer Provider Contexts\nFlng - tcpip.sys    - Framing Layer Generic Buffers (Tunnel/Port change notifications, ACLs)\nFlpC - tcpip.sys    - Framing Layer Client Contexts\nFlpI - tcpip.sys    - Framing Layer Interfaces\nFlpL - tcpip.sys    - Framing Layer Client Interface Contexts\nFlpM - tcpip.sys    - Framing Layer Multicast Groups\nFlpS - tcpip.sys    - Framing Layer Serialized Requests\nFl6D - tcpip.sys    - FL6t DataLink Addresses\nFl4D - tcpip.sys    - FL4t DataLink Addresses\nFltD - tcpip.sys    - FLt DataLink Addresses\nFlSB - tcpip.sys    - Framing Layer Stack Block\n\nFlop - <unknown>    - floppy driver\n\nFLSk - nt!ps        - Kernel TLS metadata\n\nFlst - <unknown>    - EXIFS Freelist\n\nFltt - nt!Vf        - Log of Driver Verifier fault injection stack traces.\n\nFLex - <unknown>    - exclusive file lock\nFLfl - <unknown>    - exported (non-private) file lock\nFLli - <unknown>    - per-file lock information\nFLln - <unknown>    - shared lock tree node\nFLsh - <unknown>    - shared file lock\nFLwl - <unknown>    - waiting lock\n\nFM?? - fltmgr.sys   - Unrecognized FltMgr tag (update pooltag.w)\nFMac - fltmgr.sys   -       ASCII String buffers\nFMas - fltmgr.sys   -       ASYNC_IO_COMPLETION_CONTEXT structure\nFMcb - fltmgr.sys   -       FLT_CCB structure\nFMcn - fltmgr.sys   -       Non paged context extension structures\nFMcp - fltmgr.sys   -       Client port wrapper structure\nFMcr - fltmgr.sys   -       Context registration structures\nFMct - fltmgr.sys   -       TRACK_COMPLETION_NODES structure\nFMdh - fltmgr.sys   -       Paged ECP context for targeted create reparse\nFMdl - fltmgr.sys   -       Array of DEVICE_OBJECT pointers\nFMea - fltmgr.sys   -       EA buffer for create\nFMfc - fltmgr.sys   -       FLTMGR_FILE_OBJECT_CONTEXT structure\nFMfi - fltmgr.sys   -       Fast IO dispatch table\nFMfk - fltmgr.sys   -       Byte Range Lock structure\nFMfl - fltmgr.sys   -       FLT_FILTER structure\nFMfn - fltmgr.sys   -       NAME_CACHE_NODE structure\nFMfr - fltmgr.sys   -       FLT_FRAME structure\nFMfz - fltmgr.sys   -       FILE_LIST_CTRL structure\nFMib - fltmgr.sys   -       Irp SYSTEM buffers\nFMic - fltmgr.sys   -       IRP_CTRL structure\nFMil - fltmgr.sys   -       IRP_CTRL completion node stack\nFMin - fltmgr.sys   -       FLT_INSTANCE name\nFMis - fltmgr.sys   -       FLT_INSTANCE structure\nFMla - fltmgr.sys   -       Per-processor IRPCTRL lookaside lists\nFMlp - fltmgr.sys   -       Paged stream list control entry structures\nFMnc - fltmgr.sys   -       NAME_CACHE_CREATE_CTRL structure\nFMng - fltmgr.sys   -       NAME_GENERATION_CONTEXT structure\nFMol - fltmgr.sys   -       OPLOCK_CONTEXT structure\nFMor - fltmgr.sys   -       OpenReparse ECP structure\nFMos - fltmgr.sys   -       Operation status ctrl structure\nFMpl - fltmgr.sys   -       Cache aware pushLock\nFMpr - fltmgr.sys   -       FLT_PRCB structure\nFMQc - fltmgr.sys   -       QueryOnCreate ECP structure\nFMrl - fltmgr.sys   -       FLT_OBJECT rundown logs\nFMrp - fltmgr.sys   -       Reparse point data buffer\nFMrr - fltmgr.sys   -       Per-processor Cache-aware rundown ref structure\nFMrs - fltmgr.sys   -       Registry string\nFMrw - fltmgr.sys   -       FLT_REGISTRY_WATCH_CONTEXT structure\nFMsc - fltmgr.sys   -       SECTION_CONTEXT structure\nFMsd - fltmgr.sys   -       Security descriptors\nFMsl - fltmgr.sys   -       STREAM_LIST_CTRL structure\nFMtb - fltmgr.sys   -       TXN_PARAMETER_BLOCK structure\nFMtn - fltmgr.sys   -       Temporary file names\nFMtp - fltmgr.sys   -       Non Paged TxVol context structures\nFMtr - fltmgr.sys   -       Temporary Registry information\nFMts - fltmgr.sys   -       Tree Stack\nFMus - fltmgr.sys   -       Unicode string\nFMvf - fltmgr.sys   -       FLT_VERIFIER_EXTENSION structure\nFMvj - fltmgr.sys   -       FLT_VERIFIER_OBJECT structure\nFMvl - fltmgr.sys   -       Array of FLT_VERIFIER_OBJECT structures\nFMvo - fltmgr.sys   -       FLT_VOLUME structure\nFMwi - fltmgr.sys   -       Work item structures\n\nFsb -  netio.sys    - Fixed-Size Block pool\n\nFsrc - fsrec.sys    - Filesystem recognizer (fsrec.sys)\n\nFstb - <unknown>    - ntos\\fstub\nFstB - <unknown>    - ntos\\fstub\n\nFsVg - fsvga.sys    - International VGA support\n\nflnk - <unknown>    - font link tag used in ntgdi\\gre\n\nFLpc - netio.sys    - IPv6 Framing Layer Client context\n\nfpct - wof.sys      - Compressed file chunk table\nfpcx - wof.sys      - Compressed file IO context\nfpdw - wof.sys      - Compressed file decompression workspace\nfpgn - wof.sys      - Compressed file general\nfppm - wof.sys      - Compressed file IO parameters\nfprd - wof.sys      - Compressed file small read buffer\nfpRD - wof.sys      - Compressed file large read buffer\nfpwi - wof.sys      - Compressed file work item\nfpxp - wof.sys      - Compressed file xpress context\n\nFS?? - nt!fsrtl     - Unrecoginzed File System Run Time allocations (update pooltag.w)\nFSeh - nt!fsrtl     - File System Run Time Extra Create Parameter Entry\nFSel - nt!fsrtl     - File System Run Time Extra Create Parameter List\nFSfm - nt!fsrtl     - File System Run Time Fast Mutex Lookaside List\nFSim - nt!fsrtl     - File System Run Time Mcb allocations\nFSrt - nt!fsrtl     - File System Run Time allocations (DO NOT USE!)\nFSmg - nt!fsrtl     - File System Run Time\nFSrd - nt!fsrtl     - File System Run Time\nFSrm - nt!fsrtl     - File System Run Time\nFSrn - nt!fsrtl     - File System Run Time\nFSrN - nt!fsrtl     - File System Run Time\nFSro - nt!fsrtl     - File System Run Time\nFSrs - nt!fsrtl     - File System Run Time Work Item for low-stack posting\nFSun - nt!fsrtl     - File System Run Time\nFOCX - nt!fsrtl     - File System Run Time File Object Context structure\n\nFsCo - fse.sys      - FSE_CORE_CONTEXT_OBJECT_POOL_TAG\nFsbi - fse.sys      - FSE_CORE_NBLCHAIN_INDICATION_CONTEXT_POOL_TAG\nFsGo - fse.sys      - FSE_CORE_NDIS_GENERIC_OBJECT_POOL_TAG\nFspe - fse.sys      - FSE_CORE_NIC_PAIR_ENTRY_POOL_TAG\nFsDC - fse.sys      - FSE_DEVICE_CONTEXT_TAG\nFsed - fse.sys      - FSE_DIAGNOSTICS_SCRATCH_TAG\nFseB - fse.sys      - FSE_EXPANDABLE_BUFFER_SIGNATURE\nFsIP - fse.sys      - FSE_IPS_CLIENT_TAG\nFsIf - fse.sys      - FSE_IPS_CLIENT_INTERFACE_TAG\nFsgo - fse.sys      - FSE_NDIS_GENERIC_OBJECT_POOL_TAG\nFsLS - fse.sys      - FSE_NMR_CLIENT_POOLTAG\nFseV - fse.sys      - FSE_PARTITION_SIGNATURE\nFseT - fse.sys      - FSE_PATCH_SIGNATURE\nFseC - fse.sys      - FSE_PORT_CACHE_SIGNATURE\nFsPp - fse.sys      - FSE_PORT_POLICY_TAG\nFseP - fse.sys      - FSE_PORT_POOL_SIGNATURE\nFseR - fse.sys      - FSE_PORT_RESERVATION_SIGNATURE\nFsGl - fse.sys      - FSE_SERVER_TAG_GLOBAL\nFsMt - fse.sys      - FSE_SERVER_TAG_MESSAGE\nFsMl - fse.sys      - FSE_SERVER_TAG_MIDL\nFsPd - fse.sys      - FSE_SERVER_TAG_PARTITION\nFsSt - fse.sys      - FSE_SERVER_TAG_SOCKET\nFsSc - fse.sys      - FSE_SERVER_TAG_SOCKET_CONTEXT\nFsWi - fse.sys      - FSE_SERVER_TAG_WORKITEM\nFseS - fse.sys      - FSE_SHIMS_TAG\nFseW - fse.sys      - FSE_WORKSHEET_POOLTAG\nFsTd - fse.sys      - FSE_PT_TEST_DRIVER_TAG\n\nFTrc - <unknown>    - Fault tolerance Slist tag.\nFtC  - <unknown>    - Fault tolerance driver\nFtM  - <unknown>    - Fault tolerance driver\nFtS  - <unknown>    - Fault tolerance driver\nFtT  - <unknown>    - Fault tolerance driver\nFtU  - <unknown>    - Fault tolerance driver\nFtV  - <unknown>    - Fault tolerance driver\n       <unknown>\n\nFtpA - mpsdrv.sys   - MPSDRV FTP protocol analyzer\nFwfD - mpsdrv.sys   - MPSDRV driver buffer for flattening NET_BUFFFER\n\nFwSD - tcpip.sys    - WFP security descriptor\n\nFVE? - fvevol.sys   - Full Volume Encryption Filter Driver (Bitlocker Drive Encryption)\nFVE0 - fvevol.sys   - General allocations\nFVEc - fvevol.sys   - Cryptographic allocations\nFVEl - fvevol.sys   - FVELIB allocations\nFVEp - fvevol.sys   - Write buffers\nFVEr - fvevol.sys   - Reserved mapping addresses\nFVEv - fvevol.sys   - Conversion allocations\nFVEw - fvevol.sys   - Worker threads\nFVEx - fvevol.sys   - Read/write control structures\n\nFxDr - wdf01000.sys - KMDF driver globals/generic pool allocation tag. Fallback tag in case driver tag is unusable.\nFxLg - wdf01000.sys - KMDF IFR log tag\nFxL? - wdfldr.sys   - KMDF Loader Pool allocation\n\nFwpp - fwpkclnt.sys - Windows Filtering Platform export driver.\nFwpn - fwpkclnt.sys - WFP NBL info\nFwpi - fwpkclnt.sys - WFP injector info\nFwpx - fwpkclnt.sys - WFP NBL tagged context\nFwpd - fwpkclnt.sys - WFP delayed injection context\nFwpc - fwpkclnt.sys - WFP injection call context\n\nG??? - <unknown>    - Gdi Objects\nG    - <unknown>    -     Gdi Generic allocations\nGcac - <unknown>    -     Gdi glyph cache\nGcap - <unknown>    -     Gdi capture buffer\nGcsl - <unknown>    -     Gdi string resource script names\nGdbr - <unknown>    -     Gdi driver brush realization\nGdd  - <unknown>    -     Gdi ddraw PKEY_VALUE_FULL_INFORMATION\nGdda - <unknown>    -     Gdi ddraw attach list\nGddD - <unknown>    -     Gdi ddraw dummy page\nGdde - <unknown>    -     Gdi ddraw event\nGddf - <unknown>    -     Gdi ddraw driver heaps\nGddp - <unknown>    -     Gdi ddraw driver caps\nGddv - <unknown>    -     Gdi ddraw driver video memory list\nGdxd - <unknown>    -     Gdi ddraw VPE directdraw object\nGdxs - <unknown>    -     Gdi ddraw VPE surface, videoport, capture object\nGdxx - <unknown>    -     Gdi ddraw VPE DXAPI object\nGdev - <unknown>    -     Gdi GDITAG_DEVMODE\nGDev - <unknown>    -     Gdi pdev\nGdrs - <unknown>    -     Gdi GDITAG_DRVSUP\nGebr - <unknown>    -     Gdi ENGBRUSH\ngEdg - <unknown>    -     Gdi gradient fill triangle\nGffv - <unknown>    -     Gdi FONTFILEVIEW\ngFil - <unknown>    -     Gdi FILEVIEW\nGFil - <unknown>    -     Gdi engine descriptor list\nGfsb - <unknown>    -     Gdi font sustitution list\nGfsm - <unknown>    -     Gdi Fast mutex\nGgdv - <unknown>    -     Gdi GDITAG_GDEVICE\nGglb - <unknown>    -     Gdi temp buffer\nGgls - <unknown>    -     Gdi glyphset\nGgb  - <unknown>    -     Gdi glyph bits\nGgbl - <unknown>    -     Gdi look aside buffers\nGhmg - <unknown>    -     Gdi handle manager objects\nGini - <unknown>    -     Gdi fast mutex\nGldv - <unknown>    -     Gdi Ldev\nGlnk - <unknown>    -     Gdi PFELINK\nGmap - <unknown>    -     Gdi font map signature table\nGpff - <unknown>    -     Gdi physical font file\nGpft - <unknown>    -     Gdi font table\nGsem - <unknown>    -     Gdi Semaphores\nGsp  - <unknown>    -     Gdi sprite\nGspr - <unknown>    -     Gdi sprite grow range\nGtmp - <unknown>    -     Gdi temporary allocations\nGtmw - <unknown>    -     Gdi TMW_INTERNAL\nGxlt - <unknown>    -     Gdi Xlate\n\nGfcb - <unknown>    - EXIFS Grow FCB\n\n\nHal  - hal.dll      - Hardware Abstraction Layer\nHal2 - hal.dll      - Hardware Abstraction Layer: Secondary Interrupts\nHalA - hal.dll      - Hardware Abstraction Layer: ACPI\nHala - hal.dll      - Hardware Abstraction Layer: HSA\nHalB - hal.dll      - Hardware Abstraction Layer: MM Buffer\nHalb - hal.dll      - Hardware Abstraction Layer: MM Metadata\nHalC - hal.dll      - Hardware Abstraction Layer: Dynamic Partitioning\nHalc - hal.dll      - Hardware Abstraction Layer: Processors\nHalD - hal.dll      - Hardware Abstraction Layer: DMA\nHald - hal.dll      - Hardware Abstraction Layer: Kernel Debug\nHalE - hal.dll      - Hardware Abstraction Layer: Errata Management\nHalF - hal.dll      - Hardware Abstraction Layer: Firmware\nHalH - hal.dll      - Hardware Abstraction Layer: Hypervisor\nHalI - hal.dll      - Hardware Abstraction Layer: IOMMU\nHali - hal.dll      - Hardware Abstraction Layer: Interrupts\nHalK - hal.dll      - Hardware Abstraction Layer: KINTERUPT objects\nHalM - hal.dll      - Hardware Abstraction Layer: Memory Management\nHalm - hal.dll      - Hardware Abstraction Layer: Misc\nHalP - hal.dll      - Hardware Abstraction Layer: PCI\nHalp - hal.dll      - Hardware Abstraction Layer: PNP\nHalo - hal.dll      - Hardware Abstraction Layer: Power\nHalV - ntoskrnl.exe - Driver Verifier DMA checking\nHalW - hal.dll      - Hardware Abstraction Layer: WHEA\n\nHpfs - <unknown>    - Pinball (aka Hpfs) allocations\nHisC - <unknown>    - histogram filter driver\nHist - <unknown>    - histogram filter driver\nHidP - hidparse.sys - HID Parser\nHidC - hidclass.sys - HID Class driver\nHdCl - <unknown>    - HID Client Sample Driver\nHpMM - pnpmem.sys   - HotPlug Memory Driver\n\nHCID - bthport.sys  - Bluetooth port driver HCI debug\nHCIT - bthport.sys  - Bluetooth port driver (HCI)\n\nHcRs - hcaport.sys - HCAPORT_TAG_RESOURCE_LIST\nHcEv - hcaport.sys - HCAPORT_TAG_EVENT\nHcdI - hcaport.sys - HCAPORT_TAG_HWID\nHcEn - hcaport.sys - HCAPORT_TAG_ENUM\nHcMc - hcaport.sys - HCAPORT_TAG_MISC\nHcDr - hcaport.sys - HCAPORT_TAG_DEVICE_RELATIONS\nHcBm - hcaport.sys - HCAPORT_TAG_BITMAP\nHcOb - hcaport.sys - HCAPORT_TAG_OBJECT\nHcCq - hcaport.sys - HCAPORT_TAG_CQUEUE\nHcPr - hcaport.sys - HCAPORT_TAG_PROTD\nHPmi - hcaport.sys - HCAPORT_TAG_PMI_EXTENSION\nHcMa - hcaport.sys - HCAPORT_TAG_MAD\nHcMp - hcaport.sys - HCAPORT_TAG_MINIPORT\nHcCm - hcaport.sys - HCAPORT_TAG_CM\nHcUc - hcaport.sys - HCAPORT_TAG_UCONTEXT\nHcMr - hcaport.sys - HCAPORT_TAG_REMOVE_LOCK\nHmgo - hcaport.sys - HCAPORT_TAG_WQ_MG_INFO\nHioc - hcaport.sys - HCAPORT_TAG_IOC_SERVICE_TABLE\n\nhSVD - mrxdav.sys - Shared Heap Tag\n\nHTab - <unknown>    - Hash Table pool\n\nHT01 - <unknown>    - GDI Halftone AddCachedDCI() for CurCDCIData\nHT02 - <unknown>    - GDI Halftone GetCachedDCI() for Threshold\nHT03 - <unknown>    - GDI Halftone FindCachedSMP() for CurCSMPData\nHT04 - <unknown>    - GDI Halftone FindCachedSMP() for CurCSMPBmp\nHT05 - <unknown>    - GDI Halftone HT_CreateDeviceHalftoneInfo() for HT_DHI\nHT06 - <unknown>    - GDI Halftone pDCIAdjClr() for DEVCLRADJ\nHT07 - <unknown>    - GDI Halftone ComputeRGB555LUT() for RGBLUT\nHT08 - <unknown>    - GDI Halftone ColorTriadSrcToDev() for RGB-XYZ\nHT09 - <unknown>    - GDI Halftone ColorTriadSrcToDev() for CRTX-FD6XYZ Cache\nHT10 - <unknown>    - GDI Halftone CreateDyesColorMappingTable() for DevPrims\nHT11 - <unknown>    - GDI Halftone CreateDyesColorMappingTable() for DyeMappingTable\nHT12 - <unknown>    - GDI Halftone ThresholdsFromYData() for pYData\nHT13 - <unknown>    - GDI Halftone ComputeHTCellRegress() for pThresholds\nHT14 - <unknown>    - GDI Halftone CalculateStretch() for InputSI/pSrcMaskLine\nHT15 - <unknown>    - GDI Halftone CalculateStretch() for PrimColorInfo\n\nHvlm - nt!Hvl       - Temporary MDL for the Hvl component.\nHvlP - nt!Hvl       - Hypercall marshalling pages for the Hvl component.\n\nIBCM - wibcm.sys - CM_INSTANCE_TAG Windows Infiniband Communications Manager\nCEP  - wibcm.sys - CEP_INSTANCE_TAG\nCMSH - wibcm.sys - WIBCM_SHARED_TAG\nCMWK - wibcm.sys - WIBCM_WORK_TAG\nCMWT - wibcm.sys - WIBCM_TIMER_TAG\n\nIBm* - wibms.sys - Windows Infiniband Management Server pool tags\n\nIbPm - wibpm.sys - WIBPM_TAG Windows Infiniband Performance Manager\nIbPS - wibpm.sys - WIBPM_SENT_TAG\nIbPI - wibpm.sys - WIBPM_ITEM_TAG\nIbPA - wibpm.sys - WIBPM_SAMPLE_TAG\n\nIbW0 - wibwmi.sys - WIBWMI0_TAG Windows Infiniband WMI Manager\nIbW1 - wibwmi.sys - WIBWMI1_TAG\nIbW2 - wibwmi.sys - WIBWMI2_TAG\n\nIc4c - tcpip.sys    - ICMP IPv4 Control data\nIc4h - tcpip.sys    - ICMP IPv4 Headers\nIc6c - tcpip.sys    - ICMP IPv6 Control data\nIc6h - tcpip.sys    - ICMP IPv6 Headers\nIBbf - tcpip.sys    - IP BVT Buffers\nIlom - tcpip.sys    - IPsec LBFO offload map\nIlog - tcpip.sys    - IPsec LBFO offload general\nInAD - tcpip.sys    - Inet Ancillary Data\nInCo - tcpip.sys    - Inet Compartment\nInCS - tcpip.sys    - Inet Compartment Set\nIneI - tcpip.sys    - Inet Inspects\nInF0 - tcpip.sys    - Inet Generic Fixed Size Block pool 0\nInF1 - tcpip.sys    - Inet Generic Fixed Size Block pool 1\nInF2 - tcpip.sys    - Inet Generic Fixed Size Block pool 2\nInIS - tcpip.sys    - Inet Inspect Streams\nInNA - <unknown>    - Inet Na Clients\nInNP - tcpip.sys    - Inet Nsi Providers\nInPA - tcpip.sys    - Inet Port Assignment Arrays\nInPa - tcpip.sys    - Inet Port Assignments\nInPE - tcpip.sys    - Inet Port Exclusions\nInPP - tcpip.sys    - Inet Port pool\nInSB - tcpip.sys    - Inet stack block\nInSC - tcpip.sys    - Inet Queued Send Contexts\nInWP - tcpip.sys    - Inet Wake Port Record\nIpas - tcpip.sys    - IP Buffers for Address Sort\nIpcr - tcpip.sys    - IP Cache-aware Reference Counters\nIPba - tcpip.sys    - IP Batching\nIPbw - tcpip.sys    - IP Path Bandwidth information\nIPdc - tcpip.sys    - IP Destination Cache\nIPfg - tcpip.sys    - IP Fragment Groups\nIPfp - tcpip.sys    - IP PreValidated Receives\nIPif - tcpip.sys    - IP Interfaces\nIPlc - tcpip.sys    - IP Locality\nIPle - tcpip.sys    - IP Loopback execution context\nIPlo - tcpip.sys    - IP Loopback buffers\nIPlw - tcpip.sys    - IP Loopback worker\nIPmf - tcpip.sys    - IP Multicast Forwarding Entry pool\nIPpo - tcpip.sys    - IP Offload buffers\nIPpa - tcpip.sys    - IP Path information\nIPro - tcpip.sys    - IP Router Context\nIPrq - tcpip.sys    - IP Request Control data\nIPss - tcpip.sys    - IP Session State\nIPsi - tcpip.sys    - IP SubInterfaces\nIpng - tcpip.sys    - IP Generic buffers (Address, Interface, Packetize, Route allocations)\nIpOl - tcpip.sys    - IP Offload Log data\nIppp - tcpip.sys    - IP Prefix Policy information\nIPre - tcpip.sys    - IP Reassembly buffers\nIptt - tcpip.sys    - IP Timer Tables\nIptc - tcpip.sys    - IP Transaction Context information\nIpur - tcpip.sys    - IP Unicast Routes\nIpwi - tcpip.sys    - IP Work Item allocations\nI4ai - tcpip.sys    - IPv4 Local Address Identifiers\nI4ba - tcpip.sys    - IPv4 Local Broadcast Addresses\nI4bf - tcpip.sys    - IPv4 Generic Buffers (Source Address List allocations)\nI4e -  tcpip.sys    - IPv4 Echo data\nI4ma - tcpip.sys    - IPv4 Local Multicast Addresses\nI4nb - tcpip.sys    - IPv4 Neighbors\nI4rd - tcpip.sys    - IPv4 Receive Datagrams Arguments\nI4ua - tcpip.sys    - IPv4 Local Unicast Addresses\nI6ai - tcpip.sys    - IPv6 Local Address Identifiers\nI6aa - tcpip.sys    - IPv6 Local Anycast Addresses\nI6bf - tcpip.sys    - IPv6 Generic Buffers (Source Address List allocations)\nI6e -  tcpip.sys    - IPv6 Echo data\nI6ma - tcpip.sys    - IPv6 Local Multicast Addresses\nI6nb - tcpip.sys    - IPv6 Neighbors\nI6rd - tcpip.sys    - IPv6 Receive Datagrams Arguments\nI6ua - tcpip.sys    - IPv6 Local Unicast Addresses\n\nIPX  - <unknown>    - Nwlnkipx transport\nIcp  - <unknown>    - I/O completion packets queue on a completion ports\nIcpP - <unknown>    - NPAGED_LOOKASIDE_LIST I/O completion per processor lookaside pointers\nIdeP - <unknown>    - atapi IDE\nIdeX - <unknown>    - PCI IDE\nidle - <unknown>    - Power Manager idle handler\nIfs  - <unknown>    - Default file system allocations (user's of ntifs.h)\nInfo - <unknown>    - general system information allocations\nIo   - nt!io        - general IO allocations\nIoAc - nt!io        - Io ACLs\nIoBo - nt!io        - Io boot disk information\nIoCc - nt!io        - Io completion context\nIoCo - nt!io        - Io completion\nIoCp - nt!io        - Io copy operation\nIoDn - nt!io        - Io device name info\nIoEa - nt!io        - Io extended attributes\nIoEr - nt!io        - Io error log packets\nIoEv - nt!io        - Io KEVENT\nIoFc - nt!io        - Io name transmogrify operation\nIoFs - nt!io        - Io shutdown packet\nIoFu - nt!pnp       - Io file utils\nIoin - <unknown>    - Io interrupts\nIoKa - nt!io        - Io keepalive\nIoKB - nt!io        - Registry basic key block (temp allocation)\nIoKe - nt!io        - Io registry key\nIoLe - nt!io        - Io length\nIoN1 - nt!io        - Io name strings 1\nIoN2 - nt!io        - Io name strings 2\nIoN3 - nt!io        - Io name strings 3\nIoN4 - nt!io        - Io name strings 4\nIoNm - nt!io        - Io parsing names\nIoOp - nt!io        - I/O subsystem open packet\nIoRb - nt!io        - Io remote boot related\nIoRe - nt!io        - Io reparse\nIoRi - nt!io        - I/O SubSystem Driver Reinitialization Callback Packet\nIoRN - nt!io        - Registry key name (temp allocation)\nIoSA - nt!io        - Io segment array\nIoSB - nt!io        - Io system buffer\nIoSD - nt!io        - Io system device buffer\nIoSe - nt!io        - Io security related\nIoSh - nt!io        - Io shutdown packet\nIoSi - nt!io        - Io Symbolic Links\nIoSn - nt!io        - Io Session Notifications\nIoSs - nt!io        - Io SIDs\nIoSt - nt!io        - Io Stream Identifier Context\nIoSy - nt!io        - Io system environment variables\nIoTi - nt!io        - Io timers\nIoTt - nt!vf        - I/O verifier IRP tracking table\nIoUs - nt!io        - I/O SubSystem completion Context Allocation\nIoWI - nt!io        - Io work items\nIrp  - <unknown>    - Io, IRP packets\nIrp+ - nt!vf        - I/O verifier allocated IRP packets\nIrpB - nt!vf        - I/O verifier direct I/O double buffer allocation\nIrpd - nt!vf        - I/O verifier deferred completion context\nIrps - nt!vf        - I/O verifier per-IRP session tracking data\nIrpt - nt!vf        - I/O verifier per-IRP tracking data\nIrpC - nt!vf        - I/O verifier stack contexts\nIrpl - nt!io        - system large IRP lookaside list\nIrps - nt!io        - system small IRP lookaside list\nIrpX - nt!io        - IRP Extension\nIsap - <unknown>    - Pnp Isa bus extender\nII?? - <unknown>    - IP in IP tunneling\nIIrf - <unknown>    - Free memory\nIIdt - <unknown>    - Data\nIITn - <unknown>    - Tunnel\nIIhd - <unknown>    - Header\nIIpk - <unknown>    - Packet\nIIsc - <unknown>    - Send Context\nIIts - <unknown>    - Transfer Context\nIIwc - <unknown>    - Work Context\n\nIm*  - <unknown>    - Imapi.sys from adaptec\n\nINTC - <unknown>    - Intel video driver\n\nIPm? - <unknown>    - IP Multicasting\nIPmg - <unknown>    - Group\nIPms - <unknown>    - Source\nIPmo - <unknown>    - Outgoing Interface\nIPmm - <unknown>    - Message\nIPmf - <unknown>    - Free memory (only in checked builds)\n\nIp?? - ipsec.sys    - IP Security (IPsec)\nIpSI - ipsec.sys    -  initial allocations\nIpAT - ipsec.sys    -  AH headers in transport mode\nIpAU - ipsec.sys    -  AH headers in tunnel mode\nIpET - ipsec.sys    -  ESP headers in transport mode\nIpEU - ipsec.sys    -  ESP headers in tunnel mode\nIpHT - ipsec.sys    -  HUGHES headers in transport mode\nIpHU - ipsec.sys    -  HUGHES headers in tunnel mode\nIpAX - ipsec.sys    -  key acquire contexts\nIpFI - ipsec.sys    -  filter blocks\nIpSA - ipsec.sys    -  security associations (SA)\nIpKE - ipsec.sys    -  keys\nIpTI - ipsec.sys    -  timers\nIpSQ - ipsec.sys    -  stall queues\nIpLA - ipsec.sys    -  lookaside lists\nIpBP - ipsec.sys    -  buffer pools\nIpSC - ipsec.sys    -  send complete context\nIpEQ - ipsec.sys    -  event queue\nIpHW - ipsec.sys    -  hardware accleration items\nIpCO - ipsec.sys    -  IP compression\n\nItoM - tcpip.sys    - IPsec task offload interface\nItoD - tcpip.sys    - IPsec task offload delete SA\nItoS - tcpip.sys    - IPsec task offload add SA\nItoC - tcpip.sys    - IPsec task offload context\nItoO - tcpip.sys    - IPsec task offload paramters\n\nItht - tcpip.sys    - IPsec hashtable\nISLe - tcpip.sys    - IPsec SA list entry\nIsRc - tcpip.sys    - IPsec rebalance context\nIkmb - tcpip.sys    - IPsec key module blob\nIthp - tcpip.sys    - IPsec throttle parameter\nIpfl - tcpip.sys    - IPsec flow handle\nIpap - tcpip.sys    - IPsec pend context\nInlc - tcpip.sys    - IPsec NL complete context\nIprc - tcpip.sys    - IPsec RPC context\nIpis - tcpip.sys    - IPsec inbound sequence info\nItok - tcpip.sys    - IPsec token\nIser - tcpip.sys    - IPsec inbound sequence range\nIKeO - tcpip.sys    - IPsec key object\nI4sa - tcpip.sys    - IPsec SADB v4\nI4s6 - tcpip.sys    - IPsec SADB v6\nIHaO - tcpip.sys    - IPsec hash object\nIpnc - tcpip.sys    - IPsec negotiation context\nIcse - tcpip.sys    - IPsec NS connection state\nItro - tcpip.sys    - IPsec outbound session security context\nItri - tcpip.sys    - IPsec inbound packet security context\nItuo - tcpip.sys    - IPsec outbound tunnel session security context\nItui - tcpip.sys    - IPsec inbound packet tunnel security context\nIpft - tcpip.sys    - IPsec filter\nIpwi - tcpip.sys    - IPsec work item\n\nIdqf - tcpip.sys    - IPsec DoS Protection QoS flow\nIdpc - tcpip.sys    - IPsec DoS Protection pacer create\nIdst - tcpip.sys    - IPsec DoS Protection state entry\nIfws - tcpip.sys    - IPsec forward state\n\nImPl - ndisimplatform.sys - NDIS IM (LBFO) Platform\n\nIpFl - mpsdrv.sys   - MPSDRV IP Flow\n\nIrD? - <unknown>    - IrDA TDI and RAS drivers\n\nIU?? - <unknown>    - IIS Utility Driver\nIUDl - <unknown>    -     Lookaside list allocations\nIUcp - <unknown>    -     completion port minipackets\n\nKAPC - nt!io              - I/O SubSystem HardError APC\nKbdC - kbdclass.sys - Keyboard Class Driver\nKbdH - kbdhid.sys   - Keyboard HID mapper Driver\nKCfe - <unknown>    - Kernel COM factory entry\nKDN_ - kdnic.sys    - Network Kernel Debug Adapter\nKDNT - kdnic.sys    - Network Kernel Debug Adapter TCB\nKDNR - kdnic.sys    - Network Kernel Debug Adapter RCB\nKDNr - kdnic.sys    - Network Kernel Debug Adapter RECV-NBL\nKDNF - kdnic.sys    - Network Kernel Debug Adapter FRAME\nKe   - <unknown>    - Kernel data structures\nKeIC - <unknown>    - Kernel Interrupt Object Chain\nKey  - <unknown>    - Key objects\nKMIX - <unknown>    - Kmixer (wdm audio)\nKNMI - <unknown>    - Kernel NMI Callback object\nKrbC - ksecdd.sys   - Kerberos Client package\nkrpc - nt           - NTOS midl_user_allocate\nKSah - <unknown>    - Ks auxiliary stream headers\nKSAI - <unknown>    -    allocator instance\nKSai - <unknown>    -    default allocator instance header\nKSbi - <unknown>    -    event buffered item\nKSCI - <unknown>    -    clock instance\nKSce - <unknown>    -    create item entry\nKSch - <unknown>    -    create handler entry\nKSci - <unknown>    -    default clock instance header\nKScp - <unknown>    -    object creation parameters auxiliary copy\nKSda - <unknown>    -    default allocator\nKSdc - <unknown>    -    default clock\nKSdh - <unknown>    -    device header\nKse0 - ksecdd.sys   - Security driver allocs for sec package 0\nKse1 - ksecdd.sys   - Security driver allocs for sec package 1\nKse2 - ksecdd.sys   - Security driver allocs for sec package 2\nKse3 - ksecdd.sys   - Security driver allocs for sec package 3\nKse4 - ksecdd.sys   - Security driver allocs for sec package 4\nKse5 - ksecdd.sys   - Security driver allocs for sec package 5\nKse6 - ksecdd.sys   - Security driver allocs for sec package 6\nKse7 - ksecdd.sys   - Security driver allocs for sec package 7\nKse8 - ksecdd.sys   - Security driver allocs for sec package 8\nKse9 - ksecdd.sys   - Security driver allocs for sec package 9\nKsec - ksecdd.sys   - Security device driver\nKSed - <unknown>    -    event dpc item\nKSee - <unknown>    -    event entry\nKSed - <unknown>    -    oneshot event deletion dpc\nKSep - <unknown>    -    irp system buffer event parameter\nKseS - ksecdd.sys   - Security driver allocs for LSA proper\nKSew - <unknown>    -    oneshot event deletion workitem\nKseZ - ksecdd.sys   - Security driver allocs for default sec package\nKSqr - <unknown>    -    QM quality report\nKSer - <unknown>    -    QM error report\nKSfd - <unknown>    -    filter cache data (MSKSSRV)\nKsFI - <unknown>    -    filter instance\nKSns - <unknown>    -    null security object\nKSnv - <unknown>    -    registry name value\nKSoh - <unknown>    -    object header\nKSop - <unknown>    -    object creation parameters\nKSpc - <unknown>    -    port driver instance FsContext\nKSPI - <unknown>    -    pin instance\nKSpp - <unknown>    -    irp system buffer property/method/event parameter\nKSpt - <unknown>    -    pin type list (MSKSSRV)\nKSqf - <unknown>    -    query information file buffer\nKSsc - <unknown>    -    port driver stream FsContext\nKSsf - <unknown>    -    set information file buffer\nKSsh - <unknown>    -    stream headers\nKSsi - <unknown>    -    software bus interface\nKSsl - <unknown>    -    symbolic link buffer (MSKSSRV)\nKSsp - <unknown>    -    serialized property set\nKsoO - <unknown>    -    WDM audio stuff\nL2CA - bthport.sys  - Bluetooth port driver (L2CAP)\nL2T0 - <unknown>    -    ndis\\l2tp / MTAG_FREED\nL2T1 - <unknown>    -    ndis\\l2tp / MTAG_ADAPTERCB\nL2T2 - <unknown>    -    ndis\\l2tp / MTAG_TUNNELCB\nL2T3 - <unknown>    -    ndis\\l2tp / MTAG_VCCB\nL2T4 - <unknown>    -    ndis\\l2tp / MTAG_VCTABLE\nL2T5 - <unknown>    -    ndis\\l2tp / MTAG_WORKITEM\nL2T6 - <unknown>    -    ndis\\l2tp / MTAG_TIMERQ\nL2T7 - <unknown>    -    ndis\\l2tp / MTAG_TIMERQITEM\nL2T8 - <unknown>    -    ndis\\l2tp / MTAG_PACKETPOOL\nL2T9 - <unknown>    -    ndis\\l2tp / MTAG_FBUFPOOL\nL2Ta - <unknown>    -    ndis\\l2tp / MTAG_HBUFPOOL\nL2Tb - <unknown>    -    ndis\\l2tp / MTAG_TDIXRDG\nL2Tc - <unknown>    -    ndis\\l2tp / MTAG_TDIXSDG\nL2Td - <unknown>    -    ndis\\l2tp / MTAG_CTRLRECD\nL2Te - <unknown>    -    ndis\\l2tp / MTAG_CTRLSENT\nL2Tf - <unknown>    -    ndis\\l2tp / MTAG_PAYLRECD\nL2Tg - <unknown>    -    ndis\\l2tp / MTAG_PAYLSENT\nL2Th - <unknown>    -    ndis\\l2tp / MTAG_INCALL\nL2Ti - <unknown>    -    ndis\\l2tp / MTAG_UTIL\nL2Tj - <unknown>    -    ndis\\l2tp / MTAG_ROUTEQUERY\nL2Tk - <unknown>    -    ndis\\l2tp / MTAG_ROUTESET\nL2Tl - <unknown>    -    ndis\\l2tp / MTAG_L2TPPARAMS\nL2Tm - <unknown>    -    ndis\\l2tp / MTAG_TUNNELWORK\nL2Tn - <unknown>    -    ndis\\l2tp / MTAG_TDIXROUTE\nLANE - atmlane.sys  - LAN Emulation Client for ATM\nLB?? - <unknown>    - LM Datagram receiver allocations\nLBan - <unknown>    -     Server announcement\nLBvb - <unknown>    -     View buffer\nLBma - <unknown>    -     Master announce context\nLBxp - <unknown>    -     Transport\nLBxn - <unknown>    -     TransportName\nLBxm - <unknown>    -     Master name\nLBtn - <unknown>    -     Transport name\nLBea - <unknown>    -     Ea buffer\nLBdi - <unknown>    -     POOL_DOMAIN_INFO\nLBds - <unknown>    -     Send datagram context\nLBci - <unknown>    -     Connection info\nLBmh - <unknown>    -     Mailslot header\nLBbl - <unknown>    -     Backup List\nLBsl - <unknown>    -     Browser server list\nLBbs - <unknown>    -     Browser server\nLBgb - <unknown>    -     GetBackupList request\nLBbr - <unknown>    -     GetBackupList response\nLBmb - <unknown>    -     Mailslot Buffer\nLBid - <unknown>    -     Illegal datagram context\nLBbn - <unknown>    -     Name\nLBnn - <unknown>    -     Name name\nLBic - <unknown>    -     IRP context\nLBwi - <unknown>    -     Work item\nLBel - <unknown>    -     Election context\nLBbb - <unknown>    -     Become backup context\nLBbr - <unknown>    -     Become backup request\nLBpn - <unknown>    -     Paged Name\nLBpt - <unknown>    -     Paged transport\nLBse - <unknown>    -     Browser security\n\nLbuf - <unknown>    - EXIFS Large Buffer\n\nLdmp - nt!io        -     Live Dump Buffers. Note, these buffers will not be present in the resulting live dump file.\n\nLeGe - tcpip.sys    - Legacy Registry Mapping Module Buffers\n\nLeoC - <unknown>    -     Symantec/Norton AntiVirus filter driver\nList - <unknown>    -     kernel utilities list allocation\nLCam - <unknown>    - WDM mini video capture driver for Logitech camera\nLfs  - <unknown>    - Lfs allocations\nLfsI - <unknown>    - Lfs allocations\nLLDP - mslldp.sys   - LLDP protocol driver allocations\nLogA - clfsapimp.sys - CLFS Kernel API test driver\nLpcZ - <unknown>    - LPC Zone\nLpcM - <unknown>    - Local procedure call message blocks\nLr?? - <unknown>    - LM redirector allocations\nLr   - <unknown>    -     Generic allocations\nLrcx - <unknown>    -     Context blocks of various types\nLrcl - <unknown>    -     ConnectListEntries\nLrsl - <unknown>    -     ServerListEntries\nLrse - <unknown>    -     Security entry\nLrsc - <unknown>    -     Search Control Blocks\nLrea - <unknown>    -     EA related allocations\nLric - <unknown>    -     Instance Control Blocks\nLrfc - <unknown>    -     File Control Blocks\nLrfl - <unknown>    -     Fcb Locks\nLrfp - <unknown>    -     Fcb Paging locks\nLrcn - <unknown>    -     Computer Name\nLrdn - <unknown>    -     Domain Name\nLr?? - <unknown>    -     Buffers used for FsControlFile APIs\nLrlc - <unknown>    -     Lock Control Blocks\nLrlb - <unknown>    -     Lock Control Block buffers\nLrnf - <unknown>    -     Non paged FCB\nLrnt - <unknown>    -     Non paged transport\nLrps - <unknown>    -     Paged security entry\nLrte - <unknown>    -     Transport event.\nLrxx - <unknown>    -     Transceive context blocks\nLr!! - <unknown>    -     Cancel request context blocks\nLrmt - <unknown>    -     MPX table\nLrme - <unknown>    -     MPX table entries\nLrsx - <unknown>    -     Send contexts\nLraw - <unknown>    -     Async write context\nLrwb - <unknown>    -     Write behind buffer header\nLrbb - <unknown>    -     Write behind buffer\nLrwq - <unknown>    -     Work queue item\nLrac - <unknown>    -     ACL for redirector\nLrds - <unknown>    -     Security Descriptor for redirector\nLrsm - <unknown>    -     SMB buffer\nLrds - <unknown>    -     Duplicated ansi string\nLrdu - <unknown>    -     Duplicated unicode string\nLxpt - <unknown>    -     Transport\nLrtc - <unknown>    -     Transport connection\nLrna - <unknown>    -     Netbios Addresses\nLrca - <unknown>    -     Temporary storage used in name canonicalization\nLr2x - <unknown>    -     Transact SMB context\nLrpt - <unknown>    -     Primary transport server list\nLrso - <unknown>    -     Operating system name\nLref - <unknown>    -     Reference history (debug only)\nLS?? - <unknown>    - LM server allocations\nLSac - srv.sys      -     SMB1 BlockTypeAdminCheck\nLSas - srv.sys      -     SMB1 BlockTypeAdapterStatus\nLSbf - srvnet.sys   -     SMB1 buffer descriptor or srvnet allocation\nLScd - srv.sys      -     SMB1 comm device\nLScn - srv.sys      -     SMB1 connection\nLSdb - srv.sys      -     SMB1 data buffer\nLSdc - srv.sys      -     SMB1 BlockTypeDirCache\nLSdi - srv.sys      -     SMB1 BlockTypeDirectoryInfo\nLSep - srv.sys      -     SMB1 endpoint\nLSfn - srv.sys      -     SMB1 BlockTypeFSName\nLSfR - srv2.sys     -     SMB2 rfssequence table and rfs64table\nLShs - srv2.sys     -     SMB2 lease hash table\nLSlb - srv2.sys     -     SRVLIB security descriptor/registry buffer\nLSlf - srv.sys      -     SMB1 LFCB\nLSlr - srv.sys      -     SMB1 BlockTypeLargeReadX\nLSmf - srv.sys      -     SMB1 MFCB\nLSmi - srv.sys      -     SMB1 BlockTypeMisc\nLSnh - srv.sys      -     SMB1 nonpaged block header\nLSni - srv.sys      -     SMB1 BlockTypeNameInfo\nLSnn - srv2.sys     -     SMB2 netname\nLSop - srv.sys      -     SMB1 oplock break wait\nLSpc - srv.sys      -     SMB1 paged connection\nLSpm - srv.sys      -     SMB1 paged MFCB\nLSpr - srv.sys      -     SMB1 paged RFCB\nLSrf - srv.sys      -     SMB1 RFCB\nLSrp - srvnet.sys   -     srvnet RPC allocation\nLSRp - srv2.sys     -     SRVLIB reparse point\nLSsc - srv.sys      -     SMB1 search(core)\nLSsd - srv.sys      -     SMB1 BlockTypeShareSecurityDescriptor\nLSsf - srv.sys      -     SMB1 BlockTypeDfs\nLSsh - srv.sys      -     SMB1 share\nLSSL - srv2.sys     -     SMBLIB allocation\nLSsp - srv.sys      -     SMB1 search(core complete)\nLSsr - srv.sys      -     SMB1 search\nLSss - srv.sys      -     SMB1 session\nLStb - srv.sys      -     SMB1 table\nLStc - srv.sys      -     SMB1 tree connect\nLSti - srv.sys      -     SMB1 timer\nLStr - srv.sys      -     SMB1 transaction\nLSvi - srv.sys      -     SMB1 BlockTypeVolumeInformation\nLSwi - srv.sys      -     SMB1 initial work context\nLSwn - srv.sys      -     SMB1 normal work context\nLSwq - srv.sys      -     SMB1 BlockTypeWorkQueue\nLSwr - srv.sys      -     SMB1 raw work context\nLSws - srv.sys      -     SMB1 BlockTypeWorkContextSpecial\nLS2b - srv2.sys     -     SMB2 buffer\nLS2c - srv2.sys     -     SMB2 connection\nLS2e - srv2.sys     -     SMB2 endpoint\nLS2f - srv2.sys     -     SMB2 file\nLS2h - srv2.sys     -     SMB2 share\nLS2i - srv2.sys     -     SMB2 client\nLS2l - srv2.sys     -     SMB2 lease\nLS2n - srv2.sys     -     SMB2 channel\nLS2o - srv2.sys     -     SMB2 oplock break\nLS2p - srv2.sys     -     SMB2 provider\nLS2q - srv2.sys     -     SMB2 queue\nLS2s - srv2.sys     -     SMB2 session\nLS2t - srv2.sys     -     SMB2 treeconnect\nLS2W - srv2.sys     -     SMB2 special workitem\nLS2w - srv2.sys     -     SMB2 workitem\nLS2x - srv2.sys     -     SMB2 security context\nLS$S - srv2.sys     -     SMB2 ecp\nLS2$ - srv2.sys     -     SMB2 misc. allocation\nLS00 - srvnet.sys   -     SRVNET LookasideList level 0 allocation 256 Bytes\nLS01 - srvnet.sys   -     SRVNET LookasideList level 1 allocation 512 Bytes\nLS02 - srvnet.sys   -     SRVNET LookasideList level 2 allocation 1K Bytes\nLS03 - srvnet.sys   -     SRVNET LookasideList level 3 allocation 2K Bytes\nLS04 - srvnet.sys   -     SRVNET LookasideList level 4 allocation 4K Bytes\nLS05 - srvnet.sys   -     SRVNET LookasideList level 5 allocation 8K Bytes\nLS06 - srvnet.sys   -     SRVNET LookasideList level 6 allocation 16K Bytes\nLS07 - srvnet.sys   -     SRVNET LookasideList level 7 allocation 32K Bytes\nLS08 - srvnet.sys   -     SRVNET LookasideList level 8 allocation 64K Bytes\nLS09 - srvnet.sys   -     SRVNET LookasideList level 9 allocation 128K Bytes\nLS10 - srvnet.sys   -     SRVNET LookasideList level 10 allocation 192K Bytes\nLS11 - srvnet.sys   -     SRVNET LookasideList level 11 allocation 256K Bytes\nLS12 - srvnet.sys   -     SRVNET LookasideList level 12 allocation 320K Bytes\nLS13 - srvnet.sys   -     SRVNET LookasideList level 13 allocation 384K Bytes\nLS14 - srvnet.sys   -     SRVNET LookasideList level 14 allocation 448K Bytes\nLS15 - srvnet.sys   -     SRVNET LookasideList level 15 allocation 512K Bytes\nLS16 - srvnet.sys   -     SRVNET LookasideList level 16 allocation 576K Bytes\nLS17 - srvnet.sys   -     SRVNET LookasideList level 17 allocation 640K Bytes\nLS18 - srvnet.sys   -     SRVNET LookasideList level 18 allocation 704K Bytes\nLS19 - srvnet.sys   -     SRVNET LookasideList level 19 allocation 768K Bytes\nLS20 - srvnet.sys   -     SRVNET LookasideList level 20 allocation 832K Bytes\nLSnd - <unknown>    - WDM mini sound driver for Logitech video camera\nLuaf - luafv.sys    - LUA File Virtualization\nLXMK - <unknown>    - kernel mixer line driver (KMXL - looks like they got their tag backwards)\n\nMXF  - <unknown>    - DirectMusic (MIDI Transform Filter)\n\nMapP - <unknown>    - PNP map\nMapr - <unknown>    - arc firmware registry routines\n\nMcaC - hal.dll      - HAL MCA corrected Log\nMcaD - hal.dll      - HAL MCA Driver Log\nMcaK - hal.dll      - HAL MCA Kernel Log\nMcaP - hal.dll      - HAL MCA Log from previous boot\nMcaT - hal.dll      - HAL MCA temporary Log\n\nMdp -  netio.sys    - Memory Descriptor Lists\n\nMCAM - <unknown>    - WDM mini driver for Intel USB camera\nMCDx - <unknown>    - OpenGL MCD server (mcdsrv32.dll) allocations\nMCDd - <unknown>    - OpenGL MCD driver (embedded in a display driver like s3mvirge.dll)\nMdl  - <unknown>    - Io, Mdls\nMdlP - <unknown>    - MDL per processor lookaside list pointers\nMem  - nt!po        - NT Power manager, POP_MEM_TAG\nMePr - <unknown>    - In-memory print buffer\n\nMiCf - nt!mm        - Mm compressed Control Flow Guard valid target RVA list\nMiHa - nt!mm        - Mm internal memory ranges\nMiIo - nt!mm        - Mm internal numa node information\nMiPa - nt!mm        - Mm internal partition core\nMipb - nt!mm        - Mm internal bit buffer\nMiNi - nt!mm        - Mm internal node page information\nMipp - nt!mm        - Mm internal page node\nMipr - nt!mm        - Mm internal partition resource information\n\nmkup - mpsdrv.sys   - MPSDRV upcall request\n\nMm   - nt!mm        - general Mm Allocations\nMmAc - nt!mm        - Mm access log buffers\nMmBk - nt!mm        - Mm banked sections\nMmCa - nt!mm        - Mm control areas for mapped files\nMmCd - nt!mm        - Mm fork clone descriptors\nMmCh - nt!mm        - Mm fork clone headers\nMmCi - nt!mm        - Mm control areas for images\nMmCl - nt!mm        - Mm fork clone prototype PTEs\nMmCm - nt!mm        - Calls made to MmAllocateContiguousMemory\nMmCr - nt!mm        - Mm fork clone roots\nMmCt - nt!mm        - Mm debug tracing\nMmDb - nt!mm        - NtMapViewOfSection service\nMmDT - nt!mm        - Mm debug\nMmEx - nt!mm        - Mm events\nMmHi - nt!mm        - Mm image entry - allocated per session\nMmHn - nt!mm        - Mm sessionwide address name string entry\nMmHv - nt!mm        - Mm sessionwide address entry\nMmIn - nt!mm        - Mm inpaged io structures\nMmLd - nt!mm        - Mm load module database\nMmPd - nt!mm        - Mm page table commitment bitmaps\nMmPg - nt!mm        - Mm page table pages at init time\nMmRp - nt!mm        - Mm repurpose logging\nMmRw - nt!mm        - Mm read write virtual memory buffers\nMmSb - nt!mm        - Mm subsections\nMmSe - nt!mm        - Mm secured VAD allocation\nMmSg - nt!mm        - Mm segments\nMmSt - nt!mm        - Mm section object prototype ptes\nMmSy - nt!mm        - Mm PTE and IO tracking logs\nMmdl - nt!mm        - Mm Mdls for flushes\nMmpp - nt!mm        - Mm prototype PTEs for pool\nMmpr - nt!mm        - Mm physical VAD roots\nMmVd - nt!mm        - Mm virtual address descriptors for mapped views\nMmVs - nt!mm        - Mm virtual address descriptors short form (private views)\nMmxx - nt!mm        - Mm temporary allocations\nMmCx - nt!mm        - info for dynamic section extension\nMmDm - nt!mm        - deferred MmUnlock entries\nMmHt - nt!mm        - session space PTE data\nMmLn - nt!mm        - temporary name buffer for driver loads\nMmMl - nt!mm        - physical memory range information\nMmPa - nt!mm        - pagefile space deletion slist entries\nMmRl - nt!mm        - temporary readlists for file prefetch\nMmSP - nt!mm        - SLIST entries for system PTE NB queues\nMmSi - nt!mm        - Control area security image stubs\nMmSc - nt!mm        - subsections used to map data files\nMmSd - nt!mm        - extended subsections used to map data files\nMmSm - nt!mm        - segments used to map data files\nMmWe - nt!mm        - Work entries for writing out modified filesystem pages.\nMmWw - nt!mm        - Write watch VAD info\nMmpv - nt!mm        - Physical view VAD info\nMmww - nt!mm        - Write watch bitmap VAD info\nMmSW - nt!mm        - Store write support\nMmSw - nt!mm        - Store write support when prefetching\nMmCS - nt!mm        - Pagefile CRC verification buffer\nMmCp - nt!mm        - Colored page counts for physical memory allocations\nMmdi - nt!mm        - MDLs for physical memory allocations\nMmDp - nt!mm        - Lost delayed write context\nMmFl - nt!mm        - MDLs for large clusters for flushes\nMmFr - nt!mm        - ASLR fixup records\nMmId - nt!mm        - PFN identity buffer for setting PFN priorities\nMmIh - nt!mm        - Image header allocation for Se validation\nMmIm - nt!mm        - IO space MDL trackers\nMmIo - nt!mm        - IO space mapping trackers\nMmlk - nt!mm        - ProbeAndLock MDL tracker\nMmLl - nt!mm        - Large page memory run allocation for finding large pages\nMmNo - nt!mm        - Inernal physical memory nodes\nMmPh - nt!mm        - Physical memory nodes for querying memory ranges\nMmRe - nt!mm        - ASLR relocation blocks\nMmWs - nt!mm        - PTE flush list for working set operations\nMmWS - nt!mm        - Working set swap support\nMmZw - nt!mm        - Work items for zeroing pages and pagefiles\nMmSa - nt!mm        - Subsection AVL tree allocations\nMmVt - nt!mm        - Verifier thunk allocations\nMmLa - nt!mm        - Memory list locks\nMmTp - nt!mm        - Store eviction thread params\nMmPb - nt!mm        - Paging file bitmaps\n\nMn01 - monitor.sys  - ACPI method evaluation output buffer\nMn02 - monitor.sys  - Unused\nMn03 - monitor.sys  - Raw E-EDID v.1.x byte stream including base block + extension blocks (if any)\nMn04 - monitor.sys  - Cached monitor ID WMI data block\nMn05 - monitor.sys  - Cached monitor basic display parameters WMI data block\nMn06 - monitor.sys  - Cached monitor analog video input parameters WMI data block\nMn07 - monitor.sys  - Cached monitor digitial video input parameters WMI data block\nMn08 - monitor.sys  - Cached monitor color characteristics WMI data block\nMn09 - monitor.sys  - Cached supported monitor source modes WMI data block\nMn0A - monitor.sys  - Registry subkey info buffer\nMn0B - monitor.sys  - Registry value buffer\nMn0C - monitor.sys  - Cached supported monitor frequency ranges WMI data block (overrides from registry)\nMn0D - monitor.sys  - Cached supported monitor frequency ranges WMI data block (from E-EDID v.1.x base block)\nMn0E - monitor.sys  - Buffer for E-EDID v.1.x base block, if any, populated by miniport\nMn0F - monitor.sys  - Buffer for E-EDID v.1.x extension block(s), if any, populated by miniport\n\nMNFf - msnfsflt.sys - NFS FS Filter, filename buffer\nMNFi - msnfsflt.sys - NFS FS Filter, instance name buffer\nMNFr - msnfsflt.sys - NFS FS Filter, registry access buffer\nMNFs - msnfsflt.sys - NFS FS Filter, general string buffer\nMNFv - msnfsflt.sys - NFS FS Filter, volume name buffer\nMNFC - msnfsflt.sys - NFS FS Filter, callback context\nMNFF - msnfsflt.sys - NFS FS Filter, file context\nMNFI - msnfsflt.sys - NFS FS Filter, instance context\nMNFS - msnfsflt.sys - NFS FS Filter, stream context\nMNFT - msnfsflt.sys - NFS FS Filter, thread array\n\nMp10 - nt!mm        - Mm Enumerate address space and reference images\n\nMQAA - mqac.sys     - MSMQ driver, AVL allocations\nMQAB - mqac.sys     - MSMQ driver, CCursor allocations\nMQAC - mqac.sys     - MSMQ driver, generic allocations\nMQAD - mqac.sys     - MSMQ driver, CDistribution allocations\nMQAG - mqac.sys     - MSMQ driver, CGroup allocations\nMQAH - mqac.sys     - MSMQ driver, Heap allocations\nMQAP - mqac.sys     - MSMQ driver, CPacket allocations\nMQAQ - mqac.sys     - MSMQ driver, CQueue allocations\nMQAT - mqac.sys     - MSMQ driver, CTransaction allocations\n\nMRXx - <unknown>    - Client side caching for SMB\n\nMSll - refs.sys     - MinLog allocated pool\n\nREM Minstore (an ReFS component) allocations\nMSag - refs.sys     - Minstore unspecified AVL entries (too big for lookasides; filtered AVL)\nMSah - refs.sys     - Minstore allocator history\nMSal - refs.sys     - Minstore allocator block\nMSab - refs.sys     - Minstore allocator region bitmap\nMsaE - refs.sys     - Minstore AE push lock\nMSav - refs.sys     - Minstore AVL table\nMSb+ - refs.sys     - Minstore B+ table\nMSba - refs.sys     - Minstore blockref cache array\nMSbe - refs.sys     - Minstore blockref cache entry\nMSca - refs.sys     - Minstore read cache object\nMScc - refs.sys     - Minstore tx checksum context\nMScd - refs.sys     - Minstore read cache dirty page array\nMSch - refs.sys     - Minstore read cache hash table\nMSci - refs.sys     - Minstore metadata cache instance\nMScl - refs.sys     - Minstore read cache line\nMScm - refs.sys     - Minstore composite\nMScn - refs.sys     - Minstore container\nMSco - refs.sys     - Minstore compression\nMScp - refs.sys     - Minstore cached pin\nMScr - refs.sys     - Minstore container rotation checksum buffer\nMScs - refs.sys     - Minstore read cache sync set\nMScu - refs.sys     - Minstore cursor\nMScw - refs.sys     - Minstore read cache write range\nMSdd - refs.sys     - Minstore director row data\nMSde - refs.sys     - Minstore dirty table tracking\nMSdg - refs.sys     - Minstore debug\nMSds - refs.sys     - Minstore debug stack logs\nMsdv - <unknown>    - WDM mini driver for IEEE 1394 DV Camera and VCR\nMSeb - refs.sys     - Minstore embedded factory (B+ and associated)\nMSeg - nt!mm        - segments used to support image files\nMSer - refs.sys     - Minstore reserved CRange map lookaside\nMSfa - refs.sys     - Minstore filtered AVL\nMSha - refs.sys     - Minstore hash table (incl. page tables)\nMShl - refs.sys     - Minstore hash table lite\nMSho - refs.sys     - Minstore hash table overflow (incl. page tables)\nMSht - refs.sys     - Minstore stack hash table\nMSii - refs.sys     - Minstore container initial index cache\nMSir - refs.sys     - Mscallbacks MsKmeAllocateIoRequest\nMSiz - refs.sys     - Mscallbacks RESERVED_IO_RUNS and RESERVED_IO_REQUESTS\nMSkb - refs.sys     - Minstore keys buffer\nMSkc - refs.sys     - Minstore KSR context\nMSkr - refs.sys     - Minstore CmsKeyRules object\nMSlm - refs.sys     - Minstore CRange map list lookaside\nMSlr - refs.sys     - Minstore reserved CRange map list lookaside\nMSls - refs.sys     - Minstore logged stack\nMSPi - refs.sys     - Minstore generic/untagged allocation\nMSpa - refs.sys     - Minstore hash table entries (incl. and primarily SmsPage)\nMSrc - refs.sys     - Minstore tx run cache\nMSrb - refs.sys     - Minstore redo block\nMSre - refs.sys     - Minstore AVL lite entries (incl. and primarily SmsRangeMapEntry)\nMSrk - refs.sys     - Minstore key rules\nMSrm - refs.sys     - Minstore range map\nMSri - refs.sys     - Minstore container rotation init state buffer\nMSro - refs.sys     - Minstore container rotation buffer\nMSrp - refs.sys     - Minstore read cache pages array\nMSrr - refs.sys     - Minstore AVL lite entries (incl. and primarily SmsRCRangeMapEntry)\nMSrv - refs.sys     - Minstore reserved buffers\nMSst - refs.sys     - Minstore stream object\nMStb - refs.sys     - Minstore table object\nMStu - refs.sys     - Minstore tree update filter\nMStx - refs.sys     - Minstore transaction\nMSur - refs.sys     - Minstore undo record\nMSvc - refs.sys     - Minstore volume context\nMSvs - refs.sys     - Minstore valid/invalid checksum debug buffers (debug only)\nMSvu - refs.sys     - Minstore volume/instance object\n\nMST? - <unknown>    - MSTEE (mstee.sys)\nMSTa - <unknown>    -    associated stream header\nMSTc - <unknown>    -    filer connection\nMSTd - <unknown>    -    data format\nMSTf - <unknown>    -    filter instance\nMSTp - <unknown>    -    pin instance\nMSTs - <unknown>    -    stream header\n\nMouC - mouclass.sys - Mouse Class Driver\nMouH - mouhid.sys   - Mouse HID mapper Driver\nMsFc - <unknown>    - Mailslot CCB, Client control block. Each client with an opened mailslot has one of these\nMsFC - <unknown>    - Mailslot root CCB, A client control block for the top level mailslot directory\nMsFd - <unknown>    - Mailslot data entry write buffer, This is writes buffered inside mailslots\nMsFD - <unknown>    - Mailslot root DCB and its name buffer\nMsFf - <unknown>    - Mailslot FCB, File control block, Service side block for each created mailslot.\nMsFg - <unknown>    - Mailslot global resource\nMsFn - <unknown>    - Mailslot temporary name buffer\nMsFN - <unknown>    - Mailslot FCB name buffer, name for each created mailslot\nMsFr - <unknown>    - Mailslot read buffer, buffer created for pended reads issued.\nMsFt - <unknown>    - Mailslot query template, used for directory queries.\nMsFw - <unknown>    - Mailslot work context block, blocks create when we need to timeout reads.\n\nMsvC - ksecdd.sys   - Msv/Ntlm client package\nMup  - mup.sys      - Multiple UNC provider allocations, generic\nMupI - mup.sys      - Windows Server 2003 and prior versions: DFS Irp Context allocation\nMuDn - mup.sys      - Device name\nMuFc - mup.sys      - File Context\nMuFn - mup.sys      - File name rewrite\nMuIc - mup.sys      - IRP Context\nMuMc - mup.sys      - Master context\nMuQc - mup.sys      - Query context\nMuSi - mup.sys      - Surrogate info\nMuSf - mup.sys      - Surrogate file info\nMuSr - mup.sys      - Surrogate IRP info\nMuPe - mup.sys      - Known prefix entry\nMuPi - mup.sys      - Provider info\nMuUn - mup.sys      - UNC provider\n\nMuta - <unknown>    - Mutant objects\n\nNb01 - netbt.sys    - NetBT hash table\nNb02 - netbt.sys    - NetBT remote name address cache\nNb03 - netbt.sys    - NetBT remote name address cache\nNb04 - netbt.sys    - NetBT failed address list\nNb05 - netbt.sys    - NetBT client element\nNb06 - netbt.sys    - NetBT general buffer allocation\nNb07 - netbt.sys    - NetBT datagram request tracker\nNb08 - netbt.sys    - NetBT domain address list\nNb09 - netbt.sys    - NetBT domain name\nNb10 - netbt.sys    - NetBT domain address list\nNb11 - netbt.sys    - NetBT lmhosts path\nNb12 - netbt.sys    - NetBT lmhosts path\nNb13 - netbt.sys    - NetBT lmhosts path\nNb14 - netbt.sys    - NetBT lmhosts path\nNb16 - netbt.sys    - NetBT timer entry\nNb17 - netbt.sys    - NetBT registry path\nNb18 - netbt.sys    - NetBT lmhosts file\nNb19 - netbt.sys    - NetBT lmhosts data\nNb20 - netbt.sys    - NetBT lmhosts path\nNb21 - netbt.sys    - NetBT control object\nNb22 - netbt.sys    - NetBT work item context\nNb23 - netbt.sys    - NetBT lmhosts path\nNb25 - netbt.sys    - NetBT device bindings\nNb26 - netbt.sys    - NetBT device exports\nNb27 - netbt.sys    - NetBT bind list cache\nNb28 - netbt.sys    - NetBT name server addresses\nNb29 - netbt.sys    - NetBT registry string\nNb30 - netbt.sys    - NetBT registry string\nNb31 - netbt.sys    - NetBT configuration entry\nNb33 - netbt.sys    - NetBT registry data\nNb35 - netbt.sys    - NetBT registry data\nNb36 - netbt.sys    - NetBT string\nNb37 - netbt.sys    - NetBT lmhosts path\nNb38 - netbt.sys    - NetBT string\nNb39 - netbt.sys    - NetBT file objects\nNbL0 - netbt.sys    - NetBT lower connection\nNbL1 - netbt.sys    - NetBT lower connection\nNbL2 - netbt.sys    - NetBT lower connection\nNbL3 - netbt.sys    - NetBT lower connection\nNbL4 - netbt.sys    - NetBT lower connection\nNbTA - netbt.sys    - NetBT internal address\nNba9 - netbt.sys    - NetBT IP request buffer\nNbb0 - netbt.sys    - NetBT IP request buffer\nNbt0 - netbt.sys    - NetBT name address\nNbt1 - netbt.sys    - NetBT name address\nNbt2 - netbt.sys    - NetBT NetBIOS address\nNbt4 - netbt.sys    - NetBT client list\nNbt5 - netbt.sys    - NetBT client list\nNbt6 - netbt.sys    - NetBT datagram\nNbt8 - netbt.sys    - NetBT address list\nNbt9 - netbt.sys    - NetBT temporary allocation\nNbtA - netbt.sys    - NetBT datagram\nNbtC - netbt.sys    - NetBT address element\nNbtD - netbt.sys    - NetBT connection\nNbtF - netbt.sys    - NetBT remote name\nNbtG - netbt.sys    - NetBT datagram\nNbtH - netbt.sys    - NetBT work item context\nNbtI - netbt.sys    - NetBT listen requests\nNbtJ - netbt.sys    - NetBT receive element\nNbtK - netbt.sys    - NetBT name address\nNbtL - netbt.sys    - NetBT datagram\nNbtM - netbt.sys    - NetBT address list\nNbtN - netbt.sys    - NetBT address list\nNbtO - netbt.sys    - NetBT adapter status\nNbtP - netbt.sys    - NetBT connection list\nNbtQ - netbt.sys    - NetBT name stats\nNbtR - netbt.sys    - NetBT name address\nNbtS - netbt.sys    - NetBT datagram\nNbtV - netbt.sys    - NetBT work item context\nNbtX - netbt.sys    - NetBT datagram\nNbtY - netbt.sys    - NetBT datagram\nNbtZ - netbt.sys    - NetBT datagram\nNbta - netbt.sys    - NetBT DPC\nNbtb - netbt.sys    - NetBT NetBIOS address\nNbtc - netbt.sys    - NetBT address info\nNbte - netbt.sys    - NetBT delayed connect\nNbtf - netbt.sys    - NetBT DPC\nNbtg - netbt.sys    - NetBT MDL buffer\nNbti - netbt.sys    - NetBT device list\nNbtj - netbt.sys    - NetBT EA buffer\nNbtm - netbt.sys    - NetBT EA buffer\nNbtn - netbt.sys    - NetBT device string\nNbtk - netbt.sys    - NetBT transport address\nNbtt - netbt.sys    - NetBT MDL buffer\nNbtu - netbt.sys    - NetBT MDL buffer\nNbtv - netbt.sys    - NetBT WINS allocation\nNbtw - netbt.sys    - NetBT device linkage names\nNbuf - netio.sys    - NetIO Memory Descriptor List allocations\n\nNBF  - <unknown>    - general NBF allocations\nNBFa - <unknown>    - NBF address object\nNBFb - <unknown>    - NBF receive buffer\nNBFc - <unknown>    - NBF connection object\nNBFd - <unknown>    - NBF packet pool descriptor\nNBFe - <unknown>    - NBF bind & export names\nNBFf - <unknown>    - NBF address file object\nNBFg - <unknown>    - NBF registry path name\nNBFi - <unknown>    - NBF tdi connection info\nNBFk - <unknown>    - NBF loopback buffer\nNBFl - <unknown>    - NBF link object\nNBFn - <unknown>    - NBF netbios name\nNBFo - <unknown>    - NBF config data\nNBFp - <unknown>    - NBF packet\nNBFq - <unknown>    - NBF query buffer\nNBFr - <unknown>    - NBF request\nNBFs - <unknown>    - NBF provider stats\nNBFt - <unknown>    - NBF connection table\nNBFu - <unknown>    - NBF UI frame\nNBFw - <unknown>    - NBF work item\nNBI  - <unknown>    - NwlnkNb transport\nNBS  - <unknown>    - general NetBIOS allocations\nNBSa - <unknown>    -     address block\nNBSc - <unknown>    -     connection block\nNBSe - <unknown>    -     EA buffer\nNBSf - <unknown>    -     FCB\nNBSl - <unknown>    -     LANA block\nNBSn - <unknown>    -     copy of user NCB\nNBSr - <unknown>    -     registry allocations\nNBSx - <unknown>    -     XNS NETONE address (connect block)\nNBSy - <unknown>    -     NetBIOS address (connect block)\nNBSz - <unknown>    -     NetBIOS address (listen block)\nNBqh - <unknown>    -     Non-blocking queue entries used to carry the real data in the queue.\n\nNCSt - <unknown>    - EXIFS NC\n\nND   - ndis.sys     - general NDIS allocations\nNDA  - ndis.sys     - NDIS PacketDirect tag prefix\nNDAa - ndis.sys     - NDIS_PD_ASSOCIATION\nNDAb - ndis.sys     - NDIS_PD_BLOCK\nNDAc - ndis.sys     - NDIS_PD_CLIENT\nNDAe - ndis.sys     - NDIS_PD_EC\nNDAf - ndis.sys     - NDIS_PD_FILTER\nNDAg - ndis.sys     - NDIS_PD_GLOBAL\nNDAm - ndis.sys     - NDIS_PD_MEM_BLOCK NDIS_PD_SGL_BLOCK\nNDAn - ndis.sys     - NDIS_PD_COUNTER\nNDAo - ndis.sys     - NDIS_PD_CONFIG\nNDAq - ndis.sys     - NDIS_PD_PLATFORM_QUEUE\nNDAt - ndis.sys     - NDIS_PD_QUEUE_TRACKER\nNDDl - ndis.sys     - NDIS_TAG_DBG_LOG\nNDMb - ndis.sys     - NDIS_TAG_MAC_BLOCK\nNDPX - ndis.sys     -     NDIS Proxy allocations\nNDPa - ndis.sys     - Apple Talk\nNDPb - ndis.sys     - NBF\nNDPi - ndis.sys     - NWLNKIPX\nNDPn - ndis.sys     - NWLNKNB\nNDPp - ndis.sys     - Packet Scheduler.\nNDPs - ndis.sys     - NWLNKSPX\nNDPt - ndis.sys     - TCPIP\nNDPw - ndis.sys     - WAN_PACKET_TAG\nNDSD - ndis.sys     - NDIS_SETUP_DEVICE_EXTENSION\nNDTr - ndis.sys     - NDIS_TAG_TRANSFER_DATA\nNDam - ndis.sys     -     NdisAllocateMemory\nNDan - ndis.sys     -     adapter name\nNDar - ndis.sys     - NDIS_TAG_ALLOCATED_RESOURCES\nNDas - ndis.sys     - NDIS_TAG_ALLOC_SHARED_MEM_ASYNC\nNDbi - ndis.sys     - NDIS_TAG_BUS_INTERFACE\nNDca - ndis.sys     - NDIS_TAG_NET_CFG_OPS_ACL\nNDch - ndis.sys     - NDIS_TAG_CONFIG_HANDLE\nNDcm - ndis.sys     - NDIS_TAG_CM\nNDcn - ndis.sys     - NDIS_TAG_CANCEL_DEVICE_NAME\nNDco - ndis.sys     - NDIS_TAG_CO\nNDcs - ndis.sys     - NDIS_TAG_NET_CFG_OPS_ID\nNDcw - ndis.sys     - NDIS_TAG_PCW - NDIS Performance Counters\nNDd  - ndis.sys     - NDIS_TAG_DBG\nNDda - ndis.sys     - NDIS_TAG_NET_CFG_DACL\nNDdb - ndis.sys     -     DMA block\nNDdc - ndis.sys     - NDIS_TAG_DCN - Data Center Networking\nNDdi - ndis.sys     - NDIS_TAG_IM_DEVICE_INSTANCE\nNDdl - ndis.sys     - NDIS_TAG_DBG_L\nNDdp - ndis.sys     - NDIS_TAG_DBG_P\nNDds - ndis.sys     - NDIS_TAG_DBG_S\nNDdt - ndis.sys     - NDIS_TAG_DFRD_TMR\nNDel - ndis.sys     - NDIS debugging event log\nNDfa - ndis.sys     - NDIS_TAG_FILTER_ADDR\nNDfb - ndis.sys     - NDIS_TAG_LWFILTER_BLOCK\nNDfd - ndis.sys     - NDIS_TAG_FILE_DESCRIPTOR\nNDfi - ndis.sys     - NDIS_TAG_FILE_IMAGE\nNDfm - ndis.sys     - NDIS_TAG_FAKE_MAC\nNDfn - ndis.sys     - NDIS_TAG_FILE_NAME\nNDfv - ndis.sys     - NDIS_TAG_LWFILTER_DRIVER\nNDif - ndis.sys     - NDIS_TAG_IF\nNDio - ndis.sys     - NDIS_TAG_IOV - IO Virtualization\nNDkr - ndis.sys     - NDIS_TAG_NDK - Kernel Mode Network Direct (kRDMA)\nNDlb - ndis.sys     -     lookahead buffer\nNDlp - ndis.sys     - NDIS_TAG_LOOP_PKT\nNDmb - ndis.sys     -     MAC block\nNDmo - ndis.sys     - NDIS_TAG_M_OPEN_BLK\nNDmr - ndis.sys     -     map register entry array\nNDmt - ndis.sys     - NDIS_TAG_MEDIA_TYPE_ARRAY\nNDnc - ndis.sys     - NDIS_TAG_NBL_CONTEXT\nNDnd - ndis.sys     - NDIS_TAG_POOL_NDIS\nNDoa - ndis.sys     - NDIS_TAG_OID_ARRAY\nNDob - ndis.sys     - open block\nNDoc - ndis.sys     - NDIS_TAG_OPEN_CONTEXT\nNDof - ndis.sys     - NDIS_TAG_OFFLOAD\nNDop - ndis.sys     - NDIS_TAG_PM_PROT_OFFLOAD\nNDpb - ndis.sys     -     protocol block\nNDpc - ndis.sys     - NDIS_TAG_PROTOCOL_CONFIGURATION\nNDpf - ndis.sys     - NDIS_TAG_FILTER\nNDpk - ndis.sys     - NDIS_TAG_PKT_PATTERN\nNDpl - ndis.sys     - NDIS_TAG_PERF_LOG_ID\nNDpn - ndis.sys     - NDIS_TAG_PARAMETER_NODE\nNDpo - ndis.sys     - NDIS_TAG_PORT\nNDpp - ndis.sys     -     packet pool\nNDpr - ndis.sys     - NDIS_TAG_PERIODIC_RECEIVES\nNDpw - ndis.sys     - NDIS_TAG_WOL_PATTERN\nNDqo - ndis.sys     - NDIS_TAG_QUERY_OBJECT_WORKITEM\nNDqs - ndis.sys     - NDIS_TAG_QOS\nNDqu - ndis.sys     - NDIS_TAG_QUEUE\nNDrc - ndis.sys     - NDIS_TAG_RWL_REFCOUNT\nNDrd - ndis.sys     - NDIS_TAG_REG_READ_DATA_BUFFER\nNDre - ndis.sys     - NDIS_TAG_OID_REQUEST\nNDrf - ndis.sys     - NDIS_TAG_RECEIVE_FILTER\nNDrl - ndis.sys     -     resource list\nNDrp - ndis.sys     - NDIS_TAG_REGISTRY_PATH\nNDrq - ndis.sys     - NDIS_TAG_Q_REQ\nNDrs - ndis.sys     - NDIS_TAG_RSS\nNDrt - ndis.sys     - NDIS_TAG_RST_NBL\nNDrw - ndis.sys     - NDIS_TAG_RWLOCK\nNDrx - ndis.sys     - NDIS debugging refcount\nNDsd - ndis.sys     - NDIS_TAG_NET_CFG_SEC_DESC\nNDse - ndis.sys     - NDIS_TAG_SECURITY\nNDsg - ndis.sys     - NDIS_TAG_DOUBLE_BUFFER_PKT\nNDsh - ndis.sys     - NDIS_TAG_SHARED_MEMORY\nNDsi - ndis.sys     - EISA slot information\nNDsk - ndis.sys     - NDIS debugging stacktrace\nNDsm - ndis.sys     - Cached shared memory descriptor\nNDss - ndis.sys     - NDIS_TAG_SS - Selective Suspend\nNDst - ndis.sys     - NDIS_TAG_STRING\nNDtk - ndis.sys     - NDIS_TAG_NBL_TRACKER - Lost packet diagnostics\nNDvm - ndis.sys     - NDIS_TAG_ALLOC_MEM_VERIFY_ON\nNDw0 - ndis.sys     - NDIS_TAG_WMI_REG_INFO\nNDw1 - ndis.sys     - NDIS_TAG_WMI_GUID_TO_OID\nNDw2 - ndis.sys     - NDIS_TAG_WMI_OID_SUPPORTED_LIST\nNDw3 - ndis.sys     - NDIS_TAG_WMI_EVENT_ITEM\nNDwh - ndis.sys     - NDIS_TAG_WRAPPER_HANDLE\nNDwi - ndis.sys     - NDIS_TAG_WORK_ITEM\nNDwr - ndis.sys     - NDIS_TAG_WMI_REQUEST\nNDwx - ndis.sys     - NDIS_TAG_WOL_XLATE\nNDxc - ndis.sys     - NDIS_TAG_POOL_XLATE\n\nNet  - tcpip.sys    - NetIO Generic Buffers (iBFT Table allocations)\nNeWQ - tcpip.sys    - NetIO WorkQueue Data\n\nNEEB - newt_ndis6.sys - NEWT Emulation Bench\nNEFT - newt_ndis6.sys - NEWT Filter Object\nNEIM - newt_ndis6.sys - NEWT IM Object\nNEOD - newt_ndis6.sys - NEWT OID\nNEPK - newt_ndis6.sys - NEWT Packet\nNEWI - newt_ndis6.sys - NEWT Work Item\n\nNb?? - <unknown>    - NetBT allocations\nNf?? - nfssvr.sys   - NFS (Network File System) allocations\nNfR? - nfsrdr.sys   - NFS (Network File System) client re-director\nNls  - <unknown>    - Nls strings\nNlsK - nt!ex        - Nls data\nNmdd - <unknown>    - NetMeeting display driver miniport 1 MB block\n\nNhfs - tcpip.sys    - NetIO Hash Function State Data\n\nNicT - mslbfoprovider.sys - Microsoft NDIS LBFO Provider (NIC Teaming)\n\nNavl - tcpip.sys    - Network Layer AVL Tree allocations\nNLbd - tcpip.sys    - Network Layer Buffer Data\nNLcc - tcpip.sys    - Network Layer Client Contexts\nNLpd - tcpip.sys    - Network Layer Client Requests\nNLcp - tcpip.sys    - Network Layer Compartments\nNLuh - <unknown>    - Network Layer Ul Handles\nNLap - tcpip.sys    - Network Layer Netio Helper Function allocations\nNLNa - tcpip.sys    - Network Layer Network Address Lists\n\nNMhf - netio.sys    - Handle Factory pool\nNMpt - <unknown>    - Generic AVL Tree allocations\n\nNMRb - tcpip.sys    - Network Module Registrar Bindings\nNMRc - tcpip.sys    - Network Module Registrar Arrays\nNMRf - tcpip.sys    - Network Module Registrar Filters\nNMRg - tcpip.sys    - Network Module Registrar Generic Buffers\nNMRm - tcpip.sys    - Network Module Registrar Modules\nNMRn - tcpip.sys    - Network Module Registrar Network Protocol Identifiers\n\nNnbl - netio.sys    - NetIO NetBufferLists\nNnbf - netio.sys    - NetIO NetBuffers\nNnnn - netio.sys    - NetIO NetBuffers And NetBufferLists\nNph1 - netio.sys    - NetIO Protocol Header1 Data\nNph2 - netio.sys    - NetIO Protocol Header2 Data\n\nNone - nt!Vf        - Call to ExAllocatePool without any pool tag\n\nNpEv - npfs.sys     - Npfs events\nNpf* - npfs.sys     - Npfs Allocations\nNpFc - npfs.sys     - CCB, client control block\nNpFC - npfs.sys     - ROOT_DCB CCB\nNpFD - npfs.sys     - DCB, directory block\nNpFg - npfs.sys     - Global storage\nNpFi - npfs.sys     - NPFS client info buffer.\nNpFn - npfs.sys     - Name block\nNpFq - npfs.sys     - Query template buffer used for directory query\nNpFr - npfs.sys     - DATA_ENTRY records (read/write buffers)\nNpFs - npfs.sys     - Client security context\nNpFw - npfs.sys     - Write block\nNpFW - npfs.sys     - Write block\n\nNpta - <unknown>    - NPT Addresses\nNptx - <unknown>    - NPT Packets\nNptr - <unknown>    - NPT Receive Completes\nNpts - <unknown>    - NPT Send sCompletes\n\nNrsd - netio.sys    - NRT security descriptor\nNrtr - netio.sys    - NRT record\nNrtw - netio.sys    - NRT worker\n\nNS?? - <unknown>    - Netware server allocations\n\nNSIk - nsi.dll      - NSI RPC Tansactions\nNSIr - nsi.dll      - NSI Generic Buffers\nNSpc - nsi.dll      - NSI Proxy Contexts\nNSpg - nsi.dll      - NSI Proxy Generic Buffers\nNSIc - nsi.dll      - NSI Containers\nNMcp - nsi.dll      - NSI Modules\nNAcc - nsi.dll      - NSI Access\n\nREM NTFS Specific allocation tags\nNt?? - ntfs.sys     - Unrecognized NTFS tag (update base\\published\\pooltag.w)\nNtAR - ntfs.sys     -     NTFS_ASYNC_CACHED_READ_CONTEXT\nNtce - ntfs.sys     -     CLOSE_ENTRY\nNtDt - ntfs.sys     -     Acquired range array temporary buffer\nNtEA - ntfs.sys     -     NTFS QueryOnCreate EA Buffer\nNtf0 - ntfs.sys     -     General pool allocation\nNtf9 - ntfs.sys     -     Large Temporary Buffer\nNtf5 - ntfs.sys     -     Shared Security tracking (debug only)\nNtfa - ntfs.sys     -     DELAYED_ALLOCATION\nNtfA - ntfs.sys     -     ALIGNED_MDL_CONTEXT\nNtfb - ntfs.sys     -     Reserved map buffer\nNtfB - ntfs.sys     -     Bandwidth contracts allocations\nNtfC - ntfs.sys     -     CCB\nNtfc - ntfs.sys     -     CCB_DATA\nNtfd - ntfs.sys     -     DEALLOCATED_CLUSTERS\nNtfD - ntfs.sys     -     DEALLOCATED_RECORDS\nNtfE - ntfs.sys     -     INDEX_CONTEXT\nNtff - ntfs.sys     -     FCB_DATA\nNtfF - ntfs.sys     -     FCB_INDEX\nNtfI - ntfs.sys     -     IO_CONTEXT\nNtfi - ntfs.sys     -     IRP_CONTEXT\nNtfK - ntfs.sys     -     KEVENT                            NtfsKeventLookasideList\nNtfk - ntfs.sys     -     FILE_LOCK\nNtfl - ntfs.sys     -     LCB\nNtfM - ntfs.sys     -     NTFS_MCB_ENTRY\nNtfm - ntfs.sys     -     NTFS_MCB_ARRAY\nNtfN - ntfs.sys     -     FILE_RECORDS_TO_DELETE\nNtfn - ntfs.sys     -     SCB_NONPAGED                      NtfsScbNonpagedLookasideList\nNtfo - ntfs.sys     -     SCB_INDEX normalized named buffer\nNtfp - ntfs.sys     -     COMPRESSION_CONTEXT\nNtfQ - ntfs.sys     -     QUOTA_CONTROL_BLOCK\nNtfq - ntfs.sys     -     General Allocation with Quota\nNtfR - ntfs.sys     -     READ_AHEAD_THREAD\nNtfr - ntfs.sys     -     ERESOURCE\nNtfS - ntfs.sys     -     SCB_INDEX\nNtfs - ntfs.sys     -     SCB_DATA\nNtfT - ntfs.sys     -     SCB_SNAPSHOT                      NtfsScbSnapshotLookasideList\nNtft - ntfs.sys     -     SCB (Prerestart)\nNtfu - ntfs.sys     -     NTFS_MARK_UNUSED_CONTEXT\nNtfV - ntfs.sys     -     VPB\nNtfv - ntfs.sys     -     COMPRESSION_SYNC\nNtfZ - ntfs.sys     -     POSIX_MAPPED_CLOSE_ITEM\nNtfw - ntfs.sys     -     Workspace\nNtIO - ntfs.sys     -     NTFS IO perf\nNtMC - ntfs.sys     -     MAPCOUNT_LOG\nNtOi - ntfs.sys     -     OFFLOAD_IO_CONTEXT\nNtop - ntfs.sys     -     NTFS_OPLOCK_OWNER_STACK_CAPTURE\nNtrk - ntfs.sys     -     NTFS registry key name structures\nNtrs - ntfs.sys     -     ROLLBACK_STRUCT\nNtrt - ntfs.sys     -     RANGETRACK_LOCAL_STRUCT\nNtTc - ntfs.sys     -     FILE_LEVEL_TRIM_CONTEXT\nNtTf - ntfs.sys     -     NTFS_DISK_FLUSH_CONTEXT           NtfsDiskFlushContextLookasideList\nNtTr - ntfs.sys     -     DEVICE_MANAGE_DATA_SET_ATTRIBUTES NtfsDeviceManageDataSetAttributesLookasideList\nNtTo - ntfs.sys     -     DEVICE_MANAGE_DATA_SET_ATTRIBUTES NtfsFileOffloadLookasideList\nNtTe - ntfs.sys     -     NTFS Telemetry\nNtTm - ntfs.sys     -     NtfsTPMapLookasideList\nNtWR - ntfs.sys     -     REGISTRY_WATCH_CONTEXT\nNtxF - ntfs.sys     -     FCB_NONPAGED                      NtfsFcbNonpagedDataLookasideList\nNtxI - ntfs.sys     -     FCB_NONPAGED_INDEX                NtfsFcbNonpagedIndexLookasideList\nNtxM - ntfs.sys     -     FAST_MUTEXT                       NtfsFastMutexNonpagedLookasideList\n\n\nREM NTFS tags based on source module\nNtFa - ntfs.sys     -     AllocSup.c\nNtFA - ntfs.sys     -     AttrSup.c\nNtFB - ntfs.sys     -     BitmpSup.c\nNtFl - ntfs.sys     -     Clog.c\nNtFc - ntfs.sys     -     Corrupt.c\nNtFC - ntfs.sys     -     Create.c\nNtFD - ntfs.sys     -     DevioSup.c\nNtFd - ntfs.sys     -     DirCtrl.c\nNtFE - ntfs.sys     -     Ea.c\nNtFF - ntfs.sys     -     FileInfo.c\nNtFf - ntfs.sys     -     FsCtrl.c\nNtFH - ntfs.sys     -     SelfHeal.c\nNtFI - ntfs.sys     -     IndexSup.c / TxfFilterDirectoryQuery (Ccb->IndexEntry)\nNtFi - ntfs.sys     -     TxfIdSup.c\nNtfJ - ntfs.sys     -     ntfsinit.c\nNtFL - ntfs.sys     -     LogSup.c\nNtFM - ntfs.sys     -     McbSup.c\nNtFm - ntfs.sys     -     Ntfs MFT View Ref Counter Arrays\nNtFN - ntfs.sys     -     NtfsData.c\nNtFO - ntfs.sys     -     ObjIdSup.c\nNtFQ - ntfs.sys     -     QuotaSup.c\nNtFP - ntfs.sys     -     Pnp.c / ReparSup.c\nNtFR - ntfs.sys     -     RestrSup.c\nNtFS - ntfs.sys     -     SecurSup.c\nNtFs - ntfs.sys     -     StrucSup.c\nNtFU - ntfs.sys     -     usnsup.c\nNtFV - ntfs.sys     -     VerfySup.c\nNtFv - ntfs.sys     -     ViewSup.c\nNtFW - ntfs.sys     -     Write.c\nNtFX - ntfs.sys     -     NtfsBlackbox.c\nNtMo - ntfs.sys     -     mount.c\nNtSr - ntfs.sys     -     srsup.c\n\nNulB - tlnull.sys   - Null TDI Buffers\nNulR - tlnull.sys   - Null TDI Requests\nNulS - tlnull.sys   - Null TDI Sockets\nNulE - tlnull.sys   - Null Tl Endpoints\nNull - tlnull.sys   - Null TL Generics\nNulI - tlnull.sys   - Null TL Indications\nNulr - tlnull.sys   - Null Tl Requests\n\nNV   - <unknown>      - nVidia video driver\nNvLA - <nvlddmkm.sys> - nVidia video driver\nNvLa - <nvlddmkm.sys> - nVidia video driver\nNvLC - <nvlddmkm.sys> - nVidia video driver\nNvLc - <nvlddmkm.sys> - nVidia video driver\nNvLD - <nvlddmkm.sys> - nVidia video driver\nNvLd - <nvlddmkm.sys> - nVidia video driver\nNvLE - <nvlddmkm.sys> - nVidia video driver\nNvLH - <nvlddmkm.sys> - nVidia video driver\nNvLm - <nvlddmkm.sys> - nVidia video driver\nNvLP - <nvlddmkm.sys> - nVidia video driver\nNvLp - <nvlddmkm.sys> - nVidia video driver\nNvLR - <nvlddmkm.sys> - nVidia video driver\nNvLr - <nvlddmkm.sys> - nVidia video driver\nNvLS - <nvlddmkm.sys> - nVidia video driver\nNvLs - <nvlddmkm.sys> - nVidia video driver\nNvLT - <nvlddmkm.sys> - nVidia video driver\n\nNwcs - <unknown>    - Client Services for NetWare\nNwFw - <unknown>    - ntos\\tdi\\fwd\n\n\nObSq - nt!ob        - object security descriptors (query)\nObCi - nt!ob        - captured information for ObCreateObject\nObCI - nt!ob        - object creation lookaside list\nObDi - nt!ob        - object directory\nObHd - nt!ob        - object handle count data base\nObNm - nt!ob        - object names\nObNM - nt!ob        - name buffer per processor lookaside pointers\nObRt - nt!ob        - object reference stack tracing\nObZn - nt!ob        - object zone\nObjT - nt!ob        - object type objects\nObtb - nt!ob        - object tables via EX handle.c\nObTR - nt!ob        - object table ERESOURCEs\nObeb - nt!ob        - object tables extra bit tables via EX handle.c\nObDm - nt!ob        - object device map\nObSc - nt!ob        - Object security descriptor cache block\nObSt - nt!ob        - Object Manager temporary storage\nObWm - nt!ob        - Object Manager wait blocks\n\nODMg - dxgkrnl.sys  - Output Duplication component\n\nOHCI - <unknown>    - Open Host Controller Interface for USB\nohci - <unknown>    - 1394 OHCI host controller driver\n\nOlmC - tcpip.sys    - Offload Manager Connections\nOlmI - tcpip.sys    - Offload Manager Interfaces\n\nOvfl - <unknown>    - The internal pool tag table has overflowed - usually this is a result of nontagged allocations being made\n\nOvfL - <unknown>    - EXIFS FCBOVF List\n\nPaeD - <unknown>    - PAE top level directory allocation blocks\n\nParC - <unknown>    - Parallel class driver\nParL - <unknown>    - Parallel link driver\nParP - <unknown>    - Parallel port driver\nParV - <unknown>    - ParVdm driver for vdm<->parallel port communciation\n\nPciB - pci.sys      - PnP pci bus enumerator\n\nPccr - pacer.sys    - PACER Filter Clone Requests\nPcfc - pacer.sys    - PACER Filter Contexts\nPcfl - pacer.sys    - PACER Flows\nPcge - pacer.sys    - PACER Generic Buffers (DACL, SID allocations)\nPcle - pacer.sys    - PACER Lines\nPclt - pacer.sys    - PACER Line Tables\nPcna - pacer.sys    - PACER Filter Network Addresses\nPcnt - pacer.sys    - PACER NetBufferTimes\nPcop - pacer.sys    - PACER Original Packet Contexts\nPcpc - pacer.sys    - PACER Packet Contexts\nPcsb - pacer.sys    - PACER Send Buffers\nPcta - pacer.sys    - PACER Timer Units\nPctw - pacer.sys    - PACER Timer Wheels\nPcwc - pacer.sys    - PACER WAN NetworkBufferList CTXs\n\nPcCi - <unknown>    - WDM audio port class adapter device object stuff\nPcCr - <unknown>    - WDM audio stuff\nPcDi - <unknown>    - WDM audio stuff\nPcDm - <unknown>    - DirectMusic MXF objects (WDM audio)\nPcFM - <unknown>    - WDM audio FM synthesizer\nPcFp - <unknown>    - WDM audio stuff\nPcIc - <unknown>    - WDM audio stuff\nPcIl - <unknown>    - WDM audio stuff\nPcNw - <unknown>    - WDM audio stuff\nPcPc - <unknown>    - WDM audio stuff\nPcPr - <unknown>    - WDM audio stuff\nPcSX - <unknown>    - WDM audio stuff\nPcSl - <unknown>    - WDM audio stuff\nPcSt - <unknown>    - WDM audio stuff\nPcSx - <unknown>    - WDM audio stuff\nPcUs - <unknown>    - WDM audio stuff\n\nPcmc - pcmcia.sys   - Pcmcia bus enumerator, general structures\nPcic - <unknown>    - Pcmcia bus enumerator, PCIC/Cardbus controller specific structures\nPcdb - <unknown>    - Pcmcia bus enumerator, Databook controller specific structures\n\nPdcA - pdc.sys      - PDC_ACTIVATION_TAG, ACTIVATOR_CLIENT_TAG\nPdcC - pdc.sys      - PDC_CLIENT_PORT_TAG\nPdcE - pdc.sys      - ACTIVATOR_EVENT_TAG\nPdcI - pdc.sys      - PDC_INCLUSION_LIST_TAG\nPdcM - pdc.sys      - PDC_MESSAGE_TAG\nPdcN - pdc.sys      - PDC_NOTIFICATION_TAG, NOTIFICATION_CLIENT_TAG\nPdcP - pdc.sys      - PDC_PORT_TAG\nPdcR - pdc.sys      - PDC_RESILIENCY_TAG, RESILIENCY_CLIENT_TAG\nPdcS - pdc.sys      - PDC_SUSPRES_TAG\nPdcT - pdc.sys      - PDC_TOKEN_TAG\nPSwt - pdc.sys      - PDC_PSWT_TAG\nPdcs - pdc.sys      - PDC_SCENARIO_TAG\n\nSPMp - nt!po        - Kernel Scenario Power Manager Policies.\n\nPepT - nt!PopPep    - Default Power Engine Plugin\n\nPetw - pacer.sys    - PACER ETW\n\nPf?? - nt!pf        - Pf Allocations\nPfAL - nt!pf        - Pf Application launch event data\nPfAS - nt!pf        - Pf Prefetch support array\nPfDq - nt!pf        - Pf Directory query buffers\nPfED - nt!pf        - Pf Generic event data\nPfEL - nt!pf        - Pf Event logging buffers\nPfET - nt!pf        - Pf Entry info tables\nPfFH - nt!pf        - Pf RpContext FileKeyHash buckets\nPfFh - nt!pf        - Pf Prefetch file handle cache array\nPfFK - nt!pf        - Pf RpContext FileKeyHashEntry\nPfLB - nt!pf        - Pf Log buffers\nPfMP - nt!pf        - Pf Prefetch metadata buffers\nPfNL - nt!pf        - Pf Name logging buffers\nPfOB - nt!pf        - Pf Oplock buffers\nPfPB - nt!pf        - Pf Pfn query buffers\nPfRL - nt!pf        - Pf Prefetch read list\nPfRQ - nt!pf        - Pf Prefetch request buffers\nPfSA - nt!pf        - Pf Prefetch support array\nPfTD - nt!pf        - Pf Trace Dump\nPfTt - nt!pf        - Pf Translation tables\nPfVA - nt!pf        - Pf VA prefetching buffers\nPfVH - nt!pf        - Pf Prefetch volume handles\n\nPfcs - pacer.sys    - PACER Flow Counter Sets\nPfhc - pacer.sys    - PACER File Handle Contexts\n\nPFXM - nt!PoFx      - Runtime Power Management Framework\n\nPcwC - nt!pcw       - PCW Counter set\nPcwR - nt!pcw       - PCW provider Registration\nPcwI - nt!pcw       - PCW counter set Instance\nPcwQ - nt!pcw       - PCW Query item\nPcwS - nt!pcw       - PCW System call buffer\nPcwT - nt!pcw       - PCW Temporary (short-lived) buffer\n\nPgm? - <unknown>    - Pgm (Pragmatic General Multicast) protocol: RMCast.sys\n\nPlcp - <unknown>    - Cache aware pushlock list (array of puchlock addresses)\nPlcl - <unknown>    - Cache aware pushlock entry. One per processor\n\nPlMp - storport.sys - PortpReadDriverParameterEntry\nPlRB - storport.sys - PortAllocateRegistryBuffer storport!_PORT_REGISTRY_INFO.Buffer\n\nPmpA - portmap.sys  - Portmap address list\nPmpC - portmap.sys  - Portmap device context\nPmpM - portmap.sys  - Portmap mapping\nPmpR - portmap.sys  - Portmap RPCB\n\nPmAT - partmgr.sys  - Partition Manager attributes table cache\nPmDD - partmgr.sys  - Partition Manager device descriptor\nPmIB - partmgr.sys  - Partition Manager buffer for IOCTL processing\nPmME - partmgr.sys  - Partition Manager migration entry\nPmPE - partmgr.sys  - Partition Manager partition entry\nPmPT - partmgr.sys  - Partition Manager partition table cache\nPmRL - partmgr.sys  - Partition Manager remove lock\nPmRP - partmgr.sys  - Partition Manager registry path\nPmRR - partmgr.sys  - Partition Manager removal relations\nPmSD - partmgr.sys  - Partition Manager snapshot data cache\nPmTE - partmgr.sys  - Partition Manager table entry\nPmVE - partmgr.sys  - Partition Manager volume entry\n\nPNCH - <unknown>    - Power Notify Channel\nPNCL - <unknown>    - Power Notify channel list\nPNDP - <unknown>    - Power Abort Dpc Routine\nPNI  - <unknown>    - Power Notify Instance\n\nPoEa - raspppoe.sys - MTAG_ADAPTER\nPoEb - raspppoe.sys - MTAG_BINDING\nPoEc - raspppoe.sys - MTAG_BUFFERPOOL\nPoEd - raspppoe.sys - MTAG_PACKETPOOL\nPoEe - raspppoe.sys - MTAG_PPPOEPACKET\nPoEf - raspppoe.sys - MTAG_TAPIPROV\nPoEg - raspppoe.sys - MTAG_LINE\nPoEh - raspppoe.sys - MTAG_CALL\nPoEi - raspppoe.sys - MTAG_HANDLETABLE\nPoEj - raspppoe.sys - MTAG_HANDLECB\nPoEk - raspppoe.sys - MTAG_TIMERQ\nPoEl - raspppoe.sys - MTAG_FREED\nPoEm - raspppoe.sys - MTAG_LLIST_WORKITEMS\nPoEu - raspppoe.sys - MTAG_UTIL\n\nPool - <unknown>    - Pool tables, etc.\nPooL - <unknown>    - Phase 0 initialization of the executive component, paged and nonpaged small pool lookaside structures\nPort - <unknown>    - Port objects\n\nPoSL - <unknown>    - Power shutdown event list\n\nPPMd - <unknown>    - Processor Drivers (Processor Power Management).\nPPMi - nt!po        - Kernel Processor Power Management Idle States.\nPPMp - nt!po        - Kernel Processor Power Management Perf States.\nPPMw - nt!po        - Kernel Processor Power Management WMI interface.\n\nProf - <unknown>    - Profile objects\n\nPOWI - nt!po        - Power Work Item (executive worker thread work item entry)\nPSwt - nt!po        - Power switch structure\nPSTA - nt!po        - Po registered system state\nPDss - nt!po        - Po device system state\nPRTM - nt!po        - Power runtime management\nPCol - nt!po        - Thermal cooling requests and extensions\n\nPpsP - nt!ps        - PSP_PROPERTY_TAG\n\nPpTg - mpsdrv.sys   - MPSDRV PPTP GRE analyzer\nPpTt - mpsdrv.sys   - MPSDRV PPTP TCP analyzer\n\nPrcr - processr.sys - Processr driver allocations\n\nProc - nt!ps        - Process objects\nPs   - nt!ps        - general ps allocations\nPsap - nt!ps        - Block used to hold a user mode APC while its queued to a thread\nPsAp - nt!ps        - Process APC queued by user mode process\nPsCa - nt!ps        - APC queued at thread create time.\nPsCr - nt!ps        - Working set change record (temporary allocation)\nPsEx - nt!ps        - Process exit APC\nPsFn - nt!ps        - Captured image file name buffer (temporary allocation)\nPsHl - nt!ps        - Captured list of handles to inherit in child process (temporary allocation)\nPsIm - nt!ps        - Thread impersonation (PS_IMPERSONATE_INFORMATION, pre-Vista)\nPsJa - nt!ps        - Job access control state\nPsjb - nt!ps        - Job set array (temporary allocation)\nPsLd - nt!ps        - Process LDT information blocks\nPsPb - nt!ps        - Captured process parameter block (temporary allocation)\nPsQb - nt!ps        - Process quota block\nPsRl - nt!ps        - Captured memory reserve list (temporary allocation)\nPsSb - nt!ps        - Initial process parameter block (temporary allocation)\nPsSd - nt!ps        - Augmented thread security descriptor (temporary allocation)\nPsTf - nt!ps        - Job object token filter\nPstb - nt!ps        - Process tables via EX handle.c\nPsta - nt!ps        - Power management system state\nPsTp - nt!ps        - Thread termination port block\nPsWs - nt!ps        - Process working set watch array\n\nPSE3 - pse36.sys    - Physical Size Extension driver\n\nPnp0 - nt!pnp       - PNPMGR rebalance resource request table\nPnp1 - nt!pnp       - PNPMGR IRP completion context\nPnp2 - nt!pnp       - PNPMGR device action request\nPnp3 - nt!pnp       - PNPMGR HW Profile\nPnp4 - nt!pnp       - PNPMGR CM API\nPnp5 - nt!pnp       - PNPMGR assign resources context\nPnp6 - nt!pnp       - PNPMGR resource request\nPnp7 - nt!pnp       - PNPMGR deferred notify entry\nPnp8 - nt!pnp       - PNPMGR async target device change notify\nPnp9 - nt!pnp       - PNPMGR HW profile notify\nPnpA - nt!pnp       - PNPMGR PnpRtl Operations\nPnpC - nt!pnp       - PNPMGR target device notify\nPnpF - nt!pnp       - PNPMGR eject data\nPnpG - nt!pnp       - PNPMGR generic\nPnpH - nt!pnp       - PNPMGR service name\nPnpI - nt!pnp       - PNPMGR instance path\nPnpJ - nt!pnp       - PNPMGR device event list\nPnpK - nt!pnp       - PNPMGR device event entry\nPnpL - nt!pnp       - PNPMGR device event workitem\nPnpM - nt!pnp       - PNPMGR veto buffer\nPnpN - nt!pnp       - PNPMGR PDO array\nPnpO - nt!pnp       - PNPMGR veto process\nPnpP - nt!pnp       - PNPMGR veto device object\nPnpQ - nt!pnp       - PNPMGR partition resource list\nPnpR - nt!pnp       - PNPMGR memory bitmap\nPnpS - nt!pnp       - PNPMGR dependent info\nPnpT - nt!pnp       - PNPMGR provider info\nPnpU - nt!pnp       - PNPMGR async set status control\nPnpV - nt!pnp       - PNPMGR notify entry loc\nPnpW - nt!pnp       - PNPMGR SwDevice\nPnpX - nt!pnp       - PNPMGR DevQuery\nPnpY - nt!pnp       - PNPMGR usermode device notifications\nPnpZ - nt!pnp       - PNPMGR data model\nPnPb - nt!pnp       - PnP BIOS resource manipulation\nPpEB - nt!pnp       - PNP_POOL_EVENT_BUFFER\nPpEE - nt!pnp       - PNP_DEVICE_EVENT_ENTRY_TAG\nPpEL - nt!pnp       - PNP_DEVICE_EVENT_LIST_TAG\nPpLg - nt!pnp       - PnP last good.\nPpUB - nt!pnp       - PNP_USER_BLOCK_TAG\nPpWI - nt!pnp       - PNP_DEVICE_WORK_ITEM_TAG\nPpcd - nt!pnp       - PnP critical device database\nPpcr - nt!pnp       - plug-and-play critical allocations\nPpdd - nt!pnp       - new Plug-And-Play driver entries and IRPs\nPpde - nt!pnp       - routines to perform device removal\nPpei - nt!pnp       - Eisa related code\nPpen - nt!pnp       - routines to perform device enumeration\nPpin - nt!pnp       - plug-and-play initialization\nPpio - nt!pnp       - plug-and-play IO system APIs\n\nPPMi - nt!po        - Processor Power Manager Idle States\nPPMp - nt!po        - Processor Power Manager Perf States\nPPMw - nt!po        - Processor Power Manager WMI Interface\n\nPpre - nt!pnp       - resource allocation and translation\nPprl - nt!pnp       - routines to manipulate relations list\nPpsu - nt!pnp       - plug-and-play subroutines for the I/O system\n\nPPTP - <unknown>    - PPTP_MEMORYPOOL_TAG\nPPT0 - <unknown>    - PPTP_TDIADDR_TAG\nPPT1 - <unknown>    - PPTP_TDICONN_TAG\nPPT2 - <unknown>    - PPTP_CONNINFO_TAG\nPPT3 - <unknown>    - PPTP_ADDRINFO_TAG\nPPT4 - <unknown>    - PPTP_TIMEOUT_TAG\nPPT5 - <unknown>    - PPTP_TIMER_TAG\nPPT6 - <unknown>    - PPTP_TDICOTS_TAG\nPPT7 - <unknown>    - PPTP_WRKQUEUE_TAG\nPPT8 - <unknown>    - PPTP_SEND_CTRLDATA_TAG\nPPT9 - <unknown>    - PPTP_SEND_ACKDATA_TAG\nPPTa - <unknown>    - PPTP_SEND_DGRAMDESC_TAG\nPPTb - <unknown>    - PPTP_TDICLTS_TAG\nPPTc - <unknown>    - PPTP_RECV_CTRLDESC_TAG\nPPTd - <unknown>    - PPTP_RECV_CTRLDATA_TAG\nPPTe - <unknown>    - PPTP_RECV_DGRAMDESC_TAG\nPPTf - <unknown>    - PPTP_RECV_DGRAMDATA_TAG\nPPTg - <unknown>    - PPTP_RECVDESC_TAG\nPPTh - <unknown>    - PPTP_ENGINE_TAG\nPPTi - <unknown>    - PPTP_RECVDATA_TAG\n\nPRF? - nt!wdi       - Performance Allocations\nPRFd - nt!wdi       - Performance Diagnostics Structures\n\nPSC? - <unknown>    - Packet Scheduler (PSCHED) Tags\n\nPSC0 - <unknown>    - NDIS Request\nPSC1 - <unknown>    - GPC Client Vc\nPSC2 - <unknown>    - WanLink\nPSC3 - <unknown>    - Miscellaneous allocations\nPSC4 - <unknown>    - WMI\nPSCa - <unknown>    - Adapter\nPSCb - <unknown>    - CallParameters\nPSCc - <unknown>    - PipeContext\nPSCd - <unknown>    - FlowContext\nPSCe - <unknown>    - ClassMapContext\nPSCf - <unknown>    - Adapter Profile\nPSCg - <unknown>    - Component\n\nPX1  - <unknown>    - ndis ProviderEventLookaside\n\np2?? - perm2dll.dll - Permedia2 display driver\np2d3 - perm2dll.dll - Permedia2 display driver - d3d.c\np2d6 - perm2dll.dll - Permedia2 display driver - d3ddx6.c\np2de - perm2dll.dll - Permedia2 display driver - debug.c\np2ds - perm2dll.dll - Permedia2 display driver - d3dstate.c\np2dt - perm2dll.dll - Permedia2 display driver - d3dtxman.c\np2su - perm2dll.dll - Permedia2 display driver - ddsurf.c\np2en - perm2dll.dll - Permedia2 display driver - enable.c\np2fi - perm2dll.dll - Permedia2 display driver - fillpath.c\np2he - perm2dll.dll - Permedia2 display driver - heap.c\np2hw - perm2dll.dll - Permedia2 display driver - hwinit.c\np2cx - perm2dll.dll - Permedia2 display driver - p2ctxt.c\np2pa - perm2dll.dll - Permedia2 display driver - palette.c\np2pe - perm2dll.dll - Permedia2 display driver - permedia.c\np2tx - perm2dll.dll - Permedia2 display driver - textout.c\n\nP3D? - perm3dd.dll  - Permedia3 display driver - DirectDraw/3D\nP3G? - perm3dd.dll  - Permedia3 display driver\n\nppPT - pvhdparser.sys - Proxy Virtual Machine Storage VHD Parser Driver (parser)\nppRT - pvhdparser.sys - Proxy Virtual Machine Storage VHD Parser Driver (parser)\n\nPSHD - pshed.dll    - PSHED\nPSPi - pshed.dll    - PSHED Plug-in\n\nPpcs - pacer.sys    - PACER Pipe Counter Sets\nPwff - pacer.sys    - PACER WFP Filters\nPwmi - pacer.sys    - PACER WMI notifications\n\nPX1 - ndproxy.sys - PX_EVENT_TAG\nPX2 - ndproxy.sys - PX_VCTABLE_TAG\nPX3 - ndproxy.sys - PX_ADAPTER_TAG\nPX4 - ndproxy.sys - PX_CLSAP_TAG\nPX5 - ndproxy.sys - PX_CMSAP_TAG\nPX6 - ndproxy.sys - PX_PARTY_TAG\nPX7 - ndproxy.sys - PX_COCALLPARAMS_TAG\nPX8 - ndproxy.sys - PX_REQUEST_TAG\nPX9 - ndproxy.sys - PX_PROVIDER_TAG\nPXa - ndproxy.sys - PX_ENUMLINE_TAG\nPXb - ndproxy.sys - PX_TAPILINE_TAG\nPXc - ndproxy.sys - PX_ENUMADDR_TAG\nPXd - ndproxy.sys - PX_TAPIADDR_TAG\nPXe - ndproxy.sys - PX_TAPICALL_TAG\nPXf - ndproxy.sys - PX_LINECALLINFO_TAG\nPXg - ndproxy.sys - PX_CMAF_TAG\nPXh - ndproxy.sys - PX_CLAF_TAG\nPXi - ndproxy.sys - PX_VC_TAG\nPXj - ndproxy.sys - PX_TRANSLATE_CALL_TAG\nPXk - ndproxy.sys - PX_TRANSLATE_SAP_TAG\nPXl - ndproxy.sys - PX_LINETABLE_TAG\n\nQnam - <unknown>    - EXIFS Query Name\n\nQp?? - <unknown>    - Generic Packet Classifier (MSGPC)\nQppn - <unknown>    -      Queued Notifications\nQppi - <unknown>    -      Pending Irp structures\nQpci - <unknown>    -      CfInfo\nQpct - <unknown>    -      Client blocks\nQppa - <unknown>    -      Pattern blocks\nQphf - <unknown>    -      HandleFactory\nQpph - <unknown>    -      PathHash\nQprz - <unknown>    -      Rhizome\nQppd - <unknown>    -      GenPatternDb\nQpfd - <unknown>    -      FragmentDb\nQpcf - <unknown>    -      ClassificationFamily\nQpcd - <unknown>    -      CfInfoData\nQpcb - <unknown>    -      ClassificationBlock\nQppt - <unknown>    -      Protocol\nQpdg - <unknown>    -      Debug\n\nQUIC Allocation tags are Qc00 through QcFF\nQUIC - msquic.sys   - Generic QUIC allocation\nQc00 - msquic.sys   - QUIC Silo\nQc01 - msquic.sys   - QUIC connection\nQc02 - msquic.sys   - QUIC connection transport parameters\nQc03 - msquic.sys   - QUIC stream\nQc04 - msquic.sys   - QUIC stream buffer\nQc05 - msquic.sys   - QUIC sent frame metadata\nQc06 - msquic.sys   - QUIC datagram buffer\nQc07 - msquic.sys   - QUIC test code\nQc08 - msquic.sys   - QUIC perf code\nQc09 - msquic.sys   - QUIC tool code\nQc0A - msquic.sys   - QUIC Worker\nQc0B - msquic.sys   - QUIC Listener\nQc0C - msquic.sys   - QUIC CID\nQc0D - msquic.sys   - QUIC CID Hash\nQc0E - msquic.sys   - QUIC CID List Entry\nQc0F - msquic.sys   - QUIC CID Prefix\nQc10 - msquic.sys   - QUIC ALPN\nQc11 - msquic.sys   - QUIC Range\nQc12 - msquic.sys   - QUIC Send Buffer\nQc13 - msquic.sys   - QUIC Recv Buffer\nQc14 - msquic.sys   - QUIC Timer Wheel\nQc15 - msquic.sys   - QUIC Registration\nQc16 - msquic.sys   - QUIC configuration\nQc17 - msquic.sys   - QUIC Core binding\nQc18 - msquic.sys   - QUIC API Table\nQc19 - msquic.sys   - QUIC Per Proc Context\nQc1A - msquic.sys   - QUIC Platform Send Context\nQc1B - msquic.sys   - QUIC Platform TLS ACH Context\nQc1C - msquic.sys   - QUIC Platform TLS SNI\nQc1D - msquic.sys   - QUIC Platform TLS Principal\nQc1E - msquic.sys   - QUIC Platform TLS Context\nQc1F - msquic.sys   - QUIC Platform TLS Transport Parameters\nQc20 - msquic.sys   - QUIC Platform TLS Resumption Buffer\nQc21 - msquic.sys   - QUIC Platform TLS Sec Config\nQc22 - msquic.sys   - QUIC Platform TLS Packet Key\nQc23 - msquic.sys   - QUIC Platform TLS Key\nQc24 - msquic.sys   - QUIC Platform TLS HP Key\nQc25 - msquic.sys   - QUIC Platform TLS Hash\nQc26 - msquic.sys   - QUIC Platform TLS Extra Data\nQc27 - msquic.sys   - QUIC temporary alloc\nQc28 - msquic.sys   - QUIC Platform temporary alloc\nQc29 - msquic.sys   - QUIC Platform Processor info\nQc2A - msquic.sys   - QUIC Platform generic\nQc2B - msquic.sys   - QUIC Platform datapath\nQc2C - msquic.sys   - QUIC Platform datapath binding\nQc2D - msquic.sys   - QUIC Platform storage\nQc2E - msquic.sys   - QUIC Platform hashtable\nQc2F - msquic.sys   - QUIC Platform hashtable member lists\nQc30 - msquic.sys   - QUIC Lookup Hash Table\nQc31 - msquic.sys   - QUIC Remote Hash Entry\nQc32 - msquic.sys   - QUIC Server Name\nQc33 - msquic.sys   - QUIC App Resumption Data\nQc34 - msquic.sys   - QUIC Initial Token\nQc35 - msquic.sys   - QUIC Close Reason\nQc36 - msquic.sys   - QUIC Crypto Server Ticket Buffer\nQc37 - msquic.sys   - QUIC Crypto Client Ticket Buffer\nQc38 - msquic.sys   - QUIC Crypto Resumption Ticket\nQc39 - msquic.sys   - QUIC Tls Buffer\nQc3A - msquic.sys   - QUIC Send Request\nQc3B - msquic.sys   - QUIC API Context\nQc3C - msquic.sys   - QUIC Stateless Context\nQc3D - msquic.sys   - QUIC Operation\nQc3E - msquic.sys   - QUIC Event\n\nQuU2 - mpsdrv.sys   - MPSDRV upcall response\n\nRAWb - nt!RAW       - RAW file system buffer\n\nRa12 - storport.sys - INQUIRY_TAG\nRaAM - storport.sys - MAPPED_ADDRESS_TAG\nRaCD - storport.sys - CRASHDUMP_TAG\nRaCT - storport.sys - CONCURRENT_TOKEN_TAG\nRaDI - storport.sys - ID_TAG\nRaDf - storport.sys - DEFERRED_ITEM_TAG\nRaDS - storport.sys - STRING_TAG\nRaDR - storport.sys - DEVICE_RELATIONS_TAG\nRaDr - storport.sys - DPC_REDIRECTION_TAG\nRaHI - storport.sys - HWINIT_TAG\nRaME - storport.sys - MINIPORT_EXT_TAG\nRaPC - storport.sys - PORTCFG_TAG\nRaPD - storport.sys - PORT_DATA_TAG\nRaPL - storport.sys - PENDING_LIST_TAG\nRaQT - storport.sys - QUERY_TEXT_TAG\nRaRm - storport.sys - REMLOCK_TAG\nRaRL - storport.sys - RESOURCE_LIST_TAG\nRaSr - storport.sys - SRB_TAG\nRaSE - storport.sys - SRB_EXTENSION_TAG\nRaTM - storport.sys - TAG_MAP_TAG\nRaXr - storport.sys - XRB_TAG\nRaUE - storport.sys - UNIT_EXT_TAG\nRaSN - storport.sys - SENSE_TAG\nRaMW - storport.sys - WMI_EVENT_TAG\nRaRl - storport.sys - REPORT_LUNS_TAG\nRaSI - storport.sys - SENSE_INFO_TAG\nRaSR - storport.sys - RESOURCE_TAG\nRaAE - storport.sys - ADAPTER_EXT_TAG\nRaVM - storport.sys - VM_BUSES_TAG\nRaTS - storport.sys - TARGET_RESCAN_TAG\nRaWI - storport.sys - WORK_ITEM_TAG\nRaAT - storport.sys - ADDITIONAL_TIMER_TAG\nRaPO - storport.sys - POFX_TAG\nRaPW - storport.sys - POWER_TAG\nRaIB - storport.sys - IRP_BUFFER_TAG\nRaPQ - storport.sys - PENDING_QUEUE_TAG\nRaTe - storport.sys - TELEMETRY_TAG\nRaSH - storport.sys - SHIM_TAG\nRaCE - storport.sys - COMMAND_EFFECTS_TAG\nRaCT - storport.sys - PORT_CONTEXT_TAG\nRaUL - storport.sys - UNIT_LIST_TAG\nRaZR - storport.sys - ZONE_IO_GROUP_TAG\nRaCr - storport.sys - CRYPTO_TAG\nRaET - storport.sys - ETW_TAG\nRaST - storport.sys - SMART_TAG\nRaRW - storport.sys - REGISTRY_WATCH_TAG\nRaWH - storport.sys - WHEA_TAG\nRaNP - storport.sys - NPEM_TAG\nRaOP - storport.sys - OPERATION_TAG\nRaAC - storport.sys - ACPI_TAG\nRaDQ - storport.sys - DFX_QUEUE_TAG\nRaGA - storport.sys - GATEWAY_TAG\nRaCI - storport.sys - NVME_CTRL_IDENTIFY_TAG\nRaNI - storport.sys - NVME_NS_IDENTIFY_TAG\nRaNC - storport.sys - NVME_CONFIG_TAG\nRaEt - storport.sys - ENUM_TAG\nRaMF - storport.sys - MFND_TAG\nRaRE - storport.sys - RESET_TAG\nRaTC - storport.sys - TCG_TAG\n\nRaDA - tcpip.sys    - Raw Socket Discretionary ACLs\nRaEW - tcpip.sys    - Raw Socket Endpoint Work Queue Contexts\nRaMI - tcpip.sys    - Raw Socket Message Indication Tags\nRaPM - tcpip.sys    - Raw Socket Partial Memory Descriptor List Tag\nRaSM - tcpip.sys    - Raw Socket Send Messages Requests\nRaSL - tcpip.sys    - Raw Socket Send Message Lists\nRawE - tcpip.sys    - Raw Socket Endpoints\nRawN - tcpip.sys    - Raw Socket Nsi\n\nRB?? - <unknown>    - RedBook Filter Driver, static allocations\nRBEv - <unknown>    - RedBook - Thread Events\nRBRl - <unknown>    - RedBook - Remove lock\nRBRg - <unknown>    - RedBook - driverExtension->RegistryPath\nRBSe - <unknown>    - RedBook - Serialization tracking for checked builds\nRBWa - <unknown>    - RedBook - Wait block for system thread\n\nrb?? - <unknown>    - RedBook Filter Driver, dynamic allocations\nrbBu - <unknown>    - RedBook - Buffer for read/stream\nrbIr - <unknown>    - RedBook - Irp for read/stream\nrbIp - <unknown>    - RedBook - Irp pointer block\nrbMd - <unknown>    - RedBook - Mdl for read/stream\nrbMp - <unknown>    - RedBook - Mdl pointer block\nrbRc - <unknown>    - RedBook - Read completion context\nrbRx - <unknown>    - RedBook - Read Xtra info\nrbSc - <unknown>    - RedBook - Stream completion context\nrbSx - <unknown>    - RedBook - Stream Xtra info\nrbTo - <unknown>    - RedBook - Cached table of contents\n\nRcp? - sacdrv.sys - SAC Driver (Headless)\nRcpA - sacdrv.sys -     Internal memory mgr alloc block\nRcpI - sacdrv.sys -     Internal memory mgr initial heap block\nRcpS - sacdrv.sys -     Security related block\n\nRDPD - rdpdr.sys - Device list object\n\nReEv - <unknown>    - Resource Event\nReSe - <unknown>    - Resource Semaphore\nReTa - <unknown>    - Resource Extended Table\nReTr - <unknown>    - Per ETHREAD EXECUTIVE Resource tracking.\n\nREM ReFS Specific allocation tags\nReAR - refs.sys     -     Refs Async Cached Read allocation\nReai - refs.sys     -     RefsInsertStreamAttributeLookasideList\nRef0 - refs.sys     -     General pool allocation\nRef9 - refs.sys     -     Large Temporary Buffer\nRefB - refs.sys     -     RefsGetSfioReservation\nRefb - refs.sys     -     RESERVE_POOL_TAG\nRefC - refs.sys     -     CCB\nRefc - refs.sys     -     CCB_DATA\nRefd - refs.sys     -     DEALLOCATED_CLUSTERS\nRefD - refs.sys     -     DEALLOCATED_RECORDS\nRefE - refs.sys     -     INDEX_CONTEXT\nReff - refs.sys     -     FCB_DATA\nRefF - refs.sys     -     FCB_INDEX\nRefI - refs.sys     -     IO_CONTEXT\nRefi - refs.sys     -     IRP_CONTEXT\nRefK - refs.sys     -     KEVENT\nRefk - refs.sys     -     FILE_LOCK\nRefl - refs.sys     -     LCB\nReFm - refs.sys     -     MAP_CONTEXT RefsMapContextLookasideList\nRefN - refs.sys     -     NUKEM\nRefn - refs.sys     -     SCB_NONPAGED\nRefo - refs.sys     -     SCB_INDEX normalized named buffer\nRefp - refs.sys     -     COMPRESSION_CONTEXT RefsCompressCtxLookasideList\nRefq - refs.sys     -     General Allocation with Quota\nRefR - refs.sys     -     READ_AHEAD_THREAD\nRefr - refs.sys     -     ERESOURCE\nRefS - refs.sys     -     SCB_INDEX\nRefs - refs.sys     -     SCB_DATA\nRefH - refs.sys     -     SCB_SNAPSHOT\nReft - refs.sys     -     SCB (Prerestart)\nRefu - refs.sys     -     NTFS_MARK_UNUSED_CONTEXT\nRefV - refs.sys     -     VPB\nRefv - refs.sys     -     COMPRESSION_SYNC\nRefw - refs.sys     -     Workspace\nRefx - refs.sys     -     General Allocation\nRef? - refs.sys     -     Unkown allocation\nReIO - refs.sys     -     ReFS IO perf\nRers - refs.sys     -     ROLLBACK_STRUCT RefsRollbackStructLookasideList\nReTc - refs.sys     -     FILE_LEVEL_TRIM_CONTEXT\nReTm - refs.sys     -     DEVICE_MANAGE_DATA_SET_ATTRIBUTES RefsDeviceManageDataSetAttributesLookasideList\nReTo - refs.sys     -     DEVICE_MANAGE_DATA_SET_ATTRIBUTES RefsFileOffloadLookasideList\nReTe - refs.sys     -     ReFS Telemetry\nRedf - refs.sys     -     REFS_DISK_FLUSH_CONTEXT allocations\nReF_ - refs.sys     -     FILE_REFERENCE in RefsInsertDebugInfoIrpImplementation\nReFT - refs.sys     -     Stack trace\nReRc - refs.sys     -     Read copy context\nRKsr - refs.sys     -     REFS_KSR_POOLTAG\n\nREM ReFS tags based on source module\nReFa - refs.sys     -     AllocSup.c\nReFA - refs.sys     -     AttrHelpers.c\nReFC - refs.sys     -     Create.c\nReFD - refs.sys     -     DevioSup.c\nReFd - refs.sys     -     DirCtrl.c\nReFE - refs.sys     -     Ea.c\nReFF - refs.sys     -     FileInfo.c\nReFf - refs.sys     -     FsCtrl.c\nReFH - refs.sys     -     SelfHeal.c\nRefJ - refs.sys     -     NtfsInit.c\nReFL - refs.sys     -     TransSup.c\nReFN - refs.sys     -     NtfsData.c\nReFP - refs.sys     -     ReparSup.c\nReFS - refs.sys     -     SecurSup.c\nReFs - refs.sys     -     StrucSup.c\nReFU - refs.sys     -     usnsup.c\nReFV - refs.sys     -     VerfySup.c\nReFv - refs.sys     -     ViewSup.c\nReFW - refs.sys     -     Write.c\nReMo - refs.sys     -     Mount.c\nReF? - refs.sys     -     Unknown ReFS source module\n\nRefT - <unknown>    - Bluetooth reference tracking\nRf?? - <unknown>    - Bluetooth RFCOMM TDI driver\nRfAD - rfcomm.sys   -   RFCOMM Address\nRfBB - rfcomm.sys   -   RFCOMM BRB\nRfBT - rfcomm.sys   -   RFCOMM (bthport)\nRfCB - rfcomm.sys   -   RCOMMM\nRfCH - rfcomm.sys   -   RFCOMM channel\nRfCN - rfcomm.sys   -   RFCOMM connect\nRfDA - rfcomm.sys   -   RFCOMM data\nRfFR - rfcomm.sys   -   RFCOMM frame\nRfRX - rfcomm.sys   -   RFCOMM receive\nRfPP - rfcomm.sys   -   RFCOMM pnp\nRfWR - rfcomm.sys   -   RFCOMM worker\n\nRhHi - tcpip.sys    - Reference History Pool\n\nRind - tcpip.sys    - Raw Socket Receive Indications\n\nRKRW - mpsdrv.sys   - MPSDRV work item\nRTLF - mpsdrv.sys   - MPSDRV filter\n\nRLli - FsLib        - FsLib Nonopaque Range lock entry\nRLin - FsLib        - FsLib Range lock entry\nRtrc - FsLib        - FsLib Allocations in RangeTrack.c\n\nRmPt - netio.sys    - Rtl Mapping Page Table Entries\n\nRnm  - rndismp.sys  - RNDIS MP driver generic alloc\nRnms - rndismp.sys  - RNDIS MP driver send frame\nRnmr - rndismp.sys  - RNDIS MP driver receive frame\nRnmt - rndismp.sys  - RNDIS MP driver timer\n\nRpcL - msrpc.sys    - debugging log data - present on checked builds only\nRpcM - msrpc.sys    - all msrpc.sys allocations not covered elsewhere\nRpcr - msrpc.sys    - not currently used\n\nRRle - <unknown>    - RTL_RANGE_LIST_ENTRY_TAG\nRRlm - <unknown>    - RTL_RANGE_LIST_MISC_TAG\n\nRtPi - <unknown>    - Temp allocation for product type key\n\nRpcl - msrpc.sys    - MSRpc memory logging - checked build only\nRpcm - msrpc.sys    - MSRpc memory allocations\nRpcr - msrpc.sys    - MSRpc resources\nRpcs - msrpc.sys    - Memory shared b/n MSRpc and caller\n\nRPrt - rstorprt.sys - Remote Storage Port Driver\n\nRqrv - <unknown>    - Registry query buffer\nRS?? - <unknown>    - Remote Storage\nRSFS - <unknown>    -      Recall Queue\nRSFN - <unknown>    -      File Name\nRSSE - <unknown>    -      Security info\nRSWQ - <unknown>    -      Work Queue\nRSQI - <unknown>    -      Queue info\nRSLT - <unknown>    -      Long term data\nRSIO - <unknown>    -      Ioctl Queue\nRSFO - <unknown>    -      File Obj queue\nRSVO - <unknown>    -      Validate Queue\nRSER - <unknown>    -      Error log data\n\nRtlT - nt!rtl       - Temporary RTL allocation\n\nRWan - rawwan.sys   - Raw WAN driver\n\nR300 - <unknown>    - ATI video driver\nRX00 - <unknown>    - ATI video driver\n\nRx?? - rdbss.sys - RDBSS allocations\nRxSc - rdbss.sys - RDBSS SrvCall\nRxNr - rdbss.sys - RDBSS NetRoot\nRxVn - rdbss.sys - RDBSS VNetRoot\nRxLv - rdbss.sys - RDBSS Logical View\nRxFc - rdbss.sys - RDBSS FCB\nRxSo - rdbss.sys - RDBSS SrvOpen\nRxFx - rdbss.sys - RDBSS fobx\nRxNf - rdbss.sys - RDBSS non paged FCB\nRxWq - rdbss.sys - RDBSS work queue\nRxBm - rdbss.sys - RDBSS buffering manager\nRxCo - rdbss.sys - RDBSS construction context\nRxMs - rdbss.sys - RDBSS miscellaneous\nRxM1 - rdbss.sys - RDBSS VNetRoot name\nRxM2 - rdbss.sys - RDBSS canonical name\nRxM3 - rdbss.sys - RDBSS querypath name\nRxM4 - rdbss.sys - RDBSS treeconnect name\nRxM5 - rdbss.sys - RDBSS reparse buffer name\nRxM9 - rdbss.sys - RDBSS cloned unicode string\nRxIr - rdbss.sys - RDBSS RxContext\nRxTl - rdbss.sys - RDBSS toplevel IRP\nRxMx - rdbss.sys - RDBSS mini-rdr\nRxNc - rdbss.sys - RDBSS name cache\nRxSy - rdbss.sys - RDBSS symlink\nRxCr - rdbss.sys - RDBSS credential\nRxEc - rdbss.sys - RDBSS ECP\n\nRxCt - mrxsmb.sys - RXCE transport\nRxCa - mrxsmb.sys - RXCE address\nRxCc - mrxsmb.sys - RXCE connection\nRxCv - mrxsmb.sys - RXCE VcEndpoint\nRxCd - mrxsmb.sys - RXCE TDI\n\nS3   - <unknown>    - S3 video driver\nSAad - srvnet.sys   - SrvAdmin buffer\nSBad - <unknown>    - bad block simulator - simbad.c\n\nsbp2 - <unknown>    - Sbp2 1394 storage port driver\n\nSC?? - <unknown>    - Smart card driver tags\nSCLb - <unknown>    -  Smart card driver library\nSCB8 - <unknown>    -  Bull CP8 Transac serial reader\nSCB3 - <unknown>    -  Bull SmarTlp PnP\nSCS4 - <unknown>    -  SCM Microsystems pcmcia reader\nSCl0 - <unknown>    -  Litronic 220\n\nSc?? - <unknown>    - Mass storage driver tags\n\nScB? - classpnp.sys - ClassPnP misc allocations\nScB1 - classpnp.sys -  Query registry parameters\nScB2 - classpnp.sys -  Registry path\nScB4 - classpnp.sys -  Storage descriptor header\nScB5 - classpnp.sys -  FDO relations\nScC? - classpnp.sys - ClassPnP misc allocations\nScC1 - classpnp.sys -  Registry path buffer\nScC2 - classpnp.sys -  PDO relations\nScC6 - classpnp.sys -  START_UNIT completion context\nScC7 - classpnp.sys -  Sense info buffer\nScC8 - classpnp.sys -  Registry value name\nScC9 - classpnp.sys -  Device Control SRB\n\n\n\nScC? - cdrom.sys    -  CdRom\nScCA - cdrom.sys    -      Autorun disable functionality\nScCa - cdrom.sys    -      Media change detection\nScSB - cdrom.sys    -      Scratch buffer (usually 64k)\nScCC - cdrom.sys    -      Ioctl GET_CONFIGURATION\nScCc - cdrom.sys    -      Context of completion routine\nScCD - cdrom.sys    -      Adaptor & Device descriptor buffer\nScCd - cdrom.sys    -      Disc information\nScCe - cdrom.sys    -      Request sync event\nScCF - cdrom.sys    -      Feature descriptor\nScCG - cdrom.sys    -      GESN buffer\nScCI - cdrom.sys    -      Sense info buffers\nScCi - cdrom.sys    -      Cached inquiry buffer\nScCM - cdrom.sys    -      Mode data buffer\nSCCO - cdrom.sys    -      Set stream buffer\nScCo - cdrom.sys    -      Device Notification buffer\nScCp - cdrom.sys    -      Play active checks\nScCr - cdrom.sys    -      Registry string\nScCS - cdrom.sys    -      Srb allocation\nScCs - cdrom.sys    -      Assorted string data\nScCU - cdrom.sys    -      Update capacity path\nScCu - cdrom.sys    -      Read buffer for dvd key\nScCV - cdrom.sys    -      Read buffer for dvd/rpc2 check\nScCv - cdrom.sys    -      Read buffer for rpc2 check\nScCX - cdrom.sys    -      Security descriptor\n\nScD? - <unknown>    -   Disk\nScD  - <unknown>    -      generic tag\nScDa - <unknown>    -      SMART\nScDA - <unknown>    -      Info Exceptions\nScDC - <unknown>    -      disable cache paths\nScDb - classpnp.sys -      ClassPnP debug globals buffer\nScDc - <unknown>    -      disk allocated completion c\nScDG - <unknown>    -      disk geometry buffer\nScDg - <unknown>    -      update disk geometry paths\nScDI - <unknown>    -      sense info buffers\nScDp - <unknown>    -      pnp ids\nScDM - <unknown>    -      mode data buffer\nScDM - <unknown>    -      mbr checksum code\nScDN - <unknown>    -      disk name code\nScDP - <unknown>    -      read capacity buffer\nScDp - <unknown>    -      disk partition lists\nScDS - <unknown>    -      srb allocation\nScDs - <unknown>    -      start device paths\nScDU - <unknown>    -      update capacity path\nScDW - <unknown>    -      work-item context\nScMC - <unknown>    -      medium changer allocations\n\nScIO - classpnp.sys - ClassPnP device control\nScL? - classpnp.sys -   Classpnp\nScLA - classpnp.sys -      allocation to check for autorun disable\nScLF - classpnp.sys -      File Object Extension\nScLc - classpnp.sys -      Cache filters\nScLf - classpnp.sys -      Fault prediction\nScLm - classpnp.sys -      Mount\nScLM - classpnp.sys -      Media Change Detection\nScLq - classpnp.sys -      Release queue\nScLw - classpnp.sys -      WMI\nScLW - classpnp.sys -      Power\n\nScNo - classpnp.sys - ClassPnP notification\n\nScP? - <unknown>    -   Scsiport\nScPa - <unknown>    -      Hold registry data\nScPA - <unknown>    -      Access Ranges\nScPb - <unknown>    -      Get Bus Dat Holder\nScPB - <unknown>    -      Queuetag BitMap\nScPc - <unknown>    -      Fake common buffer\nScPC - <unknown>    -      reset bus code\nScPd - <unknown>    -      Pnp id strings\nScPD - <unknown>    -      SRB_DATA allocations\nScPE - <unknown>    -      Scatter gather lists\nScPG - <unknown>    -      Global memory\nScPh - <unknown>    -      HwDevice Ext\nScPi - <unknown>    -      Sense Info\nScPI - <unknown>    -      Init data chain\nScPl - <unknown>    -      remove lock tracking\nScPL - <unknown>    -      scatter gather lists\nScPm - <unknown>    -      address mapping lists\nScPM - <unknown>    -      scatter gather lists\nScPp - <unknown>    -      device & adapter enable\nScpP - <unknown>    -      scsi PortConfig copies\nScPq - <unknown>    -      inquiry data\nScPQ - <unknown>    -      request sense\nScPr - <unknown>    -      resource list copy\nScPS - <unknown>    -      registry allocations\nScPt - <unknown>    -      legacy request rerouting\nScPT - <unknown>    -      interface mapping\nScPu - <unknown>    -      device relation structs\nScPv - <unknown>    -      KEVENT\nScPV - <unknown>    -      Device map allocations\nScPw - <unknown>    -      Wmi Events\nScPW - <unknown>    -      Wmi Requests\nScPx - <unknown>    -      Report Luns\nScPY - <unknown>    -      Report Targets\nScPZ - <unknown>    -      Device name buffer\n\nScR? - <unknown>    -   Partition Manager\nScRi - <unknown>    -      IOCTL buffer\nScRp - <unknown>    -      Partition entry\nScRr - <unknown>    -      Remove lock\nScRt - <unknown>    -      Table entry\nScRv - <unknown>    -      Dependant volume relations lists\nScRV - <unknown>    -      Volume entry\nScRw - <unknown>    -      Power mgmt private work item\n\nScS2 - classpnp.sys - Sense interpretation data\n\nScsC - <unknown>    - non-pnp SCSI CdRom\nScsD - <unknown>    - non-pnp SCSI Disk\nScsH - <unknown>    - non-pnp SCSI from class.h (class2)\nScsI - <unknown>    - non-pnp SCSI port internal\nScsL - <unknown>    - non-pnp SCSI class.c driver allocations\nScsP - <unknown>    - non-pnp SCSI port.c\nScs$ - <unknown>    - Tag for pnp class driver's SRB lookaside list\n\nScUn - <unknown>    - Default Tag for pnp class driver allocations\n\nScV? - <unknown>    -  Dvd functionality in cdrom.sys\nScVk - <unknown>    -      read buffer for DVD keys\nScVK - <unknown>    -      write buffer for DVD keys\nScVS - <unknown>    -      buffer for reads of DVD on-disk structures\n\nScWs - classpnp.sys - Working set\n\nSdCc - <unknown>    - ObsSecurityDescriptorCache / SECURITY_DESCRIPTOR_CACHE_ENTRIES\n\nSdba - <unknown>    - Application compatibility Sdb* allocations\n\nSdp? - <unknown>    - Bluetooth SDP functionality in BTHPORT.sys\nSdpC - bthport.sys  -     Bluetooth SDP client connection\nSdpD - bthport.sys  -     Bluetooth SDP database\nSdpI - bthport.sys  -     Bluetooth port driver (SDP)\n\nSD   - smbdirect.sys - SMB Direct allocations\nSDa  - smbdirect.sys - SMB Direct socket objects\nSDb  - smbdirect.sys - SMB Direct adapter objects\nSDc  - smbdirect.sys - SMB Direct MR buffers\nSDd  - smbdirect.sys - SMB Direct connect event contexts\nSDe  - smbdirect.sys - SMB Direct large receive buffers\nSDf  - smbdirect.sys - SMB Direct LAM objects\nSDg  - smbdirect.sys - SMB Direct data transfer packet buffers\nSDh  - smbdirect.sys - SMB Direct FRMR objects\nSDi  - smbdirect.sys - SMB Direct buffer registrations\nSDj  - smbdirect.sys - SMB Direct SQ work requests\nSDk  - smbdirect.sys - SMB Direct operation\n\nSe   - nt!se        - General security allocations\nSeAc - nt!se        - Security ACL\nSeAi - nt!se        - Security Audit Work Item\nSeAk - nt!se        - Security Account Name\nSeAo - nt!se        - Security Attributes and Operations\nSeAp - nt!se        - Security Audit Parameter Record\nSeAt - nt!se        - Security Attributes\nSeCL - nt!se        - Security CONTEXT_TAG\nSeDb - nt!se        - Temp directory query buffer to delete logon session symbolic links\nSeDt - nt!se        - Security Global Singleton attributes table\nSeFS - nt!se        - Security File System Notify Context\nSeGa - nt!se        - Granted Access allocations\nSeHa - nt!se        - Security Handle Array\nSeHn - nt!se        - AppContainer Handles\nSeIf - nt!se        - Security Image Filename\nSeLa - nt!se        - Security Learning Mode ACLs\nSeLs - nt!se        - Security Logon Session\nSeLu - nt!se        - Security LUID and Attributes array\nSeLS - nt!se        - Security Logon Session tracking array\nSeLw - nt!se        - Security LSA Work Item\nSeOI - nt!se        - Security Learning Mode Object Information\nSeOn - nt!se        - Security Captured Object Name information\nSeON - nt!se        - Security Learning Mode Object Name\nSeOp - nt!se        - Security Operation\nSeOT - nt!se        - Security Learning Mode Object Type\nSeOt - nt!se        - Captured object type array, used by access check\nSePa - nt!se        - Process audit image names and captured policy structures\nSePh - nt!se        - Dummy image page hash structure, used when CI is disabled\nSePr - nt!se        - Security Privilege Set\nSeRO - nt!se        - Learning Mode Root Object\nSeSA - nt!se        - Security CAPE Staged Access Array\nSeSa - nt!se        - Security SID and Attributes\nSeSb - nt!se        - Security Secure Boot\nSeSc - nt!se        - Captured Security Descriptor\nSeSd - nt!se        - Security Descriptor\nSeSi - nt!se        - Security SID\nSeSp - nt!se        - Scoped Policy\nSeSs - nt!se        - Shared Sids\nSeSv - nt!se        - Security SID values block\nSeTa - nt!se        - Security Temporary Array\nSeTd - nt!se        - Security Token dynamic part\nSeTI - ksecdd.sys   - Security TargetInfo\nSeTl - nt!se        - Security Token Lock\nSeTn - nt!se        - Security Captured Type Name information\nSeUs - nt!se        - Security Captured Unicode string\n\nSect - <unknown>    - Section objects\nSema - <unknown>    - Semaphore objects\nSenm - <unknown>    - Serenum (RS-232 serial bus enumerator)\nSimB - <unknown>    - Simbad (bad sector simulation driver) allocations\nSIfs - <unknown>    - Default tag for user's of ntsrv.h\nsidg - <unknown>    - GDI spooler events\nSis  - <unknown>    - Single Instance Store (dd\\sis\\filter)\nSisB - <unknown>    -         SIS per file object break event\nSisC - <unknown>    -         SIS common store file object\nSisF - <unknown>    -         SIS per file object\nSisL - <unknown>    -         SIS per link object\nSisS - <unknown>    -         SIS SCB\nSetp - <unknown>    - SETUPDD SpMemAlloc calls\n\nSMgk - vmsharedmemoryguestkernel.lib     - Virtual Machine Shared Memory Kernel Mode Guest Library\nSMhk - vmsharedmemoryhostkernel.lib      - Virtual Machine Shared Memory Kernel Mode Host Library\n\nSRdm - scsirdma.sys - Infiniband SRP driver\n\nStCc - netio.sys    - WFP stream inspection call context\nStDa - netio.sys    - WFP stream inspection data\nStFc - netio.sys    - WFP stream filter conditions\nStCx - netio.sys    - WFP stream internal callout context\nStdq - netio.sys    - WFP stream DPC queue\n\nSV?? - <unknown>       - Synthetic Video Driver\n\nSVXD - synvidxd.dll    - WDDM Synthetic Video Display Driver\nSVXM - synvidxm.sys    - WDDM Synthetic Video Miniport Driver\nSVid - synthvid.sys    - LDDM Synthetic Video Miniport Driver\n\nSW?? - <unknown>    - Software Bus Enumerator\nSWbi - <unknown>    -         bus ID\nSWbr - <unknown>    -         bus reference\nSWda - <unknown>    -         POOLTAG_DEVICE_ASSOCIATION\nSWdn - <unknown>    -         device name\nSWdr - <unknown>    -         device reference\nSWdr - <unknown>    -         POOLTAG_DEVICE_DRIVER_REGISTRY\nSWfd - <unknown>    -         POOLTAG_DEVICE_FDOEXTENSION\nSWid - <unknown>    -         device ID\nSWii - <unknown>    -         instance ID\nSWip - <unknown>    -         POOLTAG_DEVICE_INTERFACEPATH\nSWki - <unknown>    -         key information\nSWpd - <unknown>    -         POOLTAG_DEVICE_PDOEXTENSION\nSWre - <unknown>    -         relations\nSWrp - <unknown>    -         reparse string\nSWrs - <unknown>    -         reference string\n\nSm?? - mrxsmb.sys    - SMB miniredirector allocations\nSmCe - mrxsmb.sys    - SMB connection object\nSmXc - mrxsmb.sys    - SMB exchange\nSmBf - mrxsmb.sys    - SMB exchange buffer\nSmKy - mrxsmb.sys    - SMB compounding key\nSmMs - mrxsmb.sys    - SMB miscellaneous\nSmTp - mrxsmb.sys    - SMB transport\nSmVc - mrxsmb.sys    - SMB VC endpoint\nSmDg - mrxsmb.sys    - SMB datagram endpoint\nSmWi - mrxsmb.sys    - SMB sequence window\nSmFi - mrxsmb.sys    - SMB file\nSmTh - mrxsmb.sys    - SMB thunk\nSmSh - mrxsmb.sys    - SMB shadow file (fast loopback)\nSmTd - mrxsmb.sys    - SMB TDI notify\nSmDc - mrxsmb.sys    - SMB directory cache\n\n\nSmMm - mrxsmb.sys   -         SMB mm allocated structures.\nSmAd - mrxsmb10.sys    -      SMB1 session setup/admin exchange\nSmRw - mrxsmb10.sys    -      SMB1 read/write path\nSmTr - mrxsmb10.sys    -      SMB1 transact exchange\nSmRb - mrxsmb10.sys    -      SMB1 remote boot\n\nSmFc - mrxsmb10.sys    -      SMB1   fsctl structures  (special build only)\nSmDc - mrxsmb10.sys    -      SMB1   dir query buffer (special build only)\nSmPi - mrxsmb10.sys    -      SMB1   pipeinfo buffer (special build only)\nSmDO - mrxsmb10.sys    -      SMB1   deferred open context  (special build only)\nSmQP - mrxsmb10.sys    -      SMB1   params for directory query transact  (special build only)\n\nSmVr - mrxsmb10.sys    -      SMB1   VNetroot  (special build only)\nSmSr - mrxsmb10.sys    -      SMB1   Server  (special build only)\nSmSe - mrxsmb10.sys    -      SMB1   Session  (special build only)\nSmNr - mrxsmb10.sys    -      SMB1   NetRoot  (special build only)\nSmMa - mrxsmb10.sys    -      SMB1   mid atlas  (special build only)\nSmMt - mrxsmb10.sys    -      SMB1   mailslot buffer  (special build only)\nSmEc - mrxsmb10.sys    -      SMB1   echo buffer  (special build only)\nSmKs - mrxsmb10.sys    -      SMB1  Kerberos blob  (special build only)\n\nsm?? - nt!store or rdyboost.sys - ReadyBoost allocations\nsmCR - nt!store or rdyboost.sys - ReadyBoost encryption allocation\nsmMD - nt!store or rdyboost.sys - ReadyBoost store stats MDL\nsmWi - nt!store or rdyboost.sys - ReadyBoost various work items\nsmSt - nt!store or rdyboost.sys - ReadyBoost various store allocations\nsmBt - nt!store or rdyboost.sys - ReadyBoost various B+Tree allocations\nsmXt - nt!store or rdyboost.sys - ReadyBoost store extents array\nsmAr - nt!store or rdyboost.sys - ReadyBoost generic array allocation\nsmIt - nt!store or rdyboost.sys - ReadyBoost store ETA timers\nsmRg - nt!store or rdyboost.sys - ReadyBoost in-memory store region array\nsmET - nt!store or rdyboost.sys - ReadyBoost ETA check work item\nsmWd - nt!store or rdyboost.sys - ReadyBoost store contents rundown work item\nsmNp - nt!store or rdyboost.sys - ReadyBoost store node pool allocations\nsmDt - nt!store or rdyboost.sys - ReadyBoost store debug trace buffer\nsmDa - nt!store     -         ReadyBoost cache file DACL\nsmDS - nt!store     -         ReadyBoost cache file SID\nsmLb - nt!store     -         ReadyBoost virtual store manager log buffer\nsmCa - nt!store     -         ReadyBoost cache\nsmEK - nt!store     -         ReadyBoost encryption key\nsmEd - nt!store     -         ReadyBoost virtual store manager key descriptor allocation for logging\nsmAc - nt!store     -         ReadyBoost device arrival context\nsmFh - nt!store     -         ReadyBoost cache file header\nsmFp - nt!store     -         ReadyBoost virtual forward progress entry\nsmR? - nt!store     -         ReadyBoost virtual forward progress resources\nsmKG - nt!store     -         ReadyBoost encryption key registry path buffer\nsmms - nt!store     -         ReadyBoost virtual store memory monitor context\nsmCr - nt!store     -         ReadyBoost store region bitmap\nsmMd - rdyboost.sys -         ReadyBoost MDL allocation\nsmMb - rdyboost.sys -         ReadyBoost MDL buffer\nsmBP - rdyboost.sys -         ReadyBoot boot plan buffer\nsmBD - rdyboost.sys -         ReadyBoot decompressed boot plan buffer\nsmBX - rdyboost.sys -         ReadyBoot boot plan decompression workspace buffer\nsmMR - rdyboost.sys -         ReadyBoot multi-read ranges\nsmRW - rdyboost.sys -         ReadyBoot read-after-write ranges\nsmPr - rdyboost.sys -         ReadyBoot population ranges\nsmPi - rdyboost.sys -         ReadyBoot population ranges index\nsmPl - rdyboost.sys -         ReadyBoot pended IRP lists\nsmRT - rdyboost.sys -         ReadyBoot thread params\nsmTi - rdyboost.sys -         ReadyBoost debug IO trace buffer\nsmPc - rdyboost.sys -         ReadyBoost persist log context\nsmPb - rdyboost.sys -         ReadyBoost persist log buffer\nsmPm - rdyboost.sys -         ReadyBoost persist partial MDL buffer\nsmBR - rdyboost.sys -         ReadyBoost volume ranges array\nsmBr - rdyboost.sys -         ReadyBoost volume range\nsmVc - rdyboost.sys -         ReadyBoost read verification buffer\nsmHB - rdyboost.sys -         ReadyBoost Hybrid Drive command buffer\n\nSPX  - <unknown>    - Nwlnkspx transport\nSQOS - <unknown>    - Security quality of service in IO\n\nSpXX - spaceport.sys -          Spaceport generic\nSpXl - spaceport.sys -          Spaceport log\nSpXp - spaceport.sys -          Spaceport parity context\nSpXr - spaceport.sys -          spaceport repair\nSpXs - spaceport.sys -          spaceport parity schedule\nSpXb - spaceport.sys -          spaceport slab\nSpXa - spaceport.sys -          spaceport sparse array\nSpIc - spaceport.sys -          spaceport IO cache\nSpIl - spaceport.sys -          spaceport IO column\nSpIC - spaceport.sys -          spaceport IO counters\nSpId - spaceport.sys -          spaceport IO raid\nSpIs - spaceport.sys -          spaceport IO space\nSpIt - spaceport.sys -          spaceport IO tier\nSpBc - spaceport.sys -          spaceport SDB column\nSpBd - spaceport.sys -          spaceport SDB drive\nSpBe - spaceport.sys -          spaceport SDB extent\nSpBm - spaceport.sys -          spaceport SDB metadata\nSpBt - spaceport.sys -          spaceport SDB path\nSpBp - spaceport.sys -          spaceport SDB pool\nSpBg - spaceport.sys -          spaceport SDB pool config\nSpBs - spaceport.sys -          spaceport SDB space\nSpBn - spaceport.sys -          spaceport SDB space config\nSpBr - spaceport.sys -          spaceport SDB record\nSpBi - spaceport.sys -          spaceport SDB tier\nSpSs - spaceport.sys -          spaceport store\nSpSk - spaceport.sys -          spaceport store block\nSpSb - spaceport.sys -          spaceport store buffer\nSpSc - spaceport.sys -          spaceport store cache\nSpSr - spaceport.sys -          spaceport store record\nSpAt - spaceport.sys -          spaceport attributes\nSpBf - spaceport.sys -          spaceport buffer\nSpPK - spaceport.sys -          spaceport custom packet\nSpDg - spaceport.sys -          spaceport destage context\nSpDr - spaceport.sys -          spaceport drive\nSpDd - spaceport.sys -          spaceport dump data\nSpEL - spaceport.sys -          spaceport enclosure\nSpLa - spaceport.sys -          spaceport lookaside\nSpMp - spaceport.sys -          spaceport mapping\nSpMl - spaceport.sys -          spaceport MDL\nSpPt - spaceport.sys -          spaceport path\nSpPl - spaceport.sys -          spaceport pool\nSpPm - spaceport.sys -          spaceport prm\nSpRg - spaceport.sys -          spaceport regen context\nSpWk - spaceport.sys -          spaceport work\n\n\nSr?? - sr.sys       - System Restore file system filter driver\nSrCo - sr.sys       -         SR's control object\nSrSC - sr.sys       -         Stream contexts\nSrDB - sr.sys       -         Debug information for lookup blob\nSrDL - sr.sys       -         Device list\nSrFE - sr.sys       -         File information buffer\nSrFN - sr.sys       -         File name\nSrHB - sr.sys       -         Hash bucket\nSrHH - sr.sys       -         Hash header\nSrHK - sr.sys       -         Hash key\nSrLB - sr.sys       -         Log buffer\nSrLC - sr.sys       -         Logging context\nSrLE - sr.sys       -         Log entry\nSrLT - sr.sys       -         Lookup blob\nSrMP - sr.sys       -         Mount point information\nSrOI - sr.sys       -         Overwrite information\nSrPC - sr.sys       -         Persistant configuration information\nSrRB - sr.sys       -         Rename buffer\nSrRG - sr.sys       -         Logger context\nSrRH - sr.sys       -         Reparse data size\nSrRR - sr.sys       -         Registry information\nSrSD - sr.sys       -         Security data information\nSrST - sr.sys       -         Stream data information\nSrTI - sr.sys       -         Directory delete information\nSrWI - sr.sys       -         Work queue item\n\nSslC - ksecdd.sys   - SSL kernel mode client allocations\n\nST*  - <unknown>    - New MMC compliant storage drivers\n\nStac - <unknown>    - Stack Trace Database - i386 checked and built with NTNOFPO=1 only\nStEl - storport.sys - PortpErrorInitRecords storport!_STORAGE_TRACE_CONTEXT_INTERNAL.ErrorLogRecords\nStrg - <unknown>    - Dynamic Translated strings\nStrm - <unknown>    - Streams and streams transports allocations\nStTc - storport.sys - PortTraceInitTracing storport!_STORAGE_TRACE_CONTEXT_INTERNAL\n\nsvx? - svhdxflt.sys - VHDX sharing among multiple Hyper-V guests\nsvxc - svhdxflt.sys -         CDB (SCSI) operations\nsvxC - svhdxflt.sys -         Create File processing\nsvxd - svhdxflt.sys -         SVHDX communications port\nsvxe - svhdxflt.sys -         Stored sense data errors\nsvxf - svhdxflt.sys -         File contexts\nsvxI - svhdxflt.sys -         Initiator lists\nsvxi - svhdxflt.sys -         Instance context\nsvxl - svhdxflt.sys -         Shared VHDX RTL\nsvxP - svhdxflt.sys -         Persistent Reservation - Registrations\nsvxp - svhdxflt.sys -         Persistent Reservation support for shared VHDX files\nsvxQ - svhdxflt.sys -         Persistent Reservation - Device context\nsvxq - svhdxflt.sys -         Persistent Reservation - Reservation Info\nsvxr - svhdxflt.sys -         File read operations\nsvxs - svhdxflt.sys -         Stream context\nsvxS - svhdxflt.sys -         Stream handle context\nsvxt - svhdxflt.sys -         Test Filter\nsvxv - svhdxflt.sys -         VHDMP/SVHDX interaction\nsvxw - svhdxflt.sys -         File write operations\n\nSwMi - <unknown>    - SWMidi KS filter (WDM Audio)\nSymb - <unknown>    - Symbolic link objects\nSymt - <unknown>    - Symbolic link target strings\n\nSYPK - syspart.lib  - Kernel mode system partition detection allocations\nSYSA - <unknown>    - Sysaudio (wdm audio)\n\nTAPI - <unknown>    - ntos\\ndis\\ndistapi\n\nTcAN - tcpip.sys    - TCPIP App Name\nTcAR - tcpip.sys    - TCP Abort Requests\nTcBW - tcpip.sys    - TCP Bandwidth Allocations\nTcCC - tcpip.sys    - TCP Create And Connect Tcb Pool\nTcCM - tcpip.sys    - TCP Congestion Control Manager Contexts\nTcCo - tcpip.sys    - TCP Compartment\nTcCR - tcpip.sys    - TCP Connect Requests\nTcCT - tcpip.sys    - TCP Connection Tuples\nTcDD - tcpip.sys    - TCP Debug Delivery Buffers\nTcDQ - tcpip.sys    - TCP Delay Queues\nTcDR - tcpip.sys    - TCP Disconnect Requests\nTcEW - tcpip.sys    - TCP Endpoint Work Queue Contexts\nTcFC - tcpip.sys    - TCP Fastopen Cookies\nTcFR - tcpip.sys    - TCP FineRTT Buffers\nTcHT - tcpip.sys    - TCP Hash Tables\nTcHo - tcpip.sys    - TCPIP Histogram\nTcIn - tcpip.sys    - TCP Inputs\nTcLS - tcpip.sys    - TCP Listener SockAddrs\nTcLW - tcpip.sys    - TCP Listener Work Queue Contexts\nTcpA - tcpip.sys    - TCP DMA buffers\nTcpB - tcpip.sys    - TCP Offload Blocks\nTcDM - tcpip.sys    - TCP Delayed Delivery Memory Descriptor Lists\nTcDN - tcpip.sys    - TCP Delayed Delivery Network Buffer Lists\nTcPC - tcpip.sys    - TCP Listener Pending Connections\nTcpE - tcpip.sys    - TCP Endpoints\nTTcb - tcpip.sys    - TCP Connections\nTcpI - tcpip.sys    - TCP ISN buffers\nTcpL - tcpip.sys    - TCP Listeners\nTcpM - tcpip.sys    - TCP Offload Miscellaneous buffers\nTcpN - tcpip.sys    - TCP Name Service Interfaces\nTcOD - tcpip.sys    - TCP Offload Devices\nTcpO - tcpip.sys    - TCP Offload Requests\nTcpP - tcpip.sys    - TCP Processor Arrays\nTcPt - tcpip.sys    - TCP Partitions\nTcpt - tcpip.sys    - TCP Timers\nTcRA - tcpip.sys    - TCP Reassembly Data\nTcRB - tcpip.sys    - TCP Reassembly Buffers\nTcRD - tcpip.sys    - TCP Receive DPC Data\nTcRe - tcpip.sys    - TCP Recovery Buffers\nTcRH - tcpip.sys    - TCP Reassembly Headers\nTcRL - tcpip.sys    - TCP Create And Connect Tcb Rate Limit Pool\nTcRN - tcpip.sys    - TCP Random Number Generator Pool\nTcRR - tcpip.sys    - TCP Receive Requests\nTcRW - tcpip.sys    - TCP Receive Window Tuning Blocks\nTcSa - tcpip.sys    - TCP Sack Data\nTcSR - tcpip.sys    - TCP Send Requests\nTcST - tcpip.sys    - TCP Syn TCBs\nTcTW - tcpip.sys    - TCP Time Wait TCBs\nTcUD - tcpip.sys    - TCP Urgent Delivery Buffers\nTcWQ - tcpip.sys    - TCP TCB Work Queue Contexts\nTcWS - tcpip.sys    - TCP Window Scaling Diagnostics\nTcRF - tcpip.sys    - TCP Recent Connection Failure\nTcTI - tcpip.sys    - TCP Traceroute Info\nTcSk - tcpip.sys    - TCP Send Tracker\nTcTx - tcpip.sys    - TCP Transmit\nTrLB - tcpip.sys    - TCP RLedbat\n\n\nTDIc - <unknown>    - TDI resource\nTDId - <unknown>    - TDI resource\nTDIe - <unknown>    - TDI resource\nTDIf - <unknown>    - TDI resource\nTDIg - <unknown>    - TDI resource\nTDIk - <unknown>    - TDI resource\nTDIu - <unknown>    - TDI resource\nTDIv - <unknown>    - TDI resource\n\nTdat - <unknown>    - NB Data\n\nTdxC - tdx.sys      - TDX Connections\nTdCI - tdx.sys      - TDX Connection Information\nTdxc - tdx.sys      - TDX Control Channels\nTdxo - tdx.sys      - TDX Device Objects\nTdx  - tdx.sys      - TDX Generic Buffers (Address, Entity information, Interface change allocations)\nTdxI - tdx.sys      - TDX IO Control Buffers\nTdxM - tdx.sys      - TDX Message Indication Buffers\nTdxn - tdx.sys      - TDX Net Addresses\nTdxR - tdx.sys      - TDX Received Data\nTdxp - tdx.sys      - TDX Reserved Page Tables Entries\nTdxB - tdx.sys      - TDX Transport Layer Buffers\nTdxt - tdx.sys      - TDX Transport Layer Clients\nTdxP - tdx.sys      - TDX Transport Layer Providers\nTdxm - tdx.sys      - TDX Transport Layer TDI Mappings\nTdxA - tdx.sys      - TDX Transport Addresses\nTdxT - tdx.sys      - TDX Transport Provider Contexts\n\nTedd - tcpip.sys    - TCP/IP Event Data Descriptors\n\nthdd - <unknown>    - DirectDraw/3D handle manager table\n\nThre - nt!ps        - Thread objects\nTime - nt!ke        - Timer objects\n\nTmDn - nt!tm        - Tm Dynamic Name\nTmEn - nt!tm        - Tm KENLISTMENT object\nTmLo - nt!tm        - Tm Log Entries\nTmNo - nt!tm        - Tm Notification\nTmPa - nt!tm        - Tm Propagate Argument\nTmPb - nt!tm        - Tm Propagation Buffer\nTmPe - nt!tm        - Tm Enlistment Pointers\nTmPi - nt!tm        - Tm Protocol Information\nTmPo - nt!tm        - Tm Propagation Output\nTmPp - nt!tm        - Tm Protocol Pointers\nTmPr - nt!tm        - Tm Protocol\nTmPx - nt!tm        - Tm Protocol Array\nTmRi - nt!tm        - Tm Recovery Information\nTmRm - nt!tm        - Tm KRESOURCEMANAGER object\nTmRq - nt!tm        - Tm Propagation Request\nTmRr - nt!tm        - Tm KTM_RESTART_RECORD\nTmTm - nt!tm        - Tm KTRANSACTIONMANAGER object\nTmTx - nt!tm        - Tm KTRANSACTION object\n\nTnbl - <unknown>    - NB Lists\nTnbt - <unknown>    - NB Pool\n\nTNbl - tcpip.sys    - TCP Send NetBufferLists\n\nToke - nt!se        - Token objects\n\nTOBJ - rdpdr.sys - Topology object\n\nTpWc - nt!ex        - Threadpool minipacket context\nTpWo - nt!ex        - Threadpool worker factory objects\n\nTQoS - tcpip.sys    - TL QoS Client Data\n\nTran - <unknown>    - EXIFS Translate\n\nTrcd - netiobvt.sys - NB Control Data\n\nTslc - tcpip.sys    - WFP TL Shim Layer Cache\nTscf - netio.sys    - WFP Filter Engine Cached Filter Block\n\nTSBV - <unknown>    - WDM mini driver for Toshiba 750 capture\n\nTSdd - rdpdd.sys    - RDPDD - Hydra Display Driver\nTSch - rdpwd.sys    - RDPWD - Hydra char conversion\nTSic - termdd.sys   - Terminal Services - ICA_POOL_TAG\nTSlc - rdpwd.sys    - RDPWD - Hydra Licensing\nTSmc - <unknown>    - PDMCS - Hydra MCS Protocol Driver\nTspk - ksecdd.sys   - TS Package kernel mode client allocations\nTSq  - <unknown>    - Terminal Services - Queue - TSQ_TAG\nTSrp - termdd.sys   - Terminal Services - RP_ALLOC_TAG\nTSwd - rdpwd.sys    - RDPWD - Hydra Winstation Driver\n\nTtnc -  tcpip.sys   - WFP tunnel nexthop context\n\nTsmp - tcpip.sys    - TCP Send Memory Descriptor Lists\nTSNb - tcpip.sys    - TCP Send NetBuffers\nTTsp - tcpip.sys    - TCP TCB Sends\n\nTtCo - <unknown>    - TTCP Connections\nTtcC - <unknown>    - TTCP Controllers\nTtcL - <unknown>    - TTCP Listeners\nTtcM - <unknown>    - TTCP Mappings\nTtcN - <unknown>    - TTCP NPIs\nTtcW - <unknown>    - TTCP Work Items\n\nTtfd - <unknown>    - TrueType Font driver\nTTFC - <unknown>    - Font file cache\n\nThrm - <unknown>    - Thermal zone structure\nTun4  - <unknown>   - Tunnel cache allocation for long file name\nTunL - <unknown>    - Tunnel cache lookaside-allocated elements\nTunP - <unknown>    - Tunnel cache oddsized pool-allocated elements\nTunK - <unknown>    - Tunnel cache temporary key value\n\nTuSB - tunnel.sys   - Tunnel stack block\n\nTWTa - tcpip.sys    - Echo Request Timer Table\nTWTs - netiobvt.sys - BVT TW Generic Buffers\n\nTxcl - ntfs.sys     - TXF_CLR_RESERVATION_CHUNK\nTxdl - ntfs.sys     - TXF_DELETED_LINK\nTxdr - ntfs.sys     - TXF_DEFAULT_READER_SECTION\nTxf0 - ntfs.sys     - TxfCallbacks.c\nTxf1 - ntfs.sys     - TxfTrans.c\nTxfa - ntfs.sys     - NameForLogging\nTxfb - ntfs.sys     - TXF_FCB_LIST_FOR_WALKUP\nTxfc - ntfs.sys     - TXF_FCB\nTxfD - ntfs.sys     - TxfData.c\nTxFe - ntfs.sys     - TXF_LOGREC_FILE_NAME_OPERATION\nTxfE - ntfs.sys     - TXF_TRANS_REQUEST\nTxfe - ntfs.sys     - TXF_FCB_EXTENSION\nTxfF - ntfs.sys     - TxfAllocateTxfFcbTableEntry\nTxff - ntfs.sys     - TXF_LOGREC_SET_SHORT_NAME\nTxfg - ntfs.sys     - TXF_LOGREC_FILE_NAME_OPERATION file create\nTxfH - ntfs.sys     - TXF_TRANS_REQUEST\nTxfh - ntfs.sys     - TXF_LOGREC_FILE_NAME_OPERATION delete file\nTxfi - ntfs.sys     - TXF_FCB_INFO\nTxfj - ntfs.sys     - TxfBuildIsolatedNormalizedName\nTxfK - ntfs.sys     - LongFileNameAttribute\nTxfk - ntfs.sys     - TxfScb->AttributeName.Buffer\nTxfl - ntfs.sys     - TXF_FCB_CLEANUP\nTxfM - ntfs.sys     - ShortNameAttribute\nTxfm - ntfs.sys     - TXF FAST_MUTEX\nTxfo - ntfs.sys     - TXF_FO\nTxfq - ntfs.sys     - Txf quota block\nTxfR - ntfs.sys     - TxfAllocateFullFilePathForChangeNotify\nTxfs - ntfs.sys     - TXFS_START_RM_INFORMATION RmParameters\nTxfu - ntfs.sys     - CLFS_MGMT_CLIENT_REGISTRATION\nTxfv - ntfs.sys     - CLFS_INFORMATION LogFileInformation\nTxfW - ntfs.sys     - KEVENT in TxfWaitForEnlistmentCompletion\nTxfw - ntfs.sys     - CLFS_INFORMATION LogFileInformation\nTxfx - ntfs.sys     - TXF_STREAM_ISO_INFO\nTxgd - ntfs.sys     - TxfData global structure\nTxis - ntfs.sys     - TXF_ISO_SNAPSHOT\nTxlf - ntfs.sys     - TXF_FCB (large)\nTxls - ntfs.sys     - TXF_CANCEL_LSN\nTxre - ntfs.sys     - TXF_TOPS_RANGE_ENTRY\nTxrm - ntfs.sys     - TXF_RMCB\nTxrn - ntfs.sys     - TXF_NONPAGED_RMCB\nTxsa - ntfs.sys     - Txf sorted array item\nTxsc - ntfs.sys     - TXF_SCB\nTxsp - ntfs.sys     - TXF_SAVEPOINT\nTxsp - ntfs.sys     - TXF_SCB_PTR\nTxTb - ntfs.sys     - Tops Bitmaps\nTxtc - ntfs.sys     - TXF_TRANS_CANCEL_LIST_ENTRY\nTxte - ntfs.sys     - TXF_RMCB_TABLE_ENTRY\nTxtr - ntfs.sys     - TXF_TRANS (Txf transaction context)\nTxts - ntfs.sys     - TXF_TRANS_SYNC\nTxvc - ntfs.sys     - TXF_VCB\nTxvd - ntfs.sys     - TXF_VSCB_TO_DEREF\nTxvf - ntfs.sys     - TXF_VSCB_FILE_SIZES\nTxvl - ntfs.sys     - TXF_VSCB\nTXCT - ntfs.sys     - TxfAllocateTableSpace\nTXHT - ntfs.sys     - TXF_HANDLE_TABLE\nTXIS - ntfs.sys     - TxfAllocateTableSpace\n\nType - <unknown>    - Type objects\n\nU802 - usb8023.sys  - RNDIS USB 8023 driver\n\nUCAM - <unknown>    - USB digital camera library\n\nUdf1 - udfs.sys     - Udfs file set descriptor buffer\nUdf2 - udfs.sys     - Udfs volmume recognition sequence descriptor buffer\nUdf3 - udfs.sys     - Udfs volume descriptor sequence descriptor buffer\nUdf4 - udfs.sys     - Udfs logical volume integrity descriptor buffer\nUdfB - udfs.sys     - Udfs dynamic name buffer\nUdfC - udfs.sys     - Udfs CRC table\nUdfD - udfs.sys     - Udfs FID buffer for view spanning\nUdfF - udfs.sys     - Udfs nonpaged Fcb\nUdfI - udfs.sys     - Udfs IO context\nUdfL - udfs.sys     - Udfs IRP context lite (delayed close)\nUdfN - udfs.sys     - Udfs normalized full filename\nUdfS - udfs.sys     - Udfs short file name\nUdfT - udfs.sys     - Udfs generic table entry\nUdfa - udfs.sys     - Udfs AD buffer\nUdfb - udfs.sys     - Udfs IO buffer\nUdfc - udfs.sys     - Udfs IRP context\nUdfd - udfs.sys     - Udfs file Scb\nUdfe - udfs.sys     - Udfs enumeration match expression\nUdff - udfs.sys     - Udfs Fcb\nUdfi - udfs.sys     - Udfs directory Scb\nUdfl - udfs.sys     - Udfs Lcb\nUdfn - udfs.sys     - Udfs Nonpaged Scb\nUdfp - udfs.sys     - Udfs Pcb\nUdfs - udfs.sys     - Udfs Sparing Mcb\nUdft - udfs.sys     - Udfs CDROM TOC\nUdfv - udfs.sys     - Udfs Vpb\nUdfV - udfs.sys     - Udfs VMCB dirty sector bitmap\nUdfx - udfs.sys     - Udfs Ccb\n\nUdAE - tcpip.sys    - UDP Activate Endpoints\nUdCo - tcpip.sys    - UDP Compartment\nUdEW - tcpip.sys    - UDP Endpoint Work Queue Contexts\nUdMI - tcpip.sys    - UDP Message Indications\nUDNb - tcpip.sys    - UDP NetBuffers\nUdpA - tcpip.sys    - UDP Endpoints\nUdpH - tcpip.sys    - UDP Headers\nUdpI - tcpip.sys    - UDP Interface\nUdPM - tcpip.sys    - UDP Partial Memory Descriptor Lists\nUdpN - tcpip.sys    - UDP Name Service Interfaces\nUdSM - tcpip.sys    - UDP Send Messages Requests\nUNbl - tcpip.sys    - UDP NetBufferLists\n\nUdp  - <unknown>    - Udp protocol (TCP/IP driver)\nUfsc - <unknown>    - User FULLSCREEN\nUHCD - <unknown>    - Universal Host Controller (USB - Intel Controller)\nUHUB - <unknown>    - Universal Serial Bus Hub\n\nUl?? - http.sys     - tags. Note: In-use tags are of the form \"Ul??\" or \"Uc??\".and   Free tags are of the form \"uL??\" or \"uC??\";\nUc?? - http.sys     - i.e., the case of the leading \"Ul\" or \"Uc\" has been reversed.\n\nUcac - http.sys     - Auth Cache Pool\nUcCO - http.sys     - Client Connection\nUcmp - http.sys     - Multipart String Buffer\nUcre - http.sys     - Receive Response\nUcrp - http.sys     - Response App Buffer\nUcrq - http.sys     - Request Pool\nUcSc - http.sys     - Common Server Information\nUcSN - http.sys     - Server name\nUcSP - http.sys     - Process Server Information\nUcSp - http.sys     - Sspi Pool\nUcST - http.sys     - Server info table\nUctd - http.sys     - Response Tdi Buffer\nUcte - http.sys     - Entity Pool\nUcto - http.sys     - Tdi Objects Pool\nUlAB - http.sys     - Auxiliary Buffer\nUlAO - http.sys     - App Pool Object\nUlAP - http.sys     - App Pool Process\nUlBL - http.sys     - Binary Log File Entry\nUlBO - http.sys     - Outstanding i/o\nUlCC - http.sys     - Control Channel\nUlCE - http.sys     - Config Group Tree Entry\nUlCH - http.sys     - Config Group Tree Header\nUlCI - http.sys     - Config Group URL Info\nUlCJ - http.sys     - Config Group Object Pool\nUlCK - http.sys     - Chunk Tracker\nUlCL - http.sys     - Config Group LogDir\nUlCl - http.sys     - Connection RefTraceLog\nUlCO - http.sys     - Connection\nUlCT - http.sys     - Config Group Timestamp\nUlCY - http.sys     - Connection Count Entry\nUlDB - http.sys     - Debug\nUlDC - http.sys     - Data Chunks array\nUlDO - http.sys     - Disconnect Object\nUlDR - http.sys     - Deferred Remove Item\nUlDT - http.sys     - Debug Thread Pool\nUlEP - http.sys     - Endpoint\nUlFA - http.sys     - Force Abort Work Item\nUlFC - http.sys     - File Cache Entry\nUlfc - http.sys     - Uri Filter Context\nUlFD - http.sys     - Noncached File Data\nUlFP - http.sys     - Filter Process\nUlFR - http.sys     - Dummy Filter Receive Buffer\nUlFT - http.sys     - Filter Channel\nUlFU - http.sys     - Full Tracker\nUlFW - http.sys     - Filter Write Tracker\nUlHC - http.sys     - Http Connection\nUlHc - http.sys     - Http Connection RefTraceLog\nUlHL - http.sys     - Internal Request RefTraceLog\nUlHR - http.sys     - Internal Request\nUlHT - http.sys     - Hash Table\nUlHV - http.sys     - Header Value\nUlIC - http.sys     - Irp Context\nUlID - http.sys     - Conn ID Table\nUlIR - http.sys     - Internal Response\nUlLD - http.sys     - Log Field\nUlLF - http.sys     - Log File Entry\nUlLG - http.sys     - Log Generic\nUlLH - http.sys     - Log File Handle\nUlLL - http.sys     - Log File Buffer\nUlLS - http.sys     - Ansi Log Data Buffer\nUlLT - http.sys     - Binary Log Data Buffer\nUlNO - http.sys     - NSGO Pool\nUlNP - http.sys     - Non-Paged Data\nUlOE - http.sys     - Endpoint OwnerRefTraceLog PoolTag\nUlOR - http.sys     - Owner RefTrace Signature\nUlOT - http.sys     - Opaque ID Table\nUlPB - http.sys     - APool Proc Binding\nUlPL - http.sys     - Pipeline\nUlQF - http.sys     - TCI Filter\nUlQG - http.sys     - TCI Generic\nUlQI - http.sys     - TCI Interface\nUlQL - http.sys     - TCI Flow\nUlQT - http.sys     - TCI Tracker\nUlQW - http.sys     - TCI WMI\nUlRB - http.sys     - Receive Buffer\nUlRD - http.sys     - Registry Data\nUlRE - http.sys     - Request Body Buffer\nUlRP - http.sys     - Request Buffer\nUlRR - http.sys     - Request Buffer References\nUlRS - http.sys     - Non-Paged Resource\nUlRT - http.sys     - RefTraceLog PoolTag\nUlSC - http.sys     - SSL Cert Data\nUlSD - http.sys     - Security Data\nUlSl - http.sys     - StringLog Buffer PoolTag\nUlSL - http.sys     - StringLog PoolTag\nUlSO - http.sys     - Site Counter Entry\nUlSS - http.sys     - Simple Status Item\nUlTA - http.sys     - Address Pool\nUlTD - http.sys     - UL_TRANSPORT_ADDRESS\nUlTT - http.sys     - Thread Tracker\nUlUB - http.sys     - URL Buffer\nUlUC - http.sys     - Uri Cache Entry\nUlUH - http.sys     - HTTP Unknown Header\nUlUL - http.sys     - URL\nUlUM - http.sys     - URL Map\nUlVH - http.sys     - Virtual Host\nUlWC - http.sys     - Work Context\nUlWI - http.sys     - Work Item\n\nUndP - <unknown>    - EXIFS Underlying Path\n\nUMD? - WUDFRd.sys   - UMDF pool allocation\nUSBB - bthusb.sys   - Bluetooth USB minidriver\nUSBD - <unknown>    - Universal Serial Bus Class Driver\nUsbS - usbser.sys   - USB Serial Driver\n\nV2ic - vhdmp.sys    - VHD2 external I/O allocation\nV2io - vhdmp.sys    - VHD2 internal I/O allocation\nV2lg - vhdmp.sys    - VHD2 core large allocation\nV2rv - vhdmp.sys    - VHD2 reserved VA mapping\nV2sm - vhdmp.sys    - VHD2 core allocation\nV2sr - vhdmp.sys    - VHD2 SRB range allocation\nV2wi - vhdmp.sys    - VHD2 work item\nV2?? - vhdmp.sys    - VHD2 pool allocation\n\nVad  - nt!mm        - Mm virtual address descriptors\nVadF - nt!mm        - VADs created by a FreeVM splitting\nVadl - nt!mm        - Mm virtual address descriptors (long)\nVadS - nt!mm        - Mm virtual address descriptors (short)\n\nVbus - vmbus.sys    - Virtual Machine Bus Driver\nVbuW - vmbus.sys    - Virtual Machine Bus Driver (WDF)\nVbxp - vmbus.sys    - Virtual Machine Bus Driver (cross partition)\n\nVcCh - rdpdr.sys - Dynamic Virtual channel object\nVcFl - rdpdr.sys - Dynamic Virtual file object\nVcMn - rdpdr.sys - Dynamic Virtual manager object\nVcSn - rdpdr.sys - Dynamic Virtual session object\n\nVDM  - nt!vdm       - ntos\\vdm\n\nVdDr - Vid.sys - Virtual Machine Virtualization Infrastructure Driver\nVdMm - Vid.sys - Virtual Machine Virtualization Infrastructure Driver (VSMM service)\nVdWd - Vid.sys - Virtual Machine Virtualization Infrastructure Driver (WDF)\n\nvDMc - dmvsc.sys - Virtual Machine Dynamic Memory VSC Driver\nvDMW - dmvsc.sys - Virtual Machine Dynamic Memory VSC Driver (WDF)\n\nVflt - vmstorfl.sys - Virtual Machine Storage Filter Driver\nVflW - vmstorfl.sys - Virtual Machine Storage Filter Driver (WDF)\n\nVdPN - dxgkrnl.sys  - Video display mode management\nVepp - nt!Vf        - Verifier Pool Tracking information\nVfAT - nt!Vf        - Verifier AVL trees\nVfIT - nt!Vf        - Verifier Import Address Table information\nVfPT - nt!Vf        - Verifier Allocate/Free Pool stack traces\nVfUs - nt!Vf        - Memory allocated by a call to IoSetCompletionRoutineEx.\nVfwi - nt!Vf        - IO_WORKITEM allocated by I/O verifier version of IoAllocateWorkItem\nViIn - nt!Vf        - Verifier Internal Tag for pool tracking\nVMdl - nt!Vf        - MDL allocated by I/O verifier version of IoAllocateMdl\nVNod - nt!Vf        - Deadlock Verifier nodes\nVRes - nt!Vf        - Deadlock Verifier resources\nVStr - nt!Vf        - String buffer allocated by the Driver Verifier version of Rtl String APIs\n\nVHDa - vhdmp.sys    - VHD generic allocator\nVHDA - vhdmp.sys    - VHD generic allocator pool\nVHDb - vhdmp.sys    - VHD Block Allocation Table\nVHDf - vhdmp.sys    - VHD file entry\nVHDh - vhdmp.sys    - VHD header\nVHDi - vhdmp.sys    - VHD IO Range\nVHDI - vhdmp.sys    - VHD IO Range pool\nVHDl - vhdmp.sys    - VHD LUN\nVHDm - vhdmp.sys    - VHD bitmap\nVHDn - vhdmp.sys    - VHD filename\nVHDo - vhdmp.sys    - VHD footer\nVHDp - vhdmp.sys    - VHD filepath\nVHDr - vhdmp.sys    - VHD read buffer\nVHDs - vhdmp.sys    - VHD sector map\nVHDS - vhdmp.sys    - VHD symbolic link\nVHDt - vhdmp.sys    - VHD tracking information\nVHDw - vhdmp.sys    - VHD work item\nVHDy - vhdmp.sys    - VHD dynamic header\nVHD? - vhdmp.sys    - VHD allocation\n\nVHde - vmusbhub.sys - Virtual Machine USB Hub Driver (descriptor)\nVHif - vmusbhub.sys - Virtual Machine USB Hub Driver (interface)\nVHps - vmusbhub.sys - Virtual Machine USB Hub Driver (Pnp string)\nVHrc - vmusbhub.sys - Virtual Machine USB Hub Driver (request context)\nVHtx - vmusbhub.sys - Virtual Machine USB Hub Driver (text)\nVHub - vmusbhub.sys - Virtual Machine USB Hub Driver (Bus)\nVHur - vmusbhub.sys - Virtual Machine USB Hub Driver (URB)\nVHuW - vmusbhub.sys - Virtual Machine USB Hub Driver (WDF)\n\nVi01 - dxgmms2.sys  - Video memory manager global alloc\nVi02 - dxgmms2.sys  - Video memory manager local alloc\nVi03 - dxgmms2.sys  - Video memory manager alloc\nVi06 - dxgmms2.sys  - Video memory manager segment\nVi07 - dxgmms2.sys  - Video memory manager segment range\nVi08 - dxgmms2.sys  - Video memory manager device\nVi09 - dxgmms2.sys  - Video memory manager process\nVi0a - dxgmms2.sys  - Video memory manager global alloc VGPU\nVi10 - dxgmms2.sys  - Video memory manager process heap\nVi11 - dxgmms2.sys  - Video memory manager process heap block\nVi12 - dxgmms2.sys  - Video memory manager process heap alloc\nVi13 - dxgmms2.sys  - Video memory manager process adapter info\nVi14 - dxgmms2.sys  - Video memory manager process commitment info\nVi15 - dxgmms2.sys  - Video memory manager global state\nVi16 - dxgmms2.sys  - Video memory manager command state\nVi17 - dxgmms2.sys  - Video memory manager pool\nVi18 - dxgmms2.sys  - Video memory manager pool block\nVi19 - dxgmms2.sys  - Video memory manager pool block array\nVi20 - dxgmms2.sys  - Video memory manager commitment info\nVi21 - dxgmms2.sys  - Video memory manager segment descriptor\nVi22 - dxgmms2.sys  - Video memory manager DMA buffer\nVi23 - dxgmms2.sys  - Video memory manager DMA buffer allocation table\nVi24 - dxgmms2.sys  - Video memory manager DMA buffer allocation list\nVi25 - dxgmms2.sys  - Video memory manager DMA buffer patch location list\nVi26 - dxgmms2.sys  - Video memory manager protected allocation\nVi27 - dxgmms2.sys  - Video memory manager resource list\nVi28 - dxgmms2.sys  - Video memory manager mutex\nVi29 - dxgmms2.sys  - Video memory manager DMA pool\nVi30 - dxgmms2.sys  - Video memory manager slot table\nVi31 - dxgmms2.sys  - Video memory manager dummy page\nVi32 - dxgmms2.sys  - Video memory manager DMA buffer private data\nVi35 - dxgmms2.sys  - Video memory manager MDL\nVi36 - dxgmms2.sys  - Video memory manager pages history\nVi37 - dxgmms2.sys  - Video memory manager DMA buffer global alloc table\nVi38 - dxgmms2.sys  - Video memory manager allocation fence array\nVi39 - dxgmms2.sys  - Video memory manager migration table\nVi40 - dxgmms2.sys  - Video memory manager migration table lock\nVi41 - dxgmms2.sys  - Video memory manager process budget info\nVi42 - dxgmms2.sys  - Video memory manager global alloc nonpaged\nVi43 - dxgmms2.sys  - Video memory manager async operation\nVi44 - dxgmms2.sys  - Video memory manager fence storage\nVi45 - dxgmms2.sys  - Video memory manager CPU host aperture\nVi46 - dxgmms2.sys  - Video memory manager CPU host aperture page\nVi47 - dxgmms2.sys  - Video memory manager worker thread\nVi48 - dxgmms2.sys  - Video memory manager paging queue\nVi49 - dxgmms2.sys  - Video memory manager GPU VA\nVi50 - dxgmms2.sys  - Video memory manager physical adapter\nVi51 - dxgmms2.sys  - Video memory manager set VPR work item\nVi52 - dxgmms2.sys  - Video memory manager paging history\nVi53 - dxgmms2.sys  - Video memory manager page table\nVi54 - dxgmms2.sys  - Video memory manager PTE array\nVi55 - dxgmms2.sys  - Video memory manager VA range\nVi56 - dxgmms2.sys  - Video memory manager page directory\nVi57 - dxgmms2.sys  - Video memory manager PDE array\nVi58 - dxgmms2.sys  - Video memory manager release resource command\nVi59 - dxgmms2.sys  - Video memory manager deferred unlock\nVi5a - dxgmms2.sys  - Video memory manager PTE owner data\nVi5b - dxgmms2.sys  - Video memory manager partition\nVi5c - dxgmms2.sys  - Video memory manager partition adapter info\nVi5d - dxgmms2.sys  - Video memory manager cross adapter alloc\nVi5e - dxgmms2.sys  - Video memory manager scheduling log\nVi5f - dxgmms2.sys  - Video scheduler async operation\nVi60 - dxgmms2.sys  - Video memory manager cross adapter data\nVi61 - dxgmms2.sys  - Video memory manager context alloc\nVia0 - dxgmms2.sys  - GPU scheduler adapter state\nVia1 - dxgmms2.sys  - GPU scheduler node state\nVia2 - dxgmms2.sys  - GPU scheduler process state\nVia3 - dxgmms2.sys  - GPU scheduler device state\nVia4 - dxgmms2.sys  - GPU scheduler context state\nVia5 - dxgmms2.sys  - GPU scheduler queue packet\nVia6 - dxgmms2.sys  - GPU scheduler DMA packet\nVia7 - dxgmms2.sys  - GPU scheduler VSync cookie\nVia8 - dxgmms2.sys  - GPU scheduler GPU sync object\nVia9 - dxgmms2.sys  - GPU scheduler present info\nViaa - dxgmms2.sys  - GPU scheduler history buffer\nViab - dxgmms2.sys  - GPU scheduler periodic frame notification state\nViac - dxgmms2.sys  - GPU scheduler hardware context\nViad - dxgmms2.sys  - GPU scheduler hardware queue\nViae - dxgmms2.sys  - GPU scheduler monitored fence\nViaf - dxgmms2.sys  - GPU scheduler sync point\nVib0 - dxgmms2.sys  - GPU scheduler pending IFlip token\nVib1 - dxgmms2.sys  - GPU scheduler flip queue entry\n\nVidL - videoprt.sys - VideoPort Allocation List (FDO_EXTENSION)\nVidR - videoprt.sys - VideoPort Allocation on behalf of Miniport\n\nViMm - dxgkrnl.sys  - Video memory manager\nvirt - vmm.sys      - Virtual Machine Manager (VPC/VS)\nViSh - dxgkrnl.sys  - Video scheduler\n\nVk?? - vmbkmcl.sys  - Hyper-V VMBus KMCL driver\nVkin - vmbkmcl.sys  - Hyper-V VMBus KMCL driver (incoming packets)\nVkou - vmbkmcl.sys  - Hyper-V VMBus KMCL driver (outgoing packets)\n\nVM?? - volmgr.sys   - Volume Manager\nVM   - volmgr.sys   - General allocations\n\nVm?? - volmgrx.sys  - Volume Manager Extension\nVm   - volmgrx.sys  - General allocations\nVmBl - volmgrx.sys  - Raw configuration blocks\nVmBu - volmgrx.sys  - I/O buffers\nVmCc - volmgrx.sys  - Configuration copies\nVmCo - volmgrx.sys  - Configurations\nVmCp - volmgrx.sys  - Copies\nVmCr - volmgrx.sys  - Completion routine contexts\nVmDc - volmgrx.sys  - Device changes\nVmDd - volmgrx.sys  - Disk devices\nVmDh - volmgrx.sys  - Disk headers\nVmLa - volmgrx.sys  - Drive layouts\nVmLb - volmgrx.sys  - Log blocks\nVmLc - volmgrx.sys  - Log copies\nVmLo - volmgrx.sys  - Logs\nVmLr - volmgrx.sys  - Log raw content\nVmMm - volmgrx.sys  - Mirror emergency mappings\nVmNe - volmgrx.sys  - Notification entries\nVmOb - volmgrx.sys  - I/O objects\nVmP0 - volmgrx.sys  - Packets\nVmP1 - volmgrx.sys  - Small packets\nVmP2 - volmgrx.sys  - Large packets\nVmP3 - volmgrx.sys  - Huge packets\nVmPa - volmgrx.sys  - Packs\nVmPd - volmgrx.sys  - Physical disks\nVmPs - volmgrx.sys  - Arrays of packets\nVmRb - volmgrx.sys  - Raw record buffers\nVmRc - volmgrx.sys  - Raw configurations\nVmRe - volmgrx.sys  - Records\nVmRi - volmgrx.sys  - Record information\nVmRm - volmgrx.sys  - RAID-5 emergency mappings\nVmRr - volmgrx.sys  - Raw records\nVmTa - volmgrx.sys  - I/O tasks\nVmTc - volmgrx.sys  - Table of contents\nVmTe - volmgrx.sys  - Table of contents entries\nVmTx - volmgrx.sys  - Transactions\nVmUe - volmgrx.sys  - User entries\nVmVd - volmgrx.sys  - Volume devices\nVmWi - volmgrx.sys  - Work items\n\nVmbK - kmcl.lib        - Virtual Machine Bus Kernel Mode Client Library\n\nVmCh - ChimneyLib.lib  - Virtual Machine Network Chimney Library\n\nVmFP - vfpext.sys - Virtual Filtering Platform driver\n\nVMhd - vmbushid.sys    - Virtual Machine Input VSC Driver\nVMIN - vwifimp.sys     - Virtual Wi-Fi miniport\n\nVmsc - storchannel.lib - Virtual Machine Storage VSC Channel Library\n\nVNC  - netvsc50.sys/netvsc60.sys - Virtual Machine Network VSC Driver\nVNCm - netvsc50.sys/netvsc60.sys - Virtual Machine Network VSC Driver (RNDIS miniport driver library, message or object)\nVNCn - netvsc50.sys/netvsc60.sys - Virtual Machine Network VSC Driver (NBL)\nVNCr - netvsc50.sys/netvsc60.sys - Virtual Machine Network VSC Driver (RNDIS message context signature)\nVNCW - netvsc50.sys/netvsc60.sys - Virtual Machine Network VSC Driver (WDF)\n\nVoS? - volsnap.sys  -  VolSnap (Volume Snapshot Driver)\nVoSa - volsnap.sys  -      Application information allocations\nVoSb - volsnap.sys  -      Buffer allocations\nVoSc - volsnap.sys  -      Snapshot context allocations\nVoSd - volsnap.sys  -      Diff area volume allocations\nVoSf - volsnap.sys  -      Diff area file allocations\nVoSh - volsnap.sys  -      Bit history allocations\nVoSi - volsnap.sys  -      Io status block allocations\nVoSm - volsnap.sys  -      Bitmap allocations\nVoSo - volsnap.sys  -      Old heap entry allocations\nVoSp - volsnap.sys  -      Pnp id allocations\nVoSr - volsnap.sys  -      Device relations allocations\nVoSs - volsnap.sys  -      Short term allocations\nVoSt - volsnap.sys  -      Temp table allocations\nVoSw - volsnap.sys  -      Work queue allocations\nVoSx - volsnap.sys  -      Dispatch context allocations\n\nVpb  - <unknown>    - Io, vpb's\n\nVPrs - passthruparser.sys - Virtual Machine Storage Passthrough Parser Driver\n\nVprt - videoprt.sys - Video port for legacy (pre-Vista) display drivers\n\nVraP - <unknown>    - parallel class driver\nVtfd - <unknown>    - Font file/context\n\nVrdc - netvsc60.sys - Virtual Machine Network VSC Driver (NDIS 6, RNDIS miniport driver library, chimney neighbor or path context)\nVrdt - netvsc60.sys - Virtual Machine Network VSC Driver (NDIS 6, RNDIS miniport driver library, chimney TCP context)\nVrdi - netvsc60.sys - Virtual Machine Network VSC Driver (NDIS 6, RNDIS miniport driver library, chimney initiate offload)\n\nVSAB - utils.lib - Virtual Machine Storage VSP Utility Library\n\nVsAT - vmswitch.sys - Virtual Machine Network Switch Driver (address table)\nVsC4 - vmswitch.sys - Virtual Machine Network Switch Driver (chimney path4 context)\nVsC6 - vmswitch.sys - Virtual Machine Network Switch Driver (chimney path6 context)\nVsCH - vmswitch.sys - Virtual Machine Network Switch Driver (chimney handle)\nVsCN - vmswitch.sys - Virtual Machine Network Switch Driver (chimney neighbor context)\nVsCP - vmswitch.sys - Virtual Machine Network Switch Driver (chimney NBL context)\nVsCs - vmswitch.sys - Virtual Machine Network Switch Driver (configuration store)\nVsCT - vmswitch.sys - Virtual Machine Network Switch Driver (chimney TCP context)\nVsDI - vmswitch.sys - Virtual Machine Network Switch Driver (direct I/O NIC)\nVsNb - vmswitch.sys - Virtual Machine Network Switch Driver (NBL)\nVsOb - vmswitch.sys - Virtual Machine Network Switch Driver (object allocation)\nVsRD - vmswitch.sys - Virtual Machine Network Switch Driver (RNDIS device)\nVsRm - vmswitch.sys - Virtual Machine Network Switch Driver (routing)\nVsRT - vmswitch.sys - Virtual Machine Network Switch Driver (routing table)\nVssB - vmswitch.sys - Virtual Machine Network Switch Driver (balance)\nVssM - vmswitch.sys - Virtual Machine Network Switch Driver (miniport NIC)\nVssP - vmswitch.sys - Virtual Machine Network Switch Driver (protocol NIC)\nVsSw - vmswitch.sys - Virtual Machine Network Switch Driver\nVsSW - vmswitch.sys - Virtual Machine Network Switch Driver (WDF)\nVsVN - vmswitch.sys - Virtual Machine Network Switch Driver (VM NIC)\nVsvq - vmswitch.sys - Virtual Machine Network Switch Driver (VMQ)\n\nVSt  - storvsp.sys - Virtual Machine Storage VSP Driver\nVSta - storvsp.sys - Virtual Machine Storage VSP Driver (adapter)\nVStb - storvsp.sys - Virtual Machine Storage VSP Driver (balance)\nVStd - storvsp.sys - Virtual Machine Storage VSP Driver (device)\nVStp - storvsp.sys - Virtual Machine Storage VSP Driver (parser)\nVStu - storvsp.sys - Virtual Machine Storage VSP Driver (authentication)\nVStW - storvsp.sys - Virtual Machine Storage VSP Driver (WDF)\n\nVSVL - VMBusVideoM.sys - Virtual Machine Synthetic Video Display Driver\n\nvS3W - vms3cap.sys - Virtual Machine Emulated S3 Device Cap Driver (WDF)\n\nvTDR - dxgkrnl.sys  - Video timeout detection/recovery\n\nVubH - vmusbbus.sys  - Virtual Machine USB Bus Driver\nVubW - vmusbbus.sys  - Virtual Machine USB Bus Driver (WDF)\n\nVuCH - vuc.sys       - Virtual Machine USB Connector Driver (connector handle)\nVuCP - vuc.sys       - Virtual Machine USB Connector Driver (virtual hub ports)\nVuCU - vuc.sys       - Virtual Machine USB Connector Driver (connector URB)\nVuCW - vuc.sys       - Virtual Machine USB Connector Driver (WDF)\n\nVusW - vmusbstub.sys - Virtual Machine USB Stub Driver (WDF)\n\nVVpc - vhdparser.sys - Virtual Machine Storage VHD Parser Driver (context)\nVVpp - vhdparser.sys - Virtual Machine Storage VHD Parser Driver (parser)\n\nVWFB - vwifibus.sys - Virtual Wi-Fi Bus Driver\nVWFF - vwififlt.sys - Virtual Wi-Fi Filter Driver (object allocation)\nVWnd - vwififlt.sys -  Virtual Wi-Fi Filter Driver (requests)\n\nWait - nt!io        - WaitCompletion Packets\n\nWan? - <unknown>    - NdisWan Tags (PPP Framing module for Remote Access)\nWanA - <unknown>    - BundleCB\nWanB - <unknown>    - ProtocolCB/LinkCB\nWanC - <unknown>    - DataDesc\nWanD - <unknown>    - WanRequest\nWanE - <unknown>    - LoopbackDesc\nWanG - <unknown>    - MiniportCB\nWanH - <unknown>    - OpenCB\nWanI - <unknown>    - IoPacket\nWanJ - <unknown>    - LineUpInfo\nWanK - <unknown>    - Unicode String Buffer\nWanL - <unknown>    - Protocol Table\nWanM - <unknown>    - Connection Table\nWanN - <unknown>    - NdisPacketPool Desc\nWanQ - <unknown>    - DataBuffer\nWanR - <unknown>    - WanPacket\nWanS - <unknown>    - AfCB/SapCB/VcCB\nWanT - <unknown>    - Transform Driver\nWanV - <unknown>    - RC4 Encryption Context\nWanW - <unknown>    - SHA Encryption\nWanX - <unknown>    - Send Compression Context\nWanY - <unknown>    - Recv Compression Context\nWanZ - <unknown>    - Protocol Specific Info\n\nWdm  - <unknown>    - WDM\nWDMA - <unknown>    - WDM Audio\n\nWdog - watchdog.sys - Watchdog object/context allocation\n\nWfp? - netio.sys    - Windows Filtering Platform Tags\nWfpF - netio.sys    - WFP filters\nWfpM - netio.sys    - WFP filter match buffers\nWfpI - netio.sys    - WFP index\nWfpH - netio.sys    - WFP hash\nWfpR - netio.sys    - WFP RPC\nWfpC - netio.sys    - WFP callouts\nWfpS - netio.sys    - WFP startup\nWfpL - netio.sys    - WFP fast cache\nWfpE - netio.sys    - WFP extension\nWfpn - netio.sys    - WFP NBL info container\n\nWfTi - <unknown>    - WFP timer\nWfSt - <unknown>    - WFP string\n\nwerk - <unknown>    - WER kernel mode reporting allocation\nWKSM - werkernel.sys - WER kernel mode reporting allocation of WERSVC message\n\nWimF - wimfsf.sys   - WIM Boot Filter\n\nWl2l - wfplwfs.sys  - WFP L2 LWF context\nWl2g - wfplwfs.sys  - WFP L2 generic block\nWl2c - wfplwfs.sys  - WFP L2 classify cache\nWl2f - wfplwfs.sys  - WFP L2 flow\nWl2n - wfplwfs.sys  - WFP L2 NBL context\n\nWlBs - writelog.sys - Writelog block store\nWlFc - writelog.sys - Writelog fsd context\nWlGc - writelog.sys - Writelog global context\nWlIb - writelog.sys - Writelog I/O buffer\nWlLb - writelog.sys - Writelog library buffer\nWlCb - writelog.sys - Writelog checkpoint buffer\nWlPw - writelog.sys - Writelog planned write\nWlMh - writelog.sys - Writelog marker header\nWlMp - writelog.sys - Writelog marker payload\nWlDt - writelog.sys - Writelog drain target\n\nWmii - <unknown>    - Wmi InstId chunks\nWmij - <unknown>    - Wmi GuidMaps\nWmim - <unknown>    - Wmi KM to UM Notification Buffers\nWmin - <unknown>    - Wmi Notification Slot Chunks\nWmip - <unknown>    - Wmi General purpose allocation\nWmiq - <unknown>    - Wmi NBQ Blocks\nWmis - <unknown>    - Wmi SysId allocations\nWmit - <unknown>    - Wmi Trace\nWmiw - <unknown>    - Wmi Notification Waiting Buffers, in paged queue waiting for IOCTL\nWmiz - <unknown>    - Wmi MCA Insertions debug code\n\nWmiA - <unknown>    - Wmi ACPI mapper\nWmiC - <unknown>    - Wmi Create Pump Thread Work Item\nWmiD - <unknown>    - Wmi Registration DataSouce\nWmiG - <unknown>    - Allocation of WMIGUID\nWmiI - <unknown>    - Wmi Instance Names\nWmiL - <unknown>    - WmiLIb\nWmiN - <unknown>    - Wmi Notification Notification Packet\nWmiR - <unknown>    - Wmi Registration info blocks\n\nWmDS - <unknown>    - Wmi DataSource chunks\nWmGE - <unknown>    - Wmi GuidEntry chunks\nWmIS - <unknown>    - Wmi InstanceSet chunks\nWmMR - <unknown>    - Wmi MofResouce chunks\n\nWMca - <unknown>    - WMI MCA Handling\n\nWnf  - nt!wnf       - Windows Notification Facility\n\nWofD - wof.sys      - Wof directory buffer\nWofF - wof.sys      - Wof file context\nWoff - wof.sys      - Wof extended file context\nWofG - wof.sys      - Wof general allocation\nWofH - wof.sys      - Wof handle context\nWofI - wof.sys      - Wof inflate buffer\nWofS - wof.sys      - Wof stream context\nWoft - wof.sys      - Wof transaction context\nWofV - wof.sys      - Wof volume context\n\nwpcf - wof.sys      - Wim config file\nwpci - wof.sys      - Wim integrity\nwpct - wof.sys      - Wim chunk table\nwpcx - wof.sys      - Wim IO context\nwpdw - wof.sys      - Wim decompression workspace\nwpgn - wof.sys      - Wim general\nwppm - wof.sys      - Wim IO parameters\nwprd - wof.sys      - Wim small read buffer\nwpRD - wof.sys      - Wim large read buffer\nwprt - wof.sys      - Wim resource table\nwpvo - wof.sys      - Wim volume overlay\nwpwf - wof.sys      - Wim file\nwpwi - wof.sys      - Wim work item\nwpxp - wof.sys      - Wim xpress context\n\nWrp? - <unknown>    - WanArp Tags (ARP module for Remote Access)\n\nWrpa - <unknown>    - WAN_ADAPTER_TAG\nWrpi - <unknown>    - WAN_INTERFACE_TAG\nWrpr - <unknown>    - WAN_REQUEST_TAG\nWrps - <unknown>    - WAN_STRING_TAG\nWrpc - <unknown>    - WAN_CONN_TAG\nWrpw - <unknown>    - WAN_PACKET_TAG\nWrpf - <unknown>    - FREE_TAG (checked builds only)\nWrpd - <unknown>    - WAN_DATA_TAG\nWrph - <unknown>    - WAN_HEADER_TAG\nWrpn - <unknown>    - WAN_NOTIFICATION_TAG\n\nWSCD - WFPSamplerCalloutDriver.sys - WFPSampler Callout Driver\n\nWSKs - afd.sys      - WSK socket\n\nWSNP - WFPSamplerCalloutDriver.sys - WFPSampler Callout Driver NDIS Pool\n\nWtdA - wtd.sys      - WTD ACS implementation\nWtdE - wtd.sys      - WTD event queue\nWtdF - wtd.sys      - WTD chipc implementation\nWtdJ - wtd.sys      - WTD event stats\nWtdK - wtd.sys      - WTD KMDF framework\nWtdL - wtd.sys      - WTD chipc dll scan\nWtdN - wtd.sys      - WTD WFP implementation\n\nWvCy - <unknown>    - WDM Audio WaveCyc port\nWvPc - <unknown>    - WDM Audio WavePCI port\n\nxCVD - mrxdav.sys - AsyncEngineContext Tag\n\nXDR? - rpcxdr.sys   - NFS (Network File System) XDR driver\n\nxSMB - smbmrx.sys - IFSKIT sample SMB mini-redirector\n\nXWan - <unknown>    - ndis\\usrwan allocations\n\nXtra - <unknown>    - EXIFS Extra Create\n\nZsaB - <unknown>    - EXIFS ZeroBlock\nAdbe - win32k.sys                           - GDITAG_ATM_FONT\nBmfd - win32k.sys                           - GDITAG_BMP_FONT\nDfsm - win32k.sys                           - GDITAG_ENG_EVENT\nDwmL - win32k!HwndLookupAllocTableData      - GDITAG_DWM_HWND_LOOKUP\nDWMt - win32k.sys                           - GDITAG_DWM_SENDTOUCHCONTACTS\nDWMv - win32k.sys                           - GDITAG_DWM_VALIDATION\nDxdd - win32k!DxLddmSharedPrimaryLockNotification - GDITAG_LOCKED_PRIMARY\nGill - win32kbase.sys                       - GDITAG_ISOLATED_LOOKASIDE_LIST\nGila - win32kbase.sys                       - GDITAG_ISOLATED_LOOKASIDE_LIST_ALLOCATION\nGadb - win32k!XDCOBJ::bAddColorTransform    - GDITAG_DC_COLOR_TRANSFORM\nGadd - win32k.sys                           - GDITAG_DC_FONT\nGalp - win32k!AlphaScanLineBlend            - GDITAG_ALPHABLEND\nGapc - win32kfull!UmfdQueueTryUnzombifyPffApc - GDITAG_UNZOMBIFY_APC\nGbaf - win32k.sys                           - GDITAG_BRUSH_FREELIST\nGbdl - win32k!BRUSH::bAddIcmDIB             - GDITAG_ICM_DIB_LIST\nGcac - win32k.sys                           - GDITAG_FONTCACHE\nGcsl - win32k!InitializeScripts             - GDITAG_SCRIPTS\nGcwc - win32k!ConvertToAndFromWideChar      - GDITAG_CHAR_TO_WIDE_CHAR\nGdbr - win32k!BRUSHOBJ_pvAllocRbrush        - GDITAG_RBRUSH\nGdcf - win32k.sys                           - GDITAG_DC_FREELIST\nGDcs - win32k!GreDwmStartup                 - GDITAG_DWMSTATE\nGdev - win32k.sys                           - GDITAG_DEVMODE\nGdfm - win32k!DoFontManagement              - GDITAG_HGLYPH_ARRAY\nGdrs - win32k.sys                           - GDITAG_DRVSUP\nGdrv - win32k!EngCreateClip                 - GDITAG_CLIPOBJ\nGdtd - win32k!GreAcquireSemaphoreAndValidate - GDITAG_SEMAPHORE_VALIDATE\nGdwd - win32k.sys                           - GDITAG_WATCHDOG\nGebr - win32k!EngRealizeBrush               - GDITAG_ENGBRUSH\nGedd - win32k.sys                           - GDITAG_ENUM_DISPLAY_DEVICES\nGedg - win32k!bFill                         - GDITAG_EDGE\ngEdg - win32k!bTriangleMesh                 - GDITAG_TRIANGLEDATA\nGeto - win32k.sys                           - GDITAG_TEXTOUT\nGfda - win32k!UmfdAllocation::Create        - GDITAG_UMFD_ALLOCATION\nGfdf - win32k!InitializeDefaultFamilyFonts  - GDITAG_FONT_DEFAULT_FAMILY\nGffv - win32k.sys                           - GDITAG_FONTFILEVIEW\nGfid - win32k.sys                           - GDITAG_UNIVERSAL_FONT_ID\nGFil - win32k.sys                           - GDITAG_FILEPATH\nGfil - win32k.sys                           - GDITAG_MAPFILE\nGFld - win32k.sys                           - GDITAG_FLOODFILL\nGfnt - win32k!RFONTOBJ::bRealizeFont        - GDITAG_RFONT\nGfsb - win32k.sys                           - GDITAG_FONT_SUB\nGfsf - win32k!bInitStockFontsInternal       - GDITAG_FONT_STOCKFONT\nGfsm - win32k!GreCreateFastMutex            - GDITAG_FAST_MUTEX\nGful - win32k.sys                           - GDITAG_FULLSCREEN\nGfvi - win32k!bUnloadAllButPermanentFonts   - GDITAG_FONTVICTIM\nGgb  - win32k!RFONTOBJ::pgbCheckGlyphCache  - GDITAG_GLYPHBLOCK\nGgdv - win32k.sys                           - GDITAG_GDEVICE\nGgls - win32k.sys                           - GDITAG_GLYPHSET\nGgly - win32k.sys                           - GDITAG_HGLYPH\nGh?: - win32k.sys                           - GDITAG_HMGR_LFONT_TYPE\nGh?; - win32k.sys                           - GDITAG_HMGR_RFONT_TYPE\nGh?@ - win32k.sys                           - GDITAG_HMGR_BRUSH_TYPE\nGh?> - win32k.sys                           - GDITAG_HMGR_ICMCXF_TYPE\nGh?0 - win32k.sys                           - GDITAG_HMGR_DEF_TYPE\nGh?1 - win32k.sys                           - GDITAG_HMGR_DC_TYPE\nGh?4 - win32k.sys                           - GDITAG_HMGR_RGN_TYPE\nGh?5 - win32k.sys                           - GDITAG_HMGR_SURF_TYPE\nGh?6 - win32k.sys                           - GDITAG_HMGR_CLIENTOBJ_TYPE\nGh?7 - win32k.sys                           - GDITAG_HMGR_PATH_TYPE\nGh?8 - win32k.sys                           - GDITAG_HMGR_PAL_TYPE\nGh?9 - win32k.sys                           - GDITAG_HMGR_ICMLCS_TYPE\nGh?A - win32k.sys                           - GDITAG_HMGR_UMPD_TYPE\nGh?B - win32k.sys                           - GDITAG_HMGR_HLSURF_TYPE\nGh?E - win32k.sys                           - GDITAG_HMGR_META_TYPE\nGh?L - win32k.sys                           - GDITAG_HMGR_DRVOBJ_TYPE\nGh?? - win32k.sys                           - GDITAG_HMGR_SPRITE_TYPE\nGh00 - win32k.sys                           - GDITAG_HMGR_START\nGhab - win32k!FHOBJ::bAddPFELink            - GDITAG_PFE_HASHBUCKET\nGhas - win32k!FHMEMOBJ::FHMEMOBJ            - GDITAG_PFE_HASHTABLE\nGhml - win32k.sys                           - GDITAG_HMGR_LOCK\nGhtc - win32k!bSetHTSrcSurfInfo             - GDITAG_HALFTONE_COLORTRIAD\nGhtm - win32k.sys                           - GDITAG_HMGR_TEMP\nGi2c - win32k.sys                           - GDITAG_DDCCI\nGicm - win32k.sys                           - GDITAG_ICM\nGiga - win32k.sys                           - GDITAG_PRIVATEGAMMA\nGiog - win32k.sys                           - GDITAG_COMPOSEDGAMMA\nGkbm - win32k.sys                           - GDITAG_KMODE_BITMAP\nGla: - win32k.sys                           - GDITAG_HMGR_LOOKASIDE_LFONT_TYPE\nGla; - win32k.sys                           - GDITAG_HMGR_LOOKASIDE_RFONT_TYPE\nGla@ - win32k.sys                           - GDITAG_HMGR_LOOKASIDE_BRUSH_TYPE\nGla0 - win32k.sys                           - GDITAG_HMGR_LOOKASIDE_START\nGla1 - win32k.sys                           - GDITAG_HMGR_LOOKASIDE_DC_TYPE\nGla4 - win32k.sys                           - GDITAG_HMGR_LOOKASIDE_RGN_TYPE\nGla5 - win32k.sys                           - GDITAG_HMGR_LOOKASIDE_SURF_TYPE\nGla8 - win32k.sys                           - GDITAG_HMGR_LOOKASIDE_PAL_TYPE\nGlas - win32k.sys                           - GDITAG_SCAN_LOOKASIDE_LIST\nGldv - win32k.sys                           - GDITAG_LDEV\nGlid - win32k!GetLanguageID                 - GDITAG_LOCALEINFO\nGlnk - win32k!FHOBJ::bAddPFELink            - GDITAG_PFE_LINK\nGmap - win32k!InitializeFontSignatures      - GDITAG_FONT_MAPPER\nGmso - win32k!MULTISORTBLTORDER::MULTISORTBLTORDER - GDITAG_DISPURF_SORT\nGmul - win32k!MULTIFONT::MULTIFONT          - GDITAG_MULTIFONT\nGnls - win32k.sys                           - GDITAG_NLS\nGogl - win32k!iOpenGLExtEscape              - GDITAG_OPENGL\nGOPM - win32k.sys                           - GDITAG_OPM\nGPal - win32k.sys                           - GDITAG_PALETTE\nGpan - win32k.sys                           - GDITAG_PANNING_PDEV\nGpat - win32k.sys                           - GDITAG_PATHOBJ\nGpfe - win32k!PFFMEMOBJ::bAllocPFEData      - GDITAG_PFF_INDEXES\nGpff - win32k.sys                           - GDITAG_PFF\nGpft - win32k!pAllocateAndInitializePFT     - GDITAG_PFT\nGpgb - win32k!EngPlgBlt                     - GDITAG_PLGBLT_DATA\nGpid - win32k!NtGdiSetPUMPDOBJ              - GDITAG_PRINTCLIENTID\nGppo - win32k!XCLIPOBJ::ppoGetPath          - GDITAG_CLIP_PATHOBJ\nGppt - win32k!PROXYPORT::PROXYPORT          - GDITAG_PROXYPORT\nGpre - win32k!pSpCreatePresent              - GDITAG_PRESENT\nGqnk - win32k!bComputeQuickLookup           - GDITAG_LFONT_QUICKLOOKUP\nGrgb - win32k.sys                           - GDITAG_PALETTE_RGB_XLATE\nGrgn - win32k.sys                           - GDITAG_REGION\nGsem - win32k.sys                           - GDITAG_SEMAPHORE\nGsp  - win32k!pSpCreateSprite               - GDITAG_SPRITE\nGspm - win32k.sys                           - GDITAG_METASPRITE\nGspr - win32k.sys                           - GDITAG_SPRITESCAN\nGsta - win32k.sys                           - GDITAG_STACKTRACE\nGsth - win32k.sys                           - GDITAG_STRETCHBLT\nGsty - win32k!GreExtCreatePen               - GDITAG_PENSTYLE\nGsux - win32k.sys                           - GDITAG_SFM\nGtmp - win32k.sys                           - GDITAG_TEMP\nGTmp - win32k!AllocFreeTmpBuffer            - GDITAG_TEMP_THREADLOCK\nGtmw - win32k!vIFIMetricsToTextMetricW      - GDITAG_TEXTMETRICS\nGtvp - win32k!PFFOBJ::bAddPvtData           - GDITAG_PFF_DATA\nGtvt - win32k!bTriangleMesh                 - GDITAG_TRIANGLE_MESH\nGtxt - win32k.sys                           - GDITAG_TEXT\nGubm - win32k.sys                           - GDITAG_UMODE_BITMAP\nGUma - win32k!GDIEngUserMemAllocNodeAlloc   - GDITAG_ENG_USER_MEM_ALLOC_TABLE\nGump - win32k.sys                           - GDITAG_UMPD\nGvds - win32k!MulEnablePDEV                 - GDITAG_HDEV\nGVdv - win32k.sys                           - GDITAG_VDEV\nGVms - win32k!MulSaveScreenBits             - GDITAG_MULTISAVEBITS\nGVsf - win32k!MulCreateDeviceBitmap         - GDITAG_MDSURF\nGwnd - win32k.sys                           - GDITAG_WNDOBJ\nGxlt - win32k.sys                           - GDITAG_PXLATE\nGxpd - win32k!XUMPDOBJ::XUMPDOBJ            - GDITAG_UMPDOBJ\nknlf - win32k.sys                           - GDITAG_FONT_LINK\nPASf - win32k.sys                           - GDITAG_PANNING_SURFACE\nPSlo - win32k.sys                           - GDITAG_PANNING_SHADOWLOCK\nSsrl - win32k.sys                           - GDITAG_SINGLEREADERLOCK\nTTFC - win32k.sys                           - GDITAG_TT_FONT_CACHE\nTtfd - win32k.sys                           - GDITAG_TT_FONT\nVtfd - win32k.sys                           - GDITAG_VF_FONT\nW32l - win32k!W32PIDLOCK::vInit             - GDITAG_W32PIDLOCK\nSFMb - win32k!SfmTokenArray::EnsureTokenBufferSize - GDITAG_TOKENARRAY\nGnff - win32k.sys                           - GDITAG_NETWORKED_FONT_FILE_TABLE\nGtff - win32k.sys                           - GDITAG_TRUSTED_FONT_FILE_TABLE\nGala - win32k.sys                           - GDITAG_ADAPTER_LUID_ARRAY\nFDpd - win32k.sys                           - GDITAG_UMFD_PDEV\nFDev - win32k.sys                           - GDITAG_UMFD_EVENT\nFDUm - win32k.sys                           - GDITAG_UMFD_UM_BUFFER\nFDtl - win32k.sys                           - GDITAG_UMFD_TLS\nFDrq - win32k.sys                           - GDITAG_UMFD_REQUEST\nGFdk - win32k.sys                           - GDITAG_UMFD_KERNEL_ALLOCATION\nUHFF - win32k.sys                           - GDITAG_UMFD_HFF\nFDat - win32k.sys                           - GDITAG_UMFD_GLYPHATTRS\nGMFF - win32k.sys                           - GDITAG_FONT_MAPPER_FAMILY_FALLBACK\nGFIC - win32k.sys                           - GDITAG_FONT_INTENSITY_CORRECTION\nGhmc - win32k!GdiHandleManager::Create      - GDITAG_HANDLE_MANAGER\nGetc - win32k!GdiHandleEntryTable::_Create  - GDITAG_HANDLE_ENTRY_TABLE\nGelt - win32k!EntryDataLookupTable::Create  - GDITAG_ENTRY_DATA_LOOKUP_TABLE\nGelc - win32k!EntryDataLookupTable::Initialize - GDITAG_ENTRY_DATA_LOOKUP_TABLE_COLUMN\nGpbm - win32k.sys                           - GDITAG_POOL_BITMAP_BITS\nGapl - win32k.sys                           - GDITAG_APAL_TABLE\nGscn - win32k.sys                           - GDITAG_SCAN_ARRAY\nGGG0 - win32k.sys                           - GDITAG_CORE_SESSION_GLOBALS\nGGG1 - win32kbase.sys                       - GDITAG_BASE_SESSION_GLOBALS\nGGG2 - win32kmin.sys                        - GDITAG_MIN_SESSION_GLOBALS\nGGG3 - win32kfull.sys                       - GDITAG_FULL_SESSION_GLOBALS\nGGG4 - win32kfull.sys                       - GDITAG_HT_SESSION_GLOBALS\nGGG5 - win32kfull.sys                       - GDITAG_UMFD_SESSION_GLOBALS\nGGG6 - win32kfull.sys                       - GDITAG_TTFD_SESSION_GLOBALS\nGGG7 - win32kfull.sys                       - GDITAG_TTS_SESSION_GLOBALS\nEKmm - win32kbase!EtwTraceAuditApiQueryAddressVADInformation - ETW_MEMORY_MAPPED_NAME_TAG\nEKsa - win32kbase!CAsyncKeyEventMonitor::operator new - USERTAG_ASYNCKEYEVENT\nUcal - win32k!DriverEntry                   - USERTAG_SERVICE_TABLE\nUiso - win32k!TypeIsolation::Create         - USERTAG_ISOHEAP\nUmam - win32k!UpdateDesktopMonitorNavigationOrder - USERTAG_MONITOR_SPATIAL\nUman - win32k!NtUserSetManipulationInputTarget - USERTAG_DWM_MANIPULATION\nUrdr - win32k!SetRedirectionBitmap          - USERTAG_REDIRECT\nUsac - win32k!_CreateAcceleratorTable       - USERTAG_ACCEL\nUsai - win32k!zzzAttachThreadInput          - USERTAG_ATTACHINFO\nUsal - win32k!InitSwitchWndInfo             - USERTAG_ALTTAB\nUsbg - win32k!xxxLogClipData                - USERTAG_DEBUG\nUsbm - win32k!SetGestureConfigSettings      - USERTAG_BITMASK\nUsbr - win32k!NtUserShutdownBlockReasonCreate - USERTAG_BLOCKREASON\nUsca - win32k!NtUserSetCalibrationData      - USERTAG_CALIBRATIONDATA\nUscb - win32k!_ConvertMemHandle             - USERTAG_CLIPBOARD\nUscc - win32k!AllocCallbackMessage          - USERTAG_CALLBACK\nUscd - win32k!SetWindowCompositionInfo      - USERTAG_COMPOSITIONPROP\nUsCd - win32k!xxxUserChangeDisplaySettings  - USERTAG_CDS\nUsce - win32k!RetrieveLinkCollection        - USERTAG_COLLINK\nUsci - win32k!InitSystemThread              - USERTAG_CLIENTTHREADINFO\nUscI - win32k!CitStart                      - USERTAG_COMPAT_IMPACT\nUscl - win32k!ClassAlloc                    - USERTAG_CLASS\nUscm - win32k!InitScancodeMap               - USERTAG_SCANCODEMAP\nUscp - win32k!CreateDIBPalette              - USERTAG_CLIPBOARDPALETTE\nUscr - win32k!NtUserSetSysColors            - USERTAG_COLORS\nUsct - win32k!CkptRestore                   - USERTAG_CHECKPT\nUscu - win32k!_CreateEmptyCursorObject      - USERTAG_CURSOR\nUscv - win32k!NtUserSetSysColors            - USERTAG_COLORVALUES\nUscw - win32k!CacheAxisChildIndex           - USERTAG_CONTACTRELATIVE\nUsDI - win32k!CreateDeviceInfo              - USERTAG_DEVICEINFO\nUsDc - win32k!NtUserDisplayConfigSetDeviceInfo - USERTAG_DISPLAYCONFIG\nUsDt - win32k!NtUserCtxDisplayIOCtl         - USERTAG_DISPLAYIOCTL\nUsd1 - win32k!FreeListAdd                   - USERTAG_DDE1\nUsd2 - win32k!_DdeSetQualityOfService       - USERTAG_DDE2\nUsd4 - win32k!AddPublicObject               - USERTAG_DDE4\nUsd5 - win32k!xxxCsEvent                    - USERTAG_DDE5\nUsd6 - win32k!xxxCsEvent                    - USERTAG_DDE6\nUsd7 - win32k!xxxCsEvent                    - USERTAG_DDE7\nUsd8 - win32k!xxxMessageEvent               - USERTAG_DDE8\nUsd9 - win32k!xxxCsDdeInitialize            - USERTAG_DDE9\nUsdA - win32k!NewConversation               - USERTAG_DDEa\nUsdB - win32k!Createpxs                     - USERTAG_DDEb\nUsdc - win32k!CreateCacheDC                 - USERTAG_DCE\nUsdD - win32k!NtUserfnDDEINIT               - USERTAG_DDEd\nUsdE - win32k!xxxClientCopyDDEIn1           - USERTAG_DDE\nUsdi - win32k!CreateMonitor                 - USERTAG_DISPLAYINFO\nUsdm - win32k!CreateDCompositionHwndTargetInfo - USERTAG_DCOMPHWNDTARGETINFO\nUsdp - win32k!NtUserDelegateCapturePointers - USERTAG_DELEGATEPOINTERSTRUCT\nUsds - win32k!xxxDragObject                 - USERTAG_DRAGDROP\nUsdv - win32k!NtUserfnINDEVICECHANGE        - USERTAG_DEVICECHANGE\nUsdw - win32k!GetProductString              - USERTAG_DEVICENAME\nUsEC - win32k!AddWEFCOMPInvalidateSListEntry - USERTAG_WSEXCOMPINVALID\nUsed - win32k!AddOrUpdateListener           - USERTAG_EDGY\nUser - win32k!InitCreateUserCrit            - USERTAG_ERESOURCE\nUsex - win32k!IsDeviceExcluded              - USERTAG_EXCLUDEDLIST\nUsfi - win32k!CreatePointerDeviceInfo       - USERTAG_FEATUREIOCTL\nUsfg - win32k!NtUserSetAdditionalForegroundBoostProcesses - USERTAG_ADDITIONALFGBOOST\nUsfl - win32k!InitializeWin32KSyscallFilter - USERTAG_SERVICEFILTER\nUsft - win32k!CreateValidTouchInputInfo     - USERTAG_FORWARDTOUCHMESSAGE\nUsgc - win32k!_StoreGestureConfig           - USERTAG_GESTURECONFIG\nUsgd - win32k!SetGestureConfigSettings      - USERTAG_GESTUREDATA\nUsgh - win32k!NtUserUserHandleGrantAccess   - USERTAG_GRANTEDHANDLES\nUsgi - win32k!NtUserSendGestureInput        - USERTAG_GESTUREINFO\nUsgt - win32k!AddGhost                      - USERTAG_GHOST\nUsha - win32k!AllocateHidData               - USERTAG_HIDDATA\nUshb - win32k!NtUserGetDCompositionHwndBitmap - USERTAG_DCOMPHWNDBITMAP\nUshc - win32k!AllocateHidConfigDesc         - USERTAG_HIDCONFIG\nUshD - Win32k!AllocateHidDesc               - USERTAG_HIDDESC\nUshf - win32k!AllocateHidConfigDesc         - USERTAG_HIDFEATURE\nUshi - win32k!AllocateHidDesc               - USERTAG_HIDINPUT\nUshk - win32k!_RegisterHotKey               - USERTAG_HOTKEY\nUshl - win32k!INLPHLPSTRUCT                 - USERTAG_HELP\nUshP - win32k!HidCreateDeviceInfo           - USERTAG_HIDPREPARSED\nUshr - win32k!AllocateAndLinkHidPageOnlyRequest - USERTAG_HIDPAGEREQUEST\nUshR - win32k!AllocateHidProcessRequest     - USERTAG_HIDPROCREQUEST\nUsht - win32k!AllocateProcessHidTable       - USERTAG_HIDTABLE\nUshT - win32k!AllocateAndLinkHidTLCInfo     - USERTAG_HIDTLC\nUsih - win32k!SetImeHotKey                  - USERTAG_IMEHOTKEY\nUsim - win32k!CreateInputContext            - USERTAG_IME\nUsip - win32k!CreateNode                    - USERTAG_INPUTPOINTERNODE\nUsiq - win23k!CInputQueueProp               - USERTAG_COMPOSITIONINPUTQUEUE\nUsit - win32k!InjectTouchInput              - USERTAG_INJECT_TOUCH\nUsim - win32k!InjectMouseInput              - USERTAG_INJECT_MOUSE\nUsik - win32k!InjectKeyboardInput           - USERTAG_INJECT_KEYBOARD\nUsix - win32k!AllocInputTransformEntry      - USERTAG_INPUT_TRANSFORM\nUisc - win32k!DWMSetInputSystemOutputConfig - USERTAG_INPUT_CONFIG\nUcsc - win32k!SetShellCursorClip            - USERTAG_SHELL_CURSOR_CLIP\nUsjb - win32k!CreateW32Job                  - USERTAG_W32JOB\nUsjx - win32k!JobCalloutAddProcess          - USERTAG_W32JOBEXTRA\nUsKe - win32k!CreateKernelEvent             - USERTAG_KEVENT\nUsKf - win32k!InitCreateUserCrit            - USERTAG_FASTMUTEX\nUsKm - win32k!DriverEntry                   - USERTAG_KMUTEX\nUsKs - win32k!CreateKernelSemaphore         - USERTAG_KSEMAPHORE\nUsKt - win32k!RemoteConnect                 - USERTAG_KTIMER\nUsKw - win32k!xxxDesktopThread              - USERTAG_KWAITBLOCK\nUsKv - win32k!ReadTabletButtonConfig        - USERTAG_KEYVALUEINFORMATION\nUskb - win32k!xxxLoadKeyboardLayoutEx       - USERTAG_KBDLAYOUT\nUskd - win32k!xxxCreateDesktopEx2           - USERTAG_KERNELDESKTOPINFO\nUkdp - win32k!Win32UserInitialize           - USERTAG_KERNELDISPLAYINFO\nUske - win32k!GetKbdExId                    - USERTAG_KBDEXID\nUskf - win32k!LoadKeyboardLayoutFile        - USERTAG_KBDFILE\nUsks - win32k!PostUpdateKeyStateEvent       - USERTAG_KBDSTATE\nUskt - win32k!ReadLayoutFile                - USERTAG_KBDTABLE\nUsla - win32k!InitLockRecordLookaside       - USERTAG_LOOKASIDE\nUsld - win32k!GrowLogIfNecessary            - USERTAG_LOGDESKTOP\nUslr - win32k!InitLockRecordLookaside       - USERTAG_LOCKRECORD\nUsMP - win32k!GeneratePointerMessageFromMouse - USERTAG_MOUSEINPOINTER\nusmd - win32k!xxxSetModernAppWindow         - USERTAG_MODERNDESKTOPAPP\nUsmg - win32k!Magxxx                        - USERTAG_MAGNIFICATION\nUsmi - win32k!MirrorRegion                  - USERTAG_MIRROR\nUsml - win32k!MsgLookupTableAlloc           - USERTAG_MESSAGE_FILTER\nUsmo - win32k!_EnableIAMAccess              - USERTAG_MOSH\nUsmp - win32k!AllocMousePromotionEntry      - USERTAG_MOUSEPROMOTIONENTRY\nUsmr - win32k!SnapshotMonitorRects          - USERTAG_MONITORRECTS\nUsms - win32k!xxxMoveSize                   - USERTAG_MOVESIZE\nUsmt - win32k!xxxMNAllocMenuState           - USERTAG_MENUSTATE\nUsmx - win32k!InitializeMonitorDpiRectsAndTransforms - USERTAG_MATRIX\nUsna - win32k!UserPostNKAPC                 - USERTAG_NKAPC\nUsny - win32k!CreateNotify                  - USERTAG_NOTIFY\nUspa - win32k!AllocPointerMsgParamsList     - USERTAG_POINTERMSGPARAMS\nUspb - win32k!fnPOWERBROADCAST              - USERTAG_POWERBROADCAST\nUspd - win32k!PointerList::AddMsgData       - USERTAG_POINTERINPUTMSGDATA\nUspc - win32k!CreatePointerDeviceInfo       - USERTAG_POINTERDEVICE\nUspC - win32k!AssignPointerCaptureData      - USERTAG_POINTERCAPTUREDATA\nUspe - win32k!AllocPointerInfoNodeList      - USERTAG_POINTERINPUTEVENT\nUspf - win32k!CommitHoldingFrame            - USERTAG_POINTERINPUTFRAME\nUspg - win32k!GeneratePointerMessage        - USERTAG_POINTERINPUTMSG\nUspi - win32k!MapDesktop                    - USERTAG_PROCESSINFO\nUspk - win32k!GetProductString              - USERTAG_PRODUCTSTRING\nUspl - win32k!xxxPollAndWaitForSingleObject - USERTAG_POLLEVENT\nUspm - win32k!MNAllocPopup                  - USERTAG_POPUPMENU\nUspn - win32k!CreateProfileUserName         - USERTAG_PROFILEUSERNAME\nUspo - win32k!QueuePowerRequest             - USERTAG_POWER\nUspp - win32k!AllocateAndLinkHidTLCInfo     - USERTAG_PNP\nUspq - win32k!CreatePointerDeviceInfo       - USERTAG_PARALLELPROP\nUspQ - win32k!AllocPointerQFrameList        - USERTAG_POINTERQFRAME\nUspr - win32k!GetPrivateProfileStruct       - USERTAG_PROFILE\nUsps - win32k!InitPlaySound                 - USERTAG_PLAYSOUND\nUspt - win32k!AllocThreadPointerData        - USERTAG_POINTERTHREADDATA\nUspv - win32k!ContactVisualization          - USERTAG_POINTERVISUALIZATION\nUspw - win32k!CDynamicArray::Add            - USERTAG_DYNAMICARRAY\nUspx - win32k!GetCustomFlickPath            - USERTAG_PTRCFG\nUsph - win32k!CreateProp                    - USERTAG_PROPLISTHEADER\nUspy - win32k!CreateProp                    - USERTAG_PROPLIST\nUsql - win32k!EnsureQMsgLog                 - USERTAG_QMSGLOG\nUsqm - win32k!InitQEntryLookaside           - USERTAG_QMSG\nUsqu - win32k!InitQEntryLookaside           - USERTAG_Q\nUsrd - win32k!StoreRawDataBlock             - USERTAG_POINTERRAWDATA\nUsri - win32k!NtUserRegisterRawInputDevices - USERTAG_RAWINPUTDEVICE\nUsrt - win32k!xxxDrawMenuItemText           - USERTAG_RTL\nUssa - win32k!xxxBroadcastMessage           - USERTAG_SMS_ASYNC\nUssb - win32k!CreateSpb                     - USERTAG_SPB\nUssc - win32k!xxxInterSendMsgEx             - USERTAG_SMS_CAPTURE\nUssd - win32k!xxxAddShadow                  - USERTAG_SHADOW\nUsse - win32k!SetDisconnectDesktopSecurity  - USERTAG_SECURITY\nUssi - win32k!NtUserSendInput               - USERTAG_SENDINPUT\nUssj - win32k!NtUserSendTouchInput          - USERTAG_SENDTOUCHINPUT\nUssm - win32k!InitSMSLookaside              - USERTAG_SMS\nUsss - win32k!xxxBroadcastMessage           - USERTAG_SMS_STRING\nUssw - win32k!_BeginDeferWindowPos          - USERTAG_SWP\nUssh - win32k!zzzSetWindowsHookEx           - USERTAG_HOOK\nUscd - win32k!GetCPD                        - USERTAG_CPD\nUssr - win32k!xxxDesktopRecalc              - USERTAG_ADR\nUssy - win32k!xxxDesktopThread              - USERTAG_SYSTEM\nUsTI - win32k!NtUserQueryInformationThread  - USERTAG_THREADINFORMATION\nUsta - win32k!AssociateShellFrameAppThreads - USERTAG_THREADASSOCIATION\nUstd - win32k!TrackAddDesktop               - USERTAG_TRACKDESKTOP\nUsti - win32k!AllocateW32Thread             - USERTAG_THREADINFO\nUstn - win32k!AllocateW32Thread             - USERTAG_THREADINFONP\nUstk - win32k!HeavyAllocPool                - USERTAG_STACK\nUstm - win32k!InternalSetTimer              - USERTAG_TIMER\nUstl - win32k!AllocateW32Thread             - USERTAG_TLS\nUsto - win32k!xxxConnectService             - USERTAG_TOKEN\nUstp - win32k!FindOrCreateHoldingFrameForDevice   - USERTAG_TOUCHPADSTATE\nUsts - win32k!_Win32CreateSection           - USERTAG_SECTION\nUstx - win32k!NtUserDrawCaptionTemp         - USERTAG_TEXT\nUsty - win32k!NtUserResolveDesktopForWOW    - USERTAG_TEXT2\nUstz - win32k!AllocTouchInputInfo           - USERTAG_TOUCHINPUTINFO\nUsua - win32k!TabletButtonHandler           - USERTAG_TABLETBUTTONUSAGE\nUsub - win32k!NtUserToUnicodeEx             - USERTAG_UNICODEBUFFER\nUsvc - win32k!_GetPointerDeviceProperties   - USERTAG_VALUECAP\nUsvi - win32k!ResizeVisExcludeMemory        - USERTAG_VISRGN\nUsvl - win32k!VWPLAdd                       - USERTAG_VWPL\nUsWE - win32k!ReportHungExplorerToWer       - USERTAG_WER\nUsWP - win32k!SetGlobalWallpaperSettings    - USERTAG_WALLPAPER\nUswc - win32k!SetSwapChainProp              - USERTAG_SWAPCHAIN\nUswd - win32k!xxxCreateWindowEx             - USERTAG_WINDOW\nUswe - win32k!_SetWinEventHook              - USERTAG_WINEVENT\nUswi - win32k!RemoteShadowStart             - USERTAG_WIREDATA\nUswl - win32k!BuildHwndList                 - USERTAG_WINDOWLIST\nUswo - win32k!zzzInitTask                   - USERTAG_WOWTDB\nUswr - win32k!CoreWindowProp                - USERTAG_COREWINDOWPROP\nUsrr - win32k!TouchTargetingRankForRegion   - USERTAG_RANKFORRGN\nUslt - win32k!InitializeWin32PoolTracking   - USERTAG_LEAKEDTAG\nUsI0 - win32k!NSInstrumentation::CBackTraceStorageUnit::Create   - USERTAG_BACKTRACE_STORAGE_UNIT\nUsI1 - win32k!NSInstrumentation::CBackTraceBucket::Create   - USERTAG_BACKTRACE_BUCKET\nUsI2 - win32k!NSInstrumentation::CBackTraceBucket::CreateContext   - USERTAG_BACKTRACE_BUCKET_CONTEXT\nUsI3 - win32k!NSInstrumentation::CBackTraceStoreEx::Create   - USERTAG_BACKTRACE_STORE\nUsI4 - win32k!NSInstrumentation::CBloomFilter::Create   - USERTAG_BLOOMFILTER\nUsI5 - win32k!NSInstrumentation::CPlatformSignal::Create   - USERTAG_INSTRUMENTATION_EVENT\nUsI6 - win32k!NSInstrumentation::CLeakTrackingAllocator::Create   - USERTAG_LEAK_TRACKING_ALLOCATOR\nUsI7 - win32k!NSInstrumentation::CPrioritizedWriterLock::Create   - USERTAG_PRIORITIZED_WRITER_LOCK\nUsI8 - win32k!NSInstrumentation::CPointerHashTable::Create   - USERTAG_POINTER_HASH_TABLE\nUsI9 - win32k!NSInstrumentation::CReferenceTracker::Create   - USERTAG_REFERENCE_TRACKER\nUsIa - win32k!NSInstrumentation::CReferenceTracker::CReferenceCountedType::Create   - USERTAG_REFERENCE_COUNTED_TYPE_HANDLE\nUsIb - win32k!NSInstrumentation::CReferenceTracker::CReferenceCountedType::BeginTrack   - USERTAG_REFERENCE_COUNTED_OBJECT_HANDLE\nUsIc - win32k!NSInstrumentation::CSortedVector::Create   - USERTAG_SORTED_VECTOR\nUsId - win32k!NSInstrumentation::CSharedStorage::InitializeCommon   - USERTAG_SHARED_STORAGE\nUdpi - win32k!CreateSystemFontsForDpi       - USERTAG_DPIMETRICS\nUbwd - win32kbase!NtUserCreateBaseWindow    - USERTAG_BASE_WINDOW\nUbws - win32kmin!xxxMinSendPointerMessageWorker   - USERTAG_BASE_WINDOW_SENTLIST\nUrtm - win32kfull!InitRotationManager       - USERTAG_ROTMGR\nUsws - win32kfull!xxxCreateWindowEx         - USERTAG_WND_SERVER_EXTRA_BYTES\nUdwp - win32kbase!SetMonitorData            - USERTAG_REFCOUNTED_DPI_INFORMATION\nUiim - win32kbase!CTouchProcessor::ForwardInputToManipulationThread - USERTAG_INPUT_INTEROP_MESSAGE\nUsdz - win32kbase!DelayZonePalmRejection::_AddDelayZoneToListInternal   - USERTAG_DELAYZONEINFO\nUvtp - win32kbase!VirtualTouchpadProcessor::GetInstance - USERTAG_VIRTUALTOUCHPAD\nUmen - win32kbase!HMAllocObject - USERTAG_MENU\nUmit - win32kfull!SetLPITEMInfoNoRedraw - USERTAG_MENUITEM\nUsol - win32kmin!InitSmartObjLookaside - USERTAG_SMOBJ_LOOKASIDE\nUgwm - win32kfull!CWindowGroup::operator new - USERTAG_GROUP_WINDOW_MANAGEMENT\nUcwp - win32kfull!CloneWindowPosAndArrangementAsync - USERTAG_CLONEWINDOWPOS\nUsol - win32kbase!InputTraceLogging::PerfRegion::Initialize - USERTAG_PERFREGION_LOOKASIDE\nUagm - win32kbase!CActivationObjectManager::operator new - USERTAG_ACTIVATION_GROUP_MANAGEMENT\nUcnv - win32kbase!InputObjectMap::AllocateBucket - USERTAG_INPUTOBJECTMAP\nUvst - win32kfull!SetVisRgnTrackerProp - USERTAG_VISRGNTRACKER\nUrav - win32kmin!minPostInputMessage - USERTAG_QMSGVARPAYLOAD\nUgcd - win32kbase!NtUserGetInputContainerId - USERTAG_CONTAINERINFO\nUmid - win32kfull!GetMouseDeviceHardwareId - USERTAG_MOUSE_HARDWARE_ID\nUwmc - win32kfull!WindowMargins::CWindowMarginProp::CreateWindowProp - USERTAG_WINDOW_MARGINS_CHANGE\nUmwm - win32kfull!ShellWindowPos::MigrateWindowAsync - USERTAG_MIGRATE_WINDOW_ASYNC\nUttd - win32kfull!_RegisterForTooltipDismissNotification - USERTAG_TOOLTIP_DISMISS\nDCa0 - win32kbase!DirectComposition::CAtlasedRectsMeshMarshaler::_allocate                      - DCOMPOSITIONTAG_ATLASEDRECTSMESHMARSHALER\nDCab - win32kbase!DirectComposition::CAnimationBinding::_allocate                               - DCOMPOSITIONTAG_ANIMATIONBINDING\nDCac - win32kbase!DirectComposition::CApplicationChannel::_allocate                             - DCOMPOSITIONTAG_APPLICATIONCHANNEL\nDCae - win32kbase!DirectComposition::CAnimationMarshaler::SetBufferProperty                     - DCOMPOSITIONTAG_ANIMATIONTIMEEVENTDATA\nDCag - win32kbase!DirectComposition::CAnimationMarshaler::SetBufferProperty                     - DCOMPOSITIONTAG_ANIMATIONSCENARIOGUID\nDCah - win32kbase!DirectComposition::CAnimationControllerMarshaler::_allocate                   - DCOMPOSITIONTAG_ANIMATIONCONTROLLERMARSHALER\nDCal - win32kbase!DirectComposition::CAnimationTimeList::_allocate                              - DCOMPOSITIONTAG_ANIMATIONTIMELIST\nDCam - win32kbase!DirectComposition::CCompositionAmbientLight::_allocate                        - DCOMPOSITIONTAG_AMBIENTLIGHTMARSHALER\nDCan - win32kbase!DirectComposition::CAnimationMarshaler::_allocate                             - DCOMPOSITIONTAG_ANIMATIONMARSHALER\nDCar - win32kbase!DirectComposition::CResourceMarshaler::_allocate                              - DCOMPOSITIONTAG_ABSTRACTRESOURCE\nDCat - win32kbase!DirectComposition::CLegacyAnimationTriggerMarshaler::_allocate                - DCOMPOSITIONTAG_LEGACYANIMATIONTRIGGERMARSHALER\nDCaw - win32kbase!DirectComposition::CAtlasedRectsGroupMarshaler::_allocate                     - DCOMPOSITIONTAG_ATLASEDRECTSGROUPMARSHALER\nDCax - win32kbase!DirectComposition::CAnalogExclusiveViewMarshaler::_allocate                   - DCOMPOSITIONTAG_ANALOGEXCLUSIVEVIEWMARSHALER\nDCay - win32kbase!DirectComposition::CAnalogTextureTargetMarshaler::_allocate                   - DCOMPOSITIONTAG_ANALOGTEXTURETARGETMARSHALER\nDCaz - win32kbase!DirectComposition::CAnalogCompositorMarshaler::_allocate                      - DCOMPOSITIONTAG_ANALOGCOMPOSITORMARSHALER\nDCba - win32kbase!DirectComposition::CBatch::_allocate                                          - DCOMPOSITIONTAG_BATCH\nDCbd - win32kbase!DirectComposition::CBatchDeferralMarshaler::_allocate                         - DCOMPOSITIONTAG_BATCHDEFERRALMARSHALER\nDCbc - win32kbase!DirectComposition::CChannel::_allocate                                        - DCOMPOSITIONTAG_CHANNEL\nDCbf - win32kbase!DirectComposition::Memory::Allocate                                           - DCOMPOSITIONTAG_BUFFER\nDCbl - win32kbase!DirectComposition::CBackChannelMarshaler::_allocate                           - DCOMPOSITIONTAG_BACKCHANNELMARSHALER\nDCbr - win32kbase!DirectComposition::CBatch::CSystemResourceReference::_allocate                - DCOMPOSITIONTAG_BATCH_RESOURCEREF\nDCbs - win32kbase!DirectComposition::CBatchSharedMemoryPool::_allocate                          - DCOMPOSITIONTAG_BATCH_SHARED_MEMORY_POOL\nDCc2 - win32kbase!DirectComposition::CComponentTransform2DMarshaler::_allocate                  - DCOMPOSITIONTAG_COMPONENTTRANSFORM2DMARSHALER\nDCca - win32kbase!DirectComposition::CConditionalExpressionMarshaler::_allocate                 - DCOMPOSITIONTAG_CONDITIONALEXPRESSIONMARSHALER\nDCcb - win32kbase!DirectComposition::CCompositionSurfaceBitmapMarshaler::_allocate              - DCOMPOSITIONTAG_HCOMPBITMAPMARSHALER\nDCcc - win32kbase!DirectComposition::CConnection::_allocate                                     - DCOMPOSITIONTAG_CONNECTION\nDCcg - win32kbase!DirectComposition::CClipGroupMarshaler::_allocate                             - DCOMPOSITIONTAG_CLIPGROUPMARSHALER\nDCch - win32kbase!DirectComposition::CChannelHandleTable::_allocate                             - DCOMPOSITIONTAG_CHANNELHANDLETABLE\nDCck - win32kbase!DirectComposition::CBaseExpressionMarshaler::SetBufferProperty                - DCOMPOSITIONTAG_DEBUGTAG\nDCcl - win32kbase!DirectComposition::CCompositionLight::_allocate                               - DCOMPOSITIONTAG_LIGHTMARSHALER\nDCcm - win32kbase!DirectComposition::CCompositionCubeMapMarshaler::_allocate                    - DCOMPOSITIONTAG_CUBEMAPMARSHALER\nDCco - win32kbase!DirectComposition::CComponentTransform3DMarshaler::_allocate                  - DCOMPOSITIONTAG_COMPONENTTRANSFORM3DMARSHALER\nDCcp - win32kbase!DirectComposition::CPushLockCriticalSection::_allocate                        - DCOMPOSITIONTAG_PUSHLOCKCRITICALSECTION\nDCcq - win32kbase!DirectComposition::CCaptureControllerMarshaler::_allocate                     - DCOMPOSITIONTAG_CAPTURECONTROLLERMARSHALER\nDCcr - win32kbase!DirectComposition::CCaptureRenderTargetMarshaler::_allocate                   - DCOMPOSITIONTAG_CAPTURERENDERTARGETMARSHALER\nDCcs - win32kbase!DirectComposition::CCriticalSection::_allocate                                - DCOMPOSITIONTAG_CRITICALSECTION\nDCct - win32kbase!DirectComposition::CApplicationChannel::AllocateTableEntry                    - DCOMPOSITIONTAG_CHANNELTABLE\nDCcv - win32kbase!DirectComposition::CrossChannelVisualData::_allocate                          - DCOMPOSITIONTAG_CROSSCHANNELVISUALDATA\nDCcw - win32kbase!DirectComposition::CScreenCursorMarshaler::_allocate                          - DCOMPOSITIONTAG_SCREENCURSORMARSHALER\nDCcy - win32kbase!DirectComposition::CCursorVisualMarshaler::_allocate                          - DCOMPOSITIONTAG_CURSORVISUALMARSHALER\nDCd2 - win32kbase!DirectComposition::CStructDynamicArray::_allocate                             - DCOMPOSITIONTAG_STRUCTDYNAMICARRAY\nDCda - win32kbase!DirectComposition::CDCompDynamicArray::_allocate                              - DCOMPOSITIONTAG_DYNAMICARRAY\nDCdb - win32kbase!DirectComposition::CDCompDynamicArrayBase::_allocate                          - DCOMPOSITIONTAG_DYNAMICARRAYBASE\nDCdc - win32kbase!DirectComposition::CDwmChannel::_allocate                                     - DCOMPOSITIONTAG_DWMCHANNEL\nDCdd - win32kbase!DirectComposition::CDDisplayRenderTargetMarshaler::_allocate                  - DCOMPOSITIONTAG_DDISPLAYRENDERTARGETMARSHALER\nDCde - win32kbase!DirectComposition::CDesktopTreeMarshaler::_allocate                           - DCOMPOSITIONTAG_DESKTOPTREEMARSHALER\nDCdj - win32kbase!DirectComposition::CLegacyStereoRenderTargetMarshaler::_allocate              - DCOMPOSITIONTAG_LEGACYSTEREORENDERTARGETMARSHALER\nDCdk - win32kbase!DirectComposition::CLegacyRenderTargetMarshaler::_allocate                    - DCOMPOSITIONTAG_LEGACYRENDERTARGETMARSHALER\nDCdl - win32kbase!DirectComposition::CCompositionDistantLight::_allocate                        - DCOMPOSITIONTAG_DISTANTLIGHTMARSHALER\nDCdm - win32kbase!DirectComposition::CRemoteAppRenderTargetMarshaler::_allocate                 - DCOMPOSITIONTAG_REMOTEAPPRENDERTARGETMARSHALER\nDCdp - win32kbase!DirectComposition::CRemoteRenderTargetMarshaler::_allocate                    - DCOMPOSITIONTAG_REMOTERENDERTARGETMARSHALER\nDCds - win32kbase!DirectComposition::CDropShadowMarshaler::_allocate                            - DCOMPOSITIONTAG_DROPSHADOWMARSHALER\nDCef - win32kbase!DirectComposition::CCompiledEffect::_allocate                                 - DCOMPOSITIONTAG_COMPILEDEFFECTMARSHALER\nDCeg - win32kbase!DirectComposition::CEffectGroupMarshaler::_allocate                           - DCOMPOSITIONTAG_EFFECTGROUPMARSHALER\nDCem - win32kbase!DirectComposition::CBaseExpressionMarshaler::SetBufferProperty                - DCOMPOSITIONTAG_EXPRESSIONTARGETMASK\nDCep - win32kbase!DirectComposition::CCompiledEffectPropertyBag::_allocate                      - DCOMPOSITIONTAG_COMPILEDEFFECTPROPERTYBAGMARSHALER\nDCet - win32kbase!DirectComposition::CCompiledEffectTemplate::_allocate                         - DCOMPOSITIONTAG_COMPILEDEFFECTTEMPLATEMARSHALER\nDCev - win32kbase!DirectComposition::CEvent::_allocate                                          - DCOMPOSITIONTAG_EVENT\nDCex - win32kbase!DirectComposition::CExpressionMarshaler::_allocate                            - DCOMPOSITIONTAG_EXPRESSIONMARSHALER\nDCey - win32kbase!DirectComposition::CEllipseGeometryMarshaler::_allocate                       - DCOMPOSITIONTAG_ELLIPSEGEOMETRYMARSHALER\nDCfb - win32kbase!DirectComposition::CTableTransferEffectMarshaler::SetBufferProperty           - DCOMPOSITIONTAG_FILTEREFFECTBUFFER\nDCfe - win32kbase!DirectComposition::CFilterEffectMarshaler::_allocate                          - DCOMPOSITIONTAG_FILTEREFFECTMARSHALER\nDCff - win32kbase!DirectComposition::CFilterEffectMarshaler::Initialize                         - DCOMPOSITIONTAG_FILTERINPUTFLAGS\nDCfi - win32kbase!DirectComposition::CFilterEffectMarshaler::Initialize                         - DCOMPOSITIONTAG_FILTERINPUTS\nDCfj - win32kbase!DirectComposition::CFilterEffectMarshaler::Initialize                         - DCOMPOSITIONTAG_SUBRECTINPUTFLAGS\nDCg3 - win32kbase!DirectComposition::CTransform3DGroupMarshaler::_allocate                      - DCOMPOSITIONTAG_TRANSFORM3DGROUPMARSHALER\nDCgb - win32kbase!DirectComposition::CGradientLegacyMilBrushMarshaler::_allocate                - DCOMPOSITIONTAG_GRADIENTLEGACYMILBRUSHMARSHALER\nDCgd - win32kbase!DirectComposition::CGdiSpriteBitmapMarshaler::_allocate                       - DCOMPOSITIONTAG_GDISPRITEBITMAPMARSHALER\nDCge - win32kbase!DirectComposition::CGaussianBlurEffectMarshaler::_allocate                    - DCOMPOSITIONTAG_GAUSSIANBLUREFFECTMARSHALER\nDCgg - win32kbase!DirectComposition::CGeometry2DGroupMarshaler::_allocate                       - DCOMPOSITIONTAG_GEOMETRY2DGROUPMARSHALER\nDCgi - win32kbase!DirectComposition::CGenericInkMarshaler::_allocate                            - DCOMPOSITIONTAG_GENERICINKMARSHALER\nDCgm - win32kbase!DirectComposition::CGenericMarshaler::_allocate                               - DCOMPOSITIONTAG_GENERICMARSHALER\nDCgr - win32kbase!DirectComposition::CCompositionGlyphRunMarshaler::_allocate                   - DCOMPOSITIONTAG_COMPOSITIONGLYPHRUNMARSHALER\nDCgs - win32kbase!DirectComposition::CColorGradientStopMarshaler::_allocate                     - DCOMPOSITIONTAG_COLORGRADIENTSTOPMARSHALER\nDCgv - win32kbase!DirectComposition::CGlobalDCompVisualMarshaler::_allocate                     - DCOMPOSITIONTAG_GLOBALDCOMPVISUALMARSHALER\nDChc - win32kbase!DirectComposition::CHolographicCompositionMarshaler::_allocate                - DCOMPOSITIONTAG_HOLOGRAPHICCOMPOSITIONMARSHALER\nDChd - win32kbase!DirectComposition::CHolographicDisplayMarshaler::_allocate                    - DCOMPOSITIONTAG_HOLOGRAPHICDISPLAYMARSHALER\nDChe - win32kbase!DirectComposition::CHolographicExclusiveViewMarshaler::_allocate              - DCOMPOSITIONTAG_HOLOGRAPHICEXCLUSIVEVIEWMARSHALER\nDChi - win32kbase!DirectComposition::CHolographicInteropTextureMarshaler::_allocate             - DCOMPOSITIONTAG_HOLOGRAPHICINTEROPTEXTUREMARSHALER\nDChm - win32kbase!DirectComposition::CHolographicExclusiveModeMarshaler::_allocate              - DCOMPOSITIONTAG_HOLOGRAPHICEXCLUSIVEMODEMARSHALER\nDChp - win32kbase!DirectComposition::CHoverPointerSourceMarshaler::_allocate                    - DCOMPOSITIONTAG_HOVERPOINTERSOURCEMARSHALER\nDCht - win32kbase!DirectComposition::CHwndTargetMarshaler::_allocate                            - DCOMPOSITIONTAG_HWNDTARGETMARSHALER\nDChv - win32kbase!DirectComposition::CHostVisualMarshaler::_allocate                            - DCOMPOSITIONTAG_HOSTVISUALMARSHALER\nDChx - win32kbase!DirectComposition::CHolographicViewer::_allocate                              - DCOMPOSITIONTAG_HOLOGRAPHICVIEWERMARSHALER\nDCia - win32kbase!DirectComposition::CInjectionAnimationMarshaler::_allocate                    - DCOMPOSITIONTAG_INJECTIONANIMATIONMARSHALER\nDCib - win32kbase!DirectComposition::CImageLegacyMilBrushMarshaler::_allocate                   - DCOMPOSITIONTAG_IMAGELEGACYMILBRUSHMARSHALER\nDCic - win32kbase!DirectComposition::CInteractionConfigurationGroup::_allocate                  - DCOMPOSITIONTAG_INTERACTIONCONFIGURATIONGROUP\nDCik - win32kbase!DirectComposition::CInkMarshaler::_allocate                                   - DCOMPOSITIONTAG_INKMARSHALER\nDCio - win32kbase!DirectComposition::CInteractionMarshaler::_allocate                           - DCOMPOSITIONTAG_INTERACTIONMARSHALER\nDCir - win32kbase!DirectComposition::CInteractionTrackerMarshaler::_allocate                    - DCOMPOSITIONTAG_INTERACTIONTRACKERMARSHALER\nDCis - win32kbase!DirectComposition::CInteractionTrackerBindingManagerMarshaler::_allocate      - DCOMPOSITIONTAG_INTERACTIONTRACKERBINDINGMANAGERMARSHALER\nDCit - win32kbase!DirectComposition::CInteractionMarshaler::EnsureTouchConfigurationList        - DCOMPOSITIONTAG_INTERACTIONTOUCHCONFIGURATION\nDCjb - win32kbase!DirectComposition::CBackdropBrushMarshaler::_allocate                         - DCOMPOSITIONTAG_BACKDROPBRUSHMARSHALER\nDCjc - win32kbase!DirectComposition::CColorBrushMarshaler::_allocate                            - DCOMPOSITIONTAG_COLORBRUSHMARSHALER\nDCjd - win32kbase!DirectComposition::CBlurredWallpaperBackdropBrushMarshaler::_allocate         - DCOMPOSITIONTAG_BLURREDWALLPAPERBACKDROPBRUSHMARSHALER\nDCje - win32kbase!DirectComposition::CEffectBrushMarshaler::_allocate                           - DCOMPOSITIONTAG_EFFECTBRUSHMARSHALER\nDCjl - win32kbase!DirectComposition::CLinearGradientBrushMarshaler::_allocate                   - DCOMPOSITIONTAG_LINEARGRADIENTBRUSHMARSHALER\nDCjm - win32kbase!DirectComposition::CMaskBrushMarshaler::_allocate                             - DCOMPOSITIONTAG_MASKBRUSHMARSHALER\nDCjn - win32kbase!DirectComposition::CNineGridBrushMarshaler::_allocate                         - DCOMPOSITIONTAG_NINEGRIDBRUSHMARSHALER\nDCjo - win32kbase!DirectComposition::CRadialGradientBrushMarshaler::_allocate                   - DCOMPOSITIONTAG_RADIALGRADIENTBRUSHMARSHALER\nDCjs - win32kbase!DirectComposition::CSurfaceBrushMarshaler::_allocate                          - DCOMPOSITIONTAG_SURFACEBRUSHMARSHALER\nDCjw - win32kbase!DirectComposition::CWindowBackdropBrushMarshaler::_allocate                   - DCOMPOSITIONTAG_WINDOWBACKDROPBRUSHMARSHALER\nDCkf - win32kbase!DirectComposition::CKeyframeAnimationMarshaler::_allocate                     - DCOMPOSITIONTAG_KEYFRAMEANIMATIONMARSHALER\nDCks - win32kbase!DirectComposition::CKeyframeAnimationMarshaler::SetBufferProperty             - DCOMPOSITIONTAG_KEYFRAMEANIMATIONSCENARIOGUID\nDCkt - win32kbase!DirectComposition::CSkewTransformMarshaler::_allocate                         - DCOMPOSITIONTAG_SKEWTRANSFORMMARSHALER\nDClb - win32kbase!DirectComposition::CLinearGradientLegacyMilBrushMarshaler::_allocate          - DCOMPOSITIONTAG_LINEARGRADIENTLEGACYMILBRUSHMARSHALER\nDClc - win32kbase!DirectComposition::CVisualMarshaler::_allocate                                - DCOMPOSITIONTAG_LAYOUTCONSTRAINTINFO\nDClg - win32kbase!DirectComposition::CLineGeometryMarshaler::_allocate                          - DCOMPOSITIONTAG_LINEGEOMETRYMARSHALER\nDClm - win32kbase!DirectComposition::CAnimationLoggingManager::_allocate                        - DCOMPOSITIONTAG_ANIMATIONLOGGINGMANAGERMARSHALER\nDCls - win32kbase!DirectComposition::CVisualSurfaceMarshaler::_allocate                         - DCOMPOSITIONTAG_VISUALSURFACEMARSHALER\nDClt - win32kbase!DirectComposition::CLinearObjectTableBase::_allocate                          - DCOMPOSITIONTAG_LINEAROBJECTTABLEDATA\nDClv - win32kbase!DirectComposition::CLayerVisualMarshaler::_allocate                           - DCOMPOSITIONTAG_LAYERVISUALMARSHALER\nDCm3 - win32kbase!DirectComposition::CMatrixTransform3DMarshaler::_allocate                     - DCOMPOSITIONTAG_MATRIXTRANSFORM3DMARSHALER\nDCma - win32kbase!DirectComposition::CManipulationTransformMarshaler::_allocate                 - DCOMPOSITIONTAG_MANIPULATIONTRANSFORMMARSHALER\nDCmg - win32kbase!DirectComposition::CMeshGeometryMarshaler::_allocate                          - DCOMPOSITIONTAG_MESHGEOMETRY2DMARSHALER\nDCmh - win32kbase!DirectComposition::CMessageHandleInfo::_allocate                              - DCOMPOSITIONTAG_MESSAGEHANDLEINFO\nDCmi - win32kbase!DirectComposition::CManipulationMarshaler::_allocate                          - DCOMPOSITIONTAG_MANIPULATIONMARSHALER\nDCmm - win32kbase!DirectComposition::CCompositionMipmapSurfaceMarshaler::_allocate              - DCOMPOSITIONTAG_MIPMAPSURFACEMARSHALER\nDCmn - win32kbase!DirectComposition::CSceneSurfaceMaterialInputMarshaler::_allocate             - DCOMPOSITIONTAG_SCENESURFACEMATERIALINPUTMARSHALER\nDCmr - win32kbase!DirectComposition::CSceneMetallicRoughnessMarshaler::_allocate                - DCOMPOSITIONTAG_SCENEMETALLICROUGHNESSMATERIALMARSHALER\nDCmt - win32kbase!DirectComposition::CMatrixTransformMarshaler::_allocate                       - DCOMPOSITIONTAG_MATRIXTRANSFORMMARSHALER\nDCna - win32kbase!DirectComposition::CNaturalAnimationMarshaler::_allocate                      - DCOMPOSITIONTAG_NATURALANIMATIONMARSHALER\nDCnb - win32kbase!DirectComposition::CDeletedNotificationList::EnsureTagAllocation              - DCOMPOSITIONTAG_DELETEDNOTIFICATIONLISTBUFFER\nDCnl - win32kbase!DirectComposition::CDeletedNotificationList::_allocate                        - DCOMPOSITIONTAG_DELETEDNOTIFICATIONLIST\nDCns - win32kbase!DirectComposition::CNaturalAnimationMarshaler::SetBufferProperty              - DCOMPOSITIONTAG_NATURALANIMATIONSCENARIOGUID\nDCoc - win32kbase!DirectComposition::CContainerShapeMarshaler::_allocate                        - DCOMPOSITIONTAG_CONTAINERSHAPEMARSHALER\nDCos - win32kbase!DirectComposition::CSpriteShapeMarshaler::_allocate                           - DCOMPOSITIONTAG_SPRITESHAPEMARSHALER\nDCpb - win32kbase!DirectComposition::CPropertySetMarshaler::_allocate                           - DCOMPOSITIONTAG_PROPERTYSETMARSHALER\nDCpc - win32kbase!DirectComposition::CPrimitveColorMarshaler::_allocate                         - DCOMPOSITIONTAG_PRIMITIVECOLORMARSHALER\nDCpd - win32kbase!DirectComposition::CProcessData::_allocate                                    - DCOMPOSITIONTAG_PROCESSDATA\nDCpg - win32kbase!DirectComposition::CPrimitiveGroupMarshaler::_allocate                        - DCOMPOSITIONTAG_PRIMITIVEGROUPMARSHALER\nDCpl - win32kbase!DirectComposition::PropertySetKernelModeAllocator::AllocateAndClear           - DCOMPOSITIONTAG_PROPERTYSETSTORAGE\nDCpo - win32kbase!DirectComposition::CCompositionPointLight::_allocate                          - DCOMPOSITIONTAG_POINTLIGHTMARSHALER\nDCpr - win32kbase!DirectComposition::CPrimitiveMarshaler::_allocate                             - DCOMPOSITIONTAG_PRIMITIVEMARSHALER\nDCpy - win32kbase!DirectComposition::CPathGeometryMarshaler::_allocate                          - DCOMPOSITIONTAG_PATHGEOMETRYMARSHALER\nDCqa - win32kbase!DirectComposition::CParticleBaseBehaviorMarshaler::_allocate                  - DCOMPOSITIONTAG_PARTICLEBASEBEHAVIORMARSHALER\nDCqb - win32kbase!DirectComposition::CParticleBehaviorMarshaler::_allocate                      - DCOMPOSITIONTAG_PARTICLEBEHAVIORSMARSHALER\nDCqc - win32kbase!DirectComposition::CParticleColorRangeMarshaler::_allocate                    - DCOMPOSITIONTAG_PARTICLECOLORRANGEMARSHALER\nDCqd - win32kbase!DirectComposition::CParticleColorBehaviorMarshaler::_allocate                 - DCOMPOSITIONTAG_PARTICLECOLORBEHAVIORMARSHALER\nDCqe - win32kbase!DirectComposition::CParticleScalarBehaviorMarshaler::_allocate                - DCOMPOSITIONTAG_PARTICLESCALARBEHAVIORMARSHALER\nDCqf - win32kbase!DirectComposition::CParticleVector2BehaviorMarshaler::_allocate               - DCOMPOSITIONTAG_PARTICLEVECTOR2BEHAVIORMARSHALER\nDCqg - win32kbase!DirectComposition::CParticleGeneratorMarshaler::_allocate                     - DCOMPOSITIONTAG_PARTICLEGENERATORMARSHALER\nDCqh - win32kbase!DirectComposition::CParticleVector4BehaviorMarshaler::_allocate               - DCOMPOSITIONTAG_PARTICLEVECTOR4BEHAVIORMARSHALER\nDCqi - win32kbase!DirectComposition::CParticleVector3BehaviorMarshaler::_allocate               - DCOMPOSITIONTAG_PARTICLEVECTOR3BEHAVIORMARSHALER\nDCqr - win32kbase!DirectComposition::CParticleAttractorMarshaler::_allocate                     - DCOMPOSITIONTAG_PARTICLEATTRACTORMARSHALER\nDCqv - win32kbase!DirectComposition::CParticleEmitterVisualMarshaler::_allocate                 - DCOMPOSITIONTAG_PARTICLEEMITTERVISUALMARSHALER\nDCqw - win32kbase!DirectComposition::CParticleVector4RangeMarshaler::_allocate                  - DCOMPOSITIONTAG_PARTICLEVECTOR4RANGEMARSHALER\nDCqx - win32kbase!DirectComposition::CParticleScalarRangeMarshaler::_allocate                   - DCOMPOSITIONTAG_PARTICLESCALARRANGEMARSHALER\nDCqy - win32kbase!DirectComposition::CParticleSizeRangeMarshaler::_allocate                     - DCOMPOSITIONTAG_PARTICLESIZERANGEMARSHALER\nDCqz - win32kbase!DirectComposition::CParticleDirectionRangeMarshaler::_allocate                - DCOMPOSITIONTAG_PARTICLEDIRECTIONRANGEMARSHALER\nDCr3 - win32kbase!DirectComposition::CRotateTransform3DMarshaler::_allocate                     - DCOMPOSITIONTAG_ROTATETRANSFORM3DMARSHALER\nDCrc - win32kbase!DirectComposition::CRectangleClipMarshaler::_allocate                         - DCOMPOSITIONTAG_RECTANGLECLIPMARSHALER\nDCrf - win32kbase!DirectComposition::CVisualReferenceControllerMarshaler::_allocate             - DCOMPOSITIONTAG_VISUALREFERENCECONTROLLERMARSHALER\nDCrg - win32kbase!DirectComposition::CRegionGeometryMarshaler::_allocate                        - DCOMPOSITIONTAG_REGIONGEOMETRYMARSHALER\nDCro - win32kbase!DirectComposition::CRotateTransformMarshaler::_allocate                       - DCOMPOSITIONTAG_ROTATETRANSFORMMARSHALER\nDCrt - win32kbase!DirectComposition::CResourceTable::_allocate                                  - DCOMPOSITIONTAG_RESOURCETABLE\nDCrv - win32kbase!DirectComposition::CRedirectVisualMarshaler::_allocate                        - DCOMPOSITIONTAG_REDIRECTVISUALMARSHALER\nDCs0 - win32kbase!DirectComposition::CSharedResourceMarshaler::_allocate                        - DCOMPOSITIONTAG_SHAREDRESOURCEMARSHALER\nDCs3 - win32kbase!DirectComposition::CScaleTransform3DMarshaler::_allocate                      - DCOMPOSITIONTAG_SCALETRANSFORM3DMARSHALER\nDCsa - win32kbase!DirectComposition::CSnapshotMarshaler::_allocate                              - DCOMPOSITIONTAG_SNAPSHOTMARSHALER\nDCsb - win32kbase!DirectComposition::CCompositionSkyBoxBrushMarshaler::_allocate                - DCOMPOSITIONTAG_SKYBOXBRUSHMARSHALER\nDCsc - win32kbase!DirectComposition::CSystemChannel::_allocate                                  - DCOMPOSITIONTAG_SYSTEMCHANNEL\nDCsd - win32kbase!DirectComposition::CSpriteShapeMarshaler::SetBufferProperty                   - DCOMPOSITIONTAG_STROKEDASHARRAY\nDCse - win32kbase!DirectComposition::CSynchronizationManager::_allocate                         - DCOMPOSITIONTAG_SYNCHRONIZATIONENTRY\nDCsf - win32kbase!DirectComposition::CCrossContainerGuestReadWriteSharedSectionMarshaler        - DCOMPOSITIONTAG_CROSSCONTAINERGUESTREADWRITESHAREDSECTIONMARSHALER\nDCsg - win32kbase!DirectComposition::CCrossContainerHostReadOnlySharedSectionMarshaler          - DCOMPOSITIONTAG_CROSSCONTAINERHOSTREADONLYSHAREDSECTIONMARSHALER\nDCsh - win32kbase!DirectComposition::CShapeVisualMarshaler::_allocate                           - DCOMPOSITIONTAG_SHAPEVISUALMARSHALER\nDCsl - win32kbase!DirectComposition::CScalarMarshaler::_allocate                                - DCOMPOSITIONTAG_SCALARMARSHALER\nDCso - win32kbase!DirectComposition::CSemaphore::_allocate                                      - DCOMPOSITIONTAG_SEMAPHORE\nDCsp - win32kbase!DirectComposition::CCompositionSpotLight::_allocate                           - DCOMPOSITIONTAG_SPOTLIGHTMARSHALER\nDCsr - win32kbase!DirectComposition::CDataSourceReaderMarshaler::_allocate                      - DCOMPOSITIONTAG_DATASOURCEREADERMARSHALER\nDCss - win32kbase!DirectComposition::CSharedSectionMarshaler                                    - DCOMPOSITIONTAG_SHAREDSECTIONMARSHALER\nDCst - win32kbase!DirectComposition::CScaleTransformMarshaler::_allocate                        - DCOMPOSITIONTAG_SCALETRANSFORMMARSHALER\nDCsu - win32kbase!DirectComposition::CSuperWetInkVisualMarshaler::_allocate                     - DCOMPOSITIONTAG_SUPERWETINKVISUALMARSHALER\nDCsv - win32kbase!DirectComposition::CSpriteVisualMarshaler::_allocate                          - DCOMPOSITIONTAG_SPRITEVISUALMARSHALER\nDCsw - win32kbase!DirectComposition::CCompositionSurfaceWrapperMarshaler::_allocate             - DCOMPOSITIONTAG_SURFACEWRAPPERMARSHALER\nDCsy - win32kbase!DirectComposition::CSynchronousSuperWetInkMarshaler::_allocate                - DCOMPOSITIONTAG_SYNCHRONOUSSUPERWETINKMARSHALER\nDCsz - win32kbase!DirectComposition::CSolidColorLegacyMilBrushMarshaler::_allocate              - DCOMPOSITIONTAG_SOLIDCOLORLEGACYMILBRUSHMARSHALER\nDCt3 - win32kbase!DirectComposition::CTranslateTransform3DMarshaler::_allocate                  - DCOMPOSITIONTAG_TRANSLATETRANSFORM3DMARSHALER\nDCtc - win32kbase!DirectComposition::CTileClumpMarshaler::_allocate                             - DCOMPOSITIONTAG_TILECLUMPMARSHALER\nDCtg - win32kbase!DirectComposition::CTransformGroupMarshaler::_allocate                        - DCOMPOSITIONTAG_TRANSFORMGROUPMARSHALER\nDCtl - win32kbase!DirectComposition::CCompositionTextLineMarshaler::_allocate                   - DCOMPOSITIONTAG_COMPOSITIONTEXTLINEMARSHALER\nDCto - win32kbase!DirectComposition::CTelemetryInfo::_allocate                                  - DCOMPOSITIONTAG_TELEMETRYINFO\nDCtr - win32kbase!DirectComposition::CAnimationTriggerMarshaler::_allocate                      - DCOMPOSITIONTAG_ANIMATIONTRIGGERMARSHALER\nDCts - win32kbase!DirectComposition::_allocate                                                  - DCOMPOSITIONTAG_TELEMETRYSTRING\nDCtt - win32kbase!DirectComposition::CTranslateTransformMarshaler::_allocate                    - DCOMPOSITIONTAG_TRANSLATETRANSFORMMARSHALER\nDCtv - win32kbase!DirectComposition::CTextVisualMarshaler::_allocate                            - DCOMPOSITIONTAG_TEXTVISUALMARSHALER\nDCvb - win32kbase!DirectComposition::CViewBoxMarshaler::_allocate                               - DCOMPOSITIONTAG_VIEWBOXMARSHALER\nDCvc - win32kbase!DirectComposition::CVisualMarshaler::AllocateChildrenArray                    - DCOMPOSITIONTAG_VISUALMARSHALERCHILDREN\nDCvg - win32kbase!DirectComposition::CVisualGroupMarshaler::_allocate                           - DCOMPOSITIONTAG_VISUALGROUPMARSHALER\nDCvi - win32kbase!DirectComposition::CVisualMarshaler::_allocate                                - DCOMPOSITIONTAG_VISUALMARSHALER\nDCvm - win32kbase!DirectComposition::CVirtualMonitorCaptureRenderTargetMarshaler::_allocate     - DCOMPOSITIONTAG_VIRTUALMONITORCAPTURERENDERTARGETMARSHALER\nDCvr - win32kbase!DirectComposition::CVisualCaptureMarshaler::_allocate                         - DCOMPOSITIONTAG_VISUALCAPTUREMARSHALER\nDCvs - win32kbase!DirectComposition::CVirtualSurfaceMarshaler::_allocate                        - DCOMPOSITIONTAG_VIRTUALSURFACEMARSHALER\nDCvt - win32kbase!DirectComposition::CVisualTargetMarshaler::_allocate                          - DCOMPOSITIONTAG_VISUALTARGETMARSHALER\nDCvx - win32kbase!DirectComposition::CVisualBitmapMarshaler::_allocate                          - DCOMPOSITIONTAG_VISUALBITMAPMARSHALER\nDCwn - win32kbase!DirectComposition::CWindowNodeMarshaler::_allocate                            - DCOMPOSITIONTAG_WINDOWNODEMARSHALER\nDCwr - win32kbase!DirectComposition::CWeakReferenceBase::_allocate                              - DCOMPOSITIONTAG_WEAKREFERENCE\nDCwt - win32kbase!DirectComposition::CApplicationChannel::GetWeakReferenceBase                  - DCOMPOSITIONTAG_WEAKREFERENCETABLEENTRY\nDCxc - win32kbase!DirectComposition::CCrossChannelChildVisualMarshaler::_allocate               - DCOMPOSITIONTAG_CROSSCHANNELCHILDVISUALMARSHALER\nDCxp - win32kbase!DirectComposition::CCrossChannelParentVisualMarshaler::_allocate              - DCOMPOSITIONTAG_CROSSCHANNELPARENTVISUALMARSHALER\nDCys - win32kbase!DirectComposition::CYCbCrSurfaceMarshaler::_allocate                          - DCOMPOSITIONTAG_YCBCRSURFACEMARSHALER\nDCzc - win32kbase!DirectComposition::CProjectedShadowCasterMarshaler::_allocate                 - DCOMPOSITIONTAG_PROJECTEDSHADOWCASTERMARSHALER\nDCze - win32kbase!DirectComposition::CSceneMesh::_allocate                                      - DCOMPOSITIONTAG_SCENEMESHMARSHALER\nDCzg - win32kbase!DirectComposition::CSharedSectionWrapperMarshaler::_allocate                  - DCOMPOSITIONTAG_SHAREDSECTIONWRAPPERMARSHALER\nDCzh - win32kbase!DirectComposition::CSceneMeshRendererComponentMarshaler::_allocate            - DCOMPOSITIONTAG_SCENEMESHRENDERERCOMPONENTMARSHALER\nDCzr - win32kbase!DirectComposition::CProjectedShadowReceiverMarshaler::_allocate               - DCOMPOSITIONTAG_PROJECTEDSHADOWRECEIVERMARSHALER\nDCzs - win32kbase!DirectComposition::CProjectedShadowSceneMarshaler::_allocate                  - DCOMPOSITIONTAG_PROJECTEDSHADOWSCENEMARSHALER\nDCzt - win32kbase!DirectComposition::CSceneNode::_allocate                                      - DCOMPOSITIONTAG_SCENENODEMARSHALER\nDCzv - win32kbase!DirectComposition::CSceneVisualMarshaler::_allocate                           - DCOMPOSITIONTAG_SCENEVISUALMARSHALER\nDCzx - win32kbase!DirectComposition::CProxyGeometryClipMarshaler::_allocate                     - DCOMPOSITIONTAG_PROXYGEOMETRYCLIPMARSHALER\nDCzy - win32kbase!DirectComposition::CSpatialRemarshalerMarshaler::_allocate                    - DCOMPOSITIONTAG_SPATIALREMARSHALERMARSHALER\nDCzz - win32kbase!DirectComposition::CSceneModelTransformMarshaler::_allocate                   - DCOMPOSITIONTAG_SCENEMODELTRANSFORMMARSHALER\nCSMb - dxgkrnl!CCompositionBuffer::Create        - COMPOSITIONSURFACEMANAGER_BUFFER\nCSMr - dxgkrnl!CBufferRealization::Create        - COMPOSITIONSURFACEMANAGER_REALIZATION\nCSMi - dxgkrnl!NtOpenCompositionSurfaceRealizationInfo - COMPOSITIONSURFACEMANAGER_REALIZATIONINFOBUFFER\nTMcb - dxgkrnl!CCompositionToken::Initialize                 - TOKENMANAGER_COMPOSITIONTOKENBUFFER\nTMcc - dxgkrnl!CCompositionFrameCollection                   - TOKENMANAGER_COMPOSITIONFRAMECOLLECTION\nTMce - dxgkrnl!CCompositionFrame::TokenTableEntry::Allocate  - TOKENMANAGER_TOKENTABLEENTRY\nTMcf - dxgkrnl!CCompositionFrame::Create                     - TOKENMANAGER_COMPOSITIONFRAME\nTMlt - dxgkrnl!CTokenManager::EnsureLegacyTokenBuffer        - TOKENMANAGER_LEGACYTOKENBUFFER\nTMsg - dxgkrnl!CreateSessionTokenManager                     - TOKENMANAGER_SESSIONGLOBAL\nTMtb - dxgkrnl!CLegacyTokenBuffer::TokenBlock::Create        - TOKENMANAGER_TOKENBLOCK\nTMte - dxgkrnl!CTokenManager::TokenQueueTableEntry::Allocate - TOKENMANAGER_TOKENQUEUETABLEENTRY\nTMto - dxgkrnl!CToken::Create                                - TOKENMANAGER_TOKENOBJECT\nTMtq - dxgkrnl!CTokenQueue::Create                           - TOKENMANAGER_TOKENQUEUE\nTMac - dxgkrnl!CAdapter::Create                              - TOKENMANAGER_ADAPTER\nTMcc - dxgkrnl!CAdapterCollection::Create                    - TOKENMANAGER_ADAPTERCOLLECTION\nIMhq - win32k!CInputQueue::Create                           - INPUTMANAGER_INPUTQUEUE\nIMsg - win32k!CInputManager::Create                         - INPUTMANAGER_SESSIONGLOBAL\nFCai - dxgkrnl!CEndpointResourceStateManager::PrepareTokenInitInfoForDWM - FLIPCONTENT_AUXILIARYPRESENTINFO\nFCbm - dxgkrnl!CBackchannelManager::CBackchannelManager - FLIPCONTENT_BACKCHANNELMANAGER\nFCbr - dxgkrnl!CPoolBufferResource::Create - FLIPCONTENT_BUFFERRESOURCE\nFCbs - dxgkrnl!CPoolBufferResourceState::operator new - FLIPCONTENT_BUFFERRESOURCESTATE\nFCcr - dxgkrnl!CContentResource::Create - FLIPCONTENT_CONTENTRESOURCE\nFCcm - dxgkrnl!CFlipConsumerMessage::operator new - FLIPCONTENT_CONSUMERMESSAGE\nFCii - dxgkrnl!CEndpointResourceStateManager::PrepareTokenInitInfoForDWM - FLIPCONTENT_INDEPENDENTFLIPINFO\nFCpb - dxgkrnl!CreateFlipPropertySet - FLIPCONTENT_PROPERTYBLOBBUFFER\nFCpc - dxgkrnl!CFlipPresentCancel::operator new - FLIPCONTENT_PRESENTCANCEL\nFCph - dxgkrnl!CFlipManager::Initialize - FLIPCONTENT_DEBUG_PRESENTHISTORY\nFCpi - dxgkrnl!CreateFlipPropertySet - FLIPCONTENT_PROPERTYBLOBINDEXBUFFER\nFCps - dxgkrnl!CFlipPropertySet::operator new - FLIPCONTENT_PROPERTYSET\nFCpu - dxgkrnl!CFlipManager::ProcessTokenCreate - FLIPCONTENT_PRESENTUPDATE\nFCrs - dxgkrnl!CContentResourceState::operator new - FLIPCONTENT_CONTENTRESOURCESTATE\nFCsb - dxgkrnl!CEndpointResourceStateManager::PrepareBufferSignals - FLIPCONTENT_SIGNAL_BUFFERARRAY\nFCsi - dxgkrnl!CFlipManagerSignal::operator new - FLIPCONTENT_SIGNAL\nFCub - dxgkrnl!CEndpointResourceStateManager::PrepareIncrementalUpdateForStateManager - FLIPCONTENT_INCREMENTALRESOURCEUPDATEFORCONSUMER\nFCuu - dxgkrnl!CEndpointResourceStateManager::PrepareIncrementalUpdateForUser - FLIPCONTENT_INCREMENTALRESOURCEUPDATEFORUSER\nFCwr - dxgkrnl!CFlipWaitedConsumerReturn::operator new - FLIPCONTENT_WAITEDCONSUMERRETURN\n\u001a"
  },
  {
    "path": "SystemInformer/runas.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2013\n *     dmex    2018-2023\n *\n */\n\n/*\n * The run-as mechanism has three stages:\n * 1. The user enters the information into the dialog box. Here it is decided whether the run-as\n *    service is needed. If it is not, PhCreateProcessAsUser is called directly. Otherwise,\n *    PhExecuteRunAsCommand2 is called for stage 2.\n * 2. PhExecuteRunAsCommand2 creates a random service name and tries to create the service and\n *    execute it (using PhExecuteRunAsCommand). If the process has insufficient permissions, an\n *    elevated instance of phsvc is started and PhSvcCallExecuteRunAsCommand is called.\n * 3. The service is started, and sets up an instance of phsvc with the same random service name as\n *    its port name. Either the original or elevated Process Hacker instance then calls\n *    PhSvcCallInvokeRunAsService to complete the operation.\n */\n\n/*\n *\n * ProcessHacker.exe (user, limited privileges)\n *   *                       | ^\n *   |                       | | phsvc API (LPC)\n *   |                       | |\n *   |                       v |\n *   ProcessHacker.exe (user, full privileges)\n *         | ^                    | ^\n *         | | SCM API (RPC)      | |\n *         | |                    | |\n *         v |                    | | phsvc API (LPC)\n * services.exe                   | |\n *   *                            | |\n *   |                            | |\n *   |                            | |\n *   |                            v |\n *   ProcessHacker.exe (NT AUTHORITY\\SYSTEM)\n *     *\n *     |\n *     |\n *     |\n *     program.exe\n */\n\n#include <phapp.h>\n\n#include <shlwapi.h>\n#include <winsta.h>\n\n#include <apiimport.h>\n#include <appresolver.h>\n#include <actions.h>\n#include <lsasup.h>\n#include <phconsole.h>\n#include <phsvc.h>\n#include <phsvccl.h>\n#include <phsettings.h>\n#include <settings.h>\n#include <svcsup.h>\n#include <mainwnd.h>\n\ntypedef struct _RUNAS_DIALOG_CONTEXT\n{\n    HWND WindowHandle;\n    HWND ProgramComboBoxWindowHandle;\n    HWND UserComboBoxWindowHandle;\n    HWND TypeComboBoxWindowHandle;\n    HWND PasswordEditWindowHandle;\n    HWND SessionEditWindowHandle;\n    HWND DesktopEditWindowHandle;\n    HANDLE ProcessId;\n    PPH_STRING CurrentWinStaName;\n} RUNAS_DIALOG_CONTEXT, *PRUNAS_DIALOG_CONTEXT;\n\ntypedef struct _PH_RUNAS_SESSION_ITEM\n{\n    ULONG SessionId;\n    PPH_STRING SessionName;\n} PH_RUNAS_SESSION_ITEM, *PPH_RUNAS_SESSION_ITEM;\n\ntypedef struct _PH_RUNAS_DESKTOP_ITEM\n{\n    PPH_STRING DesktopName;\n} PH_RUNAS_DESKTOP_ITEM, *PPH_RUNAS_DESKTOP_ITEM;\n\nINT_PTR CALLBACK PhpRunAsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpRunFileWndProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhRunAsPackageWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nNTSTATUS PhRunAsUpdateDesktop(\n    _In_ PSID UserSid\n    );\n\nNTSTATUS PhRunAsUpdateWindowStation(\n    _In_opt_ PSID UserSid,\n    _In_opt_ PSID LogonSid\n    );\n\n//NTSTATUS PhSetDesktopWinStaAccess(\n//    _In_ HWND WindowHandle\n//    );\n\nBOOLEAN PhRunAsExecuteCommandPrompt(\n    _In_ HWND WindowHandle\n    );\n\nVOID PhpSplitUserName(\n    _In_ PCWSTR UserName,\n    _Out_opt_ PPH_STRING* DomainPart,\n    _Out_opt_ PPH_STRING* UserPart\n    );\n\nstatic CONST PH_KEY_VALUE_PAIR PhpLogonTypePairs[] =\n{\n    SIP(L\"Batch\", LOGON32_LOGON_BATCH),\n    SIP(L\"Interactive\", LOGON32_LOGON_INTERACTIVE),\n    SIP(L\"Network\", LOGON32_LOGON_NETWORK),\n    SIP(L\"New credentials\", LOGON32_LOGON_NEW_CREDENTIALS),\n    SIP(L\"Service\", LOGON32_LOGON_SERVICE)\n};\n\nstatic WCHAR RunAsOldServiceName[32] = L\"\";\nstatic PH_QUEUED_LOCK RunAsOldServiceLock = PH_QUEUED_LOCK_INIT;\n\nstatic PPH_STRING RunAsServiceName;\nstatic SERVICE_STATUS_HANDLE RunAsServiceStatusHandle;\nstatic PHSVC_STOP RunAsServiceStop;\n\nVOID PhShowRunAsDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_opt_ HANDLE ProcessId\n    )\n{\n    PhDialogBox(\n        NtCurrentImageBase(),\n        MAKEINTRESOURCE(IDD_RUNAS),\n        PhCsForceNoParent ? NULL : ParentWindowHandle,\n        PhpRunAsDlgProc,\n        ProcessId\n        );\n}\n\nBOOLEAN PhShowRunFileDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    // Note: Task Manager launches the command prompt instead of RunFileDlg\n    // when holding CTRL and selecting the 'Run New Task' menu. (dmex)\n    // Todo: The CTRL key is required for the menu hotkey. (GH #1859)\n    //if (PhGetKeyState(VK_CONTROL))\n    //{\n    //    if (PhRunAsExecuteCommandPrompt(ParentWindowHandle))\n    //        return TRUE;\n    //}\n\n    if (PhDialogBox(\n        NtCurrentImageBase(),\n        MAKEINTRESOURCE(IDD_RUNFILEDLG),\n        ParentWindowHandle,\n        PhpRunFileWndProc,\n        NULL\n        ) == IDOK)\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n\n    // Removed from guisup.c (dmex)\n    //BOOL (WINAPI *RunFileDlg_I)(\n    //    _In_ HWND hwndOwner,\n    //    _In_opt_ HICON hIcon,\n    //    _In_opt_ LPCWSTR lpszDirectory,\n    //    _In_opt_ LPCWSTR lpszTitle,\n    //    _In_opt_ LPCWSTR lpszDescription,\n    //    _In_ ULONG uFlags\n    //    );\n    //PVOID shell32Handle;\n    //\n    //if (shell32Handle = PhLoadLibrary(L\"shell32.dll\"))\n    //{\n    //    if (RunFileDlg_I = PhGetDllBaseProcedureAddress(shell32Handle, NULL, 61))\n    //    {\n    //        result = !!RunFileDlg_I(\n    //            WindowHandle,\n    //            WindowIcon,\n    //            WorkingDirectory,\n    //            WindowTitle,\n    //            WindowDescription,\n    //            Flags\n    //            );\n    //    }\n    //\n    //    PhFreeLibrary(shell32Handle);\n    //}\n}\n\nVOID PhShowRunAsPackageDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    PhDialogBox(\n        NtCurrentImageBase(),\n        MAKEINTRESOURCE(IDD_RUNPACKAGE),\n        NULL,\n        PhRunAsPackageWndProc,\n        PhCsForceNoParent ? NULL : ParentWindowHandle\n        );\n}\n\nBOOLEAN IsServiceAccount(\n    _In_ PPH_STRING UserName\n    )\n{\n    BOOLEAN serviceAccount = FALSE;\n    PPH_STRING localSystemSidName;\n    PPH_STRING localServiceSidName;\n    PPH_STRING localNetworkSidName;\n\n    localSystemSidName = PhGetSidFullName((PSID)&PhSeLocalSystemSid, TRUE, NULL);\n    localServiceSidName = PhGetSidFullName((PSID)&PhSeLocalServiceSid, TRUE, NULL);\n    localNetworkSidName = PhGetSidFullName((PSID)&PhSeNetworkServiceSid, TRUE, NULL);\n\n    if (\n        PhEqualString(localSystemSidName, UserName, TRUE) ||\n        PhEqualString(localServiceSidName, UserName, TRUE) ||\n        PhEqualString(localNetworkSidName, UserName, TRUE)\n        )\n    {\n        serviceAccount = TRUE;\n    }\n\n    PhDereferenceObject(localNetworkSidName);\n    PhDereferenceObject(localServiceSidName);\n    PhDereferenceObject(localSystemSidName);\n\n    return serviceAccount;\n}\n\nBOOLEAN IsCurrentUserAccount(\n    _In_ PPH_STRING UserName\n    )\n{\n    PPH_STRING userName;\n\n    if (userName = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE))\n    {\n        if (PhEndsWithString(userName, UserName, TRUE))\n        {\n            PhDereferenceObject(userName);\n            return TRUE;\n        }\n\n        PhDereferenceObject(userName);\n    }\n\n    return FALSE;\n}\n\nPPH_STRING PhpGetCurrentDesktopInfo(\n    VOID\n    )\n{\n    PPH_STRING desktopInfo = NULL;\n    PPH_STRING winstationName = NULL;\n    PPH_STRING desktopName = NULL;\n\n    winstationName = PhGetCurrentWindowStationName();\n    desktopName = PhGetCurrentThreadDesktopName();\n\n    if (winstationName && desktopName)\n    {\n        desktopInfo = PhConcatStringRef3(&winstationName->sr, &PhNtPathSeparatorString, &desktopName->sr);\n    }\n\n    if (PhIsNullOrEmptyString(desktopInfo))\n    {\n        PhMoveReference(&desktopInfo, PhCreateStringFromUnicodeString(&NtCurrentPeb()->ProcessParameters->DesktopInfo));\n    }\n\n    if (winstationName)\n        PhDereferenceObject(winstationName);\n    if (desktopName)\n        PhDereferenceObject(desktopName);\n\n    return desktopInfo;\n}\n\nBOOLEAN PhpEnumerateRecentProgramsToComboBox(\n    _In_ PPH_STRINGREF Command,\n    _In_ PVOID Context\n    )\n{\n    ComboBox_AddString(Context, PhGetStringRefZ(Command));\n    return TRUE;\n}\n\nNTSTATUS PhpEnumerateAccountsToComboBox(\n    _In_ PPH_STRINGREF AccountName,\n    _In_ PVOID Context\n    )\n{\n    ComboBox_AddString(Context, PhGetStringRefZ(AccountName));\n    return STATUS_SUCCESS;\n}\n\nstatic VOID PhpAddProgramsToComboBox(\n    _In_ HWND ComboBoxHandle\n    )\n{\n    PhDeleteComboBoxStrings(ComboBoxHandle, TRUE);\n\n    PhEnumerateRecentList(PhpEnumerateRecentProgramsToComboBox, ComboBoxHandle);\n}\n\nstatic VOID PhpAddAccountsToComboBox(\n    _In_ HWND ComboBoxHandle\n    )\n{\n    PhDeleteComboBoxStrings(ComboBoxHandle, TRUE);\n\n    ComboBox_AddString(ComboBoxHandle, PH_AUTO_T(PH_STRING, PhGetSidFullName((PSID)&PhSeLocalSystemSid, TRUE, NULL))->Buffer);\n    ComboBox_AddString(ComboBoxHandle, PH_AUTO_T(PH_STRING, PhGetSidFullName((PSID)&PhSeLocalServiceSid, TRUE, NULL))->Buffer);\n    ComboBox_AddString(ComboBoxHandle, PH_AUTO_T(PH_STRING, PhGetSidFullName((PSID)&PhSeNetworkServiceSid, TRUE, NULL))->Buffer);\n\n    PhEnumerateAccounts(PhpEnumerateAccountsToComboBox, ComboBoxHandle);\n}\n\nstatic VOID PhpFreeSessionsComboBox(\n    _In_ HWND ComboBoxHandle\n    )\n{\n    PPH_RUNAS_SESSION_ITEM entry;\n    INT total;\n    INT i;\n\n    if ((total = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR)\n        return;\n\n    for (i = 0; i < total; i++)\n    {\n        entry = (PPH_RUNAS_SESSION_ITEM)ComboBox_GetItemData(ComboBoxHandle, i);\n\n        if (entry->SessionName)\n            PhDereferenceObject(entry->SessionName);\n\n        PhFree(entry);\n    }\n\n    ComboBox_ResetContent(ComboBoxHandle);\n}\n\nstatic VOID PhpAddSessionsToComboBox(\n    _In_ HWND ComboBoxHandle\n    )\n{\n    PSESSIONIDW sessions;\n    ULONG numberOfSessions;\n    ULONG i;\n\n    PhpFreeSessionsComboBox(ComboBoxHandle);\n\n    if (WinStationEnumerateW(WINSTATION_CURRENT_SERVER, &sessions, &numberOfSessions))\n    {\n        for (i = 0; i < numberOfSessions; i++)\n        {\n            PPH_STRING menuString;\n            WINSTATIONINFORMATION winStationInfo;\n            ULONG returnLength;\n\n            if (!WinStationQueryInformationW(\n                WINSTATION_CURRENT_SERVER,\n                sessions[i].SessionId,\n                WinStationInformation,\n                &winStationInfo,\n                sizeof(WINSTATIONINFORMATION),\n                &returnLength\n                ))\n            {\n                winStationInfo.Domain[0] = UNICODE_NULL;\n                winStationInfo.UserName[0] = UNICODE_NULL;\n            }\n\n            if (\n                winStationInfo.UserName[0] != UNICODE_NULL &&\n                sessions[i].WinStationName[0] != UNICODE_NULL\n                )\n            {\n                SIZE_T formatLength;\n                PH_FORMAT format[8];\n                WCHAR formatBuffer[0x80];\n\n                // %lu: %s (%s\\\\%s)\n                PhInitFormatU(&format[0], sessions[i].SessionId);\n                PhInitFormatS(&format[1], L\": \");\n                PhInitFormatS(&format[2], sessions[i].WinStationName);\n                PhInitFormatS(&format[3], L\" (\");\n                PhInitFormatS(&format[4], winStationInfo.Domain);\n                PhInitFormatC(&format[5], L'\\\\');\n                PhInitFormatS(&format[6], winStationInfo.UserName);\n                PhInitFormatC(&format[7], L')');\n\n                if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), &formatLength))\n                {\n                    PH_STRINGREF text;\n\n                    text.Length = formatLength - sizeof(UNICODE_NULL);\n                    text.Buffer = formatBuffer;\n\n                    menuString = PhCreateString2(&text);\n                }\n                else\n                {\n                    //menuString = PhFormatString(L\"%lu: %s (%s\\\\%s)\",\n                    //    sessions[i].SessionId,\n                    //    sessions[i].WinStationName,\n                    //    winStationInfo.Domain,\n                    //    winStationInfo.UserName\n                    //    );\n\n                    menuString = PhFormat(format, RTL_NUMBER_OF(format), 0);\n                }\n            }\n            else if (winStationInfo.UserName[0] != UNICODE_NULL)\n            {\n                menuString = PhFormatString(L\"%lu: %s\\\\%s\",\n                    sessions[i].SessionId,\n                    winStationInfo.Domain,\n                    winStationInfo.UserName\n                    );\n            }\n            else if (sessions[i].WinStationName[0] != UNICODE_NULL)\n            {\n                SIZE_T formatLength;\n                PH_FORMAT format[3];\n                WCHAR formatBuffer[0x80];\n\n                // %lu: %s\n                PhInitFormatU(&format[0], sessions[i].SessionId);\n                PhInitFormatS(&format[1], L\": \");\n                PhInitFormatS(&format[2], sessions[i].WinStationName);\n\n                if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), &formatLength))\n                {\n                    PH_STRINGREF text;\n\n                    text.Length = formatLength - sizeof(UNICODE_NULL);\n                    text.Buffer = formatBuffer;\n\n                    menuString = PhCreateString2(&text);\n                }\n                else\n                {\n                    //menuString = PhFormatString(L\"%lu: %s\",\n                    //    sessions[i].SessionId,\n                    //    sessions[i].WinStationName\n                    //    );\n\n                    menuString = PhFormat(format, RTL_NUMBER_OF(format), 0);\n                }\n            }\n            else\n            {\n                menuString = PhFormatUInt64(sessions[i].SessionId, FALSE);\n            }\n\n            {\n                PPH_RUNAS_SESSION_ITEM entry;\n                INT itemIndex;\n\n                entry = PhAllocate(sizeof(PH_RUNAS_SESSION_ITEM));\n                entry->SessionId = sessions[i].SessionId;\n                entry->SessionName = menuString;\n\n                if ((itemIndex = ComboBox_AddString(ComboBoxHandle, menuString->Buffer)) != CB_ERR)\n                {\n                    ComboBox_SetItemData(ComboBoxHandle, itemIndex, entry);\n                }\n            }\n        }\n\n        WinStationFreeMemory(sessions);\n    }\n}\n\ntypedef struct _RUNAS_DIALOG_DESKTOP_CALLBACK\n{\n    PPH_LIST DesktopList;\n    PPH_STRING WinStaName;\n} RUNAS_DIALOG_DESKTOP_CALLBACK, *PRUNAS_DIALOG_DESKTOP_CALLBACK;\n\nstatic BOOL CALLBACK EnumDesktopsCallback(\n    _In_ PWSTR DesktopName,\n    _In_ LPARAM Context\n    )\n{\n    PRUNAS_DIALOG_DESKTOP_CALLBACK context = (PRUNAS_DIALOG_DESKTOP_CALLBACK)Context;\n\n    PhAddItemList(context->DesktopList, PhConcatStrings(\n        3,\n        PhGetString(context->WinStaName),\n        L\"\\\\\",\n        DesktopName\n        ));\n\n    return TRUE;\n}\n\nstatic VOID PhpFreeDesktopsComboBox(\n    _In_ HWND ComboBoxHandle\n    )\n{\n    PPH_RUNAS_DESKTOP_ITEM entry;\n    INT total;\n    INT i;\n\n    if ((total = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR)\n        return;\n\n    for (i = 0; i < total; i++)\n    {\n        entry = (PPH_RUNAS_DESKTOP_ITEM)ComboBox_GetItemData(ComboBoxHandle, i);\n\n        if (entry->DesktopName)\n            PhDereferenceObject(entry->DesktopName);\n\n        PhFree(entry);\n    }\n\n    ComboBox_ResetContent(ComboBoxHandle);\n}\n\nstatic VOID PhpAddDesktopsToComboBox(\n    _In_ HWND ComboBoxHandle\n    )\n{\n    ULONG i;\n    RUNAS_DIALOG_DESKTOP_CALLBACK callback;\n\n    PhpFreeDesktopsComboBox(ComboBoxHandle);\n\n    callback.DesktopList = PhCreateList(10);\n    callback.WinStaName = PhGetCurrentWindowStationName();\n\n    EnumDesktops(GetProcessWindowStation(), EnumDesktopsCallback, (LPARAM)&callback);\n\n    for (i = 0; i < callback.DesktopList->Count; i++)\n    {\n        INT itemIndex = ComboBox_AddString(\n            ComboBoxHandle,\n            PhGetString(callback.DesktopList->Items[i])\n            );\n\n        if (itemIndex != CB_ERR)\n        {\n            PPH_RUNAS_DESKTOP_ITEM entry;\n\n            entry = PhAllocate(sizeof(PH_RUNAS_DESKTOP_ITEM));\n            entry->DesktopName = callback.DesktopList->Items[i];\n\n            ComboBox_SetItemData(ComboBoxHandle, itemIndex, entry);\n        }\n    }\n\n    PhDereferenceObject(callback.DesktopList);\n    PhDereferenceObject(callback.WinStaName);\n}\n\nVOID SetDefaultProgramEntry(\n    _In_ HWND ComboBoxHandle\n    )\n{\n    //Edit_SetText(ComboBoxHandle, PhaGetStringSetting(SETTING_RUN_AS_PROGRAM)->Buffer);\n    ComboBox_SetCurSel(ComboBoxHandle, 0);\n}\n\nVOID SetDefaultUserEntry(\n    _In_ PRUNAS_DIALOG_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HWND ComboBoxHandle\n    )\n{\n    if (!Context->ProcessId)\n    {\n        PPH_STRING runAsUserName = PhaGetStringSetting(SETTING_RUN_AS_USER_NAME);\n        INT runAsUserNameIndex = CB_ERR;\n\n        // Fire the user name changed event so we can fix the logon type.\n        if (!PhIsNullOrEmptyString(runAsUserName))\n        {\n            runAsUserNameIndex = ComboBox_FindString(\n                ComboBoxHandle,\n                0,\n                PhGetString(runAsUserName)\n                );\n        }\n\n        if (runAsUserNameIndex != CB_ERR)\n            ComboBox_SetCurSel(ComboBoxHandle, runAsUserNameIndex);\n        else\n            ComboBox_SetCurSel(ComboBoxHandle, 0);\n\n        SendMessage(WindowHandle, WM_COMMAND, MAKEWPARAM(IDC_USERNAME, CBN_EDITCHANGE), 0);\n    }\n    else\n    {\n        HANDLE processHandle;\n        HANDLE tokenHandle;\n        PPH_STRING userName;\n\n        if (NT_SUCCESS(PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            Context->ProcessId\n            )))\n        {\n            if (NT_SUCCESS(PhOpenProcessToken(\n                processHandle,\n                TOKEN_QUERY,\n                &tokenHandle\n                )))\n            {\n                if (userName = PhGetTokenUserString(tokenHandle, TRUE))\n                {\n                    PhSetWindowText(ComboBoxHandle, userName->Buffer);\n                    PhDereferenceObject(userName);\n                }\n\n                NtClose(tokenHandle);\n            }\n\n            NtClose(processHandle);\n        }\n\n        EnableWindow(Context->UserComboBoxWindowHandle, FALSE);\n        EnableWindow(Context->PasswordEditWindowHandle, FALSE);\n        EnableWindow(Context->TypeComboBoxWindowHandle, FALSE);\n    }\n}\n\nVOID SetDefaultSessionEntry(\n    _In_ HWND ComboBoxHandle\n    )\n{\n    INT sessionCount;\n    ULONG currentSessionId = 0;\n\n    if (!NT_SUCCESS(PhGetProcessSessionId(NtCurrentProcess(), &currentSessionId)))\n        return;\n\n    if ((sessionCount = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR)\n        return;\n\n    for (INT i = 0; i < sessionCount; i++)\n    {\n        PPH_RUNAS_SESSION_ITEM entry = (PPH_RUNAS_SESSION_ITEM)ComboBox_GetItemData(ComboBoxHandle, i);\n\n        if (entry && entry->SessionId == currentSessionId)\n        {\n            ComboBox_SetCurSel(ComboBoxHandle, i);\n            break;\n        }\n    }\n}\n\nVOID SetDefaultDesktopEntry(\n    _In_ PRUNAS_DIALOG_CONTEXT Context,\n    _In_ HWND ComboBoxHandle\n    )\n{\n    INT sessionCount;\n    PPH_STRING desktopName;\n\n    if (!(desktopName = PhpGetCurrentDesktopInfo()))\n        return;\n\n    if ((sessionCount = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR)\n    {\n        PhClearReference(&desktopName);\n        return;\n    }\n\n    for (INT i = 0; i < sessionCount; i++)\n    {\n        PPH_RUNAS_DESKTOP_ITEM entry = (PPH_RUNAS_DESKTOP_ITEM)ComboBox_GetItemData(ComboBoxHandle, i);\n\n        if (PhEqualStringRef(&entry->DesktopName->sr, &desktopName->sr, TRUE))\n        {\n            ComboBox_SetCurSel(ComboBoxHandle, i);\n            break;\n        }\n    }\n\n    PhClearReference(&desktopName);\n}\n\n_Success_(return)\nBOOLEAN PhRunAsGetLogonSid(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PSID* UserSid,\n    _Out_ PSID* LogonSid\n    )\n{\n    PSID userSid = NULL;\n    PSID groupSid = NULL;\n    HANDLE tokenHandle;\n\n    if (NT_SUCCESS(PhOpenProcessToken(\n        ProcessHandle,\n        TOKEN_QUERY,\n        &tokenHandle\n        )))\n    {\n        PTOKEN_GROUPS tokenGroups = NULL;\n        PH_TOKEN_USER tokenUser;\n\n        if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser)))\n        {\n            userSid = PhAllocateCopy(tokenUser.User.Sid, PhLengthSid(tokenUser.User.Sid));\n        }\n\n        if (NT_SUCCESS(PhGetTokenGroups(\n            tokenHandle,\n            &tokenGroups\n            )))\n        {\n            for (ULONG i = 0; i < tokenGroups->GroupCount; i++)\n            {\n                PSID_AND_ATTRIBUTES group = &tokenGroups->Groups[i];\n\n                if (FlagOn(group->Attributes, SE_GROUP_LOGON_ID))\n                {\n                    groupSid = PhAllocateCopy(group->Sid, PhLengthSid(group->Sid));\n                    break;\n                }\n            }\n\n            PhFree(tokenGroups);\n        }\n    }\n\n    if (userSid && groupSid)\n    {\n        *UserSid = userSid;\n        *LogonSid = groupSid;\n        return TRUE;\n    }\n\n    if (userSid)\n        PhFree(userSid);\n    if (groupSid)\n        PhFree(groupSid);\n    return FALSE;\n}\n\nNTSTATUS PhRunAsExecutionAlias(\n    _In_ PPH_STRING Command\n    )\n{\n    NTSTATUS status = STATUS_NOT_IMPLEMENTED;\n    PPH_STRING fullFileName = NULL;\n    PPH_STRING commandString = NULL;\n    PH_STRINGREF fileName;\n    PH_STRINGREF arguments;\n\n    commandString = PhExpandEnvironmentStrings(&Command->sr);\n\n    if (PhIsNullOrEmptyString(commandString))\n    {\n        PhMoveReference(&fullFileName, PhCreateString2(&Command->sr));\n    }\n\n    PhParseCommandLineFuzzy(&commandString->sr, &fileName, &arguments, &fullFileName);\n\n    if (PhIsNullOrEmptyString(fullFileName))\n    {\n        PhMoveReference(&fullFileName, PhCreateString2(&fileName));\n    }\n\n    if (!PhIsNullOrEmptyString(fullFileName))\n    {\n        // NOTE: The CreateProcess function will ignore PROC_THREAD_ATTRIBUTE_PARENT_PROCESS when redirecting execution\n        // of the filename via execution alias. The new process incorrectly inherits our elevated process token\n        // instead of using the non-elevated parent process. To work around the issue we execute the alias using the\n        // WdcRunTaskAsInteractiveUser function and also skip resetting the token and current directory. (dmex)\n\n        if (PhIsAppExecutionAliasTarget(fullFileName))\n        {\n            status = STATUS_SUCCESS;\n        }\n    }\n\n    PhClearReference(&fullFileName);\n    PhClearReference(&commandString);\n\n    return status;\n}\n\nNTSTATUS PhRunAsExecuteParentCommand(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR CommandLine,\n    _In_ HANDLE ProcessId,\n    _In_ BOOLEAN CreateSuspendedProcess\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle = NULL;\n    HANDLE newProcessHandle = NULL;\n    STARTUPINFOEX startupInfo = { 0 };\n    PPROC_THREAD_ATTRIBUTE_LIST attributeList = NULL;\n    PSECURITY_DESCRIPTOR processSecurityDescriptor = NULL;\n    PSECURITY_DESCRIPTOR tokenSecurityDescriptor = NULL;\n    PVOID environment = NULL;\n    HANDLE tokenHandle;\n    ULONG flags = 0;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_CREATE_PROCESS | (PhGetOwnTokenAttributes().Elevated ? PROCESS_QUERY_LIMITED_INFORMATION | READ_CONTROL : 0),\n        ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhInitializeProcThreadAttributeList(&attributeList, 1);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhUpdateProcThreadAttribute(\n        attributeList,\n        PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,\n        &processHandle,\n        sizeof(HANDLE)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (PhGetOwnTokenAttributes().Elevated)\n    {\n        PhGetObjectSecurity(\n            processHandle,\n            OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,\n            &processSecurityDescriptor\n            );\n    }\n\n    if (NT_SUCCESS(PhOpenProcessToken(\n        processHandle,\n        TOKEN_QUERY | (PhGetOwnTokenAttributes().Elevated ? READ_CONTROL : 0),\n        &tokenHandle\n        )))\n    {\n        if (PhGetOwnTokenAttributes().Elevated)\n        {\n            PhGetObjectSecurity(\n                tokenHandle,\n                OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,\n                &tokenSecurityDescriptor\n                );\n        }\n\n        if (NT_SUCCESS(PhCreateEnvironmentBlock(&environment, tokenHandle, FALSE)))\n        {\n            flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT;\n        }\n\n        NtClose(tokenHandle);\n    }\n\n    memset(&startupInfo, 0, sizeof(STARTUPINFOEX));\n    startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX);\n    startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;\n    startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL;\n    startupInfo.lpAttributeList = attributeList;\n\n    status = PhCreateProcessWin32Ex(\n        NULL,\n        CommandLine,\n        environment,\n        NULL,\n        &startupInfo,\n        PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | PH_CREATE_PROCESS_DEFAULT_ERROR_MODE | flags,\n        NULL,\n        NULL,\n        &newProcessHandle,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PROCESS_BASIC_INFORMATION basicInfo;\n        PSID userSid, logonSid;\n        \n        if (PhRunAsGetLogonSid(newProcessHandle, &userSid, &logonSid))\n        {\n            status = PhRunAsUpdateDesktop(userSid);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhRunAsUpdateWindowStation(userSid, logonSid);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n        }\n\n        if (PhGetOwnTokenAttributes().Elevated)\n        {\n            // Note: This is needed to workaround a severe bug with PROC_THREAD_ATTRIBUTE_PARENT_PROCESS\n            // where the process and token security descriptors are created without an ACE for the current user,\n            // owned by the wrong user and with a High-IL when the process token is Medium-IL\n            // preventing the new process from accessing user/system resources above Low-IL. (dmex)\n\n            if (processSecurityDescriptor)\n            {\n                PhSetObjectSecurity(\n                    newProcessHandle,\n                    OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,\n                    processSecurityDescriptor\n                    );\n            }\n\n            if (tokenSecurityDescriptor && NT_SUCCESS(PhOpenProcessToken(\n                newProcessHandle,\n                WRITE_DAC | WRITE_OWNER,\n                &tokenHandle\n                )))\n            {\n                PhSetObjectSecurity(\n                    tokenHandle,\n                    OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,\n                    tokenSecurityDescriptor\n                    );\n                NtClose(tokenHandle);\n            }\n        }\n\n        if (!CreateSuspendedProcess)\n        {\n            if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo)))\n            {\n                AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId));\n            }\n\n            PhConsoleSetForeground(newProcessHandle, TRUE);\n\n            NtResumeProcess(newProcessHandle);\n        }\n    }\n\nCleanupExit:\n    if (newProcessHandle)\n    {\n        NtClose(newProcessHandle);\n    }\n\n    if (environment)\n    {\n        PhDestroyEnvironmentBlock(environment);\n    }\n\n    if (tokenSecurityDescriptor)\n    {\n        PhFree(tokenSecurityDescriptor);\n    }\n\n    if (processSecurityDescriptor)\n    {\n        PhFree(processSecurityDescriptor);\n    }\n\n    if (attributeList)\n    {\n        PhDeleteProcThreadAttributeList(attributeList);\n    }\n\n    if (processHandle)\n    {\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\nVOID PhRunAsExecuteCommmand(\n    _In_ PRUNAS_DIALOG_CONTEXT Context,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    BOOLEAN useLinkedToken;\n    BOOLEAN createSuspended;\n    BOOLEAN createUIAccess;\n    ULONG currentSessionId = ULONG_MAX;\n    ULONG logonType = ULONG_MAX;\n    ULONG sessionId = ULONG_MAX;\n    PPH_STRING program = NULL;\n    PPH_STRING username = NULL;\n    PPH_STRING password = NULL;\n    PPH_STRING logonTypeString;\n    PPH_STRING desktopName = NULL;\n    INT selectionIndex = CB_ERR;\n\n    program = PH_AUTO(PhGetWindowText(Context->ProgramComboBoxWindowHandle));\n    username = PH_AUTO(PhGetWindowText(Context->UserComboBoxWindowHandle));\n    logonTypeString = PH_AUTO(PhGetWindowText(Context->TypeComboBoxWindowHandle));\n    useLinkedToken = Button_GetCheck(GetDlgItem(Context->WindowHandle, IDC_TOGGLEELEVATION)) == BST_CHECKED;\n    createSuspended = Button_GetCheck(GetDlgItem(Context->WindowHandle, IDC_TOGGLESUSPENDED)) == BST_CHECKED;\n    createUIAccess = Button_GetCheck(GetDlgItem(Context->WindowHandle, IDC_TOGGLEUIACCESS)) == BST_CHECKED;\n\n    if (PhIsNullOrEmptyString(program))\n        return;\n\n    if ((selectionIndex = ComboBox_GetCurSel(Context->SessionEditWindowHandle)) != CB_ERR)\n    {\n        PPH_RUNAS_SESSION_ITEM sessionEntry;\n\n        if (sessionEntry = (PPH_RUNAS_SESSION_ITEM)ComboBox_GetItemData(Context->SessionEditWindowHandle, selectionIndex))\n        {\n            sessionId = sessionEntry->SessionId;\n        }\n    }\n\n    if ((selectionIndex = ComboBox_GetCurSel(Context->DesktopEditWindowHandle)) != CB_ERR)\n    {\n        PPH_RUNAS_DESKTOP_ITEM desktopEntry;\n\n        if (desktopEntry = (PPH_RUNAS_DESKTOP_ITEM)ComboBox_GetItemData(Context->DesktopEditWindowHandle, selectionIndex))\n        {\n            desktopName = desktopEntry->DesktopName;\n        }\n    }\n\n    if (selectionIndex == CB_ERR)\n        return;\n    if (sessionId == ULONG_MAX)\n        return;\n\n    // Fix up the user name if it doesn't have a domain.\n    if (PhFindCharInString(username, 0, L'\\\\') == SIZE_MAX)\n    {\n        PSID sid;\n        PPH_STRING newUserName;\n\n        if (NT_SUCCESS(PhLookupName(&username->sr, &sid, NULL, NULL)))\n        {\n            if (newUserName = PH_AUTO(PhGetSidFullName(sid, TRUE, NULL)))\n                PhSwapReference(&username, newUserName);\n\n            PhFree(sid);\n        }\n    }\n\n    //if (IsCurrentUserAccount(username))\n    //{\n    //    status = PhCreateProcessWin32(\n    //        NULL,\n    //        program->Buffer,\n    //        NULL,\n    //        NULL,\n    //        0,\n    //        NULL,\n    //        NULL,\n    //        NULL\n    //        );\n    //}\n\n    {\n        PSID userSid;\n\n        if (NT_SUCCESS(PhLookupName(\n            &username->sr,\n            &userSid,\n            NULL,\n            NULL\n            )))\n        {\n            status = PhRunAsUpdateDesktop(userSid);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhRunAsUpdateWindowStation(userSid, NULL);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n        }\n    }\n\n    if (!PhFindIntegerSiKeyValuePairs(\n        PhpLogonTypePairs,\n        sizeof(PhpLogonTypePairs),\n        logonTypeString->Buffer,\n        &logonType\n        ))\n    {\n        PhShowStatus(Context->WindowHandle, L\"Unable to start the program.\", STATUS_INVALID_PARAMETER, 0);\n        return;\n    }\n\n    if (!IsServiceAccount(username))\n    {\n        password = PhGetWindowText(Context->PasswordEditWindowHandle);\n        PhSetWindowText(Context->PasswordEditWindowHandle, L\"\");\n    }\n\n    PhGetProcessSessionId(NtCurrentProcess(), &currentSessionId);\n\n    if (\n        logonType == LOGON32_LOGON_INTERACTIVE &&\n        !ProcessId &&\n        sessionId == currentSessionId &&\n        !useLinkedToken\n        )\n    {\n        // We are eligible to load the user profile.\n        // This must be done here, not in the service, because\n        // we need to be in the target session.\n\n        PH_CREATE_PROCESS_AS_USER_INFO createInfo;\n        PPH_STRING domainPart = NULL;\n        PPH_STRING userPart = NULL;\n        HANDLE newProcessHandle;\n\n        PhpSplitUserName(username->Buffer, &domainPart, &userPart);\n\n        memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO));\n        createInfo.CommandLine = PhGetString(program);\n        createInfo.UserName = PhGetString(userPart);\n        createInfo.DomainName = PhGetString(domainPart);\n        createInfo.Password = PhGetStringOrEmpty(password);\n\n        // Whenever we can, try not to set the desktop name; it breaks a lot of things.\n        if (!PhIsNullOrEmptyString(desktopName) && !PhEqualString2(desktopName, L\"WinSta0\\\\Default\", TRUE))\n            createInfo.DesktopName = PhGetString(desktopName);\n\n        status = PhCreateProcessAsUser(\n            &createInfo,\n            PH_CREATE_PROCESS_WITH_PROFILE | PH_CREATE_PROCESS_DEFAULT_ERROR_MODE | PH_CREATE_PROCESS_SUSPENDED,\n            NULL,\n            NULL,\n            &newProcessHandle,\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            PROCESS_BASIC_INFORMATION basicInfo;\n            PSID userSid, logonSid;\n\n            if (PhRunAsGetLogonSid(newProcessHandle, &userSid, &logonSid))\n            {\n                status = PhRunAsUpdateDesktop(userSid);\n\n                if (!NT_SUCCESS(status))\n                    goto CleanupExit;\n\n                status = PhRunAsUpdateWindowStation(userSid, logonSid);\n\n                if (!NT_SUCCESS(status))\n                    goto CleanupExit;\n            }\n\n            if (!createSuspended)\n            {\n                if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo)))\n                {\n                    AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId));\n                }\n\n                PhConsoleSetForeground(newProcessHandle, TRUE);\n\n                NtResumeProcess(newProcessHandle);\n            }\n\n            NtClose(newProcessHandle);\n        }\n\n        PhClearReference(&domainPart);\n        PhClearReference(&userPart);\n    }\n    else\n    {\n        if (ProcessId)\n        {\n            status = PhRunAsExecutionAlias(program);\n\n            if (!NT_SUCCESS(status))\n            {\n                status = PhRunAsExecuteParentCommand(\n                    Context->WindowHandle,\n                    PhGetString(program),\n                    ProcessId,\n                    createSuspended\n                    );\n            }\n        }\n        else\n        {\n            status = PhExecuteRunAsCommand3(\n                Context->WindowHandle,\n                PhGetString(program),\n                PhGetString(username),\n                PhGetStringOrEmpty(password),\n                logonType,\n                ProcessId,\n                sessionId,\n                PhGetString(desktopName),\n                useLinkedToken,\n                createSuspended,\n                createUIAccess\n                );\n        }\n    }\n\nCleanupExit:\n    if (password)\n    {\n        RtlSecureZeroMemory(password->Buffer, password->Length);\n        PhDereferenceObject(password);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        if (status != STATUS_CANCELLED)\n        {\n            if (status == STATUS_NOT_IMPLEMENTED)\n            {\n                PhShowError2(\n                    Context->WindowHandle,\n                    L\"Unable to start the program.\",\n                    L\"%s\",\n                    L\"Unable to start the execution alias with a process token.\"\n                    );\n            }\n            else\n            {\n                PhShowStatus(\n                    Context->WindowHandle,\n                    L\"Unable to start the program.\",\n                    status,\n                    0\n                    );\n            }\n        }\n    }\n    else if (status != STATUS_TIMEOUT)\n    {\n        PhRecentListAddCommand(&program->sr);\n        //PhSetStringSetting2(SETTING_RUN_AS_PROGRAM, &program->sr);\n        PhSetStringSetting2(SETTING_RUN_AS_USER_NAME, &username->sr);\n        EndDialog(Context->WindowHandle, IDOK);\n    }\n}\n\nINT_PTR CALLBACK PhpRunAsDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PRUNAS_DIALOG_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocateZero(sizeof(RUNAS_DIALOG_CONTEXT));\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->ProgramComboBoxWindowHandle = GetDlgItem(hwndDlg, IDC_PROGRAMCOMBO);\n            context->SessionEditWindowHandle = GetDlgItem(hwndDlg, IDC_SESSIONCOMBO);\n            context->DesktopEditWindowHandle = GetDlgItem(hwndDlg, IDC_DESKTOPCOMBO);\n            context->TypeComboBoxWindowHandle = GetDlgItem(hwndDlg, IDC_TYPE);\n            context->UserComboBoxWindowHandle = GetDlgItem(hwndDlg, IDC_USERNAME);\n            context->PasswordEditWindowHandle = GetDlgItem(hwndDlg, IDC_PASSWORD);\n            context->ProcessId = (HANDLE)lParam;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_RUN_AS_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_RUN_AS_WINDOW_POSITION, NULL, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            if (PhGetIntegerSetting(SETTING_RUN_AS_ENABLE_AUTO_COMPLETE))\n            {\n                COMBOBOXINFO info = { sizeof(COMBOBOXINFO) };\n\n                if (SendMessage(context->ProgramComboBoxWindowHandle, CB_GETCOMBOBOXINFO, 0, (LPARAM)&info))\n                {\n                    if (SHAutoComplete_Import())\n                        SHAutoComplete_Import()(info.hwndItem, SHACF_DEFAULT);\n                }\n            }\n\n            ComboBox_AddString(context->TypeComboBoxWindowHandle, L\"Batch\");\n            ComboBox_AddString(context->TypeComboBoxWindowHandle, L\"Interactive\");\n            ComboBox_AddString(context->TypeComboBoxWindowHandle, L\"Network\");\n            ComboBox_AddString(context->TypeComboBoxWindowHandle, L\"New credentials\");\n            ComboBox_AddString(context->TypeComboBoxWindowHandle, L\"Service\");\n            PhSelectComboBoxString(context->TypeComboBoxWindowHandle, L\"Interactive\", FALSE);\n\n            PhpAddProgramsToComboBox(context->ProgramComboBoxWindowHandle);\n            PhpAddAccountsToComboBox(context->UserComboBoxWindowHandle);\n            PhpAddSessionsToComboBox(context->SessionEditWindowHandle);\n            PhpAddDesktopsToComboBox(context->DesktopEditWindowHandle);\n\n            SetDefaultProgramEntry(context->ProgramComboBoxWindowHandle);\n            SetDefaultUserEntry(context, hwndDlg, context->UserComboBoxWindowHandle);\n            SetDefaultSessionEntry(context->SessionEditWindowHandle);\n            SetDefaultDesktopEntry(context, context->DesktopEditWindowHandle);\n\n            PhSetDialogFocus(hwndDlg, context->ProgramComboBoxWindowHandle);\n            Edit_SetSel(context->ProgramComboBoxWindowHandle, -1, -1);\n\n            //if (!PhGetOwnTokenAttributes().Elevated)\n            //    Button_SetElevationRequiredState(GetDlgItem(hwndDlg, IDOK), TRUE);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveWindowPlacementToSetting(SETTING_RUN_AS_WINDOW_POSITION, NULL, hwndDlg);\n\n            PhpFreeDesktopsComboBox(context->DesktopEditWindowHandle);\n            PhpFreeSessionsComboBox(context->SessionEditWindowHandle);\n            PhDeleteComboBoxStrings(context->UserComboBoxWindowHandle, FALSE);\n            PhDeleteComboBoxStrings(context->ProgramComboBoxWindowHandle, FALSE);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n            PhFree(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_CMD(wParam, lParam))\n            {\n            case CBN_DROPDOWN:\n                {\n                    if (GET_WM_COMMAND_HWND(wParam, lParam) == context->UserComboBoxWindowHandle)\n                    {\n                        //PhpAddAccountsToComboBox(context->UserComboBoxWindowHandle);\n                    }\n\n                    if (GET_WM_COMMAND_HWND(wParam, lParam) == context->SessionEditWindowHandle)\n                    {\n                        PhpAddSessionsToComboBox(context->SessionEditWindowHandle);\n                        SetDefaultSessionEntry(context->SessionEditWindowHandle);\n                    }\n\n                    if (GET_WM_COMMAND_HWND(wParam, lParam) == context->DesktopEditWindowHandle)\n                    {\n                        PhpAddDesktopsToComboBox(context->DesktopEditWindowHandle);\n                        SetDefaultDesktopEntry(context, context->DesktopEditWindowHandle);\n                    }\n                }\n                break;\n            }\n\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                PhRunAsExecuteCommmand(context, context->ProcessId);\n                break;\n            case IDC_BROWSE:\n                {\n                    static PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Programs (*.exe;*.pif;*.com;*.bat)\", L\"*.exe;*.pif;*.com;*.bat\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog;\n\n                    fileDialog = PhCreateOpenFileDialog();\n                    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n                    PhSetFileDialogFileName(fileDialog, PH_AUTO_T(PH_STRING, PhGetWindowText(context->ProgramComboBoxWindowHandle))->Buffer);\n\n                    if (PhShowFileDialog(hwndDlg, fileDialog))\n                    {\n                        PPH_STRING fileName;\n\n                        fileName = PhGetFileDialogFileName(fileDialog);\n                        PhSetWindowText(context->ProgramComboBoxWindowHandle, fileName->Buffer);\n                        PhDereferenceObject(fileName);\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            case IDC_USERNAME:\n                {\n                    PPH_STRING username = NULL;\n\n                    if (!context->ProcessId && GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)\n                    {\n                        username = PH_AUTO(PhGetComboBoxString(context->UserComboBoxWindowHandle, INT_ERROR));\n                    }\n                    else if (!context->ProcessId && (\n                        GET_WM_COMMAND_CMD(wParam, lParam) == CBN_EDITCHANGE ||\n                        GET_WM_COMMAND_CMD(wParam, lParam) == CBN_CLOSEUP\n                        ))\n                    {\n                        username = PH_AUTO(PhGetWindowText(context->UserComboBoxWindowHandle));\n                    }\n\n                    if (username)\n                    {\n                        if (IsServiceAccount(username))\n                        {\n                            EnableWindow(context->PasswordEditWindowHandle, FALSE);\n                            PhSelectComboBoxString(context->TypeComboBoxWindowHandle, L\"Service\", FALSE);\n                        }\n                        else\n                        {\n                            EnableWindow(context->PasswordEditWindowHandle, TRUE);\n                            PhSelectComboBoxString(context->TypeComboBoxWindowHandle, L\"Interactive\", FALSE);\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nNTSTATUS PhRunAsUpdateDesktop(\n    _In_ PSID UserSid\n    )\n{\n    NTSTATUS status;\n    HDESK desktopHandle;\n\n    if (desktopHandle = OpenDesktop(\n        L\"Default\",\n        0,\n        FALSE,\n        READ_CONTROL | WRITE_DAC | DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS\n        ))\n    {\n        ULONG i;\n        BOOLEAN currentDaclPresent;\n        BOOLEAN currentDaclDefaulted;\n        PACL currentDacl;\n        PACE_HEADER currentAce;\n        ULONG newDaclLength;\n        PACL newDacl;\n        SECURITY_DESCRIPTOR newSecurityDescriptor;\n        PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n\n        status = PhGetObjectSecurity(\n            desktopHandle,\n            DACL_SECURITY_INFORMATION,\n            &currentSecurityDescriptor\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (!NT_SUCCESS(PhGetDaclSecurityDescriptor(\n                currentSecurityDescriptor,\n                &currentDaclPresent,\n                &currentDacl,\n                &currentDaclDefaulted\n                )))\n            {\n                currentDaclPresent = FALSE;\n            }\n\n            newDaclLength = sizeof(ACL) + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + PhLengthSid(UserSid);\n\n            if (currentDaclPresent && currentDacl)\n                newDaclLength += currentDacl->AclSize - sizeof(ACL);\n\n            newDacl = PhAllocateStack(newDaclLength);\n\n            if (!newDacl)\n            {\n                status = STATUS_NO_MEMORY;\n                goto CleanupExit;\n            }\n\n            RtlZeroMemory(newDacl, newDaclLength);\n\n            status = PhCreateAcl(newDacl, newDaclLength, ACL_REVISION);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            // Add the existing DACL entries.\n\n            if (currentDaclPresent && currentDacl)\n            {\n                for (i = 0; i < currentDacl->AceCount; i++)\n                {\n                    if (NT_SUCCESS(PhGetAce(currentDacl, i, &currentAce)))\n                    {\n                        if (currentAce->AceType == ACCESS_ALLOWED_ACE_TYPE)\n                        {\n                            PSID aceSid = (PSID)&((PACCESS_ALLOWED_ACE)currentAce)->SidStart;\n\n                            if (PhEqualSid(aceSid, UserSid))\n                            {\n                                if (((PACCESS_ALLOWED_ACE)currentAce)->Mask == DESKTOP_ALL_ACCESS)\n                                    continue;\n                            }\n                        }\n\n                        status = PhAddAce(\n                            newDacl,\n                            ACL_REVISION,\n                            ULONG_MAX,\n                            currentAce,\n                            currentAce->AceSize\n                            );\n\n                        if (!NT_SUCCESS(status))\n                            break;\n                    }\n                }\n            }\n\n            // Allow access for the user.\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhAddAccessAllowedAce(newDacl, ACL_REVISION, DESKTOP_ALL_ACCESS, UserSid);\n            }\n\n            // Set the security descriptor of the new token.\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhCreateSecurityDescriptor(&newSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhSetDaclSecurityDescriptor(&newSecurityDescriptor, TRUE, newDacl, FALSE);\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                assert(RtlValidSecurityDescriptor(&newSecurityDescriptor));\n\n                status = PhSetObjectSecurity(desktopHandle, DACL_SECURITY_INFORMATION, &newSecurityDescriptor);\n            }\n\n            PhFreeStack(newDacl);\n        }\n\n    CleanupExit:\n        CloseDesktop(desktopHandle);\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    return status;\n}\n\nNTSTATUS PhRunAsUpdateWindowStation(\n    _In_opt_ PSID UserSid,\n    _In_opt_ PSID LogonSid\n    )\n{\n    NTSTATUS status;\n    HWINSTA wsHandle;\n\n    if (wsHandle = OpenWindowStation(\n        L\"WinSta0\",\n        FALSE,\n        READ_CONTROL | WRITE_DAC\n        ))\n    {\n        ULONG i;\n        BOOLEAN currentDaclPresent;\n        BOOLEAN currentDaclDefaulted;\n        PACL currentDacl;\n        PACE_HEADER currentAce;\n        ULONG newDaclLength;\n        PACL newDacl;\n        SECURITY_DESCRIPTOR newSecurityDescriptor;\n        PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n\n        status = PhGetObjectSecurity(\n            wsHandle,\n            DACL_SECURITY_INFORMATION,\n            &currentSecurityDescriptor\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (!NT_SUCCESS(PhGetDaclSecurityDescriptor(\n                currentSecurityDescriptor,\n                &currentDaclPresent,\n                &currentDacl,\n                &currentDaclDefaulted\n                )))\n            {\n                currentDaclPresent = FALSE;\n            }\n\n            newDaclLength = (sizeof(ACL) + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) * 3) +\n                (UserSid ? PhLengthSid(UserSid) : 0) + (LogonSid ? PhLengthSid(LogonSid) : 0);\n\n            if (currentDaclPresent && currentDacl)\n                newDaclLength += currentDacl->AclSize - sizeof(ACL);\n\n            newDacl = PhAllocate(newDaclLength);\n            PhCreateAcl(newDacl, newDaclLength, ACL_REVISION);\n\n            // Add the existing DACL entries.\n\n            if (currentDaclPresent && currentDacl)\n            {\n                for (i = 0; i < currentDacl->AceCount; i++)\n                {\n                    if (NT_SUCCESS(PhGetAce(currentDacl, i, &currentAce)))\n                    {\n                        if (currentAce->AceType == ACCESS_ALLOWED_ACE_TYPE)\n                        {\n                            PSID aceSid = (PSID)&((PACCESS_ALLOWED_ACE)currentAce)->SidStart;\n\n                            if (UserSid && PhEqualSid(aceSid, UserSid))\n                            {\n                                if (((PACCESS_ALLOWED_ACE)currentAce)->Mask == (WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS))\n                                    continue;\n                            }\n\n                            if (LogonSid && PhEqualSid(aceSid, LogonSid))\n                            {\n                                if (((PACCESS_ALLOWED_ACE)currentAce)->Mask == WINSTA_ALL_ACCESS)\n                                    continue;\n                            }\n                        }\n\n                        status = PhAddAce(\n                            newDacl,\n                            ACL_REVISION,\n                            ULONG_MAX,\n                            currentAce,\n                            currentAce->AceSize\n                            );\n\n                        if (!NT_SUCCESS(status))\n                            break;\n                    }\n                }\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                if (UserSid)\n                {\n                    PhAddAccessAllowedAce(\n                        newDacl,\n                        ACL_REVISION,\n                        WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS,\n                        UserSid\n                        );\n\n                    //PhAddAccessAllowedAce(\n                    //    newDacl,\n                    //    ACL_REVISION,\n                    //    WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSGLOBALATOMS |\n                    //    WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN | READ_CONTROL,\n                    //    UserSid\n                    //    );\n                }\n\n                if (UserSid)\n                {\n                    PhAddAccessAllowedAceEx(\n                        newDacl,\n                        ACL_REVISION,\n                        OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE,\n                        GENERIC_ALL,\n                        LogonSid\n                        );\n                    PhAddAccessAllowedAceEx(\n                        newDacl,\n                        ACL_REVISION,\n                        NO_PROPAGATE_INHERIT_ACE,\n                        WINSTA_ALL_ACCESS,\n                        LogonSid\n                        );\n                }\n\n                // Set the security descriptor of the new token.\n\n                status = PhCreateSecurityDescriptor(&newSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhSetDaclSecurityDescriptor(&newSecurityDescriptor, TRUE, newDacl, FALSE);\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                assert(RtlValidSecurityDescriptor(&newSecurityDescriptor));\n\n                status = PhSetObjectSecurity(wsHandle, DACL_SECURITY_INFORMATION, &newSecurityDescriptor);\n            }\n        }\n\n        CloseWindowStation(wsHandle);\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    return status;\n}\n\n/**\n * Sets the access control lists of the current window station\n * and desktop to allow all access.\n */\n//NTSTATUS PhSetDesktopWinStaAccess(\n//    _In_ HWND WindowHandle\n//    )\n//{\n//    HWINSTA wsHandle;\n//    HDESK desktopHandle;\n//    ULONG allocationLength;\n//    PSID allAppPackagesSid = PhSeAnyPackageSid();\n//    UCHAR securityDescriptorBuffer[SECURITY_DESCRIPTOR_MIN_LENGTH + 0x50];\n//    PSECURITY_DESCRIPTOR securityDescriptor;\n//    PACL dacl;\n//\n//    if (!PhStartupParameters.RunAsServiceMode && WindowHandle && PhGetIntegerSetting(SETTING_ENABLE_WARNINGS))\n//    {\n//        if (PhGetIntegerSetting(SETTING_ENABLE_WARNINGS_RUNAS) && PhShowMessageOneTime(\n//            WindowHandle,\n//            TD_YES_BUTTON | TD_NO_BUTTON,\n//            TD_WARNING_ICON,\n//            L\"WARNING: This will grant Everyone access to the current window station and desktop.\",\n//            L\"Are you sure you want to continue?\"\n//            ) == IDNO)\n//        {\n//            PhSetIntegerSetting(SETTING_ENABLE_WARNINGS_RUNAS, 0);\n//            return STATUS_ACCESS_DENIED;\n//        }\n//    }\n//\n//    // TODO: Set security on the correct window station and desktop.\n//\n//    // We create a DACL that allows everyone to access everything.\n//\n//    allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH +\n//        (ULONG)sizeof(ACL) +\n//        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n//        PhLengthSid(&PhSeEveryoneSid) +\n//        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n//        PhLengthSid(allAppPackagesSid);\n//\n//    securityDescriptor = (PSECURITY_DESCRIPTOR)securityDescriptorBuffer;\n//    dacl = PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH);\n//\n//    PhCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n//    PhCreateAcl(dacl, allocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION);\n//    PhAddAccessAllowedAce(dacl, ACL_REVISION, GENERIC_ALL, &PhSeEveryoneSid);\n//\n//    if (WindowsVersion >= WINDOWS_8)\n//    {\n//        PhAddAccessAllowedAce(dacl, ACL_REVISION, GENERIC_ALL, allAppPackagesSid);\n//    }\n//\n//    PhSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE);\n//\n//    if (wsHandle = OpenWindowStation(\n//        L\"WinSta0\",\n//        FALSE,\n//        WRITE_DAC\n//        ))\n//    {\n//        PhSetObjectSecurity(wsHandle, DACL_SECURITY_INFORMATION, securityDescriptor);\n//        CloseWindowStation(wsHandle);\n//    }\n//    else\n//    {\n//        return PhGetLastWin32ErrorAsNtStatus();\n//    }\n//\n//    if (desktopHandle = OpenDesktop(\n//        L\"Default\",\n//        0,\n//        FALSE,\n//        WRITE_DAC | DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS\n//        ))\n//    {\n//        PhSetObjectSecurity(desktopHandle, DACL_SECURITY_INFORMATION, securityDescriptor);\n//        CloseDesktop(desktopHandle);\n//    }\n//    else\n//    {\n//        return PhGetLastWin32ErrorAsNtStatus();\n//    }\n//\n//#ifdef DEBUG\n//    assert(RtlValidSecurityDescriptor(securityDescriptor));\n//    assert(allocationLength < sizeof(securityDescriptorBuffer));\n//    assert(RtlLengthSecurityDescriptor(securityDescriptor) < sizeof(securityDescriptorBuffer));\n//#endif\n//\n//    return STATUS_SUCCESS;\n//}\n\nPPH_STRING PhFormatRunAsCommand(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    )\n{\n    PPH_STRING command;\n    PPH_STRING fileName;\n    PH_FORMAT format[5];\n\n    if (!(fileName = PhGetApplicationFileNameWin32()))\n        return NULL;\n\n    // L\"\\\"%s\\\" -ras \\\"%s\\\"\"\n    PhInitFormatS(&format[0], L\"\\\"\");\n    PhInitFormatSR(&format[1], fileName->sr);\n    PhInitFormatS(&format[2], L\"\\\" -ras \\\"\");\n    PhInitFormatS(&format[3], Parameters->ServiceName);\n    PhInitFormatS(&format[4], L\"\\\"\");\n\n    command = PhFormat(format, RTL_NUMBER_OF(format), 0);\n\n    PhDereferenceObject(fileName);\n    return command;\n}\n\n/**\n * Executes the run-as service.\n *\n * \\param Parameters The run-as parameters.\n *\n * \\remarks This function requires administrator-level access.\n */\nNTSTATUS PhExecuteRunAsCommand(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status;\n    PPH_STRING commandLine;\n    SC_HANDLE serviceHandle;\n    PPH_STRING portName;\n    UNICODE_STRING portNameUs;\n    ULONG attempts;\n\n    if (!(commandLine = PhFormatRunAsCommand(Parameters)))\n        return STATUS_UNSUCCESSFUL;\n\n    status = PhCreateService(\n        &serviceHandle,\n        Parameters->ServiceName,\n        Parameters->ServiceName,\n        SERVICE_ALL_ACCESS,\n        SERVICE_WIN32_OWN_PROCESS,\n        SERVICE_DEMAND_START,\n        SERVICE_ERROR_IGNORE,\n        PhGetString(commandLine),\n        L\"LocalSystem\",\n        L\"\"\n        );\n\n    PhDereferenceObject(commandLine);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhStartService(serviceHandle, 0, NULL);\n    PhDeleteService(serviceHandle);\n\n    portName = PhConcatStrings2(L\"\\\\BaseNamedObjects\\\\\", Parameters->ServiceName);\n    PhStringRefToUnicodeString(&portName->sr, &portNameUs);\n    attempts = 50;\n\n    // Try to connect several times because the server may take\n    // a while to initialize.\n    do\n    {\n        status = PhSvcConnectToServer(&portNameUs, 0);\n\n        if (NT_SUCCESS(status))\n            break;\n\n        PhDelayExecution(100);\n\n    } while (--attempts != 0);\n\n    PhDereferenceObject(portName);\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhSvcCallInvokeRunAsService(Parameters);\n        PhSvcDisconnectFromServer();\n    }\n\n    PhCloseServiceHandle(serviceHandle);\n\n    return status;\n}\n\n/**\n * Starts a program as another user.\n *\n * \\param WindowHandle A handle to the parent window.\n * \\param CommandLine The command line of the program to start.\n * \\param UserName The user to start the program as. The username should be specified as: domain\\\\name.\n *        This parameter can be NULL if \\a ProcessIdWithToken is specified.\n * \\param Password The password for the specified user. If there is no password, specify an empty string.\n *        This parameter can be NULL if \\a ProcessIdWithToken is specified.\n * \\param LogonType The logon type for the specified user. This\n *        parameter can be 0 if \\a ProcessIdWithToken is specified.\n * \\param ProcessIdWithToken The ID of a process from which to duplicate the token.\n * \\param SessionId The ID of the session to run the program under.\n * \\param DesktopName The window station and desktop to run the program under.\n * \\param UseLinkedToken Uses the linked token if possible.\n *\n * \\retval STATUS_CANCELLED The user cancelled the operation.\n *\n * \\remarks This function will cause another instance of System Informer to be executed if the current security context\n * does not have sufficient system access. This is done through a UAC elevation prompt.\n */\nNTSTATUS PhExecuteRunAsCommand2(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR CommandLine,\n    _In_opt_ PCWSTR UserName,\n    _In_opt_ PCWSTR Password,\n    _In_opt_ ULONG LogonType,\n    _In_opt_ HANDLE ProcessIdWithToken,\n    _In_opt_ ULONG SessionId,\n    _In_opt_ PCWSTR DesktopName,\n    _In_ BOOLEAN UseLinkedToken\n    )\n{\n    return PhExecuteRunAsCommand3(\n        WindowHandle,\n        CommandLine,\n        UserName,\n        Password,\n        LogonType,\n        ProcessIdWithToken,\n        SessionId,\n        DesktopName,\n        UseLinkedToken,\n        FALSE,\n        FALSE\n        );\n}\n\nNTSTATUS PhExecuteRunAsCommand3(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR CommandLine,\n    _In_opt_ PCWSTR UserName,\n    _In_opt_ PCWSTR Password,\n    _In_opt_ ULONG LogonType,\n    _In_opt_ HANDLE ProcessIdWithToken,\n    _In_opt_ ULONG SessionId,\n    _In_opt_ PCWSTR DesktopName,\n    _In_ BOOLEAN UseLinkedToken,\n    _In_ BOOLEAN CreateSuspendedProcess,\n    _In_ BOOLEAN CreateUIAccessProcess\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    PH_RUNAS_SERVICE_PARAMETERS parameters;\n    WCHAR serviceName[32];\n    PPH_STRING portName;\n    UNICODE_STRING portNameUs;\n\n    memset(&parameters, 0, sizeof(PH_RUNAS_SERVICE_PARAMETERS));\n    parameters.ProcessId = HandleToUlong(ProcessIdWithToken);\n    parameters.UserName = UserName;\n    parameters.Password = Password;\n    parameters.LogonType = LogonType;\n    parameters.SessionId = SessionId;\n    parameters.CommandLine = CommandLine;\n    parameters.DesktopName = DesktopName;\n    parameters.UseLinkedToken = UseLinkedToken;\n    parameters.CreateSuspendedProcess = CreateSuspendedProcess;\n    parameters.WindowHandle = WindowHandle;\n    parameters.CreateUIAccessProcess = CreateUIAccessProcess;\n\n    // Try to use an existing instance of the service if possible.\n    if (RunAsOldServiceName[0] != UNICODE_NULL)\n    {\n        PhAcquireQueuedLockExclusive(&RunAsOldServiceLock);\n\n        portName = PhConcatStrings2(L\"\\\\BaseNamedObjects\\\\\", RunAsOldServiceName);\n\n        if (!PhStringRefToUnicodeString(&portName->sr, &portNameUs))\n        {\n            PhDereferenceObject(portName);\n            PhReleaseQueuedLockExclusive(&RunAsOldServiceLock);\n            return STATUS_NAME_TOO_LONG;\n        }\n\n        status = PhSvcConnectToServer(&portNameUs, 0);\n\n        if (NT_SUCCESS(status))\n        {\n            parameters.ServiceName = RunAsOldServiceName;\n            status = PhSvcCallInvokeRunAsService(&parameters);\n            PhSvcDisconnectFromServer();\n\n            PhDereferenceObject(portName);\n            PhReleaseQueuedLockExclusive(&RunAsOldServiceLock);\n            return status;\n        }\n\n        PhDereferenceObject(portName);\n        PhReleaseQueuedLockExclusive(&RunAsOldServiceLock);\n    }\n\n    // An existing instance was not available. Proceed normally.\n\n    memset(serviceName, 0, sizeof(serviceName));\n    memcpy(serviceName, L\"SystemInformer\", 14 * sizeof(WCHAR));\n    PhGenerateRandomAlphaString(&serviceName[14], ARRAYSIZE(serviceName) - 14);\n    PhAcquireQueuedLockExclusive(&RunAsOldServiceLock);\n    memcpy(RunAsOldServiceName, serviceName, sizeof(serviceName) - sizeof(UNICODE_NULL));\n    PhReleaseQueuedLockExclusive(&RunAsOldServiceLock);\n\n    parameters.ServiceName = serviceName;\n\n    if (PhGetOwnTokenAttributes().Elevated)\n    {\n        status = PhExecuteRunAsCommand(&parameters);\n    }\n    else\n    {\n        if (PhUiConnectToPhSvc(WindowHandle, FALSE))\n        {\n            status = PhSvcCallExecuteRunAsCommand(&parameters);\n            PhUiDisconnectFromPhSvc();\n        }\n        else\n        {\n            status = STATUS_CANCELLED;\n        }\n    }\n\n    return status;\n}\n\nVOID PhpSplitUserName(\n    _In_ PCWSTR UserName,\n    _Out_opt_ PPH_STRING *DomainPart,\n    _Out_opt_ PPH_STRING *UserPart\n    )\n{\n    PH_STRINGREF userName;\n    PH_STRINGREF domainPart;\n    PH_STRINGREF userPart;\n\n    PhInitializeStringRefLongHint(&userName, UserName);\n\n    if (PhSplitStringRefAtChar(&userName, OBJ_NAME_PATH_SEPARATOR, &domainPart, &userPart))\n    {\n        if (DomainPart)\n            *DomainPart = PhCreateString2(&domainPart);\n        if (UserPart)\n            *UserPart = PhCreateString2(&userPart);\n    }\n    else\n    {\n        if (DomainPart)\n            *DomainPart = NULL;\n        if (UserPart)\n            *UserPart = PhCreateString2(&userName);\n    }\n}\n\nstatic VOID SetRunAsServiceStatus(\n    _In_ ULONG State\n    )\n{\n    SERVICE_STATUS status;\n\n    memset(&status, 0, sizeof(SERVICE_STATUS));\n    status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;\n    status.dwCurrentState = State;\n    status.dwControlsAccepted = SERVICE_ACCEPT_STOP;\n\n    SetServiceStatus(RunAsServiceStatusHandle, &status);\n}\n\nstatic ULONG WINAPI RunAsServiceHandlerEx(\n    _In_ ULONG dwControl,\n    _In_ ULONG dwEventType,\n    _In_ PVOID lpEventData,\n    _In_ PVOID lpContext\n    )\n{\n    switch (dwControl)\n    {\n    case SERVICE_CONTROL_STOP:\n        PhSvcStop(&RunAsServiceStop);\n        return NO_ERROR;\n    case SERVICE_CONTROL_INTERROGATE:\n        return NO_ERROR;\n    }\n\n    return ERROR_CALL_NOT_IMPLEMENTED;\n}\n\nstatic VOID WINAPI RunAsServiceMain(\n    _In_ ULONG dwArgc,\n    _In_ PWSTR *lpszArgv\n    )\n{\n    PPH_STRING portName;\n\n    memset(&RunAsServiceStop, 0, sizeof(RunAsServiceStop));\n\n    RunAsServiceStatusHandle = RegisterServiceCtrlHandlerEx(RunAsServiceName->Buffer, RunAsServiceHandlerEx, NULL);\n    SetRunAsServiceStatus(SERVICE_RUNNING);\n\n    portName = PhConcatStrings2(\n        L\"\\\\BaseNamedObjects\\\\\",\n        RunAsServiceName->Buffer\n        );\n\n    PhSvcMain(portName, &RunAsServiceStop);\n\n    SetRunAsServiceStatus(SERVICE_STOPPED);\n}\n\nNTSTATUS PhRunAsServiceStart(\n    _In_ PPH_STRING ServiceName\n    )\n{\n    const SERVICE_TABLE_ENTRY serviceDispatchTable[] =\n    {\n        { PhGetString(ServiceName), RunAsServiceMain },\n        { NULL, NULL }\n    };\n    HANDLE tokenHandle;\n\n    // Enable some required privileges.\n\n    if (NT_SUCCESS(PhOpenProcessToken(\n        NtCurrentProcess(),\n        TOKEN_ADJUST_PRIVILEGES,\n        &tokenHandle\n        )))\n    {\n        const LUID_AND_ATTRIBUTES privileges[] =\n        {\n            { RtlConvertUlongToLuid(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_INCREASE_QUOTA_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_BACKUP_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_RESTORE_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n            { RtlConvertUlongToLuid(SE_IMPERSONATE_PRIVILEGE), SE_PRIVILEGE_ENABLED },\n        };\n        UCHAR privilegesBuffer[FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(privileges)];\n        PTOKEN_PRIVILEGES tokenPrivileges;\n\n        tokenPrivileges = (PTOKEN_PRIVILEGES)privilegesBuffer;\n        tokenPrivileges->PrivilegeCount = RTL_NUMBER_OF(privileges);\n        memcpy(tokenPrivileges->Privileges, privileges, sizeof(privileges));\n\n        NtAdjustPrivilegesToken(\n            tokenHandle,\n            FALSE,\n            tokenPrivileges,\n            0,\n            NULL,\n            NULL\n            );\n\n        NtClose(tokenHandle);\n    }\n\n    RunAsServiceName = ServiceName;\n\n    StartServiceCtrlDispatcher(serviceDispatchTable);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhInvokeRunAsService(\n    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status;\n    PPH_STRING domainName;\n    PPH_STRING userName;\n    PH_CREATE_PROCESS_AS_USER_INFO createInfo;\n    HANDLE newProcessHandle = NULL;\n    ULONG flags;\n\n    //status = PhSetDesktopWinStaAccess(Parameters->WindowHandle);\n\n    //if (!NT_SUCCESS(status))\n    //    return status;\n\n    if (Parameters->UserName)\n    {\n        PhpSplitUserName(Parameters->UserName, &domainName, &userName);\n    }\n    else\n    {\n        domainName = NULL;\n        userName = NULL;\n    }\n\n    memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO));\n    createInfo.ApplicationName = Parameters->FileName;\n    createInfo.CommandLine = Parameters->CommandLine;\n    createInfo.CurrentDirectory = Parameters->CurrentDirectory;\n    createInfo.DomainName = PhGetString(domainName);\n    createInfo.UserName = PhGetString(userName);\n    createInfo.Password = Parameters->Password;\n    createInfo.LogonType = Parameters->LogonType;\n    createInfo.SessionId = Parameters->SessionId;\n    createInfo.DesktopName = Parameters->DesktopName;\n\n    flags = PH_CREATE_PROCESS_SET_SESSION_ID | PH_CREATE_PROCESS_DEFAULT_ERROR_MODE;\n\n    if (Parameters->ProcessId)\n    {\n        createInfo.ProcessIdWithToken = UlongToHandle(Parameters->ProcessId);\n        flags |= PH_CREATE_PROCESS_USE_PROCESS_TOKEN;\n    }\n\n    if (Parameters->UseLinkedToken)\n        flags |= PH_CREATE_PROCESS_USE_LINKED_TOKEN;\n    //if (Parameters->CreateSuspendedProcess)\n    //    flags |= PH_CREATE_PROCESS_SUSPENDED;\n    if (Parameters->CreateUIAccessProcess)\n        flags |= PH_CREATE_PROCESS_SET_UIACCESS;\n\n    status = PhCreateProcessAsUser(\n        &createInfo,\n        flags | PH_CREATE_PROCESS_SUSPENDED,\n        NULL,\n        NULL,\n        &newProcessHandle,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PROCESS_BASIC_INFORMATION basicInfo;\n        PSID userSid, logonSid;\n\n        if (PhRunAsGetLogonSid(newProcessHandle, &userSid, &logonSid))\n        {\n            status = PhRunAsUpdateDesktop(userSid);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhRunAsUpdateWindowStation(userSid, logonSid);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n        }\n\n        if (!Parameters->CreateSuspendedProcess)\n        {\n            status = PhGetProcessBasicInformation(newProcessHandle, &basicInfo);\n\n            if (NT_SUCCESS(status))\n            {\n                AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId));\n            }\n\n            PhConsoleSetForeground(newProcessHandle, TRUE);\n\n            PhResumeProcess(newProcessHandle);\n        }\n    }\n\nCleanupExit:\n    if (newProcessHandle) NtClose(newProcessHandle);\n    if (domainName) PhDereferenceObject(domainName);\n    if (userName) PhDereferenceObject(userName);\n\n    return status;\n}\n\ntypedef struct _PHP_RUNFILEDLG\n{\n    HWND WindowHandle;\n    HWND ComboBoxHandle;\n    HWND RunAsCheckboxHandle;\n    HWND RunAsInstallerCheckboxHandle;\n    HIMAGELIST ImageListHandle;\n    BOOLEAN RunAsInstallerCheckboxDisabled;\n    LONG WindowDpi;\n} PHP_RUNFILEDLG, *PPHP_RUNFILEDLG;\n\nPPH_STRING PhpQueryRunFileParentDirectory(\n    _In_ BOOLEAN Elevated\n    )\n{\n    // Note: Explorer creates new processes with the parent directory as SystemRoot when elevated or\n    // the below environment variables when not elevated. (dmex)\n    if (!Elevated)\n    {\n        static CONST PH_STRINGREF homeDriveNameSr = PH_STRINGREF_INIT(L\"HOMEDRIVE\");\n        static CONST PH_STRINGREF homePathNameSr = PH_STRINGREF_INIT(L\"HOMEPATH\");\n        PPH_STRING parentDirectoryString = NULL;\n        PPH_STRING homeDriveNameString = NULL;\n        PPH_STRING homePathNameString = NULL;\n\n        PhQueryEnvironmentVariable(NULL, &homeDriveNameSr, &homeDriveNameString);\n        PhQueryEnvironmentVariable(NULL, &homePathNameSr, &homePathNameString);\n\n        if (homeDriveNameString && homePathNameString)\n        {\n            parentDirectoryString = PhConcatStringRef2(\n                &homeDriveNameString->sr,\n                &homePathNameString->sr\n                );\n        }\n\n        if (homeDriveNameString)\n            PhDereferenceObject(homeDriveNameString);\n        if (homePathNameString)\n            PhDereferenceObject(homePathNameString);\n\n        return parentDirectoryString;\n    }\n    else\n    {\n        return PhGetSystemDirectory();\n    }\n}\n\nBOOLEAN PhRunAsExecuteCommandPrompt(\n    _In_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n    BOOLEAN elevated;\n    PPH_STRING commandFileName;\n    PPH_STRING commandDirectory;\n\n    elevated = !!PhGetOwnTokenAttributes().Elevated;\n    commandFileName = PhGetSystemDirectoryWin32Z(L\"\\\\cmd.exe\");\n    commandDirectory = PhpQueryRunFileParentDirectory(elevated);\n\n    status = PhShellExecuteEx(\n        WindowHandle,\n        PhGetString(commandFileName),\n        NULL,\n        PhGetString(commandDirectory),\n        SW_SHOW,\n        PH_SHELL_EXECUTE_DEFAULT,\n        0,\n        NULL\n        );\n\n    PhClearReference(&commandDirectory);\n    PhClearReference(&commandFileName);\n\n    return NT_SUCCESS(status);\n}\n\nNTSTATUS PhRunAsShellExecute(\n    _In_ HWND WindowHandle,\n    _In_ PWSTR FileName,\n    _In_opt_ PWSTR Parameters,\n    _In_ BOOLEAN Elevated\n    )\n{\n    NTSTATUS status;\n    PPH_STRING parentDirectory;\n\n    parentDirectory = PhpQueryRunFileParentDirectory(Elevated);\n\n    status = PhShellExecuteEx(\n        WindowHandle,\n        FileName,\n        Parameters,\n        PhGetString(parentDirectory),\n        SW_SHOW,\n        Elevated ? PH_SHELL_EXECUTE_ADMIN : PH_SHELL_EXECUTE_DEFAULT,\n        0,\n        NULL\n        );\n\n    PhClearReference(&parentDirectory);\n\n    return status;\n}\n\nBOOLEAN PhpRunFileAsInteractiveUser(\n    _In_ PPHP_RUNFILEDLG Context,\n    _In_ PPH_STRING Command\n    )\n{\n    BOOLEAN success = FALSE;\n    PPH_STRING executeString = NULL;\n    PPH_STRING fileName = NULL;\n    PPH_STRING fileArgs = NULL;\n    PPH_LIST cmdlineArgList;\n\n    // Extract the filename.\n    if (cmdlineArgList = PhCommandLineToList(Command->Buffer))\n    {\n        fileName = PhReferenceObject(cmdlineArgList->Items[0]);\n\n        if (cmdlineArgList->Count == 2)\n        {\n            fileArgs = PhReferenceObject(cmdlineArgList->Items[1]);\n        }\n\n        PhDereferenceObjects(cmdlineArgList->Items, cmdlineArgList->Count);\n        PhDereferenceObject(cmdlineArgList);\n    }\n\n    if (fileName && !PhDoesFileExistWin32(PhGetString(fileName)))\n    {\n        PPH_STRING filePathString;\n\n        // The user typed a name without a path so attempt to locate the executable.\n        if (filePathString = PhSearchFilePath(PhGetString(fileName), L\".exe\"))\n            PhMoveReference(&fileName, filePathString);\n        else\n            PhClearReference(&fileName);\n    }\n\n    if (fileName)\n    {\n        static CONST PH_STRINGREF separator = PH_STRINGREF_INIT(L\"\\\"\");\n        static CONST PH_STRINGREF space = PH_STRINGREF_INIT(L\" \");\n\n        // Escape the filename.\n        PhMoveReference(&fileName, PhConcatStringRef3(&separator, &fileName->sr, &separator));\n\n        if (fileArgs)\n        {\n            // Escape the parameters.\n            PhMoveReference(&fileArgs, PhConcatStringRef3(&separator, &fileArgs->sr, &separator));\n\n            // Create the escaped execute string.\n            executeString = PhConcatStringRef3(&fileName->sr, &space, &fileArgs->sr);\n\n            // Cleanup.\n            PhClearReference(&fileArgs);\n        }\n        else\n        {\n            executeString = fileName;\n        }\n    }\n\n    if (!PhIsNullOrEmptyString(executeString))\n    {\n        PPH_STRING parentDirectory = PhpQueryRunFileParentDirectory(FALSE);\n\n        if (PhCreateProcessAsInteractiveUser(PhGetString(executeString), PhGetString(parentDirectory)) == S_OK)\n        {\n            success = TRUE;\n        }\n\n        PhClearReference(&parentDirectory);\n    }\n\n    PhClearReference(&executeString);\n\n    return success;\n}\n\nNTSTATUS PhpRunFileProgram(\n    _In_ PPHP_RUNFILEDLG Context,\n    _In_ PPH_STRING Command\n    )\n{\n    NTSTATUS status;\n    PPH_STRING commandString = NULL;\n    PPH_STRING fullFileName = NULL;\n    PPH_STRING argumentsString = NULL;\n    PH_STRINGREF fileName;\n    PH_STRINGREF arguments;\n    FILE_BASIC_INFORMATION basicInfo;\n    BOOLEAN isDirectory = FALSE;\n\n    if (PhIsNullOrEmptyString(Command))\n        return STATUS_UNSUCCESSFUL;\n\n    if (!(commandString = PhExpandEnvironmentStrings(&Command->sr)))\n        commandString = PhCreateString2(&Command->sr);\n\n    PhParseCommandLineFuzzy(&commandString->sr, &fileName, &arguments, &fullFileName);\n\n    if (PhIsNullOrEmptyString(fullFileName))\n        PhMoveReference(&fullFileName, PhCreateString2(&fileName));\n\n    if (PhIsNullOrEmptyString(fullFileName))\n    {\n        if (fullFileName)\n            PhDereferenceObject(fullFileName);\n\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    if (arguments.Length)\n    {\n        argumentsString = PhCreateString2(&arguments);\n    }\n\n    if (NT_SUCCESS(PhQueryAttributesFileWin32(PhGetString(fullFileName), &basicInfo)))\n    {\n        isDirectory = !!FlagOn(basicInfo.FileAttributes, FILE_ATTRIBUTE_DIRECTORY);\n    }\n\n    if (isDirectory || !PhDoesFileExistWin32(PhGetString(fullFileName)))\n    {\n        status = PhRunAsShellExecute(\n            Context->WindowHandle,\n            PhGetString(commandString),\n            NULL,\n            FALSE\n            );\n    }\n    else if (Button_GetCheck(Context->RunAsCheckboxHandle) == BST_CHECKED ||\n        // The Windows run dialog executes programs with elevation when\n        // holding the ctrl + shift keys and selecting the OK button. (dmex)\n        (!!(GetKeyState(VK_CONTROL) < 0 && !!(GetKeyState(VK_SHIFT) < 0))))\n    {\n        status = PhRunAsShellExecute(\n            Context->WindowHandle,\n            PhGetString(fullFileName),\n            PhGetString(argumentsString),\n            TRUE\n            );\n    }\n    else\n    {\n        status = PhRunAsShellExecute(\n            Context->WindowHandle,\n            PhGetString(fullFileName),\n            PhGetString(argumentsString),\n            FALSE\n            );\n\n        if (status == STATUS_ELEVATION_REQUIRED)\n        {\n            status = PhRunAsShellExecute(\n                Context->WindowHandle,\n                PhGetString(fullFileName),\n                PhGetString(argumentsString),\n                TRUE\n                );\n        }\n    }\n\n    if (fullFileName) PhDereferenceObject(fullFileName);\n    if (argumentsString) PhDereferenceObject(argumentsString);\n    if (commandString) PhDereferenceObject(commandString);\n\n    return status;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS RunAsCreateProcessThread(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_STRING command = Parameter;\n    NTSTATUS status;\n    PPROC_THREAD_ATTRIBUTE_LIST attributeList = NULL;\n    SERVICE_STATUS_PROCESS serviceStatus = { 0 };\n    SC_HANDLE serviceHandle = NULL;\n    HANDLE processHandle = NULL;\n    HANDLE newProcessHandle;\n    STARTUPINFOEX startupInfo;\n    PPH_STRING commandLine = NULL;\n    PPH_STRING filePathString;\n\n    if (filePathString = PhSearchFilePath(command->Buffer, L\".exe\"))\n        PhMoveReference(&commandLine, filePathString);\n    else\n        PhSetReference(&commandLine, command);\n\n    if (!NT_SUCCESS(status = PhOpenService(&serviceHandle, SERVICE_QUERY_STATUS | SERVICE_START, L\"TrustedInstaller\")))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhQueryServiceStatus(serviceHandle, &serviceStatus)))\n        goto CleanupExit;\n\n    if (serviceStatus.dwCurrentState == SERVICE_RUNNING)\n    {\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        ULONG attempts = 10;\n\n        PhStartService(serviceHandle, 0, NULL);\n\n        do\n        {\n            status = PhQueryServiceStatus(serviceHandle, &serviceStatus);\n\n            if (NT_SUCCESS(status))\n            {\n                if (serviceStatus.dwCurrentState == SERVICE_RUNNING)\n                {\n                    status = STATUS_SUCCESS;\n                    break;\n                }\n            }\n\n            PhDelayExecution(1000);\n\n        } while (--attempts != 0);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        status = STATUS_SERVICES_FAILED_AUTOSTART;\n        goto CleanupExit;\n    }\n\n    if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_CREATE_PROCESS, UlongToHandle(serviceStatus.dwProcessId))))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhInitializeProcThreadAttributeList(&attributeList, 1)))\n        goto CleanupExit;\n\n    status = PhUpdateProcThreadAttribute(\n        attributeList,\n        PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,\n        &processHandle,\n        sizeof(HANDLE)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    memset(&startupInfo, 0, sizeof(STARTUPINFOEX));\n    startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX);\n    startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;\n    startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL;\n    startupInfo.lpAttributeList = attributeList;\n\n    status = PhCreateProcessWin32Ex(\n        NULL,\n        PhGetString(commandLine),\n        NULL,\n        NULL,\n        &startupInfo,\n        PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | PH_CREATE_PROCESS_DEFAULT_ERROR_MODE,\n        NULL,\n        NULL,\n        &newProcessHandle,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PROCESS_BASIC_INFORMATION basicInfo;\n\n        if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo)))\n        {\n            AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId));\n        }\n\n        PhConsoleSetForeground(newProcessHandle, TRUE);\n        NtClose(newProcessHandle);\n    }\n\nCleanupExit:\n\n    if (processHandle)\n        NtClose(processHandle);\n\n    if (serviceHandle)\n        PhCloseServiceHandle(serviceHandle);\n\n    if (attributeList)\n    {\n        PhDeleteProcThreadAttributeList(attributeList);\n    }\n\n    if (commandLine)\n    {\n        PhDereferenceObject(commandLine);\n    }\n\n    if (command)\n    {\n        PhDereferenceObject(command);\n    }\n\n    return status;\n}\n\nstatic VOID PhpRunFileSetImageList(\n    _Inout_ PPHP_RUNFILEDLG Context\n    )\n{\n    if (Context->ImageListHandle)\n    {\n        PhImageListDestroy(Context->ImageListHandle);\n        Context->ImageListHandle = NULL;\n    }\n\n    Context->ImageListHandle = PhImageListCreate(\n        PhGetSystemMetrics(SM_CXSMICON, Context->WindowDpi),\n        PhGetSystemMetrics(SM_CYSMICON, Context->WindowDpi),\n        ILC_MASK | ILC_COLOR32,\n        1, 1\n        );\n\n    if (Context->ImageListHandle)\n    {\n        HBITMAP shieldBitmap;\n\n        if (shieldBitmap = PhGetShieldBitmap(Context->WindowDpi, PhSmallIconSize.X, PhSmallIconSize.Y))\n        {\n            PhImageListAddBitmap(Context->ImageListHandle, shieldBitmap, NULL);\n            DeleteBitmap(shieldBitmap);\n        }\n    }\n}\n\nINT_PTR CALLBACK PhpRunFileWndProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_RUNFILEDLG context = NULL;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocateZero(sizeof(PHP_RUNFILEDLG));\n        PhSetDialogContext(hwndDlg, context);\n    }\n    else\n    {\n        context = PhGetDialogContext(hwndDlg);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->ComboBoxHandle = GetDlgItem(hwndDlg, IDC_PROGRAMCOMBO);\n            context->RunAsCheckboxHandle = GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION);\n            context->RunAsInstallerCheckboxHandle = GetDlgItem(hwndDlg, IDC_TRUSTEDINSTALLER);\n            context->WindowDpi = PhGetWindowDpi(hwndDlg);\n\n            PhSetApplicationWindowIconEx(hwndDlg, context->WindowDpi);\n            PhSetStaticWindowIcon(GetDlgItem(hwndDlg, IDC_FILEICON), context->WindowDpi);\n\n            PhpAddProgramsToComboBox(context->ComboBoxHandle);\n            ComboBox_SetCurSel(context->ComboBoxHandle, 0);\n\n            if (PhGetIntegerSetting(SETTING_RUN_AS_ENABLE_AUTO_COMPLETE))\n            {\n                COMBOBOXINFO info = { sizeof(COMBOBOXINFO) };\n\n                if (SendMessage(context->ComboBoxHandle, CB_GETCOMBOBOXINFO, 0, (LPARAM)& info))\n                {\n                    if (SHAutoComplete_Import() && info.hwndItem)\n                        SHAutoComplete_Import()(info.hwndItem, SHACF_DEFAULT);\n                }\n            }\n\n            Button_SetCheck(context->RunAsCheckboxHandle, PhGetIntegerSetting(SETTING_RUN_FILE_DLG_STATE) ? TRUE : FALSE);\n\n            if (!PhGetOwnTokenAttributes().Elevated)\n            {\n                Button_Enable(context->RunAsInstallerCheckboxHandle, FALSE);\n                context->RunAsInstallerCheckboxDisabled = TRUE;\n\n                PhpRunFileSetImageList(context);\n            }\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveDialogContext(hwndDlg);\n\n            PhSetIntegerSetting(SETTING_RUN_FILE_DLG_STATE, Button_GetCheck(context->RunAsCheckboxHandle) == BST_CHECKED);\n\n            PhImageListDestroy(context->ImageListHandle);\n\n            PhDestroyWindowIcon(hwndDlg);\n            PhDeleteStaticWindowIcon(GetDlgItem(hwndDlg, IDC_FILEICON));\n\n            PhFree(context);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            context->WindowDpi = PhGetWindowDpi(hwndDlg);\n\n            PhSetApplicationWindowIconEx(hwndDlg, context->WindowDpi);\n            PhSetStaticWindowIcon(GetDlgItem(hwndDlg, IDC_FILEICON), context->WindowDpi);\n\n            PhpRunFileSetImageList(context);\n        }\n        break;\n    case WM_CTLCOLORSTATIC:\n        {\n            HDC hdc = (HDC)wParam;\n\n            if (PhEnableThemeSupport)\n                break;\n\n            SetBkMode(hdc, TRANSPARENT);\n\n            return (INT_PTR)PhGetStockBrush(WHITE_BRUSH);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    NTSTATUS status;\n                    PPH_STRING commandString;\n\n                    if (commandString = PhGetWindowText(context->ComboBoxHandle))\n                    {\n                        if (Button_GetCheck(context->RunAsInstallerCheckboxHandle) == BST_CHECKED)\n                        {\n                            PhReferenceObject(commandString);\n                            status = PhCreateThread2(RunAsCreateProcessThread, commandString);\n                        }\n                        else\n                        {\n                            status = PhpRunFileProgram(context, commandString);\n                        }\n\n                        if (NT_SUCCESS(status))\n                        {\n                            PhRecentListAddCommand(&commandString->sr);\n\n                            EndDialog(hwndDlg, IDOK);\n                        }\n                        else\n                        {\n                            if (!(NT_NTWIN32(status) && WIN32_FROM_NTSTATUS(status) == ERROR_CANCELLED))\n                            {\n                                PhShowStatus(hwndDlg, L\"Unable to execute the command.\", status, 0);\n                            }\n                        }\n\n                        PhDereferenceObject(commandString);\n                    }\n                }\n                break;\n            case IDC_BROWSE:\n                {\n                    PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Executable files (*.exe;*.pif;*.com;*.bat;*.cmd)\", L\"*.exe;*.pif;*.com;*.bat;*.cmd\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog = PhCreateOpenFileDialog();\n\n                    PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters));\n\n                    if (PhShowFileDialog(hwndDlg, fileDialog))\n                    {\n                        PPH_STRING fileName;\n\n                        if (fileName = PhGetFileDialogFileName(fileDialog))\n                        {\n                            ComboBox_SetText(context->ComboBoxHandle, PhGetString(fileName));\n                            PhDereferenceObject(fileName);\n                        }\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            case IDC_TRUSTEDINSTALLER:\n                {\n                    EnableWindow(context->RunAsCheckboxHandle, Button_GetCheck(context->RunAsInstallerCheckboxHandle) == BST_UNCHECKED);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_ERASEBKGND:\n        {\n            HDC hdc = (HDC)wParam;\n            RECT clientRect;\n\n            if (!PhGetClientRect(hwndDlg, &clientRect))\n                break;\n\n            SetBkMode(hdc, TRANSPARENT);\n\n            clientRect.bottom -= PhGetDpi(60, context->WindowDpi);\n            FillRect(hdc, &clientRect, PhEnableThemeSupport ? PhThemeWindowBackgroundBrush : (HBRUSH)(COLOR_WINDOW + 1));\n\n            clientRect.top = clientRect.bottom;\n            clientRect.bottom = clientRect.top + PhGetDpi(60, context->WindowDpi);\n            FillRect(hdc, &clientRect, PhEnableThemeSupport ? PhThemeWindowBackgroundBrush : (HBRUSH)(COLOR_3DFACE + 1));\n\n            SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);\n        }\n        return TRUE;\n    case WM_NOTIFY:\n        {\n            LPNMHDR data = (LPNMHDR)lParam;\n\n            if (data->hwndFrom != context->RunAsInstallerCheckboxHandle || !context->RunAsInstallerCheckboxDisabled)\n                break;\n\n            switch (data->code)\n            {\n            case NM_CUSTOMDRAW:\n                {\n                    LPNMCUSTOMDRAW customDraw = (LPNMCUSTOMDRAW)lParam;\n                    WCHAR className[MAX_PATH];\n\n                    if (!GetClassName(customDraw->hdr.hwndFrom, className, RTL_NUMBER_OF(className)))\n                        className[0] = UNICODE_NULL;\n\n                    if (PhEqualStringZ(className, L\"Button\", FALSE))\n                    {\n                        ULONG buttonStyle = PhGetWindowStyle(customDraw->hdr.hwndFrom);\n\n                        if (FlagOn(buttonStyle, BS_CHECKBOX) == BS_CHECKBOX)\n                        {\n                            switch (customDraw->dwDrawStage)\n                            {\n                            case CDDS_PREPAINT:\n                                {\n                                    PPH_STRING buttonText;\n                                    LONG width;\n\n                                    SetTextColor(customDraw->hdc, RGB(0, 0, 0));\n                                    SetDCBrushColor(customDraw->hdc, RGB(0xff, 0xff, 0xff));\n                                    FillRect(customDraw->hdc, &customDraw->rc, PhGetStockBrush(DC_BRUSH));\n\n                                    if (buttonText = PhGetWindowText(customDraw->hdr.hwndFrom))\n                                    {\n                                        width = PhGetSystemMetrics(SM_CXSMICON, context->WindowDpi);\n\n                                        customDraw->rc.left += width;\n                                        DrawText(\n                                            customDraw->hdc,\n                                            buttonText->Buffer,\n                                            (UINT)buttonText->Length / sizeof(WCHAR),\n                                            &customDraw->rc,\n                                            DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX\n                                            );\n                                        customDraw->rc.left -= width;\n\n                                        PhDereferenceObject(buttonText);\n                                    }\n\n                                    PhImageListDrawIcon(\n                                        context->ImageListHandle,\n                                        0,\n                                        customDraw->hdc,\n                                        customDraw->rc.left,\n                                        customDraw->rc.top + 1, // offset\n                                        ILD_TRANSPARENT,\n                                        FALSE\n                                        );\n\n                                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT);\n                                    return TRUE;\n                                }\n                                break;\n                            }\n\n                            SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_DODEFAULT);\n                            return TRUE;\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\ntypedef struct _PH_RUNAS_PACKAGE_CONTEXT\n{\n    HWND WindowHandle;\n    HWND ParentWindowHandle;\n    HWND ComboBoxHandle;\n    HWND SearchBoxHandle;\n    HWND TreeNewHandle;\n    HIMAGELIST ImageListHandle;\n    LONG WindowDpi;\n    PH_LAYOUT_MANAGER LayoutManager;\n\n    PH_TN_FILTER_SUPPORT TreeFilterSupport;\n    PPH_TN_FILTER_ENTRY TreeFilterEntry;\n    ULONG_PTR SearchMatchHandle;\n\n    HFONT NormalFontHandle;\n    HFONT TitleFontHandle;\n    ULONG TreeNewSortColumn;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PPH_HASHTABLE NodeHashtable;\n    PPH_LIST NodeList;\n\n} PH_RUNAS_PACKAGE_CONTEXT, *PPH_RUNAS_PACKAGE_CONTEXT;\n\ntypedef enum _PH_RUNASPACKAGE_TREE_COLUMN_ITEM\n{\n    PH_RUNASPACKAGE_TREE_COLUMN_ITEM_NAME,\n    PH_RUNASPACKAGE_TREE_COLUMN_ITEM_APPID,\n    PH_RUNASPACKAGE_TREE_COLUMN_ITEM_MAXIMUM\n} PH_RUNASPACKAGE_TREE_COLUMN_ITEM;\n\ntypedef struct _PH_RUNASPACKAGE_TREE_ROOT_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PPH_STRING AppUserModelId;\n    PPH_STRING DisplayName;\n    PPH_STRING PackageInstallPath;\n    PPH_STRING PackageFullName;\n    PPH_STRING SmallLogoPath;\n\n    INT IconIndex;\n\n    PH_STRINGREF TextCache[PH_RUNASPACKAGE_TREE_COLUMN_ITEM_MAXIMUM];\n} PH_RUNASPACKAGE_TREE_ROOT_NODE, *PPH_RUNASPACKAGE_TREE_ROOT_NODE;\n\n#pragma region RunAsPackage TreeList\n\n#define SORT_FUNCTION(Column) PhRunAsPackageTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhRunAsPackageTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE node1 = *(PPH_RUNASPACKAGE_TREE_ROOT_NODE*)_elem1; \\\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE node2 = *(PPH_RUNASPACKAGE_TREE_ROOT_NODE*)_elem2; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \\\n    \\\n    return PhModifySort(sortResult, ((PPH_RUNAS_PACKAGE_CONTEXT)_context)->TreeNewSortOrder); \\\n}\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareStringWithNull(node1->DisplayName, node2->DisplayName, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Version)\n{\n    sortResult = PhCompareStringWithNull(node1->AppUserModelId, node2->AppUserModelId, TRUE);\n}\nEND_SORT_FUNCTION\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhRunAsPackageNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE node1 = *(PPH_RUNASPACKAGE_TREE_ROOT_NODE*)Entry1;\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE node2 = *(PPH_RUNASPACKAGE_TREE_ROOT_NODE*)Entry2;\n\n    return PhEqualString(node1->AppUserModelId, node2->AppUserModelId, TRUE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhRunAsPackageNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashStringRef(&(*(PPH_RUNASPACKAGE_TREE_ROOT_NODE*)Entry)->AppUserModelId->sr, TRUE);\n}\n\nVOID PhRunAsPackageDestroyNode(\n    _In_ PPH_RUNASPACKAGE_TREE_ROOT_NODE Node\n    )\n{\n    PhClearReference(&Node->AppUserModelId);\n    PhClearReference(&Node->DisplayName);\n    PhClearReference(&Node->PackageInstallPath);\n    PhClearReference(&Node->PackageFullName);\n    PhClearReference(&Node->SmallLogoPath);\n\n    PhFree(Node);\n}\n\nPPH_RUNASPACKAGE_TREE_ROOT_NODE PhRunAsPackageAddNode(\n    _Inout_ PPH_RUNAS_PACKAGE_CONTEXT Context,\n    _In_ PPH_APPUSERMODELID_ENUM_ENTRY Package\n    )\n{\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE node;\n\n    node = PhAllocate(sizeof(PH_RUNASPACKAGE_TREE_ROOT_NODE));\n    memset(node, 0, sizeof(PH_RUNASPACKAGE_TREE_ROOT_NODE));\n\n    PhInitializeTreeNewNode(&node->Node);\n\n    memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PH_RUNASPACKAGE_TREE_COLUMN_ITEM_MAXIMUM);\n    node->Node.TextCache = node->TextCache;\n    node->Node.TextCacheSize = PH_RUNASPACKAGE_TREE_COLUMN_ITEM_MAXIMUM;\n\n    PhSetReference(&node->AppUserModelId, Package->AppUserModelId);\n    PhSetReference(&node->DisplayName, Package->PackageDisplayName);\n    PhSetReference(&node->PackageInstallPath, Package->PackageInstallPath);\n    PhSetReference(&node->PackageFullName, Package->PackageFullName);\n    PhSetReference(&node->SmallLogoPath, Package->SmallLogoPath);\n\n    if (Package->SmallLogoPath && PhDoesFileExistWin32(Package->SmallLogoPath->Buffer))\n    {\n        HICON iconHandle = NULL;\n        HBITMAP bitmap;\n        LONG width;\n        LONG height;\n\n        width = PhGetSystemMetrics(SM_CXICON, Context->WindowDpi);\n        height = PhGetSystemMetrics(SM_CYICON, Context->WindowDpi);\n\n        if (bitmap = PhLoadImageFromFile(Package->SmallLogoPath->Buffer, width, height))\n        {\n            iconHandle = PhGdiplusConvertBitmapToIcon(bitmap, width, height, RGB(0, 0, 0));\n            DeleteBitmap(bitmap);\n        }\n\n        if (iconHandle)\n        {\n            node->IconIndex = PhImageListAddIcon(Context->ImageListHandle, iconHandle);\n            DestroyIcon(iconHandle);\n        }\n    }\n\n    PhAddEntryHashtable(Context->NodeHashtable, &node);\n    PhAddItemList(Context->NodeList, node);\n\n    if (Context->TreeFilterSupport.FilterList)\n        node->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &node->Node);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    return node;\n}\n\nPPH_RUNASPACKAGE_TREE_ROOT_NODE PhRunAsPackageFindNode(\n    _In_ PPH_RUNAS_PACKAGE_CONTEXT Context,\n    _In_ PPH_STRING AppUserModelId\n    )\n{\n    PH_RUNASPACKAGE_TREE_ROOT_NODE lookupNode;\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE lookupNodePtr = &lookupNode;\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE *node;\n\n    lookupNode.AppUserModelId = AppUserModelId;\n\n    node = (PPH_RUNASPACKAGE_TREE_ROOT_NODE*)PhFindEntryHashtable(\n        Context->NodeHashtable,\n        &lookupNodePtr\n        );\n\n    if (node)\n        return *node;\n    else\n        return NULL;\n}\n\nVOID PhRunAsPackageRemoveNode(\n    _In_ PPH_RUNAS_PACKAGE_CONTEXT Context,\n    _In_ PPH_RUNASPACKAGE_TREE_ROOT_NODE Node\n    )\n{\n    ULONG index = 0;\n\n    PhRemoveEntryHashtable(Context->NodeHashtable, &Node);\n\n    if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX)\n    {\n        PhRemoveItemList(Context->NodeList, index);\n    }\n\n    PhRunAsPackageDestroyNode(Node);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhRunAsPackageUpdateNode(\n    _In_ PPH_RUNAS_PACKAGE_CONTEXT Context,\n    _In_ PPH_RUNASPACKAGE_TREE_ROOT_NODE Node\n    )\n{\n    memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * PH_RUNASPACKAGE_TREE_COLUMN_ITEM_MAXIMUM);\n\n    PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nBOOLEAN NTAPI PhRunAsPackageTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_RUNAS_PACKAGE_CONTEXT context = Context;\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_RUNASPACKAGE_TREE_ROOT_NODE)getChildren->Node;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(Name),\n                    SORT_FUNCTION(Version)\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PH_RUNASPACKAGE_TREE_COLUMN_ITEM_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (context->TreeNewSortColumn < PH_RUNASPACKAGE_TREE_COLUMN_ITEM_MAXIMUM)\n                    sortFunction = sortFunctions[context->TreeNewSortColumn];\n                else\n                    sortFunction = NULL;\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1;\n            node = (PPH_RUNASPACKAGE_TREE_ROOT_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1;\n            node = (PPH_RUNASPACKAGE_TREE_ROOT_NODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case PH_RUNASPACKAGE_TREE_COLUMN_ITEM_NAME:\n                getCellText->Text = PhGetStringRef(node->DisplayName);\n                break;\n            case PH_RUNASPACKAGE_TREE_COLUMN_ITEM_APPID:\n                getCellText->Text = PhGetStringRef(node->AppUserModelId);\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            node = (PPH_RUNASPACKAGE_TREE_ROOT_NODE)getNodeColor->Node;\n\n            getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_COPY, 0);\n                break;\n            case VK_DELETE:\n                SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_CLOSE, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewCustomDraw:\n        {\n            PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;\n            RECT rect;\n\n            rect = customDraw->CellRect;\n            node = (PPH_RUNASPACKAGE_TREE_ROOT_NODE)customDraw->Node;\n\n            switch (customDraw->Column->Id)\n            {\n            case PH_RUNASPACKAGE_TREE_COLUMN_ITEM_NAME:\n                {\n                    PH_STRINGREF text;\n                    SIZE nameSize;\n                    SIZE textSize;\n                    LONG dpiValue;\n\n                    dpiValue = PhGetWindowDpi(WindowHandle);\n\n                    rect.left += PhGetDpi(15, dpiValue);\n                    rect.top += PhGetDpi(5, dpiValue);\n                    rect.right -= PhGetDpi(5, dpiValue);\n                    rect.bottom -= PhGetDpi(8, dpiValue);\n\n                    rect.left += 32;\n\n                    // top\n                    if (PhEnableThemeSupport)\n                        SetTextColor(customDraw->Dc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                    else\n                        SetTextColor(customDraw->Dc, RGB(0x0, 0x0, 0x0));\n\n                    SelectFont(customDraw->Dc, context->TitleFontHandle);\n                    text = PhIsNullOrEmptyString(node->DisplayName) ? PhGetStringRef(node->AppUserModelId) : PhGetStringRef(node->DisplayName);\n                    GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &nameSize);\n                    DrawText(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &rect, DT_TOP | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE);\n\n                    // bottom\n                    if (PhEnableThemeSupport)\n                        SetTextColor(customDraw->Dc, RGB(0x90, 0x90, 0x90));\n                    else\n                        SetTextColor(customDraw->Dc, RGB(0x64, 0x64, 0x64));\n\n                    SelectFont(customDraw->Dc, context->NormalFontHandle);\n                    text = PhGetStringRef(node->AppUserModelId);\n                    GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize);\n                    DrawText(\n                        customDraw->Dc,\n                        text.Buffer,\n                        (ULONG)text.Length / sizeof(WCHAR),\n                        &rect,\n                        DT_BOTTOM | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE\n                        );\n\n                    if (context->ImageListHandle)\n                    {\n                        LONG width;\n                        LONG height;\n\n                        width = PhGetSystemMetrics(SM_CXICON, context->WindowDpi);\n                        height = PhGetSystemMetrics(SM_CYICON, context->WindowDpi);\n\n                        PhImageListDrawEx(\n                            context->ImageListHandle,\n                            (ULONG)(ULONG_PTR)node->IconIndex,\n                            customDraw->Dc,\n                            customDraw->CellRect.left + 5,//((customDraw->CellRect.right - customDraw->CellRect.left) - width) / 2,\n                            customDraw->CellRect.top + ((customDraw->CellRect.bottom - customDraw->CellRect.top) - height) / 2,\n                            width,\n                            height,\n                            CLR_DEFAULT,\n                            CLR_NONE,\n                            ILD_TRANSPARENT,\n                            ILS_NORMAL\n                            );\n                    }\n\n                }\n                break;\n            }\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhRunAsPackageClearTree(\n    _In_ PPH_RUNAS_PACKAGE_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        PhRunAsPackageDestroyNode(Context->NodeList->Items[i]);\n\n    PhClearHashtable(Context->NodeHashtable);\n    PhClearList(Context->NodeList);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nPPH_RUNASPACKAGE_TREE_ROOT_NODE PhRunAsPackageGetSelectedNode(\n    _In_ PPH_RUNAS_PACKAGE_CONTEXT Context\n    )\n{\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE node = NULL;\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        node = Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n            return node;\n    }\n\n    return NULL;\n}\n\n_Success_(return)\nBOOLEAN PhRunAsPackageGetSelectedNodes(\n    _In_ PPH_RUNAS_PACKAGE_CONTEXT Context,\n    _Out_ PPH_RUNASPACKAGE_TREE_ROOT_NODE **Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_RUNASPACKAGE_TREE_ROOT_NODE node = (PPH_RUNASPACKAGE_TREE_ROOT_NODE)Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            PhAddItemList(list, node);\n        }\n    }\n\n    if (list->Count)\n    {\n        *Nodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhRunAsPackageTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PVOID Context\n    )\n{\n    PPH_RUNASPACKAGE_TREE_ROOT_NODE node = (PPH_RUNASPACKAGE_TREE_ROOT_NODE)Node;\n    PPH_RUNAS_PACKAGE_CONTEXT context = Context;\n\n    if (!context->SearchMatchHandle)\n        return TRUE;\n\n    if (node->AppUserModelId && PhSearchControlMatch(context->SearchMatchHandle, &node->AppUserModelId->sr))\n        return TRUE;\n    if (node->DisplayName && PhSearchControlMatch(context->SearchMatchHandle, &node->DisplayName->sr))\n        return TRUE;\n    if (node->PackageInstallPath && PhSearchControlMatch(context->SearchMatchHandle, &node->PackageInstallPath->sr))\n        return TRUE;\n    if (node->PackageFullName && PhSearchControlMatch(context->SearchMatchHandle, &node->PackageFullName->sr))\n        return TRUE;\n\n    return FALSE;\n}\n\nVOID PhRunAsPackageInitializeTree(\n    _Inout_ PPH_RUNAS_PACKAGE_CONTEXT Context\n    )\n{\n    static CONST PH_STRINGREF PhRunAsPackageLoadingText = PH_STRINGREF_INIT(L\"Loading package information...\");\n\n    Context->NodeList = PhCreateList(20);\n    Context->NodeHashtable = PhCreateHashtable(\n        sizeof(PPH_RUNASPACKAGE_TREE_ROOT_NODE),\n        PhRunAsPackageNodeHashtableEqualFunction,\n        PhRunAsPackageNodeHashtableHashFunction,\n        20\n        );\n\n    Context->NormalFontHandle = PhCreateCommonFont(-10, FW_NORMAL, NULL, Context->WindowDpi);\n    Context->TitleFontHandle = PhCreateCommonFont(-14, FW_BOLD, NULL, Context->WindowDpi);\n\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n    TreeNew_SetCallback(Context->TreeNewHandle, PhRunAsPackageTreeNewCallback, Context);\n    TreeNew_SetRowHeight(Context->TreeNewHandle, PhGetDpi(48, Context->WindowDpi));\n\n    PhAddTreeNewColumnEx2(Context->TreeNewHandle, PH_RUNASPACKAGE_TREE_COLUMN_ITEM_NAME, TRUE, L\"Package\", 80, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_CUSTOMDRAW);\n    //PhAddTreeNewColumnEx2(Context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_VERSION, TRUE, L\"Version\", 80, PH_ALIGN_CENTER, 1, DT_CENTER, 0);\n\n    //PhRunAsPackageLoadSettingsTreeList(Context);\n\n    PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList);\n    Context->TreeFilterEntry = PhAddTreeNewFilter(&Context->TreeFilterSupport, PhRunAsPackageTreeFilterCallback, Context);\n\n    TreeNew_SetEmptyText(Context->TreeNewHandle, &PhRunAsPackageLoadingText, 0);\n    TreeNew_SetTriState(Context->TreeNewHandle, TRUE);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n}\n\nVOID PhRunAsPackageDeleteTree(\n    _In_ PPH_RUNAS_PACKAGE_CONTEXT Context\n    )\n{\n    PhRemoveTreeNewFilter(&Context->TreeFilterSupport, Context->TreeFilterEntry);\n    PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport);\n\n    if (Context->TitleFontHandle)\n        DeleteFont(Context->TitleFontHandle);\n    if (Context->NormalFontHandle)\n        DeleteFont(Context->NormalFontHandle);\n\n    //PhRunAsPackageSaveSettingsTreeList(Context);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        PhRunAsPackageDestroyNode(Context->NodeList->Items[i]);\n\n    PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n}\n\n#pragma endregion\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhEnumPackageThreadCallback(\n    _In_ PVOID Context\n    )\n{\n    PPH_RUNAS_PACKAGE_CONTEXT context = Context;\n\n    PPH_LIST apps = PhEnumPackageApplicationUserModelIds();\n    PostMessage(context->WindowHandle, WM_PH_UPDATE_DIALOG, 0, (LPARAM)apps);\n\n    PhDereferenceObject(context);\n    return STATUS_SUCCESS;\n}\n\nstatic VOID PhRunAsPackageSetImagelist(\n    _Inout_ PPH_RUNAS_PACKAGE_CONTEXT Context\n    )\n{\n    if (Context->ImageListHandle)\n    {\n        PhImageListDestroy(Context->ImageListHandle);\n        Context->ImageListHandle = NULL;\n    }\n\n    Context->ImageListHandle = PhImageListCreate(\n        PhGetSystemMetrics(SM_CXICON, Context->WindowDpi),\n        PhGetSystemMetrics(SM_CYICON, Context->WindowDpi),\n        ILC_MASK | ILC_COLOR32,\n        20,\n        10\n        );\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhPackageWindowContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    //PPH_RUNAS_PACKAGE_CONTEXT context = (PPH_RUNAS_PACKAGE_CONTEXT)Object;\n    NOTHING;\n}\n\nPPH_RUNAS_PACKAGE_CONTEXT PhCreatePackageWindowContext(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PPH_OBJECT_TYPE PhPackageWindowContextObjectType;\n    PPH_RUNAS_PACKAGE_CONTEXT context;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhPackageWindowContextObjectType = PhCreateObjectType(L\"RunAsPackageWindowContext\", 0, PhPackageWindowContextDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    context = PhCreateObject(sizeof(PH_RUNAS_PACKAGE_CONTEXT), PhPackageWindowContextObjectType);\n    memset(context, 0, sizeof(PH_RUNAS_PACKAGE_CONTEXT));\n\n    return context;\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhpRunAsPackageSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_RUNAS_PACKAGE_CONTEXT context = Context;\n\n    assert(context);\n\n    context->SearchMatchHandle = MatchHandle;\n\n    PhApplyTreeNewFilters(&context->TreeFilterSupport);\n}\n\nINT_PTR CALLBACK PhRunAsPackageWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_RUNAS_PACKAGE_CONTEXT context = NULL;\n\n    if (WindowMessage == WM_INITDIALOG)\n    {\n        context = PhCreatePackageWindowContext();\n\n        PhSetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (WindowMessage)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = WindowHandle;\n            context->ParentWindowHandle = (HWND)lParam;\n            context->ComboBoxHandle = GetDlgItem(WindowHandle, IDC_PROGRAMCOMBO);\n            context->SearchBoxHandle = GetDlgItem(WindowHandle, IDC_SEARCH);\n            context->TreeNewHandle = GetDlgItem(WindowHandle, IDC_LIST);\n            context->WindowDpi = PhGetWindowDpi(WindowHandle);\n\n            PhSetApplicationWindowIconEx(WindowHandle, context->WindowDpi);\n\n            PhInitializeLayoutManager(&context->LayoutManager, WindowHandle);\n            PhAddLayoutItem(&context->LayoutManager, context->ComboBoxHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(WindowHandle, IDC_BROWSE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, context->SearchBoxHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(WindowHandle, IDC_REFRESH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(WindowHandle, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(WindowHandle, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_RUN_AS_PACKAGE_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_RUN_AS_PACKAGE_WINDOW_POSITION, SETTING_RUN_AS_PACKAGE_WINDOW_SIZE, WindowHandle);\n            else\n                PhCenterWindow(WindowHandle, GetParent(WindowHandle));\n\n            TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_RUNASPACKAGE_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE);\n\n            PhpAddProgramsToComboBox(context->ComboBoxHandle);\n            ComboBox_SetCurSel(context->ComboBoxHandle, 0);\n\n            PhRunAsPackageSetImagelist(context);\n            PhRunAsPackageInitializeTree(context);\n\n            PhCreateSearchControl(\n                WindowHandle,\n                context->SearchBoxHandle,\n                L\"Search Packages\",\n                PhpRunAsPackageSearchControlCallback,\n                context\n                );\n\n            PhInitializeWindowTheme(WindowHandle, PhEnableThemeSupport);\n\n            PhSetDialogFocus(WindowHandle, GetDlgItem(WindowHandle, IDCANCEL));\n\n            EnableWindow(GetDlgItem(WindowHandle, IDC_REFRESH), FALSE);\n            PhReferenceObject(context);\n            PhCreateThread2(PhEnumPackageThreadCallback, context);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhSaveWindowPlacementToSetting(SETTING_RUN_AS_PACKAGE_WINDOW_POSITION, SETTING_RUN_AS_PACKAGE_WINDOW_SIZE, WindowHandle);\n\n            PhRunAsPackageDeleteTree(context);\n\n            PhImageListDestroy(context->ImageListHandle);\n\n            PhDestroyWindowIcon(WindowHandle);\n\n            PhDereferenceObject(context);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n\n            TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_RUNASPACKAGE_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            context->WindowDpi = LOWORD(wParam);\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_PH_UPDATE_DIALOG:\n        {\n            PPH_LIST apps = (PPH_LIST)lParam;\n\n            EnableWindow(GetDlgItem(WindowHandle, IDC_REFRESH), TRUE);\n\n            if (apps)\n            {\n                TreeNew_SetRedraw(context->TreeNewHandle, FALSE);\n\n                for (ULONG i = 0; i < apps->Count; i++)\n                {\n                    PhRunAsPackageAddNode(context, apps->Items[i]);\n                }\n\n                TreeNew_SetRedraw(context->TreeNewHandle, TRUE);\n                TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_RUNASPACKAGE_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE);\n\n                PhDestroyEnumPackageApplicationUserModelIds(apps);\n            }\n            else\n            {\n                // Error\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(WindowHandle, IDCANCEL);\n                break;\n            case IDC_BROWSE:\n                {\n                    PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Executable files (*.exe;*.pif;*.com;*.bat;*.cmd)\", L\"*.exe;*.pif;*.com;*.bat;*.cmd\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog = PhCreateOpenFileDialog();\n\n                    PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters));\n\n                    if (PhShowFileDialog(WindowHandle, fileDialog))\n                    {\n                        PPH_STRING fileName;\n\n                        if (fileName = PhGetFileDialogFileName(fileDialog))\n                        {\n                            ComboBox_SetText(context->ComboBoxHandle, PhGetString(fileName));\n                            PhDereferenceObject(fileName);\n                        }\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            case IDOK:\n                {\n                    PPH_RUNASPACKAGE_TREE_ROOT_NODE node;\n                    HRESULT status;\n                    PPH_STRING windowText;\n\n                    if (node = PhRunAsPackageGetSelectedNode(context))\n                    {\n                        if (windowText = PhGetWindowText(context->ComboBoxHandle))\n                        {\n                            PPH_STRING argumentsString = NULL;\n                            PPH_STRING commandString = NULL;\n                            PPH_STRING directoryString = NULL;\n                            PPH_STRING fullFileName = NULL;\n                            PH_STRINGREF fileName;\n                            PH_STRINGREF arguments;\n\n                            if (PhIsNullOrEmptyString(windowText))\n                                break;\n\n                            if (!(commandString = PhExpandEnvironmentStrings(&windowText->sr)))\n                                commandString = PhCreateString2(&windowText->sr);\n\n                            PhParseCommandLineFuzzy(&commandString->sr, &fileName, &arguments, &fullFileName);\n\n                            if (PhIsNullOrEmptyString(fullFileName))\n                                PhMoveReference(&fullFileName, PhCreateString2(&fileName));\n\n                            if (arguments.Length)\n                            {\n                                argumentsString = PhCreateString2(&arguments);\n                            }\n\n                            directoryString = PhpQueryRunFileParentDirectory(!!PhGetOwnTokenAttributes().Elevated);\n\n                            status = PhCreateProcessDesktopPackage(\n                                PhGetString(node->AppUserModelId),\n                                PhGetString(fullFileName),\n                                PhGetString(argumentsString),\n                                PhGetString(directoryString),\n                                FALSE,\n                                NULL,\n                                NULL\n                                );\n\n                            if (HR_SUCCESS(status))\n                            {\n                                PhRecentListAddCommand(&commandString->sr);\n\n                                EndDialog(WindowHandle, IDOK);\n                            }\n                            else\n                            {\n                                PhShowStatus(WindowHandle, L\"Unable to execute the command.\", 0, status);\n                            }\n\n                            PhClearReference(&directoryString);\n                            PhClearReference(&argumentsString);\n                            PhClearReference(&fullFileName);\n                            PhClearReference(&commandString);\n                        }\n                    }\n                }\n                break;\n            case IDC_REFRESH:\n                {\n                    EnableWindow(GetDlgItem(WindowHandle, IDC_REFRESH), FALSE);\n\n                    PhRunAsPackageClearTree(context);\n                    PhRunAsPackageSetImagelist(context);\n\n                    PhReferenceObject(context);\n                    PhCreateThread2(PhEnumPackageThreadCallback, context);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/searchbox.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2012-2023\n *     jxy-s   2023-2024\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n\nVOID PhCreateSearchControl(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND SearchWindowHandle,\n    _In_opt_ PCWSTR BannerText,\n    _In_ PPH_SEARCHCONTROL_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PhCreateSearchControlEx(\n        ParentWindowHandle,\n        SearchWindowHandle,\n        BannerText,\n        NtCurrentImageBase(),\n        PhEnableThemeSupport ? MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_MODERN_LIGHT) : MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_MODERN_DARK),\n        PhEnableThemeSupport ? MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_MODERN_LIGHT) : MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_MODERN_DARK),\n        PhEnableThemeSupport ? MAKEINTRESOURCE(IDB_SEARCH_REGEX_MODERN_LIGHT) : MAKEINTRESOURCE(IDB_SEARCH_REGEX_MODERN_DARK),\n        PhEnableThemeSupport ? MAKEINTRESOURCE(IDB_SEARCH_CASE_MODERN_LIGHT) : MAKEINTRESOURCE(IDB_SEARCH_CASE_MODERN_DARK),\n        SETTING_SEARCH_CONTROL_REGEX,\n        SETTING_SEARCH_CONTROL_CASE_SENSITIVE,\n        Callback,\n        Context\n        );\n}\n"
  },
  {
    "path": "SystemInformer/sessmsg.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2013\n *     dmex    2019-2023\n *\n */\n\n#include <phapp.h>\n#include <lsasup.h>\n#include <winsta.h>\n\nstatic CONST PH_KEY_VALUE_PAIR PhpMessageBoxIconPairs[] =\n{\n    SIP(L\"None\", MB_OK),\n    SIP(L\"Information\", MB_ICONINFORMATION),\n    SIP(L\"Warning\", MB_ICONWARNING),\n    SIP(L\"Error\", MB_ICONERROR),\n    SIP(L\"Question\", MB_ICONQUESTION)\n};\n\nINT_PTR CALLBACK PhpSessionSendMessageDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HWND iconComboBox;\n            PPH_STRING currentUserName;\n\n            PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, UlongToPtr((ULONG)lParam));\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            iconComboBox = GetDlgItem(hwndDlg, IDC_TYPE);\n            ComboBox_AddString(iconComboBox, L\"None\");\n            ComboBox_AddString(iconComboBox, L\"Information\");\n            ComboBox_AddString(iconComboBox, L\"Warning\");\n            ComboBox_AddString(iconComboBox, L\"Error\");\n            ComboBox_AddString(iconComboBox, L\"Question\");\n            PhSelectComboBoxString(iconComboBox, L\"None\", FALSE);\n\n            if (currentUserName = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE))\n            {\n                PhSetDialogItemText(\n                    hwndDlg,\n                    IDC_TITLE,\n                    PhaFormatString(L\"Message from %s\", currentUserName->Buffer)->Buffer\n                    );\n                PhDereferenceObject(currentUserName);\n            }\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_TEXT));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); // HACK (dmex)\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    ULONG sessionId = PtrToUlong(PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT));\n                    PPH_STRING title;\n                    PPH_STRING text;\n                    ULONG icon = 0;\n                    ULONG64 timeout = 0;\n                    ULONG response;\n\n                    title = PhaGetDlgItemText(hwndDlg, IDC_TITLE);\n                    text = PhaGetDlgItemText(hwndDlg, IDC_TEXT);\n\n                    PhFindIntegerSiKeyValuePairs(\n                        PhpMessageBoxIconPairs,\n                        sizeof(PhpMessageBoxIconPairs),\n                        PhaGetDlgItemText(hwndDlg, IDC_TYPE)->Buffer,\n                        &icon\n                        );\n                    PhStringToInteger64(\n                        &PhaGetDlgItemText(hwndDlg, IDC_TIMEOUT)->sr,\n                        10,\n                        &timeout\n                        );\n\n                    if (WinStationSendMessageW(\n                        NULL,\n                        sessionId,\n                        title->Buffer,\n                        (ULONG)title->Length,\n                        text->Buffer,\n                        (ULONG)text->Length,\n                        icon,\n                        (ULONG)timeout,\n                        &response,\n                        TRUE\n                        ))\n                    {\n                        EndDialog(hwndDlg, IDOK);\n                    }\n                    else\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to send the message\", 0, GetLastError());\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhShowSessionSendMessageDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ ULONG SessionId\n    )\n{\n    PhDialogBox(\n        NtCurrentImageBase(),\n        MAKEINTRESOURCE(IDD_EDITMESSAGE),\n        ParentWindowHandle,\n        PhpSessionSendMessageDlgProc,\n        UlongToPtr(SessionId)\n        );\n}\n"
  },
  {
    "path": "SystemInformer/sessprp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2018-2024\n *\n */\n\n#include <phapp.h>\n#include <emenu.h>\n#include <phsettings.h>\n#include <winsta.h>\n\nINT_PTR CALLBACK PhpSessionPropertiesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nstatic CONST PH_KEY_VALUE_PAIR PhpConnectStatePairs[] =\n{\n    SIP(L\"Active\", State_Active),\n    SIP(L\"Connected\", State_Connected),\n    SIP(L\"ConnectQuery\", State_ConnectQuery),\n    SIP(L\"Shadow\", State_Shadow),\n    SIP(L\"Disconnected\", State_Disconnected),\n    SIP(L\"Idle\", State_Idle),\n    SIP(L\"Listen\", State_Listen),\n    SIP(L\"Reset\", State_Reset),\n    SIP(L\"Down\", State_Down),\n    SIP(L\"Init\", State_Init)\n};\n\nVOID PhShowSessionProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ ULONG SessionId\n    )\n{\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_SESSION),\n        PhCsForceNoParent ? NULL : ParentWindowHandle,\n        PhpSessionPropertiesDlgProc,\n        UlongToPtr(SessionId)\n        );\n}\n\ntypedef struct _PHP_SESSION_PROPERTIES_CONTEXT\n{\n    HWND ListViewHandle;\n    ULONG SessionId;\n    PH_LAYOUT_MANAGER LayoutManager;\n} PHP_SESSION_PROPERTIES_CONTEXT, *PPHP_SESSION_PROPERTIES_CONTEXT;\n\nVOID PhpSessionPropertiesQueryWinStationInfo(\n    _In_ PPHP_SESSION_PROPERTIES_CONTEXT Context,\n    _In_ ULONG SessionId\n    )\n{\n    WINSTATIONINFORMATION winStationInfo;\n    BOOLEAN haveWinStationInfo;\n    WINSTATIONCLIENT clientInfo;\n    BOOLEAN haveClientInfo;\n    ULONG returnLength;\n    PWSTR stateString;\n\n    // Query basic session information\n\n    haveWinStationInfo = WinStationQueryInformationW(\n        WINSTATION_CURRENT_SERVER,\n        SessionId,\n        WinStationInformation,\n        &winStationInfo,\n        sizeof(WINSTATIONINFORMATION),\n        &returnLength\n        );\n\n    // Query client information\n\n    haveClientInfo = WinStationQueryInformationW(\n        WINSTATION_CURRENT_SERVER,\n        SessionId,\n        WinStationClient,\n        &clientInfo,\n        sizeof(WINSTATIONCLIENT),\n        &returnLength\n        );\n\n    if (haveWinStationInfo)\n    {\n        PH_FORMAT format[3];\n        WCHAR formatBuffer[256];\n\n        PhInitFormatS(&format[0], winStationInfo.Domain);\n        PhInitFormatC(&format[1], OBJ_NAME_PATH_SEPARATOR);\n        PhInitFormatS(&format[2], winStationInfo.UserName);\n\n        if (PhFormatToBuffer(\n            format,\n            RTL_NUMBER_OF(format),\n            formatBuffer,\n            sizeof(formatBuffer),\n            NULL\n            ))\n        {\n            PhSetListViewSubItem(Context->ListViewHandle, 0, 1, formatBuffer);\n        }\n    }\n\n    PhSetListViewSubItem(Context->ListViewHandle, 1, 1, PhaFormatUInt64(SessionId, FALSE)->Buffer);\n\n    if (haveWinStationInfo)\n    {\n        if (PhFindStringSiKeyValuePairs(\n            PhpConnectStatePairs,\n            sizeof(PhpConnectStatePairs),\n            winStationInfo.ConnectState,\n            &stateString\n            ))\n        {\n            PhSetListViewSubItem(Context->ListViewHandle, 2, 1, stateString);\n        }\n    }\n\n    if (haveWinStationInfo && winStationInfo.LogonTime.QuadPart != 0)\n    {\n        SYSTEMTIME systemTime;\n        PPH_STRING time;\n\n        PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.LogonTime);\n        time = PhFormatDateTime(&systemTime);\n        PhSetListViewSubItem(Context->ListViewHandle, 3, 1, time->Buffer);\n        PhDereferenceObject(time);\n    }\n\n    if (haveWinStationInfo && winStationInfo.ConnectTime.QuadPart != 0)\n    {\n        SYSTEMTIME systemTime;\n        PPH_STRING time;\n\n        PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.ConnectTime);\n        time = PhFormatDateTime(&systemTime);\n        PhSetListViewSubItem(Context->ListViewHandle, 4, 1, time->Buffer);\n        PhDereferenceObject(time);\n    }\n\n    if (haveWinStationInfo && winStationInfo.DisconnectTime.QuadPart != 0)\n    {\n        SYSTEMTIME systemTime;\n        PPH_STRING time;\n\n        PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.DisconnectTime);\n        time = PhFormatDateTime(&systemTime);\n        PhSetListViewSubItem(Context->ListViewHandle, 5, 1, time->Buffer);\n        PhDereferenceObject(time);\n    }\n\n    if (haveWinStationInfo && winStationInfo.LastInputTime.QuadPart != 0)\n    {\n        SYSTEMTIME systemTime;\n        PPH_STRING time;\n\n        PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.LastInputTime);\n        time = PhFormatDateTime(&systemTime);\n        PhSetListViewSubItem(Context->ListViewHandle, 6, 1, time->Buffer);\n        PhDereferenceObject(time);\n    }\n\n    if (haveClientInfo && clientInfo.ClientName[0] != UNICODE_NULL)\n    {\n        WCHAR addressString[INET6_ADDRSTRLEN + 1];\n\n        PhSetListViewSubItem(Context->ListViewHandle, 7, 1, clientInfo.ClientName);\n\n        if (clientInfo.ClientAddressFamily == AF_INET6)\n        {\n            ULONG addressLength = RTL_NUMBER_OF(addressString);\n            IN6_ADDR address;\n            ULONG i;\n            PUSHORT in;\n            PUSHORT out;\n\n            // IPv6 is special - the client address data is a reversed version of\n            // the real address.\n\n            in = (PUSHORT)clientInfo.ClientAddress;\n            out = (PUSHORT)address.u.Word;\n\n            for (i = 8; i != 0; i--)\n            {\n                *out = _byteswap_ushort(*in);\n                in++;\n                out++;\n            }\n\n            RtlIpv6AddressToStringEx(&address, 0, 0, addressString, &addressLength);\n        }\n        else\n        {\n            wcscpy_s(addressString, 65, clientInfo.ClientAddress);\n        }\n\n        PhSetListViewSubItem(Context->ListViewHandle, 8, 1, addressString);\n        PhSetListViewSubItem(Context->ListViewHandle, 9, 1,\n            PhaFormatString(L\"%ux%u@%u\", clientInfo.HRes, clientInfo.VRes, clientInfo.ColorDepth)->Buffer\n            );\n    }\n}\n\nINT_PTR CALLBACK PhpSessionPropertiesDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_SESSION_PROPERTIES_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocateZero(sizeof(PHP_SESSION_PROPERTIES_CONTEXT));\n        context->SessionId = (ULONG)lParam;\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 150, L\"Name\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 250, L\"Value\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            ListView_EnableGroupView(context->ListViewHandle, TRUE);\n            PhAddListViewGroup(context->ListViewHandle, 0, L\"User\");\n            //PhAddListViewGroup(context->ListViewHandle, 1, L\"Profile\");\n\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 0, L\"User name\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 1, L\"Session ID\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 2, L\"State\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 3, L\"Logon time\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 4, L\"Connect time\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 5, L\"Disconnect time\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 6, L\"Last input time\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 7, L\"Client name\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 8, L\"Client address\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, 9, L\"Client display\", NULL);\n\n            //PhAddListViewGroupItem(context->ListViewHandle, 1, 10, L\"LastLogon\", NULL);\n            //PhAddListViewGroupItem(context->ListViewHandle, 1, 11, L\"LastLogoff\", NULL);\n            //PhAddListViewGroupItem(context->ListViewHandle, 1, 12, L\"Home directory\", NULL);\n            //PhAddListViewGroupItem(context->ListViewHandle, 1, 13, L\"Profile directory\", NULL);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            PhpSessionPropertiesQueryWinStationInfo(context, context->SessionId);\n            //PhpSessionPropertiesQuerySamAccountInfo(context, context->SessionId);\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); // HACK\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n            PhFree(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                EndDialog(hwndDlg, IDOK);\n                break;\n            }\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID* listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(context->ListViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/sessshad.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n */\n\n#include <phapp.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <winsta.h>\n\nstatic CONST PH_KEY_VALUE_PAIR VirtualKeyPairs[] =\n{\n    SIP(L\"0\", '0'),\n    SIP(L\"1\", '1'),\n    SIP(L\"2\", '2'),\n    SIP(L\"3\", '3'),\n    SIP(L\"4\", '4'),\n    SIP(L\"5\", '5'),\n    SIP(L\"6\", '6'),\n    SIP(L\"7\", '7'),\n    SIP(L\"8\", '8'),\n    SIP(L\"9\", '9'),\n    SIP(L\"A\", 'A'),\n    SIP(L\"B\", 'B'),\n    SIP(L\"C\", 'C'),\n    SIP(L\"D\", 'D'),\n    SIP(L\"E\", 'E'),\n    SIP(L\"F\", 'F'),\n    SIP(L\"G\", 'G'),\n    SIP(L\"H\", 'H'),\n    SIP(L\"I\", 'I'),\n    SIP(L\"J\", 'J'),\n    SIP(L\"K\", 'K'),\n    SIP(L\"L\", 'L'),\n    SIP(L\"M\", 'M'),\n    SIP(L\"N\", 'N'),\n    SIP(L\"O\", 'O'),\n    SIP(L\"P\", 'P'),\n    SIP(L\"Q\", 'Q'),\n    SIP(L\"R\", 'R'),\n    SIP(L\"S\", 'S'),\n    SIP(L\"T\", 'T'),\n    SIP(L\"U\", 'U'),\n    SIP(L\"V\", 'V'),\n    SIP(L\"W\", 'W'),\n    SIP(L\"X\", 'X'),\n    SIP(L\"Y\", 'Y'),\n    SIP(L\"Z\", 'Z'),\n    SIP(L\"{backspace}\", VK_BACK),\n    SIP(L\"{delete}\", VK_DELETE),\n    SIP(L\"{down}\", VK_DOWN),\n    SIP(L\"{end}\", VK_END),\n    SIP(L\"{enter}\", VK_RETURN),\n    SIP(L\"{F2}\", VK_F2),\n    SIP(L\"{F3}\", VK_F3),\n    SIP(L\"{F4}\", VK_F4),\n    SIP(L\"{F5}\", VK_F5),\n    SIP(L\"{F6}\", VK_F6),\n    SIP(L\"{F7}\", VK_F7),\n    SIP(L\"{F8}\", VK_F8),\n    SIP(L\"{F9}\", VK_F9),\n    SIP(L\"{F10}\", VK_F10),\n    SIP(L\"{F11}\", VK_F11),\n    SIP(L\"{F12}\", VK_F12),\n    SIP(L\"{home}\", VK_HOME),\n    SIP(L\"{insert}\", VK_INSERT),\n    SIP(L\"{left}\", VK_LEFT),\n    SIP(L\"{-}\", VK_SUBTRACT),\n    SIP(L\"{pagedown}\", VK_NEXT),\n    SIP(L\"{pageup}\", VK_PRIOR),\n    SIP(L\"{+}\", VK_ADD),\n    SIP(L\"{prtscrn}\", VK_SNAPSHOT),\n    SIP(L\"{right}\", VK_RIGHT),\n    SIP(L\"{spacebar}\", VK_SPACE),\n    SIP(L\"{*}\", VK_MULTIPLY),\n    SIP(L\"{tab}\", VK_TAB),\n    SIP(L\"{up}\", VK_UP)\n};\n\nINT_PTR CALLBACK PhpSessionShadowDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowSessionShadowDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ ULONG SessionId\n    )\n{\n    ULONG sessionId = ULONG_MAX;\n\n    PhGetProcessSessionId(NtCurrentProcess(), &sessionId);\n\n    if (SessionId == sessionId)\n    {\n        PhShowError2(ParentWindowHandle, L\"Unable to shadow session.\", L\"%s\", L\"You cannot remote control the current session.\");\n        return;\n    }\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_SHADOWSESSION),\n        ParentWindowHandle,\n        PhpSessionShadowDlgProc,\n        UlongToPtr(SessionId)\n        );\n}\n\nINT_PTR CALLBACK PhpSessionShadowDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HWND virtualKeyComboBox;\n            PH_INTEGER_PAIR hotkey;\n            ULONG i;\n            PWSTR stringToSelect;\n\n            PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, UlongToPtr((ULONG)lParam));\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            hotkey = PhGetIntegerPairSetting(SETTING_SESSION_SHADOW_HOTKEY);\n\n            // Set up the hotkeys.\n\n            virtualKeyComboBox = GetDlgItem(hwndDlg, IDC_VIRTUALKEY);\n            stringToSelect = L\"{*}\";\n\n            for (i = 0; i < sizeof(VirtualKeyPairs) / sizeof(PH_KEY_VALUE_PAIR); i++)\n            {\n                ComboBox_AddString(virtualKeyComboBox, VirtualKeyPairs[i].Key);\n\n                if (PtrToUlong(VirtualKeyPairs[i].Value) == (ULONG)hotkey.X)\n                {\n                    stringToSelect = VirtualKeyPairs[i].Key;\n                }\n            }\n\n            PhSelectComboBoxString(virtualKeyComboBox, stringToSelect, FALSE);\n\n            // Set up the modifiers.\n\n            Button_SetCheck(GetDlgItem(hwndDlg, IDC_SHIFT), hotkey.Y & KBDSHIFT);\n            Button_SetCheck(GetDlgItem(hwndDlg, IDC_CTRL), hotkey.Y & KBDCTRL);\n            Button_SetCheck(GetDlgItem(hwndDlg, IDC_ALT), hotkey.Y & KBDALT);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (LOWORD(wParam))\n            {\n            case IDCANCEL:\n                EndDialog(hwndDlg, IDCANCEL);\n                break;\n            case IDOK:\n                {\n                    ULONG sessionId = PtrToUlong(PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT));\n                    ULONG virtualKey;\n                    ULONG modifiers;\n                    PPH_STRING computerName;\n\n                    virtualKey = VK_MULTIPLY;\n                    PhFindIntegerSiKeyValuePairs(\n                        VirtualKeyPairs,\n                        sizeof(VirtualKeyPairs),\n                        PhaGetDlgItemText(hwndDlg, IDC_VIRTUALKEY)->Buffer,\n                        &virtualKey\n                        );\n\n                    modifiers = 0;\n\n                    if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHIFT)) == BST_CHECKED)\n                        modifiers |= KBDSHIFT;\n                    if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_CTRL)) == BST_CHECKED)\n                        modifiers |= KBDCTRL;\n                    if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALT)) == BST_CHECKED)\n                        modifiers |= KBDALT;\n\n                    if (computerName = PhGetActiveComputerName())\n                    {\n                        if (WinStationShadow(NULL, PhGetString(computerName), sessionId, (UCHAR)virtualKey, (USHORT)modifiers))\n                        {\n                            PH_INTEGER_PAIR hotkey;\n\n                            hotkey.X = virtualKey;\n                            hotkey.Y = modifiers;\n                            PhSetIntegerPairSetting(SETTING_SESSION_SHADOW_HOTKEY, hotkey);\n\n                            EndDialog(hwndDlg, IDOK);\n                        }\n                        else\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to remote control the session\", 0, GetLastError());\n                        }\n\n                        PhDereferenceObject(computerName);\n                    }\n                    else\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to remote control the session\", 0, ERROR_DS_NAME_TOO_LONG);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/settings.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *     jxy-s   2021\n *\n */\n\n#include <phapp.h>\n#include <settings.h>\n#define PH_SETTINGS_PRIVATE\n#include <phsettings.h>\n\nVOID PhAddDefaultSettings(\n    VOID\n    )\n{\n    PhpAddStringSetting(SETTING_SCHEMA_FILE, L\"https://systeminformer.io/settings.schema.json\");\n    PhpAddIntegerSetting(SETTING_ALLOW_ONLY_ONE_INSTANCE, L\"1\");\n    PhpAddIntegerSetting(SETTING_CLOSE_ON_ESCAPE, L\"0\");\n    PhpAddStringSetting(SETTING_DBGHELP_SEARCH_PATH, L\"SRV*C:\\\\Symbols*https://msdl.microsoft.com/download/symbols\");\n    PhpAddIntegerSetting(SETTING_DBGHELP_UNDECORATE, L\"1\");\n    PhpAddIntegerSetting(SETTING_DBGHELP_VERIFY_MICROSOFT_CHAIN, L\"1\");\n    PhpAddStringSetting(SETTING_DISABLED_PLUGINS, L\"\");\n    PhpAddIntegerSetting(SETTING_ELEVATION_LEVEL, L\"1\"); // PromptElevateAction\n    PhpAddIntegerSetting(SETTING_ENABLE_ADVANCED_OPTIONS, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_AVX_SUPPORT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_BITMAP_SUPPORT, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_BREAK_ON_TERMINATION, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_BOOT_OBJECTS_ENUMERATE, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_COMMAND_LINE_TOOLTIPS, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_CYCLE_CPU_USAGE, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_DEFERRED_LAYOUT, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_DEVICE_SUPPORT, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_DEVICE_NOTIFY_SUPPORT, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_IMAGE_COHERENCY_SUPPORT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_INSTANT_TOOLTIPS, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_HEAP_REFLECTION, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_HEAP_MEMORY_TAGGING, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_LAST_PROCESS_SHUTDOWN, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_LINUX_SUBSYSTEM_SUPPORT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_HANDLE_SNAPSHOT, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_MINIDUMP_KERNEL_MINIDUMP, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_MINIDUMP_SNAPSHOT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_MONOSPACE_FONT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_NETWORK_BOUND_CONNECTIONS, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_NETWORK_RESOLVE, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_NETWORK_RESOLVE_DOH, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_MEM_STRINGS_TREE_DIALOG, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_PACKAGE_ICON_SUPPORT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_PROCESS_HANDLE_PNP_DEVICE_NAME_SUPPORT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_PLUGINS, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_PLUGINS_NATIVE, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_GRAPH_MAX_SCALE, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_GRAPH_MAX_TEXT, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SERVICE_NON_POLL, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SERVICE_NON_POLL_NOTIFY, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SERVICE_STAGE2, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SERVICE_PROGRESS_DIALOG, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SHELL_EXECUTE_SKIP_IFEO_DEBUGGER, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_STAGE2, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_STREAMER_MODE, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_START_AS_ADMIN, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_START_AS_ADMIN_ALWAYS_ON_TOP, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_DEFAULT_SAFE_PLUGINS, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SECURITY_ADVANCED_DIALOG, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SHORT_RELATIVE_START_TIME, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SHUTDOWN_CRITICAL_MENU, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SHUTDOWN_BOOT_MENU, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_SILENT_CRASH_NOTIFY, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_THEME_SUPPORT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_THEME_ACRYLIC_SUPPORT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_THEME_ACRYLIC_WINDOW_SUPPORT, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_THEME_ANIMATION, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_THEME_NATIVE_BUTTONS, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_THREAD_STACK_INLINE_SYMBOLS, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_THREAD_STACK_LINE_INFORMATION, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_TOKEN_REMOVED_PRIVILEGES, L\"0\");\n    PhpAddIntegerSetting(SETTING_ENABLE_TOOLTIP_SUPPORT, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_UPDATE_DEFAULT_FIRMWARE_BOOT_ENTRY, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_VERSION_SUPPORT, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_WARNINGS, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_WARNINGS_RUNAS, L\"1\");\n    PhpAddIntegerSetting(SETTING_ENABLE_WINDOW_TEXT, L\"1\");\n    PhpAddStringSetting(SETTING_ENVIRONMENT_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_ENVIRONMENT_TREE_LIST_SORT, L\"0,0\"); // 0, NoSortOrder\n    PhpAddIntegerSetting(SETTING_ENVIRONMENT_TREE_LIST_FLAGS, L\"0\");\n    PhpAddIntegerSetting(SETTING_SEARCH_CONTROL_REGEX, L\"0\");\n    PhpAddIntegerSetting(SETTING_SEARCH_CONTROL_CASE_SENSITIVE, L\"0\");\n    PhpAddStringSetting(SETTING_FIND_OBJ_TREE_LIST_COLUMNS, L\"\");\n    PhpAddIntegerPairSetting(SETTING_FIND_OBJ_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_FIND_OBJ_WINDOW_SIZE, L\"@96|550,420\");\n    PhpAddStringSetting(SETTING_THREAD_STACKS_TREE_LIST_COLUMNS, L\"\");\n    PhpAddIntegerPairSetting(SETTING_THREAD_STACKS_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_THREAD_STACKS_WINDOW_SIZE, L\"@96|550,420\");\n    PhpAddStringSetting(SETTING_FILE_BROWSE_EXECUTABLE, L\"%SystemRoot%\\\\explorer.exe /select,\\\"%s\\\"\");\n    PhpAddIntegerSetting(SETTING_FIRST_RUN, L\"1\");\n    PhpAddStringSetting(SETTING_FONT, L\"\"); // null\n    PhpAddStringSetting(SETTING_FONT_MONOSPACE, L\"\"); // null\n    PhpAddIntegerSetting(SETTING_FONT_QUALITY, L\"0\");\n    PhpAddIntegerSetting(SETTING_FORCE_NO_PARENT, L\"1\");\n    PhpAddStringSetting(SETTING_HANDLE_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_HANDLE_TREE_LIST_SORT, L\"0,1\"); // 0, AscendingSortOrder\n    PhpAddIntegerSetting(SETTING_HANDLE_TREE_LIST_FLAGS, L\"3\");\n    PhpAddIntegerPairSetting(SETTING_HANDLE_PROPERTIES_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_HANDLE_PROPERTIES_WINDOW_SIZE, L\"@96|260,260\");\n    PhpAddStringSetting(SETTING_HANDLE_STATISTICS_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_HANDLE_STATISTICS_LIST_VIEW_SORT, L\"0,1\");\n    PhpAddIntegerPairSetting(SETTING_HANDLE_STATISTICS_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_HANDLE_STATISTICS_WINDOW_SIZE, L\"@96|0,0\");\n    PhpAddIntegerSetting(SETTING_HIDE_DEFAULT_SERVICES, L\"0\");\n    PhpAddIntegerSetting(SETTING_HIDE_DRIVER_SERVICES, L\"0\");\n    PhpAddIntegerSetting(SETTING_HIDE_FREE_REGIONS, L\"1\");\n    PhpAddIntegerSetting(SETTING_HIDE_ON_CLOSE, L\"0\");\n    PhpAddIntegerSetting(SETTING_HIDE_ON_MINIMIZE, L\"0\");\n    PhpAddIntegerSetting(SETTING_HIDE_OTHER_USER_PROCESSES, L\"0\");\n    PhpAddIntegerSetting(SETTING_HIDE_SIGNED_PROCESSES, L\"0\");\n    PhpAddIntegerSetting(SETTING_HIDE_MICROSOFT_PROCESSES, L\"0\");\n    PhpAddIntegerSetting(SETTING_HIDE_WAITING_CONNECTIONS, L\"0\");\n    PhpAddIntegerSetting(SETTING_HIGHLIGHTING_DURATION, L\"3e8\"); // 1000ms\n    PhpAddIntegerSetting(SETTING_ICON_BALLOON_SHOW_ICON, L\"0\");\n    PhpAddIntegerSetting(SETTING_ICON_BALLOON_MUTE_SOUND, L\"0\");\n    PhpAddIntegerSetting(SETTING_TOAST_NOTIFY_ENABLED, L\"0\");\n    PhpAddStringSetting(SETTING_ICON_TRAY_GUIDS, L\"\");\n    PhpAddIntegerSetting(SETTING_ICON_TRAY_PERSIST_GUID_ENABLED, L\"0\");\n    PhpAddIntegerSetting(SETTING_ICON_TRAY_LAZY_START_DELAY, L\"1\");\n    PhpAddIntegerSetting(SETTING_ICON_IGNORE_BALLOON_CLICK, L\"0\");\n    PhpAddStringSetting(SETTING_ICON_SETTINGS, L\"\");\n    PhpAddIntegerSetting(SETTING_ICON_NOTIFY_MASK, L\"c\"); // PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE\n    PhpAddIntegerSetting(SETTING_ICON_PROCESSES, L\"f\"); // 15\n    PhpAddIntegerSetting(SETTING_ICON_SINGLE_CLICK, L\"0\");\n    PhpAddIntegerSetting(SETTING_ICON_TOGGLES_VISIBILITY, L\"1\");\n    PhpAddIntegerSetting(SETTING_ICON_TRANSPARENCY_ENABLED, L\"0\");\n    PhpAddIntegerPairSetting(SETTING_INFORMATION_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_INFORMATION_WINDOW_SIZE, L\"@96|140,190\");\n    PhpAddIntegerSetting(SETTING_IMAGE_COHERENCY_SCAN_LEVEL, L\"1\");\n    PhpAddStringSetting(SETTING_JOB_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddIntegerSetting(SETTING_LOG_ENTRIES, L\"200\"); // 512\n    PhpAddStringSetting(SETTING_LOG_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddIntegerPairSetting(SETTING_LOG_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_LOG_WINDOW_SIZE, L\"@96|450,500\");\n    PhpAddIntegerSetting(SETTING_MAIN_WINDOW_ALWAYS_ON_TOP, L\"0\");\n    PhpAddStringSetting(SETTING_MAIN_WINDOW_CLASS_NAME, L\"MainWindowClassName\");\n    PhpAddIntegerSetting(SETTING_MAIN_WINDOW_OPACITY, L\"0\"); // means 100%\n    PhpAddIntegerPairSetting(SETTING_MAIN_WINDOW_POSITION, L\"100,100\");\n    PhpAddScalableIntegerPairSetting(SETTING_MAIN_WINDOW_SIZE, L\"@96|800,600\");\n    PhpAddIntegerSetting(SETTING_MAIN_WINDOW_STATE, L\"1\");\n    PhpAddIntegerSetting(SETTING_MAIN_WINDOW_TAB_RESTORE_ENABLED, L\"0\");\n    PhpAddIntegerSetting(SETTING_MAIN_WINDOW_TAB_RESTORE_INDEX, L\"0\");\n    PhpAddIntegerSetting(SETTING_MAX_SIZE_UNIT, L\"6\");\n    PhpAddIntegerSetting(SETTING_MAX_PRECISION_UNIT, L\"2\");\n    PhpAddIntegerSetting(SETTING_MEM_EDIT_BYTES_PER_ROW, L\"10\"); // 16\n    PhpAddStringSetting(SETTING_MEM_EDIT_GOTO_CHOICES, L\"\");\n    PhpAddIntegerPairSetting(SETTING_MEM_EDIT_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_MEM_EDIT_SIZE, L\"@96|600,500\");\n    PhpAddStringSetting(SETTING_MEM_FILTER_CHOICES, L\"\");\n    PhpAddStringSetting(SETTING_MEM_RESULTS_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddIntegerPairSetting(SETTING_MEM_RESULTS_POSITION, L\"300,300\");\n    PhpAddScalableIntegerPairSetting(SETTING_MEM_RESULTS_SIZE, L\"@96|500,520\");\n    PhpAddIntegerSetting(SETTING_MEMORY_LIST_FLAGS, L\"3\");\n    PhpAddStringSetting(SETTING_MEMORY_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_MEMORY_TREE_LIST_SORT, L\"0,0\"); // 0, NoSortOrder\n    PhpAddIntegerPairSetting(SETTING_MEMORY_LISTS_WINDOW_POSITION, L\"400,400\");\n    PhpAddStringSetting(SETTING_MEMORY_READ_WRITE_ADDRESS_CHOICES, L\"\");\n    PhpAddIntegerPairSetting(SETTING_MEMORY_MODIFIED_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_MEMORY_MODIFIED_WINDOW_SIZE, L\"@96|450,500\");\n    PhpAddStringSetting(SETTING_MEMORY_MODIFIED_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_MEMORY_MODIFIED_LIST_VIEW_SORT, L\"0,0\"); // 0, NoSortOrder\n    PhpAddStringSetting(SETTING_MEM_STRINGS_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_MEM_STRINGS_TREE_LIST_SORT, L\"0,1\"); // 0, AscendingSortOrder\n    PhpAddIntegerSetting(SETTING_MEM_STRINGS_TREE_LIST_FLAGS, L\"b\"); // ANSI, Unicode, Private\n    PhpAddIntegerSetting(SETTING_MEM_STRINGS_MINIMUM_LENGTH, L\"a\"); // 10\n    PhpAddIntegerPairSetting(SETTING_MEM_STRINGS_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_MEM_STRINGS_WINDOW_SIZE, L\"@96|550,420\");\n    PhpAddStringSetting(SETTING_MINI_INFO_CONTAINER_CLASS_NAME, L\"MiniInfoContainerClassName\");\n    PhpAddStringSetting(SETTING_MINI_INFO_WINDOW_CLASS_NAME, L\"MiniInfoWindowClassName\");\n    PhpAddIntegerSetting(SETTING_MINI_INFO_WINDOW_ENABLED, L\"1\");\n    PhpAddIntegerSetting(SETTING_MINI_INFO_WINDOW_OPACITY, L\"0\"); // means 100%\n    PhpAddIntegerSetting(SETTING_MINI_INFO_WINDOW_PINNED, L\"0\");\n    PhpAddIntegerPairSetting(SETTING_MINI_INFO_WINDOW_POSITION, L\"200,200\");\n    PhpAddIntegerSetting(SETTING_MINI_INFO_WINDOW_REFRESH_AUTOMATICALLY, L\"3\");\n    PhpAddScalableIntegerPairSetting(SETTING_MINI_INFO_WINDOW_SIZE, L\"@96|10,200\");\n    PhpAddIntegerSetting(SETTING_MODULE_TREE_LIST_FLAGS, L\"1\");\n    PhpAddStringSetting(SETTING_MODULE_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_MODULE_TREE_LIST_SORT, L\"0,0\"); // 0, NoSortOrder\n    PhpAddStringSetting(SETTING_NETWORK_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_NETWORK_TREE_LIST_SORT, L\"0,1\"); // 0, AscendingSortOrder\n    PhpAddIntegerSetting(SETTING_NON_POLL_FLUSH_INTERVAL, L\"A\"); // % 10\n    PhpAddIntegerSetting(SETTING_NO_PURGE_PROCESS_RECORDS, L\"0\");\n    PhpAddStringSetting(SETTING_OPTIONS_CUSTOM_COLOR_LIST, L\"\");\n    PhpAddStringSetting(SETTING_OPTIONS_WINDOW_ADVANCED_COLUMNS, L\"\");\n    PhpAddIntegerSetting(SETTING_OPTIONS_WINDOW_ADVANCED_FLAGS, L\"0\");\n    PhpAddIntegerPairSetting(SETTING_OPTIONS_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_OPTIONS_WINDOW_SIZE, L\"@96|900,590\");\n    PhpAddIntegerPairSetting(SETTING_PAGE_FILE_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_PAGE_FILE_WINDOW_SIZE, L\"@96|500,300\");\n    PhpAddStringSetting(SETTING_PAGE_FILE_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_PLUGIN_MANAGER_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_PROCESS_SERVICE_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_PROCESS_TREE_COLUMN_SET_CONFIG, L\"\");\n    PhpAddStringSetting(SETTING_PROCESS_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_PROCESS_TREE_LIST_SORT, L\"0,0\"); // 0, NoSortOrder\n    PhpAddIntegerSetting(SETTING_PROCESS_TREE_LIST_NAME_DEFAULT, L\"1\");\n    PhpAddStringSetting(SETTING_PROC_PROP_PAGE, L\"General\");\n    PhpAddIntegerPairSetting(SETTING_PROC_PROP_POSITION, L\"200,200\");\n    PhpAddScalableIntegerPairSetting(SETTING_PROC_PROP_SIZE, L\"@96|460,580\");\n    PhpAddStringSetting(SETTING_PROC_STAT_PROP_PAGE_GROUP_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_PROC_STAT_PROP_PAGE_GROUP_LIST_VIEW_SORT, L\"0,0\");\n    PhpAddStringSetting(SETTING_PROC_STAT_PROP_PAGE_GROUP_STATES, L\"\");\n    PhpAddStringSetting(SETTING_PROGRAM_INSPECT_EXECUTABLES, L\"peview.exe \\\"%s\\\"\");\n    PhpAddIntegerSetting(SETTING_PROPAGATE_CPU_USAGE, L\"0\");\n    PhpAddIntegerSetting(SETTING_RELEASE_CHANNEL, L\"0\"); // PhReleaseChannel\n    PhpAddIntegerSetting(SETTING_RUN_AS_ENABLE_AUTO_COMPLETE, L\"0\");\n    PhpAddStringSetting(SETTING_RUN_AS_PROGRAM, L\"\");\n    PhpAddStringSetting(SETTING_RUN_AS_USER_NAME, L\"\");\n    PhpAddIntegerPairSetting(SETTING_RUN_AS_WINDOW_POSITION, L\"0,0\");\n    PhpAddIntegerPairSetting(SETTING_RUN_AS_PACKAGE_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_RUN_AS_PACKAGE_WINDOW_SIZE, L\"@96|500,300\");\n    PhpAddIntegerSetting(SETTING_RUN_FILE_DLG_STATE, L\"0\");\n    PhpAddIntegerSetting(SETTING_SAMPLE_COUNT, L\"200\"); // 512\n    PhpAddIntegerSetting(SETTING_SAMPLE_COUNT_AUTOMATIC, L\"1\");\n    PhpAddIntegerSetting(SETTING_SCROLL_TO_NEW_PROCESSES, L\"0\");\n    PhpAddIntegerSetting(SETTING_SCROLL_TO_REMOVED_PROCESSES, L\"0\");\n    PhpAddStringSetting(SETTING_SEARCH_ENGINE, L\"https://duckduckgo.com/?q=\\\"%s\\\"\");\n    PhpAddStringSetting(SETTING_SEGMENT_HEAP_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_SEGMENT_HEAP_LIST_VIEW_SORT, L\"0,1\");\n    PhpAddIntegerPairSetting(SETTING_SEGMENT_HEAP_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_SEGMENT_HEAP_WINDOW_SIZE, L\"@96|450,500\");\n    PhpAddStringSetting(SETTING_SEGMENT_LOCKS_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_SEGMENT_LOCKS_LIST_VIEW_SORT, L\"0,1\");\n    PhpAddIntegerPairSetting(SETTING_SEGMENT_LOCKS_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_SEGMENT_LOCKS_WINDOW_SIZE, L\"@96|450,500\");\n    PhpAddIntegerPairSetting(SETTING_SERVICE_WINDOW_POSITION, L\"0,0\");\n    PhpAddStringSetting(SETTING_SERVICE_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_SERVICE_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_SERVICE_TREE_LIST_SORT, L\"0,1\"); // 0, AscendingSortOrder\n    PhpAddIntegerPairSetting(SETTING_SESSION_SHADOW_HOTKEY, L\"106,2\"); // VK_MULTIPLY,KBDCTRL\n    PhpAddIntegerSetting(SETTING_SHOW_PLUGIN_LOAD_ERRORS, L\"1\");\n    PhpAddIntegerSetting(SETTING_SHOW_COMMIT_IN_SUMMARY, L\"1\");\n    PhpAddIntegerSetting(SETTING_SHOW_CPU_BELOW_001, L\"0\");\n    PhpAddIntegerSetting(SETTING_SHOW_HEX_ID, L\"0\");\n    PhpAddIntegerSetting(SETTING_SORT_CHILD_PROCESSES, L\"0\");\n    PhpAddIntegerSetting(SETTING_SORT_ROOT_PROCESSES, L\"0\");\n    PhpAddIntegerSetting(SETTING_START_HIDDEN, L\"0\");\n    PhpAddIntegerSetting(SETTING_SYSINFO_SHOW_CPU_SPEED_MHZ, L\"0\");\n    PhpAddIntegerSetting(SETTING_SYSINFO_SHOW_CPU_SPEED_PER_CPU, L\"0\");\n    PhpAddIntegerSetting(SETTING_SYSINFO_WINDOW_ALWAYS_ON_TOP, L\"0\");\n    PhpAddIntegerSetting(SETTING_SYSINFO_WINDOW_ONE_GRAPH_PER_CPU, L\"0\");\n    PhpAddIntegerPairSetting(SETTING_SYSINFO_WINDOW_POSITION, L\"200,200\");\n    PhpAddStringSetting(SETTING_SYSINFO_WINDOW_SECTION, L\"\");\n    PhpAddScalableIntegerPairSetting(SETTING_SYSINFO_WINDOW_SIZE, L\"@96|900,590\");\n    PhpAddIntegerSetting(SETTING_SYSINFO_WINDOW_STATE, L\"1\");\n    PhpAddIntegerSetting(SETTING_TASKMGR_WINDOW_STATE, L\"0\");\n    PhpAddIntegerSetting(SETTING_THEME_WINDOW_FOREGROUND_COLOR, L\"1c1c1c\"); // RGB(28, 28, 28)\n    PhpAddIntegerSetting(SETTING_THEME_WINDOW_BACKGROUND_COLOR, L\"2b2b2b\"); // RGB(43, 43, 43)\n    PhpAddIntegerSetting(SETTING_THEME_WINDOW_BACKGROUND2_COLOR, L\"414141\"); // RGB(65, 65, 65)\n    PhpAddIntegerSetting(SETTING_THEME_WINDOW_HIGHLIGHT_COLOR, L\"808080\"); // RGB(128, 128, 128)\n    PhpAddIntegerSetting(SETTING_THEME_WINDOW_HIGHLIGHT2_COLOR, L\"8f8f8f\"); // RGB(143, 143, 143)\n    PhpAddIntegerSetting(SETTING_THEME_WINDOW_TEXT_COLOR, L\"ffffff\"); // RGB(255, 255, 255)\n    PhpAddIntegerSetting(SETTING_THIN_ROWS, L\"0\");\n    PhpAddStringSetting(SETTING_THREAD_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_THREAD_TREE_LIST_SORT, L\"1,2\"); // 1, DescendingSortOrder\n    PhpAddIntegerSetting(SETTING_THREAD_TREE_LIST_FLAGS, L\"60\");\n    PhpAddStringSetting(SETTING_THREAD_STACK_TREE_LIST_COLUMNS, L\"\");\n    PhpAddScalableIntegerPairSetting(SETTING_THREAD_STACK_WINDOW_SIZE, L\"@96|420,400\");\n    PhpAddIntegerPairSetting(SETTING_TOKEN_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_TOKEN_WINDOW_SIZE, L\"@96|0,0\");\n    PhpAddStringSetting(SETTING_TOKEN_GROUPS_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_TOKEN_GROUPS_LIST_VIEW_STATES, L\"\");\n    PhpAddStringSetting(SETTING_TOKEN_GROUPS_LIST_VIEW_SORT, L\"1,2\");\n    PhpAddStringSetting(SETTING_TOKEN_PRIVILEGES_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddIntegerSetting(SETTING_TREE_LIST_BORDER_ENABLE, L\"0\");\n    PhpAddIntegerSetting(SETTING_TREE_LIST_CUSTOM_COLORS_ENABLE, L\"0\");\n    PhpAddIntegerSetting(SETTING_TREE_LIST_CUSTOM_COLOR_TEXT, L\"0\");\n    PhpAddIntegerSetting(SETTING_TREE_LIST_CUSTOM_COLOR_FOCUS, L\"0\");\n    PhpAddIntegerSetting(SETTING_TREE_LIST_CUSTOM_COLOR_SELECTION, L\"0\");\n    PhpAddIntegerSetting(SETTING_TREE_LIST_CUSTOM_ROW_SIZE, L\"0\");\n    PhpAddIntegerSetting(SETTING_TREE_LIST_ENABLE_HEADER_TOTALS, L\"1\");\n    PhpAddIntegerSetting(SETTING_TREE_LIST_ENABLE_DRAG_REORDER, L\"0\");\n    PhpAddIntegerSetting(SETTING_UPDATE_INTERVAL, L\"3e8\"); // 1000ms\n    PhpAddIntegerSetting(SETTING_ENABLE_HIGH_RESOLUTION_PROVIDER_TIMER, L\"1\");\n    PhpAddStringSetting(SETTING_USER_LIST_TREE_LIST_COLUMNS, L\"\");\n    PhpAddIntegerPairSetting(SETTING_USER_LIST_WINDOW_POSITION, L\"0,0\");\n    PhpAddScalableIntegerPairSetting(SETTING_USER_LIST_WINDOW_SIZE, L\"@96|550,420\");\n    PhpAddIntegerSetting(SETTING_WMI_PROVIDER_ENABLE_HIDDEN_MENU, L\"0\");\n    PhpAddIntegerSetting(SETTING_WMI_PROVIDER_ENABLE_TOOLTIP_SUPPORT, L\"0\");\n    PhpAddStringSetting(SETTING_WMI_PROVIDER_TREE_LIST_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_WMI_PROVIDER_TREE_LIST_SORT, L\"0,0\"); // 0, NoSortOrder\n    PhpAddIntegerSetting(SETTING_WMI_PROVIDER_TREE_LIST_FLAGS, L\"0\");\n    PhpAddStringSetting(SETTING_VDM_HOST_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddStringSetting(SETTING_ZOMBIE_PROCESSES_LIST_VIEW_COLUMNS, L\"\");\n    PhpAddIntegerPairSetting(SETTING_ZOMBIE_PROCESSES_WINDOW_POSITION, L\"400,400\");\n    PhpAddScalableIntegerPairSetting(SETTING_ZOMBIE_PROCESSES_WINDOW_SIZE, L\"@96|520,400\");\n\n    // Colors are specified with R in the lowest byte, then G, then B. So: bbggrr.\n    PhpAddIntegerSetting(SETTING_COLOR_NEW, L\"00ff7f\"); // Chartreuse\n    PhpAddIntegerSetting(SETTING_COLOR_REMOVED, L\"283cff\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_OWN_PROCESSES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_OWN_PROCESSES, L\"aaffff\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_SYSTEM_PROCESSES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_SYSTEM_PROCESSES, L\"ffccaa\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_SERVICE_PROCESSES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_SERVICE_PROCESSES, L\"ffffcc\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_BACKGROUND_PROCESSES, L\"0\");\n    PhpAddIntegerSetting(SETTING_COLOR_BACKGROUND_PROCESSES, L\"bcbc78\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_JOB_PROCESSES, L\"0\");\n    PhpAddIntegerSetting(SETTING_COLOR_JOB_PROCESSES, L\"3f85cd\"); // Peru\n    PhpAddIntegerSetting(SETTING_USE_COLOR_WOW64_PROCESSES, L\"0\");\n    PhpAddIntegerSetting(SETTING_COLOR_WOW64_PROCESSES, L\"8f8fbc\"); // Rosy Brown\n    PhpAddIntegerSetting(SETTING_USE_COLOR_DEBUGGED_PROCESSES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_DEBUGGED_PROCESSES, L\"ffbbcc\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_ELEVATED_PROCESSES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_ELEVATED_PROCESSES, L\"00aaff\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_HANDLE_FILTERED, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_HANDLE_FILTERED, L\"000000\"); // Black\n    PhpAddIntegerSetting(SETTING_USE_COLOR_IMMERSIVE_PROCESSES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_IMMERSIVE_PROCESSES, L\"cbc0ff\"); // Pink\n    PhpAddIntegerSetting(SETTING_USE_COLOR_UI_ACCESS_PROCESSES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_UI_ACCESS_PROCESSES, L\"00aaff\"); // Orange\n    PhpAddIntegerSetting(SETTING_USE_COLOR_PICO_PROCESSES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_PICO_PROCESSES, L\"ff8000\"); // Blue\n    PhpAddIntegerSetting(SETTING_USE_COLOR_SUSPENDED, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_SUSPENDED, L\"777777\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_DOT_NET, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_DOT_NET, L\"00ffde\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_PACKED, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_PACKED, L\"9314ff\"); // Deep Pink\n    PhpAddIntegerSetting(SETTING_USE_COLOR_LOW_IMAGE_COHERENCY, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_LOW_IMAGE_COHERENCY, L\"ff14b9\"); // Deep Purple\n    PhpAddIntegerSetting(SETTING_USE_COLOR_PARTIALLY_SUSPENDED, L\"0\");\n    PhpAddIntegerSetting(SETTING_COLOR_PARTIALLY_SUSPENDED, L\"c0c0c0\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_GUI_THREADS, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_GUI_THREADS, L\"77ffff\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_RELOCATED_MODULES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_RELOCATED_MODULES, L\"80c0ff\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_PROTECTED_HANDLES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_PROTECTED_HANDLES, L\"777777\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_PROTECTED_INHERIT_HANDLES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_PROTECTED_INHERIT_HANDLES, L\"c0c0c0\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_PROTECTED_PROCESS, L\"0\");\n    PhpAddIntegerSetting(SETTING_COLOR_PROTECTED_PROCESS, L\"ff8080\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_INHERIT_HANDLES, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_INHERIT_HANDLES, L\"ffff77\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_EFFICIENCY_MODE, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_EFFICIENCY_MODE, L\"80ff00\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_SERVICE_DISABLED, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_SERVICE_DISABLED, L\"6d6d6d\"); // Dark grey\n    PhpAddIntegerSetting(SETTING_USE_COLOR_SERVICE_STOP, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_SERVICE_STOP, L\"6d6d6d\"); // Dark grey\n    PhpAddIntegerSetting(SETTING_USE_COLOR_UNKNOWN, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_UNKNOWN, L\"8080ff\"); // Light Red\n\n    PhpAddIntegerSetting(SETTING_USE_COLOR_SYSTEM_THREAD_STACK, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_SYSTEM_THREAD_STACK, L\"ffccaa\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_USER_THREAD_STACK, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_USER_THREAD_STACK, L\"aaffff\");\n    PhpAddIntegerSetting(SETTING_USE_COLOR_INLINE_THREAD_STACK, L\"1\");\n    PhpAddIntegerSetting(SETTING_COLOR_INLINE_THREAD_STACK, L\"00ffde\");\n\n    PhpAddIntegerSetting(SETTING_GRAPH_SHOW_TEXT, L\"1\");\n    PhpAddIntegerSetting(SETTING_GRAPH_COLOR_MODE, L\"0\");\n    PhpAddIntegerSetting(SETTING_COLOR_CPU_KERNEL, L\"00ff00\");\n    PhpAddIntegerSetting(SETTING_COLOR_CPU_USER, L\"0000ff\");\n    PhpAddIntegerSetting(SETTING_COLOR_IO_READ_OTHER, L\"00ffff\");\n    PhpAddIntegerSetting(SETTING_COLOR_IO_WRITE, L\"ff0077\");\n    PhpAddIntegerSetting(SETTING_COLOR_PRIVATE, L\"0077ff\");\n    PhpAddIntegerSetting(SETTING_COLOR_PHYSICAL, L\"ff8000\"); // Blue\n\n    PhpAddIntegerSetting(SETTING_COLOR_POWER_USAGE, L\"00ff00\");\n    PhpAddIntegerSetting(SETTING_COLOR_TEMPERATURE, L\"0000ff\");\n    PhpAddIntegerSetting(SETTING_COLOR_FAN_RPM, L\"ff0077\");\n\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE_WARNINGS, L\"1\");\n    PhpAddStringSetting(SETTING_KSI_SERVICE_NAME, L\"\");\n    PhpAddStringSetting(SETTING_KSI_OBJECT_NAME, L\"\");\n    PhpAddStringSetting(SETTING_KSI_PORT_NAME, L\"\");\n    PhpAddStringSetting(SETTING_KSI_ALTITUDE, L\"\");\n    PhpAddStringSetting(SETTING_KSI_SYSTEM_PROCESS_NAME, L\"\");\n    PhpAddIntegerSetting(SETTING_KSI_DISABLE_IMAGE_LOAD_PROTECTION, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE_SPLASH_SCREEN, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE_LOAD_NATIVE, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE_LOAD_FILTER, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_UNLOAD_ON_EXIT, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_RANDOMIZED_POOL_TAG, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE_UNLOAD_PROTECTION, L\"1\");\n    PhpAddIntegerSetting(SETTING_KSI_DYN_DATA_NO_EMBEDDED, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_DISABLE_SYSTEM_PROCESS, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_DISABLE_THREAD_NAMES, L\"0\");\n    PhpAddIntegerSetting(SETTING_KSI_CLIENT_PROCESS_PROTECTION_LEVEL, L\"0\");\n    PhpAddStringSetting(SETTING_KSI_PREVIOUS_TEMPORARY_DRIVER_FILE, L\"\");\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE_FS_FEATURE_OFFLOAD_READ, L\"1\");  // SUPPORTED_FS_FEATURES_OFFLOAD_READ\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE_FS_FEATURE_OFFLOAD_WRITE, L\"1\"); // SUPPORTED_FS_FEATURES_OFFLOAD_WRITE\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE_FS_FEATURE_QUERY_OPEN, L\"1\");    // SUPPORTED_FS_FEATURES_QUERY_OPEN\n    PhpAddIntegerSetting(SETTING_KSI_ENABLE_FS_FEATURE_BYPASS_IO, L\"1\");     // SUPPORTED_FS_FEATURES_BYPASS_IO\n    PhpAddIntegerSetting(SETTING_KSI_RING_BUFFER_LENGTH, L\"10000000\"); // bytes\n\n    PhpAddIntegerSetting(SETTING_ENABLE_PROCESS_MONITOR, L\"0\");\n    PhpAddIntegerSetting(SETTING_PROCESS_MONITOR_LOOKBACK, L\"1e\");\n    PhpAddIntegerSetting(SETTING_PROCESS_MONITOR_CACHE_LIMIT, L\"20000\");\n}\n\nVOID PhUpdateCachedSettings(\n    VOID\n    )\n{\n    PH_GET_INTEGER_CACHED_SETTING(ForceNoParent);\n    PH_GET_INTEGER_CACHED_SETTING(HighlightingDuration);\n    PH_GET_INTEGER_CACHED_SETTING(PropagateCpuUsage);\n    PH_GET_INTEGER_CACHED_SETTING(ScrollToNewProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ScrollToRemovedProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(SortChildProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(SortRootProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ShowCpuBelow001);\n    PH_GET_INTEGER_CACHED_SETTING(UpdateInterval);\n\n    PH_GET_INTEGER_CACHED_SETTING(ColorNew);\n    PH_GET_INTEGER_CACHED_SETTING(ColorRemoved);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorOwnProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorOwnProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorSystemProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorSystemProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorServiceProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorServiceProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorBackgroundProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorBackgroundProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorJobProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorJobProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorWow64Processes);\n    PH_GET_INTEGER_CACHED_SETTING(ColorWow64Processes);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorDebuggedProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorDebuggedProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorHandleFiltered);\n    PH_GET_INTEGER_CACHED_SETTING(ColorHandleFiltered);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorElevatedProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorElevatedProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorUIAccessProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorUIAccessProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorPicoProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorPicoProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorImmersiveProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(ColorImmersiveProcesses);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorSuspended);\n    PH_GET_INTEGER_CACHED_SETTING(ColorSuspended);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorDotNet);\n    PH_GET_INTEGER_CACHED_SETTING(ColorDotNet);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorPacked);\n    PH_GET_INTEGER_CACHED_SETTING(ColorPacked);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorLowImageCoherency);\n    PH_GET_INTEGER_CACHED_SETTING(ColorLowImageCoherency);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorPartiallySuspended);\n    PH_GET_INTEGER_CACHED_SETTING(ColorPartiallySuspended);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorGuiThreads);\n    PH_GET_INTEGER_CACHED_SETTING(ColorGuiThreads);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorRelocatedModules);\n    PH_GET_INTEGER_CACHED_SETTING(ColorRelocatedModules);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorProtectedHandles);\n    PH_GET_INTEGER_CACHED_SETTING(ColorProtectedHandles);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorProtectedInheritHandles);\n    PH_GET_INTEGER_CACHED_SETTING(ColorProtectedInheritHandles);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorInheritHandles);\n    PH_GET_INTEGER_CACHED_SETTING(ColorInheritHandles);\n    PH_GET_INTEGER_CACHED_SETTING(ColorProtectedProcess);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorProtectedProcess);\n    PH_GET_INTEGER_CACHED_SETTING(ColorEfficiencyMode);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorEfficiencyMode);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorServiceDisabled);\n    PH_GET_INTEGER_CACHED_SETTING(ColorServiceDisabled);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorServiceStop);\n    PH_GET_INTEGER_CACHED_SETTING(ColorServiceStop);\n    PH_GET_INTEGER_CACHED_SETTING(UseColorUnknown);\n    PH_GET_INTEGER_CACHED_SETTING(ColorUnknown);\n\n    PH_GET_INTEGER_CACHED_SETTING(GraphShowText);\n    PH_GET_INTEGER_CACHED_SETTING(GraphColorMode);\n    PH_GET_INTEGER_CACHED_SETTING(ColorCpuKernel);\n    PH_GET_INTEGER_CACHED_SETTING(ColorCpuUser);\n    PH_GET_INTEGER_CACHED_SETTING(ColorIoReadOther);\n    PH_GET_INTEGER_CACHED_SETTING(ColorIoWrite);\n    PH_GET_INTEGER_CACHED_SETTING(ColorPrivate);\n    PH_GET_INTEGER_CACHED_SETTING(ColorPhysical);\n\n    PH_GET_INTEGER_CACHED_SETTING(ColorPowerUsage);\n    PH_GET_INTEGER_CACHED_SETTING(ColorTemperature);\n    PH_GET_INTEGER_CACHED_SETTING(ColorFanRpm);\n\n    PH_GET_INTEGER_CACHED_SETTING(ImageCoherencyScanLevel);\n\n    PH_GET_INTEGER_CACHED_SETTING(EnableAvxSupport);\n    PH_GET_INTEGER_CACHED_SETTING(EnableGraphMaxScale);\n    PH_GET_INTEGER_CACHED_SETTING(EnableGraphMaxText);\n    PH_GET_INTEGER_CACHED_SETTING(EnableNetworkResolveDoH);\n    PH_GET_INTEGER_CACHED_SETTING(EnableVersionSupport);\n    PH_GET_INTEGER_CACHED_SETTING(EnableHandleSnapshot);\n\n    PhEnableProcessMonitor = !!PhGetIntegerSetting(SETTING_ENABLE_PROCESS_MONITOR);\n    PhProcessMonitorLookback = PhGetIntegerSetting(SETTING_PROCESS_MONITOR_LOOKBACK);\n    PhProcessMonitorCacheLimit = PhGetIntegerSetting(SETTING_PROCESS_MONITOR_CACHE_LIMIT);\n}\n"
  },
  {
    "path": "SystemInformer/srvcr.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2013\n *     dmex    2019-2023\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n#include <svcsup.h>\n\n#include <actions.h>\n#include <phsvccl.h>\n\nINT_PTR CALLBACK PhpCreateServiceDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhShowCreateServiceDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_CREATESERVICE),\n        PhCsForceNoParent ? NULL : ParentWindowHandle,\n        PhpCreateServiceDlgProc,\n        NULL\n        );\n}\n\nINT_PTR CALLBACK PhpCreateServiceDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhAddComboBoxStringRefs(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, RTL_NUMBER_OF(PhServiceTypeStrings));\n            PhAddComboBoxStringRefs(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, RTL_NUMBER_OF(PhServiceStartTypeStrings));\n            PhAddComboBoxStringRefs(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, RTL_NUMBER_OF(PhServiceErrorControlStrings));\n\n            PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L\"Own Process\", FALSE);\n            PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), L\"Demand Start\", FALSE);\n            PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), L\"Ignore\", FALSE);\n\n            if (!PhGetOwnTokenAttributes().Elevated)\n            {\n                Button_SetElevationRequiredState(GetDlgItem(hwndDlg, IDOK), TRUE);\n            }\n\n            PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME));\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                {\n                    EndDialog(hwndDlg, IDCANCEL);\n                }\n                break;\n            case IDOK:\n                {\n                    NTSTATUS status;\n                    SC_HANDLE serviceHandle;\n                    PPH_STRING serviceName;\n                    PPH_STRING serviceDisplayName;\n                    PPH_STRING serviceTypeString;\n                    PPH_STRING serviceStartTypeString;\n                    PPH_STRING serviceErrorControlString;\n                    ULONG serviceType;\n                    ULONG serviceStartType;\n                    ULONG serviceErrorControl;\n                    PPH_STRING serviceBinaryPath;\n                    PPH_STRING serviceBinaryEscaped;\n\n                    serviceName = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_NAME)));\n                    serviceDisplayName = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_DISPLAYNAME)));\n                    serviceTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_TYPE)));\n                    serviceStartTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STARTTYPE)));\n                    serviceErrorControlString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_ERRORCONTROL)));\n                    serviceBinaryPath = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_BINARYPATH)));\n\n                    serviceType = PhGetServiceTypeInteger(&serviceTypeString->sr);\n                    serviceStartType = PhGetServiceStartTypeInteger(&serviceStartTypeString->sr);\n                    serviceErrorControl = PhGetServiceErrorControlInteger(&serviceErrorControlString->sr);\n\n                    if (PhIsNullOrEmptyString(serviceBinaryPath))\n                    {\n                        PhShowError2(hwndDlg, L\"Unable to create the service.\", L\"%s\", L\"The binary path is empty.\");\n                        break;\n                    }\n\n                    if (!FlagOn(serviceType, SERVICE_DRIVER))\n                    {\n                        serviceBinaryEscaped = PH_AUTO(PhCommandLineQuoteSpaces(&serviceBinaryPath->sr));\n\n                        if (!PhIsNullOrEmptyString(serviceBinaryEscaped))\n                        {\n                            serviceBinaryPath = serviceBinaryEscaped;\n                        }\n                    }\n\n                    if (PhGetOwnTokenAttributes().Elevated)\n                    {\n                        status = PhCreateService(\n                            &serviceHandle,\n                            PhGetString(serviceName),\n                            PhGetString(serviceDisplayName),\n                            SERVICE_QUERY_CONFIG,\n                            serviceType,\n                            serviceStartType,\n                            serviceErrorControl,\n                            PhGetString(serviceBinaryPath),\n                            NULL,\n                            L\"\"\n                            );\n\n                        if (NT_SUCCESS(status))\n                        {\n                            EndDialog(hwndDlg, IDOK);\n                            PhCloseServiceHandle(serviceHandle);\n                        }\n                    }\n                    else\n                    {\n                        if (PhUiConnectToPhSvc(hwndDlg, FALSE))\n                        {\n                            status = PhSvcCallCreateService(\n                                PhGetString(serviceName),\n                                PhGetString(serviceDisplayName),\n                                serviceType,\n                                serviceStartType,\n                                serviceErrorControl,\n                                PhGetString(serviceBinaryPath),\n                                NULL,\n                                NULL,\n                                NULL,\n                                NULL,\n                                L\"\"\n                                );\n                            PhUiDisconnectFromPhSvc();\n\n                            if (NT_SUCCESS(status))\n                            {\n                                EndDialog(hwndDlg, IDOK);\n                            }\n                        }\n                        else\n                        {\n                            // User cancelled elevation.\n                            status = STATUS_SUCCESS;\n                        }\n                    }\n\n                    if (!NT_SUCCESS(status))\n                        PhShowStatus(hwndDlg, L\"Unable to create the service.\", status, 0);\n                }\n                break;\n            case IDC_BROWSE:\n                {\n                    static PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Executable files (*.exe;*.sys)\", L\"*.exe;*.sys\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog;\n                    PPH_STRING fileName;\n\n                    fileDialog = PhCreateOpenFileDialog();\n                    PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));\n\n                    fileName = PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_BINARYPATH));\n                    PhSetFileDialogFileName(fileDialog, fileName->Buffer);\n                    PhDereferenceObject(fileName);\n\n                    if (PhShowFileDialog(hwndDlg, fileDialog))\n                    {\n                        fileName = PhGetFileDialogFileName(fileDialog);\n                        PhSetDialogItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer);\n                        PhDereferenceObject(fileName);\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/srvctl.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <svcsup.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <emenu.h>\n\n#include <actions.h>\n#include <srvprv.h>\n#include <mainwnd.h>\n\n#include <proctree.h>\n#include <mainwndp.h>\n#include <hndlinfo.h>\n\ntypedef struct _PH_SERVICES_CONTEXT\n{\n    PPH_SERVICE_ITEM *Services;\n    ULONG NumberOfServices;\n    PH_CALLBACK_REGISTRATION ModifiedEventRegistration;\n\n    PWSTR ListViewSettingName;\n\n    PH_LAYOUT_MANAGER LayoutManager;\n    HWND WindowHandle;\n    HWND ListViewHandle;\n    HFONT TreeNewFont;\n} PH_SERVICES_CONTEXT, *PPH_SERVICES_CONTEXT;\n\n#define WM_PH_SERVICE_PAGE_MODIFIED (WM_APP + 106)\n\nINT_PTR CALLBACK PhpServicesPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n/**\n * Creates a service list property page.\n *\n * \\param ParentWindowHandle The parent of the service list.\n * \\param Services An array of service items. Each\n * service item must have a reference that is transferred\n * to this function. The array must be allocated using\n * PhAllocate() and must not be freed by the caller; it\n * will be freed automatically when no longer needed.\n * \\param NumberOfServices The number of service items\n * in \\a Services.\n */\nHWND PhCreateServiceListControl(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_SERVICE_ITEM *Services,\n    _In_ ULONG NumberOfServices\n    )\n{\n    HWND windowHandle;\n    PPH_SERVICES_CONTEXT servicesContext;\n\n    servicesContext = PhAllocateZero(sizeof(PH_SERVICES_CONTEXT));\n    servicesContext->Services = Services;\n    servicesContext->NumberOfServices = NumberOfServices;\n\n    windowHandle = PhCreateDialog(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_SRVLIST),\n        ParentWindowHandle,\n        PhpServicesPageProc,\n        servicesContext\n        );\n\n    if (!windowHandle)\n    {\n        PhFree(servicesContext);\n        return windowHandle;\n    }\n\n    return windowHandle;\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhServiceListModifiedHandler(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)Parameter;\n    PPH_SERVICES_CONTEXT servicesContext = (PPH_SERVICES_CONTEXT)Context;\n    PPH_SERVICE_MODIFIED_DATA copy;\n\n    copy = PhAllocateCopy(serviceModifiedData, sizeof(PH_SERVICE_MODIFIED_DATA));\n\n    PostMessage(servicesContext->WindowHandle, WM_PH_SERVICE_PAGE_MODIFIED, 0, (LPARAM)copy);\n}\n\nVOID PhpFixProcessServicesControls(\n    _In_ HWND hWnd,\n    _In_opt_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    HWND startButton;\n    HWND pauseButton;\n    HWND descriptionLabel;\n\n    startButton = GetDlgItem(hWnd, IDC_START);\n    pauseButton = GetDlgItem(hWnd, IDC_PAUSE);\n    descriptionLabel = GetDlgItem(hWnd, IDC_DESCRIPTION);\n\n    if (ServiceItem)\n    {\n        SC_HANDLE serviceHandle;\n        PPH_STRING description;\n\n        switch (ServiceItem->State)\n        {\n        case SERVICE_RUNNING:\n            {\n                PhSetWindowText(startButton, L\"S&top\");\n                PhSetWindowText(pauseButton, L\"&Pause\");\n                EnableWindow(startButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_STOP);\n                EnableWindow(pauseButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);\n            }\n            break;\n        case SERVICE_PAUSED:\n            {\n                PhSetWindowText(startButton, L\"S&top\");\n                PhSetWindowText(pauseButton, L\"C&ontinue\");\n                EnableWindow(startButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_STOP);\n                EnableWindow(pauseButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);\n            }\n            break;\n        case SERVICE_STOPPED:\n            {\n                PhSetWindowText(startButton, L\"&Start\");\n                PhSetWindowText(pauseButton, L\"&Pause\");\n                EnableWindow(startButton, TRUE);\n                EnableWindow(pauseButton, FALSE);\n            }\n            break;\n        case SERVICE_START_PENDING:\n        case SERVICE_CONTINUE_PENDING:\n        case SERVICE_PAUSE_PENDING:\n        case SERVICE_STOP_PENDING:\n            {\n                PhSetWindowText(startButton, L\"&Start\");\n                PhSetWindowText(pauseButton, L\"&Pause\");\n                EnableWindow(startButton, FALSE);\n                EnableWindow(pauseButton, FALSE);\n            }\n            break;\n        }\n\n        if (NT_SUCCESS(PhOpenService(&serviceHandle, SERVICE_QUERY_CONFIG, PhGetString(ServiceItem->Name))))\n        {\n            if (description = PhGetServiceDescription(serviceHandle))\n            {\n                PhSetWindowText(descriptionLabel, description->Buffer);\n                PhDereferenceObject(description);\n            }\n\n            PhCloseServiceHandle(serviceHandle);\n        }\n    }\n    else\n    {\n        PhSetWindowText(startButton, L\"&Start\");\n        PhSetWindowText(pauseButton, L\"&Pause\");\n        EnableWindow(startButton, FALSE);\n        EnableWindow(pauseButton, FALSE);\n        PhSetWindowText(descriptionLabel, L\"\");\n    }\n}\n\nINT_PTR CALLBACK PhpServicesPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_SERVICES_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_SERVICES_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            if (PhTreeWindowFont)\n            {\n                context->TreeNewFont = PhDuplicateFont(PhTreeWindowFont);\n                SetWindowFont(context->ListViewHandle, context->TreeNewFont, FALSE);\n            }\n\n            PhSetListViewStyle(context->ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 120, L\"Name\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 220, L\"Display name\");\n            PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 220, L\"File name\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            for (ULONG i = 0; i < context->NumberOfServices; i++)\n            {\n                SC_HANDLE serviceHandle;\n                PPH_SERVICE_ITEM serviceItem;\n                LONG lvItemIndex;\n\n                serviceItem = context->Services[i];\n                lvItemIndex = PhAddListViewItem(context->ListViewHandle, MAXINT, serviceItem->Name->Buffer, serviceItem);\n                PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 1, serviceItem->DisplayName->Buffer);\n\n                if (NT_SUCCESS(PhOpenService(&serviceHandle, SERVICE_QUERY_CONFIG, PhGetString(serviceItem->Name))))\n                {\n                    PPH_STRING fileName;\n\n                    if (NT_SUCCESS(PhGetServiceHandleFileName(serviceHandle, &serviceItem->Name->sr, &fileName)))\n                    {\n                        PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 2, PhGetStringOrEmpty(fileName));\n                        PhDereferenceObject(fileName);\n                    }\n\n                    PhCloseServiceHandle(serviceHandle);\n                }\n            }\n\n            ExtendedListView_SortItems(context->ListViewHandle);\n\n            if (context->NumberOfServices > 0)\n            {\n                SetFocus(context->ListViewHandle);\n                ListView_SetItemState(context->ListViewHandle, 0, LVNI_SELECTED, LVNI_SELECTED);\n                ListView_EnsureVisible(context->ListViewHandle, 0, FALSE);\n                PhpFixProcessServicesControls(hwndDlg, context->Services[0]);\n            }\n            else\n            {\n                PhpFixProcessServicesControls(hwndDlg, NULL);\n            }\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_START), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PAUSE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n\n            PhRegisterCallback(\n                PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent),\n                PhServiceListModifiedHandler,\n                context,\n                &context->ModifiedEventRegistration\n                );\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhUnregisterCallback(\n                PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent),\n                &context->ModifiedEventRegistration\n                );\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            if (context->TreeNewFont)\n                DeleteFont(context->TreeNewFont);\n\n            if (context->ListViewSettingName)\n                PhSaveListViewColumnsToSetting(context->ListViewSettingName, context->ListViewHandle);\n\n            for (ULONG i = 0; i < context->NumberOfServices; i++)\n                PhDereferenceObject(context->Services[i]);\n\n            PhFree(context->Services);\n\n            PhFree(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_START:\n                {\n                    PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle);\n\n                    if (serviceItem)\n                    {\n                        switch (serviceItem->State)\n                        {\n                        case SERVICE_RUNNING:\n                            PhUiStopService(hwndDlg, serviceItem);\n                            break;\n                        case SERVICE_PAUSED:\n                            PhUiStopService(hwndDlg, serviceItem);\n                            break;\n                        case SERVICE_STOPPED:\n                            PhUiStartService(hwndDlg, serviceItem);\n                            break;\n                        }\n                    }\n                }\n                break;\n            case IDC_PAUSE:\n                {\n                    PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle);\n\n                    if (serviceItem)\n                    {\n                        switch (serviceItem->State)\n                        {\n                        case SERVICE_RUNNING:\n                            PhUiPauseService(hwndDlg, serviceItem);\n                            break;\n                        case SERVICE_PAUSED:\n                            PhUiContinueService(hwndDlg, serviceItem);\n                            break;\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);\n\n            switch (header->code)\n            {\n            case NM_DBLCLK:\n                {\n                    if (header->hwndFrom == context->ListViewHandle)\n                    {\n                        PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle);\n\n                        if (serviceItem)\n                        {\n                            PhShowServiceProperties(hwndDlg, serviceItem);\n                        }\n                    }\n                }\n                break;\n            case LVN_ITEMCHANGED:\n                {\n                    if (header->hwndFrom == context->ListViewHandle)\n                    {\n                        //LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header;\n                        PPH_SERVICE_ITEM serviceItem = NULL;\n\n                        if (ListView_GetSelectedCount(context->ListViewHandle) == 1)\n                            serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle);\n\n                        PhpFixProcessServicesControls(hwndDlg, serviceItem);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_PH_SERVICE_PAGE_MODIFIED:\n        {\n            PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)lParam;\n            PPH_SERVICE_ITEM serviceItem = NULL;\n\n            if (ListView_GetSelectedCount(context->ListViewHandle) == 1)\n                serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle);\n\n            if (serviceModifiedData->ServiceItem == serviceItem)\n            {\n                PhpFixProcessServicesControls(hwndDlg, serviceItem);\n            }\n\n            PhFree(serviceModifiedData);\n        }\n        break;\n    case WM_PH_SET_LIST_VIEW_SETTINGS:\n        {\n            PWSTR settingName = (PWSTR)lParam;\n\n            context->ListViewSettingName = settingName;\n            PhLoadListViewColumnsFromSetting(settingName, context->ListViewHandle);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID* listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L\"Go to service\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhServiceListInsertContextMenu(hwndDlg, menu, (PPH_SERVICE_ITEM*)listviewItems, numberOfItems);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case 1:\n                                {\n                                    SetForegroundWindow(PhMwpServiceTreeNewHandle);\n\n                                    SystemInformer_SelectTabPage(1);\n\n                                    SetFocus(PhMwpServiceTreeNewHandle);\n\n                                    SystemInformer_SelectServiceItem((PPH_SERVICE_ITEM)listviewItems[0]);\n                                }\n                                break;\n                            case ID_SERVICE_GOTOPROCESS:\n                                {\n                                    PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)listviewItems[0];\n                                    PPH_PROCESS_NODE processNode;\n\n                                    if (serviceItem)\n                                    {\n                                        if (processNode = PhFindProcessNode(serviceItem->ProcessId))\n                                        {\n                                            SetForegroundWindow(PhMwpProcessTreeNewHandle);\n\n                                            SystemInformer_SelectTabPage(0);\n\n                                            SetFocus(PhMwpProcessTreeNewHandle);\n\n                                            PhSelectAndEnsureVisibleProcessNode(processNode);\n                                        }\n                                        else\n                                        {\n                                            PhShowStatus(hwndDlg, L\"The process does not exist.\", STATUS_INVALID_CID, 0);\n                                        }\n                                    }\n                                }\n                                break;\n                            case ID_SERVICE_START:\n                                {\n                                    PPH_SERVICE_ITEM* serviceItems = (PPH_SERVICE_ITEM*)listviewItems;\n                                    ULONG numberOfServiceItems = numberOfItems;\n\n                                    PhReferenceObjects(serviceItems, numberOfServiceItems);\n                                    PhUiStartServices(hwndDlg, serviceItems, numberOfServiceItems);\n                                    PhDereferenceObjects(serviceItems, numberOfServiceItems);\n                                }\n                                break;\n                            case ID_SERVICE_CONTINUE:\n                                {\n                                    PPH_SERVICE_ITEM* serviceItems = (PPH_SERVICE_ITEM*)listviewItems;\n                                    ULONG numberOfServiceItems = numberOfItems;\n\n                                    PhReferenceObjects(serviceItems, numberOfServiceItems);\n                                    PhUiContinueServices(hwndDlg, serviceItems, numberOfServiceItems);\n                                    PhDereferenceObjects(serviceItems, numberOfServiceItems);\n                                }\n                                break;\n                            case ID_SERVICE_PAUSE:\n                                {\n                                    PPH_SERVICE_ITEM* serviceItems = (PPH_SERVICE_ITEM*)listviewItems;\n                                    ULONG numberOfServiceItems = numberOfItems;\n\n                                    PhReferenceObjects(serviceItems, numberOfServiceItems);\n                                    PhUiPauseServices(hwndDlg, serviceItems, numberOfServiceItems);\n                                    PhDereferenceObjects(serviceItems, numberOfServiceItems);\n                                }\n                                break;\n                            case ID_SERVICE_STOP:\n                                {\n                                    PPH_SERVICE_ITEM* serviceItems = (PPH_SERVICE_ITEM*)listviewItems;\n                                    ULONG numberOfServiceItems = numberOfItems;\n\n                                    PhReferenceObjects(serviceItems, numberOfServiceItems);\n                                    PhUiStopServices(hwndDlg, serviceItems, numberOfServiceItems);\n                                    PhDereferenceObjects(serviceItems, numberOfServiceItems);\n                                }\n                                break;\n                            case ID_SERVICE_DELETE:\n                                {\n                                    PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)listviewItems[0];\n\n                                    if (serviceItem)\n                                    {\n                                        PhReferenceObject(serviceItem);\n\n                                        if (PhUiDeleteService(hwndDlg, serviceItem))\n                                        {\n                                            LONG lvItemIndex;\n\n                                            lvItemIndex = PhFindListViewItemByFlags(context->ListViewHandle, INT_ERROR, LVNI_SELECTED);\n\n                                            if (lvItemIndex != INT_ERROR)\n                                            {\n                                                PhRemoveListViewItem(context->ListViewHandle, lvItemIndex);\n                                            }\n                                        }\n\n                                        PhDereferenceObject(serviceItem);\n                                    }\n                                }\n                                break;\n                            case ID_SERVICE_OPENKEY:\n                                {\n                                    PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)listviewItems[0];\n\n                                    if (serviceItem)\n                                    {\n                                        HANDLE keyHandle;\n\n                                        if (NT_SUCCESS(PhOpenServiceKey(\n                                            &keyHandle,\n                                            KEY_READ,\n                                            &serviceItem->Name->sr\n                                            )))\n                                        {\n                                            PPH_STRING hklmServiceKeyName;\n\n                                            if (NT_SUCCESS(PhQueryObjectName(keyHandle, &hklmServiceKeyName)))\n                                            {\n                                                PhMoveReference(&hklmServiceKeyName, PhFormatNativeKeyName(hklmServiceKeyName));\n\n                                                PhShellOpenKey2(hwndDlg, hklmServiceKeyName);\n\n                                                PhDereferenceObject(hklmServiceKeyName);\n                                            }\n                                            else\n                                            {\n                                                PhShowStatus(hwndDlg, L\"The service does not exist.\", STATUS_OBJECT_NAME_NOT_FOUND, 0);\n                                            }\n\n                                            NtClose(keyHandle);\n                                        }\n                                        else\n                                        {\n                                            PhShowStatus(hwndDlg, L\"The service does not exist.\", STATUS_OBJECT_NAME_NOT_FOUND, 0);\n                                        }\n                                    }\n                                }\n                                break;\n                            case ID_SERVICE_OPENFILELOCATION:\n                                {\n                                    PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)listviewItems[0];\n                                    NTSTATUS status;\n                                    SC_HANDLE serviceHandle;\n\n                                    if (serviceItem)\n                                    {\n                                        status = PhOpenService(&serviceHandle, SERVICE_QUERY_CONFIG, PhGetString(serviceItem->Name));\n\n                                        if (NT_SUCCESS(status))\n                                        {\n                                            PPH_STRING fileName;\n\n                                            status = PhGetServiceHandleFileName(serviceHandle, &serviceItem->Name->sr, &fileName);\n\n                                            if (NT_SUCCESS(status))\n                                            {\n                                                PhShellExecuteUserString(\n                                                    hwndDlg,\n                                                    SETTING_FILE_BROWSE_EXECUTABLE,\n                                                    PhGetString(fileName),\n                                                    FALSE,\n                                                    L\"Make sure the Explorer executable file is present.\"\n                                                    );\n                                                PhDereferenceObject(fileName);\n                                            }\n                                            else\n                                            {\n                                                PhShowStatus(hwndDlg, L\"Unable to locate the file.\", status, 0);\n                                            }\n\n                                            PhCloseServiceHandle(serviceHandle);\n                                        }\n                                        else\n                                        {\n                                            PhShowStatus(hwndDlg, L\"Unable to locate the file.\", status, 0);\n                                        }\n                                    }\n                                }\n                                break;\n                            case ID_SERVICE_PROPERTIES:\n                                {\n                                    PPH_SERVICE_ITEM serviceItem = listviewItems[0];\n\n                                    if (serviceItem)\n                                    {\n                                        // The object relies on the list view reference, which could\n                                        // disappear if we don't reference the object here.\n                                        PhReferenceObject(serviceItem);\n                                        PhShowServiceProperties(hwndDlg, serviceItem);\n                                        PhDereferenceObject(serviceItem);\n                                    }\n                                }\n                                break;\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(context->ListViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/srvlist.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <srvlist.h>\n\n#include <cpysave.h>\n#include <emenu.h>\n#include <svcsup.h>\n#include <settings.h>\n#include <verify.h>\n#include <mapldr.h>\n\n#include <colmgr.h>\n#include <extmgri.h>\n#include <mainwnd.h>\n#include <phplug.h>\n#include <phsettings.h>\n#include <procprv.h>\n#include <srvprv.h>\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpServiceNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpServiceNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\nVOID PhpRemoveServiceNode(\n    _In_ PPH_SERVICE_NODE ServiceNode,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpServiceTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    );\n\nBOOLEAN NTAPI PhpServiceTreeNewCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    );\n\nstatic HWND ServiceTreeListHandle;\nstatic ULONG ServiceTreeListSortColumn;\nstatic PH_SORT_ORDER ServiceTreeListSortOrder;\nstatic PH_CM_MANAGER ServiceTreeListCm;\n\nstatic PPH_HASHTABLE ServiceNodeHashtable; // hashtable of all nodes\nstatic PPH_LIST ServiceNodeList; // list of all nodes\nstatic PH_TN_FILTER_SUPPORT FilterSupport;\n\nBOOLEAN PhServiceTreeListStateHighlighting = TRUE;\nstatic PPH_POINTER_LIST ServiceNodeStateList = NULL; // list of nodes which need to be processed\n\nVOID PhServiceTreeListInitialization(\n    VOID\n    )\n{\n    ServiceNodeHashtable = PhCreateHashtable(\n        sizeof(PPH_SERVICE_NODE),\n        PhpServiceNodeHashtableEqualFunction,\n        PhpServiceNodeHashtableHashFunction,\n        100\n        );\n    ServiceNodeList = PhCreateList(100);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpServiceNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_SERVICE_NODE serviceNode1 = *(PPH_SERVICE_NODE *)Entry1;\n    PPH_SERVICE_NODE serviceNode2 = *(PPH_SERVICE_NODE *)Entry2;\n\n    return serviceNode1->ServiceItem == serviceNode2->ServiceItem;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpServiceNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashIntPtr((ULONG_PTR)(*(PPH_SERVICE_NODE *)Entry)->ServiceItem);\n}\n\nVOID PhInitializeServiceTreeList(\n    _In_ HWND hwnd\n    )\n{\n    ServiceTreeListHandle = hwnd;\n\n    TreeNew_SetRedraw(hwnd, FALSE);\n    PhSetControlTheme(ServiceTreeListHandle, L\"explorer\");\n    TreeNew_SetCallback(hwnd, PhpServiceTreeNewCallback, NULL);\n    TreeNew_SetImageList(hwnd, PhProcessSmallImageList);\n\n    // Default columns\n    PhAddTreeNewColumn(hwnd, PHSVTLC_NAME, TRUE, L\"Name\", 140, PH_ALIGN_LEFT, 0, 0);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_PID, TRUE, L\"PID\", 50, PH_ALIGN_RIGHT, 1, DT_RIGHT);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_DISPLAYNAME, TRUE, L\"Display name\", 220, PH_ALIGN_LEFT, 2, 0);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_TYPE, TRUE, L\"Type\", 100, PH_ALIGN_LEFT, 3, 0);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_STATUS, TRUE, L\"Status\", 70, PH_ALIGN_LEFT, 4, 0);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_STARTTYPE, TRUE, L\"Start type\", 130, PH_ALIGN_LEFT, 5, 0);\n    // Customizable columns\n    PhAddTreeNewColumn(hwnd, PHSVTLC_BINARYPATH, FALSE, L\"Binary path\", 180, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_ERRORCONTROL, FALSE, L\"Error control\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_GROUP, FALSE, L\"Group\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_DESCRIPTION, FALSE, L\"Description\", 200, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(hwnd, PHSVTLC_KEYMODIFIEDTIME, FALSE, L\"Key modified time\", 140, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFICATIONSTATUS, FALSE, L\"Verification status\", 70, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFIEDSIGNER, FALSE, L\"Verified signer\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_FILENAME, FALSE, L\"File name\", 100, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS);\n    PhAddTreeNewColumnEx2(hwnd, PHSVTLC_TIMELINE, FALSE, L\"Timeline\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING);\n    PhAddTreeNewColumn(hwnd, PHSVTLC_EXITCODE, FALSE, L\"Exit code\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n\n    PhCmInitializeManager(&ServiceTreeListCm, hwnd, PHSVTLC_MAXIMUM, PhpServiceTreeNewPostSortFunction);\n    PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, ServiceNodeList);\n\n    TreeNew_SetTriState(hwnd, TRUE);\n    TreeNew_SetRedraw(hwnd, TRUE);\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;\n\n        treeNewInfo.TreeNewHandle = hwnd;\n        treeNewInfo.CmData = &ServiceTreeListCm;\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing), &treeNewInfo);\n    }\n}\n\nVOID PhLoadSettingsServiceTreeList(\n    VOID\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhGetStringSetting(SETTING_SERVICE_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_SERVICE_TREE_LIST_SORT);\n    PhCmLoadSettingsEx(ServiceTreeListHandle, &ServiceTreeListCm, 0, &settings->sr, &sortSettings->sr);\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_INSTANT_TOOLTIPS))\n        SendMessage(TreeNew_GetTooltips(ServiceTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0);\n    else\n        SendMessage(TreeNew_GetTooltips(ServiceTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);\n}\n\nVOID PhSaveSettingsServiceTreeList(\n    VOID\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(ServiceTreeListHandle, &ServiceTreeListCm, 0, &sortSettings);\n    PhSetStringSetting2(SETTING_SERVICE_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_SERVICE_TREE_LIST_SORT, &sortSettings->sr);\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nstruct _PH_TN_FILTER_SUPPORT *PhGetFilterSupportServiceTreeList(\n    VOID\n    )\n{\n    return &FilterSupport;\n}\n\nPPH_SERVICE_NODE PhAddServiceNode(\n    _In_ PPH_SERVICE_ITEM ServiceItem,\n    _In_ ULONG RunId\n    )\n{\n    PPH_SERVICE_NODE serviceNode;\n\n    serviceNode = PhAllocate(PhEmGetObjectSize(EmServiceNodeType, sizeof(PH_SERVICE_NODE)));\n    memset(serviceNode, 0, sizeof(PH_SERVICE_NODE));\n    PhInitializeTreeNewNode(&serviceNode->Node);\n\n    if (PhServiceTreeListStateHighlighting && RunId != 1)\n    {\n        PhChangeShStateTn(\n            &serviceNode->Node,\n            &serviceNode->ShState,\n            &ServiceNodeStateList,\n            NewItemState,\n            PhCsColorNew,\n            NULL\n            );\n    }\n\n    serviceNode->ServiceItem = ServiceItem;\n    PhReferenceObject(ServiceItem);\n\n    memset(serviceNode->TextCache, 0, sizeof(PH_STRINGREF) * PHSVTLC_MAXIMUM);\n    serviceNode->Node.TextCache = serviceNode->TextCache;\n    serviceNode->Node.TextCacheSize = PHSVTLC_MAXIMUM;\n\n    PhAddEntryHashtable(ServiceNodeHashtable, &serviceNode);\n    PhAddItemList(ServiceNodeList, serviceNode);\n\n    if (FilterSupport.FilterList)\n        serviceNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &serviceNode->Node);\n\n    PhEmCallObjectOperation(EmServiceNodeType, serviceNode, EmObjectCreate);\n\n    TreeNew_NodesStructured(ServiceTreeListHandle);\n\n    return serviceNode;\n}\n\nPPH_SERVICE_NODE PhFindServiceNode(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    PH_SERVICE_NODE lookupServiceNode;\n    PPH_SERVICE_NODE lookupServiceNodePtr = &lookupServiceNode;\n    PPH_SERVICE_NODE *serviceNode;\n\n    lookupServiceNode.ServiceItem = ServiceItem;\n\n    serviceNode = (PPH_SERVICE_NODE *)PhFindEntryHashtable(\n        ServiceNodeHashtable,\n        &lookupServiceNodePtr\n        );\n\n    if (serviceNode)\n        return *serviceNode;\n    else\n        return NULL;\n}\n\nVOID PhRemoveServiceNode(\n    _In_ PPH_SERVICE_NODE ServiceNode\n    )\n{\n    // Remove from the hashtable here to avoid problems in case the key is re-used.\n    PhRemoveEntryHashtable(ServiceNodeHashtable, &ServiceNode);\n\n    if (PhServiceTreeListStateHighlighting)\n    {\n        PhChangeShStateTn(\n            &ServiceNode->Node,\n            &ServiceNode->ShState,\n            &ServiceNodeStateList,\n            RemovingItemState,\n            PhCsColorRemoved,\n            ServiceTreeListHandle\n            );\n    }\n    else\n    {\n        PhpRemoveServiceNode(ServiceNode, NULL);\n    }\n}\n\nVOID PhpRemoveServiceNode(\n    _In_ PPH_SERVICE_NODE ServiceNode,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG index;\n\n    PhEmCallObjectOperation(EmServiceNodeType, ServiceNode, EmObjectDelete);\n\n    // Remove from list and cleanup.\n\n    if ((index = PhFindItemList(ServiceNodeList, ServiceNode)) != ULONG_MAX)\n        PhRemoveItemList(ServiceNodeList, index);\n\n    PhClearReference(&ServiceNode->BinaryPath);\n    PhClearReference(&ServiceNode->LoadOrderGroup);\n    PhClearReference(&ServiceNode->Description);\n    PhClearReference(&ServiceNode->TooltipText);\n    PhClearReference(&ServiceNode->KeyModifiedTimeText);\n    PhClearReference(&ServiceNode->ExitCodeText);\n\n    PhDereferenceObject(ServiceNode->ServiceItem);\n\n    PhFree(ServiceNode);\n\n    TreeNew_NodesStructured(ServiceTreeListHandle);\n}\n\nVOID PhUpdateServiceNode(\n    _In_ PPH_SERVICE_NODE ServiceNode\n    )\n{\n    memset(ServiceNode->TextCache, 0, sizeof(PH_STRINGREF) * PHSVTLC_MAXIMUM);\n\n    PhClearReference(&ServiceNode->TooltipText);\n\n    ServiceNode->ValidMask = 0;\n    PhInvalidateTreeNewNode(&ServiceNode->Node, TN_CACHE_ICON);\n    TreeNew_InvalidateNode(ServiceTreeListHandle, &ServiceNode->Node);\n}\n\nVOID PhTickServiceNodes(\n    VOID\n    )\n{\n    if (ServiceTreeListSortOrder != NoSortOrder)\n    {\n        // Force a rebuild to sort the items.\n        TreeNew_NodesStructured(ServiceTreeListHandle);\n    }\n\n    PH_TICK_SH_STATE_TN(PH_SERVICE_NODE, ShState, ServiceNodeStateList, PhpRemoveServiceNode, PhCsHighlightingDuration, ServiceTreeListHandle, TRUE, NULL, NULL);\n}\n\nstatic VOID PhpUpdateServiceNodeConfig(\n    _Inout_ PPH_SERVICE_NODE ServiceNode\n    )\n{\n    if (!FlagOn(ServiceNode->ValidMask, PHSN_CONFIG))\n    {\n        SC_HANDLE serviceHandle;\n        LPQUERY_SERVICE_CONFIG serviceConfig;\n\n        if (NT_SUCCESS(PhOpenService(&serviceHandle, SERVICE_QUERY_CONFIG, PhGetString(ServiceNode->ServiceItem->Name))))\n        {\n            if (NT_SUCCESS(PhGetServiceConfig(serviceHandle, &serviceConfig)))\n            {\n                if (serviceConfig->lpBinaryPathName)\n                    PhMoveReference(&ServiceNode->BinaryPath, PhCreateString(serviceConfig->lpBinaryPathName));\n                if (serviceConfig->lpLoadOrderGroup)\n                    PhMoveReference(&ServiceNode->LoadOrderGroup, PhCreateString(serviceConfig->lpLoadOrderGroup));\n\n                PhFree(serviceConfig);\n            }\n\n            PhCloseServiceHandle(serviceHandle);\n        }\n\n        SetFlag(ServiceNode->ValidMask, PHSN_CONFIG);\n    }\n}\n\nstatic VOID PhpUpdateServiceNodeDescription(\n    _Inout_ PPH_SERVICE_NODE ServiceNode\n    )\n{\n    if (!FlagOn(ServiceNode->ValidMask, PHSN_DESCRIPTION))\n    {\n        PhSwapReference(\n            &ServiceNode->Description,\n            PhGetServiceDescriptionKey(&ServiceNode->ServiceItem->Name->sr)\n            );\n\n        SetFlag(ServiceNode->ValidMask, PHSN_DESCRIPTION);\n    }\n\n    // NOTE: Querying the service description via RPC is extremely slow. (dmex)\n    //SC_HANDLE serviceHandle;\n    //\n    //if (serviceHandle = PhOpenService(ServiceNode->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG))\n    //{\n    //    PhMoveReference(&ServiceNode->Description, PhGetServiceDescription(serviceHandle));\n    //    CloseServiceHandle(serviceHandle);\n    //}\n}\n\nstatic VOID PhpUpdateServiceNodeKey(\n    _Inout_ PPH_SERVICE_NODE ServiceNode\n    )\n{\n    if (!FlagOn(ServiceNode->ValidMask, PHSN_KEY))\n    {\n        HANDLE keyHandle;\n\n        if (NT_SUCCESS(PhOpenServiceKey(\n            &keyHandle,\n            KEY_QUERY_VALUE,\n            &ServiceNode->ServiceItem->Name->sr\n            )))\n        {\n            LARGE_INTEGER lastWriteTime;\n\n            if (NT_SUCCESS(PhQueryKeyLastWriteTime(keyHandle, &lastWriteTime)))\n            {\n                ServiceNode->KeyLastWriteTime = lastWriteTime;\n            }\n\n            NtClose(keyHandle);\n        }\n        else\n        {\n            RtlZeroMemory(&ServiceNode->KeyLastWriteTime, sizeof(ServiceNode->KeyLastWriteTime));\n        }\n\n        SetFlag(ServiceNode->ValidMask, PHSN_KEY);\n    }\n}\n\n#define SORT_FUNCTION(Column) PhpServiceTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpServiceTreeNewCompare##Column( \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_SERVICE_NODE node1 = *(PPH_SERVICE_NODE *)_elem1; \\\n    PPH_SERVICE_NODE node2 = *(PPH_SERVICE_NODE *)_elem2; \\\n    PPH_SERVICE_ITEM serviceItem1 = node1->ServiceItem; \\\n    PPH_SERVICE_ITEM serviceItem2 = node2->ServiceItem; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); \\\n    \\\n    return PhModifySort(sortResult, ServiceTreeListSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpServiceTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    PPH_SERVICE_NODE node1 = (PPH_SERVICE_NODE)Node1;\n    PPH_SERVICE_NODE node2 = (PPH_SERVICE_NODE)Node2;\n    PPH_SERVICE_ITEM serviceItem1 = node1->ServiceItem;\n    PPH_SERVICE_ITEM serviceItem2 = node2->ServiceItem;\n\n    if (Result == 0)\n        Result = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Pid)\n{\n    sortResult = uintptrcmp((ULONG_PTR)serviceItem1->ProcessId, (ULONG_PTR)serviceItem2->ProcessId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(DisplayName)\n{\n    sortResult = PhCompareStringWithNull(serviceItem1->DisplayName, serviceItem2->DisplayName, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Type)\n{\n    sortResult = uintcmp(serviceItem1->Type, serviceItem2->Type);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Status)\n{\n    sortResult = uintcmp(serviceItem1->State, serviceItem2->State);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StartType)\n{\n    sortResult = uintcmp(serviceItem1->StartType, serviceItem2->StartType);\n\n    if (sortResult == 0)\n        sortResult = ucharcmp(serviceItem1->DelayedStart, serviceItem2->DelayedStart);\n    if (sortResult == 0)\n        sortResult = ucharcmp(serviceItem1->HasTriggers, serviceItem2->HasTriggers);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(BinaryPath)\n{\n    PhpUpdateServiceNodeConfig(node1);\n    PhpUpdateServiceNodeConfig(node2);\n    sortResult = PhCompareStringWithNullSortOrder(node1->BinaryPath, node2->BinaryPath, ServiceTreeListSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ErrorControl)\n{\n    sortResult = uintcmp(serviceItem1->ErrorControl, serviceItem2->ErrorControl);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Group)\n{\n    PhpUpdateServiceNodeConfig(node1);\n    PhpUpdateServiceNodeConfig(node2);\n    sortResult = PhCompareStringWithNullSortOrder(node1->LoadOrderGroup, node2->LoadOrderGroup, ServiceTreeListSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Description)\n{\n    PhpUpdateServiceNodeDescription(node1);\n    PhpUpdateServiceNodeDescription(node2);\n    sortResult = PhCompareStringWithNullSortOrder(node1->Description, node2->Description, ServiceTreeListSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(KeyModifiedTime)\n{\n    PhpUpdateServiceNodeKey(node1);\n    PhpUpdateServiceNodeKey(node2);\n    sortResult = int64cmp(node1->KeyLastWriteTime.QuadPart, node2->KeyLastWriteTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(VerificationStatus)\n{\n    sortResult = uintcmp(serviceItem1->VerifyResult, serviceItem2->VerifyResult);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(VerifiedSigner)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        serviceItem1->VerifySignerName,\n        serviceItem2->VerifySignerName,\n        ServiceTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        serviceItem1->FileName,\n        serviceItem2->FileName,\n        ServiceTreeListSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ExitCode)\n{\n    sortResult = uintcmp(serviceItem1->Win32ExitCode, serviceItem2->Win32ExitCode);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpServiceTreeNewCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_SERVICE_NODE node;\n\n    if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &ServiceTreeListCm))\n        return TRUE;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n\n            if (!getChildren->Node)\n            {\n                static PVOID sortFunctions[] =\n                {\n                    SORT_FUNCTION(Name),\n                    SORT_FUNCTION(Pid),\n                    SORT_FUNCTION(DisplayName),\n                    SORT_FUNCTION(Type),\n                    SORT_FUNCTION(Status),\n                    SORT_FUNCTION(StartType),\n                    SORT_FUNCTION(BinaryPath),\n                    SORT_FUNCTION(ErrorControl),\n                    SORT_FUNCTION(Group),\n                    SORT_FUNCTION(Description),\n                    SORT_FUNCTION(KeyModifiedTime),\n                    SORT_FUNCTION(VerificationStatus),\n                    SORT_FUNCTION(VerifiedSigner),\n                    SORT_FUNCTION(FileName),\n                    SORT_FUNCTION(KeyModifiedTime), // Timeline\n                    SORT_FUNCTION(ExitCode),\n                };\n                int (__cdecl *sortFunction)(const void *, const void *);\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PHSVTLC_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (!PhCmForwardSort(\n                    (PPH_TREENEW_NODE *)ServiceNodeList->Items,\n                    ServiceNodeList->Count,\n                    ServiceTreeListSortColumn,\n                    ServiceTreeListSortOrder,\n                    &ServiceTreeListCm\n                    ))\n                {\n                    if (ServiceTreeListSortColumn < PHSVTLC_MAXIMUM)\n                        sortFunction = sortFunctions[ServiceTreeListSortColumn];\n                    else\n                        sortFunction = NULL;\n\n                    if (sortFunction)\n                    {\n                        qsort(ServiceNodeList->Items, ServiceNodeList->Count, sizeof(PVOID), sortFunction);\n                    }\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)ServiceNodeList->Items;\n                getChildren->NumberOfChildren = ServiceNodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            PPH_SERVICE_ITEM serviceItem;\n\n            node = (PPH_SERVICE_NODE)getCellText->Node;\n            serviceItem = node->ServiceItem;\n\n            switch (getCellText->Id)\n            {\n            case PHSVTLC_NAME:\n                getCellText->Text = PhGetStringRef(serviceItem->Name);\n                break;\n            case PHSVTLC_PID:\n                {\n                    if (PH_IS_REAL_PROCESS_ID(serviceItem->ProcessId))\n                    {\n                        PhInitializeStringRefLongHint(&getCellText->Text, serviceItem->ProcessIdString);\n                    }\n                }\n                break;\n            case PHSVTLC_DISPLAYNAME:\n                getCellText->Text = PhGetStringRef(serviceItem->DisplayName);\n                break;\n            case PHSVTLC_TYPE:\n                {\n                    PCPH_STRINGREF string;\n\n                    string = PhGetServiceTypeString(serviceItem->Type);\n                    getCellText->Text.Buffer = string->Buffer;\n                    getCellText->Text.Length = string->Length;\n                }\n                break;\n            case PHSVTLC_STATUS:\n                {\n                    PCPH_STRINGREF string;\n\n                    string = PhGetServiceStateString(serviceItem->State);\n                    getCellText->Text.Buffer = string->Buffer;\n                    getCellText->Text.Length = string->Length;\n                }\n                break;\n            case PHSVTLC_STARTTYPE:\n                {\n                    PH_FORMAT format[2];\n                    PCPH_STRINGREF string;\n                    PWSTR additional = NULL;\n                    SIZE_T returnLength;\n\n                    string = PhGetServiceStartTypeString(serviceItem->StartType);\n                    format[0].Type = StringFormatType;\n                    format[0].u.String.Buffer = string->Buffer;\n                    format[0].u.String.Length = string->Length;\n                    //PhInitFormatSR(&format[0], PhGetServiceStartTypeString(serviceItem->StartType));\n\n                    if (serviceItem->StartType == SERVICE_DISABLED)\n                        additional = NULL;\n                    else if (serviceItem->DelayedStart && serviceItem->HasTriggers)\n                        additional = L\" (delayed, trigger)\";\n                    else if (serviceItem->DelayedStart)\n                        additional = L\" (delayed)\";\n                    else if (serviceItem->HasTriggers)\n                        additional = L\" (trigger)\";\n\n                    if (additional)\n                        PhInitFormatS(&format[1], additional);\n\n                    if (PhFormatToBuffer(format, 1 + (additional ? 1 : 0), node->StartTypeText,\n                        sizeof(node->StartTypeText), &returnLength))\n                    {\n                        getCellText->Text.Buffer = node->StartTypeText;\n                        getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                break;\n            case PHSVTLC_BINARYPATH:\n                {\n                    PhpUpdateServiceNodeConfig(node);\n                    getCellText->Text = PhGetStringRef(node->BinaryPath);\n                }\n                break;\n            case PHSVTLC_ERRORCONTROL:\n                {\n                    PCPH_STRINGREF string;\n\n                    string = PhGetServiceErrorControlString(serviceItem->ErrorControl);\n                    getCellText->Text.Buffer = string->Buffer;\n                    getCellText->Text.Length = string->Length;\n                }\n                break;\n            case PHSVTLC_GROUP:\n                {\n                    PhpUpdateServiceNodeConfig(node);\n                    getCellText->Text = PhGetStringRef(node->LoadOrderGroup);\n                }\n                break;\n            case PHSVTLC_DESCRIPTION:\n                {\n                    PhpUpdateServiceNodeDescription(node);\n                    getCellText->Text = PhGetStringRef(node->Description);\n                }\n                break;\n            case PHSVTLC_KEYMODIFIEDTIME:\n                {\n                    PhpUpdateServiceNodeKey(node);\n\n                    if (node->KeyLastWriteTime.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &node->KeyLastWriteTime);\n                        PhMoveReference(&node->KeyModifiedTimeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = node->KeyModifiedTimeText->sr;\n                    }\n                }\n                break;\n            case PHSVTLC_VERIFICATIONSTATUS:\n                {\n                    if (PhEnableServiceQueryStage2)\n                        getCellText->Text = PhVerifyResultToStringRef(serviceItem->VerifyResult);\n                    else\n                        PhInitializeStringRef(&getCellText->Text, L\"Service digital signature support disabled.\");\n                }\n                break;\n            case PHSVTLC_VERIFIEDSIGNER:\n                {\n                    if (PhEnableServiceQueryStage2)\n                        getCellText->Text = PhGetStringRef(serviceItem->VerifySignerName);\n                    else\n                        PhInitializeStringRef(&getCellText->Text, L\"Service digital signature support disabled.\");\n                }\n                break;\n            case PHSVTLC_FILENAME:\n                {\n                    getCellText->Text = PhGetStringRef(serviceItem->FileName);\n                }\n                break;\n            case PHSVTLC_EXITCODE:\n                {\n                    if (serviceItem->Win32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR)\n                    {\n                        PhMoveReference(&node->ExitCodeText, PhFormatUInt64(serviceItem->ServiceSpecificExitCode, FALSE));\n                        getCellText->Text = node->ExitCodeText->sr;\n                    }\n                    else\n                    {\n                        PH_STRING_BUILDER stringBuilder;\n                        PPH_STRING statusMessage;\n\n                        PhInitializeStringBuilder(&stringBuilder, 0x50);\n                        statusMessage = PhGetStatusMessage(0, serviceItem->Win32ExitCode);\n                        PhAppendFormatStringBuilder(&stringBuilder, L\"(0x%lx) \", serviceItem->Win32ExitCode);\n\n                        if (!PhIsNullOrEmptyString(statusMessage))\n                        {\n                            PhAppendStringBuilder(&stringBuilder, &statusMessage->sr);\n                            PhClearReference(&statusMessage);\n                        }\n\n                        PhMoveReference(&node->ExitCodeText, PhFinalStringBuilderString(&stringBuilder));\n                        getCellText->Text = node->ExitCodeText->sr;\n                    }\n                }\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeIcon:\n        {\n            PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1;\n            node = (PPH_SERVICE_NODE)getNodeIcon->Node;\n\n            if (node->ServiceItem->IconEntry)\n            {\n                getNodeIcon->Icon = (HICON)(ULONG_PTR)node->ServiceItem->IconEntry->SmallIconIndex;\n            }\n            else\n            {\n                if (FlagOn(node->ServiceItem->Type, SERVICE_DRIVER))\n                    getNodeIcon->Icon = (HICON)(ULONG_PTR)1; // ServiceCogIcon\n                else\n                    getNodeIcon->Icon = (HICON)(ULONG_PTR)0; // ServiceApplicationIcon\n            }\n\n            //getNodeIcon->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            PPH_SERVICE_ITEM serviceItem;\n\n            node = (PPH_SERVICE_NODE)getNodeColor->Node;\n            serviceItem = node->ServiceItem;\n\n            if (!serviceItem)\n                ; // Dummy\n            else if (PhEnableServiceQueryStage2 && PhCsUseColorUnknown && PH_VERIFY_UNTRUSTED(serviceItem->VerifyResult))\n            {\n                getNodeColor->BackColor = PhCsColorUnknown;\n                getNodeColor->Flags |= TN_AUTO_FORECOLOR;\n            }\n            else if (PhCsUseColorServiceDisabled && serviceItem->State == SERVICE_STOPPED && serviceItem->StartType == SERVICE_DISABLED)\n            {\n                getNodeColor->BackColor = PhCsColorServiceDisabled;\n                getNodeColor->Flags |= TN_AUTO_FORECOLOR;\n            }\n            else if (PhCsUseColorServiceStop && serviceItem->State == SERVICE_STOPPED)\n            {\n                getNodeColor->ForeColor = PhCsColorServiceStop;\n            }\n            else\n            {\n                getNodeColor->Flags |= TN_AUTO_FORECOLOR;\n            }\n        }\n        return TRUE;\n    case TreeNewGetCellTooltip:\n        {\n            PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;\n            node = (PPH_SERVICE_NODE)getCellTooltip->Node;\n\n            if (getCellTooltip->Column->Id != 0)\n                return FALSE;\n\n            if (!node->TooltipText)\n                node->TooltipText = PhGetServiceTooltipText(node->ServiceItem);\n\n            if (!PhIsNullOrEmptyString(node->TooltipText))\n            {\n                getCellTooltip->Text = node->TooltipText->sr;\n                getCellTooltip->Unfolding = FALSE;\n                getCellTooltip->MaximumWidth = 550;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case TreeNewCustomDraw:\n        {\n            PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;\n            PPH_SERVICE_ITEM serviceItem;\n            RECT rect;\n\n            node = (PPH_SERVICE_NODE)customDraw->Node;\n            serviceItem = node->ServiceItem;\n            rect = customDraw->CellRect;\n\n            if (rect.right - rect.left <= 1)\n                break; // nothing to draw\n\n            switch (customDraw->Column->Id)\n            {\n            case PHSVTLC_TIMELINE:\n                {\n                    PhpUpdateServiceNodeKey(node);\n\n                    if (node->KeyLastWriteTime.QuadPart == 0)\n                        break; // nothing to draw\n\n                    PhCustomDrawTreeTimeLine(\n                        customDraw->Dc,\n                        &customDraw->CellRect,\n                        PhEnableThemeSupport ? PH_DRAW_TIMELINE_DARKTHEME : 0,\n                        NULL,\n                        &node->KeyLastWriteTime\n                        );\n                }\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            ServiceTreeListSortColumn = sorting->SortColumn;\n            ServiceTreeListSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(hwnd);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_COPY, 0);\n                break;\n            case VK_DELETE:\n                SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_DELETE, 0);\n                break;\n            case VK_RETURN:\n                if (GetKeyState(VK_CONTROL) >= 0)\n                    SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_PROPERTIES, 0);\n                else\n                    SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_OPENFILELOCATION, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = hwnd;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = PHSVTLC_NAME;\n            data.DefaultSortOrder = NoSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_PROPERTIES, 0);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n\n            if (!contextMenu)\n                break;\n\n            PhShowServiceContextMenu(contextMenu);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nPPH_SERVICE_ITEM PhGetSelectedServiceItem(\n    VOID\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = NULL;\n    ULONG i;\n\n    for (i = 0; i < ServiceNodeList->Count; i++)\n    {\n        PPH_SERVICE_NODE node = ServiceNodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            serviceItem = node->ServiceItem;\n            break;\n        }\n    }\n\n    return serviceItem;\n}\n\nVOID PhGetSelectedServiceItems(\n    _Out_ PPH_SERVICE_ITEM **Services,\n    _Out_ PULONG NumberOfServices\n    )\n{\n    PH_ARRAY array;\n    ULONG i;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    for (i = 0; i < ServiceNodeList->Count; i++)\n    {\n        PPH_SERVICE_NODE node = ServiceNodeList->Items[i];\n\n        if (node->Node.Selected)\n            PhAddItemArray(&array, &node->ServiceItem);\n    }\n\n    *NumberOfServices = (ULONG)PhFinalArrayCount(&array);\n    *Services = PhFinalArrayItems(&array);\n}\n\nVOID PhDeselectAllServiceNodes(\n    VOID\n    )\n{\n    TreeNew_DeselectRange(ServiceTreeListHandle, 0, -1);\n}\n\nBOOLEAN PhSelectAndEnsureVisibleServiceNode(\n    _In_ PPH_SERVICE_NODE ServiceNode\n    )\n{\n    PhDeselectAllServiceNodes();\n\n    if (ServiceNode->Node.Visible)\n    {\n        TreeNew_FocusMarkSelectNode(ServiceTreeListHandle, &ServiceNode->Node);\n        return TRUE;\n    }\n    else\n    {\n        PhShowInformation2(\n            PhMainWndHandle,\n            L\"Unable to perform the operation.\",\n            L\"%s\",\n            L\"This node cannot be displayed because it is currently hidden by your active filter settings or preferences.\"\n            );\n        return FALSE;\n    }\n}\n\nVOID PhCopyServiceList(\n    VOID\n    )\n{\n    PPH_STRING text;\n\n    text = PhGetTreeNewText(ServiceTreeListHandle, 0);\n    PhSetClipboardString(ServiceTreeListHandle, &text->sr);\n    PhDereferenceObject(text);\n}\n\nVOID PhWriteServiceList(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ ULONG Mode\n    )\n{\n    PPH_LIST lines;\n    ULONG i;\n\n    lines = PhGetGenericTreeNewLines(ServiceTreeListHandle, Mode);\n\n    for (i = 0; i < lines->Count; i++)\n    {\n        PPH_STRING line;\n\n        line = lines->Items[i];\n        PhWriteStringAsUtf8FileStream(FileStream, &line->sr);\n        PhDereferenceObject(line);\n        PhWriteStringAsUtf8FileStream2(FileStream, L\"\\r\\n\");\n    }\n\n    PhDereferenceObject(lines);\n}\n"
  },
  {
    "path": "SystemInformer/srvprp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <secedit.h>\n#include <svcsup.h>\n#include <mainwnd.h>\n#include <settings.h>\n\n#include <actions.h>\n#include <phplug.h>\n#include <phsvccl.h>\n#include <phsettings.h>\n#include <procprv.h>\n#include <srvprv.h>\n\ntypedef struct _SERVICE_PROPERTIES_CONTEXT\n{\n    PPH_SERVICE_ITEM ServiceItem;\n\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN Ready : 1;\n            BOOLEAN Dirty : 1;\n            BOOLEAN OldDelayedStart : 1;\n            BOOLEAN Spare : 5;\n        };\n    };\n\n    HWND WindowHandle;\n    HWND TypeWindowHandle;\n    HWND StartTypeWindowHandle;\n    HWND ErrorControlWindowHandle;\n    HWND DelayedStartWindowHandle;\n    HWND DescriptionWindowHandle;\n    HWND GroupWindowHandle;\n    HWND BinaryPathWindowHandle;\n    HWND UserNameWindowHandle;\n    HWND PassBoxWindowHandle;\n    HWND PassCheckBoxWindowHandle;\n    HWND ServiceDllWindowHandle;\n} SERVICE_PROPERTIES_CONTEXT, *PSERVICE_PROPERTIES_CONTEXT;\n\nINT_PTR CALLBACK PhpServiceGeneralDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenServiceCallback(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PVOID Context\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = ((PPH_SERVICE_ITEM)Context);\n    NTSTATUS status;\n    SC_HANDLE serviceHandle;\n\n    status = PhOpenService(\n        &serviceHandle,\n        DesiredAccess,\n        PhGetString(serviceItem->Name)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Handle = serviceHandle;\n        return STATUS_SUCCESS;\n    }\n\n    *Handle = NULL;\n    return status;\n}\n\n_Function_class_(PH_CLOSE_OBJECT)\nNTSTATUS PhpCloseServiceCallback(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle)\n    {\n        PhCloseServiceHandle(Handle);\n    }\n\n    if (Release && Context)\n    {\n        PhDereferenceObject(((PPH_SERVICE_ITEM)Context));\n    }\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PH_SET_OBJECT_SECURITY)\nstatic _Callback_ NTSTATUS PhpSetServiceSecurityCallback(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PVOID Context\n    )\n{\n    PPH_STD_OBJECT_SECURITY stdObjectSecurity = ((PPH_STD_OBJECT_SECURITY)Context);\n    PPH_SERVICE_ITEM serviceItem = ((PPH_SERVICE_ITEM)stdObjectSecurity->Context);\n    NTSTATUS status;\n\n    status = PhStdSetObjectSecurity(\n        SecurityDescriptor,\n        SecurityInformation,\n        stdObjectSecurity->ObjectContext\n        );\n\n    if (status == STATUS_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated)\n    {\n        // Elevate using phsvc.\n        if (PhUiConnectToPhSvc(NULL, FALSE))\n        {\n            status = PhSvcCallSetServiceSecurity(\n                PhGetString(serviceItem->Name),\n                SecurityInformation,\n                SecurityDescriptor\n                );\n            PhUiDisconnectFromPhSvc();\n        }\n    }\n\n    return status;\n}\n\nLRESULT CALLBACK PhpPropSheetSrvWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    WNDPROC oldWndProc;\n\n    oldWndProc = PhGetWindowContext(hwnd, 0xF);\n\n    if (!oldWndProc)\n        return 0;\n\n    switch (uMsg)\n    {\n    case WM_NCDESTROY:\n        {\n            PhSetWindowProcedure(hwnd, oldWndProc);\n            PhRemoveWindowContext(hwnd, 0xF);\n        }\n        break;\n    case WM_SYSCOMMAND:\n        {\n            // Note: This fixes closing the window from the taskbar preview window. (dmex)\n            switch (wParam & 0xFFF0)\n            {\n            case SC_CLOSE:\n                {\n                    PostQuitMessage(0);\n                    //SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);\n                    //return TRUE;\n                }\n                break;\n            }\n        }\n        break;\n    case WM_KEYDOWN: // forward key messages\n        {\n            HWND pageWindowHandle;\n\n            if (pageWindowHandle = PropSheet_GetCurrentPageHwnd(hwnd))\n            {\n                if (SendMessage(pageWindowHandle, uMsg, wParam, lParam))\n                {\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);\n}\n\nLONG CALLBACK PhpPropSheetSrvProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case PSCB_INITIALIZED:\n        {\n            PhSetWindowContext(hwndDlg, 0xF, (PVOID)PhGetWindowProcedure(hwndDlg));\n            PhSetWindowProcedure(hwndDlg, PhpPropSheetSrvWndProc);\n        }\n        break;\n    }\n\n    return 0;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpShowServicePropertiesThread(\n    _In_ PVOID Context\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = ((PPH_SERVICE_ITEM)Context);\n    PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };\n    PROPSHEETPAGE propSheetPage;\n    HPROPSHEETPAGE pages[32];\n    SERVICE_PROPERTIES_CONTEXT context;\n\n    propSheetHeader.dwFlags =\n        PSH_MODELESS |\n        PSH_NOAPPLYNOW |\n        PSH_NOCONTEXTHELP |\n        PSH_PROPTITLE |\n        PSH_USECALLBACK |\n        PSH_USEHICON;\n    propSheetHeader.hInstance = NtCurrentImageBase();\n    //propSheetHeader.hwndParent = ParentWindowHandle;\n    propSheetHeader.pszCaption = PhGetString(serviceItem->Name);\n    propSheetHeader.nPages = 0;\n    propSheetHeader.nStartPage = 0;\n    propSheetHeader.phpage = pages;\n    propSheetHeader.pfnCallback = PhpPropSheetSrvProc;\n\n    // General\n\n    memset(&context, 0, sizeof(SERVICE_PROPERTIES_CONTEXT));\n    context.ServiceItem = serviceItem;\n    context.Ready = FALSE;\n    context.Dirty = FALSE;\n\n    memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));\n    propSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVGENERAL);\n    propSheetPage.hInstance = NtCurrentImageBase();\n    propSheetPage.pfnDlgProc = PhpServiceGeneralDlgProc;\n    propSheetPage.lParam = (LPARAM)&context;\n    pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_OBJECT_PROPERTIES objectProperties;\n\n        objectProperties.Parameter = serviceItem;\n        objectProperties.NumberOfPages = propSheetHeader.nPages;\n        objectProperties.MaximumNumberOfPages = sizeof(pages) / sizeof(HPROPSHEETPAGE);\n        objectProperties.Pages = pages;\n\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing), &objectProperties);\n\n        propSheetHeader.nPages = objectProperties.NumberOfPages;\n    }\n\n    PhModalPropertySheet(&propSheetHeader);\n\n    PhDereferenceObject(serviceItem);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhShowServiceProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    PhReferenceObject(ServiceItem);\n    PhCreateThread2(PhpShowServicePropertiesThread, ServiceItem);\n}\n\nstatic VOID PhServicePropertiesRefreshIcon(\n    _In_ PSERVICE_PROPERTIES_CONTEXT Context\n    )\n{\n    HICON serviceIcon;\n\n    if (Context->ServiceItem->IconEntry && Context->ServiceItem->IconEntry->SmallIconIndex)\n        serviceIcon = PhGetImageListIcon(Context->ServiceItem->IconEntry->SmallIconIndex, FALSE);\n    else\n    {\n        if (Context->ServiceItem->Type == SERVICE_KERNEL_DRIVER || Context->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER)\n            serviceIcon = PhGetImageListIcon(1, FALSE); // ServiceCogIcon;\n        else\n            serviceIcon = PhGetImageListIcon(0, FALSE); // ServiceApplicationIcon;\n    }\n\n    if (serviceIcon)\n    {\n        PhSetWindowIcon(GetParent(Context->WindowHandle), serviceIcon, NULL, TRUE);\n    }\n}\n\nstatic VOID PhServicePropertiesRefreshControls(\n    _In_ PSERVICE_PROPERTIES_CONTEXT Context\n    )\n{\n    PPH_STRING serviceStartTypeString;\n    PPH_STRING serviceTypeString;\n\n    serviceStartTypeString = PH_AUTO(PhGetWindowText(Context->StartTypeWindowHandle));\n    serviceTypeString = PH_AUTO(PhGetWindowText(Context->TypeWindowHandle));\n\n    if (PhEqualString2(serviceStartTypeString, L\"Auto start\", FALSE))\n        EnableWindow(Context->DelayedStartWindowHandle, TRUE);\n    else\n        EnableWindow(Context->DelayedStartWindowHandle, FALSE);\n\n    if (PhEqualString2(serviceTypeString, L\"Driver\", FALSE) ||\n        PhEqualString2(serviceTypeString, L\"FS driver\", FALSE))\n    {\n        EnableWindow(Context->UserNameWindowHandle, FALSE);\n        EnableWindow(Context->PassBoxWindowHandle, FALSE);\n        EnableWindow(Context->PassCheckBoxWindowHandle, FALSE);\n        EnableWindow(Context->ServiceDllWindowHandle, FALSE);\n    }\n    else\n    {\n        EnableWindow(Context->UserNameWindowHandle, TRUE);\n        EnableWindow(Context->PassBoxWindowHandle, TRUE);\n        EnableWindow(Context->PassCheckBoxWindowHandle, TRUE);\n        EnableWindow(Context->ServiceDllWindowHandle, TRUE);\n    }\n}\n\nINT_PTR CALLBACK PhpServiceGeneralDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PSERVICE_PROPERTIES_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;\n        context = (PSERVICE_PROPERTIES_CONTEXT)propSheetPage->lParam;\n\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_SERVICE_ITEM serviceItem = context->ServiceItem;\n            SC_HANDLE serviceHandle;\n            ULONG startType;\n            ULONG errorControl;\n            PPH_STRING serviceDll;\n\n            context->WindowHandle = hwndDlg;\n            context->TypeWindowHandle = GetDlgItem(hwndDlg, IDC_TYPE);\n            context->StartTypeWindowHandle = GetDlgItem(hwndDlg, IDC_STARTTYPE);\n            context->ErrorControlWindowHandle = GetDlgItem(hwndDlg, IDC_ERRORCONTROL);\n            context->DelayedStartWindowHandle = GetDlgItem(hwndDlg, IDC_DELAYEDSTART);\n            context->DescriptionWindowHandle = GetDlgItem(hwndDlg, IDC_DESCRIPTION);\n            context->GroupWindowHandle = GetDlgItem(hwndDlg, IDC_GROUP);\n            context->BinaryPathWindowHandle = GetDlgItem(hwndDlg, IDC_BINARYPATH);\n            context->UserNameWindowHandle = GetDlgItem(hwndDlg, IDC_USERACCOUNT);\n            context->PassBoxWindowHandle = GetDlgItem(hwndDlg, IDC_PASSWORD);\n            context->PassCheckBoxWindowHandle = GetDlgItem(hwndDlg, IDC_PASSWORDCHECK);\n            context->ServiceDllWindowHandle = GetDlgItem(hwndDlg, IDC_SERVICEDLL);\n\n            // HACK\n            if (PhValidWindowPlacementFromSetting(SETTING_SERVICE_WINDOW_POSITION))\n                PhCenterWindow(GetParent(hwndDlg), PhMainWndHandle);\n            else\n                PhLoadWindowPlacementFromSetting(SETTING_SERVICE_WINDOW_POSITION, NULL, GetParent(hwndDlg));\n\n            PhAddComboBoxStringRefs(context->TypeWindowHandle, PhServiceTypeStrings, RTL_NUMBER_OF(PhServiceTypeStrings));\n            PhAddComboBoxStringRefs(context->StartTypeWindowHandle, PhServiceStartTypeStrings, RTL_NUMBER_OF(PhServiceStartTypeStrings));\n            PhAddComboBoxStringRefs(context->ErrorControlWindowHandle, PhServiceErrorControlStrings, RTL_NUMBER_OF(PhServiceErrorControlStrings));\n\n            PhSetWindowText(context->DescriptionWindowHandle, PhGetStringOrEmpty(serviceItem->DisplayName));\n            PhSelectComboBoxString(context->TypeWindowHandle, PhGetServiceTypeString(serviceItem->Type)->Buffer, FALSE);\n\n            startType = serviceItem->StartType;\n            errorControl = serviceItem->ErrorControl;\n\n            if (NT_SUCCESS(PhOpenService(&serviceHandle, SERVICE_QUERY_CONFIG, PhGetString(serviceItem->Name))))\n            {\n                LPQUERY_SERVICE_CONFIG config;\n                PPH_STRING description;\n                BOOLEAN delayedStart;\n\n                if (NT_SUCCESS(PhGetServiceConfig(serviceHandle, &config)))\n                {\n                    PhSetWindowText(context->GroupWindowHandle, config->lpLoadOrderGroup);\n                    PhSetWindowText(context->BinaryPathWindowHandle, config->lpBinaryPathName);\n                    PhSetWindowText(context->UserNameWindowHandle, config->lpServiceStartName);\n\n                    if (startType != config->dwStartType || errorControl != config->dwErrorControl)\n                    {\n                        startType = config->dwStartType;\n                        errorControl = config->dwErrorControl;\n                        PhMarkNeedsConfigUpdateServiceItem(serviceItem);\n                    }\n\n                    PhFree(config);\n                }\n\n                if (description = PhGetServiceDescription(serviceHandle))\n                {\n                    PhSetWindowText(context->DescriptionWindowHandle, PhGetString(description));\n                    PhDereferenceObject(description);\n                }\n\n                if (NT_SUCCESS(PhGetServiceDelayedAutoStart(serviceHandle, &delayedStart)))\n                {\n                    context->OldDelayedStart = delayedStart;\n\n                    if (delayedStart)\n                        Button_SetCheck(context->DelayedStartWindowHandle, BST_CHECKED);\n                }\n\n                PhCloseServiceHandle(serviceHandle);\n            }\n\n            PhSelectComboBoxString(context->StartTypeWindowHandle, PhGetServiceStartTypeString(startType)->Buffer, FALSE);\n            PhSelectComboBoxString(context->ErrorControlWindowHandle, PhGetServiceErrorControlString(errorControl)->Buffer, FALSE);\n\n            PhSetWindowText(context->PassBoxWindowHandle, L\"password\");\n            Button_SetCheck(context->PassCheckBoxWindowHandle, BST_UNCHECKED);\n\n            if (NT_SUCCESS(PhGetServiceDllParameter(serviceItem->Type, &serviceItem->Name->sr, &serviceDll)))\n            {\n                PhSetDialogItemText(hwndDlg, IDC_SERVICEDLL, PhGetString(serviceDll));\n                PhDereferenceObject(serviceDll);\n            }\n            else\n            {\n                PhSetDialogItemText(hwndDlg, IDC_SERVICEDLL, L\"N/A\");\n            }\n\n            PhServicePropertiesRefreshIcon(context);\n            PhServicePropertiesRefreshControls(context);\n\n            context->Ready = TRUE;\n\n            if (PhEnableThemeSupport) // TODO: Required for compat (dmex)\n                PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport);  // HACK (GetParent)\n            else\n                PhInitializeWindowTheme(hwndDlg, FALSE);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveWindowPlacementToSetting(SETTING_SERVICE_WINDOW_POSITION, NULL, GetParent(hwndDlg));\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n                {\n                    // Workaround for property sheet + multiline edit: http://support.microsoft.com/kb/130765\n                    SendMessage(GetParent(hwndDlg), uMsg, wParam, lParam);\n                }\n                break;\n            case IDC_PASSWORD:\n                {\n                    if (HIWORD(wParam) == EN_CHANGE)\n                    {\n                        Button_SetCheck(context->PassCheckBoxWindowHandle, BST_CHECKED);\n                    }\n                }\n                break;\n            case IDC_DELAYEDSTART:\n                {\n                    context->Dirty = TRUE;\n                }\n                break;\n            case IDC_BROWSE:\n                {\n                    static PH_FILETYPE_FILTER filters[] =\n                    {\n                        { L\"Executable files (*.exe;*.sys)\", L\"*.exe;*.sys\" },\n                        { L\"All files (*.*)\", L\"*.*\" }\n                    };\n                    PVOID fileDialog;\n                    PPH_STRING commandLine;\n                    PPH_STRING fileName;\n\n                    fileDialog = PhCreateOpenFileDialog();\n                    PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters));\n\n                    commandLine = PH_AUTO_T(PH_STRING, PhGetWindowText(context->BinaryPathWindowHandle));\n\n                    if (context->ServiceItem->Type & SERVICE_WIN32)\n                    {\n                        PH_STRINGREF dummyFileName;\n                        PH_STRINGREF dummyArguments;\n\n                        if (!PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName))\n                            fileName = NULL;\n\n                        if (!fileName)\n                            PhSwapReference(&fileName, commandLine);\n                    }\n                    else\n                    {\n                        fileName = PhGetFileName(commandLine);\n                    }\n\n                    PhSetFileDialogFileName(fileDialog, PhGetString(fileName));\n                    PhDereferenceObject(fileName);\n\n                    if (PhShowFileDialog(hwndDlg, fileDialog))\n                    {\n                        fileName = PhGetFileDialogFileName(fileDialog);\n                        PhSetWindowText(context->BinaryPathWindowHandle, PhGetString(fileName));\n                        PhDereferenceObject(fileName);\n                    }\n\n                    PhFreeFileDialog(fileDialog);\n                }\n                break;\n            case IDC_PERMISSIONS:\n                {\n                    PhReferenceObject(context->ServiceItem);\n\n                    PhEditSecurityEx(\n                        PhCsForceNoParent ? NULL : hwndDlg,\n                        PhGetStringOrEmpty(context->ServiceItem->DisplayName),\n                        L\"Service\",\n                        PhpOpenServiceCallback,\n                        PhpCloseServiceCallback,\n                        NULL,\n                        PhpSetServiceSecurityCallback,\n                        context->ServiceItem\n                        );\n                }\n                break;\n            }\n\n            switch (GET_WM_COMMAND_CMD(wParam, lParam))\n            {\n            case EN_CHANGE:\n            case CBN_SELCHANGE:\n                {\n                    PhServicePropertiesRefreshControls(context);\n\n                    if (context->Ready)\n                        context->Dirty = TRUE;\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                {\n                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)context->StartTypeWindowHandle);\n                }\n                return TRUE;\n            //case PSN_KILLACTIVE:\n            //    {\n            //        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE);\n            //    }\n            //    return TRUE;\n            case PSN_APPLY:\n                {\n                    NTSTATUS status;\n                    PPH_SERVICE_ITEM serviceItem = context->ServiceItem;\n                    SC_HANDLE serviceHandle;\n                    PPH_STRING newServiceTypeString;\n                    PPH_STRING newServiceStartTypeString;\n                    PPH_STRING newServiceErrorControlString;\n                    ULONG newServiceType;\n                    ULONG newServiceStartType;\n                    ULONG newServiceErrorControl;\n                    PPH_STRING newServiceGroup = NULL;\n                    PPH_STRING newServiceBinaryPath = NULL;\n                    PPH_STRING newServiceUserAccount = NULL;\n                    PPH_STRING newServicePassword = NULL;\n\n                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);\n\n                    if (!context->Dirty)\n                    {\n                        return TRUE;\n                    }\n\n                    newServiceTypeString = PH_AUTO(PhGetWindowText(context->TypeWindowHandle));\n                    newServiceStartTypeString = PH_AUTO(PhGetWindowText(context->StartTypeWindowHandle));\n                    newServiceErrorControlString = PH_AUTO(PhGetWindowText(context->ErrorControlWindowHandle));\n                    newServiceType = PhGetServiceTypeInteger(&newServiceTypeString->sr);\n                    newServiceStartType = PhGetServiceStartTypeInteger(&newServiceStartTypeString->sr);\n                    newServiceErrorControl = PhGetServiceErrorControlInteger(&newServiceErrorControlString->sr);\n\n                    if (PhEqualStringRef(PhGetServiceTypeString(serviceItem->Type), &newServiceTypeString->sr, TRUE))\n                        newServiceType = SERVICE_NO_CHANGE;\n                    if (PhEqualStringRef(PhGetServiceStartTypeString(serviceItem->StartType), &newServiceStartTypeString->sr, TRUE))\n                        newServiceStartType = SERVICE_NO_CHANGE;\n                    if (PhEqualStringRef(PhGetServiceErrorControlString(serviceItem->ErrorControl), &newServiceErrorControlString->sr, TRUE))\n                        newServiceErrorControl = SERVICE_NO_CHANGE;\n\n                    if (PhGetWindowTextLength(context->GroupWindowHandle))\n                        newServiceGroup = PH_AUTO(PhGetWindowText(context->GroupWindowHandle));\n                    if (PhGetWindowTextLength(context->BinaryPathWindowHandle))\n                        newServiceBinaryPath = PH_AUTO(PhGetWindowText(context->BinaryPathWindowHandle));\n                    if (PhGetWindowTextLength(context->UserNameWindowHandle))\n                        newServiceUserAccount = PH_AUTO(PhGetWindowText(context->UserNameWindowHandle));\n\n                    if (Button_GetCheck(context->PassCheckBoxWindowHandle) == BST_CHECKED)\n                        newServicePassword = PhGetWindowText(context->PassBoxWindowHandle);\n\n                    status = PhOpenService(&serviceHandle, SERVICE_CHANGE_CONFIG, PhGetString(serviceItem->Name));\n\n                    if (NT_SUCCESS(status))\n                    {\n                        status = PhChangeServiceConfig(\n                            serviceHandle,\n                            newServiceType,\n                            newServiceStartType,\n                            newServiceErrorControl,\n                            PhGetString(newServiceBinaryPath),\n                            PhGetString(newServiceGroup),\n                            NULL,\n                            NULL,\n                            PhGetString(newServiceUserAccount),\n                            PhGetString(newServicePassword),\n                            NULL\n                            );\n\n                        if (NT_SUCCESS(status))\n                        {\n                            BOOLEAN newDelayedStart;\n\n                            newDelayedStart = Button_GetCheck(context->DelayedStartWindowHandle) == BST_CHECKED;\n\n                            if (newDelayedStart != context->OldDelayedStart)\n                            {\n                                PhSetServiceDelayedAutoStart(serviceHandle, newDelayedStart);\n                            }\n\n                            PhMarkNeedsConfigUpdateServiceItem(serviceItem);\n\n                            PhCloseServiceHandle(serviceHandle);\n                        }\n                        else\n                        {\n                            PhCloseServiceHandle(serviceHandle);\n                            goto ErrorCase;\n                        }\n                    }\n                    else\n                    {\n                        if (status == STATUS_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated)\n                        {\n                            // Elevate using phsvc.\n                            if (PhUiConnectToPhSvc(hwndDlg, FALSE))\n                            {\n                                status = PhSvcCallChangeServiceConfig(\n                                    PhGetString(serviceItem->Name),\n                                    newServiceType,\n                                    newServiceStartType,\n                                    newServiceErrorControl,\n                                    PhGetString(newServiceBinaryPath),\n                                    PhGetString(newServiceGroup),\n                                    NULL,\n                                    NULL,\n                                    PhGetString(newServiceUserAccount),\n                                    PhGetString(newServicePassword),\n                                    NULL\n                                    );\n\n                                if (NT_SUCCESS(status))\n                                {\n                                    BOOLEAN newDelayedStart;\n\n                                    newDelayedStart = Button_GetCheck(context->DelayedStartWindowHandle) == BST_CHECKED;\n\n                                    if (newDelayedStart != context->OldDelayedStart)\n                                    {\n                                        SERVICE_DELAYED_AUTO_START_INFO info;\n\n                                        info.fDelayedAutostart = newDelayedStart;\n                                        PhSvcCallChangeServiceConfig2(\n                                            PhGetString(serviceItem->Name),\n                                            SERVICE_CONFIG_DELAYED_AUTO_START_INFO,\n                                            &info\n                                            );\n                                    }\n\n                                    PhMarkNeedsConfigUpdateServiceItem(serviceItem);\n                                }\n\n                                PhUiDisconnectFromPhSvc();\n\n                                if (!NT_SUCCESS(status))\n                                {\n                                    goto ErrorCase;\n                                }\n                            }\n                            else\n                            {\n                                // User cancelled elevation.\n                                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);\n                            }\n                        }\n                        else\n                        {\n                            goto ErrorCase;\n                        }\n                    }\n\n                    goto Cleanup;\nErrorCase:\n\n                    PhShowStatus(hwndDlg, L\"Unable to change service configuration.\", status, 0);\n                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);\n\nCleanup:\n                    if (newServicePassword)\n                    {\n                        RtlSecureZeroMemory(newServicePassword->Buffer, newServicePassword->Length);\n                        PhDereferenceObject(newServicePassword);\n                    }\n                }\n                return TRUE;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/srvprv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2015\n *     dmex    2017-2024\n *\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <srvprv.h>\n#include <svcsup.h>\n#include <workqueue.h>\n#include <extmgri.h>\n#include <procprv.h>\n#include <phsettings.h>\n#include <apiimport.h>\n#include <mapldr.h>\n\n#include <trace.h>\n\ntypedef struct _PHP_SERVICE_NAME_ENTRY\n{\n    PH_HASH_ENTRY HashEntry;\n    PH_STRINGREF Name;\n    ENUM_SERVICE_STATUS_PROCESS *ServiceEntry;\n} PHP_SERVICE_NAME_ENTRY, *PPHP_SERVICE_NAME_ENTRY;\n\ntypedef enum _PHP_SERVICE_NOTIFY_STATE\n{\n    SnNone,\n    SnAdding,\n    SnRemoving,\n    SnNotify\n} PHP_SERVICE_NOTIFY_STATE;\n\ntypedef struct _PHP_SERVICE_NOTIFY_CONTEXT\n{\n    LIST_ENTRY ListEntry;\n    SC_HANDLE ServiceHandle;\n    PPH_STRING ServiceName;\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN IsServiceManager : 1;\n            BOOLEAN NonPollDisabled : 1;\n            BOOLEAN Spare : 6;\n        };\n    };\n    PHP_SERVICE_NOTIFY_STATE State;\n    SERVICE_NOTIFY Buffer;\n} PHP_SERVICE_NOTIFY_CONTEXT, *PPHP_SERVICE_NOTIFY_CONTEXT;\n\ntypedef struct _PH_SERVICE_QUERY_DATA\n{\n    SLIST_ENTRY ListEntry;\n    ULONG Stage;\n    PPH_SERVICE_ITEM ServiceItem;\n    PPH_STRING FileName;\n} PH_SERVICE_QUERY_DATA, *PPH_SERVICE_QUERY_DATA;\n\ntypedef struct _PH_SERVICE_QUERY_S1_DATA\n{\n    PH_SERVICE_QUERY_DATA Header;\n\n    PPH_IMAGELIST_ITEM IconEntry;\n    //PH_IMAGE_VERSION_INFO VersionInfo;\n    BOOLEAN MicrosoftService;\n} PH_SERVICE_QUERY_S1_DATA, *PPH_SERVICE_QUERY_S1_DATA;\n\ntypedef struct _PH_SERVICE_QUERY_S2_DATA\n{\n    PH_SERVICE_QUERY_DATA Header;\n\n    VERIFY_RESULT VerifyResult;\n    PPH_STRING VerifySignerName;\n    BOOLEAN MicrosoftService;\n} PH_SERVICE_QUERY_S2_DATA, *PPH_SERVICE_QUERY_S2_DATA;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpServiceItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PhpServiceHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpServiceHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\nVOID PhAddProcessItemService(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    );\n\nVOID PhRemoveProcessItemService(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    );\n\nVOID PhInitializeServiceNonPoll(\n    VOID\n    );\n\nVOID PhCreateServiceNotifyCallback(\n    _In_ PPH_SERVICE_ITEM ServiceItem,\n    _In_ SC_HANDLE ServiceHandle\n    );\nVOID PhDestroyServiceNotifyCallback(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    );\n\nPPH_OBJECT_TYPE PhServiceItemType = NULL;\nPPH_HASHTABLE PhServiceHashtable = NULL;\nPH_QUEUED_LOCK PhServiceHashtableLock = PH_QUEUED_LOCK_INIT;\n\nBOOLEAN PhEnableServiceNonPoll = FALSE;\nBOOLEAN PhEnableServiceNonPollNotify = FALSE;\nULONG PhServiceNonPollFlushInterval = 10;\nstatic BOOLEAN PhNonPollActive = FALSE;\nstatic volatile LONG PhNonPollGate = 0;\nstatic HANDLE PhNonPollEventHandle = NULL;\nstatic RTL_STATIC_LIST_HEAD(PhpNonPollServiceListHead);\nstatic RTL_STATIC_LIST_HEAD(PhpNonPollServicePendingListHead);\nstatic SLIST_HEADER PhpServiceQueryDataListHead;\nstatic typeof(&NotifyServiceStatusChangeW) NotifyServiceStatusChange_I = NULL;\nstatic typeof(&SubscribeServiceChangeNotifications) SubscribeServiceChangeNotifications_I = NULL;\nstatic typeof(&UnsubscribeServiceChangeNotifications) UnsubscribeServiceChangeNotifications_I = NULL;\n\nBOOLEAN PhServiceProviderInitialization(\n    VOID\n    )\n{\n    PhServiceItemType = PhCreateObjectType(L\"ServiceItem\", 0, PhpServiceItemDeleteProcedure);\n    PhServiceHashtable = PhCreateHashtable(\n        sizeof(PPH_SERVICE_ITEM),\n        PhpServiceHashtableEqualFunction,\n        PhpServiceHashtableHashFunction,\n        40\n        );\n\n    PhInitializeSListHead(&PhpServiceQueryDataListHead);\n\n    if (PhEnableServiceNonPoll)\n    {\n        PhInitializeServiceNonPoll();\n    }\n\n    return TRUE;\n}\n\nPPH_SERVICE_ITEM PhCreateServiceItem(\n    _In_opt_ LPENUM_SERVICE_STATUS_PROCESS Information\n    )\n{\n    PPH_SERVICE_ITEM serviceItem;\n\n    serviceItem = PhCreateObject(\n        PhEmGetObjectSize(EmServiceItemType, sizeof(PH_SERVICE_ITEM)),\n        PhServiceItemType\n        );\n    memset(serviceItem, 0, sizeof(PH_SERVICE_ITEM));\n\n    if (Information)\n    {\n        serviceItem->Name = PhCreateString(Information->lpServiceName);\n        serviceItem->Key = serviceItem->Name->sr;\n        serviceItem->DisplayName = PhCreateString(Information->lpDisplayName);\n        serviceItem->Type = Information->ServiceStatusProcess.dwServiceType;\n        serviceItem->State = Information->ServiceStatusProcess.dwCurrentState;\n        serviceItem->ControlsAccepted = Information->ServiceStatusProcess.dwControlsAccepted;\n        serviceItem->Win32ExitCode = Information->ServiceStatusProcess.dwWin32ExitCode;\n        serviceItem->ServiceSpecificExitCode = Information->ServiceStatusProcess.dwServiceSpecificExitCode;\n        serviceItem->Flags = Information->ServiceStatusProcess.dwServiceFlags;\n        serviceItem->ProcessId = UlongToHandle(Information->ServiceStatusProcess.dwProcessId);\n\n        if (PH_IS_REAL_PROCESS_ID(serviceItem->ProcessId))\n        {\n            PhPrintUInt32(serviceItem->ProcessIdString, HandleToUlong(serviceItem->ProcessId));\n        }\n    }\n\n    PhEmCallObjectOperation(EmServiceItemType, serviceItem, EmObjectCreate);\n\n    return serviceItem;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpServiceItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Object;\n\n    PhEmCallObjectOperation(EmServiceItemType, serviceItem, EmObjectDelete);\n\n    if (serviceItem->Name) PhDereferenceObject(serviceItem->Name);\n    if (serviceItem->DisplayName) PhDereferenceObject(serviceItem->DisplayName);\n    if (serviceItem->FileName) PhDereferenceObject(serviceItem->FileName);\n    if (serviceItem->VerifySignerName) PhDereferenceObject(serviceItem->VerifySignerName);\n    if (serviceItem->IconEntry) PhDereferenceObject(serviceItem->IconEntry);\n    //PhDeleteImageVersionInfo(&serviceItem->VersionInfo);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpServiceHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)Entry1;\n    PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)Entry2;\n\n    return PhEqualStringRef(&serviceItem1->Key, &serviceItem2->Key, TRUE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpServiceHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = *(PPH_SERVICE_ITEM *)Entry;\n\n    return PhHashStringRefEx(&serviceItem->Key, TRUE, PH_STRING_HASH_X65599);\n}\n\nPPH_SERVICE_ITEM PhpLookupServiceItem(\n    _In_ PPH_STRINGREF Name\n    )\n{\n    PH_SERVICE_ITEM lookupServiceItem;\n    PPH_SERVICE_ITEM lookupServiceItemPtr = &lookupServiceItem;\n    PPH_SERVICE_ITEM *serviceItem;\n\n    // Construct a temporary service item for the lookup.\n    lookupServiceItem.Key = *Name;\n\n    serviceItem = (PPH_SERVICE_ITEM *)PhFindEntryHashtable(\n        PhServiceHashtable,\n        &lookupServiceItemPtr\n        );\n\n    if (serviceItem)\n        return *serviceItem;\n    else\n        return NULL;\n}\n\nPPH_SERVICE_ITEM PhReferenceServiceItem(\n    _In_ PPH_STRINGREF Name\n    )\n{\n    PPH_SERVICE_ITEM serviceItem;\n\n    PhAcquireQueuedLockShared(&PhServiceHashtableLock);\n\n    serviceItem = PhpLookupServiceItem(Name);\n\n    if (serviceItem)\n        PhReferenceObject(serviceItem);\n\n    PhReleaseQueuedLockShared(&PhServiceHashtableLock);\n\n    return serviceItem;\n}\n\nVOID PhpResetServiceNonPollGate(\n    VOID\n    )\n{\n    if (PhEnableServiceNonPoll)\n    {\n        InterlockedExchange(&PhNonPollGate, TRUE);\n    }\n}\n\nVOID PhMarkNeedsConfigUpdateServiceItem(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    ServiceItem->NeedsConfigUpdate = TRUE;\n\n    PhpResetServiceNonPollGate();\n}\n\nVOID PhpRemoveServiceItem(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    PhRemoveEntryHashtable(PhServiceHashtable, &ServiceItem);\n\n    PhDestroyServiceNotifyCallback(ServiceItem);\n\n    PhDereferenceObject(ServiceItem);\n}\n\nPH_SERVICE_CHANGE PhGetServiceChange(\n    _In_ PPH_SERVICE_MODIFIED_DATA Data\n    )\n{\n    if (\n        (\n        Data->OldService.State == SERVICE_STOPPED ||\n        Data->OldService.State == SERVICE_START_PENDING\n        ) &&\n        Data->ServiceItem->State == SERVICE_RUNNING\n        )\n    {\n        return ServiceStarted;\n    }\n\n    if (\n        (\n        Data->OldService.State == SERVICE_PAUSED ||\n        Data->OldService.State == SERVICE_CONTINUE_PENDING\n        ) &&\n        Data->ServiceItem->State == SERVICE_RUNNING\n        )\n    {\n        return ServiceContinued;\n    }\n\n    if (\n        (\n        Data->OldService.State == SERVICE_RUNNING ||\n        Data->OldService.State == SERVICE_PAUSE_PENDING\n        ) &&\n        Data->ServiceItem->State == SERVICE_PAUSED\n        )\n    {\n        return ServicePaused;\n    }\n\n    if (\n        (\n        Data->OldService.State == SERVICE_RUNNING ||\n        Data->OldService.State == SERVICE_STOP_PENDING\n        ) &&\n        Data->ServiceItem->State == SERVICE_STOPPED\n        )\n    {\n        return ServiceStopped;\n    }\n\n    // TODO: ServiceModified (dmex)\n\n    return ULONG_MAX;\n}\n\nVOID PhUpdateProcessItemServices(\n    _In_ PPH_PROCESS_ITEM ProcessItem\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SERVICE_ITEM *serviceItem;\n\n    // We don't need to lock as long as the service provider\n    // never runs concurrently with the process provider. This\n    // is currently true. (wj32)\n\n    // Starting 2022 the service provider runs concurrently with\n    // the process provider and now requires locking. If the service\n    // provider is moved back to the primary provider thread then\n    // remove these locks per the above comments (dmex)\n\n    PhAcquireQueuedLockShared(&PhServiceHashtableLock);\n\n    PhBeginEnumHashtable(PhServiceHashtable, &enumContext);\n\n    while (serviceItem = PhNextEnumHashtable(&enumContext))\n    {\n        if (\n            (*serviceItem)->PendingProcess &&\n            (*serviceItem)->ProcessId == ProcessItem->ProcessId\n            )\n        {\n            PhAddProcessItemService(ProcessItem, *serviceItem);\n        }\n    }\n\n    PhReleaseQueuedLockShared(&PhServiceHashtableLock);\n}\n\nVOID PhAddProcessItemService(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    PhAcquireQueuedLockExclusive(&ProcessItem->ServiceListLock);\n\n    if (!ProcessItem->ServiceList)\n        ProcessItem->ServiceList = PhCreatePointerList(2);\n\n    if (!PhFindItemPointerList(ProcessItem->ServiceList, ServiceItem))\n    {\n        PhReferenceObject(ServiceItem);\n        PhAddItemPointerList(ProcessItem->ServiceList, ServiceItem);\n    }\n\n    PhReleaseQueuedLockExclusive(&ProcessItem->ServiceListLock);\n\n    ServiceItem->PendingProcess = FALSE;\n    InterlockedExchange(&ProcessItem->JustProcessed, TRUE);\n}\n\nVOID PhRemoveProcessItemService(\n    _In_ PPH_PROCESS_ITEM ProcessItem,\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    HANDLE pointerHandle;\n\n    if (!ProcessItem->ServiceList)\n        return;\n\n    PhAcquireQueuedLockExclusive(&ProcessItem->ServiceListLock);\n\n    if (pointerHandle = PhFindItemPointerList(ProcessItem->ServiceList, ServiceItem))\n    {\n        PhRemoveItemPointerList(ProcessItem->ServiceList, pointerHandle);\n        PhDereferenceObject(ServiceItem);\n    }\n\n    PhReleaseQueuedLockExclusive(&ProcessItem->ServiceListLock);\n\n    InterlockedExchange(&ProcessItem->JustProcessed, TRUE);\n}\n\nstatic BOOLEAN PhCompareServiceNameEntry(\n    _In_ PPHP_SERVICE_NAME_ENTRY Value1,\n    _In_ PPHP_SERVICE_NAME_ENTRY Value2\n    )\n{\n    return PhEqualStringRef(&Value1->Name, &Value2->Name, TRUE);\n}\n\nstatic ULONG PhHashServiceNameEntry(\n    _In_ PPHP_SERVICE_NAME_ENTRY Value\n    )\n{\n    return PhHashStringRefEx(&Value->Name, TRUE, PH_STRING_HASH_XXH32);\n}\n\nVOID PhServiceQueryStage1(\n    _Inout_ PPH_SERVICE_QUERY_S1_DATA Data\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = Data->Header.ServiceItem;\n    PPH_STRING fileName = Data->Header.FileName;\n\n    if (fileName)\n    {\n        if (!FlagOn(serviceItem->Type, SERVICE_DRIVER)) // Skip icons for kernel drivers (dmex)\n        {\n            Data->IconEntry = PhImageListExtractIcon(fileName, FALSE, SYSTEM_IDLE_PROCESS_ID, NULL, PhSystemDpi);\n        }\n\n        if (!PhEnableProcessQueryStage2)\n        {\n            PH_IMAGE_VERSION_INFO versionInfo;\n            PPH_STRING nativeFilename;\n\n            if (nativeFilename = PhDosPathNameToNtPathName(&fileName->sr))\n            {\n                if (NT_SUCCESS(PhInitializeImageVersionInfoCached(\n                    &versionInfo, // Data->VersionInfo\n                    nativeFilename,\n                    FALSE,\n                    !!PhCsEnableVersionSupport\n                    )))\n                {\n                    // Note: This is how msconfig determines default services. (dmex)\n                    if (versionInfo.CompanyName && PhStartsWithStringRef2(&versionInfo.CompanyName->sr, L\"Microsoft\", TRUE))\n                    {\n                        Data->MicrosoftService = TRUE;\n                    }\n\n                    PhDeleteImageVersionInfo(&versionInfo);\n                }\n\n                PhDereferenceObject(nativeFilename);\n            }\n        }\n    }\n}\n\nVOID PhServiceQueryStage2(\n    _Inout_ PPH_SERVICE_QUERY_S2_DATA Data\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = Data->Header.ServiceItem;\n    PPH_STRING fileName = Data->Header.FileName;\n\n    if (fileName)\n    {\n        Data->VerifyResult = PhVerifyFileCached(\n            fileName,\n            NULL,\n            &Data->VerifySignerName,\n            FALSE,\n            FALSE\n            );\n\n        if (!PhIsNullOrEmptyString(Data->VerifySignerName))\n        {\n            static CONST PH_STRINGREF microsoftSignerNameSr = PH_STRINGREF_INIT(L\"Microsoft Windows\");\n\n            if (PhEqualStringRef(&Data->VerifySignerName->sr, &microsoftSignerNameSr, TRUE))\n            {\n                Data->MicrosoftService = TRUE;\n            }\n        }\n    }\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpServiceQueryStage1Worker(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_SERVICE_QUERY_S1_DATA data = Parameter;\n\n    PhServiceQueryStage1(data);\n\n    RtlInterlockedPushEntrySList(&PhpServiceQueryDataListHead, &data->Header.ListEntry);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpServiceQueryStage2Worker(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_SERVICE_QUERY_S2_DATA data = Parameter;\n\n    PhServiceQueryStage2(data);\n\n    RtlInterlockedPushEntrySList(&PhpServiceQueryDataListHead, &data->Header.ListEntry);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhQueueServiceQueryStage1(\n    _Inout_ PPH_SERVICE_QUERY_S1_DATA Data\n    )\n{\n    PH_WORK_QUEUE_ENVIRONMENT environment;\n\n    PhInitializeWorkQueueEnvironment(&environment);\n    environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL;\n    environment.IoPriority = IoPriorityLow;\n    environment.PagePriority = MEMORY_PRIORITY_LOW;\n\n    PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpServiceQueryStage1Worker, Data, NULL, &environment);\n}\n\nVOID PhQueueServiceQueryStage2(\n    _Inout_ PPH_SERVICE_QUERY_S2_DATA Data\n    )\n{\n    PH_WORK_QUEUE_ENVIRONMENT environment;\n\n    PhInitializeWorkQueueEnvironment(&environment);\n    environment.BasePriority = THREAD_PRIORITY_LOWEST;\n    environment.IoPriority = IoPriorityVeryLow;\n    environment.PagePriority = MEMORY_PRIORITY_VERY_LOW;\n\n    PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpServiceQueryStage2Worker, Data, NULL, &environment);\n}\n\nVOID PhCreateQueueServiceQueryStage2(\n    _In_ PPH_SERVICE_ITEM ServiceItem,\n    _In_ PPH_STRING FileName\n    )\n{\n    PPH_SERVICE_QUERY_S2_DATA data;\n\n    ServiceItem->VerifyResult = 0;\n    PhClearReference(&ServiceItem->VerifySignerName);\n\n    data = PhAllocateZero(sizeof(PH_SERVICE_QUERY_S2_DATA));\n    data->Header.Stage = 2;\n    PhSetReference(&data->Header.ServiceItem, ServiceItem);\n    PhSetReference(&data->Header.FileName, FileName);\n\n    PhQueueServiceQueryStage2(data);\n}\n\nVOID PhpFillServiceItemStage1(\n    _In_ PPH_SERVICE_QUERY_S1_DATA Data\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = Data->Header.ServiceItem;\n    PPH_STRING fileName = Data->Header.FileName;\n\n    PhTrace(\"Service query stage 1: %ls\", PhGetString(serviceItem->Name));\n\n    serviceItem->IconEntry = Data->IconEntry;\n    //memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO));\n    serviceItem->MicrosoftService = !!Data->MicrosoftService;\n\n    // Note: Queue stage 2 processing after filling stage1 process data.\n\n    if (PhEnableServiceQueryStage2)\n    {\n        PhCreateQueueServiceQueryStage2(serviceItem, fileName);\n    }\n}\n\nVOID PhpFillServiceItemStage2(\n    _In_ PPH_SERVICE_QUERY_S2_DATA Data\n    )\n{\n    PPH_SERVICE_ITEM serviceItem = Data->Header.ServiceItem;\n\n    PhTrace(\"Service query stage 2: %ls\", PhGetString(serviceItem->Name));\n\n    serviceItem->VerifyResult = Data->VerifyResult;\n    PhMoveReference(&serviceItem->VerifySignerName, Data->VerifySignerName);\n    serviceItem->MicrosoftService = !!Data->MicrosoftService;\n}\n\nVOID PhFlushServiceQueryData(\n    VOID\n    )\n{\n    PSLIST_ENTRY entry;\n    PPH_SERVICE_QUERY_DATA data;\n\n    //if (!RtlFirstEntrySList(&PhpServiceQueryDataListHead))\n    //    return;\n\n    entry = RtlInterlockedFlushSList(&PhpServiceQueryDataListHead);\n\n    while (entry)\n    {\n        data = CONTAINING_RECORD(entry, PH_SERVICE_QUERY_DATA, ListEntry);\n        entry = entry->Next;\n\n        if (data->Stage == 1)\n        {\n            PhpFillServiceItemStage1((PPH_SERVICE_QUERY_S1_DATA)data);\n        }\n        else if (data->Stage == 2)\n        {\n            PhpFillServiceItemStage2((PPH_SERVICE_QUERY_S2_DATA)data);\n        }\n\n        InterlockedExchange(&data->ServiceItem->JustProcessed, TRUE);\n\n        if (data->FileName) PhDereferenceObject(data->FileName);\n        PhDereferenceObject(data->ServiceItem);\n        PhFree(data);\n    }\n}\n\nVOID PhUpdateServiceItemConfig(\n    _In_ PPH_SERVICE_ITEM ServiceItem,\n    _In_ BOOLEAN CreateServiceNotifyCallback\n    )\n{\n    NTSTATUS status;\n    SC_HANDLE serviceHandle;\n    LPQUERY_SERVICE_CONFIG config;\n    BOOLEAN delayedAutoStartInfo;\n\n    status = PhOpenService(\n        &serviceHandle,\n        SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG,\n        PhGetString(ServiceItem->Name)\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        status = PhOpenService(\n            &serviceHandle,\n            SERVICE_QUERY_CONFIG,\n            PhGetString(ServiceItem->Name)\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return;\n\n    if (NT_SUCCESS(PhGetServiceConfig(serviceHandle, &config)))\n    {\n        ServiceItem->StartType = config->dwStartType;\n        ServiceItem->ErrorControl = config->dwErrorControl;\n\n        {\n            PPH_STRING fileName;\n\n            fileName = PhGetServiceConfigFileName(\n                config->dwServiceType,\n                config->lpBinaryPathName,\n                &ServiceItem->Name->sr\n                );\n\n            if (fileName && ServiceItem->FileName && !PhEqualStringRef(&fileName->sr, &ServiceItem->FileName->sr, TRUE))\n            {\n                if (PhEnableServiceQueryStage2)\n                {\n                    PhCreateQueueServiceQueryStage2(ServiceItem, fileName);\n                }\n            }\n\n            PhMoveReference(&ServiceItem->FileName, fileName);\n        }\n\n        PhFree(config);\n    }\n\n    if (NT_SUCCESS(PhGetServiceDelayedAutoStart(serviceHandle, &delayedAutoStartInfo)))\n        ServiceItem->DelayedStart = delayedAutoStartInfo;\n    else\n        ServiceItem->DelayedStart = FALSE;\n\n    if (NT_SUCCESS(PhGetServiceTriggerInfo(serviceHandle, NULL)))\n        ServiceItem->HasTriggers = TRUE;\n    else\n        ServiceItem->HasTriggers = FALSE;\n\n    if (CreateServiceNotifyCallback)\n    {\n        PhCreateServiceNotifyCallback(ServiceItem, serviceHandle);\n    }\n\n    PhCloseServiceHandle(serviceHandle);\n}\n\n_Function_class_(PH_PROVIDER_FUNCTION)\nVOID PhServiceProviderUpdate(\n    _In_ PVOID Object\n    )\n{\n    static ULONG runCount = 0;\n    static PPH_HASH_ENTRY nameHashSet[256];\n    static PPHP_SERVICE_NAME_ENTRY nameEntries = NULL;\n    static ULONG nameEntriesCount;\n    static ULONG nameEntriesAllocated = 0;\n    NTSTATUS status;\n    LPENUM_SERVICE_STATUS_PROCESS services;\n    ULONG numberOfServices;\n    ULONG i;\n    PPH_HASH_ENTRY hashEntry;\n\n    PhTraceFuncEnter(\"Service provider run count: %lu\", runCount);\n\n    // We always execute the first run, and we only initialize non-polling after the first run.\n    if (PhEnableServiceNonPoll && runCount != 0)\n    {\n        if (PhNonPollActive)\n        {\n            if (InterlockedExchange(&PhNonPollGate, 0) == 0)\n            {\n                // The SCM doesn't generate notifications for drivers. So flush service\n                // information once in a while so we can detect driver events. (dmex)\n                if (runCount % PhServiceNonPollFlushInterval == 0)\n                {\n                    // Go through the queued services query data.\n                    PhFlushServiceQueryData();\n                    goto UpdateStart;\n                }\n\n                // Non-poll gate is closed; skip all processing.\n                goto UpdateEnd;\n            }\n        }\n    }\n\nUpdateStart:\n\n    if (!NT_SUCCESS(status = PhEnumServices(&services, &numberOfServices)))\n    {\n        PhTraceFuncExit(\"Failed to enumerate services: %lu %!STATUS!\", runCount, status);\n        return;\n    }\n\n    // Build a hash set containing the service names.\n\n    // This has caused a massive decrease in background CPU usage, and\n    // is certainly much better than the quadratic-time string comparisons\n    // we were doing before (in the \"Look for dead services\" section). (wj32)\n\n    nameEntriesCount = 0;\n\n    if (nameEntriesAllocated < numberOfServices)\n    {\n        nameEntriesAllocated = numberOfServices + 32;\n\n        if (nameEntries) PhFree(nameEntries);\n        nameEntries = PhAllocate(sizeof(PHP_SERVICE_NAME_ENTRY) * nameEntriesAllocated);\n    }\n\n    PhInitializeHashSet(nameHashSet, PH_HASH_SET_SIZE(nameHashSet));\n\n    for (i = 0; i < numberOfServices; i++)\n    {\n        PPHP_SERVICE_NAME_ENTRY entry;\n\n        entry = &nameEntries[nameEntriesCount++];\n        PhInitializeStringRefLongHint(&entry->Name, services[i].lpServiceName);\n        entry->ServiceEntry = &services[i];\n\n        if (WindowsVersion >= WINDOWS_10_RS2)\n        {\n            PhServiceWorkaroundWindowsServiceTypeBug(entry->ServiceEntry);\n        }\n\n        PhAddEntryHashSet(\n            nameHashSet,\n            PH_HASH_SET_SIZE(nameHashSet),\n            &entry->HashEntry,\n            PhHashServiceNameEntry(entry)\n            );\n    }\n\n    // Go through the queued services query data.\n    PhFlushServiceQueryData();\n\n    // Look for dead services.\n    {\n        PPH_LIST servicesToRemove = NULL;\n        PH_HASHTABLE_ENUM_CONTEXT enumContext;\n        PPH_SERVICE_ITEM *serviceItem;\n\n        PhBeginEnumHashtable(PhServiceHashtable, &enumContext);\n\n        while (serviceItem = PhNextEnumHashtable(&enumContext))\n        {\n            BOOLEAN found = FALSE;\n            PHP_SERVICE_NAME_ENTRY lookupNameEntry;\n\n            // Check if the service still exists.\n\n            lookupNameEntry.Name = (*serviceItem)->Name->sr;\n            hashEntry = PhFindEntryHashSet(\n                nameHashSet,\n                PH_HASH_SET_SIZE(nameHashSet),\n                PhHashServiceNameEntry(&lookupNameEntry)\n                );\n\n            for (; hashEntry; hashEntry = hashEntry->Next)\n            {\n                PPHP_SERVICE_NAME_ENTRY nameEntry;\n\n                nameEntry = CONTAINING_RECORD(hashEntry, PHP_SERVICE_NAME_ENTRY, HashEntry);\n\n                if (PhCompareServiceNameEntry(&lookupNameEntry, nameEntry))\n                {\n                    found = TRUE;\n                    break;\n                }\n            }\n\n            if (!found)\n            {\n                // Remove the service from its process.\n                if ((*serviceItem)->ProcessId)\n                {\n                    PPH_PROCESS_ITEM processItem;\n\n                    processItem = PhReferenceProcessItem((*serviceItem)->ProcessId);\n\n                    if (processItem)\n                    {\n                        PhRemoveProcessItemService(processItem, *serviceItem);\n                        PhDereferenceObject(processItem);\n                    }\n                }\n\n                // Raise the service removed event.\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderRemovedEvent), *serviceItem);\n\n                if (!servicesToRemove)\n                    servicesToRemove = PhCreateList(2);\n\n                PhAddItemList(servicesToRemove, *serviceItem);\n            }\n        }\n\n        if (servicesToRemove)\n        {\n            PhAcquireQueuedLockExclusive(&PhServiceHashtableLock);\n\n            for (i = 0; i < servicesToRemove->Count; i++)\n            {\n                PhpRemoveServiceItem((PPH_SERVICE_ITEM)servicesToRemove->Items[i]);\n            }\n\n            PhReleaseQueuedLockExclusive(&PhServiceHashtableLock);\n            PhDereferenceObject(servicesToRemove);\n        }\n    }\n\n    // Look for new services and update existing ones.\n    for (i = 0; i < PH_HASH_SET_SIZE(nameHashSet); i++)\n    {\n        for (hashEntry = nameHashSet[i]; hashEntry; hashEntry = hashEntry->Next)\n        {\n            PPH_SERVICE_ITEM serviceItem;\n            PPHP_SERVICE_NAME_ENTRY nameEntry;\n            ENUM_SERVICE_STATUS_PROCESS *serviceEntry;\n\n            nameEntry = CONTAINING_RECORD(hashEntry, PHP_SERVICE_NAME_ENTRY, HashEntry);\n            serviceEntry = nameEntry->ServiceEntry;\n            serviceItem = PhpLookupServiceItem(&nameEntry->Name);\n\n            if (!serviceItem)\n            {\n                // Create the service item and fill in basic information.\n\n                serviceItem = PhCreateServiceItem(serviceEntry);\n                PhUpdateServiceItemConfig(serviceItem, TRUE);\n\n                // Add the service to its process, if appropriate.\n                if (serviceItem->ProcessId)\n                {\n                    PPH_PROCESS_ITEM processItem;\n\n                    if (processItem = PhReferenceProcessItem(serviceItem->ProcessId))\n                    {\n                        PhAddProcessItemService(processItem, serviceItem);\n                        PhDereferenceObject(processItem);\n                    }\n                    else\n                    {\n                        // The process doesn't exist yet (to us). Set the pending\n                        // flag and when the process is added this will be\n                        // fixed. (wj32)\n                        serviceItem->PendingProcess = TRUE;\n                    }\n                }\n\n                // If this is the first run of the provider, queue the\n                // process query tasks. Otherwise, perform stage 1\n                // processing now and queue stage 2 processing. (wj32)\n                if (runCount > 0)\n                {\n                    PH_SERVICE_QUERY_S1_DATA data;\n\n                    memset(&data, 0, sizeof(PH_SERVICE_QUERY_S1_DATA));\n                    data.Header.Stage = 1;\n                    data.Header.ServiceItem = serviceItem;\n                    data.Header.FileName = serviceItem->FileName;\n\n                    PhServiceQueryStage1(&data);\n                    PhpFillServiceItemStage1(&data);\n                }\n                else\n                {\n                    PPH_SERVICE_QUERY_S1_DATA data;\n\n                    data = PhAllocateZero(sizeof(PH_SERVICE_QUERY_S1_DATA));\n                    data->Header.Stage = 1;\n                    PhSetReference(&data->Header.ServiceItem, serviceItem);\n                    PhSetReference(&data->Header.FileName, serviceItem->FileName);\n\n                    PhQueueServiceQueryStage1(data);\n                }\n\n                // Add the service item to the hashtable.\n                PhAcquireQueuedLockExclusive(&PhServiceHashtableLock);\n                PhAddEntryHashtable(PhServiceHashtable, &serviceItem);\n                PhReleaseQueuedLockExclusive(&PhServiceHashtableLock);\n\n                // Raise the service added event.\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderAddedEvent), serviceItem);\n            }\n            else\n            {\n                if (\n                    serviceItem->Type != serviceEntry->ServiceStatusProcess.dwServiceType ||\n                    serviceItem->State != serviceEntry->ServiceStatusProcess.dwCurrentState ||\n                    serviceItem->ControlsAccepted != serviceEntry->ServiceStatusProcess.dwControlsAccepted ||\n                    serviceItem->Win32ExitCode != serviceEntry->ServiceStatusProcess.dwWin32ExitCode ||\n                    serviceItem->ServiceSpecificExitCode != serviceEntry->ServiceStatusProcess.dwServiceSpecificExitCode ||\n                    serviceItem->ProcessId != UlongToHandle(serviceEntry->ServiceStatusProcess.dwProcessId) ||\n                    serviceItem->NeedsConfigUpdate ||\n                    serviceItem->JustProcessed\n                    )\n                {\n                    PH_SERVICE_MODIFIED_DATA serviceModifiedData;\n                    PH_SERVICE_CHANGE serviceChange;\n\n                    // The service has been \"modified\".\n\n                    serviceModifiedData.ServiceItem = serviceItem;\n                    memset(&serviceModifiedData.OldService, 0, sizeof(PH_SERVICE_ITEM));\n                    serviceModifiedData.OldService.Type = serviceItem->Type;\n                    serviceModifiedData.OldService.State = serviceItem->State;\n                    serviceModifiedData.OldService.ControlsAccepted = serviceItem->ControlsAccepted;\n                    serviceModifiedData.OldService.ProcessId = serviceItem->ProcessId;\n\n                    // Update the service item.\n                    serviceItem->Type = serviceEntry->ServiceStatusProcess.dwServiceType;\n                    serviceItem->State = serviceEntry->ServiceStatusProcess.dwCurrentState;\n                    serviceItem->ControlsAccepted = serviceEntry->ServiceStatusProcess.dwControlsAccepted;\n                    serviceItem->Win32ExitCode = serviceEntry->ServiceStatusProcess.dwWin32ExitCode;\n                    serviceItem->ServiceSpecificExitCode = serviceEntry->ServiceStatusProcess.dwServiceSpecificExitCode;\n                    serviceItem->ProcessId = UlongToHandle(serviceEntry->ServiceStatusProcess.dwProcessId);\n\n                    if (PH_IS_REAL_PROCESS_ID(serviceItem->ProcessId))\n                        PhPrintUInt32(serviceItem->ProcessIdString, HandleToUlong(serviceItem->ProcessId));\n                    else\n                        serviceItem->ProcessIdString[0] = UNICODE_NULL;\n\n                    // Add/remove the service from its process.\n\n                    serviceChange = PhGetServiceChange(&serviceModifiedData);\n\n                    if (\n                        (serviceChange == ServiceStarted && serviceItem->ProcessId) ||\n                        (serviceChange == ServiceStopped && serviceModifiedData.OldService.ProcessId)\n                        )\n                    {\n                        PPH_PROCESS_ITEM processItem;\n\n                        if (serviceChange == ServiceStarted)\n                            processItem = PhReferenceProcessItem(serviceItem->ProcessId);\n                        else\n                            processItem = PhReferenceProcessItem(serviceModifiedData.OldService.ProcessId);\n\n                        if (processItem)\n                        {\n                            if (serviceChange == ServiceStarted)\n                                PhAddProcessItemService(processItem, serviceItem);\n                            else\n                                PhRemoveProcessItemService(processItem, serviceItem);\n\n                            PhDereferenceObject(processItem);\n                        }\n                        else\n                        {\n                            if (serviceChange == ServiceStarted)\n                                serviceItem->PendingProcess = TRUE;\n                            else\n                                serviceItem->PendingProcess = FALSE;\n                        }\n                    }\n                    else if (\n                        serviceItem->State == SERVICE_RUNNING &&\n                        serviceItem->ProcessId != serviceModifiedData.OldService.ProcessId &&\n                        serviceItem->ProcessId\n                        )\n                    {\n                        PPH_PROCESS_ITEM processItem;\n\n                        // The service stopped and started, and the only change we have detected\n                        // is in the process ID. (wj32)\n\n                        if (processItem = PhReferenceProcessItem(serviceModifiedData.OldService.ProcessId))\n                        {\n                            PhRemoveProcessItemService(processItem, serviceItem);\n                            PhDereferenceObject(processItem);\n                        }\n\n                        if (processItem = PhReferenceProcessItem(serviceItem->ProcessId))\n                        {\n                            PhAddProcessItemService(processItem, serviceItem);\n                            PhDereferenceObject(processItem);\n                        }\n                        else\n                        {\n                            serviceItem->PendingProcess = TRUE;\n                        }\n                    }\n\n                    // Do a config update if necessary.\n                    if (serviceItem->NeedsConfigUpdate)\n                    {\n                        PhUpdateServiceItemConfig(serviceItem, FALSE);\n                        serviceItem->NeedsConfigUpdate = FALSE;\n                    }\n\n                    InterlockedExchange(&serviceItem->JustProcessed, FALSE);\n\n                    // Raise the service modified event.\n                    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent), &serviceModifiedData);\n                }\n            }\n        }\n    }\n\n    PhFree(services);\n\nUpdateEnd:\n    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderUpdatedEvent), UlongToPtr(runCount));\n\n    PhTraceFuncExit(\"Service provider run count: %lu\", runCount);\n\n    runCount++;\n}\n\nVOID CALLBACK PhServiceNotifyNonPollCallback(\n    _In_ PVOID pParameter\n    )\n{\n    PSERVICE_NOTIFYW notifyBuffer = pParameter;\n    PPHP_SERVICE_NOTIFY_CONTEXT notifyContext = notifyBuffer->pContext;\n\n    if (notifyBuffer->dwNotificationStatus == ERROR_SUCCESS)\n    {\n        if (FlagOn(notifyBuffer->dwNotificationTriggered, SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED) && notifyBuffer->pszServiceNames)\n        {\n            PWSTR name;\n            SIZE_T nameLength;\n\n            name = notifyBuffer->pszServiceNames;\n\n            while (TRUE)\n            {\n                nameLength = PhCountStringZ(name);\n\n                if (nameLength == 0)\n                    break;\n\n                if (name[0] == L'/')\n                {\n                    PPHP_SERVICE_NOTIFY_CONTEXT newNotifyContext;\n\n                    // Service creation\n                    newNotifyContext = PhAllocateZero(sizeof(PHP_SERVICE_NOTIFY_CONTEXT));\n                    newNotifyContext->State = SnAdding;\n                    newNotifyContext->ServiceName = PhCreateString(name + 1);\n                    InsertTailList(&PhpNonPollServicePendingListHead, &newNotifyContext->ListEntry);\n                }\n\n                name += nameLength + 1;\n            }\n\n            LocalFree(notifyBuffer->pszServiceNames);\n        }\n\n        notifyContext->State = SnNotify;\n        RemoveEntryList(&notifyContext->ListEntry);\n        InsertTailList(&PhpNonPollServicePendingListHead, &notifyContext->ListEntry);\n    }\n    else if (notifyBuffer->dwNotificationStatus == ERROR_SERVICE_MARKED_FOR_DELETE)\n    {\n        if (!notifyContext->IsServiceManager)\n        {\n            notifyContext->State = SnRemoving;\n            RemoveEntryList(&notifyContext->ListEntry);\n            InsertTailList(&PhpNonPollServicePendingListHead, &notifyContext->ListEntry);\n        }\n    }\n    else\n    {\n        notifyContext->State = SnNotify;\n        RemoveEntryList(&notifyContext->ListEntry);\n        InsertTailList(&PhpNonPollServicePendingListHead, &notifyContext->ListEntry);\n    }\n\n    PhpResetServiceNonPollGate();\n    NtSetEvent(PhNonPollEventHandle, NULL);\n    NtSetEventBoostPriority(PhNonPollEventHandle);\n}\n\nVOID PhDestroyServiceNotifyContext(\n    _In_ PPHP_SERVICE_NOTIFY_CONTEXT NotifyContext\n    )\n{\n    if (NotifyContext->Buffer.pszServiceNames)\n        LocalFree(NotifyContext->Buffer.pszServiceNames);\n\n    PhCloseServiceHandle(NotifyContext->ServiceHandle);\n    PhClearReference(&NotifyContext->ServiceName);\n    PhFree(NotifyContext);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhServiceNonPollThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    ULONG result;\n    LPENUM_SERVICE_STATUS_PROCESS services;\n    ULONG numberOfServices;\n    ULONG i;\n    PLIST_ENTRY listEntry;\n    PPHP_SERVICE_NOTIFY_CONTEXT notifyContext;\n\n    if (!NT_SUCCESS(PhCreateEvent(&PhNonPollEventHandle, EVENT_ALL_ACCESS, SynchronizationEvent, FALSE)))\n    {\n        PhNonPollActive = FALSE;\n        PhpResetServiceNonPollGate();\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    while (TRUE)\n    {\n        InitializeListHead(&PhpNonPollServiceListHead);\n        InitializeListHead(&PhpNonPollServicePendingListHead);\n\n        if (!NT_SUCCESS(PhEnumServices(&services, &numberOfServices)))\n            goto ErrorExit;\n\n        for (i = 0; i < numberOfServices; i++)\n        {\n            SC_HANDLE serviceHandle;\n\n            if (NT_SUCCESS(PhOpenService(&serviceHandle, SERVICE_QUERY_STATUS, services[i].lpServiceName)))\n            {\n                notifyContext = PhAllocateZero(sizeof(PHP_SERVICE_NOTIFY_CONTEXT));\n                notifyContext->ServiceHandle = serviceHandle;\n                notifyContext->State = SnNotify;\n                InsertTailList(&PhpNonPollServicePendingListHead, &notifyContext->ListEntry);\n            }\n        }\n\n        PhFree(services);\n\n        notifyContext = PhAllocateZero(sizeof(PHP_SERVICE_NOTIFY_CONTEXT));\n        notifyContext->ServiceHandle = PhGetServiceManagerHandle();\n        notifyContext->IsServiceManager = TRUE;\n        notifyContext->State = SnNotify;\n        InsertTailList(&PhpNonPollServicePendingListHead, &notifyContext->ListEntry);\n\n        while (TRUE)\n        {\n            BOOLEAN lagging = FALSE;\n\n            listEntry = PhpNonPollServicePendingListHead.Flink;\n\n            while (listEntry != &PhpNonPollServicePendingListHead)\n            {\n                notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry);\n                listEntry = listEntry->Flink;\n\n                switch (notifyContext->State)\n                {\n                case SnAdding:\n                    if (!NT_SUCCESS(PhOpenService(&notifyContext->ServiceHandle, SERVICE_QUERY_STATUS, PhGetString(notifyContext->ServiceName))))\n                    {\n                        RemoveEntryList(&notifyContext->ListEntry);\n                        PhDestroyServiceNotifyContext(notifyContext);\n                        continue;\n                    }\n\n                    PhClearReference(&notifyContext->ServiceName);\n                    notifyContext->State = SnNotify;\n                    goto NotifyCase;\n                case SnRemoving:\n                    RemoveEntryList(&notifyContext->ListEntry);\n                    PhDestroyServiceNotifyContext(notifyContext);\n                    break;\n                case SnNotify:\nNotifyCase:\n                    memset(&notifyContext->Buffer, 0, sizeof(SERVICE_NOTIFY));\n                    notifyContext->Buffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;\n                    notifyContext->Buffer.pfnNotifyCallback = PhServiceNotifyNonPollCallback;\n                    notifyContext->Buffer.pContext = notifyContext;\n                    result = NotifyServiceStatusChange_I(\n                        notifyContext->ServiceHandle,\n                        notifyContext->IsServiceManager\n                        ? (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED)\n                        : (SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_STOP_PENDING |\n                        SERVICE_NOTIFY_RUNNING | SERVICE_NOTIFY_CONTINUE_PENDING | SERVICE_NOTIFY_PAUSE_PENDING |\n                        SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_DELETE_PENDING),\n                        &notifyContext->Buffer\n                        );\n\n                    switch (result)\n                    {\n                    case ERROR_SUCCESS:\n                        notifyContext->State = SnNone;\n                        RemoveEntryList(&notifyContext->ListEntry);\n                        InsertTailList(&PhpNonPollServiceListHead, &notifyContext->ListEntry);\n                        break;\n                    case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:\n                        // We are lagging behind. Re-open the handle to the SCM as soon as possible.\n                        lagging = TRUE;\n                        break;\n                    case ERROR_SERVICE_MARKED_FOR_DELETE:\n                    default:\n                        RemoveEntryList(&notifyContext->ListEntry);\n                        PhDestroyServiceNotifyContext(notifyContext);\n                        break;\n                    }\n\n                    break;\n                }\n            }\n\n            while (NtWaitForSingleObject(PhNonPollEventHandle, TRUE, NULL) != STATUS_WAIT_0)\n                NOTHING;\n\n            if (lagging)\n                break;\n        }\n\n        // Execute all pending callbacks.\n        NtTestAlert();\n\n        listEntry = PhpNonPollServiceListHead.Flink;\n\n        while (listEntry != &PhpNonPollServiceListHead)\n        {\n            notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry);\n            listEntry = listEntry->Flink;\n            PhDestroyServiceNotifyContext(notifyContext);\n        }\n\n        listEntry = PhpNonPollServicePendingListHead.Flink;\n\n        while (listEntry != &PhpNonPollServicePendingListHead)\n        {\n            notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry);\n            listEntry = listEntry->Flink;\n            PhDestroyServiceNotifyContext(notifyContext);\n        }\n    }\n\n    PhNonPollActive = FALSE;\n    PhpResetServiceNonPollGate();\n    NtClose(PhNonPollEventHandle);\n    return STATUS_SUCCESS;\n\nErrorExit:\n    PhNonPollActive = FALSE;\n    PhpResetServiceNonPollGate();\n    NtClose(PhNonPollEventHandle);\n    return STATUS_UNSUCCESSFUL;\n}\n\nVOID CALLBACK PhServiceNotifyPropertyChangeCallback(\n    _In_ ULONG ServiceNotifyFlags,\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    if (ServiceItem->NotifyCreatedPropertyRegistration)\n    {\n        ServiceItem->NotifyCreatedPropertyRegistration = FALSE;\n        return;\n    }\n\n    PhMarkNeedsConfigUpdateServiceItem(ServiceItem);\n}\n\nVOID CALLBACK PhServiceNotifyStatusChangeCallback(\n    _In_ ULONG ServiceNotifyFlags,\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    if (ServiceItem->NotifyCreatedStatusRegistration)\n    {\n        ServiceItem->NotifyCreatedStatusRegistration = FALSE;\n        return;\n    }\n\n    PhMarkNeedsConfigUpdateServiceItem(ServiceItem);\n}\n\nVOID CALLBACK PhServiceNotifyDatabaseChangeCallback(\n    _In_ ULONG ServiceNotifyFlags,\n    _In_ PVOID Context\n    )\n{\n    static BOOLEAN NotifyCreatedDatabaseRegistration = TRUE;\n\n    if (NotifyCreatedDatabaseRegistration)\n    {\n        NotifyCreatedDatabaseRegistration = FALSE;\n        return;\n    }\n\n    PhpResetServiceNonPollGate();\n}\n\nVOID PhCreateServiceNotifyCallback(\n    _In_ PPH_SERVICE_ITEM ServiceItem,\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    PSC_NOTIFICATION_REGISTRATION servicePropertyRegistration;\n    PSC_NOTIFICATION_REGISTRATION serviceStatusRegistration;\n\n    if (!SubscribeServiceChangeNotifications_I)\n        return;\n\n    //if (FlagOn(ServiceItem->Type, SERVICE_DRIVER))\n    //    return;\n\n    if (!ServiceItem->NotifyCreatedPropertyRegistration)\n    {\n        ServiceItem->NotifyCreatedPropertyRegistration = TRUE;\n\n        PhReferenceObject(ServiceItem);\n\n        if (SubscribeServiceChangeNotifications_I(\n            ServiceHandle,\n            SC_EVENT_PROPERTY_CHANGE,\n            PhServiceNotifyPropertyChangeCallback,\n            ServiceItem,\n            &servicePropertyRegistration\n            ) == ERROR_SUCCESS)\n        {\n            ServiceItem->NotifyPropertyRegistration = servicePropertyRegistration;\n        }\n        else\n        {\n            PhDereferenceObject(ServiceItem);\n        }\n    }\n\n    if (!ServiceItem->NotifyCreatedStatusRegistration)\n    {\n        ServiceItem->NotifyCreatedStatusRegistration = TRUE;\n\n        PhReferenceObject(ServiceItem);\n\n        if (SubscribeServiceChangeNotifications_I(\n            ServiceHandle,\n            SC_EVENT_STATUS_CHANGE,\n            PhServiceNotifyStatusChangeCallback,\n            ServiceItem,\n            &serviceStatusRegistration\n            ) == ERROR_SUCCESS)\n        {\n            ServiceItem->NotifyStatusRegistration = serviceStatusRegistration;\n        }\n        else\n        {\n            PhDereferenceObject(ServiceItem);\n        }\n    }\n}\n\nVOID PhDestroyServiceNotifyCallback(\n    _In_ PPH_SERVICE_ITEM ServiceItem\n    )\n{\n    if (!UnsubscribeServiceChangeNotifications_I)\n        return;\n\n    if (ServiceItem->NotifyStatusRegistration)\n    {\n        UnsubscribeServiceChangeNotifications_I(ServiceItem->NotifyStatusRegistration);\n        ServiceItem->NotifyStatusRegistration = NULL;\n        PhDereferenceObject(ServiceItem);\n    }\n\n    if (ServiceItem->NotifyPropertyRegistration)\n    {\n        UnsubscribeServiceChangeNotifications_I(ServiceItem->NotifyPropertyRegistration);\n        ServiceItem->NotifyPropertyRegistration = NULL;\n        PhDereferenceObject(ServiceItem);\n    }\n}\n\nVOID PhCreateServiceDatabaseNotifyCallback(\n    VOID\n    )\n{\n    PSC_NOTIFICATION_REGISTRATION serviceNotifyRegistration;\n\n    if (!SubscribeServiceChangeNotifications_I)\n        return;\n\n    SubscribeServiceChangeNotifications_I(\n        PhGetServiceManagerHandle(),\n        SC_EVENT_DATABASE_CHANGE,\n        PhServiceNotifyDatabaseChangeCallback,\n        NULL,\n        &serviceNotifyRegistration\n        );\n}\n\nVOID PhInitializeServiceNonPoll(\n    VOID\n    )\n{\n    PVOID baseAddress;\n\n    if (baseAddress = PhLoadLibrary(L\"sechost.dll\"))\n    {\n        if (PhEnableServiceNonPollNotify && WindowsVersion >= WINDOWS_8)\n        {\n            SubscribeServiceChangeNotifications_I = PhGetDllBaseProcedureAddress(baseAddress, \"SubscribeServiceChangeNotifications\", 0);\n            UnsubscribeServiceChangeNotifications_I = PhGetDllBaseProcedureAddress(baseAddress, \"UnsubscribeServiceChangeNotifications\", 0);\n        }\n        else\n        {\n            NotifyServiceStatusChange_I = PhGetDllBaseProcedureAddress(baseAddress, \"NotifyServiceStatusChangeW\", 0);\n        }\n    }\n\n    PhNonPollActive = TRUE;\n    InterlockedExchange(&PhNonPollGate, 1); // initially the gate should be open since we only just initialized everything (wj32)\n\n    if (NotifyServiceStatusChange_I)\n    {\n        PhCreateThread2(PhServiceNonPollThreadStart, NULL);\n    }\n\n    PhCreateServiceDatabaseNotifyCallback();\n}\n"
  },
  {
    "path": "SystemInformer/sysinfo.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n *\n */\n\n/*\n * This file contains the System Information framework. The \"framework\" handles creation, layout and\n * events for the top-level window itself. It manages the list of sections.\n *\n * A section is an object that provides information to the user about a type of system resource. The\n * CPU, Memory and I/O sections are added automatically to every System Information window. Plugins\n * can also add sections to the window. There are two views: summary and section. In summary view,\n * rows of graphs are displayed in the window, one graph for each section. The section is\n * responsible for providing the graph data and any text to draw on the left-hand side of the graph.\n * In section view, the graphs become mini-graphs on the left-hand side of the window. The section\n * displays its own embedded dialog in the remaining space. Any controls contained in this dialog,\n * including graphs, are the responsibility of the section.\n *\n * Users can enter section view by:\n * * Clicking on a graph or mini-graph.\n * * Pressing a number from 1 to 9.\n * * Using the tab or arrow keys to select a graph and pressing space or enter.\n *\n * Users can return to summary view by:\n * * Clicking \"Back\" on the left-hand side of the window.\n * * Pressing Backspace.\n * * Using the tab or arrow keys to select \"Back\" and pressing space or enter.\n */\n\n#include <phapp.h>\n#include <settings.h>\n#include <sysinfo.h>\n#include <sysinfop.h>\n\n#include <vssym32.h>\n\n#include <mainwnd.h>\n#include <guisup.h>\n#include <phplug.h>\n#include <phsettings.h>\n\nstatic HANDLE PhSipThread = NULL;\nHWND PhSipWindow = NULL;\nstatic PPH_LIST PhSipDialogList = NULL;\nstatic PH_EVENT InitializedEvent = PH_EVENT_INIT;\nstatic PCWSTR InitialSectionName;\nstatic RECT MinimumSize;\nstatic PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;\nstatic PH_CALLBACK_REGISTRATION SettingsUpdatedRegistration;\n\nstatic PPH_LIST SectionList;\nstatic PH_SYSINFO_PARAMETERS CurrentParameters = {0};\nstatic PH_SYSINFO_VIEW_TYPE CurrentView;\nstatic PPH_SYSINFO_SECTION CurrentSection;\nstatic HWND ContainerControl;\nstatic HWND SeparatorControl;\nstatic HWND RestoreSummaryControl;\nstatic WNDPROC RestoreSummaryControlOldWndProc;\nstatic BOOLEAN RestoreSummaryControlHot;\nstatic BOOLEAN RestoreSummaryControlHasFocus;\nstatic HTHEME ThemeData;\nstatic BOOLEAN ThemeHasItemBackground;\n\nVOID PhShowSystemInformationDialog(\n    _In_opt_ PCWSTR SectionName\n    )\n{\n    InitialSectionName = SectionName;\n\n    if (!PhSipThread)\n    {\n        if (!NT_SUCCESS(PhCreateThreadEx(&PhSipThread, PhSipSysInfoThreadStart, NULL)))\n        {\n            PhShowStatus(PhMainWndHandle, L\"Unable to create the window.\", 0, ERROR_OUTOFMEMORY);\n            return;\n        }\n\n        PhWaitForEvent(&InitializedEvent, NULL);\n    }\n\n    SendMessage(PhSipWindow, SI_MSG_SYSINFO_ACTIVATE, (WPARAM)SectionName, 0);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhSipSysInfoThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PH_AUTO_POOL autoPool;\n    BOOL result;\n    MSG message;\n    HACCEL acceleratorTable;\n    BOOLEAN processed;\n\n    PhInitializeAutoPool(&autoPool);\n\n    PhSipWindow = PhCreateDialog(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_SYSINFO),\n        NULL,\n        PhSipSysInfoDialogProc,\n        NULL\n        );\n\n    PhSetEvent(&InitializedEvent);\n\n    acceleratorTable = LoadAccelerators(PhInstanceHandle, MAKEINTRESOURCE(IDR_SYSINFO_ACCEL));\n\n    while (result = GetMessage(&message, NULL, 0, 0))\n    {\n        if (result == -1)\n            break;\n\n        processed = FALSE;\n\n        if (\n            message.hwnd == PhSipWindow ||\n            IsChild(PhSipWindow, message.hwnd)\n            )\n        {\n            if (TranslateAccelerator(PhSipWindow, acceleratorTable, &message))\n                processed = TRUE;\n        }\n\n        if (!processed && PhSipDialogList)\n        {\n            ULONG i;\n\n            for (i = 0; i < PhSipDialogList->Count; i++)\n            {\n                if (IsDialogMessage((HWND)PhSipDialogList->Items[i], &message))\n                {\n                    processed = TRUE;\n                    break;\n                }\n            }\n        }\n\n        if (!processed)\n        {\n            if (!IsDialogMessage(PhSipWindow, &message))\n            {\n                TranslateMessage(&message);\n                DispatchMessage(&message);\n            }\n        }\n\n        PhDrainAutoPool(&autoPool);\n    }\n\n    PhDeleteAutoPool(&autoPool);\n    PhResetEvent(&InitializedEvent);\n    NtClose(PhSipThread);\n\n    PhSipWindow = NULL;\n    PhSipThread = NULL;\n\n    if (PhSipDialogList)\n    {\n        PhDereferenceObject(PhSipDialogList);\n        PhSipDialogList = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nINT_PTR CALLBACK PhSipSysInfoDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhSipWindow = hwndDlg;\n            PhSipOnInitDialog();\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSipOnDestroy();\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            PhSipOnNcDestroy();\n        }\n        break;\n    case WM_SYSCOMMAND:\n        {\n            if (PhSipOnSysCommand((ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))\n                return 0;\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhSipOnSize(hwndDlg, (UINT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhSipOnSizing((ULONG)wParam, (PRECT)lParam);\n        }\n        break;\n    case WM_THEMECHANGED:\n        {\n            PhSipOnThemeChanged();\n        }\n        break;\n    case WM_COMMAND:\n        {\n            PhSipOnCommand((HWND)lParam, LOWORD(wParam), HIWORD(wParam));\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LRESULT result;\n\n            if (PhSipOnNotify((NMHDR *)lParam, &result))\n            {\n                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, result);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_DRAWITEM:\n        {\n            if (PhSipOnDrawItem(wParam, (DRAWITEMSTRUCT *)lParam))\n                return TRUE;\n        }\n        break;\n    case WM_CTLCOLORBTN:\n    case WM_CTLCOLORDLG:\n    case WM_CTLCOLORSTATIC:\n        {\n            SetBkMode((HDC)wParam, TRANSPARENT);\n\n            if (PhEnableThemeSupport)\n            {\n                switch (PhCsGraphColorMode)\n                {\n                case 0: // New colors\n                    SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0));\n                    SetDCBrushColor((HDC)wParam, RGB(0xef, 0xef, 0xef)); // GetSysColor(COLOR_WINDOW)\n                    break;\n                case 1: // Old colors\n                    SetTextColor((HDC)wParam, RGB(0xff, 0xff, 0xff));\n                    SetDCBrushColor((HDC)wParam, PhThemeWindowBackgroundColor); // RGB(30, 30, 30));\n                    break;\n                }\n            }\n            else\n            {\n                SetTextColor((HDC)wParam, GetSysColor(COLOR_WINDOWTEXT));\n                SetDCBrushColor((HDC)wParam, GetSysColor(COLOR_WINDOW));\n            }\n\n            return (INT_PTR)PhGetStockBrush(DC_BRUSH);\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhSipInitializeParameters();\n\n            if (SectionList)\n            {\n                for (ULONG i = 0; i < SectionList->Count; i++)\n                {\n                    PPH_SYSINFO_SECTION section = SectionList->Items[i];\n\n                    if (section->DialogHandle)\n                    {\n                        section->Callback(section, SysInfoDpiChanged, UlongToPtr(LOWORD(wParam)), 0);\n                    }\n                }\n            }\n\n            PhSipOnSize(hwndDlg, 0, 0, 0);\n        }\n        break;\n    }\n\n    if (uMsg >= SI_MSG_SYSINFO_FIRST && uMsg <= SI_MSG_SYSINFO_LAST)\n    {\n        PhSipOnUserMessage(uMsg, wParam, lParam);\n    }\n\n    return FALSE;\n}\n\nINT_PTR CALLBACK PhSipContainerDialogProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (WindowMessage)\n    {\n    case WM_INITDIALOG:\n        {\n            //if (WindowsVersion >= WINDOWS_8)\n            //{\n            //    // TODO: The container background is drawn before child controls\n            //    // causing slight flickering when switching between sysinfo panels.\n            //    // We need to somehow exclude the container background drawing,\n            //    // setting the container window as composited works well but has\n            //    // slower drawing and should be considered a temporary workaround. (dmex)\n            //    PhSetWindowExStyle(hwndDlg, WS_EX_COMPOSITED, WS_EX_COMPOSITED);\n            //}\n        }\n        break;\n    case WM_CTLCOLORBTN:\n    case WM_CTLCOLORDLG:\n    case WM_CTLCOLORSTATIC:\n        {\n            SetBkMode((HDC)wParam, TRANSPARENT);\n\n            if (PhEnableThemeSupport)\n            {\n                switch (PhCsGraphColorMode)\n                {\n                case 0: // New colors\n                    SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0));\n                    SetDCBrushColor((HDC)wParam, GetSysColor(COLOR_WINDOW));\n                    break;\n                case 1: // Old colors\n                    SetTextColor((HDC)wParam, RGB(0xff, 0xff, 0xff));\n                    SetDCBrushColor((HDC)wParam, PhThemeWindowBackgroundColor);\n                    break;\n                }\n            }\n            else\n            {\n                SetTextColor((HDC)wParam, GetSysColor(COLOR_WINDOWTEXT));\n                SetDCBrushColor((HDC)wParam, GetSysColor(COLOR_WINDOW));\n            }\n\n            return (INT_PTR)PhGetStockBrush(DC_BRUSH);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhSipOnInitDialog(\n    VOID\n    )\n{\n    //RECT clientRect;\n    PH_STRINGREF sectionName;\n    PPH_SYSINFO_SECTION section;\n\n    PhSetApplicationWindowIcon(PhSipWindow);\n\n    PhSetControlTheme(PhSipWindow, L\"explorer\");\n\n    PhRegisterCallback(\n        PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent),\n        PhSipSysInfoUpdateHandler,\n        PhSipWindow,\n        &ProcessesUpdatedRegistration\n        );\n    PhRegisterCallback(\n        PhGetGeneralCallback(GeneralCallbackSettingsUpdated),\n        PhSipSysInfoSettingsCallback,\n        PhSipWindow,\n        &SettingsUpdatedRegistration\n        );\n\n    ContainerControl = PhCreateDialog(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_CONTAINER),\n        PhSipWindow,\n        PhSipContainerDialogProc,\n        NULL\n        );\n\n    PhSipUpdateThemeData();\n\n    SectionList = PhCreateList(8);\n    PhSipInitializeParameters();\n    CurrentView = SysInfoSummaryView;\n    CurrentSection = NULL;\n\n    PhSipCreateInternalSection(L\"CPU\", 0, PhSipCpuSectionCallback);\n    PhSipCreateInternalSection(L\"Memory\", 0, PhSipMemorySectionCallback);\n    PhSipCreateInternalSection(L\"I/O\", 0, PhSipIoSectionCallback);\n\n    if (PhPluginsEnabled)\n    {\n        PH_PLUGIN_SYSINFO_POINTERS pointers;\n\n        pointers.WindowHandle = PhSipWindow;\n        pointers.CreateSection = PhSipCreateSection;\n        pointers.FindSection = PhSipFindSection;\n        pointers.EnterSectionView = PhSipEnterSectionView;\n        pointers.RestoreSummaryView = PhSipRestoreSummaryView;\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackSystemInformationInitializing), &pointers);\n    }\n\n    SeparatorControl = PhCreateWindow(\n        WC_STATIC,\n        NULL,\n        WS_CHILD | SS_OWNERDRAW,\n        0,\n        0,\n        0,\n        0,\n        PhSipWindow,\n        NULL,\n        NULL,\n        NULL\n        );\n    RestoreSummaryControl = PhCreateWindow(\n        WC_STATIC,\n        NULL,\n        WS_CHILD | WS_TABSTOP | SS_OWNERDRAW | SS_NOTIFY,\n        0,\n        0,\n        0,\n        0,\n        PhSipWindow,\n        NULL,\n        NULL,\n        NULL\n        );\n\n    RestoreSummaryControlOldWndProc = PhGetWindowProcedure(RestoreSummaryControl);\n    PhSetWindowProcedure(RestoreSummaryControl, PhSipPanelHookWndProc);\n    RestoreSummaryControlHot = FALSE;\n\n    //PhGetClientRect(PhSipWindow, &clientRect);\n    MinimumSize.left = 0;\n    MinimumSize.top = 0;\n    MinimumSize.right = 430;\n    MinimumSize.bottom = 290;\n    MapDialogRect(PhSipWindow, &MinimumSize);\n\n    MinimumSize.right += CurrentParameters.PanelWidth;\n    MinimumSize.right += PhGetSystemMetrics(SM_CXFRAME, CurrentParameters.WindowDpi) * 2;\n    MinimumSize.bottom += PhGetSystemMetrics(SM_CYFRAME, CurrentParameters.WindowDpi) * 2;\n\n    if (SectionList->Count != 0)\n    {\n        //ULONG newMinimumHeight;\n        //\n        //newMinimumHeight =\n        //    GetSystemMetrics(SM_CYCAPTION) +\n        //    CurrentParameters.WindowPadding +\n        //    CurrentParameters.MinimumGraphHeight * SectionList->Count +\n        //    CurrentParameters.MinimumGraphHeight + // Back button\n        //    CurrentParameters.GraphPadding * SectionList->Count +\n        //    CurrentParameters.WindowPadding +\n        //    clientRect.bottom - buttonRect.top +\n        //    GetSystemMetrics(SM_CYFRAME) * 2;\n        //\n        //if (newMinimumHeight > (ULONG)MinimumSize.bottom)\n        //    MinimumSize.bottom = newMinimumHeight;\n    }\n\n    PhLoadWindowPlacementFromSetting(SETTING_SYSINFO_WINDOW_POSITION, SETTING_SYSINFO_WINDOW_SIZE, PhSipWindow);\n\n    if (PhGetIntegerSetting(SETTING_SYSINFO_WINDOW_STATE) == SW_MAXIMIZE)\n        ShowWindow(PhSipWindow, SW_MAXIMIZE);\n\n    if (InitialSectionName)\n        PhInitializeStringRefLongHint(&sectionName, InitialSectionName);\n    else\n        sectionName = PhaGetStringSetting(SETTING_SYSINFO_WINDOW_SECTION)->sr;\n\n    if (sectionName.Length != 0 && (section = PhSipFindSection(&sectionName)))\n    {\n        PhSipEnterSectionView(section);\n    }\n\n    PhRegisterWindowCallback(PhSipWindow, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL);\n\n    //PhInitializeWindowTheme(PhSipWindow, PhEnableThemeSupport);\n    PhInitializeThemeWindowFrame(PhSipWindow);\n\n    PhSipOnSize(PhSipWindow, 0, 0, 0);\n    PhSipOnUserMessage(SI_MSG_SYSINFO_UPDATE, 0, 0);\n}\n\nVOID PhSipOnDestroy(\n    VOID\n    )\n{\n    PhUnregisterWindowCallback(PhSipWindow);\n    PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackSettingsUpdated), &SettingsUpdatedRegistration);\n    PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedRegistration);\n\n    if (CurrentSection)\n        PhSetStringSetting2(SETTING_SYSINFO_WINDOW_SECTION, &CurrentSection->Name);\n    else\n        PhSetStringSetting(SETTING_SYSINFO_WINDOW_SECTION, L\"\");\n\n    PhSaveWindowPlacementToSetting(SETTING_SYSINFO_WINDOW_POSITION, SETTING_SYSINFO_WINDOW_SIZE, PhSipWindow);\n    PhSipSaveWindowState();\n\n    PostQuitMessage(0);\n}\n\nVOID PhSipOnNcDestroy(\n    VOID\n    )\n{\n    ULONG i;\n    PPH_SYSINFO_SECTION section;\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n        PhSipDestroySection(section);\n    }\n\n    PhDereferenceObject(SectionList);\n    SectionList = NULL;\n    PhSipDeleteParameters();\n\n    if (ThemeData)\n    {\n        PhCloseThemeData(ThemeData);\n        ThemeData = NULL;\n    }\n}\n\nBOOLEAN PhSipOnSysCommand(\n    _In_ ULONG Type,\n    _In_ LONG CursorScreenX,\n    _In_ LONG CursorScreenY\n    )\n{\n    switch (Type)\n    {\n    case SC_MINIMIZE:\n        {\n            // Save the current window state because we may not have a chance to later.\n            PhSipSaveWindowState();\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhSipOnSize(\n    _In_ HWND WindowHandle,\n    _In_ UINT State,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    if (State != SIZE_MINIMIZED)\n    {\n        if (SectionList && SectionList->Count != 0)\n        {\n            if (CurrentView == SysInfoSummaryView)\n                PhSipLayoutSummaryView();\n            else if (CurrentView == SysInfoSectionView)\n                PhSipLayoutSectionView();\n        }\n    }\n}\n\nVOID PhSipOnSizing(\n    _In_ ULONG Edge,\n    _In_ PRECT DragRectangle\n    )\n{\n    PhResizingMinimumSize(DragRectangle, Edge, MinimumSize.right, MinimumSize.bottom);\n}\n\nVOID PhSipOnThemeChanged(\n    VOID\n    )\n{\n    PhSipUpdateThemeData();\n}\n\nVOID PhSipOnCommand(\n    _In_ HWND HwndControl,\n    _In_ ULONG Id,\n    _In_ ULONG Code\n    )\n{\n    switch (Id)\n    {\n    case IDCANCEL:\n        DestroyWindow(PhSipWindow);\n        break;\n    case IDC_BACK:\n        {\n            PhSipRestoreSummaryView();\n        }\n        break;\n    case IDC_REFRESH:\n        {\n            SystemInformer_Refresh();\n        }\n        break;\n    case IDC_PAUSE:\n        {\n            SystemInformer_SetUpdateAutomatically(!SystemInformer_GetUpdateAutomatically());\n        }\n        break;\n    case IDC_MAXSCREEN:\n        {\n            static WINDOWPLACEMENT windowLayout = { sizeof(WINDOWPLACEMENT) };\n            ULONG windowStyle = PhGetWindowStyle(PhSipWindow);\n\n            if (windowStyle & WS_OVERLAPPEDWINDOW)\n            {\n                MONITORINFO info = { sizeof(MONITORINFO) };\n\n                if (\n                    GetWindowPlacement(PhSipWindow, &windowLayout) &&\n                    GetMonitorInfo(MonitorFromWindow(PhSipWindow, MONITOR_DEFAULTTOPRIMARY), &info)\n                    )\n                {\n                    PhSetWindowStyle(PhSipWindow, WS_OVERLAPPEDWINDOW, 0);\n                    SetWindowPos(\n                        PhSipWindow,\n                        HWND_TOPMOST,\n                        info.rcMonitor.left,\n                        info.rcMonitor.top,\n                        (info.rcMonitor.right - info.rcMonitor.left),\n                        (info.rcMonitor.bottom - info.rcMonitor.top),\n                        SWP_NOOWNERZORDER | SWP_FRAMECHANGED\n                        );\n                }\n            }\n            else\n            {\n                PhSetWindowStyle(PhSipWindow, WS_OVERLAPPEDWINDOW, WS_OVERLAPPEDWINDOW);\n                SetWindowPlacement(PhSipWindow, &windowLayout);\n                SetWindowPos(PhSipWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);\n            }\n        }\n        break;\n    }\n\n    if (SectionList && Id >= ID_DIGIT1 && Id <= ID_DIGIT9)\n    {\n        ULONG index;\n\n        index = Id - ID_DIGIT1;\n\n        if (index < SectionList->Count)\n            PhSipEnterSectionView(SectionList->Items[index]);\n    }\n\n    if (SectionList && Code == STN_CLICKED)\n    {\n        ULONG i;\n        PPH_SYSINFO_SECTION section;\n\n        for (i = 0; i < SectionList->Count; i++)\n        {\n            section = SectionList->Items[i];\n\n            if (Id == section->PanelId)\n            {\n                PhSipEnterSectionView(section);\n                break;\n            }\n        }\n    }\n\n    if (HwndControl == RestoreSummaryControl)\n    {\n        if (Code == STN_CLICKED)\n        {\n            PhSipRestoreSummaryView();\n        }\n    }\n}\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipGraphCallback(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    switch (GraphMessage)\n    {\n    case GCN_GETDRAWINFO:\n        {\n            PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Parameter1;\n            PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;\n            PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Context;\n\n            section->Callback(section, SysInfoGraphGetDrawInfo, drawInfo, NULL);\n\n            if (CurrentView == SysInfoSectionView)\n            {\n                drawInfo->Flags &= ~(PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y);\n            }\n            else\n            {\n                LONG badWidth = CurrentParameters.PanelWidth;\n\n                // Try not to draw max data point labels that will get covered by the\n                // fade-out part of the graph.\n                if (badWidth < drawInfo->Width)\n                    drawInfo->LabelMaxYIndexLimit = (drawInfo->Width - badWidth) / 2;\n                else\n                    drawInfo->LabelMaxYIndexLimit = ULONG_MAX;\n            }\n        }\n        break;\n    case GCN_GETTOOLTIPTEXT:\n        {\n            PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Parameter1;\n            PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Context;\n\n            if (getTooltipText->Index < getTooltipText->TotalCount)\n            {\n                PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT graphGetTooltipText;\n\n                graphGetTooltipText.Index = getTooltipText->Index;\n                PhInitializeEmptyStringRef(&graphGetTooltipText.Text);\n\n                section->Callback(section, SysInfoGraphGetTooltipText, &graphGetTooltipText, NULL);\n\n                getTooltipText->Text = graphGetTooltipText.Text;\n            }\n        }\n        break;\n    case GCN_DRAWPANEL:\n        {\n            PPH_GRAPH_DRAWPANEL drawPanel = (PPH_GRAPH_DRAWPANEL)Parameter1;\n            PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Context;\n\n            if (CurrentView == SysInfoSummaryView)\n            {\n                PhSipDrawPanel(section, drawPanel->hdc, &drawPanel->Rect);\n            }\n        }\n        break;\n    case GCN_MOUSEEVENT:\n        {\n            PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Parameter1;\n            PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Context;\n\n            if (mouseEvent->Message == WM_LBUTTONDOWN)\n            {\n                PhSipEnterSectionView(section);\n            }\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\n_Success_(return)\nBOOLEAN PhSipOnNotify(\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    )\n{\n    switch (Header->code)\n    {\n    case GCN_GETDRAWINFO:\n        {\n            PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;\n            PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;\n            ULONG i;\n            PPH_SYSINFO_SECTION section;\n\n            for (i = 0; i < SectionList->Count; i++)\n            {\n                section = SectionList->Items[i];\n\n                if (getDrawInfo->Header.hwndFrom == section->GraphHandle)\n                {\n                    section->Callback(section, SysInfoGraphGetDrawInfo, drawInfo, 0);\n\n                    if (CurrentView == SysInfoSectionView)\n                    {\n                        drawInfo->Flags &= ~(PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y);\n                    }\n                    else\n                    {\n                        LONG badWidth = CurrentParameters.PanelWidth;\n\n                        // Try not to draw max data point labels that will get covered by the\n                        // fade-out part of the graph.\n                        if (badWidth < drawInfo->Width)\n                            drawInfo->LabelMaxYIndexLimit = (drawInfo->Width - badWidth) / 2;\n                        else\n                            drawInfo->LabelMaxYIndexLimit = ULONG_MAX;\n                    }\n\n                    break;\n                }\n            }\n        }\n        break;\n    case GCN_GETTOOLTIPTEXT:\n        {\n            PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;\n            ULONG i;\n            PPH_SYSINFO_SECTION section;\n\n            if (getTooltipText->Index < getTooltipText->TotalCount)\n            {\n                for (i = 0; i < SectionList->Count; i++)\n                {\n                    section = SectionList->Items[i];\n\n                    if (getTooltipText->Header.hwndFrom == section->GraphHandle)\n                    {\n                        PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT graphGetTooltipText;\n\n                        graphGetTooltipText.Index = getTooltipText->Index;\n                        PhInitializeEmptyStringRef(&graphGetTooltipText.Text);\n\n                        section->Callback(section, SysInfoGraphGetTooltipText, &graphGetTooltipText, 0);\n\n                        getTooltipText->Text = graphGetTooltipText.Text;\n\n                        break;\n                    }\n                }\n            }\n        }\n        break;\n    case GCN_DRAWPANEL:\n        {\n            PPH_GRAPH_DRAWPANEL drawPanel = (PPH_GRAPH_DRAWPANEL)Header;\n            ULONG i;\n            PPH_SYSINFO_SECTION section;\n\n            if (CurrentView == SysInfoSummaryView)\n            {\n                for (i = 0; i < SectionList->Count; i++)\n                {\n                    section = SectionList->Items[i];\n\n                    if (drawPanel->Header.hwndFrom == section->GraphHandle)\n                    {\n                        PhSipDrawPanel(section, drawPanel->hdc, &drawPanel->Rect);\n                        break;\n                    }\n                }\n            }\n        }\n        break;\n    case GCN_MOUSEEVENT:\n        {\n            PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;\n            ULONG i;\n            PPH_SYSINFO_SECTION section;\n\n            for (i = 0; i < SectionList->Count; i++)\n            {\n                section = SectionList->Items[i];\n\n                if (mouseEvent->Header.hwndFrom == section->GraphHandle)\n                {\n                    if (mouseEvent->Message == WM_LBUTTONDOWN)\n                    {\n                        PhSipEnterSectionView(section);\n                    }\n\n                    break;\n                }\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhSipOnDrawItem(\n    _In_ ULONG_PTR Id,\n    _In_ PDRAWITEMSTRUCT DrawItemStruct\n    )\n{\n    ULONG i;\n    PPH_SYSINFO_SECTION section;\n\n    if (DrawItemStruct->hwndItem == RestoreSummaryControl)\n    {\n        PhSipDrawRestoreSummaryPanel(DrawItemStruct);\n        return TRUE;\n    }\n    else if (DrawItemStruct->hwndItem == SeparatorControl)\n    {\n        PhSipDrawSeparator(DrawItemStruct);\n        return TRUE;\n    }\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n\n        if (Id == section->PanelId)\n        {\n            PhSipDrawPanel(section, DrawItemStruct->hDC, &DrawItemStruct->rcItem);\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nVOID PhSipOnUserMessage(\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    )\n{\n    switch (Message)\n    {\n    case SI_MSG_SYSINFO_ACTIVATE:\n        {\n            PWSTR sectionName = (PWSTR)WParam;\n\n            if (SectionList && sectionName)\n            {\n                PH_STRINGREF sectionNameSr;\n                PPH_SYSINFO_SECTION section;\n\n                PhInitializeStringRefLongHint(&sectionNameSr, sectionName);\n                section = PhSipFindSection(&sectionNameSr);\n\n                if (section)\n                    PhSipEnterSectionView(section);\n                else\n                    PhSipRestoreSummaryView();\n            }\n\n            if (IsMinimized(PhSipWindow))\n                ShowWindow(PhSipWindow, SW_RESTORE);\n            else\n                ShowWindow(PhSipWindow, SW_SHOW);\n\n            SetForegroundWindow(PhSipWindow);\n        }\n        break;\n    case SI_MSG_SYSINFO_UPDATE:\n        {\n            ULONG i;\n            PPH_SYSINFO_SECTION section;\n\n            if (SectionList)\n            {\n                for (i = 0; i < SectionList->Count; i++)\n                {\n                    section = SectionList->Items[i];\n\n                    section->Callback(section, SysInfoTick, NULL, NULL);\n\n                    section->GraphState.Valid = FALSE;\n                    section->GraphState.TooltipIndex = ULONG_MAX;\n                    Graph_Update(section->GraphHandle);\n\n                    InvalidateRect(section->PanelHandle, NULL, FALSE);\n                }\n            }\n        }\n        break;\n    case SI_MSG_SYSINFO_CHANGE_SETTINGS:\n        {\n            ULONG i;\n            PPH_SYSINFO_SECTION section;\n            PH_GRAPH_OPTIONS options;\n\n            PhSipUpdateColorParameters();\n\n            if (SectionList)\n            {\n                for (i = 0; i < SectionList->Count; i++)\n                {\n                    section = SectionList->Items[i];\n                    Graph_GetOptions(section->GraphHandle, &options);\n                    options.FadeOutBackColor = CurrentParameters.GraphBackColor;\n                    Graph_SetOptions(section->GraphHandle, &options);\n                }\n            }\n\n            InvalidateRect(PhSipWindow, NULL, TRUE);\n        }\n        break;\n    }\n}\n\nVOID PhSiNotifyChangeSettings(\n    VOID\n    )\n{\n    PhSipUpdateColorParameters();\n}\n\n_Function_class_(PH_SYSINFO_COLOR_SETUP_FUNCTION)\nVOID PhSiSetColorsGraphDrawInfo(\n    _Out_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ COLORREF Color1,\n    _In_ COLORREF Color2,\n    _In_ LONG WindowDpi\n    )\n{\n    static PH_QUEUED_LOCK lock = PH_QUEUED_LOCK_INIT;\n    static LONG lastDpi = ULONG_MAX;\n    static HFONT iconTitleFont = NULL;\n\n    // Get the appropriate fonts.\n\n    if (DrawInfo->Flags & PH_GRAPH_LABEL_MAX_Y)\n    {\n        PhAcquireQueuedLockExclusive(&lock);\n\n        if (lastDpi != WindowDpi)\n        {\n            LOGFONT logFont;\n\n            if (PhGetSystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, WindowDpi))\n            {\n                logFont.lfHeight += PhMultiplyDivide(1, WindowDpi, 72);\n\n                HFONT fontHandle = iconTitleFont;\n                iconTitleFont = CreateFontIndirect(&logFont);\n                if (fontHandle) DeleteFont(fontHandle);\n            }\n\n            if (!iconTitleFont)\n                iconTitleFont = PhApplicationFont;\n\n            lastDpi = WindowDpi;\n        }\n\n        DrawInfo->LabelYFont = iconTitleFont;\n\n        PhReleaseQueuedLockExclusive(&lock);\n    }\n\n    DrawInfo->TextFont = PhApplicationFont;\n\n    // Set up the colors.\n\n    switch (PhCsGraphColorMode)\n    {\n    case 0: // New colors\n        DrawInfo->BackColor = RGB(0xef, 0xef, 0xef);\n        DrawInfo->LineColor1 = PhHalveColorBrightness(Color1);\n        DrawInfo->LineBackColor1 = PhMakeColorBrighter(Color1, 125);\n        DrawInfo->LineColor2 = PhHalveColorBrightness(Color2);\n        DrawInfo->LineBackColor2 = PhMakeColorBrighter(Color2, 125);\n        DrawInfo->GridColor = RGB(0xc7, 0xc7, 0xc7);\n        DrawInfo->LabelYColor = RGB(0xa0, 0x60, 0x20);\n        DrawInfo->TextColor = RGB(0x00, 0x00, 0x00);\n        DrawInfo->TextBoxColor = RGB(0xe7, 0xe7, 0xe7);\n        break;\n    case 1: // Old colors\n        DrawInfo->BackColor = RGB(0x00, 0x00, 0x00);\n        DrawInfo->LineColor1 = Color1;\n        DrawInfo->LineBackColor1 = PhHalveColorBrightness(Color1);\n        DrawInfo->LineColor2 = Color2;\n        DrawInfo->LineBackColor2 = PhHalveColorBrightness(Color2);\n        DrawInfo->GridColor = RGB(0x00, 0x57, 0x00);\n        DrawInfo->LabelYColor = RGB(0xd0, 0xa0, 0x70);\n        DrawInfo->TextColor = RGB(0x00, 0xff, 0x00);\n        DrawInfo->TextBoxColor = RGB(0x00, 0x22, 0x00);\n        break;\n    }\n}\n\n_Function_class_(PH_GRAPH_LABEL_Y_FUNCTION)\nPPH_STRING PhSiSizeLabelYFunction(\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataIndex,\n    _In_ FLOAT Value,\n    _In_ FLOAT Parameter\n    )\n{\n    ULONG64 size;\n\n    size = (ULONG64)(Value * Parameter);\n\n    if (size != 0)\n    {\n        PH_FORMAT format;\n\n        format.Type = SizeFormatType | FormatUsePrecision | FormatUseRadix;\n        format.Precision = 0;\n        format.Radix = (UCHAR)PhMaxSizeUnit;\n        format.u.Size = size;\n\n        return PhFormat(&format, 1, 0);\n    }\n    else\n    {\n        return PhReferenceEmptyString();\n    }\n}\n\n_Function_class_(PH_GRAPH_LABEL_Y_FUNCTION)\nPPH_STRING PhSiDoubleLabelYFunction(\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataIndex,\n    _In_ FLOAT Value,\n    _In_ FLOAT Parameter\n    )\n{\n    FLOAT value;\n\n    value = (FLOAT)(Value * Parameter);\n\n    if (value != 0)\n    {\n        PH_FORMAT format[2];\n\n        PhInitFormatF(&format[0], value * 100.f, PhMaxPrecisionUnit);\n        PhInitFormatC(&format[1], L'%');\n\n        return PhFormat(format, RTL_NUMBER_OF(format), 0);\n    }\n    else\n    {\n        return PhReferenceEmptyString();\n    }\n}\n\n_Function_class_(PH_GRAPH_LABEL_Y_FUNCTION)\nPPH_STRING PhSiUInt64LabelYFunction(\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataIndex,\n    _In_ FLOAT Value,\n    _In_ FLOAT Parameter\n    )\n{\n    ULONG64 value = (ULONG64)Value * (ULONG64)Parameter;\n\n    if (value != 0)\n    {\n        return PhFormatUInt64(value, TRUE);\n    }\n    else\n    {\n        return PhReferenceEmptyString();\n    }\n}\n\nVOID PhSipRegisterDialog(\n    _In_ HWND DialogWindowHandle\n    )\n{\n    if (!PhSipDialogList)\n        PhSipDialogList = PhCreateList(4);\n\n    PhAddItemList(PhSipDialogList, DialogWindowHandle);\n}\n\nVOID PhSipUnregisterDialog(\n    _In_ HWND DialogWindowHandle\n    )\n{\n    ULONG index;\n\n    if ((index = PhFindItemList(PhSipDialogList, DialogWindowHandle)) != ULONG_MAX)\n        PhRemoveItemList(PhSipDialogList, index);\n}\n\nVOID PhSipInitializeParameters(\n    VOID\n    )\n{\n    LOGFONT logFont;\n    HDC hdc;\n    TEXTMETRIC textMetrics;\n    HFONT originalFont;\n\n    PhSipDeleteParameters();\n\n    memset(&CurrentParameters, 0, sizeof(PH_SYSINFO_PARAMETERS));\n\n    CurrentParameters.WindowDpi = PhGetWindowDpi(PhSipWindow);\n    CurrentParameters.SysInfoWindowHandle = PhSipWindow;\n    CurrentParameters.ContainerWindowHandle = ContainerControl;\n\n    if (PhGetSystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, CurrentParameters.WindowDpi))\n    {\n        CurrentParameters.Font = CreateFontIndirect(&logFont);\n    }\n    else\n    {\n        CurrentParameters.Font = PhApplicationFont;\n        GetObject(PhApplicationFont, sizeof(LOGFONT), &logFont);\n    }\n\n    hdc = GetDC(PhSipWindow);\n\n    logFont.lfHeight -= PhMultiplyDivide(3, CurrentParameters.WindowDpi, 72);\n    CurrentParameters.MediumFont = CreateFontIndirect(&logFont);\n\n    logFont.lfHeight -= PhMultiplyDivide(3, CurrentParameters.WindowDpi, 72);\n    CurrentParameters.LargeFont = CreateFontIndirect(&logFont);\n\n    PhSipUpdateColorParameters();\n\n    CurrentParameters.ColorSetupFunction = PhSiSetColorsGraphDrawInfo;\n\n    originalFont = SelectFont(hdc, CurrentParameters.Font);\n    GetTextMetrics(hdc, &textMetrics);\n    CurrentParameters.FontHeight = textMetrics.tmHeight;\n    CurrentParameters.FontAverageWidth = textMetrics.tmAveCharWidth;\n\n    SelectFont(hdc, CurrentParameters.MediumFont);\n    GetTextMetrics(hdc, &textMetrics);\n    CurrentParameters.MediumFontHeight = textMetrics.tmHeight;\n    CurrentParameters.MediumFontAverageWidth = textMetrics.tmAveCharWidth;\n\n    SelectFont(hdc, originalFont);\n\n    // Internal padding and other values\n    CurrentParameters.PanelPadding = PhGetDpi(PH_SYSINFO_PANEL_PADDING, CurrentParameters.WindowDpi);\n    CurrentParameters.WindowPadding = PhGetDpi(PH_SYSINFO_WINDOW_PADDING, CurrentParameters.WindowDpi);\n    CurrentParameters.GraphPadding = PhGetDpi(PH_SYSINFO_GRAPH_PADDING, CurrentParameters.WindowDpi);\n    CurrentParameters.SmallGraphWidth = PhGetDpi(PH_SYSINFO_SMALL_GRAPH_WIDTH, CurrentParameters.WindowDpi);\n    CurrentParameters.SmallGraphPadding = PhGetDpi(PH_SYSINFO_SMALL_GRAPH_PADDING, CurrentParameters.WindowDpi);\n    CurrentParameters.SeparatorWidth = PhGetDpi(PH_SYSINFO_SEPARATOR_WIDTH, CurrentParameters.WindowDpi);\n    CurrentParameters.CpuPadding = PhGetDpi(PH_SYSINFO_CPU_PADDING, CurrentParameters.WindowDpi);\n    CurrentParameters.MemoryPadding = PhGetDpi(PH_SYSINFO_MEMORY_PADDING, CurrentParameters.WindowDpi);\n\n    CurrentParameters.MinimumGraphHeight =\n        CurrentParameters.PanelPadding +\n        CurrentParameters.MediumFontHeight +\n        CurrentParameters.PanelPadding;\n\n    CurrentParameters.SectionViewGraphHeight =\n        CurrentParameters.PanelPadding +\n        CurrentParameters.MediumFontHeight +\n        CurrentParameters.PanelPadding +\n        CurrentParameters.FontHeight +\n        2 +\n        CurrentParameters.FontHeight +\n        CurrentParameters.PanelPadding +\n        2;\n\n    CurrentParameters.PanelWidth = CurrentParameters.MediumFontAverageWidth * 10;\n\n    ReleaseDC(PhSipWindow, hdc);\n}\n\nVOID PhSipDeleteParameters(\n    VOID\n    )\n{\n    if (CurrentParameters.Font)\n        DeleteFont(CurrentParameters.Font);\n    if (CurrentParameters.MediumFont)\n        DeleteFont(CurrentParameters.MediumFont);\n    if (CurrentParameters.LargeFont)\n        DeleteFont(CurrentParameters.LargeFont);\n}\n\nVOID PhSipUpdateColorParameters(\n    VOID\n    )\n{\n    switch (PhCsGraphColorMode)\n    {\n    case 0: // New colors\n        CurrentParameters.GraphBackColor = RGB(0xef, 0xef, 0xef);\n        CurrentParameters.PanelForeColor = RGB(0x00, 0x00, 0x00);\n        break;\n    case 1: // Old colors\n        CurrentParameters.GraphBackColor = RGB(0x00, 0x00, 0x00);\n        CurrentParameters.PanelForeColor = RGB(0xff, 0xff, 0xff);\n        break;\n    }\n}\n\n_Function_class_(PH_SYSINFO_CREATE_SECTION)\nPPH_SYSINFO_SECTION PhSipCreateSection(\n    _In_ PPH_SYSINFO_SECTION Template\n    )\n{\n    PPH_SYSINFO_SECTION section;\n    PH_GRAPH_OPTIONS options;\n    PH_GRAPH_CREATEPARAMS graphCreateParams;\n\n    section = PhAllocateZero(sizeof(PH_SYSINFO_SECTION));\n    section->Name = Template->Name;\n    section->Flags = Template->Flags;\n    section->Callback = Template->Callback;\n    section->Context = Template->Context;\n\n    memset(&options, 0, sizeof(PH_GRAPH_OPTIONS));\n    options.FadeOutBackColor = CurrentParameters.GraphBackColor;\n    options.FadeOutWidth = CurrentParameters.PanelWidth + PH_SYSINFO_FADE_ADD;\n    options.DefaultCursor = PhLoadCursor(NULL, IDC_HAND);\n\n    memset(&graphCreateParams, 0, sizeof(PH_GRAPH_CREATEPARAMS));\n    graphCreateParams.Size = sizeof(PH_GRAPH_CREATEPARAMS);\n    graphCreateParams.Callback = PhSipGraphCallback;\n    graphCreateParams.Options = options;\n    graphCreateParams.Context = section;\n\n    section->GraphHandle = PhCreateWindow(\n        PH_GRAPH_CLASSNAME,\n        NULL,\n        WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP | GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL,\n        0,\n        0,\n        0,\n        0,\n        PhSipWindow,\n        NULL,\n        NULL,\n        &graphCreateParams\n        );\n    PhInitializeGraphState(&section->GraphState);\n    if (PhEnableTooltipSupport) Graph_SetTooltip(section->GraphHandle, TRUE);\n    section->Parameters = &CurrentParameters;\n\n    section->PanelId = IDDYNAMIC + SectionList->Count * 2 + 2;\n    section->PanelHandle = PhCreateWindow(\n        WC_STATIC,\n        NULL,\n        WS_CHILD | SS_OWNERDRAW | SS_NOTIFY,\n        0,\n        0,\n        0,\n        0,\n        PhSipWindow,\n        UlongToHandle(section->PanelId),\n        NULL,\n        NULL\n        );\n\n    section->GraphWindowProc = PhGetWindowProcedure(section->GraphHandle);\n    section->PanelWindowProc = PhGetWindowProcedure(section->PanelHandle);\n\n    PhSetWindowContext(section->GraphHandle, 0xF, section);\n    PhSetWindowContext(section->PanelHandle, 0xF, section);\n\n    PhSetWindowProcedure(section->GraphHandle, PhSipGraphHookWndProc);\n    PhSetWindowProcedure(section->PanelHandle, PhSipPanelHookWndProc);\n\n    PhAddItemList(SectionList, section);\n\n    section->Callback(section, SysInfoCreate, NULL, NULL);\n\n    return section;\n}\n\nVOID PhSipDestroySection(\n    _In_ PPH_SYSINFO_SECTION Section\n    )\n{\n    Section->Callback(Section, SysInfoDestroy, NULL, NULL);\n\n    PhDeleteGraphState(&Section->GraphState);\n    PhFree(Section);\n}\n\n_Function_class_(PH_SYSINFO_FIND_SECTION)\nPPH_SYSINFO_SECTION PhSipFindSection(\n    _In_ PPH_STRINGREF Name\n    )\n{\n    ULONG i;\n    PPH_SYSINFO_SECTION section;\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n\n        if (PhEqualStringRef(&section->Name, Name, TRUE))\n            return section;\n    }\n\n    return NULL;\n}\n\nPPH_SYSINFO_SECTION PhSipCreateInternalSection(\n    _In_ PWSTR Name,\n    _In_ ULONG Flags,\n    _In_ PPH_SYSINFO_SECTION_CALLBACK Callback\n    )\n{\n    PH_SYSINFO_SECTION section;\n\n    memset(&section, 0, sizeof(PH_SYSINFO_SECTION));\n    PhInitializeStringRefLongHint(&section.Name, Name);\n    section.Flags = Flags;\n    section.Callback = Callback;\n\n    return PhSipCreateSection(&section);\n}\n\nVOID PhSipDrawRestoreSummaryPanel(\n    _In_ PDRAWITEMSTRUCT DrawItemStruct\n    )\n{\n    HDC hdc;\n    HDC bufferDc;\n    HBITMAP bufferBitmap;\n    HBITMAP oldBufferBitmap;\n    RECT bufferRect =\n    {\n        0, 0,\n        DrawItemStruct->rcItem.right - DrawItemStruct->rcItem.left,\n        DrawItemStruct->rcItem.bottom - DrawItemStruct->rcItem.top\n    };\n\n    if (!(hdc = GetDC(DrawItemStruct->hwndItem)))\n        return;\n\n    bufferDc = CreateCompatibleDC(hdc);\n    bufferBitmap = CreateCompatibleBitmap(hdc, bufferRect.right, bufferRect.bottom);\n    oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap);\n\n    SetBkMode(bufferDc, TRANSPARENT);\n\n    if (PhEnableThemeSupport)\n    {\n        switch (PhCsGraphColorMode)\n        {\n        case 0: // New colors\n            SetTextColor(bufferDc, RGB(0x00, 0x00, 0x00));\n            SetDCBrushColor(bufferDc, RGB(0xff, 0xff, 0xff));\n            FillRect(bufferDc, &bufferRect, PhGetStockBrush(DC_BRUSH));\n            break;\n        case 1: // Old colors\n            SetTextColor(bufferDc, PhThemeWindowTextColor);\n            SetDCBrushColor(bufferDc, PhThemeWindowBackgroundColor);\n            FillRect(bufferDc, &bufferRect, PhGetStockBrush(DC_BRUSH));\n            break;\n        }\n    }\n    else\n    {\n        SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT));\n        FillRect(bufferDc, &bufferRect, (HBRUSH)(COLOR_WINDOW + 1));\n    }\n\n    if (RestoreSummaryControlHot || RestoreSummaryControlHasFocus)\n    {\n        if (ThemeHasItemBackground)\n        {\n            PhDrawThemeBackground(\n                ThemeData,\n                bufferDc,\n                TVP_TREEITEM,\n                TREIS_HOT,\n                &bufferRect,\n                &bufferRect\n                );\n        }\n        else\n        {\n            FillRect(bufferDc, &bufferRect, (HBRUSH)(COLOR_WINDOW + 1));\n        }\n    }\n\n    SelectFont(bufferDc, CurrentParameters.MediumFont);\n    DrawText(bufferDc, L\"Back\", 4, &bufferRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);\n\n    BitBlt(\n        hdc,\n        DrawItemStruct->rcItem.left,\n        DrawItemStruct->rcItem.top,\n        DrawItemStruct->rcItem.right,\n        DrawItemStruct->rcItem.bottom,\n        bufferDc,\n        0,\n        0,\n        SRCCOPY\n        );\n\n    SelectBitmap(bufferDc, oldBufferBitmap);\n    DeleteBitmap(bufferBitmap);\n    DeleteDC(bufferDc);\n\n    ReleaseDC(DrawItemStruct->hwndItem, hdc);\n}\n\nVOID PhSipDrawSeparator(\n    _In_ PDRAWITEMSTRUCT DrawItemStruct\n    )\n{\n    HDC hdc;\n    HDC bufferDc;\n    HBITMAP bufferBitmap;\n    HBITMAP oldBufferBitmap;\n    RECT bufferRect =\n    {\n        0, 0,\n        DrawItemStruct->rcItem.right - DrawItemStruct->rcItem.left,\n        DrawItemStruct->rcItem.bottom - DrawItemStruct->rcItem.top\n    };\n\n    if (!(hdc = GetDC(DrawItemStruct->hwndItem)))\n        return;\n\n    bufferDc = CreateCompatibleDC(hdc);\n    bufferBitmap = CreateCompatibleBitmap(hdc, bufferRect.right, bufferRect.bottom);\n    oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap);\n\n    SetBkMode(bufferDc, TRANSPARENT);\n\n    if (PhEnableThemeSupport)\n    {\n        switch (PhCsGraphColorMode)\n        {\n        case 0: // New colors\n            {\n                //FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DFACE));\n                //bufferRect.left += 1;\n                //FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DSHADOW));\n                //bufferRect.left -= 1;\n            }\n            break;\n        case 1: // Old colors\n            {\n                SetDCBrushColor(bufferDc, PhThemeWindowBackgroundColor);\n                FillRect(bufferDc, &bufferRect, PhGetStockBrush(DC_BRUSH));\n            }\n            break;\n        }\n    }\n    else\n    {\n        //FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DHIGHLIGHT));\n        //bufferRect.left += 1;\n        //FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DSHADOW));\n        //bufferRect.left -= 1;\n\n        SetDCBrushColor(bufferDc, RGB(0xff, 0xff, 0xff));\n        FillRect(bufferDc, &bufferRect, PhGetStockBrush(DC_BRUSH));\n    }\n\n    BitBlt(\n        hdc,\n        DrawItemStruct->rcItem.left,\n        DrawItemStruct->rcItem.top,\n        DrawItemStruct->rcItem.right,\n        DrawItemStruct->rcItem.bottom,\n        bufferDc,\n        0,\n        0,\n        SRCCOPY\n        );\n\n    SelectBitmap(bufferDc, oldBufferBitmap);\n    DeleteBitmap(bufferBitmap);\n    DeleteDC(bufferDc);\n\n    ReleaseDC(DrawItemStruct->hwndItem, hdc);\n}\n\nVOID PhSipDrawPanel(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ HDC hdc,\n    _In_ PRECT Rect\n    )\n{\n    PH_SYSINFO_DRAW_PANEL sysInfoDrawPanel;\n\n    if (CurrentView == SysInfoSectionView)\n    {\n        if (PhEnableThemeSupport)\n        {\n            switch (PhCsGraphColorMode)\n            {\n            case 0: // New colors\n                SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff));\n                FillRect(hdc, Rect, PhGetStockBrush(DC_BRUSH));\n                break;\n            case 1: // Old colors\n                SetDCBrushColor(hdc, PhThemeWindowBackgroundColor);\n                FillRect(hdc, Rect, PhGetStockBrush(DC_BRUSH));\n                break;\n            }\n        }\n        else\n        {\n            SetDCBrushColor(hdc, RGB(255, 255, 255));\n            FillRect(hdc, Rect, PhGetStockBrush(DC_BRUSH));\n        }\n\n        //if (PhEnableThemeSupport)\n        //{\n        //    switch (PhCsGraphColorMode)\n        //    {\n        //    case 0: // New colors\n        //        FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE));\n        //        break;\n        //    case 1: // Old colors\n        //        SetDCBrushColor(hdc, RGB(30, 30, 30));\n        //        FillRect(hdc, Rect, PhGetStockBrush(DC_BRUSH));\n        //        break;\n        //    }\n        //}\n        //else\n        //{\n        //    FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE));\n        //}\n    }\n\n    sysInfoDrawPanel.hdc = hdc;\n    sysInfoDrawPanel.Rect = *Rect;\n    sysInfoDrawPanel.Rect.right = CurrentParameters.PanelWidth;\n    sysInfoDrawPanel.CustomDraw = FALSE;\n\n    sysInfoDrawPanel.Title = NULL;\n    sysInfoDrawPanel.SubTitle = NULL;\n    sysInfoDrawPanel.SubTitleOverflow = NULL;\n\n    Section->Callback(Section, SysInfoGraphDrawPanel, &sysInfoDrawPanel, NULL);\n\n    if (!sysInfoDrawPanel.CustomDraw)\n    {\n        sysInfoDrawPanel.Rect.right = Rect->right;\n        PhSipDefaultDrawPanel(Section, &sysInfoDrawPanel);\n    }\n\n    PhClearReference(&sysInfoDrawPanel.Title);\n    PhClearReference(&sysInfoDrawPanel.SubTitle);\n    PhClearReference(&sysInfoDrawPanel.SubTitleOverflow);\n}\n\nVOID PhSipDefaultDrawPanel(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ PPH_SYSINFO_DRAW_PANEL DrawPanel\n    )\n{\n    HDC hdc;\n    RECT rect;\n    ULONG flags;\n\n    hdc = DrawPanel->hdc;\n\n    if (ThemeHasItemBackground)\n    {\n        if (CurrentView == SysInfoSummaryView)\n        {\n            //if (Section->GraphHot)\n            //{\n            //    PhDrawThemeBackground(\n            //        ThemeData,\n            //        hdc,\n            //        TVP_TREEITEM,\n            //        TREIS_HOT,\n            //        &DrawPanel->Rect,\n            //        &DrawPanel->Rect\n            //        );\n            //}\n        }\n        else if (CurrentView == SysInfoSectionView)\n        {\n            INT stateId;\n\n            stateId = -1;\n\n            if (Section->GraphHot || Section->PanelHot || (Section->HasFocus && !Section->HideFocus))\n            {\n                if (Section == CurrentSection)\n                    stateId = TREIS_HOTSELECTED;\n                else\n                    stateId = TREIS_HOT;\n            }\n            else if (Section == CurrentSection)\n            {\n                stateId = TREIS_SELECTED;\n            }\n\n            if (stateId != -1)\n            {\n                RECT themeRect;\n\n                themeRect = DrawPanel->Rect;\n                themeRect.left -= 2; // remove left edge\n\n                PhDrawThemeBackground(\n                    ThemeData,\n                    hdc,\n                    TVP_TREEITEM,\n                    stateId,\n                    &themeRect,\n                    &DrawPanel->Rect\n                    );\n            }\n        }\n        else if (Section->HasFocus)\n        {\n            PhDrawThemeBackground(\n                ThemeData,\n                hdc,\n                TVP_TREEITEM,\n                TREIS_HOT,\n                &DrawPanel->Rect,\n                &DrawPanel->Rect\n                );\n        }\n    }\n    else\n    {\n        if (CurrentView == SysInfoSectionView)\n        {\n            HBRUSH brush = NULL;\n\n            if (Section->GraphHot || Section->PanelHot || Section->HasFocus)\n            {\n                brush = GetSysColorBrush(COLOR_HOTLIGHT);\n            }\n            else if (Section == CurrentSection)\n            {\n                brush = GetSysColorBrush(COLOR_WINDOW);\n            }\n\n            if (brush)\n            {\n                FillRect(hdc, &DrawPanel->Rect, brush);\n            }\n        }\n    }\n\n    SetBkMode(hdc, TRANSPARENT);\n\n    if (PhEnableThemeSupport)\n    {\n        switch (PhCsGraphColorMode)\n        {\n        case 0: // New colors\n            SetTextColor(hdc, RGB(0x00, 0x00, 0x00));\n            //SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff));\n            //FillRect(hdc, Rect, PhGetStockBrush(DC_BRUSH));\n            break;\n        case 1: // Old colors\n            SetTextColor(hdc, RGB(0xff, 0xff, 0xff));\n            //SetDCBrushColor(hdc, RGB(0xff, 0xff, 0x00));\n            //FillRect(hdc, Rect, PhGetStockBrush(DC_BRUSH));\n            break;\n        }\n\n        //SetTextColor(hdc, CurrentParameters.PanelForeColor);\n    }\n    else\n    {\n        //SetTextColor(hdc, RGB(0x00, 0x00, 0x00));\n\n        if (CurrentView == SysInfoSummaryView)\n        {\n            SetTextColor(hdc, CurrentParameters.PanelForeColor);\n        }\n        else\n        {\n            SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));\n        }\n    }\n\n    rect.left = CurrentParameters.SmallGraphPadding + CurrentParameters.PanelPadding;\n    rect.top = CurrentParameters.PanelPadding;\n    rect.right = CurrentParameters.PanelWidth;\n    rect.bottom = DrawPanel->Rect.bottom;\n\n    flags = DT_NOPREFIX;\n\n    if (CurrentView == SysInfoSummaryView)\n        rect.right = DrawPanel->Rect.right; // allow the text to overflow\n    else\n        flags |= DT_END_ELLIPSIS;\n\n    if (DrawPanel->Title)\n    {\n        SelectFont(hdc, CurrentParameters.MediumFont);\n        DrawText(hdc, DrawPanel->Title->Buffer, (ULONG)DrawPanel->Title->Length / sizeof(WCHAR), &rect, flags | DT_SINGLELINE);\n    }\n\n    if (DrawPanel->SubTitle)\n    {\n        RECT measureRect;\n        SIZE textSize;\n        LONG lineHeight;\n        LONG lineWidth;\n        LONG rectHeight;\n        LONG rectWidth;\n        LONG textHeight;\n        LONG textWidth;\n\n        rect.top += CurrentParameters.MediumFontHeight + CurrentParameters.PanelPadding;\n        measureRect = rect;\n\n        SelectFont(hdc, CurrentParameters.Font);\n        GetTextExtentPoint32(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &textSize);\n        DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &measureRect, flags | DT_CALCRECT);\n\n        lineHeight = textSize.cy;\n        lineWidth = textSize.cx;\n        rectHeight = rect.bottom - rect.top;\n        rectWidth = rect.right - rect.left;\n        textHeight = measureRect.bottom - measureRect.top;\n        textWidth = measureRect.right - measureRect.left;\n        //dprintf(\n        //    \"[rectHeight: %u, rectwidth: %u] [lineHeight: %u, lineWidth: %u] [textHeight: %u, textWidth: %u]\\n\",\n        //    rectHeight, rectWidth,\n        //    lineHeight, lineWidth,\n        //    textHeight, textWidth\n        //    );\n\n        if (rectHeight > lineHeight)\n        {\n            if (rectHeight > textHeight)\n            {\n                if (lineWidth < rectWidth || !DrawPanel->SubTitleOverflow)\n                {\n                    // Text fits; draw normally.\n                    DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &rect, flags);\n                }\n                else\n                {\n                    // Text doesn't fit; draw the alternative text.\n                    DrawText(hdc, DrawPanel->SubTitleOverflow->Buffer, (ULONG)DrawPanel->SubTitleOverflow->Length / sizeof(WCHAR), &rect, flags);\n                }\n            }\n            else\n            {\n                PH_STRINGREF titlePart;\n                PH_STRINGREF remainingPart;\n\n                // dmex: Multiline text doesn't fit; split the string and draw the first line.\n                if (DrawPanel->SubTitleOverflow)\n                {\n                    if (PhSplitStringRefAtChar(&DrawPanel->SubTitleOverflow->sr, L'\\n', &titlePart, &remainingPart))\n                        DrawText(hdc, titlePart.Buffer, (ULONG)titlePart.Length / sizeof(WCHAR), &rect, flags);\n                    else\n                        DrawText(hdc, DrawPanel->SubTitleOverflow->Buffer, (ULONG)DrawPanel->SubTitleOverflow->Length / sizeof(WCHAR), &rect, flags);\n                }\n                else\n                {\n                    if (PhSplitStringRefAtChar(&DrawPanel->SubTitle->sr, L'\\n', &titlePart, &remainingPart))\n                        DrawText(hdc, titlePart.Buffer, (ULONG)titlePart.Length / sizeof(WCHAR), &rect, flags);\n                    else\n                        DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &rect, flags);\n                }\n            }\n        }\n    }\n}\n\nVOID PhSipLayoutSummaryView(\n    VOID\n    )\n{\n    RECT clientRect;\n    ULONG availableHeight;\n    ULONG availableWidth;\n    ULONG graphHeight;\n    ULONG i;\n    PPH_SYSINFO_SECTION section;\n    HDWP deferHandle;\n    ULONG y;\n\n    if (!PhGetClientRect(PhSipWindow, &clientRect))\n        return;\n\n    availableHeight = clientRect.bottom - CurrentParameters.WindowPadding * 2;\n    availableWidth = clientRect.right - CurrentParameters.WindowPadding * 2;\n    graphHeight = (availableHeight - CurrentParameters.GraphPadding * (SectionList->Count - 1)) / SectionList->Count;\n\n    deferHandle = BeginDeferWindowPos(SectionList->Count);\n    y = CurrentParameters.WindowPadding;\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n\n        deferHandle = DeferWindowPos(\n            deferHandle,\n            section->GraphHandle,\n            NULL,\n            CurrentParameters.WindowPadding,\n            y,\n            availableWidth,\n            graphHeight,\n            SWP_NOACTIVATE | SWP_NOZORDER\n            );\n        y += graphHeight + CurrentParameters.GraphPadding;\n\n        section->GraphState.Valid = FALSE;\n    }\n\n    EndDeferWindowPos(deferHandle);\n}\n\nVOID PhSipLayoutSectionView(\n    VOID\n    )\n{\n    RECT clientRect;\n    ULONG availableHeight;\n    ULONG availableWidth;\n    ULONG graphHeight;\n    ULONG i;\n    PPH_SYSINFO_SECTION section;\n    HDWP deferHandle;\n    ULONG y;\n    ULONG containerLeft;\n\n    if (!PhGetClientRect(PhSipWindow, &clientRect))\n        return;\n\n    availableHeight = clientRect.bottom - CurrentParameters.WindowPadding * 2;\n    availableWidth = clientRect.right - CurrentParameters.WindowPadding * 2;\n    graphHeight = (availableHeight - CurrentParameters.SmallGraphPadding * SectionList->Count) / (SectionList->Count + 1);\n\n    if (graphHeight > CurrentParameters.SectionViewGraphHeight)\n        graphHeight = CurrentParameters.SectionViewGraphHeight;\n\n    deferHandle = BeginDeferWindowPos(SectionList->Count * 2 + 3);\n    y = CurrentParameters.WindowPadding;\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n\n        deferHandle = DeferWindowPos(\n            deferHandle,\n            section->GraphHandle,\n            NULL,\n            CurrentParameters.WindowPadding,\n            y,\n            CurrentParameters.SmallGraphWidth,\n            graphHeight,\n            SWP_NOACTIVATE | SWP_NOZORDER\n            );\n\n        deferHandle = DeferWindowPos(\n            deferHandle,\n            section->PanelHandle,\n            NULL,\n            CurrentParameters.WindowPadding + CurrentParameters.SmallGraphWidth,\n            y,\n            CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth,\n            graphHeight,\n            SWP_NOACTIVATE | SWP_NOZORDER\n            );\n        InvalidateRect(section->PanelHandle, NULL, TRUE);\n\n        y += graphHeight + CurrentParameters.SmallGraphPadding;\n\n        section->GraphState.Valid = FALSE;\n    }\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        RestoreSummaryControl,\n        NULL,\n        CurrentParameters.WindowPadding,\n        y,\n        CurrentParameters.SmallGraphWidth + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth,\n        graphHeight,\n        SWP_NOACTIVATE | SWP_NOZORDER\n        );\n    InvalidateRect(RestoreSummaryControl, NULL, TRUE);\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        SeparatorControl,\n        NULL,\n        CurrentParameters.WindowPadding + CurrentParameters.SmallGraphWidth + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth + CurrentParameters.WindowPadding - 7,\n        0,\n        CurrentParameters.SeparatorWidth,\n        CurrentParameters.WindowPadding + availableHeight,\n        SWP_NOACTIVATE | SWP_NOZORDER\n        );\n\n    containerLeft = CurrentParameters.WindowPadding + CurrentParameters.SmallGraphWidth + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth + CurrentParameters.WindowPadding - 7 + CurrentParameters.SeparatorWidth;\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        ContainerControl,\n        NULL,\n        containerLeft,\n        0,\n        clientRect.right - containerLeft,\n        CurrentParameters.WindowPadding + availableHeight,\n        SWP_NOACTIVATE | SWP_NOZORDER\n        );\n\n    EndDeferWindowPos(deferHandle);\n\n    if (CurrentSection && CurrentSection->DialogHandle)\n    {\n        SetWindowPos(\n            CurrentSection->DialogHandle,\n            NULL,\n            CurrentParameters.WindowPadding,\n            CurrentParameters.WindowPadding,\n            clientRect.right - containerLeft - CurrentParameters.WindowPadding - CurrentParameters.WindowPadding,\n            availableHeight,\n            SWP_NOACTIVATE | SWP_NOZORDER\n            );\n    }\n}\n\n_Function_class_(PH_SYSINFO_ENTER_SECTION_VIEW)\nVOID PhSipEnterSectionView(\n    _In_ PPH_SYSINFO_SECTION NewSection\n    )\n{\n    ULONG i;\n    PPH_SYSINFO_SECTION section;\n    BOOLEAN fromSummaryView;\n    PPH_SYSINFO_SECTION oldSection;\n    HDWP deferHandle;\n    HDWP containerDeferHandle;\n\n    if (CurrentSection == NewSection)\n        return;\n\n    fromSummaryView = CurrentView == SysInfoSummaryView;\n    CurrentView = SysInfoSectionView;\n    oldSection = CurrentSection;\n    CurrentSection = NewSection;\n\n    deferHandle = BeginDeferWindowPos(SectionList->Count + 3);\n    containerDeferHandle = BeginDeferWindowPos(SectionList->Count);\n\n    PhSipEnterSectionViewInner(NewSection, fromSummaryView, &deferHandle, &containerDeferHandle);\n    PhSipLayoutSectionView();\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n\n        if (section != NewSection)\n            PhSipEnterSectionViewInner(section, fromSummaryView, &deferHandle, &containerDeferHandle);\n    }\n\n    deferHandle = DeferWindowPos(deferHandle, ContainerControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY);\n    deferHandle = DeferWindowPos(deferHandle, RestoreSummaryControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY);\n    deferHandle = DeferWindowPos(deferHandle, SeparatorControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY);\n\n    EndDeferWindowPos(deferHandle);\n    EndDeferWindowPos(containerDeferHandle);\n\n    if (oldSection)\n        InvalidateRect(oldSection->PanelHandle, NULL, TRUE);\n\n    InvalidateRect(NewSection->PanelHandle, NULL, TRUE);\n\n    if (NewSection->DialogHandle)\n        RedrawWindow(NewSection->DialogHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);\n}\n\nVOID PhSipEnterSectionViewInner(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ BOOLEAN FromSummaryView,\n    _Inout_ HDWP *DeferHandle,\n    _Inout_ HDWP *ContainerDeferHandle\n    )\n{\n    Section->HasFocus = FALSE;\n    Section->Callback(Section, SysInfoViewChanging, UlongToPtr(CurrentView), CurrentSection);\n\n    if (FromSummaryView)\n    {\n        PhSetWindowStyle(Section->GraphHandle, GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL, 0);\n        *DeferHandle = DeferWindowPos(*DeferHandle, Section->PanelHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY);\n    }\n\n    if (Section == CurrentSection && !Section->DialogHandle)\n        PhSipCreateSectionDialog(Section);\n\n    if (Section->DialogHandle)\n    {\n        if (Section == CurrentSection)\n            *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY | SWP_NOREDRAW);\n        else\n            *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY | SWP_NOREDRAW);\n    }\n}\n\n_Function_class_(PH_SYSINFO_RESTORE_SUMMARY_VIEW)\nVOID PhSipRestoreSummaryView(\n    VOID\n    )\n{\n    ULONG i;\n    PPH_SYSINFO_SECTION section;\n\n    if (CurrentView == SysInfoSummaryView)\n        return;\n\n    CurrentView = SysInfoSummaryView;\n    CurrentSection = NULL;\n\n    for (i = 0; i < SectionList->Count; i++)\n    {\n        section = SectionList->Items[i];\n\n        section->Callback(section, SysInfoViewChanging, UlongToPtr(CurrentView), NULL);\n\n        PhSetWindowStyle(section->GraphHandle, GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL, GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL);\n        ShowWindow(section->PanelHandle, SW_HIDE);\n\n        if (section->DialogHandle)\n            ShowWindow(section->DialogHandle, SW_HIDE);\n    }\n\n    ShowWindow(ContainerControl, SW_HIDE);\n    ShowWindow(RestoreSummaryControl, SW_HIDE);\n    ShowWindow(SeparatorControl, SW_HIDE);\n\n    PhSipLayoutSummaryView();\n}\n\nVOID PhSipCreateSectionDialog(\n    _In_ PPH_SYSINFO_SECTION Section\n    )\n{\n    PH_SYSINFO_CREATE_DIALOG createDialog;\n\n    memset(&createDialog, 0, sizeof(PH_SYSINFO_CREATE_DIALOG));\n\n    if (Section->Callback(Section, SysInfoCreateDialog, &createDialog, NULL))\n    {\n        if (!createDialog.CustomCreate)\n        {\n            Section->DialogHandle = PhCreateDialogFromTemplate(\n                ContainerControl,\n                DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD,\n                createDialog.Instance,\n                createDialog.Template,\n                createDialog.DialogProc,\n                createDialog.Parameter\n                );\n\n            if (PhEnableThemeSupport)\n            {\n                PhInitializeWindowTheme(Section->DialogHandle, PhEnableThemeSupport);\n            }\n        }\n    }\n}\n\nLRESULT CALLBACK PhSipGraphHookWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_SYSINFO_SECTION section;\n    WNDPROC oldWndProc;\n\n    if (!(section = PhGetWindowContext(hwnd, 0xF)))\n        return 0;\n\n    oldWndProc = section->GraphWindowProc;\n\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            PhSetWindowProcedure(hwnd, oldWndProc);\n            PhRemoveWindowContext(hwnd, 0xF);\n        }\n        break;\n    case WM_SETFOCUS:\n        {\n            section->HasFocus = TRUE;\n\n            if (CurrentView == SysInfoSummaryView)\n            {\n                Graph_Draw(section->GraphHandle);\n                InvalidateRect(section->GraphHandle, NULL, FALSE);\n            }\n            else\n            {\n                InvalidateRect(section->PanelHandle, NULL, TRUE);\n            }\n        }\n        break;\n    case WM_KILLFOCUS:\n        {\n            section->HasFocus = FALSE;\n\n            if (CurrentView == SysInfoSummaryView)\n            {\n                Graph_Draw(section->GraphHandle);\n                InvalidateRect(section->GraphHandle, NULL, FALSE);\n            }\n            else\n            {\n                InvalidateRect(section->PanelHandle, NULL, TRUE);\n            }\n        }\n        break;\n    case WM_GETDLGCODE:\n        if (wParam == VK_SPACE || wParam == VK_RETURN ||\n            wParam == VK_UP || wParam == VK_DOWN ||\n            wParam == VK_LEFT || wParam == VK_RIGHT)\n            return DLGC_WANTALLKEYS;\n        break;\n    case WM_KEYDOWN:\n        {\n            if (wParam == VK_SPACE || wParam == VK_RETURN)\n            {\n                PhSipEnterSectionView(section);\n            }\n            else if (wParam == VK_UP || wParam == VK_LEFT ||\n                wParam == VK_DOWN || wParam == VK_RIGHT)\n            {\n                ULONG i;\n\n                for (i = 0; i < SectionList->Count; i++)\n                {\n                    if (SectionList->Items[i] == section)\n                    {\n                        if ((wParam == VK_UP || wParam == VK_LEFT) && i > 0)\n                        {\n                            SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[i - 1])->GraphHandle);\n                        }\n                        else if (wParam == VK_DOWN || wParam == VK_RIGHT)\n                        {\n                            if (i < SectionList->Count - 1)\n                                SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[i + 1])->GraphHandle);\n                            else\n                                SetFocus(RestoreSummaryControl);\n                        }\n\n                        break;\n                    }\n                }\n            }\n        }\n        break;\n    case WM_MOUSEMOVE:\n        {\n            TRACKMOUSEEVENT trackMouseEvent;\n\n            trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);\n            trackMouseEvent.dwFlags = TME_LEAVE;\n            trackMouseEvent.hwndTrack = hwnd;\n            trackMouseEvent.dwHoverTime = 0;\n            TrackMouseEvent(&trackMouseEvent);\n\n            if (!(section->GraphHot || section->PanelHot))\n            {\n                section->GraphHot = TRUE;\n            }\n            else\n            {\n                section->GraphHot = TRUE;\n            }\n\n            Graph_Draw(section->GraphHandle);\n            InvalidateRect(section->GraphHandle, NULL, TRUE);\n            InvalidateRect(section->PanelHandle, NULL, TRUE);\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            if (!section->PanelHot)\n            {\n                section->GraphHot = FALSE;\n                InvalidateRect(section->PanelHandle, NULL, TRUE);\n            }\n            else\n            {\n                section->GraphHot = FALSE;\n            }\n\n            section->HasFocus = FALSE;\n\n            if (CurrentView == SysInfoSummaryView)\n            {\n                Graph_Draw(section->GraphHandle);\n                InvalidateRect(section->GraphHandle, NULL, FALSE);\n            }\n        }\n        break;\n    case WM_NCLBUTTONDOWN:\n        {\n            PhSipEnterSectionView(section);\n        }\n        break;\n    case WM_UPDATEUISTATE:\n        {\n            switch (LOWORD(wParam))\n            {\n            case UIS_SET:\n                if (HIWORD(wParam) & UISF_HIDEFOCUS)\n                    section->HideFocus = TRUE;\n                break;\n            case UIS_CLEAR:\n                if (HIWORD(wParam) & UISF_HIDEFOCUS)\n                    section->HideFocus = FALSE;\n                break;\n            case UIS_INITIALIZE:\n                section->HideFocus = !!(HIWORD(wParam) & UISF_HIDEFOCUS);\n                break;\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);\n}\n\nLRESULT CALLBACK PhSipPanelHookWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_SYSINFO_SECTION section;\n    WNDPROC oldWndProc;\n\n    section = PhGetWindowContext(hwnd, 0xF);\n\n    if (section)\n        oldWndProc = section->PanelWindowProc;\n    else\n        oldWndProc = RestoreSummaryControlOldWndProc;\n\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            PhSetWindowProcedure(hwnd, oldWndProc);\n            PhRemoveWindowContext(hwnd, 0xF);\n        }\n        break;\n    case WM_SETFOCUS:\n        {\n            if (!section)\n            {\n                RestoreSummaryControlHasFocus = TRUE;\n                InvalidateRect(hwnd, NULL, TRUE);\n            }\n        }\n        break;\n    case WM_KILLFOCUS:\n        {\n            if (!section)\n            {\n                RestoreSummaryControlHasFocus = FALSE;\n                InvalidateRect(hwnd, NULL, TRUE);\n            }\n        }\n        break;\n    case WM_SETCURSOR:\n        {\n            PhSetCursor(PhLoadCursor(NULL, IDC_HAND));\n        }\n        return TRUE;\n    case WM_GETDLGCODE:\n        if (wParam == VK_SPACE || wParam == VK_RETURN ||\n            wParam == VK_UP || wParam == VK_DOWN ||\n            wParam == VK_LEFT || wParam == VK_RIGHT)\n            return DLGC_WANTALLKEYS;\n        break;\n    case WM_KEYDOWN:\n        {\n            if (wParam == VK_SPACE || wParam == VK_RETURN)\n            {\n                if (section)\n                    PhSipEnterSectionView(section);\n                else\n                    PhSipRestoreSummaryView();\n            }\n            else if (wParam == VK_UP || wParam == VK_LEFT)\n            {\n                if (!section && SectionList->Count != 0)\n                {\n                    SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[SectionList->Count - 1])->GraphHandle);\n                }\n            }\n        }\n        break;\n    case WM_MOUSEMOVE:\n        {\n            TRACKMOUSEEVENT trackMouseEvent;\n\n            trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);\n            trackMouseEvent.dwFlags = TME_LEAVE;\n            trackMouseEvent.hwndTrack = hwnd;\n            trackMouseEvent.dwHoverTime = 0;\n            TrackMouseEvent(&trackMouseEvent);\n\n            if (section)\n            {\n                if (!(section->GraphHot || section->PanelHot))\n                {\n                    section->PanelHot = TRUE;\n                    InvalidateRect(section->PanelHandle, NULL, TRUE);\n                }\n                else\n                {\n                    section->PanelHot = TRUE;\n                }\n            }\n            else\n            {\n                RestoreSummaryControlHot = TRUE;\n                InvalidateRect(RestoreSummaryControl, NULL, TRUE);\n            }\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            if (section)\n            {\n                section->HasFocus = FALSE;\n\n                if (!section->GraphHot)\n                {\n                    section->PanelHot = FALSE;\n                    InvalidateRect(section->PanelHandle, NULL, TRUE);\n                }\n                else\n                {\n                    section->PanelHot = FALSE;\n                }\n            }\n            else\n            {\n                RestoreSummaryControlHasFocus = FALSE;\n                RestoreSummaryControlHot = FALSE;\n                InvalidateRect(RestoreSummaryControl, NULL, TRUE);\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);\n}\n\nVOID PhSipUpdateThemeData(\n    VOID\n    )\n{\n    LONG dpi = PhGetWindowDpi(PhSipWindow);\n\n    if (ThemeData)\n    {\n        PhCloseThemeData(ThemeData);\n        ThemeData = NULL;\n    }\n\n    ThemeData = PhOpenThemeData(PhSipWindow, VSCLASS_TREEVIEW, dpi);\n\n    if (ThemeData)\n    {\n        ThemeHasItemBackground = PhIsThemePartDefined(ThemeData, TVP_TREEITEM, 0);\n    }\n    else\n    {\n        ThemeHasItemBackground = FALSE;\n    }\n}\n\nVOID PhSipSaveWindowState(\n    VOID\n    )\n{\n    WINDOWPLACEMENT placement = { sizeof(placement) };\n\n    GetWindowPlacement(PhSipWindow, &placement);\n\n    if (placement.showCmd == SW_NORMAL)\n        PhSetIntegerSetting(SETTING_SYSINFO_WINDOW_STATE, SW_NORMAL);\n    else if (placement.showCmd == SW_MAXIMIZE)\n        PhSetIntegerSetting(SETTING_SYSINFO_WINDOW_STATE, SW_MAXIMIZE);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhSipSysInfoUpdateHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    PostMessage(PhSipWindow, SI_MSG_SYSINFO_UPDATE, 0, 0);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PhSipSysInfoSettingsCallback(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    PostMessage(PhSipWindow, SI_MSG_SYSINFO_CHANGE_SETTINGS, 0, 0);\n}\n"
  },
  {
    "path": "SystemInformer/syssccpu.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <settings.h>\n#include <sysinfo.h>\n#include <sysinfop.h>\n#include <procprv.h>\n#include <phsettings.h>\n#include <phfirmware.h>\n#include <devguid.h>\n\nstatic PPH_SYSINFO_SECTION CpuSection;\nstatic HWND CpuDialog;\nstatic PH_LAYOUT_MANAGER CpuLayoutManager;\nstatic RECT CpuGraphMargin;\nstatic HWND CpuGraphHandle;\nstatic PH_GRAPH_STATE CpuGraphState;\nstatic HWND *CpusGraphHandle;\nstatic PPH_GRAPH_STATE CpusGraphState;\nstatic BOOLEAN OneGraphPerCpu;\nstatic HWND CpuPanel;\nstatic ULONG CpuTicked;\nstatic ULONG CpuMaxMhz;\nstatic ULONG NumberOfProcessors;\nstatic FLOAT CpuTimerResolution;\nstatic PFLOAT CpuFrequencyInformation;\nstatic FLOAT CpuCurrentFrequency;\nstatic PSYSTEM_INTERRUPT_INFORMATION InterruptInformation;\nstatic PPROCESSOR_POWER_INFORMATION PowerInformation;\nstatic PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION CurrentPerformanceDistribution;\nstatic PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION PreviousPerformanceDistribution;\nstatic PH_LOGICAL_PROCESSOR_INFORMATION LogicalProcessorInformation;\nstatic PH_UINT32_DELTA ContextSwitchesDelta;\nstatic PH_UINT32_DELTA InterruptsDelta;\nstatic PH_UINT64_DELTA DpcsDelta;\nstatic PH_UINT32_DELTA SystemCallsDelta;\nstatic HWND CpuPanelUtilizationLabel;\nstatic HWND CpuPanelSpeedLabel;\nstatic HWND CpuVirtualizationLabel;\nstatic HWND CpuPanelProcessesLabel;\nstatic HWND CpuPanelThreadsLabel;\nstatic HWND CpuPanelHandlesLabel;\nstatic HWND CpuPanelUptimeLabel;\nstatic HWND CpuPanelContextSwitchesLabel;\nstatic HWND CpuPanelInterruptDeltaLabel;\nstatic HWND CpuPanelDpcDeltaLabel;\nstatic HWND CpuPanelSystemCallsDeltaLabel;\nstatic HWND CpuPanelCoresLabel;\nstatic HWND CpuPanelSocketsLabel;\nstatic HWND CpuPanelLogicalLabel;\nstatic HWND CpuPanelLatencyLabel;\nstatic ULONG64 CpuL1CacheSize;\nstatic ULONG64 CpuL2CacheSize;\nstatic ULONG64 CpuL3CacheSize;\n\n_Function_class_(PH_SYSINFO_SECTION_CALLBACK)\nBOOLEAN PhSipCpuSectionCallback(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ PH_SYSINFO_SECTION_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case SysInfoCreate:\n        {\n            CpuSection = Section;\n        }\n        return TRUE;\n    case SysInfoDestroy:\n        {\n            if (CpuDialog)\n            {\n                PhSipUninitializeCpuDialog();\n                CpuDialog = NULL;\n            }\n        }\n        return TRUE;\n    case SysInfoTick:\n        {\n            if (CpuDialog)\n            {\n                PhSipTickCpuDialog();\n            }\n        }\n        return TRUE;\n    case SysInfoViewChanging:\n        {\n            PH_SYSINFO_VIEW_TYPE view = (PH_SYSINFO_VIEW_TYPE)PtrToUlong(Parameter1);\n            PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Parameter2;\n\n            if (view == SysInfoSummaryView || section != Section)\n                return TRUE;\n\n            if (OneGraphPerCpu)\n            {\n                for (ULONG i = 0; i < NumberOfProcessors; i++)\n                {\n                    if (CpusGraphHandle && CpusGraphHandle[i] && CpusGraphState)\n                    {\n                        CpusGraphState[i].Valid = FALSE;\n                        CpusGraphState[i].TooltipIndex = ULONG_MAX;\n                        Graph_Draw(CpusGraphHandle[i]);\n                    }\n                }\n            }\n            else\n            {\n                if (CpuGraphHandle)\n                {\n                    CpuGraphState.Valid = FALSE;\n                    CpuGraphState.TooltipIndex = ULONG_MAX;\n                    Graph_Draw(CpuGraphHandle);\n                }\n            }\n        }\n        return TRUE;\n    case SysInfoCreateDialog:\n        {\n            PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;\n\n            createDialog->Instance = PhInstanceHandle;\n            createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_CPU);\n            createDialog->DialogProc = PhSipCpuDialogProc;\n        }\n        return TRUE;\n    case SysInfoGraphGetDrawInfo:\n        {\n            PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;\n\n            drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_USE_LINE_2 | PH_GRAPH_LABEL_MAX_Y;\n            Section->Parameters->ColorSetupFunction(drawInfo, PhCsColorCpuKernel, PhCsColorCpuUser, Section->Parameters->WindowDpi);\n            PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, PhCpuKernelHistory.Count);\n\n            if (!Section->GraphState.Valid)\n            {\n                PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory, Section->GraphState.Data1, drawInfo->LineDataCount);\n                PhCopyCircularBuffer_FLOAT(&PhCpuUserHistory, Section->GraphState.Data2, drawInfo->LineDataCount);\n\n                if (PhCsEnableGraphMaxScale)\n                {\n                    FLOAT max = 0;\n\n                    if (PhCsEnableAvxSupport && drawInfo->LineDataCount > 128)\n                    {\n                        max = PhAddPlusMaxMemorySingles(\n                            Section->GraphState.Data1,\n                            Section->GraphState.Data2,\n                            drawInfo->LineDataCount\n                            );\n                    }\n                    else\n                    {\n                        for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                        {\n                            FLOAT data = Section->GraphState.Data1[i] + Section->GraphState.Data2[i];\n\n                            if (max < data)\n                                max = data;\n                        }\n                    }\n\n                    if (max != 0)\n                    {\n                        PhDivideSinglesBySingle(Section->GraphState.Data1, max, drawInfo->LineDataCount);\n                        PhDivideSinglesBySingle(Section->GraphState.Data2, max, drawInfo->LineDataCount);\n                    }\n\n                    drawInfo->LabelYFunction = PhSiDoubleLabelYFunction;\n                    drawInfo->LabelYFunctionParameter = max;\n                }\n                else\n                {\n                    drawInfo->LabelYFunction = PhSiDoubleLabelYFunction;\n                    drawInfo->LabelYFunctionParameter = 1.0f;\n                }\n\n                Section->GraphState.Valid = TRUE;\n            }\n        }\n        return TRUE;\n    case SysInfoGraphGetTooltipText:\n        {\n            PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;\n            FLOAT cpuKernel;\n            FLOAT cpuUser;\n            PH_FORMAT format[9];\n\n            cpuKernel = PhGetItemCircularBuffer_FLOAT(&PhCpuKernelHistory, getTooltipText->Index);\n            cpuUser = PhGetItemCircularBuffer_FLOAT(&PhCpuUserHistory, getTooltipText->Index);\n\n            // %.2f%% (K: %.2f%%, U: %.2f%%)\\n%s\\n%s\n            PhInitFormatF(&format[0], (cpuKernel + cpuUser) * 100, PhMaxPrecisionUnit);\n            PhInitFormatS(&format[1], L\"% (K: \");\n            PhInitFormatF(&format[2], cpuKernel * 100, PhMaxPrecisionUnit);\n            PhInitFormatS(&format[3], L\"%, U: \");\n            PhInitFormatF(&format[4], cpuUser * 100, PhMaxPrecisionUnit);\n            PhInitFormatS(&format[5], L\"%)\");\n            PhInitFormatSR(&format[6], PH_AUTO_T(PH_STRING, PhSipGetMaxCpuString(getTooltipText->Index))->sr);\n            PhInitFormatC(&format[7], L'\\n');\n            PhInitFormatSR(&format[8], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n            PhMoveReference(&Section->GraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 160));\n            getTooltipText->Text = Section->GraphState.TooltipText->sr;\n        }\n        return TRUE;\n    case SysInfoGraphDrawPanel:\n        {\n            PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;\n            PH_FORMAT format[2];\n\n            // %.2f%%\n            PhInitFormatF(&format[0], (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhMaxPrecisionUnit);\n            PhInitFormatC(&format[1], L'%');\n\n            drawPanel->Title = PhCreateString(L\"CPU\");\n            drawPanel->SubTitle = PhFormat(format, RTL_NUMBER_OF(format), 16);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhSipInitializeCpuDialog(\n    VOID\n    )\n{\n    PhInitializeDelta(&ContextSwitchesDelta);\n    PhInitializeDelta(&InterruptsDelta);\n    PhInitializeDelta(&DpcsDelta);\n    PhInitializeDelta(&SystemCallsDelta);\n\n    NumberOfProcessors = PhSystemProcessorInformation.NumberOfProcessors;\n    CpusGraphHandle = PhAllocate(sizeof(HWND) * NumberOfProcessors);\n    CpusGraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * NumberOfProcessors);\n    InterruptInformation = PhAllocate(sizeof(SYSTEM_INTERRUPT_INFORMATION) * NumberOfProcessors);\n    PowerInformation = PhAllocate(sizeof(PROCESSOR_POWER_INFORMATION) * NumberOfProcessors);\n\n    if (PhGetIntegerSetting(SETTING_SYSINFO_SHOW_CPU_SPEED_PER_CPU))\n    {\n        CpuFrequencyInformation = PhAllocateZero(sizeof(FLOAT) * NumberOfProcessors);\n    }\n\n    PhInitializeGraphState(&CpuGraphState);\n\n    for (ULONG i = 0; i < NumberOfProcessors; i++)\n        PhInitializeGraphState(&CpusGraphState[i]);\n\n    CpuTicked = 0;\n    CpuMaxMhz = 0;\n\n    PhSipUpdateTimerResolution();\n    PhSipUpdateProcessorInformation();\n    PhSipUpdateProcessorFrequency();\n\n    CurrentPerformanceDistribution = NULL;\n    PhGetSystemProcessorPerformanceDistribution(&CurrentPerformanceDistribution);\n\n    PhGetSystemLogicalProcessorRelationInformation(&LogicalProcessorInformation);\n}\n\nVOID PhSipUninitializeCpuDialog(\n    VOID\n    )\n{\n    ULONG i;\n\n    PhDeleteGraphState(&CpuGraphState);\n\n    for (i = 0; i < NumberOfProcessors; i++)\n        PhDeleteGraphState(&CpusGraphState[i]);\n\n    PhFree(CpusGraphHandle);\n    PhFree(CpusGraphState);\n    PhFree(InterruptInformation);\n    PhFree(PowerInformation);\n\n    // Note: Required for SysInfoViewChanging (dmex)\n    NumberOfProcessors = 0;\n    CpuGraphHandle = NULL;\n    CpusGraphHandle = NULL;\n    CpusGraphState = NULL;\n    InterruptInformation = NULL;\n    PowerInformation = NULL;\n\n    if (CurrentPerformanceDistribution)\n    {\n        PhFree(CurrentPerformanceDistribution);\n        CurrentPerformanceDistribution = NULL;\n    }\n    if (PreviousPerformanceDistribution)\n    {\n        PhFree(PreviousPerformanceDistribution);\n        PreviousPerformanceDistribution = NULL;\n    }\n\n    PhSetIntegerSetting(SETTING_SYSINFO_WINDOW_ONE_GRAPH_PER_CPU, OneGraphPerCpu);\n}\n\nVOID PhSipTickCpuDialog(\n    VOID\n    )\n{\n    ULONG64 dpcCount;\n\n    PhSipUpdateInterruptInformation(&dpcCount);\n\n    PhUpdateDelta(&ContextSwitchesDelta, PhPerfInformation.ContextSwitches);\n    PhUpdateDelta(&InterruptsDelta, PhCpuTotals.InterruptCount);\n    PhUpdateDelta(&DpcsDelta, dpcCount);\n    PhUpdateDelta(&SystemCallsDelta, PhPerfInformation.SystemCalls);\n\n    PhSipUpdateTimerResolution();\n    PhSipUpdateProcessorInformation();\n    PhSipUpdateProcessorPerformanceDistribution();\n    //PhGetSystemLogicalProcessorRelationInformation(&LogicalProcessorInformation);\n\n    if (CpuTicked < 2)\n        CpuTicked++;\n\n    PhSipUpdateCpuGraphs();\n    PhSipUpdateCpuPanel();\n}\n\nINT_PTR CALLBACK PhSipCpuDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_LAYOUT_ITEM graphItem;\n            PPH_LAYOUT_ITEM panelItem;\n            PPH_STRING brandString;\n            HWND labelHandle;\n\n            PhSipInitializeCpuDialog();\n\n            CpuDialog = hwndDlg;\n            labelHandle = GetDlgItem(hwndDlg, IDC_CPUNAME);\n\n            PhInitializeLayoutManager(&CpuLayoutManager, hwndDlg);\n            PhAddLayoutItem(&CpuLayoutManager, labelHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);\n            graphItem = PhAddLayoutItem(&CpuLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);\n            panelItem = PhAddLayoutItem(&CpuLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            CpuGraphMargin = graphItem->Margin;\n\n            SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), CpuSection->Parameters->LargeFont, FALSE);\n            SetWindowFont(labelHandle, CpuSection->Parameters->MediumFont, FALSE);\n\n            brandString = PhSipGetCpuBrandString();\n            PhSetWindowText(labelHandle, PhGetStringOrEmpty(brandString));\n            PhClearReference(&brandString);\n\n            CpuPanel = PhCreateDialog(PhInstanceHandle, MAKEINTRESOURCE(IDD_SYSINFO_CPUPANEL), hwndDlg, PhSipCpuPanelDialogProc, NULL);\n            ShowWindow(CpuPanel, SW_SHOW);\n            PhAddLayoutItemEx(&CpuLayoutManager, CpuPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, &panelItem->Margin);\n\n            PhSipCreateCpuGraphs();\n\n            if (NumberOfProcessors != 1)\n            {\n                OneGraphPerCpu = (BOOLEAN)PhGetIntegerSetting(SETTING_SYSINFO_WINDOW_ONE_GRAPH_PER_CPU);\n                Button_SetCheck(GetDlgItem(CpuPanel, IDC_ONEGRAPHPERCPU), OneGraphPerCpu ? BST_CHECKED : BST_UNCHECKED);\n                PhSipSetOneGraphPerCpu();\n            }\n            else\n            {\n                OneGraphPerCpu = FALSE;\n                EnableWindow(GetDlgItem(CpuPanel, IDC_ONEGRAPHPERCPU), FALSE);\n                PhSipSetOneGraphPerCpu();\n            }\n\n            PhSipUpdateCpuGraphs();\n            PhSipUpdateCpuPanel();\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDeleteLayoutManager(&CpuLayoutManager);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            if (CpuSection->Parameters->LargeFont)\n            {\n                SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), CpuSection->Parameters->LargeFont, FALSE);\n            }\n\n            if (CpuSection->Parameters->MediumFont)\n            {\n                SetWindowFont(GetDlgItem(hwndDlg, IDC_CPUNAME), CpuSection->Parameters->MediumFont, FALSE);\n            }\n\n            if (OneGraphPerCpu)\n            {\n                for (ULONG i = 0; i < NumberOfProcessors; i++)\n                {\n                    CpusGraphState[i].Valid = FALSE;\n                    CpusGraphState[i].TooltipIndex = ULONG_MAX;\n                }\n            }\n            else\n            {\n                CpuGraphState.Valid = FALSE;\n                CpuGraphState.TooltipIndex = ULONG_MAX;\n            }\n\n            PhLayoutManagerUpdate(&CpuLayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&CpuLayoutManager);\n            PhSipLayoutCpuGraphs();\n        }\n        break;\n    case WM_SIZE:\n        {\n            if (OneGraphPerCpu)\n            {\n                for (ULONG i = 0; i < NumberOfProcessors; i++)\n                {\n                    CpusGraphState[i].Valid = FALSE;\n                    CpusGraphState[i].TooltipIndex = ULONG_MAX;\n                }\n            }\n            else\n            {\n                CpuGraphState.Valid = FALSE;\n                CpuGraphState.TooltipIndex = ULONG_MAX;\n            }\n\n            PhLayoutManagerLayout(&CpuLayoutManager);\n            PhSipLayoutCpuGraphs();\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nINT_PTR CALLBACK PhSipCpuPanelDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            CpuL1CacheSize = 0;\n            CpuL2CacheSize = 0;\n            CpuL3CacheSize = 0;\n\n            CpuPanelUtilizationLabel = GetDlgItem(hwndDlg, IDC_UTILIZATION);\n            CpuPanelSpeedLabel = GetDlgItem(hwndDlg, IDC_SPEED);\n            CpuVirtualizationLabel = GetDlgItem(hwndDlg, IDC_VIRTUALIZATION);\n            CpuPanelProcessesLabel = GetDlgItem(hwndDlg, IDC_ZPROCESSES_V);\n            CpuPanelThreadsLabel = GetDlgItem(hwndDlg, IDC_ZTHREADS_V);\n            CpuPanelHandlesLabel = GetDlgItem(hwndDlg, IDC_ZHANDLES_V);\n            CpuPanelUptimeLabel = GetDlgItem(hwndDlg, IDC_ZUPTIME_V);\n            CpuPanelContextSwitchesLabel = GetDlgItem(hwndDlg, IDC_ZCONTEXTSWITCHESDELTA_V);\n            CpuPanelInterruptDeltaLabel = GetDlgItem(hwndDlg, IDC_ZINTERRUPTSDELTA_V);\n            CpuPanelDpcDeltaLabel = GetDlgItem(hwndDlg, IDC_ZDPCSDELTA_V);\n            CpuPanelSystemCallsDeltaLabel = GetDlgItem(hwndDlg, IDC_ZSYSTEMCALLSDELTA_V);\n            CpuPanelCoresLabel = GetDlgItem(hwndDlg, IDC_ZCORES);\n            CpuPanelSocketsLabel = GetDlgItem(hwndDlg, IDC_ZSOCKETS);\n            CpuPanelLogicalLabel = GetDlgItem(hwndDlg, IDC_ZLOGICAL);\n            CpuPanelLatencyLabel = GetDlgItem(hwndDlg, IDC_ZLATENCY);\n\n            SetWindowFont(CpuPanelUtilizationLabel, CpuSection->Parameters->MediumFont, FALSE);\n            SetWindowFont(CpuPanelSpeedLabel, CpuSection->Parameters->MediumFont, FALSE);\n            SetWindowFont(CpuVirtualizationLabel, CpuSection->Parameters->MediumFont, FALSE);\n\n            PhQueueUserWorkItem(PhSipCpuSMBIOSWorkRoutine, NULL);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_ONEGRAPHPERCPU:\n                {\n                    OneGraphPerCpu = Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED;\n                    PhSipLayoutCpuGraphs();\n                    PhSipSetOneGraphPerCpu();\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            if (CpuSection->Parameters->MediumFont)\n            {\n                SetWindowFont(CpuPanelUtilizationLabel, CpuSection->Parameters->MediumFont, FALSE);\n            }\n\n            if (CpuSection->Parameters->MediumFont)\n            {\n                SetWindowFont(CpuPanelSpeedLabel, CpuSection->Parameters->MediumFont, FALSE);\n            }\n\n            PhSipLayoutCpuGraphs();\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhSipCreateCpuGraphs(\n    VOID\n    )\n{\n    PH_GRAPH_CREATEPARAMS graphCreateParams;\n\n    memset(&graphCreateParams, 0, sizeof(PH_GRAPH_CREATEPARAMS));\n    graphCreateParams.Size = sizeof(PH_GRAPH_CREATEPARAMS);\n    graphCreateParams.Callback = PhSipCpuGraphCallback;\n    graphCreateParams.Context = UlongToPtr(ULONG_MAX);\n\n    CpuGraphHandle = PhCreateWindow(\n        PH_GRAPH_CLASSNAME,\n        NULL,\n        WS_CHILD | WS_BORDER,\n        0,\n        0,\n        0,\n        0,\n        CpuDialog,\n        NULL,\n        NULL,\n        &graphCreateParams\n        );\n\n    if (PhEnableTooltipSupport)\n    {\n        Graph_SetTooltip(CpuGraphHandle, TRUE);\n    }\n\n    for (ULONG i = 0; i < NumberOfProcessors; i++)\n    {\n        graphCreateParams.Context = UlongToPtr(i);\n\n        CpusGraphHandle[i] = PhCreateWindow(\n            PH_GRAPH_CLASSNAME,\n            NULL,\n            WS_CHILD | WS_BORDER,\n            0,\n            0,\n            0,\n            0,\n            CpuDialog,\n            NULL,\n            NULL,\n            &graphCreateParams\n            );\n\n        if (PhEnableTooltipSupport)\n        {\n            Graph_SetTooltip(CpusGraphHandle[i], TRUE);\n        }\n    }\n}\n\nVOID PhSipLayoutCpuGraphs(\n    VOID\n    )\n{\n    RECT clientRect;\n    RECT rect;\n    HDWP deferHandle;\n\n    rect = CpuGraphMargin;\n    PhGetSizeDpiValue(&rect, CpuSection->Parameters->WindowDpi, TRUE);\n\n    if (!PhGetClientRect(CpuDialog, &clientRect))\n        return;\n\n    deferHandle = BeginDeferWindowPos(OneGraphPerCpu ? NumberOfProcessors : 1);\n\n    if (!OneGraphPerCpu)\n    {\n        deferHandle = DeferWindowPos(\n            deferHandle,\n            CpuGraphHandle,\n            NULL,\n            rect.left,\n            rect.top,\n            clientRect.right - rect.left - rect.right,\n            clientRect.bottom - rect.top - rect.bottom,\n            SWP_NOACTIVATE | SWP_NOZORDER\n            );\n    }\n    else\n    {\n        ULONG numberOfRows = 1;\n        ULONG numberOfColumns = NumberOfProcessors;\n\n        for (ULONG rows = 2; rows <= NumberOfProcessors / rows; rows++)\n        {\n            if (NumberOfProcessors % rows != 0)\n                continue;\n\n            numberOfRows = rows;\n            numberOfColumns = NumberOfProcessors / rows;\n        }\n\n        if (numberOfRows == 1)\n        {\n            numberOfRows = (ULONG)sqrt(NumberOfProcessors);\n            numberOfColumns = (NumberOfProcessors + numberOfRows - 1) / numberOfRows;\n        }\n\n        ULONG numberOfYPaddings = numberOfRows - 1;\n        ULONG numberOfXPaddings = numberOfColumns - 1;\n\n        ULONG cellHeight = (clientRect.bottom - rect.top - rect.bottom - CpuSection->Parameters->CpuPadding * numberOfYPaddings) / numberOfRows;\n        ULONG y = rect.top;\n        ULONG cellWidth;\n        ULONG x;\n        ULONG i = 0;\n\n        for (ULONG row = 0; row < numberOfRows; row++)\n        {\n            // Give the last row the remaining space; the height we calculated might be off by a few\n            // pixels due to integer division.\n            if (row == numberOfRows - 1)\n                cellHeight = clientRect.bottom - rect.bottom - y;\n\n            cellWidth = (clientRect.right - rect.left - rect.right - CpuSection->Parameters->CpuPadding * numberOfXPaddings) / numberOfColumns;\n            x = rect.left;\n\n            for (ULONG column = 0; column < numberOfColumns; column++)\n            {\n                // Give the last cell the remaining space; the width we calculated might be off by a few\n                // pixels due to integer division.\n                if (column == numberOfColumns - 1)\n                    cellWidth = clientRect.right - rect.right - x;\n\n                if (i < NumberOfProcessors)\n                {\n                    deferHandle = DeferWindowPos(\n                        deferHandle,\n                        CpusGraphHandle[i],\n                        NULL,\n                        x,\n                        y,\n                        cellWidth,\n                        cellHeight,\n                        SWP_NOACTIVATE | SWP_NOZORDER\n                        );\n                    i++;\n                }\n\n                x += cellWidth + CpuSection->Parameters->CpuPadding;\n            }\n\n            y += cellHeight + CpuSection->Parameters->CpuPadding;\n        }\n    }\n\n    EndDeferWindowPos(deferHandle);\n}\n\nVOID PhSipSetOneGraphPerCpu(\n    VOID\n    )\n{\n    ShowWindow(CpuGraphHandle, !OneGraphPerCpu ? SW_SHOW : SW_HIDE);\n\n    for (ULONG i = 0; i < NumberOfProcessors; i++)\n    {\n        ShowWindow(CpusGraphHandle[i], OneGraphPerCpu ? SW_SHOW : SW_HIDE);\n    }\n}\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipCpuGraphCallback(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    switch (GraphMessage)\n    {\n    case GCN_GETDRAWINFO:\n        {\n            PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Parameter1;\n            PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;\n            ULONG index = PtrToUlong(Context);\n\n            drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_USE_LINE_2 | (PhCsEnableGraphMaxText ? PH_GRAPH_LABEL_MAX_Y : 0);\n            PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorCpuKernel, PhCsColorCpuUser, CpuSection->Parameters->WindowDpi);\n\n            if (index == ULONG_MAX)\n            {\n                PhGraphStateGetDrawInfo(\n                    &CpuGraphState,\n                    getDrawInfo,\n                    PhCpuKernelHistory.Count\n                    );\n\n                if (!CpuGraphState.Valid)\n                {\n                    PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory, CpuGraphState.Data1, drawInfo->LineDataCount);\n                    PhCopyCircularBuffer_FLOAT(&PhCpuUserHistory, CpuGraphState.Data2, drawInfo->LineDataCount);\n\n                    if (PhCsEnableGraphMaxScale)\n                    {\n                        FLOAT max = 0;\n\n                        if (PhCsEnableAvxSupport && drawInfo->LineDataCount > 128)\n                        {\n                            max = PhAddPlusMaxMemorySingles(\n                                CpuGraphState.Data1,\n                                CpuGraphState.Data2,\n                                drawInfo->LineDataCount\n                                );\n                        }\n                        else\n                        {\n                            for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                            {\n                                FLOAT data = CpuGraphState.Data1[i] + CpuGraphState.Data2[i];\n\n                                if (max < data)\n                                    max = data;\n                            }\n                        }\n\n                        if (max != 0)\n                        {\n                            PhDivideSinglesBySingle(CpuGraphState.Data1, max, drawInfo->LineDataCount);\n                            PhDivideSinglesBySingle(CpuGraphState.Data2, max, drawInfo->LineDataCount);\n                        }\n\n                        drawInfo->LabelYFunction = PhSiDoubleLabelYFunction;\n                        drawInfo->LabelYFunctionParameter = max;\n                    }\n                    else\n                    {\n                        drawInfo->LabelYFunction = PhSiDoubleLabelYFunction;\n                        drawInfo->LabelYFunctionParameter = 1.0f;\n                    }\n\n                    CpuGraphState.Valid = TRUE;\n                }\n            }\n            else\n            {\n                PhGraphStateGetDrawInfo(\n                    &CpusGraphState[index],\n                    getDrawInfo,\n                    PhCpuKernelHistory.Count\n                    );\n\n                if (!CpusGraphState[index].Valid)\n                {\n                    PhCopyCircularBuffer_FLOAT(&PhCpusKernelHistory[index], CpusGraphState[index].Data1, drawInfo->LineDataCount);\n                    PhCopyCircularBuffer_FLOAT(&PhCpusUserHistory[index], CpusGraphState[index].Data2, drawInfo->LineDataCount);\n\n                    if (PhCsEnableGraphMaxScale)\n                    {\n                        FLOAT max = 0;\n\n                        if (PhCsEnableAvxSupport && drawInfo->LineDataCount > 128)\n                        {\n                            max = PhAddPlusMaxMemorySingles(\n                                CpusGraphState[index].Data1,\n                                CpusGraphState[index].Data2,\n                                drawInfo->LineDataCount\n                                );\n                        }\n                        else\n                        {\n                            for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                            {\n                                FLOAT data = CpusGraphState[index].Data1[i] + CpusGraphState[index].Data2[i];\n\n                                if (max < data)\n                                    max = data;\n                            }\n                        }\n\n                        if (max != 0)\n                        {\n                            PhDivideSinglesBySingle(CpusGraphState[index].Data1, max, drawInfo->LineDataCount);\n                            PhDivideSinglesBySingle(CpusGraphState[index].Data2, max, drawInfo->LineDataCount);\n                        }\n\n                        drawInfo->LabelYFunction = PhSiDoubleLabelYFunction;\n                        drawInfo->LabelYFunctionParameter = max;\n                    }\n                    else\n                    {\n                        drawInfo->LabelYFunction = PhSiDoubleLabelYFunction;\n                        drawInfo->LabelYFunctionParameter = 1.0f;\n                    }\n\n                    CpusGraphState[index].Valid = TRUE;\n                }\n\n                if (PhCsGraphShowText)\n                {\n                    HDC hdc;\n                    FLOAT cpuKernel;\n                    FLOAT cpuUser;\n                    PH_FORMAT format[11];\n\n                    cpuKernel = PhGetItemCircularBuffer_FLOAT(&PhCpusKernelHistory[index], 0);\n                    cpuUser = PhGetItemCircularBuffer_FLOAT(&PhCpusUserHistory[index], 0);\n\n                    // %.2f%% (K: %.2f%%, U: %.2f%%)\n                    PhInitFormatF(&format[0], (cpuKernel + cpuUser) * 100, PhMaxPrecisionUnit);\n                    PhInitFormatS(&format[1], L\"% (K: \");\n                    PhInitFormatF(&format[2], cpuKernel * 100, PhMaxPrecisionUnit);\n                    PhInitFormatS(&format[3], L\"%, U: \");\n                    PhInitFormatF(&format[4], cpuUser * 100, PhMaxPrecisionUnit);\n\n                    if (CpuFrequencyInformation)\n                    {\n                        PhInitFormatS(&format[5], L\"%)\\r\\n\");\n                        PhInitFormatF(&format[6], CpuFrequencyInformation[index] / 1000, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[7], L\" GHz\");\n                        PhInitFormatS(&format[8], L\" (\");\n                        PhInitFormatFD(&format[9], 1000 / CpuFrequencyInformation[index], 3); // ns per cycle\n                        PhInitFormatS(&format[10], L\" \\u00B5s)\");\n                        PhMoveReference(&CpusGraphState[index].Text, PhFormat(format, RTL_NUMBER_OF(format), 0));\n\n                        hdc = Graph_GetBufferedContext(CpusGraphHandle[index]);\n                        PhSetGraphText2(\n                            hdc,\n                            drawInfo,\n                            &CpusGraphState[index].Text->sr,\n                            &PhNormalGraphTextMargin,\n                            &PhNormalGraphTextPadding,\n                            PH_ALIGN_TOP | PH_ALIGN_LEFT\n                            );\n                    }\n                    else\n                    {\n                        PhInitFormatS(&format[5], L\"%) \");\n                        PhMoveReference(&CpusGraphState[index].Text, PhFormat(format, 6, 0));\n\n                        hdc = Graph_GetBufferedContext(CpusGraphHandle[index]);\n                        PhSetGraphText(\n                            hdc,\n                            drawInfo,\n                            &CpusGraphState[index].Text->sr,\n                            &PhNormalGraphTextMargin,\n                            &PhNormalGraphTextPadding,\n                            PH_ALIGN_TOP | PH_ALIGN_LEFT\n                            );\n                    }\n                }\n                else\n                {\n                    drawInfo->Text.Buffer = NULL;\n                }\n            }\n        }\n        break;\n    case GCN_GETTOOLTIPTEXT:\n        {\n            PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Parameter1;\n            ULONG index = PtrToUlong(Context);\n\n            if (getTooltipText->Index < getTooltipText->TotalCount)\n            {\n                if (index == ULONG_MAX)\n                {\n                    if (CpuGraphState.TooltipIndex != getTooltipText->Index)\n                    {\n                        FLOAT cpuKernel;\n                        FLOAT cpuUser;\n                        PH_FORMAT format[9];\n\n                        cpuKernel = PhGetItemCircularBuffer_FLOAT(&PhCpuKernelHistory, getTooltipText->Index);\n                        cpuUser = PhGetItemCircularBuffer_FLOAT(&PhCpuUserHistory, getTooltipText->Index);\n\n                        // %.2f%% (K: %.2f%%, U: %.2f%%)\\n%s\\n%s\n                        PhInitFormatF(&format[0], (cpuKernel + cpuUser) * 100, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[1], L\"% (K: \");\n                        PhInitFormatF(&format[2], cpuKernel * 100, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[3], L\"%, U: \");\n                        PhInitFormatF(&format[4], cpuUser * 100, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[5], L\"%)\");\n                        PhInitFormatSR(&format[6], PH_AUTO_T(PH_STRING, PhSipGetMaxCpuString(getTooltipText->Index))->sr);\n                        PhInitFormatC(&format[7], L'\\n');\n                        PhInitFormatSR(&format[8], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n                        PhMoveReference(&CpuGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 160));\n                    }\n\n                    getTooltipText->Text = CpuGraphState.TooltipText->sr;\n                }\n                else\n                {\n                    if (CpusGraphState[index].TooltipIndex != getTooltipText->Index)\n                    {\n                        FLOAT cpuKernel;\n                        FLOAT cpuUser;\n                        PCPH_STRINGREF cpuType;\n                        PH_FORMAT format[20];\n                        ULONG count = 0;\n\n                        cpuKernel = PhGetItemCircularBuffer_FLOAT(&PhCpusKernelHistory[index], getTooltipText->Index);\n                        cpuUser = PhGetItemCircularBuffer_FLOAT(&PhCpusUserHistory[index], getTooltipText->Index);\n\n                        // %.2f%% (K: %.2f%%, U: %.2f%%)%s\\n%s\n                        PhInitFormatF(&format[count++], (cpuKernel + cpuUser) * 100, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[count++], L\"% (K: \");\n                        PhInitFormatF(&format[count++], cpuKernel * 100, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[count++], L\"%, U: \");\n                        PhInitFormatF(&format[count++], cpuUser * 100, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[count++], L\"%)\");\n                        PhInitFormatSR(&format[count++], PH_AUTO_T(PH_STRING, PhSipGetMaxCpuString(getTooltipText->Index))->sr);\n                        PhInitFormatS(&format[count++], L\"\\nCPU \");\n\n                        if (PhSystemProcessorInformation.SingleProcessorGroup)\n                        {\n                            PhInitFormatU(&format[count++], index);\n                            PhInitFormatS(&format[count++], L\", Core \");\n                            PhInitFormatU(&format[count++], PhSipGetProcessorRelationshipIndex(RelationProcessorCore, index));\n                            PhInitFormatS(&format[count++], L\", Socket \");\n                            PhInitFormatU(&format[count++], PhSipGetProcessorRelationshipIndex(RelationProcessorPackage, index));\n                        }\n                        else\n                        {\n                            PH_PROCESSOR_NUMBER processorNumber;\n                            USHORT processorNode;\n\n                            if (NT_SUCCESS(PhGetProcessorNumberFromIndex(index, &processorNumber)))\n                            {\n                                PhInitFormatU(&format[count++], processorNumber.Number);\n                                PhInitFormatS(&format[count++], L\", Group \");\n                                PhInitFormatU(&format[count++], processorNumber.Group);\n\n                                if (PhGetNumaProcessorNode(&processorNumber, &processorNode))\n                                {\n                                    PhInitFormatS(&format[count++], L\", Node \");\n                                    PhInitFormatU(&format[count++], processorNode);\n                                }\n                                else\n                                {\n                                    PhInitFormatS(&format[count++], L\", Node \");\n                                    PhInitFormatU(&format[count++], 0);\n                                }\n                            }\n                            else\n                            {\n                                PhInitFormatU(&format[count++], index);\n                                PhInitFormatS(&format[count++], L\", Group \");\n                                PhInitFormatU(&format[count++], ULONG_MAX);\n                                PhInitFormatS(&format[count++], L\", Node \");\n                                PhInitFormatU(&format[count++], ULONG_MAX);\n                            }\n                        }\n\n                        if (cpuType = PhGetHybridProcessorType(index))\n                        {\n                            PhInitFormatS(&format[count++], L\", \");\n                            PhInitFormatSR(&format[count++], *cpuType);\n                            PhInitFormatS(&format[count++], L\"\\n\");\n\n                            if (PhIsCoreParked(index))\n                                PhInitFormatS(&format[count++], L\"Parked\\n\");\n                        }\n                        else\n                        {\n                            PhInitFormatS(&format[count++], L\"\\n\");\n\n                            if (PhIsCoreParked(index))\n                                PhInitFormatS(&format[count++], L\"Parked\\n\");\n                        }\n\n                        PhInitFormatSR(&format[count++], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n                        PhMoveReference(&CpusGraphState[index].TooltipText, PhFormat(format, count, 0));\n                    }\n\n                    getTooltipText->Text = CpusGraphState[index].TooltipText->sr;\n                }\n            }\n        }\n        break;\n    case GCN_MOUSEEVENT:\n        {\n            PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Parameter1;\n            PPH_PROCESS_RECORD record;\n\n            record = NULL;\n\n            if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)\n            {\n                record = PhSipReferenceMaxCpuRecord(mouseEvent->Index);\n            }\n\n            if (record)\n            {\n                PhShowProcessRecordDialog(CpuDialog, record);\n                PhDereferenceProcessRecord(record);\n            }\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\nVOID PhSipUpdateCpuGraphs(\n    VOID\n    )\n{\n    CpuGraphState.Valid = FALSE;\n    CpuGraphState.TooltipIndex = ULONG_MAX;\n    Graph_Update(CpuGraphHandle);\n\n    for (ULONG i = 0; i < NumberOfProcessors; i++)\n    {\n        CpusGraphState[i].Valid = FALSE;\n        CpusGraphState[i].TooltipIndex = ULONG_MAX;\n        Graph_Update(CpusGraphHandle[i]);\n    }\n}\n\nVOID PhSipUpdateCpuPanel(\n    VOID\n    )\n{\n    LARGE_INTEGER systemUptime;\n    LARGE_INTEGER performanceCounterStart;\n    LARGE_INTEGER performanceCounterEnd;\n    LARGE_INTEGER performanceCounterTicks;\n    ULONG64 timeStampCounterStart;\n    ULONG64 timeStampCounterEnd;\n#ifdef _ARM64_\n    ULONG64 currentExceptionLevel;\n#else\n    LONG cpubrand[4];\n#endif\n    PH_FORMAT format[6];\n    WCHAR formatBuffer[256];\n    WCHAR uptimeString[PH_TIMESPAN_STR_LEN_1] = { L\"Unknown\" };\n\n    // Hardware\n\n    if (CpuTicked == 0)\n    {\n        switch (PhGetVirtualStatus())\n        {\n        case PhVirtualStatusVirtualMachine:\n            PhSetWindowText(CpuVirtualizationLabel, L\"Virtual machine\");\n            break;\n        case PhVirtualStatusEnabledHyperV:\n        case PhVirtualStatusEnabledFirmware:\n            PhSetWindowText(CpuVirtualizationLabel, L\"Enabled\");\n            break;\n        case PhVirtualStatusDisabledWithHyperV:\n            PhSetWindowText(CpuVirtualizationLabel, L\"Disabled / Hyper-V\");\n            break;\n        case PhVirtualStatusDisabled:\n            PhSetWindowText(CpuVirtualizationLabel, L\"Disabled\");\n            break;\n        case PhVirtualStatusNotCapable:\n        default:\n            PhSetWindowText(CpuVirtualizationLabel, L\"Not capable\");\n            break;\n        }\n\n        PhSetDialogItemText(CpuPanel, IDC_ZL1CACHE_V, CpuL1CacheSize ? PhaFormatSize(CpuL1CacheSize, ULONG_MAX)->Buffer : L\"N/A\");\n        PhSetDialogItemText(CpuPanel, IDC_ZL2CACHE_V, CpuL2CacheSize ? PhaFormatSize(CpuL2CacheSize, ULONG_MAX)->Buffer : L\"N/A\");\n        PhSetDialogItemText(CpuPanel, IDC_ZL3CACHE_V, CpuL3CacheSize ? PhaFormatSize(CpuL3CacheSize, ULONG_MAX)->Buffer : L\"N/A\");\n    }\n\n    // %.2f%%\n    PhInitFormatF(&format[0], (PhCpuUserUsage + PhCpuKernelUsage) * 100, PhMaxPrecisionUnit);\n    PhInitFormatC(&format[1], L'%');\n\n    if (PhFormatToBuffer(format, 2, formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(CpuPanelUtilizationLabel, formatBuffer);\n    else\n    {\n        PhSetWindowText(CpuPanelUtilizationLabel, PH_AUTO_T(PH_STRING, PhFormat(format, 2, 0))->Buffer);\n    }\n\n    if (PhGetIntegerSetting(SETTING_SYSINFO_SHOW_CPU_SPEED_MHZ))\n    {\n        PhInitFormatF(&format[0], CpuCurrentFrequency, 0);\n        PhInitFormatS(&format[1], L\" / \");\n        PhInitFormatF(&format[2], (FLOAT)CpuMaxMhz, 0);\n        PhInitFormatS(&format[3], L\" MHz\");\n    }\n    else\n    {\n        PhInitFormatF(&format[0], CpuCurrentFrequency / 1000, PhMaxPrecisionUnit);\n        PhInitFormatS(&format[1], L\" / \");\n        PhInitFormatF(&format[2], (FLOAT)CpuMaxMhz / 1000, PhMaxPrecisionUnit);\n        PhInitFormatS(&format[3], L\" GHz\");\n    }\n\n    // %.2f / %.2f GHz\n    if (PhFormatToBuffer(format, 4, formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(CpuPanelSpeedLabel, formatBuffer);\n    else\n    {\n        PhSetWindowText(CpuPanelSpeedLabel, PH_AUTO_T(PH_STRING, PhFormat(format, 4, 0))->Buffer);\n    }\n\n    PhInitFormatI64UGroupDigits(&format[0], PhTotalProcesses);\n\n    if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(CpuPanelProcessesLabel, formatBuffer);\n    else\n        PhSetWindowText(CpuPanelProcessesLabel, PhaFormatUInt64(PhTotalProcesses, TRUE)->Buffer);\n\n    PhInitFormatI64UGroupDigits(&format[0], PhTotalThreads);\n\n    if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(CpuPanelThreadsLabel, formatBuffer);\n    else\n        PhSetWindowText(CpuPanelThreadsLabel, PhaFormatUInt64(PhTotalThreads, TRUE)->Buffer);\n\n    PhInitFormatI64UGroupDigits(&format[0], PhTotalHandles);\n\n    if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(CpuPanelHandlesLabel, formatBuffer);\n    else\n        PhSetWindowText(CpuPanelHandlesLabel, PhaFormatUInt64(PhTotalHandles, TRUE)->Buffer);\n\n    if (NT_SUCCESS(PhGetSystemUptime(&systemUptime)))\n    {\n        PhPrintTimeSpan(uptimeString, systemUptime.QuadPart, PH_TIMESPAN_DHMS);\n    }\n\n    PhSetWindowText(CpuPanelUptimeLabel, uptimeString);\n\n    if (CpuTicked > 1)\n    {\n        PhInitFormatI64UGroupDigits(&format[0], ContextSwitchesDelta.Delta);\n\n        if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(CpuPanelContextSwitchesLabel, formatBuffer);\n        else\n            PhSetWindowText(CpuPanelContextSwitchesLabel, PhaFormatUInt64(ContextSwitchesDelta.Delta, TRUE)->Buffer);\n    }\n    else\n    {\n        PhSetWindowText(CpuPanelContextSwitchesLabel, L\"-\");\n    }\n\n    if (CpuTicked > 1)\n    {\n        PhInitFormatI64UGroupDigits(&format[0], InterruptsDelta.Delta);\n\n        if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(CpuPanelInterruptDeltaLabel, formatBuffer);\n        else\n            PhSetWindowText(CpuPanelInterruptDeltaLabel, PhaFormatUInt64(InterruptsDelta.Delta, TRUE)->Buffer);\n    }\n    else\n    {\n        PhSetWindowText(CpuPanelInterruptDeltaLabel, L\"-\");\n    }\n\n    if (CpuTicked > 1)\n    {\n        PhInitFormatI64UGroupDigits(&format[0], DpcsDelta.Delta);\n\n        if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(CpuPanelDpcDeltaLabel, formatBuffer);\n        else\n            PhSetWindowText(CpuPanelDpcDeltaLabel, PhaFormatUInt64(DpcsDelta.Delta, TRUE)->Buffer);\n    }\n    else\n    {\n        PhSetWindowText(CpuPanelDpcDeltaLabel, L\"-\");\n    }\n\n    if (CpuTicked > 1)\n    {\n        PhInitFormatI64UGroupDigits(&format[0], SystemCallsDelta.Delta);\n\n        if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(CpuPanelSystemCallsDeltaLabel, formatBuffer);\n        else\n            PhSetWindowText(CpuPanelSystemCallsDeltaLabel, PhaFormatUInt64(SystemCallsDelta.Delta, TRUE)->Buffer);\n    }\n    else\n    {\n        PhSetWindowText(CpuPanelSystemCallsDeltaLabel, L\"-\");\n    }\n\n    {\n        PhInitFormatI64UGroupDigits(&format[0], LogicalProcessorInformation.ProcessorCoreCount);\n\n        if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(CpuPanelCoresLabel, formatBuffer);\n        else\n            PhSetWindowText(CpuPanelCoresLabel, PhaFormatUInt64(LogicalProcessorInformation.ProcessorCoreCount, TRUE)->Buffer);\n\n        PhInitFormatI64UGroupDigits(&format[0], LogicalProcessorInformation.ProcessorPackageCount);\n\n        if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(CpuPanelSocketsLabel, formatBuffer);\n        else\n            PhSetWindowText(CpuPanelSocketsLabel, PhaFormatUInt64(LogicalProcessorInformation.ProcessorPackageCount, TRUE)->Buffer);\n\n        PhInitFormatI64UGroupDigits(&format[0], LogicalProcessorInformation.ProcessorLogicalCount);\n\n        if (PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(CpuPanelLogicalLabel, formatBuffer);\n        else\n            PhSetWindowText(CpuPanelLogicalLabel, PhaFormatUInt64(LogicalProcessorInformation.ProcessorLogicalCount, TRUE)->Buffer);\n    }\n\n    // Do not optimize (dmex)\n    PhQueryPerformanceCounter(&performanceCounterStart);\n    timeStampCounterStart = PhReadTimeStampCounter();\n#ifdef _ARM64_\n    // 0b11    0b000    0b0100    0b0010    0b010    CurrentEL     Current Exception Level\n    currentExceptionLevel = _ReadStatusReg(ARM64_SYSREG(3, 0, 4, 2, 2));\n#else\n    CpuIdEx(cpubrand, 0, 0);\n#endif\n    MemoryBarrier();\n    timeStampCounterEnd = PhReadTimeStampCounter();\n    PhQueryPerformanceCounter(&performanceCounterEnd);\n    performanceCounterTicks.QuadPart = performanceCounterEnd.QuadPart - performanceCounterStart.QuadPart;\n\n    if (timeStampCounterStart == 0 && timeStampCounterEnd == 0 &&\n#ifdef _ARM64_\n        currentExceptionLevel == MAXULONG64\n#else\n        cpubrand[0] == 0 && cpubrand[3] == 0\n#endif\n        )\n    {\n        performanceCounterTicks.QuadPart = 0;\n    }\n\n    PhInitFormatI64UGroupDigits(&format[0], performanceCounterTicks.QuadPart);\n    PhInitFormatS(&format[1], L\" | \");\n    PhInitFormatF(&format[2], CpuTimerResolution, 0);\n    PhInitFormatS(&format[3], L\" | \");\n    PhInitFormatI64UGroupDigits(&format[4], PhTotalCpuQueueLength);\n\n    if (PhFormatToBuffer(format, 5, formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(CpuPanelLatencyLabel, formatBuffer);\n    else\n        PhSetWindowText(CpuPanelLatencyLabel, PhaFormatUInt64(performanceCounterTicks.QuadPart, TRUE)->Buffer);\n}\n\nPPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord(\n    _In_ LONG Index\n    )\n{\n    LARGE_INTEGER time;\n    LONG maxProcessIdLong;\n    HANDLE maxProcessId;\n\n    // Find the process record for the max. CPU process for the particular time.\n\n    maxProcessIdLong = PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, Index);\n\n    if (!maxProcessIdLong)\n        return NULL;\n\n    // This must be treated as a signed integer to handle Interrupts correctly.\n    maxProcessId = LongToHandle(maxProcessIdLong);\n\n    // Note that the time we get has its components beyond seconds cleared.\n    // For example:\n    // * At 2.5 seconds a process is started.\n    // * At 2.75 seconds our process provider is fired, and the process is determined\n    //   to have 75% CPU usage, which happens to be the maximum CPU usage.\n    // * However the 2.75 seconds is recorded as 2 seconds due to\n    //   RtlTimeToSecondsSince1980.\n    // * If we call PhFindProcessRecord, it cannot find the process because it was\n    //   started at 2.5 seconds, not 2 seconds or older.\n    //\n    // This means we must add one second minus one tick (100ns) to the time, giving us\n    // 2.9999999 seconds. This will then make sure we find the process.\n    PhGetStatisticsTime(NULL, Index, &time);\n    time.QuadPart += PH_TICKS_PER_SEC - 1;\n\n    return PhFindProcessRecord(maxProcessId, &time);\n}\n\nPPH_STRING PhSipGetMaxCpuString(\n    _In_ LONG Index\n    )\n{\n    PPH_PROCESS_RECORD maxProcessRecord;\n#ifdef PH_RECORD_MAX_USAGE\n    FLOAT maxCpuUsage;\n#endif\n\n    if (maxProcessRecord = PhSipReferenceMaxCpuRecord(Index))\n    {\n        PPH_STRING maxUsageString;\n\n        // We found the process record, so now we construct the max. usage string.\n#ifdef PH_RECORD_MAX_USAGE\n        maxCpuUsage = PhGetItemCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, Index);\n\n        // Make sure we don't try to display the PID of DPCs or Interrupts.\n        if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId))\n        {\n            PH_FORMAT format[7];\n\n            // \\n%s (%lu): %.2f%%\n            PhInitFormatC(&format[0], L'\\n');\n            PhInitFormatSR(&format[1], maxProcessRecord->ProcessName->sr);\n            PhInitFormatS(&format[2], L\" (\");\n            PhInitFormatU(&format[3], HandleToUlong(maxProcessRecord->ProcessId));\n            PhInitFormatS(&format[4], L\"): \");\n            PhInitFormatF(&format[5], maxCpuUsage * 100, PhMaxPrecisionUnit);\n            PhInitFormatC(&format[6], L'%');\n\n            maxUsageString = PhFormat(format, RTL_NUMBER_OF(format), 128);\n        }\n        else\n        {\n            PH_FORMAT format[5];\n\n            // \\n%s: %.2f%%\n            PhInitFormatC(&format[0], L'\\n');\n            PhInitFormatSR(&format[1], maxProcessRecord->ProcessName->sr);\n            PhInitFormatS(&format[2], L\": \");\n            PhInitFormatF(&format[3], maxCpuUsage * 100, PhMaxPrecisionUnit);\n            PhInitFormatC(&format[4], L'%');\n\n            maxUsageString = PhFormat(format, RTL_NUMBER_OF(format), 128);\n        }\n#else\n        PH_FORMAT format[2];\n\n        PhInitFormatC(&format[0], L'\\n');\n        PhInitFormatSR(&format[1], maxProcessRecord->ProcessName->sr);\n\n        maxUsageString = PhFormat(format, RTL_NUMBER_OF(format), 128);\n#endif\n        PhDereferenceProcessRecord(maxProcessRecord);\n\n        return maxUsageString;\n    }\n\n    return PhReferenceEmptyString();\n}\n\nPPH_STRING PhSipGetCpuBrandString(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF whitespace = PH_STRINGREF_INIT(L\" \");\n    PPH_STRING brand = NULL;\n    ULONG brandLength;\n    CHAR brandString[49];\n\n    if (NT_SUCCESS(NtQuerySystemInformation(\n        SystemProcessorBrandString,\n        brandString,\n        sizeof(brandString),\n        NULL\n        )))\n    {\n        brandLength = sizeof(brandString) - sizeof(ANSI_NULL);\n        brand = PhConvertUtf8ToUtf16Ex(brandString, brandLength);\n    }\n    else\n    {\n#ifndef _ARM64_\n        ULONG cpubrand[4 * 3];\n\n        __cpuid(&cpubrand[0], 0x80000002);\n        __cpuid(&cpubrand[4], 0x80000003);\n        __cpuid(&cpubrand[8], 0x80000004);\n\n        brandLength = sizeof(brandString) - sizeof(ANSI_NULL);\n        brand = PhZeroExtendToUtf16Ex((PCSTR)cpubrand, brandLength);\n#else\n        ULONG deviceCount = 0;\n        PDEV_OBJECT deviceObjects = NULL;\n\n        const DEVPROPCOMPKEY deviceProperties[] =\n        {\n            { DEVPKEY_NAME, DEVPROP_STORE_SYSTEM, NULL },\n            { DEVPKEY_Device_FriendlyName, DEVPROP_STORE_SYSTEM, NULL },\n        };\n\n        const DEVPROP_FILTER_EXPRESSION deviceFilter[] =\n        {\n            { DEVPROP_OPERATOR_EQUALS,\n            { { DEVPKEY_Device_ClassGuid, DEVPROP_STORE_SYSTEM, NULL },\n                DEVPROP_TYPE_GUID, sizeof(GUID), (PVOID)&GUID_DEVCLASS_PROCESSOR\n            } }\n        };\n\n        if (SUCCEEDED(PhDevGetObjects(\n            DevObjectTypeDevice,\n            DevQueryFlagNone,\n            RTL_NUMBER_OF(deviceProperties),\n            deviceProperties,\n            RTL_NUMBER_OF(deviceFilter),\n            deviceFilter,\n            &deviceCount,\n            &deviceObjects\n            )))\n        {\n            if (deviceCount > 0)\n            {\n                DEV_OBJECT device = deviceObjects[0];\n                PH_STRINGREF string;\n\n                string.Buffer = device.pProperties[0].Buffer;\n                string.Length = device.pProperties[0].BufferSize ?\n                    device.pProperties[0].BufferSize - sizeof(UNICODE_NULL) : 0;\n\n                if (string.Length > 0)\n                {\n                    brand = PhCreateString2(&string);\n                }\n                else if (device.pProperties[1].BufferSize > 0)\n                {\n                    string.Buffer = device.pProperties[1].Buffer;\n                    string.Length = device.pProperties[1].BufferSize - sizeof(UNICODE_NULL);\n                    brand = PhCreateString2(&string);\n                }\n            }\n\n            PhDevFreeObjects(deviceCount, deviceObjects);\n        }\n\n        //static CONST PH_STRINGREF processorKeyName = PH_STRINGREF_INIT(L\"Hardware\\\\Description\\\\System\\\\CentralProcessor\\\\0\");\n        //HANDLE keyHandle;\n        //\n        //if (NT_SUCCESS(PhOpenKey(&keyHandle, KEY_READ, PH_KEY_LOCAL_MACHINE, &processorKeyName, 0)))\n        //{\n        //    brand = PhQueryRegistryStringZ(keyHandle, L\"ProcessorNameString\");\n        //    NtClose(keyHandle);\n        //}\n\n        if (PhIsNullOrEmptyString(brand))\n            PhMoveReference(&brand, PhCreateString(L\"N/A\"));\n#endif\n    }\n\n    PhTrimToNullTerminatorString(brand);\n\n    // Trim empty space (#611) (dmex)\n    PhMoveReference(&brand, PhCreateString3(&brand->sr, PH_TRIM_END_ONLY, &whitespace));\n\n    return brand;\n}\n\nVOID PhSipUpdateProcessorPerformanceDistribution(\n    VOID\n    )\n{\n    ULONG i, j;\n    PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION current = NULL;\n    PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION previous = NULL;\n    ULONGLONG totalCount = 0;\n    ULONGLONG totalValue = 0;\n\n    if (PreviousPerformanceDistribution)\n    {\n        PhFree(PreviousPerformanceDistribution);\n        PreviousPerformanceDistribution = NULL;\n    }\n\n    PreviousPerformanceDistribution = CurrentPerformanceDistribution;\n    CurrentPerformanceDistribution = NULL;\n\n    PhGetSystemProcessorPerformanceDistribution(&CurrentPerformanceDistribution);\n\n    if (!CurrentPerformanceDistribution || !PreviousPerformanceDistribution)\n        goto CleanupExit;\n    if (CurrentPerformanceDistribution->ProcessorCount != PreviousPerformanceDistribution->ProcessorCount)\n        goto CleanupExit;\n    if (CurrentPerformanceDistribution->ProcessorCount != NumberOfProcessors)\n        goto CleanupExit;\n\n    for (i = 0; i < NumberOfProcessors; i++)\n    {\n        ULONGLONG count = 0;\n        ULONGLONG value = 0;\n\n        current = PTR_ADD_OFFSET(CurrentPerformanceDistribution, CurrentPerformanceDistribution->Offsets[i]);\n        previous = PTR_ADD_OFFSET(PreviousPerformanceDistribution, PreviousPerformanceDistribution->Offsets[i]);\n\n        if (current->StateCount != previous->StateCount)\n            goto CleanupExit;\n\n        if (WindowsVersion >= WINDOWS_8_1)\n        {\n            for (j = 0; j < current->StateCount; j++)\n            {\n                PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT hitcountCurrent = PTR_ADD_OFFSET(current->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT) * j);\n                PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT hitcountPrevious = PTR_ADD_OFFSET(previous->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT) * j);\n                ULONGLONG delta = hitcountCurrent->Hits - hitcountPrevious->Hits;\n\n                if (delta)\n                {\n                    count += delta;\n                    value += delta * hitcountCurrent->PercentFrequency * CpuMaxMhz;\n                }\n            }\n        }\n        else\n        {\n            for (j = 0; j < current->StateCount; j++)\n            {\n                PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 hitcountOldCurrent = PTR_ADD_OFFSET(current->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8) * j);\n                PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 hitcountOldPrevious = PTR_ADD_OFFSET(previous->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8) * j);\n                ULONGLONG delta = hitcountOldCurrent->Hits - hitcountOldPrevious->Hits;\n\n                if (delta)\n                {\n                    count += delta;\n                    value += delta * hitcountOldCurrent->PercentFrequency * CpuMaxMhz;\n                }\n            }\n        }\n\n        if (CpuFrequencyInformation)\n        {\n            CpuFrequencyInformation[i] = count ? (FLOAT)((DOUBLE)value / (DOUBLE)count / 100.0) : 0.0f;\n        }\n\n        totalCount += count;\n        totalValue += value;\n    }\n\n    if (PreviousPerformanceDistribution)\n    {\n        PhFree(PreviousPerformanceDistribution);\n        PreviousPerformanceDistribution = NULL;\n    }\n\n    if (totalCount == 0)\n        CpuCurrentFrequency = (FLOAT)PowerInformation[0].CurrentMhz;\n    else\n        CpuCurrentFrequency = (FLOAT)((DOUBLE)totalValue / (DOUBLE)totalCount / 100.0);\n\n    return;\n\nCleanupExit:\n    if (CurrentPerformanceDistribution)\n    {\n        PhFree(CurrentPerformanceDistribution);\n        CurrentPerformanceDistribution = NULL;\n    }\n    if (PreviousPerformanceDistribution)\n    {\n        PhFree(PreviousPerformanceDistribution);\n        PreviousPerformanceDistribution = NULL;\n    }\n\n    if (CpuFrequencyInformation)\n    {\n        memset(CpuFrequencyInformation, 0, sizeof(FLOAT) * NumberOfProcessors);\n    }\n\n    CpuCurrentFrequency = (FLOAT)PowerInformation[0].CurrentMhz;\n}\n\n_Success_(return)\nBOOLEAN PhSipGetCpuFrequencyFromDistributionLegacy(\n    _Out_ DOUBLE *Frequency\n    )\n{\n    ULONG stateSize;\n    PVOID differences;\n    PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION stateDistribution;\n    PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION stateDifference;\n    PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 hitcountOld;\n    ULONG i;\n    ULONG j;\n    DOUBLE count;\n    DOUBLE total;\n\n    // Calculate the differences from the last performance distribution.\n\n    if (CurrentPerformanceDistribution->ProcessorCount != NumberOfProcessors || PreviousPerformanceDistribution->ProcessorCount != NumberOfProcessors)\n        return FALSE;\n\n    stateSize = FIELD_OFFSET(SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION, States) + sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT) * 2;\n    differences = PhAllocate(UInt32x32To64(stateSize, NumberOfProcessors));\n\n    for (i = 0; i < NumberOfProcessors; i++)\n    {\n        stateDistribution = PTR_ADD_OFFSET(CurrentPerformanceDistribution, CurrentPerformanceDistribution->Offsets[i]);\n        stateDifference = PTR_ADD_OFFSET(differences, UInt32x32To64(stateSize, i));\n\n        if (stateDistribution->StateCount != 2)\n        {\n            PhFree(differences);\n        return FALSE;\n    }\n\n        for (j = 0; j < stateDistribution->StateCount; j++)\n        {\n            if (WindowsVersion >= WINDOWS_8_1)\n            {\n                stateDifference->States[j] = stateDistribution->States[j];\n            }\n            else\n            {\n                hitcountOld = PTR_ADD_OFFSET(stateDistribution->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8) * j);\n                stateDifference->States[j].Hits = hitcountOld->Hits;\n                stateDifference->States[j].PercentFrequency = hitcountOld->PercentFrequency;\n            }\n        }\n    }\n\n    for (i = 0; i < NumberOfProcessors; i++)\n    {\n        stateDistribution = PTR_ADD_OFFSET(PreviousPerformanceDistribution, PreviousPerformanceDistribution->Offsets[i]);\n        stateDifference = PTR_ADD_OFFSET(differences, UInt32x32To64(stateSize, i));\n\n        if (stateDistribution->StateCount != 2)\n        {\n            PhFree(differences);\n            return FALSE;\n        }\n\n        for (j = 0; j < stateDistribution->StateCount; j++)\n        {\n            if (WindowsVersion >= WINDOWS_8_1)\n            {\n                stateDifference->States[j].Hits -= stateDistribution->States[j].Hits;\n            }\n            else\n            {\n                hitcountOld = PTR_ADD_OFFSET(stateDistribution->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8) * j);\n                stateDifference->States[j].Hits -= hitcountOld->Hits;\n            }\n        }\n    }\n\n    // Calculate the frequency.\n\n    count = 0;\n    total = 0;\n\n    for (i = 0; i < NumberOfProcessors; i++)\n    {\n        stateDifference = PTR_ADD_OFFSET(differences, UInt32x32To64(stateSize, i));\n\n        for (j = 0; j < 2; j++)\n        {\n            count += stateDifference->States[j].Hits;\n            total += stateDifference->States[j].Hits * stateDifference->States[j].PercentFrequency * PowerInformation[i].MaxMhz;\n        }\n    }\n\n    PhFree(differences);\n\n    if (count == 0)\n        return FALSE;\n\n    total /= count;\n    total /= 100;\n    *Frequency = total;\n\n    return TRUE;\n}\n\n_Success_(return)\nBOOLEAN PhSipGetCpuFrequencyFromDistribution(\n    _Out_ DOUBLE *Frequency\n    )\n{\n    ULONG i, j;\n    PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION current = NULL;\n    PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION previous = NULL;\n    ULONGLONG count = 0;\n    ULONGLONG total = 0;\n    PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION tempPrev = NULL;\n\n    // Free any previous distribution and clear pointer\n    if (PreviousPerformanceDistribution)\n    {\n        PhFree(PreviousPerformanceDistribution);\n        PreviousPerformanceDistribution = NULL;\n    }\n\n    // Move current to previous, then get new current\n    PreviousPerformanceDistribution = CurrentPerformanceDistribution;\n    CurrentPerformanceDistribution = NULL;\n\n    PhGetSystemProcessorPerformanceDistribution(&CurrentPerformanceDistribution);\n\n    if (!CurrentPerformanceDistribution || !PreviousPerformanceDistribution)\n        goto CleanupExit;\n    if (CurrentPerformanceDistribution->ProcessorCount != PreviousPerformanceDistribution->ProcessorCount)\n        goto CleanupExit;\n    if (CurrentPerformanceDistribution->ProcessorCount != NumberOfProcessors)\n        goto CleanupExit;\n\n    for (i = 0; i < NumberOfProcessors; i++)\n    {\n        current = PTR_ADD_OFFSET(CurrentPerformanceDistribution, CurrentPerformanceDistribution->Offsets[i]);\n        previous = PTR_ADD_OFFSET(PreviousPerformanceDistribution, PreviousPerformanceDistribution->Offsets[i]);\n\n        if (current->StateCount != previous->StateCount)\n            goto CleanupExit;\n\n        if (WindowsVersion >= WINDOWS_8_1)\n        {\n            PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT hitcountCurrent;\n            PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT hitcountPrevious;\n            ULONGLONG delta;\n            UCHAR percent;\n\n            for (j = 0; j < current->StateCount; j++)\n            {\n                hitcountCurrent = PTR_ADD_OFFSET(current->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT) * j);\n                hitcountPrevious = PTR_ADD_OFFSET(previous->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT) * j);\n                delta = hitcountCurrent->Hits - hitcountPrevious->Hits;\n                percent = hitcountCurrent->PercentFrequency;\n\n                if (delta)\n                {\n                    count += delta;\n                    total += delta * percent * CpuMaxMhz;\n                }\n            }\n        }\n        else\n        {\n            PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 hitcountOldCurrent;\n            PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 hitcountOldPrevious;\n            ULONGLONG delta;\n            UCHAR percent;\n\n            for (j = 0; j < current->StateCount; j++)\n            {\n                hitcountOldCurrent = PTR_ADD_OFFSET(current->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8) * j);\n                hitcountOldPrevious = PTR_ADD_OFFSET(previous->States, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8) * j);\n\n                delta = hitcountOldCurrent->Hits - hitcountOldPrevious->Hits;\n                percent = hitcountOldCurrent->PercentFrequency;\n\n                if (delta)\n                {\n                    count += delta;\n                    total += delta * percent * CpuMaxMhz;\n                }\n            }\n        }\n    }\n\n    // Cleanup previous, but keep current for next call\n    if (PreviousPerformanceDistribution)\n    {\n        PhFree(PreviousPerformanceDistribution);\n        PreviousPerformanceDistribution = NULL;\n    }\n\n    if (count == 0)\n        return FALSE;\n\n    // Total contains sum(delta * percent * maxMhz).\n    // Convert to average frequency (MHz).\n    *Frequency = (DOUBLE)(total / (DOUBLE)count / 100.0);\n\n    return TRUE;\n\nCleanupExit:\n    if (CurrentPerformanceDistribution)\n    {\n        PhFree(CurrentPerformanceDistribution);\n        CurrentPerformanceDistribution = NULL;\n    }\n    if (PreviousPerformanceDistribution)\n    {\n        PhFree(PreviousPerformanceDistribution);\n        PreviousPerformanceDistribution = NULL;\n    }\n    return FALSE;\n}\n\nULONG PhSipGetProcessorRelationshipIndex(\n    _In_ LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,\n    _In_ ULONG Index\n    )\n{\n    ULONG index;\n    ULONG bufferLength;\n    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX logicalInformation;\n    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX processorInfo;\n\n    if (!NT_SUCCESS(PhGetSystemLogicalProcessorInformation(RelationshipType, &logicalInformation, &bufferLength)))\n        return ULONG_MAX;\n\n    index = 0;\n\n    for (\n        processorInfo = logicalInformation;\n        (ULONG_PTR)processorInfo < (ULONG_PTR)PTR_ADD_OFFSET(logicalInformation, bufferLength);\n        processorInfo = PTR_ADD_OFFSET(processorInfo, processorInfo->Size)\n        )\n    {\n        PROCESSOR_RELATIONSHIP processor = processorInfo->Processor;\n        //BOOLEAN hyperThreaded = processor.Flags & LTP_PC_SMT;\n\n        if (processor.GroupMask[0].Mask & AFFINITY_MASK(Index))\n        {\n            PhFree(logicalInformation);\n            return index;\n        }\n\n        //for (USHORT j = 0; j < processor.GroupCount; j++)\n        //{\n        //    if (processor.GroupMask[j].Mask & ((KAFFINITY)1 << (Index % PhGetActiveProcessorCount(j))))\n        //    {\n        //        PhFree(logicalInformation);\n        //        return index;\n        //    }\n        //}\n\n        index++;\n    }\n\n    PhFree(logicalInformation);\n    return ULONG_MAX;\n}\n\n#ifndef _ARM64_\n// Hybrid CPU detection (dmex)\n\n#define CPUID_EXTENDED_FEATURES_FUNCTION 0x07\n#define CPUID_HYBRID_INFORMATION_FUNCTION 0x1A\n#define CPUID_HYBRID_CORETYPE_ECORE 0x20\n#define CPUID_HYBRID_CORETYPE_PCORE 0x40\n\ntypedef union _CPUID_HYBRID_INFORMATION\n{\n    struct\n    {\n        INT32 Eax;\n        INT32 Ebx;\n        INT32 Ecx;\n        INT32 Edx;\n    };\n    INT32 AsINT32[4];\n    struct\n    {\n        INT32 ModelId : 24;\n        INT32 CoreType : 8;\n    };\n} CPUID_HYBRID_INFORMATION;\n\n_Success_(return)\nBOOLEAN PhInitializeHybridProcessorTypeCache(\n    _Out_ PPH_LIST *HybridProcessorTypeList\n    )\n{\n    PPH_LIST hybridProcessorTypeList = NULL;\n    GROUP_AFFINITY previousThreadGroupAffinity;\n    INT32 CPUIDInformation[4] = { 0 };\n    INT32 CPUIDFunctionMax;\n    //INT32 CPUIDExtendedFunctionMax;\n    INT32 CPUIDExtendedFeatureFlags;\n\n    memset(&CPUIDInformation, 0, sizeof(CPUIDInformation));\n    CpuIdEx(CPUIDInformation, 0, 0);\n    CPUIDFunctionMax = CPUIDInformation[0];\n    if (!(CPUIDFunctionMax >= CPUID_HYBRID_INFORMATION_FUNCTION))\n        return FALSE;\n\n    //memset(&CPUIDInformation, 0, sizeof(CPUIDInformation));\n    //CpuIdEx(CPUIDInformation, 0x80000000, 0);\n    //CPUIDExtendedFunctionMax = CPUIDInformation[0] & ~0x80000000;\n    //if (CPUIDExtendedFunctionMax < CPUID_EXTENDED_FEATURES_FUNCTION)\n    //    return FALSE;\n\n    memset(&CPUIDInformation, 0, sizeof(CPUIDInformation));\n    CpuIdEx(CPUIDInformation, CPUID_EXTENDED_FEATURES_FUNCTION, 0);\n    CPUIDExtendedFeatureFlags = CPUIDInformation[3];\n    if (!_bittest(&CPUIDExtendedFeatureFlags, 15)) // hybrid\n        return FALSE;\n\n    if (!NT_SUCCESS(PhGetThreadGroupAffinity(NtCurrentThread(), &previousThreadGroupAffinity)))\n        return FALSE;\n\n    hybridProcessorTypeList = PhCreateList(PhSystemProcessorInformation.NumberOfProcessors);\n\n    for (USHORT processorGroup = 0; processorGroup < PhSystemProcessorInformation.NumberOfProcessorGroups; processorGroup++)\n    {\n        USHORT processorCount = PhGetActiveProcessorCount(processorGroup);\n\n        for (USHORT i = 0; i < processorCount; i++)\n        {\n            GROUP_AFFINITY threadGroup = { 0 };\n            CPUID_HYBRID_INFORMATION hybridInfo = { 0 };\n\n            threadGroup.Mask = AFFINITY_MASK(i);\n            threadGroup.Group = processorGroup;\n\n            if (NT_SUCCESS(PhSetThreadGroupAffinity(NtCurrentThread(), threadGroup)))\n            {\n                CpuIdEx(hybridInfo.AsINT32, CPUID_HYBRID_INFORMATION_FUNCTION, 0);\n            }\n\n            switch (hybridInfo.CoreType)\n            {\n            case CPUID_HYBRID_CORETYPE_ECORE:\n                PhAddItemList(hybridProcessorTypeList, UlongToPtr(CPUID_HYBRID_CORETYPE_ECORE));\n                break;\n            case CPUID_HYBRID_CORETYPE_PCORE:\n                PhAddItemList(hybridProcessorTypeList, UlongToPtr(CPUID_HYBRID_CORETYPE_PCORE));\n                break;\n            default:\n                PhAddItemList(hybridProcessorTypeList, UlongToPtr(0));\n                break;\n            }\n        }\n    }\n\n    PhSetThreadGroupAffinity(NtCurrentThread(), previousThreadGroupAffinity);\n\n    *HybridProcessorTypeList = hybridProcessorTypeList;\n    return TRUE;\n}\n\nPCPH_STRINGREF PhGetHybridProcessorType(\n    _In_ ULONG ProcessorIndex\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PPH_LIST hybridProcessorTypeList = NULL;\n\n    // Hybrid processors are not supported on earlier versions (dmex)\n    if (WindowsVersion < WINDOWS_10)\n        return NULL;\n    // Hybrid processors are not included with multiple groups (for now) (dmex)\n    if (PhSystemProcessorInformation.NumberOfProcessors >= MAXIMUM_PROC_PER_GROUP)\n        return NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeHybridProcessorTypeCache(&hybridProcessorTypeList);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!hybridProcessorTypeList || ProcessorIndex > hybridProcessorTypeList->Count)\n        return NULL;\n\n    switch (PtrToUlong(hybridProcessorTypeList->Items[ProcessorIndex]))\n    {\n    case CPUID_HYBRID_CORETYPE_ECORE:\n        {\n            static CONST PH_STRINGREF hybridECoreTypeSr = PH_STRINGREF_INIT(L\"E-Core\");\n            return &hybridECoreTypeSr;\n        }\n    case CPUID_HYBRID_CORETYPE_PCORE:\n        {\n            static CONST PH_STRINGREF hybridPCoreTypeSr = PH_STRINGREF_INIT(L\"P-Core\");\n            return &hybridPCoreTypeSr;\n        }\n    }\n\n    return NULL;\n}\n#else\n\n#define ARM_CORETYPE_LITTLE 0\n#define ARM_CORETYPE_BIG 1\n\n_Success_(return)\nBOOLEAN PhInitializeHybridProcessorTypeCache(\n    _Out_ PPH_LIST *HybridProcessorTypeList\n    )\n{\n    ULONG bufferLength;\n    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX logicalInformation;\n    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX processorInfo;\n    PPH_LIST hybridProcessorTypeList = NULL;\n\n    if (!NT_SUCCESS(PhGetSystemLogicalProcessorInformation(RelationProcessorCore, &logicalInformation, &bufferLength)))\n        return FALSE;\n\n    hybridProcessorTypeList = PhCreateList(PhSystemProcessorInformation.NumberOfProcessors);\n\n    for (\n        processorInfo = logicalInformation;\n        (ULONG_PTR)processorInfo < (ULONG_PTR)PTR_ADD_OFFSET(logicalInformation, bufferLength);\n        processorInfo = PTR_ADD_OFFSET(processorInfo, processorInfo->Size)\n        )\n    {\n        for (USHORT j = 0; j < processorInfo->Processor.GroupCount; j++)\n        {\n            //One logical processor per bit set in the core mask\n            ULONG logicalProcessorsInGroup = PhCountBitsUlongPtr(processorInfo->Processor.GroupMask[j].Mask);\n            while (logicalProcessorsInGroup--)\n            {\n                PhAddItemList(hybridProcessorTypeList, UlongToPtr(processorInfo->Processor.EfficiencyClass));\n            }\n        }\n    }\n    PhFree(logicalInformation);\n\n    *HybridProcessorTypeList = hybridProcessorTypeList;\n    return TRUE;\n}\n\nPCPH_STRINGREF PhGetHybridProcessorType(\n    _In_ ULONG ProcessorIndex\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PPH_LIST hybridProcessorTypeList = NULL;\n\n    // Hybrid processors are not supported on earlier versions (dmex)\n    if (WindowsVersion < WINDOWS_10)\n        return NULL;\n    // Hybrid processors are not included with multiple groups (for now) (dmex)\n    if (PhSystemProcessorInformation.NumberOfProcessors >= MAXIMUM_PROC_PER_GROUP)\n        return NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeHybridProcessorTypeCache(&hybridProcessorTypeList);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!hybridProcessorTypeList || ProcessorIndex > hybridProcessorTypeList->Count)\n        return NULL;\n\n    switch (PtrToUlong(hybridProcessorTypeList->Items[ProcessorIndex]))\n    {\n    case ARM_CORETYPE_LITTLE:\n        {\n            static CONST PH_STRINGREF hybridECoreTypeSr = PH_STRINGREF_INIT(L\"E-Core\");\n            return &hybridECoreTypeSr;\n        }\n    case ARM_CORETYPE_BIG:\n        {\n            static CONST PH_STRINGREF hybridPCoreTypeSr = PH_STRINGREF_INIT(L\"P-Core\");\n            return &hybridPCoreTypeSr;\n        }\n    }\n\n    return NULL;\n}\n#endif\n\n/**\n * \\brief Checks if a specific logical processor (core) in the system is parked.\n *\n * This function determines whether a specific logical processor in the system\n * is parked, meaning it is temporarily unavailable for the thread scheduler.\n * It utilizes CPU sets functionality available starting with Windows 10.\n *\n * \\param[in] ProcessorIndex The index of the logical processor to check.\n *\n * \\return TRUE if the specified logical processor is parked, FALSE otherwise or\n * in case of failure.\n */\nBOOLEAN PhIsCoreParked(\n    _In_ ULONG ProcessorIndex\n    )\n{\n    static ULONG initialBufferSize = 0;\n    static HANDLE processHandle = NULL;\n    NTSTATUS status;\n    ULONG returnLength;\n    BOOLEAN isParked;\n    PSYSTEM_CPU_SET_INFORMATION cpuSetInfo;\n\n    if (WindowsVersion < WINDOWS_10)\n        return FALSE;\n\n    //\n    // MSDN: https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_cpu_set_information\n    // This is a variable-sized structure designed for future expansion. When iterating over\n    // this structure, use the size field to determine the offset to the next structure.\n    //\n    // N.B. The kernel returns the size even in the last element, we over-allocate by the\n    // Size offset and check it to minimize instructions (jxy-s).\n    //\n\n    if (initialBufferSize)\n    {\n        returnLength = initialBufferSize;\n        cpuSetInfo = PhAllocateStack(returnLength);\n        if (!cpuSetInfo) return FALSE;\n        RtlZeroMemory(cpuSetInfo, returnLength);\n    }\n    else\n    {\n        returnLength = 0;\n        cpuSetInfo = NULL;\n    }\n\n    status = NtQuerySystemInformationEx(\n        SystemCpuSetInformation,\n        &processHandle,\n        sizeof(HANDLE),\n        cpuSetInfo,\n        returnLength,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        returnLength += RTL_SIZEOF_THROUGH_FIELD(SYSTEM_CPU_SET_INFORMATION, Size);\n\n        PhFreeStack(cpuSetInfo);\n        cpuSetInfo = PhAllocateStack(returnLength);\n        if (!cpuSetInfo) return FALSE;\n        RtlZeroMemory(cpuSetInfo, returnLength);\n\n        status = NtQuerySystemInformationEx(\n            SystemCpuSetInformation,\n            &processHandle,\n            sizeof(HANDLE),\n            cpuSetInfo,\n            returnLength,\n            NULL\n            );\n\n        if (NT_SUCCESS(status) && initialBufferSize <= 0x100000)\n            initialBufferSize = returnLength;\n    }\n\n    if (!cpuSetInfo)\n        return FALSE;\n\n    isParked = FALSE;\n\n    if (NT_SUCCESS(status))\n    {\n        for (PSYSTEM_CPU_SET_INFORMATION info = cpuSetInfo;\n             RTL_CONTAINS_FIELD(info, info->Size, CpuSet);\n             info = PTR_ADD_OFFSET(info, info->Size))\n        {\n            if (info->CpuSet.LogicalProcessorIndex == ProcessorIndex)\n            {\n                isParked = info->CpuSet.Parked;\n                break;\n            }\n        }\n    }\n\n    PhFreeStack(cpuSetInfo);\n\n    return isParked;\n}\n\nVOID PhSipUpdateProcessorInformation(\n    VOID\n    )\n{\n    if (PhSystemProcessorInformation.SingleProcessorGroup)\n    {\n        if (!NT_SUCCESS(NtPowerInformation(\n            ProcessorInformation,\n            NULL,\n            0,\n            PowerInformation,\n            sizeof(PROCESSOR_POWER_INFORMATION) * NumberOfProcessors\n            )))\n        {\n            memset(PowerInformation, 0, sizeof(PROCESSOR_POWER_INFORMATION) * NumberOfProcessors);\n        }\n    }\n    else\n    {\n        USHORT processorCount = 0;\n\n        for (USHORT processorGroup = 0; processorGroup < PhSystemProcessorInformation.NumberOfProcessorGroups; processorGroup++)\n        {\n            USHORT activeProcessorCount = PhGetActiveProcessorCount(processorGroup);\n\n            if (!NT_SUCCESS(NtPowerInformation(\n                ProcessorInformationEx,\n                &processorGroup,\n                sizeof(USHORT),\n                PTR_ADD_OFFSET(PowerInformation, sizeof(PROCESSOR_POWER_INFORMATION) * processorCount),\n                sizeof(PROCESSOR_POWER_INFORMATION) * activeProcessorCount\n                )))\n            {\n                memset(\n                    PTR_ADD_OFFSET(PowerInformation, sizeof(PROCESSOR_POWER_INFORMATION) * processorCount),\n                    0,\n                    sizeof(PROCESSOR_POWER_INFORMATION) * activeProcessorCount\n                    );\n            }\n\n            processorCount += activeProcessorCount;\n        }\n    }\n}\n\nVOID PhSipUpdateInterruptInformation(\n    _Out_ PULONG64 DpcCount\n    )\n{\n    ULONG64 dpcCount;\n    ULONG i;\n\n    dpcCount = 0;\n\n    if (PhSystemProcessorInformation.SingleProcessorGroup)\n    {\n        if (!NT_SUCCESS(NtQuerySystemInformation(\n            SystemInterruptInformation,\n            InterruptInformation,\n            sizeof(SYSTEM_INTERRUPT_INFORMATION) * NumberOfProcessors,\n            NULL\n            )))\n        {\n            memset(InterruptInformation, 0, sizeof(SYSTEM_INTERRUPT_INFORMATION) * NumberOfProcessors);\n        }\n\n        for (i = 0; i < NumberOfProcessors; i++)\n            dpcCount += InterruptInformation[i].DpcCount;\n    }\n    else\n    {\n        USHORT processorCount = 0;\n\n        for (USHORT processorGroup = 0; processorGroup < PhSystemProcessorInformation.NumberOfProcessorGroups; processorGroup++)\n        {\n            USHORT activeProcessorCount = PhGetActiveProcessorCount(processorGroup);\n\n            if (!NT_SUCCESS(NtQuerySystemInformationEx(\n                SystemInterruptInformation,\n                &processorGroup,\n                sizeof(USHORT),\n                PTR_ADD_OFFSET(InterruptInformation, sizeof(SYSTEM_INTERRUPT_INFORMATION) * processorCount),\n                sizeof(SYSTEM_INTERRUPT_INFORMATION) * activeProcessorCount,\n                NULL\n                )))\n            {\n                memset(\n                    PTR_ADD_OFFSET(InterruptInformation, sizeof(SYSTEM_INTERRUPT_INFORMATION) * processorCount),\n                    0,\n                    sizeof(SYSTEM_INTERRUPT_INFORMATION) * activeProcessorCount\n                    );\n            }\n\n            processorCount += activeProcessorCount;\n        }\n\n        for (i = 0; i < NumberOfProcessors; i++)\n            dpcCount += InterruptInformation[i].DpcCount;\n    }\n\n    *DpcCount = dpcCount;\n}\n\nVOID PhSipUpdateProcessorFrequency(\n    VOID\n    )\n{\n    POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_INPUT input;\n    POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_OUTPUT output;\n\n    memset(&input, 0, sizeof(POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_INPUT));\n    input.InternalType = PowerInternalProcessorBrandedFrequency;\n    input.ProcessorNumber.Group = USHRT_MAX;\n    input.ProcessorNumber.Number = UCHAR_MAX;\n    input.ProcessorNumber.Reserved = UCHAR_MAX;\n\n    memset(&output, 0, sizeof(POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_OUTPUT));\n    output.Version = POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_VERSION;\n\n    if (NT_SUCCESS(NtPowerInformation(\n        PowerInformationInternal,\n        &input,\n        sizeof(input),\n        &output,\n        sizeof(output)\n        )))\n    {\n        if (output.Version == POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_VERSION)\n        {\n            CpuMaxMhz = output.NominalFrequency;\n            return;\n        }\n    }\n\n    for (ULONG i = 0; i < NumberOfProcessors; i++)\n    {\n        if (CpuMaxMhz < PowerInformation[i].MaxMhz)\n            CpuMaxMhz = PowerInformation[i].MaxMhz;\n    }\n}\n\nVOID PhSipUpdateTimerResolution(\n    VOID\n    )\n{\n    ULONG maximumTime;\n    ULONG minimumTime;\n    ULONG currentTime;\n\n    if (NT_SUCCESS(NtQueryTimerResolution(&maximumTime, &minimumTime, &currentTime)))\n    {\n        CpuTimerResolution = (FLOAT)((DOUBLE)currentTime / 10000.0);\n    }\n    else\n    {\n        CpuTimerResolution = 0.0f;\n    }\n}\n\n_Function_class_(PH_ENUM_SMBIOS_CALLBACK)\nBOOLEAN NTAPI PhpSipCpuSMBIOSCallback(\n    _In_ ULONG_PTR EnumHandle,\n    _In_ UCHAR MajorVersion,\n    _In_ UCHAR MinorVersion,\n    _In_ PPH_SMBIOS_ENTRY Entry,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG64 size;\n\n    if (Entry->Header.Type != SMBIOS_CACHE_INFORMATION_TYPE)\n        return FALSE;\n\n    if (!PH_SMBIOS_CONTAINS_FIELD(Entry, Cache, Configuration) ||\n        !Entry->Cache.Configuration.Enabled)\n    {\n        return FALSE;\n    }\n\n    size = 0;\n\n    if (PH_SMBIOS_CONTAINS_FIELD(Entry, Cache, InstalledSize))\n    {\n        if (Entry->Cache.InstalledSize.Value == MAXUSHORT &&\n            PH_SMBIOS_CONTAINS_FIELD(Entry, Cache, InstalledSize2))\n        {\n            if (Entry->Cache.InstalledSize2.Granularity)\n                size = (ULONG64)Entry->Cache.InstalledSize2.Size * 0x10000;\n            else\n                size = (ULONG64)Entry->Cache.InstalledSize2.Size * 0x400;\n        }\n        else\n        {\n            if (Entry->Cache.InstalledSize.Granularity)\n                size = (ULONG64)Entry->Cache.InstalledSize.Size * 0x10000;\n            else\n                size = (ULONG64)Entry->Cache.InstalledSize.Size * 0x400;\n        }\n    }\n\n    switch (Entry->Cache.Configuration.Level)\n    {\n    case 0:\n        CpuL1CacheSize += size;\n        break;\n    case 1:\n        CpuL2CacheSize += size;\n        break;\n    case 2:\n        CpuL3CacheSize += size;\n        break;\n    }\n\n    return FALSE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI PhSipCpuSMBIOSWorkRoutine(\n    _In_ PVOID ThreadParameter\n    )\n{\n    PhEnumSMBIOS(PhpSipCpuSMBIOSCallback, NULL);\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "SystemInformer/sysscio.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <sysinfo.h>\n#include <sysinfop.h>\n\n#include <procprv.h>\n#include <phsettings.h>\n\nstatic PPH_SYSINFO_SECTION IoSection;\nstatic HWND IoDialog;\nstatic PH_LAYOUT_MANAGER IoLayoutManager;\nstatic RECT IoGraphMargin;\nstatic HWND IoReadLabelHandle;\nstatic HWND IoReadGraphHandle;\nstatic HWND IoWriteLabelHandle;\nstatic HWND IoWriteGraphHandle;\nstatic HWND IoOtherLabelHandle;\nstatic HWND IoOtherGraphHandle;\nstatic PH_GRAPH_STATE IoReadGraphState;\nstatic PH_GRAPH_STATE IoWriteGraphState;\nstatic PH_GRAPH_STATE IoOtherGraphState;\nstatic HWND IoPanel;\nstatic ULONG IoTicked;\nstatic PH_UINT64_DELTA IoReadDelta;\nstatic PH_UINT64_DELTA IoWriteDelta;\nstatic PH_UINT64_DELTA IoOtherDelta;\nstatic HWND IoPanelReadsDeltaLabel;\nstatic HWND IoPanelWritesDeltaLabel;\nstatic HWND IoPanelOtherDeltaLabel;\nstatic HWND IoPanelReadBytesDeltaLabel;\nstatic HWND IoPanelWriteBytesDeltaLabel;\nstatic HWND IoPanelOtherBytesDeltaLabel;\nstatic HWND IoPanelReadsLabel;\nstatic HWND IoPanelReadBytesLabel;\nstatic HWND IoPanelWritesLabel;\nstatic HWND IoPanelWriteBytesLabel;\nstatic HWND IoPanelOtherLabel;\nstatic HWND IoPanelOtherBytesLabel;\n\n_Function_class_(PH_SYSINFO_SECTION_CALLBACK)\nBOOLEAN PhSipIoSectionCallback(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ PH_SYSINFO_SECTION_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case SysInfoCreate:\n        {\n            IoSection = Section;\n        }\n        return TRUE;\n    case SysInfoDestroy:\n        {\n            if (IoDialog)\n            {\n                PhSipUninitializeIoDialog();\n                IoDialog = NULL;\n            }\n        }\n        break;\n    case SysInfoTick:\n        {\n            if (IoDialog)\n            {\n                PhSipTickIoDialog();\n            }\n        }\n        break;\n    case SysInfoViewChanging:\n        {\n            PH_SYSINFO_VIEW_TYPE view = (PH_SYSINFO_VIEW_TYPE)PtrToUlong(Parameter1);\n            PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Parameter2;\n\n            if (view == SysInfoSummaryView || section != Section)\n                return TRUE;\n\n            if (IoReadGraphHandle)\n            {\n                IoReadGraphState.Valid = FALSE;\n                IoReadGraphState.TooltipIndex = ULONG_MAX;\n                Graph_Draw(IoReadGraphHandle);\n            }\n\n            if (IoWriteGraphHandle)\n            {\n                IoWriteGraphState.Valid = FALSE;\n                IoWriteGraphState.TooltipIndex = ULONG_MAX;\n                Graph_Draw(IoWriteGraphHandle);\n            }\n\n            if (IoOtherGraphHandle)\n            {\n                IoOtherGraphState.Valid = FALSE;\n                IoOtherGraphState.TooltipIndex = ULONG_MAX;\n                Graph_Draw(IoOtherGraphHandle);\n            }\n        }\n        return TRUE;\n    case SysInfoCreateDialog:\n        {\n            PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;\n\n            createDialog->Instance = PhInstanceHandle;\n            createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_IO);\n            createDialog->DialogProc = PhSipIoDialogProc;\n        }\n        return TRUE;\n    case SysInfoGraphGetDrawInfo:\n        {\n            PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;\n            ULONG i;\n            FLOAT max;\n\n            drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y;\n            Section->Parameters->ColorSetupFunction(drawInfo, PhCsColorIoReadOther, 0, Section->Parameters->WindowDpi);\n            PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, PhIoReadHistory.Count);\n\n            if (!Section->GraphState.Valid)\n            {\n                max = 1024 * 1024; // Minimum scaling of 1 MB\n\n                for (i = 0; i < drawInfo->LineDataCount; i++)\n                {\n                    FLOAT data;\n\n                    Section->GraphState.Data1[i] = data =\n                        (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i) +\n                        (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i) +\n                        (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i);\n\n                    if (max < data)\n                        max = data;\n                }\n\n                if (max != 0)\n                {\n                    // Scale the data.\n\n                    PhDivideSinglesBySingle(\n                        Section->GraphState.Data1,\n                        max,\n                        drawInfo->LineDataCount\n                        );\n                }\n\n                drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                drawInfo->LabelYFunctionParameter = max;\n\n                Section->GraphState.Valid = TRUE;\n            }\n        }\n        return TRUE;\n    case SysInfoGraphGetTooltipText:\n        {\n            PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;\n            ULONG64 ioRead;\n            ULONG64 ioWrite;\n            ULONG64 ioOther;\n            PH_FORMAT format[9];\n\n            ioRead = PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, getTooltipText->Index);\n            ioWrite = PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, getTooltipText->Index);\n            ioOther = PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, getTooltipText->Index);\n\n            // R: %s\\nW: %s\\nO: %s%s\\n%s\n            PhInitFormatS(&format[0], L\"R: \");\n            PhInitFormatSize(&format[1], ioRead);\n            PhInitFormatS(&format[2], L\"\\nW: \");\n            PhInitFormatSize(&format[3], ioWrite);\n            PhInitFormatS(&format[4], L\"\\nO: \");\n            PhInitFormatSize(&format[5], ioOther);\n            PhInitFormatSR(&format[6], PH_AUTO_T(PH_STRING, PhSipGetMaxIoString(getTooltipText->Index))->sr);\n            PhInitFormatC(&format[7], L'\\n');\n            PhInitFormatSR(&format[8], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n            PhMoveReference(&Section->GraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 160));\n            getTooltipText->Text = Section->GraphState.TooltipText->sr;\n        }\n        return TRUE;\n    case SysInfoGraphDrawPanel:\n        {\n            PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;\n            PH_FORMAT format[4];\n\n            drawPanel->Title = PhCreateString(L\"I/O\");\n\n            // R+O: %s\\nW: %s\n            PhInitFormatS(&format[0], L\"R+O: \");\n            PhInitFormatSizeWithPrecision(&format[1], PhIoReadDelta.Delta + PhIoOtherDelta.Delta, 1);\n            PhInitFormatS(&format[2], L\"\\nW: \");\n            PhInitFormatSizeWithPrecision(&format[3], PhIoWriteDelta.Delta, 1);\n\n            drawPanel->SubTitle = PhFormat(format, RTL_NUMBER_OF(format), 64);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhSipInitializeIoDialog(\n    VOID\n    )\n{\n    PhInitializeDelta(&IoReadDelta);\n    PhInitializeDelta(&IoWriteDelta);\n    PhInitializeDelta(&IoOtherDelta);\n\n    PhInitializeGraphState(&IoReadGraphState);\n    PhInitializeGraphState(&IoWriteGraphState);\n    PhInitializeGraphState(&IoOtherGraphState);\n\n    IoTicked = 0;\n}\n\nVOID PhSipUninitializeIoDialog(\n    VOID\n    )\n{\n    PhDeleteGraphState(&IoReadGraphState);\n    PhDeleteGraphState(&IoWriteGraphState);\n    PhDeleteGraphState(&IoOtherGraphState);\n\n    // Note: Required for SysInfoViewChanging (dmex)\n    IoReadGraphHandle = NULL;\n    IoWriteGraphHandle = NULL;\n    IoOtherGraphHandle = NULL;\n}\n\nVOID PhSipTickIoDialog(\n    VOID\n    )\n{\n    PhUpdateDelta(&IoReadDelta, PhPerfInformation.IoReadOperationCount);\n    PhUpdateDelta(&IoWriteDelta, PhPerfInformation.IoWriteOperationCount);\n    PhUpdateDelta(&IoOtherDelta, PhPerfInformation.IoOtherOperationCount);\n\n    if (IoTicked < 2)\n        IoTicked++;\n\n    PhSipUpdateIoGraph();\n    PhSipUpdateIoPanel();\n}\n\nINT_PTR CALLBACK PhSipIoDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_LAYOUT_ITEM graphItem;\n            PPH_LAYOUT_ITEM panelItem;\n            RECT margin;\n\n            PhSipInitializeIoDialog();\n\n            IoDialog = hwndDlg;\n            IoReadLabelHandle = GetDlgItem(hwndDlg, IDC_IOREAD_L);\n            IoWriteLabelHandle = GetDlgItem(hwndDlg, IDC_IOWRITE_L);\n            IoOtherLabelHandle = GetDlgItem(hwndDlg, IDC_IOOTHER_L);\n\n            PhInitializeLayoutManager(&IoLayoutManager, hwndDlg);\n            graphItem = PhAddLayoutItem(&IoLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);\n            panelItem = PhAddLayoutItem(&IoLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            IoGraphMargin = graphItem->Margin;\n\n            SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), IoSection->Parameters->LargeFont, FALSE);\n\n            IoPanel = PhCreateDialog(PhInstanceHandle, MAKEINTRESOURCE(IDD_SYSINFO_IOPANEL), hwndDlg, PhSipIoPanelDialogProc, NULL);\n            ShowWindow(IoPanel, SW_SHOW);\n\n            margin = panelItem->Margin;\n            PhGetSizeDpiValue(&margin, IoSection->Parameters->WindowDpi, TRUE);\n            PhAddLayoutItemEx(&IoLayoutManager, IoPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, &margin);\n\n            PhSipCreateIoGraph();\n            PhSipUpdateIoGraph();\n            PhSipUpdateIoPanel();\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDeleteLayoutManager(&IoLayoutManager);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            if (IoSection->Parameters->LargeFont)\n            {\n                SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), IoSection->Parameters->LargeFont, FALSE);\n            }\n\n            IoReadGraphState.Valid = FALSE;\n            IoReadGraphState.TooltipIndex = ULONG_MAX;\n\n            IoWriteGraphState.Valid = FALSE;\n            IoWriteGraphState.TooltipIndex = ULONG_MAX;\n\n            IoOtherGraphState.Valid = FALSE;\n            IoOtherGraphState.TooltipIndex = ULONG_MAX;\n\n            PhLayoutManagerUpdate(&IoLayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&IoLayoutManager);\n            PhSipLayoutIoGraphs(hwndDlg);\n        }\n        break;\n    case WM_SIZE:\n        {\n            IoReadGraphState.Valid = FALSE;\n            IoReadGraphState.TooltipIndex = ULONG_MAX;\n\n            IoWriteGraphState.Valid = FALSE;\n            IoWriteGraphState.TooltipIndex = ULONG_MAX;\n\n            IoOtherGraphState.Valid = FALSE;\n            IoOtherGraphState.TooltipIndex = ULONG_MAX;\n\n            PhLayoutManagerLayout(&IoLayoutManager);\n            PhSipLayoutIoGraphs(hwndDlg);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nINT_PTR CALLBACK PhSipIoPanelDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            IoPanelReadsDeltaLabel = GetDlgItem(hwndDlg, IDC_ZREADSDELTA_V);\n            IoPanelWritesDeltaLabel = GetDlgItem(hwndDlg, IDC_ZWRITESDELTA_V);\n            IoPanelOtherDeltaLabel = GetDlgItem(hwndDlg, IDC_ZOTHERDELTA_V);\n            IoPanelReadBytesDeltaLabel = GetDlgItem(hwndDlg, IDC_ZREADBYTESDELTA_V);\n            IoPanelWriteBytesDeltaLabel = GetDlgItem(hwndDlg, IDC_ZWRITEBYTESDELTA_V);\n            IoPanelOtherBytesDeltaLabel = GetDlgItem(hwndDlg, IDC_ZOTHERBYTESDELTA_V);\n            IoPanelReadsLabel = GetDlgItem(hwndDlg, IDC_ZREADS_V);\n            IoPanelReadBytesLabel = GetDlgItem(hwndDlg, IDC_ZREADBYTES_V);\n            IoPanelWritesLabel = GetDlgItem(hwndDlg, IDC_ZWRITES_V);\n            IoPanelWriteBytesLabel = GetDlgItem(hwndDlg, IDC_ZWRITEBYTES_V);\n            IoPanelOtherLabel = GetDlgItem(hwndDlg, IDC_ZOTHER_V);\n            IoPanelOtherBytesLabel = GetDlgItem(hwndDlg, IDC_ZOTHERBYTES_V);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhSipCreateIoGraph(\n    VOID\n    )\n{\n    PH_GRAPH_CREATEPARAMS graphCreateParams;\n\n    memset(&graphCreateParams, 0, sizeof(PH_GRAPH_CREATEPARAMS));\n    graphCreateParams.Size = sizeof(PH_GRAPH_CREATEPARAMS);\n    graphCreateParams.Callback = PhSipNotifyIoReadGraph;\n\n    IoReadGraphHandle = PhCreateWindow(\n        PH_GRAPH_CLASSNAME,\n        NULL,\n        WS_VISIBLE | WS_CHILD | WS_BORDER,\n        0,\n        0,\n        0,\n        0,\n        IoDialog,\n        NULL,\n        NULL,\n        &graphCreateParams\n        );\n    Graph_SetTooltip(IoReadGraphHandle, TRUE);\n\n    memset(&graphCreateParams, 0, sizeof(PH_GRAPH_CREATEPARAMS));\n    graphCreateParams.Size = sizeof(PH_GRAPH_CREATEPARAMS);\n    graphCreateParams.Callback = PhSipNotifyIoWriteGraph;\n\n    IoWriteGraphHandle = PhCreateWindow(\n        PH_GRAPH_CLASSNAME,\n        NULL,\n        WS_VISIBLE | WS_CHILD | WS_BORDER,\n        0,\n        0,\n        0,\n        0,\n        IoDialog,\n        NULL,\n        NULL,\n        &graphCreateParams\n        );\n    Graph_SetTooltip(IoWriteGraphHandle, TRUE);\n\n    memset(&graphCreateParams, 0, sizeof(PH_GRAPH_CREATEPARAMS));\n    graphCreateParams.Size = sizeof(PH_GRAPH_CREATEPARAMS);\n    graphCreateParams.Callback = PhSipNotifyIoOtherGraph;\n\n    IoOtherGraphHandle = PhCreateWindow(\n        PH_GRAPH_CLASSNAME,\n        NULL,\n        WS_VISIBLE | WS_CHILD | WS_BORDER,\n        0,\n        0,\n        0,\n        0,\n        IoDialog,\n        NULL,\n        NULL,\n        &graphCreateParams\n        );\n    Graph_SetTooltip(IoOtherGraphHandle, TRUE);\n}\n\nVOID PhSipLayoutIoGraphs(\n    _In_ HWND WindowHandle\n    )\n{\n    RECT clientRect;\n    RECT labelRect;\n    RECT marginRect;\n    LONG graphWidth;\n    LONG graphHeight;\n    HDWP deferHandle;\n    LONG y;\n\n    marginRect = IoGraphMargin;\n    PhGetSizeDpiValue(&marginRect, IoSection->Parameters->WindowDpi, TRUE);\n\n    if (!PhGetClientRect(IoDialog, &clientRect))\n        return;\n    if (!PhGetClientRect(IoReadLabelHandle, &labelRect))\n        return;\n\n    graphWidth = clientRect.right - marginRect.left - marginRect.right;\n    graphHeight = (clientRect.bottom - marginRect.top - marginRect.bottom - labelRect.bottom * 3 - IoSection->Parameters->MemoryPadding * 4) / 3;\n\n    deferHandle = BeginDeferWindowPos(6);\n    y = marginRect.top;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        IoReadLabelHandle,\n        NULL,\n        marginRect.left,\n        y,\n        0,\n        0,\n        SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER\n        );\n    y += labelRect.bottom + IoSection->Parameters->MemoryPadding;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        IoReadGraphHandle,\n        NULL,\n        marginRect.left,\n        y,\n        graphWidth,\n        graphHeight,\n        SWP_NOACTIVATE | SWP_NOZORDER\n        );\n    y += graphHeight + IoSection->Parameters->MemoryPadding;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        IoWriteLabelHandle,\n        NULL,\n        marginRect.left,\n        y,\n        0,\n        0,\n        SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER\n        );\n    y += labelRect.bottom + IoSection->Parameters->MemoryPadding;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        IoWriteGraphHandle,\n        NULL,\n        marginRect.left,\n        y,\n        graphWidth,\n        graphHeight,\n        SWP_NOACTIVATE | SWP_NOZORDER\n        );\n    y += graphHeight + IoSection->Parameters->MemoryPadding;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        IoOtherLabelHandle,\n        NULL,\n        marginRect.left,\n        y,\n        0,\n        0,\n        SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER\n        );\n    y += labelRect.bottom + IoSection->Parameters->MemoryPadding;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        IoOtherGraphHandle,\n        NULL,\n        marginRect.left,\n        y,\n        graphWidth,\n        clientRect.bottom - marginRect.bottom - y,\n        SWP_NOACTIVATE | SWP_NOZORDER\n        );\n\n    EndDeferWindowPos(deferHandle);\n}\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipNotifyIoReadGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    switch (GraphMessage)\n    {\n    case GCN_GETDRAWINFO:\n        {\n            PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Parameter1;\n            PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;\n\n            drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y;\n            PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorIoReadOther, 0, IoSection->Parameters->WindowDpi);\n\n            PhGraphStateGetDrawInfo(\n                &IoReadGraphState,\n                getDrawInfo,\n                PhIoReadHistory.Count\n                );\n\n            if (!IoReadGraphState.Valid)\n            {\n                FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB\n\n                if (PhCsEnableAvxSupport && drawInfo->LineDataCount > 1024)\n                {\n                    PhCopyConvertCircularBufferULONG64(&PhIoReadHistory, IoReadGraphState.Data1, drawInfo->LineDataCount);\n                    max = PhMaxMemorySingles(IoReadGraphState.Data1, drawInfo->LineDataCount);\n\n#ifdef DEBUG\n                    for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        assert(IoReadGraphState.Data1[i] == (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i));\n                    }\n#endif\n                }\n                else\n                {\n                    for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        FLOAT value;\n\n                        IoReadGraphState.Data1[i] = value = (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i);\n\n                        if (max < value)\n                            max = value;\n                    }\n                }\n\n                if (max != 0)\n                {\n                    // Scale the data.\n\n                    PhDivideSinglesBySingle(\n                        IoReadGraphState.Data1,\n                        max,\n                        drawInfo->LineDataCount\n                        );\n                }\n\n                drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                drawInfo->LabelYFunctionParameter = max;\n\n                IoReadGraphState.Valid = TRUE;\n            }\n        }\n        break;\n    case GCN_GETTOOLTIPTEXT:\n        {\n            PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Parameter1;\n\n            if (getTooltipText->Index < getTooltipText->TotalCount)\n            {\n                if (IoReadGraphState.TooltipIndex != getTooltipText->Index)\n                {\n                    ULONG64 ioRead;\n                    PH_FORMAT format[5];\n\n                    ioRead = PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, getTooltipText->Index);\n\n                    // R: %s\\nW: %s\\nO: %s%s\\n%s\n                    PhInitFormatS(&format[0], L\"R: \");\n                    PhInitFormatSize(&format[1], ioRead);\n                    PhInitFormatSR(&format[2], PH_AUTO_T(PH_STRING, PhSipGetMaxIoString(getTooltipText->Index))->sr);\n                    PhInitFormatC(&format[3], L'\\n');\n                    PhInitFormatSR(&format[4], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n                    PhMoveReference(&IoReadGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 160));\n                }\n\n                getTooltipText->Text = IoReadGraphState.TooltipText->sr;\n            }\n        }\n        break;\n    case GCN_MOUSEEVENT:\n        {\n            PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Parameter1;\n            PPH_PROCESS_RECORD record;\n\n            record = NULL;\n\n            if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)\n            {\n                record = PhSipReferenceMaxIoRecord(mouseEvent->Index);\n            }\n\n            if (record)\n            {\n                PhShowProcessRecordDialog(IoDialog, record);\n                PhDereferenceProcessRecord(record);\n            }\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN PhSipNotifyIoWriteGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    switch (GraphMessage)\n    {\n    case GCN_GETDRAWINFO:\n        {\n            PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Parameter1;\n            PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;\n\n            drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y;\n            PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorIoWrite, 0, IoSection->Parameters->WindowDpi);\n\n            PhGraphStateGetDrawInfo(\n                &IoWriteGraphState,\n                getDrawInfo,\n                PhIoWriteHistory.Count\n                );\n\n            if (!IoWriteGraphState.Valid)\n            {\n                FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB\n\n                if (PhCsEnableAvxSupport && drawInfo->LineDataCount > 1024)\n                {\n                    PhCopyConvertCircularBufferULONG64(&PhIoWriteHistory, IoWriteGraphState.Data1, drawInfo->LineDataCount);\n                    max = PhMaxMemorySingles(IoWriteGraphState.Data1, drawInfo->LineDataCount);\n\n#ifdef DEBUG\n                    for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        assert(IoWriteGraphState.Data1[i] == (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i));\n                    }\n#endif\n                }\n                else\n                {\n                    for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        FLOAT value;\n\n                        IoWriteGraphState.Data1[i] = value = (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i);\n\n                        if (max < value)\n                            max = value;\n                    }\n                }\n\n                if (max != 0)\n                {\n                    // Scale the data.\n\n                    PhDivideSinglesBySingle(\n                        IoWriteGraphState.Data1,\n                        max,\n                        drawInfo->LineDataCount\n                        );\n                }\n\n                drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                drawInfo->LabelYFunctionParameter = max;\n\n                IoWriteGraphState.Valid = TRUE;\n            }\n        }\n        break;\n    case GCN_GETTOOLTIPTEXT:\n        {\n            PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Parameter1;\n\n            if (getTooltipText->Index < getTooltipText->TotalCount)\n            {\n                if (IoWriteGraphState.TooltipIndex != getTooltipText->Index)\n                {\n                    ULONG64 ioWrite;\n                    PH_FORMAT format[5];\n\n                    ioWrite = PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, getTooltipText->Index);\n\n                    // W: %s\\n%s\n                    PhInitFormatS(&format[0], L\"W: \");\n                    PhInitFormatSize(&format[1], ioWrite);\n                    PhInitFormatSR(&format[2], PH_AUTO_T(PH_STRING, PhSipGetMaxIoString(getTooltipText->Index))->sr);\n                    PhInitFormatC(&format[3], L'\\n');\n                    PhInitFormatSR(&format[4], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n                    PhMoveReference(&IoWriteGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 160));\n                }\n\n                getTooltipText->Text = IoWriteGraphState.TooltipText->sr;\n            }\n        }\n        break;\n    case GCN_MOUSEEVENT:\n        {\n            PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Parameter1;\n            PPH_PROCESS_RECORD record;\n\n            record = NULL;\n\n            if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)\n            {\n                record = PhSipReferenceMaxIoRecord(mouseEvent->Index);\n            }\n\n            if (record)\n            {\n                PhShowProcessRecordDialog(IoDialog, record);\n                PhDereferenceProcessRecord(record);\n            }\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN PhSipNotifyIoOtherGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    switch (GraphMessage)\n    {\n    case GCN_GETDRAWINFO:\n        {\n            PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Parameter1;\n            PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;\n\n            drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y;\n            PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorIoWrite, 0, IoSection->Parameters->WindowDpi);\n\n            PhGraphStateGetDrawInfo(\n                &IoOtherGraphState,\n                getDrawInfo,\n                PhIoOtherHistory.Count\n                );\n\n            if (!IoOtherGraphState.Valid)\n            {\n                FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB\n\n                if (PhCsEnableAvxSupport && drawInfo->LineDataCount > 1024)\n                {\n                    PhCopyConvertCircularBufferULONG64(&PhIoOtherHistory, IoOtherGraphState.Data1, drawInfo->LineDataCount);\n                    max = PhMaxMemorySingles(IoOtherGraphState.Data1, drawInfo->LineDataCount);\n\n#ifdef DEBUG\n                    for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        assert(IoOtherGraphState.Data1[i] == (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i));\n                    }\n#endif\n                }\n                else\n                {\n                    for (ULONG i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        FLOAT value;\n\n                        IoOtherGraphState.Data1[i] = value = (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i);\n\n                        if (max < value)\n                            max = value;\n                    }\n                }\n\n                if (max != 0)\n                {\n                    PhDivideSinglesBySingle(\n                        IoOtherGraphState.Data1,\n                        max,\n                        drawInfo->LineDataCount\n                        );\n                }\n\n                drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                drawInfo->LabelYFunctionParameter = max;\n\n                IoOtherGraphState.Valid = TRUE;\n            }\n        }\n        break;\n    case GCN_GETTOOLTIPTEXT:\n        {\n            PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Parameter1;\n\n            if (getTooltipText->Index < getTooltipText->TotalCount)\n            {\n                if (IoOtherGraphState.TooltipIndex != getTooltipText->Index)\n                {\n                    ULONG64 ioOther;\n                    PH_FORMAT format[5];\n\n                    ioOther = PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, getTooltipText->Index);\n\n                    // O: %s\\n%s\n                    PhInitFormatS(&format[0], L\"O: \");\n                    PhInitFormatSize(&format[1], ioOther);\n                    PhInitFormatSR(&format[2], PH_AUTO_T(PH_STRING, PhSipGetMaxIoString(getTooltipText->Index))->sr);\n                    PhInitFormatC(&format[3], L'\\n');\n                    PhInitFormatSR(&format[4], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n                    PhMoveReference(&IoOtherGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 160));\n                }\n\n                getTooltipText->Text = IoOtherGraphState.TooltipText->sr;\n            }\n        }\n        break;\n    case GCN_MOUSEEVENT:\n        {\n            PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Parameter1;\n            PPH_PROCESS_RECORD record;\n\n            record = NULL;\n\n            if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)\n            {\n                record = PhSipReferenceMaxIoRecord(mouseEvent->Index);\n            }\n\n            if (record)\n            {\n                PhShowProcessRecordDialog(IoDialog, record);\n                PhDereferenceProcessRecord(record);\n            }\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\nVOID PhSipUpdateIoGraph(\n    VOID\n    )\n{\n    IoReadGraphState.Valid = FALSE;\n    IoReadGraphState.TooltipIndex = ULONG_MAX;\n    Graph_Update(IoReadGraphHandle);\n\n    IoWriteGraphState.Valid = FALSE;\n    IoWriteGraphState.TooltipIndex = ULONG_MAX;\n    Graph_Update(IoWriteGraphHandle);\n\n    IoOtherGraphState.Valid = FALSE;\n    IoOtherGraphState.TooltipIndex = ULONG_MAX;\n    Graph_Update(IoOtherGraphHandle);\n}\n\nVOID PhSipUpdateIoPanel(\n    VOID\n    )\n{\n    PH_FORMAT format[1];\n    WCHAR formatBuffer[256];\n\n    // I/O Deltas\n\n    if (IoTicked > 1)\n    {\n        PhInitFormatI64UGroupDigits(&format[0], IoReadDelta.Delta);\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(IoPanelReadsDeltaLabel, formatBuffer);\n        else\n            PhSetWindowText(IoPanelReadsDeltaLabel, PhaFormatUInt64(IoReadDelta.Delta, TRUE)->Buffer);\n\n        PhInitFormatI64UGroupDigits(&format[0], IoWriteDelta.Delta);\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(IoPanelWritesDeltaLabel, formatBuffer);\n        else\n            PhSetWindowText(IoPanelWritesDeltaLabel, PhaFormatUInt64(IoWriteDelta.Delta, TRUE)->Buffer);\n\n        PhInitFormatI64UGroupDigits(&format[0], IoOtherDelta.Delta);\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(IoPanelOtherDeltaLabel, formatBuffer);\n        else\n            PhSetWindowText(IoPanelOtherDeltaLabel, PhaFormatUInt64(IoOtherDelta.Delta, TRUE)->Buffer);\n    }\n    else\n    {\n        PhSetWindowText(IoPanelReadsDeltaLabel, L\"-\");\n        PhSetWindowText(IoPanelWritesDeltaLabel, L\"-\");\n        PhSetWindowText(IoPanelOtherDeltaLabel, L\"-\");\n    }\n\n    if (PhIoReadHistory.Count != 0)\n    {\n        PhInitFormatSize(&format[0], PhIoReadDelta.Delta);\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(IoPanelReadBytesDeltaLabel, formatBuffer);\n        else\n            PhSetWindowText(IoPanelReadBytesDeltaLabel, PhaFormatSize(PhIoReadDelta.Delta, ULONG_MAX)->Buffer);\n\n        PhInitFormatSize(&format[0], PhIoWriteDelta.Delta);\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(IoPanelWriteBytesDeltaLabel, formatBuffer);\n        else\n            PhSetWindowText(IoPanelWriteBytesDeltaLabel, PhaFormatSize(PhIoWriteDelta.Delta, ULONG_MAX)->Buffer);\n\n        PhInitFormatSize(&format[0], PhIoOtherDelta.Delta);\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n            PhSetWindowText(IoPanelOtherBytesDeltaLabel, formatBuffer);\n        else\n            PhSetWindowText(IoPanelOtherBytesDeltaLabel, PhaFormatSize(PhIoOtherDelta.Delta, ULONG_MAX)->Buffer);\n    }\n    else\n    {\n        PhSetWindowText(IoPanelReadBytesDeltaLabel, L\"-\");\n        PhSetWindowText(IoPanelWriteBytesDeltaLabel, L\"-\");\n        PhSetWindowText(IoPanelOtherBytesDeltaLabel, L\"-\");\n    }\n\n    // I/O Totals\n\n    PhInitFormatI64UGroupDigits(&format[0], PhPerfInformation.IoReadOperationCount);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(IoPanelReadsLabel, formatBuffer);\n    else\n        PhSetWindowText(IoPanelReadsLabel, PhaFormatUInt64(PhPerfInformation.IoReadOperationCount, TRUE)->Buffer);\n\n    PhInitFormatSize(&format[0], PhPerfInformation.IoReadTransferCount.QuadPart);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(IoPanelReadBytesLabel, formatBuffer);\n    else\n        PhSetWindowText(IoPanelReadBytesLabel, PhaFormatSize(PhPerfInformation.IoReadTransferCount.QuadPart, ULONG_MAX)->Buffer);\n\n    PhInitFormatI64UGroupDigits(&format[0], PhPerfInformation.IoWriteOperationCount);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(IoPanelWritesLabel, formatBuffer);\n    else\n        PhSetWindowText(IoPanelWritesLabel, PhaFormatUInt64(PhPerfInformation.IoWriteOperationCount, TRUE)->Buffer);\n\n    PhInitFormatSize(&format[0], PhPerfInformation.IoWriteTransferCount.QuadPart);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(IoPanelWriteBytesLabel, formatBuffer);\n    else\n        PhSetWindowText(IoPanelWriteBytesLabel, PhaFormatSize(PhPerfInformation.IoWriteTransferCount.QuadPart, ULONG_MAX)->Buffer);\n\n    PhInitFormatI64UGroupDigits(&format[0], PhPerfInformation.IoOtherOperationCount);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(IoPanelOtherLabel, formatBuffer);\n    else\n        PhSetWindowText(IoPanelOtherLabel, PhaFormatUInt64(PhPerfInformation.IoOtherOperationCount, TRUE)->Buffer);\n\n    PhInitFormatSize(&format[0], PhPerfInformation.IoOtherTransferCount.QuadPart);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL))\n        PhSetWindowText(IoPanelOtherBytesLabel, formatBuffer);\n    else\n        PhSetWindowText(IoPanelOtherBytesLabel, PhaFormatSize(PhPerfInformation.IoOtherTransferCount.QuadPart, ULONG_MAX)->Buffer);\n}\n\nPPH_PROCESS_RECORD PhSipReferenceMaxIoRecord(\n    _In_ LONG Index\n    )\n{\n    LARGE_INTEGER time;\n    ULONG maxProcessId;\n\n    // Find the process record for the max. I/O process for the particular time.\n\n    maxProcessId = PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, Index);\n\n    if (!maxProcessId)\n        return NULL;\n\n    // See above for the explanation.\n    PhGetStatisticsTime(NULL, Index, &time);\n    time.QuadPart += PH_TICKS_PER_SEC - 1;\n\n    return PhFindProcessRecord(UlongToHandle(maxProcessId), &time);\n}\n\nPPH_STRING PhSipGetMaxIoString(\n    _In_ LONG Index\n    )\n{\n    PPH_PROCESS_RECORD maxProcessRecord;\n#ifdef PH_RECORD_MAX_USAGE\n    ULONG64 maxIoReadOther;\n    ULONG64 maxIoWrite;\n#endif\n\n    if (maxProcessRecord = PhSipReferenceMaxIoRecord(Index))\n    {\n        PPH_STRING maxUsageString;\n\n        // We found the process record, so now we construct the max. usage string.\n#ifdef PH_RECORD_MAX_USAGE\n        maxIoReadOther = PhGetItemCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, Index);\n        maxIoWrite = PhGetItemCircularBuffer_ULONG64(&PhMaxIoWriteHistory, Index);\n\n        if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId))\n        {\n            PH_FORMAT format[8];\n\n            // \\n%s (%u): R+O: %s, W: %s\n            PhInitFormatC(&format[0], L'\\n');\n            PhInitFormatSR(&format[1], maxProcessRecord->ProcessName->sr);\n            PhInitFormatS(&format[2], L\" (\");\n            PhInitFormatU(&format[3], HandleToUlong(maxProcessRecord->ProcessId));\n            PhInitFormatS(&format[4], L\"): R+O: \");\n            PhInitFormatSize(&format[5], maxIoReadOther);\n            PhInitFormatS(&format[6], L\", W: \");\n            PhInitFormatSize(&format[7], maxIoWrite);\n\n            maxUsageString = PhFormat(format, RTL_NUMBER_OF(format), 128);\n        }\n        else\n        {\n            PH_FORMAT format[6];\n\n            // \\n%s: R+O: %s, W: %s\n            PhInitFormatC(&format[0], L'\\n');\n            PhInitFormatSR(&format[1], maxProcessRecord->ProcessName->sr);\n            PhInitFormatS(&format[2], L\": R+O: \");\n            PhInitFormatSize(&format[3], maxIoReadOther);\n            PhInitFormatS(&format[4], L\", W: \");\n            PhInitFormatSize(&format[5], maxIoWrite);\n\n            maxUsageString = PhFormat(format, RTL_NUMBER_OF(format), 128);\n        }\n#else\n        PH_FORMAT format[2];\n\n        PhInitFormatC(&format[0], L'\\n');\n        PhInitFormatSR(&format[1], maxProcessRecord->ProcessName->sr);\n\n        maxUsageString = PhFormat(format, RTL_NUMBER_OF(format), 128);\n#endif\n\n        PhDereferenceProcessRecord(maxProcessRecord);\n\n        return maxUsageString;\n    }\n\n    return PhReferenceEmptyString();\n}\n"
  },
  {
    "path": "SystemInformer/sysscmem.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <sysinfo.h>\n#include <sysinfop.h>\n\n#include <kphuser.h>\n#include <symprv.h>\n#include <workqueue.h>\n#include <settings.h>\n#include <phfirmware.h>\n\n#include <procprv.h>\n#include <phsettings.h>\n\nstatic CONST PH_KEY_VALUE_PAIR MemoryFormFactors[] =\n{\n    SIP(L\"Other\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_OTHER),\n    SIP(L\"Unknown\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_UNKNOWN),\n    SIP(L\"SIMM\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_SIMM),\n    SIP(L\"SIP\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_SIP),\n    SIP(L\"Chip\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_CHIP),\n    SIP(L\"DIP\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_DIP),\n    SIP(L\"ZIP\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_ZIP),\n    SIP(L\"Proprietary\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_PROPRIETARY),\n    SIP(L\"DIMM\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_DIMM),\n    SIP(L\"TOSP\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_TSOP),\n    SIP(L\"Row of chips\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_ROW_OF_CHIPS),\n    SIP(L\"RIMM\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_RIMM),\n    SIP(L\"SODIMM\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_SODIMM),\n    SIP(L\"SRIMM\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_SRIMM),\n    SIP(L\"FB-DIMM\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_FB_DIMM),\n    SIP(L\"Die\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_DIE),\n    SIP(L\"CAMM\", SMBIOS_MEMORY_DEVICE_FORM_FACTOR_CAMM),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR MemoryTypes[] =\n{\n    SIP(L\"Other\", SMBIOS_MEMORY_DEVICE_TYPE_OTHER),\n    SIP(L\"Unknown\", SMBIOS_MEMORY_DEVICE_TYPE_UNKNOWN),\n    SIP(L\"DRAM\", SMBIOS_MEMORY_DEVICE_TYPE_DRAM),\n    SIP(L\"EDRAM\", SMBIOS_MEMORY_DEVICE_TYPE_EDRAM),\n    SIP(L\"VRAM\", SMBIOS_MEMORY_DEVICE_TYPE_VRAM),\n    SIP(L\"SRAM\", SMBIOS_MEMORY_DEVICE_TYPE_SRAM),\n    SIP(L\"RAM\", SMBIOS_MEMORY_DEVICE_TYPE_RAM),\n    SIP(L\"ROM\", SMBIOS_MEMORY_DEVICE_TYPE_ROM),\n    SIP(L\"FLASH\", SMBIOS_MEMORY_DEVICE_TYPE_FLASH),\n    SIP(L\"EEPROM\", SMBIOS_MEMORY_DEVICE_TYPE_EEPROM),\n    SIP(L\"FEPROM\", SMBIOS_MEMORY_DEVICE_TYPE_FEPROM),\n    SIP(L\"EPROM\", SMBIOS_MEMORY_DEVICE_TYPE_EPROM),\n    SIP(L\"CDRAM\", SMBIOS_MEMORY_DEVICE_TYPE_CDRAM),\n    SIP(L\"3DRAM\", SMBIOS_MEMORY_DEVICE_TYPE_3DRAM),\n    SIP(L\"SDRAM\", SMBIOS_MEMORY_DEVICE_TYPE_SDRAM),\n    SIP(L\"SGRAM\", SMBIOS_MEMORY_DEVICE_TYPE_SGRAM),\n    SIP(L\"RDRAM\", SMBIOS_MEMORY_DEVICE_TYPE_RDRAM),\n    SIP(L\"DDR\", SMBIOS_MEMORY_DEVICE_TYPE_DDR),\n    SIP(L\"DDR2\", SMBIOS_MEMORY_DEVICE_TYPE_DDR2),\n    SIP(L\"DDR2-FM-DIMM\", SMBIOS_MEMORY_DEVICE_TYPE_DDR2_FB_DIMM),\n    SIP(L\"DDR3\", SMBIOS_MEMORY_DEVICE_TYPE_DDR3),\n    SIP(L\"FBD2\", SMBIOS_MEMORY_DEVICE_TYPE_FBD2),\n    SIP(L\"DDR4\", SMBIOS_MEMORY_DEVICE_TYPE_DDR4),\n    SIP(L\"LPDDR\", SMBIOS_MEMORY_DEVICE_TYPE_LPDDR),\n    SIP(L\"LPDDR2\", SMBIOS_MEMORY_DEVICE_TYPE_LPDDR2),\n    SIP(L\"LPDDR3\", SMBIOS_MEMORY_DEVICE_TYPE_LPDDR3),\n    SIP(L\"LPDDR4\", SMBIOS_MEMORY_DEVICE_TYPE_LPDDR4),\n    SIP(L\"Local non-volatile\", SMBIOS_MEMORY_DEVICE_TYPE_LOCAL_NON_VOLATILE),\n    SIP(L\"HBM\", SMBIOS_MEMORY_DEVICE_TYPE_HBM),\n    SIP(L\"HBM2\", SMBIOS_MEMORY_DEVICE_TYPE_HBM2),\n    SIP(L\"DDR5\", SMBIOS_MEMORY_DEVICE_TYPE_DDR5),\n    SIP(L\"LPDDR5\", SMBIOS_MEMORY_DEVICE_TYPE_LPDDR5),\n    SIP(L\"HBM3\", SMBIOS_MEMORY_DEVICE_TYPE_HBM3),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR MemoryTechnologies[] =\n{\n    SIP(L\"Other\", SMBIOS_MEMORY_DEVICE_TECHNOLOGY_OTHER),\n    SIP(L\"Unknown\", SMBIOS_MEMORY_DEVICE_TECHNOLOGY_UNKNOWN),\n    SIP(L\"DRAM\", SMBIOS_MEMORY_DEVICE_TECHNOLOGY_DRAM),\n    SIP(L\"NVDIMM-N\", SMBIOS_MEMORY_DEVICE_TECHNOLOGY_NVDIMM_N),\n    SIP(L\"NVDIMM-F\", SMBIOS_MEMORY_DEVICE_TECHNOLOGY_NVDIMM_F),\n    SIP(L\"NVDIMM-P\", SMBIOS_MEMORY_DEVICE_TECHNOLOGY_NVDIMM_P),\n    SIP(L\"Intel Optane\", SMBIOS_MEMORY_DEVICE_TECHNOLOGY_INTEL_OPTANE),\n    SIP(L\"MRDIMM\", SMBIOS_MEMORY_DEVICE_TECHNOLOGY_MRDIMM),\n};\n\nstatic BOOLEAN ShowCommitInSummary;\nstatic PPH_SYSINFO_SECTION MemorySection;\nstatic HWND MemoryDialog;\nstatic PH_LAYOUT_MANAGER MemoryLayoutManager;\nstatic RECT MemoryGraphMargin;\nstatic HWND CommitGraphHandle;\nstatic PH_GRAPH_STATE CommitGraphState;\nstatic HWND PhysicalGraphHandle;\nstatic PH_GRAPH_STATE PhysicalGraphState;\nstatic HWND MemoryPanel;\nstatic ULONG MemoryTicked;\nstatic PH_UINT32_DELTA PagedAllocsDelta;\nstatic PH_UINT32_DELTA PagedFreesDelta;\nstatic PH_UINT32_DELTA NonPagedAllocsDelta;\nstatic PH_UINT32_DELTA NonPagedFreesDelta;\nstatic PH_UINT32_DELTA PageFaultsDelta;\nstatic PH_UINT32_DELTA PageReadsDelta;\nstatic PH_UINT32_DELTA PagefileWritesDelta;\nstatic PH_UINT32_DELTA MappedWritesDelta;\nstatic PH_UINT64_DELTA MappedIoReadDelta;\nstatic PH_UINT64_DELTA MappedIoWritesDelta;\nstatic BOOLEAN MmAddressesInitialized;\nstatic PSIZE_T MmSizeOfPagedPoolInBytes;\nstatic PSIZE_T MmMaximumNonPagedPoolInBytes;\nstatic ULONGLONG InstalledMemory;\nstatic ULONGLONG ReservedMemory;\nstatic ULONG MemorySlotsTotal;\nstatic ULONG MemorySlotsUsed;\nstatic UCHAR MemoryFormFactor;\nstatic UCHAR MemoryTechnology;\nstatic UCHAR MemoryType;\nstatic ULONG MemorySpeed;\n\n_Function_class_(PH_ENUM_SMBIOS_CALLBACK)\nBOOLEAN NTAPI PhpSipMemorySMBIOSCallback(\n    _In_ ULONG_PTR EnumHandle,\n    _In_ UCHAR MajorVersion,\n    _In_ UCHAR MinorVersion,\n    _In_ PPH_SMBIOS_ENTRY Entry,\n    _In_opt_ PVOID Context\n    )\n{\n    UCHAR formFactor = 0;\n    UCHAR memoryType = 0;\n    UCHAR technology = 0;\n    ULONG speed = 0;\n\n    if (Entry->Header.Type != SMBIOS_MEMORY_DEVICE_INFORMATION_TYPE)\n        return FALSE;\n\n    if (PH_SMBIOS_CONTAINS_FIELD(Entry, MemoryDevice, Technology))\n        technology = Entry->MemoryDevice.Technology;\n    if (PH_SMBIOS_CONTAINS_FIELD(Entry, MemoryDevice, MemoryType))\n        memoryType = Entry->MemoryDevice.MemoryType;\n    if (PH_SMBIOS_CONTAINS_FIELD(Entry, MemoryDevice, FormFactor))\n        formFactor = Entry->MemoryDevice.FormFactor;\n\n    if (PH_SMBIOS_CONTAINS_FIELD(Entry, MemoryDevice, ConfiguredSpeed))\n        speed = Entry->MemoryDevice.ConfiguredSpeed;\n    if (speed == MAXUSHORT && PH_SMBIOS_CONTAINS_FIELD(Entry, MemoryDevice, ExtendedConfiguredSpeed))\n        speed = Entry->MemoryDevice.ExtendedConfiguredSpeed;\n\n    if (!speed)\n    {\n        if (PH_SMBIOS_CONTAINS_FIELD(Entry, MemoryDevice, Speed))\n            speed = Entry->MemoryDevice.Speed;\n        if (speed == MAXUSHORT && PH_SMBIOS_CONTAINS_FIELD(Entry, MemoryDevice, ExtendedSpeed))\n            speed = Entry->MemoryDevice.ExtendedSpeed;\n    }\n\n    MemorySlotsTotal++;\n    if (Entry->MemoryDevice.Size.Value)\n        MemorySlotsUsed++;\n\n    MemoryFormFactor = max(MemoryFormFactor, formFactor);\n    MemoryType = max(MemoryType, memoryType);\n    MemoryTechnology = max(MemoryTechnology, technology);\n    MemorySpeed = max(MemorySpeed, speed);\n\n    return FALSE;\n}\n\n_Function_class_(PH_SYSINFO_SECTION_CALLBACK)\nBOOLEAN PhSipMemorySectionCallback(\n    _In_ PPH_SYSINFO_SECTION Section,\n    _In_ PH_SYSINFO_SECTION_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2\n    )\n{\n    switch (Message)\n    {\n    case SysInfoCreate:\n        {\n            ShowCommitInSummary = !!PhGetIntegerSetting(SETTING_SHOW_COMMIT_IN_SUMMARY);\n            MemorySection = Section;\n            MemorySlotsTotal = 0;\n            MemorySlotsUsed = 0;\n            MemoryFormFactor = 0;\n            MemoryType = 0;\n            MemorySpeed = 0;\n            PhEnumSMBIOS(PhpSipMemorySMBIOSCallback, NULL);\n        }\n        return TRUE;\n    case SysInfoDestroy:\n        {\n            if (MemoryDialog)\n            {\n                PhSipUninitializeMemoryDialog();\n                MemoryDialog = NULL;\n            }\n        }\n        break;\n    case SysInfoTick:\n        {\n            if (MemoryDialog)\n            {\n                PhSipTickMemoryDialog();\n            }\n        }\n        return TRUE;\n    case SysInfoViewChanging:\n        {\n            PH_SYSINFO_VIEW_TYPE view = (PH_SYSINFO_VIEW_TYPE)PtrToUlong(Parameter1);\n            PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Parameter2;\n\n            if (view == SysInfoSummaryView || section != Section)\n                return TRUE;\n\n            if (CommitGraphHandle)\n            {\n                CommitGraphState.Valid = FALSE;\n                CommitGraphState.TooltipIndex = ULONG_MAX;\n                Graph_Draw(CommitGraphHandle);\n            }\n\n            if (PhysicalGraphHandle)\n            {\n                PhysicalGraphState.Valid = FALSE;\n                PhysicalGraphState.TooltipIndex = ULONG_MAX;\n                Graph_Draw(PhysicalGraphHandle);\n            }\n        }\n        return TRUE;\n    case SysInfoCreateDialog:\n        {\n            PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;\n\n            createDialog->Instance = PhInstanceHandle;\n            createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_MEM);\n            createDialog->DialogProc = PhSipMemoryDialogProc;\n        }\n        return TRUE;\n    case SysInfoGraphGetDrawInfo:\n        {\n            PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;\n            ULONG i;\n\n            if (ShowCommitInSummary)\n            {\n                drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | (PhCsEnableGraphMaxText ? PH_GRAPH_LABEL_MAX_Y : 0);\n                Section->Parameters->ColorSetupFunction(drawInfo, PhCsColorPrivate, 0, Section->Parameters->WindowDpi);\n                PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, PhCommitHistory.Count);\n\n                if (!Section->GraphState.Valid)\n                {\n                    if (PhCsEnableAvxSupport)\n                    {\n                        PhCopyConvertCircularBufferULONG(&PhCommitHistory, Section->GraphState.Data1, drawInfo->LineDataCount);\n#ifdef DEBUG\n                        for (i = 0; i < drawInfo->LineDataCount; i++)\n                        {\n                            assert(Section->GraphState.Data1[i] == (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i));\n                        }\n#endif\n                    }\n                    else\n                    {\n                        for (i = 0; i < drawInfo->LineDataCount; i++)\n                        {\n                            Section->GraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i);\n                        }\n                    }\n\n                    if (PhPerfInformation.CommitLimit != 0)\n                    {\n                        // Scale the data.\n                        PhDivideSinglesBySingle(\n                            Section->GraphState.Data1,\n                            (FLOAT)PhPerfInformation.CommitLimit,\n                            drawInfo->LineDataCount\n                            );\n                    }\n\n                    if (PhCsEnableGraphMaxText)\n                    {\n                        drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                        drawInfo->LabelYFunctionParameter = (FLOAT)UInt32x32To64(PhPerfInformation.CommitLimit, PAGE_SIZE);\n                    }\n\n                    Section->GraphState.Valid = TRUE;\n                }\n            }\n            else\n            {\n                drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | (PhCsEnableGraphMaxText ? PH_GRAPH_LABEL_MAX_Y : 0);\n                Section->Parameters->ColorSetupFunction(drawInfo, PhCsColorPhysical, 0, Section->Parameters->WindowDpi);\n                PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, PhPhysicalHistory.Count);\n\n                if (!Section->GraphState.Valid)\n                {\n                    if (PhCsEnableAvxSupport)\n                    {\n                        PhCopyConvertCircularBufferULONG(&PhPhysicalHistory, Section->GraphState.Data1, drawInfo->LineDataCount);\n#ifdef DEBUG\n                        for (i = 0; i < drawInfo->LineDataCount; i++)\n                        {\n                            assert(Section->GraphState.Data1[i] == (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i));\n                        }\n#endif\n                    }\n                    else\n                    {\n                        for (i = 0; i < drawInfo->LineDataCount; i++)\n                        {\n                            Section->GraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i);\n                        }\n                    }\n\n                    if (PhSystemBasicInformation.NumberOfPhysicalPages != 0)\n                    {\n                        // Scale the data.\n                        PhDivideSinglesBySingle(\n                            Section->GraphState.Data1,\n                            (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages,\n                            drawInfo->LineDataCount\n                            );\n                    }\n\n                    if (PhCsEnableGraphMaxText)\n                    {\n                        drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                        drawInfo->LabelYFunctionParameter = (FLOAT)UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE);\n                    }\n\n                    Section->GraphState.Valid = TRUE;\n                }\n            }\n        }\n        return TRUE;\n    case SysInfoGraphGetTooltipText:\n        {\n            PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;\n            ULONG usedPages;\n            PH_FORMAT format[3];\n\n            if (ShowCommitInSummary)\n            {\n                usedPages = PhGetItemCircularBuffer_ULONG(&PhCommitHistory, getTooltipText->Index);\n\n                // Commit charge: %s\\n%s\n                PhInitFormatSize(&format[0], UInt32x32To64(usedPages, PAGE_SIZE));\n                PhInitFormatC(&format[1], L'\\n');\n                PhInitFormatSR(&format[2], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n                PhMoveReference(&Section->GraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 128));\n                getTooltipText->Text = Section->GraphState.TooltipText->sr;\n            }\n            else\n            {\n                usedPages = PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, getTooltipText->Index);\n\n                // Physical memory: %s\\n%s\n                PhInitFormatSize(&format[0], UInt32x32To64(usedPages, PAGE_SIZE));\n                PhInitFormatC(&format[1], L'\\n');\n                PhInitFormatSR(&format[2], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n                PhMoveReference(&Section->GraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 128));\n                getTooltipText->Text = Section->GraphState.TooltipText->sr;\n            }\n        }\n        return TRUE;\n    case SysInfoGraphDrawPanel:\n        {\n            PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;\n            ULONG totalPages;\n            ULONG usedPages;\n            PH_FORMAT format[5];\n\n            if (ShowCommitInSummary)\n            {\n                totalPages = PhPerfInformation.CommitLimit;\n                usedPages = PhPerfInformation.CommittedPages;\n            }\n            else\n            {\n                totalPages = PhSystemBasicInformation.NumberOfPhysicalPages;\n                usedPages = totalPages - PhPerfInformation.AvailablePages;\n            }\n\n            drawPanel->Title = PhCreateString(L\"Memory\");\n\n            // %.0f%%\\n%s / %s\n            PhInitFormatF(&format[0], ((FLOAT)usedPages / (FLOAT)totalPages) * 100, 0);\n            PhInitFormatS(&format[1], L\"%\\n\");\n            PhInitFormatSizeWithPrecision(&format[2], UInt32x32To64(usedPages, PAGE_SIZE), 1);\n            PhInitFormatS(&format[3], L\" / \");\n            PhInitFormatSizeWithPrecision(&format[4], UInt32x32To64(totalPages, PAGE_SIZE), 1);\n\n            drawPanel->SubTitle = PhFormat(format, 5, 64);\n\n            // %.0f%%\\n%s\n            PhInitFormatF(&format[0], ((FLOAT)usedPages / (FLOAT)totalPages) * 100, 0);\n            PhInitFormatS(&format[1], L\"%\\n\");\n            PhInitFormatSizeWithPrecision(&format[2], UInt32x32To64(usedPages, PAGE_SIZE), 1);\n\n            drawPanel->SubTitleOverflow = PhFormat(format, 3, 0);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhSipInitializeMemoryDialog(\n    VOID\n    )\n{\n    PhInitializeDelta(&PagedAllocsDelta);\n    PhInitializeDelta(&PagedFreesDelta);\n    PhInitializeDelta(&NonPagedAllocsDelta);\n    PhInitializeDelta(&NonPagedFreesDelta);\n    PhInitializeDelta(&PageFaultsDelta);\n    PhInitializeDelta(&PageReadsDelta);\n    PhInitializeDelta(&PagefileWritesDelta);\n    PhInitializeDelta(&MappedWritesDelta);\n    PhInitializeDelta(&MappedIoReadDelta);\n    PhInitializeDelta(&MappedIoWritesDelta);\n\n    PhInitializeGraphState(&CommitGraphState);\n    PhInitializeGraphState(&PhysicalGraphState);\n\n    MemoryTicked = 0;\n\n    if (!MmAddressesInitialized)\n    {\n        PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhSipLoadMmAddresses, NULL);\n        MmAddressesInitialized = TRUE;\n    }\n}\n\nVOID PhSipUninitializeMemoryDialog(\n    VOID\n    )\n{\n    PhDeleteGraphState(&CommitGraphState);\n    PhDeleteGraphState(&PhysicalGraphState);\n\n    // Note: Required for SysInfoViewChanging (dmex)\n    CommitGraphHandle = NULL;\n    PhysicalGraphHandle = NULL;\n}\n\nVOID PhSipTickMemoryDialog(\n    VOID\n    )\n{\n    PhUpdateDelta(&PagedAllocsDelta, PhPerfInformation.PagedPoolAllocs);\n    PhUpdateDelta(&PagedFreesDelta, PhPerfInformation.PagedPoolFrees);\n    PhUpdateDelta(&NonPagedAllocsDelta, PhPerfInformation.NonPagedPoolAllocs);\n    PhUpdateDelta(&NonPagedFreesDelta, PhPerfInformation.NonPagedPoolFrees);\n    PhUpdateDelta(&PageFaultsDelta, PhPerfInformation.PageFaultCount);\n    PhUpdateDelta(&PageReadsDelta, PhPerfInformation.PageReadCount);\n    PhUpdateDelta(&PagefileWritesDelta, PhPerfInformation.DirtyPagesWriteCount);\n    PhUpdateDelta(&MappedWritesDelta, PhPerfInformation.MappedPagesWriteCount);\n    PhUpdateDelta(&MappedIoReadDelta, UInt32x32To64(PhPerfInformation.PageReadCount, PAGE_SIZE));\n    PhUpdateDelta(&MappedIoWritesDelta, ((ULONG64)PhPerfInformation.MappedPagesWriteCount + PhPerfInformation.DirtyPagesWriteCount + PhPerfInformation.CcLazyWritePages) * PAGE_SIZE);\n\n    if (MemoryTicked < 2)\n        MemoryTicked++;\n\n    PhSipUpdateMemoryGraphs();\n    PhSipUpdateMemoryPanel();\n}\n\nINT_PTR CALLBACK PhSipMemoryDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_LAYOUT_ITEM graphItem;\n            PPH_LAYOUT_ITEM panelItem;\n            RECT margin;\n            HWND totalPhysicalLabel;\n\n            PhSipInitializeMemoryDialog();\n\n            MemoryDialog = hwndDlg;\n            totalPhysicalLabel = GetDlgItem(hwndDlg, IDC_TOTALPHYSICAL);\n\n            PhInitializeLayoutManager(&MemoryLayoutManager, hwndDlg);\n            PhAddLayoutItem(&MemoryLayoutManager, totalPhysicalLabel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);\n            graphItem = PhAddLayoutItem(&MemoryLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);\n            panelItem = PhAddLayoutItem(&MemoryLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            MemoryGraphMargin = graphItem->Margin;\n\n            SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), MemorySection->Parameters->LargeFont, FALSE);\n            SetWindowFont(totalPhysicalLabel, MemorySection->Parameters->MediumFont, FALSE);\n\n            if (NT_SUCCESS(PhGetPhysicallyInstalledSystemMemory(&InstalledMemory, &ReservedMemory)))\n            {\n                PhSetWindowText(totalPhysicalLabel, PhaConcatStrings2(\n                    PhaFormatSize(InstalledMemory, ULONG_MAX)->Buffer, L\" installed\")->Buffer);\n            }\n            else\n            {\n                PhSetWindowText(totalPhysicalLabel, PhaConcatStrings2(\n                    PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), ULONG_MAX)->Buffer, L\" total\")->Buffer);\n            }\n\n            MemoryPanel = PhCreateDialog(PhInstanceHandle, MAKEINTRESOURCE(IDD_SYSINFO_MEMPANEL), hwndDlg, PhSipMemoryPanelDialogProc, NULL);\n            ShowWindow(MemoryPanel, SW_SHOW);\n\n            margin = panelItem->Margin;\n            PhGetSizeDpiValue(&margin, MemorySection->Parameters->WindowDpi, TRUE);\n            PhAddLayoutItemEx(&MemoryLayoutManager, MemoryPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, &margin);\n\n            PhSipCreateMemoryGraphs();\n            PhSipUpdateMemoryGraphs();\n            PhSipUpdateMemoryPanel();\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhDeleteLayoutManager(&MemoryLayoutManager);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            if (MemorySection->Parameters->LargeFont)\n            {\n                SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), MemorySection->Parameters->LargeFont, FALSE);\n            }\n\n            if (MemorySection->Parameters->MediumFont)\n            {\n                SetWindowFont(GetDlgItem(hwndDlg, IDC_TOTALPHYSICAL), MemorySection->Parameters->MediumFont, FALSE);\n            }\n\n            CommitGraphState.Valid = FALSE;\n            CommitGraphState.TooltipIndex = ULONG_MAX;\n            PhysicalGraphState.Valid = FALSE;\n            PhysicalGraphState.TooltipIndex = ULONG_MAX;\n\n            PhLayoutManagerUpdate(&MemoryLayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&MemoryLayoutManager);\n            PhSipLayoutMemoryGraphs(hwndDlg);\n        }\n        break;\n    case WM_SIZE:\n        {\n            CommitGraphState.Valid = FALSE;\n            CommitGraphState.TooltipIndex = ULONG_MAX;\n            PhysicalGraphState.Valid = FALSE;\n            PhysicalGraphState.TooltipIndex = ULONG_MAX;\n            PhLayoutManagerLayout(&MemoryLayoutManager);\n            PhSipLayoutMemoryGraphs(hwndDlg);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nINT_PTR CALLBACK PhSipMemoryPanelDialogProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            NOTHING;\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_MORE:\n                {\n                    PhShowMemoryListsDialog(PhSipWindow, PhSipRegisterDialog, PhSipUnregisterDialog);\n                }\n                break;\n            case IDC_EMPTY:\n                {\n                    extern VOID PhShowMemoryListCommand(_In_ HWND ParentWindow, _In_ HWND ButtonWindow, _In_ BOOLEAN ShowTopAlign); // memlists.c (dmex);\n\n                    PhShowMemoryListCommand(PhSipWindow, GET_WM_COMMAND_HWND(wParam, lParam), TRUE);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhSipCreateMemoryGraphs(\n    VOID\n    )\n{\n    PH_GRAPH_CREATEPARAMS graphCreateParams;\n\n    memset(&graphCreateParams, 0, sizeof(PH_GRAPH_CREATEPARAMS));\n    graphCreateParams.Size = sizeof(PH_GRAPH_CREATEPARAMS);\n    graphCreateParams.Callback = PhSipNotifyCommitGraph;\n\n    CommitGraphHandle = PhCreateWindow(\n        PH_GRAPH_CLASSNAME,\n        NULL,\n        WS_VISIBLE | WS_CHILD | WS_BORDER,\n        0,\n        0,\n        0,\n        0,\n        MemoryDialog,\n        NULL,\n        PhInstanceHandle,\n        &graphCreateParams\n        );\n    Graph_SetTooltip(CommitGraphHandle, TRUE);\n\n    memset(&graphCreateParams, 0, sizeof(PH_GRAPH_CREATEPARAMS));\n    graphCreateParams.Size = sizeof(PH_GRAPH_CREATEPARAMS);\n    graphCreateParams.Callback = PhSipNotifyPhysicalGraph;\n\n    PhysicalGraphHandle = PhCreateWindow(\n        PH_GRAPH_CLASSNAME,\n        NULL,\n        WS_VISIBLE | WS_CHILD | WS_BORDER,\n        0,\n        0,\n        0,\n        0,\n        MemoryDialog,\n        NULL,\n        PhInstanceHandle,\n        &graphCreateParams\n        );\n    Graph_SetTooltip(PhysicalGraphHandle, TRUE);\n}\n\nVOID PhSipLayoutMemoryGraphs(\n    _In_ HWND hwnd\n    )\n{\n    RECT clientRect;\n    RECT labelRect;\n    RECT marginRect;\n    ULONG graphWidth;\n    ULONG graphHeight;\n    HDWP deferHandle;\n    ULONG y;\n\n    marginRect = MemoryGraphMargin;\n    PhGetSizeDpiValue(&marginRect, MemorySection->Parameters->WindowDpi, TRUE);\n\n    if (!PhGetClientRect(MemoryDialog, &clientRect))\n        return;\n    if (!PhGetClientRect(GetDlgItem(MemoryDialog, IDC_COMMIT_L), &labelRect))\n        return;\n\n    graphWidth = clientRect.right - marginRect.left - marginRect.right;\n    graphHeight = (clientRect.bottom - marginRect.top - marginRect.bottom - labelRect.bottom * 2 - MemorySection->Parameters->MemoryPadding * 3) / 2;\n\n    deferHandle = BeginDeferWindowPos(4);\n    y = marginRect.top;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        GetDlgItem(MemoryDialog, IDC_COMMIT_L),\n        NULL,\n        marginRect.left,\n        y,\n        0,\n        0,\n        SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER\n        );\n    y += labelRect.bottom + MemorySection->Parameters->MemoryPadding;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        CommitGraphHandle,\n        NULL,\n        marginRect.left,\n        y,\n        graphWidth,\n        graphHeight,\n        SWP_NOACTIVATE | SWP_NOZORDER\n        );\n    y += graphHeight + MemorySection->Parameters->MemoryPadding;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        GetDlgItem(MemoryDialog, IDC_PHYSICAL_L),\n        NULL,\n        marginRect.left,\n        y,\n        0,\n        0,\n        SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER\n        );\n    y += labelRect.bottom + MemorySection->Parameters->MemoryPadding;\n\n    deferHandle = DeferWindowPos(\n        deferHandle,\n        PhysicalGraphHandle,\n        NULL,\n        marginRect.left,\n        y,\n        graphWidth,\n        clientRect.bottom - marginRect.bottom - y,\n        SWP_NOACTIVATE | SWP_NOZORDER\n        );\n\n    EndDeferWindowPos(deferHandle);\n}\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipNotifyCommitGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    switch (GraphMessage)\n    {\n    case GCN_GETDRAWINFO:\n        {\n            PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Parameter1;\n            PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;\n            ULONG i;\n\n            drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | (PhCsEnableGraphMaxText ? PH_GRAPH_LABEL_MAX_Y : 0);\n            PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorPrivate, 0, MemorySection->Parameters->WindowDpi);\n\n            PhGraphStateGetDrawInfo(\n                &CommitGraphState,\n                getDrawInfo,\n                PhCommitHistory.Count\n                );\n\n            if (!CommitGraphState.Valid)\n            {\n                if (PhCsEnableAvxSupport)\n                {\n                    PhCopyConvertCircularBufferULONG(&PhCommitHistory, CommitGraphState.Data1, drawInfo->LineDataCount);\n#ifdef DEBUG\n                    for (i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        assert(CommitGraphState.Data1[i] == (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i));\n                    }\n#endif\n                }\n                else\n                {\n                    for (i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        CommitGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i);\n                    }\n                }\n\n                if (PhPerfInformation.CommitLimit != 0)\n                {\n                    // Scale the data.\n                    PhDivideSinglesBySingle(\n                        CommitGraphState.Data1,\n                        (FLOAT)PhPerfInformation.CommitLimit,\n                        drawInfo->LineDataCount\n                        );\n                }\n\n                if (PhCsEnableGraphMaxText)\n                {\n                    drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                    drawInfo->LabelYFunctionParameter = (FLOAT)UInt32x32To64(PhPerfInformation.CommitLimit, PAGE_SIZE);\n                }\n\n                CommitGraphState.Valid = TRUE;\n            }\n        }\n        break;\n    case GCN_GETTOOLTIPTEXT:\n        {\n            PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Parameter1;\n\n            if (getTooltipText->Index < getTooltipText->TotalCount)\n            {\n                if (CommitGraphState.TooltipIndex != getTooltipText->Index)\n                {\n                    ULONG usedPages;\n                    PH_FORMAT format[3];\n\n                    usedPages = PhGetItemCircularBuffer_ULONG(&PhCommitHistory, getTooltipText->Index);\n\n                    // Commit charge: %s\\n%s\n                    //PhInitFormatS(&format[0], L\"Commit charge: \");\n                    PhInitFormatSize(&format[0], UInt32x32To64(usedPages, PAGE_SIZE));\n                    PhInitFormatC(&format[1], L'\\n');\n                    PhInitFormatSR(&format[2], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n                    PhMoveReference(&CommitGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 128));\n                }\n\n                getTooltipText->Text = CommitGraphState.TooltipText->sr;\n            }\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\n_Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PhSipNotifyPhysicalGraph(\n    _In_ HWND GraphHandle,\n    _In_ ULONG GraphMessage,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    switch (GraphMessage)\n    {\n    case GCN_GETDRAWINFO:\n        {\n            PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Parameter1;\n            PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;\n            ULONG i;\n\n            drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | (PhCsEnableGraphMaxText ? PH_GRAPH_LABEL_MAX_Y : 0);\n            PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorPhysical, 0, MemorySection->Parameters->WindowDpi);\n\n            PhGraphStateGetDrawInfo(\n                &PhysicalGraphState,\n                getDrawInfo,\n                PhPhysicalHistory.Count\n                );\n\n            if (!PhysicalGraphState.Valid)\n            {\n                if (PhCsEnableAvxSupport)\n                {\n                    PhCopyConvertCircularBufferULONG(&PhPhysicalHistory, PhysicalGraphState.Data1, drawInfo->LineDataCount);\n#ifdef DEBUG\n                    for (i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        assert(PhysicalGraphState.Data1[i] == (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i));\n                    }\n#endif\n                }\n                else\n                {\n                    for (i = 0; i < drawInfo->LineDataCount; i++)\n                    {\n                        PhysicalGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i);\n                    }\n                }\n\n                if (PhSystemBasicInformation.NumberOfPhysicalPages != 0)\n                {\n                    // Scale the data.\n                    PhDivideSinglesBySingle(\n                        PhysicalGraphState.Data1,\n                        (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages,\n                        drawInfo->LineDataCount\n                        );\n                }\n\n                if (PhCsEnableGraphMaxText)\n                {\n                    drawInfo->LabelYFunction = PhSiSizeLabelYFunction;\n                    drawInfo->LabelYFunctionParameter = (FLOAT)UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE);\n                }\n\n                PhysicalGraphState.Valid = TRUE;\n            }\n        }\n        break;\n    case GCN_GETTOOLTIPTEXT:\n        {\n            PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Parameter1;\n\n            if (getTooltipText->Index < getTooltipText->TotalCount)\n            {\n                if (PhysicalGraphState.TooltipIndex != getTooltipText->Index)\n                {\n                    ULONG usedPages;\n                    FLOAT currentCompressedMemory;\n                    FLOAT totalCompressedMemory;\n                    FLOAT totalSavedMemory;\n\n                    usedPages = PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, getTooltipText->Index);\n\n                    if (PhSipGetMemoryCompressionLimits(&currentCompressedMemory, &totalCompressedMemory, &totalSavedMemory))\n                    {\n                        PH_FORMAT format[13];\n\n                        PhInitFormatS(&format[0], L\"Physical memory: \");\n                        PhInitFormatSize(&format[1], UInt32x32To64(usedPages, PAGE_SIZE));\n                        PhInitFormatC(&format[2], L'\\n');\n                        PhInitFormatS(&format[3], L\"Compressed memory: \");\n                        PhInitFormatSize(&format[4], (ULONG64)currentCompressedMemory);\n                        PhInitFormatC(&format[5], L'\\n');\n                        PhInitFormatS(&format[6], L\"Total compressed: \");\n                        PhInitFormatSize(&format[7], (ULONG64)totalCompressedMemory);\n                        PhInitFormatC(&format[8], L'\\n');\n                        PhInitFormatS(&format[9], L\"Total memory saved: \");\n                        PhInitFormatSize(&format[10], (ULONG64)totalSavedMemory);\n                        PhInitFormatC(&format[11], L'\\n');\n                        PhInitFormatSR(&format[12], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n                        PhMoveReference(&PhysicalGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                    }\n                    else\n                    {\n                        PH_FORMAT format[3];\n\n                        // Physical memory: %s\\n%s\n                        PhInitFormatSize(&format[0], UInt32x32To64(usedPages, PAGE_SIZE));\n                        PhInitFormatC(&format[1], L'\\n');\n                        PhInitFormatSR(&format[2], PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->sr);\n\n                        PhMoveReference(&PhysicalGraphState.TooltipText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                    }\n                }\n\n                getTooltipText->Text = PhysicalGraphState.TooltipText->sr;\n            }\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\nVOID PhSipUpdateMemoryGraphs(\n    VOID\n    )\n{\n    CommitGraphState.Valid = FALSE;\n    CommitGraphState.TooltipIndex = ULONG_MAX;\n    Graph_Update(CommitGraphHandle);\n\n    PhysicalGraphState.Valid = FALSE;\n    PhysicalGraphState.TooltipIndex = ULONG_MAX;\n    Graph_Update(PhysicalGraphHandle);\n}\n\nVOID PhSipUpdateMemoryPanel(\n    VOID\n    )\n{\n    PWSTR pagedLimit;\n    PWSTR nonPagedLimit;\n    SYSTEM_MEMORY_LIST_INFORMATION memoryListInfo;\n\n    // Hardware\n\n    if (MemoryTicked == 0)\n    {\n        if (PhGetVirtualStatus() == PhVirtualStatusVirtualMachine)\n        {\n            PhSetDialogItemText(MemoryPanel, IDC_ZMEMSLOTS_V, L\"N/A\");\n            PhSetDialogItemText(MemoryPanel, IDC_ZMEMFORMFACTOR_V, L\"N/A\");\n            PhSetDialogItemText(MemoryPanel, IDC_ZMEMTYPE_V, L\"N/A\");\n            PhSetDialogItemText(MemoryPanel, IDC_ZMEMTECHNOLOGY_V, L\"N/A\");\n            PhSetDialogItemText(MemoryPanel, IDC_ZMEMSPEED_V, L\"N/A\");\n        }\n        else\n        {\n            PH_FORMAT format[3];\n            PCWSTR string;\n\n            PhInitFormatU(&format[0], MemorySlotsUsed);\n            PhInitFormatS(&format[1], L\" of \");\n            PhInitFormatU(&format[2], MemorySlotsTotal);\n            PhSetDialogItemText(MemoryPanel, IDC_ZMEMSLOTS_V, PhaFormat(format, 3, 10)->Buffer);\n\n            if (PhFindStringSiKeyValuePairs(MemoryFormFactors, sizeof(MemoryFormFactors), MemoryFormFactor, &string))\n                PhSetDialogItemText(MemoryPanel, IDC_ZMEMFORMFACTOR_V, string);\n            else\n                PhSetDialogItemText(MemoryPanel, IDC_ZMEMFORMFACTOR_V, L\"Undefined\");\n\n            if (PhFindStringSiKeyValuePairs(MemoryTypes, sizeof(MemoryTypes), MemoryType, &string))\n                PhSetDialogItemText(MemoryPanel, IDC_ZMEMTYPE_V, string);\n            else\n                PhSetDialogItemText(MemoryPanel, IDC_ZMEMTYPE_V, L\"Undefined\");\n\n            if (PhFindStringSiKeyValuePairs(MemoryTechnologies, sizeof(MemoryTechnologies), MemoryTechnology, &string))\n                PhSetDialogItemText(MemoryPanel, IDC_ZMEMTECHNOLOGY_V, string);\n            else\n                PhSetDialogItemText(MemoryPanel, IDC_ZMEMTECHNOLOGY_V, L\"Undefined\");\n\n            PhInitFormatU(&format[0], MemorySpeed);\n            PhInitFormatS(&format[1], L\" MT/s\");\n            PhSetDialogItemText(MemoryPanel, IDC_ZMEMSPEED_V, PhaFormat(format, 2, 10)->Buffer);\n        }\n    }\n\n    // Commit charge\n\n    PhSetDialogItemText(MemoryPanel, IDC_ZCOMMITCURRENT_V,\n        PhaFormatSize(UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE), ULONG_MAX)->Buffer);\n    PhSetDialogItemText(MemoryPanel, IDC_ZCOMMITPEAK_V,\n        PhaFormatSize(UInt32x32To64(PhPerfInformation.PeakCommitment, PAGE_SIZE), ULONG_MAX)->Buffer);\n    PhSetDialogItemText(MemoryPanel, IDC_ZCOMMITLIMIT_V,\n        PhaFormatSize(UInt32x32To64(PhPerfInformation.CommitLimit, PAGE_SIZE), ULONG_MAX)->Buffer);\n\n    // Physical memory\n\n    PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALCURRENT_V,\n        PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages, PAGE_SIZE), ULONG_MAX)->Buffer);\n    PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALTOTAL_V,\n        PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), ULONG_MAX)->Buffer);\n\n    if (ReservedMemory != 0)\n        PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALRESERVED_V, PhaFormatSize(ReservedMemory, ULONG_MAX)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALRESERVED_V, L\"-\");\n\n    PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALCACHEWS_V,\n        PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCachePage, PAGE_SIZE), ULONG_MAX)->Buffer);\n    PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALKERNELWS_V,\n        PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCodePage, PAGE_SIZE), ULONG_MAX)->Buffer);\n    PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALDRIVERWS_V,\n        PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemDriverPage, PAGE_SIZE), ULONG_MAX)->Buffer);\n\n    // Paged pool\n\n    PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDWORKINGSET_V,\n        PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentPagedPoolPage, PAGE_SIZE), ULONG_MAX)->Buffer);\n    PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDVIRTUALSIZE_V,\n        PhaFormatSize(UInt32x32To64(PhPerfInformation.PagedPoolPages, PAGE_SIZE), ULONG_MAX)->Buffer);\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDALLOCSDELTA_V, PhaFormatUInt64(PagedAllocsDelta.Delta, TRUE)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDALLOCSDELTA_V, L\"-\");\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDFREESDELTA_V, PhaFormatUInt64(PagedFreesDelta.Delta, TRUE)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDFREESDELTA_V, L\"-\");\n\n    // Non-paged pool\n\n    PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDUSAGE_V,\n        PhaFormatSize(UInt32x32To64(PhPerfInformation.NonPagedPoolPages, PAGE_SIZE), ULONG_MAX)->Buffer);\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDALLOCSDELTA_V, PhaFormatUInt64(NonPagedAllocsDelta.Delta, TRUE)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDALLOCSDELTA_V, L\"-\");\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDFREESDELTA_V, PhaFormatUInt64(NonPagedFreesDelta.Delta, TRUE)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDFREESDELTA_V, L\"-\");\n\n    // Pools\n\n    if (MmAddressesInitialized)\n    {\n        SIZE_T paged;\n        SIZE_T nonPaged;\n\n        PhSipGetPoolLimits(&paged, &nonPaged);\n\n        if (paged != MAXSIZE_T)\n            pagedLimit = PhaFormatSize(paged, ULONG_MAX)->Buffer;\n        else\n            pagedLimit = KsiLevel() ? L\"no symbols\" : L\"no driver\";\n\n        if (nonPaged != MAXSIZE_T)\n            nonPagedLimit = PhaFormatSize(nonPaged, ULONG_MAX)->Buffer;\n        else\n            nonPagedLimit = L\"N/A\";\n    }\n    else\n    {\n        if (KsiLevel())\n        {\n            pagedLimit = L\"no symbols\";\n            nonPagedLimit = L\"N/A\";\n        }\n        else\n        {\n            pagedLimit = L\"no driver\";\n            nonPagedLimit = L\"N/A\";\n        }\n    }\n\n    PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDLIMIT_V, pagedLimit);\n    PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDLIMIT_V, nonPagedLimit);\n\n    // Paging\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEFAULTSDELTA_V, PhaFormatUInt64(PageFaultsDelta.Delta, TRUE)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEFAULTSDELTA_V, L\"-\");\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEREADSDELTA_V, PhaFormatUInt64(PageReadsDelta.Delta, TRUE)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEREADSDELTA_V, L\"-\");\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEFILEWRITESDELTA_V, PhaFormatUInt64(PagefileWritesDelta.Delta, TRUE)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEFILEWRITESDELTA_V, L\"-\");\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGMAPPEDWRITESDELTA_V, PhaFormatUInt64(MappedWritesDelta.Delta, TRUE)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGMAPPEDWRITESDELTA_V, L\"-\");\n\n    // Mapped\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZMAPPEDREADIO, PhaFormatSize(MappedIoReadDelta.Delta, ULONG_MAX)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZMAPPEDREADIO, L\"-\");\n\n    if (MemoryTicked > 1)\n        PhSetDialogItemText(MemoryPanel, IDC_ZMAPPEDWRITEIO, PhaFormatSize(MappedIoWritesDelta.Delta, ULONG_MAX)->Buffer);\n    else\n        PhSetDialogItemText(MemoryPanel, IDC_ZMAPPEDWRITEIO, L\"-\");\n\n    // Memory lists\n\n    if (NT_SUCCESS(NtQuerySystemInformation(\n        SystemMemoryListInformation,\n        &memoryListInfo,\n        sizeof(SYSTEM_MEMORY_LIST_INFORMATION),\n        NULL\n        )))\n    {\n        ULONG_PTR standbyPageCount;\n        ULONG_PTR repurposedPageCount;\n        ULONG i;\n\n        standbyPageCount = 0;\n        repurposedPageCount = 0;\n\n        for (i = 0; i < 8; i++)\n        {\n            standbyPageCount += memoryListInfo.PageCountByPriority[i];\n            repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i];\n        }\n\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, ULONG_MAX)->Buffer);\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, ULONG_MAX)->Buffer);\n\n        if (WindowsVersion >= WINDOWS_8)\n            PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, ULONG_MAX)->Buffer);\n        else\n            PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L\"N/A\");\n    }\n    else\n    {\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTZEROED_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTFREE_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, L\"N/A\");\n        PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, L\"N/A\");\n    }\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhSipLoadMmAddresses(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_STRING kernelFileName;\n    PVOID kernelImageBase;\n    ULONG kernelImageSize;\n    PPH_SYMBOL_PROVIDER symbolProvider;\n    PH_SYMBOL_INFORMATION symbolInfo;\n\n    if (NT_SUCCESS(PhGetKernelFileNameEx(&kernelFileName, &kernelImageBase, &kernelImageSize)))\n    {\n        symbolProvider = PhCreateSymbolProvider(NULL);\n        PhLoadSymbolProviderOptions(symbolProvider);\n\n        PhLoadModuleSymbolProvider(\n            symbolProvider,\n            kernelFileName,\n            kernelImageBase,\n            kernelImageSize\n            );\n\n        if (PhGetSymbolFromName(\n            symbolProvider,\n            L\"MmSizeOfPagedPoolInBytes\",\n            &symbolInfo\n            ))\n        {\n            MmSizeOfPagedPoolInBytes = (PSIZE_T)symbolInfo.Address;\n        }\n\n        if (WindowsVersion < WINDOWS_8)\n        {\n            if (PhGetSymbolFromName(\n                symbolProvider,\n                L\"MmMaximumNonPagedPoolInBytes\",\n                &symbolInfo\n                ))\n            {\n                MmMaximumNonPagedPoolInBytes = (PSIZE_T)symbolInfo.Address;\n            }\n        }\n\n        PhDereferenceObject(symbolProvider);\n        PhDereferenceObject(kernelFileName);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhSipGetPoolLimits(\n    _Out_ PSIZE_T Paged,\n    _Out_ PSIZE_T NonPaged\n    )\n{\n    SIZE_T paged = MAXSIZE_T;\n    SIZE_T nonPaged = MAXSIZE_T;\n\n    if (MmSizeOfPagedPoolInBytes && (KsiLevel() >= KphLevelMed))\n    {\n        KphReadVirtualMemory(\n            NtCurrentProcess(),\n            MmSizeOfPagedPoolInBytes,\n            &paged,\n            sizeof(SIZE_T),\n            NULL\n            );\n    }\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        // The maximum nonpaged pool size was fixed on Windows 8 and above? The kernel does use\n        // a function named MmGetMaximumNonPagedPoolInBytes() but it's not exported. We return\n        // the fixed limit value from the documentation here similar to MS tools. (dmex)\n        // https://learn.microsoft.com/en-us/windows/win32/memory/memory-limits-for-windows-releases#memory-and-address-space-limits\n        //\n        // Windows 8.1 and Windows Server 2012 R2: RAM or 16 TB, whichever is smaller:\n\n        if (UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE) <= 16ULL * 1024ULL * 1024ULL * 1024ULL)\n        {\n            nonPaged = UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE);\n        }\n        else\n        {\n            nonPaged = (SIZE_T)(16ULL * 1024ULL * 1024ULL * 1024ULL);\n        }\n    }\n    else if (WindowsVersion < WINDOWS_8 && MmMaximumNonPagedPoolInBytes && (KsiLevel() >= KphLevelMed))\n    {\n        KphReadVirtualMemory(\n            NtCurrentProcess(),\n            MmMaximumNonPagedPoolInBytes,\n            &nonPaged,\n            sizeof(SIZE_T),\n            NULL\n            );\n    }\n\n    *Paged = paged;\n    *NonPaged = nonPaged;\n}\n\n_Success_(return)\nBOOLEAN PhSipGetMemoryCompressionLimits(\n    _Out_ FLOAT *CurrentCompressedMemory,\n    _Out_ FLOAT *TotalCompressedMemory,\n    _Out_ FLOAT *TotalSavedMemory\n    )\n{\n    PH_SYSTEM_STORE_COMPRESSION_INFORMATION compressionInfo;\n    FLOAT current;\n    FLOAT total;\n    FLOAT saved;\n\n    if (!NT_SUCCESS(PhGetSystemCompressionStoreInformation(&compressionInfo)))\n        return FALSE;\n    if (!(compressionInfo.TotalDataCompressed && compressionInfo.TotalCompressedSize))\n        return FALSE;\n\n    current = (FLOAT)compressionInfo.WorkingSetSize / (FLOAT)(1024 * 1024);\n    total = current * (FLOAT)compressionInfo.TotalDataCompressed / (FLOAT)compressionInfo.TotalCompressedSize;\n    saved = total - current;\n\n    *CurrentCompressedMemory = current * 1024 * 1024;\n    *TotalCompressedMemory = total * 1024 * 1024;\n    *TotalSavedMemory = saved * 1024 * 1024;\n    return TRUE;\n}\n"
  },
  {
    "path": "SystemInformer/thrdlist.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2012\n *     dmex    2018-2023\n *\n */\n\n#include <phapp.h>\n#include <phuisup.h>\n#include <kphuser.h>\n#include <colmgr.h>\n\n#include <thrdlist.h>\n\n#include <emenu.h>\n#include <settings.h>\n\n#include <extmgri.h>\n#include <phsettings.h>\n#include <thrdprv.h>\n#include <secedit.h>\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpThreadNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpThreadNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\nVOID PhpDestroyThreadNode(\n    _In_ PPH_THREAD_NODE ThreadNode\n    );\n\nVOID PhpRemoveThreadNode(\n    _In_ PPH_THREAD_NODE ThreadNode,\n    _In_ PPH_THREAD_LIST_CONTEXT Context\n    );\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpThreadTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    );\n\nBOOLEAN NTAPI PhpThreadTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\nPPH_STRING PhGetApartmentTypeString(\n    _In_ PPH_APARTMENT_INFO ApartmentInfo\n    );\n\nPPH_STRING PhGetApartmentFlagsString(\n    _In_ ULONG ApartmentState\n    );\n\nVOID PhInitializeThreadList(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND TreeNewHandle,\n    _Out_ PPH_THREAD_LIST_CONTEXT Context\n    )\n{\n    memset(Context, 0, sizeof(PH_THREAD_LIST_CONTEXT));\n    Context->EnableStateHighlighting = TRUE;\n\n    Context->NodeHashtable = PhCreateHashtable(\n        sizeof(PPH_THREAD_NODE),\n        PhpThreadNodeHashtableEqualFunction,\n        PhpThreadNodeHashtableHashFunction,\n        100\n        );\n    Context->NodeList = PhCreateList(100);\n\n    Context->ParentWindowHandle = ParentWindowHandle;\n    Context->TreeNewHandle = TreeNewHandle;\n\n    PhSetControlTheme(TreeNewHandle, L\"explorer\");\n    TreeNew_SetRedraw(TreeNewHandle, FALSE);\n    TreeNew_SetCallback(TreeNewHandle, PhpThreadTreeNewCallback, Context);\n\n    // Default columns\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_TID, TRUE, L\"TID\", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT);\n    PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CPU, TRUE, L\"CPU\", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CYCLESDELTA, TRUE, L\"Cycles delta\", 80, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTADDRESSWIN32, TRUE, L\"Start address (Win32)\", 180, PH_ALIGN_LEFT, 3, 0);\n    PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PRIORITYSYMBOLIC, TRUE, L\"Priority (symbolic)\", 80, PH_ALIGN_LEFT, 4, 0, TRUE);\n    // Available columns\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_SERVICE, FALSE, L\"Service\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_NAME, FALSE, L\"Name\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTED, FALSE, L\"Created\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTMODULE, FALSE, L\"Start module\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHES, FALSE, L\"Context switches\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHESDELTA, FALSE, L\"Context switches delta\", 100, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PRIORITY, FALSE, L\"Priority\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_BASEPRIORITY, FALSE, L\"Base priority\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PAGEPRIORITY, FALSE, L\"Page priority\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOPRIORITY, FALSE, L\"I/O priority\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CYCLES, FALSE, L\"Cycles\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STATE, FALSE, L\"State\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_KERNELTIME, FALSE, L\"Kernel time\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_USERTIME, FALSE, L\"User time\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR, FALSE, L\"Ideal processor\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CRITICAL, FALSE, L\"Critical\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_TIDHEX, FALSE, L\"TID (hex)\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT);\n    PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CPUCORECYCLES, FALSE, L\"CPU (relative)\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_TOKEN_STATE, FALSE, L\"Impersonation\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PENDINGIRP, FALSE, L\"Pending IRP\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_LASTSYSTEMCALL, FALSE, L\"Last system call\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_LASTSTATUSCODE, FALSE, L\"Last status code\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx2(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_TIMELINE, FALSE, L\"Timeline\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_APARTMENTTYPE, FALSE, L\"COM apartment\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_APARTMENTFLAGS, FALSE, L\"COM flags\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_FIBER, FALSE, L\"Fiber\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PRIORITYBOOST, FALSE, L\"Priority boost\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CPUUSER, FALSE, L\"CPU (user)\", 50, PH_ALIGN_LEFT, ULONG_MAX, DT_RIGHT, TRUE);\n    PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CPUKERNEL, FALSE, L\"CPU (kernel)\", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE);\n    //PhAddTreeNewColumnEx2(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CPUHISTORY, FALSE, L\"CPU history\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STACKUSAGE, FALSE, L\"Stack usage\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_WAITTIME, FALSE, L\"Wait time\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOREADS, FALSE, L\"I/O reads\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOWRITES, FALSE, L\"I/O writes\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOOTHER, FALSE, L\"I/O other\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOREADBYTES, FALSE, L\"I/O read bytes\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOWRITEBYTES, FALSE, L\"I/O write bytes\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOOTHERBYTES, FALSE, L\"I/O other bytes\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_LXSSTID, FALSE, L\"TID (LXSS)\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_POWERTHROTTLING, FALSE, L\"Power throttling\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    //PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CONTAINERID, FALSE, L\"Container ID\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTADDRESS, FALSE, L\"Start address (Native)\", 180, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_KSTACKUSAGE, FALSE, L\"Kernel stack usage\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_RPC, FALSE, L\"RPC usage\", 50, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_ACTUALBASEPRIORITY, FALSE, L\"Base priority (actual)\", 80, PH_ALIGN_LEFT, ULONG_MAX, 0);\n\n    PhCmInitializeManager(&Context->Cm, TreeNewHandle, PH_THREAD_TREELIST_COLUMN_MAXIMUM, PhpThreadTreeNewPostSortFunction);\n    PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList);\n\n    TreeNew_SetSort(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CYCLESDELTA, DescendingSortOrder);\n\n    TreeNew_SetTriState(TreeNewHandle, TRUE);\n    TreeNew_SetRedraw(TreeNewHandle, TRUE);\n}\n\nVOID PhDeleteThreadList(\n    _In_ PPH_THREAD_LIST_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport);\n\n    PhCmDeleteManager(&Context->Cm);\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n        PhpDestroyThreadNode(Context->NodeList->Items[i]);\n\n    PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpThreadNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_THREAD_NODE threadNode1 = *(PPH_THREAD_NODE *)Entry1;\n    PPH_THREAD_NODE threadNode2 = *(PPH_THREAD_NODE *)Entry2;\n\n    return threadNode1->ThreadId == threadNode2->ThreadId;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpThreadNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return HandleToUlong((*(PPH_THREAD_NODE *)Entry)->ThreadId) / 4;\n}\n\nVOID PhLoadSettingsThreadList(\n    _Inout_ PPH_THREAD_LIST_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n    PH_TREENEW_COLUMN column;\n    ULONG sortColumn;\n    PH_SORT_ORDER sortOrder;\n\n    settings = PhGetStringSetting(SETTING_THREAD_TREE_LIST_COLUMNS);\n    sortSettings = PhGetStringSetting(SETTING_THREAD_TREE_LIST_SORT);\n    Context->Flags = PhGetIntegerSetting(SETTING_THREAD_TREE_LIST_FLAGS);\n\n    PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n\n    TreeNew_GetSort(Context->TreeNewHandle, &sortColumn, &sortOrder);\n\n    // Make sure we're not sorting by an invisible column.\n    if (sortOrder != NoSortOrder && !(TreeNew_GetColumn(Context->TreeNewHandle, sortColumn, &column) && column.Visible))\n    {\n        TreeNew_SetSort(Context->TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CYCLESDELTA, DescendingSortOrder);\n    }\n}\n\nVOID PhSaveSettingsThreadList(\n    _Inout_ PPH_THREAD_LIST_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n    PPH_STRING sortSettings;\n\n    settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings);\n\n    PhSetIntegerSetting(SETTING_THREAD_TREE_LIST_FLAGS, Context->Flags);\n    PhSetStringSetting2(SETTING_THREAD_TREE_LIST_COLUMNS, &settings->sr);\n    PhSetStringSetting2(SETTING_THREAD_TREE_LIST_SORT, &sortSettings->sr);\n\n    PhDereferenceObject(settings);\n    PhDereferenceObject(sortSettings);\n}\n\nVOID PhSetOptionsThreadList(\n    _Inout_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ ULONG Options\n    )\n{\n    switch (Options)\n    {\n    case PH_THREAD_TREELIST_MENUITEM_HIDE_SUSPENDED:\n        Context->HideSuspended = !Context->HideSuspended;\n        break;\n    case PH_THREAD_TREELIST_MENUITEM_HIDE_GUITHREADS:\n        Context->HideGuiThreads = !Context->HideGuiThreads;\n        break;\n    case PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_SUSPENDED:\n        Context->HighlightSuspended = !Context->HighlightSuspended;\n        break;\n    case PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_GUITHREADS:\n        Context->HighlightGuiThreads = !Context->HighlightGuiThreads;\n        break;\n    }\n}\n\nPPH_THREAD_NODE PhAddThreadNode(\n    _Inout_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_ITEM ThreadItem,\n    _In_ BOOLEAN FirstRun\n    )\n{\n    PPH_THREAD_NODE threadNode;\n\n    threadNode = PhAllocate(PhEmGetObjectSize(EmThreadNodeType, sizeof(PH_THREAD_NODE)));\n    memset(threadNode, 0, sizeof(PH_THREAD_NODE));\n    PhInitializeTreeNewNode(&threadNode->Node);\n\n    if (Context->EnableStateHighlighting && !FirstRun)\n    {\n        PhChangeShStateTn(\n            &threadNode->Node,\n            &threadNode->ShState,\n            &Context->NodeStateList,\n            NewItemState,\n            PhCsColorNew,\n            NULL\n            );\n    }\n\n    PhReferenceObject(ThreadItem);\n    threadNode->ThreadId = ThreadItem->ThreadId;\n    threadNode->ThreadItem = ThreadItem;\n    threadNode->PagePriority = MEMORY_PRIORITY_NORMAL + 1;\n    threadNode->IoPriority = MaxIoPriorityTypes;\n\n    memset(threadNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_THREAD_TREELIST_COLUMN_MAXIMUM);\n    threadNode->Node.TextCache = threadNode->TextCache;\n    threadNode->Node.TextCacheSize = PH_THREAD_TREELIST_COLUMN_MAXIMUM;\n\n    PhAddEntryHashtable(Context->NodeHashtable, &threadNode);\n    PhAddItemList(Context->NodeList, threadNode);\n\n    PhEmCallObjectOperation(EmThreadNodeType, threadNode, EmObjectCreate);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    return threadNode;\n}\n\nPPH_THREAD_NODE PhFindThreadNode(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ HANDLE ThreadId\n    )\n{\n    PH_THREAD_NODE lookupThreadNode;\n    PPH_THREAD_NODE lookupThreadNodePtr = &lookupThreadNode;\n    PPH_THREAD_NODE *threadNode;\n\n    lookupThreadNode.ThreadId = ThreadId;\n\n    threadNode = (PPH_THREAD_NODE *)PhFindEntryHashtable(\n        Context->NodeHashtable,\n        &lookupThreadNodePtr\n        );\n\n    if (threadNode)\n        return *threadNode;\n    else\n        return NULL;\n}\n\nVOID PhRemoveThreadNode(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    // Remove from the hashtable here to avoid problems in case the key is re-used.\n    PhRemoveEntryHashtable(Context->NodeHashtable, &ThreadNode);\n\n    if (Context->EnableStateHighlighting)\n    {\n        PhChangeShStateTn(\n            &ThreadNode->Node,\n            &ThreadNode->ShState,\n            &Context->NodeStateList,\n            RemovingItemState,\n            PhCsColorRemoved,\n            Context->TreeNewHandle\n            );\n    }\n    else\n    {\n        PhpRemoveThreadNode(ThreadNode, Context);\n    }\n}\n\nVOID PhpDestroyThreadNode(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    PhEmCallObjectOperation(EmThreadNodeType, ThreadNode, EmObjectDelete);\n\n    if (ThreadNode->CyclesDeltaText) PhDereferenceObject(ThreadNode->CyclesDeltaText);\n    if (ThreadNode->ContextSwitchesDeltaText) PhDereferenceObject(ThreadNode->ContextSwitchesDeltaText);\n    if (ThreadNode->StartAddressText) PhDereferenceObject(ThreadNode->StartAddressText);\n    if (ThreadNode->CreatedText) PhDereferenceObject(ThreadNode->CreatedText);\n    if (ThreadNode->NameText) PhDereferenceObject(ThreadNode->NameText);\n    if (ThreadNode->StateText) PhDereferenceObject(ThreadNode->StateText);\n    if (ThreadNode->LastSystemCallText) PhDereferenceObject(ThreadNode->LastSystemCallText);\n    if (ThreadNode->LastErrorCodeText) PhDereferenceObject(ThreadNode->LastErrorCodeText);\n    if (ThreadNode->ApartmentTypeText) PhDereferenceObject(ThreadNode->ApartmentTypeText);\n    if (ThreadNode->ApartmentFlagsText) PhDereferenceObject(ThreadNode->ApartmentFlagsText);\n    if (ThreadNode->StackUsageText) PhDereferenceObject(ThreadNode->StackUsageText);\n    if (ThreadNode->KernelStackUsageText) PhDereferenceObject(ThreadNode->KernelStackUsageText);\n\n    if (ThreadNode->KernelTimeText) PhDereferenceObject(ThreadNode->KernelTimeText);\n    if (ThreadNode->UserTimeText) PhDereferenceObject(ThreadNode->UserTimeText);\n\n    if (ThreadNode->WaitTimeText) PhDereferenceObject(ThreadNode->WaitTimeText);\n    if (ThreadNode->IoReads) PhDereferenceObject(ThreadNode->IoReads);\n    if (ThreadNode->IoWrites) PhDereferenceObject(ThreadNode->IoWrites);\n    if (ThreadNode->IoOther) PhDereferenceObject(ThreadNode->IoOther);\n    if (ThreadNode->IoReadBytes) PhDereferenceObject(ThreadNode->IoReadBytes);\n    if (ThreadNode->IoWriteBytes) PhDereferenceObject(ThreadNode->IoWriteBytes);\n    if (ThreadNode->IoOtherBytes) PhDereferenceObject(ThreadNode->IoOtherBytes);\n\n    if (ThreadNode->ThreadContextHandle) NtClose(ThreadNode->ThreadContextHandle);\n    if (ThreadNode->ThreadReadVmHandle) NtClose(ThreadNode->ThreadReadVmHandle);\n\n    PhDereferenceObject(ThreadNode->ThreadItem);\n\n    PhFree(ThreadNode);\n}\n\nVOID PhpRemoveThreadNode(\n    _In_ PPH_THREAD_NODE ThreadNode,\n    _In_ PPH_THREAD_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after ThreadNode\n    )\n{\n    ULONG index;\n\n    // Remove from list and cleanup.\n\n    if ((index = PhFindItemList(Context->NodeList, ThreadNode)) != ULONG_MAX)\n        PhRemoveItemList(Context->NodeList, index);\n\n    PhpDestroyThreadNode(ThreadNode);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhUpdateThreadNode(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    memset(ThreadNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_THREAD_TREELIST_COLUMN_MAXIMUM);\n\n    ThreadNode->ValidMask = 0;\n    PhInvalidateTreeNewNode(&ThreadNode->Node, TN_CACHE_COLOR);\n    TreeNew_InvalidateNode(Context->TreeNewHandle, &ThreadNode->Node);\n}\n\nVOID PhTickThreadNodes(\n    _In_ PPH_THREAD_LIST_CONTEXT Context\n    )\n{\n    // Text invalidation, node updates\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_THREAD_NODE node = Context->NodeList->Items[i];\n\n        // The TID never changes, so we don't invalidate that.\n        memset(&node->TextCache[1], 0, sizeof(PH_STRINGREF) * (PH_THREAD_TREELIST_COLUMN_MAXIMUM - 1));\n        node->ValidMask = 0; // Items that always remain valid\n    }\n\n    if (Context->TreeNewSortOrder != NoSortOrder)\n    {\n        // Force a rebuild to sort the items.\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n    }\n\n    // State highlighting\n    PH_TICK_SH_STATE_TN(PH_THREAD_NODE, ShState, Context->NodeStateList, PhpRemoveThreadNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context);\n}\n\nVOID PhpUpdateThreadNodeNameText(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    PhClearReference(&ThreadNode->NameText);\n\n    if (WindowsVersion >= WINDOWS_10_RS1 && ThreadNode->ThreadItem->ThreadHandle)\n    {\n        PPH_STRING threadName;\n\n        if (NT_SUCCESS(PhGetThreadName(ThreadNode->ThreadItem->ThreadHandle, &threadName)))\n        {\n            PhMoveReference(&ThreadNode->NameText, threadName);\n        }\n    }\n}\n\nVOID PhpUpdateThreadNodeStartedText(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    SYSTEMTIME time;\n\n    PhLargeIntegerToLocalSystemTime(&time, &ThreadNode->ThreadItem->CreateTime);\n    PhMoveReference(&ThreadNode->CreatedText, PhFormatDateTime(&time));\n}\n\nVOID PhpUpdateThreadNodePagePriority(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    ULONG pagePriorityInteger = MEMORY_PRIORITY_NORMAL + 1;\n\n    ThreadNode->PagePriority = ULONG_MAX;\n\n    if (ThreadNode->ThreadItem->ThreadHandle)\n    {\n        if (NT_SUCCESS(PhGetThreadPagePriority(ThreadNode->ThreadItem->ThreadHandle, &pagePriorityInteger)) && pagePriorityInteger <= MEMORY_PRIORITY_NORMAL)\n        {\n            ThreadNode->PagePriority = pagePriorityInteger;\n        }\n    }\n}\n\nVOID PhpUpdateThreadNodeIoPriority(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    IO_PRIORITY_HINT ioPriorityInteger = MaxIoPriorityTypes;\n\n    ThreadNode->IoPriority = ULONG_MAX;\n\n    if (ThreadNode->ThreadItem->ThreadHandle)\n    {\n        if (NT_SUCCESS(PhGetThreadIoPriority(ThreadNode->ThreadItem->ThreadHandle, &ioPriorityInteger)) && ioPriorityInteger <= MaxIoPriorityTypes)\n        {\n            ThreadNode->IoPriority = ioPriorityInteger;\n        }\n    }\n}\n\nVOID PhpUpdateThreadNodeSuspendCount(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    ULONG suspendCount = 0;\n\n    if (ThreadNode->ThreadItem->ThreadHandle)\n    {\n        if (ThreadNode->ThreadItem->WaitReason == Suspended)\n        {\n            PhGetThreadSuspendCount(ThreadNode->ThreadItem->ThreadHandle, &suspendCount);\n        }\n    }\n\n    ThreadNode->SuspendCount = suspendCount;\n}\n\nVOID PhpUpdateThreadNodeIdealProcessor(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    PROCESSOR_NUMBER idealProcessorNumber;\n\n    ThreadNode->IdealProcessorMask = 0;\n\n    if (ThreadNode->ThreadItem->ThreadHandle)\n    {\n        if (NT_SUCCESS(PhGetThreadIdealProcessor(ThreadNode->ThreadItem->ThreadHandle, &idealProcessorNumber)))\n        {\n            ThreadNode->IdealProcessorMask = MAKELONG(idealProcessorNumber.Number, idealProcessorNumber.Group);\n        }\n    }\n}\n\nVOID PhpUpdateThreadNodeBreakOnTermination(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    BOOLEAN breakOnTermination = FALSE;\n\n    if (ThreadNode->ThreadItem->ThreadHandle)\n    {\n        PhGetThreadBreakOnTermination(ThreadNode->ThreadItem->ThreadHandle, &breakOnTermination);\n    }\n\n    ThreadNode->BreakOnTermination = breakOnTermination;\n}\n\nVOID PhpUpdateThreadNodeTokenState(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    PH_THREAD_TOKEN_STATE tokenState = PH_THREAD_TOKEN_STATE_UNKNOWN;\n\n    if (ThreadNode->ThreadItem->ThreadHandle)\n    {\n        NTSTATUS status;\n        HANDLE tokenHandle;\n\n        // Since the system must verify that the thread is impersonating before it can perform\n        // an access check on the target token, we can reliably determine the token's presence\n        // even if we fail the subsequent access check. (diversenok)\n\n        status = PhOpenThreadToken(ThreadNode->ThreadItem->ThreadHandle, 0, TRUE, &tokenHandle);\n\n        if (status == STATUS_NO_TOKEN)\n        {\n            tokenState = PH_THREAD_TOKEN_STATE_NOT_PRESENT;\n        }\n        else if (status == STATUS_CANT_OPEN_ANONYMOUS)\n        {\n            tokenState = PH_THREAD_TOKEN_STATE_ANONYMOUS;\n        }\n        else\n        {\n            tokenState = PH_THREAD_TOKEN_STATE_PRESENT;\n        }\n\n        if (NT_SUCCESS(status))\n            NtClose(tokenHandle);\n    }\n\n    ThreadNode->TokenState = tokenState;\n}\n\nVOID PhpUpdateThreadNodeIoPending(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    BOOLEAN pendingIrp = FALSE;\n\n    if (ThreadNode->ThreadItem->ThreadHandle)\n    {\n        PhGetThreadIsIoPending(ThreadNode->ThreadItem->ThreadHandle, &pendingIrp);\n    }\n\n    ThreadNode->PendingIrp = pendingIrp;\n}\n\nVOID PhpUpdateThreadNodeLastSystemCall(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    if (!ThreadNode->ThreadContextHandleValid)\n    {\n        if (!ThreadNode->ThreadContextHandle)\n        {\n            HANDLE threadHandle;\n\n            if (NT_SUCCESS(PhOpenThread(\n                &threadHandle,\n                THREAD_GET_CONTEXT,\n                ThreadNode->ThreadId\n                )))\n            {\n                ThreadNode->ThreadContextHandle = threadHandle;\n            }\n        }\n\n        ThreadNode->ThreadContextHandleValid = TRUE;\n    }\n\n    RtlZeroMemory(&ThreadNode->LastSystemCall, sizeof(THREAD_LAST_SYSCALL_INFORMATION));\n\n    if (ThreadNode->ThreadContextHandle)\n    {\n        GUID containerId;\n\n        PhGetThreadContainerId(ThreadNode->ThreadContextHandle, &containerId);\n\n        ThreadNode->LastSystemCallStatus = PhGetThreadLastSystemCall(\n            ThreadNode->ThreadContextHandle,\n            &ThreadNode->LastSystemCall\n            );\n    }\n    else\n    {\n        ThreadNode->LastSystemCallStatus = STATUS_SUCCESS;\n    }\n}\n\nVOID PhpUpdateThreadNodeLastStatusCode(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    NTSTATUS lastStatusValue = STATUS_SUCCESS;\n\n    if (!ThreadNode->ThreadReadVmHandleValid)\n    {\n        if (!ThreadNode->ThreadReadVmHandle)\n        {\n            if (ThreadNode->ThreadItem->ThreadHandle)\n            {\n                HANDLE processHandle;\n\n                if (NT_SUCCESS(PhOpenProcess(\n                    &processHandle,\n                    PROCESS_VM_READ | (WindowsVersion > WINDOWS_7 ? PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_QUERY_INFORMATION),\n                    Context->ProcessId\n                    )))\n                {\n                    ThreadNode->ThreadReadVmHandle = processHandle;\n                }\n            }\n        }\n\n        ThreadNode->ThreadReadVmHandleValid = TRUE;\n    }\n\n    if (ThreadNode->ThreadItem->ThreadHandle && ThreadNode->ThreadReadVmHandle)\n    {\n        ThreadNode->LastStatusQueryStatus = PhGetThreadLastStatusValue(\n            ThreadNode->ThreadItem->ThreadHandle,\n            ThreadNode->ThreadReadVmHandle,\n            &lastStatusValue\n            );\n\n        if (NT_SUCCESS(ThreadNode->LastStatusQueryStatus))\n        {\n            ThreadNode->LastStatusValue = lastStatusValue;\n        }\n    }\n}\n\nVOID PhpUpdateThreadNodeApartmentState(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    PH_APARTMENT_INFO apartmentInfo;\n\n    if (!ThreadNode->ThreadReadVmHandleValid)\n    {\n        if (!ThreadNode->ThreadReadVmHandle)\n        {\n            if (ThreadNode->ThreadItem->ThreadHandle)\n            {\n                HANDLE processHandle;\n\n                if (NT_SUCCESS(PhOpenProcess(\n                    &processHandle,\n                    PROCESS_VM_READ | (WindowsVersion > WINDOWS_7 ? PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_QUERY_INFORMATION),\n                    Context->ProcessId\n                    )))\n                {\n                    ThreadNode->ThreadReadVmHandle = processHandle;\n                }\n            }\n        }\n\n        ThreadNode->ThreadReadVmHandleValid = TRUE;\n    }\n\n    if (ThreadNode->ThreadItem->ThreadHandle && ThreadNode->ThreadReadVmHandle)\n    {\n        status = PhGetThreadApartment(\n            ThreadNode->ThreadItem->ThreadHandle,\n            ThreadNode->ThreadReadVmHandle,\n            &apartmentInfo\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        ThreadNode->ApartmentInfo = apartmentInfo;\n    }\n    else\n    {\n        RtlZeroMemory(&ThreadNode->ApartmentInfo, sizeof(PH_APARTMENT_INFO));\n    }\n}\n\nVOID PhpUpdateThreadNodeRpc(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    BOOLEAN hasRpcState = FALSE;\n\n    if (!ThreadNode->ThreadReadVmHandleValid)\n    {\n        if (!ThreadNode->ThreadReadVmHandle)\n        {\n            if (ThreadNode->ThreadItem->ThreadHandle)\n            {\n                HANDLE processHandle;\n\n                if (NT_SUCCESS(PhOpenProcess(\n                    &processHandle,\n                    PROCESS_VM_READ | (WindowsVersion > WINDOWS_7 ? PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_QUERY_INFORMATION),\n                    Context->ProcessId\n                    )))\n                {\n                    ThreadNode->ThreadReadVmHandle = processHandle;\n                }\n            }\n        }\n\n        ThreadNode->ThreadReadVmHandleValid = TRUE;\n    }\n\n    if (ThreadNode->ThreadItem->ThreadHandle && ThreadNode->ThreadReadVmHandle)\n    {\n        status = PhGetThreadRpcState(\n            ThreadNode->ThreadItem->ThreadHandle,\n            ThreadNode->ThreadReadVmHandle,\n            &hasRpcState\n            );\n    }\n\n    ThreadNode->HasRpcState = NT_SUCCESS(status) && hasRpcState;\n}\n\nVOID PhpUpdateThreadNodeFiber(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    BOOLEAN threadIsFiber = FALSE;\n\n    if (!ThreadNode->ThreadReadVmHandleValid)\n    {\n        if (!ThreadNode->ThreadReadVmHandle)\n        {\n            if (ThreadNode->ThreadItem->ThreadHandle)\n            {\n                HANDLE processHandle;\n\n                if (NT_SUCCESS(PhOpenProcess(\n                    &processHandle,\n                    PROCESS_VM_READ | (WindowsVersion > WINDOWS_7 ? PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_QUERY_INFORMATION),\n                    Context->ProcessId\n                    )))\n                {\n                    ThreadNode->ThreadReadVmHandle = processHandle;\n                }\n            }\n        }\n\n        ThreadNode->ThreadReadVmHandleValid = TRUE;\n    }\n\n    if (ThreadNode->ThreadItem->ThreadHandle && ThreadNode->ThreadReadVmHandle)\n    {\n        PhGetThreadIsFiber(\n            ThreadNode->ThreadItem->ThreadHandle,\n            ThreadNode->ThreadReadVmHandle,\n            &threadIsFiber\n            );\n    }\n\n    ThreadNode->Fiber = threadIsFiber;\n}\n\nVOID PhpUpdateThreadNodePriorityBoost(\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    BOOLEAN priorityBoost = FALSE;\n\n    if (ThreadNode->ThreadItem->ThreadHandle)\n    {\n        PhGetThreadPriorityBoost(ThreadNode->ThreadItem->ThreadHandle, &priorityBoost);\n    }\n\n    ThreadNode->PriorityBoost = priorityBoost;\n}\n\nVOID PhpUpdateThreadNodeStackUsage(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    ULONG_PTR stackUsage = 0;\n    ULONG_PTR stackLimit = 0;\n\n    if (!ThreadNode->ThreadReadVmHandleValid)\n    {\n        if (!ThreadNode->ThreadReadVmHandle)\n        {\n            if (ThreadNode->ThreadItem->ThreadHandle)\n            {\n                HANDLE processHandle;\n\n                if (NT_SUCCESS(PhOpenProcess(\n                    &processHandle,\n                    PROCESS_VM_READ | (WindowsVersion > WINDOWS_7 ? PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_QUERY_INFORMATION),\n                    Context->ProcessId\n                    )))\n                {\n                    ThreadNode->ThreadReadVmHandle = processHandle;\n                }\n            }\n        }\n\n        ThreadNode->ThreadReadVmHandleValid = TRUE;\n    }\n\n    if (ThreadNode->ThreadItem->ThreadHandle && ThreadNode->ThreadReadVmHandle)\n    {\n        status = PhGetThreadStackSize(\n            ThreadNode->ThreadItem->ThreadHandle,\n            ThreadNode->ThreadReadVmHandle,\n            &stackUsage,\n            &stackLimit\n            );\n    }\n\n    if (NT_SUCCESS(status) && stackUsage && stackLimit)\n    {\n        FLOAT percent = (FLOAT)stackUsage / stackLimit * 100;\n\n        ThreadNode->StackUsageFloat = percent;\n        ThreadNode->StackUsage = stackUsage;\n        ThreadNode->StackLimit = stackLimit;\n    }\n    else\n    {\n        ThreadNode->StackUsageFloat = 0;\n        ThreadNode->StackUsage = 0;\n        ThreadNode->StackLimit = 0;\n    }\n}\n\nVOID PhpUpdateThreadNodeKernelStackSize(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _In_ PPH_THREAD_NODE ThreadNode\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    KPH_KERNEL_STACK_INFORMATION info;\n\n    // This is imperfect because the KernelStack is infrequently updated by the kernel (happens on\n    // context swaps). Additionally, the space between InitialStack and first stack usage is not\n    // accounted for. But generally this is a good enough representation of the kernel stack usage.\n    // (jxy-s)\n\n    if (ThreadNode->ThreadItem->ThreadHandle && KsiLevel() == KphLevelMax)\n    {\n        status = KphQueryInformationThread(\n            ThreadNode->ThreadItem->ThreadHandle,\n            KphThreadKernelStackInformation,\n            &info,\n            sizeof(info),\n            NULL\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        ULONG_PTR stackUsage = (ULONG_PTR)PTR_SUB_OFFSET(info.InitialStack, info.KernelStack);\n        ULONG_PTR stackLimit = (ULONG_PTR)PTR_SUB_OFFSET(info.StackBase, info.StackLimit);\n        FLOAT percent = (FLOAT)stackUsage / stackLimit * 100;\n\n        ThreadNode->KernelStackUsageFloat = percent;\n        ThreadNode->KernelStackUsage = stackUsage;\n        ThreadNode->KernelStackLimit = stackLimit;\n    }\n    else\n    {\n        ThreadNode->KernelStackUsageFloat = 0;\n        ThreadNode->KernelStackUsage = 0;\n        ThreadNode->KernelStackLimit = 0;\n    }\n}\n\n#define SORT_FUNCTION(Column) PhpThreadTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpThreadTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_THREAD_LIST_CONTEXT context = (PPH_THREAD_LIST_CONTEXT)_context; \\\n    PPH_THREAD_NODE node1 = *(PPH_THREAD_NODE *)_elem1; \\\n    PPH_THREAD_NODE node2 = *(PPH_THREAD_NODE *)_elem2; \\\n    PPH_THREAD_ITEM threadItem1 = node1->ThreadItem; \\\n    PPH_THREAD_ITEM threadItem2 = node2->ThreadItem; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)node1->ThreadId, (ULONG_PTR)node2->ThreadId); \\\n    \\\n    return PhModifySort(sortResult, context->TreeNewSortOrder); \\\n}\n\n_Function_class_(PH_CM_POST_SORT_FUNCTION)\nLONG PhpThreadTreeNewPostSortFunction(\n    _In_ LONG Result,\n    _In_ PVOID Node1,\n    _In_ PVOID Node2,\n    _In_ PH_SORT_ORDER SortOrder\n    )\n{\n    if (Result == 0)\n        Result = uintptrcmp((ULONG_PTR)((PPH_THREAD_NODE)Node1)->ThreadId, (ULONG_PTR)((PPH_THREAD_NODE)Node2)->ThreadId);\n\n    return PhModifySort(Result, SortOrder);\n}\n\nBEGIN_SORT_FUNCTION(Tid)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->ThreadId, (ULONG_PTR)node2->ThreadId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Cpu)\n{\n    sortResult = singlecmp(threadItem1->CpuUsage, threadItem2->CpuUsage);\n\n    if (sortResult == 0)\n    {\n        if (context->UseCycleTime)\n            sortResult = uint64cmp(threadItem1->CyclesDelta.Delta, threadItem2->CyclesDelta.Delta);\n        else\n            sortResult = uintcmp(threadItem1->ContextSwitchesDelta.Delta, threadItem2->ContextSwitchesDelta.Delta);\n    }\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CyclesDelta)\n{\n    if (context->UseCycleTime)\n        sortResult = uint64cmp(threadItem1->CyclesDelta.Delta, threadItem2->CyclesDelta.Delta);\n    else\n        sortResult = uintcmp(threadItem1->ContextSwitchesDelta.Delta, threadItem2->ContextSwitchesDelta.Delta);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StartAddressWin32)\n{\n    sortResult = uint64cmp((ULONG_PTR)threadItem1->StartAddressWin32, (ULONG_PTR)threadItem2->StartAddressWin32);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PrioritySymbolic)\n{\n    sortResult = intcmp(threadItem1->BasePriority, threadItem2->BasePriority);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Service)\n{\n    sortResult = PhCompareStringWithNullSortOrder(threadItem1->ServiceName, threadItem2->ServiceName, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    PhpUpdateThreadNodeNameText(node1);\n    PhpUpdateThreadNodeNameText(node2);\n\n    sortResult = PhCompareStringWithNullSortOrder(node1->NameText, node2->NameText, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Created)\n{\n    sortResult = uint64cmp(threadItem1->CreateTime.QuadPart, threadItem2->CreateTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StartModule)\n{\n    sortResult = PhCompareStringWithNullSortOrder(threadItem1->StartAddressWin32FileName, threadItem2->StartAddressWin32FileName, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ContextSwitches)\n{\n    sortResult = uint64cmp(threadItem1->ContextSwitchesDelta.Value, threadItem2->ContextSwitchesDelta.Value);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ContextSwitchesDelta)\n{\n    sortResult = uint64cmp(threadItem1->ContextSwitchesDelta.Delta, threadItem2->ContextSwitchesDelta.Delta);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Priority)\n{\n    sortResult = intcmp(threadItem1->Priority, threadItem2->Priority);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(BasePriority)\n{\n    sortResult = intcmp(threadItem1->BasePriority, threadItem2->BasePriority);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PagePriority)\n{\n    PhpUpdateThreadNodePagePriority(node1);\n    PhpUpdateThreadNodePagePriority(node2);\n\n    sortResult = uintcmp(node1->PagePriority, node2->PagePriority);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoPriority)\n{\n    PhpUpdateThreadNodeIoPriority(node1);\n    PhpUpdateThreadNodeIoPriority(node2);\n\n    sortResult = uintcmp(node1->IoPriority, node2->IoPriority);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Cycles)\n{\n    sortResult = uint64cmp(threadItem1->CyclesDelta.Value, threadItem2->CyclesDelta.Value);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(State)\n{\n    ULONG threadState1 = ULONG_MAX;\n    ULONG threadState2 = ULONG_MAX;\n\n    if (threadItem1->State != Waiting)\n    {\n        if ((ULONG)threadItem1->State < MaximumThreadState)\n            threadState1 = (ULONG)threadItem1->State;\n        else\n            threadState1 = (ULONG)MaximumThreadState;\n    }\n    else\n    {\n        if ((ULONG)threadItem1->WaitReason < MaximumWaitReason)\n            threadState1 = (ULONG)threadItem1->WaitReason;\n        else\n            threadState1 = (ULONG)MaximumWaitReason;\n    }\n\n    if (threadItem2->State != Waiting)\n    {\n        if ((ULONG)threadItem2->State < MaximumThreadState)\n            threadState2 = (ULONG)threadItem2->State;\n        else\n            threadState2 = (ULONG)MaximumThreadState;\n    }\n    else\n    {\n        if ((ULONG)threadItem2->WaitReason < MaximumWaitReason)\n            threadState2 = (ULONG)threadItem2->WaitReason;\n        else\n            threadState2 = (ULONG)MaximumWaitReason;\n    }\n\n    sortResult = uintcmp(threadState1, threadState2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(KernelTime)\n{\n    sortResult = uint64cmp(threadItem1->KernelTime.QuadPart, threadItem2->KernelTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(UserTime)\n{\n    sortResult = uint64cmp(threadItem1->UserTime.QuadPart, threadItem2->UserTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IdealProcessor)\n{\n    PhpUpdateThreadNodeIdealProcessor(node1);\n    PhpUpdateThreadNodeIdealProcessor(node2);\n\n    sortResult = int64cmp(node1->IdealProcessorMask, node2->IdealProcessorMask);\n    //sortResult = PhCompareStringZ(node1->IdealProcessorText, node2->IdealProcessorText, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Critical)\n{\n    PhpUpdateThreadNodeBreakOnTermination(node1);\n    PhpUpdateThreadNodeBreakOnTermination(node2);\n\n    sortResult = ucharcmp(node1->BreakOnTermination, node2->BreakOnTermination);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(TidHex)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->ThreadId, (ULONG_PTR)node2->ThreadId);\n    //sortResult = ucharcmp(node1->ThreadIdHexText, node2->ThreadIdHexText, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CpuCore)\n{\n    FLOAT cpuUsage1;\n    FLOAT cpuUsage2;\n\n    cpuUsage1 = threadItem1->CpuUsage * 100;\n    cpuUsage1 *= PhSystemProcessorInformation.NumberOfProcessors;\n\n    cpuUsage2 = threadItem2->CpuUsage * 100;\n    cpuUsage2 *= PhSystemProcessorInformation.NumberOfProcessors;\n\n    sortResult = singlecmp(cpuUsage1, cpuUsage2);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(TokenState)\n{\n    PhpUpdateThreadNodeTokenState(node1);\n    PhpUpdateThreadNodeTokenState(node2);\n\n    sortResult = uintcmp(node1->TokenState, node2->TokenState);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PendingIrp)\n{\n    PhpUpdateThreadNodeIoPending(node1);\n    PhpUpdateThreadNodeIoPending(node2);\n\n    sortResult = ucharcmp(node1->PendingIrp, node2->PendingIrp);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LastSystemCall)\n{\n    PhpUpdateThreadNodeLastSystemCall(node1);\n    PhpUpdateThreadNodeLastSystemCall(node2);\n\n    sortResult = ushortcmp(node1->LastSystemCall.SystemCallNumber, node2->LastSystemCall.SystemCallNumber);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LastStatusCode)\n{\n    PhpUpdateThreadNodeLastStatusCode(context, node1);\n    PhpUpdateThreadNodeLastStatusCode(context, node2);\n\n    sortResult = uintcmp(node1->LastStatusValue, node2->LastStatusValue);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ApartmentType)\n{\n    PhpUpdateThreadNodeApartmentState(context, node1);\n    PhpUpdateThreadNodeApartmentState(context, node2);\n\n    sortResult = uintcmp(node1->ApartmentInfo.Type, node2->ApartmentInfo.Type);\n\n    if (sortResult == 0)\n        sortResult = uintcmp(node1->ApartmentInfo.ComInits, node2->ApartmentInfo.ComInits);\n\n    if (sortResult == 0)\n        sortResult = uintcmp(node1->ApartmentInfo.Flags, node2->ApartmentInfo.Flags);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ApartmentFlags)\n{\n    PhpUpdateThreadNodeApartmentState(context, node1);\n    PhpUpdateThreadNodeApartmentState(context, node2);\n\n    sortResult = uintcmp(node1->ApartmentInfo.Flags, node2->ApartmentInfo.Flags);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Fiber)\n{\n    PhpUpdateThreadNodeFiber(context, node1);\n    PhpUpdateThreadNodeFiber(context, node2);\n\n    sortResult = ucharcmp(node1->Fiber, node2->Fiber);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PriorityBoost)\n{\n    PhpUpdateThreadNodePriorityBoost(node1);\n    PhpUpdateThreadNodePriorityBoost(node2);\n\n    sortResult = ucharcmp(node1->PriorityBoost, node2->PriorityBoost);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CpuUser)\n{\n    sortResult = singlecmp(threadItem1->CpuUserUsage, threadItem2->CpuUserUsage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(CpuKernel)\n{\n    sortResult = singlecmp(threadItem1->CpuKernelUsage, threadItem2->CpuKernelUsage);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StackUsage)\n{\n    PhpUpdateThreadNodeStackUsage(context, node1);\n    PhpUpdateThreadNodeStackUsage(context, node2);\n\n    sortResult = singlecmp(node1->StackUsageFloat, node2->StackUsageFloat);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(WaitTime)\n{\n    sortResult = uintcmp(threadItem1->WaitTime, threadItem2->WaitTime);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoReads)\n{\n    sortResult = uint64cmp(threadItem1->IoCounters.ReadOperationCount, threadItem2->IoCounters.ReadOperationCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoWrites)\n{\n    sortResult = uint64cmp(threadItem1->IoCounters.WriteOperationCount, threadItem2->IoCounters.WriteOperationCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoOther)\n{\n    sortResult = uint64cmp(threadItem1->IoCounters.OtherOperationCount, threadItem2->IoCounters.OtherOperationCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoReadBytes)\n{\n    sortResult = uint64cmp(threadItem1->IoCounters.ReadTransferCount, threadItem2->IoCounters.ReadTransferCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoWriteBytes)\n{\n    sortResult = uint64cmp(threadItem1->IoCounters.WriteTransferCount, threadItem2->IoCounters.WriteTransferCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(IoOtherBytes)\n{\n    sortResult = uint64cmp(threadItem1->IoCounters.OtherTransferCount, threadItem2->IoCounters.OtherTransferCount);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LxssTid)\n{\n    sortResult = uintcmp(threadItem1->LxssThreadId, threadItem2->LxssThreadId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PowerThrottling)\n{\n    sortResult = uintcmp(threadItem1->PowerThrottling, threadItem2->PowerThrottling);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StartAddressKernel)\n{\n    sortResult = uint64cmp((ULONG_PTR)threadItem1->StartAddress, (ULONG_PTR)threadItem2->StartAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(KernelStackUsage)\n{\n    PhpUpdateThreadNodeKernelStackSize(context, node1);\n    PhpUpdateThreadNodeKernelStackSize(context, node2);\n\n    sortResult = singlecmp(node1->KernelStackUsageFloat, node2->KernelStackUsageFloat);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(HasRpc)\n{\n    PhpUpdateThreadNodeRpc(context, node1);\n    PhpUpdateThreadNodeRpc(context, node2);\n\n    sortResult = ucharcmp(node1->HasRpcState, node2->HasRpcState);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ActualBasePriority)\n{\n    sortResult = intcmp(threadItem1->ActualBasePriority, threadItem2->ActualBasePriority);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpThreadTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREAD_LIST_CONTEXT context = Context;\n    PPH_THREAD_NODE node;\n\n    if (PhCmForwardMessage(WindowHandle, Message, Parameter1, Parameter2, &context->Cm))\n        return TRUE;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(Tid),\n                    SORT_FUNCTION(Cpu),\n                    SORT_FUNCTION(CyclesDelta),\n                    SORT_FUNCTION(StartAddressWin32),\n                    SORT_FUNCTION(PrioritySymbolic),\n                    SORT_FUNCTION(Service),\n                    SORT_FUNCTION(Name),\n                    SORT_FUNCTION(Created),\n                    SORT_FUNCTION(StartModule),\n                    SORT_FUNCTION(ContextSwitches),\n                    SORT_FUNCTION(ContextSwitchesDelta), // delta\n                    SORT_FUNCTION(Priority),\n                    SORT_FUNCTION(BasePriority),\n                    SORT_FUNCTION(PagePriority),\n                    SORT_FUNCTION(IoPriority),\n                    SORT_FUNCTION(Cycles),\n                    SORT_FUNCTION(State),\n                    SORT_FUNCTION(KernelTime),\n                    SORT_FUNCTION(UserTime),\n                    SORT_FUNCTION(IdealProcessor),\n                    SORT_FUNCTION(Critical),\n                    SORT_FUNCTION(TidHex),\n                    SORT_FUNCTION(CpuCore),\n                    SORT_FUNCTION(TokenState),\n                    SORT_FUNCTION(PendingIrp),\n                    SORT_FUNCTION(LastSystemCall),\n                    SORT_FUNCTION(LastStatusCode),\n                    SORT_FUNCTION(Created), // Timeline\n                    SORT_FUNCTION(ApartmentType),\n                    SORT_FUNCTION(ApartmentFlags),\n                    SORT_FUNCTION(Fiber),\n                    SORT_FUNCTION(PriorityBoost),\n                    SORT_FUNCTION(CpuUser),\n                    SORT_FUNCTION(CpuKernel),\n                    SORT_FUNCTION(StackUsage),\n                    SORT_FUNCTION(WaitTime),\n                    SORT_FUNCTION(IoReads),\n                    SORT_FUNCTION(IoWrites),\n                    SORT_FUNCTION(IoOther),\n                    SORT_FUNCTION(IoReadBytes),\n                    SORT_FUNCTION(IoWriteBytes),\n                    SORT_FUNCTION(IoOtherBytes),\n                    SORT_FUNCTION(LxssTid),\n                    SORT_FUNCTION(PowerThrottling),\n                    SORT_FUNCTION(StartAddressKernel),\n                    SORT_FUNCTION(KernelStackUsage),\n                    SORT_FUNCTION(HasRpc),\n                    SORT_FUNCTION(ActualBasePriority),\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PH_THREAD_TREELIST_COLUMN_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (!PhCmForwardSort(\n                    (PPH_TREENEW_NODE *)context->NodeList->Items,\n                    context->NodeList->Count,\n                    context->TreeNewSortColumn,\n                    context->TreeNewSortOrder,\n                    &context->Cm\n                    ))\n                {\n                    if (context->TreeNewSortColumn < PH_THREAD_TREELIST_COLUMN_MAXIMUM)\n                        sortFunction = sortFunctions[context->TreeNewSortColumn];\n                    else\n                        sortFunction = NULL;\n                }\n                else\n                {\n                    sortFunction = NULL;\n                }\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            PPH_THREAD_ITEM threadItem;\n\n            node = (PPH_THREAD_NODE)getCellText->Node;\n            threadItem = node->ThreadItem;\n\n            switch (getCellText->Id)\n            {\n            case PH_THREAD_TREELIST_COLUMN_TID:\n                {\n                    PhInitializeStringRefLongHint(&getCellText->Text, threadItem->ThreadIdString);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_LXSSTID:\n                {\n                    PhInitializeStringRefLongHint(&getCellText->Text, threadItem->LxssThreadIdString);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_CPU:\n                {\n                    FLOAT cpuUsage;\n\n                    cpuUsage = threadItem->CpuUsage * 100;\n\n                    if (cpuUsage >= PhMaxPrecisionLimit)\n                    {\n                        PH_FORMAT format;\n                        SIZE_T returnLength;\n\n                        PhInitFormatF(&format, cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                    else if (cpuUsage != 0 && PhCsShowCpuBelow001)\n                    {\n                        PH_FORMAT format[2];\n                        SIZE_T returnLength;\n\n                        PhInitFormatS(&format[0], L\"< \");\n                        PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(format, 2, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_CYCLESDELTA:\n                {\n                    if (context->UseCycleTime)\n                    {\n                        if (threadItem->CyclesDelta.Delta != threadItem->CyclesDelta.Value && threadItem->CyclesDelta.Delta != 0)\n                        {\n                            PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->CyclesDelta.Delta, TRUE));\n                            getCellText->Text = node->CyclesDeltaText->sr;\n                        }\n                    }\n                    else\n                    {\n                        if (threadItem->ContextSwitchesDelta.Delta != threadItem->ContextSwitchesDelta.Value && threadItem->ContextSwitchesDelta.Delta != 0)\n                        {\n                            PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->ContextSwitchesDelta.Delta, TRUE));\n                            getCellText->Text = node->CyclesDeltaText->sr;\n                        }\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_STARTADDRESSWIN32:\n                {\n                    if (NT_SUCCESS(threadItem->StartAddressStatus))\n                    {\n                        getCellText->Text = PhGetStringRef(threadItem->StartAddressWin32String);\n                    }\n                    else\n                    {\n                        PPH_STRING errorMessage;\n                        PH_FORMAT format[5];\n\n                        PhInitFormatS(&format[0], L\"0x\");\n                        PhInitFormatX(&format[1], threadItem->StartAddressStatus);\n\n                        if (errorMessage = PhGetStatusMessage(threadItem->StartAddressStatus, 0))\n                        {\n                            PhInitFormatS(&format[2], L\" (\");\n                            PhInitFormatSR(&format[3], errorMessage->sr);\n                            PhInitFormatC(&format[4], L')');\n\n                            PhMoveReference(&threadItem->StartAddressWin32String, PhFormat(format, 5, 0));\n                            PhDereferenceObject(errorMessage);\n                        }\n                        else\n                        {\n                            PhMoveReference(&threadItem->StartAddressWin32String, PhFormat(format, 2, 0));\n                        }\n\n                        getCellText->Text = PhGetStringRef(threadItem->StartAddressWin32String);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_STARTADDRESS:\n                {\n                    if (threadItem->StartAddress)\n                    {\n                        getCellText->Text = PhGetStringRef(threadItem->StartAddressString);\n                    }\n                    else\n                    {\n                        NTSTATUS status;\n                        PPH_STRING errorMessage;\n                        PH_FORMAT format[5];\n\n                        if (WindowsVersion > WINDOWS_10_22H2)\n                            status = STATUS_ACCESS_DENIED;\n                        else\n                            status = STATUS_BUFFER_ALL_ZEROS;\n\n                        PhInitFormatS(&format[0], L\"0x\");\n                        PhInitFormatX(&format[1], status);\n\n                        if (errorMessage = PhGetStatusMessage(status, 0))\n                        {\n                            PhInitFormatS(&format[2], L\" (\");\n                            PhInitFormatSR(&format[3], errorMessage->sr);\n                            PhInitFormatC(&format[4], L')');\n\n                            PhMoveReference(&threadItem->StartAddressString, PhFormat(format, 5, 0));\n                            PhDereferenceObject(errorMessage);\n                        }\n                        else\n                        {\n                            PhMoveReference(&threadItem->StartAddressString, PhFormat(format, 2, 0));\n                        }\n\n                        getCellText->Text = PhGetStringRef(threadItem->StartAddressString);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_PRIORITYSYMBOLIC:\n                {\n                    getCellText->Text = *PhGetBasePrioritySymbolicString(threadItem->BasePriority);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_SERVICE:\n                {\n                    getCellText->Text = PhGetStringRef(threadItem->ServiceName);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_NAME:\n                {\n                    PhpUpdateThreadNodeNameText(node);\n                    getCellText->Text = PhGetStringRef(node->NameText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_STARTED:\n                {\n                    PhpUpdateThreadNodeStartedText(node);\n                    getCellText->Text = PhGetStringRef(node->CreatedText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_STARTMODULE:\n                {\n                    getCellText->Text = PhGetStringRef(threadItem->StartAddressWin32FileName);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHES:\n                {\n                    SIZE_T returnLength;\n                    PH_FORMAT format[1];\n\n                    PhInitFormatI64UGroupDigits(&format[0], threadItem->ContextSwitchesDelta.Value);\n\n                    if (PhFormatToBuffer(format, 1, node->ContextSwitchesText, sizeof(node->ContextSwitchesText), &returnLength))\n                    {\n                        getCellText->Text.Buffer = node->ContextSwitchesText;\n                        getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHESDELTA:\n                {\n                    if ((LONG)threadItem->ContextSwitchesDelta.Delta >= 0) // the delta may be negative if a thread exits - just don't show anything\n                    {\n                        ULONG value = threadItem->ContextSwitchesDelta.Delta;\n\n                        if (value != 0)\n                        {\n                            PhMoveReference(&node->ContextSwitchesDeltaText, PhFormatUInt64(value, TRUE));\n                            getCellText->Text = node->ContextSwitchesDeltaText->sr;\n                        }\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_PRIORITY:\n                {\n                    SIZE_T returnLength;\n                    PH_FORMAT format[1];\n\n                    PhInitFormatD(&format[0], threadItem->Priority);\n\n                    if (PhFormatToBuffer(format, 1, node->PriorityText, sizeof(node->PriorityText), &returnLength))\n                    {\n                        getCellText->Text.Buffer = node->PriorityText;\n                        getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_BASEPRIORITY:\n                {\n                    SIZE_T returnLength;\n                    PH_FORMAT format[1];\n\n                    PhInitFormatD(&format[0], threadItem->BasePriority);\n\n                    if (PhFormatToBuffer(format, 1, node->BasePriorityText, sizeof(node->BasePriorityText), &returnLength))\n                    {\n                        getCellText->Text.Buffer = node->BasePriorityText;\n                        getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_PAGEPRIORITY:\n                {\n                    PH_STRINGREF pagePriority = PH_STRINGREF_INIT(L\"N/A\");\n\n                    PhpUpdateThreadNodePagePriority(node);\n\n                    if (node->PagePriority != ULONG_MAX && node->PagePriority <= MEMORY_PRIORITY_NORMAL)\n                    {\n                        pagePriority = PhPagePriorityNames[node->PagePriority];\n                    }\n\n                    getCellText->Text.Buffer = pagePriority.Buffer;\n                    getCellText->Text.Length = pagePriority.Length;\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_IOPRIORITY:\n                {\n                    PH_STRINGREF ioPriority = PH_STRINGREF_INIT(L\"N/A\");\n\n                    PhpUpdateThreadNodeIoPriority(node);\n\n                    if (node->IoPriority != ULONG_MAX && node->IoPriority >= IoPriorityVeryLow && node->IoPriority < MaxIoPriorityTypes)\n                    {\n                        ioPriority = PhIoPriorityHintNames[node->IoPriority];\n                    }\n\n                    getCellText->Text.Buffer = ioPriority.Buffer;\n                    getCellText->Text.Length = ioPriority.Length;\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_CYCLES:\n                {\n                    if (threadItem->CyclesDelta.Value != 0)\n                    {\n                        SIZE_T returnLength;\n                        PH_FORMAT format[1];\n\n                        PhInitFormatI64UGroupDigits(&format[0], threadItem->CyclesDelta.Value);\n\n                        if (PhFormatToBuffer(format, 1, node->CyclesText, sizeof(node->CyclesText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CyclesText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_STATE:\n                {\n                    if (threadItem->State != Waiting)\n                    {\n                        static const PH_STRINGREF stringUnknown = PH_STRINGREF_INIT(L\"Unknown\");\n\n                        if ((ULONG)threadItem->State < MaximumThreadState)\n                            PhMoveReference(&node->StateText, PhCreateString2((PPH_STRINGREF)&PhKThreadStateNames[(ULONG)threadItem->State]));\n                        else\n                            PhMoveReference(&node->StateText, PhCreateString2((PPH_STRINGREF)&stringUnknown));\n                    }\n                    else\n                    {\n                        static const PH_STRINGREF stringWait = PH_STRINGREF_INIT(L\"Wait:\");\n                        static const PH_STRINGREF stringWaiting = PH_STRINGREF_INIT(L\"Waiting\");\n\n                        if ((ULONG)threadItem->WaitReason < MaximumWaitReason)\n                            PhMoveReference(&node->StateText, PhConcatStringRef2((PPH_STRINGREF)&stringWait, (PPH_STRINGREF)&PhKWaitReasonNames[(ULONG)threadItem->WaitReason]));\n                        else\n                            PhMoveReference(&node->StateText, PhCreateString2((PPH_STRINGREF)&stringWaiting));\n                    }\n\n                    if (threadItem->ThreadHandle && threadItem->WaitReason == Suspended)\n                    {\n                        PH_FORMAT format[4];\n\n                        PhpUpdateThreadNodeSuspendCount(node);\n\n                        PhInitFormatSR(&format[0], node->StateText->sr);\n                        PhInitFormatS(&format[1], L\" (\");\n                        PhInitFormatU(&format[2], node->SuspendCount);\n                        PhInitFormatS(&format[3], L\")\");\n\n                        PhMoveReference(&node->StateText, PhFormat(format, 4, 30));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->StateText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_KERNELTIME:\n                {\n                    if (threadItem->KernelTime.QuadPart != 0)\n                    {\n                        PhMoveReference(&node->KernelTimeText, PhFormatTimeSpan(threadItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->KernelTimeText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_USERTIME:\n                {\n                    if (threadItem->UserTime.QuadPart != 0)\n                    {\n                        PhMoveReference(&node->UserTimeText, PhFormatTimeSpan(threadItem->UserTime.QuadPart, PH_TIMESPAN_HMSM));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->UserTimeText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR:\n                {\n                    PROCESSOR_NUMBER idealProcessorNumber;\n                    SIZE_T returnLength;\n                    PH_FORMAT format[3];\n\n                    PhpUpdateThreadNodeIdealProcessor(node);\n\n                    memset(&idealProcessorNumber, 0, sizeof(idealProcessorNumber));\n                    idealProcessorNumber.Group = HIWORD(node->IdealProcessorMask);\n                    idealProcessorNumber.Number = (BYTE)LOWORD(node->IdealProcessorMask);\n\n                    PhInitFormatU(&format[0], idealProcessorNumber.Group);\n                    PhInitFormatC(&format[1], L':');\n                    PhInitFormatU(&format[2], idealProcessorNumber.Number);\n\n                    if (PhFormatToBuffer(format, 3, node->IdealProcessorText, sizeof(node->IdealProcessorText), &returnLength))\n                    {\n                        getCellText->Text.Buffer = node->IdealProcessorText;\n                        getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_CRITICAL:\n                {\n                    PhpUpdateThreadNodeBreakOnTermination(node);\n\n                    if (node->BreakOnTermination)\n                        PhInitializeStringRef(&getCellText->Text, L\"Critical\");\n                    else\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_TIDHEX:\n                {\n                    PhInitializeStringRefLongHint(&getCellText->Text, threadItem->ThreadIdHexString);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_CPUCORECYCLES:\n                {\n                    FLOAT cpuUsage;\n\n                    cpuUsage = threadItem->CpuUsage * 100.f;\n                    cpuUsage *= threadItem->AffinityPopulationCount;  // linux style (dmex)\n\n                    if (cpuUsage >= PhMaxPrecisionLimit)\n                    {\n                        PH_FORMAT format;\n                        SIZE_T returnLength;\n\n                        PhInitFormatF(&format, cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(&format, 1, node->CpuCoreUsageText, sizeof(node->CpuCoreUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuCoreUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                    else if (cpuUsage != 0 && PhCsShowCpuBelow001)\n                    {\n                        PH_FORMAT format[2];\n                        SIZE_T returnLength;\n\n                        PhInitFormatS(&format[0], L\"< \");\n                        PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(format, 2, node->CpuCoreUsageText, sizeof(node->CpuCoreUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuCoreUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_TOKEN_STATE:\n                {\n                    PhpUpdateThreadNodeTokenState(node);\n\n                    if (node->TokenState == PH_THREAD_TOKEN_STATE_NOT_PRESENT)\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                    else if (node->TokenState == PH_THREAD_TOKEN_STATE_ANONYMOUS)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Anonymous\");\n                    }\n                    else if (node->TokenState == PH_THREAD_TOKEN_STATE_PRESENT)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Yes\");\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_PENDINGIRP:\n                {\n                    PhpUpdateThreadNodeIoPending(node);\n\n                    if (node->PendingIrp)\n                        PhInitializeStringRef(&getCellText->Text, L\"Yes\");\n                    else\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_LASTSYSTEMCALL:\n                {\n                    if (context->ProcessId == SYSTEM_IDLE_PROCESS_ID || context->ProcessId == SYSTEM_PROCESS_ID)\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                        break;\n                    }\n\n                    PhpUpdateThreadNodeLastSystemCall(node);\n\n                    if (NT_SUCCESS(node->LastSystemCallStatus))\n                    {\n                        PPH_STRING systemCallName;\n                        PH_FORMAT format[8];\n\n                        if (node->LastSystemCall.SystemCallNumber == 0 && !node->LastSystemCall.FirstArgument)\n                        {\n                            // If the thread was created in a frozen/suspended process and hasn't executed, the\n                            // ThreadLastSystemCall returns status_success but the values are invalid. (dmex)\n                            PhClearReference(&node->LastSystemCallText);\n                        }\n                        else\n                        {\n                            if (systemCallName = PhGetSystemCallNumberName(node->LastSystemCall.SystemCallNumber))\n                            {\n                                PhInitFormatSR(&format[0], systemCallName->sr);\n                                PhInitFormatS(&format[1], L\" (0x\");\n                                PhInitFormatX(&format[2], node->LastSystemCall.SystemCallNumber);\n                                PhInitFormatS(&format[3], L\") (Arg0: 0x\");\n                                PhInitFormatI64X(&format[4], (ULONG64)node->LastSystemCall.FirstArgument);\n\n                                if (WindowsVersion < WINDOWS_8)\n                                {\n                                    PhInitFormatC(&format[5], L')');\n                                    PhMoveReference(&node->LastSystemCallText, PhFormat(format, 6, 0x40));\n                                }\n                                else\n                                {\n                                    PPH_STRING waitTime;\n\n                                    waitTime = PhFormatTimeSpanRelative(node->LastSystemCall.WaitTime);\n                                    PhInitFormatS(&format[5], L\") [\");\n                                    PhInitFormatSR(&format[6], waitTime->sr);\n                                    PhInitFormatC(&format[7], L']');\n                                    PhMoveReference(&node->LastSystemCallText, PhFormat(format, 8, 0x40));\n                                    PhDereferenceObject(waitTime);\n                                }\n\n                                PhDereferenceObject(systemCallName);\n                            }\n                            else\n                            {\n                                PhInitFormatS(&format[0], L\"0x\");\n                                PhInitFormatX(&format[1], node->LastSystemCall.SystemCallNumber);\n                                PhInitFormatS(&format[2], L\" (Arg0: 0x\");\n                                PhInitFormatI64X(&format[3], (ULONG64)node->LastSystemCall.FirstArgument);\n\n                                if (WindowsVersion < WINDOWS_8)\n                                {\n                                    PhInitFormatC(&format[4], L')');\n                                    PhMoveReference(&node->LastSystemCallText, PhFormat(format, 5, 0x40));\n                                }\n                                else\n                                {\n                                    PPH_STRING waitTime;\n\n                                    waitTime = PhFormatTimeSpanRelative(node->LastSystemCall.WaitTime);\n                                    PhInitFormatS(&format[4], L\") [\");\n                                    PhInitFormatSR(&format[5], waitTime->sr);\n                                    PhInitFormatC(&format[6], L']');\n                                    PhMoveReference(&node->LastSystemCallText, PhFormat(format, 7, 0x40));\n                                }\n                            }\n                        }\n                    }\n                    else\n                    {\n                        PH_FORMAT format[2];\n\n                        PhInitFormatS(&format[0], L\"0x\");\n                        PhInitFormatX(&format[1], node->LastSystemCallStatus);\n                        PhMoveReference(&node->LastSystemCallText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->LastSystemCallText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_LASTSTATUSCODE:\n                {\n                    PPH_STRING errorMessage;\n\n                    if (context->ProcessId == SYSTEM_IDLE_PROCESS_ID || context->ProcessId == SYSTEM_PROCESS_ID)\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                        break;\n                    }\n\n                    PhpUpdateThreadNodeLastStatusCode(context, node);\n\n                    if (NT_SUCCESS(node->LastStatusQueryStatus))\n                    {\n                        if (node->LastStatusValue == STATUS_SUCCESS)\n                        {\n                            PhClearReference(&node->LastErrorCodeText);\n                        }\n                        else\n                        {\n                            PH_FORMAT format[5];\n\n                            PhInitFormatS(&format[0], L\"0x\");\n                            PhInitFormatX(&format[1], node->LastStatusValue);\n\n                            if (errorMessage = PhGetStatusMessage(node->LastStatusValue, 0))\n                            {\n                                PhInitFormatS(&format[2], L\" (\");\n                                PhInitFormatSR(&format[3], errorMessage->sr);\n                                PhInitFormatC(&format[4], L')');\n\n                                PhMoveReference(&node->LastErrorCodeText, PhFormat(format, 5, 0x40));\n                                PhDereferenceObject(errorMessage);\n                            }\n                            else\n                            {\n                                PhMoveReference(&node->LastErrorCodeText, PhFormat(format, 2, 0x40));\n                            }\n                        }\n                    }\n                    else\n                    {\n                        PH_FORMAT format[2];\n\n                        PhInitFormatS(&format[0], L\"0x\");\n                        PhInitFormatX(&format[1], node->LastStatusQueryStatus);\n\n                        PhMoveReference(&node->LastErrorCodeText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->LastErrorCodeText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_APARTMENTTYPE:\n                {\n                    if (context->ProcessId == SYSTEM_IDLE_PROCESS_ID || context->ProcessId == SYSTEM_PROCESS_ID)\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                        break;\n                    }\n\n                    PhpUpdateThreadNodeApartmentState(context, node);\n\n                    if (node->ApartmentInfo.Type)\n                    {\n                        PPH_STRING apartmentTypeString;\n\n                        if (apartmentTypeString = PhGetApartmentTypeString(&node->ApartmentInfo))\n                        {\n                            PhMoveReference(&node->ApartmentTypeText, apartmentTypeString);\n                        }\n                        else\n                        {\n                            PhClearReference(&node->ApartmentTypeText);\n                        }\n                    }\n                    else\n                    {\n                        PhClearReference(&node->ApartmentTypeText);\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->ApartmentTypeText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_APARTMENTFLAGS:\n                {\n                    if (context->ProcessId == SYSTEM_IDLE_PROCESS_ID || context->ProcessId == SYSTEM_PROCESS_ID)\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                        break;\n                    }\n\n                    PhpUpdateThreadNodeApartmentState(context, node);\n\n                    if (node->ApartmentInfo.Flags)\n                    {\n                        PPH_STRING apartmentStateString;\n\n                        if (apartmentStateString = PhGetApartmentFlagsString(node->ApartmentInfo.Flags))\n                        {\n                            PhMoveReference(&node->ApartmentFlagsText, apartmentStateString);\n                        }\n                        else\n                        {\n                            PhClearReference(&node->ApartmentFlagsText);\n                        }\n                    }\n                    else\n                    {\n                        PhClearReference(&node->ApartmentFlagsText);\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->ApartmentFlagsText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_FIBER:\n                {\n                    if (context->ProcessId == SYSTEM_IDLE_PROCESS_ID || context->ProcessId == SYSTEM_PROCESS_ID)\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                        break;\n                    }\n\n                    PhpUpdateThreadNodeFiber(context, node);\n\n                    if (node->Fiber)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Yes\");\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_PRIORITYBOOST:\n                {\n                    PhpUpdateThreadNodePriorityBoost(node);\n\n                    if (node->PriorityBoost)\n                        PhInitializeStringRef(&getCellText->Text, L\"Yes\");\n                    else\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_CPUUSER:\n                {\n                    FLOAT cpuUsage;\n\n                    cpuUsage = threadItem->CpuUserUsage * 100.f;\n\n                    if (cpuUsage >= PhMaxPrecisionLimit)\n                    {\n                        PH_FORMAT format;\n                        SIZE_T returnLength;\n\n                        PhInitFormatF(&format, cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(&format, 1, node->CpuUserUsageText, sizeof(node->CpuUserUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuUserUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                    else if (cpuUsage != 0 && PhCsShowCpuBelow001)\n                    {\n                        PH_FORMAT format[2];\n                        SIZE_T returnLength;\n\n                        PhInitFormatS(&format[0], L\"< \");\n                        PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(format, 2, node->CpuUserUsageText, sizeof(node->CpuUserUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuUserUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_CPUKERNEL:\n                {\n                    FLOAT cpuUsage;\n\n                    cpuUsage = threadItem->CpuKernelUsage * 100.f;\n\n                    if (cpuUsage >= PhMaxPrecisionLimit)\n                    {\n                        PH_FORMAT format;\n                        SIZE_T returnLength;\n\n                        PhInitFormatF(&format, cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(&format, 1, node->CpuKernelUsageText, sizeof(node->CpuKernelUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuKernelUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                    else if (cpuUsage != 0 && PhCsShowCpuBelow001)\n                    {\n                        PH_FORMAT format[2];\n                        SIZE_T returnLength;\n\n                        PhInitFormatS(&format[0], L\"< \");\n                        PhInitFormatF(&format[1], cpuUsage, PhMaxPrecisionUnit);\n\n                        if (PhFormatToBuffer(format, 2, node->CpuKernelUsageText, sizeof(node->CpuKernelUsageText), &returnLength))\n                        {\n                            getCellText->Text.Buffer = node->CpuKernelUsageText;\n                            getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                        }\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_STACKUSAGE:\n                {\n                    if (context->ProcessId == SYSTEM_IDLE_PROCESS_ID || context->ProcessId == SYSTEM_PROCESS_ID)\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                        break;\n                    }\n\n                    PhpUpdateThreadNodeStackUsage(context, node);\n\n                    if (node->StackUsage && node->StackLimit)\n                    {\n                        PH_FORMAT format[6];\n\n                        // %s / %s (%.0f%%)\n                        PhInitFormatSize(&format[0], node->StackUsage);\n                        PhInitFormatS(&format[1], L\" | \");\n                        PhInitFormatSize(&format[2], node->StackLimit);\n                        PhInitFormatS(&format[3], L\" (\");\n                        PhInitFormatF(&format[4], node->StackUsageFloat, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[5], L\"%)\");\n\n                        PhMoveReference(&node->StackUsageText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                    }\n                    else\n                    {\n                        PhClearReference(&node->StackUsageText);\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->StackUsageText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_KSTACKUSAGE:\n                {\n                    PhpUpdateThreadNodeKernelStackSize(context, node);\n\n                    if (node->KernelStackUsage && node->KernelStackLimit)\n                    {\n                        PH_FORMAT format[6];\n\n                        // %s / %s (%.0f%%)\n                        PhInitFormatSize(&format[0], node->KernelStackUsage);\n                        PhInitFormatS(&format[1], L\" | \");\n                        PhInitFormatSize(&format[2], node->KernelStackLimit);\n                        PhInitFormatS(&format[3], L\" (\");\n                        PhInitFormatF(&format[4], node->KernelStackUsageFloat, PhMaxPrecisionUnit);\n                        PhInitFormatS(&format[5], L\"%)\");\n\n                        PhMoveReference(&node->KernelStackUsageText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                    }\n                    else\n                    {\n                        PhClearReference(&node->KernelStackUsageText);\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->KernelStackUsageText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_WAITTIME:\n                {\n                    if (threadItem->WaitTime != 0)\n                    {\n                        PhMoveReference(&node->WaitTimeText, PhFormatTimeSpan(threadItem->WaitTime, PH_TIMESPAN_HMSM));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->WaitTimeText);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_IOREADS:\n                {\n                    if (threadItem->IoCounters.ReadOperationCount != 0)\n                    {\n                        PhMoveReference(&node->IoReads, PhFormatUInt64(threadItem->IoCounters.ReadOperationCount, TRUE));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->IoReads);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_IOWRITES:\n                {\n                    if (threadItem->IoCounters.WriteOperationCount != 0)\n                    {\n                        PhMoveReference(&node->IoWrites, PhFormatUInt64(threadItem->IoCounters.WriteOperationCount, TRUE));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->IoWrites);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_IOOTHER:\n                {\n                    if (threadItem->IoCounters.OtherOperationCount != 0)\n                    {\n                        PhMoveReference(&node->IoOther, PhFormatUInt64(threadItem->IoCounters.OtherOperationCount, TRUE));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->IoOther);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_IOREADBYTES:\n                {\n                    if (threadItem->IoCounters.ReadTransferCount != 0)\n                    {\n                        PhMoveReference(&node->IoReadBytes, PhFormatSize(threadItem->IoCounters.ReadTransferCount, ULONG_MAX));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->IoReadBytes);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_IOWRITEBYTES:\n                {\n                    if (threadItem->IoCounters.WriteTransferCount != 0)\n                    {\n                        PhMoveReference(&node->IoWriteBytes, PhFormatSize(threadItem->IoCounters.WriteTransferCount, ULONG_MAX));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->IoWriteBytes);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_IOOTHERBYTES:\n                {\n                    if (threadItem->IoCounters.OtherTransferCount != 0)\n                    {\n                        PhMoveReference(&node->IoOtherBytes, PhFormatSize(threadItem->IoCounters.OtherTransferCount, ULONG_MAX));\n                    }\n\n                    getCellText->Text = PhGetStringRef(node->IoOtherBytes);\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_POWERTHROTTLING:\n                {\n                    if (threadItem->PowerThrottling)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Yes\");\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_RPC:\n                {\n                    if (context->ProcessId == SYSTEM_IDLE_PROCESS_ID || context->ProcessId == SYSTEM_PROCESS_ID)\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                        break;\n                    }\n\n                    PhpUpdateThreadNodeRpc(context, node);\n\n                    if (node->HasRpcState)\n                    {\n                        PhInitializeStringRef(&getCellText->Text, L\"Yes\");\n                    }\n                    else\n                    {\n                        PhInitializeEmptyStringRef(&getCellText->Text);\n                    }\n                }\n                break;\n            case PH_THREAD_TREELIST_COLUMN_ACTUALBASEPRIORITY:\n                {\n                    SIZE_T returnLength;\n                    PH_FORMAT format[1];\n\n                    PhInitFormatD(&format[0], threadItem->ActualBasePriority);\n\n                    if (PhFormatToBuffer(format, 1, node->ActualBasePriorityText, sizeof(node->ActualBasePriorityText), &returnLength))\n                    {\n                        getCellText->Text.Buffer = node->ActualBasePriorityText;\n                        getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL);\n                    }\n                }\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            PPH_THREAD_ITEM threadItem;\n\n            node = (PPH_THREAD_NODE)getNodeColor->Node;\n            threadItem = node->ThreadItem;\n\n            if (!threadItem)\n                NOTHING;\n            //else if (context->HighlightUnknownStartAddress && threadItem->StartAddressWin32ResolveLevel == PhsrlAddress)\n            //    getNodeColor->BackColor = PhCsColorUnknown;\n            else if (context->HighlightSuspended && threadItem->WaitReason == Suspended)\n                getNodeColor->BackColor = PhCsColorSuspended;\n            else if (context->HighlightSuspended && threadItem->WaitReason == DelayExecution) // NtDelayExecution\n                getNodeColor->BackColor = PhCsColorImmersiveProcesses;\n            else if (context->HighlightSuspended && threadItem->WaitReason == UserRequest) // NtWaitForSingleObject\n                getNodeColor->BackColor = PhCsColorOwnProcesses;\n            else if (context->HighlightSuspended && threadItem->WaitReason == WrAlertByThreadId)\n                getNodeColor->BackColor = PhCsColorSystemProcesses;\n            else if (context->HighlightSuspended && threadItem->WaitReason == WrQueue) // NtRemoveIoCompletion\n                getNodeColor->BackColor = PhCsColorEfficiencyMode;\n            else if (context->HighlightSuspended && threadItem->WaitReason == Executive)\n                getNodeColor->BackColor = PhCsColorElevatedProcesses;\n            else if (context->HighlightGuiThreads && threadItem->IsGuiThread)\n                getNodeColor->BackColor = PhCsColorGuiThreads;\n\n            getNodeColor->Flags = TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewCustomDraw:\n        {\n            PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;\n            PPH_THREAD_ITEM threadItem;\n            RECT rect;\n\n            node = (PPH_THREAD_NODE)customDraw->Node;\n            threadItem = node->ThreadItem;\n            rect = customDraw->CellRect;\n\n            if (rect.right - rect.left <= 1)\n                break; // nothing to draw\n\n            switch (customDraw->Column->Id)\n            {\n            case PH_THREAD_TREELIST_COLUMN_TIMELINE:\n                {\n                    if (threadItem->CreateTime.QuadPart == 0)\n                        break; // nothing to draw\n\n                    PhCustomDrawTreeTimeLine(\n                        customDraw->Dc,\n                        &customDraw->CellRect,\n                        PhEnableThemeSupport ? PH_DRAW_TIMELINE_DARKTHEME : 0,\n                        &context->ProcessCreateTime,\n                        &threadItem->CreateTime\n                        );\n                }\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_COPY, 0);\n                break;\n            case VK_DELETE:\n                SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_TERMINATE, 0);\n                break;\n            case VK_RETURN:\n                SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_INSPECT, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            // Customizable columns are disabled until we can figure out how to make it\n            // co-operate with the column adjustments (e.g. Cycles Delta vs Context Switches Delta,\n            // Service column).\n\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = PH_THREAD_TREELIST_COLUMN_CYCLESDELTA;\n            data.DefaultSortOrder = DescendingSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_INSPECT, 0);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n\n            SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu);\n        }\n        return TRUE;\n    case TreeNewGetDialogCode:\n        {\n            PULONG code = Parameter2;\n\n            if (PtrToUlong(Parameter1) == VK_RETURN)\n            {\n                *code = DLGC_WANTMESSAGE;\n                return TRUE;\n            }\n        }\n        return FALSE;\n    }\n\n    return FALSE;\n}\n\nPPH_THREAD_ITEM PhGetSelectedThreadItem(\n    _In_ PPH_THREAD_LIST_CONTEXT Context\n    )\n{\n    PPH_THREAD_ITEM threadItem = NULL;\n    ULONG i;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_THREAD_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            threadItem = node->ThreadItem;\n            break;\n        }\n    }\n\n    return threadItem;\n}\n\nVOID PhGetSelectedThreadItems(\n    _In_ PPH_THREAD_LIST_CONTEXT Context,\n    _Out_ PPH_THREAD_ITEM **Threads,\n    _Out_ PULONG NumberOfThreads\n    )\n{\n    PH_ARRAY array;\n    ULONG i;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_THREAD_NODE node = Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n            PhAddItemArray(&array, &node->ThreadItem);\n    }\n\n    *NumberOfThreads = (ULONG)PhFinalArrayCount(&array);\n    *Threads = PhFinalArrayItems(&array);\n}\n\nPPH_STRING PhGetApartmentTypeString(\n    _In_ PPH_APARTMENT_INFO ApartmentInfo\n    )\n{\n    PH_FORMAT format[5];\n    ULONG count = 0;\n\n    if (ApartmentInfo->InNeutral)\n        PhInitFormatS(&format[count++], L\"NTA on \");\n\n    switch (ApartmentInfo->Type)\n    {\n    case PH_APARTMENT_TYPE_STA:\n        PhInitFormatS(&format[count++], L\"STA\");\n        break;\n    case PH_APARTMENT_TYPE_MAIN_STA:\n        PhInitFormatS(&format[count++], L\"Main STA\");\n        break;\n    case PH_APARTMENT_TYPE_APPLICATION_STA:\n        PhInitFormatS(&format[count++], L\"ASTA\");\n        break;\n    case PH_APARTMENT_TYPE_MTA:\n        PhInitFormatS(&format[count++], L\"MTA\");\n        break;\n    case PH_APARTMENT_TYPE_IMPLICIT_MTA:\n        PhInitFormatS(&format[count++], L\"Implicit MTA\");\n        break;\n    default:\n        assert(FALSE);\n    }\n\n    if (ApartmentInfo->ComInits > 1)\n    {\n        PhInitFormatS(&format[count++], L\" (x\");\n        PhInitFormatU(&format[count++], ApartmentInfo->ComInits);\n        PhInitFormatC(&format[count++], L')');\n    }\n\n    return PhFormat(format, count, 10);\n}\n\nPPH_STRING PhGetApartmentFlagsString(\n    _In_ ULONG ApartmentState\n    )\n{\n#define PH_OLE_TLS_FLAG(x, n) { TEXT(#x), (x), FALSE, FALSE, (n) }\n    static const PH_ACCESS_ENTRY oleTlsflags[] =\n    {\n        PH_OLE_TLS_FLAG(OLETLS_LOCALTID, L\"Local TID\"),\n        PH_OLE_TLS_FLAG(OLETLS_UUIDINITIALIZED, L\"UUID initialized\"),\n        PH_OLE_TLS_FLAG(OLETLS_INTHREADDETACH, L\"In thread detach\"),\n        PH_OLE_TLS_FLAG(OLETLS_CHANNELTHREADINITIALZED, L\"Channel thread initialized\"),\n        PH_OLE_TLS_FLAG(OLETLS_WOWTHREAD, L\"WoW thread\"),\n        PH_OLE_TLS_FLAG(OLETLS_THREADUNINITIALIZING, L\"Thread uninitializing\"),\n        PH_OLE_TLS_FLAG(OLETLS_DISABLE_OLE1DDE, L\"OLE1DDE disabled\"),\n        PH_OLE_TLS_FLAG(OLETLS_APARTMENTTHREADED, L\"Single threaded (STA)\"),\n        PH_OLE_TLS_FLAG(OLETLS_MULTITHREADED, L\"Multi threaded (MTA)\"),\n        PH_OLE_TLS_FLAG(OLETLS_IMPERSONATING, L\"Impersonating\"),\n        PH_OLE_TLS_FLAG(OLETLS_DISABLE_EVENTLOGGER, L\"Eventlogger disabled\"),\n        PH_OLE_TLS_FLAG(OLETLS_INNEUTRALAPT, L\"Neutral threaded (NTA)\"),\n        PH_OLE_TLS_FLAG(OLETLS_DISPATCHTHREAD, L\"Dispatch thread\"),\n        PH_OLE_TLS_FLAG(OLETLS_HOSTTHREAD, L\"Host thread\"),\n        PH_OLE_TLS_FLAG(OLETLS_ALLOWCOINIT, L\"Allow CoInit\"),\n        PH_OLE_TLS_FLAG(OLETLS_PENDINGUNINIT, L\"Pending uninit\"),\n        PH_OLE_TLS_FLAG(OLETLS_FIRSTMTAINIT, L\"First MTA init\"),\n        PH_OLE_TLS_FLAG(OLETLS_FIRSTNTAINIT, L\"First NTA init\"),\n        PH_OLE_TLS_FLAG(OLETLS_APTINITIALIZING, L\"Apartment initializing\"),\n        PH_OLE_TLS_FLAG(OLETLS_UIMSGSINMODALLOOP, L\"UI messages in modal loop\"),\n        PH_OLE_TLS_FLAG(OLETLS_MARSHALING_ERROR_OBJECT, L\"Marshaling error object\"),\n        PH_OLE_TLS_FLAG(OLETLS_WINRT_INITIALIZE, L\"WinRT initialized\"),\n        PH_OLE_TLS_FLAG(OLETLS_APPLICATION_STA, L\"Application STA\"),\n        PH_OLE_TLS_FLAG(OLETLS_IN_SHUTDOWN_CALLBACKS, L\"In shutdown callbacks\"),\n        PH_OLE_TLS_FLAG(OLETLS_POINTER_INPUT_BLOCKED, L\"Pointer input blocked\"),\n        PH_OLE_TLS_FLAG(OLETLS_IN_ACTIVATION_FILTER, L\"In activation filter\"),\n        PH_OLE_TLS_FLAG(OLETLS_ASTATOASTAEXEMPT_QUIRK, L\"ASTA-to-ASTA exempt quirk\"),\n        PH_OLE_TLS_FLAG(OLETLS_ASTATOASTAEXEMPT_PROXY, L\"ASTA-to-ASTA exempt proxy\"),\n        PH_OLE_TLS_FLAG(OLETLS_ASTATOASTAEXEMPT_INDOUBT, L\"ASTA-to-ASTA exempt in doubt\"),\n        PH_OLE_TLS_FLAG(OLETLS_DETECTED_USER_INITIALIZED, L\"Detected user initialized\"),\n        PH_OLE_TLS_FLAG(OLETLS_BRIDGE_STA, L\"Bridge STA\"),\n        PH_OLE_TLS_FLAG(OLETLS_NAINITIALIZING, L\"NTA initializing\"),\n    };\n\n    PPH_STRING string;\n    PH_FORMAT format[4];\n\n    string = PhGetAccessString(\n        ApartmentState,\n        (PPH_ACCESS_ENTRY)oleTlsflags,\n        RTL_NUMBER_OF(oleTlsflags)\n        );\n\n    PhInitFormatSR(&format[0], string->sr);\n    PhInitFormatS(&format[1], L\" (0x\");\n    PhInitFormatX(&format[2], ApartmentState);\n    PhInitFormatC(&format[3], L')');\n\n    PhMoveReference(&string, PhFormat(format, RTL_NUMBER_OF(format), 10));\n\n    return string;\n}\n"
  },
  {
    "path": "SystemInformer/thrdprv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n/*\n * The thread provider is tied to the process provider, and runs by registering a callback for the\n * processes-updated event. This is because calculating CPU usage depends on deltas calculated by\n * the process provider. However, this does increase the complexity of the thread provider system.\n */\n\n#include <phapp.h>\n#include <phplug.h>\n#include <thrdprv.h>\n\n#include <svcsup.h>\n#include <symprv.h>\n#include <workqueue.h>\n#include <kphuser.h>\n\n#include <extmgri.h>\n#include <procprv.h>\n\ntypedef struct _PH_THREAD_QUERY_DATA\n{\n    SLIST_ENTRY ListEntry;\n    PPH_THREAD_PROVIDER ThreadProvider;\n    PPH_THREAD_ITEM ThreadItem;\n    ULONG64 RunId;\n\n    PPH_STRING StartAddressWin32String;\n    PPH_STRING StartAddressWin32FileName;\n    PH_SYMBOL_RESOLVE_LEVEL StartAddressWin32ResolveLevel;\n\n    PPH_STRING StartAddressString;\n    PPH_STRING StartAddressFileName;\n    PH_SYMBOL_RESOLVE_LEVEL StartAddressResolveLevel;\n\n    PPH_STRING ServiceName;\n} PH_THREAD_QUERY_DATA, *PPH_THREAD_QUERY_DATA;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpThreadProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpThreadItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PhpThreadHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpThreadHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhpThreadProviderCallbackHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhpThreadProviderUpdate(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _In_ PVOID ProcessInformation\n    );\n\nPPH_OBJECT_TYPE PhThreadProviderType = NULL;\nPPH_OBJECT_TYPE PhThreadItemType = NULL;\nPH_WORK_QUEUE PhThreadProviderWorkQueue;\nPH_INITONCE PhThreadProviderWorkQueueInitOnce = PH_INITONCE_INIT;\n\nVOID PhpQueueThreadWorkQueueItem(\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context\n    )\n{\n    if (PhBeginInitOnce(&PhThreadProviderWorkQueueInitOnce))\n    {\n        PhInitializeWorkQueue(&PhThreadProviderWorkQueue, 0, 1, 1000);\n        PhEndInitOnce(&PhThreadProviderWorkQueueInitOnce);\n    }\n\n    PhQueueItemWorkQueue(&PhThreadProviderWorkQueue, Function, Context);\n}\n\nPPH_THREAD_PROVIDER PhCreateThreadProvider(\n    _In_ HANDLE ProcessId\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_THREAD_PROVIDER threadProvider;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhThreadProviderType = PhCreateObjectType(L\"ThreadProvider\", 0, PhpThreadProviderDeleteProcedure);\n        PhThreadItemType = PhCreateObjectType(L\"ThreadItem\", 0, PhpThreadItemDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    threadProvider = PhCreateObject(\n        PhEmGetObjectSize(EmThreadProviderType, sizeof(PH_THREAD_PROVIDER)),\n        PhThreadProviderType\n        );\n    memset(threadProvider, 0, sizeof(PH_THREAD_PROVIDER));\n\n    threadProvider->ThreadHashtable = PhCreateHashtable(\n        sizeof(PPH_THREAD_ITEM),\n        PhpThreadHashtableEqualFunction,\n        PhpThreadHashtableHashFunction,\n        20\n        );\n    PhInitializeFastLock(&threadProvider->ThreadHashtableLock);\n\n    PhInitializeCallback(&threadProvider->ThreadAddedEvent);\n    PhInitializeCallback(&threadProvider->ThreadModifiedEvent);\n    PhInitializeCallback(&threadProvider->ThreadRemovedEvent);\n    PhInitializeCallback(&threadProvider->UpdatedEvent);\n    PhInitializeCallback(&threadProvider->LoadingStateChangedEvent);\n\n    threadProvider->ProcessId = ProcessId;\n    threadProvider->SymbolProvider = PhCreateSymbolProvider(ProcessId);\n\n    if (threadProvider->SymbolProvider)\n    {\n        if (threadProvider->SymbolProvider->IsRealHandle)\n            threadProvider->ProcessHandle = threadProvider->SymbolProvider->ProcessHandle;\n    }\n\n    PhInitializeSListHead(&threadProvider->QueryListHead);\n    PhInitializeQueuedLock(&threadProvider->LoadSymbolsLock);\n\n    threadProvider->RunId = 1;\n    threadProvider->SymbolsLoadedRunId = 0; // Force symbols to be loaded the first time we try to resolve an address\n\n    PhEmCallObjectOperation(EmThreadProviderType, threadProvider, EmObjectCreate);\n\n    return threadProvider;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpThreadProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_THREAD_PROVIDER threadProvider = (PPH_THREAD_PROVIDER)Object;\n\n    PhEmCallObjectOperation(EmThreadProviderType, threadProvider, EmObjectDelete);\n\n    // Dereference all thread items (we referenced them\n    // when we added them to the hashtable).\n    PhDereferenceAllThreadItems(threadProvider);\n\n    PhDereferenceObject(threadProvider->ThreadHashtable);\n    PhDeleteFastLock(&threadProvider->ThreadHashtableLock);\n    PhDeleteCallback(&threadProvider->ThreadAddedEvent);\n    PhDeleteCallback(&threadProvider->ThreadModifiedEvent);\n    PhDeleteCallback(&threadProvider->ThreadRemovedEvent);\n    PhDeleteCallback(&threadProvider->UpdatedEvent);\n    PhDeleteCallback(&threadProvider->LoadingStateChangedEvent);\n\n    // Destroy all queue items.\n    {\n        PSLIST_ENTRY entry;\n        PPH_THREAD_QUERY_DATA data;\n\n        entry = RtlInterlockedFlushSList(&threadProvider->QueryListHead);\n\n        while (entry)\n        {\n            data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry);\n            entry = entry->Next;\n\n            PhClearReference(&data->StartAddressString);\n            PhClearReference(&data->ServiceName);\n            PhDereferenceObject(data->ThreadItem);\n            PhFree(data);\n        }\n    }\n\n    // We don't close the process handle because it is owned by the symbol provider.\n    if (threadProvider->SymbolProvider) PhDereferenceObject(threadProvider->SymbolProvider);\n}\n\nVOID PhRegisterThreadProvider(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _Out_ PPH_CALLBACK_REGISTRATION CallbackRegistration\n    )\n{\n    PhReferenceObject(ThreadProvider);\n    PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), PhpThreadProviderCallbackHandler, ThreadProvider, CallbackRegistration);\n}\n\nVOID PhUnregisterThreadProvider(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _In_ PPH_CALLBACK_REGISTRATION CallbackRegistration\n    )\n{\n    PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), CallbackRegistration);\n    PhDereferenceObject(ThreadProvider);\n}\n\nVOID PhSetTerminatingThreadProvider(\n    _Inout_ PPH_THREAD_PROVIDER ThreadProvider\n    )\n{\n    ThreadProvider->Terminating = TRUE;\n}\n\nVOID PhLoadSymbolsThreadProvider(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider\n    )\n{\n    ULONG64 runId;\n\n    PhAcquireQueuedLockExclusive(&ThreadProvider->LoadSymbolsLock);\n    runId = ThreadProvider->RunId;\n    PhLoadSymbolProviderOptions(ThreadProvider->SymbolProvider);\n\n    PhLoadSymbolProviderModules(\n        ThreadProvider->SymbolProvider,\n        ThreadProvider->ProcessId\n        );\n\n    ThreadProvider->SymbolsLoadedRunId = runId;\n    PhReleaseQueuedLockExclusive(&ThreadProvider->LoadSymbolsLock);\n}\n\nPPH_THREAD_ITEM PhCreateThreadItem(\n    _In_ CLIENT_ID ClientId\n    )\n{\n    PPH_THREAD_ITEM threadItem;\n\n    threadItem = PhCreateObject(\n        PhEmGetObjectSize(EmThreadItemType, sizeof(PH_THREAD_ITEM)),\n        PhThreadItemType\n        );\n    memset(threadItem, 0, sizeof(PH_THREAD_ITEM));\n    threadItem->ClientId = ClientId;\n\n    PhPrintUInt32(threadItem->ThreadIdString, HandleToUlong(ClientId.UniqueThread));\n    PhPrintUInt32IX(threadItem->ThreadIdHexString, HandleToUlong(ClientId.UniqueThread));\n\n    PhEmCallObjectOperation(EmThreadItemType, threadItem, EmObjectCreate);\n\n    return threadItem;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID PhpThreadItemDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_THREAD_ITEM threadItem = (PPH_THREAD_ITEM)Object;\n\n    PhEmCallObjectOperation(EmThreadItemType, threadItem, EmObjectDelete);\n\n    if (threadItem->ThreadHandle) NtClose(threadItem->ThreadHandle);\n    if (threadItem->StartAddressWin32String) PhDereferenceObject(threadItem->StartAddressWin32String);\n    if (threadItem->StartAddressWin32FileName) PhDereferenceObject(threadItem->StartAddressWin32FileName);\n    if (threadItem->ServiceName) PhDereferenceObject(threadItem->ServiceName);\n\n    if (!PhSystemProcessorInformation.SingleProcessorGroup)\n    {\n        if (threadItem->AffinityMaskGroups) PhFree(threadItem->AffinityMaskGroups);\n    }\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpThreadHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    return\n        (*(PPH_THREAD_ITEM *)Entry1)->ThreadId ==\n        (*(PPH_THREAD_ITEM *)Entry2)->ThreadId;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpThreadHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return HandleToUlong((*(PPH_THREAD_ITEM *)Entry)->ThreadId) / 4;\n}\n\nPPH_THREAD_ITEM PhReferenceThreadItem(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _In_ HANDLE ThreadId\n    )\n{\n    PH_THREAD_ITEM lookupThreadItem;\n    PPH_THREAD_ITEM lookupThreadItemPtr = &lookupThreadItem;\n    PPH_THREAD_ITEM *threadItemPtr;\n    PPH_THREAD_ITEM threadItem;\n\n    lookupThreadItem.ThreadId = ThreadId;\n\n    PhAcquireFastLockShared(&ThreadProvider->ThreadHashtableLock);\n\n    threadItemPtr = (PPH_THREAD_ITEM *)PhFindEntryHashtable(\n        ThreadProvider->ThreadHashtable,\n        &lookupThreadItemPtr\n        );\n\n    if (threadItemPtr)\n    {\n        threadItem = *threadItemPtr;\n        PhReferenceObject(threadItem);\n    }\n    else\n    {\n        threadItem = NULL;\n    }\n\n    PhReleaseFastLockShared(&ThreadProvider->ThreadHashtableLock);\n\n    return threadItem;\n}\n\nVOID PhDereferenceAllThreadItems(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider\n    )\n{\n    ULONG enumerationKey = 0;\n    PPH_THREAD_ITEM *threadItem;\n\n    PhAcquireFastLockExclusive(&ThreadProvider->ThreadHashtableLock);\n\n    while (PhEnumHashtable(ThreadProvider->ThreadHashtable, (PVOID *)&threadItem, &enumerationKey))\n    {\n        PhDereferenceObject(*threadItem);\n    }\n\n    PhReleaseFastLockExclusive(&ThreadProvider->ThreadHashtableLock);\n}\n\nVOID PhpRemoveThreadItem(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _In_ PPH_THREAD_ITEM ThreadItem\n    )\n{\n    PhRemoveEntryHashtable(ThreadProvider->ThreadHashtable, &ThreadItem);\n    PhDereferenceObject(ThreadItem);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpThreadQueryWorker(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_THREAD_QUERY_DATA data = (PPH_THREAD_QUERY_DATA)Parameter;\n    LONG newSymbolsLoading;\n\n    if (data->ThreadProvider->Terminating)\n        goto CleanupExit;\n\n    newSymbolsLoading = _InterlockedIncrement(&data->ThreadProvider->SymbolsLoading);\n\n    if (newSymbolsLoading == 1)\n        PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, UlongToPtr(TRUE));\n\n    if (data->ThreadProvider->SymbolsLoadedRunId == 0)\n        PhLoadSymbolsThreadProvider(data->ThreadProvider);\n\n    // Start address\n    {\n        if (data->ThreadItem->StartAddressWin32)\n        {\n            data->StartAddressWin32String = PhGetSymbolFromAddress(\n                data->ThreadProvider->SymbolProvider,\n                data->ThreadItem->StartAddressWin32,\n                &data->StartAddressWin32ResolveLevel,\n                &data->StartAddressWin32FileName,\n                NULL,\n                NULL\n                );\n\n            if (data->StartAddressWin32ResolveLevel == PhsrlAddress && data->ThreadProvider->SymbolsLoadedRunId < data->RunId)\n            {\n                // The process may have loaded new modules, so load symbols for those and try again.\n\n                PhLoadSymbolsThreadProvider(data->ThreadProvider);\n\n                PhClearReference(&data->StartAddressWin32String);\n                PhClearReference(&data->StartAddressWin32FileName);\n                data->StartAddressWin32String = PhGetSymbolFromAddress(\n                    data->ThreadProvider->SymbolProvider,\n                    data->ThreadItem->StartAddressWin32,\n                    &data->StartAddressWin32ResolveLevel,\n                    &data->StartAddressWin32FileName,\n                    NULL,\n                    NULL\n                    );\n            }\n        }\n\n        if (data->ThreadItem->StartAddress)\n        {\n            data->StartAddressString = PhGetSymbolFromAddress(\n                data->ThreadProvider->SymbolProvider,\n                data->ThreadItem->StartAddress,\n                &data->StartAddressResolveLevel,\n                &data->StartAddressFileName,\n                NULL,\n                NULL\n                );\n\n            if (data->StartAddressResolveLevel == PhsrlAddress && data->ThreadProvider->SymbolsLoadedRunId < data->RunId)\n            {\n                // The process may have loaded new modules, so load symbols for those and try again.\n\n                PhLoadSymbolsThreadProvider(data->ThreadProvider);\n\n                PhClearReference(&data->StartAddressString);\n                PhClearReference(&data->StartAddressFileName);\n                data->StartAddressString = PhGetSymbolFromAddress(\n                    data->ThreadProvider->SymbolProvider,\n                    data->ThreadItem->StartAddress,\n                    &data->StartAddressResolveLevel,\n                    &data->StartAddressFileName,\n                    NULL,\n                    NULL\n                    );\n            }\n        }\n    }\n\n    newSymbolsLoading = _InterlockedDecrement(&data->ThreadProvider->SymbolsLoading);\n\n    if (newSymbolsLoading == 0)\n        PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, UlongToPtr(FALSE));\n\n    // Check if the process has services - we'll need to know before getting service tag/name\n    // information.\n    if (!data->ThreadProvider->HasServicesKnown)\n    {\n        PPH_PROCESS_ITEM processItem;\n\n        if (processItem = PhReferenceProcessItem(data->ThreadProvider->ProcessId))\n        {\n            data->ThreadProvider->HasServices = processItem->ServiceList && processItem->ServiceList->Count != 0;\n            PhDereferenceObject(processItem);\n        }\n\n        data->ThreadProvider->HasServicesKnown = TRUE;\n    }\n\n    // Get the service tag, and the service name.\n    if (data->ThreadItem->ThreadHandle)\n    {\n        PVOID serviceTag;\n\n        if (NT_SUCCESS(PhGetThreadServiceTag(\n            data->ThreadItem->ThreadHandle,\n            data->ThreadProvider->ProcessHandle,\n            &serviceTag\n            )))\n        {\n            data->ServiceName = PhGetServiceNameFromTag(\n                data->ThreadProvider->ProcessId,\n                serviceTag\n                );\n        }\n    }\n\nCleanupExit:\n    RtlInterlockedPushEntrySList(&data->ThreadProvider->QueryListHead, &data->ListEntry);\n    PhDereferenceObject(data->ThreadProvider);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpQueueThreadQuery(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _In_ PPH_THREAD_ITEM ThreadItem\n    )\n{\n    PPH_THREAD_QUERY_DATA data;\n\n    data = PhAllocateZero(sizeof(PH_THREAD_QUERY_DATA));\n    PhSetReference(&data->ThreadProvider, ThreadProvider);\n    PhSetReference(&data->ThreadItem, ThreadItem);\n    data->RunId = ThreadProvider->RunId;\n\n    PhpQueueThreadWorkQueueItem(PhpThreadQueryWorker, data);\n}\n\nPPH_STRING PhpGetThreadBasicStartAddress(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _In_ PVOID Address,\n    _Out_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel\n    )\n{\n    PVOID modBase;\n    PPH_STRING fileName = NULL;\n    PPH_STRING baseName = NULL;\n    PPH_STRING symbol;\n\n    modBase = PhGetModuleFromAddress(\n        ThreadProvider->SymbolProvider,\n        Address,\n        &fileName\n        );\n\n    if (fileName == NULL)\n    {\n        *ResolveLevel = PhsrlAddress;\n\n        symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR));\n        PhPrintPointer(symbol->Buffer, Address);\n        PhTrimToNullTerminatorString(symbol);\n    }\n    else\n    {\n        PH_FORMAT format[3];\n\n        baseName = PhGetBaseName(fileName);\n        *ResolveLevel = PhsrlModule;\n\n        PhInitFormatSR(&format[0], baseName->sr);\n        PhInitFormatS(&format[1], L\"+0x\");\n        PhInitFormatIX(&format[2], (ULONG_PTR)Address - (ULONG_PTR)modBase);\n\n        symbol = PhFormat(format, 3, baseName->Length + 6 + 32);\n    }\n\n    if (fileName)\n        PhDereferenceObject(fileName);\n    if (baseName)\n        PhDereferenceObject(baseName);\n\n    return symbol;\n}\n\nstatic NTSTATUS PhThreadProviderOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ PPH_THREAD_ITEM ThreadItem\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n\n    if (ThreadItem->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n    {\n        if (HandleToUlong(ThreadItem->ThreadId) < PhSystemProcessorInformation.NumberOfProcessors)\n            return STATUS_UNSUCCESSFUL;\n    }\n\n    status = PhOpenThreadClientId(\n        &threadHandle,\n        THREAD_QUERY_INFORMATION,\n        &ThreadItem->ClientId\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        status = PhOpenThreadClientId(\n            &threadHandle,\n            THREAD_QUERY_LIMITED_INFORMATION,\n            &ThreadItem->ClientId\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *ThreadHandle = threadHandle;\n    }\n\n    return status;\n}\n\nstatic NTSTATUS PhpGetThreadCycleTime(\n    _In_ PPH_THREAD_ITEM ThreadItem,\n    _Out_ PULONG64 CycleTime\n    )\n{\n    if (ThreadItem->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n    {\n        if (HandleToUlong(ThreadItem->ThreadId) < PhSystemProcessorInformation.NumberOfProcessors)\n        {\n            *CycleTime = PhCpuIdleCycleTime[HandleToUlong(ThreadItem->ThreadId)].CycleTime;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    if (ThreadItem->ThreadHandle)\n    {\n        return PhGetThreadCycleTime(ThreadItem->ThreadHandle, CycleTime);\n    }\n\n    return STATUS_INVALID_PARAMETER;\n}\n\nPCPH_STRINGREF PhGetBasePrioritySymbolicString(\n    _In_ KPRIORITY BasePriority\n    )\n{\n    static const PH_STRINGREF errorReturn = PH_STRINGREF_INIT(L\"\");\n    static const PH_STRINGREF realTime = PH_STRINGREF_INIT(L\"Real-time\");\n    static const PH_STRINGREF idle = PH_STRINGREF_INIT(L\"Idle\");\n    static const PH_STRINGREF background = PH_STRINGREF_INIT(L\"Background\");\n    static const PH_STRINGREF timeCritical = PH_STRINGREF_INIT(L\"Time critical\");\n    static const PH_STRINGREF highest = PH_STRINGREF_INIT(L\"Highest\");\n    static const PH_STRINGREF aboveNormal = PH_STRINGREF_INIT(L\"Above normal\");\n    static const PH_STRINGREF normal = PH_STRINGREF_INIT(L\"Normal\");\n    static const PH_STRINGREF belowNormal = PH_STRINGREF_INIT(L\"Below normal\");\n    static const PH_STRINGREF lowest = PH_STRINGREF_INIT(L\"Lowest\");\n\n    if (BasePriority == THREAD_PRIORITY_ERROR_RETURN)\n        return &errorReturn;\n\n    //\n    // N.B. This check is > 16 despite 16 being a real-time priority since\n    // requesting THREAD_PRIORITY_TIME_CRITICAL actually sets the base priority\n    // to the saturation value of LOW_REALTIME_PRIORITY. (jxy-s)\n    //\n    if (BasePriority > LOW_REALTIME_PRIORITY)      // 16\n        return &realTime;\n\n    if (BasePriority <= THREAD_BASE_PRIORITY_IDLE) // -15\n        return &idle;\n\n    if (BasePriority < THREAD_BASE_PRIORITY_MIN)   // -2\n        return &background;\n\n    if (BasePriority > THREAD_BASE_PRIORITY_MAX)   // 2\n        return &timeCritical;\n\n    switch (BasePriority)\n    {\n    case THREAD_PRIORITY_HIGHEST:                  // 2\n        return &highest;\n    case THREAD_PRIORITY_ABOVE_NORMAL:             // 1\n        return &aboveNormal;\n    case THREAD_PRIORITY_NORMAL:                   // 0\n        return &normal;\n    case THREAD_PRIORITY_BELOW_NORMAL:             // -1\n        return &belowNormal;\n    case THREAD_PRIORITY_LOWEST:                   // -2\n        return &lowest;\n    DEFAULT_UNREACHABLE;\n    }\n}\n\nVOID PhThreadProviderInitialUpdate(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider\n    )\n{\n    PVOID processes;\n\n    if (NT_SUCCESS(PhEnumProcesses(&processes)))\n    {\n        PhpThreadProviderUpdate(ThreadProvider, processes);\n        PhFree(processes);\n    }\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhpThreadProviderCallbackHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Context && PhProcessInformation)\n    {\n        PhpThreadProviderUpdate((PPH_THREAD_PROVIDER)Context, PhProcessInformation);\n    }\n}\n\nVOID PhpThreadProviderUpdate(\n    _In_ PPH_THREAD_PROVIDER ThreadProvider,\n    _In_ PVOID ProcessInformation\n    )\n{\n    PPH_THREAD_PROVIDER threadProvider = ThreadProvider;\n    PSYSTEM_PROCESS_INFORMATION process;\n    SYSTEM_PROCESS_INFORMATION localProcess;\n    PSYSTEM_THREAD_INFORMATION threads;\n    ULONG numberOfThreads;\n    ULONG i;\n\n    process = PhFindProcessInformation(ProcessInformation, threadProvider->ProcessId);\n\n    if (!process)\n    {\n        // The process doesn't exist anymore. Pretend it does but has no threads.\n        process = &localProcess;\n        process->NumberOfThreads = 0;\n\n        //\n        // We want dbghelp.dll to release the symbol files so that the exited process symbols can\n        // be rebuilt. This is most common for developers building, inspecting with system informer,\n        // then rebuilding without closing the process properties dialog.\n        //\n        // There are downstream dependencies on the symbol provider and the process handle from it,\n        // so we can't just dereference it immediately here.\n        //\n        // PhUnregisterSymbolProvider will unregister this symbol provider from dbghelp.dll which\n        // will get it to release the symbol files. This gives us the desired result without\n        // breaking downstream logic. The consequence is that symbol resolution downstream will\n        // fail cleanly, but it shouldn't matter in this path as it relies on being able to query\n        // information about the process threads, which no longer exist.\n        //\n        if (threadProvider->SymbolProvider)\n            PhUnregisterSymbolProvider(threadProvider->SymbolProvider);\n    }\n\n    threads = process->Threads;\n    numberOfThreads = process->NumberOfThreads;\n\n    // System Idle Process has one thread per CPU. They all have a TID of 0. We can't have duplicate\n    // TIDs, so we'll assign unique TIDs. (wj32)\n    if (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID)\n    {\n        ULONG processorIndex = 0;\n\n        for (i = 0; i < numberOfThreads; i++)\n        {\n            if (!threads[i].ClientId.UniqueThread)\n            {\n                threads[i].ClientId.UniqueThread = UlongToHandle(processorIndex);\n                processorIndex++;\n            }\n        }\n    }\n\n    // Look for dead threads.\n    {\n        PPH_LIST threadsToRemove = NULL;\n        ULONG enumerationKey = 0;\n        PPH_THREAD_ITEM *threadItem;\n\n        while (PhEnumHashtable(threadProvider->ThreadHashtable, (PVOID *)&threadItem, &enumerationKey))\n        {\n            BOOLEAN found = FALSE;\n\n            // Check if the thread still exists.\n            for (i = 0; i < numberOfThreads; i++)\n            {\n                PSYSTEM_THREAD_INFORMATION thread = &threads[i];\n\n                if ((*threadItem)->ThreadId == thread->ClientId.UniqueThread)\n                {\n                    found = TRUE;\n                    break;\n                }\n            }\n\n            if (!found)\n            {\n                // Raise the thread removed event.\n                PhInvokeCallback(&threadProvider->ThreadRemovedEvent, *threadItem);\n\n                if (!threadsToRemove)\n                    threadsToRemove = PhCreateList(2);\n\n                PhAddItemList(threadsToRemove, *threadItem);\n            }\n        }\n\n        if (threadsToRemove)\n        {\n            PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock);\n\n            for (i = 0; i < threadsToRemove->Count; i++)\n            {\n                PhpRemoveThreadItem(\n                    threadProvider,\n                    (PPH_THREAD_ITEM)threadsToRemove->Items[i]\n                    );\n            }\n\n            PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock);\n            PhDereferenceObject(threadsToRemove);\n        }\n    }\n\n    // Go through the queued thread query data.\n    {\n        PSLIST_ENTRY entry;\n        PPH_THREAD_QUERY_DATA data;\n\n        entry = RtlInterlockedFlushSList(&threadProvider->QueryListHead);\n\n        while (entry)\n        {\n            data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry);\n            entry = entry->Next;\n\n            if (data->StartAddressWin32ResolveLevel == PhsrlFunction && data->StartAddressWin32String)\n            {\n                PhSwapReference(&data->ThreadItem->StartAddressWin32String, data->StartAddressWin32String);\n                PhSwapReference(&data->ThreadItem->StartAddressWin32FileName, data->StartAddressWin32FileName);\n                data->ThreadItem->StartAddressWin32ResolveLevel = data->StartAddressWin32ResolveLevel;\n            }\n\n            if (data->StartAddressResolveLevel == PhsrlFunction && data->StartAddressString)\n            {\n                PhSwapReference(&data->ThreadItem->StartAddressString, data->StartAddressString);\n                PhSwapReference(&data->ThreadItem->StartAddressFileName, data->StartAddressFileName);\n                data->ThreadItem->StartAddressResolveLevel = data->StartAddressResolveLevel;\n            }\n\n            PhMoveReference(&data->ThreadItem->ServiceName, data->ServiceName);\n\n            data->ThreadItem->JustResolved = TRUE;\n\n            if (data->StartAddressWin32String) PhDereferenceObject(data->StartAddressWin32String);\n            if (data->StartAddressWin32FileName) PhDereferenceObject(data->StartAddressWin32FileName);\n            if (data->StartAddressString) PhDereferenceObject(data->StartAddressString);\n            if (data->StartAddressFileName) PhDereferenceObject(data->StartAddressFileName);\n            PhDereferenceObject(data->ThreadItem);\n            PhFree(data);\n        }\n    }\n\n    // Look for new threads and update existing ones.\n    for (i = 0; i < numberOfThreads; i++)\n    {\n        PSYSTEM_THREAD_INFORMATION thread = &threads[i];\n        PPH_THREAD_ITEM threadItem;\n        THREAD_BASIC_INFORMATION basicInfo;\n\n        threadItem = PhReferenceThreadItem(threadProvider, thread->ClientId.UniqueThread);\n\n        if (!threadItem)\n        {\n            threadItem = PhCreateThreadItem(thread->ClientId);\n            threadItem->KernelTime = thread->KernelTime;\n            PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart);\n            threadItem->UserTime = thread->UserTime;\n            PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart);\n            threadItem->CreateTime = thread->CreateTime;\n            threadItem->StartAddress = thread->StartAddress;\n            threadItem->Priority = thread->Priority;\n            threadItem->ActualBasePriority = thread->BasePriority;\n            PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches);\n            threadItem->State = thread->ThreadState;\n            threadItem->WaitReason = thread->WaitReason;\n\n            {\n                NTSTATUS status;\n                HANDLE threadHandle;\n\n                status = PhThreadProviderOpenThread(\n                    &threadHandle,\n                    threadItem\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    threadItem->ThreadHandle = threadHandle;\n                }\n\n                threadItem->ThreadHandleStatus = threadItem->StartAddressStatus = status;\n            }\n\n            // Get the cycle count.\n            if (threadItem->ThreadHandle)\n            {\n                ULONG64 cycleTime;\n\n                if (NT_SUCCESS(PhGetThreadCycleTime(\n                    threadItem->ThreadHandle,\n                    &cycleTime\n                    )))\n                {\n                    PhUpdateDelta(&threadItem->CyclesDelta, cycleTime);\n                }\n            }\n\n            // Get the start address.\n\n            if (threadItem->ThreadHandle)\n            {\n                NTSTATUS status;\n                ULONG_PTR startAddress;\n\n                status = PhGetThreadStartAddress(\n                    threadItem->ThreadHandle,\n                    &startAddress\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    threadItem->StartAddressWin32 = (PVOID)startAddress;\n                }\n\n                threadItem->StartAddressStatus = status;\n            }\n\n            // Get the base priority increment (relative to the process priority).\n            if (threadItem->ThreadHandle && NT_SUCCESS(PhGetThreadBasicInformation(\n                threadItem->ThreadHandle,\n                &basicInfo\n                )))\n            {\n                threadItem->BasePriority = basicInfo.BasePriority;\n            }\n            else\n            {\n                threadItem->BasePriority = THREAD_PRIORITY_ERROR_RETURN;\n            }\n\n            // Affinity\n            {\n                ULONG affinityPopulationCount = 0;\n\n                if (PhSystemProcessorInformation.SingleProcessorGroup)\n                {\n                    KAFFINITY affinityMask;\n\n                    if (threadItem->ThreadHandle &&\n                        NT_SUCCESS(PhGetThreadAffinityMask(threadItem->ThreadHandle, &affinityMask)))\n                    {\n                        threadItem->AffinityMaskSingle = affinityMask;\n                    }\n                    else\n                    {\n                        threadItem->AffinityMaskSingle = PhSystemProcessorInformation.ActiveProcessorsAffinityMasks[0];\n                    }\n\n                    affinityPopulationCount = PhCountBitsUlongPtr(threadItem->AffinityMaskSingle);\n                }\n                else\n                {\n                    GROUP_AFFINITY affinity;\n\n                    threadItem->AffinityMaskGroups = PhAllocateZero(sizeof(KAFFINITY) * PhSystemProcessorInformation.NumberOfProcessorGroups);\n\n                    for (USHORT j = 0; j < PhSystemProcessorInformation.NumberOfProcessorGroups; j++)\n                    {\n                        RtlZeroMemory(&affinity, sizeof(GROUP_AFFINITY));\n                        affinity.Group = j;\n\n                        if (threadItem->ThreadHandle &&\n                            NT_SUCCESS(PhGetThreadGroupAffinity(threadItem->ThreadHandle, &affinity)))\n                        {\n                            threadItem->AffinityMaskGroups[j] = affinity.Mask;\n                        }\n                        else\n                        {\n                            threadItem->AffinityMaskGroups[j] = PhSystemProcessorInformation.ActiveProcessorsAffinityMasks[j];\n                        }\n\n                        affinityPopulationCount += PhCountBitsUlongPtr(threadItem->AffinityMaskGroups[j]);\n                    }\n                }\n\n                threadItem->AffinityPopulationCount = affinityPopulationCount;\n            }\n\n            // Start address\n            {\n                // Win32\n                if (threadProvider->SymbolsLoadedRunId != 0 && threadItem->StartAddressWin32)\n                {\n                    threadItem->StartAddressWin32String = PhpGetThreadBasicStartAddress(\n                        threadProvider,\n                        threadItem->StartAddressWin32,\n                        &threadItem->StartAddressWin32ResolveLevel\n                        );\n                }\n\n                if (PhIsNullOrEmptyString(threadItem->StartAddressWin32String) && threadItem->StartAddressWin32)\n                {\n                    threadItem->StartAddressWin32ResolveLevel = PhsrlAddress;\n                    threadItem->StartAddressWin32String = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR));\n                    PhPrintPointer(\n                        threadItem->StartAddressWin32String->Buffer,\n                        threadItem->StartAddressWin32\n                        );\n                    PhTrimToNullTerminatorString(threadItem->StartAddressWin32String);\n                }\n\n                // Native\n                if (threadProvider->SymbolsLoadedRunId != 0 && threadItem->StartAddress)\n                {\n                    threadItem->StartAddressString = PhpGetThreadBasicStartAddress(\n                        threadProvider,\n                        threadItem->StartAddress,\n                        &threadItem->StartAddressResolveLevel\n                        );\n                }\n\n                if (PhIsNullOrEmptyString(threadItem->StartAddressString) && threadItem->StartAddress)\n                {\n                    threadItem->StartAddressResolveLevel = PhsrlAddress;\n                    threadItem->StartAddressString = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR));\n                    PhPrintPointer(\n                        threadItem->StartAddressString->Buffer,\n                        threadItem->StartAddress\n                        );\n                    PhTrimToNullTerminatorString(threadItem->StartAddressString);\n                }\n            }\n\n            // Is it a GUI thread?\n            if (threadItem->ThreadId)\n            {\n                threadItem->IsGuiThread = PhGetThreadWin32Thread(threadItem->ThreadId);\n            }\n\n            if (WindowsVersion >= WINDOWS_10_22H2 && threadItem->ThreadHandle)\n            {\n                if (KsiLevel() >= KphLevelMed) // threadItem->IsSubsystemProcess\n                {\n                    ULONG lxssThreadId;\n\n                    if (NT_SUCCESS(KphQueryInformationThread(\n                        threadItem->ThreadHandle,\n                        KphThreadWSLThreadId,\n                        &lxssThreadId,\n                        sizeof(ULONG),\n                        NULL\n                        )))\n                    {\n                        threadItem->LxssThreadId = lxssThreadId;\n                        PhPrintUInt32(threadItem->LxssThreadIdString, lxssThreadId);\n                    }\n                }\n            }\n\n            if (WindowsVersion >= WINDOWS_11_22H2 && threadItem->ThreadHandle)\n            {\n                POWER_THROTTLING_THREAD_STATE powerThrottlingState;\n\n                if (NT_SUCCESS(PhGetThreadPowerThrottlingState(threadItem->ThreadHandle, &powerThrottlingState)))\n                {\n                    if (powerThrottlingState.ControlMask & POWER_THROTTLING_THREAD_EXECUTION_SPEED &&\n                        powerThrottlingState.StateMask & POWER_THROTTLING_THREAD_EXECUTION_SPEED)\n                    {\n                        threadItem->PowerThrottling = TRUE;\n                    }\n                }\n            }\n\n            PhpQueueThreadQuery(threadProvider, threadItem);\n\n            // Add the thread item to the hashtable.\n            PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock);\n            PhAddEntryHashtable(threadProvider->ThreadHashtable, &threadItem);\n            PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock);\n\n            // Raise the thread added event.\n            PhInvokeCallback(&threadProvider->ThreadAddedEvent, threadItem);\n        }\n        else\n        {\n            BOOLEAN modified = FALSE;\n\n            if (threadItem->JustResolved)\n                modified = TRUE;\n\n            threadItem->KernelTime = thread->KernelTime;\n            threadItem->UserTime = thread->UserTime;\n            threadItem->State = thread->ThreadState;\n            threadItem->WaitTime = thread->WaitTime;\n\n            if (threadItem->Priority != thread->Priority)\n            {\n                threadItem->Priority = thread->Priority;\n                modified = TRUE;\n            }\n\n            if (threadItem->ActualBasePriority != thread->BasePriority)\n            {\n                threadItem->ActualBasePriority = thread->BasePriority;\n                modified = TRUE;\n            }\n\n            if (threadItem->WaitReason != thread->WaitReason)\n            {\n                threadItem->WaitReason = thread->WaitReason;\n                modified = TRUE;\n            }\n\n            {\n                // If the resolve level is only at address, it probably\n                // means symbols weren't loaded the last time we\n                // tried to get the start address. Try again.\n                if (threadItem->StartAddressWin32ResolveLevel == PhsrlAddress)\n                {\n                    if (threadProvider->SymbolsLoadedRunId != 0 && threadItem->StartAddressWin32)\n                    {\n                        PPH_STRING newStartAddressString;\n\n                        newStartAddressString = PhpGetThreadBasicStartAddress(\n                            threadProvider,\n                            threadItem->StartAddressWin32,\n                            &threadItem->StartAddressWin32ResolveLevel\n                            );\n\n                        PhMoveReference(\n                            &threadItem->StartAddressWin32String,\n                            newStartAddressString\n                            );\n\n                        modified = TRUE;\n                    }\n                }\n\n                if (threadItem->StartAddressResolveLevel == PhsrlAddress)\n                {\n                    if (threadProvider->SymbolsLoadedRunId != 0 && threadItem->StartAddress)\n                    {\n                        PPH_STRING newStartAddressString;\n\n                        newStartAddressString = PhpGetThreadBasicStartAddress(\n                            threadProvider,\n                            threadItem->StartAddress,\n                            &threadItem->StartAddressResolveLevel\n                            );\n\n                        PhMoveReference(\n                            &threadItem->StartAddressString,\n                            newStartAddressString\n                            );\n\n                        modified = TRUE;\n                    }\n                }\n\n                // If we couldn't resolve the start address to a module+offset, use the StartAddress\n                // instead of the Win32StartAddress and try again. Note that we check the resolve level\n                // again because we may have changed it in the previous block.\n                if (threadItem->JustResolved &&\n                    threadItem->StartAddressResolveLevel == PhsrlAddress)\n                {\n                    if (threadItem->StartAddress != thread->StartAddress)\n                    {\n                        threadItem->StartAddress = thread->StartAddress;\n                        PhpQueueThreadQuery(threadProvider, threadItem);\n                    }\n                }\n            }\n\n            // Update the context switch count.\n            {\n                ULONG oldDelta;\n\n                oldDelta = threadItem->ContextSwitchesDelta.Delta;\n                PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches);\n\n                if (threadItem->ContextSwitchesDelta.Delta != oldDelta)\n                {\n                    modified = TRUE;\n                }\n            }\n\n            // Update the cycle count.\n            {\n                ULONG64 cycles;\n                ULONG64 oldDelta;\n\n                oldDelta = threadItem->CyclesDelta.Delta;\n\n                if (NT_SUCCESS(PhpGetThreadCycleTime(\n                    threadItem,\n                    &cycles\n                    )))\n                {\n                    PhUpdateDelta(&threadItem->CyclesDelta, cycles);\n\n                    if (threadItem->CyclesDelta.Delta != oldDelta)\n                    {\n                        modified = TRUE;\n                    }\n                }\n            }\n\n            // Update the CPU time deltas.\n            PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart);\n            PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart);\n\n            // Update the CPU usage.\n            // If the cycle time isn't available, we'll fall back to using the CPU time.\n            //if (PhEnableCycleCpuUsage && (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID || threadItem->ThreadHandle))\n            //{\n            //    threadItem->CpuUsage = (FLOAT)threadItem->CyclesDelta.Delta / PhCpuTotalCycleDelta;\n            //}\n            //else\n            //{\n            //    threadItem->CpuUsage = (FLOAT)(threadItem->CpuKernelDelta.Delta + threadItem->CpuUserDelta.Delta) /\n            //        (PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta);\n            //}\n\n            // Update the CPU user/kernel usage (based on the same code from procprv.c) (dmex)\n            {\n                FLOAT newCpuUsage;\n                FLOAT kernelCpuUsage;\n                FLOAT userCpuUsage;\n                ULONG64 totalTime;\n\n                if (PhEnableCycleCpuUsage)\n                {\n                    ULONG64 totalDelta;\n\n                    if (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID || threadItem->ThreadHandle)\n                    {\n                        newCpuUsage = (FLOAT)threadItem->CyclesDelta.Delta / PhCpuTotalCycleDelta;\n                    }\n                    else\n                    {\n                        totalTime = PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta;\n                        newCpuUsage = (FLOAT)(threadItem->CpuKernelDelta.Delta + threadItem->CpuUserDelta.Delta) / totalTime;\n                    }\n\n                    totalDelta = (threadItem->CpuKernelDelta.Delta + threadItem->CpuUserDelta.Delta);\n\n                    if (totalDelta != 0)\n                    {\n                        kernelCpuUsage = newCpuUsage * (FLOAT)threadItem->CpuKernelDelta.Delta / totalDelta;\n                        userCpuUsage = newCpuUsage * (FLOAT)threadItem->CpuUserDelta.Delta / totalDelta;\n                    }\n                    else\n                    {\n                        if (threadItem->UserTime.QuadPart != 0)\n                        {\n                            kernelCpuUsage = newCpuUsage / 2;\n                            userCpuUsage = newCpuUsage / 2;\n                        }\n                        else\n                        {\n                            kernelCpuUsage = newCpuUsage;\n                            userCpuUsage = 0;\n                        }\n                    }\n                }\n                else\n                {\n                    totalTime = PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta;\n                    kernelCpuUsage = (FLOAT)threadItem->CpuKernelDelta.Delta / totalTime;\n                    userCpuUsage = (FLOAT)threadItem->CpuUserDelta.Delta / totalTime;\n                    newCpuUsage = kernelCpuUsage + userCpuUsage;\n                }\n\n                threadItem->CpuUsage = newCpuUsage;\n                threadItem->CpuKernelUsage = kernelCpuUsage;\n                threadItem->CpuUserUsage = userCpuUsage;\n            }\n\n            // Update the base priority.\n            {\n                KPRIORITY oldBasePriorityIncrement = threadItem->BasePriority;\n\n                if (threadItem->ThreadHandle && NT_SUCCESS(PhGetThreadBasicInformation(\n                    threadItem->ThreadHandle,\n                    &basicInfo\n                    )))\n                {\n                    threadItem->BasePriority = basicInfo.BasePriority;\n                }\n                else\n                {\n                    threadItem->BasePriority = THREAD_PRIORITY_ERROR_RETURN;\n                }\n\n                if (threadItem->BasePriority != oldBasePriorityIncrement)\n                {\n                    modified = TRUE;\n                }\n            }\n\n            // Affinity\n            {\n                ULONG affinityPopulationCount = 0;\n\n                if (PhSystemProcessorInformation.SingleProcessorGroup)\n                {\n                    KAFFINITY affinityMask;\n\n                    if (threadItem->ThreadHandle &&\n                        NT_SUCCESS(PhGetThreadAffinityMask(threadItem->ThreadHandle, &affinityMask)))\n                    {\n                        threadItem->AffinityMaskSingle = affinityMask;\n                    }\n                    else\n                    {\n                        threadItem->AffinityMaskSingle = PhSystemProcessorInformation.ActiveProcessorsAffinityMasks[0];\n                    }\n\n                    affinityPopulationCount = PhCountBitsUlongPtr(threadItem->AffinityMaskSingle);\n                }\n                else\n                {\n                    for (USHORT j = 0; j < PhSystemProcessorInformation.NumberOfProcessorGroups; j++)\n                    {\n                        GROUP_AFFINITY affinity;\n\n                        RtlZeroMemory(&affinity, sizeof(GROUP_AFFINITY));\n                        affinity.Group = j;\n\n                        if (threadItem->ThreadHandle &&\n                            NT_SUCCESS(PhGetThreadGroupAffinity(threadItem->ThreadHandle, &affinity)))\n                        {\n                            threadItem->AffinityMaskGroups[j] = affinity.Mask;\n                        }\n                        else\n                        {\n                            threadItem->AffinityMaskGroups[j] = PhSystemProcessorInformation.ActiveProcessorsAffinityMasks[j];\n                        }\n\n                        affinityPopulationCount += PhCountBitsUlongPtr(threadItem->AffinityMaskGroups[j]);\n                    }\n                }\n\n                if (threadItem->AffinityPopulationCount != affinityPopulationCount)\n                {\n                    threadItem->AffinityPopulationCount = affinityPopulationCount;\n                    modified = TRUE;\n                }\n            }\n\n            // Update the GUI thread status.\n            if (threadItem->ThreadId)\n            {\n                GUITHREADINFO info = { sizeof(GUITHREADINFO) };\n                BOOLEAN oldIsGuiThread = threadItem->IsGuiThread;\n\n                threadItem->IsGuiThread = !!GetGUIThreadInfo(HandleToUlong(threadItem->ThreadId), &info);\n\n                if (threadItem->IsGuiThread != oldIsGuiThread)\n                    modified = TRUE;\n            }\n\n            if (!threadItem->ThreadHandle || KsiLevel() < KphLevelMed ||\n                !NT_SUCCESS(KphQueryInformationThread(\n                    threadItem->ThreadHandle,\n                    KphThreadIoCounters,\n                    &threadItem->IoCounters,\n                    sizeof(IO_COUNTERS),\n                    NULL\n                    )))\n            {\n                RtlZeroMemory(&threadItem->IoCounters, sizeof(IO_COUNTERS));\n            }\n\n            threadItem->JustResolved = FALSE;\n\n            if (modified)\n            {\n                // Raise the thread modified event.\n                PhInvokeCallback(&threadProvider->ThreadModifiedEvent, threadItem);\n            }\n\n            PhDereferenceObject(threadItem);\n        }\n    }\n\n    PhInvokeCallback(&threadProvider->UpdatedEvent, NULL);\n    threadProvider->RunId++;\n}\n"
  },
  {
    "path": "SystemInformer/thrdstk.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <phapp.h>\n#include <phsettings.h>\n\n#include <cpysave.h>\n#include <emenu.h>\n#include <kphuser.h>\n#include <ksisup.h>\n#include <symprv.h>\n\n#include <actions.h>\n#include <colmgr.h>\n#include <phplug.h>\n#include <settings.h>\n#include <thrdprv.h>\n\n#define WM_PH_COMPLETED (WM_APP + 301)\n//#define WM_PH_STATUS_UPDATE (WM_APP + 302)\n#define WM_PH_SHOWSTACKMENU (WM_APP + 303)\n#define WM_PH_SHOWSTACKDEFAULT (WM_APP + 304)\n\nstatic PPH_OBJECT_TYPE PhThreadStackContextType = NULL;\nstatic RECT MinimumSize = { -1, -1, -1, -1 };\n\ntypedef struct _PH_THREAD_STACK_CONTEXT\n{\n    HANDLE ProcessId;\n    HANDLE ThreadId;\n    HANDLE ThreadHandle;\n    PPH_THREAD_PROVIDER ThreadProvider;\n    PPH_SYMBOL_PROVIDER SymbolProvider;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG CustomWalk : 1;\n            ULONG StopWalk : 1;\n            ULONG EnableCloseDialog : 1;\n            ULONG HighlightSystemPages : 1;\n            ULONG HighlightUserPages : 1;\n            ULONG HideSystemPages : 1;\n            ULONG HideUserPages : 1;\n            ULONG HighlightInlineFrames : 1;\n            ULONG HideInlineFrames : 1;\n            ULONG Spare : 23;\n        };\n    };\n\n    PPH_LIST List;\n    PPH_LIST NewList;\n    PH_TN_FILTER_SUPPORT TreeFilterSupport;\n    PPH_TN_FILTER_ENTRY TreeFilterEntry;\n\n    HWND TaskDialogHandle;\n\n    NTSTATUS WalkStatus;\n    PPH_STRING StatusMessage;\n    PPH_STRING StatusContent;\n    PH_QUEUED_LOCK StatusLock;\n\n    BOOLEAN SymbolProgressMarquee;\n    BOOLEAN SymbolProgressReset;\n    ULONG SymbolProgress;\n\n    PH_LAYOUT_MANAGER LayoutManager;\n\n    HWND WindowHandle;\n    HWND ParentHandle;\n    HWND TreeNewHandle;\n    ULONG TreeNewSortColumn;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PPH_HASHTABLE NodeHashtable;\n    PPH_LIST NodeList;\n    PPH_LIST NodeRootList;\n    WNDPROC ThreadStackStatusDefaultWindowProc;\n    PH_CALLBACK_REGISTRATION SymbolProviderEventRegistration;\n} PH_THREAD_STACK_CONTEXT, *PPH_THREAD_STACK_CONTEXT;\n\ntypedef struct _THREAD_STACK_ITEM\n{\n    PH_THREAD_STACK_FRAME StackFrame;\n    ULONG Index;\n    PPH_STRING Symbol;\n    PPH_STRING FileName;\n    PPH_STRING LineText;\n} THREAD_STACK_ITEM, *PTHREAD_STACK_ITEM;\n\ntypedef enum _PH_STACK_TREE_COLUMN_ITEM_NAME\n{\n    PH_STACK_TREE_COLUMN_INDEX,\n    PH_STACK_TREE_COLUMN_SYMBOL,\n    PH_STACK_TREE_COLUMN_STACKADDRESS,\n    PH_STACK_TREE_COLUMN_FRAMEADDRESS,\n    PH_STACK_TREE_COLUMN_PARAMETER1,\n    PH_STACK_TREE_COLUMN_PARAMETER2,\n    PH_STACK_TREE_COLUMN_PARAMETER3,\n    PH_STACK_TREE_COLUMN_PARAMETER4,\n    PH_STACK_TREE_COLUMN_CONTROLADDRESS,\n    PH_STACK_TREE_COLUMN_RETURNADDRESS,\n    PH_STACK_TREE_COLUMN_FILENAME,\n    PH_STACK_TREE_COLUMN_LINETEXT,\n    PH_STACK_TREE_COLUMN_ARCHITECTURE,\n    PH_STACK_TREE_COLUMN_FRAMEDISTANCE,\n    TREE_COLUMN_ITEM_MAXIMUM\n} PH_STACK_TREE_COLUMN_ITEM_NAME;\n\ntypedef struct _PH_STACK_TREE_ROOT_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PH_THREAD_STACK_FRAME StackFrame;\n\n    ULONG Index;\n    ULONG FrameDistance;\n    PPH_STRING TooltipText;\n    PPH_STRING IndexString;\n    PPH_STRING SymbolString;\n    PPH_STRING FileNameString;\n    PPH_STRING LineTextString;\n    WCHAR StackAddressString[PH_PTR_STR_LEN_1];\n    WCHAR FrameAddressString[PH_PTR_STR_LEN_1];\n    WCHAR Parameter1String[PH_PTR_STR_LEN_1];\n    WCHAR Parameter2String[PH_PTR_STR_LEN_1];\n    WCHAR Parameter3String[PH_PTR_STR_LEN_1];\n    WCHAR Parameter4String[PH_PTR_STR_LEN_1];\n    WCHAR PcAddressString[PH_PTR_STR_LEN_1];\n    WCHAR ReturnAddressString[PH_PTR_STR_LEN_1];\n    PH_STRINGREF Architecture;\n    PPH_STRING FrameDistanceString;\n\n    PH_STRINGREF TextCache[TREE_COLUMN_ITEM_MAXIMUM];\n} PH_STACK_TREE_ROOT_NODE, *PPH_STACK_TREE_ROOT_NODE;\n\ntypedef enum _PH_THREAD_STACK_MENUITEM\n{\n    PH_THREAD_STACK_MENUITEM_INSPECT = 1,\n    PH_THREAD_STACK_MENUITEM_OPENFILELOCATION,\n} PH_THREAD_STACK_MENUITEM;\n\nINT_PTR CALLBACK PhpThreadStackDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhpFreeThreadStackItem(\n    _In_ PTHREAD_STACK_ITEM StackItem\n    );\n\nNTSTATUS PhpRefreshThreadStack(\n    _In_ HWND WindowHandle,\n    _In_ PPH_THREAD_STACK_CONTEXT ThreadStackContext\n    );\n\n#define SORT_FUNCTION(Column) ThreadStackTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl ThreadStackTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_THREAD_STACK_CONTEXT context = ((PPH_THREAD_STACK_CONTEXT)_context); \\\n    PPH_STACK_TREE_ROOT_NODE node1 = *(PPH_STACK_TREE_ROOT_NODE*)_elem1; \\\n    PPH_STACK_TREE_ROOT_NODE node2 = *(PPH_STACK_TREE_ROOT_NODE*)_elem2; \\\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \\\n    \\\n    return PhModifySort(sortResult, context->TreeNewSortOrder); \\\n}\n\nBEGIN_SORT_FUNCTION(Index)\n{\n    sortResult = uint64cmp(node1->Index, node2->Index);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Symbol)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->SymbolString, node2->SymbolString, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StackAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->StackFrame.StackAddress, (ULONG_PTR)node2->StackFrame.StackAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FrameAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->StackFrame.FrameAddress, (ULONG_PTR)node2->StackFrame.FrameAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StackParameter1)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->StackFrame.Params[0], (ULONG_PTR)node2->StackFrame.Params[0]);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StackParameter2)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->StackFrame.Params[1], (ULONG_PTR)node2->StackFrame.Params[1]);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StackParameter3)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->StackFrame.Params[2], (ULONG_PTR)node2->StackFrame.Params[2]);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(StackParameter4)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->StackFrame.Params[3], (ULONG_PTR)node2->StackFrame.Params[3]);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ControlAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->StackFrame.PcAddress, (ULONG_PTR)node2->StackFrame.PcAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ReturnAddress)\n{\n    sortResult = uintptrcmp((ULONG_PTR)node1->StackFrame.ReturnAddress, (ULONG_PTR)node2->StackFrame.ReturnAddress);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FileName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->FileNameString, node2->FileNameString, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LineText)\n{\n    sortResult = PhCompareStringWithNullSortOrder(node1->LineTextString, node2->LineTextString, context->TreeNewSortOrder, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Architecture)\n{\n    sortResult = ushortcmp(node1->StackFrame.Machine, node2->StackFrame.Machine);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FrameDistance)\n{\n    sortResult = uintcmp(node1->FrameDistance, node2->FrameDistance);\n}\nEND_SORT_FUNCTION\n\nVOID ThreadStackLoadSettingsTreeList(\n    _Inout_ PPH_THREAD_STACK_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhGetStringSetting(SETTING_THREAD_STACK_TREE_LIST_COLUMNS);\n    PhCmLoadSettings(Context->TreeNewHandle, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\nVOID ThreadStackSaveSettingsTreeList(\n    _Inout_ PPH_THREAD_STACK_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhCmSaveSettings(Context->TreeNewHandle);\n    PhSetStringSetting2(SETTING_THREAD_STACK_TREE_LIST_COLUMNS, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN ThreadStackNodeHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_STACK_TREE_ROOT_NODE node1 = *(PPH_STACK_TREE_ROOT_NODE *)Entry1;\n    PPH_STACK_TREE_ROOT_NODE node2 = *(PPH_STACK_TREE_ROOT_NODE *)Entry2;\n\n    return node1->Index == node2->Index;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG ThreadStackNodeHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashInt32((*(PPH_STACK_TREE_ROOT_NODE*)Entry)->Index);\n}\n\nVOID DestroyThreadStackNode(\n    _In_ PPH_STACK_TREE_ROOT_NODE Node\n    )\n{\n    if (Node->TooltipText)\n        PhDereferenceObject(Node->TooltipText);\n    if (Node->IndexString)\n        PhDereferenceObject(Node->IndexString);\n    if (Node->FrameDistanceString)\n        PhDereferenceObject(Node->FrameDistanceString);\n    PhDereferenceObject(Node);\n}\n\nPPH_STACK_TREE_ROOT_NODE AddThreadStackNode(\n    _Inout_ PPH_THREAD_STACK_CONTEXT Context,\n    _In_ ULONG Index\n    )\n{\n    PPH_STACK_TREE_ROOT_NODE threadStackNode;\n\n    threadStackNode = PhCreateAlloc(sizeof(PH_STACK_TREE_ROOT_NODE));\n    memset(threadStackNode, 0, sizeof(PH_STACK_TREE_ROOT_NODE));\n\n    PhInitializeTreeNewNode(&threadStackNode->Node);\n\n    memset(threadStackNode->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM);\n    threadStackNode->Node.TextCache = threadStackNode->TextCache;\n    threadStackNode->Node.TextCacheSize = TREE_COLUMN_ITEM_MAXIMUM;\n\n    threadStackNode->Index = Index;\n\n    PhAddEntryHashtable(Context->NodeHashtable, &threadStackNode);\n    PhAddItemList(Context->NodeList, threadStackNode);\n\n    // TreeNew_NodesStructured(Context->TreeNewHandle);\n\n    return threadStackNode;\n}\n\nPPH_STACK_TREE_ROOT_NODE FindThreadStackNode(\n    _In_ PPH_THREAD_STACK_CONTEXT Context,\n    _In_ ULONG Index\n    )\n{\n    PH_STACK_TREE_ROOT_NODE lookupThreadStackNode;\n    PPH_STACK_TREE_ROOT_NODE lookupThreadStackNodePtr = &lookupThreadStackNode;\n    PPH_STACK_TREE_ROOT_NODE *threadStackNode;\n\n    lookupThreadStackNode.Index = Index;\n\n    threadStackNode = (PPH_STACK_TREE_ROOT_NODE*)PhFindEntryHashtable(\n        Context->NodeHashtable,\n        &lookupThreadStackNodePtr\n        );\n\n    if (threadStackNode)\n        return *threadStackNode;\n    else\n        return NULL;\n}\n\nVOID RemoveThreadStackNode(\n    _In_ PPH_THREAD_STACK_CONTEXT Context,\n    _In_ PPH_STACK_TREE_ROOT_NODE Node\n)\n{\n    ULONG index = 0;\n\n    PhRemoveEntryHashtable(Context->NodeHashtable, &Node);\n\n    if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX)\n    {\n        PhRemoveItemList(Context->NodeList, index);\n    }\n\n    DestroyThreadStackNode(Node);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID UpdateThreadStackNode(\n    _In_ PPH_THREAD_STACK_CONTEXT Context,\n    _In_ PPH_STACK_TREE_ROOT_NODE Node\n    )\n{\n    memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM);\n\n    PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nBOOLEAN NTAPI ThreadStackTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREAD_STACK_CONTEXT context = Context;\n    PPH_STACK_TREE_ROOT_NODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_STACK_TREE_ROOT_NODE)getChildren->Node;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(Index),\n                    SORT_FUNCTION(Symbol),\n                    SORT_FUNCTION(StackAddress),\n                    SORT_FUNCTION(FrameAddress),\n                    SORT_FUNCTION(StackParameter1),\n                    SORT_FUNCTION(StackParameter2),\n                    SORT_FUNCTION(StackParameter3),\n                    SORT_FUNCTION(StackParameter4),\n                    SORT_FUNCTION(ControlAddress),\n                    SORT_FUNCTION(ReturnAddress),\n                    SORT_FUNCTION(FileName),\n                    SORT_FUNCTION(LineText),\n                    SORT_FUNCTION(Architecture),\n                    SORT_FUNCTION(FrameDistance),\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == TREE_COLUMN_ITEM_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (context->TreeNewSortColumn < TREE_COLUMN_ITEM_MAXIMUM)\n                    sortFunction = sortFunctions[context->TreeNewSortColumn];\n                else\n                    sortFunction = NULL;\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1;\n            node = (PPH_STACK_TREE_ROOT_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1;\n            node = (PPH_STACK_TREE_ROOT_NODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case PH_STACK_TREE_COLUMN_INDEX:\n                {\n                    PhMoveReference(&node->IndexString, PhFormatUInt64(node->Index, TRUE));\n                    getCellText->Text = PhGetStringRef(node->IndexString);\n                }\n                break;\n            case PH_STACK_TREE_COLUMN_SYMBOL:\n                getCellText->Text = PhGetStringRef(node->SymbolString);\n                break;\n            case PH_STACK_TREE_COLUMN_STACKADDRESS:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->StackAddressString);\n                break;\n            case PH_STACK_TREE_COLUMN_FRAMEADDRESS:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->FrameAddressString);\n                break;\n            case PH_STACK_TREE_COLUMN_PARAMETER1:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->Parameter1String);\n                break;\n            case PH_STACK_TREE_COLUMN_PARAMETER2:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->Parameter2String);\n                break;\n            case PH_STACK_TREE_COLUMN_PARAMETER3:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->Parameter3String);\n                break;\n            case PH_STACK_TREE_COLUMN_PARAMETER4:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->Parameter4String);\n                break;\n            case PH_STACK_TREE_COLUMN_CONTROLADDRESS:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->PcAddressString);\n                break;\n            case PH_STACK_TREE_COLUMN_RETURNADDRESS:\n                PhInitializeStringRefLongHint(&getCellText->Text, node->ReturnAddressString);\n                break;\n            case PH_STACK_TREE_COLUMN_FILENAME:\n                getCellText->Text = PhGetStringRef(node->FileNameString);\n                break;\n            case PH_STACK_TREE_COLUMN_LINETEXT:\n                getCellText->Text = PhGetStringRef(node->LineTextString);\n                break;\n            case PH_STACK_TREE_COLUMN_ARCHITECTURE:\n                getCellText->Text = node->Architecture;\n                break;\n            case PH_STACK_TREE_COLUMN_FRAMEDISTANCE:\n                {\n                    if (node->FrameDistance)\n                        PhMoveReference(&node->FrameDistanceString, PhFormatSize(node->FrameDistance, ULONG_MAX));\n                    getCellText->Text = PhGetStringRef(node->FrameDistanceString);\n                }\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            node = (PPH_STACK_TREE_ROOT_NODE)getNodeColor->Node;\n\n            if (context->HighlightInlineFrames && PhIsStackFrameTypeInline(node->StackFrame.InlineFrameContext))\n            {\n                getNodeColor->BackColor = PhGetIntegerSetting(SETTING_COLOR_INLINE_THREAD_STACK);\n            }\n            else if (context->HighlightSystemPages && (ULONG_PTR)node->StackFrame.PcAddress > PhSystemBasicInformation.MaximumUserModeAddress)\n            {\n                getNodeColor->BackColor = PhGetIntegerSetting(SETTING_COLOR_SYSTEM_THREAD_STACK);\n            }\n            else if (context->HighlightUserPages && (ULONG_PTR)node->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress)\n            {\n                getNodeColor->BackColor = PhGetIntegerSetting(L\"ColorUserThreadStack\");\n                getNodeColor->BackColor = PhGetIntegerSetting(SETTING_COLOR_USER_THREAD_STACK);\n            }\n\n            getNodeColor->Flags = TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1;\n\n            SendMessage(\n                context->WindowHandle,\n                WM_COMMAND,\n                WM_PH_SHOWSTACKMENU,\n                (LPARAM)contextMenuEvent\n                );\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case VK_F5:\n                SendMessage(context->WindowHandle, WM_COMMAND, IDC_REFRESH, 0);\n                break;\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    SendMessage(context->WindowHandle, WM_COMMAND, IDC_COPY, 0);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        {\n            SendMessage(context->WindowHandle, WM_COMMAND, WM_PH_SHOWSTACKDEFAULT, 0);\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = 0;\n            data.DefaultSortOrder = AscendingSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewGetCellTooltip:\n        {\n            PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;\n            node = (PPH_STACK_TREE_ROOT_NODE)getCellTooltip->Node;\n\n            if (getCellTooltip->Column->Id != 0)\n                return FALSE;\n\n            if (!node->TooltipText)\n            {\n                PH_STRING_BUILDER stringBuilder;\n                PPH_STRING fileName;\n                PH_SYMBOL_LINE_INFORMATION lineInfo;\n\n                PhInitializeStringBuilder(&stringBuilder, 40);\n\n                if (PhGetLineFromAddress(\n                    context->SymbolProvider,\n                    node->StackFrame.PcAddress,\n                    &fileName,\n                    NULL,\n                    &lineInfo\n                    ))\n                {\n                    PH_FORMAT format[5];\n                    SIZE_T returnLength;\n                    WCHAR buffer[0x100];\n\n                    PhMoveReference(&fileName, PhGetFileName(fileName));\n\n                    // File: %s: line %lu\\n\n                    PhInitFormatS(&format[0], L\"File: \");\n                    PhInitFormatSR(&format[1], fileName->sr);\n                    PhInitFormatS(&format[2], L\": line \");\n                    PhInitFormatU(&format[3], lineInfo.LineNumber);\n                    PhInitFormatS(&format[4], L\"\\n\");\n\n                    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n                    {\n                        PhAppendStringBuilderEx(&stringBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n                    }\n                    else\n                    {\n                        PhAppendFormatStringBuilder(\n                            &stringBuilder,\n                            L\"File: %s: line %lu\\n\",\n                            fileName->Buffer,\n                            lineInfo.LineNumber\n                            );\n                    }\n\n                    PhDereferenceObject(fileName);\n                }\n\n                if (stringBuilder.String->Length != 0)\n                    PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n                if (PhPluginsEnabled)\n                {\n                    PH_PLUGIN_THREAD_STACK_CONTROL control;\n\n                    control.Type = PluginThreadStackGetTooltip;\n                    control.UniqueKey = context;\n                    control.u.GetTooltip.StackFrame = &node->StackFrame;\n                    control.u.GetTooltip.StringBuilder = &stringBuilder;\n                    PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n                }\n\n                node->TooltipText = PhFinalStringBuilderString(&stringBuilder);\n            }\n\n            if (!PhIsNullOrEmptyString(node->TooltipText))\n            {\n                getCellTooltip->Text = node->TooltipText->sr;\n                getCellTooltip->Unfolding = FALSE;\n                getCellTooltip->Font = NULL; // use default font\n                getCellTooltip->MaximumWidth = 550;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case TreeNewGetDialogCode:\n        {\n            PULONG code = Parameter2;\n\n            if (PtrToUlong(Parameter1) == VK_F5)\n            {\n                *code = DLGC_WANTMESSAGE;\n                return TRUE;\n            }\n        }\n        return FALSE;\n    }\n\n    return FALSE;\n}\n\nVOID ClearThreadStackTree(\n    _In_ PPH_THREAD_STACK_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        DestroyThreadStackNode(Context->NodeList->Items[i]);\n\n    PhClearHashtable(Context->NodeHashtable);\n    PhClearList(Context->NodeList);\n}\n\nPPH_STACK_TREE_ROOT_NODE GetSelectedThreadStackNode(\n    _In_ PPH_THREAD_STACK_CONTEXT Context\n    )\n{\n    PPH_STACK_TREE_ROOT_NODE stackNode = NULL;\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        stackNode = Context->NodeList->Items[i];\n\n        if (stackNode->Node.Selected)\n            return stackNode;\n    }\n\n    return NULL;\n}\n\n_Success_(return)\nBOOLEAN GetSelectedThreadStackNodes(\n    _In_ PPH_THREAD_STACK_CONTEXT Context,\n    _Out_ PPH_STACK_TREE_ROOT_NODE **Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_STACK_TREE_ROOT_NODE node = (PPH_STACK_TREE_ROOT_NODE)Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            PhAddItemList(list, node);\n        }\n    }\n\n    if (list->Count)\n    {\n        *Nodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhpThreadStackTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREAD_STACK_CONTEXT stackContext = Context;\n    PPH_STACK_TREE_ROOT_NODE stackNode = (PPH_STACK_TREE_ROOT_NODE)Node;\n\n    if (stackContext->HideSystemPages && (ULONG_PTR)stackNode->StackFrame.PcAddress > PhSystemBasicInformation.MaximumUserModeAddress)\n        return FALSE;\n    if (stackContext->HideUserPages && (ULONG_PTR)stackNode->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress)\n        return FALSE;\n    if (stackContext->HideInlineFrames && PhIsStackFrameTypeInline(stackNode->StackFrame.InlineFrameContext))\n        return FALSE;\n\n    return TRUE;\n}\n\nVOID InitializeThreadStackTree(\n    _Inout_ PPH_THREAD_STACK_CONTEXT Context\n    )\n{\n    Context->NodeList = PhCreateList(100);\n    Context->NodeHashtable = PhCreateHashtable(\n        sizeof(PPH_STACK_TREE_ROOT_NODE),\n        ThreadStackNodeHashtableEqualFunction,\n        ThreadStackNodeHashtableHashFunction,\n        100\n        );\n\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n    TreeNew_SetCallback(Context->TreeNewHandle, ThreadStackTreeNewCallback, Context);\n\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_INDEX, TRUE, L\"#\", 30, PH_ALIGN_LEFT, 0, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_SYMBOL, TRUE, L\"Name\", 250, PH_ALIGN_LEFT, 1, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_STACKADDRESS, FALSE, L\"Stack address\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_FRAMEADDRESS, FALSE, L\"Frame address\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER1, FALSE, L\"Stack parameter #1\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER2, FALSE, L\"Stack parameter #2\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER3, FALSE, L\"Stack parameter #3\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER4, FALSE, L\"Stack parameter #4\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_CONTROLADDRESS, FALSE, L\"Control address\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_RETURNADDRESS, FALSE, L\"Return address\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_FILENAME, FALSE, L\"File name\", 100, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_LINETEXT, FALSE, L\"Line number\", 100, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_ARCHITECTURE, FALSE, L\"Architecture\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_FRAMEDISTANCE, FALSE, L\"Frame distance\", 100, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT);\n\n    PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList);\n    Context->TreeFilterEntry = PhAddTreeNewFilter(&Context->TreeFilterSupport, PhpThreadStackTreeFilterCallback, Context);\n\n    TreeNew_SetSort(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_INDEX, AscendingSortOrder);\n    TreeNew_SetTriState(Context->TreeNewHandle, FALSE);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n\n    ThreadStackLoadSettingsTreeList(Context);\n}\n\nVOID DeleteThreadStackTree(\n    _In_ PPH_THREAD_STACK_CONTEXT Context\n    )\n{\n    PhRemoveTreeNewFilter(&Context->TreeFilterSupport, Context->TreeFilterEntry);\n    PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport);\n\n    ThreadStackSaveSettingsTreeList(Context);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        DestroyThreadStackNode(Context->NodeList->Items[i]);\n    }\n\n    PhDereferenceObject(Context->NodeHashtable);\n    PhDereferenceObject(Context->NodeList);\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpThreadStackContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_THREAD_STACK_CONTEXT context = (PPH_THREAD_STACK_CONTEXT)Object;\n\n    if (context->StatusMessage) PhDereferenceObject(context->StatusMessage);\n    if (context->StatusContent) PhDereferenceObject(context->StatusContent);\n    if (context->NewList) PhDereferenceObject(context->NewList);\n    if (context->List) PhDereferenceObject(context->List);\n\n    if (context->ThreadHandle)\n        NtClose(context->ThreadHandle);\n}\n\nVOID PhShowThreadStackDialog(\n    _In_ HWND ParentWindowHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ThreadId,\n    _In_ PPH_THREAD_PROVIDER ThreadProvider\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    NTSTATUS status;\n    HANDLE threadHandle;\n    PPH_THREAD_STACK_CONTEXT context;\n\n    // If the user is trying to view a system thread stack\n    // but KSystemInformer is not loaded, show an error message.\n    if (ProcessId == SYSTEM_PROCESS_ID && (KsiLevel() < KphLevelMed))\n    {\n        PhShowKsiNotConnected(\n            ParentWindowHandle,\n            L\"Inspecting kernel stacks requires a connection to the kernel driver.\"\n            );\n        return;\n    }\n\n    // The idle process has pseudo CIDs (dmex)\n    if (ProcessId == SYSTEM_IDLE_PROCESS_ID &&\n        HandleToUlong(ThreadId) < PhSystemProcessorInformation.NumberOfProcessors)\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to open the thread.\", STATUS_UNSUCCESSFUL, 0);\n        return;\n    }\n\n    if (!NT_SUCCESS(status = PhOpenThread(\n        &threadHandle,\n        THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME,\n        ThreadId\n        )))\n    {\n        status = PhOpenThread(\n            &threadHandle,\n            THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT,\n            ThreadId\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to open the thread.\", status, 0);\n        return;\n    }\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhThreadStackContextType = PhCreateObjectType(L\"ThreadStackContext\", 0, PhpThreadStackContextDeleteProcedure);\n        PhEndInitOnce(&initOnce);\n    }\n\n    context = PhCreateObjectZero(sizeof(PH_THREAD_STACK_CONTEXT), PhThreadStackContextType);\n    context->List = PhCreateList(10);\n    context->NewList = PhCreateList(10);\n    PhInitializeQueuedLock(&context->StatusLock);\n\n    context->ParentHandle = ParentWindowHandle;\n    context->ThreadHandle = threadHandle;\n    context->ProcessId = ProcessId;\n    context->ThreadId = ThreadId;\n    context->ThreadProvider = ThreadProvider;\n    context->SymbolProvider = ThreadProvider->SymbolProvider;\n\n    PhDialogBox(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_THRDSTACK),\n        ParentWindowHandle,\n        PhpThreadStackDlgProc,\n        context\n        );\n}\n\nINT_PTR CALLBACK PhpThreadStackDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_THREAD_STACK_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_THREAD_STACK_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            NTSTATUS status;\n\n            context->WindowHandle = hwndDlg;\n            context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_TREELIST);\n            context->HighlightUserPages = !!PhGetIntegerSetting(SETTING_USE_COLOR_USER_THREAD_STACK);\n            context->HighlightSystemPages = !!PhGetIntegerSetting(SETTING_USE_COLOR_SYSTEM_THREAD_STACK);\n            context->HighlightInlineFrames = !!PhGetIntegerSetting(SETTING_USE_COLOR_INLINE_THREAD_STACK);\n            PhSetWindowExStyle(context->TreeNewHandle, WS_EX_CLIENTEDGE, 0);\n\n            PhSetApplicationWindowIcon(hwndDlg);\n\n            PhSetWindowText(hwndDlg, PhaFormatString(L\"Stack - thread %lu\", HandleToUlong(context->ThreadId))->Buffer);\n\n            InitializeThreadStackTree(context);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_OPTIONS), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n            if (MinimumSize.left == -1)\n            {\n                RECT rect;\n\n                rect.left = 0;\n                rect.top = 0;\n                rect.right = 190;\n                rect.bottom = 120;\n                MapDialogRect(hwndDlg, &rect);\n                MinimumSize = rect;\n                MinimumSize.left = 0;\n            }\n\n            PhLoadWindowPlacementFromSetting(NULL, SETTING_THREAD_STACK_WINDOW_SIZE, hwndDlg);\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n            PhSetDialogFocus(hwndDlg, context->TreeNewHandle);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_THREAD_STACK_CONTROL control;\n\n                control.Type = PluginThreadStackInitializing;\n                control.UniqueKey = context;\n                control.u.Initializing.ProcessId = context->ProcessId;\n                control.u.Initializing.ThreadId = context->ThreadId;\n                control.u.Initializing.ThreadHandle = context->ThreadHandle;\n                control.u.Initializing.ProcessHandle = context->SymbolProvider->ProcessHandle;\n                control.u.Initializing.SymbolProvider = context->SymbolProvider;\n                control.u.Initializing.CustomWalk = FALSE;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n\n                context->CustomWalk = control.u.Initializing.CustomWalk;\n            }\n\n            status = PhpRefreshThreadStack(hwndDlg, context);\n\n            if (status == STATUS_ABANDONED)\n                EndDialog(hwndDlg, IDCANCEL);\n            else if (!NT_SUCCESS(status))\n            {\n                // HACK: Show error dialog on the parent window.\n                PhShowStatus(GetParent(hwndDlg), L\"Unable to load the stack.\", status, 0);\n                EndDialog(hwndDlg, IDCANCEL);\n            }\n        }\n        break;\n    case WM_DESTROY:\n        {\n            context->StopWalk = TRUE;\n\n            DeleteThreadStackTree(context);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            if (PhPluginsEnabled)\n            {\n                PH_PLUGIN_THREAD_STACK_CONTROL control;\n                control.Type = PluginThreadStackUninitializing;\n                control.UniqueKey = context;\n                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n            }\n\n            for (ULONG i = 0; i < context->List->Count; i++)\n                PhpFreeThreadStackItem(context->List->Items[i]);\n\n            PhSaveWindowPlacementToSetting(NULL, L\"ThreadStackWindowSize\", hwndDlg);\n\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n            PhDereferenceObject(context);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                EndDialog(hwndDlg, IDOK);\n                break;\n            case IDC_REFRESH:\n                {\n                    NTSTATUS status;\n\n                    if (!NT_SUCCESS(status = PhpRefreshThreadStack(hwndDlg, context)))\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to refresh the stack.\", status, 0);\n                    }\n                }\n                break;\n            case WM_PH_SHOWSTACKMENU:\n                {\n                    PPH_EMENU menu;\n                    PPH_STACK_TREE_ROOT_NODE selectedNode;\n                    PPH_EMENU_ITEM selectedItem;\n                    PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam;\n\n                    if (selectedNode = GetSelectedThreadStackNode(context))\n                    {\n                        menu = PhCreateEMenu();\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_DEFAULT, PH_THREAD_STACK_MENUITEM_INSPECT, L\"&Inspect\", NULL, NULL), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_THREAD_STACK_MENUITEM_OPENFILELOCATION, L\"Open &file location\", NULL, NULL), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"Copy\", NULL, NULL), ULONG_MAX);\n                        PhInsertCopyCellEMenuItem(menu, IDC_COPY, context->TreeNewHandle, contextMenuEvent->Column);\n\n                        selectedItem = PhShowEMenu(\n                            menu,\n                            hwndDlg,\n                            PH_EMENU_SHOW_LEFTRIGHT,\n                            PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                            contextMenuEvent->Location.x,\n                            contextMenuEvent->Location.y\n                            );\n\n                        if (selectedItem && selectedItem->Id != ULONG_MAX)\n                        {\n                            BOOLEAN handled = FALSE;\n\n                            handled = PhHandleCopyCellEMenuItem(selectedItem);\n\n                            if (handled)\n                                break;\n\n                            switch (selectedItem->Id)\n                            {\n                            case PH_THREAD_STACK_MENUITEM_INSPECT:\n                                {\n                                    if (!PhIsNullOrEmptyString(selectedNode->FileNameString) && PhDoesFileExistWin32(PhGetString(selectedNode->FileNameString)))\n                                    {\n                                        PhShellExecuteUserString(\n                                            hwndDlg,\n                                            SETTING_PROGRAM_INSPECT_EXECUTABLES,\n                                            PhGetString(selectedNode->FileNameString),\n                                            FALSE,\n                                            L\"Make sure the PE Viewer executable file is present.\"\n                                            );\n                                    }\n                                }\n                                break;\n                            case PH_THREAD_STACK_MENUITEM_OPENFILELOCATION:\n                                {\n                                    if (!PhIsNullOrEmptyString(selectedNode->FileNameString) && PhDoesFileExistWin32(PhGetString(selectedNode->FileNameString)))\n                                    {\n                                        PhShellExecuteUserString(\n                                            hwndDlg,\n                                            SETTING_FILE_BROWSE_EXECUTABLE,\n                                            PhGetString(selectedNode->FileNameString),\n                                            FALSE,\n                                            L\"Make sure the Explorer executable file is present.\"\n                                            );\n                                    }\n                                }\n                                break;\n                            case IDC_COPY:\n                                {\n                                    PPH_STRING text;\n\n                                    text = PhGetTreeNewText(context->TreeNewHandle, 0);\n                                    PhSetClipboardString(context->TreeNewHandle, &text->sr);\n                                    PhDereferenceObject(text);\n                                }\n                                break;\n                            }\n                        }\n\n                        PhDestroyEMenu(menu);\n                    }\n                }\n                break;\n            case WM_PH_SHOWSTACKDEFAULT:\n                {\n                    PPH_STACK_TREE_ROOT_NODE selectedNode;\n\n                    if (selectedNode = GetSelectedThreadStackNode(context))\n                    {\n                        if (!PhIsNullOrEmptyString(selectedNode->FileNameString) && PhDoesFileExistWin32(PhGetString(selectedNode->FileNameString)))\n                        {\n                            PhShellExecuteUserString(\n                                hwndDlg,\n                                SETTING_PROGRAM_INSPECT_EXECUTABLES,\n                                PhGetString(selectedNode->FileNameString),\n                                FALSE,\n                                L\"Make sure the PE Viewer executable file is present.\"\n                                );\n                        }\n                    }\n                }\n                break;\n            case IDC_OPTIONS:\n                {\n                    RECT rect;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM hideUserItem;\n                    PPH_EMENU_ITEM hideSystemItem;\n                    PPH_EMENU_ITEM hideInlineItem;\n                    PPH_EMENU_ITEM userItem;\n                    PPH_EMENU_ITEM systemItem;\n                    PPH_EMENU_ITEM inlineItem;\n                    PPH_EMENU_ITEM selectedItem;\n\n                    if (!PhGetWindowRect(GET_WM_COMMAND_HWND(wParam, lParam), &rect))\n                        break;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, hideUserItem = PhCreateEMenuItem(0, 1, L\"Hide user frames\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, hideSystemItem = PhCreateEMenuItem(0, 2, L\"Hide system frames\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, hideInlineItem = PhCreateEMenuItem(0, 3, L\"Hide inline frames\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, userItem = PhCreateEMenuItem(0, 4, L\"Highlight user frames\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, systemItem = PhCreateEMenuItem(0, 5, L\"Highlight system frames\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, inlineItem = PhCreateEMenuItem(0, 6, L\"Highlight inline frames\", NULL, NULL), ULONG_MAX);\n\n                    if (context->HideUserPages)\n                        hideUserItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HideSystemPages)\n                        hideSystemItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HideInlineFrames)\n                        hideInlineItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightUserPages)\n                        userItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightSystemPages)\n                        systemItem->Flags |= PH_EMENU_CHECKED;\n                    if (context->HighlightInlineFrames)\n                        inlineItem->Flags |= PH_EMENU_CHECKED;\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        GET_WM_COMMAND_HWND(wParam, lParam),\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_BOTTOM,\n                        rect.left,\n                        rect.top\n                        );\n\n                    if (selectedItem && selectedItem->Id)\n                    {\n                        if (selectedItem->Id == 1)\n                        {\n                            context->HideUserPages = !context->HideUserPages;\n                        }\n                        else if (selectedItem->Id == 2)\n                        {\n                            context->HideSystemPages = !context->HideSystemPages;\n                        }\n                        else if (selectedItem->Id == 3)\n                        {\n                            context->HideInlineFrames = !context->HideInlineFrames;\n                        }\n                        else if (selectedItem->Id == 4)\n                        {\n                            context->HighlightUserPages = !context->HighlightUserPages;\n                            PhSetIntegerSetting(SETTING_USE_COLOR_USER_THREAD_STACK, context->HighlightUserPages);\n                        }\n                        else if (selectedItem->Id == 5)\n                        {\n                            context->HighlightSystemPages = !context->HighlightSystemPages;\n                            PhSetIntegerSetting(SETTING_USE_COLOR_SYSTEM_THREAD_STACK, context->HighlightSystemPages);\n                        }\n                        else if (selectedItem->Id == 6)\n                        {\n                            context->HighlightInlineFrames = !context->HighlightInlineFrames;\n                            PhSetIntegerSetting(SETTING_USE_COLOR_INLINE_THREAD_STACK, context->HighlightInlineFrames);\n                        }\n\n                        PhApplyTreeNewFilters(&context->TreeFilterSupport);\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhpFreeThreadStackItem(\n    _In_ PTHREAD_STACK_ITEM StackItem\n    )\n{\n    if (StackItem->Symbol) PhDereferenceObject(StackItem->Symbol);\n    if (StackItem->FileName) PhDereferenceObject(StackItem->FileName);\n    if (StackItem->LineText) PhDereferenceObject(StackItem->LineText);\n\n    PhFree(StackItem);\n}\n\nBOOLEAN NTAPI PhpWalkThreadStackCallback(\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREAD_STACK_CONTEXT threadStackContext = (PPH_THREAD_STACK_CONTEXT)Context;\n    PPH_STRING symbol;\n    PPH_STRING fileName = NULL;\n    PPH_STRING lineText = NULL;\n    PTHREAD_STACK_ITEM item;\n    PVOID baseAddress = NULL;\n    BOOLEAN enableStackFrameInlineInfo;\n    BOOLEAN enableStackFrameLineInfo;\n\n    if (threadStackContext->StopWalk)\n        return FALSE;\n\n    enableStackFrameInlineInfo = !!PhGetIntegerSetting(SETTING_ENABLE_THREAD_STACK_INLINE_SYMBOLS);\n    enableStackFrameLineInfo = !!PhGetIntegerSetting(SETTING_ENABLE_THREAD_STACK_LINE_INFORMATION);\n\n    PhAcquireQueuedLockExclusive(&threadStackContext->StatusLock);\n    {\n        if (threadStackContext->NewList->Count)\n        {\n            PH_FORMAT format[3];\n\n            PhInitFormatS(&format[0], L\"Processing stack frame #\");\n            PhInitFormatU(&format[1], threadStackContext->NewList->Count);\n            PhInitFormatS(&format[2], L\"...\");\n\n            PhMoveReference(&threadStackContext->StatusMessage, PhFormat(format, RTL_NUMBER_OF(format), 0));\n        }\n        else\n        {\n            PhMoveReference(&threadStackContext->StatusMessage, PhCreateString(L\"Processing stack frames...\"));\n        }\n    }\n    PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock);\n\n    if (enableStackFrameInlineInfo && PhSymbolProviderInlineContextSupported())\n    {\n        symbol = PhGetSymbolFromInlineContext(\n            threadStackContext->SymbolProvider,\n            StackFrame,\n            NULL,\n            &fileName,\n            NULL,\n            NULL,\n            &baseAddress\n            );\n\n        if (symbol &&\n            (StackFrame->Machine == IMAGE_FILE_MACHINE_I386) &&\n            !(StackFrame->Flags & PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT))\n        {\n            PhMoveReference(&symbol, PhConcatStringRefZ(&symbol->sr, L\" (No unwind info)\"));\n        }\n\n        if (PhPluginsEnabled)\n        {\n            PH_PLUGIN_THREAD_STACK_CONTROL control;\n\n            control.Type = PluginThreadStackResolveSymbol;\n            control.UniqueKey = threadStackContext;\n            control.u.ResolveSymbol.StackFrame = StackFrame;\n            control.u.ResolveSymbol.Symbol = symbol;\n            control.u.ResolveSymbol.FileName = fileName;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n\n            symbol = control.u.ResolveSymbol.Symbol;\n            fileName = control.u.ResolveSymbol.FileName;\n        }\n\n        if (enableStackFrameLineInfo)\n        {\n            PPH_STRING lineFileName;\n            PH_SYMBOL_LINE_INFORMATION lineInfo;\n\n            if (PhGetLineFromInlineContext(\n                threadStackContext->SymbolProvider,\n                StackFrame,\n                baseAddress,\n                &lineFileName,\n                NULL,\n                &lineInfo\n                ))\n            {\n                PH_FORMAT format[3];\n\n                PhInitFormatSR(&format[0], lineFileName->sr);\n                PhInitFormatS(&format[1], L\" @ \");\n                PhInitFormatU(&format[2], lineInfo.LineNumber);\n\n                lineText = PhFormat(format, RTL_NUMBER_OF(format), 0);\n                PhDereferenceObject(lineFileName);\n            }\n        }\n\n        if (symbol && PhIsStackFrameTypeInline(StackFrame->InlineFrameContext))\n        {\n            PhMoveReference(&symbol, PhConcatStringRefZ(&symbol->sr, L\" (Inline function)\"));\n        }\n    }\n    else\n    {\n        symbol = PhGetSymbolFromAddress(\n            threadStackContext->SymbolProvider,\n            StackFrame->PcAddress,\n            NULL,\n            &fileName,\n            NULL,\n            NULL\n            );\n\n        if (symbol &&\n            (StackFrame->Machine == IMAGE_FILE_MACHINE_I386) &&\n            !(StackFrame->Flags & PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT))\n        {\n            PhMoveReference(&symbol, PhConcatStringRefZ(&symbol->sr, L\" (No unwind info)\"));\n        }\n\n        if (PhPluginsEnabled)\n        {\n            PH_PLUGIN_THREAD_STACK_CONTROL control;\n\n            control.Type = PluginThreadStackResolveSymbol;\n            control.UniqueKey = threadStackContext;\n            control.u.ResolveSymbol.StackFrame = StackFrame;\n            control.u.ResolveSymbol.Symbol = symbol;\n            control.u.ResolveSymbol.FileName = fileName;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n\n            symbol = control.u.ResolveSymbol.Symbol;\n            fileName = control.u.ResolveSymbol.FileName;\n        }\n\n        if (enableStackFrameLineInfo)\n        {\n            PPH_STRING lineFileName;\n            PH_SYMBOL_LINE_INFORMATION lineInfo;\n\n            if (PhGetLineFromAddress(\n                threadStackContext->SymbolProvider,\n                StackFrame->PcAddress,\n                &lineFileName,\n                NULL,\n                &lineInfo\n                ))\n            {\n                PH_FORMAT format[3];\n\n                PhInitFormatSR(&format[0], lineFileName->sr);\n                PhInitFormatS(&format[1], L\" @ \");\n                PhInitFormatU(&format[2], lineInfo.LineNumber);\n\n                lineText = PhFormat(format, RTL_NUMBER_OF(format), 0);\n                PhDereferenceObject(lineFileName);\n            }\n        }\n    }\n\n    item = PhAllocateZero(sizeof(THREAD_STACK_ITEM));\n    item->StackFrame = *StackFrame;\n    item->Index = threadStackContext->NewList->Count;\n    item->Symbol = symbol;\n    item->FileName = fileName;\n    item->LineText = lineText;\n    PhAddItemList(threadStackContext->NewList, item);\n\n    if ( // Zero inline frames so the stack matches windbg output. (dmex)\n        PhSymbolProviderInlineContextSupported() &&\n        PhIsStackFrameTypeInline(StackFrame->InlineFrameContext)\n        )\n    {\n        // Note: Only zero the item->StackFrame local copy. (dmex)\n        item->StackFrame.PcAddress = 0;\n        item->StackFrame.ReturnAddress = 0;\n        item->StackFrame.FrameAddress = 0;\n        item->StackFrame.StackAddress = 0;\n        memset(item->StackFrame.Params, 0, sizeof(item->StackFrame.Params));\n    }\n\n    return TRUE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpRefreshThreadStackThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PH_AUTO_POOL autoPool;\n    NTSTATUS status;\n    PPH_THREAD_STACK_CONTEXT threadStackContext = Parameter;\n    CLIENT_ID clientId;\n    BOOLEAN defaultWalk;\n\n    PhInitializeAutoPool(&autoPool);\n\n    PhLoadSymbolProviderOptions(threadStackContext->SymbolProvider);\n    PhLoadSymbolProviderModules(threadStackContext->SymbolProvider, threadStackContext->ProcessId);\n\n    clientId.UniqueProcess = threadStackContext->ProcessId;\n    clientId.UniqueThread = threadStackContext->ThreadId;\n    defaultWalk = TRUE;\n\n    if (threadStackContext->CustomWalk)\n    {\n        PH_PLUGIN_THREAD_STACK_CONTROL control;\n\n        control.Type = PluginThreadStackWalkStack;\n        control.UniqueKey = threadStackContext;\n        control.u.WalkStack.Status = STATUS_UNSUCCESSFUL;\n        control.u.WalkStack.ThreadHandle = threadStackContext->ThreadHandle;\n        control.u.WalkStack.ProcessHandle = threadStackContext->SymbolProvider->ProcessHandle;\n        control.u.WalkStack.ClientId = &clientId;\n        control.u.WalkStack.Flags = PH_WALK_USER_WOW64_STACK | PH_WALK_USER_STACK | PH_WALK_KERNEL_STACK;\n        control.u.WalkStack.Callback = PhpWalkThreadStackCallback;\n        control.u.WalkStack.CallbackContext = threadStackContext;\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n        status = control.u.WalkStack.Status;\n\n        if (NT_SUCCESS(status))\n            defaultWalk = FALSE;\n    }\n\n    if (defaultWalk)\n    {\n        PH_PLUGIN_THREAD_STACK_CONTROL control;\n\n        control.UniqueKey = threadStackContext;\n\n        if (PhPluginsEnabled)\n        {\n            control.Type = PluginThreadStackBeginDefaultWalkStack;\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n        }\n\n        status = PhWalkThreadStack(\n            threadStackContext->ThreadHandle,\n            threadStackContext->SymbolProvider->ProcessHandle,\n            &clientId,\n            threadStackContext->SymbolProvider,\n            PH_WALK_USER_WOW64_STACK | PH_WALK_USER_STACK | PH_WALK_KERNEL_STACK,\n            PhpWalkThreadStackCallback,\n            threadStackContext\n            );\n\n        if (PhPluginsEnabled)\n        {\n            control.Type = PluginThreadStackEndDefaultWalkStack;\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n        }\n    }\n\n    if (threadStackContext->NewList->Count != 0)\n        status = STATUS_SUCCESS;\n\n    threadStackContext->WalkStatus = status;\n    PostMessage(threadStackContext->TaskDialogHandle, WM_PH_COMPLETED, 0, 0);\n\n    PhDeleteAutoPool(&autoPool);\n    PhDereferenceObject(threadStackContext);\n\n    return STATUS_SUCCESS;\n}\n\nLRESULT CALLBACK PhpThreadStackTaskDialogSubclassProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_THREAD_STACK_CONTEXT context;\n    WNDPROC oldWndProc;\n\n    if (!(context = PhGetWindowContext(hwndDlg, 0xF)))\n        return 0;\n\n    oldWndProc = context->ThreadStackStatusDefaultWindowProc;\n\n    switch (uMsg)\n    {\n    case WM_NCDESTROY:\n        {\n            PhSetWindowProcedure(hwndDlg, oldWndProc);\n            PhRemoveWindowContext(hwndDlg, 0xF);\n        }\n        break;\n    case WM_PH_COMPLETED:\n        {\n            context->EnableCloseDialog = TRUE;\n            SendMessage(hwndDlg, TDM_CLICK_BUTTON, IDOK, 0);\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhpSymbolProviderEventCallbackHandler(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_SYMBOL_EVENT_DATA event = Parameter;\n    PPH_THREAD_STACK_CONTEXT context = Context;\n    PPH_STRING statusMessage = NULL;\n    ULONG statusProgress = 0;\n\n    if (!event) return;\n    if (!context) return;\n\n    switch (event->EventType)\n    {\n    case PH_SYMBOL_EVENT_TYPE_LOAD_START:\n        statusMessage = PhReferenceObject(event->EventMessage);\n        break;\n    case PH_SYMBOL_EVENT_TYPE_LOAD_END:\n        statusMessage = PhCreateString(L\"Loading symbols...\");\n        break;\n    case PH_SYMBOL_EVENT_TYPE_PROGRESS:\n        {\n            statusMessage = PhReferenceObject(event->EventMessage);\n            statusProgress = (ULONG)event->EventProgress;\n        }\n        break;\n    }\n\n    if (statusMessage)\n    {\n        PhAcquireQueuedLockExclusive(&context->StatusLock);\n        PhMoveReference(&context->StatusContent, statusMessage);\n        context->SymbolProgress = statusProgress;\n        PhReleaseQueuedLockExclusive(&context->StatusLock);\n    }\n}\n\nHRESULT CALLBACK PhpThreadStackTaskDialogCallback(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ LONG_PTR dwRefData\n    )\n{\n    PPH_THREAD_STACK_CONTEXT context = (PPH_THREAD_STACK_CONTEXT)dwRefData;\n\n    switch (uMsg)\n    {\n    case TDN_DIALOG_CONSTRUCTED:\n        {\n            context->TaskDialogHandle = hwndDlg;\n\n            PhSetApplicationWindowIcon(hwndDlg);\n            //SendMessage(hwndDlg, TDM_UPDATE_ICON, TDIE_ICON_MAIN, (LPARAM)PhGetApplicationIcon(FALSE));\n\n            SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n            SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n            InterlockedExchange8(&context->SymbolProgressMarquee, TRUE);\n\n            context->ThreadStackStatusDefaultWindowProc = PhGetWindowProcedure(hwndDlg);\n            PhSetWindowContext(hwndDlg, 0xF, context);\n            PhSetWindowProcedure(hwndDlg, PhpThreadStackTaskDialogSubclassProc);\n\n            PhRegisterCallback(\n                &PhSymbolEventCallback,\n                PhpSymbolProviderEventCallbackHandler,\n                context,\n                &context->SymbolProviderEventRegistration\n                );\n\n            PhReferenceObject(context);\n            PhCreateThread2(PhpRefreshThreadStackThreadStart, context);\n        }\n        break;\n    case TDN_DESTROYED:\n        {\n            // TDN_DESTROYED can occur without TDN_DIALOG_CONSTRUCTED\n            if (context->TaskDialogHandle)\n                PhUnregisterCallback(&PhSymbolEventCallback, &context->SymbolProviderEventRegistration);\n        }\n        break;\n    case TDN_BUTTON_CLICKED:\n        {\n            if ((INT)wParam == IDCANCEL)\n            {\n                context->StopWalk = TRUE;\n                context->SymbolProvider->Terminating = TRUE;\n            }\n\n            //if (!context->EnableCloseDialog)\n            //    return S_FALSE;\n        }\n        break;\n    case TDN_TIMER:\n        {\n            PPH_STRING message;\n            PPH_STRING content;\n            ULONG progress = 0;\n\n            PhAcquireQueuedLockShared(&context->StatusLock);\n            PhSetReference(&message, context->StatusMessage);\n            PhSetReference(&content, context->StatusContent);\n            progress = context->SymbolProgress;\n            PhReleaseQueuedLockShared(&context->StatusLock);\n\n            SendMessage(context->TaskDialogHandle, TDM_SET_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)PhGetStringOrDefault(message, L\"Processing stack frames...\"));\n            SendMessage(context->TaskDialogHandle, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)PhGetStringOrDefault(content, L\"Loading symbols for image...\"));\n\n            PhClearReference(&message);\n            PhClearReference(&content);\n\n            if (context->SymbolProgressReset)\n            {\n                SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n                SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n\n                PhAcquireQueuedLockExclusive(&context->StatusLock);\n                InterlockedExchange8(&context->SymbolProgressMarquee, TRUE);\n                InterlockedExchange8(&context->SymbolProgressReset, FALSE);\n                PhReleaseQueuedLockExclusive(&context->StatusLock);\n            }\n\n            if (progress)\n            {\n                if (context->SymbolProgressMarquee)\n                {\n                    SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, FALSE, 0);\n                    SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, FALSE, 0);\n\n                    PhAcquireQueuedLockExclusive(&context->StatusLock);\n                    InterlockedExchange8(&context->SymbolProgressMarquee, FALSE);\n                    PhReleaseQueuedLockExclusive(&context->StatusLock);\n                }\n\n                SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_POS, (WPARAM)progress, 0);\n            }\n            else\n            {\n                if (!context->SymbolProgressMarquee)\n                {\n                    SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0);\n                    SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1);\n\n                    PhAcquireQueuedLockExclusive(&context->StatusLock);\n                    InterlockedExchange8(&context->SymbolProgressMarquee, TRUE);\n                    PhReleaseQueuedLockExclusive(&context->StatusLock);\n                }\n            }\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\nBOOLEAN PhpShowThreadStackWindow(\n    _In_ PPH_THREAD_STACK_CONTEXT Context\n    )\n{\n    TASKDIALOGCONFIG config;\n    INT result;\n\n    {\n        PPH_STRING windowText;\n        HWND control;\n\n        if (control = GetDlgItem(Context->ParentHandle, IDC_STATE))\n        {\n            if (windowText = PhGetWindowText(control))\n            {\n                PhMoveReference(&Context->StatusContent, windowText);\n            }\n        }\n    }\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags =\n        TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION |\n        TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SHOW_MARQUEE_PROGRESS_BAR |\n        TDF_CALLBACK_TIMER;\n    config.dwCommonButtons = TDCBF_CANCEL_BUTTON;\n    config.hMainIcon = PhGetApplicationIcon(FALSE);\n    config.pfCallback = PhpThreadStackTaskDialogCallback;\n    config.lpCallbackData = (LONG_PTR)Context;\n    config.hwndParent = Context->WindowHandle;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainInstruction = L\"Processing stack frames...\";\n    config.pszContent = PhGetStringOrDefault(Context->StatusContent, L\"Loading symbols for image...\");\n    config.cxWidth = 200;\n\n    return PhShowTaskDialog(&config, &result, NULL, NULL) && result != IDCANCEL;\n}\n\nNTSTATUS PhpRefreshThreadStack(\n    _In_ HWND hwnd,\n    _In_ PPH_THREAD_STACK_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    Context->StopWalk = FALSE;\n    PhMoveReference(&Context->StatusMessage, PhCreateString(L\"Processing stack frames...\"));\n\n    if (!PhpShowThreadStackWindow(Context))\n    {\n        return STATUS_ABANDONED;\n    }\n\n    if (!Context->StopWalk && NT_SUCCESS(Context->WalkStatus))\n    {\n        for (i = 0; i < Context->List->Count; i++)\n            PhpFreeThreadStackItem(Context->List->Items[i]);\n\n        PhDereferenceObject(Context->List);\n        Context->List = Context->NewList;\n        Context->NewList = PhCreateList(10);\n\n        ClearThreadStackTree(Context);\n\n        for (i = 0; i < Context->List->Count; i++)\n        {\n            PTHREAD_STACK_ITEM item = Context->List->Items[i];\n            PPH_STACK_TREE_ROOT_NODE stackNode;\n\n            stackNode = AddThreadStackNode(Context, item->Index);\n            stackNode->StackFrame = item->StackFrame;\n            stackNode->SymbolString = item->Symbol;\n            stackNode->FileNameString = item->FileName;\n            stackNode->LineTextString = item->LineText;\n\n            if (stackNode->FileNameString)\n                stackNode->FileNameString = PhGetFileName(stackNode->FileNameString);\n\n            if (item->StackFrame.StackAddress)\n                PhPrintPointer(stackNode->StackAddressString, item->StackFrame.StackAddress);\n            if (item->StackFrame.FrameAddress)\n                PhPrintPointer(stackNode->FrameAddressString, item->StackFrame.FrameAddress);\n\n            // There are no params for kernel-mode stack traces.\n            if ((ULONG_PTR)item->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress)\n            {\n                if (item->StackFrame.Params[0])\n                    PhPrintPointer(stackNode->Parameter1String, item->StackFrame.Params[0]);\n                if (item->StackFrame.Params[1])\n                    PhPrintPointer(stackNode->Parameter2String, item->StackFrame.Params[1]);\n                if (item->StackFrame.Params[2])\n                    PhPrintPointer(stackNode->Parameter3String, item->StackFrame.Params[2]);\n                if (item->StackFrame.Params[3])\n                    PhPrintPointer(stackNode->Parameter4String, item->StackFrame.Params[3]);\n            }\n\n            if (item->StackFrame.PcAddress)\n                PhPrintPointer(stackNode->PcAddressString, item->StackFrame.PcAddress);\n            if (item->StackFrame.ReturnAddress)\n                PhPrintPointer(stackNode->ReturnAddressString, item->StackFrame.ReturnAddress);\n\n            switch (stackNode->StackFrame.Machine)\n            {\n            case IMAGE_FILE_MACHINE_ARM64EC:\n                PhInitializeStringRef(&stackNode->Architecture, L\"ARM64EC\");\n                break;\n            case IMAGE_FILE_MACHINE_CHPE_X86:\n                PhInitializeStringRef(&stackNode->Architecture, L\"CHPE\");\n                break;\n            case IMAGE_FILE_MACHINE_ARM64:\n                PhInitializeStringRef(&stackNode->Architecture, L\"ARM64\");\n                break;\n            case IMAGE_FILE_MACHINE_ARM:\n                PhInitializeStringRef(&stackNode->Architecture, L\"ARM\");\n                break;\n            case IMAGE_FILE_MACHINE_AMD64:\n                PhInitializeStringRef(&stackNode->Architecture, L\"x64\");\n                break;\n            case IMAGE_FILE_MACHINE_I386:\n                PhInitializeStringRef(&stackNode->Architecture, L\"x86\");\n                break;\n            default:\n                PhInitializeStringRef(&stackNode->Architecture, L\"\");\n                break;\n            }\n\n            if (i > 0 && item->StackFrame.StackAddress)\n            {\n                PTHREAD_STACK_ITEM previousFrame = Context->List->Items[i - 1];\n\n                // Windbg \"k f\" displays the distance between adjacent frames. (dmex)\n                if (previousFrame->StackFrame.StackAddress)\n                {\n                    stackNode->FrameDistance = (ULONG)((ULONG_PTR)item->StackFrame.StackAddress - (ULONG_PTR)previousFrame->StackFrame.StackAddress);\n                }\n            }\n\n            UpdateThreadStackNode(Context, stackNode);\n        }\n\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n    }\n    else\n    {\n        for (i = 0; i < Context->NewList->Count; i++)\n            PhpFreeThreadStackItem(Context->NewList->Items[i]);\n\n        PhClearList(Context->NewList);\n    }\n\n    if (Context->StopWalk)\n        return STATUS_ABANDONED;\n\n    return Context->WalkStatus;\n}\n"
  },
  {
    "path": "SystemInformer/thrdstks.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023\n *\n */\n\n#include <phapp.h>\n#include <settings.h>\n#include <phsettings.h>\n#include <colmgr.h>\n#include <emenu.h>\n#include <symprv.h>\n#include <phplug.h>\n#include <cpysave.h>\n#include <procprv.h>\n#include <procprp.h>\n\n#define WM_PH_THREAD_STACKS_PUBLISH    (WM_USER + 2000)\n\ntypedef enum _PH_THREAD_STACKS_COLUMN\n{\n    PH_THREAD_STACKS_COLUMN_SYMBOL,\n    PH_THREAD_STACKS_COLUMN_PROCESSID,\n    PH_THREAD_STACKS_COLUMN_THREADID,\n    PH_THREAD_STACKS_COLUMN_FRAMENUMBER,\n    PH_THREAD_STACKS_COLUMN_STACKADDRESS,\n    PH_THREAD_STACKS_COLUMN_FRAMEADDRESS,\n    PH_THREAD_STACKS_COLUMN_PARAMETER1,\n    PH_THREAD_STACKS_COLUMN_PARAMETER2,\n    PH_THREAD_STACKS_COLUMN_PARAMETER3,\n    PH_THREAD_STACKS_COLUMN_PARAMETER4,\n    PH_THREAD_STACKS_COLUMN_CONTROLADDRESS,\n    PH_THREAD_STACKS_COLUMN_RETURNADDRESS,\n    PH_THREAD_STACKS_COLUMN_FILENAME,\n    PH_THREAD_STACKS_COLUMN_LINETEXT,\n    PH_THREAD_STACKS_COLUMN_ARCHITECTURE,\n    PH_THREAD_STACKS_COLUMN_FRAMEDISTANCE,\n    PH_THREAD_STACKS_COLUMN_STARTADDRESS,\n    PH_THREAD_STACKS_COLUMN_STARTADDRESSSYMBOL,\n    PH_THREAD_STACKS_COLUMN_PROCESSNAME,\n    PH_THREAD_STACKS_COLUMN_THREADNAME,\n    MAX_PH_THREAD_STACKS_COLUMN,\n} PH_THREAD_STACKS_COLUMN;\n\ntypedef enum _PH_THREAD_STACKS_NODE_TYPE\n{\n    PhThreadStacksNodeTypeProcess,\n    PhThreadStacksNodeTypeThread,\n    PhThreadStacksNodeTypeFrame,\n} PH_THREAD_STACKS_NODE_TYPE, *PPH_THREAD_STACKS_NODE_TYPE;\n\ntypedef struct _PH_THREAD_STACKS_PROCESS_NODE\n{\n    HANDLE ProcessId;\n    PPH_SYMBOL_PROVIDER SymbolProvider;\n    PPH_STRING ProcessName;\n    WCHAR ProcessIdString[PH_INT32_STR_LEN_1];\n    PPH_STRING FileName;\n    PH_STRINGREF Architecture;\n    PPH_LIST Threads;\n} PH_THREAD_STACKS_PROCESS_NODE, *PPH_THREAD_STACKS_PROCESS_NODE;\n\ntypedef struct _PH_THREAD_STACKS_THREAD_NODE\n{\n    PPH_THREAD_STACKS_PROCESS_NODE Process;\n\n    HANDLE ThreadId;\n    HANDLE ThreadHandle;\n    PVOID StartAddress;\n    PPH_STRING ThreadName;\n    WCHAR ThreadIdString[PH_INT32_STR_LEN_1];\n    WCHAR StartAddressString[PH_PTR_STR_LEN_1];\n    PPH_STRING StartAddressSymbol;\n    PPH_STRING FileName;\n    PPH_LIST Frames;\n    BOOLEAN FramesComplete;\n} PH_THREAD_STACKS_THREAD_NODE, *PPH_THREAD_STACKS_THREAD_NODE;\n\ntypedef struct _PH_THREAD_STACKS_FRAME_NODE\n{\n    PPH_THREAD_STACKS_THREAD_NODE Thread;\n\n    PH_THREAD_STACK_FRAME StackFrame;\n    ULONG FrameNumber;\n    ULONG FrameDistance;\n    PPH_STRING FileName;\n    PPH_STRING LineText;\n    WCHAR FrameNumberString[PH_INT32_STR_LEN_1];\n    WCHAR StackAddressString[PH_PTR_STR_LEN_1];\n    WCHAR FrameAddressString[PH_PTR_STR_LEN_1];\n    WCHAR Parameter1String[PH_PTR_STR_LEN_1];\n    WCHAR Parameter2String[PH_PTR_STR_LEN_1];\n    WCHAR Parameter3String[PH_PTR_STR_LEN_1];\n    WCHAR Parameter4String[PH_PTR_STR_LEN_1];\n    WCHAR PcAddressString[PH_PTR_STR_LEN_1];\n    WCHAR ReturnAddressString[PH_PTR_STR_LEN_1];\n    PH_STRINGREF Architecture;\n    PPH_STRING FrameDistanceString;\n    PPH_STRING SymbolStatusString;\n} PH_THREAD_STACKS_FRAME_NODE, *PPH_THREAD_STACKS_FRAME_NODE;\n\ntypedef struct _PH_THREAD_STACKS_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    PH_THREAD_STACKS_NODE_TYPE Type;\n\n    PPH_STRING Symbol;\n\n    union\n    {\n        PH_THREAD_STACKS_PROCESS_NODE Process;\n        PH_THREAD_STACKS_THREAD_NODE Thread;\n        PH_THREAD_STACKS_FRAME_NODE Frame;\n    };\n\n    PH_STRINGREF TextCache[MAX_PH_THREAD_STACKS_COLUMN];\n} PH_THREAD_STACKS_NODE, *PPH_THREAD_STACKS_NODE;\n\ntypedef struct _PH_THREAD_STACKS_WORKER_CONTEXT\n{\n    volatile LONG Stop;\n    PVOID Context;\n    ULONG TotalThreads;\n    ULONG WalkedThreads;\n    PPH_LIST NodeList;\n    PPH_LIST NodeRootList;\n} PH_THREAD_STACKS_WORKER_CONTEXT, *PPH_THREAD_STACKS_WORKER_CONTEXT;\n\ntypedef struct _PH_THREAD_STACKS_CONTEXT\n{\n    HWND WindowHandle;\n    HWND ParentWindowHandle;\n    HWND TreeNewHandle;\n    HWND MessageHandle;\n    HWND SearchWindowHandle;\n    ULONG_PTR SearchMatchHandle;\n\n    PH_LAYOUT_MANAGER LayoutManager;\n    RECT MinimumSize;\n\n    ULONG MessageCount;\n    ULONG LastMessageCount;\n    PPH_STRING StatusMessage;\n    PPH_STRING SymbolMessage;\n    PH_QUEUED_LOCK MessageLock;\n\n    PPH_LIST NodeList;\n    PPH_LIST NodeRootList;\n    PPH_THREAD_STACKS_WORKER_CONTEXT WorkerContext;\n    PH_CALLBACK_REGISTRATION SymbolProviderEventRegistration;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG HideSystemFrames : 1;\n            ULONG HideUserFrames : 1;\n            ULONG HideInlineFrames : 1;\n            ULONG HighlightSystemFrames : 1;\n            ULONG HighlightUserFrames : 1;\n            ULONG HighlightInlineFrames : 1;\n            ULONG Spare : 26;\n        };\n    };\n} PH_THREAD_STACKS_CONTEXT, *PPH_THREAD_STACKS_CONTEXT;\n\ntypedef struct _PH_THREAD_STACKS_WALK_CONTEXT\n{\n    PPH_THREAD_STACKS_WORKER_CONTEXT Context;\n    PPH_THREAD_STACKS_THREAD_NODE ThreadNode;\n} PH_THREAD_STACKS_WALK_CONTEXT, *PPH_THREAD_STACKS_WALK_CONTEXT;\n\nstatic PPH_OBJECT_TYPE PhpThreadStacksObjectType = NULL;\nstatic PPH_OBJECT_TYPE PhpThreadStacksWorkerObjectType = NULL;\nstatic PPH_OBJECT_TYPE PhpThreadStacksNodeObjectType = NULL;\n\nconst ACCESS_MASK PhpThreadStacksThreadAccessMasks[] =\n{\n    THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME,\n    THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT,\n    THREAD_QUERY_LIMITED_INFORMATION,\n};\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpThreadStacksNodeDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_THREAD_STACKS_NODE node = Object;\n\n    PhDereferenceObject(node->Symbol);\n\n    switch (node->Type)\n    {\n    case PhThreadStacksNodeTypeProcess:\n        {\n            PhClearReference(&node->Process.SymbolProvider);\n            PhDereferenceObject(node->Process.ProcessName);\n            PhClearReference(&node->Process.FileName);\n            PhDereferenceObject(node->Process.Threads);\n        }\n        break;\n    case PhThreadStacksNodeTypeThread:\n        {\n            if (node->Thread.ThreadHandle)\n                NtClose(node->Thread.ThreadHandle);\n            PhClearReference(&node->Thread.ThreadName);\n            PhDereferenceObject(node->Thread.Frames);\n            PhClearReference(&node->Thread.StartAddressSymbol);\n            PhClearReference(&node->Thread.FileName);\n        }\n        break;\n    case PhThreadStacksNodeTypeFrame:\n        {\n            PhClearReference(&node->Frame.FileName);\n            PhClearReference(&node->Frame.LineText);\n            PhClearReference(&node->Frame.FrameDistanceString);\n        }\n        break;\n    }\n}\n\nPPH_THREAD_STACKS_NODE PhpThreadStacksCreateNode(\n    _In_ PH_THREAD_STACKS_NODE_TYPE Type\n    )\n{\n    PPH_THREAD_STACKS_NODE node;\n\n    node = PhCreateObjectZero(sizeof(PH_THREAD_STACKS_NODE), PhpThreadStacksNodeObjectType);\n\n    PhInitializeTreeNewNode(&node->Node);\n\n    node->Type = Type;\n\n    memset(node->TextCache, 0, sizeof(PH_STRINGREF) * MAX_PH_THREAD_STACKS_COLUMN);\n    node->Node.TextCache = node->TextCache;\n    node->Node.TextCacheSize = MAX_PH_THREAD_STACKS_COLUMN;\n\n    return node;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpThreadStacksWorkerContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_THREAD_STACKS_WORKER_CONTEXT context = Object;\n\n    for (ULONG i = 0; i < context->NodeList->Count; i++)\n    {\n        PhDereferenceObject(context->NodeList->Items[i]);\n    }\n\n    PhClearReference(&context->Context);\n    PhDereferenceObject(context->NodeList);\n    PhDereferenceObject(context->NodeRootList);\n}\n\nPPH_THREAD_STACKS_WORKER_CONTEXT PhpThreadStacksCreateWorkerContext(\n    _In_ PPH_THREAD_STACKS_CONTEXT Context\n    )\n{\n    PPH_THREAD_STACKS_WORKER_CONTEXT context;\n\n    context = PhCreateObjectZero(sizeof(PH_THREAD_STACKS_WORKER_CONTEXT), PhpThreadStacksWorkerObjectType);\n\n    context->Context = Context;\n    PhReferenceObject(context->Context);\n\n    context->NodeList = PhCreateList(500);\n    context->NodeRootList = PhCreateList(100);\n\n    return context;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpThreadStacksContextDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_THREAD_STACKS_CONTEXT context = Object;\n\n    PhClearReference(&context->WorkerContext);\n\n    for (ULONG i = 0; i < context->NodeList->Count; i++)\n    {\n        PhDereferenceObject(context->NodeList->Items[i]);\n    }\n\n    PhDereferenceObject(context->NodeList);\n    PhDereferenceObject(context->NodeRootList);\n    PhDereferenceObject(context->StatusMessage);\n    PhDereferenceObject(context->SymbolMessage);\n}\n\nPPH_THREAD_STACKS_CONTEXT PhpThreadStacksCreateContext(\n    VOID\n    )\n{\n    PPH_THREAD_STACKS_CONTEXT context;\n\n    context = PhCreateObjectZero(sizeof(PH_THREAD_STACKS_CONTEXT), PhpThreadStacksObjectType);\n\n    context->NodeList = PhCreateList(500);\n    context->NodeRootList = PhCreateList(100);\n\n    context->StatusMessage = PhReferenceEmptyString();\n    context->SymbolMessage = PhReferenceEmptyString();\n    PhInitializeQueuedLock(&context->MessageLock);\n\n    return context;\n}\n\nVOID PhpThreadStacksMessage(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context,\n    _In_ __format_string PCWSTR Format,\n    ...\n    )\n{\n    PPH_THREAD_STACKS_CONTEXT context = Context->Context;\n    PPH_STRING message;\n    va_list args;\n\n    if (Context->Stop)\n        return;\n\n    va_start(args, Format);\n    message = PhFormatString_V(Format, args);\n    va_end(args);\n\n    PhAcquireQueuedLockExclusive(&context->MessageLock);\n    PhMoveReference(&context->StatusMessage, message);\n    context->MessageCount++;\n    PhReleaseQueuedLockExclusive(&context->MessageLock);\n}\n\nVOID PhpThreadStacksPublish(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context,\n    _In_ BOOLEAN Restructure,\n    _In_opt_ PPH_THREAD_STACKS_NODE Node\n    )\n{\n    PPH_THREAD_STACKS_CONTEXT context = Context->Context;\n\n    if (Context->Stop)\n        return;\n\n    if (Node)\n        PhReferenceObject(Node);\n\n    PostMessage(context->WindowHandle, WM_PH_THREAD_STACKS_PUBLISH, (WPARAM)Restructure, (LPARAM)Node);\n}\n\nVOID PhpThreadStacksCreateThreadNode(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context,\n    _In_ PPH_THREAD_STACKS_PROCESS_NODE ProcessNode,\n    _In_ PSYSTEM_THREAD_INFORMATION ThreadInfo\n    )\n{\n    PPH_THREAD_STACKS_NODE node;\n\n    node = PhpThreadStacksCreateNode(PhThreadStacksNodeTypeThread);\n\n    PhAddItemList(Context->NodeList, node);\n    PhAddItemList(ProcessNode->Threads, node);\n\n    node->Thread.Process = ProcessNode;\n\n    node->Thread.ThreadId = ThreadInfo->ClientId.UniqueThread;\n    PhPrintUInt32(node->Thread.ThreadIdString, HandleToUlong(node->Thread.ThreadId));\n\n    for (ULONG i = 0; i < ARRAYSIZE(PhpThreadStacksThreadAccessMasks); i++)\n    {\n        if (NT_SUCCESS(PhOpenThread(&node->Thread.ThreadHandle, PhpThreadStacksThreadAccessMasks[i], node->Thread.ThreadId)))\n            break;\n    }\n\n    if (node->Thread.ThreadHandle)\n    {\n        ULONG_PTR startAddress;\n\n        if (NT_SUCCESS(PhGetThreadStartAddress(node->Thread.ThreadHandle, &startAddress)))\n            node->Thread.StartAddress = (PVOID)startAddress;\n\n        PhGetThreadName(node->Thread.ThreadHandle, &node->Thread.ThreadName);\n    }\n\n    if (!node->Thread.StartAddress)\n        node->Thread.StartAddress = (PVOID)ThreadInfo->StartAddress;\n\n    PhPrintPointer(node->Thread.StartAddressString, node->Thread.StartAddress);\n\n    if (!PhIsNullOrEmptyString(node->Thread.ThreadName))\n        node->Symbol = PhReferenceObject(node->Thread.ThreadName);\n    else\n        node->Symbol = PhCreateString(node->Thread.StartAddressString);\n\n    node->Thread.Frames = PhCreateList(10);\n\n    Context->TotalThreads++;\n\n    PhpThreadStacksPublish(Context, FALSE, node);\n}\n\nVOID PhpThreadStacksCreateProcessNode(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context,\n    _In_ PSYSTEM_PROCESS_INFORMATION ProcessInfo\n    )\n{\n    PPH_THREAD_STACKS_NODE node;\n    HANDLE processHandle;\n\n    node = PhpThreadStacksCreateNode(PhThreadStacksNodeTypeProcess);\n\n    PhAddItemList(Context->NodeList, node);\n    PhAddItemList(Context->NodeRootList, node);\n\n    node->Process.ProcessId = ProcessInfo->UniqueProcessId;\n    PhPrintUInt32(node->Process.ProcessIdString, HandleToUlong(node->Process.ProcessId));\n\n    node->Process.SymbolProvider = PhCreateSymbolProvider(node->Process.ProcessId);\n\n    PhLoadSymbolProviderOptions(node->Process.SymbolProvider);\n\n    if (node->Process.ProcessId != SYSTEM_IDLE_PROCESS_ID)\n        node->Process.ProcessName = PhCreateStringFromUnicodeString(&ProcessInfo->ImageName);\n    else\n        node->Process.ProcessName = PhCreateStringFromUnicodeString(&SYSTEM_IDLE_PROCESS_NAME);\n\n    node->Symbol = PhReferenceObject(node->Process.ProcessName);\n\n    if (node->Process.ProcessId == SYSTEM_PROCESS_ID)\n        node->Process.FileName = PhGetKernelFileName();\n\n    if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, node->Process.ProcessId)))\n    {\n        USHORT machine;\n\n        if (!node->Process.FileName)\n            PhGetProcessImageFileName(processHandle, &node->Process.FileName);\n\n        if (NT_SUCCESS(PhGetProcessArchitecture(processHandle, &machine)))\n        {\n            switch (machine)\n            {\n            case IMAGE_FILE_MACHINE_I386:\n                PhInitializeStringRef(&node->Process.Architecture, L\"x86\");\n                break;\n            case IMAGE_FILE_MACHINE_AMD64:\n                PhInitializeStringRef(&node->Process.Architecture, L\"x64\");\n                break;\n            case IMAGE_FILE_MACHINE_ARMNT:\n                PhInitializeStringRef(&node->Process.Architecture, L\"ARM\");\n                break;\n            case IMAGE_FILE_MACHINE_ARM64:\n                PhInitializeStringRef(&node->Process.Architecture, L\"ARM64\");\n                break;\n            default:\n                PhInitializeEmptyStringRef(&node->Process.Architecture);\n                break;\n            }\n        }\n        else\n        {\n            PhInitializeEmptyStringRef(&node->Process.Architecture);\n        }\n\n        NtClose(processHandle);\n    }\n\n    node->Process.Threads = PhCreateList(ProcessInfo->NumberOfThreads);\n    for (ULONG i = 0; i < ProcessInfo->NumberOfThreads; i++)\n    {\n        PSYSTEM_THREAD_INFORMATION threadInfo;\n\n        threadInfo = &ProcessInfo->Threads[i];\n\n        PhpThreadStacksCreateThreadNode(Context, &node->Process, threadInfo);\n    }\n\n    PhpThreadStacksPublish(Context, FALSE, node);\n}\n\nPPH_STRING PhpThreadStacksInitFrameNode(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context,\n    _In_ PPH_THREAD_STACKS_FRAME_NODE FrameNode,\n    _In_ PPH_THREAD_STACK_FRAME StackFrame\n    )\n{\n    PPH_STRING symbol = NULL;\n    PPH_STRING fileName = NULL;\n    PPH_STRING lineText = NULL;\n    PVOID baseAddress = NULL;\n    PPH_STRING lineFileName;\n    PH_SYMBOL_LINE_INFORMATION lineInfo;\n\n    if (PhSymbolProviderInlineContextSupported())\n    {\n        symbol = PhGetSymbolFromInlineContext(\n            FrameNode->Thread->Process->SymbolProvider,\n            StackFrame,\n            NULL,\n            &fileName,\n            NULL,\n            NULL,\n            &baseAddress\n            );\n\n        if (PhPluginsEnabled)\n        {\n            PH_PLUGIN_THREAD_STACK_CONTROL control;\n\n            control.Type = PluginThreadStackResolveSymbol;\n            control.UniqueKey = Context;\n            control.u.ResolveSymbol.StackFrame = StackFrame;\n            control.u.ResolveSymbol.Symbol = symbol;\n            control.u.ResolveSymbol.FileName = fileName;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n\n            symbol = control.u.ResolveSymbol.Symbol;\n            fileName = control.u.ResolveSymbol.FileName;\n        }\n\n        if (PhGetLineFromInlineContext(\n            FrameNode->Thread->Process->SymbolProvider,\n            StackFrame,\n            baseAddress,\n            &lineFileName,\n            NULL,\n            &lineInfo\n            ))\n        {\n            PH_FORMAT format[3];\n\n            PhInitFormatSR(&format[0], lineFileName->sr);\n            PhInitFormatS(&format[1], L\" @ \");\n            PhInitFormatU(&format[2], lineInfo.LineNumber);\n\n            lineText = PhFormat(format, RTL_NUMBER_OF(format), 0);\n            PhDereferenceObject(lineFileName);\n        }\n    }\n    else\n    {\n        symbol = PhGetSymbolFromAddress(\n            FrameNode->Thread->Process->SymbolProvider,\n            StackFrame->PcAddress,\n            NULL,\n            &fileName,\n            NULL,\n            NULL\n            );\n\n        if (PhPluginsEnabled)\n        {\n            PH_PLUGIN_THREAD_STACK_CONTROL control;\n\n            control.Type = PluginThreadStackResolveSymbol;\n            control.UniqueKey = Context;\n            control.u.ResolveSymbol.StackFrame = StackFrame;\n            control.u.ResolveSymbol.Symbol = symbol;\n            control.u.ResolveSymbol.FileName = fileName;\n\n            PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n\n            symbol = control.u.ResolveSymbol.Symbol;\n            fileName = control.u.ResolveSymbol.FileName;\n        }\n\n        if (PhGetLineFromAddress(\n            FrameNode->Thread->Process->SymbolProvider,\n            StackFrame->PcAddress,\n            &lineFileName,\n            NULL,\n            &lineInfo\n            ))\n        {\n            PH_FORMAT format[3];\n\n            PhInitFormatSR(&format[0], lineFileName->sr);\n            PhInitFormatS(&format[1], L\" @ \");\n            PhInitFormatU(&format[2], lineInfo.LineNumber);\n\n            lineText = PhFormat(format, RTL_NUMBER_OF(format), 0);\n            PhDereferenceObject(lineFileName);\n        }\n    }\n\n    FrameNode->StackFrame = *StackFrame;\n\n    if (symbol &&\n        (FrameNode->StackFrame.Machine == IMAGE_FILE_MACHINE_I386) &&\n        FlagOn(FrameNode->StackFrame.Flags, PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT))\n    {\n        PhMoveReference(&symbol, PhConcatStringRefZ(&symbol->sr, L\" (No unwind info)\"));\n    }\n\n    if (PhSymbolProviderInlineContextSupported() &&\n        PhIsStackFrameTypeInline(FrameNode->StackFrame.InlineFrameContext))\n    {\n        if (symbol)\n            PhMoveReference(&symbol, PhConcatStringRefZ(&symbol->sr, L\" (Inline Function)\"));\n\n        // Zero inline frames so the stack matches windbg output.\n        FrameNode->StackFrame.PcAddress = NULL;\n        FrameNode->StackFrame.ReturnAddress = NULL;\n        FrameNode->StackFrame.FrameAddress = NULL;\n        FrameNode->StackFrame.StackAddress = NULL;\n        memset(FrameNode->StackFrame.Params, 0, sizeof(FrameNode->StackFrame.Params));\n    }\n\n    if (FrameNode->StackFrame.StackAddress)\n    {\n        PhPrintPointer(FrameNode->StackAddressString, (PVOID)FrameNode->StackFrame.StackAddress);\n\n        if (FrameNode->FrameNumber > 0)\n        {\n            PPH_THREAD_STACKS_NODE prev = FrameNode->Thread->Frames->Items[FrameNode->FrameNumber - 1];\n\n            if (prev->Frame.StackFrame.StackAddress)\n            {\n                FrameNode->FrameDistance = (ULONG)((ULONG_PTR)FrameNode->StackFrame.StackAddress - (ULONG_PTR)prev->Frame.StackFrame.StackAddress);\n                FrameNode->FrameDistanceString = PhFormatSize(FrameNode->FrameDistance, ULONG_MAX);\n            }\n        }\n    }\n\n    // There are no parameters for kernel-mode frames.\n    if ((ULONG_PTR)FrameNode->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress)\n    {\n        PhPrintPointer(FrameNode->Parameter1String, FrameNode->StackFrame.Params[0]);\n        PhPrintPointer(FrameNode->Parameter2String, FrameNode->StackFrame.Params[1]);\n        PhPrintPointer(FrameNode->Parameter3String, FrameNode->StackFrame.Params[2]);\n        PhPrintPointer(FrameNode->Parameter4String, FrameNode->StackFrame.Params[3]);\n    }\n\n    if (FrameNode->StackFrame.PcAddress)\n        PhPrintPointer(FrameNode->PcAddressString, (PVOID)FrameNode->StackFrame.PcAddress);\n\n    if (FrameNode->StackFrame.ReturnAddress)\n        PhPrintPointer(FrameNode->ReturnAddressString, (PVOID)FrameNode->StackFrame.ReturnAddress);\n\n    switch (FrameNode->StackFrame.Machine)\n    {\n    case IMAGE_FILE_MACHINE_ARM64EC:\n        PhInitializeStringRef(&FrameNode->Architecture, L\"ARM64EC\");\n        break;\n    case IMAGE_FILE_MACHINE_CHPE_X86:\n        PhInitializeStringRef(&FrameNode->Architecture, L\"CHPE\");\n        break;\n    case IMAGE_FILE_MACHINE_ARM64:\n        PhInitializeStringRef(&FrameNode->Architecture, L\"ARM64\");\n        break;\n    case IMAGE_FILE_MACHINE_ARM:\n        PhInitializeStringRef(&FrameNode->Architecture, L\"ARM\");\n        break;\n    case IMAGE_FILE_MACHINE_AMD64:\n        PhInitializeStringRef(&FrameNode->Architecture, L\"x64\");\n        break;\n    case IMAGE_FILE_MACHINE_I386:\n        PhInitializeStringRef(&FrameNode->Architecture, L\"x86\");\n        break;\n    default:\n        PhInitializeStringRef(&FrameNode->Architecture, L\"\");\n        break;\n    }\n\n    PhMoveReference(&FrameNode->FileName, fileName);\n    PhMoveReference(&FrameNode->LineText, lineText);\n\n    return symbol;\n}\n\nVOID PhpThreadStacksCreateFrameNode(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context,\n    _In_ PPH_THREAD_STACKS_THREAD_NODE ThreadNode,\n    _In_ PPH_THREAD_STACK_FRAME StackFrame\n    )\n{\n    PPH_THREAD_STACKS_NODE node;\n\n    node = PhpThreadStacksCreateNode(PhThreadStacksNodeTypeFrame);\n\n    // frame nodes will become visible during publishing\n    node->Node.Visible = FALSE;\n\n    node->Frame.Thread = ThreadNode;\n    node->Frame.FrameNumber = ThreadNode->Frames->Count;\n\n    PhAddItemList(Context->NodeList, node);\n    PhAddItemList(ThreadNode->Frames, node);\n\n    PhPrintUInt32(node->Frame.FrameNumberString, node->Frame.FrameNumber);\n\n    node->Symbol = PhpThreadStacksInitFrameNode(Context, &node->Frame, StackFrame);\n\n    PhpThreadStacksPublish(Context, FALSE, node);\n}\n\nVOID PhpThreadStacksWorkerPhase1(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context\n    )\n{\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n\n    if (!NT_SUCCESS(PhEnumProcesses(&processes)))\n        return;\n\n    process = PH_FIRST_PROCESS(processes);\n\n    PhpThreadStacksMessage(Context, L\"Enumerating processes...\");\n\n    do\n    {\n        PhpThreadStacksCreateProcessNode(Context, process);\n    } while (process = PH_NEXT_PROCESS(process));\n\n    PhFree(processes);\n\n    PhpThreadStacksPublish(Context, TRUE, NULL);\n}\n\nBOOLEAN NTAPI PhpThreadStacksWalkCallback(\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREAD_STACKS_WALK_CONTEXT context = Context;\n\n    if (context->Context->Stop)\n        return FALSE;\n\n    PhpThreadStacksCreateFrameNode(context->Context, context->ThreadNode, StackFrame);\n\n    return TRUE;\n}\n\nVOID PhpThreadStacksThreadPhase2(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context,\n    _In_ PPH_THREAD_STACKS_THREAD_NODE ThreadNode\n    )\n{\n    PH_THREAD_STACKS_WALK_CONTEXT context;\n    CLIENT_ID clientId;\n\n    if (!ThreadNode->ThreadHandle)\n        return;\n\n    clientId.UniqueProcess = ThreadNode->Process->ProcessId;\n    clientId.UniqueThread = ThreadNode->ThreadId;\n\n    context.Context = Context;\n    context.ThreadNode = ThreadNode;\n\n    PhWalkThreadStack(\n        ThreadNode->ThreadHandle,\n        ThreadNode->Process->SymbolProvider->ProcessHandle,\n        &clientId,\n        ThreadNode->Process->SymbolProvider,\n        PH_WALK_USER_WOW64_STACK | PH_WALK_USER_STACK | PH_WALK_KERNEL_STACK,\n        PhpThreadStacksWalkCallback,\n        &context\n        );\n}\n\nVOID PhpThreadStacksProcessPhase2(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context,\n    _In_ PPH_THREAD_STACKS_PROCESS_NODE ProcessNode\n    )\n{\n    for (ULONG i = 0; i < ProcessNode->Threads->Count; i++)\n    {\n        PPH_THREAD_STACKS_NODE node = ProcessNode->Threads->Items[i];\n\n        PhpThreadStacksMessage(\n            Context,\n            L\"Walking stacks... %lu%% - %ls (%lu) %lu%%\",\n            (ULONG)(((FLOAT)Context->WalkedThreads / (FLOAT)Context->TotalThreads) * 100),\n            ProcessNode->ProcessName->Buffer,\n            HandleToUlong(ProcessNode->ProcessId),\n            (ULONG)(((FLOAT)(i + 1) / ProcessNode->Threads->Count) * 100)\n            );\n\n        // Resolve the start address symbol.\n        node->Thread.StartAddressSymbol = PhGetSymbolFromAddress(\n            ProcessNode->SymbolProvider,\n            node->Thread.StartAddress,\n            NULL,\n            &node->Thread.FileName,\n            NULL,\n            NULL\n            );\n\n        if (node->Symbol == node->Thread.ThreadName)\n        {\n            // Keep the thread name as the symbol.\n            NOTHING;\n        }\n        else if (node->Thread.StartAddressSymbol)\n        {\n            PhMoveReference(&node->Symbol, PhReferenceObject(node->Thread.StartAddressSymbol));\n        }\n\n        PhpThreadStacksThreadPhase2(Context, &node->Thread);\n\n        Context->WalkedThreads++;\n        node->Thread.FramesComplete = TRUE;\n\n        PhpThreadStacksPublish(Context, TRUE, NULL);\n\n        if (Context->Stop)\n            break;\n    }\n}\n\nVOID PhpThreadStacksWorkerPhase2(\n    _In_ PPH_THREAD_STACKS_WORKER_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeRootList->Count; i++)\n    {\n        PPH_THREAD_STACKS_NODE node = Context->NodeRootList->Items[i];\n\n        PhpThreadStacksMessage(\n            Context,\n            L\"Walking stacks... %lu%% - %ls (%lu)\",\n            (ULONG)(((FLOAT)Context->WalkedThreads / (FLOAT)Context->TotalThreads) * 100),\n            node->Process.ProcessName->Buffer,\n            HandleToUlong(node->Process.ProcessId)\n            );\n\n        PhLoadSymbolProviderModules(node->Process.SymbolProvider, node->Process.ProcessId);\n\n        PhpThreadStacksProcessPhase2(Context, &node->Process);\n\n        // Clean up the symbol provider as soon as possible.\n        PhClearReference(&node->Process.SymbolProvider);\n\n        if (Context->Stop)\n            break;\n    }\n}\n\nNTSTATUS PhpThreadStacksWorkerThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_THREAD_STACKS_WORKER_CONTEXT context = Parameter;\n    PH_PLUGIN_THREAD_STACK_CONTROL control;\n\n    control.UniqueKey = context;\n\n    if (PhPluginsEnabled)\n    {\n        control.Type = PluginThreadStackBeginDefaultWalkStack;\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n    }\n\n    // Phase 1 enumerates processes and threads\n    PhpThreadStacksWorkerPhase1(context);\n\n    // Phase 2 walks stacks, resolves symbols, and creates frame nodes\n    PhpThreadStacksWorkerPhase2(context);\n\n    if (PhPluginsEnabled)\n    {\n        control.Type = PluginThreadStackEndDefaultWalkStack;\n        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control);\n    }\n\n    PhpThreadStacksMessage(context, L\"\");\n\n    PhClearReference(&context->Context);\n\n    PhDereferenceObject(context);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpThreadStacksRefresh(\n    _In_ PPH_THREAD_STACKS_CONTEXT Context\n    )\n{\n    PPH_THREAD_STACKS_WORKER_CONTEXT context;\n\n    if (Context->WorkerContext)\n        InterlockedIncrement(&Context->WorkerContext->Stop);\n\n    context = PhpThreadStacksCreateWorkerContext(Context);\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        PhDereferenceObject(Context->NodeList->Items[i]);\n\n    PhClearList(Context->NodeList);\n    PhClearList(Context->NodeRootList);\n\n    PhMoveReference(&Context->WorkerContext, PhReferenceObject(context));\n\n    if (!NT_SUCCESS(PhCreateThread2(PhpThreadStacksWorkerThreadStart, context)))\n        PhDereferenceObject(context);\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhpThreadStacksExpandNodes(\n    _In_ PPH_THREAD_STACKS_CONTEXT Context,\n    _In_ BOOLEAN Expand\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_THREAD_STACKS_NODE node = Context->NodeList->Items[i];\n\n        node->Node.Expanded = Expand;\n    }\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\nVOID PhpThreadStacksInvalidateNodes(\n    _In_ PPH_THREAD_STACKS_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_THREAD_STACKS_NODE node = Context->NodeList->Items[i];\n\n        PhInvalidateTreeNewNode(&node->Node, TN_CACHE_COLOR);\n        TreeNew_InvalidateNode(Context->TreeNewHandle, &node->Node);\n    }\n}\n\nBOOLEAN PhpThreadStackFrameVisible(\n    _In_ PPH_THREAD_STACKS_CONTEXT Context,\n    _In_ PPH_THREAD_STACKS_FRAME_NODE FrameNode,\n    _In_ BOOLEAN Matched\n    )\n{\n    if (Context->HideSystemFrames && (ULONG_PTR)FrameNode->StackFrame.PcAddress > PhSystemBasicInformation.MaximumUserModeAddress)\n        return FALSE;\n    if (Context->HideUserFrames && (ULONG_PTR)FrameNode->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress)\n        return FALSE;\n    if (Context->HideInlineFrames && PhIsStackFrameTypeInline(FrameNode->StackFrame.InlineFrameContext))\n        return FALSE;\n\n    return Matched;\n}\n\nVOID PhpThreadStacksRestructureNodesWithSearch(\n    _In_ PPH_THREAD_STACKS_CONTEXT Context\n    )\n{\n    if (!Context->SearchMatchHandle)\n    {\n        for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        {\n            PPH_THREAD_STACKS_NODE node = Context->NodeList->Items[i];\n\n            if (node->Type == PhThreadStacksNodeTypeFrame)\n                node->Node.Visible = PhpThreadStackFrameVisible(Context, &node->Frame, TRUE);\n            else\n                node->Node.Visible = TRUE;\n        }\n\n        TreeNew_NodesStructured(Context->TreeNewHandle);\n        return;\n    }\n\n    // We only search for symbols in stack frames when searching, if any frame\n    // matches the entire ancestry related to the node is made visible.\n    for (ULONG i = 0; i < Context->NodeRootList->Count; i++)\n    {\n        PPH_THREAD_STACKS_NODE processNode = Context->NodeRootList->Items[i];\n\n        processNode->Node.Visible = FALSE;\n\n        for (ULONG j = 0; j < processNode->Process.Threads->Count; j++)\n        {\n            PPH_THREAD_STACKS_NODE threadNode = processNode->Process.Threads->Items[j];\n            BOOLEAN match;\n\n            threadNode->Node.Visible = FALSE;\n\n            if (!threadNode->Thread.FramesComplete)\n            {\n                continue;\n            }\n\n            match = FALSE;\n\n            for (ULONG k = 0; k < threadNode->Thread.Frames->Count; k++)\n            {\n                PPH_THREAD_STACKS_NODE frameNode = threadNode->Thread.Frames->Items[k];\n\n                frameNode->Node.Visible = PhpThreadStackFrameVisible(Context, &frameNode->Frame, match);\n\n                if (match || !PhSearchControlMatch(Context->SearchMatchHandle, &frameNode->Symbol->sr))\n                    continue;\n\n                match = TRUE;\n\n                threadNode->Node.Visible = TRUE;\n                processNode->Node.Visible = TRUE;\n\n                for (ULONG l = 0; l <= k; l++)\n                {\n                    PPH_THREAD_STACKS_NODE prevFrameNode = threadNode->Thread.Frames->Items[l];\n                    prevFrameNode->Node.Visible = PhpThreadStackFrameVisible(Context, &frameNode->Frame, TRUE);\n                }\n            }\n        }\n    }\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhpThreadStacksSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_THREAD_STACKS_CONTEXT context = Context;\n\n    assert(context);\n\n    context->SearchMatchHandle = MatchHandle;\n\n    PhpThreadStacksRestructureNodesWithSearch(context);\n}\n\nBOOLEAN NTAPI PhpThreadStacksTreeNewCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_THREAD_STACKS_CONTEXT context = Context;\n    PPH_THREAD_STACKS_NODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_THREAD_STACKS_NODE)getChildren->Node;\n\n            if (!getChildren->Node)\n            {\n                getChildren->Children = (PPH_TREENEW_NODE*)context->NodeRootList->Items;\n                getChildren->NumberOfChildren = context->NodeRootList->Count;\n            }\n            else\n            {\n                switch (node->Type)\n                {\n                case PhThreadStacksNodeTypeProcess:\n                    getChildren->Children = (PPH_TREENEW_NODE*)node->Process.Threads->Items;\n                    getChildren->NumberOfChildren = node->Process.Threads->Count;\n                    break;\n                case PhThreadStacksNodeTypeThread:\n                    getChildren->Children = (PPH_TREENEW_NODE*)node->Thread.Frames->Items;\n                    getChildren->NumberOfChildren = node->Thread.Frames->Count;\n                    break;\n                case PhThreadStacksNodeTypeFrame:\n                default:\n                    getChildren->Children = NULL;\n                    getChildren->NumberOfChildren = 0;\n                    break;\n                }\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n            node = (PPH_THREAD_STACKS_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = node->Type == PhThreadStacksNodeTypeFrame;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            node = (PPH_THREAD_STACKS_NODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case PH_THREAD_STACKS_COLUMN_SYMBOL:\n                getCellText->Text = PhGetStringRef(node->Symbol);\n                break;\n            case PH_THREAD_STACKS_COLUMN_PROCESSID:\n                {\n                    switch (node->Type)\n                    {\n                    case PhThreadStacksNodeTypeProcess:\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->Process.ProcessIdString);\n                        break;\n                    case PhThreadStacksNodeTypeThread:\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->Thread.Process->ProcessIdString);\n                        break;\n                    case PhThreadStacksNodeTypeFrame:\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.Thread->Process->ProcessIdString);\n                        break;\n                    }\n                }\n                break;\n            case PH_THREAD_STACKS_COLUMN_THREADID:\n                {\n                    switch (node->Type)\n                    {\n                    case PhThreadStacksNodeTypeThread:\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->Thread.ThreadIdString);\n                        break;\n                    case PhThreadStacksNodeTypeFrame:\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.Thread->ThreadIdString);\n                        break;\n                    }\n                }\n                break;\n            case PH_THREAD_STACKS_COLUMN_FRAMENUMBER:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.FrameNumberString);\n                break;\n            case PH_THREAD_STACKS_COLUMN_STACKADDRESS:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.StackAddressString);\n                break;\n            case PH_THREAD_STACKS_COLUMN_FRAMEADDRESS:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.FrameAddressString);\n                break;\n            case PH_THREAD_STACKS_COLUMN_PARAMETER1:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.Parameter1String);\n                break;\n            case PH_THREAD_STACKS_COLUMN_PARAMETER2:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.Parameter2String);\n                break;\n            case PH_THREAD_STACKS_COLUMN_PARAMETER3:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.Parameter3String);\n                break;\n            case PH_THREAD_STACKS_COLUMN_PARAMETER4:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.Parameter4String);\n                break;\n            case PH_THREAD_STACKS_COLUMN_CONTROLADDRESS:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.PcAddressString);\n                break;\n            case PH_THREAD_STACKS_COLUMN_RETURNADDRESS:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.ReturnAddressString);\n                break;\n            case PH_THREAD_STACKS_COLUMN_FILENAME:\n                {\n                    switch (node->Type)\n                    {\n                    case PhThreadStacksNodeTypeProcess:\n                        getCellText->Text = PhGetStringRef(node->Process.FileName);\n                        break;\n                    case PhThreadStacksNodeTypeThread:\n                        getCellText->Text = PhGetStringRef(node->Thread.FileName);\n                        break;\n                    case PhThreadStacksNodeTypeFrame:\n                        getCellText->Text = PhGetStringRef(node->Frame.FileName);\n                        break;\n                    }\n                }\n                break;\n            case PH_THREAD_STACKS_COLUMN_LINETEXT:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    getCellText->Text = PhGetStringRef(node->Frame.LineText);\n                break;\n            case PH_THREAD_STACKS_COLUMN_ARCHITECTURE:\n                {\n                    switch (node->Type)\n                    {\n                    case PhThreadStacksNodeTypeProcess:\n                        getCellText->Text = node->Process.Architecture;\n                        break;\n                    case PhThreadStacksNodeTypeFrame:\n                        getCellText->Text = node->Frame.Architecture;\n                        break;\n                    }\n                }\n                break;\n            case PH_THREAD_STACKS_COLUMN_FRAMEDISTANCE:\n                if (node->Type == PhThreadStacksNodeTypeFrame)\n                    getCellText->Text = PhGetStringRef(node->Frame.FrameDistanceString);\n                break;\n            case PH_THREAD_STACKS_COLUMN_STARTADDRESS:\n                {\n                    switch (node->Type)\n                    {\n                    case PhThreadStacksNodeTypeThread:\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->Thread.StartAddressString);\n                        break;\n                    case PhThreadStacksNodeTypeFrame:\n                        PhInitializeStringRefLongHint(&getCellText->Text, node->Frame.Thread->StartAddressString);\n                        break;\n                    }\n                }\n                break;\n            case PH_THREAD_STACKS_COLUMN_STARTADDRESSSYMBOL:\n                {\n                    switch (node->Type)\n                    {\n                    case PhThreadStacksNodeTypeThread:\n                        getCellText->Text = PhGetStringRef(node->Thread.StartAddressSymbol);\n                        break;\n                    case PhThreadStacksNodeTypeFrame:\n                        getCellText->Text = PhGetStringRef(node->Frame.Thread->StartAddressSymbol);\n                        break;\n                    }\n                }\n                break;\n            case PH_THREAD_STACKS_COLUMN_PROCESSNAME:\n                {\n                    switch (node->Type)\n                    {\n                    case PhThreadStacksNodeTypeProcess:\n                        getCellText->Text = PhGetStringRef(node->Process.ProcessName);\n                        break;\n                    case PhThreadStacksNodeTypeThread:\n                        getCellText->Text = PhGetStringRef(node->Thread.Process->ProcessName);\n                        break;\n                    case PhThreadStacksNodeTypeFrame:\n                        getCellText->Text = PhGetStringRef(node->Frame.Thread->Process->ProcessName);\n                        break;\n                    }\n                }\n                break;\n            case PH_THREAD_STACKS_COLUMN_THREADNAME:\n                {\n                    switch (node->Type)\n                    {\n                    case PhThreadStacksNodeTypeThread:\n                        getCellText->Text = PhGetStringRef(node->Thread.ThreadName);\n                        break;\n                    case PhThreadStacksNodeTypeFrame:\n                        getCellText->Text = PhGetStringRef(node->Frame.Thread->ThreadName);\n                        break;\n                    }\n                }\n                break;\n            default:\n                return FALSE;\n            }\n\n            switch (node->Type)\n                {\n                case PhThreadStacksNodeTypeProcess:\n                    getCellText->Flags = TN_CACHE;\n                    break;\n                case PhThreadStacksNodeTypeThread:\n                    if (node->Thread.FramesComplete)\n                        getCellText->Flags = TN_CACHE;\n                    break;\n                case PhThreadStacksNodeTypeFrame:\n                    if (node->Frame.Thread->FramesComplete)\n                        getCellText->Flags = TN_CACHE;\n                    break;\n                }\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;\n            node = (PPH_THREAD_STACKS_NODE)getNodeColor->Node;\n\n            if (node->Type == PhThreadStacksNodeTypeFrame)\n            {\n                if (context->HighlightInlineFrames && PhIsStackFrameTypeInline(node->Frame.StackFrame.InlineFrameContext))\n                    getNodeColor->BackColor = PhGetIntegerSetting(SETTING_COLOR_INLINE_THREAD_STACK);\n                else if (context->HighlightSystemFrames && (ULONG_PTR)node->Frame.StackFrame.PcAddress > PhSystemBasicInformation.MaximumUserModeAddress)\n                    getNodeColor->BackColor = PhGetIntegerSetting(SETTING_COLOR_SYSTEM_THREAD_STACK);\n                else if (context->HighlightUserFrames && (ULONG_PTR)node->Frame.StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress)\n                    getNodeColor->BackColor = PhGetIntegerSetting(SETTING_COLOR_USER_THREAD_STACK);\n\n                getNodeColor->Flags = TN_AUTO_FORECOLOR;\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = hwnd;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortOrder = NoSortOrder;\n            data.DefaultSortColumn = 0;\n\n            PhInitializeTreeNewColumnMenuEx(&data, 0);\n\n            data.Selection = PhShowEMenu(\n                data.Menu,\n                hwnd,\n                PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                data.MouseEvent->ScreenLocation.x,\n                data.MouseEvent->ScreenLocation.y\n                );\n\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM selectedItem;\n            PPH_EMENU_ITEM gotoProcess;\n            PPH_EMENU_ITEM gotoThread;\n            PPH_EMENU_ITEM hideUserFrames;\n            PPH_EMENU_ITEM hideSystemFrames;\n            PPH_EMENU_ITEM hideInlineFrames;\n            PPH_EMENU_ITEM highlightUserFrames;\n            PPH_EMENU_ITEM highlightSystemFrames;\n            PPH_EMENU_ITEM highlightInlineFrames;\n\n            node = (PPH_THREAD_STACKS_NODE)contextMenuEvent->Node;\n\n            menu = PhCreateEMenu();\n            PhInsertEMenuItem(menu, gotoProcess = PhCreateEMenuItem(0, 1, L\"Go to process...\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, gotoThread = PhCreateEMenuItem(0, 2, L\"Go to thread...\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n            PhInsertEMenuItem(menu, hideUserFrames = PhCreateEMenuItem(0, 3, L\"Expand all\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, hideUserFrames = PhCreateEMenuItem(0, 4, L\"Collapse all\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n            PhInsertEMenuItem(menu, hideUserFrames = PhCreateEMenuItem(0, 5, L\"Hide user frames\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, hideSystemFrames = PhCreateEMenuItem(0, 6, L\"Hide system frames\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, hideInlineFrames = PhCreateEMenuItem(0, 7, L\"Hide inline frames\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n            PhInsertEMenuItem(menu, highlightUserFrames = PhCreateEMenuItem(0, 8, L\"Highlight user frames\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, highlightSystemFrames = PhCreateEMenuItem(0, 9, L\"Highlight system frames\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, highlightInlineFrames = PhCreateEMenuItem(0, 10, L\"Highlight inline frames\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 100, L\"Copy\", NULL, NULL), ULONG_MAX);\n            PhInsertCopyCellEMenuItem(menu, 100, hwnd, contextMenuEvent->Column);\n\n            if (node)\n            {\n                if (node->Type == PhThreadStacksNodeTypeProcess)\n                    PhSetDisabledEMenuItem(gotoThread);\n            }\n            else\n            {\n                PhSetDisabledEMenuItem(gotoProcess);\n                PhSetDisabledEMenuItem(gotoThread);\n            }\n\n            if (context->HideUserFrames)\n                hideUserFrames->Flags |= PH_EMENU_CHECKED;\n            if (context->HideSystemFrames)\n                hideSystemFrames->Flags |= PH_EMENU_CHECKED;\n            if (context->HideInlineFrames)\n                hideInlineFrames->Flags |= PH_EMENU_CHECKED;\n            if (context->HighlightUserFrames)\n                highlightUserFrames->Flags |= PH_EMENU_CHECKED;\n            if (context->HighlightSystemFrames)\n                highlightSystemFrames->Flags |= PH_EMENU_CHECKED;\n            if (context->HighlightInlineFrames)\n                highlightInlineFrames->Flags |= PH_EMENU_CHECKED;\n\n            selectedItem = PhShowEMenu(\n                menu,\n                context->WindowHandle,\n                PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                contextMenuEvent->Location.x,\n                contextMenuEvent->Location.y\n                );\n\n            if (selectedItem && selectedItem->Id != ULONG_MAX && !PhHandleCopyCellEMenuItem(selectedItem))\n            {\n                switch (selectedItem->Id)\n                {\n                case 1:\n                    {\n                        PPH_PROCESS_ITEM processItem;\n                        HANDLE processId;\n\n                        assert(node);\n\n                        switch (node->Type)\n                        {\n                        case PhThreadStacksNodeTypeProcess:\n                            processId = node->Process.ProcessId;\n                            break;\n                        case PhThreadStacksNodeTypeThread:\n                            processId = node->Thread.Process->ProcessId;\n                            break;\n                        case PhThreadStacksNodeTypeFrame:\n                            processId = node->Frame.Thread->Process->ProcessId;\n                            break;\n                        DEFAULT_UNREACHABLE;\n                        }\n\n                        if (processItem = PhReferenceProcessItem(processId))\n                        {\n                            PPH_PROCESS_PROPCONTEXT propContext;\n\n                            if (propContext = PhCreateProcessPropContext(NULL, processItem))\n                            {\n                                PhShowProcessProperties(propContext);\n                                PhDereferenceObject(propContext);\n                            }\n\n                            PhDereferenceObject(processItem);\n                        }\n                    }\n                    break;\n                case 2:\n                    {\n                        PPH_PROCESS_ITEM processItem;\n                        HANDLE processId;\n                        HANDLE threadId;\n\n                        assert(node);\n                        assert(node->Type == PhThreadStacksNodeTypeThread ||\n                               node->Type == PhThreadStacksNodeTypeFrame);\n\n                        switch (node->Type)\n                        {\n                        case PhThreadStacksNodeTypeThread:\n                            processId = node->Thread.Process->ProcessId;\n                            threadId = node->Thread.ThreadId;\n                            break;\n                        case PhThreadStacksNodeTypeFrame:\n                            processId = node->Frame.Thread->Process->ProcessId;\n                            threadId = node->Frame.Thread->ThreadId;\n                            break;\n                        DEFAULT_UNREACHABLE;\n                        }\n\n                        if (processItem = PhReferenceProcessItem(processId))\n                        {\n                            PPH_PROCESS_PROPCONTEXT propContext;\n\n                            if (propContext = PhCreateProcessPropContext(NULL, processItem))\n                            {\n                                PhSetSelectThreadIdProcessPropContext(propContext, threadId);\n                                PhShowProcessProperties(propContext);\n                                PhDereferenceObject(propContext);\n                            }\n\n                            PhDereferenceObject(processItem);\n                        }\n                    }\n                    break;\n                case 3:\n                    PhpThreadStacksExpandNodes(context, TRUE);\n                    break;\n                case 4:\n                    PhpThreadStacksExpandNodes(context, FALSE);\n                    break;\n                case 5:\n                    context->HideUserFrames = !context->HideUserFrames;\n                    PhpThreadStacksRestructureNodesWithSearch(context);\n                    break;\n                case 6:\n                    context->HideSystemFrames = !context->HideSystemFrames;\n                    PhpThreadStacksRestructureNodesWithSearch(context);\n                    break;\n                case 7:\n                    context->HideInlineFrames = !context->HideInlineFrames;\n                    PhpThreadStacksRestructureNodesWithSearch(context);\n                    break;\n                case 8:\n                    context->HighlightUserFrames = !context->HighlightUserFrames;\n                    PhSetIntegerSetting(SETTING_USE_COLOR_USER_THREAD_STACK, context->HighlightUserFrames);\n                    PhpThreadStacksInvalidateNodes(context);\n                    break;\n                case 9:\n                    context->HighlightSystemFrames = !context->HighlightSystemFrames;\n                    PhSetIntegerSetting(SETTING_USE_COLOR_SYSTEM_THREAD_STACK, context->HighlightSystemFrames);\n                    PhpThreadStacksInvalidateNodes(context);\n                    break;\n                case 10:\n                    context->HighlightInlineFrames = !context->HighlightInlineFrames;\n                    PhSetIntegerSetting(SETTING_USE_COLOR_INLINE_THREAD_STACK, context->HighlightInlineFrames);\n                    PhpThreadStacksInvalidateNodes(context);\n                    break;\n                case 100:\n                    {\n                        PPH_STRING text;\n\n                        text = PhGetTreeNewText(hwnd, 0);\n                        PhSetClipboardString(hwnd, &text->sr);\n                        PhDereferenceObject(text);\n                    }\n                    break;\n                }\n            }\n\n            PhDestroyEMenu(menu);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpThreadStacksLoadSettingsTreeList(\n    _Inout_ PPH_THREAD_STACKS_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhGetStringSetting(L\"ThreadStacksTreeListColumns\");\n    PhCmLoadSettings(Context->TreeNewHandle, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\nVOID PhpThreadStacksSaveSettingsTreeList(\n    _Inout_ PPH_THREAD_STACKS_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhCmSaveSettings(Context->TreeNewHandle);\n    PhSetStringSetting2(SETTING_THREAD_STACKS_TREE_LIST_COLUMNS, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\nVOID PhpInitializeThreadStacksTree(\n    _In_ PPH_THREAD_STACKS_CONTEXT Context\n    )\n{\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n\n    TreeNew_SetCallback(Context->TreeNewHandle, PhpThreadStacksTreeNewCallback, Context);\n    TreeNew_SetExtendedFlags(Context->TreeNewHandle, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT);\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_SYMBOL, TRUE, L\"Symbol\", 250, PH_ALIGN_LEFT, 0, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_PROCESSID, TRUE, L\"PID\", 80, PH_ALIGN_LEFT, 1, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_THREADID, TRUE, L\"TID\", 80, PH_ALIGN_LEFT, 2, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_FRAMENUMBER, TRUE, L\"Frame\", 80, PH_ALIGN_LEFT, 3, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_ARCHITECTURE, TRUE, L\"Architecture\", 100, PH_ALIGN_LEFT, 4, 0);\n\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_STACKADDRESS, FALSE, L\"Stack address\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_FRAMEADDRESS, FALSE, L\"Frame address\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_PARAMETER1, FALSE, L\"Stack parameter #1\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_PARAMETER2, FALSE, L\"Stack parameter #2\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_PARAMETER3, FALSE, L\"Stack parameter #3\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_PARAMETER4, FALSE, L\"Stack parameter #4\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_CONTROLADDRESS, FALSE, L\"Control address\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_RETURNADDRESS, FALSE, L\"Return address\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_FILENAME, FALSE, L\"File name\", 250, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_LINETEXT, FALSE, L\"Line number\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_FRAMEDISTANCE, FALSE, L\"Frame distance\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_STARTADDRESS, FALSE, L\"Start address\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_STARTADDRESSSYMBOL, FALSE, L\"Start address (symbolic)\", 100, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_PROCESSNAME, FALSE, L\"Process name\", 250, PH_ALIGN_LEFT, ULONG_MAX, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_THREAD_STACKS_COLUMN_THREADNAME, FALSE, L\"Thread name\", 250, PH_ALIGN_LEFT, ULONG_MAX, 0);\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n    //TreeNew_SetTriState(Context->TreeNewHandle, FALSE);\n\n    PhpThreadStacksLoadSettingsTreeList(Context);\n}\n\n_Function_class_(PH_CALLBACK_FUNCTION)\nVOID PhpThreadStacksSymbolProviderEventCallback(\n    _In_ PVOID Parameter,\n    _In_ PVOID Context\n    )\n{\n    PPH_SYMBOL_EVENT_DATA event = Parameter;\n    PPH_THREAD_STACKS_CONTEXT context = Context;\n    PPH_STRING statusMessage;\n\n    if (!event || !context)\n        return;\n\n    switch (event->EventType)\n    {\n    case PH_SYMBOL_EVENT_TYPE_LOAD_START:\n    case PH_SYMBOL_EVENT_TYPE_PROGRESS:\n        statusMessage = PhReferenceObject(event->EventMessage);\n        break;\n    default:\n        statusMessage = PhReferenceEmptyString();\n        break;\n    }\n\n    PhAcquireQueuedLockExclusive(&context->MessageLock);\n    PhMoveReference(&context->SymbolMessage, statusMessage);\n    context->MessageCount++;\n    PhReleaseQueuedLockExclusive(&context->MessageLock);\n}\n\nINT_PTR CALLBACK PhpThreadStacksDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_THREAD_STACKS_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_THREAD_STACKS_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_TREELIST);\n            context->MessageHandle = GetDlgItem(hwndDlg, IDC_MESSAGE);\n            context->SearchWindowHandle = GetDlgItem(hwndDlg, IDC_FILTER);\n\n            context->HighlightUserFrames = !!PhGetIntegerSetting(SETTING_USE_COLOR_USER_THREAD_STACK);\n            context->HighlightSystemFrames = !!PhGetIntegerSetting(SETTING_USE_COLOR_SYSTEM_THREAD_STACK);\n            context->HighlightInlineFrames = !!PhGetIntegerSetting(SETTING_USE_COLOR_INLINE_THREAD_STACK);\n\n            PhSetApplicationWindowIcon(hwndDlg);\n            PhRegisterDialog(hwndDlg);\n            PhCreateSearchControl(\n                hwndDlg,\n                context->SearchWindowHandle,\n                L\"Search Thread Stacks\",\n                PhpThreadStacksSearchControlCallback,\n                context\n                );\n\n            PhpInitializeThreadStacksTree(context);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->SearchWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, context->MessageHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n\n            context->MinimumSize.left = 0;\n            context->MinimumSize.top = 0;\n            context->MinimumSize.right = 300;\n            context->MinimumSize.bottom = 100;\n            MapDialogRect(hwndDlg, &context->MinimumSize);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_THREAD_STACKS_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_THREAD_STACKS_WINDOW_POSITION, SETTING_THREAD_STACKS_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, context->ParentWindowHandle);\n\n            PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL);\n\n            PhSetTimer(hwndDlg, PH_WINDOW_TIMER_DEFAULT, 200, NULL);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n\n            PhpThreadStacksRefresh(context);\n\n            PhRegisterCallback(\n                &PhSymbolEventCallback,\n                PhpThreadStacksSymbolProviderEventCallback,\n                context,\n                &context->SymbolProviderEventRegistration\n                );\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhUnregisterCallback(&PhSymbolEventCallback, &context->SymbolProviderEventRegistration);\n\n            PhKillTimer(hwndDlg, PH_WINDOW_TIMER_DEFAULT);\n\n            PhSaveWindowPlacementToSetting(SETTING_THREAD_STACKS_WINDOW_POSITION, SETTING_THREAD_STACKS_WINDOW_SIZE, hwndDlg);\n\n            PhUnregisterWindowCallback(hwndDlg);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhpThreadStacksSaveSettingsTreeList(context);\n\n            if (context->WorkerContext)\n                InterlockedIncrement(&context->WorkerContext->Stop);\n\n            PhDereferenceObject(context);\n\n            PostQuitMessage(0);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n                {\n                case IDC_REFRESH:\n                    PhpThreadStacksRefresh(context);\n                    break;\n                case IDCANCEL:\n                    DestroyWindow(hwndDlg);\n                    break;\n                }\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_TIMER:\n        {\n            PPH_STRING statusMessage = NULL;\n            PPH_STRING symbolMessage = NULL;\n\n            PhAcquireQueuedLockExclusive(&context->MessageLock);\n            if (context->MessageCount != context->LastMessageCount)\n            {\n                context->LastMessageCount = context->MessageCount;\n                statusMessage = PhReferenceObject(context->StatusMessage);\n                symbolMessage = PhReferenceObject(context->SymbolMessage);\n            }\n            PhReleaseQueuedLockExclusive(&context->MessageLock);\n\n            if (statusMessage)\n            {\n                PPH_STRING message;\n                PH_FORMAT format[3];\n                ULONG count = 0;\n\n                assert(symbolMessage);\n\n                PhInitFormatSR(&format[count++], statusMessage->sr);\n                if (symbolMessage->Length)\n                {\n                    PhInitFormatS(&format[count++], L\" - \");\n                    PhInitFormatSR(&format[count++], symbolMessage->sr);\n                }\n\n                message = PhFormat(format, count, 80);\n\n                SetWindowText(context->MessageHandle, message->Buffer);\n\n                PhDereferenceObject(message);\n                PhDereferenceObject(statusMessage);\n                PhDereferenceObject(symbolMessage);\n            }\n        }\n        break;\n    case WM_PH_THREAD_STACKS_PUBLISH:\n        {\n            BOOLEAN restructure = (BOOLEAN)wParam;\n            PPH_THREAD_STACKS_NODE node = (PPH_THREAD_STACKS_NODE)lParam;\n\n            if (node)\n            {\n                PhAddItemList(context->NodeList, node);\n                if (node->Type == PhThreadStacksNodeTypeProcess)\n                    PhAddItemList(context->NodeRootList, node);\n            }\n\n            if (restructure)\n                PhpThreadStacksRestructureNodesWithSearch(context);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpThreadStacksDialogThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    HWND windowHandle;\n    BOOL result;\n    MSG message;\n    PH_AUTO_POOL autoPool;\n\n    PhInitializeAutoPool(&autoPool);\n\n    windowHandle = PhCreateDialog(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_THRDSTACKS),\n        NULL,\n        PhpThreadStacksDlgProc,\n        Parameter\n        );\n\n    ShowWindow(windowHandle, SW_SHOW);\n    SetForegroundWindow(windowHandle);\n\n    while (result = GetMessage(&message, NULL, 0, 0))\n    {\n        if (result == INT_ERROR)\n            break;\n\n        if (!IsDialogMessage(windowHandle, &message))\n        {\n            TranslateMessage(&message);\n            DispatchMessage(&message);\n        }\n\n        PhDrainAutoPool(&autoPool);\n    }\n\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhShowThreadStacksDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_THREAD_STACKS_CONTEXT context;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhpThreadStacksObjectType = PhCreateObjectType(L\"ThreadStacks\", 0, PhpThreadStacksContextDeleteProcedure);\n        PhpThreadStacksWorkerObjectType = PhCreateObjectType(L\"ThreadStacksWorker\", 0, PhpThreadStacksWorkerContextDeleteProcedure);\n        PhpThreadStacksNodeObjectType = PhCreateObjectType(L\"ThreadStacksNode\", 0, PhpThreadStacksNodeDeleteProcedure);\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    context = PhpThreadStacksCreateContext();\n    context->ParentWindowHandle = ParentWindowHandle;\n\n    if (!NT_SUCCESS(PhCreateThread2(PhpThreadStacksDialogThreadStart, context)))\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to create the window.\", 0, ERROR_OUTOFMEMORY);\n        PhDereferenceObject(context);\n    }\n}\n"
  },
  {
    "path": "SystemInformer/tokprp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2012\n *     dmex    2017-2026\n *\n */\n\n#include <phapp.h>\n#include <apiimport.h>\n#include <appresolver.h>\n#include <appmodel.h>\n#include <cpysave.h>\n#include <emenu.h>\n#include <hndlinfo.h>\n#include <lsasup.h>\n#include <mapldr.h>\n#include <secedit.h>\n#include <settings.h>\n#include <symprv.h>\n#include <workqueue.h>\n#include <phsettings.h>\n\ntypedef enum _PH_PROCESS_TOKEN_CATEGORY\n{\n    PH_PROCESS_TOKEN_CATEGORY_FLAGS,\n    PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES,\n    PH_PROCESS_TOKEN_CATEGORY_RESTRICTED,\n    PH_PROCESS_TOKEN_CATEGORY_GROUPS,\n    PH_PROCESS_TOKEN_CATEGORY_LOGON,\n    PH_PROCESS_TOKEN_CATEGORY_INTEGRITY,\n} PH_PROCESS_TOKEN_CATEGORY;\n\ntypedef enum _PH_PROCESS_TOKEN_FLAG\n{\n    PH_PROCESS_TOKEN_FLAG_NO_WRITE_UP,\n    PH_PROCESS_TOKEN_FLAG_SANDBOX_INERT,\n    PH_PROCESS_TOKEN_FLAG_UIACCESS\n} PH_PROCESS_TOKEN_FLAG;\n\ntypedef enum _PH_PROCESS_TOKEN_INDEX\n{\n    PH_PROCESS_TOKEN_INDEX_NAME,\n    PH_PROCESS_TOKEN_INDEX_STATUS,\n    PH_PROCESS_TOKEN_INDEX_DESCRIPTION,\n    PH_PROCESS_TOKEN_INDEX_SID,\n    PH_PROCESS_TOKEN_INDEX_TYPE,\n    PH_PROCESS_TOKEN_INDEX_USE,\n} PH_PROCESS_TOKEN_INDEX;\n\ntypedef struct _PHP_TOKEN_PAGE_LISTVIEW_ITEM\n{\n    PH_PROCESS_TOKEN_CATEGORY GroupId;\n    PSID_AND_ATTRIBUTES TokenGroup;\n    PLUID_AND_ATTRIBUTES TokenPrivilege;\n    PH_PROCESS_TOKEN_FLAG ItemFlag;\n    BOOLEAN ItemFlagState;\n} PHP_TOKEN_PAGE_LISTVIEW_ITEM, *PPHP_TOKEN_PAGE_LISTVIEW_ITEM;\n\ntypedef struct _PHP_TOKEN_USER_RESOLVE_CONTEXT\n{\n    HWND WindowHandle;\n    PSID TokenUserSid;\n} PHP_TOKEN_USER_RESOLVE_CONTEXT, *PPHP_TOKEN_USER_RESOLVE_CONTEXT;\n\ntypedef struct _PHP_TOKEN_GROUP_RESOLVE_CONTEXT\n{\n    HWND ListViewHandle;\n    PPHP_TOKEN_PAGE_LISTVIEW_ITEM LvItem;\n    LONG GroupId;\n    PSID TokenGroupSid;\n} PHP_TOKEN_GROUP_RESOLVE_CONTEXT, *PPHP_TOKEN_GROUP_RESOLVE_CONTEXT;\n\ntypedef struct _PH_TOKEN_ATTRIBUTE_NODE\n{\n    PH_TREENEW_NODE Node;\n    PPH_LIST Children;\n    PPH_STRING Text;\n    PPH_STRING Value;\n} PH_TOKEN_ATTRIBUTE_NODE, *PPH_TOKEN_ATTRIBUTE_NODE;\n\ntypedef struct _PH_TOKEN_ATTRIBUTE_TREE_CONTEXT\n{\n    HWND WindowHandle;\n    PPH_LIST RootList;\n    PPH_LIST NodeList;\n    ULONG TreeNewSortColumn;\n    PH_SORT_ORDER TreeNewSortOrder;\n} PH_TOKEN_ATTRIBUTE_TREE_CONTEXT, *PPH_TOKEN_ATTRIBUTE_TREE_CONTEXT;\n\ntypedef struct _TOKEN_PAGE_CONTEXT\n{\n    PPH_OPEN_OBJECT OpenObject;\n    PPH_CLOSE_OBJECT CloseObject;\n    PVOID Context;\n    DLGPROC HookProc;\n    HANDLE ProcessId;\n\n    HWND ListViewHandle;\n    HIMAGELIST ListViewImageList;\n    PH_LAYOUT_MANAGER LayoutManager;\n    BOOLEAN SinglePageContext;\n\n    PTOKEN_GROUPS Groups;\n    PTOKEN_GROUPS RestrictedSids;\n    PTOKEN_PRIVILEGES Privileges;\n    PTOKEN_GROUPS Capabilities;\n\n    PH_TOKEN_ATTRIBUTE_TREE_CONTEXT CapsTreeContext;\n    PH_TOKEN_ATTRIBUTE_TREE_CONTEXT ClaimsTreeContext;\n    PH_TOKEN_ATTRIBUTE_TREE_CONTEXT AuthzTreeContext;\n    PH_TOKEN_ATTRIBUTE_TREE_CONTEXT AppPolicyTreeContext;\n} TOKEN_PAGE_CONTEXT, *PTOKEN_PAGE_CONTEXT;\n\nstatic CONST PH_KEY_VALUE_PAIR PhElevationTypePairs[] =\n{\n    SIP(SREF(L\"Unknown\"), 0),\n    SIP(SREF(L\"No (Default)\"), TokenElevationTypeDefault),\n    SIP(SREF(L\"No (Full)\"), TokenElevationTypeFull),\n    SIP(SREF(L\"No (Limited)\"), TokenElevationTypeLimited),\n    SIP(SREF(L\"Yes\"), 4),\n    SIP(SREF(L\"Yes (Default)\"), 4 + TokenElevationTypeDefault),\n    SIP(SREF(L\"Yes (Full)\"), 4 + TokenElevationTypeFull),\n    SIP(SREF(L\"Yes (Limited)\"), 4 + TokenElevationTypeLimited),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR PhImpersonationLevelPairs[] =\n{\n    SIP(L\"Anonymous\", SecurityAnonymous),\n    SIP(L\"Identification\", SecurityIdentification),\n    SIP(L\"Impersonation\", SecurityImpersonation),\n    SIP(L\"Delegation\", SecurityDelegation),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR PhTokenTypePairs[] =\n{\n    SIP(L\"Unknown\", 0),\n    SIP(L\"Primary\", TokenPrimary),\n    SIP(L\"Impersonation\", TokenImpersonation),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR PhSidTypePairs[] =\n{\n    SIP(L\"Unknown\", 0),\n    SIP(L\"User\", SidTypeUser),\n    SIP(L\"Group\", SidTypeGroup),\n    SIP(L\"Domain\", SidTypeDomain),\n    SIP(L\"Alias\", SidTypeAlias),\n    SIP(L\"WellKnownGroup\", SidTypeWellKnownGroup),\n    SIP(L\"DeletedAccount\", SidTypeDeletedAccount),\n    SIP(L\"Yes (Limited)\", SidTypeInvalid),\n    SIP(L\"Unknown\", SidTypeUnknown),\n    SIP(L\"Computer\", SidTypeComputer),\n    SIP(L\"Label\", SidTypeLabel),\n    SIP(L\"Logon session\", SidTypeLogonSession),\n};\n\nPH_ACCESS_ENTRY CONST PhpGroupDescriptionEntries[6] =\n{\n    { NULL, SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED, FALSE, FALSE, L\"Integrity\" },\n    { NULL, SE_GROUP_LOGON_ID, FALSE, FALSE, L\"Logon Id\" },\n    { NULL, SE_GROUP_OWNER, FALSE, FALSE, L\"Owner\" },\n    { NULL, SE_GROUP_MANDATORY, FALSE, FALSE, L\"Mandatory\" },\n    { NULL, SE_GROUP_USE_FOR_DENY_ONLY, FALSE, FALSE, L\"Use for deny only\" },\n    { NULL, SE_GROUP_RESOURCE, FALSE, FALSE, L\"Resource\" }\n};\n\nstatic CONST PH_STRINGREF PhpEmptyTokenAttributesText = PH_STRINGREF_INIT(L\"There are no attributes to display.\");\nstatic CONST PH_STRINGREF PhpEmptyTokenClaimsText = PH_STRINGREF_INIT(L\"There are no claims to display.\");\nstatic CONST PH_STRINGREF PhpEmptyTokenCapabilitiesText = PH_STRINGREF_INIT(L\"There are no capabilities to display.\");\n\nUINT CALLBACK PhpTokenPropPageProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ LPPROPSHEETPAGE ppsp\n    );\n\nINT_PTR CALLBACK PhpTokenPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhpShowTokenAdvancedProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PTOKEN_PAGE_CONTEXT Context,\n    _In_ BOOLEAN ShowAppContainerPage\n    );\n\nINT_PTR CALLBACK PhpTokenGeneralPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpTokenAdvancedPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpTokenCapabilitiesPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nBOOLEAN NTAPI PhpAttributeTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    );\n\nINT_PTR CALLBACK PhpTokenClaimsPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpTokenAttributesPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpTokenContainerPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nINT_PTR CALLBACK PhpTokenAppPolicyPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nPPH_STRING PhpGetTokenFolderPath(\n    _In_ HANDLE TokenHandle\n    );\n\nPPH_STRING PhpGetTokenRegistryPath(\n    _In_ HANDLE TokenHandle\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpTokenDialogThread(\n    _In_ PVOID Context\n    )\n{\n    PH_AUTO_POOL autoPool;\n    LPPROPSHEETPAGE propSheetPage;\n\n    PhInitializeAutoPool(&autoPool);\n\n    propSheetPage = PhAllocateZero(sizeof(PROPSHEETPAGE));\n    propSheetPage->lParam = (LPARAM)Context;\n\n    PhDialogBox(\n        NtCurrentImageBase(),\n        MAKEINTRESOURCE(IDD_OBJTOKEN),\n        NULL,\n        PhpTokenPageProc,\n        propSheetPage\n        );\n\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhCreateTokenDialog(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_ HANDLE ProcessId,\n    _In_ PVOID Context,\n    _In_opt_ DLGPROC HookProc\n    )\n{\n    NTSTATUS status;\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n    HANDLE tokenHandle = NULL;\n\n    if (!NT_SUCCESS(status = NtDuplicateObject(\n        NtCurrentProcess(),\n        Context,\n        NtCurrentProcess(),\n        &tokenHandle,\n        0,\n        0,\n        DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES\n        )))\n    {\n        PhShowStatus(NULL, L\"Unable to duplicate the token.\", status, 0);\n        return;\n    }\n\n    tokenPageContext = PhCreateAlloc(sizeof(TOKEN_PAGE_CONTEXT));\n    memset(tokenPageContext, 0, sizeof(TOKEN_PAGE_CONTEXT));\n    tokenPageContext->OpenObject = OpenObject;\n    tokenPageContext->CloseObject = CloseObject;\n    tokenPageContext->Context = tokenHandle;\n    //tokenPageContext->HookProc = HookProc;\n    tokenPageContext->ProcessId = ProcessId;\n    tokenPageContext->SinglePageContext = TRUE;\n\n    PhCreateThread2(PhpTokenDialogThread, tokenPageContext);\n}\n\nVOID PhShowTokenProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_ HANDLE ProcessId,\n    _In_ PVOID Context,\n    _In_opt_ PCWSTR Title\n    )\n{\n    PhCreateTokenDialog(OpenObject, CloseObject, ProcessId, Context, NULL);\n}\n\nHPROPSHEETPAGE PhCreateTokenPage(\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_ HANDLE ProcessId,\n    _In_opt_ PVOID Context,\n    _In_opt_ DLGPROC HookProc\n    )\n{\n    HPROPSHEETPAGE propSheetPageHandle;\n    PROPSHEETPAGE propSheetPage;\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n\n    tokenPageContext = PhCreateAlloc(sizeof(TOKEN_PAGE_CONTEXT));\n    memset(tokenPageContext, 0, sizeof(TOKEN_PAGE_CONTEXT));\n    tokenPageContext->OpenObject = OpenObject;\n    tokenPageContext->CloseObject = CloseObject;\n    tokenPageContext->Context = Context;\n    tokenPageContext->HookProc = HookProc;\n    tokenPageContext->ProcessId = ProcessId;\n\n    memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));\n    propSheetPage.dwSize = sizeof(PROPSHEETPAGE);\n    propSheetPage.dwFlags = PSP_USECALLBACK;\n    propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJTOKEN);\n    propSheetPage.hInstance = NtCurrentImageBase();\n    propSheetPage.pfnDlgProc = PhpTokenPageProc;\n    propSheetPage.lParam = (LPARAM)tokenPageContext;\n    propSheetPage.pfnCallback = PhpTokenPropPageProc;\n\n    propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);\n    // CreatePropertySheetPage would have sent PSPCB_ADDREF (below),\n    // which would have added a reference.\n    PhDereferenceObject(tokenPageContext);\n\n    return propSheetPageHandle;\n}\n\nUINT CALLBACK PhpTokenPropPageProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ LPPROPSHEETPAGE ppsp\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n\n    tokenPageContext = (PTOKEN_PAGE_CONTEXT)ppsp->lParam;\n\n    if (uMsg == PSPCB_ADDREF)\n    {\n        PhReferenceObject(tokenPageContext);\n    }\n    else if (uMsg == PSPCB_RELEASE)\n    {\n        PhDereferenceObject(tokenPageContext);\n    }\n\n    return 1;\n}\n\nPPH_STRING PhGetGroupAttributesString(\n    _In_ ULONG Attributes,\n    _In_ BOOLEAN Restricted\n    )\n{\n    PPH_STRING string;\n\n    if (FlagOn(Attributes, SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED))\n    {\n        if (FlagOn(Attributes, SE_GROUP_ENABLED))\n            string = PhCreateString(L\"Enabled (as a group)\");\n        else\n            string = PhReferenceEmptyString();\n    }\n    else\n    {\n        if (FlagOn(Attributes, SE_GROUP_ENABLED))\n        {\n            if (FlagOn(Attributes, SE_GROUP_ENABLED_BY_DEFAULT))\n                string = PhCreateString(L\"Enabled\");\n            else\n                string = PhCreateString(L\"Enabled (modified)\");\n        }\n        else\n        {\n            if (FlagOn(Attributes, SE_GROUP_ENABLED_BY_DEFAULT))\n                string = PhCreateString(L\"Disabled (modified)\");\n            else\n                string = PhCreateString(L\"Disabled\");\n        }\n    }\n\n    if (Restricted)\n    {\n        PhMoveReference(&string, PhConcatStringRefZ(&string->sr, L\" (restricted)\"));\n    }\n\n    return string;\n}\n\nCOLORREF PhGetGroupAttributesColorDark(\n    _In_ ULONG Attributes\n    )\n{\n    if (FlagOn(Attributes, SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED))\n    {\n        if (!FlagOn(Attributes, SE_GROUP_ENABLED))\n            return RGB(0, 26, 0);\n    }\n\n    if (FlagOn(Attributes, SE_GROUP_ENABLED))\n    {\n        if (FlagOn(Attributes, SE_GROUP_ENABLED_BY_DEFAULT))\n            return RGB(0, 26, 0);\n        else\n            return RGB(0, 102, 0);\n    }\n    else\n    {\n        if (FlagOn(Attributes, SE_GROUP_ENABLED_BY_DEFAULT))\n            return RGB(122, 77, 84);\n        else\n            return RGB(43, 12, 15);\n    }\n}\n\nCOLORREF PhGetPrivilegeAttributesColorDark(\n    _In_ ULONG Attributes\n    )\n{\n    if (FlagOn(Attributes, SE_PRIVILEGE_REMOVED))\n    {\n        return RGB(0, 0, 0);\n    }\n\n    if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED))\n    {\n        if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED_BY_DEFAULT))\n            return RGB(0, 26, 0);\n        else\n            return RGB(0, 102, 0);\n    }\n    else\n    {\n        if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED_BY_DEFAULT))\n            return RGB(122, 77, 84);\n        else\n            return RGB(43, 12, 15);\n    }\n}\n\nCOLORREF PhGetDangerousFlagColorDark(\n    _In_ BOOLEAN FlagState\n    )\n{\n    if (FlagState)\n        return RGB(0xc0, 0xf0, 0xc0);\n    else\n        return RGB(0xf0, 0xc0, 0xc0);\n}\n\nCOLORREF PhGetGroupAttributesColor(\n    _In_ ULONG Attributes\n    )\n{\n    if (FlagOn(Attributes, SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED))\n    {\n        if (!FlagOn(Attributes, SE_GROUP_ENABLED))\n            return RGB(0xe0, 0xf0, 0xe0);\n    }\n\n    if (FlagOn(Attributes, SE_GROUP_ENABLED))\n    {\n        if (FlagOn(Attributes, SE_GROUP_ENABLED_BY_DEFAULT))\n            return RGB(0xe0, 0xf0, 0xe0);\n        else\n            return RGB(0xc0, 0xf0, 0xc0);\n    }\n    else\n    {\n        if (FlagOn(Attributes, SE_GROUP_ENABLED_BY_DEFAULT))\n            return RGB(0xf0, 0xc0, 0xc0);\n        else\n            return RGB(0xf0, 0xe0, 0xe0);\n    }\n}\n\nCOLORREF PhGetPrivilegeAttributesColor(\n    _In_ ULONG Attributes\n    )\n{\n    if (FlagOn(Attributes, SE_PRIVILEGE_REMOVED))\n    {\n        return RGB(0xc0, 0xc0, 0xc0);\n    }\n\n    if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED))\n    {\n        if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED_BY_DEFAULT))\n            return RGB(0xe0, 0xf0, 0xe0);\n        else\n            return RGB(0xc0, 0xf0, 0xc0);\n    }\n    else\n    {\n        if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED_BY_DEFAULT))\n            return RGB(0xf0, 0xc0, 0xc0);\n        else\n            return RGB(0xf0, 0xe0, 0xe0);\n    }\n}\n\nCOLORREF PhGetDangerousFlagColor(\n    _In_ BOOLEAN FlagState\n    )\n{\n    if (FlagState)\n        return RGB(0xc0, 0xf0, 0xc0);\n    else\n        return RGB(0xf0, 0xc0, 0xc0);\n}\n\nstatic COLORREF NTAPI PhpTokenGroupColorFunction(\n    _In_ LONG Index,\n    _In_ PVOID Param,\n    _In_opt_ PVOID Context\n    )\n{\n    PPHP_TOKEN_PAGE_LISTVIEW_ITEM entry = Param;\n\n    if (PhEnableThemeSupport)\n    {\n        if (entry->GroupId == PH_PROCESS_TOKEN_CATEGORY_FLAGS)\n            return PhGetDangerousFlagColorDark(entry->ItemFlagState);\n        else if (entry->GroupId == PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES)\n            return PhGetPrivilegeAttributesColorDark(entry->TokenPrivilege->Attributes);\n        else\n            return PhGetGroupAttributesColorDark(entry->TokenGroup->Attributes);\n    }\n    else\n    {\n        if (entry->GroupId == PH_PROCESS_TOKEN_CATEGORY_FLAGS)\n            return PhGetDangerousFlagColor(entry->ItemFlagState);\n        else if (entry->GroupId == PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES)\n            return PhGetPrivilegeAttributesColor(entry->TokenPrivilege->Attributes);\n        else\n            return PhGetGroupAttributesColor(entry->TokenGroup->Attributes);\n    }\n}\n\nPCWSTR PhGetPrivilegeAttributesString(\n    _In_ ULONG Attributes\n    )\n{\n    if (FlagOn(Attributes, SE_PRIVILEGE_REMOVED))\n    {\n        return L\"Removed\";\n    }\n\n    if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED))\n    {\n        if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED_BY_DEFAULT))\n            return L\"Enabled\";\n        else\n            return L\"Enabled (modified)\";\n    }\n    else\n    {\n        if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED_BY_DEFAULT))\n            return L\"Disabled (modified)\";\n        else\n            return L\"Disabled\";\n    }\n}\n\n_Success_(return)\nBOOLEAN PhGetElevationTypeString(\n    _In_ BOOLEAN IsElevated,\n    _In_ TOKEN_ELEVATION_TYPE ElevationType,\n    _Out_ PCPH_STRINGREF* ElevationTypeString\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        PhElevationTypePairs,\n        sizeof(PhElevationTypePairs),\n        (IsElevated ? 4 : 0) + (ULONG)ElevationType,\n        &string\n        ))\n    {\n        *ElevationTypeString = string;\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Success_(return)\nBOOLEAN PhGetImpersonationLevelString(\n    _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,\n    _Out_ PCWSTR* ImpersonationLevelString\n    )\n{\n    if (PhIndexStringSiKeyValuePairs(\n        PhImpersonationLevelPairs,\n        sizeof(PhImpersonationLevelPairs),\n        ImpersonationLevel,\n        ImpersonationLevelString\n        ))\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Success_(return)\nBOOLEAN PhGetTokenTypeString(\n    _In_ TOKEN_TYPE TokenType,\n    _Out_ PCWSTR* TokenTypeString\n    )\n{\n    if (PhIndexStringSiKeyValuePairs(\n        PhTokenTypePairs,\n        sizeof(PhTokenTypePairs),\n        TokenType,\n        TokenTypeString\n        ))\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpTokenPageFreeListViewEntries(\n    _In_ PTOKEN_PAGE_CONTEXT TokenPageContext\n    )\n{\n    LONG index = INT_ERROR;\n\n    while ((index = PhFindListViewItemByFlags(\n        TokenPageContext->ListViewHandle,\n        index,\n        LVNI_ALL\n        )) != INT_ERROR)\n    {\n        PPHP_TOKEN_PAGE_LISTVIEW_ITEM entry;\n\n        if (PhGetListViewItemParam(TokenPageContext->ListViewHandle, index, &entry))\n        {\n            PhFree(entry);\n        }\n    }\n}\n\n_Success_(return)\nBOOLEAN PhGetTokenSidTypeString(\n    _In_ SID_NAME_USE TokenNameUse,\n    _Out_ PCWSTR* TokenNameUseString\n    )\n{\n    if (PhIndexStringSiKeyValuePairs(\n        PhSidTypePairs,\n        sizeof(PhSidTypePairs),\n        TokenNameUse,\n        TokenNameUseString\n        ))\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS NTAPI PhpTokenGroupResolveWorker(\n    _In_ PVOID ThreadParameter\n    )\n{\n    PPHP_TOKEN_GROUP_RESOLVE_CONTEXT context = ThreadParameter;\n    PPH_STRING sidString;\n    SID_NAME_USE sidUse;\n    LONG ItemIndex;\n\n    ItemIndex = PhFindListViewItemByParam(\n        context->ListViewHandle,\n        INT_ERROR,\n        context->LvItem\n        );\n\n    if (ItemIndex != INT_ERROR)\n    {\n        if (sidString = PhGetSidFullName(context->TokenGroupSid, TRUE, NULL))\n        {\n            PhMoveReference(&sidString, PhReferenceObject(sidString));\n        }\n        else if (sidString = PhGetAppContainerPackageName(context->TokenGroupSid))\n        {\n            PhMoveReference(&sidString, PhConcatStringRefZ(&sidString->sr, L\" (APP_PACKAGE)\"));\n        }\n        else if (sidString = PhGetAppContainerName(context->TokenGroupSid))\n        {\n            PhMoveReference(&sidString, PhConcatStringRefZ(&sidString->sr, L\" (APP_CONTAINER)\"));\n        }\n        else if (sidString = PhGetCapabilitySidName(context->TokenGroupSid))\n        {\n            PhMoveReference(&sidString, PhConcatStringRefZ(&sidString->sr, L\" (APP_CAPABILITY)\"));\n        }\n        else\n        {\n            if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(context->TokenGroupSid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_NT_AUTHORITY))\n            {\n                ULONG subAuthority = *PhSubAuthoritySid(context->TokenGroupSid, 0);\n\n                switch (subAuthority)\n                {\n                case SECURITY_UMFD_BASE_RID:\n                    PhMoveReference(&sidString, PhCreateString(L\"Font Driver Host\\\\UMFD\"));\n                    break;\n                }\n            }\n            else if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(context->TokenGroupSid), PhIdentifierAuthoritySid(PhSeCloudActiveDirectorySid())))\n            {\n                ULONG subAuthority = *PhSubAuthoritySid(context->TokenGroupSid, 0);\n\n                if (subAuthority == 1)\n                {\n                    PhMoveReference(&sidString, PhGetAzureDirectoryObjectSid(context->TokenGroupSid));\n                }\n            }\n        }\n\n        PhSetListViewSubItem(context->ListViewHandle, ItemIndex, PH_PROCESS_TOKEN_INDEX_NAME, PhGetStringOrDefault(sidString, L\"[Unknown SID]\"));\n        PhSetListViewSubItem(context->ListViewHandle, ItemIndex, PH_PROCESS_TOKEN_INDEX_TYPE, PhGetSidAccountTypeString(context->TokenGroupSid));\n\n        PhClearReference(&sidString);\n    }\n\n    if (NT_SUCCESS(PhLookupSid(context->TokenGroupSid, NULL, NULL, &sidUse)))\n    {\n        PWSTR tokenSidType;\n\n        if (PhGetTokenSidTypeString(sidUse, &tokenSidType))\n            PhSetListViewSubItem(context->ListViewHandle, ItemIndex, PH_PROCESS_TOKEN_INDEX_USE, tokenSidType);\n        else\n            PhSetListViewSubItem(context->ListViewHandle, ItemIndex, PH_PROCESS_TOKEN_INDEX_USE, L\"N/A\");\n    }\n    else\n    {\n        PhSetListViewSubItem(context->ListViewHandle, ItemIndex, PH_PROCESS_TOKEN_INDEX_USE, L\"N/A\");\n    }\n\n    PhFree(context->TokenGroupSid);\n    PhFree(context);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpUpdateSidsFromTokenGroups(\n    _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,\n    _In_ PTOKEN_GROUPS Groups,\n    _In_ BOOLEAN Restricted\n    )\n{\n    for (ULONG i = 0; i < Groups->GroupCount; i++)\n    {\n        PPH_STRING stringUserSid;\n        PPH_STRING attributesString;\n        PPH_STRING descriptionString;\n        PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem;\n        LONG ItemIndex;\n\n        lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM));\n        lvitem->GroupId = Restricted ? PH_PROCESS_TOKEN_CATEGORY_RESTRICTED : PH_PROCESS_TOKEN_CATEGORY_GROUPS;\n        lvitem->TokenGroup = &Groups->Groups[i];\n\n        if (FlagOn(Groups->Groups[i].Attributes, SE_GROUP_LOGON_ID))\n        {\n            lvitem->GroupId = PH_PROCESS_TOKEN_CATEGORY_LOGON;\n        }\n        else if (FlagOn(Groups->Groups[i].Attributes, SE_GROUP_INTEGRITY))\n        {\n            lvitem->GroupId = PH_PROCESS_TOKEN_CATEGORY_INTEGRITY;\n        }\n\n        ItemIndex = PhAddListViewGroupItem(\n            TokenPageContext->ListViewHandle,\n            lvitem->GroupId,\n            MAXINT,\n            L\"Resolving...\",\n            lvitem\n            );\n\n        if (attributesString = PhGetGroupAttributesString(Groups->Groups[i].Attributes, Restricted))\n        {\n            PhSetListViewSubItem(TokenPageContext->ListViewHandle, ItemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, PhGetString(attributesString));\n            PhDereferenceObject(attributesString);\n        }\n\n        descriptionString = PhGetAccessString(\n            Groups->Groups[i].Attributes,\n            (PPH_ACCESS_ENTRY)PhpGroupDescriptionEntries,\n            RTL_NUMBER_OF(PhpGroupDescriptionEntries)\n            );\n\n        if (descriptionString)\n        {\n            PhSetListViewSubItem(TokenPageContext->ListViewHandle, ItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetString(descriptionString));\n            PhDereferenceObject(descriptionString);\n        }\n\n        if (stringUserSid = PhSidToStringSid(Groups->Groups[i].Sid))\n        {\n            PhSetListViewSubItem(TokenPageContext->ListViewHandle, ItemIndex, PH_PROCESS_TOKEN_INDEX_SID, PhGetString(stringUserSid));\n            PhDereferenceObject(stringUserSid);\n        }\n\n        {\n            PPHP_TOKEN_GROUP_RESOLVE_CONTEXT tokenGroupResolve;\n\n            tokenGroupResolve = PhAllocateZero(sizeof(PHP_TOKEN_GROUP_RESOLVE_CONTEXT));\n            tokenGroupResolve->ListViewHandle = TokenPageContext->ListViewHandle;\n            tokenGroupResolve->LvItem = lvitem;\n            tokenGroupResolve->GroupId = lvitem->GroupId;\n            tokenGroupResolve->TokenGroupSid = PhAllocateCopy(Groups->Groups[i].Sid, PhLengthSid(Groups->Groups[i].Sid));\n\n            PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpTokenGroupResolveWorker, tokenGroupResolve);\n        }\n    }\n}\n\nBOOLEAN PhpUpdateTokenGroups(\n    _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,\n    _In_ HANDLE TokenHandle\n    )\n{\n    PTOKEN_GROUPS groups = NULL;\n    PTOKEN_GROUPS restrictedSIDs = NULL;\n\n    if (NT_SUCCESS(PhGetTokenGroups(TokenHandle, &groups)))\n    {\n        PhpUpdateSidsFromTokenGroups(TokenPageContext, groups, FALSE);\n    }\n\n    if (NT_SUCCESS(PhGetTokenRestrictedSids(TokenHandle, &restrictedSIDs)))\n    {\n        PhpUpdateSidsFromTokenGroups(TokenPageContext, restrictedSIDs, TRUE);\n    }\n\n    if (TokenPageContext->RestrictedSids)\n        PhFree(TokenPageContext->RestrictedSids);\n    if (TokenPageContext->Groups)\n        PhFree(TokenPageContext->Groups);\n\n    TokenPageContext->RestrictedSids = restrictedSIDs;\n    TokenPageContext->Groups = groups;\n\n    return TRUE;\n}\n\nNTSTATUS NTAPI PhpEnumeratePrivilegesCallback(\n    _In_ PPOLICY_PRIVILEGE_DEFINITION Privileges,\n    _In_ ULONG NumberOfPrivileges,\n    _In_ PVOID Context\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext = Context;\n\n    if (!tokenPageContext->Privileges)\n        return STATUS_UNSUCCESSFUL;\n\n    for (ULONG i = 0; i < NumberOfPrivileges; i++)\n    {\n        PPH_STRING privilegeName;\n        PPH_STRING privilegeDisplayName;\n        PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem;\n        LONG itemIndex;\n\n        for (ULONG j = 0; j < tokenPageContext->Privileges->PrivilegeCount; j++)\n        {\n            if (RtlIsEqualLuid(&tokenPageContext->Privileges->Privileges[j].Luid, &Privileges[i].LocalValue))\n            {\n                continue;\n            }\n        }\n\n        privilegeName = PhCreateStringFromUnicodeString(&Privileges[i].Name);\n        privilegeDisplayName = NULL;\n        PhLookupPrivilegeDisplayName(&privilegeName->sr, &privilegeDisplayName);\n\n        lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM));\n        lvitem->GroupId = PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES;\n        lvitem->TokenPrivilege = PhAllocateZero(sizeof(LUID_AND_ATTRIBUTES));\n        lvitem->TokenPrivilege->Luid = Privileges[i].LocalValue;\n        lvitem->TokenPrivilege->Attributes = SE_PRIVILEGE_REMOVED;\n\n        // Name\n        itemIndex = PhAddListViewGroupItem(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, MAXINT, PhGetString(privilegeName), lvitem);\n        // Status\n        PhSetListViewSubItem(tokenPageContext->ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, PhGetPrivilegeAttributesString(lvitem->TokenPrivilege->Attributes));\n        // Description\n        PhSetListViewSubItem(tokenPageContext->ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetStringOrEmpty(privilegeDisplayName));\n        // Privilege value\n        PhSetListViewSubItem(tokenPageContext->ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_SID, PhaFormatUInt64(Privileges[i].LocalValue.LowPart, FALSE)->Buffer);\n\n        PhClearReference(&privilegeDisplayName);\n        PhClearReference(&privilegeName);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nBOOLEAN PhpUpdateTokenPrivileges(\n    _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,\n    _In_ HANDLE TokenHandle\n    )\n{\n    PTOKEN_PRIVILEGES privileges;\n    ULONG i;\n\n    if (!NT_SUCCESS(PhGetTokenPrivileges(TokenHandle, &privileges)))\n        return FALSE;\n\n    for (i = 0; i < privileges->PrivilegeCount; i++)\n    {\n        PPH_STRING privilegeName;\n        PPH_STRING privilegeDisplayName;\n\n        if (NT_SUCCESS(PhLookupPrivilegeName(\n            &privileges->Privileges[i].Luid,\n            &privilegeName\n            )))\n        {\n            PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem;\n            LONG itemIndex;\n\n            lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM));\n            lvitem->GroupId = PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES;\n            lvitem->TokenPrivilege = &privileges->Privileges[i];\n\n            privilegeDisplayName = NULL;\n            PhLookupPrivilegeDisplayName(&privilegeName->sr, &privilegeDisplayName);\n\n            // Name\n            itemIndex = PhAddListViewGroupItem(TokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, MAXINT, privilegeName->Buffer, lvitem);\n            // Status\n            PhSetListViewSubItem(TokenPageContext->ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, PhGetPrivilegeAttributesString(privileges->Privileges[i].Attributes));\n            // Description\n            PhSetListViewSubItem(TokenPageContext->ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetStringOrEmpty(privilegeDisplayName));\n            // Value\n            PhSetListViewSubItem(TokenPageContext->ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_SID, PhaFormatUInt64(privileges->Privileges[i].Luid.LowPart, FALSE)->Buffer);\n\n            PhClearReference(&privilegeDisplayName);\n            PhClearReference(&privilegeName);\n        }\n    }\n\n    if (TokenPageContext->Privileges)\n        PhFree(TokenPageContext->Privileges);\n\n    TokenPageContext->Privileges = privileges;\n\n    if (PhGetIntegerSetting(SETTING_ENABLE_TOKEN_REMOVED_PRIVILEGES))\n    {\n        PhEnumeratePrivileges(PhpEnumeratePrivilegesCallback, TokenPageContext);\n    }\n\n    return TRUE;\n}\n\nVOID PhpUpdateTokenDangerousFlagItem(\n    _In_ HWND ListViewHandle,\n    _In_ PH_PROCESS_TOKEN_FLAG Flag,\n    _In_ BOOLEAN State,\n    _In_ PWSTR Name,\n    _In_ PWSTR Description\n    )\n{\n    PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem;\n    LONG itemIndex;\n\n    lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM));\n    lvitem->GroupId = PH_PROCESS_TOKEN_CATEGORY_FLAGS;\n    lvitem->ItemFlag = Flag;\n    lvitem->ItemFlagState = State;\n\n    // Name\n    itemIndex = PhAddListViewGroupItem(ListViewHandle, lvitem->GroupId, MAXINT, Name, lvitem);\n    // Status\n    PhSetListViewSubItem(ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, State ? L\"Enabled (modified)\" : L\"Disabled (modified)\");\n    // Description\n    PhSetListViewSubItem(ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, Description);\n    // Value\n    PhSetListViewSubItem(ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_SID, PhaFormatUInt64(Flag, FALSE)->Buffer);\n}\n\nBOOLEAN PhpUpdateTokenDangerousFlags(\n    _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,\n    _In_ HANDLE TokenHandle\n    )\n{\n    TOKEN_MANDATORY_POLICY mandatoryPolicy;\n    BOOLEAN isSandboxInert;\n    BOOLEAN isUIAccess;\n\n    if (NT_SUCCESS(PhGetTokenMandatoryPolicy(TokenHandle, &mandatoryPolicy)))\n    {\n        // The disabled no-write-up policy is considered to be dangerous (diversenok)\n        if ((mandatoryPolicy.Policy & TOKEN_MANDATORY_POLICY_NO_WRITE_UP) == 0)\n        {\n            PhpUpdateTokenDangerousFlagItem(\n                TokenPageContext->ListViewHandle,\n                PH_PROCESS_TOKEN_FLAG_NO_WRITE_UP,\n                FALSE,\n                L\"No-Write-Up Policy\",\n                L\"Prevents the process from modifying objects with a higher integrity\"\n                );\n        }\n    }\n\n    if (NT_SUCCESS(PhGetTokenIsSandBoxInert(TokenHandle, &isSandboxInert)))\n    {\n        // The presence of SandboxInert flag is considered dangerous (diversenok)\n        if (isSandboxInert)\n        {\n            PhpUpdateTokenDangerousFlagItem(\n                TokenPageContext->ListViewHandle,\n                PH_PROCESS_TOKEN_FLAG_SANDBOX_INERT,\n                TRUE,\n                L\"Sandbox Inert\",\n                L\"Ignore AppLocker rules and Software Restriction Policies\"\n                );\n        }\n    }\n\n    if (NT_SUCCESS(PhGetTokenUIAccess(TokenHandle, &isUIAccess)))\n    {\n        // The presence of UIAccess flag is considered dangerous (diversenok)\n        if (isUIAccess)\n        {\n            PhpUpdateTokenDangerousFlagItem(\n                TokenPageContext->ListViewHandle,\n                PH_PROCESS_TOKEN_FLAG_UIACCESS,\n                TRUE,\n                L\"UIAccess\",\n                L\"Ignore User Interface Privilege Isolation\"\n                );\n        }\n    }\n\n    return TRUE;\n}\n\nFORCEINLINE PTOKEN_PAGE_CONTEXT PhpTokenPageHeader(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    return PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 3);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS NTAPI PhpTokenUserResolveWorker(\n    _In_ PVOID ThreadParameter\n    )\n{\n    PPHP_TOKEN_USER_RESOLVE_CONTEXT context = ThreadParameter;\n    PPH_STRING fullUserName;\n\n    if (fullUserName = PhGetSidFullName(context->TokenUserSid, TRUE, NULL))\n    {\n        PhSetWindowText(context->WindowHandle, PhGetString(fullUserName));\n        PhDereferenceObject(fullUserName);\n    }\n    else\n    {\n        if (fullUserName = PhGetAzureDirectoryObjectSid(context->TokenUserSid))\n        {\n            PhSetWindowText(context->WindowHandle, PhGetString(fullUserName));\n            PhDereferenceObject(fullUserName);\n        }\n    }\n\n    PhFree(context->TokenUserSid);\n    PhFree(context);\n\n    return STATUS_SUCCESS;\n}\n\nstatic VOID PhpTokenSetImageList(\n    _In_ HWND WindowHandle,\n    _Inout_ PTOKEN_PAGE_CONTEXT TokenPageContext\n    )\n{\n    LONG dpiValue;\n\n    dpiValue = PhGetWindowDpi(WindowHandle);\n\n    if (TokenPageContext->ListViewImageList)\n    {\n        PhImageListSetIconSize(\n            TokenPageContext->ListViewImageList,\n            2,\n            PhGetDpi(20, dpiValue)\n            );\n    }\n    else\n    {\n        TokenPageContext->ListViewImageList = PhImageListCreate(\n            2,\n            PhGetDpi(20, dpiValue),\n            ILC_MASK | ILC_COLOR32,\n            1, 1\n            );\n    }\n\n    ListView_SetImageList(TokenPageContext->ListViewHandle, TokenPageContext->ListViewImageList, LVSIL_SMALL);\n}\n\nLONG PhpGetTokenPrivilegeSortingIndex(\n    _In_ ULONG Attributes\n    )\n{\n    if (FlagOn(Attributes, SE_PRIVILEGE_REMOVED))\n        return 4;\n    else\n    {\n        if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED))\n        {\n            if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED_BY_DEFAULT))\n                return 0;\n            else\n                return 1;\n        }\n        else\n        {\n            if (FlagOn(Attributes, SE_PRIVILEGE_ENABLED_BY_DEFAULT))\n                return 2;\n            else\n                return 3;\n        }\n    }\n}\n\nLONG PhpGetTokenGroupSortingIndex(\n    _In_ ULONG Attributes\n    )\n{\n    if (FlagOn(Attributes, SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED))\n    {\n        if (!FlagOn(Attributes, SE_GROUP_ENABLED))\n            return 0;\n    }\n\n    if (FlagOn(Attributes, SE_GROUP_ENABLED))\n    {\n        if (FlagOn(Attributes, SE_GROUP_ENABLED_BY_DEFAULT))\n            return 1;\n        else\n            return 2;\n    }\n    else\n    {\n        if (FlagOn(Attributes, SE_GROUP_ENABLED_BY_DEFAULT))\n            return 3;\n        else\n            return 4;\n    }\n}\n\nLONG NTAPI PhpTokenStatusColumnCompareFunction(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_opt_ PVOID Context\n    )\n{\n    PPHP_TOKEN_PAGE_LISTVIEW_ITEM item1 = Item1;\n    PPHP_TOKEN_PAGE_LISTVIEW_ITEM item2 = Item2;\n    ULONG value1;\n    ULONG value2;\n\n    if (item1->GroupId == PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES)\n    {\n        value1 = PhpGetTokenPrivilegeSortingIndex(item1->TokenPrivilege->Attributes);\n    }\n    else if (\n        item1->GroupId == PH_PROCESS_TOKEN_CATEGORY_GROUPS ||\n        item1->GroupId == PH_PROCESS_TOKEN_CATEGORY_LOGON ||\n        item1->GroupId == PH_PROCESS_TOKEN_CATEGORY_INTEGRITY\n        )\n    {\n        value1 = PhpGetTokenGroupSortingIndex(item1->TokenGroup->Attributes);\n    }\n    else\n    {\n        value1 = 0;\n    }\n\n    if (item2->GroupId == PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES)\n    {\n        value2 = PhpGetTokenPrivilegeSortingIndex(item2->TokenPrivilege->Attributes);\n    }\n    else if (\n        item2->GroupId == PH_PROCESS_TOKEN_CATEGORY_GROUPS ||\n        item2->GroupId == PH_PROCESS_TOKEN_CATEGORY_LOGON ||\n        item2->GroupId == PH_PROCESS_TOKEN_CATEGORY_INTEGRITY\n        )\n    {\n        value2 = PhpGetTokenGroupSortingIndex(item2->TokenGroup->Attributes);\n    }\n    else\n    {\n        value2 = 0;\n    }\n\n    return uintcmp(value1, value2);\n}\n\nINT_PTR CALLBACK PhpTokenPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n\n    tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!tokenPageContext)\n        return FALSE;\n\n    if (tokenPageContext->HookProc)\n    {\n        if (tokenPageContext->HookProc(hwndDlg, uMsg, wParam, lParam))\n            return TRUE;\n    }\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HANDLE tokenHandle;\n\n            tokenPageContext->ListViewHandle = GetDlgItem(hwndDlg, IDC_GROUPS);\n\n            PhSetListViewStyle(tokenPageContext->ListViewHandle, TRUE, TRUE);\n            PhSetControlTheme(tokenPageContext->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(tokenPageContext->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 100, L\"Name\");\n            PhAddListViewColumn(tokenPageContext->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 100, L\"Status\");\n            PhAddListViewColumn(tokenPageContext->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 170, L\"Description\");\n            PhAddListViewColumn(tokenPageContext->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 100, L\"SID\");\n            PhAddListViewColumn(tokenPageContext->ListViewHandle, 4, 4, 4, LVCFMT_LEFT, 100, L\"Type\");\n            PhAddListViewColumn(tokenPageContext->ListViewHandle, 5, 5, 5, LVCFMT_LEFT, 100, L\"Use\");\n\n            PhSetExtendedListView(tokenPageContext->ListViewHandle);\n            ExtendedListView_SetCompareFunction(tokenPageContext->ListViewHandle, 1, PhpTokenStatusColumnCompareFunction);\n            ExtendedListView_SetItemColorFunction(tokenPageContext->ListViewHandle, PhpTokenGroupColorFunction);\n            ListView_EnableGroupView(tokenPageContext->ListViewHandle, TRUE);\n            PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_FLAGS, L\"Flags\");\n            PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, L\"Privileges\");\n            PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_RESTRICTED, L\"Restricting SIDs\");\n            PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_GROUPS, L\"Groups\");\n            PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_LOGON, L\"Groups (Logon SID)\");\n            PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_INTEGRITY, L\"Groups (Mandatory label)\");\n            PhLoadListViewColumnsFromSetting(SETTING_TOKEN_GROUPS_LIST_VIEW_COLUMNS, tokenPageContext->ListViewHandle);\n            PhLoadListViewGroupStatesFromSetting(SETTING_TOKEN_GROUPS_LIST_VIEW_STATES, tokenPageContext->ListViewHandle);\n            PhLoadListViewSortColumnsFromSetting(SETTING_TOKEN_GROUPS_LIST_VIEW_SORT, tokenPageContext->ListViewHandle);\n            PhpTokenSetImageList(hwndDlg, tokenPageContext);\n\n            PhSetDialogItemText(hwndDlg, IDC_USER, L\"Unknown\");\n            PhSetDialogItemText(hwndDlg, IDC_USERSID, L\"Unknown\");\n\n            if (NT_SUCCESS(tokenPageContext->OpenObject(\n                &tokenHandle,\n                TOKEN_QUERY,\n                tokenPageContext->Context // ProcessId\n                )))\n            {\n                PH_TOKEN_USER tokenUser;\n                PPH_STRING stringUserSid;\n                ULONG tokenSessionId = ULONG_MAX;\n                BOOLEAN tokenElevation = FALSE;\n                TOKEN_ELEVATION_TYPE tokenElevationType = 0;\n                PPH_STRINGREF tokenElevationTypeString;\n                BOOLEAN isVirtualizationAllowed;\n                BOOLEAN isVirtualizationEnabled;\n                PH_TOKEN_APPCONTAINER tokenAppContainer;\n                PPH_STRING appContainerName;\n                PPH_STRING appContainerSidString;\n\n                if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser)))\n                {\n                    BOOLEAN tokenIsAppContainer = FALSE;\n\n                    PhGetTokenIsAppContainer(tokenHandle, &tokenIsAppContainer);\n\n                    if (!tokenIsAppContainer) // HACK (dmex)\n                    {\n                        PPHP_TOKEN_USER_RESOLVE_CONTEXT tokenUserResolve;\n\n                        PhSetDialogItemText(hwndDlg, IDC_USER, L\"Resolving...\");\n\n                        tokenUserResolve = PhAllocateZero(sizeof(PHP_TOKEN_USER_RESOLVE_CONTEXT));\n                        tokenUserResolve->WindowHandle = GetDlgItem(hwndDlg, IDC_USER);\n                        tokenUserResolve->TokenUserSid = PhAllocateCopy(tokenUser.User.Sid, PhLengthSid(tokenUser.User.Sid));\n\n                        PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpTokenUserResolveWorker, tokenUserResolve);\n                    }\n\n                    if (stringUserSid = PhSidToStringSid(tokenUser.User.Sid))\n                    {\n                        PhSetDialogItemText(hwndDlg, IDC_USERSID, stringUserSid->Buffer);\n                        PhDereferenceObject(stringUserSid);\n                    }\n                }\n\n                PhGetTokenSessionId(tokenHandle, &tokenSessionId);\n                PhGetTokenElevation(tokenHandle, &tokenElevation);\n                PhGetTokenElevationType(tokenHandle, &tokenElevationType);\n\n                if (tokenSessionId != ULONG_MAX)\n                    PhSetDialogItemValue(hwndDlg, IDC_SESSIONID, tokenSessionId, FALSE);\n                else\n                    PhSetDialogItemText(hwndDlg, IDC_SESSIONID, L\"Unknown\");\n\n                if (PhGetElevationTypeString(tokenElevation, tokenElevationType, &tokenElevationTypeString))\n                    PhSetDialogItemText(hwndDlg, IDC_ELEVATED, PhGetStringRefZ(tokenElevationTypeString));\n                else\n                    PhSetDialogItemText(hwndDlg, IDC_ELEVATED, L\"Unknown\");\n\n                if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed)))\n                {\n                    if (isVirtualizationAllowed)\n                    {\n                        if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled)))\n                        {\n                            PhSetDialogItemText(hwndDlg, IDC_VIRTUALIZED, isVirtualizationEnabled ? L\"Yes\" : L\"No\");\n                        }\n                    }\n                    else\n                    {\n                        PhSetDialogItemText(hwndDlg, IDC_VIRTUALIZED, L\"Not allowed\");\n                    }\n                }\n\n                if (WindowsVersion >= WINDOWS_8)\n                {\n                    appContainerName = NULL;\n                    appContainerSidString = NULL;\n\n                    if (NT_SUCCESS(PhGetTokenAppContainerSid(tokenHandle, &tokenAppContainer)))\n                    {\n                        appContainerName = PhGetAppContainerName(tokenAppContainer.AppContainer.Sid);\n                        appContainerSidString = PhSidToStringSid(tokenAppContainer.AppContainer.Sid);\n                    }\n\n                    if (appContainerName)\n                    {\n                        PPH_STRING packageFamilyName;\n\n                        packageFamilyName = PhConcatStrings2(appContainerName->Buffer, L\" (APP_CONTAINER)\");\n                        PhSetDialogItemText(hwndDlg, IDC_USER, PhGetString(packageFamilyName));\n\n                        PhDereferenceObject(packageFamilyName);\n                        PhDereferenceObject(appContainerName);\n                    }\n\n                    if (appContainerSidString)\n                    {\n                        PhSetDialogItemText(hwndDlg, IDC_USERSID, PhGetString(appContainerSidString));\n                        PhDereferenceObject(appContainerSidString);\n                    }\n                }\n\n                {\n                    ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE);\n                    PhpTokenPageFreeListViewEntries(tokenPageContext);\n                    ListView_DeleteAllItems(tokenPageContext->ListViewHandle);\n\n                    PhpUpdateTokenDangerousFlags(tokenPageContext, tokenHandle);\n                    PhpUpdateTokenGroups(tokenPageContext, tokenHandle);\n                    PhpUpdateTokenPrivileges(tokenPageContext, tokenHandle);\n\n                    ExtendedListView_SortItems(tokenPageContext->ListViewHandle);\n                    ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE);\n                }\n\n                tokenPageContext->CloseObject(tokenHandle, FALSE, tokenPageContext->Context);\n            }\n\n            if (tokenPageContext->SinglePageContext)\n            {\n                LPPROPSHEETPAGE page = (LPPROPSHEETPAGE)lParam;\n                if (page) PhFree(page);\n\n                PhSetApplicationWindowIcon(hwndDlg);\n                PhSetWindowText(hwndDlg, L\"Linked Token\");\n\n                PhInitializeLayoutManager(&tokenPageContext->LayoutManager, hwndDlg);\n                PhAddLayoutItem(&tokenPageContext->LayoutManager, tokenPageContext->ListViewHandle, NULL, PH_ANCHOR_ALL);\n                PhAddLayoutItem(&tokenPageContext->LayoutManager, GetDlgItem(hwndDlg, IDC_DEFAULTPERM), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n                PhAddLayoutItem(&tokenPageContext->LayoutManager, GetDlgItem(hwndDlg, IDC_PERMISSIONS), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n                PhAddLayoutItem(&tokenPageContext->LayoutManager, GetDlgItem(hwndDlg, IDC_INTEGRITY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n                PhAddLayoutItem(&tokenPageContext->LayoutManager, GetDlgItem(hwndDlg, IDC_ADVANCED), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);\n\n                if (PhValidWindowPlacementFromSetting(SETTING_TOKEN_WINDOW_POSITION))\n                    PhLoadWindowPlacementFromSetting(SETTING_TOKEN_WINDOW_POSITION, SETTING_TOKEN_WINDOW_SIZE, hwndDlg);\n                else\n                    PhCenterWindow(hwndDlg, NULL);\n\n                PhSetDialogFocus(hwndDlg, tokenPageContext->ListViewHandle);\n            }\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhSaveListViewSortColumnsToSetting(SETTING_TOKEN_GROUPS_LIST_VIEW_SORT, tokenPageContext->ListViewHandle);\n            PhSaveListViewGroupStatesToSetting(SETTING_TOKEN_GROUPS_LIST_VIEW_STATES, tokenPageContext->ListViewHandle);\n            PhSaveListViewColumnsToSetting(SETTING_TOKEN_GROUPS_LIST_VIEW_COLUMNS, tokenPageContext->ListViewHandle);\n\n            if (tokenPageContext->SinglePageContext)\n            {\n                PhSaveWindowPlacementToSetting(SETTING_TOKEN_WINDOW_POSITION, SETTING_TOKEN_WINDOW_SIZE, hwndDlg);\n                PhDeleteLayoutManager(&tokenPageContext->LayoutManager);\n\n                if (tokenPageContext->Context)\n                {\n                    NtClose(tokenPageContext->Context);\n                    tokenPageContext->Context = NULL;\n                }\n            }\n\n            PhpTokenPageFreeListViewEntries(tokenPageContext);\n\n            if (tokenPageContext->ListViewImageList) PhImageListDestroy(tokenPageContext->ListViewImageList);\n            if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups);\n            if (tokenPageContext->RestrictedSids) PhFree(tokenPageContext->RestrictedSids);\n            if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges);\n        }\n        break;\n    case WM_SIZE:\n        {\n            if (tokenPageContext->SinglePageContext)\n            {\n                PhLayoutManagerLayout(&tokenPageContext->LayoutManager);\n            }\n        }\n        break;\n    case WM_DPICHANGED:\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            PhpTokenSetImageList(hwndDlg, tokenPageContext);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDCANCEL:\n            case IDOK:\n                {\n                    if (tokenPageContext->SinglePageContext)\n                    {\n                        EndDialog(hwndDlg, IDOK);\n                    }\n                }\n                break;\n            case ID_PRIVILEGE_ENABLE:\n            case ID_PRIVILEGE_DISABLE:\n            case ID_PRIVILEGE_RESET:\n            case ID_PRIVILEGE_REMOVE:\n                {\n                    NTSTATUS status;\n                    BOOLEAN listViewGroupItemsValid = TRUE;\n                    PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listViewItems;\n                    ULONG numberOfItems;\n                    HANDLE tokenHandle;\n                    ULONG i;\n\n                    PhGetSelectedListViewItemParams(tokenPageContext->ListViewHandle, &listViewItems, &numberOfItems);\n\n                    for (i = 0; i < numberOfItems; i++)\n                    {\n                        if (listViewItems[i]->GroupId != PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES)\n                        {\n                            listViewGroupItemsValid = FALSE;\n                            break;\n                        }\n                    }\n\n                    if (!listViewGroupItemsValid)\n                    {\n                        PhFree(listViewItems);\n                        break;\n                    }\n\n                    if (GET_WM_COMMAND_ID(wParam, lParam) == ID_PRIVILEGE_REMOVE)\n                    {\n                        if (!PhShowConfirmMessage(\n                            hwndDlg,\n                            L\"remove\",\n                            L\"the selected privilege(s)\",\n                            L\"Removing privileges may reduce the functionality of the process, \"\n                            L\"and is permanent for the lifetime of the process.\",\n                            FALSE\n                            ))\n                        {\n                            PhFree(listViewItems);\n                            break;\n                        }\n                    }\n\n                    status = tokenPageContext->OpenObject(\n                        &tokenHandle,\n                        TOKEN_ADJUST_PRIVILEGES,\n                        tokenPageContext->Context // ProcessId\n                        );\n\n                    if (NT_SUCCESS(status))\n                    {\n                        ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE);\n\n                        for (i = 0; i < numberOfItems; i++)\n                        {\n                            PPH_STRING privilegeName = NULL;\n                            ULONG newAttributes = listViewItems[i]->TokenPrivilege->Attributes;\n\n                            if (NT_SUCCESS(PhLookupPrivilegeName(&listViewItems[i]->TokenPrivilege->Luid, &privilegeName)))\n                            {\n                                PH_AUTO(privilegeName);\n                            }\n\n                            switch (GET_WM_COMMAND_ID(wParam, lParam))\n                            {\n                            case ID_PRIVILEGE_ENABLE:\n                                {\n                                    SetFlag(newAttributes, SE_PRIVILEGE_ENABLED);\n                                }\n                                break;\n                            case ID_PRIVILEGE_DISABLE:\n                                {\n                                    ClearFlag(newAttributes, SE_PRIVILEGE_ENABLED);\n                                }\n                                break;\n                            case ID_PRIVILEGE_RESET:\n                                {\n                                    if (FlagOn(newAttributes, SE_PRIVILEGE_ENABLED_BY_DEFAULT))\n                                        SetFlag(newAttributes, SE_PRIVILEGE_ENABLED);\n                                    else\n                                        ClearFlag(newAttributes, SE_PRIVILEGE_ENABLED);\n                                }\n                                break;\n                            case ID_PRIVILEGE_REMOVE:\n                                {\n                                    newAttributes = SE_PRIVILEGE_REMOVED;\n                                }\n                                break;\n                            }\n\n                            if (NT_SUCCESS(PhSetTokenPrivilege(\n                                tokenHandle,\n                                NULL,\n                                &listViewItems[i]->TokenPrivilege->Luid,\n                                newAttributes\n                                )))\n                            {\n                                LONG itemIndex;\n\n                                itemIndex = PhFindListViewItemByParam(\n                                    tokenPageContext->ListViewHandle,\n                                    INT_ERROR,\n                                    listViewItems[i]\n                                    );\n\n                                if (itemIndex != INT_ERROR)\n                                {\n                                    if (GET_WM_COMMAND_ID(wParam, lParam) != ID_PRIVILEGE_REMOVE)\n                                    {\n                                        // Refresh the status text (and background color).\n                                        listViewItems[i]->TokenPrivilege->Attributes = newAttributes;\n                                        PhSetListViewSubItem(\n                                            tokenPageContext->ListViewHandle,\n                                            itemIndex,\n                                            PH_PROCESS_TOKEN_INDEX_STATUS,\n                                            PhGetPrivilegeAttributesString(newAttributes)\n                                            );\n                                    }\n                                    else\n                                    {\n                                        ListView_DeleteItem(tokenPageContext->ListViewHandle, itemIndex);\n                                    }\n                                }\n                            }\n                            else\n                            {\n                                PWSTR action = L\"set\";\n\n                                switch (GET_WM_COMMAND_ID(wParam, lParam))\n                                {\n                                case ID_PRIVILEGE_ENABLE:\n                                    action = L\"enable\";\n                                    break;\n                                case ID_PRIVILEGE_DISABLE:\n                                    action = L\"disable\";\n                                    break;\n                                case ID_PRIVILEGE_RESET:\n                                    action = L\"reset\";\n                                    break;\n                                case ID_PRIVILEGE_REMOVE:\n                                    action = L\"remove\";\n                                    break;\n                                }\n\n                                if (!PhShowContinueStatus(\n                                    hwndDlg,\n                                    PhaFormatString(L\"Unable to %s %s.\", action, PhGetStringOrDefault(privilegeName, L\"privilege\"))->Buffer,\n                                    STATUS_UNSUCCESSFUL,\n                                    0\n                                    ))\n                                    break;\n                            }\n                        }\n\n                        ExtendedListView_SortItems(tokenPageContext->ListViewHandle);\n                        ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE);\n\n                        tokenPageContext->CloseObject(tokenHandle, FALSE, tokenPageContext->Context);\n                    }\n                    else\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to open the token.\", status, 0);\n                    }\n\n                    PhFree(listViewItems);\n                }\n                break;\n            case ID_GROUP_ENABLE:\n            case ID_GROUP_DISABLE:\n            case ID_GROUP_RESET:\n                {\n                    NTSTATUS status;\n                    BOOLEAN listViewGroupItemsValid = TRUE;\n                    PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listViewItems;\n                    ULONG numberOfItems;\n                    HANDLE tokenHandle;\n                    ULONG i;\n\n                    PhGetSelectedListViewItemParams(\n                        tokenPageContext->ListViewHandle,\n                        &listViewItems,\n                        &numberOfItems\n                        );\n\n                    for (i = 0; i < numberOfItems; i++)\n                    {\n                        if (!(listViewItems[i]->GroupId == PH_PROCESS_TOKEN_CATEGORY_GROUPS ||\n                            listViewItems[i]->GroupId == PH_PROCESS_TOKEN_CATEGORY_LOGON ||\n                            listViewItems[i]->GroupId == PH_PROCESS_TOKEN_CATEGORY_INTEGRITY))\n                        {\n                            listViewGroupItemsValid = FALSE;\n                            break;\n                        }\n                    }\n\n                    if (!listViewGroupItemsValid)\n                    {\n                        PhFree(listViewItems);\n                        break;\n                    }\n\n                    status = tokenPageContext->OpenObject(\n                        &tokenHandle,\n                        TOKEN_ADJUST_GROUPS,\n                        tokenPageContext->Context // ProcessId\n                        );\n\n                    if (NT_SUCCESS(status))\n                    {\n                        ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE);\n\n                        for (i = 0; i < numberOfItems; i++)\n                        {\n                            ULONG newAttributes = listViewItems[i]->TokenGroup->Attributes;\n\n                            switch (GET_WM_COMMAND_ID(wParam, lParam))\n                            {\n                            case ID_GROUP_ENABLE:\n                                newAttributes |= SE_GROUP_ENABLED;\n                                break;\n                            case ID_GROUP_DISABLE:\n                                newAttributes &= ~SE_GROUP_ENABLED;\n                                break;\n                            case ID_GROUP_RESET:\n                                {\n                                    if (newAttributes & SE_GROUP_ENABLED_BY_DEFAULT)\n                                        newAttributes |= SE_GROUP_ENABLED;\n                                    else\n                                        newAttributes &= ~SE_GROUP_ENABLED;\n                                }\n                                break;\n                            }\n\n                            if (NT_SUCCESS(status = PhSetTokenGroups(\n                                tokenHandle,\n                                NULL,\n                                listViewItems[i]->TokenGroup->Sid,\n                                newAttributes\n                                )))\n                            {\n                                PPH_STRING attributesString;\n\n                                if (attributesString = PhGetGroupAttributesString(newAttributes, FALSE))\n                                {\n                                    LONG itemIndex;\n\n                                    itemIndex = PhFindListViewItemByParam(\n                                        tokenPageContext->ListViewHandle,\n                                        INT_ERROR,\n                                        listViewItems[i]\n                                        );\n\n                                    if (itemIndex != INT_ERROR)\n                                    {\n                                        // Refresh the status text (and background color).\n                                        listViewItems[i]->TokenGroup->Attributes = newAttributes;\n\n                                        PhSetListViewSubItem(tokenPageContext->ListViewHandle, itemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, attributesString->Buffer);\n                                    }\n\n                                    PhDereferenceObject(attributesString);\n                                }\n                            }\n                            else\n                            {\n                                PWSTR action = L\"set\";\n\n                                switch (GET_WM_COMMAND_ID(wParam, lParam))\n                                {\n                                case ID_GROUP_ENABLE:\n                                    action = L\"enable\";\n                                    break;\n                                case ID_GROUP_DISABLE:\n                                    action = L\"disable\";\n                                    break;\n                                case ID_GROUP_RESET:\n                                    action = L\"reset\";\n                                    break;\n                                }\n\n                                if (!PhShowContinueStatus(\n                                    hwndDlg,\n                                    PhaFormatString(L\"Unable to %s %s.\", action, L\"group\")->Buffer,\n                                    status,\n                                    0\n                                    ))\n                                    break;\n                            }\n                        }\n\n                        ExtendedListView_SortItems(tokenPageContext->ListViewHandle);\n                        ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE);\n\n                        tokenPageContext->CloseObject(\n                            tokenHandle,\n                            FALSE,\n                            tokenPageContext->Context\n                            );\n                    }\n                    else\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to open the token.\", status, 0);\n                    }\n\n                    PhFree(listViewItems);\n                }\n                break;\n            case ID_UIACCESS_REMOVE:\n                {\n                    NTSTATUS status;\n                    PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listViewItems;\n                    ULONG numberOfItems;\n                    HANDLE tokenHandle;\n\n                    PhGetSelectedListViewItemParams(\n                        tokenPageContext->ListViewHandle,\n                        &listViewItems,\n                        &numberOfItems\n                        );\n\n                    if (numberOfItems != 1)\n                    {\n                        PhFree(listViewItems);\n                        break;\n                    }\n\n                    if ((listViewItems[0]->GroupId != PH_PROCESS_TOKEN_CATEGORY_FLAGS) ||\n                        (listViewItems[0]->ItemFlag != PH_PROCESS_TOKEN_FLAG_UIACCESS))\n                    {\n                        PhFree(listViewItems);\n                        break;\n                    }\n\n                    if (!PhShowConfirmMessage(\n                        hwndDlg,\n                        L\"remove\",\n                        L\"the UIAccess flag\",\n                        L\"Removing this flag may reduce the functionality of the process \"\n                        L\"provided it is an accessibility application.\",\n                        FALSE\n                        ))\n                    {\n                        PhFree(listViewItems);\n                        break;\n                    }\n\n                    status = tokenPageContext->OpenObject(\n                        &tokenHandle,\n                        TOKEN_ADJUST_DEFAULT,\n                        tokenPageContext->Context // ProcessId\n                        );\n\n                    if (NT_SUCCESS(status))\n                    {\n                        ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE);\n\n                        status = PhSetTokenUIAccess(tokenHandle, FALSE);\n\n                        if (NT_SUCCESS(status))\n                        {\n                            LONG itemIndex;\n\n                            itemIndex = PhFindListViewItemByParam(\n                                tokenPageContext->ListViewHandle,\n                                INT_ERROR,\n                                listViewItems[0]\n                                );\n\n                            if (itemIndex != INT_ERROR)\n                            {\n                                ListView_DeleteItem(tokenPageContext->ListViewHandle, itemIndex);\n                            }\n                        }\n                        else\n                        {\n                            PhShowStatus(hwndDlg, L\"Unable to disable UIAccess flag.\", status, 0);\n                        }\n\n                        ExtendedListView_SortItems(tokenPageContext->ListViewHandle);\n                        ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE);\n\n                        tokenPageContext->CloseObject(\n                            tokenHandle,\n                            FALSE,\n                            tokenPageContext->Context\n                            );\n                    }\n                    else\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to open the token.\", status, 0);\n                    }\n\n                    PhFree(listViewItems);\n                }\n                break;\n            case IDC_DEFAULTPERM:\n                {\n                    PhEditSecurity(\n                        PhCsForceNoParent ? NULL : hwndDlg,\n                        L\"Default Token\",\n                        L\"TokenDefault\",\n                        tokenPageContext->OpenObject,\n                        tokenPageContext->CloseObject,\n                        tokenPageContext->Context // ProcessId\n                        );\n                }\n                break;\n            case IDC_PERMISSIONS:\n                {\n                    PhEditSecurity(\n                        PhCsForceNoParent ? NULL : hwndDlg,\n                        L\"Token\",\n                        L\"Token\",\n                        tokenPageContext->OpenObject,\n                        tokenPageContext->CloseObject,\n                        tokenPageContext->Context // ProcessId\n                        );\n                }\n                break;\n            case IDC_INTEGRITY:\n                {\n                    NTSTATUS status;\n                    RECT rect;\n                    PPH_EMENU menu;\n                    HANDLE tokenHandle;\n                    MANDATORY_LEVEL_RID integrityLevelRID;\n                    PPH_EMENU_ITEM selectedItem;\n\n                    if (!PhGetWindowRect(GetDlgItem(hwndDlg, IDC_INTEGRITY), &rect))\n                        break;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatorySecureProcessRID, L\"Protected\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatorySystemRID, L\"System\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryHighRID, L\"High\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryMediumPlusRID, L\"Medium +\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryMediumRID, L\"Medium\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLowRID, L\"Low\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryUntrustedRID, L\"Untrusted\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, USHRT_MAX, L\"Custom...\", NULL, NULL), ULONG_MAX);\n\n                    integrityLevelRID = ULONG_MAX;\n\n                    // Put a radio check on the menu item that corresponds with the current integrity level.\n                    // Also disable menu items which correspond to higher integrity levels since\n                    // NtSetInformationToken doesn't allow integrity levels to be raised.\n                    if (NT_SUCCESS(status = tokenPageContext->OpenObject(\n                        &tokenHandle,\n                        TOKEN_QUERY,\n                        tokenPageContext->Context // ProcessId\n                        )))\n                    {\n                        if (NT_SUCCESS(status = PhGetTokenIntegrityLevelRID(\n                            tokenHandle,\n                            &integrityLevelRID,\n                            NULL\n                            )))\n                        {\n                            ULONG customLevelPosition = 0; // Processing atypical integrity levels\n\n                            for (ULONG i = 0; i < menu->Items->Count; i++)\n                            {\n                                PPH_EMENU_ITEM menuItem = menu->Items->Items[i];\n\n                                if (menuItem->Id == (ULONG)integrityLevelRID)\n                                {\n                                    menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK;\n                                    customLevelPosition = 0; // The integrity level is a well-known one. No need to add a new menu item.\n                                }\n                                else if (menuItem->Id > (ULONG)integrityLevelRID && menuItem->Id != USHRT_MAX)\n                                {\n                                    PhSetDisabledEMenuItem(menuItem);\n                                    customLevelPosition = i + 1;\n                                }\n                            }\n\n                            if (customLevelPosition)\n                            {\n                                PPH_EMENU_ITEM unknownIntegrityItem;\n\n                                unknownIntegrityItem = PhCreateEMenuItem(0, (ULONG)integrityLevelRID, L\"Intermediate level\", NULL, NULL);\n                                unknownIntegrityItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK;\n                                PhInsertEMenuItem(menu, unknownIntegrityItem, customLevelPosition);\n                            }\n                        }\n\n                        tokenPageContext->CloseObject(\n                            tokenHandle,\n                            FALSE,\n                            tokenPageContext->Context\n                            );\n                    }\n\n                    if (!NT_SUCCESS(status))\n                    {\n                        for (ULONG i = 0; i < menu->Items->Count; i++)\n                        {\n                            PhSetDisabledEMenuItem(menu->Items->Items[i]);\n                        }\n                    }\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_BOTTOM,\n                        rect.left,\n                        rect.top\n                        );\n\n                    if (selectedItem && selectedItem->Id != integrityLevelRID)\n                    {\n                        if (PhShowConfirmMessage(\n                            hwndDlg,\n                            L\"set\",\n                            L\"the integrity level\",\n                            L\"Once lowered, the integrity level of the token cannot be raised again.\",\n                            FALSE\n                            ))\n                        {\n                            ULONG integrityLevel = ULONG_MAX;\n\n                            if (selectedItem->Id == USHRT_MAX)\n                            {\n                                PPH_STRING selectedChoice = NULL;\n                                ULONG64 integer = 0;\n\n                                while (PhaChoiceDialog(\n                                    hwndDlg,\n                                    L\"Integrity Level\",\n                                    L\"Enter a custom integrity level:\",\n                                    NULL,\n                                    0,\n                                    NULL,\n                                    PH_CHOICE_DIALOG_USER_CHOICE,\n                                    &selectedChoice,\n                                    NULL,\n                                    NULL\n                                    ))\n                                {\n                                    if (PhStringToInteger64(&selectedChoice->sr, 0, &integer))\n                                    {\n                                        if ((ULONG)integer < (ULONG)integrityLevelRID)\n                                        {\n                                            integrityLevel = (ULONG)integer;\n                                            break;\n                                        }\n                                    }\n                                }\n\n                                if (integrityLevel == ULONG_MAX)\n                                    goto CleanupExit;\n                            }\n                            else\n                            {\n                                integrityLevel = selectedItem->Id;\n                            }\n\n                            if (NT_SUCCESS(status = tokenPageContext->OpenObject(\n                                &tokenHandle,\n                                TOKEN_QUERY | TOKEN_ADJUST_DEFAULT,\n                                tokenPageContext->Context // ProcessId\n                                )))\n                            {\n                                static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;\n                                UCHAR newSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];\n                                PSID newSid;\n                                TOKEN_MANDATORY_LABEL mandatoryLabel;\n\n                                newSid = (PSID)newSidBuffer;\n                                PhInitializeSid(newSid, &mandatoryLabelAuthority, 1);\n                                *PhSubAuthoritySid(newSid, 0) = integrityLevel;\n                                mandatoryLabel.Label.Sid = newSid;\n                                mandatoryLabel.Label.Attributes = SE_GROUP_INTEGRITY;\n\n                                status = NtSetInformationToken(\n                                    tokenHandle,\n                                    TokenIntegrityLevel,\n                                    &mandatoryLabel,\n                                    sizeof(TOKEN_MANDATORY_LABEL)\n                                    );\n\n                                if (NT_SUCCESS(status))\n                                {\n                                    ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE);\n                                    PhpTokenPageFreeListViewEntries(tokenPageContext);\n                                    ListView_DeleteAllItems(tokenPageContext->ListViewHandle);\n                                    PhpUpdateTokenGroups(tokenPageContext, tokenHandle);\n                                    PhpUpdateTokenPrivileges(tokenPageContext, tokenHandle);\n                                    ExtendedListView_SortItems(tokenPageContext->ListViewHandle);\n                                    ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE);\n                                }\n\n                                tokenPageContext->CloseObject(\n                                    tokenHandle,\n                                    FALSE,\n                                    tokenPageContext->Context\n                                    );\n                            }\n\n                            if (!NT_SUCCESS(status))\n                                PhShowStatus(hwndDlg, L\"Unable to set the integrity level\", status, 0);\n                        }\n                    }\n\n                CleanupExit:\n                    PhDestroyEMenu(menu);\n                }\n                break;\n            case IDC_ADVANCED:\n                {\n                    HANDLE tokenHandle;\n                    BOOLEAN tokenIsAppContainer = FALSE;\n\n                    if (NT_SUCCESS(tokenPageContext->OpenObject(\n                        &tokenHandle,\n                        TOKEN_QUERY,\n                        tokenPageContext->Context // ProcessId\n                        )))\n                    {\n                        PhGetTokenIsAppContainer(tokenHandle, &tokenIsAppContainer);\n\n                        if (!tokenIsAppContainer)\n                        {\n                            PPH_STRING packageName;\n\n                            if (NT_SUCCESS(PhGetTokenPackageFullName(tokenHandle, &packageName)))\n                            {\n                                tokenIsAppContainer = !PhIsNullOrEmptyString(packageName);\n                                PhDereferenceObject(packageName);\n                            }\n                        }\n\n                        tokenPageContext->CloseObject(\n                            tokenHandle,\n                            FALSE,\n                            tokenPageContext->Context\n                            );\n                    }\n\n                    PhpShowTokenAdvancedProperties(hwndDlg, tokenPageContext, tokenIsAppContainer);\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                {\n                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_SESSIONID));\n                    return TRUE;\n                }\n                break;\n            }\n\n            PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);\n\n            REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->ListViewHandle, uMsg, wParam, lParam);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == tokenPageContext->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(tokenPageContext->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(tokenPageContext->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    BOOLEAN hasMixedCategories = FALSE;\n                    BOOLEAN hasRemovedItems = FALSE;\n                    PH_PROCESS_TOKEN_CATEGORY currentCategory = listviewItems[0]->GroupId;\n                    ULONG i;\n\n                    for (i = 0; i < numberOfItems; i++)\n                    {\n                        if (listviewItems[i]->GroupId != currentCategory)\n                        {\n                            hasMixedCategories = TRUE;\n                            break;\n                        }\n                    }\n\n                    if (currentCategory == PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES)\n                    {\n                        for (i = 0; i < numberOfItems; i++)\n                        {\n                            if (listviewItems[i]->TokenPrivilege &&\n                                FlagOn(listviewItems[i]->TokenPrivilege->Attributes, SE_PRIVILEGE_REMOVED))\n                            {\n                                hasRemovedItems = TRUE;\n                                break;\n                            }\n                        }\n                    }\n\n                    menu = PhCreateEMenu();\n\n                    if (!hasMixedCategories)\n                    {\n                        switch (currentCategory)\n                        {\n                        case PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES:\n                            {\n                                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_ENABLE, L\"&Enable\", NULL, NULL), ULONG_MAX);\n                                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_DISABLE, L\"&Disable\", NULL, NULL), ULONG_MAX);\n                                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_RESET, L\"Re&set\", NULL, NULL), ULONG_MAX);\n                                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_REMOVE, L\"&Remove\", NULL, NULL), ULONG_MAX);\n                                PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n\n                                if (hasRemovedItems)\n                                {\n                                    PhSetFlagsAllEMenuItems(menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);\n                                }\n                            }\n                            break;\n                        case PH_PROCESS_TOKEN_CATEGORY_GROUPS:\n                        case PH_PROCESS_TOKEN_CATEGORY_LOGON:\n                        case PH_PROCESS_TOKEN_CATEGORY_INTEGRITY:\n                            {\n                                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_GROUP_ENABLE, L\"&Enable\", NULL, NULL), ULONG_MAX);\n                                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_GROUP_DISABLE, L\"&Disable\", NULL, NULL), ULONG_MAX);\n                                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_GROUP_RESET, L\"Re&set\", NULL, NULL), ULONG_MAX);\n                                PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                            }\n                            break;\n                        case PH_PROCESS_TOKEN_CATEGORY_FLAGS:\n                            {\n                                if ((numberOfItems == 1) && (listviewItems[0]->ItemFlag == PH_PROCESS_TOKEN_FLAG_UIACCESS))\n                                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_UIACCESS_REMOVE, L\"&Remove\", NULL, NULL), ULONG_MAX);\n                            }\n                            break;\n                        }\n                    }\n\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, tokenPageContext->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(tokenPageContext->ListViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        {\n            if (tokenPageContext->SinglePageContext)\n                return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n        }\n        break;\n    case WM_CTLCOLORDLG:\n        {\n            if (tokenPageContext->SinglePageContext)\n                return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n        }\n        break;\n    case WM_CTLCOLORSTATIC:\n        {\n            if (tokenPageContext->SinglePageContext)\n                return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhpShowTokenAdvancedProperties(\n    _In_ HWND ParentWindowHandle,\n    _In_ PTOKEN_PAGE_CONTEXT Context,\n    _In_ BOOLEAN ShowAppContainerPage\n    )\n{\n    PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };\n    HPROPSHEETPAGE pages[7];\n    PROPSHEETPAGE page;\n    ULONG numberOfPages;\n\n    propSheetHeader.dwFlags =\n        PSH_NOAPPLYNOW |\n        PSH_NOCONTEXTHELP |\n        PSH_PROPTITLE;\n    propSheetHeader.hInstance = NtCurrentImageBase();\n    propSheetHeader.hwndParent = ParentWindowHandle;\n    propSheetHeader.pszCaption = L\"Token\";\n    propSheetHeader.nStartPage = 0;\n    propSheetHeader.phpage = pages;\n\n    numberOfPages = 0;\n\n    // General\n\n    memset(&page, 0, sizeof(PROPSHEETPAGE));\n    page.dwSize = sizeof(PROPSHEETPAGE);\n    page.pszTemplate = MAKEINTRESOURCE(IDD_TOKGENERAL);\n    page.hInstance = NtCurrentImageBase();\n    page.pfnDlgProc = PhpTokenGeneralPageProc;\n    page.lParam = (LPARAM)Context;\n    pages[numberOfPages++] = CreatePropertySheetPage(&page);\n\n    // Advanced\n\n    memset(&page, 0, sizeof(PROPSHEETPAGE));\n    page.dwSize = sizeof(PROPSHEETPAGE);\n    page.pszTemplate = MAKEINTRESOURCE(IDD_TOKADVANCED);\n    page.hInstance = NtCurrentImageBase();\n    page.pfnDlgProc = PhpTokenAdvancedPageProc;\n    page.lParam = (LPARAM)Context;\n    pages[numberOfPages++] = CreatePropertySheetPage(&page);\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        if (ShowAppContainerPage)\n        {\n            memset(&page, 0, sizeof(PROPSHEETPAGE));\n            page.dwSize = sizeof(PROPSHEETPAGE);\n            page.dwFlags = PSP_USETITLE;\n            page.pszTemplate = MAKEINTRESOURCE(IDD_TOKADVANCED);\n            page.hInstance = NtCurrentImageBase();\n            page.pszTitle = L\"Container\";\n            page.pfnDlgProc = PhpTokenContainerPageProc;\n            page.lParam = (LPARAM)Context;\n            pages[numberOfPages++] = CreatePropertySheetPage(&page);\n        }\n\n        // Capabilities\n\n        memset(&page, 0, sizeof(PROPSHEETPAGE));\n        page.dwSize = sizeof(PROPSHEETPAGE);\n        page.pszTemplate = MAKEINTRESOURCE(IDD_TOKCAPABILITIES);\n        page.hInstance = NtCurrentImageBase();\n        page.pfnDlgProc = PhpTokenCapabilitiesPageProc;\n        page.lParam = (LPARAM)Context;\n        pages[numberOfPages++] = CreatePropertySheetPage(&page);\n\n        // Claims\n\n        memset(&page, 0, sizeof(PROPSHEETPAGE));\n        page.dwSize = sizeof(PROPSHEETPAGE);\n        page.dwFlags = PSP_USETITLE;\n        page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES);\n        page.hInstance = NtCurrentImageBase();\n        page.pszTitle = L\"Claims\";\n        page.pfnDlgProc = PhpTokenClaimsPageProc;\n        page.lParam = (LPARAM)Context;\n        pages[numberOfPages++] = CreatePropertySheetPage(&page);\n\n        // AppModel Policy\n\n        memset(&page, 0, sizeof(PROPSHEETPAGE));\n        page.dwSize = sizeof(PROPSHEETPAGE);\n        page.dwFlags = PSP_USETITLE;\n        page.pszTemplate = MAKEINTRESOURCE(IDD_TOKAPPPOLICY);\n        page.hInstance = NtCurrentImageBase();\n        page.pszTitle = L\"Policy\";\n        page.pfnDlgProc = PhpTokenAppPolicyPageProc;\n        page.lParam = (LPARAM)Context;\n        pages[numberOfPages++] = CreatePropertySheetPage(&page);\n\n        // (Token) Attributes\n\n        memset(&page, 0, sizeof(PROPSHEETPAGE));\n        page.dwSize = sizeof(PROPSHEETPAGE);\n        page.dwFlags = PSP_USETITLE;\n        page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES);\n        page.hInstance = NtCurrentImageBase();\n        page.pszTitle = L\"Attributes\";\n        page.pfnDlgProc = PhpTokenAttributesPageProc;\n        page.lParam = (LPARAM)Context;\n        pages[numberOfPages++] = CreatePropertySheetPage(&page);\n    }\n\n    propSheetHeader.nPages = numberOfPages;\n    PhModalPropertySheet(&propSheetHeader);\n}\n\n_Function_class_(PH_OPEN_OBJECT)\nstatic NTSTATUS PhpOpenLinkedToken(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Context) return PhGetTokenLinkedToken((HANDLE)Context, Handle);\n    return STATUS_UNSUCCESSFUL;\n}\n\n_Function_class_(PH_CLOSE_OBJECT)\nstatic NTSTATUS PhpCloseLinkedToken(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    )\n{\n    if (Handle) NtClose(Handle);\n    return STATUS_SUCCESS;\n}\n\nINT_PTR CALLBACK PhpTokenGeneralPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n\n    tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!tokenPageContext)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HANDLE tokenHandle;\n            PPH_STRING tokenUserName = NULL;\n            PPH_STRING tokenUserSid = NULL;\n            PPH_STRING tokenOwnerName = NULL;\n            PPH_STRING tokenPrimaryGroupName = NULL;\n            ULONG tokenSessionId = ULONG_MAX;\n            BOOLEAN tokenElevation = FALSE;\n            TOKEN_ELEVATION_TYPE tokenElevationType = 0;\n            PPH_STRINGREF tokenElevationTypeString;\n            BOOLEAN hasLinkedToken = FALSE;\n            PWSTR tokenVirtualization = L\"N/A\";\n            PWSTR tokenUIAccess = L\"Unknown\";\n            WCHAR tokenSourceName[TOKEN_SOURCE_LENGTH + 1] = { L\"Unknown\" };\n            WCHAR tokenSourceLuid[PH_INT64_STR_LEN_1] = { L\"Unknown\" };\n\n            // HACK\n            PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg)));\n\n            if (NT_SUCCESS(tokenPageContext->OpenObject(\n                &tokenHandle,\n                TOKEN_QUERY,\n                tokenPageContext->Context // ProcessId\n                )))\n            {\n                PH_TOKEN_USER tokenUser;\n                PH_TOKEN_OWNER tokenOwner;\n                PTOKEN_PRIMARY_GROUP tokenPrimaryGroup;\n                BOOLEAN isVirtualizationAllowed;\n                BOOLEAN isVirtualizationEnabled;\n                BOOLEAN isUIAccessEnabled;\n\n                if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser)))\n                {\n                    tokenUserName = PH_AUTO(PhGetSidFullName(tokenUser.User.Sid, TRUE, NULL));\n                    tokenUserSid = PH_AUTO(PhSidToStringSid(tokenUser.User.Sid));\n                }\n\n                if (NT_SUCCESS(PhGetTokenOwner(tokenHandle, &tokenOwner)))\n                {\n                    tokenOwnerName = PH_AUTO(PhGetSidFullName(tokenOwner.Owner.Sid, TRUE, NULL));\n                }\n\n                if (NT_SUCCESS(PhGetTokenPrimaryGroup(tokenHandle, &tokenPrimaryGroup)))\n                {\n                    tokenPrimaryGroupName = PH_AUTO(PhGetSidFullName(tokenPrimaryGroup->PrimaryGroup, TRUE, NULL));\n                    PhFree(tokenPrimaryGroup);\n                }\n\n                PhGetTokenSessionId(tokenHandle, &tokenSessionId);\n                PhGetTokenElevation(tokenHandle, &tokenElevation);\n\n                if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &tokenElevationType)))\n                {\n                    hasLinkedToken = tokenElevationType != TokenElevationTypeDefault;\n                }\n\n                if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed)))\n                {\n                    if (isVirtualizationAllowed)\n                    {\n                        if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled)))\n                        {\n                            tokenVirtualization = isVirtualizationEnabled ? L\"Enabled\" : L\"Disabled\";\n                        }\n                    }\n                    else\n                    {\n                        tokenVirtualization = L\"Not Allowed\";\n                    }\n                }\n\n                if (NT_SUCCESS(PhGetTokenUIAccess(tokenHandle, &isUIAccessEnabled)))\n                {\n                    tokenUIAccess = isUIAccessEnabled ? L\"Enabled\": L\"Disabled\";\n                }\n\n                tokenPageContext->CloseObject(tokenHandle, FALSE, tokenPageContext->Context);\n            }\n\n            if (NT_SUCCESS(tokenPageContext->OpenObject(\n                &tokenHandle,\n                TOKEN_QUERY_SOURCE,\n                tokenPageContext->Context // ProcessId\n                )))\n            {\n                TOKEN_SOURCE tokenSource;\n                PCPH_STRINGREF tokenSourceTypeString;\n\n                if (NT_SUCCESS(PhGetTokenSource(tokenHandle, &tokenSource)))\n                {\n                    PhCopyStringZFromBytes(\n                        tokenSource.SourceName,\n                        TOKEN_SOURCE_LENGTH,\n                        tokenSourceName,\n                        RTL_NUMBER_OF(tokenSourceName),\n                        NULL\n                        );\n\n                    PhPrintPointer(tokenSourceLuid, UlongToPtr(tokenSource.SourceIdentifier.LowPart));\n\n                    if (tokenSourceTypeString = PhGetLuidKnownTypeToString(&tokenSource.SourceIdentifier))\n                    {\n                        wcscat_s(tokenSourceLuid, RTL_NUMBER_OF(tokenSourceLuid), L\" (\");\n                        wcscat_s(tokenSourceLuid, RTL_NUMBER_OF(tokenSourceLuid), PhGetStringRefZ(tokenSourceTypeString));\n                        wcscat_s(tokenSourceLuid, RTL_NUMBER_OF(tokenSourceLuid), L\")\");\n                    }\n                }\n\n                tokenPageContext->CloseObject(tokenHandle, FALSE, tokenPageContext->Context);\n            }\n\n            PhSetDialogItemText(hwndDlg, IDC_USER, PhGetStringOrDefault(tokenUserName, L\"Unknown\"));\n            PhSetDialogItemText(hwndDlg, IDC_USERSID, PhGetStringOrDefault(tokenUserSid, L\"Unknown\"));\n            PhSetDialogItemText(hwndDlg, IDC_OWNER, PhGetStringOrDefault(tokenOwnerName, L\"Unknown\"));\n            PhSetDialogItemText(hwndDlg, IDC_PRIMARYGROUP, PhGetStringOrDefault(tokenPrimaryGroupName, L\"Unknown\"));\n\n            if (tokenSessionId != ULONG_MAX)\n                PhSetDialogItemValue(hwndDlg, IDC_SESSIONID, tokenSessionId, FALSE);\n            else\n                PhSetDialogItemText(hwndDlg, IDC_SESSIONID, L\"Unknown\");\n\n            if (PhGetElevationTypeString(tokenElevation, tokenElevationType, &tokenElevationTypeString))\n                PhSetDialogItemText(hwndDlg, IDC_ELEVATED, PhGetStringRefZ(tokenElevationTypeString));\n            else\n                PhSetDialogItemText(hwndDlg, IDC_ELEVATED, L\"Unknown\");\n\n            PhSetDialogItemText(hwndDlg, IDC_VIRTUALIZATION, tokenVirtualization);\n            PhSetDialogItemText(hwndDlg, IDC_UIACCESS, tokenUIAccess);\n            PhSetDialogItemText(hwndDlg, IDC_SOURCENAME, tokenSourceName);\n            PhSetDialogItemText(hwndDlg, IDC_SOURCELUID, tokenSourceLuid);\n\n            EnableWindow(GetDlgItem(hwndDlg, IDC_LINKEDTOKEN), !!hasLinkedToken);\n\n            if (PhEnableThemeSupport) // TODO: Required for compat (dmex)\n                PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport);  // HACK (GetParent)\n            else\n                PhInitializeWindowTheme(hwndDlg, FALSE);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDC_LINKEDTOKEN:\n                {\n                    NTSTATUS status;\n                    HANDLE tokenHandle;\n\n                    if (NT_SUCCESS(status = tokenPageContext->OpenObject(\n                        &tokenHandle,\n                        TOKEN_QUERY,\n                        tokenPageContext->Context // ProcessId\n                        )))\n                    {\n                        PhShowTokenProperties(\n                            hwndDlg,\n                            PhpOpenLinkedToken,\n                            PhpCloseLinkedToken,\n                            tokenPageContext->ProcessId,\n                            (PVOID)tokenHandle,\n                            L\"Linked Token\"\n                            );\n\n                        tokenPageContext->CloseObject(tokenHandle, FALSE, tokenPageContext->Context);\n                    }\n                    else\n                    {\n                        PhShowStatus(hwndDlg, L\"Unable to open the token\", status, 0);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case PSN_QUERYINITIALFOCUS:\n                {\n                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_LINKEDTOKEN));\n                    return TRUE;\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\ntypedef struct _PHP_TOKEN_ADVANCED_CONTEXT\n{\n    HWND WindowHandle;\n    HWND ListViewHandle;\n    PH_LAYOUT_MANAGER LayoutManager;\n} PHP_TOKEN_ADVANCED_CONTEXT, *PPHP_TOKEN_ADVANCED_CONTEXT;\n\nINT_PTR CALLBACK PhpTokenAdvancedPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n    PPHP_TOKEN_ADVANCED_CONTEXT context;\n\n    tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!tokenPageContext)\n        return FALSE;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocateZero(sizeof(PHP_TOKEN_ADVANCED_CONTEXT));\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HANDLE tokenHandle;\n            LONG listViewGroupIndex = 0;\n            PWSTR tokenType = L\"Unknown\";\n            PWSTR tokenImpersonationLevel = L\"Unknown\";\n            WCHAR tokenLuid[PH_PTR_STR_LEN_1] = { L\"Unknown\" };\n            WCHAR authenticationLuid[PH_PTR_STR_LEN_1] = { L\"Unknown\" };\n            WCHAR tokenModifiedLuid[PH_PTR_STR_LEN_1] = { L\"Unknown\" };\n            WCHAR tokenOriginLogonSession[PH_PTR_STR_LEN_1] = { L\"Unknown\" };\n            PPH_STRING memoryUsed = NULL;\n            PPH_STRING memoryAvailable = NULL;\n            PPH_STRING tokenNamedObjectPathString = NULL;\n            PPH_STRING tokenSecurityDescriptorString = NULL;\n            PPH_STRING tokenTrustLevelSidString;\n            PPH_STRING tokenTrustLevelNameString;\n            PPH_STRING tokenProfilePathString;\n            PPH_STRING tokenProfileRegistryString;\n            PPH_STRING tokenSystemIdForPublisher = NULL;\n            PPH_STRING tokenSystemIdForUser = NULL;\n\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 120, L\"Name\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 280, L\"Value\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n\n            ListView_EnableGroupView(context->ListViewHandle, TRUE);\n            PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L\"General\");\n            PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L\"LUIDs\");\n            PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L\"Memory\");\n            PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L\"Properties\");\n            PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L\"Type\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L\"Impersonation level\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L\"Token LUID\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L\"Authentication LUID\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L\"ModifiedId LUID\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L\"Origin LUID\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L\"Memory used\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L\"Memory available\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L\"Token object path\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L\"Token SDDL\", NULL);\n\n            if (NT_SUCCESS(tokenPageContext->OpenObject(\n                &tokenHandle,\n                TOKEN_QUERY,\n                tokenPageContext->Context // ProcessId\n                )))\n            {\n                TOKEN_STATISTICS statistics;\n                TOKEN_ORIGIN origin;\n\n                if (NT_SUCCESS(PhGetTokenStatistics(tokenHandle, &statistics)))\n                {\n                    PhGetTokenTypeString(statistics.TokenType, &tokenType);\n                    PhGetImpersonationLevelString(statistics.ImpersonationLevel, &tokenImpersonationLevel);\n\n                    PhPrintPointer(tokenLuid, UlongToPtr(statistics.TokenId.LowPart));\n                    PhPrintPointer(authenticationLuid, UlongToPtr(statistics.AuthenticationId.LowPart));\n                    PhPrintPointer(tokenModifiedLuid, UlongToPtr(statistics.ModifiedId.LowPart));\n\n                    memoryUsed = PhFormatSize(statistics.DynamicCharged - statistics.DynamicAvailable, ULONG_MAX); // DynamicAvailable contains the number of bytes free.\n                    memoryAvailable = PhFormatSize(statistics.DynamicCharged, ULONG_MAX); // DynamicCharged contains the number of bytes allocated.\n                }\n\n                if (NT_SUCCESS(PhGetTokenOrigin(tokenHandle, &origin)))\n                {\n                    PhPrintPointer(tokenOriginLogonSession, UlongToPtr(origin.OriginatingLogonSession.LowPart));\n                }\n\n                PhGetTokenNamedObjectPath(tokenHandle, NULL, &tokenNamedObjectPathString);\n                PhGetObjectSecurityDescriptorAsString(tokenHandle, &tokenSecurityDescriptorString);\n\n                if (NT_SUCCESS(PhGetTokenProcessTrustLevelRID(\n                    tokenHandle,\n                    NULL,\n                    NULL,\n                    &tokenTrustLevelNameString,\n                    &tokenTrustLevelSidString\n                    )))\n                {\n                    LONG trustLevelGroupIndex;\n                    LONG trustLevelSidIndex;\n                    LONG trustLevelNameIndex;\n\n                    trustLevelGroupIndex = PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L\"TrustLevel\");\n                    trustLevelSidIndex = PhAddListViewGroupItem(context->ListViewHandle, trustLevelGroupIndex, MAXINT, L\"TrustLevel Sid\", NULL);\n                    trustLevelNameIndex = PhAddListViewGroupItem(context->ListViewHandle, trustLevelGroupIndex, MAXINT, L\"TrustLevel Name\", NULL);\n                    PhSetListViewSubItem(context->ListViewHandle, trustLevelSidIndex, 1, PhGetStringOrDefault(tokenTrustLevelSidString, L\"N/A\"));\n                    PhSetListViewSubItem(context->ListViewHandle, trustLevelNameIndex, 1, PhGetStringOrDefault(tokenTrustLevelNameString, L\"N/A\"));\n\n                    PhClearReference(&tokenTrustLevelNameString);\n                    PhClearReference(&tokenTrustLevelSidString);\n                }\n\n                //PTOKEN_GROUPS tokenLogonGroups;\n                //if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenLogonSid, &tokenLogonGroups)))\n                //{\n                //    PPH_STRING tokenLogonName = PhGetSidFullName(tokenLogonGroups->Groups[0].Sid, TRUE, NULL);\n                //    PPH_STRING tokenLogonSid = PhSidToStringSid(tokenLogonGroups->Groups[0].Sid);\n                //    LONG tokenLogonGroupIndex = PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L\"Logon\");\n                //    LONG tokenLogonNameIndex = PhAddListViewGroupItem(context->ListViewHandle, tokenLogonGroupIndex, MAXINT, L\"Token logon SID\", NULL);\n                //    LONG tokenLogonSidIndex = PhAddListViewGroupItem(context->ListViewHandle, tokenLogonGroupIndex, MAXINT, L\"Token logon Name\", NULL);\n                //    PhSetListViewSubItem(context->ListViewHandle, tokenLogonNameIndex, 1, PhGetStringOrDefault(tokenLogonName, L\"Unknown\"));\n                //    PhSetListViewSubItem(context->ListViewHandle, tokenLogonSidIndex, 1, PhGetStringOrDefault(tokenLogonSid, L\"Unknown\"));\n                //    PhFree(tokenLogonGroups);\n                //}\n\n                if (tokenProfilePathString = PhpGetTokenFolderPath(tokenHandle))\n                {\n                    LONG profileGroupIndex;\n                    LONG profileFolderIndex;\n                    LONG profileRegistryIndex;\n\n                    profileGroupIndex = PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L\"Profile\");\n                    profileFolderIndex = PhAddListViewGroupItem(context->ListViewHandle, profileGroupIndex, MAXINT, L\"Folder path\", NULL);\n                    profileRegistryIndex = PhAddListViewGroupItem(context->ListViewHandle, profileGroupIndex, MAXINT, L\"Registry path\", NULL);\n\n                    PhSetListViewSubItem(context->ListViewHandle, profileFolderIndex, 1, PhGetStringOrDefault(tokenProfilePathString, L\"N/A\"));\n\n                    if (tokenProfileRegistryString = PhpGetTokenRegistryPath(tokenHandle))\n                    {\n                        PhSetListViewSubItem(context->ListViewHandle, profileRegistryIndex, 1, PhGetStringOrDefault(tokenProfileRegistryString, L\"N/A\"));\n                        PhDereferenceObject(tokenProfileRegistryString);\n                    }\n\n                    PhDereferenceObject(tokenProfilePathString);\n                }\n\n                tokenPageContext->CloseObject(tokenHandle, FALSE, tokenPageContext->Context);\n            }\n\n            if (SUCCEEDED(PhGetProcessSystemIdentification(\n                tokenPageContext->Context, // ProcessId,\n                &tokenSystemIdForPublisher,\n                &tokenSystemIdForUser\n                )))\n            {\n                LONG systemIdGroupIndex;\n                LONG systemIdPublisherIndex;\n                LONG systemIdUserIndex;\n\n                systemIdGroupIndex = PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L\"System ID\");\n                systemIdPublisherIndex = PhAddListViewGroupItem(context->ListViewHandle, systemIdGroupIndex, MAXINT, L\"HWID (Publisher)\", NULL);\n                systemIdUserIndex = PhAddListViewGroupItem(context->ListViewHandle, systemIdGroupIndex, MAXINT, L\"HWID (User)\", NULL);\n\n                PhSetListViewSubItem(context->ListViewHandle, systemIdPublisherIndex, 1, PhGetStringOrDefault(tokenSystemIdForPublisher, L\"N/A\"));\n                PhSetListViewSubItem(context->ListViewHandle, systemIdUserIndex, 1, PhGetStringOrDefault(tokenSystemIdForUser, L\"N/A\"));\n\n                PhClearReference(&tokenSystemIdForPublisher);\n                PhClearReference(&tokenSystemIdForUser);\n            }\n\n            PhSetListViewSubItem(context->ListViewHandle, 0, 1, tokenType);\n            PhSetListViewSubItem(context->ListViewHandle, 1, 1, tokenImpersonationLevel);\n            PhSetListViewSubItem(context->ListViewHandle, 2, 1, tokenLuid);\n            PhSetListViewSubItem(context->ListViewHandle, 3, 1, authenticationLuid);\n            PhSetListViewSubItem(context->ListViewHandle, 4, 1, tokenModifiedLuid);\n            PhSetListViewSubItem(context->ListViewHandle, 5, 1, tokenOriginLogonSession);\n            PhSetListViewSubItem(context->ListViewHandle, 6, 1, PhGetStringOrDefault(memoryUsed, L\"Unknown\"));\n            PhSetListViewSubItem(context->ListViewHandle, 7, 1, PhGetStringOrDefault(memoryAvailable, L\"Unknown\"));\n            PhSetListViewSubItem(context->ListViewHandle, 8, 1, PhGetStringOrDefault(tokenNamedObjectPathString, L\"Unknown\"));\n            PhSetListViewSubItem(context->ListViewHandle, 9, 1, PhGetStringOrDefault(tokenSecurityDescriptorString, L\"Unknown\"));\n\n            PhClearReference(&memoryUsed);\n            PhClearReference(&memoryAvailable);\n            PhClearReference(&tokenNamedObjectPathString);\n            PhClearReference(&tokenSecurityDescriptorString);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n            PhFree(context);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n\n            ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID* listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(context->ListViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN NTAPI PhpAttributeTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_TOKEN_ATTRIBUTE_TREE_CONTEXT context = Context;\n    PPH_TOKEN_ATTRIBUTE_NODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_TOKEN_ATTRIBUTE_NODE)getChildren->Node;\n\n            if (!node)\n            {\n                getChildren->Children = (PPH_TREENEW_NODE *)context->RootList->Items;\n                getChildren->NumberOfChildren = context->RootList->Count;\n            }\n            else\n            {\n                getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;\n                getChildren->NumberOfChildren = node->Children->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n            node = (PPH_TOKEN_ATTRIBUTE_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = node->Children->Count == 0;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            node = (PPH_TOKEN_ATTRIBUTE_NODE)getCellText->Node;\n\n            if (getCellText->Id == 0)\n                getCellText->Text = PhGetStringRef(node->Text);\n            else\n                return FALSE;\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(WindowHandle, 0);\n                    PhSetClipboardString(WindowHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1;\n\n            SendMessage(\n                context->WindowHandle,\n                WM_CONTEXTMENU,\n                0,\n                (LPARAM)contextMenuEvent\n                );\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nPPH_TOKEN_ATTRIBUTE_NODE PhpAddAttributeNode(\n    _In_ PPH_TOKEN_ATTRIBUTE_TREE_CONTEXT Context,\n    _In_opt_ PPH_TOKEN_ATTRIBUTE_NODE Parent,\n    _In_opt_ _Assume_refs_(1) PPH_STRING Text\n    )\n{\n    PPH_TOKEN_ATTRIBUTE_NODE node;\n\n    node = PhAllocate(sizeof(PH_TOKEN_ATTRIBUTE_NODE));\n    memset(node, 0, sizeof(PH_TOKEN_ATTRIBUTE_NODE));\n    PhInitializeTreeNewNode(&node->Node);\n\n    node->Children = PhCreateList(2);\n\n    PhAddItemList(Context->NodeList, node);\n\n    if (Parent)\n        PhAddItemList(Parent->Children, node);\n    else\n        PhAddItemList(Context->RootList, node);\n\n    PhMoveReference(&node->Text, Text);\n\n    return node;\n}\n\nVOID PhpDestroyAttributeNode(\n    _In_ PPH_TOKEN_ATTRIBUTE_NODE Node\n    )\n{\n    PhDereferenceObject(Node->Children);\n    PhClearReference(&Node->Text);\n    PhClearReference(&Node->Value);\n    PhFree(Node);\n}\n\nVOID PhpRemoveAttributeNode(\n    _In_ PPH_TOKEN_ATTRIBUTE_TREE_CONTEXT Context,\n    _In_ PPH_TOKEN_ATTRIBUTE_NODE Node\n    )\n{\n    ULONG index;\n\n    if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX)\n        PhRemoveItemList(Context->NodeList, index);\n    if ((index = PhFindItemList(Context->RootList, Node)) != ULONG_MAX)\n        PhRemoveItemList(Context->RootList, index);\n\n    PhpDestroyAttributeNode(Node);\n}\n\n_Success_(return)\nBOOLEAN PhpGetSelectedAttributeTreeNodes(\n    _Inout_ PPH_TOKEN_ATTRIBUTE_TREE_CONTEXT Context,\n    _Out_ PPH_TOKEN_ATTRIBUTE_NODE **Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = (PPH_TOKEN_ATTRIBUTE_NODE)Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n        {\n            PhAddItemList(list, node);\n        }\n    }\n\n    if (list->Count)\n    {\n        *Nodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\nVOID PhpInitializeAttributeTreeContext(\n    _Out_ PPH_TOKEN_ATTRIBUTE_TREE_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HWND TreeNewHandle\n    )\n{\n    Context->WindowHandle = WindowHandle;\n    Context->NodeList = PhCreateList(10);\n    Context->RootList = PhCreateList(10);\n\n    PhSetControlTheme(TreeNewHandle, L\"explorer\");\n    TreeNew_SetRedraw(TreeNewHandle, FALSE);\n    TreeNew_SetCallback(TreeNewHandle, PhpAttributeTreeNewCallback, Context);\n    //TreeNew_GetViewParts(TreeNewHandle, &parts); // column width = (parts.ClientRect.right - parts.VScrollWidth) // TODO: VScrollWidth not set during INITDIALOG. (dmex)\n    PhAddTreeNewColumnEx2(TreeNewHandle, 0, TRUE, L\"Attributes\", 200, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_NODPISCALEONADD);\n    TreeNew_SetRedraw(TreeNewHandle, TRUE);\n}\n\nVOID PhpDeleteAttributeTreeContext(\n    _Inout_ PPH_TOKEN_ATTRIBUTE_TREE_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Context->NodeList->Count; i++)\n        PhpDestroyAttributeNode(Context->NodeList->Items[i]);\n\n    PhDereferenceObject(Context->NodeList);\n    PhDereferenceObject(Context->RootList);\n}\n\n//static COLORREF NTAPI PhpTokenCapabilitiesColorFunction(\n//    _In_ LONG Index,\n//    _In_ PVOID Param,\n//    _In_opt_ PVOID Context\n//    )\n//{\n//    PSID_AND_ATTRIBUTES sidAndAttributes = Param;\n//\n//    return PhGetGroupAttributesColor(sidAndAttributes->Attributes);\n//}\n\nBOOLEAN PhpAddTokenCapabilities(\n    _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,\n    _In_ HWND tnHandle\n    )\n{\n    HANDLE tokenHandle;\n    ULONG i;\n\n    if (!NT_SUCCESS(TokenPageContext->OpenObject(\n        &tokenHandle,\n        TOKEN_QUERY,\n        TokenPageContext->Context\n        )))\n        return FALSE;\n\n    if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenCapabilities, &TokenPageContext->Capabilities)))\n    {\n        for (i = 0; i < TokenPageContext->Capabilities->GroupCount; i++)\n        {\n            PPH_TOKEN_ATTRIBUTE_NODE node;\n            PPH_STRING name;\n            ULONG subAuthoritiesCount;\n            ULONG subAuthority;\n\n            name = PhSidToStringSid(TokenPageContext->Capabilities->Groups[i].Sid);\n            node = PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, NULL, name);\n\n            if (name = PhGetSidFullName(TokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL))\n            {\n                PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L\"FullName: %s\", PhGetString(name)));\n                PhDereferenceObject(name);\n            }\n\n            if (name = PhGetCapabilitySidName(TokenPageContext->Capabilities->Groups[i].Sid))\n            {\n                PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L\"Capability: %s\", PhGetString(name)));\n                PhDereferenceObject(name);\n            }\n\n            subAuthoritiesCount = *PhSubAuthorityCountSid(TokenPageContext->Capabilities->Groups[i].Sid);\n            subAuthority = *PhSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 0);\n\n            if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_APP_PACKAGE_AUTHORITY))\n            {\n                if (subAuthority == SECURITY_CAPABILITY_BASE_RID)\n                {\n                    if (subAuthoritiesCount == SECURITY_APP_PACKAGE_RID_COUNT)\n                    {\n                        PH_TOKEN_APPCONTAINER tokenAppContainer;\n\n                        //if (*PhSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 1) == SECURITY_CAPABILITY_APP_RID)\n                        //    continue;\n\n                        if (NT_SUCCESS(PhGetTokenAppContainerSid(tokenHandle, &tokenAppContainer)))\n                        {\n                            if (PhIsPackageCapabilitySid(tokenAppContainer.AppContainer.Sid, TokenPageContext->Capabilities->Groups[i].Sid))\n                            {\n                                static CONST PH_STRINGREF packageNameStringRef = PH_STRINGREF_INIT(L\"Package: \");\n\n                                if (NT_SUCCESS(PhGetTokenPackageFullName(tokenHandle, &name)))\n                                {\n                                    PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhConcatStringRef2(&packageNameStringRef, &name->sr));\n                                    PhDereferenceObject(name);\n                                }\n                                else\n                                {\n                                    PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhCreateString2(&packageNameStringRef));\n                                }\n                            }\n                        }\n                    }\n                    else if (subAuthoritiesCount == SECURITY_CAPABILITY_RID_COUNT)\n                    {\n                        PPH_STRING capabilityName;\n                        union\n                        {\n                            GUID Guid;\n                            struct\n                            {\n                                ULONG Data1;\n                                ULONG Data2;\n                                ULONG Data3;\n                                ULONG Data4;\n                            };\n                        } capabilityGuid;\n\n                        capabilityGuid.Data1 = *PhSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 1);\n                        capabilityGuid.Data2 = *PhSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 2);\n                        capabilityGuid.Data3 = *PhSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 3);\n                        capabilityGuid.Data4 = *PhSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 4);\n\n                        if (name = PhFormatGuid(&capabilityGuid.Guid))\n                        {\n                            static CONST PH_STRINGREF guidNameStringRef = PH_STRINGREF_INIT(L\"Guid: \");\n                            static CONST PH_STRINGREF capabilityNameStringRef = PH_STRINGREF_INIT(L\"Capability: \");\n\n                            PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhConcatStringRef2(&guidNameStringRef, &name->sr));\n\n                            if (capabilityName = PhGetCapabilityGuidName(name))\n                            {\n                                PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhConcatStringRef2(&capabilityNameStringRef, &capabilityName->sr));\n                                PhDereferenceObject(capabilityName);\n                            }\n\n                            PhDereferenceObject(name);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    TokenPageContext->CloseObject(tokenHandle, FALSE, TokenPageContext->Context);\n\n    return TRUE;\n}\n\nINT_PTR CALLBACK PhpTokenCapabilitiesPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n    HWND tnHandle;\n\n    tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!tokenPageContext)\n        return FALSE;\n\n    tnHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            tokenPageContext->CapsTreeContext.WindowHandle = hwndDlg;\n            tokenPageContext->CapsTreeContext.NodeList = PhCreateList(10);\n            tokenPageContext->CapsTreeContext.RootList = PhCreateList(10);\n\n            PhSetControlTheme(tnHandle, L\"explorer\");\n            TreeNew_SetRedraw(tnHandle, FALSE);\n            TreeNew_SetEmptyText(tnHandle, &PhpEmptyTokenCapabilitiesText, 0);\n            TreeNew_SetCallback(tnHandle, PhpAttributeTreeNewCallback, &tokenPageContext->CapsTreeContext);\n            PhAddTreeNewColumnEx2(tnHandle, 0, TRUE, L\"Capabilities\", 200, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_NODPISCALEONADD);\n            PhpAddTokenCapabilities(tokenPageContext, tnHandle);\n            TreeNew_NodesStructured(tnHandle);\n            TreeNew_SetRedraw(tnHandle, TRUE);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhpDeleteAttributeTreeContext(&tokenPageContext->CapsTreeContext);\n\n            if (tokenPageContext->Capabilities)\n            {\n                PhFree(tokenPageContext->Capabilities);\n                tokenPageContext->Capabilities = NULL;\n            }\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            TreeNew_AutoSizeColumn(tnHandle, 0, TN_AUTOSIZE_REMAINING_SPACE);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM selectedItem;\n            PPH_TOKEN_ATTRIBUTE_NODE *attributeObjectNodes = NULL;\n            ULONG numberOfAttributeObjectNodes = 0;\n\n            if (!PhpGetSelectedAttributeTreeNodes(&tokenPageContext->CapsTreeContext, &attributeObjectNodes, &numberOfAttributeObjectNodes))\n                break;\n\n            if (numberOfAttributeObjectNodes != 0)\n            {\n                menu = PhCreateEMenu();\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"Copy\", NULL, NULL), ULONG_MAX);\n                PhInsertCopyCellEMenuItem(menu, IDC_COPY, tnHandle, contextMenuEvent->Column);\n\n                selectedItem = PhShowEMenu(\n                    menu,\n                    hwndDlg,\n                    PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                    PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                    contextMenuEvent->Location.x,\n                    contextMenuEvent->Location.y\n                    );\n\n                if (selectedItem && selectedItem->Id != ULONG_MAX)\n                {\n                    if (!PhHandleCopyCellEMenuItem(selectedItem))\n                    {\n                        switch (selectedItem->Id)\n                        {\n                        case IDC_COPY:\n                            {\n                                PPH_STRING text;\n\n                                text = PhGetTreeNewText(tnHandle, 0);\n                                PhSetClipboardString(tnHandle, &text->sr);\n                                PhDereferenceObject(text);\n                            }\n                            break;\n                        }\n                    }\n                }\n\n                PhDestroyEMenu(menu);\n            }\n\n            PhFree(attributeObjectNodes);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nPWSTR PhGetSecurityAttributeTypeString(\n    _In_ USHORT Type\n    )\n{\n    // These types are shared between CLAIM_* and TOKEN_* security attributes.\n\n    switch (Type)\n    {\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_INVALID:\n        return L\"Invalid\";\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64:\n        return L\"Int64\";\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64:\n        return L\"UInt64\";\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING:\n        return L\"String\";\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN:\n        return L\"FQBN\";\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_SID:\n        return L\"SID\";\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:\n        return L\"Boolean\";\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:\n        return L\"Octet string\";\n    default:\n        return L\"(Unknown)\";\n    }\n}\n\nPPH_STRING PhGetSecurityAttributeFlagsString(\n    _In_ ULONG Flags\n    )\n{\n    PH_STRING_BUILDER sb;\n\n    // These flags are shared between CLAIM_* and TOKEN_* security attributes.\n\n    PhInitializeStringBuilder(&sb, 100);\n\n    if (Flags & TOKEN_SECURITY_ATTRIBUTE_MANDATORY)\n        PhAppendStringBuilder2(&sb, L\"Mandatory, \");\n    if (Flags & TOKEN_SECURITY_ATTRIBUTE_DISABLED)\n        PhAppendStringBuilder2(&sb, L\"Disabled, \");\n    if (Flags & TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT)\n        PhAppendStringBuilder2(&sb, L\"Default disabled, \");\n    if (Flags & TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY)\n        PhAppendStringBuilder2(&sb, L\"Use for deny only, \");\n    if (Flags & TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE)\n        PhAppendStringBuilder2(&sb, L\"Case-sensitive, \");\n    if (Flags & TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE)\n        PhAppendStringBuilder2(&sb, L\"Non-inheritable, \");\n    if (Flags & TOKEN_SECURITY_ATTRIBUTE_COMPARE_IGNORE)\n        PhAppendStringBuilder2(&sb, L\"Compare-ignore, \");\n\n    if (sb.String->Length != 0)\n        PhRemoveEndStringBuilder(&sb, 2);\n    else\n        PhAppendStringBuilder2(&sb, L\"(None)\");\n\n    return PhFinalStringBuilderString(&sb);\n}\n\nPPH_STRING PhFormatClaimSecurityAttributeValue(\n    _In_ PCLAIM_SECURITY_ATTRIBUTE_V1 Attribute,\n    _In_ ULONG ValueIndex\n    )\n{\n    PH_FORMAT format[10];\n\n    switch (Attribute->ValueType)\n    {\n    case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:\n        PhInitFormatI64D(&format[0], Attribute->Values.pInt64[ValueIndex]);\n        return PhFormat(format, 1, 0);\n    case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:\n        PhInitFormatI64U(&format[0], Attribute->Values.pUint64[ValueIndex]);\n        return PhFormat(format, 1, 0);\n    case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:\n        return PhCreateString(Attribute->Values.ppString[ValueIndex]);\n    case CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN:\n        {\n            PhInitFormatS(&format[0], L\"Version \");\n            PhInitFormatU(&format[1], HIWORD(Attribute->Values.pFqbn[ValueIndex].Version >> 32));\n            PhInitFormatC(&format[2], L'.');\n            PhInitFormatU(&format[3], LOWORD(Attribute->Values.pFqbn[ValueIndex].Version >> 32));\n            PhInitFormatC(&format[4], L'.');\n            PhInitFormatU(&format[5], HIWORD(Attribute->Values.pFqbn[ValueIndex].Version));\n            PhInitFormatC(&format[6], L'.');\n            PhInitFormatU(&format[7], LOWORD(Attribute->Values.pFqbn[ValueIndex].Version));\n            PhInitFormatS(&format[8], L\": \");\n            PhInitFormatS(&format[9], Attribute->Values.pFqbn[ValueIndex].Name);\n            return PhFormat(format, 10, 40);\n        }\n    case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:\n        {\n            if (PhValidSid(Attribute->Values.pOctetString[ValueIndex].pValue))\n            {\n                PPH_STRING name;\n\n                name = PhGetSidFullName(Attribute->Values.pOctetString[ValueIndex].pValue, TRUE, NULL);\n\n                if (name)\n                    return name;\n\n                name = PhSidToStringSid(Attribute->Values.pOctetString[ValueIndex].pValue);\n\n                if (name)\n                    return name;\n            }\n        }\n        return PhCreateString(L\"(Invalid SID)\");\n    case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:\n        return PhCreateString(Attribute->Values.pInt64[ValueIndex] != 0 ? L\"True\" : L\"False\");\n    case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:\n        return PhCreateString(L\"(Octet string)\");\n    default:\n        return PhCreateString(L\"(Unknown)\");\n    }\n}\n\nPPH_STRING PhFormatTokenSecurityAttributeValue(\n    _In_ PPH_STRINGREF Name,\n    _In_ PTOKEN_SECURITY_ATTRIBUTE_V1 Attribute,\n    _In_ ULONG ValueIndex\n    )\n{\n    static CONST PH_STRINGREF winPkg = PH_STRINGREF_INIT(L\"WIN://PKG\");\n    static CONST PH_STRINGREF winBgkd = PH_STRINGREF_INIT(L\"WIN://BGKD\");\n    static CONST PH_STRINGREF appidSHA1 = PH_STRINGREF_INIT(L\"APPID://SHA1HASH\");\n    static CONST PH_STRINGREF appidSHA256 = PH_STRINGREF_INIT(L\"APPID://SHA256HASH\");\n    static CONST PH_STRINGREF appidSHA256Flat = PH_STRINGREF_INIT(L\"APPID://SHA256FLATHASH\");\n    static CONST PH_STRINGREF originClaim = PH_STRINGREF_INIT(L\"SMARTLOCKER://SMARTSCREENORIGINCLAIM\");\n    static CONST PH_STRINGREF originClaimNI = PH_STRINGREF_INIT(L\"SMARTLOCKER://SMARTSCREENORIGINCLAIMNOTINHERITED\");\n    PH_FORMAT format[10];\n    ULONG count = 0;\n\n    // Special cases for known attributes\n\n    // WIN://PKG\n    if (ValueIndex == 0 &&\n        Attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64 &&\n        PhEqualStringRef(Name, &winPkg, TRUE))\n    {\n#define PH_ACTIVIATION_TOKEN_FLAG(x, n) { TEXT(#x), x, FALSE, FALSE, n }\n\n        static const PH_ACCESS_ENTRY activationTokenFlag[] =\n        {\n            PH_ACTIVIATION_TOKEN_FLAG(PSM_ACTIVATION_TOKEN_PACKAGED_APPLICATION, L\"AppX\"),\n            PH_ACTIVIATION_TOKEN_FLAG(PSM_ACTIVATION_TOKEN_SHARED_ENTITY, L\"Shared token\"),\n            PH_ACTIVIATION_TOKEN_FLAG(PSM_ACTIVATION_TOKEN_FULL_TRUST, L\"Trusted\"),\n            PH_ACTIVIATION_TOKEN_FLAG(PSM_ACTIVATION_TOKEN_NATIVE_SERVICE, L\"Service\"),\n            PH_ACTIVIATION_TOKEN_FLAG(PSM_ACTIVATION_TOKEN_MULTIPLE_INSTANCES_ALLOWED, L\"Multiple instances allowed\"),\n            PH_ACTIVIATION_TOKEN_FLAG(PSM_ACTIVATION_TOKEN_BREAKAWAY_INHIBITED, L\"Breakaway inhibited\"),\n            PH_ACTIVIATION_TOKEN_FLAG(PSM_ACTIVATION_TOKEN_RUNTIME_BROKER, L\"Runtime broker\"),\n            PH_ACTIVIATION_TOKEN_FLAG(PSM_ACTIVATION_TOKEN_UNIVERSAL_CONSOLE, L\"Universal console\"),\n            PH_ACTIVIATION_TOKEN_FLAG(PSM_ACTIVATION_TOKEN_WIN32ALACARTE_PROCESS, L\"Win32 process\"),\n\n        };\n\n        ULONG upper = (ULONG)(Attribute->Values.Uint64[0] >> 32);\n        ULONG lower = (ULONG)Attribute->Values.Uint64[0];\n        PPH_STRING string;\n\n        switch (upper)\n        {\n        case PackageOrigin_Unknown:\n            PhInitFormatS(&format[count++], L\"Unknown\");\n            break;\n        case PackageOrigin_Unsigned:\n            PhInitFormatS(&format[count++], L\"Unsigned\");\n            break;\n        case PackageOrigin_Inbox:\n            PhInitFormatS(&format[count++], L\"Inbox\");\n            break;\n        case PackageOrigin_Store:\n            PhInitFormatS(&format[count++], L\"Store\");\n            break;\n        case PackageOrigin_DeveloperUnsigned:\n            PhInitFormatS(&format[count++], L\"Developer unsigned\");\n            break;\n        case PackageOrigin_DeveloperSigned:\n            PhInitFormatS(&format[count++], L\"Developer signed\");\n            break;\n        case PackageOrigin_LineOfBusiness:\n            PhInitFormatS(&format[count++], L\"Line of business\");\n            break;\n        default:\n            PhInitFormatS(&format[count++], L\"Undefined\");\n            break;\n        }\n\n        string = PhGetAccessString(\n            lower,\n            (PPH_ACCESS_ENTRY)activationTokenFlag,\n            RTL_NUMBER_OF(activationTokenFlag)\n            );\n\n        if (string->Length)\n        {\n            PhInitFormatS(&format[count++], L\" : \");\n            PhInitFormatSR(&format[count++], string->sr);\n        }\n\n        PhInitFormatS(&format[count++], L\" (0x\");\n        PhInitFormatI64X(&format[count++], Attribute->Values.Uint64[0]);\n        PhInitFormatS(&format[count++], L\")\");\n\n        PhMoveReference(&string, PhFormat(format, count, 0));\n\n        return string;\n    }\n\n    // WIN://BGKD\n    if (ValueIndex == 0 &&\n        Attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64 &&\n        PhEqualStringRef(Name, &winBgkd, TRUE))\n    {\n        switch (Attribute->Values.Uint64[0])\n        {\n        case PsmActNotBackground:\n            PhInitFormatS(&format[0], L\"Not background\");\n            break;\n        case PsmActMixedHost:\n            PhInitFormatS(&format[0], L\"Mixed host\");\n            break;\n        case PsmActPureHost:\n            PhInitFormatS(&format[0], L\"Pure host\");\n            break;\n        case PsmActSystemHost:\n            PhInitFormatS(&format[0], L\"System host\");\n            break;\n        case PsmActInvalidType:\n            PhInitFormatS(&format[0], L\"Invalid\");\n            break;\n        default:\n            PhInitFormatS(&format[0], L\"Unknown\");\n            break;\n        }\n\n        PhInitFormatS(&format[1], L\" (\");\n        PhInitFormatI64D(&format[2], Attribute->Values.Uint64[0]);\n        PhInitFormatC(&format[3], L')');\n\n        return PhFormat(format, 4, 10);\n    }\n\n    // APPID://SHA1HASH, APPID://SHA256HASH, APPID://SHA256FLATHASH\n    if (ValueIndex == 0 &&\n        Attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING &&\n        ((Attribute->Values.OctetString[0].ValueLength == 20 && PhEqualStringRef(Name, &appidSHA1, TRUE)) ||\n        (Attribute->Values.OctetString[0].ValueLength == 32 && PhEqualStringRef(Name, &appidSHA256, TRUE)) ||\n        (Attribute->Values.OctetString[0].ValueLength == 32 && PhEqualStringRef(Name, &appidSHA256Flat, TRUE))))\n    {\n        return PhBufferToHexString(\n            Attribute->Values.OctetString[0].Value,\n            Attribute->Values.OctetString[0].ValueLength\n            );\n    }\n\n    // SMARTLOCKER://SMARTSCREENORIGINCLAIM, SMARTLOCKER://SMARTSCREENORIGINCLAIMNOTINHERITED\n    if (ValueIndex == 0 &&\n        Attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING &&\n        Attribute->Values.OctetString[0].ValueLength == sizeof(SE_SAFE_OPEN_PROMPT_RESULTS) &&\n        (PhEqualStringRef(Name, &originClaim, TRUE) || PhEqualStringRef(Name, &originClaimNI, TRUE)))\n    {\n        PSE_SAFE_OPEN_PROMPT_RESULTS claimValue = Attribute->Values.OctetString[0].Value;\n        PPH_STRING pathString;\n        PPH_STRING resultsString;\n        PPH_STRING string;\n\n#define PH_ORIGIN_CLAIM_RESULT(x, n) { TEXT(#x), x, FALSE, FALSE, n }\n\n        static const PH_ACCESS_ENTRY originClaimResults[] =\n        {\n            PH_ORIGIN_CLAIM_RESULT(SeSafeOpenExperienceCalled, L\"Called\"),\n            PH_ORIGIN_CLAIM_RESULT(SeSafeOpenExperienceAppRepCalled, L\"App reputation called\"),\n            PH_ORIGIN_CLAIM_RESULT(SeSafeOpenExperiencePromptDisplayed, L\"Prompt displayed\"),\n            PH_ORIGIN_CLAIM_RESULT(SeSafeOpenExperienceUAC, L\"UAC\"),\n            PH_ORIGIN_CLAIM_RESULT(SeSafeOpenExperienceUninstaller, L\"Uninstaller\"),\n            PH_ORIGIN_CLAIM_RESULT(SeSafeOpenExperienceIgnoreUnknownOrBad, L\"Ignore unknown or bad\"),\n            PH_ORIGIN_CLAIM_RESULT(SeSafeOpenExperienceDefenderTrustedInstaller, L\"Defender trusted installer\"),\n            PH_ORIGIN_CLAIM_RESULT(SeSafeOpenExperienceMOTWPresent, L\"MOTW present\"),\n            PH_ORIGIN_CLAIM_RESULT(SeSafeOpenExperienceElevatedNoPropagation, L\"Elevated no propagation\"),\n        };\n\n        resultsString = PhGetAccessString(\n            claimValue->Results,\n            (PPH_ACCESS_ENTRY)originClaimResults,\n            RTL_NUMBER_OF(originClaimResults)\n            );\n\n        pathString = PhCreateStringZ2(claimValue->Path, sizeof(claimValue->Path));\n\n        PhInitFormatSR(&format[0], resultsString->sr);\n        PhInitFormatS(&format[1], L\" (0x\");\n        PhInitFormatX(&format[2], claimValue->Results);\n        PhInitFormatS(&format[3], L\") : \\\"\");\n        PhInitFormatSR(&format[4], pathString->sr);\n        PhInitFormatC(&format[5], L'\"');\n\n        string = PhFormat(format, 6, 10);\n        PhDereferenceObject(pathString);\n        PhDereferenceObject(resultsString);\n        return string;\n    }\n\n    // Default handling\n    switch (Attribute->ValueType)\n    {\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64:\n        PhInitFormatI64D(&format[0], Attribute->Values.Int64[ValueIndex]);\n        PhInitFormatS(&format[1], L\" (0x\");\n        PhInitFormatI64X(&format[2], Attribute->Values.Int64[ValueIndex]);\n        PhInitFormatS(&format[3], L\")\");\n        return PhFormat(format, 4, 0);\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64:\n        PhInitFormatI64U(&format[0], Attribute->Values.Uint64[ValueIndex]);\n        PhInitFormatS(&format[1], L\" (0x\");\n        PhInitFormatI64X(&format[2], Attribute->Values.Uint64[ValueIndex]);\n        PhInitFormatS(&format[3], L\")\");\n        return PhFormat(format, 4, 0);\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING:\n        return PhCreateStringFromUnicodeString(&Attribute->Values.String[ValueIndex]);\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN:\n        {\n            PhInitFormatS(&format[0], L\"Version \");\n            PhInitFormatU(&format[1], HIWORD(Attribute->Values.Fqbn[ValueIndex].Version >> 32));\n            PhInitFormatC(&format[2], L'.');\n            PhInitFormatU(&format[3], LOWORD(Attribute->Values.Fqbn[ValueIndex].Version >> 32));\n            PhInitFormatC(&format[4], L'.');\n            PhInitFormatU(&format[5], HIWORD(Attribute->Values.Fqbn[ValueIndex].Version));\n            PhInitFormatC(&format[6], L'.');\n            PhInitFormatU(&format[7], LOWORD(Attribute->Values.Fqbn[ValueIndex].Version));\n            PhInitFormatS(&format[8], L\": \");\n            PhInitFormatUCS(&format[9], &Attribute->Values.Fqbn[ValueIndex].Name);\n            return PhFormat(format, 10, 40);\n        }\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_SID:\n        {\n            if (PhValidSid(Attribute->Values.OctetString[ValueIndex].Value))\n            {\n                PPH_STRING name;\n\n                name = PhGetSidFullName(Attribute->Values.OctetString[ValueIndex].Value, TRUE, NULL);\n\n                if (name)\n                    return name;\n\n                name = PhSidToStringSid(Attribute->Values.OctetString[ValueIndex].Value);\n\n                if (name)\n                    return name;\n            }\n        }\n        return PhCreateString(L\"(Invalid SID)\");\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:\n        return PhCreateString(Attribute->Values.Int64[ValueIndex] != 0 ? L\"True\" : L\"False\");\n    case TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:\n        PhInitFormatS(&format[0], L\"(Octet string of \");\n        PhInitFormatD(&format[1], Attribute->Values.OctetString[ValueIndex].ValueLength);\n        PhInitFormatS(&format[2], L\" bytes)\");\n        return PhFormat(format, 3, 10);\n    default:\n        return PhCreateString(L\"(Unknown)\");\n    }\n}\n\nBOOLEAN PhpAddTokenClaimAttributes(\n    _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,\n    _In_ HWND tnHandle,\n    _In_ BOOLEAN DeviceClaims,\n    _In_ PPH_TOKEN_ATTRIBUTE_NODE Parent\n    )\n{\n    HANDLE tokenHandle;\n    PCLAIM_SECURITY_ATTRIBUTES_INFORMATION info;\n    ULONG i;\n    ULONG j;\n\n    if (!NT_SUCCESS(TokenPageContext->OpenObject(\n        &tokenHandle,\n        TOKEN_QUERY,\n        TokenPageContext->Context // ProcessId\n        )))\n        return FALSE;\n\n    if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, DeviceClaims ? TokenDeviceClaimAttributes : TokenUserClaimAttributes, &info)))\n    {\n        for (i = 0; i < info->AttributeCount; i++)\n        {\n            PCLAIM_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i];\n            PPH_TOKEN_ATTRIBUTE_NODE node;\n            PPH_STRING temp;\n\n            // Attribute\n            node = PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, Parent, PhCreateString(attribute->Name));\n            // Type\n            PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node,\n                PhFormatString(L\"Type: %s\", PhGetSecurityAttributeTypeString(attribute->ValueType)));\n            // Flags\n            temp = PhGetSecurityAttributeFlagsString(attribute->Flags);\n            PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node,\n                PhFormatString(L\"Flags: %s (0x%lx)\", temp->Buffer, attribute->Flags));\n            PhDereferenceObject(temp);\n\n            // Values\n            for (j = 0; j < attribute->ValueCount; j++)\n            {\n                temp = PhFormatClaimSecurityAttributeValue(attribute, j);\n                PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node,\n                    PhFormatString(L\"Value %u: %s\", j, temp->Buffer));\n                PhDereferenceObject(temp);\n            }\n        }\n\n        PhFree(info);\n    }\n\n    TokenPageContext->CloseObject(tokenHandle, FALSE, TokenPageContext->Context);\n\n    return TRUE;\n}\n\nINT_PTR CALLBACK PhpTokenClaimsPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n    HWND tnHandle;\n\n    tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!tokenPageContext)\n        return FALSE;\n\n    tnHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PPH_TOKEN_ATTRIBUTE_NODE userNode;\n            PPH_TOKEN_ATTRIBUTE_NODE deviceNode;\n\n            PhpInitializeAttributeTreeContext(&tokenPageContext->ClaimsTreeContext, hwndDlg, tnHandle);\n\n            TreeNew_SetEmptyText(tnHandle, &PhpEmptyTokenClaimsText, 0);\n            TreeNew_SetRedraw(tnHandle, FALSE);\n\n            userNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L\"User claims\"));\n            deviceNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L\"Device claims\"));\n\n            PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, FALSE, userNode);\n            PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, TRUE, deviceNode);\n\n            if (userNode->Children->Count == 0 && deviceNode->Children->Count == 0)\n            {\n                PhpRemoveAttributeNode(&tokenPageContext->ClaimsTreeContext, userNode);\n                PhpRemoveAttributeNode(&tokenPageContext->ClaimsTreeContext, deviceNode);\n            }\n            else\n            {\n                if (userNode->Children->Count == 0)\n                    PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, userNode, PhCreateString(L\"(None)\"));\n                if (deviceNode->Children->Count == 0)\n                    PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, deviceNode, PhCreateString(L\"(None)\"));\n            }\n\n            TreeNew_NodesStructured(tnHandle);\n            TreeNew_SetRedraw(tnHandle, TRUE);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhpDeleteAttributeTreeContext(&tokenPageContext->ClaimsTreeContext);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            TreeNew_AutoSizeColumn(tnHandle, 0, TN_AUTOSIZE_REMAINING_SPACE);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM selectedItem;\n            PPH_TOKEN_ATTRIBUTE_NODE *attributeObjectNodes = NULL;\n            ULONG numberOfAttributeObjectNodes = 0;\n\n            if (!PhpGetSelectedAttributeTreeNodes(&tokenPageContext->ClaimsTreeContext, &attributeObjectNodes, &numberOfAttributeObjectNodes))\n                break;\n\n            if (numberOfAttributeObjectNodes != 0)\n            {\n                menu = PhCreateEMenu();\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"Copy\", NULL, NULL), ULONG_MAX);\n                PhInsertCopyCellEMenuItem(menu, IDC_COPY, tnHandle, contextMenuEvent->Column);\n\n                selectedItem = PhShowEMenu(\n                    menu,\n                    hwndDlg,\n                    PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                    PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                    contextMenuEvent->Location.x,\n                    contextMenuEvent->Location.y\n                    );\n\n                if (selectedItem && selectedItem->Id != ULONG_MAX)\n                {\n                    if (!PhHandleCopyCellEMenuItem(selectedItem))\n                    {\n                        switch (selectedItem->Id)\n                        {\n                        case IDC_COPY:\n                            {\n                                PPH_STRING text;\n\n                                text = PhGetTreeNewText(tnHandle, 0);\n                                PhSetClipboardString(tnHandle, &text->sr);\n                                PhDereferenceObject(text);\n                            }\n                            break;\n                        }\n                    }\n                }\n\n                PhDestroyEMenu(menu);\n            }\n\n            PhFree(attributeObjectNodes);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhpAddTokenAttributes(\n    _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,\n    _In_ HWND tnHandle\n    )\n{\n    HANDLE tokenHandle;\n    PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info;\n    ULONG i;\n    ULONG j;\n\n    if (!NT_SUCCESS(TokenPageContext->OpenObject(\n        &tokenHandle,\n        TOKEN_QUERY,\n        TokenPageContext->Context // ProcessId\n        )))\n        return FALSE;\n\n    if (NT_SUCCESS(PhGetTokenSecurityAttributes(tokenHandle, &info)))\n    {\n        for (i = 0; i < info->AttributeCount; i++)\n        {\n            PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->AttributeV1[i];\n            PPH_STRING name;\n            PPH_TOKEN_ATTRIBUTE_NODE node;\n            PPH_STRING temp;\n\n            name = PhCreateStringFromUnicodeString(&attribute->Name);\n\n            // Attribute\n            node = PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, NULL, PhReferenceObject(name));\n            // Type\n            PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node,\n                PhFormatString(L\"Type: %s\", PhGetSecurityAttributeTypeString(attribute->ValueType)));\n            // Flags\n            temp = PhGetSecurityAttributeFlagsString(attribute->Flags);\n            PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node,\n                PhFormatString(L\"Flags: %s (0x%lx)\", temp->Buffer, attribute->Flags));\n            PhDereferenceObject(temp);\n\n            // Values\n            for (j = 0; j < attribute->ValueCount; j++)\n            {\n                temp = PhFormatTokenSecurityAttributeValue(&name->sr, attribute, j);\n                PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node,\n                    PhFormatString(L\"Value %u: %s\", j, temp->Buffer));\n                PhDereferenceObject(temp);\n            }\n        }\n\n        PhFree(info);\n    }\n\n    TokenPageContext->CloseObject(tokenHandle, FALSE, TokenPageContext->Context);\n\n    return TRUE;\n}\n\nINT_PTR CALLBACK PhpTokenAttributesPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n    HWND tnHandle;\n\n    tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!tokenPageContext)\n        return FALSE;\n\n    tnHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            PhpInitializeAttributeTreeContext(&tokenPageContext->AuthzTreeContext, hwndDlg, tnHandle);\n\n            TreeNew_SetEmptyText(tnHandle, &PhpEmptyTokenAttributesText, 0);\n            TreeNew_SetRedraw(tnHandle, FALSE);\n\n            PhpAddTokenAttributes(tokenPageContext, tnHandle);\n\n            //if (tokenPageContext->AuthzTreeContext.RootList->Count == 0)\n            //    PhpAddAttributeNode(&tokenPageContext->AuthzTreeContext, NULL, PhCreateString(L\"(None)\"));\n\n            TreeNew_NodesStructured(tnHandle);\n            TreeNew_SetRedraw(tnHandle, TRUE);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhpDeleteAttributeTreeContext(&tokenPageContext->AuthzTreeContext);\n        }\n        break;\n    case WM_SHOWWINDOW:\n        {\n            TreeNew_AutoSizeColumn(tnHandle, 0, TN_AUTOSIZE_REMAINING_SPACE);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM selectedItem;\n            PPH_TOKEN_ATTRIBUTE_NODE *attributeObjectNodes = NULL;\n            ULONG numberOfAttributeObjectNodes = 0;\n\n            if (!PhpGetSelectedAttributeTreeNodes(&tokenPageContext->AuthzTreeContext, &attributeObjectNodes, &numberOfAttributeObjectNodes))\n                break;\n\n            if (numberOfAttributeObjectNodes != 0)\n            {\n                menu = PhCreateEMenu();\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"Copy\", NULL, NULL), ULONG_MAX);\n                PhInsertCopyCellEMenuItem(menu, IDC_COPY, tnHandle, contextMenuEvent->Column);\n\n                selectedItem = PhShowEMenu(\n                    menu,\n                    hwndDlg,\n                    PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                    PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                    contextMenuEvent->Location.x,\n                    contextMenuEvent->Location.y\n                    );\n\n                if (selectedItem && selectedItem->Id != ULONG_MAX)\n                {\n                    if (!PhHandleCopyCellEMenuItem(selectedItem))\n                    {\n                        switch (selectedItem->Id)\n                        {\n                        case IDC_COPY:\n                            {\n                                PPH_STRING text;\n\n                                text = PhGetTreeNewText(tnHandle, 0);\n                                PhSetClipboardString(tnHandle, &text->sr);\n                                PhDereferenceObject(text);\n                            }\n                            break;\n                        }\n                    }\n                }\n\n                PhDestroyEMenu(menu);\n            }\n\n            PhFree(attributeObjectNodes);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n// rev from GetUserProfileDirectory (dmex)\nPPH_STRING PhpGetTokenFolderPath(\n    _In_ HANDLE TokenHandle\n    )\n{\n    static CONST PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\ProfileList\\\\\");\n    PPH_STRING profileFolderPath = NULL;\n    PPH_STRING profileKeyPath = NULL;\n    PPH_STRING tokenUserSid;\n    PH_TOKEN_USER tokenUser;\n\n    if (NT_SUCCESS(PhGetTokenUser(TokenHandle, &tokenUser)))\n    {\n        if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(tokenUser.User.Sid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_NT_AUTHORITY))\n        {\n            ULONG subAuthority = *PhSubAuthoritySid(tokenUser.User.Sid, 0);\n\n            if (subAuthority == SECURITY_UMFD_BASE_RID)\n            {\n                if (tokenUserSid = PhSidToStringSid((PSID)&PhSeLocalSystemSid))\n                {\n                    profileKeyPath = PhConcatStringRef2(&servicesKeyName, &tokenUserSid->sr);\n                    PhDereferenceObject(tokenUserSid);\n                }\n            }\n            else\n            {\n                if (tokenUserSid = PhSidToStringSid(tokenUser.User.Sid))\n                {\n                    profileKeyPath = PhConcatStringRef2(&servicesKeyName, &tokenUserSid->sr);\n                    PhDereferenceObject(tokenUserSid);\n                }\n            }\n        }\n        else\n        {\n            if (tokenUserSid = PhSidToStringSid(tokenUser.User.Sid))\n            {\n                profileKeyPath = PhConcatStringRef2(&servicesKeyName, &tokenUserSid->sr);\n                PhDereferenceObject(tokenUserSid);\n            }\n        }\n    }\n\n    if (profileKeyPath)\n    {\n        HANDLE keyHandle;\n\n        if (NT_SUCCESS(PhOpenKey(\n            &keyHandle,\n            KEY_READ,\n            PH_KEY_LOCAL_MACHINE,\n            &profileKeyPath->sr,\n            0\n            )))\n        {\n            PPH_STRING profileImagePath;\n\n            if (profileFolderPath = PhQueryRegistryStringZ(keyHandle, L\"ProfileImagePath\"))\n            {\n                if (profileImagePath = PhExpandEnvironmentStrings(&profileFolderPath->sr))\n                {\n                    PhMoveReference(&profileFolderPath, profileImagePath);\n                }\n            }\n\n            NtClose(keyHandle);\n        }\n\n        PhDereferenceObject(profileKeyPath);\n    }\n\n    //ULONG profileFolderLength;\n    //if (GetUserProfileDirectory)\n    //{\n    //    GetUserProfileDirectory(TokenHandle, NULL, &profileFolderLength);\n    //    profileFolderPath = PhCreateStringEx(NULL, profileFolderLength * sizeof(WCHAR));\n    //    GetUserProfileDirectory(TokenHandle, profileFolderPath->Buffer, &profileFolderLength);\n    //}\n\n    return profileFolderPath;\n}\n\nPPH_STRING PhpGetTokenRegistryPath(\n    _In_ HANDLE TokenHandle\n    )\n{\n    PPH_STRING profileRegistryPath = NULL;\n    PPH_STRING tokenUserSid = NULL;\n    PH_TOKEN_USER tokenUser;\n\n    if (NT_SUCCESS(PhGetTokenUser(TokenHandle, &tokenUser)))\n    {\n        tokenUserSid = PhSidToStringSid(tokenUser.User.Sid);\n    }\n\n    if (tokenUserSid)\n    {\n        NTSTATUS status;\n        HANDLE keyHandle = NULL;\n\n        status = PhOpenKey(\n            &keyHandle,\n            KEY_READ,\n            PH_KEY_USERS,\n            &tokenUserSid->sr,\n            0\n            );\n\n        if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED)\n        {\n            profileRegistryPath = PhConcatStrings2(L\"HKU\\\\\", tokenUserSid->Buffer);\n        }\n\n        if (keyHandle)\n            NtClose(keyHandle);\n\n        PhDereferenceObject(tokenUserSid);\n    }\n\n    return profileRegistryPath;\n}\n\nPPH_STRING PhpGetTokenAppContainerFolderPath(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PSID TokenAppContainerSid\n    )\n{\n    if (PhGetTokenIsFullTrustPackage(TokenHandle))\n    {\n        PPH_STRING packageLocalAppData = PhGetKnownFolderPathEx(\n            &FOLDERID_LocalAppData,\n            PH_KF_FLAG_FORCE_PACKAGE_REDIRECTION,\n            TokenHandle,\n            NULL\n            );\n        PPH_STRING localAppData = PhGetKnownFolderPathEx(\n            &FOLDERID_LocalAppData,\n            0,\n            NULL,\n            NULL\n            );\n\n        if (PhEqualString(packageLocalAppData, localAppData, TRUE))\n        {\n            PhDereferenceObject(localAppData);\n            PhDereferenceObject(packageLocalAppData);\n            return NULL;\n        }\n\n        PhDereferenceObject(localAppData);\n\n        return packageLocalAppData;\n    }\n    else if (TokenAppContainerSid)\n    {\n        PPH_STRING appContainerFolderPath;\n        //PWSTR folderPath = NULL;\n\n        appContainerFolderPath = PhGetKnownFolderPathEx(\n            &FOLDERID_LocalAppData,\n            PH_KF_FLAG_FORCE_APPCONTAINER_REDIRECTION,\n            TokenHandle,\n            NULL\n            );\n\n        //if (PhIsNullOrEmptyString(appContainerFolderPath))\n        //{\n        //    if (NT_SUCCESS(PhImpersonateToken(NtCurrentThread(), TokenHandle)))\n        //    {\n        //        if (GetAppContainerFolderPath_Import())\n        //        {\n        //            PPH_STRING appContainerSid = PhSidToStringSid(TokenAppContainerSid);\n        //\n        //            if (SUCCEEDED(GetAppContainerFolderPath_Import()(appContainerSid->Buffer, &folderPath)) && folderPath)\n        //            {\n        //                assert(PhEqualString2(appContainerFolderPath, folderPath, TRUE));\n        //                CoTaskMemFree(folderPath);\n        //            }\n        //\n        //            PhDereferenceObject(appContainerSid);\n        //        }\n        //\n        //        PhRevertImpersonationToken(NtCurrentThread());\n        //    }\n        //}\n\n        // Workaround for pseudo Appcontainers created by System processes that default to the \\systemprofile path. (dmex)\n        if (PhIsNullOrEmptyString(appContainerFolderPath))\n        {\n            PH_TOKEN_USER tokenUser;\n\n            if (NT_SUCCESS(PhGetTokenUser(TokenHandle, &tokenUser)))\n            {\n                ULONG subAuthority;\n                PPH_STRING tokenProfilePathString;\n                PPH_STRING appContainerName;\n\n                subAuthority = *PhSubAuthoritySid(tokenUser.User.Sid, 0);\n                //PhIdentifierAuthoritySid(tokenUser.User.Sid) == (BYTE[])SECURITY_NT_AUTHORITY\n\n                if (subAuthority == SECURITY_UMFD_BASE_RID)\n                {\n                    if (tokenProfilePathString = PhpGetTokenFolderPath(TokenHandle))\n                    {\n                        if (appContainerName = PhGetAppContainerName(TokenAppContainerSid))\n                        {\n                            static CONST PH_STRINGREF appDataPackagePath = PH_STRINGREF_INIT(L\"\\\\AppData\\\\Local\\\\Packages\\\\\");\n\n                            PhMoveReference(&appContainerFolderPath, PhConcatStringRef3(\n                                &tokenProfilePathString->sr,\n                                &appDataPackagePath,\n                                &appContainerName->sr\n                                ));\n\n                            PhDereferenceObject(appContainerName);\n                        }\n\n                        PhDereferenceObject(tokenProfilePathString);\n                    }\n                }\n            }\n        }\n\n        return appContainerFolderPath;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\nPPH_STRING PhpGetTokenAppContainerRegistryPath(\n    _In_ HANDLE TokenHandle\n    )\n{\n    PPH_STRING appContainerRegistryPath = NULL;\n    HKEY registryHandle = NULL;\n\n    if (NT_SUCCESS(PhImpersonateToken(NtCurrentThread(), TokenHandle)))\n    {\n        if (GetAppContainerRegistryLocation_Import())\n            GetAppContainerRegistryLocation_Import()(KEY_READ, &registryHandle);\n\n        PhRevertImpersonationToken(NtCurrentThread());\n    }\n\n    if (registryHandle)\n    {\n        PhQueryObjectName(registryHandle, &appContainerRegistryPath);\n\n        NtClose(registryHandle);\n    }\n\n    return appContainerRegistryPath;\n}\n\nINT_PTR CALLBACK PhpTokenContainerPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n    PPHP_TOKEN_ADVANCED_CONTEXT context;\n\n    tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!tokenPageContext)\n        return FALSE;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = PhAllocateZero(sizeof(PHP_TOKEN_ADVANCED_CONTEXT));\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            HANDLE tokenHandle;\n            BOOLEAN isLessPrivilegedAppContainer = FALSE;\n            PPH_STRING tokenNamedObjectPathString = NULL;\n\n            context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n            PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);\n            PhSetControlTheme(context->ListViewHandle, L\"explorer\");\n            PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 120, L\"Name\");\n            PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 280, L\"Value\");\n            PhSetExtendedListView(context->ListViewHandle);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL);\n\n            ListView_EnableGroupView(context->ListViewHandle, TRUE);\n            PhAddListViewGroup(context->ListViewHandle, 0, L\"General\");\n            PhAddListViewGroup(context->ListViewHandle, 1, L\"Properties\");\n            PhAddListViewGroup(context->ListViewHandle, 2, L\"Parent\");\n            PhAddListViewGroup(context->ListViewHandle, 3, L\"Package\");\n            PhAddListViewGroup(context->ListViewHandle, 4, L\"Profile\");\n\n            PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L\"Name\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L\"Type\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L\"SID\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L\"Number\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L\"LPAC\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L\"Token object path\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L\"Name\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L\"SID\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L\"Name\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L\"Path\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 4, MAXINT, L\"Folder path\", NULL);\n            PhAddListViewGroupItem(context->ListViewHandle, 4, MAXINT, L\"Registry path\", NULL);\n\n            if (NT_SUCCESS(tokenPageContext->OpenObject(\n                &tokenHandle,\n                TOKEN_QUERY,\n                tokenPageContext->Context // ProcessId\n                )))\n            {\n                APPCONTAINER_SID_TYPE appContainerSidType = InvalidAppContainerSidType;\n                PH_TOKEN_APPCONTAINER tokenAppContainer;\n                PSID appContainerSidParent = NULL;\n                PPH_STRING appContainerName = NULL;\n                PPH_STRING appContainerSidString = NULL;\n                ULONG appContainerNumber;\n                PPH_STRING packageFullName;\n                PPH_STRING packagePath;\n\n                if (NT_SUCCESS(PhGetTokenAppContainerSid(tokenHandle, &tokenAppContainer)))\n                {\n                    if (RtlGetAppContainerSidType_Import())\n                        RtlGetAppContainerSidType_Import()(tokenAppContainer.AppContainer.Sid, &appContainerSidType);\n                    if (RtlGetAppContainerParent_Import())\n                        RtlGetAppContainerParent_Import()(tokenAppContainer.AppContainer.Sid, &appContainerSidParent);\n\n                    appContainerName = PhGetAppContainerName(tokenAppContainer.AppContainer.Sid);\n                    appContainerSidString = PhSidToStringSid(tokenAppContainer.AppContainer.Sid);\n                }\n\n                if (appContainerName)\n                {\n                    PhSetListViewSubItem(context->ListViewHandle, 0, 1, appContainerName->Buffer);\n                    PhDereferenceObject(appContainerName);\n                }\n\n                switch (appContainerSidType)\n                {\n                case ChildAppContainerSidType:\n                    PhSetListViewSubItem(context->ListViewHandle, 1, 1, L\"Child\");\n                    break;\n                case ParentAppContainerSidType:\n                    PhSetListViewSubItem(context->ListViewHandle, 1, 1, L\"Parent\");\n                    break;\n                }\n\n                if (appContainerSidString)\n                {\n                    PhSetListViewSubItem(context->ListViewHandle, 2, 1, appContainerSidString->Buffer);\n                    PhDereferenceObject(appContainerSidString);\n                }\n\n                if (!PhGetTokenIsFullTrustPackage(tokenHandle))\n                {\n                    if (NT_SUCCESS(PhGetTokenAppContainerNumber(tokenHandle, &appContainerNumber)))\n                    {\n                        WCHAR string[PH_INT64_STR_LEN_1] = L\"Unknown\";\n\n                        PhPrintUInt32(string, appContainerNumber);\n                        PhSetListViewSubItem(context->ListViewHandle, 3, 1, string);\n                    }\n\n                    PhGetTokenIsLessPrivilegedAppContainer(tokenHandle, &isLessPrivilegedAppContainer);\n                    PhSetListViewSubItem(context->ListViewHandle, 4, 1, isLessPrivilegedAppContainer ? L\"True\" : L\"False\");\n                }\n\n                if (NT_SUCCESS(PhGetAppContainerNamedObjectPath(tokenHandle, NULL, FALSE, &tokenNamedObjectPathString)))\n                {\n                    PhSetListViewSubItem(context->ListViewHandle, 5, 1, PhGetStringOrDefault(tokenNamedObjectPathString, L\"Unknown\"));\n                    PhDereferenceObject(tokenNamedObjectPathString);\n                }\n\n                if (appContainerSidParent)\n                {\n                    if (appContainerName = PhGetAppContainerName(appContainerSidParent))\n                    {\n                        PhSetListViewSubItem(context->ListViewHandle, 6, 1, appContainerName->Buffer);\n                        PhDereferenceObject(appContainerName);\n                    }\n\n                    if (appContainerSidString = PhSidToStringSid(appContainerSidParent))\n                    {\n                        PhSetListViewSubItem(context->ListViewHandle, 7, 1, appContainerSidString->Buffer);\n                        PhDereferenceObject(appContainerSidString);\n                    }\n\n                    RtlFreeSid(appContainerSidParent);\n                }\n\n                if (NT_SUCCESS(PhGetTokenPackageFullName(tokenHandle, &packageFullName)))\n                {\n                    PhSetListViewSubItem(context->ListViewHandle, 8, 1, packageFullName->Buffer);\n\n                    if (packagePath = PhGetPackagePath(packageFullName))\n                    {\n                        PhSetListViewSubItem(context->ListViewHandle, 9, 1, packagePath->Buffer);\n                        PhDereferenceObject(packagePath);\n                    }\n\n                    PhDereferenceObject(packageFullName);\n                }\n\n                tokenPageContext->CloseObject(tokenHandle, FALSE, tokenPageContext->Context);\n            }\n\n            tokenHandle = NULL;\n\n            if (!NT_SUCCESS(tokenPageContext->OpenObject(\n                &tokenHandle,\n                TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,\n                tokenPageContext->Context // ProcessId\n                )))\n            {\n                if (!NT_SUCCESS(tokenPageContext->OpenObject(\n                    &tokenHandle,\n                    TOKEN_QUERY | TOKEN_IMPERSONATE,\n                    tokenPageContext->Context // ProcessId\n                    )))\n                {\n                    tokenPageContext->OpenObject(\n                        &tokenHandle,\n                        TOKEN_QUERY,\n                        tokenPageContext->Context // ProcessId\n                        );\n                }\n            }\n\n            if (tokenHandle)\n            {\n                PH_TOKEN_APPCONTAINER tokenAppContainer;\n                PPH_STRING appContainerFolderPath;\n                PPH_STRING appContainerRegistryPath;\n\n                if (NT_SUCCESS(PhGetTokenAppContainerSid(tokenHandle, &tokenAppContainer)))\n                    appContainerFolderPath = PhpGetTokenAppContainerFolderPath(tokenHandle, tokenAppContainer.AppContainer.Sid);\n                else\n                    appContainerFolderPath = PhpGetTokenAppContainerFolderPath(tokenHandle, NULL);\n\n                if (appContainerFolderPath)\n                {\n                    PhSetListViewSubItem(context->ListViewHandle, 10, 1, appContainerFolderPath->Buffer);\n                    PhDereferenceObject(appContainerFolderPath);\n                }\n\n                if (appContainerRegistryPath = PhpGetTokenAppContainerRegistryPath(tokenHandle))\n                {\n                    PhSetListViewSubItem(context->ListViewHandle, 11, 1, appContainerRegistryPath->Buffer);\n                    PhDereferenceObject(appContainerRegistryPath);\n                }\n\n                tokenPageContext->CloseObject(tokenHandle, FALSE, tokenPageContext->Context);\n            }\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n            PhFree(context);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n\n            ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if ((HWND)wParam == context->ListViewHandle)\n            {\n                POINT point;\n                PPH_EMENU menu;\n                PPH_EMENU item;\n                PVOID* listviewItems;\n                ULONG numberOfItems;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n\n                if (point.x == -1 && point.y == -1)\n                    PhGetListViewContextMenuPoint(context->ListViewHandle, &point);\n\n                PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems);\n\n                if (numberOfItems != 0)\n                {\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"&Copy\", NULL, NULL), ULONG_MAX);\n                    PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle);\n\n                    item = PhShowEMenu(\n                        menu,\n                        hwndDlg,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        point.x,\n                        point.y\n                        );\n\n                    if (item)\n                    {\n                        BOOLEAN handled = FALSE;\n\n                        handled = PhHandleCopyListViewEMenuItem(item);\n\n                        //if (!handled && PhPluginsEnabled)\n                        //    handled = PhPluginTriggerEMenuItem(&menuInfo, item);\n\n                        if (!handled)\n                        {\n                            switch (item->Id)\n                            {\n                            case IDC_COPY:\n                                {\n                                    PhCopyListView(context->ListViewHandle);\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n\n                PhFree(listviewItems);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\ntypedef enum _AppModelPolicy_Type\n{\n    AppModelPolicy_Type_LifecycleManager = 1,\n    AppModelPolicy_Type_AppDataAccess = 2,\n    AppModelPolicy_Type_WindowingModel = 3,\n    AppModelPolicy_Type_DllSearchOrder = 4,\n    AppModelPolicy_Type_Fusion = 5,\n    AppModelPolicy_Type_NonWindowsCodecLoading = 6,\n    AppModelPolicy_Type_ProcessEnd = 7,\n    AppModelPolicy_Type_BeginThreadInit = 8,\n    AppModelPolicy_Type_DeveloperInformation = 9,\n    AppModelPolicy_Type_CreateFileAccess = 10,\n    AppModelPolicy_Type_ImplicitPackageBreakaway_Internal = 11,\n    AppModelPolicy_Type_ProcessActivationShim = 12,\n    AppModelPolicy_Type_AppKnownToStateRepository = 13,\n    AppModelPolicy_Type_AudioManagement = 14,\n    AppModelPolicy_Type_PackageMayContainPublicComRegistrations = 15,\n    AppModelPolicy_Type_PackageMayContainPrivateComRegistrations = 16,\n    AppModelPolicy_Type_LaunchCreateProcessExtensions = 17,\n    AppModelPolicy_Type_ClrCompat = 18,\n    AppModelPolicy_Type_LoaderIgnoreAlteredSearchForRelativePath = 19,\n    AppModelPolicy_Type_ImplicitlyActivateClassicAAAServersAsIU = 20,\n    AppModelPolicy_Type_ComClassicCatalog = 21,\n    AppModelPolicy_Type_ComUnmarshaling = 22,\n    AppModelPolicy_Type_ComAppLaunchPerfEnhancements = 23,\n    AppModelPolicy_Type_ComSecurityInitialization = 24,\n    AppModelPolicy_Type_RoInitializeSingleThreadedBehavior = 25,\n    AppModelPolicy_Type_ComDefaultExceptionHandling = 26,\n    AppModelPolicy_Type_ComOopProxyAgility = 27,\n    AppModelPolicy_Type_AppServiceLifetime = 28,\n    AppModelPolicy_Type_WebPlatform = 29,\n    AppModelPolicy_Type_WinInetStoragePartitioning = 30,\n    AppModelPolicy_Type_IndexerProtocolHandlerHost = 31, // since RS2\n    AppModelPolicy_Type_LoaderIncludeUserDirectories = 32,\n    AppModelPolicy_Type_ConvertAppContainerToRestrictedAppContainer = 33,\n    AppModelPolicy_Type_PackageMayContainPrivateMapiProvider = 34,\n    AppModelPolicy_Type_AdminProcessPackageClaims = 35, // since RS3\n    AppModelPolicy_Type_RegistryRedirectionBehavior = 36,\n    AppModelPolicy_Type_BypassCreateProcessAppxExtension = 37,\n    AppModelPolicy_Type_KnownFolderRedirection = 38,\n    AppModelPolicy_Type_PrivateActivateAsPackageWinrtClasses = 39,\n    AppModelPolicy_Type_AppPrivateFolderRedirection = 40,\n    AppModelPolicy_Type_GlobalSystemAppDataAccess = 41,\n    AppModelPolicy_Type_ConsoleHandleInheritance = 42, // since RS4\n    AppModelPolicy_Type_ConsoleBufferAccess = 43,\n    AppModelPolicy_Type_ConvertCallerTokenToUserTokenForDeployment = 44,\n    AppModelPolicy_Type_ShellExecuteRetrieveIdentityFromCurrentProcess = 45, // since RS5\n    AppModelPolicy_Type_CodeIntegritySigning = 46, // since 19H1\n    AppModelPolicy_Type_PTCActivation = 47,\n    AppModelPolicy_Type_ComIntraPackageRpcCall = 48, // since 20H1\n    AppModelPolicy_Type_LoadUser32ShimOnWindowsCoreOS = 49,\n    AppModelPolicy_Type_SecurityCapabilitiesOverride = 50,\n    AppModelPolicy_Type_CurrentDirectoryOverride = 51,\n    AppModelPolicy_Type_ComTokenMatchingForAAAServers = 52,\n    AppModelPolicy_Type_UseOriginalFileNameInTokenFQBNAttribute = 53,\n    AppModelPolicy_Type_LoaderIncludeAlternateForwarders = 54,\n    AppModelPolicy_Type_PullPackageDependencyData = 55,\n    AppModelPolicy_Type_AppInstancingErrorBehavior = 56, // since WIN11\n    AppModelPolicy_Type_BackgroundTaskRegistrationType = 57,\n    AppModelPolicy_Type_ModsPowerNotification = 58,\n    AppModelPolicy_Type_DamRegistration = 59, // since 24H2\n    AppModelPolicy_Type_Count = 59,\n} AppModelPolicy_Type;\n\ntypedef enum _AppModelPolicy_PolicyValue\n{\n    AppModelPolicy_LifecycleManager_Unmanaged = 0x10000,\n    AppModelPolicy_LifecycleManager_ManagedByPLM = 0x10001,\n    AppModelPolicy_LifecycleManager_ManagedByEM = 0x10002,\n    AppModelPolicy_AppDataAccess_Allowed = 0x20000,\n    AppModelPolicy_AppDataAccess_Denied = 0x20001,\n    AppModelPolicy_WindowingModel_Hwnd = 0x30000,\n    AppModelPolicy_WindowingModel_CoreWindow = 0x30001,\n    AppModelPolicy_WindowingModel_LegacyPhone = 0x30002,\n    AppModelPolicy_WindowingModel_None = 0x30003,\n    AppModelPolicy_DllSearchOrder_Traditional = 0x40000,\n    AppModelPolicy_DllSearchOrder_PackageGraphBased = 0x40001,\n    AppModelPolicy_Fusion_Full = 0x50000,\n    AppModelPolicy_Fusion_Limited = 0x50001,\n    AppModelPolicy_NonWindowsCodecLoading_Allowed = 0x60000,\n    AppModelPolicy_NonWindowsCodecLoading_Denied = 0x60001,\n    AppModelPolicy_ProcessEnd_TerminateProcess = 0x70000,\n    AppModelPolicy_ProcessEnd_ExitProcess = 0x70001,\n    AppModelPolicy_BeginThreadInit_RoInitialize = 0x80000,\n    AppModelPolicy_BeginThreadInit_None = 0x80001,\n    AppModelPolicy_DeveloperInformation_UI = 0x90000,\n    AppModelPolicy_DeveloperInformation_None = 0x90001,\n    AppModelPolicy_CreateFileAccess_Full = 0xa0000,\n    AppModelPolicy_CreateFileAccess_Limited = 0xa0001,\n    AppModelPolicy_ImplicitPackageBreakaway_Allowed = 0xb0000,\n    AppModelPolicy_ImplicitPackageBreakaway_Denied = 0xb0001,\n    AppModelPolicy_ImplicitPackageBreakaway_DeniedByApp = 0xb0002,\n    AppModelPolicy_ProcessActivationShim_None = 0xc0000,\n    AppModelPolicy_ProcessActivationShim_PackagedCWALauncher = 0xc0001,\n    AppModelPolicy_AppKnownToStateRepository_Known = 0xd0000,\n    AppModelPolicy_AppKnownToStateRepository_Unknown = 0xd0001,\n    AppModelPolicy_AudioManagement_Unmanaged = 0xe0000,\n    AppModelPolicy_AudioManagement_ManagedByPBM = 0xe0001,\n    AppModelPolicy_PackageMayContainPublicComRegistrations_Yes = 0xf0000,\n    AppModelPolicy_PackageMayContainPublicComRegistrations_No = 0xf0001,\n    AppModelPolicy_PackageMayContainPrivateComRegistrations_None = 0x100000,\n    AppModelPolicy_PackageMayContainPrivateComRegistrations_PrivateHive = 0x100001,\n    AppModelPolicy_LaunchCreateProcessExtensions_None = 0x110000,\n    AppModelPolicy_LaunchCreateProcessExtensions_RegisterWithPsm = 0x110001,\n    AppModelPolicy_LaunchCreateProcessExtensions_RegisterWithDesktopAppX = 0x110002,\n    AppModelPolicy_LaunchCreateProcessExtensions_RegisterWithDesktopAppXNoHeliumContainer = 0x110003,\n    AppModelPolicy_ClrCompat_Others = 0x120000,\n    AppModelPolicy_ClrCompat_ClassicDesktop = 0x120001,\n    AppModelPolicy_ClrCompat_Universal = 0x120002,\n    AppModelPolicy_ClrCompat_PackagedDesktop = 0x120003,\n    AppModelPolicy_LoaderIgnoreAlteredSearchForRelativePath_False = 0x130000,\n    AppModelPolicy_LoaderIgnoreAlteredSearchForRelativePath_True = 0x130001,\n    AppModelPolicy_ImplicitlyActivateClassicAAAServersAsIU_Yes = 0x140000,\n    AppModelPolicy_ImplicitlyActivateClassicAAAServersAsIU_No = 0x140001,\n    AppModelPolicy_ComClassicCatalog_MachineHiveAndUserHive = 0x150000,\n    AppModelPolicy_ComClassicCatalog_MachineHiveOnly = 0x150001,\n    AppModelPolicy_ComUnmarshaling_ForceStrongUnmarshaling = 0x160000,\n    AppModelPolicy_ComUnmarshaling_ApplicationManaged = 0x160001,\n    AppModelPolicy_ComAppLaunchPerfEnhancements_Enabled = 0x170000,\n    AppModelPolicy_ComAppLaunchPerfEnhancements_Disabled = 0x170001,\n    AppModelPolicy_ComSecurityInitialization_ApplicationManaged = 0x180000,\n    AppModelPolicy_ComSecurityInitialization_SystemManaged = 0x180001,\n    AppModelPolicy_RoInitializeSingleThreadedBehavior_ASTA = 0x190000,\n    AppModelPolicy_RoInitializeSingleThreadedBehavior_STA = 0x190001,\n    AppModelPolicy_ComDefaultExceptionHandling_HandleAll = 0x1a0000,\n    AppModelPolicy_ComDefaultExceptionHandling_HandleNone = 0x1a0001,\n    AppModelPolicy_ComOopProxyAgility_Agile = 0x1b0000,\n    AppModelPolicy_ComOopProxyAgility_NonAgile = 0x1b0001,\n    AppModelPolicy_AppServiceLifetime_StandardTimeout = 0x1c0000,\n    AppModelPolicy_AppServiceLifetime_ExtensibleTimeout = 0x1c0001,\n    AppModelPolicy_AppServiceLifetime_ExtendedForSamePackage = 0x1c0002,\n    AppModelPolicy_WebPlatform_Edge = 0x1d0000,\n    AppModelPolicy_WebPlatform_Legacy = 0x1d0001,\n    AppModelPolicy_WinInetStoragePartitioning_Isolated = 0x1e0000,\n    AppModelPolicy_WinInetStoragePartitioning_SharedWithAppContainer = 0x1e0001,\n    AppModelPolicy_IndexerProtocolHandlerHost_PerUser = 0x1f0000,\n    AppModelPolicy_IndexerProtocolHandlerHost_PerApp = 0x1f0001,\n    AppModelPolicy_LoaderIncludeUserDirectories_False = 0x200000,\n    AppModelPolicy_LoaderIncludeUserDirectories_True = 0x200001,\n    AppModelPolicy_ConvertAppContainerToRestrictedAppContainer_False = 0x210000,\n    AppModelPolicy_ConvertAppContainerToRestrictedAppContainer_True = 0x210001,\n    AppModelPolicy_PackageMayContainPrivateMapiProvider_None = 0x220000,\n    AppModelPolicy_PackageMayContainPrivateMapiProvider_PrivateHive = 0x220001,\n    AppModelPolicy_AdminProcessPackageClaims_None = 0x230000,\n    AppModelPolicy_AdminProcessPackageClaims_Caller = 0x230001,\n    AppModelPolicy_RegistryRedirectionBehavior_None = 0x240000,\n    AppModelPolicy_RegistryRedirectionBehavior_CopyOnWrite = 0x240001,\n    AppModelPolicy_BypassCreateProcessAppxExtension_False = 0x250000,\n    AppModelPolicy_BypassCreateProcessAppxExtension_True = 0x250001,\n    AppModelPolicy_KnownFolderRedirection_Isolated = 0x260000,\n    AppModelPolicy_KnownFolderRedirection_RedirectToPackage = 0x260001,\n    AppModelPolicy_PrivateActivateAsPackageWinrtClasses_AllowNone = 0x270000,\n    AppModelPolicy_PrivateActivateAsPackageWinrtClasses_AllowFullTrust = 0x270001,\n    AppModelPolicy_PrivateActivateAsPackageWinrtClasses_AllowNonFullTrust = 0x270002,\n    AppModelPolicy_AppPrivateFolderRedirection_None = 0x280000,\n    AppModelPolicy_AppPrivateFolderRedirection_AppPrivate = 0x280001,\n    AppModelPolicy_GlobalSystemAppDataAccess_Normal = 0x290000,\n    AppModelPolicy_GlobalSystemAppDataAccess_Virtualized = 0x290001,\n    AppModelPolicy_ConsoleHandleInheritance_ConsoleOnly = 0x2a0000,\n    AppModelPolicy_ConsoleHandleInheritance_All = 0x2a0001,\n    AppModelPolicy_ConsoleBufferAccess_RestrictedUnidirectional = 0x2b0000,\n    AppModelPolicy_ConsoleBufferAccess_Unrestricted = 0x2b0001,\n    AppModelPolicy_ConvertCallerTokenToUserTokenForDeployment_UserCallerToken = 0x2c0000,\n    AppModelPolicy_ConvertCallerTokenToUserTokenForDeployment_ConvertTokenToUserToken = 0x2c0001,\n    AppModelPolicy_ShellExecuteRetrieveIdentityFromCurrentProcess_False = 0x2d0000,\n    AppModelPolicy_ShellExecuteRetrieveIdentityFromCurrentProcess_True = 0x2d0001,\n    AppModelPolicy_CodeIntegritySigning_Default = 0x2e0000,\n    AppModelPolicy_CodeIntegritySigning_OriginBased = 0x2e0001,\n    AppModelPolicy_CodeIntegritySigning_OriginBasedForDev = 0x2e0002,\n    AppModelPolicy_PTCActivation_Default = 0x2f0000,\n    AppModelPolicy_PTCActivation_AllowActivationInBrokerForMediumILContainer = 0x2f0001,\n    AppModelPolicy_Type_ComIntraPackageRpcCall_NoWake = 0x300000,\n    AppModelPolicy_Type_ComIntraPackageRpcCall_Wake = 0x300001,\n    AppModelPolicy_LoadUser32ShimOnWindowsCoreOS_True = 0x310000,\n    AppModelPolicy_LoadUser32ShimOnWindowsCoreOS_False = 0x310001,\n    AppModelPolicy_SecurityCapabilitiesOverride_None = 0x320000,\n    AppModelPolicy_SecurityCapabilitiesOverride_PackageCapabilities = 0x320001,\n    AppModelPolicy_CurrentDirectoryOverride_None = 0x330000,\n    AppModelPolicy_CurrentDirectoryOverride_PackageInstallDirectory = 0x330001,\n    AppModelPolicy_ComTokenMatchingForAAAServers_DontUseNtCompareTokens = 0x340000,\n    AppModelPolicy_ComTokenMatchingForAAAServers_UseNtCompareTokens = 0x340001,\n    AppModelPolicy_UseOriginalFileNameInTokenFQBNAttribute_False = 0x350000,\n    AppModelPolicy_UseOriginalFileNameInTokenFQBNAttribute_True = 0x350001,\n    AppModelPolicy_LoaderIncludeAlternateForwarders_False = 0x360000,\n    AppModelPolicy_LoaderIncludeAlternateForwarders_True = 0x360001,\n    AppModelPolicy_PullPackageDependencyData_False = 0x370000,\n    AppModelPolicy_PullPackageDependencyData_True = 0x370001,\n    AppModelPolicy_AppInstancingErrorBehavior_SuppressErrors = 0x380000,\n    AppModelPolicy_AppInstancingErrorBehavior_RaiseErrors = 0x380001,\n    AppModelPolicy_BackgroundTaskRegistrationType_Unsupported = 0x390000,\n    AppModelPolicy_BackgroundTaskRegistrationType_Manifested = 0x390001,\n    AppModelPolicy_BackgroundTaskRegistrationType_Win32Clsid = 0x390002,\n    AppModelPolicy_Type_ModsPowerNotification_Disabled = 0x3a0000,\n    AppModelPolicy_Type_ModsPowerNotification_Enabled = 0x3a0001,\n    AppModelPolicy_Type_ModsPowerNotification_QueryDam = 0x3a0002,\n    AppModelPolicy_Type_DamRegistration_DoNotRegister = 0x3B0000,\n    AppModelPolicy_Type_DamRegistration_RegisterAtLaunch = 0x3B0001,\n} AppModelPolicy_PolicyValue;\n\n#define WM_PH_APPMODEL_SYMBOL_RESULT (WM_APP + 101)\n\nstatic NTSTATUS (NTAPI* GetAppModelPolicy_I)(\n    _In_ HANDLE TokenHandle,\n    _In_ AppModelPolicy_Type PolicyType,\n    _Out_ AppModelPolicy_PolicyValue* PolicyValue\n    ) = NULL;\n\nDECLSPEC_GUARDNOCF\nNTSTATUS PhpGetAppModelPolicy(\n    _In_ HANDLE TokenHandle,\n    _In_ AppModelPolicy_Type PolicyType,\n    _Out_ AppModelPolicy_PolicyValue* PolicyValue\n    )\n{\n    assert(GetAppModelPolicy_I);\n\n    //\n    // GetAppModelPolicy is not in the KernelBase CFG bitmap so it can not be\n    // runtime marked as a valid indirect call target when CFG is enabled. Here\n    // we wrap the call in a routine that disables CFG.\n    //\n    return GetAppModelPolicy_I(TokenHandle, PolicyType, PolicyValue);\n}\n\nNTSTATUS PhGetAppModelPolicy(\n    _In_ HANDLE TokenHandle,\n    _In_ AppModelPolicy_Type PolicyType,\n    _Out_ AppModelPolicy_PolicyValue* PolicyValue\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    NTSTATUS status = STATUS_SUCCESS;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PPH_SYMBOL_PROVIDER symbolProvider;\n        PH_SYMBOL_INFORMATION symbolInfo;\n        PVOID baseAddress;\n        ULONG sizeOfImage;\n        PPH_STRING fileName;\n\n        symbolProvider = PhCreateSymbolProvider(NULL);\n        PhLoadSymbolProviderOptions(symbolProvider);\n\n        if (PhGetLoaderEntryDataZ(L\"kernelbase.dll\", &baseAddress, &sizeOfImage, &fileName))\n        {\n            PhLoadModuleSymbolProvider(symbolProvider, fileName, baseAddress, sizeOfImage);\n            PhDereferenceObject(fileName);\n        }\n\n        if (PhGetSymbolFromName(symbolProvider, L\"GetAppModelPolicy\", &symbolInfo))\n        {\n            GetAppModelPolicy_I = symbolInfo.Address;\n        }\n\n        PhDereferenceObject(symbolProvider);\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (GetAppModelPolicy_I)\n    {\n        // GetAppModelPolicy doesn't perform range checks and will read out-of-bound\n        // and return garbage if we ask it about a not-yet-supported policy type (diversenok)\n        if ((PolicyType >= AppModelPolicy_Type_AppInstancingErrorBehavior && WindowsVersion < WINDOWS_11) ||\n            (PolicyType >= AppModelPolicy_Type_ComIntraPackageRpcCall && WindowsVersion < WINDOWS_10_20H1) ||\n            (PolicyType >= AppModelPolicy_Type_CodeIntegritySigning && WindowsVersion < WINDOWS_10_19H1) ||\n            (PolicyType >= AppModelPolicy_Type_ShellExecuteRetrieveIdentityFromCurrentProcess && WindowsVersion < WINDOWS_10_RS5) ||\n            (PolicyType >= AppModelPolicy_Type_ConsoleHandleInheritance && WindowsVersion < WINDOWS_10_RS4) ||\n            (PolicyType >= AppModelPolicy_Type_AdminProcessPackageClaims && WindowsVersion < WINDOWS_10_RS3) ||\n            (PolicyType >= AppModelPolicy_Type_IndexerProtocolHandlerHost && WindowsVersion < WINDOWS_10_RS2))\n        {\n            return STATUS_INVALID_INFO_CLASS;\n        }\n\n        status = PhpGetAppModelPolicy(TokenHandle, PolicyType, PolicyValue);\n    }\n    else\n    {\n        status = STATUS_PROCEDURE_NOT_FOUND;\n    }\n\n    return status;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhGetAppModelPolicySymbolDownloadThread(\n    _In_ PVOID Context\n    )\n{\n    AppModelPolicy_PolicyValue result;\n\n    if (PhGetAppModelPolicy(\n        PhGetOwnTokenAttributes().TokenHandle,\n        AppModelPolicy_Type_DllSearchOrder,\n        &result\n        ) != STATUS_PROCEDURE_NOT_FOUND)\n    {\n        PostMessage(Context, WM_PH_APPMODEL_SYMBOL_RESULT, 0, TRUE);\n    }\n    else\n    {\n        PostMessage(Context, WM_PH_APPMODEL_SYMBOL_RESULT, 0, FALSE);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhEnumTokenAppModelPolicy(\n    _In_ PTOKEN_PAGE_CONTEXT TokenPageContext\n    )\n{\n    HANDLE TokenHandle;\n    AppModelPolicy_PolicyValue result;\n\n    if (!NT_SUCCESS(TokenPageContext->OpenObject(\n        &TokenHandle,\n        TOKEN_QUERY,\n        TokenPageContext->Context // ProcessId\n        )))\n    {\n        return;\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_LifecycleManager, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"LifecycleManager\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_LifecycleManager_Unmanaged:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Unmanaged\"));\n            break;\n        case AppModelPolicy_LifecycleManager_ManagedByPLM:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ManagedByPLM\"));\n            break;\n        case AppModelPolicy_LifecycleManager_ManagedByEM:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ManagedByEM\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_AppDataAccess, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"AppDataAccess\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_AppDataAccess_Allowed:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Allowed\"));\n            break;\n        case AppModelPolicy_AppDataAccess_Denied:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Denied\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_WindowingModel, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"WindowingModel\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_WindowingModel_Hwnd:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Hwnd\"));\n            break;\n        case AppModelPolicy_WindowingModel_CoreWindow:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"CoreWindow\"));\n            break;\n        case AppModelPolicy_WindowingModel_LegacyPhone:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"LegacyPhone\"));\n            break;\n        case AppModelPolicy_WindowingModel_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_DllSearchOrder, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"DllSearchOrder\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_DllSearchOrder_Traditional:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Traditional\"));\n            break;\n        case AppModelPolicy_DllSearchOrder_PackageGraphBased:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"PackageGraphBased\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_Fusion, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"Fusion\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_Fusion_Full:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Full\"));\n            break;\n        case AppModelPolicy_Fusion_Limited:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Limited\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_NonWindowsCodecLoading, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"NonWindowsCodecLoading\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_NonWindowsCodecLoading_Allowed:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Allowed\"));\n            break;\n        case AppModelPolicy_NonWindowsCodecLoading_Denied:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Denied\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ProcessEnd, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ProcessEnd\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ProcessEnd_TerminateProcess:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"TerminateProcess\"));\n            break;\n        case AppModelPolicy_ProcessEnd_ExitProcess:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ExitProcess\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_BeginThreadInit, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"BeginThreadInit\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_BeginThreadInit_RoInitialize:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"RoInitialize\"));\n            break;\n        case AppModelPolicy_BeginThreadInit_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_DeveloperInformation, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"DeveloperInformation\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_DeveloperInformation_UI:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"UI\"));\n            break;\n        case AppModelPolicy_DeveloperInformation_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_CreateFileAccess, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"CreateFileAccess\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_CreateFileAccess_Full:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Full\"));\n            break;\n        case AppModelPolicy_CreateFileAccess_Limited:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Limited\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ImplicitPackageBreakaway_Internal, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ImplicitPackageBreakaway\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ImplicitPackageBreakaway_Allowed:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Allowed\"));\n            break;\n        case AppModelPolicy_ImplicitPackageBreakaway_Denied:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Denied\"));\n            break;\n        case AppModelPolicy_ImplicitPackageBreakaway_DeniedByApp:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"DeniedByApp\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ProcessActivationShim, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ProcessActivationShim\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ProcessActivationShim_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        case AppModelPolicy_ProcessActivationShim_PackagedCWALauncher:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"PackagedCWALauncher\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_AppKnownToStateRepository, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"AppKnownToStateRepository\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_AppKnownToStateRepository_Known:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Known\"));\n            break;\n        case AppModelPolicy_AppKnownToStateRepository_Unknown:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Unknown\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_AudioManagement, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"AudioManagement\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_AudioManagement_Unmanaged:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Unmanaged\"));\n            break;\n        case AppModelPolicy_AudioManagement_ManagedByPBM:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ManagedByPBM\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_PackageMayContainPublicComRegistrations, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"PackageMayContainPublicComRegistrations\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_PackageMayContainPublicComRegistrations_Yes:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Yes\"));\n            break;\n        case AppModelPolicy_PackageMayContainPublicComRegistrations_No:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"No\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_PackageMayContainPrivateComRegistrations, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"PackageMayContainPrivateComRegistrations\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_PackageMayContainPrivateComRegistrations_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        case AppModelPolicy_PackageMayContainPrivateComRegistrations_PrivateHive:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"PrivateHive\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_LaunchCreateProcessExtensions, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"LaunchCreateProcessExtensions\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_LaunchCreateProcessExtensions_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        case AppModelPolicy_LaunchCreateProcessExtensions_RegisterWithPsm:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"RegisterWithPsm\"));\n            break;\n        case AppModelPolicy_LaunchCreateProcessExtensions_RegisterWithDesktopAppX:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"RegisterWithDesktopAppX\"));\n            break;\n        case AppModelPolicy_LaunchCreateProcessExtensions_RegisterWithDesktopAppXNoHeliumContainer:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"RegisterWithDesktopAppXNoHeliumContainer\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ClrCompat, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ClrCompat\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ClrCompat_Others:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Others\"));\n            break;\n        case AppModelPolicy_ClrCompat_ClassicDesktop:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ClassicDesktop\"));\n            break;\n        case AppModelPolicy_ClrCompat_Universal:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Universal\"));\n            break;\n        case AppModelPolicy_ClrCompat_PackagedDesktop:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"PackagedDesktop\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_LoaderIgnoreAlteredSearchForRelativePath, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"IgnoreAlteredSearchForRelativePath\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_LoaderIgnoreAlteredSearchForRelativePath_False:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"False\"));\n            break;\n        case AppModelPolicy_LoaderIgnoreAlteredSearchForRelativePath_True:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"True\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ImplicitlyActivateClassicAAAServersAsIU, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ImplicitlyActivateClassicAAAServersAsIU\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ImplicitlyActivateClassicAAAServersAsIU_Yes:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Yes\"));\n            break;\n        case AppModelPolicy_ImplicitlyActivateClassicAAAServersAsIU_No:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"No\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ComClassicCatalog, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ComClassicCatalog\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ComClassicCatalog_MachineHiveAndUserHive:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"MachineHiveAndUserHive\"));\n            break;\n        case AppModelPolicy_ComClassicCatalog_MachineHiveOnly:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"MachineHiveOnly\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ComUnmarshaling, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ComUnmarshaling\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ComUnmarshaling_ForceStrongUnmarshaling:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ForceStrongUnmarshaling\"));\n            break;\n        case AppModelPolicy_ComUnmarshaling_ApplicationManaged:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ApplicationManaged\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ComAppLaunchPerfEnhancements, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ComAppLaunchPerfEnhancements\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ComAppLaunchPerfEnhancements_Enabled:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Enabled\"));\n            break;\n        case AppModelPolicy_ComAppLaunchPerfEnhancements_Disabled:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Disabled\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ComSecurityInitialization, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ComSecurityInitialization\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ComSecurityInitialization_ApplicationManaged:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ApplicationManaged\"));\n            break;\n        case AppModelPolicy_ComSecurityInitialization_SystemManaged:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"SystemManaged\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_RoInitializeSingleThreadedBehavior, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"RoInitializeSingleThreadedBehavior\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_RoInitializeSingleThreadedBehavior_ASTA:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ASTA\"));\n            break;\n        case AppModelPolicy_RoInitializeSingleThreadedBehavior_STA:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"STA\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ComDefaultExceptionHandling, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ComDefaultExceptionHandling\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ComDefaultExceptionHandling_HandleAll:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"All\"));\n            break;\n        case AppModelPolicy_ComDefaultExceptionHandling_HandleNone:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ComOopProxyAgility, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ComOopProxyAgility\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ComOopProxyAgility_Agile:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Agile\"));\n            break;\n        case AppModelPolicy_ComOopProxyAgility_NonAgile:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"NonAgile\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_AppServiceLifetime, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"AppServiceLifetime\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_AppServiceLifetime_StandardTimeout:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"StandardTimeout\"));\n            break;\n        case AppModelPolicy_AppServiceLifetime_ExtensibleTimeout:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ExtensibleTimeout\"));\n            break;\n        case AppModelPolicy_AppServiceLifetime_ExtendedForSamePackage:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ExtendedForSamePackage\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_WebPlatform, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"WebPlatform\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_WebPlatform_Edge:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Edge\"));\n            break;\n        case AppModelPolicy_WebPlatform_Legacy:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Legacy\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_WinInetStoragePartitioning, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"WinInetStoragePartitioning\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_WinInetStoragePartitioning_Isolated:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Isolated\"));\n            break;\n        case AppModelPolicy_WinInetStoragePartitioning_SharedWithAppContainer:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"SharedWithAppContainer\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_IndexerProtocolHandlerHost, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"IndexerProtocolHandlerHost\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_IndexerProtocolHandlerHost_PerUser:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"PerUser\"));\n            break;\n        case AppModelPolicy_IndexerProtocolHandlerHost_PerApp:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"PerApp\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_LoaderIncludeUserDirectories, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"LoaderIncludeUserDirectories\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_LoaderIncludeUserDirectories_False:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"False\"));\n            break;\n        case AppModelPolicy_LoaderIncludeUserDirectories_True:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"True\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ConvertAppContainerToRestrictedAppContainer, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ConvertAppContainerToRestrictedAppContainer\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ConvertAppContainerToRestrictedAppContainer_False:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"False\"));\n            break;\n        case AppModelPolicy_ConvertAppContainerToRestrictedAppContainer_True:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"True\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_PackageMayContainPrivateMapiProvider, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"PackageMayContainPrivateMapiProvider\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_PackageMayContainPrivateMapiProvider_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        case AppModelPolicy_PackageMayContainPrivateMapiProvider_PrivateHive:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"PrivateHive\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_AdminProcessPackageClaims, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"AdminProcessPackageClaims\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_AdminProcessPackageClaims_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        case AppModelPolicy_AdminProcessPackageClaims_Caller:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Caller\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_RegistryRedirectionBehavior, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"RegistryRedirectionBehavior\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_RegistryRedirectionBehavior_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        case AppModelPolicy_RegistryRedirectionBehavior_CopyOnWrite:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"CopyOnWrite\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_BypassCreateProcessAppxExtension, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"BypassCreateProcessAppxExtension\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_BypassCreateProcessAppxExtension_False:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"False\"));\n            break;\n        case AppModelPolicy_BypassCreateProcessAppxExtension_True:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"True\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_KnownFolderRedirection, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"KnownFolderRedirection\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_KnownFolderRedirection_Isolated:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Isolated\"));\n            break;\n        case AppModelPolicy_KnownFolderRedirection_RedirectToPackage:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"RedirectToPackage\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_PrivateActivateAsPackageWinrtClasses, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"PrivateActivateAsPackageWinrtClasses\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_PrivateActivateAsPackageWinrtClasses_AllowNone:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"AllowNone\"));\n            break;\n        case AppModelPolicy_PrivateActivateAsPackageWinrtClasses_AllowFullTrust:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"AllowFullTrust\"));\n            break;\n        case AppModelPolicy_PrivateActivateAsPackageWinrtClasses_AllowNonFullTrust:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"AllowNonFullTrust\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_AppPrivateFolderRedirection, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"AppPrivateFolderRedirection\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_AppPrivateFolderRedirection_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        case AppModelPolicy_AppPrivateFolderRedirection_AppPrivate:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"AppPrivate\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_GlobalSystemAppDataAccess, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"GlobalSystemAppDataAccess\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_GlobalSystemAppDataAccess_Normal:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Normal\"));\n            break;\n        case AppModelPolicy_GlobalSystemAppDataAccess_Virtualized:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Virtualized\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ConsoleHandleInheritance, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ConsoleHandleInheritance\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ConsoleHandleInheritance_ConsoleOnly:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ConsoleOnly\"));\n            break;\n        case AppModelPolicy_ConsoleHandleInheritance_All:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"All\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ConsoleBufferAccess, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ConsoleBufferAccess\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ConsoleBufferAccess_RestrictedUnidirectional:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"RestrictedUnidirectional\"));\n            break;\n        case AppModelPolicy_ConsoleBufferAccess_Unrestricted:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Unrestricted\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ConvertCallerTokenToUserTokenForDeployment, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ConvertCallerTokenToUserTokenForDeployment\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ConvertCallerTokenToUserTokenForDeployment_UserCallerToken:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"UserCallerToken\"));\n            break;\n        case AppModelPolicy_ConvertCallerTokenToUserTokenForDeployment_ConvertTokenToUserToken:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"ConvertTokenToUserToken\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ShellExecuteRetrieveIdentityFromCurrentProcess, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ShellExecuteRetrieveIdentityFromCurrentProcess\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ShellExecuteRetrieveIdentityFromCurrentProcess_False:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"False\"));\n            break;\n        case AppModelPolicy_ShellExecuteRetrieveIdentityFromCurrentProcess_True:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"True\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_CodeIntegritySigning, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"CodeIntegritySigning\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_CodeIntegritySigning_Default:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Default\"));\n            break;\n        case AppModelPolicy_CodeIntegritySigning_OriginBased:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"OriginBased\"));\n            break;\n        case AppModelPolicy_CodeIntegritySigning_OriginBasedForDev:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"OriginBasedForDev\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_PTCActivation, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"PTCActivation\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_PTCActivation_Default:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Default\"));\n            break;\n        case AppModelPolicy_PTCActivation_AllowActivationInBrokerForMediumILContainer:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"AllowActivationInBrokerForMediumIL\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ComIntraPackageRpcCall, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ComIntraPackageRpcCall\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_Type_ComIntraPackageRpcCall_NoWake:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"NoWake\"));\n            break;\n        case AppModelPolicy_Type_ComIntraPackageRpcCall_Wake:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Wake\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_LoadUser32ShimOnWindowsCoreOS, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"LoadUser32ShimOnWindowsCoreOS\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_LoadUser32ShimOnWindowsCoreOS_True:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"True\"));\n            break;\n        case AppModelPolicy_LoadUser32ShimOnWindowsCoreOS_False:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"False\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_SecurityCapabilitiesOverride, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"SecurityCapabilitiesOverride\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_SecurityCapabilitiesOverride_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        case AppModelPolicy_SecurityCapabilitiesOverride_PackageCapabilities:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"PackageCapabilities\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_CurrentDirectoryOverride, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"CurrentDirectoryOverride\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_CurrentDirectoryOverride_None:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"None\"));\n            break;\n        case AppModelPolicy_CurrentDirectoryOverride_PackageInstallDirectory:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"PackageInstallDirectory\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ComTokenMatchingForAAAServers, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ComTokenMatching\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_ComTokenMatchingForAAAServers_DontUseNtCompareTokens:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"DontUseNtCompareTokens\"));\n            break;\n        case AppModelPolicy_ComTokenMatchingForAAAServers_UseNtCompareTokens:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"UseNtCompareTokens\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_UseOriginalFileNameInTokenFQBNAttribute, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"UseOriginalFileNameInTokenFQBN\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_UseOriginalFileNameInTokenFQBNAttribute_False:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"False\"));\n            break;\n        case AppModelPolicy_UseOriginalFileNameInTokenFQBNAttribute_True:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"True\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_LoaderIncludeAlternateForwarders, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"LoaderIncludeAlternateForwarders\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_LoaderIncludeAlternateForwarders_False:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"False\"));\n            break;\n        case AppModelPolicy_LoaderIncludeAlternateForwarders_True:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"True\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_PullPackageDependencyData, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"PullPackageDependencyData\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_PullPackageDependencyData_False:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"False\"));\n            break;\n        case AppModelPolicy_PullPackageDependencyData_True:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"True\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_AppInstancingErrorBehavior, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"AppInstancingErrorBehavior\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_AppInstancingErrorBehavior_SuppressErrors:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"SuppressErrors\"));\n            break;\n        case AppModelPolicy_AppInstancingErrorBehavior_RaiseErrors:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"RaiseErrors\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_BackgroundTaskRegistrationType, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"BackgroundTaskRegistrationType\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_BackgroundTaskRegistrationType_Unsupported:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Unsupported\"));\n            break;\n        case AppModelPolicy_BackgroundTaskRegistrationType_Manifested:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Manifested\"));\n            break;\n        case AppModelPolicy_BackgroundTaskRegistrationType_Win32Clsid:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Win32Clsid\"));\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetAppModelPolicy(TokenHandle, AppModelPolicy_Type_ModsPowerNotification, &result)))\n    {\n        PPH_TOKEN_ATTRIBUTE_NODE node = PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, NULL, PhCreateString(L\"ModsPowerNotification\"));\n\n        switch (result)\n        {\n        case AppModelPolicy_Type_ModsPowerNotification_Disabled:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Disabled\"));\n            break;\n        case AppModelPolicy_Type_ModsPowerNotification_Enabled:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"Enabled\"));\n            break;\n        case AppModelPolicy_Type_ModsPowerNotification_QueryDam:\n            PhpAddAttributeNode(&TokenPageContext->AppPolicyTreeContext, node, PhCreateString(L\"QueryDam\"));\n            break;\n        }\n    }\n\n    TokenPageContext->CloseObject(TokenHandle, FALSE, TokenPageContext->Context);\n}\n\n#define SORT_FUNCTION(Column) PhpAppPolicyTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpAppPolicyTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_TOKEN_ATTRIBUTE_NODE node1 = *(PPH_TOKEN_ATTRIBUTE_NODE*)_elem1; \\\n    PPH_TOKEN_ATTRIBUTE_NODE node2 = *(PPH_TOKEN_ATTRIBUTE_NODE*)_elem2; \\\n    LONG sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    if (sortResult == 0) \\\n        sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \\\n    \\\n    return PhModifySort(sortResult, ((PPH_TOKEN_ATTRIBUTE_TREE_CONTEXT)_context)->TreeNewSortOrder); \\\n}\n\nBEGIN_SORT_FUNCTION(Name)\n{\n    sortResult = PhCompareStringWithNull(node1->Text, node2->Text, TRUE);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Value)\n{\n    sortResult = PhCompareStringWithNull(node1->Text, node2->Text, TRUE);\n}\nEND_SORT_FUNCTION\n\nBOOLEAN NTAPI PhpAppPolicyTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_TOKEN_ATTRIBUTE_TREE_CONTEXT context = Context;\n    PPH_TOKEN_ATTRIBUTE_NODE node;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            node = (PPH_TOKEN_ATTRIBUTE_NODE)getChildren->Node;\n\n            if (context->TreeNewSortOrder == NoSortOrder)\n            {\n                if (!node)\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE*)context->RootList->Items;\n                    getChildren->NumberOfChildren = context->RootList->Count;\n                }\n                else\n                {\n                    getChildren->Children = (PPH_TREENEW_NODE*)node->Children->Items;\n                    getChildren->NumberOfChildren = node->Children->Count;\n                }\n            }\n            else\n            {\n                if (!node)\n                {\n                    static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                    {\n                        SORT_FUNCTION(Name),\n                        SORT_FUNCTION(Value)\n                    };\n                    _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                    static_assert(RTL_NUMBER_OF(sortFunctions) == 2, \"SortFunctions must equal maximum.\");\n\n                    if (context->TreeNewSortColumn < 2)\n                        sortFunction = sortFunctions[context->TreeNewSortColumn];\n                    else\n                        sortFunction = NULL;\n\n                    if (sortFunction)\n                    {\n                        qsort_s(context->RootList->Items, context->RootList->Count, sizeof(PVOID), sortFunction, context);\n                    }\n\n                    getChildren->Children = (PPH_TREENEW_NODE*)context->RootList->Items;\n                    getChildren->NumberOfChildren = context->RootList->Count;\n                }\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = Parameter1;\n            node = (PPH_TOKEN_ATTRIBUTE_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;\n            node = (PPH_TOKEN_ATTRIBUTE_NODE)getCellText->Node;\n\n            if (getCellText->Id == 0)\n                getCellText->Text = PhGetStringRef(node->Text);\n            else if (getCellText->Id == 1)\n            {\n                if (PhIsNullOrEmptyString(node->Value))\n                {\n                    PH_STRING_BUILDER stringBuilder;\n\n                    PhInitializeStringBuilder(&stringBuilder, 64);\n\n                    for (ULONG i = 0; i < node->Children->Count; i++)\n                    {\n                        PhAppendStringBuilder(&stringBuilder, &((PPH_TOKEN_ATTRIBUTE_NODE)node->Children->Items[i])->Text->sr);\n                        PhAppendStringBuilder2(&stringBuilder, L\", \");\n                    }\n\n                    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n                        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n                    node->Value = PhFinalStringBuilderString(&stringBuilder);\n                }\n\n                getCellText->Text = PhGetStringRef(node->Value);\n            }\n            else\n                return FALSE;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            // Force a rebuild to sort the items.\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    PPH_STRING text;\n\n                    text = PhGetTreeNewText(WindowHandle, 0);\n                    PhSetClipboardString(WindowHandle, &text->sr);\n                    PhDereferenceObject(text);\n                }\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1;\n\n            SendMessage(context->WindowHandle, WM_CONTEXTMENU, 0, (LPARAM)contextMenuEvent);\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = 0;\n            data.DefaultSortOrder = AscendingSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nstatic CONST PH_STRINGREF PhAppPolicyLoadingText = PH_STRINGREF_INIT(L\"Initializing kernelbase symbols...\");\nstatic CONST PH_STRINGREF PhAppPolicyEmptyText = PH_STRINGREF_INIT(L\"There are no policies to display.\");\n\nINT_PTR CALLBACK PhpTokenAppPolicyPageProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PTOKEN_PAGE_CONTEXT tokenPageContext;\n    HWND tnHandle;\n\n    tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);\n\n    if (!tokenPageContext)\n        return FALSE;\n\n    tnHandle = GetDlgItem(hwndDlg, IDC_LIST);\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            tokenPageContext->AppPolicyTreeContext.WindowHandle = hwndDlg;\n            tokenPageContext->AppPolicyTreeContext.NodeList = PhCreateList(10);\n            tokenPageContext->AppPolicyTreeContext.RootList = PhCreateList(10);\n\n            PhSetControlTheme(tnHandle, L\"explorer\");\n            TreeNew_SetRedraw(tnHandle, FALSE);\n            TreeNew_SetEmptyText(tnHandle, &PhAppPolicyLoadingText, 0);\n            TreeNew_SetCallback(tnHandle, PhpAppPolicyTreeNewCallback, &tokenPageContext->AppPolicyTreeContext);\n            PhAddTreeNewColumnEx2(tnHandle, 0, TRUE, L\"Policy\", 220, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_NODPISCALEONADD);\n            PhAddTreeNewColumnEx2(tnHandle, 1, TRUE, L\"Value\", 150, PH_ALIGN_LEFT, 1, 0, TN_COLUMN_FLAG_NODPISCALEONADD);\n            TreeNew_SetTriState(tnHandle, TRUE);\n            TreeNew_SetRedraw(tnHandle, TRUE);\n\n            PhCreateThread2(PhGetAppModelPolicySymbolDownloadThread, hwndDlg);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhpDeleteAttributeTreeContext(&tokenPageContext->AppPolicyTreeContext);\n        }\n        break;\n    case WM_PH_APPMODEL_SYMBOL_RESULT:\n        {\n            BOOLEAN result = (BOOLEAN)lParam;\n\n            if (result)\n            {\n                TreeNew_SetEmptyText(tnHandle, &PhAppPolicyEmptyText, 0);\n\n                TreeNew_SetRedraw(tnHandle, FALSE);\n                PhEnumTokenAppModelPolicy(tokenPageContext);\n                TreeNew_NodesStructured(tnHandle);\n                TreeNew_SetRedraw(tnHandle, TRUE);\n            }\n            else\n            {\n                TreeNew_SetEmptyText(tnHandle, &PhAppPolicyEmptyText, 0);\n            }\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM selectedItem;\n            PPH_TOKEN_ATTRIBUTE_NODE* attributeObjectNodes = NULL;\n            ULONG numberOfAttributeObjectNodes = 0;\n\n            if (!PhpGetSelectedAttributeTreeNodes(&tokenPageContext->AppPolicyTreeContext, &attributeObjectNodes, &numberOfAttributeObjectNodes))\n                break;\n\n            if (numberOfAttributeObjectNodes != 0)\n            {\n                menu = PhCreateEMenu();\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"Copy\", NULL, NULL), ULONG_MAX);\n                PhInsertCopyCellEMenuItem(menu, IDC_COPY, tnHandle, contextMenuEvent->Column);\n\n                selectedItem = PhShowEMenu(\n                    menu,\n                    hwndDlg,\n                    PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                    PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                    contextMenuEvent->Location.x,\n                    contextMenuEvent->Location.y\n                    );\n\n                if (selectedItem && selectedItem->Id != ULONG_MAX)\n                {\n                    if (!PhHandleCopyCellEMenuItem(selectedItem))\n                    {\n                        switch (selectedItem->Id)\n                        {\n                        case IDC_COPY:\n                            {\n                                PPH_STRING text;\n\n                                text = PhGetTreeNewText(tnHandle, 0);\n                                PhSetClipboardString(tnHandle, &text->sr);\n                                PhDereferenceObject(text);\n                            }\n                            break;\n                        }\n                    }\n                }\n\n                PhDestroyEMenu(menu);\n            }\n\n            PhFree(attributeObjectNodes);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n"
  },
  {
    "path": "SystemInformer/usrlist.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025\n *\n */\n\n#include <phapp.h>\n#include <colmgr.h>\n#include <cpysave.h>\n#include <emenu.h>\n#include <lsasup.h>\n#include <mapldr.h>\n#include <secedit.h>\n#include <settings.h>\n#include <phsettings.h>\n\nstatic NTSTATUS (NTAPI* LsaFreeReturnBuffer_I)(\n    _In_ PVOID Buffer\n    ) = NULL;\n\nstatic NTSTATUS (NTAPI* LsaEnumerateLogonSessions_I)(\n    _Out_ PULONG LogonSessionCount,\n    _Out_ PLUID* LogonSessionList\n    ) = NULL;\n\nstatic NTSTATUS (NTAPI* LsaGetLogonSessionData_I)(\n    _In_ PLUID LogonId,\n    _Out_ PSECURITY_LOGON_SESSION_DATA* ppLogonSessionData\n    );\n\n//\n// Values for UserFlags. (ntscapi.h)\n//\n#define LOGON_GUEST                 0x01\n#define LOGON_NOENCRYPTION          0x02\n#define LOGON_CACHED_ACCOUNT        0x04\n#define LOGON_USED_LM_PASSWORD      0x08\n#define LOGON_EXTRA_SIDS            0x20\n#define LOGON_SUBAUTH_SESSION_KEY   0x40\n#define LOGON_SERVER_TRUST_ACCOUNT  0x80\n#define LOGON_NTLMV2_ENABLED        0x100       // says DC understands NTLMv2\n#define LOGON_RESOURCE_GROUPS       0x200\n#define LOGON_PROFILE_PATH_RETURNED 0x400\n#define LOGON_NT_V2                 0x800   // NT response was used for validation\n#define LOGON_LM_V2                 0x1000  // LM response was used for validation\n#define LOGON_NTLM_V2               0x2000  // LM response was used to authenticate but NT response was used to derive the session key\n#define LOGON_OPTIMIZED             0x4000  // this is an optimized logon\n#define LOGON_WINLOGON              0x8000  // the logon session was created for winlogon\n#define LOGON_PKINIT               0x10000  // Kerberos PKINIT extension was used to authenticate the user\n#define LOGON_NO_OPTIMIZED         0x20000  // optimized logon has been disabled for this account\n#define LOGON_NO_ELEVATION         0x40000  // Do not allow elevation for this logon\n#define LOGON_MANAGED_SERVICE      0x80000  // Managed service account\n\nPPH_STRING PhpFormatUserFlags(\n    _In_ ULONG UserFlags\n    )\n{\n#define PH_LSA_USER_FLAG(x, n)            { TEXT(#x), x, FALSE, FALSE, n }\n    static const PH_ACCESS_ENTRY userFlags[] =\n    {\n        PH_LSA_USER_FLAG(LOGON_GUEST, L\"Guest\"),\n        PH_LSA_USER_FLAG(LOGON_NOENCRYPTION, L\"No encryption\"),\n        PH_LSA_USER_FLAG(LOGON_CACHED_ACCOUNT, L\"Cached account\"),\n        PH_LSA_USER_FLAG(LOGON_USED_LM_PASSWORD, L\"Used LM password\"),\n        PH_LSA_USER_FLAG(LOGON_EXTRA_SIDS, L\"Extra SIDs\"),\n        PH_LSA_USER_FLAG(LOGON_SUBAUTH_SESSION_KEY, L\"Subauth session key\"),\n        PH_LSA_USER_FLAG(LOGON_SERVER_TRUST_ACCOUNT, L\"Server trust account\"),\n        PH_LSA_USER_FLAG(LOGON_NTLMV2_ENABLED, L\"NTLMv2 enabled\"),\n        PH_LSA_USER_FLAG(LOGON_RESOURCE_GROUPS, L\"Resource groups\"),\n        PH_LSA_USER_FLAG(LOGON_PROFILE_PATH_RETURNED, L\"Profile path returned\"),\n        PH_LSA_USER_FLAG(LOGON_NT_V2, L\"NTv2\"),\n        PH_LSA_USER_FLAG(LOGON_LM_V2, L\"LMv2\"),\n        PH_LSA_USER_FLAG(LOGON_NTLM_V2, L\"NTLMv2\"),\n        PH_LSA_USER_FLAG(LOGON_OPTIMIZED, L\"Optimized\"),\n        PH_LSA_USER_FLAG(LOGON_WINLOGON, L\"WinLogon created\"),\n        PH_LSA_USER_FLAG(LOGON_PKINIT, L\"Keberos\"),\n        PH_LSA_USER_FLAG(LOGON_NO_OPTIMIZED, L\"Not optimized\"),\n        PH_LSA_USER_FLAG(LOGON_NO_ELEVATION, L\"No elevation\"),\n        PH_LSA_USER_FLAG(LOGON_MANAGED_SERVICE, L\"Managed service\"),\n    };\n\n    PH_FORMAT format[4];\n    PPH_STRING string;\n\n    string = PhGetAccessString(UserFlags, (PPH_ACCESS_ENTRY)userFlags, RTL_NUMBER_OF(userFlags));\n    PhInitFormatSR(&format[0], string->sr);\n    PhInitFormatS(&format[1], L\" (0x\");\n    PhInitFormatX(&format[2], UserFlags);\n    PhInitFormatS(&format[3], L\")\");\n\n    PhMoveReference(&string, PhFormat(format, 4, 10));\n\n    return string;\n}\n\ntypedef enum _PH_USER_LIST_COLUMN\n{\n    PH_USER_LIST_COLUMN_LOGON_ID,\n    PH_USER_LIST_COLUMN_USER_NAME,\n    PH_USER_LIST_COLUMN_LOGON_DOMAIN,\n    PH_USER_LIST_COLUMN_AUTHENTICATION_PACKAGE,\n    PH_USER_LIST_COLUMN_LOGON_TYPE,\n    PH_USER_LIST_COLUMN_SESSION_ID,\n    PH_USER_LIST_COLUMN_SID,\n    PH_USER_LIST_COLUMN_LOGON_TIME,\n    PH_USER_LIST_COLUMN_LOGON_SERVER,\n    PH_USER_LIST_COLUMN_DNS_DOMAIN_NAME,\n    PH_USER_LIST_COLUMN_USER_PRINCIPAL_NAME,\n    PH_USER_LIST_COLUMN_USER_FLAGS,\n    PH_USER_LIST_COLUMN_FAILED_ATTEMPTS_SINCE_LAST_SUCCESSFUL_LOGON,\n    PH_USER_LIST_COLUMN_LAST_SUCCESSFUL_LOGON,\n    PH_USER_LIST_COLUMN_LAST_FAILED_LOGON,\n    PH_USER_LIST_COLUMN_LOGON_SCRIPT,\n    PH_USER_LIST_COLUMN_PROFILE_PATH,\n    PH_USER_LIST_COLUMN_HOME_DIRECTORY,\n    PH_USER_LIST_COLUMN_HOME_DIRECTORY_DRIVE,\n    PH_USER_LIST_COLUMN_LOGOFF_TIME,\n    PH_USER_LIST_COLUMN_KICKOFF_TIME,\n    PH_USER_LIST_COLUMN_PASSWORD_LAST_SET,\n    PH_USER_LIST_COLUMN_PASSWORD_CAN_CHANGE,\n    PH_USER_LIST_COLUMN_PASSWORD_MUST_CHANGE,\n    PH_USER_LIST_COLUMN_MAXIMUM,\n} PH_USER_LIST_COLUMN;\n\ntypedef struct _PH_USER_NODE\n{\n    PH_TREENEW_NODE Node;\n\n    LUID LogonId;\n    PPH_STRING UserName;\n    PPH_STRING LogonDomain;\n    PPH_STRING AuthenticationPackage;\n    SECURITY_LOGON_TYPE LogonType;\n    ULONG SessionId;\n    PPH_STRING Sid;\n    LARGE_INTEGER LogonTime;\n    PPH_STRING LogonServer;\n    PPH_STRING DnsDomainName;\n    PPH_STRING UserPrincipalName;\n    ULONG UserFlags;\n    ULONG FailedAttemptsSinceLastSuccessfulLogon;\n    LARGE_INTEGER LastSuccessfulLogon;\n    LARGE_INTEGER LastFailedLogon;\n    PPH_STRING LogonScript;\n    PPH_STRING ProfilePath;\n    PPH_STRING HomeDirectory;\n    PPH_STRING HomeDirectoryDrive;\n    LARGE_INTEGER LogoffTime;\n    LARGE_INTEGER KickOffTime;\n    LARGE_INTEGER PasswordLastSet;\n    LARGE_INTEGER PasswordCanChange;\n    LARGE_INTEGER PasswordMustChange;\n\n    WCHAR LogonIdText[PH_PTR_STR_LEN_1];\n    PPH_STRING SessionIdText;\n    PPH_STRING LogonTimeText;\n    PPH_STRING UserFlagsText;\n    PPH_STRING FailedAttemptsSinceLastSuccessfulLogonText;\n    PPH_STRING LastSuccessfulLogonText;\n    PPH_STRING LastFailedLogonText;\n    PPH_STRING LogoffTimeText;\n    PPH_STRING KickOffTimeText;\n    PPH_STRING PasswordLastSetText;\n    PPH_STRING PasswordCanChangeText;\n    PPH_STRING PasswordMustChangeText;\n\n    PH_STRINGREF TextCache[PH_USER_LIST_COLUMN_MAXIMUM];\n} PH_USER_NODE, *PPH_USER_NODE;\n\ntypedef struct _PH_USER_LIST_CONTEXT\n{\n    HWND WindowHandle;\n    HWND ParentWindowHandle;\n    HWND TreeNewHandle;\n    HWND MessageHandle;\n    HWND SearchWindowHandle;\n    ULONG_PTR SearchMatchHandle;\n    PH_LAYOUT_MANAGER LayoutManager;\n    PH_TN_FILTER_SUPPORT FilterSupport;\n    RECT MinimumSize;\n    ULONG TreeNewSortColumn;\n    PH_SORT_ORDER TreeNewSortOrder;\n    PPH_LIST NodeList;\n} PH_USER_LIST_CONTEXT, *PPH_USER_LIST_CONTEXT;\n\nVOID PhpDeleteUserNode(\n    _In_ PPH_USER_NODE User\n    )\n{\n    PhClearReference(&User->UserName);\n    PhClearReference(&User->LogonDomain);\n    PhClearReference(&User->AuthenticationPackage);\n    PhClearReference(&User->Sid);\n    PhClearReference(&User->LogonServer);\n    PhClearReference(&User->DnsDomainName);\n    PhClearReference(&User->UserPrincipalName);\n    PhClearReference(&User->LogonScript);\n    PhClearReference(&User->ProfilePath);\n    PhClearReference(&User->HomeDirectory);\n    PhClearReference(&User->HomeDirectoryDrive);\n\n    PhClearReference(&User->SessionIdText);\n    PhClearReference(&User->LogonTimeText);\n    PhClearReference(&User->UserFlagsText);\n    PhClearReference(&User->FailedAttemptsSinceLastSuccessfulLogonText);\n    PhClearReference(&User->LastSuccessfulLogonText);\n    PhClearReference(&User->LastFailedLogonText);\n    PhClearReference(&User->LogoffTimeText);\n    PhClearReference(&User->KickOffTimeText);\n    PhClearReference(&User->PasswordLastSetText);\n    PhClearReference(&User->PasswordCanChangeText);\n    PhClearReference(&User->PasswordMustChangeText);\n}\n\nPPH_USER_NODE PhpCreateUserNode(\n    _In_ PPH_USER_LIST_CONTEXT Context,\n    _In_ PSECURITY_LOGON_SESSION_DATA LogonSessionData\n    )\n{\n    PPH_USER_NODE user;\n\n    user = PhAllocateZero(sizeof(PH_USER_NODE));\n\n    PhInitializeTreeNewNode(&user->Node);\n    memset(user->TextCache, 0, sizeof(PH_STRINGREF) * PH_USER_LIST_COLUMN_MAXIMUM);\n    user->Node.TextCache = user->TextCache;\n    user->Node.TextCacheSize = PH_USER_LIST_COLUMN_MAXIMUM;\n\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, LogonId))\n        user->LogonId = LogonSessionData->LogonId;\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, UserName))\n        user->UserName = PhCreateStringFromUnicodeString(&LogonSessionData->UserName);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, LogonDomain))\n        user->LogonDomain = PhCreateStringFromUnicodeString(&LogonSessionData->LogonDomain);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, AuthenticationPackage))\n        user->AuthenticationPackage = PhCreateStringFromUnicodeString(&LogonSessionData->AuthenticationPackage);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, LogonType))\n        user->LogonType = LogonSessionData->LogonType;\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, Session))\n        user->SessionId = LogonSessionData->Session;\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, Sid))\n        user->Sid = PhSidToStringSid(LogonSessionData->Sid);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, LogonTime))\n        user->LogonTime = LogonSessionData->LogonTime;\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, LogonServer))\n        user->LogonServer = PhCreateStringFromUnicodeString(&LogonSessionData->LogonServer);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, DnsDomainName))\n        user->DnsDomainName = PhCreateStringFromUnicodeString(&LogonSessionData->DnsDomainName);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, Upn))\n        user->UserPrincipalName = PhCreateStringFromUnicodeString(&LogonSessionData->Upn);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, UserFlags))\n        user->UserFlags = LogonSessionData->UserFlags;\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, LastLogonInfo))\n    {\n        user->FailedAttemptsSinceLastSuccessfulLogon = LogonSessionData->LastLogonInfo.FailedAttemptCountSinceLastSuccessfulLogon;\n        user->LastSuccessfulLogon = LogonSessionData->LastLogonInfo.LastSuccessfulLogon;\n        user->LastFailedLogon = LogonSessionData->LastLogonInfo.LastFailedLogon;\n    }\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, LogonScript))\n        user->LogonScript = PhCreateStringFromUnicodeString(&LogonSessionData->LogonScript);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, ProfilePath))\n        user->ProfilePath = PhCreateStringFromUnicodeString(&LogonSessionData->ProfilePath);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, HomeDirectory))\n        user->HomeDirectory = PhCreateStringFromUnicodeString(&LogonSessionData->HomeDirectory);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, HomeDirectoryDrive))\n        user->HomeDirectoryDrive = PhCreateStringFromUnicodeString(&LogonSessionData->HomeDirectoryDrive);\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, LogoffTime))\n        user->LogoffTime = LogonSessionData->LogoffTime;\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, KickOffTime))\n        user->KickOffTime = LogonSessionData->KickOffTime;\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, PasswordLastSet))\n        user->PasswordLastSet = LogonSessionData->PasswordLastSet;\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, PasswordCanChange))\n        user->PasswordCanChange = LogonSessionData->PasswordCanChange;\n    if (RTL_CONTAINS_FIELD(LogonSessionData, LogonSessionData->Size, PasswordMustChange))\n        user->PasswordMustChange = LogonSessionData->PasswordMustChange;\n\n    if (Context->FilterSupport.NodeList)\n        user->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &user->Node);\n\n    return user;\n}\n\n_Function_class_(PH_TN_FILTER_FUNCTION)\nBOOLEAN PhpUserListTreeFilterCallback(\n    _In_ PPH_TREENEW_NODE Node,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_USER_LIST_CONTEXT context = Context;\n    PPH_USER_NODE user = (PPH_USER_NODE)Node;\n\n    assert(Context);\n\n    if (!context->SearchMatchHandle)\n        return TRUE;\n\n    if (PhSearchControlMatchLongHintZ(context->SearchMatchHandle, user->LogonIdText))\n        return TRUE;\n    if (user->UserName && PhSearchControlMatch(context->SearchMatchHandle, &user->UserName->sr))\n        return TRUE;\n    if (user->LogonDomain && PhSearchControlMatch(context->SearchMatchHandle, &user->LogonDomain->sr))\n        return TRUE;\n    if (user->AuthenticationPackage && PhSearchControlMatch(context->SearchMatchHandle, &user->AuthenticationPackage->sr))\n        return TRUE;\n    if (user->LogonTimeText && PhSearchControlMatch(context->SearchMatchHandle, &user->LogonTimeText->sr))\n        return TRUE;\n    if (user->SessionIdText && PhSearchControlMatch(context->SearchMatchHandle, &user->SessionIdText->sr))\n        return TRUE;\n    if (user->Sid && PhSearchControlMatch(context->SearchMatchHandle, &user->Sid->sr))\n        return TRUE;\n    if (user->LogoffTimeText && PhSearchControlMatch(context->SearchMatchHandle, &user->LogoffTimeText->sr))\n        return TRUE;\n    if (user->LogonServer && PhSearchControlMatch(context->SearchMatchHandle, &user->LogonServer->sr))\n        return TRUE;\n    if (user->DnsDomainName && PhSearchControlMatch(context->SearchMatchHandle, &user->DnsDomainName->sr))\n        return TRUE;\n    if (user->UserPrincipalName && PhSearchControlMatch(context->SearchMatchHandle, &user->UserPrincipalName->sr))\n        return TRUE;\n    if (user->UserFlagsText && PhSearchControlMatch(context->SearchMatchHandle, &user->UserFlagsText->sr))\n        return TRUE;\n    if (user->FailedAttemptsSinceLastSuccessfulLogonText && PhSearchControlMatch(context->SearchMatchHandle, &user->FailedAttemptsSinceLastSuccessfulLogonText->sr))\n        return TRUE;\n    if (user->LastSuccessfulLogonText && PhSearchControlMatch(context->SearchMatchHandle, &user->LastSuccessfulLogonText->sr))\n        return TRUE;\n    if (user->LastFailedLogonText && PhSearchControlMatch(context->SearchMatchHandle, &user->LastFailedLogonText->sr))\n        return TRUE;\n    if (user->LogonScript && PhSearchControlMatch(context->SearchMatchHandle, &user->LogonScript->sr))\n        return TRUE;\n    if (user->ProfilePath && PhSearchControlMatch(context->SearchMatchHandle, &user->ProfilePath->sr))\n        return TRUE;\n    if (user->HomeDirectory && PhSearchControlMatch(context->SearchMatchHandle, &user->HomeDirectory->sr))\n        return TRUE;\n    if (user->HomeDirectoryDrive && PhSearchControlMatch(context->SearchMatchHandle, &user->HomeDirectoryDrive->sr))\n        return TRUE;\n    if (user->LogoffTimeText && PhSearchControlMatch(context->SearchMatchHandle, &user->LogoffTimeText->sr))\n        return TRUE;\n    if (user->KickOffTimeText && PhSearchControlMatch(context->SearchMatchHandle, &user->KickOffTimeText->sr))\n        return TRUE;\n    if (user->PasswordLastSetText && PhSearchControlMatch(context->SearchMatchHandle, &user->PasswordLastSetText->sr))\n        return TRUE;\n    if (user->PasswordCanChangeText && PhSearchControlMatch(context->SearchMatchHandle, &user->PasswordCanChangeText->sr))\n        return TRUE;\n    if (user->PasswordMustChangeText && PhSearchControlMatch(context->SearchMatchHandle, &user->PasswordMustChangeText->sr))\n        return TRUE;\n\n    return FALSE;\n}\n\nVOID PhpDeleteUserListTree(\n    _In_ PPH_USER_LIST_CONTEXT Context\n    )\n{\n    if (Context->NodeList)\n    {\n        for (ULONG i = 0; i < Context->NodeList->Count; i++)\n        {\n            PhpDeleteUserNode(Context->NodeList->Items[i]);\n        }\n\n        PhDereferenceObject(Context->NodeList);\n        Context->NodeList = NULL;\n    }\n\n    PhDeleteTreeNewFilterSupport(&Context->FilterSupport);\n}\n\nVOID PhpUserListRefresh(\n    _In_ PPH_USER_LIST_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    ULONG logonSessionCount;\n    PLUID logonSessionList;\n    PH_FORMAT format[2];\n    PPH_STRING message;\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n\n    PhpDeleteUserListTree(Context);\n\n    Context->NodeList = PhCreateList(1);\n\n    PhInitializeTreeNewFilterSupport(&Context->FilterSupport, Context->TreeNewHandle, Context->NodeList);\n    PhAddTreeNewFilter(&Context->FilterSupport, PhpUserListTreeFilterCallback, Context);\n\n    if (NT_SUCCESS(status = LsaEnumerateLogonSessions_I(&logonSessionCount, &logonSessionList)))\n    {\n        for (ULONG i = 0; i < logonSessionCount; i++)\n        {\n            PSECURITY_LOGON_SESSION_DATA logonSessionData;\n\n            if (NT_SUCCESS(status = LsaGetLogonSessionData_I(&logonSessionList[i], &logonSessionData)))\n            {\n                PhAddItemList(Context->NodeList, PhpCreateUserNode(Context, logonSessionData));\n                LsaFreeReturnBuffer_I(logonSessionData);\n            }\n        }\n\n        LsaFreeReturnBuffer_I(logonSessionList);\n    }\n\n    PhInitFormatS(&format[0], L\"Number of users: \");\n    PhInitFormatU(&format[1], Context->NodeList->Count);\n    message = PhFormat(format, 2, 10);\n\n    SetWindowText(Context->MessageHandle, message->Buffer);\n\n    PhDereferenceObject(message);\n\n    TreeNew_NodesStructured(Context->TreeNewHandle);\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n}\n\nBOOLEAN PhpGetSelectedUserListNodes(\n    _In_ PPH_USER_LIST_CONTEXT Context,\n    _Out_ PPH_USER_NODE** Nodes,\n    _Out_ PULONG NumberOfNodes\n    )\n{\n    PPH_LIST list = PhCreateList(2);\n\n    for (ULONG i = 0; i < Context->NodeList->Count; i++)\n    {\n        PPH_USER_NODE node = (PPH_USER_NODE)Context->NodeList->Items[i];\n\n        if (node->Node.Selected)\n            PhAddItemList(list, node);\n    }\n\n    if (list->Count)\n    {\n        *Nodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);\n        *NumberOfNodes = list->Count;\n\n        PhDereferenceObject(list);\n        return TRUE;\n    }\n\n    *Nodes = NULL;\n    *NumberOfNodes = 0;\n\n    PhDereferenceObject(list);\n    return FALSE;\n}\n\n#define SORT_FUNCTION(Column) PvpUserListTreeNewCompare##Column\n#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PvpUserListTreeNewCompare##Column( \\\n    _In_ void *_context, \\\n    _In_ const void *_elem1, \\\n    _In_ const void *_elem2 \\\n    ) \\\n{ \\\n    PPH_USER_NODE node1 = *(PPH_USER_NODE *)_elem1; \\\n    PPH_USER_NODE node2 = *(PPH_USER_NODE *)_elem2; \\\n    PPH_USER_LIST_CONTEXT context = _context;\n    int sortResult = 0;\n\n#define END_SORT_FUNCTION \\\n    return PhModifySort(sortResult, context->TreeNewSortOrder); \\\n}\n\nBEGIN_SORT_FUNCTION(LogonId)\n{\n    sortResult = uintcmp(node1->LogonId.LowPart, node2->LogonId.LowPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(UserName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->UserName,\n        node2->UserName,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LogonDomain)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->LogonDomain,\n        node2->LogonDomain,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(AuthenticationPackage)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->AuthenticationPackage,\n        node2->AuthenticationPackage,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LogonType)\n{\n    sortResult = uintcmp(node1->LogonType, node2->LogonType);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Session)\n{\n    sortResult = uintcmp(node1->SessionId, node2->SessionId);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(Sid)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->Sid,\n        node2->Sid,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LogonTime)\n{\n    sortResult = int64cmp(node1->LogonTime.QuadPart, node2->LogonTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LogonServer)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->LogonServer,\n        node2->LogonServer,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(DnsDomainName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->DnsDomainName,\n        node2->DnsDomainName,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(UserPrincipalName)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->UserPrincipalName,\n        node2->UserPrincipalName,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(UserFlags)\n{\n    sortResult = uintcmp(node1->UserFlags, node2->UserFlags);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(FailedAttemptsSinceLastSuccessfulLogon)\n{\n    sortResult = uintcmp(node1->FailedAttemptsSinceLastSuccessfulLogon, node2->FailedAttemptsSinceLastSuccessfulLogon);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LastSuccessfulLogon)\n{\n    sortResult = int64cmp(node1->LastSuccessfulLogon.QuadPart, node2->LastSuccessfulLogon.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LastFailedLogon)\n{\n    sortResult = int64cmp(node1->LastFailedLogon.QuadPart, node2->LastFailedLogon.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LogonScript)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->LogonScript,\n        node2->LogonScript,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(ProfilePath)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->ProfilePath,\n        node2->ProfilePath,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(HomeDirectory)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->HomeDirectory,\n        node2->HomeDirectory,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(HomeDirectoryDrive)\n{\n    sortResult = PhCompareStringWithNullSortOrder(\n        node1->HomeDirectoryDrive,\n        node2->HomeDirectoryDrive,\n        context->TreeNewSortOrder,\n        TRUE\n        );\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(LogoffTime)\n{\n    sortResult = int64cmp(node1->LogoffTime.QuadPart, node2->LogoffTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(KickOffTime)\n{\n    sortResult = int64cmp(node1->KickOffTime.QuadPart, node2->KickOffTime.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PasswordLastSet)\n{\n    sortResult = int64cmp(node1->PasswordLastSet.QuadPart, node2->PasswordLastSet.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PasswordCanChange)\n{\n    sortResult = int64cmp(node1->PasswordCanChange.QuadPart, node2->PasswordCanChange.QuadPart);\n}\nEND_SORT_FUNCTION\n\nBEGIN_SORT_FUNCTION(PasswordMustChange)\n{\n    sortResult = int64cmp(node1->PasswordMustChange.QuadPart, node2->PasswordMustChange.QuadPart);\n}\nEND_SORT_FUNCTION\n\n\nBOOLEAN NTAPI PhpUserListTreeNewCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ PVOID Parameter1,\n    _In_ PVOID Parameter2,\n    _In_ PVOID Context\n    )\n{\n    PPH_USER_LIST_CONTEXT context = Context;\n    PPH_USER_NODE user;\n\n    switch (Message)\n    {\n    case TreeNewGetChildren:\n        {\n            PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;\n            user = (PPH_USER_NODE)getChildren->Node;\n\n            if (!getChildren->Node)\n            {\n                static _CoreCrtSecureSearchSortCompareFunction sortFunctions[] =\n                {\n                    SORT_FUNCTION(LogonId),\n                    SORT_FUNCTION(UserName),\n                    SORT_FUNCTION(LogonDomain),\n                    SORT_FUNCTION(AuthenticationPackage),\n                    SORT_FUNCTION(LogonType),\n                    SORT_FUNCTION(Session),\n                    SORT_FUNCTION(Sid),\n                    SORT_FUNCTION(LogonTime),\n                    SORT_FUNCTION(LogonServer),\n                    SORT_FUNCTION(DnsDomainName),\n                    SORT_FUNCTION(UserPrincipalName),\n                    SORT_FUNCTION(UserFlags),\n                    SORT_FUNCTION(FailedAttemptsSinceLastSuccessfulLogon),\n                    SORT_FUNCTION(LastSuccessfulLogon),\n                    SORT_FUNCTION(LastFailedLogon),\n                    SORT_FUNCTION(LogonScript),\n                    SORT_FUNCTION(ProfilePath),\n                    SORT_FUNCTION(HomeDirectory),\n                    SORT_FUNCTION(HomeDirectoryDrive),\n                    SORT_FUNCTION(LogoffTime),\n                    SORT_FUNCTION(KickOffTime),\n                    SORT_FUNCTION(PasswordLastSet),\n                    SORT_FUNCTION(PasswordCanChange),\n                    SORT_FUNCTION(PasswordMustChange),\n\n                };\n                _CoreCrtSecureSearchSortCompareFunction sortFunction;\n\n                static_assert(RTL_NUMBER_OF(sortFunctions) == PH_USER_LIST_COLUMN_MAXIMUM, \"SortFunctions must equal maximum.\");\n\n                if (context->TreeNewSortColumn < PH_USER_LIST_COLUMN_MAXIMUM)\n                    sortFunction = sortFunctions[context->TreeNewSortColumn];\n                else\n                    sortFunction = NULL;\n\n                if (sortFunction)\n                {\n                    qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);\n                }\n\n                getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;\n                getChildren->NumberOfChildren = context->NodeList->Count;\n            }\n        }\n        return TRUE;\n    case TreeNewIsLeaf:\n        {\n            PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1;\n            user = (PPH_USER_NODE)isLeaf->Node;\n\n            isLeaf->IsLeaf = TRUE;\n        }\n        return TRUE;\n    case TreeNewGetCellText:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1;\n            user = (PPH_USER_NODE)getCellText->Node;\n\n            switch (getCellText->Id)\n            {\n            case PH_USER_LIST_COLUMN_LOGON_ID:\n                PhPrintPointer(user->LogonIdText, UlongToPtr(user->LogonId.LowPart));\n                PhInitializeStringRefLongHint(&getCellText->Text, user->LogonIdText);\n                break;\n            case PH_USER_LIST_COLUMN_USER_NAME:\n                getCellText->Text = PhGetStringRef(user->UserName);\n                break;\n            case PH_USER_LIST_COLUMN_LOGON_DOMAIN:\n                getCellText->Text = PhGetStringRef(user->LogonDomain);\n                break;\n            case PH_USER_LIST_COLUMN_AUTHENTICATION_PACKAGE:\n                getCellText->Text = PhGetStringRef(user->AuthenticationPackage);\n                break;\n            case PH_USER_LIST_COLUMN_LOGON_TYPE:\n                switch (user->LogonType)\n                {\n                case UndefinedLogonType:\n                    PhInitializeStringRef(&getCellText->Text, L\"Undefined\");\n                    break;\n                case Interactive:\n                    PhInitializeStringRef(&getCellText->Text, L\"Interactive\");\n                    break;\n                case Network:\n                    PhInitializeStringRef(&getCellText->Text, L\"Network\");\n                    break;\n                case Batch:\n                    PhInitializeStringRef(&getCellText->Text, L\"Batch\");\n                    break;\n                case Service:\n                    PhInitializeStringRef(&getCellText->Text, L\"Service\");\n                    break;\n                case Proxy:\n                    PhInitializeStringRef(&getCellText->Text, L\"Proxy\");\n                    break;\n                case Unlock:\n                    PhInitializeStringRef(&getCellText->Text, L\"Unlock\");\n                    break;\n                case NetworkCleartext:\n                    PhInitializeStringRef(&getCellText->Text, L\"Network cleartext\");\n                    break;\n                case NewCredentials:\n                    PhInitializeStringRef(&getCellText->Text, L\"New credentials\");\n                    break;\n                case RemoteInteractive:\n                    PhInitializeStringRef(&getCellText->Text, L\"Remote interactive\");\n                    break;\n                case CachedInteractive:\n                    PhInitializeStringRef(&getCellText->Text, L\"Cached interactive\");\n                    break;\n                case CachedRemoteInteractive:\n                    PhInitializeStringRef(&getCellText->Text, L\"Cached remote interactive\");\n                    break;\n                case CachedUnlock:\n                    PhInitializeStringRef(&getCellText->Text, L\"Cached unlock\");\n                    break;\n                default:\n                    break;\n                }\n                break;\n            case PH_USER_LIST_COLUMN_SESSION_ID:\n                PhMoveReference(&user->SessionIdText, PhFormatUInt64(user->SessionId, TRUE));\n                getCellText->Text = user->SessionIdText->sr;\n                break;\n            case PH_USER_LIST_COLUMN_SID:\n                getCellText->Text = PhGetStringRef(user->Sid);\n                break;\n            case PH_USER_LIST_COLUMN_LOGON_TIME:\n                {\n                    if (user->LogonTime.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &user->LogonTime);\n                        PhMoveReference(&user->LogonTimeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(user->LogonTimeText);\n                    }\n                }\n                break;\n            case PH_USER_LIST_COLUMN_LOGON_SERVER:\n                getCellText->Text = PhGetStringRef(user->LogonServer);\n                break;\n            case PH_USER_LIST_COLUMN_DNS_DOMAIN_NAME:\n                getCellText->Text = PhGetStringRef(user->DnsDomainName);\n                break;\n            case PH_USER_LIST_COLUMN_USER_PRINCIPAL_NAME:\n                getCellText->Text = PhGetStringRef(user->UserPrincipalName);\n                break;\n            case PH_USER_LIST_COLUMN_USER_FLAGS:\n                {\n                    if (user->UserFlags)\n                    {\n                        user->UserFlagsText = PhpFormatUserFlags(user->UserFlags);\n                        getCellText->Text = user->UserFlagsText->sr;\n                    }\n                }\n                break;\n            case PH_USER_LIST_COLUMN_FAILED_ATTEMPTS_SINCE_LAST_SUCCESSFUL_LOGON:\n                PhMoveReference(&user->FailedAttemptsSinceLastSuccessfulLogonText, PhFormatUInt64(user->FailedAttemptsSinceLastSuccessfulLogon, TRUE));\n                getCellText->Text = user->FailedAttemptsSinceLastSuccessfulLogonText->sr;\n                break;\n            case PH_USER_LIST_COLUMN_LAST_SUCCESSFUL_LOGON:\n                {\n                    if (user->LastSuccessfulLogon.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &user->LastSuccessfulLogon);\n                        PhMoveReference(&user->LastSuccessfulLogonText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(user->LastSuccessfulLogonText);\n                    }\n                }\n                break;\n            case PH_USER_LIST_COLUMN_LAST_FAILED_LOGON:\n                {\n                    if (user->LastFailedLogon.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &user->LastFailedLogon);\n                        PhMoveReference(&user->LastFailedLogonText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(user->LastFailedLogonText);\n                    }\n                }\n                break;\n            case PH_USER_LIST_COLUMN_LOGON_SCRIPT:\n                getCellText->Text = PhGetStringRef(user->LogonScript);\n                break;\n            case PH_USER_LIST_COLUMN_PROFILE_PATH:\n                getCellText->Text = PhGetStringRef(user->ProfilePath);\n                break;\n            case PH_USER_LIST_COLUMN_HOME_DIRECTORY:\n                getCellText->Text = PhGetStringRef(user->HomeDirectory);\n                break;\n            case PH_USER_LIST_COLUMN_HOME_DIRECTORY_DRIVE:\n                getCellText->Text = PhGetStringRef(user->HomeDirectoryDrive);\n                break;\n            case PH_USER_LIST_COLUMN_LOGOFF_TIME:\n                {\n                    if (user->LogoffTime.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &user->LogoffTime);\n                        PhMoveReference(&user->LogoffTimeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(user->LogoffTimeText);\n                    }\n                }\n                break;\n            case PH_USER_LIST_COLUMN_KICKOFF_TIME:\n                {\n                    if (user->KickOffTime.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &user->KickOffTime);\n                        PhMoveReference(&user->KickOffTimeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(user->KickOffTimeText);\n                    }\n                }\n                break;\n            case PH_USER_LIST_COLUMN_PASSWORD_LAST_SET:\n                {\n                    if (user->PasswordLastSet.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &user->PasswordLastSet);\n                        PhMoveReference(&user->PasswordLastSetText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(user->PasswordLastSetText);\n                    }\n                }\n                break;\n            case PH_USER_LIST_COLUMN_PASSWORD_CAN_CHANGE:\n                {\n                    if (user->PasswordCanChange.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &user->PasswordCanChange);\n                        PhMoveReference(&user->PasswordCanChangeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(user->PasswordCanChangeText);\n                    }\n                }\n                break;\n            case PH_USER_LIST_COLUMN_PASSWORD_MUST_CHANGE:\n                {\n                    if (user->PasswordMustChange.QuadPart != 0)\n                    {\n                        SYSTEMTIME systemTime;\n\n                        PhLargeIntegerToLocalSystemTime(&systemTime, &user->PasswordMustChange);\n                        PhMoveReference(&user->PasswordMustChangeText, PhFormatDateTime(&systemTime));\n                        getCellText->Text = PhGetStringRef(user->PasswordMustChangeText);\n                    }\n                }\n                break;\n            default:\n                return FALSE;\n            }\n\n            getCellText->Flags = TN_CACHE;\n        }\n        return TRUE;\n    case TreeNewGetNodeColor:\n        {\n            PPH_TREENEW_GET_NODE_COLOR getNodeColor = (PPH_TREENEW_GET_NODE_COLOR)Parameter1;\n            user = (PPH_USER_NODE)getNodeColor->Node;\n\n            getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR;\n        }\n        return TRUE;\n    case TreeNewSortChanged:\n        {\n            PPH_TREENEW_SORT_CHANGED_EVENT sorting = Parameter1;\n\n            context->TreeNewSortColumn = sorting->SortColumn;\n            context->TreeNewSortOrder = sorting->SortOrder;\n\n            TreeNew_NodesStructured(WindowHandle);\n        }\n        return TRUE;\n    case TreeNewKeyDown:\n        {\n            PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;\n\n            switch (keyEvent->VirtualKey)\n            {\n            case 'C':\n                {\n                    if (GetKeyState(VK_CONTROL) < 0)\n                    {\n                        PPH_STRING text;\n\n                        text = PhGetTreeNewText(WindowHandle, 0);\n                        PhSetClipboardString(WindowHandle, &text->sr);\n                        PhDereferenceObject(text);\n                    }\n                }\n                break;\n            case 'A':\n                if (GetKeyState(VK_CONTROL) < 0)\n                    TreeNew_SelectRange(context->TreeNewHandle, 0, -1);\n                break;\n            }\n        }\n        return TRUE;\n    case TreeNewNodeExpanding:\n        return TRUE;\n    case TreeNewLeftDoubleClick:\n        return TRUE;\n    case TreeNewContextMenu:\n        {\n            PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;\n            PPH_EMENU menu;\n            PPH_EMENU_ITEM selectedItem;\n            PPH_USER_NODE* userNodes = NULL;\n            ULONG numberOfNodes = 0;\n\n            if (!PhpGetSelectedUserListNodes(context, &userNodes, &numberOfNodes))\n                break;\n\n            if (numberOfNodes != 0)\n            {\n                menu = PhCreateEMenu();\n                PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L\"Copy\", NULL, NULL), ULONG_MAX);\n                PhInsertCopyCellEMenuItem(menu, IDC_COPY, context->TreeNewHandle, contextMenu->Column);\n\n                selectedItem = PhShowEMenu(\n                    menu,\n                    WindowHandle,\n                    PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                    PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                    contextMenu->Location.x,\n                    contextMenu->Location.y\n                    );\n\n                if (selectedItem && selectedItem->Id != ULONG_MAX && !PhHandleCopyCellEMenuItem(selectedItem))\n                {\n                    if (selectedItem->Id == IDC_COPY)\n                    {\n                        PPH_STRING text;\n\n                        text = PhGetTreeNewText(context->TreeNewHandle, 0);\n                        PhSetClipboardString(context->TreeNewHandle, &text->sr);\n                        PhDereferenceObject(text);\n                    }\n                }\n\n                PhDestroyEMenu(menu);\n                PhFree(userNodes);\n            }\n        }\n        return TRUE;\n    case TreeNewHeaderRightClick:\n        {\n            PH_TN_COLUMN_MENU_DATA data;\n\n            data.TreeNewHandle = WindowHandle;\n            data.MouseEvent = Parameter1;\n            data.DefaultSortColumn = 0;\n            data.DefaultSortOrder = AscendingSortOrder;\n            PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);\n\n            data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);\n            PhHandleTreeNewColumnMenu(&data);\n            PhDeleteTreeNewColumnMenu(&data);\n        }\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhpUserListLoadSettingsTreeList(\n    _Inout_ PPH_USER_LIST_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhGetStringSetting(SETTING_USER_LIST_TREE_LIST_COLUMNS);\n    PhCmLoadSettings(Context->TreeNewHandle, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\nVOID PhpUserListSaveSettingsTreeList(\n    _Inout_ PPH_USER_LIST_CONTEXT Context\n    )\n{\n    PPH_STRING settings;\n\n    settings = PhCmSaveSettings(Context->TreeNewHandle);\n    PhSetStringSetting2(SETTING_USER_LIST_TREE_LIST_COLUMNS, &settings->sr);\n    PhDereferenceObject(settings);\n}\n\nVOID PhpInitializeUserListTree(\n    _In_ PPH_USER_LIST_CONTEXT Context\n    )\n{\n    ULONG index = 0;\n\n    PhSetControlTheme(Context->TreeNewHandle, L\"explorer\");\n\n    TreeNew_SetCallback(Context->TreeNewHandle, PhpUserListTreeNewCallback, Context);\n    TreeNew_SetExtendedFlags(Context->TreeNewHandle, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT);\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);\n\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_USER_NAME, TRUE, L\"User name\", 250, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_LOGON_DOMAIN, TRUE, L\"Logon domain\", 180, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_SESSION_ID, TRUE, L\"Session ID\", 80, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_LOGON_TYPE, TRUE, L\"Logon type\", 100, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_AUTHENTICATION_PACKAGE, TRUE, L\"Authentication package\", 140, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_DNS_DOMAIN_NAME, TRUE, L\"DNS domain name\", 140, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_LOGON_TIME, TRUE, L\"Logon time\", 140, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_PASSWORD_LAST_SET, TRUE, L\"Password last set\", 140, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_SID, TRUE, L\"SID\", 180, PH_ALIGN_LEFT, index++, 0);\n\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_LOGON_ID, FALSE, L\"Logon ID\", 80, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_LOGON_SERVER, FALSE, L\"Logon server\", 180, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_USER_PRINCIPAL_NAME, FALSE, L\"User principal name\", 180, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_USER_FLAGS, FALSE, L\"User flags\", 180, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_FAILED_ATTEMPTS_SINCE_LAST_SUCCESSFUL_LOGON, FALSE, L\"Failed logon attempts since\", 80, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_LAST_SUCCESSFUL_LOGON, FALSE, L\"Last successful logon\", 140, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_LAST_FAILED_LOGON, FALSE, L\"Last failed logon\", 140, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_LOGON_SCRIPT, FALSE, L\"Longon script\", 180, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_PROFILE_PATH, FALSE, L\"Profile path\", 180, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_HOME_DIRECTORY, FALSE, L\"Home directory\", 180, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_HOME_DIRECTORY_DRIVE, FALSE, L\"Home directory drive\", 80, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_LOGOFF_TIME, FALSE, L\"Logoff time\", 140, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_KICKOFF_TIME, FALSE, L\"Kickoff time\", 140, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_PASSWORD_CAN_CHANGE, FALSE, L\"Password can set\", 140, PH_ALIGN_LEFT, index++, 0);\n    PhAddTreeNewColumn(Context->TreeNewHandle, PH_USER_LIST_COLUMN_PASSWORD_MUST_CHANGE, FALSE, L\"Password must set\", 140, PH_ALIGN_LEFT, index++, 0);\n\n    TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);\n    //TreeNew_SetTriState(Context->TreeNewHandle, FALSE);\n\n    PhpUserListLoadSettingsTreeList(Context);\n}\n\n_Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PhpUserListSearchControlCallback(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_USER_LIST_CONTEXT context = Context;\n\n    assert(context);\n\n    context->SearchMatchHandle = MatchHandle;\n\n    PhApplyTreeNewFilters(&context->FilterSupport);\n}\n\nINT_PTR CALLBACK PhpUserListDlgProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_USER_LIST_CONTEXT context;\n\n    if (uMsg == WM_INITDIALOG)\n    {\n        context = (PPH_USER_LIST_CONTEXT)lParam;\n        PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);\n    }\n    else\n    {\n        context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n    }\n\n    if (!context)\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            context->WindowHandle = hwndDlg;\n            context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_TREELIST);\n            context->MessageHandle = GetDlgItem(hwndDlg, IDC_MESSAGE);\n            context->SearchWindowHandle = GetDlgItem(hwndDlg, IDC_FILTER);\n\n            PhSetApplicationWindowIcon(hwndDlg);\n            PhRegisterDialog(hwndDlg);\n            PhCreateSearchControl(\n                hwndDlg,\n                context->SearchWindowHandle,\n                L\"Search Users\",\n                PhpUserListSearchControlCallback,\n                context\n                );\n\n            PhpInitializeUserListTree(context);\n\n            PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);\n            PhAddLayoutItem(&context->LayoutManager, context->SearchWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);\n            PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL);\n            PhAddLayoutItem(&context->LayoutManager, context->MessageHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);\n\n            context->MinimumSize.left = 0;\n            context->MinimumSize.top = 0;\n            context->MinimumSize.right = 300;\n            context->MinimumSize.bottom = 100;\n            MapDialogRect(hwndDlg, &context->MinimumSize);\n\n            if (PhValidWindowPlacementFromSetting(SETTING_USER_LIST_WINDOW_POSITION))\n                PhLoadWindowPlacementFromSetting(SETTING_USER_LIST_WINDOW_POSITION, SETTING_USER_LIST_WINDOW_SIZE, hwndDlg);\n            else\n                PhCenterWindow(hwndDlg, context->ParentWindowHandle);\n\n            PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL);\n\n            PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);\n\n            PhpUserListRefresh(context);\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);\n\n            PhSaveWindowPlacementToSetting(SETTING_USER_LIST_WINDOW_POSITION, SETTING_USER_LIST_WINDOW_SIZE, hwndDlg);\n\n            PhUnregisterWindowCallback(hwndDlg);\n\n            PhDeleteLayoutManager(&context->LayoutManager);\n\n            PhpUserListSaveSettingsTreeList(context);\n\n            PhpDeleteUserListTree(context);\n            PhFree(context);\n\n            PostQuitMessage(0);\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n                {\n                case IDC_REFRESH:\n                    PhpUserListRefresh(context);\n                    break;\n                case IDCANCEL:\n                    DestroyWindow(hwndDlg);\n                    break;\n                }\n        }\n        break;\n    case WM_DPICHANGED:\n        {\n            PhLayoutManagerUpdate(&context->LayoutManager, LOWORD(wParam));\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhLayoutManagerLayout(&context->LayoutManager);\n        }\n        break;\n    case WM_SIZING:\n        {\n            PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpUserListDialogThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    HWND windowHandle;\n    BOOL result;\n    MSG message;\n    PH_AUTO_POOL autoPool;\n\n    PhInitializeAutoPool(&autoPool);\n\n    windowHandle = PhCreateDialog(\n        PhInstanceHandle,\n        MAKEINTRESOURCE(IDD_USRLIST),\n        NULL,\n        PhpUserListDlgProc,\n        Parameter\n        );\n\n    ShowWindow(windowHandle, SW_SHOW);\n    SetForegroundWindow(windowHandle);\n\n    while (result = GetMessage(&message, NULL, 0, 0))\n    {\n        if (result == INT_ERROR)\n            break;\n\n        if (!IsDialogMessage(windowHandle, &message))\n        {\n            TranslateMessage(&message);\n            DispatchMessage(&message);\n        }\n\n        PhDrainAutoPool(&autoPool);\n    }\n\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhShowUserListDialog(\n    _In_ HWND ParentWindowHandle\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPH_USER_LIST_CONTEXT context;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"secur32.dll\"))\n        {\n            LsaFreeReturnBuffer_I = PhGetDllBaseProcedureAddress(baseAddress, \"LsaFreeReturnBuffer\", 0);\n            LsaEnumerateLogonSessions_I = PhGetDllBaseProcedureAddress(baseAddress, \"LsaEnumerateLogonSessions\", 0);\n            LsaGetLogonSessionData_I = PhGetDllBaseProcedureAddress(baseAddress, \"LsaGetLogonSessionData\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!LsaFreeReturnBuffer_I || !LsaEnumerateLogonSessions_I || !LsaGetLogonSessionData_I)\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to locate routines.\", STATUS_NOINTERFACE, 0);\n        return;\n    }\n\n    context = PhAllocateZero(sizeof(PH_USER_LIST_CONTEXT));\n    context->ParentWindowHandle = ParentWindowHandle;\n\n    if (!NT_SUCCESS(PhCreateThread2(PhpUserListDialogThreadStart, context)))\n    {\n        PhShowStatus(ParentWindowHandle, L\"Unable to create the window.\", 0, ERROR_OUTOFMEMORY);\n        PhFree(context);\n    }\n}\n"
  },
  {
    "path": "SystemInformer/version.rc",
    "content": "﻿// Microsoft Visual C++ generated resource script.\n//\n#pragma code_page(65001)\n\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"winres.h\"\n#include \"include/phappres.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// English (United States) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE\nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE\nBEGIN\n    \"#include \"\"winres.h\"\"\\r\\n\"\n    \"#include \"\"include/phappres.h\"\"\\0\"\nEND\n\n3 TEXTINCLUDE\nBEGIN\n    \"\\r\\n\"\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION PHAPP_VERSION_NUMBER\n PRODUCTVERSION PHAPP_VERSION_NUMBER\n FILEFLAGSMASK 0x3fL\n#ifdef _DEBUG\n FILEFLAGS 0x1L\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS 0x40004L\n FILETYPE 0x1L\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904B0\"\n        BEGIN\n            VALUE \"CompanyName\", \"Winsider Seminars & Solutions, Inc.\"\n            VALUE \"FileDescription\", \"System Informer\"\n            VALUE \"FileVersion\", PHAPP_VERSION_STRING\n            VALUE \"InternalName\", \"System Informer\"\n            VALUE \"LegalCopyright\", \"Copyright (c) Winsider Seminars & Solutions, Inc.  All rights reserved.\"\n            VALUE \"OriginalFilename\", \"System Informer.exe\"\n            VALUE \"ProductName\", \"System Informer\"\n            VALUE \"ProductVersion\", PHAPP_VERSION_STRING\n            VALUE \"Comments\", PHAPP_VERSION_COMMIT\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x0409, 0x04b0\n    END\nEND\n\n#endif    // English (United States) resources\n/////////////////////////////////////////////////////////////////////////////\n\n"
  },
  {
    "path": "SystemInformer.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n\nThis file is part of System Informer.\n\nAuthors:\n\n    jxy-s   2024\n-->\n\n<!-- Debugger Visualizers -->\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n\n    <!-- PH_STRING -->\n    <Type Name=\"_PH_STRING\">\n        <DisplayString>{Buffer,[Length / 2]su}</DisplayString>\n        <Expand>\n            <Item Name=\"[string]\" ExcludeView=\"simple\">Buffer,[Length / 2]su</Item>\n            <Item Name=\"[bytes]\">Length</Item>\n            <Item Name=\"[length]\">Length / 2</Item>\n            <Item Name=\"[real-length]\">wcslen(Buffer)</Item>\n        </Expand>\n    </Type>\n\n    <!-- PH_STRINGREF -->\n    <Type Name=\"_PH_STRINGREF\">\n        <DisplayString>{Buffer,[Length / 2]su}</DisplayString>\n        <Expand>\n            <Item Name=\"[string]\" ExcludeView=\"simple\">Buffer,[Length / 2]su</Item>\n            <Item Name=\"[bytes]\">Length</Item>\n            <Item Name=\"[length]\">Length / 2</Item>\n            <Item Name=\"[real-length]\">wcslen(Buffer)</Item>\n        </Expand>\n    </Type>\n\n    <!-- PH_LIST -->\n    <Type Name=\"_PH_LIST\">\n        <DisplayString>{{size={Count}}}</DisplayString>\n        <Expand>\n            <Item Name=\"[size]\" ExcludeView=\"simple\">Count</Item>\n            <Item Name=\"[capacity]\" ExcludeView=\"simple\">AllocatedCount</Item>\n            <ArrayItems>\n                <Size>Count</Size>\n                <ValuePointer>Items</ValuePointer>\n            </ArrayItems>\n        </Expand>\n    </Type>\n\n</AutoVisualizer>"
  },
  {
    "path": "SystemInformer.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.12.35527.113 d17.12\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SystemInformer\", \"SystemInformer\\SystemInformer.vcxproj\", \"{0271DD27-6707-4290-8DFE-285702B7115D}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17} = {477D0215-F252-41A1-874B-F27E3EA1ED17}\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0} = {F1757430-8EEE-49DF-A5F1-0999A53BB4A0}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"phlib\", \"phlib\\phlib.vcxproj\", \"{477D0215-F252-41A1-874B-F27E3EA1ED17}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0} = {F1757430-8EEE-49DF-A5F1-0999A53BB4A0}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"peview\", \"tools\\peview\\peview.vcxproj\", \"{72C124A2-3C80-41C6-ABA1-C4948B713204}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"kphlib\", \"kphlib\\kphlib_um.vcxproj\", \"{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|ARM64 = Debug|ARM64\n\t\tDebug|Win32 = Debug|Win32\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|ARM64 = Release|ARM64\n\t\tRelease|Win32 = Release|Win32\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Debug|ARM64.Deploy.0 = Debug|ARM64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.Deploy.0 = Debug|Win32\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.Build.0 = Debug|x64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Release|ARM64.Deploy.0 = Release|ARM64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.Build.0 = Release|Win32\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.Deploy.0 = Release|Win32\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.ActiveCfg = Release|x64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.Build.0 = Release|x64\n\t\t{0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.Deploy.0 = Release|x64\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.Build.0 = Debug|x64\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.Build.0 = Release|Win32\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.ActiveCfg = Release|x64\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.Build.0 = Release|x64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|ARM64.Deploy.0 = Debug|ARM64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.Deploy.0 = Debug|Win32\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.Build.0 = Debug|x64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|ARM64.Deploy.0 = Release|ARM64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.Build.0 = Release|Win32\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.Deploy.0 = Release|Win32\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.ActiveCfg = Release|x64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.Build.0 = Release|x64\n\t\t{72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.Deploy.0 = Release|x64\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Debug|x64.Build.0 = Debug|x64\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Release|Win32.Build.0 = Release|Win32\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Release|x64.ActiveCfg = Release|x64\n\t\t{F1757430-8EEE-49DF-A5F1-0999A53BB4A0}.Release|x64.Build.0 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {096726E0-A447-47E3-8E9C-3F2B2C695CFC}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "SystemInformer.slnx",
    "content": "<Solution>\n  <Configurations>\n    <Platform Name=\"ARM64\" />\n    <Platform Name=\"Win32\" />\n    <Platform Name=\"x64\" />\n  </Configurations>\n  <Project Path=\"kphlib/kphlib_um.vcxproj\" Id=\"f1757430-8eee-49df-a5f1-0999a53bb4a0\" />\n  <Project Path=\"phlib/phlib.vcxproj\" Id=\"477d0215-f252-41a1-874b-f27e3ea1ed17\">\n    <BuildDependency Project=\"kphlib/kphlib_um.vcxproj\" />\n  </Project>\n  <Project Path=\"SystemInformer/SystemInformer.vcxproj\" Id=\"0271dd27-6707-4290-8dfe-285702b7115d\">\n    <BuildDependency Project=\"kphlib/kphlib_um.vcxproj\" />\n    <BuildDependency Project=\"phlib/phlib.vcxproj\" />\n  </Project>\n  <Project Path=\"tools/peview/peview.vcxproj\" Id=\"72c124a2-3c80-41c6-aba1-c4948b713204\" />\n</Solution>\n"
  },
  {
    "path": "build/KSystemInformer.ddf",
    "content": ";\n; Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n;\n; This file is part of System Informer.\n;\n; Authors:\n;\n;     jxy-s   2022\n;\n\n.OPTION EXPLICIT\n.Set CabinetFileCountThreshold=0\n.Set FolderFileCountThreshold=0\n.Set FolderSizeThreshold=0\n.Set MaxCabinetSize=0\n.Set MaxDiskFileCount=0\n.Set MaxDiskSize=0\n.Set CompressionType=MSZIP\n.Set Cabinet=on\n.Set Compress=on\n.Set CabinetNameTemplate=KSystemInformer.cab\n\n.Set DestinationDir=x64\nKSystemInformer.inf\nRelease64\\systeminformer.sys\nRelease64\\systeminformer.pdb\nRelease64\\ksi.dll\nRelease64\\ksi.pdb\n\n.Set DestinationDir=arm64\nKSystemInformer.inf\nReleaseARM64\\systeminformer.sys\nReleaseARM64\\systeminformer.pdb\nReleaseARM64\\ksi.dll\nReleaseARM64\\ksi.pdb\n"
  },
  {
    "path": "build/README.md",
    "content": "# Building System Informer\n\nGeneral rule of thumb is to run `build_init.cmd` then `build_release.cmd` after cloning the repo.\nAfter running `build_init.cmd` you generally don't need to run it again unless there are updates\nto the tools or third party libraries. If you're having trouble, when in doubt, run\n`build_init.cmd`. You may also build the solutions directly in Visual Studio.\n\n## Errors, Problems, Gotchas\n\nThis section contains common errors, problems, and gotchas when building System Informer.\nIf you're having trouble building then the information here is likely to resolve your problem.\n\n### LINK : fatal error C1047 (thirdparty.lib)\n\nTL;DR - run `build_thirdparty.cmd`\n\nThis error occurs because `thirdparty.lib` was built using a different compiler than the one\nin the environment. To resolve this in your environment run `build_thirdparty.cmd`.\n\n### Built plugins not loading with kernel driver enabled\n\nIt is possible to load built plugins with the driver enabled, but there is an intentional security\nmitigation to protect the driver from abuse. Please refer to the\n[kernel driver readme](../KSystemInformer/README.md) for more information. You may also disable\nthe advanced setting for image load denial, but access to the driver will be restricted with\nunsigned plugins loaded.\n"
  },
  {
    "path": "build/build_clean.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nif not exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n    echo CustomBuildTool.exe not found. Run build\\build_init.cmd first.\n    exit /b 1\n)\n\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-cleanup\"\n\npause\n"
  },
  {
    "path": "build/build_cmake.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nset \"TIB=false\"\nif \"%GITHUB_ACTIONS%\"==\"true\" (\n    set \"TIB=true\"\n) else if \"%TF_BUILD%\"==\"true\" (\n    set \"TIB=true\"\n)\n\nset GENERATOR=%~1\nset CONFIG=%~2\nset TOOLCHAIN=%~3\nset ACTION=%~4\nset TOOLCHAIN_FILE=\nset BUILD_DIR=\n\nfor /f \"usebackq tokens=*\" %%a in (`call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath`) do (\n   set \"VSINSTALLPATH=%%a\"\n)\n\nif not defined VSINSTALLPATH (\n   echo No Visual Studio installation detected.\n   goto end\n)\n\nif /i \"%CONFIG%\"==\"Debug\" (\n    set BUILD_DIR=build-debug\n) else if /i \"%CONFIG%\"==\"Release\" (\n    set BUILD_DIR=build-release\n) else (\n    echo Error: Unsupported configuration: %CONFIG%\n    echo Supported configurations: Debug, Release\n    set ERRORLEVEL=1\n    goto end\n)\n\nif /i \"%TOOLCHAIN%\"==\"msvc-x86\" (\n    set PLATFORM=Win32\n    set VCVARS_ARCH=amd64_x86\n    set BUILD_DIR=\"%CD%\\%BUILD_DIR%-msvc-32\"\n    set TOOLCHAIN_FILE=\"%CD%\\cmake\\toolchain\\msvc-x86.cmake\"\n) else if /i \"%TOOLCHAIN%\"==\"msvc-amd64\" (\n    set PLATFORM=x64\n    set VCVARS_ARCH=amd64\n    set BUILD_DIR=\"%CD%\\%BUILD_DIR%-msvc-64\"\n    set TOOLCHAIN_FILE=\"%CD%\\cmake\\toolchain\\msvc-amd64.cmake\"\n) else if /i \"%TOOLCHAIN%\"==\"msvc-arm64\" (\n    set PLATFORM=ARM64\n    set VCVARS_ARCH=amd64_arm64\n    set BUILD_DIR=\"%CD%\\%BUILD_DIR%-msvc-arm64\"\n    set TOOLCHAIN_FILE=\"%CD%\\cmake\\toolchain\\msvc-arm64.cmake\"\n) else if /i \"%TOOLCHAIN%\"==\"clang-msvc-x86\" (\n    set PLATFORM=Win32\n    set VCVARS_ARCH=amd64_x86\n    set BUILD_DIR=\"%CD%\\%BUILD_DIR%-clang-msvc-32\"\n    set TOOLCHAIN_FILE=\"%CD%\\cmake\\toolchain\\clang-msvc-x86.cmake\"\n) else if /i \"%TOOLCHAIN%\"==\"clang-msvc-amd64\" (\n    set PLATFORM=x64\n    set VCVARS_ARCH=amd64\n    set BUILD_DIR=\"%CD%\\%BUILD_DIR%-clang-msvc-64\"\n    set TOOLCHAIN_FILE=\"%CD%\\cmake\\toolchain\\clang-msvc-amd64.cmake\"\n) else if /i \"%TOOLCHAIN%\"==\"clang-msvc-arm64\" (\n    set PLATFORM=ARM64\n    set VCVARS_ARCH=amd64_arm64\n    set BUILD_DIR=\"%CD%\\%BUILD_DIR%-clang-msvc-arm64\"\n    set TOOLCHAIN_FILE=\"%CD%\\cmake\\toolchain\\clang-msvc-arm64.cmake\"\n) else (\n    echo Error: Unsupported toolchain: %TOOLCHAIN%\n    echo Supported toolchains: msvc-x86, msvc-amd64, msvc-arm64, clang-msvc-x86, clang-msvc-amd64, clang-msvc-arm64\n    set ERRORLEVEL=1\n    goto end\n)\n\nset SOURCE_DIR=\"%CD%\"\n\necho ===============================================\necho System Informer CMake Build Script\necho ===============================================\necho Action:        %ACTION%\necho Generator:     %GENERATOR%\necho Configuration: %CONFIG%\necho Platform:      %PLATFORM%\necho Toolchain:     %TOOLCHAIN%\necho VCVARS:        %VCVARS_ARCH%\necho Source:        %SOURCE_DIR%\necho Build:         %BUILD_DIR%\necho ===============================================\n\nset CMAKE_GEN_OPTS=\nif /i \"%GENERATOR%\"==\"Ninja\" (\n    set CMAKE_GEN_OPTS=-DCMAKE_BUILD_TYPE=%CONFIG%\n)\n\nset CMAKE_BUILD_OPTS=\nif not \"%GENERATOR:Visual Studio=%\"==\"%GENERATOR%\" (\n    set CMAKE_BUILD_OPTS=-- /m /p:Platform=%PLATFORM% -terminalLogger:auto\n)\n\nif /i \"%ACTION%\"==\"clean\" (\n    if exist \"%BUILD_DIR%\" rmdir /s /q \"%BUILD_DIR%\"\n) else if /i \"%ACTION%\"==\"generate\" (\n    echo Setting up Visual Studio environment for %VCVARS_ARCH%...\n    call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" %VCVARS_ARCH%\n    if %ERRORLEVEL% neq 0 goto end\n    if not exist \"%BUILD_DIR%\" mkdir \"%BUILD_DIR%\"\n    cmake -G \"%GENERATOR%\" -S %SOURCE_DIR% -B %BUILD_DIR% ^\n        --toolchain %TOOLCHAIN_FILE% ^\n        -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ^\n        -DSI_WITH_CORE=ON ^\n        -DSI_WITH_PLUGINS=ON ^\n        %CMAKE_GEN_OPTS%\n    if %ERRORLEVEL% neq 0 goto end\n) else if /i \"%ACTION%\"==\"build\" (\n    echo Setting up Visual Studio environment for %VCVARS_ARCH%...\n    call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" %VCVARS_ARCH%\n    if %ERRORLEVEL% neq 0 goto end\n    if \"%NINJA_STATUS%\"==\"\" (\n        set \"NINJA_STATUS=[%%p][%%w][%%f/%%t][%%o/s] \"\n    )\n    cmake --build %BUILD_DIR% --config %CONFIG% %CMAKE_BUILD_OPTS%\n    if %ERRORLEVEL% neq 0 goto end\n) else (\n    echo Error: Invalid action \"%ACTION%\". Use \"generate\", \"build\", or \"clean\".\n    set ERRORLEVEL=1\n)\n\n:end\nif \"%TIB%\"==\"false\" pause\n"
  },
  {
    "path": "build/build_compile_commands.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nfor /f \"usebackq tokens=*\" %%a in (`call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath`) do (\n   set \"VSINSTALLPATH=%%a\"\n)\n\nif exist \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" (\n    if \"%PROCESSOR_ARCHITECTURE%\"==\"ARM64\" (\n       call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" arm64\n       dotnet publish tools\\CompileCommandsJson\\CompileCommandsJson.sln -c Release /p:PublishProfile=Properties\\PublishProfiles\\arm64.pubxml\n       set COMPILE_COMMANDS_LOGGER=tools\\CompileCommandsJson\\bin\\Release\\arm64\\CompileCommandsJson.dll\n       set BUILD_PLATFORM=ARM64\n    ) else (\n       call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" amd64\n       dotnet publish tools\\CompileCommandsJson\\CompileCommandsJson.sln -c Release /p:PublishProfile=Properties\\PublishProfiles\\amd64.pubxml\n       set COMPILE_COMMANDS_LOGGER=tools\\CompileCommandsJson\\bin\\Release\\amd64\\CompileCommandsJson.dll\n       set BUILD_PLATFORM=x64\n    )\n) else (\n   goto end\n)\n\nif not exist %COMPILE_COMMANDS_LOGGER% (\n    echo CompileCommandsJson.dll not found.\n    goto end\n)\n\nset BUILD_ARGS=-t:rebuild -p:Configuration=Debug;Platform=%BUILD_PLATFORM% -logger:%COMPILE_COMMANDS_LOGGER% -terminalLogger:auto\n\nmsbuild /m KSystemInformer\\KSystemInformer.sln %BUILD_ARGS%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\nmsbuild /m SystemInformer.sln %BUILD_ARGS%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\nmsbuild /m Plugins\\Plugins.sln %BUILD_ARGS%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\n:end\npause\n"
  },
  {
    "path": "build/build_debug.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nif not exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n    echo CustomBuildTool.exe not found. Run build\\build_init.cmd first.\n    exit /b 1\n)\n\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-debug\"\n\npause\n"
  },
  {
    "path": "build/build_devenv.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nif not exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n    echo CustomBuildTool.exe not found. Run build\\build_init.cmd first.\n    exit /b 1\n)\n\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"tools\\thirdparty\\thirdparty.sln /Rebuild Debug /Project thirdparty /projectconfig \"\"Debug|Win32\"\" \"\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"tools\\thirdparty\\thirdparty.sln /rebuild Debug /Project thirdparty /projectconfig \"\"Debug|x64\"\" \"\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"tools\\thirdparty\\thirdparty.sln /Rebuild Release /Project thirdparty /projectconfig \"\"Release|Win32\"\" \"\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"tools\\thirdparty\\thirdparty.sln /rebuild Release /Project thirdparty /projectconfig \"\"Release|x64\"\" \"\n\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"SystemInformer.sln /Rebuild \"\"Debug|Win32\"\" \"\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"SystemInformer.sln /Rebuild \"\"Debug|x64\"\" \"\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"SystemInformer.sln /Rebuild \"\"Release|Win32\"\" \"\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"SystemInformer.sln /Rebuild \"\"Release|x64\"\" \"\n\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"Plugins\\Plugins.sln /Rebuild \"\"Debug|Win32\"\" \"\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"Plugins\\Plugins.sln /Rebuild \"\"Debug|x64\"\" \"\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"Plugins\\Plugins.sln /Rebuild \"\"Release|Win32\"\" \"\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-devenv-build\" \"Plugins\\Plugins.sln /Rebuild \"\"Release|x64\"\" \"\n\npause\n"
  },
  {
    "path": "build/build_dyndata.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@setlocal enabledelayedexpansion\n@cd /d \"%~dp0\\..\\\"\n\nset localerror=1\n\nif \"%1\"==\"\" (\n   echo Usage: build_dyndata.cmd [BUILD_OUTPUT_PATH]\n   goto end\n)\n\nif exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n   \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-dyndata\" \"%1\"\n   set localerror=!errorlevel!\n) else (\n   echo CustomBuildTool.exe not found in tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE% folder.\n)\n\n:end\nexit /B %localerror%"
  },
  {
    "path": "build/build_header.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nset BUILD_TOOL=\"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\"\n\nif not exist %BUILD_TOOL% (\n    echo CustomBuildTool.exe not found. Run build\\build_init.cmd first.\n    exit /b 1\n)\n\nstart /B /W \"\" %BUILD_TOOL% \"-phnt_headers_gen\"\n\npause\n"
  },
  {
    "path": "build/build_init.cmd",
    "content": "@echo off\n@setlocal enableextensions\n\ncall \"%~dp0build_thirdparty.cmd\" INIT\ncall \"%~dp0build_tools.cmd\" INIT\n"
  },
  {
    "path": "build/build_msix.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nif not exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n    echo CustomBuildTool.exe not found. Run build\\build_init.cmd first.\n    exit /b 1\n)\n\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-msix-build\"\n\npause\n"
  },
  {
    "path": "build/build_release.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nif not exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n    echo CustomBuildTool.exe not found. Run build\\build_init.cmd first.\n    exit /b 1\n)\n\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-release\"\n\npause\n"
  },
  {
    "path": "build/build_sdk.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nset BUILD_TOOL=\"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\"\n\nif not exist %BUILD_TOOL% (\n    echo CustomBuildTool.exe not found. Run build\\build_init.cmd first.\n    exit /b 1\n)\n\nstart /B /W \"\" %BUILD_TOOL% \"-sdk\" \"-Debug\" \"-Win32\" \"-verbose\"\nstart /B /W \"\" %BUILD_TOOL% \"-sdk\" \"-Debug\" \"-x64\" \"-verbose\"\nstart /B /W \"\" %BUILD_TOOL% \"-sdk\" \"-Debug\" \"-arm64\" \"-verbose\"\n\nstart /B /W \"\" %BUILD_TOOL% \"-sdk\" \"-Release\" \"-Win32\" \"-verbose\"\nstart /B /W \"\" %BUILD_TOOL% \"-sdk\" \"-Release\" \"-x64\" \"-verbose\"\nstart /B /W \"\" %BUILD_TOOL% \"-sdk\" \"-Release\" \"-arm64\" \"-verbose\"\n\npause\n"
  },
  {
    "path": "build/build_sdk_rebuild.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nif not exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\"(\n    echo CustomBuildTool.exe not found. Run build\\build_init.cmd first.\n    exit /b 1\n)\n\nstart /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-cleansdk\"\n\npause\n"
  },
  {
    "path": "build/build_thirdparty.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nREM Check if an argument is provided and if it is \"INIT\"\nset \"IS_INIT=false\"\nif \"%1\"==\"INIT\" (\n    set \"IS_INIT=true\"\n)\n\nREM Check if terminal logging is supported\nset \"TLG=auto\"\nif \"%GITHUB_ACTIONS%\"==\"true\" (\n    set \"TLG=off\"\n) else if \"%TF_BUILD%\"==\"true\" (\n    set \"TLG=off\"\n)\n\nfor /f \"usebackq tokens=*\" %%a in (`call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath`) do (\n   set \"VSINSTALLPATH=%%a\"\n)\n\nif not defined VSINSTALLPATH if defined WindowsSdkDir (\n   set \"VSINSTALLPATH=%WindowsSdkDir%\"\n)\n\nif not defined VSINSTALLPATH if defined EWDK_ROOT (\n   set \"VSINSTALLPATH=%EWDK_ROOT%\"\n)\n\nif not defined VSINSTALLPATH (\n   echo No Visual Studio installation detected.\n   goto end\n)\n\nset \"VS_ARM64_SUPPORT=false\"\nfor /f \"usebackq tokens=*\" %%a in (`call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -prerelease -products * -requires \"Microsoft.VisualStudio.Component.VC.Tools.ARM64\" -property installationPath`) do (\n   set \"VS_ARM64_SUPPORT=true\"\n)\n\nif \"%PROCESSOR_ARCHITECTURE%\"==\"ARM64\" (\n   call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" arm64\n) else (\n   call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" amd64\n)\n\nif exist \"tools\\thirdparty\\bin\" (\n   rmdir /S /Q \"tools\\thirdparty\\bin\"\n)\nif exist \"tools\\thirdparty\\obj\" (\n   rmdir /S /Q \"tools\\thirdparty\\obj\"\n)\n\necho:\n\necho Building thirdparty.sln [Debug32]\nmsbuild /m tools\\thirdparty\\thirdparty.sln -property:Configuration=Debug -property:Platform=x86 -terminalLogger:%TLG%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\necho Building thirdparty.sln [Release32]\nmsbuild /m tools\\thirdparty\\thirdparty.sln -property:Configuration=Release -property:Platform=x86 -terminalLogger:%TLG%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\necho Building thirdparty.sln [Debug64]\nmsbuild /m tools\\thirdparty\\thirdparty.sln -property:Configuration=Debug -property:Platform=x64 -terminalLogger:%TLG%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\necho Building thirdparty.sln [Release64]\nmsbuild /m tools\\thirdparty\\thirdparty.sln -property:Configuration=Release -property:Platform=x64 -terminalLogger:%TLG%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\nif \"%VS_ARM64_SUPPORT%\"==\"true\" (\n   echo Building thirdparty.sln [DebugARM64]\n   msbuild /m tools\\thirdparty\\thirdparty.sln -property:Configuration=Debug -property:Platform=ARM64 -terminalLogger:%TLG%\n   if %ERRORLEVEL% neq 0 goto end\n   echo:\n\n   echo Building thirdparty.sln [ReleaseARM64]\n   msbuild /m tools\\thirdparty\\thirdparty.sln -property:Configuration=Release -property:Platform=ARM64 -terminalLogger:%TLG%\n   if %ERRORLEVEL% neq 0 goto end\n   echo:\n)\n\n:end\n\nREM If IS_INIT is not provided, print a message and exit\nif /i \"%IS_INIT%\"==\"false\" (\n   REM Avoid pause in non-interactive runs (stdin redirected).\n   set \"STDIN_REDIRECTED=False\"\n   for /f %%i in ('powershell -NoProfile -Command \"[Console]::IsInputRedirected\"') do set \"STDIN_REDIRECTED=%%i\"\n   REM Pause only for interactive console sessions.\n   if /i not \"%STDIN_REDIRECTED%\"==\"True\" pause\n) else (\n   REM INIT mode is used by scripts, so return immediately.\n   exit /b 0\n)\n"
  },
  {
    "path": "build/build_tools.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nset \"TIB=false\"\nif \"%GITHUB_ACTIONS%\"==\"true\" (\n    set \"TIB=true\"\n) else if \"%TF_BUILD%\"==\"true\" (\n    set \"TIB=true\"\n)\n\nfor /f \"usebackq tokens=*\" %%a in (`call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath`) do (\n   set \"VSINSTALLPATH=%%a\"\n)\n\nif not defined VSINSTALLPATH if defined WindowsSdkDir (\n   set \"VSINSTALLPATH=%WindowsSdkDir%\"\n)\n\nif not defined VSINSTALLPATH if defined EWDK_ROOT (\n   set \"VSINSTALLPATH=%EWDK_ROOT%\"\n)\n\nif not defined VSINSTALLPATH (\n   echo No Visual Studio installation detected.\n   goto end\n)\n\n:: Pre-cleanup (required since dotnet doesn't cleanup)\nif exist \"tools\\CustomBuildTool\\bin\\\" (\n   rmdir /S /Q \"tools\\CustomBuildTool\\bin\\\"\n)\nif exist \"tools\\CustomBuildTool\\obj\" (\n   rmdir /S /Q \"tools\\CustomBuildTool\\obj\"\n)\nif exist \"tools\\CustomBuildTool\\.vs\" (\n   rmdir /S /Q \"tools\\CustomBuildTool\\.vs\"\n)\n\nif exist \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" (\n    if \"%PROCESSOR_ARCHITECTURE%\"==\"ARM64\" (\n       call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" arm64\n       dotnet publish tools\\CustomBuildTool\\CustomBuildTool.sln -c Release /p:PublishProfile=Properties\\PublishProfiles\\arm64.pubxml /p:ContinuousIntegrationBuild=%TIB%\n    ) else (\n       call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" amd64\n       dotnet publish tools\\CustomBuildTool\\CustomBuildTool.sln -c Release /p:PublishProfile=Properties\\PublishProfiles\\amd64.pubxml /p:ContinuousIntegrationBuild=%TIB%\n    )\n) else (\n    goto end\n)\n\n:: Post-cleanup (required since dotnet doesn't cleanup)\nif exist \"tools\\CustomBuildTool\\bin\\ARM64\" (\n   rmdir /S /Q \"tools\\CustomBuildTool\\bin\\ARM64\"\n)\nif exist \"tools\\CustomBuildTool\\bin\\x64\" (\n   rmdir /S /Q \"tools\\CustomBuildTool\\bin\\x64\"\n)\nif exist \"tools\\CustomBuildTool\\bin\\Release\\net9.0-windows-arm64\" (\n   rmdir /S /Q \"tools\\CustomBuildTool\\bin\\Release\\net9.0-windows-arm64\"\n)\nif exist \"tools\\CustomBuildTool\\bin\\Release\\net9.0-windows-x64\" (\n   rmdir /S /Q \"tools\\CustomBuildTool\\bin\\Release\\net9.0-windows-x64\"\n)\nif exist \"tools\\CustomBuildTool\\obj\" (\n   rmdir /S /Q \"tools\\CustomBuildTool\\obj\"\n)\nif exist \"tools\\CustomBuildTool\\.vs\" (\n   rmdir /S /Q \"tools\\CustomBuildTool\\.vs\"\n)\n\nif exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n   echo:\n   start /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-write-tools-id\"\n   echo:\n) else (\n   echo:\n   echo CustomBuildTool build failed.\n   echo:\n)\n\n:end\n\nif \"%TIB%\"==\"false\" (\n   REM Avoid pause in non-interactive runs (stdin redirected).\n   set \"STDIN_REDIRECTED=False\"\n   for /f %%i in ('powershell -NoProfile -Command \"[Console]::IsInputRedirected\"') do set \"STDIN_REDIRECTED=%%i\"\n   REM Pause only for interactive console sessions.\n   if /i not \"%STDIN_REDIRECTED%\"==\"True\" pause\n)\n"
  },
  {
    "path": "build/build_verbose.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nREM Check if terminal logging is supported\nset \"TLG=auto\"\nif \"%GITHUB_ACTIONS%\"==\"true\" (\n    set \"TLG=off\"\n) else if \"%TF_BUILD%\"==\"true\" (\n    set \"TLG=off\"\n)\n\nREM Check if diagnostic is supported\nset \"TLV=normal\"\nif not \"%~1\"==\"\" (\n    set \"TLV=diagnostic\"\n)\n\nfor /f \"usebackq tokens=*\" %%a in (`call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath`) do (\n   set \"VSINSTALLPATH=%%a\"\n)\n\nif not defined VSINSTALLPATH (\n   echo No Visual Studio installation detected.\n   goto end\n)\n\nset \"VS_ARM64_SUPPORT=false\"\nfor /f \"usebackq tokens=*\" %%a in (`call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -prerelease -products * -requires \"Microsoft.VisualStudio.Component.VC.Tools.ARM64\" -property installationPath`) do (\n   set \"VS_ARM64_SUPPORT=true\"\n)\n\nif exist \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" (\n   if \"%VS_ARM64_SUPPORT%\"==\"true\" (\n      call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" amd64_arm64\n   ) else (\n      call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" amd64\n   )\n   if %ERRORLEVEL% neq 0 goto end\n) else (\n   echo Warning: vcvarsall.bat not found and compilation environment variables are not defined.\n   echo The build may fail if the environment is not properly initialized.\n   goto end\n)\n\necho:\n\necho Building thirdparty.sln [Debug32]\nmsbuild /m SystemInformer.sln -t:rebuild -p:Configuration=Debug -p:Platform=Win32 -verbosity:%TLV% -terminalLogger:%TLG%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\necho Building thirdparty.sln [Debug64]\nmsbuild /m SystemInformer.sln -t:rebuild -p:Configuration=Debug -p:Platform=x64 -verbosity:%TLV% -terminalLogger:%TLG%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\necho Building thirdparty.sln [Release32]\nmsbuild /m Plugins\\Plugins.sln -t:rebuild -p:Configuration=Debug -p:Platform=Win32 -verbosity:%TLV% -terminalLogger:%TLG%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\necho Building thirdparty.sln [Release64]\nmsbuild /m Plugins\\Plugins.sln -t:rebuild -p:Configuration=Debug -p:Platform=x64 -verbosity:%TLV% -terminalLogger:%TLG%\nif %ERRORLEVEL% neq 0 goto end\necho:\n\nif \"%VS_ARM64_SUPPORT%\"==\"true\" (\n   echo Building thirdparty.sln [DebugARM64]\n   msbuild /m SystemInformer.sln -t:rebuild -p:Configuration=Debug -p:Platform=ARM64 -verbosity:%TLV% -terminalLogger:%TLG%\n   if %ERRORLEVEL% neq 0 goto end\n   echo:\n\n   echo Building thirdparty.sln [ReleaseARM64]\n   msbuild /m Plugins\\Plugins.sln -t:rebuild -p:Configuration=Debug -p:Platform=ARM64 -verbosity:%TLV% -terminalLogger:%TLG%\n   if %ERRORLEVEL% neq 0 goto end\n   echo:\n)\n\n:end\npause\n"
  },
  {
    "path": "build/build_zdriver.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nREM Check if terminal logging is supported\nset \"TLG=auto\"\nif \"%GITHUB_ACTIONS%\"==\"true\" (\n    set \"TLG=off\"\n) else if \"%TF_BUILD%\"==\"true\" (\n    set \"TLG=off\"\n)\n\nif not exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n    echo Build tool not found. Run build\\build_init.cmd first.\n    exit /b 1\n)\n\nset BUILD_CONFIGURATION=Debug\nset BUILD_TARGET=Build\nset PREFAST_ANALYSIS=\n\n:argloop\nif not \"%1\"==\"\" (\n    if \"%1\"==\"debug\" (\n        set BUILD_CONFIGURATION=Debug\n        shift\n        goto :argloop\n    )\n    if \"%1\"==\"release\" (\n        set BUILD_CONFIGURATION=Release\n        shift\n        goto :argloop\n    )\n    if \"%1\"==\"build\" (\n        set BUILD_TARGET=Build\n        shift\n        goto :argloop\n    )\n    if \"%1\"==\"rebuild\" (\n        set BUILD_TARGET=Rebuild\n        shift\n        goto :argloop\n    )\n    if \"%1\"==\"clean\" (\n        set BUILD_TARGET=Clean\n        shift\n        goto :argloop\n    )\n    if \"%1\"==\"prefast\" (\n        set PREFAST_ANALYSIS=-p:RunCodeAnalysis=true -p:CodeAnalysisTreatWarningsAsErrors=true\n        shift\n        goto :argloop\n    )\n    shift\n    goto :argloop\n)\n\nfor /f \"usebackq tokens=*\" %%A in (`call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath`) do (\n    set VSINSTALLPATH=%%A\n)\n\nif not defined VSINSTALLPATH if defined WindowsSdkDir (\n   set \"VSINSTALLPATH=%WindowsSdkDir%\"\n)\n\nif not defined VSINSTALLPATH if defined EWDK_ROOT (\n   set \"VSINSTALLPATH=%EWDK_ROOT%\"\n)\n\nif not defined VSINSTALLPATH (\n    echo [-] Visual Studio not found\n    goto end\n)\n\nif exist \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" (\n   call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" amd64_arm64\n) else (\n   if not defined INCLUDE (\n      if not defined LIB (\n         echo Warning: vcvarsall.bat not found and compilation environment variables ^(INCLUDE/LIB^) are not defined.\n         echo The build may fail if the environment is not properly initialized.\n      )\n   )\n)\n\necho [+] Building... [WIN64] %BUILD_CONFIGURATION% %BUILD_TARGET% %PREFAST_ANALYSIS% %LEGACY_BUILD%\n\nmsbuild KSystemInformer\\KSystemInformer.sln -t:%BUILD_TARGET% -p:Configuration=%BUILD_CONFIGURATION%;Platform=x64 -maxCpuCount -terminalLogger:%TLG% -consoleLoggerParameters:Summary;Verbosity=minimal %PREFAST_ANALYSIS%\nif %ERRORLEVEL% neq 0 goto end\n\necho [+] Building... [ARM64] %BUILD_CONFIGURATION% %BUILD_TARGET% %PREFAST_ANALYSIS% %LEGACY_BUILD%\n\nmsbuild KSystemInformer\\KSystemInformer.sln -t:%BUILD_TARGET% -p:Configuration=%BUILD_CONFIGURATION%;Platform=ARM64 -maxCpuCount -terminalLogger:%TLG% -consoleLoggerParameters:Summary;Verbosity=minimal %PREFAST_ANALYSIS%\nif %ERRORLEVEL% neq 0 goto end\n\necho [+] Build Complete! %BUILD_CONFIGURATION% %BUILD_TARGET% %PREFAST_ANALYSIS% %LEGACY_BUILD%\n\n:end\npause\n"
  },
  {
    "path": "build/build_zdriver_cab.cmd",
    "content": "@echo off\n@setlocal enableextensions\n\nrmdir /q /s %~dp0\\output\\cab\ndel %~dp0\\output\\KSystemInformer.cab\n\ncall %~dp0\\build_zdriver.cmd release rebuild\nif %ERRORLEVEL% neq 0 (\n    echo [-] Build failed, CAB was not generated.\n    goto end\n)\n\nmkdir %~dp0\\output\\cab\n\n(robocopy %~dp0\\..\\KSystemInformer\\bin %~dp0\\output\\cab *.sys *.dll *.pdb /mir) ^& if %ERRORLEVEL% lss 8 set ERRORLEVEL = 0\nif %ERRORLEVEL% neq 0 (\n    echo [-] Failed to copy build artifacts to CAB directory.\n    goto end\n)\n\n(robocopy %~dp0\\..\\KSystemInformer %~dp0\\output\\cab KSystemInformer.inf) ^& if %ERRORLEVEL% lss 8 set ERRORLEVEL = 0\nif %ERRORLEVEL% neq 0 (\n    echo [-] Failed to copy INF to CAB directory.\n    goto end\n)\n\npushd %~dp0\\output\\cab\nmakecab /f %~dp0\\KSystemInformer.ddf\nif %ERRORLEVEL% neq 0 (\n    echo [-] Failed to generate CAB.\n    popd\n    goto end\n)\npopd\n\n(robocopy %~dp0\\output\\cab\\disk1 %~dp0\\output KSystemInformer.cab) ^& if %ERRORLEVEL% lss 8 set ERRORLEVEL = 0\nif %ERRORLEVEL% neq 0 (\n    echo [-] Failed to copy CAB to output folder.\n    goto end\n)\n\nrmdir /q /s %~dp0\\output\\cab\n\necho [+] CAB Complete!\n\necho [.] Preparing to sign CAB...\n\nfor /f \"usebackq tokens=*\" %%A in (`call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath`) do (\n    set VSINSTALLPATH=%%A\n)\n\nif not defined VSINSTALLPATH (\n    echo [-] Visual Studio not found\n    goto end\n)\n\nif exist \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" (\n   call \"%VSINSTALLPATH%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" amd64_arm64\n) else (\n    echo [-] Failed to set up build environment\n    goto end\n)\n\necho [.] Signing: %~dp0\\output\\KSystemInformer.cab\nsigntool sign /fd sha256 /n \"Winsider\" %~dp0\\output\\KSystemInformer.cab\nif %ERRORLEVEL% neq 0 goto end\n\necho [+] CAB Signed!\n\n:end\npause\n"
  },
  {
    "path": "build/build_zdriver_sdk.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nif \"%1\"==\"\" (\n   echo:\n   echo Usage: build_zdriver_sdk.cmd [FILE_PATH] [CONFIGURATION] [PLATFORM]\n   echo:\n   pause\n   goto end\n)\nif \"%2\"==\"\" (\n   echo:\n   echo Usage: build_zdriver_sdk.cmd [FILE_PATH] [CONFIGURATION] [PLATFORM]\n   echo:\n   pause\n   goto end\n)\nif \"%3\"==\"\" (\n   echo:\n   echo Usage: build_zdriver_sdk.cmd [FILE_PATH] [CONFIGURATION] [PLATFORM]\n   echo:\n   pause\n   goto end\n)\n\nif exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n    start /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-kphsign\" %1\n    if %ERRORLEVEL% neq 0 (\n        echo \"[CustomBuildTool] Failed to sign %1\"\n    )  \n    start /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-sdk\" \"-verbose\" %2 %3\n    if %ERRORLEVEL% neq 0 (\n        echo \"[CustomBuildTool] SDK Failed %2 %3\"\n    )\n) else (\n   echo CustomBuildTool.exe not found in tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE% folder.\n)\n\n:end\n"
  },
  {
    "path": "build/build_zsign.cmd",
    "content": "@echo off\n@setlocal enableextensions\n@cd /d \"%~dp0\\..\\\"\n\nif \"%1\"==\"\" (\n   echo:\n   echo Usage: build_zsign.cmd [FILE_PATH] [CONFIGURATION] [PLATFORM]\n   echo:\n   pause\n   goto end\n)\n\nif exist \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" (\n   echo:\n   start /B /W \"\" \"tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE%\\CustomBuildTool.exe\" \"-kphsign\" \"%1\"\n   echo:\n) else (\n   echo CustomBuildTool.exe not found in tools\\CustomBuildTool\\bin\\Release\\%PROCESSOR_ARCHITECTURE% folder.\n)\n\n:end\n"
  },
  {
    "path": "build/build_zwntapi.ps1",
    "content": "\nfunction InitializeScriptEnvironment()\n{\n    # Get script start time\n    $global:TimeStart = (Get-Date);\n    # Stop script execution after any errors.\n    $global:ErrorActionPreference = \"Stop\";\n}\n\nfunction CheckSolutionDirectory()\n{\n    # Check if the current directory contains the main solution\n    if (!(Test-Path \"SystemInformer.sln\"))\n    {\n        # Change root directory to the \\build\\internal\\ directory (where this script is located).\n        Set-Location $PSScriptRoot;\n\n        # Set the current location to the base repository directory.\n        Set-Location \"..\\\";\n\n        # Re-check if the current directory\n        if (!(Test-Path \"SystemInformer.sln\"))\n        {\n            Write-Host \"Unable to find project directory... Exiting.\" -ForegroundColor Red\n            exit 5\n        }\n    }\n}\n\nfunction GenerateZw()\n{\n    $BaseDirectory = \"phnt\\include\"\n    $OutputFile = \"ntzwapi.h\"\n    $Header = \"#ifndef _NTZWAPI_H`r`n#define _NTZWAPI_H`r`n`r`n// This file was automatically generated. Do not edit.`r`n`r`n\"\n    $Footer = \"#endif`r`n\"\n\n    $directoryInfo = Get-Item -Path \"..\"\n    while ($null -ne $directoryInfo.Parent -and $null -ne $directoryInfo.Parent.Parent) {\n        $directoryInfo = $directoryInfo.Parent\n        if (Test-Path -Path \"$($directoryInfo.FullName)\\$BaseDirectory\") {\n            Set-Location -Path $directoryInfo.FullName\n            break\n        }\n    }\n\n    $regex = New-Object System.Text.RegularExpressions.RegEx(\"NTSYSCALLAPI[\\w\\s_]*NTAPI\\s*(Nt(\\w)*)\\(.*?\\);\", [System.Text.RegularExpressions.RegexOptions]::Singleline)\n    $definitions = @()\n    \n    $files = Get-ChildItem -Path $BaseDirectory -Filter \"*.h\" -Exclude \"ntuser.h\" -Recurse\n    foreach ($file in $files) {\n        $text = Get-Content -Path $file.FullName -Raw\n\n        if ([String]::IsNullOrEmpty($text)) {\n            continue\n        }\n\n        $textmatches = $regex.Matches($text)\n    \n        foreach ($match in $textmatches)\n        {\n            $definitions += [PSCustomObject]@{\n                Name = $match.Groups[1].Value\n                Text = $match.Value\n                NameIndex = $match.Groups[1].Index - $match.Index\n            }\n        }\n    }\n    \n    $defs = $definitions | Sort-Object -Property Name -CaseSensitive -Unique\n\n    $fileName = New-Item -Name ($BaseDirectory + '\\\\' + $OutputFile) -ItemType File -Force\n    $fileStream = $fileName.OpenWrite()\n    $sw = [System.IO.StreamWriter]::new($fileStream)\n    $sw.Write($Header)\n\n    Write-Host \"Updating $($fileName)\"\n\n    foreach ($d in $defs) \n    {\n        Write-Host \"System service: $($d.Name)\"\n\n        $sw.Write($d.Text.Substring(0, $d.NameIndex) + \"Zw\" + $d.Text.Substring($d.NameIndex + 2) + \"`r`n`r`n\")\n    }\n\n    $sw.Write($Footer)\n    $sw.Dispose()\n    $fileStream.Dispose();\n}\n\n# Entry point\nInitializeScriptEnvironment;\n\n# Check the current directory\nCheckSolutionDirectory;\n\n# Update the ntzwapi.h exports\nGenerateZw;\n"
  },
  {
    "path": "cmake/commands.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nlist(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})\ninclude(tools)\ninclude(platform)\ninclude(tracewpp)\n\nset(SI_UM_CLANG_NO_DIAGNOSTICS\n    -Wno-c23-extensions\n    -Wno-incompatible-pointer-types\n    -Wno-missing-braces\n    -Wno-parentheses\n    -Wno-pointer-sign\n    -Wno-switch\n    -Wno-unused-but-set-variable\n    -Wno-unused-function\n    -Wno-unused-variable\n    -Wno-visibility\n    -Wno-defaulted-function-deleted\n    -Wno-class-conversion\n    -Wno-microsoft-explicit-constructor-call\n    -Wno-nontrivial-memaccess\n)\n\n#\n# Helper function for setting up a System Informer target\n#\nfunction(_si_set_target_defaults target)\n    set(options PLUGIN)\n    set(oneValueArgs TYPE)\n    set(multiValueArgs)\n    cmake_parse_arguments(PARSE_ARGV 0 arg \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\")\n\n    if(NOT arg_TYPE MATCHES \"^(UM|KM)(_LIB|_BIN)$\")\n        message(FATAL_ERROR \"Invalid target type: ${arg_TYPE}\")\n    endif()\n\n    target_link_options(${target} PRIVATE /NATVIS:${SI_ROOT}/SystemInformer.natvis)\n\n    if(NOT SI_OUTPUT_DIR STREQUAL \"\" AND NOT SI_OUTPUT_DIR STREQUAL \"OFF\")\n        if(arg_PLUGIN)\n            set_target_properties(${target} PROPERTIES\n                RUNTIME_OUTPUT_DIRECTORY \"${SI_OUTPUT_DIR}/$<CONFIG>${SI_PLATFORM_SHORT}/plugins\"\n                ARCHIVE_OUTPUT_DIRECTORY \"${SI_OUTPUT_DIR}/$<CONFIG>${SI_PLATFORM_SHORT}/plugins\"\n                PDB_OUTPUT_DIRECTORY \"${SI_OUTPUT_DIR}/$<CONFIG>${SI_PLATFORM_SHORT}/plugins\"\n            )\n        else()\n            set_target_properties(${target} PROPERTIES\n                RUNTIME_OUTPUT_DIRECTORY \"${SI_OUTPUT_DIR}/$<CONFIG>${SI_PLATFORM_SHORT}\"\n                ARCHIVE_OUTPUT_DIRECTORY \"${SI_OUTPUT_DIR}/$<CONFIG>${SI_PLATFORM_SHORT}\"\n                PDB_OUTPUT_DIRECTORY \"${SI_OUTPUT_DIR}/$<CONFIG>${SI_PLATFORM_SHORT}\"\n            )\n        endif()\n    endif()\n\n    get_target_property(_target_sources ${target} SOURCES)\n    if(NOT _target_sources)\n        set(_target_sources \"\")\n    endif()\n\n    if(arg_TYPE STREQUAL \"UM_LIB\")\n        target_compile_options(${target} PRIVATE /Gz) # __stcall calling convention\n        target_link_options(${target} PRIVATE /SUBSYSTEM:WINDOWS,6.1)\n        if(MSVC_CLANG)\n            target_compile_options(${target} PRIVATE ${SI_UM_CLANG_NO_DIAGNOSTICS})\n        endif()\n        if(SI_WITH_WPP_USER)\n            si_target_tracewpp(${target} WPP_USER_MODE\n                WPP_EXT \".c.cpp.h.hpp\" WPP_PRESERVE_EXT\n                WPP_SCAN \"${CMAKE_SOURCE_DIR}/phlib/include/trace.h\"\n                ${_target_sources}\n            )\n            target_link_libraries(${target} PRIVATE advapi32)\n        else()\n            target_compile_definitions(${target} PRIVATE SI_NO_WPP)\n        endif()\n    elseif(arg_TYPE STREQUAL \"UM_BIN\")\n        target_compile_options(${target} PRIVATE /Gz) # __stcall calling convention\n        target_link_options(${target} PRIVATE /SUBSYSTEM:WINDOWS,6.1)\n        if(MSVC_CLANG)\n            target_compile_options(${target} PRIVATE ${SI_UM_CLANG_NO_DIAGNOSTICS})\n        endif()\n        if(SI_WITH_WPP_USER)\n            si_target_tracewpp(${target} WPP_USER_MODE\n                WPP_EXT \".c.cpp.h.hpp\" WPP_PRESERVE_EXT\n                WPP_SCAN \"${CMAKE_SOURCE_DIR}/phlib/include/trace.h\"\n                ${_target_sources}\n            )\n            target_link_libraries(${target} PRIVATE advapi32)\n        else()\n            target_compile_definitions(${target} PRIVATE SI_NO_WPP)\n        endif()\n        si_kphsign(${target})\n    elseif(arg_TYPE STREQUAL \"KM_LIB\")\n        if(SI_WITH_WPP_KERNEL)\n            si_target_tracewpp(${target} WPP_KERNEL_MODE\n                WPP_EXT \".c.cpp.h.hpp\" WPP_PRESERVE_EXT\n                WPP_SCAN \"${CMAKE_SOURCE_DIR}/KSystemInformer/include/trace.h\"\n                ${_target_sources}\n            )\n        else()\n            target_compile_definitions(${target} PRIVATE KSI_NO_WPP)\n        endif()\n    elseif(arg_TYPE STREQUAL \"KM_BIN\")\n        set_target_properties(${target} PROPERTIES SUFFIX \".sys\")\n        if(SI_WITH_WPP_KERNEL)\n            si_target_tracewpp(${target} WPP_KERNEL_MODE\n                WPP_EXT \".c.cpp.h.hpp\" WPP_PRESERVE_EXT\n                WPP_SCAN \"${CMAKE_SOURCE_DIR}/KSystemInformer/include/trace.h\"\n                ${_target_sources}\n            )\n        else()\n            target_compile_definitions(${target} PRIVATE KSI_NO_WPP)\n        endif()\n    endif()\n\n    if (arg_PLUGIN)\n        target_link_libraries(${target} PRIVATE SystemInformer thirdparty)\n        target_include_directories(${target} PRIVATE\n            \"${SI_ROOT}/plugins/include\"\n            \"${SI_ROOT}/phnt/include\"\n            \"${SI_ROOT}/sdk/include\"\n            \"${SI_ROOT}/kphlib/include\"\n        )\n        target_link_directories(${target} PRIVATE\n            \"${SI_ROOT}/sdk/lib/${SI_PLATFORM_SDK_LIB}\"\n            \"${SI_OUTPUT_DIR}/$<CONFIG>${SI_PLATFORM_SHORT}\"\n        )\n    endif()\n\n    if(SI_WITH_PREFAST)\n        # TODO configure this with the additional analysis options and ruleset\n        # once the kph-staging branch is merged into master.\n        target_compile_options(${target} PRIVATE /analyze)\n    endif()\nendfunction()\n\n#\n# add_library for user mode System Informer libraries\n#\nfunction(si_add_library target)\n    add_library(${target} ${ARGN})\n    _si_set_target_defaults(${target} TYPE UM_LIB)\nendfunction()\n\n#\n# add_executable for user mode System Informer executables\n#\nfunction(si_add_executable target)\n    add_executable(${target} ${ARGN})\n    _si_set_target_defaults(${target} TYPE UM_BIN)\nendfunction()\n\n#\n# add_library for System Informer plugins\n#\nfunction(si_add_plugin target)\n    add_library(${target} SHARED ${ARGN})\n    _si_set_target_defaults(${target} TYPE UM_LIB PLUGIN)\nendfunction()\n\n#\n# add_library for kernel mode System Informer libraries\n#\nfunction(si_add_kernel_library target)\n    add_library(${target} ${ARGN})\n    _si_set_target_defaults(${target} TYPE KM_LIB)\nendfunction()\n\n#\n# add_executable for kernel mode System Informer drivers\n#\nfunction(si_add_kernel_driver target)\n    add_executable(${target} ${ARGN})\n    _si_set_target_defaults(${target} TYPE KM_BIN)\nendfunction()\n"
  },
  {
    "path": "cmake/platform.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nif(MSVC AND CMAKE_C_COMPILER_ID STREQUAL \"Clang\")\n    set(MSVC_CLANG ON)\nelse()\n    set(MSVC_CLANG OFF)\nendif()\nif (MSVC AND NOT CMAKE_C_COMPILER_ID STREQUAL \"Clang\")\n    set(MSVC_NOT_CLANG ON)\nelse()\n    set(MSVC_NOT_CLANG OFF)\nendif()\n\nif(CMAKE_VS_PLATFORM_NAME)\n    set(SI_PLATFORM \"${CMAKE_VS_PLATFORM_NAME}\")\nelseif(CMAKE_GENERATOR_PLATFORM)\n    if(CMAKE_GENERATOR_PLATFORM MATCHES \"x64|AMD64|x86_64\")\n        set(SI_PLATFORM \"x64\")\n    elseif(CMAKE_GENERATOR_PLATFORM MATCHES \"ARM64|aarch64\")\n        set(SI_PLATFORM \"ARM64\")\n    elseif(CMAKE_GENERATOR_PLATFORM MATCHES \"i[3-6]86|[xX]86|Win32\")\n        set(SI_PLATFORM \"Win32\")\n    else()\n        message(FATAL_ERROR \"Unsupported platform: ${CMAKE_GENERATOR_PLATFORM}\")\n    endif()\nelseif(CMAKE_C_COMPILER_ARCHITECTURE_ID)\n    if(CMAKE_C_COMPILER_ARCHITECTURE_ID MATCHES \"x64|AMD64|x86_64\")\n        set(SI_PLATFORM \"x64\")\n    elseif(CMAKE_C_COMPILER_ARCHITECTURE_ID MATCHES \"ARM64|aarch64\")\n        set(SI_PLATFORM \"ARM64\")\n    elseif(CMAKE_C_COMPILER_ARCHITECTURE_ID MATCHES \"i[3-6]86|[xX]86|Win32\")\n        set(SI_PLATFORM \"Win32\")\n    else()\n        message(FATAL_ERROR \"Unsupported platform: ${CMAKE_C_COMPILER_ARCHITECTURE_ID}\")\n    endif()\nelse()\n    message(FATAL_ERROR \"Unable to detect target platform.\")\nendif()\nif(SI_PLATFORM STREQUAL \"x64\")\n    set(SI_PLATFORM_SHORT \"64\")\n    set(SI_PLATFORM_SDK_LIB \"amd64\")\nelseif(SI_PLATFORM STREQUAL \"ARM64\")\n    set(SI_PLATFORM_SHORT \"ARM64\")\n    set(SI_PLATFORM_SDK_LIB \"arm64\")\nelseif(SI_PLATFORM STREQUAL \"Win32\")\n    set(SI_PLATFORM_SHORT \"32\")\n    set(SI_PLATFORM_SDK_LIB \"i386\")\nelse()\n    message(FATAL_ERROR \"Unexpected platform: ${SI_PLATFORM}\")\nendif()\n"
  },
  {
    "path": "cmake/prefast.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\ninclude(commands)\n\n#\n# Enables PREfast analysis using a props file (for VS generators).\n#\nfunction(_si_target_prefast_props target)\n    set(options)\n    set(oneValueArgs RULE_SET STACK_SIZE)\n    set(multiValueArgs EXCLUDE_PATHS)\n    cmake_parse_arguments(PARSE_ARGV 1 arg \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\")\n\n    set(_ruleset)\n    if(DEFINED arg_RULE_SET)\n        if(IS_ABSOLUTE \"${arg_RULE_SET}\")\n            set(_ruleset \"${arg_RULE_SET}\")\n        else()\n            set(_ruleset \"${CMAKE_CURRENT_SOURCE_DIR}/${arg_RULE_SET}\")\n        endif()\n        cmake_path(NATIVE_PATH _ruleset NORMALIZE _ruleset)\n    endif()\n\n    if(DEFINED arg_STACK_SIZE)\n        set(_stack_size \"stacksize${arg_STACK_SIZE}\")\n    else()\n        set(_stack_size \"stacksize1024\")\n    endif()\n\n    set(_exclude_paths)\n    foreach(_arg ${arg_EXCLUDE_PATHS})\n        if(IS_ABSOLUTE \"${_arg}\")\n            set(_exclude_path \"${_arg}\")\n        else()\n            set(_exclude_path \"${CMAKE_CURRENT_SOURCE_DIR}/${_arg}\")\n        endif()\n        cmake_path(NATIVE_PATH _exclude_path NORMALIZE _exclude_path)\n        list(APPEND _exclude_paths ${_exclude_path})\n    endforeach()\n\n    set(_props_file \"${CMAKE_CURRENT_BINARY_DIR}/${target}_prefast.props\")\n\n    string(APPEND _props \"<Project>\\n\")\n    string(APPEND _props \"  <PropertyGroup>\\n\")\n    string(APPEND _props \"    <RunCodeAnalysis>true</RunCodeAnalysis>\\n\")\n    string(APPEND _props \"    <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>\\n\")\n    if(_ruleset)\n    string(APPEND _props \"    <CodeAnalysisRuleset>${_ruleset}</CodeAnalysisRuleset>\\n\")\n    endif()\n    foreach(_exclude_path ${_exclude_paths})\n    string(APPEND _props \"    <CAExcludePath>${_exclude_path};$(CAExcludePath)</CAExcludePath>\\n\")\n    endforeach()\n    string(APPEND _props \"    <PREfastAdditionalOptions>${_stack_size};$(PREfastAdditionalOptions)</PREfastAdditionalOptions>\\n\")\n    string(APPEND _props \"  </PropertyGroup>\\n\")\n    string(APPEND _props \"</Project>\\n\")\n\n    file(GENERATE OUTPUT \"${_props_file}\" CONTENT \"${_props}\")\n\n    set_target_properties(${target} PROPERTIES VS_USER_PROPS \"${_props_file}\")\nendfunction()\n\n#\n# Enables PREfast analysis compiler configuration (for non-VS generators).\n#\nfunction(_si_target_prefast_opts target)\n    set(options)\n    set(oneValueArgs RULE_SET STACK_SIZE)\n    set(multiValueArgs EXCLUDE_PATHS)\n    cmake_parse_arguments(PARSE_ARGV 1 arg \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\")\n\n    #\n    # Doing this without the MSBuild system requires looking up some necessary\n    # parts to pass to the compiler ourself:\n    # 1. The project directory.\n    # 2. The directories which contain predefined rulesets.\n    # 3. Plugins for analysis.\n    #\n\n    cmake_path(NATIVE_PATH CMAKE_CURRENT_SOURCE_DIR NORMALIZE _project_dir)\n    string(REGEX REPLACE \"[\\\\\\\\/]+$\" \"\" _project_dir \"${_project_dir}\")\n\n    find_path(_rulesets_dir \"AllRules.ruleset\" PATHS\n        ENV \"VSINSTALLDIR\"\n        PATH_SUFFIXES \"Team Tools/Static Analysis Tools/Rule Sets\"\n        REQUIRED\n    )\n    string(REGEX REPLACE \"[\\\\\\\\/]+$\" \"\" _rulesets_dir \"${_rulesets_dir}\")\n\n    #\n    # Plugins other than EspXEngine are disabled for now. Only EspXEngine is\n    # included by MSBuild for user mode code analysis. Including the others in\n    # user mode causes some interesting analysis errors. If this path ever gets\n    # used for kernel mode builds this section should be revisited. (jxy-s)\n    #\n    set(_plugins)\n    find_program(_plugin \"EspXEngine.dll\" PATHS \"VC/Tools/MSVC\" REQUIRED)\n    cmake_path(NATIVE_PATH _plugin NORMALIZE _plugin)\n    list(APPEND _plugins ${_plugin})\n    #find_program(_plugin \"WindowsPrefast.dll\" PATHS \"Windows Kits/10/bin\" REQUIRED)\n    #cmake_path(NATIVE_PATH _plugin NORMALIZE _plugin)\n    #list(APPEND _plugins ${_plugin})\n    #find_program(_plugin \"drivers.dll\" PATHS \"Windows Kits/10/bin\" REQUIRED)\n    #cmake_path(NATIVE_PATH _plugin NORMALIZE _plugin)\n    #list(APPEND _plugins ${_plugin})\n\n    #\n    # Handle arguments - N.B. exclude paths will be handled later.\n    #\n\n    set(_ruleset)\n    if(DEFINED arg_RULE_SET)\n        if(IS_ABSOLUTE \"${arg_RULE_SET}\")\n            set(_ruleset \"${arg_RULE_SET}\")\n        else()\n            set(_ruleset \"${CMAKE_CURRENT_SOURCE_DIR}/${arg_RULE_SET}\")\n        endif()\n        cmake_path(NATIVE_PATH _ruleset NORMALIZE _ruleset)\n    endif()\n\n    if(DEFINED arg_STACK_SIZE)\n        set(_stack_size \"stacksize${arg_STACK_SIZE}\")\n    else()\n        set(_stack_size \"stacksize1024\")\n    endif()\n\n    #\n    # Create a response file to bypass CMake's automatic escaping.\n    #\n\n    set(_response_file \"${CMAKE_CURRENT_BINARY_DIR}/${target}_prefast.rsp\")\n    string(APPEND _analyze \"/analyze\\n\")\n    string(APPEND _analyze \"/analyze:projectdirectory\\\"${_project_dir}\\\"\\n\")\n    string(APPEND _analyze \"/analyze:rulesetdirectory\\\";${_rulesets_dir};\\\"\\n\")\n    if(_ruleset)\n    string(APPEND _analyze \"/analyze:ruleset\\\"${_ruleset}\\\"\\n\")\n    endif()\n    string(APPEND _analyze \"/analyze:${_stack_size}\\n\")\n    foreach(_plugin ${_plugins})\n    string(APPEND _analyze \"/analyze:plugin\\\"${_plugin}\\\"\\n\")\n    endforeach()\n\n    file(GENERATE OUTPUT \"${_response_file}\" CONTENT \"${_analyze}\")\n    cmake_path(NATIVE_PATH _response_file NORMALIZE _response_file)\n\n    #\n    # Configure the compiler for analysis.\n    #\n\n    target_compile_definitions(${target} PRIVATE CODE_ANALYSIS)\n    target_compile_options(${target} PRIVATE \"@${_response_file}\")\n\n    #\n    # Handle exclude path arguments.\n    #\n    # The analyzer expects the CAExcludePath environment variable to be set to\n    # exclude certain paths from code analysis. So generate a compiler wrapper\n    # script that sets the environment variable to exclude files from analysis\n    # that should be.\n    #\n\n    set(_exclude_paths)\n    foreach(_arg ${arg_EXCLUDE_PATHS})\n        if(IS_ABSOLUTE \"${_arg}\")\n            set(_exclude_path \"${_arg}\")\n        else()\n            set(_exclude_path \"${CMAKE_CURRENT_SOURCE_DIR}/${_arg}\")\n        endif()\n        cmake_path(NATIVE_PATH _exclude_path NORMALIZE _exclude_path)\n        list(APPEND _exclude_paths ${_exclude_path})\n    endforeach()\n\n    if (_exclude_paths)\n        string(JOIN \";\" _exclude_paths ${_exclude_paths})\n        set(_wrapper_file \"${CMAKE_CURRENT_BINARY_DIR}/${target}_prefast_wrapper.cmd\")\n\n        string(APPEND _wrapper \"@echo off\\n\")\n        string(APPEND _wrapper \"set \\\"CAExcludePath=${_exclude_paths}\\\"\\n\")\n        string(APPEND _wrapper \"%*\\n\")\n\n        file(GENERATE OUTPUT \"${_wrapper_file}\" CONTENT \"${_wrapper}\")\n\n        set_target_properties(${target} PROPERTIES\n            CXX_COMPILER_LAUNCHER \"${_wrapper_file}\"\n            C_COMPILER_LAUNCHER \"${_wrapper_file}\"\n        )\n    endif()\nendfunction()\n\n#\n# Enables PREfast analysis for a given target.\n#\nfunction(si_target_prefast target)\n    set(options)\n    set(oneValueArgs RULE_SET STACK_SIZE)\n    set(multiValueArgs EXCLUDE_PATHS)\n    cmake_parse_arguments(PARSE_ARGV 1 arg \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\")\n\n    if(NOT MSVC_NOT_CLANG)\n        message(NOTICE \"PREfast skipped for ${target} because it is not compatible with Clang.\")\n        return()\n    endif()\n\n    #\n    # Append exclude paths that are excluded from PREfast by MSBuild by default.\n    # Note that using EXTERNAL_INCLUDE and INCLUDE is a cheat here, but it's\n    # close enough. See: Microsoft.CodeAnalysis.Targets CAExcludePath\n    #\n    set(_exclude_paths ${arg_EXCLUDE_PATHS})\n    list(APPEND _exclude_paths $ENV{EXTERNAL_INCLUDE})\n    list(APPEND _exclude_paths $ENV{INCLUDE})\n    list(REMOVE_DUPLICATES _exclude_paths)\n\n    if(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n        _si_target_prefast_props(${target}\n            RULE_SET ${arg_RULE_SET}\n            STACK_SIZE ${arg_STACK_SIZE}\n            EXCLUDE_PATHS ${_exclude_paths}\n        )\n    else()\n        _si_target_prefast_opts(${target}\n            RULE_SET ${arg_RULE_SET}\n            STACK_SIZE ${arg_STACK_SIZE}\n            EXCLUDE_PATHS ${_exclude_paths}\n         )\n    endif()\nendfunction()\n"
  },
  {
    "path": "cmake/toolchain/clang-msvc-amd64.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(CMAKE_SYSTEM_NAME      Windows)\nset(CMAKE_SYSTEM_PROCESSOR AMD64)\nif(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n    set(CMAKE_GENERATOR_PLATFORM x64)\nendif()\n\nset(CMAKE_C_COMPILER          clang-cl)\nset(CMAKE_CXX_COMPILER        clang-cl)\nset(CMAKE_LINKER              link)\nset(CMAKE_AR                  lib)\nset(CMAKE_C_COMPILER_AR       lib)\nset(CMAKE_CXX_COMPILER_AR     lib)\nset(CMAKE_NINJA_CMCLDEPS_RC   OFF)\nset(CMAKE_MC_COMPILER         mc)\nset(CMAKE_RC_COMPILER         rc)\nset(CMAKE_C_COMPILER_TARGET   \"x86_64-pc-windows-msvc\")\nset(CMAKE_CXX_COMPILER_TARGET \"x86_64-pc-windows-msvc\")\n\nset(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/override-msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/clang-msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/finalize-msvc.cmake)\n"
  },
  {
    "path": "cmake/toolchain/clang-msvc-arm64.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(CMAKE_SYSTEM_NAME      Windows)\nset(CMAKE_SYSTEM_PROCESSOR ARM64)\nif(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n    set(CMAKE_GENERATOR_PLATFORM ARM64)\nendif()\n\nset(CMAKE_C_COMPILER          clang-cl)\nset(CMAKE_CXX_COMPILER        clang-cl)\nset(CMAKE_LINKER              link)\nset(CMAKE_AR                  lib)\nset(CMAKE_C_COMPILER_AR       lib)\nset(CMAKE_CXX_COMPILER_AR     lib)\nset(CMAKE_NINJA_CMCLDEPS_RC   OFF)\nset(CMAKE_MC_COMPILER         mc)\nset(CMAKE_RC_COMPILER         rc)\nset(CMAKE_C_COMPILER_TARGET   \"arm64-pc-windows-msvc\")\nset(CMAKE_CXX_COMPILER_TARGET \"arm64-pc-windows-msvc\")\n\nset(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/override-msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/clang-msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/finalize-msvc.cmake)\n"
  },
  {
    "path": "cmake/toolchain/clang-msvc-x86.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(CMAKE_SYSTEM_NAME      Windows)\nset(CMAKE_SYSTEM_PROCESSOR x86)\nif(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n    set(CMAKE_GENERATOR_PLATFORM Win32)\nendif()\n\nset(CMAKE_C_COMPILER          clang-cl)\nset(CMAKE_CXX_COMPILER        clang-cl)\nset(CMAKE_LINKER              link)\nset(CMAKE_AR                  lib)\nset(CMAKE_C_COMPILER_AR       lib)\nset(CMAKE_CXX_COMPILER_AR     lib)\nset(CMAKE_NINJA_CMCLDEPS_RC   OFF)\nset(CMAKE_MC_COMPILER         mc)\nset(CMAKE_RC_COMPILER         rc)\nset(CMAKE_C_FLAGS             \"-m32\")\nset(CMAKE_CXX_FLAGS           \"-m32\")\nset(CMAKE_C_COMPILER_TARGET   \"i686-pc-windows-msvc\")\nset(CMAKE_CXX_COMPILER_TARGET \"i686-pc-windows-msvc\")\n\nset(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/override-msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/clang-msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/finalize-msvc.cmake)\n"
  },
  {
    "path": "cmake/toolchain/clang-msvc.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(_clang_version)\nexecute_process(\n    COMMAND clang-cl --version\n    OUTPUT_VARIABLE _clang_output\n    RESULT_VARIABLE _clang_result\n)\nif(_clang_result EQUAL 0)\n    if(_clang_output MATCHES \"clang version ([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)\")\n        set(_clang_major ${CMAKE_MATCH_1})\n        set(_clang_minor ${CMAKE_MATCH_2})\n        set(_clang_patch ${CMAKE_MATCH_3})\n        math(EXPR _clang_version \"${_clang_major} * 10000 + ${_clang_minor} * 100 + ${_clang_patch}\")\n    endif()\nendif()\nif(NOT _clang_version)\n    message(FATAL_ERROR \"Failed to resolve clang version: ${_clang_result}\\n${_clang_output}\")\nendif()\n\ninclude(${CMAKE_CURRENT_LIST_DIR}/msvc.cmake)\n\nset(SI_C_STANDARD_FLAG   /std:c17)\nset(SI_CXX_STANDARD_FLAG /std:c++latest)\n\nset(CMAKE_RC_FLAGS_INIT \"/nologo\")\n\nset(_remove \"__SI_REMOVE\")\nset(SI_CLANG_MSVC_REPLACE_COMPILE_FLAGS\n    /MP                 ${_remove}\n    /Gm-                ${_remove}\n    /Zc:preprocessor    ${_remove}\n    /d1nodatetime       ${_remove}\n    /guard:xfg          ${_remove}\n    /ZI                 /Z7\n    # TODO(jxy-s) Investigate failures related to this flag.\n    /Qspectre           ${_remove} # -mspeculative-load-hardening\n    /guard:signret      -msign-return-address=all\n)\nlist(LENGTH SI_CLANG_MSVC_REPLACE_COMPILE_FLAGS _replace_total)\nmath(EXPR _max_idx \"${_replace_total} - 1\")\nforeach(_idx RANGE 0 ${_max_idx} 2)\n    math(EXPR _next_idx \"${_idx} + 1\")\n    list(GET SI_CLANG_MSVC_REPLACE_COMPILE_FLAGS ${_idx} _old_flag)\n    list(GET SI_CLANG_MSVC_REPLACE_COMPILE_FLAGS ${_next_idx} _new_flag)\n\n    if(_new_flag STREQUAL \"${_remove}\")\n        message(VERBOSE \"clang-msvc removing: ${_old_flag}\")\n        list(REMOVE_ITEM SI_COMPILE_FLAGS_INIT ${_old_flag})\n        list(REMOVE_ITEM SI_COMPILE_FLAGS_DEBUG_INIT ${_old_flag})\n        list(REMOVE_ITEM SI_COMPILE_FLAGS_RELEASE_INIT ${_old_flag})\n    else()\n        message(VERBOSE \"clang-msvc replacing: ${_old_flag} ${_new_flag}\")\n        list(TRANSFORM SI_COMPILE_FLAGS_INIT REPLACE \"${_old_flag}\" \"${_new_flag}\")\n        list(TRANSFORM SI_COMPILE_FLAGS_DEBUG_INIT REPLACE \"${_old_flag}\" \"${_new_flag}\")\n        list(TRANSFORM SI_COMPILE_FLAGS_RELEASE_INIT REPLACE \"${_old_flag}\" \"${_new_flag}\")\n    endif()\nendforeach()\n\nlist(APPEND SI_COMPILE_FLAGS_INIT\n    -fcolor-diagnostics               # Quality of life compiler output\n    -fansi-escape-codes               # Quality of life compiler output\n)\nif(CMAKE_SYSTEM_PROCESSOR STREQUAL \"ARM64\")\n    list(APPEND SI_COMPILE_FLAGS_INIT\n        -mcrc                         # Enable ARM64 CRC32 instructions\n    )\nelse()\n    list(APPEND SI_COMPILE_FLAGS_INIT\n        -mavx                         # Enable AVX instructions\n        -mavx2                        # Enable AVX2 instructions\n        -mavx512vl                    # Enable AVX512VL instructions\n        -mrdrnd                       # Enable RDRAND instructions\n    )\nendif()\n\n#\n# Only suppress here if Microsoft code ends up needing it.\n#\nlist(APPEND SI_COMPILE_FLAGS_INIT\n    -fms-compatibility\n    -fms-extensions\n    -Wno-comment\n    -Wno-extern-c-compat\n    -Wno-extern-initializer\n    -Wno-ignored-attributes\n    -Wno-ignored-pragma-intrinsic\n    -Wno-microsoft-anon-tag\n    -Wno-microsoft-enum-forward-reference\n    -Wno-microsoft-include\n    -Wno-overloaded-virtual\n    -Wno-pragma-pack\n    -Wno-unknown-pragmas\n    -Wno-unused-local-typedef\n    -Wno-unused-value\n    -Wno-defaulted-function-deleted\n    -Wno-class-conversion\n    -Wno-microsoft-explicit-constructor-call\n\n    # TODO(jxy-s) Needs investigation. Works locally, but fails on CI.\n    -Wno-int-to-void-pointer-cast\n    -Wno-void-pointer-to-int-cast\n)\nif(_clang_version LESS 210100)\n    list(APPEND SI_COMPILE_FLAGS_INIT\n        -Wno-microsoft-static-assert\n    )\nendif()\nif(CMAKE_SYSTEM_PROCESSOR STREQUAL \"ARM64\")\n    list(APPEND SI_COMPILE_FLAGS_INIT\n        -Wno-implicit-function-declaration\n    )\nendif()\nif(CMAKE_SYSTEM_PROCESSOR STREQUAL \"x86\")\n    list(APPEND SI_COMPILE_FLAGS_INIT\n        -Wno-missing-prototype-for-cc\n    )\nendif()\n"
  },
  {
    "path": "cmake/toolchain/finalize-msvc.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(SI_C_FLAGS_INIT ${SI_C_STANDARD_FLAG} ${SI_COMPILE_FLAGS_INIT})\nset(SI_C_FLAGS_DEBUG_INIT ${SI_COMPILE_FLAGS_DEBUG_INIT})\nset(SI_C_FLAGS_RELEASE_INIT ${SI_COMPILE_FLAGS_RELEASE_INIT})\nset(SI_CXX_FLAGS_INIT ${SI_CXX_STANDARD_FLAG} ${SI_COMPILE_FLAGS_INIT})\nset(SI_CXX_FLAGS_DEBUG_INIT ${SI_COMPILE_FLAGS_DEBUG_INIT})\nset(SI_CXX_FLAGS_RELEASE_INIT ${SI_COMPILE_FLAGS_RELEASE_INIT})\nset(SI_EXE_LINKER_FLAGS_INIT ${SI_LINK_FLAGS_INIT})\nset(SI_EXE_LINKER_FLAGS_DEBUG_INIT ${SI_LINK_FLAGS_DEBUG_INIT})\nset(SI_EXE_LINKER_FLAGS_RELEASE_INIT ${SI_LINK_FLAGS_RELEASE_INIT})\nset(SI_SHARED_LINKER_FLAGS_INIT ${SI_LINK_FLAGS_INIT})\nset(SI_SHARED_LINKER_FLAGS_DEBUG_INIT ${SI_LINK_FLAGS_DEBUG_INIT})\nset(SI_SHARED_LINKER_FLAGS_RELEASE_INIT ${SI_LINK_FLAGS_RELEASE_INIT})\nset(SI_MODULE_LINKER_FLAGS_INIT ${SI_LINK_FLAGS_INIT})\nset(SI_MODULE_LINKER_FLAGS_DEBUG_INIT ${SI_LINK_FLAGS_DEBUG_INIT})\nset(SI_MODULE_LINKER_FLAGS_RELEASE_INIT ${SI_LINK_FLAGS_RELEASE_INIT})\nset(SI_STATIC_LINKER_FLAGS_INIT ${SI_STATIC_LINK_FLAGS_INIT})\nset(SI_STATIC_LINKER_FLAGS_DEBUG_INIT ${SI_STATIC_LINK_FLAGS_DEBUG_INIT})\nset(SI_STATIC_LINKER_FLAGS_RELEASE_INIT ${SI_STATIC_LINK_FLAGS_RELEASE_INIT})\n\nmacro(_si_set_init _suffix)\n    set(__joined)\n    list(JOIN SI_${_suffix}_INIT \" \" __joined)\n    set(CMAKE_${_suffix} \"${__joined}\")\nendmacro()\n\n_si_set_init(C_FLAGS)\n_si_set_init(C_FLAGS_DEBUG)\n_si_set_init(C_FLAGS_RELEASE)\n_si_set_init(CXX_FLAGS)\n_si_set_init(CXX_FLAGS_DEBUG)\n_si_set_init(CXX_FLAGS_RELEASE)\n_si_set_init(EXE_LINKER_FLAGS)\n_si_set_init(EXE_LINKER_FLAGS_DEBUG)\n_si_set_init(EXE_LINKER_FLAGS_RELEASE)\n_si_set_init(SHARED_LINKER_FLAGS)\n_si_set_init(SHARED_LINKER_FLAGS_DEBUG)\n_si_set_init(SHARED_LINKER_FLAGS_RELEASE)\n_si_set_init(MODULE_LINKER_FLAGS)\n_si_set_init(MODULE_LINKER_FLAGS_DEBUG)\n_si_set_init(MODULE_LINKER_FLAGS_RELEASE)\n_si_set_init(STATIC_LINKER_FLAGS)\n_si_set_init(STATIC_LINKER_FLAGS_DEBUG)\n_si_set_init(STATIC_LINKER_FLAGS_RELEASE)\n"
  },
  {
    "path": "cmake/toolchain/msvc-amd64.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(CMAKE_SYSTEM_NAME      Windows)\nset(CMAKE_SYSTEM_PROCESSOR AMD64)\nif(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n    set(CMAKE_GENERATOR_PLATFORM x64)\nendif()\n\nset(CMAKE_C_COMPILER   cl)\nset(CMAKE_CXX_COMPILER cl)\nset(CMAKE_LINKER       link)\nset(CMAKE_MC_COMPILER  mc)\nset(CMAKE_RC_COMPILER  rc)\n\nset(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/override-msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/finalize-msvc.cmake)\n"
  },
  {
    "path": "cmake/toolchain/msvc-arm64.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(CMAKE_SYSTEM_NAME      Windows)\nset(CMAKE_SYSTEM_PROCESSOR ARM64)\nif(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n    set(CMAKE_GENERATOR_PLATFORM ARM64)\nendif()\n\nset(CMAKE_C_COMPILER   cl)\nset(CMAKE_CXX_COMPILER cl)\nset(CMAKE_LINKER       link)\nset(CMAKE_MC_COMPILER  mc)\nset(CMAKE_RC_COMPILER  rc)\n\nset(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/override-msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/finalize-msvc.cmake)\n"
  },
  {
    "path": "cmake/toolchain/msvc-x86.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(CMAKE_SYSTEM_NAME      Windows)\nset(CMAKE_SYSTEM_PROCESSOR x86)\nif(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n    set(CMAKE_GENERATOR_PLATFORM Win32)\nendif()\n\nset(CMAKE_C_COMPILER   cl)\nset(CMAKE_CXX_COMPILER cl)\nset(CMAKE_LINKER       link)\nset(CMAKE_MC_COMPILER  mc)\nset(CMAKE_RC_COMPILER  rc)\n\nset(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/override-msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/msvc.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/finalize-msvc.cmake)\n"
  },
  {
    "path": "cmake/toolchain/msvc.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(SI_C_STANDARD_FLAG   /std:clatest)\nset(SI_CXX_STANDARD_FLAG /std:c++latest)\n\n#\n# Compiler flags\n#\nset(SI_COMPILE_FLAGS_INIT\n    /diagnostics:caret                  # Quality of life compiler output\n    /W3                                 # Warning level 3\n    /MP                                 # Multi-processor compilation\n    /WX                                 # Treat warnings as errors\n    /Oi                                 # Enable intrinsic functions\n    /GF                                 # Enable string pooling\n    /Gm-                                # Disable minimal rebuild\n    /GS                                 # Buffer security check\n    /Gy                                 # Enable function-level linking\n    /Zc:wchar_t                         # wchar_t is native type\n    /Zc:forScope                        # Force conformance in for loop scope\n    /Zc:inline                          # Remove unreferenced functions\n    /Zc:rvalueCast                      # Enforce type conversion rules\n    /Zc:preprocessor                    # New preprocessor conformance\n    /permissive-                        # Standards conformance\n    /external:W3                        # Warning level for external headers\n    /utf-8                              # Set source and execution charsets to UTF-8\n    /DEBUG                              # Generate debug info\n    /fp:precise                         # Precise floating point\n    /EHsc                               # Exception handling model\n    /sdl                                # Additional security checks\n    /d1nodatetime                       # Disable date/time in debug info\n)\nset(SI_COMPILE_FLAGS_DEBUG_INIT\n    /ZI                                 # Debug information format (edit and continue)\n    /MTd                                # Static runtime library (debug)\n    /Od                                 # Optimizations (disabled)\n    /RTC1                               # Run-time error checks\n)\nset(SI_COMPILE_FLAGS_RELEASE_INIT\n    /Z7                                 # Debug information format (full)\n    /MT                                 # Static runtime library\n    /O2                                 # Optimizations (maximum speed)\n    /Qspectre                           # Enable spectre mitigations\n    /guard:cf                           # Control flow guard\n)\n\n#\n# Linker flags\n#\nset(SI_STATIC_LINK_FLAGS_INIT\n    /MACHINE:${CMAKE_SYSTEM_PROCESSOR}  # Target platform\n)\nset(SI_LINK_FLAGS_INIT\n    /MACHINE:${CMAKE_SYSTEM_PROCESSOR}  # Target platform\n    /DEBUG                              # Generate debug info\n    /DEBUGTYPE:CV,PDATA\n    /DYNAMICBASE                        # Enable ASLR\n    /NXCOMPAT                           # Enable DEP\n    /DEPENDENTLOADFLAG:0x800            # LOAD_LIBRARY_SEARCH_SYSTEM32\n    /FILEALIGN:0x1000                   # Align sections to 4K\n    /BREPRO                             # Reproducible builds\n    /LARGEADDRESSAWARE                  # Handles addresses larger than 2GB\n    /BASERELOCCLUSTERING                # Better relocation compression\n)\nset(SI_LINK_FLAGS_DEBUG_INIT\n    /INCREMENTAL                        # Incremental linking\n)\nset(SI_LINK_FLAGS_RELEASE_INIT\n    /RELEASE                            # Set release checksum\n    /INCREMENTAL:NO                     # Incremental linking off\n    /OPT:REF                            # Eliminate unreferenced\n    /OPT:ICF                            # COMDAT folding\n    /LTCG                               # Link-time code generation\n    /GUARD:CF                           # Control flow guard\n)\n\n#\n# Processor specific options\n#\nif(CMAKE_SYSTEM_PROCESSOR STREQUAL \"ARM64\")\n    list(APPEND SI_COMPILE_FLAGS_RELEASE_INIT\n        /guard:signret                  # Signed return instruction generation\n        /guard:ehcont                   # EH continuation guard\n    )\n    list(APPEND SI_LINK_FLAGS_RELEASE_INIT\n        /GUARD:EHCONT                   # EH continuation guard\n    )\nelseif(CMAKE_SYSTEM_PROCESSOR STREQUAL \"AMD64\")\n    list(APPEND SI_COMPILE_FLAGS_RELEASE_INIT\n        /guard:xfg                      # Extended flow guard\n        /guard:ehcont                   # EH continuation guard\n        /QIntel-jcc-erratum             # Intel erratum 1279\n    )\n    list(APPEND SI_LINK_FLAGS_RELEASE_INIT\n        /GUARD:XFG                      # Extended flow guard\n        /GUARD:EHCONT                   # EH continuation guard\n        /CETCOMPAT                      # CET compatibility\n    )\nelseif(CMAKE_SYSTEM_PROCESSOR STREQUAL \"x86\")\n    list(APPEND SI_COMPILE_FLAGS_RELEASE_INIT\n        /QIntel-jcc-erratum             # Intel erratum 1279\n    )\n    list(APPEND SI_LINK_FLAGS_RELEASE_INIT\n        /SAFESEH                        # EH continuation guard\n        /CETCOMPAT                      # CET compatibility\n    )\nelse()\n    message(FATAL_ERROR \"Unknown system processor: ${CMAKE_SYSTEM_PROCESSOR}\")\nendif()\n"
  },
  {
    "path": "cmake/toolchain/override-msvc.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(CMAKE_MSVC_RUNTIME_CHECKS \"\")\nset(CMAKE_MSVC_RUNTIME_LIBRARY \"\")\nset(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT \"\")\nset(CMAKE_C_FLAGS_INIT \"\")\nset(CMAKE_C_FLAGS_DEBUG_INI \"\")\nset(CMAKE_C_FLAGS_RELEASE_INIT \"\")\nset(CMAKE_C_STANDARD_LIBRARIES_INIT \"\")\nset(CMAKE_CXX_FLAGS_INIT \"\")\nset(CMAKE_CXX_FLAGS_DEBUG_INIT \"\")\nset(CMAKE_CXX_FLAGS_RELEASE_INIT \"\")\nset(CMAKE_CXX_STANDARD_LIBRARIES_INIT \"\")\nset(CMAKE_EXE_LINKER_FLAGS_INIT \"\")\nset(CMAKE_EXE_LINKER_FLAGS_DEBUG_INIT \"\")\nset(CMAKE_EXE_LINKER_FLAGS_RELEASE_INIT \"\")\nset(CMAKE_SHARED_LINKER_FLAGS_INIT \"\")\nset(CMAKE_SHARED_LINKER_FLAGS_DEBUG_INIT \"\")\nset(CMAKE_SHARED_LINKER_FLAGS_RELEASE_INIT \"\")\nset(CMAKE_MODULE_LINKER_FLAGS_INIT \"\")\nset(CMAKE_MODULE_LINKER_FLAGS_DEBUG_INIT \"\")\nset(CMAKE_MODULE_LINKER_FLAGS_RELEASE_INIT \"\")\nset(CMAKE_STATIC_LINKER_FLAGS_INIT \"\")\nset(CMAKE_STATIC_LINKER_FLAGS_DEBUG_INIT \"\")\nset(CMAKE_STATIC_LINKER_FLAGS_RELEASE_INIT \"\")\n"
  },
  {
    "path": "cmake/tools.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nset(SI_CUSTOM_BUILD_TOOL \"${SI_ROOT}/tools/CustomBuildTool/bin/Release/$ENV{PROCESSOR_ARCHITECTURE}/CustomBuildTool.exe\")\n\nif (NOT EXISTS \"${SI_CUSTOM_BUILD_TOOL}\")\n    message(FATAL_ERROR \"CustomBuildTool.exe not found. Run build\\\\build_tools.cmd first.\")\nendif()\n\nfunction(si_sdkbuild target)\n    add_custom_command(\n        TARGET ${target}\n        POST_BUILD\n        COMMAND \"${SI_CUSTOM_BUILD_TOOL}\" -sdk -$<CONFIG> -${SI_PLATFORM} -cmake\n        WORKING_DIRECTORY \"${SI_ROOT}\"\n        VERBATIM\n    )\nendfunction()\n\nfunction(si_kphsign target)\n    add_custom_command(\n        TARGET ${target}\n        POST_BUILD\n        COMMAND \"${SI_CUSTOM_BUILD_TOOL}\" -kphsign \"$<SHELL_PATH:$<TARGET_FILE:${target}>>\"\n        WORKING_DIRECTORY \"${SI_ROOT}\"\n        VERBATIM\n    )\nendfunction()\n"
  },
  {
    "path": "cmake/tracewpp.cmake",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\n#\n# Helper function for adding WPP trace custom commands.\n#\nfunction(_si_tracewpp_command tmh_files src_files)\n    set(options WPP_KERNEL_MODE WPP_USER_MODE WPP_PRESERVE_EXT)\n    set(oneValueArgs WPP_EXT WPP_SCAN WPP_CONFIG_DIR TMH_OUT_DIR)\n    set(multiValueArgs)\n    cmake_parse_arguments(PARSE_ARGV 2 arg \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\")\n\n    if(arg_WPP_KERNEL_MODE)\n        set(_mode \"-km\")\n    elseif(arg_WPP_USER_MODE)\n        set(_mode \"-um\")\n    else()\n        message(FATAL_ERROR \"WPP_KERNEL_MODE or WPP_USER_MODE must be provided for wpptrace generation.\")\n    endif()\n\n    if(DEFINED arg_WPP_EXT)\n        set(_ext \"-ext:${arg_WPP_EXT}\")\n    else()\n        message(FATAL_ERROR \"WPP_EXT must be provided for wpptrace generation.\")\n    endif()\n\n    if(arg_WPP_PRESERVE_EXT)\n        set(_preserveext \"-preserveext:${arg_WPP_EXT}\")\n    else()\n        set(_preserveext \"\")\n    endif()\n\n    if(DEFINED arg_WPP_SCAN)\n        cmake_path(NATIVE_PATH arg_WPP_SCAN NORMALIZE _scan_file)\n        set(_scan \"-scan:\\\"${_scan_file}\\\"\")\n    else()\n        set(_scan \"\")\n    endif()\n\n    if(DEFINED arg_WPP_CONFIG_DIR)\n        cmake_path(NATIVE_PATH arg_WPP_CONFIG_DIR NORMALIZE _cfg_dir)\n        set(_cfgdir \"-cfgdir:\\\"${_cfg_dir}\\\"\")\n    else()\n        set(_cfgdir \"\")\n    endif()\n\n    if(DEFINED arg_TMH_OUT_DIR)\n        cmake_path(NATIVE_PATH arg_TMH_OUT_DIR NORMALIZE _out_dir)\n    else()\n        message(FATAL_ERROR \"TMH_OUT_DIR must be provided for wpptrace generation.\")\n    endif()\n\n    set(_tmh_files)\n    set(_src_files)\n    foreach(_source_file ${arg_UNPARSED_ARGUMENTS})\n        #\n        # Check that the source file has a relevant extension.\n        #\n        cmake_path(GET _source_file EXTENSION _file_ext)\n        string(REPLACE \".\" \"\\\\.\" _file_ext_match ${_file_ext})\n        if(NOT ${arg_WPP_EXT} MATCHES ${_file_ext_match})\n            continue()\n        endif()\n\n        cmake_path(GET _source_file FILENAME _file_name)\n        if(NOT arg_WPP_PRESERVE_EXT)\n            cmake_path(REMOVE_EXTENSION _file_name)\n        endif()\n\n        if(IS_ABSOLUTE \"${_source_file}\")\n            set(_source_file_abs \"${_source_file}\")\n        else()\n            set(_source_file_abs \"${CMAKE_CURRENT_SOURCE_DIR}/${_source_file}\")\n        endif()\n        cmake_path(NATIVE_PATH _source_file_abs NORMALIZE _source_file_abs)\n\n        #\n        # Build the output directory. To avoid collisions the output directory\n        # is appended with the relative path from the target's current source\n        # directory. Also sanitize the path for insertion into the tracewpp\n        # outdir parameter.\n        #\n        cmake_path(GET _source_file_abs PARENT_PATH _tmf_out_dir)\n        cmake_path(RELATIVE_PATH _tmf_out_dir OUTPUT_VARIABLE _tmf_out_dir)\n        cmake_path(APPEND _out_dir \"${_tmf_out_dir}\" OUTPUT_VARIABLE _tmf_out_dir)\n        cmake_path(NATIVE_PATH _tmf_out_dir NORMALIZE _tmf_out_dir)\n        file(MAKE_DIRECTORY \"${_tmf_out_dir}\")\n        string(REGEX REPLACE \"[\\\\\\\\/]+$\" \"\" _tmf_out_dir \"${_tmf_out_dir}\")\n        set(_odir \"-odir:\\\"${_tmf_out_dir}\\\"\")\n\n        cmake_path(\n            APPEND _tmf_out_dir \"${_file_name}.tmh\"\n            OUTPUT_VARIABLE _tmh_file\n        )\n        cmake_path(\n            RELATIVE_PATH _tmh_file\n            BASE_DIRECTORY ${CMAKE_BINARY_DIR}\n            OUTPUT_VARIABLE _tmh_comment\n        )\n        cmake_path(NATIVE_PATH _tmh_file NORMALIZE _tmh_file)\n\n        add_custom_command(\n            OUTPUT ${_tmh_file}\n            COMMAND tracewpp ${_mode}\n                             ${_ext}\n                             ${_preserveext}\n                             ${_cfgdir}\n                             ${_odir}\n                             ${_scan}\n                             \"\\\"${_source_file_abs}\\\"\"\n            DEPENDS \"${_source_file_abs}\" \"${_scan_file}\"\n            COMMENT \"Generating WPP trace header ${_tmh_comment}\"\n        )\n\n        list(APPEND _tmh_files ${_tmh_file})\n        list(APPEND _src_files ${_source_file})\n    endforeach()\n\n    set(${tmh_files} ${_tmh_files} PARENT_SCOPE)\n    set(${src_files} ${_src_files} PARENT_SCOPE)\nendfunction()\n\n#\n# Configures a target for WPP trace generation.\n#\nfunction(si_target_tracewpp target)\n    set(options WPP_KERNEL_MODE WPP_USER_MODE WPP_PRESERVE_EXT)\n    set(oneValueArgs WPP_EXT WPP_SCAN)\n    set(multiValueArgs)\n    cmake_parse_arguments(PARSE_ARGV 1 arg \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\")\n\n    if(arg_WPP_KERNEL_MODE)\n        set(_mode WPP_KERNEL_MODE)\n    elseif(arg_WPP_USER_MODE)\n        set(_mode WPP_USER_MODE)\n    else()\n        message(FATAL_ERROR \"WPP_KERNEL_MODE or WPP_USER_MODE must be provided for wpptrace generation.\")\n    endif()\n\n    set(_preserve_ext)\n    if(arg_WPP_PRESERVE_EXT)\n        set(_preserve_ext WPP_PRESERVE_EXT)\n    endif()\n\n    #\n    # Try to locate the WPP config directory.\n    #\n    find_path(_config_dir \"defaultwpp.ini\" PATHS\n        ENV \"WDKBinRoot\"\n        ENV \"WindowsSdkVerBinPath\"\n        PATH_SUFFIXES \"WppConfig/Rev1\"\n        REQUIRED\n    )\n\n    get_target_property(_target_binary_dir ${target} BINARY_DIR)\n    set(_tmh_out_dir \"${_target_binary_dir}/tmh\")\n\n    _si_tracewpp_command(_tmh_files _src_files\n        ${_mode} ${_preserve_ext}\n        WPP_EXT ${arg_WPP_EXT}\n        WPP_SCAN ${arg_WPP_SCAN}\n        WPP_CONFIG_DIR ${_config_dir}\n        TMH_OUT_DIR ${_tmh_out_dir}\n        ${arg_UNPARSED_ARGUMENTS}\n    )\n\n    #\n    # N.B. _si_tracewpp_command guarantees that _tmh_files to _src_files\n    # have the same number of elements. The work in this block is setting the\n    # required TMH_FILE compile definition for the individual source files.\n    # Along the way, gather the include directories to be added to the target.\n    #\n    set(_include_dirs)\n    list(LENGTH _tmh_files _list_length)\n    if(_list_length GREATER 0)\n        math(EXPR _max_index \"${_list_length} - 1\")\n        foreach(_index RANGE ${_max_index})\n            list(GET _src_files ${_index} _src_file)\n            list(GET _tmh_files ${_index} _tmh_file)\n            cmake_path(GET _tmh_file PARENT_PATH _tmh_dir)\n            list(APPEND _include_dirs \"${_tmh_dir}\")\n            cmake_path(GET _tmh_file FILENAME _tmh_file)\n            set_source_files_properties(${_src_file} PROPERTIES\n                TARGET_DIRECTORY ${target}\n                COMPILE_DEFINITIONS \"TMH_FILE=${_tmh_file}\"\n            )\n        endforeach()\n    endif()\n\n    #\n    # This custom target associates the custom commands per source file with\n    # actual target. Here we also set the include paths.\n    #\n    list(REMOVE_DUPLICATES _include_dirs)\n    if(_include_dirs)\n        add_custom_target(${target}_tracewpp\n            DEPENDS ${_tmh_files}\n            COMMENT \"Generating WPP trace headers for ${target}\"\n        )\n        add_dependencies(${target} ${target}_tracewpp)\n        target_include_directories(${target} PRIVATE ${_include_dirs})\n    endif()\nendfunction()\n"
  },
  {
    "path": "kphlib/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nproject(kphlib)\n\nset(HEADERS\n    \"include/kphapi.h\"\n    \"include/kphdyn.h\"\n    \"include/kphdyndata.h\"\n    \"include/kphlibbase.h\"\n    \"include/kphmsg.h\"\n    \"include/kphmsgdefs.h\"\n    \"include/kphmsgdyn.h\"\n    \"include/sistatus.h\"\n)\nsource_group(\"Header Files\" FILES ${HEADERS})\n\nset(RESOURCES\n    \"include/sistatus_MSG00001.bin\"\n    \"kphdyn.xml\"\n    \"sistatus.mc\"\n)\nsource_group(\"Resource Files\" FILES ${RESOURCES})\n\nset(SOURCES\n    \"kphdyn.c\"\n    \"kphdyndata.c\"\n    \"kphmsg.c\"\n    \"kphmsgdyn.c\"\n    \"kphringbuff.c\"\n)\nsource_group(\"Source Files\" FILES SOURCES)\n\nset(ALL_FILES\n    ${HEADERS}\n    ${RESOURCES}\n    ${SOURCES}\n)\n\nsi_add_library(kphlib_um STATIC ${ALL_FILES})\n\ntarget_include_directories(kphlib_um PUBLIC\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include\"\n)\n\ntarget_link_libraries(kphlib_um PRIVATE\n    phnt\n)\n"
  },
  {
    "path": "kphlib/Directory.Build.props",
    "content": "<Project>\n  <!-- Merge with parent Directory.Build.props -->\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />\n  <Import Condition=\"$(RootNamespace.EndsWith('_km'))\" Project=\"$(SystemInformerRoot)/Common.Kernel.props\" />\n  <Import Condition=\"$(RootNamespace.EndsWith('_um'))\" Project=\"$(SystemInformerRoot)/Common.User.props\" />\n</Project>\n"
  },
  {
    "path": "kphlib/include/kphapi.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n\n#ifdef _KERNEL_MODE\n#define PHNT_MODE PHNT_MODE_KERNEL\n#endif\n#pragma warning(push)\n#pragma warning(disable : 4201)\n\n// Process\n\ntypedef ULONG KPH_PROCESS_STATE;\ntypedef KPH_PROCESS_STATE* PKPH_PROCESS_STATE;\n\n#define KPH_PROCESS_SECURELY_CREATED                     0x00000001ul\n#define KPH_PROCESS_VERIFIED_PROCESS                     0x00000002ul\n#define KPH_PROCESS_PROTECTED_PROCESS                    0x00000004ul\n#define KPH_PROCESS_NO_UNTRUSTED_IMAGES                  0x00000008ul\n#define KPH_PROCESS_HAS_FILE_OBJECT                      0x00000010ul\n#define KPH_PROCESS_HAS_SECTION_OBJECT_POINTERS          0x00000020ul\n#define KPH_PROCESS_NO_USER_WRITABLE_REFERENCES          0x00000040ul\n#define KPH_PROCESS_NO_FILE_TRANSACTION                  0x00000080ul\n#define KPH_PROCESS_NOT_BEING_DEBUGGED                   0x00000100ul\n#define KPH_PROCESS_NO_WRITABLE_FILE_OBJECT              0x00000200ul\n#define KPH_PROCESS_CREATE_NOTIFICATION                  0x00000400ul\n\n#define KPH_PROCESS_STATE_MAXIMUM (KPH_PROCESS_SECURELY_CREATED               |\\\n                                   KPH_PROCESS_VERIFIED_PROCESS               |\\\n                                   KPH_PROCESS_PROTECTED_PROCESS              |\\\n                                   KPH_PROCESS_NO_UNTRUSTED_IMAGES            |\\\n                                   KPH_PROCESS_HAS_FILE_OBJECT                |\\\n                                   KPH_PROCESS_HAS_SECTION_OBJECT_POINTERS    |\\\n                                   KPH_PROCESS_NO_USER_WRITABLE_REFERENCES    |\\\n                                   KPH_PROCESS_NO_FILE_TRANSACTION            |\\\n                                   KPH_PROCESS_NOT_BEING_DEBUGGED             |\\\n                                   KPH_PROCESS_NO_WRITABLE_FILE_OBJECT        |\\\n                                   KPH_PROCESS_CREATE_NOTIFICATION)\n\n#define KPH_PROCESS_STATE_HIGH    (KPH_PROCESS_VERIFIED_PROCESS               |\\\n                                   KPH_PROCESS_PROTECTED_PROCESS              |\\\n                                   KPH_PROCESS_NO_UNTRUSTED_IMAGES            |\\\n                                   KPH_PROCESS_HAS_FILE_OBJECT                |\\\n                                   KPH_PROCESS_HAS_SECTION_OBJECT_POINTERS    |\\\n                                   KPH_PROCESS_NO_USER_WRITABLE_REFERENCES    |\\\n                                   KPH_PROCESS_NO_FILE_TRANSACTION            |\\\n                                   KPH_PROCESS_NOT_BEING_DEBUGGED             |\\\n                                   KPH_PROCESS_NO_WRITABLE_FILE_OBJECT        |\\\n                                   KPH_PROCESS_CREATE_NOTIFICATION)\n\n#define KPH_PROCESS_STATE_MEDIUM  (KPH_PROCESS_VERIFIED_PROCESS               |\\\n                                   KPH_PROCESS_PROTECTED_PROCESS              |\\\n                                   KPH_PROCESS_HAS_FILE_OBJECT                |\\\n                                   KPH_PROCESS_HAS_SECTION_OBJECT_POINTERS    |\\\n                                   KPH_PROCESS_NO_USER_WRITABLE_REFERENCES    |\\\n                                   KPH_PROCESS_NO_FILE_TRANSACTION            |\\\n                                   KPH_PROCESS_NO_WRITABLE_FILE_OBJECT)\n\n#define KPH_PROCESS_STATE_LOW     (KPH_PROCESS_VERIFIED_PROCESS               |\\\n                                   KPH_PROCESS_HAS_FILE_OBJECT                |\\\n                                   KPH_PROCESS_HAS_SECTION_OBJECT_POINTERS    |\\\n                                   KPH_PROCESS_NO_USER_WRITABLE_REFERENCES    |\\\n                                   KPH_PROCESS_NO_FILE_TRANSACTION            |\\\n                                   KPH_PROCESS_NO_WRITABLE_FILE_OBJECT)\n\n#define KPH_PROCESS_STATE_MINIMUM (KPH_PROCESS_HAS_FILE_OBJECT                |\\\n                                   KPH_PROCESS_HAS_SECTION_OBJECT_POINTERS    |\\\n                                   KPH_PROCESS_NO_USER_WRITABLE_REFERENCES    |\\\n                                   KPH_PROCESS_NO_FILE_TRANSACTION            |\\\n                                   KPH_PROCESS_NO_WRITABLE_FILE_OBJECT)\n\ntypedef enum _KPH_PROCESS_INFORMATION_CLASS\n{\n    KphProcessBasicInformation,      // q: KPH_PROCESS_BASIC_INFORMATION\n    KphProcessStateInformation,      // q: KPH_PROCESS_STATE\n    KphProcessQuotaLimits,           // s: QUOTA_LIMITS\n    KphProcessBasePriority,          // s: KPRIORITY\n    KphProcessRaisePriority,         // s: ULONG\n    KphProcessPriorityClass,         // s: PROCESS_PRIORITY_CLASS\n    KphProcessAffinityMask,          // s: KAFFINITY/GROUP_AFFINITY\n    KphProcessPriorityBoost,         // s: ULONG\n    KphProcessIoPriority,            // s: IO_PRIORITY_HINT\n    KphProcessPagePriority,          // s: PAGE_PRIORITY_INFORMATION\n    KphProcessPowerThrottlingState,  // s: POWER_THROTTLING_PROCESS_STATE\n    KphProcessPriorityClassEx,       // s: PROCESS_PRIORITY_CLASS_EX\n    KphProcessEmptyWorkingSet,       // s\n    KphProcessWSLProcessId,          // q: ULONG\n    KphProcessSequenceNumber,        // q: ULONG64\n    KphProcessStartKey,              // q: ULONG64\n    KphProcessImageSection,          // q: HANDLE\n    KphProcessImageFileName,         // q: UNICODE_STRING\n} KPH_PROCESS_INFORMATION_CLASS;\n\ntypedef enum _KPH_THREAD_INFORMATION_CLASS\n{\n    KphThreadPriority,               // s: KPRIORITY\n    KphThreadBasePriority,           // s: KPRIORITY\n    KphThreadAffinityMask,           // s: KAFFINITY\n    KphThreadIdealProcessor,         // s: ULONG\n    KphThreadPriorityBoost,          // s: ULONG\n    KphThreadIoPriority,             // s: IO_PRIORITY_HINT\n    KphThreadPagePriority,           // s: PAGE_PRIORITY_INFORMATION\n    KphThreadActualBasePriority,     // s: LONG\n    KphThreadGroupInformation,       // s: GROUP_AFFINITY\n    KphThreadIdealProcessorEx,       // s: PROCESSOR_NUMBER\n    KphThreadActualGroupAffinity,    // s: GROUP_AFFINITY\n    KphThreadPowerThrottlingState,   // s: POWER_THROTTLING_THREAD_STATE\n    KphThreadIoCounters,             // q: IO_COUNTERS\n    KphThreadWSLThreadId,            // q: ULONG\n    KphThreadExplicitCaseSensitivity,// s: ULONG; s: 0 disables, otherwise enables\n    KphThreadKernelStackInformation, // q: KPH_KERNEL_STACK_INFORMATION\n} KPH_THREAD_INFORMATION_CLASS;\n\ntypedef struct _KPH_PROCESS_BASIC_INFORMATION\n{\n    KPH_PROCESS_STATE ProcessState;\n\n    ULONG64 ProcessStartKey;\n    CLIENT_ID CreatorClientId;\n\n    ULONG UserWritableReferences;\n\n    SIZE_T NumberOfImageLoads;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG CreateNotification : 1;\n            ULONG ExitNotification : 1;\n            ULONG VerifiedProcess : 1;\n            ULONG SecurelyCreated : 1;\n            ULONG Protected : 1;\n            ULONG IsWow64 : 1;\n            ULONG IsSubsystemProcess : 1;\n            ULONG AllocatedImageName : 1;\n            ULONG Reserved : 24;\n        };\n    };\n\n    SIZE_T NumberOfThreads;\n\n    //\n    // Only valid if Protected flag is set.\n    //\n    ACCESS_MASK ProcessAllowedMask;\n    ACCESS_MASK ThreadAllowedMask;\n\n    //\n    // These are only tracked for verified processes.\n    //\n    SIZE_T NumberOfMicrosoftImageLoads;\n    SIZE_T NumberOfAntimalwareImageLoads;\n    SIZE_T NumberOfVerifiedImageLoads;\n    SIZE_T NumberOfUntrustedImageLoads;\n} KPH_PROCESS_BASIC_INFORMATION, *PKPH_PROCESS_BASIC_INFORMATION;\n\ntypedef struct _KPH_KERNEL_STACK_INFORMATION\n{\n    PVOID InitialStack;\n    PVOID StackLimit;\n    PVOID StackBase;\n    PVOID KernelStack;\n} KPH_KERNEL_STACK_INFORMATION, *PKPH_KERNEL_STACK_INFORMATION;\n\n// Process handle information\n\ntypedef struct _KPH_PROCESS_HANDLE\n{\n    HANDLE Handle;\n    PVOID Object;\n    ACCESS_MASK GrantedAccess;\n    USHORT ObjectTypeIndex;\n    USHORT Reserved1;\n    ULONG HandleAttributes;\n    ULONG Reserved2;\n} KPH_PROCESS_HANDLE, *PKPH_PROCESS_HANDLE;\n\ntypedef struct _KPH_PROCESS_HANDLE_INFORMATION\n{\n    ULONG HandleCount;\n    _Field_size_(HandleCount) KPH_PROCESS_HANDLE Handles[1];\n} KPH_PROCESS_HANDLE_INFORMATION, *PKPH_PROCESS_HANDLE_INFORMATION;\n\n// Object information\n\ntypedef enum _KPH_OBJECT_INFORMATION_CLASS\n{\n    KphObjectBasicInformation,                // q: OBJECT_BASIC_INFORMATION\n    KphObjectNameInformation,                 // q: OBJECT_NAME_INFORMATION\n    KphObjectTypeInformation,                 // q: OBJECT_TYPE_INFORMATION\n    KphObjectHandleFlagInformation,           // qs: OBJECT_HANDLE_FLAG_INFORMATION\n    KphObjectProcessBasicInformation,         // q: PROCESS_BASIC_INFORMATION\n    KphObjectThreadBasicInformation,          // q: THREAD_BASIC_INFORMATION\n    KphObjectEtwRegBasicInformation,          // q: ETWREG_BASIC_INFORMATION\n    KphObjectFileObjectInformation,           // q: KPH_FILE_OBJECT_INFORMATION\n    KphObjectFileObjectDriver,                // q: HANDLE\n    KphObjectProcessTimes,                    // q: KERNEL_USER_TIMES\n    KphObjectThreadTimes,                     // q: KERNEL_USER_TIMES\n    KphObjectProcessImageFileName,            // q: UNICODE_STRING\n    KphObjectThreadNameInformation,           // q: THREAD_NAME_INFORMATION\n    KphObjectThreadIsTerminated,              // q: ULONG\n    KphObjectSectionBasicInformation,         // q: SECTION_BASIC_INFORMATION\n    KphObjectSectionFileName,                 // q: UNICODE_STRING\n    KphObjectSectionImageInformation,         // q; SECTION_IMAGE_INFORMATION\n    KphObjectSectionRelocationInformation,    // q; PVOID RelocationAddress\n    KphObjectSectionOriginalBaseInformation,  // q: PVOID BaseAddress\n    KphObjectSectionInternalImageInformation, // q: SECTION_INTERNAL_IMAGE_INFORMATION\n    KphObjectSectionMappingsInformation,      // q: KPH_SECTION_MAPPINGS_INFORMATION\n    KphObjectAttributesInformation,           // q: KPH_OBJECT_ATTRIBUTES_INFORMATION\n    MaxKphObjectInfoClass\n} KPH_OBJECT_INFORMATION_CLASS;\n\ntypedef struct _KPH_VPB\n{\n    CSHORT Type;\n    CSHORT Size;\n    USHORT Flags;\n    USHORT VolumeLabelLength;\n    ULONG SerialNumber;\n    ULONG ReferenceCount;\n    WCHAR VolumeLabel[32];\n} KPH_VPB, *PKPH_VPB;\n\ntypedef struct _KPH_DEVICE_INFO\n{\n    DEVICE_TYPE Type;\n    ULONG Characteristics;\n    ULONG Flags;\n    KPH_VPB Vpb;\n} KPH_DEVICE_INFO, *PKPH_DEVICE_INFO;\n\ntypedef struct _KPH_FILE_OBJECT_INFORMATION\n{\n    BOOLEAN LockOperation;\n    BOOLEAN DeletePending;\n    BOOLEAN ReadAccess;\n    BOOLEAN WriteAccess;\n    BOOLEAN DeleteAccess;\n    BOOLEAN SharedRead;\n    BOOLEAN SharedWrite;\n    BOOLEAN SharedDelete;\n    LARGE_INTEGER CurrentByteOffset;\n    ULONG Flags;\n    ULONG UserWritableReferences;\n    BOOLEAN HasActiveTransaction;\n    BOOLEAN IsIgnoringSharing;\n    LONG Waiters;\n    LONG Busy;\n    KPH_VPB Vpb;\n    KPH_DEVICE_INFO Device;\n    KPH_DEVICE_INFO AttachedDevice;\n    KPH_DEVICE_INFO RelatedDevice;\n} KPH_FILE_OBJECT_INFORMATION, *PKPH_FILE_OBJECT_INFORMATION;\n\ntypedef struct _KPH_OBJECT_ATTRIBUTES_INFORMATION\n{\n    union\n    {\n        UCHAR Flags;\n        struct\n        {\n            UCHAR NewObject : 1;\n            UCHAR KernelObject : 1;\n            UCHAR KernelOnlyAccess : 1;\n            UCHAR ExclusiveObject : 1;\n            UCHAR PermanentObject : 1;\n            UCHAR DefaultSecurityQuota : 1;\n            UCHAR SingleHandleEntry : 1;\n            UCHAR DeletedInline : 1;\n        };\n    };\n} KPH_OBJECT_ATTRIBUTES_INFORMATION, *PKPH_OBJECT_ATTRIBUTES_INFORMATION;\n\n// Driver information\n\ntypedef enum _KPH_DRIVER_INFORMATION_CLASS\n{\n    KphDriverBasicInformation,          // q: DRIVER_BASIC_INFORMATION\n    KphDriverNameInformation,           // q: UNICODE_STRING\n    KphDriverServiceKeyNameInformation, // q: UNICODE_STRING\n    KphDriverImageFileNameInformation,  // q: UNICODE_STRING\n    MaxKphDriverInfoClass\n} KPH_DRIVER_INFORMATION_CLASS;\n\ntypedef struct _KPH_DRIVER_BASIC_INFORMATION\n{\n    ULONG Flags;\n    PVOID DriverStart;\n    ULONG DriverSize;\n} KPH_DRIVER_BASIC_INFORMATION, *PKPH_DRIVER_BASIC_INFORMATION;\n\ntypedef struct _KPH_DRIVER_NAME_INFORMATION\n{\n    UNICODE_STRING DriverName;\n} KPH_DRIVER_NAME_INFORMATION, *PKPH_DRIVER_NAME_INFORMATION;\n\ntypedef struct _KPH_DRIVER_SERVICE_KEY_NAME_INFORMATION\n{\n    UNICODE_STRING ServiceKeyName;\n} KPH_DRIVER_SERVICE_KEY_NAME_INFORMATION, *PKPH_DRIVER_SERVICE_KEY_NAME_INFORMATION;\n\n// ETW registration object information\n\ntypedef struct _KPH_ETWREG_BASIC_INFORMATION\n{\n    GUID Guid;\n    ULONG_PTR SessionId;\n} KPH_ETWREG_BASIC_INFORMATION, *PKPH_ETWREG_BASIC_INFORMATION;\n\n// ALPC object information\n\ntypedef enum _KPH_ALPC_INFORMATION_CLASS\n{\n    KphAlpcBasicInformation,               // q: KPH_ALPC_BASIC_INFORMATION\n    KphAlpcCommunicationInformation,       // q: KPH_ALPC_COMMUNICATION_INFORMATION\n    KphAlpcCommunicationNamesInformation,  // q: KPH_ALPC_COMMUNICATION_NAMES_INFORMATION\n} KPH_ALPC_INFORMATION_CLASS;\n\ntypedef struct _KPH_ALPC_BASIC_INFORMATION\n{\n    HANDLE OwnerProcessId;\n    ULONG Flags;\n    LONG SequenceNo;\n    PVOID PortContext;\n    union\n    {\n        ULONG State;\n        struct\n        {\n            ULONG Initialized : 1;\n            ULONG Type : 2;\n            ULONG ConnectionPending : 1;\n            ULONG ConnectionRefused : 1;\n            ULONG Disconnected : 1;\n            ULONG Closed : 1;\n            ULONG NoFlushOnClose : 1;\n            ULONG ReturnExtendedInfo : 1;\n            ULONG Waitable : 1;\n            ULONG DynamicSecurity : 1;\n            ULONG Wow64CompletionList : 1;\n            ULONG Lpc : 1;\n            ULONG LpcToLpc : 1;\n            ULONG HasCompletionList : 1;\n            ULONG HadCompletionList : 1;\n            ULONG EnableCompletionList : 1;\n        };\n    };\n} KPH_ALPC_BASIC_INFORMATION, *PKPH_ALPC_BASIC_INFORMATION;\n\ntypedef struct _KPH_ALPC_COMMUNICATION_INFORMATION\n{\n    KPH_ALPC_BASIC_INFORMATION ConnectionPort;\n    KPH_ALPC_BASIC_INFORMATION ServerCommunicationPort;\n    KPH_ALPC_BASIC_INFORMATION ClientCommunicationPort;\n} KPH_ALPC_COMMUNICATION_INFORMATION, *PKPH_ALPC_COMMUNICATION_INFORMATION;\n\ntypedef struct _KPH_ALPC_COMMUNICATION_NAMES_INFORMATION\n{\n    UNICODE_STRING ConnectionPort;\n    UNICODE_STRING ServerCommunicationPort;\n    UNICODE_STRING ClientCommunicationPort;\n} KPH_ALPC_COMMUNICATION_NAMES_INFORMATION, *PKPH_ALPC_COMMUNICATION_NAMES_INFORMATION;\n\n// System control\n\ntypedef enum _KPH_SYSTEM_CONTROL_CLASS\n{\n    KphSystemControlEmptyCompressionStore\n} KPH_SYSTEM_CONTROL_CLASS;\n\n// Section\n\ntypedef enum _KPH_SECTION_INFORMATION_CLASS\n{\n    KphSectionMappingsInformation, // q: KPH_SECTION_MAPPINGS_INFORMATION\n} KPH_SECTION_INFORMATION_CLASS;\n\n#define VIEW_MAP_TYPE_PROCESS         1\n#define VIEW_MAP_TYPE_SESSION         2\n#define VIEW_MAP_TYPE_SYSTEM_CACHE    3\n\ntypedef struct _KPH_SECTION_MAP_ENTRY\n{\n    UCHAR ViewMapType;\n    HANDLE ProcessId;\n    PVOID StartVa;\n    PVOID EndVa;\n} KPH_SECTION_MAP_ENTRY, *PKPH_SECTION_MAP_ENTRY;\n\ntypedef struct _KPH_SECTION_MAPPINGS_INFORMATION\n{\n    ULONG NumberOfMappings;\n    KPH_SECTION_MAP_ENTRY Mappings[ANYSIZE_ARRAY];\n} KPH_SECTION_MAPPINGS_INFORMATION, *PKPH_SECTION_MAPPINGS_INFORMATION;\n\n// Virtual memory\n\ntypedef enum _KPH_MEMORY_INFORMATION_CLASS\n{\n    KphMemoryImageSection,          // q: HANDLE\n    KphMemoryDataSection,           // q: KPH_MEMORY_DATA_SECTION\n    KphMemoryMappedInformation,     // q: KPH_MEMORY_MAPPED_INFORMATION\n} KPH_MEMORY_INFORMATION_CLASS, *PKPH_MEMORY_INFORMATION_CLASS;\n\ntypedef struct _KPH_MEMORY_DATA_SECTION\n{\n    HANDLE SectionHandle;\n    LARGE_INTEGER SectionFileSize;\n} KPH_MEMORY_DATA_SECTION, *PKPH_MEMORY_DATA_SECTION;\n\ntypedef struct _KPH_MEMORY_MAPPED_INFORMATION\n{\n    PVOID FileObject;\n    PVOID SectionObjectPointers;\n    PVOID DataControlArea;\n    PVOID SharedCacheMap;\n    PVOID ImageControlArea;\n    ULONG UserWritableReferences;\n} KPH_MEMORY_MAPPED_INFORMATION, *PKPH_MEMORY_MAPPED_INFORMATION;\n\n// File\n\ntypedef enum _KPH_HASH_ALGORITHM\n{\n    KphHashAlgorithmMd5,\n    KphHashAlgorithmSha1,\n    KphHashAlgorithmSha1Authenticode,\n    KphHashAlgorithmSha256,\n    KphHashAlgorithmSha256Authenticode,\n    KphHashAlgorithmSha384,\n    KphHashAlgorithmSha512,\n    MaxKphHashAlgorithm,\n} KPH_HASH_ALGORITHM, *PKPH_HASH_ALGORITHM;\n\n#define KPH_HASH_ALGORITHM_MAX_LENGTH (512 / 8)\n\ntypedef struct _KPH_HASH_INFORMATION\n{\n    KPH_HASH_ALGORITHM Algorithm;\n    ULONG Length;\n    BYTE Hash[KPH_HASH_ALGORITHM_MAX_LENGTH];\n} KPH_HASH_INFORMATION, *PKPH_HASH_INFORMATION;\n\n// Verification\n\n#define KPH_PROCESS_READ_ACCESS   (STANDARD_RIGHTS_READ                       |\\\n                                   SYNCHRONIZE                                |\\\n                                   PROCESS_QUERY_INFORMATION                  |\\\n                                   PROCESS_QUERY_LIMITED_INFORMATION          |\\\n                                   PROCESS_VM_READ)\n\n#define KPH_THREAD_READ_ACCESS    (STANDARD_RIGHTS_READ                       |\\\n                                   SYNCHRONIZE                                |\\\n                                   THREAD_QUERY_INFORMATION                   |\\\n                                   THREAD_QUERY_LIMITED_INFORMATION           |\\\n                                   THREAD_GET_CONTEXT)\n\n#define KPH_TOKEN_READ_ACCESS     (STANDARD_RIGHTS_READ                       |\\\n                                   SYNCHRONIZE                                |\\\n                                   TOKEN_QUERY                                |\\\n                                   TOKEN_QUERY_SOURCE)\n\n#define KPH_JOB_READ_ACCESS       (STANDARD_RIGHTS_READ                       |\\\n                                   SYNCHRONIZE                                |\\\n                                   JOB_OBJECT_QUERY)\n\n#define KPH_FILE_READ_ACCESS      (STANDARD_RIGHTS_READ                       |\\\n                                   SYNCHRONIZE                                |\\\n                                   FILE_READ_DATA                             |\\\n                                   FILE_READ_ATTRIBUTES                       |\\\n                                   FILE_READ_EA)\n\n#define KPH_FILE_READ_DISPOSITION (FILE_OPEN)\n\n#define KPH_SECTION_READ_ACCESS   (SECTION_MAP_READ | SECTION_QUERY)\n\n// Informer\n\ntypedef struct _KPH_RATE_LIMIT_POLICY\n{\n    ULONG TokensPerPeriod;\n    ULONG PeriodInSeconds;\n    ULONG MaxBucketSize;\n} KPH_RATE_LIMIT_POLICY, *PKPH_RATE_LIMIT_POLICY;\ntypedef const KPH_RATE_LIMIT_POLICY* PCKPH_RATE_LIMIT_POLICY;\n\n#define KPH_RATE_LIMIT_UNLIMITED             { ULONG_MAX, 0, ULONG_MAX }\n#define KPH_RATE_LIMIT_DENY_ALL              { 0, 0, 0 }\n#define KPH_RATE_LIMIT_PER_SEC(rate, burst)  { rate, 1, burst }\n#define KPH_RATE_LIMIT_PER_MIN(rate, burst)  { rate, 60, burst }\n#define KPH_RATE_LIMIT_PER_HOUR(rate, burst) { rate, 3600, burst }\n#define KPH_RATE_LIMIT_PER_DAY(rate, burst)  { rate, 86400, burst }\n\n#define KPH_INFORMER_COUNT       153\n#define KPH_INFORMER_INDEX(name) (KphMsg##name - (MaxKphMsgClientAllowed + 1))\n\ntypedef union _KPH_INFORMER_OPTIONS\n{\n    struct\n    {\n        ULONG EnableStackTraces : 1;\n        ULONG EnableProcessCreateReply : 1;\n        ULONG FileEnablePreCreateReply : 1;\n        ULONG FileEnablePostCreateReply : 1;\n        ULONG FileEnablePostFileNames : 1;\n        ULONG FileEnablePagingIo : 1;\n        ULONG FileEnableSyncPagingIo : 1;\n        ULONG FileEnableIoControlBuffers : 1;\n        ULONG FileEnableFsControlBuffers : 1;\n        ULONG FileEnableDirControlBuffers : 1;\n        ULONG RegEnablePostObjectNames : 1;\n        ULONG RegEnablePostValueNames : 1;\n        ULONG RegEnableValueBuffers : 1;\n        ULONG Spare : 19;\n    };\n\n    ULONG Flags;\n} KPH_INFORMER_OPTIONS, *PKPH_INFORMER_OPTIONS;\n\ntypedef struct _KPH_INFORMER_SETTINGS\n{\n    KPH_INFORMER_OPTIONS Options;\n    KPH_RATE_LIMIT_POLICY Policy[KPH_INFORMER_COUNT];\n} KPH_INFORMER_SETTINGS, *PKPH_INFORMER_SETTINGS;\ntypedef const KPH_INFORMER_SETTINGS* PCKPH_INFORMER_SETTINGS;\n\ntypedef struct _KPH_MESSAGE_TIMEOUTS\n{\n    LARGE_INTEGER AsyncTimeout;\n    LARGE_INTEGER DefaultTimeout;\n    LARGE_INTEGER ProcessCreateTimeout;\n    LARGE_INTEGER FilePreCreateTimeout;\n    LARGE_INTEGER FilePostCreateTimeout;\n} KPH_MESSAGE_TIMEOUTS, *PKPH_MESSAGE_TIMEOUTS;\n\ntypedef struct _KPH_INFORMER_CLIENT_SETTINGS\n{\n    KPH_MESSAGE_TIMEOUTS MessageTimeouts;\n    KPH_RATE_LIMIT_POLICY AsyncQueuePolicy;\n    KPH_RATE_LIMIT_POLICY InformerPolicy[KPH_INFORMER_COUNT];\n} KPH_INFORMER_CLIENT_SETTINGS, *PKPH_INFORMER_CLIENT_SETTINGS;\n\ntypedef struct _KPH_RATE_LIMIT_STATS\n{\n    KPH_RATE_LIMIT_POLICY Policy;\n    LONG64 Allowed;\n    LONG64 Dropped;\n    LONG64 CasMiss;\n} KPH_RATE_LIMIT_STATS, *PKPH_RATE_LIMIT_STATS;\n\ntypedef struct _KPH_INFORMER_CLIENT_STATS\n{\n    KPH_RATE_LIMIT_STATS AsyncQueueRateLimit;\n    KPH_RATE_LIMIT_STATS InformerRateLimit[KPH_INFORMER_COUNT];\n} KPH_INFORMER_CLIENT_STATS, *PKPH_INFORMER_CLIENT_STATS;\n\ntypedef struct _KPH_INFORMER_STATS\n{\n    KPH_RATE_LIMIT_STATS RateLimit[KPH_INFORMER_COUNT];\n} KPH_INFORMER_STATS, *PKPH_INFORMER_STATS;\n\n// Parameters\n\ntypedef union _KPH_PARAMETER_FLAGS\n{\n    struct\n    {\n        ULONG DisableImageLoadProtection : 1;\n        ULONG RandomizedPoolTag : 1;\n        ULONG DynDataNoEmbedded : 1;\n        ULONG DisableSystemProcess : 1;\n        ULONG DisableThreadNames : 1;\n        ULONG Reserved : 27;\n    };\n\n    ULONG Flags;\n} KPH_PARAMETER_FLAGS, *PKPH_PARAMETER_FLAGS;\n\n// Session Token\n\n#define KPH_TOKEN_PRIVILEGE_TERMINATE 0x00000001ul\n#define KPH_TOKEN_VALID_PRIVILEGES    (KPH_TOKEN_PRIVILEGE_TERMINATE)\n\n#include <pshpack1.h>\ntypedef struct _KPH_SESSION_ACCESS_TOKEN\n{\n    LARGE_INTEGER Expiry;\n    ULONG Privileges;\n    LONG Uses;\n    GUID Identifier;\n    BYTE Material[32];\n} KPH_SESSION_ACCESS_TOKEN, *PKPH_SESSION_ACCESS_TOKEN;\nC_ASSERT(sizeof(KPH_SESSION_ACCESS_TOKEN) == 64);\n#include <poppack.h>\n\n#pragma warning(pop)\n"
  },
  {
    "path": "kphlib/include/kphdyn.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * THIS IS AN AUTOGENERATED FILE, DO NOT MODIFY\n *\n */\n\n#pragma once\n\n#include <kphlibbase.h>\n#define KPH_DYN_CONFIGURATION_VERSION           ((ULONG)16)\n#define KPH_DYN_SESSION_TOKEN_PUBLIC_KEY_LENGTH ((ULONG)539)\n#define KPH_DYN_CLASS_NTOSKRNL                  ((USHORT)0)\n#define KPH_DYN_CLASS_NTKRLA57                  ((USHORT)1)\n#define KPH_DYN_CLASS_LXCORE                    ((USHORT)2)\n\n#include <pshpack1.h>\n\ntypedef struct _KPH_DYN_KERNEL_FIELDS\n{\n    USHORT EgeGuid;                      // dt nt!_ETW_GUID_ENTRY Guid\n    USHORT EpObjectTable;                // dt nt!_EPROCESS ObjectTable\n    USHORT EreGuidEntry;                 // dt nt!_ETW_REG_ENTRY GuidEntry\n    USHORT HtHandleContentionEvent;      // dt nt!_HANDLE_TABLE HandleContentionEvent\n    USHORT OtName;                       // dt nt!_OBJECT_TYPE Name\n    USHORT OtIndex;                      // dt nt!_OBJECT_TYPE Index\n    USHORT ObDecodeShift;                // dt nt!_HANDLE_TABLE_ENTRY ObjectPointerBits\n    USHORT ObAttributesShift;            // dt nt!_HANDLE_TABLE_ENTRY Attributes\n    USHORT AlpcCommunicationInfo;        // dt nt!_ALPC_PORT CommunicationInfo\n    USHORT AlpcOwnerProcess;             // dt nt!_ALPC_PORT OwnerProcess\n    USHORT AlpcConnectionPort;           // dt nt!_ALPC_COMMUNICATION_INFO ConnectionPort\n    USHORT AlpcServerCommunicationPort;  // dt nt!_ALPC_COMMUNICATION_INFO ServerCommunicationPort\n    USHORT AlpcClientCommunicationPort;  // dt nt!_ALPC_COMMUNICATION_INFO ClientCommunicationPort\n    USHORT AlpcHandleTable;              // dt nt!_ALPC_COMMUNICATION_INFO HandleTable\n    USHORT AlpcHandleTableLock;          // dt nt!_ALPC_HANDLE_TABLE Lock\n    USHORT AlpcAttributes;               // dt nt!_ALPC_PORT PortAttributes\n    USHORT AlpcAttributesFlags;          // dt nt!_ALPC_PORT_ATTRIBUTES Flags\n    USHORT AlpcPortContext;              // dt nt!_ALPC_PORT PortContext\n    USHORT AlpcPortObjectLock;           // dt nt!_ALPC_PORT PortObjectLock\n    USHORT AlpcSequenceNo;               // dt nt!_ALPC_PORT SequenceNo\n    USHORT AlpcState;                    // dt nt!_ALPC_PORT u1.State\n    USHORT KtInitialStack;               // dt nt!_KTHREAD InitialStack\n    USHORT KtStackLimit;                 // dt nt!_KTHREAD StackLimit\n    USHORT KtStackBase;                  // dt nt!_KTHREAD StackBase\n    USHORT KtKernelStack;                // dt nt!_KTHREAD KernelStack\n    USHORT KtReadOperationCount;         // dt nt!_KTHREAD ReadOperationCount\n    USHORT KtWriteOperationCount;        // dt nt!_KTHREAD WriteOperationCount\n    USHORT KtOtherOperationCount;        // dt nt!_KTHREAD OtherOperationCount\n    USHORT KtReadTransferCount;          // dt nt!_KTHREAD ReadTransferCount\n    USHORT KtWriteTransferCount;         // dt nt!_KTHREAD WriteTransferCount\n    USHORT KtOtherTransferCount;         // dt nt!_KTHREAD OtherTransferCount\n    USHORT MmSectionControlArea;         // dt nt!_SECTION u1.ControlArea\n    USHORT MmControlAreaListHead;        // dt nt!_CONTROL_AREA ListHead\n    USHORT MmControlAreaLock;            // dt nt!_CONTROL_AREA ControlAreaLock\n    USHORT EpSectionObject;              // dt nt!_EPROCESS SectionObject\n} KPH_DYN_KERNEL_FIELDS, *PKPH_DYN_KERNEL_FIELDS;\n\ntypedef KPH_DYN_KERNEL_FIELDS KPH_DYN_NTOSKRNL_FIELDS;\ntypedef PKPH_DYN_KERNEL_FIELDS PKPH_DYN_NTOSKRNL_FIELDS;\ntypedef KPH_DYN_KERNEL_FIELDS KPH_DYN_NTKRLA57_FIELDS;\ntypedef PKPH_DYN_KERNEL_FIELDS PKPH_DYN_NTKRLA57_FIELDS;\n\ntypedef struct _KPH_DYN_LXCORE_FIELDS\n{\n    USHORT LxPicoProc;                   // uf lxcore!LxpSyscall_GETPID\n    USHORT LxPicoProcInfo;               // uf lxcore!LxpSyscall_GETPID\n    USHORT LxPicoProcInfoPID;            // uf lxcore!LxpSyscall_GETPID\n    USHORT LxPicoThrdInfo;               // uf lxcore!LxpSyscall_GETTID\n    USHORT LxPicoThrdInfoTID;            // uf lxcore!LxpSyscall_GETTID\n} KPH_DYN_LXCORE_FIELDS, *PKPH_DYN_LXCORE_FIELDS;\n\ntypedef struct _KPH_DYN_FIELDS\n{\n    ULONG FieldsId;\n    USHORT Length;\n    BYTE Fields[ANYSIZE_ARRAY];\n} KPH_DYN_FIELDS, *PKPH_DYN_FIELDS;\n\ntypedef struct _KPH_DYN_DATA\n{\n    USHORT Class;\n    USHORT Machine;\n    ULONG TimeDateStamp;\n    ULONG SizeOfImage;\n    ULONG Offset;\n} KPH_DYN_DATA, *PKPH_DYN_DATA;\n\ntypedef struct _KPH_DYN_CONFIG\n{\n    ULONG Version;\n    BYTE SessionTokenPublicKey[KPH_DYN_SESSION_TOKEN_PUBLIC_KEY_LENGTH];\n    ULONG Count;\n    KPH_DYN_DATA Data[ANYSIZE_ARRAY];\n    // BYTE Fields[ANYSIZE_ARRAY];\n} KPH_DYN_CONFIG, *PKPH_DYN_CONFIG;\n\n#include <poppack.h>\n\n#ifdef _WIN64\nextern CONST BYTE KphDynConfig[];\nextern CONST ULONG KphDynConfigLength;\n#endif\n"
  },
  {
    "path": "kphlib/include/kphdyndata.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n\n#pragma once\n\n#include <kphdyn.h>\n\n_Must_inspect_result_\nNTSTATUS KphDynDataLookup(\n    _In_reads_bytes_(Length) PKPH_DYN_CONFIG Config,\n    _In_ ULONG Length,\n    _In_ USHORT Class,\n    _In_ USHORT Machine,\n    _In_ ULONG TimeDateStamp,\n    _In_ ULONG SizeOfImage,\n    _Out_opt_ PKPH_DYN_DATA* Data,\n    _Out_opt_ PVOID* Fields\n    );\n"
  },
  {
    "path": "kphlib/include/kphlibbase.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n\n#include <sistatus.h>\n\n#ifdef _KERNEL_MODE\n#pragma warning(push)\n#pragma warning(disable: 5103) // invalid preprocessing token (/Zc:preprocessor)\n#include <ntifs.h>\n#include <ntintsafe.h>\n#include <minwindef.h>\n#include <ntstrsafe.h>\n#include <fltKernel.h>\n#pragma warning(pop)\n#else\n#pragma warning(push)\n#pragma warning(disable : 4201)\n#pragma warning(disable : 4214)\n#pragma warning(disable : 4324)\n#pragma warning(disable : 4115)\n#include <phnt_windows.h>\n#include <phnt.h>\n#pragma warning(pop)\n#endif\n"
  },
  {
    "path": "kphlib/include/kphmsg.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n\n#include <kphmsgdefs.h>\n\n#pragma warning(push)\n#pragma warning(disable : 4201)\n\ntypedef enum _KPH_MESSAGE_ID\n{\n    InvalidKphMsg,\n\n    //\n    // PH -> KPH\n    //\n\n    KphMsgGetInformerSettings,\n    KphMsgSetInformerSettings,\n    KphMsgOpenProcess,\n    KphMsgOpenProcessToken,\n    KphMsgOpenProcessJob,\n    KphMsgTerminateProcess,\n    KphMsgReadVirtualMemory,\n    KphMsgOpenThread,\n    KphMsgOpenThreadProcess,\n    KphMsgCaptureStackBackTraceThread,\n    KphMsgEnumerateProcessHandles,\n    KphMsgQueryInformationObject,\n    KphMsgSetInformationObject,\n    KphMsgOpenDriver,\n    KphMsgQueryInformationDriver,\n    KphMsgQueryInformationProcess,\n    KphMsgSetInformationProcess,\n    KphMsgSetInformationThread,\n    KphMsgSystemControl,\n    KphMsgAlpcQueryInformation,\n    KphMsgQueryInformationFile,\n    KphMsgQueryVolumeInformationFile,\n    KphMsgDuplicateObject,\n    KphMsgQueryPerformanceCounter,\n    KphMsgCreateFile,\n    KphMsgQueryInformationThread,\n    KphMsgQuerySection,\n    KphMsgCompareObjects,\n    KphMsgGetInformerClientSettings,\n    KphMsgSetInformerClientSettings,\n    KphMsgAcquireDriverUnloadProtection,\n    KphMsgReleaseDriverUnloadProtection,\n    KphMsgGetConnectedClientCount,\n    KphMsgActivateDynData,\n    KphMsgIsDynDataActive,\n    KphMsgRequestSessionAccessToken,\n    KphMsgAssignProcessSessionToken,\n    KphMsgAssignThreadSessionToken,\n    KphMsgGetInformerProcessSettings,\n    KphMsgSetInformerProcessSettings,\n    KphMsgStripProtectedProcessMasks,\n    KphMsgQueryVirtualMemory,\n    KphMsgQueryHashInformationFile,\n    KphMsgOpenDevice,\n    KphMsgOpenDeviceDriver,\n    KphMsgOpenDeviceBaseDevice,\n    KphMsgGetInformerStats,\n    KphMsgGetInformerClientStats,\n\n    MaxKphMsgClient,\n    MaxKphMsgClientAllowed = 0x40000000,\n\n    //\n    // KPH <-> PH\n    //\n\n    KphMsgProcessCreate,\n    KphMsgProcessExit,\n    KphMsgThreadCreate,\n    KphMsgThreadExecute,\n    KphMsgThreadExit,\n    KphMsgImageLoad,\n    KphMsgDebugPrint,\n    KphMsgHandlePreCreateProcess,\n    KphMsgHandlePostCreateProcess,\n    KphMsgHandlePreDuplicateProcess,\n    KphMsgHandlePostDuplicateProcess,\n    KphMsgHandlePreCreateThread,\n    KphMsgHandlePostCreateThread,\n    KphMsgHandlePreDuplicateThread,\n    KphMsgHandlePostDuplicateThread,\n    KphMsgHandlePreCreateDesktop,\n    KphMsgHandlePostCreateDesktop,\n    KphMsgHandlePreDuplicateDesktop,\n    KphMsgHandlePostDuplicateDesktop,\n    KphMsgRequiredStateFailure,\n    KphMsgFilePreCreate,\n    KphMsgFilePostCreate,\n    KphMsgFilePreCreateNamedPipe,\n    KphMsgFilePostCreateNamedPipe,\n    KphMsgFilePreClose,\n    KphMsgFilePostClose,\n    KphMsgFilePreRead,\n    KphMsgFilePostRead,\n    KphMsgFilePreWrite,\n    KphMsgFilePostWrite,\n    KphMsgFilePreQueryInformation,\n    KphMsgFilePostQueryInformation,\n    KphMsgFilePreSetInformation,\n    KphMsgFilePostSetInformation,\n    KphMsgFilePreQueryEa,\n    KphMsgFilePostQueryEa,\n    KphMsgFilePreSetEa,\n    KphMsgFilePostSetEa,\n    KphMsgFilePreFlushBuffers,\n    KphMsgFilePostFlushBuffers,\n    KphMsgFilePreQueryVolumeInformation,\n    KphMsgFilePostQueryVolumeInformation,\n    KphMsgFilePreSetVolumeInformation,\n    KphMsgFilePostSetVolumeInformation,\n    KphMsgFilePreDirectoryControl,\n    KphMsgFilePostDirectoryControl,\n    KphMsgFilePreFileSystemControl,\n    KphMsgFilePostFileSystemControl,\n    KphMsgFilePreDeviceControl,\n    KphMsgFilePostDeviceControl,\n    KphMsgFilePreInternalDeviceControl,\n    KphMsgFilePostInternalDeviceControl,\n    KphMsgFilePreShutdown,\n    KphMsgFilePostShutdown,\n    KphMsgFilePreLockControl,\n    KphMsgFilePostLockControl,\n    KphMsgFilePreCleanup,\n    KphMsgFilePostCleanup,\n    KphMsgFilePreCreateMailslot,\n    KphMsgFilePostCreateMailslot,\n    KphMsgFilePreQuerySecurity,\n    KphMsgFilePostQuerySecurity,\n    KphMsgFilePreSetSecurity,\n    KphMsgFilePostSetSecurity,\n    KphMsgFilePrePower,\n    KphMsgFilePostPower,\n    KphMsgFilePreSystemControl,\n    KphMsgFilePostSystemControl,\n    KphMsgFilePreDeviceChange,\n    KphMsgFilePostDeviceChange,\n    KphMsgFilePreQueryQuota,\n    KphMsgFilePostQueryQuota,\n    KphMsgFilePreSetQuota,\n    KphMsgFilePostSetQuota,\n    KphMsgFilePrePnp,\n    KphMsgFilePostPnp,\n    KphMsgFilePreAcquireForSectionSync,\n    KphMsgFilePostAcquireForSectionSync,\n    KphMsgFilePreReleaseForSectionSync,\n    KphMsgFilePostReleaseForSectionSync,\n    KphMsgFilePreAcquireForModWrite,\n    KphMsgFilePostAcquireForModWrite,\n    KphMsgFilePreReleaseForModWrite,\n    KphMsgFilePostReleaseForModWrite,\n    KphMsgFilePreAcquireForCcFlush,\n    KphMsgFilePostAcquireForCcFlush,\n    KphMsgFilePreReleaseForCcFlush,\n    KphMsgFilePostReleaseForCcFlush,\n    KphMsgFilePreQueryOpen,\n    KphMsgFilePostQueryOpen,\n    KphMsgFilePreFastIoCheckIfPossible,\n    KphMsgFilePostFastIoCheckIfPossible,\n    KphMsgFilePreNetworkQueryOpen,\n    KphMsgFilePostNetworkQueryOpen,\n    KphMsgFilePreMdlRead,\n    KphMsgFilePostMdlRead,\n    KphMsgFilePreMdlReadComplete,\n    KphMsgFilePostMdlReadComplete,\n    KphMsgFilePrePrepareMdlWrite,\n    KphMsgFilePostPrepareMdlWrite,\n    KphMsgFilePreMdlWriteComplete,\n    KphMsgFilePostMdlWriteComplete,\n    KphMsgFilePreVolumeMount,\n    KphMsgFilePostVolumeMount,\n    KphMsgFilePreVolumeDismount,\n    KphMsgFilePostVolumeDismount,\n    KphMsgRegPreDeleteKey,\n    KphMsgRegPostDeleteKey,\n    KphMsgRegPreSetValueKey,\n    KphMsgRegPostSetValueKey,\n    KphMsgRegPreDeleteValueKey,\n    KphMsgRegPostDeleteValueKey,\n    KphMsgRegPreSetInformationKey,\n    KphMsgRegPostSetInformationKey,\n    KphMsgRegPreRenameKey,\n    KphMsgRegPostRenameKey,\n    KphMsgRegPreEnumerateKey,\n    KphMsgRegPostEnumerateKey,\n    KphMsgRegPreEnumerateValueKey,\n    KphMsgRegPostEnumerateValueKey,\n    KphMsgRegPreQueryKey,\n    KphMsgRegPostQueryKey,\n    KphMsgRegPreQueryValueKey,\n    KphMsgRegPostQueryValueKey,\n    KphMsgRegPreQueryMultipleValueKey,\n    KphMsgRegPostQueryMultipleValueKey,\n    KphMsgRegPreKeyHandleClose,\n    KphMsgRegPostKeyHandleClose,\n    KphMsgRegPreCreateKey,\n    KphMsgRegPostCreateKey,\n    KphMsgRegPreOpenKey,\n    KphMsgRegPostOpenKey,\n    KphMsgRegPreFlushKey,\n    KphMsgRegPostFlushKey,\n    KphMsgRegPreLoadKey,\n    KphMsgRegPostLoadKey,\n    KphMsgRegPreUnLoadKey,\n    KphMsgRegPostUnLoadKey,\n    KphMsgRegPreQueryKeySecurity,\n    KphMsgRegPostQueryKeySecurity,\n    KphMsgRegPreSetKeySecurity,\n    KphMsgRegPostSetKeySecurity,\n    KphMsgRegPreRestoreKey,\n    KphMsgRegPostRestoreKey,\n    KphMsgRegPreSaveKey,\n    KphMsgRegPostSaveKey,\n    KphMsgRegPreReplaceKey,\n    KphMsgRegPostReplaceKey,\n    KphMsgRegPreQueryKeyName,\n    KphMsgRegPostQueryKeyName,\n    KphMsgRegPreSaveMergedKey,\n    KphMsgRegPostSaveMergedKey,\n    KphMsgImageVerify,\n\n    MaxKphMsg,\n\n    KphMsgUnhandled = 0xffffffff,\n} KPH_MESSAGE_ID, *PKPH_MESSAGE_ID;\n\nC_ASSERT(sizeof(KPH_MESSAGE_ID) == 4);\nC_ASSERT(MaxKphMsg > 0);\nC_ASSERT(KPH_INFORMER_COUNT == (MaxKphMsg - (MaxKphMsgClientAllowed + 1)));\n\ntypedef enum _KPH_MESSAGE_FIELD_ID\n{\n    InvalidKphMsgField,\n\n    KphMsgFieldFileName,\n    KphMsgFieldCommandLine,\n    KphMsgFieldOutput,\n    KphMsgFieldObjectName,\n    KphMsgFieldStackTrace,\n    KphMsgFieldDestinationFileName,\n    KphMsgFieldEaBuffer,\n    KphMsgFieldInformationBuffer,\n    KphMsgFieldInput,\n    KphMsgFieldValueName,\n    KphMsgFieldValueBuffer,\n    KphMsgFieldMultipleValueNames,\n    KphMsgFieldMultipleValueEntries,\n    KphMsgFieldNewName,\n    KphMsgFieldClass,\n    KphMsgFieldOtherObjectName,\n    KphMsgFieldHash,\n    KphMsgFieldRegistryPath,\n    KphMsgFieldCertificatePublisher,\n    KphMsgFieldCertificateIssuer,\n    KphMsgFieldCertificateThumbprint,\n\n    MaxKphMsgField\n} KPH_MESSAGE_FIELD_ID, *PKPH_MESSAGE_FIELD_ID;\n\nC_ASSERT(sizeof(KPH_MESSAGE_FIELD_ID) == 4);\nC_ASSERT(MaxKphMsgField > 0);\n\ntypedef enum _KPH_MESSAGE_TYPE_ID\n{\n    InvalidKphMsgType,\n\n    KphMsgTypeUnicodeString,\n    KphMsgTypeAnsiString,\n    KphMsgTypeStackTrace,\n    KphMsgTypeSizedBuffer,\n\n    MaxKphMsgType\n} KPH_MESSAGE_TYPE_ID, *PKPH_MESSAGE_TYPE_ID;\n\nC_ASSERT(sizeof(KPH_MESSAGE_TYPE_ID) == 4);\nC_ASSERT(MaxKphMsgType > 0);\n\ntypedef struct _KPH_MESSAGE_DYNAMIC_TABLE_ENTRY\n{\n    KPH_MESSAGE_FIELD_ID FieldId;\n    KPH_MESSAGE_TYPE_ID TypeId;\n    USHORT Offset;\n    USHORT Length;\n} KPH_MESSAGE_DYNAMIC_TABLE_ENTRY, *PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY;\n\ntypedef const KPH_MESSAGE_DYNAMIC_TABLE_ENTRY* PCKPH_MESSAGE_DYNAMIC_TABLE_ENTRY;\n\ntypedef struct _KPH_MESSAGE\n{\n    struct\n    {\n        USHORT Version;\n        USHORT Size;\n        KPH_MESSAGE_ID MessageId;\n        LARGE_INTEGER TimeStamp;\n    } Header;\n\n    union\n    {\n        //\n        // Message from user\n        //\n        union\n        {\n            KPHM_GET_INFORMER_SETTINGS GetInformerSettings;\n            KPHM_SET_INFORMER_SETTINGS SetInformerSettings;\n            KPHM_OPEN_PROCESS OpenProcess;\n            KPHM_OPEN_PROCESS_TOKEN OpenProcessToken;\n            KPHM_OPEN_PROCESS_JOB OpenProcessJob;\n            KPHM_TERMINATE_PROCESS TerminateProcess;\n            KPHM_READ_VIRTUAL_MEMORY ReadVirtualMemory;\n            KPHM_OPEN_THREAD OpenThread;\n            KPHM_OPEN_THREAD_PROCESS OpenThreadProcess;\n            KPHM_CAPTURE_STACK_BACKTRACE_THREAD CaptureStackBackTraceThread;\n            KPHM_ENUMERATE_PROCESS_HANDLES EnumerateProcessHandles;\n            KPHM_QUERY_INFORMATION_OBJECT QueryInformationObject;\n            KPHM_SET_INFORMATION_OBJECT SetInformationObject;\n            KPHM_OPEN_DRIVER OpenDriver;\n            KPHM_QUERY_INFORMATION_DRIVER QueryInformationDriver;\n            KPHM_QUERY_INFORMATION_PROCESS QueryInformationProcess;\n            KPHM_SET_INFORMATION_PROCESS SetInformationProcess;\n            KPHM_SET_INFORMATION_THREAD SetInformationThread;\n            KPHM_SYSTEM_CONTROL SystemControl;\n            KPHM_ALPC_QUERY_INFORMATION AlpcQueryInformation;\n            KPHM_QUERY_INFORMATION_FILE QueryInformationFile;\n            KPHM_QUERY_VOLUME_INFORMATION_FILE QueryVolumeInformationFile;\n            KPHM_DUPLICATE_OBJECT DuplicateObject;\n            KPHM_QUERY_PERFORMANCE_COUNTER QueryPerformanceCounter;\n            KPHM_CREATE_FILE CreateFile;\n            KPHM_QUERY_INFORMATION_THREAD QueryInformationThread;\n            KPHM_QUERY_SECTION QuerySection;\n            KPHM_COMPARE_OBJECTS CompareObjects;\n            KPHM_GET_INFORMER_CLIENT_SETTINGS GetInformerClientSettings;\n            KPHM_SET_INFORMER_CLIENT_SETTINGS SetInformerClientSettings;\n            KPHM_ACQUIRE_DRIVER_UNLOAD_PROTECTION AcquireDriverUnloadProtection;\n            KPHM_RELEASE_DRIVER_UNLOAD_PROTECTION ReleaseDriverUnloadProtection;\n            KPHM_GET_CONNECTED_CLIENT_COUNT GetConnectedClientCount;\n            KPHM_ACTIVATE_DYNDATA ActivateDynData;\n            KPHM_IS_DYNDATA_ACTIVE IsDynDataActive;\n            KPHM_REQUEST_SESSION_ACCESS_TOKEN RequestSessionAccessToken;\n            KPHM_ASSIGN_PROCESS_SESSION_TOKEN AssignProcessSessionToken;\n            KPHM_ASSIGN_THREAD_SESSION_TOKEN AssignThreadSessionToken;\n            KPHM_GET_INFORMER_PROCESS_SETTINGS GetInformerProcessSettings;\n            KPHM_SET_INFORMER_PROCESS_SETTINGS SetInformerProcessSettings;\n            KPHM_STRIP_PROTECTED_PROCESS_MASKS StripProtectedProcessMasks;\n            KPHM_QUERY_VIRTUAL_MEMORY QueryVirtualMemory;\n            KPHM_QUERY_HASH_INFORMATION_FILE QueryHashInformationFile;\n            KPHM_OPEN_DEVICE OpenDevice;\n            KPHM_OPEN_DEVICE_DRIVER OpenDeviceDriver;\n            KPHM_OPEN_DEVICE_BASE_DEVICE OpenDeviceBaseDevice;\n            KPHM_GET_INFORMER_STATS GetInformerStats;\n            KPHM_GET_INFORMER_CLIENT_STATS GetInformerClientStats;\n        } User;\n\n        //\n        // Message from kernel\n        //\n        union\n        {\n            KPHM_PROCESS_CREATE ProcessCreate;\n            KPHM_PROCESS_EXIT ProcessExit;\n            KPHM_THREAD_CREATE ThreadCreate;\n            KPHM_THREAD_EXECUTE ThreadExecute;\n            KPHM_THREAD_EXIT ThreadExit;\n            KPHM_IMAGE_LOAD ImageLoad;\n            KPHM_DEBUG_PRINT DebugPrint;\n            KPHM_HANDLE Handle;\n            KPHM_REQUIRED_STATE_FAILURE RequiredStateFailure;\n            KPHM_FILE File;\n            KPHM_REGISTRY Reg;\n            KPHM_IMAGE_VERIFY ImageVerify;\n        } Kernel;\n\n        //\n        // Reply to kernel\n        //\n        union\n        {\n            KPHM_PROCESS_CREATE_REPLY ProcessCreate;\n            KPHM_FILE_REPLY File;\n        } Reply;\n    };\n\n    //\n    // Dynamic data accessed through KphMsgDyn APIs\n    //\n    struct\n    {\n        UCHAR Count;\n        KPH_MESSAGE_DYNAMIC_TABLE_ENTRY Entries[8];\n        CHAR Buffer[0x4000 - 380];\n    } _Dyn;\n} KPH_MESSAGE, *PKPH_MESSAGE;\ntypedef const KPH_MESSAGE* PCKPH_MESSAGE;\n\n#define KPH_MESSAGE_MIN_SIZE RTL_SIZEOF_THROUGH_FIELD(KPH_MESSAGE, _Dyn.Entries)\n\n//\n// ABI breaking asserts. KPH_MESSAGE_VERSION must be updated.\n// const int value = sizeof(KPH_MESSAGE);\n// const int value = FIELD_OFFSET(KPH_MESSAGE, _Dyn);\n// const int value = FIELD_OFFSET(KPH_MESSAGE, _Dyn.Buffer);\n// const int value = KPH_MESSAGE_MIN_SIZE;\n//\nC_ASSERT(sizeof(KPH_MESSAGE) <= 0xffff);\n#ifdef _WIN64\nC_ASSERT(sizeof(KPH_MESSAGE) == 0x4000);\nC_ASSERT(FIELD_OFFSET(KPH_MESSAGE, _Dyn) == 280);\nC_ASSERT(FIELD_OFFSET(KPH_MESSAGE, _Dyn.Buffer) == 380);\nC_ASSERT(KPH_MESSAGE_MIN_SIZE == 380);\nC_ASSERT(KPH_MESSAGE_MIN_SIZE == FIELD_OFFSET(KPH_MESSAGE, _Dyn.Buffer));\n#else\n// not supported\n#endif\n\n#pragma warning(pop)\n\nEXTERN_C_START\n\nVOID KphMsgQuerySystemTime(\n    _Out_ PLARGE_INTEGER SystemTime\n    );\n\nVOID KphMsgInit(\n    _Out_writes_bytes_(KPH_MESSAGE_MIN_SIZE) PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_ID MessageId\n    );\n\n_Must_inspect_result_\nNTSTATUS KphMsgValidate(\n    _In_ PCKPH_MESSAGE Message\n    );\n\nEXTERN_C_END\n"
  },
  {
    "path": "kphlib/include/kphmsgdefs.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n\n#include <kphapi.h>\n\n//\n// PH -> KPH\n//\n\n#pragma warning(push)\n#pragma warning(disable : 4201)\n\ntypedef struct _KPHM_SET_INFORMER_SETTINGS\n{\n    NTSTATUS Status;\n    PKPH_INFORMER_SETTINGS Settings;\n} KPHM_SET_INFORMER_SETTINGS, *PKPHM_SET_INFORMER_SETTINGS;\n\ntypedef struct _KPHM_GET_INFORMER_SETTINGS\n{\n    NTSTATUS Status;\n    PKPH_INFORMER_SETTINGS Settings;\n} KPHM_GET_INFORMER_SETTINGS, *PKPHM_GET_INFORMER_SETTINGS;\n\ntypedef struct _KPHM_OPEN_PROCESS\n{\n    NTSTATUS Status;\n    PHANDLE ProcessHandle;\n    ACCESS_MASK DesiredAccess;\n    PCLIENT_ID ClientId;\n} KPHM_OPEN_PROCESS, *PKPHM_OPEN_PROCESS;\n\ntypedef struct _KPHM_OPEN_PROCESS_TOKEN\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    ACCESS_MASK DesiredAccess;\n    PHANDLE TokenHandle;\n} KPHM_OPEN_PROCESS_TOKEN, *PKPHM_OPEN_PROCESS_TOKEN;\n\ntypedef struct _KPHM_OPEN_PROCESS_JOB\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    ACCESS_MASK DesiredAccess;\n    PHANDLE JobHandle;\n} KPHM_OPEN_PROCESS_JOB, *PKPHM_OPEN_PROCESS_JOB;\n\ntypedef struct _KPHM_TERMINATE_PROCESS\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    NTSTATUS ExitStatus;\n} KPHM_TERMINATE_PROCESS, *PKPHM_TERMINATE_PROCESS;\n\ntypedef struct _KPHM_READ_VIRTUAL_MEMORY\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    PVOID BaseAddress;\n    PVOID Buffer;\n    SIZE_T BufferSize;\n    PSIZE_T NumberOfBytesRead;\n} KPHM_READ_VIRTUAL_MEMORY, *PKPHM_READ_VIRTUAL_MEMORY;\n\ntypedef struct _KPHM_OPEN_THREAD\n{\n    NTSTATUS Status;\n    PHANDLE ThreadHandle;\n    ACCESS_MASK DesiredAccess;\n    PCLIENT_ID ClientId;\n} KPHM_OPEN_THREAD, *PKPHM_OPEN_THREAD;\n\ntypedef struct _KPHM_OPEN_THREAD_PROCESS\n{\n    NTSTATUS Status;\n    HANDLE ThreadHandle;\n    ACCESS_MASK DesiredAccess;\n    PHANDLE ProcessHandle;\n} KPHM_OPEN_THREAD_PROCESS, *PKPHM_OPEN_THREAD_PROCESS;\n\ntypedef struct _KPHM_CAPTURE_STACK_BACKTRACE_THREAD\n{\n    NTSTATUS Status;\n    HANDLE ThreadHandle;\n    ULONG FramesToSkip;\n    ULONG FramesToCapture;\n    PVOID* BackTrace;\n    PULONG CapturedFrames;\n    PULONG BackTraceHash;\n    ULONG Flags;\n    PLARGE_INTEGER Timeout;\n} KPHM_CAPTURE_STACK_BACKTRACE_THREAD, *PKPHM_CAPTURE_STACK_BACKTRACE_THREAD;\n\ntypedef struct _KPHM_ENUMERATE_PROCESS_HANDLES\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    PVOID Buffer;\n    ULONG BufferLength;\n    PULONG ReturnLength;\n} KPHM_ENUMERATE_PROCESS_HANDLES, *PKPHM_ENUMERATE_PROCESS_HANDLES;\n\ntypedef struct _KPHM_QUERY_INFORMATION_OBJECT\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    HANDLE Handle;\n    KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;\n    PVOID ObjectInformation;\n    ULONG ObjectInformationLength;\n    PULONG ReturnLength;\n} KPHM_QUERY_INFORMATION_OBJECT, *PKPHM_QUERY_INFORMATION_OBJECT;\n\ntypedef struct _KPHM_SET_INFORMATION_OBJECT\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    HANDLE Handle;\n    KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;\n    PVOID ObjectInformation;\n    ULONG ObjectInformationLength;\n} KPHM_SET_INFORMATION_OBJECT, *PKPHM_SET_INFORMATION_OBJECT;\n\ntypedef struct _KPHM_OPEN_DRIVER\n{\n    NTSTATUS Status;\n    PHANDLE DriverHandle;\n    ACCESS_MASK DesiredAccess;\n    POBJECT_ATTRIBUTES ObjectAttributes;\n} KPHM_OPEN_DRIVER, *PKPHM_OPEN_DRIVER;\n\ntypedef struct _KPHM_QUERY_INFORMATION_DRIVER\n{\n    NTSTATUS Status;\n    HANDLE DriverHandle;\n    KPH_DRIVER_INFORMATION_CLASS DriverInformationClass;\n    PVOID DriverInformation;\n    ULONG DriverInformationLength;\n    PULONG ReturnLength;\n} KPHM_QUERY_INFORMATION_DRIVER, *PKPHM_QUERY_INFORMATION_DRIVER;\n\ntypedef struct _KPHM_QUERY_INFORMATION_PROCESS\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;\n    PVOID ProcessInformation;\n    ULONG ProcessInformationLength;\n    PULONG ReturnLength;\n} KPHM_QUERY_INFORMATION_PROCESS, *PKPHM_QUERY_INFORMATION_PROCESS;\n\ntypedef struct _KPHM_SET_INFORMATION_PROCESS\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;\n    PVOID ProcessInformation;\n    ULONG ProcessInformationLength;\n} KPHM_SET_INFORMATION_PROCESS, *PKPHM_SET_INFORMATION_PROCESS;\n\ntypedef struct _KPHM_SET_INFORMATION_THREAD\n{\n    NTSTATUS Status;\n    HANDLE ThreadHandle;\n    KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;\n    PVOID ThreadInformation;\n    ULONG ThreadInformationLength;\n} KPHM_SET_INFORMATION_THREAD, *PKPHM_SET_INFORMATION_THREAD;\n\ntypedef struct _KPHM_SYSTEM_CONTROL\n{\n    NTSTATUS Status;\n    KPH_SYSTEM_CONTROL_CLASS SystemControlClass;\n    PVOID SystemControlInfo;\n    ULONG SystemControlInfoLength;\n} KPHM_SYSTEM_CONTROL, *PKPHM_SYSTEM_CONTROL;\n\ntypedef struct _KPHM_ALPC_QUERY_INFORMATION\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    HANDLE PortHandle;\n    KPH_ALPC_INFORMATION_CLASS AlpcInformationClass;\n    PVOID AlpcInformation;\n    ULONG AlpcInformationLength;\n    PULONG ReturnLength;\n} KPHM_ALPC_QUERY_INFORMATION, *PKPHM_ALPC_QUERY_INFORMATION;\n\ntypedef struct _KPHM_QUERY_INFORMATION_FILE\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    HANDLE FileHandle;\n    FILE_INFORMATION_CLASS FileInformationClass;\n    PVOID FileInformation;\n    ULONG FileInformationLength;\n    PIO_STATUS_BLOCK IoStatusBlock;\n} KPHM_QUERY_INFORMATION_FILE, *PKPHM_QUERY_INFORMATION_FILE;\n\ntypedef struct _KPHM_QUERY_VOLUME_INFORMATION_FILE\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    HANDLE FileHandle;\n    FS_INFORMATION_CLASS FsInformationClass;\n    PVOID FsInformation;\n    ULONG FsInformationLength;\n    PIO_STATUS_BLOCK IoStatusBlock;\n} KPHM_QUERY_VOLUME_INFORMATION_FILE, *PKPHM_QUERY_VOLUME_INFORMATION_FILE;\n\ntypedef struct _KPHM_DUPLICATE_OBJECT\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    HANDLE SourceHandle;\n    ACCESS_MASK DesiredAccess;\n    PHANDLE TargetHandle;\n} KPHM_DUPLICATE_OBJECT, *PKPHM_DUPLICATE_OBJECT;\n\ntypedef struct _KPHM_QUERY_PERFORMANCE_COUNTER\n{\n    LARGE_INTEGER PerformanceCounter;\n    LARGE_INTEGER PerformanceFrequency;\n} KPHM_QUERY_PERFORMANCE_COUNTER, *PKPHM_QUERY_PERFORMANCE_COUNTER;\n\ntypedef struct _KPHM_CREATE_FILE\n{\n    NTSTATUS Status;\n    PHANDLE FileHandle;\n    ACCESS_MASK DesiredAccess;\n    POBJECT_ATTRIBUTES ObjectAttributes;\n    PIO_STATUS_BLOCK IoStatusBlock;\n    PLARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG ShareAccess;\n    ULONG CreateDisposition;\n    ULONG CreateOptions;\n    PVOID EaBuffer;\n    ULONG EaLength;\n    ULONG Options;\n} KPHM_CREATE_FILE, *PKPHM_CREATE_FILE;\n\ntypedef struct _KPHM_QUERY_INFORMATION_THREAD\n{\n    NTSTATUS Status;\n    HANDLE ThreadHandle;\n    KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;\n    PVOID ThreadInformation;\n    ULONG ThreadInformationLength;\n    PULONG ReturnLength;\n} KPHM_QUERY_INFORMATION_THREAD, *PKPHM_QUERY_INFORMATION_THREAD;\n\ntypedef struct _KPHM_QUERY_SECTION\n{\n    NTSTATUS Status;\n    HANDLE SectionHandle;\n    KPH_SECTION_INFORMATION_CLASS SectionInformationClass;\n    PVOID SectionInformation;\n    ULONG SectionInformationLength;\n    PULONG ReturnLength;\n} KPHM_QUERY_SECTION, *PKPHM_QUERY_SECTION;\n\ntypedef struct _KPHM_COMPARE_OBJECTS\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    HANDLE FirstObjectHandle;\n    HANDLE SecondObjectHandle;\n} KPHM_COMPARE_OBJECTS, *PKPHM_COMPARE_OBJECTS;\n\ntypedef struct _KPHM_GET_INFORMER_CLIENT_SETTINGS\n{\n    NTSTATUS Status;\n    PKPH_INFORMER_CLIENT_SETTINGS Settings;\n} KPHM_GET_INFORMER_CLIENT_SETTINGS, *PKPHM_GET_INFORMER_CLIENT_SETTINGS;\n\ntypedef struct _KPHM_SET_INFORMER_CLIENT_SETTINGS\n{\n    NTSTATUS Status;\n    PKPH_INFORMER_CLIENT_SETTINGS Settings;\n} KPHM_SET_INFORMER_CLIENT_SETTINGS, *PKPHM_SET_INFORMER_CLIENT_SETTINGS;\n\ntypedef struct _KPHM_ACQUIRE_DRIVER_UNLOAD_PROTECTION\n{\n    NTSTATUS Status;\n    LONG PreviousCount;\n    LONG ClientPreviousCount;\n} KPHM_ACQUIRE_DRIVER_UNLOAD_PROTECTION, *PKPHM_ACQUIRE_DRIVER_UNLOAD_PROTECTION;\n\ntypedef struct _KPHM_RELEASE_DRIVER_UNLOAD_PROTECTION\n{\n    NTSTATUS Status;\n    LONG PreviousCount;\n    LONG ClientPreviousCount;\n} KPHM_RELEASE_DRIVER_UNLOAD_PROTECTION, *PKPHM_RELEASE_DRIVER_UNLOAD_PROTECTION;\n\ntypedef struct _KPHM_GET_CONNECTED_CLIENT_COUNT\n{\n    ULONG Count;\n} KPHM_GET_CONNECTED_CLIENT_COUNT, *PKPHM_GET_CONNECTED_CLIENT_COUNT;\n\ntypedef struct _KPHM_ACTIVATE_DYNDATA\n{\n    NTSTATUS Status;\n    PBYTE DynData;\n    ULONG DynDataLength;\n    PBYTE Signature;\n    ULONG SignatureLength;\n} KPHM_ACTIVATE_DYNDATA, *PKPHM_ACTIVATE_DYNDATA;\n\ntypedef struct _KPHM_IS_DYNDATA_ACTIVE\n{\n    NTSTATUS Status;\n    PBOOLEAN IsActive;\n} KPHM_IS_DYNDATA_ACTIVE, *PKPHM_IS_DYNDATA_ACTIVE;\n\ntypedef struct _KPHM_REQUEST_SESSION_ACCESS_TOKEN\n{\n    NTSTATUS Status;\n    KPH_SESSION_ACCESS_TOKEN AccessToken;\n    LARGE_INTEGER Expiry;\n    ULONG Privileges;\n    LONG Uses;\n} KPHM_REQUEST_SESSION_ACCESS_TOKEN, *PKPHM_REQUEST_SESSION_ACCESS_TOKEN;\n\ntypedef struct _KPHM_ASSIGN_PROCESS_SESSION_TOKEN\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    PBYTE Signature;\n    ULONG SignatureLength;\n} KPHM_ASSIGN_PROCESS_SESSION_TOKEN, *PKPHM_ASSIGN_PROCESS_SESSION_TOKEN;\n\ntypedef struct _KPHM_ASSIGN_THREAD_SESSION_TOKEN\n{\n    NTSTATUS Status;\n    HANDLE ThreadHandle;\n    PBYTE Signature;\n    ULONG SignatureLength;\n} KPHM_ASSIGN_THREAD_SESSION_TOKEN, *PKPHM_ASSIGN_THREAD_SESSION_TOKEN;\n\ntypedef struct _KPHM_GET_INFORMER_PROCESS_SETTINGS\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    PKPH_INFORMER_SETTINGS Settings;\n} KPHM_GET_INFORMER_PROCESS_SETTINGS, *PKPHM_GET_INFORMER_PROCESS_SETTINGS;\n\ntypedef struct _KPHM_SET_INFORMER_PROCESS_SETTINGS\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    PKPH_INFORMER_SETTINGS Settings;\n} KPHM_SET_INFORMER_PROCESS_SETTINGS, *PKPHM_SET_INFORMER_PROCESS_SETTINGS;\n\ntypedef struct _KPHM_STRIP_PROTECTED_PROCESS_MASKS\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    ACCESS_MASK ProcessAllowedMask;\n    ACCESS_MASK ThreadAllowedMask;\n} KPHM_STRIP_PROTECTED_PROCESS_MASKS, *PKPHM_STRIP_PROTECTED_PROCESS_MASKS;\n\ntypedef struct _KPHM_QUERY_VIRTUAL_MEMORY\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    PVOID BaseAddress;\n    KPH_MEMORY_INFORMATION_CLASS MemoryInformationClass;\n    PVOID MemoryInformation;\n    ULONG MemoryInformationLength;\n    PULONG ReturnLength;\n} KPHM_QUERY_VIRTUAL_MEMORY, *PKPHM_QUERY_VIRTUAL_MEMORY;\n\ntypedef struct _KPHM_QUERY_HASH_INFORMATION_FILE\n{\n    NTSTATUS Status;\n    HANDLE FileHandle;\n    PKPH_HASH_INFORMATION HashingInformation;\n    ULONG HashingInformationLength;\n} KPHM_QUERY_HASH_INFORMATION_FILE, *PKPHM_QUERY_HASH_INFORMATION_FILE;\n\ntypedef struct _KPHM_OPEN_DEVICE\n{\n    NTSTATUS Status;\n    PHANDLE DeviceHandle;\n    ACCESS_MASK DesiredAccess;\n    POBJECT_ATTRIBUTES ObjectAttributes;\n} KPHM_OPEN_DEVICE, *PKPHM_OPEN_DEVICE;\n\ntypedef struct _KPHM_OPEN_DEVICE_DRIVER\n{\n    NTSTATUS Status;\n    HANDLE DeviceHandle;\n    ACCESS_MASK DesiredAccess;\n    PHANDLE DriverHandle;\n} KPHM_OPEN_DEVICE_DRIVER, *PKPHM_OPEN_DEVICE_DRIVER;\n\ntypedef struct _KPHM_OPEN_DEVICE_BASE_DEVICE\n{\n    NTSTATUS Status;\n    HANDLE DeviceHandle;\n    ACCESS_MASK DesiredAccess;\n    PHANDLE BaseDeviceHandle;\n} KPHM_OPEN_DEVICE_BASE_DEVICE, *PKPHM_OPEN_DEVICE_BASE_DEVICE;\n\ntypedef struct _KPHM_GET_INFORMER_STATS\n{\n    NTSTATUS Status;\n    HANDLE ProcessHandle;\n    PKPH_INFORMER_STATS Stats;\n} KPHM_GET_INFORMER_STATS, *PKPHM_GET_INFORMER_STATS;\n\ntypedef struct _KPHM_GET_INFORMER_CLIENT_STATS\n{\n    NTSTATUS Status;\n    PKPH_INFORMER_CLIENT_STATS Stats;\n} KPHM_GET_INFORMER_CLIENT_STATS, *PKPHM_GET_INFORMER_CLIENT_STATS;\n\n//\n// KPH -> PH\n//\n\ntypedef struct _KPHM_PROCESS_CREATE\n{\n    CLIENT_ID CreatingClientId;\n    ULONG64 CreatingProcessStartKey;\n    PVOID CreatingThreadSubProcessTag;\n    HANDLE TargetProcessId;\n    ULONG64 TargetProcessStartKey;\n    HANDLE ParentProcessId;\n    ULONG64 ParentProcessStartKey;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG FileOpenNameAvailable : 1;\n            ULONG IsSubsystemProcess : 1;\n            ULONG Reserved : 30;\n        };\n    };\n\n    PVOID FileObject;\n\n    //\n    // Dynamic\n    //\n    // id: KphMsgFieldFileName       type: KphMsgTypeUnicodeString\n    // id: KphMsgFieldCommandLine    type: KphMsgTypeUnicodeString\n    //\n} KPHM_PROCESS_CREATE, *PKPHM_PROCESS_CREATE;\n\ntypedef struct _KPHM_PROCESS_CREATE_REPLY\n{\n    NTSTATUS CreationStatus;\n} KPHM_PROCESS_CREATE_REPLY, *PKPHM_PROCESS_CREATE_REPLY;\n\ntypedef struct _KPHM_PROCESS_EXIT\n{\n    CLIENT_ID ClientId;\n    ULONG64 ProcessStartKey;\n    PVOID ThreadSubProcessTag;\n    NTSTATUS ExitStatus;\n} KPHM_PROCESS_EXIT, *PKPHM_PROCESS_EXIT;\n\ntypedef struct _KPHM_THREAD_CREATE\n{\n    CLIENT_ID CreatingClientId;\n    ULONG64 CreatingProcessStartKey;\n    PVOID CreatingThreadSubProcessTag;\n    CLIENT_ID TargetClientId;\n    ULONG64 TargetProcessStartKey;\n} KPHM_THREAD_CREATE, *PKPHM_THREAD_CREATE;\n\ntypedef struct _KPHM_THREAD_EXECUTE\n{\n    CLIENT_ID ClientId;\n    ULONG64 ProcessStartKey;\n    PVOID ThreadSubProcessTag;\n} KPHM_THREAD_EXECUTE, *PKPHM_THREAD_EXECUTE;\n\ntypedef struct _KPHM_THREAD_EXIT\n{\n    CLIENT_ID ClientId;\n    ULONG64 ProcessStartKey;\n    PVOID ThreadSubProcessTag;\n    NTSTATUS ExitStatus;\n} KPHM_THREAD_EXIT, *PKPHM_THREAD_EXIT;\n\ntypedef struct _KPHM_IMAGE_LOAD\n{\n    CLIENT_ID LoadingClientId;\n    ULONG64 LoadingProcessStartKey;\n    PVOID LoadingThreadSubProcessTag;\n    HANDLE TargetProcessId;\n    ULONG64 TargetProcessStartKey;\n\n    union\n    {\n        ULONG Properties;\n        struct\n        {\n            ULONG ImageAddressingMode : 8;\n            ULONG SystemModeImage : 1;\n            ULONG ImageMappedToAllPids : 1;\n            ULONG ExtendedInfoPresent : 1;\n            ULONG MachineTypeMismatch : 1;\n            ULONG ImageSignatureLevel : 4;\n            ULONG ImageSignatureType : 3;\n            ULONG ImagePartialMap : 1;\n            ULONG Reserved : 12;\n        };\n    };\n\n    PVOID ImageBase;\n    ULONG ImageSelector;\n    SIZE_T ImageSize;\n    ULONG ImageSectionNumber;\n    PVOID FileObject;\n\n    //\n    // Dynamic\n    //\n    // id: KphMsgFieldFileName    type: KphMsgTypeUnicodeString\n    //\n} KPHM_IMAGE_LOAD, *PKPHM_IMAGE_LOAD;\n\ntypedef struct _KPHM_DEBUG_PRINT\n{\n    CLIENT_ID ContextClientId;\n    ULONG ComponentId;\n    ULONG Level;\n\n    //\n    // Dynamic\n    //\n    // id: KphMsgFieldOutput      type: KphMsgTypeAnsiString\n    //\n} KPHM_DEBUG_PRINT, *PKPHM_DEBUG_PRINT;\n\ntypedef struct _KPHM_HANDLE\n{\n    CLIENT_ID ContextClientId;\n    ULONG64 ContextProcessStartKey;\n    PVOID ContextThreadSubProcessTag;\n\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG KernelHandle : 1;\n            ULONG Reserved : 31;\n        };\n    };\n\n    PVOID Object;\n\n    union\n    {\n        USHORT Information;\n        struct\n        {\n            USHORT PostOperation : 1;\n            USHORT Duplicate : 1;      // Create = 0, Duplicate = 1\n            USHORT Spare : 14;\n        };\n    };\n\n    ULONG64 Sequence;\n\n    union\n    {\n        struct\n        {\n            ACCESS_MASK DesiredAccess;\n            ACCESS_MASK OriginalDesiredAccess;\n\n            union\n            {\n                struct\n                {\n                    union\n                    {\n                        struct\n                        {\n                            HANDLE ProcessId;\n                        } Process; // KphMsgHandlePreCreateProcess\n\n                        struct\n                        {\n                            CLIENT_ID ClientId;\n                            PVOID SubProcessTag;\n                        } Thread; // KphMsgHandlePreCreateThread\n                    };\n                } Create;\n\n                struct\n                {\n                    HANDLE SourceProcessId;\n                    HANDLE TargetProcessId;\n\n                    union\n                    {\n                        struct\n                        {\n                            HANDLE ProcessId;\n                        } Process; // KphMsgHandlePreDuplicateProcess\n\n                        struct\n                        {\n                            CLIENT_ID ClientId;\n                            PVOID SubProcessTag;\n                        } Thread; // KphMsgHandlePreDuplicateThread\n                    };\n                } Duplicate;\n            };\n        } Pre;\n\n        struct\n        {\n            ULONG64 PreSequence;\n            LARGE_INTEGER PreTimeStamp;\n            NTSTATUS ReturnStatus;\n            ACCESS_MASK GrantedAccess;\n            ACCESS_MASK DesiredAccess;\n            ACCESS_MASK OriginalDesiredAccess;\n\n            union\n            {\n                struct\n                {\n                    union\n                    {\n                        struct\n                        {\n                            HANDLE ProcessId;\n                        } Process; // KphMsgHandlePostCreateProcess\n\n                        struct\n                        {\n                            CLIENT_ID ClientId;\n                            PVOID SubProcessTag;\n                        } Thread; // KphMsgHandlePostCreateThread\n                    };\n                } Create;\n\n                struct\n                {\n                    HANDLE SourceProcessId;\n                    HANDLE TargetProcessId;\n\n                    union\n                    {\n                        struct\n                        {\n                            HANDLE ProcessId;\n                        } Process; // KphMsgHandlePostDuplicateProcess\n\n                        struct\n                        {\n                            CLIENT_ID ClientId;\n                            PVOID SubProcessTag;\n                        } Thread; // KphMsgHandlePostDuplicateThread\n                    };\n                } Duplicate;\n            };\n        } Post;\n    };\n\n    //\n    // Dynamic\n    //\n    // id: KphMsgFieldObjectName    type: KphMsgTypeUnicodeString\n    //     - KphMsgHandlePreCreateDesktop\n    //     - KphMsgHandlePostCreateDesktop\n    //     - KphMsgHandlePreDuplicateDesktop\n    //     - KphMsgHandlePostDuplicateDesktop\n    //\n} KPHM_HANDLE, *PKPHM_HANDLE;\n\ntypedef struct _KPHM_REQUIRED_STATE_FAILURE\n{\n    CLIENT_ID ClientId;\n    enum _KPH_MESSAGE_ID MessageId;\n    KPH_PROCESS_STATE ClientState;\n    KPH_PROCESS_STATE RequiredState;\n} KPHM_REQUIRED_STATE_FAILURE, *PKPHM_REQUIRED_STATE_FAILURE;\n\n//\n// FLT_PARAMETERS adapted for KPH_MESSAGE, there are some minor renaming of\n// members to fit with KPH_MESSAGE convention.\n//\n#pragma warning(push)\n#pragma warning(disable : 4324) // structure was padded due to alignment specifier\ntypedef union _KPHM_FILE_PARAMETERS\n{\n    // FLT_PARAMETERS.Create\n    struct\n    {\n        PVOID SecurityContext; //PIO_SECURITY_CONTEXT\n        ULONG Options;\n        USHORT POINTER_ALIGNMENT FileAttributes;\n        USHORT ShareAccess;\n        ULONG POINTER_ALIGNMENT EaLength;\n        PVOID EaBuffer;\n        LARGE_INTEGER AllocationSize;\n    } Create;\n\n    // FLT_PARAMETERS.CreatePipe\n    struct\n    {\n        PVOID SecurityContext; //PIO_SECURITY_CONTEXT\n        ULONG Options;\n        USHORT POINTER_ALIGNMENT Reserved;\n        USHORT ShareAccess;\n        PVOID Parameters;\n    } CreateNamedPipe;\n\n    // FLT_PARAMETERS.CreateMailslot\n    struct\n    {\n        PVOID SecurityContext; // PIO_SECURITY_CONTEXT\n        ULONG Options;\n        USHORT POINTER_ALIGNMENT Reserved;\n        USHORT ShareAccess;\n        PVOID Parameters;\n    } CreateMailslot;\n\n    // FLT_PARAMETERS.Read\n    struct\n    {\n        ULONG Length;\n        ULONG POINTER_ALIGNMENT Key;\n        LARGE_INTEGER ByteOffset;\n        PVOID ReadBuffer;\n        PVOID MdlAddress; // PMDL\n    } Read;\n\n    // FLT_PARAMETERS.Write\n    struct\n    {\n        ULONG Length;\n        ULONG POINTER_ALIGNMENT Key;\n        LARGE_INTEGER ByteOffset;\n        PVOID WriteBuffer;\n        PVOID MdlAddress; // PMDL\n    } Write;\n\n    // FLT_PARAMETERS.QueryFileInformation\n    struct\n    {\n        ULONG Length;\n        FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;\n        PVOID InfoBuffer;\n    } QueryInformation;\n\n    // FLT_PARAMETERS.SetFileInformation\n    struct\n    {\n        ULONG Length;\n        FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;\n        PFILE_OBJECT ParentOfTarget;\n        union\n        {\n            struct\n            {\n                BOOLEAN ReplaceIfExists;\n                BOOLEAN AdvanceOnly;\n            };\n            ULONG ClusterCount;\n            HANDLE DeleteHandle;\n        };\n        PVOID InfoBuffer;\n    } SetInformation;\n\n    // FLT_PARAMETERS.QueryEa\n    struct\n    {\n        ULONG Length;\n        PVOID EaList;\n        ULONG EaListLength;\n        ULONG POINTER_ALIGNMENT EaIndex;\n        PVOID EaBuffer;\n        PVOID MdlAddress; // PMDL\n    } QueryEa;\n\n    // FLT_PARAMETERS.SetEa\n    struct\n    {\n        ULONG Length;\n        PVOID EaBuffer;\n        PVOID MdlAddress; // PMDL\n    } SetEa;\n\n    // FLT_PARAMETERS.QueryVolumeInformation\n    struct\n    {\n        ULONG Length;\n        FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;\n        PVOID VolumeBuffer;\n    } QueryVolumeInformation;\n\n    // FLT_PARAMETERS.SetVolumeInformation\n    struct\n    {\n        ULONG Length;\n        FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;\n        PVOID VolumeBuffer;\n    } SetVolumeInformation;\n\n    // FLT_PARAMETERS.DirectoryControl\n    union\n    {\n        struct\n        {\n            ULONG Length;\n            PUNICODE_STRING FileName;\n            FILE_INFORMATION_CLASS FileInformationClass;\n            ULONG POINTER_ALIGNMENT FileIndex;\n            PVOID DirectoryBuffer;\n            PVOID MdlAddress; // PMDL\n        } QueryDirectory;\n\n        struct\n        {\n            ULONG Length;\n            ULONG POINTER_ALIGNMENT CompletionFilter;\n            ULONG POINTER_ALIGNMENT Spare1;\n            ULONG POINTER_ALIGNMENT Spare2;\n            PVOID DirectoryBuffer;\n            PVOID MdlAddress; // PMDL\n        } NotifyDirectory;\n\n        struct\n        {\n            ULONG Length;\n            ULONG POINTER_ALIGNMENT CompletionFilter;\n            DIRECTORY_NOTIFY_INFORMATION_CLASS POINTER_ALIGNMENT DirectoryNotifyInformationClass;\n            ULONG POINTER_ALIGNMENT Spare2;\n            PVOID DirectoryBuffer;\n            PVOID MdlAddress; // PMDL\n        } NotifyDirectoryEx;\n    } DirectoryControl;\n\n    // FLT_PARAMETERS.FileSystemControl\n    union\n    {\n        struct\n        {\n            PVOID Vpb; // PVPB\n            PDEVICE_OBJECT DeviceObject;\n        } VerifyVolume;\n\n        struct\n        {\n            ULONG OutputBufferLength;\n            ULONG POINTER_ALIGNMENT InputBufferLength;\n            ULONG POINTER_ALIGNMENT FsControlCode;\n        } Common;\n\n        struct\n        {\n            ULONG OutputBufferLength;\n            ULONG POINTER_ALIGNMENT InputBufferLength;\n            ULONG POINTER_ALIGNMENT FsControlCode;\n            PVOID InputBuffer;\n            PVOID OutputBuffer;\n            PVOID OutputMdlAddress; // PMDL\n        } Neither;\n\n        struct\n        {\n            ULONG OutputBufferLength;\n            ULONG POINTER_ALIGNMENT InputBufferLength;\n            ULONG POINTER_ALIGNMENT FsControlCode;\n            PVOID SystemBuffer;\n        } Buffered;\n\n        struct\n        {\n            ULONG OutputBufferLength;\n            ULONG POINTER_ALIGNMENT InputBufferLength;\n            ULONG POINTER_ALIGNMENT FsControlCode;\n            PVOID InputSystemBuffer;\n            PVOID OutputBuffer;\n            PVOID OutputMdlAddress; // PMDL\n        } Direct;\n    } FileSystemControl;\n\n    // FLT_PARAMETERS.DeviceIoControl\n    union\n    {\n        struct\n        {\n            ULONG OutputBufferLength;\n            ULONG POINTER_ALIGNMENT InputBufferLength;\n            ULONG POINTER_ALIGNMENT IoControlCode;\n        } Common;\n\n        struct\n        {\n            ULONG OutputBufferLength;\n            ULONG POINTER_ALIGNMENT InputBufferLength;\n            ULONG POINTER_ALIGNMENT IoControlCode;\n            PVOID InputBuffer;\n            PVOID OutputBuffer;\n            PVOID OutputMdlAddress; // PMDL\n        } Neither;\n\n        struct\n        {\n            ULONG OutputBufferLength;\n            ULONG POINTER_ALIGNMENT InputBufferLength;\n            ULONG POINTER_ALIGNMENT IoControlCode;\n            PVOID SystemBuffer;\n        } Buffered;\n\n        struct\n        {\n            ULONG OutputBufferLength;\n            ULONG POINTER_ALIGNMENT InputBufferLength;\n            ULONG POINTER_ALIGNMENT IoControlCode;\n            PVOID InputSystemBuffer;\n            PVOID OutputBuffer;\n            PVOID OutputMdlAddress; // PMDL\n        } Direct;\n\n        struct\n        {\n            ULONG OutputBufferLength;\n            ULONG POINTER_ALIGNMENT InputBufferLength;\n            ULONG POINTER_ALIGNMENT IoControlCode;\n            PVOID InputBuffer;\n            PVOID OutputBuffer;\n        } FastIo;\n    } DeviceControl;\n\n    // FLT_PARAMETERS.LockControl\n    struct\n    {\n        PLARGE_INTEGER Length;\n        ULONG POINTER_ALIGNMENT Key;\n        LARGE_INTEGER ByteOffset;\n        PVOID ProcessId; // PEPROCESS\n        BOOLEAN FailImmediately;\n        BOOLEAN ExclusiveLock;\n    } LockControl;\n\n    // FLT_PARAMETERS.QuerySecurity\n    struct\n    {\n        SECURITY_INFORMATION SecurityInformation;\n        ULONG POINTER_ALIGNMENT Length;\n        PVOID SecurityBuffer;\n        PVOID MdlAddress; // PMDL\n    } QuerySecurity;\n\n    // FLT_PARAMETERS.SetSecurity\n    struct\n    {\n        SECURITY_INFORMATION SecurityInformation;\n        PSECURITY_DESCRIPTOR SecurityDescriptor;\n    } SetSecurity;\n\n    // FLT_PARAMETERS.WMI\n    struct\n    {\n        ULONG_PTR ProviderId;\n        PVOID DataPath;\n        ULONG BufferSize;\n        PVOID Buffer;\n    } SystemControl;\n\n    // FLT_PARAMETERS.QueryQuota\n    struct\n    {\n        ULONG Length;\n        PSID StartSid;\n        PFILE_GET_QUOTA_INFORMATION SidList;\n        ULONG SidListLength;\n        PVOID QuotaBuffer;\n        PVOID MdlAddress; // PMDL\n    } QueryQuota;\n\n    // FLT_PARAMETERS.SetQuota\n    struct\n    {\n        ULONG Length;\n        PVOID QuotaBuffer;\n        PVOID MdlAddress; // PMDL\n    } SetQuota;\n\n    // FLT_PARAMETERS.Pnp\n    union\n    {\n        struct\n        {\n            PVOID AllocatedResources; // PCM_RESOURCE_LIST\n            PVOID AllocatedResourcesTranslated; // PCM_RESOURCE_LIST\n        } StartDevice;\n\n        struct\n        {\n            DEVICE_RELATION_TYPE Type;\n        } QueryDeviceRelations;\n\n        struct\n        {\n            CONST GUID *InterfaceType;\n            USHORT Size;\n            USHORT Version;\n            PVOID Interface; // PINTERFACE\n            PVOID InterfaceSpecificData;\n        } QueryInterface;\n\n        struct\n        {\n            PVOID Capabilities; // PDEVICE_CAPABILITIES\n        } DeviceCapabilities;\n\n        struct\n        {\n            PVOID IoResourceRequirementList; // PIO_RESOURCE_REQUIREMENTS_LIST\n        } FilterResourceRequirements;\n\n        struct\n        {\n            ULONG WhichSpace;\n            PVOID Buffer;\n            ULONG Offset;\n            ULONG POINTER_ALIGNMENT Length;\n        } ReadWriteConfig;\n\n        struct\n        {\n            BOOLEAN Lock;\n        } SetLock;\n\n        struct\n        {\n            BUS_QUERY_ID_TYPE IdType;\n        } QueryId;\n\n        struct\n        {\n            DEVICE_TEXT_TYPE DeviceTextType;\n            LCID POINTER_ALIGNMENT LocaleId;\n        } QueryDeviceText;\n\n        struct\n        {\n            BOOLEAN InPath;\n            BOOLEAN Reserved[3];\n            DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type;\n        } UsageNotification;\n    } Pnp;\n\n     // FLT_PARAMETERS.AcquireForSectionSynchronization\n    struct\n    {\n        FS_FILTER_SECTION_SYNC_TYPE SyncType;\n        ULONG PageProtection;\n        PVOID OutputInformation; // PFS_FILTER_SECTION_SYNC_OUTPUT\n        ULONG Flags;\n        ULONG AllocationAttributes;\n    } AcquireForSectionSync;\n\n    // FLT_PARAMETERS.AcquireForModifiedPageWriter\n    struct\n    {\n        PLARGE_INTEGER EndingOffset;\n        PVOID *ResourceToRelease; // PERESOURCE\n    } AcquireForModWrite;\n\n    // FLT_PARAMETERS.ReleaseForModifiedPageWriter\n    struct\n    {\n        PVOID ResourceToRelease; // PERESOURCE\n    } ReleaseForModWrite;\n\n    // FLT_PARAMETERS.QueryOpen\n    struct\n    {\n        PIRP Irp;\n        PVOID FileInformation;\n        PULONG Length;\n        FILE_INFORMATION_CLASS FileInformationClass;\n    } QueryOpen;\n\n    // FLT_PARAMETERS.FastIoCheckIfPossible\n    struct\n    {\n        LARGE_INTEGER FileOffset;\n        ULONG Length;\n        ULONG POINTER_ALIGNMENT LockKey;\n        BOOLEAN POINTER_ALIGNMENT CheckForReadOperation;\n    } FastIoCheckIfPossible;\n\n    // FLT_PARAMETERS.NetworkQueryOpen\n    struct\n    {\n        PIRP Irp;\n        PFILE_NETWORK_OPEN_INFORMATION NetworkInformation;\n    } NetworkQueryOpen;\n\n    // FLT_PARAMETERS.MdlRead\n    struct\n    {\n        LARGE_INTEGER FileOffset;\n        ULONG POINTER_ALIGNMENT Length;\n        ULONG POINTER_ALIGNMENT Key;\n        PVOID *MdlChain; // PMDL\n    } MdlRead;\n\n    // FLT_PARAMETERS.MdlReadComplete\n    struct\n    {\n        PVOID MdlChain; // PMDL\n    } MdlReadComplete;\n\n    // FLT_PARAMETERS.PrepareMdlWrite\n    struct\n    {\n        LARGE_INTEGER FileOffset;\n        ULONG POINTER_ALIGNMENT Length;\n        ULONG POINTER_ALIGNMENT Key;\n        PVOID *MdlChain; // PMDL\n    } PrepareMdlWrite;\n\n    // FLT_PARAMETERS.MdlWriteComplete\n    struct\n    {\n        LARGE_INTEGER FileOffset;\n        PVOID MdlChain; // PMDL\n    } MdlWriteComplete;\n\n    // FLT_PARAMETERS.MountVolume\n    struct\n    {\n        ULONG DeviceType;\n    } VolumeMount;\n\n    // FLT_PARAMETERS.Others\n    struct\n    {\n        PVOID Argument1;\n        PVOID Argument2;\n        PVOID Argument3;\n        PVOID Argument4;\n        PVOID Argument5;\n        LARGE_INTEGER Argument6;\n    } Others;\n} KPHM_FILE_PARAMETERS, *PKPHM_FILE_PARAMETERS;\n#pragma warning(pop)\n\n//\n// COPY_INFORMATION\n//\ntypedef struct _KPHM_COPY_INFORMATION\n{\n    PVOID SourceFileObject;\n    ULONG64 SourceFileOffset;\n} KPHM_COPY_INFORMATION, *PKPHM_COPY_INFORMATION;\n\ntypedef struct _KPHM_FILE\n{\n    CLIENT_ID ClientId;\n    ULONG64 ProcessStartKey;\n    PVOID ThreadSubProcessTag;\n\n    UCHAR MajorFunction;  // IRP_MJ_*\n    UCHAR MinorFunction;  // IRP_MN_*\n    UCHAR Irql;           //                        KeGetCurrentIrql\n    UCHAR OperationFlags; // SL_*                   IO_STACK_LOCATION.Flags\n    ULONG FltFlags;       // FLTFL_CALLBACK_DATA_*  FLT_CALLBACK_DATA.Flags\n    ULONG IrpFlags;       // IRP_*                  IRP.Flags\n    ULONG Flags;          // FO_*                   FILE_OBJECT.Flags\n\n    union\n    {\n        ULONG Information;\n        struct\n        {\n            ULONG RequestorMode : 1;       // KernelMode == 0, UserMode == 1\n            ULONG IsPagingFile : 1;        // FsRtlIsPagingFile\n            ULONG IsSystemPagingFile : 1;  // FsRtlIsSystemPagingFile\n            ULONG OriginRemote : 1;        // IoIsFileOriginRemote\n            ULONG IgnoringSharing : 1;     // IoIsFileObjectIgnoringSharing\n            ULONG InStackFileObject : 1;   // IoGetStackLimits FLT_RELATED_OBJECTS.FileObject\n            ULONG LockOperation : 1;       // FILE_OBJECT.LockOperation\n            ULONG DeletePending : 1;       // FILE_OBJECT.DeletePending\n            ULONG ReadAccess : 1;          // FILE_OBJECT.ReadAccess\n            ULONG WriteAccess : 1;         // FILE_OBJECT.WriteAccess\n            ULONG DeleteAccess : 1;        // FILE_OBJECT.DeleteAccess\n            ULONG SharedRead : 1;          // FILE_OBJECT.SharedRead\n            ULONG SharedWrite : 1;         // FILE_OBJECT.SharedWrite\n            ULONG SharedDelete : 1;        // FILE_OBJECT.SharedDelete\n            ULONG Busy : 1;                // FILE_OBJECT.Busy\n            ULONG Spare : 1;\n            ULONG TransactionContext : 16; // FLT_RELATED_OBJECTS.TransactionContext\n        };\n    };\n\n    ULONG Waiters;                         // FILE_OBJECT.Waiters\n    LARGE_INTEGER CurrentByteOffset;       // FILE_OBJECT.CurrentByteOffset\n    OPLOCK_KEY_CONTEXT OplockKeyContext;   // IoGetOplockKeyContextEx\n    KPHM_COPY_INFORMATION CopyInformation; // FltGetCopyInformationFromCallbackData\n\n    union\n    {\n        ULONG64 Information2;\n        struct\n        {\n            ULONG64 OpenedAsCopySource : 1;      // IoCheckFileObjectOpenedAsCopySource\n            ULONG64 OpenedAsCopyDestination : 1; // IoCheckFileObjectOpenedAsCopyDestination\n            ULONG64 Spare2 : 62;\n        };\n    };\n\n    PVOID Volume;             // FLT_RELATED_OBJECTS.Volume\n    PVOID FileObject;         // FLT_RELATED_OBJECTS.FileObject\n    PVOID Transaction;        // FLT_RELATED_OBJECTS.Transaction\n    PVOID DataSectionObject;  // FILE_OBJECT.SectionObjectPointer.DataSectionObject\n    PVOID ImageSectionObject; // FILE_OBJECT.SectionObjectPointer.ImageSectionObject\n\n    ULONG64 Sequence;\n    KPHM_FILE_PARAMETERS Parameters;\n\n    union\n    {\n        struct\n        {\n            union\n            {\n                struct\n                {\n                    BOOLEAN MaybeTunneledFileName;\n                } Create;\n\n                struct\n                {\n                    NAMED_PIPE_CREATE_PARAMETERS Parameters;\n                } CreateNamedPipe;\n\n                struct\n                {\n                    BOOLEAN MaybeTunneledFileName;\n                    BOOLEAN MaybeTunneledDestinationFileName;\n                } SetInformation;\n\n                struct\n                {\n                    LARGE_INTEGER Length;\n                } LockControl;\n\n                struct\n                {\n                    MAILSLOT_CREATE_PARAMETERS Parameters;\n                } CreateMailslot;\n\n                struct\n                {\n                    LARGE_INTEGER EndingOffset;\n                } AcquireForModWrite;\n\n                struct\n                {\n                    ULONG Length;\n                } QueryOpen;\n            };\n        } Pre;\n\n        struct\n        {\n            ULONG64 PreSequence;\n            LARGE_INTEGER PreTimeStamp;\n            IO_STATUS_BLOCK IoStatus;\n            union\n            {\n                struct\n                {\n                    BOOLEAN TunneledFileName;\n                } Create;\n\n                struct\n                {\n                    BOOLEAN TunneledFileName;\n                    BOOLEAN TunneledDestinationFileName;\n                } SetInformation;\n            };\n        } Post;\n    };\n\n    //\n    // Dynamic\n    //\n    // id: KphMsgFieldFileName                type: KphMsgTypeUnicodeString\n    //\n    // id: KphMsgFieldEaBuffer                type: KphMsgTypeSizedBuffer\n    //     - KphMsgFilePreCreate\n    //\n    // id: KphMsgFieldInformationBuffer       type: KphMsgTypeSizedBuffer\n    //     - KphMsgFilePreSetInformation\n    //     - KphMsgFilePreQueryEa\n    //     - KphMsgFilePreSetEa\n    //     - KphMsgFilePreSetVolumeInformation\n    //     - KphMsgFilePostQueryEa\n    //     - KphMsgFilePostQueryVolumeInformation\n    //     - KphMsgFilePostDirectoryControl\n    //     - KphMsgFilePostQuerySecurity\n    //     - KphMsgFilePostQueryOpen\n    //     - KphMsgFilePostNetworkQueryOpen\n    //\n    // id: KphMsgFieldDestinationFileName     type: KphMsgTypeUnicodeString\n    //     - KphMsgFilePreDirectoryControl\n    //     - KphMsgFilePreSetInformation\n    //         - FileInformationClass == FileRename* || FileLink*\n    //     - KphMsgFilePostSetInformation\n    //         - FileInformationClass == FileRename* || FileLink*\n    //\n    // id: KphMsgFieldInput                   type: KphMsgTypeSizedBuffer\n    //     - KphMsgFilePreFileSystemControl\n    //     - KphMsgFilePreDeviceControl\n    //     - KphMsgFilePreInternalDeviceControl\n    //     - KphMsgFilePostFileSystemControl\n    //     - KphMsgFilePostDeviceControl\n    //     - KphMsgFilePostInternalDeviceControl\n    //\n    // id: KphMsgFieldOutput                  type: KphMsgTypeSizedBuffer\n    //     - KphMsgFilePreFileSystemControl\n    //     - KphMsgFilePreDeviceControl\n    //     - KphMsgFilePreInternalDeviceControl\n    //     - KphMsgFilePostFileSystemControl\n    //     - KphMsgFilePostDeviceControl\n    //     - KphMsgFilePostInternalDeviceControl\n    //\n} KPHM_FILE, *PKPHM_FILE;\n\ntypedef struct _KPHM_FILE_REPLY\n{\n    union\n    {\n        struct\n        {\n            struct\n            {\n                NTSTATUS Status;\n            } Create;\n        } Pre;\n\n        struct\n        {\n            struct\n            {\n                NTSTATUS Status;\n            } Create;\n        } Post;\n    };\n} KPHM_FILE_REPLY, *PKPHM_FILE_REPLY;\n\ntypedef union _KPHM_REGISTRY_PARAMETERS\n{\n    struct\n    {\n        PUNICODE_STRING ValueName;\n        ULONG TitleIndex;\n        ULONG Type;\n        PVOID Data;\n        ULONG DataSize;\n    } SetValueKey;\n\n    struct\n    {\n        PUNICODE_STRING ValueName;\n    } DeleteValueKey;\n\n    struct\n    {\n        KEY_SET_INFORMATION_CLASS KeySetInformationClass;\n        PVOID KeySetInformation;\n        ULONG KeySetInformationLength;\n    } SetInformationKey;\n\n    struct\n    {\n        PUNICODE_STRING NewName;\n    } RenameKey;\n\n    struct\n    {\n        ULONG Index;\n        KEY_INFORMATION_CLASS KeyInformationClass;\n        PVOID KeyInformation;\n        ULONG Length;\n        PULONG ResultLength;\n    } EnumerateKey;\n\n    struct\n    {\n        ULONG Index;\n        KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass;\n        PVOID KeyValueInformation;\n        ULONG Length;\n        PULONG ResultLength;\n    } EnumerateValueKey;\n\n    struct\n    {\n        KEY_INFORMATION_CLASS KeyInformationClass;\n        PVOID KeyInformation;\n        ULONG Length;\n        PULONG ResultLength;\n    } QueryKey;\n\n    struct\n    {\n        PUNICODE_STRING ValueName;\n        KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass;\n        PVOID KeyValueInformation;\n        ULONG Length;\n        PULONG ResultLength;\n    } QueryValueKey;\n\n    struct\n    {\n        PKEY_VALUE_ENTRY ValueEntries;\n        ULONG EntryCount;\n        PVOID ValueBuffer;\n        PULONG BufferLength;\n        PULONG RequiredBufferLength;\n    } QueryMultipleValueKey;\n\n    struct\n    {\n        PUNICODE_STRING CompleteName;\n        PVOID RootObject;\n        PVOID ObjectType;\n        ULONG Options;\n        PUNICODE_STRING Class;\n        PVOID SecurityDescriptor;\n        PVOID SecurityQualityOfService;\n        ACCESS_MASK DesiredAccess;\n        ACCESS_MASK GrantedAccess;\n        PULONG Disposition;\n        PUNICODE_STRING RemainingName;\n        ULONG Wow64Flags;\n        ULONG Attributes;\n        UCHAR CheckAccessMode;\n    } CreateKey;\n\n    struct\n    {\n        PUNICODE_STRING CompleteName;\n        PVOID RootObject;\n        PVOID ObjectType;\n        ULONG Options;\n        PUNICODE_STRING Class;\n        PVOID SecurityDescriptor;\n        PVOID SecurityQualityOfService;\n        ACCESS_MASK DesiredAccess;\n        ACCESS_MASK GrantedAccess;\n        PULONG Disposition;\n        PUNICODE_STRING RemainingName;\n        ULONG Wow64Flags;\n        ULONG Attributes;\n        UCHAR CheckAccessMode;\n    } OpenKey;\n\n    struct\n    {\n        PVOID RootObject;\n        PUNICODE_STRING KeyName;\n        PUNICODE_STRING SourceFile;\n        ULONG Flags;\n        PVOID TrustClassObject;\n        PVOID UserEvent;\n        ACCESS_MASK DesiredAccess;\n        PHANDLE RootHandle;\n        PVOID FileAccessToken;\n    } LoadKey;\n\n    struct\n    {\n        PVOID UserEvent;\n    } UnLoadKey;\n\n    struct\n    {\n        PSECURITY_INFORMATION SecurityInformation;\n        PSECURITY_DESCRIPTOR SecurityDescriptor;\n        PULONG Length;\n    } QueryKeySecurity;\n\n    struct\n    {\n        PSECURITY_INFORMATION SecurityInformation;\n        PSECURITY_DESCRIPTOR SecurityDescriptor;\n    } SetKeySecurity;\n\n    struct\n    {\n        HANDLE FileHandle;\n        ULONG Flags;\n    } RestoreKey;\n\n    struct\n    {\n        HANDLE FileHandle;\n        ULONG Format;\n    } SaveKey;\n\n    struct\n    {\n        PUNICODE_STRING OldFileName;\n        PUNICODE_STRING NewFileName;\n    } ReplaceKey;\n\n    struct\n    {\n        POBJECT_NAME_INFORMATION ObjectNameInfo;\n        ULONG Length;\n        PULONG ReturnLength;\n    } QueryKeyName;\n\n    struct\n    {\n        HANDLE FileHandle;\n        PVOID HighKeyObject;\n        PVOID LowKeyObject;\n    } SaveMergedKey;\n} KPHM_REGISTRY_PARAMETERS, *PKPHM_REGISTRY_PARAMETERS;\n\ntypedef struct _KPHM_REGISTRY\n{\n    CLIENT_ID ClientId;\n    ULONG64 ProcessStartKey;\n    PVOID ThreadSubProcessTag;\n\n    union\n    {\n        USHORT Information;\n        struct\n        {\n            USHORT PostOperation : 1;\n            USHORT PreviousMode : 1;       // KernelMode == 0, UserMode == 1\n            USHORT Spare : 14;\n        };\n    };\n\n    PVOID Object;\n    ULONG_PTR ObjectId;   // CmCallbackGetKeyObjectIDEx\n    PVOID Transaction;    // CmGetBoundTransaction\n\n    ULONG64 Sequence;\n    KPHM_REGISTRY_PARAMETERS Parameters;\n\n    union\n    {\n        struct\n        {\n            union\n            {\n                struct\n                {\n                    ULONG BufferLength;\n                } QueryMultipleValueKey;\n\n                struct\n                {\n                    SECURITY_INFORMATION SecurityInformation;\n                    ULONG Length;\n                } QueryKeySecurity;\n\n                struct\n                {\n                    SECURITY_INFORMATION SecurityInformation;\n                } SetKeySecurity;\n\n                struct\n                {\n                    ULONG_PTR LowKeyObjectId;\n                    PVOID LowKeyTransaction;\n                } SaveMergedKey;\n            };\n        } Pre;\n\n        struct\n        {\n            ULONG64 PreSequence;\n            LARGE_INTEGER PreTimeStamp;\n            NTSTATUS Status;\n\n            union\n            {\n                struct\n                {\n                    ULONG ResultLength;\n                } EnumerateKey;\n\n                struct\n                {\n                    ULONG ResultLength;\n                } EnumerateValueKey;\n\n                struct\n                {\n                    ULONG ResultLength;\n                } QueryKey;\n\n                struct\n                {\n                    ULONG ResultLength;\n                } QueryValueKey;\n\n                struct\n                {\n                    ULONG BufferLength;\n                    ULONG RequiredBufferLength;\n                } QueryMultipleValueKey;\n\n                struct\n                {\n                    ULONG Disposition;\n                } CreateKey;\n\n                struct\n                {\n                    ULONG Disposition;\n                } OpenKey;\n\n                struct\n                {\n                    HANDLE RootHandle;\n                } LoadKey;\n\n                struct\n                {\n                    ULONG Length;\n                } QueryKeySecurity;\n\n                struct\n                {\n                    ULONG ReturnLength;\n                } QueryKeyName;\n\n                struct\n                {\n                    ULONG_PTR LowKeyObjectId;\n                    PVOID LowKeyTransaction;\n                } SaveMergedKey;\n            };\n        } Post;\n    };\n\n    //\n    // Dynamic\n    //\n    // id: KphMsgFieldObjectName              type: KphMsgTypeUnicodeString\n    //\n    // id: KphMsgFieldValueName               type: KphMsgTypeUnicodeString\n    //     - KphMsgRegPreSetValueKey\n    //     - KphMsgRegPreDeleteValueKey\n    //     - KphMsgRegPostSetValueKey\n    //     - KphMsgRegPostDeleteValueKey\n    //\n    // id: KphMsgFieldValueBuffer             type: KphMsgTypeSizedBuffer\n    //     - KphMsgRegPreSetValueKey\n    //     - KphMsgRegPostQueryValueKey\n    //     - KphMsgRegPostQueryMultipleValueKey\n    //\n    // id: KphMsgFieldInformationBuffer       type: KphMsgTypeSizedBuffer\n    //     - KphMsgRegPreSetInformationKey\n    //     - KphMsgRegPostEnumerateKey\n    //     - KphMsgRegPostEnumerateValueKey\n    //     - KphMsgRegPostQueryKey\n    //\n    // id: KphMsgFieldNewName                 type: KphMsgTypeSizedBuffer\n    //     - KphMsgRegPreRenameKey\n    //\n    // id: KphMsgFieldMultiValueNames         type: KphMsgTypeSizedBuffer\n    //     - KphMsgRegPreQueryMultipleValueKey\n    //     - KphMsgRegPostQueryMultipleValueKey\n    //\n    // id: KphMsgFieldMultiValueEntries       type: KphMsgTypeSizedBuffer\n    //     - KphMsgRegPostQueryMultipleValueKey\n    //\n    // id: KphMsgFieldClass                   type: KphMsgTypeUnicodeString\n    //     - KphMsgRegPreCreateKey\n    //\n    // id: KphMsgFieldFileName                type: KphMsgTypeUnicodeString\n    //     - KphMsgRegPreLoadKey\n    //     - KphMsgRegPreRestoreKey\n    //     - KphMsgRegPreSaveKey\n    //     - KphMsgRegPreReplaceKey\n    //     - KphMsgRegPreSaveMergedKey\n    //     - KphMsgRegPostLoadKey\n    //     - KphMsgRegPostRestoreKey\n    //     - KphMsgRegPostSaveKey\n    //     - KphMsgRegPostReplaceKey\n    //     - KphMsgRegPostSaveMergedKey\n    //\n    // id: KphMsgFieldDestinationFileName     type: KphMsgTypeUnicodeString\n    //     - KphMsgRegPreRenameKey\n    //     - KphMsgRegPostRenameKey\n    //\n    // id: KphMsgFieldOtherObjectName         type: KphMsgTypeUnicodeString\n    //     - KphMsgRegPreSaveMergedKey\n    //     - KphMsgRegPostSaveMergedKey\n    //\n} KPHM_REGISTRY, *PKPHM_REGISTRY;\n\ntypedef struct _KPHM_IMAGE_VERIFY\n{\n    CLIENT_ID ClientId;\n    ULONG64 ProcessStartKey;\n    PVOID ThreadSubProcessTag;\n    ULONG ImageType;               // SE_IMAGE_TYPE\n    ULONG Classification;          // BDCB_CLASSIFICATION\n    ULONG ImageFlags;\n    ULONG ImageHashAlgorithm;\n    ULONG ThumbprintHashAlgorithm;\n\n    //\n    // Dynamic\n    //\n    // id: KphMsgFieldFileName                type: KphMsgTypeUnicodeString\n    // id: KphMsgFieldHash                    type: KphMsgTypeSizedBuffer\n    // id: KphMsgFieldCertificatePublisher    type: KphMsgTypeUnicodeString\n    // id: KphMsgFieldCertificateIssuer       type: KphMsgTypeUnicodeString\n    // id: KphMsgFieldCertificateThumbprint   type: KphMsgTypeSizedBuffer\n    // id: KphMsgFieldRegistryPath            type: KphMsgTypeUnicodeString\n    //\n} KPHM_IMAGE_VERIFY, *PKPHM_IMAGE_VERIFY;\n\n#pragma warning(pop)\n"
  },
  {
    "path": "kphlib/include/kphmsgdyn.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#pragma once\n\n#include <kphmsg.h>\n\nEXTERN_C_START\n\ntypedef struct _KPHM_STACK_TRACE\n{\n    USHORT Count;\n    PVOID* Frames;\n} KPHM_STACK_TRACE, *PKPHM_STACK_TRACE;\n\ntypedef struct _KPHM_SIZED_BUFFER\n{\n    USHORT Size;\n    PBYTE Buffer;\n} KPHM_SIZED_BUFFER, *PKPHM_SIZED_BUFFER;\n\nVOID KphMsgDynClear(\n    _Inout_ PKPH_MESSAGE Message\n    );\n\nVOID KphMsgDynClearLast(\n    _Inout_ PKPH_MESSAGE Message\n    );\n\nUSHORT KphMsgDynRemaining(\n    _In_ PCKPH_MESSAGE Message\n    );\n\n_Must_inspect_result_\nNTSTATUS KphMsgDynAddUnicodeString(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PCUNICODE_STRING String\n    );\n\nNTSTATUS KphMsgDynGetUnicodeString(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _Out_ PUNICODE_STRING String\n    );\n\n_Must_inspect_result_\nNTSTATUS KphMsgDynAddAnsiString(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PCANSI_STRING String\n    );\n\nNTSTATUS KphMsgDynGetAnsiString(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _Out_ PANSI_STRING String\n    );\n\n_Must_inspect_result_\nNTSTATUS KphMsgDynAddStackTrace(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PKPHM_STACK_TRACE StackTrace\n    );\n\nNTSTATUS KphMsgDynGetStackTrace(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _Out_ PKPHM_STACK_TRACE StackTrace\n    );\n\n_Must_inspect_result_\nNTSTATUS KphMsgDynAddSizedBuffer(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PKPHM_SIZED_BUFFER SizedBuffer\n    );\n\nNTSTATUS KphMsgDynGetSizedBuffer(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _Out_ PKPHM_SIZED_BUFFER SizedBuffer\n    );\n\nEXTERN_C_END\n"
  },
  {
    "path": "kphlib/include/kphringbuff.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025-2026\n *\n */\n\n#pragma once\n\n#pragma warning(push)\n#pragma warning(disable : 4201)\n#pragma warning(disable : 4324)\n\ntypedef struct _KPH_RING_HEADER\n{\n    union\n    {\n        struct\n        {\n            ULONG64 Length : 30;\n            ULONG64 Busy : 1;\n            ULONG64 Discard : 1;\n            ULONG64 Reset : 1;\n            ULONG64 Alignment : 4;\n            ULONG64 Spare : 27;\n        };\n\n        ULONG64 Value;\n    };\n\n#ifdef _WIN64\n    ULONG64 Padding;\n#endif\n} KPH_RING_HEADER, *PKPH_RING_HEADER;\n\nC_ASSERT(sizeof(KPH_RING_HEADER) == MEMORY_ALLOCATION_ALIGNMENT);\n\n#define KPH_RING_BUFFER_HEADER_SIZE MEMORY_ALLOCATION_ALIGNMENT\n#define KPH_RING_BUFFER_RESERVE_MAX (((1UL << 30) - 1) -                       \\\n                                     (MEMORY_ALLOCATION_ALIGNMENT - 1) -       \\\n                                     (KPH_RING_BUFFER_HEADER_SIZE * 2))\n\ntypedef struct _KPH_RING_CONSUMER_BLOCK\n{\n    ULONG Position;\n    ULONG Processing;\n} KPH_RING_CONSUMER_BLOCK, *PKPH_RING_CONSUMER_BLOCK;\n\ntypedef struct _KPH_RING_PRODUCER_BLOCK\n{\n    ULONG Position;\n    ULONG Length;\n    DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) BYTE Buffer[ANYSIZE_ARRAY];\n} KPH_RING_PRODUCER_BLOCK, *PKPH_RING_PRODUCER_BLOCK;\n\ntypedef struct _KPH_RING_BUFFER_USER\n{\n    PKPH_RING_CONSUMER_BLOCK Consumer;\n    PKPH_RING_PRODUCER_BLOCK Producer;\n} KPH_RING_BUFFER_USER, *PKPH_RING_BUFFER_USER;\n\ntypedef\n_Function_class_(KPH_RING_CALLBACK)\nBOOLEAN\nNTAPI\nKPH_RING_CALLBACK(\n    _In_opt_ PVOID Context,\n    _In_bytecount_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\ntypedef KPH_RING_CALLBACK* PKPH_RING_CALLBACK;\n\nBOOLEAN KphProcessRingBuffer(\n    _In_ PKPH_RING_BUFFER_USER Ring,\n    _In_ PKPH_RING_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef struct _KPH_RING_BUFFER_CONNECT\n{\n    _In_ ULONG Length;\n    _In_opt_ HANDLE EventHandle;\n    _Out_ KPH_RING_BUFFER_USER Ring;\n} KPH_RING_BUFFER_CONNECT, *PKPH_RING_BUFFER_CONNECT;\n\n#pragma warning(pop)\n"
  },
  {
    "path": "kphlib/include/sistatus.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * sistatus.h IS AN AUTOGENERATED FILE, DO NOT MODIFY\n *\n * Changes should be made in sistatus.mc\n *\n */\n\n#ifndef SI_STATUS_H\n#define SI_STATUS_H\n//\n//  Values are 32 bit values laid out as follows:\n//\n//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\n//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0\n//  +---+-+-+-----------------------+-------------------------------+\n//  |Sev|C|R|     Facility          |               Code            |\n//  +---+-+-+-----------------------+-------------------------------+\n//\n//  where\n//\n//      Sev - is the severity code\n//\n//          00 - Success\n//          01 - Informational\n//          10 - Warning\n//          11 - Error\n//\n//      C - is the Customer code flag\n//\n//      R - is a reserved bit\n//\n//      Facility - is the facility code\n//\n//      Code - is the facility's status code\n//\n//\n// Define the facility codes\n//\n#define FACILITY_SI                      0x1\n#define FACILITY_SI_DYNDATA              0x2\n#define FACILITY_KSI                     0x3\n\n\n//\n// Define the severity codes\n//\n#define STATUS_SEVERITY_SUCCESS          0x0\n#define STATUS_SEVERITY_INFORMATIONAL    0x1\n#define STATUS_SEVERITY_WARNING          0x2\n#define STATUS_SEVERITY_ERROR            0x3\n\n\n//\n// MessageId: STATUS_SI_DYNDATA_UNSUPPORTED_KERNEL\n//\n// MessageText:\n//\n// System Informer dynamic data is not yet supported on this kernel version.\n//\n#define STATUS_SI_DYNDATA_UNSUPPORTED_KERNEL ((NTSTATUS)0xE0020001L)\n\n//\n// MessageId: STATUS_SI_DYNDATA_VERSION_MISMATCH\n//\n// MessageText:\n//\n// System Informer dynamic data version is incompatible.\n//\n#define STATUS_SI_DYNDATA_VERSION_MISMATCH ((NTSTATUS)0xE0020002L)\n\n//\n// MessageId: STATUS_SI_DYNDATA_INVALID_LENGTH\n//\n// MessageText:\n//\n// System Informer dynamic data is an invalid length.\n//\n#define STATUS_SI_DYNDATA_INVALID_LENGTH ((NTSTATUS)0xE0020003L)\n\n//\n// MessageId: STATUS_SI_DYNDATA_INVALID_SIGNATURE\n//\n// MessageText:\n//\n// System Informer dynamic data signature is invalid.\n//\n#define STATUS_SI_DYNDATA_INVALID_SIGNATURE ((NTSTATUS)0xE0020004L)\n\n//\n// MessageId: STATUS_SI_KSIDLL_VERSION_MISMATCH\n//\n// MessageText:\n//\n// System Informer kernel library version is incompatible.\n//\n#define STATUS_SI_KSIDLL_VERSION_MISMATCH ((NTSTATUS)0xE0030001L)\n\n#endif\n"
  },
  {
    "path": "kphlib/include/sistatus.rc",
    "content": "LANGUAGE 0x9,0x1\n1 11 \"sistatus_MSG00001.bin\"\n"
  },
  {
    "path": "kphlib/kphdyn.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * THIS IS AN AUTOGENERATED FILE, DO NOT MODIFY\n *\n */\n\n#include <kphlibbase.h>\n\n#ifdef _WIN64\nCONST BYTE KphDynConfig[] =\n{\n    0x10, 0x00, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31,\n    0x00, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n    0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xde,\n    0x4c, 0x64, 0xca, 0x4e, 0xea, 0x1c, 0x06, 0xbd,\n    0x40, 0x42, 0x46, 0x3a, 0x80, 0x2e, 0xb1, 0x13,\n    0xce, 0x53, 0x6b, 0x00, 0xc0, 0x53, 0x79, 0x54,\n    0xb2, 0xf3, 0xc2, 0xad, 0x21, 0xfd, 0xb4, 0x06,\n    0xb2, 0xa7, 0x8f, 0x75, 0xc4, 0xf2, 0xc9, 0x6b,\n    0x30, 0x7e, 0x46, 0x48, 0x70, 0x58, 0x38, 0x26,\n    0x14, 0x63, 0xc9, 0xb7, 0xb6, 0x28, 0x90, 0xa5,\n    0x3e, 0x03, 0xfc, 0x30, 0xd7, 0xe0, 0xf9, 0x06,\n    0xc1, 0x08, 0x5a, 0x7a, 0x1d, 0x64, 0x2b, 0x2c,\n    0x21, 0x25, 0x4d, 0x97, 0x22, 0x66, 0xd6, 0x2b,\n    0x16, 0x4b, 0x83, 0xa7, 0x00, 0x40, 0xff, 0xd4,\n    0xb3, 0xb9, 0xed, 0x6b, 0x11, 0x89, 0x87, 0x7b,\n    0xaa, 0xfd, 0x27, 0x9d, 0x9c, 0x2c, 0x2c, 0x6d,\n    0xad, 0x8e, 0xd7, 0xbc, 0xe2, 0x0a, 0xce, 0x27,\n    0x08, 0x35, 0xde, 0x32, 0x77, 0xac, 0xc6, 0x21,\n    0xba, 0x06, 0xeb, 0xd2, 0xce, 0x5b, 0xf2, 0x14,\n    0x8f, 0x7c, 0x20, 0x99, 0x43, 0x25, 0xd4, 0x3f,\n    0xdd, 0x7e, 0xbb, 0xe4, 0xf8, 0x3b, 0x3b, 0xb9,\n    0x2f, 0x74, 0xa5, 0xaf, 0xa4, 0x47, 0x8a, 0x21,\n    0x83, 0x4d, 0x40, 0x69, 0x55, 0x6f, 0xef, 0x26,\n    0x9c, 0x76, 0x80, 0xe0, 0x4e, 0x12, 0x95, 0xb6,\n    0x8c, 0xfa, 0x4b, 0x4d, 0x6d, 0x8a, 0x37, 0xb6,\n    0xdd, 0x21, 0xd7, 0x99, 0x0f, 0xeb, 0x7b, 0x95,\n    0xe8, 0xc9, 0x39, 0x58, 0xbb, 0x56, 0x3b, 0x3c,\n    0x21, 0x63, 0x29, 0xdb, 0x36, 0xe2, 0x81, 0xf2,\n    0x46, 0x61, 0xb6, 0xec, 0xdb, 0x19, 0x73, 0xe5,\n    0x25, 0x12, 0xbe, 0x98, 0x99, 0x0f, 0x52, 0x75,\n    0xfa, 0x8a, 0x12, 0x52, 0xe1, 0x01, 0x82, 0x29,\n    0x79, 0x69, 0x7b, 0x2b, 0xdb, 0xbd, 0x7f, 0x0a,\n    0x87, 0xad, 0x9a, 0x1f, 0xc0, 0xc1, 0x6c, 0x96,\n    0x7d, 0x84, 0x86, 0xad, 0x53, 0x64, 0x7d, 0x88,\n    0x67, 0xe2, 0x56, 0x7f, 0x89, 0x6c, 0x00, 0x30,\n    0xc7, 0xeb, 0x93, 0xcf, 0x58, 0xb0, 0xe3, 0xdc,\n    0x4d, 0x23, 0xad, 0x78, 0x8b, 0xad, 0xfc, 0x1d,\n    0x09, 0x49, 0x92, 0xcb, 0x7a, 0x0c, 0x6e, 0xca,\n    0x50, 0xab, 0xdd, 0x0e, 0xba, 0xe4, 0x8b, 0x87,\n    0x16, 0x94, 0x66, 0x03, 0x0d, 0x07, 0xdc, 0xb8,\n    0x06, 0xe7, 0x29, 0xc5, 0x57, 0xee, 0x65, 0xf2,\n    0x7e, 0x85, 0xc2, 0x49, 0x28, 0xa3, 0x4e, 0x69,\n    0x3e, 0xad, 0x81, 0x2d, 0x47, 0xc8, 0x31, 0xa4,\n    0xae, 0x3b, 0x23, 0xf6, 0x33, 0x5f, 0xa3, 0xa2,\n    0xbf, 0x77, 0xfe, 0x98, 0x76, 0xb0, 0x37, 0xd6,\n    0x08, 0x09, 0x8e, 0x6e, 0x8c, 0xfb, 0x77, 0x87,\n    0xf2, 0x29, 0xc2, 0x00, 0xb9, 0xad, 0x2a, 0x71,\n    0x5b, 0x64, 0x1f, 0x06, 0x2b, 0x18, 0x17, 0xb7,\n    0x90, 0xa4, 0xef, 0xf2, 0x64, 0x26, 0x20, 0xe4,\n    0x15, 0xe0, 0xec, 0xd6, 0x86, 0xde, 0x70, 0x8a,\n    0xcd, 0x57, 0xfe, 0xb2, 0xd3, 0x16, 0xbf, 0xd4,\n    0x72, 0x5b, 0x26, 0xd6, 0x80, 0x84, 0x10, 0xab,\n    0xd1, 0x12, 0x4d, 0x84, 0xca, 0x99, 0x22, 0x72,\n    0x7d, 0x95, 0xde, 0x31, 0x0e, 0x01, 0x80, 0x3f,\n    0xce, 0x5d, 0x11, 0xf8, 0xa1, 0x66, 0x2a, 0xdf,\n    0x42, 0x24, 0x69, 0x3e, 0x47, 0x8d, 0xb7, 0x96,\n    0xb2, 0x36, 0x70, 0x41, 0x5f, 0xc8, 0x63, 0x5f,\n    0xa1, 0x39, 0x2d, 0x2b, 0xdd, 0xe2, 0xf5, 0xb9,\n    0x8d, 0xe0, 0x91, 0x73, 0xa8, 0xca, 0xbf, 0xa7,\n    0x77, 0x61, 0x9f, 0xa2, 0x30, 0x18, 0x31, 0xdb,\n    0x79, 0x89, 0xed, 0xe1, 0x89, 0x45, 0x52, 0x05,\n    0x7c, 0xd7, 0x11, 0x15, 0x45, 0xd4, 0x19, 0xe1,\n    0xf4, 0x23, 0xd9, 0x9d, 0xb0, 0x80, 0x19, 0xb8,\n    0x79, 0x20, 0x8c, 0xcb, 0xa3, 0xe3, 0x53, 0x4e,\n    0x8b, 0x2e, 0xc1, 0x9c, 0x0a, 0x53, 0x1a, 0x14,\n    0x65, 0x71, 0xc4, 0x66, 0x4a, 0x82, 0x8a, 0xf3,\n    0x67, 0x50, 0xfa, 0xb7, 0x3a, 0x25, 0x61, 0x5a,\n    0x0e, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcf,\n    0x00, 0xbe, 0x54, 0x00, 0xb0, 0x80, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0a,\n    0xd8, 0x3a, 0x55, 0x00, 0x20, 0x84, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1a,\n    0x3c, 0x9f, 0x55, 0x00, 0x20, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x14,\n    0xd1, 0xa9, 0x55, 0x00, 0x20, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x32,\n    0x9f, 0xb9, 0x55, 0x00, 0x20, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb6,\n    0xbc, 0xc9, 0x55, 0x00, 0x20, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6b,\n    0x62, 0xd5, 0x55, 0x00, 0x20, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0x56, 0xfa, 0x55, 0x00, 0x20, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0xa4, 0x0c, 0x56, 0x00, 0x20, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x48,\n    0x4f, 0xcc, 0x56, 0x00, 0x20, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc8,\n    0xb3, 0x08, 0x57, 0x00, 0x20, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1c,\n    0x78, 0xa1, 0x57, 0x00, 0x10, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcf,\n    0x97, 0xcf, 0x57, 0x00, 0x10, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6b,\n    0xe7, 0xed, 0x57, 0x00, 0x10, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x37,\n    0x05, 0x0f, 0x58, 0x00, 0x10, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3c,\n    0x07, 0x30, 0x58, 0x00, 0x10, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa3,\n    0x50, 0xba, 0x58, 0x00, 0x10, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x84, 0xcd, 0x58, 0x00, 0x10, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xea,\n    0x15, 0xda, 0x58, 0x00, 0x10, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7c,\n    0x9c, 0x02, 0x59, 0x00, 0x00, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x52,\n    0x9c, 0x32, 0x59, 0x00, 0xf0, 0x84, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x52,\n    0xd8, 0x44, 0x59, 0x00, 0xf0, 0x84, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd6,\n    0xfc, 0x5d, 0x59, 0x00, 0xf0, 0x84, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb8,\n    0xe6, 0x81, 0x59, 0x00, 0xf0, 0x84, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcf,\n    0x38, 0xae, 0x59, 0x00, 0xf0, 0x84, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf4,\n    0xb0, 0xc0, 0x59, 0x00, 0xf0, 0x84, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8b,\n    0x7a, 0x20, 0x5a, 0x00, 0xf0, 0x84, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x84,\n    0xd5, 0x4a, 0x5a, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x85,\n    0xc3, 0x5b, 0x5a, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0x8e, 0x7e, 0x5a, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x00,\n    0xa8, 0x97, 0x5a, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdc,\n    0xec, 0xb5, 0x5a, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2c,\n    0x12, 0xe4, 0x5a, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc0,\n    0x83, 0x0e, 0x5b, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x24,\n    0x87, 0x34, 0x5b, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb8,\n    0x4d, 0x48, 0x5b, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x92,\n    0x56, 0x69, 0x5b, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x97,\n    0x5e, 0x90, 0x5b, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x63,\n    0xc7, 0xa9, 0x5b, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x37,\n    0x51, 0xd1, 0x5b, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x85,\n    0x22, 0x06, 0x5c, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7f,\n    0x0a, 0x2b, 0x5c, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2d,\n    0x59, 0x5a, 0x5c, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf7,\n    0xe9, 0x69, 0x5c, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc9,\n    0x7d, 0x7f, 0x5c, 0x00, 0xb0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0xfd, 0xa2, 0x5c, 0x00, 0xb0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x23,\n    0x7c, 0xad, 0x5c, 0x00, 0xb0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x17,\n    0xf0, 0xcb, 0x5c, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x16,\n    0x96, 0x1d, 0x5d, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x71,\n    0xec, 0x3f, 0x5d, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf8,\n    0x5a, 0x67, 0x5d, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x24,\n    0x4d, 0x91, 0x5d, 0x00, 0xc0, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe8,\n    0x2e, 0xb1, 0x5d, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x45,\n    0xa6, 0xe7, 0x5d, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x48,\n    0xd9, 0xf1, 0x5d, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x05,\n    0xd5, 0x2f, 0x5e, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x02,\n    0x7a, 0x5f, 0x5e, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x98,\n    0xe9, 0x82, 0x5e, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb2,\n    0xe4, 0xb0, 0x5e, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x76,\n    0x0b, 0xd6, 0x5e, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8a,\n    0xbc, 0xe4, 0x5e, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x87, 0x05, 0x5f, 0x00, 0x80, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x85,\n    0x58, 0x2b, 0x5f, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7f,\n    0x4c, 0x4f, 0x5f, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x45,\n    0x18, 0x74, 0x5f, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x84,\n    0x51, 0x9a, 0x5f, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0xc2, 0xc8, 0x5f, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0xbe, 0xf7, 0x5f, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0x50, 0xfd, 0x5f, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5f,\n    0x5b, 0x50, 0x60, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8b,\n    0xd8, 0x6e, 0x60, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x48,\n    0xa3, 0x87, 0x60, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x70,\n    0x29, 0xbb, 0x60, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x72,\n    0x39, 0xe1, 0x60, 0x00, 0x70, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x09,\n    0x15, 0xe3, 0x60, 0x00, 0x60, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcd,\n    0x03, 0x05, 0x61, 0x00, 0x60, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe5,\n    0x7a, 0x3d, 0x61, 0x00, 0x60, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd1,\n    0xfa, 0x5b, 0x61, 0x00, 0x50, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0xca, 0x80, 0x61, 0x00, 0x50, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x74,\n    0xef, 0xaa, 0x61, 0x00, 0x50, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x27,\n    0x3f, 0xd5, 0x61, 0x00, 0x50, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0x4e, 0xe1, 0x61, 0x00, 0x50, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x35,\n    0xe0, 0xf4, 0x61, 0x00, 0x50, 0x85, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa6,\n    0x0e, 0x1f, 0x62, 0x00, 0x60, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0d,\n    0x10, 0x44, 0x62, 0x00, 0x60, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x53,\n    0x83, 0x70, 0x62, 0x00, 0x60, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcc,\n    0x55, 0xa0, 0x62, 0x00, 0x60, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x49,\n    0xba, 0xba, 0x62, 0x00, 0x60, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xad,\n    0x66, 0xeb, 0x62, 0x00, 0x60, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0x22, 0x18, 0x63, 0x00, 0x60, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x88,\n    0xfe, 0x3a, 0x63, 0x00, 0x50, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb0,\n    0x9e, 0x47, 0x63, 0x00, 0x50, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0x9b, 0x64, 0x63, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf5,\n    0x43, 0x88, 0x63, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x54,\n    0xc1, 0xb7, 0x63, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc7,\n    0xba, 0xd8, 0x63, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd8,\n    0xbb, 0x09, 0x64, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x55,\n    0x43, 0x25, 0x64, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0xb7, 0x4c, 0x64, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x37,\n    0x37, 0x78, 0x64, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x64,\n    0x22, 0x92, 0x64, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdb,\n    0x8f, 0xa4, 0x64, 0x00, 0x70, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0xcf, 0xca, 0x64, 0x00, 0x70, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7d,\n    0x19, 0xd3, 0x64, 0x00, 0x70, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0x32, 0x1f, 0x65, 0x00, 0x70, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0x3b, 0x46, 0x65, 0x00, 0x70, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x36,\n    0x1c, 0x5c, 0x65, 0x00, 0x70, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1a,\n    0x3d, 0x81, 0x65, 0x00, 0x70, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x20,\n    0x62, 0xaf, 0x65, 0x00, 0x70, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x40,\n    0x90, 0xdd, 0x65, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x35,\n    0xb0, 0x07, 0x66, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x04,\n    0xc6, 0x3a, 0x66, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xad,\n    0x93, 0x62, 0x66, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x15,\n    0x1a, 0x7d, 0x66, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xaa,\n    0x97, 0xac, 0x66, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0xa9, 0xbd, 0x66, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x12,\n    0xbf, 0xeb, 0x66, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0d,\n    0x47, 0x17, 0x67, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x71,\n    0x47, 0x38, 0x67, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc3,\n    0x95, 0x5a, 0x67, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd0,\n    0x87, 0x98, 0x67, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x83,\n    0x00, 0xab, 0x67, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb1,\n    0x48, 0xde, 0x67, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0x51, 0xf7, 0x67, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8f,\n    0x17, 0x2c, 0x68, 0x00, 0x80, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xae,\n    0x8b, 0x63, 0x68, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xad,\n    0xb0, 0x8d, 0x68, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5f,\n    0x32, 0xb1, 0x68, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc8,\n    0x7f, 0xe6, 0x68, 0x00, 0x90, 0x85, 0x00, 0x46,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd1,\n    0xd2, 0x32, 0x56, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x70,\n    0x11, 0x3b, 0x56, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0x77, 0x45, 0x56, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x58,\n    0x1c, 0x8b, 0x56, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0x49, 0xa8, 0x56, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4e,\n    0x07, 0xcc, 0x56, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0x44, 0xcd, 0x56, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x56,\n    0x1e, 0xfa, 0x56, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x45,\n    0xf4, 0x1a, 0x57, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfe,\n    0xf4, 0x3b, 0x57, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8b,\n    0x17, 0x49, 0x57, 0x00, 0xc0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf5,\n    0xe2, 0x75, 0x57, 0x00, 0xa0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x15,\n    0xb6, 0xa1, 0x57, 0x00, 0xa0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0x94, 0xcf, 0x57, 0x00, 0xa0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe9,\n    0x70, 0xf4, 0x57, 0x00, 0xa0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0xf0, 0x0e, 0x58, 0x00, 0xa0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xce,\n    0x3e, 0xba, 0x58, 0x00, 0xa0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa1,\n    0x6f, 0xcd, 0x58, 0x00, 0xa0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x56,\n    0x8f, 0x02, 0x59, 0x00, 0x90, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xab,\n    0x87, 0x32, 0x59, 0x00, 0x90, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa2,\n    0xc7, 0x44, 0x59, 0x00, 0x90, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xce,\n    0x32, 0x5f, 0x59, 0x00, 0x90, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa1,\n    0x69, 0x7c, 0x59, 0x00, 0x90, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd4,\n    0x2e, 0xae, 0x59, 0x00, 0x90, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x13,\n    0x16, 0xba, 0x59, 0x00, 0x90, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x76,\n    0xe4, 0xf3, 0x59, 0x00, 0x90, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0x15, 0x20, 0x5a, 0x00, 0x90, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb5,\n    0x6f, 0x4a, 0x5a, 0x00, 0xe0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xea,\n    0xcd, 0x5b, 0x5a, 0x00, 0xe0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbe,\n    0x7d, 0x7e, 0x5a, 0x00, 0xe0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x43,\n    0x96, 0x97, 0x5a, 0x00, 0xe0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x03,\n    0xa1, 0xb4, 0x5a, 0x00, 0xe0, 0x7c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6a,\n    0x95, 0x36, 0x57, 0x00, 0x40, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x67,\n    0x96, 0x36, 0x57, 0x00, 0x00, 0x0c, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf1,\n    0x98, 0x89, 0x57, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xd2,\n    0x99, 0x89, 0x57, 0x00, 0x60, 0x0c, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xbf,\n    0x53, 0xa0, 0x57, 0x00, 0x60, 0x0c, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0x58, 0xa5, 0x57, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc6,\n    0xe3, 0xb7, 0x57, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0x9a, 0xcf, 0x57, 0x00, 0xf0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa7,\n    0xca, 0xda, 0x57, 0x00, 0xf0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xc8,\n    0xcb, 0xda, 0x57, 0x00, 0x60, 0x0c, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x41,\n    0xc5, 0xf4, 0x57, 0x00, 0xf0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x3c,\n    0xc6, 0xf4, 0x57, 0x00, 0x60, 0x0c, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbe,\n    0xa4, 0x01, 0x58, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1f,\n    0xbd, 0x19, 0x58, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf4,\n    0x89, 0x25, 0x58, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf6,\n    0x77, 0x4a, 0x58, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x51,\n    0x26, 0x5a, 0x58, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe7,\n    0x57, 0x78, 0x58, 0x00, 0x90, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0xd7, 0x86, 0x58, 0x00, 0x90, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0x5a, 0xba, 0x58, 0x00, 0x80, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x97,\n    0xf0, 0xd9, 0x58, 0x00, 0x80, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0x81, 0x02, 0x59, 0x00, 0x80, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb1,\n    0x78, 0x32, 0x59, 0x00, 0x80, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x81,\n    0x29, 0x5f, 0x59, 0x00, 0x70, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xca,\n    0xac, 0x65, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf6,\n    0x07, 0x80, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7e,\n    0xc8, 0x80, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0x44, 0x89, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x91,\n    0xb6, 0x9b, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x21,\n    0xd1, 0xb0, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0x01, 0xbb, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x68,\n    0x2c, 0xbf, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc8,\n    0xd4, 0xda, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x89,\n    0xf5, 0xf3, 0x59, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x65,\n    0xa9, 0x0f, 0x5a, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6d,\n    0xb4, 0x1f, 0x5a, 0x00, 0x60, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2b,\n    0xbb, 0x49, 0x5a, 0x00, 0x20, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xa9,\n    0xbc, 0x49, 0x5a, 0x00, 0x60, 0x0c, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8b,\n    0x00, 0x57, 0x5a, 0x00, 0x20, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x98,\n    0x6e, 0x7e, 0x5a, 0x00, 0x20, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf0,\n    0x0a, 0x82, 0x5a, 0x00, 0x20, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc8,\n    0x07, 0x99, 0x5a, 0x00, 0x20, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x86,\n    0x22, 0x9e, 0x5a, 0x00, 0x20, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x98,\n    0x1a, 0xb3, 0x5a, 0x00, 0x20, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0xae, 0xbd, 0x5a, 0x00, 0x20, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd4,\n    0xf6, 0xc2, 0x5a, 0x00, 0x20, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0xf9, 0xe3, 0x5a, 0x00, 0x10, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7e,\n    0x09, 0xe4, 0x5a, 0x00, 0x10, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdf,\n    0x16, 0x1a, 0x5b, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe0,\n    0x16, 0x1f, 0x5b, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcd,\n    0xad, 0x31, 0x5b, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0x25, 0x48, 0x5b, 0x00, 0x00, 0x82, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x64,\n    0xda, 0x4a, 0x5b, 0x00, 0xf0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9f,\n    0x1a, 0x69, 0x5b, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x24,\n    0x2b, 0x7e, 0x5b, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x16,\n    0xc5, 0x84, 0x5b, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0x54, 0x88, 0x5b, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x8d,\n    0x56, 0x88, 0x5b, 0x00, 0x60, 0x0c, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf0,\n    0x96, 0xb6, 0x5b, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x57,\n    0xad, 0xbd, 0x5b, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0x34, 0xd1, 0x5b, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x77,\n    0x7f, 0xda, 0x5b, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4a,\n    0x0d, 0x06, 0x5c, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0xf2, 0x2a, 0x5c, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x72,\n    0x49, 0x30, 0x5c, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x30,\n    0x42, 0x5a, 0x5c, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x31,\n    0xbf, 0x68, 0x5c, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0x63, 0x7f, 0x5c, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0xea, 0x89, 0x5c, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x00,\n    0xe1, 0xa2, 0x5c, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0x15, 0xcd, 0x5c, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0x6c, 0xe3, 0x5c, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbf,\n    0xd0, 0x01, 0x5d, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1e,\n    0x7d, 0x1d, 0x5d, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0x06, 0x24, 0x5d, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0f,\n    0x72, 0x3a, 0x5d, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x99,\n    0x90, 0x4a, 0x5d, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb2,\n    0xc6, 0x69, 0x5d, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa6,\n    0x6c, 0x78, 0x5d, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0x34, 0x91, 0x5d, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0xb9, 0x93, 0x5d, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4c,\n    0xfe, 0xa7, 0x5d, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x81,\n    0xba, 0xdc, 0x5d, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1c,\n    0x4c, 0xfc, 0x5d, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbd,\n    0xf8, 0xfa, 0x5d, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x48,\n    0x83, 0x34, 0x5e, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0xe9, 0x4c, 0x5e, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4a,\n    0x4d, 0x5f, 0x5e, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x54,\n    0xfb, 0x6a, 0x5e, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0x44, 0x8d, 0x5e, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0x41, 0x91, 0x5e, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5c,\n    0xbf, 0xb0, 0x5e, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0xdc, 0xd5, 0x5e, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0x13, 0xe8, 0x5e, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x45,\n    0x6c, 0x05, 0x5f, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x65,\n    0x7f, 0x2c, 0x5f, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3d,\n    0x30, 0x4f, 0x5f, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0xfd, 0x77, 0x5f, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0x3f, 0x9a, 0x5f, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3f,\n    0xce, 0xb1, 0x5f, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x17,\n    0x6d, 0xc8, 0x5f, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x49,\n    0x8d, 0xf7, 0x5f, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x75,\n    0x44, 0x12, 0x60, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc0,\n    0x68, 0x40, 0x60, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x70,\n    0x3c, 0x50, 0x60, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1c,\n    0xb0, 0x6e, 0x60, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe4,\n    0x95, 0x87, 0x60, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8c,\n    0xfe, 0xba, 0x60, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3b,\n    0x66, 0xe2, 0x60, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0x3d, 0xe3, 0x60, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x36,\n    0x1d, 0xff, 0x60, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbb,\n    0xd5, 0x04, 0x61, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe3,\n    0x5d, 0x3d, 0x61, 0x00, 0xd0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdd,\n    0xdf, 0x5b, 0x61, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x17,\n    0x89, 0x80, 0x61, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4f,\n    0x72, 0x8d, 0x61, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbc,\n    0x8e, 0xa9, 0x61, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5e,\n    0x9d, 0xce, 0x61, 0x00, 0xb0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0x23, 0xd5, 0x61, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x43,\n    0x51, 0xe2, 0x61, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd3,\n    0x2c, 0xf8, 0x61, 0x00, 0xc0, 0x81, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4d,\n    0xf3, 0x1e, 0x62, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0xcb, 0x47, 0x62, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x97,\n    0xa9, 0x6c, 0x62, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x43,\n    0x71, 0x80, 0x62, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd8,\n    0xf3, 0xa3, 0x62, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6a,\n    0xb7, 0xbf, 0x62, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xae,\n    0x02, 0xef, 0x62, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x49,\n    0xbd, 0x17, 0x63, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xae,\n    0x89, 0x36, 0x63, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x62,\n    0xba, 0x47, 0x63, 0x00, 0xd0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc0,\n    0x7a, 0x64, 0x63, 0x00, 0x00, 0x82, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x91,\n    0x0f, 0x73, 0x63, 0x00, 0x00, 0x82, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1f,\n    0x23, 0x88, 0x63, 0x00, 0x00, 0x82, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x98,\n    0x92, 0xb7, 0x63, 0x00, 0x00, 0x82, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x17,\n    0xda, 0xdd, 0x63, 0x00, 0x00, 0x82, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfa,\n    0x90, 0x09, 0x64, 0x00, 0x00, 0x82, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6e,\n    0x3b, 0x25, 0x64, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0x68, 0x54, 0x64, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfd,\n    0x1d, 0x92, 0x64, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x35,\n    0x52, 0xa4, 0x64, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcd,\n    0xa5, 0xca, 0x64, 0x00, 0xe0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2c,\n    0x81, 0x02, 0x65, 0x00, 0xe0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xab,\n    0xb4, 0x45, 0x65, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0xf5, 0x52, 0x65, 0x00, 0xe0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xac,\n    0x15, 0x81, 0x65, 0x00, 0xe0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7c,\n    0x3a, 0xaf, 0x65, 0x00, 0xe0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd2,\n    0x65, 0xdd, 0x65, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0x5f, 0x0f, 0x66, 0x00, 0x00, 0x82, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7a,\n    0xb6, 0x35, 0x66, 0x00, 0x00, 0x82, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x96,\n    0x6a, 0x62, 0x66, 0x00, 0x00, 0x82, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0x37, 0x7a, 0x66, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9d,\n    0x6f, 0xac, 0x66, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x43,\n    0xd3, 0xba, 0x66, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x98,\n    0xd5, 0xba, 0x66, 0x00, 0x60, 0x0c, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc7,\n    0x01, 0xf6, 0x66, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xeb,\n    0x30, 0x17, 0x67, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x44,\n    0x19, 0x48, 0x67, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7d,\n    0xb7, 0x5b, 0x67, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbb,\n    0x44, 0x8f, 0x67, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3e,\n    0x4d, 0xab, 0x67, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa4,\n    0xea, 0xd4, 0x67, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7c,\n    0x47, 0xf4, 0x67, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8c,\n    0xe9, 0x13, 0x68, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x27,\n    0xee, 0x2b, 0x68, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x52,\n    0x2a, 0x66, 0x68, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd0,\n    0x83, 0x8d, 0x68, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfe,\n    0xcd, 0xb7, 0x68, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdf,\n    0x63, 0xe6, 0x68, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb4,\n    0xa0, 0xf9, 0x68, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x31,\n    0x00, 0x31, 0x69, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x92, 0x41, 0x69, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe4,\n    0xbb, 0x4c, 0x69, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0x02, 0x6f, 0x69, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8b,\n    0xc2, 0xa2, 0x69, 0x00, 0xf0, 0x81, 0x00, 0xdc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4c,\n    0xba, 0xcc, 0x58, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xdc,\n    0xdd, 0x68, 0xce, 0x00, 0xa0, 0x0d, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7d,\n    0x8f, 0xdc, 0x58, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf6,\n    0xe9, 0xde, 0x58, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x47,\n    0xfd, 0xf6, 0x58, 0x00, 0xa0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3e,\n    0x84, 0x02, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x02,\n    0xd9, 0x1f, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0x79, 0x32, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd5,\n    0xaa, 0x48, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x28,\n    0xde, 0x47, 0x96, 0x00, 0xa0, 0x0d, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xeb,\n    0x24, 0x5f, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9f,\n    0xb8, 0x7a, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0d,\n    0xd8, 0x7f, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x61,\n    0x4d, 0xe1, 0xee, 0x00, 0xa0, 0x0d, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7e,\n    0x23, 0xae, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0xf4, 0xcd, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x5b,\n    0x28, 0x8f, 0xf9, 0x00, 0xa0, 0x0d, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0x6a, 0xe3, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x38,\n    0x9d, 0xfa, 0x59, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x49,\n    0xa2, 0x0e, 0x5a, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x22,\n    0x6e, 0x1f, 0x5a, 0x00, 0x90, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x8e, 0x49, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x3e,\n    0xa7, 0x87, 0xc4, 0x00, 0xa0, 0x0d, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb1,\n    0xf0, 0x57, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0x74, 0x7e, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfb,\n    0x0d, 0x82, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2c,\n    0xa1, 0x9c, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdf,\n    0x53, 0x99, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0xb9, 0xbd, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x45,\n    0xfb, 0xc2, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd8,\n    0xf4, 0xe3, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0x28, 0xe2, 0x5a, 0x00, 0x00, 0x89, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0c,\n    0x13, 0x1a, 0x5b, 0x00, 0xe0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4b,\n    0x1d, 0x1f, 0x5b, 0x00, 0xe0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x58,\n    0x6c, 0x34, 0x5b, 0x00, 0xe0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6f,\n    0x27, 0x48, 0x5b, 0x00, 0xe0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6e,\n    0x7f, 0x4e, 0x5b, 0x00, 0xe0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0xf9, 0x5f, 0x5b, 0x00, 0xb0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x39,\n    0xea, 0x60, 0x5b, 0x00, 0xb0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2c,\n    0xd3, 0x85, 0x5b, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe9,\n    0x6c, 0x87, 0x5b, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0x58, 0xac, 0x5b, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x02,\n    0xa8, 0xbd, 0x5b, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd6,\n    0xe1, 0xd7, 0x5b, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x50,\n    0x63, 0xe3, 0x5b, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe0,\n    0x07, 0x06, 0x5c, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9a,\n    0x09, 0x2b, 0x5c, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe5,\n    0x68, 0x56, 0xc6, 0x00, 0xa0, 0x0d, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x13,\n    0x51, 0x30, 0x5c, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7a,\n    0x4c, 0x5a, 0x5c, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0xc0, 0x67, 0x5c, 0x00, 0xb0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6f,\n    0x6c, 0x7f, 0x5c, 0x00, 0xb0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x84,\n    0xf1, 0x89, 0x5c, 0x00, 0xb0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3c,\n    0xf4, 0xa2, 0x5c, 0x00, 0xb0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0x35, 0xa8, 0x5c, 0x00, 0xb0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8e,\n    0xe0, 0xcb, 0x5c, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0xc7, 0xe4, 0x5c, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4b,\n    0xef, 0xf9, 0x5c, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdd,\n    0xe2, 0x01, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb8,\n    0xac, 0x1d, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x09,\n    0x0a, 0x24, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xeb,\n    0xf5, 0x3f, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7a,\n    0x12, 0x4b, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xab,\n    0xcd, 0x69, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe1,\n    0x40, 0x6f, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc7,\n    0x3a, 0x91, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3e,\n    0xf4, 0xa7, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0xbf, 0xdc, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcf,\n    0x80, 0xfc, 0x5d, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x05,\n    0x34, 0x29, 0x5e, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0x56, 0x5f, 0x5e, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6d,\n    0x47, 0x8d, 0x5e, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf4,\n    0xc3, 0xb0, 0x5e, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2b,\n    0xdc, 0xd5, 0x5e, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0x2e, 0xe5, 0x5e, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa5,\n    0x80, 0x05, 0x5f, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa8,\n    0xaa, 0x2b, 0x5f, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0x19, 0x50, 0x5f, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x37,\n    0x04, 0x75, 0x5f, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe2,\n    0x38, 0x9a, 0x5f, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1f,\n    0x6c, 0xc8, 0x5f, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x27,\n    0x8f, 0xf7, 0x5f, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0xae, 0x0f, 0x60, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0xdb, 0x39, 0x60, 0x00, 0xc0, 0x88, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0xce, 0x44, 0x59, 0x00, 0x80, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0xa7, 0xcd, 0x59, 0x00, 0x20, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x9d,\n    0xd9, 0xd9, 0xd8, 0x00, 0x60, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3b,\n    0x59, 0xdc, 0x59, 0x00, 0x20, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0xff, 0xef, 0x59, 0x00, 0x20, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x40,\n    0xaa, 0x1a, 0x5a, 0x00, 0x20, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd4,\n    0xb8, 0x29, 0x5a, 0x00, 0x20, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x5f,\n    0x11, 0xd2, 0xa1, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0x16, 0x4a, 0x5a, 0x00, 0x50, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x47,\n    0xb4, 0x5f, 0x5a, 0x00, 0x60, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xcb,\n    0xa3, 0xdc, 0x1b, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0x76, 0x7e, 0x5a, 0x00, 0x60, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x50,\n    0x0c, 0x8e, 0x5a, 0x00, 0x60, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x99,\n    0x7e, 0x3c, 0x45, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x77,\n    0x91, 0x97, 0x5a, 0x00, 0x60, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x73,\n    0x60, 0xa7, 0x5a, 0x00, 0x60, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x89,\n    0xad, 0xbd, 0x5a, 0x00, 0x50, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe6,\n    0x20, 0xef, 0xeb, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x05,\n    0xaf, 0xd3, 0x5a, 0x00, 0x50, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xdf,\n    0x7f, 0x4c, 0x40, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa2,\n    0xa6, 0xea, 0x5a, 0x00, 0x50, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc9,\n    0x0d, 0xf6, 0x5a, 0x00, 0x50, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x22,\n    0x1a, 0x1a, 0x5b, 0x00, 0x40, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc8,\n    0x85, 0x21, 0x5b, 0x00, 0xe0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe4,\n    0xe5, 0x35, 0x5b, 0x00, 0xe0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0x29, 0x48, 0x5b, 0x00, 0xe0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x97,\n    0x9d, 0x4e, 0x5b, 0x00, 0xe0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0f,\n    0x23, 0x69, 0x5b, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x54,\n    0xc1, 0x6b, 0x5b, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0xcc, 0x84, 0x5b, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x98,\n    0x2f, 0xd4, 0xdb, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0x72, 0x9c, 0x5b, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x54,\n    0x0e, 0xa7, 0x5b, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x69,\n    0xb2, 0xa9, 0x5b, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x75, 0xbd, 0x5b, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x29,\n    0xdd, 0xd7, 0x5b, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0x71, 0xe2, 0x5b, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdd,\n    0x0f, 0x06, 0x5c, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x77,\n    0xf5, 0x2a, 0x5c, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x71,\n    0x2c, 0x4d, 0xf7, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3e,\n    0x52, 0x30, 0x5c, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5f,\n    0x44, 0x5a, 0x5c, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb2,\n    0xb5, 0x68, 0x5c, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x49,\n    0x8b, 0x7f, 0x5c, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x7c,\n    0xc0, 0xe4, 0x54, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x27,\n    0x03, 0x8a, 0x5c, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1b,\n    0xe5, 0xa2, 0x5c, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xa6,\n    0x76, 0xd9, 0x02, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x62,\n    0x34, 0xa8, 0x5c, 0x00, 0xa0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc4,\n    0xda, 0xcb, 0x5c, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xde,\n    0x0b, 0xe6, 0x5c, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd2,\n    0xf6, 0xf9, 0x5c, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0xd3, 0x01, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8a,\n    0xa8, 0x1e, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5c,\n    0x05, 0x24, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x16,\n    0x85, 0x4a, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcf,\n    0xab, 0x4b, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7f,\n    0x47, 0x6f, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0a,\n    0x1d, 0x7b, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4f,\n    0x2f, 0x94, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x37,\n    0x28, 0x94, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x16,\n    0x1a, 0xb1, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x0a,\n    0xca, 0x18, 0x00, 0x00, 0x70, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9e,\n    0xeb, 0xe5, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4e,\n    0xc5, 0xf1, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2d,\n    0xc5, 0xf1, 0x5d, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb7,\n    0x2c, 0x29, 0x5e, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb4,\n    0x2d, 0x29, 0x5e, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe2,\n    0xb4, 0x61, 0x5e, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc6,\n    0xbf, 0x61, 0x5e, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x45,\n    0xd0, 0x7a, 0x5e, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0xc9, 0x82, 0x5e, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x56,\n    0x11, 0xb1, 0x5e, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd2,\n    0x0e, 0xd6, 0x5e, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0x8b, 0xe4, 0x5e, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x05,\n    0x6d, 0x05, 0x5f, 0x00, 0xb0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0x40, 0x2b, 0x5f, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x57,\n    0x25, 0x4f, 0x5f, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x32,\n    0x3b, 0x74, 0x5f, 0x00, 0xc0, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x65,\n    0x5e, 0xdd, 0x59, 0x00, 0x50, 0x8d, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe4,\n    0x8b, 0xb5, 0x5a, 0x00, 0x50, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x66,\n    0x89, 0xcd, 0x5a, 0x00, 0x50, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb2,\n    0xe4, 0x69, 0xbd, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x48,\n    0xf1, 0xe3, 0x5a, 0x00, 0x50, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xd2,\n    0x18, 0xad, 0x47, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0x5a, 0x01, 0x5b, 0x00, 0x50, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x3e,\n    0x4a, 0xa3, 0xd7, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x78,\n    0xcf, 0x11, 0x5b, 0x00, 0x50, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0x45, 0x1a, 0x5b, 0x00, 0x10, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xdc,\n    0x64, 0x22, 0x8d, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb3,\n    0x43, 0x23, 0x5b, 0x00, 0x10, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x14,\n    0x2e, 0xb4, 0x50, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf4,\n    0x12, 0x3f, 0x5b, 0x00, 0x10, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7f,\n    0x24, 0x48, 0x5b, 0x00, 0x10, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb7,\n    0x73, 0x49, 0x5b, 0x00, 0x20, 0x96, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb5,\n    0xc7, 0x63, 0x5b, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x21,\n    0xc2, 0x6b, 0x5b, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb5,\n    0xb2, 0x88, 0x5b, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe5,\n    0x72, 0x31, 0x02, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe1,\n    0x6b, 0x9c, 0x5b, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0x41, 0x93, 0x5b, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2b,\n    0x68, 0xa4, 0x5b, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xae,\n    0x16, 0xa3, 0x5b, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x7e,\n    0xed, 0x8c, 0xc3, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x09,\n    0x28, 0xcc, 0x5b, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0xa3, 0xda, 0x5b, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc3,\n    0xee, 0xe4, 0x5b, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x68,\n    0x74, 0x0b, 0x5c, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x58,\n    0x1d, 0xe2, 0x97, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x51,\n    0x53, 0x13, 0x5c, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3d,\n    0x0c, 0x2b, 0x5c, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x94,\n    0xb9, 0x41, 0xfd, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa7,\n    0xac, 0x35, 0x5c, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xab,\n    0x45, 0x5a, 0x5c, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd9,\n    0xbb, 0x67, 0x5c, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8f,\n    0x85, 0x7f, 0x5c, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe4,\n    0xae, 0x49, 0x79, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa8,\n    0x08, 0x8a, 0x5c, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x5e,\n    0xe7, 0x28, 0x8a, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x32,\n    0x14, 0xa3, 0x5c, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x4f,\n    0x49, 0xd6, 0x12, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xee,\n    0x50, 0xb9, 0x5c, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x66,\n    0xd8, 0xcb, 0x5c, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x67,\n    0x4f, 0xde, 0x5c, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdb,\n    0x47, 0xde, 0x5c, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0xf4, 0xf9, 0x5c, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5d,\n    0xe9, 0x01, 0x5d, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6c,\n    0x7f, 0x1d, 0x5d, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0x00, 0x24, 0x5d, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf8,\n    0x7e, 0x4a, 0x5d, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd1,\n    0x38, 0x52, 0x5d, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0x40, 0x6f, 0x5d, 0x00, 0x40, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe2,\n    0x18, 0x7b, 0x5d, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x95,\n    0x26, 0x94, 0x5d, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x95,\n    0x24, 0x94, 0x5d, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdb,\n    0xce, 0xc4, 0x5d, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x8c,\n    0x31, 0x15, 0xb3, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa0,\n    0x4f, 0xdf, 0x5d, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x14,\n    0xfa, 0x13, 0x5e, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0xfc, 0x13, 0x5e, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9d,\n    0x66, 0x3a, 0x5e, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf3,\n    0x5d, 0x4f, 0x5e, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0x51, 0x5f, 0x5e, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3b,\n    0x51, 0x5f, 0x5e, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xff,\n    0xae, 0x7c, 0x5e, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcc,\n    0xc1, 0x82, 0x5e, 0x00, 0x30, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x23,\n    0xfe, 0x8c, 0x5e, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0x1b, 0xb2, 0x5e, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x65,\n    0x12, 0x52, 0x63, 0x00, 0xf0, 0x0f, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf1,\n    0x0f, 0xd6, 0x5e, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x06,\n    0x86, 0xe4, 0x5e, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xda,\n    0x87, 0x04, 0x5f, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa1,\n    0x4c, 0x2a, 0x5f, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0x22, 0x4f, 0x5f, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x99,\n    0xfc, 0x73, 0x5f, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xef,\n    0xad, 0x97, 0x5f, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0x34, 0xc8, 0x5f, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb0,\n    0xc0, 0xf6, 0x5f, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x61,\n    0x4c, 0x12, 0x60, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa8,\n    0xe6, 0x38, 0x60, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0xf8, 0x4a, 0x60, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc0,\n    0x19, 0x51, 0x60, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8c,\n    0xaf, 0x6e, 0x60, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3f,\n    0xbf, 0x95, 0x60, 0x00, 0x20, 0x95, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc4,\n    0x4f, 0xa4, 0x1f, 0x00, 0x10, 0x9f, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xff,\n    0x1f, 0x19, 0xb9, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3f,\n    0x43, 0xb4, 0xaf, 0x00, 0x10, 0x9f, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xd1,\n    0xe9, 0x4e, 0xbd, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1e,\n    0x57, 0xb5, 0x8b, 0x00, 0x10, 0x9f, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0xac, 0xea, 0x3e, 0x00, 0x10, 0x9f, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd6,\n    0xb9, 0xfa, 0x6a, 0x00, 0x00, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf7,\n    0x24, 0xdb, 0x3b, 0x00, 0x00, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0xae, 0x34, 0xea, 0x00, 0x00, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9a,\n    0xb7, 0x30, 0x11, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb5,\n    0x56, 0x55, 0x1c, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x58,\n    0x8f, 0x80, 0xa1, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xeb,\n    0xb0, 0x29, 0x82, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xcb,\n    0x99, 0x7d, 0xd8, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0x7e, 0x18, 0x2d, 0x00, 0xf0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x0c, 0x4b, 0xbc, 0x00, 0xf0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0a,\n    0xf0, 0x5b, 0xa4, 0x00, 0xf0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xca,\n    0xb3, 0xac, 0xde, 0x00, 0xf0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x62,\n    0x99, 0xd6, 0xaa, 0x00, 0xf0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb2,\n    0xce, 0x35, 0x3e, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x99,\n    0x7a, 0x14, 0x5b, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0x25, 0x7e, 0x62, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc3,\n    0xfe, 0x8f, 0x43, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x45,\n    0x7b, 0x42, 0x92, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x11,\n    0x97, 0x8c, 0x8e, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1f,\n    0x70, 0x05, 0x61, 0x00, 0x10, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7b,\n    0x08, 0xc0, 0x99, 0x00, 0x10, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0xba, 0xd0, 0x7f, 0x00, 0x10, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0xc3, 0xa6, 0x33, 0x00, 0x10, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x88,\n    0xad, 0x26, 0xf0, 0x00, 0x10, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xaf,\n    0xbf, 0xbe, 0x5e, 0x00, 0x10, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe4,\n    0xf9, 0x53, 0xa0, 0x00, 0x10, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc9,\n    0xa2, 0x55, 0xe5, 0x00, 0x10, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x63,\n    0xaf, 0x1a, 0xc2, 0x00, 0x00, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x5a, 0x8b, 0x2e, 0x00, 0x00, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe0,\n    0x33, 0x58, 0x01, 0x00, 0x00, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb6,\n    0x60, 0x07, 0x32, 0x00, 0x00, 0xa7, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd8,\n    0x71, 0x9a, 0xe5, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0x64, 0x9e, 0xd5, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xbb,\n    0xde, 0xcf, 0xbf, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0xe7, 0x79, 0xdf, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7e,\n    0x5b, 0xb3, 0x11, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0x7b, 0x52, 0xee, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0xed, 0xb6, 0x5f, 0x00, 0xe0, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xda,\n    0x6f, 0x3a, 0x78, 0x00, 0x00, 0xa7, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x3c, 0x74, 0x72, 0x00, 0xf0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5b,\n    0x43, 0x15, 0xd8, 0x00, 0xf0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x29,\n    0xa8, 0x23, 0x1c, 0x00, 0xf0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0x12, 0xb4, 0xf3, 0x00, 0xf0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb3,\n    0x96, 0xb8, 0x87, 0x00, 0xf0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3f,\n    0xfe, 0xa2, 0xbd, 0x00, 0xf0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xf9,\n    0x6a, 0x8f, 0xc0, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb8,\n    0x56, 0x56, 0xfd, 0x00, 0x00, 0xa7, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa5,\n    0x53, 0xde, 0xd9, 0x00, 0x00, 0xa7, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8a,\n    0xbe, 0x8f, 0x7f, 0x00, 0x00, 0xa7, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8c,\n    0xff, 0x3d, 0x52, 0x00, 0x00, 0xa7, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdb,\n    0x77, 0xe2, 0x8d, 0x00, 0x00, 0xa7, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8e,\n    0x15, 0xe8, 0x67, 0x00, 0xe0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb7,\n    0xa0, 0xbb, 0xc2, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x32,\n    0xb0, 0x53, 0xad, 0x00, 0xe0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc6,\n    0x85, 0xa0, 0x04, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd8,\n    0x4b, 0x58, 0x63, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0x18, 0x6c, 0xee, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0xe1, 0xd0, 0x64, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe1,\n    0xbf, 0xb4, 0x60, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5c,\n    0xd1, 0x14, 0x1a, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4f,\n    0x4a, 0x6e, 0x75, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xce,\n    0x2d, 0xea, 0x4c, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x21,\n    0x0f, 0x30, 0x2b, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0x5e, 0x96, 0x87, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x11,\n    0x07, 0x55, 0x5d, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x01,\n    0xb1, 0x9f, 0x68, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0x09, 0x7f, 0x71, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x11,\n    0xf7, 0xce, 0x6d, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0x81, 0xdd, 0x2f, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3e,\n    0x5b, 0x4e, 0x44, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0xf7, 0x39, 0xf2, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x39,\n    0xb3, 0xea, 0xf5, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb6,\n    0xd9, 0x62, 0x6b, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6c,\n    0x2b, 0xa0, 0xd3, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0x40, 0xde, 0x39, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0xa8, 0xe6, 0xd7, 0x00, 0xc0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6c,\n    0xf2, 0x1c, 0x9a, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0x4a, 0x4a, 0xa2, 0x00, 0xa0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc9,\n    0xd3, 0x39, 0x45, 0x00, 0xa0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x54,\n    0x2d, 0xaf, 0x2f, 0x00, 0xa0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x83,\n    0xee, 0x9e, 0x5d, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0x61, 0x2c, 0x4c, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x56,\n    0x87, 0x8e, 0x57, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7b,\n    0x31, 0xbb, 0xe3, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x71,\n    0x4d, 0x83, 0xaf, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7f,\n    0xe0, 0x84, 0x30, 0x00, 0xa0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x42,\n    0x5f, 0x63, 0x2f, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2e,\n    0x62, 0x3a, 0x53, 0x00, 0xa0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xde,\n    0x49, 0x10, 0x66, 0x00, 0xa0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x64,\n    0xa0, 0x63, 0xd2, 0x00, 0xa0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0x5f, 0x0a, 0xc4, 0x00, 0xa0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x53,\n    0x13, 0xca, 0xab, 0x00, 0xa0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x78,\n    0xec, 0x7c, 0xdf, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x06,\n    0x35, 0x9a, 0x89, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa1,\n    0xc8, 0x9b, 0x9f, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xde,\n    0x6c, 0x6c, 0x44, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1d,\n    0xbd, 0xd3, 0x70, 0x00, 0xb0, 0xa6, 0x00, 0x22,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0x0f, 0xe1, 0x0d, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc4,\n    0x66, 0xd5, 0x3d, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0xd5, 0xd6, 0xef, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xea,\n    0x04, 0xdf, 0x11, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5e,\n    0x1e, 0xf9, 0x3b, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa5,\n    0xe5, 0xf1, 0x99, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb1,\n    0x96, 0xc2, 0x3f, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5c,\n    0x0f, 0x80, 0x5c, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfa,\n    0x7c, 0x0f, 0x1a, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4c,\n    0x6e, 0xd2, 0xad, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x45,\n    0xa1, 0x39, 0x39, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0xe9, 0x35, 0x46, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7a,\n    0xbe, 0xd5, 0x19, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x91,\n    0x52, 0x9b, 0x9c, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x83,\n    0x3a, 0xb3, 0x77, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0x7f, 0xc3, 0xe2, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x23,\n    0x38, 0xcd, 0xb1, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x47,\n    0x73, 0x1d, 0xc7, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6b,\n    0xa9, 0x8b, 0x5e, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0x4c, 0xba, 0x02, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc1,\n    0xc8, 0x5d, 0x30, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0xe2, 0xc9, 0xfd, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x88,\n    0xea, 0xf8, 0xb7, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5c,\n    0x2a, 0x7f, 0x7a, 0x00, 0xb0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xda,\n    0xdd, 0x47, 0xd2, 0x00, 0xc0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0a,\n    0xb6, 0xb9, 0x3a, 0x00, 0xc0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1f,\n    0x4a, 0x33, 0x0b, 0x00, 0xc0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xac,\n    0x83, 0xe4, 0xb7, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0x0c, 0xb0, 0xc7, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd4,\n    0x28, 0xd2, 0xce, 0x00, 0xc0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x57,\n    0xe4, 0xbe, 0x22, 0x00, 0xc0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9e,\n    0x5a, 0x97, 0xa7, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x69,\n    0xeb, 0x30, 0x18, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3c,\n    0xab, 0x47, 0xee, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0xc9, 0x89, 0x3b, 0x00, 0xc0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x03,\n    0x5c, 0x57, 0x20, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x56,\n    0x15, 0xa1, 0xd8, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x30,\n    0x37, 0xc6, 0xc4, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xaa,\n    0x8b, 0x36, 0xb6, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3c,\n    0x46, 0x5b, 0xd6, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc5,\n    0xa4, 0xe9, 0xdc, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6a,\n    0xa5, 0xc3, 0x9b, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4a,\n    0x70, 0x69, 0xd2, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfa,\n    0x53, 0xac, 0x90, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xae,\n    0x51, 0xdb, 0xd6, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8b,\n    0x29, 0x28, 0x6e, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x14,\n    0x42, 0xff, 0x17, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0x95, 0x07, 0x0e, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x86,\n    0xc1, 0xb4, 0x96, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc0,\n    0x2e, 0x8b, 0xff, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0xb7, 0xab, 0xc9, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfa,\n    0x74, 0x60, 0xa9, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfb,\n    0xbd, 0xcf, 0x84, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4f,\n    0x7d, 0x01, 0x90, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5b,\n    0xfa, 0xae, 0x26, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3c,\n    0xc5, 0x09, 0xc9, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x77,\n    0x61, 0x7c, 0x1f, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd0,\n    0xca, 0xd5, 0x8e, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x50,\n    0xaa, 0xed, 0x96, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa2,\n    0xf9, 0x7a, 0x70, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xeb,\n    0x9d, 0x89, 0x88, 0x00, 0xd0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8e,\n    0x39, 0x5f, 0x16, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x30,\n    0x2d, 0x16, 0x6c, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd9,\n    0xaa, 0xa1, 0x1b, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x49,\n    0x18, 0xec, 0x45, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb8,\n    0xc7, 0x1c, 0x5d, 0x00, 0xf0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa5,\n    0x48, 0x55, 0x4c, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfe,\n    0x5c, 0x60, 0x0e, 0x00, 0xe0, 0xa6, 0x00, 0x68,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0a,\n    0xed, 0xc2, 0xc9, 0x00, 0x00, 0xa6, 0x00, 0x8c,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x27,\n    0x6c, 0xa7, 0x1e, 0x00, 0xb0, 0xa9, 0x00, 0xae,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0x8e, 0xe7, 0x00, 0x00, 0x20, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x77,\n    0x24, 0xb5, 0xde, 0x00, 0x60, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2b,\n    0xa5, 0xf1, 0xe2, 0x00, 0x20, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x27,\n    0x43, 0xef, 0xf4, 0x00, 0x20, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb0,\n    0x99, 0xaa, 0x4d, 0x00, 0x20, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcc,\n    0x2a, 0x09, 0xfc, 0x00, 0x20, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x09,\n    0xff, 0x52, 0xdd, 0x00, 0x20, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb7,\n    0x74, 0xcf, 0xfe, 0x00, 0x20, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x65,\n    0x91, 0x8c, 0xd4, 0x00, 0x20, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0x0f, 0xed, 0x03, 0x00, 0x20, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0x15, 0xda, 0x74, 0x00, 0x50, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0x76, 0x70, 0x35, 0x00, 0x50, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe3,\n    0x27, 0xed, 0x72, 0x00, 0x50, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8e,\n    0x3c, 0x1a, 0x57, 0x00, 0x50, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4d,\n    0x9c, 0x83, 0xa5, 0x00, 0x50, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb3,\n    0x1c, 0xba, 0x02, 0x00, 0x50, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x05,\n    0x72, 0x0e, 0x74, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x42, 0x0c, 0xd5, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf2,\n    0x70, 0x95, 0xfc, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0x32, 0x26, 0x39, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdb,\n    0xb2, 0x2d, 0x4d, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0xf7, 0xfc, 0x4e, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xbf,\n    0x9d, 0x02, 0x95, 0x00, 0x60, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x70,\n    0xb4, 0xdc, 0x12, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa0,\n    0xeb, 0xf6, 0x04, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe3,\n    0x1f, 0x37, 0x29, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0xa7, 0x69, 0x42, 0x00, 0x60, 0xab, 0x00, 0xf4,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb6,\n    0xc6, 0xd7, 0x88, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0x60, 0x6c, 0xd3, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x24,\n    0xdf, 0x5e, 0xe4, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x04,\n    0x03, 0x08, 0xcb, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0xe5, 0xb8, 0xdb, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0xd6, 0x29, 0x56, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0xfd, 0xe3, 0x81, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x89,\n    0xe3, 0x85, 0xb7, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x66,\n    0x2b, 0xc1, 0xe0, 0x00, 0x60, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x57, 0xf7, 0x4f, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb2,\n    0x6c, 0xb3, 0x74, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc1,\n    0x2a, 0x49, 0xd1, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x40,\n    0x5b, 0x48, 0xc7, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd3,\n    0xc6, 0x30, 0x75, 0x00, 0x70, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x00,\n    0xa6, 0xf0, 0x93, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xd3,\n    0x6e, 0xb3, 0x6d, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd7,\n    0xdf, 0xbe, 0x91, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0x8c, 0x68, 0x93, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x99,\n    0x5b, 0x92, 0xd6, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe2,\n    0x32, 0x8a, 0x5d, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x73,\n    0xb5, 0xfe, 0x15, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5b,\n    0x52, 0x38, 0x99, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x38,\n    0x0d, 0x9b, 0xae, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x62,\n    0x0a, 0x5f, 0x9b, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x11,\n    0xbe, 0x0d, 0xd1, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf1,\n    0x36, 0x8e, 0x88, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x84,\n    0xb5, 0x74, 0xbd, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2e,\n    0x3e, 0xe0, 0x90, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1c,\n    0x34, 0x5b, 0x23, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x62,\n    0x2e, 0xa8, 0xb5, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb1,\n    0xb1, 0x61, 0x3e, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x49,\n    0xe9, 0xce, 0x86, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0x8f, 0xd3, 0x73, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0xde, 0x91, 0x65, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2b,\n    0xe0, 0x7a, 0x33, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe5,\n    0x11, 0x23, 0xbf, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x56,\n    0x21, 0xe4, 0x61, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x77,\n    0xd7, 0xce, 0x21, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x46,\n    0x29, 0xd1, 0xdb, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3c,\n    0x88, 0x0f, 0x1d, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9d,\n    0x48, 0xcb, 0x13, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0x19, 0x62, 0x77, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x0e, 0xb0, 0x85, 0x00, 0x50, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x46,\n    0xf1, 0xd2, 0x46, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa6,\n    0x08, 0x8d, 0xe0, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x67,\n    0x3f, 0xee, 0xc7, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1b,\n    0x5d, 0x2d, 0x81, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0x5b, 0xa9, 0x7c, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0x9d, 0xa9, 0xaf, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf0,\n    0xfb, 0xd4, 0xaf, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf1,\n    0xce, 0xfd, 0xef, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x22,\n    0x09, 0xdc, 0x04, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x97,\n    0x17, 0x83, 0x48, 0x00, 0x40, 0xab, 0x00, 0x3a,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x23,\n    0x61, 0x71, 0xa1, 0x00, 0x40, 0xab, 0x00, 0x80,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x01,\n    0x9f, 0x78, 0xd7, 0x00, 0x40, 0xab, 0x00, 0x80,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe0,\n    0x0d, 0x75, 0x42, 0x00, 0x40, 0xab, 0x00, 0x80,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8b,\n    0xc5, 0x83, 0xea, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6a,\n    0xde, 0xb9, 0x28, 0x00, 0x30, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xef,\n    0x69, 0x08, 0x8e, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4c,\n    0x0b, 0x17, 0x12, 0x00, 0x30, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbb,\n    0xa5, 0x2d, 0x4b, 0x00, 0x30, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x40,\n    0x3f, 0x59, 0x06, 0x00, 0x30, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x85,\n    0x08, 0xcf, 0x31, 0x00, 0x30, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x25,\n    0xdb, 0x6e, 0x4e, 0x00, 0x30, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xeb,\n    0x10, 0x95, 0xe5, 0x00, 0x30, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcc,\n    0x90, 0x80, 0x6a, 0x00, 0x30, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6c,\n    0xde, 0x5c, 0xbb, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xab,\n    0xfb, 0x63, 0x9c, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x55,\n    0x9e, 0x4b, 0x92, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2e,\n    0xd8, 0x6d, 0xbf, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x43,\n    0xe4, 0x6c, 0xa1, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbe,\n    0x70, 0x8e, 0x18, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdc,\n    0x82, 0x29, 0xce, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x39,\n    0x3e, 0x50, 0x07, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8d,\n    0x18, 0x73, 0xad, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd6,\n    0x51, 0x66, 0x0d, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xa1,\n    0x01, 0x3f, 0x5e, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe9,\n    0xa2, 0x71, 0xa3, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0x28, 0x73, 0xbc, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x62,\n    0xa4, 0xe8, 0xf5, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xde,\n    0x0e, 0x6e, 0x2e, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0x29, 0xee, 0x90, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x56,\n    0x80, 0x57, 0x83, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0xcc, 0x50, 0xdc, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x57,\n    0xcc, 0xeb, 0x64, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1e,\n    0xc3, 0x9d, 0xed, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1b,\n    0xd8, 0xb5, 0xda, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0xb8, 0x29, 0xc1, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x76,\n    0xcd, 0x16, 0xf5, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xba,\n    0x5e, 0x4d, 0x59, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0xa2, 0xfc, 0xea, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0x33, 0x83, 0x0d, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0xd0, 0xa5, 0x36, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x97,\n    0x46, 0xf6, 0xd3, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x03,\n    0x41, 0x4e, 0xdb, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9f,\n    0x89, 0xc2, 0xd3, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0x72, 0x18, 0xe5, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7a,\n    0x87, 0xa0, 0x0e, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x06,\n    0x61, 0xfe, 0x1d, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0x9e, 0x1f, 0x41, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6d,\n    0xea, 0x04, 0xe3, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe0,\n    0xe3, 0xc0, 0x05, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9c,\n    0x4d, 0xb9, 0xe7, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0xc4, 0x81, 0xab, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7a,\n    0x2a, 0xf2, 0xe9, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0x14, 0x0e, 0x15, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4c,\n    0xf9, 0x3d, 0x55, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9f,\n    0x9c, 0x5b, 0xf4, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xde,\n    0xb6, 0x77, 0x2c, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x41,\n    0xe6, 0xd5, 0xb8, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x99,\n    0xf7, 0x17, 0x43, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x9e,\n    0x12, 0x14, 0x84, 0x00, 0x80, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf0,\n    0xa6, 0x51, 0x8a, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x6b,\n    0xb0, 0x37, 0x9a, 0x00, 0x80, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb2,\n    0xbf, 0x04, 0x7a, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x8e,\n    0xf8, 0xa9, 0xce, 0x00, 0x80, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa7,\n    0x7a, 0x56, 0x6e, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9f,\n    0x23, 0x0a, 0x2f, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x00,\n    0xaf, 0x89, 0xc9, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0x23, 0x57, 0xf0, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0a,\n    0x03, 0xf2, 0x8d, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x21,\n    0xfa, 0x45, 0xfa, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa8,\n    0x15, 0x23, 0x27, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5c,\n    0xdd, 0x88, 0x4e, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x56,\n    0x2b, 0x96, 0xd2, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0xa6, 0x58, 0x6a, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x50,\n    0x33, 0xd4, 0x0b, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfb,\n    0x4c, 0xc0, 0x7c, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0x86, 0xbb, 0x1d, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0x52, 0xe3, 0x06, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x84,\n    0xf7, 0x40, 0x4a, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0x88, 0xdc, 0x01, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8e,\n    0x53, 0x8e, 0x8d, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa1,\n    0x3c, 0x2b, 0xfa, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4c,\n    0xd7, 0x5f, 0x07, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x48,\n    0x47, 0xc1, 0x79, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8e,\n    0xe6, 0x37, 0xdf, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc4,\n    0xc0, 0xf1, 0x73, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x24,\n    0x3d, 0x26, 0x9a, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd9,\n    0x46, 0x22, 0xe2, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x92,\n    0xd7, 0xb8, 0xd5, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x22,\n    0xd7, 0xf0, 0x2f, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0xf7, 0xc6, 0xa7, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xda,\n    0xe0, 0x03, 0xc1, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc3,\n    0x9d, 0x63, 0xbf, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x87,\n    0xe5, 0xcb, 0x5d, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x75,\n    0xab, 0xee, 0x7d, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xcd,\n    0x89, 0x73, 0xfb, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0x28, 0x67, 0xff, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x4d,\n    0x2e, 0xd3, 0xb9, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc5,\n    0xaf, 0x02, 0x0e, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x14,\n    0xe4, 0xc5, 0x33, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8b,\n    0xec, 0xe6, 0x07, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x02,\n    0xfc, 0xed, 0x76, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9e,\n    0x32, 0xf2, 0xc3, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x27,\n    0x1c, 0x79, 0x1f, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0x7b, 0xc9, 0xbd, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0xcb, 0xa2, 0xcd, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x06,\n    0x4c, 0x67, 0xe8, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x96,\n    0x3e, 0x95, 0x76, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4a,\n    0x41, 0x1f, 0xf7, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x39,\n    0x11, 0xdd, 0x97, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x51,\n    0xfc, 0xc7, 0x23, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8d,\n    0x44, 0xba, 0x37, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x64,\n    0x1a, 0x2a, 0xa6, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe1,\n    0x20, 0x00, 0x8e, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc9,\n    0x45, 0xeb, 0xea, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x25,\n    0x35, 0xfb, 0xa4, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x8b,\n    0x59, 0x5f, 0x4d, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xaf,\n    0x68, 0xee, 0xcf, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb5,\n    0x45, 0x4e, 0x12, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x6f,\n    0xc8, 0x33, 0x22, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8d,\n    0xf1, 0xe2, 0x66, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0x98, 0x36, 0xe5, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xfd,\n    0xaa, 0x10, 0x53, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb3,\n    0x8b, 0x55, 0x03, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x72,\n    0xda, 0x0a, 0xe0, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0x1e, 0x94, 0xad, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x89,\n    0x0a, 0x53, 0x04, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0x2b, 0xee, 0x5d, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0x54, 0x4f, 0x46, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6e,\n    0xe1, 0xfc, 0x92, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x32,\n    0x3d, 0x0a, 0x46, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdc,\n    0x64, 0x60, 0xd8, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd1,\n    0x2f, 0x58, 0xe6, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd4,\n    0xf1, 0x4e, 0x3e, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd1,\n    0xd1, 0xb9, 0x99, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x29,\n    0xda, 0x31, 0xac, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xac,\n    0x8c, 0xd2, 0x46, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x21,\n    0xa8, 0xfe, 0x68, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x15,\n    0xc9, 0x70, 0xa0, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1e,\n    0xc4, 0x37, 0xb7, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x96,\n    0x24, 0x3d, 0xa0, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3b,\n    0x82, 0xc3, 0x1e, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0x9e, 0x66, 0xc9, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4a,\n    0x6b, 0x4f, 0xf8, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7c,\n    0x09, 0xa9, 0x48, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0xbf, 0x70, 0x5d, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9c,\n    0x99, 0xec, 0x3f, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9d,\n    0x34, 0xb9, 0x6a, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x76,\n    0x97, 0x0b, 0xbb, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0x68, 0x44, 0xf4, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc4,\n    0x9f, 0xe7, 0xf5, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2d,\n    0x62, 0x2f, 0x6e, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0x5f, 0xa7, 0x1a, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0x88, 0xa9, 0xd9, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf5,\n    0x71, 0xe4, 0x10, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xed,\n    0x7f, 0x12, 0x65, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa1,\n    0x81, 0x48, 0x69, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0x52, 0x51, 0x89, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0xb3, 0x4d, 0x78, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0x28, 0x69, 0x7e, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x78,\n    0xc8, 0x5e, 0x5b, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb4,\n    0xd2, 0x32, 0x35, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9d,\n    0xe1, 0xf3, 0x57, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd5,\n    0x0d, 0x46, 0x0f, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2d,\n    0xdd, 0x07, 0x74, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x27,\n    0x25, 0x14, 0x70, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8e,\n    0x0a, 0xae, 0x98, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x78,\n    0xb8, 0xee, 0x7f, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6c,\n    0xf7, 0xb7, 0x91, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0xb4, 0x4d, 0x11, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdd,\n    0xa8, 0xa5, 0xbc, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0x78, 0x6d, 0xc4, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x73,\n    0x42, 0x9c, 0xfa, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x67,\n    0x65, 0xb6, 0x39, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7e,\n    0xa4, 0xd4, 0x1e, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0x5a, 0x9f, 0x62, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7e,\n    0xbe, 0xd0, 0xfc, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe3,\n    0xbe, 0x62, 0x1c, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x06,\n    0xf0, 0x2c, 0x27, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfb,\n    0x94, 0xbf, 0xe1, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe5,\n    0x87, 0x88, 0x91, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x99,\n    0x18, 0xd4, 0x98, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0x58, 0x9d, 0x10, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x76,\n    0x96, 0xbe, 0x2f, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb8,\n    0xa0, 0x67, 0x59, 0x00, 0x90, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4d,\n    0x55, 0xef, 0x50, 0x00, 0x60, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0xd8, 0xaa, 0x7f, 0x00, 0x50, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc4,\n    0x5b, 0x1e, 0xf0, 0x00, 0x50, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0xd5, 0xf4, 0xaf, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3d,\n    0x51, 0x49, 0x12, 0x00, 0x30, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0x32, 0x35, 0xc2, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x76,\n    0xaf, 0x4d, 0xb4, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x30,\n    0x96, 0x6b, 0xb2, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x43,\n    0x32, 0x0d, 0x9e, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x69,\n    0x1d, 0x80, 0x4a, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd8,\n    0x7e, 0x36, 0x6c, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa4,\n    0x6c, 0x12, 0x3e, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x35,\n    0x57, 0xde, 0x94, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbd,\n    0xf6, 0xe9, 0xc9, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x39,\n    0xee, 0x81, 0xf1, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x67,\n    0xb4, 0xdf, 0x0f, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4d,\n    0x15, 0x99, 0x7d, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcd,\n    0xaa, 0xe5, 0xda, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x40,\n    0x81, 0x2c, 0x93, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7b,\n    0x1e, 0x2f, 0x1e, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x20,\n    0x8c, 0x66, 0xcb, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe8,\n    0x68, 0xcc, 0x0d, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8c,\n    0xe7, 0x70, 0x3c, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbf,\n    0x03, 0xac, 0x89, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa7,\n    0xc1, 0xd5, 0x4b, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xed,\n    0x0d, 0x10, 0x09, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8f,\n    0x38, 0x50, 0xe8, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd6,\n    0x8a, 0x70, 0x3a, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0xd8, 0x4d, 0x51, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb1,\n    0x3d, 0x17, 0x7e, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb8,\n    0xfb, 0x1f, 0x33, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x71,\n    0xda, 0x45, 0x8e, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0x3d, 0x11, 0xc4, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x39,\n    0x06, 0x5f, 0x82, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xac,\n    0xc9, 0xa3, 0x81, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x75,\n    0x94, 0x74, 0x86, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x86,\n    0x3f, 0x16, 0x78, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd6,\n    0xcb, 0xe0, 0x9c, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe3,\n    0x00, 0x76, 0x20, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x84,\n    0x0b, 0xd1, 0x20, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0xa9, 0x4d, 0x03, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5a,\n    0xa5, 0x14, 0x04, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe5,\n    0xf9, 0xbb, 0x87, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x48,\n    0x1a, 0x14, 0x11, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8a,\n    0xae, 0x0e, 0xdc, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3c,\n    0x25, 0xdf, 0x32, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xad,\n    0xc9, 0x14, 0x0d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc2,\n    0x65, 0x29, 0x1e, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x73,\n    0x66, 0x82, 0x55, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xea,\n    0xb7, 0x5e, 0x66, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc1,\n    0x43, 0x3b, 0xff, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x38,\n    0x74, 0xa6, 0x81, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6c,\n    0xb4, 0xab, 0xdf, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdf,\n    0xd2, 0xf9, 0x27, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xee,\n    0x7e, 0x31, 0x52, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2d,\n    0x2f, 0xb0, 0x4f, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd2,\n    0xf2, 0x98, 0x95, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x69,\n    0x05, 0x98, 0x92, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0x52, 0x98, 0x9a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf2,\n    0xdc, 0x09, 0xb6, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x76,\n    0x22, 0x5d, 0x96, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x36,\n    0xb0, 0xa7, 0xd0, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x47,\n    0xd4, 0x49, 0x4a, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdd,\n    0x53, 0x0d, 0xdc, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x63,\n    0xd3, 0xd9, 0x8e, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa8,\n    0xab, 0x13, 0xf0, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8e,\n    0x66, 0x99, 0x62, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xac,\n    0x6a, 0x14, 0x89, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6d,\n    0xd7, 0x53, 0x26, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x45,\n    0x5c, 0x4b, 0xd2, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9f,\n    0x29, 0x14, 0x99, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0x6b, 0x01, 0x60, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8f,\n    0xde, 0x9b, 0x30, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0xc8, 0xcc, 0x2b, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x30,\n    0x3d, 0xf5, 0x75, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe5,\n    0x24, 0x2b, 0x44, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6f,\n    0x9b, 0x12, 0x36, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcd,\n    0x7d, 0x3a, 0x83, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3a,\n    0x20, 0x06, 0x48, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd1,\n    0x24, 0xad, 0x83, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8f,\n    0x33, 0x19, 0x7a, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x4e,\n    0x1f, 0x4b, 0x68, 0x00, 0x60, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0a,\n    0x82, 0x72, 0x41, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe6,\n    0xff, 0x88, 0xe4, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0x16, 0x6e, 0xc3, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x19,\n    0xf5, 0x91, 0xa9, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8f,\n    0x25, 0x0e, 0x4c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd5,\n    0x2f, 0xc0, 0xe9, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4b,\n    0x7f, 0x8f, 0x8e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8b,\n    0xef, 0x71, 0x80, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0x7d, 0xfb, 0x72, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5b,\n    0x0a, 0xf4, 0x5a, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x15,\n    0x07, 0xc8, 0x2c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa8,\n    0xfc, 0x2b, 0xe8, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc5,\n    0xd7, 0x37, 0xe5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x73,\n    0x6d, 0xa2, 0xdb, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd5,\n    0x2d, 0xaf, 0x3a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc9,\n    0x10, 0xf6, 0xf5, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe2,\n    0xa8, 0x20, 0xea, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x92,\n    0xf9, 0x9a, 0x70, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0xa9, 0x05, 0xb9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x65,\n    0x6c, 0x4e, 0x80, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9f,\n    0xd2, 0x1f, 0xf7, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x17,\n    0x3e, 0xb9, 0x95, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe4,\n    0x9d, 0x9f, 0x1d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x46,\n    0xf5, 0xed, 0x44, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8b,\n    0x52, 0x29, 0x97, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbd,\n    0xa2, 0x3e, 0xde, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5d,\n    0x5e, 0x84, 0x3b, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc4,\n    0xee, 0x1e, 0xf1, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xcc,\n    0x37, 0x81, 0xcd, 0x00, 0x60, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0d,\n    0x80, 0x90, 0xf2, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2b,\n    0x11, 0x5d, 0x25, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x06,\n    0x52, 0x82, 0xc1, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfa,\n    0x53, 0xd4, 0x6c, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0xa8, 0x75, 0x05, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf8,\n    0x52, 0xc4, 0x41, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x58,\n    0xf5, 0x55, 0x68, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x58,\n    0xe6, 0x35, 0xf8, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd3,\n    0xb0, 0x6e, 0x3a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x96,\n    0x7d, 0x97, 0x60, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x98,\n    0x6e, 0x23, 0x5e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4b,\n    0x83, 0x66, 0xf0, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x20,\n    0x83, 0x76, 0xe8, 0x00, 0x60, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0x3e, 0xa4, 0x3d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1e,\n    0x02, 0x5e, 0x24, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa3,\n    0x95, 0x47, 0xbd, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb8,\n    0xb1, 0x58, 0x6a, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xee,\n    0x45, 0x22, 0x10, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x54,\n    0x24, 0x25, 0x7c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x81,\n    0x56, 0x50, 0xd4, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8c,\n    0xf3, 0x43, 0xc9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x11,\n    0x82, 0xb1, 0x84, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x46,\n    0xc9, 0xae, 0xb5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe8,\n    0x5f, 0xed, 0xb9, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb8,\n    0x23, 0x68, 0xa5, 0x00, 0x60, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0x6d, 0x5b, 0xc0, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd5,\n    0x91, 0xad, 0x0b, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0xb1, 0xc8, 0x44, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9e,\n    0x78, 0x96, 0x63, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2e,\n    0x38, 0xb0, 0x66, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x86,\n    0x40, 0xc3, 0x58, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x84,\n    0x7e, 0x7b, 0xb4, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x96,\n    0x87, 0x46, 0xdd, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf5,\n    0x5e, 0xd8, 0x4d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd3,\n    0xfc, 0xee, 0x7f, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcc,\n    0xec, 0x67, 0xe3, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x10,\n    0x2a, 0x01, 0x2b, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7f,\n    0x57, 0xe3, 0x5c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa1,\n    0xca, 0x37, 0xb5, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfd,\n    0x1a, 0xf8, 0x20, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7e,\n    0x52, 0xc3, 0xbe, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5d,\n    0x88, 0x91, 0x50, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x33,\n    0x4b, 0x84, 0x53, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0x04, 0x72, 0xec, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x21,\n    0xeb, 0xbd, 0x97, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x57,\n    0xdf, 0x29, 0xd2, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbf,\n    0x93, 0xea, 0x65, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd1,\n    0x89, 0x2e, 0x6b, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1d,\n    0x8e, 0xf4, 0xbe, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x46,\n    0xaa, 0x8a, 0xe4, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x52,\n    0x6d, 0x75, 0x5d, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7a,\n    0x61, 0x5e, 0xf0, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x51,\n    0x38, 0xbf, 0xbd, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4c,\n    0xfd, 0x62, 0xa4, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4f,\n    0x5f, 0x12, 0xed, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1c,\n    0x85, 0x5e, 0x78, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xee,\n    0x5e, 0x3a, 0x0e, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x71,\n    0x77, 0xc0, 0xb1, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x18,\n    0x87, 0x3e, 0xe0, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfb,\n    0x8f, 0x36, 0x73, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x70,\n    0x64, 0xeb, 0x4a, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe1,\n    0x87, 0x89, 0x95, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x60,\n    0x4d, 0x9f, 0xc4, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8a,\n    0xe3, 0x4c, 0x3d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcc,\n    0xce, 0x87, 0xa7, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0xee, 0x8a, 0x3d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc5,\n    0x71, 0x8b, 0x3f, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x66,\n    0x52, 0x4b, 0xe3, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5d,\n    0x44, 0xe6, 0xdf, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8a,\n    0xaf, 0x24, 0x09, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x46,\n    0xaa, 0x0c, 0x8d, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0x0c, 0x5c, 0xa2, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x17,\n    0x2c, 0xf7, 0xa4, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x46,\n    0x5b, 0x2a, 0xf9, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x25,\n    0xbb, 0x1a, 0xf6, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbd,\n    0x57, 0xa0, 0xe4, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x49,\n    0x46, 0x56, 0xcb, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6d,\n    0x4d, 0x63, 0x17, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc6,\n    0x33, 0xf5, 0x3e, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x02,\n    0xd9, 0x99, 0x6f, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x64,\n    0x9d, 0x09, 0x23, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0c,\n    0xe1, 0x13, 0x88, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x06,\n    0x73, 0xb2, 0x3d, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x18,\n    0xf8, 0x23, 0xf6, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0x8c, 0x32, 0x2d, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x41,\n    0x15, 0x60, 0xdd, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xab,\n    0xa2, 0xa3, 0x2e, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd2,\n    0xfb, 0x6c, 0xfc, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0x06, 0x92, 0xfc, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x38,\n    0xa9, 0xc6, 0x94, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0xb8, 0x95, 0x03, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdc,\n    0x92, 0x0d, 0x20, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x51,\n    0xbb, 0x39, 0xa3, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8c,\n    0x92, 0xaf, 0x19, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5f,\n    0x64, 0x71, 0x2c, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x35,\n    0xd9, 0x58, 0x63, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x14,\n    0x87, 0x62, 0x7c, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x09,\n    0xec, 0xb6, 0x72, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x58,\n    0x26, 0xc6, 0x12, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2b,\n    0xb0, 0x19, 0x39, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x05,\n    0xb9, 0x97, 0xdc, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x88,\n    0x94, 0xd4, 0xa6, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe7,\n    0x0b, 0xa4, 0x01, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x90,\n    0xdb, 0x7f, 0xcb, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5b,\n    0x36, 0x9f, 0x24, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3d,\n    0xff, 0x25, 0x32, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x11,\n    0xb7, 0x2a, 0x88, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8b,\n    0x60, 0x4d, 0x3c, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x88,\n    0xa9, 0x0f, 0xb3, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1d,\n    0xf4, 0xab, 0xf3, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfd,\n    0xd3, 0xbb, 0x38, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe7,\n    0x46, 0x7d, 0x88, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x20,\n    0x6c, 0x63, 0xed, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x89,\n    0xef, 0x68, 0xe5, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0x9d, 0x6c, 0xb3, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x24,\n    0xa6, 0x01, 0x8a, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa0,\n    0xb7, 0x7c, 0xd1, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1c,\n    0x1a, 0xba, 0x53, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcf,\n    0x98, 0x7a, 0x7f, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcd,\n    0xe6, 0xea, 0x29, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0x11, 0x60, 0xc1, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6b,\n    0x8b, 0x9b, 0x6c, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x70,\n    0xd2, 0xcc, 0xa7, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcf,\n    0x7c, 0x92, 0x98, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd7,\n    0xa2, 0x80, 0x18, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7c,\n    0xd8, 0xb9, 0xc3, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x53,\n    0x0f, 0x13, 0xbf, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5e,\n    0x77, 0xcf, 0xfc, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x66,\n    0xa1, 0x26, 0x82, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0f,\n    0x3c, 0x7a, 0x05, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xce,\n    0x8f, 0xc8, 0x3c, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4a,\n    0xcc, 0xa4, 0x91, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3f,\n    0x6c, 0xc6, 0xdd, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xce,\n    0x9d, 0xc3, 0xd1, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0xd0, 0x9c, 0xe0, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x97,\n    0xa4, 0x2e, 0xc6, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0x8b, 0x8d, 0x8e, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3a,\n    0xd8, 0x60, 0x2b, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x53,\n    0xa4, 0x18, 0x05, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x27,\n    0x60, 0x59, 0x76, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa5,\n    0x6f, 0xc5, 0x50, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf7,\n    0x8e, 0xf2, 0xa8, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0x05, 0x7f, 0x9a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4e,\n    0xf2, 0x08, 0x00, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x66,\n    0x99, 0xb0, 0xc9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdc,\n    0x17, 0xd4, 0xbc, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0a,\n    0xc8, 0x0e, 0x08, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x78,\n    0x6d, 0x50, 0xc4, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe3,\n    0xd2, 0x34, 0xd5, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xad,\n    0x4e, 0xe0, 0xfe, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdf,\n    0x0f, 0x58, 0x4c, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xee,\n    0x9f, 0xb1, 0x79, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x1c,\n    0x86, 0x80, 0x7e, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x01, 0x97, 0x6f, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd3,\n    0x45, 0x12, 0x53, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6a,\n    0xaa, 0x0d, 0xef, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe5,\n    0xf0, 0x71, 0x78, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4d,\n    0xd4, 0xf9, 0xec, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7c,\n    0xd7, 0x04, 0x91, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0x97, 0x95, 0x1a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf1,\n    0xc3, 0x9e, 0xbb, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xee,\n    0xb8, 0xe1, 0x06, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x34,\n    0x2e, 0xb1, 0xb1, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x91,\n    0x04, 0x48, 0x60, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xff,\n    0x66, 0x88, 0xb7, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0xbe, 0x9d, 0x8c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe9,\n    0x68, 0x4c, 0xaf, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x13,\n    0xb2, 0x35, 0x8e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9a,\n    0x3b, 0x8b, 0x21, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6f,\n    0x97, 0x45, 0xb7, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x85,\n    0xf2, 0x7a, 0x59, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd3,\n    0xc8, 0x30, 0x85, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x34,\n    0xa1, 0xc0, 0x66, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x76,\n    0xa9, 0xfb, 0xa9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x66,\n    0xc2, 0xdc, 0xd1, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfd,\n    0x30, 0x7c, 0x94, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe0,\n    0xee, 0x6f, 0xa0, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe9,\n    0x05, 0xc6, 0x5f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x96,\n    0x66, 0x7f, 0x4f, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xc4,\n    0x50, 0x48, 0x9e, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0x6b, 0xe4, 0xd6, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6a,\n    0xce, 0x67, 0x34, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xed,\n    0x9a, 0x34, 0xac, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xed,\n    0x45, 0x59, 0xa0, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcf,\n    0xd3, 0x91, 0xa6, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdb,\n    0x43, 0x75, 0x75, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdd,\n    0x7b, 0x33, 0x81, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x17,\n    0x33, 0x76, 0xf8, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0x7a, 0xf4, 0x6c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb6,\n    0xe5, 0x9a, 0xc9, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0x64, 0xd8, 0xa6, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x19,\n    0x7a, 0x0d, 0x43, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x2d, 0xea, 0x6d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb5,\n    0x92, 0xd5, 0xd9, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3f,\n    0xfb, 0x81, 0xd6, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8f,\n    0xaa, 0xfb, 0xab, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbc,\n    0x24, 0xed, 0xbf, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdf,\n    0x7f, 0x0f, 0xe0, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x17,\n    0xb6, 0xf4, 0xd1, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1f,\n    0xf6, 0x35, 0x12, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x31,\n    0x34, 0xc3, 0xf6, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8c,\n    0x97, 0x12, 0x98, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x65,\n    0xa1, 0x33, 0x5a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf4,\n    0x6d, 0x4e, 0xa3, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x91,\n    0xd7, 0xfc, 0x40, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9a,\n    0x7a, 0x19, 0xf5, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe1,\n    0xbb, 0x0d, 0xb3, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x82,\n    0xdc, 0x6b, 0x1f, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc7,\n    0x01, 0xa5, 0x83, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x25,\n    0x6a, 0xb6, 0xcc, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xad,\n    0x26, 0x7e, 0xdc, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbe,\n    0x9b, 0x76, 0x6a, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x32,\n    0x8a, 0xe8, 0xa5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xde,\n    0x97, 0xe9, 0x4f, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x04,\n    0x01, 0x6d, 0xb7, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbb,\n    0x27, 0xa4, 0x56, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xba,\n    0x97, 0x40, 0x62, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x83,\n    0x16, 0xeb, 0x52, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6f,\n    0x0b, 0xb1, 0xde, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd3,\n    0xa9, 0x9e, 0x48, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9e,\n    0x1b, 0x5e, 0xbd, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc0,\n    0x7b, 0x06, 0xdf, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe0,\n    0x38, 0x96, 0x51, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x49,\n    0xf6, 0x65, 0x5c, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x02,\n    0xf2, 0xdf, 0x9c, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0x42, 0xda, 0x9c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc8,\n    0xc5, 0xbd, 0x3d, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1d,\n    0x76, 0xe6, 0x6d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x80,\n    0x19, 0x50, 0x7a, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe8,\n    0xb0, 0xae, 0xca, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x14,\n    0x20, 0xef, 0x81, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0xbb, 0xfb, 0x61, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb6,\n    0xf0, 0x3a, 0x3b, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x24,\n    0x93, 0x2e, 0x50, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc0,\n    0xc0, 0x8f, 0x89, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0x27, 0xfd, 0x76, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x85,\n    0xbf, 0x24, 0x4a, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4b,\n    0xc0, 0x99, 0x4e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x01,\n    0x3c, 0x7f, 0x11, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xff,\n    0x97, 0x21, 0x79, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6e,\n    0x94, 0xee, 0x90, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0xd2, 0x3e, 0xb2, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc4,\n    0xd9, 0x23, 0x3d, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb3,\n    0x46, 0x4f, 0x2a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xad,\n    0x40, 0xc5, 0x4a, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xee,\n    0xd9, 0xba, 0x58, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3d,\n    0x32, 0xba, 0x5c, 0x00, 0x20, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0x62, 0x8c, 0x88, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbd,\n    0xf5, 0x04, 0xe6, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x71,\n    0xf8, 0xd2, 0xb5, 0x00, 0x70, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0xd5, 0x65, 0x52, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe8,\n    0x1c, 0xd9, 0x6d, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0x02, 0xc0, 0x60, 0x00, 0x80, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x62,\n    0x36, 0x9d, 0x78, 0x00, 0x20, 0x04, 0x01, 0x52,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0x8e, 0x37, 0x35, 0x00, 0x60, 0x04, 0x01, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xff,\n    0x83, 0xd7, 0xa9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf2,\n    0xf7, 0xe5, 0xc2, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xab,\n    0x8b, 0x45, 0x7c, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x75,\n    0x67, 0xea, 0x5f, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0xbb, 0x51, 0xc5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x74,\n    0xbc, 0x5c, 0xe9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x38,\n    0x2a, 0xa1, 0x42, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0xea, 0x82, 0x91, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfe,\n    0x20, 0x94, 0xd2, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x73,\n    0xb5, 0xa4, 0x1e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0x71, 0x62, 0x69, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x49,\n    0x05, 0x34, 0xb1, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x49, 0x13, 0x4e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x93,\n    0xbb, 0xfa, 0x1a, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x98,\n    0xb6, 0xfc, 0x6f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd5,\n    0x7b, 0xf9, 0x11, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x65,\n    0xeb, 0x72, 0x44, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9a,\n    0xc0, 0x88, 0x12, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf9,\n    0x97, 0x36, 0x60, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xc9,\n    0xf1, 0xd3, 0x1e, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd3,\n    0xd2, 0x5b, 0xc5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0x1a, 0x28, 0xbb, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1c,\n    0x0c, 0xd2, 0xc9, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd6,\n    0x90, 0x07, 0xc9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x59,\n    0x86, 0xfb, 0xc0, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x14,\n    0x0d, 0xd7, 0x2d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1e,\n    0xaf, 0x2e, 0x02, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc2,\n    0x0c, 0x41, 0x64, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x98,\n    0xf6, 0x28, 0x92, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x65,\n    0x24, 0x2e, 0x4c, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x15,\n    0xa0, 0x7a, 0xf9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd5,\n    0x2f, 0x7e, 0xeb, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe8,\n    0xb2, 0x34, 0xc9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdf,\n    0xda, 0xef, 0xc5, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x63,\n    0xc6, 0x55, 0x0e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xea,\n    0x85, 0xa6, 0xae, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc9,\n    0xfb, 0xbb, 0xd2, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5b,\n    0xb8, 0xcb, 0xdf, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xed,\n    0xe5, 0xe8, 0x26, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7c,\n    0x12, 0x6f, 0xdb, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc7,\n    0x13, 0xd6, 0x80, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbc,\n    0x7c, 0x93, 0x0e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x54,\n    0x82, 0xa8, 0xc9, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9a,\n    0xdd, 0x65, 0xa6, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe6,\n    0x20, 0x0f, 0xda, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbc,\n    0x56, 0xb4, 0xe5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1c,\n    0xbb, 0x60, 0x43, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x36,\n    0x33, 0x7c, 0xeb, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x43,\n    0x87, 0xa0, 0x73, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xca,\n    0x5d, 0x68, 0x99, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb2,\n    0x86, 0x58, 0xb3, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x52,\n    0x0b, 0xc3, 0x37, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8d,\n    0xdd, 0x7e, 0x6e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0x37, 0x02, 0xac, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x14,\n    0x1a, 0xf5, 0xda, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x11,\n    0xe7, 0x2b, 0x08, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x09,\n    0x97, 0xbf, 0x3c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x44,\n    0x8b, 0x82, 0x00, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x70,\n    0x17, 0xdc, 0x08, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x72,\n    0xf0, 0x3a, 0xa3, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0x33, 0x1c, 0x7e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x21,\n    0x55, 0x24, 0xba, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x94,\n    0x21, 0x29, 0x72, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x43, 0x31, 0x2e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6a,\n    0xeb, 0x33, 0x67, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0x5a, 0x7b, 0xf5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5d,\n    0x44, 0x64, 0x74, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x07,\n    0xc2, 0x7a, 0x09, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd9,\n    0x1a, 0x05, 0xd4, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6c,\n    0x19, 0xbc, 0xab, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9b,\n    0x14, 0x66, 0x87, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa1,\n    0x43, 0x6b, 0xdd, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa4,\n    0x7c, 0x02, 0xac, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x43,\n    0x11, 0xa5, 0xb4, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xad,\n    0x87, 0x05, 0x51, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf6,\n    0xb5, 0x33, 0x62, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xff,\n    0x0e, 0x96, 0x3f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb7,\n    0xbc, 0x28, 0xba, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd2,\n    0xe9, 0xe3, 0xba, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x95,\n    0x2d, 0xdf, 0xc7, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x68,\n    0x59, 0x7d, 0x64, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc7,\n    0x28, 0x63, 0x71, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbf,\n    0x6f, 0xdc, 0x9a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb5,\n    0x54, 0x6f, 0x20, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf2,\n    0x45, 0x5f, 0x73, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0x1b, 0xe3, 0xf7, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcf,\n    0xcd, 0xe3, 0x94, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdc,\n    0xf0, 0xb9, 0x0a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x22,\n    0xb7, 0xb6, 0x17, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xca,\n    0xd1, 0x0b, 0xa4, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x49,\n    0x6e, 0x41, 0xca, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x74,\n    0x4f, 0x66, 0x7a, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc4,\n    0x45, 0xa3, 0x2a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd5,\n    0xb7, 0x25, 0xfd, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x78,\n    0xf5, 0x5e, 0x7a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x78,\n    0xf5, 0x5e, 0x7a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbd,\n    0x21, 0xba, 0x04, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x36,\n    0xe8, 0x87, 0x7c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb0,\n    0xc3, 0x78, 0x19, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9c,\n    0x7e, 0xd0, 0x00, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa9,\n    0x7e, 0xf4, 0x23, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x11,\n    0xc3, 0x82, 0x99, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x05,\n    0x2f, 0xf6, 0xad, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0x4e, 0x4e, 0x0c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd3,\n    0x3b, 0x6b, 0x10, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0xc1, 0x85, 0xe5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0x38, 0x38, 0x0e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6c,\n    0x16, 0xaf, 0x01, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xca,\n    0xf5, 0xd9, 0x97, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd3,\n    0xef, 0xf8, 0x31, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe5,\n    0x8c, 0xf1, 0xaf, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfd,\n    0x59, 0x21, 0x43, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x05,\n    0xe8, 0x3c, 0x20, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9b,\n    0x16, 0x20, 0xe9, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0x5b, 0x26, 0x44, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf4,\n    0x0d, 0xbb, 0x5d, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc9,\n    0xa0, 0xe5, 0x3f, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x52,\n    0x90, 0xc6, 0x13, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf7,\n    0x83, 0xd2, 0xd7, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x26,\n    0xe6, 0xf1, 0xf1, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb8,\n    0x2f, 0xbf, 0x9d, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0xd6, 0x23, 0x7f, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3e,\n    0x01, 0xb8, 0x7f, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x39,\n    0xf2, 0x09, 0x77, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x00,\n    0x24, 0xe3, 0xa8, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x61,\n    0xbb, 0x2a, 0x4c, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xf3,\n    0x5a, 0xae, 0xbf, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x04,\n    0xfd, 0x00, 0xd1, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x00,\n    0xeb, 0x11, 0x7e, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7c,\n    0x9d, 0xe0, 0xab, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfe,\n    0x57, 0x61, 0x23, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe0,\n    0x6d, 0x73, 0x74, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe3,\n    0x4b, 0xf1, 0x0f, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd5,\n    0xd3, 0x7a, 0xcd, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbd,\n    0x4e, 0x89, 0x60, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf0,\n    0x30, 0xc2, 0x8c, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x99,\n    0x63, 0xa4, 0x69, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x33,\n    0x19, 0x1f, 0x3d, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x05,\n    0xaf, 0xfa, 0x35, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9a,\n    0xc9, 0x99, 0x01, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0xaa, 0x97, 0xd6, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x59,\n    0x1b, 0x55, 0x44, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0x7c, 0x7d, 0x2f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb4,\n    0xd0, 0x04, 0x0b, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0x88, 0xb6, 0x8d, 0x00, 0x80, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe6,\n    0xe3, 0xe1, 0x96, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe5,\n    0x57, 0x0d, 0xef, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1d,\n    0x0d, 0xcd, 0xaa, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x60,\n    0xc3, 0xc8, 0x75, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfe,\n    0x1b, 0x35, 0x37, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2c,\n    0x7b, 0x75, 0xdf, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9b,\n    0xab, 0xa9, 0x22, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3e,\n    0x61, 0x02, 0x7d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf7,\n    0xb4, 0xbf, 0x9a, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8f,\n    0xb3, 0xf5, 0xce, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7b,\n    0xd6, 0x6d, 0x04, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf1,\n    0x69, 0x77, 0x4a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd9,\n    0x36, 0x88, 0x3e, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x11,\n    0x2c, 0x56, 0xb8, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x54,\n    0xef, 0x80, 0x24, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x24,\n    0x1c, 0x7a, 0xb7, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x20,\n    0xf6, 0x72, 0x0c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf1,\n    0x09, 0xae, 0xab, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0c,\n    0x84, 0x83, 0x25, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x18,\n    0xe3, 0xb6, 0x84, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc5,\n    0xb9, 0x42, 0x20, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x48,\n    0x1e, 0xeb, 0xb3, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0x11, 0x98, 0x9b, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5d,\n    0x90, 0xe0, 0x45, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3a,\n    0xa1, 0x7d, 0xf0, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x23,\n    0x14, 0x7f, 0x92, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x27,\n    0x2e, 0x79, 0x73, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5e,\n    0x33, 0x7b, 0x9f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xde,\n    0x36, 0xee, 0x9e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe1,\n    0xc3, 0xc2, 0xae, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x87,\n    0x44, 0x0e, 0x05, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd1,\n    0x0a, 0x11, 0x96, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0x37, 0xee, 0xb5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5d,\n    0x91, 0x10, 0x74, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x37,\n    0x60, 0xb9, 0x16, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3c,\n    0xd0, 0x85, 0x59, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1d,\n    0xe3, 0x45, 0x2f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5f,\n    0x2b, 0x9c, 0x52, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1e,\n    0x17, 0xf4, 0xa6, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x54,\n    0xce, 0x96, 0x91, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x83,\n    0x57, 0x8e, 0x62, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf7,\n    0xd4, 0x7e, 0x8a, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc0,\n    0xbc, 0x53, 0x26, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x50,\n    0x2d, 0x84, 0xdb, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7a,\n    0x80, 0x96, 0x31, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd8,\n    0x02, 0x7f, 0x3d, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8c,\n    0x1e, 0x7b, 0xc8, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbf,\n    0x6d, 0x91, 0x4f, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc7,\n    0xe1, 0x79, 0x64, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd7,\n    0x48, 0x31, 0x8d, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x61,\n    0x75, 0x0f, 0xc7, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7b,\n    0xfc, 0xc9, 0xd1, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9d,\n    0xff, 0x53, 0xc0, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf5,\n    0x1f, 0x7f, 0xcb, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4d,\n    0x9b, 0x48, 0x8b, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb0,\n    0xcb, 0x4e, 0x5a, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa3,\n    0x3a, 0xaf, 0x38, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6a,\n    0xef, 0xae, 0x40, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xca,\n    0xbc, 0x57, 0x77, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd6,\n    0x9f, 0xac, 0xad, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x77,\n    0x89, 0x47, 0x4a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7d,\n    0x8b, 0x1d, 0xdd, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3d,\n    0xa4, 0x86, 0x9a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x20,\n    0xb2, 0x98, 0xe4, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0xab, 0xa0, 0x17, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3b,\n    0xc6, 0x49, 0x8d, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfe,\n    0x4d, 0x89, 0x90, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe5,\n    0x9a, 0x27, 0xd6, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x3f,\n    0x56, 0x53, 0x4f, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x52,\n    0xc9, 0x4d, 0x70, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x89,\n    0x86, 0x7e, 0x37, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x78,\n    0x65, 0x7c, 0xec, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0f,\n    0x3f, 0x65, 0x0e, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2d,\n    0x18, 0xd6, 0x51, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xde,\n    0xc6, 0xea, 0x15, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1d,\n    0x76, 0x82, 0xb4, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x21,\n    0xeb, 0x3f, 0x3e, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x43,\n    0xb4, 0xed, 0x5f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x00,\n    0x77, 0xa3, 0xb7, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7f,\n    0x61, 0xac, 0x3f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x64,\n    0x82, 0x4f, 0x19, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x81,\n    0xa2, 0x29, 0x9d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x38,\n    0x95, 0x4c, 0x61, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xab,\n    0xfa, 0x48, 0x06, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x19,\n    0x6b, 0xdc, 0x13, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa9,\n    0x14, 0x41, 0xe2, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x16,\n    0x5a, 0x3a, 0x8a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1e,\n    0xe3, 0x3b, 0x40, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6b,\n    0xcc, 0x77, 0x78, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6e,\n    0x68, 0xaf, 0x06, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x23,\n    0xe6, 0x9f, 0x35, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xff,\n    0xe6, 0x33, 0xbe, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x70,\n    0x19, 0x52, 0xd3, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd2,\n    0x5a, 0x6b, 0xce, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8d,\n    0x5d, 0xf6, 0xfb, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x5c,\n    0x8c, 0x86, 0xef, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xae,\n    0x25, 0x02, 0xd0, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe8,\n    0x53, 0x4d, 0x27, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x72,\n    0x0e, 0x26, 0x3f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x58,\n    0xa6, 0x5b, 0xd7, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0x41, 0x5b, 0x23, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfa,\n    0x03, 0x5f, 0x5d, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9d,\n    0xc1, 0xb1, 0x08, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4e,\n    0x2f, 0x09, 0xca, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x03,\n    0xb5, 0xa0, 0x72, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf6,\n    0xa3, 0xb6, 0xf2, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x29,\n    0xad, 0x5c, 0xa4, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x33,\n    0x4e, 0x5a, 0xe7, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x88,\n    0xa1, 0x71, 0x6b, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xaa,\n    0x8a, 0x82, 0x11, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1d,\n    0x86, 0xee, 0x36, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe5,\n    0x66, 0xbc, 0x75, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0xa5, 0xc9, 0x1a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf3,\n    0x86, 0xa1, 0xc4, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x01,\n    0xc3, 0x67, 0x60, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6a,\n    0xa7, 0x08, 0x4c, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x22,\n    0x32, 0x97, 0x19, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x68,\n    0x5d, 0x4a, 0x48, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4f,\n    0xef, 0x1b, 0x4f, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x43,\n    0x79, 0xc6, 0x7f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x28,\n    0xf2, 0x64, 0x95, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x46,\n    0x68, 0xc5, 0x2d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xee,\n    0x67, 0xdb, 0x98, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe2,\n    0x90, 0x97, 0x45, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0x8c, 0x64, 0xce, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd7,\n    0x4a, 0xfb, 0x48, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0x90, 0xcf, 0xcb, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x44,\n    0x77, 0xf2, 0x6e, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0x28, 0x3e, 0xa4, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0a,\n    0x86, 0xdc, 0x38, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb2,\n    0x93, 0xe7, 0xa0, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x91,\n    0x99, 0xbc, 0x64, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6a,\n    0xc8, 0x63, 0x36, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x53,\n    0xb2, 0x2c, 0x36, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x15,\n    0xeb, 0x73, 0x7d, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xf5,\n    0xa4, 0xb4, 0x88, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6f,\n    0x67, 0x80, 0xeb, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x12,\n    0xd4, 0x3d, 0x42, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x09,\n    0x3d, 0x26, 0x53, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0f,\n    0x75, 0x5a, 0x89, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5c,\n    0x0d, 0x10, 0x41, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xed,\n    0xa4, 0x54, 0x48, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x08,\n    0xc5, 0x33, 0x2c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9d,\n    0xbe, 0x43, 0x72, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf0,\n    0xec, 0x6d, 0xd3, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5d,\n    0xc6, 0xce, 0xd4, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xab,\n    0x79, 0x1e, 0xdf, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4d,\n    0x4e, 0x1e, 0xe2, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x14,\n    0xf1, 0x60, 0x75, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf3,\n    0x11, 0xf7, 0xd0, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xeb,\n    0x31, 0x06, 0x1e, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdd,\n    0xfd, 0xf2, 0x08, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcc,\n    0xdc, 0x81, 0xe5, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3f,\n    0x29, 0x6b, 0xe9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcf,\n    0x16, 0x90, 0x8c, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0x21, 0x54, 0x14, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe7,\n    0xfe, 0xc9, 0xa6, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x03,\n    0xe5, 0x7e, 0xd1, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x24,\n    0x40, 0xa3, 0x0a, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x81,\n    0x39, 0x70, 0xcd, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcd,\n    0x76, 0xec, 0x7c, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe5,\n    0x81, 0xa2, 0x16, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb4,\n    0x92, 0x82, 0x6c, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9c,\n    0x4f, 0x49, 0x95, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x60,\n    0xb7, 0x53, 0x39, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0xcd, 0x08, 0x21, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbf,\n    0x37, 0x97, 0x92, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6d,\n    0x2e, 0xbd, 0x3a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x19,\n    0xb2, 0xb4, 0xf5, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc7,\n    0x12, 0xb5, 0x84, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x31,\n    0x35, 0xdc, 0x8d, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1e,\n    0xc1, 0x06, 0x77, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf7,\n    0x48, 0xda, 0x84, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1c,\n    0x79, 0x0f, 0xe1, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5c,\n    0x16, 0x07, 0xbc, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x12,\n    0x7b, 0x7f, 0x07, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1e,\n    0x81, 0x00, 0x17, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x83,\n    0x82, 0x8c, 0x38, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x35,\n    0x7f, 0xd0, 0xdd, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x65,\n    0x6e, 0xc4, 0x62, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x09,\n    0x24, 0xe7, 0x06, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4a,\n    0xbe, 0x94, 0xe9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0f,\n    0x97, 0x3a, 0x20, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2c,\n    0x6f, 0x31, 0x22, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x14,\n    0x6e, 0xde, 0x69, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x64,\n    0x02, 0xbe, 0x81, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfd,\n    0x5d, 0x18, 0x64, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf7,\n    0x35, 0xfb, 0x49, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5d,\n    0x3e, 0x7b, 0xeb, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x97,\n    0x81, 0x24, 0xfb, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x73,\n    0xe2, 0x8a, 0x19, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc6,\n    0x41, 0x48, 0x2e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x80,\n    0x14, 0x70, 0xe0, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0xa4, 0xcb, 0xa7, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x93,\n    0xeb, 0xd9, 0xb3, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0x4a, 0x1b, 0xff, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0e,\n    0x29, 0x60, 0xec, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x67,\n    0xee, 0xab, 0xe5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa3,\n    0x68, 0xe3, 0x09, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb1,\n    0x7a, 0x8d, 0x09, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x71,\n    0xcb, 0x60, 0x78, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x98,\n    0x88, 0x29, 0x9c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2a,\n    0x48, 0x5b, 0xcd, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6e,\n    0x93, 0xd0, 0xa1, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3c,\n    0x25, 0x73, 0xcb, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0xd6, 0x10, 0x1b, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x99,\n    0x73, 0x04, 0x8f, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc1,\n    0x15, 0xbc, 0x90, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x06,\n    0x5a, 0x22, 0x08, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x72,\n    0xdc, 0x23, 0xbd, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x82,\n    0x55, 0x14, 0x8d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x73,\n    0x37, 0x40, 0x08, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3b,\n    0x26, 0x6c, 0xa0, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb3,\n    0x73, 0xe6, 0x2b, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x91,\n    0x93, 0xc3, 0x75, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9b,\n    0xca, 0x0d, 0xf8, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x30,\n    0xdb, 0xf6, 0x3b, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xed,\n    0x5f, 0x0a, 0x20, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x1e,\n    0x8f, 0xee, 0x2b, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4b,\n    0x2e, 0x03, 0xeb, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0f,\n    0xa0, 0x67, 0x2f, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa1,\n    0xfc, 0x2c, 0x13, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdb,\n    0x3a, 0x8f, 0x3d, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x39,\n    0xfc, 0x36, 0x8f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x68,\n    0x8d, 0x53, 0x26, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x29,\n    0x29, 0x7b, 0xca, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x09,\n    0x28, 0x63, 0xcc, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x04,\n    0x3c, 0x59, 0xe3, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x98,\n    0x2f, 0x73, 0xbb, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x55,\n    0x38, 0x8e, 0x60, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc6,\n    0xac, 0x3e, 0xa5, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x90,\n    0x6e, 0x53, 0x98, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6b,\n    0xf4, 0x6f, 0xe9, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x95,\n    0xaa, 0x54, 0xb3, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x1e,\n    0x48, 0xcb, 0x17, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf7,\n    0x3b, 0xdf, 0x0a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0f,\n    0xc7, 0x4a, 0xd4, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd2,\n    0xc2, 0x5b, 0xff, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x68,\n    0xb5, 0xa0, 0x6c, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xef,\n    0xb1, 0xf8, 0xb5, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x54,\n    0xde, 0xf2, 0x94, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x43,\n    0x02, 0x4f, 0xc8, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0f,\n    0xb3, 0x1d, 0xe5, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0xb9, 0x97, 0x67, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7f,\n    0x1e, 0xa1, 0x18, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x15,\n    0x2e, 0x51, 0x21, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x96,\n    0x7b, 0xf2, 0xc8, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xde,\n    0x69, 0x3d, 0xc2, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x26,\n    0x4a, 0x1d, 0x52, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0x7a, 0x3f, 0x77, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcf,\n    0x4d, 0xd5, 0xf7, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8f,\n    0xaa, 0x65, 0xaf, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x58,\n    0xcc, 0x50, 0x57, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0x17, 0x23, 0x93, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa8,\n    0xea, 0xb6, 0x23, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xff,\n    0x61, 0x1c, 0xdf, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc6,\n    0xb1, 0x41, 0xd9, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa6,\n    0xb1, 0x6a, 0x6d, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd0,\n    0x60, 0xa9, 0x3f, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x96,\n    0x41, 0xd9, 0xfc, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x59,\n    0xd4, 0x42, 0x0e, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe9,\n    0x20, 0xd8, 0x5e, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x92,\n    0xa9, 0xb3, 0x56, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa2,\n    0x83, 0xeb, 0x04, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x72,\n    0x16, 0x8b, 0x05, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4f,\n    0xb8, 0x40, 0x18, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xab,\n    0xf3, 0x9b, 0x65, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x64,\n    0x72, 0x31, 0x2c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd0,\n    0x5a, 0x4f, 0x2b, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0xb9, 0xa1, 0x8c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x85,\n    0xcb, 0x49, 0x32, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9d,\n    0x15, 0x4e, 0x91, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x57,\n    0xfe, 0xe6, 0xa7, 0x00, 0x10, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe3,\n    0xcb, 0x89, 0x99, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x11,\n    0xb9, 0x02, 0x3c, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0x09, 0x6d, 0x4f, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x17,\n    0x08, 0xd8, 0x1b, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x68,\n    0x18, 0x31, 0x3f, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbf,\n    0x92, 0xbb, 0xaf, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf5,\n    0x66, 0xfe, 0xca, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x38,\n    0x14, 0x65, 0xfa, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x2a,\n    0x44, 0x86, 0x93, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7c,\n    0xf2, 0x63, 0x1a, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1a,\n    0xdd, 0x1b, 0xad, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0xfd, 0xda, 0x71, 0x00, 0x70, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x10,\n    0x6e, 0x30, 0x2e, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x72,\n    0x80, 0x2c, 0x0d, 0x00, 0xc0, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9c,\n    0x00, 0x43, 0x70, 0x00, 0x60, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x13,\n    0x8b, 0x96, 0x2f, 0x00, 0xd0, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x5a,\n    0x3d, 0x1b, 0x52, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x08,\n    0xb9, 0x6f, 0xbe, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0xd6, 0x75, 0xf7, 0x00, 0xd0, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf6,\n    0x62, 0x69, 0x4d, 0x00, 0xc0, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x2c,\n    0x95, 0xd0, 0x9d, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0x15, 0x84, 0x0c, 0x00, 0xd0, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5c,\n    0x7c, 0x50, 0xd6, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbb,\n    0x82, 0x9c, 0x00, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0c,\n    0x92, 0x77, 0x98, 0x00, 0xc0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe9,\n    0x87, 0x04, 0xf8, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3d,\n    0x5a, 0xc1, 0xc5, 0x00, 0xc0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x71,\n    0x81, 0x8f, 0xd9, 0x00, 0xc0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x32,\n    0xc5, 0xb3, 0xb9, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x34,\n    0xcd, 0x96, 0xa1, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfb,\n    0x7b, 0xfb, 0xe4, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x09,\n    0x90, 0xdd, 0x36, 0x00, 0x40, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x54,\n    0xf4, 0xe1, 0x86, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x59,\n    0x7f, 0x0f, 0x3f, 0x00, 0x40, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x02,\n    0xcf, 0x1d, 0x6e, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1d,\n    0x01, 0x35, 0xe1, 0x00, 0x40, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0xb5, 0x10, 0x5e, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x65,\n    0x63, 0x97, 0xc6, 0x00, 0x40, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x63,\n    0x0e, 0x21, 0x47, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd5,\n    0x46, 0xa5, 0x53, 0x00, 0xd0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbc,\n    0x5f, 0x61, 0x66, 0x00, 0xc0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1c,\n    0x11, 0xb2, 0xad, 0x00, 0x40, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x68,\n    0xe1, 0x74, 0x91, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x80,\n    0x75, 0xc1, 0xf1, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcd,\n    0x53, 0xe0, 0x48, 0x00, 0xc0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x30,\n    0x57, 0xef, 0x12, 0x00, 0xc0, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6b,\n    0xad, 0x7e, 0x00, 0x00, 0x40, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0x3b, 0x87, 0x1e, 0x00, 0xc0, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x38,\n    0xb0, 0x12, 0x98, 0x00, 0x40, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0x0c, 0x68, 0x78, 0x00, 0xc0, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3c,\n    0xd4, 0xbb, 0x3a, 0x00, 0xc0, 0x04, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd2,\n    0x7d, 0x11, 0x09, 0x00, 0x40, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x3e,\n    0x3b, 0xff, 0xf8, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd7,\n    0x9e, 0x2f, 0xf2, 0x00, 0x00, 0x05, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe3,\n    0xc1, 0x52, 0x2c, 0x00, 0x80, 0x04, 0x01, 0x98,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2e,\n    0x67, 0x46, 0xdb, 0x00, 0xc0, 0x24, 0x01, 0x0c,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0x74, 0xa2, 0xed, 0x00, 0xc0, 0x24, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0x22, 0x08, 0xaf, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe0,\n    0x3b, 0x95, 0xfe, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfb,\n    0x95, 0xe8, 0xd1, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe7,\n    0x93, 0xad, 0x79, 0x00, 0x80, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf7,\n    0x1f, 0x5b, 0x34, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xd6,\n    0x37, 0xc4, 0x48, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x71,\n    0x85, 0x60, 0x4e, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7e,\n    0x7d, 0xfc, 0x14, 0x00, 0x80, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcc,\n    0xe1, 0x00, 0x30, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb8,\n    0x04, 0x03, 0x4d, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0b,\n    0xca, 0x2a, 0xe0, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x31,\n    0xb5, 0x48, 0x94, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x1f,\n    0x39, 0x7c, 0x50, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x03,\n    0x6e, 0x0a, 0x93, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x53,\n    0x1a, 0x14, 0xc3, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe5,\n    0x04, 0x77, 0x98, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9d,\n    0x90, 0xea, 0x46, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2d,\n    0x4d, 0xbf, 0x4f, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4e,\n    0x51, 0xf8, 0x6d, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0x62, 0xb0, 0x29, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x69,\n    0xe8, 0xaf, 0x15, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x28,\n    0x79, 0xa8, 0x53, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8d,\n    0x79, 0x09, 0xfc, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x19,\n    0x62, 0x32, 0x05, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x7a,\n    0x89, 0xd6, 0x91, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x25,\n    0x18, 0x43, 0xbe, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8d,\n    0x83, 0x36, 0x32, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb7,\n    0x55, 0x2e, 0x9f, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfe,\n    0x5d, 0xff, 0x1c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x51,\n    0x38, 0x0f, 0x77, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1a,\n    0x8b, 0x05, 0xbd, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x21,\n    0x24, 0xa5, 0xc3, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x2e,\n    0x70, 0x08, 0x98, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x52,\n    0xa7, 0x66, 0x1f, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x16,\n    0x14, 0x4d, 0x1c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xef,\n    0x56, 0x68, 0x28, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3e,\n    0x80, 0x84, 0x68, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x71,\n    0xe2, 0x8c, 0x64, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb6,\n    0x27, 0x5d, 0xc0, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0x33, 0xd4, 0x86, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc6,\n    0x57, 0x6d, 0x16, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9b,\n    0xf8, 0x94, 0x04, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcf,\n    0x99, 0x2c, 0xf6, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9c,\n    0x6c, 0xe5, 0x75, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcb,\n    0x9c, 0x24, 0x1b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc6,\n    0xfb, 0x3a, 0x6f, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe3,\n    0xc3, 0x30, 0x7a, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x29,\n    0xee, 0xa5, 0x9a, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9f,\n    0x2d, 0x3d, 0x28, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0x8c, 0x73, 0x62, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc3,\n    0xd4, 0x79, 0x7b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xee,\n    0xa4, 0xc9, 0xfb, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcb,\n    0x54, 0x58, 0xef, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf0,\n    0x0d, 0x30, 0xa2, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x49,\n    0xdf, 0x8e, 0xe8, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0x9c, 0x25, 0x6e, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb0,\n    0xd7, 0x9e, 0x94, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x6a,\n    0x60, 0xa1, 0xe0, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe2,\n    0x57, 0x32, 0x3f, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbf,\n    0xad, 0xa3, 0xf3, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe7,\n    0x8b, 0xd3, 0x87, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5d,\n    0xde, 0x49, 0x6c, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbe,\n    0xcc, 0x4b, 0x0f, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x16,\n    0x9a, 0xfd, 0x7e, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9d,\n    0x94, 0x52, 0x3e, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0x9d, 0xdd, 0xce, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x93,\n    0xb2, 0xbd, 0x39, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x18,\n    0xff, 0x52, 0x2d, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2f,\n    0xbf, 0x62, 0x15, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x85, 0x5d, 0xbc, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf8,\n    0x8a, 0x5d, 0x79, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9c,\n    0xb7, 0x39, 0x17, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x83,\n    0xc9, 0x07, 0x41, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe4,\n    0x6a, 0xcb, 0x10, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf2,\n    0x25, 0xd8, 0x6b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa6,\n    0xb6, 0x8d, 0xd9, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x83,\n    0xb0, 0xce, 0x12, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x88,\n    0x79, 0x8b, 0xca, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7a,\n    0xa9, 0x2a, 0x9f, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0xaf, 0x2e, 0x00, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb4,\n    0x92, 0xd3, 0xb7, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xfb,\n    0xfb, 0x6c, 0xb1, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7e,\n    0x9c, 0x30, 0x6d, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8f,\n    0x17, 0x1c, 0x87, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3f,\n    0xa6, 0x92, 0xfb, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x42,\n    0x57, 0xa2, 0x8c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xda,\n    0xa9, 0x0f, 0xcb, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2c,\n    0xa9, 0xfb, 0x1d, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0xac, 0x5a, 0x14, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb3,\n    0x6f, 0xa3, 0x3e, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe0,\n    0x45, 0x4d, 0x3c, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x87,\n    0xb5, 0x02, 0xc7, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0x1a, 0x21, 0xec, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe5,\n    0x70, 0xcd, 0xda, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0x61, 0xb0, 0x75, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xab,\n    0xea, 0x27, 0xd5, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfa,\n    0xc2, 0x5b, 0xe2, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd7,\n    0x38, 0x30, 0x02, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3d,\n    0x1c, 0x0d, 0x09, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa1,\n    0x85, 0xf2, 0x8a, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xde,\n    0x28, 0x50, 0x3c, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x39,\n    0x6d, 0x8d, 0x8f, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4a,\n    0x66, 0xd8, 0xfc, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x10,\n    0x55, 0x66, 0x8a, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x80,\n    0xfd, 0x7b, 0x5c, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd5,\n    0x5a, 0x39, 0xed, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2e,\n    0x05, 0x8b, 0x11, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0a,\n    0xfc, 0x72, 0x97, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7b,\n    0x80, 0xec, 0x47, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x41,\n    0x45, 0xdb, 0xbe, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0x47, 0x6c, 0x4f, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc1,\n    0xe1, 0x6b, 0x97, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x32, 0xbe, 0x3c, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x72,\n    0xfa, 0x55, 0xcf, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x92,\n    0x7d, 0xf4, 0x9e, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x38,\n    0x03, 0xe8, 0x4b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbb,\n    0xf4, 0xba, 0x23, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x03,\n    0x8c, 0xcd, 0x70, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5e,\n    0x9a, 0x84, 0x45, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb1,\n    0x58, 0xd6, 0xcd, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x52,\n    0x2b, 0xa1, 0x69, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x10,\n    0xaa, 0xd3, 0xf3, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd0,\n    0xb4, 0x36, 0x35, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa4,\n    0x3b, 0xec, 0x62, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3c,\n    0x7a, 0xf1, 0x09, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcd,\n    0xed, 0x0d, 0xc5, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa8,\n    0xc8, 0x65, 0x4e, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb3,\n    0x16, 0x2d, 0x2c, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbd,\n    0xbd, 0x56, 0x4b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc0,\n    0xfb, 0xdf, 0xe0, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x74,\n    0xdd, 0xd9, 0x7b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6a,\n    0x9a, 0x49, 0x56, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5e,\n    0x3e, 0xfd, 0xed, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0x37, 0x3d, 0x71, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x87,\n    0x1f, 0x08, 0x68, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf7,\n    0xf5, 0x13, 0x12, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbf,\n    0x42, 0x46, 0x3a, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x37,\n    0xac, 0xf4, 0x2b, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa0,\n    0xc7, 0x29, 0xd5, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe7,\n    0xd8, 0x02, 0xce, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc5,\n    0x2d, 0xad, 0xa9, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x06,\n    0x62, 0xfa, 0x9a, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x49,\n    0xac, 0xaa, 0xad, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x83,\n    0x7a, 0x3a, 0x78, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x02,\n    0xf6, 0x9b, 0x1c, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc6,\n    0x18, 0xb7, 0xbf, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0x81, 0x91, 0x05, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x79,\n    0xc1, 0x25, 0x23, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x90,\n    0x6f, 0x43, 0xa3, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4f,\n    0x1e, 0x57, 0xde, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8a,\n    0xc4, 0x2c, 0x23, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x58,\n    0x9b, 0x40, 0x56, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc5,\n    0xde, 0x2b, 0x9d, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe6,\n    0xaa, 0xca, 0x18, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5d,\n    0xa8, 0xdc, 0x53, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2d,\n    0x36, 0xe0, 0xa6, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcd,\n    0xe5, 0x63, 0x85, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb2,\n    0x41, 0x33, 0xe0, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x81,\n    0x2e, 0x60, 0x8a, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x81,\n    0xa0, 0x92, 0xb2, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc8,\n    0x60, 0x36, 0xdb, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xeb,\n    0x5d, 0x40, 0x89, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9d,\n    0xab, 0x47, 0xc0, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd7,\n    0xfa, 0xce, 0xa6, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6a,\n    0x51, 0x18, 0xdf, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe3,\n    0x3b, 0x2b, 0x70, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0x82, 0xb5, 0x3e, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf9,\n    0x0a, 0xc0, 0xe1, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x96,\n    0x6a, 0x67, 0x05, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb6,\n    0xf1, 0x8d, 0xb3, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb3,\n    0x44, 0xb8, 0xf7, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdd,\n    0x78, 0x58, 0xe2, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x70,\n    0x6b, 0x84, 0x63, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd4,\n    0x70, 0xf5, 0xbe, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xed,\n    0x5c, 0xa7, 0xa1, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x61,\n    0xee, 0x8f, 0x8c, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0x1e, 0xff, 0x62, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x44,\n    0x60, 0x71, 0xcc, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdd,\n    0x9c, 0x4b, 0x73, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc4,\n    0xef, 0x1b, 0x2f, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x76,\n    0x12, 0x4c, 0x21, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x58,\n    0x06, 0x41, 0x1e, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x99,\n    0x59, 0x36, 0x97, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0x9b, 0x1f, 0x65, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd9,\n    0xe0, 0xf1, 0x6d, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xef,\n    0xd0, 0x35, 0x89, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x97,\n    0x13, 0x41, 0x3e, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd9,\n    0x55, 0xa0, 0xe4, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x30,\n    0xc4, 0x30, 0xc8, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfd,\n    0x08, 0xe6, 0x87, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0x10, 0x24, 0x6d, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf7,\n    0x6c, 0xe9, 0x91, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7d,\n    0x4c, 0x9c, 0xb5, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2a,\n    0x11, 0x4a, 0x35, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3a,\n    0x40, 0xf2, 0x2f, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3e,\n    0x33, 0xfd, 0x91, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6e,\n    0xed, 0xf2, 0xe4, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7e,\n    0x99, 0xc0, 0xd6, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x31,\n    0x97, 0xd7, 0xfe, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb5,\n    0x7f, 0x61, 0x72, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9d,\n    0xbc, 0x4a, 0x65, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb0,\n    0x8a, 0x8c, 0xdf, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0x3b, 0xca, 0xab, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x4f,\n    0x9b, 0xa0, 0x96, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x45, 0x67, 0x4e, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xed,\n    0xb8, 0x11, 0x13, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x51,\n    0xef, 0x40, 0x37, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x15,\n    0xf7, 0x41, 0x34, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf2,\n    0x15, 0x6c, 0x57, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5a,\n    0x85, 0xf2, 0xcb, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x72,\n    0x6a, 0xc8, 0xad, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9a,\n    0xc7, 0x2c, 0x79, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x57,\n    0xff, 0x72, 0xad, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb3,\n    0xda, 0x8a, 0x2f, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2a,\n    0xb7, 0xe9, 0x96, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x9d,\n    0x9e, 0x83, 0x5d, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xaa,\n    0x6f, 0xee, 0x5e, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2e,\n    0xbd, 0x09, 0x44, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd1,\n    0x87, 0x62, 0x5e, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfc,\n    0xd2, 0xf0, 0x8b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x25,\n    0xd1, 0xda, 0x93, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb5,\n    0x96, 0x0b, 0x5c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x52,\n    0x87, 0xb2, 0x78, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0x29, 0xfc, 0xaa, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x90,\n    0x6a, 0x01, 0x7c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5f,\n    0x8c, 0x5d, 0xc6, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2e,\n    0x69, 0x5b, 0x63, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xdf,\n    0xcb, 0x03, 0xd5, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8e,\n    0xf9, 0x11, 0xea, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe3,\n    0x29, 0xb3, 0x7c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa1,\n    0x49, 0x0d, 0x71, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6d,\n    0x98, 0xe8, 0x63, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9a,\n    0x56, 0xec, 0xa3, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x45,\n    0x66, 0x19, 0x89, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd8,\n    0x52, 0xfe, 0x48, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb1,\n    0xb6, 0x17, 0x62, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x78,\n    0xc0, 0x8f, 0x8d, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xba,\n    0xc9, 0x1d, 0x59, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcd,\n    0x39, 0xf9, 0xde, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x91,\n    0x97, 0x94, 0x9b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xeb,\n    0x73, 0x81, 0x5a, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x60,\n    0x30, 0xe3, 0x7a, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc5,\n    0xd7, 0xa0, 0x8b, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x66,\n    0xcd, 0xc1, 0x16, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x01,\n    0xd3, 0x58, 0xed, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfa,\n    0xae, 0x69, 0xb9, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x34,\n    0xeb, 0xb7, 0xc6, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2a,\n    0x4a, 0x18, 0x56, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbf,\n    0x12, 0xb9, 0x42, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf3,\n    0xc1, 0x15, 0x14, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3b,\n    0xbd, 0xb5, 0xb8, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x44,\n    0x09, 0xad, 0x7e, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x42,\n    0x08, 0x52, 0x7d, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa7,\n    0x89, 0x94, 0x6c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcf,\n    0x99, 0x76, 0xbf, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa7,\n    0x0b, 0x8d, 0x65, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x88,\n    0x89, 0xd0, 0x34, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa2,\n    0xdf, 0xcf, 0x04, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd7,\n    0x73, 0x6e, 0x24, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x24,\n    0xc5, 0x43, 0x11, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2e,\n    0x04, 0x30, 0x05, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x47,\n    0xe5, 0xbd, 0xdc, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xaa,\n    0x05, 0x47, 0xd3, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0x89, 0xba, 0x70, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1b,\n    0x11, 0x00, 0xc1, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4b,\n    0xf0, 0x97, 0xcf, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x62,\n    0x87, 0x99, 0x7d, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xda,\n    0xb7, 0x2f, 0xdd, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x60,\n    0x4e, 0x5d, 0x73, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe1,\n    0x71, 0xe9, 0xeb, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7f,\n    0x07, 0x20, 0x90, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbb,\n    0xda, 0x0b, 0xee, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb8,\n    0xd3, 0xe2, 0xdb, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa5,\n    0x42, 0x2c, 0x9a, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0d,\n    0xe4, 0xc4, 0xea, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x26,\n    0x20, 0x39, 0x53, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa1,\n    0x61, 0xf0, 0x1c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x61,\n    0xf4, 0xa9, 0xd8, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdf,\n    0x8c, 0x08, 0x2f, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0e,\n    0x4e, 0x21, 0x12, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa8,\n    0xec, 0xb0, 0xbe, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2c,\n    0x73, 0xa7, 0x6a, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe6,\n    0x3f, 0xe6, 0xd8, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x84,\n    0x9a, 0x22, 0xfe, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xae,\n    0xf4, 0x2e, 0xac, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdf,\n    0x9c, 0x38, 0xbb, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa4,\n    0xe6, 0x1e, 0x79, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x63,\n    0x8d, 0xed, 0x23, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7b,\n    0x4b, 0x57, 0xd5, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3c,\n    0x34, 0x61, 0xcb, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe3,\n    0x21, 0xd4, 0x7c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb2,\n    0x96, 0x2b, 0x5f, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb5,\n    0x60, 0xcc, 0xda, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2b,\n    0x99, 0x9d, 0x7a, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb5,\n    0x5f, 0x8a, 0xa4, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x51,\n    0x79, 0x0f, 0xcf, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4a,\n    0x03, 0x87, 0x8e, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x04,\n    0xcf, 0x8d, 0xb8, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd4,\n    0x0b, 0x1e, 0x1c, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xff,\n    0x93, 0xf3, 0x85, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc5,\n    0x11, 0xf4, 0x34, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbb,\n    0x09, 0x89, 0xc2, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbb,\n    0xf5, 0x6b, 0x4f, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x63,\n    0xba, 0x9b, 0xd5, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0a,\n    0xd6, 0x9e, 0xa3, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8d,\n    0x10, 0x87, 0xe6, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc9,\n    0x72, 0x2c, 0xd2, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x07,\n    0x0f, 0xf2, 0xce, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x57,\n    0xa8, 0x12, 0xee, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf3,\n    0x7e, 0x7f, 0xc4, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8f,\n    0x9a, 0xe7, 0x62, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe0,\n    0x64, 0xc8, 0x40, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x57,\n    0x59, 0xe5, 0x06, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7b,\n    0x9a, 0xe1, 0xea, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3f,\n    0x87, 0xa2, 0x7d, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x4e,\n    0x36, 0x5c, 0x01, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1b,\n    0xc0, 0x8b, 0x19, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x51,\n    0x49, 0xb5, 0x71, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x02,\n    0x02, 0x77, 0x05, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0f,\n    0xd6, 0x88, 0x96, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x08,\n    0xf3, 0x9a, 0x63, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x22,\n    0x12, 0x2a, 0x6f, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1d,\n    0x28, 0xfc, 0xe2, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1b,\n    0x2d, 0xf0, 0xde, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1b,\n    0x35, 0x39, 0x79, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3f,\n    0x45, 0x53, 0xd4, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7b,\n    0x64, 0xa0, 0x97, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x86,\n    0xd5, 0x03, 0x48, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x96,\n    0x8f, 0x68, 0x0a, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1d,\n    0x2f, 0x32, 0x2a, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcb,\n    0xcd, 0x75, 0x6c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xd7,\n    0x38, 0xc1, 0x1d, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xd7,\n    0x38, 0xc1, 0x1d, 0x80, 0x45, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xda,\n    0x78, 0x0f, 0x4e, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x38,\n    0xde, 0xe5, 0xf9, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x91,\n    0xc6, 0xb6, 0x9f, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x97,\n    0x27, 0x14, 0x30, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x26,\n    0x53, 0x56, 0x1f, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0xea, 0xc8, 0xee, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xba,\n    0x41, 0xb6, 0x9a, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x78,\n    0x2b, 0x5b, 0xae, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9e,\n    0x99, 0xec, 0x3f, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2d,\n    0xe5, 0x59, 0xb2, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x49,\n    0xcb, 0x48, 0x9d, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0f,\n    0x81, 0xef, 0x43, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0xf5, 0x24, 0x91, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8a,\n    0x47, 0xdd, 0x28, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcf,\n    0x48, 0x1d, 0x9d, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x85,\n    0xe7, 0x0b, 0xe5, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdb,\n    0x2a, 0x58, 0xe0, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe4,\n    0xba, 0x30, 0x4f, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xab,\n    0x3e, 0x7f, 0xe7, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x05,\n    0x0e, 0xec, 0xa8, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6f,\n    0x86, 0x01, 0x55, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0xee, 0x4b, 0x2d, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe0,\n    0x17, 0xb1, 0x10, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9f,\n    0xf8, 0x70, 0x5c, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8d,\n    0x12, 0xc7, 0x06, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9f,\n    0xf5, 0xc7, 0x0b, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x69,\n    0x3a, 0xcd, 0xa2, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x88,\n    0x30, 0xbf, 0x84, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfb,\n    0x09, 0xc2, 0x36, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x19,\n    0xef, 0x70, 0x40, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x51,\n    0x93, 0x73, 0x9d, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa0,\n    0x7f, 0x53, 0x41, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x27,\n    0x19, 0x29, 0x96, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9e,\n    0x2e, 0xd7, 0x5a, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xca,\n    0x62, 0x16, 0xff, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x99,\n    0x29, 0xd7, 0x4a, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0xfa, 0xe3, 0xbc, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xad,\n    0xbc, 0xfd, 0x43, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8f,\n    0xe2, 0x38, 0xae, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xef,\n    0xff, 0x4f, 0xf4, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfe,\n    0x0c, 0x29, 0xf0, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc3,\n    0xc2, 0xe8, 0x86, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x15,\n    0xe1, 0x5c, 0x81, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdb,\n    0xbd, 0xae, 0x80, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe6,\n    0x0a, 0xe2, 0xe6, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf2,\n    0xa0, 0xde, 0xc2, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfb,\n    0xcb, 0xaa, 0x98, 0x00, 0x00, 0x45, 0x01, 0x6a,\n    0x04, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x25,\n    0x94, 0x0d, 0x34, 0x00, 0xa0, 0x24, 0x01, 0xb0,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x18,\n    0xdb, 0xd4, 0x69, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe1,\n    0xd1, 0x1a, 0x3c, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x5b,\n    0x7a, 0x64, 0x52, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdd,\n    0x71, 0x3f, 0xd1, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x79,\n    0xd7, 0xd8, 0xe9, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x31,\n    0xd5, 0xcd, 0x9c, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8a,\n    0x36, 0xc7, 0xc6, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa1,\n    0xaf, 0xe3, 0x63, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x44,\n    0xaa, 0x91, 0xde, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x79,\n    0xf4, 0x3c, 0xaa, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8d,\n    0xd7, 0x73, 0x44, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x14,\n    0xa3, 0x3a, 0xd5, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0xec, 0x7d, 0xa8, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3a,\n    0xef, 0x20, 0xc9, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xef,\n    0xb1, 0x72, 0x8a, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4b,\n    0xdb, 0x0f, 0x8a, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x03,\n    0x72, 0x83, 0x51, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfc,\n    0x3c, 0x1e, 0x57, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf7,\n    0x8d, 0x68, 0xcd, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xad,\n    0x0f, 0x04, 0x71, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x22,\n    0xe1, 0x9b, 0x19, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7f,\n    0x0b, 0x71, 0xe6, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x19,\n    0x28, 0x78, 0xea, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe2,\n    0x11, 0x8a, 0xd8, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb0,\n    0xa1, 0x17, 0xe4, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x63,\n    0x7d, 0x94, 0x0f, 0x00, 0xe0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbc,\n    0x88, 0x1c, 0x05, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x02,\n    0x74, 0xa3, 0xf5, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbe,\n    0xf7, 0x69, 0xc8, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xfd,\n    0xf2, 0xd8, 0xec, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x81,\n    0xd1, 0x52, 0x26, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbc,\n    0x57, 0xe8, 0xb3, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x43,\n    0x70, 0x16, 0x3b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xde,\n    0x7b, 0xcf, 0xf7, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8c,\n    0x96, 0x13, 0xe0, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7b,\n    0x47, 0x96, 0x3f, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x41,\n    0xa0, 0x31, 0x81, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfd,\n    0x96, 0x47, 0x64, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa5,\n    0x1c, 0xcd, 0xe2, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x22,\n    0x4a, 0x88, 0xfb, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0xa5, 0xed, 0x13, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8a,\n    0x22, 0x8a, 0xd4, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x07,\n    0xc4, 0x23, 0xb7, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xce,\n    0x0b, 0x7a, 0xae, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x10,\n    0xfc, 0x67, 0xdf, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x51,\n    0xb0, 0x99, 0x7a, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x61,\n    0x54, 0xa9, 0xcf, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x85,\n    0x55, 0x9d, 0x0c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb8,\n    0x36, 0xfc, 0x4a, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe2,\n    0xd2, 0xf5, 0xc5, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xab,\n    0xfd, 0x2a, 0x7d, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x68,\n    0x5d, 0xbc, 0x3e, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xcb,\n    0x2d, 0xdf, 0xa9, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x16,\n    0xb1, 0x4c, 0xf9, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x64,\n    0xeb, 0x9f, 0x18, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb5,\n    0x36, 0xb1, 0x6a, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x12,\n    0xb9, 0x87, 0xcb, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x47,\n    0xbd, 0x7e, 0x11, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x90,\n    0x74, 0x27, 0x6f, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x07,\n    0xbb, 0xf2, 0xed, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x85,\n    0x2f, 0x9e, 0x19, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0x4f, 0x1d, 0x99, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3c,\n    0xf7, 0x2d, 0xe9, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xd7,\n    0x95, 0x48, 0x27, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1f,\n    0xb4, 0xd1, 0x4d, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf2,\n    0xba, 0x73, 0x7d, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xbb,\n    0x89, 0x96, 0xee, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x02,\n    0x8f, 0xa5, 0xf6, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x71,\n    0x9c, 0xf1, 0xcb, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0d,\n    0x16, 0x23, 0x02, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x31,\n    0x02, 0xcc, 0x50, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x9b,\n    0xc0, 0x6d, 0xee, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x91,\n    0x9f, 0x1c, 0xfd, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe2,\n    0xdd, 0xb7, 0x0d, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x86,\n    0xac, 0x6c, 0x51, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8e,\n    0x04, 0x13, 0xec, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x57,\n    0xf1, 0xa1, 0x0e, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x11,\n    0x1f, 0x9c, 0xa7, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd8,\n    0xb8, 0x94, 0x86, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xba,\n    0x1c, 0x2c, 0x94, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb2,\n    0x26, 0x28, 0x8b, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0a,\n    0x68, 0xdc, 0xcd, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb9,\n    0xdf, 0x3f, 0xa5, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd0,\n    0x06, 0x08, 0x96, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x60,\n    0x17, 0x1e, 0x7f, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa9,\n    0x65, 0xb9, 0x94, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0x9a, 0x4b, 0x17, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd3,\n    0xca, 0xcd, 0x77, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x6b,\n    0xfd, 0x99, 0x8a, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x80,\n    0x72, 0x3c, 0x8a, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x02,\n    0x7e, 0xaa, 0x21, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x3c,\n    0xd2, 0xfc, 0x1c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc3,\n    0xa4, 0x30, 0x3a, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x91,\n    0x1b, 0x97, 0xcc, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x51,\n    0xd9, 0x55, 0xae, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x53,\n    0xaf, 0x17, 0xd6, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0b,\n    0x42, 0x43, 0x1f, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x5f,\n    0xdc, 0x1b, 0x65, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x89,\n    0xc3, 0x53, 0x1c, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5d,\n    0x80, 0x32, 0xda, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xf9,\n    0x9d, 0xf0, 0x5f, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa6,\n    0xcd, 0xd4, 0x72, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdd,\n    0xc7, 0x00, 0x59, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x92,\n    0xe3, 0xf1, 0xbb, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x7d,\n    0xd0, 0x09, 0x42, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x16,\n    0xea, 0xb8, 0x88, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x54,\n    0x18, 0x42, 0x22, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x62,\n    0xc8, 0x41, 0xd1, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xe2,\n    0xe0, 0xd0, 0xae, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe1,\n    0xaf, 0xe8, 0xd7, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x72,\n    0xe7, 0xa4, 0x37, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x10,\n    0x87, 0x89, 0xae, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x01,\n    0x24, 0x9a, 0x43, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x84,\n    0x69, 0x94, 0x46, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x57,\n    0x60, 0x19, 0xdd, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb6,\n    0x57, 0x87, 0x4b, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc1,\n    0x08, 0xce, 0x89, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x55,\n    0x5a, 0x5c, 0x72, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x98,\n    0x23, 0x45, 0x7f, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x01,\n    0x16, 0xca, 0xc1, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5f,\n    0x26, 0xf4, 0x53, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x9e,\n    0xe8, 0x4d, 0x7d, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xd4,\n    0x65, 0x64, 0xe4, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x34,\n    0x4f, 0x28, 0xde, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe8,\n    0x2f, 0x21, 0x08, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xab,\n    0x73, 0xf4, 0xb7, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6b,\n    0x19, 0xcf, 0x33, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xa4,\n    0x0d, 0x37, 0x90, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2a,\n    0xf9, 0xa0, 0x7e, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x91,\n    0xcd, 0x58, 0x8b, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xb0,\n    0xf9, 0x87, 0xdb, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x74,\n    0x2c, 0xc5, 0x30, 0x00, 0xf0, 0x44, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x70,\n    0x29, 0x84, 0x2d, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x04,\n    0xa1, 0xef, 0xa0, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xf3,\n    0xbb, 0xcb, 0x94, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x0f,\n    0xcd, 0xd5, 0x0c, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x02,\n    0x2b, 0x05, 0x88, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xfe,\n    0xfb, 0x51, 0xd2, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x03,\n    0x46, 0x97, 0xe2, 0x00, 0xa0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x1f,\n    0x4c, 0xf5, 0x6d, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0xea, 0x4c, 0xa6, 0x00, 0x00, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdd,\n    0x31, 0x05, 0x34, 0x00, 0x90, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x00,\n    0x39, 0x8b, 0xeb, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xdb,\n    0x8f, 0x1e, 0xd0, 0x00, 0x40, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xce,\n    0x2e, 0x3b, 0x86, 0x00, 0xf0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x41,\n    0x91, 0x36, 0x3c, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xa0,\n    0x08, 0x90, 0x27, 0x00, 0x40, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x50,\n    0x34, 0xf1, 0x21, 0x00, 0xf0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x23,\n    0xd4, 0x2a, 0x2f, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xee,\n    0x67, 0xe9, 0x5a, 0x00, 0x40, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x45,\n    0x47, 0x20, 0x39, 0x00, 0xf0, 0x24, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x60,\n    0xf0, 0x00, 0x04, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc3,\n    0xea, 0xa4, 0x38, 0x00, 0x60, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x1b,\n    0x86, 0x01, 0x0f, 0x00, 0x00, 0x25, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xf6,\n    0xb8, 0x91, 0x88, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x93,\n    0x60, 0x8e, 0x22, 0x00, 0x60, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xbb,\n    0x5b, 0x2d, 0x4c, 0x00, 0x00, 0x25, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x85,\n    0xa3, 0x01, 0xbf, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x15,\n    0x90, 0x1e, 0xb4, 0x00, 0x60, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbd,\n    0x56, 0xfb, 0x3f, 0x00, 0x60, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x5d,\n    0x28, 0x5d, 0xf3, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe0,\n    0xe9, 0xca, 0xb2, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x77,\n    0x8f, 0xdb, 0xad, 0x00, 0x60, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf9,\n    0x49, 0x1f, 0xa7, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xec,\n    0xa5, 0x08, 0x6a, 0x00, 0x60, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe8,\n    0x5b, 0xde, 0x44, 0x00, 0x60, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x85,\n    0x48, 0x05, 0xf3, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe5,\n    0x95, 0x57, 0x6a, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x12,\n    0x3c, 0x5c, 0x61, 0x00, 0x60, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7c,\n    0xd7, 0x26, 0x2e, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xba,\n    0xf6, 0xca, 0xb7, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc9,\n    0x7e, 0xfa, 0xfb, 0x00, 0x70, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9d,\n    0xd0, 0xd2, 0x00, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x50,\n    0x9c, 0xdc, 0x22, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0x98, 0xfd, 0xa1, 0x00, 0x60, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xa5,\n    0xec, 0xbc, 0x06, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x55,\n    0x4b, 0x2e, 0x51, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x09,\n    0x28, 0x4f, 0xdf, 0x00, 0x80, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x7b,\n    0x7d, 0x75, 0x33, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x28,\n    0x0c, 0xa9, 0xda, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xaf,\n    0x05, 0x86, 0xb2, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x3c,\n    0xb4, 0xd3, 0x90, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2d,\n    0xce, 0x96, 0x40, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xeb,\n    0xdc, 0xe4, 0xbb, 0x00, 0x80, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf6,\n    0x18, 0xa6, 0x09, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xaa,\n    0xbc, 0x2e, 0xec, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcb,\n    0xd7, 0xb9, 0xf9, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xad,\n    0x4a, 0xd5, 0xac, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x26,\n    0xef, 0xdb, 0x49, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x01,\n    0x09, 0x64, 0x5f, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xca,\n    0x5b, 0xc1, 0xe1, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x88,\n    0x9d, 0xf0, 0xf5, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x39,\n    0x38, 0x4d, 0x91, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x2e,\n    0x37, 0x76, 0xef, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc0,\n    0x58, 0x02, 0xbe, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x6f,\n    0x5e, 0xca, 0x74, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xca,\n    0x55, 0x88, 0x04, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x66,\n    0x2f, 0x42, 0x4d, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xe6,\n    0xfe, 0x04, 0x07, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x74,\n    0x1c, 0xee, 0x89, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x10,\n    0x36, 0xdd, 0x89, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x33,\n    0xff, 0x58, 0xab, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdb,\n    0x50, 0xce, 0x94, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x51,\n    0x62, 0xff, 0x02, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x43,\n    0xcc, 0x87, 0x6d, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9c,\n    0x4a, 0xc6, 0xc8, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x9e,\n    0xd1, 0xb2, 0xfc, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xf6,\n    0x3f, 0x51, 0x74, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0x42,\n    0x80, 0xf6, 0xfc, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0d,\n    0x93, 0x40, 0xad, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x67,\n    0x1e, 0x04, 0x54, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xe0,\n    0x80, 0x3f, 0x10, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd8,\n    0x06, 0x08, 0x85, 0x00, 0x00, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x02, 0x00, 0x64, 0x86, 0xff,\n    0x21, 0xd9, 0xc3, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x81,\n    0x6b, 0x51, 0x7d, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xcb,\n    0xe5, 0x9a, 0x02, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb7,\n    0x8e, 0xc6, 0xa1, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x39,\n    0xfe, 0x40, 0xf4, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x83,\n    0x7b, 0x5f, 0x2c, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x47,\n    0x3e, 0xcf, 0x67, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x94,\n    0xd0, 0x90, 0x18, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xdc,\n    0x06, 0x61, 0x43, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2f,\n    0xf9, 0xbd, 0x22, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x40,\n    0x7b, 0x19, 0x11, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x59,\n    0x02, 0x1c, 0xd4, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb4,\n    0xee, 0xfa, 0xa8, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xae,\n    0xc3, 0xe9, 0x07, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xb4,\n    0x99, 0xae, 0xcb, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x69,\n    0x3e, 0x23, 0xde, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd6,\n    0x12, 0xbd, 0xff, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x0f,\n    0x07, 0xa2, 0x42, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x04,\n    0x87, 0x2b, 0x1e, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x10,\n    0xd7, 0xbc, 0x72, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xc3,\n    0x45, 0x76, 0xf1, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x67,\n    0xbb, 0x98, 0x16, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x48,\n    0x07, 0x26, 0xe0, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd7,\n    0x9a, 0xb6, 0x76, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x8f,\n    0x8b, 0x38, 0x31, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x77,\n    0xeb, 0xc8, 0xc9, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x1e,\n    0x34, 0xfe, 0x7a, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x9f,\n    0x26, 0x96, 0x63, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xbb,\n    0x2f, 0x00, 0x72, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x82,\n    0x4c, 0xed, 0x02, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2c,\n    0xfa, 0x90, 0x2f, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x25,\n    0xd1, 0x90, 0x5d, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x44,\n    0xad, 0x58, 0x20, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0xd9,\n    0x84, 0x55, 0x0c, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x54,\n    0xf3, 0xec, 0xb1, 0x00, 0x90, 0x45, 0x01, 0x6a,\n    0x04, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x66,\n    0x92, 0x63, 0x5e, 0x00, 0x10, 0x45, 0x01, 0xb0,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x4f,\n    0xee, 0x4f, 0xab, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x2d,\n    0xf4, 0x1c, 0x5c, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xb0,\n    0x13, 0xdf, 0xf1, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x39,\n    0xb8, 0x1d, 0x43, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x75,\n    0xd0, 0x62, 0xe8, 0x00, 0x10, 0x45, 0x01, 0x24,\n    0x04, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0xc2,\n    0xf6, 0x62, 0x68, 0x00, 0x90, 0x45, 0x01, 0xde,\n    0x03, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x11,\n    0x2d, 0x76, 0x75, 0x00, 0x90, 0x45, 0x01, 0xf6,\n    0x04, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x8e,\n    0xf4, 0xa1, 0xad, 0x00, 0x10, 0x45, 0x01, 0x3c,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0x86, 0x2b,\n    0xfa, 0xb1, 0xa1, 0x00, 0x90, 0x45, 0x01, 0xf6,\n    0x04, 0x00, 0x00, 0x01, 0x00, 0x64, 0x86, 0x99,\n    0xcc, 0x42, 0x40, 0x00, 0x10, 0x45, 0x01, 0x3c,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x03,\n    0xa1, 0xcd, 0x59, 0x00, 0xc0, 0x8c, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x76,\n    0x52, 0xdc, 0x59, 0x00, 0xb0, 0x8c, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2a,\n    0x00, 0xf0, 0x59, 0x00, 0xb0, 0x8c, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfc,\n    0xb7, 0x29, 0x5a, 0x00, 0xb0, 0x8c, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x93,\n    0x16, 0x4a, 0x5a, 0x00, 0x00, 0x8a, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x79,\n    0x73, 0x7e, 0x5a, 0x00, 0xf0, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x21,\n    0x8f, 0x97, 0x5a, 0x00, 0xe0, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9a,\n    0x4f, 0xa7, 0x5a, 0x00, 0xe0, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3e,\n    0xad, 0xbd, 0x5a, 0x00, 0xd0, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x69,\n    0x10, 0x1a, 0x5b, 0x00, 0xa0, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd6,\n    0xe6, 0x35, 0x5b, 0x00, 0x90, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x34,\n    0x49, 0x48, 0x5b, 0x00, 0x90, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0f,\n    0x9e, 0x4e, 0x5b, 0x00, 0x90, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x34,\n    0x1b, 0x69, 0x5b, 0x00, 0x60, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xef,\n    0xbf, 0x6b, 0x5b, 0x00, 0x60, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd0,\n    0xcd, 0x84, 0x5b, 0x00, 0x60, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x21,\n    0x74, 0x9c, 0x5b, 0x00, 0x60, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x14,\n    0x0f, 0xa7, 0x5b, 0x00, 0x60, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x87,\n    0xad, 0xa9, 0x5b, 0x00, 0x60, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xde,\n    0x74, 0xbd, 0x5b, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x14,\n    0xdb, 0xd7, 0x5b, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd7,\n    0x70, 0xe2, 0x5b, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0x0b, 0x06, 0x5c, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0x05, 0x2b, 0x5c, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2f,\n    0x52, 0x30, 0x5c, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x59,\n    0x55, 0x5a, 0x5c, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xef,\n    0x9b, 0x68, 0x5c, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbd,\n    0x65, 0x7f, 0x5c, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x65,\n    0xee, 0x89, 0x5c, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4d,\n    0xe5, 0xa2, 0x5c, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x07,\n    0x34, 0xa8, 0x5c, 0x00, 0x20, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x49,\n    0xd9, 0xcb, 0x5c, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd5,\n    0x0a, 0xe6, 0x5c, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xda,\n    0xd6, 0x01, 0x5d, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xce,\n    0x05, 0x24, 0x5d, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x03,\n    0x84, 0x4a, 0x5d, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4f,\n    0xac, 0x4b, 0x5d, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x76,\n    0x47, 0x6f, 0x5d, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7b,\n    0x22, 0x7b, 0x5d, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf0,\n    0x2b, 0x94, 0x5d, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xff,\n    0x2c, 0x94, 0x5d, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x27,\n    0xc5, 0xf1, 0x5d, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc0,\n    0x2d, 0x29, 0x5e, 0x00, 0x30, 0x89, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x12,\n    0xbe, 0x61, 0x5e, 0x00, 0xb0, 0x88, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xac,\n    0xcf, 0x7a, 0x5e, 0x00, 0xb0, 0x88, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1b,\n    0xa7, 0xe4, 0x5e, 0x00, 0xa0, 0x88, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x86,\n    0x6d, 0x05, 0x5f, 0x00, 0xb0, 0x88, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa5,\n    0x3f, 0x2b, 0x5f, 0x00, 0xc0, 0x88, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd3,\n    0x25, 0x4f, 0x5f, 0x00, 0xa0, 0x88, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x25,\n    0x26, 0x74, 0x5f, 0x00, 0xa0, 0x88, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x34,\n    0x8d, 0xcd, 0x5a, 0x00, 0x50, 0x91, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4d,\n    0xf4, 0xe3, 0x5a, 0x00, 0x50, 0x91, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa3,\n    0x59, 0x01, 0x5b, 0x00, 0x60, 0x91, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfe,\n    0x56, 0x6e, 0x70, 0x00, 0x10, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x60,\n    0x45, 0x1a, 0x5b, 0x00, 0x10, 0x91, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xc1,\n    0x45, 0xcd, 0xb5, 0x00, 0x10, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x78,\n    0x45, 0x23, 0x5b, 0x00, 0x20, 0x91, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x13,\n    0x14, 0x3f, 0x5b, 0x00, 0x20, 0x91, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x84,\n    0x23, 0x48, 0x5b, 0x00, 0x20, 0x91, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x70,\n    0x74, 0x49, 0x5b, 0x00, 0x20, 0x91, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x02,\n    0xc9, 0x63, 0x5b, 0x00, 0xd0, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x3a,\n    0x67, 0x60, 0xdc, 0x00, 0x10, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x88,\n    0xc3, 0x6b, 0x5b, 0x00, 0xd0, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x94,\n    0xb3, 0x88, 0x5b, 0x00, 0xf0, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x39,\n    0xc7, 0xf2, 0x5f, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x46,\n    0x6e, 0x9c, 0x5b, 0x00, 0xf0, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8a,\n    0x68, 0xa4, 0x5b, 0x00, 0xd0, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x27,\n    0x2f, 0xa3, 0x5b, 0x00, 0xe0, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x7a,\n    0x8c, 0xbb, 0xff, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb1,\n    0x25, 0xcc, 0x5b, 0x00, 0xe0, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0c,\n    0x8c, 0xda, 0x5b, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x42,\n    0xf4, 0xe4, 0x5b, 0x00, 0x80, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x79,\n    0x74, 0x0b, 0x5c, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x3d,\n    0xcd, 0x2f, 0xfd, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6f,\n    0x69, 0x2d, 0x5c, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x76,\n    0xf3, 0xb9, 0x03, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7c,\n    0x88, 0x35, 0x5c, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x26,\n    0x42, 0x5a, 0x5c, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x07,\n    0xbc, 0x67, 0x5c, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd4,\n    0x6d, 0x7f, 0x5c, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x57,\n    0xdf, 0x64, 0x1f, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7a,\n    0x10, 0x8a, 0x5c, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xbe,\n    0x75, 0xb6, 0x36, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9f,\n    0xe8, 0xa2, 0x5c, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xdc,\n    0x31, 0x5e, 0xfe, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x52,\n    0x54, 0xb9, 0x5c, 0x00, 0x90, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2f,\n    0x4a, 0xde, 0x5c, 0x00, 0x70, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcd,\n    0xe7, 0x01, 0x5d, 0x00, 0x70, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd1,\n    0x00, 0x24, 0x5d, 0x00, 0x70, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xf0,\n    0x3e, 0xdf, 0xf9, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd8,\n    0xb9, 0x53, 0x5d, 0x00, 0x70, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xbf,\n    0xc1, 0x2a, 0xe4, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe1,\n    0x42, 0x6f, 0x5d, 0x00, 0x50, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2a,\n    0x19, 0x7b, 0x5d, 0x00, 0x40, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x6c,\n    0x16, 0xf3, 0xc1, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x34,\n    0x28, 0x94, 0x5d, 0x00, 0x40, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe6,\n    0x25, 0x94, 0x5d, 0x00, 0x40, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x80,\n    0xc9, 0xc4, 0x5d, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xcc,\n    0xe4, 0x99, 0xb9, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc5,\n    0x4f, 0xdf, 0x5d, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x82,\n    0xfd, 0x13, 0x5e, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe3,\n    0x69, 0x3a, 0x5e, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x35,\n    0x5e, 0x4f, 0x5e, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x41,\n    0x0d, 0xd4, 0x47, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x13,\n    0x52, 0x5f, 0x5e, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc5,\n    0xae, 0x7c, 0x5e, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x90,\n    0xfe, 0x8b, 0x5e, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa4,\n    0x20, 0x23, 0x8a, 0x00, 0x20, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe1,\n    0x96, 0xe4, 0x5e, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x98,\n    0x4e, 0x2a, 0x5f, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x20,\n    0x24, 0x4f, 0x5f, 0x00, 0x20, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x14,\n    0x49, 0x75, 0x5f, 0x00, 0x00, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa2,\n    0x99, 0x97, 0x5f, 0x00, 0x00, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x46,\n    0x33, 0xc8, 0x5f, 0x00, 0x00, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8d,\n    0xc0, 0xf6, 0x5f, 0x00, 0x00, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x06,\n    0x46, 0x12, 0x60, 0x00, 0x00, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x29,\n    0x70, 0x3d, 0x60, 0x00, 0x00, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9e,\n    0xc4, 0x49, 0x60, 0x00, 0x00, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xdb,\n    0x9f, 0x50, 0x60, 0x00, 0x00, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x80,\n    0xb5, 0x6e, 0x60, 0x00, 0x00, 0x8f, 0x00, 0x82,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfb,\n    0x38, 0x9b, 0xf8, 0x00, 0x00, 0x9a, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x93,\n    0xe5, 0x00, 0xee, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc8,\n    0x6d, 0xb3, 0x47, 0x00, 0x00, 0x9a, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x8a,\n    0xa0, 0xe0, 0x65, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7b,\n    0x59, 0xc7, 0x64, 0x00, 0x00, 0x9a, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xaf,\n    0x38, 0xdf, 0x30, 0x00, 0x00, 0x9a, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x22,\n    0x88, 0xd4, 0x5a, 0x00, 0xf0, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x89,\n    0xbf, 0xf2, 0xed, 0x00, 0xf0, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfa,\n    0x69, 0xde, 0xe3, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x98,\n    0xfc, 0xe6, 0x0d, 0x00, 0xf0, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9b,\n    0xf7, 0xd3, 0x52, 0x00, 0xf0, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x54,\n    0xa8, 0x5b, 0xd4, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfe,\n    0xe1, 0x15, 0x22, 0x00, 0xa0, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xac,\n    0x05, 0x41, 0xc1, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x30,\n    0x78, 0x05, 0xfe, 0x00, 0xa0, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd2,\n    0x95, 0x0f, 0x89, 0x00, 0xa0, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xbc,\n    0xe6, 0xd2, 0x7b, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd5,\n    0x4d, 0x13, 0x22, 0x00, 0xa0, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfa,\n    0xb6, 0xa9, 0x15, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xca,\n    0x48, 0xd2, 0x91, 0x00, 0x90, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x3e,\n    0xba, 0xcb, 0xaf, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb0,\n    0x9b, 0x16, 0xa6, 0x00, 0x90, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x54,\n    0x26, 0xcd, 0x20, 0x00, 0x90, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb4,\n    0x51, 0x82, 0x9b, 0x00, 0x90, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x39,\n    0xe3, 0xff, 0xbf, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9a,\n    0xe8, 0xfc, 0x04, 0x00, 0x80, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0f,\n    0xbe, 0x0a, 0xac, 0x00, 0x80, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9f,\n    0x5f, 0xa4, 0x83, 0x00, 0x80, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xf1,\n    0x9c, 0x44, 0xab, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xaf,\n    0x95, 0x55, 0x7e, 0x00, 0x80, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xab,\n    0x12, 0xdc, 0x73, 0x00, 0x80, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x42,\n    0x49, 0x11, 0xc6, 0x00, 0x80, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xf1,\n    0x25, 0x2c, 0x76, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0a,\n    0x83, 0x21, 0x12, 0x00, 0x80, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x79,\n    0x53, 0xfe, 0xa7, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1c,\n    0x9b, 0xe6, 0xbd, 0x00, 0x70, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x77,\n    0xd7, 0x67, 0xbb, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3d,\n    0x33, 0xa6, 0xc2, 0x00, 0x80, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x47,\n    0x68, 0x54, 0xd8, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf4,\n    0x6e, 0x03, 0xb0, 0x00, 0x90, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x58,\n    0x5d, 0x5b, 0x0f, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x61,\n    0x71, 0x86, 0x0c, 0x00, 0x70, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbd,\n    0xf3, 0xf5, 0x35, 0x00, 0x60, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb3,\n    0x95, 0x6d, 0x4c, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x13,\n    0xdc, 0x51, 0x8e, 0x00, 0x60, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x97,\n    0xe5, 0x45, 0x3b, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5c,\n    0x73, 0xdf, 0xdb, 0x00, 0x60, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xaa,\n    0xcd, 0xa1, 0xde, 0x00, 0x60, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd8,\n    0x29, 0x59, 0x00, 0x00, 0x60, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x92,\n    0x02, 0xa8, 0x39, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0xf5, 0x66, 0x68, 0x00, 0x60, 0xa1, 0x00, 0xc8,\n    0x05, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x44,\n    0x9a, 0xc1, 0x59, 0x00, 0x70, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb6,\n    0x4d, 0x69, 0x9f, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0x22, 0x1f, 0x4d, 0x00, 0x70, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x22,\n    0xed, 0x7a, 0x0a, 0x00, 0x70, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa3,\n    0x79, 0xb4, 0xa0, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7d,\n    0x02, 0x1d, 0x6d, 0x00, 0x70, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1c,\n    0x5a, 0x8b, 0x35, 0x00, 0x70, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xca,\n    0x86, 0x3a, 0xd1, 0x00, 0x70, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb2,\n    0x8a, 0xd3, 0x9c, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb0,\n    0x3e, 0xf6, 0x3f, 0x00, 0x70, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x77,\n    0x03, 0x97, 0x1f, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe6,\n    0x0b, 0x0c, 0x14, 0x00, 0x60, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x95,\n    0x3b, 0xc0, 0xa0, 0x00, 0x60, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x71,\n    0xcb, 0x11, 0x47, 0x00, 0x60, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa9,\n    0x56, 0xbc, 0xac, 0x00, 0x60, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x04,\n    0x6e, 0xb2, 0x83, 0x00, 0x60, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x93,\n    0x32, 0x00, 0x35, 0x00, 0x50, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x32,\n    0x45, 0x4a, 0x7b, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4b,\n    0x2a, 0x3a, 0x0a, 0x00, 0x50, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xed,\n    0xe7, 0x63, 0x4a, 0x00, 0x50, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x23,\n    0x0b, 0xe1, 0xba, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x84,\n    0xa6, 0xfe, 0x5f, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa1,\n    0xf0, 0xec, 0xca, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7d,\n    0xd6, 0x22, 0x37, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf8,\n    0x20, 0x41, 0x9a, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4d,\n    0x35, 0xc8, 0x66, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x32,\n    0xfb, 0x8f, 0x9e, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7a,\n    0x0c, 0xb8, 0x2a, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfe,\n    0xe0, 0x47, 0xae, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2a,\n    0x53, 0x55, 0x58, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xba,\n    0x96, 0xde, 0xaf, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xae,\n    0x14, 0xcc, 0x82, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x24,\n    0x66, 0x72, 0xb7, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xaf,\n    0x44, 0x5a, 0xf8, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xae,\n    0xcc, 0x27, 0xcc, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc0,\n    0x1c, 0xb2, 0x96, 0x00, 0x40, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x75,\n    0x9e, 0x18, 0xef, 0x00, 0x50, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0x9a, 0xd1, 0x31, 0x00, 0x50, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x00,\n    0x7d, 0x7a, 0x34, 0x00, 0x20, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcf,\n    0x55, 0x65, 0xd8, 0x00, 0x20, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x90,\n    0xf9, 0x1d, 0x2c, 0x00, 0x20, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xee,\n    0xef, 0x80, 0x24, 0x00, 0x20, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x37,\n    0xbf, 0x91, 0xce, 0x00, 0x20, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa1,\n    0x44, 0x83, 0x53, 0x00, 0x20, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x9b,\n    0x46, 0xaf, 0x01, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfa,\n    0x17, 0xeb, 0x6b, 0x00, 0x20, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0xec, 0xf6, 0x0b, 0x00, 0x20, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x34,\n    0xd1, 0xd6, 0xa7, 0x00, 0x10, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbc,\n    0x97, 0xbe, 0x3e, 0x00, 0x10, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd9,\n    0x31, 0x9d, 0x5b, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbf,\n    0xda, 0x3e, 0x7b, 0x00, 0x10, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x12,\n    0x32, 0xe6, 0xd2, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x50,\n    0x46, 0x6d, 0xb8, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x68,\n    0x3f, 0x8e, 0xa9, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa9,\n    0x18, 0x85, 0x5e, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1b,\n    0xf0, 0x94, 0x16, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x32,\n    0xbc, 0x05, 0x3d, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1d,\n    0x74, 0xd9, 0x68, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9e,\n    0x39, 0x76, 0x3c, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x16,\n    0xc9, 0x1e, 0x6f, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3e,\n    0xa8, 0x19, 0x50, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe4,\n    0x5b, 0x7a, 0xed, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0xfa, 0xa6, 0x42, 0x00, 0xf0, 0xa0, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1c,\n    0xfc, 0xec, 0x8f, 0x00, 0x00, 0xa1, 0x00, 0x0e,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3c,\n    0xb1, 0x85, 0x58, 0x00, 0xf0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0xe1, 0x28, 0xc3, 0x00, 0xf0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x14,\n    0x2c, 0xa4, 0x2a, 0x00, 0xf0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfd,\n    0xf5, 0x23, 0x22, 0x00, 0xe0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x98,\n    0x27, 0xa4, 0x77, 0x00, 0xe0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x52,\n    0xda, 0xeb, 0xb6, 0x00, 0xe0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2d,\n    0x6a, 0xca, 0x6a, 0x00, 0xf0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x6b,\n    0x71, 0x3d, 0xc0, 0x00, 0x00, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4e,\n    0x36, 0x83, 0xb7, 0x00, 0xf0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x92,\n    0xb3, 0x09, 0x83, 0x00, 0xd0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0x41, 0x48, 0x30, 0x00, 0xe0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x66,\n    0xf2, 0xb2, 0x08, 0x00, 0xe0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xaf,\n    0x06, 0x12, 0x3b, 0x00, 0xd0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x54,\n    0x8c, 0x99, 0xff, 0x00, 0xd0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x33,\n    0x92, 0xd8, 0xa7, 0x00, 0xd0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x21,\n    0xd0, 0xdd, 0xd2, 0x00, 0xd0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8b,\n    0x82, 0xac, 0x36, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc9,\n    0x77, 0x10, 0x4c, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x52,\n    0x30, 0x0a, 0x4b, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5c,\n    0x4a, 0x52, 0x1f, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x74,\n    0x83, 0x37, 0x8e, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x70,\n    0x12, 0x32, 0x12, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd2,\n    0xc5, 0xdd, 0x2a, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x24,\n    0xf9, 0x25, 0xc6, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf7,\n    0x4f, 0x97, 0xad, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf2,\n    0x52, 0xd0, 0x43, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfc,\n    0xec, 0xb6, 0x0a, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0d,\n    0xca, 0xc6, 0x74, 0x00, 0xb0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3f,\n    0x90, 0x38, 0x05, 0x00, 0xc0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8e,\n    0xee, 0x7c, 0x84, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x87,\n    0xb7, 0x1c, 0xdd, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x38,\n    0x69, 0xab, 0x3f, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd0,\n    0xf5, 0x56, 0xb0, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0x44, 0xf7, 0x7e, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb1,\n    0x24, 0xfc, 0x07, 0x00, 0x90, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x29,\n    0xa2, 0xdc, 0x3c, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4a,\n    0x6b, 0x56, 0xc5, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0a,\n    0xca, 0xce, 0xad, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc2,\n    0xde, 0x0a, 0xec, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x86,\n    0x82, 0xc3, 0xeb, 0x00, 0xa0, 0xa0, 0x00, 0x54,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x4b,\n    0x89, 0xbc, 0x7c, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc7,\n    0x14, 0xc3, 0xcb, 0x00, 0xa0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xdd,\n    0x1e, 0x53, 0x94, 0x00, 0xa0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x57,\n    0xa8, 0x77, 0xae, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x70,\n    0x6a, 0xdc, 0x71, 0x00, 0xa0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd7,\n    0x51, 0x8f, 0x61, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x71,\n    0x55, 0x11, 0x7e, 0x00, 0xa0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x22,\n    0x10, 0x9d, 0xbd, 0x00, 0xd0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x51,\n    0x6d, 0x8e, 0x91, 0x00, 0xd0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x09,\n    0xf9, 0xc4, 0xd0, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3d,\n    0xb3, 0xd5, 0x17, 0x00, 0xd0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa3,\n    0x93, 0xf7, 0x54, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcf,\n    0x79, 0x19, 0x5b, 0x00, 0xd0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x67,\n    0xe2, 0x3e, 0xa7, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8c,\n    0xef, 0x83, 0xc1, 0x00, 0xd0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0x11, 0xd5, 0x15, 0x00, 0xe0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xdb,\n    0xa4, 0x06, 0x3f, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x01,\n    0x5a, 0xb1, 0x87, 0x00, 0xe0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x52,\n    0x05, 0xd7, 0xa8, 0x00, 0xf0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x27,\n    0xfa, 0xce, 0xb3, 0x00, 0xf0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x27,\n    0x10, 0x42, 0x01, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x99,\n    0x47, 0x3f, 0x47, 0x00, 0xf0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa2,\n    0xa7, 0x21, 0xd9, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x12,\n    0x86, 0xac, 0x0d, 0x00, 0xf0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xc5,\n    0xbe, 0xb3, 0xb1, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9d,\n    0xc0, 0x91, 0x0a, 0x00, 0xf0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfb,\n    0xf5, 0xd2, 0x1b, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x74,\n    0x25, 0x34, 0x05, 0x00, 0xf0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x49,\n    0x42, 0x3a, 0xf0, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xed,\n    0x32, 0xff, 0xb6, 0x00, 0xf0, 0x99, 0x00, 0x9a,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0xd3, 0xcd, 0x0c, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x92,\n    0x6e, 0x9d, 0x71, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6f,\n    0x21, 0x13, 0x5a, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8e,\n    0x6f, 0x07, 0xe5, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xad,\n    0xc8, 0x3d, 0x46, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe2,\n    0x05, 0x17, 0xea, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe7,\n    0xe1, 0x21, 0x40, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xc9,\n    0x8a, 0x2e, 0x18, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd2,\n    0x72, 0x03, 0xb8, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc9,\n    0x64, 0xd3, 0x64, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xaf,\n    0xad, 0x96, 0xc1, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xdf,\n    0xac, 0x8a, 0x5f, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x13,\n    0x6b, 0x7e, 0x24, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xac,\n    0x8c, 0x50, 0x1f, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1e,\n    0x8b, 0x1d, 0xf5, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x8d,\n    0xe8, 0x02, 0xf7, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x06,\n    0x3e, 0xab, 0xfb, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x6f,\n    0xd5, 0xdf, 0xc0, 0x00, 0x30, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x80,\n    0x95, 0x2f, 0x9f, 0x00, 0x00, 0x9a, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbf,\n    0x8e, 0x73, 0xad, 0x00, 0xe0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa8,\n    0x50, 0x2d, 0xf1, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xed,\n    0x0a, 0xbe, 0x1b, 0x00, 0xe0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x94,\n    0x94, 0x15, 0x18, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x64,\n    0x99, 0x12, 0xe2, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x1c,\n    0xad, 0xce, 0x07, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd3,\n    0x71, 0x38, 0xb9, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x39,\n    0x22, 0x86, 0x86, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8c,\n    0x90, 0xb1, 0x44, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x38,\n    0x6f, 0xdd, 0x4a, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x00,\n    0xc8, 0x5c, 0x4b, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xaa,\n    0xcb, 0x3a, 0x52, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3b,\n    0x53, 0x53, 0x5f, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8a,\n    0x80, 0x7a, 0x19, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x43,\n    0xd9, 0x24, 0xee, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6e,\n    0xec, 0x4e, 0xcd, 0x00, 0xe0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1b,\n    0x32, 0xbd, 0x68, 0x00, 0xe0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x59,\n    0x6d, 0x73, 0x4a, 0x00, 0xe0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc5,\n    0x87, 0x6b, 0x8c, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9b,\n    0x41, 0x26, 0x71, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9c,\n    0xfa, 0x9a, 0xae, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x42,\n    0xbf, 0xd7, 0xe4, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb2,\n    0x74, 0xfb, 0xc7, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8b,\n    0xd7, 0xe9, 0x57, 0x00, 0xe0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xec,\n    0x74, 0x79, 0x2e, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb1,\n    0x35, 0x79, 0x05, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x94,\n    0xed, 0x4f, 0xe6, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x36,\n    0x58, 0x09, 0xfa, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x63,\n    0x3e, 0x0a, 0x33, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0x91, 0x31, 0xd6, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x56,\n    0xa6, 0x39, 0x65, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x73,\n    0xc2, 0x06, 0xff, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xab,\n    0x8e, 0xb0, 0x56, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3e,\n    0x43, 0xaa, 0x92, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x43,\n    0x75, 0x7f, 0x2e, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x01,\n    0x41, 0x33, 0xe6, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd8,\n    0x01, 0x02, 0x5f, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x45,\n    0x69, 0xc7, 0xe1, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb4,\n    0x7d, 0xf2, 0xf7, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe7,\n    0xed, 0x77, 0x33, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x49,\n    0x3b, 0x0d, 0xba, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x57,\n    0x3d, 0xd3, 0x70, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4e,\n    0x9a, 0xde, 0xe4, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x79,\n    0xd4, 0xb7, 0x1a, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x29,\n    0x57, 0x8a, 0x17, 0x00, 0xf0, 0x99, 0x00, 0xe0,\n    0x06, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd2,\n    0x4a, 0xc7, 0x8b, 0x00, 0xf0, 0x99, 0x00, 0x26,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe1,\n    0xfd, 0xb3, 0x3b, 0x00, 0xf0, 0x99, 0x00, 0x26,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4a,\n    0x4e, 0xcb, 0x12, 0x00, 0xe0, 0x99, 0x00, 0x26,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x34,\n    0x33, 0x27, 0xdc, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x37,\n    0xd1, 0x84, 0x0a, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x33,\n    0xf1, 0x44, 0x1e, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0xb3, 0xe9, 0x93, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x29,\n    0x53, 0xaf, 0x77, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8a,\n    0x50, 0xcb, 0x4c, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0x78, 0x00, 0xe8, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x7d,\n    0x1a, 0xcb, 0x02, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe3,\n    0xd1, 0xbd, 0x45, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1c,\n    0x77, 0x22, 0xfc, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xdd,\n    0xa0, 0x7c, 0xaf, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa5,\n    0xfb, 0xc7, 0x61, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1d,\n    0x61, 0x92, 0x5d, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe9,\n    0x14, 0x9d, 0x15, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x97,\n    0xdb, 0x73, 0xf4, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x54,\n    0x81, 0xb4, 0x02, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa8,\n    0x12, 0x12, 0x95, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x81,\n    0xb4, 0x2a, 0x3f, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x73,\n    0xe8, 0x8e, 0xcc, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x0b,\n    0xc6, 0x7f, 0xcf, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1a,\n    0xaa, 0xb5, 0xbc, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2a,\n    0xd3, 0x38, 0xe1, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x09,\n    0x77, 0x91, 0x5b, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5e,\n    0x5f, 0x51, 0xf8, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6b,\n    0xb5, 0xd2, 0x9f, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xab,\n    0xeb, 0x77, 0x64, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x00,\n    0x79, 0x36, 0xf3, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa9,\n    0x3b, 0x51, 0x5e, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xde,\n    0x0a, 0x89, 0x50, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0e,\n    0x17, 0x6b, 0x8f, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x89,\n    0x9b, 0x7d, 0x6d, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8e,\n    0x66, 0xcf, 0xe2, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x93,\n    0x46, 0xd3, 0x8c, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcb,\n    0x3e, 0x3e, 0x70, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe5,\n    0x31, 0x36, 0xd5, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x26,\n    0xad, 0xaa, 0x55, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x69,\n    0x8e, 0x32, 0xd3, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb9,\n    0xa6, 0xd4, 0x30, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x0a,\n    0xef, 0x3a, 0xbe, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa8,\n    0xe8, 0x41, 0xf6, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1f,\n    0xb2, 0xb2, 0x94, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0b,\n    0x5c, 0x6c, 0xd4, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x77,\n    0x8e, 0x26, 0x97, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfe,\n    0x75, 0x84, 0x9c, 0x00, 0x10, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5b,\n    0x61, 0x49, 0xb4, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9a,\n    0x19, 0x3d, 0x6a, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd1,\n    0xfe, 0x99, 0x92, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfb,\n    0xdf, 0xbf, 0x72, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x9d,\n    0xcf, 0xde, 0xa2, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3c,\n    0x0b, 0xea, 0xc7, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd4,\n    0xaa, 0x10, 0x14, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd2,\n    0xe7, 0xed, 0xcf, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd2,\n    0xa7, 0x99, 0xd6, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x04,\n    0x03, 0x19, 0x0f, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9e,\n    0xb7, 0xd7, 0x1d, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc9,\n    0xa2, 0xc4, 0x5b, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa9,\n    0x3e, 0xf1, 0xb6, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb9,\n    0x5b, 0x38, 0x41, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf0,\n    0x8d, 0xfe, 0x32, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x1e,\n    0x1c, 0x81, 0x03, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x42,\n    0x16, 0xe9, 0x0f, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x12,\n    0xfd, 0x89, 0x76, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x44,\n    0xfe, 0xa0, 0x2b, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6e,\n    0xb1, 0xfe, 0xb7, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf2,\n    0xf3, 0x1e, 0x8b, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6a,\n    0xfd, 0x68, 0xd6, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcd,\n    0x76, 0xb8, 0x59, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa1,\n    0xe2, 0x8e, 0xd2, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcf,\n    0x85, 0xa2, 0xe9, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x78,\n    0x76, 0xff, 0x84, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3b,\n    0xd2, 0x0a, 0x88, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfb,\n    0x7b, 0x06, 0xde, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb6,\n    0x60, 0x44, 0x72, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd3,\n    0xf3, 0xe0, 0xda, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x76,\n    0x30, 0xf5, 0xbd, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x1a,\n    0x33, 0x6a, 0x6f, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x46,\n    0xdb, 0x79, 0x67, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd6,\n    0x65, 0x7e, 0x12, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x99,\n    0x04, 0xea, 0x24, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc2,\n    0x50, 0x2f, 0x6f, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf4,\n    0x9c, 0x44, 0x6e, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x98,\n    0x90, 0x6c, 0x8b, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xed,\n    0xc8, 0x2d, 0xb1, 0x00, 0x40, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc3,\n    0x0a, 0x48, 0xe9, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x43,\n    0x23, 0x2d, 0x38, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5d,\n    0x99, 0x43, 0xfd, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x7f,\n    0xef, 0xf3, 0x40, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x34,\n    0x28, 0xb0, 0x6b, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xae,\n    0xd2, 0xcf, 0x3c, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x78,\n    0x14, 0x82, 0xad, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb6,\n    0x47, 0x72, 0xd6, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcb,\n    0xe1, 0xfc, 0x5b, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x63,\n    0x45, 0xfd, 0x6b, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2c,\n    0x1a, 0x60, 0x0e, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x94,\n    0x9e, 0x27, 0x8b, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xeb,\n    0xa1, 0xb3, 0xa6, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x46,\n    0x19, 0x96, 0xaf, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc3,\n    0x06, 0x84, 0xeb, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0d,\n    0x59, 0x4f, 0xd2, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5b,\n    0x9b, 0xe8, 0x22, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x22,\n    0xe8, 0x73, 0x97, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3e,\n    0xc8, 0x7c, 0xad, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x72,\n    0x89, 0x62, 0x05, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0x4b, 0xa7, 0x2d, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd0,\n    0x33, 0xc6, 0x32, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x90,\n    0xdc, 0x14, 0x36, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x75,\n    0x65, 0xef, 0x38, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xde,\n    0xa1, 0x01, 0x7f, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xab,\n    0x12, 0x1c, 0x72, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x50,\n    0xc0, 0x46, 0x4e, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xcb,\n    0x5d, 0xa0, 0xed, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x28,\n    0xae, 0x33, 0xf4, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa0,\n    0x3f, 0xa4, 0x32, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xff,\n    0xa2, 0x74, 0xd7, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x82,\n    0xbc, 0x84, 0xda, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x22,\n    0x1c, 0xdd, 0xb5, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x3d,\n    0x94, 0xe6, 0x54, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9b,\n    0xd5, 0x0a, 0xe4, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfe,\n    0xdd, 0x0e, 0x20, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe1,\n    0x5d, 0x0e, 0x36, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x2e,\n    0xd4, 0xb6, 0x0c, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x98,\n    0xef, 0xa6, 0x32, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd9,\n    0x85, 0x5c, 0x17, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe3,\n    0xd3, 0x04, 0xbb, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa5,\n    0x59, 0x8e, 0x3a, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc0,\n    0xc7, 0x9f, 0xf5, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x5a,\n    0x3b, 0xea, 0x97, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x39,\n    0xb6, 0x59, 0x56, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x18,\n    0xf8, 0x0d, 0xb5, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf0,\n    0x2e, 0x10, 0xc0, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe8,\n    0xc8, 0xd0, 0xaf, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xae,\n    0x7d, 0x96, 0x42, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x97,\n    0xa4, 0x52, 0x2d, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf2,\n    0x26, 0x20, 0x42, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe8,\n    0xf1, 0x9a, 0x3f, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x63,\n    0xc0, 0xdc, 0x43, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xbf,\n    0x6c, 0x31, 0xb6, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xda,\n    0xf7, 0x89, 0x01, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x4a,\n    0xcc, 0x19, 0x21, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8b,\n    0x1e, 0x60, 0x3b, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xca,\n    0xf9, 0x1c, 0x1d, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x9e,\n    0x2d, 0xbd, 0x77, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5b,\n    0xe4, 0xa3, 0x76, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x69,\n    0xe0, 0x9d, 0xe3, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x48,\n    0xee, 0x53, 0x1d, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x79,\n    0xd9, 0x6a, 0x82, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1c,\n    0x33, 0xe3, 0xf6, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe9,\n    0x45, 0x50, 0xfe, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1d,\n    0x8e, 0x90, 0xe5, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfb,\n    0x34, 0xc0, 0x23, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9a,\n    0xb3, 0xe3, 0xb8, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x5f,\n    0x4f, 0xc0, 0x28, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0xfb, 0xc9, 0x31, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x45,\n    0xab, 0x14, 0x28, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x30,\n    0x5e, 0x5d, 0xa3, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xdf,\n    0x8c, 0xc0, 0x56, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb8,\n    0x56, 0xb0, 0x24, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xf1,\n    0x5e, 0x3e, 0x58, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0xc1, 0x87, 0x82, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x43,\n    0x97, 0xf0, 0xd5, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x8a,\n    0xda, 0x2f, 0xe1, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x86,\n    0x25, 0x97, 0x63, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa4,\n    0x02, 0xf8, 0x59, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x95,\n    0xd4, 0xc2, 0x21, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa7,\n    0x52, 0xcc, 0xe4, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x91,\n    0xce, 0x5a, 0xd3, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x57,\n    0x2b, 0x80, 0x5c, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf8,\n    0x60, 0xfe, 0x5a, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x32,\n    0x4c, 0xf3, 0xc8, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe0,\n    0x53, 0x42, 0xb5, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb1,\n    0xe0, 0xf2, 0x5b, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb4,\n    0x94, 0xc3, 0x85, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa4,\n    0x57, 0x5f, 0x0e, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x16,\n    0x7b, 0xdd, 0x10, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb5,\n    0x3e, 0x1f, 0xed, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x82,\n    0x0a, 0xd9, 0xcf, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x37,\n    0x2f, 0x29, 0xcb, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa2,\n    0xd9, 0x54, 0x00, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x37,\n    0x24, 0x41, 0x02, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x52,\n    0x3f, 0x67, 0x64, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x82,\n    0xec, 0xea, 0xcd, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa1,\n    0x35, 0x59, 0xb9, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x96,\n    0x98, 0xaa, 0x99, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x85,\n    0xa8, 0x9e, 0x3d, 0x00, 0x50, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbd,\n    0x73, 0xb5, 0x65, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4d,\n    0xbd, 0x73, 0x15, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xea,\n    0x70, 0x1a, 0x6e, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9b,\n    0xec, 0x73, 0x3e, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd4,\n    0x4c, 0x7b, 0x51, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x69,\n    0x3c, 0x6a, 0xc3, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x47,\n    0x16, 0xd6, 0x37, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbe,\n    0xb7, 0x11, 0xde, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x43,\n    0x38, 0x59, 0xd3, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x30,\n    0xf9, 0x7c, 0x45, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x47,\n    0xae, 0xa6, 0x82, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfe,\n    0x0d, 0xda, 0xd0, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf9,\n    0xb3, 0x39, 0x4c, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x55,\n    0x12, 0x31, 0xea, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0x7a, 0x25, 0x3a, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xab,\n    0x62, 0x97, 0xfb, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb2,\n    0xe4, 0x2f, 0x34, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe7,\n    0xf6, 0x8e, 0x62, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4b,\n    0xe4, 0x67, 0x4a, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x49,\n    0x8e, 0xc6, 0xcc, 0x00, 0xd0, 0x43, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x49,\n    0xf9, 0xbf, 0x8c, 0x00, 0xe0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x41,\n    0x15, 0x6d, 0x20, 0x00, 0xe0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x56,\n    0x07, 0x4b, 0x6b, 0x00, 0xd0, 0x43, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x66,\n    0x86, 0x89, 0x40, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe1,\n    0x46, 0xf9, 0x33, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x79,\n    0x45, 0xab, 0x49, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x22,\n    0xfc, 0xf6, 0x3f, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x99,\n    0x92, 0x74, 0x67, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe0,\n    0x14, 0xe2, 0xef, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb1,\n    0x59, 0x3f, 0x8c, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xff,\n    0xce, 0x68, 0x0e, 0x00, 0xe0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x26,\n    0x10, 0xd6, 0x01, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc6,\n    0x1c, 0xf7, 0x80, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x55,\n    0x7f, 0x24, 0x4a, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xab,\n    0x44, 0x39, 0x3d, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x41,\n    0x9d, 0x6d, 0x29, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb9,\n    0x85, 0x9d, 0x12, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x29,\n    0xdc, 0xe2, 0xe6, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xba,\n    0xd0, 0x37, 0x7a, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x81,\n    0x8a, 0x82, 0x1b, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcc,\n    0xa6, 0xeb, 0xb3, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x75,\n    0x77, 0xdd, 0x4f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa2,\n    0xb6, 0x19, 0xfa, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x56,\n    0x0b, 0x75, 0xb5, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb9,\n    0xa4, 0xc2, 0x66, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xce,\n    0x5e, 0xc9, 0x0b, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6d,\n    0xed, 0x44, 0x42, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x97,\n    0x38, 0x68, 0x80, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3d,\n    0x56, 0xed, 0xbc, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd0,\n    0xbe, 0x23, 0x76, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa7,\n    0x2d, 0x0b, 0x3b, 0x00, 0xe0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3f,\n    0x90, 0x8c, 0xd2, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb8,\n    0xa7, 0x16, 0x78, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x50,\n    0x67, 0xc7, 0x1a, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf5,\n    0x01, 0x9c, 0xed, 0x00, 0xe0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5e,\n    0x16, 0x1e, 0x2d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfd,\n    0x89, 0x7e, 0xd8, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x38,\n    0xcd, 0xb6, 0x42, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x32,\n    0x71, 0x05, 0xb3, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x11,\n    0x6e, 0x90, 0xd7, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x76,\n    0x55, 0xfa, 0x8d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3a,\n    0xa3, 0xe8, 0xde, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x98,\n    0xdc, 0x0c, 0xb8, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x28,\n    0xfe, 0x00, 0xd9, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x88,\n    0xa3, 0x96, 0xe7, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe9,\n    0x6a, 0xca, 0x07, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2f,\n    0x32, 0xd7, 0x47, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x55,\n    0x18, 0xce, 0x8d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8d,\n    0x07, 0x82, 0xb6, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc7,\n    0xed, 0x4e, 0x82, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x82,\n    0xd8, 0xe6, 0x70, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc6,\n    0xc5, 0x14, 0xc0, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd8,\n    0x5b, 0x52, 0x3b, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8b,\n    0x7b, 0x3b, 0x90, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x45,\n    0x67, 0x83, 0xa4, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x31,\n    0x1e, 0x13, 0xf3, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x75,\n    0x16, 0x30, 0xfc, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb6,\n    0x87, 0xa6, 0xf8, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0xa1, 0x42, 0x10, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x20,\n    0x6b, 0x28, 0x84, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xca,\n    0x0b, 0xde, 0xdd, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x29,\n    0x2f, 0x2e, 0xba, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa6,\n    0xcc, 0xaa, 0x89, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x03,\n    0xcc, 0x4b, 0x18, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xec,\n    0x1f, 0x08, 0x86, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbb,\n    0x15, 0xbe, 0x30, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x04,\n    0x45, 0x8a, 0xd6, 0x00, 0x20, 0x11, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6f,\n    0x3e, 0x08, 0x2f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x66,\n    0x75, 0xac, 0xb5, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x33,\n    0xc9, 0xb9, 0x88, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf9,\n    0x46, 0x9a, 0x6f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf7,\n    0x07, 0x18, 0x7c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd7,\n    0x15, 0xf4, 0x76, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfe,\n    0xa6, 0x21, 0x23, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd8,\n    0x3e, 0x06, 0x7c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7b,\n    0xd1, 0x33, 0x06, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x52,\n    0xa8, 0xef, 0xb9, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x25,\n    0x44, 0x15, 0x04, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x48,\n    0x56, 0x87, 0x35, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcd,\n    0x49, 0x10, 0xcd, 0x00, 0xd0, 0x03, 0x01, 0x6c,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x79,\n    0x4c, 0x0f, 0xad, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x03,\n    0x95, 0x95, 0x86, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x16,\n    0x9a, 0xab, 0x9c, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x3d,\n    0x81, 0x1b, 0x1a, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb1,\n    0x22, 0x86, 0x46, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xda,\n    0xf7, 0xac, 0x6a, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x01,\n    0x7e, 0x79, 0x48, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xc6,\n    0x03, 0x71, 0x73, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x24,\n    0xe8, 0x7f, 0x3b, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf1,\n    0x27, 0xe5, 0x35, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3c,\n    0x6a, 0x41, 0x3d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbc,\n    0x51, 0x56, 0xb2, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8b,\n    0xd4, 0xe3, 0x8f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x7d,\n    0x27, 0xe2, 0x0e, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4b,\n    0xfd, 0xbd, 0xeb, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x70,\n    0x06, 0xc8, 0x7c, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xde,\n    0x4b, 0x71, 0x71, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x61,\n    0x7e, 0xc4, 0x64, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x38,\n    0x82, 0xcc, 0x14, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x67,\n    0xe5, 0xed, 0xad, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2c,\n    0x7f, 0x30, 0x0a, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x49,\n    0x4c, 0xfa, 0x67, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0b,\n    0x9a, 0x03, 0xb4, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0x48, 0x44, 0x43, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1c,\n    0x19, 0xc5, 0x4e, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x99,\n    0x96, 0x32, 0x00, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3e,\n    0x46, 0xf5, 0x03, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x89,\n    0xbf, 0xce, 0x85, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe6,\n    0xe7, 0x01, 0x47, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe2,\n    0xae, 0x71, 0xc2, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x74,\n    0xb6, 0xc7, 0x2c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xc0,\n    0xf2, 0x42, 0x70, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3d,\n    0x01, 0xf7, 0x74, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x55,\n    0xac, 0xcb, 0x5e, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x80,\n    0xd8, 0xf7, 0x69, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe3,\n    0xd2, 0x60, 0x10, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x9e,\n    0x72, 0x4c, 0xb6, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9a,\n    0xa5, 0xff, 0x72, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbb,\n    0x59, 0x8a, 0xab, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x65,\n    0x0f, 0x35, 0x9a, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd7,\n    0x67, 0x70, 0x1b, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x96,\n    0xb2, 0xbe, 0x1f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x98,\n    0xad, 0x44, 0xbe, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1b,\n    0x99, 0xe3, 0x20, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x47,\n    0xa3, 0x97, 0x7c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x13,\n    0xa3, 0x8c, 0x2d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x94,\n    0xeb, 0xca, 0x96, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb5,\n    0xe6, 0x33, 0xd1, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2f,\n    0x69, 0x9e, 0xfc, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd5,\n    0xd7, 0xde, 0xaf, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x87,\n    0x8c, 0xa3, 0x65, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0a,\n    0x4e, 0x8f, 0x5d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5f,\n    0xd3, 0x0e, 0x44, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb4,\n    0x36, 0x22, 0x1c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe1,\n    0xe5, 0xce, 0x24, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x5d,\n    0x9d, 0xff, 0xf1, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x30,\n    0x09, 0x48, 0x7c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x10,\n    0x4a, 0xc5, 0x20, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x45,\n    0xff, 0xc0, 0x07, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x91,\n    0xe7, 0x4d, 0x5a, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe2,\n    0x9e, 0xed, 0x16, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xca,\n    0x85, 0xb2, 0xd1, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe4,\n    0x4f, 0xb7, 0x97, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbd,\n    0xf3, 0x3a, 0x00, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6b,\n    0x93, 0xf4, 0xd2, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0xa3, 0xd8, 0x0d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x59,\n    0x91, 0x7b, 0xf9, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x50,\n    0x6b, 0x76, 0x91, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x09,\n    0x03, 0x85, 0xe0, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x82,\n    0x98, 0x15, 0x41, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xdf,\n    0x44, 0x3b, 0x70, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2d,\n    0x9c, 0x5d, 0xe2, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x0b,\n    0x4e, 0x46, 0x13, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa5,\n    0x08, 0x73, 0x02, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x03,\n    0x82, 0xb0, 0xdb, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6c,\n    0xfd, 0x77, 0xfd, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc0,\n    0x19, 0x5d, 0x83, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xc8,\n    0x79, 0xc1, 0x89, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x7a,\n    0xeb, 0xe7, 0xd0, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc5,\n    0xc2, 0x5b, 0x1c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf9,\n    0x81, 0xad, 0x14, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5d,\n    0xeb, 0x61, 0xf9, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbe,\n    0x8f, 0xf1, 0x5c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x95,\n    0xfc, 0x64, 0x6e, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xdb,\n    0x51, 0x15, 0x17, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xdc,\n    0x86, 0x2e, 0x21, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x94,\n    0x5d, 0x26, 0xb6, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x73,\n    0xbc, 0x49, 0x48, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbf,\n    0x9e, 0x88, 0xae, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x1e,\n    0xd9, 0xe4, 0x86, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x39,\n    0xcb, 0x41, 0xdd, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8c,\n    0x84, 0xd8, 0xb8, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa9,\n    0xf8, 0x08, 0x5d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa3,\n    0x21, 0xfb, 0x54, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x52,\n    0x86, 0x13, 0xb7, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x41,\n    0x04, 0x6d, 0x4d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x89,\n    0x08, 0x50, 0xaa, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x56,\n    0x11, 0x91, 0xd8, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfb,\n    0x23, 0xbd, 0x79, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x82,\n    0x93, 0xe3, 0x27, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x69,\n    0x8f, 0x9d, 0x6c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x29,\n    0x46, 0x4c, 0x17, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb4,\n    0x46, 0x4b, 0x2f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xaa,\n    0xa5, 0x0d, 0x0f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe8,\n    0xdd, 0xf4, 0xad, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x08,\n    0x04, 0x80, 0x24, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3a,\n    0x51, 0x2c, 0xa0, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x83,\n    0x60, 0x68, 0xcd, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9a,\n    0xce, 0x5a, 0x6f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe9,\n    0xb6, 0x83, 0xa6, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x54,\n    0xe9, 0xa9, 0xc9, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3e,\n    0xf8, 0x40, 0xf6, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0xd0, 0xa7, 0x82, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcb,\n    0x2b, 0x4b, 0x46, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xea,\n    0x2f, 0xea, 0x53, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x03,\n    0xc0, 0x9f, 0x43, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x52,\n    0xfb, 0xcb, 0xf9, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2c,\n    0x09, 0xe8, 0x23, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x23,\n    0x2d, 0x80, 0x38, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x66,\n    0x81, 0xf2, 0xdf, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa8,\n    0x88, 0x6e, 0xf4, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf9,\n    0x72, 0x12, 0xb2, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xf4,\n    0x55, 0xdf, 0x9a, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xee,\n    0x16, 0xba, 0xda, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x12,\n    0xba, 0x7a, 0xa5, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x36,\n    0xe7, 0x52, 0x06, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x1c,\n    0x70, 0x28, 0xb8, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf1,\n    0x9b, 0x28, 0xbc, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x98,\n    0x7b, 0x46, 0xbd, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x52,\n    0x54, 0xa2, 0xc5, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9a,\n    0x8b, 0x2f, 0x4f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x75,\n    0x8c, 0x2a, 0x81, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbc,\n    0xda, 0xde, 0x6b, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x10,\n    0xf8, 0x79, 0x42, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xc9,\n    0xcf, 0x0e, 0x77, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x35,\n    0x54, 0x29, 0x70, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x61,\n    0x75, 0x50, 0x9a, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xea,\n    0xaa, 0x63, 0x40, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x89,\n    0xf8, 0x2e, 0xd6, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x9b,\n    0x89, 0xa2, 0x18, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x87,\n    0xb4, 0x9d, 0x7d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf1,\n    0xce, 0x0b, 0xd6, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa4,\n    0x61, 0x57, 0x0c, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x85,\n    0x35, 0x80, 0xd4, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x5c,\n    0x45, 0x61, 0x0e, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xaa,\n    0xf5, 0x58, 0x01, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x79,\n    0xfe, 0x2a, 0x25, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x55,\n    0x33, 0x93, 0xd0, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd8,\n    0xe7, 0xe6, 0x70, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa4,\n    0xaa, 0xf2, 0x53, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x87,\n    0x76, 0x93, 0x43, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xce,\n    0xb3, 0xdd, 0x61, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe1,\n    0x68, 0xaa, 0x1d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd6,\n    0x62, 0x37, 0x29, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd5,\n    0x51, 0x32, 0x2d, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xff,\n    0xf4, 0xe6, 0x01, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xc1,\n    0x46, 0x5b, 0x1d, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1a,\n    0xba, 0x0b, 0xe1, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x27,\n    0x7b, 0x3a, 0xc5, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x99,\n    0x62, 0x92, 0xcb, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4e,\n    0x4c, 0x63, 0x51, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x02,\n    0x1d, 0xf2, 0x40, 0x00, 0xf0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd6,\n    0x68, 0xe2, 0x70, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2f,\n    0x41, 0x81, 0x60, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1e,\n    0x95, 0x81, 0xb7, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x21,\n    0xe2, 0xea, 0xbb, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6e,\n    0xdd, 0xb1, 0xa0, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x70,\n    0x7e, 0xab, 0xdb, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x93,\n    0xd3, 0x5f, 0xa2, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf7,\n    0x82, 0xbf, 0x0f, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x90,\n    0xe4, 0xaa, 0x37, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x16,\n    0x35, 0x0c, 0xd4, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x03,\n    0x56, 0x51, 0x69, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xdf,\n    0xd8, 0x38, 0xd1, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe3,\n    0x4a, 0x0e, 0x46, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x56,\n    0x65, 0x94, 0x33, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc6,\n    0xaf, 0x60, 0xd6, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe1,\n    0x13, 0xb1, 0x79, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x96,\n    0xa5, 0x27, 0x79, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x01,\n    0x89, 0x01, 0x48, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa7,\n    0x9a, 0x36, 0xd5, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb7,\n    0x4a, 0xd2, 0xc9, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb9,\n    0x52, 0x90, 0x3b, 0x00, 0xd0, 0x03, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xaa,\n    0xb0, 0xa4, 0xdb, 0x00, 0x00, 0x04, 0x01, 0xb2,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4f,\n    0xbd, 0x79, 0x16, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x14,\n    0x37, 0x6c, 0xfa, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x76,\n    0x21, 0x6e, 0x07, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0x99, 0x07, 0xc8, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb2,\n    0x6f, 0x61, 0x56, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x74,\n    0x8a, 0xf1, 0x58, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x62,\n    0xf1, 0x30, 0x8d, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x86,\n    0xa8, 0xfe, 0x9e, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x93,\n    0x51, 0x09, 0xf3, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa5,\n    0xa4, 0xc3, 0x69, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xee,\n    0x5d, 0x3f, 0x98, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2d,\n    0xc6, 0x49, 0x11, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb4,\n    0x7e, 0x34, 0xb0, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x55,\n    0xa1, 0x1d, 0x2d, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbf,\n    0x70, 0xf4, 0xff, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0x9f, 0x41, 0x9b, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x41,\n    0x68, 0xb3, 0x87, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x65,\n    0xa5, 0x34, 0x1a, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x16,\n    0x98, 0x43, 0xea, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4f,\n    0xfb, 0xd4, 0x80, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x30,\n    0xd9, 0x4d, 0x0c, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb4,\n    0x52, 0x0a, 0x27, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7a,\n    0xbe, 0x9b, 0x0f, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe6,\n    0x2e, 0xf9, 0x9d, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xef,\n    0x36, 0x61, 0x28, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x06,\n    0x3c, 0x47, 0xf0, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xf8,\n    0xdf, 0xa8, 0xc9, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x12,\n    0x75, 0xad, 0x5b, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x83,\n    0xbc, 0x32, 0x20, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe6,\n    0xe3, 0xfc, 0x0e, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x4c,\n    0x95, 0xc6, 0x81, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x24,\n    0x90, 0x39, 0xed, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x1f,\n    0x20, 0x22, 0xca, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6f,\n    0x4b, 0xf4, 0x71, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5a,\n    0xc9, 0xbd, 0x6c, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe0,\n    0x7b, 0x87, 0x4c, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5f,\n    0xa7, 0x3e, 0x05, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x01,\n    0x77, 0xad, 0x5a, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4a,\n    0x44, 0x65, 0x9d, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x93,\n    0xb5, 0xcd, 0xf3, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf8,\n    0xc2, 0x7d, 0xc2, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x07,\n    0x7c, 0x31, 0x14, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfe,\n    0xe7, 0x4b, 0x87, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x74,\n    0xe6, 0x6b, 0x4b, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x27,\n    0x6c, 0xf1, 0xf8, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x59,\n    0xb2, 0x6d, 0xd8, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x8f,\n    0xbd, 0x0e, 0x64, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfb,\n    0x88, 0x8f, 0x64, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfa,\n    0x9f, 0x6c, 0x10, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x81,\n    0xba, 0xa1, 0xef, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xff,\n    0xed, 0x29, 0xef, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa2,\n    0xcf, 0x58, 0x75, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8d,\n    0xc0, 0x2f, 0xe6, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x4c,\n    0xaf, 0x67, 0x85, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0e,\n    0x0e, 0xbf, 0xc9, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1b,\n    0x3e, 0xc5, 0x78, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe3,\n    0xc9, 0xcd, 0xe8, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3d,\n    0xdd, 0x91, 0x52, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x11,\n    0x23, 0xb0, 0x83, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1f,\n    0x32, 0x57, 0x74, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0x95, 0x03, 0x32, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd4,\n    0x61, 0x56, 0xaf, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe5,\n    0xbd, 0x46, 0x06, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x85,\n    0xe8, 0x68, 0xef, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb5,\n    0xdf, 0x14, 0xbc, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x61,\n    0xbe, 0x57, 0xdd, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x4f,\n    0xaa, 0xca, 0x4b, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6b,\n    0xf8, 0xde, 0x9e, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x74,\n    0x7f, 0x2d, 0xb3, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x44,\n    0x36, 0xec, 0x03, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x98,\n    0x42, 0xea, 0x32, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x68,\n    0x5c, 0xe6, 0xb6, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf2,\n    0x88, 0x17, 0x52, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9e,\n    0x2f, 0x69, 0xfe, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x09,\n    0x65, 0xa6, 0x13, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0e,\n    0x8b, 0xa0, 0x3c, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x9b,\n    0xda, 0x84, 0xf7, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb7,\n    0x58, 0x84, 0xee, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x94,\n    0x28, 0x67, 0x4f, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcf,\n    0xdb, 0xc7, 0xbf, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xde,\n    0x44, 0xdb, 0xcc, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x47,\n    0x11, 0xf9, 0x0e, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x30,\n    0xa0, 0x9b, 0x88, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xea,\n    0x64, 0xc5, 0x2e, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x78,\n    0xd7, 0x44, 0xf2, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x71,\n    0xd5, 0xa5, 0xb8, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x72,\n    0x59, 0x69, 0x68, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4e,\n    0x0d, 0x12, 0x02, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x09,\n    0xd3, 0xdb, 0x8b, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x92,\n    0x89, 0x2b, 0x08, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x89,\n    0xce, 0x4c, 0xca, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xda,\n    0x52, 0x44, 0x1f, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc3,\n    0x9b, 0x1a, 0x53, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x35,\n    0xd0, 0xb3, 0xf1, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x19,\n    0x6b, 0x19, 0x27, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa2,\n    0xca, 0xc0, 0x3e, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd3,\n    0x2c, 0x81, 0x40, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xaf,\n    0x96, 0x3e, 0x9b, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd6,\n    0x65, 0x71, 0x59, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf1,\n    0xf4, 0x9b, 0x83, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x77,\n    0xaa, 0xa2, 0x0d, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb9,\n    0x1b, 0xa0, 0xd2, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd1,\n    0x62, 0x0a, 0xbe, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xed,\n    0x8e, 0x8a, 0xfc, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb1,\n    0xc5, 0x6c, 0x47, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x27,\n    0x14, 0xf1, 0x7d, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0x3b, 0xa7, 0x05, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x8b,\n    0x76, 0xac, 0xf8, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7e,\n    0x2c, 0xc9, 0xc5, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xad,\n    0x5d, 0x93, 0x37, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x25,\n    0x64, 0xe9, 0xeb, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc6,\n    0x82, 0x9b, 0xae, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0c,\n    0x50, 0x09, 0x51, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x90,\n    0xca, 0x3e, 0x77, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x63,\n    0x46, 0x89, 0xeb, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd0,\n    0x72, 0xf8, 0xd9, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd8,\n    0xbb, 0x2d, 0xee, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x53,\n    0x9d, 0x66, 0xa7, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x75,\n    0xfb, 0x42, 0xbc, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcc,\n    0x64, 0xae, 0x9f, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x24,\n    0xdc, 0x1d, 0x88, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8e,\n    0xe1, 0x40, 0x1b, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9e,\n    0x48, 0xba, 0x81, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x82,\n    0xd2, 0x89, 0x67, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcf,\n    0x13, 0x87, 0xce, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xed,\n    0x80, 0x0c, 0x19, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcd,\n    0xd4, 0xf5, 0x92, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0b,\n    0x4b, 0x45, 0xd2, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x9e,\n    0x82, 0x94, 0x16, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x33,\n    0x61, 0x29, 0xd3, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd6,\n    0xe5, 0x90, 0x86, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1c,\n    0xa3, 0xa5, 0xaf, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfb,\n    0xb8, 0x2e, 0x30, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb9,\n    0x21, 0x06, 0x79, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa8,\n    0x1b, 0x51, 0x98, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x33,\n    0x5c, 0x40, 0x75, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x88,\n    0x8b, 0xd6, 0x91, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x53,\n    0x1f, 0x91, 0xa1, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0x74, 0x14, 0x1f, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x9c,\n    0x86, 0x4a, 0x7a, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xdd,\n    0x43, 0xf8, 0x91, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0c,\n    0x51, 0xb6, 0x4b, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbb,\n    0xce, 0x7e, 0xdd, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x49,\n    0x12, 0xa6, 0x12, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x41,\n    0x3b, 0xe8, 0x7f, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd5,\n    0xf8, 0xa3, 0x03, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xda,\n    0x08, 0x39, 0x59, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x01,\n    0x05, 0x52, 0xf4, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xba,\n    0xe1, 0xed, 0xb0, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5a,\n    0x19, 0xc5, 0xa7, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf9,\n    0xca, 0x4a, 0xf0, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe4,\n    0x7d, 0xf4, 0xa3, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xee,\n    0xab, 0xc1, 0x9a, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1a,\n    0xe7, 0x75, 0x30, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x16,\n    0xa2, 0xf3, 0x4e, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x25,\n    0x90, 0x23, 0xf0, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1b,\n    0xfd, 0x3b, 0xbb, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0a,\n    0x3c, 0x10, 0x68, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb0,\n    0x5c, 0xbf, 0x7f, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x59,\n    0xb7, 0x17, 0x6d, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x33,\n    0xd9, 0xdf, 0xba, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbf,\n    0xaa, 0x8a, 0x5a, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8b,\n    0x03, 0x6c, 0x50, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x08,\n    0xf7, 0x1f, 0xc1, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xce,\n    0xfc, 0x6e, 0x66, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd7,\n    0x45, 0x6d, 0xe3, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x93,\n    0x74, 0xb6, 0x81, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc4,\n    0xfa, 0xec, 0x3e, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x35,\n    0x9c, 0x3d, 0xa5, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x91,\n    0x83, 0x69, 0x08, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6e,\n    0x38, 0xb5, 0xe4, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd1,\n    0x87, 0x3d, 0xfb, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4a,\n    0x9d, 0x8f, 0x42, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x45,\n    0x5b, 0x67, 0xe5, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x18,\n    0x6b, 0x3a, 0xe8, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5a,\n    0xff, 0x5a, 0xa6, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe3,\n    0xb6, 0x98, 0xe7, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf0,\n    0xcb, 0xbd, 0xa6, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc9,\n    0xc2, 0xb1, 0xe8, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x00,\n    0xf7, 0x41, 0x1f, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7a,\n    0xb7, 0x28, 0xf5, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x78,\n    0xf9, 0xda, 0xb3, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x26,\n    0x16, 0xa2, 0x49, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x0e,\n    0x95, 0x37, 0x7c, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x37,\n    0x0b, 0xa1, 0x8b, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2c,\n    0xcd, 0xb1, 0x29, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xee,\n    0xf1, 0xa2, 0xdb, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd0,\n    0x75, 0xa9, 0x5c, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x20,\n    0xc3, 0x5f, 0xff, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd3,\n    0xf1, 0xb7, 0x68, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcb,\n    0x63, 0x24, 0x60, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf7,\n    0xa5, 0x94, 0x5f, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc2,\n    0x03, 0x23, 0x3a, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe6,\n    0x46, 0x83, 0x3b, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe8,\n    0x13, 0xcf, 0xdc, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x5b,\n    0x3f, 0x77, 0x6a, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x36,\n    0xb4, 0x8b, 0xbe, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2f,\n    0xe6, 0x5e, 0xfd, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x61,\n    0x3b, 0xca, 0xb3, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x43,\n    0x5a, 0xb3, 0x91, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x35,\n    0x03, 0x1b, 0xbd, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x53,\n    0xdd, 0x70, 0x88, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc7,\n    0xd4, 0x95, 0x55, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd1,\n    0x8d, 0x90, 0xe5, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6d,\n    0x10, 0x87, 0x8e, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x36,\n    0x41, 0xf0, 0x0c, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x08,\n    0x33, 0xa7, 0x79, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd8,\n    0x32, 0x0f, 0xe0, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc7,\n    0xed, 0xb4, 0x16, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1e,\n    0x2a, 0x7d, 0x5c, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x18,\n    0xea, 0xb9, 0xa2, 0x00, 0xa0, 0x24, 0x01, 0x3e,\n    0x08, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x66,\n    0x18, 0x0f, 0xb4, 0x00, 0xa0, 0x24, 0x01, 0x3e,\n    0x08, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x08,\n    0x26, 0xf4, 0x05, 0x00, 0xa0, 0x24, 0x01, 0x3e,\n    0x08, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbf,\n    0x83, 0x31, 0x0a, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1e,\n    0xc4, 0x2f, 0x1e, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x26,\n    0x8e, 0x9b, 0xc8, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xda,\n    0xfe, 0xd0, 0x2f, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x39,\n    0x88, 0x26, 0x84, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x07,\n    0x07, 0x94, 0x2d, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xeb,\n    0xf5, 0x3a, 0x03, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb9,\n    0xa8, 0xa2, 0xce, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x0f,\n    0xd3, 0x13, 0xac, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x19,\n    0x78, 0xad, 0x95, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd1,\n    0x1f, 0xa7, 0xcb, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8e,\n    0xa1, 0x96, 0x69, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xc7,\n    0xff, 0x2a, 0xaf, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0x1d, 0xf4, 0x9b, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x8d,\n    0x71, 0x88, 0xf0, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe2,\n    0x20, 0xbc, 0xad, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd8,\n    0x22, 0xb5, 0xd9, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xec,\n    0xe1, 0xb0, 0x44, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfe,\n    0x90, 0x88, 0x20, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x35,\n    0x89, 0x8d, 0x8a, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xe1,\n    0xff, 0x00, 0xf7, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x71,\n    0xa6, 0x3e, 0x91, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x04,\n    0x01, 0x29, 0xd0, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xef,\n    0xf1, 0x42, 0xd2, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x52,\n    0x09, 0x00, 0xa8, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfc,\n    0x87, 0x14, 0xcd, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x53,\n    0x70, 0x02, 0x9b, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xab,\n    0x83, 0xef, 0x9c, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa0,\n    0x26, 0x7d, 0xb9, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xca,\n    0x7c, 0xba, 0xa7, 0x00, 0xa0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x60,\n    0x9c, 0x1f, 0x5f, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x6c,\n    0xed, 0x01, 0x8c, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd0,\n    0x3c, 0x82, 0xbe, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x1a,\n    0x8e, 0xb9, 0xd2, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x97,\n    0x09, 0xda, 0x43, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x08,\n    0xf0, 0x92, 0xf3, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x73,\n    0xc6, 0xdf, 0x5f, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x5d,\n    0xa6, 0xf3, 0x3c, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0xb0, 0x51, 0x37, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x61,\n    0x55, 0x0b, 0x8a, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x33,\n    0x8c, 0xf1, 0xba, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xa6,\n    0xca, 0x24, 0xa3, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x2f,\n    0xe5, 0x07, 0x6d, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xfa,\n    0x44, 0x40, 0x9b, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa4,\n    0xaf, 0x30, 0xc6, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x15,\n    0x15, 0xba, 0xc8, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xc6,\n    0x93, 0xce, 0x5b, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x9f,\n    0x7b, 0x3b, 0x84, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x06,\n    0xdb, 0xed, 0x30, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb3,\n    0x53, 0x17, 0xda, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa7,\n    0xd9, 0xa4, 0xf2, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x20,\n    0xeb, 0x20, 0x4c, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe1,\n    0x34, 0xba, 0x76, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xf6,\n    0xb8, 0x8f, 0x0b, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x43,\n    0x76, 0x28, 0x3e, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x63,\n    0xb3, 0x52, 0x09, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x42,\n    0xd1, 0x68, 0xe4, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x0c,\n    0x98, 0x8a, 0x5f, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x09,\n    0xa1, 0x5b, 0x27, 0x00, 0x90, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xb2,\n    0x2f, 0x0a, 0xc6, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x00,\n    0x8b, 0xdd, 0xba, 0x00, 0xe0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x42,\n    0x2c, 0x61, 0xa9, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x6f,\n    0xb7, 0x14, 0xfa, 0x00, 0xe0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x2f,\n    0x9d, 0x8a, 0xbf, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xe2,\n    0xff, 0x6e, 0x58, 0x00, 0xe0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x36,\n    0xc7, 0xaf, 0x53, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7c,\n    0x24, 0x4c, 0xbe, 0x00, 0xf0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd4,\n    0x6e, 0x60, 0x13, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x96,\n    0x95, 0xac, 0x47, 0x00, 0xf0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x2e,\n    0x0e, 0xb0, 0x2b, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x81,\n    0x39, 0x82, 0xda, 0x00, 0xf0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x47,\n    0x57, 0xba, 0xec, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x45,\n    0x6c, 0xd1, 0x10, 0x00, 0xf0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x52,\n    0x81, 0xca, 0xab, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xd4,\n    0x45, 0x23, 0x4a, 0x00, 0xf0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x35,\n    0x9d, 0xf9, 0xfe, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xfe,\n    0x58, 0x24, 0xa9, 0x00, 0xf0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0xd1,\n    0xbd, 0x2f, 0x06, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbb,\n    0xa4, 0xbb, 0x03, 0x00, 0xf0, 0x24, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x02, 0x00, 0x64, 0xaa, 0x58,\n    0x46, 0x3f, 0x62, 0x00, 0xe0, 0x10, 0x00, 0xd2,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4c,\n    0xec, 0x6b, 0x9c, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x69,\n    0xdc, 0x11, 0x3a, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcd,\n    0x6e, 0xd3, 0xdf, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x73,\n    0x7d, 0xdd, 0xb8, 0x00, 0xf0, 0x44, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa1,\n    0x85, 0xd1, 0x98, 0x00, 0xf0, 0x44, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7a,\n    0x96, 0xe6, 0xff, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xbb,\n    0x29, 0x6c, 0xaa, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x14,\n    0x11, 0x02, 0x79, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x1f,\n    0x05, 0x4e, 0x0e, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3f,\n    0x3f, 0x77, 0x58, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xcf,\n    0x37, 0xab, 0x0f, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x66,\n    0xa2, 0x28, 0x83, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xdd,\n    0x14, 0x4c, 0xb6, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x05,\n    0xfc, 0x2d, 0x18, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x10,\n    0x7d, 0xe4, 0xe4, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x8b,\n    0x2e, 0x77, 0x09, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x62,\n    0xba, 0x18, 0x5f, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x75,\n    0xaf, 0x6b, 0x3a, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x78,\n    0x40, 0x20, 0x09, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x63,\n    0xa1, 0x67, 0x6b, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xdd,\n    0x25, 0x2e, 0xcc, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x3a,\n    0x2a, 0x35, 0x7c, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x78,\n    0x55, 0x9e, 0xbb, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x4b,\n    0xa1, 0x0c, 0xb1, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xb3,\n    0x44, 0x52, 0xa6, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x59,\n    0xc0, 0x0a, 0xb3, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x76,\n    0x8a, 0xff, 0x5c, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xa4,\n    0x71, 0x5a, 0xca, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x44,\n    0xb1, 0x7b, 0xe1, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf3,\n    0xcb, 0xea, 0x85, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x85,\n    0x3c, 0xb8, 0x42, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x70,\n    0x9b, 0x7b, 0x65, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x25,\n    0x37, 0x4f, 0x59, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x33,\n    0xa1, 0x82, 0xe4, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x7d,\n    0xf8, 0x42, 0x4b, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x80,\n    0x0d, 0x0f, 0x80, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0xf9,\n    0x26, 0xee, 0x6d, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x58,\n    0x4c, 0x8a, 0x8c, 0x00, 0x00, 0x45, 0x01, 0xf8,\n    0x07, 0x00, 0x00, 0x00, 0x00, 0x64, 0xaa, 0x41,\n    0xd4, 0xb4, 0x23, 0x00, 0x00, 0x45, 0x01, 0x84,\n    0x08, 0x00, 0x00, 0x18, 0x00, 0x18, 0x04, 0x20,\n    0x00, 0x30, 0x00, 0x10, 0x00, 0x28, 0x00, 0x14,\n    0x00, 0x11, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x28, 0x00, 0x10,\n    0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x00, 0x60,\n    0x01, 0x90, 0x01, 0xa0, 0x01, 0x28, 0x00, 0x30,\n    0x00, 0x38, 0x00, 0x58, 0x00, 0xa0, 0x05, 0xa8,\n    0x05, 0xb0, 0x05, 0xb8, 0x05, 0xc0, 0x05, 0xc8,\n    0x05, 0x28, 0x00, 0x08, 0x00, 0x48, 0x00, 0xb8,\n    0x03, 0x18, 0x00, 0x18, 0x04, 0x20, 0x00, 0x30,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x14, 0x00, 0x11,\n    0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x08, 0x00, 0x00,\n    0x01, 0x00, 0x00, 0x38, 0x00, 0x60, 0x01, 0x90,\n    0x01, 0xa0, 0x01, 0x28, 0x00, 0x30, 0x00, 0x38,\n    0x00, 0x58, 0x00, 0xa0, 0x05, 0xa8, 0x05, 0xb0,\n    0x05, 0xb8, 0x05, 0xc0, 0x05, 0xc8, 0x05, 0x28,\n    0x00, 0x08, 0x00, 0x48, 0x00, 0xb8, 0x03, 0x18,\n    0x00, 0x18, 0x04, 0x20, 0x00, 0x30, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x14, 0x00, 0x11, 0x00, 0x10,\n    0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00,\n    0x00, 0x38, 0x00, 0x60, 0x01, 0x90, 0x01, 0xa0,\n    0x01, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x58,\n    0x00, 0xa8, 0x05, 0xb0, 0x05, 0xb8, 0x05, 0xc0,\n    0x05, 0xc8, 0x05, 0xd0, 0x05, 0x28, 0x00, 0x08,\n    0x00, 0x48, 0x00, 0xb8, 0x03, 0x80, 0x00, 0x10,\n    0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x18,\n    0x00, 0x18, 0x04, 0x20, 0x00, 0x30, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x14, 0x00, 0x11, 0x00, 0x10,\n    0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00,\n    0x00, 0x38, 0x00, 0x60, 0x01, 0x90, 0x01, 0xa0,\n    0x01, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x58,\n    0x00, 0xa8, 0x05, 0xb0, 0x05, 0xb8, 0x05, 0xc0,\n    0x05, 0xc8, 0x05, 0xd0, 0x05, 0x28, 0x00, 0x08,\n    0x00, 0x48, 0x00, 0xb8, 0x03, 0x28, 0x00, 0x18,\n    0x04, 0x20, 0x00, 0x30, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x14, 0x00, 0x11, 0x00, 0x10, 0x00, 0x18,\n    0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38,\n    0x00, 0x60, 0x01, 0x90, 0x01, 0xa0, 0x01, 0x28,\n    0x00, 0x30, 0x00, 0x38, 0x00, 0x58, 0x00, 0xa8,\n    0x05, 0xb0, 0x05, 0xb8, 0x05, 0xc0, 0x05, 0xc8,\n    0x05, 0xd0, 0x05, 0x28, 0x00, 0x08, 0x00, 0x48,\n    0x00, 0xb8, 0x03, 0x28, 0x00, 0x18, 0x04, 0x20,\n    0x00, 0x30, 0x00, 0x10, 0x00, 0x28, 0x00, 0x14,\n    0x00, 0x11, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x28, 0x00, 0x08,\n    0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x00, 0x60,\n    0x01, 0x90, 0x01, 0xa0, 0x01, 0x28, 0x00, 0x30,\n    0x00, 0x38, 0x00, 0x58, 0x00, 0xa8, 0x05, 0xb0,\n    0x05, 0xb8, 0x05, 0xc0, 0x05, 0xc8, 0x05, 0xd0,\n    0x05, 0x28, 0x00, 0x08, 0x00, 0x48, 0x00, 0xb8,\n    0x03, 0x18, 0x00, 0x20, 0x04, 0x20, 0x00, 0x30,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x14, 0x00, 0x11,\n    0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00,\n    0x01, 0x00, 0x00, 0x38, 0x00, 0x60, 0x01, 0x90,\n    0x01, 0xa0, 0x01, 0x28, 0x00, 0x30, 0x00, 0x38,\n    0x00, 0x58, 0x00, 0xa8, 0x05, 0xb0, 0x05, 0xb8,\n    0x05, 0xc0, 0x05, 0xc8, 0x05, 0xd0, 0x05, 0x28,\n    0x00, 0x08, 0x00, 0x48, 0x00, 0xc0, 0x03, 0x18,\n    0x00, 0x18, 0x04, 0x20, 0x00, 0x30, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x14, 0x00, 0x11, 0x00, 0x10,\n    0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00,\n    0x00, 0x38, 0x00, 0x60, 0x01, 0x90, 0x01, 0xa0,\n    0x01, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x58,\n    0x00, 0xa8, 0x05, 0xb0, 0x05, 0xb8, 0x05, 0xc0,\n    0x05, 0xc8, 0x05, 0xd0, 0x05, 0x28, 0x00, 0x08,\n    0x00, 0x48, 0x00, 0xc0, 0x03, 0x28, 0x00, 0x18,\n    0x04, 0x20, 0x00, 0x30, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x14, 0x00, 0x11, 0x00, 0x10, 0x00, 0x18,\n    0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38,\n    0x00, 0x60, 0x01, 0x90, 0x01, 0xa0, 0x01, 0x28,\n    0x00, 0x30, 0x00, 0x38, 0x00, 0x58, 0x00, 0xa8,\n    0x05, 0xb0, 0x05, 0xb8, 0x05, 0xc0, 0x05, 0xc8,\n    0x05, 0xd0, 0x05, 0x28, 0x00, 0x08, 0x00, 0x48,\n    0x00, 0xc0, 0x03, 0x28, 0x00, 0x18, 0x04, 0x20,\n    0x00, 0x30, 0x00, 0x10, 0x00, 0x28, 0x00, 0x14,\n    0x00, 0x11, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x28, 0x00, 0x08,\n    0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x00, 0x60,\n    0x01, 0x90, 0x01, 0xa0, 0x01, 0x28, 0x00, 0x30,\n    0x00, 0x38, 0x00, 0x58, 0x00, 0xa8, 0x05, 0xb0,\n    0x05, 0xb8, 0x05, 0xc0, 0x05, 0xc8, 0x05, 0xd0,\n    0x05, 0x28, 0x00, 0x08, 0x00, 0x48, 0x00, 0xc0,\n    0x03, 0x28, 0x00, 0x70, 0x05, 0x20, 0x00, 0x30,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x14, 0x00, 0x11,\n    0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00,\n    0x01, 0x00, 0x00, 0x38, 0x00, 0x60, 0x01, 0x90,\n    0x01, 0xa0, 0x01, 0x28, 0x00, 0x30, 0x00, 0x38,\n    0x00, 0x58, 0x00, 0x80, 0x03, 0x88, 0x03, 0x90,\n    0x03, 0x98, 0x03, 0xa0, 0x03, 0xa8, 0x03, 0x28,\n    0x00, 0x08, 0x00, 0x48, 0x00, 0x18, 0x05, 0x28,\n    0x00, 0x70, 0x05, 0x20, 0x00, 0x30, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x14, 0x00, 0x11, 0x00, 0x10,\n    0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00,\n    0x00, 0x38, 0x00, 0x60, 0x01, 0x90, 0x01, 0xa0,\n    0x01, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x58,\n    0x00, 0x80, 0x03, 0x88, 0x03, 0x90, 0x03, 0x98,\n    0x03, 0xa0, 0x03, 0xa8, 0x03, 0x28, 0x00, 0x08,\n    0x00, 0x48, 0x00, 0x18, 0x05, 0x28, 0x00, 0x70,\n    0x05, 0x20, 0x00, 0x30, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x0b, 0x00, 0x08, 0x00, 0x10, 0x00, 0x18,\n    0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38,\n    0x00, 0x60, 0x01, 0x90, 0x01, 0xa0, 0x01, 0x28,\n    0x00, 0x30, 0x00, 0x38, 0x00, 0x58, 0x00, 0x80,\n    0x03, 0x88, 0x03, 0x90, 0x03, 0x98, 0x03, 0xa0,\n    0x03, 0xa8, 0x03, 0x28, 0x00, 0x08, 0x00, 0x48,\n    0x00, 0x18, 0x05, 0x28, 0x00, 0x70, 0x05, 0x20,\n    0x00, 0x30, 0x00, 0x10, 0x00, 0x28, 0x00, 0x0b,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x28, 0x00, 0x08,\n    0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x00, 0x60,\n    0x01, 0x90, 0x01, 0xa0, 0x01, 0x28, 0x00, 0x30,\n    0x00, 0x38, 0x00, 0x58, 0x00, 0x80, 0x03, 0x88,\n    0x03, 0x90, 0x03, 0x98, 0x03, 0xa0, 0x03, 0xa8,\n    0x03, 0x28, 0x00, 0x08, 0x00, 0x48, 0x00, 0x18,\n    0x05, 0x28, 0x00, 0x00, 0x03, 0x20, 0x00, 0x30,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x14, 0x00, 0x11,\n    0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x08, 0x00, 0x00,\n    0x01, 0x00, 0x00, 0x38, 0x00, 0x60, 0x01, 0x90,\n    0x01, 0xa0, 0x01, 0x28, 0x00, 0x30, 0x00, 0x38,\n    0x00, 0x58, 0x00, 0x80, 0x03, 0x88, 0x03, 0x90,\n    0x03, 0x98, 0x03, 0xa0, 0x03, 0xa8, 0x03, 0x28,\n    0x00, 0x08, 0x00, 0x48, 0x00, 0xa8, 0x02, 0x28,\n    0x00, 0x00, 0x03, 0x20, 0x00, 0x30, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00,\n    0x00, 0x38, 0x00, 0x60, 0x01, 0x90, 0x01, 0xa0,\n    0x01, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x58,\n    0x00, 0x80, 0x03, 0x88, 0x03, 0x90, 0x03, 0x98,\n    0x03, 0xa0, 0x03, 0xa8, 0x03, 0x28, 0x00, 0x08,\n    0x00, 0x48, 0x00, 0xa8, 0x02, 0x28, 0x00, 0x00,\n    0x03, 0x20, 0x00, 0x30, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x14, 0x00, 0x11, 0x00, 0x10, 0x00, 0x18,\n    0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38,\n    0x00, 0x60, 0x01, 0x90, 0x01, 0xa0, 0x01, 0xff,\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,\n    0x03, 0x88, 0x03, 0x90, 0x03, 0x98, 0x03, 0xa0,\n    0x03, 0xa8, 0x03, 0x28, 0x00, 0x08, 0x00, 0x48,\n    0x00, 0xa8, 0x02, 0x28, 0x00, 0x00, 0x03, 0x20,\n    0x00, 0x30, 0x00, 0x10, 0x00, 0x28, 0x00, 0x0b,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x28, 0x00, 0x08,\n    0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x00, 0x60,\n    0x01, 0x90, 0x01, 0xa0, 0x01, 0xff, 0xff, 0xff,\n    0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0x88,\n    0x03, 0x90, 0x03, 0x98, 0x03, 0xa0, 0x03, 0xa8,\n    0x03, 0x28, 0x00, 0x08, 0x00, 0x48, 0x00, 0xa8,\n    0x02, 0x28, 0x00, 0x00, 0x03, 0x20, 0x00, 0x30,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x14, 0x00, 0x11,\n    0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x08, 0x00, 0xe8,\n    0x00, 0x00, 0x00, 0x38, 0x00, 0x48, 0x01, 0x78,\n    0x01, 0x88, 0x01, 0x28, 0x00, 0x30, 0x00, 0x38,\n    0x00, 0x58, 0x00, 0x80, 0x03, 0x88, 0x03, 0x90,\n    0x03, 0x98, 0x03, 0xa0, 0x03, 0xa8, 0x03, 0x28,\n    0x00, 0x08, 0x00, 0x48, 0x00, 0xa8, 0x02, 0x28,\n    0x00, 0x00, 0x03, 0x20, 0x00, 0x30, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x08, 0x00, 0xe8, 0x00, 0x00,\n    0x00, 0x38, 0x00, 0x48, 0x01, 0x78, 0x01, 0x88,\n    0x01, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x58,\n    0x00, 0x80, 0x03, 0x88, 0x03, 0x90, 0x03, 0x98,\n    0x03, 0xa0, 0x03, 0xa8, 0x03, 0x28, 0x00, 0x08,\n    0x00, 0x48, 0x00, 0xa8, 0x02, 0x18, 0x00, 0xc0,\n    0x03, 0x20, 0x00, 0x30, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x14, 0x00, 0x11, 0x00, 0x10, 0x00, 0x18,\n    0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38,\n    0x00, 0x60, 0x01, 0x90, 0x01, 0xa0, 0x01, 0x28,\n    0x00, 0x30, 0x00, 0x38, 0x00, 0x58, 0x00, 0xc8,\n    0x05, 0xd0, 0x05, 0xd8, 0x05, 0xe0, 0x05, 0xe8,\n    0x05, 0xf0, 0x05, 0x28, 0x00, 0x08, 0x00, 0x48,\n    0x00, 0x68, 0x03, 0x18, 0x00, 0xc8, 0x03, 0x20,\n    0x00, 0x30, 0x00, 0x10, 0x00, 0x28, 0x00, 0x14,\n    0x00, 0x11, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x28, 0x00, 0x10,\n    0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x00, 0x60,\n    0x01, 0x90, 0x01, 0xa0, 0x01, 0x28, 0x00, 0x30,\n    0x00, 0x38, 0x00, 0x58, 0x00, 0xc8, 0x05, 0xd0,\n    0x05, 0xd8, 0x05, 0xe0, 0x05, 0xe8, 0x05, 0xf0,\n    0x05, 0x28, 0x00, 0x08, 0x00, 0x48, 0x00, 0x70,\n    0x03, 0x28, 0x00, 0xc8, 0x03, 0x20, 0x00, 0x30,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x14, 0x00, 0x11,\n    0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00,\n    0x01, 0x00, 0x00, 0x38, 0x00, 0x60, 0x01, 0x90,\n    0x01, 0xa0, 0x01, 0x28, 0x00, 0x30, 0x00, 0x38,\n    0x00, 0x58, 0x00, 0xc8, 0x05, 0xd0, 0x05, 0xd8,\n    0x05, 0xe0, 0x05, 0xe8, 0x05, 0xf0, 0x05, 0x28,\n    0x00, 0x08, 0x00, 0x48, 0x00, 0x70, 0x03, 0x28,\n    0x00, 0xc8, 0x03, 0x20, 0x00, 0x30, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x14, 0x00, 0x11, 0x00, 0x10,\n    0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00,\n    0x00, 0x38, 0x00, 0x60, 0x01, 0x90, 0x01, 0xa0,\n    0x01, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x58,\n    0x00, 0xc8, 0x05, 0xd0, 0x05, 0xd8, 0x05, 0xe0,\n    0x05, 0xe8, 0x05, 0xf0, 0x05, 0x28, 0x00, 0x08,\n    0x00, 0x48, 0x00, 0x70, 0x03, 0x18, 0x00, 0xd0,\n    0x03, 0x20, 0x00, 0x30, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x14, 0x00, 0x11, 0x00, 0x10, 0x00, 0x18,\n    0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38,\n    0x00, 0x60, 0x01, 0x90, 0x01, 0xa0, 0x01, 0x28,\n    0x00, 0x30, 0x00, 0x38, 0x00, 0x58, 0x00, 0xc8,\n    0x05, 0xd0, 0x05, 0xd8, 0x05, 0xe0, 0x05, 0xe8,\n    0x05, 0xf0, 0x05, 0x28, 0x00, 0x08, 0x00, 0x48,\n    0x00, 0x78, 0x03, 0x28, 0x00, 0xd0, 0x03, 0x20,\n    0x00, 0x30, 0x00, 0x10, 0x00, 0x28, 0x00, 0x14,\n    0x00, 0x11, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x28, 0x00, 0x10,\n    0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x00, 0x60,\n    0x01, 0x90, 0x01, 0xa0, 0x01, 0x28, 0x00, 0x30,\n    0x00, 0x38, 0x00, 0x58, 0x00, 0xc8, 0x05, 0xd0,\n    0x05, 0xd8, 0x05, 0xe0, 0x05, 0xe8, 0x05, 0xf0,\n    0x05, 0x28, 0x00, 0x08, 0x00, 0x48, 0x00, 0x78,\n    0x03, 0x28, 0x00, 0xd0, 0x03, 0x20, 0x00, 0x30,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x14, 0x00, 0x11,\n    0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x08, 0x00, 0x00,\n    0x01, 0x00, 0x00, 0x38, 0x00, 0x60, 0x01, 0x90,\n    0x01, 0xa0, 0x01, 0x28, 0x00, 0x30, 0x00, 0x38,\n    0x00, 0x58, 0x00, 0xc8, 0x05, 0xd0, 0x05, 0xd8,\n    0x05, 0xe0, 0x05, 0xe8, 0x05, 0xf0, 0x05, 0x28,\n    0x00, 0x08, 0x00, 0x48, 0x00, 0x78, 0x03, 0x28,\n    0x00, 0x28, 0x05, 0x20, 0x00, 0x30, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x14, 0x00, 0x11, 0x00, 0x10,\n    0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00,\n    0x00, 0x38, 0x00, 0x60, 0x01, 0x90, 0x01, 0xa0,\n    0x01, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x58,\n    0x00, 0xa0, 0x03, 0xa8, 0x03, 0xb0, 0x03, 0xb8,\n    0x03, 0xc0, 0x03, 0xc8, 0x03, 0x28, 0x00, 0x08,\n    0x00, 0x48, 0x00, 0xd0, 0x04, 0x28, 0x00, 0x28,\n    0x05, 0x20, 0x00, 0x30, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x14, 0x00, 0x11, 0x00, 0x10, 0x00, 0x18,\n    0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x28,\n    0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38,\n    0x00, 0x60, 0x01, 0x90, 0x01, 0xa0, 0x01, 0x28,\n    0x00, 0x30, 0x00, 0x38, 0x00, 0x58, 0x00, 0xa0,\n    0x03, 0xa8, 0x03, 0xb0, 0x03, 0xb8, 0x03, 0xc0,\n    0x03, 0xc8, 0x03, 0x28, 0x00, 0x08, 0x00, 0x48,\n    0x00, 0xd0, 0x04, 0x28, 0x00, 0xf0, 0x02, 0x20,\n    0x00, 0x30, 0x00, 0x10, 0x00, 0x28, 0x00, 0x14,\n    0x00, 0x11, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00,\n    0x00, 0x08, 0x00, 0x10, 0x00, 0x28, 0x00, 0x08,\n    0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x00, 0x60,\n    0x01, 0x90, 0x01, 0xa0, 0x01, 0x28, 0x00, 0x30,\n    0x00, 0x38, 0x00, 0x58, 0x00, 0xa0, 0x03, 0xa8,\n    0x03, 0xb0, 0x03, 0xb8, 0x03, 0xc0, 0x03, 0xc8,\n    0x03, 0x28, 0x00, 0x08, 0x00, 0x48, 0x00, 0x98,\n    0x02, 0x28, 0x00, 0xf0, 0x02, 0x20, 0x00, 0x30,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x14, 0x00, 0x11,\n    0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n    0x00, 0x10, 0x00, 0x28, 0x00, 0x08, 0x00, 0x00,\n    0x01, 0x00, 0x00, 0x38, 0x00, 0x60, 0x01, 0x90,\n    0x01, 0xa0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,\n    0xff, 0xff, 0xff, 0xa0, 0x03, 0xa8, 0x03, 0xb0,\n    0x03, 0xb8, 0x03, 0xc0, 0x03, 0xc8, 0x03, 0x28,\n    0x00, 0x08, 0x00, 0x48, 0x00, 0x98, 0x02, 0x28,\n    0x00, 0xf0, 0x02, 0x20, 0x00, 0x30, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x14, 0x00, 0x11, 0x00, 0x10,\n    0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10,\n    0x00, 0x28, 0x00, 0x08, 0x00, 0xe8, 0x00, 0x00,\n    0x00, 0x38, 0x00, 0x48, 0x01, 0x78, 0x01, 0x88,\n    0x01, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x58,\n    0x00, 0xa0, 0x03, 0xa8, 0x03, 0xb0, 0x03, 0xb8,\n    0x03, 0xc0, 0x03, 0xc8, 0x03, 0x28, 0x00, 0x08,\n    0x00, 0x48, 0x00, 0x98, 0x02,\n};\n\nCONST ULONG KphDynConfigLength = ARRAYSIZE(KphDynConfig);\n#endif\n"
  },
  {
    "path": "kphlib/kphdyn.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n\nThis file is part of System Informer.\n\nTHIS IS AN AUTOGENERATED FILE, DO NOT MODIFY\n    -->\n<dyn>\n    <data arch=\"amd64\" version=\"10.0.9926.0\" file=\"ntoskrnl.exe\" hash=\"533298f2809c0ef286353ba4e5e2f1e60016011fea982a8a03a1540c91f65d23\" timestamp=\"0x54be00cf\" size=\"0x0080b000\" added=\"2025-08-12T14:54:17Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10074.0\" file=\"ntoskrnl.exe\" hash=\"6be92e7a65da3f41225c13168098e589c43c89c29fa23c7803018bbcd5d28e5c\" timestamp=\"0x553ad80a\" size=\"0x00842000\" added=\"2024-12-10T02:56:39Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.16384\" file=\"ntoskrnl.exe\" hash=\"57a0ff848e21e3c79525cfed69141455680f5fe06b46c086775b50da0ca582a5\" timestamp=\"0x559f3c1a\" size=\"0x00852000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.16393\" file=\"ntoskrnl.exe\" hash=\"a5a58ce9866fc83598b683f69d2278cbf09ae870127459ae93bdbe511a26e7cd\" timestamp=\"0x55a9d114\" size=\"0x00852000\" added=\"2024-11-15T06:04:33Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.16412\" file=\"ntoskrnl.exe\" hash=\"ec1f82cd58598cfc8e3a8e855ecad4e4009a0dd510085cf36be91284e8235285\" timestamp=\"0x55b99f32\" size=\"0x00852000\" added=\"2025-05-01T02:24:25Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.16431\" file=\"ntoskrnl.exe\" hash=\"3b0eac71a451db1b9777f5a529358748eeb3420c76e68311604fef80b3a512e7\" timestamp=\"0x55c9bcb6\" size=\"0x00852000\" added=\"2026-03-06T20:01:11Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.16463\" file=\"ntoskrnl.exe\" hash=\"3ffbbb11a3ec0cdd35e40314d1bca47f4ed6dcb804ffd5883002cd0c9da33bf6\" timestamp=\"0x55d5626b\" size=\"0x00852000\" added=\"2024-11-05T01:22:32Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.16515\" file=\"ntoskrnl.exe\" hash=\"d5d90d1af85e5bc876633893eddf34bdd9c13cfffa260ecca226489b22f41df9\" timestamp=\"0x55fa569b\" size=\"0x00852000\" added=\"2026-01-22T02:43:17Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.16545\" file=\"ntoskrnl.exe\" hash=\"166ab6fa3dddf22006fac45ac9172bbc9af20b7c5d90bcc14d7f139ac5696720\" timestamp=\"0x560ca418\" size=\"0x00852000\" added=\"2026-01-15T04:51:11Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.16724\" file=\"ntoskrnl.exe\" hash=\"bd2aea02b2f212a775c4548f2c8c74fcbe38f6ec6e79b92818aa7e18dc49f768\" timestamp=\"0x56cc4f48\" size=\"0x00852000\" added=\"2026-01-22T02:43:17Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.16841\" file=\"ntoskrnl.exe\" hash=\"53bd7aa223cda0e80822464d2dcbb0cb5bb3d73fb2df2140978ede15ef6add48\" timestamp=\"0x5708b3c8\" size=\"0x00852000\" added=\"2025-08-12T05:13:33Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17071\" file=\"ntoskrnl.exe\" hash=\"d32aeecd5497514ede12ffb21e53122012383fb5671d39bfb9c5c8fed20a141a\" timestamp=\"0x57a1781c\" size=\"0x00851000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17113\" file=\"ntoskrnl.exe\" hash=\"44f548e357ce7ceeabe4b43d6f3eb0c89f7e1a7d2dd872b7307ed90bc1543d8a\" timestamp=\"0x57cf97cf\" size=\"0x00851000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17146\" file=\"ntoskrnl.exe\" hash=\"8b61b04a7e54cea564786640837779dc906ecedb7ac4fde19945f5c2093f351d\" timestamp=\"0x57ede76b\" size=\"0x00851000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17184\" file=\"ntoskrnl.exe\" hash=\"2907325b23456ef117a498b2881314e7d9a5d06f05de298216fc97fdd7087e9d\" timestamp=\"0x580f0537\" size=\"0x00851000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17202\" file=\"ntoskrnl.exe\" hash=\"ea3bd9aa0a5d7327d23b22e18950a6b4e6e26244291803d35922e59144b290f9\" timestamp=\"0x5830073c\" size=\"0x00851000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17319\" file=\"ntoskrnl.exe\" hash=\"8c2d5e62b390392a610df0ff41d053502aaa74b74a17712b1cf168d1e0cf8358\" timestamp=\"0x58ba50a3\" size=\"0x00851000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17320\" file=\"ntoskrnl.exe\" hash=\"ce8be449b0bff0cbf1dc91da580e9397de3e7e76c62bf21aa48fa75b42d1481b\" timestamp=\"0x58cd8426\" size=\"0x00851000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17354\" file=\"ntoskrnl.exe\" hash=\"db25412c4b9a8c2a49d53301a5fbcdd8ff00570f2835b5c13b992f4e08a1a850\" timestamp=\"0x58da15ea\" size=\"0x00851000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17394\" file=\"ntoskrnl.exe\" hash=\"9ba3491a19385bc6491bea1e0fa0096a2bfdddd6a54cab5882902976039d09a7\" timestamp=\"0x59029c7c\" size=\"0x00850000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17443\" file=\"ntoskrnl.exe\" hash=\"01874987b02621824876a41fb3d3646f83ef8b66183b11413aa279da74fd015a\" timestamp=\"0x59329c52\" size=\"0x0084f000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17446\" file=\"ntoskrnl.exe\" hash=\"1c965f05106e4d612e3b89512bb47259a3f08d0f20672b416ee2ece1a1ac17cf\" timestamp=\"0x5944d852\" size=\"0x0084f000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17488\" file=\"ntoskrnl.exe\" hash=\"d8b4d4793a5ee815b0f2c7c08049b7b0db2396f117fb17c505bae44ae3ea19bd\" timestamp=\"0x595dfcd6\" size=\"0x0084f000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17533\" file=\"ntoskrnl.exe\" hash=\"71a677b73bc80b21f62126289b96a072a22e95b9f00a54574e1402bffaef5221\" timestamp=\"0x5981e6b8\" size=\"0x0084f000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17609\" file=\"ntoskrnl.exe\" hash=\"e7566f5b71c876ff742f1f9733208d44fd66085ca62a478b32057a4d3bc2e20c\" timestamp=\"0x59ae38cf\" size=\"0x0084f000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17643\" file=\"ntoskrnl.exe\" hash=\"c76a790a9cf0d12fffd63be2ee409892675864ea6a59f2b8774e4db04e889bca\" timestamp=\"0x59c0b0f4\" size=\"0x0084f000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17709\" file=\"ntoskrnl.exe\" hash=\"69ec331011ef7230860c4425153c9fdaa05ab1b5eb91256987e2871b6db162a9\" timestamp=\"0x5a207a8b\" size=\"0x0084f000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17738\" file=\"ntoskrnl.exe\" hash=\"c05aa83503d1bd327757f2eabcd5053ef3aaef0790e2efde8a1cd73b162f5f3f\" timestamp=\"0x5a4ad584\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17741\" file=\"ntoskrnl.exe\" hash=\"778eb79c0acad75b148fe4b3073327c7d10989a731f2d6226f0f2052592de30c\" timestamp=\"0x5a5bc385\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17770\" file=\"ntoskrnl.exe\" hash=\"a987e4f7f3814ff1d3a668ac34ff9ae0a00f834935f528f0e14fe1eb0191c9b8\" timestamp=\"0x5a7e8e07\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17797\" file=\"ntoskrnl.exe\" hash=\"00e307fb1cda321169bc4fd242be74d2b02419ecc74d16babb38d0c7fa950c35\" timestamp=\"0x5a97a800\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17831\" file=\"ntoskrnl.exe\" hash=\"8a6adbdb70d6346125a0672d538af18edc28e65b2500fdd688069b92e29eab2c\" timestamp=\"0x5ab5ecdc\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17861\" file=\"ntoskrnl.exe\" hash=\"ccb09ea4e78cbece0249bbe6b903f15d0d8ddfd8870bdf32999614e676146789\" timestamp=\"0x5ae4122c\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17889\" file=\"ntoskrnl.exe\" hash=\"7fa7bc673d64d4c686e3928e4b83737eb2ea8fa43dde29f9ef386aa942455260\" timestamp=\"0x5b0e83c0\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17914\" file=\"ntoskrnl.exe\" hash=\"003419aebe2778285d7d5fa59858477684332eeeb7baf4857262a1ed2a608971\" timestamp=\"0x5b348724\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17918\" file=\"ntoskrnl.exe\" hash=\"12b3d5086ee3ad60d022c7fd40cafcd9ecf536bf2f70c012d15b9347f0cc0317\" timestamp=\"0x5b484db8\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17946\" file=\"ntoskrnl.exe\" hash=\"1f8cbbfba58cd6738122685750cd6ef31e72c6dc43d5757538d6672d363a8093\" timestamp=\"0x5b695692\" size=\"0x0085c000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.17976\" file=\"ntoskrnl.exe\" hash=\"2083680a0a725ec1428663c63646042174454fc519836a5509dc1bb28df32d9a\" timestamp=\"0x5b905e97\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18005\" file=\"ntoskrnl.exe\" hash=\"0f70a6839cf60c10d9b91dfd2b607183985c87c5c56277fe5c98406978e54e02\" timestamp=\"0x5ba9c763\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18036\" file=\"ntoskrnl.exe\" hash=\"84231ea0ac9b1986b007d803646d1ee506f6d0b92cc5b7450174eaf2faa84cfe\" timestamp=\"0x5bd15137\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18063\" file=\"ntoskrnl.exe\" hash=\"6a8ea0b0d312a917681f83e17397c1b066dbf31a500a4456f5efc596feeb37b2\" timestamp=\"0x5c062285\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18094\" file=\"ntoskrnl.exe\" hash=\"621d7bcbba953345394192422c8787c28bdca9fbaf21f4ddfb9aeebb9f24618f\" timestamp=\"0x5c2b0a7f\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18132\" file=\"ntoskrnl.exe\" hash=\"beb1968ad3f6ca9ba0f17ebb41bb0d1b61c86d57500201764f989e4013101aa2\" timestamp=\"0x5c5a592d\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18135\" file=\"ntoskrnl.exe\" hash=\"7a56257e0d73e54c6b86c6b329bbaccfed4b55547d0e1052a08632991ace858f\" timestamp=\"0x5c69e9f7\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18158\" file=\"ntoskrnl.exe\" hash=\"058c6f6d386a62a8c43674b3b4404823d8de625633a4c94788b4f687f5921e0d\" timestamp=\"0x5c7f7dc9\" size=\"0x0085b000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18186\" file=\"ntoskrnl.exe\" hash=\"5bd38f4ebad2854ec5c29d360fc9cd37dc982ec05e76eeb032a9de1449463224\" timestamp=\"0x5ca2fd28\" size=\"0x0085b000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18187\" file=\"ntoskrnl.exe\" hash=\"8b2948b73cd8a6f530f26af23cb3d518079e42b91e5da6d5a4d08789df2dbac0\" timestamp=\"0x5cad7c23\" size=\"0x0085b000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18215\" file=\"ntoskrnl.exe\" hash=\"6a57497d22933c04b3bcc3d982b57694a9d53805a8b1faf4d5556403e44be558\" timestamp=\"0x5ccbf017\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18275\" file=\"ntoskrnl.exe\" hash=\"6160d119b941ae1a40914a04a1779f2e9403898d5d59bd26869770d3085b7de2\" timestamp=\"0x5d1d9616\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18303\" file=\"ntoskrnl.exe\" hash=\"53db89d3958c3670829d9e8402e225c5953659ec98fe52582a7d52c0d33d7960\" timestamp=\"0x5d3fec71\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18333\" file=\"ntoskrnl.exe\" hash=\"713cf1c15af5ce2a922dda0202b36cad7e243e0b075ed318928e7ea13da60745\" timestamp=\"0x5d675af8\" size=\"0x0085c000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18366\" file=\"ntoskrnl.exe\" hash=\"1444071f41a18fff201482b0f280bddbffbf824f64eba5136d9f30616da0f66b\" timestamp=\"0x5d914d24\" size=\"0x0085c000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18394\" file=\"ntoskrnl.exe\" hash=\"c22b175c129e394d6536fc99255882a83291a67e83cb7afc7fefeebe7e89daf8\" timestamp=\"0x5db12ee8\" size=\"0x00858000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18427\" file=\"ntoskrnl.exe\" hash=\"05d09fe212851483ebbe209f4f58280bef98e3c5740f2be8f748e20d34d6b5da\" timestamp=\"0x5de7a645\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18452\" file=\"ntoskrnl.exe\" hash=\"d506aa98b1e4d2977347713c9e9a267add14bde23226c70c5a1369b1736f8dc4\" timestamp=\"0x5df1d948\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18485\" file=\"ntoskrnl.exe\" hash=\"a6ed17499a24f0247236eae157f9bfbfeadd1c158957c62a2bcdd7e7d94a3f34\" timestamp=\"0x5e2fd505\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18519\" file=\"ntoskrnl.exe\" hash=\"6c792ca8e00165f0eec125269ed687b27467cb7fe3a63e65f36f988b05939e8e\" timestamp=\"0x5e5f7a02\" size=\"0x00858000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18545\" file=\"ntoskrnl.exe\" hash=\"12103c0877a8153f4a7b49433684a4b6db44c72e26e66d9e327942d4df1570ce\" timestamp=\"0x5e82e998\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18575\" file=\"ntoskrnl.exe\" hash=\"6eec93c5809b4f9958350c4ae16d1235f6aee650659e10bb43d40019f3648c89\" timestamp=\"0x5eb0e4b2\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18608\" file=\"ntoskrnl.exe\" hash=\"108a305775bbe37a19c88676bb3259e63d3e9523285e75bbcdab8d4ab79dd317\" timestamp=\"0x5ed60b76\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18609\" file=\"ntoskrnl.exe\" hash=\"4732dd7b4b6642d2ded0e06c52c54213fb351dfdb35d4d8f1107088983f8f952\" timestamp=\"0x5ee4bc8a\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18638\" file=\"ntoskrnl.exe\" hash=\"3c51eeb02f987e700d7ba7778b9d8e94e7963235831250c26cc6b0c7524c15b4\" timestamp=\"0x5f058726\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18666\" file=\"ntoskrnl.exe\" hash=\"59a5ea630fa4c822df813b07d1e4bd057e0c789bb8c9fe1321245ecaf3006685\" timestamp=\"0x5f2b5885\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18696\" file=\"ntoskrnl.exe\" hash=\"0775d9eb0fe7901fcdf009fd5373f8b77ae3bac686b7ac05b311421c5e2de459\" timestamp=\"0x5f4f4c7f\" size=\"0x00857000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18725\" file=\"ntoskrnl.exe\" hash=\"4a59283cc75b6f740556ebf3823dc00e2b98575d5007d94bb44db159ede8b1f7\" timestamp=\"0x5f741845\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18756\" file=\"ntoskrnl.exe\" hash=\"959017719df099cfd1f98582e33b68810803df6e0480bbabb41fe25e396bd0d7\" timestamp=\"0x5f9a5184\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18782\" file=\"ntoskrnl.exe\" hash=\"8b9ac90e2741978c938b3fb25e55c83f0c5df8bb8dfa27e7dc094ac95881b4e3\" timestamp=\"0x5fc8c259\" size=\"0x00857000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18818\" file=\"ntoskrnl.exe\" hash=\"7ae6465e555c607a2aa3a2375f0d9b29aafadd6bb390f02b42aeed4c08a740ca\" timestamp=\"0x5ff7be26\" size=\"0x00857000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18841\" file=\"ntoskrnl.exe\" hash=\"6da55e214ca4c675f13bb33ffe92bf4af6b46f88a4bc9abe2c62134129d55aa7\" timestamp=\"0x5ffd5008\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18875\" file=\"ntoskrnl.exe\" hash=\"8ffe4ae09df4fe056a651c8baad2ed9fbd643349a2b7b3dcde213dcde141fb94\" timestamp=\"0x60505b5f\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18906\" file=\"ntoskrnl.exe\" hash=\"811a3e69c9e7e0087d465f2ef1703c58fa0d94ffa7f55db00d675c1d85a10ef6\" timestamp=\"0x606ed88b\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18932\" file=\"ntoskrnl.exe\" hash=\"f199ed8e35326af60afa638862eaaa187194e9afd6905d255871034b33f00418\" timestamp=\"0x6087a348\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18967\" file=\"ntoskrnl.exe\" hash=\"7bfda33271dfb651676c0a9f16767a0a8c3c553a863f7f1b1f1d0c05d89acd19\" timestamp=\"0x60bb2970\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.18969\" file=\"ntoskrnl.exe\" hash=\"a9efe38bd5ff72c4a86479d416f0ecb3c7ba55ab130ad0d58d973e9ac03d91f7\" timestamp=\"0x60e13972\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19003\" file=\"ntoskrnl.exe\" hash=\"5615b1f6ee532c186ea92e3b6499440ace778147ec0ea526ed97deeec9ad4da8\" timestamp=\"0x60e31509\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19022\" file=\"ntoskrnl.exe\" hash=\"d008b5f8c302c1599bc809aabdb234977e2dc3ac06106dcd111fa6c68e9afa98\" timestamp=\"0x610503cd\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19060\" file=\"ntoskrnl.exe\" hash=\"55be470960693f676d15b2fc9c196f594235f664b3860d72d11064770d8957bb\" timestamp=\"0x613d7ae5\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19086\" file=\"ntoskrnl.exe\" hash=\"ee6cec733c6cbb461556306dfd15a2383bfecf95a54790f98755a1f9b7b1eb10\" timestamp=\"0x615bfad1\" size=\"0x00855000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19119\" file=\"ntoskrnl.exe\" hash=\"0f39d3bf0251e3dbfc8a7b1ddfbd7bd4ba08acbe0b89cf12a8bc04b9b7174670\" timestamp=\"0x6180ca34\" size=\"0x00855000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19145\" file=\"ntoskrnl.exe\" hash=\"dbf56c146cf3cda988d314aa5d3a8848afcf205bf20e2bdf54d4eb65f2e1537a\" timestamp=\"0x61aaef74\" size=\"0x00855000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19177\" file=\"ntoskrnl.exe\" hash=\"1cf5ee2ef514487ae47aecb4b04ec06b13c5aed1ebdada24b2d6a8fadc7530d4\" timestamp=\"0x61d53f27\" size=\"0x00855000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19179\" file=\"ntoskrnl.exe\" hash=\"03e92d14db79aa55b566ca723831411730aa47c789d0c45619913598d28f71e4\" timestamp=\"0x61e14e0e\" size=\"0x00855000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19204\" file=\"ntoskrnl.exe\" hash=\"23fc22090331ca442c4213138bfb243472ebd92d189697130c0d5dea56f07ed7\" timestamp=\"0x61f4e035\" size=\"0x00855000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19235\" file=\"ntoskrnl.exe\" hash=\"e40105f832b2cd401d0d21afadf76df437b569f0461b94166454cd8949dc1676\" timestamp=\"0x621f0ea6\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19265\" file=\"ntoskrnl.exe\" hash=\"5f2619e54de88a5572343ebd7d6a6d2cd462236edc06e56960da643d0db2b83e\" timestamp=\"0x6244100d\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19297\" file=\"ntoskrnl.exe\" hash=\"6cb07ba92cb8d8ffd5ef0d8b02696ee33a44ef43df36fe0e4ef10aa6d90c20c0\" timestamp=\"0x62708353\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19325\" file=\"ntoskrnl.exe\" hash=\"02fc4ff5430c6f36599b50ab3e4a7c7b1865ba97e077580f0944fbe240e00572\" timestamp=\"0x62a055cc\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19360\" file=\"ntoskrnl.exe\" hash=\"9d56a57202d35a7486d371b32ffacc1413326f39f855cb778752f5192003a98f\" timestamp=\"0x62baba49\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19387\" file=\"ntoskrnl.exe\" hash=\"da66699c87dfd7a14c5d1020a04bc661d1ffa8fdd42f638bd6cdbaef99692844\" timestamp=\"0x62eb66ad\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19444\" file=\"ntoskrnl.exe\" hash=\"7df0678ab02ebaa24cc6c0ec021c717448a4a59e3fcb19221fe0c503c41f252c\" timestamp=\"0x631822a9\" size=\"0x00856000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19507\" file=\"ntoskrnl.exe\" hash=\"777269061d4a23039ff04072c3706757f58ccee709d2182ebafb1f0ff013d1cd\" timestamp=\"0x633afe88\" size=\"0x00855000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19509\" file=\"ntoskrnl.exe\" hash=\"bed93dabeaaedb51fce26b3c655272aad4100d02c1f7ee94110499d9ef96de0e\" timestamp=\"0x63479eb0\" size=\"0x00855000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19567\" file=\"ntoskrnl.exe\" hash=\"6d15a6a3b9d9a4a5be31d560e6a517aca5efe0340cc6df0e222827221e838eb1\" timestamp=\"0x63649bec\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19624\" file=\"ntoskrnl.exe\" hash=\"4759c4b69ff48a6682d4036a4159f254be4dcdb73ea9a599ede25b7cc5c07553\" timestamp=\"0x638843f5\" size=\"0x00859000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19685\" file=\"ntoskrnl.exe\" hash=\"8332eeadc605bec4219331db4c62ef667133e8a7cf82ceafbd7fd5c6685fbd9f\" timestamp=\"0x63b7c154\" size=\"0x00859000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19747\" file=\"ntoskrnl.exe\" hash=\"8673a86c63fee864f7d990e8ee1f4352f436d9d460ecce1ed4c800d40b3a2eb0\" timestamp=\"0x63d8bac7\" size=\"0x00859000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19805\" file=\"ntoskrnl.exe\" hash=\"6d755bee50ca6721e8431ea9310b099c0739745216511f731adda2285ee8b992\" timestamp=\"0x6409bbd8\" size=\"0x00859000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19869\" file=\"ntoskrnl.exe\" hash=\"91602e57d5e9d592cd8a55e3d3a1f2d1f3428955fcad3035d98c6b6dba4fb0dc\" timestamp=\"0x64254355\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19926\" file=\"ntoskrnl.exe\" hash=\"2d64a097af48ad3909ec79828cccf60640e43d21ba57cf7e3725d4c52726327a\" timestamp=\"0x644cb70e\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19983\" file=\"ntoskrnl.exe\" hash=\"f083423b886f01101fcdf3f9d5087ebb0de3fee21c10365ee4db3e0d913f0884\" timestamp=\"0x64783737\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.19986\" file=\"ntoskrnl.exe\" hash=\"a8ab1ac217c01ede2e8ec8a0d41fb6ca65844acaeb06e826e1e42844c2e28f09\" timestamp=\"0x64922264\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20048\" file=\"ntoskrnl.exe\" hash=\"8f83e1783e8995d5a2a6819b480326da42af81084b31a43f5d70f3ab25215839\" timestamp=\"0x64a48fdb\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20107\" file=\"ntoskrnl.exe\" hash=\"350be9f3ab85c3812bb9b3747cb32805b0f2ceec88b669656d6b9398d5da8391\" timestamp=\"0x64cacf79\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20161\" file=\"ntoskrnl.exe\" hash=\"1ed1283581ad84a2c6a17165b2f8086773a1edb086af3ec983e41ea43c7b9b76\" timestamp=\"0x64d3197d\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20232\" file=\"ntoskrnl.exe\" hash=\"8fa956a31ed1349ce48dc27bdce8efeb202a4bde96fa054a57f5f4a27313b2c4\" timestamp=\"0x651f3228\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20307\" file=\"ntoskrnl.exe\" hash=\"eeefa7d41592f72ba534d3395b764e37206d1d77eef0750545da30a0e75f7464\" timestamp=\"0x65463b94\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20345\" file=\"ntoskrnl.exe\" hash=\"e2de66d32f73b5d29715e12256a876ebce665fd2c3b1345b14fcce69ea3eb860\" timestamp=\"0x655c1c36\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20401\" file=\"ntoskrnl.exe\" hash=\"48c418d7fb1e2bb819d19714ed3f2dad20d91f330a5e3e8beaf69934a590cf07\" timestamp=\"0x65813d1a\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20466\" file=\"ntoskrnl.exe\" hash=\"4579ca4ebc403976597b205368179c89f3ae76b3f421f7401c3899a1057c5a76\" timestamp=\"0x65af6220\" size=\"0x00857000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20526\" file=\"ntoskrnl.exe\" hash=\"8fa8b979c165464b9bc530f7e48b8045ed6a061214467d0aeb42f7209f7b4b7c\" timestamp=\"0x65dd9040\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20593\" file=\"ntoskrnl.exe\" hash=\"35aee7f6fc08043e90426d49a69e8687df91356ec22bcf623067b5b29e37f9b4\" timestamp=\"0x6607b035\" size=\"0x00859000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20651\" file=\"ntoskrnl.exe\" hash=\"012715289fda6a23a56c43ade81dc45a66eeef9181835cf711152a092f5ae4b5\" timestamp=\"0x663ac604\" size=\"0x00859000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20680\" file=\"ntoskrnl.exe\" hash=\"fbb4dd7295873f2e8ad0144dc15e039e9b781a53faea03d8ad070584c8e8046d\" timestamp=\"0x666293ad\" size=\"0x00859000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20708\" file=\"ntoskrnl.exe\" hash=\"bffdff5b68b1201a730024cdca841cb9056ea15a33df18a81e1c0f1a5b08f372\" timestamp=\"0x667d1a15\" size=\"0x00858000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20747\" file=\"ntoskrnl.exe\" hash=\"c816bcb7eff4179b3f07d5ade6e89ad058d1d87a18b415f4688838418e9f18c0\" timestamp=\"0x66ac97aa\" size=\"0x00859000\" added=\"2024-09-12T01:41:05Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20761\" file=\"ntoskrnl.exe\" hash=\"ee7e25891edc45f3820ebccb10e7d013aa16936a50d94314f455d73de7e84ce8\" timestamp=\"0x66bda919\" size=\"0x00858000\" added=\"2024-09-24T23:22:06Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20793\" file=\"ntoskrnl.exe\" hash=\"3774af503beffffa7c0c2fcdbe7a6c1bac3e81212218d469e76784040899e945\" timestamp=\"0x66ebbf12\" size=\"0x00858000\" added=\"2024-10-20T15:35:22Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20822\" file=\"ntoskrnl.exe\" hash=\"80c2507d9f0b012952d26be87480bfec53c684a337c1d0449bee7f4b8a4e9d4c\" timestamp=\"0x6717470d\" size=\"0x00859000\" added=\"2024-11-13T15:20:35Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20852\" file=\"ntoskrnl.exe\" hash=\"d50f0acd17b1fef61099ab736bbde22a8b324d78aeb568a58d9ad22a8ec3c866\" timestamp=\"0x67384771\" size=\"0x00859000\" added=\"2024-12-11T14:53:46Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20883\" file=\"ntoskrnl.exe\" hash=\"99c0e9012ac2411b76f7ea55fd67cfcc0d74239fc847d0b64a032fbf794e56da\" timestamp=\"0x675a95c3\" size=\"0x00859000\" added=\"2025-01-16T23:14:03Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20915\" file=\"ntoskrnl.exe\" hash=\"004efe60ef9c87e7248b9efecd9cc1c28da5cfe4e463bce4b34842a58ac80e1b\" timestamp=\"0x679887d0\" size=\"0x00858000\" added=\"2025-02-12T06:18:33Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20940\" file=\"ntoskrnl.exe\" hash=\"efd2c059464bcb332aae98622923e2a315b7dc854caeef5f63a9c4f442e6c217\" timestamp=\"0x67ab0083\" size=\"0x00858000\" added=\"2025-03-11T22:25:17Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.20973\" file=\"ntoskrnl.exe\" hash=\"c2706806c14a35e3ccae395dc1b4d77e3827ad4aedf90372ed147d3f6a933527\" timestamp=\"0x67de48b1\" size=\"0x00858000\" added=\"2025-04-12T23:13:14Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.21002\" file=\"ntoskrnl.exe\" hash=\"732319fb3bbc7dbfc37509656b257fb17546d01a63f36083c0aa5a077097c355\" timestamp=\"0x67f75193\" size=\"0x00858000\" added=\"2025-05-13T22:56:23Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.21033\" file=\"ntoskrnl.exe\" hash=\"848acdce10fe957930401f830135198d21a02306d431cd83cc8f9ff143e870c6\" timestamp=\"0x682c178f\" size=\"0x00858000\" added=\"2025-06-14T19:47:51Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.21072\" file=\"ntoskrnl.exe\" hash=\"d8f7b8320f1138cc3b0499986718b047ddf5c76b729c6edb2b2e785ed146354e\" timestamp=\"0x68638bae\" size=\"0x00859000\" added=\"2025-07-08T22:13:00Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.21100\" file=\"ntoskrnl.exe\" hash=\"60ec0f3e7fe7df266f5490e9a3e721bbb8c4da74646acc477d4e7535aefacbfb\" timestamp=\"0x688db0ad\" size=\"0x00859000\" added=\"2025-08-13T21:37:12Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.21128\" file=\"ntoskrnl.exe\" hash=\"4a017b5e05634e5969dca26d11a32992d0872f9bfe2895bcab55d9223c332d8c\" timestamp=\"0x68b1325f\" size=\"0x00859000\" added=\"2025-09-11T03:22:38Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10240.21161\" file=\"ntoskrnl.exe\" hash=\"48cb578d39c0012f060834c824fa590d6e016c9254ee029556a52d9fc4f8497c\" timestamp=\"0x68e67fc8\" size=\"0x00859000\" added=\"2025-10-16T23:37:47Z\">9</data>\n    <data arch=\"amd64\" version=\"10.0.10586.0\" file=\"ntoskrnl.exe\" hash=\"bbbb647ad2f73cb0e968597e527e6334a8ee4c53e9845ca941bbbccc7d113699\" timestamp=\"0x5632d2d1\" size=\"0x007cc000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.3\" file=\"ntoskrnl.exe\" hash=\"7c6d46d5d0f7b97739165b86c0ac2002a1478d9906466cb0f6096ef569063137\" timestamp=\"0x563b1170\" size=\"0x007cc000\" added=\"2025-01-11T02:34:03Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.11\" file=\"ntoskrnl.exe\" hash=\"b84fb5bac8a41127e728fcf67957b2864c920ee0b606a1992c870bd972b2e0f8\" timestamp=\"0x56457780\" size=\"0x007cc000\" added=\"2024-12-27T01:34:36Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.63\" file=\"ntoskrnl.exe\" hash=\"3c6c5ca2b9c3ea775023332e9c7be93e2a338180fb4b3f65fe09e3879b7a46ed\" timestamp=\"0x568b1c58\" size=\"0x007cc000\" added=\"2024-11-19T23:19:13Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.103\" file=\"ntoskrnl.exe\" hash=\"378356b32f41bf5b72742a1e0528a69ba050b5a0941aac9128be04fbeb63310a\" timestamp=\"0x56a849a9\" size=\"0x007cc000\" added=\"2024-11-05T01:22:32Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.122\" file=\"ntoskrnl.exe\" hash=\"065d4b009fc5f8c48b94d47251beaedcf083c3aba5adeb38f3da137af00d08b4\" timestamp=\"0x56cc074e\" size=\"0x007cc000\" added=\"2024-12-10T02:56:39Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.162\" file=\"ntoskrnl.exe\" hash=\"357847314af084b4202cc90927c73ed4852d88a834ea81913a86c7a8c51d1333\" timestamp=\"0x56cd4410\" size=\"0x007cc000\" added=\"2024-09-19T04:21:44Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.212\" file=\"ntoskrnl.exe\" hash=\"205ac97370d2872aa61410ab1fe64fd82823e3fb67dff5e237496d1ad1101c7c\" timestamp=\"0x56fa1e56\" size=\"0x007cc000\" added=\"2025-03-05T02:47:21Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.306\" file=\"ntoskrnl.exe\" hash=\"a21c08b0a569a4a8c54eca077192dfbb8fc4b105d68ca47aa1bddb6a7ae1b6d1\" timestamp=\"0x571af445\" size=\"0x007cc000\" added=\"2024-12-13T00:14:01Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.338\" file=\"ntoskrnl.exe\" hash=\"5e9c65c31c7397b8051ac5850264cd0fdad11d305b9e11b7755e383722679c92\" timestamp=\"0x573bf4fe\" size=\"0x007cc000\" added=\"2025-04-09T14:22:28Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.420\" file=\"ntoskrnl.exe\" hash=\"e23b0d7e1c1e21b5a5feaf45746c5b3299189b2cce43cc58a59f239c01935597\" timestamp=\"0x5749178b\" size=\"0x007cc000\" added=\"2025-09-26T02:51:04Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.494\" file=\"ntoskrnl.exe\" hash=\"f4294d58fd8ca83adbadb0cb839c87237b4c61eb10d580c58eafde7957eed496\" timestamp=\"0x5775e2f5\" size=\"0x007ca000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.545\" file=\"ntoskrnl.exe\" hash=\"0d053df194556d9512a1a1f538c95430b791eb1535312d616bb3a776ac56cc1a\" timestamp=\"0x57a1b615\" size=\"0x007ca000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.589\" file=\"ntoskrnl.exe\" hash=\"5848067ce27623623bdd51d94c8d855b0294a054ace56a556f0adfc96738b982\" timestamp=\"0x57cf9490\" size=\"0x007ca000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.633\" file=\"ntoskrnl.exe\" hash=\"c98ba4b28612a1f93ef92f498450cecf26019840c89423613669e57fcd930f49\" timestamp=\"0x57f470e9\" size=\"0x007ca000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.672\" file=\"ntoskrnl.exe\" hash=\"7999ad6c6a3b203c1cfe646b3e469468a7861b0ad6c6cc457be51ec07edb15e3\" timestamp=\"0x580ef0e6\" size=\"0x007ca000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.839\" file=\"ntoskrnl.exe\" hash=\"b2f12ce20d770177b5beff408534944db739f5b51553e1f8f9915c8e92d7171d\" timestamp=\"0x58ba3ece\" size=\"0x007ca000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.842\" file=\"ntoskrnl.exe\" hash=\"f3d16ee379e38546d9e611cc1ea9b36762e002541b84d6c1c84e97167ce4cb5a\" timestamp=\"0x58cd6fa1\" size=\"0x007ca000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.916\" file=\"ntoskrnl.exe\" hash=\"fa1405406084a5e3ceb180e0e3e0aa1491ef6c98c8b305f4ed55ec8c4b56e518\" timestamp=\"0x59028f56\" size=\"0x007c9000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.962\" file=\"ntoskrnl.exe\" hash=\"7c6f21a8fdf9d90085dd9ac98b2252341e84a43165cf6e4be28a9e1325ec29c2\" timestamp=\"0x593287ab\" size=\"0x007c9000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.965\" file=\"ntoskrnl.exe\" hash=\"86db83d90a74e3117d6121eaf25f2a2da9d5cf0128438ea9b3a52eb2e39084ff\" timestamp=\"0x5944c7a2\" size=\"0x007c9000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1007\" file=\"ntoskrnl.exe\" hash=\"05ec10e6bf430a7da547db1c17ab77b44fc9dac66fb8e155c6c7f9436a5a7035\" timestamp=\"0x595f32ce\" size=\"0x007c9000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1045\" file=\"ntoskrnl.exe\" hash=\"a2d01d28e6d6916ee0acf56342e65cc88bb1a1c1e1366c8409b66dd4e5d02072\" timestamp=\"0x597c69a1\" size=\"0x007c9000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1106\" file=\"ntoskrnl.exe\" hash=\"e68c3b82fbc2a1844ff4ab5d456464913ccb004416b385bec4d26a55536a157b\" timestamp=\"0x59ae2ed4\" size=\"0x007c9000\" added=\"2024-10-20T15:35:22Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1176\" file=\"ntoskrnl.exe\" hash=\"ffe2882bf8de3c256a43c8d34ad44712e38b2ca1f86c17f0bcdaa92148bec240\" timestamp=\"0x59ba1613\" size=\"0x007c9000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1177\" file=\"ntoskrnl.exe\" hash=\"3f68dffc9cb3b3af698be66f412f9a360ed13045b48ad4ac8d14965c9d074022\" timestamp=\"0x59f3e476\" size=\"0x007c9000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1295\" file=\"ntoskrnl.exe\" hash=\"3d6b6c9dc7229dd56b2e3ee93e66b60dbf1a9db1e73acc36a5c47b5b0d4077e1\" timestamp=\"0x5a2015fc\" size=\"0x007c9000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1356\" file=\"ntoskrnl.exe\" hash=\"33c15ad678543c9cebdd7e2049d90da20fe354a9d5d9037da2b0f2af734d6403\" timestamp=\"0x5a4a6fb5\" size=\"0x007ce000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1358\" file=\"ntoskrnl.exe\" hash=\"fea3186d4c34043a5a82fc21ef29229fece4e7184e2af7f4d73b06c7b161b348\" timestamp=\"0x5a5bcdea\" size=\"0x007ce000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1417\" file=\"ntoskrnl.exe\" hash=\"3f68e6909da1a0b80b6e73bc60340d7f10446f0bdeb30dd9e27510eac34a1849\" timestamp=\"0x5a7e7dbe\" size=\"0x007ce000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1478\" file=\"ntoskrnl.exe\" hash=\"7944a6b142a11f787276f9c4d7c96a6de411f9727ea8cd34e3165bf3efcc29e5\" timestamp=\"0x5a979643\" size=\"0x007ce000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.10586.1540\" file=\"ntoskrnl.exe\" hash=\"b59339803bc68ba5a22687dad8e8594309d09f07213bcbd671486b0bd6270fca\" timestamp=\"0x5ab4a103\" size=\"0x007ce000\" added=\"2024-09-12T01:41:05Z\">1</data>\n    <data arch=\"amd64\" version=\"10.0.14347.1000\" file=\"ntoskrnl.exe\" hash=\"9fd9e33c728a0c06080579af84b77a4a2c0cea6dd07f098a4364362c63fb01e7\" timestamp=\"0x5736956a\" size=\"0x00814000\" added=\"2025-06-18T01:25:23Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14347.1000\" file=\"lxcore.sys\" hash=\"bced9f821ea43143191789d770e2de710a11f82a80fcd6660fc0df24a8191cea\" timestamp=\"0x57369667\" size=\"0x000c0000\" added=\"2025-06-18T01:25:23Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.14393.0\" file=\"ntoskrnl.exe\" hash=\"dc7c834054d80629c1f643599914c3824b05d933b50087cd82d26b5f844158c5\" timestamp=\"0x578998f1\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.0\" file=\"lxcore.sys\" hash=\"c82cfba4b2d6f68e2f3047d5b683890b956c5af2879b3c2c74a61b018975096c\" timestamp=\"0x578999d2\" size=\"0x000c6000\" added=\"2025-05-17T15:31:20Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.14393.51\" file=\"lxcore.sys\" hash=\"47358b3a645125e0a96e6d718278f6ec10bed9e411268d3596a9b3a092dc482d\" timestamp=\"0x57a053bf\" size=\"0x000c6000\" added=\"2025-05-17T15:31:20Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.14393.82\" file=\"ntoskrnl.exe\" hash=\"c4a6045fff943112c4e05d908a4dfbf6b0b32af036bcb1eb69f419dc0bf396b2\" timestamp=\"0x57a558b9\" size=\"0x00820000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.103\" file=\"ntoskrnl.exe\" hash=\"b82caed53887889a6fa93483010bb7f39a335526310f0e1ce852b09f5c6a529e\" timestamp=\"0x57b7e3c6\" size=\"0x00820000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.187\" file=\"ntoskrnl.exe\" hash=\"ff77bae296130f3b8e5a367971fa2dee689392ed6c52694912248b553864305c\" timestamp=\"0x57cf9a34\" size=\"0x0081f000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.206\" file=\"ntoskrnl.exe\" hash=\"ee16a0234b518408a28c14b7793654ea26d0593f42f7bcd322844bad97ea0aab\" timestamp=\"0x57dacaa7\" size=\"0x0081f000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.206\" file=\"lxcore.sys\" hash=\"59319ed630e631fe34dc5108dfe11d13a261d9bdc625123393040ea2b85d1067\" timestamp=\"0x57dacbc8\" size=\"0x000c6000\" added=\"2025-03-14T04:05:46Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.14393.321\" file=\"ntoskrnl.exe\" hash=\"44c31fb7154a7a1dd183e8d9d709ccd8be2817d6c50eca12cc9928184f03f00b\" timestamp=\"0x57f4c541\" size=\"0x0081f000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.321\" file=\"lxcore.sys\" hash=\"d34402340a2bcdc19c3abd2ee5a10686c641e24e3207bd115b7a27f6adf082ac\" timestamp=\"0x57f4c63c\" size=\"0x000c6000\" added=\"2025-03-14T04:05:46Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.14393.351\" file=\"ntoskrnl.exe\" hash=\"795fa6667bec9afa40193d02f7e084d9999f7bcc30887f1fb333c4d2b91545c3\" timestamp=\"0x5801a4be\" size=\"0x00820000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.447\" file=\"ntoskrnl.exe\" hash=\"07de2c1c4cb497a0cf53f71c6947149f5d3e3e4e49357654b3c490ee4a63627e\" timestamp=\"0x5819bd1f\" size=\"0x00820000\" added=\"2024-09-12T01:41:07Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.479\" file=\"ntoskrnl.exe\" hash=\"e8b265c572155fa2f7725bf01f924868101ca635f3e956e65ede90e34e583ce7\" timestamp=\"0x582589f4\" size=\"0x00820000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.576\" file=\"ntoskrnl.exe\" hash=\"1a30518ce61100331cad5944ad2892227c275615f89b7286c7ca0d2c719d9d49\" timestamp=\"0x584a77f6\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.693\" file=\"ntoskrnl.exe\" hash=\"d4bc16b546838dd59d00f4c8fe87ce5d2ada41b10d57487628f909272ca360f5\" timestamp=\"0x585a2651\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.726\" file=\"ntoskrnl.exe\" hash=\"02dc548918fc66c71d5a614f7a9753ce92db74465af2ef16ef0ac5d612e567aa\" timestamp=\"0x587857e7\" size=\"0x00819000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.729\" file=\"ntoskrnl.exe\" hash=\"c995a9497702cf5f7f537be9da1ed559e26d59d0335147f6df63a544821a5318\" timestamp=\"0x5886d72a\" size=\"0x00819000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.953\" file=\"ntoskrnl.exe\" hash=\"6bd3acb607fe6a089b0efdcf15a05b3f5d2e345a4756e8ccf47ce38ec29ab40d\" timestamp=\"0x58ba5a34\" size=\"0x00818000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1066\" file=\"ntoskrnl.exe\" hash=\"f3fc691ea0be0212ef1f6c427ac4b1b74f3dd2524baf0e1adf1dac5c942682de\" timestamp=\"0x58d9f097\" size=\"0x00818000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1198\" file=\"ntoskrnl.exe\" hash=\"6a000942b9d09673544df95f051b973f7bdfe46f7ae985d06b47f2aa4c923739\" timestamp=\"0x59028118\" size=\"0x00818000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1358\" file=\"ntoskrnl.exe\" hash=\"cb6ada3f394686ee1ac2e818a654c9fb13721d9bb974e68cf1bc0c72dbb39f2b\" timestamp=\"0x593278b1\" size=\"0x00818000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1480\" file=\"ntoskrnl.exe\" hash=\"181a596d018326ad9306cc3b6a64aabd33e794a9f35247561322837d831c4a52\" timestamp=\"0x595f2981\" size=\"0x00817000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1532\" file=\"ntoskrnl.exe\" hash=\"d442c083201de639258c3dfe3010675a864106f997174f3c4386c848633ed074\" timestamp=\"0x5965acca\" size=\"0x00816000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1537\" file=\"ntoskrnl.exe\" hash=\"dd7dc6e5d0abfeeec3bdd57795e1976765290a8416bebe82611921c5ccf6d7db\" timestamp=\"0x598007f6\" size=\"0x00816000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1593\" file=\"ntoskrnl.exe\" hash=\"aa88c1a0c98359bc487f20461d2904c397d924f13c3997ce1148d2a7c7416b2c\" timestamp=\"0x5980c87e\" size=\"0x00816000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1613\" file=\"ntoskrnl.exe\" hash=\"cf4bbd506a0e0b5669b619fce2195571fa4b27493929ab8da6e403fb15ab5520\" timestamp=\"0x5989449b\" size=\"0x00816000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1670\" file=\"ntoskrnl.exe\" hash=\"b20380ac4478b5c53d1222e01d18d518751fbac92e6d563cc7b358713a3723c7\" timestamp=\"0x599bb691\" size=\"0x00816000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1715\" file=\"ntoskrnl.exe\" hash=\"a47868cd64e682473e3b153548e384be2c75c1bb96186b8ae58794368bfa4a1c\" timestamp=\"0x59b0d121\" size=\"0x00816000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1737\" file=\"ntoskrnl.exe\" hash=\"c291b716e5599a61aa2a55022c6d05b0f7984fad6d7ef900421cbc181f5b6e9a\" timestamp=\"0x59bb0133\" size=\"0x00816000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1770\" file=\"ntoskrnl.exe\" hash=\"1eb8ef201c2666e64c5b3b12885d0c1df9f71d87612cbaa40fdeb364ba71397e\" timestamp=\"0x59bf2c68\" size=\"0x00816000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1794\" file=\"ntoskrnl.exe\" hash=\"8796c37c1a8ad00ab0c63e545fe2450ad5817e69ce6bf8246d5ca2fdda193595\" timestamp=\"0x59dad4c8\" size=\"0x00816000\" added=\"2024-09-23T21:48:53Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1797\" file=\"ntoskrnl.exe\" hash=\"06d2cd70e18f04b19e096118dd1457ed891af8db1f78f3d95c1e327552148bbc\" timestamp=\"0x59f3f589\" size=\"0x00816000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1914\" file=\"ntoskrnl.exe\" hash=\"7192722450b7c3090ee2ddce427afd5738ebd1bfb5965ecebdf26adfa133211c\" timestamp=\"0x5a0fa965\" size=\"0x00816000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.1944\" file=\"ntoskrnl.exe\" hash=\"5c2f92ec6d0857075202d7c079653477b4b3bfc8fe1ac8674cbcc6797a7677f0\" timestamp=\"0x5a1fb46d\" size=\"0x00816000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2007\" file=\"ntoskrnl.exe\" hash=\"698ca1a85d067a6a91adb87e8b6fcfdeea45aba8078910d6b8bad133f7507dbb\" timestamp=\"0x5a49bb2b\" size=\"0x00822000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2007\" file=\"lxcore.sys\" hash=\"df97cc9d50c8f8ead2a92d30340b14cfe7dfe449435c79d084a516e3ef2a3789\" timestamp=\"0x5a49bca9\" size=\"0x000c6000\" added=\"2025-03-14T04:05:46Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2035\" file=\"ntoskrnl.exe\" hash=\"0c649f8db07b247df63e923faf93296059e47d5b42ad8fc0666e12d2bb11a39e\" timestamp=\"0x5a57008b\" size=\"0x00822000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2068\" file=\"ntoskrnl.exe\" hash=\"b158f0c175e89f4186f300b34f19f86eb87f83144990a62af314af2c8e5640d4\" timestamp=\"0x5a7e6e98\" size=\"0x00822000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2097\" file=\"ntoskrnl.exe\" hash=\"ac55d266c1198b5394f4224bd2bbf78a650b9e60708f9488e49bfd8c1c63faa9\" timestamp=\"0x5a820af0\" size=\"0x00822000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2125\" file=\"ntoskrnl.exe\" hash=\"9313cb275ef21c03faa12c61ba41ee1c39aa0e482431ded305e4ef268efd56e7\" timestamp=\"0x5a9907c8\" size=\"0x00822000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2155\" file=\"ntoskrnl.exe\" hash=\"16abbf20cc788021907a714cc5a707dc9fe53880ff2ae9d0e9e18903f898b679\" timestamp=\"0x5a9e2286\" size=\"0x00822000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2156\" file=\"ntoskrnl.exe\" hash=\"a7b6df7ae17723bf47d18e4dd8d7cc5b141fcc7715e062636951b09fd680dd20\" timestamp=\"0x5ab31a98\" size=\"0x00822000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2189\" file=\"ntoskrnl.exe\" hash=\"5af28ef158dc54b7f1ccbed8fb681ca5477c2ee81a585a8459bb22883760f594\" timestamp=\"0x5abdae10\" size=\"0x00822000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2214\" file=\"ntoskrnl.exe\" hash=\"4619c46b4a2b92d68bbd891441fb51fe23f010da38e143061f5b56f35faeb7cc\" timestamp=\"0x5ac2f6d4\" size=\"0x00822000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2248\" file=\"ntoskrnl.exe\" hash=\"6ec2fa6a0ff893056be981bef2d7a7f64920c19174eb35e60dac12123d42cd1a\" timestamp=\"0x5ae3f92a\" size=\"0x00821000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2273\" file=\"ntoskrnl.exe\" hash=\"872baef44d370d7ed3b69126eba06fcb93b0681804ba948ead512863d067ee9b\" timestamp=\"0x5ae4097e\" size=\"0x00821000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2312\" file=\"ntoskrnl.exe\" hash=\"fc2fdf4ff38e5492654172f26cdc890864f87787283e8e03b0e5950c9231c1fa\" timestamp=\"0x5b1a16df\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2339\" file=\"ntoskrnl.exe\" hash=\"db61ff22dcd23bb620b81e30aa01d4a787ac3eba9e95734fe4b182b3b1ec750a\" timestamp=\"0x5b1f16e0\" size=\"0x00820000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2363\" file=\"ntoskrnl.exe\" hash=\"f43e0a2d7a32938147402c1849e28f949c8db6b9de02fd9e6fe9856efdbf3de9\" timestamp=\"0x5b31adcd\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2368\" file=\"ntoskrnl.exe\" hash=\"0bd834e2ad5a3eb35b50d8b3abb2afcf5e1ed0daf70a239b28904403cbe50510\" timestamp=\"0x5b482579\" size=\"0x00820000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2395\" file=\"ntoskrnl.exe\" hash=\"99a3682ad2c26c1106d9777ff5db945fd7aa72fa4842ec8b4b4e748e0af52274\" timestamp=\"0x5b4ada64\" size=\"0x0081f000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2430\" file=\"ntoskrnl.exe\" hash=\"d3643254cb4439a6ab3343397b404d2f1c36a1ef6c037ecb931feefab4b35799\" timestamp=\"0x5b691a9f\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2457\" file=\"ntoskrnl.exe\" hash=\"6d6af9d315af9cb9bed59c1d283a1a9c740332fe69e42c79e0c4b0f25abdb9ed\" timestamp=\"0x5b7e2b24\" size=\"0x0081b000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2485\" file=\"ntoskrnl.exe\" hash=\"02229a8360e1ad2d5169992a3e7f6b270fec10aeacc0f34dc616d99d04c43dfe\" timestamp=\"0x5b84c516\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2515\" file=\"ntoskrnl.exe\" hash=\"f756a88cdcdf9227def146bd55a4802ef062081fcf6a25382be015bd8585cfa4\" timestamp=\"0x5b885460\" size=\"0x0081b000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2515\" file=\"lxcore.sys\" hash=\"750287c11a7d15d04bf8783c4a7e39e6026317e2d1f3056fd0db1bd344e57fa6\" timestamp=\"0x5b88568d\" size=\"0x000c6000\" added=\"2025-03-14T04:05:46Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2551\" file=\"ntoskrnl.exe\" hash=\"c9e95694f241ae65074625dcdb44bc39d08ee528fb5fbf5034341f8e13563172\" timestamp=\"0x5bb696f0\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2580\" file=\"ntoskrnl.exe\" hash=\"b36486cd18adad1bc13af9a643184a55e0d9119e67eb6b7e1557d2b10499bf71\" timestamp=\"0x5bbdad57\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2608\" file=\"ntoskrnl.exe\" hash=\"e7b697b76807d1a9f6b3e9ad0e61b277699e15beef6b7ff34eb29a19c18450ef\" timestamp=\"0x5bd13460\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2636\" file=\"ntoskrnl.exe\" hash=\"15265f4b8c503b643f76f93ba4da38659ea9eb44b2f88a8025cdc2418e63cfbd\" timestamp=\"0x5bda7f77\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2665\" file=\"ntoskrnl.exe\" hash=\"f9ec80e2bf499c06127cda3ce0cd8e5aaf2b86691402b1016365929b563ef051\" timestamp=\"0x5c060d4a\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2724\" file=\"ntoskrnl.exe\" hash=\"084a7d7f054142016836acfc9a69ce9efe107d78642806a82f0b8ce1f7ce76cc\" timestamp=\"0x5c2af2cb\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2758\" file=\"ntoskrnl.exe\" hash=\"e10b3449965e3fe717668bdd3293506211f7436808441aafa7ef2d0aedabcfb9\" timestamp=\"0x5c304972\" size=\"0x0081b000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2791\" file=\"ntoskrnl.exe\" hash=\"e29c7371f649e3e7a7eb57dd89bde3dea022f0d70c4e20d4eb8ec34654a9dee2\" timestamp=\"0x5c5a4230\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2828\" file=\"ntoskrnl.exe\" hash=\"d82c58a8f4240da0fa312e42c548af78e8ab876b8fa7aeb2ae6f9d013b638434\" timestamp=\"0x5c68bf31\" size=\"0x0081b000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2848\" file=\"ntoskrnl.exe\" hash=\"d8025e2722c2e5f6501bcdb70a1b1f97626d277c5b1a08aa688cd7c1d5b2ccf8\" timestamp=\"0x5c7f630b\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2879\" file=\"ntoskrnl.exe\" hash=\"0d287362c1859615c60126ad01bae034d693b42bb1a9d0443cf94e204b3ce18e\" timestamp=\"0x5c89eacb\" size=\"0x0081b000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2906\" file=\"ntoskrnl.exe\" hash=\"093b432bb0691edc66430145d59b7d6c1ca69587d8d54bf5eeb21dda8fd5a54a\" timestamp=\"0x5ca2e100\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2969\" file=\"ntoskrnl.exe\" hash=\"badcddd79ea0e91b43e492dd391125184edd53cb6c9b3f6c6f0826e18c8a7891\" timestamp=\"0x5ccd1534\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.2999\" file=\"ntoskrnl.exe\" hash=\"2a8569378ce84fc0aa2507c820950f25f181d01f91b206828e14241d609c0714\" timestamp=\"0x5ce36ce6\" size=\"0x0081d000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3053\" file=\"ntoskrnl.exe\" hash=\"5dc3788194f2a99644d016d2196570d2d430d2f5f1aabfa6e2d00e2015f7b06b\" timestamp=\"0x5d01d0bf\" size=\"0x0081d000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3085\" file=\"ntoskrnl.exe\" hash=\"b0ea4ddb4d78996bc5ff3ec8ffc06c6f228be335b1dc971dad3d45ea541f5883\" timestamp=\"0x5d1d7d1e\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3115\" file=\"ntoskrnl.exe\" hash=\"bd19877d53bacbe544d5d625aafdbfbf8dd6d67efd7d180b78048dedc00c7deb\" timestamp=\"0x5d24060b\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3143\" file=\"ntoskrnl.exe\" hash=\"01acf405a67a0f39440452c9edf52948f4610a5d84a304d50ed2eba3f0289b4a\" timestamp=\"0x5d3a720f\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3179\" file=\"ntoskrnl.exe\" hash=\"a73d7b15d980a870b1ffe2fcd5b0766f0d346b5f238261ee22fb623463d782b9\" timestamp=\"0x5d4a9099\" size=\"0x0081d000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3204\" file=\"ntoskrnl.exe\" hash=\"2ad264672f4462e7f8fd0e9cfa3430c63eda2102af7387a00b296b1c475833f7\" timestamp=\"0x5d69c6b2\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3241\" file=\"ntoskrnl.exe\" hash=\"2ec2a321f7021c9b4baeb53f63eea52b9c29fe87045939cb01f7f383ab853650\" timestamp=\"0x5d786ca6\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3269\" file=\"ntoskrnl.exe\" hash=\"aa8b78f25f77e2905c29b03d75759c44497fb1234cb675ae0aa818daf4784a62\" timestamp=\"0x5d91345a\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3297\" file=\"ntoskrnl.exe\" hash=\"961e2ba4756c8c977b420de48743d6bf120dd98ad69c2c13afcf3a07a05943ca\" timestamp=\"0x5d93b99b\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3321\" file=\"ntoskrnl.exe\" hash=\"fb891bd5e4c6563b73d90aaec56eefff7170d048bb591b79b9cad84da8dcc10e\" timestamp=\"0x5da7fe4c\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3383\" file=\"ntoskrnl.exe\" hash=\"d391a9a805ad9d7fac28e6bd1ee05da39605bc0de0130c5f3155a88834d0b1b0\" timestamp=\"0x5ddcba81\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3442\" file=\"ntoskrnl.exe\" hash=\"85070dc0305e8455d5518a49cbfabe935cffddfb34f94702b3030bdf9dcc582e\" timestamp=\"0x5dfc4c1c\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3471\" file=\"ntoskrnl.exe\" hash=\"dc880ca431d38b9edd33c10f9f7d008b9dc24be024b4e23c25f230ac21648ca3\" timestamp=\"0x5dfaf8bd\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3503\" file=\"ntoskrnl.exe\" hash=\"f285b37d58dae3feb8643d649770f9b8b5af43067f3cf61d2177f1bf1b9f1335\" timestamp=\"0x5e348348\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3541\" file=\"ntoskrnl.exe\" hash=\"57795824662ecd7cef29ddfb7f3c0d210506dbe204db59f474ab007e9e64c9c8\" timestamp=\"0x5e4ce982\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3564\" file=\"ntoskrnl.exe\" hash=\"1deac109cbb2de37d69e606cc8e46eedf3c1e6aea3cb6032d581048a2e232191\" timestamp=\"0x5e5f4d4a\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3595\" file=\"ntoskrnl.exe\" hash=\"f1d57c540a6414ad7530b2e7b3c340928f6c63ea61231e5add2296ff00c20df6\" timestamp=\"0x5e6afb54\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3630\" file=\"ntoskrnl.exe\" hash=\"78d9d880a785261dc2e18c42bae58ed9b7734e49da5508bc59c58af30a380939\" timestamp=\"0x5e8d4434\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3659\" file=\"ntoskrnl.exe\" hash=\"fba7c3b05e4ff2512a50741c2ba9e594d7d32fe73ca01cd095f4d37f4fc388d8\" timestamp=\"0x5e914159\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3686\" file=\"ntoskrnl.exe\" hash=\"7e50d19b89b4b29259625b58f5eb4696b37eef69820c2227ab2a19457187f836\" timestamp=\"0x5eb0bf5c\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3750\" file=\"ntoskrnl.exe\" hash=\"3e6bc795489d1fb7ff24de1890ceabdd38fd50bf2128566e8b871cf8a1c9fbd2\" timestamp=\"0x5ed5dcec\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3755\" file=\"ntoskrnl.exe\" hash=\"304b5dcfcbd784ff0e7d71e94a33d4e8619cfbaed076bfc325e9c0eafb3fc4ed\" timestamp=\"0x5ee813e6\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3808\" file=\"ntoskrnl.exe\" hash=\"05c25bed8a84ef27abce25bae29b2a10b8c2af84902bae08019fa87e4447208b\" timestamp=\"0x5f056c45\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3866\" file=\"ntoskrnl.exe\" hash=\"a60f463897b50da89df46124b5234dd49e42b47f2982aa8d7c6d81f73a57d711\" timestamp=\"0x5f2c7f65\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3930\" file=\"ntoskrnl.exe\" hash=\"e36292576e411c2ebe1a940be2e4def0c25f8c451e0cd6e4b372436a156e1fb0\" timestamp=\"0x5f4f303d\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.3986\" file=\"ntoskrnl.exe\" hash=\"0716429c2eb7526bd96b0a6224a859db4e6eef9254510bc75ea02b4bee7121f5\" timestamp=\"0x5f77fdc2\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4046\" file=\"ntoskrnl.exe\" hash=\"9e30e6bbb7d1e58f398b3e64256230b39ddfcdcd047016d8f559dbdf988923e0\" timestamp=\"0x5f9a3f10\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4048\" file=\"ntoskrnl.exe\" hash=\"a8b168ecf6d2106fff5787b2d806e4d48e5852511b6009b74fb13e3b21111134\" timestamp=\"0x5fb1ce3f\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4104\" file=\"ntoskrnl.exe\" hash=\"eb8e4e7dc016848ddf025aee06ee2d82240e07794697de66f76a50723382e8e7\" timestamp=\"0x5fc86d17\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4169\" file=\"ntoskrnl.exe\" hash=\"5fadcc2d2c8f90727ef686f6418f470957c0a82ff2ca57d2d4610d45445fd8b4\" timestamp=\"0x5ff78d49\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4225\" file=\"ntoskrnl.exe\" hash=\"2d12817c19b08e835192614863e95b2d9b5adfb3307d28faf8b0ee42c6198057\" timestamp=\"0x60124475\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4283\" file=\"ntoskrnl.exe\" hash=\"875d16c6eac066a553598f24cd9e4a96df4bbc2c1f1020f091b21714d0cdd800\" timestamp=\"0x604068c0\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4288\" file=\"ntoskrnl.exe\" hash=\"48347b124e4f6c783d3108942beb7dc420d06e81fc9b6addbf0365d81bb0ab7e\" timestamp=\"0x60503c70\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4350\" file=\"ntoskrnl.exe\" hash=\"50e80686b4eb9e6a587c02f1ffaf0f7073b2b2b5165dcd0dbcf0b0427904f8e3\" timestamp=\"0x606eb01c\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4402\" file=\"ntoskrnl.exe\" hash=\"a370b2f2d46af560c24b3f7fe170d6efca8cf94b06f89185b3aff61e77e591a6\" timestamp=\"0x608795e4\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4467\" file=\"ntoskrnl.exe\" hash=\"7cb9156e52b1c1c1391db3baa6850778609ea6c74f63d1a6e017e3ed92d4f3fc\" timestamp=\"0x60bafe8c\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4470\" file=\"ntoskrnl.exe\" hash=\"2e6b1225b59c35f7ce3b597f2f1bbfd3fa18a821c9f4f3fbf6f8149dc5811b90\" timestamp=\"0x60e2663b\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4530\" file=\"ntoskrnl.exe\" hash=\"69fe243046d5417d7ecdf04cf73f089937c243aec24238cef3890b63219f3032\" timestamp=\"0x60e33d5a\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4532\" file=\"ntoskrnl.exe\" hash=\"ba1cfe5506465b51a85a744bcfae88ff28e24a4f4f488230c2c495a993d19a7d\" timestamp=\"0x60ff1d36\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4583\" file=\"ntoskrnl.exe\" hash=\"170d9100f8f8b0d793c8e0530e396d3e2e83aa56cac0e4c89eee93e6526871ed\" timestamp=\"0x6104d5bb\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4651\" file=\"ntoskrnl.exe\" hash=\"25907704155a98c9e5a1def1303ece6af1a06637f4751b53238445609cc4cb2e\" timestamp=\"0x613d5de3\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4704\" file=\"ntoskrnl.exe\" hash=\"38f21b0035f64dcd357369f0f5b7e86df9ce647e5324cac2299b62fe71af585b\" timestamp=\"0x615bdfdd\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4770\" file=\"ntoskrnl.exe\" hash=\"67d5473491a59286794f1eaad658886d3142b13e21bdec97dd052b5b7d109300\" timestamp=\"0x61808917\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4771\" file=\"ntoskrnl.exe\" hash=\"8fe9a45f828d3c20dd7bc3a788e86a2f647fea2bec4385defab1ae5648fab302\" timestamp=\"0x618d724f\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4825\" file=\"ntoskrnl.exe\" hash=\"924141156dec9770b4bd29dff6facf33b7d2cbe9ed39bdb43f1b1f18177021fc\" timestamp=\"0x61a98ebc\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4827\" file=\"ntoskrnl.exe\" hash=\"2834cac27c2f4d630381731e610058e24a5c3999f5c56ccda246a431eee604d1\" timestamp=\"0x61ce9d5e\" size=\"0x0081b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4886\" file=\"ntoskrnl.exe\" hash=\"02144498ea8f8da7a443f8c514945b2b9d9c8cf13ed12867cbaeaa1939141e4b\" timestamp=\"0x61d523cb\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4889\" file=\"ntoskrnl.exe\" hash=\"d7c3c658b5f23b8a260471eca703003c69bda3ba245a56553669c41c505ca71c\" timestamp=\"0x61e25143\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.4946\" file=\"ntoskrnl.exe\" hash=\"a46e420bc6b96f2ac217a0d591a8e5109b3d6ceac9fe454a45a02bbd64278ddc\" timestamp=\"0x61f82cd3\" size=\"0x0081c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5006\" file=\"ntoskrnl.exe\" hash=\"e0f291b588c78441db21e8395b58c0c1cd284d83a5650cae85c789b80b467639\" timestamp=\"0x621ef34d\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5066\" file=\"ntoskrnl.exe\" hash=\"fab5414b91053288e26cb21153e21f27918ef687b91f4afd5aabeef54c9aa1ea\" timestamp=\"0x6247cb82\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5125\" file=\"ntoskrnl.exe\" hash=\"699bfb4ccd1e46a1b70d1fa8b9c110546659facdd6edc71b0271b0cfa6822c2f\" timestamp=\"0x626ca997\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5127\" file=\"ntoskrnl.exe\" hash=\"24e2d845a87bfe41d644318bb757a6cd6b2b74557e1878ed51f30866084bfafc\" timestamp=\"0x62807143\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5192\" file=\"ntoskrnl.exe\" hash=\"3bcfa88e468620c18ea255fe299346a53c1a76d15e9c1195c672c241ad78a862\" timestamp=\"0x62a3f3d8\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5246\" file=\"ntoskrnl.exe\" hash=\"ccf3561323372a1b38b0b8a53c851c9da07205698b9ea34f0c51534653687ab5\" timestamp=\"0x62bfb76a\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5291\" file=\"ntoskrnl.exe\" hash=\"88ac1a9ca4640c04b3fd4e2bc95f870282db4e6d08c750d66da78ffc1fabc6c2\" timestamp=\"0x62ef02ae\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5356\" file=\"ntoskrnl.exe\" hash=\"4cf14412ce57dab7509e0154d457a0db9649040f924f28fa48469bb43e12824d\" timestamp=\"0x6317bd49\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5427\" file=\"ntoskrnl.exe\" hash=\"286180b6de41e400a7acff2897cd44540210c77d23f3a0c5eb4b28efcbb6e2d2\" timestamp=\"0x633689ae\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5429\" file=\"ntoskrnl.exe\" hash=\"62fb3fb4b285d26fa0c19ee0f755d416ee7cd58211668e5a7026b6a60540e30b\" timestamp=\"0x6347ba62\" size=\"0x0081d000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5501\" file=\"ntoskrnl.exe\" hash=\"7d70960b6751244be0e5f203d7c342c078fe5cfbab3b8dd794af51fe99a5411e\" timestamp=\"0x63647ac0\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5502\" file=\"ntoskrnl.exe\" hash=\"928505aca6b1f4d19d2d0f989ae8a47003812168d3b18baa28f9f384282254d0\" timestamp=\"0x63730f91\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5582\" file=\"ntoskrnl.exe\" hash=\"e14f559795c782f269ca151529a15ec2fd2cad8fd6d7ae4fa9248ee83dc6282c\" timestamp=\"0x6388231f\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5648\" file=\"ntoskrnl.exe\" hash=\"82a9178ebd9bd725936064b03e63e23dcc0c24ff052556aa0179a66c1cda7cdb\" timestamp=\"0x63b79298\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5717\" file=\"ntoskrnl.exe\" hash=\"5e17eb940d57280fe7a62d25d4db6a5e406a4d610dba7f15bc8be7f839e6b2bd\" timestamp=\"0x63ddda17\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5786\" file=\"ntoskrnl.exe\" hash=\"804cd2a5bb767a3b4cbd3926532a4685038fbf739a59abd895b7c5e6524cf3ce\" timestamp=\"0x640990fa\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5850\" file=\"ntoskrnl.exe\" hash=\"debde59612e02a9a72f599ad02e2e9b95a24d743b357a340dbc2fad810f3dd70\" timestamp=\"0x64253b6e\" size=\"0x0081f000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5921\" file=\"ntoskrnl.exe\" hash=\"87abd81e8112af60a088f0ea018bff6b22b32e31b111cf06475191207646caec\" timestamp=\"0x64546818\" size=\"0x0081f000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.5996\" file=\"ntoskrnl.exe\" hash=\"b3ce3fbf9973ff46ab7b4ec137b074fb063cee2faefb6de3314d887285baa3c3\" timestamp=\"0x64921dfd\" size=\"0x0081f000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6085\" file=\"ntoskrnl.exe\" hash=\"2cea77e84f0006978125642ac23265ec345902b259d56fa534023709ee43d4cb\" timestamp=\"0x64a45235\" size=\"0x0081f000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6167\" file=\"ntoskrnl.exe\" hash=\"bd22c7e13da39184ac9c41bedb09cee5a969979da3508b1ebc21c3720bb7fd99\" timestamp=\"0x64caa5cd\" size=\"0x0081e000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6343\" file=\"ntoskrnl.exe\" hash=\"4b90fd10976f59f98b9f07db84843ca379f5b462741d297e327d1d5d9c9a3dd1\" timestamp=\"0x6502812c\" size=\"0x0081e000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6451\" file=\"ntoskrnl.exe\" hash=\"138f329cfb8340fbc5bf6ef5863e8946ad50f4d37d074ea2e08240f078c373f9\" timestamp=\"0x6545b4ab\" size=\"0x0081f000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6522\" file=\"ntoskrnl.exe\" hash=\"5a07d7e996eb5f9491dbcb6bd1063d166a1524192a026531206c330212350e36\" timestamp=\"0x6552f593\" size=\"0x0081e000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6611\" file=\"ntoskrnl.exe\" hash=\"cc6c2d93da842aa35048340e0885bde8062b795165c4ae312cf7d8ebf37780da\" timestamp=\"0x658115ac\" size=\"0x0081e000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6707\" file=\"ntoskrnl.exe\" hash=\"83040c9542b35cac5456e837c0287ad2457bc93686c028c46340dde8614c8919\" timestamp=\"0x65af3a7c\" size=\"0x0081e000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6795\" file=\"ntoskrnl.exe\" hash=\"fd69b3d9b4ad22a01542498137dbc962dd78c842192a9c807f0c6a16f933f3e5\" timestamp=\"0x65dd65d2\" size=\"0x0081f000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6897\" file=\"ntoskrnl.exe\" hash=\"ea14ada3e725070b3779e1e51175318605c4b1e7442954757ea1c3c294175c1c\" timestamp=\"0x660f5f28\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.6981\" file=\"ntoskrnl.exe\" hash=\"2ea1611effba41fed7feb7b0c485bd992c4cd3c1933dd3aebf90c683da80ef99\" timestamp=\"0x6635b67a\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7070\" file=\"ntoskrnl.exe\" hash=\"b813d5aaad910281eb33d25bdb6423789f48b5fc2b35bac8e2418a468580d94f\" timestamp=\"0x66626a96\" size=\"0x00820000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7155\" file=\"ntoskrnl.exe\" hash=\"dfd0308f3f936b5420933cde7fb5ffb3e9c0fabe507fae48c980457d8d32408c\" timestamp=\"0x667a37ec\" size=\"0x0081f000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7254\" file=\"ntoskrnl.exe\" hash=\"0552cfc3a14f5f1da40df3e0279e18f9a2ac9ae4805f6b4b939125c6700e13ee\" timestamp=\"0x66ac6f9d\" size=\"0x0081f000\" added=\"2024-09-12T01:41:05Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7330\" file=\"ntoskrnl.exe\" hash=\"47b594c9cff6a9988dfaee89420bb8dc157258605bde21319169b5c3a3cae055\" timestamp=\"0x66bad343\" size=\"0x0081f000\" added=\"2024-09-16T00:33:18Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7330\" file=\"lxcore.sys\" hash=\"2c397730c089d4ac7cb0f744922d0de8f5ebe160cba0d882d61b524e2c16e927\" timestamp=\"0x66bad598\" size=\"0x000c6000\" added=\"2025-03-14T04:05:46Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7426\" file=\"ntoskrnl.exe\" hash=\"7409692355f37e9c2e80680e3044836bfba02235816509b67ff08314340b8654\" timestamp=\"0x66f601c7\" size=\"0x0081f000\" added=\"2024-10-12T01:50:50Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7513\" file=\"ntoskrnl.exe\" hash=\"8829fef1ebdc0144c11464da58e53136d65a0230cc3b83e686ae6c5572415f51\" timestamp=\"0x671730eb\" size=\"0x0081f000\" added=\"2024-11-13T15:20:35Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7604\" file=\"ntoskrnl.exe\" hash=\"26e63a1e67e4a09b930c75d734bac519dbd0874e5821da098b2e8695d78074ef\" timestamp=\"0x67481944\" size=\"0x0081f000\" added=\"2024-12-11T14:53:46Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7693\" file=\"ntoskrnl.exe\" hash=\"70d781dd0338a41445cedc3996b66465dd18615c0b4d6f616da14ddc4bd3d75e\" timestamp=\"0x675bb77d\" size=\"0x0081f000\" added=\"2025-01-15T01:55:10Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7783\" file=\"ntoskrnl.exe\" hash=\"2df3c30fcf0d7478e8e40da72753efcc29ed0c4a76449b47a4d06bdc5d7f36f7\" timestamp=\"0x678f44bb\" size=\"0x0081f000\" added=\"2025-02-12T06:18:33Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7870\" file=\"ntoskrnl.exe\" hash=\"173b39c063ab7afea10929c43a752dc083862204596a32fcde8ff866ac16a44b\" timestamp=\"0x67ab4d3e\" size=\"0x0081f000\" added=\"2025-03-11T22:25:17Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7962\" file=\"ntoskrnl.exe\" hash=\"aa6f92d9a36d30449c3bb05cc64cecaf9b3aa2710543294dfcb6e1b480dbe638\" timestamp=\"0x67d4eaa4\" size=\"0x0081f000\" added=\"2025-04-09T14:22:28Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.7973\" file=\"ntoskrnl.exe\" hash=\"06cf03daf8b9875f1f4b5f9f94cf546ce44ca08759f897d8f24e8dc6ddfd43ab\" timestamp=\"0x67f4477c\" size=\"0x0081f000\" added=\"2025-04-12T23:13:14Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8062\" file=\"ntoskrnl.exe\" hash=\"14aeda822c7e35501b31f080c0809e07c09784900ee93bb5c978398fc9900f49\" timestamp=\"0x6813e98c\" size=\"0x0081f000\" added=\"2025-05-15T00:22:34Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8146\" file=\"ntoskrnl.exe\" hash=\"e646e42f4cf0a56ab1368433ab18952113ecda75d87b5fbfe152e11e33fad9bd\" timestamp=\"0x682bee27\" size=\"0x0081f000\" added=\"2025-06-11T00:42:44Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8246\" file=\"ntoskrnl.exe\" hash=\"e1508c8fa2ac93948e01941aec8104a3371e855d85fc27f0ecaf2b562d3cc2b2\" timestamp=\"0x68662a52\" size=\"0x0081f000\" added=\"2025-07-08T22:13:00Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8330\" file=\"ntoskrnl.exe\" hash=\"542cb4efb757314e6667ec002885d487ea4ffd9905e8718445f7fe61aa36db17\" timestamp=\"0x688d83d0\" size=\"0x0081f000\" added=\"2025-08-13T21:37:12Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8422\" file=\"ntoskrnl.exe\" hash=\"6444f5a0d778aedc96603f540f99420409fa48ea34733f8d31ec60b85496d21e\" timestamp=\"0x68b7cdfe\" size=\"0x0081f000\" added=\"2025-09-11T03:22:38Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8519\" file=\"ntoskrnl.exe\" hash=\"c0099b86c28350871bed704a46b19003d7426a16652b7ba71eb8cc740a408fb2\" timestamp=\"0x68e663df\" size=\"0x0081f000\" added=\"2025-10-16T23:37:47Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8592\" file=\"ntoskrnl.exe\" hash=\"43c551b8040cbff4138319bff44c0bb9a1dcfda23116718d6c837c375fd63bb3\" timestamp=\"0x68f9a0b4\" size=\"0x0081f000\" added=\"2025-11-12T23:55:08Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8688\" file=\"ntoskrnl.exe\" hash=\"20faa32486d3195ca711565ea20a475068d0155de4a2f49cddb0d5a3ec29a108\" timestamp=\"0x69310031\" size=\"0x0081f000\" added=\"2025-12-10T04:39:55Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8692\" file=\"ntoskrnl.exe\" hash=\"fa737b0b60b18e2f4af2bdbc92ec699d0fdb5a0af615987114a6cc040010469c\" timestamp=\"0x69419219\" size=\"0x0081f000\" added=\"2025-12-24T02:56:52Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8781\" file=\"ntoskrnl.exe\" hash=\"af4fc7f201c2e6c7e544cf154c23d9dd11a97fd96f497f0b8bc2c5d218b53b6e\" timestamp=\"0x694cbbe4\" size=\"0x0081f000\" added=\"2026-01-15T04:51:11Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8864\" file=\"ntoskrnl.exe\" hash=\"219b51947253acfa0e00917859c3c80c34e3267d4d740b9782c483ad03239fb8\" timestamp=\"0x696f0259\" size=\"0x0081f000\" added=\"2026-02-11T00:54:58Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.14393.8957\" file=\"ntoskrnl.exe\" hash=\"4f3524b4aad5df69331039bbe5b5d9203f1c64da95e74e53ff8784443a44482a\" timestamp=\"0x69a2c28b\" size=\"0x0081f000\" added=\"2026-03-11T23:28:21Z\">10</data>\n    <data arch=\"amd64\" version=\"10.0.15063.0\" file=\"ntoskrnl.exe\" hash=\"8373267ef4dceb7999ccfa9c3c47e75c2623f5aa16a5e46baf2a394faaf5d77f\" timestamp=\"0x58ccba4c\" size=\"0x00889000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.0\" file=\"lxcore.sys\" hash=\"8771c73f2abc1af90d3376fdaa245e594c120cd29cb35fdeb4158a7a9b38ee24\" timestamp=\"0xce68dddc\" size=\"0x000da000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.15063.13\" file=\"ntoskrnl.exe\" hash=\"fc859fabda7455b5057721a9872e77d348520a9693e3164b2826c026aff55f35\" timestamp=\"0x58dc8f7d\" size=\"0x00889000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.138\" file=\"ntoskrnl.exe\" hash=\"30360ff2a41ab8ce733280aedfe61c0bbcb76a82cdb3d6c1f2859767f3d20ea5\" timestamp=\"0x58dee9f6\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.250\" file=\"ntoskrnl.exe\" hash=\"66318fdd9289f58764359a871faf235bdad190bf237bd0c0d0fcde785de24b71\" timestamp=\"0x58f6fd47\" size=\"0x0088a000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.296\" file=\"ntoskrnl.exe\" hash=\"3fd464b08e01baf92e91b17d4003d638f5ff52b8d9be5fe6db7277c9c616e8ca\" timestamp=\"0x5902843e\" size=\"0x00889000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.332\" file=\"ntoskrnl.exe\" hash=\"25df9f7e3ca37910797d6a892458365a744c9a82352cc2f7ff225be1c146ec66\" timestamp=\"0x591fd902\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.413\" file=\"ntoskrnl.exe\" hash=\"912126454faae8d481e9da06a12d9ce2a6684cae91218bc000e6a03f2e932b34\" timestamp=\"0x59327910\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.447\" file=\"ntoskrnl.exe\" hash=\"50d5f058ccc291b1ff74d3653948c4d91a486f43b417b5538a997247e4cb3e4f\" timestamp=\"0x5948aad5\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.447\" file=\"lxcore.sys\" hash=\"6c87465a32f7b38f0f84347e32e268df505dc7e8ee1872db206a3b10c42b2f21\" timestamp=\"0x9647de28\" size=\"0x000da000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.15063.483\" file=\"ntoskrnl.exe\" hash=\"81e40fd0674ed4efe02ec2e6d596c50afd0326757bdad6b4884e0e03bbc4bc20\" timestamp=\"0x595f24eb\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.502\" file=\"ntoskrnl.exe\" hash=\"e8ae6f95197817bf4978a45bcbec805357946bd8d2259383d51f641d09a8575c\" timestamp=\"0x597ab89f\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.540\" file=\"ntoskrnl.exe\" hash=\"ea7a9f80270b8802f4f8376a62b8e6ec455fb517a82e759bb65207249de7349c\" timestamp=\"0x597fd80d\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.540\" file=\"lxcore.sys\" hash=\"911ce928811b012f53d138f215805ab44e8883171c5101a52f12f0c15fa4d743\" timestamp=\"0xeee14d61\" size=\"0x000da000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.15063.608\" file=\"ntoskrnl.exe\" hash=\"6e4ac6533294426f223924acff32ed201c1371ea372823c913aaee023b21df9f\" timestamp=\"0x59ae237e\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.674\" file=\"ntoskrnl.exe\" hash=\"54c6488a59d80ed86a39221bc6292943dd0a00987971d9d1487e28c0dc79d324\" timestamp=\"0x59cdf43a\" size=\"0x00889000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.674\" file=\"lxcore.sys\" hash=\"189eba1c9856589a6b6ccca78f3c7d6d5d56931304e40aef746eb1998aef7383\" timestamp=\"0xf98f285b\" size=\"0x000da000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.15063.675\" file=\"ntoskrnl.exe\" hash=\"da1169b3bf03b1d29940522c9b19733507e1d1046ccbc7c55c1dbcd4f17a67e2\" timestamp=\"0x59e36a60\" size=\"0x00889000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.726\" file=\"ntoskrnl.exe\" hash=\"79d57bd9f36519502a2b804cbf1c693a70051bbb57b5f18ed2a98e710fe20a0d\" timestamp=\"0x59fa9d38\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.729\" file=\"ntoskrnl.exe\" hash=\"b124b12b0160a5651c4d130309ace09057745d42f06f68eeb5114268c3c33eff\" timestamp=\"0x5a0ea249\" size=\"0x00889000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.786\" file=\"ntoskrnl.exe\" hash=\"d6988ef6e59c5591ba398a654cc12b6d23f29fb5adfd0843a6ab45ed3ab12c51\" timestamp=\"0x5a1f6e22\" size=\"0x00889000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.850\" file=\"ntoskrnl.exe\" hash=\"92c0d1c12af845f23829e945a6e7d892c004ca820eefcef2042e1ecf137c62a1\" timestamp=\"0x5a498e19\" size=\"0x00890000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.850\" file=\"lxcore.sys\" hash=\"fdfee0abbbed5bf3fcd2214ada07b24df6c92b8bb7445db1553395406ef22d0e\" timestamp=\"0xc487a73e\" size=\"0x000da000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.15063.877\" file=\"ntoskrnl.exe\" hash=\"2c6076f912200af9def02aa7000415583a5f49c73daf64328f8ab1003f67a5c6\" timestamp=\"0x5a57f0b1\" size=\"0x00890000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.909\" file=\"ntoskrnl.exe\" hash=\"75dd92b43aca815a3ca529d3e5d98806ecc4135f472170966578498ac90fe341\" timestamp=\"0x5a7e743a\" size=\"0x00890000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.936\" file=\"ntoskrnl.exe\" hash=\"3ed4922858cbd2c6873057f63c4e540583fd6061d05352fc24ffcde6d2073582\" timestamp=\"0x5a820dfb\" size=\"0x00890000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.966\" file=\"ntoskrnl.exe\" hash=\"df2a304465698667e0a41d0d34f0e4b66ad4a7bc77c8c1db47c8efd29d7bd74d\" timestamp=\"0x5a9ca12c\" size=\"0x00890000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.994\" file=\"ntoskrnl.exe\" hash=\"203b1890ef6f584dfb658bf8dcaa9f2bda01d52f9bf4753025ca92d2981f4790\" timestamp=\"0x5a9953df\" size=\"0x00890000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1029\" file=\"ntoskrnl.exe\" hash=\"639a6aca46260807c0e64dcd7eee171ff786112377916fe911d9645b85413026\" timestamp=\"0x5abdb933\" size=\"0x00890000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1058\" file=\"ntoskrnl.exe\" hash=\"88c6ad9a5016955a9648b6580dbdd10a3707120d43179c5bcac472b6a8d02562\" timestamp=\"0x5ac2fb45\" size=\"0x00890000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1088\" file=\"ntoskrnl.exe\" hash=\"df6c5f2feb93ec2d91c99a3611b867c9181e452a54cf4fec8325d694b2256597\" timestamp=\"0x5ae3f4d8\" size=\"0x00890000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1112\" file=\"ntoskrnl.exe\" hash=\"039be74d644adf153bfb34227a5e140b1120653a0f286d06ab040b163c8b47b5\" timestamp=\"0x5ae2282f\" size=\"0x00890000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1155\" file=\"ntoskrnl.exe\" hash=\"e84aeba723b998124d6c658d70c864d1a8dd360d871d55938f33bad44dd9be41\" timestamp=\"0x5b1a130c\" size=\"0x0088e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1182\" file=\"ntoskrnl.exe\" hash=\"e79382ea4f8d7e73a0393e52446a7698188d085b9fb4f0215923f4dbfff94971\" timestamp=\"0x5b1f1d4b\" size=\"0x0088e000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1206\" file=\"ntoskrnl.exe\" hash=\"fa08fd873ea2b27f27dac54a25820c020b051ce0c51da3661940c5ac859ca512\" timestamp=\"0x5b346c58\" size=\"0x0088e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1209\" file=\"ntoskrnl.exe\" hash=\"0851aee94d15d5183be574e6ffe551b36f3b53b6d7165215ec356d7e6c6f107c\" timestamp=\"0x5b48276f\" size=\"0x0088e000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1235\" file=\"ntoskrnl.exe\" hash=\"9e5e8f4be5c76746ee1cf44160522ce0792984616c93e519858524abbe9b9c2b\" timestamp=\"0x5b4e7f6e\" size=\"0x0088e000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1266\" file=\"ntoskrnl.exe\" hash=\"d05e1aba666e94745735994c29807529e0a3f4b4e783e09d78ae5f5e29744ec5\" timestamp=\"0x5b5ff907\" size=\"0x0088b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1292\" file=\"ntoskrnl.exe\" hash=\"798f13c117f12995f43fc58f6738c2e003aedefc8c16b9c5bce2ab6f2f299f50\" timestamp=\"0x5b60ea39\" size=\"0x0088b000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1324\" file=\"ntoskrnl.exe\" hash=\"f7bb4ef046560a3e41fc87beeed7f2b9e241b4145985a14238880cf88a6fd94f\" timestamp=\"0x5b85d32c\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1356\" file=\"ntoskrnl.exe\" hash=\"3b3d4767c6eb13562db67bd71ec8e1a67991b6f283975f0f6d6c67a3b84bb8b6\" timestamp=\"0x5b876ce9\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1387\" file=\"ntoskrnl.exe\" hash=\"88b873c50cd843972b22c549bbaa5c02e8c68b00c7e14697cfa9eb0c4de0c49f\" timestamp=\"0x5bac5894\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1418\" file=\"ntoskrnl.exe\" hash=\"6d729cdf7520abbcdc16ddbee560141842844df52b53f361c7ec32f10e6561b3\" timestamp=\"0x5bbda802\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1446\" file=\"ntoskrnl.exe\" hash=\"1c07f40aae1b358a3bbde05564a0504c38b235afd7319e76ced7c2036bccd671\" timestamp=\"0x5bd7e1d6\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1478\" file=\"ntoskrnl.exe\" hash=\"94931c74684246956dfc999a52e5749234f72df7fbf27a26b740375891dca8f1\" timestamp=\"0x5be36350\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1506\" file=\"ntoskrnl.exe\" hash=\"e6071d545d4395ae7bb91ccbfeffd36e7654415b2cb98afa74d081cd6811f74f\" timestamp=\"0x5c0607e0\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1563\" file=\"ntoskrnl.exe\" hash=\"1042efa409247ba0d8814589c12fa0c82f5aa085a3733e1bda49bdcee33609f1\" timestamp=\"0x5c2b099a\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1563\" file=\"lxcore.sys\" hash=\"973233eeb1bcd02eb0cef22f4b3ac6e01b897a6021e977998841d799515571f3\" timestamp=\"0xc65668e5\" size=\"0x000da000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1596\" file=\"ntoskrnl.exe\" hash=\"f4c682ed08d371c0cf2411f43023f005222ea5c344e03fd713c9895a05d8985f\" timestamp=\"0x5c305113\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1631\" file=\"ntoskrnl.exe\" hash=\"eb902d1053fc8e3027d20d922b7298b0411fb38fbab0b88c41b903bd1252d9b9\" timestamp=\"0x5c5a4c7a\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1659\" file=\"ntoskrnl.exe\" hash=\"ebeb072d14c5185db14e72c61842c3f85185fa59d307408f7a9c9311c7871b4d\" timestamp=\"0x5c67c0ec\" size=\"0x0088b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1689\" file=\"ntoskrnl.exe\" hash=\"b035ff64ee023a4e1d2f1db163bb044f3904f8c2371e08958011d7b89355eaeb\" timestamp=\"0x5c7f6c6f\" size=\"0x0088b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1716\" file=\"ntoskrnl.exe\" hash=\"f23bd8a8fd1d6e023787b569ca7f480a94ce53f388ce13fb3d9859fe7fa062e3\" timestamp=\"0x5c89f184\" size=\"0x0088b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1746\" file=\"ntoskrnl.exe\" hash=\"452edbfcb32eae969595233e6509e8cba2428cc39eaa2b65d9bf787968f641ac\" timestamp=\"0x5ca2f43c\" size=\"0x0088b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1779\" file=\"ntoskrnl.exe\" hash=\"f534b73925f0ea6c2628e3090fbee77d3323faeb00ae70ac2cf473ec231069c8\" timestamp=\"0x5ca83582\" size=\"0x0088b000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1805\" file=\"ntoskrnl.exe\" hash=\"552ea892cc511aafd5010ee546a905a8c2fc726fbcf237fc933604bfb9e3d3ff\" timestamp=\"0x5ccbe08e\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1836\" file=\"ntoskrnl.exe\" hash=\"33fdbc36c6151635fe5b2907aa16d4585e1886ef97c545a8935222da42da4b6f\" timestamp=\"0x5ce4c79b\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1868\" file=\"ntoskrnl.exe\" hash=\"beb608dea1988e8e7d767c655f5da3ace662a3f58dadf1124b80f190af2f507e\" timestamp=\"0x5cf9ef4b\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1897\" file=\"ntoskrnl.exe\" hash=\"8621f8ede70c3aa34f9eac462f69080b01d35f71125091dbcb1ad2948e6189c0\" timestamp=\"0x5d01e2dd\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1928\" file=\"ntoskrnl.exe\" hash=\"44de018ab02a7e3f74c397d6a8d06dc96e60c2bf8999f69b94f784bddaf488d5\" timestamp=\"0x5d1dacb8\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1955\" file=\"ntoskrnl.exe\" hash=\"d1cde009fc50540a945fb978926ad1dc7a7d489ab177722596615a67b2bf84a5\" timestamp=\"0x5d240a09\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.1987\" file=\"ntoskrnl.exe\" hash=\"d9f1bdc0d8e4a5ccc2f97c7889cf1bd67db8a1a995d7f801e49353545e6e8478\" timestamp=\"0x5d3ff5eb\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2017\" file=\"ntoskrnl.exe\" hash=\"76131ca378bd54a7abcf634053448f16a539847f7c08473f29e85cec48e346d4\" timestamp=\"0x5d4b127a\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2045\" file=\"ntoskrnl.exe\" hash=\"260d154c73aaea881e82d97213646ab4d9d9d701ee64102d01e31aabe7dccb2e\" timestamp=\"0x5d69cdab\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2076\" file=\"ntoskrnl.exe\" hash=\"6ba9cfe52a79243dbd48052f10bbf3e6bd2510842242e8836dcc6f71cb4fd6d5\" timestamp=\"0x5d6f40e1\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2106\" file=\"ntoskrnl.exe\" hash=\"3be061247feac2020232b5e0c804f832cc514066e68746b7585f8622903508f8\" timestamp=\"0x5d913ac7\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2161\" file=\"ntoskrnl.exe\" hash=\"3bce38c822b59ccbb722b3fd09fb2229b76c446f852b4f16700a1220e1ad7c40\" timestamp=\"0x5da7f43e\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2223\" file=\"ntoskrnl.exe\" hash=\"fd704a6ef7f03fada89734e2c8f5c26b2e2f163fc546d6866250e156b103a701\" timestamp=\"0x5ddcbf10\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2253\" file=\"ntoskrnl.exe\" hash=\"3f1ace409b85f40d5cdf512b4a6cc11c3b14ae9ea84dd9f0a5a01b36c97d794f\" timestamp=\"0x5dfc80cf\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2283\" file=\"ntoskrnl.exe\" hash=\"5f8e9122d62f69b94195ca3ee530ea43a7715ad198b5da0ea10dbe299fc744ec\" timestamp=\"0x5e293405\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2313\" file=\"ntoskrnl.exe\" hash=\"c560260b1ad3e1de992dc589d8c0fe0dc18c0154bc3bd0b207154956998d4b76\" timestamp=\"0x5e5f5679\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2346\" file=\"ntoskrnl.exe\" hash=\"2500007290b8dc648b74a6183e7d853dd64d89619c92592169b2da985e6d2059\" timestamp=\"0x5e8d476d\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2375\" file=\"ntoskrnl.exe\" hash=\"f3a8e21cdefb349d997f27eef367bd9ba725c14281c473e9233c35932c67556a\" timestamp=\"0x5eb0c3f4\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2409\" file=\"ntoskrnl.exe\" hash=\"618414fc01c79eed76f450b090bbba86efc1ab2c5df9b72fa04786399cef74af\" timestamp=\"0x5ed5dc2b\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2411\" file=\"ntoskrnl.exe\" hash=\"61a911bcf030c2edc11d9b678cffa0c851ada9f25fa43e95aa67bc16ab4d063f\" timestamp=\"0x5ee52e60\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2439\" file=\"ntoskrnl.exe\" hash=\"c9f12b3e21632a205251d96103dd135ac7be9b0d593fe858eda455bd763a4d2e\" timestamp=\"0x5f0580a5\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2467\" file=\"ntoskrnl.exe\" hash=\"b6869bac88441c45477c35de6b2a694f525e5fd3bcec1f4fe9d685213ab3f1b1\" timestamp=\"0x5f2baaa8\" size=\"0x0088c000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2500\" file=\"ntoskrnl.exe\" hash=\"5f55c8971930bf49ef5f526b1e5631eb79729c8b0dfd42eaca92a1cdfb9e50f7\" timestamp=\"0x5f5019b9\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2525\" file=\"ntoskrnl.exe\" hash=\"e5147b34379ed49f58a3eccdab1a7cc7c55ba3dbddb06cfd69f7fd18fd450ba8\" timestamp=\"0x5f750437\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2554\" file=\"ntoskrnl.exe\" hash=\"7f0ed5cf357b953aceaecbd80f90f144766c1dc41cbf0f1af52a586d11dfbed3\" timestamp=\"0x5f9a38e2\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2584\" file=\"ntoskrnl.exe\" hash=\"af8213c4efedc706c919945b2cbe8553f511b476411cdb72bfad2a1d73b6437e\" timestamp=\"0x5fc86c1f\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2614\" file=\"ntoskrnl.exe\" hash=\"39512d27413faf68b40dc91ecbd62d651915116ac714aafe453f161ff7ce5943\" timestamp=\"0x5ff78f27\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2642\" file=\"ntoskrnl.exe\" hash=\"a117fa88ec12b31097e59fc3042a9e10bd575db911b55f72ec77b8fb18842649\" timestamp=\"0x600fae2a\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.15063.2679\" file=\"ntoskrnl.exe\" hash=\"73657a669929e8128786db034f7be53d956f6c8a0943bf381e786a2d849b0fdb\" timestamp=\"0x6039db60\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16226.1000\" file=\"ntoskrnl.exe\" hash=\"d573de9f195c23e476f15d6b60f692f3a0870838c7e5f13dac4347c63417d316\" timestamp=\"0x5944ce26\" size=\"0x008d8000\" added=\"2025-09-21T13:49:59Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.15\" file=\"ntoskrnl.exe\" hash=\"fdf3472d58ddb404e91ced547ca96f872a8cd719db6ab5e00ef7715dff113cf6\" timestamp=\"0x59cda780\" size=\"0x008d2000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.15\" file=\"lxcore.sys\" hash=\"051ddc7eb4a5818b4611a6b9b3a6b6bc7fa7444004dfcaae9624027c451908a8\" timestamp=\"0xd8d9d99d\" size=\"0x000f6000\" added=\"2025-02-17T22:56:35Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.19\" file=\"ntoskrnl.exe\" hash=\"79ac396dfeb1bfa56fc4fc301ad398a5ce425a05e74514ac8da391f1d3e46535\" timestamp=\"0x59dc593b\" size=\"0x008d2000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.64\" file=\"ntoskrnl.exe\" hash=\"6759b26962c0e183350b3c3ed5068cf4e98b0d55b72845ba5f36af8abc53debc\" timestamp=\"0x59efff9b\" size=\"0x008d2000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.98\" file=\"ntoskrnl.exe\" hash=\"5c029ea25e8ea528287466fd87f35b202b7f6b5f6d0ef1829537293eb8ce0496\" timestamp=\"0x5a1aaa40\" size=\"0x008d2000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.125\" file=\"ntoskrnl.exe\" hash=\"8afc023e59fb6ee3ed4c2d94c6a716fe932f840b126081dca47269c13b07a811\" timestamp=\"0x5a29b8d4\" size=\"0x008d2000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.182\" file=\"lxcore.sys\" hash=\"95651d2a89242f50f456f9859b54cb8753575dc2ad77643b80bb821772f22e62\" timestamp=\"0xa1d2115f\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.192\" file=\"ntoskrnl.exe\" hash=\"b2ae87c21b1753eb31a8f5dde8aa0eb08240c8dbe7078ff977d99a606382be17\" timestamp=\"0x5a4a1659\" size=\"0x008d5000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.214\" file=\"ntoskrnl.exe\" hash=\"ec0e1627b79097f8ac95056eeff4579a4b5502bf94562cb9127a1116ebbdf37c\" timestamp=\"0x5a5fb447\" size=\"0x008d6000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.214\" file=\"lxcore.sys\" hash=\"2e76a9dfd0466feef3928e8ffb2486a0c559559be22f55e5ef98b20957d25eeb\" timestamp=\"0x1bdca3cb\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.248\" file=\"ntoskrnl.exe\" hash=\"8e9d6338373d05158a5a48ddcd6518cdb1ff9a918185f265231cc1ecf14f0fb1\" timestamp=\"0x5a7e7659\" size=\"0x008d6000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.251\" file=\"ntoskrnl.exe\" hash=\"3ec2bc808186b99f030ac777c974a6f4e49f168365d711b307d2e43893528dc9\" timestamp=\"0x5a8e0c50\" size=\"0x008d6000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.302\" file=\"lxcore.sys\" hash=\"208f96641f5e5f0268ececeac2a0760f7270f21eb2855a2f8215b91bc55fc598\" timestamp=\"0x453c7e99\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.309\" file=\"ntoskrnl.exe\" hash=\"f696af250062293e36c4b722819fc6604a46f8ef8604536110fa13f5ccaa4446\" timestamp=\"0x5a979177\" size=\"0x008d6000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.334\" file=\"ntoskrnl.exe\" hash=\"65f27739d3c74ab8ae9afa5fc8c04955c38341f89e087b93e314519fb3c133ab\" timestamp=\"0x5aa76073\" size=\"0x008d6000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.371\" file=\"ntoskrnl.exe\" hash=\"a4a49039f99541ca4eed231fbd977cfd616f2ad42944a25eebe162e0f0b7d8f4\" timestamp=\"0x5abdad89\" size=\"0x008d5000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.371\" file=\"lxcore.sys\" hash=\"f0204db6b9bc5f5c54b85a248a67aad3dd0f4cbc98cd8e681f4984cd5b760361\" timestamp=\"0xebef20e6\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.402\" file=\"ntoskrnl.exe\" hash=\"84ddc7cb9d0d6288ad850f74240c7c9444a18fc43679ee468298fcbcf341e916\" timestamp=\"0x5ad3af05\" size=\"0x008d5000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.402\" file=\"lxcore.sys\" hash=\"29298dbf03aa6aa8451f27aa53d56bb17afa3b54b6c4c6b24905beb752710205\" timestamp=\"0x404c7fdf\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.431\" file=\"ntoskrnl.exe\" hash=\"ffc11bd8a27adf3ef6cb05f1e2ef8dafb791f9628e84041c09a997ce783189b9\" timestamp=\"0x5aeaa6a2\" size=\"0x008d5000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.461\" file=\"ntoskrnl.exe\" hash=\"96c7da0db759710829035892579db38a9a4d1f9b93cc2bc13b330ab64e20b292\" timestamp=\"0x5af60dc9\" size=\"0x008d5000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.492\" file=\"ntoskrnl.exe\" hash=\"d822f4e0a4b7285252c47324a6d74a9897647f9ffa5cf3a94a95fb7a6dc742d9\" timestamp=\"0x5b1a1a22\" size=\"0x008d4000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.522\" file=\"ntoskrnl.exe\" hash=\"7af28054a17e99d2463a8cc7bd0b5dd8dcb25885097ebcb9836cd46e3d9188d7\" timestamp=\"0x5b2185c8\" size=\"0x008de000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.547\" file=\"ntoskrnl.exe\" hash=\"33c23bcd806a9b39cfbfa1cf5d58c06c97a84e059dc472f8065e02bbe80c3c56\" timestamp=\"0x5b35e5e4\" size=\"0x008de000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.551\" file=\"ntoskrnl.exe\" hash=\"83c269780adf9ce69e9b19f18ca0086a1f531aff318ba2b80cd9eb2f24e3701a\" timestamp=\"0x5b482982\" size=\"0x008de000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.579\" file=\"ntoskrnl.exe\" hash=\"7250055b58e84dfeb15f3e758720271cd0b7719970d3257771ec276495756e8a\" timestamp=\"0x5b4e9d97\" size=\"0x008de000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.611\" file=\"ntoskrnl.exe\" hash=\"ecff4ea6ef291b4c116fec893fc86a727aaf1eded46631b24d7432d6aecae4ce\" timestamp=\"0x5b69230f\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.637\" file=\"ntoskrnl.exe\" hash=\"98416fd4f126ce442ea5424bc50d0dcac16354cb3a068194e352ba7c0adf93c6\" timestamp=\"0x5b6bc154\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.665\" file=\"ntoskrnl.exe\" hash=\"21cf49b24f30967a68db77c9127f210c698a2372579a03721dfecd3672c4fa9e\" timestamp=\"0x5b84cc34\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.665\" file=\"lxcore.sys\" hash=\"23f73bce8cb105023bd023690bdf37525a0dca3181ffc2c8413bfb2c4dfe7aee\" timestamp=\"0xdbd42f98\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.666\" file=\"ntoskrnl.exe\" hash=\"fb60eb6a1d18038dc2f8a8302ddd0d262fa6f636bfe769468c51392018ff013d\" timestamp=\"0x5b9c720e\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.699\" file=\"ntoskrnl.exe\" hash=\"664a8b86220047f1c116caf329e5f033b35af4a6cb8d33cafe30826a877ed93a\" timestamp=\"0x5ba70e54\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.726\" file=\"ntoskrnl.exe\" hash=\"a222955cf73752d9e4309c4042e4868b89b01442ef68fe09ef1cf4f4e04e40ad\" timestamp=\"0x5ba9b269\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.755\" file=\"ntoskrnl.exe\" hash=\"06e71080f3c9327e2237fd7532c57d0c24565ab47b8f3e87d3b09dffc5cabe1d\" timestamp=\"0x5bbd7526\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.785\" file=\"ntoskrnl.exe\" hash=\"8d3717edffe39b80791887475d283406412f26a5d6d98845d8f0bf5792efede6\" timestamp=\"0x5bd7dd29\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.820\" file=\"ntoskrnl.exe\" hash=\"268349d9a9baa96c1abeca9051ff6a2564ea1d9b463518826f60282a3746cf33\" timestamp=\"0x5be2710b\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.846\" file=\"ntoskrnl.exe\" hash=\"f10f23af979a51a8d0b5f47a6b8ad69954d9f3dcba9b59d04e570b4f0f535975\" timestamp=\"0x5c060fdd\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.904\" file=\"ntoskrnl.exe\" hash=\"f07343f17a6731f7daa43e43f2e46e15362c02a352d2b37c7fb0cde417c4d6d3\" timestamp=\"0x5c2af577\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.904\" file=\"lxcore.sys\" hash=\"5f6dd146fd2df976aa31d17c70ed029c45a99891d1d65bc0716ca95be4fe3c80\" timestamp=\"0xf74d2c71\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.936\" file=\"ntoskrnl.exe\" hash=\"c6abc4c4a6812b0b9c3ef02b3b34aa22b1abf8bff70366dc095bb66f62200df3\" timestamp=\"0x5c30523e\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.967\" file=\"ntoskrnl.exe\" hash=\"b55abf153f1ba2444a079db8d1ab149912b79101e66a7add84fd01b42b927fcb\" timestamp=\"0x5c5a445f\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1004\" file=\"ntoskrnl.exe\" hash=\"39859f82e5ed111e8ea7b8da953b6630b0884096e38d4eeec36940a2cff0f036\" timestamp=\"0x5c68b5b2\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1029\" file=\"ntoskrnl.exe\" hash=\"b250926be003294b87342449a24d1a9c48396aa87f2879882313726b1d04eb24\" timestamp=\"0x5c7f8b49\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1029\" file=\"lxcore.sys\" hash=\"73d79143034f13e3d1dc58d4f57b84c0e70f8e39dd078823a3a26c809c57a52c\" timestamp=\"0x54e4c07c\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1059\" file=\"ntoskrnl.exe\" hash=\"ed5fe4277a254af38bcd607e7e9c11285f9eb2e679c7b19ccb3dfd48695ed81a\" timestamp=\"0x5c8a0327\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1087\" file=\"ntoskrnl.exe\" hash=\"8cddafa8ee910df60b6829fbc4c74d7f803bf028c8ec20550ef8daa75a211fc8\" timestamp=\"0x5ca2e51b\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1087\" file=\"lxcore.sys\" hash=\"55973f74e3c206da84858b04fb9635fc5c89626d53427b8c2e5f551a55bb3b53\" timestamp=\"0x02d976a6\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1120\" file=\"ntoskrnl.exe\" hash=\"21c3c485a8903ad0b92a0d48781971077f1d883b32cd1b4a9082f831a0644fe9\" timestamp=\"0x5ca83462\" size=\"0x008da000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1146\" file=\"ntoskrnl.exe\" hash=\"7fa25cf925a035e5b07757f2040345894e80e140ec5b3808c73107e8d89f6c1a\" timestamp=\"0x5ccbdac4\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1182\" file=\"ntoskrnl.exe\" hash=\"bbe69026396d7714fe2e2657c32cb1a793e0c901b3b2b9ccf171732ff5e75571\" timestamp=\"0x5ce60bde\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1217\" file=\"ntoskrnl.exe\" hash=\"bec8e41b2aec1fc1a690a3fc3f76a7bb8bf9398b142b4692132985467eb35811\" timestamp=\"0x5cf9f6d2\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1237\" file=\"ntoskrnl.exe\" hash=\"00439e0be2d8fe2b6037af3761ba37a062d440208a37c7d7225fb3742eca3a6f\" timestamp=\"0x5d01d3e6\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1268\" file=\"ntoskrnl.exe\" hash=\"de9a0afd59a57f396c7c20d5c86fe0e6905f0ea158b9c4b643f53e06b9f263d6\" timestamp=\"0x5d1ea88a\" size=\"0x008dc000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1296\" file=\"ntoskrnl.exe\" hash=\"0a23e029ada4ab38b1cff20488ae20600cda2997be31f592ddc8f71fe3102f30\" timestamp=\"0x5d24055c\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1331\" file=\"ntoskrnl.exe\" hash=\"fafd639e5dc57fd3dd1b44f9b946d532fbce24a30e55f9ffcecce86c34e2f887\" timestamp=\"0x5d4a8516\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1364\" file=\"ntoskrnl.exe\" hash=\"aede9e9b30ec3dbac382084e97384fdbac17b6a4bc29ae6cfa428a32e8383986\" timestamp=\"0x5d4babcf\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1387\" file=\"ntoskrnl.exe\" hash=\"e9c96238f67aa2bb4835c0adc2ca49e76bd0b41e64d3f88091f21d7242365fdd\" timestamp=\"0x5d6f477f\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1419\" file=\"ntoskrnl.exe\" hash=\"bc774b9be684e49720ce97731085f8e776bebb1f259a4b32c4a6ef2bdaaec3b2\" timestamp=\"0x5d7b1d0a\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1448\" file=\"ntoskrnl.exe\" hash=\"354d036c5e536559017b866d87cfe70d7634e0ddce8106cbab5b6562189448c0\" timestamp=\"0x5d942f4f\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1480\" file=\"ntoskrnl.exe\" hash=\"27f18d3b4c8fc49e442fca846dfbdce3ff47e8f772de702a3e4ec1542190b9a4\" timestamp=\"0x5d942837\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1504\" file=\"ntoskrnl.exe\" hash=\"aadc273de526d6a5e07200f2570249343612c66d905041412bce990299a225e3\" timestamp=\"0x5db11a16\" size=\"0x008dc000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1504\" file=\"lxcore.sys\" hash=\"b151e408dcd0056cfad7b02ab7982d78eacae7ccad3eb04dfbc9ecb02dda51f2\" timestamp=\"0x0018ca0a\" size=\"0x000f7000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1565\" file=\"ntoskrnl.exe\" hash=\"f36666856506000c71c767478773f34db7e0a028adb6291eb0b38937d97d7d8b\" timestamp=\"0x5de5eb9e\" size=\"0x008dc000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1622\" file=\"ntoskrnl.exe\" hash=\"3abf3d3c98cec461d106efba4d8771c1615d4933e75823c6d75963b6f14deddf\" timestamp=\"0x5df1c54e\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1653\" file=\"ntoskrnl.exe\" hash=\"e2f2e24d349d72be73fe69e08c09a63873fdd3616f9be3ab2df839566e72794f\" timestamp=\"0x5df1c52d\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1685\" file=\"ntoskrnl.exe\" hash=\"6f09ad07ca7b22eb79d68b96767d449a739ed182ebdffc48b9f32c247e383001\" timestamp=\"0x5e292cb7\" size=\"0x008db000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1715\" file=\"ntoskrnl.exe\" hash=\"ac3a8199b0851d375e9163b96d2e9086664544744a4f2013362f33eceb1bde68\" timestamp=\"0x5e292db4\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1747\" file=\"ntoskrnl.exe\" hash=\"e1a241546d77632473f12959d50f67d9bac3be1e3f9f39573e4bad6c08391d4c\" timestamp=\"0x5e61b4e2\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1775\" file=\"ntoskrnl.exe\" hash=\"67851ff29c13d51ea3e216874c4a8350b0889b4bb12bf8a0ba490aaa538daa3c\" timestamp=\"0x5e61bfc6\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1776\" file=\"ntoskrnl.exe\" hash=\"4b21eea27abe5a2433a34f9117a05f2cf661585f0bdf358d7a00fbbec934833d\" timestamp=\"0x5e7ad045\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1806\" file=\"ntoskrnl.exe\" hash=\"13b515db5b59a0ffb09e6aa8f57f61e1d7d488a0a3b4a07c95e0c64efccc6a01\" timestamp=\"0x5e82c918\" size=\"0x008db000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1868\" file=\"ntoskrnl.exe\" hash=\"53f5da1e68f6b692c3c6dac26cd45d2c8d66526a254bea32a2fb711f91010176\" timestamp=\"0x5eb11156\" size=\"0x008db000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1932\" file=\"ntoskrnl.exe\" hash=\"e1aea0d3c982e906d8bd4767393a6a1f3de043a05ec7dde96a1215658fcb70a1\" timestamp=\"0x5ed60ed2\" size=\"0x008db000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1937\" file=\"ntoskrnl.exe\" hash=\"cfa7fcb2bed76ad3c33387c040e105e001887bd96d35144a333786e4fb95ee72\" timestamp=\"0x5ee48bc2\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.1992\" file=\"ntoskrnl.exe\" hash=\"e145a5485742b00e8d363ab6983516de8d4fa373aeeb6587d4046736acc97aba\" timestamp=\"0x5f056d05\" size=\"0x008db000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.2045\" file=\"ntoskrnl.exe\" hash=\"3f4594b484a9c998c5ce73a07a42275dad8558f2e21482b455d12f5e3d0c893b\" timestamp=\"0x5f2b405a\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.2107\" file=\"ntoskrnl.exe\" hash=\"6defcd9234576efcbb7f2622638a26827a55d224528467307ce4ed99c808acbb\" timestamp=\"0x5f4f2557\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.16299.2166\" file=\"ntoskrnl.exe\" hash=\"21aaf1aabe51a50a915ea7fc8a4a78b7ca53615022bb2dfdf9454b7162883512\" timestamp=\"0x5f743b32\" size=\"0x008dc000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17017.1000\" file=\"ntoskrnl.exe\" hash=\"3c3bbce22a26cfbb8b26d8fd381bc3c9be6a71876b49a3e95e363bfd58dfdffc\" timestamp=\"0x59dd5e65\" size=\"0x008d5000\" added=\"2025-04-12T23:13:14Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17133.1\" file=\"ntoskrnl.exe\" hash=\"c8562a4e2be4f51fbab5260f38f92f08fdfba059eda299e1960b32b97d14234d\" timestamp=\"0x5ab58be4\" size=\"0x00965000\" added=\"2024-12-10T02:56:39Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1\" file=\"ntoskrnl.exe\" hash=\"804e60c6dfa0591037b73cfacf7e2cd8eedfffa047ceffc050181289195fd352\" timestamp=\"0x5acd8966\" size=\"0x00965000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1\" file=\"lxcore.sys\" hash=\"e49b538a821eac33186759de5c66ef319e33e71e0a671bbbc3368a717c58cbe4\" timestamp=\"0xbd69e4b2\" size=\"0x000ff000\" added=\"2025-03-11T02:45:33Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.48\" file=\"ntoskrnl.exe\" hash=\"ddb99ede515366fcca09671dc77024c4686b3f008ad4d5a29cc6a7ad75f4c67f\" timestamp=\"0x5ae3f148\" size=\"0x00965000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.48\" file=\"lxcore.sys\" hash=\"2908b31f050763685da8530e45befd410961532e39107664a64018c5e390ca6d\" timestamp=\"0x47ad18d2\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.81\" file=\"ntoskrnl.exe\" hash=\"247f0844087b3fba3c1eea50ecc493a44d75dc186f2b8d4dc6a347756bd4dadf\" timestamp=\"0x5b015ac2\" size=\"0x00965000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.81\" file=\"lxcore.sys\" hash=\"3033a1afce1ecafb1c498ed608daae81296ff6bc9b079507b4a5c3e8544df331\" timestamp=\"0xd7a34a3e\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.83\" file=\"ntoskrnl.exe\" hash=\"f2dc5612d9011b07359990b2a1f5a30950dd465536c61a0c829f28dc5c6debb0\" timestamp=\"0x5b11cf78\" size=\"0x00965000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.112\" file=\"ntoskrnl.exe\" hash=\"a125ccfbda53eeb7489da3d765b15f93fff5c593c24638ebd3756d1708952119\" timestamp=\"0x5b1a4590\" size=\"0x00961000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.112\" file=\"lxcore.sys\" hash=\"7b8744662f58bdba2168d5c77f36178ccb8ba3605a7236f2ca3f03b387b21c02\" timestamp=\"0x8d2264dc\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.137\" file=\"ntoskrnl.exe\" hash=\"27b758cb3056a3d48c032aae175ed83013ee0a2b3c35a0fd0587ecc4ab1ec586\" timestamp=\"0x5b2343b3\" size=\"0x00961000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.137\" file=\"lxcore.sys\" hash=\"2ba8a9ad8f9e2a5760930ac7cae9b327c6e894b3bffea2c4ad8d41633554fc48\" timestamp=\"0x50b42e14\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.165\" file=\"ntoskrnl.exe\" hash=\"54bd8f06d52630fc92f3bb3f66eb23fde78876b1707d080e0beff01ded8cbc60\" timestamp=\"0x5b3f12f4\" size=\"0x00961000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.167\" file=\"ntoskrnl.exe\" hash=\"568685baf05810eeb658660077db0ea5e48e893d4a3350d8fcd99029597cd4ea\" timestamp=\"0x5b48247f\" size=\"0x00961000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.191\" file=\"ntoskrnl.exe\" hash=\"d4fb496174626474c648be0d885705f01aa36b56ab7a68e8848a65fdf5d34c95\" timestamp=\"0x5b4973b7\" size=\"0x00962000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.228\" file=\"ntoskrnl.exe\" hash=\"1d28e407390ae8fa4d4c444af1f57cd529ad03f223e8cc3e7bd4c96608ed6758\" timestamp=\"0x5b63c7b5\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.254\" file=\"ntoskrnl.exe\" hash=\"f62a20d5205461e3c58d8bc541139923139adc0b91852c9a3ceec2021290ad5d\" timestamp=\"0x5b6bc221\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.285\" file=\"ntoskrnl.exe\" hash=\"8d48df695910146d9b9769d914795304848b16c867a74bfecdba0e74ff908053\" timestamp=\"0x5b88b2b5\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.285\" file=\"lxcore.sys\" hash=\"917f1dc3cba77fc94b85607fafaca928b565fda20ce576112897c6346d5454a9\" timestamp=\"0x023172e5\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.286\" file=\"ntoskrnl.exe\" hash=\"8211c4a409ac6cf3e6b3a8cba5377240db2cf137bac366dd071a9e77c8bbd7a4\" timestamp=\"0x5b9c6be1\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.319\" file=\"ntoskrnl.exe\" hash=\"b7878157ba7454380bfec425fdce30b6c40f15fa72cc4e25581ebe550f711a52\" timestamp=\"0x5b93419b\" size=\"0x00953000\" added=\"2024-11-09T04:03:18Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.320\" file=\"ntoskrnl.exe\" hash=\"cf8545c9967273f1948bb0b22f33ed0dec6f7678e8b58a02aaca6deb683b3bc1\" timestamp=\"0x5ba4682b\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.345\" file=\"ntoskrnl.exe\" hash=\"379dae76df0d79c020ef367866e7d6140c780017777c69c54da5ce17cb232c6d\" timestamp=\"0x5ba316ae\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.345\" file=\"lxcore.sys\" hash=\"a60ced8b0d84d4b2cd9fe26bf2b953956ff2ac3536543cb199106f7a880b88b2\" timestamp=\"0xc38ced7e\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.376\" file=\"ntoskrnl.exe\" hash=\"d01687941d7978f9a59da89f608c6458c47e2d4056ceb6b9e04fc82205c02e0a\" timestamp=\"0x5bcc2809\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.407\" file=\"ntoskrnl.exe\" hash=\"c26629ace83554dfbf1e24655014e9a1f6fc5566522ff2470e9881b2a2cb39d7\" timestamp=\"0x5bdaa393\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.441\" file=\"ntoskrnl.exe\" hash=\"039cb549ae615ae6e27800b493ca19a6ac134a055761c3c5f1e13c037691ed2e\" timestamp=\"0x5be4eec3\" size=\"0x00953000\" added=\"2024-10-20T15:35:22Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.471\" file=\"ntoskrnl.exe\" hash=\"36eb58651caa7ee90e0c858c8b6d5ca212c6c0e4f2bbcc9b28fda043365cde0d\" timestamp=\"0x5c0b7468\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.471\" file=\"lxcore.sys\" hash=\"33cf6099541d157a135fb0b29df6ea1bc48241aadbaac9e5d7d01a30b155d3e8\" timestamp=\"0x97e21d58\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.472\" file=\"ntoskrnl.exe\" hash=\"c334559619b77a07eb906856460e071298a240677d24c5152a4822a0b5f41601\" timestamp=\"0x5c135351\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.523\" file=\"ntoskrnl.exe\" hash=\"c732b1dd3480285b6666641bc417a0c897884331229f47b055b79a9e42df4282\" timestamp=\"0x5c2b0c3d\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.523\" file=\"lxcore.sys\" hash=\"8b99400d0f398fe75c5aa434ea6051231fb9dbfb6a86dbe8139dd73db1f6360d\" timestamp=\"0xfd41b994\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.556\" file=\"ntoskrnl.exe\" hash=\"665b90ee0f42be85f2915c14cc0035deb017603b6414379f74342bcaf074592a\" timestamp=\"0x5c35aca7\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.590\" file=\"ntoskrnl.exe\" hash=\"8fbfc2d45a3a858e3689a35b9885c3f46fc582295aa336692456ae873bab76f1\" timestamp=\"0x5c5a45ab\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.619\" file=\"ntoskrnl.exe\" hash=\"70c976e4a26b345789e58afaed0061087a73fd2168f2fb9fe4a899867513821e\" timestamp=\"0x5c67bbd9\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.648\" file=\"ntoskrnl.exe\" hash=\"9961401ac4aeb775d6a27cf91f8e5024f1995689f3fabd10299b48d86c800a3d\" timestamp=\"0x5c7f858f\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.648\" file=\"lxcore.sys\" hash=\"5ba6377c469d833f6ddda9b789886bc0fbf3b309d973044baad0267a070362a4\" timestamp=\"0x7949aee4\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.677\" file=\"ntoskrnl.exe\" hash=\"73d848099f6aeaa4f871b725b23d77e69120f3533ca4a10164fc3437fae2c0cc\" timestamp=\"0x5c8a08a8\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.677\" file=\"lxcore.sys\" hash=\"a60b4867dd922c46cf86e41de7bb2379d586a58738bf8d510ed0f8d85d3cbe72\" timestamp=\"0x8a28e75e\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.706\" file=\"ntoskrnl.exe\" hash=\"24d70a614e98a3ae5f925efbcdf2c191dc4eff2930d2e8704eeb7ed4716a0b5d\" timestamp=\"0x5ca31432\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.706\" file=\"lxcore.sys\" hash=\"713419c80fdb8b13b33c3dae2870ef5a7ee9298e5267c064c868cc1f793f1dc5\" timestamp=\"0x12d6494f\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.753\" file=\"ntoskrnl.exe\" hash=\"dc4b9988f4e9e4faf12ec071f0f76d1d420f5def81a4ff4f0d9be8e306116a8f\" timestamp=\"0x5cb950ee\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.765\" file=\"ntoskrnl.exe\" hash=\"53fb8d84be97fb15199c8492e91bce3e352d1dd716a4cc26cb0b6b67b46214f8\" timestamp=\"0x5ccbd866\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.766\" file=\"ntoskrnl.exe\" hash=\"a80e3f214f1b8b0bca3e711225c92b09b5fbf0f22989b61c34d9f84b2b2baa2b\" timestamp=\"0x5cde4f67\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.799\" file=\"ntoskrnl.exe\" hash=\"8fbadd436e9748b5f99fc3cf818f04bef3345f4740492d2aadc6d653544da638\" timestamp=\"0x5cde47db\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.829\" file=\"ntoskrnl.exe\" hash=\"706d41e581adf86a635d34a865fc2c23fa1a5e86e165eb5ce447260ccef336a6\" timestamp=\"0x5cf9f460\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.858\" file=\"ntoskrnl.exe\" hash=\"29bd2921929950594272195ad684891681068bbf0839751c203720fe98920213\" timestamp=\"0x5d01e95d\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.885\" file=\"ntoskrnl.exe\" hash=\"003fed1a0afb68d76e055342c0eb9042ff22570f254d7b1b7d9e485f9925ad64\" timestamp=\"0x5d1d7f6c\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.915\" file=\"ntoskrnl.exe\" hash=\"d9e278492d8bfcf8261917cdffa7f3f286ded9ebd33a67a44d3fe962e7bac33b\" timestamp=\"0x5d240008\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.950\" file=\"ntoskrnl.exe\" hash=\"1388f5d64cff1defb2ec2ee7fce97c5b07004cf938048977b2cef2fd6f24ed75\" timestamp=\"0x5d4a7ef8\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.982\" file=\"ntoskrnl.exe\" hash=\"43548ee2726041423012c9b6fcd24bb1fdef63aef4b7c5bb4e5138f4c0aad1c5\" timestamp=\"0x5d5238d1\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1006\" file=\"ntoskrnl.exe\" hash=\"7a392b508cebf8ac89a682a698bb2f3ffa1c8915257c33ea4642737b50047a2f\" timestamp=\"0x5d6f4094\" size=\"0x00954000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1038\" file=\"ntoskrnl.exe\" hash=\"1dcacf3d0dc60e36ce946cdb511454c9e51805b462f1f1f26fec963ab10c9fff\" timestamp=\"0x5d7b18e2\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1067\" file=\"ntoskrnl.exe\" hash=\"9db0cd9344e37fda65cbf79c6f3a561b3ee7e98f86f5d8e57e67140ea35f6c57\" timestamp=\"0x5d942695\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1098\" file=\"ntoskrnl.exe\" hash=\"697288c69ffebc666a2756679eb90ac4e65c937e56d377fec8e422f4b4ac4397\" timestamp=\"0x5d942495\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1130\" file=\"ntoskrnl.exe\" hash=\"73bd0b0dc7579f779106c5ec2df3fc4fac5f0ba84a4c0c1d8097a53c390611b1\" timestamp=\"0x5dc4cedb\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1130\" file=\"lxcore.sys\" hash=\"6ca8f0d830a4a57ccffbc9ca55fe77f15d5843981374c974a0ad32c1af327015\" timestamp=\"0xb315318c\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1184\" file=\"ntoskrnl.exe\" hash=\"ddb2aea21d4becd2212cea1a34e5c39e64e72de0f885f372b33f135f40505f3f\" timestamp=\"0x5ddf4fa0\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1246\" file=\"ntoskrnl.exe\" hash=\"0119be9b80a3577ad42e2dc7e7c4de65768031f3636854453e9a66633de9f5d8\" timestamp=\"0x5e13fa14\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1276\" file=\"ntoskrnl.exe\" hash=\"d8c5adf9c5d35ac929829d97f687434926d392653a65e80d6a9fe1333ea64211\" timestamp=\"0x5e13fc82\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1304\" file=\"ntoskrnl.exe\" hash=\"980466323694296bff7d307a1efd76a95c6bffa9a810efb867d5eb4a1d989a20\" timestamp=\"0x5e3a669d\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1345\" file=\"ntoskrnl.exe\" hash=\"c20147cfdaacbbbe9cc376e535e9e42b26f0fadc43ab80f0dc8744d771bbdaf8\" timestamp=\"0x5e4f5df3\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1365\" file=\"ntoskrnl.exe\" hash=\"63b29abff0a2a15df5c2e96b0410c90324f10097f925d34b3a423dc9c2e8a0ec\" timestamp=\"0x5e5f510b\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1399\" file=\"ntoskrnl.exe\" hash=\"192deb2d6e211432249ca9f8a11e02f7d6a78d489cd17b436aded87afc250e82\" timestamp=\"0x5e5f513b\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1401\" file=\"ntoskrnl.exe\" hash=\"e19104d028d028b287b4cbadc5ba08a7ba1b38ef59cdfaa1ca7565b4a6a12c6a\" timestamp=\"0x5e7caeff\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1425\" file=\"ntoskrnl.exe\" hash=\"5b63ed4dc76f5a1389230f046aa640b3e489e2b1880879c8eaed03b2f8b50c20\" timestamp=\"0x5e82c1cc\" size=\"0x00953000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1456\" file=\"ntoskrnl.exe\" hash=\"41b6fa6336e7554ea326e1c6d7c21f80c395da49c4182f7b0b595851b77f23c3\" timestamp=\"0x5e8cfe23\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1488\" file=\"ntoskrnl.exe\" hash=\"effb9360a7aa713efa90642ce51487ba19a4765bbe1e1211074a29d29abb73bc\" timestamp=\"0x5eb21b10\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1488\" file=\"lxcore.sys\" hash=\"7b986bf73fcd259b143ca2e3ce537241b170f4717d225d59f84dc1dc85e9faaf\" timestamp=\"0x63521265\" size=\"0x000ff000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1550\" file=\"ntoskrnl.exe\" hash=\"f3b4b308c5668e456202682c406473db3972a2700a028461d0696e8d323f6616\" timestamp=\"0x5ed60ff1\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1553\" file=\"ntoskrnl.exe\" hash=\"b90234d88f31dcc5486e115fcd1e2a6983b8be3c1735658d346e12f0e9167ea4\" timestamp=\"0x5ee48606\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1610\" file=\"ntoskrnl.exe\" hash=\"7401bc709070a594cfd3712703e828ee28d088be5b6521eb51f1901ef0ff023e\" timestamp=\"0x5f0487da\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1667\" file=\"ntoskrnl.exe\" hash=\"266e970bf7a040e241241307dbaef00cba940e5b39fe7acf78ffe518c91e7253\" timestamp=\"0x5f2a4ca1\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1726\" file=\"ntoskrnl.exe\" hash=\"dfb01ead9171fda6dc452b83c268140c289dba5443cd31283d3c13593fdc0bc1\" timestamp=\"0x5f4f222a\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1792\" file=\"ntoskrnl.exe\" hash=\"7d0cfc8c6b227d9a43613fcf113311cea72df5417ce33c912f4f743ce05f2974\" timestamp=\"0x5f73fc99\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1845\" file=\"ntoskrnl.exe\" hash=\"1ef4818439719542d852c53c0f62bd5727b55ec55bb0a98d86b5cd96e7acbffe\" timestamp=\"0x5f97adef\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1902\" file=\"ntoskrnl.exe\" hash=\"35d1b62cd5ec36b486780d18cf82aab013d1008d44dac25fa1ba7f742a27faba\" timestamp=\"0x5fc83408\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.1967\" file=\"ntoskrnl.exe\" hash=\"9d58caeb0ece63dd4e2ad9acb4ebdde0259684965d321ad14a58e9e7c46e7c63\" timestamp=\"0x5ff6c0b0\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.2026\" file=\"ntoskrnl.exe\" hash=\"45ddcba4097101656654f7a551ac80a1c358d2281343af5a9dd9e87a10bb3caf\" timestamp=\"0x60124c61\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.2087\" file=\"ntoskrnl.exe\" hash=\"2c2e7a02263bd6bf19fd0af9aec2b2c0df4ab95856c23fcb3e805391f0fc0835\" timestamp=\"0x6038e6a8\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.2088\" file=\"ntoskrnl.exe\" hash=\"baf699e7c580ce8c74c1081c9b996203fb1441132eaee078c492046f4e7ecc68\" timestamp=\"0x604af8c2\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.2090\" file=\"ntoskrnl.exe\" hash=\"03f525b20f6496175def37ec59c50eeeef36d3e7641975bcc7b7f3030dd3e81a\" timestamp=\"0x605119c0\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.2145\" file=\"ntoskrnl.exe\" hash=\"7ce13da56a554a9e5bbe25f4d908b563a6783601681ecbe8d245a2bfb8d5caf2\" timestamp=\"0x606eaf8c\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17134.2208\" file=\"ntoskrnl.exe\" hash=\"44b4ed38258580f0b5db439efb4f4dda362965c4049ec83be855a174a087cf11\" timestamp=\"0x6095bf3f\" size=\"0x00952000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1\" file=\"ntoskrnl.exe\" hash=\"1bb29ea42923e145d74a74c802a46f5debcfcba218166e75503cf0f041760acb\" timestamp=\"0x1fa44fc4\" size=\"0x009f1000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1\" file=\"lxcore.sys\" hash=\"580624e70b50e05ac01e10222a343760a3c1f15a2722bae82724199dd70fb54b\" timestamp=\"0xb9191fff\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.55\" file=\"ntoskrnl.exe\" hash=\"3d40c4d8bcc60d6c28e952d4443c6314da9da5b148893dffee8a23dbf04ac90f\" timestamp=\"0xafb4433f\" size=\"0x009f1000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.55\" file=\"lxcore.sys\" hash=\"aa21b6f14ef98cbec980b2f2cf5cd5008504f8479405d785abac1ab17ffba626\" timestamp=\"0xbd4ee9d1\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.107\" file=\"ntoskrnl.exe\" hash=\"79fcd9ef2646be98bc12b8b745f832b82fd49ca0a849912e9110c743c246896c\" timestamp=\"0x8bb5571e\" size=\"0x009f1000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.134\" file=\"ntoskrnl.exe\" hash=\"f7db939c2dcf6fdbaf9ef93f80a39a92ad5d088dcd0b9db1f812c12cace4bf84\" timestamp=\"0x3eeaaca9\" size=\"0x009f1000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.165\" file=\"ntoskrnl.exe\" hash=\"77e835b28869a377f796a1467251d1258e0ef141531b383e26e07b4829ae2e80\" timestamp=\"0x6afab9d6\" size=\"0x00a70000\" added=\"2026-01-07T20:08:38Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.167\" file=\"ntoskrnl.exe\" hash=\"67ae5dda3d0191809998935025dd79a8dbdc81ceeaee0923cd62f21780ecaf59\" timestamp=\"0x3bdb24f7\" size=\"0x00a70000\" added=\"2025-07-17T01:08:50Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.168\" file=\"ntoskrnl.exe\" hash=\"3935e753a151f4e7618891dc58de6d284b7a37418117f2218a4fad1b27927a05\" timestamp=\"0xea34ae08\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.194\" file=\"ntoskrnl.exe\" hash=\"0d737f853fdb6f78c24224216b05a88468eb349eca2b88315387934a6512db30\" timestamp=\"0x1130b79a\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.194\" file=\"lxcore.sys\" hash=\"00d78dd720f634e32282f5c02ef26caa9a07c75a9d486b6c426768873d179f32\" timestamp=\"0x1c5556b5\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.195\" file=\"ntoskrnl.exe\" hash=\"6553d0984202d9146c609cf25aba976f5211f5badf1e5147a8bee1d6f13e7d2a\" timestamp=\"0xa1808f58\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.253\" file=\"ntoskrnl.exe\" hash=\"8396814c875f40fefacd91654ef6b031171f3c55713f2a08d9da2464354803cb\" timestamp=\"0x8229b0eb\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.253\" file=\"lxcore.sys\" hash=\"6ca3464e0ddcf37d64c6a8f8cc33936ddaf654189ca4329ddcca1079cf34ec1b\" timestamp=\"0xd87d99cb\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.288\" file=\"ntoskrnl.exe\" hash=\"4c588fbbf9169269f5ac7a7e92cd0fa99163681d1232e8237f1e6cc3c91181a4\" timestamp=\"0x2d187efc\" size=\"0x00a6f000\" added=\"2026-03-04T03:13:34Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.292\" file=\"ntoskrnl.exe\" hash=\"15e2ac5967294bc45dafddc1103dbd2c7aad9e1fdf4f83f26d247940fb642590\" timestamp=\"0xbc4b0c19\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.316\" file=\"ntoskrnl.exe\" hash=\"2c731f2a2257aeaa00444ff8268d75d552d3afddf8a9c8336e0ebb6c3cf8230f\" timestamp=\"0xa45bf00a\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.348\" file=\"ntoskrnl.exe\" hash=\"f73833b2a138b2d9dff3af97f4d3871fb0969200b63e3f70537303eff60ad68b\" timestamp=\"0xdeacb3ca\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.379\" file=\"ntoskrnl.exe\" hash=\"0a6a97ce1b5463bc7e3e039bc33137ff2391ef9fdbecbe5508ac82585cc9ca2b\" timestamp=\"0xaad69962\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.379\" file=\"lxcore.sys\" hash=\"c02020bfe7c98bdab50917e83e698527cb06961e0477704153d0a793959ecf68\" timestamp=\"0x3e35ceb2\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.402\" file=\"ntoskrnl.exe\" hash=\"4a411319de7cfea22a2e28f760089d065d463204a90e5e1b5a98828341d2fbd7\" timestamp=\"0x5b147a99\" size=\"0x00a6e000\" added=\"2024-11-09T04:03:18Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.404\" file=\"ntoskrnl.exe\" hash=\"dc3e3ad9cb1bc768323e27752738f77bbbad2aa6b1277f56059dc41c611df0b5\" timestamp=\"0x627e2507\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.437\" file=\"ntoskrnl.exe\" hash=\"f7d80de3feacd6a97d2644714965a8ec4e0f79788e0868c85b3ad8806ad061e8\" timestamp=\"0x438ffec3\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.439\" file=\"ntoskrnl.exe\" hash=\"122bcef1935be7ce75910545e92bb5de49963a96c40f2164daebfe5750f3570e\" timestamp=\"0x92427b45\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.475\" file=\"ntoskrnl.exe\" hash=\"4a6c3cc9b076e100cb2c329b44ca6ae8060542689ce77f142bae7d026d1d59fb\" timestamp=\"0x8e8c9711\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.503\" file=\"ntoskrnl.exe\" hash=\"6d93f48654870abfd0624f7f4b4a02037369fe8e32cab0619a58bc156780c793\" timestamp=\"0x6105701f\" size=\"0x00a71000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.504\" file=\"ntoskrnl.exe\" hash=\"3e1a8f3aa9f6e437c3e514485de13a5cb36e45071bba1bfbdee597a608116e60\" timestamp=\"0x99c0087b\" size=\"0x00a71000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.529\" file=\"ntoskrnl.exe\" hash=\"33a80c7269b60ea89ab5fe51f931ddfb12b422071a430b2adfdd9f0f42449d22\" timestamp=\"0x7fd0bac2\" size=\"0x00a71000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.557\" file=\"ntoskrnl.exe\" hash=\"cd564ccdb1d920cbbb4715e85386fad6f9d670a31f5a78694be5ffb27f108d35\" timestamp=\"0x33a6c3fc\" size=\"0x00a71000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.593\" file=\"ntoskrnl.exe\" hash=\"2d293de6fa934952e4efefe60eb857c7a0df6bb314c743efc8d13187b2d8f09f\" timestamp=\"0xf026ad88\" size=\"0x00a71000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.615\" file=\"ntoskrnl.exe\" hash=\"2c5423ae810e58d725a98cb83193cb9180fecb7509367eaaa08f2fc2d89f551d\" timestamp=\"0x5ebebfaf\" size=\"0x00a71000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.652\" file=\"ntoskrnl.exe\" hash=\"3efb409953ab312aaa72b8be1d21c19ff73101c969dc82b8c6d7c97d4362b704\" timestamp=\"0xa053f9e4\" size=\"0x00a71000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.678\" file=\"ntoskrnl.exe\" hash=\"db94f8fe7f01297284e4f4417889c215991da69315ad3874bc581b11cf243508\" timestamp=\"0xe555a2c9\" size=\"0x00a71000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.719\" file=\"ntoskrnl.exe\" hash=\"af4242878d6d3ca96752aca9b75f1419271382a64bc49999f55689f4718280ce\" timestamp=\"0xc21aaf63\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.737\" file=\"ntoskrnl.exe\" hash=\"53acadfdf4ec1bc0621fbf16f3a717c3423af3f5fe277bf52babb4fc91696e41\" timestamp=\"0x2e8b5a19\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.771\" file=\"ntoskrnl.exe\" hash=\"5457613b8eb7763048e4b06065527236ca0412b8e14d1b50e93b4299a88119cc\" timestamp=\"0x015833e0\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.802\" file=\"ntoskrnl.exe\" hash=\"7b05e74446d3be3dcf99dc2c1cce07cf54ddce3c1e2b217dcd75549be009c66a\" timestamp=\"0x320760b6\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.831\" file=\"ntoskrnl.exe\" hash=\"045b8a5073b8d3e201c2b7b373116a1bebe8f8a34309a6e9fc1765dff9662117\" timestamp=\"0xe59a71d8\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.864\" file=\"ntoskrnl.exe\" hash=\"18c893161281e9e516597b3567913b5df9a5b4bb9e646b7ea359d057217b915a\" timestamp=\"0xd59e6482\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.864\" file=\"lxcore.sys\" hash=\"1c3d24814cd285bea7064c5b5ed1d688b7a674c64fcdb618c2f3036f19b8f256\" timestamp=\"0xbfcfdebb\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.914\" file=\"ntoskrnl.exe\" hash=\"2a18f232990a56a1482c91c6f31930fd911f85afcad5428d176a4c84aeb0a301\" timestamp=\"0xdf79e7cb\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.973\" file=\"ntoskrnl.exe\" hash=\"c36a8fac48690632731d56747cbbdce2453d3e5303a73896505d495f7678dff0\" timestamp=\"0x11b35b7e\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1007\" file=\"ntoskrnl.exe\" hash=\"2f52fd0d97276c0e5f3ea3ec8b04397aced579537c4942baf81c29212dad6ced\" timestamp=\"0xee527b28\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1039\" file=\"ntoskrnl.exe\" hash=\"3e9b2530465a99c54b94d490d159a9cc5d594b68c1f9cceb16193bd7879950a2\" timestamp=\"0x5fb6edc2\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1075\" file=\"ntoskrnl.exe\" hash=\"1aa7263f714cc0af3dcdde4f6d020edda1aee6884a7972c7bb89d604fb5744e3\" timestamp=\"0x783a6fda\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1098\" file=\"ntoskrnl.exe\" hash=\"2690a8500d412290b7a1e4c2d7196afd2286998ac778cc6f14d1f3afc12a6160\" timestamp=\"0x72743c19\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1131\" file=\"ntoskrnl.exe\" hash=\"0bc59cb3470418fc4b5c23984efab96da211ab6eccc3de215bba0b5a72a3496f\" timestamp=\"0xd815435b\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1132\" file=\"ntoskrnl.exe\" hash=\"ea2e3b09db6a0c6f9bb58b6d7de3e7a408a32ce86b0b59f426cd060f111b3afc\" timestamp=\"0x1c23a829\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1158\" file=\"ntoskrnl.exe\" hash=\"4e49d272dd93658c73fc9cb6a5f23f47959b7910ab5217f4380e52b6895f0f5d\" timestamp=\"0xf3b41210\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1192\" file=\"ntoskrnl.exe\" hash=\"cbaef69876f0405d06a9584b3355fc3b48161c96e6bb8836279427a53d38f908\" timestamp=\"0x87b896b3\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1217\" file=\"ntoskrnl.exe\" hash=\"afe37a783586e5983a9b7bfd13a4512725f7522b540c821aab290ff30a566ade\" timestamp=\"0xbda2fe3f\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1217\" file=\"lxcore.sys\" hash=\"75d122e4c2cc71f0141133dbf7952e9fd886f8dfbee4293ff282fa23add13bca\" timestamp=\"0xc08f6af9\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1282\" file=\"ntoskrnl.exe\" hash=\"0d72b46a5b1bc55bb7fbe916f3eb2db5b0e9d75e07f1b8fc3774976695d93327\" timestamp=\"0xfd5656b8\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1294\" file=\"ntoskrnl.exe\" hash=\"7d3f4daa73c5c56fd303f9d82a2c97b16ba8b7c2ddc6689e3f5e9f78c92c80b9\" timestamp=\"0xd9de53a5\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1339\" file=\"ntoskrnl.exe\" hash=\"388a84c81ccbd2a5d708e6e9d9aca974d07ce8bcea7375c05054201141629a29\" timestamp=\"0x7f8fbe8a\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1369\" file=\"ntoskrnl.exe\" hash=\"2e0c0e7c3741b99354742ab11e7879ba8a51be9a59f071e46b8c149b61f5d1ac\" timestamp=\"0x523dff8c\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1397\" file=\"ntoskrnl.exe\" hash=\"fbebb420fce2056e992e97b396dbfd11d856c61003619a8b68cfdc330f94012b\" timestamp=\"0x8de277db\" size=\"0x00a70000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1432\" file=\"ntoskrnl.exe\" hash=\"4dd05bc3c68aa760cf99a7d432d079e69875b8d39b65aba732426498f006115d\" timestamp=\"0x67e8158e\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1432\" file=\"lxcore.sys\" hash=\"8eba2a00f03d1f764e7242e146f9c14b728ec2790c23f684b4005920c6b21d55\" timestamp=\"0xc2bba0b7\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1457\" file=\"ntoskrnl.exe\" hash=\"a1cd4bc88718bee6c288341463c12e457cf319aa23b91c7d3b5069996cfd6f67\" timestamp=\"0xad53b032\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1490\" file=\"ntoskrnl.exe\" hash=\"e314cac88e0360f539904134d055b170d45102a7a582f30eb8d835c47271b77d\" timestamp=\"0x04a085c6\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1518\" file=\"ntoskrnl.exe\" hash=\"0e039c3bbd86d31ceb8f3fd2046134d067ee41ebd974597e59f6518b4d9b60b7\" timestamp=\"0x63584bd8\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1554\" file=\"ntoskrnl.exe\" hash=\"8db2060a38810355d69f724a0664bc9dbf804867db17bafa18d9818c616a0150\" timestamp=\"0xee6c182a\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1577\" file=\"ntoskrnl.exe\" hash=\"e75a7a8e32a2ba8bb718c39ab5ed38288c6aa9e900ef6f6c93071e8be6afe13a\" timestamp=\"0x64d0e15a\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1579\" file=\"ntoskrnl.exe\" hash=\"0b9ac611655bdb9be95196e3b258c4ab12410f00bba12fcb08982e212073f0a9\" timestamp=\"0x60b4bfe1\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1613\" file=\"ntoskrnl.exe\" hash=\"4636fbd0d14be6f99248748f2efc6ca1ce159fb8a867ac2644399fd7d5a1cf83\" timestamp=\"0x1a14d15c\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1637\" file=\"ntoskrnl.exe\" hash=\"fb8a84c1d37f14db4d8e8ba17461b38bd51e57c06fe70a225356310ad1d03eb5\" timestamp=\"0x756e4a4f\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1697\" file=\"ntoskrnl.exe\" hash=\"462f55dc08df450d62a25224ce5e76e857e60d30e17d4972ed8b0cc6adf65e1a\" timestamp=\"0x4cea2dce\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1728\" file=\"ntoskrnl.exe\" hash=\"94718578d564f74e9322a034c461b7b54ba5bdc855073a7f0479c81876ea452b\" timestamp=\"0x2b300f21\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1757\" file=\"ntoskrnl.exe\" hash=\"54c10ea5e7675d3cee8966798b7e69e6e44783c8f28f3a42d838d1cdcd16066f\" timestamp=\"0x87965e08\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1790\" file=\"ntoskrnl.exe\" hash=\"5e16f9c5146dbab4a6bd0c250e9095ae215d986742f193963c71c9eb640e2e16\" timestamp=\"0x5d550711\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1817\" file=\"ntoskrnl.exe\" hash=\"48ad0a9846f406f3252657c8778cfc5fa2e049bd23bf5ec82187600929e27fdf\" timestamp=\"0x689fb101\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1821\" file=\"ntoskrnl.exe\" hash=\"c0c04057d288872c12097e1abe9c4ad32ceeb2d7445fd8ec0ec53e3fbf20e3c1\" timestamp=\"0x717f0990\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1823\" file=\"ntoskrnl.exe\" hash=\"a2953426fb1ad82c8827ebe90c688bc2406a9332b56aff5d766492dd181a18ba\" timestamp=\"0x6dcef711\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1852\" file=\"ntoskrnl.exe\" hash=\"eb5060daf7879b50ded8b3a24b54c0d4edf965b7652f57f13688710ab97dbec9\" timestamp=\"0x2fdd813a\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1879\" file=\"ntoskrnl.exe\" hash=\"e2f1857de3560a5237ca7ea661fc3688715bbbf6baa483511d49baac4ce1acf9\" timestamp=\"0x444e5b3e\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1911\" file=\"ntoskrnl.exe\" hash=\"8a077ac2937baa9882a003b435fa2574a630e9aff0d9a32d89ebdae3d4930ece\" timestamp=\"0xf239f780\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1935\" file=\"ntoskrnl.exe\" hash=\"b638f4ce0737945459bf1522eaef0962807605d82095e8721e4fc58233170800\" timestamp=\"0xf5eab339\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1971\" file=\"ntoskrnl.exe\" hash=\"749945259e6273d2a2e934da009057f5d988f619a1aed0ea1b5f8aa0bc0bab17\" timestamp=\"0x6b62d9b6\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.1999\" file=\"ntoskrnl.exe\" hash=\"0fcca24bc0e7aeaecf9121e1702363152d02918e1c5e7ab9addf2bb8569fa8b1\" timestamp=\"0xd3a02b6c\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2028\" file=\"ntoskrnl.exe\" hash=\"88cf4f2dcddacc42455c7aba95efdd3f686c23fa82127b4a105b0ba3aa2f8263\" timestamp=\"0x39de4034\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2029\" file=\"ntoskrnl.exe\" hash=\"d2aab7469c92ad2508afe5c6af056861504e8d2c9c56e8ee7e47cfde5c952493\" timestamp=\"0xd7e6a842\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2061\" file=\"ntoskrnl.exe\" hash=\"5787739fc6cf124cb151aa0cd913d9b05caf7745e37d496458007f814fbc874e\" timestamp=\"0x9a1cf26c\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2090\" file=\"ntoskrnl.exe\" hash=\"1c8146c4001acde0194408822f16e64ef976faf28d080328f3b8ae3701f93e19\" timestamp=\"0xa24a4a33\" size=\"0x00a6a000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2091\" file=\"ntoskrnl.exe\" hash=\"cb56ecf9c37ba8d934040df75d7e7b5228bde0f124c92ab3da7c8b38f7920ad8\" timestamp=\"0x4539d3c9\" size=\"0x00a6a000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2114\" file=\"ntoskrnl.exe\" hash=\"896dacc858e3eda772dcbb1d8c605c532837d6fb27c73e8e5ab8b0dac4b0c3a8\" timestamp=\"0x2faf2d54\" size=\"0x00a6a000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2145\" file=\"ntoskrnl.exe\" hash=\"4fd33cbcd593dd0ebe04ec10d24ad0ebdafa6823bcdb0aa8632a86bf7f26c48d\" timestamp=\"0x5d9eee83\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2183\" file=\"ntoskrnl.exe\" hash=\"e060fb528f2c5532f5b0c182620b68ff540f5196a5b2775656c2120a198dd0aa\" timestamp=\"0x4c2c61c2\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2183\" file=\"lxcore.sys\" hash=\"6374529ac744ba7868e98e08cd98ec23dc5290b7ce638687a7b3d988d3aa7eb4\" timestamp=\"0x578e8756\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2213\" file=\"ntoskrnl.exe\" hash=\"4fc01f8b79576d681b5df57aa4b15162acd43aac9a987f0f9a0e428f2956716d\" timestamp=\"0xe3bb317b\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2237\" file=\"ntoskrnl.exe\" hash=\"4a5753c4446606293269e183dc2682afd22f043fd91b74565cb56e3e4f8e88f2\" timestamp=\"0xaf834d71\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2268\" file=\"ntoskrnl.exe\" hash=\"ec1976b976bc6bd30a66e378e9aa0cdf6bae07344bb5e90dc2b8cac0507ecc63\" timestamp=\"0x3084e07f\" size=\"0x00a6a000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2268\" file=\"lxcore.sys\" hash=\"578fdcc20db305966e45d06f71290de02fc581da4f76a12c4312dbb00180b957\" timestamp=\"0x2f635f42\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2300\" file=\"ntoskrnl.exe\" hash=\"819e4c3bb269d62de9fee00194b9414b39f336577880adf05ee3ae335375b4b7\" timestamp=\"0x533a622e\" size=\"0x00a6a000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2305\" file=\"ntoskrnl.exe\" hash=\"6615f4ae39ae25423ade4e1ec01546a6daef2f9139fafbb1321d374cf3554413\" timestamp=\"0x661049de\" size=\"0x00a6a000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2330\" file=\"ntoskrnl.exe\" hash=\"999b11da71e3d7973dcaeaf8961791ad0b82ea0da894753fcb97d858eb29744d\" timestamp=\"0xd263a064\" size=\"0x00a6a000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2366\" file=\"ntoskrnl.exe\" hash=\"f0f9ae95425ccfdf2f89059c9d894e4087a2fb5ed1aaa30dfb405b85935a0007\" timestamp=\"0xc40a5f9b\" size=\"0x00a6a000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2369\" file=\"ntoskrnl.exe\" hash=\"d11da5ba3d8ae4f52e9a5fbdf41b0ef85df247920c2bb522c4e34b5491642e53\" timestamp=\"0xabca1353\" size=\"0x00a6a000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2452\" file=\"ntoskrnl.exe\" hash=\"f33ec0c2b089cffd03f11f25fee8db46cac54cac4f5dd3d9ae4bf657620746f1\" timestamp=\"0xdf7cec78\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2458\" file=\"ntoskrnl.exe\" hash=\"d387bfdabeb9b2756beb1e374b158362183bb0ee3f1522d044185bb17d3a6e32\" timestamp=\"0x899a3506\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2510\" file=\"ntoskrnl.exe\" hash=\"631e567903185c6ac045437f336838fb4d42d5ea2c599554577cef1d0571e97f\" timestamp=\"0x9f9bc8a1\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2565\" file=\"ntoskrnl.exe\" hash=\"7ff3ab13d439a3874c8a75a95304966672a921be81018d65eb0b56307d879df3\" timestamp=\"0x446c6cde\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2628\" file=\"ntoskrnl.exe\" hash=\"6acdb597871f5917614a98501dae7adfdaddc44505e92e90ac09f7348632ba07\" timestamp=\"0x70d3bd1d\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">4</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2686\" file=\"ntoskrnl.exe\" hash=\"93ae48b840d77f0918b5f2f1898e4b39ba57a5f3a1e6ae877cf430aa3448dff0\" timestamp=\"0x0de10fb9\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2746\" file=\"ntoskrnl.exe\" hash=\"088fbdf5c1653479bad50de2e3c0bc7527a12a8e0db8c7ac4abe42d057767dfc\" timestamp=\"0x3dd566c4\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2803\" file=\"ntoskrnl.exe\" hash=\"7880a73ca424fecfcdcae9d3587b7b4be2c164395e499a7328935393fca54466\" timestamp=\"0xefd6d518\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2867\" file=\"ntoskrnl.exe\" hash=\"49c71e10ade8b6c2442ef422ab544c3559a339c0f382354e2e1399a756c77a5b\" timestamp=\"0x11df04ea\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2928\" file=\"ntoskrnl.exe\" hash=\"bb4b577e1d421ceb46815d284e7c17460e26707a5a56d913519c394a184434c6\" timestamp=\"0x3bf91e5e\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2931\" file=\"ntoskrnl.exe\" hash=\"48ffe97fbac8b13cbc0f8412e06feb93c162906cbd324938fe3b7a6a7fc08633\" timestamp=\"0x99f1e5a5\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.2989\" file=\"ntoskrnl.exe\" hash=\"189bbab8021614109c76acf8582236fbf52d9530b0c49b643e82cb3bed65ca40\" timestamp=\"0x3fc296b1\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3046\" file=\"ntoskrnl.exe\" hash=\"589ccbb1d24214df47b01eebf20ed944d2b5f03d1074c8a5694f9dc5c7a7b039\" timestamp=\"0x5c800f5c\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3113\" file=\"ntoskrnl.exe\" hash=\"640e8ff6b80ac06e4fe5461a32a7a5333d617d4fb47e2bbe9c791c57aff0c034\" timestamp=\"0x1a0f7cfa\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3165\" file=\"ntoskrnl.exe\" hash=\"8adc4061faa4a3d7f9ba3fcef45b97fa7c2c7f570f2358daa4d7b5ef2167579d\" timestamp=\"0xadd26e4c\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3232\" file=\"ntoskrnl.exe\" hash=\"2a063e3b227ae7d0d8891df985bf73400a80f9e3b57a84814f4af002eaff5bfb\" timestamp=\"0x3939a145\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3287\" file=\"ntoskrnl.exe\" hash=\"842f94031c0e4e2f4d568a13d22c82a238384195e9a294e7587ef2925f8d83ea\" timestamp=\"0x4635e928\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3346\" file=\"ntoskrnl.exe\" hash=\"72092c8fdb3dba8134fd3bbb51a55b8f949d6292c88d1fb0de04870b1c99d967\" timestamp=\"0x19d5be7a\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3406\" file=\"ntoskrnl.exe\" hash=\"6bad21f62ca1a3f48376b959525c5b6814b28a33613fa436a02d8784ff4788a5\" timestamp=\"0x9c9b5291\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3469\" file=\"ntoskrnl.exe\" hash=\"78a03a33faaa4c58a40db436fa1fab8815d2303bfc547e3dd3e8c0c9dbc04d16\" timestamp=\"0x77b33a83\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3532\" file=\"ntoskrnl.exe\" hash=\"0cdc74db15c370a53335c0331b49103358b8ea9613db2f29d544230ea2622a06\" timestamp=\"0xe2c37fec\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3534\" file=\"ntoskrnl.exe\" hash=\"69819de0bfeac6a85b74b82570312c2a41dd43f15f46decf2e395510d9bd9ac6\" timestamp=\"0xb1cd3823\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3650\" file=\"ntoskrnl.exe\" hash=\"944ec53f47a739e8bd9ebfd86124174b5c993604ff46c4ee612a8ec258b7938f\" timestamp=\"0xc71d7347\" size=\"0x00a6d000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3653\" file=\"ntoskrnl.exe\" hash=\"b4b3d10dc8d509cfec38b195194b5bc1aee80b3c813a49854cde3d1ef3f23c76\" timestamp=\"0x5e8ba96b\" size=\"0x00a6d000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3770\" file=\"ntoskrnl.exe\" hash=\"3f817ab90ea7edf2a50959de00383553e4828d93161ed3df1c472d195ff04e20\" timestamp=\"0x02ba4c59\" size=\"0x00a6d000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3772\" file=\"ntoskrnl.exe\" hash=\"b153885e03b98b1f50313bea0189e393f24d4b4516ceb1bad2a57db2daebd381\" timestamp=\"0x305dc8c1\" size=\"0x00a6d000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.3887\" file=\"ntoskrnl.exe\" hash=\"d58678644dd4c5dcbef6f34befd76e04bb5d903f9f79eeaf3963d481f7786200\" timestamp=\"0xfdc9e20e\" size=\"0x00a6d000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.4010\" file=\"ntoskrnl.exe\" hash=\"db60233b7a7c27e9f9cf414b8c18fb31102e2b33c35fd6a8f4d827d197231fc2\" timestamp=\"0xb7f8ea88\" size=\"0x00a6d000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.4131\" file=\"ntoskrnl.exe\" hash=\"fb8cd14b1428f1977e5f3e02b21f08effe0264988aae12a984c2a8117c3a53ed\" timestamp=\"0x7a7f2a5c\" size=\"0x00a6b000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.4252\" file=\"ntoskrnl.exe\" hash=\"d396d792cca27187f2a35e1ddbda82e85cc506476635da8e96f79a68d9754fd1\" timestamp=\"0xd247ddda\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.4377\" file=\"ntoskrnl.exe\" hash=\"cd35c74567de47437a1553065c7df1d39be319b82069740f3e4e4e079e8def0f\" timestamp=\"0x3ab9b60a\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.4644\" file=\"ntoskrnl.exe\" hash=\"eb10c2a1de5e6178e1d7e8eca8f42ecb6af7b4d0269514ec6c5bcdae228a8451\" timestamp=\"0x0b334a1f\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.4737\" file=\"ntoskrnl.exe\" hash=\"9d2f75ec40da98def10f15b8fc75cd00733a095c4ce5630db461897690bb5d7b\" timestamp=\"0xb7e483ac\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.4851\" file=\"ntoskrnl.exe\" hash=\"64de0585c49e769249fdef8236364a2c0f49d5c93408cd78a4f6591cc50ec98b\" timestamp=\"0xc7b00c2a\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.4964\" file=\"ntoskrnl.exe\" hash=\"8d35abbb094584cff67e60003d3d6a8085c579842ae698153078d95461d99dec\" timestamp=\"0xced228d4\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.4974\" file=\"ntoskrnl.exe\" hash=\"324a350553ea5715880a269529fc904bc9369b87ca1ff543d16482d7d555d38a\" timestamp=\"0x22bee457\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.5122\" file=\"ntoskrnl.exe\" hash=\"b5d725a882ba4f8d9b380700f460be22775b6969c842cefec90bf976c4747ab3\" timestamp=\"0xa7975a9e\" size=\"0x00a6d000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.5202\" file=\"ntoskrnl.exe\" hash=\"23245d870bff7f925ec6031ec72f4f83b0902c305e6e50b60263e65e58b57304\" timestamp=\"0x1830eb69\" size=\"0x00a6d000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.5328\" file=\"ntoskrnl.exe\" hash=\"45364bbd4b91cb18b406db65cccf28f19b9535982dc87a1adeffa184766ac410\" timestamp=\"0xee47ab3c\" size=\"0x00a6d000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.5458\" file=\"ntoskrnl.exe\" hash=\"f13b502bf09bdb6349bface6a6969fed94fd50d9eef620b8fc0d6a167d007141\" timestamp=\"0x3b89c92f\" size=\"0x00a6c000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.5576\" file=\"ntoskrnl.exe\" hash=\"1814d912d2bc9dfa7dcdd9a6d094067462cac79090820046cc99cf9545b9ee1f\" timestamp=\"0x20575c03\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.5696\" file=\"ntoskrnl.exe\" hash=\"2aee999837064f8c72464c560f699b8fd8c7d8eaebc29f2e1d00ea2e73ae5fd1\" timestamp=\"0xd8a11556\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.5820\" file=\"ntoskrnl.exe\" hash=\"2036e0435f777eeb44590def15124bf4d238160ba5683faad73bdf866955b860\" timestamp=\"0xc4c63730\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.5830\" file=\"ntoskrnl.exe\" hash=\"bd6aa143f8d3b8d0e7196991ccecad886705f42175bdb3874c05838b1d8c5f2c\" timestamp=\"0xb6368baa\" size=\"0x00a6f000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.5933\" file=\"ntoskrnl.exe\" hash=\"ade757ff23480d1b0dbeb16ea164a0f8834c52a76773aea14d8d3956d6925507\" timestamp=\"0xd65b463c\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.6054\" file=\"ntoskrnl.exe\" hash=\"4315112605b3816e526beee8a9d682338363b06022f313c188f2441ab97f81d8\" timestamp=\"0xdce9a4c5\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.6189\" file=\"ntoskrnl.exe\" hash=\"d8c7b2be1734d5def6c2abfb4f71c4f97b821c170e13d691063f8806ee860252\" timestamp=\"0x9bc3a56a\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:05Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.6292\" file=\"ntoskrnl.exe\" hash=\"cd29fb18ad5406131780b32e1a81f967be48541bd161cc18737c9ebf34329eef\" timestamp=\"0xd269704a\" size=\"0x00a6e000\" added=\"2024-09-12T01:41:07Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.6414\" file=\"ntoskrnl.exe\" hash=\"ba7f50595ea0c0150eecd2d8db32b49b1da2de3f1719b91e8a4c1fb7914baf87\" timestamp=\"0x90ac53fa\" size=\"0x00a6e000\" added=\"2024-10-09T02:21:15Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.6530\" file=\"ntoskrnl.exe\" hash=\"d6de6c58ade2219bc19cbf6f9ac7f3d5e52875cd4db875b5c934cb0c93976e7e\" timestamp=\"0xd6db51ae\" size=\"0x00a6e000\" added=\"2024-11-13T15:20:35Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.6640\" file=\"ntoskrnl.exe\" hash=\"b7da7ae1c4d7175036a34d0ae8580f637b8626588e0162ed72d161ecfeeae8e8\" timestamp=\"0x6e28298b\" size=\"0x00a6e000\" added=\"2024-12-11T14:53:46Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.6766\" file=\"ntoskrnl.exe\" hash=\"82d04a19ad3318d7e0629345cb8f1222de56539182a1eada800afba70240139c\" timestamp=\"0x17ff4214\" size=\"0x00a6e000\" added=\"2025-01-15T01:55:10Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.6893\" file=\"ntoskrnl.exe\" hash=\"ab40631764282ca30d5dfacf660adb84a636bbccb27d6bb8486a5e8414d5ad48\" timestamp=\"0x0e079518\" size=\"0x00a6e000\" added=\"2025-02-12T06:18:33Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7009\" file=\"ntoskrnl.exe\" hash=\"220ec50f81c0df96828e1ada00acfb95dc6c3fbfbecfae248c6f8b2d7ccece5a\" timestamp=\"0x96b4c186\" size=\"0x00a6d000\" added=\"2025-03-11T22:25:17Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7131\" file=\"ntoskrnl.exe\" hash=\"ace88181798ee890a6917e00ef7999029656942f4f485292ed6f9d05cf2fb6a1\" timestamp=\"0xff8b2ec0\" size=\"0x00a6d000\" added=\"2025-04-09T14:22:28Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7240\" file=\"ntoskrnl.exe\" hash=\"e541303946cee42e079848ba9e9e610969db0e02d10958536dfbc24602a16820\" timestamp=\"0xc9abb782\" size=\"0x00a6d000\" added=\"2025-04-12T23:13:14Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7249\" file=\"ntoskrnl.exe\" hash=\"181e27838eb6f1a7224830a60a830ad9e9ad867825a4761e5b2c7f5da1456f59\" timestamp=\"0xa96074fa\" size=\"0x00a6d000\" added=\"2025-04-19T15:54:38Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7309\" file=\"ntoskrnl.exe\" hash=\"7466ec0535ca534cfb21ae9b5f27486300e0470bd7719aecbd6f23abcaff78e0\" timestamp=\"0x84cfbdfb\" size=\"0x00a6d000\" added=\"2025-05-13T22:56:23Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7434\" file=\"ntoskrnl.exe\" hash=\"5377faf16b7b2d74cced4c415d8a8da16321e4a4a7e21777b994993365f95dc9\" timestamp=\"0x90017d4f\" size=\"0x00a6d000\" added=\"2025-06-11T00:42:44Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7558\" file=\"ntoskrnl.exe\" hash=\"fe2f8da00dcbf2e8e5d9558a35961a875c5fcbe69c5d9ee2d28ea91e89e3c42d\" timestamp=\"0x26aefa5b\" size=\"0x00a6e000\" added=\"2025-07-08T22:13:00Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7560\" file=\"ntoskrnl.exe\" hash=\"7401fcec9eb8de76f41dccece2b05d989ab42b8db0de32f0faa2345b8903974e\" timestamp=\"0xc909c53c\" size=\"0x00a6e000\" added=\"2025-07-10T01:24:18Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7671\" file=\"ntoskrnl.exe\" hash=\"e6e05ec5f95e3c5c6720ef9e86e5da7afd048f8895d077b95c8abcbf4e00dcfc\" timestamp=\"0x1f7c6177\" size=\"0x00a6f000\" added=\"2025-08-13T21:37:12Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7683\" file=\"ntoskrnl.exe\" hash=\"90c8686c1eb4e201fb26629d62adfd592053b91e048ade23cf83314168b843d8\" timestamp=\"0x8ed5cad0\" size=\"0x00a6f000\" added=\"2025-08-21T15:11:13Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7786\" file=\"ntoskrnl.exe\" hash=\"24b0b77571625270fd9f5a6100320e1636f5f0728f223eab11a0a78d9cbe299b\" timestamp=\"0x96edaa50\" size=\"0x00a6f000\" added=\"2025-09-11T03:22:38Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.7919\" file=\"ntoskrnl.exe\" hash=\"123841c9159ff36c235b46d7cc05a90965742a29b078c253e5b024804abafa48\" timestamp=\"0x707af9a2\" size=\"0x00a6f000\" added=\"2025-10-15T03:12:43Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.8024\" file=\"ntoskrnl.exe\" hash=\"ed0c66d50e7d29d67b8c2eccfeb5b207831c34d8725d857779f9ec0b9f5d4984\" timestamp=\"0x88899deb\" size=\"0x00a6d000\" added=\"2025-11-12T23:55:08Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.8146\" file=\"ntoskrnl.exe\" hash=\"fcab247d1f919c9bb2fa2399c8a5c3ea76d92f1f23784b76d3ab7e1936c7187e\" timestamp=\"0x165f398e\" size=\"0x00a6e000\" added=\"2025-12-10T04:39:55Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.8148\" file=\"ntoskrnl.exe\" hash=\"f63605075c0ec69a39100f40892de05b517c5628b41a49e85c1737e81bf70e81\" timestamp=\"0x6c162d30\" size=\"0x00a6e000\" added=\"2025-12-24T02:56:52Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.8269\" file=\"ntoskrnl.exe\" hash=\"015bddbd7d90aa75e291bf173d8c41ed8f66ef9c73a8ef3f5a0f51e4a93e9c9c\" timestamp=\"0x1ba1aad9\" size=\"0x00a6f000\" added=\"2026-01-15T04:51:11Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.8276\" file=\"ntoskrnl.exe\" hash=\"82e9ed7602d96946c29b8ee710ef7067475d7e1aea78b3e540b1282229367456\" timestamp=\"0x45ec1849\" size=\"0x00a6f000\" added=\"2026-01-15T04:51:11Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.8280\" file=\"ntoskrnl.exe\" hash=\"cacbcf9d55cf0e9dde6ef382d058503c420daa1fa3e7e7ed718a1b33bcfc2f7c\" timestamp=\"0x5d1cc7b8\" size=\"0x00a6f000\" added=\"2026-01-22T02:43:17Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.8385\" file=\"ntoskrnl.exe\" hash=\"3804de1efbdf9c961dc1785c8d3f6ea4684c427f2521a274f5ce34788076ebb6\" timestamp=\"0x4c5548a5\" size=\"0x00a6e000\" added=\"2026-02-11T00:54:58Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.17763.8510\" file=\"ntoskrnl.exe\" hash=\"8ba872a1f34da094925dd42b4a89f70028995558f3f89bd2c67fb5499006d0a0\" timestamp=\"0x0e605cfe\" size=\"0x00a6e000\" added=\"2026-03-11T23:28:21Z\">11</data>\n    <data arch=\"amd64\" version=\"10.0.18277.1000\" file=\"ntoskrnl.exe\" hash=\"163b05e43b1661e68a0b3c3c8144189d4ce14fe0b296909a08c54533814565d4\" timestamp=\"0xc9c2ed0a\" size=\"0x00a60000\" added=\"2025-08-05T22:30:10Z\">2</data>\n    <data arch=\"amd64\" version=\"10.0.18305.1000\" file=\"ntoskrnl.exe\" hash=\"02c571edddd2418a5802c9917c3e3301001a879eb6681d34cc417b5d09a75a22\" timestamp=\"0x1ea76c27\" size=\"0x00a9b000\" added=\"2025-08-29T21:12:06Z\">27</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1\" file=\"ntoskrnl.exe\" hash=\"635a43262ffec9ecb1ef48f7583ff09888e93c95781fd086afe9833ecc8e8276\" timestamp=\"0x00e78e2f\" size=\"0x00ab2000\" added=\"2024-10-29T02:19:33Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1\" file=\"lxcore.sys\" hash=\"9cf8475aac34217233db70e632c23d116032324658a4ceb6d03540fd45e6355d\" timestamp=\"0xdeb52477\" size=\"0x00116000\" added=\"2024-12-27T01:34:36Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.18362.30\" file=\"ntoskrnl.exe\" hash=\"3033be1f35f4bb17ea3049fc4132d30a3fbaa1bfd26b5444313641f1530b2326\" timestamp=\"0xe2f1a52b\" size=\"0x00ab2000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.53\" file=\"ntoskrnl.exe\" hash=\"c08cf1030216ddc7cc87d8a211534df7bc356b22cf98d093eb33f194d42a5a73\" timestamp=\"0xf4ef4327\" size=\"0x00ab2000\" added=\"2024-11-05T01:22:32Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.86\" file=\"ntoskrnl.exe\" hash=\"b6c258a188a9fbd733b00e3493cfcbbeb33ce7fcc6fa96251ff135d489c3afe3\" timestamp=\"0x4daa99b0\" size=\"0x00ab2000\" added=\"2024-12-10T02:56:39Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.113\" file=\"ntoskrnl.exe\" hash=\"ba5ce56266f17ed8c0f7e98b6bea5ae32930b784bb9ecedc77cc63481f349630\" timestamp=\"0xfc092acc\" size=\"0x00ab2000\" added=\"2024-10-29T02:19:33Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.116\" file=\"ntoskrnl.exe\" hash=\"dbcd8a80f53906780389970772c0b6c094d81c27d23cf934db564e7f3cb57055\" timestamp=\"0xdd52ff09\" size=\"0x00ab2000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.145\" file=\"ntoskrnl.exe\" hash=\"c17b8e328205cef5c7dae5d23deb93f25e41476846ab58e37d10cffd1df1615b\" timestamp=\"0xfecf74b7\" size=\"0x00ab2000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.207\" file=\"ntoskrnl.exe\" hash=\"9070003a325f389812a6df6a5ae9f99f9ab20a9bb7e04ac43699c6136709b531\" timestamp=\"0xd48c9165\" size=\"0x00ab2000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.239\" file=\"ntoskrnl.exe\" hash=\"89ac63f78215074b150eab559c179caf656751410ba2bd57e774d90c39d1ece7\" timestamp=\"0x03ed0f42\" size=\"0x00ab2000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.267\" file=\"ntoskrnl.exe\" hash=\"aa0bddbd4b1eef2b825c9eb603d6584e52d6aa73dbf473cf0765a1c63328be7b\" timestamp=\"0x74da155a\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.295\" file=\"ntoskrnl.exe\" hash=\"3e4bb89d4dcf19cf6bb5c19e8dda22fc186c7c2b71cb2de1b4bcde587bbb3799\" timestamp=\"0x35707659\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.327\" file=\"ntoskrnl.exe\" hash=\"016603d971b8a7e8c053d103bb35d987246fc9f8ec3154fa60e66d593ec5fc49\" timestamp=\"0x72ed27e3\" size=\"0x00ab5000\" added=\"2024-12-10T02:56:39Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.329\" file=\"ntoskrnl.exe\" hash=\"a130f992521a45764695256659885dcb80cb53650897c4091fb0a9de909fa0c8\" timestamp=\"0x571a3c8e\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.356\" file=\"ntoskrnl.exe\" hash=\"778cee105f540fb8492fa9cdbce66152352bbe56e44dcd302a87ff673322b0e0\" timestamp=\"0xa5839c4d\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.357\" file=\"ntoskrnl.exe\" hash=\"321a4952cfec944561ea74d194dc7d9318e340d9c8306aecd57b2886106cff09\" timestamp=\"0x02ba1cb3\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.387\" file=\"ntoskrnl.exe\" hash=\"e8cf4beea73f92b74b03dc9ae2ed30d4cc442015cb6da25e66a08936b0479248\" timestamp=\"0x740e7205\" size=\"0x00ab6000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.388\" file=\"ntoskrnl.exe\" hash=\"6911ddf4f790fa9612beb297f7d28ece31ec28ebb7d88b8f3ada9b47ba8477be\" timestamp=\"0xd50c4226\" size=\"0x00ab6000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.418\" file=\"ntoskrnl.exe\" hash=\"bf8b1023243dd8764d2b71a9156b782b4b84c61509c8d7edceb062ff798715b5\" timestamp=\"0xfc9570f2\" size=\"0x00ab6000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.448\" file=\"ntoskrnl.exe\" hash=\"a03f2b512b78468b84ab542a0464669c862ad6e0bf5ec2435c0c4107a71a1204\" timestamp=\"0x39263280\" size=\"0x00ab6000\" added=\"2025-02-17T22:56:35Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.449\" file=\"ntoskrnl.exe\" hash=\"4d7e4580f44ff5b0268a7d62047c08f6911534bfeec5c6d2a9613eb1b8e10acf\" timestamp=\"0x4d2db2db\" size=\"0x00ab6000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.476\" file=\"ntoskrnl.exe\" hash=\"a7785200f44317f54d1eadfa80de850bcab91ed4fba84b0fe511458e85b8ed8e\" timestamp=\"0x4efcf7a9\" size=\"0x00ab6000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.476\" file=\"lxcore.sys\" hash=\"73b2d92f6f0e4b1fa201c6f14e9fa7e3f69a0bd868699af80d5e69170689e7cd\" timestamp=\"0x95029dbf\" size=\"0x00116000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.18362.535\" file=\"ntoskrnl.exe\" hash=\"47e07ac729750d74342bc5d89e9747eea1dbd7e63f54cd6a16ae7e9c473cd14d\" timestamp=\"0x12dcb470\" size=\"0x00ab6000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.592\" file=\"ntoskrnl.exe\" hash=\"2ea1e2a2945fc4808b9fef1701bcfb5430bd1d7ccc9b9321986b12f807b53c37\" timestamp=\"0x04f6eba0\" size=\"0x00ab6000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.628\" file=\"ntoskrnl.exe\" hash=\"2ce2012049c77c514643eadd328d0bb326d328c970e1699ff4e39e2e362c17f3\" timestamp=\"0x29371fe3\" size=\"0x00ab6000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.657\" file=\"ntoskrnl.exe\" hash=\"c16e8e0df58046b44c5150f6fe1177e4d469155b32349b078adfa7df4c7e1ef6\" timestamp=\"0x4269a790\" size=\"0x00ab6000\" added=\"2024-09-12T01:41:05Z\">5</data>\n    <data arch=\"amd64\" version=\"10.0.18362.693\" file=\"ntoskrnl.exe\" hash=\"9aa29a8443f614db45a5ac56ef20ae86dece59cb20ca911f9d6b1de4f409ca8e\" timestamp=\"0x88d7c6b6\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.719\" file=\"ntoskrnl.exe\" hash=\"83fe49d0e84a8383f5dd4255ce0d2678edce0bea2c9f49f3afe1f766800d52b4\" timestamp=\"0xd36c6033\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.720\" file=\"ntoskrnl.exe\" hash=\"cfee1796884a024a355000e44e50d9a84041b97db09a55620064bb14e6b24801\" timestamp=\"0xe45edf24\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.752\" file=\"ntoskrnl.exe\" hash=\"063da2583a7c24b35fbdeffc1fb2c5fda8163c237fb4d994b15f0b369ca2f863\" timestamp=\"0xcb080304\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.753\" file=\"ntoskrnl.exe\" hash=\"0a5ba7c51080da58ec4f6f24978f6c59aacc741e8b16c26a5217cef83719e20d\" timestamp=\"0xdbb8e579\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.778\" file=\"ntoskrnl.exe\" hash=\"f9b7b8e8d69159ee2c3aadc70e6bf3b7dfd5df024cff9c330da2ff6b8a7159cd\" timestamp=\"0x5629d63a\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.815\" file=\"ntoskrnl.exe\" hash=\"40c695e24769e1a64e6bbf752fcca85d72e8848cb4500bb04f6261137e3f4773\" timestamp=\"0x81e3fd80\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.836\" file=\"ntoskrnl.exe\" hash=\"cccfda078a89d2adb3bd6e93f30a031b24fd37fbf2caf3d2a6bb39f2e790d13b\" timestamp=\"0xb785e389\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.836\" file=\"lxcore.sys\" hash=\"0a1000d49bb2fbdca028dca97c36e37cceb2b9d29ff72d5b29495e3a3abb80da\" timestamp=\"0xe0c12b66\" size=\"0x00116000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.18362.900\" file=\"ntoskrnl.exe\" hash=\"6d666f98ccf744c4a45b3847fdb67435661b8b785ee6d1f0c69ba90be09ec611\" timestamp=\"0x4ff75719\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.904\" file=\"ntoskrnl.exe\" hash=\"df5334c5a4f92994fd77fe735a89fa4113cb356aa2d7c56644a7eb170f5dcab9\" timestamp=\"0x74b36cb2\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.959\" file=\"ntoskrnl.exe\" hash=\"cd90bf259fb2e592eba93be145535fd7fefd0b8658c1782667e0d904ca2af1e9\" timestamp=\"0xd1492ac1\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.997\" file=\"ntoskrnl.exe\" hash=\"a8459259081e0fdf98345bdc2fe71dcef78e74b405878389e11b0cdd51411406\" timestamp=\"0xc7485b40\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1016\" file=\"ntoskrnl.exe\" hash=\"519c3b6c4db7d4d2f64744b8c81353d679835bc3d0f37bbdae3a7dd40882ad44\" timestamp=\"0x7530c6d3\" size=\"0x00ab7000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1049\" file=\"ntoskrnl.exe\" hash=\"bc9611210344d4a56bd19fdf80dc5ebe0111ffcdc08b2a82c2547a6593fea3f0\" timestamp=\"0x93f0a600\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1049\" file=\"lxcore.sys\" hash=\"46734df3b981f3de2ac3e6326b385f1135ca4dfe66d0021605a0909b00782537\" timestamp=\"0x6db36ed3\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1082\" file=\"ntoskrnl.exe\" hash=\"8779dfed3042625a748dc6705edb8c4d65683cdeefbaaae89121d031cb231bf7\" timestamp=\"0x91bedfd7\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1110\" file=\"ntoskrnl.exe\" hash=\"1683d43c4dbd089201d31074c18cece3bc3bd534bff8ddf64d64c24c1d246005\" timestamp=\"0x93688c82\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1139\" file=\"ntoskrnl.exe\" hash=\"99895910cf67bd8a45e34ebabc05bf9f1cbdc4127541f7c68c320a21a7feefe4\" timestamp=\"0xd6925b99\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1171\" file=\"ntoskrnl.exe\" hash=\"d46a8ab22bb1267f46907fac4bc633681a52a023dfb7c82e37c53acab72d2160\" timestamp=\"0x5d8a32e2\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1198\" file=\"ntoskrnl.exe\" hash=\"22f08690a0e352557d1f073fc22bb9070e075c640b242f8007ae1a2098575d3f\" timestamp=\"0x15feb573\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1199\" file=\"ntoskrnl.exe\" hash=\"8af41c2b1a059a9a9e1c17c6ac93580304088af9b0a80bbd879df0993c5308a2\" timestamp=\"0x9938525b\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1237\" file=\"ntoskrnl.exe\" hash=\"205f4d5b9a68c60f4dc18b80472b7299e2e727d5a52f40072e74f54c6e54bc81\" timestamp=\"0xae9b0d38\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1256\" file=\"ntoskrnl.exe\" hash=\"e4acc215a3584deaed9bd5fa6e6a9a5adce56fe21efa149e736424c8e4f77c65\" timestamp=\"0x9b5f0a62\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1316\" file=\"ntoskrnl.exe\" hash=\"b80f408111c090c34be064b29cf00f839a7249eecb84a434b866a8b6d855965b\" timestamp=\"0xd10dbe11\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1350\" file=\"ntoskrnl.exe\" hash=\"e2f120ca0c36c8b7a5f5dbeda74a822a53de495e29485f8417378ae99e220720\" timestamp=\"0x888e36f1\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1377\" file=\"ntoskrnl.exe\" hash=\"31238fc7235b76b0202e67560e7fc3b12db55d512af3da2f732785da24d85895\" timestamp=\"0xbd74b584\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1379\" file=\"ntoskrnl.exe\" hash=\"cd1d217677273db6877f56188e9314999305266b248440ba7b14887dd1f30dff\" timestamp=\"0x90e03e2e\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1411\" file=\"ntoskrnl.exe\" hash=\"4eaa39083c2d1fa4691932186d936f128398b47fdcc5363531476540d760fd07\" timestamp=\"0x235b341c\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1440\" file=\"ntoskrnl.exe\" hash=\"224160cf9b03cf728cc6d129064313104215a7090feec24e3514acf0427e9059\" timestamp=\"0xb5a82e62\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1441\" file=\"ntoskrnl.exe\" hash=\"0002faa2554ea030e52d775bf348a1776d383a0e7cd3a78aecd769f779668a71\" timestamp=\"0x3e61b1b1\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1443\" file=\"ntoskrnl.exe\" hash=\"ae91f8ae236e97cf0c4a54d6e8732e87b76041eecb6f54929ae77dc404a15058\" timestamp=\"0x86cee949\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1474\" file=\"ntoskrnl.exe\" hash=\"ad852e73217adcdd8b9ae72e29887688a2b9923bc2b2b36a8ee3c2fc8593949d\" timestamp=\"0x73d38f28\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1500\" file=\"ntoskrnl.exe\" hash=\"c2a8f5cf7b94b6b8fa3e9dde1d765d053500ee7e774517974d661e90d61d03bc\" timestamp=\"0x6591de0e\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1533\" file=\"ntoskrnl.exe\" hash=\"6e1e3a390cdabe7fc46d6ddbdead7cf5861bf48a0a738f7ecd3ce864f7d37c02\" timestamp=\"0x337ae02b\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1556\" file=\"ntoskrnl.exe\" hash=\"c19d63855583899b6e46f4d884c22398549a70da4df08ba33a9231a35397c0be\" timestamp=\"0xbf2311e5\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1593\" file=\"ntoskrnl.exe\" hash=\"3b63198ebefd1730f6b13cb8ae0835f6d01af3b06cd5dc8317e79662fc287323\" timestamp=\"0x61e42156\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1621\" file=\"ntoskrnl.exe\" hash=\"50980e5cafe3ea978d907d278e8d92d914905e5f12717bfd8591d73e733f3b5d\" timestamp=\"0x21ced777\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1645\" file=\"ntoskrnl.exe\" hash=\"b30a91a401ed04ab61cf902218e52cef577ec4e21359ad22c5ba761265dc4ac4\" timestamp=\"0xdbd12946\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1646\" file=\"ntoskrnl.exe\" hash=\"3926432d68db7f8b426887471721cb0449615069b7b23142623721b6f9df97c7\" timestamp=\"0x1d0f883c\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1679\" file=\"ntoskrnl.exe\" hash=\"8d76c2696fa931f5defde393d4ce441f59bb28d0a59048e737906e3b24664f23\" timestamp=\"0x13cb489d\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1714\" file=\"ntoskrnl.exe\" hash=\"2006e380a5f145d5bd68b89b4d94805bcfc7c18185445f0dac4fe977f2dc6109\" timestamp=\"0x77621990\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1734\" file=\"ntoskrnl.exe\" hash=\"70990afea2a55c3eb207c1356da5fe09d157ed623b401fbb53dc789855e21d85\" timestamp=\"0x85b00e19\" size=\"0x00ab5000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1766\" file=\"ntoskrnl.exe\" hash=\"f67b1479dbd2297a1fee0227b525a58b8e9c49c78e828303e7de1370403fe920\" timestamp=\"0x46d2f146\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1801\" file=\"ntoskrnl.exe\" hash=\"92018427e9190890940a33f67354ce8a8d2f6f4f03191a7ca81f8bae34461eaa\" timestamp=\"0xe08d08a6\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1801\" file=\"lxcore.sys\" hash=\"df5aa278ccf2e025a036d5f3c6dd5d63da8066affddad5001499d51e5e10b56c\" timestamp=\"0xc7ee3f67\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1832\" file=\"ntoskrnl.exe\" hash=\"773953df3defe8b3d2dc48ca5641a7016e72edb65b8b6bc0614ce618ac2044cc\" timestamp=\"0x812d5d1b\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1854\" file=\"ntoskrnl.exe\" hash=\"8fb9651b51329d2a38510a0b092a6fd4a735fe22a958b305af910f0c5195a138\" timestamp=\"0x7ca95b80\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1916\" file=\"ntoskrnl.exe\" hash=\"805ed5232a97dfdfc61a29e59fb8cbbedbe50b142f013e333f1e60da560dbd7b\" timestamp=\"0xafa99d34\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.1977\" file=\"ntoskrnl.exe\" hash=\"fa9f3fd7b32f81f86677b457a0f1019a13d5f0d6de026c31d9d6fd5706b94097\" timestamp=\"0xafd4fbf0\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.2037\" file=\"ntoskrnl.exe\" hash=\"59f2ff479b277f5abae48b0dadac7631468e646c8c1224dcaecef66cffac6d56\" timestamp=\"0xeffdcef1\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.2039\" file=\"ntoskrnl.exe\" hash=\"3cc4f692fccb6a5e95579168a91259ecec3e3d53cbf4b791553ce94888fc9728\" timestamp=\"0x04dc0922\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.2094\" file=\"ntoskrnl.exe\" hash=\"38d6d1ca3c4132d94b66a29c2e6467a3c75c96276e7a951d0f8660eb627a2727\" timestamp=\"0x48831797\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">3</data>\n    <data arch=\"amd64\" version=\"10.0.18362.2158\" file=\"ntoskrnl.exe\" hash=\"b918e21e26da09662d8dd323f4cc082b7a9d69395d8d5438e350fd7e25a82a6e\" timestamp=\"0xa1716123\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">7</data>\n    <data arch=\"amd64\" version=\"10.0.18362.2212\" file=\"ntoskrnl.exe\" hash=\"ae0e6d2ad70cc4cf9e3c123ec0bfa0be4ffe8366aa3b4854ffe951c59e370176\" timestamp=\"0xd7789f01\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">7</data>\n    <data arch=\"amd64\" version=\"10.0.18362.2274\" file=\"ntoskrnl.exe\" hash=\"96880d2301204dd76b315ab35ae17e962ac20a169870bcdc397a2465c06cfd90\" timestamp=\"0x42750de0\" size=\"0x00ab4000\" added=\"2024-09-12T01:41:05Z\">7</data>\n    <data arch=\"amd64\" version=\"10.0.19030.1\" file=\"ntoskrnl.exe\" hash=\"ad033c821c426439ed288d45231bddd72a9d42df1fa4faf6ff987f9b88166883\" timestamp=\"0xea83c58b\" size=\"0x01046000\" added=\"2025-03-02T06:42:51Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1\" file=\"ntoskrnl.exe\" hash=\"25b2a0d539085e598692fdb9deb52fd2e5877ebd702d638098c1194b087194aa\" timestamp=\"0x28b9de6a\" size=\"0x01043000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1\" file=\"lxcore.sys\" hash=\"07409e927627f3c02969737eb23d3f06a3df72f75c3eaeafe972853053834490\" timestamp=\"0x8e0869ef\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.21\" file=\"ntoskrnl.exe\" hash=\"fde0f6f0acacaeb3d1ce55da553dee3326dc6484d35d1facbea4dcfbeb4d24b3\" timestamp=\"0x12170b4c\" size=\"0x01043000\" added=\"2025-12-11T18:37:57Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.84\" file=\"ntoskrnl.exe\" hash=\"fcefa4276cb529e724fb6a89b048a25a7cb54d7b31d5fc044adf0aaec75863f8\" timestamp=\"0x4b2da5bb\" size=\"0x01043000\" added=\"2024-10-30T01:06:53Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.113\" file=\"ntoskrnl.exe\" hash=\"238ad880f7994998251293937202d413f593651d57b19988b44803be5ab754a5\" timestamp=\"0x06593f40\" size=\"0x01043000\" added=\"2025-03-19T05:55:37Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.153\" file=\"ntoskrnl.exe\" hash=\"f8089bfec753f514ca1dd1db261f8edcdde22a57ebd830d8bba6d7daad2e487a\" timestamp=\"0x31cf0885\" size=\"0x01043000\" added=\"2024-11-16T21:02:32Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.172\" file=\"ntoskrnl.exe\" hash=\"a209721c84df38911931a0aa9cbb9e8d9063624e8120844ba347c64a34293582\" timestamp=\"0x4e6edb25\" size=\"0x01043000\" added=\"2024-10-26T06:39:10Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.207\" file=\"ntoskrnl.exe\" hash=\"4da2bec90611b75ceb035c892f11362c1f2da129bcb22b6a84ccb61609bf069b\" timestamp=\"0xe59510eb\" size=\"0x01043000\" added=\"2024-11-05T01:22:32Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.208\" file=\"ntoskrnl.exe\" hash=\"ad63a2731ceb2aa104e6081b323e57d1f4c39156488072dd413c2cc680a604b7\" timestamp=\"0x6a8090cc\" size=\"0x01043000\" added=\"2024-10-29T02:19:33Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.264\" file=\"ntoskrnl.exe\" hash=\"c95935ab90796a0707027d87ab3beb018a366df653d340f29283cb7066d9124e\" timestamp=\"0xbb5cde6c\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.329\" file=\"ntoskrnl.exe\" hash=\"9923b54ed79b57e1fd609b8226bac634d5167a1afcd0eb06bc79d1f1c274d496\" timestamp=\"0x9c63fbab\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.330\" file=\"ntoskrnl.exe\" hash=\"4a9443bba3a42a501e8ded52d0e25341923d53b24be22013039a981b6a1d6cc6\" timestamp=\"0x924b9e55\" size=\"0x01046000\" added=\"2024-11-09T04:03:18Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.331\" file=\"ntoskrnl.exe\" hash=\"a4a3762c9ee0424eb79cca8c61e0978c16f437c158f9ae2f528b84a80ab51851\" timestamp=\"0xbf6dd82e\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.388\" file=\"ntoskrnl.exe\" hash=\"8c71d9df32fe8f63d4865e322eaaad6bf85ebd2b7e05fd3be4ec12b790fb6a85\" timestamp=\"0xa16ce443\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.421\" file=\"ntoskrnl.exe\" hash=\"ce9fe3d0ea27867027027af325d52bda83e6472ab1e57baafda57afdceca4bb7\" timestamp=\"0x188e70be\" size=\"0x01046000\" added=\"2024-11-21T19:38:04Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.423\" file=\"ntoskrnl.exe\" hash=\"f230a92e50b065e6d6307b805369dd275adeec59efaa850cd66e575a31e4fb3a\" timestamp=\"0xce2982dc\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.450\" file=\"ntoskrnl.exe\" hash=\"1878b3aef56db720fda0307fe88d4283849b08af6a7a97d42f3cc8b10081f61b\" timestamp=\"0x07503e39\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.487\" file=\"ntoskrnl.exe\" hash=\"75db4f25ab8eac2a51870381336a53d3e73d65779ed94445a5ade89aa8547bd6\" timestamp=\"0xad73188d\" size=\"0x01046000\" added=\"2024-11-13T15:20:35Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.488\" file=\"ntoskrnl.exe\" hash=\"652557b0a7d3f76e56a186fd0b6c864bc338c5c647c09be3f30cafcca4a96147\" timestamp=\"0x0d6651d6\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.488\" file=\"lxcore.sys\" hash=\"a7d5c56e7ba7f982d7d7c4a68363046c11d4353b75a98d82f510e0ad138d4c30\" timestamp=\"0x5e3f01a1\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.508\" file=\"ntoskrnl.exe\" hash=\"a577850d67d1b4df94e64b3309169e20f3850d4bfa54c40dc9f4f09722e2f5ea\" timestamp=\"0xa371a2e9\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.538\" file=\"ntoskrnl.exe\" hash=\"654f8b2a47fa184473464b6dc5ac374dadf783cd3a46c366a8995972faa3bbe6\" timestamp=\"0xbc732859\" size=\"0x01046000\" added=\"2025-02-17T22:56:35Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.541\" file=\"ntoskrnl.exe\" hash=\"73233afa194af586d2be328ea319b094b9d5ce69382cbfe99ac2bbb2f88e70f8\" timestamp=\"0xf5e8a462\" size=\"0x01046000\" added=\"2024-11-13T15:20:35Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.546\" file=\"ntoskrnl.exe\" hash=\"ba2f70baa3597095c7bb6e0c8792bed0d692095fad1a324d7b419a9bb73bb2c7\" timestamp=\"0x2e6e0ede\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.572\" file=\"ntoskrnl.exe\" hash=\"6ffeab8fc8855ac18a2f0dcc142fe164cfcd98660577432d6bcc7ec961811256\" timestamp=\"0x90ee290b\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.608\" file=\"ntoskrnl.exe\" hash=\"299f2524d68ad7385eb6827c52758d67eb0ca4725e8d04d0d16b4b4d61904fe0\" timestamp=\"0x83578056\" size=\"0x01046000\" added=\"2024-10-29T02:19:33Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.610\" file=\"ntoskrnl.exe\" hash=\"adba735e87f72021a87d10e67710f15b44486a0720711a324e03849da528834b\" timestamp=\"0xdc50cce6\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.630\" file=\"ntoskrnl.exe\" hash=\"f83844e18605fea95ca284161845319fe5aeaaac368362442bdb4b599ca016ec\" timestamp=\"0x64ebcc57\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.631\" file=\"ntoskrnl.exe\" hash=\"ce707a4009b1d65b8d3f51e572fee8939150afb8fde557d0e5ba66db90f1e4ac\" timestamp=\"0xed9dc31e\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.662\" file=\"ntoskrnl.exe\" hash=\"9a2db492037f6512821b5ba141aa9e7b294f9f9d1d85aa71e231608a4eef91da\" timestamp=\"0xdab5d81b\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.685\" file=\"ntoskrnl.exe\" hash=\"acec36b1c1a3665ca16349a928b36f2f90335e4d1d385f7239af2474d7ac25b9\" timestamp=\"0xc129b808\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.746\" file=\"ntoskrnl.exe\" hash=\"c42d99a42dc1f6ce00f7c6d1283bb5ce7e901621c9987fc6bba42f797e5e1f23\" timestamp=\"0xf516cd76\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.782\" file=\"ntoskrnl.exe\" hash=\"9a0aef9391a83fab64bbeb67ca8887c037214453b9314c90bf0f7af21b9fb7e9\" timestamp=\"0x594d5eba\" size=\"0x01046000\" added=\"2024-11-05T01:22:32Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.789\" file=\"ntoskrnl.exe\" hash=\"49e79b90fb6e85e1454c3c2a229c6f0ce1bf0ccc39837ce3f678928995d267ff\" timestamp=\"0xeafca2cb\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.804\" file=\"ntoskrnl.exe\" hash=\"d0051bfdd4c3622d135b754a9df8b4f7a458e3072be8ac94e798b649758593bb\" timestamp=\"0x0d8333e6\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.844\" file=\"ntoskrnl.exe\" hash=\"213f1b487e7a638d0a5f58675b899439149ab8ce5cd9f8dedf26dc16203efd0a\" timestamp=\"0x36a5d042\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.867\" file=\"ntoskrnl.exe\" hash=\"a1d919ea067bc879e51745e777eb1ed8d9be44d623f50976b59e79cb4d8bf1a3\" timestamp=\"0xd3f64697\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.868\" file=\"ntoskrnl.exe\" hash=\"22b84000410143adcdb7062d1cd22c1e0d09c92e0b8d24f084b698f56cd59465\" timestamp=\"0xdb4e4103\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.870\" file=\"ntoskrnl.exe\" hash=\"bac55981be595c6d170ffeb2a033e9e2883bb4b2ff6dc22dbcd540f6b3a2ced0\" timestamp=\"0xd3c2899f\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.906\" file=\"ntoskrnl.exe\" hash=\"1ecf6655ae5a8d8d309a5b6f0b95f74907df03cab846d88114ca43fa3f7c0c44\" timestamp=\"0xe5187294\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.928\" file=\"ntoskrnl.exe\" hash=\"fd167e59573a944b4170e9e167861484a74d79d84c39202bc7d87890a85f175b\" timestamp=\"0x0ea0877a\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.964\" file=\"ntoskrnl.exe\" hash=\"604c6ebd45c71c6ceae0edb918c435362c1828a0d2665f250512b70d9681f21a\" timestamp=\"0x1dfe6106\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.985\" file=\"ntoskrnl.exe\" hash=\"c9abc778e392e3c7568fed0efb0460b10732c7f290c09c6a8a96fd3e885720e9\" timestamp=\"0x411f9e5a\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1023\" file=\"ntoskrnl.exe\" hash=\"16ab962cc9ee80ead31680b6d23be231469893636d69076d0dbcaaa7737bc985\" timestamp=\"0xe304ea6d\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1052\" file=\"ntoskrnl.exe\" hash=\"5961b49dfbf2898f8fd1ea9b0f2ccc167a320671599809f748c6bb3ff700dd3e\" timestamp=\"0x05c0e3e0\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1055\" file=\"ntoskrnl.exe\" hash=\"e4fb7faf39fec89f84c22bc68d35b5fbfa4a8fa2d367905a1cb3ce6ffd8fdab9\" timestamp=\"0xe7b94d9c\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1081\" file=\"ntoskrnl.exe\" hash=\"601033c74a9e1ca2fc16a6d43eacd395760d166a7d2523145752952f4796cd6b\" timestamp=\"0xab81c410\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1082\" file=\"ntoskrnl.exe\" hash=\"71a1454a1c75c5f3b691a5ef25ee9136fec8852049c1fd27a09e998e92b3d9a4\" timestamp=\"0xe9f22a7a\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1083\" file=\"ntoskrnl.exe\" hash=\"b28e07c258cdd72678488909604950b88814e123d61f693e78831b6a59ad3b81\" timestamp=\"0x150e143a\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1110\" file=\"ntoskrnl.exe\" hash=\"8453f9dcb8f86c04fc0ce1cf357018973939b4d7027bc87dc5d9c37c8601ad18\" timestamp=\"0x553df94c\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1151\" file=\"ntoskrnl.exe\" hash=\"f5d3c66efb00f7c086220a862fc64d14b9950a7c6742b38e263984ebf2e431e8\" timestamp=\"0xf45b9c9f\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1151\" file=\"lxcore.sys\" hash=\"d29200d80eb4183545885d0f4fd4c2712ab1a48104989002cc046acc8556f525\" timestamp=\"0x2c77b6de\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1165\" file=\"ntoskrnl.exe\" hash=\"4ffa3d9c8a12bf45c4de8540f42d460bc2f55320e63caac4fdfabbb384720b40\" timestamp=\"0xb8d5e641\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1200\" file=\"ntoskrnl.exe\" hash=\"c702fbc3eb6f11167005f1939ad47a6365e309e95723a03f5a4c6599a6a67c24\" timestamp=\"0x4317f799\" size=\"0x01046000\" added=\"2025-08-12T14:43:40Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1200\" file=\"lxcore.sys\" hash=\"d8a42ebdb9f146e270cc37ace09b1fc37be9a0a882ea82782dc1d21d8c9063b5\" timestamp=\"0x8414129e\" size=\"0x00118000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1202\" file=\"ntoskrnl.exe\" hash=\"9ac67c83d7c5bf7d6a9d56adb65739f7fc3f03b15f963c5d6e636132e3756115\" timestamp=\"0x8a51a6f0\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1202\" file=\"lxcore.sys\" hash=\"a859e0c995bb5190461db79c3a2d290d62ee0677636271be2a4c9008ac6cbd32\" timestamp=\"0x9a37b06b\" size=\"0x00118000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1237\" file=\"ntoskrnl.exe\" hash=\"74c8ed223688bd121d4718b9919352695a3775657289b1715bd89a5e70364535\" timestamp=\"0x7a04bfb2\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1237\" file=\"lxcore.sys\" hash=\"a42856aa3235addfa4b55590062273adcf5f69730b76359ea89dd314b50402ce\" timestamp=\"0xcea9f88e\" size=\"0x00118000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1266\" file=\"ntoskrnl.exe\" hash=\"ed402a1ba78cb8a91eb5f2330be4d80ea34770c27809e2b86c96ad353e47ee48\" timestamp=\"0x6e567aa7\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1288\" file=\"ntoskrnl.exe\" hash=\"11dce42a13a49f025856414748b03e62db7c955d6894a3c36cb3776aa45be857\" timestamp=\"0x2f0a239f\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1320\" file=\"ntoskrnl.exe\" hash=\"7dd334edd7db7fc6f8c170f3338c92e2cf30a621cdf5b50727d210d8434974ee\" timestamp=\"0xc989af00\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1348\" file=\"ntoskrnl.exe\" hash=\"8a5e0683ea17f4c571356849692638e5fd45aaf8567efd72bca7a55892529b9f\" timestamp=\"0xf0572342\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1387\" file=\"ntoskrnl.exe\" hash=\"9aaff7ba5751dc696d765791f126459725d2b16ad5ee950ccdec6c73184d9e78\" timestamp=\"0x8df2030a\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1415\" file=\"ntoskrnl.exe\" hash=\"919599fa3c8e350791eb5cd79df4dfbe18fb9bb4c658acad740198efd498c476\" timestamp=\"0xfa45fa21\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1466\" file=\"ntoskrnl.exe\" hash=\"7eb83c81b9c6b54785087eaab5201ac7863d48f2974378c12bd2b9af55efb54f\" timestamp=\"0x272315a8\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1469\" file=\"ntoskrnl.exe\" hash=\"a233ac9de36d60fe3d6bb4ff1c8444f81fcd26b26980f2cead7556651d8da84e\" timestamp=\"0x4e88dd5c\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1503\" file=\"ntoskrnl.exe\" hash=\"9e97e8170d44eeddd490c5121808d39b4de823d2013b0a2c445542b6bf4f9ba2\" timestamp=\"0xd2962b56\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1526\" file=\"ntoskrnl.exe\" hash=\"979bee0df7c8d0a902f9f69cb358d56cee542c7240962f723a9461c43bc8edc2\" timestamp=\"0x6a58a618\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1566\" file=\"ntoskrnl.exe\" hash=\"a779978161299ccbb2df1616f7bb5f74d7aec2070e22d76825a03341be10676a\" timestamp=\"0x0bd43350\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1586\" file=\"ntoskrnl.exe\" hash=\"4d5b2985d212084004a46672f992fd08fa44062cd31571c280aab2681b8e386b\" timestamp=\"0x7cc04cfb\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1620\" file=\"ntoskrnl.exe\" hash=\"011f8f6ae707ec32da9cde7695ad698df0ad656a6c2f26e08c3125240a4ef668\" timestamp=\"0x1dbb86c2\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1645\" file=\"ntoskrnl.exe\" hash=\"346502c5443f161a564a3b718be980c4a8bf139ebb84821e8f61dbedc3e83d0b\" timestamp=\"0x06e35293\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1682\" file=\"ntoskrnl.exe\" hash=\"cae6d772ba15e89e3e8307cb775b2488a64a0460e2e081d388886162612a1fb2\" timestamp=\"0x4a40f784\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1706\" file=\"ntoskrnl.exe\" hash=\"efbc7f3eb3cd767a1bd9fd82329461b66e98ffe4fa67d3937f59887ac1e8bf2d\" timestamp=\"0x01dc8893\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1708\" file=\"ntoskrnl.exe\" hash=\"fb7c21547e82e9e930ca42b4cf1163fe0170dfded5bb898cfa22029c6bd18819\" timestamp=\"0x8d8e538e\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1737\" file=\"ntoskrnl.exe\" hash=\"89b28d8e7842a6ba26e4c9f4ddbb2db3d134bf38e0d4d4036a4e4bd181bea139\" timestamp=\"0xfa2b3ca1\" size=\"0x01046000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1741\" file=\"ntoskrnl.exe\" hash=\"511a3c5c227a9460989a391f1da5e8704e0d2d3a6eaa7555ac6c1831f5390720\" timestamp=\"0x075fd74c\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1766\" file=\"ntoskrnl.exe\" hash=\"8d8556f35e8003ea0beac15250d810071ec8ea01d38a18e763027a4aa53749a8\" timestamp=\"0x79c14748\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1806\" file=\"ntoskrnl.exe\" hash=\"6b24f3f5a13934418e879dbaf3a9ab5a8bd989cbd4509577499e3c7704af3f1b\" timestamp=\"0xdf37e68e\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1826\" file=\"ntoskrnl.exe\" hash=\"2c9299efa63e9ea31c8c3815f7e521046f1a69ec9623c11dd03fc9e154a65d83\" timestamp=\"0x73f1c0c4\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1865\" file=\"ntoskrnl.exe\" hash=\"f801aee0d8e2bd0d2fbdb0f812d045771bd1e60f54cedd25ac85a881030ccbae\" timestamp=\"0x9a263d24\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1889\" file=\"ntoskrnl.exe\" hash=\"9392666e693572f12bc560cbdd4a6ca1ce5e95faeea1bd750a96e9ac7b944494\" timestamp=\"0xe22246d9\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.1949\" file=\"ntoskrnl.exe\" hash=\"dfd78bdbcf5507d24c2602d0200b8f76356f8e98333f7d1f10bdf6f5ee691df1\" timestamp=\"0xd5b8d792\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2006\" file=\"ntoskrnl.exe\" hash=\"cc9b3a6c057ca31d0886c8efb7965a4c47e2d80fd0185d9b9fa55c5dc1d0dc55\" timestamp=\"0x2ff0d722\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2075\" file=\"ntoskrnl.exe\" hash=\"4927b4528c1f18abf8fbfc364617845adc2e709d0a712f25c10c109564bb2f96\" timestamp=\"0xa7c6f73a\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2130\" file=\"ntoskrnl.exe\" hash=\"fc4864065d84ccb4c855f4c47afa318113c1ba81e105c2ca0a8a33b51fe72299\" timestamp=\"0xc103e0da\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2193\" file=\"ntoskrnl.exe\" hash=\"79e2a676786e5fdee9181c2ba7a71978e03a3639a302633279755fe2758ceb8c\" timestamp=\"0xbf639dc3\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2194\" file=\"ntoskrnl.exe\" hash=\"54813e3be3d823aed202db6e68be8741f5bb55c39e83cf4452538ef7c94301f9\" timestamp=\"0x5dcbe587\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2251\" file=\"ntoskrnl.exe\" hash=\"7e4a848626c99c715bd2c8686061420b8895e12ab8dfa0cce091f9df25750c13\" timestamp=\"0x7deeab75\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2310\" file=\"lxcore.sys\" hash=\"d469ef00c274846c0dc1ab66ba10199f2769be79c32d6c7bc1368ab072c67329\" timestamp=\"0xfb7389cd\" size=\"0x00119000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2311\" file=\"ntoskrnl.exe\" hash=\"3a9c2aab568d8f944d034a9c8981ad647855fd0a2f4bd596dccfa4295b2b854c\" timestamp=\"0xff67283a\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2311\" file=\"lxcore.sys\" hash=\"69c83598768b7ef7abd07862ce62c031bd9258ccfe268b0c1cf5d6815cff4aa1\" timestamp=\"0xb9d32e4d\" size=\"0x00119000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2364\" file=\"ntoskrnl.exe\" hash=\"bc4b64553cd9b81e2fd5e382fd4024d4eacc04417682c02b468900ea79883238\" timestamp=\"0x0e02afc5\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2486\" file=\"ntoskrnl.exe\" hash=\"15b43062b002432b89fa7f799cf2b3021a485e5e48fc38db62bda270b598f671\" timestamp=\"0x33c5e414\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2545\" file=\"ntoskrnl.exe\" hash=\"4ab192399160f405c840fe939dd73de38cac5414e20f9ec9f5f0bf6bd9c9bd06\" timestamp=\"0x07e6ec8b\" size=\"0x01046000\" added=\"2025-03-14T04:05:46Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2546\" file=\"ntoskrnl.exe\" hash=\"ea520ed6590f042d9a12b29e9fba921683c15b1a8f73a7e865582619f4095893\" timestamp=\"0x76edfc02\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2604\" file=\"ntoskrnl.exe\" hash=\"223af7d155e647b4d1f357b6f68373e34f22c359f883a20f4b433de20a025f68\" timestamp=\"0xc3f2329e\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2673\" file=\"ntoskrnl.exe\" hash=\"e3a3fd9b9de67c744dc29a5c27e57a25b87511a6b5c602eee2ea5ecd9cb4baf5\" timestamp=\"0x1f791c27\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2728\" file=\"ntoskrnl.exe\" hash=\"cfbd58c465439c25065cc153ebf99980eb03dc6edb731b444efb090e01d64da7\" timestamp=\"0xbdc97bfc\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2788\" file=\"ntoskrnl.exe\" hash=\"9e026adf332650e4ba60db04a242683b0373d3a7751e49b8a1d0867315877484\" timestamp=\"0xcda2cb94\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2846\" file=\"ntoskrnl.exe\" hash=\"147901e279255564c99d1e1ce845794a7b175aee8a60027df77fbc8e667759b6\" timestamp=\"0xe8674c06\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2913\" file=\"ntoskrnl.exe\" hash=\"6f43398f2e8c7ef3a1bce8115405a662c10fdcfea9c2bbc63a1ab25b9b9ac942\" timestamp=\"0x76953e96\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.2965\" file=\"ntoskrnl.exe\" hash=\"eace65a06bab6b67461ed29783cde9367c3ddd2a31b2594c59d22d77460d4f4b\" timestamp=\"0xf71f414a\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3031\" file=\"ntoskrnl.exe\" hash=\"2e39d967fb7ae1d727a091ba19bf27240ac969d74875342668eb0fa9ad1b58d2\" timestamp=\"0x97dd1139\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3086\" file=\"ntoskrnl.exe\" hash=\"9c4a699872215f77484bd037724599bbd0f00d38b7750433edd3b591576050ec\" timestamp=\"0x23c7fc51\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3155\" file=\"ntoskrnl.exe\" hash=\"2a704063c806068c3ab89158c860f802e61e884083557d3a639d4dd677823381\" timestamp=\"0x37ba448d\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3208\" file=\"ntoskrnl.exe\" hash=\"e8e6040640c9dddc8feeb0a9310bab92e7e422ef469beabdd8b5bb63b7a9dad0\" timestamp=\"0xa62a1a64\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3271\" file=\"ntoskrnl.exe\" hash=\"fa2158e0f4b1d9b29f294b10f3bcdba2083a65707bb2ac252525dbfcd05a79d0\" timestamp=\"0x8e0020e1\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3324\" file=\"ntoskrnl.exe\" hash=\"3a7bbe1c5fe0cd115ede21a01341f9e2be30b4bdf81feb89e982de5630ce883f\" timestamp=\"0xeaeb45c9\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3393\" file=\"ntoskrnl.exe\" hash=\"4b6086304a7cb47e305e59c69eda946aa509f5b91bfa9f50582e25239942be21\" timestamp=\"0xa4fb3525\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3393\" file=\"lxcore.sys\" hash=\"ec5e5757dd616c60a073620c70f7816a8119df2893c1453cd8cf232006d3e5b8\" timestamp=\"0x4d5f598b\" size=\"0x00119000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3448\" file=\"ntoskrnl.exe\" hash=\"d436d6bbf5b73a7fbade752d9d548326dc8ab464f27bf3dfda70f7fbe2d519a9\" timestamp=\"0xcfee68af\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3516\" file=\"ntoskrnl.exe\" hash=\"2ee30082fbb10398d94e826327891c55cadf5d464625f360419d21383bf80510\" timestamp=\"0x124e45b5\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3516\" file=\"lxcore.sys\" hash=\"2c640b8fe878e33519db805190c6a460a88ed0c1331d4d33448ac3162d1d9dd0\" timestamp=\"0x2233c86f\" size=\"0x00119000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3562\" file=\"ntoskrnl.exe\" hash=\"85732ed5e3fa041188da23c231f2c38a970e0950e3905b46f1d3d96e7e48293c\" timestamp=\"0x66e2f18d\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3570\" file=\"ntoskrnl.exe\" hash=\"9525de34802380a2d101e788c0b1d0b7fbb4fdf146e915253d64d931b858fe2b\" timestamp=\"0xe5369842\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3570\" file=\"lxcore.sys\" hash=\"668dce812c3201ed50fb2696a581856d2eaaa99128cb899411c157373f0202d5\" timestamp=\"0x5310aafd\" size=\"0x00119000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3636\" file=\"ntoskrnl.exe\" hash=\"1f248ab742164df3ef8b0d6114f0b5ae8f77fa1ffd7322e3da843692106d1438\" timestamp=\"0x03558bb3\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3636\" file=\"lxcore.sys\" hash=\"e6e7e5896524efac3255e3743889e2b2af9d69f23520d740afc21888ea96eb89\" timestamp=\"0xe00ada72\" size=\"0x00119000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3693\" file=\"ntoskrnl.exe\" hash=\"1ad490cc37aff28f00ace39f99d27bab11b1d9d36095409888d09db2b143571e\" timestamp=\"0xad941e79\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3758\" file=\"ntoskrnl.exe\" hash=\"3d2a9b05fd8de5c1c86e2ff48e25d5678017fcb09b8f47266bbb6d72bec8fd47\" timestamp=\"0x04530a89\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3803\" file=\"ntoskrnl.exe\" hash=\"5788ef18e2cdbc8bdddf1ddfaf2975652df18c469e11db0d51c98970e6c4636e\" timestamp=\"0x5dee2b07\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3930\" file=\"ntoskrnl.exe\" hash=\"8a318674092f5ecdccc9818521946bb1f1df95849df898df1494b79c8241971d\" timestamp=\"0x464f5428\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3996\" file=\"ntoskrnl.exe\" hash=\"1b2d6e491df661a37dce2850696cfb8bc02c98d73f8fcd3db27c380c0d75f829\" timestamp=\"0x92fce16e\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.3996\" file=\"lxcore.sys\" hash=\"4fcd8ae8ad94f48e32eeb09c84508930f41432761b5147df8613fad17e000e1c\" timestamp=\"0x460a3d32\" size=\"0x00119000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4046\" file=\"ntoskrnl.exe\" hash=\"4efcd51661325335ad88ff1b71f0477f868bb81f8bb6eb22e683ea12780b2cea\" timestamp=\"0xd86064dc\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4123\" file=\"ntoskrnl.exe\" hash=\"3a52f07b7ca0a5e09e6ca59b05372b10bfb9c9a89b6f4c6686bfe04d4cff0110\" timestamp=\"0xe6582fd1\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4170\" file=\"ntoskrnl.exe\" hash=\"e747dfcef5af0356153c3c57902293919bacab7ae501afd75c937163dd58a6f0\" timestamp=\"0x3e4ef1d4\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4239\" file=\"ntoskrnl.exe\" hash=\"5e26e6bf584d5c52a1d5844a9c8004797c00814a3c4d06289cda19593b3c2c12\" timestamp=\"0x99b9d1d1\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4291\" file=\"ntoskrnl.exe\" hash=\"d2d44a847fa61ad52982e5694db1376695fd60bc9698060eedd17fc646422f49\" timestamp=\"0xac31da29\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4355\" file=\"ntoskrnl.exe\" hash=\"c9a859e48a6cf903b62444c79c7a73b83bba057d1148b5d709f732c7bb92629a\" timestamp=\"0x46d28cac\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4355\" file=\"lxcore.sys\" hash=\"22a0535cc47ad7b47b46556311b49c9b56582f7edec91a3d28a71a4b43fde066\" timestamp=\"0x68fea821\" size=\"0x00119000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4412\" file=\"ntoskrnl.exe\" hash=\"f9e2d1f0b0d47ba24979a283d435a4e9f9f4194b07669a33d0904c64e812dc1c\" timestamp=\"0xa070c915\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4474\" file=\"ntoskrnl.exe\" hash=\"0d14f42d655509dc9078bc32bcebcd1fd75d79da8b3c97119876d437468dff87\" timestamp=\"0xb737c41e\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4522\" file=\"ntoskrnl.exe\" hash=\"f729521924dc164f7855ee16b218e86cbc767057c7bcb512e1137673c8021353\" timestamp=\"0xa03d2496\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4597\" file=\"ntoskrnl.exe\" hash=\"94ede189505daaf5f003aa4c6ed8829172d219da3d373513db3e7cbc4e9e5b9d\" timestamp=\"0x1ec3823b\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4648\" file=\"ntoskrnl.exe\" hash=\"5b5072b0524c90e98d869a2b4c5c089998f3642f2dc2c5bf82989caccb0a58a4\" timestamp=\"0xc9669e93\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4717\" file=\"ntoskrnl.exe\" hash=\"a9c28c70a1921e01f8208e7a609cc0847479dda62ae3ed01ae4be920dd08593a\" timestamp=\"0xf84f6b4a\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4780\" file=\"ntoskrnl.exe\" hash=\"5f7d1f531ab2c6de6c55a16d129e72c798cde9c702f12dbf633ba3466cebd517\" timestamp=\"0x48a9097c\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4842\" file=\"ntoskrnl.exe\" hash=\"d96cb1916f17e98d5fe757b471888a48c8e777e8e015a42688f5cb28dc4c5105\" timestamp=\"0x5d70bfa9\" size=\"0x01046000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4894\" file=\"ntoskrnl.exe\" hash=\"6e69b12ba30d241b8f61464a34b2a9d056e80fde73f04a342b90b7c99d46044c\" timestamp=\"0x3fec999c\" size=\"0x01046000\" added=\"2024-09-12T01:41:07Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.4957\" file=\"ntoskrnl.exe\" hash=\"6ca61bc3b100391f86046050b6c881b8b94a7423128b1f499db8adf3a70e772b\" timestamp=\"0x6ab9349d\" size=\"0x01046000\" added=\"2024-09-26T00:30:31Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5007\" file=\"ntoskrnl.exe\" hash=\"b657b601085117768430ac44b95bd6d81a0779d06dcac3ae4e45cd95923857ca\" timestamp=\"0xbb0b9776\" size=\"0x01046000\" added=\"2024-10-09T02:21:15Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5072\" file=\"ntoskrnl.exe\" hash=\"077e25aa2378b48b6c7c1530767ced99626693b21492018f376ebfbb50fcc247\" timestamp=\"0xf44468cb\" size=\"0x01046000\" added=\"2024-10-23T02:12:58Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5129\" file=\"ntoskrnl.exe\" hash=\"a7a11a6f277b30bb7029d33e20ea4746155c321739eabe94ca60d7cef7883249\" timestamp=\"0xf5e79fc4\" size=\"0x01046000\" added=\"2024-11-13T15:20:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5198\" file=\"ntoskrnl.exe\" hash=\"458b6b991746bec2121794ab779ba3e3f85ca3f6ea32faacf587bf9b60112d05\" timestamp=\"0x6e2f622d\" size=\"0x01046000\" added=\"2024-11-22T17:11:50Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5247\" file=\"ntoskrnl.exe\" hash=\"dabe030ba16354b048e41913245aca1c59c675c03bc2a2a631deb92076e3bf27\" timestamp=\"0x1aa75f33\" size=\"0x01046000\" added=\"2024-12-11T14:53:46Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5369\" file=\"ntoskrnl.exe\" hash=\"0b98c3730b7d8f0736c81a58fad15071696eb879946b3e330107ac6934ad7f7c\" timestamp=\"0xd9a988a9\" size=\"0x01046000\" added=\"2025-01-15T01:55:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5440\" file=\"ntoskrnl.exe\" hash=\"95069a820e7656da9521bd024ae368e03150c9b0dc774f69c2520be767ce2c5f\" timestamp=\"0x10e471f5\" size=\"0x01046000\" added=\"2025-01-31T00:35:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5486\" file=\"ntoskrnl.exe\" hash=\"00bddcb825d2bbc566c6ffd80b5d41db1c49dba3f6dae68b3dc66676040a5bd3\" timestamp=\"0x65127fed\" size=\"0x01046000\" added=\"2025-02-12T06:18:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5553\" file=\"ntoskrnl.exe\" hash=\"00056cddf6f25d7fdd783f3079e0f39503c105361b61bd3bea42780262316015\" timestamp=\"0x694881a1\" size=\"0x01046000\" added=\"2025-02-26T02:04:23Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5607\" file=\"ntoskrnl.exe\" hash=\"f25c0bff5eedfce2e90842dd72597ee6dc468ff3ad711e233c4926529d24b7bc\" timestamp=\"0x89515290\" size=\"0x01046000\" added=\"2025-03-11T22:25:17Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5678\" file=\"ntoskrnl.exe\" hash=\"34e39619b1316232b4786dce7825bc7e524a963a802a6ab08c4ade78fbfb3c8c\" timestamp=\"0x784db3fc\" size=\"0x01046000\" added=\"2025-03-28T03:59:19Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5737\" file=\"ntoskrnl.exe\" hash=\"23b2d4d6e35c31f93e0bfedd6cf9c958deac1c7ea39d78eaa2c35937b5d907b5\" timestamp=\"0x7e692880\" size=\"0x01046000\" added=\"2025-04-09T14:22:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5794\" file=\"ntoskrnl.exe\" hash=\"f394a43b4aad1936af9a4fc6954904c22b9193a105b26cb9113a18652068eed4\" timestamp=\"0x5b5ec878\" size=\"0x01046000\" added=\"2025-04-23T00:45:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5794\" file=\"lxcore.sys\" hash=\"27da12eb6e55560f125696646558ab4cf75277d5a6079ace416ea2a6402b558b\" timestamp=\"0x3532d2b4\" size=\"0x00119000\" added=\"2025-04-23T00:45:13Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5848\" file=\"ntoskrnl.exe\" hash=\"a46fe2afcf1dd7cfafebe2946217b1fc866f7881a322f69f24898225c1828145\" timestamp=\"0x57f3e19d\" size=\"0x01046000\" added=\"2025-05-15T00:22:34Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5856\" file=\"ntoskrnl.exe\" hash=\"020a37bc0a8dbf3d1a040afbb15eac0ffa6df6ccbd2b6a9eba421b7d31bcddfa\" timestamp=\"0x0f460dd5\" size=\"0x01046000\" added=\"2025-05-22T02:15:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5915\" file=\"ntoskrnl.exe\" hash=\"22c4119a6e37ec77cc520068a22faab1a59f5ab17f25dbd5971844832709ce2d\" timestamp=\"0x7407dd2d\" size=\"0x01046000\" added=\"2025-05-29T05:57:37Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.5965\" file=\"ntoskrnl.exe\" hash=\"9af901fe53bc6b0a5ee97ab65e2709baf74f4ed407d3003f93f44425ac744c7d\" timestamp=\"0x70142527\" size=\"0x01046000\" added=\"2025-06-11T00:42:44Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6033\" file=\"ntoskrnl.exe\" hash=\"68a62b2da2623e86e8e35d2c9295c5570f60d9d6e4352637177daaf3e3101f14\" timestamp=\"0x98ae0a8e\" size=\"0x01046000\" added=\"2025-06-24T22:12:14Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6093\" file=\"ntoskrnl.exe\" hash=\"a3c9b171416ecd281b9891051d128948ce3a7bcba2a8d60b920ed832637e66a8\" timestamp=\"0x7feeb878\" size=\"0x01046000\" added=\"2025-07-08T22:13:00Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6094\" file=\"ntoskrnl.exe\" hash=\"08e4fa945b65742e1bbd19adb22d2e58f20629df8761ad6a78c57876c8e22b8a\" timestamp=\"0x91b7f76c\" size=\"0x01046000\" added=\"2025-07-10T01:24:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6157\" file=\"ntoskrnl.exe\" hash=\"590d503925506a4388c503d894363b1f0eaf7ee67cda0c77cca9e34de7a4aa40\" timestamp=\"0x114db43a\" size=\"0x01046000\" added=\"2025-07-23T02:01:02Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6216\" file=\"ntoskrnl.exe\" hash=\"13dbc938fb3997d7189121b350f0c40c4b6ae5c457d89d08f142951bba310a30\" timestamp=\"0xbca5a8dd\" size=\"0x01046000\" added=\"2025-08-13T21:37:12Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6218\" file=\"ntoskrnl.exe\" hash=\"5b4f3a5ef1141fdd2fd0e53bf3b9da26588018d2036ae74433c80503d9a9e873\" timestamp=\"0xc46d782a\" size=\"0x01046000\" added=\"2025-08-20T05:10:57Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6280\" file=\"ntoskrnl.exe\" hash=\"d270401cfd07e0625a9e87fc94818f75a7865dc2f93fa451d32c9ca0b26380bd\" timestamp=\"0xfa9c4273\" size=\"0x01046000\" added=\"2025-08-27T04:03:40Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6328\" file=\"ntoskrnl.exe\" hash=\"331bc90db64b52e18231f17a75f563e93936d4ed59d896ad89fc8775c5cff268\" timestamp=\"0x39b66567\" size=\"0x01046000\" added=\"2025-09-11T03:22:38Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6389\" file=\"ntoskrnl.exe\" hash=\"ab3008c48cbb15a00df15cb79288231c9562763508563cfaf57820694f5d253f\" timestamp=\"0x1ed4a47e\" size=\"0x01046000\" added=\"2025-09-26T02:51:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6392\" file=\"ntoskrnl.exe\" hash=\"1c53302f17112b1a2cfd589e96439b0e69027a83cee3b6474c2ffcb67de5d92b\" timestamp=\"0x629f5a08\" size=\"0x01046000\" added=\"2025-09-26T02:51:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6455\" file=\"ntoskrnl.exe\" hash=\"df94a03236f53f5f03fc2f3267b4892b7f4ab2e74e9670a41ad32701bb3f3c46\" timestamp=\"0xfcd0be7e\" size=\"0x01046000\" added=\"2025-10-16T23:37:47Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6456\" file=\"ntoskrnl.exe\" hash=\"563f486f45853248e54b3ee800d6b19289101c6cca15e0e3fa11a70452b5ce91\" timestamp=\"0x1c62bee3\" size=\"0x01046000\" added=\"2025-10-15T03:12:43Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6566\" file=\"ntoskrnl.exe\" hash=\"dabb24259129548589cc9ce3299da88820423536b47b19ff7c5baf120cad8298\" timestamp=\"0x272cf006\" size=\"0x01046000\" added=\"2025-11-12T23:55:08Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6575\" file=\"ntoskrnl.exe\" hash=\"432155c8f34cdcf0407308305d59200288b4c3b86e7f6afe6f5f862b201b8a2b\" timestamp=\"0xe1bf94fb\" size=\"0x01046000\" added=\"2025-11-11T19:37:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6683\" file=\"ntoskrnl.exe\" hash=\"1e9f51ef0ca5b1581244692bb86330e9a5cc4c11bae8f253ec061344a371d455\" timestamp=\"0x918887e5\" size=\"0x01046000\" added=\"2025-12-10T04:39:55Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6691\" file=\"ntoskrnl.exe\" hash=\"0e44d8c90fbec261066898cd41a24d15b6cea5581ed4b7b1c67dd05b4c12e4bb\" timestamp=\"0x98d41899\" size=\"0x01046000\" added=\"2025-12-11T18:37:57Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6693\" file=\"ntoskrnl.exe\" hash=\"58f62f8d4582b033712b3d144e47e27076ef87a7bab80729518050ac2851d15b\" timestamp=\"0x109d58b9\" size=\"0x01046000\" added=\"2025-12-24T02:56:52Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6807\" file=\"ntoskrnl.exe\" hash=\"fb3347be01f878bd2a8d769020193a2d0cc1c45b265fe3f513a2784f096c0235\" timestamp=\"0x2fbe9676\" size=\"0x01046000\" added=\"2026-01-15T04:51:11Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6807\" file=\"lxcore.sys\" hash=\"4095d77573adcb625efbb9765679a5117b72e0300ec6bb814ca87fd47018ccb3\" timestamp=\"0x5967a0b8\" size=\"0x00119000\" added=\"2026-01-15T04:51:11Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6811\" file=\"ntoskrnl.exe\" hash=\"aa71170f5ec1b9521b7b180e1c140be32b1cb33fdc305ca9265be4e4043c1f02\" timestamp=\"0x50ef554d\" size=\"0x01046000\" added=\"2026-01-22T02:43:17Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.6926\" file=\"ntoskrnl.exe\" hash=\"9a853a15243b934416f16e0f3ae3a928c0066d83b8ab13fedc2ec976e2cf8310\" timestamp=\"0x7faad808\" size=\"0x01045000\" added=\"2026-02-11T00:54:58Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.19041.7058\" file=\"ntoskrnl.exe\" hash=\"b1735d629107b23ce1606fed839a9abf8528d1495bdce220695b272fc02cd8cc\" timestamp=\"0xf01e5bc4\" size=\"0x01045000\" added=\"2026-03-11T23:28:21Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20231.1000\" file=\"ntoskrnl.exe\" hash=\"b2a5f8281131dc997a90612aac248f76dab2fc65a7ebc90821cb73abe9eac053\" timestamp=\"0xaff4d52a\" size=\"0x01047000\" added=\"2025-06-11T00:42:44Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20231.1000\" file=\"ntkrla57.exe\" hash=\"1fb6f38f80b0d1f1b8f43981de00bddf0512e993887af887e938e4b7a3f80962\" timestamp=\"0x1249513d\" size=\"0x01043000\" added=\"2025-06-11T00:42:44Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20270.1\" file=\"ntoskrnl.exe\" hash=\"f7dd4adcd43d67750df2c19a3d7d2dd0fc4a59a640e34447360df2fd5e32df45\" timestamp=\"0xc2353282\" size=\"0x01047000\" added=\"2025-09-26T02:51:04Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20270.1\" file=\"ntkrla57.exe\" hash=\"55fece6fddab09c442176734d76f668482a78566ce939091ce6d661b62fe2c5f\" timestamp=\"0xb44daf76\" size=\"0x01042000\" added=\"2025-09-26T02:51:04Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20279.1\" file=\"ntoskrnl.exe\" hash=\"87d3b77d78d08f0218269f3fb3fb08cc6c6aa2a34a22e3e359108504f0e25c57\" timestamp=\"0xb26b9630\" size=\"0x01047000\" added=\"2025-07-19T02:10:13Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20279.1\" file=\"ntkrla57.exe\" hash=\"44ec4957d5a732cd494b500c37e0d751aacf89a02fa6af7e4aa73bd2faef4eae\" timestamp=\"0x9e0d3243\" size=\"0x01042000\" added=\"2025-07-19T02:10:13Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20324.3\" file=\"ntoskrnl.exe\" hash=\"253ed6cf3c158c25fe80c019a7d05317e1645108ace9933fb89611908898a6d3\" timestamp=\"0x4a801d69\" size=\"0x01047000\" added=\"2025-05-29T05:57:37Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20324.3\" file=\"ntkrla57.exe\" hash=\"774d7607ccbe7cacdc284ee9791562a41252f999caac444ee2cc56226561e4b3\" timestamp=\"0x6c367ed8\" size=\"0x01042000\" added=\"2025-05-29T05:57:37Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20344.1\" file=\"ntoskrnl.exe\" hash=\"1dbdddb3cb39652c8a282fbcc4d071205d78c8a04f8ef61cdd842e2eebc942cc\" timestamp=\"0x3e126ca4\" size=\"0x01047000\" added=\"2025-04-19T15:54:38Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20344.1\" file=\"ntkrla57.exe\" hash=\"8e451c74e47d7cfe637a7e110336f7ddc742fccf03dc50f860ca818bbcb0acad\" timestamp=\"0x94de5735\" size=\"0x01042000\" added=\"2025-04-19T15:54:38Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1\" file=\"ntoskrnl.exe\" hash=\"15f9bb11899bd88546833fe6da862afd539b4c4c188c379b167cecba425bda27\" timestamp=\"0xc9e9f6bd\" size=\"0x01047000\" added=\"2024-11-24T17:20:19Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1\" file=\"ntkrla57.exe\" hash=\"438385de83eedd42143117647c5479af07e9adf4a06d00b080ae183437efb6fe\" timestamp=\"0xf181ee39\" size=\"0x01042000\" added=\"2024-11-24T17:20:19Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1\" file=\"lxcore.sys\" hash=\"9e0a8c9146c84e2870ee2cbfe38bdaf4b356f8866399e7b22b3f037e52d4f781\" timestamp=\"0x0fdfb467\" size=\"0x00114000\" added=\"2024-10-29T02:19:33Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.20348.51\" file=\"ntoskrnl.exe\" hash=\"83da0d11bba3983fa71c7a08eec63b27b7da9b19bf1efac75dafd96e0e854f4d\" timestamp=\"0x7d99154d\" size=\"0x01047000\" added=\"2025-03-07T05:06:12Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.51\" file=\"ntkrla57.exe\" hash=\"6f8b1b372af3f6c0725670c600947fee26a116c5a4c5c01ce0e5e6e17b70ed0f\" timestamp=\"0xdae5aacd\" size=\"0x01042000\" added=\"2025-03-07T05:06:12Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.143\" file=\"ntoskrnl.exe\" hash=\"8ef80f90a452d1446837c0e93ded2715861477abce69ee34d1d5f7ae3f1d90a5\" timestamp=\"0x932c8140\" size=\"0x01047000\" added=\"2024-11-09T04:03:18Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.143\" file=\"ntkrla57.exe\" hash=\"373227e41ea7456a77248efe1e9f616b9abec42af0fda02212b8f3851d6c39b7\" timestamp=\"0x1e2f1e7b\" size=\"0x01042000\" added=\"2024-11-09T04:03:18Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.169\" file=\"ntoskrnl.exe\" hash=\"9eb55c400d11e01a577933ec977652d9e25cba5e27c2af21c0873d45375e2d0c\" timestamp=\"0xcb668c20\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.169\" file=\"ntkrla57.exe\" hash=\"e385658dc7ad2c5146574679d09dacfbb6159f691a48afcb0340c5d2a81987ee\" timestamp=\"0x0dcc68e8\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.202\" file=\"ntoskrnl.exe\" hash=\"588170c4312974357a6cac8d23d967def9ccd8ec3b4c383c88f4da6c2edcd2cc\" timestamp=\"0x3c70e78c\" size=\"0x01047000\" added=\"2025-01-15T01:55:10Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.202\" file=\"ntkrla57.exe\" hash=\"7cf3d5c6efb8109ab6b23e6daf04797e31ac9f08b41361adcea4e2e1d2ca4040\" timestamp=\"0x89ac03bf\" size=\"0x01042000\" added=\"2025-01-15T01:55:10Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.230\" file=\"ntoskrnl.exe\" hash=\"f1704c13aa7dd88e9d02a1fe6239a808c28247cfbb248d77e8a95c247e28472f\" timestamp=\"0x4bd5c1a7\" size=\"0x01047000\" added=\"2024-11-13T15:20:35Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.230\" file=\"ntkrla57.exe\" hash=\"dbbaac73403e1fba850c31fb0bc3bcab349788fe532f53e2e0b22e88f2c9a857\" timestamp=\"0x09100ded\" size=\"0x01042000\" added=\"2024-11-13T15:20:35Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.261\" file=\"ntoskrnl.exe\" hash=\"abe2e9e1d207d07e9ec8fddfd1c5030e5345e350b574be3734cc62bcc5fd8a1c\" timestamp=\"0xe850388f\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.261\" file=\"ntkrla57.exe\" hash=\"6211b5ee1978298dc20071db029c902c8f0e220f515691ed0cdefc5b163b7a53\" timestamp=\"0x3a708ad6\" size=\"0x01042000\" added=\"2025-02-17T22:56:35Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.288\" file=\"ntoskrnl.exe\" hash=\"65f8e50720667a65c5f96ac14c394f74b897392ab0669216ed58d7e0828521fa\" timestamp=\"0x514dd82f\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.288\" file=\"ntkrla57.exe\" hash=\"0a845313b1ac7235ccfd652aafaf812bd43c923affe647469d7d9ed7dd41a509\" timestamp=\"0x7e173db1\" size=\"0x01042000\" added=\"2025-02-17T22:56:35Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.320\" file=\"ntoskrnl.exe\" hash=\"2331b8ad27ef8f6abb6295e079dd7fff6172238b7b62b8d8e308f27d5f6b6847\" timestamp=\"0x331ffbb8\" size=\"0x01047000\" added=\"2025-01-11T18:16:31Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.320\" file=\"ntkrla57.exe\" hash=\"5f4f2def887eda1a81eb8041b16612b57f7500b1f308a2f7edc499c6aae99d42\" timestamp=\"0x8e45da71\" size=\"0x01042000\" added=\"2025-01-11T18:16:31Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.350\" file=\"ntoskrnl.exe\" hash=\"52ab04e179259c26de05296b058faa2f89b7e1f9ba8a3d385b144c6300dc1a51\" timestamp=\"0xc4113d2f\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.350\" file=\"ntkrla57.exe\" hash=\"9ea150a25a92492b6a5bdd8e0975031f8c58f62b62daf85d73e2b34a74a24420\" timestamp=\"0x825f0639\" size=\"0x01042000\" added=\"2024-11-05T01:22:32Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.469\" file=\"ntoskrnl.exe\" hash=\"6f2d6d77ca7534b3b1073d5be07364079899129ed606e02cc6a86cacba5e24ad\" timestamp=\"0x81a3c9ac\" size=\"0x01047000\" added=\"2024-11-16T00:53:13Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.469\" file=\"ntkrla57.exe\" hash=\"7707252ae34fa4b1868a85aa479be3e13bc27fa129d44adfa2c24065f03c0c19\" timestamp=\"0x86749475\" size=\"0x01042000\" added=\"2024-11-16T00:53:13Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.524\" file=\"ntoskrnl.exe\" hash=\"e03a152ea59eba2d27d80dcb690996d6f6a3528026ffdc96c20fd452f873d91d\" timestamp=\"0x78163f86\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.524\" file=\"ntkrla57.exe\" hash=\"2daad73f7446e385cb938db1cbd4adba9e6eb880142367579b2d84e8c359b9f9\" timestamp=\"0x9ce0cbd6\" size=\"0x01042000\" added=\"2024-11-05T01:22:32Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.558\" file=\"ntoskrnl.exe\" hash=\"49f3089b27f0985d1ec75fd6c035cb09c981fd3cdd09e05e70a9779a0015d10d\" timestamp=\"0x207600e3\" size=\"0x01047000\" added=\"2025-01-11T02:34:03Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.20348.558\" file=\"ntkrla57.exe\" hash=\"ded6cb9b75599c48dd85722f21fe043967f8ea9dcdf5dc4af4ae5c5541ef824b\" timestamp=\"0x20d10b84\" size=\"0x01042000\" added=\"2025-01-10T06:00:00Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.20348.587\" file=\"ntoskrnl.exe\" hash=\"5669b9b8bfcf20f08b7d1d65dc2deccbf836279c0e3f66722d72ad33ee7f672a\" timestamp=\"0x034da928\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.587\" file=\"ntkrla57.exe\" hash=\"fe82ce59b76cdfff9f680cec8cc48d887614b6164125b2b6be8cd1428cece79f\" timestamp=\"0x0414a55a\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.617\" file=\"ntoskrnl.exe\" hash=\"f72142bcd38da023c7c34f53a8751ea3b7865feac9b3cb7d9005448b109045e6\" timestamp=\"0x87bbf9e5\" size=\"0x01047000\" added=\"2024-11-09T04:03:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.617\" file=\"ntkrla57.exe\" hash=\"19d38465cef305eec4fe920cc080cbd71ff44167b8f47e648ed30de8d3729c3c\" timestamp=\"0x11141a48\" size=\"0x01042000\" added=\"2024-11-09T04:03:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.643\" file=\"ntoskrnl.exe\" hash=\"cdf72cd0856638d8afa3f0f91a75c849297a2dda7241b7fa80379644ccc7e62c\" timestamp=\"0xdc0eae8a\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.643\" file=\"ntkrla57.exe\" hash=\"94aad34e03b546739b16a26b12abdb1be338ac50bcb60f9139c27541ced8c7b5\" timestamp=\"0x32df253c\" size=\"0x01042000\" added=\"2025-02-17T22:56:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.681\" file=\"ntoskrnl.exe\" hash=\"db024306abe23fb221c1d208f824b11385f788578ad805f761ef3bbffc602b81\" timestamp=\"0x0d14c9ad\" size=\"0x01047000\" added=\"2025-05-10T01:12:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.681\" file=\"ntkrla57.exe\" hash=\"0fe73e4813ec807e21346c6deededd2d94fdc62674940a588f0c67150dd0a974\" timestamp=\"0x1e2965c2\" size=\"0x01042000\" added=\"2025-05-10T01:12:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.707\" file=\"ntoskrnl.exe\" hash=\"a7ae077bd4e856d0a6919a338abc8a1e3afb09778a82d9927d95d06472778a2c\" timestamp=\"0x55826673\" size=\"0x01047000\" added=\"2025-03-11T02:45:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.707\" file=\"ntkrla57.exe\" hash=\"29658cf6602ac5249af474f0089a445eea5707977ff72e4db8fb7b6325e78555\" timestamp=\"0x665eb7ea\" size=\"0x01042000\" added=\"2025-03-11T02:45:33Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.709\" file=\"ntoskrnl.exe\" hash=\"9562c60e36d0774e3cf240fab651eb131cdb56db6a2c35b8815a5e4c6698f8ee\" timestamp=\"0xff3b43c1\" size=\"0x01047000\" added=\"2024-11-22T17:11:50Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.709\" file=\"ntkrla57.exe\" hash=\"d76c8a79e12e58bdbc8a6f816c33f08a9f41a7f03168e532bf952267e8849491\" timestamp=\"0x81a67438\" size=\"0x01042000\" added=\"2024-11-22T17:11:50Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.740\" file=\"ntoskrnl.exe\" hash=\"104ed34afbd40d7d8b9f0da27a57c1cb48c6ded3e2dbc5ccb46416f8538558c4\" timestamp=\"0xdfabb46c\" size=\"0x01047000\" added=\"2025-04-01T05:31:15Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.740\" file=\"ntkrla57.exe\" hash=\"bcffd5a579d0cb69f4b92d5e9b73a2bb56438a0998368d1cd6948ff6f7143e51\" timestamp=\"0x27f9d2df\" size=\"0x01042000\" added=\"2025-04-01T05:31:15Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.768\" file=\"ntoskrnl.exe\" hash=\"a174f3e1a1abb31480821473cc4fb27e04de91c131706d212e41b9eed17b5108\" timestamp=\"0x52317eee\" size=\"0x01047000\" added=\"2025-03-17T02:43:00Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.768\" file=\"ntkrla57.exe\" hash=\"1dd8fbba863299ae0d40652eb7f0076a440b0d0db23ccf1edc0ec27b2a06c603\" timestamp=\"0x4fb02f2d\" size=\"0x01042000\" added=\"2025-03-17T02:43:00Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.803\" file=\"ntoskrnl.exe\" hash=\"dd06a7230f3836c8a342f1c129beb1999a7d6e480f0f0c8f3ac38d1e3b6397c2\" timestamp=\"0x9598f2d2\" size=\"0x01047000\" added=\"2024-11-13T15:20:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.803\" file=\"ntkrla57.exe\" hash=\"6269aacecf328371e9b75907884b8d56209ee21d8888c8866473450c3beadcc9\" timestamp=\"0x92980569\" size=\"0x01042000\" added=\"2024-11-13T15:20:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.825\" file=\"ntoskrnl.exe\" hash=\"dea7555c9a109e8e897dbeac3c10251f7b7df5268b0585b6479c1eec00c937be\" timestamp=\"0x9a985228\" size=\"0x01047000\" added=\"2025-01-15T01:55:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.825\" file=\"ntkrla57.exe\" hash=\"ec6847bef58c45995a582a898abf43f23664d0fa41dbec3d83138e22918b998e\" timestamp=\"0xb609dcf2\" size=\"0x01042000\" added=\"2025-01-15T01:55:10Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.859\" file=\"ntoskrnl.exe\" hash=\"d9316a47df50ea5e0a218d2ae2e16ed25c063173022a23984b43028a946e2450\" timestamp=\"0x965d2276\" size=\"0x01047000\" added=\"2025-01-03T06:52:30Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.859\" file=\"ntkrla57.exe\" hash=\"358e2cfc6db845260040a88109113b1798c855ffba9d502b599ccf5e0d968f90\" timestamp=\"0xd0a7b036\" size=\"0x01042000\" added=\"2025-01-03T06:52:30Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.859\" file=\"lxcore.sys\" hash=\"312ee8b4ace72539f28b13086f2eb94ff9884d93966dd38896957a6a9d1f339d\" timestamp=\"0x4a49d447\" size=\"0x00115000\" added=\"2024-12-11T14:53:46Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.20348.887\" file=\"ntoskrnl.exe\" hash=\"b82c14f84ff595c09f11cb931f2078b8d66a1de732cd3eb15f0bb82ea36e3370\" timestamp=\"0xdc0d53dd\" size=\"0x01047000\" added=\"2024-11-13T15:20:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.887\" file=\"ntkrla57.exe\" hash=\"890a22b8919ea7b34ef871ab5dd9ae0da5c5c97c516713489f1025959af4850a\" timestamp=\"0x8ed9d363\" size=\"0x01042000\" added=\"2024-11-13T15:20:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.946\" file=\"ntoskrnl.exe\" hash=\"603448362abf685921e416c5ff5318d61327e7309b294ce7de7d6082a220202c\" timestamp=\"0xf013aba8\" size=\"0x01047000\" added=\"2024-10-16T00:54:19Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.946\" file=\"ntkrla57.exe\" hash=\"5fd6a60e9e9a3fba5c375262530834166482d815b32a190b77e96d7161a3e5f1\" timestamp=\"0x6299668e\" size=\"0x01042000\" added=\"2024-10-16T00:54:19Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1006\" file=\"ntoskrnl.exe\" hash=\"72fa8799c61b3f13e841ddff5da274281740e83d02b1c39dc151c7a3fc4bb591\" timestamp=\"0x89146aac\" size=\"0x01047000\" added=\"2024-10-26T06:39:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1006\" file=\"ntkrla57.exe\" hash=\"f0d54cc354f31700a9c5b7e8feddefa9756b602546c203348073c278311e4af4\" timestamp=\"0x2653d76d\" size=\"0x01042000\" added=\"2024-10-26T06:39:10Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1070\" file=\"ntoskrnl.exe\" hash=\"5ed19534f1c4eb86bde7c5c1e241233d7880582e27faba3f2c3626907ea03798\" timestamp=\"0xd24b5c45\" size=\"0x01047000\" added=\"2025-03-29T06:48:24Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1070\" file=\"ntkrla57.exe\" hash=\"f6e1b149fa3673a3ecdb17eff8fe02ac8d72bf418ec97acd9a759dfef6e89ca4\" timestamp=\"0x9914299f\" size=\"0x01042000\" added=\"2025-03-29T06:48:24Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1129\" file=\"ntoskrnl.exe\" hash=\"a73d2dd36ea1bbad717f56b2329006ec8c56c82682ddde4238453e58c583f3b9\" timestamp=\"0x60016b79\" size=\"0x01047000\" added=\"2024-10-19T15:36:45Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1129\" file=\"ntkrla57.exe\" hash=\"035df8010f7fa05c7eddd6d303d537c65d5f9d0c4c0ee1eb888dfd1fa5f6b9ac\" timestamp=\"0x309bde8f\" size=\"0x01042000\" added=\"2024-10-19T15:36:45Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1194\" file=\"ntoskrnl.exe\" hash=\"7c4f2bfe2d55d49c4ca1fb24b4180daf1b1db9fab88a2fefa10437bd651d4775\" timestamp=\"0x2bccc8e6\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1194\" file=\"ntkrla57.exe\" hash=\"7233124d6819d1ce36675b6fc847c9d33aac9d848a45e999435c72a858852957\" timestamp=\"0x75f53d30\" size=\"0x01042000\" added=\"2025-02-17T22:56:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1249\" file=\"ntoskrnl.exe\" hash=\"862074585d52f3d32a8d731d740904b16132a4bac44d000d6a171caf1bfed01d\" timestamp=\"0x442b24e5\" size=\"0x01047000\" added=\"2024-10-26T06:39:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1249\" file=\"ntkrla57.exe\" hash=\"96e1bfe77bc5c02f9f6f097793cfeb07aeeb0052268476af0d6e60ba15acba46\" timestamp=\"0x36129b6f\" size=\"0x01042000\" added=\"2024-10-26T06:39:10Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1251\" file=\"ntoskrnl.exe\" hash=\"ef5f9e175ffeaf0615d725d57a5939e30e9a9996f98b9ce19cdf6cd2726b6ad9\" timestamp=\"0x833a7dcd\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1251\" file=\"ntkrla57.exe\" hash=\"77a49ba62fdae51ef6dde2dfc369387e501b5c9bd4b9d0fde033eeb6f6b87e4d\" timestamp=\"0x4806203a\" size=\"0x01042000\" added=\"2025-02-17T22:56:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1311\" file=\"ntoskrnl.exe\" hash=\"162fe1c4e05b9b7ff5435f27c414f2473d7862b13ad1c54da72dd037cea21fe6\" timestamp=\"0x83ad24d1\" size=\"0x01047000\" added=\"2025-06-18T01:25:23Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1311\" file=\"ntkrla57.exe\" hash=\"e88c41a35ffd18f3606dfb6d10fa93b7a9294ea5d6726cdb07b4e939cd302690\" timestamp=\"0x7a19338f\" size=\"0x01042000\" added=\"2025-06-18T01:25:23Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1311\" file=\"lxcore.sys\" hash=\"3457de81a67976ae4297f01fca311fe0ff63ef80625ad0bcb40100da12114268\" timestamp=\"0x684b1f4e\" size=\"0x00116000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1366\" file=\"ntoskrnl.exe\" hash=\"1377a079d9c128951406f4165ad9a22347bce1cf181082e966b2677320244b4d\" timestamp=\"0x4172820a\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1366\" file=\"ntkrla57.exe\" hash=\"6e4bd7641603e8c753ae2222c9327ec398589ea336aeeeb6c914eefb7010f238\" timestamp=\"0xe488ffe6\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1368\" file=\"ntoskrnl.exe\" hash=\"7b1ca9fa988da0120d0dfbed3c54d7e8e0a1f442174ab2018d7a6587ca371506\" timestamp=\"0xc36e165a\" size=\"0x01047000\" added=\"2026-02-05T23:25:24Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1368\" file=\"ntkrla57.exe\" hash=\"201c9d60df7726b29a5edca41fc97ae59ac9e87b9a32a75c3f823f314c0168e8\" timestamp=\"0xa991f519\" size=\"0x01042000\" added=\"2026-02-05T23:25:24Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1487\" file=\"ntoskrnl.exe\" hash=\"99d95d2d0ecf6c2059ee892fc79e648d93a828e3170b25f2f3b7b639cc42aa77\" timestamp=\"0x4c0e258f\" size=\"0x01047000\" added=\"2024-10-16T00:54:19Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1487\" file=\"ntkrla57.exe\" hash=\"d1b7e00c7fd3acc3361d39fb1479ffbc8a8580dc5aacc9fef7b7143c64b78a05\" timestamp=\"0xe9c02fd5\" size=\"0x01042000\" added=\"2024-10-16T00:54:19Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1547\" file=\"ntoskrnl.exe\" hash=\"124865ffe1d970d2884fa78e5079b8c2208f70d9b99771cba9b8acb2c49b6a92\" timestamp=\"0x8e8f7f4b\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1547\" file=\"ntkrla57.exe\" hash=\"89aa10abf5a9469adc35b649bf77ae1f4662de1d18bc306d4335a56b7a84e2b3\" timestamp=\"0x8071ef8b\" size=\"0x01042000\" added=\"2024-11-05T01:22:32Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1607\" file=\"ntoskrnl.exe\" hash=\"be5c01e0fcf25a17a6fefd1d26669dd9f7904da81f58ef232e4e0ecf42a7abf1\" timestamp=\"0x72fb7d08\" size=\"0x01047000\" added=\"2024-11-19T23:19:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1607\" file=\"ntkrla57.exe\" hash=\"1567df898ba7207c82be8289e1e4fa596ffa968631725aa104ce1b62a0c6a792\" timestamp=\"0x5af40a5b\" size=\"0x01042000\" added=\"2024-11-19T23:19:13Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1668\" file=\"ntoskrnl.exe\" hash=\"f47286c93e14d6a3f796fbe96dfd2c342f7532f3dfc8909a16ef3cee2097238b\" timestamp=\"0x2cc80715\" size=\"0x01047000\" added=\"2024-10-06T07:32:47Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1668\" file=\"ntkrla57.exe\" hash=\"a2e4b3644de004492dd92dea553f2a63f4ded0e289578c4b561a7fa32c208831\" timestamp=\"0xe82bfca8\" size=\"0x01042000\" added=\"2024-10-06T07:32:47Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1726\" file=\"ntoskrnl.exe\" hash=\"8c5fefffa77c17329868f1c59e8bf8768f3b4d60d0c9fa3e7687be7ee218437c\" timestamp=\"0xe537d7c5\" size=\"0x01047000\" added=\"2024-11-21T19:38:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1726\" file=\"ntkrla57.exe\" hash=\"ea837d33a45e347c46f99386a77afb76e106a9961d3812fc03b9251bea7282ee\" timestamp=\"0xdba26d73\" size=\"0x01042000\" added=\"2024-11-21T19:38:04Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1787\" file=\"ntoskrnl.exe\" hash=\"c3fd33f4abdb09e429c64d99f2d6555c8acc3519ae7dd48f8185cc5cc057c345\" timestamp=\"0x3aaf2dd5\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1787\" file=\"ntkrla57.exe\" hash=\"b497648d57aa242e04baa72a03aaf2338ca38a707952bdbb086ad7a6029227f6\" timestamp=\"0xf5f610c9\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1850\" file=\"ntoskrnl.exe\" hash=\"6916446a5677f164fff65b1e2f91399c856da145dd46800c4f1cdf8b47bed5f5\" timestamp=\"0xea20a8e2\" size=\"0x01047000\" added=\"2024-11-13T15:20:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1850\" file=\"ntkrla57.exe\" hash=\"a0c6066cbfe419e9489e28c9e6ca1d43c6e0bd110a6345e3532119b154ffe4c0\" timestamp=\"0x709af992\" size=\"0x01042000\" added=\"2024-11-13T15:20:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1906\" file=\"ntoskrnl.exe\" hash=\"29dbadd3a4f90630d8bdd7ca6f6816ab81210328e117cfa6af8ad415c52be41a\" timestamp=\"0xb905a928\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1906\" file=\"ntkrla57.exe\" hash=\"e8ab883a9c8c43971d8113a3b9d27cfdad038ab36780e75b3fbae8e79d37c1a2\" timestamp=\"0x804e6c65\" size=\"0x01042000\" added=\"2024-11-13T15:20:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1970\" file=\"ntoskrnl.exe\" hash=\"f630c65648450fedcc4975eddda9135c80631eb8a70acd7bb7b0d32fd7d9d549\" timestamp=\"0xf71fd29f\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.1970\" file=\"ntkrla57.exe\" hash=\"22082efde6f6ac2a2b1778db36981ad741657c455b70eaf37e98e2fefdeb0f39\" timestamp=\"0x95b93e17\" size=\"0x01042000\" added=\"2024-11-05T01:22:32Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2031\" file=\"ntoskrnl.exe\" hash=\"1a70263cdfcb07c3c2604fea5a4e567ae5c721268326ca0ddb7c7294094e9d63\" timestamp=\"0x1d9f9de4\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2031\" file=\"ntkrla57.exe\" hash=\"c966d3ccfd3f074b49b5e8326ff8153d4fb4815a473252b4ad6897d5c6042ce5\" timestamp=\"0x44edf546\" size=\"0x01042000\" added=\"2024-11-05T01:22:32Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2110\" file=\"ntoskrnl.exe\" hash=\"7f74e7c98b7c8c6d53eb7a58f68af7ca00d29b906fab3103114cc9b0a2e5556d\" timestamp=\"0x9729528b\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2110\" file=\"ntkrla57.exe\" hash=\"f58cfb4dbf9cf7134c57cf89b4ff79e824406a00ad2ccf48139849822de50e28\" timestamp=\"0xde3ea2bd\" size=\"0x01042000\" added=\"2024-10-13T16:15:06Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2141\" file=\"ntoskrnl.exe\" hash=\"836de740411f037e211b21214db95f5728a4068df37ae9cefc60931213d6abb9\" timestamp=\"0x3b845e5d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2141\" file=\"ntkrla57.exe\" hash=\"97971051c09013e0fc4dbaf958d0a808e18847d1d10dbde893290f419b27d01a\" timestamp=\"0xf11eeec4\" size=\"0x01042000\" added=\"2024-10-29T02:19:33Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2141\" file=\"lxcore.sys\" hash=\"9d1be7b50484c55e4417a1f44eb32ba627f8f4172ac81e2da635c737fc22b039\" timestamp=\"0xcd8137cc\" size=\"0x00116000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2227\" file=\"ntoskrnl.exe\" hash=\"c3a4bad801ad4796c656d0e951818808e10b7232587b374887b260bcf9f221cb\" timestamp=\"0xf290800d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2227\" file=\"ntkrla57.exe\" hash=\"9a61ab8613cfce4fb24636bdeb7983311765092213cc51e94b7ccac18d145377\" timestamp=\"0x255d112b\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2322\" file=\"ntoskrnl.exe\" hash=\"6ac2f287a8275505d7bc5c2347569a021405abf5db2324eea83d6f3f00767cc8\" timestamp=\"0xc1825206\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2322\" file=\"ntkrla57.exe\" hash=\"d29eb8d5c6f52d56fdee8e0eea7e88478447c79aed39d8506c91bb186b307143\" timestamp=\"0x6cd453fa\" size=\"0x01042000\" added=\"2024-10-01T23:04:59Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2340\" file=\"ntoskrnl.exe\" hash=\"b9ab9b8d94679f58396ec2ecc9c8d7dae6406eb6c7ab942ae2d4ab096b1dc129\" timestamp=\"0x0575a82a\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2340\" file=\"ntkrla57.exe\" hash=\"afb1df25d6cd3a141f62476e319f4a852e06645777f74d7e86b534e82c40633e\" timestamp=\"0x41c452f8\" size=\"0x01042000\" added=\"2024-09-24T23:09:36Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2400\" file=\"ntoskrnl.exe\" hash=\"f55b56050512a793730cb0450af4bb9e56d32b3667e1a51c0d31f7aff43b373c\" timestamp=\"0x6855f558\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2400\" file=\"ntkrla57.exe\" hash=\"53eea02a07ed220fea4112257ac1fe1a67c6e05502b71274f8df7066dd4c138d\" timestamp=\"0xf835e658\" size=\"0x01042000\" added=\"2024-09-27T22:22:02Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2461\" file=\"ntoskrnl.exe\" hash=\"fd0c398d62c3a05457fafca9a3ed2e1e2d445617e2e9da95ec207472e1b5722d\" timestamp=\"0x3a6eb0d3\" size=\"0x01047000\" added=\"2024-09-26T00:30:31Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2461\" file=\"ntkrla57.exe\" hash=\"39eaa99f8fe0878d3bcff9d8159e385fe15a26a8899740f42c81af1c0def7697\" timestamp=\"0x60977d96\" size=\"0x01042000\" added=\"2024-09-26T00:30:31Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2520\" file=\"ntoskrnl.exe\" hash=\"011d5d42f8238855851684001e298dd941369694e1afe079ee27ca99e019e47c\" timestamp=\"0x5e236e98\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2520\" file=\"ntkrla57.exe\" hash=\"f35629fdd32f63b06616cf6a8d9f8fe91c8b435620f29c6ebf56a2a31482eee5\" timestamp=\"0xf066834b\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2520\" file=\"lxcore.sys\" hash=\"cf6ea287ceb4a085aa206a740d0ac849d90f67194e127aadda08c27f3de0ce95\" timestamp=\"0xe8768320\" size=\"0x00116000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2529\" file=\"ntoskrnl.exe\" hash=\"c7825fb29c1d5807094530df6e456aa4d94d6d09af7f072915aed6cb10f3ae30\" timestamp=\"0x3da43e42\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2529\" file=\"ntkrla57.exe\" hash=\"9cba431697889c1babe83b761deb3e7cddf2a3c844300b09bfa294c3a0f03bbe\" timestamp=\"0x245e021e\" size=\"0x01042000\" added=\"2025-02-17T22:56:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2582\" file=\"ntoskrnl.exe\" hash=\"b5152b3ccae82d983f863a5dc9b6d3ae93f82ab93326dd7a4ecb61dd70f2ecd8\" timestamp=\"0xbd4795a3\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2582\" file=\"ntkrla57.exe\" hash=\"ae75c04509b9daa7e3117d1a7d09dc557feef1f89b594a65354aa455bdef1803\" timestamp=\"0x6a58b1b8\" size=\"0x01042000\" added=\"2024-09-14T02:14:31Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2652\" file=\"ntoskrnl.exe\" hash=\"27c110251a932d30b89784fa81ce6b8945cafbb07aef14ad227b24550ba22d76\" timestamp=\"0x102245ee\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2694\" file=\"ntoskrnl.exe\" hash=\"4d3dacf5b90a75b0252ab29522fb8eb3c04f301cf48d358e3ebda5f9385f2177\" timestamp=\"0x7c252454\" size=\"0x01047000\" added=\"2024-09-12T01:41:07Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2694\" file=\"ntkrla57.exe\" hash=\"5d1de895c6394cb6ccd91833909103d16a06a68e2cc4a2debbc298023c07ecce\" timestamp=\"0xd4505681\" size=\"0x01042000\" added=\"2024-09-12T01:41:07Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2760\" file=\"ntoskrnl.exe\" hash=\"8c348719b9cf984866b5f13b608add4f2bc3a4c15243524117a885cc6134f0bf\" timestamp=\"0xc943f38c\" size=\"0x01047000\" added=\"2024-10-09T02:21:15Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2760\" file=\"ntkrla57.exe\" hash=\"0ca499b72169ee1b11c6a042540dcdffb3e503c198d0e8034110693f4b86caca\" timestamp=\"0x84b18211\" size=\"0x01042000\" added=\"2024-10-09T02:21:15Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2849\" file=\"ntoskrnl.exe\" hash=\"ec9a51f2f9766d3a471e1a71c45c0d7e5b7366c82ff831d486067aa75ef09b0b\" timestamp=\"0xb5aec946\" size=\"0x01047000\" added=\"2024-11-13T15:20:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2849\" file=\"ntkrla57.exe\" hash=\"4990c81d33ac0157d06047bd36dcd8722cb69e865c5b7d2c06eb104a8a7f042a\" timestamp=\"0xb9ed5fe8\" size=\"0x01042000\" added=\"2024-11-13T15:20:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2849\" file=\"lxcore.sys\" hash=\"370d129f0b9565bdd8515cf3cceebc5208b270e06eb3c2ee8a7477b2bd9096e7\" timestamp=\"0xa56823b8\" size=\"0x00116000\" added=\"2024-11-15T06:04:33Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2965\" file=\"ntoskrnl.exe\" hash=\"b2c6b1ca61e189f3932d6ee1d6c3f9b4afee3daedf61e6f4c6e1fb6ac5e891fd\" timestamp=\"0xc05b6d60\" size=\"0x01047000\" added=\"2024-12-11T14:53:46Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.2965\" file=\"ntkrla57.exe\" hash=\"9d2403f45603c03e6f8b96631d55ea990850944ccb098c03ebac0a5977150354\" timestamp=\"0x0bad91d5\" size=\"0x01042000\" added=\"2024-12-11T14:53:46Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3089\" file=\"ntoskrnl.exe\" hash=\"08376ce0adc0434e2e94930a69aa4358ff2b4e5887346672bc6e280653632c22\" timestamp=\"0x44c8b13a\" size=\"0x01047000\" added=\"2025-01-15T01:55:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3089\" file=\"ntkrla57.exe\" hash=\"257724a504e946c6cc606364efe855ad13f96234512181bf7493bb082633b1d5\" timestamp=\"0x6396789e\" size=\"0x01042000\" added=\"2025-01-15T01:55:10Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3095\" file=\"ntoskrnl.exe\" hash=\"1b92b0fec3c488fae49042de21e3079fced6875df6c52c7de9aad19438be2cf4\" timestamp=\"0x66b0382e\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3095\" file=\"ntkrla57.exe\" hash=\"ab7cdf271cf17a46ead2564417163dfca21ffd292fce197934bfab122662b96c\" timestamp=\"0x58c34086\" size=\"0x01042000\" added=\"2025-02-17T22:56:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3207\" file=\"ntoskrnl.exe\" hash=\"e55b6a81c10b9bb2e613175479c649ad543bc9befd721e5258deb2e1d8a17345\" timestamp=\"0xb47b7e84\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3207\" file=\"ntkrla57.exe\" hash=\"20f1643362631ae40fd3780bd36d0f0ea19e20b2f67fc042533a94aea15afff3\" timestamp=\"0xdd468796\" size=\"0x01042000\" added=\"2025-02-17T22:56:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3328\" file=\"ntoskrnl.exe\" hash=\"8ef16f0b95e44f56dde59dc935d38c0bc2572312a9f27d607112933a733b79cf\" timestamp=\"0x4dd85ef5\" size=\"0x01047000\" added=\"2025-03-14T04:05:46Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3328\" file=\"ntkrla57.exe\" hash=\"125ea903df63ca79db3b874ba47ba11a6c0d293b125ae9f480e6019be06a4469\" timestamp=\"0x7feefcd3\" size=\"0x01042000\" added=\"2025-03-14T04:05:46Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3451\" file=\"ntoskrnl.exe\" hash=\"042869ae33e6b7522c6931763b54221769ae95c1d68725cfbad0c7b8914f7aaf\" timestamp=\"0xe367eccc\" size=\"0x01047000\" added=\"2025-04-09T14:22:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3451\" file=\"ntkrla57.exe\" hash=\"7e17dcf3dee2bba4b1378c2192c10e570dd23d4794396ef0ab9b8218e1d54755\" timestamp=\"0x2b012a10\" size=\"0x01042000\" added=\"2025-04-09T14:22:28Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3561\" file=\"ntoskrnl.exe\" hash=\"e3fef2679635043874ad51db0cc2960c24b499ed4780d2418d1c047513e08a97\" timestamp=\"0x5ce3577f\" size=\"0x01047000\" added=\"2025-04-25T01:12:29Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3561\" file=\"ntkrla57.exe\" hash=\"e9cc6c1b66e853369977d4f8ffad48f6c082e11aff3758eae9c041ccb2956cab\" timestamp=\"0xb537caa1\" size=\"0x01042000\" added=\"2025-04-25T01:12:29Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3566\" file=\"ntoskrnl.exe\" hash=\"01b18c2e28fa47ddc8d295c1ac19e2b8e842aa7daa62a84f9ece6063e01e559e\" timestamp=\"0x20f81afd\" size=\"0x01047000\" added=\"2025-06-28T02:27:55Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3566\" file=\"ntkrla57.exe\" hash=\"f0596734dedbdc4478fe1a9e686ad486374397ffa3f408ffa44992ef79632e98\" timestamp=\"0xbec3527e\" size=\"0x01042000\" added=\"2025-06-28T02:27:55Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3692\" file=\"ntoskrnl.exe\" hash=\"382a309fee8c1517a74917c43f6559d52128a0b9b4dbb388d6a8825364783ddf\" timestamp=\"0x5091885d\" size=\"0x01047000\" added=\"2025-05-13T22:56:23Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3692\" file=\"ntkrla57.exe\" hash=\"60442ec11630af823d13520438446732a676a59f775ef649236be6bf267b7506\" timestamp=\"0x53844b33\" size=\"0x01042000\" added=\"2025-05-13T22:56:23Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3804\" file=\"ntoskrnl.exe\" hash=\"b3548c419299ac33cb87e5544af6e09f8222584ebb1f314df3ee1a53e63dbfc9\" timestamp=\"0xec720482\" size=\"0x01047000\" added=\"2025-06-13T19:27:57Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3804\" file=\"ntkrla57.exe\" hash=\"0b6c2e33e6628d636f94ce07faad11e834d33773f3f314d1491ed9aa865f286d\" timestamp=\"0x97bdeb21\" size=\"0x01042000\" added=\"2025-06-13T19:27:57Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3932\" file=\"ntoskrnl.exe\" hash=\"ecae9cc0d5fe56cfda3ae3e669e6787ec319234dcfaa70a2efa4a143f9115a1d\" timestamp=\"0xd229df57\" size=\"0x01047000\" added=\"2025-07-08T22:13:00Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3932\" file=\"ntkrla57.exe\" hash=\"56a66df68b008c2954a2b36c70c5210d6ca4f3e19582d453e8cada109ff9c089\" timestamp=\"0x65ea93bf\" size=\"0x01042000\" added=\"2025-07-08T22:13:00Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3933\" file=\"ntoskrnl.exe\" hash=\"0a73fa833e6d8c4cdad5b31e5253704b1415fc4ae1d6ea55e3460df430f06fd7\" timestamp=\"0x6b2e89d1\" size=\"0x01047000\" added=\"2025-07-10T01:24:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.3933\" file=\"ntkrla57.exe\" hash=\"342c497e5b5edf68093accd375149811c14ce18610a253483f81eacb34387c04\" timestamp=\"0xbef48e1d\" size=\"0x01042000\" added=\"2025-07-10T01:24:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4050\" file=\"ntoskrnl.exe\" hash=\"92faa7c89eec099c089f14740af21d9cd6bff13508e7fee154bd6c4da91e0928\" timestamp=\"0xe48aaa46\" size=\"0x01047000\" added=\"2025-08-13T21:37:12Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4050\" file=\"ntkrla57.exe\" hash=\"b965515800e60c97563ec0d16b614b0ca0af15bba46414b51b43603847c36523\" timestamp=\"0x5d756d52\" size=\"0x01042000\" added=\"2025-08-13T21:37:12Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4163\" file=\"ntoskrnl.exe\" hash=\"abf069b16ac7b0a363dc51f0a2b02738c084971040c67b5ebf0ae267b402b28f\" timestamp=\"0xf05e617a\" size=\"0x01047000\" added=\"2025-09-11T03:22:38Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4163\" file=\"ntkrla57.exe\" hash=\"60e15a0181159839628694568b54648cb1fd57b5e291218947ee855dda2a980e\" timestamp=\"0xbdbf3851\" size=\"0x01042000\" added=\"2025-09-11T03:22:38Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4294\" file=\"ntoskrnl.exe\" hash=\"4f841ec31ad0767379a4295a72feeb5f61bbca9a98bfd14b11b8ad91d10ecd88\" timestamp=\"0xa462fd4c\" size=\"0x01047000\" added=\"2025-10-15T03:12:43Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4294\" file=\"ntkrla57.exe\" hash=\"03774393479891a129774988198fa6f0fcf2f23015506aa3212116a4e9d4596a\" timestamp=\"0xed125f4f\" size=\"0x01042000\" added=\"2025-10-15T03:12:43Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4297\" file=\"ntoskrnl.exe\" hash=\"3435642b1bce562db09aba4b2e2c7356e8d4ad7f65aea9b9b83ec6bbb213d01d\" timestamp=\"0x785e851c\" size=\"0x01047000\" added=\"2025-10-29T20:10:48Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4297\" file=\"ntkrla57.exe\" hash=\"841c417c7923c23336813095eae2a023980b8e34f64e0e71cb9680dcc7e86008\" timestamp=\"0x0e3a5eee\" size=\"0x01042000\" added=\"2025-10-29T20:10:48Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4405\" file=\"ntoskrnl.exe\" hash=\"a685f5a5e90744f50ae2627a9188e5a68b718443841d5c6ec0a42655e27dda44\" timestamp=\"0xb1c07771\" size=\"0x01047000\" added=\"2025-11-12T23:55:08Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4405\" file=\"ntkrla57.exe\" hash=\"435bcb00d210977ff3d815acb895bca1e6f30e757a39e919d78e670fcecf6f5c\" timestamp=\"0xe03e8718\" size=\"0x01042000\" added=\"2025-11-12T23:55:08Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4529\" file=\"ntoskrnl.exe\" hash=\"c4738c314231f2b02b7859e5a7740d81d636a0875a708d1a596db7c4730668d1\" timestamp=\"0x73368ffb\" size=\"0x01047000\" added=\"2025-12-10T04:39:55Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4529\" file=\"ntkrla57.exe\" hash=\"065e08262009b38d51dc5e6d07bf279e5016e56be0e17583e70f4ff8b30c7fe4\" timestamp=\"0x4aeb6470\" size=\"0x01042000\" added=\"2025-12-10T04:39:55Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4647\" file=\"ntoskrnl.exe\" hash=\"f4634487338b78351cb8708e36d6d7186f83d3267ac7f082d05eaaeb1b190434\" timestamp=\"0x958987e1\" size=\"0x01047000\" added=\"2026-01-15T04:51:11Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4647\" file=\"ntkrla57.exe\" hash=\"c35f1dd466f07d2da5642877d18f4c70baa45882ad8f2f46136835e1dcd2e950\" timestamp=\"0xc49f4d60\" size=\"0x01042000\" added=\"2026-01-15T04:51:11Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4650\" file=\"ntoskrnl.exe\" hash=\"1bf74883fc5f3f9ff0ffdcb3a8110b7053e4adb0235c8bbffbae3114601895e6\" timestamp=\"0x3d4ce38a\" size=\"0x01047000\" added=\"2026-02-05T23:25:24Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4650\" file=\"ntkrla57.exe\" hash=\"9281c38106fcb1f317c19fc8327e4ccd00667e5a43596ce4f763c1f6054dc82f\" timestamp=\"0xa787cecc\" size=\"0x01042000\" added=\"2026-02-05T23:25:24Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4767\" file=\"ntoskrnl.exe\" hash=\"cda9634e1bb8ae192d59745f329702425d21a14195e3610065aca30dd3421ed0\" timestamp=\"0x3d8aee59\" size=\"0x01047000\" added=\"2026-02-11T00:54:58Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4767\" file=\"ntkrla57.exe\" hash=\"cece75da6dd4c7ca5210f97479dc3b54f48dcd5eddf7fb4d417107972436fea1\" timestamp=\"0x3f8b71c5\" size=\"0x01042000\" added=\"2026-02-11T00:54:58Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4893\" file=\"ntoskrnl.exe\" hash=\"fbdb6779ce30507e8f4cdb738017ced30495ecb93d145ccfc476eb5eb39b42f4\" timestamp=\"0xe34b5266\" size=\"0x01047000\" added=\"2026-03-11T23:28:21Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.20348.4893\" file=\"ntkrla57.exe\" hash=\"96d939e7dac34e43cebe190e5338c14b5f4858929bc03465c72461466b56eeb5\" timestamp=\"0xdfe6445d\" size=\"0x01042000\" added=\"2026-03-11T23:28:21Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.21277.1000\" file=\"ntoskrnl.exe\" hash=\"cef8837548e51ef742ead17fbe4c9605284f7ba280b2337cd8d922d2ba6378f4\" timestamp=\"0x0924af8a\" size=\"0x01047000\" added=\"2025-05-30T19:55:37Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21277.1000\" file=\"ntkrla57.exe\" hash=\"bdceddad8f16db5498db1ee28a91d1aae3b1aac4929f537cd0888fda8a6d83a2\" timestamp=\"0x8d0caa46\" size=\"0x01042000\" added=\"2025-05-30T19:55:37Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21286.1000\" file=\"ntoskrnl.exe\" hash=\"741e4c65c2b196b1d720ac5e894bdd37af10299fddf0adf5d27b334249270e55\" timestamp=\"0xa25c0cb9\" size=\"0x01047000\" added=\"2025-03-29T06:48:24Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21286.1000\" file=\"ntkrla57.exe\" hash=\"34b6c8194924d51526618779be3b79960d077c606ddc6aa71f920121f1b83e3c\" timestamp=\"0xa4f72c17\" size=\"0x01042000\" added=\"2025-03-29T06:48:24Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21322.1000\" file=\"ntoskrnl.exe\" hash=\"9df9efb349d930bae56696b916b68eaac7dab8d0b713b8d0645915b94d31af01\" timestamp=\"0xf92a5b46\" size=\"0x01047000\" added=\"2026-01-15T04:51:11Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21322.1000\" file=\"ntkrla57.exe\" hash=\"8e3a8acc45547c01e4f2efddf142e75597a10f8a26765f25b61f62377d6c74f9\" timestamp=\"0xf61abb25\" size=\"0x01042000\" added=\"2026-01-15T04:51:11Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21327.1010\" file=\"ntoskrnl.exe\" hash=\"f7e1dc9775c708b4bdb5ef04a198df946394415e7ae57e9678df46d0bf0d2df6\" timestamp=\"0xe4a057bd\" size=\"0x01047000\" added=\"2024-11-09T04:03:18Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21343.1000\" file=\"ntoskrnl.exe\" hash=\"8a6ee2e3a15e75e2cd2baa0fa71d3f8a018f3e6b7b8e18e5144778f8c1deaaaa\" timestamp=\"0xcb564649\" size=\"0x01047000\" added=\"2025-01-10T06:00:00Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21343.1000\" file=\"ntkrla57.exe\" hash=\"a6e74de7cfc1faf3b8ef4cb8e1c5373464cb978a54f980ee752e3e7f9d53f624\" timestamp=\"0x17634d6d\" size=\"0x01042000\" added=\"2025-01-10T06:00:00Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21354.1\" file=\"ntoskrnl.exe\" hash=\"5b7687f790efd1cf9b8b6f5ac3ba59a5099496c5ba53a44802a54de77a027a63\" timestamp=\"0x3ef533c6\" size=\"0x01047000\" added=\"2025-07-17T01:08:50Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21354.1\" file=\"ntkrla57.exe\" hash=\"7ba2f5f7e0e30c4617c5fa03ad3ba1847bfd9b6246a3bea695df13245f25f8d0\" timestamp=\"0x6f99d902\" size=\"0x01042000\" added=\"2025-07-17T01:08:50Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21364.1\" file=\"ntoskrnl.exe\" hash=\"8e1c385369b689b32a3e267e9950e871de8dd8eadbabba41e56d8ca47add487c\" timestamp=\"0x23099d64\" size=\"0x01047000\" added=\"2025-01-10T06:00:00Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21364.1\" file=\"ntkrla57.exe\" hash=\"5a1f571ba3c61b1bc4bb1c5c686a3228c6455c56df6771cd9472f75dab6fadc3\" timestamp=\"0x8813e10c\" size=\"0x01042000\" added=\"2025-01-10T06:00:00Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21376.1\" file=\"ntoskrnl.exe\" hash=\"288dd30103d9d1308bcfdb3267106d65b0155a6b75cefe0f192ccbd2e6981eb8\" timestamp=\"0x3db27306\" size=\"0x01048000\" added=\"2026-01-15T04:51:11Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21376.1\" file=\"ntkrla57.exe\" hash=\"13db93768dbe98d783cd770de272b9cef69b2720fbd32cd9f5a3ea1f59591677\" timestamp=\"0xf623f818\" size=\"0x01042000\" added=\"2026-01-15T04:51:11Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21387.1\" file=\"ntoskrnl.exe\" hash=\"c133b29eb883fde9926b189f86f6ba088fe4e7b1930f236810df8ea78846fd4d\" timestamp=\"0x2d328ccb\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21387.1\" file=\"ntkrla57.exe\" hash=\"b0292aceceb33056723c462a27e6075d3f264670501b4e58ed57fbb56cd16886\" timestamp=\"0xdd601541\" size=\"0x01042000\" added=\"2025-03-19T05:55:37Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21390.1\" file=\"ntoskrnl.exe\" hash=\"1fac9f86ae789f122f36de4752c8275355398112e4c7a60abf4f8de63cb55add\" timestamp=\"0x2ea3a2ab\" size=\"0x01048000\" added=\"2025-05-10T01:12:18Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21390.1\" file=\"ntkrla57.exe\" hash=\"02ddba55532b76be585ae37312f35a339b9b631f0baba4d10b608dbb62cba7b9\" timestamp=\"0xfc6cfbd2\" size=\"0x01042000\" added=\"2025-05-10T01:12:18Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21390.1010\" file=\"ntoskrnl.exe\" hash=\"3dedaf634bb214f003a340b6df82954d903c90e9680880c4bf80c215bb15de2e\" timestamp=\"0xfc92062f\" size=\"0x01048000\" added=\"2025-06-20T04:21:21Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21390.1010\" file=\"ntkrla57.exe\" hash=\"b9de680ea94e20c4347ddca58e0acc5950279ec67c62a4b2fb52474e0bd802da\" timestamp=\"0x94c6a938\" size=\"0x01042000\" added=\"2025-06-20T04:21:21Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21390.2025\" file=\"ntoskrnl.exe\" hash=\"43189e17b3e4a43f391decc6792560cc65b3f52897e1f2f96c612ddd3cdd792d\" timestamp=\"0x0395b828\" size=\"0x01048000\" added=\"2024-11-05T01:22:32Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.21390.2025\" file=\"ntkrla57.exe\" hash=\"7cd6a5e2a2be3d79aaf24bcbb8a047b220d5d5c6668102baf4e8c70e4dfb7433\" timestamp=\"0x200d92dc\" size=\"0x01042000\" added=\"2024-11-05T01:22:32Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.21996.1\" file=\"lxcore.sys\" hash=\"362f8699cdff1cf51ed864d91e30aac73a4c16715fae69ddeac6761086d5e265\" timestamp=\"0xa339bb51\" size=\"0x00111000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1\" file=\"ntoskrnl.exe\" hash=\"a9b5c0a47f1c4606a94adb3674017cbd35448c3792c4d26f51847a3ffa8c7b7c\" timestamp=\"0x19af928c\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1\" file=\"ntkrla57.exe\" hash=\"471bb2021cf14a8648a371eba17bcf6064e0850c40b8be91e58e17b832282413\" timestamp=\"0x2c71645f\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1\" file=\"lxcore.sys\" hash=\"84dc60c511ae20711a32444ffa379e4ec6f962da74ff0a2b18e324a95728c20f\" timestamp=\"0x6358d935\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22000.9\" file=\"ntoskrnl.exe\" hash=\"abb89f1b41fb48c0ea5088e3882069e14ce20328e68b8bfd6c2f4433be9ebaeb\" timestamp=\"0x7c628714\" size=\"0x01048000\" added=\"2025-02-17T22:56:35Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.9\" file=\"ntkrla57.exe\" hash=\"b60850c6e50bff38f0f1b35e7031dce63f3e7c04583e058a868e77509740aaed\" timestamp=\"0x72b6ec09\" size=\"0x01042000\" added=\"2025-02-17T22:56:35Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.51\" file=\"ntoskrnl.exe\" hash=\"2c85e2e1aabf0d57cf0038a5ef561a910df4b3e859c6617b8cac3a3d532080cf\" timestamp=\"0x12c62658\" size=\"0x01048000\" added=\"2024-10-30T23:26:34Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.51\" file=\"ntkrla57.exe\" hash=\"fce749c1255ffe6700df11f546a23cad8796087bade104ccf8c42bc005b1115c\" timestamp=\"0x3919b02b\" size=\"0x01042000\" added=\"2024-10-30T23:26:34Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.65\" file=\"ntoskrnl.exe\" hash=\"b541693b8d87675da36baf00a34e8900b447c622607d8d029a0baacdf6e66f9c\" timestamp=\"0xdc97b905\" size=\"0x01048000\" added=\"2024-11-24T17:20:19Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.65\" file=\"ntkrla57.exe\" hash=\"bd813cf865aa39e61c8ab16fd2ca4e096f803a4a5ad275b0412a4724e3ae9a4f\" timestamp=\"0xa6d49488\" size=\"0x01042000\" added=\"2024-11-24T17:20:19Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.71\" file=\"ntoskrnl.exe\" hash=\"9a468c78fb03bf56cf0e8328e91d6125f04d28bcd675f8614ac62f834948f882\" timestamp=\"0x01a40be7\" size=\"0x01048000\" added=\"2025-05-29T05:57:37Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.71\" file=\"ntkrla57.exe\" hash=\"996fa4038a81c79756f49fff5c07f58621105a912963ea3d5d6991f858870349\" timestamp=\"0xcb7fdb90\" size=\"0x01042000\" added=\"2025-05-29T05:57:37Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.100\" file=\"ntoskrnl.exe\" hash=\"a06a757922aee14a2b34768c3f1ef213a6ac5d9cc3847be6a54a614fea8172cb\" timestamp=\"0x249f365b\" size=\"0x01048000\" added=\"2025-01-15T01:55:10Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.100\" file=\"ntkrla57.exe\" hash=\"ed6bf12fa7599c5e9dd40d62cb97264f8a91d6ef9026e4712c4b099822ff5cee\" timestamp=\"0x3225ff3d\" size=\"0x01042000\" added=\"2025-01-15T01:55:10Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.120\" file=\"ntoskrnl.exe\" hash=\"7c2e8896423c5a5459fd5d039dcd53a0befef09ae4c44e286bb00e7670ddd965\" timestamp=\"0x882ab711\" size=\"0x01048000\" added=\"2025-06-19T01:46:28Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.120\" file=\"ntkrla57.exe\" hash=\"51c9386447d726cdd14ec7e706c569c970d7647bb1921cb325cb7f8bd6c9edc4\" timestamp=\"0x3c4d608b\" size=\"0x01042000\" added=\"2025-06-19T01:46:28Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.132\" file=\"ntoskrnl.exe\" hash=\"540c9b9aeacc9e45495f49774f67c0fd989c44a232431841ce1831cd1f155127\" timestamp=\"0xb30fa988\" size=\"0x01048000\" added=\"2024-12-27T01:34:36Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.132\" file=\"ntkrla57.exe\" hash=\"acb8ecef6f511403159c7f767411b6727e986514bcae23ddf62a9e8f1077e73b\" timestamp=\"0xf3abf41d\" size=\"0x01042000\" added=\"2024-12-27T01:34:36Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.160\" file=\"ntoskrnl.exe\" hash=\"ae587df10d70de8494a18bd355d2ff52fc578cd98f06efdbb662aa27efb38f79\" timestamp=\"0x38bbd3fd\" size=\"0x01048000\" added=\"2025-01-15T01:55:10Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.160\" file=\"ntkrla57.exe\" hash=\"f9dd90bc5a26ad082e4f391aa88da089e91824eba125cdf7fc0055d544e2ac49\" timestamp=\"0x887d46e7\" size=\"0x01042000\" added=\"2025-01-15T01:55:10Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.184\" file=\"ntoskrnl.exe\" hash=\"6792b8471190967a2f91aa17d3ad7cd6f9a9ea93244340e0ee724f3659a04cce\" timestamp=\"0xed636c20\" size=\"0x01048000\" added=\"2024-11-16T21:02:32Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.184\" file=\"ntkrla57.exe\" hash=\"05e5676df0f74128c6423c4f2b021530f20a15994fc2ca921471cdaf87a84c7f\" timestamp=\"0xe568ef89\" size=\"0x01042000\" added=\"2024-11-16T21:02:32Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.194\" file=\"ntoskrnl.exe\" hash=\"66b99e6127876245e25e004ab66928934f0f18d3a2011f5f359686a60d1ca924\" timestamp=\"0xb36c9db9\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.194\" file=\"ntkrla57.exe\" hash=\"384c897bbce70a6e37e69a8132d968c8b9b07fe82ef1d72f71b51ecd3371631c\" timestamp=\"0x8a01a624\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.258\" file=\"ntoskrnl.exe\" hash=\"e294e7a9a3c97a6baf468b91db9c974a1f16c7cbcd63ef8d9e65c9ed5f0c673f\" timestamp=\"0xd17cb7a0\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.258\" file=\"ntkrla57.exe\" hash=\"e659624c838324a134d582e8101a77c1ba5dc0182eacc1d6cbda5b7d71cb2d6d\" timestamp=\"0x53ba1a1c\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.282\" file=\"ntoskrnl.exe\" hash=\"77761ae0821caa94c42d5a4cf9d18126a729ef1acc6c1fd7a137e89b076d9f65\" timestamp=\"0x7f7a98cf\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.282\" file=\"ntkrla57.exe\" hash=\"32470b947e873b575abd419b79e8f43d579552ddc0387a05516cf6978b786709\" timestamp=\"0x29eae6cd\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.318\" file=\"ntoskrnl.exe\" hash=\"e1aa98d073b336d65cb1d8749700231e354b016beda3708593c6a256dce2387e\" timestamp=\"0xc16011b9\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.318\" file=\"ntkrla57.exe\" hash=\"09bffdfda6f67a10db1efeffe34302df0eec89f24d782099d15e7b2c4c7db505\" timestamp=\"0x6c9b8b6b\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.348\" file=\"ntoskrnl.exe\" hash=\"35d6497adc41f631ce34fd237900bfde69de0c92ebf8e727a27b934d4ee4c730\" timestamp=\"0xa7ccd270\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.348\" file=\"ntkrla57.exe\" hash=\"b498b4459f22afaa1eaf9c4c88fd415e5a4afcb0cb26afcdf341ce892329afcc\" timestamp=\"0x98927ccf\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.376\" file=\"ntoskrnl.exe\" hash=\"bf5eb744965fccf144fd1d6bd5de24e0230a6d439d135df85d4abdd944221a15\" timestamp=\"0x1880a2d7\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.376\" file=\"ntkrla57.exe\" hash=\"599249d0a967f534be9c3f1e932328ab7a6c12356b29a80e9be284abdcf3673d\" timestamp=\"0xc3b9d87c\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.434\" file=\"ntoskrnl.exe\" hash=\"6999347714248d872f0dda54a31454626a9f2149f165407b7445c0293ce68411\" timestamp=\"0xbf130f53\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.434\" file=\"ntkrla57.exe\" hash=\"8a7cf227e376cbac37c8e81073d2ab84d91c45a4c7267a66c6beac3b6ca0f25a\" timestamp=\"0xfccf775e\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.438\" file=\"ntoskrnl.exe\" hash=\"ba45169d655b60ba5df068dc76bf9f9753dd1d950a0326ba11ae9bcd61137df4\" timestamp=\"0x8226a166\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.438\" file=\"ntkrla57.exe\" hash=\"6fa598b6aa63bdc261e5ae4c4a4ce62c72d520e211dcc174edd7d7f566cc2287\" timestamp=\"0x057a3c0f\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.466\" file=\"ntoskrnl.exe\" hash=\"b4bb5b5437dd71c9564c719537bc42768fd7c7b335c8a53585f88f31240e2e7d\" timestamp=\"0x3cc88fce\" size=\"0x01047000\" added=\"2025-03-05T02:47:21Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.466\" file=\"ntkrla57.exe\" hash=\"c75e4571b2f314f9e356b73e366c793bacd9b314bb81f1e5289ea830fee75075\" timestamp=\"0x91a4cc4a\" size=\"0x01042000\" added=\"2025-03-05T02:47:21Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.469\" file=\"ntoskrnl.exe\" hash=\"10fa51f72f7ae6a23e79eba30dc126007b2fcb06e963fa0bf1e988664cdb6c54\" timestamp=\"0xddc66c3f\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.469\" file=\"ntkrla57.exe\" hash=\"e7b4c51aee343935f33166456cc8f768471bde1e94dc13b6bbb583a4a118be28\" timestamp=\"0xd1c39dce\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.493\" file=\"ntoskrnl.exe\" hash=\"630fc0bab7d7a2adaff35879d72057fc8678fc1673e4b380bb602d11c11e2430\" timestamp=\"0xe09cd02f\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.493\" file=\"ntkrla57.exe\" hash=\"c488fca86ab0e3fa9d0a4de510fc84b6e99ed8ab6e551b86c0d3676ed35c4f9b\" timestamp=\"0xc62ea497\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.526\" file=\"ntoskrnl.exe\" hash=\"54be35fd8a5719748b5457ecad60f4e99643affa3e2e21182c8fdd021f8de5bd\" timestamp=\"0x8e8d8b3a\" size=\"0x01047000\" added=\"2024-11-13T15:20:35Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.526\" file=\"ntkrla57.exe\" hash=\"1ade4e6dab893a1eade3c87857a0acb987975cac60edc8a73cdd141acd97dbf0\" timestamp=\"0x2b60d83a\" size=\"0x01042000\" added=\"2024-11-13T15:20:35Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.527\" file=\"ntoskrnl.exe\" hash=\"21e850f88c93ee105263d59ac082f0f32f99a02af11a81f6fbd2759001639d46\" timestamp=\"0x0518a453\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22000.527\" file=\"ntkrla57.exe\" hash=\"9c32c99001bdc945db018701ba8cc658376170bb075b59872dd283e7c97f815f\" timestamp=\"0x76596027\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22000.556\" file=\"ntoskrnl.exe\" hash=\"b8b5725dfc472528f9c003328d2320da03ad7f0eb409d53a8bcec1ceca969aa8\" timestamp=\"0x50c56fa5\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.556\" file=\"ntkrla57.exe\" hash=\"d3759f2c9e968696624792595660c6ea00777ac7efeebf2b657b3d56a264dd60\" timestamp=\"0xa8f28ef7\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.588\" file=\"ntoskrnl.exe\" hash=\"0bb47dbcf406584401a95e668e48fa40a1245fd96d70e0711cf1e78d28bb875e\" timestamp=\"0x9a7f0580\" size=\"0x01047000\" added=\"2025-06-10T13:19:34Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.588\" file=\"ntkrla57.exe\" hash=\"dc44960426986887aba6d71ac9edd82a7d1250b3a6509cb07b0697cee588e428\" timestamp=\"0x0008f24e\" size=\"0x01042000\" added=\"2025-06-10T13:19:34Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.593\" file=\"ntoskrnl.exe\" hash=\"4817467a924915967039dcfcad9637ca545fa5480aa785d3211cbf55bae020f9\" timestamp=\"0xc9b09966\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.593\" file=\"ntkrla57.exe\" hash=\"a154a019b34af2caa63a34787f016a31605fd4efaa5195e15c6202f76abfdb56\" timestamp=\"0xbcd417dc\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.613\" file=\"ntoskrnl.exe\" hash=\"abd61195df8b9d7a80881d54f0a1e8bfa0ef29acf1cdb5a293dd13ea3be25bb5\" timestamp=\"0x080ec80a\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.613\" file=\"ntkrla57.exe\" hash=\"cc88ee11bbd2c56843f36911183958ff45aa0193c8593afe28baffa57256f2bd\" timestamp=\"0xc4506d78\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.651\" file=\"lxcore.sys\" hash=\"dc8912413c19628c6c6ff06e4609fa2f8c0a5344c8a945d25de23ae902067d7f\" timestamp=\"0xd534d2e3\" size=\"0x00111000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22000.652\" file=\"ntoskrnl.exe\" hash=\"3af36dd653f5152980f23979f4127f36aa400298d404eb675f1e59c75f62bf84\" timestamp=\"0xfee04ead\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.652\" file=\"ntkrla57.exe\" hash=\"462a8d885a51b6bf015b4455fc20c752217722df2005023ab12dbebc1694cccc\" timestamp=\"0x4c580fdf\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.652\" file=\"lxcore.sys\" hash=\"20476f1a74c55e5037c557a5ef8f0a5936b5a35b38cd6943ce4abf505db8e4e3\" timestamp=\"0x79b19fee\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22000.653\" file=\"lxcore.sys\" hash=\"7c53c8154a1cff5dd44de11f0767307a7e3f8bd715af198442dbb2e8069a3d28\" timestamp=\"0x7e80861c\" size=\"0x00111000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22000.675\" file=\"ntoskrnl.exe\" hash=\"efdb03fea529d366c31065d7ac8a1a1f41f91de4ab7fe966788016e6c2dd5b9c\" timestamp=\"0x6f970119\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.675\" file=\"ntkrla57.exe\" hash=\"b19d60cdaf72a6c2e2865f2ba2437f8b3473be4aedab3635af39ade920f637b2\" timestamp=\"0x531245d3\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.739\" file=\"ntoskrnl.exe\" hash=\"02b7dcd938a84dfa6163974650e17fe12752ec665f46b046cba7ac2c3d80b19d\" timestamp=\"0xef0daa6a\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.739\" file=\"ntkrla57.exe\" hash=\"168b75944e5b7add18d022171a10f99b159b8ba4caf4761e34312c44552657ca\" timestamp=\"0x7871f0e5\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.778\" file=\"ntoskrnl.exe\" hash=\"26e2b69967bd85acf37360d6a307e8c3107c032a00df79cd54476df9454ff008\" timestamp=\"0xecf9d44d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.778\" file=\"ntkrla57.exe\" hash=\"215d3c2ddb839282b0b328866554bd1f33ef2bd070f117df83a356f8cb965ae1\" timestamp=\"0x9104d77c\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.795\" file=\"ntoskrnl.exe\" hash=\"e67084679de1a56ed5cc7eb04fa0a4897cda6c35899890c9a2ded071fcccd428\" timestamp=\"0x1a959742\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.795\" file=\"ntkrla57.exe\" hash=\"66117af313c4c338ac11ed8623d72ff884b51161b96c986fc9c7a3bfa8cdf849\" timestamp=\"0xbb9ec3f1\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.832\" file=\"ntoskrnl.exe\" hash=\"c36f61a0c5e27dabadd424e5420b68a0a32284ceba305d740e7714bf0441b096\" timestamp=\"0x06e1b8ee\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.832\" file=\"ntkrla57.exe\" hash=\"a2b8c65e01184047b081dbdd25c6b7bfb447981ec83e04d92df2d25ec1571952\" timestamp=\"0xb1b12e34\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.856\" file=\"ntoskrnl.exe\" hash=\"cd9c68338e86f1f6fdfa166ea9e8f5b3f37372dcd62bf0a4ddd46377dddbf31b\" timestamp=\"0x60480491\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.856\" file=\"ntkrla57.exe\" hash=\"1853f17d499a861d332b00169ece23f2b6b790d8afc35dfaca7a386b07d5073a\" timestamp=\"0xb78866ff\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.918\" file=\"ntoskrnl.exe\" hash=\"1176773ef3c51974e8a73cf0cb6062fd8ec1e02e8a345b5da61c89933370e89c\" timestamp=\"0x8c9dbe80\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.918\" file=\"ntkrla57.exe\" hash=\"c4269c81c3efcdf10fb53ae5b5279d5ffac479484e6ba14494400853c63da39b\" timestamp=\"0xaf4c68e9\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.978\" file=\"ntoskrnl.exe\" hash=\"a5f7ffeb3cb0ef428ef0e49368763d864b60035b24088e13ad16d8c12e0d87b7\" timestamp=\"0x8e35b213\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.978\" file=\"ntkrla57.exe\" hash=\"3fedb426fddd7fd31f326e7c5fe5a65e3c1a4339439abf400a32070296298bb8\" timestamp=\"0x218b3b9a\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1042\" file=\"ntoskrnl.exe\" hash=\"c39f7344f953f74eec3368d2c8fefdadf740c3c8f9bbd634b5c6f922380f9a9d\" timestamp=\"0xb745976f\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1042\" file=\"ntkrla57.exe\" hash=\"89b198ace6ceab27de2cb868cc5940404deff8702568cf59204dbfa471ff5a99\" timestamp=\"0x597af285\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1098\" file=\"ntoskrnl.exe\" hash=\"e132c6085be791c5ab306029e17dd5f19eb8b7b1714a993bdf72580bb0daea61\" timestamp=\"0x8530c8d3\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1098\" file=\"ntkrla57.exe\" hash=\"155a9d621b9bead2eb6266091f91cfdcf09e112c203a057048ffe7a6eb03c9e8\" timestamp=\"0x66c0a134\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1165\" file=\"ntoskrnl.exe\" hash=\"3cfe8bdabc19d9a583551faaa622c2d95f7ffa02ff1c73ee03f6fc483d186bed\" timestamp=\"0xa9fba976\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1165\" file=\"ntkrla57.exe\" hash=\"5fd2e139d33c618ae859d81f58c7a6ac1ec6b5369543d6099bf40608ea4fdf0e\" timestamp=\"0xd1dcc266\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1219\" file=\"ntoskrnl.exe\" hash=\"2db528ed2334328f9323c44a564ca13a7fc8a197b82b4546699b83d34c38a064\" timestamp=\"0x947c30fd\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1219\" file=\"ntkrla57.exe\" hash=\"eb8c15f62a80e104e5cf95c45a7e540f8e1aee8e95c8d67270ef7cae40347202\" timestamp=\"0xa06feee0\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1281\" file=\"ntoskrnl.exe\" hash=\"1624313da08dab9efd056740ed9c8dfdee35d086210225ee1cb953815f73ee4b\" timestamp=\"0x5fc605e9\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1281\" file=\"ntkrla57.exe\" hash=\"68999577ea692152303c494e69c7757e52d65efc2c85a79c7cd4a09e0536ad00\" timestamp=\"0x4f7f6696\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1281\" file=\"lxcore.sys\" hash=\"9731180ca07771938cc1eaa48c3c2bcc0cf956528b93108543eb3e83a85602c7\" timestamp=\"0x9e4850c4\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1335\" file=\"ntoskrnl.exe\" hash=\"95abe0e67283164ab779e52f21109d1dc6194dcd420483b4b93a31d7f7b5ef49\" timestamp=\"0xd6e46b79\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1335\" file=\"ntkrla57.exe\" hash=\"945a9e0eb8fefc3904ef409409325ec2e69af678b221996e23b99f3d00d9a34c\" timestamp=\"0x3467ce6a\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1455\" file=\"ntoskrnl.exe\" hash=\"db10f8f37d6cf91ef88921ec5a66377c59604c35687e122729f0a82360b562cc\" timestamp=\"0xac349aed\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1455\" file=\"ntkrla57.exe\" hash=\"6a224921079501540bdbf58666b7196227ba61190109fb783e8c41100ae5776a\" timestamp=\"0xa05945ed\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1516\" file=\"ntoskrnl.exe\" hash=\"2519d314ac36ef92e0e2b0ff75e6e528be8098f226eb222a49fa2d2edab91caa\" timestamp=\"0xa691d3cf\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1516\" file=\"ntkrla57.exe\" hash=\"0b4f0d86057829be5b7f9b3c319cdc63db41ac44efe5b2aec99439b82fabe499\" timestamp=\"0x757543db\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1574\" file=\"ntoskrnl.exe\" hash=\"5ef98625c968578012b8539ccfc896921a726b1c95480ccba84e5ee937ca190c\" timestamp=\"0x81337bdd\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1574\" file=\"ntkrla57.exe\" hash=\"bd699e163629c131e186a6767341f97fa679864ce379a2e7e04821a1ef9ecda6\" timestamp=\"0xf8763317\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1641\" file=\"ntoskrnl.exe\" hash=\"2ab00139679bb2181e54ae29198476e28eba43fe42b5fa593ac1a6e661b03e55\" timestamp=\"0x6cf47acb\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1641\" file=\"ntkrla57.exe\" hash=\"05d07482fedc4aa3b79967095d8f9841a49b7d34f48b6cd74ed59f66744a752f\" timestamp=\"0xc99ae5b6\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1696\" file=\"ntoskrnl.exe\" hash=\"1587c08577a5e402d789ce8a88d11e33466d9ae0f6ab086f2beba1d2f2330f5b\" timestamp=\"0xa6d8642f\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1696\" file=\"ntkrla57.exe\" hash=\"fdb7c0b803460a2d4eaf10fb7efcfdc8c44d436a06420a5b157736731784e597\" timestamp=\"0x430d7a19\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1761\" file=\"ntoskrnl.exe\" hash=\"7a0279cedfaeea39ff49b9e215cd82bb639fdde8288761a4d944b4191ad96486\" timestamp=\"0x6dea2d26\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1761\" file=\"ntkrla57.exe\" hash=\"37db50a397901eb34ca7d921bf6ceb04da5b10ba2b0bae524506d0225b3853e8\" timestamp=\"0xd9d592b5\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1817\" file=\"ntoskrnl.exe\" hash=\"c81a59ef67e0ba077f1df6ca871902ed419b83271cd6b5c73a9532815d9e6f48\" timestamp=\"0xd681fb3f\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1817\" file=\"ntkrla57.exe\" hash=\"52cebba2c057855ef0c4c28396e2af3b444cff7fef4258eef179f3b3842fca6f\" timestamp=\"0xabfbaa8f\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1880\" file=\"ntoskrnl.exe\" hash=\"db88a6412782d59e528cb00c543502a8067dcc9308b24e7d072414e993ce74f1\" timestamp=\"0xbfed24bc\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1880\" file=\"ntkrla57.exe\" hash=\"f8580205857a794cc7f81754714fbb84ba2485455f7ff2462894bfbd2ab3959b\" timestamp=\"0xe00f7fdf\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1936\" file=\"ntoskrnl.exe\" hash=\"b1581f575657f9522fed4885ed39283707c7837e733e9c0194fe2ba4c4bce4ec\" timestamp=\"0xd1f4b617\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.1936\" file=\"ntkrla57.exe\" hash=\"f2f234a2d25f5028d8327628d4ef7995a9e2c9bb212cefd3a7d89a4537f8fe8c\" timestamp=\"0x1235f61f\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2003\" file=\"ntoskrnl.exe\" hash=\"866a1fe9ce579eba75b9d3a4e8a6e5a73da859f9bb38a18d91119d16386a00c9\" timestamp=\"0xf6c33431\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2003\" file=\"ntkrla57.exe\" hash=\"bd56498058ecf6f487a28bc11a82fcd371b665542811b2d1916262e6f2780d5f\" timestamp=\"0x9812978c\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2057\" file=\"ntoskrnl.exe\" hash=\"048dfdbad43558aab82d882522b1005e5a78f6a5c903570db7852e091207dc6f\" timestamp=\"0x5a33a165\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2057\" file=\"ntkrla57.exe\" hash=\"aec31cc73f0e5a528880497e9879c5b87983b867321a521a6f5a847a9bff6dac\" timestamp=\"0xa34e6df4\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2124\" file=\"ntoskrnl.exe\" hash=\"7dbf9213b7b1803ef8437a6789e6034e4004dc88d6638cc7381a1649a57c308f\" timestamp=\"0x40fcd791\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2124\" file=\"ntkrla57.exe\" hash=\"8c2c36bf59925a1a9a8b621bed7381c047258d373aff8e6cb9c1eb981ff207d7\" timestamp=\"0xf5197a9a\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2176\" file=\"ntoskrnl.exe\" hash=\"e13a878265e0be1b9f4d05c8d8b566ddd0db97df0c031f20ad0797a3ae9e192b\" timestamp=\"0xb30dbbe1\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2176\" file=\"ntkrla57.exe\" hash=\"e7436006abc247b2120021cd812a984948227801ba3b315447c47f994a3b21e9\" timestamp=\"0x1f6bdc82\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2245\" file=\"ntoskrnl.exe\" hash=\"c0db64ca0f72f5c318b4db4e77d0ef7d3f9480a795aa11c8b40f769eff8f710f\" timestamp=\"0x83a501c7\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2245\" file=\"ntkrla57.exe\" hash=\"b89b747bbfbd4bffde113382024bbbd5eb226e1c89937de063abb2879acdf5a7\" timestamp=\"0xccb66a25\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2295\" file=\"ntoskrnl.exe\" hash=\"3d9411b50da638b2107551c40abaffa69d48e18894f562fcb637077765e2c466\" timestamp=\"0xdc7e26ad\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2295\" file=\"ntkrla57.exe\" hash=\"2701f94dcd4776a041dc7bb9086d6a71f1f4f0b40fb9ed57c24c81095e17bee6\" timestamp=\"0x6a769bbe\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2360\" file=\"ntoskrnl.exe\" hash=\"b951acbea60e5ec105fc3e9370eb829ccb038ca2796248b8b371abc786df8d9f\" timestamp=\"0xa5e88a32\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2360\" file=\"ntkrla57.exe\" hash=\"9ac296b817c0fa69011614b76964773fe5e4f7cceaec748aff0062f6c8e974f9\" timestamp=\"0x4fe997de\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2416\" file=\"ntoskrnl.exe\" hash=\"0a1ff47bdf13b42d2f4645495fcb525d35b02f6342ccfeb1238ee2b0a0172ebf\" timestamp=\"0xb76d0104\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2416\" file=\"ntkrla57.exe\" hash=\"02bc51af213a5dd1a17d4b4b1cf263f51df7c774f83c09dc11e494d81114cab8\" timestamp=\"0x56a427bb\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2482\" file=\"ntoskrnl.exe\" hash=\"9e0a3ad48753a1e8fc6dbe20d983c8e50f608855b69f7f27b15a35b07b43cc8f\" timestamp=\"0x624097ba\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2482\" file=\"ntkrla57.exe\" hash=\"ac539b793234fe1e0438f2c5475cdbf0d56f350b7e71aa5c9ba613a9e5bd76a8\" timestamp=\"0x52eb1683\" size=\"0x01042000\" added=\"2024-10-20T15:35:22Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2531\" file=\"ntoskrnl.exe\" hash=\"29b5c970d552a013a9aa140ce9335bee3bb5731a74595b78cee250c49053ee18\" timestamp=\"0xdeb10b6f\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2531\" file=\"ntkrla57.exe\" hash=\"2766cdb72f7ec6952e95408a072bbebf8b0c8bea16ad76a5ca144ad5cfba2ea9\" timestamp=\"0x489ea9d3\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2538\" file=\"ntoskrnl.exe\" hash=\"90965522df752ee47dbb16ab42f65b10f8f092a4d3c99df7f195db14f5d2041b\" timestamp=\"0xbd5e1b9e\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2538\" file=\"ntkrla57.exe\" hash=\"c0d9e6b451df24b36af9f30590344dc06f02da9e68941b558c328a19b6a870f0\" timestamp=\"0xdf067bc0\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2600\" file=\"ntoskrnl.exe\" hash=\"a2604c54600d8539139d985d0774ac667bcf9232594c6b7fad6b12fe314c23fa\" timestamp=\"0x519638e0\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2600\" file=\"ntkrla57.exe\" hash=\"b468f77231891dbad57a4b54dd3f933d1496f28ccc8ff8fbe7e11acc5d54101b\" timestamp=\"0x5c65f649\" size=\"0x01042000\" added=\"2024-10-20T15:35:22Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2600\" file=\"lxcore.sys\" hash=\"65285024ff3bccb0ffc944f9802cb51108c423b3f91b8639517921d73bab8a5b\" timestamp=\"0x9cdff202\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2652\" file=\"ntoskrnl.exe\" hash=\"5d691b1385b31b46195665300980076d004514a7d91ed51aba9989513b1bfb63\" timestamp=\"0x9cda42ec\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2652\" file=\"ntkrla57.exe\" hash=\"019cbd36ce29d34c1e85a3868f310faa92bc9a301aa66c6da5ab72798a03b22c\" timestamp=\"0x3dbdc5c8\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2713\" file=\"ntoskrnl.exe\" hash=\"3538c46ecfae46cde5c0a98b908bca45c6bf9ba8d69f95007f26da6b6ebb6917\" timestamp=\"0x6de6761d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2713\" file=\"ntkrla57.exe\" hash=\"8cd77b2abdf355571a2625d9d8b58cf9f2379521e3a557e030642662db8b4a90\" timestamp=\"0x7a501980\" size=\"0x01042000\" added=\"2024-10-20T15:35:22Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2777\" file=\"ntoskrnl.exe\" hash=\"2b93af0a62c1b2c80c6e8c815cd4dd8d41af9391f71e9b1a8f01e40ce5cefa89\" timestamp=\"0xcaaeb0e8\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2777\" file=\"ntkrla57.exe\" hash=\"b68624e303a363aacf62988ba757b437d029889b1af85a35b75b66c93ca9a053\" timestamp=\"0x81ef2014\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2836\" file=\"ntoskrnl.exe\" hash=\"85e34f0d3eb8d1ff0dd74caa1d5060d60bdb9e3a9abc4b8c41265ae9fca040ba\" timestamp=\"0x61fbbb07\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2836\" file=\"ntkrla57.exe\" hash=\"ea84167d908a209c39bbd655cbeac2b1119ce3bffc8f66a45a7a11d82add305a\" timestamp=\"0x3b3af0b6\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2899\" file=\"ntoskrnl.exe\" hash=\"34aedd543eebcb52cf0478219b4f2e945bf030dadadfe495cb3bcfd5b75dd8d7\" timestamp=\"0x502e9324\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2899\" file=\"ntkrla57.exe\" hash=\"5c1f67119f28383ac0d472cda9be590c1ab5715d1ad17739d7e4b83e65712724\" timestamp=\"0x898fc0c0\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2960\" file=\"ntoskrnl.exe\" hash=\"6d045cd4663306e12b554c9803ede48adc339ce32ad08421493f1b395100b8a4\" timestamp=\"0x76fd27ec\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.2960\" file=\"ntkrla57.exe\" hash=\"73701f202264197cc783669a9e9ce1da2c220dd08b1aed4ee8d289fd170e4718\" timestamp=\"0x4a24bf85\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3019\" file=\"ntoskrnl.exe\" hash=\"c4331eca3988c842dd5408a20915af63c2016a976f125170bffe1993b74f9ba2\" timestamp=\"0x4e99c04b\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3019\" file=\"ntkrla57.exe\" hash=\"6289150fcce5545d7d34900f97ceea27b35f15caf8cf68f3b8661beee2e03706\" timestamp=\"0x117f3c01\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3079\" file=\"ntoskrnl.exe\" hash=\"7b97fdd9a465b41423e4e3c3cff478841ad1830b683904706afe282df145a9b6\" timestamp=\"0x792197ff\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3079\" file=\"ntkrla57.exe\" hash=\"bb822bec8747b75bf9365f91f6b5f52115bd124cb719842c7cca053ac83fa3dd\" timestamp=\"0x90ee946e\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3147\" file=\"ntoskrnl.exe\" hash=\"b50ab6a4e0289d30b346dd7644304dfc07cdf63b32ebcb83c2995150c9158e43\" timestamp=\"0xb23ed20b\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3147\" file=\"ntkrla57.exe\" hash=\"164e0923dbcf06355b21c75651b16029d602d91ff76862731a70555329307ece\" timestamp=\"0x3d23d9c4\" size=\"0x01042000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3197\" file=\"ntoskrnl.exe\" hash=\"4b6593143155e1a1314ab73bf9d0622180764268d54984541627b5041bb46de8\" timestamp=\"0x2a4f46b3\" size=\"0x01047000\" added=\"2024-09-14T02:14:31Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3197\" file=\"ntkrla57.exe\" hash=\"d4d7f0599857b29bbc5e0aa61df5413ed34a805b9fde967f6d1642f68c68cad3\" timestamp=\"0x4ac540ad\" size=\"0x01042000\" added=\"2024-09-14T02:14:31Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3260\" file=\"ntoskrnl.exe\" hash=\"913bc1ae4f89554145e75968e8de1084bca5682d00fcf77415097fe5f713f50a\" timestamp=\"0x58bad9ee\" size=\"0x01047000\" added=\"2024-10-12T01:50:50Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22000.3260\" file=\"ntkrla57.exe\" hash=\"8687fc3d2f74eb98f1690c83fd5015e992e62397531d5beb1c9dadf8ffcec260\" timestamp=\"0x5cba323d\" size=\"0x01042000\" added=\"2024-10-12T01:50:50Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22431.1000\" file=\"ntoskrnl.exe\" hash=\"b9e13f858272ddafe18cc53e266d5d3582eaa56063f3363d773d0caba7a5db6d\" timestamp=\"0x888c6207\" size=\"0x01047000\" added=\"2025-05-02T23:03:56Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22431.1000\" file=\"ntkrla57.exe\" hash=\"6f0c2f40341c532adf858eeb1030cebff52d8ea99447be39dd1db60222355076\" timestamp=\"0xe604f5bd\" size=\"0x01042000\" added=\"2025-05-02T23:03:56Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22454.1000\" file=\"ntoskrnl.exe\" hash=\"ebd0f26f81e0f0d57cfd0d4415e8d6ca708cd529d0800c5498f161a00175c0f8\" timestamp=\"0xb5d2f871\" size=\"0x01047000\" added=\"2026-02-05T23:25:24Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22494.1000\" file=\"ntoskrnl.exe\" hash=\"1519d0a9ea28d9bf720bf75b5c4afd39937e51e78310867e478dfbe6907b50b0\" timestamp=\"0x5265d507\" size=\"0x01048000\" added=\"2024-11-21T19:38:04Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22495.1000\" file=\"lxcore.sys\" hash=\"8021fdbd678c00c10076c3e582d3fc82b5b5d7f9e8be8553e7bc5a50bc26c984\" timestamp=\"0x6dd91ce8\" size=\"0x0010e000\" added=\"2024-11-21T19:38:04Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22499.1000\" file=\"ntoskrnl.exe\" hash=\"afcae4258a192a743fe5a49661adcbc9c2f46c68befb2dcead60e0565bf8d16c\" timestamp=\"0x60c002c2\" size=\"0x01048000\" added=\"2025-09-11T03:22:38Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22499.1000\" file=\"ntkrla57.exe\" hash=\"91c7c246eb7503800a6739b8036faf7464f4ea34db2d855bdf4ebb5213c1e4f3\" timestamp=\"0x789d3662\" size=\"0x01042000\" added=\"2025-09-11T03:22:38Z\">12</data>\n    <data arch=\"amd64\" version=\"10.0.22526.1000\" file=\"ntoskrnl.exe\" hash=\"fbef64e45aca1c61b956a59aa5d8ab3b0fefc1f1a6c48ffc0f87666a3e7ccfa4\" timestamp=\"0x35378e90\" size=\"0x01046000\" added=\"2025-04-23T00:45:13Z\">6</data>\n    <data arch=\"amd64\" version=\"10.0.22563.1\" file=\"ntoskrnl.exe\" hash=\"21cc808bb32d2b5aebf7deb2dde072ace9bd52753dff50d126f085090bd373e6\" timestamp=\"0xa9d783ff\" size=\"0x01047000\" added=\"2025-03-02T06:42:51Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22567.200\" file=\"ntoskrnl.exe\" hash=\"8e719872fcc04d041c874101946214b31a12de9039937395e693b536ed681455\" timestamp=\"0xc2e5f7f2\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22579.1\" file=\"lxcore.sys\" hash=\"4346ef5e05cc49524276700132d44e8c0e9e46ed80e6f52c590f2b090c403863\" timestamp=\"0x7c458bab\" size=\"0x0010e000\" added=\"2025-03-02T06:42:51Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22589.1\" file=\"lxcore.sys\" hash=\"01e93289e0769f0b3e1f8f60b9f9e0d4ceea831ee2a871a283dfa2c6c78e22f6\" timestamp=\"0x5fea6775\" size=\"0x0010e000\" added=\"2025-06-07T14:16:57Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22610.1\" file=\"ntoskrnl.exe\" hash=\"d2e462f77d8df46ae0e5cb9f0d7419099ac41eebc4e88dd0e1d72d7e266a2e88\" timestamp=\"0xc551bb0b\" size=\"0x01047000\" added=\"2025-03-14T04:05:46Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22616.1\" file=\"ntoskrnl.exe\" hash=\"ecb1eb4178b561074f3eb4a5ae5f12bb96e21a3ca5514a34aa726bdddabc25b8\" timestamp=\"0xe95cbc74\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22616.1\" file=\"ntkrla57.exe\" hash=\"c48bd91a1896b40b6b9940ec561bb7cf8d0a9fa29e3bb106aa445d4df7b596be\" timestamp=\"0x42a12a38\" size=\"0x01041000\" added=\"2024-11-05T01:22:32Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1\" file=\"ntoskrnl.exe\" hash=\"8da58257e42b4716cd873fb2a6244daf769fb13c7585d078dd281513bd1c6f7d\" timestamp=\"0x9182ea07\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1\" file=\"ntkrla57.exe\" hash=\"6b7be416aa884bf653f41da20adec1b592b1b868982c40c2d2e6237b9c9fb024\" timestamp=\"0xd29420fe\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3\" file=\"ntoskrnl.exe\" hash=\"8e68597a7d3dee86e7149b0632b6e3b5ed095ff2cedea8ae7989f99db85e6286\" timestamp=\"0x1ea4b573\" size=\"0x01047000\" added=\"2025-08-12T14:54:17Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4\" file=\"ntoskrnl.exe\" hash=\"e78fba1c4a4e73680d910c57046d4473cd6b1dbbbcb5b779ebd3ba9437aa8186\" timestamp=\"0x696271a9\" size=\"0x01047000\" added=\"2024-12-03T02:17:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4\" file=\"ntkrla57.exe\" hash=\"9831d62c8be776a4034fc68797214ed1eea6e4e4455e7ff85a648e5839ee0b96\" timestamp=\"0xb1340549\" size=\"0x01041000\" added=\"2024-12-03T02:17:28Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.105\" file=\"ntoskrnl.exe\" hash=\"ae3e24617168ea046a165c883b8fc32c19020e1e22a52cbbc99a830fda8bf3b6\" timestamp=\"0x4e134926\" size=\"0x01047000\" added=\"2024-11-19T23:19:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.105\" file=\"ntkrla57.exe\" hash=\"f0cd3de87dab266a557cebcf144822c36543415e121dc24cd0410848d0bba8c5\" timestamp=\"0x1afabb93\" size=\"0x01041000\" added=\"2024-11-19T23:19:13Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.160\" file=\"ntoskrnl.exe\" hash=\"80ece5ad75ccc4f16f05ee92c2332f49bcf2bb31c2448c0d478d7a7c5bffad87\" timestamp=\"0x6ffcb698\" size=\"0x01047000\" added=\"2025-05-01T02:24:25Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.169\" file=\"ntoskrnl.exe\" hash=\"3f6dd94d7574d22dce95c2bcb141dd913960223bb3276ffea5c54f0954923c28\" timestamp=\"0x11f97bd5\" size=\"0x01047000\" added=\"2024-11-13T15:20:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.169\" file=\"ntkrla57.exe\" hash=\"b568a91be40f6041ec09590b7241ffae3684597520328063e4d761546a66657d\" timestamp=\"0x4472eb65\" size=\"0x01041000\" added=\"2024-12-10T02:56:39Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.232\" file=\"ntoskrnl.exe\" hash=\"439af936dc1f2a92269c4bb6627f4dc4720cf83f7314d2c1e3b143beb1cce1ed\" timestamp=\"0x1288c09a\" size=\"0x01047000\" added=\"2025-03-14T04:05:46Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.232\" file=\"ntkrla57.exe\" hash=\"10f246a328db17f05134c8b41c8345ebb5f875382e0ad44015158602ef078205\" timestamp=\"0x603697f9\" size=\"0x01041000\" added=\"2025-03-14T04:05:46Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.232\" file=\"lxcore.sys\" hash=\"77b82ed7c16b3c7739c7eecb55199c502fd89cad898490b00f11eb83b69de575\" timestamp=\"0x1ed3f1c9\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.290\" file=\"ntoskrnl.exe\" hash=\"016f4140add55ef97c9514be9a4abb483dc9f97b60399433d42ff2003b0dea18\" timestamp=\"0xc55bd2d3\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.317\" file=\"ntoskrnl.exe\" hash=\"e63034a38ad4b4b156bb398535329dcc668f64de988ca0cdd6d143b9baf8288f\" timestamp=\"0xbb281a07\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.317\" file=\"ntkrla57.exe\" hash=\"b101e196e1d2d598dd4e76ddc8779ea4519ecf6844a1ef2d427f5cea723ab1a5\" timestamp=\"0xc9d20c1c\" size=\"0x01041000\" added=\"2025-02-17T22:56:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.382\" file=\"ntoskrnl.exe\" hash=\"945b23dbe1c67bb89dd9ed1428d1779d31857c92803696642de5bb921c0cc9f8\" timestamp=\"0xc90790d6\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.382\" file=\"ntkrla57.exe\" hash=\"b8fda6eef5ece118d32d46e7797bea18edcb789ed17100c89ed7e2d2e098302b\" timestamp=\"0xc0fb8659\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.436\" file=\"ntoskrnl.exe\" hash=\"0a9dec1442bac4c8ca11925db58a11561849e51e8473359f286ccf00f9bc7ec2\" timestamp=\"0x2dd70d14\" size=\"0x01047000\" added=\"2024-09-26T00:30:31Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.450\" file=\"ntoskrnl.exe\" hash=\"9cfaeada5d6f4c55c6eeb02f9c49b1c2cc1e09b6faab6c84016caa5365e15421\" timestamp=\"0x022eaf1e\" size=\"0x01047000\" added=\"2025-04-03T06:14:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.450\" file=\"ntkrla57.exe\" hash=\"4691ed255629c4f68db9c188ef54c880236c4eec05e8b76d73385ef920053b7a\" timestamp=\"0x64410cc2\" size=\"0x01041000\" added=\"2025-11-25T23:06:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.457\" file=\"ntoskrnl.exe\" hash=\"8565a938929bdc22da62b1c0b96eef7a76c3fd4405a96b3ba745bc5edaae2d10\" timestamp=\"0x9228f698\" size=\"0x01047000\" added=\"2025-10-09T21:10:38Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.457\" file=\"ntkrla57.exe\" hash=\"be9dd4a95fd027e6af9cb970d274bd5a27ada662c2a75879bbdd715f7b78f96d\" timestamp=\"0x4c2e2465\" size=\"0x01041000\" added=\"2025-10-09T21:10:38Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.521\" file=\"ntoskrnl.exe\" hash=\"ffdaec8083b242a3d0beaf4f5194662a8cc90d534649504bca374053bd97a51f\" timestamp=\"0xf97aa015\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.521\" file=\"ntkrla57.exe\" hash=\"505bf3b77aaf25afb3c0dab6ab677da4ea4ae02ee90f9623ab518cf95a4c83fb\" timestamp=\"0xeb7e2fd5\" size=\"0x01041000\" added=\"2024-11-05T01:22:32Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.525\" file=\"ntoskrnl.exe\" hash=\"f70a89c1f806ed10ba1ffb64a8d0734c746ed33951557866c50b207b74899fca\" timestamp=\"0xc934b2e8\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.525\" file=\"ntkrla57.exe\" hash=\"23e2039d25a2c654038d687129cf541c22a466e047d50d4f833859d3b390ef75\" timestamp=\"0xc5efdadf\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.575\" file=\"ntoskrnl.exe\" hash=\"d2e0c42ccefe266ebdc3c8c680b96e39d1cf063c259512e5800f5998168dc303\" timestamp=\"0x0e55c663\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.575\" file=\"ntkrla57.exe\" hash=\"927bb8a5dbbdacdbc1a8491e40ceee33d3184ad70904ef8c90040da29753e81c\" timestamp=\"0xaea685ea\" size=\"0x01041000\" added=\"2025-04-03T06:14:10Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.590\" file=\"ntoskrnl.exe\" hash=\"18de072425bc315596275dad3f4a582691285806bf8b2468b050d8eaba34e15a\" timestamp=\"0xd2bbfbc9\" size=\"0x01047000\" added=\"2025-04-09T14:22:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.590\" file=\"ntkrla57.exe\" hash=\"c3553774db5af4475d36e1244d1975214ed4bec3ae66d404cb76937202b55b23\" timestamp=\"0xdfcbb85b\" size=\"0x01041000\" added=\"2025-04-29T19:16:15Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.598\" file=\"ntoskrnl.exe\" hash=\"34233b7c17c7274df1ebd7245d41137462af482f8cb7383bce500812789444c0\" timestamp=\"0x26e8e5ed\" size=\"0x01047000\" added=\"2025-05-10T01:12:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.598\" file=\"ntkrla57.exe\" hash=\"ba3467b38685fb84988835dad9567154736e3e2999c1ff130e848a372924be26\" timestamp=\"0xdb6f127c\" size=\"0x01041000\" added=\"2025-05-10T01:12:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.601\" file=\"ntoskrnl.exe\" hash=\"c846f1e200d25ca2ca26de70eb94b99ee9610a4763ece05c3e9fd8b4e8c7de5b\" timestamp=\"0x80d613c7\" size=\"0x01047000\" added=\"2024-12-11T14:53:46Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.608\" file=\"ntoskrnl.exe\" hash=\"87b093efcd5052320585b0f42c755ae9ccf7674b03494adcebb98bff110d9601\" timestamp=\"0x0e937cbc\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.608\" file=\"ntkrla57.exe\" hash=\"e725f3ad613099a635d1ce15eec5759c1adca29bc0e5365e8f2f76d951972235\" timestamp=\"0xc9a88254\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.674\" file=\"ntoskrnl.exe\" hash=\"0b80914bff91675f85551b009d0cc68fd6c89616914e4d4a0da9003a6d16fe62\" timestamp=\"0xa665dd9a\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.674\" file=\"ntkrla57.exe\" hash=\"ad0d97ec1779b161e26354d5e2bc37b1461a11f3c615d7b247e8f26833b4fac5\" timestamp=\"0xda0f20e6\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.675\" file=\"ntoskrnl.exe\" hash=\"478e44011b464f8aa5b37128d203fd44b12f43f155583647b9b72029c918d32e\" timestamp=\"0xe5b456bc\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.675\" file=\"ntkrla57.exe\" hash=\"e084f8114d5d64a2fa7acd049567334cef280d4caec222d46177074b3097d668\" timestamp=\"0x4360bb1c\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.730\" file=\"ntoskrnl.exe\" hash=\"dd0e8c4e0e68dfbd5c3891bf6901f302d5bd29350c82a30cc2bd654166c115a2\" timestamp=\"0xeb7c3336\" size=\"0x01047000\" added=\"2024-09-26T00:30:31Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.730\" file=\"ntkrla57.exe\" hash=\"b70409fdc809b47aeaca6cbc5040df733367865f0360aa6556d2208764924d9f\" timestamp=\"0x73a08743\" size=\"0x01041000\" added=\"2026-03-19T02:51:26Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.741\" file=\"ntoskrnl.exe\" hash=\"8025c442b39a5e8f0ac64045350f0f1128e24f313fa1e32784f9854334188df3\" timestamp=\"0x99685dca\" size=\"0x01047000\" added=\"2025-11-29T19:10:30Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.741\" file=\"ntkrla57.exe\" hash=\"342b1a052015b8b6214b3cfd5167c08d43ec93fa38734b330ce38012996fd205\" timestamp=\"0xb35886b2\" size=\"0x01041000\" added=\"2025-11-29T19:10:30Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.741\" file=\"lxcore.sys\" hash=\"c9af4d601ba768440a6eddffbd37f2fb3d8114182cdc34d0cf114de6261c7983\" timestamp=\"0x37c30b52\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.746\" file=\"ntoskrnl.exe\" hash=\"b35652268407ca7fe7b02a152f6c62754037f99a294afb452d1ba4770513c9a6\" timestamp=\"0x6e7edd8d\" size=\"0x01047000\" added=\"2024-10-26T06:39:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.754\" file=\"ntoskrnl.exe\" hash=\"d491372a6b8fb6c8ceae1d104ff0b54242f6be6245d3115dfb8e4cc40090853b\" timestamp=\"0xac023782\" size=\"0x01047000\" added=\"2025-03-28T03:59:19Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.755\" file=\"ntoskrnl.exe\" hash=\"35eb6f97a2cc007101e80a436fb11eb43803f813bbcf55e7d8ee91c8cac9169c\" timestamp=\"0xdaf51a14\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.755\" file=\"ntkrla57.exe\" hash=\"7a65e1d3aae19d8103c575d42a9395bde71eec4e17844921873d0cb70d3b661f\" timestamp=\"0x082be711\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.819\" file=\"ntoskrnl.exe\" hash=\"09ba0359ba3e8ec909295582833b625dcc9af201b637e870a88e062a4a742dd0\" timestamp=\"0x3cbf9709\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.819\" file=\"ntkrla57.exe\" hash=\"92e0ef561a0133f334dbe6c5c2936bc60e95ae039e36bfa090b1a3415841e634\" timestamp=\"0x00828b44\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.870\" file=\"ntoskrnl.exe\" hash=\"e8b5e2ac8154502ea91d527553480a471cd1ecf139e199575230fb7351ffb578\" timestamp=\"0x08dc1770\" size=\"0x01047000\" added=\"2024-09-27T22:22:02Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.885\" file=\"ntoskrnl.exe\" hash=\"37e7883ec4407dcd9ba88f75e9f9986dde72102cbef7150afa62f85eaed94eeb\" timestamp=\"0xa33af072\" size=\"0x01047000\" added=\"2024-12-24T06:47:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.891\" file=\"ntoskrnl.exe\" hash=\"0b6e5c9cd21860d8dddda726cab3846538e151002bf220afab83e9986e1e5b26\" timestamp=\"0x7e1c330e\" size=\"0x01047000\" added=\"2025-03-11T02:45:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.898\" file=\"ntoskrnl.exe\" hash=\"4e12f363aad765b16655b5a7f3f02084357be98ac9d973c509d6c33cc0e6fca3\" timestamp=\"0xba245521\" size=\"0x01047000\" added=\"2025-06-13T19:27:57Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.898\" file=\"ntkrla57.exe\" hash=\"4a938403e153fb674bbea6b1895130183e317cc1ec7b557dbf7f0a43a9a1a0eb\" timestamp=\"0x72292194\" size=\"0x01041000\" added=\"2025-06-13T19:27:57Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.900\" file=\"ntoskrnl.exe\" hash=\"b1ea45275fb3c5f522add838584d718517e11cc05bf04b7ad4da063ac0805e48\" timestamp=\"0x2e314319\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.900\" file=\"ntkrla57.exe\" hash=\"2c67ff364df14d1218dd4d701d6325c49c00617c276943bf1b72a5b9b36b85ff\" timestamp=\"0x6733eb6a\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.963\" file=\"ntoskrnl.exe\" hash=\"7c9792b097a33fcfc1ac21ce039a3f084482845ebd26c28d4f59e65aa8b99e60\" timestamp=\"0xf57b5a93\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.963\" file=\"ntkrla57.exe\" hash=\"1f56463f36877631c9d668ae6f5f198c34016c3652dd4887d32e38bdf1217803\" timestamp=\"0x7464445d\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.963\" file=\"lxcore.sys\" hash=\"c5c9f7b055cd949159ec9bb7a35e6ff69ba515161b39048797dcf0d1734e0487\" timestamp=\"0x097ac207\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1020\" file=\"ntoskrnl.exe\" hash=\"b513f6b4c9d4be2a289a30180c22a21e535db994298e3e283dc3630389c5a352\" timestamp=\"0xd4051ad9\" size=\"0x01047000\" added=\"2024-12-10T02:56:39Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1028\" file=\"ntoskrnl.exe\" hash=\"721ce1c1a5606350766ca9dcb70fc19c1194c21c83e6be610ffba3a9fa8938bc\" timestamp=\"0xabbc196c\" size=\"0x01047000\" added=\"2025-02-06T01:33:17Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1028\" file=\"ntkrla57.exe\" hash=\"cba12fe8561dc82c60ae0ddf4b41aec851b159022c3b6291f5d01f2cdeebfdc9\" timestamp=\"0x8766149b\" size=\"0x01041000\" added=\"2025-02-06T01:33:17Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1037\" file=\"ntoskrnl.exe\" hash=\"e8e074a33075e7418748bcc94a47a9916f46384e9b53ab342f0891b80bfaa245\" timestamp=\"0xdd6b43a1\" size=\"0x01047000\" added=\"2024-10-29T02:19:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1105\" file=\"ntoskrnl.exe\" hash=\"2104395fbf7e239a881ae89cc39884424976772e0d389644a063f84e7e9d04d0\" timestamp=\"0xac027ca4\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1105\" file=\"ntkrla57.exe\" hash=\"73c69ffff08855346c91112c1272cf091432f9da3e0b90c3530da4b4a5531ca4\" timestamp=\"0xb4a51143\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1105\" file=\"lxcore.sys\" hash=\"fbe476951f67fcfd80cba00cf08aa9fbaacc44d21b9dabf5a1a3b630444cbdbc\" timestamp=\"0x510587ad\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1180\" file=\"ntoskrnl.exe\" hash=\"e95dc743af3902632d6c7c538ed7a548d81873d1f128eee4f61feb276d9a57fc\" timestamp=\"0x6233b5f6\" size=\"0x01047000\" added=\"2025-08-21T15:11:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1194\" file=\"ntoskrnl.exe\" hash=\"c246397fd3c0446e58b4be2e487b852e0f963c76d1453e00a4e1e8dabebc56ab\" timestamp=\"0x3f960eff\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1194\" file=\"ntkrla57.exe\" hash=\"e6f3c4bea2a6fd9774d98870c790af48a34f9d1240fafb646280e3dede6e4b13\" timestamp=\"0xba28bcb7\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1245\" file=\"ntoskrnl.exe\" hash=\"6be5dbff4bef2f5585c06d542724e339170e66cb1228243312f336229742eee0\" timestamp=\"0xbae3e9d2\" size=\"0x01047000\" added=\"2024-11-24T17:20:19Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1245\" file=\"ntkrla57.exe\" hash=\"ab44ffe75c2e94ecee6381496fce7f3b52f0b6a5e2509116daf352642ea28478\" timestamp=\"0xc7df2d95\" size=\"0x01041000\" added=\"2024-11-24T17:20:19Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1255\" file=\"ntoskrnl.exe\" hash=\"98802311859f43077c4de39a7c344b2fae5987dc12cdf7742a3888e33cccd9f2\" timestamp=\"0x647d5968\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1255\" file=\"ntkrla57.exe\" hash=\"29bf1c3bec2c141c4ccf713617f823c34a63efb60851fb05bbb6214ccc6b1fef\" timestamp=\"0x716328c7\" size=\"0x01041000\" added=\"2025-02-17T22:56:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1265\" file=\"ntoskrnl.exe\" hash=\"7d17ecac9aae8e222fd54741a1f17ff8809eaf67dab630094879adba002317ee\" timestamp=\"0x9adc6fbf\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1265\" file=\"ntkrla57.exe\" hash=\"586d903d0adceb796f5c9d6b9cfcea2d76e534dd860c80c7f2d9b639e4965505\" timestamp=\"0x206f54b5\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1325\" file=\"ntoskrnl.exe\" hash=\"4b4dfc809bc5a109ba94d6f20284adad8a32f86a854456f0d67a1ea59f19fee7\" timestamp=\"0x735f45f2\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1344\" file=\"ntoskrnl.exe\" hash=\"1b30d5f89790f8ee0d80d2ed29d1177dd3f58042a89e9efee9be17a4660c7d58\" timestamp=\"0xf7e31ba9\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1344\" file=\"ntkrla57.exe\" hash=\"49ee753f0e13ba4383a38613de7c90654eafc99a7da4b73f58614a61a799dc2a\" timestamp=\"0x94e3cdcf\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1391\" file=\"ntoskrnl.exe\" hash=\"565fede69c1c2bd5441cb7258352a385c252459e77f328e231c176c27a4dd3bd\" timestamp=\"0x0ab9f0dc\" size=\"0x01047000\" added=\"2024-11-19T23:19:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1413\" file=\"ntoskrnl.exe\" hash=\"140ae8fda7efff8039514b89f571e6ae27e2c634881e3d3e1dc4b4e37ddbd6c8\" timestamp=\"0x17b6b722\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1413\" file=\"ntkrla57.exe\" hash=\"83c120cb957241d22dae894c3374bdd456bb54e4ff9a148104bda205473c8abc\" timestamp=\"0xa40bd1ca\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1465\" file=\"ntoskrnl.exe\" hash=\"b6a7e3da5f48b9d402534251b281c4bde74799c52f96622deaffe95e25d5f2dc\" timestamp=\"0xca416e49\" size=\"0x01047000\" added=\"2024-11-09T04:03:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1465\" file=\"ntkrla57.exe\" hash=\"c37a021addf808124bc152eb590a3647cfbabe98414278386251566e47eb3cca\" timestamp=\"0x7a664f74\" size=\"0x01041000\" added=\"2024-12-10T02:56:39Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1470\" file=\"ntoskrnl.exe\" hash=\"3743187523c1988c943579b38f65b231ef713f8b214fb2a1df2af59546a00966\" timestamp=\"0x2aa345c4\" size=\"0x01047000\" added=\"2024-11-19T23:19:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1470\" file=\"ntkrla57.exe\" hash=\"310888939a2cba5d3527368d62e00449e75bea796d71d511fc40123cbfbd2ada\" timestamp=\"0xfd25b7d5\" size=\"0x01041000\" added=\"2024-11-19T23:19:13Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1483\" file=\"ntoskrnl.exe\" hash=\"e71f2fbce0928fc02646985e8072214389247d69632b5a661f9fca49367ac346\" timestamp=\"0x7a5ef578\" size=\"0x01047000\" added=\"2025-03-14T04:05:46Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1485\" file=\"ntoskrnl.exe\" hash=\"e71f2fbce0928fc02646985e8072214389247d69632b5a661f9fca49367ac346\" timestamp=\"0x7a5ef578\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1485\" file=\"ntkrla57.exe\" hash=\"d93f5906da4d0f2023ee9c6ad77a6a0ab21ab8325a642fdd0c9b03e3b7299ca7\" timestamp=\"0x04ba21bd\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1537\" file=\"ntoskrnl.exe\" hash=\"7ef31b7f1aa2de5d1e6c8147aae95a3944eb0fb64473b30fa90e44bd7b770e6a\" timestamp=\"0x7c87e836\" size=\"0x01047000\" added=\"2024-11-09T04:03:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1537\" file=\"ntkrla57.exe\" hash=\"1017a5f8ab04bfada1d8d5e9e1e6b5d88bbbca5a5344258f74ca1078d04cfc1e\" timestamp=\"0x1978c3b0\" size=\"0x01041000\" added=\"2024-11-09T04:03:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1546\" file=\"ntoskrnl.exe\" hash=\"659d4994a124dd968e017584bbb709a0845307883e622626474e68831c1fc05a\" timestamp=\"0x00d07e9c\" size=\"0x01047000\" added=\"2025-01-15T01:55:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1546\" file=\"ntkrla57.exe\" hash=\"42f5a57f8fdd183212bd0ad27742685dfc6ce95d56e8ef0e7dc4e40e880014d1\" timestamp=\"0x23f47ea9\" size=\"0x01041000\" added=\"2025-09-04T03:27:22Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1555\" file=\"ntoskrnl.exe\" hash=\"35c9d3384ab1858b5460415ce752daa884dfd73eb25c02755909cd82a130103f\" timestamp=\"0x9982c311\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1555\" file=\"ntkrla57.exe\" hash=\"2b1e470e935dfe55b67d1bf2dc9ac56364505ed2f0134a9ebfbf11ba0cbafd2a\" timestamp=\"0xadf62f05\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1610\" file=\"ntoskrnl.exe\" hash=\"af49dd93e377b9d253a8f8232a582278e3a10f425d3b32c272a9310aab85dcc9\" timestamp=\"0x0c4e4ea9\" size=\"0x01047000\" added=\"2025-12-13T17:54:25Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1610\" file=\"ntkrla57.exe\" hash=\"356b92553cdaaf12356bd53f05f7e2409afb45a0ebe7eddb42a553daf1ae52aa\" timestamp=\"0x106b3bd3\" size=\"0x01041000\" added=\"2025-12-13T17:54:25Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1616\" file=\"ntoskrnl.exe\" hash=\"d18083cb3cf395783bab09f2fa17af1ea63107da3139b58b24fb8970607594d8\" timestamp=\"0xe585c10e\" size=\"0x01047000\" added=\"2025-07-03T02:32:17Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1635\" file=\"ntoskrnl.exe\" hash=\"d70274429b40c5c90c5136b65f34ecdc0e988d7d3d277cb683d57bd04fa426d6\" timestamp=\"0x0e3838fc\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1635\" file=\"ntkrla57.exe\" hash=\"5a0c4be5ab0b5ef4e1401d7bfa64d357cfa2a87c7a9ce7bc524ca8d3fc0ac196\" timestamp=\"0x01af166c\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1680\" file=\"ntoskrnl.exe\" hash=\"7593a4dd020d55dd3c6d5d979e7fa245705a3aa0b8b1e4330013742f93e6bf01\" timestamp=\"0x97d9f5ca\" size=\"0x01047000\" added=\"2025-01-15T01:55:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1680\" file=\"ntkrla57.exe\" hash=\"d0684eb6f852c7fa8a68b6747a7898a5acc21b8cf8f7f068ec65f41ccb629425\" timestamp=\"0x31f8efd3\" size=\"0x01041000\" added=\"2026-03-11T23:28:21Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1702\" file=\"ntoskrnl.exe\" hash=\"970d9bdc6927282bc9779ce235bc0a6384f6ef5ca05b69b64eadb2f9bd08cbfb\" timestamp=\"0xaff18ce5\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1702\" file=\"ntkrla57.exe\" hash=\"1db472eba3fd1d881a356c44ba4e552c48a45d7ef365a98ae8fb6b103c9af641\" timestamp=\"0x432159fd\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1755\" file=\"ntoskrnl.exe\" hash=\"b76e95c1b469bcaa7a2444ccb99615f46506e7e3496228baac84c48e04055476\" timestamp=\"0x203ce805\" size=\"0x01048000\" added=\"2025-06-19T01:46:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1755\" file=\"ntkrla57.exe\" hash=\"d60eea5dcef83bd7a2882ab8d4c8dc057884b91ad439cb96cbf50c056b3a5f64\" timestamp=\"0xe920169b\" size=\"0x01041000\" added=\"2025-06-19T01:46:28Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1778\" file=\"ntoskrnl.exe\" hash=\"3f21e646ab2febb818634de4639a3f3a1982398cd08977d20225f122d05595f8\" timestamp=\"0x44265b0b\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1778\" file=\"ntkrla57.exe\" hash=\"9549160513f5b0c4f38c6ca618d9f7f850efaa6f5a4c750e9f6a3340869a2d72\" timestamp=\"0x5dbb0df4\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1835\" file=\"ntoskrnl.exe\" hash=\"8bae0622566eeecfc4f2a5154adecc0da7ebeb58ed9675a37dc33b5a4f13d847\" timestamp=\"0x3fe5a0c9\" size=\"0x01048000\" added=\"2025-04-09T14:22:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1835\" file=\"ntkrla57.exe\" hash=\"4aab30e3dac717010e20b7100e94841d4661ac0b7bd6b40b0c48eee820004d1c\" timestamp=\"0x13c69052\" size=\"0x01041000\" added=\"2025-09-17T06:25:37Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1848\" file=\"ntoskrnl.exe\" hash=\"c7a3f55fd7817cec48d095fbb121cd471f61529cd6915f961c67e8e7a9fb40af\" timestamp=\"0xd7d283f7\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1848\" file=\"ntkrla57.exe\" hash=\"0adda15e89fd8e8be0a747f05b4160101d52fe70b1e4fa104417273d6b87d50b\" timestamp=\"0xf1f1e626\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1900\" file=\"ntoskrnl.exe\" hash=\"2bc9703d336ef1cc681c93135cb4182dfbf4344c9270a85c607b4131248c7332\" timestamp=\"0x9dbf2fb8\" size=\"0x01048000\" added=\"2025-03-19T05:55:37Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1906\" file=\"ntoskrnl.exe\" hash=\"e0a606a2b608a02a71a9b5141ae6baee0b262cb3d4c623261b33fcfe4ef1dbfe\" timestamp=\"0x7f23d60b\" size=\"0x01048000\" added=\"2024-11-24T17:20:19Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1906\" file=\"ntkrla57.exe\" hash=\"98d7975df406c01beb8847e13298ad5297bbe9d001ea403d4f28942558873a95\" timestamp=\"0x7fb8013e\" size=\"0x01041000\" added=\"2025-03-02T06:42:51Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1928\" file=\"ntoskrnl.exe\" hash=\"87d0daa24d4143a602f80f671d49967e3f8c926ff96d0b2b1a6611b518970eaf\" timestamp=\"0x7709f239\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1928\" file=\"ntkrla57.exe\" hash=\"3a1a2238b687480b5dc3fc7b13349b1c4a31a74e7709393ea38d76296cac3fef\" timestamp=\"0xa8e32400\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1972\" file=\"ntoskrnl.exe\" hash=\"98c7da6954f8b86a7803e28ecda028d4d56c771c8778d588172d5e469dd7c362\" timestamp=\"0x4c2abb61\" size=\"0x01048000\" added=\"2025-04-09T14:22:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1972\" file=\"lxcore.sys\" hash=\"c4b851af319e25a587be89cf730f3b84c9ac20c27bd1a0505db6272cf8f7e947\" timestamp=\"0xbfae5af3\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1986\" file=\"lxcore.sys\" hash=\"1d52aa734226c2ed12aec40c8190648c4fccabffbb6cf12e63638f7d8bd74f81\" timestamp=\"0xd100fd04\" size=\"0x00110000\" added=\"2024-11-24T17:20:19Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1992\" file=\"ntoskrnl.exe\" hash=\"536d620bef8b97a765c0c9fee5f9fa5fa79fb5d057b6f6cba03343f538dad29f\" timestamp=\"0x7e11eb00\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.1992\" file=\"ntkrla57.exe\" hash=\"b0134cf7fa969fc8958079e94f29fc7d01319f48efb893ced10fd09090dc4f4c\" timestamp=\"0xabe09d7c\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2048\" file=\"ntoskrnl.exe\" hash=\"e5a9c28a5aff4b4afed46a277d37894ce2852c8830848cf5afb33148bbb78ba9\" timestamp=\"0x236157fe\" size=\"0x01048000\" added=\"2026-03-04T03:13:34Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2050\" file=\"ntoskrnl.exe\" hash=\"c1742de15aa008590eace58e1bc19e7e404384884db59390888a0031a47816d1\" timestamp=\"0x74736de0\" size=\"0x01048000\" added=\"2024-12-24T06:47:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2050\" file=\"ntkrla57.exe\" hash=\"01383d3768b343b37068e72ba6b8a6e068fc94b94e6557c337cb1c91b0e5d801\" timestamp=\"0x0ff14be3\" size=\"0x01041000\" added=\"2024-12-24T06:47:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2070\" file=\"ntoskrnl.exe\" hash=\"62a4980090d5be72a21f07c4295d5cac9e6932cc7d6ba58e833d6b020e757252\" timestamp=\"0xcd7ad3d5\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2070\" file=\"ntkrla57.exe\" hash=\"0ab4fc7a5feccb96fee598eb842957ef4ca942cf081650db39eb693a1be0362a\" timestamp=\"0x60894ebd\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2115\" file=\"ntoskrnl.exe\" hash=\"e1be4d5dbe4b42b2ebdd984b44acacb99c88dc2d27a8693d8007703dedbb5ca8\" timestamp=\"0x8cc230f0\" size=\"0x01048000\" added=\"2025-12-10T04:39:55Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2134\" file=\"ntoskrnl.exe\" hash=\"75101b918e9f9999efef294fa94a318184f7dddb3ea0935fee5b2044cb3d2da1\" timestamp=\"0x69a46399\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2134\" file=\"ntkrla57.exe\" hash=\"6ba81a705c77a8a58e78b77f9e44aaa350c737ada7e15b876f8a589431447b53\" timestamp=\"0x3d1f1933\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2191\" file=\"ntoskrnl.exe\" hash=\"b66e5088118bb94c290b7de00c78604b5dc5dcd8f50bb48095e1b8e9e12a589f\" timestamp=\"0x35faaf05\" size=\"0x01048000\" added=\"2025-10-01T01:37:34Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2191\" file=\"ntkrla57.exe\" hash=\"c4ef7cf53e01bbaf4ba5dadb46c237aa42426125894d90409e5ac0db74542aef\" timestamp=\"0x0199c99a\" size=\"0x01041000\" added=\"2025-10-01T01:37:34Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2215\" file=\"ntoskrnl.exe\" hash=\"9f0ad49c1a2c0c9f822db8262daa059bd0a0319e986902a699d117d281935191\" timestamp=\"0xd697aa93\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2215\" file=\"ntkrla57.exe\" hash=\"43a862019791c8f36ee03293a691e6878d2bc0489e82d01002165d37440beac2\" timestamp=\"0x44551b59\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2271\" file=\"ntoskrnl.exe\" hash=\"9df3012c64a6328fb308992ca30844dc3e638bec7eeccd721b297b9ebb0a6696\" timestamp=\"0x2f7d7c33\" size=\"0x01047000\" added=\"2025-03-11T02:45:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2271\" file=\"ntkrla57.exe\" hash=\"d2de617a31399300d0e0c2d090a29308024ca06ee9a1cf9739e2d22bf0d3181c\" timestamp=\"0x0b04d0b4\" size=\"0x01041000\" added=\"2025-03-11T02:45:33Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2283\" file=\"ntoskrnl.exe\" hash=\"d67c38552062a51eef56013bae30eedd2bae1c357067efb50be18a300860dce4\" timestamp=\"0x8db68818\" size=\"0x01048000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2283\" file=\"ntkrla57.exe\" hash=\"33a3319db3807c71c11712e3482d7a446e882d444f1040ef8b23d86f9652dd3f\" timestamp=\"0x96e1e3e6\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2338\" file=\"ntoskrnl.exe\" hash=\"cd766270e919b8ab4e2cb5a816d49e742e1556ad7f79ee19bfea33e48eb0ac15\" timestamp=\"0xef0d57e5\" size=\"0x01047000\" added=\"2024-11-24T17:20:19Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2361\" file=\"ntoskrnl.exe\" hash=\"ae09a8d4fcfdc9fdafbdb834e671fef5e037aac5b99799037c0d546985873453\" timestamp=\"0xaacd0d1d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2361\" file=\"ntkrla57.exe\" hash=\"c133cebd0985908aebf35ea5a90ecbf01ae08c6cec1d0fca179e857577eb5faf\" timestamp=\"0x75c8c360\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2419\" file=\"ntoskrnl.exe\" hash=\"519979c376bcc3400d83c790602cfb2de2bc8a031fc1a1d70eaf8d6a508cf155\" timestamp=\"0x37351bfe\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2420\" file=\"ntoskrnl.exe\" hash=\"acb10115dc298629badd95a6eade338e98b03e6805ea8bed61f2dd5a2af1a089\" timestamp=\"0xdf757b2c\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2420\" file=\"ntkrla57.exe\" hash=\"aaaebc58d7726eab8af551f814c63577760ccd0db8131da9ec793727641c1d29\" timestamp=\"0x22a9ab9b\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2428\" file=\"ntoskrnl.exe\" hash=\"bf8489d981ea5d73dfb29b883405d68590f2b0b74dc2e9796e35cc1849c56826\" timestamp=\"0x7d02613e\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2428\" file=\"ntkrla57.exe\" hash=\"f636eb14c99644ea1fc5ea87497df5d31667a03e6a32a069d0f495e8f1ba070f\" timestamp=\"0x9abfb4f7\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2483\" file=\"ntoskrnl.exe\" hash=\"bfad341a3eb113a307ccfcb7bad7ca840dfe3f922e50775cd93c40acedf24bc4\" timestamp=\"0xcef5b38f\" size=\"0x01047000\" added=\"2024-10-09T02:21:15Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2483\" file=\"ntkrla57.exe\" hash=\"1d5cfeffde78432289a159259f04452cae1f9f4ba772c63807dceae61ae2f229\" timestamp=\"0x046dd67b\" size=\"0x01041000\" added=\"2024-10-09T02:21:15Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2486\" file=\"ntoskrnl.exe\" hash=\"43c2ba36f2a41abdc9537f22fd2a2c96220c8840e84270c732432496955765d5\" timestamp=\"0x4a7769f1\" size=\"0x01047000\" added=\"2024-12-03T02:17:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2486\" file=\"ntkrla57.exe\" hash=\"a3849193e96aeddef1f7e8aacb3f8cd07eaffe19f327fe2b6b316a0626303be7\" timestamp=\"0x3e8836d9\" size=\"0x01041000\" added=\"2025-11-25T23:06:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2506\" file=\"ntoskrnl.exe\" hash=\"4b954aae4b18a231b2254c0989b1b6bcc55741a8ef90a350f036d09cd480cc99\" timestamp=\"0xb8562c11\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2506\" file=\"ntkrla57.exe\" hash=\"9a172a8db3d0ef87810d1024bfcd41b77ef6de245bd6b7aaaa907f3f2014895b\" timestamp=\"0x2480ef54\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2552\" file=\"ntoskrnl.exe\" hash=\"95e34acea1aa315d4e26962a8db931a8ac434d38b0bfaae2eb74ad68e3df5f8e\" timestamp=\"0xb77a1c24\" size=\"0x01047000\" added=\"2024-11-19T23:19:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2700\" file=\"ntoskrnl.exe\" hash=\"2adc17cccf9a59361c6ac351001af895ca87709a13e8305232fa5d6e99f32149\" timestamp=\"0x0c72f620\" size=\"0x01047000\" added=\"2024-10-04T01:28:54Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2700\" file=\"ntkrla57.exe\" hash=\"e7371f64cf0a0b61253d3c56f6e239770b3a27996d7a31cc0c6b245d707dc5ca\" timestamp=\"0xabae09f1\" size=\"0x01041000\" added=\"2025-04-21T06:14:41Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2715\" file=\"ntoskrnl.exe\" hash=\"dcb872125f963f80b5d31132f1be41139afc62e4b48385236caa60d6d3a3f5f9\" timestamp=\"0x2583840c\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2715\" file=\"ntkrla57.exe\" hash=\"2724d94f35ce8fa0d8857ea4238fdfb6bedfcd2dbe57e71d4047da52983ef6d3\" timestamp=\"0x84b6e318\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2771\" file=\"ntoskrnl.exe\" hash=\"f857667901a367970b643730a420705e30355a8a3a2400a1cd5196a9ee7fbf6d\" timestamp=\"0x2042b9c5\" size=\"0x01047000\" added=\"2024-11-09T04:03:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2771\" file=\"ntkrla57.exe\" hash=\"55f70b76ff34d689c0050e6d2d5443765ab44ca745fe4189ac20be74a2e9a415\" timestamp=\"0xb3eb1e48\" size=\"0x01041000\" added=\"2024-11-09T04:03:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2776\" file=\"ntoskrnl.exe\" hash=\"743c3b8875e49edf797afa43bab20290a2b727c5b86e2c168a62c0157d01344f\" timestamp=\"0x9b981190\" size=\"0x01047000\" added=\"2024-11-09T04:03:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2792\" file=\"ntoskrnl.exe\" hash=\"98831dafa306900ac2b11f23fe69a789f1232127c653f3e01554c339bcb08365\" timestamp=\"0x45e0905d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2792\" file=\"ntkrla57.exe\" hash=\"e98990cf407f9baa3cd303bfe0786cb9ebd114988829e9a2994c2b78eb6412c5\" timestamp=\"0xf07da13a\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2841\" file=\"ntoskrnl.exe\" hash=\"37d97e1b2c50ac3aeee221dd6c55bade4120e6b4928bb6ec79eb658e2614be46\" timestamp=\"0x927f1423\" size=\"0x01047000\" added=\"2025-01-11T02:34:03Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2841\" file=\"ntkrla57.exe\" hash=\"283cef30117f7ea3b6fecfe05e1a820beba5fa34dbdcd95bb6192ddba8e7e64b\" timestamp=\"0x73792e27\" size=\"0x01041000\" added=\"2025-01-11T02:34:03Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2850\" file=\"ntoskrnl.exe\" hash=\"575287b4c0947bbdf672b38ef07b05df0ec38535e1e507ead532da8bc87e5a9b\" timestamp=\"0x9f7b335e\" size=\"0x01047000\" added=\"2025-05-29T05:57:37Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2861\" file=\"ntoskrnl.exe\" hash=\"0ce15480462e9cd3f7cbf2d44d2e393cf5674ee1d69a3459adfa0e913a7a2aeb\" timestamp=\"0x9eee36de\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2861\" file=\"ntkrla57.exe\" hash=\"8744e73e1401bd1d5615b7114c2d004e642622bafc05bf6021fb231e1ba9c65e\" timestamp=\"0xaec2c3e1\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2915\" file=\"ntoskrnl.exe\" hash=\"0d70589c160afe593027fcbb8026c62326dc2069d00d76fbfb050158feff3696\" timestamp=\"0x050e4487\" size=\"0x01047000\" added=\"2024-09-14T02:14:31Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2915\" file=\"ntkrla57.exe\" hash=\"cfbf75e48b9599efc4a4bddb9188d9d28648a4b96a96e2feb9f10c90af871efe\" timestamp=\"0x96110ad1\" size=\"0x01041000\" added=\"2024-09-14T02:14:31Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2921\" file=\"ntoskrnl.exe\" hash=\"aa7a6b50c3a770cbb10a1327eab3a9677a188b84c0d22a4b734f1adabc2d354b\" timestamp=\"0xb5ee37fc\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.2921\" file=\"ntkrla57.exe\" hash=\"11154f3d000b0234c0f20be182a0db45e6a899e794e5145b160aab00cc1ef4f4\" timestamp=\"0x7410915d\" size=\"0x01041000\" added=\"2024-11-13T15:20:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3007\" file=\"ntoskrnl.exe\" hash=\"74e592a94ea0c3324bc2fb3498324a1566b77cf1bb3e8435e90eb7d5450bcac8\" timestamp=\"0x16b96037\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3007\" file=\"ntkrla57.exe\" hash=\"9657be67658c3102c0de18b375738134708a54368d1749eaf912d2dde190873b\" timestamp=\"0x5985d03c\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3061\" file=\"ntoskrnl.exe\" hash=\"4e76230db7e389d4c069ec58501c3b9d3f1f5f15fefba4ae9d611213c15bdf7c\" timestamp=\"0x2f45e31d\" size=\"0x01047000\" added=\"2024-12-22T17:47:47Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3061\" file=\"ntkrla57.exe\" hash=\"4de68045482ba4c85ab5af3845ac3b2a464a64dd905b93a176a9e874a30dd490\" timestamp=\"0x529c2b5f\" size=\"0x01041000\" added=\"2025-08-12T05:13:33Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3066\" file=\"ntoskrnl.exe\" hash=\"854e29db8e426f05d7269fdb2676343e6c8368e2f0a6a77c485006552aed3710\" timestamp=\"0xa6f4171e\" size=\"0x01047000\" added=\"2024-09-12T01:41:06Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3066\" file=\"ntkrla57.exe\" hash=\"88556b04127257fb2a06e49803952d2c682ffd9de0c520f6bb9c1bf393aae583\" timestamp=\"0x9196ce54\" size=\"0x01041000\" added=\"2024-11-19T23:19:13Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3085\" file=\"ntoskrnl.exe\" hash=\"5f1e8f8851a00580d297ff13f12f7463f1a3292df11645db6da3e12c489910d2\" timestamp=\"0x628e5783\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3085\" file=\"ntkrla57.exe\" hash=\"8a797032a7ec7a2c2cb95cbae4929cc00c4624c61c15851139ae056d283167a2\" timestamp=\"0x8a7ed4f7\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3130\" file=\"ntoskrnl.exe\" hash=\"3a6babd7788ee37528336fb18f1eb5baad38a9de4a42f803dd871f76b1eb7fe3\" timestamp=\"0x2653bcc0\" size=\"0x01047000\" added=\"2024-09-12T01:41:07Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3130\" file=\"ntkrla57.exe\" hash=\"0d8403fd5f97a84369d7c9b015266a2d8d173253b737a5d12aeaa18985c3a8f0\" timestamp=\"0xdb842d50\" size=\"0x01041000\" added=\"2024-11-05T01:22:32Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3139\" file=\"ntoskrnl.exe\" hash=\"d4a33dbc5b2dbe28c69e9e9b1dbaba01639cf9bfdce129d3bee4a938d9e2e5ee\" timestamp=\"0x3196807a\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3139\" file=\"ntkrla57.exe\" hash=\"909e9f842d25bde7a2effb54799292186f70a70ff844911c6e4b5a032d0e9213\" timestamp=\"0x3d7f02d8\" size=\"0x01041000\" added=\"2025-02-17T22:56:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3140\" file=\"ntoskrnl.exe\" hash=\"81f83cebb5512b1c9fcef2a5820a595a2604d711da60d91fbe3bb03101bdce33\" timestamp=\"0xc87b1e8c\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3140\" file=\"ntkrla57.exe\" hash=\"784615f8959abbf4df63fc3066c4e460dac606a6437846621b6074be5a6eb53a\" timestamp=\"0x4f916dbf\" size=\"0x01041000\" added=\"2024-11-05T01:22:32Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3155\" file=\"ntoskrnl.exe\" hash=\"34eff4651d8d2305ab77eebc6dbbb94b193fa1d9382d5cab7beb60191a71a982\" timestamp=\"0x6479e1c7\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3155\" file=\"ntkrla57.exe\" hash=\"a5c53d0c3709539f1d28184d0c509008af55a198a7e711b9628231b88edef64c\" timestamp=\"0x8d3148d7\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3209\" file=\"ntoskrnl.exe\" hash=\"8727015620a6b990b8b1efd1485a8fd9ff5dc298bea4d261e798367d9b304ec6\" timestamp=\"0xc70f7561\" size=\"0x01047000\" added=\"2024-11-09T04:03:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3212\" file=\"ntoskrnl.exe\" hash=\"4ac7bb2d1e617e6ba8731235648822aced0a63657fadc9deba1ee07833ec7aa9\" timestamp=\"0xd1c9fc7b\" size=\"0x01047000\" added=\"2025-03-17T02:43:00Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3227\" file=\"ntoskrnl.exe\" hash=\"6644307f4660b714115f0aad40fd9c984024a07501356c2db70b9828d9a2892f\" timestamp=\"0xc053ff9d\" size=\"0x01047000\" added=\"2024-10-29T02:19:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3227\" file=\"ntkrla57.exe\" hash=\"73c3676eb7ffafaf9ecbc4e02b8af9d04236eba136149cac6e56d48a61f36fd4\" timestamp=\"0xcb7f1ff5\" size=\"0x01041000\" added=\"2024-10-29T02:19:33Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3235\" file=\"ntoskrnl.exe\" hash=\"b433fbf64818818fdf8a56f73199410dc55ad3c2d1e191a2faa2d34eeef08f9f\" timestamp=\"0x8b489b4d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3235\" file=\"ntkrla57.exe\" hash=\"3e369c6f45ab54daf4269863dcbec5ccf4ba609d956f79e56342c2b322d8bbd2\" timestamp=\"0x5a4ecbb0\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3276\" file=\"ntoskrnl.exe\" hash=\"c73564dda4c9a55ef8c21a4506854e34f850d0e8327083f9657e6123f485b203\" timestamp=\"0x38af3aa3\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3276\" file=\"ntkrla57.exe\" hash=\"0496fde92180eaa787d4c2ea8cb3a2038c45c9a297562712e078d053eddcf0e9\" timestamp=\"0x40aeef6a\" size=\"0x01041000\" added=\"2025-06-07T14:16:57Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3286\" file=\"ntoskrnl.exe\" hash=\"18a1f09807a8643b44deca40310396c3ee03e68d44eeb96a492ae9813853ada3\" timestamp=\"0x7757bcca\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3286\" file=\"ntkrla57.exe\" hash=\"c569f2668a56a40d852495b51d05c4108910261c94a88e867c4126d0b3327f56\" timestamp=\"0xadac9fd6\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3296\" file=\"ntoskrnl.exe\" hash=\"52d860c99bd4fbf53994dad9cf8be727c8e08db1a3074eb5cd4d39bbc3974ca0\" timestamp=\"0x4a478977\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3296\" file=\"ntkrla57.exe\" hash=\"95d23e60fec96ec26e6bdd1a271fe797db6156ae79964390b70a77bf4a4f6d28\" timestamp=\"0xdd1d8b7d\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3350\" file=\"ntoskrnl.exe\" hash=\"7fedb64a728452f05e7a53755362dc40f305916363319b3e012d4329f1ec5a2e\" timestamp=\"0x9a86a43d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3350\" file=\"ntkrla57.exe\" hash=\"5a63730abc7bb153e1b912d2d81142759b54d5e34bbca0981cdd58de38defa64\" timestamp=\"0xe498b220\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3374\" file=\"ntoskrnl.exe\" hash=\"41ee592fe253caf442c7b162cbc70a08fab284fce47fd07d301f5a46b29e82e0\" timestamp=\"0x17a0ab34\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3374\" file=\"ntkrla57.exe\" hash=\"d95c2a525714aa1d233e18f6eced25cc1357799f9417d22a18fd826fe420fe3b\" timestamp=\"0x8d49c63b\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3420\" file=\"ntoskrnl.exe\" hash=\"649fcc524a5aad7a25ffe7f5ccf045efee3ad8511ce666ef7081b3c597a7de18\" timestamp=\"0x90894dfe\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3420\" file=\"ntkrla57.exe\" hash=\"d44711a46fcddfe47c25710e9a1d53c722cae16b646daf16a14bb9bfbe5d8a3f\" timestamp=\"0xd6279ae5\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3420\" file=\"lxcore.sys\" hash=\"9161309a4f2d55c003145c5a97c06576b668de1a2961c28098141d7ceb7099e8\" timestamp=\"0x4f53563f\" size=\"0x00110000\" added=\"2024-12-03T02:17:28Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3430\" file=\"ntoskrnl.exe\" hash=\"58cce5a055ee03def3f587468f82ad6bc0e16757d6c9d9ff41b50f1ec5a93376\" timestamp=\"0x704dc952\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3430\" file=\"ntkrla57.exe\" hash=\"3e4e558e7deb55929da73b89882478aa47e6709c5d0b3dd159d08472b23dd6d9\" timestamp=\"0x377e8689\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3447\" file=\"ntoskrnl.exe\" hash=\"a6b0411ff311e6b7ee93960dec3730edf444bdea26bdf82b12bd9844c9b781a8\" timestamp=\"0xec7c6578\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3447\" file=\"ntkrla57.exe\" hash=\"64d50b4a87210e2775fe06b65bbd4e4803bd06a7a9ddc7941624a34403b5c172\" timestamp=\"0x0e653f0f\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3495\" file=\"ntoskrnl.exe\" hash=\"9a401a451d99dd9d3bdc88eaad5070280b7a6790d47905cd24e1508bb6573cf9\" timestamp=\"0x51d6182d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3495\" file=\"ntkrla57.exe\" hash=\"4736897f39e3934ab2fac84d0b80144970103fbaa71205eb3fa2c3781c8dc028\" timestamp=\"0x15eac6de\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3500\" file=\"ntoskrnl.exe\" hash=\"34fbf6441f4f7833b9c8ab59af2dd169d1e8709fabf8ce93792660aa126aef88\" timestamp=\"0xb482761d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3500\" file=\"ntkrla57.exe\" hash=\"c70fc8405d3eb89602f628834399139a431951d9635de6d338e44a3377a04781\" timestamp=\"0x3e3feb21\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3527\" file=\"ntoskrnl.exe\" hash=\"d5c53140c2675b49e2d972d96f6d5c4e0b219b46c61e6222586dd2f4bd202616\" timestamp=\"0x5fedb443\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3527\" file=\"ntkrla57.exe\" hash=\"98eb46e2747332aa0b95482cbc7eac18b5437f51822101af067bbbcd33f4c26c\" timestamp=\"0xb7a37700\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3566\" file=\"ntoskrnl.exe\" hash=\"49173360abf77dae498a547011fa5f919e88997e403600897f46aef66ceb15c4\" timestamp=\"0x3fac617f\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3566\" file=\"ntkrla57.exe\" hash=\"337afeafa13b8c78333c39c8d57d0971d0a1216a1f0203a9f195a725cac868b9\" timestamp=\"0x194f8264\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3570\" file=\"ntoskrnl.exe\" hash=\"0832d17ed3fa071aa367e83aeaee0328e42b8e1e9d1e383ed99f839821a6aa04\" timestamp=\"0x9d29a281\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3570\" file=\"ntkrla57.exe\" hash=\"d98b4f713ccd8cbc48189ded64745fd9e1da9e4ce0d50d54aa285b5e8b872b26\" timestamp=\"0x614c9538\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3570\" file=\"lxcore.sys\" hash=\"9aaf8da135c564b629e4eb0628a86fd231c38b55b8cfb33a8e790f6d3e2436d3\" timestamp=\"0x0648faab\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3575\" file=\"ntoskrnl.exe\" hash=\"8e0deb787c6dbc622d21a83f6987bb2629d71af0bda8035c57dbdf116d9563d6\" timestamp=\"0x13dc6b19\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3575\" file=\"ntkrla57.exe\" hash=\"a518b9e52a5c4d0f24c09310731e670fc73aac39d6caec8363a0a47ad7d9567b\" timestamp=\"0xe24114a9\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3593\" file=\"ntoskrnl.exe\" hash=\"fb95e5d14eab68e3b5a9ec998b08fd4cd15d73c3d422d78fe97e75e6d8e021b6\" timestamp=\"0x8a3a5a16\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3593\" file=\"ntkrla57.exe\" hash=\"0c9eecc746fbbe0117b2297b106f76365249e0d429e034619a098faf63a6e821\" timestamp=\"0x403be31e\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3640\" file=\"ntoskrnl.exe\" hash=\"5f2daf71acf4fe543809d1e5a329a5513e49074b5772d92b194045f48fbf2b9e\" timestamp=\"0x7877cc6b\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3640\" file=\"ntkrla57.exe\" hash=\"c914b05203a3515ae37991d2a197a41987def9c96be25c1b29063783273a003b\" timestamp=\"0x06af686e\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3640\" file=\"lxcore.sys\" hash=\"935957997ba6288df5055974716bd9dd370f5d366fb5a569e1dbccc398418be0\" timestamp=\"0x359fe623\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3646\" file=\"ntoskrnl.exe\" hash=\"4e9bd7c711dad2d4774f2026609077e2bc693c7a71ae24c34e74ce2f7d7e9bb4\" timestamp=\"0xbe33e6ff\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3646\" file=\"ntkrla57.exe\" hash=\"de6be7b92da72fb209446198b28139541d09eba3f9a726e0dd47591407d4cb10\" timestamp=\"0xd3521970\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3672\" file=\"ntoskrnl.exe\" hash=\"abf6854325023ec00811fb44f6abc7a00d2af5e17171ad9a7339ca3e8d75f81d\" timestamp=\"0xce6b5ad2\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3672\" file=\"ntkrla57.exe\" hash=\"eaecd5ebd6e6be5ae913eac0ff146e086c143e4e7c591f722edcadcd409aa086\" timestamp=\"0xfbf65d8d\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3672\" file=\"lxcore.sys\" hash=\"47dbd308fc59d733e8f8a11427db9c6d23f4941e5d478c023d171f76e34d4f25\" timestamp=\"0xef868c5c\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3720\" file=\"ntoskrnl.exe\" hash=\"b68f69c4745e5240080be96efaae062b6ab253f0642c3f51b0b47bfaecec8532\" timestamp=\"0xd00225ae\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3720\" file=\"ntkrla57.exe\" hash=\"a5cf02980e83655d8d93129b44f3910f1d4bbd74c7c59e591fb00503747c45c3\" timestamp=\"0x274d53e8\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3733\" file=\"ntoskrnl.exe\" hash=\"d2c63f71382ab464c9b243e4f19f123fb4b44917468ddb6928a57f90fe94664a\" timestamp=\"0x3f260e72\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3733\" file=\"ntkrla57.exe\" hash=\"05b3446737ba46b9e2cc63e7ee290996e7e4c03bae37a2c3c9c310f1940bbe3b\" timestamp=\"0xd75ba658\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3785\" file=\"ntoskrnl.exe\" hash=\"abb3d488854794e0601f5e40c1bc83ddd2a6929b8fb0fa839385135bea45e161\" timestamp=\"0x235b4194\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3785\" file=\"ntkrla57.exe\" hash=\"7d561f4283c660fefb80bd3e08a6281d2263ac9473225c1e7631b76e5cfc78f3\" timestamp=\"0x5d5f03fa\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3790\" file=\"ntoskrnl.exe\" hash=\"f1afdfc8f4551ff62586a93e1d828b0ea613bed70b5a1f6783885fba71e5720f\" timestamp=\"0x08b1c19d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3790\" file=\"ntkrla57.exe\" hash=\"e047cca83754d55566f6022e71a61a25e1a1f28924e6035118e7d12a89831f0b\" timestamp=\"0xca092f4e\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3810\" file=\"ntoskrnl.exe\" hash=\"1c8fc096b11da9cdc7d44d8c7aca7a555548c4b87a6797efa3e815c3656aee83\" timestamp=\"0x72a0b503\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3810\" file=\"ntkrla57.exe\" hash=\"0c2df2403e9dffb40710b856bffef1859612cab06a846bab2513a5de0a7d46f5\" timestamp=\"0xf2b6a3f6\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3858\" file=\"ntoskrnl.exe\" hash=\"cb2f1317ae1ed775200ae8fe224b1f02998b63557d5248251f5a224443d746ba\" timestamp=\"0xa45cad29\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3858\" file=\"ntkrla57.exe\" hash=\"3edf33cdb82ae6b2f953708969101252424352798ad9df587127e20504953d0a\" timestamp=\"0xe75a4e33\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3880\" file=\"ntoskrnl.exe\" hash=\"ff790c868e0522fa314676664b6343954de8ed6225c420e565ea3f8fe3957043\" timestamp=\"0x6b71a188\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3880\" file=\"ntkrla57.exe\" hash=\"0a82ed43035dce1e5f64701f9d89f3cfd8d89239f60946ec88dab1f9255d3bf3\" timestamp=\"0x11828aaa\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3930\" file=\"ntoskrnl.exe\" hash=\"1c0643dbc1e34293f10a5fc3b1dfdbe5f566ad73559237327f44b94b162a808a\" timestamp=\"0x36ee861d\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3930\" file=\"ntkrla57.exe\" hash=\"1e7575e227f5759526f9da82b4283e7f3ce69c95b0f0dcfb1a8c76ddeb825974\" timestamp=\"0x75bc66e5\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3936\" file=\"ntoskrnl.exe\" hash=\"04270482526a4d4ac4029bb09cad9b8752814d6b3f35f8c3b1a1c75c50da2a69\" timestamp=\"0x1ac9a52f\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3936\" file=\"ntkrla57.exe\" hash=\"61079ba605e584d70c9837a1fcd1b6e054443e6d3335949ccadb2967d8467d6c\" timestamp=\"0xc4a186f3\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3958\" file=\"ntoskrnl.exe\" hash=\"6eadc85aef8bc4693ffeb2ae2dec09f01bae883e1e596a0236fcc8f789e8170e\" timestamp=\"0x6067c301\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3958\" file=\"ntkrla57.exe\" hash=\"54395eca327703105965723242f2fba36e5cf9c0846eafc015b038de98fc70a5\" timestamp=\"0x4c08a76a\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.3958\" file=\"lxcore.sys\" hash=\"3d468c032301d974a5179b42ae05975efb3808b49c2f5a70afb3ce012bc1093d\" timestamp=\"0x19973222\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4000\" file=\"ntoskrnl.exe\" hash=\"b8be7d57fd18e06626354b2f20bd5cd30a136e7a41191fd4a6b56f361beaaef7\" timestamp=\"0x484a5d68\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4000\" file=\"ntkrla57.exe\" hash=\"40fc4b18af9fed193035dac70339805799011118a28c30ac5831ad94a59e3d9a\" timestamp=\"0x4f1bef4f\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4005\" file=\"ntoskrnl.exe\" hash=\"91d61c3813f0d2269b0d00c133219b538cd9e72d78e80ffe26e8289628fae1fb\" timestamp=\"0x7fc67943\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4005\" file=\"ntkrla57.exe\" hash=\"c967932c3550110d56639f733bf2c40d9840343bab7cd4e098db3c01f214d046\" timestamp=\"0x9564f228\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4010\" file=\"ntoskrnl.exe\" hash=\"8c0e21ccca1a1a401f95ec85eff99d07df4657a2e7a2b19cd43e48936a3d0dd1\" timestamp=\"0x2dc56846\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4010\" file=\"ntkrla57.exe\" hash=\"dde9ef775be3d5dd26566301954dd73c08a3d4d6b6cf9e34bef5826b0edd18a8\" timestamp=\"0x98db67ee\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4036\" file=\"ntoskrnl.exe\" hash=\"e40b74571521d1f63d387ae441b3296e505a29550be75c770851832f064d2f40\" timestamp=\"0x459790e2\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4076\" file=\"ntoskrnl.exe\" hash=\"9ea82f63e2f35c0d775394bfcdb65dc77ecac0308e04e7ec5097c2b03a66d1ff\" timestamp=\"0xce648c93\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4076\" file=\"ntkrla57.exe\" hash=\"1b35459add2ca4a000bb94f07c1460096cedf1d6eefe8ca095918d37dfb7de29\" timestamp=\"0x48fb4ad7\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4082\" file=\"ntoskrnl.exe\" hash=\"ae5753a1e7d3878dfcd3f44d31fa506114279ad067fd5890915c51514947e8e1\" timestamp=\"0xcbcf90fc\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4082\" file=\"ntkrla57.exe\" hash=\"7c60445cd4f6b7edad8abd7ca8af5dc990e82df07e28d4c417cf4f3aa37ef17b\" timestamp=\"0x6ef27744\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4111\" file=\"ntoskrnl.exe\" hash=\"78ee32fd777f0bc53c2e1977270cea3d6d6b0bbdb95a8e2be9473b12d10e1996\" timestamp=\"0xa43e28fc\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4145\" file=\"ntoskrnl.exe\" hash=\"9805f5858a91f33238df6ef778baa700c38377779ecd417bd16de345ab091e50\" timestamp=\"0x38dc860a\" size=\"0x01047000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4145\" file=\"ntkrla57.exe\" hash=\"a55286c14bf1a8e65749f564455f114cc6f9ddac993cc820ce49902b27247eb5\" timestamp=\"0xa0e793b2\" size=\"0x01041000\" added=\"2024-09-12T01:41:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4169\" file=\"ntoskrnl.exe\" hash=\"f7970a8c13be1b35a093eeffec1e4c8aa8271d5bd8a9a1802aa849e95b635d79\" timestamp=\"0x64bc9991\" size=\"0x01047000\" added=\"2024-09-12T01:41:07Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4169\" file=\"ntkrla57.exe\" hash=\"f83fa9e45bb4bb7c877e68bc0fcbdc996fc89d3a8bdf62345ced1362da89d46b\" timestamp=\"0x3663c86a\" size=\"0x01041000\" added=\"2024-09-12T01:41:07Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4225\" file=\"ntoskrnl.exe\" hash=\"d75cd521e742dc670f3f9b8c132d6de4f1f515286127d05317ae0fd0c46bc0e4\" timestamp=\"0x362cb253\" size=\"0x01047000\" added=\"2024-09-21T19:30:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4225\" file=\"ntkrla57.exe\" hash=\"0690437ce7a36de0e24a4c12931c2a0d7663a6d44c3fbfa357c65d5fc1f53529\" timestamp=\"0x7d73eb15\" size=\"0x01041000\" added=\"2024-09-21T19:30:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4225\" file=\"lxcore.sys\" hash=\"0d0107efe823c858244b9e62ef81a66b6e0e799f5a95e2908b78ca3ab8f691f9\" timestamp=\"0x88b4a4f5\" size=\"0x00110000\" added=\"2024-09-21T19:30:35Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4249\" file=\"ntoskrnl.exe\" hash=\"989e9b2a1691dd36412936ce23999acd1b100092f0b352b551f0cb4ac27ca80d\" timestamp=\"0xeb80676f\" size=\"0x01047000\" added=\"2024-09-27T22:22:02Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4249\" file=\"ntkrla57.exe\" hash=\"4d5e5a3be5af2780c644b9709b894018a87ac5809fa8a6b28e78f5b55750d071\" timestamp=\"0x423dd412\" size=\"0x01041000\" added=\"2024-09-27T22:22:02Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4291\" file=\"ntoskrnl.exe\" hash=\"66cbe4df3c8369618ab6af28f476aa1ae06c718e5ff60578a09649edd14b718a\" timestamp=\"0x53263d09\" size=\"0x01047000\" added=\"2024-10-01T23:04:59Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4291\" file=\"ntkrla57.exe\" hash=\"294ea9611ee7163009e8ba2eb4ce7a91d6bfb9380f4d52c4fcfa1de61c132416\" timestamp=\"0x895a750f\" size=\"0x01041000\" added=\"2024-10-01T23:04:59Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4300\" file=\"ntoskrnl.exe\" hash=\"31a81777e2d8f16d584d16bf5041e621a0b93a3d046e5b25e78690937606b376\" timestamp=\"0x41100d5c\" size=\"0x01047000\" added=\"2024-10-04T23:07:12Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4300\" file=\"ntkrla57.exe\" hash=\"c8467767bf73d0e4dd2e1c014357a270a152d4735ef4678f8e7355edf31c6d60\" timestamp=\"0x4854a4ed\" size=\"0x01041000\" added=\"2024-10-06T07:32:47Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4317\" file=\"ntoskrnl.exe\" hash=\"8214b4f98d1e18df604bf2a9ed0cb3c6c4df062a95181964e3da5e359cca4008\" timestamp=\"0x2c33c508\" size=\"0x01047000\" added=\"2024-10-09T02:21:15Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4317\" file=\"ntkrla57.exe\" hash=\"92605ec7357fea654106662d3c8cb0c5d0675a64a4066df4151e14be5701b44c\" timestamp=\"0x7243be9d\" size=\"0x01041000\" added=\"2024-10-09T02:21:15Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4367\" file=\"ntoskrnl.exe\" hash=\"52c0d1ee0f64002080fa74d5ceaef24272304216ce2c498661e0d7eaa054eb5a\" timestamp=\"0xd36decf0\" size=\"0x01047000\" added=\"2024-10-13T16:15:06Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4367\" file=\"ntkrla57.exe\" hash=\"28bc1e23b02708f5b224d145c302706d88f96a5a167ff7fc3bded00ce9655132\" timestamp=\"0xd4cec65d\" size=\"0x01041000\" added=\"2024-10-13T16:15:06Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4371\" file=\"ntoskrnl.exe\" hash=\"27cc6773e0994b77fa8621c08541c05194333c4b02152c515a62b1e3619f1e26\" timestamp=\"0xdf1e79ab\" size=\"0x01047000\" added=\"2024-10-19T15:36:45Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4371\" file=\"ntkrla57.exe\" hash=\"76d83f056c897d58b6d129992387af35e5075b0fea6c7a1a5bbc33ac656847a0\" timestamp=\"0xe21e4e4d\" size=\"0x01041000\" added=\"2024-10-19T15:36:45Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4387\" file=\"ntoskrnl.exe\" hash=\"b8bf39580cc7531f74c14a00c47644120c29ead6ba8c71cd9104080a5d508d7b\" timestamp=\"0x7560f114\" size=\"0x01047000\" added=\"2024-11-09T04:03:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4391\" file=\"ntoskrnl.exe\" hash=\"9ecbf0b5046d2e4ced289fcf41c5b0b4e54efd2f3084c8c0edcf10a5653e9109\" timestamp=\"0xd0f711f3\" size=\"0x01047000\" added=\"2024-10-23T02:12:58Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4391\" file=\"ntkrla57.exe\" hash=\"c3178469da08cb35493aa52f567995c59561808b86d0955c4dc22c9f3a186497\" timestamp=\"0x1e0631eb\" size=\"0x01041000\" added=\"2024-10-23T02:12:58Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4435\" file=\"ntoskrnl.exe\" hash=\"11eded38946156925d7ba898751a590087c7aefe08bdded89cb9896806011946\" timestamp=\"0x08f2fddd\" size=\"0x01047000\" added=\"2024-10-26T06:39:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4435\" file=\"ntkrla57.exe\" hash=\"89a78c23b2b171937544c980cfc8f66b4bf3a2436d6c86761f8db5e847c31fa6\" timestamp=\"0xe581dccc\" size=\"0x01041000\" added=\"2024-10-26T06:39:10Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4440\" file=\"ntoskrnl.exe\" hash=\"59cd940609a9a9f023d655c9694262a0a5a1f1073aaa66be0144805508069dff\" timestamp=\"0xe96b293f\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4440\" file=\"ntkrla57.exe\" hash=\"f2f23d2f7a971f9bbc843500132ddda6765d40b89fc4c586260623dcc92543d7\" timestamp=\"0x8c9016cf\" size=\"0x01041000\" added=\"2024-11-05T01:22:32Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4445\" file=\"ntoskrnl.exe\" hash=\"b9680ccf26184f5269c10624689cba1c2987f5c0af1d22dffc45d31884106414\" timestamp=\"0x14542194\" size=\"0x01047000\" added=\"2024-11-10T00:28:44Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4445\" file=\"ntkrla57.exe\" hash=\"d893510c49df072e14d625ff23c68df9b0a2c6dcc9b23ab82e74978b96c7bf8a\" timestamp=\"0xa6c9fee7\" size=\"0x01041000\" added=\"2024-11-10T00:28:44Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4455\" file=\"ntoskrnl.exe\" hash=\"999c51d12cdf17a57054068d909e88e1587a9a715f15e0de9e32f4aa4875c473\" timestamp=\"0xd17ee503\" size=\"0x01047000\" added=\"2024-11-13T15:20:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4455\" file=\"ntkrla57.exe\" hash=\"bb9b19cfd4998364a76b6727bf4a32b10039a43cabd1674b76ef8dde0e38f5c8\" timestamp=\"0x0aa34024\" size=\"0x01041000\" added=\"2024-11-13T15:20:35Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4510\" file=\"ntoskrnl.exe\" hash=\"5085d964c9a1b0dfc2323bd24780d6ab5c794a9623968660193d625fec3f98ce\" timestamp=\"0xcd703981\" size=\"0x01047000\" added=\"2024-11-16T00:53:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4510\" file=\"ntkrla57.exe\" hash=\"7056586426aa77e3dec3aabf3e55ddbcacac17ed832af63467828d89bdec9dbb\" timestamp=\"0x7cec76cd\" size=\"0x01041000\" added=\"2024-11-16T00:53:13Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4515\" file=\"ntoskrnl.exe\" hash=\"6cb8f40b1a15a023c215f0dbad6b620d965978136f8b9a17f7538d37c867389a\" timestamp=\"0x16a281e5\" size=\"0x01047000\" added=\"2024-11-24T17:20:19Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4515\" file=\"ntkrla57.exe\" hash=\"b8f0e4f134a8a2c44299dd20b4c0402e2db7c2ac33edb56f2b1cfcf8fa6ee2a5\" timestamp=\"0x6c8292b4\" size=\"0x01041000\" added=\"2024-11-24T17:20:19Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4541\" file=\"ntoskrnl.exe\" hash=\"61b9596eae4484650cbc8fd0add025624074eeb2f89167c369c0cf09d36b7aee\" timestamp=\"0x95494f9c\" size=\"0x01047000\" added=\"2024-11-21T19:38:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4541\" file=\"ntkrla57.exe\" hash=\"7acf1f634fcfe44d64eca9c44b875a5a126724bfedbcb7393ce2844af762836b\" timestamp=\"0x3953b760\" size=\"0x01041000\" added=\"2024-11-21T19:38:04Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4580\" file=\"ntoskrnl.exe\" hash=\"7fb0556f7933a392c355c5663e48ef57e5192fe5fa45eb55ec70d574a1b86517\" timestamp=\"0x2108cdc2\" size=\"0x01047000\" added=\"2024-12-10T02:56:39Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4580\" file=\"ntkrla57.exe\" hash=\"cf96f5046e0bc8b40a1ca366b514af2fca037cca1531cc5d80d92a4d08f08c63\" timestamp=\"0x929737bf\" size=\"0x01041000\" added=\"2024-12-10T02:56:39Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4601\" file=\"ntoskrnl.exe\" hash=\"ab8ee9b6ed2670d5ceee6bde0a52a79e1c3c2e376bee2d17e7bedc84947d0ebe\" timestamp=\"0x3abd2e6d\" size=\"0x01047000\" added=\"2024-12-11T14:53:46Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4601\" file=\"ntkrla57.exe\" hash=\"dc5ec2787e95c31de5cda17b210d784158da002a41f4558c123ebdfde63774c6\" timestamp=\"0xf5b4b219\" size=\"0x01041000\" added=\"2024-12-11T14:53:46Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4655\" file=\"ntoskrnl.exe\" hash=\"5f9152bafe647cc2978f976c213f1ce5ffcfa36e6cee47834edb0122f65ff159\" timestamp=\"0x84b512c7\" size=\"0x01047000\" added=\"2024-12-16T15:35:11Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4655\" file=\"ntkrla57.exe\" hash=\"2385a1c9d71ea6cc4a5f519bd88bed254cf7d3621a806df626f0b27ec56a11c0\" timestamp=\"0x8ddc3531\" size=\"0x01041000\" added=\"2024-12-16T15:35:11Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4660\" file=\"ntoskrnl.exe\" hash=\"aee8729155568493776dd40c30e327baa3a4924a30389f40c2d46a7b3a1e8a3a\" timestamp=\"0x7706c11e\" size=\"0x01047000\" added=\"2025-01-04T05:49:38Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4660\" file=\"ntkrla57.exe\" hash=\"67d4e849753b8e65cd67d83244368b6bf07d47ac8242cd5ddc0425ed99977200\" timestamp=\"0x84da48f7\" size=\"0x01041000\" added=\"2025-01-04T05:49:38Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4746\" file=\"ntoskrnl.exe\" hash=\"28a9531362a74cb16a02574f28606a1eb84c6524749c1c7f70029e533be759a4\" timestamp=\"0xe10f791c\" size=\"0x01047000\" added=\"2025-01-15T01:55:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4746\" file=\"ntkrla57.exe\" hash=\"21fa9be43aaa716043175fcab5898a9086cad95a36ef5440d8dd3ab6d5d95795\" timestamp=\"0xbc07165c\" size=\"0x01041000\" added=\"2025-01-15T01:55:10Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4800\" file=\"ntoskrnl.exe\" hash=\"2fc094c95ebc11a344b109d8c526a0b018c30de97b36a3fa838d33289dd228c0\" timestamp=\"0x077f7b12\" size=\"0x01047000\" added=\"2025-01-18T23:48:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4800\" file=\"ntkrla57.exe\" hash=\"ce955d207c2f0674ddd93ff7b51bfff6cbcffb9ec5593f4d47fdbf1b95a343b6\" timestamp=\"0x1700811e\" size=\"0x01041000\" added=\"2025-01-18T23:48:32Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4805\" file=\"ntoskrnl.exe\" hash=\"44bcda2627d859f26cd05074fbe8b94a21e76bde0eb8f8670d6653b8941d0c01\" timestamp=\"0x388c8283\" size=\"0x01047000\" added=\"2025-01-25T15:27:45Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4805\" file=\"ntkrla57.exe\" hash=\"c1691f54a62c40db672835e166d4a0e3bc52db30ee1405b8723b58f78f9cad08\" timestamp=\"0xddd07f35\" size=\"0x01041000\" added=\"2025-01-25T15:27:45Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4825\" file=\"ntoskrnl.exe\" hash=\"a3a3f511d2101744ca9c494c0301c9582ff68aad9e692efd4ed05a807335ff01\" timestamp=\"0x62c46e65\" size=\"0x01047000\" added=\"2025-01-31T00:35:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4825\" file=\"ntkrla57.exe\" hash=\"f0b7d047427a4e06653ea17a4fb462ce2fe0928c70e3f0b5d7ac1651ef034f48\" timestamp=\"0x06e72409\" size=\"0x01041000\" added=\"2025-01-31T00:35:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4830\" file=\"ntoskrnl.exe\" hash=\"1f0d199f3cf1e72ab1e1571e06d1692dbcb8a36d2d86e39a426c2b7f0f2c0aa6\" timestamp=\"0xe994be4a\" size=\"0x01047000\" added=\"2025-01-31T00:35:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4830\" file=\"ntkrla57.exe\" hash=\"588f82fcd0a0d16d938894f6d4e6a0d17e306928cbc18b5c40d76ce0fbf42078\" timestamp=\"0x203a970f\" size=\"0x01041000\" added=\"2025-01-31T00:35:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4870\" file=\"ntoskrnl.exe\" hash=\"181fee20e4c4dae9e2301abb528de96e655429e7d6354dbf0dfeb61be38798a6\" timestamp=\"0x22316f2c\" size=\"0x01047000\" added=\"2025-02-06T01:33:17Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4870\" file=\"ntkrla57.exe\" hash=\"8fa63fe8e8b4088de7c922c1c6c9385e270cda9b846ee3c526d01cc108f05bda\" timestamp=\"0x69de6e14\" size=\"0x01041000\" added=\"2025-02-06T01:33:17Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4880\" file=\"ntoskrnl.exe\" hash=\"e073b8b7a8ad6598387fadfc045e799bb7a5dbc0973e6d0fd903a04d32094b72\" timestamp=\"0x81be0264\" size=\"0x01047000\" added=\"2025-02-09T01:52:18Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4880\" file=\"ntkrla57.exe\" hash=\"56592f2f51445befbabb1cdf8391c5cf2d7ad6a9e127c67ade7bb05c9ebd74a2\" timestamp=\"0x64185dfd\" size=\"0x01041000\" added=\"2025-02-09T01:52:18Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4890\" file=\"ntoskrnl.exe\" hash=\"b94103a049acde9fec25d8e66c5f0a844c1fc53f197ba10724ec141345c4dd57\" timestamp=\"0x49fb35f7\" size=\"0x01047000\" added=\"2025-02-12T06:18:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4890\" file=\"ntkrla57.exe\" hash=\"1fe8c9df96e8288915c9db0502afbd38ed1a06e78a50e6719161f6177f3d2084\" timestamp=\"0xeb7b3e5d\" size=\"0x01041000\" added=\"2025-02-12T06:18:33Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4945\" file=\"ntoskrnl.exe\" hash=\"988ff2107ee137ee0216b070fe975745317b501ab0324652f1f7db4dfc24c43b\" timestamp=\"0xfb248197\" size=\"0x01047000\" added=\"2025-02-15T17:18:17Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4945\" file=\"ntkrla57.exe\" hash=\"69e02180b3e5f784b82a743ec0debee76c79ceabf6ae8dadeb50c316d63f4c47\" timestamp=\"0x198ae273\" size=\"0x01041000\" added=\"2025-02-15T17:18:17Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4950\" file=\"ntoskrnl.exe\" hash=\"b37e9638241faccde7cb8333dfd251641213c0570029489a843f5fc399a29227\" timestamp=\"0x2e4841c6\" size=\"0x01047000\" added=\"2025-02-22T16:10:41Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4950\" file=\"ntkrla57.exe\" hash=\"c4bed79f3c4df2e0a7117d7bbfcee1ae59bc6938c3616248a6a7992c9819fe55\" timestamp=\"0xe0701480\" size=\"0x01041000\" added=\"2025-02-22T16:10:41Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4974\" file=\"ntoskrnl.exe\" hash=\"985305c5a4e418f3f99f136ba7672d900f684de75021b3f0971df3b623c30f8c\" timestamp=\"0xa7cba442\" size=\"0x01047000\" added=\"2025-02-26T02:04:23Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.4974\" file=\"ntkrla57.exe\" hash=\"0dd84014568c3f2dc1fe8b46b59bf5cc9c0a2886e64cd99445d9362ce1ec1966\" timestamp=\"0xb3d9eb93\" size=\"0x01041000\" added=\"2025-02-26T02:04:23Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5015\" file=\"ntoskrnl.exe\" hash=\"20fc5469978c5c7ddcd30caca5970bb3225ef1a2f5f19fc571c8f3f8fa13b356\" timestamp=\"0xff1b4ae6\" size=\"0x01047000\" added=\"2025-03-02T06:42:51Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5015\" file=\"ntkrla57.exe\" hash=\"a61c24d29207deb75f20f1543dd7b6915feefb3324649cefb9d6540427b6030e\" timestamp=\"0xec60290e\" size=\"0x01041000\" added=\"2025-03-02T06:42:51Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5025\" file=\"ntoskrnl.exe\" hash=\"bb838ed108319131bff9accc40917f4974acc91f1fbb92acc622f40adb5f716b\" timestamp=\"0xe5abee67\" size=\"0x01047000\" added=\"2025-03-11T02:45:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5025\" file=\"ntkrla57.exe\" hash=\"4a9c9907d134191dafdf4bd4aebde5e213965bc10d6f8f587b521cca7fc6faaa\" timestamp=\"0x09e368a3\" size=\"0x01041000\" added=\"2025-03-11T02:45:33Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5037\" file=\"ntoskrnl.exe\" hash=\"cad22ccf5189f55a2dc91cb7abc3f18a638a318d5cc7629aa14f676c3568d77b\" timestamp=\"0x098d7ab1\" size=\"0x01047000\" added=\"2025-03-11T22:25:17Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5037\" file=\"ntkrla57.exe\" hash=\"4442be1d6d9ae1d61f6764421a75a0333e3063125db4d75c81f113e5f6e1bd67\" timestamp=\"0x7860cb71\" size=\"0x01041000\" added=\"2025-03-11T22:25:17Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5090\" file=\"ntoskrnl.exe\" hash=\"7970d67d2d61597c46ca34f063e432c90dca40ad01f0cfc75fd599ff82998691\" timestamp=\"0x9c298898\" size=\"0x01047000\" added=\"2025-03-19T05:55:37Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5090\" file=\"ntkrla57.exe\" hash=\"9a85923cb440836f341c1e648f917a534e9ae31bea4f20cfcb29d9c8bcdb2730\" timestamp=\"0xcd5b482a\" size=\"0x01041000\" added=\"2025-03-19T05:55:37Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5097\" file=\"ntoskrnl.exe\" hash=\"252626ae1e2e173a8bbfcab9c2556964127c6de5caf6855939888ac4afde9b4b\" timestamp=\"0xa1d0936e\" size=\"0x01047000\" added=\"2025-03-23T17:06:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5097\" file=\"ntkrla57.exe\" hash=\"45e9c7abd888da3b63cba3b6e7a2c4d2a0c9124f17670a92a4783d384403eee6\" timestamp=\"0xcb73253c\" size=\"0x01041000\" added=\"2025-03-23T17:06:04Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5124\" file=\"ntoskrnl.exe\" hash=\"d27836dc2f6b6eaabb3ff3da845842eb3f60d98b940a27ac1f2567d12cdc829f\" timestamp=\"0x1b10d63a\" size=\"0x01047000\" added=\"2025-03-28T03:59:19Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5124\" file=\"ntkrla57.exe\" hash=\"9cfb3075f092d25c8c7168ddfa604df858ef1f0f86df51f95ca68801d652e56c\" timestamp=\"0x8f047399\" size=\"0x01041000\" added=\"2025-03-28T03:59:19Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5160\" file=\"ntoskrnl.exe\" hash=\"5063ea50ac7cf444eeca423824b26da0d58730a1ce63bffe462217ea89b247db\" timestamp=\"0x90bc15c1\" size=\"0x01047000\" added=\"2025-04-01T05:31:15Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5160\" file=\"ntkrla57.exe\" hash=\"c4d9c632452da810c7a7c2930e87e2af6842fffd1037ed5c6b7c6636a331b641\" timestamp=\"0x08225a06\" size=\"0x01041000\" added=\"2025-04-01T05:31:15Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5160\" file=\"lxcore.sys\" hash=\"8c9200f8cd98de7bd5373086e1aee92073308d6be7d62eb3a9f6be4fe360ce53\" timestamp=\"0xbd23dc72\" size=\"0x00110000\" added=\"2025-04-02T01:27:00Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5170\" file=\"ntoskrnl.exe\" hash=\"da27ab820642aa5cb19c98ace4e4476a9ee18287fc070715d09d5b6a0638d6d1\" timestamp=\"0x8d145582\" size=\"0x01047000\" added=\"2025-04-09T14:22:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5170\" file=\"ntkrla57.exe\" hash=\"7d149842bbe8a1acbe07c9f1aef0b77b3dbd445ed599c0e2e8dc2265438fe287\" timestamp=\"0x08403773\" size=\"0x01041000\" added=\"2025-04-09T14:22:28Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5185\" file=\"ntoskrnl.exe\" hash=\"b21a9a464a69fc7f0fcde3e51db466ecad8ae5fe6c9edc370d51e336c824e136\" timestamp=\"0xa06c263b\" size=\"0x01047000\" added=\"2025-04-09T14:22:28Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5185\" file=\"ntkrla57.exe\" hash=\"4256856d419a4c7824f1e8b644c1e2f4f3d8880389ab16ebe7c53063882f610d\" timestamp=\"0x2be673b3\" size=\"0x01041000\" added=\"2025-04-09T14:22:28Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5192\" file=\"ntoskrnl.exe\" hash=\"c5467295ae9e9c3ef8cea2e5f52cd87aa1c0ac7d2b7bec9aa9a74fa408739c49\" timestamp=\"0x75c39391\" size=\"0x01047000\" added=\"2025-04-12T23:13:14Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5192\" file=\"ntkrla57.exe\" hash=\"44858f1d542fcc6f493c39b936c350aac9e22926fa69e01ad494166f20d5e14f\" timestamp=\"0xf80dca9b\" size=\"0x01041000\" added=\"2025-04-12T23:13:14Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5235\" file=\"ntoskrnl.exe\" hash=\"3ba0ac1f137fdeb88fb9f15210546c29d106045101bab308a0dab81999158508\" timestamp=\"0x3bf6db30\" size=\"0x01047000\" added=\"2025-04-17T02:01:01Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5235\" file=\"ntkrla57.exe\" hash=\"4e6496a43058cc6c272c1b1be84b0f6db37e9ccb535a82231705c41afc5147ed\" timestamp=\"0x200a5fed\" size=\"0x01041000\" added=\"2025-04-17T02:01:01Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5235\" file=\"lxcore.sys\" hash=\"99b4d87ef8747caff875922ba452a2a7c8245312597d55f20c6ccfe17dac536f\" timestamp=\"0x2bee8f1e\" size=\"0x00110000\" added=\"2025-04-17T02:01:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5240\" file=\"ntoskrnl.exe\" hash=\"c21a330b7f9bc22f12261cdc72a7aacb9bcb6fc0e2bcb4045fee0795d906c3a9\" timestamp=\"0xeb032e4b\" size=\"0x01047000\" added=\"2025-04-19T15:54:38Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5240\" file=\"ntkrla57.exe\" hash=\"8a441450513250d6e1c55be8599aa76a252f352f4a6ef6f279d63148ee0a5b94\" timestamp=\"0x2f67a00f\" size=\"0x01041000\" added=\"2025-04-19T15:54:38Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5262\" file=\"ntoskrnl.exe\" hash=\"40366220f121506c2d57f50327fdd562579f8413094689a45e120c1122676de5\" timestamp=\"0x132cfca1\" size=\"0x01047000\" added=\"2025-04-23T00:45:13Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5262\" file=\"ntkrla57.exe\" hash=\"a375efff7dd6aa647a2ef7d5ad9cc0c287e1b097b1b10730cbbd739e44bdeaf0\" timestamp=\"0x3d8f3adb\" size=\"0x01041000\" added=\"2025-04-23T00:45:13Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5305\" file=\"ntoskrnl.exe\" hash=\"db858e0ee47e3883a3892e5ebd4bca62b2686d73386caed2894f38f3930e08c7\" timestamp=\"0x8f36fc39\" size=\"0x01047000\" added=\"2025-04-26T20:45:50Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5305\" file=\"ntkrla57.exe\" hash=\"a965b6e65bea642a9d323b449f199f6670730ea44b11c2629d1603a4abcd3490\" timestamp=\"0x26538d68\" size=\"0x01041000\" added=\"2025-04-26T20:45:50Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5331\" file=\"ntoskrnl.exe\" hash=\"1fa89be1e7f4cab6a4ee176eccf3c00ca3395ab158773aa6c71c867d19b30dd4\" timestamp=\"0xca7b2929\" size=\"0x01047000\" added=\"2025-05-13T22:56:23Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5331\" file=\"ntkrla57.exe\" hash=\"93c95dedd650dccdba2c4cb36d56fad47d4a283a059875297ff14fc62ebace37\" timestamp=\"0xcc632809\" size=\"0x01041000\" added=\"2025-05-13T22:56:23Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5413\" file=\"ntoskrnl.exe\" hash=\"beeccda61c51aeb5bd351d56fead3c3d189a5140cfc000a361eaf214b50cb8db\" timestamp=\"0xe3593c04\" size=\"0x01047000\" added=\"2025-05-29T05:57:37Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5413\" file=\"ntkrla57.exe\" hash=\"859a7cb16c79360a0884985f85c75bfbd23592aa4db4826e7c44a0de480c7ffe\" timestamp=\"0xbb732f98\" size=\"0x01041000\" added=\"2025-05-29T05:57:37Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5415\" file=\"ntoskrnl.exe\" hash=\"0d99afd25bdce0c2f708d7b7bc57a29c1ecfba4fdd71460e8f63edbc3e9479ea\" timestamp=\"0x608e3855\" size=\"0x01047000\" added=\"2025-06-01T15:47:54Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5415\" file=\"ntkrla57.exe\" hash=\"6912840a3cb39ad77da5dcd4871fc3fa146c0c69edd84d0f09df60a3fe4e5245\" timestamp=\"0xa53eacc6\" size=\"0x01041000\" added=\"2025-06-01T15:47:54Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5415\" file=\"lxcore.sys\" hash=\"711b4c1afe29996114ef353315aa90da3038f6335114af0ff23cfa90c96421cd\" timestamp=\"0x98536e90\" size=\"0x00110000\" added=\"2025-06-01T15:47:54Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5471\" file=\"ntoskrnl.exe\" hash=\"13d68c41f8a8665e02dcafeb6efe96f4bed3139a4fe7cc8cc888df39eaca730f\" timestamp=\"0xe96ff46b\" size=\"0x01047000\" added=\"2025-06-11T00:42:44Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5471\" file=\"ntkrla57.exe\" hash=\"c516560c22d3721a30af79d97757bfdc954854a49e930c8cccbee2252721094e\" timestamp=\"0xb354aa95\" size=\"0x01041000\" added=\"2025-06-11T00:42:44Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5471\" file=\"lxcore.sys\" hash=\"586c73c05876396399c1eec09cd65336a6e9984dcde265fc3f965373e29cac29\" timestamp=\"0x17cb481e\" size=\"0x00110000\" added=\"2025-06-13T19:27:57Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5541\" file=\"ntoskrnl.exe\" hash=\"68e6c27f56ff341770702cd35ec3d7c3b36bac143dc581431de9cb3a18ac93aa\" timestamp=\"0x0adf3bf7\" size=\"0x01047000\" added=\"2025-06-28T02:27:55Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5541\" file=\"ntkrla57.exe\" hash=\"607d8e7920e48e7af18f62673d33ceb06544782ae7b7a6905ec91b0eb975ee0e\" timestamp=\"0xd44ac70f\" size=\"0x01041000\" added=\"2025-06-28T02:27:55Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5547\" file=\"ntoskrnl.exe\" hash=\"3e640d33fcc0ea403eabe03dc1df3fc522799c62a5aab4dad610e95d707da6a5\" timestamp=\"0xff5bc2d2\" size=\"0x01047000\" added=\"2025-06-26T22:28:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5547\" file=\"ntkrla57.exe\" hash=\"845c9fa0ce98ab8df5bf66db45376a315ad1b0deca0a20517f71197692e4dc84\" timestamp=\"0x6ca0b568\" size=\"0x01041000\" added=\"2025-06-26T22:59:22Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5624\" file=\"ntoskrnl.exe\" hash=\"ded038f6c8344ae068f85f098ee82cf7e6f3c98f6ce5737861e814e44ed23106\" timestamp=\"0xb5f8b1ef\" size=\"0x01047000\" added=\"2025-07-08T22:13:00Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5624\" file=\"ntkrla57.exe\" hash=\"48bb69ec7c9b5cb80fd2fb054addb76e93d4aa4f3c7ec3d271d31a76fef94f49\" timestamp=\"0x94f2de54\" size=\"0x01041000\" added=\"2025-07-08T22:13:00Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5697\" file=\"ntoskrnl.exe\" hash=\"4ed95ba5d199ce563e86ea521e00ea6365ea798fa5b9b3c38eab41258239e8c8\" timestamp=\"0xc84f0243\" size=\"0x01047000\" added=\"2025-07-23T02:01:02Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5697\" file=\"ntkrla57.exe\" hash=\"18ca0dc48f2e3ee17f132f2bf95363b886114c247b2585ff575d521d8e79eeed\" timestamp=\"0xe51db30f\" size=\"0x01041000\" added=\"2025-07-23T02:01:02Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5766\" file=\"ntoskrnl.exe\" hash=\"54dabab774bd0c3939558d7dfc0c2e0d58f7c0e392e73682c62fec5589bffe10\" timestamp=\"0x6797b960\" size=\"0x01047000\" added=\"2025-08-13T21:37:12Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5766\" file=\"ntkrla57.exe\" hash=\"7e13fbe3fb2e208adc7e5268ccc2e07029c304740e23732918238da127267d70\" timestamp=\"0x18a11e7f\" size=\"0x01041000\" added=\"2025-08-13T21:37:12Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5771\" file=\"ntoskrnl.exe\" hash=\"1438fad5d761ac0e78160831a47bdc5f9f8481641d4f5de7dac4e973e2028f7a\" timestamp=\"0x21512e15\" size=\"0x01047000\" added=\"2025-08-20T05:10:57Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5771\" file=\"ntkrla57.exe\" hash=\"b065aef779b642c7cf0cf2e01459d19e0cd267fa7dbd47fb5f33193042fc0f96\" timestamp=\"0xc8f27b96\" size=\"0x01041000\" added=\"2025-08-20T05:10:57Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5840\" file=\"ntoskrnl.exe\" hash=\"ee9972ccac7b41dcd8a3417e98dce494efaa5f5ea58548208c3302785f606752\" timestamp=\"0xc23d69de\" size=\"0x01047000\" added=\"2025-08-27T04:03:40Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5840\" file=\"ntkrla57.exe\" hash=\"e211959a97a37cf1c17b521a8521f9a2ca305af2ff8bda67653fa9abdefcf74e\" timestamp=\"0x521d4a26\" size=\"0x01041000\" added=\"2025-08-27T04:03:40Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5909\" file=\"ntoskrnl.exe\" hash=\"fa82dff1bb034f355cdc31f6f3e1e97f2e6e61ef72a025a3386757588b37c8b9\" timestamp=\"0x773f7a2a\" size=\"0x01047000\" added=\"2025-09-11T03:22:38Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5909\" file=\"ntkrla57.exe\" hash=\"cf14217a54153ac160c13692c9cf7b85f14202abb17e9e3da65dbe04c356fc92\" timestamp=\"0xf7d54dcf\" size=\"0x01041000\" added=\"2025-09-11T03:22:38Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5983\" file=\"ntoskrnl.exe\" hash=\"5df4295cc4cd0c5fecb7593dcac61c0091b1fc26c132aa28a9154b2835a98c2c\" timestamp=\"0xaf65aa8f\" size=\"0x01047000\" added=\"2025-09-26T02:51:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.5983\" file=\"ntkrla57.exe\" hash=\"3498d4204d35c767d6164b76318511c881ec2f1d525f60131e32f2ae105b1b41\" timestamp=\"0x5750cc58\" size=\"0x01041000\" added=\"2025-09-26T02:51:04Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6060\" file=\"ntoskrnl.exe\" hash=\"3255a69b65c23e1356b247aa8c05e93f6a4868268c878952af60c520d887596b\" timestamp=\"0x9323179b\" size=\"0x01047000\" added=\"2025-10-15T03:12:43Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6060\" file=\"ntkrla57.exe\" hash=\"f9913be62aa64b4b67d74a3c752fa054a5fdff675bbeb2c1fe9997692b8cb82f\" timestamp=\"0x23b6eaa8\" size=\"0x01041000\" added=\"2025-10-15T03:12:43Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6133\" file=\"ntoskrnl.exe\" hash=\"3bf9c2a9d2c1b162f88afc29cd9eec01f6469b9d43d4538ac154732ffcbb3434\" timestamp=\"0xdf1c61ff\" size=\"0x01047000\" added=\"2025-10-29T20:10:48Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6133\" file=\"ntkrla57.exe\" hash=\"d9ef776e53260f71e70354dc3b6cca7a709416e27b62e6f0f16f84164c09f622\" timestamp=\"0xd941b1c6\" size=\"0x01041000\" added=\"2025-10-29T20:10:48Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6197\" file=\"ntoskrnl.exe\" hash=\"261998aba5244cc9c8a43957422a0efe14bdd2b1186c748de48c2645404fcbe8\" timestamp=\"0x6d6ab1a6\" size=\"0x01047000\" added=\"2025-11-12T23:55:08Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6197\" file=\"ntkrla57.exe\" hash=\"562d57fa78a75bd150146f12eb6f584759c054ed3a28cecc03199277dbc36a80\" timestamp=\"0x3fa960d0\" size=\"0x01041000\" added=\"2025-11-12T23:55:08Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6199\" file=\"ntoskrnl.exe\" hash=\"bf8086243bd0f5139e3c516e1a7ab6acb43c8c5787ef6206b25447b264c4a665\" timestamp=\"0xfcd94196\" size=\"0x01047000\" added=\"2025-11-12T23:55:08Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6199\" file=\"ntkrla57.exe\" hash=\"b9d878d9e244e199dc3e48aeaeaf0e47ffd625fad7e2451f076f4a056e8fae53\" timestamp=\"0x0e42d459\" size=\"0x01041000\" added=\"2025-11-12T23:55:08Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6274\" file=\"ntoskrnl.exe\" hash=\"680e316b500baefd49417820ba35d9122fc2ba5e69f698350c0f834dd0840d07\" timestamp=\"0x5ed820e9\" size=\"0x01047000\" added=\"2025-11-25T23:06:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6274\" file=\"ntkrla57.exe\" hash=\"ff14ce610f96059033eeb9b0d6ee6655da7aa2cb136adb798c77536a347fb098\" timestamp=\"0x56b3a992\" size=\"0x01041000\" added=\"2025-11-25T23:06:05Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6337\" file=\"ntoskrnl.exe\" hash=\"7fa50017d5ffcd3bd1f0ff871191a17f8eaed3a04e079e0c16c4da90fcdee2fd\" timestamp=\"0x04eb83a2\" size=\"0x01047000\" added=\"2025-12-10T04:39:55Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6337\" file=\"ntkrla57.exe\" hash=\"5ed3001402dc9fa902ba63b6a7c831cdb996ef3915ec278ec68da3e389e281ae\" timestamp=\"0x058b1672\" size=\"0x01041000\" added=\"2025-12-10T04:39:55Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6345\" file=\"ntoskrnl.exe\" hash=\"6e9c710209b45699452eefadadab32a26e261fcf3dc7f13f7f5a423abef28051\" timestamp=\"0x1840b84f\" size=\"0x01047000\" added=\"2025-12-11T18:37:57Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6345\" file=\"ntkrla57.exe\" hash=\"3d1bdb3aae3dbe5a519cfecc387c736cc2e3715e4084839461cd3ef1c60381d0\" timestamp=\"0x659bf3ab\" size=\"0x01041000\" added=\"2025-12-11T18:37:57Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6489\" file=\"ntoskrnl.exe\" hash=\"3b98f8982ed0025a94407996076c15a2c4146e4372a2377d6d34d0227d18a086\" timestamp=\"0x2c317264\" size=\"0x01047000\" added=\"2026-01-15T04:51:11Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6489\" file=\"ntkrla57.exe\" hash=\"7d2db58f15e44b5b362c0d9b43ca044b6261c6becda81823f37bf207c0d1135b\" timestamp=\"0x2b4f5ad0\" size=\"0x01041000\" added=\"2026-01-15T04:51:11Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6630\" file=\"ntoskrnl.exe\" hash=\"f1e5edf5175327d22c10eb2248456070b46b78db5dfdbc665d3b30fd570eefee\" timestamp=\"0x8ca1b99b\" size=\"0x01047000\" added=\"2026-02-11T00:54:58Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6630\" file=\"ntkrla57.exe\" hash=\"6a45e9ada8c191258b79fb009ac5b258cabd9dc880d8cbb2bb97b648732edab9\" timestamp=\"0x3249cb85\" size=\"0x01041000\" added=\"2026-02-11T00:54:58Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6783\" file=\"ntoskrnl.exe\" hash=\"c4e266f8558d1fef33061f3839cc907e43ac7a345164a5b4ba01de516f8ded47\" timestamp=\"0x914e159d\" size=\"0x01047000\" added=\"2026-03-11T23:28:21Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.22621.6783\" file=\"ntkrla57.exe\" hash=\"79b0fb1a5489969386751cf0a153223352dd62cb8f9ce5ef71bb2f038f4448e5\" timestamp=\"0xa7e6fe57\" size=\"0x01041000\" added=\"2026-03-11T23:28:21Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.23451.1000\" file=\"ntoskrnl.exe\" hash=\"b7a4f1b2532e8796c6166555f3ac4d165dab02b5378a1626c0dd2c4e7971abb6\" timestamp=\"0x9989cbe3\" size=\"0x01047000\" added=\"2024-12-16T15:35:11Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.23466.1001\" file=\"ntoskrnl.exe\" hash=\"7b1e69fba1b01f8a73f00bec8f451ceb2bdde91aa403b25038e80320b3d8376f\" timestamp=\"0x3c02b911\" size=\"0x01047000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.23493.1000\" file=\"ntoskrnl.exe\" hash=\"3e10cc2b060d7384cdf50d7c418a3d2b0b612fbea4493734ddf31cfce638502e\" timestamp=\"0x4f6d0918\" size=\"0x01047000\" added=\"2025-01-10T06:00:00Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.23506.1000\" file=\"lxcore.sys\" hash=\"2a67f4afbe65a0fd05213fba8618af6623c320bc25eaae2ecd06a5d9c82ad1a4\" timestamp=\"0x1bd80817\" size=\"0x00110000\" added=\"2025-01-10T06:00:00Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.23521.1000\" file=\"lxcore.sys\" hash=\"caab6f9654f5cf6377e210d439d6616061155b547c31b45fae1de9d5eb1b8b18\" timestamp=\"0x3f311868\" size=\"0x00110000\" added=\"2025-02-17T22:56:35Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.23536.1000\" file=\"ntoskrnl.exe\" hash=\"58d0f4956b7591ad1f5d8d2d679fea168a6bf3f1c6749cf9271caeec9e335c5d\" timestamp=\"0xafbb92bf\" size=\"0x01047000\" added=\"2024-10-29T02:19:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.23560.1000\" file=\"ntoskrnl.exe\" hash=\"2689bef2125116914e5daff076f7019dccc92371fb96e42671099564a731aa89\" timestamp=\"0xcafe66f5\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.23590.1000\" file=\"ntoskrnl.exe\" hash=\"41efa3ba30180d5f241519d9d1f01f260ef09fe078c2dd48e8f5537e653cedf4\" timestamp=\"0xfa651438\" size=\"0x01047000\" added=\"2025-06-10T13:19:34Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.23590.1000\" file=\"lxcore.sys\" hash=\"9a23fb12c1687211bca11272e950a5835ac6b7c822c138e6e6aff503f355e471\" timestamp=\"0x9386442a\" size=\"0x00110000\" added=\"2025-03-14T04:05:46Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.23606.1000\" file=\"ntoskrnl.exe\" hash=\"9eab47b7f0a4a74dbfb9a26c5b67c17e5a6409c099393529d2ad454b597cc6d9\" timestamp=\"0x1a63f27c\" size=\"0x01047000\" added=\"2024-11-05T01:22:32Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.23619.1000\" file=\"ntoskrnl.exe\" hash=\"1e40c3650af549f32a93b7a7d42bd58d77879601a3fceae827473d1a39d16b6b\" timestamp=\"0xad1bdd1a\" size=\"0x01047000\" added=\"2024-11-13T15:20:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.23620.1000\" file=\"ntoskrnl.exe\" hash=\"347ffa23adba436afbffbc6d3c0ec5664cdce416c6da8b35bbed9b1032c445ad\" timestamp=\"0x71dafd90\" size=\"0x01047000\" added=\"2024-09-15T09:54:12Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.23620.1000\" file=\"lxcore.sys\" hash=\"01cc889f1105bf0cca57dc9c72548bd916ce27e8ad17dc8702934ecc42456010\" timestamp=\"0x2e306e10\" size=\"0x00110000\" added=\"2024-09-15T09:54:12Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.25110.1000\" file=\"ntoskrnl.exe\" hash=\"304b860802cdb25b8354a0840880838a7a88ede6a5f547596ae196881917efab\" timestamp=\"0x0d2c8072\" size=\"0x0104c000\" added=\"2025-03-23T17:06:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25110.1000\" file=\"ntkrla57.exe\" hash=\"d022a480dc7ced1fe048dc64c93833d659809dab14020e4b31609630a6741180\" timestamp=\"0x7043009c\" size=\"0x01046000\" added=\"2026-01-07T20:08:38Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.25179.1000\" file=\"ntoskrnl.exe\" hash=\"8573cff3255cebda19d7d6f8a2ebd843d4cbfbe6d8f0a7f3b330537067137f55\" timestamp=\"0x2f968b13\" size=\"0x0104d000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25181.1000\" file=\"lxcore.sys\" hash=\"60389f110221243b7cd088b3d814b69b805ebcea71e4954d8de5c45db5e08b16\" timestamp=\"0x521b3d5a\" size=\"0x00110000\" added=\"2025-01-10T06:00:00Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.25182.1000\" file=\"lxcore.sys\" hash=\"3e8b8ed8dcb9b289a3358fea3ef781d5a52f0ee8006d0797614ab3f7c92fb7b7\" timestamp=\"0xbe6fb908\" size=\"0x00110000\" added=\"2025-05-29T05:57:37Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.25188.1000\" file=\"ntoskrnl.exe\" hash=\"a0abf5c40d9c65adf247232e1173f5034d55077e24134bf9eabca0dfb62a511c\" timestamp=\"0xf775d6cb\" size=\"0x0104d000\" added=\"2025-06-22T18:46:02Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25236.1000\" file=\"ntoskrnl.exe\" hash=\"6d99d03dd03c3c47e272deb293c40c5f949af6947b2b11650c79d5fb90cc9183\" timestamp=\"0x4d6962f6\" size=\"0x0104c000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25252.1000\" file=\"lxcore.sys\" hash=\"8ce8667e551dddcde1ba4e8b4a4e12277ff2dc764bfd9f2649bc6f25c2aa5fd7\" timestamp=\"0x9dd0952c\" size=\"0x00110000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.25262.1000\" file=\"ntoskrnl.exe\" hash=\"1d251c948d1f9f453a9f3082c741538c759cb3f7d086bcdd28e1e81d197b3c67\" timestamp=\"0x0c84150b\" size=\"0x0104d000\" added=\"2025-07-29T22:48:22Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25295.1000\" file=\"ntoskrnl.exe\" hash=\"1aeda1b5ea390fa749a7dba07d1196d494ab86e90b1c83b7edcd065daf7d9fd1\" timestamp=\"0xd6507c5c\" size=\"0x0124d000\" added=\"2025-09-04T03:27:22Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25300.1000\" file=\"ntoskrnl.exe\" hash=\"5b47bbd4f0ba1eec3b8345c6c218f52a8c9e7310e3aaa712f088e286a5e2f498\" timestamp=\"0x009c82bb\" size=\"0x0124d000\" added=\"2025-09-04T03:27:22Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25314.1000\" file=\"ntoskrnl.exe\" hash=\"a8fa362efd97ec7298334d578c6396e5e3f29d4777d7be6e4046849aed323eaa\" timestamp=\"0x9877920c\" size=\"0x0124c000\" added=\"2026-02-14T07:40:21Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25330.1000\" file=\"ntoskrnl.exe\" hash=\"df870cf403b06f96aa61b2cf7a148d8341a3bb66b4a2717280f00d720685f3f0\" timestamp=\"0xf80487e9\" size=\"0x0124d000\" added=\"2024-09-12T01:41:05Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25346.1001\" file=\"ntoskrnl.exe\" hash=\"678595c0848db0b648db232839c3423efa93f4f71e7aded55f47318657bb7421\" timestamp=\"0xc5c15a3d\" size=\"0x0124c000\" added=\"2025-04-01T05:31:15Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25352.1\" file=\"ntoskrnl.exe\" hash=\"3022fe7b4f6c5a91a566aa1e92f4f009ef7f7394c88827fa4ffe21d1725e714d\" timestamp=\"0xd98f8171\" size=\"0x0124c000\" added=\"2025-08-19T16:07:50Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25393.1\" file=\"ntoskrnl.exe\" hash=\"0f898e97f1a09430494563ef28d907c5420e04229e5b9a1b08bb6ccc31a63c58\" timestamp=\"0xb9b3c532\" size=\"0x0124d000\" added=\"2025-06-13T19:27:57Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25393.1\" file=\"lxcore.sys\" hash=\"0c7965352ef719e70f38d6dbd266102cb6f4ed92b2f0a529e4592faf1d2ae0b0\" timestamp=\"0xa196cd34\" size=\"0x00110000\" added=\"2025-06-13T19:27:57Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.25398.1\" file=\"ntoskrnl.exe\" hash=\"3934f6d41f0d035f0dc672f4ed3ab1e3640f7fd2331815028196b1b3c7a2043b\" timestamp=\"0xe4fb7bfb\" size=\"0x0124d000\" added=\"2025-08-29T21:12:06Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25398.1\" file=\"ntkrla57.exe\" hash=\"c56b00804fc5fc88fa82802235307c7c9ce82f0aa1729576f34d92a4f739c258\" timestamp=\"0x36dd9009\" size=\"0x01044000\" added=\"2025-08-29T21:12:06Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.25398.1551\" file=\"ntoskrnl.exe\" hash=\"193bcd640e19f3127cbd9a6548b61bc0773a1558c7da69c0cbf9c287029eb386\" timestamp=\"0x86e1f454\" size=\"0x0124d000\" added=\"2025-05-18T22:45:47Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25398.1551\" file=\"ntkrla57.exe\" hash=\"3f5e9151768a1de0cce2c58b7801b59e9d4d06ac9ed61241575726b1611d35d6\" timestamp=\"0x3f0f7f59\" size=\"0x01044000\" added=\"2025-05-18T22:45:47Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.25398.1913\" file=\"ntoskrnl.exe\" hash=\"2fa07ddcc29ef12dc3123e62a5aa765310919b40030a7dec1339e0c1ebb3b1f3\" timestamp=\"0x6e1dcf02\" size=\"0x0124d000\" added=\"2025-10-24T14:15:26Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25398.1913\" file=\"ntkrla57.exe\" hash=\"7b736cc4fb56286a8f370f72619a80fa98b0df3d5b32565260807412743f31f8\" timestamp=\"0xe135011d\" size=\"0x01044000\" added=\"2025-10-24T14:15:26Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.25398.1916\" file=\"ntoskrnl.exe\" hash=\"c2afff61d87af971b16a851279bce18035398c76f55593b3a197f5dee55a9084\" timestamp=\"0x5e10b528\" size=\"0x0124d000\" added=\"2025-11-02T15:30:04Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25398.1916\" file=\"ntkrla57.exe\" hash=\"235bf909b9820a981bac00c4f9b53c38bae0469f44c00a11d49b71ac44a10486\" timestamp=\"0xc6976365\" size=\"0x01044000\" added=\"2025-11-02T15:30:04Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.25921.1000\" file=\"ntoskrnl.exe\" hash=\"46c98248f9b1211f5bd114a40fefb4068bd97e3629126967a8d6f2a448704cd7\" timestamp=\"0x47210e63\" size=\"0x0124d000\" added=\"2025-02-17T22:56:35Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25926.1000\" file=\"ntoskrnl.exe\" hash=\"58deb806c8134bf3730774f8a5fa3d4ea22178909b2b68d3e671d66d3ca73724\" timestamp=\"0x53a546d5\" size=\"0x0124d000\" added=\"2024-10-04T01:28:54Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25941.1000\" file=\"ntoskrnl.exe\" hash=\"31aab372d2fb41c5fa4a1f0f4fcacc7e07d4516485fa0717357252644a4a1997\" timestamp=\"0x66615fbc\" size=\"0x0124c000\" added=\"2024-09-15T09:54:12Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25941.1000\" file=\"ntkrla57.exe\" hash=\"fb9fb4996c4ff0ac309fac2552232419a48efcbb5072a340fcd873e949d6d672\" timestamp=\"0xadb2111c\" size=\"0x01044000\" added=\"2025-05-17T15:31:20Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.25941.1000\" file=\"lxcore.sys\" hash=\"54a0f6651c5ef7935a00c881dbe90771a9c4557cd1b7cdc52fe46c7fa6b4fc59\" timestamp=\"0x9174e168\" size=\"0x00110000\" added=\"2025-05-10T01:12:18Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.25951.1000\" file=\"lxcore.sys\" hash=\"7737af0e7c1f35fed1c574805cde08acd38c1bab3aca6dedd1fd87fa69212267\" timestamp=\"0xf1c17580\" size=\"0x00110000\" added=\"2024-09-27T22:22:02Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.25951.1010\" file=\"ntoskrnl.exe\" hash=\"c06de3db49b3d9d398d97e56a5fe241d19f53973dff7d0ce126f3b958d7f2a99\" timestamp=\"0x48e053cd\" size=\"0x0124c000\" added=\"2024-09-27T22:22:02Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25967.1000\" file=\"ntoskrnl.exe\" hash=\"9e6a19ba5d5f97d498a77d8ec8ec2b706286b48026da5dc50fa79f7bcd346fd6\" timestamp=\"0x12ef5730\" size=\"0x0104c000\" added=\"2025-04-01T05:31:15Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25967.1000\" file=\"ntkrla57.exe\" hash=\"6920c76097bb431a48e5b51c575f55329a3e1c01e92e243522e908c376d5344f\" timestamp=\"0x007ead6b\" size=\"0x01044000\" added=\"2025-08-16T02:03:03Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.25977.1000\" file=\"ntoskrnl.exe\" hash=\"f58a9ff113f93f73c308a2589b9d3c41d26ae789eb51f57e82d05d00b1795c08\" timestamp=\"0x1e873b0e\" size=\"0x0104c000\" added=\"2025-03-11T02:45:33Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25977.1000\" file=\"ntkrla57.exe\" hash=\"d6777461c7ef6a8acb7693a79e5a0dc7373c105880351a32ad31aedcb2b261ed\" timestamp=\"0x9812b038\" size=\"0x01044000\" added=\"2025-03-11T02:45:33Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.25982.1000\" file=\"ntoskrnl.exe\" hash=\"0b0535d6260e052d3c47aba1634e134245775a66e64782800c682c860bff1eaa\" timestamp=\"0x78680c42\" size=\"0x0104c000\" added=\"2025-02-19T22:12:09Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25992.1000\" file=\"ntoskrnl.exe\" hash=\"69ce1ab959785ccb015e30cf80e76818fa4d52a3b3927ba977b2a758dec9ef53\" timestamp=\"0x3abbd43c\" size=\"0x0104c000\" added=\"2024-09-27T22:22:02Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25992.1000\" file=\"ntkrla57.exe\" hash=\"025a13321a5c9a7325d41578a363da7e264a8927da17d9b418dd98909d42d67e\" timestamp=\"0x09117dd2\" size=\"0x01044000\" added=\"2025-06-21T07:33:49Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.25992.1000\" file=\"lxcore.sys\" hash=\"0019199073c8597da6a2a592195fd067601e7ea337e1269fbddaa98825e79970\" timestamp=\"0xf8ff3b3e\" size=\"0x00110000\" added=\"2024-09-27T22:22:02Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.25997.1000\" file=\"ntoskrnl.exe\" hash=\"0ea44ddc238f347a3225cd064f075ab08c847cb938b87d162cf284cd5e51218a\" timestamp=\"0xf22f9ed7\" size=\"0x01050000\" added=\"2025-06-18T01:25:23Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.25997.1000\" file=\"ntkrla57.exe\" hash=\"c202d34b01694824ab1025daa898735ffd08c38b72df346df1928b13851ae442\" timestamp=\"0x2c52c1e3\" size=\"0x01048000\" added=\"2025-06-18T01:25:23Z\">13</data>\n    <data arch=\"amd64\" version=\"10.0.26016.1012\" file=\"ntoskrnl.exe\" hash=\"19c2785cc907f6e821c3dce782e10b7b3d07f58c8dbc41cc9e2e4ff341675ac0\" timestamp=\"0xdb46672e\" size=\"0x0124c000\" added=\"2024-10-26T06:39:10Z\">8</data>\n    <data arch=\"amd64\" version=\"10.0.26019.1000\" file=\"ntoskrnl.exe\" hash=\"3e1441c37dc1aef88c4411b077c9a5a676aeae893f02247ab4bd7629f60a13c2\" timestamp=\"0xeda27410\" size=\"0x0124c000\" added=\"2025-03-02T06:42:51Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26040.1000\" file=\"ntoskrnl.exe\" hash=\"69197a7aa80e6bbdb3858becf2beeb3953173ae4ccc30cf747e7c5c59fbe8628\" timestamp=\"0xaf082233\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26040.1000\" file=\"lxcore.sys\" hash=\"61c7deb58233d991e2a46344d32373865f301bde2cbfb9e98b189c6506d3ac8e\" timestamp=\"0xfe953be0\" size=\"0x00110000\" added=\"2024-09-12T01:41:07Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26052.1000\" file=\"ntoskrnl.exe\" hash=\"b3cc7086065b0588488a0609dde395e1f774b7d69e51f78691472ba9f6f8fa33\" timestamp=\"0xd1e895fb\" size=\"0x0144e000\" added=\"2025-10-24T14:15:26Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26052.1000\" file=\"ntkrla57.exe\" hash=\"d6174cfcd0df36ab1004dcffd2034a217a466faaa49ca86d2e5fd3f175a3d9f6\" timestamp=\"0x79ad93e7\" size=\"0x01248000\" added=\"2025-10-24T14:15:26Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26058.1000\" file=\"ntoskrnl.exe\" hash=\"92ad4803a06d0514586edca0a6f73f1d7b3cd4e2cf43debd3a5c3f042568b24e\" timestamp=\"0x345b1ff7\" size=\"0x0144e000\" added=\"2024-11-26T20:43:33Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26058.1000\" file=\"lxcore.sys\" hash=\"ed2d166d3affb47b1bc4407ca4d1f31c7098b999755280c1e04f05d6ed2bb13f\" timestamp=\"0x48c437d6\" size=\"0x00110000\" added=\"2024-11-26T20:43:33Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26058.1100\" file=\"ntoskrnl.exe\" hash=\"730911accbdc0dbde1551ab07d66ab5db4df2880d332c91978486ecc8f97b279\" timestamp=\"0x4e608571\" size=\"0x0144e000\" added=\"2024-11-21T19:38:04Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26058.1100\" file=\"ntkrla57.exe\" hash=\"d049edc2f7a01922370d59dd6ebd77e557acbafc6de81b10d557a91d7afde78b\" timestamp=\"0x14fc7d7e\" size=\"0x01248000\" added=\"2025-10-16T23:37:47Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26063.1\" file=\"ntoskrnl.exe\" hash=\"e7a695486e470a40ff350a5d3ad2344283bdf64abad5644f7643a9056768c006\" timestamp=\"0x3000e1cc\" size=\"0x0144e000\" added=\"2025-07-19T02:10:13Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26063.1\" file=\"ntkrla57.exe\" hash=\"19ef535b3c36ec0d66551908a3a3c775037f6b6d814188d7625517dd8bc96586\" timestamp=\"0x4d0304b8\" size=\"0x01249000\" added=\"2025-07-19T02:10:13Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26080.1\" file=\"ntoskrnl.exe\" hash=\"0c1b6d83b54c0edce234e2bfc959bfc28f2e645e1b329a763efbbefd50881f9e\" timestamp=\"0xe02aca0b\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26080.1\" file=\"ntkrla57.exe\" hash=\"7a1dc4cfb1e75048002a788d4c0de9413e9f45d31966363c865073160dee93c6\" timestamp=\"0x9448b531\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26080.1\" file=\"lxcore.sys\" hash=\"b93d6c66f8ea85c8e7a97af527c819d9e2155be8cb54a9255883080a471c88a3\" timestamp=\"0x507c391f\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26080.1100\" file=\"ntoskrnl.exe\" hash=\"63ecee154daf17b56d53fa8fec3818c5badd66be61bef3cf38fecbb3870316cc\" timestamp=\"0x930a6e03\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26080.1100\" file=\"ntkrla57.exe\" hash=\"06897941ad824be38f11a83a11bb2d9063f05b520175341ef8352b3b5439a999\" timestamp=\"0xc3141a53\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26080.1201\" file=\"ntoskrnl.exe\" hash=\"a15c1d21106fd982c11b8881055761206d84086e9eb83a212a2c9177e3a6959d\" timestamp=\"0x987704e5\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26080.1201\" file=\"ntkrla57.exe\" hash=\"7f6b46ade1efd4ec724707ab8cca023003ed694f5c2b66127a1ed0af9aa976d0\" timestamp=\"0x46ea909d\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26080.1300\" file=\"ntoskrnl.exe\" hash=\"77abcd00b8ceacc3c67603b22d1dcfc827bb34951b4c3ead7220382c2b41b8c8\" timestamp=\"0x4fbf4d2d\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26080.1300\" file=\"ntkrla57.exe\" hash=\"46f8e757e486a5d8178bdd03b14f93d4110055c55bcaee057d7678aa297ac97a\" timestamp=\"0x6df8514e\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26085.1\" file=\"ntoskrnl.exe\" hash=\"542af774884e9f5b87ba18981510c1bafe7f5361a829a97fa48db2297ff98717\" timestamp=\"0x29b06294\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26085.1\" file=\"ntkrla57.exe\" hash=\"b7527ea026ce9a90dc35051ff81bb94a012d980ad201a9f6fd478cb0b61a6816\" timestamp=\"0x15afe869\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26085.1\" file=\"lxcore.sys\" hash=\"a3a4401cf201bba3bac992cfe317528774971a3b23d23e0006baf331afedc39c\" timestamp=\"0x53a87928\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26090.1\" file=\"ntoskrnl.exe\" hash=\"ef68101261be06d04d4bdda39b768bc0ed42ce1c7029149789a40ad7de794490\" timestamp=\"0xfc09798d\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26090.1\" file=\"ntkrla57.exe\" hash=\"b067f65711b390b3cf08d90c37065a6ee50971e5b3d89071fe13ca7df3a8274b\" timestamp=\"0x05326219\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26090.1\" file=\"lxcore.sys\" hash=\"885f64ce8437029744eb4ddb1e3b32a7e76bb9275f3b9a9bbf4b4365655d5c2b\" timestamp=\"0x91d6897a\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26090.112\" file=\"ntoskrnl.exe\" hash=\"88bbbba84fb5f8d839bce4bafdb55bfffd6db55a75a6cfba5f33cf220e026636\" timestamp=\"0xbe431825\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26090.112\" file=\"ntkrla57.exe\" hash=\"a0815b9ec8d3e836990b55ed428c9ccd258433a1bdc8691df751e0c67cb932e2\" timestamp=\"0x3236838d\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1\" file=\"ntoskrnl.exe\" hash=\"1cc3b103b25333ee2b79363bb898832a93576befd2e3a29817bd34cf7a3a102b\" timestamp=\"0x9f2e55b7\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1\" file=\"ntkrla57.exe\" hash=\"8f87bd8ac15a226202bdb1601cdbbc84ae01016975a0331b15e7ad3bf11d64d4\" timestamp=\"0x1cff5dfe\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1\" file=\"lxcore.sys\" hash=\"3fff515219ab9c8ac77bc637ac23a6d4c4b72366b9021925acfe5676916301a9\" timestamp=\"0x770f3851\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2\" file=\"ntoskrnl.exe\" hash=\"145093b1bb6a085691c09d4c62c759b1c6e9c515daf4b6ab3b5ae5390967692a\" timestamp=\"0xbd058b1a\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2\" file=\"ntkrla57.exe\" hash=\"cc7f4119787324538a59b63d1298809ea409ddaa569dec89b2dc10cd646ac51f\" timestamp=\"0xc3a52421\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2\" file=\"lxcore.sys\" hash=\"fda8df97161d86052182cce327610c25987cd6e0acd73917e549899e52791cf2\" timestamp=\"0x9808702e\" size=\"0x00110000\" added=\"2026-02-02T00:46:25Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.268\" file=\"ntoskrnl.exe\" hash=\"8480be4e92e6e1bf063ee17f52fd5aeb3f3779715ada3b94022bc3605fc0c51e\" timestamp=\"0x1f66a752\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.268\" file=\"ntkrla57.exe\" hash=\"aa57cfec3fe646f45b8eecb3bed35d439567dd771492a5c9afe62be283909ab2\" timestamp=\"0x1c4d1416\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.461\" file=\"ntoskrnl.exe\" hash=\"9d90e6e5db56cf4adddcd488623e649a68e09e84424de2489aa79b2d88b3740c\" timestamp=\"0x286856ef\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.461\" file=\"ntkrla57.exe\" hash=\"8df8b69e20796d7d50d5d0b6674e7a4546c93320568fcaa64b221dedc9106e9a\" timestamp=\"0x6884803e\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.470\" file=\"ntoskrnl.exe\" hash=\"d44532c5296368587e8b8716b10848300a66e0827d9442393dc2baa8a28d2366\" timestamp=\"0x648ce271\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.470\" file=\"ntkrla57.exe\" hash=\"3082acd0adf693aca82f03a8fe362747f0590ac486d6acd02e76409069f4b369\" timestamp=\"0xc05d27b6\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.560\" file=\"ntoskrnl.exe\" hash=\"d40d8d985f8ac27dc031967ff622f3e97ceb08a171b6bb99e30d5fc385b3dd5a\" timestamp=\"0x86d43390\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.560\" file=\"ntkrla57.exe\" hash=\"b712db9cc87b07c55ef164617d6ec2f0ad4ec7fbbd4a44c41ebc510b6b1fbe8d\" timestamp=\"0x166d57c6\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.670\" file=\"ntoskrnl.exe\" hash=\"8a4ed0aefe5c41cb7a65b9a12c160a6562d1d599eb924a40b60e99981412545c\" timestamp=\"0x0494f89b\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.670\" file=\"ntkrla57.exe\" hash=\"e19e7b6c680dded3c99d8c2f918a8dab881ab2e8ce623dbca66ef9ce736d8822\" timestamp=\"0xf62c99cf\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.712\" file=\"ntoskrnl.exe\" hash=\"bdb02d5f616222452e0578028210768f6aeae841bbd90e87496dba731cd70ad6\" timestamp=\"0x75e56c9c\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.712\" file=\"ntkrla57.exe\" hash=\"617fa2bab18f12bcb7cd6551d4a140d52cf0c951f9bf5c37b5098844a26196d7\" timestamp=\"0x1b249ccb\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.751\" file=\"ntoskrnl.exe\" hash=\"8e54a5b518297e672b2e123519e0008697d47a0606481952922412f40dd4577a\" timestamp=\"0x6f3afbc6\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.751\" file=\"ntkrla57.exe\" hash=\"f659ac049eb1c28981c2ae2517a127bbac47af3582986f6157520e1f89f32fab\" timestamp=\"0x7a30c3e3\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.770\" file=\"ntoskrnl.exe\" hash=\"567790575a62c1d67f2bc8f721e81ccce5af99d2a7c27f3578b441ce19a6fa66\" timestamp=\"0x9aa5ee29\" size=\"0x0144f000\" added=\"2024-10-26T06:39:10Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.770\" file=\"ntkrla57.exe\" hash=\"556d74f556c98ef3685e157894d78a6d29fd97299cd5727dc542a9a4f327aad2\" timestamp=\"0x283d2d9f\" size=\"0x01249000\" added=\"2024-12-03T02:17:28Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.863\" file=\"ntoskrnl.exe\" hash=\"4775594470b73e3a12bfcd0f891e1460e789416350b7bacd348887a647af7c0a\" timestamp=\"0x62738c60\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.863\" file=\"ntkrla57.exe\" hash=\"e804a44ef0d63c5b642492077f2f548430689421cb9c03ac5c7b6b5735c24fb7\" timestamp=\"0x7b79d4c3\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.961\" file=\"ntoskrnl.exe\" hash=\"1593a7fb8ef81ce3e2fa907c44e53f69ab085cebbc90b5383210893d69468636\" timestamp=\"0xfbc9a4ee\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.961\" file=\"ntkrla57.exe\" hash=\"201b8ab5f3ac214180d8307122804b5befab9ba86a1e0f92e9398d889cb6eac1\" timestamp=\"0xef5854cb\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1000\" file=\"ntoskrnl.exe\" hash=\"fec879038dda054398c329be63fcb49cbdcfaa3f62b18d142581295ae17f1c83\" timestamp=\"0xa2300df0\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1000\" file=\"ntkrla57.exe\" hash=\"b4a3206c79e795996ad927603e7133cb488b0a537820f588bea4aa8885dc082b\" timestamp=\"0xe88edf49\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1150\" file=\"ntoskrnl.exe\" hash=\"53af7121ce55fcec24933c56cbb5b8fd9e4bec8d2df94d6bceda3b591ca04de3\" timestamp=\"0x6e259c5a\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1150\" file=\"ntkrla57.exe\" hash=\"62a32afd83d41f198c71b5c767ec7deb7cd547921b601cf910cfc113e275dae2\" timestamp=\"0x949ed7b0\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1150\" file=\"lxcore.sys\" hash=\"e56098ad51dce87efa3c6a773aa3f56f9212a5d25dd897a9cafdd1ceb1248b3e\" timestamp=\"0xe0a1606a\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1252\" file=\"ntoskrnl.exe\" hash=\"80cd4cb8b5650e7ab864cd134e35211d5edb3cd8f8d9cff9f28bb9e08513c63c\" timestamp=\"0x3f3257e2\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1252\" file=\"ntkrla57.exe\" hash=\"444c409432697c2ca7d5aa8b7c01f94320f35d8ce53d7b1bc72318a99041742f\" timestamp=\"0xf3a3adbf\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1252\" file=\"lxcore.sys\" hash=\"0f3e019a20db0075903d6876202327e1c5afd4505b3d1f2f3697eebd64fa1f2b\" timestamp=\"0x87d38be7\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1297\" file=\"ntoskrnl.exe\" hash=\"05577747478d2744488045cb8984cd332a408efb5a7e7b52b03129656e419a46\" timestamp=\"0x6c49de5d\" size=\"0x0144f000\" added=\"2024-09-21T19:30:35Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1297\" file=\"ntkrla57.exe\" hash=\"8d5b99b1f6da018ddcf6b29aadcc82eaadbb3d3425db725cf0f4baadaef4d46b\" timestamp=\"0x0f4bccbe\" size=\"0x01249000\" added=\"2024-09-21T19:30:35Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1301\" file=\"ntoskrnl.exe\" hash=\"5991bd464e3574854415910f0f6d2d1402755b4bdf4127328157e71f3ac252b0\" timestamp=\"0x7efd9a16\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1301\" file=\"ntkrla57.exe\" hash=\"4885873108bda88f842e8758511125d03e615eafb328734e490fa1910772ee69\" timestamp=\"0x3e52949d\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1330\" file=\"ntoskrnl.exe\" hash=\"c611efeefe0fbf7b0ef9fe2cb57d886fd7189086ba0d253c8bb96a91e1665ca3\" timestamp=\"0xcedd9d42\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1330\" file=\"ntkrla57.exe\" hash=\"9bde85149105f882f1984af952dad2f7981acc4b1b42abcd27efb6875f9c13f6\" timestamp=\"0x39bdb293\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1340\" file=\"ntoskrnl.exe\" hash=\"4272373f0df66ed3891eb9b3248b724d11e3c50fc37ef12f5fb380570a1c6958\" timestamp=\"0x2d52ff18\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1340\" file=\"ntkrla57.exe\" hash=\"4b6f2d697707ef8abc98ae03fb7dcbf20df9ab6f20d5995737052868c85e2fdf\" timestamp=\"0x1562bf2f\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1350\" file=\"ntoskrnl.exe\" hash=\"5e7cb94a8b3a45d024e48d9235c56689d3887ad2a761481889283b1d521ce9a8\" timestamp=\"0xbc5d8526\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1350\" file=\"ntkrla57.exe\" hash=\"c52a3780cbacac2100c8b3744075ce4e88c4adb8b134f3c5885a69837974a9a2\" timestamp=\"0x795d8af8\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1455\" file=\"ntoskrnl.exe\" hash=\"44c54268ab0a89d6a1b270184122e2e7128396f41dee9b4a7ad5f490945b75e3\" timestamp=\"0x1739b79c\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1455\" file=\"ntkrla57.exe\" hash=\"2d5c5f26a92f39d325a6610459402b5248ed1ea28dea599a9dd8bdf5c75971a8\" timestamp=\"0x4107c983\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1591\" file=\"ntoskrnl.exe\" hash=\"475457f5a280b71a33ce0ddf2b1faf394457f81384f53f756c70996d2ebb0c05\" timestamp=\"0x10cb6ae4\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1591\" file=\"ntkrla57.exe\" hash=\"e6a5ce41b7012d146e55e0fe42bfd552156a2d6022d399cc54b838a1c0a83fdc\" timestamp=\"0x6bd825f2\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1742\" file=\"ntoskrnl.exe\" hash=\"93db70780a95192d13d04b4c3cb49c22a138063adba5c83d4855be02b645fdd0\" timestamp=\"0xd98db6a6\" size=\"0x0144f000\" added=\"2024-09-12T01:41:07Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1742\" file=\"ntkrla57.exe\" hash=\"f0f6a96e343b9fcf8aede82b1595f49f61e1d8c058b323aa9602b29dff8c5391\" timestamp=\"0x12ceb083\" size=\"0x01249000\" added=\"2024-09-12T01:41:07Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1843\" file=\"ntoskrnl.exe\" hash=\"2c836d6f04052a9acb15b4e10281eab4b81f52f2bc392cd1b0a997863b34033c\" timestamp=\"0xca8b7988\" size=\"0x0144f000\" added=\"2024-09-21T19:30:35Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1843\" file=\"ntkrla57.exe\" hash=\"e7e33914f34cb3b44d7a0c284852be7650151e4a4ece2c01b605a13be4841d82\" timestamp=\"0x9f2aa97a\" size=\"0x01249000\" added=\"2024-09-21T19:30:35Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1882\" file=\"ntoskrnl.exe\" hash=\"dcbb965ec88e67b10b941c593326d889d9ecb64782a62afc2897f1e9e8b0da47\" timestamp=\"0x002eaf5a\" size=\"0x0144f000\" added=\"2024-09-30T22:51:30Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1882\" file=\"ntkrla57.exe\" hash=\"ad7e3217597b371214a443bce14e3aaf90e95dc9d77d305f430f7d3238f250e5\" timestamp=\"0xb7d392b4\" size=\"0x01249000\" added=\"2024-09-30T22:51:30Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1882\" file=\"lxcore.sys\" hash=\"f40604bde9d29d01b7bcf7103f8bc3e877b889d891c1556cf105fc9c9d955e88\" timestamp=\"0xb16cfbfb\" size=\"0x00110000\" added=\"2024-10-01T23:04:59Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1912\" file=\"ntoskrnl.exe\" hash=\"9078f529738c93d3c84ae49edd186b8cd41602600684faf924c01160a5199ed1\" timestamp=\"0x6d309c7e\" size=\"0x0144f000\" added=\"2024-09-30T22:51:30Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1912\" file=\"ntkrla57.exe\" hash=\"f9e38fef69d9918d99a53b7a5eb6b74f5a132493e89c7a3a26a98681da04bada\" timestamp=\"0x871c178f\" size=\"0x01249000\" added=\"2024-10-01T23:04:59Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1930\" file=\"ntoskrnl.exe\" hash=\"3b775a986bfc42d9ba67d76db7233f9238fdd672fcda2f1db7b7b1043a215665\" timestamp=\"0xfb92a63f\" size=\"0x0144f000\" added=\"2024-10-06T07:32:47Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.1930\" file=\"ntkrla57.exe\" hash=\"fa3d3e11a94216b2b8d4ca32ccbf61ee55580e8ca2fd3d2128034d3e902b504d\" timestamp=\"0x8ca25742\" size=\"0x01249000\" added=\"2024-10-06T07:32:47Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2033\" file=\"ntoskrnl.exe\" hash=\"80eb4c09526b97be23f6daa4ccd2bc97c467d2f3f5b278127693ccbcc17c8369\" timestamp=\"0xcb0fa9da\" size=\"0x0144f000\" added=\"2024-10-09T02:21:15Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2033\" file=\"ntkrla57.exe\" hash=\"2ac9e0f99b57c0391d640db624cf06beb273631e8038e1c9d5dcc241f43879fd\" timestamp=\"0x1dfba92c\" size=\"0x01249000\" added=\"2024-10-09T02:21:15Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2122\" file=\"ntoskrnl.exe\" hash=\"25a34f36d2d332e223e875ac89c6e256c993ca869b864737401e80d3f1735ada\" timestamp=\"0x145aacec\" size=\"0x0144f000\" added=\"2024-10-12T01:50:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2122\" file=\"ntkrla57.exe\" hash=\"d6fab8b9c68bdd88e5a6205aeacf3393d0352b508d05c6ed3c05933b250325dd\" timestamp=\"0x3ea36fb3\" size=\"0x01249000\" added=\"2024-10-12T01:50:50Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2130\" file=\"ntoskrnl.exe\" hash=\"536f45474dc70339b17be47777de2dc74731a69fa245c7eb2b858526d970fe22\" timestamp=\"0x3c4d45e0\" size=\"0x0144f000\" added=\"2024-10-19T15:36:45Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2130\" file=\"ntkrla57.exe\" hash=\"76b9af7f369833b557c4c13ceb2d368431ca75d9954d35c7f72b608fcbce9601\" timestamp=\"0xc702b587\" size=\"0x01249000\" added=\"2024-10-19T15:36:45Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2161\" file=\"ntoskrnl.exe\" hash=\"eef130017cf8e31807adf16170f65374dfd074092320c96adcfef89e4f5ac395\" timestamp=\"0xec211a59\" size=\"0x0144f000\" added=\"2024-10-26T06:39:10Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2161\" file=\"ntkrla57.exe\" hash=\"e2714e2f225161d273f5e4734db380368f7479f18ff670b4fb8568cfaabffbce\" timestamp=\"0xdacd70e5\" size=\"0x01249000\" added=\"2024-10-26T06:39:10Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2200\" file=\"ntoskrnl.exe\" hash=\"6941e2f87d9fc4d4b54c3b2925dbc8dae5d749ed68cc66fbeb8ad2da625133ac\" timestamp=\"0x75b061e6\" size=\"0x0144f000\" added=\"2024-10-26T06:39:10Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2200\" file=\"ntkrla57.exe\" hash=\"5839e146ece6d316402a152497e53e4a2394f4029bba09bb7bcee9cf38070ae5\" timestamp=\"0xd527eaab\" size=\"0x01249000\" added=\"2024-10-26T06:39:10Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2213\" file=\"ntoskrnl.exe\" hash=\"b9a47d9b206577b6c8ccb718ae0667df84b7e91bb8bb4ee622652e5a1b60349e\" timestamp=\"0xe25bc2fa\" size=\"0x0144f000\" added=\"2024-11-09T04:03:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2213\" file=\"ntkrla57.exe\" hash=\"2971ddd0f6f68a0d9cd5975f316ae08718c5b4331651f0063f32b6c8e749c925\" timestamp=\"0x023038d7\" size=\"0x01249000\" added=\"2024-11-09T04:03:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2222\" file=\"ntoskrnl.exe\" hash=\"ac74eac000f53078bf402a7e22829db30ae9d709cf71e6968b8bfd01036fe1f8\" timestamp=\"0x090d1c3d\" size=\"0x0144f000\" added=\"2024-11-09T04:03:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2222\" file=\"ntkrla57.exe\" hash=\"85c0deceba0a7c3cc0bdb040b11264b0c36c538ece6b6622bd824813d630ca77\" timestamp=\"0x8af285a1\" size=\"0x01249000\" added=\"2024-11-09T04:03:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2314\" file=\"ntoskrnl.exe\" hash=\"866bc13d7872cc9f7f1807d1d6bfac63ed9b761651c653258ec972eed493bd95\" timestamp=\"0x3c5028de\" size=\"0x0144f000\" added=\"2024-11-13T15:20:35Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2314\" file=\"ntkrla57.exe\" hash=\"a71c16e34017ac4d35c131ad8a420fb50e703020a800544439c981905d7f145b\" timestamp=\"0x8f8d6d39\" size=\"0x01249000\" added=\"2024-11-13T15:20:35Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2415\" file=\"ntoskrnl.exe\" hash=\"20ebb5b9ff0a1f31fbd47418926375f974e528be43744daa80d2e669d89d671e\" timestamp=\"0xfcd8664a\" size=\"0x0144f000\" added=\"2024-11-24T17:20:19Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2415\" file=\"ntkrla57.exe\" hash=\"2e8aed335094af832f5c772596e356ba1fba5139aa99bb0f5d0ade29856bd840\" timestamp=\"0x8a665510\" size=\"0x01249000\" added=\"2024-11-24T17:20:19Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2448\" file=\"ntoskrnl.exe\" hash=\"591d34d91113b4929ac2e16683e7bc697edbc81a8894d1fdfce5a9e004e9c865\" timestamp=\"0x5c7bfd80\" size=\"0x0144f000\" added=\"2024-11-21T19:38:04Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2448\" file=\"ntkrla57.exe\" hash=\"b177f877a561b9c7230e009c352cdc07d39eb5de38c3434d492947998e6f2b78\" timestamp=\"0xed395ad5\" size=\"0x01249000\" added=\"2024-11-21T19:38:04Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2454\" file=\"ntoskrnl.exe\" hash=\"7550d69115ee1a763ee92d26c24a8b340533f60bf61f06d79f282552850ab5a7\" timestamp=\"0x118b052e\" size=\"0x0144f000\" added=\"2024-11-19T23:28:40Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2454\" file=\"ntkrla57.exe\" hash=\"96f7d80ef1962b2ca2943eb05962d0871b2463e34de80de47cb1d517628a14d4\" timestamp=\"0x9772fc0a\" size=\"0x01249000\" added=\"2024-11-19T23:28:40Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2510\" file=\"ntoskrnl.exe\" hash=\"098fbf2a9ad9d7b3108376426443cfbb7cc3fd882cf20e173bd86c9350e671e9\" timestamp=\"0x47ec807b\" size=\"0x0144f000\" added=\"2024-12-10T02:56:39Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2510\" file=\"ntkrla57.exe\" hash=\"b1cb1d16d76170c42c3309db13e7cd02805b28e0341da436718fdc1b5a08bb8f\" timestamp=\"0xbedb4541\" size=\"0x01249000\" added=\"2024-12-10T02:56:39Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2605\" file=\"ntoskrnl.exe\" hash=\"5f71d2ec174651a1b573b5acc3172f1c626b3ba23e8f54e735166764da39a244\" timestamp=\"0x4f6c47b9\" size=\"0x0144f000\" added=\"2024-12-11T14:53:46Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2605\" file=\"ntkrla57.exe\" hash=\"05cf77a3a171847c1792b52c39e3b4176f62d29119b0f185e81a2cb8a03f3198\" timestamp=\"0x976be1c1\" size=\"0x01249000\" added=\"2024-12-11T14:53:46Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2702\" file=\"ntoskrnl.exe\" hash=\"d79a8fbc692e46916c781c2e10630587c2af326ddeee023fa4ae3b1e10468d45\" timestamp=\"0x3cbe3226\" size=\"0x0144f000\" added=\"2024-12-16T15:35:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2702\" file=\"ntkrla57.exe\" hash=\"cec7213e10335b764a59e359f0aeeec383dda4a45053bc8a80348df12f172f28\" timestamp=\"0xcf55fa72\" size=\"0x01249000\" added=\"2024-12-16T15:35:11Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2705\" file=\"ntoskrnl.exe\" hash=\"e71e5f17eb753d07c716fc2e0dfe2a3970194bc391ba54cb8bd8426263cebd6a\" timestamp=\"0x9ef47d92\" size=\"0x0144f000\" added=\"2024-12-19T19:52:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2705\" file=\"ntkrla57.exe\" hash=\"9da0301219c041d28ee32541f0cb99a96d41c5939cc00d74495aeed8da1c6083\" timestamp=\"0x4be80338\" size=\"0x01249000\" added=\"2024-12-19T19:52:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2894\" file=\"ntoskrnl.exe\" hash=\"7de227afd50c0981da7e6479893e0c820ac7d5e26fb55ebcfce25bbb0e80d687\" timestamp=\"0x23baf4bb\" size=\"0x0144f000\" added=\"2025-01-15T01:55:10Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2894\" file=\"ntkrla57.exe\" hash=\"813fe519703e23ae7f1b9191c307cbc58762525fd313961b6732f4f8cddda0ee\" timestamp=\"0x70cd8c03\" size=\"0x01249000\" added=\"2025-01-15T01:55:10Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2992\" file=\"ntoskrnl.exe\" hash=\"bc5f0ce39353cb982ff551a9eb36d043817eb2e3456a062929e8c5e676b35547\" timestamp=\"0x45849a5e\" size=\"0x0144f000\" added=\"2025-01-18T23:48:32Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.2992\" file=\"ntkrla57.exe\" hash=\"e8d7b3c51467d48b98753894b1e7010c445f5e5272428ee508f0e90e3c58b964\" timestamp=\"0xcdd658b1\" size=\"0x01249000\" added=\"2025-01-18T23:48:32Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3000\" file=\"ntoskrnl.exe\" hash=\"fd7e5abd92308e6bfe96c3b34f511be14a2397ca8fe754f7d80469c7ac94e489\" timestamp=\"0x69a12b52\" size=\"0x0144f000\" added=\"2025-01-25T15:27:45Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3000\" file=\"ntkrla57.exe\" hash=\"df60e8f7785ff4e998edbee3ba5dfb8c3f06fe87ed29d9acc5c27e3a50172281\" timestamp=\"0xf3d3aa10\" size=\"0x01249000\" added=\"2025-01-25T15:27:45Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3025\" file=\"ntoskrnl.exe\" hash=\"820764046804a30cade4b5d76775d6444e94a65f7c85a307c9a94e452672e9fc\" timestamp=\"0x3536b4d0\" size=\"0x0144f000\" added=\"2025-03-14T04:05:46Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3037\" file=\"ntoskrnl.exe\" hash=\"00e65cb6bb72e836d37ab1ec460bed22080d3de46623fc38e7921a0e850db87f\" timestamp=\"0x62ec3ba4\" size=\"0x0144f000\" added=\"2025-01-31T00:35:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3037\" file=\"ntkrla57.exe\" hash=\"34df53a1c6350a8925fb122cc43102d8b021f67fa7e712502dbb645e7042b385\" timestamp=\"0x09f17a3c\" size=\"0x01249000\" added=\"2025-01-31T00:35:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3073\" file=\"ntoskrnl.exe\" hash=\"9aa605f326ee6acbf9487ccca92b58268355ec87a6841210c225f08995f17e6a\" timestamp=\"0xc50dedcd\" size=\"0x0144f000\" added=\"2025-02-02T03:08:17Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3073\" file=\"ntkrla57.exe\" hash=\"a401e4e8eda7068854beaaf583ac41d92c2533f2851426a9f14e77de50af0a54\" timestamp=\"0x4e65c8a8\" size=\"0x01249000\" added=\"2025-02-02T03:08:17Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3194\" file=\"ntoskrnl.exe\" hash=\"f17b73cb132ac289bd40247685ee07e92786e7667cf50440c1a37d5110869e5f\" timestamp=\"0x2c2d16b3\" size=\"0x0144f000\" added=\"2025-02-12T06:18:33Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3194\" file=\"ntkrla57.exe\" hash=\"b096ee8a5ec4c6b5150c3d95923c3151d281a72c6ca3b302aff0550aebe27aa7\" timestamp=\"0x4b56bdbd\" size=\"0x01249000\" added=\"2025-02-12T06:18:33Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3281\" file=\"ntoskrnl.exe\" hash=\"aa88265f8849d69c4e45b19caad4a9d190a2bb411ec268cc29ddcdbd3ba05815\" timestamp=\"0xe0dffbc0\" size=\"0x0144f000\" added=\"2025-02-15T17:18:17Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3281\" file=\"ntkrla57.exe\" hash=\"d2cd956e9303f094946b1c938af49a8e7d05b446d8be3664d96122d92f1b9b5d\" timestamp=\"0x7bd9dd74\" size=\"0x01249000\" added=\"2025-02-15T17:18:17Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3291\" file=\"ntoskrnl.exe\" hash=\"efaf22a45cf838e96113401fbb4e9c2a1a347213293d7e926e2ab093ed1ccb73\" timestamp=\"0x56499a6a\" size=\"0x0144f000\" added=\"2025-02-22T16:10:41Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3291\" file=\"ntkrla57.exe\" hash=\"eb5540b55a4baa81b68bec894bac9bf1bc428354feb088c57fecfdd5979b24d2\" timestamp=\"0xedfd3e5e\" size=\"0x01249000\" added=\"2025-02-22T16:10:41Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3321\" file=\"ntoskrnl.exe\" hash=\"fa59db4baf650824d0acaef9804f7331eb0b4ce3914667ecdb3616150f60c3f6\" timestamp=\"0x713d37b9\" size=\"0x0144f000\" added=\"2025-02-26T02:04:23Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3321\" file=\"ntkrla57.exe\" hash=\"14d9731c9a84f059633b10f338d069fd19c66911d0f96af7ec9f07ee0392fe5d\" timestamp=\"0x68081f87\" size=\"0x01249000\" added=\"2025-02-26T02:04:23Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3323\" file=\"ntoskrnl.exe\" hash=\"95e38650e89f0151e35e27e2b71f505d52304c117eddcb448969e85c1657427d\" timestamp=\"0x1213f5f7\" size=\"0x0144f000\" added=\"2025-02-26T02:04:23Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3323\" file=\"ntkrla57.exe\" hash=\"bdcd665e8fa6c2ed337fa79e6eb3df290a002e2094c9ee9382964188781d8cba\" timestamp=\"0x3a4642bf\" size=\"0x01249000\" added=\"2025-02-26T02:04:23Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3360\" file=\"ntoskrnl.exe\" hash=\"03611a6d52cd6492b0da15c98a9086d972934411c3fa5e93d45a1248c16a6f3f\" timestamp=\"0x2bf4ac37\" size=\"0x0144f000\" added=\"2025-03-02T06:42:51Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3360\" file=\"ntkrla57.exe\" hash=\"3f52cb45e101d6e6c144f8733e4d88978282e93341a4c8b419495e8e4a5d73a2\" timestamp=\"0xd529c7a0\" size=\"0x01249000\" added=\"2025-03-02T06:42:51Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3380\" file=\"ntoskrnl.exe\" hash=\"67973ee3fd1991aca7fc1c078d568bf2075689b9338907034af47d8f95131e7f\" timestamp=\"0xce02d8e7\" size=\"0x0144f000\" added=\"2025-03-11T02:45:33Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3380\" file=\"ntkrla57.exe\" hash=\"73e83010e48a4409dbfa707eb1de4587d8b711626b62cf7fb799bdb6e13a240e\" timestamp=\"0xa9ad2dc5\" size=\"0x01249000\" added=\"2025-03-11T22:25:17Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3470\" file=\"ntoskrnl.exe\" hash=\"b4dc29d7bf913058e67da49fdd46e47781c67b5d1e7aa0cd912d709756802a6c\" timestamp=\"0x9afa6206\" size=\"0x0144f000\" added=\"2025-03-19T05:55:37Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3470\" file=\"ntkrla57.exe\" hash=\"ac2053a59f9d7dcea11c2cc7aabdd7d427fd063d0ba4e72aea97e6f9e7bd5401\" timestamp=\"0xadaaac49\" size=\"0x01249000\" added=\"2025-03-11T22:25:17Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3476\" file=\"ntoskrnl.exe\" hash=\"0fb338e78146cda5eca21415a88be60da38121df48e1b3e9e73401ee9184fbce\" timestamp=\"0x783a7a83\" size=\"0x0144f000\" added=\"2025-03-14T04:05:46Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3575\" file=\"ntoskrnl.exe\" hash=\"4793d3194572ff7688a29ad67204327bf76e6c0a4bc5d97d2c1a0b325991d5d4\" timestamp=\"0x1c9bf602\" size=\"0x0144f000\" added=\"2025-03-19T05:55:37Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3575\" file=\"ntkrla57.exe\" hash=\"5d6901065546042a3c1da5bfed8f2a398fe2d410934eebc2daff7efd876f296c\" timestamp=\"0xbfb718c6\" size=\"0x01249000\" added=\"2025-03-19T05:55:37Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3585\" file=\"ntoskrnl.exe\" hash=\"244edb44be48742204f614780ab442df4172fcb6fde06ee3e3ec23458c04ca01\" timestamp=\"0x059181ec\" size=\"0x0144f000\" added=\"2025-03-28T03:59:19Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3585\" file=\"ntkrla57.exe\" hash=\"dd38b05103bae175b8ed9c821417b28d5c6a25e672ade6cf8bea062ffc5af830\" timestamp=\"0x2325c179\" size=\"0x01249000\" added=\"2025-03-28T03:59:19Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3613\" file=\"ntoskrnl.exe\" hash=\"0a5e666e859ec16f939b82dc1685abc8ad99c9359cf3a861de5b46dc09238cb3\" timestamp=\"0xa3436f90\" size=\"0x0144f000\" added=\"2025-03-28T03:59:19Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3613\" file=\"ntkrla57.exe\" hash=\"eb3c639b2ba1468ff45cd9146e7ed49c529e6989b86336e81cbb1aa1fa4cc6bd\" timestamp=\"0xde571e4f\" size=\"0x01249000\" added=\"2025-03-28T03:59:19Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3624\" file=\"ntoskrnl.exe\" hash=\"7bda94993a4ca9a70036d744c729745bbee0e3489a7f82c337003dab7efe153c\" timestamp=\"0x232cc48a\" size=\"0x0144f000\" added=\"2025-03-28T03:59:19Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3624\" file=\"ntkrla57.exe\" hash=\"58e2309e57156cfd1068e35391bdc99e25849387a5a9086e004def4191fb871b\" timestamp=\"0x56409b58\" size=\"0x01249000\" added=\"2025-03-28T03:59:19Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3653\" file=\"ntoskrnl.exe\" hash=\"ef8bfc3c4fade20c821475c48957139666b5169247e44735693594604f18e0e7\" timestamp=\"0x9d2bdec5\" size=\"0x01450000\" added=\"2025-03-29T06:48:24Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3653\" file=\"ntkrla57.exe\" hash=\"f5a167d5764106704a2009d0e6d453f2d0e0a17c832e814206292acb385fc71b\" timestamp=\"0x18caaae6\" size=\"0x01249000\" added=\"2025-03-29T06:48:24Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3671\" file=\"ntoskrnl.exe\" hash=\"c2509bebf67297d22aba14bae5d83946b0ca35ada1b75689a38e5bac4a113757\" timestamp=\"0x53dca85d\" size=\"0x01450000\" added=\"2025-04-05T04:20:29Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3671\" file=\"ntkrla57.exe\" hash=\"6ae3f36f09bf4a470737b9e61ce34c2ebd61a2e8eb862308883acfb8dceffe11\" timestamp=\"0xa6e0362d\" size=\"0x01249000\" added=\"2025-04-05T04:20:29Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3775\" file=\"ntoskrnl.exe\" hash=\"e27e76b272cac6ae91a1d93a419ec1007822c65d7c35debcc6a596dcfb065503\" timestamp=\"0x8563e5cd\" size=\"0x0144f000\" added=\"2025-04-09T14:22:28Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3775\" file=\"ntkrla57.exe\" hash=\"c44638001f9c143a27ee103b7643bd110d2d2cd2f4dcd3078f4f4e93dde0e9fa\" timestamp=\"0xe03341b2\" size=\"0x01249000\" added=\"2025-04-09T14:22:28Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3781\" file=\"ntoskrnl.exe\" hash=\"bf21e19605f3e72660b641fcbcd45db8deea29bcf3cef51ccf4ac86378ec90f3\" timestamp=\"0x8a602e81\" size=\"0x0144f000\" added=\"2025-04-19T15:54:38Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3781\" file=\"ntkrla57.exe\" hash=\"e478de2164cd870e130a146196a64d6de0e90139350af19398ef0ee6a151207a\" timestamp=\"0xb292a081\" size=\"0x01249000\" added=\"2025-04-19T15:54:38Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3863\" file=\"ntoskrnl.exe\" hash=\"d4e9128c0157d22b135084e56756ee434c14cc2dcaaf8ad4092ada835f4b2d6c\" timestamp=\"0xdb3660c8\" size=\"0x01450000\" added=\"2025-04-12T23:13:14Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3863\" file=\"ntkrla57.exe\" hash=\"c8e919de28e6b4f29793b2cd6cb78533b029dfb06045d8e9d98ad486fc056172\" timestamp=\"0x89405deb\" size=\"0x01249000\" added=\"2025-04-12T23:13:14Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3872\" file=\"ntoskrnl.exe\" hash=\"6b735542da9538de20061c1918d4fb367c8dc207907cff7dcce794cdb5c5b9dc\" timestamp=\"0xc047ab9d\" size=\"0x01450000\" added=\"2025-04-23T00:45:13Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3872\" file=\"ntkrla57.exe\" hash=\"b6eb2af3d8bed6e6045b70050e69eff25f87a2ff9101d720971d27dc91c5838f\" timestamp=\"0xa6cefad7\" size=\"0x01249000\" added=\"2025-04-23T00:45:13Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3902\" file=\"ntoskrnl.exe\" hash=\"689fd236ba45cfea4e04fef2cea0258931ec4b219a8553644ca63f4b5f7c8277\" timestamp=\"0xdf18516a\" size=\"0x01450000\" added=\"2025-05-01T02:24:25Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3902\" file=\"ntkrla57.exe\" hash=\"14faae021515a15951928c792c5dae129c11653fbeaa844a42e813178c8c17f2\" timestamp=\"0x702b3be3\" size=\"0x01249000\" added=\"2025-05-01T02:24:25Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3909\" file=\"ntoskrnl.exe\" hash=\"f1cb8ed5fe6dbec95349c866862d0e1aa631990bff9c5ffb33127c408c05a1ab\" timestamp=\"0x3eb5820e\" size=\"0x01450000\" added=\"2025-05-01T02:24:25Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3909\" file=\"ntkrla57.exe\" hash=\"b63b47e5c87a83517edeef32445d5e6897676e888481b97c93e04bce08661091\" timestamp=\"0xe1c00af9\" size=\"0x01249000\" added=\"2025-05-01T02:24:25Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3911\" file=\"ntoskrnl.exe\" hash=\"88c0c138f185e555420499d39f65cc9fa216b326fa343e02217c61033c583a40\" timestamp=\"0x05676a96\" size=\"0x01450000\" added=\"2025-04-26T20:45:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3912\" file=\"ntoskrnl.exe\" hash=\"be454a67222d5aa5ae2bdf54f1f923a39c7e39eb255f1c7600b1b8e8e6c42569\" timestamp=\"0xb38df1b6\" size=\"0x01450000\" added=\"2025-04-26T20:45:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3912\" file=\"ntkrla57.exe\" hash=\"54210034c3775d1e6392180fb51eb98bc23b37df724b6ee3fbfc54fa6cabf1e1\" timestamp=\"0xf7b844b3\" size=\"0x01249000\" added=\"2025-04-26T20:45:50Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3941\" file=\"ntoskrnl.exe\" hash=\"6588c6b3ccbfa7a17631138c023f9acad65d0c922d7466df2ff5e05ef5b5e2be\" timestamp=\"0xe25878dd\" size=\"0x01450000\" added=\"2025-04-26T20:45:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3941\" file=\"ntkrla57.exe\" hash=\"220158a9b168fe05104141d402e5d497193cafb197cc79f2fa9ad6d88b35fab5\" timestamp=\"0x63846b70\" size=\"0x01249000\" added=\"2025-04-26T20:45:50Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3950\" file=\"ntoskrnl.exe\" hash=\"29d87d148b9c5b15b404e61478436c618f2293c525d25965c5674c9f5701cdb2\" timestamp=\"0xbef570d4\" size=\"0x01450000\" added=\"2025-05-10T01:12:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3950\" file=\"ntkrla57.exe\" hash=\"8573019f256f07d9953ed3fa9be9075497264739f47344e79e340b0eaee732f3\" timestamp=\"0xa1a75ced\" size=\"0x01249000\" added=\"2025-05-10T01:12:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3961\" file=\"ntoskrnl.exe\" hash=\"6fd2c69f15048cf5fc4fa643ff4214c34e86533f34f0d7e765e3f579cc499479\" timestamp=\"0x8c8fee61\" size=\"0x01450000\" added=\"2025-05-13T22:56:23Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3964\" file=\"ntoskrnl.exe\" hash=\"9ba44bf7dc4d190efd7ee7ea2f660566462efd373ac038fa2e53aeb5b7724c5f\" timestamp=\"0x62ff1e42\" size=\"0x01450000\" added=\"2025-05-13T22:56:23Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.3964\" file=\"ntkrla57.exe\" hash=\"7c450e9aa3958be71c8f70eca9c8215699b871710e61d82eeec5bc6a72b66639\" timestamp=\"0xcc716044\" size=\"0x01249000\" added=\"2025-05-13T22:56:23Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4054\" file=\"ntoskrnl.exe\" hash=\"8e343a6d87ca9ca3b68975a92dc9d308f73f4a6ac671408203bdecc333bdf261\" timestamp=\"0x734b9cdd\" size=\"0x01450000\" added=\"2025-05-13T22:56:23Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4061\" file=\"ntoskrnl.exe\" hash=\"6906ccc9622e7f3bd9a152c1f164418e19a26003c6c5081421c6fe5e4a957949\" timestamp=\"0x2f1befc4\" size=\"0x01450000\" added=\"2025-05-13T22:56:23Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4061\" file=\"ntkrla57.exe\" hash=\"4c2b5afb62fe7de619f3a94fc83b2c5fec866cc8e5cf514f73ce468463632d43\" timestamp=\"0x214c1276\" size=\"0x01249000\" added=\"2025-05-13T22:56:23Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4151\" file=\"ntoskrnl.exe\" hash=\"df7737fb13e7afa45615dd813ba7b65db90a1fcb185c70bff74ead678e740336\" timestamp=\"0x1e410658\" size=\"0x01450000\" added=\"2025-05-19T22:45:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4151\" file=\"ntkrla57.exe\" hash=\"efdc6eb3815391a21ae4ef082ff2073280c2c1c31ea540e69c85546176251144\" timestamp=\"0x97365999\" size=\"0x01249000\" added=\"2025-05-22T02:15:04Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4161\" file=\"ntoskrnl.exe\" hash=\"e6dff74b2a9728d3a711424fa21815b18213a93211afab7db289dea7d31160a1\" timestamp=\"0x651f9b3a\" size=\"0x01450000\" added=\"2025-05-24T14:17:56Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4161\" file=\"ntkrla57.exe\" hash=\"a0a168d2f25dfa47acab24723e0bd7e2f55738a164ecc72c04aa58595b6f94f0\" timestamp=\"0x6df1e0d9\" size=\"0x01249000\" added=\"2025-05-24T14:17:56Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4187\" file=\"ntoskrnl.exe\" hash=\"528b2f3c1b3f0a2b9ec1c4aa14eb400c01e9e371c5f7976de2cc9cbd4e65915a\" timestamp=\"0x8935d0ef\" size=\"0x01450000\" added=\"2025-05-31T18:37:56Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4202\" file=\"ntoskrnl.exe\" hash=\"c14d40119ff8d601a98abbdbbb3f15ae6205836b3c7155ff91f7d4f28ba10e2f\" timestamp=\"0x3e411397\" size=\"0x01450000\" added=\"2025-05-29T05:57:37Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4202\" file=\"ntkrla57.exe\" hash=\"3c17ce874da965132d36632c420632934fd3f64aa6fa1f0b7b3bc87e30acde7c\" timestamp=\"0xe4a055d9\" size=\"0x01249000\" added=\"2025-05-29T05:57:37Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4230\" file=\"ntoskrnl.exe\" hash=\"f4417eb4dd0ea3e497e38503ff3c0d4746f5d6a262b71f272d4356bb340a24f3\" timestamp=\"0xc830c430\" size=\"0x01450000\" added=\"2025-06-07T14:16:57Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4230\" file=\"ntkrla57.exe\" hash=\"14c4f450733e4e76cf14287e39b7e38e3907d33f0757ef512a063f56897b9615\" timestamp=\"0x87e608fd\" size=\"0x01249000\" added=\"2025-06-07T14:16:57Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4250\" file=\"ntoskrnl.exe\" hash=\"5a7fb8e9214f77d8ad95c81af7373bc00c12de2e5969697ea3f4fedbdb4c9807\" timestamp=\"0x6d241093\" size=\"0x01450000\" added=\"2025-06-10T13:19:34Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4250\" file=\"ntkrla57.exe\" hash=\"44959c7d54d5541c7bff821a1829fcba6a733ff76573cf070330533b05971d61\" timestamp=\"0x91e96cf7\" size=\"0x01249000\" added=\"2025-06-10T13:19:34Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4343\" file=\"ntoskrnl.exe\" hash=\"e8a8064931b1217e2341644f5013046d56d3dc3e909bd9f1cb40da03f65c53d2\" timestamp=\"0xb59c4c7d\" size=\"0x01450000\" added=\"2025-06-11T00:42:44Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4343\" file=\"ntkrla57.exe\" hash=\"fd8911312a6e34c9418b56314256b0d3d82aa44f396786a0428b99967de5c79d\" timestamp=\"0x354a112a\" size=\"0x01249000\" added=\"2025-06-11T00:42:44Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4351\" file=\"ntoskrnl.exe\" hash=\"eb3aff3f0c7d210e31dc8da896493b2f74dbafe8ebf2c10b0600e33cb3139aa2\" timestamp=\"0x2ff2403a\" size=\"0x01450000\" added=\"2025-06-13T19:27:57Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4351\" file=\"ntkrla57.exe\" hash=\"6dfe1f4e2ede83b6b31e701c2775a9508fc0dfe277c53f355acb0b57baf3d56a\" timestamp=\"0x91fd333e\" size=\"0x01249000\" added=\"2025-06-13T19:27:57Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4441\" file=\"ntoskrnl.exe\" hash=\"fe4e5fed0d2d7f15604606998b5c9970bea63d1dd45440d52357549403dccaf3\" timestamp=\"0xe4f2ed6e\" size=\"0x01450000\" added=\"2025-06-13T19:27:57Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4441\" file=\"ntkrla57.exe\" hash=\"1997ab55e94c4d4f5edbe4a33deeafe897a5abadac6943e5f245c1fbf20c8a83\" timestamp=\"0xd6c0997e\" size=\"0x01249000\" added=\"2025-06-14T19:47:51Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4451\" file=\"ntoskrnl.exe\" hash=\"d8a93904f15afc1554b7fb9d012631480a878a190ee1b8375e7fd2075bba0772\" timestamp=\"0xfed79731\" size=\"0x01450000\" added=\"2025-06-24T22:12:14Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4452\" file=\"ntoskrnl.exe\" hash=\"49ea2c5df1ad188d8234b988d10c4b7c1ef87941c2482b7410a6bac42b5f7544\" timestamp=\"0x72617fb5\" size=\"0x01450000\" added=\"2025-06-23T23:25:34Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4452\" file=\"ntkrla57.exe\" hash=\"efd3fda225cc2e332ead51a32df9e1a99a45fbc3f9cba2ed0ea5f0ee721b1e8d\" timestamp=\"0x654abc9d\" size=\"0x01249000\" added=\"2025-06-24T22:12:14Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4483\" file=\"ntoskrnl.exe\" hash=\"71eab33fdf7fc3647c5658f58ab831117e5469dc1ab39e486d59f43d51da2ab2\" timestamp=\"0xdf8c8ab0\" size=\"0x01450000\" added=\"2025-06-28T02:27:55Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4484\" file=\"ntoskrnl.exe\" hash=\"1b006febd10410d7db9af56176115ecd4aa5ddc72cee7d180971404b725bcc6b\" timestamp=\"0xabca3b79\" size=\"0x01450000\" added=\"2025-06-26T22:28:04Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4484\" file=\"ntkrla57.exe\" hash=\"2b4cf2208f2673b73cc2f5688a866fbc81ac8b820a24240e73315e9f889f75f2\" timestamp=\"0x96a09b4f\" size=\"0x01249000\" added=\"2025-06-26T22:28:04Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4520\" file=\"ntoskrnl.exe\" hash=\"6b814749be125338c675d6e78573ec675b040dd6ff858f943239e81c3c51696d\" timestamp=\"0x4e674526\" size=\"0x01450000\" added=\"2025-06-28T02:27:55Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4520\" file=\"ntkrla57.exe\" hash=\"f51de793ebb1fce00ce50ca204f5462702a9e49524d0b4d5c38cc847159bd1c4\" timestamp=\"0x1311b8ed\" size=\"0x01249000\" added=\"2025-06-28T15:48:40Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4648\" file=\"ntoskrnl.exe\" hash=\"30840dd944070e8dac1f6d5cb57c15b8e85f81df54d1a53d8ce65bbb8f3e3afb\" timestamp=\"0x3740ef51\" size=\"0x01450000\" added=\"2025-07-10T01:24:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4652\" file=\"ntoskrnl.exe\" hash=\"593136dedfc7151185458ef2a2eb1a7c216b3ac0145097c1e1d97eaa911e23b5\" timestamp=\"0x3441f715\" size=\"0x01450000\" added=\"2025-07-08T22:13:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4652\" file=\"ntkrla57.exe\" hash=\"77fd92dfa53ec9c2b4f759a87650a1b9cf8faaa954b94e4d7ca05a4e3c54e825\" timestamp=\"0x576c15f2\" size=\"0x01249000\" added=\"2025-07-08T22:13:00Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4656\" file=\"ntoskrnl.exe\" hash=\"1db0766097e5fd89d95c7926a1142b80847cd4b12eb647e399ff3b70f2ffe4d5\" timestamp=\"0xcbf2855a\" size=\"0x01450000\" added=\"2025-07-17T01:08:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4656\" file=\"ntkrla57.exe\" hash=\"a9173ec613d17f210f72d91eb19e2011fd3c267b6efbf01eef9e2a5c36bca974\" timestamp=\"0xadc86a72\" size=\"0x01249000\" added=\"2025-07-17T01:08:50Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4733\" file=\"ntoskrnl.exe\" hash=\"4b1ec5469ef0df34416902436ccf80086ba50cf337f2cd6794e836da7cffd5cb\" timestamp=\"0x792cc79a\" size=\"0x01450000\" added=\"2025-07-17T01:08:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4733\" file=\"ntkrla57.exe\" hash=\"05b7b301b27c86d31d9133697a711a0748c6bb5302ddf1daa54134bc4c7272c1\" timestamp=\"0xad72ff57\" size=\"0x01249000\" added=\"2025-07-17T01:08:50Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4741\" file=\"ntoskrnl.exe\" hash=\"a5919f060893f0b4aad242832e374bfbfc680669ca4969a35fb2339db27e2b05\" timestamp=\"0x2f8adab3\" size=\"0x0144f000\" added=\"2025-07-19T02:10:13Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4741\" file=\"ntkrla57.exe\" hash=\"176a3edee0692b5ad8cba6d6042ed065e30d4f355c7fd7d6585b215c6061dd6c\" timestamp=\"0x96e9b72a\" size=\"0x01249000\" added=\"2025-07-21T06:28:17Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4741\" file=\"lxcore.sys\" hash=\"ad58fbdd725df004c2af4274fc9334094d01ccbe6ab1400c4a4992b5920014a5\" timestamp=\"0x5d839e9d\" size=\"0x00110000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4762\" file=\"ntoskrnl.exe\" hash=\"47918cbc6cb0c4061de7b92cedff10cd885fbbe93d256b34d1d4990cd2817ffd\" timestamp=\"0x5eee6faa\" size=\"0x01450000\" added=\"2025-07-23T02:01:02Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4762\" file=\"ntkrla57.exe\" hash=\"14fc0c897e39ef7aa71e70896eb305caa81e0b9d66ed66826abd06b6b09f44ce\" timestamp=\"0x4409bd2e\" size=\"0x01249000\" added=\"2025-07-23T02:01:02Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4768\" file=\"ntoskrnl.exe\" hash=\"9b00ca17004d0c1a9af2cbf02f8b9d9f219d296e0c83e4bd66057547a77df688\" timestamp=\"0x5e6287d1\" size=\"0x01450000\" added=\"2025-07-23T02:01:02Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4768\" file=\"ntkrla57.exe\" hash=\"e8e2320749c016ef9ed02ebd67669df1256497b5663c02070bc8692ad9a362ea\" timestamp=\"0x8bf0d2fc\" size=\"0x01249000\" added=\"2025-07-23T02:01:02Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4946\" file=\"ntoskrnl.exe\" hash=\"e5a221f557eb03d7e1a8ec6b6aea6f698eff974eafb13cfaa9317b65ba47e935\" timestamp=\"0x93dad125\" size=\"0x01450000\" added=\"2025-08-13T21:37:12Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.4946\" file=\"ntkrla57.exe\" hash=\"36f1f1881519b09c5eda56937a2dfcc321ddde012dfc6d862441b4d514188797\" timestamp=\"0x5c0b96b5\" size=\"0x01249000\" added=\"2025-08-13T21:37:12Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5059\" file=\"ntoskrnl.exe\" hash=\"1a15589d458f49f741770c69d026fb61a4343fc4fa95016cb8db384a249bd132\" timestamp=\"0x78b28752\" size=\"0x0144f000\" added=\"2025-08-30T18:01:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5061\" file=\"ntoskrnl.exe\" hash=\"7567b87061af11e756fe60ac01fed3e913cbb8aa0d84d92cde2419b936feb775\" timestamp=\"0xaafc29ec\" size=\"0x0144f000\" added=\"2025-08-29T21:12:06Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5061\" file=\"ntkrla57.exe\" hash=\"09d78a4f2eebc42aa388cf569d03ff7a3f87fed03ff68a5ef16503ed12a4adf4\" timestamp=\"0x7c016a90\" size=\"0x01249000\" added=\"2025-08-29T21:12:06Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5074\" file=\"ntoskrnl.exe\" hash=\"6975ad867e4b7795f8ddb23a798d04a19753781b40be607736366e8244303ebf\" timestamp=\"0xc65d8c5f\" size=\"0x0144f000\" added=\"2025-08-29T21:12:06Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5074\" file=\"ntkrla57.exe\" hash=\"24b30a5a1b218ea70bd120e65fce9aa132ce39d70b2618f52b2f809f74d684ed\" timestamp=\"0x635b692e\" size=\"0x01249000\" added=\"2025-08-30T18:01:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5074\" file=\"lxcore.sys\" hash=\"14599af079bdf9e5d6e1a45a69477d1e4074615bbfc0facd11802f0f32d8ee38\" timestamp=\"0xd503cbdf\" size=\"0x00110000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5510\" file=\"ntoskrnl.exe\" hash=\"2e4348080b9e7a299a3ec83401fbb971e48d2dddc1331fea3df4680ba55f9265\" timestamp=\"0xea11f98e\" size=\"0x0144f000\" added=\"2025-03-28T03:59:19Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5510\" file=\"ntkrla57.exe\" hash=\"ce5796a898dce7ec8f892d51b9edc9db1448bdde0cf66abbae2c3c3659215231\" timestamp=\"0x7cb329e3\" size=\"0x01249000\" added=\"2025-03-28T03:59:19Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5516\" file=\"ntoskrnl.exe\" hash=\"722174bc81ecab83b4cf5d56e2b02b58d6e08bb2c5a03bce163463e325c44818\" timestamp=\"0x710d49a1\" size=\"0x01450000\" added=\"2025-03-29T06:48:24Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5516\" file=\"ntkrla57.exe\" hash=\"23fef9204b011102f4303b8dc6e598abbe8f69d01a558167eb5e9d58aca96020\" timestamp=\"0x63e8986d\" size=\"0x01249000\" added=\"2025-03-29T06:48:24Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5518\" file=\"ntoskrnl.exe\" hash=\"48a0dee190a5250fbc7bfd5c3fab39a7a09d4b9b98eb5f64c0b047ab8faf6227\" timestamp=\"0xa3ec569a\" size=\"0x01450000\" added=\"2025-04-05T04:20:29Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5518\" file=\"ntkrla57.exe\" hash=\"1174eab9d39a69c9ebdfa38d0bc37bd71e1dbef5c82d0b6049cd65944b0e3d00\" timestamp=\"0x89196645\" size=\"0x01249000\" added=\"2025-04-05T04:20:29Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5551\" file=\"ntoskrnl.exe\" hash=\"c82f17c9da5073ab75e25090be0768cc7aa04902a8320eb665e944720ffb4780\" timestamp=\"0x48fe52d8\" size=\"0x01450000\" added=\"2025-04-12T23:13:14Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5551\" file=\"ntkrla57.exe\" hash=\"5d679d14c0c9d6b3580b7d1914e4e1bb321d84d034d5439522544ecf94c18e46\" timestamp=\"0x6217b6b1\" size=\"0x01249000\" added=\"2025-04-12T23:13:14Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5562\" file=\"ntoskrnl.exe\" hash=\"6955d5411e8047946e05d10e7f1e59a2b106ab80b573e1680d450bf517f2b54d\" timestamp=\"0x8d8fc078\" size=\"0x01450000\" added=\"2025-04-23T00:45:13Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5562\" file=\"ntkrla57.exe\" hash=\"6de73a932d7c248d1cc621bccc162384fffe25fedb10807d9da1d2e038ecc711\" timestamp=\"0x591dc9ba\" size=\"0x01249000\" added=\"2025-04-23T00:45:13Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5570\" file=\"ntoskrnl.exe\" hash=\"60617ee7a4ce3bb3435f752d641ace2b03bec2296664af38158ca1af0c59af6b\" timestamp=\"0xdef939cd\" size=\"0x01450000\" added=\"2025-04-26T20:45:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5570\" file=\"ntkrla57.exe\" hash=\"a5519e7dbfee6ea242a7cb35cd411c9ff0741884f1a3da9b15ee2cf6f1a065e9\" timestamp=\"0x9b949791\" size=\"0x01249000\" added=\"2025-04-26T20:45:50Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5581\" file=\"ntoskrnl.exe\" hash=\"ef752a4d1783214113619e3a4b2f510e2ee97806264bd6968d1b1f167b8179ba\" timestamp=\"0x5a8173eb\" size=\"0x01450000\" added=\"2025-05-10T01:12:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5581\" file=\"ntkrla57.exe\" hash=\"8507f6e3f3e0a4e105739592750ff5a25f791014c6efa05de33c78d7f6eb49fa\" timestamp=\"0x7ae33060\" size=\"0x01249000\" added=\"2025-05-10T01:12:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5590\" file=\"ntoskrnl.exe\" hash=\"b8c3a9627eaa49cc0ae5839f67fd83772e2d342f22e89b99fe36e6e83bf6e9ef\" timestamp=\"0x8ba0d7c5\" size=\"0x01450000\" added=\"2025-05-13T22:56:23Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5600\" file=\"ntoskrnl.exe\" hash=\"68ab1eda086bf73ffee96c86ab3cd790567a0711230cfaae4106829c0ab64807\" timestamp=\"0x16c1cd66\" size=\"0x01450000\" added=\"2025-05-13T22:56:23Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5600\" file=\"ntkrla57.exe\" hash=\"53716bd78ac0040337bdc995697271d9538444c83a56324c0a15b721f15206f9\" timestamp=\"0xed58d301\" size=\"0x01249000\" added=\"2025-05-13T22:56:23Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5601\" file=\"ntoskrnl.exe\" hash=\"072fafd8c2050bc31b2726ece916a02c072fbb9b87dab50f15d29dbbdff5b6c2\" timestamp=\"0xb969aefa\" size=\"0x01450000\" added=\"2025-05-22T02:15:04Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5603\" file=\"ntoskrnl.exe\" hash=\"b674513d59b5ba96dfc4df2db9a9d14b758bed3324a6ca0b8643cf93151c7b5c\" timestamp=\"0xc6b7eb34\" size=\"0x01450000\" added=\"2025-05-19T22:45:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5603\" file=\"ntkrla57.exe\" hash=\"c6c5986de68e314d06bc4f29bcac9e774db9defec636f46f369c07d3e68ef89d\" timestamp=\"0x56184a2a\" size=\"0x01249000\" added=\"2025-05-22T02:15:04Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5622\" file=\"ntoskrnl.exe\" hash=\"90968802c4087dd523804718c504e2c943f733935258394a24622e6c71067988\" timestamp=\"0x42b912bf\" size=\"0x01450000\" added=\"2025-06-07T14:16:57Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5622\" file=\"ntkrla57.exe\" hash=\"1a358a6ecf987fd302adf1db8e919f87c43a237f466287b96d9f1ddef4d20985\" timestamp=\"0x1415c1f3\" size=\"0x01249000\" added=\"2025-06-07T14:16:57Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5641\" file=\"ntoskrnl.exe\" hash=\"39eb6fb31b6d6c1e81e84cec7941e59d6c7589f819461691c38b6e1c60cb56c7\" timestamp=\"0xb8b5bd3b\" size=\"0x0144f000\" added=\"2025-06-10T13:19:34Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5641\" file=\"ntkrla57.exe\" hash=\"83215146f61222ec4ab1758770a25ef1dcb0a30572cd5c74ab898c3ceacf61a7\" timestamp=\"0x7ead0944\" size=\"0x01249000\" added=\"2025-06-10T13:19:34Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5651\" file=\"ntoskrnl.exe\" hash=\"11daa8217ae8bb687a7fe71fc4adfe316d6c91282b0bbc7b2fa307235cf3da6e\" timestamp=\"0x7d520842\" size=\"0x0144f000\" added=\"2025-06-13T19:27:57Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5651\" file=\"ntkrla57.exe\" hash=\"7a06a10d8a125facfae7d462e08cd5e82838b288fb43c47ad17ca3d7d1ed8a84\" timestamp=\"0x6c9489a7\" size=\"0x01249000\" added=\"2025-06-13T19:27:57Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5661\" file=\"ntoskrnl.exe\" hash=\"2138066b02c0da7c05b31ddb451bf1ef7b7eefc35d2c0b72ba45727e98c898de\" timestamp=\"0xbf7699cf\" size=\"0x0144f000\" added=\"2025-06-24T22:12:14Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5661\" file=\"ntkrla57.exe\" hash=\"8aa96b1fa1d645ccdd5d177e71c5a06d938b5db446b498d2dbdcfc881e08ad63\" timestamp=\"0x658d0ba7\" size=\"0x01249000\" added=\"2025-06-24T22:12:14Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5670\" file=\"ntoskrnl.exe\" hash=\"2677fa2f87ae41c4b49c44dc62c63c0948e9bb728b736d41c17839b08b75308a\" timestamp=\"0x34d08988\" size=\"0x0144f000\" added=\"2025-06-28T02:27:55Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5670\" file=\"ntkrla57.exe\" hash=\"6729476921e67d36a975a24edbed73c40026ebde76f5ca557c165638b2222d33\" timestamp=\"0x04cfdfa2\" size=\"0x01249000\" added=\"2025-06-28T15:48:40Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5702\" file=\"ntoskrnl.exe\" hash=\"8d351c46b2208759c0bd0341af015d911d948cfb4d3c759b7923d80702d9b78a\" timestamp=\"0x246e73d7\" size=\"0x0144f000\" added=\"2025-07-17T01:08:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5702\" file=\"ntkrla57.exe\" hash=\"094076625e4ecbb1a98f18d70a3c6a92f74a33cf0685663d408e26ee71f4b7fa\" timestamp=\"0x1143c524\" size=\"0x01249000\" added=\"2025-07-17T01:08:50Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5710\" file=\"ntoskrnl.exe\" hash=\"3dcbf9ca85d9a905c9c0c930b9af04a4bc5447d1c79e9ee3251ba4643441084c\" timestamp=\"0x0530042e\" size=\"0x0144f000\" added=\"2025-07-19T02:10:13Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5710\" file=\"ntkrla57.exe\" hash=\"56a814dae2f8434763eb2a644ce700db79942a7ea60c080698d89b55eb8de108\" timestamp=\"0xdcbde547\" size=\"0x01249000\" added=\"2025-07-21T06:28:17Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5720\" file=\"ntoskrnl.exe\" hash=\"4e4281ff037b6664539a9afa9f112c91802d0bf870f648a3a1f09a66aeb86e43\" timestamp=\"0xd34705aa\" size=\"0x0144f000\" added=\"2025-07-29T22:48:22Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5722\" file=\"ntoskrnl.exe\" hash=\"c76a8bf7decaa88cb4abd62885514bed341dae54c1872d613276d98acb5be4ab\" timestamp=\"0x70ba8960\" size=\"0x0144f000\" added=\"2025-07-29T22:48:22Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5722\" file=\"ntkrla57.exe\" hash=\"f43423caeb70a170a5097916d7a8163a62d537ee9d5822ede37051c1de10c5e5\" timestamp=\"0xc100111b\" size=\"0x01249000\" added=\"2025-07-29T22:48:22Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5733\" file=\"ntoskrnl.exe\" hash=\"1fd2448e7143a3116ecc35fb9b70755e0029da965ea37c0fe090e6178928a1ce\" timestamp=\"0xcf97f04b\" size=\"0x0144f000\" added=\"2025-08-03T19:14:39Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5733\" file=\"ntkrla57.exe\" hash=\"6ca5653e4733e050f7132bfeb412a97575860e6acff212bad3389668957fdb6e\" timestamp=\"0x7d998762\" size=\"0x01249000\" added=\"2025-08-03T19:14:39Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5742\" file=\"ntoskrnl.exe\" hash=\"8e489c2c6449758cccd8ecc674b14c05b4204b7bb381bffd0d6cadc808991fb0\" timestamp=\"0xdd2fb7da\" size=\"0x0144f000\" added=\"2025-08-12T05:13:33Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5742\" file=\"ntkrla57.exe\" hash=\"1b3182ba35f7365afe0a02884804de2d1463d543d8972d41daab07a5ec45bd2c\" timestamp=\"0x735d4e60\" size=\"0x01249000\" added=\"2025-08-12T05:13:33Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5751\" file=\"ntoskrnl.exe\" hash=\"e350452506c3f4229fc643e1366f6af13364d90990116cce166e94cb52de13db\" timestamp=\"0xebe971e1\" size=\"0x0144f000\" added=\"2025-08-16T02:03:03Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5751\" file=\"ntkrla57.exe\" hash=\"5142874e1e15468dad4cf6012f3522cccbea2356b8d9cbe5ca11c7de206ec75d\" timestamp=\"0x9020077f\" size=\"0x01249000\" added=\"2025-08-16T02:03:03Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5761\" file=\"ntoskrnl.exe\" hash=\"c24433df1173aa83bccef971d060ec8f7a7b97d4f3f14c53a6deace5717db484\" timestamp=\"0xee0bdabb\" size=\"0x0144f000\" added=\"2025-08-22T22:51:27Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5761\" file=\"ntkrla57.exe\" hash=\"5333463887ff6b12d0ecf8ceb073728c58bebf6960e898792829d085e82d529d\" timestamp=\"0xdbe2d3b8\" size=\"0x01249000\" added=\"2025-08-23T19:31:57Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5770\" file=\"ntoskrnl.exe\" hash=\"133e40e8bf4be1de60386302934f06a6010de6e62a079ad59785ca3c1096a642\" timestamp=\"0x9a2c42a5\" size=\"0x0144f000\" added=\"2025-08-29T21:12:06Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5770\" file=\"ntkrla57.exe\" hash=\"224c2fa3e48da89b6b32fccdc41ada9f158d5c01bef96af20f90539a7e44d050\" timestamp=\"0xeac4e40d\" size=\"0x01249000\" added=\"2025-08-30T18:01:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5790\" file=\"ntoskrnl.exe\" hash=\"cde686be568132ae5517398cba8f9a099aedd97adc9ad8f9269078be5824711a\" timestamp=\"0x53392026\" size=\"0x0144f000\" added=\"2025-09-11T03:22:38Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.5790\" file=\"ntkrla57.exe\" hash=\"e7be38200e4d4c0fecfc7f07c695cfe809353ec252fc85ed4215977084349184\" timestamp=\"0x1cf061a1\" size=\"0x01249000\" added=\"2025-09-11T03:22:38Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6584\" file=\"ntoskrnl.exe\" hash=\"e64c39474974c5f7b07eeb6845994e949e76d7dd5970991e25025e5d55d61873\" timestamp=\"0xd8a9f461\" size=\"0x0144f000\" added=\"2025-09-11T03:22:38Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6584\" file=\"ntkrla57.exe\" hash=\"67d9e17fafaa8ec5be54c25210dd15eb71b162d6f0da306039c51d89f30b0347\" timestamp=\"0x2f088cdf\" size=\"0x01249000\" added=\"2025-09-11T03:22:38Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6682\" file=\"ntoskrnl.exe\" hash=\"cbdc6b5a8774fb6fa0872254a1546ed3ea4c7d55cbea477ae70071e77cb69253\" timestamp=\"0x12214e0e\" size=\"0x01450000\" added=\"2025-09-14T14:54:27Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6682\" file=\"ntkrla57.exe\" hash=\"04c8876a42e844a001b36fbd23b0d43f1c70f28569d80f4f3b62c178475fd27c\" timestamp=\"0xbeb0eca8\" size=\"0x01249000\" added=\"2025-09-14T14:54:27Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6690\" file=\"ntoskrnl.exe\" hash=\"964ec4dd26f712877cc8c49d17018512119695425428ebcedc5b4934bf685634\" timestamp=\"0x6aa7732c\" size=\"0x01450000\" added=\"2025-09-21T13:49:59Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6690\" file=\"ntkrla57.exe\" hash=\"6eb737ffe2dc1864c1c1dbabf6bfdac2b6cdf84a4da4ad0582437146fa265457\" timestamp=\"0xd8e63fe6\" size=\"0x01249000\" added=\"2025-09-21T13:49:59Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6713\" file=\"ntoskrnl.exe\" hash=\"1c2fc13b1693abfdb55ec4d6979520a41a4ea90f75d805acabc6b824b2a3133d\" timestamp=\"0xfe229a84\" size=\"0x01450000\" added=\"2025-10-01T01:37:34Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6713\" file=\"ntkrla57.exe\" hash=\"7f3674f06079440c47dddce9b637720b5f7f46085cb701a95e598287c45a2ff1\" timestamp=\"0xac2ef4ae\" size=\"0x01249000\" added=\"2025-10-01T01:37:34Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6717\" file=\"ntoskrnl.exe\" hash=\"f0773eddfb631261ea96afc47b137c2c2fa14bb2dbc78b42144edd654351eb2c\" timestamp=\"0xbb389cdf\" size=\"0x01450000\" added=\"2025-09-28T18:19:17Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6717\" file=\"ntkrla57.exe\" hash=\"b447be5b8381313ede96e7c3f99b36a71f3571c7c134d0ab7906458a2e2a98b9\" timestamp=\"0x791ee6a4\" size=\"0x01249000\" added=\"2025-10-01T01:37:34Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6725\" file=\"ntoskrnl.exe\" hash=\"4f4e0772425290d60c20b8d32800fb41ffb1a6a6b1edf710c27bf487ada50f52\" timestamp=\"0x23ed8d63\" size=\"0x01450000\" added=\"2025-10-01T01:37:34Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6725\" file=\"ntkrla57.exe\" hash=\"c9eeb2dc44b183bad0053d2e21573246563b9f762c0eecc2120569f453c5dd20\" timestamp=\"0xd5574b7b\" size=\"0x01249000\" added=\"2025-10-01T01:37:34Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6760\" file=\"ntoskrnl.exe\" hash=\"b7eb2dd112b1250d41f34dffb5dbe6e49428d4b671481ca843ed4de4c64ea134\" timestamp=\"0xcb61343c\" size=\"0x01450000\" added=\"2025-10-01T01:37:34Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6760\" file=\"ntkrla57.exe\" hash=\"ccb7f767f1f1eae26e261f4c651ec97d0c09323e61bc48b5afb55bf23dd7f736\" timestamp=\"0x7cd421e3\" size=\"0x01249000\" added=\"2025-10-01T01:37:34Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6772\" file=\"ntoskrnl.exe\" hash=\"b632396a407fd531d2a0c03cb1288ecce85d68c3535214de53d84ed2e9d40fdd\" timestamp=\"0x5f2b96b2\" size=\"0x01450000\" added=\"2025-10-09T21:10:38Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6772\" file=\"ntkrla57.exe\" hash=\"4760163a0b9c7fce3d445d8dec795fccce71a4f58f7a259363bcee626a5c631d\" timestamp=\"0xdacc60b5\" size=\"0x01249000\" added=\"2025-10-09T21:10:38Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6780\" file=\"ntoskrnl.exe\" hash=\"80310e1456c9d6641b6812458f4fcdcc5e4417b68060966d8e939329cc31a112\" timestamp=\"0x7a9d992b\" size=\"0x01450000\" added=\"2025-10-15T03:12:43Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6780\" file=\"ntkrla57.exe\" hash=\"78eeec3fa3dba6f6846c42c44bbc0cf4d837c0cfd6eee803aec195c1549fb251\" timestamp=\"0xa48a5fb5\" size=\"0x01249000\" added=\"2025-10-15T03:12:43Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6891\" file=\"ntoskrnl.exe\" hash=\"66dfed2614cb6ffd18ffe0ae20652f6260946560edeb245171e61ded67c2c288\" timestamp=\"0xcf0f7951\" size=\"0x0144f000\" added=\"2025-10-16T23:37:47Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6899\" file=\"ntoskrnl.exe\" hash=\"2014e8fdb170187248b6c4b8ee2ec3bd2de9a91bc6ccceeb2d73082987bcd332\" timestamp=\"0x8e87034a\" size=\"0x0144f000\" added=\"2025-10-15T03:12:43Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6899\" file=\"ntkrla57.exe\" hash=\"b58b6cba2d74f86647a1e2df867dc82f95e5b73d7e46a0a5c4b1ac44fa2eb1a7\" timestamp=\"0xb88dcf04\" size=\"0x01249000\" added=\"2025-10-15T03:12:43Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6901\" file=\"ntoskrnl.exe\" hash=\"94d9ea908f6ce0f958b14ef75ab473645adc8be37f3df8b496b0316ef051bc3c\" timestamp=\"0x1c1e0bd4\" size=\"0x0144f000\" added=\"2025-10-24T14:15:26Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6901\" file=\"ntkrla57.exe\" hash=\"f282d58940652da57350823c4b66b2f3d39f305046ec68c10b7737037b39f0e9\" timestamp=\"0x85f393ff\" size=\"0x01249000\" added=\"2025-10-24T14:15:26Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6905\" file=\"ntoskrnl.exe\" hash=\"184f7f1e574a46870a2343fbb3caca27f5a47216bddf7ace9d176af32956f23a\" timestamp=\"0x34f411c5\" size=\"0x0144f000\" added=\"2025-10-29T20:10:48Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6905\" file=\"ntkrla57.exe\" hash=\"018a90568c1ec3e367c196c4ebb3961eea37203a73df51a720d983358800e4b2\" timestamp=\"0xc28909bb\" size=\"0x01249000\" added=\"2025-10-29T20:10:48Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6970\" file=\"ntoskrnl.exe\" hash=\"e00b97ffd0ba410f92ee202c91f8c05c856d5f6e145fba06febe3dfabe8c38f6\" timestamp=\"0x4f6bf5bb\" size=\"0x01450000\" added=\"2025-10-24T14:15:26Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6972\" file=\"ntoskrnl.exe\" hash=\"a6f640404d44f3ce4e4e40d78c94ace0a2cfd1104c619a853c5847fb225e1fcd\" timestamp=\"0xd59bba63\" size=\"0x01450000\" added=\"2025-10-24T14:15:26Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6972\" file=\"ntkrla57.exe\" hash=\"0633b82dea8a769b13f65c097772ad9fbef436134fccefb7402243bdbd1765f2\" timestamp=\"0xa39ed60a\" size=\"0x01249000\" added=\"2025-10-24T14:15:26Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6982\" file=\"ntoskrnl.exe\" hash=\"71d4a9538180e385ddd47b15e86a3202bef3d76b0babb3bd0f582360aa088122\" timestamp=\"0xe687108d\" size=\"0x01450000\" added=\"2025-10-29T20:10:48Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.6982\" file=\"ntkrla57.exe\" hash=\"8a54b356c1b89772e419c56766eea09c9f9df4f213d3ede7008a5841d42701eb\" timestamp=\"0xd22c72c9\" size=\"0x01249000\" added=\"2025-10-29T20:10:48Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7014\" file=\"ntoskrnl.exe\" hash=\"e6cbb4072590a5d5a44f5beddd949306201d7cafdc93cd0d2d14572ce921fd3b\" timestamp=\"0xcef20f07\" size=\"0x01450000\" added=\"2025-10-29T20:10:48Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7015\" file=\"ntoskrnl.exe\" hash=\"78573018b1e0e0af9f2e0742ecf1b2774117b1beeed1dd5f23dc6c3069ed337e\" timestamp=\"0xee12a857\" size=\"0x01450000\" added=\"2025-10-29T20:10:48Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7015\" file=\"ntkrla57.exe\" hash=\"3801b25e62a1625b52bee7e50335342a1c53e4965f766249c590af4ce9b4ab6f\" timestamp=\"0xc47f7ef3\" size=\"0x01249000\" added=\"2025-10-29T20:10:48Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7019\" file=\"ntoskrnl.exe\" hash=\"2aebef5036073a2a2d74e20e032db412b6ec23f304a5643c95a27a85b7672d74\" timestamp=\"0x62e79a8f\" size=\"0x01450000\" added=\"2025-10-29T20:10:48Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7019\" file=\"ntkrla57.exe\" hash=\"afc5313ad8fd778904ba6c3e3c0cbf388de7e66d2c873bcc3b9dc6458dfc07aa\" timestamp=\"0x40c864e0\" size=\"0x01249000\" added=\"2025-10-29T20:10:48Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7050\" file=\"ntoskrnl.exe\" hash=\"eb89f9a7df5ce7af67f2a40eeca36908532e7f60339f5e9c1668ba7aaef87086\" timestamp=\"0x06e55957\" size=\"0x0144f000\" added=\"2025-11-02T15:30:04Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7051\" file=\"ntoskrnl.exe\" hash=\"8a7d53843061e9fd42d6f862a0e180e70a2e90db63d8e6d9971b6c2521a3c8c4\" timestamp=\"0xeae19a7b\" size=\"0x0144f000\" added=\"2025-11-01T02:59:40Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7051\" file=\"ntkrla57.exe\" hash=\"5dfb16e0f27449b5949a60076c9c948f1bb1240cc1dc97bcbc2f316da10dfeb6\" timestamp=\"0x7da2873f\" size=\"0x01249000\" added=\"2025-11-02T15:30:04Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7051\" file=\"lxcore.sys\" hash=\"7d942149570516f7c8c5335445430e20bb05c8889358875c91b1201407b8178f\" timestamp=\"0x015c364e\" size=\"0x00110000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7070\" file=\"ntoskrnl.exe\" hash=\"8f342ba653cb5c213676f064b9ce76d29cf1739a0c1ff8479ebe35a2675599aa\" timestamp=\"0x198bc01b\" size=\"0x01450000\" added=\"2025-11-07T23:30:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7070\" file=\"ntkrla57.exe\" hash=\"a275c1177ae807b3244602e9f3133626670c7e224e553527fbbd1b4aa741d372\" timestamp=\"0x71b54951\" size=\"0x01249000\" added=\"2025-11-07T23:30:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7149\" file=\"ntoskrnl.exe\" hash=\"7e24e5aa177e4e5cf663361f1d448e4553bd2cb0e909fc60e1c06d417fb7450d\" timestamp=\"0x05770202\" size=\"0x0144f000\" added=\"2025-11-12T23:55:08Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7171\" file=\"ntoskrnl.exe\" hash=\"33f254bf40042ed25f4d96dc77225451582b3f43c1859ab642106b056138ca4e\" timestamp=\"0x9688d60f\" size=\"0x0144f000\" added=\"2025-11-12T23:55:08Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7171\" file=\"ntkrla57.exe\" hash=\"ced29eb68434395fad72046823c03e778cdc057c5bffd20efe1a38d6083d76a2\" timestamp=\"0x639af308\" size=\"0x01249000\" added=\"2025-11-12T23:55:08Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7178\" file=\"ntoskrnl.exe\" hash=\"b595114665d60f81bc7669aedc87703dccee30792d86ebc126bba64fc9496893\" timestamp=\"0x6f2a1222\" size=\"0x01450000\" added=\"2025-11-25T23:06:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7178\" file=\"ntkrla57.exe\" hash=\"5fcecab3e8a178c2995ff3e2fe2deeec79b97dbeca471db5f8f15fa8f4adb10f\" timestamp=\"0xe2fc281d\" size=\"0x01249000\" added=\"2025-12-10T04:39:55Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7262\" file=\"ntoskrnl.exe\" hash=\"6bacc56037fa09ad36a9d76417ef4cf0c3c36330529284652eed14cdfe9d30bc\" timestamp=\"0xdef02d1b\" size=\"0x01450000\" added=\"2025-11-20T04:01:51Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7262\" file=\"ntkrla57.exe\" hash=\"b1a31a18d46428e8c2b0e624a435fd54786d10af68d9f3f30f5f865233a35e8d\" timestamp=\"0x7939351b\" size=\"0x01249000\" added=\"2025-11-20T04:01:51Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7270\" file=\"ntoskrnl.exe\" hash=\"a8399bcecc1010bd9435bb143518f31a84e7e643f9d57653d09e8d8f4b095031\" timestamp=\"0xd453453f\" size=\"0x01450000\" added=\"2025-11-25T23:06:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7271\" file=\"ntoskrnl.exe\" hash=\"ed0ed46066dc002ef9f43830db72ee3e6eb2293c55c0469b5bfc7bc14c0ce626\" timestamp=\"0x97a0647b\" size=\"0x01450000\" added=\"2025-11-25T23:06:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7271\" file=\"ntkrla57.exe\" hash=\"bd86ff7cb7f4b1546888c1e1f9303b6abaad817fb12b94ab6b1ec16229db3495\" timestamp=\"0x4803d586\" size=\"0x01249000\" added=\"2025-11-25T23:06:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7297\" file=\"ntoskrnl.exe\" hash=\"ea2b8f65e1fe4cf0313c399a349b0b9ac939f0adc7bf733cb6d3327c0c857c4c\" timestamp=\"0x0a688f96\" size=\"0x01450000\" added=\"2025-12-04T00:42:33Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7309\" file=\"ntoskrnl.exe\" hash=\"aece8d51b814c904c9b69f7660d0f978f3a394929f7e418d83586d477e885365\" timestamp=\"0x2a322f1d\" size=\"0x01450000\" added=\"2025-12-03T19:03:15Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7309\" file=\"ntkrla57.exe\" hash=\"1a9b5c872d07bad1bf5d26c25bd9b882c64d17eb9c72b4d2a7c53531e90dd662\" timestamp=\"0x6c75cdcb\" size=\"0x01249000\" added=\"2025-12-03T19:03:15Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7309\" file=\"lxcore.sys\" hash=\"f881d78c2eed64707f36c77e7a2bd3c660e589100104650ad5ece8178b4b9d51\" timestamp=\"0x1dc138d7\" size=\"0x00113000\" added=\"2025-12-03T19:03:15Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7309\" file=\"lxcore.sys\" hash=\"f881d78c2eed64707f36c77e7a2bd3c660e589100104650ad5ece8178b4b9d51\" timestamp=\"0x1dc138d7\" size=\"0x00114580\" added=\"2025-12-03T19:03:15Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7340\" file=\"ntoskrnl.exe\" hash=\"c1fad2f0ff6bf80e6ffe3115a1e68549915399d9307c4087ba66345191f0dcfe\" timestamp=\"0x4e0f78da\" size=\"0x01450000\" added=\"2025-12-10T04:39:55Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7344\" file=\"ntoskrnl.exe\" hash=\"2ecefccff4fd55e33d4089f8e10a7e9becb144a46c1105924ed42d7b03d0997b\" timestamp=\"0xf9e5de38\" size=\"0x01450000\" added=\"2025-12-06T03:12:56Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7344\" file=\"ntkrla57.exe\" hash=\"1749f8f5051b03834622a5fb57ab7a5fd09ce8344d48769a2133a20d1374f24b\" timestamp=\"0x9fb6c691\" size=\"0x01249000\" added=\"2025-12-10T04:39:55Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7344\" file=\"lxcore.sys\" hash=\"46b7ae0915fdcf7c95b9c01be01f1a24df96f312263bb39809b2dcb8fdd0db4f\" timestamp=\"0x30142797\" size=\"0x00111000\" added=\"2025-12-31T16:26:30Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7378\" file=\"lxcore.sys\" hash=\"33f18ed21c2b333008abe54faf37de8a0c89fc8bd0bb04baa25d00c0304f339d\" timestamp=\"0x1f565326\" size=\"0x00111000\" added=\"2026-02-02T00:46:25Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7447\" file=\"ntoskrnl.exe\" hash=\"a14e300657a3df0654d59a2ea14fadc22617c4033397f1772f752bfe74e7193a\" timestamp=\"0xeec8ea28\" size=\"0x01450000\" added=\"2025-12-10T04:39:55Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7462\" file=\"ntoskrnl.exe\" hash=\"710cf711b95c30f4fe78ac15026e2aa8c0bc96c2f72b15a09903818219e6c85a\" timestamp=\"0x9ab641ba\" size=\"0x01450000\" added=\"2025-12-10T04:39:55Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7462\" file=\"ntkrla57.exe\" hash=\"a460dbfe12febd9757526e02cc991141d5538241f9d8b00372945bcea3ffa481\" timestamp=\"0xae5b2b78\" size=\"0x01249000\" added=\"2025-12-10T04:39:55Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7520\" file=\"ntoskrnl.exe\" hash=\"a27cf5f5ec9fc1d429a0fdc2b4ce90865e8a79ac814fb99e2a9f318a5ef7a84f\" timestamp=\"0x3fec999e\" size=\"0x01450000\" added=\"2025-12-24T02:56:52Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7523\" file=\"ntoskrnl.exe\" hash=\"b1ce7ded9976b62da3ac9e2875805bb66c49369eb0ba60cb976eac9ba1a78b9f\" timestamp=\"0xb259e52d\" size=\"0x01450000\" added=\"2025-12-24T02:56:52Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7523\" file=\"ntkrla57.exe\" hash=\"f3a5189e448a7a9343628c563d29cea8b893b136afd1c36d75150ca3d328b5f1\" timestamp=\"0x9d48cb49\" size=\"0x0124a000\" added=\"2025-12-24T02:56:52Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7526\" file=\"ntoskrnl.exe\" hash=\"34b7a559a0e1ec71e5684524d3841609c15547cd9a48918c77a3958d5430b8fd\" timestamp=\"0x43ef810f\" size=\"0x01450000\" added=\"2026-01-29T10:23:29Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7535\" file=\"ntoskrnl.exe\" hash=\"72499b8ed5c42e47c67f36209da07ac3992160870066a27e5e14455cbd351de6\" timestamp=\"0x9124f559\" size=\"0x01450000\" added=\"2026-01-15T04:51:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7535\" file=\"ntkrla57.exe\" hash=\"0373e4fc5876665d06556830811e781ca81f1a5e114325dfec50adacb7922248\" timestamp=\"0x28dd478a\" size=\"0x0124a000\" added=\"2026-01-15T04:51:11Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7618\" file=\"ntoskrnl.exe\" hash=\"5a0c573268caa6f78236ab8a86f3e4dbffd4e089c5b4f8044e00049e88fae072\" timestamp=\"0x9d1d48cf\" size=\"0x01450000\" added=\"2026-01-15T04:51:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7623\" file=\"ntoskrnl.exe\" hash=\"8fe12fb477a59e000c787b7fa3971f589b7208c56eb0d2501e5cebf314b13b7c\" timestamp=\"0xe50be785\" size=\"0x01450000\" added=\"2026-01-15T04:51:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7623\" file=\"ntkrla57.exe\" hash=\"6ec19d575de6cc5e669727043fec80901c2316ecfbabf3d3dffd2771c503c036\" timestamp=\"0xe0582adb\" size=\"0x01249000\" added=\"2026-01-15T04:51:11Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7627\" file=\"ntoskrnl.exe\" hash=\"80d392edfa295b4483736c6bd5a1acb31962f01d0fd799fa68b9a4780ff93c91\" timestamp=\"0x4f30bae4\" size=\"0x01450000\" added=\"2026-01-22T02:43:17Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7627\" file=\"ntkrla57.exe\" hash=\"e16ac72a9ff845f6715ad716bffb98cb9e39ce545e436158dba71d6a69cd584e\" timestamp=\"0xe77f3eab\" size=\"0x01249000\" added=\"2026-01-22T02:43:17Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7653\" file=\"ntoskrnl.exe\" hash=\"c64c752fe35039add3770649abda57454b4a81fccfd68dea524b0663c492a1e2\" timestamp=\"0xa8ec0e05\" size=\"0x01450000\" added=\"2026-01-17T15:14:22Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7653\" file=\"ntkrla57.exe\" hash=\"a23a6a162cb6fa4fe922fd9d8c4cfc6e52275f71de9510ad6ad416e08d5f6200\" timestamp=\"0x5501866f\" size=\"0x0124a000\" added=\"2026-01-17T15:14:22Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7670\" file=\"ntoskrnl.exe\" hash=\"f1dac4efd01652ccd66f2e2041c568c54c1842ce5c43eed13e015d1ed1e86193\" timestamp=\"0x2d4beefc\" size=\"0x01450000\" added=\"2026-01-29T10:23:29Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7670\" file=\"ntkrla57.exe\" hash=\"53f9dee52b0ade90c3a6734d174e00f23edf648470efeef3521a5ed546dc4b5b\" timestamp=\"0x10b117e0\" size=\"0x0124a000\" added=\"2026-01-29T10:23:29Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7674\" file=\"ntoskrnl.exe\" hash=\"94391a9d0d02f9009895552690b68b3cee8c042e748c2a94d91e2e69ce23219e\" timestamp=\"0x5c70f89f\" size=\"0x01450000\" added=\"2026-01-28T03:27:30Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7674\" file=\"ntkrla57.exe\" hash=\"d85406cd46dd3f4f1e8a77f36d0f1a46fec311b9eccabf4492087c57130142b6\" timestamp=\"0x06c7128d\" size=\"0x0124a000\" added=\"2026-01-29T10:23:29Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7701\" file=\"ntoskrnl.exe\" hash=\"e51abfae603a5ed5b2d559a5143afa04f7f2e20371e547cbd5e07e0097f66109\" timestamp=\"0x0bc7f59f\" size=\"0x01450000\" added=\"2026-02-01T01:21:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7701\" file=\"ntkrla57.exe\" hash=\"302d9a926bfc3d5217f93028f4093c1ce425ab9f92decfea677e3347e7f68ed7\" timestamp=\"0xa2cd3a69\" size=\"0x0124a000\" added=\"2026-02-05T23:25:24Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7705\" file=\"ntoskrnl.exe\" hash=\"6902ecad43b2f9a1ad4cb86ddebb08c78577f6f831e974e2a869e70431d5fa86\" timestamp=\"0x84bf3088\" size=\"0x01450000\" added=\"2026-02-01T01:21:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7705\" file=\"ntkrla57.exe\" hash=\"1ab540441a115554e52009c6e3c7538a34af3e306a989b2c5538124816a4a373\" timestamp=\"0x36c209fb\" size=\"0x0124a000\" added=\"2026-02-01T01:21:00Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7705\" file=\"lxcore.sys\" hash=\"2a2f857225901a8d3f13462e7239d1c85eb7ff952f56a44ae1f4a808d4d1dd96\" timestamp=\"0x4070ef19\" size=\"0x00111000\" added=\"2026-02-05T23:25:24Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7724\" file=\"ntoskrnl.exe\" hash=\"13affabd5c86f84067463a76e20d021ac34023b7983014d43bf9c590ff3f749a\" timestamp=\"0x9d739351\" size=\"0x01450000\" added=\"2026-02-05T23:25:24Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7724\" file=\"ntkrla57.exe\" hash=\"d9c9a79ea2729717bc6571ac94e6818e6db7aa370fbcc19e17cc8e8d551de64d\" timestamp=\"0x41537fa0\" size=\"0x0124a000\" added=\"2026-02-05T23:25:24Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7733\" file=\"ntoskrnl.exe\" hash=\"7dc983eebb722f241a9f40b3dbe99f1554c65405c68dcee65a9b11bdbeff02aa\" timestamp=\"0x96291927\" size=\"0x01450000\" added=\"2026-02-05T23:25:24Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7733\" file=\"ntkrla57.exe\" hash=\"3a6469cfc32bdcc3a6f9003e9ab981d2399ed9f163fa93468b57fbd7f47ac914\" timestamp=\"0x5ad72e9e\" size=\"0x0124a000\" added=\"2026-02-05T23:25:24Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7755\" file=\"ntoskrnl.exe\" hash=\"32654c8aa7347b6f2d595927c8f98f4bff9843f3d14a5523d178ad25d7edb7d8\" timestamp=\"0xff1662ca\" size=\"0x01450000\" added=\"2026-02-11T00:54:58Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7755\" file=\"ntkrla57.exe\" hash=\"0e0dfa9bd5d807fa07b4cdebe9518364fc244a6dee891a34e86ac5f5b853227f\" timestamp=\"0x4ad72999\" size=\"0x0124a000\" added=\"2026-02-11T00:54:58Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7760\" file=\"ntoskrnl.exe\" hash=\"86771f377cba1f8cc2856413b0487e66a679684a344651e004b94002fe7455a0\" timestamp=\"0xbce3fa79\" size=\"0x01450000\" added=\"2026-02-11T00:54:58Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7760\" file=\"ntkrla57.exe\" hash=\"4ed8d4b2e5b63ffa2de29b60f564e2f75e4244220af2519400874cc06022d46f\" timestamp=\"0x43fdbcad\" size=\"0x0124a000\" added=\"2026-02-11T00:54:58Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7824\" file=\"ntoskrnl.exe\" hash=\"54f57116bcbbe96da72088130a8f949e13884a3db39d81f4b80cb26a88de00ac\" timestamp=\"0xae38e28f\" size=\"0x01450000\" added=\"2026-02-11T00:54:58Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7824\" file=\"ntkrla57.exe\" hash=\"d611c3ab58239f52d4484bc41bdfc1e881ed82e32e6f28c5cb397c88926243d7\" timestamp=\"0xf44fffef\" size=\"0x0124a000\" added=\"2026-02-11T00:54:58Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7859\" file=\"ntoskrnl.exe\" hash=\"e1f8a556ab3be8f782d8eec309493a2dab4e539c5613ba6f883d4f0dccb24149\" timestamp=\"0xf0290cfe\" size=\"0x01450000\" added=\"2026-02-19T05:09:13Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7859\" file=\"ntkrla57.exe\" hash=\"b3acd5e2ac5cde074e3b89cbfbdbc4d70ef0504893cf2208ed44304711fe197f\" timestamp=\"0x86e8c2c3\" size=\"0x0124a000\" added=\"2026-02-19T05:09:13Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7872\" file=\"ntoskrnl.exe\" hash=\"c6e63ed19e56050fda1d7728d79d66a188119d01933308bc6e9cd23048ce094c\" timestamp=\"0x815ce115\" size=\"0x01450000\" added=\"2026-02-21T23:40:53Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7872\" file=\"ntkrla57.exe\" hash=\"284d30548cea3b7b8c0f9d648e83d14eafb1f9619c7cc87d8050a316be56ce80\" timestamp=\"0x80aebddb\" size=\"0x01249000\" added=\"2026-02-21T23:40:53Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7877\" file=\"ntoskrnl.exe\" hash=\"0c4e1aa57f720d6d9fcef73391c02ebe203ae7e935426b65f1f0da620a8715a0\" timestamp=\"0xe6e20ae6\" size=\"0x01450000\" added=\"2026-02-21T23:40:53Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7877\" file=\"ntkrla57.exe\" hash=\"86eb103f43b2c39cad3aa8dbaa697c37689f4cb0d40a56cfcfc8a9ff811cb6db\" timestamp=\"0xc2dea0f2\" size=\"0x01249000\" added=\"2026-02-21T23:40:53Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7920\" file=\"ntoskrnl.exe\" hash=\"26cc8c3eb2a12e3309092ecda22e59178ee3c8ced4b0db67dd5ec508ca7aba46\" timestamp=\"0x98aacbfb\" size=\"0x01450000\" added=\"2026-02-25T16:03:39Z\">31</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7920\" file=\"ntkrla57.exe\" hash=\"a8cf25a449627838d5607f561242c9350d9bdf29e8385505af4a2c71acbf422e\" timestamp=\"0x340d9425\" size=\"0x0124a000\" added=\"2026-02-25T16:03:39Z\">32</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7920\" file=\"lxcore.sys\" hash=\"dfcff1cb626beb3c7f2b2faad1f5a1b903e8471c86dcf27f0c34163a4f8c6162\" timestamp=\"0x69d4db18\" size=\"0x00111000\" added=\"2026-03-04T03:13:34Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7931\" file=\"ntoskrnl.exe\" hash=\"c7f29cbdbb752362c487e4e2557ad0b93ad1a3bb94042bed174d98d6d6975082\" timestamp=\"0x3c1ad1e1\" size=\"0x01450000\" added=\"2026-02-28T14:39:37Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7934\" file=\"ntoskrnl.exe\" hash=\"3c4a4b29d54010af94dcbaa1386725d038d2ba3d7a846fbf8465f04df2bf13fa\" timestamp=\"0x52647a5b\" size=\"0x01450000\" added=\"2026-02-28T14:39:37Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7934\" file=\"ntkrla57.exe\" hash=\"1bab91139a2316adac2c54dfdb40ce1f60407b5c2f406a4a777d8a7e0bb1bbe0\" timestamp=\"0xd13f71dd\" size=\"0x0124a000\" added=\"2026-02-28T14:39:37Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7939\" file=\"ntoskrnl.exe\" hash=\"fbb43c0a1fd013dca810a33f4fce771a25b84b2984b619e8e51c0e6be8af9e37\" timestamp=\"0xe9d8d779\" size=\"0x01450000\" added=\"2026-02-28T14:39:37Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7939\" file=\"ntkrla57.exe\" hash=\"491785d84e9a8383d549e92ef5393fc6135c11f425f112be51813c49f776301a\" timestamp=\"0x9ccdd531\" size=\"0x0124a000\" added=\"2026-03-04T03:13:34Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7961\" file=\"ntoskrnl.exe\" hash=\"130c7214409e843e0f6f993c5edaa24b0d46f6c83a012174c6d086677fd61a8d\" timestamp=\"0xc6c7368a\" size=\"0x01450000\" added=\"2026-03-11T23:28:21Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7961\" file=\"ntkrla57.exe\" hash=\"88d5026b6164f4beca50f7ea3e2ccffa70e672255cd6f9da39b5b8fcdb2edc16\" timestamp=\"0x63e3afa1\" size=\"0x0124a000\" added=\"2026-03-11T23:28:21Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7965\" file=\"ntoskrnl.exe\" hash=\"a020b4d28ceed3846b83577032aaa67537275ead58c401170410d5d33b0b58f1\" timestamp=\"0xde91aa44\" size=\"0x01450000\" added=\"2026-03-06T20:01:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.7965\" file=\"ntkrla57.exe\" hash=\"2c3e709e641715ef641e64ead38b532c2f4a3b1635a61531db75b78ad5582959\" timestamp=\"0xaa3cf479\" size=\"0x0124a000\" added=\"2026-03-11T23:28:21Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.8036\" file=\"ntoskrnl.exe\" hash=\"620777f6aa7186447ae9b45cbcdddcf0c59516b87a2f702ffc8a1d07dbfe678b\" timestamp=\"0x4473d78d\" size=\"0x01450000\" added=\"2026-03-11T23:28:21Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.8036\" file=\"ntkrla57.exe\" hash=\"4342a98fafac7c80a0a065362aa18e65c73db06d5fbaed79dadca9154b0f85c0\" timestamp=\"0xd53aa314\" size=\"0x0124a000\" added=\"2026-03-11T23:28:21Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.8062\" file=\"ntoskrnl.exe\" hash=\"4f1bd21a5b6ecec819b8341927ad171a238973637b90dc26580d571217121592\" timestamp=\"0xa87decec\" size=\"0x01450000\" added=\"2026-03-14T04:38:17Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.8062\" file=\"ntkrla57.exe\" hash=\"ef1c8b9ca1a9d1a29ebf6d36c3736b07a71a73e911c323824e0ea55ddba44ed1\" timestamp=\"0xc920ef3a\" size=\"0x0124a000\" added=\"2026-03-19T02:51:26Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.8062\" file=\"lxcore.sys\" hash=\"646622dcff29faa7b1ce9ff07e0076f4f203d40b85759c10c91810d2a3e9f071\" timestamp=\"0x8a72b1ef\" size=\"0x00111000\" added=\"2026-03-19T02:51:26Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26100.8068\" file=\"ntoskrnl.exe\" hash=\"b10bc5b3e3d6fcf86f6545613551073c3c2054179462470df11d085222be5e89\" timestamp=\"0x8a0fdb4b\" size=\"0x01450000\" added=\"2026-03-14T04:38:17Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.8068\" file=\"ntkrla57.exe\" hash=\"63dd0909571d65cde712c89149359d2a1d50b3e60150667229080e9843db6c7b\" timestamp=\"0x51837203\" size=\"0x0124a000\" added=\"2026-03-19T02:51:26Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.32230\" file=\"ntoskrnl.exe\" hash=\"a22c81e8c1507b42bce8d17181c3af9a9314c4b4d6dbaef6bf07e1aa3d179636\" timestamp=\"0x571e3cfc\" size=\"0x01450000\" added=\"2026-01-15T04:51:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.32230\" file=\"ntkrla57.exe\" hash=\"4c10cc653a6f8cff93144edd8613c8210b0fe301321cd9427c9b75bb480d598c\" timestamp=\"0xcd688df7\" size=\"0x01249000\" added=\"2026-01-15T04:51:11Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.32234\" file=\"ntoskrnl.exe\" hash=\"de44866deaa5a01c992ce85caf27af4d55638f554fffc32d09d1b43d58a4f675\" timestamp=\"0x71040fad\" size=\"0x01450000\" added=\"2026-01-22T02:43:17Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.32236\" file=\"ntoskrnl.exe\" hash=\"66f134788dfbadd20f3c736fbaab9aab952d1f418aee23fa0e78b2d6b195ad95\" timestamp=\"0x199be122\" size=\"0x01450000\" added=\"2026-02-13T07:18:51Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.32370\" file=\"ntoskrnl.exe\" hash=\"b6b2afa5eb78923362e55073cadc0dcea9bd4c702781241d4cfda315ccc4face\" timestamp=\"0xe6710b7f\" size=\"0x01450000\" added=\"2026-02-13T07:18:51Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.32370\" file=\"ntkrla57.exe\" hash=\"c31a5b8f1814dae41cc62562665c1467966412fc78ecbcb7502dc61cb9397e16\" timestamp=\"0xea782819\" size=\"0x01249000\" added=\"2026-02-13T07:18:51Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26100.32522\" file=\"ntoskrnl.exe\" hash=\"aed37a739af67c70697aad820633772a8b8011703b5fe2c0b36a6f084b0d969a\" timestamp=\"0xd88a11e2\" size=\"0x01450000\" added=\"2026-03-11T23:28:21Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26100.32522\" file=\"ntkrla57.exe\" hash=\"2f238bb823dcad838edcbc6e7149031eb8ae93a39bb8755d4206c2a9f13c9cbd\" timestamp=\"0xe417a1b0\" size=\"0x01249000\" added=\"2026-03-11T23:28:21Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26200.5001\" file=\"ntoskrnl.exe\" hash=\"2b5c8f42ce4fb4e3bfda5ee55f3a0c44f1f4b938321829c8e261060397c66c29\" timestamp=\"0x0f947d63\" size=\"0x0144e000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26200.5001\" file=\"ntkrla57.exe\" hash=\"23552d1b0ca1821d43f5014099cae904806549d779ab7d741c9ce302d3cbc864\" timestamp=\"0x051c88bc\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26200.5001\" file=\"lxcore.sys\" hash=\"da992e4f19764b4a34640f2332964c762bf7b9c8a8158a267d9ee236958596e0\" timestamp=\"0xf5a37402\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26212.5000\" file=\"ntoskrnl.exe\" hash=\"99e13ce21fead763befce36a719a6de1f069d8e6766c8ba8b1b552b07095d73f\" timestamp=\"0xc869f7be\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26212.5000\" file=\"ntkrla57.exe\" hash=\"0fe49d59a956651609fc9f87a8d45f21bf3855f548e24bfe1d14b15dec80b545\" timestamp=\"0xecd8f2fd\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26212.5000\" file=\"lxcore.sys\" hash=\"35c9681b81d69265650bcc855cc4741fbbfbb51afb900eb027baf5cc1bc49887\" timestamp=\"0x2652d181\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26217.5000\" file=\"ntoskrnl.exe\" hash=\"5cdee4fd78252566779e0885f6df08c43f3422bfd92ea96e29bc97e64f0bdaa3\" timestamp=\"0xb3e857bc\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26217.5000\" file=\"ntkrla57.exe\" hash=\"5ba2ecb81f9d81612416f680c15d5eaee54ec778b50b709271ac69e474ac55e8\" timestamp=\"0x3b167043\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26217.5000\" file=\"lxcore.sys\" hash=\"fcadeb8eb111873eebe3c93df92a8f1ed5d52f80ed4852a2dc5f6ecd4bb75131\" timestamp=\"0xf7cf7bde\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26227.5000\" file=\"ntoskrnl.exe\" hash=\"c5aaa7f913a3c0eac13b2cbe4183f68290f374b60fc8f8180c58b7b12230f05f\" timestamp=\"0xe013968c\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26227.5000\" file=\"ntkrla57.exe\" hash=\"ccce66a46a1d4d05a5375ab501f424e9cc78e3151e363186ac8151738e158a2a\" timestamp=\"0x3f96477b\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26227.5000\" file=\"lxcore.sys\" hash=\"f1cdf028783935e066a1922652c5d55cfb64c2bdc5de321baac5b1c279b40b50\" timestamp=\"0x8131a041\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26231.5000\" file=\"ntoskrnl.exe\" hash=\"0f9ea8a026c6380aa867707ebbf73f9786eb2d6d47befb1e304d23962628a2df\" timestamp=\"0x644796fd\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26231.5000\" file=\"ntkrla57.exe\" hash=\"e32a539b826045efe8c0455345008f78e71a94969200a372c1fc3e669cd5762f\" timestamp=\"0xe2cd1ca5\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26231.5000\" file=\"lxcore.sys\" hash=\"706a242af1a29c186c66e88bda3cd9a311c2f8334da6376583e1aa89257e568a\" timestamp=\"0xfb884a22\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26236.5000\" file=\"ntoskrnl.exe\" hash=\"7dafc05386624431c7c96060b228c73e1643e9306da5a13999b6f78467ff969f\" timestamp=\"0x13eda5ec\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26236.5000\" file=\"ntkrla57.exe\" hash=\"d2209ab8263e0dc0e8826fddbfe3d9db1006b280ca06d161581bb5302314d507\" timestamp=\"0xd48a228a\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26236.5000\" file=\"lxcore.sys\" hash=\"8ad598834052bbd962cb1e94a932b546e32f3755dd8c5541483574e9a9f2f14f\" timestamp=\"0xb723c407\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26241.5000\" file=\"ntoskrnl.exe\" hash=\"c4797f6366575bb1df8afa163feb283a49a679a3149923dd6fd648269181a01e\" timestamp=\"0xae7a0bce\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26241.5000\" file=\"ntkrla57.exe\" hash=\"eb01226f52f9c015788542e227313069939a00819618d2d5f6f1e2efbce7363f\" timestamp=\"0xdf67fc10\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26241.5000\" file=\"lxcore.sys\" hash=\"243f9c792fa5cbcd6489f9d68dc0b1418be2d5735704c728fa94c0db00b1d5cf\" timestamp=\"0x7a99b051\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26244.5000\" file=\"ntoskrnl.exe\" hash=\"6d1fac1b7742c4df2f02346d2f39cb0b512653958ba4ba14110e72ecb805e3bb\" timestamp=\"0xcfa95461\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26244.5000\" file=\"ntkrla57.exe\" hash=\"b346818b287d41c9f5ec72cec9f27eb3a5ccc7c4038e3f828a6a2e1ea8fbdfe6\" timestamp=\"0x0c9d5585\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26244.5000\" file=\"lxcore.sys\" hash=\"5eb761c4e8ef2cedf88d87ec510d1c782010b6f6d60a2cc2c4058c56ca5ec0e6\" timestamp=\"0x4afc36b8\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26252.5000\" file=\"ntoskrnl.exe\" hash=\"feedccdffc6c77b268e2faed879d0aff413d192e6e1aaf817107496aea3d3d0a\" timestamp=\"0xc5f5d2e2\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26252.5000\" file=\"ntkrla57.exe\" hash=\"ab6d715518bdf3e35f8e0594a19743b950d6e4662c0ef56e3e526a68df213e1f\" timestamp=\"0x7d2afdab\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26252.5000\" file=\"lxcore.sys\" hash=\"540f8d8b0c02e685dad4f8701ef89acf726becff6751394eb98fff891f3e4c4d\" timestamp=\"0x3ebc5d68\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26257.5000\" file=\"ntoskrnl.exe\" hash=\"0ac8fb52fd13d8498b6af4f13066af08a3fec1f5861fcabe93df1863b7927fd1\" timestamp=\"0xa9df2dcb\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26257.5000\" file=\"ntkrla57.exe\" hash=\"e1bef2a6301a77583b4d6654b07952c1cfb18d08e8b18719ee9046a33c19d5b8\" timestamp=\"0xf94cb116\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26257.5000\" file=\"lxcore.sys\" hash=\"758a66ccb3f7573b4cc5a95e90d106ef39f3fe6bd46bb8ecd3a6a28bfbc26bf6\" timestamp=\"0x189feb64\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26280.5000\" file=\"ntoskrnl.exe\" hash=\"111d423e92d1e3c8725b9069208e78131d3719755d91d029612b0f986bd6c625\" timestamp=\"0x6ab136b5\" size=\"0x0144f000\" added=\"2024-09-19T04:21:44Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26280.5000\" file=\"lxcore.sys\" hash=\"aee5033720f4611cab069bd6cd5bf769727179020039d91a006e4448580baabf\" timestamp=\"0xcb87b912\" size=\"0x00110000\" added=\"2024-12-22T17:47:47Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26296.5001\" file=\"ntoskrnl.exe\" hash=\"5bf73685b0cdca51c212de8cf7662dcfb9997ab645bef5c5290c6a307794ff4a\" timestamp=\"0x117ebd47\" size=\"0x0144f000\" added=\"2024-10-06T07:32:47Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26296.5001\" file=\"ntkrla57.exe\" hash=\"c70a689cbe1ea2f0e0713ddb0596521fec6934f58c6fcceac1ef833a64204cb1\" timestamp=\"0x6f277490\" size=\"0x01249000\" added=\"2025-03-28T03:59:19Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26296.5001\" file=\"lxcore.sys\" hash=\"4530bfe3b9d882dc25120e0a0925564b540454827eb2278815bc2cdef20ce367\" timestamp=\"0xedf2bb07\" size=\"0x00110000\" added=\"2024-10-29T02:19:33Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26304.5000\" file=\"ntoskrnl.exe\" hash=\"d3e2f82e20ac47e0e1aa1acfe562768e9e97c98956591ad16bc18c4cb352e4bd\" timestamp=\"0x199e2f85\" size=\"0x0144f000\" added=\"2024-12-10T02:56:39Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26311.5000\" file=\"ntoskrnl.exe\" hash=\"125e4f4c2a2704af15f48264917f2368d5bcc5bd00d493c12b9a5ee9fcf44aee\" timestamp=\"0x991d4f33\" size=\"0x0144f000\" added=\"2024-10-26T06:39:10Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26311.5000\" file=\"ntkrla57.exe\" hash=\"7490977d8d45cfa3303ec84c98926ba8385cdb72405b2f48eaae9bcc0549a64a\" timestamp=\"0xe92df73c\" size=\"0x01249000\" added=\"2024-10-29T02:19:33Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26311.5000\" file=\"lxcore.sys\" hash=\"6776e643ac9ebc2a1e67e048135b8432fb7f352e2c437b40304730601feb6cf0\" timestamp=\"0x274895d7\" size=\"0x00110000\" added=\"2024-11-13T15:20:35Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26334.5000\" file=\"ntoskrnl.exe\" hash=\"f50742895fb23560e4bd447f891fe731212142538278a8428fe01ebfdc297f1d\" timestamp=\"0x4dd1b41f\" size=\"0x0144f000\" added=\"2024-12-19T19:52:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26334.5000\" file=\"ntkrla57.exe\" hash=\"b62bddd478e946c2802d899b97b5edccf70cb8f7c76fbc52ec8df7d4912df8c3\" timestamp=\"0x7d73baf2\" size=\"0x01249000\" added=\"2024-12-19T19:52:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26334.5000\" file=\"lxcore.sys\" hash=\"455ba80fde382b251bfe60e16103f2d79e9a571b74aa6fcc1a223fdcd2765b3e\" timestamp=\"0xee9689bb\" size=\"0x00110000\" added=\"2024-12-22T17:47:47Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26360.5000\" file=\"ntoskrnl.exe\" hash=\"8ffabce9275a0a91a569317c3ee4caf39d12e7fa57a3c805a3eb5bf86e1dd9d0\" timestamp=\"0xf6a58f02\" size=\"0x0144f000\" added=\"2025-02-19T22:12:09Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26360.5000\" file=\"ntkrla57.exe\" hash=\"9a17e1004fd7dacca8dff539c877f89cc27d5b2aa697c9c7b10c72d18fa6e98e\" timestamp=\"0xcbf19c71\" size=\"0x01249000\" added=\"2025-02-19T22:12:09Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26376.5000\" file=\"ntoskrnl.exe\" hash=\"32957ef43ac90245b5aed66ddec5fc4e76998c67dccbd6f146f42e4ca5ca8e1d\" timestamp=\"0x0223160d\" size=\"0x0144f000\" added=\"2025-03-17T02:43:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26376.5000\" file=\"ntkrla57.exe\" hash=\"c5a1e35cad10e9e95b8a3610bab70be11c6a58b072e4b152f817375a53412049\" timestamp=\"0x50cc0231\" size=\"0x01249000\" added=\"2025-03-17T02:43:00Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26376.5000\" file=\"lxcore.sys\" hash=\"44f8399981e200e79fef6855d33d26295055a75393deddb126ad52f0e46d065b\" timestamp=\"0xee6dc09b\" size=\"0x00110000\" added=\"2025-03-23T17:06:04Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26392.5000\" file=\"ntoskrnl.exe\" hash=\"59033d1290f2d2402fe2bbd6bb4be4ceb89ad985b3050e56c66812648397ccf1\" timestamp=\"0xfd1c9f91\" size=\"0x01450000\" added=\"2025-04-12T23:13:14Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26392.5000\" file=\"ntkrla57.exe\" hash=\"3e5c224f5274307c3f19f4f2977d3ac1c3b48c04f29a81ac8ebfbb4428de66cd\" timestamp=\"0x0db7dde2\" size=\"0x01249000\" added=\"2025-04-12T23:13:14Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26392.5000\" file=\"lxcore.sys\" hash=\"9bc53f590592096749b35bd601f8fcb7470a89bc7f997934acf1078c4072c463\" timestamp=\"0x516cac86\" size=\"0x00110000\" added=\"2025-04-12T23:13:14Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26404.5000\" file=\"ntoskrnl.exe\" hash=\"52d943d8e7f2badd830f7a4fb0ceb13913bbd41dc58bb0605acee3c3f3c1cdc9\" timestamp=\"0xec13048e\" size=\"0x01450000\" added=\"2025-05-10T01:12:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26404.5000\" file=\"ntkrla57.exe\" hash=\"d6592c814cc2d197ead72024dadae1fc1ffc9e1b82f2c03266737150e5869cc9\" timestamp=\"0x0ea1f157\" size=\"0x01249000\" added=\"2025-05-10T01:12:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26404.5000\" file=\"lxcore.sys\" hash=\"8fb4a2ba84d87e3ee122e086bea0a8eed1755dc67fed71598124b431741f5737\" timestamp=\"0xa79c1f11\" size=\"0x00110000\" added=\"2025-06-01T15:47:54Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.26433.1000\" file=\"ntoskrnl.exe\" hash=\"c29ca03b4c9bc16dcbfba44db782b83df40fff51354826f8f970ab3968ba1b9e\" timestamp=\"0x8694b8d8\" size=\"0x0144f000\" added=\"2025-06-22T18:46:02Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26433.1000\" file=\"ntkrla57.exe\" hash=\"54da87f21875256b410536d212d9e89fe9ce10e40de3c327defe1bb1c1e8d5c9\" timestamp=\"0x942c1cba\" size=\"0x01249000\" added=\"2025-06-22T18:46:02Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26445.1002\" file=\"ntoskrnl.exe\" hash=\"ffbd77c295c68540338f7045b8d4a5e458fed24858e4e2b594bf6e3d73e5d950\" timestamp=\"0x8b2826b2\" size=\"0x0144f000\" added=\"2025-07-17T01:08:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26445.1002\" file=\"ntkrla57.exe\" hash=\"97c43fac7838613935a9bf6b4faa7b05d52cf81bee4c50690e4f06bd645d64aa\" timestamp=\"0xcddc680a\" size=\"0x01249000\" added=\"2025-07-17T01:08:50Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26454.1000\" file=\"ntoskrnl.exe\" hash=\"5b008179704412c87edbbea95a80a3e0865df5343fd96188ca8c3e72130a31fe\" timestamp=\"0xa53fdfb9\" size=\"0x0144f000\" added=\"2025-07-31T03:02:16Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26454.1000\" file=\"ntkrla57.exe\" hash=\"7b75bff4ab311276307a9449719892e2a5c6394e7892bcd852bc016adaa6a9d5\" timestamp=\"0x960806d0\" size=\"0x01249000\" added=\"2025-07-31T03:02:16Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26461.1001\" file=\"ntoskrnl.exe\" hash=\"0732479243f31f4acfa045516c933371644aafeabfef09cad80110d1d818d495\" timestamp=\"0x7f1e1760\" size=\"0x0144f000\" added=\"2025-08-13T21:37:12Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26470.1000\" file=\"ntoskrnl.exe\" hash=\"107188b55127a1614c09a67b8fe82f8785bee841a841bc6e05ba2dc51a696e7b\" timestamp=\"0x94b965a9\" size=\"0x0144f000\" added=\"2025-09-02T00:24:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26484.1000\" file=\"ntoskrnl.exe\" hash=\"fc3d1009379cef5090e1e1bbdb3f80abeb1a57afdefcf58079c9c4fb8e058227\" timestamp=\"0x174b9a94\" size=\"0x01450000\" added=\"2025-09-17T06:25:37Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26484.1000\" file=\"ntkrla57.exe\" hash=\"597c5d66c27fb77a25af686bdc1fac506c046726c0a75bbb1e60e54b7d2683cb\" timestamp=\"0x77cdcad3\" size=\"0x01249000\" added=\"2025-09-27T02:00:45Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26491.1000\" file=\"ntoskrnl.exe\" hash=\"e4ddcb34fdba6e2804f737cc49cc3557506977e44278a616f1f73cf420f9736d\" timestamp=\"0x8a99fd6b\" size=\"0x01450000\" added=\"2025-10-29T20:10:48Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26491.1000\" file=\"ntkrla57.exe\" hash=\"0d91b3565a9b2b158df28ad13e458ad85bb091c7b3b3aee72b1f73e625b3522c\" timestamp=\"0x8a3c7280\" size=\"0x01249000\" added=\"2025-10-29T20:10:48Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26501.1000\" file=\"ntoskrnl.exe\" hash=\"45225a5da251722e686989872ce50c3885efa5411088e1342be59d2a5622f150\" timestamp=\"0x21aa7e02\" size=\"0x0144f000\" added=\"2025-10-16T23:37:47Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26501.1000\" file=\"ntkrla57.exe\" hash=\"b836e0c04ae2cb3c043a64909043e56db255a4e5098a0adf99e4ade3160a630e\" timestamp=\"0x1cfcd23c\" size=\"0x01249000\" added=\"2025-10-16T23:37:47Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.26525.1001\" file=\"ntoskrnl.exe\" hash=\"26fbcfdeed726bf23d1f2108b61a91b198e66bd97bf859f163c31cfe227cdbfe\" timestamp=\"0x3a30a4c3\" size=\"0x01450000\" added=\"2025-12-06T03:12:56Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26534.1000\" file=\"ntoskrnl.exe\" hash=\"867fef89e6b1457655f475079a0163e794cf4b07d77bc9c32fe5e3a512695f74\" timestamp=\"0xcc971b91\" size=\"0x01450000\" added=\"2025-12-11T18:37:57Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.26534.1000\" file=\"ntkrla57.exe\" hash=\"2223ca752542a9a3e2f781df799bd20e4015f2aeeb97c6c4942cdedef82c5f52\" timestamp=\"0xae55d951\" size=\"0x01249000\" added=\"2025-12-24T02:56:52Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27686.1000\" file=\"ntoskrnl.exe\" hash=\"57d3c664cb115842f2591c85423b099adec6efcab89b221fcd95458f8ac61771\" timestamp=\"0xd617af53\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27686.1000\" file=\"ntkrla57.exe\" hash=\"c686b6e164bb15ae51bebda93ea963f3cd94e3ea1d214bd154c8737ccdc51299\" timestamp=\"0x1f43420b\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27686.1000\" file=\"lxcore.sys\" hash=\"6a73fb7c9899e683610c76b5563257273b451091eca3239e130024d3f774631f\" timestamp=\"0x651bdc5f\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27695.1000\" file=\"ntoskrnl.exe\" hash=\"3e0197b41c8ec3ce7060ce7b3eb6c518d92ab6c45bbd54d0191d43f771f02e01\" timestamp=\"0x1c53c389\" size=\"0x0144f000\" added=\"2024-09-12T01:41:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27695.1000\" file=\"ntkrla57.exe\" hash=\"6a83db26ffc63560d8e15145e11be5a5b76c8bf1bacade45c8ebe65d8afdada8\" timestamp=\"0xda32805d\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27695.1000\" file=\"lxcore.sys\" hash=\"84fb98d18f866a1a2d06d0a9927a5b1a55917ffc65aa61aa156e660ef3f9cd79\" timestamp=\"0x5ff09df9\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27718.1000\" file=\"ntoskrnl.exe\" hash=\"b8b771a0f587f9bb8be536c1701ef0771aaf71dbbdf9b8eabb154eb9671939da\" timestamp=\"0x72d4cda6\" size=\"0x0144f000\" added=\"2024-10-04T01:28:54Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27718.1000\" file=\"ntkrla57.exe\" hash=\"ef8dc7fdaeaa04bd26b6a1d99907e64e5f0d6c75e4fb9fa30c9558842b43c30a\" timestamp=\"0x5900c7dd\" size=\"0x01249000\" added=\"2024-10-04T01:28:54Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27718.1000\" file=\"lxcore.sys\" hash=\"9835a33b6fe3cc486bdbe2740a438a11396a7776180ad057d9d914093019e172\" timestamp=\"0xbbf1e392\" size=\"0x00110000\" added=\"2024-10-04T01:28:54Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27723.1000\" file=\"ntoskrnl.exe\" hash=\"783b037d73c62865a5a49855cafc2962428de1083ab173600b4951f2db90db97\" timestamp=\"0x4209d07d\" size=\"0x0144f000\" added=\"2024-10-12T01:50:50Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27723.1000\" file=\"ntkrla57.exe\" hash=\"3ad0ea661737d5f42c17762ad935186f380298c68752e12ddf27b9082164a6ae\" timestamp=\"0x88b8ea16\" size=\"0x01249000\" added=\"2024-10-12T01:50:50Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27723.1000\" file=\"lxcore.sys\" hash=\"bb1cf7e042b96f429ca6a8182a9e9b19e6ec309f5b8c04cc3092d5b82f7c92a3\" timestamp=\"0x22421854\" size=\"0x00110000\" added=\"2024-10-12T01:50:50Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27729.1000\" file=\"ntoskrnl.exe\" hash=\"198aaea3838716902757ba8213bb13edc91f38bf560388815e8c6837165e6d6a\" timestamp=\"0xd141c862\" size=\"0x0144f000\" added=\"2024-10-19T15:36:45Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27729.1000\" file=\"ntkrla57.exe\" hash=\"2b489b81e9a239e98e2a87420f5a19cc7dfeda8cc1c2551d4ae90d88aa2dbe10\" timestamp=\"0xaed0e0e2\" size=\"0x01249000\" added=\"2024-10-19T15:36:45Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27729.1000\" file=\"lxcore.sys\" hash=\"ff12655323ca52ce48f1fccbd468c43757c4ad75d39e913305e021429a093336\" timestamp=\"0xd7e8afe1\" size=\"0x00110000\" added=\"2024-10-19T15:36:45Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27744.1000\" file=\"ntoskrnl.exe\" hash=\"26751c91965e185864ed97ba88d055984546ca8c517afd8fb9f5a3f969d23635\" timestamp=\"0x37a4e772\" size=\"0x0144f000\" added=\"2024-11-09T04:03:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27744.1000\" file=\"ntkrla57.exe\" hash=\"f24b6b94482a21b8e05eb2834945e2bfa0b00aa15c8ff190f74ac982ea9d0c3a\" timestamp=\"0xae898710\" size=\"0x01249000\" added=\"2024-11-09T04:03:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27744.1000\" file=\"lxcore.sys\" hash=\"e67791dc184cfc6456395553609a19b28ba250085d6c986595d9f2dff6f1f630\" timestamp=\"0x439a2401\" size=\"0x00110000\" added=\"2024-11-09T04:03:18Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27749.1000\" file=\"ntoskrnl.exe\" hash=\"037ce2813e6b29e84b5e436d84f804cfc5ef48a3f71789650252f26c2ed3245e\" timestamp=\"0x46946984\" size=\"0x0144f000\" added=\"2024-11-15T06:04:33Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27749.1000\" file=\"ntkrla57.exe\" hash=\"1a0b288ccb8aed2f6bf9711ed0d6c9483e671d37e26def464cebe891a013f726\" timestamp=\"0xdd196057\" size=\"0x0124a000\" added=\"2024-11-15T06:04:33Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27749.1000\" file=\"lxcore.sys\" hash=\"b1b3fbadd805b41e2f99fec1bb7f9fba0f03cb5c4c0e24f52425f9f020cd442f\" timestamp=\"0x4b8757b6\" size=\"0x00110000\" added=\"2024-11-15T06:04:33Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27754.1000\" file=\"ntoskrnl.exe\" hash=\"321066eb65b474efaf335e733daad006a163a4f04a4f458cabee277f0f8bb1f3\" timestamp=\"0x89ce08c1\" size=\"0x0144f000\" added=\"2024-11-21T19:38:04Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27754.1000\" file=\"ntkrla57.exe\" hash=\"cfb92d94163f28f841fb1bb7286bbc2a2cabc0f281bc960fc51c4efec09c5bb9\" timestamp=\"0x725c5a55\" size=\"0x01249000\" added=\"2024-11-21T19:38:04Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27754.1000\" file=\"lxcore.sys\" hash=\"7f24293aee987d1a11e4e04ae1c51f0ca47f912cedaed54d0356164260fd8e9e\" timestamp=\"0x7f452398\" size=\"0x00110000\" added=\"2024-11-21T19:38:04Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27758.1000\" file=\"ntoskrnl.exe\" hash=\"2b0e88cd7b94f78326ed0b28fc733391d794dd1322adf48deb9d6f86ade3584d\" timestamp=\"0xc1ca1601\" size=\"0x0144f000\" added=\"2024-12-10T02:56:39Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27758.1000\" file=\"ntkrla57.exe\" hash=\"d71c638fb347a5897d887c02f4317b00a182657286618f55f51b20b504d4c17c\" timestamp=\"0x53f4265f\" size=\"0x01249000\" added=\"2024-12-10T02:56:39Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27758.1000\" file=\"lxcore.sys\" hash=\"a101c01e5a9e255d2605267db4dbe0c5b8b1efa9c59afbcc9c58b9fa60fea39b\" timestamp=\"0x7d4de89e\" size=\"0x00110000\" added=\"2024-12-10T02:56:39Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27764.1000\" file=\"ntoskrnl.exe\" hash=\"9aa90783d5d8cbb2d6286f7ba902066eac22fc4fe9b16f1dca892626e1470c9d\" timestamp=\"0xe46465d4\" size=\"0x0144f000\" added=\"2024-12-13T00:14:01Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27764.1000\" file=\"ntkrla57.exe\" hash=\"c58ec1aa003b27ab798791ef854110ecb0564d00566a9007cc93c33f3f2f2b35\" timestamp=\"0xde284f34\" size=\"0x01249000\" added=\"2024-12-13T00:14:01Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27764.1000\" file=\"lxcore.sys\" hash=\"ad5c5517d545438b68f22ceb5f68ef03d1a1cca01079b8f0222ab50083ddfdd4\" timestamp=\"0x08212fe8\" size=\"0x00110000\" added=\"2024-12-13T00:14:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27766.1000\" file=\"ntoskrnl.exe\" hash=\"18411a6f01dff14a1ffbdd4e386e45b910519ee62b0890f09cf28b22184201f1\" timestamp=\"0xb7f473ab\" size=\"0x0144f000\" added=\"2024-12-16T15:35:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27766.1000\" file=\"ntkrla57.exe\" hash=\"7a537797c7db695fc90b4553ccb1f33a2a112e0c4a3a2bff4b3d781ab531bf00\" timestamp=\"0x33cf196b\" size=\"0x01249000\" added=\"2024-12-16T15:35:11Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27766.1000\" file=\"lxcore.sys\" hash=\"8f34f67b3937bc6bbaa3ac56b57f757780742bcf6acdbb4e34434617ed5a173c\" timestamp=\"0x90370da4\" size=\"0x00110000\" added=\"2025-01-04T05:49:38Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27768.1000\" file=\"ntoskrnl.exe\" hash=\"c620cfeaebe1e1b7d765b9e4c4200aab7c8a994d3361eb05343c613ab6864ae6\" timestamp=\"0x7ea0f92a\" size=\"0x0144f000\" added=\"2025-01-10T06:00:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27768.1000\" file=\"ntkrla57.exe\" hash=\"96d543a7ceb4d4b5f3e33aac13340f70fc831d45bf63a9f7081709750f6d539f\" timestamp=\"0x8b58cd91\" size=\"0x01249000\" added=\"2025-01-11T02:34:03Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27768.1000\" file=\"lxcore.sys\" hash=\"3688cf0bc492be5849a41894ce1182f6f7bc2cfcd76d533bf699c1f806d90e77\" timestamp=\"0xdb87f9b0\" size=\"0x00110000\" added=\"2025-01-10T06:00:00Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27774.1000\" file=\"ntoskrnl.exe\" hash=\"b34f0634c5bbf9903bd4f61cf7b47de20dc5bff38193b0d1ed1a3c5c8693523d\" timestamp=\"0x30c52c74\" size=\"0x0144f000\" added=\"2025-01-18T23:48:32Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27774.1000\" file=\"ntkrla57.exe\" hash=\"d2c6f15b67aed22b2038c60ad1e78921787772d19e1920403ae3643e343969c2\" timestamp=\"0x2d842970\" size=\"0x0124a000\" added=\"2025-01-18T23:48:32Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27774.1000\" file=\"lxcore.sys\" hash=\"7e07be9a5024b2035a850b564c5beee0a70a4f3964bab4fb4aea833b480da375\" timestamp=\"0xa0efa104\" size=\"0x00110000\" added=\"2025-01-18T23:48:32Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27779.1000\" file=\"ntoskrnl.exe\" hash=\"1359905c5b18c08ac653acb856ee4c99ab74d500a6be2df68754d00bec1f1d9a\" timestamp=\"0x94cbbbf3\" size=\"0x01450000\" added=\"2025-02-17T22:56:35Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27779.1000\" file=\"ntkrla57.exe\" hash=\"ed584e600dda5b7b3bca9ca47731fdc4fe5a970b7e4c9385e02b39fb04b24264\" timestamp=\"0x0cd5cd0f\" size=\"0x01249000\" added=\"2025-02-17T22:56:35Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27779.1000\" file=\"lxcore.sys\" hash=\"885a5242d758e9ff615c5d95912dc8bbccfee77545232829356b1371c8ddb2e5\" timestamp=\"0x88052b02\" size=\"0x00110000\" added=\"2025-02-17T22:56:35Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27783.1000\" file=\"ntoskrnl.exe\" hash=\"f415706305c951bf355bbd7e04e0b3789e668807dda0fff5eaec8ac1fb5d10b3\" timestamp=\"0xd251fbfe\" size=\"0x01450000\" added=\"2025-01-31T00:35:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27783.1000\" file=\"ntkrla57.exe\" hash=\"5da4c3b05cd9435fb111fb6fdde6a259f4365c03c18ce2bac1b4568cab827e67\" timestamp=\"0xe2974603\" size=\"0x0124a000\" added=\"2025-01-31T00:35:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27783.1000\" file=\"lxcore.sys\" hash=\"4365c9481ef4be5b1b96d6a4d67966ad6760bdc6f6dd3d7c446ed94f33969746\" timestamp=\"0x6df54c1f\" size=\"0x00110000\" added=\"2025-01-31T00:35:18Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27788.1000\" file=\"ntoskrnl.exe\" hash=\"3cd8d3e73c8f6ad091daa26e8cfb00ae481b6438be1a636a575c682e91b17d92\" timestamp=\"0xa64cea33\" size=\"0x01450000\" added=\"2025-02-09T01:52:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27788.1000\" file=\"ntkrla57.exe\" hash=\"c6721a566414abf6e1c69a26badff55b91c5f026842a07f44ffaf26ed9657748\" timestamp=\"0x340531dd\" size=\"0x01249000\" added=\"2025-02-09T01:52:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27788.1000\" file=\"lxcore.sys\" hash=\"2773de03e8d2a73b65451c4a464f532d183c3c8c82bdeb3d8a590cc2b27b120c\" timestamp=\"0xeb8b3900\" size=\"0x00110000\" added=\"2025-02-09T01:52:18Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27802.1000\" file=\"ntoskrnl.exe\" hash=\"8bd55f5bb2e94d4715d0e9dfe893df45d6adfb486503cfc0574bdd73a3511aae\" timestamp=\"0xd01e8fdb\" size=\"0x01454000\" added=\"2025-03-02T06:42:51Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27802.1000\" file=\"ntkrla57.exe\" hash=\"c93c9c88b77dd82fd4e926e96f4d72f8ea240e60e8e3a56a8276d47b13ec1f01\" timestamp=\"0x863b2ece\" size=\"0x0124f000\" added=\"2025-03-02T06:42:51Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27802.1000\" file=\"lxcore.sys\" hash=\"c9ee873e2bf3a88faf60637d5a1a3ef84973a27e51a0402d50f979a1c8d8ab90\" timestamp=\"0x3c369141\" size=\"0x0010f000\" added=\"2025-03-02T06:42:51Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27808.1000\" file=\"ntoskrnl.exe\" hash=\"649304c2f1c99d8ba537529a88bdc54fa7ad65b8d566454fd5e039bcf1ba02be\" timestamp=\"0x279008a0\" size=\"0x01454000\" added=\"2025-03-11T02:45:33Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27808.1000\" file=\"ntkrla57.exe\" hash=\"fab9a357aaa5175c2bbe9628fbb1ac7f82a8bb1cc4fd6ca67f06f45fcf12970e\" timestamp=\"0x21f13450\" size=\"0x0124f000\" added=\"2025-03-11T02:45:33Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27808.1000\" file=\"lxcore.sys\" hash=\"d7f8daae29fec8211a644ea7dbe7fed9f2881a33186b19ce90496b19608114a8\" timestamp=\"0x2f2ad423\" size=\"0x0010f000\" added=\"2025-03-11T02:45:33Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27813.1000\" file=\"ntoskrnl.exe\" hash=\"37e239fc33d3f3d0dc3b709ff5b9569808f3578f5ad8608a68481305f537398c\" timestamp=\"0x5ae967ee\" size=\"0x01454000\" added=\"2025-03-14T04:05:46Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27813.1000\" file=\"ntkrla57.exe\" hash=\"cac5f545e74f4fee8cf7ad405bfce8c008d93019d74bb3ffd56f28cc6703f853\" timestamp=\"0x39204745\" size=\"0x0124f000\" added=\"2025-03-14T04:05:46Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27813.1000\" file=\"lxcore.sys\" hash=\"59014198befca95da359dca7bd01d360de4c39887c2d156181e2d8258cd2f91a\" timestamp=\"0x0400f060\" size=\"0x0010f000\" added=\"2025-03-14T04:05:46Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27818.1000\" file=\"ntoskrnl.exe\" hash=\"8d3cf0889ab8fd6cbd3b178c9c9c0470ed8d8d669ab75349971d3a69dd5cb6b9\" timestamp=\"0x38a4eac3\" size=\"0x01456000\" added=\"2025-03-23T17:06:04Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27818.1000\" file=\"ntkrla57.exe\" hash=\"f719cc1e5a5d3d9aa712f53657260d05cc21647c35d64fb85205a278eb3437cd\" timestamp=\"0x0f01861b\" size=\"0x01250000\" added=\"2025-03-23T17:06:04Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27818.1000\" file=\"lxcore.sys\" hash=\"55de33695c1239491e5c645fd13e1a51e82638ee56b0cd10d44ca6744a405816\" timestamp=\"0x8891b8f6\" size=\"0x0010f000\" added=\"2025-03-23T17:06:04Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27823.1000\" file=\"ntoskrnl.exe\" hash=\"a6ac14be0d7ecb239ab4c36078217b3dd25cae66aa70d3eff4d5f09172f9f236\" timestamp=\"0x228e6093\" size=\"0x01456000\" added=\"2025-03-28T03:59:19Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27823.1000\" file=\"ntkrla57.exe\" hash=\"56ba1b859fc6c76d98e52aab739ee8ebe224d28ad0dae55bc2e934bfce1eba85\" timestamp=\"0x4c2d5bbb\" size=\"0x01250000\" added=\"2025-03-28T03:59:19Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27823.1000\" file=\"lxcore.sys\" hash=\"fd0f98285189b3f799475f8b39801f46b350a665b3a02fc2ae55a76f4dea9e0b\" timestamp=\"0xbf01a385\" size=\"0x0010f000\" added=\"2025-03-28T03:59:19Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27834.1000\" file=\"ntoskrnl.exe\" hash=\"716c19e3767551c9cb8d7fc4164ce6fe54788d15b87b26c46992f018673f68a2\" timestamp=\"0xb41e9015\" size=\"0x01456000\" added=\"2025-05-19T22:45:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27842.1000\" file=\"ntoskrnl.exe\" hash=\"c10faf39694bd2b42ee9427ef766236e714d663c362f3c7cda99c0b6fba556de\" timestamp=\"0x3ffb56bd\" size=\"0x01456000\" added=\"2025-04-25T01:12:29Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27842.1000\" file=\"ntkrla57.exe\" hash=\"f95161b2520d93747a85109e634569aa3e0b775e2744877609d99115eea608bf\" timestamp=\"0xf35d285d\" size=\"0x01450000\" added=\"2025-04-25T01:12:29Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27842.1000\" file=\"lxcore.sys\" hash=\"c58486a7a3426733b65f5720da725c39eb97cf71a159502911fbf88a977587b5\" timestamp=\"0xb2cae9e0\" size=\"0x0010f000\" added=\"2025-04-25T01:12:29Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27852.1000\" file=\"ntoskrnl.exe\" hash=\"711c87c7f01147cdf6fe3c757b164619c6b2a2a0d5a6c051aea7832d02d14b2d\" timestamp=\"0xaddb8f77\" size=\"0x01456000\" added=\"2025-05-10T01:12:18Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27852.1000\" file=\"ntkrla57.exe\" hash=\"1021eb9a2103c6a35f018f583e987b35010bf6cae6f9d2614a41ed8ffda62c6b\" timestamp=\"0xa71f49f9\" size=\"0x01450000\" added=\"2025-05-10T01:12:18Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27854.1000\" file=\"ntoskrnl.exe\" hash=\"03eb0a0d447cbf9211d06bb5d52c8e80b7d3e6e1ac57d9d094020bd6df6a0aea\" timestamp=\"0x6a08a5ec\" size=\"0x01456000\" added=\"2025-05-19T22:45:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27858.1000\" file=\"ntoskrnl.exe\" hash=\"2ee6c4d86603df4364db2d027fdc2fbc997d0fe331a84e52ef5ef1a6b61db21f\" timestamp=\"0x44de5be8\" size=\"0x01456000\" added=\"2025-05-17T15:31:20Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27858.1000\" file=\"ntkrla57.exe\" hash=\"6e8e65c517c37d94c6368bd42cd1f2d60e08c3cfcd6b12d2ef4d4a459970013e\" timestamp=\"0xf3054885\" size=\"0x01450000\" added=\"2025-05-17T15:31:20Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27858.1000\" file=\"lxcore.sys\" hash=\"ac06a37ec14b09bd7b9cde830514bed831c1d4d2beb02960fb53befc6fe8bbdc\" timestamp=\"0x6a5795e5\" size=\"0x0010f000\" added=\"2025-05-17T15:31:20Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27863.1000\" file=\"ntoskrnl.exe\" hash=\"4efcf53305ac279beac9d303e1900cce5c8ca2dbe5d8de2a8662d64cbe17b1a2\" timestamp=\"0x615c3c12\" size=\"0x01456000\" added=\"2025-05-24T14:17:56Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27863.1000\" file=\"ntkrla57.exe\" hash=\"00119d446f63cb8446d63cbd888213c1575d0dad340f68d8f9c0004dc456fa21\" timestamp=\"0x2e26d77c\" size=\"0x01450000\" added=\"2025-05-24T14:17:56Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27863.1000\" file=\"lxcore.sys\" hash=\"e25274534a92e0cc0f49a65dcfb8368855b88f5bda73d2877fc0c0c6f50a05a9\" timestamp=\"0xb7caf6ba\" size=\"0x0010f000\" added=\"2025-05-24T14:17:56Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27868.1000\" file=\"ntoskrnl.exe\" hash=\"af053df9b66bfe3bed34269cfff2e9e1abeb5565ee5385a5458e3b737307763c\" timestamp=\"0xfbfa7ec9\" size=\"0x01457000\" added=\"2025-05-30T19:55:37Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27868.1000\" file=\"ntkrla57.exe\" hash=\"ad3886015d5e99cc360ca38412219309f9561e803a7a445f24bda81e8dacb194\" timestamp=\"0x00d2d09d\" size=\"0x01450000\" added=\"2025-05-30T19:55:37Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27868.1000\" file=\"lxcore.sys\" hash=\"108410212997f3f65553c006c243fbc751292473b5d2699bf1c47d2da6aac7ea\" timestamp=\"0x22dc9c50\" size=\"0x0010f000\" added=\"2025-05-30T19:55:37Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27871.1000\" file=\"ntoskrnl.exe\" hash=\"f21c1d6a8f21e0dfcf99c1fea3a0ad632df6530d10aea663629708f9e5871e49\" timestamp=\"0xa1fd9894\" size=\"0x01456000\" added=\"2025-06-07T14:16:57Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27871.1000\" file=\"ntkrla57.exe\" hash=\"f43c41e474aad28fe51ee8d3d09bdbe8620f0228a1f6ddad0e14bfe0d629e86a\" timestamp=\"0x06bceca5\" size=\"0x01450000\" added=\"2025-06-07T14:16:57Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27871.1000\" file=\"lxcore.sys\" hash=\"2063c1330be69c1e75e078bcbf9802d8617034412c7b5a60546e2fcef9879e13\" timestamp=\"0x512e4b55\" size=\"0x0010f000\" added=\"2025-06-07T14:16:57Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27881.1000\" file=\"ntoskrnl.exe\" hash=\"e6f7355ed9ad3ce1d674093026517de281dcb287cf478a66177cbc1bfd5bcd1a\" timestamp=\"0xdf4f2809\" size=\"0x01458000\" added=\"2025-06-20T04:21:21Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27881.1000\" file=\"ntkrla57.exe\" hash=\"23f67d007824a58545104be6fa528b4bcc84466e12163e6ab2f5e3f218cc3387\" timestamp=\"0x33757d7b\" size=\"0x01450000\" added=\"2025-06-20T04:21:21Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27891.1000\" file=\"ntoskrnl.exe\" hash=\"a5e10cc40b2c9af5233697ce756de1c41330e89a3af92d444ddb946cb5b0151c\" timestamp=\"0xdaa90c28\" size=\"0x01459000\" added=\"2025-07-04T02:52:29Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27891.1000\" file=\"ntkrla57.exe\" hash=\"7797e0289d791610e77299bbe46f1b4fe6009f6cfaa2ed3a90b89cdc63a3f055\" timestamp=\"0xb28605af\" size=\"0x01450000\" added=\"2025-07-05T15:11:44Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27898.1000\" file=\"ntoskrnl.exe\" hash=\"6a44d53d1c5372956a15a752a2f42459ea575a92a1a0a09a74270b793c623425\" timestamp=\"0x90d3b43c\" size=\"0x01459000\" added=\"2025-07-12T20:34:08Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27898.1000\" file=\"ntkrla57.exe\" hash=\"3891bcb1b230950b514d9cea8e35ab6121ede346a5195521c48c7d65b3cce471\" timestamp=\"0x4096ce2d\" size=\"0x01450000\" added=\"2025-07-12T20:34:08Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27902.1000\" file=\"ntoskrnl.exe\" hash=\"bcb01e5f9982c0bd9297bc5733a0262ed57c476b43879529eaf44f8616063715\" timestamp=\"0xbbe4dceb\" size=\"0x01458000\" added=\"2025-07-19T02:10:13Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27902.1000\" file=\"ntkrla57.exe\" hash=\"a6bf612d23954cca789969b0ff94eb28d05b8e269bd0a5a6f51cc0f054dede32\" timestamp=\"0x09a618f6\" size=\"0x01450000\" added=\"2025-07-19T02:10:13Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27909.1000\" file=\"ntoskrnl.exe\" hash=\"d5d6ef5ff1ee8dddb924658c85ff06604fe6c48cbb782734ab1f635feb4806a0\" timestamp=\"0xec2ebcaa\" size=\"0x01459000\" added=\"2025-07-26T16:12:52Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27909.1000\" file=\"ntkrla57.exe\" hash=\"d317755dbe0d295fbcbee9bdbf1b317c362762fc04f48eff7c6b2b4f66fb63d0\" timestamp=\"0xf9b9d7cb\" size=\"0x01450000\" added=\"2025-07-26T16:12:52Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27913.1000\" file=\"ntoskrnl.exe\" hash=\"9363cf90c8107cafe85b6a5ed8381498629d2bf8e9c6c51add2f749bcc83533c\" timestamp=\"0xacd54aad\" size=\"0x01459000\" added=\"2025-08-01T03:02:04Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27913.1000\" file=\"ntkrla57.exe\" hash=\"e98785fc24c728f6bb20a10ae7f464e7d46fb4f5ae631f8e74fa66e56785aa20\" timestamp=\"0x49dbef26\" size=\"0x01450000\" added=\"2025-08-01T03:02:04Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27919.1000\" file=\"ntoskrnl.exe\" hash=\"8127cb724e08b28b5579deeb840a57ca151bb8464ee80238aee50f3f2e309884\" timestamp=\"0x5f640901\" size=\"0x01459000\" added=\"2025-08-12T05:13:33Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27919.1000\" file=\"ntkrla57.exe\" hash=\"76e8e56f1cbb95b0ccd43ee2b56b0e966deaf0a3a314f6f44a803ff4626872ac\" timestamp=\"0xe1c15bca\" size=\"0x01450000\" added=\"2025-08-12T05:13:33Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27924.1000\" file=\"ntoskrnl.exe\" hash=\"c14807e21ce989e2a1170455c4f74e4e58be6a29fe29b7684845628a30dec008\" timestamp=\"0xf5f09d88\" size=\"0x01459000\" added=\"2025-08-16T02:03:03Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27924.1000\" file=\"ntkrla57.exe\" hash=\"48cc9b9341a8bc673511bf3cfd483ebc58420dd4eac8b84f1ed290f3b1db351b\" timestamp=\"0x914d3839\" size=\"0x01451000\" added=\"2025-08-16T02:03:03Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27924.1000\" file=\"lxcore.sys\" hash=\"5882bbb4777ed2818fd66a6b89ad61f00fa8cf380401ac1bb7ede2430378cac7\" timestamp=\"0xef76372e\" size=\"0x0010f000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27928.1\" file=\"ntoskrnl.exe\" hash=\"aac8ff4f26a72d8f429aeff11c1276a81045e033cf8f60559b6609e248e93c70\" timestamp=\"0xbe0258c0\" size=\"0x01459000\" added=\"2025-08-21T15:11:13Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27928.1\" file=\"ntkrla57.exe\" hash=\"7ba58ac4f350130bce1fad65a8cefac7d7074ba49a0456bd17689c11d214877d\" timestamp=\"0x74ca5e6f\" size=\"0x01450000\" added=\"2025-08-21T15:11:13Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27934.1\" file=\"ntoskrnl.exe\" hash=\"22de415ef3654ebdbacbb52793da569c0abc0b79a65555d33f051229f672b1a0\" timestamp=\"0x048855ca\" size=\"0x01459000\" added=\"2025-08-30T18:01:05Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27934.1\" file=\"ntkrla57.exe\" hash=\"b83a6e572420ddafe2e096bb5da8b97715868d6f949f8f86a86fd37a13491006\" timestamp=\"0x4d422f66\" size=\"0x01450000\" added=\"2025-08-30T18:01:05Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27934.1\" file=\"lxcore.sys\" hash=\"eab73043f498b409219aed91f001b106cf0a8ee92226d96de4af156b1ee0bc0e\" timestamp=\"0x0704fee6\" size=\"0x0010f000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27938.1\" file=\"ntoskrnl.exe\" hash=\"5c5a1c5b8e67b28999f6a5c77b045e96ca42be43ecb4dc9234f9319165812ec3\" timestamp=\"0x89ee1c74\" size=\"0x01459000\" added=\"2025-09-11T03:22:38Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27938.1\" file=\"ntkrla57.exe\" hash=\"61ecad7f6182c3d7f6d5ed0f83f8352db52310903a45c90e1aab5b579a895e95\" timestamp=\"0x89dd3610\" size=\"0x01450000\" added=\"2025-09-11T03:22:38Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27943.1\" file=\"ntoskrnl.exe\" hash=\"935fdcd63aee52e6c0d2357bff57063f2c95d8a40c8bb959e3c0f9858848324b\" timestamp=\"0xab58ff33\" size=\"0x01459000\" added=\"2025-09-12T23:16:14Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27943.1\" file=\"ntkrla57.exe\" hash=\"bfdbd4a23837fb583020df018239339f90bc207f0a070d66ee6e5b617d8d9194\" timestamp=\"0x94ce50db\" size=\"0x01450000\" added=\"2025-09-12T23:16:14Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27943.1\" file=\"lxcore.sys\" hash=\"68ff7378f89729a2a76ad4dea174ee409ea6fd7f606bd46fb638ceaacb91d679\" timestamp=\"0x02ff6251\" size=\"0x00110000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27950.1\" file=\"ntoskrnl.exe\" hash=\"ddeda7b8ac066ea7eabe538d309103a8e74abe4ba3e327665f24e43b6781f138\" timestamp=\"0x6d87cc43\" size=\"0x01459000\" added=\"2025-09-21T13:49:59Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27950.1\" file=\"ntkrla57.exe\" hash=\"ee0c2facf5de1d53ecad1f59cba3e14f51526c4c3f7f8723f0b5ed6d6a238e9b\" timestamp=\"0xc8c64a9c\" size=\"0x01450000\" added=\"2025-09-21T13:49:59Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27954.1\" file=\"ntoskrnl.exe\" hash=\"88d9e86345e73eb397b81e600598a1d65816e76f0774e810d8100b8d884531c3\" timestamp=\"0xfcb2d19e\" size=\"0x01459000\" added=\"2025-09-26T02:51:04Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27954.1\" file=\"ntkrla57.exe\" hash=\"8c57f000ddef6191d9e95dc792a64df9cf769d11dae0ace0dea59a2d0369117a\" timestamp=\"0x74513ff6\" size=\"0x01450000\" added=\"2025-09-27T02:00:45Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27954.1\" file=\"lxcore.sys\" hash=\"83d48bc382e98f03934984d0e4e61a491782ba92d69619f05daa508757dd52e7\" timestamp=\"0xfcf68042\" size=\"0x00110000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27959.1\" file=\"ntoskrnl.exe\" hash=\"b3ab594347e6ab07a5349740c02b930397125741e7f8a349191e6c765cdda9a0\" timestamp=\"0xad40930d\" size=\"0x01459000\" added=\"2025-10-09T21:10:38Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27959.1\" file=\"ntkrla57.exe\" hash=\"1c259aa8797f9d19f8e7e094d9dddddf6e1b36d76d20330c7534716501fa137a\" timestamp=\"0x54041e67\" size=\"0x01450000\" added=\"2025-10-09T21:10:38Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27965.1\" file=\"ntoskrnl.exe\" hash=\"55f607e8969c923d967696a62dc360b08b9e2b23d04d6363cd7eb6dcdce8ef0a\" timestamp=\"0x103f80e0\" size=\"0x01459000\" added=\"2025-10-09T21:10:38Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27965.1\" file=\"ntkrla57.exe\" hash=\"9585ce422cfed2ac9b3ed5aa1692b2b6cac611be84fd9f00e907185c655c8776\" timestamp=\"0x850806d8\" size=\"0x01450000\" added=\"2025-10-09T21:10:38Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27965.1\" file=\"lxcore.sys\" hash=\"a81a41fa06ca71ef78f47121fadb8ce47f7c67ae5363d17eaed927d65a3f3c33\" timestamp=\"0xc3d921ff\" size=\"0x00110000\" added=\"2025-11-26T04:11:01Z\">14</data>\n    <data arch=\"amd64\" version=\"10.0.27971.1\" file=\"ntoskrnl.exe\" hash=\"53c13faf6e4d52a34f66058d35f91dd98880ef959e188cbc08178a3b9fac29bd\" timestamp=\"0x7d516b81\" size=\"0x01459000\" added=\"2025-10-16T23:37:47Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27971.1\" file=\"ntkrla57.exe\" hash=\"5a62713b34e3bf9a79d7ae6265a320fed81c694c578512b1bf49053464a64d74\" timestamp=\"0x029ae5cb\" size=\"0x01451000\" added=\"2025-10-24T14:15:26Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27975.1\" file=\"ntoskrnl.exe\" hash=\"0e815fb8a6933c2b73ff839c9670b6c4e7836ce6f0d7bdc60afb7592020a02ce\" timestamp=\"0xa1c68eb7\" size=\"0x01459000\" added=\"2025-10-24T14:15:26Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27975.1\" file=\"ntkrla57.exe\" hash=\"ea42edf696f8ec0a6151cb9d7c5a2d95c8ca10da6c768ac164c24e3e94cd406c\" timestamp=\"0xf440fe39\" size=\"0x01451000\" added=\"2025-10-24T14:15:26Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27975.984\" file=\"ntoskrnl.exe\" hash=\"a33f81e4e295df72fcdbbaf7fdebbe4252efb83ae945c4968461022f3ff09524\" timestamp=\"0x2c5f7b83\" size=\"0x01459000\" added=\"2025-10-29T20:10:48Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27975.984\" file=\"ntkrla57.exe\" hash=\"d10b500118968055e140b058b43479366736897d90f7a22376e44fa5b1a42a15\" timestamp=\"0x67cf3e47\" size=\"0x01451000\" added=\"2025-10-29T20:10:48Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.27982.1\" file=\"ntoskrnl.exe\" hash=\"fb5b84d71b01407fef05673d8f104e975a8c8fd2e9053fab4ab7f2dea3ee2d74\" timestamp=\"0x1890d094\" size=\"0x01459000\" added=\"2025-11-05T04:35:14Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.27982.1\" file=\"ntkrla57.exe\" hash=\"dfa90119e833e1cf0f80bb908950c4207581ba746e40e00eb110b911d626e453\" timestamp=\"0x436106dc\" size=\"0x01451000\" added=\"2025-11-05T04:35:14Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1\" file=\"ntoskrnl.exe\" hash=\"bd03f8757b633b0aa65ad2f780a5a9521f87f4c8ed7894483184e3bf01711620\" timestamp=\"0x22bdf92f\" size=\"0x01459000\" added=\"2025-11-09T14:13:48Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1\" file=\"ntkrla57.exe\" hash=\"c0efd943e9051708adf082c60adfdf1caeda75809ba403ab333ba4063bda4b6d\" timestamp=\"0x11197b40\" size=\"0x01451000\" added=\"2025-11-09T14:13:48Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.4\" file=\"ntoskrnl.exe\" hash=\"fc6a0f11a62d07f95f3e793af8e7c41e5d4b84a7417dd073a4357c4dd5e5abf3\" timestamp=\"0xd41c0259\" size=\"0x01459000\" added=\"2025-12-24T02:56:52Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.4\" file=\"ntkrla57.exe\" hash=\"288d7024550b8316c05a10204f48a0c34ce4ebe2644d10230764d709af709a0a\" timestamp=\"0xa8faeeb4\" size=\"0x01451000\" added=\"2025-12-24T02:56:52Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1199\" file=\"ntoskrnl.exe\" hash=\"8363d7054d63e48ecb5080d4933927b0be942ce3d43606891c0a38851f5e90ea\" timestamp=\"0x07e9c3ae\" size=\"0x01459000\" added=\"2025-11-20T04:01:51Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1199\" file=\"ntkrla57.exe\" hash=\"4a457609108d6b4f0217118e72c2f2426a741f8d0854a17dc3572336e91735f9\" timestamp=\"0xcbae99b4\" size=\"0x01451000\" added=\"2025-11-20T04:01:51Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1340\" file=\"ntoskrnl.exe\" hash=\"d2b31edb1ee45b85b087af80c11a2b5ad1017300f2dfae3bd0a8d0812eae52b7\" timestamp=\"0xde233e69\" size=\"0x01459000\" added=\"2025-12-10T04:39:55Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1340\" file=\"ntkrla57.exe\" hash=\"ba8ea125ed3d357e517b75490fed29921369e270011c6c0e25dc19d40239d4e6\" timestamp=\"0xffbd12d6\" size=\"0x01451000\" added=\"2025-12-10T04:39:55Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1362\" file=\"ntoskrnl.exe\" hash=\"68d5867b5e66fce486c863c11cf69020658cadbbacbbda1e167766f236fefe78\" timestamp=\"0x42a2070f\" size=\"0x01459000\" added=\"2025-12-18T01:38:46Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1362\" file=\"ntkrla57.exe\" hash=\"9f67f21d4a5881488b080e689e2ff22e646913c011501a68ae636fed491fd838\" timestamp=\"0x1e2b8704\" size=\"0x01451000\" added=\"2025-12-18T01:38:46Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1371\" file=\"ntoskrnl.exe\" hash=\"6ac786657eb2e9cb7ca179779204b321adf2e182a0274e48fc8cb68f19b23de4\" timestamp=\"0x72bcd710\" size=\"0x01459000\" added=\"2026-01-15T04:51:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1371\" file=\"ntkrla57.exe\" hash=\"c9752c3a5196d5e57aa10c47690965f4913c65c8d06e67171fd413a291ec8a33\" timestamp=\"0xf17645c3\" size=\"0x01451000\" added=\"2026-01-17T15:14:22Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1446\" file=\"ntoskrnl.exe\" hash=\"10b4935aace01ebb72ca9999b3dc1c243b96c65a6f68becda03d1d81a0d7ff14\" timestamp=\"0x1698bb67\" size=\"0x01459000\" added=\"2026-01-15T04:51:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1450\" file=\"ntoskrnl.exe\" hash=\"393f76166ae48079a628f52e971bb87037cd77085819418b7b7dc4184222a3a9\" timestamp=\"0xe0260748\" size=\"0x01459000\" added=\"2026-01-15T04:51:11Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1450\" file=\"ntkrla57.exe\" hash=\"8b6ced5048838dccf60f6c8d88ec4567bcd88dcc1a3798fc22dc580be7a6477d\" timestamp=\"0x76b69ad7\" size=\"0x01451000\" added=\"2026-01-15T04:51:11Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1495\" file=\"ntoskrnl.exe\" hash=\"12611b29eb34ca44b1b53855a55c9b7c5d60ab10f1c1f8b9291f1ee9a12d3b0b\" timestamp=\"0x31388b8f\" size=\"0x01459000\" added=\"2026-02-01T01:21:00Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1495\" file=\"ntkrla57.exe\" hash=\"0abc4a2716d6c550956ca12f3dd7345f9100b1cd2010e2ef438ff577e761d8f3\" timestamp=\"0xc9c8eb77\" size=\"0x01451000\" added=\"2026-02-01T01:21:00Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1546\" file=\"ntoskrnl.exe\" hash=\"3206d6262d802aa961213607e08f7b5ea509afe43645771baadfd165ee52bc59\" timestamp=\"0x7afe341e\" size=\"0x01459000\" added=\"2026-02-05T23:25:24Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1546\" file=\"ntkrla57.exe\" hash=\"2a09316578dbfc0fd5209f41a60a9902b890e315a96730aa91a556e83fee31c0\" timestamp=\"0x6396269f\" size=\"0x01451000\" added=\"2026-02-05T23:25:24Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1575\" file=\"ntoskrnl.exe\" hash=\"9b2063bdf3b5a20190a469e27a242f5ba10cfcff560bc3c08ed3283e35acf312\" timestamp=\"0x72002fbb\" size=\"0x01459000\" added=\"2026-02-11T00:54:58Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1575\" file=\"ntkrla57.exe\" hash=\"0931e6705c117aa9ebd98d90629d9a11c9ebbfaca5cf16d1547066eef0fd3638\" timestamp=\"0x02ed4c82\" size=\"0x01451000\" added=\"2026-02-11T00:54:58Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1611\" file=\"ntoskrnl.exe\" hash=\"5e2e05abccb844153919819f79256f4e1b6ed1aa47eca0f71d21c38b718e95c2\" timestamp=\"0x2f90fa2c\" size=\"0x01459000\" added=\"2026-02-13T07:18:51Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1611\" file=\"ntkrla57.exe\" hash=\"49c86756ec17d8b6c64ee48547d1bd215faf54ebdbe4389379e0a8726afb88d3\" timestamp=\"0x5d90d125\" size=\"0x01451000\" added=\"2026-02-14T07:40:21Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1619\" file=\"ntoskrnl.exe\" hash=\"a1fde922f7004d50414d3d988b5a979c60a4c3c18d41c747f52f8686dc538c3d\" timestamp=\"0x2058ad44\" size=\"0x01459000\" added=\"2026-02-21T23:40:53Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1619\" file=\"ntkrla57.exe\" hash=\"706f25e3b8e5295abfccbcfb360673c59cbb2e2546a62b6e8789ed5e191857c9\" timestamp=\"0x0c5584d9\" size=\"0x01451000\" added=\"2026-02-28T14:39:37Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1643\" file=\"ntoskrnl.exe\" hash=\"d938c989b653510d613a8b81a3a1b09cc605bd73dc18bba53e69d28222bb056f\" timestamp=\"0xb1ecf354\" size=\"0x01459000\" added=\"2026-02-25T16:03:39Z\">31</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1643\" file=\"ntkrla57.exe\" hash=\"c3a77e8754505275b1e776c05e7c37de6cbabb81eea829b75c498d38113af802\" timestamp=\"0x5e639266\" size=\"0x01451000\" added=\"2026-02-25T16:03:39Z\">32</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1673\" file=\"ntoskrnl.exe\" hash=\"fb5cfc27135da0b9295c577640c375fee0fe99bba3c8e723e0f6500855c878a1\" timestamp=\"0xab4fee4f\" size=\"0x01459000\" added=\"2026-02-28T14:39:37Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1673\" file=\"ntkrla57.exe\" hash=\"be5fbe1f7ea8f42cb4bd46482ac11249f771032763bcc7675c9a39d5bbc396f5\" timestamp=\"0x5c1cf42d\" size=\"0x01451000\" added=\"2026-03-04T03:13:34Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1685\" file=\"ntoskrnl.exe\" hash=\"5dd9d2d09bce5718d3a739c51da5519c1fdd4d17f0fd06b09bba49ec11a96259\" timestamp=\"0xf1df13b0\" size=\"0x01459000\" added=\"2026-03-11T23:28:21Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1719\" file=\"ntoskrnl.exe\" hash=\"56f61593e90e42437ee3894117f0a2dc196f46780194302d0c6238a1f6e246c4\" timestamp=\"0x431db839\" size=\"0x01459000\" added=\"2026-03-11T23:28:21Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1719\" file=\"ntkrla57.exe\" hash=\"b97aa07e7c1aa620a3b9f64f9b673e20e412632fa05fe30891f6c6dada71933b\" timestamp=\"0xe862d075\" size=\"0x01451000\" added=\"2026-03-11T23:28:21Z\">26</data>\n    <data arch=\"amd64\" version=\"10.0.28000.1737\" file=\"ntoskrnl.exe\" hash=\"23aa6e269b2395157f017695c97eb87ba1d7bafbee9a3caf068e455b50cfd5d7\" timestamp=\"0x6862f6c2\" size=\"0x01459000\" added=\"2026-03-14T04:38:17Z\">25</data>\n    <data arch=\"amd64\" version=\"10.0.29531.1000\" file=\"ntoskrnl.exe\" hash=\"5d493916b9d48691667493284d34d682cfa192f35a235c2e00f823cd3d99a605\" timestamp=\"0x75762d11\" size=\"0x01459000\" added=\"2026-02-13T07:18:51Z\">28</data>\n    <data arch=\"amd64\" version=\"10.0.29531.1000\" file=\"ntkrla57.exe\" hash=\"f7358413d82223e92abd4fa224ea6ba524ca57316314189886febb53c7009a32\" timestamp=\"0xada1f48e\" size=\"0x01451000\" added=\"2026-02-13T07:18:51Z\">29</data>\n    <data arch=\"amd64\" version=\"10.0.29550.1000\" file=\"ntoskrnl.exe\" hash=\"40775320910563e380c128d48de61e200650f6955c875c1a2df8ce0e8a09b567\" timestamp=\"0xa1b1fa2b\" size=\"0x01459000\" added=\"2026-03-14T04:38:17Z\">28</data>\n    <data arch=\"amd64\" version=\"10.0.29550.1000\" file=\"ntkrla57.exe\" hash=\"61a000b5b2aa44cf33aa68518655556e8042254b31557c42bcdda78afa54d419\" timestamp=\"0x4042cc99\" size=\"0x01451000\" added=\"2026-03-15T01:29:55Z\">29</data>\n    <data arch=\"arm64\" version=\"10.0.16299.15\" file=\"ntoskrnl.exe\" hash=\"91a192d28642f36d3de02fc1f24d2c27f4f4cfa3f4141a4a96042ad0c49e062a\" timestamp=\"0x59cda103\" size=\"0x008cc000\" added=\"2025-07-05T15:11:44Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.19\" file=\"ntoskrnl.exe\" hash=\"b87af01f8162b8742490e40ea96c3df977ccaed3c1d4239e84f1a515c9fa719d\" timestamp=\"0x59dc5276\" size=\"0x008cb000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.64\" file=\"ntoskrnl.exe\" hash=\"b69c45a5f36a89b328f8c33206827aa9a20aab9b6de82072746ebb90d4fddc2e\" timestamp=\"0x59f0002a\" size=\"0x008cb000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.125\" file=\"ntoskrnl.exe\" hash=\"42d360571b1e75b36dc497f58d4f65bc1ee8e8c512d9e1c0d29ab3232ccb901b\" timestamp=\"0x5a29b7fc\" size=\"0x008cb000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.192\" file=\"ntoskrnl.exe\" hash=\"0a8e1e55fb534548c5d3ef12336322662f8bf23bfaa2c78b2fa36de59940d5ac\" timestamp=\"0x5a4a1693\" size=\"0x008a0000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.248\" file=\"ntoskrnl.exe\" hash=\"39274e8d65d358fe5a0e63918a91291de956ea40db66e53964531e093f71a08a\" timestamp=\"0x5a7e7379\" size=\"0x0089f000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.309\" file=\"ntoskrnl.exe\" hash=\"f0a7a0e169d723e570a1901e2f29fb6ba1edb6170a1e53702a28d1e6af41c20a\" timestamp=\"0x5a978f21\" size=\"0x0089e000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.334\" file=\"ntoskrnl.exe\" hash=\"5d1636205b61338320fd841a183a2c517434051181d04f6c326f070433d63422\" timestamp=\"0x5aa74f9a\" size=\"0x0089e000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.371\" file=\"ntoskrnl.exe\" hash=\"4d53a27c0701a195f4d8e7cc9baccd25a5eefd7b499b76e7291bb4a3c6e42b78\" timestamp=\"0x5abdad3e\" size=\"0x0089d000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.492\" file=\"ntoskrnl.exe\" hash=\"2a2ca1d322b2dae454ee96b1c6b1a294ce4a46fc43fedc2a12d71f5aa11df3c9\" timestamp=\"0x5b1a1069\" size=\"0x0089a000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.547\" file=\"ntoskrnl.exe\" hash=\"fa0cc3690755940c14202083f247fa93039b8f31ccfa6a25ee515346a5f1ad33\" timestamp=\"0x5b35e6d6\" size=\"0x00899000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.551\" file=\"ntoskrnl.exe\" hash=\"71cd66fb57071bd6d77388a0cfdccf861d9e7e47c0bf16dedb00e5afb3d52f04\" timestamp=\"0x5b484934\" size=\"0x00899000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.579\" file=\"ntoskrnl.exe\" hash=\"b45d487f02a3a159ea8b9e505ca7e7e82a318f449cff83a8f96888cf713298dd\" timestamp=\"0x5b4e9e0f\" size=\"0x00899000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.611\" file=\"ntoskrnl.exe\" hash=\"4888723fc33e8794530aae6d45450f59c78df6e20a91e66f967a3f69610bb8d8\" timestamp=\"0x5b691b34\" size=\"0x00896000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.637\" file=\"ntoskrnl.exe\" hash=\"49263f395b17a84957e4f034f303f8b509969ed5089bc1ed9d9a4f4179489e67\" timestamp=\"0x5b6bbfef\" size=\"0x00896000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.665\" file=\"ntoskrnl.exe\" hash=\"320ca7809ec6530440141f14b066a30db7e64abecd57a56ab5c6bf08022433db\" timestamp=\"0x5b84cdd0\" size=\"0x00896000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.666\" file=\"ntoskrnl.exe\" hash=\"1c7b1a047a4bf7dde47f7120a61e6ad6e21bfe079f8a010f6a082f28b48575d7\" timestamp=\"0x5b9c7421\" size=\"0x00896000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.699\" file=\"ntoskrnl.exe\" hash=\"c395903f3388b4e7c3ce33d9cca0f8eaf548dae3f9ffd1b2316ba37f9316d37c\" timestamp=\"0x5ba70f14\" size=\"0x00896000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.726\" file=\"ntoskrnl.exe\" hash=\"b6c43f60de1d90283a90303f25a4897496cb91de32ccfe953dc198f0f6579e3d\" timestamp=\"0x5ba9ad87\" size=\"0x00896000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.755\" file=\"ntoskrnl.exe\" hash=\"b0bcc871de246fb68c693585ea3b214a1090cfab811b0c3fa66598689a0548fb\" timestamp=\"0x5bbd74de\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.785\" file=\"ntoskrnl.exe\" hash=\"eacefe993e15f65f64696ae2ea98b231fd380d851881a7fba5b99a5afc582b17\" timestamp=\"0x5bd7db14\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.820\" file=\"ntoskrnl.exe\" hash=\"ecbc67f55341e669f470e88edc1dc3513f81a9ed4f92ee5b2f859f1a1282a905\" timestamp=\"0x5be270d7\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.846\" file=\"ntoskrnl.exe\" hash=\"12aff9d35212952745749d58d790c67bb732c7defde7c50c68d35157c9cee1b5\" timestamp=\"0x5c060b05\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.904\" file=\"ntoskrnl.exe\" hash=\"3a70854e8565e078492e5cca01e4a749f716514b4975a29d4a9c830ed9311980\" timestamp=\"0x5c2b054c\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.936\" file=\"ntoskrnl.exe\" hash=\"2b0f64ce116071dbb24513ce4a9d0540e3be670afbdc2aa59dc9c58fa45062d3\" timestamp=\"0x5c30522f\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.967\" file=\"ntoskrnl.exe\" hash=\"5914122e6bb662a8ca011bf3e699c243014c16ed0d3ae195ddbe0ccaabdeed02\" timestamp=\"0x5c5a5559\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1004\" file=\"ntoskrnl.exe\" hash=\"3744752069f13da1d2b728386c94373d2b342254818ad0c0af9c3c8632991459\" timestamp=\"0x5c689bef\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1029\" file=\"ntoskrnl.exe\" hash=\"848a799bb140053e9136bdf5a63c5cd3ef42d80e0996de01c2f9ead333b31d5d\" timestamp=\"0x5c7f65bd\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1059\" file=\"ntoskrnl.exe\" hash=\"83442ee412fa05069c7005b4d44409ce9616e0ffc06b6426d861c60192cc50c6\" timestamp=\"0x5c89ee65\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1087\" file=\"ntoskrnl.exe\" hash=\"9198285775f725aed4bfa701ebee90c311bc0c072e543a7dc31a307dbcce37e3\" timestamp=\"0x5ca2e54d\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1120\" file=\"ntoskrnl.exe\" hash=\"2e6c0308a786466af83d595d0dc4b4717a1ea63bcc9edc279016064ef41adc95\" timestamp=\"0x5ca83407\" size=\"0x00892000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1146\" file=\"ntoskrnl.exe\" hash=\"caf1cf1e12d7e7c9e8c7bffa052b2179a3c2e8b73b8e2e49889cee9b8480c89b\" timestamp=\"0x5ccbd949\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1182\" file=\"ntoskrnl.exe\" hash=\"380ac0af13311105312a7ed870ee415f9f8fbacf5daa2178bdbd4234937e7639\" timestamp=\"0x5ce60ad5\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1237\" file=\"ntoskrnl.exe\" hash=\"d59b09551df7a1cbc0ecd58c52a607a464366e3c82101da6d16c30c9ce39982c\" timestamp=\"0x5d01d6da\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1296\" file=\"ntoskrnl.exe\" hash=\"4be7f86bafbe924a4d54a432ef21824b095514a954a9fabef4d6fd049a250fa5\" timestamp=\"0x5d2405ce\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1331\" file=\"ntoskrnl.exe\" hash=\"fce2c14d4dc76930cc4466cbd762216f444e06235df2149d8d344063bb268fc9\" timestamp=\"0x5d4a8403\" size=\"0x00893000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1364\" file=\"ntoskrnl.exe\" hash=\"400c6c7fc807e8fa4d5fd42059f6b3e1e67bd738c8a96174fd8c908cfcd0fd82\" timestamp=\"0x5d4bac4f\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1387\" file=\"ntoskrnl.exe\" hash=\"3145feb64f2d75f3159cc48cc2379cc280cbc4d4542e2142f0461f5b3386fc0f\" timestamp=\"0x5d6f4776\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1419\" file=\"ntoskrnl.exe\" hash=\"5c058bfe2b24d659f8f42c09a9d09222cf41e2264841f59191fa96aadc3c765f\" timestamp=\"0x5d7b227b\" size=\"0x00893000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1448\" file=\"ntoskrnl.exe\" hash=\"637fd1bb2ec57d89f5080bfcccc0cf40bfffed792d407d549f52c819a70caa60\" timestamp=\"0x5d942bf0\" size=\"0x00893000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1480\" file=\"ntoskrnl.exe\" hash=\"6f380f0f65b4ddb35d1be8fe0f36ef1599fc96599e1c393c03ab56ac3ae457b6\" timestamp=\"0x5d942cff\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1653\" file=\"ntoskrnl.exe\" hash=\"48e2059f064e80a9bcdfb42d30200583a58fc726f1ca64649f8283d3a6a6a712\" timestamp=\"0x5df1c527\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1715\" file=\"ntoskrnl.exe\" hash=\"0dd19372c996f57c67b012c5491dbef70edba6a1b3d46df13c913ee312be427b\" timestamp=\"0x5e292dc0\" size=\"0x00893000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1775\" file=\"ntoskrnl.exe\" hash=\"2eb7e0e1b61939ac5465dfcf1b73a1389cf8df2b4a28c702dabfeb0ed08b0b55\" timestamp=\"0x5e61be12\" size=\"0x0088b000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1776\" file=\"ntoskrnl.exe\" hash=\"2112f077beaadbb4086aed24a4077340aca18d5695477677bb6f34360701550e\" timestamp=\"0x5e7acfac\" size=\"0x0088b000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1937\" file=\"ntoskrnl.exe\" hash=\"91732e3bc35682d253f094523479591938e3ba94e4c8b44e068f7edba2b30605\" timestamp=\"0x5ee4a71b\" size=\"0x0088a000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.1992\" file=\"ntoskrnl.exe\" hash=\"277588ede19970a26234bde27baeaba50a65e2fd93ecfdbf32de1c79ef5af0c6\" timestamp=\"0x5f056d86\" size=\"0x0088b000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.2045\" file=\"ntoskrnl.exe\" hash=\"3d2069a15185b703499893113c9f8cc0aa515aeca9ac8c8c8a463f7950bbaefd\" timestamp=\"0x5f2b3fa5\" size=\"0x0088c000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.2107\" file=\"ntoskrnl.exe\" hash=\"7f1d4962bce51d33667fe01e3cc148612f0830bbbb1e57892be308cb5f7553d4\" timestamp=\"0x5f4f25d3\" size=\"0x0088a000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.16299.2166\" file=\"ntoskrnl.exe\" hash=\"e0f96db43963fdc2461e0a2eb4ccec92e72be3fca6504cec259679201868ad08\" timestamp=\"0x5f742625\" size=\"0x0088a000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1\" file=\"ntoskrnl.exe\" hash=\"cdcf703ad4e4a21f529c717f33f41273a10dcb17069e351042c4e2765fd3a8a0\" timestamp=\"0x5acd8d34\" size=\"0x00915000\" added=\"2025-07-12T20:34:08Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.48\" file=\"ntoskrnl.exe\" hash=\"848091874fa9657968f7226f87c45bcc8119d88c4173727083ee9daf83769002\" timestamp=\"0x5ae3f44d\" size=\"0x00915000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.81\" file=\"ntoskrnl.exe\" hash=\"ab259ba9f4433f70dcee28424275439a2e83da808d3da1233dcf1fe46cfa39dc\" timestamp=\"0x5b0159a3\" size=\"0x00916000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.81\" file=\"lxcore.sys\" hash=\"7647865e71ccec8adab8558affb65afbef957f05ce4e0723f546f7b238d3b4a0\" timestamp=\"0x706e56fe\" size=\"0x00101000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.112\" file=\"ntoskrnl.exe\" hash=\"971420810ade35a39d5665207301a36bcebe9d898c26bb0302e4aadf92c096ae\" timestamp=\"0x5b1a4560\" size=\"0x00911000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.112\" file=\"lxcore.sys\" hash=\"404b3ecf8fb5be83246dce07e4525a2ca6944691531d3448f65283a7e2bdf53b\" timestamp=\"0xb5cd45c1\" size=\"0x00101000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.137\" file=\"ntoskrnl.exe\" hash=\"1094458c1c980bae94314ab322c8dc4ada54e23d32e1d27f65be962e639309fc\" timestamp=\"0x5b234578\" size=\"0x00912000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.165\" file=\"ntoskrnl.exe\" hash=\"b7adc68fa1e14528db779ce7c132072e22edde157e61a81039fbf362b424f75b\" timestamp=\"0x5b3f1413\" size=\"0x00912000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.167\" file=\"ntoskrnl.exe\" hash=\"d9612a5fbdfd440be6bf553b5bbc5cc2157be2f8b4b4e4a14cbccbf37f45a1a1\" timestamp=\"0x5b482384\" size=\"0x00912000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.191\" file=\"ntoskrnl.exe\" hash=\"9eead360d2e33d0f2398e5270c5e25954a2ca6a458bcae10dfcd87010877cf75\" timestamp=\"0x5b497470\" size=\"0x00912000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.228\" file=\"ntoskrnl.exe\" hash=\"f2f93097d2b7ec61228482f7fe57ee131000171fb565cc78fab40656cd7c8990\" timestamp=\"0x5b63c902\" size=\"0x008fd000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.228\" file=\"lxcore.sys\" hash=\"f234d54e69de74f134fd1ce14c33b8d7c8a2dc574ca8d1cf6ec2cfeb68a89c97\" timestamp=\"0xdc60673a\" size=\"0x00101000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.254\" file=\"ntoskrnl.exe\" hash=\"6b5c3df956e625b059a98ce6fefb089d2323de5ff3bb2fec702fee15b108bc76\" timestamp=\"0x5b6bc388\" size=\"0x008fd000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.285\" file=\"ntoskrnl.exe\" hash=\"27d5bdf1f09d6fb533fc96ca661800e3e902b4a93b5b6ec8641ae94dadb583aa\" timestamp=\"0x5b88b394\" size=\"0x008ff000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.285\" file=\"lxcore.sys\" hash=\"36d791e707e85b5fa2081432072a897fb5e305b7e3b1cecea284b3fd920d5612\" timestamp=\"0x5ff2c739\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.286\" file=\"ntoskrnl.exe\" hash=\"584b0a82aacff83e692831036544cb113321200d8733c4a4d873fbdbb4d6209a\" timestamp=\"0x5b9c6e46\" size=\"0x008ff000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.320\" file=\"ntoskrnl.exe\" hash=\"fe7ddea6b82d06bfbfb559a0be125d52b3e922d2c10d6abbda8710b0dc8bbe4e\" timestamp=\"0x5ba4688a\" size=\"0x008fd000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.345\" file=\"ntoskrnl.exe\" hash=\"e78700a9a07f85356c434926549ead12dceed2199c2057b9e0fff077ace6eb80\" timestamp=\"0x5ba32f27\" size=\"0x008fe000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.345\" file=\"lxcore.sys\" hash=\"524b9363d74de6a7b3742513471125ea3a2331a051ceaa5ad3fb95f2c67d423c\" timestamp=\"0xffbb8c7a\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.376\" file=\"ntoskrnl.exe\" hash=\"5a434c600c67e60a26ac5898156aec3d659404a29242b19af707165380151d2d\" timestamp=\"0x5bcc25b1\" size=\"0x008fe000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.407\" file=\"ntoskrnl.exe\" hash=\"7a92ddb090b56f4cf97ee6df479d1579625885888b4ea75a71bc8f9d17af2a17\" timestamp=\"0x5bda8c0c\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.441\" file=\"ntoskrnl.exe\" hash=\"69a6a73a9474285297e7b355377fb6f5767f524eee3d371a17e947e6d71ffa3e\" timestamp=\"0x5be4f442\" size=\"0x008f8000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.471\" file=\"ntoskrnl.exe\" hash=\"e8fa222af38a3d6d9d0a16b2ef2dd01f0b87692a145f83250976bc373ac289be\" timestamp=\"0x5c0b7479\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.471\" file=\"lxcore.sys\" hash=\"33366741dcccff461ea44d53347c093e34bbb83b8a1e2b4c58055eca98ecf94e\" timestamp=\"0xfd2fcd3d\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.523\" file=\"ntoskrnl.exe\" hash=\"edf5598b0c1a6dc82be61e7b6bd0645fe8d773d604c3750fc301d92f49c37ff8\" timestamp=\"0x5c2d696f\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.523\" file=\"lxcore.sys\" hash=\"41021d414e00670687d67dc99ebc3aeb35c0d0f3fa9aa005f21ef64264392996\" timestamp=\"0x03b9f376\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.556\" file=\"ntoskrnl.exe\" hash=\"b16ca5aec79898a1cca04047a570c54a188901f135f741fbfd67c62f7419ef91\" timestamp=\"0x5c35887c\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.590\" file=\"ntoskrnl.exe\" hash=\"8e49a88d6b498fdaffaf8c23773a38b09fb61bc3ce7280f2d1e811fa3fc4178a\" timestamp=\"0x5c5a4226\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.619\" file=\"ntoskrnl.exe\" hash=\"6d2a7022a8ae2a043cc1032f77957b7b397d4c56bc5b995791939f9ef235e8d9\" timestamp=\"0x5c67bc07\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.648\" file=\"ntoskrnl.exe\" hash=\"3abc8b85732181bd47769079afcd9fe8fd90d4836f8269d1b471da0a7e241636\" timestamp=\"0x5c7f6dd4\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.648\" file=\"lxcore.sys\" hash=\"987f3641ae0899d03321f1ddf4170fe2a57a3e3a7cd65d18ce743b0e37555e7f\" timestamp=\"0x1f64df57\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.677\" file=\"ntoskrnl.exe\" hash=\"7a689c4a4f60d1f246b4e874c431c175ebce0c6ffb74de84959a9805140e1197\" timestamp=\"0x5c8a107a\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.677\" file=\"lxcore.sys\" hash=\"58609e5687998fac05c572c1ae99420a075219039d97a7351c910dc3bf0da088\" timestamp=\"0x36b675be\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.706\" file=\"ntoskrnl.exe\" hash=\"061c0baebfadd757423da4937343a72cd2712074dfb252be2747e347c7fc3294\" timestamp=\"0x5ca2e89f\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.706\" file=\"lxcore.sys\" hash=\"bdf412cad56510353e8edaeb5289b003cd43aef8e2d3a2c8486f63638b8d50db\" timestamp=\"0xfe5e31dc\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.753\" file=\"ntoskrnl.exe\" hash=\"b0c727cf43fc7fe89814456b9aba1ce5f0117af95fb5e2637ce0f080c47fcd39\" timestamp=\"0x5cb95452\" size=\"0x008f9000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.799\" file=\"ntoskrnl.exe\" hash=\"9e456ec0b9a435eab52681d98d8d18ef463b5fa3b58c28b2826e63fad68f318e\" timestamp=\"0x5cde4a2f\" size=\"0x008f7000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.858\" file=\"ntoskrnl.exe\" hash=\"956396fdc5d50f645a87bccbadcecfd6a42e95771cd4826228c526ebd9cfa94d\" timestamp=\"0x5d01e7cd\" size=\"0x008f7000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.915\" file=\"ntoskrnl.exe\" hash=\"7909156cc3454b674e15fc9e32c0c02a6e4953f2e389446d80c52865b8884087\" timestamp=\"0x5d2400d1\" size=\"0x008f7000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.915\" file=\"lxcore.sys\" hash=\"148c3ef6c2300b786fc4f36eb7755c00578512ff0f9e9f733b0627c5bfe45c69\" timestamp=\"0xf9df3ef0\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.982\" file=\"ntoskrnl.exe\" hash=\"e0241af9195f028a57a33a29b5917bba10dca5409e2d27d15dd6e77dd228fa16\" timestamp=\"0x5d53b9d8\" size=\"0x008f7000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.982\" file=\"lxcore.sys\" hash=\"54807501f85ea14113652be119cdf0aa0172e13ee02a6b41a7f58681f927a140\" timestamp=\"0xe42ac1bf\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1006\" file=\"ntoskrnl.exe\" hash=\"6fc9bccb8e584fac79f96ad37bac6dacc02469cd8485f785c5fb53235be3ea12\" timestamp=\"0x5d6f42e1\" size=\"0x008f5000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1038\" file=\"ntoskrnl.exe\" hash=\"dea0c5b05583347a46ae90f9c93ace97de613d635349d40328dc91a2f908c185\" timestamp=\"0x5d7b192a\" size=\"0x008f4000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1038\" file=\"lxcore.sys\" hash=\"eb883ea914fc1241d060fd185d9f71c2ee268903178f7f98b6b54379822b82e2\" timestamp=\"0xc1f3166c\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1067\" file=\"ntoskrnl.exe\" hash=\"88e025bee2ed5b12a79443fb876cb39ff37f86ffc3e1c3298a04fbb41e6eb4d6\" timestamp=\"0x5d942834\" size=\"0x008f4000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1098\" file=\"ntoskrnl.exe\" hash=\"a8f9902dc51cf0d7fb75fccf5646b1355a7934644bbe5735dff122d61fca27e7\" timestamp=\"0x5d9425e6\" size=\"0x008f4000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1130\" file=\"ntoskrnl.exe\" hash=\"eca4630a620b2b0484b515881b40c6bc752eb3b0ee3b208d56b22913c43adfcf\" timestamp=\"0x5dc4c980\" size=\"0x008f2000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1130\" file=\"lxcore.sys\" hash=\"b19272d281065419696779abe7001e5349c52ab5f6d039815c710384acbdc7bf\" timestamp=\"0xb999e4cc\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1184\" file=\"ntoskrnl.exe\" hash=\"b453403095fa6c8db105b4439124e5c7fff9600d77d63e131db8bcfcd890d176\" timestamp=\"0x5ddf4fc5\" size=\"0x008f2000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1276\" file=\"ntoskrnl.exe\" hash=\"cc4fc91394c17cc43544eda584cf4fb8b9afeb468365c01ce442eee7377476d7\" timestamp=\"0x5e13fd82\" size=\"0x008f2000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1304\" file=\"ntoskrnl.exe\" hash=\"036613c9f1cc2717257ca49ade7e972928c33638ee12b97978061980662fc147\" timestamp=\"0x5e3a69e3\" size=\"0x008f2000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1345\" file=\"ntoskrnl.exe\" hash=\"aef4f79b9b14138e319cde2b838eb84c20cc84cc0678531db84d3b6d3ff58102\" timestamp=\"0x5e4f5e35\" size=\"0x008f2000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1345\" file=\"lxcore.sys\" hash=\"565baa7121b385ceb456501d8d6e6381d88d13db2c13a48a96040488d7da38de\" timestamp=\"0x47d40d41\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1399\" file=\"ntoskrnl.exe\" hash=\"4c2eabc879ed9fd8ca3d794e25d3bf274a1c04a6a66203a696ca16e75b530606\" timestamp=\"0x5e5f5213\" size=\"0x008f2000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1401\" file=\"ntoskrnl.exe\" hash=\"de1cc0cdeeaa99f8dbdf72b0298418ab00f9ab5d905cdd581136304ee9351bf7\" timestamp=\"0x5e7caec5\" size=\"0x008f2000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1456\" file=\"ntoskrnl.exe\" hash=\"da958a8edef76c41730595c8425de117467d8997cef9e4bbf41079a82f3ea5c9\" timestamp=\"0x5e8bfe90\" size=\"0x008f2000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1488\" file=\"lxcore.sys\" hash=\"7a588b6199ead2b2121b893ebc092ea3dc6f8de2977b9747cd5907f7905ae8b8\" timestamp=\"0x8a2320a4\" size=\"0x00102000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1553\" file=\"ntoskrnl.exe\" hash=\"4f410a394ce165cfc99d74ef45115e0d6f3b18e67d26e256304cd008ea8ce3d0\" timestamp=\"0x5ee496e1\" size=\"0x008f2000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1667\" file=\"ntoskrnl.exe\" hash=\"28c576a496aec917d3312b8afa5dbbdf5d0e58d1531e6005195df531536bad55\" timestamp=\"0x5f2a4e98\" size=\"0x008f2000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1726\" file=\"ntoskrnl.exe\" hash=\"a892a47e00c1e583756a5e1202cc600e0b577fc89f059495dba9e5e80b0e1f70\" timestamp=\"0x5f4f2420\" size=\"0x008f2000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1792\" file=\"ntoskrnl.exe\" hash=\"cf096a332ddcd61b158b1a69990284a68efd06a2defe748ea4ce91437bc256fc\" timestamp=\"0x5f754914\" size=\"0x008f0000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1845\" file=\"ntoskrnl.exe\" hash=\"9c13135bf41220385b03f64260ca294e6850395a0932e952011efd777ba30e4c\" timestamp=\"0x5f9799a2\" size=\"0x008f0000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1902\" file=\"ntoskrnl.exe\" hash=\"c2ef50fef6aa0221b028b78c81d02dde7619bec30c172754fa0ec0b9c5645c26\" timestamp=\"0x5fc83346\" size=\"0x008f0000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.1967\" file=\"ntoskrnl.exe\" hash=\"b538560f05653fa8179ffb9bf7c4faa1f9cfeb5e8fad334e48cf8a31f9963947\" timestamp=\"0x5ff6c08d\" size=\"0x008f0000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.2026\" file=\"ntoskrnl.exe\" hash=\"77380477634bdce8f2765a1bf95e28364ebb232790ba9569e58b76707d72d741\" timestamp=\"0x60124606\" size=\"0x008f0000\" added=\"2024-10-20T15:35:22Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.2087\" file=\"ntoskrnl.exe\" hash=\"30696a1fa9264b7c6b2fbd28437de4c5b80a42e656bdcc9f3a1cafb117abaa52\" timestamp=\"0x603d7029\" size=\"0x008f0000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.2088\" file=\"ntoskrnl.exe\" hash=\"aa6c3b125288d5a99a29774c0548f7c57f9bf07e07998a3967f11f5b34d5df5e\" timestamp=\"0x6049c49e\" size=\"0x008f0000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.2090\" file=\"ntoskrnl.exe\" hash=\"43b55561bf14340b38c8806e130c9ab5de390b46c578b025da0ad5b2768d4358\" timestamp=\"0x60509fdb\" size=\"0x008f0000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17134.2145\" file=\"ntoskrnl.exe\" hash=\"027db1e655492b03ffc809f426a692098f7f7e8894b13fcb750456cbd81a47f7\" timestamp=\"0x606eb580\" size=\"0x008f0000\" added=\"2024-09-12T01:41:05Z\">15</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1\" file=\"ntoskrnl.exe\" hash=\"d350145e22a19ee2325a083b06bc3d6c30141e80f50d58059afeece3835685ab\" timestamp=\"0xf89b38fb\" size=\"0x009a0000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1\" file=\"lxcore.sys\" hash=\"e82fae94353ac63097634132957df894e2763dd3fcc03b556a329f257c6c4ce6\" timestamp=\"0xee00e593\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.55\" file=\"ntoskrnl.exe\" hash=\"65c23af55c9f35fe259b349a59983e9b7ed4c16ce3ce83a7cf37d7d45c92cba7\" timestamp=\"0x47b36dc8\" size=\"0x009a0000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.55\" file=\"lxcore.sys\" hash=\"6cbb32a70d6bd5b1badeae8e000b50fc3df3918613a0fdbc88e295d4b225b547\" timestamp=\"0x65e0a08a\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.107\" file=\"ntoskrnl.exe\" hash=\"236247c6ed9d850a399655f3b37a351f378e3206afb5cc43e54051a1e01021f4\" timestamp=\"0x64c7597b\" size=\"0x009a0000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.134\" file=\"ntoskrnl.exe\" hash=\"5131b2a0dff2ea1865500ad30d1e258fef3c8a3d02dbe403de9a71d28717a0a9\" timestamp=\"0x30df38af\" size=\"0x009a0000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.168\" file=\"ntoskrnl.exe\" hash=\"549a63524fe6931b157e3683ae608301ff3855fa42e7001c1b2fc4c6b950bd42\" timestamp=\"0x5ad48822\" size=\"0x00a1f000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.194\" file=\"ntoskrnl.exe\" hash=\"0fb4f4d30038046077c5bcbe4a866650fb9eb3727054a898170df97b3af89864\" timestamp=\"0xedf2bf89\" size=\"0x00a1f000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.194\" file=\"lxcore.sys\" hash=\"6f939f29509fef8ac09a166a277d8dd45c6aac47c26c7be7b271c05b7931487b\" timestamp=\"0xe3de69fa\" size=\"0x00110000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.195\" file=\"ntoskrnl.exe\" hash=\"c225692c96a33e22fe7d5741ac7f588c2ee43ebcc8b4e2fc007d1ebfab21b320\" timestamp=\"0x0de6fc98\" size=\"0x00a1f000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.253\" file=\"ntoskrnl.exe\" hash=\"6dd5b0ada6802e964c2ebc49a8c87b703996deee9ed055afae814a4607cdb431\" timestamp=\"0x52d3f79b\" size=\"0x00a1f000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.253\" file=\"lxcore.sys\" hash=\"9bbf0e94c5617ca39ddd234c1c5a1f84f9cf35011372baee5a08f082d59c21c6\" timestamp=\"0xd45ba854\" size=\"0x00110000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.292\" file=\"ntoskrnl.exe\" hash=\"361be2daad8720cb63a8d7604cb14b92b73ac52672eca2bd72bb35d126a85fc2\" timestamp=\"0x2215e1fe\" size=\"0x00a1a000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.292\" file=\"lxcore.sys\" hash=\"61d41ccaeb77522753ed40464f0e973d28d9a71bafeea6ac764ed1bc3612506a\" timestamp=\"0xc14105ac\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.316\" file=\"ntoskrnl.exe\" hash=\"2d321477eb065213edadecc981abf256282c694e151ca2120fe48b554923f5f3\" timestamp=\"0xfe057830\" size=\"0x00a1a000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.348\" file=\"ntoskrnl.exe\" hash=\"975d2f65f49b513f73c1d9e75d95fabc404eb7089671a5df5b1e605c1e181779\" timestamp=\"0x890f95d2\" size=\"0x00a1a000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.348\" file=\"lxcore.sys\" hash=\"db861299dcacc6be40d07dbf63cd245dc07121be359b9e281b1d944bf24d9665\" timestamp=\"0x7bd2e6bc\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.379\" file=\"ntoskrnl.exe\" hash=\"8edbafbdedcb97932851541a7a4b54343a759bb80e4352c9748cc7afe91ccace\" timestamp=\"0x22134dd5\" size=\"0x00a1a000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.379\" file=\"lxcore.sys\" hash=\"490100e0125424b5847a293ed71c861603c4a0d6d3ff0bb2adc6abbdef43f8b9\" timestamp=\"0x15a9b6fa\" size=\"0x00110000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.404\" file=\"ntoskrnl.exe\" hash=\"4dc6ddfea8f641378d8783a3bee4fb6f2cc541ea6f78b4d2007ac7f1af2968e1\" timestamp=\"0x91d248ca\" size=\"0x00a19000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.404\" file=\"lxcore.sys\" hash=\"330c5b0b17ec0d5cf21bf012dab6bf8e6290fc5d962955a49ef00b8e5ecd38df\" timestamp=\"0xafcbba3e\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.437\" file=\"ntoskrnl.exe\" hash=\"9532a143ce15f8e04e09aa1db7ad51bf5ad15a71a88f1a09793171833a65d205\" timestamp=\"0xa6169bb0\" size=\"0x00a19000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.439\" file=\"ntoskrnl.exe\" hash=\"1ca61f6194e9bc288c5fb7084bc763e548ec370056809d3d53258085587ee627\" timestamp=\"0x20cd2654\" size=\"0x00a19000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.475\" file=\"ntoskrnl.exe\" hash=\"d93f1a33da16929ff97548922d20df5762fe8f60c4debfd35956f0187aa3f059\" timestamp=\"0x9b8251b4\" size=\"0x00a19000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.475\" file=\"lxcore.sys\" hash=\"5aca38d9a251e218642fe14699a26f2498b77bbbe68411e0d961e91e5e722478\" timestamp=\"0xbfffe339\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.503\" file=\"ntoskrnl.exe\" hash=\"efa8b991da1d71990645baf9f867679b3710d3d480a1e5a5a937f602e30e851c\" timestamp=\"0x04fce89a\" size=\"0x00a18000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.504\" file=\"ntoskrnl.exe\" hash=\"f3439d6a3f75ade5ca91864984bf60c023f01a6f8d30bf0e76aaeed3a2deb44c\" timestamp=\"0xac0abe0f\" size=\"0x00a18000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.529\" file=\"ntoskrnl.exe\" hash=\"20a75c49da49ae1e0404968c07489f0765b972354835876651643a8aa89d5bc3\" timestamp=\"0x83a45f9f\" size=\"0x00a18000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.592\" file=\"lxcore.sys\" hash=\"df83824e57d566b4b98252889e9f68c2d53c9d953e449ba067b167f194fb4571\" timestamp=\"0xab449cf1\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.593\" file=\"ntoskrnl.exe\" hash=\"797fe0ec7f082ef11744e5c2007d0cb8dc4375feb7c32d1b580ab7ec124d817d\" timestamp=\"0x7e5595af\" size=\"0x00a18000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.615\" file=\"ntoskrnl.exe\" hash=\"66781ddccdc84fc4f8e5c69e421385fd4c9b6419b20b532bae658e58771868ff\" timestamp=\"0x73dc12ab\" size=\"0x00a18000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.652\" file=\"ntoskrnl.exe\" hash=\"671bcc5fea0854ea6a391ad4a70f9338e29ea8ed2985ff9417687bbed7756709\" timestamp=\"0xc6114942\" size=\"0x00a18000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.652\" file=\"lxcore.sys\" hash=\"c7073a9ab5c120a86484383a49c5df9aa821910187a5aea4828dcf76d4e769c0\" timestamp=\"0x762c25f1\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.678\" file=\"ntoskrnl.exe\" hash=\"f5c92aa63c8e8be61011ab15fd1fca60166a634f95506590145de84f1494e8e2\" timestamp=\"0x1221830a\" size=\"0x00a18000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.678\" file=\"lxcore.sys\" hash=\"e0b3eb1fc33261a2ac03289e090ba919df7d9b91975dbde032f8ffe099c99111\" timestamp=\"0xa7fe5379\" size=\"0x00110000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.719\" file=\"ntoskrnl.exe\" hash=\"9ca74e88177103ca1b4a1b3c1063f1409c661cf96f487474098e090687e5537c\" timestamp=\"0xbde69b1c\" size=\"0x00a17000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.719\" file=\"lxcore.sys\" hash=\"00b327441e8db08cea61150dcaf4f7eaf773197b422441476bde3016eda1a0e6\" timestamp=\"0xbb67d777\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.737\" file=\"ntoskrnl.exe\" hash=\"0f8a19e0a7401ae8c28b82360d450ab167b9d58bcb5952bbad3b4b16f5a5eda8\" timestamp=\"0xc2a6333d\" size=\"0x00a18000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.737\" file=\"lxcore.sys\" hash=\"6f80da847cd5682dcb6929a392081140488b069b5f8065b7105ef32ce61f5a25\" timestamp=\"0xd8546847\" size=\"0x00110000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.771\" file=\"ntoskrnl.exe\" hash=\"3eb6abf44d61e561c997c4ca3d82463147e209353c09fc40cd3a52ac6de219d7\" timestamp=\"0xb0036ef4\" size=\"0x00a19000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.771\" file=\"lxcore.sys\" hash=\"3da51642a7e2c96caeb3d2d77c0823016bf834d4197fc3c06f92eb5a4a1766f4\" timestamp=\"0x0f5b5d58\" size=\"0x00110000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.802\" file=\"ntoskrnl.exe\" hash=\"bafb9e539e10b250c3859d164a77b29722801644b8d852bbd259acd1ab678703\" timestamp=\"0x0c867161\" size=\"0x00a17000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.831\" file=\"ntoskrnl.exe\" hash=\"139512da1e3b18bc3c54840cdf8348a2023ad55c2f40f8f7e4a74053567cfa7e\" timestamp=\"0x35f5f3bd\" size=\"0x00a16000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.831\" file=\"lxcore.sys\" hash=\"e73d0a8b7c9169729e600f1c1038eb6d5990b01a30eb9407d46f4e57589e6a1a\" timestamp=\"0x4c6d95b3\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.864\" file=\"ntoskrnl.exe\" hash=\"584e02c0cd043b62857d90c7c8499a5d75c6c1fff36a7688f2d5075a472b5a04\" timestamp=\"0x8e51dc13\" size=\"0x00a16000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.864\" file=\"lxcore.sys\" hash=\"a973c1d21a7ce3afca39c105e5151ef2da7b5e640b7d926c6b520807e955d20d\" timestamp=\"0x3b45e597\" size=\"0x00110000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.914\" file=\"ntoskrnl.exe\" hash=\"bd843dc4190576b3db7c2add31889fc239b80d961fd6bd34687fa5707e342a1a\" timestamp=\"0xdbdf735c\" size=\"0x00a16000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.973\" file=\"ntoskrnl.exe\" hash=\"a3a9d3d2d085670bba3bbf26fbd7f0d0b85857d059f3380b8385b8194abc5974\" timestamp=\"0xdea1cdaa\" size=\"0x00a16000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1007\" file=\"ntoskrnl.exe\" hash=\"a88993ba6dfe671beb98f07beb9fa70b9d6aaff017b8d6db4aecbd4eafc16bfc\" timestamp=\"0x005929d8\" size=\"0x00a16000\" added=\"2024-09-12T01:41:05Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1007\" file=\"lxcore.sys\" hash=\"8cc2507d3a3228a699c1d2aa7c6281cdc2f072c863201060ba6f7f5cd603b135\" timestamp=\"0x39a80292\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1039\" file=\"ntoskrnl.exe\" hash=\"80e7c8f0118746a9fb063f60fe682fe000919d2d1294f9e81b251373f4ad6d21\" timestamp=\"0x6866f5a6\" size=\"0x00a16000\" added=\"2024-10-20T15:35:22Z\">16</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1075\" file=\"ntoskrnl.exe\" hash=\"19b0a23414ea1660f7e4dc7224a9429eeefd1ff4cba106d389a93b460993f0cc\" timestamp=\"0x59c19a44\" size=\"0x00a17000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1075\" file=\"lxcore.sys\" hash=\"0cd55186c8ac808bc08a641dbd0d0b641ccc44c74283ab811b89fbfa30a7ed5d\" timestamp=\"0x9f694db6\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1098\" file=\"ntoskrnl.exe\" hash=\"9869471864380ccb1010b65f259c5aa83bb88b45b6699654932c78004a1985d3\" timestamp=\"0x4d1f22a6\" size=\"0x00a17000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1131\" file=\"ntoskrnl.exe\" hash=\"49d7b18e59f8e912c3cdcce5098625b4e8e774c453a6a0cf513185dd8b9634a1\" timestamp=\"0x0a7aed22\" size=\"0x00a17000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1131\" file=\"lxcore.sys\" hash=\"52cb545e01199a6a0d8561b4b5b1b9d81c5cabbdcea397bf29d9f2fbd6ed1972\" timestamp=\"0xa0b479a3\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1132\" file=\"ntoskrnl.exe\" hash=\"1dc6c3ec949c63e7f6428ce460980829c0c14729c6924949e0903b325d7a3d27\" timestamp=\"0x6d1d027d\" size=\"0x00a17000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1158\" file=\"ntoskrnl.exe\" hash=\"e4a595a801e71b0941e5add6f720c57d90a590cf5947a125d4b706a02f0ed65f\" timestamp=\"0x358b5a1c\" size=\"0x00a17000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1192\" file=\"ntoskrnl.exe\" hash=\"c63ae079b4ec92d2a044032c5f2723fcef0ecc6f2878cdbfdbe2b6d5fb3653bf\" timestamp=\"0xd13a86ca\" size=\"0x00a17000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1192\" file=\"lxcore.sys\" hash=\"e58634cf3e532d434ddd9068fb95b9847e3ffdccee59c53a9489ee1c4203b710\" timestamp=\"0x9cd38ab2\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1217\" file=\"ntoskrnl.exe\" hash=\"c5d16614101bf879c8d2b3fbfa1532b1d1c23d10048d58818c3f2b34f30c25ea\" timestamp=\"0x3ff63eb0\" size=\"0x00a17000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1217\" file=\"lxcore.sys\" hash=\"1d333b9d10bf61999839c6300dc300b1a9acfd58b9eab97de51b61fce1edbc8f\" timestamp=\"0x1f970377\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1282\" file=\"ntoskrnl.exe\" hash=\"959c8c5322d563c0fb7187fc5739be496a4ccb409e1f929e80a7474f721e963b\" timestamp=\"0x140c0be6\" size=\"0x00a16000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1294\" file=\"ntoskrnl.exe\" hash=\"c83d6bd3fea38cac46d14a18b418bd8413cb0b0de441817e3ce3e35fba967639\" timestamp=\"0xa0c03b95\" size=\"0x00a16000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1339\" file=\"ntoskrnl.exe\" hash=\"7cc0837b72ee21efd9d646d7741967ecc9429278ffb02c9fcc1a9ef6d2db722f\" timestamp=\"0x4711cb71\" size=\"0x00a16000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1369\" file=\"ntoskrnl.exe\" hash=\"6b32d35db022ceb7300316b8a398eafeaed069cf7422d0aa3628db411002c9a6\" timestamp=\"0xacbc56a9\" size=\"0x00a16000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1397\" file=\"ntoskrnl.exe\" hash=\"e9ed9f9738066baeae5c04e98d9175d715a3a7205ea83cb35ad481b126fe2217\" timestamp=\"0x83b26e04\" size=\"0x00a16000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1432\" file=\"ntoskrnl.exe\" hash=\"5ca5653704139d7512d31deeb05a6408a67df42af337a5bb4b1eef9a97868e77\" timestamp=\"0x35003293\" size=\"0x00a15000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1432\" file=\"lxcore.sys\" hash=\"cd7024e5c1c6cc69fd907308928ca89971e6706796ce6e47c38bf643554442ee\" timestamp=\"0x7b4a4532\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1457\" file=\"ntoskrnl.exe\" hash=\"04c19e0beab4ed32b65f6ac65a305a65e3844a392bdef9cadd240640b48d7c39\" timestamp=\"0x0a3a2a4b\" size=\"0x00a15000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1490\" file=\"ntoskrnl.exe\" hash=\"775723e553ee4fac3c96b8c645a9d310038243cab1c9a3680f16179dbea2b107\" timestamp=\"0x4a63e7ed\" size=\"0x00a15000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1518\" file=\"ntoskrnl.exe\" hash=\"fe15aec32911e2f3a72406cab5825ac8555286b1c73ef2d8a42f8f4266b26e13\" timestamp=\"0xbae10b23\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1554\" file=\"ntoskrnl.exe\" hash=\"69c90f5b5a0f4d1ef145bd8b9779c568f9150b8ccb6df90a77632d937463ae81\" timestamp=\"0x5ffea684\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1554\" file=\"lxcore.sys\" hash=\"41c48877a090a46e21a7ad23650dafe778cc93ea86462b9b72e4cd63148aeb75\" timestamp=\"0xcaecf0a1\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1577\" file=\"ntoskrnl.exe\" hash=\"8b74a70207af9a7b22f23a40c6fa6ee24a8d5f3a069e3dafcc2f7215a5e10f04\" timestamp=\"0x3722d67d\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1579\" file=\"ntoskrnl.exe\" hash=\"5525adad6acece9d2bffefca5526f96b14bb2405390f28baac107547d73841bb\" timestamp=\"0x9a4120f8\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1613\" file=\"ntoskrnl.exe\" hash=\"c58b2a1a39bee2ee584de419daa8fe4ea87d4ddd8343e1554b6aef91093ad23d\" timestamp=\"0x66c8354d\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1637\" file=\"ntoskrnl.exe\" hash=\"8e66d8382d57f7d699477dc82d50059e83cb48c9d1d187d219ec0194bd919fac\" timestamp=\"0x9e8ffb32\" size=\"0x00a14000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1697\" file=\"ntoskrnl.exe\" hash=\"642d310f62d9d2ea6b7363706b92f7f04b5b081fef01217ca38a86362c19012b\" timestamp=\"0x2ab80c7a\" size=\"0x00a14000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1728\" file=\"ntoskrnl.exe\" hash=\"c22935c31e3cb650ea384637e6b047903919a345c4848c6eaead2bdeaabcc8e8\" timestamp=\"0xae47e0fe\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1757\" file=\"ntoskrnl.exe\" hash=\"d9c6a831543b9060a050406730d23799ae489cffd5d86ecca13086b4baafee54\" timestamp=\"0x5855532a\" size=\"0x00a14000\" added=\"2024-10-20T15:35:22Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1790\" file=\"ntoskrnl.exe\" hash=\"88fcfd76efb5ee25305d518f751518343b0ab58e8369653dc600a9ee750eaa9a\" timestamp=\"0xafde96ba\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1817\" file=\"ntoskrnl.exe\" hash=\"030ce85593f69e6b8dd8e6738ccf6bbc4cfa44effae8e75472a39146f3c1762c\" timestamp=\"0x82cc14ae\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1821\" file=\"ntoskrnl.exe\" hash=\"43a9bf5bc81b68d27c2b222d896441f71042d9b29256386fa729a0e2dc8fb3d4\" timestamp=\"0xb7726624\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1823\" file=\"ntoskrnl.exe\" hash=\"5901d64627db02716bf698a6e6d307ac6c5b6c0d97bec5d2c87f3bc88c1c44ec\" timestamp=\"0xf85a44af\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1852\" file=\"ntoskrnl.exe\" hash=\"3091ed74463b0abc7278852beeaf179a41b5f1dfb5bec49ae0caa4d3336dd8cd\" timestamp=\"0xcc27ccae\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1879\" file=\"ntoskrnl.exe\" hash=\"8f61c622dd1135b1dfccd43066e91897f8800de65499fdcd36d7409b8035e097\" timestamp=\"0x96b21cc0\" size=\"0x00a14000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1911\" file=\"ntoskrnl.exe\" hash=\"75df6ab31e5e9ef22865e2b952ee8b34855804220d73742c1ce038a230143a7b\" timestamp=\"0xef189e75\" size=\"0x00a15000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1935\" file=\"ntoskrnl.exe\" hash=\"aee9fa6ab5c5876c15031112941e176e39ec0e6ee5ce73322390671ede5b0eed\" timestamp=\"0x31d19a4c\" size=\"0x00a15000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1971\" file=\"ntoskrnl.exe\" hash=\"7248f8c085e246fd5b43a01ce7bc884c5a75a59f1fe03ae9ae9aa04effb796bd\" timestamp=\"0x347a7d00\" size=\"0x00a12000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.1999\" file=\"ntoskrnl.exe\" hash=\"5a9fd4bb466134ce38ec55a445f5ff1bf629d3f2195a818c424dcc7a7c319994\" timestamp=\"0xd86555cf\" size=\"0x00a12000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2028\" file=\"ntoskrnl.exe\" hash=\"a7cb69e1d6fda20deb675cd26a3fe5e2d62c84555ca12eeb335068cc9e8c726b\" timestamp=\"0x2c1df990\" size=\"0x00a12000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2029\" file=\"ntoskrnl.exe\" hash=\"7c7c1c864e5bc7c4eca76e9286014f9b4b4942e0d2d8e4893a6e82dbea3760b9\" timestamp=\"0x2480efee\" size=\"0x00a12000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2061\" file=\"ntoskrnl.exe\" hash=\"87e426b03a144e16767c5a79c54dc30ed6b1e2b42c7f2ec304d10ca118712c43\" timestamp=\"0xce91bf37\" size=\"0x00a12000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2090\" file=\"ntoskrnl.exe\" hash=\"24ae423df4de660c393bfe47031f4b5933fb4565a6fd356c64d2bea31cb4eaa2\" timestamp=\"0x538344a1\" size=\"0x00a12000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2090\" file=\"lxcore.sys\" hash=\"2a9f63c0d716657229f4c2ca5da9afe1f8eb827c7523975aec945227f933725b\" timestamp=\"0x01af469b\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2091\" file=\"ntoskrnl.exe\" hash=\"e3ecfb6086f58186d24434342be6233e89a6b46c8a569fcfa88402057cc675ca\" timestamp=\"0x6beb17fa\" size=\"0x00a12000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2114\" file=\"ntoskrnl.exe\" hash=\"371a8db74753891a02571230d847028f4a87b340dc4089ebf197351bf835ef43\" timestamp=\"0x0bf6eca6\" size=\"0x00a12000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2145\" file=\"ntoskrnl.exe\" hash=\"207dd2717f5b0ab4d2437374b4227f4ee0a32eba8147598adfa88a8626a893b4\" timestamp=\"0xa7d6d134\" size=\"0x00a11000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2183\" file=\"ntoskrnl.exe\" hash=\"353a35be62f6a4f5dcf8bbdc132497cfb35645be85302b9e5f9da95d5fd1ad3c\" timestamp=\"0x3ebe97bc\" size=\"0x00a11000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2183\" file=\"lxcore.sys\" hash=\"6fd779d608101d4b99e9f00caf05abcd03d7bf38da14e1299bc0bbb974aedfc2\" timestamp=\"0x5b9d31d9\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2213\" file=\"ntoskrnl.exe\" hash=\"b206038e7cfa0250d38895a4698b577a4658477dd83c4e9a376fd0a219b8f506\" timestamp=\"0x7b3edabf\" size=\"0x00a11000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2237\" file=\"ntoskrnl.exe\" hash=\"39025665e397a633077344ed621c7deff47fcd5791b170f98c851f9ecc80b067\" timestamp=\"0xd2e63212\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2268\" file=\"ntoskrnl.exe\" hash=\"5bf6f8cca377890929ca71c4b3feb5953d991982bb75b6efa9a770020e7fb2eb\" timestamp=\"0xb86d4650\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2268\" file=\"lxcore.sys\" hash=\"7b429ee7e49a2f822afd1d71c2ed40c69fe9e4273ca1929f31890a5733419b7e\" timestamp=\"0xa98e3f68\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2300\" file=\"ntoskrnl.exe\" hash=\"09f33fc24d24117cfeec0548316eb057b165ad79c5934a744915f790b1bba0f0\" timestamp=\"0x5e8518a9\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2305\" file=\"ntoskrnl.exe\" hash=\"d5579c4630c7d62c1891c826b9eff391e37dfbf240ef1f01e1c31e08260384b7\" timestamp=\"0x1694f01b\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2330\" file=\"ntoskrnl.exe\" hash=\"57843f811481fb874e9dbfc0fe61cb57fd04efae000e7a07954bdbbf2aaa2171\" timestamp=\"0x3d05bc32\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2366\" file=\"ntoskrnl.exe\" hash=\"a1c3b499e0b144f2c6869f5d5b7e8113e272723138a5a26563118bd1a7355fbd\" timestamp=\"0x68d9741d\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2369\" file=\"ntoskrnl.exe\" hash=\"353d7cc7f618e0ef90d0efbbc3de9f34ae43109e211dcd31364ae8f72f6fc0ac\" timestamp=\"0x3c76399e\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2452\" file=\"ntoskrnl.exe\" hash=\"4adb874939252d5658101f92f49580d9ae04ab30789d2ed736f9dcdbdd1cf062\" timestamp=\"0x6f1ec916\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2458\" file=\"ntoskrnl.exe\" hash=\"1c03cc15733755f0e215d6f55cc109104ab3e7c0de18455a2bd42449d1a508ba\" timestamp=\"0x5019a83e\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2510\" file=\"ntoskrnl.exe\" hash=\"3fab33757323db69697c369963f640926ca7eaf5e2346f0c27826e9699cf7fe2\" timestamp=\"0xed7a5be4\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2565\" file=\"ntoskrnl.exe\" hash=\"73a88a453e3618392ea92029ea3261547e18f51bacfb2a73c8ccf7c59406d718\" timestamp=\"0x42a6fa05\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2628\" file=\"ntoskrnl.exe\" hash=\"023e0a7ce1c89b52aea7f190ea6610f1af83e8350a25a5ecf5600bb40bfc5b53\" timestamp=\"0x8fecfc1c\" size=\"0x00a10000\" added=\"2024-09-12T01:41:05Z\">19</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2686\" file=\"ntoskrnl.exe\" hash=\"e4f9d8e393f2e7dfd356513280c6ee4b1a54467c30fe77f7019cb623c007036f\" timestamp=\"0x5885b13c\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2746\" file=\"ntoskrnl.exe\" hash=\"3e101569205e6cf62f031e12d8712f45272cb7b95111baad8e2dff139db8cf2b\" timestamp=\"0xc328e14c\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2803\" file=\"ntoskrnl.exe\" hash=\"1e105d57159ffc051ebb1064ff7f5e0b27cc6de28270042b6aee02a7fcff5eb3\" timestamp=\"0x2aa42c14\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2867\" file=\"ntoskrnl.exe\" hash=\"2256763f9ee30a4e45572e29389cf7931c501deded3d2ed2042e0064a9b04a0b\" timestamp=\"0x2223f5fd\" size=\"0x00a0e000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2928\" file=\"ntoskrnl.exe\" hash=\"baffdc007cf9e1aad9893e315f4676ddd22274daebf96af22dd60c4247ef8ff5\" timestamp=\"0x77a42798\" size=\"0x00a0e000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2931\" file=\"ntoskrnl.exe\" hash=\"5d6837df1e0ad0d179de9cd5c9de9e512d88e7a1e066443c03519f863408bf2e\" timestamp=\"0xb6ebda52\" size=\"0x00a0e000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2989\" file=\"ntoskrnl.exe\" hash=\"5cd1f5ae8d63547c66809208b93d6a99739b81b0febb591f129f4548a4421812\" timestamp=\"0x6aca6a2d\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.2989\" file=\"lxcore.sys\" hash=\"abd5c5da0a54de2561aa3eb8afbda9d88dacc4c956a0f9543ea920c4e6d9f928\" timestamp=\"0xc03d716b\" size=\"0x00110000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3046\" file=\"ntoskrnl.exe\" hash=\"12caf1445c48648ccff61498e555c313906369a521dc63226194fd86ff14092a\" timestamp=\"0xb783364e\" size=\"0x00a0f000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3113\" file=\"ntoskrnl.exe\" hash=\"f1b2df0d4e2dbc057c22f578b9fb81bbf6115509d236ba6a789d0248f26e931c\" timestamp=\"0x8309b392\" size=\"0x00a0d000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3165\" file=\"ntoskrnl.exe\" hash=\"368e558b4de99ee76ccf67638127e16e8c30cbdfaff4d88dac62c54de6805cd3\" timestamp=\"0x30484105\" size=\"0x00a0e000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3232\" file=\"ntoskrnl.exe\" hash=\"c134ca19e1566b588a34e74131d8c56be93c3a1c88a17d7726140d180dbfcab4\" timestamp=\"0x08b2f266\" size=\"0x00a0e000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3287\" file=\"ntoskrnl.exe\" hash=\"c6f268569fc11ea9f72221d24ee298b87a7d695d2ace628e60a2d3cbc0e0335a\" timestamp=\"0x3b1206af\" size=\"0x00a0d000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3346\" file=\"ntoskrnl.exe\" hash=\"5f78c8355fb8e2c5a514b31be2c28a6b63ad34cca9b3dbc8f17bd352616d9c14\" timestamp=\"0xff998c54\" size=\"0x00a0d000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3406\" file=\"ntoskrnl.exe\" hash=\"dbe4c67d7d920967a95f2fc0ddd9a0245995a3ddb6bb679d508c6cd37e271ecb\" timestamp=\"0xa7d89233\" size=\"0x00a0d000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3469\" file=\"ntoskrnl.exe\" hash=\"13a498d1e6534ed41670163139e0d45f0da11cf8c61882e01bddc31825aba5da\" timestamp=\"0xd2ddd021\" size=\"0x00a0d000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3532\" file=\"ntoskrnl.exe\" hash=\"d918a0204cf6d689eeaded3a35d823e508e70685eeeac7ff01485d4592eaa67a\" timestamp=\"0x36ac828b\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3534\" file=\"ntoskrnl.exe\" hash=\"c8ccafbb08aa6ab857de90f9d73f980f4f384f1d0b08cd8e7c4e66fa257e878a\" timestamp=\"0x4c1077c9\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3650\" file=\"ntoskrnl.exe\" hash=\"58633143a0b5a95c6fa02db764616e7aba28ab40dbc0542006d61718268708a6\" timestamp=\"0x4b0a3052\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3653\" file=\"ntoskrnl.exe\" hash=\"5f2b5da8d826621a73c0004cacc975a8b1941c4c435d3c1a0b1a7348b981faff\" timestamp=\"0x1f524a5c\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3770\" file=\"ntoskrnl.exe\" hash=\"5e28275e155060da462171eea2d00bf60ea73d204518d75bc1f4d5a2a763d3aa\" timestamp=\"0x8e378374\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3772\" file=\"ntoskrnl.exe\" hash=\"097be18b72ed1d2fb0ce89a311ebc0c2b33bfe2307ff35f8769445a356258385\" timestamp=\"0x12321270\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.3887\" file=\"ntoskrnl.exe\" hash=\"cb70f81b64c2799fb10ae1918f8b88682b9f7587f27ee0fd3dc9779598641af2\" timestamp=\"0x2addc5d2\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.4010\" file=\"ntoskrnl.exe\" hash=\"03dbce17f1124c284985cefe79161d77647b4cfdcdef00d76eb17d403272f546\" timestamp=\"0xc625f924\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.4131\" file=\"ntoskrnl.exe\" hash=\"4910ec8fe2a7a5cef571fb8cf3671a5a376cb289c2412d5c7c83d75c2e690f4b\" timestamp=\"0xad974ff7\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.4252\" file=\"ntoskrnl.exe\" hash=\"57d0796d5bbe57240d835b4b1c7139a303111adb9931450b4ab64fcbc20fc739\" timestamp=\"0x43d052f2\" size=\"0x00a0a000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.4377\" file=\"ntoskrnl.exe\" hash=\"aed72fcf5f4a84efbd25bf790515e58eb0d531c8d09f496229f0151275996276\" timestamp=\"0x0ab6ecfc\" size=\"0x00a0b000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.4737\" file=\"ntoskrnl.exe\" hash=\"547ea2374b819211d22f3c1547cc80d0ace17ffdc583a7c6ac7fc3ef6a8c757f\" timestamp=\"0x74c6ca0d\" size=\"0x00a0b000\" added=\"2024-10-20T15:35:22Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.4851\" file=\"ntoskrnl.exe\" hash=\"a4156d099bb3b715b2a9e8b2029e1de04524c06aed5153d590de3564cd7c01c8\" timestamp=\"0x0538903f\" size=\"0x00a0c000\" added=\"2024-10-20T15:35:22Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.4964\" file=\"ntoskrnl.exe\" hash=\"6f77a53dfac54f3c7115db244321b06eb8fdb6e50b8696225d08fe1157e1a357\" timestamp=\"0x847cee8e\" size=\"0x00a0a000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.4974\" file=\"ntoskrnl.exe\" hash=\"137ab33b92615cd57a5826580a58a12a4c1b78c24f2cf21a0986b79cbabd43cb\" timestamp=\"0xdd1cb787\" size=\"0x00a0a000\" added=\"2024-10-20T15:35:22Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.5122\" file=\"ntoskrnl.exe\" hash=\"a6e37ff7005f63ae8e6078cacd8b160e4bc9dbfddc11e08286f88a63f8e5aa16\" timestamp=\"0x3fab6938\" size=\"0x00a0a000\" added=\"2024-10-20T15:35:22Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.5202\" file=\"ntoskrnl.exe\" hash=\"9f59067dfc85fcd3f7abe3633f5f931e0c1cfc2e8e64b668510db870dd9aa014\" timestamp=\"0xb056f5d0\" size=\"0x00a0a000\" added=\"2024-10-20T15:35:22Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.5328\" file=\"ntoskrnl.exe\" hash=\"322b2a59f10d9f43638c9057010491eeef4f046bbab1a3989a1819027245cc11\" timestamp=\"0x7ef744a6\" size=\"0x00a0a000\" added=\"2024-10-20T15:35:22Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.5458\" file=\"ntoskrnl.exe\" hash=\"3abfbfbcaac258a678aed499aea98689930a2da0172bbf131767eb2ff396bb77\" timestamp=\"0x07fc24b1\" size=\"0x00a09000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.5576\" file=\"ntoskrnl.exe\" hash=\"30d3af5671f3f39c467e2169da51a7def41a6c40c212338cdd01367913c92826\" timestamp=\"0x3cdca229\" size=\"0x00a0a000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.5696\" file=\"ntoskrnl.exe\" hash=\"0b7308136f9d6f54d042af824ef18d338a554967ad807bbbebdf94211ac2c25f\" timestamp=\"0xc5566b4a\" size=\"0x00a0a000\" added=\"2024-10-20T15:35:22Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.5820\" file=\"ntoskrnl.exe\" hash=\"8821c0c54a956b4c8bdb9f8be624ca7a45fee1d94d63ddb50c6e04d6740383ab\" timestamp=\"0xadceca0a\" size=\"0x00a0a000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.5830\" file=\"ntoskrnl.exe\" hash=\"9647656d0ec5dfebedf2c3d3910d76a55b2ac58b7c82ba619d4095955c6c4f0a\" timestamp=\"0xec0adec2\" size=\"0x00a0a000\" added=\"2024-10-20T15:35:22Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.17763.5933\" file=\"ntoskrnl.exe\" hash=\"c345d2a588ed31ad4b1fcb8efe90efc76aa34d0785d88eeca9f46230d5d67583\" timestamp=\"0xebc38286\" size=\"0x00a0a000\" added=\"2024-09-12T01:41:05Z\">23</data>\n    <data arch=\"arm64\" version=\"10.0.18362.113\" file=\"lxcore.sys\" hash=\"a7d84cd32bc24bea8ecbc86fc1b16546e27a94be5855d5a551673716453b96bb\" timestamp=\"0x7cbc894b\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.116\" file=\"ntoskrnl.exe\" hash=\"4a260090075120d78f747d3750dcc3e04a36bdb0820004e36e863303c3c033fc\" timestamp=\"0xcbc314c7\" size=\"0x0099a000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.145\" file=\"ntoskrnl.exe\" hash=\"c797fccf3958209aa35fac15f9fad270045f2f5b14b3e80fdc2667e82b9dcf1c\" timestamp=\"0x94531edd\" size=\"0x0099a000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.145\" file=\"lxcore.sys\" hash=\"b692e6d0319584060690c21c02b34d38abedc3e6f77c3996e148f043a7cc8b49\" timestamp=\"0xae77a857\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.207\" file=\"ntoskrnl.exe\" hash=\"80693bf3fa237e6a2af8054149ff203c0b4de667c850131b1072e01a013e0a4e\" timestamp=\"0x71dc6a70\" size=\"0x0099a000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.207\" file=\"lxcore.sys\" hash=\"64ac6d3054528a58479e89fbf490e83a0d06749acbb378aae31743caca1a9c62\" timestamp=\"0x618f51d7\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.239\" file=\"ntoskrnl.exe\" hash=\"4ea5182700a06380640d35a81ec3e9a5d6369e8ae2da7a0b78da46ea612a3f38\" timestamp=\"0x7e115571\" size=\"0x0099a000\" added=\"2024-10-20T15:35:22Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.267\" file=\"ntoskrnl.exe\" hash=\"1ded0005ff9894b96333f16cd1f7f4739e148656f8f76413282edcf4619ac690\" timestamp=\"0xbd9d1022\" size=\"0x0099d000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.295\" file=\"ntoskrnl.exe\" hash=\"75be4eea54e0d75f4c69bfc561ee39a083eadb728a17fba716cfe91cf3a85b9b\" timestamp=\"0x918e6d51\" size=\"0x0099d000\" added=\"2024-10-20T15:35:22Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.295\" file=\"lxcore.sys\" hash=\"b789f6d3a03c97ae0687eb9e01de0b168fcd1b1bba6868deeaea7479fa4925a8\" timestamp=\"0xd0c4f909\" size=\"0x00113000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.329\" file=\"ntoskrnl.exe\" hash=\"4f798d6425a76e7429973995364f6170233765c8ce709cd5f5cbb0f1b7b5b434\" timestamp=\"0x17d5b33d\" size=\"0x0099d000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.329\" file=\"lxcore.sys\" hash=\"64a43b795e1fc6cc79542f8e44458f697e7d68495130260acc853d4187f8636a\" timestamp=\"0x54f793a3\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.356\" file=\"ntoskrnl.exe\" hash=\"6bdde5ea188f80920173f49951374feb30ab2aa8cd5547bcce0bec89f4a5a0bc\" timestamp=\"0x5b1979cf\" size=\"0x0099d000\" added=\"2024-10-20T15:35:22Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.356\" file=\"lxcore.sys\" hash=\"26c3a039feae1392b4590d46e7875bd33e9552e1fceedc7809472fff3d9d4b2e\" timestamp=\"0xa73ee267\" size=\"0x00113000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.357\" file=\"ntoskrnl.exe\" hash=\"7bf9859c7c2f92ef11f926ac4a3e041bddde51ab9f1d32797368b7254517cad2\" timestamp=\"0xc183ef8c\" size=\"0x0099d000\" added=\"2024-10-20T15:35:22Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.387\" file=\"ntoskrnl.exe\" hash=\"6667a4b2859f49b882257dfad81d891af6a1ab380642aa5fb6de5e164dbcc6ea\" timestamp=\"0x15d5114c\" size=\"0x0099e000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.387\" file=\"lxcore.sys\" hash=\"a4cad2b163f9a7d7f6ba45e83514ba484060e33fa30f24f2e71a13ac81edd01e\" timestamp=\"0x3f06a4db\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.388\" file=\"ntoskrnl.exe\" hash=\"f2661177d3b676c3a29ffa278db85c3aa5ac6cac1a2bbc6326e4100957452037\" timestamp=\"0x87b15a01\" size=\"0x0099e000\" added=\"2024-10-20T15:35:22Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.418\" file=\"ntoskrnl.exe\" hash=\"2875acf0b430de9c2f2f11aa68ef8be10ebfe9aa3d63be160dfb23e1484f4474\" timestamp=\"0xa8d70552\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.449\" file=\"ntoskrnl.exe\" hash=\"5aeb98676aa37bce31676846e28991e63d0a9edbc432daf4283f9766d010aee0\" timestamp=\"0xb3cefa27\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.449\" file=\"lxcore.sys\" hash=\"9d60dd0d891c7dc5dd4dd88f8dd4c54181dc86699a5d760c5b042800e9d1b40f\" timestamp=\"0x01421027\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.476\" file=\"ntoskrnl.exe\" hash=\"db09be687ebf9fdb3d7aa98b21cc2f063691a9689e60b7bfb5ee1bc9084f6bb5\" timestamp=\"0x473f4799\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.476\" file=\"lxcore.sys\" hash=\"b8c61605f0a8164b2e7c329979420205e50b38523ea24f9facb91576f976d684\" timestamp=\"0xd921a7a2\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.535\" file=\"ntoskrnl.exe\" hash=\"bae859ed58bf22ef7e8453276bca8e581326f724ac2a53e08dc9c93ab428e141\" timestamp=\"0x0dac8612\" size=\"0x0099f000\" added=\"2024-10-20T15:35:22Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.535\" file=\"lxcore.sys\" hash=\"a55d73444f0f86af6dd358aca43a0583485641dc326570e4845d791336ce1823\" timestamp=\"0xb1b3bec5\" size=\"0x00113000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.592\" file=\"ntoskrnl.exe\" hash=\"bbd07ff41926c659a592881953f82a3c3451c16919c983f04cbe4aa14070b9ae\" timestamp=\"0x0a91c09d\" size=\"0x0099f000\" added=\"2024-10-20T15:35:22Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.592\" file=\"lxcore.sys\" hash=\"a609e0515dc3be97e8c1771c4934e54fa44ec03a5516ffdabeaa54e2a2e0fe13\" timestamp=\"0x1bd2f5fb\" size=\"0x00113000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.628\" file=\"ntoskrnl.exe\" hash=\"ee979cd6ee2fa0603544d766452170bbf7b593d2cbb3cd819cc65f2c17f469cf\" timestamp=\"0x05342574\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.628\" file=\"lxcore.sys\" hash=\"9489c75e1a0a4c1f044e45d5d5fa75359207ce6cd49f8882c9602ace5ad7c078\" timestamp=\"0xf03a4249\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.657\" file=\"ntoskrnl.exe\" hash=\"9736ac40c34c2d4e09b4025247d0ceba247f58a6656e11cdfaa53b354ed86e92\" timestamp=\"0xb6ff32ed\" size=\"0x0099f000\" added=\"2024-10-20T15:35:22Z\">17</data>\n    <data arch=\"arm64\" version=\"10.0.18362.693\" file=\"ntoskrnl.exe\" hash=\"960ddaea39d4f1967c5208ac08420fe358cf6ed434dfcc363a977a73f64a74f7\" timestamp=\"0x0ccdd34c\" size=\"0x009a0000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.693\" file=\"lxcore.sys\" hash=\"129933940a9b8e3cb79a52f08ebec07991c0ad0ea38cd59cf4b0ba73c6652c65\" timestamp=\"0x719d6e92\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.719\" file=\"ntoskrnl.exe\" hash=\"d35ba44c9c5f9370de46cc32cb37ecabfe8ff3fc9b242fa4021b20321be33661\" timestamp=\"0x5a13216f\" size=\"0x009a0000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.720\" file=\"ntoskrnl.exe\" hash=\"5aa0ee8bb44cf6848f5ded6d420eb7f961ea473edac7088f8ebf035bdc1df126\" timestamp=\"0xe5076f8e\" size=\"0x009a0000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.752\" file=\"ntoskrnl.exe\" hash=\"3bff81454e8c31f1aa1bd3a714b6af6db59b2b5cb49077815d61d0f7744c42f9\" timestamp=\"0x463dc8ad\" size=\"0x009a0000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.753\" file=\"ntoskrnl.exe\" hash=\"cb198c3a9540d239ebaf72b0a2bc51fb15879d206f40bf579f39cff00871036d\" timestamp=\"0xea1705e2\" size=\"0x009a0000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.778\" file=\"ntoskrnl.exe\" hash=\"1bf417ebf7720badb14849e3fc403c29b49d73f570dda06adcdb931c72efd9d8\" timestamp=\"0x4021e1e7\" size=\"0x009a0000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.778\" file=\"lxcore.sys\" hash=\"2bfb6db20643b7e892de69079e8d70980573ce273c899e15ff7386ca19c05515\" timestamp=\"0x182e8ac9\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.815\" file=\"ntoskrnl.exe\" hash=\"07af02660b0095c7ce3fe31b1e001fa0fd8070ae269a837dd55aad96b2934800\" timestamp=\"0xb80372d2\" size=\"0x009a0000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.836\" file=\"ntoskrnl.exe\" hash=\"42780d9eb9e2e4c77a79402783e73ee9997a2aeb4ba4627797382e42394c6eef\" timestamp=\"0x64d364c9\" size=\"0x009a0000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.836\" file=\"lxcore.sys\" hash=\"125ce0d4bbba2de00e74c10d7a738d1c1529e4f54cbecbefae1f0943157c491e\" timestamp=\"0xc196adaf\" size=\"0x00113000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.900\" file=\"ntoskrnl.exe\" hash=\"62d7cc64c0e7e35968af9813c0fc6818bea52e6a91a613c63974043d3cff31f3\" timestamp=\"0x5f8aacdf\" size=\"0x009a0000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.900\" file=\"lxcore.sys\" hash=\"8bee1a7d87b072274a954421687f82919d969b45318325522747be81259e351a\" timestamp=\"0x247e6b13\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.904\" file=\"ntoskrnl.exe\" hash=\"af3d34deceb6ac4dbbf298adaed2d8ad066f0188c0dbc6ba14fa2ffa5a2294ee\" timestamp=\"0x1f508cac\" size=\"0x009a0000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.959\" file=\"ntoskrnl.exe\" hash=\"e89e28afb5c0974c137639b1ae571a9544bdc0122ba3626ad23babefc644841f\" timestamp=\"0xf51d8b1e\" size=\"0x009a0000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.959\" file=\"lxcore.sys\" hash=\"9ea66fca41fda715dc0cfff561a8e45af3fc9170b49f348fd0b96929ba37b8a9\" timestamp=\"0xf702e88d\" size=\"0x00113000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.997\" file=\"ntoskrnl.exe\" hash=\"e2ecebcc84db48df9d87adb5a9577771d02490a1ce0c799812a7e43756d2f263\" timestamp=\"0xfbab3e06\" size=\"0x009a0000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.997\" file=\"lxcore.sys\" hash=\"9f68e8a3fe25908d962a4c6a1af354ee614e1c990061df6012a4e2c887215411\" timestamp=\"0xc0dfd56f\" size=\"0x00113000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1016\" file=\"ntoskrnl.exe\" hash=\"2461c111894ae6d4bbe448413a81ad487886d390806a37cbbafbdc832d543b4c\" timestamp=\"0x9f2f9580\" size=\"0x009a0000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1049\" file=\"ntoskrnl.exe\" hash=\"0c71847a49adf8fa2be75650d5b300cedb0e2b3e85f1bb8357e3ac14dab80f36\" timestamp=\"0xad738ebf\" size=\"0x0099e000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1049\" file=\"lxcore.sys\" hash=\"597555942b0d4f05f7d82ead49357961d46475bbff40f7c774f3adc2d4f392d8\" timestamp=\"0xf12d50a8\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1082\" file=\"ntoskrnl.exe\" hash=\"e5f11a8edd3ad984d7d7bb994b86d1e74175a981b2f4d439524704edc4ff7918\" timestamp=\"0x1bbe0aed\" size=\"0x0099e000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1082\" file=\"lxcore.sys\" hash=\"946b3f8c2b7276c396e32586025bdfba47854f94c134cdf8ab4e4d05b8b09fee\" timestamp=\"0x18159494\" size=\"0x00112000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1110\" file=\"ntoskrnl.exe\" hash=\"d4179d08f6b6bd103302bcbf209c6db14cee212328425d94981a933353dba119\" timestamp=\"0xe2129964\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1110\" file=\"lxcore.sys\" hash=\"7f99bd330e1b71df875f3ae4c5f1cb3245e8ac5fbe1fa8c6d23d55ef9cf70671\" timestamp=\"0x07cead1c\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1139\" file=\"ntoskrnl.exe\" hash=\"8c8a6510158320627e85e8b01c928c05c2a48611d62fc1d5558a212d043521ce\" timestamp=\"0xb93871d3\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1139\" file=\"lxcore.sys\" hash=\"a9395692b7225e798f6769e526e448e0e7f6873b589b3f47078169e49b9e238c\" timestamp=\"0x86862239\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1171\" file=\"ntoskrnl.exe\" hash=\"6477e35c1ec0a8f7ceebef83c88f93fce73a116654eae4e9220c378194b3f7b3\" timestamp=\"0x44b1908c\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1171\" file=\"lxcore.sys\" hash=\"658cfb8065fcddabb66bf1e72f8d0fff428bda797f78833ed05b9665d454801e\" timestamp=\"0x4add6f38\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1198\" file=\"ntoskrnl.exe\" hash=\"8e31d064dbe7dd876003d88ea367e685ffd0ddc5c5715cf7a23fc090cd47df6f\" timestamp=\"0x4b5cc800\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1199\" file=\"ntoskrnl.exe\" hash=\"966b9787c4dfb800ff44f29e7b361b0136f1edf4966c5576997c309dae5dfc32\" timestamp=\"0x523acbaa\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1237\" file=\"ntoskrnl.exe\" hash=\"1731aef610a52d558fd22c70cb5ad24ab8108108883483c13571bdf336f8aaf7\" timestamp=\"0x5f53533b\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1256\" file=\"ntoskrnl.exe\" hash=\"738ede1f75b8bdf3534ada0eef4c6f33bfceba125b996c07132078e1526cb2c2\" timestamp=\"0x197a808a\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1316\" file=\"ntoskrnl.exe\" hash=\"5c11661927980861a7001bd604e6f9f2f40c674d88c311e998f1d553f702f451\" timestamp=\"0xee24d943\" size=\"0x0099f000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1350\" file=\"ntoskrnl.exe\" hash=\"786151a8eebf3b0f398d9c9c477e036294d3b747e42d906298fd87670bfa6625\" timestamp=\"0xcd4eec6e\" size=\"0x0099e000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1377\" file=\"ntoskrnl.exe\" hash=\"684ca4f4f2db88e7fc1f659a09ac986487e11301a8912fc918bc8614c295294c\" timestamp=\"0x68bd321b\" size=\"0x0099e000\" added=\"2024-10-20T15:35:22Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1379\" file=\"ntoskrnl.exe\" hash=\"e46502b5e6d14f29cdc1ff3506320c5f38bf33c47426f071abcd3851ee6a67b0\" timestamp=\"0x4a736d59\" size=\"0x0099e000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1411\" file=\"ntoskrnl.exe\" hash=\"c50688868aead60cc27d45d1e9c95b480c79f743865fe9df3fb21851a9483239\" timestamp=\"0x8c6b87c5\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1440\" file=\"ntoskrnl.exe\" hash=\"83ddf4e9f79dd22b56225109f6c07e000bf9a0b7cf0d28f8f95ef31bd36ebf48\" timestamp=\"0x7126419b\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1441\" file=\"ntoskrnl.exe\" hash=\"fe0d3fa2a0d206fee2250c9b39f748b4133b01f8746116a976979e661bc2d469\" timestamp=\"0xae9afa9c\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1443\" file=\"ntoskrnl.exe\" hash=\"e6916ee2e5aac5c7b1f5dacd6008843fb1c8d752f391b0e8ad12f6a3379986f4\" timestamp=\"0xe4d7bf42\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1474\" file=\"ntoskrnl.exe\" hash=\"267155cff097b95e17a7b9bc970dc7ea48baa3b4c7c7673e1f043661cefb03ad\" timestamp=\"0xc7fb74b2\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1500\" file=\"ntoskrnl.exe\" hash=\"1bd7550bcb66f83858c3e2eae1e0a61801867590cb6b38bfdcc25a5c3a10d42c\" timestamp=\"0x57e9d78b\" size=\"0x0099e000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1533\" file=\"ntoskrnl.exe\" hash=\"1134949190229957008df076a1c0f2dc37d6443eba5011c764b2d2216b010a13\" timestamp=\"0x2e7974ec\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1556\" file=\"ntoskrnl.exe\" hash=\"e30725a3172f5520ca2ee901fa3395cfbc9249e53e3391965be5348669b0c024\" timestamp=\"0x057935b1\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1593\" file=\"ntoskrnl.exe\" hash=\"7e9e7b8f16a61d3bbb981201b381c2047fc2af4fd53300a7115fe6f773430db8\" timestamp=\"0xe64fed94\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1621\" file=\"ntoskrnl.exe\" hash=\"3929289df6f3f4b2d9d39864b5473e7715fbe92a5d4899269ac9e598161e88ae\" timestamp=\"0xfa095836\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1645\" file=\"ntoskrnl.exe\" hash=\"413df7e2168e657c3d1364addce9c7809526dbbaf401359844e5a9921d2493d5\" timestamp=\"0x330a3e63\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1646\" file=\"ntoskrnl.exe\" hash=\"66870de7bcb99fc92909b21f73cb44401d1a845f2b5d25bbe4ad0ebfcadf6cf0\" timestamp=\"0xd631914c\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1679\" file=\"ntoskrnl.exe\" hash=\"5cbde6257006ede486510ec241ce6f44b2f0693ffac9d011021086a476ba15e9\" timestamp=\"0x6539a656\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1714\" file=\"ntoskrnl.exe\" hash=\"b25adf4f154d4926f8272974d64b29fdc9708e22ee14d0a6ac7d4a730bf43dd0\" timestamp=\"0xff06c273\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1714\" file=\"lxcore.sys\" hash=\"75566795d1209ce45393ab1cfa363c87cce457356a42923c921ab582051e43bc\" timestamp=\"0x56b08eab\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1734\" file=\"ntoskrnl.exe\" hash=\"9b5e03c626c14371628d259a71c787a84d17773b48858ead4e94b1cf7e8a710b\" timestamp=\"0x92aa433e\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1766\" file=\"ntoskrnl.exe\" hash=\"6f29ab9bf75b22c058d03a26ac7b1df0c12333d7c7235b62dbed2fa891f0f2c8\" timestamp=\"0x2e7f7543\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1801\" file=\"ntoskrnl.exe\" hash=\"c6e0ac5154148bf60978d7af346fc15c63f65a795d031330fce0ac782dce9c99\" timestamp=\"0xe6334101\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1801\" file=\"lxcore.sys\" hash=\"d3bc2c3480c2b9fbd72e7d00a1076218fdac9c381335a4e6b3590b81f8dee384\" timestamp=\"0x5f0201d8\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1832\" file=\"ntoskrnl.exe\" hash=\"c41b0c89009ce90144ccebfaa00c890b661af5d5aceb835508c8655bb36c1d2b\" timestamp=\"0xe1c76945\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1854\" file=\"ntoskrnl.exe\" hash=\"2c8ad0dc7ff1a42c530432d9927ee6b071dba812f10ddad14db864301f9f0166\" timestamp=\"0xf7f27db4\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1916\" file=\"ntoskrnl.exe\" hash=\"4494cc741089780bc492bd98168ec1f5eb8c6f6399181ee8d20d41ecc6c7801b\" timestamp=\"0x3377ede7\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1916\" file=\"lxcore.sys\" hash=\"5a13f8ec37162e4ffef35deba84076ad2902beb2b0419f2148b2be6767e3496a\" timestamp=\"0xba0d3b49\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.18362.1977\" file=\"ntoskrnl.exe\" hash=\"6077d10dcd85c825ecd2c11868f31503b219bfbf008aadcf79265013900d75e8\" timestamp=\"0x70d33d57\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.2037\" file=\"ntoskrnl.exe\" hash=\"9aa898d1fb5e20303be8b692e7adfd6f58b194f68061db01b359a031d0942305\" timestamp=\"0xe4de9a4e\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.2039\" file=\"ntoskrnl.exe\" hash=\"d45505cced711b58b59564e6c4e375854f9794f5d0a9671ac6958b19cbe5ffee\" timestamp=\"0x1ab7d479\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.2094\" file=\"ntoskrnl.exe\" hash=\"a2f4e8b9581d9c4b04da8f6c37c32fc74428f532cd93b7d5ab3bf72a34423293\" timestamp=\"0x178a5729\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">18</data>\n    <data arch=\"arm64\" version=\"10.0.18362.2158\" file=\"ntoskrnl.exe\" hash=\"048bc9d918af02cb45df89fb252620652ffb3565a5dc7fea3fa35b25e6964435\" timestamp=\"0x8bc74ad2\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">21</data>\n    <data arch=\"arm64\" version=\"10.0.18362.2212\" file=\"ntoskrnl.exe\" hash=\"a16e33e1011cbd5354a1bf038254f919e1855c307ab3d6613b292d37c399590d\" timestamp=\"0x3bb3fde1\" size=\"0x0099f000\" added=\"2024-09-12T01:41:05Z\">21</data>\n    <data arch=\"arm64\" version=\"10.0.18362.2274\" file=\"ntoskrnl.exe\" hash=\"a1cb788d989068f187167cd6dac0c51a03809ec5504f5d9131eb8b49772275a2\" timestamp=\"0x12cb4e4a\" size=\"0x0099e000\" added=\"2024-09-12T01:41:05Z\">21</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1\" file=\"ntoskrnl.exe\" hash=\"9d1c17012033bddafeb7a66a393261b14918e4da977027f1677ea54fd4a149ac\" timestamp=\"0xdc273334\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1\" file=\"lxcore.sys\" hash=\"d8160de3634f92fc2717345f2762ca2dd444178d12a263d7af54998ecc193a02\" timestamp=\"0x0a84d137\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.292\" file=\"lxcore.sys\" hash=\"6959a03be7101784c9bafb67c6736463211c1b42e5ee9e4d3a1a34bbf4d9471b\" timestamp=\"0x1e44f133\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.329\" file=\"ntoskrnl.exe\" hash=\"442946b50e9c9875c054362958cc5784e9c8f48d572e0908dba43363f8074989\" timestamp=\"0x93e9b3a6\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.331\" file=\"ntoskrnl.exe\" hash=\"306afb0acc8b8baa5a6c21827240e691878285612c4a57fa969107e2d82dffcc\" timestamp=\"0x77af5329\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.388\" file=\"ntoskrnl.exe\" hash=\"aa72e2e486446ebad986282d8e37340135d0e71f66e75bb626b91654a100e0a6\" timestamp=\"0x4ccb508a\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.423\" file=\"ntoskrnl.exe\" hash=\"c59aaeddfbf7c37ff2af3ec3c16dcc534ef6318deb7b138a0c93d9e6afe90f93\" timestamp=\"0xe80078a6\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.423\" file=\"lxcore.sys\" hash=\"4a7a62e0a1e6e1370aaf011e560465ac4d7e384024762b7c91fbcf0c6caa2823\" timestamp=\"0x02cb1a7d\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.450\" file=\"ntoskrnl.exe\" hash=\"fc0d3b2767ebe483293a6c17b3882049a3eec98ba62d762afb1afe2c7eec4849\" timestamp=\"0x45bdd1e3\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.488\" file=\"ntoskrnl.exe\" hash=\"73103cccd180dc377f39cd2e9a207e0206498f6983b548994cf23303e198584d\" timestamp=\"0xfc22771c\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.488\" file=\"lxcore.sys\" hash=\"4ac932381872cbe38cd1d18eb9a66ff6762966438f629dac1a0daa42d0f62da1\" timestamp=\"0xaf7ca0dd\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.508\" file=\"ntoskrnl.exe\" hash=\"96e8ee807c08d607b7f2015d6dcc897614d0134ad51d82b7272410fc999b640e\" timestamp=\"0x61c7fba5\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.546\" file=\"ntoskrnl.exe\" hash=\"b6a17672510da31ea182f8330d9783a5b9fb95be50bfd2afe847c619017e08c2\" timestamp=\"0x5d92611d\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.572\" file=\"ntoskrnl.exe\" hash=\"d31c36fd0e1671bee348eacbffe768e1448252b51bb0465bb2f3753649c2b254\" timestamp=\"0x159d14e9\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.572\" file=\"lxcore.sys\" hash=\"b2c27cad0fc4270faac659d53452428d107cc207dae82e9138f3bf5fe63b2384\" timestamp=\"0xf473db97\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.610\" file=\"ntoskrnl.exe\" hash=\"b995849dc84640b9b027e98fff83025e1259529eeee4430155b09688557e148a\" timestamp=\"0x02b48154\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.630\" file=\"ntoskrnl.exe\" hash=\"9d0e976ab48c6924a9c5f8296be147395643302ad86490a101acb3687b14e728\" timestamp=\"0x951212a8\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.631\" file=\"ntoskrnl.exe\" hash=\"63e82e95eb40ebedb53e68cdd14381931d2b182a2105b15ffe3e5bc9306e0e93\" timestamp=\"0x3f2ab481\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.662\" file=\"ntoskrnl.exe\" hash=\"4d3c55897534ce9e33fc04da5515ced81315d284a94a79d86f1ca3aa2f2a0f3d\" timestamp=\"0xcc8ee873\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.662\" file=\"lxcore.sys\" hash=\"2ca8e7a43da3b8548f76ad5377e35ff616fe6bf2030df52b3e5d0fa08122265e\" timestamp=\"0xcf7fc60b\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.685\" file=\"ntoskrnl.exe\" hash=\"856cb4d2763c7358a826bd1a57e271ad6c15f4c07cdc6dcb21d46071945313a6\" timestamp=\"0xbcb5aa1a\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.746\" file=\"ntoskrnl.exe\" hash=\"ac49ec4fabcf1062d564681d8b5efea9a33569545f30426a896d08080d599144\" timestamp=\"0xe138d32a\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.746\" file=\"lxcore.sys\" hash=\"aff86338f4377e228c244fb44da3308809e88e286a7c4c7ba0c1fe6b6a605d3d\" timestamp=\"0x5b917709\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.789\" file=\"ntoskrnl.exe\" hash=\"7d73321044d565a804e36171ef7e9ef12f414715178334418eb5a2066363c007\" timestamp=\"0xf8515f5e\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.804\" file=\"ntoskrnl.exe\" hash=\"8f2e2d2ffd363b1d20129f295e904ec4fd4c206f5b7347a70f6f83f927d46e34\" timestamp=\"0x9fd2b56b\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.844\" file=\"ntoskrnl.exe\" hash=\"88acbad6d4da221e774f38db1190f6fa830d0a8458dadbf0a68d93629a29f4a5\" timestamp=\"0x6477ebab\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.867\" file=\"ntoskrnl.exe\" hash=\"d194af3b48d2a49efb1ce4d9a9b84f7a2d22a034afec3533e28e801b80255470\" timestamp=\"0xf3367900\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.868\" file=\"ntoskrnl.exe\" hash=\"c499406b1b9723a216efdbdb72e9c298f4caa443c87b908776672d0bbf4ec866\" timestamp=\"0x5e513ba9\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.870\" file=\"ntoskrnl.exe\" hash=\"25ae2ac209bd2188b711fe159374a2c74eba135a7ee29749763ca6716f361ea8\" timestamp=\"0x50890ade\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.906\" file=\"ntoskrnl.exe\" hash=\"b22fe70150f5a59cefcf2e6eefeaeebf3f3f6bba7e810e45a63b509b7a3596dc\" timestamp=\"0x8f6b170e\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.928\" file=\"ntoskrnl.exe\" hash=\"b1035eee82c8c073ef0187ad712443f44e619a57703cd999ed7fd72a45f26694\" timestamp=\"0x6d7d9b89\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.964\" file=\"ntoskrnl.exe\" hash=\"790ad56b992b5afa851a52e66ef743516810b4fdec77294c6caf698fab373543\" timestamp=\"0xe2cf668e\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.985\" file=\"ntoskrnl.exe\" hash=\"eb1cbb6d5a9d147126ceb0ee83f85f25cbcc97326d8daa03999f69631c28d3a9\" timestamp=\"0x8cd34693\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1023\" file=\"ntoskrnl.exe\" hash=\"5e31141aeaa58d7e971e947557583de9b5edc0e9f14492ad1d606acf144fefeb\" timestamp=\"0x703e3ecb\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1023\" file=\"lxcore.sys\" hash=\"99dbb7cbbd3f99e28b68645d8d63dbddedfbaebcc1fe93a7d2a8df0cab7f74d3\" timestamp=\"0xd53631e5\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1052\" file=\"ntoskrnl.exe\" hash=\"2e182f4568670e5abfbcbba6fcb0ae14dd39dafbbf18d56aae559fc824eee452\" timestamp=\"0x55aaad26\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1055\" file=\"ntoskrnl.exe\" hash=\"4008b6fa51ebcd6759afe4c4618798baf59553686787f4b7a1a49584e3f90509\" timestamp=\"0xd3328e69\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1081\" file=\"ntoskrnl.exe\" hash=\"e3315cc4f0c59c61245b002191a680f8174f72654d65b49de91abd0e96e455c0\" timestamp=\"0x30d4a6b9\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1081\" file=\"lxcore.sys\" hash=\"e77647c501ca80644cc501b8da6ba9b4365d50991dca20e8ac7ac0b2326559c2\" timestamp=\"0xbe3aef0a\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1082\" file=\"ntoskrnl.exe\" hash=\"6615413fa605462beb0d1bd64f17e23881956755150e87525e8c56cf87e9a2b9\" timestamp=\"0xf641e8a8\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1083\" file=\"ntoskrnl.exe\" hash=\"4e913b1d50e1590138772acbb77d77cf72f6fb73bae44ae59a691b3c3b23a0c1\" timestamp=\"0x94b2b21f\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1110\" file=\"ntoskrnl.exe\" hash=\"51a733caa9e7cf597fe0cd85d2457a40999397ef43c2a8bf8137ecac7168f6d5\" timestamp=\"0xd46c5c0b\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1151\" file=\"ntoskrnl.exe\" hash=\"ccbca54df41c9d89337fbc3bb52fae2da22ac179ee486134626892538a82bbdc\" timestamp=\"0x97268e77\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1151\" file=\"lxcore.sys\" hash=\"330da0b6cbef966747d9620b2fae6b80b4b2900d7fdc99e445158ad29cb3edf0\" timestamp=\"0x9c8475fe\" size=\"0x00111000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1165\" file=\"ntoskrnl.exe\" hash=\"6c45bbdcde17b69783016335d73bb86f719fb2580dbca0d802b747133bdbed5b\" timestamp=\"0xb449615b\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1202\" file=\"ntoskrnl.exe\" hash=\"fc2cd944f9643e23c194ac6f5ffa23cc38b5b9884aaa99dc9859a4faace23de7\" timestamp=\"0x6a3d199a\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1202\" file=\"lxcore.sys\" hash=\"8a9fad1e95be8495ee99a37fb5890327ecee252b8dc39af9538de8bfe10adfeb\" timestamp=\"0x9299fed1\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1237\" file=\"ntoskrnl.exe\" hash=\"955bdb8410d38abe4d5b76e7b36fa53d7d99bb83967e173a2a2a955907ea5914\" timestamp=\"0x72bfdffb\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1237\" file=\"lxcore.sys\" hash=\"883f06215e6fae68e49d04d79ccfd511d41ca2e852378acd9727e6a4004a9173\" timestamp=\"0xa2decf9d\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1266\" file=\"ntoskrnl.exe\" hash=\"e53f3b729c27a07007bc7fcc7b39613f36ca8450a29b1ab4fac9e9bdf1219614\" timestamp=\"0xc7ea0b3c\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1288\" file=\"ntoskrnl.exe\" hash=\"1f0801edbd8d2f8f6f96d0dcafddda48f92228b6dfef6a863475e67f9cf4b380\" timestamp=\"0x1410aad4\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1320\" file=\"ntoskrnl.exe\" hash=\"d6d9f03d83c05c5e58a6734aeb5af09d810bd248be669db2b7264041b0f387c3\" timestamp=\"0xcfede7d2\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1348\" file=\"ntoskrnl.exe\" hash=\"817eef0cb9f4792f2d9cc769b312eeba8bb93bc18f009ba268b6ac4fb2fc83ef\" timestamp=\"0xd699a7d2\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1387\" file=\"ntoskrnl.exe\" hash=\"aff764feb6bb7044127c6f627ed606ce868842b1464ccd5a6db9a41b60e921ea\" timestamp=\"0x0f190304\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1415\" file=\"ntoskrnl.exe\" hash=\"65a7c749043854b5f1b5eaabdf05659d89ac12e9ad19b306926fb98a85c3b786\" timestamp=\"0x1dd7b79e\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1466\" file=\"ntoskrnl.exe\" hash=\"fd15e13a07209a062d8b1e2d567c079cf5d53be1c16016fbaafb4de4815afa22\" timestamp=\"0x5bc4a2c9\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1466\" file=\"lxcore.sys\" hash=\"c55b1c9b25bf6342b2f2687f7fe5863fafd6b7c965b4c3ac5ff06f5dde0b9844\" timestamp=\"0xb6f13ea9\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1469\" file=\"ntoskrnl.exe\" hash=\"ea7a7ee46a82f02e580f7f9a1e06665a7be002bfa51d990dab53a45382f6366b\" timestamp=\"0x41385bb9\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1503\" file=\"ntoskrnl.exe\" hash=\"ee0039c62195676ca269fff30ff52bee96a50295b1127b39eade40068e7c43ef\" timestamp=\"0x32fe8df0\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1503\" file=\"lxcore.sys\" hash=\"fdc04d3fe1ba26cfb112b0129992e657ffa03685915460a369071dc30da3f0c3\" timestamp=\"0x03811c1e\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1526\" file=\"ntoskrnl.exe\" hash=\"ec4faac438267647439c961b27a05193b12e90f202ecf5f3addd3fdafc958904\" timestamp=\"0x0fe91642\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1566\" file=\"ntoskrnl.exe\" hash=\"dfe57735b0273ff945ec6bb839c2937aa3bc6f9419d309330ee13c85ba61286e\" timestamp=\"0x7689fd12\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1586\" file=\"ntoskrnl.exe\" hash=\"c06b76afa857cf342f0cf3948336ccc8d24a6b242d040215fd3f4553f60e7652\" timestamp=\"0x2ba0fe44\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1620\" file=\"ntoskrnl.exe\" hash=\"893177ea6b5e59099bc424f67739e91a6bbea277bc38c8f39c1e504c2d0e2529\" timestamp=\"0xb7feb16e\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1645\" file=\"ntoskrnl.exe\" hash=\"5d48af8f68d19dce4b670f41d4153a0a9960db6ab9d5013a7be162c61d0b6fb8\" timestamp=\"0x8b1ef3f2\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1682\" file=\"ntoskrnl.exe\" hash=\"6123d9add2ecc87c50540a3af7a9306ea9004f0a5c638022f2241efb059aa675\" timestamp=\"0xd668fd6a\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1706\" file=\"ntoskrnl.exe\" hash=\"324d376564245fbfab2ef06310f3a2b5884d9292bb8b88113af05a5f75519c10\" timestamp=\"0x59b876cd\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1708\" file=\"ntoskrnl.exe\" hash=\"ae4f7c50e82f74089e7b8d209217400b1e79d8f81c373bbfddb004d62c58892b\" timestamp=\"0xd28ee2a1\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1741\" file=\"ntoskrnl.exe\" hash=\"dc3a7f50792e507767a2c5c31710d9109ddf2b482e8ed02c44ff9c702cf89ec3\" timestamp=\"0xe9a285cf\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1766\" file=\"ntoskrnl.exe\" hash=\"012ee5939052375efd6fe417a406ef87d495cd1317904a33d485e2862a3216de\" timestamp=\"0x84ff7678\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1767\" file=\"ntoskrnl.exe\" hash=\"412ad51220df37e21fa1ccd820be50c921169db6567b9bbbf170a3c6ade8c6a3\" timestamp=\"0x880ad23b\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1806\" file=\"ntoskrnl.exe\" hash=\"41bfc6502956ec481c8d2feec0efd3bc2c36e7ba4c044f693c5adabec44b43ec\" timestamp=\"0xde067bfb\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1806\" file=\"lxcore.sys\" hash=\"807f451a0e36c274086860c2b72f728b0919b56f84eaa2817affb297a10bc533\" timestamp=\"0x724460b6\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1826\" file=\"ntoskrnl.exe\" hash=\"5a6a1f6afdb01e6b57bec38b8d94ff1e8677408d2a1d71d47cf9cc4e2eebb98e\" timestamp=\"0xdae0f3d3\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1865\" file=\"ntoskrnl.exe\" hash=\"038e7d169a34fef7203dd9c9626718e86063dbc139fa6890680c18f3944cd34b\" timestamp=\"0xbdf53076\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1865\" file=\"lxcore.sys\" hash=\"747db8af569225bc4279d2fe275752bd749cb097c4e1c23c9688e19a309713b5\" timestamp=\"0x6f6a331a\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1889\" file=\"ntoskrnl.exe\" hash=\"bee3985761f99ab40b36614021163b58127bc452555024beda35d373c966044e\" timestamp=\"0x6779db46\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.1949\" file=\"ntoskrnl.exe\" hash=\"348ab9778548a5aabeca3dcc4b89afaa705eb99cc7f98a8e6ef045efc2d3b11a\" timestamp=\"0x127e65d6\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2006\" file=\"ntoskrnl.exe\" hash=\"19e60200fc9cf57e561d301020d6da1309b778cdaa4964eb45e0cae250206162\" timestamp=\"0x24ea0499\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2075\" file=\"ntoskrnl.exe\" hash=\"e012434b41645e30002bdf4911da988696fc43406db9fbaa65df22d2beb4b872\" timestamp=\"0x6f2f50c2\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2130\" file=\"ntoskrnl.exe\" hash=\"a62bf8737334a605c68b0918271201818f7825dff22d47a3d41358557ffc939b\" timestamp=\"0x6e449cf4\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2193\" file=\"ntoskrnl.exe\" hash=\"a1ac726a26f7965336f1dc75d7ca9d0b04955980bfc198dd03d6408e6e611fe1\" timestamp=\"0x8b6c9098\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2193\" file=\"lxcore.sys\" hash=\"f5ac36bdadece4bac2fe50fd073c8bb8ce1c537fed6b9f0c47e3870440320614\" timestamp=\"0xb12dc8ed\" size=\"0x00114000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2194\" file=\"ntoskrnl.exe\" hash=\"b876bbdf46de671d2e426021a5852681a8c054788b7b9a0ddd218939b0750215\" timestamp=\"0xe9480ac3\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2251\" file=\"ntoskrnl.exe\" hash=\"628c797290a78bd4769d79efaa995c2fc30d867c6b9a1b1e9e66ee53362afae9\" timestamp=\"0x382d2343\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2311\" file=\"ntoskrnl.exe\" hash=\"b20ba48e0608a2b0bb89a1511610d6b3b2c0bdaaf0dfc9eff97e03b36815920b\" timestamp=\"0xfd43995d\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2311\" file=\"lxcore.sys\" hash=\"c1802525c3b5ce0b3c111ec7c329e00554314121e078461ccfb363768e2028e1\" timestamp=\"0x40f3ef7f\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2364\" file=\"ntoskrnl.exe\" hash=\"bfe41f918cc05d4454d553d347e0475bb3ac16edbcbd782e269b3367d063aa58\" timestamp=\"0x6bb02834\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2486\" file=\"ntoskrnl.exe\" hash=\"fbf0f97f223408c375363bcd12082611b1ca36fb57499373827020ceb6d98429\" timestamp=\"0x3ccfd2ae\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2546\" file=\"ntoskrnl.exe\" hash=\"220e0440911dffb5745d7660808ac57e491631daca9e49091bd9e5a065427ac6\" timestamp=\"0xad821478\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2604\" file=\"ntoskrnl.exe\" hash=\"54298874d10139566a87c61bd857b0eac6771c40a9c2ea8f86f8eef12f689d4d\" timestamp=\"0xd67247b6\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2673\" file=\"ntoskrnl.exe\" hash=\"a91f5bc24f93c086f407f51723833bc2f4adf965db383e8623dd7b9e2a2ce2d8\" timestamp=\"0x5bfce1cb\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2728\" file=\"ntoskrnl.exe\" hash=\"d61ab685a01489b1ed5dd203be17c06481a75288675be900e8ed088c62e17d79\" timestamp=\"0x6bfd4563\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2788\" file=\"ntoskrnl.exe\" hash=\"249e44f0681bc1e8e87946cd959bf5d6732ed863f79116729f80ac9555b48b8e\" timestamp=\"0x0e601a2c\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2846\" file=\"ntoskrnl.exe\" hash=\"cbeed67129cac6f269a4e3c5383b2ee3e6057261e7b52f38b50167ac1ef84190\" timestamp=\"0x8b279e94\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2913\" file=\"ntoskrnl.exe\" hash=\"31d99b2b598e38b5cd8915c7395b87f8d44858a2deb4515b9f63505635bef507\" timestamp=\"0xa6b3a1eb\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.2965\" file=\"ntoskrnl.exe\" hash=\"dd9579f53f2d0367b72f7ea887a28942982e3a4041756d0261196a89b18ed6ee\" timestamp=\"0xaf961946\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3031\" file=\"ntoskrnl.exe\" hash=\"388a1ad3489440f631d882c8d4feda1ab2cf26c11fcac7a3c7d817b8af02544d\" timestamp=\"0xeb8406c3\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3086\" file=\"ntoskrnl.exe\" hash=\"905ad81718049fb87440a7dde2d65a02517f55d97f35a09da1add20970b7f1c5\" timestamp=\"0xd24f590d\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3155\" file=\"ntoskrnl.exe\" hash=\"1805a9c7082048bbe4a554a4485941d5d2bccaf77d079d5e554ee74c8587aeff\" timestamp=\"0x22e89b5b\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3208\" file=\"ntoskrnl.exe\" hash=\"0454c61ddec15dda0f676d0b49614f066204e264f6829dc7722ed1a31bae79e7\" timestamp=\"0x9773e822\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3271\" file=\"ntoskrnl.exe\" hash=\"a2b68f1b667ac4f37609d0fe687fef7bb9b1daa0b35c74f9f304207f6b39f203\" timestamp=\"0xad7cc83e\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3324\" file=\"ntoskrnl.exe\" hash=\"13829255b0115a1747fd5d4ba0cb95d568ba9f936167f9fc64f957f0cefe8083\" timestamp=\"0x05628972\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3393\" file=\"ntoskrnl.exe\" hash=\"9d2aef35e41b9d71d84c5ef9d34a92bd16ef767e5ba8b8fb3c2f071e4107cec4\" timestamp=\"0x2da74b05\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3393\" file=\"lxcore.sys\" hash=\"59e479e0fcde0b4da8adec24b994137b88ac87e24ca96134d58da12d39b7b07b\" timestamp=\"0x32c633d0\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3448\" file=\"ntoskrnl.exe\" hash=\"9a6fdaf2fd8f0561c4dda375eed14bc6047055fd6503f402de54cacc26575251\" timestamp=\"0x3614dc90\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3516\" file=\"ntoskrnl.exe\" hash=\"5c15607e29162a4867dabaccbedf3eb6cbc3fd61c0bfac99d65dac3fc05cff5e\" timestamp=\"0x38ef6575\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3516\" file=\"lxcore.sys\" hash=\"1af741cc2f043c17c43ad21fb850454e3ba4909073315ecffc1f5f840f49cbef\" timestamp=\"0x7f01a1de\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3562\" file=\"ntoskrnl.exe\" hash=\"e97a76dfbf70fcb2f6f5d0d8690a50fbea90179662de0be11175cc7c9577c53e\" timestamp=\"0x721c12ab\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3570\" file=\"ntoskrnl.exe\" hash=\"e3ae87cb80c3268199504f0dbd6210656c838e09fde2fcbf6e1beb4cb940bc5c\" timestamp=\"0x4e46c050\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3570\" file=\"lxcore.sys\" hash=\"dcf53619909ea8b3ef1c7567b31aa8986147e36214847a6591d343ce393eae02\" timestamp=\"0xeda05dcb\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3636\" file=\"ntoskrnl.exe\" hash=\"d943b690cd7127b318f9303e12e925fbe7cbb9555bb2c5ef0646e38f332a1ed5\" timestamp=\"0xf433ae28\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3636\" file=\"lxcore.sys\" hash=\"a16b19acb33ff11cecd3b1915859718191f144da113050f9449f115d004f4310\" timestamp=\"0x32a43fa0\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3693\" file=\"ntoskrnl.exe\" hash=\"339ef1f30372eac2b3bc416d125db62279f2507a19e36717941912a446d07bb6\" timestamp=\"0xd774a2ff\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3693\" file=\"lxcore.sys\" hash=\"e69303ad6411b5296d9e651a3c8bfd248a67339004baf8aa218e0560228bf7b7\" timestamp=\"0xda84bc82\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3758\" file=\"ntoskrnl.exe\" hash=\"c365a964bf73982dec54d35a70447b05aad5288791db2858409518b1d51837c6\" timestamp=\"0xb5dd1c22\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3758\" file=\"lxcore.sys\" hash=\"985e01951f311776a1e55fcd8394319ee2f37901caa9e232efbd04221b5ec996\" timestamp=\"0x54e6943d\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3803\" file=\"ntoskrnl.exe\" hash=\"7a0ad6af1db56ee6f969769493fccfe78221694eed1c66c817c4989ed2e117f7\" timestamp=\"0xe40ad59b\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3803\" file=\"lxcore.sys\" hash=\"e7ddae021bd9622c9128a60a95e3bf75b37d0ac780760ad76df1e4533ce9a1e3\" timestamp=\"0x200eddfe\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3930\" file=\"ntoskrnl.exe\" hash=\"e039ec8ae72314a3c83ba4809f604d27cc0d54cbc593df232d8c86ec4adf5b49\" timestamp=\"0x360e5de1\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3930\" file=\"lxcore.sys\" hash=\"61f680ebd3759e09fa9030b82e3d72d2242a12e44246687b8508af8277330f0e\" timestamp=\"0x0cb6d42e\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3996\" file=\"ntoskrnl.exe\" hash=\"d40aad9a4ee7b28f7215d9a60a3e06e7397faaf41de138a8f0d5f3b1340ba5df\" timestamp=\"0x32a6ef98\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.3996\" file=\"lxcore.sys\" hash=\"bf0c7feb364706dc22dd7485b7bc0a50554bd582782929e1315577613f75fbf0\" timestamp=\"0x175c85d9\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4046\" file=\"ntoskrnl.exe\" hash=\"cb66432ec03e619f359f5f1c16ddb79771f12721402dee42cab65b81e2d27453\" timestamp=\"0xbb04d3e3\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4046\" file=\"lxcore.sys\" hash=\"04a7eb65582f8145b6d1aa45943f15bcb04b54b67cf7d84b8fe1f620b83d5ac6\" timestamp=\"0x3a8e59a5\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4123\" file=\"ntoskrnl.exe\" hash=\"25e591d516cc2ea1f19b17fa89e4b5875b0a53614463b0cdfd9d5cf44a0be165\" timestamp=\"0xf59fc7c0\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4123\" file=\"lxcore.sys\" hash=\"e21363f9686b8c783097f9c22f6e7073b71a0d799a57f0cb61e6710c6fea782e\" timestamp=\"0x97ea3b5a\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4170\" file=\"ntoskrnl.exe\" hash=\"19a32a15d470e1596223f4bc72e39798fc73389c6cc784ce6583b18c600fd5db\" timestamp=\"0x5659b639\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4170\" file=\"lxcore.sys\" hash=\"c04ad835856324f1ce39286946f993b58694c00cefe9b74fb15e9e471a0e9a1e\" timestamp=\"0xb50df818\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4239\" file=\"ntoskrnl.exe\" hash=\"d1ba668cc8ade9c2a75723ff9771a46d09a315f871dc84638e65e9f58d7012c2\" timestamp=\"0xc0102ef0\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4239\" file=\"lxcore.sys\" hash=\"6e20c907f99fce3dc8a7a16247565c616c6a8252acc6ca31d594f4b1a4628e5c\" timestamp=\"0xafd0c8e8\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4291\" file=\"ntoskrnl.exe\" hash=\"5f848eea5508ea0b0719a67870906c7a2842432bd83cd0320668b653c67550a3\" timestamp=\"0x42967dae\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4291\" file=\"lxcore.sys\" hash=\"b1facbdfa9566914c33251d850b03b39f6e1d6ddbd66a28375e728d71517cabe\" timestamp=\"0x2d52a497\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4355\" file=\"ntoskrnl.exe\" hash=\"bf3c1bac1a87f6ca5c53896e3c1b4a6a027bcd186da893b74acdf3db0c727fb4\" timestamp=\"0x422026f2\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4355\" file=\"lxcore.sys\" hash=\"8432b2bb4781faeff8516eca949b927b88641e7ed4efebb4d1f3d62e774b64c9\" timestamp=\"0x3f9af1e8\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4412\" file=\"ntoskrnl.exe\" hash=\"ec24a158e0b3718f61d8c72929b28942dcb98f14456a793d8f073edf710edf94\" timestamp=\"0x43dcc063\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4412\" file=\"lxcore.sys\" hash=\"3ac86b9857ddcde8d080899c6fd4e15255306eafb7785f2d7c994cc15725be65\" timestamp=\"0xb6316cbf\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4474\" file=\"ntoskrnl.exe\" hash=\"fb1992c1a8a261f7b8b22db440e7a83e7da93edb54fcb7a793b0811a28ab16a0\" timestamp=\"0x0189f7da\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4474\" file=\"lxcore.sys\" hash=\"6ed59743ea0fe432aa93447fba7f7515f160c9021e3f7ff5b4b1b08c50e0a128\" timestamp=\"0x2119cc4a\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4522\" file=\"ntoskrnl.exe\" hash=\"ed3ee85207fa922f27ce98a45bc6a43903ff6d5abf00842c235ba5133bb821a9\" timestamp=\"0x3b601e8b\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4597\" file=\"ntoskrnl.exe\" hash=\"7cbd4aabe9b9b3a7161c36a2a2664634fb6c9e2eb687db1a1e24a215f298d636\" timestamp=\"0x1d1cf9ca\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4597\" file=\"lxcore.sys\" hash=\"ee601b82869bff52377744037460b7429d1636e90bbeef02588431ca04638c16\" timestamp=\"0x77bd2d9e\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4648\" file=\"ntoskrnl.exe\" hash=\"f9d6f9e502e796cc0c905de8b37cc289f589c1178da07ba7823f7ca1747104fe\" timestamp=\"0x76a3e45b\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4648\" file=\"lxcore.sys\" hash=\"b8be00606dd908f9e3254c4b9a5de80c0267dddb92c42014dee51a1152689ad7\" timestamp=\"0xe39de069\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4717\" file=\"ntoskrnl.exe\" hash=\"645a97b77e9b01a5d81d555fb6899bf98430d674624a9a2467bf33cbc76fe504\" timestamp=\"0x1d53ee48\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4717\" file=\"lxcore.sys\" hash=\"99a780cfc249ce491c52e757bba3c34f1634f7dab0eb6994e8020adf9ffc9220\" timestamp=\"0x826ad979\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4780\" file=\"ntoskrnl.exe\" hash=\"e0f85a4e0fec08eff0264342088732e18429d30b12263134e446f200108ec728\" timestamp=\"0xf6e3331c\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4780\" file=\"lxcore.sys\" hash=\"c6849e1c7d9d6fdb8f063b2a4fadcff875d748c5d2cab06f1652185ac9fa368e\" timestamp=\"0xfe5045e9\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4842\" file=\"ntoskrnl.exe\" hash=\"716b2ce68a22dc2e6d87e14338b63437fef1fb72b88c0f7c79ee962c3acbc80b\" timestamp=\"0xe5908e1d\" size=\"0x0143d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4842\" file=\"lxcore.sys\" hash=\"1c0e2de6e8aab8876facc31d6303726bc0a0dba0fc99b4d72c6802eb27b16db8\" timestamp=\"0x23c034fb\" size=\"0x00115000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4894\" file=\"ntoskrnl.exe\" hash=\"b0352c4710eba5b332d872dc955567eadc4c18a0c3468cae32e5b025e36e42d1\" timestamp=\"0xb8e3b39a\" size=\"0x0143d000\" added=\"2024-09-24T23:22:06Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4894\" file=\"lxcore.sys\" hash=\"8878c270b766fb11625484f8638c2d47bccc4bc0aed45a0fab52c94202e55c31\" timestamp=\"0x28c04f5f\" size=\"0x00115000\" added=\"2024-09-24T23:22:06Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4957\" file=\"ntoskrnl.exe\" hash=\"3978fe2f2fe0caae015a41eea341ab17cc4e3f0b364b1cec4122ab18fb551e1a\" timestamp=\"0x31c9fba6\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.4957\" file=\"lxcore.sys\" hash=\"c0d483428a0b90a9bf78a06e5714de632381e27feb683a210ca0c394613c98c1\" timestamp=\"0x2814ab45\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5007\" file=\"ntoskrnl.exe\" hash=\"548ef0c1714e27b7a93f164d7761f6152df60fc69cf8a82960db455a5c9aefdf\" timestamp=\"0xa35d5e30\" size=\"0x0143d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5007\" file=\"lxcore.sys\" hash=\"ec87ddcb52be9610b902b6be81522382c0ce24601aeebb3afc538f7976bd573a\" timestamp=\"0x56c08cdf\" size=\"0x00115000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5072\" file=\"ntoskrnl.exe\" hash=\"a52316c482ea221796aafb3d88ee838682fc4d8a435957cd2442c6302f9430d9\" timestamp=\"0x24b056b8\" size=\"0x0143d000\" added=\"2024-10-26T06:39:10Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5072\" file=\"lxcore.sys\" hash=\"64d07e5c1ea49318bd3041b69a0e3dfc08a8ac393e2c2455cc46cb86a53c9d2a\" timestamp=\"0x583e5ef1\" size=\"0x00115000\" added=\"2024-10-26T06:39:10Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5129\" file=\"ntoskrnl.exe\" hash=\"235353f4420391cc50aa300141aa81a0c6de7628b466c63c598ad7a0c501f7e7\" timestamp=\"0x8287c1a6\" size=\"0x0143d000\" added=\"2024-11-13T15:20:35Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5198\" file=\"ntoskrnl.exe\" hash=\"00a899925e2c365ce1fbc43cb675ec7d24faccf8b93f3f981ccff02dae1b9609\" timestamp=\"0xd5f09743\" size=\"0x0143d000\" added=\"2024-11-22T17:11:50Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5198\" file=\"lxcore.sys\" hash=\"00b658ef1a4d6d247f8b14dbe2987ee6e9a9e5e6f5be5e470f77ba563928d8ab\" timestamp=\"0xe12fda8a\" size=\"0x00115000\" added=\"2024-11-22T17:11:50Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5247\" file=\"ntoskrnl.exe\" hash=\"c70e6030ba79844d721e3ec1ec1b745c19a55cc7450f323a1d2a8039124979c2\" timestamp=\"0x63972586\" size=\"0x0143d000\" added=\"2024-12-11T14:53:46Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5369\" file=\"ntoskrnl.exe\" hash=\"5c05530727fb3fc18ab843804337081c9eacef5b97a486841445cb8a71e42118\" timestamp=\"0x59f802a4\" size=\"0x0143d000\" added=\"2025-01-15T01:55:10Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5369\" file=\"lxcore.sys\" hash=\"0fea36ef1a7c7db81e183b04bdf880ad9e123e5a104065f27b80042d2d384a88\" timestamp=\"0x21c2d495\" size=\"0x00115000\" added=\"2025-01-15T01:55:10Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5440\" file=\"ntoskrnl.exe\" hash=\"a2faff6079d66d9afeb21cd8403081889d5c504f1662b0afc32212f1de4af6d4\" timestamp=\"0xe4cc52a7\" size=\"0x0143d000\" added=\"2025-01-31T00:35:18Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5440\" file=\"lxcore.sys\" hash=\"b0b2bb29dc4de0b07f28d11a82470115cebcfb07d838f89105f024b42123c1a0\" timestamp=\"0xd35ace91\" size=\"0x00115000\" added=\"2025-01-31T00:35:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5486\" file=\"ntoskrnl.exe\" hash=\"b906a221b3b835d54acd911460a952cd09070782c0609e257f4261ad6a1fb998\" timestamp=\"0x5c802b57\" size=\"0x0143d000\" added=\"2025-02-12T06:18:33Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5553\" file=\"ntoskrnl.exe\" hash=\"cb5cb3bb008ad68ec913bdc92cc154de8c7265fab5bae84db06c13489770e376\" timestamp=\"0x5afe60f8\" size=\"0x0143d000\" added=\"2025-02-26T02:04:23Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5553\" file=\"lxcore.sys\" hash=\"bae7640caa266527555dff8cfc693be1b1be45332ece578f95b439c1cd199f1b\" timestamp=\"0xc8f34c32\" size=\"0x00115000\" added=\"2025-02-26T02:04:23Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5607\" file=\"ntoskrnl.exe\" hash=\"924c560db3522a7e3b9bc583481b903b8cb1e2a2f1e65f28fc09c8c0f88c4583\" timestamp=\"0xb54253e0\" size=\"0x0143d000\" added=\"2025-03-11T22:25:17Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5607\" file=\"lxcore.sys\" hash=\"ee3f7a0be4e4780a149fb7346413c30c071d6e9e09b01e2e07f3830feb26c369\" timestamp=\"0x5bf2e0b1\" size=\"0x00115000\" added=\"2025-03-11T22:25:17Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5678\" file=\"ntoskrnl.exe\" hash=\"36e4ebdb1911a9516253f913b482b5c5b2113538bd834ee4579681e444fa589a\" timestamp=\"0x85c394b4\" size=\"0x0143d000\" added=\"2025-03-28T03:59:19Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5678\" file=\"lxcore.sys\" hash=\"d92f446543e4186770568f8393f2b8ca8ea121b64e53fd140b397e6fb8c91b09\" timestamp=\"0x0e5f57a4\" size=\"0x00115000\" added=\"2025-03-28T03:59:19Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5737\" file=\"ntoskrnl.exe\" hash=\"16b93f91f483a5106b38a2401a3fc6b8c0ab74dd479bf0726dd828d44195c722\" timestamp=\"0x10dd7b16\" size=\"0x0143d000\" added=\"2025-04-09T14:22:28Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5737\" file=\"lxcore.sys\" hash=\"582c80e358ffd9b3854764a94dd8a79d52afec24218bf717b432d47f8ed1e4ea\" timestamp=\"0xed1f3eb5\" size=\"0x00115000\" added=\"2025-04-09T14:22:28Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5794\" file=\"ntoskrnl.exe\" hash=\"3d42c1b4e7c21f88f8b21a521832b8344138e4eb42eb09bda4c276fa0592e628\" timestamp=\"0xcfd90a82\" size=\"0x0143d000\" added=\"2025-04-23T00:45:13Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5794\" file=\"lxcore.sys\" hash=\"408c6c5fdca461f9a298b794ed2fa8c9a667772656cc8d2e78c93d2afe046648\" timestamp=\"0xcb292f37\" size=\"0x00115000\" added=\"2025-04-23T00:45:13Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5848\" file=\"ntoskrnl.exe\" hash=\"71925d59b09dc4374a8446e8d6c4e341f5119ffe469901cf8551d4135d3faaf4\" timestamp=\"0x0054d9a2\" size=\"0x0143d000\" added=\"2025-05-13T22:56:23Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5848\" file=\"lxcore.sys\" hash=\"639df05dc042d79ddf904f844dc1a5199c4cfc18205c3e1eb4dd07e087800750\" timestamp=\"0x02412437\" size=\"0x00115000\" added=\"2025-05-13T22:56:23Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5856\" file=\"ntoskrnl.exe\" hash=\"c4f7013b3bc66101c982457f47d66aba2279db02f95eedfd291a3708d26923af\" timestamp=\"0x64673f52\" size=\"0x0143d000\" added=\"2025-05-22T02:15:04Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5915\" file=\"ntoskrnl.exe\" hash=\"31919723fe2d954cc66854885392815da489d87f360215efa370936afa337681\" timestamp=\"0xcdeaec82\" size=\"0x0143d000\" added=\"2025-05-30T19:55:37Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5915\" file=\"lxcore.sys\" hash=\"22416bb66f6d4d3954c492d7a87db280ada3abe352daaa645de9fea436c9decd\" timestamp=\"0xb95935a1\" size=\"0x00115000\" added=\"2025-05-30T19:55:37Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5965\" file=\"ntoskrnl.exe\" hash=\"33a47fdc20d4e3ef1a5238677756be585e0ed56d303f30f4fbd10409426c786c\" timestamp=\"0x99aa9896\" size=\"0x0143d000\" added=\"2025-06-11T00:42:44Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.5965\" file=\"lxcore.sys\" hash=\"c441b28c1de83fc8bca29fda2a6bc321bb7fb3f8ee6ced317bb14caf743ab021\" timestamp=\"0x3d9ea885\" size=\"0x00115000\" added=\"2025-06-11T00:42:44Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6033\" file=\"ntoskrnl.exe\" hash=\"288183505178712c52fa0de077740366ffee4b6e807b302d18ef411b18ffffd9\" timestamp=\"0x65b573bd\" size=\"0x0143d000\" added=\"2025-06-24T22:12:14Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6093\" file=\"ntoskrnl.exe\" hash=\"3933772a7f198569fc518409f1351090fb46a8a45cfbd33f1de4844392a3cb4f\" timestamp=\"0x1573bd4d\" size=\"0x0143d000\" added=\"2025-07-08T22:13:00Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6094\" file=\"ntoskrnl.exe\" hash=\"9e50552498073677cd88d94097ba574dd7f49cfba12221f51d6d428336f5e1ec\" timestamp=\"0x6e1a70ea\" size=\"0x0143d000\" added=\"2025-07-10T01:24:18Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6157\" file=\"ntoskrnl.exe\" hash=\"8ac61c173bd3f7ce80f00a596516303c037a203cebc44762666a6268a3421faf\" timestamp=\"0x3e73ec9b\" size=\"0x0143d000\" added=\"2025-07-24T05:27:30Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6216\" file=\"ntoskrnl.exe\" hash=\"2037b4652a3547215291982d2e24deaab7e64257f89fee4063debf3368e52ac9\" timestamp=\"0x517b4cd4\" size=\"0x0143d000\" added=\"2025-08-13T21:37:12Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6218\" file=\"ntoskrnl.exe\" hash=\"4af68dabc2a5a166e70b0603fcd3877ba11b94eef2217c12db538c4e91890f84\" timestamp=\"0xc36a3c69\" size=\"0x0143d000\" added=\"2025-08-21T15:11:13Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6280\" file=\"ntoskrnl.exe\" hash=\"47b7230291b72d663612ba95139289f04a95ad2a32d468deb08a947da5a05f02\" timestamp=\"0x37d61647\" size=\"0x0143d000\" added=\"2025-08-27T04:03:40Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6328\" file=\"ntoskrnl.exe\" hash=\"6449589e382d8f1bd65dd7f66b4dcdad397a3dcc0ed0837ea9b9884359a22dfe\" timestamp=\"0xde11b7be\" size=\"0x0143d000\" added=\"2025-09-11T03:22:38Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6392\" file=\"ntoskrnl.exe\" hash=\"3ba0e81b1849e5b43a1ac92351b56676f1c40e5d5562cc46196167f6f2a8cb8a\" timestamp=\"0xd3593843\" size=\"0x0143d000\" added=\"2025-09-27T02:00:45Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6455\" file=\"ntoskrnl.exe\" hash=\"b883c0c8ac815c4bd372654e01b2cc37b9e2f1489b0b5cc7df035665e00d546c\" timestamp=\"0x457cf930\" size=\"0x0143d000\" added=\"2025-10-16T23:37:47Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6456\" file=\"ntoskrnl.exe\" hash=\"854b1226ce786f8a2eb4a6552817b67c5f3747629de76c54e36265fff703beba\" timestamp=\"0x82a6ae47\" size=\"0x0143d000\" added=\"2025-10-16T23:37:47Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6566\" file=\"ntoskrnl.exe\" hash=\"382870253aeca7ef279949358fb8373b3d2562fd03e063f11e7daa51c6ad33c7\" timestamp=\"0xd0da0dfe\" size=\"0x0143d000\" added=\"2025-11-12T23:55:08Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6575\" file=\"ntoskrnl.exe\" hash=\"e3cc63675061d280c2f9c610a2ff3fd238a0e08a3f474bff2b1044d5fb182842\" timestamp=\"0x4c39b3f9\" size=\"0x0143d000\" added=\"2025-11-12T23:55:08Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6683\" file=\"ntoskrnl.exe\" hash=\"b84f8b32eee2bd4765d934096b6760cc77b4f76ccd1edf5d0a560f2dea01ad47\" timestamp=\"0xea311255\" size=\"0x0143d000\" added=\"2025-12-10T04:39:55Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6691\" file=\"ntoskrnl.exe\" hash=\"8f13d80b98b5beb4cec11bf51d2eb1180cc05ad518870058d884ad4441016d72\" timestamp=\"0x3a257aa6\" size=\"0x0143d000\" added=\"2025-12-10T04:39:55Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6693\" file=\"ntoskrnl.exe\" hash=\"7d1ca5dcb77fc32e0ab8f7090da1f08436e31d79db027e13807269c33ff6fa21\" timestamp=\"0xfb9762ab\" size=\"0x0143d000\" added=\"2025-12-24T02:56:52Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6807\" file=\"ntoskrnl.exe\" hash=\"f8b2e41d01f95d6acfe84e92cae5bd0e392f9055e8466c33f752c10c68e743bd\" timestamp=\"0x342fe4b2\" size=\"0x0143d000\" added=\"2026-01-15T04:51:11Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6811\" file=\"ntoskrnl.exe\" hash=\"09e6b5390682787b49f8baed2a23b1a5258683c8823594b59398b4fb75d2fd3e\" timestamp=\"0x628ef6e7\" size=\"0x0143d000\" added=\"2026-01-22T02:43:17Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.6926\" file=\"ntoskrnl.exe\" hash=\"e8316712f60806bd28891343a08c27e32c3796bcf6db5bde2f736fa535220b74\" timestamp=\"0x4a67e44b\" size=\"0x0143d000\" added=\"2026-02-11T00:54:58Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19041.7058\" file=\"ntoskrnl.exe\" hash=\"ac0ce416d3d4aa27ca732a446c986bfe05fad9fc6321b940013c417878d72eba\" timestamp=\"0xccc68e49\" size=\"0x0143d000\" added=\"2026-03-19T02:51:26Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.19577.1000\" file=\"ntoskrnl.exe\" hash=\"f048287988997969110f78de4de0ca56626fe555611ca8973f2d41858a044292\" timestamp=\"0x8cbff949\" size=\"0x0143e000\" added=\"2025-04-26T20:45:50Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.21277.1000\" file=\"ntoskrnl.exe\" hash=\"aae6a6e6c835b94b4f7d29b3b1f0950b26d328dddb0023241d2d11cfd8941566\" timestamp=\"0x206d1541\" size=\"0x0143e000\" added=\"2024-11-22T17:11:50Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.21286.1000\" file=\"ntoskrnl.exe\" hash=\"86d6424990358ddf66ea719b70e00ae2494fa2e6326c0fe42a72ece2ef22bc1f\" timestamp=\"0x6b4b0756\" size=\"0x0143d000\" added=\"2026-01-23T20:47:18Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.21354.1\" file=\"ntoskrnl.exe\" hash=\"84156b1e198303e8751d8c97bb3e292c3ae1012ac5365685f5c254266a478b41\" timestamp=\"0x40898666\" size=\"0x0103d000\" added=\"2024-10-26T06:39:10Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.21376.1\" file=\"ntoskrnl.exe\" hash=\"81b12d9fa549e80435cbab882c0dbe097888511989ba0576c331dd50553028dd\" timestamp=\"0x33f946e1\" size=\"0x0103d000\" added=\"2025-09-11T03:22:38Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.21390.1\" file=\"ntoskrnl.exe\" hash=\"1ffc0e18d7f0cd2ff4e8988900b9296a891461480fc6261013b25ff030cb6512\" timestamp=\"0x49ab4579\" size=\"0x0103d000\" added=\"2025-01-16T23:14:03Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.21390.2025\" file=\"ntoskrnl.exe\" hash=\"2277fe6fe2855cb22b0ef8c0af8b14137a8ce1b4e7b6dc36674dfa9b921de938\" timestamp=\"0x3ff6fc22\" size=\"0x0103d000\" added=\"2025-09-21T13:49:59Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1\" file=\"ntoskrnl.exe\" hash=\"743de2a8da36d3aaa07149d87cfcb1f2bcc1d90446ca806c15753fb6af1114ec\" timestamp=\"0x67749299\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1\" file=\"lxcore.sys\" hash=\"f86a468846ac56b113203294f290b2402cb9e2a8832f71481b1994996154695c\" timestamp=\"0xefe214e0\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22000.120\" file=\"lxcore.sys\" hash=\"22d4adc5be2e75b1e53668c28974e2a5f6430e48a0c2f320c4ef4e6a39497e0d\" timestamp=\"0x8c3f59b1\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22000.258\" file=\"ntoskrnl.exe\" hash=\"1d6fe3fa27aa9856b44bbedeb566bc3500d52abd4a7c401e358cdc2a21b6ea9e\" timestamp=\"0x0e68ceff\" size=\"0x0103e000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.282\" file=\"ntoskrnl.exe\" hash=\"77854442a8282c13141983391304d552049a0543d34d613fb7fedc517b82840c\" timestamp=\"0x01d61026\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.318\" file=\"ntoskrnl.exe\" hash=\"9590bad7cbef4ac541991896c3388445cbb3ac314d27fdeba07c5c8a34c43d98\" timestamp=\"0x80f71cc6\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.348\" file=\"ntoskrnl.exe\" hash=\"20c34e2bd1309fd5739f23651255240dfcd81e92ee8d55ebae46a0ba879706f7\" timestamp=\"0x4a247f55\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.376\" file=\"ntoskrnl.exe\" hash=\"9e7aea8e810d23f1d36d90f271424c6c2e67096ec4f8bd9c3880acc6dd0909d4\" timestamp=\"0x3d3944ab\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.434\" file=\"ntoskrnl.exe\" hash=\"7f5caa2f1277335c3b8ae346c7dc635cfbe3ffb1c1fc641c12d8a4a1704160a1\" timestamp=\"0x296d9d41\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.438\" file=\"ntoskrnl.exe\" hash=\"5a89b1cbdab820f7a331d269475f6a04bf2d461882c34ae120860255c48b2b10\" timestamp=\"0x129d85b9\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.469\" file=\"ntoskrnl.exe\" hash=\"7f2b09f8c1a1845d6b8dd0173add07864f632cc0a76377c39e08b90bc69c730f\" timestamp=\"0xe6e2dc29\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.493\" file=\"ntoskrnl.exe\" hash=\"a40b8aab8ef61d81dc521d0967f618274ba0d9ee30e8ed85fadb7877985592a5\" timestamp=\"0x7a37d0ba\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.527\" file=\"ntoskrnl.exe\" hash=\"2e2078551e5eee1280482c980e689304e2d324424f702786496558b364a50fa2\" timestamp=\"0x1b828a81\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22000.556\" file=\"ntoskrnl.exe\" hash=\"7b6174f900681eaed9e66dc3f263982806efbb9409dfcb2349a7ba886e4cacf3\" timestamp=\"0xb3eba6cc\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.593\" file=\"ntoskrnl.exe\" hash=\"b9d659626a9a8c690b068ab55a7e78c5f14973272e5fb48a4a7a4947a990bbcc\" timestamp=\"0x4fdd7775\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.613\" file=\"ntoskrnl.exe\" hash=\"c05ec441ab478059f5c4bef5b0e79010483b3ee22764522d368cfc547d0c8b9e\" timestamp=\"0xfa19b6a2\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.652\" file=\"ntoskrnl.exe\" hash=\"cbd1cfaaf0748d7cb6577db21ef57b3debb29af7fad29c23435c69893656b961\" timestamp=\"0xb5750b56\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.652\" file=\"lxcore.sys\" hash=\"67e91cd01001b419f3f46d11be7fcd8c388d4842c6cb3b9388f211d06999647f\" timestamp=\"0x66c2a4b9\" size=\"0x00112000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22000.675\" file=\"ntoskrnl.exe\" hash=\"5c7f71c5c8a299a62e1c9a9c99a8afbdb9567231113742d6d984033362060485\" timestamp=\"0x0bc95ece\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.708\" file=\"ntoskrnl.exe\" hash=\"dc742dbd371c71623a00de05579cec591126a5653b7bc86679a7464a5762a3db\" timestamp=\"0x4244ed6d\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.708\" file=\"lxcore.sys\" hash=\"96f4489531581c7b641e0cff2ed99c8aae270792d93e135cf4859cbf96a8ed94\" timestamp=\"0x80683897\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22000.739\" file=\"ntoskrnl.exe\" hash=\"c541ada0cd685e6d7ddbd4e8818dde33546105d999710bb9d614b2334d12e0bb\" timestamp=\"0xbced563d\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.740\" file=\"ntoskrnl.exe\" hash=\"5b114faa41c436cde5aaf17cb107291af331041ec795815915973cbff26a9c1b\" timestamp=\"0x7623bed0\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.778\" file=\"ntoskrnl.exe\" hash=\"3704c38d64975b00126da723339588de713699a730a3b48189cce84315e17100\" timestamp=\"0x3b0b2da7\" size=\"0x0103e000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.795\" file=\"ntoskrnl.exe\" hash=\"13759107db6dc83f00b54dd3969c1f6d39ef198b0baadb2494b160033d6e1953\" timestamp=\"0xd28c903f\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.832\" file=\"ntoskrnl.exe\" hash=\"29d79ea8393295382dc43d3c960834dcbf06c85b4244bbf04d5cdb9abefbcb73\" timestamp=\"0x7816a7b8\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.832\" file=\"lxcore.sys\" hash=\"d9f1cd01428da28127b636940f1dc42cdded42f86fdd9e5f3fc04421db1a522f\" timestamp=\"0x1ac76750\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22000.856\" file=\"ntoskrnl.exe\" hash=\"c0c17cde5528b232e70be38b0d31fa004052645ab27389985236c3888b5eac46\" timestamp=\"0xed9c01f5\" size=\"0x0103e000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.918\" file=\"ntoskrnl.exe\" hash=\"9d970e833925ccb4f931a878657b1655772225e24f42c6c53c418c9ea414517e\" timestamp=\"0x2d1e165e\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.978\" file=\"ntoskrnl.exe\" hash=\"1c191f33c0bb6cf7a6937782e42867ea5c31dd8bde5a072b1c25f826b4eedf65\" timestamp=\"0xd87e89fd\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1042\" file=\"ntoskrnl.exe\" hash=\"a770d528de9efee2f430e4318d679e1507e0fd269eba65560be850dbad7e1120\" timestamp=\"0x42b6cd38\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1098\" file=\"ntoskrnl.exe\" hash=\"aaffd5c4969d1705fb43837fb0a9025e09d170dfd4b1298ae6fced4562d00a58\" timestamp=\"0xb3057132\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1165\" file=\"ntoskrnl.exe\" hash=\"6b4549776dd1c1e4e5305578b80aea864c4eededcdd21a1ce41f51c139f00127\" timestamp=\"0xd7906e11\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1219\" file=\"ntoskrnl.exe\" hash=\"9c06205acea95ef6b3933b1c3091a838fc0f1b302c13102ee3aa36f5d75a354b\" timestamp=\"0x8dfa5576\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1281\" file=\"ntoskrnl.exe\" hash=\"0f7d858c5c9971497d4f8238440542cc14659f6750e3949577762c3bb8e3f962\" timestamp=\"0xdee8a33a\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1281\" file=\"lxcore.sys\" hash=\"62174c93db7d40a6e6aa106207124f4d9cc4aa843ad5b60ad12d176a922937f5\" timestamp=\"0xb80cdc98\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1335\" file=\"ntoskrnl.exe\" hash=\"8d05c35620292ca32e5c7a0aa2d38bf077333bc7f15bd43aca31dc79e7c23ce4\" timestamp=\"0xd900fe28\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1455\" file=\"ntoskrnl.exe\" hash=\"f07aee7aad2516a9cc7701d279529529e9242a4017d17709661d98a2f7f3900b\" timestamp=\"0xe796a388\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1516\" file=\"ntoskrnl.exe\" hash=\"9a46f65608112d683243cf069be8d7c9ff6091ceb8fd42016fed22446027fdb7\" timestamp=\"0x07ca6ae9\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1574\" file=\"ntoskrnl.exe\" hash=\"74a21c823c345bf9ee05a22ce1c5300694983eb793b572a5449a217513d601db\" timestamp=\"0x47d7322f\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1641\" file=\"ntoskrnl.exe\" hash=\"a7c4004810e3df6a9634ea07bb4f1c3896114d2c701317aed22e36e141845bc8\" timestamp=\"0x8dce1855\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1696\" file=\"ntoskrnl.exe\" hash=\"41a47ff20adb1eb0d8f04b066dfa720117cab1858a30aa29d5b52c28bfce9772\" timestamp=\"0xb682078d\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1761\" file=\"ntoskrnl.exe\" hash=\"4e1abc91dfd858b4fa6b28a07609cbf45375b5bdf17c0370d3d1b594c38064a6\" timestamp=\"0x824eedc7\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1817\" file=\"ntoskrnl.exe\" hash=\"83afb8dc078ff76ea9a1e07c73291f12ad26cb9baadf8c2c173438f987e79e44\" timestamp=\"0x70e6d882\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1880\" file=\"ntoskrnl.exe\" hash=\"d6fe2778c270cfde9d55855c436e3f4490ca3ed4a3f12bf4d1e1b9fd32bef5bd\" timestamp=\"0xc014c5c6\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.1936\" file=\"ntoskrnl.exe\" hash=\"85d6f49b415c31d77fc979f38ae5e8ee627d3229cbb60a678efad720d6020b09\" timestamp=\"0x3b525bd8\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2003\" file=\"ntoskrnl.exe\" hash=\"1855f093e58182df33acd8ff20eaaff8d417da2f25f3f789015ad93139eeca86\" timestamp=\"0x903b7b8b\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2057\" file=\"ntoskrnl.exe\" hash=\"6b365591945eca645d8984a808b0371c77d1c5dc8c4bd84afaa31eba3b8d73d3\" timestamp=\"0xa4836745\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2124\" file=\"ntoskrnl.exe\" hash=\"24e57eb915ca6ed042cd7fe4421833cd2b7e88d87241bca70f21e14b3f1e88fd\" timestamp=\"0xf3131e31\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2176\" file=\"ntoskrnl.exe\" hash=\"1bf5a17cf014a0e9652ec1fcfa0cff36d96430bb2c68e6d0e6124c22e5b6c5e4\" timestamp=\"0xfc301675\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2245\" file=\"ntoskrnl.exe\" hash=\"c19a23be22c6c99284a0eab06b3d039a3e443d63194723fd5e4b574fbd64c23d\" timestamp=\"0xf8a687b6\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2295\" file=\"ntoskrnl.exe\" hash=\"2e67659d08d577434b12d97c6607af9d87aa58aa6bd2c86994b878d2de2b25e5\" timestamp=\"0x1042a1a6\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2360\" file=\"ntoskrnl.exe\" hash=\"97b463487b0f4571a34524d45fb5a402a9fec0b7aec0ad9535e927fc5db61284\" timestamp=\"0x84286b20\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2360\" file=\"lxcore.sys\" hash=\"6fd7c4b40a6582ec4cc3b61b508cb300def89bcd8bb49864e2df2c4a57fc8d43\" timestamp=\"0xddde0bca\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2416\" file=\"ntoskrnl.exe\" hash=\"0c8ed0e039a7bc488a8e9199a49e71e129be576fc26dd7c472360f8a2ff21bc0\" timestamp=\"0xba2e2f29\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2482\" file=\"ntoskrnl.exe\" hash=\"5009cf9dbfd7115cc1776f040011f66aa45bc73c4d0be0ed4b6cd7ae95c3736b\" timestamp=\"0x89aacca6\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2531\" file=\"ntoskrnl.exe\" hash=\"5fe09efd99efa6e5152384b6262f3c10ac1947619031707029d2bfb6421d395f\" timestamp=\"0x184bcc03\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2538\" file=\"ntoskrnl.exe\" hash=\"9ef40610528e463f714d0d034334da7fc8c735d5e0abbdb5ab0c687145115b6b\" timestamp=\"0x86081fec\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2600\" file=\"ntoskrnl.exe\" hash=\"fdfeb6cd539c0d6e2b328a335de05e9ef43fd769a52dcccbb70480ba503599f3\" timestamp=\"0x30be15bb\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2600\" file=\"lxcore.sys\" hash=\"36727a518fc64b4c4eb98afbd6ad9c738fdcdd36dcc593eaf567916bef7571c4\" timestamp=\"0xd68a4504\" size=\"0x00112000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2652\" file=\"ntoskrnl.exe\" hash=\"d1724d52866eb815492c156ee81095e83afed5d11221be31174ab1bdf0008928\" timestamp=\"0x2f083e6f\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2713\" file=\"ntoskrnl.exe\" hash=\"248dbdd284f99d520daeeb861f0a1cc7771f2f5c141715c6b5882cc9fb42e10c\" timestamp=\"0xb5ac7566\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2777\" file=\"ntoskrnl.exe\" hash=\"d16584c40dd1fdd9ff886582187013bd48a3540c29ce8b73fcfb178400d4de0e\" timestamp=\"0x88b9c933\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2836\" file=\"ntoskrnl.exe\" hash=\"6c81ea17d8956dcc9320da23957fa83b252831020a1c10893260fb622e45a7a8\" timestamp=\"0x6f9a46f9\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2899\" file=\"ntoskrnl.exe\" hash=\"81af3223c7874e155fa2e0eb0084f34c8173d2d16357ede8cd8354053584d745\" timestamp=\"0x7c1807f7\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.2960\" file=\"ntoskrnl.exe\" hash=\"00d341db32f214f04ee7e1a210cd1abd8b8710e6c30b1d87c650c89f97a5b302\" timestamp=\"0x76f415d7\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.3019\" file=\"ntoskrnl.exe\" hash=\"c24bf9c2d830a3e452118771b14f4c6780ceabb0daa0ab93dac1ed4f3fb4b6bd\" timestamp=\"0x2321a6fe\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.3079\" file=\"ntoskrnl.exe\" hash=\"9cab11e09373113bbcccb1b2189fdbb2752aeb64800c90f10f602ccc91272a3e\" timestamp=\"0x7c063ed8\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.3147\" file=\"ntoskrnl.exe\" hash=\"9c6370e0d19d865831a7c6a03d190b3369f1247d5bc865764b9895805722155b\" timestamp=\"0x0633d17b\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.3197\" file=\"ntoskrnl.exe\" hash=\"6afe8350f17f46a23705af22818c69c078302bd27c003bdf9e62c3f5af353c7b\" timestamp=\"0xb9efa852\" size=\"0x0103d000\" added=\"2024-09-24T23:22:06Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22000.3260\" file=\"ntoskrnl.exe\" hash=\"594e5a166ed4c8cd2df85676d8e1a8c861b15fca985dd1ce3c59f8fafc8bd62a\" timestamp=\"0x04154425\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22454.1000\" file=\"ntoskrnl.exe\" hash=\"a82f824c4ebb5822ce4915ebd9bab65cd672f1d57b20d540dc4906c1559a4ed6\" timestamp=\"0x35875648\" size=\"0x0103d000\" added=\"2024-11-13T15:20:35Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22533.1001\" file=\"ntoskrnl.exe\" hash=\"14956ed8d0ec2a3055010ffc49bf428459f50d8b643352ef667ac779c015df1c\" timestamp=\"0xcd1049cd\" size=\"0x0103d000\" added=\"2025-04-17T02:01:01Z\">20</data>\n    <data arch=\"arm64\" version=\"10.0.22598.1\" file=\"ntoskrnl.exe\" hash=\"41b637030e0b50c794b03880e6935bd43912ca88889be7694eb18eeb939ff182\" timestamp=\"0xad0f4c79\" size=\"0x0103d000\" added=\"2024-10-29T02:19:33Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1\" file=\"ntoskrnl.exe\" hash=\"7bcfe0a8e3147fafa357eb7f19c9b7d45b4edb6a75b905be1e639eea382b551f\" timestamp=\"0x86959503\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1\" file=\"lxcore.sys\" hash=\"df8d493e689d1a54ede61488ef205de8c3565c238ae7079a539b0752b18d2602\" timestamp=\"0x9cab9a16\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.317\" file=\"lxcore.sys\" hash=\"629cd2c006cb22071bf002cb5a525bf90e9765aa54392f36caa0393aaafd3645\" timestamp=\"0x1a1b813d\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.382\" file=\"ntoskrnl.exe\" hash=\"e426c383ad316e22c487ba0feeaa55837fa9f9564f904c23784da9a82551803e\" timestamp=\"0x468622b1\" size=\"0x0103d000\" added=\"2025-06-24T22:12:14Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.525\" file=\"ntoskrnl.exe\" hash=\"7c357da8f62a93bd71e2f4c79eb8cedb396f61d78144def95c2eb4db435904b0\" timestamp=\"0x6aacf7da\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.608\" file=\"ntoskrnl.exe\" hash=\"1a894a46bc42d5cbffcaf5bb316f5a5e2212fb22401acc415d2739d14327512e\" timestamp=\"0x48797e01\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.608\" file=\"lxcore.sys\" hash=\"2b60d402c993247e9d67cd4954033496028540b700e10baaed5c9288929a58a3\" timestamp=\"0x737103c6\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.674\" file=\"ntoskrnl.exe\" hash=\"fedb6ea80c80a94131d78797556099d2062de6d340db45b00a721b0bf513fce8\" timestamp=\"0x3b7fe824\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.675\" file=\"ntoskrnl.exe\" hash=\"c400295d474122a3d1716f6dcd93c83779493aba83cc88a5b43ffd149ebb568e\" timestamp=\"0x35e527f1\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.755\" file=\"ntoskrnl.exe\" hash=\"42ef05e692e1e6b34eb19f008d05a090216bbe717e211ec52ba37d0766eff1a5\" timestamp=\"0x3d416a3c\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.819\" file=\"ntoskrnl.exe\" hash=\"45bc62b20ea7e85de546e1f7659cbd7c7b65160563e81f0c720f75002d5bcb9c\" timestamp=\"0xb25651bc\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.900\" file=\"ntoskrnl.exe\" hash=\"7b08450fdcffb466d13e0fc949c87c9a2428d356b57e89a7d6da631d66756a4f\" timestamp=\"0x8fe3d48b\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.900\" file=\"lxcore.sys\" hash=\"cd92a75eaaaa40241da9cdbd80d450cb3bb27bfa8aaf2564311417f6c1b6e154\" timestamp=\"0x0ee2277d\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.963\" file=\"ntoskrnl.exe\" hash=\"a4d7f709fa014988082b93554894cb92e6606e03b2fe6290a7f88e64de554a22\" timestamp=\"0xebbdfd4b\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1020\" file=\"lxcore.sys\" hash=\"c4d4ae38e2db736eaa01394300607fc2cf3203ad5dcf23e6d0085234326bd0ef\" timestamp=\"0x7cc80670\" size=\"0x0010f000\" added=\"2025-01-04T05:49:38Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1028\" file=\"ntoskrnl.exe\" hash=\"e194a6745ae8dba18157f7c5528e958ec852ed36ca9f1987448bc83cbe7f4b79\" timestamp=\"0x71714bde\" size=\"0x0103d000\" added=\"2025-02-09T01:52:18Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1105\" file=\"ntoskrnl.exe\" hash=\"e3b96b52b2b74be98764af69825ae0cd151ce0f38d9bf2336c752a3ef3b0a039\" timestamp=\"0x64c47e61\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1105\" file=\"lxcore.sys\" hash=\"e03e496fe68bfdfed203dddb77d5662cc5d98e4eb92ddcfa439f24b6ac166043\" timestamp=\"0x14cc8238\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1194\" file=\"ntoskrnl.exe\" hash=\"ea31a7b21bf6627bfac5c823b5ff59c51894ca63ba32862371dd8bbfb1e8902d\" timestamp=\"0xadede567\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1265\" file=\"ntoskrnl.exe\" hash=\"92908243cbb68bb964bbffddb835cdb1d9e7908a60494b8be1842738bc4fe8a7\" timestamp=\"0x0a307f2c\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1344\" file=\"ntoskrnl.exe\" hash=\"46054dcb662bdb7f7549af74a5aea0796ed0ce0864ec50d894f8303caa0525c3\" timestamp=\"0x67fa4c49\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1413\" file=\"ntoskrnl.exe\" hash=\"085c537b8a216b123ff6401533703a23bdfffd8960d9575ee54f61d2f8589fe0\" timestamp=\"0xb4039a0b\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1465\" file=\"ntoskrnl.exe\" hash=\"39d34892f779b30f07bdf4242c9a2519ebbbd690fc0f59f0c529eff504521349\" timestamp=\"0x4344484c\" size=\"0x0103d000\" added=\"2025-01-04T05:49:38Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1485\" file=\"ntoskrnl.exe\" hash=\"8c018c5c4aa689225b93d435e730a7fe03481599a55722b9624d198c7e9bef96\" timestamp=\"0x4ec5191c\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1537\" file=\"ntoskrnl.exe\" hash=\"bd7d38fb43e846d7e474519c1bf754c5d111fd0c5521bdf6511d211e614269e5\" timestamp=\"0x00329699\" size=\"0x0103d000\" added=\"2024-11-09T04:03:18Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1555\" file=\"ntoskrnl.exe\" hash=\"98f4576a4ac28be68ec5b99f063b482f28ee9d86b7e9da8d2cffcde41d705761\" timestamp=\"0x03f5463e\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1635\" file=\"ntoskrnl.exe\" hash=\"1bd4eb811f1d605d2de02582774e67010422a33789d32a5147480cc302a7e151\" timestamp=\"0x85cebf89\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1635\" file=\"lxcore.sys\" hash=\"151c777a30d9bde36e0e5e93d0e41d24ae8288dbffe4709f54a130d56b04ce5e\" timestamp=\"0x4701e7e6\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1702\" file=\"ntoskrnl.exe\" hash=\"0ae43302342243d218e78021bf20cd308eb777d7ec26a9d36a1dd4670d0a1b2a\" timestamp=\"0xc271aee2\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1778\" file=\"ntoskrnl.exe\" hash=\"4f02acee73aeaae3910f12ca3110b89131837c0e50e32d1f96fc0b6f95cdec40\" timestamp=\"0x2cc7b674\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1778\" file=\"lxcore.sys\" hash=\"f0f601b5243be13610c28ccb4e1dbb612494bc03704ffad9bcf573ccea975c3d\" timestamp=\"0x7042f2c0\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1848\" file=\"ntoskrnl.exe\" hash=\"239aadcab6099714176bedb3862a9ffb79132398e10f3c0551c9821762b8fd0a\" timestamp=\"0x74f7013d\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1928\" file=\"ntoskrnl.exe\" hash=\"0ba0da713ae34b1860a579b34656b71d50a5b95ecd3f1dfa106e20919ea4ec97\" timestamp=\"0x5ecbac55\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.1992\" file=\"ntoskrnl.exe\" hash=\"14751ddffdd3ec07ac4c7bcb067e20e132cd618ef8d7a924c5f223c2469acf0f\" timestamp=\"0x69f7d880\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2070\" file=\"ntoskrnl.exe\" hash=\"67c2164c2463e9c9dd1e005bb4a814e2d0dfd955a2e27683db7adc2c32d4f894\" timestamp=\"0x1060d2e3\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2070\" file=\"lxcore.sys\" hash=\"8596f7cbd140a540ce9366da57e5675a40f5f8a1240ca25da210030e5bf76677\" timestamp=\"0xb64c729e\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2134\" file=\"ntoskrnl.exe\" hash=\"0b2e37fe7382c2c4cbd305737c84839b52ba9ccdb1487789e4bf3f9232282b19\" timestamp=\"0x72ffa59a\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2215\" file=\"ntoskrnl.exe\" hash=\"5e599ce9cd86786c47e69e349204bd4f7b2f062aa44e17a0141332bd360f14cc\" timestamp=\"0xab8a59bb\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2215\" file=\"lxcore.sys\" hash=\"aa00b785c8682c88675bb6221503a081a09764d9a26371c0958850ef2359baf6\" timestamp=\"0x9a350f65\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2283\" file=\"ntoskrnl.exe\" hash=\"f75d8834bdff9a37e16d8f9980b814d819ed264c0897120682223c4adfa059ce\" timestamp=\"0x1b7067d7\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2361\" file=\"ntoskrnl.exe\" hash=\"ae980865a7bacf4200e9f386e8671bcd0507c1c697eee0eb0fbd5999ab798158\" timestamp=\"0x1fbeb296\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2361\" file=\"lxcore.sys\" hash=\"54feff256e5d445590138fb067d619f1b03124735be96605fcbf54d477e9c50d\" timestamp=\"0xbe44ad98\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2420\" file=\"ntoskrnl.exe\" hash=\"82668a368735a77c42f5b305e3b0e13139f2d46fb7b124288182844d1abf66eb\" timestamp=\"0x20e3991b\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2428\" file=\"ntoskrnl.exe\" hash=\"b3e83f4a54a09f439b7e51e686dfcfb0273717594bba21fefe8bb05f69f321bc\" timestamp=\"0x7c97a347\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2506\" file=\"ntoskrnl.exe\" hash=\"5fef4789bf6b85289a5152a25f465df546899b3b31f668e2bcbd50ded9f04f89\" timestamp=\"0x2d8ca313\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2506\" file=\"lxcore.sys\" hash=\"2ded486541c29853995f15eccf1ebeab3794fd4b2b3b6e9bd78949ca3e81c789\" timestamp=\"0x96caeb94\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2715\" file=\"ntoskrnl.exe\" hash=\"20660b05b4086af381ca445967149e9ee3abc10638bff3018a2f0b8bf726e08a\" timestamp=\"0xd133e6b5\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2792\" file=\"ntoskrnl.exe\" hash=\"f5423fe3384086128f3231c52e4c995e5f7014b36300476d8e2cf4212d49e4f9\" timestamp=\"0xfc9e692f\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2792\" file=\"lxcore.sys\" hash=\"9f277f4d31e623e0a76a3ae3d04a73cfdd4e264b49ff3be1ae90563d9fd67f94\" timestamp=\"0xafded7d5\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2861\" file=\"ntoskrnl.exe\" hash=\"db84703895bbc9f10771dabc117f7b3d3a7f8bc66d0d3e1918f01983e77e7aad\" timestamp=\"0x65a38c87\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.2915\" file=\"ntoskrnl.exe\" hash=\"f449e4621a6ef83d32cc5b6f8d1ba5d53bf69a7b1f360fe6fee2fa1b89fb9198\" timestamp=\"0x5d8f4e0a\" size=\"0x0103d000\" added=\"2025-08-06T22:20:00Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3007\" file=\"ntoskrnl.exe\" hash=\"689e1391722d445bb2fedca1c13bfe83c6285f8e800ba2d9ebd7df8aac97d486\" timestamp=\"0x440ed35f\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3085\" file=\"ntoskrnl.exe\" hash=\"cdd6e664907b392667038d4f4ed7ce673048689d48e9ad0a9049000d5921309d\" timestamp=\"0x1c2236b4\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3155\" file=\"ntoskrnl.exe\" hash=\"2193ff2925e7ca365914dfc4504c19038cda5f8398591d60b72fd846837e1533\" timestamp=\"0x24cee5e1\" size=\"0x0103d000\" added=\"2024-10-20T15:35:22Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3212\" file=\"lxcore.sys\" hash=\"1ed25fe51e99d269af443c425f931fdc14cdbefbe8357d4ecd6729de32352a12\" timestamp=\"0xf1ff9d5d\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3235\" file=\"ntoskrnl.exe\" hash=\"14a92ae4ec6afcb087d83a8c9a6722db28dee3508055d56369355d79bc727fd2\" timestamp=\"0x7c480930\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3235\" file=\"lxcore.sys\" hash=\"6db562a658e306cb801a00a4ede030242b6b76803c8d5efb24eb676561b4eec3\" timestamp=\"0x20c54a10\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3286\" file=\"ntoskrnl.exe\" hash=\"32d0715cf693f325f5236959f20460d63d59658e5d8e80d7d4379b01509f852b\" timestamp=\"0x07c0ff45\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3296\" file=\"ntoskrnl.exe\" hash=\"0ecdb82ae6e6f2f631a2239a0bd0ed643531331dd4e9301b03ac0b59e38526b5\" timestamp=\"0x5a4de791\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3350\" file=\"ntoskrnl.exe\" hash=\"6c46b4f20fcdfb45f697111396128031d41dafab8c12fcecb4cce76e10bd2339\" timestamp=\"0x16ed9ee2\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3350\" file=\"lxcore.sys\" hash=\"b76a5e9a3ba7d721056fc63516a10fa490017dde1ebb279e12c4e287119258c9\" timestamp=\"0xd1b285ca\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3374\" file=\"ntoskrnl.exe\" hash=\"124eb049e2e8604f3d599b93cce37fbb6e6afdd4c87d7b27a2e73a20e28d47cb\" timestamp=\"0x97b74fe4\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3420\" file=\"ntoskrnl.exe\" hash=\"c7aaf7904b9ae89f9a2ccc3be68e3787f794f11febdf213bd955edf8d4dbb8d9\" timestamp=\"0x003af3bd\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3430\" file=\"ntoskrnl.exe\" hash=\"18e735b8e2d2c36cbf5eae3e0108f0419d1421e0bea5f38e9d6dd0f020691929\" timestamp=\"0xd2f4936b\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3447\" file=\"ntoskrnl.exe\" hash=\"2cffdff50e744c76c10f395afbe9daac4bf3cc1135b631fb742d4c5f29e1729f\" timestamp=\"0x0dd8a34c\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3495\" file=\"ntoskrnl.exe\" hash=\"0ffa9b16d74151cf633cda3308f373f72b246066236910ad398f5de120e2b9e7\" timestamp=\"0xf97b9159\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3500\" file=\"ntoskrnl.exe\" hash=\"eba87e2f3cde2fd8c56fda3108c865c91cda1ba61168d71f308a0a74cc735db9\" timestamp=\"0x91766b50\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3500\" file=\"lxcore.sys\" hash=\"ef73821527c28cfbb8d8d9b5f875bf62ae7254e81c8ed18a3f3408d587217323\" timestamp=\"0xe0850309\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3527\" file=\"ntoskrnl.exe\" hash=\"0ea65913e60c810632f3bfc95469a0c08130505d292454a1bb5a4ab5cdac850f\" timestamp=\"0x41159882\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3527\" file=\"lxcore.sys\" hash=\"c3ccb67e72f980e8d33c249f2eec839856d6c127aaff07ea9863bfb2383de1a7\" timestamp=\"0x703b44df\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3566\" file=\"ntoskrnl.exe\" hash=\"c3ef001ee191503fa1e74695501db8eec5ee21b0a65176a6a3b75260978632f5\" timestamp=\"0xe25d9c2d\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3566\" file=\"lxcore.sys\" hash=\"f5ad14380fe01a7c62a103c48c5733e080d4fd18ecaa5d922ab8717ac2a4fcf9\" timestamp=\"0x13464e0b\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3575\" file=\"ntoskrnl.exe\" hash=\"fe77d496b81c325d58c4e3357a476137d9cd25c493f9c43940ef04a86650118a\" timestamp=\"0x027308a5\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3575\" file=\"lxcore.sys\" hash=\"ebfecfd67a2f3b866e30bc85f6aafd0a1a40a4fe4926400a0e5952b906dfb907\" timestamp=\"0xdbb08203\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3593\" file=\"ntoskrnl.exe\" hash=\"60f0680fa8100311769bcbe30e2a63a307b4194bc36dc21689ba45c786738baa\" timestamp=\"0xfd77fd6c\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3672\" file=\"ntoskrnl.exe\" hash=\"96402fe2ca46a65d5d3903a2c5d2571d929e01aa805c5b3dfd008b1ff7e4e7ce\" timestamp=\"0x835d19c0\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3672\" file=\"lxcore.sys\" hash=\"134cb7d4893b4b8cffe2cc6f48d03ead0004ef5c40f1e1cb8e6ba6936b0e4537\" timestamp=\"0x89c179c8\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3720\" file=\"lxcore.sys\" hash=\"935b5655fc07cf1f2d4c0455f163e50e73acc329659004627a1307750e782fc2\" timestamp=\"0xd0e7eb7a\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3733\" file=\"ntoskrnl.exe\" hash=\"cbd3fd1e7889894634ff93b5908e5d758cc7f5d4fe5165f294405e328f7ff738\" timestamp=\"0x1c5bc2c5\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3785\" file=\"ntoskrnl.exe\" hash=\"b1e1ff0b5e3b9e900587127a823f964efc7d41120ec79ba48ff5cf6b6ebe6dba\" timestamp=\"0x14ad81f9\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3790\" file=\"ntoskrnl.exe\" hash=\"b100bb551d3102fd44536cd0729df974833b5cd3e814b3e07e317b713a07c76f\" timestamp=\"0xf961eb5d\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3810\" file=\"ntoskrnl.exe\" hash=\"0761e0e20075120c697c01a5296ae0a9e56596b6fa28c99fa9b6fdd74a6c0fc6\" timestamp=\"0x5cf18fbe\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3810\" file=\"lxcore.sys\" hash=\"489056e9b9cde6ffb4e6e6a496cce889a244f8742aff1c3894278447b7094018\" timestamp=\"0x6e64fc95\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3858\" file=\"ntoskrnl.exe\" hash=\"6d032d959ed047383b7c6abe2b88590da6f2f0316b9bf94c83bcc13feef97952\" timestamp=\"0x171551db\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3880\" file=\"ntoskrnl.exe\" hash=\"d9c6f344be25387e4d4f73bf1b2e02d21ff96dd2ad3f68e77c1b7df70322f21c\" timestamp=\"0x212e86dc\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3930\" file=\"ntoskrnl.exe\" hash=\"9e6b7645c31afcaee14c9cca2c22e806e75e993ad8bdab9a57a1ac9e5b52f7bb\" timestamp=\"0xb6265d94\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3936\" file=\"ntoskrnl.exe\" hash=\"d0c5a945d2aaa47093187a49d1d21a86a63071b7e7fba4be07e1ad44daf2f32a\" timestamp=\"0x4849bc73\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3958\" file=\"ntoskrnl.exe\" hash=\"e9d1a379ef0626b4f01c149efb8f64933ad9ec0f429f148cf59798c88f453142\" timestamp=\"0xae889ebf\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.3958\" file=\"lxcore.sys\" hash=\"ead6fd22701b71322e0392869e86c2077407ba6e70f22abc82bfa2fec214b2bb\" timestamp=\"0x86e4d91e\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4000\" file=\"ntoskrnl.exe\" hash=\"03afecfc152a2876815600f37dd0b4ae6f3151d8d1cb2063ad79c2ddc84439e6\" timestamp=\"0xdd41cb39\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4005\" file=\"ntoskrnl.exe\" hash=\"a50e6892bcfed8f4e09dde01144328bd42c009b08c5bd43cc3bf6871c7d5c0b2\" timestamp=\"0xb8d8848c\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4010\" file=\"ntoskrnl.exe\" hash=\"f6209e8fdc69cfa12c54f939e40b246ddd4d49043b8dd8560c5659fb7c385477\" timestamp=\"0x5d08f8a9\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4036\" file=\"ntoskrnl.exe\" hash=\"f1c7036d48cbb27dad769c4f6b535d9fad90e43a233ed64bfc9ad5301af6e99c\" timestamp=\"0x54fb21a3\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4076\" file=\"ntoskrnl.exe\" hash=\"cd678199a162cc0416387c5a4a3ee419cb765ebf4b4897abeb556b31c648b5da\" timestamp=\"0xb7138652\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4082\" file=\"ntoskrnl.exe\" hash=\"c0259bb464382b9529a81aa508aab92e2b2353125681ce47dcd9ce34bc9c5e38\" timestamp=\"0x4d6d0441\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4111\" file=\"ntoskrnl.exe\" hash=\"122e8a4f7d6b17c69fb29df91e2c876fd2c0595a1277cd3203f7dc1bfc2f0094\" timestamp=\"0xaa500889\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4111\" file=\"lxcore.sys\" hash=\"554e52417f92003c6e2dcd8f89e0dc117a61cbce88816b983ce5fdea7a6b43fc\" timestamp=\"0xd8911156\" size=\"0x0010f000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4145\" file=\"ntoskrnl.exe\" hash=\"75d759e26e138798bcf2324eeb22d053f9b4b66be88b3a5a4894e1c8d3de5e6d\" timestamp=\"0x79bd23fb\" size=\"0x0103d000\" added=\"2024-09-12T01:41:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4169\" file=\"ntoskrnl.exe\" hash=\"e9875015a8a4259c5920410ba68348eaf4ac1790ec9aee0a1c7d57d9b3f1df50\" timestamp=\"0x27e39382\" size=\"0x0103d000\" added=\"2024-09-22T15:08:21Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4225\" file=\"ntoskrnl.exe\" hash=\"ac30640e6258bc5b3e7c349d59fc77160a9c39f17b2bcf05e7e149c65cc68316\" timestamp=\"0x6c9d8f69\" size=\"0x0103d000\" added=\"2024-09-24T23:22:06Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4249\" file=\"ntoskrnl.exe\" hash=\"8fca5b9619f3c9ab3ec5af0c1b1fe8d888bc7417200d6b0889f820444ac77400\" timestamp=\"0x174c4629\" size=\"0x0103d000\" added=\"2024-09-27T22:22:02Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4291\" file=\"ntoskrnl.exe\" hash=\"016c6cfd7d4ee14d2441a0b0d0c55feb56b371813751b2a286cfd134a6b3ff3c\" timestamp=\"0x2f4b46b4\" size=\"0x0103d000\" added=\"2024-10-04T01:28:54Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4300\" file=\"ntoskrnl.exe\" hash=\"3677bd379d833c512522da00aecb355aa32fa0c1350176378a37cf5e6b00ff8e\" timestamp=\"0x0f0da5aa\" size=\"0x0103d000\" added=\"2024-10-12T01:50:50Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4317\" file=\"ntoskrnl.exe\" hash=\"558c0b04e4f8b56081a6111beea2bee5bcfa4edc6f86ba84c900b76567e28edd\" timestamp=\"0xadf4dde8\" size=\"0x0103d000\" added=\"2024-10-09T02:21:15Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4367\" file=\"ntoskrnl.exe\" hash=\"071220f59442108d4eb6726143d87b914a29128d3d4ff4cd5f2ccb81a7bf4746\" timestamp=\"0x24800408\" size=\"0x0103d000\" added=\"2024-10-19T15:36:45Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4371\" file=\"ntoskrnl.exe\" hash=\"8344034bf8b181f35efc7afb446daf91e6d411c38caad07efa9d8d34434e21ef\" timestamp=\"0xa02c513a\" size=\"0x0103d000\" added=\"2024-10-26T06:39:10Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4371\" file=\"lxcore.sys\" hash=\"d1a1c1039934fb7c9c78338667c33ca11b63f8724991b4af31845f776c68aa0c\" timestamp=\"0xcd686083\" size=\"0x0010f000\" added=\"2024-11-09T04:03:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4391\" file=\"ntoskrnl.exe\" hash=\"a125da11ddf41d4e3e07041e007b07b8f859ae68706b5f51e8d5e152628c186f\" timestamp=\"0x6f5ace9a\" size=\"0x0103d000\" added=\"2024-10-26T06:39:10Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4391\" file=\"lxcore.sys\" hash=\"b0d6c202fdabadc62e88eef9cd8a26a0444044360bf03855701107fb4f53434c\" timestamp=\"0xa683b6e9\" size=\"0x0010f000\" added=\"2024-10-26T06:39:10Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4435\" file=\"ntoskrnl.exe\" hash=\"fd49c534479ed61816128eb6c83156b7a43028eeda364d1a8e8b53143002f760\" timestamp=\"0xc9a9e954\" size=\"0x0103d000\" added=\"2024-11-05T01:22:32Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4440\" file=\"ntoskrnl.exe\" hash=\"26ac047f10234c2f432ac3e3e508222e4b6c92adcddffca0aedb476e2451ece2\" timestamp=\"0xf640f83e\" size=\"0x0103d000\" added=\"2024-11-09T04:03:18Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4445\" file=\"ntoskrnl.exe\" hash=\"78423a44922b0efcce285246d678998fbaeab2e7d7061db1ca79a7c2c44f60aa\" timestamp=\"0x82a7d005\" size=\"0x0103d000\" added=\"2024-11-10T00:28:44Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4455\" file=\"ntoskrnl.exe\" hash=\"4ec29bc3a665f0de4f6a1831ba7ccb9532384127fa2db6180bfd8bcf88217887\" timestamp=\"0x464b2bcb\" size=\"0x0103d000\" added=\"2024-11-13T15:20:35Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4510\" file=\"ntoskrnl.exe\" hash=\"3e08d6230b98719c8de122860ac05fc166d13a62c5d6d4151bbd48180ff7aa3b\" timestamp=\"0x53ea2fea\" size=\"0x0103d000\" added=\"2024-12-10T02:56:39Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4510\" file=\"lxcore.sys\" hash=\"a533f4e6299388bd4f66fea79e95e0e227ba9de86ffdbb108c9528f086960060\" timestamp=\"0x439fc003\" size=\"0x0010f000\" added=\"2024-11-26T20:43:33Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4515\" file=\"ntoskrnl.exe\" hash=\"e8ca3490e506d6d55e53ddf0bd14bf2d28ec1b96677d8196165591bb2201204b\" timestamp=\"0xf9cbfb52\" size=\"0x0103d000\" added=\"2024-11-26T20:43:33Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4541\" file=\"ntoskrnl.exe\" hash=\"118ed56546c97919b1bd3d323dc5f660736d2d0c67eae15970cc9295a4599d10\" timestamp=\"0x23e8092c\" size=\"0x0103d000\" added=\"2024-11-22T17:11:50Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4541\" file=\"lxcore.sys\" hash=\"6c35267539b59142bc49725ddf5fa8c1a5692eb20b30b5b32c0b22a124d7a13f\" timestamp=\"0x38802d23\" size=\"0x0010f000\" added=\"2024-11-22T17:11:50Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4580\" file=\"ntoskrnl.exe\" hash=\"23d0a9a197f7113c0bec5d43c0dc48311b736f000b7292fd3d8d4a82b37b1742\" timestamp=\"0xdff28166\" size=\"0x0103d000\" added=\"2024-12-10T02:56:39Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4601\" file=\"ntoskrnl.exe\" hash=\"c230f352b3e2eaeae023231e6bb48662d324dae0fb94cacb768a23c91d7ae89a\" timestamp=\"0xf46e88a8\" size=\"0x0103d000\" added=\"2024-12-11T14:53:46Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4655\" file=\"ntoskrnl.exe\" hash=\"a16f494ec5df2e0a667072523a0b2344b33f2b42f349e77d5006e3c1b5738ebe\" timestamp=\"0xb21272f9\" size=\"0x0103d000\" added=\"2024-12-16T15:35:11Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4655\" file=\"lxcore.sys\" hash=\"24553d6f71113b01a68ec9f74eb726db98c70e9ff51c26d3acf07efc11c6b27b\" timestamp=\"0x9adf55f4\" size=\"0x0010f000\" added=\"2024-12-16T15:35:11Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4660\" file=\"ntoskrnl.exe\" hash=\"a15688cc1a2f0a766a78bbe46f22cd105d5f47a8ce2d00bd8c8f491d4d81f3de\" timestamp=\"0xdaba16ee\" size=\"0x0103d000\" added=\"2025-01-10T06:00:00Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4746\" file=\"ntoskrnl.exe\" hash=\"5e2e0ab207a35edce66be50593833834ae6af96adf4bec526e8646ef0a7ab03b\" timestamp=\"0xa57aba12\" size=\"0x0103d000\" added=\"2025-01-15T01:55:10Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4800\" file=\"ntoskrnl.exe\" hash=\"67591c501999fd952344a8918aec299669047a3db7f6009bb36a7e104efcf721\" timestamp=\"0x0652e736\" size=\"0x0103d000\" added=\"2025-01-18T23:48:32Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4800\" file=\"lxcore.sys\" hash=\"18b36883a70d58ac27594c347dbed6eca38c5794c50974c776cb13f69438b1e4\" timestamp=\"0xb828701c\" size=\"0x0010f000\" added=\"2025-01-18T23:48:32Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4805\" file=\"ntoskrnl.exe\" hash=\"06dd17c4b267c4c4196980d75a88e413799c33a042e9fbd29438030337ab5964\" timestamp=\"0xbc289bf1\" size=\"0x0103d000\" added=\"2025-01-25T15:27:45Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4825\" file=\"ntoskrnl.exe\" hash=\"199803eae730d623ed6179c8bfc44d04ca42eb08c588e15fe32e235afa9d119f\" timestamp=\"0xbd467b98\" size=\"0x0103d000\" added=\"2025-06-07T14:16:57Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4825\" file=\"lxcore.sys\" hash=\"ad4bda85b8aa5ffa4ca47a0a13ac3706fd1392df587891e7331d06e20c4c112c\" timestamp=\"0xc5a25452\" size=\"0x0010f000\" added=\"2025-06-07T14:16:57Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4830\" file=\"ntoskrnl.exe\" hash=\"6540fb2a5aac44cfcd9a1faa7cd18a5127ea066394d89b64dbc9d12ddffed868\" timestamp=\"0x4f2f8b9a\" size=\"0x0103d000\" added=\"2025-01-31T00:35:18Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4830\" file=\"lxcore.sys\" hash=\"3e0a05b9c6286b09c93a7e6f4331651470594b0af1b79243ca696e7f28c04532\" timestamp=\"0x812a8c75\" size=\"0x0010f000\" added=\"2025-01-31T00:35:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4870\" file=\"ntoskrnl.exe\" hash=\"86059190fdac909ec738fffeb0555c6b4a91dc83f6b297b94985948e1555ce6e\" timestamp=\"0x6bdedabc\" size=\"0x0103d000\" added=\"2025-02-06T01:33:17Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4880\" file=\"ntoskrnl.exe\" hash=\"29ef0cbd438fb1a8faaefee2320614217721ddfd8a7458d6c63d6f90ff3ac23b\" timestamp=\"0x4279f810\" size=\"0x0103d000\" added=\"2025-02-09T01:52:18Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4880\" file=\"lxcore.sys\" hash=\"d5d7b7bde301f3b19ce86d0b71695411be21fa87bb1901cda38782599289ba73\" timestamp=\"0x770ecfc9\" size=\"0x0010f000\" added=\"2025-02-09T01:52:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4890\" file=\"ntoskrnl.exe\" hash=\"8d7f0003f55354f9777ce3912314ae1e133ca1460300deb147355703bfcb2740\" timestamp=\"0x70295435\" size=\"0x0103d000\" added=\"2025-02-12T06:18:33Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4945\" file=\"ntoskrnl.exe\" hash=\"935cb71127d5137dc4f83dcc6ca9f502d5eee97b7f36a2591d7608ff8e940a0b\" timestamp=\"0x9a507561\" size=\"0x0103d000\" added=\"2025-02-15T17:18:17Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4950\" file=\"ntoskrnl.exe\" hash=\"4ae270bce0ebe22c1ea8f0ca816879ac4a18a148aafcd6b2afafc732a12d0301\" timestamp=\"0x4063aaea\" size=\"0x0103d000\" added=\"2025-02-22T16:10:41Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4974\" file=\"ntoskrnl.exe\" hash=\"4e20a81c7fde40ef4a1fa57c746aede079dd3b58d69dfa30b07fc0db1518c0d8\" timestamp=\"0xd62ef889\" size=\"0x0103d000\" added=\"2025-02-26T02:04:23Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.4974\" file=\"lxcore.sys\" hash=\"626488dcd0f5929d3b12aa260bb44085af219443a8697316cfac09866806345f\" timestamp=\"0x18a2899b\" size=\"0x0010f000\" added=\"2025-02-26T02:04:23Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5015\" file=\"ntoskrnl.exe\" hash=\"1be3f18c6d5d9951a7ebed9e1b36d17283dfb007593093a8bfb94407d7968fa8\" timestamp=\"0x7d9db487\" size=\"0x0103d000\" added=\"2025-03-02T06:42:51Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5025\" file=\"ntoskrnl.exe\" hash=\"a459952f0683b9b37763d520b86be17caad37fc07038a03abcd783f65b729467\" timestamp=\"0xd60bcef1\" size=\"0x0103d000\" added=\"2025-03-11T02:45:33Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5037\" file=\"ntoskrnl.exe\" hash=\"9e6d591330fd2616e69bc1d062eeb7587eaadcc1c93d73824f3d6af1abfcaf98\" timestamp=\"0x0c5761a4\" size=\"0x0103d000\" added=\"2025-03-11T22:25:17Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5090\" file=\"ntoskrnl.exe\" hash=\"c148eaf561d20a23539068456ae369e4c9bdcdcfe1e0550210ca5286329b8684\" timestamp=\"0xd4803585\" size=\"0x0103d000\" added=\"2025-03-19T05:55:37Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5090\" file=\"lxcore.sys\" hash=\"229237c74315b0a8328554510e2623480820856e9c4297aa804f407c810c0ed3\" timestamp=\"0x0e61455c\" size=\"0x0010f000\" added=\"2025-03-19T05:55:37Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5097\" file=\"ntoskrnl.exe\" hash=\"4153e87ea448adf58e8978b0edb7c1d59a479603a9f613b5e7fb7b4262edd750\" timestamp=\"0x0158f5aa\" size=\"0x0103d000\" added=\"2025-03-23T17:06:04Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5124\" file=\"ntoskrnl.exe\" hash=\"6047a7337c49317e4188856dc5e10a4dc82f20dacb4c3cfa5170bb380a0f2a4c\" timestamp=\"0x252afe79\" size=\"0x0103d000\" added=\"2025-03-28T03:59:19Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5124\" file=\"lxcore.sys\" hash=\"c58213af0e15fc158fd8dadaedbcea322f954305d2bbe6712ac05928351918f3\" timestamp=\"0xd0933355\" size=\"0x0010f000\" added=\"2025-03-28T03:59:19Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5160\" file=\"ntoskrnl.exe\" hash=\"6c8b284c2a83b42ed77932d2610e53a4c92a1d70caa99e1c196856ebe76bab11\" timestamp=\"0x70e6e7d8\" size=\"0x0103d000\" added=\"2025-04-02T01:27:00Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5160\" file=\"lxcore.sys\" hash=\"a22bee3f78e77444a2ad71635d8ad5b98646b00d86723be34b5b4611c58ac7df\" timestamp=\"0x53f2aaa4\" size=\"0x0010f000\" added=\"2025-04-02T01:27:00Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5170\" file=\"ntoskrnl.exe\" hash=\"42faf9dfb1a7026be8511d1f906b31d20ce58bda72cc4dfd4c1f7d10bd94ce06\" timestamp=\"0x43937687\" size=\"0x0103d000\" added=\"2025-04-09T14:22:28Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5185\" file=\"ntoskrnl.exe\" hash=\"de1b42e8a148ab7757f0a9226d609df5d0cbe72f5074ec88ed9349487692fc45\" timestamp=\"0x61ddb3ce\" size=\"0x0103d000\" added=\"2025-04-09T14:22:28Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5192\" file=\"ntoskrnl.exe\" hash=\"c372d25c644180a33c7542585a8f83bb951673813037bdfeecf9796583e56a94\" timestamp=\"0x1daa68e1\" size=\"0x0103d000\" added=\"2025-04-12T23:13:14Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5235\" file=\"ntoskrnl.exe\" hash=\"5b5122322a369509eb4f49ecdd7b6a7b0f1ad74a04d82951a5074a52132efa81\" timestamp=\"0x293762d6\" size=\"0x0103d000\" added=\"2025-04-17T02:01:01Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5240\" file=\"ntoskrnl.exe\" hash=\"5d73fd8c0911ea71a2c5ebee50023aa20221151d44fa3f02adc729432bcb8f34\" timestamp=\"0x2d3251d5\" size=\"0x0103d000\" added=\"2025-04-19T15:54:38Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5262\" file=\"ntoskrnl.exe\" hash=\"4e8e10a28a4fb0baeabd16d7a44b68d2039ce85f7a51013b740578b7963804fe\" timestamp=\"0x01e6f4ff\" size=\"0x0103d000\" added=\"2025-04-24T00:56:55Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5262\" file=\"lxcore.sys\" hash=\"c307f7b7f9d40741157f3c84141d34f6ef60362c691b7d118c4844b1c876e32e\" timestamp=\"0x1d5b46c1\" size=\"0x0010f000\" added=\"2025-04-24T00:56:55Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5305\" file=\"ntoskrnl.exe\" hash=\"e2e4dd3087c0a6289b91929cf2da4dde97c806ef867c646ac15cce9cd503a7ac\" timestamp=\"0xe10bba1a\" size=\"0x0103d000\" added=\"2025-04-26T20:45:50Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5331\" file=\"ntoskrnl.exe\" hash=\"f5b94b1c91667c739dd918f228c28679f11d0c51f2109382fe614e52899036e9\" timestamp=\"0xc53a7b27\" size=\"0x0103d000\" added=\"2025-05-13T22:56:23Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5413\" file=\"ntoskrnl.exe\" hash=\"2e54e77583f71d5eff8bde68fbccf18cbc576dda7c54664997c978ca6cd63c7c\" timestamp=\"0xcb926299\" size=\"0x0103d000\" added=\"2025-05-29T05:57:37Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5415\" file=\"ntoskrnl.exe\" hash=\"5ddac55dc384461a2b81e7bea160c3649a48df301db9679d65d6852ad6df4bbb\" timestamp=\"0x51634c4e\" size=\"0x0103d000\" added=\"2025-06-01T15:47:54Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5415\" file=\"lxcore.sys\" hash=\"ac8f984ef2b08b1101809f9eb548c7656d70787dbe5bd17be95d1fc91c7de7d3\" timestamp=\"0x40f21d02\" size=\"0x0010f000\" added=\"2025-06-01T15:47:54Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5471\" file=\"ntoskrnl.exe\" hash=\"8a06af395f5f4623640bfe099a468b0be2f86a4f921923bcc256623f2e07c287\" timestamp=\"0x70e268d6\" size=\"0x0103d000\" added=\"2025-06-13T19:27:57Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5541\" file=\"ntoskrnl.exe\" hash=\"5fb613985b73d0def291acd88df49589742b60fd50d6bd0f9fb5718b6a903032\" timestamp=\"0x6081412f\" size=\"0x0103d000\" added=\"2025-06-28T02:27:55Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5547\" file=\"ntoskrnl.exe\" hash=\"4a9944ea0b3a1d0763f61a8227eb39cffacee90a5246a50b0b045121b1100eab\" timestamp=\"0xb781951e\" size=\"0x0103d000\" added=\"2025-06-28T02:27:55Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5624\" file=\"ntoskrnl.exe\" hash=\"10237ed35a88f5f6eaf97a48b6eb19d6ccf99d75833639d6ad39e30b0142ab30\" timestamp=\"0xbbeae221\" size=\"0x0103d000\" added=\"2025-07-08T22:13:00Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5697\" file=\"ntoskrnl.exe\" hash=\"0b359bfcb3645f8bf8be2c92c1b3a2066003acf3ea44582785d0580f4b294dd5\" timestamp=\"0xa0b1dd6e\" size=\"0x0103d000\" added=\"2025-07-24T05:27:30Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5766\" file=\"ntoskrnl.exe\" hash=\"bc1ccfd0510972ba7a3e5f248a516ab8eb62381105367443602fcb60dc2ab151\" timestamp=\"0xdbab7e70\" size=\"0x0103d000\" added=\"2025-08-13T21:37:12Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5771\" file=\"ntoskrnl.exe\" hash=\"a32bdf04b3d373715022da8b29af185919c2cff27bfc66529d80e5a8e1d310ca\" timestamp=\"0xa25fd393\" size=\"0x0103d000\" added=\"2025-08-21T15:11:13Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5840\" file=\"ntoskrnl.exe\" hash=\"fcc3110832f78aff7a40ea7da3558c8d03d0959432f40c10ffb1004f0b7f64dc\" timestamp=\"0x0fbf82f7\" size=\"0x0103d000\" added=\"2025-08-27T04:03:40Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5909\" file=\"ntoskrnl.exe\" hash=\"be15537c75b00028d5631f89e3da0d5c9233e6ff75963149a2c2feb22e17c5cc\" timestamp=\"0x37aae490\" size=\"0x0103d000\" added=\"2025-09-11T03:22:38Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.5983\" file=\"ntoskrnl.exe\" hash=\"4d50fb3f621b8a97cacdef6494999e01d631ea2f7007f8f79eae992905b26d42\" timestamp=\"0xd40c3516\" size=\"0x0103d000\" added=\"2025-09-26T02:51:04Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.6060\" file=\"ntoskrnl.exe\" hash=\"b616e73e2ca823d686cfcf7cf607bd312b9a43bf1ec9e2a57ea283ce64be6b9f\" timestamp=\"0x69515603\" size=\"0x0103d000\" added=\"2025-10-16T23:37:47Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.6133\" file=\"ntoskrnl.exe\" hash=\"6c0081cec909fd2d4a044c668a3d127bdce15442e797c9ae0c098024756e5a2e\" timestamp=\"0xd138d8df\" size=\"0x0103d000\" added=\"2025-10-29T20:10:48Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.6197\" file=\"ntoskrnl.exe\" hash=\"55c441b3a1621003b458f16c7f4dec3f54c3678b64344d16a9664303d2a31f1d\" timestamp=\"0x460e4ae3\" size=\"0x0103d000\" added=\"2025-11-12T23:55:08Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.6199\" file=\"ntoskrnl.exe\" hash=\"6b97225e78f9eb50535e7b5969bc093c6ac4c474e2857125401c76e9c82b3c87\" timestamp=\"0x33946556\" size=\"0x0103d000\" added=\"2025-11-12T23:55:08Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.6274\" file=\"ntoskrnl.exe\" hash=\"19e31778ccfeb02dc3ed22f06b048fc423daf8caa79bffc5c15c2ae450b45c61\" timestamp=\"0xd660afc6\" size=\"0x0103d000\" added=\"2025-11-25T23:06:05Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.6337\" file=\"ntoskrnl.exe\" hash=\"1bdbf994faf82cd3d7764380e3c51f8a6b9adbc316a091fcf24a2259af283717\" timestamp=\"0x79b113e1\" size=\"0x0103d000\" added=\"2025-12-11T18:37:57Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.6345\" file=\"ntoskrnl.exe\" hash=\"04bb20298cecbf86b0f7725a4856173e25f762907451cfb0677493b8f96f1135\" timestamp=\"0x7927a596\" size=\"0x0103d000\" added=\"2025-12-10T04:39:55Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.6489\" file=\"ntoskrnl.exe\" hash=\"0e09727c786cbd582983218339e87f3cdccdeeb81d45d263ba8bf890d54c79f9\" timestamp=\"0x48018901\" size=\"0x0103d000\" added=\"2026-01-15T04:51:11Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.22621.6630\" file=\"ntoskrnl.exe\" hash=\"aeaeb4798cbcfe12ae93a837f06f1ea2c948400bac843e6d36b51ea32d841816\" timestamp=\"0xd5369aa7\" size=\"0x0103d000\" added=\"2026-02-11T00:54:58Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.23440.1000\" file=\"ntoskrnl.exe\" hash=\"b14a987d01b5c85affa3f1ddb451c8810f0e6d9f0b9521cb730f69f44ee02df1\" timestamp=\"0xc9d24ab7\" size=\"0x0103d000\" added=\"2024-12-03T02:17:28Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.23526.1000\" file=\"ntoskrnl.exe\" hash=\"0a7d6233fbc0aa872f607c85298a82c90a1f86b3dd32356ee5d56e67cc9408be\" timestamp=\"0x3b9052b9\" size=\"0x0103d000\" added=\"2025-05-10T01:12:18Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.25227.1000\" file=\"ntoskrnl.exe\" hash=\"a416922679cca5df48d28a9fb13e5c04e92cd6e11b4555006ed686ef99966308\" timestamp=\"0xdba4b0aa\" size=\"0x01040000\" added=\"2024-11-24T17:20:19Z\">22</data>\n    <data arch=\"arm64\" version=\"10.0.26058.1000\" file=\"ntoskrnl.exe\" hash=\"781d5033cc344c16488a5843c2c45ba27aab20cc246dc20a320777702747deed\" timestamp=\"0x1679bd4f\" size=\"0x01249000\" added=\"2025-03-28T03:59:19Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26080.1\" file=\"ntoskrnl.exe\" hash=\"94616fa03a4b1de6825f84dd042a933dd8c8eaf58b259cd658dc98a0fa23926a\" timestamp=\"0xfa6c3714\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26080.1\" file=\"lxcore.sys\" hash=\"acdf7e697cf2a3cd56ffe3546d25b029a579af29ce0bac49ad02ae6de2252243\" timestamp=\"0x076e2176\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26080.1100\" file=\"ntoskrnl.exe\" hash=\"a811706be79d7646383a3e6006aaf7a0d4f0dd52d0b01f75567ac7e739fd865a\" timestamp=\"0xc8079905\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26080.1201\" file=\"ntoskrnl.exe\" hash=\"6266ef378a61c7ba3578e2d7fd5f81b33d619aa9c3e4456c6a1572de3f14100f\" timestamp=\"0x56616fb2\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26080.1300\" file=\"ntoskrnl.exe\" hash=\"063f51cff8fab8fb3e96c6ba6624264443e3b2c30937811db90aa109b993c6a3\" timestamp=\"0x58f18a74\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26085.1\" file=\"ntoskrnl.exe\" hash=\"c36d19f66da64d540cdca255b199f6e11760809d51ae2bc2e54a3c895a0d801c\" timestamp=\"0x8d30f162\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26085.1\" file=\"lxcore.sys\" hash=\"5246eda4769402af3c61446d339a7c4e73d306c4468f1e13a06106d7a48dcde7\" timestamp=\"0x9efea886\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26090.1\" file=\"ntoskrnl.exe\" hash=\"823f05dd041c8c47cd70f35dd02ce39a232491d50680f6e7a3850417177434bf\" timestamp=\"0xf3095193\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26090.1\" file=\"lxcore.sys\" hash=\"38579047eab10cdc5d8a8e90ab3e1030dc60352c8100faa1dd31f589c8305488\" timestamp=\"0x69c3a4a5\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26090.112\" file=\"ntoskrnl.exe\" hash=\"d6b41817b4ee2281c576e11292b3be4f6ac09195ba3992ea34c4a76a590e22b1\" timestamp=\"0x983f5dee\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1\" file=\"ntoskrnl.exe\" hash=\"d4b87433d6a49ef09ccfc1d76745635d039dfccecfa11e9b4832328c1406e3a7\" timestamp=\"0x1149c62d\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1\" file=\"lxcore.sys\" hash=\"898fe8c6d8f8369cee255de4a7279af3a8eae9ef82592e5af948680a0be87c1b\" timestamp=\"0xb0347eb4\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2\" file=\"ntoskrnl.exe\" hash=\"a15280d995b374d87dbeee6765ecb6345a6d10bef7e3f9ed50661d7c8861c157\" timestamp=\"0x2d1da155\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3\" file=\"ntoskrnl.exe\" hash=\"b5b01de8562eaedf576e605eb5a9959255bc1c0d320c7877495984bc709fbe3b\" timestamp=\"0xfff470bf\" size=\"0x01249000\" added=\"2024-10-26T06:39:10Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.268\" file=\"ntoskrnl.exe\" hash=\"55cb0b9a9985eab15e80ebadcdb8f619b69c91cfa735492aaa78d7904f80e464\" timestamp=\"0x9b419f05\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.470\" file=\"ntoskrnl.exe\" hash=\"6047b065dc88bb72b0897cce61683a651c918f7a13e9af7298c53fce9887b858\" timestamp=\"0x87b36841\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.560\" file=\"ntoskrnl.exe\" hash=\"8000125ca5c2b84f1d16c1343c055a1bce47ea7b9f66bd20ac1d4e233e4c339b\" timestamp=\"0x1a34a565\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.670\" file=\"ntoskrnl.exe\" hash=\"a100a6a0ee50cb7d88b1e5772c042c80533c0b9383b03a7a8617b87ae427b0ec\" timestamp=\"0xea439816\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.712\" file=\"ntoskrnl.exe\" hash=\"b7244d01ef1d552bbcbeb4be65a86195253c3613d80e5ecc42e33b22a690771c\" timestamp=\"0x80d4fb4f\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.751\" file=\"ntoskrnl.exe\" hash=\"4b2720e5188c218e19dd4280bdd1d46dad0dceb383c3ca1ab7c80d74fd769a40\" timestamp=\"0x0c4dd930\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.863\" file=\"ntoskrnl.exe\" hash=\"7c11dc8c511e34eb3162067e19abd700f1eeab38976355cb950b2b90d2505efd\" timestamp=\"0x270a52b4\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.961\" file=\"ntoskrnl.exe\" hash=\"8f4124d5e2cb3cd39ec2d42fe0c87dc07db9bee111cc14a4cd89b1ed3219b8a4\" timestamp=\"0x0f9bbe7a\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.961\" file=\"lxcore.sys\" hash=\"587ae9aa58a6225796549dc879010f94ff9696d04c708194cd4d7551eca77c5f\" timestamp=\"0x9df92ee6\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1000\" file=\"ntoskrnl.exe\" hash=\"8c8c34f2b63212f119c6fcd15f61e0583a1474735c89a638fbbd7c34c797d5e9\" timestamp=\"0x286136ef\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1150\" file=\"ntoskrnl.exe\" hash=\"828fa103638a9156e6a185acd50fefbbcb065eb0b438a9aa980557acfcd21bda\" timestamp=\"0xf0473c06\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1150\" file=\"lxcore.sys\" hash=\"af387baf441ffcf92466e90ea43083a7d0ff9232c5d135b08777846f2b9b5a4f\" timestamp=\"0xc9a8dff8\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1252\" file=\"ntoskrnl.exe\" hash=\"65973eedeef9ce1742c991c8c192681645549dd1ac063dc42bd578b549c38031\" timestamp=\"0x5bad7512\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1252\" file=\"lxcore.sys\" hash=\"e07fe7f69e960838353853953ad8aa3b616cb68ed67bc2e92a012dd756ac6872\" timestamp=\"0x2032bc83\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1301\" file=\"ntoskrnl.exe\" hash=\"735578abdd743a5aad3395a31c90d36ffd5b8ca1ed5bfca4c95011c4cc7bc1e4\" timestamp=\"0x0efce3e6\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1301\" file=\"lxcore.sys\" hash=\"cfff05fb3a5b2409e3f949c44270bae2c9b7def842630d3cd62a39ece8dcab59\" timestamp=\"0x81c6954c\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1330\" file=\"ntoskrnl.exe\" hash=\"b0bfe651edac98acb99d902f92fae0d668976ee80816d2e866ddc86117e82088\" timestamp=\"0xed399024\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1330\" file=\"lxcore.sys\" hash=\"df252b5999779c1517d34158c57fbcf8e7a73bbbdef5220bbaccfa8ae1d86a4c\" timestamp=\"0xca22201f\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1340\" file=\"ntoskrnl.exe\" hash=\"3d4b84c42f5821a1797dedb6840d95ea3c7fc8939f5ec356c1c792852d404520\" timestamp=\"0x71f44b6f\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1350\" file=\"ntoskrnl.exe\" hash=\"3316509254d153cfc5ab4f84ab5415a41a48496948ab1f86ed1d71ac3a43ef18\" timestamp=\"0x6cbdc95a\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1455\" file=\"ntoskrnl.exe\" hash=\"3f4963e4e4c502f23f8941f0e87670a30639f84205f0acf684aff359c599fcaf\" timestamp=\"0x4c877be0\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1542\" file=\"ntoskrnl.exe\" hash=\"168bc5400e8df6edb2836443fa1614022310baa4f03c09333d10d844a72b7479\" timestamp=\"0x053ea75f\" size=\"0x01249000\" added=\"2025-08-12T14:54:17Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1591\" file=\"ntoskrnl.exe\" hash=\"faa80fe42dde2ea8e5e3d9a27feea401c664e9910832ae8f2214d24c0f290ec3\" timestamp=\"0x5aad7701\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1742\" file=\"ntoskrnl.exe\" hash=\"8e31b99670c5930c9de68574aff5702ccfe5c34942f2f6fa4a6473e22431f5dd\" timestamp=\"0x9d65444a\" size=\"0x01249000\" added=\"2024-09-12T01:41:07Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1843\" file=\"ntoskrnl.exe\" hash=\"a1c9871b50c0aeaa96717e0527b13ea26b5af77350a65bddea9882ea50984290\" timestamp=\"0xf3cdb593\" size=\"0x01249000\" added=\"2024-09-22T15:12:26Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1882\" file=\"ntoskrnl.exe\" hash=\"b76d4382edae9264307c3c999b25bc76995813e2295259dd751235338e00d622\" timestamp=\"0xc27dc2f8\" size=\"0x01249000\" added=\"2024-10-01T23:04:59Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1912\" file=\"ntoskrnl.exe\" hash=\"45f9df49d337b9eb423e7c5371b9000c4ea1541c32c372bff810515c74430880\" timestamp=\"0x14317c07\" size=\"0x01249000\" added=\"2024-10-09T02:21:15Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.1930\" file=\"ntoskrnl.exe\" hash=\"8fb69ffa4cd84d4382b537d810b133e6a3b2f87b45f981a5c4914f682ab40dcc\" timestamp=\"0x874be7fe\" size=\"0x01249000\" added=\"2024-10-12T01:50:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2033\" file=\"ntoskrnl.exe\" hash=\"d6098a5d92e1bd38567a24d52f6c2f326e69a5af89e25e832d9595a7e17ea9db\" timestamp=\"0x4b6be674\" size=\"0x01249000\" added=\"2024-10-09T02:21:15Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2033\" file=\"lxcore.sys\" hash=\"fc057d818c9b72bd5064fadf280e7d21adadee31ac06f0c674c0a59f229e916f\" timestamp=\"0xf8f16c27\" size=\"0x0010e000\" added=\"2024-10-09T02:21:15Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2122\" file=\"ntoskrnl.exe\" hash=\"d83824b3ad6c39853377e4f3a15460d73ddb3305ea30be8d2e0c3ccc929e6b2c\" timestamp=\"0xd86db259\" size=\"0x01249000\" added=\"2024-10-16T00:54:19Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2122\" file=\"lxcore.sys\" hash=\"aab3f971a35be3154e540bb7f84f9cde3a2acf594c915d81b2d4b5e6f47c14d8\" timestamp=\"0x640ebd8f\" size=\"0x0010e000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2130\" file=\"ntoskrnl.exe\" hash=\"bbd55339f9d344360212919471bba650014a37b89f20e7ea4788939d593c12a8\" timestamp=\"0x648f88fb\" size=\"0x01249000\" added=\"2024-10-20T15:35:22Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2161\" file=\"ntoskrnl.exe\" hash=\"c021675d178cae2b62a39b693ffc463970b68a541a7a1b37ab39559dd1c09b2f\" timestamp=\"0x106c9ffa\" size=\"0x01249000\" added=\"2024-10-26T06:39:10Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2200\" file=\"ntoskrnl.exe\" hash=\"9eadbe65a2e095ac872b96d40a513ce0a0d69b826f910313207bc80371d05877\" timestamp=\"0xefa1ba81\" size=\"0x01249000\" added=\"2024-10-30T23:26:34Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2213\" file=\"ntoskrnl.exe\" hash=\"d342f00db9e065bd1d5d704512298258b3b933fc2a542da3e8bc9d23b818fc29\" timestamp=\"0xef29edff\" size=\"0x01249000\" added=\"2024-11-10T01:43:06Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2213\" file=\"lxcore.sys\" hash=\"d3e791daa43628c58946383c75358a84906d94daf14caac709c2af15a7928266\" timestamp=\"0x7558cfa2\" size=\"0x0010e000\" added=\"2024-11-10T01:43:06Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2222\" file=\"ntoskrnl.exe\" hash=\"c96c2c12d0b2990de5ba735c774ee803e5c6b97c81674bfac8e7aec3a7d59389\" timestamp=\"0xe62fc08d\" size=\"0x01249000\" added=\"2024-11-10T01:43:06Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2222\" file=\"lxcore.sys\" hash=\"7f40414212052260badf0d8535a930b39bdc5c9b55f852066808866af805ed2d\" timestamp=\"0x8567af4c\" size=\"0x0010e000\" added=\"2024-11-10T01:43:06Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2314\" file=\"ntoskrnl.exe\" hash=\"b60a475d89596436304849190609647b82e9acd91d9f244f3a23f2741ef2b867\" timestamp=\"0xc9bf0e0e\" size=\"0x01249000\" added=\"2024-11-13T15:20:35Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2415\" file=\"ntoskrnl.exe\" hash=\"d29a71a9da51ceb5f9a01d06d8933c4c60e2793c85b49e41d4b3c3c9ffedbf4a\" timestamp=\"0x78c53e1b\" size=\"0x01249000\" added=\"2024-11-24T17:20:19Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2415\" file=\"lxcore.sys\" hash=\"8c9cedc5f66fcb9760c01900c3c39fa6edf9b362c4c52472c898e806cf0981dd\" timestamp=\"0xe8cdc9e3\" size=\"0x0010e000\" added=\"2024-11-24T17:20:19Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2448\" file=\"ntoskrnl.exe\" hash=\"c992c95da8ba39d4935c65c0531505d7f7a2c082c8e24650122077da85545d0c\" timestamp=\"0x5291dd3d\" size=\"0x01249000\" added=\"2024-11-22T17:11:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2454\" file=\"ntoskrnl.exe\" hash=\"343959c650d8b3a8006f37c40ec10abce410dd6702153fe323c4b3c8b7f6d632\" timestamp=\"0x83b02311\" size=\"0x01249000\" added=\"2024-11-19T23:28:40Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2510\" file=\"ntoskrnl.exe\" hash=\"d7df9e96c3af0d38f4e34bce681b443af78f6b6409fc48ec4b45f68d7ccb80f5\" timestamp=\"0x7457321f\" size=\"0x01249000\" added=\"2024-12-10T02:56:39Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2605\" file=\"ntoskrnl.exe\" hash=\"322a103e9651570ed0472af5ebc20b99fa02f7368d4e971a555d34248e3bf8fc\" timestamp=\"0x32039505\" size=\"0x01249000\" added=\"2024-12-11T14:53:46Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2702\" file=\"ntoskrnl.exe\" hash=\"b1c11369e7388f37d7360f21fdde925d4781826b184513cec922002982380e59\" timestamp=\"0xaf5661d4\" size=\"0x01249000\" added=\"2024-12-16T15:35:11Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2702\" file=\"lxcore.sys\" hash=\"0452922132595423e628e85aabd5e7eb1fcbda823f3dbc650847fe94718703d3\" timestamp=\"0x0646bde5\" size=\"0x0010e000\" added=\"2024-12-16T15:35:11Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2705\" file=\"ntoskrnl.exe\" hash=\"5228ee34a8ec3e814e5a692c85279fbdc61152e271307ce314ec2c86fa65a583\" timestamp=\"0xef68e885\" size=\"0x01249000\" added=\"2024-12-19T19:52:18Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2894\" file=\"ntoskrnl.exe\" hash=\"1ad1ce7a6b0f9ef691f55e8647814370b63353e1f7321939d48f19d7e7adf60f\" timestamp=\"0xbc14dfb5\" size=\"0x01249000\" added=\"2025-01-15T01:55:10Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2992\" file=\"ntoskrnl.exe\" hash=\"dbc8fe5d88ea81863dbd0bfa2e49c4f7596314bbdda719bbd61f7eea6374e628\" timestamp=\"0xdd57be61\" size=\"0x01249000\" added=\"2025-01-18T23:48:32Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.2992\" file=\"lxcore.sys\" hash=\"c21ab285537b1431f79deca4a53463061bf6155977aa175184647899138bf857\" timestamp=\"0x4bcaaa4f\" size=\"0x0010e000\" added=\"2025-01-18T23:48:32Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3000\" file=\"ntoskrnl.exe\" hash=\"0f7b996062fc12fb307e4ad31767d93519693aef43749bb260911ed44c59f982\" timestamp=\"0x9edef86b\" size=\"0x01249000\" added=\"2025-01-25T15:27:45Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3037\" file=\"ntoskrnl.exe\" hash=\"2190aeb2b488b9211440d001b441c679178fb419439797397408e78820f70225\" timestamp=\"0xb32d7f74\" size=\"0x01249000\" added=\"2025-01-31T00:35:18Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3037\" file=\"lxcore.sys\" hash=\"d91885cb274708d0096a5b305f797ababe365cb7188be43ad350fe89eb4beb33\" timestamp=\"0x03ec3644\" size=\"0x0010e000\" added=\"2025-01-31T00:35:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3073\" file=\"ntoskrnl.exe\" hash=\"66a18c2fc0caa84ddd9d4e55e665e25fd916fb673087f6e92af39c9e8de2da03\" timestamp=\"0x32ea4298\" size=\"0x01249000\" added=\"2025-02-02T03:08:17Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3073\" file=\"lxcore.sys\" hash=\"15ed2a3ebfabeef9bb7988fcfc677ab3621c37a332c9c1f295256ea97d9d9a2b\" timestamp=\"0xb6e65c68\" size=\"0x0010e000\" added=\"2025-02-02T03:08:17Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3194\" file=\"ntoskrnl.exe\" hash=\"a9b71ba1c9c43428dc8d2877e52a5c571094e391175f32ab9e2ffb5563363f3f\" timestamp=\"0x521788f2\" size=\"0x01249000\" added=\"2025-02-12T06:18:33Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3281\" file=\"ntoskrnl.exe\" hash=\"2237e6240a506c53c463f467a4f6dedb41bd0ac54354d089cf805beafa9bfc61\" timestamp=\"0xfe692f9e\" size=\"0x01249000\" added=\"2025-02-15T17:18:17Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3291\" file=\"ntoskrnl.exe\" hash=\"d780850a678e0140d137e29acfa5fc19b7d21339b423abdea2c4d53288b67485\" timestamp=\"0x13a66509\" size=\"0x01249000\" added=\"2025-02-22T16:10:41Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3323\" file=\"ntoskrnl.exe\" hash=\"ba4f8b0693556ff3272e605a95c1a8ba8fce12e3dbf4f4201d3319c5dc776c43\" timestamp=\"0x3ca08b0e\" size=\"0x01249000\" added=\"2025-02-27T03:21:46Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3323\" file=\"lxcore.sys\" hash=\"8a9cc515d99a35bda712f7fa3fd376e39ac2049d2b6f962ff4593115396c3236\" timestamp=\"0xf784da9b\" size=\"0x0010e000\" added=\"2025-02-27T03:21:46Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3360\" file=\"ntoskrnl.exe\" hash=\"9cb01d789708b73760c2d2be838094303151eafefe814b592bc03457a41c28c1\" timestamp=\"0xee8458b7\" size=\"0x01249000\" added=\"2025-03-02T06:42:51Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3380\" file=\"ntoskrnl.exe\" hash=\"20c7177a81acdc7b8b6936778cc4abbf7130e772002611ffb7ae12e10e708ad4\" timestamp=\"0x4f672894\" size=\"0x01249000\" added=\"2025-03-11T22:25:17Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3470\" file=\"ntoskrnl.exe\" hash=\"732e771389f6d20695c3f461007e91b11247470d4e8e9c96a587f53e25f66a10\" timestamp=\"0xbfc7dbcf\" size=\"0x01249000\" added=\"2025-03-19T05:55:37Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3476\" file=\"ntoskrnl.exe\" hash=\"3c550939ed5bcf8728cad8f80badd068e501cafc016e433cf9fc41d2dc65e612\" timestamp=\"0xccdb44de\" size=\"0x01249000\" added=\"2025-03-14T04:05:46Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3575\" file=\"ntoskrnl.exe\" hash=\"89937267923e5489027badd0af810f667981e3ebf62f079ff5f9632d91861f15\" timestamp=\"0x0ef91147\" size=\"0x01249000\" added=\"2025-03-19T05:55:37Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3585\" file=\"ntoskrnl.exe\" hash=\"54063a46014192fdab24c339feb7925d9a2bdaf65ffb587e8ebce7af6cc52a76\" timestamp=\"0x889ba030\" size=\"0x01249000\" added=\"2025-03-28T03:59:19Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3613\" file=\"ntoskrnl.exe\" hash=\"697fd168f6917b35cf28b0d6855d13ece1d030ced447eb6a589457cc17736f8d\" timestamp=\"0x2ec564ea\" size=\"0x01249000\" added=\"2025-03-29T06:48:24Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3624\" file=\"ntoskrnl.exe\" hash=\"26b90d08e850650bd82b7765b218a7851cbd813c8896796f25308d7afab60a1d\" timestamp=\"0xf244d778\" size=\"0x01249000\" added=\"2025-03-28T03:59:19Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3653\" file=\"ntoskrnl.exe\" hash=\"1fdaad9d2a317f5405e669552c9c19b616242737e27c0a885d44e8db87ec2bcd\" timestamp=\"0xb8a5d571\" size=\"0x0124a000\" added=\"2025-04-01T05:31:15Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3653\" file=\"lxcore.sys\" hash=\"d4abe32e97b82cdadc9a1de4deded2fbd8d311aee1d34df89c9035de745672c6\" timestamp=\"0x68695972\" size=\"0x0010e000\" added=\"2025-04-01T05:31:15Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3671\" file=\"ntoskrnl.exe\" hash=\"be81badd9557212aa8f3f89cf2f45a6a2b3c1fd730b8616da81df9243813cfcf\" timestamp=\"0x02120d4e\" size=\"0x0124a000\" added=\"2025-04-05T04:20:29Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3671\" file=\"lxcore.sys\" hash=\"aa66f6a2a6cbf2e1acc7e5ac46ba8843b3cbb5f7c25e3c82b9c94bf665bc7bb3\" timestamp=\"0x8bdbd309\" size=\"0x0010e000\" added=\"2025-04-05T04:20:29Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3775\" file=\"ntoskrnl.exe\" hash=\"ce58acf1beaf9fba579430d71cdf80b64b5e7012730ec0d941a437f2cb483844\" timestamp=\"0x082b8992\" size=\"0x01249000\" added=\"2025-04-09T14:22:28Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3781\" file=\"ntoskrnl.exe\" hash=\"28cc97336e052efc3c9bb68a207dfae077e504c6079801b4f74af62874f782e0\" timestamp=\"0xca4cce89\" size=\"0x01249000\" added=\"2025-04-19T15:54:38Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3863\" file=\"ntoskrnl.exe\" hash=\"5f987f24c1f8324112db8c783c18479fd801afaa39aac227f785a09594fe9a48\" timestamp=\"0x1f4452da\" size=\"0x0124a000\" added=\"2025-04-12T23:13:14Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3911\" file=\"ntoskrnl.exe\" hash=\"21a0b8a0e4f91f66dc78e0588904611f0a8f4ef5cf134f2af3c4a8218fef9264\" timestamp=\"0x531a9bc3\" size=\"0x0124a000\" added=\"2025-04-26T20:45:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3912\" file=\"ntoskrnl.exe\" hash=\"5b9bc06a59a9940caebbfe182d59253536f6c4c7e573482a62b109ffbbae1225\" timestamp=\"0xf1b3d035\" size=\"0x0124a000\" added=\"2025-04-26T20:45:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3912\" file=\"lxcore.sys\" hash=\"9254793e9e1d1c8c9d3cd0a8cbf7a2cd9fab3be881cfe80368abe99075a7836f\" timestamp=\"0x27196b19\" size=\"0x0010e000\" added=\"2025-04-26T20:45:50Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3941\" file=\"ntoskrnl.exe\" hash=\"1951b6816e4b076136b457cbdb5fd70880d484074debe7d63e115e339394c2ce\" timestamp=\"0x3ec0caa2\" size=\"0x0124a000\" added=\"2025-04-26T20:45:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3950\" file=\"ntoskrnl.exe\" hash=\"eaca373e00c07fde4371a9982efbb6d4f9046e6b35d35d57c6cdf6329ff5b2ff\" timestamp=\"0x40812cd3\" size=\"0x0124a000\" added=\"2025-05-10T01:12:18Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3950\" file=\"lxcore.sys\" hash=\"e6d13dfe47047c40d9fe1c980c66392617fc45942109b02caf916a29a5e2361d\" timestamp=\"0x9b3e96af\" size=\"0x0010e000\" added=\"2025-05-10T01:12:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3961\" file=\"ntoskrnl.exe\" hash=\"9452687da31347ce979113fbfaf4547f2287085442e50306cec603bd3a6556a5\" timestamp=\"0x597165d6\" size=\"0x0124a000\" added=\"2025-05-13T22:56:23Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.3964\" file=\"ntoskrnl.exe\" hash=\"91bc1666efe8ef030cdf68c82657f7cc33c2784902ba328c13caf06af6c1520d\" timestamp=\"0x839bf4f1\" size=\"0x0124a000\" added=\"2025-05-13T22:56:23Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4054\" file=\"ntoskrnl.exe\" hash=\"01fa0adcf3a3ceac01c530223c631eae07b0a1910d0d756b2166c8ecfe871e0e\" timestamp=\"0x0da2aa77\" size=\"0x0124a000\" added=\"2025-05-13T22:56:23Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4061\" file=\"ntoskrnl.exe\" hash=\"4fba4990cd529345d08d8f22409b583337ae6d7e4aed9ec1a959a7de650b706b\" timestamp=\"0xd2a01bb9\" size=\"0x0124a000\" added=\"2025-05-13T22:56:23Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4061\" file=\"lxcore.sys\" hash=\"f249f7d1297cc4e7d685bfc6db7bc2bd5eb4c24d6fafd99452e8cb00c8d783ad\" timestamp=\"0xbe0a62d1\" size=\"0x0010e000\" added=\"2025-05-13T22:56:23Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4151\" file=\"ntoskrnl.exe\" hash=\"6c4e27de79659ad23ad2895ec70e2cbd207c7339c338966e83be3c72425c300e\" timestamp=\"0xfc8a8eed\" size=\"0x0124a000\" added=\"2025-05-22T02:15:04Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4161\" file=\"ntoskrnl.exe\" hash=\"92c2aa274a9eff325f761daeb465296d95cfaaae0eca0da0cfe81cc168dc0bef\" timestamp=\"0x476cc5b1\" size=\"0x0124a000\" added=\"2025-05-24T14:17:56Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4187\" file=\"ntoskrnl.exe\" hash=\"bd56f50f240d04ed69ed1cd8e283cc42664cc3bd7ffc3da3aa77389c41d1bfcd\" timestamp=\"0x7df11427\" size=\"0x0124a000\" added=\"2025-05-31T18:37:56Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4202\" file=\"ntoskrnl.exe\" hash=\"e63bc43f4b7a8cb960e28cdd47eec412cbcbe3661685d67c777fdf87728a13d1\" timestamp=\"0x05a73b4c\" size=\"0x0124a000\" added=\"2025-05-29T05:57:37Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4202\" file=\"lxcore.sys\" hash=\"47585d895466eed810578288ed931a5c1e29a4237d92e076533e5e4f1205fd82\" timestamp=\"0xf8ac768b\" size=\"0x0010e000\" added=\"2025-05-30T19:55:37Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4230\" file=\"ntoskrnl.exe\" hash=\"d4582a001f5e8661d790b38210a15c64bbe1d540187138cd18956a3bd356e1a2\" timestamp=\"0xc5c92c7e\" size=\"0x0124a000\" added=\"2025-06-07T14:16:57Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4250\" file=\"ntoskrnl.exe\" hash=\"68c432c1b41be9c81d0d9655f303b92be98d0d2c5eacb7bd85e3a8be4f914f3c\" timestamp=\"0x37935dad\" size=\"0x0124a000\" added=\"2025-06-10T13:19:34Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4343\" file=\"ntoskrnl.exe\" hash=\"f8b5790fe89dbb8dbff86ad44d22c4212475a4e70ec625b41c073686df9d529f\" timestamp=\"0xebe96425\" size=\"0x0124a000\" added=\"2025-06-11T00:42:44Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4351\" file=\"ntoskrnl.exe\" hash=\"0e9239ed9ae6606854dbcf546a2511a323d4edb360cdd7e18c2db41986704a19\" timestamp=\"0xae9b82c6\" size=\"0x0124a000\" added=\"2025-06-13T19:27:57Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4441\" file=\"ntoskrnl.exe\" hash=\"7e77908ef98f01dfc01815141888fba1a38942d9011bc1a8328de719d9ef559b\" timestamp=\"0x5109500c\" size=\"0x0124a000\" added=\"2025-06-14T19:47:51Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4441\" file=\"lxcore.sys\" hash=\"199107a9378155eede5cf138128dda350a1db81be46e3179ad5a3815b6460d30\" timestamp=\"0x773eca90\" size=\"0x0010e000\" added=\"2025-06-14T19:47:51Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4451\" file=\"ntoskrnl.exe\" hash=\"ee8088fc87ddade57ca163f575ba2af0ff0bdaad826ed303f22eb32d5f845640\" timestamp=\"0xeb894663\" size=\"0x0124a000\" added=\"2025-06-24T22:12:14Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4452\" file=\"ntoskrnl.exe\" hash=\"bac070933b4ea373338bb85a6250ab011213bc692a63282f2c74ab78fb086cf1\" timestamp=\"0xd9f872d0\" size=\"0x0124a000\" added=\"2025-06-24T22:12:14Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4483\" file=\"ntoskrnl.exe\" hash=\"c2e8a1114810227d384d75da4225e4b9ee4ac9cfeccdd891bf3c989aa381a7d1\" timestamp=\"0xee2dbbd8\" size=\"0x0124a000\" added=\"2025-06-28T02:27:55Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4484\" file=\"ntoskrnl.exe\" hash=\"636927558b9846d6333e0292ba8bed6ae67187f4d6e22fbc311e660c6b0ef6c7\" timestamp=\"0xa7669d53\" size=\"0x0124a000\" added=\"2025-06-28T02:27:55Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4520\" file=\"ntoskrnl.exe\" hash=\"4d01ca65c33dd93680ce857af30fca0ec7e0d15edf390b8e1f80ef7d845afee3\" timestamp=\"0xbc42fb75\" size=\"0x0124a000\" added=\"2025-06-28T15:48:40Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4648\" file=\"ntoskrnl.exe\" hash=\"9fa8c3c99dbc67082a11340f7126bfed1b9e61228d7bad8db2902b0d9a42257e\" timestamp=\"0x9fae64cc\" size=\"0x0124a000\" added=\"2025-07-10T01:24:18Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4652\" file=\"ntoskrnl.exe\" hash=\"0095391e14924179177093663af8c50b11af04fe5442a90311b06c5877d61a6f\" timestamp=\"0x881ddc24\" size=\"0x0124a000\" added=\"2025-07-08T22:13:00Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4656\" file=\"ntoskrnl.exe\" hash=\"269949d2b739c4e767578afe47e5a4f999f02d4f16a3b71fa9476e52b0625345\" timestamp=\"0x1b40e18e\" size=\"0x0124a000\" added=\"2025-07-17T01:08:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4733\" file=\"ntoskrnl.exe\" hash=\"7fcbc042ae92d3509d397145d1a62161b8117c70758ee982bddffa4a4cd6e480\" timestamp=\"0x81ba489e\" size=\"0x0124a000\" added=\"2025-07-17T01:08:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4741\" file=\"ntoskrnl.exe\" hash=\"819c058d7e19c3b29cabe2be822947428329088093d662694355660f8a10f1c7\" timestamp=\"0x6789d282\" size=\"0x0124a000\" added=\"2025-07-21T06:28:17Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4762\" file=\"ntoskrnl.exe\" hash=\"49f37f80686502cd409d3de34b4a942fb9a2ddb1837fb7e229e2ecda718e6813\" timestamp=\"0xce8713cf\" size=\"0x0124a000\" added=\"2025-07-23T02:01:02Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4768\" file=\"ntoskrnl.exe\" hash=\"b91aaa81f42ecf0951b86cadec2927dd33db6fc7d75474495bf311f88b11f0ad\" timestamp=\"0x190c80ed\" size=\"0x0124a000\" added=\"2025-07-23T02:01:02Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.4946\" file=\"ntoskrnl.exe\" hash=\"6245efc78bb2e51d6757180ca9de2cf4e28fa629654be346f9bd4b591786b84c\" timestamp=\"0x92f5d4cd\" size=\"0x0124a000\" added=\"2025-08-13T21:37:12Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5059\" file=\"ntoskrnl.exe\" hash=\"16c11960b35b603605c683630f38d3abb34198e62ecafbde8f4be9ad423e0923\" timestamp=\"0xd2454b0b\" size=\"0x0124a000\" added=\"2025-08-30T18:01:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5061\" file=\"ntoskrnl.exe\" hash=\"f1e936391722b87d3a3bc44ab6ad66c142be4f1dcee0bb66439635ec03a98387\" timestamp=\"0x1694829e\" size=\"0x0124a000\" added=\"2025-08-29T21:12:06Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5074\" file=\"ntoskrnl.exe\" hash=\"2754fafa1de3956e06b8c6156828e6d362f0307bcc017c98dd93683fe886903b\" timestamp=\"0xd3296133\" size=\"0x0124a000\" added=\"2025-08-30T18:01:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5510\" file=\"ntoskrnl.exe\" hash=\"cd097b39e913596a6caa703a900bed7503beff0d1ef2a85b118e30c6975438ec\" timestamp=\"0x8690e5d6\" size=\"0x01249000\" added=\"2025-03-28T03:59:19Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5516\" file=\"ntoskrnl.exe\" hash=\"8df757972ebb12087c52f897953601c10f66df87ff947638ad1e5de2f59a9b6a\" timestamp=\"0xafa5a31c\" size=\"0x0124a000\" added=\"2025-04-05T04:20:29Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5516\" file=\"lxcore.sys\" hash=\"de1a3853df5c45963c8e64cdd2dfa1462c79522ec06d9ecda10591691bc20dbb\" timestamp=\"0x302eb8fb\" size=\"0x0010e000\" added=\"2025-05-10T01:12:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5518\" file=\"ntoskrnl.exe\" hash=\"1de398f0e0ae9b15d0909934d973b421c5d3b8a4ae00ecede3174b701ce58d6c\" timestamp=\"0x790621b9\" size=\"0x0124a000\" added=\"2025-04-05T04:20:29Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5518\" file=\"lxcore.sys\" hash=\"319db9744bb4eb54403f2790adbe9a813dd3e181241f0776ea13aa2d4f7c6ac3\" timestamp=\"0x98511ba8\" size=\"0x0010e000\" added=\"2025-04-05T04:20:29Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5551\" file=\"ntoskrnl.exe\" hash=\"f0be22857956e92db7f946212af6a49fe172184a73c1d2e1e6bd1179b8cf011b\" timestamp=\"0x75405c33\" size=\"0x0124a000\" added=\"2025-04-12T23:13:14Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5562\" file=\"ntoskrnl.exe\" hash=\"3897097e8aafbb3cb2cb0c7252434838dea88ea01b45d1380d1c233209274df6\" timestamp=\"0x91d68b88\" size=\"0x0124a000\" added=\"2025-04-23T00:45:13Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5570\" file=\"ntoskrnl.exe\" hash=\"10d9fd930c67500a8cf7f2f4e2942ce42f0ebd26fbeefb288a9e87ecfb6cd1b2\" timestamp=\"0xa1911f53\" size=\"0x0124a000\" added=\"2025-04-26T20:45:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5581\" file=\"ntoskrnl.exe\" hash=\"ec8453ad6d1363f1645de0cb51d4fe0f190d5e9b700411b02057f0de14112ac0\" timestamp=\"0x1f147405\" size=\"0x0124a000\" added=\"2025-05-10T01:12:18Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5581\" file=\"lxcore.sys\" hash=\"e7a0ec4b119c943b61e46ae5dbfd9f245ec609a026881bd908002f09a1e12c63\" timestamp=\"0x7a4a869c\" size=\"0x0010e000\" added=\"2025-05-10T01:12:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5590\" file=\"ntoskrnl.exe\" hash=\"6a9d3fabf484f294a77c0ee1fdb2d98469ba99e2688438d38045b085a98f1944\" timestamp=\"0x91f843dd\" size=\"0x0124a000\" added=\"2025-05-13T22:56:23Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5600\" file=\"ntoskrnl.exe\" hash=\"e3f8fcaeb82c0d07bcac9880fc2f38c245dcc4e9ebdf77a4411749498e621b4d\" timestamp=\"0x4bb6510c\" size=\"0x0124a000\" added=\"2025-05-13T22:56:23Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5601\" file=\"ntoskrnl.exe\" hash=\"82bdc6974ab5c0aca10c9c181eff9fa6cca5b7aa92d99ff172052b32d3973438\" timestamp=\"0xdd7ecebb\" size=\"0x0124a000\" added=\"2025-05-22T02:15:04Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5603\" file=\"ntoskrnl.exe\" hash=\"aedf99148d4305f0d9bcfc509446b6a5a5e3fabc649e99f148c8a63ce47f7c31\" timestamp=\"0x12a61249\" size=\"0x0124a000\" added=\"2025-05-22T02:15:04Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5622\" file=\"ntoskrnl.exe\" hash=\"f6be03e771a2d31f87ae89baae6ebc64915b8644a261265a97cebbdfb5d53300\" timestamp=\"0x7fe83b41\" size=\"0x0124a000\" added=\"2025-06-07T14:16:57Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5641\" file=\"ntoskrnl.exe\" hash=\"489dde8ca246174140ed6195f353c29d3a0e385851d8e5dd3d64cc1d47e22381\" timestamp=\"0x03a3f8d5\" size=\"0x0124a000\" added=\"2025-06-10T13:19:34Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5651\" file=\"ntoskrnl.exe\" hash=\"a4a29133552416b776ca9deaa316cfdf4ac125c19a080d740981d3683f704976\" timestamp=\"0x593908da\" size=\"0x0124a000\" added=\"2025-06-14T19:47:51Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5651\" file=\"lxcore.sys\" hash=\"e9eb69f3eb37a76885c12d4dde6d0daab51d8ca89a802376460cef963ff0befb\" timestamp=\"0xf4520501\" size=\"0x0010e000\" added=\"2025-06-14T19:47:51Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5661\" file=\"ntoskrnl.exe\" hash=\"9b9f3463176daa8cde4254d7738aba71d4f564c889f96c66203440ebd657efa4\" timestamp=\"0xb0ede1ba\" size=\"0x0124a000\" added=\"2025-06-24T22:12:14Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5670\" file=\"ntoskrnl.exe\" hash=\"fd8a30adee7fd459d45bea1b3a0d9a4f97edd74c4f8c92fb73c652ecffd4333c\" timestamp=\"0xa7c5195a\" size=\"0x0124a000\" added=\"2025-06-28T15:48:40Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5702\" file=\"ntoskrnl.exe\" hash=\"f408eab8d01db7db3b01aecf18d04cc2b2cc2938d5007739f4191b7be66b2374\" timestamp=\"0xf04acaf9\" size=\"0x0124a000\" added=\"2025-07-17T01:08:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5710\" file=\"ntoskrnl.exe\" hash=\"bc6bf04e524de09223d0cf4c8410fabd03986feb61a200beacc9e754a4a64a0a\" timestamp=\"0xa3f47de4\" size=\"0x0124a000\" added=\"2025-07-21T06:28:17Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5720\" file=\"ntoskrnl.exe\" hash=\"d765968b16ef791dedcf915a8fbe7802557b6bf3b394257ec6cf9a600da94cab\" timestamp=\"0x9ac1abee\" size=\"0x0124a000\" added=\"2025-07-29T22:48:22Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5722\" file=\"ntoskrnl.exe\" hash=\"25442b59a41151194e46e5266dfa44bf3aaf619adadc63cceef013e22a01b805\" timestamp=\"0x3075e71a\" size=\"0x0124a000\" added=\"2025-07-29T22:48:22Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5733\" file=\"ntoskrnl.exe\" hash=\"afa0f9d33211c059074298a7c3b0c3cf66405551888a309fbc637f798be9ac65\" timestamp=\"0x4ef3a216\" size=\"0x0124a000\" added=\"2025-08-03T19:14:39Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5742\" file=\"ntoskrnl.exe\" hash=\"c9e9055857afe6220e44768fd85faab573641ceb88e5ae2b6513cce972099360\" timestamp=\"0xf0239025\" size=\"0x0124a000\" added=\"2025-08-12T05:13:33Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5751\" file=\"ntoskrnl.exe\" hash=\"6769838103e945f9cc0c405db9ebfab186ed86acdb76f56d2a9c2bd6fc51f257\" timestamp=\"0xbb3bfd1b\" size=\"0x0124a000\" added=\"2025-08-16T02:03:03Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5761\" file=\"ntoskrnl.exe\" hash=\"330ab5f28c9e7796d161d0ac833e0a6e77a387182a28a97aacd8b8bf54861abb\" timestamp=\"0x68103c0a\" size=\"0x0124a000\" added=\"2025-08-23T19:31:57Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5770\" file=\"ntoskrnl.exe\" hash=\"858480e7f64610456907a0209e50e64bcaa31bef92d5dd1246ebff5bea93e47d\" timestamp=\"0x7fbf5cb0\" size=\"0x0124a000\" added=\"2025-08-30T18:01:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.5790\" file=\"ntoskrnl.exe\" hash=\"6124d2503d9d85c750998e19806c8e4e9fa5a34a9600af8ace6e9ead5ff5bb0a\" timestamp=\"0x6d17b759\" size=\"0x0124a000\" added=\"2025-09-11T03:22:38Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6584\" file=\"ntoskrnl.exe\" hash=\"c667739004d1186daca2fd3fe7ccde61394bc068f385b4bb8cd5364d3005a734\" timestamp=\"0xbadfd933\" size=\"0x0124a000\" added=\"2025-09-11T03:22:38Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6682\" file=\"ntoskrnl.exe\" hash=\"480bc942790420ea3cd5e44ab27e05ae62bbe60dfa52403584e560b7ad5b941d\" timestamp=\"0x5a8aaabf\" size=\"0x0124a000\" added=\"2025-09-14T14:54:27Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6690\" file=\"ntoskrnl.exe\" hash=\"309698c615d3aac203eb1fe16e5ea46d877988c39ba4c69206d47d4fc667cdbf\" timestamp=\"0x506c038b\" size=\"0x0124a000\" added=\"2025-09-21T13:49:59Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6713\" file=\"ntoskrnl.exe\" hash=\"cd2b487f799d14cb669c20192f8d6788a17ee87e1c250ac1b4144a74504d0b36\" timestamp=\"0xc11ff708\" size=\"0x0124a000\" added=\"2025-10-01T01:37:34Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6717\" file=\"ntoskrnl.exe\" hash=\"521a63c4cc80af70e0d70e16f4dbb5ae69744b8664e64569844c51429d607737\" timestamp=\"0x666efcce\" size=\"0x0124a000\" added=\"2025-10-01T01:37:34Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6725\" file=\"ntoskrnl.exe\" hash=\"cdb40cae0881bf2655b9741043ab07bb7491b0f997d391bfdffacb0c5c493c02\" timestamp=\"0xe36d45d7\" size=\"0x0124a000\" added=\"2025-10-01T01:37:34Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6760\" file=\"ntoskrnl.exe\" hash=\"905425e4c1f3c39b01cda873da39299f6175bac4af1f43ddd47ba57cbf783db0\" timestamp=\"0x81b67493\" size=\"0x0124a000\" added=\"2025-10-01T01:37:34Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6772\" file=\"ntoskrnl.exe\" hash=\"28b3225fbf25f5ed0a20894f29e6bb06200a60093debcbda1ecd4e0b4b9d59ae\" timestamp=\"0x3eecfac4\" size=\"0x0124a000\" added=\"2025-10-09T21:10:38Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6780\" file=\"ntoskrnl.exe\" hash=\"65a6edce92fec59d242bb8ab697354bee89f8b77a84174f64dbc238d1d7de657\" timestamp=\"0xa53d9c35\" size=\"0x0124a000\" added=\"2025-10-15T03:12:43Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6891\" file=\"ntoskrnl.exe\" hash=\"d163d9c3d8a71154d2ddf8949c158eac8d24084da7c76916d3e635b5aeda2f57\" timestamp=\"0x08698391\" size=\"0x0124a000\" added=\"2025-10-16T23:37:47Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6899\" file=\"ntoskrnl.exe\" hash=\"78b10a6b8563a9e227d6744bb35fc712cc4fe75f83fbaeb65d35aed696613f0c\" timestamp=\"0xe4b5386e\" size=\"0x0124a000\" added=\"2025-10-15T03:12:43Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6901\" file=\"ntoskrnl.exe\" hash=\"7086d81053e3fde3e3dcfc053536fedec8f2d0223184b72514d79d004a239f4e\" timestamp=\"0xfb3d87d1\" size=\"0x0124a000\" added=\"2025-10-24T14:15:26Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6970\" file=\"ntoskrnl.exe\" hash=\"3d24bea8caf349cc276ec8074a7b8e6861d9d3f9585de52b3d5459d3249d1bfd\" timestamp=\"0x428f9d4a\" size=\"0x0124a000\" added=\"2025-10-24T14:15:26Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6972\" file=\"ntoskrnl.exe\" hash=\"f390f819b38fef3c38af4b422d09ff8d6b75898feded02f6a46790bbeb80c71e\" timestamp=\"0xe5675b45\" size=\"0x0124a000\" added=\"2025-10-24T14:15:26Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.6982\" file=\"ntoskrnl.exe\" hash=\"86b8a87461539b8e147af59f2f5ef2f71640b6000f30f1dccb2add40828b560f\" timestamp=\"0xe83a6b18\" size=\"0x0124a000\" added=\"2025-10-29T20:10:48Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7014\" file=\"ntoskrnl.exe\" hash=\"f2cfc0da9ecce6e6381b55af2da27e6ffc18bb2d29c45f5c7c840841c42e0d1b\" timestamp=\"0xa65aff5a\" size=\"0x0124a000\" added=\"2025-10-29T20:10:48Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7015\" file=\"ntoskrnl.exe\" hash=\"8401216b8d41d01630270d95b4f5844d8ede96fa4b8b1eb64eef40df815cf96a\" timestamp=\"0xe798b6e3\" size=\"0x0124a000\" added=\"2025-10-29T20:10:48Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7019\" file=\"ntoskrnl.exe\" hash=\"bf80e04dbfb3dc98d44a3d59b4e9b4b4549e46eb5af18868e209c02bc286301a\" timestamp=\"0xa6bdcbf0\" size=\"0x0124a000\" added=\"2025-10-29T20:10:48Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7050\" file=\"ntoskrnl.exe\" hash=\"e406ed7aa691aa0e670f36417b3ee802f312c95025be584f219f9659f8dccfa2\" timestamp=\"0xe8b1c2c9\" size=\"0x0124a000\" added=\"2025-11-02T15:30:04Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7051\" file=\"ntoskrnl.exe\" hash=\"6dd4acdef11f3f278626e92a237557d0257855eccde183f72b55b4d3f48d8162\" timestamp=\"0x1f41f700\" size=\"0x0124a000\" added=\"2025-11-01T02:59:40Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7070\" file=\"ntoskrnl.exe\" hash=\"e39224dd1f0782ffd515e0ae423d0e15d4e7959be5a36a614d1033fe2c90ee80\" timestamp=\"0xf528b77a\" size=\"0x0124a000\" added=\"2025-11-09T14:13:48Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7149\" file=\"ntoskrnl.exe\" hash=\"e39113634fc23f6174fdf7451f2228c8deca160f3dc95eda0c58a5444f28bb65\" timestamp=\"0xb3daf978\" size=\"0x0124a000\" added=\"2025-11-13T23:46:44Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7171\" file=\"ntoskrnl.exe\" hash=\"3bff7584f3ac87c8b435c7a0f9dc978e4033d4928ffd0dcc53aeb516ca28c5aa\" timestamp=\"0x49a21626\" size=\"0x0124a000\" added=\"2025-11-12T23:55:08Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7262\" file=\"ntoskrnl.exe\" hash=\"470db5d94a39eddfa84af074ecceb960234ccde5737c01e95f8dc434a5de6035\" timestamp=\"0x7c37950e\" size=\"0x0124a000\" added=\"2025-11-20T04:01:51Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7270\" file=\"ntoskrnl.exe\" hash=\"ffa73a55299fbe60d3ba1dd2167a66c8e9d1ee3e1db8babcf1f92730e51e8bca\" timestamp=\"0x8ba10b37\" size=\"0x0124a000\" added=\"2025-11-25T23:06:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7271\" file=\"ntoskrnl.exe\" hash=\"08dd9d86f0c14e81c4a9d646cca6cf124cf6fed7a3a1d7323d1330a3cf877583\" timestamp=\"0x29b1cd2c\" size=\"0x0124a000\" added=\"2025-11-25T23:06:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7297\" file=\"ntoskrnl.exe\" hash=\"691493f7edb789b03f16635c3eaf2d590ec9a59a621cba3269453417346198dc\" timestamp=\"0xdba2f1ee\" size=\"0x0124a000\" added=\"2025-12-10T04:39:55Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7309\" file=\"ntoskrnl.exe\" hash=\"727327ca037d4f2a211035a7257256dba50cf2c293f1451bbdc3967e1f28bac7\" timestamp=\"0x5ca975d0\" size=\"0x0124a000\" added=\"2025-12-03T19:03:15Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7340\" file=\"ntoskrnl.exe\" hash=\"bc3cfc010afc021a5503d50204c73ce9efde76cfe264c27af28e46308bf24efe\" timestamp=\"0xff5fc320\" size=\"0x0124a000\" added=\"2025-12-10T04:39:55Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7344\" file=\"ntoskrnl.exe\" hash=\"8ab9c19a62e12e0c891b54282f6c2211796058be0ef9b48542a4802b82453ee9\" timestamp=\"0x68b7f1d3\" size=\"0x0124a000\" added=\"2025-12-06T03:12:56Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7447\" file=\"ntoskrnl.exe\" hash=\"0e3ec319e782d3413198575ee719538b9b482cbc8c5bbd0a72309c343f8525bf\" timestamp=\"0x602463cb\" size=\"0x0124a000\" added=\"2025-12-10T04:39:55Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7462\" file=\"ntoskrnl.exe\" hash=\"1a23f727ed0c8c4d1f4f471cdcd63da37cc32442eccca4ad0d74568afb1a9292\" timestamp=\"0x5f94a5f7\" size=\"0x0124a000\" added=\"2025-12-10T04:39:55Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7520\" file=\"ntoskrnl.exe\" hash=\"a1264977fc88dd71b139b598f1b3cb5a0f2c0740bf4703861ebeb4e9aa4b5b87\" timestamp=\"0x3a2303c2\" size=\"0x0124a000\" added=\"2025-12-24T02:56:52Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7523\" file=\"ntoskrnl.exe\" hash=\"d3c6c7b380bd399c81233670432a19dd4bbd57a890aba45666900e630b311f87\" timestamp=\"0x3b8346e6\" size=\"0x0124a000\" added=\"2025-12-24T02:56:52Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7526\" file=\"ntoskrnl.exe\" hash=\"2e919f565995bd5a0dce3081cb5d8fa778aa41ecffa7b308582489713a25939d\" timestamp=\"0xdccf13e8\" size=\"0x0124a000\" added=\"2026-01-29T10:23:29Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7535\" file=\"ntoskrnl.exe\" hash=\"bc9b5804cb2490fe81eab9a339084ea72bd4fd03237c0225e33498c98a0c3cdd\" timestamp=\"0x6a773f5b\" size=\"0x0124a000\" added=\"2026-01-15T04:51:11Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7618\" file=\"ntoskrnl.exe\" hash=\"d0b60ba43070f883d43b74f6e3a6a423fea5e6b4b73e446e46712a1cbc3ae6d7\" timestamp=\"0xbe8bb436\" size=\"0x0124a000\" added=\"2026-01-17T15:14:22Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7623\" file=\"ntoskrnl.exe\" hash=\"d27000d23d953a2f51691c7d725aa8c41a0186e1a35136be69342b75520ddd22\" timestamp=\"0xfd5ee62f\" size=\"0x0124a000\" added=\"2026-01-15T04:51:11Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7627\" file=\"ntoskrnl.exe\" hash=\"13a5903b85d8e5c70bf5ecf793309d5a2f37e11006cd8cf49627489fa8f581d9\" timestamp=\"0xb3ca3b61\" size=\"0x0124a000\" added=\"2026-01-22T02:43:17Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7653\" file=\"ntoskrnl.exe\" hash=\"2d4cd8aa7fcaff1da5474982505176af2604ef06380c425e6dec1283f1520cdf\" timestamp=\"0x91b35a43\" size=\"0x0124a000\" added=\"2026-01-17T15:14:22Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7670\" file=\"ntoskrnl.exe\" hash=\"a0404800750dd218d4812e4ecf3f1c0cd7a55ede2cb457e15f05e81f40c33e23\" timestamp=\"0xbd1b0335\" size=\"0x0124a000\" added=\"2026-01-29T10:23:29Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7674\" file=\"ntoskrnl.exe\" hash=\"604e484c67217dffc03ee6031037e5958e94aa9eafd08ebfd8862bd8f1dca933\" timestamp=\"0x8870dd53\" size=\"0x0124a000\" added=\"2026-01-29T10:23:29Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7701\" file=\"ntoskrnl.exe\" hash=\"201824c2ba41cba813c08b33dcf2d132a566141be873c5bc1a30ec52eba10d0f\" timestamp=\"0x5595d4c7\" size=\"0x0124a000\" added=\"2026-02-01T01:21:00Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7705\" file=\"ntoskrnl.exe\" hash=\"996287aaba403fffe272cf391550649b853d79330e85c77105bc94b098c5c824\" timestamp=\"0xe5908dd1\" size=\"0x0124a000\" added=\"2026-02-01T01:21:00Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7724\" file=\"ntoskrnl.exe\" hash=\"41ce727a6eaec30b66fbc7695aad610553f4daffa36f2b1add73e2a30cf933cf\" timestamp=\"0x8e87106d\" size=\"0x0124a000\" added=\"2026-02-05T23:25:24Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7733\" file=\"ntoskrnl.exe\" hash=\"081c1b60ec45c9393046585d2190bddbbd4f792cc3db535ba9ef178955934fd7\" timestamp=\"0x0cf04136\" size=\"0x0124a000\" added=\"2026-02-05T23:25:24Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7755\" file=\"ntoskrnl.exe\" hash=\"a0d7bb7e08960a78b9cc70671926055b2fe3eea789a91e472d8725413e6df88b\" timestamp=\"0x79a73308\" size=\"0x0124a000\" added=\"2026-02-11T00:54:58Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7760\" file=\"ntoskrnl.exe\" hash=\"2fae799efd73a4ec1258df42dd104a7936856c3db0c294e965c002a18756b0e9\" timestamp=\"0xe00f32d8\" size=\"0x0124a000\" added=\"2026-02-11T00:54:58Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7824\" file=\"ntoskrnl.exe\" hash=\"beb03466823b2cc0e3b371f90dda2275878d663d93938e1b73e3105d805d9e82\" timestamp=\"0x16b4edc7\" size=\"0x0124a000\" added=\"2026-02-11T00:54:58Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7859\" file=\"ntoskrnl.exe\" hash=\"2e5789021a79be7a53a214ddb5b678c0213f7ea7d8fb85250e9dee09eb8fdf51\" timestamp=\"0x5c7d2a1e\" size=\"0x0124a000\" added=\"2026-02-19T05:09:13Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7872\" file=\"ntoskrnl.exe\" hash=\"479b755d99795bdff07304db8e6b72ae56e4f6c6a20e112e4e8c90c27a2d0704\" timestamp=\"0xa2b9ea18\" size=\"0x0124a000\" added=\"2026-02-25T16:03:39Z\">33</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7877\" file=\"ntoskrnl.exe\" hash=\"54b1a3634fddcd3f0a4bfbad9627d0132fef387ab35195a6665cd7be15cda333\" timestamp=\"0xb40f1866\" size=\"0x0124a000\" added=\"2026-02-25T16:03:39Z\">33</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7920\" file=\"ntoskrnl.exe\" hash=\"7fdb870ebddffce916fc7f6b44a45a3067f9f1b17d5fefbd70037bad204140bc\" timestamp=\"0x05f42608\" size=\"0x0124a000\" added=\"2026-02-25T16:03:39Z\">33</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7931\" file=\"ntoskrnl.exe\" hash=\"0bc4ce70370fbefeaaa8985454290843416b7005db57b1856e20c14ee97897cc\" timestamp=\"0x0a3183bf\" size=\"0x0124a000\" added=\"2026-03-04T03:13:34Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7939\" file=\"ntoskrnl.exe\" hash=\"1e5d8d3e09b0a41b355bbecc7ab555ebad8ed6bc3630f2f7fc51c5a5ee6ce37d\" timestamp=\"0x1e2fc41e\" size=\"0x0124a000\" added=\"2026-03-11T23:28:21Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7961\" file=\"ntoskrnl.exe\" hash=\"55678329e9a475fbb30c27791631e5b578c723392abc4efe9216ddca71d5e39e\" timestamp=\"0xc89b8e26\" size=\"0x0124a000\" added=\"2026-03-11T23:28:21Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.7965\" file=\"ntoskrnl.exe\" hash=\"7952c32324a217eeb07ebc42ffa92ba2f7cb7f77f6eadd16f08252ab8178db9a\" timestamp=\"0x2fd0feda\" size=\"0x0124a000\" added=\"2026-03-11T23:28:21Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.8036\" file=\"ntoskrnl.exe\" hash=\"5bb49f8383e38b26ef0c18f3087db3be541e99143b80b92d2f83d824b7e5301c\" timestamp=\"0x84268839\" size=\"0x0124a000\" added=\"2026-03-11T23:28:21Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.8062\" file=\"ntoskrnl.exe\" hash=\"ed6e304153c486a36363742a59f86463602bec5d092bf43f40aa6a02096c7cdf\" timestamp=\"0x2d940707\" size=\"0x0124a000\" added=\"2026-03-19T02:51:26Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26100.8068\" file=\"ntoskrnl.exe\" hash=\"80011fd4ef22328f9f55b67585667240b5d3239fc112515a27283560628a1ff7\" timestamp=\"0x033af5eb\" size=\"0x0124a000\" added=\"2026-03-14T04:38:17Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26200.5001\" file=\"ntoskrnl.exe\" hash=\"b3715d49cec1d1f4deb765973334c876d1c71ce3ec1d42a1232fcb9f380ac429\" timestamp=\"0xcea2a8b9\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26200.5001\" file=\"lxcore.sys\" hash=\"be615f0c70bd5bfca08984386f5caf82e5c942cbd37e197e618643e4fb7f81f8\" timestamp=\"0xac13d30f\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26212.5000\" file=\"ntoskrnl.exe\" hash=\"e3573c0b744aa7af11a38c294937158687ed7738429e35e9f82a64ada856cdd5\" timestamp=\"0x95ad7819\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26212.5000\" file=\"lxcore.sys\" hash=\"c7f32a5113f456c8cafb4541a213d5111f69aeec26956f8ff56ac72adda9e0f2\" timestamp=\"0xcba71fd1\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26217.5000\" file=\"ntoskrnl.exe\" hash=\"34d2464a5f8e65fa3753c089b0d3b09e358662d5b70660d4c0fb25d7c5b7fa9f\" timestamp=\"0x6996a18e\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26217.5000\" file=\"lxcore.sys\" hash=\"82c5a77167f93743e46a5dd6c5418e10b8895030330df10062a309fed140d951\" timestamp=\"0xaf2affc7\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26227.5000\" file=\"ntoskrnl.exe\" hash=\"0dc9da9956389a134fffd2e541eee4eabef35561c0057d1864c3664e0ed537a4\" timestamp=\"0x9bf41d05\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26227.5000\" file=\"lxcore.sys\" hash=\"310fd62fa596f39c5bd8d934875668b4531f4d8134a94e9122e91534c09e624d\" timestamp=\"0xf088718d\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26231.5000\" file=\"ntoskrnl.exe\" hash=\"18aa4c77e408092ad54a8b0b18361dfe7539c19e9f5f7dffb5c6f74ac8a6f687\" timestamp=\"0xadbc20e2\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26231.5000\" file=\"lxcore.sys\" hash=\"bc5403f759cbc453736cfaa5145092deaf176cd63c63b69fe28174b43031053d\" timestamp=\"0xd9b522d8\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26236.5000\" file=\"ntoskrnl.exe\" hash=\"c6ab03376908651b9f231f430703460b90a8b0d9b115a66d275548467e1b4467\" timestamp=\"0x44b0e1ec\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26236.5000\" file=\"lxcore.sys\" hash=\"b26e33f6b7ca1ccf03fec3291c60eef4fd5c847059b936c37d942da4005eefdd\" timestamp=\"0x208890fe\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26241.5000\" file=\"ntoskrnl.exe\" hash=\"a8947933908bfe8b48b149ee7c18f0d117f35bc468014b7a6e306a3acf221cf7\" timestamp=\"0x8a8d8935\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26241.5000\" file=\"lxcore.sys\" hash=\"b9d8addb760f915397f90891bc80caa086d11672e99d3bfd84bd0ded8e4ab1f2\" timestamp=\"0xf700ffe1\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26244.5000\" file=\"ntoskrnl.exe\" hash=\"0179aca7bc201b8ba143937781a379e121ac826de6ccd4cd8928eb2a54286da2\" timestamp=\"0x913ea671\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26244.5000\" file=\"lxcore.sys\" hash=\"fe126edb2675da428d1c2f619cb6450e2be3e34f7864528a8a61e8efb92b08a9\" timestamp=\"0xd0290104\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26252.5000\" file=\"ntoskrnl.exe\" hash=\"41490a1edfe3a4efb404e77deddf991f1d90221058ec2e473cfb084884add94c\" timestamp=\"0xd242f1ef\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26252.5000\" file=\"lxcore.sys\" hash=\"9c87347744f0c9bb2d766c3a9a4c372fbc15a4ddb347b01c877de96943ccd22d\" timestamp=\"0xa8000952\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26257.5000\" file=\"ntoskrnl.exe\" hash=\"c8f3b2e6619d1ce9bb085da4c4c5ffba9f749e912d2184b79f9480722f5a8ab3\" timestamp=\"0xcd1487fc\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26257.5000\" file=\"lxcore.sys\" hash=\"00c819f5231d24a52eb2ff013772557a78dc0ffdd1b603b2376ff91a7051b631\" timestamp=\"0x9b027053\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.26334.5000\" file=\"ntoskrnl.exe\" hash=\"6887d0249cec14c788cf20cc5ea4d0ff2aef3fcfd78a0548e98fbf48fc855f53\" timestamp=\"0x9cef83ab\" size=\"0x01249000\" added=\"2025-02-17T22:56:35Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26404.5000\" file=\"ntoskrnl.exe\" hash=\"69502c5ad0ccf510e61ed636973f5ea6332d86236b78b8ca095afe47aae09511\" timestamp=\"0xb97d26a0\" size=\"0x0124a000\" added=\"2025-06-26T02:06:12Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.26470.1000\" file=\"ntoskrnl.exe\" hash=\"84de6bc2e2e0f2ab8a6b856cffed26819294f9d5b256dc463cefb19cd26a3de9\" timestamp=\"0xa7ba7cca\" size=\"0x0124a000\" added=\"2025-09-02T00:24:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27686.1000\" file=\"ntoskrnl.exe\" hash=\"28a68886283da2431c8d6ece1f93d89e880cbe424039a300bf70ddf41bd985a2\" timestamp=\"0x5f1f9c60\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27686.1000\" file=\"lxcore.sys\" hash=\"6c2234e0bab4177a7a139347c984b7bb568a60459c136bbfe7bdeb7f05c405b8\" timestamp=\"0x8c01ed6c\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27695.1000\" file=\"ntoskrnl.exe\" hash=\"8b040bacd3657556929d650117ff4b5604427fa8e09f5f0297b26b10e5c27e8a\" timestamp=\"0xbe823cd0\" size=\"0x01249000\" added=\"2024-09-12T01:41:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27695.1000\" file=\"lxcore.sys\" hash=\"3c84d631512cc36ed70180746f6b4982e9636fc55465e60aa158259c3d156387\" timestamp=\"0xd2b98e1a\" size=\"0x0010e000\" added=\"2024-09-12T01:41:05Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27718.1000\" file=\"ntoskrnl.exe\" hash=\"937931e938128ba9daadda8c2607f121859520db6346a87f5b13ef07dff4959f\" timestamp=\"0x43da0997\" size=\"0x01249000\" added=\"2024-10-12T01:50:50Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27718.1000\" file=\"lxcore.sys\" hash=\"e411d16b248e0fe9352d1dc7c370a3865648be8ad87a0752dcb250c62d2ecfc9\" timestamp=\"0xf392f008\" size=\"0x0010e000\" added=\"2024-10-12T01:50:50Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27723.1000\" file=\"ntoskrnl.exe\" hash=\"04d8aa85774dce6ae0da374da21d09e3c413ae3a0771b261cf35eaed975c6622\" timestamp=\"0x5fdfc673\" size=\"0x01249000\" added=\"2024-10-16T00:54:19Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27723.1000\" file=\"lxcore.sys\" hash=\"724d67d7f83687dbd52a1e606930bc320dbafcaacce03a5954ae6dc4db0ae943\" timestamp=\"0x3cf3a65d\" size=\"0x0010e000\" added=\"2024-10-18T02:50:06Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27729.1000\" file=\"ntoskrnl.exe\" hash=\"aa31d98ca6cc6a5170c4f13e6ca52ea0f03b448c93ec641bd5a0cd6d29c11aa7\" timestamp=\"0x3751b005\" size=\"0x01249000\" added=\"2024-10-20T15:35:22Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27729.1000\" file=\"lxcore.sys\" hash=\"465d912666e8e091e72f57163119a8698bb77984e8477aff82bb7c897663c2e5\" timestamp=\"0x8a0b5561\" size=\"0x0010e000\" added=\"2024-10-20T15:35:22Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27744.1000\" file=\"ntoskrnl.exe\" hash=\"bf8b4e6f9b2a71ee88ac1dcbec897933f3bb61d0b013d9f4859c38d8da80b69b\" timestamp=\"0xbaf18c33\" size=\"0x01249000\" added=\"2024-11-10T01:43:06Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27744.1000\" file=\"lxcore.sys\" hash=\"ade02b11befcef5b7a598672ae39ba0d84311b67612252908aa2bc03cd3fc46b\" timestamp=\"0xa324caa6\" size=\"0x0010e000\" added=\"2024-11-10T01:43:06Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27749.1000\" file=\"ntoskrnl.exe\" hash=\"dbec1f1ac91746c14786495cc86677ad21a0bf61846f64e9a650e4ab21e476d0\" timestamp=\"0x6d07e52f\" size=\"0x01249000\" added=\"2024-11-17T16:04:58Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27749.1000\" file=\"lxcore.sys\" hash=\"137742bbda1b1b2a5ab33dfc18d277e25ac67c2d07f04a65cfcf85b2a0075f3c\" timestamp=\"0x9b4044fa\" size=\"0x0010e000\" added=\"2024-11-17T16:04:58Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27754.1000\" file=\"ntoskrnl.exe\" hash=\"84a68ac9dbebcefedf73636544615af39f904ebf2e9ca823f6e1004a2648339b\" timestamp=\"0xc630afa4\" size=\"0x01249000\" added=\"2024-11-21T19:38:04Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27754.1000\" file=\"lxcore.sys\" hash=\"f09d30bffac5a21fd8cd631d5859f420dd27260fe090ae49c362ae0d5f4ce2be\" timestamp=\"0xc8ba1515\" size=\"0x0010e000\" added=\"2024-11-21T19:38:04Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27758.1000\" file=\"ntoskrnl.exe\" hash=\"fc5212c8fbfd2f45c3aed90d151acc8ed55be3317f54d7bbb95b550a1669e7c3\" timestamp=\"0x5bce93c6\" size=\"0x01249000\" added=\"2024-12-10T02:56:39Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27758.1000\" file=\"lxcore.sys\" hash=\"c75ccd4f57d01285ca0f3c0d5643e2240c629913aa9370429d36b270270d5050\" timestamp=\"0x843b7b9f\" size=\"0x0010e000\" added=\"2024-12-10T02:56:39Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27764.1000\" file=\"ntoskrnl.exe\" hash=\"2178a2cb58b1c6290b712d3024ed30f1bcaaf2fd690a9826b6e0ae0001198970\" timestamp=\"0x30eddb06\" size=\"0x01249000\" added=\"2024-12-13T00:14:01Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27764.1000\" file=\"lxcore.sys\" hash=\"6200f2e12fe3d28d61ff86051128a51e767a9c46b2761daeac5e2234f7d3a074\" timestamp=\"0xda1753b3\" size=\"0x0010e000\" added=\"2024-12-13T00:14:01Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27766.1000\" file=\"ntoskrnl.exe\" hash=\"64a3716d281d643eebcf4023a1fec8264f29d6239f4a5505af7507eebe7a0b7a\" timestamp=\"0xf2a4d9a7\" size=\"0x01249000\" added=\"2025-01-10T06:00:00Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27766.1000\" file=\"lxcore.sys\" hash=\"fbace37599226ea52ff24e7edd1ede7366f982eb8aea4be373e4d7839a753614\" timestamp=\"0x4c20eb20\" size=\"0x0010e000\" added=\"2025-01-10T06:00:00Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27768.1000\" file=\"ntoskrnl.exe\" hash=\"df489ea5ae892ab9a2002d717149abc228b857ee1559db92cfe5a0bb61632232\" timestamp=\"0x76ba34e1\" size=\"0x01249000\" added=\"2025-01-11T02:34:03Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27768.1000\" file=\"lxcore.sys\" hash=\"74c0ce5aa48ecf5afb7e9e494d621d7bea1888df220efd9891e69c58a84fcb9f\" timestamp=\"0x0b8fb8f6\" size=\"0x0010e000\" added=\"2025-01-11T02:34:03Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27774.1000\" file=\"ntoskrnl.exe\" hash=\"c37a4a498da34c3f8e00d5015d1341effd74ad3d346efd44b4669dd393968790\" timestamp=\"0x3e287643\" size=\"0x01249000\" added=\"2025-01-18T23:48:32Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27774.1000\" file=\"lxcore.sys\" hash=\"c09cd305bffb465aa98fa646a8d8d82c313e20b895c0d2f8a89e611a6de1dfca\" timestamp=\"0x0952b363\" size=\"0x0010e000\" added=\"2025-01-18T23:48:32Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27783.1000\" file=\"ntoskrnl.exe\" hash=\"7f9d2fa3f6d9533e85402f205671328d523d58b78069c2af83846e4d60b0334e\" timestamp=\"0xe468d142\" size=\"0x01249000\" added=\"2025-01-31T00:35:18Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27783.1000\" file=\"lxcore.sys\" hash=\"53f2c080b33eb34dfe68ef73a80f1396965feeec574591ca8f074653279f481f\" timestamp=\"0x5f8a980c\" size=\"0x0010e000\" added=\"2025-01-31T00:35:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27788.1000\" file=\"ntoskrnl.exe\" hash=\"6ad496d181a422846170599661c3aa3ced47a5e15cfd33a36a471b78fad3c7ae\" timestamp=\"0x275ba109\" size=\"0x01249000\" added=\"2025-02-09T01:52:18Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27788.1000\" file=\"lxcore.sys\" hash=\"c1e6d25ddb0b5fbad1a26616c5c928cc65146d11e184a03e46476d4fad81741f\" timestamp=\"0xc60a2fb2\" size=\"0x0010e000\" added=\"2025-02-09T01:52:18Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27802.1000\" file=\"ntoskrnl.exe\" hash=\"6d72cef8ccd319a7a9f043b5989e424eedd85db6600bc607ee0803d297b7ba64\" timestamp=\"0xbadd8b00\" size=\"0x0124e000\" added=\"2025-03-02T06:42:51Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27802.1000\" file=\"lxcore.sys\" hash=\"b746d632f2c68feec377251e074340c5056967a74334c1d633d2ab5e95d34d7f\" timestamp=\"0xa9612c42\" size=\"0x0010e000\" added=\"2025-03-02T06:42:51Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27808.1000\" file=\"ntoskrnl.exe\" hash=\"237b737e1516d99421402bead8dc6249f310e2f81ed2b4cf7717a09bdd4a89ee\" timestamp=\"0xfa14b76f\" size=\"0x0124e000\" added=\"2025-03-11T02:45:33Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27808.1000\" file=\"lxcore.sys\" hash=\"0f9bf224db1050d3d92d4c867130e9394450d3e552baa7907b33d9d8c9a46502\" timestamp=\"0xbf8a9d2f\" size=\"0x0010e000\" added=\"2025-03-11T02:45:33Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27813.1000\" file=\"ntoskrnl.exe\" hash=\"96c3ecf00c8731ea9b77a9088c142e3ec27a68e9c5cb2dae6149cb3be6f4f20f\" timestamp=\"0x586effe2\" size=\"0x0124e000\" added=\"2025-03-14T04:05:46Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27813.1000\" file=\"lxcore.sys\" hash=\"c47346166ed6f55a73d81a70ed1aaa7650da12d90f0f635a15d7e7b664179a73\" timestamp=\"0x53afc736\" size=\"0x0010e000\" added=\"2025-03-14T04:05:46Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27818.1000\" file=\"ntoskrnl.exe\" hash=\"ca1d73ea25fcdb4b78ba01aa427d950c25bb475337f58a6931901c19e0ad92db\" timestamp=\"0xbe4c247c\" size=\"0x0124f000\" added=\"2025-03-23T17:06:04Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27818.1000\" file=\"lxcore.sys\" hash=\"35ec2ebfaaac4ecbbe1fa845ec6c4439c4bf5fa8f249f3ae78bf5ab899db9b78\" timestamp=\"0x13606ed4\" size=\"0x0010e000\" added=\"2025-03-23T17:06:04Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27823.1000\" file=\"ntoskrnl.exe\" hash=\"9023714bf8b764b4ac402b5da957a3f09c6b8171f77d0abe60399d9bc78e824c\" timestamp=\"0x47ac9596\" size=\"0x0124f000\" added=\"2025-03-28T03:59:19Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27823.1000\" file=\"lxcore.sys\" hash=\"0d8a5da34aa0978d6c1c47e8fc48ae6edc16a5c322362445b4b51209bf3b5381\" timestamp=\"0x2bb00e2e\" size=\"0x0010e000\" added=\"2025-03-28T03:59:19Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27842.1000\" file=\"ntoskrnl.exe\" hash=\"d80910bf4f1b225878dd8809dbbde666d2dbabe68dfdaf5659cc031570d60ff2\" timestamp=\"0xda823981\" size=\"0x0124f000\" added=\"2025-04-25T01:12:29Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27842.1000\" file=\"lxcore.sys\" hash=\"c80c69f9f64171cdde376ffba8a2359304d91382efe98b78d0735d65a3b02763\" timestamp=\"0xecba5747\" size=\"0x0010e000\" added=\"2025-04-25T01:12:29Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27858.1000\" file=\"ntoskrnl.exe\" hash=\"a2a85d56e574fa072bb3c46ebc23a483b38a6f3a9b232477cc519c40b3b5226f\" timestamp=\"0x10d16c45\" size=\"0x0124f000\" added=\"2025-05-17T15:31:20Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27858.1000\" file=\"lxcore.sys\" hash=\"c9b08288d22813580ba444cef5f67dd3873da51c99daced8591abd7313a6b0c8\" timestamp=\"0xabca8152\" size=\"0x0010e000\" added=\"2025-05-17T15:31:20Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27863.1000\" file=\"ntoskrnl.exe\" hash=\"ed931b593d90a5c29396a77ef22bd567450ae206cf35e06c9e76e2bf558b5e2c\" timestamp=\"0x4a2345d4\" size=\"0x0124f000\" added=\"2025-05-24T14:17:56Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27863.1000\" file=\"lxcore.sys\" hash=\"7fe79153e3f0e027f16f6c5adcfa658562cb4a1c529b8bf1fc562c309015f407\" timestamp=\"0xfef99d35\" size=\"0x0010e000\" added=\"2025-05-24T14:17:56Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27868.1000\" file=\"ntoskrnl.exe\" hash=\"7be69d0081caeebb45f793aa9bba0638148c63415d6b04fe57da2047b6ac6f47\" timestamp=\"0xa92458fe\" size=\"0x0124f000\" added=\"2025-05-30T19:55:37Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27868.1000\" file=\"lxcore.sys\" hash=\"b4932a793a5be472074e0e2be949d2333b3dbaacce0d574f9874b3422e952413\" timestamp=\"0x062fbdd1\" size=\"0x0010e000\" added=\"2025-05-30T19:55:37Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27871.1000\" file=\"ntoskrnl.exe\" hash=\"773dee28013b678ad4ff450e1d5ba92a50d8170da4e9c735256fc184c07b3b55\" timestamp=\"0x03bba4bb\" size=\"0x0124f000\" added=\"2025-06-07T14:16:57Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27871.1000\" file=\"lxcore.sys\" hash=\"c9e429440285ede9ece336fd45b2bb2fc190f88316f47d18d59457762f4ba8cd\" timestamp=\"0x623f4658\" size=\"0x0010e000\" added=\"2025-06-07T14:16:57Z\">14</data>\n    <data arch=\"arm64\" version=\"10.0.27881.1000\" file=\"ntoskrnl.exe\" hash=\"654a1ed9adeaf379e9fd71a0826d9ff62efadde79ecda287745eedd195ae7b3a\" timestamp=\"0x9c6bec4c\" size=\"0x01450000\" added=\"2025-06-20T04:21:21Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27891.1000\" file=\"ntoskrnl.exe\" hash=\"03acb772e0550621db652b287ab924180680c1b2fcc66677527fe16a79b1acd0\" timestamp=\"0x3a11dc69\" size=\"0x01450000\" added=\"2025-07-05T15:11:44Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27898.1000\" file=\"ntoskrnl.exe\" hash=\"586ca2a4be95a787aab91a2836501f2412cf9ca7916bd86b7a1519658fd58068\" timestamp=\"0xdfd36ecd\" size=\"0x01450000\" added=\"2025-07-12T20:34:08Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27902.1000\" file=\"ntoskrnl.exe\" hash=\"35d4e81c0986ebd5683bd15e65e99a0572b8b99806729d07ca64ef4b07d270f3\" timestamp=\"0xb8dd7d73\" size=\"0x0144f000\" added=\"2025-07-19T02:10:13Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27909.1000\" file=\"ntoskrnl.exe\" hash=\"653373fb123c957cbf50c208fb56aeb6c2b4b2126ee274802aed0f601668ee63\" timestamp=\"0x98d185a1\" size=\"0x0144f000\" added=\"2025-07-26T16:12:52Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27913.1000\" file=\"ntoskrnl.exe\" hash=\"f4f12499c7bcffc4e9a53319b5a2b4041809a45eb48818c575c3ad1bb1e05902\" timestamp=\"0xffe6967a\" size=\"0x01450000\" added=\"2025-08-01T03:02:04Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27919.1000\" file=\"ntoskrnl.exe\" hash=\"613eed0d3a54898a3ebb42247669a290071e6c78ddae21e8158341608cd73a9e\" timestamp=\"0xaa6c29bb\" size=\"0x01450000\" added=\"2025-08-12T05:13:33Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27924.1000\" file=\"ntoskrnl.exe\" hash=\"d77acc4b8b3a9d01e3e6548941cad84dc0c97be1661ba5db7cc184952ebfcb5a\" timestamp=\"0x79021114\" size=\"0x01450000\" added=\"2025-08-16T02:03:03Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27928.1\" file=\"ntoskrnl.exe\" hash=\"5f40976256e5f06d2c7c2c6c3937fe443f96235d91e515a0628d9733a2b9781b\" timestamp=\"0x0e4e051f\" size=\"0x01450000\" added=\"2025-08-21T15:11:13Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27934.1\" file=\"ntoskrnl.exe\" hash=\"b3085cb2f98137cb80f68cca3110816bb1474b7729857d77f0c6f5f8e3d68f97\" timestamp=\"0x58773f3f\" size=\"0x01450000\" added=\"2025-08-30T18:01:05Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27938.1\" file=\"ntoskrnl.exe\" hash=\"ea165fe70e697515b0243513f604cebd3bd3398a143c24aa7bf49736f0709570\" timestamp=\"0x0fab37cf\" size=\"0x01450000\" added=\"2025-09-11T03:22:38Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27943.1\" file=\"ntoskrnl.exe\" hash=\"3b627fa730bc3b06d468766ad3642997a38ab62303ff63573552929679ee8095\" timestamp=\"0x8328a266\" size=\"0x01450000\" added=\"2025-09-12T23:16:14Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27950.1\" file=\"ntoskrnl.exe\" hash=\"07b9c8aff2d0d03ba87e6d5459019e2f1c6d94dfba20c3adebdf432b31e06744\" timestamp=\"0xb64c14dd\" size=\"0x01450000\" added=\"2025-09-21T13:49:59Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27954.1\" file=\"ntoskrnl.exe\" hash=\"e24ca3d35e2bb62576302933516f2198b7f7267bfbedf514cfdeaf587d4f6621\" timestamp=\"0x182dfc05\" size=\"0x01450000\" added=\"2025-09-27T02:00:45Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27959.1\" file=\"ntoskrnl.exe\" hash=\"15c834383f7ae13903b0742728a470a5b1a40f1c78183c584c43674119f342f0\" timestamp=\"0xe4e47d10\" size=\"0x01450000\" added=\"2025-10-09T21:10:38Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27965.1\" file=\"ntoskrnl.exe\" hash=\"9d2aa1613e75c773c41d0a80ad45a19f26e380c5bfda08fb2f87f97a4335c3ce\" timestamp=\"0x09772e8b\" size=\"0x01450000\" added=\"2025-10-09T21:10:38Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27971.1\" file=\"ntoskrnl.exe\" hash=\"ec58ff36f06d62d8d7f74f9431f74b3a9043c7f4a2d16dd94cc00bfcb7e0eebc\" timestamp=\"0x5f18ba62\" size=\"0x01450000\" added=\"2025-10-24T14:15:26Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27975.1\" file=\"ntoskrnl.exe\" hash=\"d17afb78d6c1ee9d2d50b75f65ade1cd3c159d743b33a3885dd345b3ece199dd\" timestamp=\"0x3a6baf75\" size=\"0x01450000\" added=\"2025-10-24T14:15:26Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27975.984\" file=\"ntoskrnl.exe\" hash=\"14b8147c793882f3f195c8a8a07562e5eabc438ee2721699a0c94e4e520a2b45\" timestamp=\"0x09204078\" size=\"0x01450000\" added=\"2025-10-29T20:10:48Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.27982.1\" file=\"ntoskrnl.exe\" hash=\"6cb56d548cb69fd160ba6ac90103194a5349b06869493589028409ac053d78c8\" timestamp=\"0x6b67a163\" size=\"0x01450000\" added=\"2025-11-05T04:35:14Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1\" file=\"ntoskrnl.exe\" hash=\"8002fb6a4de9d663e9176952845385e9dbc8bfcd97f8d4288be1faa39aeb86ae\" timestamp=\"0xcc2e25dd\" size=\"0x01450000\" added=\"2025-11-07T23:30:18Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.4\" file=\"ntoskrnl.exe\" hash=\"fab59a656a5f15dde4ecb0672b85d93525a8303ef8e7d1d3178c7fa8c0a549c5\" timestamp=\"0x7c352a3a\" size=\"0x01450000\" added=\"2025-12-24T02:56:52Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1199\" file=\"ntoskrnl.exe\" hash=\"e546f5e9110cedfcd4a3e10b3a804621717e62f8edcb6e78513ede2bd448cb02\" timestamp=\"0xbb9e5578\" size=\"0x01450000\" added=\"2025-11-20T04:01:51Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1340\" file=\"ntoskrnl.exe\" hash=\"c23f01d96dadb05be3e5805c38281fd5ecff665fae32ce1e52f95bf9825fabd2\" timestamp=\"0xb10ca14b\" size=\"0x01450000\" added=\"2025-12-10T04:39:55Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1362\" file=\"ntoskrnl.exe\" hash=\"ee38022eb22df889a95b1fedaf77b5cbf2fafbcb9855cc1ba135d37186343e75\" timestamp=\"0xa65244b3\" size=\"0x01450000\" added=\"2025-12-18T01:38:46Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1371\" file=\"ntoskrnl.exe\" hash=\"890795c16f7d8db5a925c34b2b909ed3eb695b2ef70600fc245e5813a682d0f4\" timestamp=\"0xb30ac059\" size=\"0x01450000\" added=\"2026-01-16T04:57:10Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1446\" file=\"ntoskrnl.exe\" hash=\"02c956be161b89a2067317dfba45d8ff88807bb3512d7137b218aa40a200732f\" timestamp=\"0x5cff8a76\" size=\"0x01450000\" added=\"2026-01-15T04:51:11Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1450\" file=\"ntoskrnl.exe\" hash=\"9696710c7b45811dbda64b5e8c8e23343116018e406aa0d14dc8d7907ad6e29b\" timestamp=\"0xca5a71a4\" size=\"0x01450000\" added=\"2026-01-16T04:57:10Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1495\" file=\"ntoskrnl.exe\" hash=\"f82604ee6642ef3b50e7053080ad2df19e2532f40c6bfab321aab768c7678dba\" timestamp=\"0xe17bb144\" size=\"0x01450000\" added=\"2026-02-01T01:21:00Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1504\" file=\"ntoskrnl.exe\" hash=\"ecb6293c977b6d2cbcc39114ab08a5f082fd8cd6ee193404a50def81bff6a165\" timestamp=\"0x85eacbf3\" size=\"0x01450000\" added=\"2026-02-01T01:21:00Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1516\" file=\"ntoskrnl.exe\" hash=\"c2c584d5a53d492ef55a849bc876d7155200fc90e98186feb895b307b0512b67\" timestamp=\"0x42b83c85\" size=\"0x01450000\" added=\"2026-02-01T01:21:00Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1546\" file=\"ntoskrnl.exe\" hash=\"4af99b5871800978e79df9ec9600137ff8a9c9e26acc4ff4b298d307d31eb6cc\" timestamp=\"0x657b9b70\" size=\"0x01450000\" added=\"2026-02-05T23:25:24Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1575\" file=\"ntoskrnl.exe\" hash=\"f16d863e0db93b8716843b9c599b9c27a7c44bd1ce07ab16d4b7d7d66f60e5c6\" timestamp=\"0x594f3725\" size=\"0x01450000\" added=\"2026-02-11T00:54:58Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1611\" file=\"ntoskrnl.exe\" hash=\"da59869273fe27872c82daec730c7288697b77a3827d7c18c0ff73bc448f438c\" timestamp=\"0xe482a133\" size=\"0x01450000\" added=\"2026-02-17T23:38:22Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1619\" file=\"ntoskrnl.exe\" hash=\"e2cbdf6f4d62dbc00919b45388ddca8b62ce7b1d94dae2ab6337b74df1936424\" timestamp=\"0x4b42f87d\" size=\"0x01450000\" added=\"2026-02-28T14:39:37Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1673\" file=\"ntoskrnl.exe\" hash=\"9e08af4c90ef1a55895186b51a2941eb599a38672f123b4104190c369cdd3fdf\" timestamp=\"0x800f0d80\" size=\"0x01450000\" added=\"2026-03-04T03:13:34Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1685\" file=\"ntoskrnl.exe\" hash=\"f333b886ff81eb835e97e4b35954e84b85127682fedf9003f15d0ea1f7dc4a65\" timestamp=\"0x6dee26f9\" size=\"0x01450000\" added=\"2026-03-11T23:28:21Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.28000.1719\" file=\"ntoskrnl.exe\" hash=\"c50284a17c4fec36f5f99f18e157983a8fb89371fbc035c364878bf1b52f050a\" timestamp=\"0x8c8a4c58\" size=\"0x01450000\" added=\"2026-03-11T23:28:21Z\">24</data>\n    <data arch=\"arm64\" version=\"10.0.29531.1000\" file=\"ntoskrnl.exe\" hash=\"e0cb5d6829ffc3497d5385d2cd99772c378305477e7fe571329e9de5c958cab5\" timestamp=\"0x23b4d441\" size=\"0x01450000\" added=\"2026-02-21T23:40:53Z\">30</data>\n    <fields id=\"15\">\n        <field value=\"0x0018\" name=\"EgeGuid\"/>\n        <field value=\"0x03c0\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05c8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05d0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05d8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05e0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05e8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05f0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0368\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"16\">\n        <field value=\"0x0018\" name=\"EgeGuid\"/>\n        <field value=\"0x03c8\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05c8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05d0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05d8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05e0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05e8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05f0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0370\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"17\">\n        <field value=\"0x0018\" name=\"EgeGuid\"/>\n        <field value=\"0x03d0\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05c8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05d0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05d8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05e0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05e8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05f0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0378\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"9\">\n        <field value=\"0x0018\" name=\"EgeGuid\"/>\n        <field value=\"0x0418\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a0\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05a8\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03b8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"10\">\n        <field value=\"0x0018\" name=\"EgeGuid\"/>\n        <field value=\"0x0418\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05c0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05d0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03b8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"1\">\n        <field value=\"0x0018\" name=\"EgeGuid\"/>\n        <field value=\"0x0418\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a0\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05a8\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03b8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"2\">\n        <field value=\"0x0018\" name=\"EgeGuid\"/>\n        <field value=\"0x0418\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05c0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05d0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03b8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"5\">\n        <field value=\"0x0018\" name=\"EgeGuid\"/>\n        <field value=\"0x0418\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05c0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05d0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03c0\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"27\">\n        <field value=\"0x0018\" name=\"EgeGuid\"/>\n        <field value=\"0x0420\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05c0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05d0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03c0\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"30\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x02f0\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x00e8\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0148\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0178\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x0188\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x03a0\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x03a8\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x03b0\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x03b8\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03c0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03c8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0298\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"24\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x02f0\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x03a0\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x03a8\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x03b0\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x03b8\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03c0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03c8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0298\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"33\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x02f0\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x03a0\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x03a8\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x03b0\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x03b8\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03c0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03c8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0298\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"29\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0300\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x000b\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0008\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x00e8\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0148\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0178\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x0188\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x02a8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"26\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0300\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x000b\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0008\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x02a8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"32\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0300\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x000b\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0008\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x02a8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"28\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0300\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x00e8\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0148\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0178\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x0188\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x02a8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"25\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0300\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x02a8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"31\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0300\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x02a8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"23\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x03c8\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05c8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05d0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05d8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05e0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05e8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05f0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0370\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"19\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x03c8\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05c8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05d0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05d8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05e0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05e8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05f0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0370\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"21\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x03d0\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05c8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05d0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05d8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05e0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05e8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05f0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0378\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"18\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x03d0\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05c8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05d0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05d8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05e0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05e8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05f0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0378\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"11\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0418\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05c0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05d0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03b8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"7\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0418\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05c0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05d0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03c0\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"4\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0418\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05c0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05d0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03b8\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"3\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0418\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x05a8\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x05b0\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x05b8\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x05c0\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x05c8\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x05d0\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x03c0\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"22\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0528\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x03a0\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x03a8\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x03b0\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x03b8\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03c0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03c8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x04d0\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"20\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0528\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x03a0\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x03a8\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x03b0\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x03b8\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03c0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03c8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x04d0\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"13\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0570\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x000b\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0008\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0518\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"12\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0570\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x000b\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0008\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0518\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"8\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0570\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0008\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0518\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"6\">\n        <field value=\"0x0028\" name=\"EgeGuid\"/>\n        <field value=\"0x0570\" name=\"EpObjectTable\"/>\n        <field value=\"0x0020\" name=\"EreGuidEntry\"/>\n        <field value=\"0x0030\" name=\"HtHandleContentionEvent\"/>\n        <field value=\"0x0010\" name=\"OtName\"/>\n        <field value=\"0x0028\" name=\"OtIndex\"/>\n        <field value=\"0x0014\" name=\"ObDecodeShift\"/>\n        <field value=\"0x0011\" name=\"ObAttributesShift\"/>\n        <field value=\"0x0010\" name=\"AlpcCommunicationInfo\"/>\n        <field value=\"0x0018\" name=\"AlpcOwnerProcess\"/>\n        <field value=\"0x0000\" name=\"AlpcConnectionPort\"/>\n        <field value=\"0x0008\" name=\"AlpcServerCommunicationPort\"/>\n        <field value=\"0x0010\" name=\"AlpcClientCommunicationPort\"/>\n        <field value=\"0x0028\" name=\"AlpcHandleTable\"/>\n        <field value=\"0x0010\" name=\"AlpcHandleTableLock\"/>\n        <field value=\"0x0100\" name=\"AlpcAttributes\"/>\n        <field value=\"0x0000\" name=\"AlpcAttributesFlags\"/>\n        <field value=\"0x0038\" name=\"AlpcPortContext\"/>\n        <field value=\"0x0160\" name=\"AlpcPortObjectLock\"/>\n        <field value=\"0x0190\" name=\"AlpcSequenceNo\"/>\n        <field value=\"0x01a0\" name=\"AlpcState\"/>\n        <field value=\"0x0028\" name=\"KtInitialStack\"/>\n        <field value=\"0x0030\" name=\"KtStackLimit\"/>\n        <field value=\"0x0038\" name=\"KtStackBase\"/>\n        <field value=\"0x0058\" name=\"KtKernelStack\"/>\n        <field value=\"0x0380\" name=\"KtReadOperationCount\"/>\n        <field value=\"0x0388\" name=\"KtWriteOperationCount\"/>\n        <field value=\"0x0390\" name=\"KtOtherOperationCount\"/>\n        <field value=\"0x0398\" name=\"KtReadTransferCount\"/>\n        <field value=\"0x03a0\" name=\"KtWriteTransferCount\"/>\n        <field value=\"0x03a8\" name=\"KtOtherTransferCount\"/>\n        <field value=\"0x0028\" name=\"MmSectionControlArea\"/>\n        <field value=\"0x0008\" name=\"MmControlAreaListHead\"/>\n        <field value=\"0x0048\" name=\"MmControlAreaLock\"/>\n        <field value=\"0x0518\" name=\"EpSectionObject\"/>\n    </fields>\n    <fields id=\"14\">\n        <field value=\"0x0080\" name=\"LxPicoProc\"/>\n        <field value=\"0x0010\" name=\"LxPicoProcInfo\"/>\n        <field value=\"0x0010\" name=\"LxPicoProcInfoPID\"/>\n        <field value=\"0x0010\" name=\"LxPicoThrdInfo\"/>\n        <field value=\"0x0010\" name=\"LxPicoThrdInfoTID\"/>\n    </fields>\n</dyn>\n"
  },
  {
    "path": "kphlib/kphdyndata.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2026\n *\n */\n\n#include <kphlibbase.h>\n#include <kphdyndata.h>\n\n#ifndef _KERNEL_MODE\n#include <ntintsafe.h>\n#ifndef Add2Ptr\n#define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I)))\n#endif\n#endif\n\n/**\n * \\brief Searches for a dynamic data configuration.\n *\n * \\param[in] Config The dynamic data configuration.\n * \\param[in] Length The length of the dynamic data configuration.\n * \\param[in] Class The class to search for.\n * \\param[in] Machine The machine to search for.\n * \\param[in] TimeDateStamp The time date stamp to search for.\n * \\param[in] SizeOfImage The size of image to search for.\n * \\param[out] Data Receives a pointer into the dynamic data configuration if\n * the requested data is found.\n * \\param[out] Fields Receives a pointer into the dynamic data configuration for\n * the related fields if the requested data is found.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphDynDataLookup(\n    _In_reads_bytes_(Length) PKPH_DYN_CONFIG Config,\n    _In_ ULONG Length,\n    _In_ USHORT Class,\n    _In_ USHORT Machine,\n    _In_ ULONG TimeDateStamp,\n    _In_ ULONG SizeOfImage,\n    _Out_opt_ PKPH_DYN_DATA* Data,\n    _Out_opt_ PVOID* Fields\n    )\n{\n    NTSTATUS status;\n    ULONG dataLength;\n    ULONG length;\n\n    if (Data)\n    {\n        *Data = NULL;\n    }\n\n    if (Fields)\n    {\n        *Fields = NULL;\n    }\n\n    status = RtlULongSub(Length,\n                         RTL_SIZEOF_THROUGH_FIELD(KPH_DYN_CONFIG, Count),\n                         &length);\n    if (!NT_SUCCESS(status))\n    {\n        return STATUS_SI_DYNDATA_INVALID_LENGTH;\n    }\n\n    if (Config->Version != KPH_DYN_CONFIGURATION_VERSION)\n    {\n        return STATUS_SI_DYNDATA_VERSION_MISMATCH;\n    }\n\n    status = RtlULongMult(sizeof(KPH_DYN_DATA), Config->Count, &dataLength);\n    if (!NT_SUCCESS(status))\n    {\n        return STATUS_SI_DYNDATA_INVALID_LENGTH;\n    }\n\n    status = RtlULongSub(length, dataLength, &length);\n    if (!NT_SUCCESS(status))\n    {\n        return STATUS_SI_DYNDATA_INVALID_LENGTH;\n    }\n\n    for (ULONG i = 0; i < Config->Count; i++)\n    {\n        PKPH_DYN_DATA data;\n\n        data = &Config->Data[i];\n\n        if ((data->Class != Class) ||\n            (data->Machine != Machine) ||\n            (data->TimeDateStamp != TimeDateStamp) ||\n            (data->SizeOfImage != SizeOfImage))\n        {\n            continue;\n        }\n\n        if (data->Offset >= length)\n        {\n            return STATUS_SI_DYNDATA_INVALID_LENGTH;\n        }\n\n        if (Data)\n        {\n            *Data = data;\n        }\n\n        if (Fields)\n        {\n            PVOID start;\n\n            start = &Config->Data[Config->Count];\n\n            *Fields = Add2Ptr(start, data->Offset);\n        }\n\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_SI_DYNDATA_UNSUPPORTED_KERNEL;\n}\n"
  },
  {
    "path": "kphlib/kphlib_km.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{c6f1d7ed-ed5d-4745-9ea8-c0dfaa942906}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{545176e3-50a7-46f9-84b8-fbd1e9fec5d8}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\kphmsg.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphmsgdyn.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phcomm.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphmsgbase.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"kphmsgdyn.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphmsg.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "kphlib/kphlib_km.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>17.0</VCProjectVersion>\n    <ProjectGuid>{B1863396-A667-42DB-97AC-C5E033CEE321}</ProjectGuid>\n    <TemplateGuid>{dd38f7fc-d7bd-488b-9242-7d8754cde80d}</TemplateGuid>\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <RootNamespace>kphlib_km</RootNamespace>\n    <ProjectName>kphlib</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <IntDir>$(SystemInformerRoot)KSystemInformer\\obj\\$(Configuration)$(PlatformArchitecture)\\$(ProjectName)\\</IntDir>\n    <OutDir>$(SystemInformerRoot)KSystemInformer\\bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <TargetName>kphlib_km</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup>\n    <Link>\n      <AdditionalDependencies>ksecdd.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <PreBuildEvent>\n      <Command>\"$(SolutionDir)..\\tools\\CustomBuildTool\\bin\\Release\\$(PROCESSOR_ARCHITECTURE)\\CustomBuildTool.exe\" -dyndata \"$(SolutionDir)..\\bin\\$(Configuration)$(PlatformArchitecture)\"</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <!-- sistatus\n    Compiling of the message file is only done in the kernelmode side of KPHLIB\n    so that the WDK is not a requirement only building the usermode parts. If\n    changes are made to sistatus.mc, you must build the kernel parts for the\n    header and resources to be regenerated.\n  -->\n  <ItemGroup>\n    <MessageCompile Include=\"sistatus.mc\">\n      <GeneratedHeaderPath>true</GeneratedHeaderPath>\n      <HeaderFilePath>$(ProjectDir)include</HeaderFilePath>\n      <GeneratedRcAndMessagesPath>true</GeneratedRcAndMessagesPath>\n      <RCFilePath>$(ProjectDir)include</RCFilePath>\n      <SetCustomerbit>true</SetCustomerbit>\n      <TerminateMessageWithNull>true</TerminateMessageWithNull>\n      <UnicodeMessageInBinFile>true</UnicodeMessageInBinFile>\n      <UnicodeInputFile>true</UnicodeInputFile>\n      <Verbose>true</Verbose>\n    </MessageCompile>\n    <None Include=\"include\\sistatus_MSG00001.bin\" />\n    <ResourceCompile Include=\"include\\sistatus.rc\" />\n    <ClInclude Include=\"include\\kphringbuff.h\" />\n    <ClInclude Include=\"include\\sistatus.h\" />\n  </ItemGroup>\n  <!-- sistatus -->\n  <ItemGroup>\n    <ClInclude Include=\"include\\kphapi.h\" />\n    <ClInclude Include=\"include\\kphdyndata.h\" />\n    <ClInclude Include=\"include\\kphlibbase.h\" />\n    <ClInclude Include=\"include\\kphmsg.h\" />\n    <ClInclude Include=\"include\\kphmsgdyn.h\" />\n    <ClInclude Include=\"include\\kphmsgdefs.h\" />\n    <ClInclude Include=\"include\\kphdyn.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"kphdyndata.c\" />\n    <ClCompile Include=\"kphmsg.c\" />\n    <ClCompile Include=\"kphmsgdyn.c\" />\n    <ClCompile Include=\"kphdyn.c\" />\n    <ClCompile Include=\"kphringbuff.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"kphdyn.xml\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>"
  },
  {
    "path": "kphlib/kphlib_km.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{82b195b6-02b5-4bd3-b6be-ef713fcec8aa}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{1d7a73eb-3cee-4ae3-82bc-0846578dc715}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{2a9e0704-3950-492f-9cf5-ce4b10a57b22}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\kphmsg.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphmsgdyn.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphapi.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphlibbase.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphdyn.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphmsgdefs.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphdyndata.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\sistatus.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphringbuff.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"kphmsgdyn.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphmsg.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphdyn.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphdyndata.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphringbuff.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"kphdyn.xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <MessageCompile Include=\"sistatus.mc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"include\\sistatus_MSG00001.bin\">\n      <Filter>Resource Files</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"include\\sistatus.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "kphlib/kphlib_um.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>17.0</VCProjectVersion>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectGuid>{f1757430-8eee-49df-a5f1-0999a53bb4a0}</ProjectGuid>\n    <RootNamespace>kphlib_um</RootNamespace>\n    <ProjectName>kphlib</ProjectName>\n    <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <LinkIncremental>false</LinkIncremental>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <LinkIncremental>true</LinkIncremental>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <LinkIncremental>false</LinkIncremental>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <LinkIncremental>false</LinkIncremental>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <LinkIncremental>true</LinkIncremental>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <LinkIncremental>true</LinkIncremental>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)obj\\um\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)obj\\um\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">$(ProjectDir)obj\\um\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)obj\\um\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)obj\\um\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">$(ProjectDir)obj\\um\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\n    <TargetName>kphlib_um</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\n    <TargetName>kphlib_um</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <TargetName>kphlib_um</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <TargetName>kphlib_um</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <TargetName>kphlib_um</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <TargetName>kphlib_um</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>DEBUG;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Lib>\n      <TargetMachine>MachineX86</TargetMachine>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n    </Lib>\n    <PreBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_dyndata.cmd\" \"$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\"</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>DEBUG;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Lib>\n      <TargetMachine>MachineX64</TargetMachine>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n    </Lib>\n    <PreBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_dyndata.cmd\" \"$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\"</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>DEBUG;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Lib>\n      <TargetMachine>MachineARM64</TargetMachine>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n    </Lib>\n    <PreBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_dyndata.cmd\" \"$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\"</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <AdditionalOptions>/utf-8 /d1nodatetime /guard:xfg %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Lib>\n      <TargetMachine>MachineX86</TargetMachine>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n    </Lib>\n    <PreBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_dyndata.cmd\" \"$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\"</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <AdditionalOptions>/utf-8 /d1nodatetime /guard:xfg %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Lib>\n      <TargetMachine>MachineX64</TargetMachine>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n    </Lib>\n    <PreBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_dyndata.cmd\" \"$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\"</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <AdditionalOptions>/utf-8 /d1nodatetime %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Lib>\n      <TargetMachine>MachineARM64</TargetMachine>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <UseUnicodeResponseFiles>true</UseUnicodeResponseFiles>\n    </Lib>\n    <PreBuildEvent>\n      <Command>\"$(SolutionDir)build\\build_dyndata.cmd\" \"$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\"</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <FilesToPackage Include=\"$(TargetPath)\" />\n  </ItemGroup>\n  <!-- sistatus\n    Compiling of the message file is only done in the kernelmode side of KPHLIB\n    so that the WDK is not a requirement only building the usermode parts. If\n    changes are made to sistatus.mc, you must build the kernel parts for the\n    header and resources to be regenerated.\n  -->\n  <ItemGroup>\n    <None Include=\"sistatus.mc\" />\n    <None Include=\"include\\sistatus_MSG00001.bin\" />\n    <ResourceCompile Include=\"include\\sistatus.rc\" />\n    <ClInclude Include=\"include\\kphringbuff.h\" />\n    <ClInclude Include=\"include\\sistatus.h\" />\n  </ItemGroup>\n  <!-- sistatus -->\n  <ItemGroup>\n    <ClInclude Include=\"include\\kphapi.h\" />\n    <ClInclude Include=\"include\\kphdyndata.h\" />\n    <ClInclude Include=\"include\\kphmsg.h\" />\n    <ClInclude Include=\"include\\kphlibbase.h\" />\n    <ClInclude Include=\"include\\kphmsgdefs.h\" />\n    <ClInclude Include=\"include\\kphmsgdyn.h\" />\n    <ClInclude Include=\"include\\kphdyn.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"kphdyndata.c\" />\n    <ClCompile Include=\"kphmsg.c\" />\n    <ClCompile Include=\"kphmsgdyn.c\" />\n    <ClCompile Include=\"kphdyn.c\" />\n    <ClCompile Include=\"kphringbuff.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"kphdyn.xml\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "kphlib/kphlib_um.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{d727b7f5-c766-42e2-b006-b57a27838deb}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{9cc800b4-95ec-4b5e-8575-80a523f61365}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{fa49d35d-f550-434b-b86f-2ee4378bdb63}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\kphmsg.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphmsgdyn.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphapi.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphlibbase.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphdyn.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphmsgdefs.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphdyndata.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\sistatus.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphringbuff.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"kphmsgdyn.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphmsg.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphdyn.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphdyndata.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphringbuff.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"kphdyn.xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"sistatus.mc\" />\n    <None Include=\"include\\sistatus_MSG00001.bin\">\n      <Filter>Resource Files</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"include\\sistatus.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "kphlib/kphmsg.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *     dmex    2022\n *\n */\n\n#include <kphlibbase.h>\n#include <kphmsg.h>\n\n#define KPH_MESSAGE_VERSION 6\n\n/**\n * Gets the current system time (UTC).\n *\n * \\remarks Use this function instead of NtQuerySystemTime() because no system calls are involved.\n */\nVOID KphMsgQuerySystemTime(\n    _Out_ PLARGE_INTEGER SystemTime\n    )\n{\n#ifdef _KERNEL_MODE\n    KeQuerySystemTime(SystemTime);\n#else\n    while (TRUE)\n    {\n        SystemTime->HighPart = USER_SHARED_DATA->SystemTime.High1Time;\n        SystemTime->LowPart = USER_SHARED_DATA->SystemTime.LowPart;\n\n        if (SystemTime->HighPart == USER_SHARED_DATA->SystemTime.High2Time)\n            break;\n\n        YieldProcessor();\n    }\n#endif\n}\n\n/**\n * \\brief Initializes a message.\n *\n * \\param MessageId Message identifier to initialize with.\n */\nVOID KphMsgInit(\n    _Out_writes_bytes_(KPH_MESSAGE_MIN_SIZE) PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_ID MessageId\n    )\n{\n    RtlZeroMemory(Message, KPH_MESSAGE_MIN_SIZE);\n    Message->Header.Version = KPH_MESSAGE_VERSION;\n    Message->Header.Size = KPH_MESSAGE_MIN_SIZE;\n    Message->Header.MessageId = MessageId;\n    KphMsgQuerySystemTime(&Message->Header.TimeStamp);\n}\n\n/**\n * \\brief Validates a message.\n *\n * \\param Message The message to validate.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphMsgValidate(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    if (Message->Header.Version != KPH_MESSAGE_VERSION)\n    {\n        return STATUS_REVISION_MISMATCH;\n    }\n\n    if ((Message->Header.Size < KPH_MESSAGE_MIN_SIZE) ||\n        (Message->Header.Size > sizeof(KPH_MESSAGE)))\n    {\n        return STATUS_INVALID_MESSAGE;\n    }\n\n    if (Message->Header.MessageId != KphMsgUnhandled)\n    {\n        if ((Message->Header.MessageId <= InvalidKphMsg) ||\n            (Message->Header.MessageId >= MaxKphMsg))\n        {\n            return STATUS_INVALID_MESSAGE;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "kphlib/kphmsgdyn.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2026\n *\n */\n\n#include <kphlibbase.h>\n#include <kphmsgdyn.h>\n\n#ifndef _KERNEL_MODE\n#include <ntintsafe.h>\n#ifndef Add2Ptr\n#define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I)))\n#endif\n#endif\n\n/**\n * \\brief Finds a dynamic message entry in the table.\n *\n * \\param[in] Message The message to get the table entry from.\n * \\param[in] FieldId Field identifier to look for.\n *\n * \\return Pointer to table entry on success, null if not found.\n */\n_Must_inspect_result_\nPCKPH_MESSAGE_DYNAMIC_TABLE_ENTRY KphpMsgDynFindEntry(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId\n    )\n{\n    for (USHORT i = 0; i < Message->_Dyn.Count; i++)\n    {\n        if (Message->_Dyn.Entries[i].FieldId == FieldId)\n        {\n            return &Message->_Dyn.Entries[i];\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * \\brief Claims some data in the dynamic message buffer.\n *\n * \\param[in] Message The message to claim dynamic message in.\n * \\param[in] FieldId Field identifier of the data to be populated.\n * \\param[in] TypeId Type identifier of the data to be populated.\n * \\param[in] Length The length to claim.\n * \\param[out] Entry Set to the claimed entry.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphpMsgDynClaimEntry(\n    _In_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ KPH_MESSAGE_TYPE_ID TypeId,\n    _In_ USHORT Length,\n    _Outptr_ PCKPH_MESSAGE_DYNAMIC_TABLE_ENTRY* Entry\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY claimed;\n    USHORT offset;\n\n    *Entry = NULL;\n\n    if ((FieldId <= InvalidKphMsgField) || (FieldId >= MaxKphMsgField))\n    {\n        return STATUS_INVALID_PARAMETER_2;\n    }\n\n    if ((TypeId <= InvalidKphMsgType) || (TypeId >= MaxKphMsgType))\n    {\n        return STATUS_INVALID_PARAMETER_3;\n    }\n\n    status = KphMsgValidate(Message);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    if (Message->_Dyn.Count >= ARRAYSIZE(Message->_Dyn.Entries))\n    {\n        return STATUS_INSUFFICIENT_RESOURCES;\n    }\n\n    if (KphpMsgDynFindEntry(Message, FieldId))\n    {\n        return STATUS_ALREADY_COMMITTED;\n    }\n\n    offset = Message->Header.Size;\n\n    status = RtlUShortAdd(offset, Length, &offset);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    if (offset > sizeof(KPH_MESSAGE))\n    {\n        return STATUS_INSUFFICIENT_RESOURCES;\n    }\n\n    offset = Message->Header.Size;\n\n    claimed = &Message->_Dyn.Entries[Message->_Dyn.Count++];\n    claimed->FieldId = FieldId;\n    claimed->TypeId = TypeId;\n    claimed->Offset = offset;\n    claimed->Length = Length;\n\n    Message->Header.Size += Length;\n\n    *Entry = claimed;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Looks up a dynamic message entry.\n *\n * \\param[in] Message The message to look up dynamic message entry in.\n * \\param[in] FieldId Field identifier to look up.\n * \\param[in] TypeId Type identifier to look up.\n * \\param[out] DynData Set to point to dynamic message entry.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphpMsgDynLookupEntry(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ KPH_MESSAGE_TYPE_ID TypeId,\n    _Outptr_ PCKPH_MESSAGE_DYNAMIC_TABLE_ENTRY* Entry\n    )\n{\n    NTSTATUS status;\n    PCKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    *Entry = NULL;\n\n    status = KphMsgValidate(Message);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    entry = KphpMsgDynFindEntry(Message, FieldId);\n    if (!entry)\n    {\n        return STATUS_NOT_FOUND;\n    }\n\n    if (entry->TypeId != TypeId)\n    {\n        return STATUS_CONTEXT_MISMATCH;\n    }\n\n    if (entry->Offset >= Message->Header.Size)\n    {\n        return STATUS_HEAP_CORRUPTION;\n    }\n\n    *Entry = entry;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Clears the dynamic message table, effectively \"freeing\" the dynamic\n * message buffer to be populated with other information.\n *\n * \\param[in,out] Message The message to clear the dynamic message table of.\n */\nVOID KphMsgDynClear(\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    Message->Header.Size = KPH_MESSAGE_MIN_SIZE;\n    Message->_Dyn.Count = 0;\n    RtlZeroMemory(&Message->_Dyn.Entries, sizeof(Message->_Dyn.Entries));\n}\n\n/**\n * \\brief Clears that last added dynamic message entry.\n *\n * \\param[in,out] Message The message to clear the last dynamic message entry.\n */\nVOID KphMsgDynClearLast(\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    if (Message->_Dyn.Count)\n    {\n        return;\n    }\n\n    Message->_Dyn.Count--;\n    entry = &Message->_Dyn.Entries[Message->_Dyn.Count];\n    Message->Header.Size -= entry->Length;\n    RtlZeroMemory(entry, sizeof(KPH_MESSAGE_DYNAMIC_TABLE_ENTRY));\n}\n\n/**\n * \\brief Retrieves the remaining size of the dynamic message buffer.\n *\n * \\param[in] Message The message to retrieve the remaining size of.\n *\n * \\return Remaining size of the dynamic message buffer.\n */\nUSHORT KphMsgDynRemaining(\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    NTSTATUS status;\n    USHORT remaining;\n\n    remaining = sizeof(KPH_MESSAGE);\n\n    status = RtlUShortSub(remaining, Message->Header.Size, &remaining);\n    if (!NT_SUCCESS(status))\n    {\n        return 0;\n    }\n\n    return remaining;\n}\n\n/**\n * \\brief Adds a Unicode string to the dynamic message buffer.\n *\n * \\param[in,out] Message The message to populate dynamic message buffer of.\n * \\param[in] FieldId Field identifier for the data.\n * \\param[in] String Unicode string to copy into the dynamic message buffer.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphMsgDynAddUnicodeString(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PCUNICODE_STRING String\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    status = KphpMsgDynClaimEntry(Message,\n                                  FieldId,\n                                  KphMsgTypeUnicodeString,\n                                  String->Length,\n                                  &entry);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    RtlCopyMemory(Add2Ptr(Message, entry->Offset),\n                  String->Buffer,\n                  String->Length);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Retrieves a Unicode string from the dynamic message buffer.\n *\n * \\param[in] Message The message to retrieve the Unicode string from.\n * \\param[in] FieldId Field identifier for the data.\n * \\param[out] String If found populated with a reference to the string data in\n * the dynamic message buffer.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS KphMsgDynGetUnicodeString(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _Out_ PUNICODE_STRING String\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    status = KphpMsgDynLookupEntry(Message,\n                                   FieldId,\n                                   KphMsgTypeUnicodeString,\n                                   &entry);\n    if (!NT_SUCCESS(status))\n    {\n        String->Length = 0;\n        String->MaximumLength = 0;\n        String->Buffer = NULL;\n\n        return status;\n    }\n\n    String->Length = entry->Length;\n    String->MaximumLength = String->Length;\n    String->Buffer = Add2Ptr(Message, entry->Offset);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Adds an ANSI string to the dynamic message buffer.\n *\n * \\param[in,out] Message The message to add the string to.\n * \\param[in] FieldId Field identifier for the string.\n * \\param[in] String ANSI string to copy into the dynamic message buffer.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphMsgDynAddAnsiString(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PCANSI_STRING String\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    status = KphpMsgDynClaimEntry(Message,\n                                  FieldId,\n                                  KphMsgTypeAnsiString,\n                                  String->Length,\n                                  &entry);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    RtlCopyMemory(Add2Ptr(Message, entry->Offset),\n                  String->Buffer,\n                  String->Length);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Retrieves an ANSI string from the message.\n *\n * \\param[in] Message The message to retrieve the string from.\n * \\param[in] FieldId Field identifier of the string.\n * \\param[out] String If found populated with a reference to the string data in\n * the dynamic message buffer.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS KphMsgDynGetAnsiString(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _Out_ PANSI_STRING String\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    status = KphpMsgDynLookupEntry(Message,\n                                   FieldId,\n                                   KphMsgTypeAnsiString,\n                                   &entry);\n    if (!NT_SUCCESS(status))\n    {\n        String->Length = 0;\n        String->MaximumLength = 0;\n        String->Buffer = NULL;\n\n        return status;\n    }\n\n    String->Length = entry->Length;\n    String->MaximumLength = String->Length;\n    String->Buffer = Add2Ptr(Message, entry->Offset);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Adds a stack trace to the dynamic message buffer.\n *\n * \\param[in,out] Message The message to add the stack trace to.\n * \\param[in] FieldId Field identifier for the stack trace.\n * \\param[in] StackTrace Stack trace to copy into the dynamic message buffer.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphMsgDynAddStackTrace(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PKPHM_STACK_TRACE StackTrace\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    status = KphpMsgDynClaimEntry(Message,\n                                  FieldId,\n                                  KphMsgTypeStackTrace,\n                                  (StackTrace->Count * sizeof(PVOID)),\n                                  &entry);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    RtlCopyMemory(Add2Ptr(Message, entry->Offset),\n                  StackTrace->Frames,\n                  (StackTrace->Count * sizeof(PVOID)));\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Retrieves a stack trace from the message.\n *\n * \\param[in] Message The message to retrieve the stack trace from.\n * \\param[in] FieldId Field identifier of the stack trace.\n * \\param[out] StackTrace If found populated with a reference to the stack\n * trace data in the dynamic message buffer.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS KphMsgDynGetStackTrace(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _Out_ PKPHM_STACK_TRACE StackTrace\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    status = KphpMsgDynLookupEntry(Message,\n                                   FieldId,\n                                   KphMsgTypeStackTrace,\n                                   &entry);\n    if (!NT_SUCCESS(status))\n    {\n        StackTrace->Count = 0;\n        StackTrace->Frames = NULL;\n\n        return status;\n    }\n\n    StackTrace->Count = (entry->Length / sizeof(PVOID));\n    StackTrace->Frames = Add2Ptr(Message, entry->Offset);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Adds a sized buffer to the dynamic message buffer.\n *\n * \\param[in,out] Message The message to add the sized buffer to.\n * \\param[in] FieldId Field identifier for the sized buffer.\n * \\param[in] SizedBuffer Sized buffer to copy into the dynamic message buffer.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphMsgDynAddSizedBuffer(\n    _Inout_ PKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _In_ PKPHM_SIZED_BUFFER SizedBuffer\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    status = KphpMsgDynClaimEntry(Message,\n                                  FieldId,\n                                  KphMsgTypeSizedBuffer,\n                                  SizedBuffer->Size,\n                                  &entry);\n    if (!NT_SUCCESS(status))\n    {\n        return status;\n    }\n\n    RtlCopyMemory(Add2Ptr(Message, entry->Offset),\n                  SizedBuffer->Buffer,\n                  SizedBuffer->Size);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Retrieves a sized buffer from the message.\n *\n * \\param[in] Message The message to retrieve the sized buffer from.\n * \\param[in] FieldId Field identifier of the sized buffer.\n * \\param[out] SizedBuffer If found populated with a reference to the sized\n * buffer data in the dynamic message buffer.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS KphMsgDynGetSizedBuffer(\n    _In_ PCKPH_MESSAGE Message,\n    _In_ KPH_MESSAGE_FIELD_ID FieldId,\n    _Out_ PKPHM_SIZED_BUFFER SizedBuffer\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE_DYNAMIC_TABLE_ENTRY entry;\n\n    status = KphpMsgDynLookupEntry(Message,\n                                    FieldId,\n                                    KphMsgTypeSizedBuffer,\n                                    &entry);\n    if (!NT_SUCCESS(status))\n    {\n        SizedBuffer->Size = 0;\n        SizedBuffer->Buffer = NULL;\n        return status;\n    }\n\n    SizedBuffer->Size = entry->Length;\n    SizedBuffer->Buffer = Add2Ptr(Message, entry->Offset);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "kphlib/kphringbuff.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025-2026\n *\n */\n\n#include <kphlibbase.h>\n#include <kphringbuff.h>\n\n#ifndef _KERNEL_MODE\n#include <ntintsafe.h>\n#ifndef Add2Ptr\n#define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I)))\n#endif\n#endif\n\n/**\n * \\brief Processes the ring buffer.\n *\n * \\details The callback routine will continue to be invoked with new buffers\n * as long as the callback routine returns FALSE. Control is returned to the\n * caller once the callback routine returns TRUE or if there are no more buffer\n * to process.\n *\n * \\param[in] Ring Pointer to the user ring buffer block.\n * \\param[in] Callback Routine to process the ring buffer entries. The routine\n * should return FALSE to continue to processing, otherwise TRUE to stop.\n * \\param[in] Context The context to pass to the callback routine.\n *\n * \\return TRUE if there are more buffers to process, FALSE otherwise.\n */\nBOOLEAN KphProcessRingBuffer(\n    _In_ PKPH_RING_BUFFER_USER Ring,\n    _In_ PKPH_RING_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG consumerPos;\n\n    WriteULongRelease(&Ring->Consumer->Processing, TRUE);\n\n    consumerPos = ReadULongAcquire(&Ring->Consumer->Position);\n\n    for (BOOLEAN done = FALSE; !done; NOTHING)\n    {\n        ULONG producerPos;\n        PKPH_RING_HEADER headerPointer;\n        KPH_RING_HEADER header;\n        PVOID buffer;\n\n        producerPos = ReadULongAcquire(&Ring->Producer->Position);\n\n        if (consumerPos == producerPos)\n        {\n            WriteULongRelease(&Ring->Consumer->Processing, FALSE);\n            return FALSE;\n        }\n\n        headerPointer = Add2Ptr(Ring->Producer->Buffer, consumerPos);\n\n        header.Value = ReadULong64Acquire(&headerPointer->Value);\n\n        if (header.Reset)\n        {\n            //\n            // Producer wrapped, reset to start.\n            //\n            WriteULongRelease(&Ring->Consumer->Position, 0);\n            consumerPos = 0;\n            continue;\n        }\n\n        //\n        // Check if the producer is busy at this position. If it is then it\n        // hasn't committed or discarded this region yet.\n        //\n        if (header.Busy)\n        {\n            WriteULongRelease(&Ring->Consumer->Processing, FALSE);\n            return FALSE;\n        }\n\n        consumerPos += KPH_RING_BUFFER_HEADER_SIZE;\n        consumerPos += (ULONG)header.Length;\n        consumerPos += (ULONG)header.Alignment;\n\n        if (!header.Discard)\n        {\n            buffer = Add2Ptr(headerPointer, KPH_RING_BUFFER_HEADER_SIZE);\n\n            done = Callback(Context, buffer, (ULONG)header.Length);\n        }\n\n        WriteULongRelease(&Ring->Consumer->Position, consumerPos);\n    }\n\n    return TRUE;\n}\n"
  },
  {
    "path": "kphlib/sistatus.mc",
    "content": "﻿;/*\n; * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n; *\n; * This file is part of System Informer.\n; *\n; * sistatus.h IS AN AUTOGENERATED FILE, DO NOT MODIFY\n; *\n; * Changes should be made in sistatus.mc\n; *\n; */\n;\n;#ifndef SI_STATUS_H\n;#define SI_STATUS_H\n\nMessageIdTypedef=NTSTATUS\n\nSeverityNames = (\n    Success       = 0x0:STATUS_SEVERITY_SUCCESS\n    Informational = 0x1:STATUS_SEVERITY_INFORMATIONAL\n    Warning       = 0x2:STATUS_SEVERITY_WARNING\n    Error         = 0x3:STATUS_SEVERITY_ERROR\n    )\n\nFacilityNames = (\n    System          = 0x0\n    SystemInformer  = 0x1:FACILITY_SI\n    DynamicData     = 0x2:FACILITY_SI_DYNDATA\n    KSystemInformer = 0x3:FACILITY_KSI\n    )\n\nMessageId    = 0x0001\nFacility     = DynamicData\nSeverity     = Error\nSymbolicName = STATUS_SI_DYNDATA_UNSUPPORTED_KERNEL\nLanguage     = English\nSystem Informer dynamic data is not yet supported on this kernel version.\n.\n\nMessageId    = 0x0002\nFacility     = DynamicData\nSeverity     = Error\nSymbolicName = STATUS_SI_DYNDATA_VERSION_MISMATCH\nLanguage     = English\nSystem Informer dynamic data version is incompatible.\n.\n\nMessageId    = 0x0003\nFacility     = DynamicData\nSeverity     = Error\nSymbolicName = STATUS_SI_DYNDATA_INVALID_LENGTH\nLanguage     = English\nSystem Informer dynamic data is an invalid length.\n.\n\nMessageId    = 0x0004\nFacility     = DynamicData\nSeverity     = Error\nSymbolicName = STATUS_SI_DYNDATA_INVALID_SIGNATURE\nLanguage     = English\nSystem Informer dynamic data signature is invalid.\n.\n\nMessageId    = 0x0001\nFacility     = KSystemInformer\nSeverity     = Error\nSymbolicName = STATUS_SI_KSIDLL_VERSION_MISMATCH\nLanguage     = English\nSystem Informer kernel library version is incompatible.\n.\n\n;#endif\n"
  },
  {
    "path": "packages.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Microsoft.Windows.SDK.CPP\" version=\"10.0.26100.7463\" targetFramework=\"native\" />\n  <package id=\"Microsoft.Windows.SDK.CPP.x86\" version=\"10.0.26100.7463\" targetFramework=\"native\" />\n  <package id=\"Microsoft.Windows.SDK.CPP.x64\" version=\"10.0.26100.7463\" targetFramework=\"native\" />\n  <package id=\"Microsoft.Windows.SDK.CPP.ARM64\" version=\"10.0.26100.7463\" targetFramework=\"native\" />\n  <package id=\"Microsoft.Windows.WDK.x64\" version=\"10.0.26100.6584\" targetFramework=\"native\" />\n  <package id=\"Microsoft.Windows.WDK.ARM64\" version=\"10.0.26100.6584\" targetFramework=\"native\" />\n</packages>\n"
  },
  {
    "path": "phlib/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nproject(phlib)\n\nset(HEADERS\n    \"circbuf_i.h\"\n    \"format_i.h\"\n    \"include/apiimport.h\"\n    \"include/appresolver.h\"\n    \"include/appresolverp.h\"\n    \"include/bcd.h\"\n    \"include/circbuf.h\"\n    \"include/circbuf_h.h\"\n    \"include/colorbox.h\"\n    \"include/cpysave.h\"\n    \"include/dltmgr.h\"\n    \"include/dspick.h\"\n    \"include/emenu.h\"\n    \"include/exlf.h\"\n    \"include/exprodid.h\"\n    \"include/fastlock.h\"\n    \"include/filepool.h\"\n    \"include/filepoolp.h\"\n    \"include/filestream.h\"\n    \"include/filestreamp.h\"\n    \"include/graph.h\"\n    \"include/guisup.h\"\n    \"include/guisupp.h\"\n    \"include/guisupview.h\"\n    \"include/handle.h\"\n    \"include/handlep.h\"\n    \"include/hexedit.h\"\n    \"include/hexeditp.h\"\n    \"include/hndlinfo.h\"\n    \"include/hvsocketcontrol.h\"\n    \"include/json.h\"\n    \"include/kphcomms.h\"\n    \"include/kphuser.h\"\n    \"include/lsamsup.h\"\n    \"include/lsasup.h\"\n    \"include/mapimg.h\"\n    \"include/mapldr.h\"\n    \"include/ph.h\"  \n    \"include/phafd.h\"\n    \"include/phbase.h\"\n    \"include/phbasesup.h\"\n    \"include/phconfig.h\"\n    \"include/phconsole.h\"\n    \"include/phdata.h\"\n    \"include/phfirmware.h\"\n    \"include/phintrin.h\"\n    \"include/phintrnl.h\"\n    \"include/phnative.h\"\n    \"include/phnativeinl.h\"\n    \"include/phnet.h\"\n    \"include/phsup.h\"\n    \"include/phutil.h\"\n    \"include/provider.h\"\n    \"include/queuedlock.h\"\n    \"include/ref.h\"\n    \"include/refp.h\"\n    \"include/searchbox.h\"\n    \"include/secedit.h\"\n    \"include/seceditp.h\"\n    \"include/secwmi.h\"\n    \"include/settings.h\"\n    \"include/strsrch.h\"\n    \"include/svcsup.h\"\n    \"include/symprv.h\"\n    \"include/symprvp.h\"\n    \"include/templ.h\"\n    \"include/thirdparty.h\"\n    \"include/treenew.h\"\n    \"include/treenewp.h\"\n    \"include/verify.h\"\n    \"include/verifyp.h\"\n    \"include/workqueue.h\"\n    \"include/workqueuep.h\"\n    \"include/wslsup.h\"\n)\nsource_group(\"Header Files\" FILES ${HEADERS})\n\nset(SOURCES\n    \"apiimport.c\"\n    \"appresolver.c\"\n    \"appruntime.c\"\n    \"avltree.c\"\n    \"basestring.c\"\n    \"basesup.c\"\n    \"bcd.cpp\"\n    \"circbuf.c\"\n    \"colorbox.c\"\n    \"cpysave.c\"\n    \"data.c\"\n    \"directdraw.cpp\"\n    \"dspick.c\"\n    \"emenu.c\"\n    \"error.c\"\n    \"extlv.c\"\n    \"fastlock.c\"\n    \"filepool.c\"\n    \"filestream.c\"\n    \"firmware.c\"\n    \"format.c\"\n    \"format_std.cpp\"\n    \"global.c\"\n    \"graph.c\"\n    \"guisup.c\"\n    \"guisuplistview.cpp\"\n    \"handle.c\"\n    \"hexedit.c\"\n    \"hndlinfo.c\"\n    \"http.c\"\n    \"hvsocketcontrol.c\"\n    \"icotobmp.c\"\n    \"imgcoherency.c\"\n    \"json.c\"\n    \"kph.c\"\n    \"kphcomms.c\"\n    \"lsamsup.c\"\n    \"lsasup.c\"\n    \"mapexlf.c\"\n    \"mapimg.c\"\n    \"mapldr.c\"\n    \"maplib.c\"\n    \"native.c\"\n    \"nativefile.c\"\n    \"nativeflt.c\"\n    \"nativemodule.c\"\n    \"nativejob.c\"\n    \"nativekey.c\"\n    \"nativetxn.c\"\n    \"nativeprocess.c\"\n    \"nativetoken.c\"\n    \"nativepipe.c\"\n    \"nativesocket.c\"\n    \"nativethread.c\"\n    \"nativeuser.c\"\n    \"provider.c\"\n    \"queuedlock.c\"\n    \"ref.c\"\n    \"searchbox.c\"\n    \"secdata.c\"\n    \"secedit.c\"\n    \"secwmi.c\"\n    \"settings.c\"\n    \"strsrch.c\"\n    \"svcsup.c\"\n    \"symprv.c\"\n    \"symprv_std.cpp\"\n    \"sync.c\"\n    \"theme.c\"\n    \"treenew.c\"\n    \"util.c\"\n    \"verify.c\"\n    \"workqueue.c\"\n    \"wslsup.c\"\n)\nsource_group(\"Source Files\" FILES ${SOURCES})\n\nset(ALL_FILES\n    ${HEADERS}\n    ${SOURCES}\n)\n\nsi_add_library(phlib STATIC ${ALL_FILES})\n\ntarget_include_directories(phlib PUBLIC\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include\"\n)\n\ntarget_compile_definitions(phlib PUBLIC\n    _PHLIB_\n)\n\ntarget_link_libraries(phlib PRIVATE\n    phnt\n    kphlib_um\n    thirdparty\n    gdiplus\n)\n\nadd_library(phlib_interface INTERFACE)\n\ntarget_include_directories(phlib_interface INTERFACE\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include\"\n)\n"
  },
  {
    "path": "phlib/Directory.Build.props",
    "content": "<Project>\n  <!-- Merge with parent Directory.Build.props -->\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />\n  <Import Project=\"$(SystemInformerRoot)/Common.User.props\" />\n</Project>\n"
  },
  {
    "path": "phlib/apiimport.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015\n *     dmex    2019-2024\n *\n */\n\n#include <ph.h>\n\n#include <mapldr.h>\n#include <sddl.h>\n#include <shlwapi.h>\n#include <userenv.h>\n#include <ntuser.h>\n#include <xmllite.h>\n\n#include <apiimport.h>\n\n/**\n * Imports a procedure from a specified module.\n *\n * \\param InitOnce A pointer to an initialization structure.\n * \\param Cache A pointer to a cache for the procedure address.\n * \\param Cookie A pointer to a cookie for the procedure address.\n * \\param ModuleName The name of the module.\n * \\param ProcedureName The name of the procedure.\n * \\return A pointer to the imported procedure, or NULL if the procedure could not be imported.\n */\nFORCEINLINE\nPVOID PhpImportProcedure(\n    _Inout_ PPH_INITONCE InitOnce,\n    _Inout_ PVOID *Cache,\n    _Inout_ PULONG_PTR Cookie,\n    _In_ PCWSTR ModuleName,\n    _In_ PCSTR ProcedureName\n    )\n{\n    if (PhBeginInitOnce(InitOnce))\n    {\n        PVOID module;\n        PVOID procedure;\n\n        module = PhGetLoaderEntryDllBaseZ(ModuleName);\n\n        if (!module)\n            module = PhLoadLibrary(ModuleName);\n\n        if (module)\n        {\n            if (procedure = PhGetDllBaseProcedureAddress(module, ProcedureName, 0))\n            {\n                *Cookie = (ULONG_PTR)PhReadTimeStampCounter();\n                *Cache = (PVOID)((ULONG_PTR)procedure ^ (ULONG_PTR)*Cookie);\n            }\n        }\n\n        PhEndInitOnce(InitOnce);\n    }\n\n    if (*Cache && *Cookie)\n        return (PVOID)((ULONG_PTR)*Cache ^ (ULONG_PTR)*Cookie);\n\n    return NULL;\n}\n\n/**\n * Imports a procedure from a specified module using native methods.\n *\n * \\param InitOnce A pointer to an initialization structure.\n * \\param Cache A pointer to a cache for the procedure address.\n * \\param Cookie A pointer to a cookie for the procedure address.\n * \\param ModuleName The name of the module.\n * \\param ProcedureName The name of the procedure.\n * \\return A pointer to the imported procedure, or NULL if the procedure could not be imported.\n */\nFORCEINLINE\nPVOID PhpImportProcedureNative(\n    _Inout_ PPH_INITONCE InitOnce,\n    _Inout_ PVOID *Cache,\n    _Inout_ PULONG_PTR Cookie,\n    _In_ PCWSTR ModuleName,\n    _In_ PCSTR ProcedureName\n    )\n{\n    if (PhBeginInitOnce(InitOnce))\n    {\n        PVOID module;\n        PVOID procedure;\n\n        module = PhGetLoaderEntryDllBaseZ(ModuleName);\n\n        if (!module)\n            module = PhLoadLibrary(ModuleName);\n\n        if (module)\n        {\n            ANSI_STRING procedureName;\n\n            RtlInitAnsiString(&procedureName, ProcedureName);\n\n            if (NT_SUCCESS(LdrGetProcedureAddress(\n                module,\n                &procedureName,\n                0,\n                &procedure\n                )))\n            {\n                *Cookie = (ULONG_PTR)PhReadTimeStampCounter();\n                *Cache = (PVOID)((ULONG_PTR)procedure ^ (ULONG_PTR)*Cookie);\n            }\n        }\n\n        PhEndInitOnce(InitOnce);\n    }\n\n    if (*Cache && *Cookie)\n        return (PVOID)((ULONG_PTR)*Cache ^ (ULONG_PTR)*Cookie);\n\n    return NULL;\n}\n\n/**\n * Defines an import function for a specified module and procedure.\n *\n * \\param Module The name of the module.\n * \\param Name The name of the procedure.\n */\n#define PH_DEFINE_IMPORT(Module, Name) \\\ntypeof(&(Name)) Name##_Import(VOID) \\\n{ \\\n    static PH_INITONCE initOnce = PH_INITONCE_INIT; \\\n    static PVOID cache = NULL; \\\n    static ULONG_PTR cookie = 0; \\\n\\\n    return (typeof(&(Name)))PhpImportProcedure(&initOnce, &cache, &cookie, (Module), (#Name)); \\\n}\n\n/**\n * Defines an import function for a specified module and procedure for native loading.\n *\n * \\param Module The name of the module.\n * \\param Name The name of the procedure.\n */\n#define PH_DEFINE_IMPORT_NATIVE(Module, Name) \\\ntypeof(&(Name)) Name##_Import(VOID) \\\n{ \\\n    static PH_INITONCE initOnce = PH_INITONCE_INIT; \\\n    static PVOID cache = NULL; \\\n    static ULONG_PTR cookie = 0; \\\n\\\n    return (typeof(&(Name)))PhpImportProcedureNative(&initOnce, &cache, &cookie, (Module), (#Name)); \\\n}\n\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtQueryInformationEnlistment);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtQueryInformationResourceManager);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtQueryInformationTransaction);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtQueryInformationTransactionManager);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtCreateProcessStateChange);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtChangeProcessState);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtCreateThreadStateChange);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtChangeThreadState);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtCopyFileChunk);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtCompareObjects);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtCreateTimer2);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtSetTimer2);\n\nPH_DEFINE_IMPORT_NATIVE(L\"ntdll.dll\", NtSetInformationVirtualMemory);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", LdrSystemDllInitBlock);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", LdrResFindResource);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", LdrResSearchResource);\n\nPH_DEFINE_IMPORT(L\"ntdll.dll\", RtlDefaultNpAcl);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", RtlDelayExecution);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", RtlDeriveCapabilitySidsFromName);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", RtlDosLongPathNameToNtPathName_U_WithStatus);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", RtlGetTokenNamedObjectPath);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", RtlGetAppContainerNamedObjectPath);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", RtlGetAppContainerSidType);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", RtlGetAppContainerParent);\n\nPH_DEFINE_IMPORT(L\"ntdll.dll\", PssNtCaptureSnapshot);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", PssNtQuerySnapshot);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", PssNtFreeSnapshot);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", PssNtFreeRemoteSnapshot);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtPssCaptureVaSpaceBulk);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", TpSetPoolThreadBasePriority);\n\nPH_DEFINE_IMPORT(L\"advapi32.dll\", ConvertSecurityDescriptorToStringSecurityDescriptorW);\nPH_DEFINE_IMPORT(L\"advapi32.dll\", ConvertStringSecurityDescriptorToSecurityDescriptorW);\n\nPH_DEFINE_IMPORT(L\"cfgmgr32.dll\", DevGetObjects);\nPH_DEFINE_IMPORT(L\"cfgmgr32.dll\", DevFreeObjects);\nPH_DEFINE_IMPORT(L\"cfgmgr32.dll\", DevGetObjectProperties);\nPH_DEFINE_IMPORT(L\"cfgmgr32.dll\", DevFreeObjectProperties);\nPH_DEFINE_IMPORT(L\"cfgmgr32.dll\", DevCreateObjectQuery);\nPH_DEFINE_IMPORT(L\"cfgmgr32.dll\", DevCloseObjectQuery);\n\nPH_DEFINE_IMPORT(L\"shlwapi.dll\", SHAutoComplete);\nPH_DEFINE_IMPORT(L\"shlwapi.dll\", SHCreateStreamOnFileEx);\n\nPH_DEFINE_IMPORT(L\"userenv.dll\", CreateEnvironmentBlock);\nPH_DEFINE_IMPORT(L\"userenv.dll\", DestroyEnvironmentBlock);\nPH_DEFINE_IMPORT(L\"userenv.dll\", GetAppContainerRegistryLocation);\nPH_DEFINE_IMPORT(L\"userenv.dll\", GetAppContainerFolderPath);\n\nPH_DEFINE_IMPORT(L\"user32.dll\", ConsoleControl);\nPH_DEFINE_IMPORT(L\"user32.dll\", GetCurrentInputMessageSource);\nPH_DEFINE_IMPORT(L\"user32.dll\", GetCIMSSM);\nPH_DEFINE_IMPORT(L\"win32u.dll\", NtUserBuildHwndList);\n\nPH_DEFINE_IMPORT(L\"xmllite.dll\", CreateXmlReader);\nPH_DEFINE_IMPORT(L\"xmllite.dll\", CreateXmlWriter);\n"
  },
  {
    "path": "phlib/apistubs.cpp",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2019-2024\n *\n */\n\n#include <ph.h>\n\n#include <mapldr.h>\n#include <sddl.h>\n#include <shlwapi.h>\n#include <userenv.h>\n#include <ntuser.h>\n#include <xmllite.h>\n\nEXTERN_C_START\n\nstatic BOOL WINAPI CloseHandle_Stub(\n    _In_ HANDLE Handle\n    )\n{\n    NTSTATUS status;\n\n    status = NtClose(Handle);\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return NT_SUCCESS(status);\n}\n\nstatic BOOL WINAPI GetFileSizeEx_Stub(\n    _In_ HANDLE hFile,\n    _Out_ PLARGE_INTEGER lpFileSize\n    )\n{\n    NTSTATUS status;\n\n    status = PhGetFileSize(hFile, lpFileSize);\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return NT_SUCCESS(status);\n}\n\nstatic FARPROC WINAPI GetProcAddress_Stub(\n    _In_ HMODULE Module,\n    _In_ PCSTR Name\n    )\n{\n    NTSTATUS status;\n    PVOID procedureAddress;\n\n    if (IS_INTRESOURCE(Name))\n    {\n        status = LdrGetProcedureAddress(\n            Module,\n            nullptr,\n            PtrToUshort(Name),\n            &procedureAddress\n            );\n    }\n    else\n    {\n        ANSI_STRING procedureName;\n\n        RtlInitAnsiString(&procedureName, Name);\n        status = LdrGetProcedureAddress(\n            Module,\n            &procedureName,\n            0,\n            &procedureAddress\n            );\n    }\n\n    PhSetLastError(PhNtStatusToDosError(status));\n\n    if (NT_SUCCESS(status))\n    {\n        return reinterpret_cast<FARPROC>(procedureAddress);\n    }\n\n    return nullptr;\n}\n\nstatic BOOL WINAPI FlushFileBuffers_Stub(\n    _In_ HANDLE hFile\n    )\n{\n    NTSTATUS status;\n\n    status = PhFlushBuffersFile(hFile);\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return NT_SUCCESS(status);\n}\n\nstatic BOOL WINAPI IsDebuggerPresent_Stub(\n    VOID\n    )\n{\n    NTSTATUS status;\n    BOOL result;\n\n    result = !!NtCurrentPeb()->BeingDebugged;\n    status = STATUS_SUCCESS;\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return result;\n}\n\nstatic BOOL WINAPI SetEndOfFile_Stub(\n    _In_ HANDLE hFile\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER position;\n\n    status = PhGetFilePosition(hFile, &position);\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhSetFilePosition(hFile, &position);\n    }\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return NT_SUCCESS(status);\n}\n\nstatic BOOL WINAPI SetFilePointerEx_Stub(\n    _In_ HANDLE File,\n    _In_ LARGE_INTEGER DistanceToMove,\n    _Out_opt_ PLARGE_INTEGER NewFilePointer,\n    _In_ ULONG MoveMethod\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER position;\n    LARGE_INTEGER current;\n    LARGE_INTEGER fileSize;\n\n    switch (MoveMethod)\n    {\n    case FILE_BEGIN:\n        position = DistanceToMove;\n        break;\n    case FILE_CURRENT:\n        {\n            status = PhGetFilePosition(File, &current);\n\n            if (!NT_SUCCESS(status))\n            {\n                PhSetLastError(PhNtStatusToDosError(status));\n                return FALSE;\n            }\n\n            position.QuadPart = current.QuadPart + DistanceToMove.QuadPart;\n        }\n        break;\n    case FILE_END:\n        {\n            status = PhGetFileSize(File, &fileSize);\n\n            if (!NT_SUCCESS(status))\n            {\n                PhSetLastError(PhNtStatusToDosError(status));\n                return FALSE;\n            }\n\n            position.QuadPart = fileSize.QuadPart + DistanceToMove.QuadPart;\n        }\n        break;\n    default:\n        PhSetLastError(ERROR_INVALID_PARAMETER);\n        return FALSE;\n    }\n\n    status = PhSetFilePosition(File, &position);\n\n    PhSetLastError(PhNtStatusToDosError(status));\n\n    if (NT_SUCCESS(status))\n    {\n        if (NewFilePointer)\n        {\n            *NewFilePointer = position;\n        }\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nDECLSPEC_NORETURN\nstatic VOID WINAPI ExitProcess_Stub(\n    _In_ UINT uExitCode\n    )\n{\n    PhExitApplication(PhDosErrorToNtStatus(uExitCode));\n}\n\nstatic BOOL WINAPI TerminateProcess_Stub(\n    _In_ HANDLE hProcess,\n    _In_ UINT uExitCode\n    )\n{\n    NTSTATUS status;\n\n    status = NtTerminateProcess(hProcess, PhDosErrorToNtStatus(uExitCode));\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return NT_SUCCESS(status);\n}\n\nstatic ULONG WINAPI GetCurrentThreadId_Stub(\n    VOID\n    )\n{\n    NTSTATUS status;\n    ULONG result;\n\n    result = HandleToUlong(NtCurrentThreadId());\n    status = STATUS_SUCCESS;\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return result;\n}\n\nstatic ULONG WINAPI GetCurrentProcessId_Stub(\n    VOID\n    )\n{\n    NTSTATUS status;\n    ULONG result;\n\n    result = HandleToUlong(NtCurrentProcessId());\n    status = STATUS_SUCCESS;\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return result;\n}\n\nstatic HANDLE WINAPI GetCurrentProcess_Stub(\n    VOID\n    )\n{\n    NTSTATUS status;\n    HANDLE result;\n\n    result = NtCurrentProcess();\n    status = STATUS_SUCCESS;\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return result;\n}\n\nstatic HANDLE WINAPI GetProcessHeap_Stub(\n    VOID\n    )\n{\n    NTSTATUS status;\n    HANDLE result;\n\n    result = RtlProcessHeap();\n    status = STATUS_SUCCESS;\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return result;\n}\n\nstatic LPSTR WINAPI GetCommandLineA_Stub(\n    VOID\n    )\n{\n    return nullptr;\n}\n\nstatic LPWSTR WINAPI GetCommandLineW_Stub(\n    VOID\n    )\n{\n    return nullptr;\n}\n\nstatic HMODULE WINAPI GetModuleHandleW_Stub(\n    _In_opt_ PCWSTR ModuleName\n    )\n{\n    NTSTATUS status;\n    HMODULE result;\n\n    if (ModuleName)\n        result = static_cast<HMODULE>(PhGetDllHandle(ModuleName));\n    else\n        result = static_cast<HMODULE>(NtCurrentPeb()->ImageBaseAddress);\n\n    if (result)\n        status = STATUS_SUCCESS;\n    else\n        status = STATUS_DLL_NOT_FOUND;\n\n    PhSetLastError(PhNtStatusToDosError(status));\n    return result;\n}\n\nstatic BOOL WINAPI QueryPerformanceCounter_Stub(\n    _Out_ LARGE_INTEGER* PerformanceCount\n    )\n{\n    return !!RtlQueryPerformanceCounter(PerformanceCount);\n}\n\nstatic VOID WINAPI GetSystemTimeAsFileTime_Stub(\n    _Out_ PFILETIME SystemTime\n    )\n{\n    LARGE_INTEGER systemTime;\n\n    PhQuerySystemTime(&systemTime);\n\n    SystemTime->dwLowDateTime = systemTime.LowPart;\n    SystemTime->dwHighDateTime = systemTime.HighPart;\n}\n\nstatic BOOL WINAPI VirtualProtect_Stub(\n    _In_ PVOID Address,\n    _In_ SIZE_T Size,\n    _In_ ULONG NewProtect,\n    _Out_opt_ PULONG OldProtect\n    )\n{\n    NTSTATUS status;\n    ULONG oldProtect = 0;\n\n    status = PhProtectVirtualMemory(\n        NtCurrentProcess(),\n        Address,\n        Size,\n        NewProtect,\n        &oldProtect\n        );\n\n    PhSetLastError(PhNtStatusToDosError(status));\n\n    if (NT_SUCCESS(status))\n    {\n        if (OldProtect)\n        {\n            *OldProtect = oldProtect;\n        }\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nstatic VOID WINAPI EnterCriticalSection_Stub(\n    _Inout_ LPCRITICAL_SECTION CriticalSection\n    )\n{\n    RtlEnterCriticalSection(CriticalSection);\n}\n\nstatic VOID WINAPI LeaveCriticalSection_Stub(\n    _Inout_ LPCRITICAL_SECTION CriticalSection\n    )\n{\n    _Analysis_assume_lock_acquired_(*CriticalSection);\n\n    RtlLeaveCriticalSection(CriticalSection);\n}\n\nstatic VOID WINAPI DeleteCriticalSection_Stub(\n    _Inout_ LPCRITICAL_SECTION CriticalSection\n    )\n{\n    RtlDeleteCriticalSection(CriticalSection);\n}\n\nstatic PVOID WINAPI HeapAllocate_Stub(\n    _In_ PVOID HeapHandle,\n    _In_opt_ ULONG Flags,\n    _In_ SIZE_T Size\n    )\n{\n    return RtlAllocateHeap(HeapHandle, Flags, Size);\n}\n\nstatic PVOID WINAPI HeapReAlloc_Stub(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _Frees_ptr_opt_ PVOID BaseAddress,\n    _In_ SIZE_T Size\n    )\n{\n    return RtlReAllocateHeap(HeapHandle, Flags, BaseAddress, Size);\n}\n\nstatic SIZE_T WINAPI HeapSize_Stub(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ PCVOID BaseAddress\n    )\n{\n    return RtlSizeHeap(HeapHandle, Flags, BaseAddress);\n}\n\nstatic BOOL WINAPI HeapFree_Stub(\n    _In_ PVOID HeapHandle,\n    _In_opt_ ULONG Flags,\n    _Frees_ptr_opt_ _Post_invalid_ PVOID BaseAddress\n    )\n{\n    return !!RtlFreeHeap(HeapHandle, Flags, BaseAddress);\n}\n\n#if defined(_M_IX86)\n#pragma warning(push)\n#pragma warning(disable: 4483)\n__declspec(selectany) decltype(&CloseHandle) __identifier(\"_imp__CloseHandle@4\") = CloseHandle_Stub;\n__declspec(selectany) decltype(&GetFileSizeEx) __identifier(\"_imp__GetFileSizeEx@4\") = GetFileSizeEx_Stub;\n__declspec(selectany) decltype(&GetProcAddress) __identifier(\"_imp__GetProcAddress@8\") = GetProcAddress_Stub;\n__declspec(selectany) decltype(&FlushFileBuffers) __identifier(\"_imp__FlushFileBuffers@4\") = FlushFileBuffers_Stub;\n__declspec(selectany) decltype(&TerminateProcess) __identifier(\"_imp__TerminateProcess@8\") = TerminateProcess_Stub;\n__declspec(selectany) decltype(&GetCurrentThreadId) __identifier(\"_imp__GetCurrentThreadId@0\") = GetCurrentThreadId_Stub;\n__declspec(selectany) decltype(&GetCurrentProcessId) __identifier(\"_imp__GetCurrentProcessId@0\") = GetCurrentProcessId_Stub;\n__declspec(selectany) decltype(&GetCurrentProcess) __identifier(\"_imp__GetCurrentProcess@0\") = GetCurrentProcess_Stub;\n__declspec(selectany) decltype(&GetProcessHeap) __identifier(\"_imp__GetProcessHeap@0\") = GetProcessHeap_Stub;\n__declspec(selectany) decltype(&GetCommandLineA) __identifier(\"_imp__GetCommandLineA@0\") = GetCommandLineA_Stub;\n__declspec(selectany) decltype(&GetCommandLineW) __identifier(\"_imp__GetCommandLineW@0\") = GetCommandLineW_Stub;\n__declspec(selectany) decltype(&GetModuleHandleW) __identifier(\"_imp__GetModuleHandleW@4\") = GetModuleHandleW_Stub;\n__declspec(selectany) decltype(&IsDebuggerPresent) __identifier(\"_imp__IsDebuggerPresent@0\") = IsDebuggerPresent_Stub;\n__declspec(selectany) decltype(&SetEndOfFile) __identifier(\"_imp__SetEndOfFile@4\") = SetEndOfFile_Stub;\n__declspec(selectany) decltype(&ExitProcess) __identifier(\"_imp__ExitProcess@4\") = ExitProcess_Stub;\n__declspec(selectany) decltype(&VirtualProtect) __identifier(\"_imp__VirtualProtect@16\") = VirtualProtect_Stub;\n__declspec(selectany) decltype(&InitializeSListHead) __identifier(\"_imp__InitializeSListHead@4\") = PhInitializeSListHead;\n__declspec(selectany) decltype(&InterlockedPushEntrySList) __identifier(\"_imp__InterlockedPushEntrySList@8\") = RtlInterlockedPushEntrySList;\n__declspec(selectany) decltype(&InterlockedFlushSList) __identifier(\"_imp__InterlockedFlushSList@4\") = RtlInterlockedFlushSList;\n__declspec(selectany) decltype(&QueryPerformanceCounter) __identifier(\"_imp__QueryPerformanceCounter@4\") = QueryPerformanceCounter_Stub;\n__declspec(selectany) decltype(&GetSystemTimeAsFileTime) __identifier(\"_imp__GetSystemTimeAsFileTime@4\") = GetSystemTimeAsFileTime_Stub;\n__declspec(selectany) decltype(&SetFilePointerEx) __identifier(\"_imp__SetFilePointerEx@16\") = SetFilePointerEx_Stub;\n__declspec(selectany) decltype(&EnterCriticalSection) __identifier(\"_imp__EnterCriticalSection@4\") = EnterCriticalSection_Stub;\n__declspec(selectany) decltype(&LeaveCriticalSection) __identifier(\"_imp__LeaveCriticalSection@4\") = LeaveCriticalSection_Stub;\n__declspec(selectany) decltype(&DeleteCriticalSection) __identifier(\"_imp__DeleteCriticalSection@4\") = DeleteCriticalSection_Stub;\n__declspec(selectany) decltype(&AcquireSRWLockExclusive) __identifier(\"_imp__AcquireSRWLockExclusive@4\") = RtlAcquireSRWLockExclusive;\n__declspec(selectany) decltype(&ReleaseSRWLockExclusive) __identifier(\"_imp__ReleaseSRWLockExclusive@4\") = RtlReleaseSRWLockExclusive;\n__declspec(selectany) decltype(&HeapAlloc) __identifier(\"_imp__HeapAlloc@12\") = HeapAllocate_Stub;\n__declspec(selectany) decltype(&HeapReAlloc) __identifier(\"_imp__HeapReAlloc@16\") = HeapReAlloc_Stub;\n__declspec(selectany) decltype(&HeapSize) __identifier(\"_imp__HeapSize@12\") = HeapSize_Stub;\n__declspec(selectany) decltype(&HeapFree) __identifier(\"_imp__HeapFree@12\") = HeapFree_Stub;\n#pragma warning(pop)\n#else\n__declspec(selectany) decltype(&CloseHandle) __imp_CloseHandle = CloseHandle_Stub;\n__declspec(selectany) decltype(&GetFileSizeEx) __imp_GetFileSizeEx = GetFileSizeEx_Stub;\n__declspec(selectany) decltype(&GetProcAddress) __imp_GetProcAddress = GetProcAddress_Stub;\n__declspec(selectany) decltype(&FlushFileBuffers) __imp_FlushFileBuffers = FlushFileBuffers_Stub;\n__declspec(selectany) decltype(&TerminateProcess) __imp_TerminateProcess = TerminateProcess_Stub;\n__declspec(selectany) decltype(&GetCurrentThreadId) __imp_GetCurrentThreadId = GetCurrentThreadId_Stub;\n__declspec(selectany) decltype(&GetCurrentProcessId) __imp_GetCurrentProcessId = GetCurrentProcessId_Stub;\n__declspec(selectany) decltype(&GetCurrentProcess) __imp_GetCurrentProcess = GetCurrentProcess_Stub;\n__declspec(selectany) decltype(&GetProcessHeap) __imp_GetProcessHeap = GetProcessHeap_Stub;\n__declspec(selectany) decltype(&GetCommandLineA) __imp_GetCommandLineA = GetCommandLineA_Stub;\n__declspec(selectany) decltype(&GetCommandLineW) __imp_GetCommandLineW = GetCommandLineW_Stub;\n__declspec(selectany) decltype(&GetModuleHandleW) __imp_GetModuleHandleW = GetModuleHandleW_Stub;\n__declspec(selectany) decltype(&IsDebuggerPresent) __imp_IsDebuggerPresent = IsDebuggerPresent_Stub;\n__declspec(selectany) decltype(&SetEndOfFile) __imp_SetEndOfFile = SetEndOfFile_Stub;\n__declspec(selectany) decltype(&ExitProcess) __imp_ExitProcess = ExitProcess_Stub;\n__declspec(selectany) decltype(&VirtualProtect) __imp_VirtualProtect = VirtualProtect_Stub;\n__declspec(selectany) decltype(&InitializeSListHead) __imp_InitializeSListHead = PhInitializeSListHead;\n__declspec(selectany) decltype(&InterlockedPushEntrySList) __imp_InterlockedPushEntrySList = RtlInterlockedPushEntrySList;\n__declspec(selectany) decltype(&InterlockedFlushSList) __imp_InterlockedFlushSList = RtlInterlockedFlushSList;\n__declspec(selectany) decltype(&QueryPerformanceCounter) __imp_QueryPerformanceCounter = QueryPerformanceCounter_Stub;\n__declspec(selectany) decltype(&GetSystemTimeAsFileTime) __imp_GetSystemTimeAsFileTime = GetSystemTimeAsFileTime_Stub;\n__declspec(selectany) decltype(&SetFilePointerEx) __imp_SetFilePointerEx = SetFilePointerEx_Stub;\n__declspec(selectany) decltype(&EnterCriticalSection) __imp_EnterCriticalSection = EnterCriticalSection_Stub;\n__declspec(selectany) decltype(&LeaveCriticalSection) __imp_LeaveCriticalSection = LeaveCriticalSection_Stub;\n__declspec(selectany) decltype(&DeleteCriticalSection) __imp_DeleteCriticalSection = DeleteCriticalSection_Stub;\n__declspec(selectany) decltype(&AcquireSRWLockExclusive) __imp_AcquireSRWLockExclusive = RtlAcquireSRWLockExclusive;\n__declspec(selectany) decltype(&ReleaseSRWLockExclusive) __imp_ReleaseSRWLockExclusive = RtlReleaseSRWLockExclusive;\n__declspec(selectany) decltype(&HeapAlloc) __imp_HeapAlloc = HeapAllocate_Stub;\n__declspec(selectany) decltype(&HeapReAlloc) __imp_HeapReAlloc = HeapReAlloc_Stub;\n__declspec(selectany) decltype(&HeapSize) __imp_HeapSize = HeapSize_Stub;\n__declspec(selectany) decltype(&HeapFree) __imp_HeapFree = HeapFree_Stub;\n#endif\n\nEXTERN_C_END\n"
  },
  {
    "path": "phlib/appresolver.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017-2023\n *\n */\n\n#include <ph.h>\n#include <lsasup.h>\n#include <mapldr.h>\n#include <guisup.h>\n\n#include <shobjidl.h>\n#include <shlobj_core.h>\n\n#include <appresolverp.h>\n#include <appresolver.h>\n\nstatic typeof(&AppContainerDeriveSidFromMoniker) AppContainerDeriveSidFromMoniker_I = NULL;\nstatic typeof(&AppContainerLookupMoniker) AppContainerLookupMoniker_I = NULL;\nstatic typeof(&AppContainerFreeMemory) AppContainerFreeMemory_I = NULL;\n\n/**\n * Queries the AppResolver interface.\n *\n * \\return A pointer to the AppResolver interface, or NULL if the interface could not be queried.\n */\nstatic PVOID PhpQueryAppResolverInterface(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID resolverInterface = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion < WINDOWS_8)\n            PhGetClassObject(L\"appresolver.dll\", &CLSID_StartMenuCacheAndAppResolver_I, &IID_IApplicationResolver_I, &resolverInterface);\n        else\n            PhGetClassObject(L\"appresolver.dll\", &CLSID_StartMenuCacheAndAppResolver_I, &IID_IApplicationResolver2_I, &resolverInterface);\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return resolverInterface;\n}\n\n/**\n * Queries the StartMenuCache interface.\n *\n * \\return A pointer to the StartMenuCache interface, or NULL if the interface could not be queried.\n */\nstatic PVOID PhpQueryStartMenuCacheInterface(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID startMenuInterface = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion < WINDOWS_8)\n            PhGetClassObject(L\"appresolver.dll\", &CLSID_StartMenuCacheAndAppResolver_I, &IID_IStartMenuAppItems_I, &startMenuInterface);\n        else\n            PhGetClassObject(L\"appresolver.dll\", &CLSID_StartMenuCacheAndAppResolver_I, &IID_IStartMenuAppItems2_I, &startMenuInterface);\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return startMenuInterface;\n}\n\n/**\n * Checks if the AppContainer functions are initialized.\n *\n * \\return TRUE if initialized, FALSE otherwise.\n */\nstatic BOOLEAN PhpKernelAppCoreInitialized(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOLEAN kernelAppCoreInitialized = FALSE;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion >= WINDOWS_8)\n        {\n            PVOID baseAddress;\n\n            if(baseAddress = PhLoadLibrary(L\"kernelbase.dll\"))\n            {\n                AppContainerDeriveSidFromMoniker_I = PhGetDllBaseProcedureAddress(baseAddress, \"AppContainerDeriveSidFromMoniker\", 0);\n                AppContainerLookupMoniker_I = PhGetDllBaseProcedureAddress(baseAddress, \"AppContainerLookupMoniker\", 0);\n                AppContainerFreeMemory_I = PhGetDllBaseProcedureAddress(baseAddress, \"AppContainerFreeMemory\", 0);\n            }\n\n            if (\n                AppContainerDeriveSidFromMoniker_I &&\n                AppContainerLookupMoniker_I &&\n                AppContainerFreeMemory_I\n                )\n            {\n                kernelAppCoreInitialized = TRUE;\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return kernelAppCoreInitialized;\n}\n\n/**\n * Retrieves the Application User Model ID (AppUserModelId) for a specified process.\n *\n * \\param ProcessId The handle to the process.\n * \\param ApplicationUserModelId A pointer to a string that receives the Application User Model ID.\n * \\return HRESULT indicating success or failure.\n */\nHRESULT PhAppResolverGetAppIdForProcess(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING *ApplicationUserModelId\n    )\n{\n    HRESULT status;\n    PVOID resolverInterface;\n    PWSTR appIdText;\n\n    if (!(resolverInterface = PhpQueryAppResolverInterface()))\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    if (WindowsVersion < WINDOWS_8)\n    {\n        status = IApplicationResolver_GetAppIDForProcess(\n            (IApplicationResolver*)resolverInterface,\n            HandleToUlong(ProcessId),\n            &appIdText,\n            NULL,\n            NULL,\n            NULL\n            );\n    }\n    else\n    {\n        status = IApplicationResolver2_GetAppIDForProcess(\n            (IApplicationResolver2*)resolverInterface,\n            HandleToUlong(ProcessId),\n            &appIdText,\n            NULL,\n            NULL,\n            NULL\n            );\n    }\n\n    if (HR_SUCCESS(status))\n    {\n        SIZE_T appIdTextLength;\n\n        appIdTextLength = RtlSizeHeap(\n            RtlProcessHeap(),\n            0,\n            appIdText\n            );\n\n        if ((appIdTextLength % sizeof(WCHAR)) == 0 && appIdTextLength > sizeof(UNICODE_NULL))\n        {\n            *ApplicationUserModelId = PhCreateStringEx(\n                appIdText,\n                appIdTextLength - sizeof(UNICODE_NULL)\n                );\n        }\n        else\n        {\n            *ApplicationUserModelId = NULL;\n            status = E_UNEXPECTED;\n        }\n\n        CoTaskMemFree(appIdText);\n    }\n    else\n    {\n        *ApplicationUserModelId = NULL;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the Application User Model ID (AppUserModelId) for a specified window.\n *\n * \\param WindowHandle The handle to the window.\n * \\param ApplicationUserModelId A pointer to a string that receives the Application User Model ID.\n * \\return HRESULT indicating success or failure.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iapplicationactivationmanager-activateapplication\n */\nHRESULT PhAppResolverGetAppIdForWindow(\n    _In_ HWND WindowHandle,\n    _Out_ PPH_STRING *ApplicationUserModelId\n    )\n{\n    HRESULT status;\n    PVOID resolverInterface;\n    PWSTR appIdText;\n\n    if (!(resolverInterface = PhpQueryAppResolverInterface()))\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    if (WindowsVersion < WINDOWS_8)\n    {\n        status = IApplicationResolver_GetAppIDForWindow(\n            (IApplicationResolver*)resolverInterface,\n            WindowHandle,\n            &appIdText,\n            NULL,\n            NULL,\n            NULL\n            );\n    }\n    else\n    {\n        status = IApplicationResolver_GetAppIDForWindow(\n            (IApplicationResolver2*)resolverInterface,\n            WindowHandle,\n            &appIdText,\n            NULL,\n            NULL,\n            NULL\n            );\n    }\n\n    if (SUCCEEDED(status))\n    {\n        SIZE_T appIdTextLength;\n\n        appIdTextLength = RtlSizeHeap(\n            RtlProcessHeap(),\n            0,\n            appIdText\n            );\n\n        if ((appIdTextLength % sizeof(WCHAR)) == 0 && appIdTextLength > sizeof(UNICODE_NULL))\n        {\n            *ApplicationUserModelId = PhCreateStringEx(\n                appIdText,\n                appIdTextLength - sizeof(UNICODE_NULL)\n                );\n        }\n        else\n        {\n            status = E_UNEXPECTED;\n        }\n\n        CoTaskMemFree(appIdText);\n    }\n\n    return status;\n}\n\n/**\n * Activates the specified Windows Store app for the generic launch contract (Windows.Launch) in the current session.\n *\n * \\param[in] ApplicationUserModelId The application user model ID of the Windows Store app.\n * \\param[in] CommandLine A pointer to an optional, app-specific, argument string.\n * \\param[out] ProcessId The process ID of the new instance.\n * \\return HRESULT Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iapplicationactivationmanager-activateapplication\n */\nHRESULT PhAppResolverActivateAppId(\n    _In_ PPH_STRING ApplicationUserModelId,\n    _In_opt_ PCWSTR CommandLine,\n    _Out_opt_ HANDLE *ProcessId\n    )\n{\n    HRESULT status;\n    ULONG processId = ULONG_MAX;\n    IApplicationActivationManager* applicationActivationManager;\n\n    status = PhGetClassObject(\n        L\"twinui.appcore.dll\",\n        &CLSID_ApplicationActivationManager,\n        &IID_IApplicationActivationManager,\n        &applicationActivationManager\n        );\n\n    if (SUCCEEDED(status))\n    {\n        CoAllowSetForegroundWindow((IUnknown*)applicationActivationManager, NULL);\n\n        status = IApplicationActivationManager_ActivateApplication(\n            applicationActivationManager,\n            PhGetString(ApplicationUserModelId),\n            CommandLine,\n            AO_NONE,\n            &processId\n            );\n\n        IApplicationActivationManager_Release(applicationActivationManager);\n    }\n\n    if (SUCCEEDED(status))\n    {\n        if (ProcessId) *ProcessId = UlongToHandle(processId);\n    }\n\n    return status;\n}\n\n/**\n * Terminates all processes for the specified package.\n *\n * \\param PackageFullName The package full name.\n * \\return HRESULT Successful or errant status.\n */\nHRESULT PhAppResolverPackageTerminateProcess(\n    _In_ PCWSTR PackageFullName\n    )\n{\n    HRESULT status;\n    IPackageDebugSettings* packageDebugSettings;\n\n    status = PhGetClassObject(\n        L\"twinapi.appcore.dll\",\n        &CLSID_PackageDebugSettings,\n        &IID_IPackageDebugSettings,\n        &packageDebugSettings\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IPackageDebugSettings_TerminateAllProcesses(\n            packageDebugSettings,\n            PackageFullName\n            );\n\n        IPackageDebugSettings_Release(packageDebugSettings);\n    }\n\n    return status;\n}\n\n/**\n * Enables debug mode for the processes of the specified package.\n *\n * \\param PackageFullName The package full name.\n * \\return HRESULT Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ipackagedebugsettings-enabledebugging\n */\nHRESULT PhAppResolverEnablePackageDebug(\n    _In_ PCWSTR PackageFullName\n    )\n{\n    HRESULT status;\n    IPackageDebugSettings* packageDebugSettings;\n\n    status = PhGetClassObject(\n        L\"twinapi.appcore.dll\",\n        &CLSID_PackageDebugSettings,\n        &IID_IPackageDebugSettings,\n        &packageDebugSettings\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IPackageDebugSettings_EnableDebugging(\n            packageDebugSettings,\n            PackageFullName,\n            NULL,\n            NULL\n            );\n\n        IPackageDebugSettings_Release(packageDebugSettings);\n    }\n\n    return status;\n}\n\n/**\n * Disables debug mode for the processes of the specified package.\n *\n * \\param PackageFullName The package full name.\n * \\return HRESULT Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ipackagedebugsettings-disabledebugging\n */\nHRESULT PhAppResolverDisablePackageDebug(\n    _In_ PCWSTR PackageFullName\n    )\n{\n    HRESULT status;\n    IPackageDebugSettings* packageDebugSettings;\n\n    status = PhGetClassObject(\n        L\"twinapi.appcore.dll\",\n        &CLSID_PackageDebugSettings,\n        &IID_IPackageDebugSettings,\n        &packageDebugSettings\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IPackageDebugSettings_DisableDebugging(\n            packageDebugSettings,\n            PackageFullName\n            );\n\n        IPackageDebugSettings_Release(packageDebugSettings);\n    }\n\n    return status;\n}\n\n/**\n * Suspends the processes of the package if they are currently running.\n *\n * \\param PackageFullName The package full name.\n * \\return HRESULT Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ipackagedebugsettings-suspend\n */\nHRESULT PhAppResolverPackageSuspend(\n    _In_ PCWSTR PackageFullName\n    )\n{\n    HRESULT status;\n    IPackageDebugSettings* packageDebugSettings;\n\n    status = PhGetClassObject(\n        L\"twinapi.appcore.dll\",\n        &CLSID_PackageDebugSettings,\n        &IID_IPackageDebugSettings,\n        &packageDebugSettings\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IPackageDebugSettings_Suspend(\n            packageDebugSettings,\n            PackageFullName\n            );\n\n        IPackageDebugSettings_Release(packageDebugSettings);\n    }\n\n    return status;\n}\n\n/**\n * Resumes the processes of the package if they are currently suspended.\n *\n * \\param PackageFullName The package full name.\n * \\return HRESULT Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ipackagedebugsettings-resume\n */\nHRESULT PhAppResolverPackageResume(\n    _In_ PCWSTR PackageFullName\n    )\n{\n    HRESULT status;\n    IPackageDebugSettings* packageDebugSettings;\n\n    status = PhGetClassObject(\n        L\"twinapi.appcore.dll\",\n        &CLSID_PackageDebugSettings,\n        &IID_IPackageDebugSettings,\n        &packageDebugSettings\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IPackageDebugSettings_Resume(\n            packageDebugSettings,\n            PackageFullName\n            );\n\n        IPackageDebugSettings_Release(packageDebugSettings);\n    }\n\n    return status;\n}\n\n/**\n * Gets the background tasks that are provided by the specified package.\n *\n * \\param[in] PackageFullName The package full name.\n * \\param[in,out] BackgroundTasks A list of task names.\n * \\return HRESULT Successful or errant status.\n */\nHRESULT PhAppResolverEnumeratePackageBackgroundTasks(\n    _In_ PCWSTR PackageFullName,\n    _Inout_ PPH_LIST BackgroundTasks\n    )\n{\n    HRESULT status;\n    IPackageDebugSettings* packageDebugSettings;\n\n    status = PhGetClassObject(\n        L\"twinapi.appcore.dll\",\n        &CLSID_PackageDebugSettings,\n        &IID_IPackageDebugSettings,\n        &packageDebugSettings\n        );\n\n    if (SUCCEEDED(status))\n    {\n        ULONG taskCount = 0;\n        PCGUID taskIds = NULL;\n        PCWSTR* taskNames = NULL;\n\n        status = IPackageDebugSettings_EnumerateBackgroundTasks(\n            packageDebugSettings,\n            PackageFullName,\n            &taskCount,\n            &taskIds,\n            &taskNames\n            );\n\n        if (SUCCEEDED(status))\n        {\n            for (ULONG i = 0; i < taskCount; i++)\n            {\n                PPH_PACKAGE_TASK_ENTRY entry;\n\n                entry = PhAllocateZero(sizeof(PH_PACKAGE_TASK_ENTRY));\n                entry->TaskGuid = taskIds[i];\n                entry->TaskName = PhCreateString(taskNames[i]);\n\n                PhAddItemList(BackgroundTasks, entry);\n            }\n        }\n\n        IPackageDebugSettings_Release(packageDebugSettings);\n    }\n\n    return status;\n}\n\n/**\n * Stops redirection of background tasks for the specified package.\n *\n * \\param PackageFullName The package full name.\n * \\return HRESULT Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ipackagedebugsettings-stopsessionredirection\n */\nHRESULT PhAppResolverPackageStopSessionRedirection(\n    _In_ PCWSTR PackageFullName\n    )\n{\n    HRESULT status;\n    IPackageDebugSettings* packageDebugSettings;\n\n    status = PhGetClassObject(\n        L\"twinapi.appcore.dll\",\n        &CLSID_PackageDebugSettings,\n        &IID_IPackageDebugSettings,\n        &packageDebugSettings\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IPackageDebugSettings_StopSessionRedirection(\n            packageDebugSettings,\n            PackageFullName\n            );\n\n        IPackageDebugSettings_Release(packageDebugSettings);\n    }\n\n    return status;\n}\n\nPPH_STRING PhGetAppContainerName(\n    _In_ PSID AppContainerSid\n    )\n{\n    HRESULT result;\n    PPH_STRING appContainerName = NULL;\n    PWSTR packageMonikerName;\n\n    if (!PhpKernelAppCoreInitialized())\n        return NULL;\n\n    result = AppContainerLookupMoniker_I(\n        AppContainerSid,\n        &packageMonikerName\n        );\n\n    if (HR_SUCCESS(result))\n    {\n        appContainerName = PhCreateString(packageMonikerName);\n        AppContainerFreeMemory_I(packageMonikerName);\n    }\n    else // Check the local system account appcontainer mappings. (dmex)\n    {\n        static CONST PH_STRINGREF appcontainerMappings = PH_STRINGREF_INIT(L\"Software\\\\Classes\\\\Local Settings\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\AppContainer\\\\Mappings\\\\\");\n        static CONST PH_STRINGREF appcontainerDefaultMappings = PH_STRINGREF_INIT(L\".DEFAULT\\\\\");\n\n        HANDLE keyHandle;\n        PPH_STRING keyPath;\n        USHORT sidStringLength = 0;\n        WCHAR sidString[SECURITY_MAX_SID_STRING_CHARACTERS];\n\n        if (NT_SUCCESS(PhSidToBuffer(\n            AppContainerSid,\n            sidString,\n            sizeof(sidString),\n            &sidStringLength\n            )))\n        {\n            PH_STRINGREF string;\n\n            string.Length = sidStringLength;\n            string.Buffer = sidString;\n\n            keyPath = PhConcatStringRef3(&appcontainerDefaultMappings, &appcontainerMappings, &string);\n\n            if (NT_SUCCESS(PhOpenKey(\n                &keyHandle,\n                KEY_READ,\n                PH_KEY_USERS,\n                &keyPath->sr,\n                0\n                )))\n            {\n                PhMoveReference(&appContainerName, PhQueryRegistryStringZ(keyHandle, L\"Moniker\"));\n                NtClose(keyHandle);\n            }\n\n            PhDereferenceObject(keyPath);\n        }\n    }\n\n    return appContainerName;\n}\n\nPPH_STRING PhGetAppContainerSidFromName(\n    _In_ PCWSTR AppContainerName\n    )\n{\n    PSID appContainerSid;\n    PPH_STRING packageSidString = NULL;\n\n    if (!PhpKernelAppCoreInitialized())\n        return NULL;\n\n    if (HR_SUCCESS(AppContainerDeriveSidFromMoniker_I(\n        AppContainerName,\n        &appContainerSid\n        )))\n    {\n        packageSidString = PhSidToStringSid(appContainerSid);\n\n        RtlFreeSid(appContainerSid);\n    }\n\n    return packageSidString;\n}\n\nPPH_STRING PhGetAppContainerPackageName(\n    _In_ PSID Sid\n    )\n{\n    static CONST PH_STRINGREF appcontainerMappings = PH_STRINGREF_INIT(L\"Software\\\\Classes\\\\Local Settings\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\AppContainer\\\\Mappings\\\\\");\n    static CONST PH_STRINGREF appcontainerDefaultMappings = PH_STRINGREF_INIT(L\".DEFAULT\\\\\");\n    HANDLE keyHandle;\n    PPH_STRING sidString;\n    PPH_STRING keyPath;\n    PPH_STRING packageName = NULL;\n\n    if (PhEqualSid(Sid, PhSeInternetExplorerSid())) // S-1-15-3-4096 (dmex)\n    {\n        return PhCreateString(L\"InternetExplorer\");\n    }\n\n    if (!(sidString = PhSidToStringSid(Sid)))\n        return NULL;\n\n    keyPath = PhConcatStringRef2(&appcontainerMappings, &sidString->sr);\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_CURRENT_USER,\n        &keyPath->sr,\n        0\n        )))\n    {\n        PhMoveReference(&packageName, PhQueryRegistryStringZ(keyHandle, L\"Moniker\"));\n        NtClose(keyHandle);\n    }\n\n    PhDereferenceObject(keyPath);\n\n    // Check the local system account appcontainer mappings. (dmex)\n    if (PhIsNullOrEmptyString(packageName))\n    {\n        keyPath = PhConcatStringRef3(&appcontainerDefaultMappings, &appcontainerMappings, &sidString->sr);\n\n        if (NT_SUCCESS(PhOpenKey(\n            &keyHandle,\n            KEY_READ,\n            PH_KEY_USERS,\n            &keyPath->sr,\n            0\n            )))\n        {\n            PhMoveReference(&packageName, PhQueryRegistryStringZ(keyHandle, L\"Moniker\"));\n            NtClose(keyHandle);\n        }\n\n        PhDereferenceObject(keyPath);\n    }\n\n    PhDereferenceObject(sidString);\n\n    return packageName;\n}\n\n// rev from GetPackagePath (dmex)\nPPH_STRING PhGetPackagePath(\n    _In_ PPH_STRING PackageFullName\n    )\n{\n    static CONST PH_STRINGREF storeAppPackages = PH_STRINGREF_INIT(L\"Software\\\\Classes\\\\Local Settings\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\AppModel\\\\Repository\\\\Packages\\\\\");\n    HANDLE keyHandle;\n    PPH_STRING keyPath;\n    PPH_STRING packagePath = NULL;\n\n    keyPath = PhConcatStringRef2(&storeAppPackages, &PackageFullName->sr);\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_CURRENT_USER,\n        &keyPath->sr,\n        0\n        )))\n    {\n        packagePath = PhQueryRegistryStringZ(keyHandle, L\"PackageRootFolder\");\n        NtClose(keyHandle);\n    }\n\n    PhDereferenceObject(keyPath);\n\n    return packagePath;\n}\n\nPPH_STRING PhGetPackageAppDataPath(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    static CONST PH_STRINGREF attributeName = PH_STRINGREF_INIT(L\"WIN://SYSAPPID\");\n    PPH_STRING packageAppDataPath = NULL;\n    PPH_STRING localAppDataPath;\n    PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info;\n    HANDLE tokenHandle;\n\n    localAppDataPath = PhGetKnownLocationZ(PH_FOLDERID_LocalAppData, L\"\\\\Packages\\\\\", FALSE);\n\n    if (PhIsNullOrEmptyString(localAppDataPath))\n        return NULL;\n\n    if (NT_SUCCESS(PhOpenProcessToken(ProcessHandle, TOKEN_QUERY, &tokenHandle)))\n    {\n        if (NT_SUCCESS(PhGetTokenSecurityAttribute(tokenHandle, &attributeName, &info)))\n        {\n            for (ULONG i = 0; i < info->AttributeCount; i++)\n            {\n                PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->AttributeV1[i];\n\n                if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING)\n                {\n                    PH_STRINGREF valueAttributeName;\n\n                    PhUnicodeStringToStringRef(&attribute->Name, &valueAttributeName);\n\n                    if (PhEqualStringRef(&valueAttributeName, &attributeName, FALSE))\n                    {\n                        PPH_STRING attributeValue;\n\n                        attributeValue = PhCreateStringFromUnicodeString(&attribute->Values.String[2]);\n                        packageAppDataPath = PhConcatStringRef2(&localAppDataPath->sr, &attributeValue->sr);\n\n                        PhDereferenceObject(attributeValue);\n                        break;\n                    }\n                }\n            }\n\n            PhFree(info);\n        }\n\n        NtClose(tokenHandle);\n    }\n\n    PhDereferenceObject(localAppDataPath);\n\n    return packageAppDataPath;\n}\n\nBOOLEAN PhIsPackageCapabilitySid(\n    _In_ PSID AppContainerSid,\n    _In_ PSID Sid\n    )\n{\n    BOOLEAN isPackageCapability = TRUE;\n\n    for (ULONG i = 1; i < SECURITY_APP_PACKAGE_RID_COUNT - 1; i++)\n    {\n        if (\n            *PhSubAuthoritySid(AppContainerSid, i) !=\n            *PhSubAuthoritySid(Sid, i)\n            )\n        {\n            isPackageCapability = FALSE;\n            break;\n        }\n    }\n\n    return isPackageCapability;\n}\n\nPPH_LIST PhGetPackageAssetsFromResourceFile(\n    _In_ PCWSTR FilePath\n    )\n{\n    IMrtResourceManager* resourceManager = NULL;\n    IResourceMap* resourceMap = NULL;\n    PPH_LIST resourceList = NULL;\n    ULONG resourceCount = 0;\n\n    if (FAILED(PhGetClassObject(\n        L\"mrmcorer.dll\",\n        &CLSID_MrtResourceManager_I,\n        &IID_IMrtResourceManager_I,\n        &resourceManager\n        )))\n    {\n        return FALSE;\n    }\n\n    if (FAILED(IMrtResourceManager_InitializeForFile(resourceManager, FilePath)))\n        goto CleanupExit;\n\n    if (FAILED(IMrtResourceManager_GetMainResourceMap(resourceManager, &IID_IResourceMap_I, &resourceMap)))\n        goto CleanupExit;\n\n    if (FAILED(IResourceMap_GetNamedResourceCount(resourceMap, &resourceCount)))\n        goto CleanupExit;\n\n    resourceList = PhCreateList(10);\n\n    for (ULONG i = 0; i < resourceCount; i++)\n    {\n        PWSTR resourceName;\n\n        if (SUCCEEDED(IResourceMap_GetNamedResourceUri(resourceMap, i, &resourceName)))\n        {\n            PhAddItemList(resourceList, PhCreateString(resourceName));\n        }\n    }\n\nCleanupExit:\n\n    if (resourceMap)\n        IResourceMap_Release(resourceMap);\n\n    if (resourceManager)\n        IMrtResourceManager_Release(resourceManager);\n\n    return resourceList;\n}\n\nHRESULT PhAppResolverBeginCrashDumpTask(\n    _In_ HANDLE ProcessId,\n    _Out_ HANDLE *TaskHandle\n    )\n{\n    HRESULT status;\n    IOSTaskCompletion* taskCompletion = NULL;\n\n    status = PhGetClassObject(\n        L\"twinapi.appcore.dll\",\n        &CLSID_OSTaskCompletion_I,\n        &IID_IOSTaskCompletion_I,\n        &taskCompletion\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IOSTaskCompletion_BeginTask(\n            taskCompletion,\n            HandleToUlong(ProcessId),\n            PT_TC_CRASHDUMP\n            );\n    }\n\n    if (SUCCEEDED(status))\n    {\n        *TaskHandle = taskCompletion;\n    }\n    else if (taskCompletion)\n    {\n        IOSTaskCompletion_Release(taskCompletion);\n    }\n\n    return status;\n}\n\nHRESULT PhAppResolverBeginCrashDumpTaskByHandle(\n    _In_ HANDLE ProcessHandle,\n    _Out_ HANDLE *TaskHandle\n    )\n{\n    HRESULT status;\n    IOSTaskCompletion* taskCompletion = NULL;\n\n    status = PhGetClassObject(\n        L\"twinapi.appcore.dll\",\n        &CLSID_OSTaskCompletion_I,\n        &IID_IOSTaskCompletion_I,\n        &taskCompletion\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IOSTaskCompletion_BeginTaskByHandle(\n            taskCompletion,\n            ProcessHandle,\n            PT_TC_CRASHDUMP\n            );\n    }\n\n    if (SUCCEEDED(status))\n    {\n        *TaskHandle = taskCompletion;\n    }\n    else if (taskCompletion)\n    {\n        IOSTaskCompletion_Release(taskCompletion);\n    }\n\n    return status;\n}\n\nHRESULT PhAppResolverEndCrashDumpTask(\n    _In_ HANDLE TaskHandle\n    )\n{\n    IOSTaskCompletion* taskCompletionManager = TaskHandle;\n    HRESULT status;\n\n    status = IOSTaskCompletion_EndTask(taskCompletionManager);\n    IOSTaskCompletion_Release(taskCompletionManager);\n\n    return status;\n}\n\nHRESULT PhAppResolverGetEdpContextForWindow(\n    _In_ HWND WindowHandle,\n    _Out_ EDP_CONTEXT_STATES* State\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    HRESULT status;\n    PEDP_CONTEXT context;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion >= WINDOWS_10)\n        {\n            PVOID baseAddress;\n\n            if (baseAddress = PhLoadLibrary(L\"edputil.dll\"))\n            {\n                EdpGetContextForWindow_I = PhGetDllBaseProcedureAddress(baseAddress, \"EdpGetContextForWindow\", 0);\n                EdpFreeContext_I = PhGetDllBaseProcedureAddress(baseAddress, \"EdpFreeContext\", 0);\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!(EdpGetContextForWindow_I && EdpFreeContext_I))\n        return E_FAIL;\n\n    status = EdpGetContextForWindow_I(\n        WindowHandle,\n        &context\n        );\n\n    if (SUCCEEDED(status))\n    {\n        *State = context->contextStates;\n        EdpFreeContext_I(context);\n    }\n\n    return status;\n}\n\nHRESULT PhAppResolverGetEdpContextForProcess(\n    _In_ HANDLE ProcessId,\n    _Out_ EDP_CONTEXT_STATES* State\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    HRESULT status;\n    PEDP_CONTEXT context;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion >= WINDOWS_10)\n        {\n            PVOID baseAddress;\n\n            if (baseAddress = PhLoadLibrary(L\"edputil.dll\"))\n            {\n                EdpGetContextForProcess_I = PhGetDllBaseProcedureAddress(baseAddress, \"EdpGetContextForProcess\", 0);\n                EdpFreeContext_I = PhGetDllBaseProcedureAddress(baseAddress, \"EdpFreeContext\", 0);\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!(EdpGetContextForWindow_I && EdpFreeContext_I))\n        return E_FAIL;\n\n    status = EdpGetContextForProcess_I(\n        HandleToUlong(ProcessId),\n        &context\n        );\n\n    if (SUCCEEDED(status))\n    {\n        *State = context->contextStates;\n        EdpFreeContext_I(context);\n    }\n\n    return status;\n}\n\n// Note: IStartMenuAppItems_EnumItems doesn't return immersive items on Win11 (dmex)\n//VOID PhEnumerateStartMenuAppUserModelIds(VOID)\n//{\n//    PVOID startMenuInterface;\n//    IEnumObjects* startMenuEnumObjects;\n//    ULONG count = 0;\n//\n//    if (!(startMenuInterface = PhpQueryStartMenuCacheInterface()))\n//        return;\n//\n//    if (WindowsVersion < WINDOWS_8)\n//    {\n//        IStartMenuAppItems_EnumItems(\n//            (IStartMenuAppItems61*)startMenuInterface,\n//            SMAIF_DEFAULT,\n//            &IID_IEnumObjects,\n//            &startMenuEnumObjects\n//            );\n//    }\n//    else\n//    {\n//        IStartMenuAppItems_EnumItems(\n//            (IStartMenuAppItems62*)startMenuInterface,\n//            SMAIF_DEFAULT,\n//            &IID_IEnumObjects,\n//            &startMenuEnumObjects\n//            );\n//    }\n//\n//    while (TRUE)\n//    {\n//        IPropertyStore* propStoreInterface[10];\n//\n//        if (IEnumObjects_Next(startMenuEnumObjects, 10, &IID_IPropertyStore, propStoreInterface, &count) != S_OK)\n//            break;\n//        if (count == 0)\n//            break;\n//\n//        for (ULONG i = 0; i < count; i++)\n//        {\n//            PROPVARIANT propValue;\n//\n//            if (SUCCEEDED(IPropertyStore_GetValue(propStoreInterface[i], &PKEY_AppUserModel_ID, &propValue)))\n//            {\n//                PropVariantClear(&propValue);\n//            }\n//\n//            IPropertyStore_Release(propStoreInterface[i]);\n//        }\n//    }\n//\n//    IStartMenuAppItems_Release(startMenuEnumObjects);\n//}\n\nDEFINE_GUID(FOLDERID_AppsFolder, 0x1e87508d, 0x89c2, 0x42f0, 0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58);\nDEFINE_GUID(BHID_EnumItems, 0x94f60519, 0x2850, 0x4924, 0xaa, 0x5a, 0xd1, 0x5e, 0x84, 0x86, 0x80, 0x39);\nDEFINE_GUID(BHID_PropertyStore, 0x0384e1a4, 0x1523, 0x439c, 0xa4, 0xc8, 0xab, 0x91, 0x10, 0x52, 0xf5, 0x86);\n\nstatic BOOLEAN PhParseStartMenuAppShellItem(\n    _In_ IShellItem2* ShellItem,\n    _In_ PPH_LIST List\n    )\n{\n    PROPVARIANT packageHostEnvironment;\n    PWSTR packageAppUserModelID = NULL;\n    PWSTR packageInstallPath = NULL;\n    PWSTR packageFullName = NULL;\n    PWSTR packageSmallLogoPath = NULL;\n    PWSTR packageLongDisplayName = NULL;\n\n    PropVariantInit(&packageHostEnvironment);\n\n    if (HR_FAILED(IShellItem2_GetProperty(ShellItem, &PKEY_AppUserModel_HostEnvironment, &packageHostEnvironment)))\n        return FALSE;\n    if (packageHostEnvironment.vt != VT_UI4 && packageHostEnvironment.ulVal)\n        return FALSE;\n\n    IShellItem2_GetString(ShellItem, &PKEY_AppUserModel_ID, &packageAppUserModelID);\n    IShellItem2_GetString(ShellItem, &PKEY_AppUserModel_PackageInstallPath, &packageInstallPath);\n    IShellItem2_GetString(ShellItem, &PKEY_AppUserModel_PackageFullName, &packageFullName);\n    IShellItem2_GetString(ShellItem, &PKEY_Tile_SmallLogoPath, &packageSmallLogoPath);\n    IShellItem2_GetString(ShellItem, &PKEY_Tile_LongDisplayName, &packageLongDisplayName);\n\n    if (packageAppUserModelID &&\n        packageInstallPath &&\n        packageFullName &&\n        packageSmallLogoPath &&\n        packageLongDisplayName)\n    {\n        PPH_APPUSERMODELID_ENUM_ENTRY entry;\n        PWSTR imagePath = NULL;\n\n        entry = PhAllocateZero(sizeof(PH_APPUSERMODELID_ENUM_ENTRY));\n        entry->AppUserModelId = PhCreateString(packageAppUserModelID);\n        entry->PackageDisplayName = PhCreateString(packageLongDisplayName);\n        entry->PackageInstallPath = PhCreateString(packageInstallPath);\n        entry->PackageFullName = PhCreateString(packageFullName);\n\n        if (HR_SUCCESS(PhAppResolverGetPackageResourceFilePath(packageFullName, packageSmallLogoPath, &imagePath)))\n        {\n            entry->SmallLogoPath = PhCreateString(imagePath);\n            CoTaskMemFree(imagePath);\n        }\n\n        PhAddItemList(List, entry);\n\n        return TRUE;\n    }\n\n    if (packageAppUserModelID)\n        CoTaskMemFree(packageAppUserModelID);\n    if (packageInstallPath)\n        CoTaskMemFree(packageInstallPath);\n    if (packageFullName)\n        CoTaskMemFree(packageFullName);\n    if (packageSmallLogoPath)\n        CoTaskMemFree(packageSmallLogoPath);\n    if (packageLongDisplayName)\n        CoTaskMemFree(packageLongDisplayName);\n    return FALSE;\n}\n\nPPH_LIST PhEnumApplicationUserModelIds(\n    VOID\n    )\n{\n    HRESULT status;\n    PPH_LIST list = NULL;\n    IShellItem2* shellKnownFolderItem = NULL;\n    IEnumShellItems* shellEnumFolderItem = NULL;\n\n    status = PhShellGetKnownFolderItem(\n        &FOLDERID_AppsFolder,\n        KF_FLAG_DONT_VERIFY,\n        NULL,\n        &IID_IShellItem2,\n        &shellKnownFolderItem\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = IShellItem2_BindToHandler(\n        shellKnownFolderItem,\n        NULL,\n        &BHID_EnumItems,\n        &IID_IEnumShellItems,\n        &shellEnumFolderItem\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    list = PhCreateList(10);\n\n    while (TRUE)\n    {\n        ULONG count = 0;\n        IShellItem* itemlist[10];\n\n        if (HR_FAILED(IEnumShellItems_Next(shellEnumFolderItem, 10, itemlist, &count)))\n            break;\n        if (count == 0)\n            break;\n\n        for (ULONG i = 0; i < count; i++)\n        {\n            IShellItem2* item;\n\n            if (HR_SUCCESS(IShellItem_QueryInterface(itemlist[i], &IID_IShellItem2, &item)))\n            {\n                PhParseStartMenuAppShellItem(item, list);\n\n                IShellItem2_Release(item);\n            }\n\n            IShellItem_Release(itemlist[i]);\n        }\n    }\n\nCleanupExit:\n    if (shellEnumFolderItem)\n    {\n        IEnumShellItems_Release(shellEnumFolderItem);\n    }\n    if (shellKnownFolderItem)\n    {\n        IShellItem2_Release(shellKnownFolderItem);\n    }\n\n    return list;\n}\n\nHRESULT PhAppResolverGetPackageResourceFilePath(\n    _In_ PCWSTR PackageFullName,\n    _In_ PCWSTR Key,\n    _Out_ PWSTR* FilePath\n    )\n{\n    HRESULT status;\n    IMrtResourceManager* resourceManager = NULL;\n    IResourceMap* resourceMap = NULL;\n\n    status = PhGetClassObject(\n        L\"mrmcorer.dll\",\n        &CLSID_MrtResourceManager_I,\n        &IID_IMrtResourceManager_I,\n        &resourceManager\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = IMrtResourceManager_InitializeForPackage(resourceManager, PackageFullName);\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = IMrtResourceManager_GetMainResourceMap(resourceManager, &IID_IResourceMap_I, &resourceMap);\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    status = IResourceMap_GetFilePath(resourceMap, Key, FilePath);\n\nCleanupExit:\n    if (resourceMap)\n        IResourceMap_Release(resourceMap);\n    if (resourceManager)\n        IMrtResourceManager_Release(resourceManager);\n\n    return status;\n}\n\nHRESULT PhAppResolverGetPackageStartMenuPropertyStore(\n    _In_ HANDLE ProcessId,\n    _Out_ IPropertyStore** PropertyStore\n    )\n{\n    HRESULT status;\n    PVOID startMenuInterface;\n    PPH_STRING applicationUserModelId;\n\n    if (!(startMenuInterface = PhpQueryStartMenuCacheInterface()))\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    status = PhAppResolverGetAppIdForProcess(ProcessId, &applicationUserModelId);\n\n    if (FAILED(status))\n        return status;\n\n    if (WindowsVersion < WINDOWS_8)\n    {\n        status = IStartMenuAppItems_GetItem(\n            (IStartMenuAppItems*)startMenuInterface,\n            SMAIF_DEFAULT,\n            PhGetString(applicationUserModelId),\n            &IID_IPropertyStore,\n            PropertyStore\n            );\n    }\n    else\n    {\n        status = IStartMenuAppItems2_GetItem(\n            (IStartMenuAppItems2*)startMenuInterface,\n            SMAIF_DEFAULT,\n            PhGetString(applicationUserModelId),\n            &IID_IPropertyStore,\n            PropertyStore\n            );\n        \n    }\n\n    PhDereferenceObject(applicationUserModelId);\n\n    return status;\n}\n\n_Success_(return)\nBOOLEAN PhAppResolverGetPackageIcon(\n    _In_ HANDLE ProcessId,\n    _In_ PPH_STRING PackageFullName,\n    _Out_opt_ HICON* IconLarge,\n    _Out_opt_ HICON* IconSmall,\n    _In_ LONG SystemDpi\n    )\n{\n    IPropertyStore* propertyStore = NULL;\n    PROPVARIANT propertyPathValue;\n    PROPVARIANT propertyColorValue;\n    PWSTR imagePath = NULL;\n    HICON iconLarge = NULL;\n    HICON iconSmall = NULL;\n\n    PropVariantInit(&propertyPathValue);\n    PropVariantInit(&propertyColorValue);\n\n    if (HR_FAILED(PhAppResolverGetPackageStartMenuPropertyStore(ProcessId, &propertyStore)))\n        goto CleanupExit;\n    if (HR_FAILED(IPropertyStore_GetValue(propertyStore, &PKEY_Tile_SmallLogoPath, &propertyPathValue)))\n        goto CleanupExit;\n    if (HR_FAILED(IPropertyStore_GetValue(propertyStore, &PKEY_Tile_Background, &propertyColorValue)))\n        goto CleanupExit;\n    if (HR_FAILED(PhAppResolverGetPackageResourceFilePath(PhGetString(PackageFullName), propertyPathValue.bstrVal, &imagePath)))\n        goto CleanupExit;\n\n    if (IconLarge)\n    {\n        HBITMAP bitmap;\n        LONG width;\n        LONG height;\n\n        width = PhGetSystemMetrics(SM_CXICON, SystemDpi);\n        height = PhGetSystemMetrics(SM_CYICON, SystemDpi);\n\n        if (bitmap = PhLoadImageFromFile(imagePath, width, height))\n        {\n            iconLarge = PhGdiplusConvertBitmapToIcon(bitmap, width, height, propertyColorValue.ulVal);\n            DeleteBitmap(bitmap);\n        }\n    }\n\n    if (IconSmall)\n    {\n        HBITMAP bitmap;\n        LONG width;\n        LONG height;\n\n        width = PhGetSystemMetrics(SM_CXSMICON, SystemDpi);\n        height = PhGetSystemMetrics(SM_CYSMICON, SystemDpi);\n\n        if (bitmap = PhLoadImageFromFile(imagePath, width, height))\n        {\n            iconSmall = PhGdiplusConvertBitmapToIcon(bitmap, width, height, propertyColorValue.ulVal);\n            DeleteBitmap(bitmap);\n        }\n    }\n\nCleanupExit:\n    if (imagePath)\n        CoTaskMemFree(imagePath);\n    if (propertyPathValue.bstrVal)\n        CoTaskMemFree(propertyPathValue.bstrVal);\n    if (propertyStore)\n        IPropertyStore_Release(propertyStore);\n\n    if (IconLarge && IconSmall)\n    {\n        if (iconLarge && iconSmall)\n        {\n            *IconLarge = iconLarge;\n            *IconSmall = iconSmall;\n            return TRUE;\n        }\n\n        if (iconLarge)\n            DestroyIcon(iconLarge);\n        if (iconSmall)\n            DestroyIcon(iconSmall);\n\n        return FALSE;\n    }\n\n    if (IconLarge && iconLarge)\n    {\n        *IconLarge = iconLarge;\n        return TRUE;\n    }\n\n    if (IconSmall && iconSmall)\n    {\n        *IconSmall = iconSmall;\n        return TRUE;\n    }\n\n    if (iconLarge)\n        DestroyIcon(iconLarge);\n    if (iconSmall)\n        DestroyIcon(iconSmall);\n\n    return FALSE;\n}\n\n// rev from Invoke-CommandInDesktopPackage (dmex)\n/**\n * Creates a new process in the context of the supplied PackageFamilyName and AppId.\n * \n * \\li \\c The created process will have the identity of the provided AppId and will have access to its virtualized file system and registry (if any).\n * \\li \\c The new process will have a token that's similar to, but not identical to, a real AppId process.\n * \\li \\c The primary use-case of this command is to invoke debugging or troubleshooting tools in the context of the packaged app to access its virtualized resources.\n * \\li \\c For example, you can run the Registry Editor to see virtualized registry keys, or Notepad to read virtualized files.\n * \\li \\c See the important note that follows on using tools such as the Registry Editor that require elevation.\n * \\li \\c No guarantees are made about the behavior of the created process, other than it having the package identity and access to the package's virtualized resources.\n * \\li \\c In particular, the new process will not be created in an AppContainer even if an AppId process would normally be created in an AppContainer.\n * \\li \\c Features such as Privacy Controls or other App Settings may or may not apply to the new process.\n * \\li \\c You shouldn't rely on any specific side-effects of using this command, as they're undefined and subject to change.\n\n * \\param ApplicationUserModelId The Application ID from the target package's manifest.\n * \\param Executable An executable to invoke.\n * \\param Arguments Optional arguments to be passed to the new process.\n * \\param Directory Optional \n * \\param PreventBreakaway Causes all child processes of the invoked process to also be created in the context of the AppId. By default, child processes are created without any context. This switch is useful for running cmd.exe so that you can launch multiple other tools in the package context.\n * \\param ParentProcessId A process to use instead of the calling process as the parent for the process being created.\n * \\param ProcessHandle A handle to a process.\n * \\return Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/powershell/module/appx/invoke-commandindesktoppackage\n */\nHRESULT PhCreateProcessDesktopPackage(\n    _In_ PCWSTR ApplicationUserModelId,\n    _In_ PCWSTR Executable,\n    _In_ PCWSTR Arguments,\n    _In_opt_ PCWSTR Directory,\n    _In_ BOOLEAN PreventBreakaway,\n    _In_opt_ HANDLE ParentProcessId,\n    _Out_opt_ PHANDLE ProcessHandle\n    )\n{\n    HRESULT status;\n    IDesktopAppXActivator* desktopAppXActivator;\n\n    if (WindowsVersion < WINDOWS_11)\n    {\n        status = PhGetClassObject(\n            L\"twinui.dll\",\n            &CLSID_IDesktopAppXActivator_I,\n            &IID_IDesktopAppXActivator1_I,\n            &desktopAppXActivator\n            );\n    }\n    else\n    {\n        status = PhGetClassObject(\n            L\"twinui.appcore.dll\",\n            &CLSID_IDesktopAppXActivator_I,\n            &IID_IDesktopAppXActivator2_I,\n            &desktopAppXActivator\n            );\n    }\n\n    if (SUCCEEDED(status))\n    {\n        ULONG options = DAXAO_CHECK_FOR_APPINSTALLER_UPDATES | DAXAO_CENTENNIAL_PROCESS;\n        SetFlag(options, PreventBreakaway ? DAXAO_NONPACKAGED_EXE_PROCESS_TREE : DAXAO_NONPACKAGED_EXE);\n\n        status = IDesktopAppXActivator_ActivateWithOptionsArgsWorkingDirectoryShowWindow(\n            desktopAppXActivator,\n            ApplicationUserModelId,\n            Executable,\n            Arguments,\n            options,\n            HandleToUlong(ParentProcessId),\n            NULL,\n            Directory,\n            SW_SHOW,\n            ProcessHandle\n            );\n\n        if (HR_FAILED(status))\n        {\n            status = IDesktopAppXActivator_ActivateWithOptions(\n                desktopAppXActivator,\n                ApplicationUserModelId,\n                Executable,\n                Arguments,\n                options,\n                HandleToUlong(ParentProcessId),\n                ProcessHandle\n                );\n        }\n\n        IDesktopAppXActivator_Release(desktopAppXActivator);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/appruntime.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2023\n *\n */\n\n#include <ph.h>\n#include <mapldr.h>\n#include <appresolver.h>\n\n#if defined(PH_NATIVE_WINDOWS_RUNTIME_STRING)\n#pragma comment(lib, \"runtimeobject.lib\")\n#include <roapi.h>\n#include <winstring.h>\n#endif\n\n#ifdef __hstring_h__\nstatic_assert(sizeof(HSTRING_REFERENCE) == sizeof(HSTRING_HEADER), \"HSTRING_REFERENCE must equal WSTRING_HEADER\");\n#else\nstatic_assert(sizeof(HSTRING_REFERENCE) == sizeof(WSTRING_HEADER), \"HSTRING_REFERENCE must equal WSTRING_HEADER\");\n#endif\n\n/**\n * Creates a string from a Windows Runtime string.\n *\n * \\param String The Windows Runtime string.\n *\n * \\return A pointer to the created string.\n */\nPPH_STRING PhCreateStringFromWindowsRuntimeString(\n    _In_ HSTRING String\n    )\n{\n#if defined(PH_NATIVE_WINDOWS_RUNTIME_STRING)\n    UINT32 stringLength;\n    PCWSTR string;\n\n    if (string = PhGetWindowsRuntimeStringBuffer(String, &stringLength))\n    {\n        if (stringLength >= sizeof(UNICODE_NULL))\n        {\n            return PhCreateStringEx(string, stringLength * sizeof(WCHAR));\n        }\n    }\n#else\n    HSTRING_INSTANCE* string = (HSTRING_INSTANCE*)String;\n\n    if (string && string->Length >= sizeof(UNICODE_NULL))\n    {\n        return PhCreateStringEx(string->Buffer, string->Length * sizeof(WCHAR));\n    }\n#endif\n\n    return PhReferenceEmptyString();\n}\n\n// rev from WindowsCreateStringReference (dmex)\n/**\n * \\brief Creates a new string reference based on the specified string.\n *\n * \\param SourceString A null-terminated string to use as the source for the new string.\n * \\param String A pointer to the newly created string.\n *\n * \\return Successful or errant status.\n */\nHRESULT PhCreateWindowsRuntimeStringReference(\n    _In_ PCWSTR SourceString,\n    _Out_ PVOID String\n    )\n{\n#if defined(PH_NATIVE_WINDOWS_RUNTIME_STRING)\n    HSTRING stringHandle;\n\n    return WindowsCreateStringReference(\n        SourceString,\n        (UINT32)PhCountStringZ(SourceString),\n        String,\n        &stringHandle\n        );\n#else\n    HSTRING_REFERENCE* string = (HSTRING_REFERENCE*)String;\n\n    string->Flags = HSTRING_REFERENCE_FLAG;\n    string->Length = (UINT32)PhCountStringZ(SourceString);\n    string->Buffer = SourceString;\n\n    return S_OK;\n#endif\n}\n\n// rev from WindowsCreateStringReference (dmex)\n/**\n * \\brief Creates a new string reference based on the specified string.\n *\n * \\param SourceString A null-terminated string to use as the source for the new string.\n * \\param Length The count of characters for the string.\n * \\param String A pointer to the newly created string.\n *\n * \\return Successful or errant status.\n */\nHRESULT PhCreateWindowsRuntimeStringReferenceEx(\n    _In_ PCWSTR SourceString,\n    _In_ UINT32 Length,\n    _Out_ PVOID String\n    )\n{\n#if defined(PH_NATIVE_WINDOWS_RUNTIME_STRING)\n    HSTRING stringHandle;\n\n    return WindowsCreateStringReference(\n        SourceString,\n        (UINT32)PhCountStringZ(SourceString),\n        String,\n        &stringHandle\n        );\n#else\n    HSTRING_REFERENCE* string = (HSTRING_REFERENCE*)String;\n\n    string->Flags = HSTRING_REFERENCE_FLAG;\n    string->Length = Length;\n    string->Buffer = SourceString;\n\n    return S_OK;\n#endif\n}\n\n// rev from WindowsCreateString (dmex)\n/**\n * \\brief Creates a new string based on the specified string.\n *\n * \\param SourceString A null-terminated string to use as the source for the new string.\n * \\param String A pointer to the newly created string.\n *\n * \\return Successful or errant status.\n */\nHRESULT PhCreateWindowsRuntimeString(\n    _In_ PCWSTR SourceString,\n    _Out_ HSTRING* String\n    )\n{\n#if defined(PH_NATIVE_WINDOWS_RUNTIME_STRING)\n    return WindowsCreateString(\n        SourceString,\n        (UINT32)PhCountStringZ(SourceString),\n        String\n        );\n#else\n    SIZE_T stringLength;\n    SIZE_T bufferLength;\n    HSTRING_INSTANCE* string;\n\n    stringLength = PhCountStringZ(SourceString) * sizeof(WCHAR);\n    bufferLength = sizeof(HSTRING_INSTANCE) + stringLength + sizeof(UNICODE_NULL);\n\n    if (bufferLength > UINT_MAX)\n        return MEM_E_INVALID_SIZE;\n\n    string = RtlAllocateHeap(RtlProcessHeap(), 0, bufferLength);\n\n    if (!string)\n        return E_OUTOFMEMORY;\n\n    assert(!(stringLength & 1));\n\n    string->Flags = 0;\n    string->ReferenceCount = 1;\n    string->Buffer = string->Data;\n    string->Length = (UINT32)stringLength / sizeof(WCHAR);\n    memcpy(string->Data, SourceString, stringLength);\n    string->Data[string->Length] = UNICODE_NULL;\n\n    *String = (HSTRING)string;\n    return S_OK;\n#endif\n}\n\n// rev from WindowsDeleteString (dmex)\n/**\n * \\brief Decrements the reference count of a string.\n *\n * \\param String The string to be deleted.\n */\nVOID PhDeleteWindowsRuntimeString(\n    _In_opt_ HSTRING String\n    )\n{\n#if defined(PH_NATIVE_WINDOWS_RUNTIME_STRING)\n    WindowsDeleteString(String);\n#else\n    HSTRING_INSTANCE* string = (HSTRING_INSTANCE*)String;\n    LONG newRefCount;\n\n    if (!string || BooleanFlagOn(string->Flags, HSTRING_REFERENCE_FLAG))\n        return;\n\n    newRefCount = InterlockedDecrement(&string->ReferenceCount);\n    ASSUME_ASSERT(newRefCount >= 0);\n\n    if (newRefCount == 0)\n    {\n        RtlFreeHeap(RtlProcessHeap(), 0, string);\n    }\n#endif\n}\n\n// rev from WindowsGetStringLen (dmex)\n/**\n * \\brief Gets the length, in Unicode characters, of the specified string.\n *\n * \\param String The string to be counted.\n *\n * \\return Successful or errant status.\n */\nULONG PhGetWindowsRuntimeStringLength(\n    _In_opt_ HSTRING String\n    )\n{\n#if defined(PH_NATIVE_WINDOWS_RUNTIME_STRING)\n    return WindowsGetStringLen(String);\n#else\n    HSTRING_INSTANCE* string = (HSTRING_INSTANCE*)String;\n\n    if (string)\n    {\n        return string->Length;\n    }\n\n    return 0;\n#endif\n}\n\n// rev from WindowsGetStringRawBuffer (dmex)\n/**\n * \\brief Retrieves the backing buffer for the specified string.\n *\n * \\param String An optional string for which the backing buffer is to be retrieved. Can be NULL.\n * \\param Length The number of Unicode characters in the backing buffer for String (including embedded null characters, but excluding the terminating null).\n *\n * \\return A pointer to the buffer that provides the backing store for string, or the empty string if string is NULL or the empty string.\n */\nPCWSTR PhGetWindowsRuntimeStringBuffer(\n    _In_opt_ HSTRING String,\n    _Out_opt_ PULONG Length\n    )\n{\n#if defined(PH_NATIVE_WINDOWS_RUNTIME_STRING)\n    return WindowsGetStringRawBuffer(String, Length);\n#else\n    HSTRING_INSTANCE* string = (HSTRING_INSTANCE*)String;\n\n    if (string)\n    {\n        if (Length)\n            *Length = string->Length;\n\n        return string->Buffer;\n    }\n    else\n    {\n        if (Length)\n            *Length = 0;\n\n        return L\"\";\n    }\n#endif\n}\n\n#pragma region Cryptographic Buffer\n\n#include <windows.security.cryptography.h>\n\n// 320b7e22-3cb0-4cdf-8663-1d28910065eb\nDEFINE_GUID(IID_ICryptographicBufferStatics, 0x320b7e22, 0x3cb0, 0x4cdf, 0x86, 0x63, 0x1d, 0x28, 0x91, 0x00, 0x65, 0xeb);\n\nPPH_STRING PhCryptographicBufferToHexString(\n    _In_ __x_ABI_CWindows_CStorage_CStreams_CIBuffer* Buffer\n    )\n{\n    PPH_STRING string = NULL;\n    __x_ABI_CWindows_CSecurity_CCryptography_CICryptographicBufferStatics* cryptographicBufferStatics;\n    HSTRING cryptographicBufferHandle;\n\n    if (SUCCEEDED(PhGetActivationFactory(\n        L\"CryptoWinRT.dll\",\n        RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer,\n        &IID_ICryptographicBufferStatics,\n        &cryptographicBufferStatics\n        )))\n    {\n        if (SUCCEEDED(__x_ABI_CWindows_CSecurity_CCryptography_CICryptographicBufferStatics_EncodeToHexString(\n            cryptographicBufferStatics,\n            Buffer,\n            &cryptographicBufferHandle\n            )))\n        {\n            string = PhCreateStringFromWindowsRuntimeString(cryptographicBufferHandle);\n            PhDeleteWindowsRuntimeString(cryptographicBufferHandle);\n        }\n\n        __x_ABI_CWindows_CSecurity_CCryptography_CICryptographicBufferStatics_Release(cryptographicBufferStatics);\n    }\n\n    return string;\n}\n\n#pragma endregion\n\n#pragma region Data Reader\n\n// 11fcbfc8-f93a-471b-b121-f379e349313c\nDEFINE_GUID(IID_IDataReaderStatics, 0x11fcbfc8, 0xf93a, 0x471b, 0xb1, 0x21, 0xf3, 0x79, 0xe3, 0x49, 0x31, 0x3c);\n\nPPH_STRING PhDataReaderBufferToHexString(\n    _In_ __x_ABI_CWindows_CStorage_CStreams_CIBuffer* Buffer\n    )\n{\n    PPH_STRING string = NULL;\n    __x_ABI_CWindows_CStorage_CStreams_CIDataReaderStatics* dataReaderStatics;\n    __x_ABI_CWindows_CStorage_CStreams_CIDataReader* dataReader;\n    ULONG dataBufferLength = 0;\n    UCHAR dataBuffer[128] = { 0 };\n\n    if (SUCCEEDED(__x_ABI_CWindows_CStorage_CStreams_CIBuffer_get_Length(Buffer, &dataBufferLength)) && dataBufferLength < sizeof(dataBuffer))\n    {\n        if (SUCCEEDED(PhGetActivationFactory(\n            L\"WinTypes.dll\",\n            RuntimeClass_Windows_Storage_Streams_DataReader,\n            &IID_IDataReaderStatics,\n            &dataReaderStatics\n            )))\n        {\n            if (SUCCEEDED(__x_ABI_CWindows_CStorage_CStreams_CIDataReaderStatics_FromBuffer(dataReaderStatics, Buffer, &dataReader)))\n            {\n                if (SUCCEEDED(__x_ABI_CWindows_CStorage_CStreams_CIDataReader_ReadBytes(dataReader, dataBufferLength, dataBuffer)))\n                {\n                    string = PhBufferToHexString(dataBuffer, dataBufferLength);\n                }\n\n                __x_ABI_CWindows_CStorage_CStreams_CIDataReader_Release(dataReader);\n            }\n\n            __x_ABI_CWindows_CStorage_CStreams_CIDataReaderStatics_Release(dataReaderStatics);\n        }\n    }\n\n    return string;\n}\n\n#pragma endregion\n\n#pragma region System Identification\n\n#include <windows.system.profile.h>\n\n// 5581f42a-d3df-4d93-a37d-c41a616c6d01\nDEFINE_GUID(IID_ISystemIdentificationStatics, 0x5581f42a, 0xd3df, 0x4d93, 0xa3, 0x7d, 0xc4, 0x1a, 0x61, 0x6c, 0x6d, 0x01);\n\nPPH_STRING PhSystemIdentificationToString(\n    _In_ __x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationInfo* IdentificationInfo\n    )\n{\n    __x_ABI_CWindows_CSystem_CProfile_CSystemIdentificationSource source;\n    __x_ABI_CWindows_CStorage_CStreams_CIBuffer* buffer;\n    PPH_STRING identifier = NULL;\n    PCWSTR string = L\"Unknown\";\n\n    if (SUCCEEDED(__x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationInfo_get_Id(IdentificationInfo, &buffer)))\n    {\n        identifier = PhCryptographicBufferToHexString(buffer);\n\n        if (PhIsNullOrEmptyString(identifier))\n        {\n            identifier = PhDataReaderBufferToHexString(buffer);\n        }\n\n        __x_ABI_CWindows_CStorage_CStreams_CIBuffer_Release(buffer);\n    }\n\n    if (SUCCEEDED(__x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationInfo_get_Source(IdentificationInfo, &source)))\n    {\n        switch (source)\n        {\n        case SystemIdentificationSource_Tpm:\n            string = L\"TPM\";\n            break;\n        case SystemIdentificationSource_Uefi:\n            string = L\"UEFI\";\n            break;\n        case SystemIdentificationSource_Registry:\n            string = L\"Registry\";\n            break;\n        }\n    }\n\n    PhMoveReference(&identifier, PhFormatString(\n        L\"%s (%s)\",\n        PhGetStringOrDefault(identifier, L\"Unknown\"),\n        string\n        ));\n\n    return identifier;\n}\n\ntypedef struct _PH_APPHWID_QUERY_CONTEXT\n{\n    HANDLE ProcessId;\n    HANDLE ThreadId;\n    HANDLE ProcessHandle;\n    HANDLE ThreadHandle;\n} PH_APPHWID_QUERY_CONTEXT, *PPH_APPHWID_QUERY_CONTEXT;\n\nstatic PVOID PhDetoursPackageSystemIdentificationContext(\n    _In_opt_ PPH_APPHWID_QUERY_CONTEXT Buffer,\n    _In_ BOOLEAN Initialize\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static ULONG index = TLS_OUT_OF_INDEXES;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        index = PhTlsAlloc();\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (index != TLS_OUT_OF_INDEXES)\n    {\n        if (Initialize)\n        {\n            if (NT_SUCCESS(PhTlsSetValue(index, Buffer)))\n                return Buffer;\n        }\n        else\n        {\n            return PhTlsGetValue(index);\n        }\n    }\n\n    return NULL;\n}\n\nstatic HANDLE WINAPI PhDetoursPackageSystemIdentificationCurrentProcess(\n    VOID\n    )\n{\n    PPH_APPHWID_QUERY_CONTEXT context = PhDetoursPackageSystemIdentificationContext(NULL, FALSE);\n\n    if (context)\n        return context->ProcessHandle;\n    else\n        return NtCurrentProcess();\n}\n\nstatic HANDLE WINAPI PhDetoursPackageSystemIdentificationCurrentThread(\n    VOID\n    )\n{\n    PPH_APPHWID_QUERY_CONTEXT context = PhDetoursPackageSystemIdentificationContext(NULL, FALSE);\n\n    if (context)\n        return context->ThreadHandle;\n    else\n        return NtCurrentThread();\n}\n\nstatic ULONG WINAPI PhDetoursPackageSystemIdentificationCurrentProcessId(\n    VOID\n    )\n{\n    PPH_APPHWID_QUERY_CONTEXT context = PhDetoursPackageSystemIdentificationContext(NULL, FALSE);\n\n    if (context)\n        return HandleToUlong(context->ProcessId);\n    else\n        return HandleToUlong(NtCurrentProcessId());\n}\n\nstatic ULONG WINAPI PhDetoursPackageSystemIdentificationCurrentThreadId(\n    VOID\n    )\n{\n    PPH_APPHWID_QUERY_CONTEXT context = PhDetoursPackageSystemIdentificationContext(NULL, FALSE);\n\n    if (context)\n        return HandleToUlong(context->ThreadId);\n    else\n        return HandleToUlong(NtCurrentThreadId());\n}\n\nstatic BOOL WINAPI PhDetoursPackageSystemIdentificationCloseHandle(\n    _In_ _Post_ptr_invalid_ HANDLE hObject\n    )\n{\n    return TRUE;\n}\n\nstatic HRESULT PhDetoursPackageSystemIdentificationInitialize(\n    _In_ PVOID Address,\n    _In_ PPH_APPHWID_QUERY_CONTEXT Context\n    )\n{\n    PVOID baseAddress = PhGetLoaderEntryAddressDllBase(Address);\n\n    if (!baseAddress)\n        return E_FAIL;\n\n    if (!NT_SUCCESS(PhLoaderEntryDetourImportProcedure(\n        baseAddress,\n        \"api-ms-win-core-processthreads-l1-1-0.dll\",\n        \"GetCurrentProcess\",\n        PhDetoursPackageSystemIdentificationCurrentProcess,\n        NULL\n        )))\n    {\n        return E_FAIL;\n    }\n\n    if (!NT_SUCCESS(PhLoaderEntryDetourImportProcedure(\n        baseAddress,\n        \"api-ms-win-core-processthreads-l1-1-0.dll\",\n        \"GetCurrentProcessId\",\n        PhDetoursPackageSystemIdentificationCurrentProcessId,\n        NULL\n        )))\n    {\n        return E_FAIL;\n    }\n\n    if (!NT_SUCCESS(PhLoaderEntryDetourImportProcedure(\n        baseAddress,\n        \"api-ms-win-core-processthreads-l1-1-0.dll\",\n        \"GetCurrentThread\",\n        PhDetoursPackageSystemIdentificationCurrentThread,\n        NULL\n        )))\n    {\n        return E_FAIL;\n    }\n\n    if (!NT_SUCCESS(PhLoaderEntryDetourImportProcedure(\n        baseAddress,\n        \"api-ms-win-core-processthreads-l1-1-0.dll\",\n        \"GetCurrentThreadId\",\n        PhDetoursPackageSystemIdentificationCurrentThreadId,\n        NULL\n        )))\n    {\n        return E_FAIL;\n    }\n\n    if (!NT_SUCCESS(PhLoaderEntryDetourImportProcedure(\n        baseAddress,\n        \"api-ms-win-core-handle-l1-1-0.dll\",\n        \"CloseHandle\",\n        PhDetoursPackageSystemIdentificationCloseHandle,\n        NULL\n        )))\n    {\n        return E_FAIL;\n    }\n\n    if (!PhDetoursPackageSystemIdentificationContext(Context, TRUE))\n    {\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\nstatic HRESULT PhDetoursPackageSystemIdentificationDelete(\n    VOID\n    )\n{\n    if (!PhDetoursPackageSystemIdentificationContext(NULL, TRUE))\n    {\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\nstatic HRESULT PhQueryProcessSystemIdentification(\n    _In_ PPH_APPHWID_QUERY_CONTEXT Context,\n    _Out_ PPH_STRING* SystemIdForPublisher,\n    _Out_ PPH_STRING* SystemIdForUser\n    )\n{\n    HRESULT status;\n    __x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationStatics* systemIdStatics = NULL;\n    __x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationInfo* systemIdPublisher;\n    __x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationInfo* systemIdUser;\n    BOOLEAN revertImpersonationToken = FALSE;\n    HANDLE tokenHandle = NULL;\n    HRESULT systemIdForUserStatus = E_FAIL;\n    HRESULT systemIdPublisherStatus = E_FAIL;\n    PPH_STRING systemIdForPublisherString = NULL;\n    PPH_STRING systemIdForUserString = NULL;\n\n    status = PhGetActivationFactory(\n        L\"Windows.System.Profile.SystemId.dll\",\n        RuntimeClass_Windows_System_Profile_SystemIdentification,\n        &IID_ISystemIdentificationStatics,\n        &systemIdStatics\n        );\n\n    if (FAILED(status))\n        return status;\n\n    if (NT_SUCCESS(PhOpenProcessToken(\n        Context->ProcessHandle,\n        TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,\n        &tokenHandle\n        )))\n    {\n        revertImpersonationToken = NT_SUCCESS(PhImpersonateToken(NtCurrentThread(), tokenHandle));\n    }\n\n    // We've impersonated the package but the SystemIdentification class\n    // gets confused and the package manager queries the impersonated token\n    // and the WinRT class queries our token... Redirect the handle imports\n    // so we can query the correct token. If we can't then unfortunately\n    // developers can't verify their SystemID support returns correct values\n    // or verify their capabilities/sandboxing/token permissions are setup correctly (dmex)\n\n    status = PhDetoursPackageSystemIdentificationInitialize(\n        systemIdStatics->lpVtbl,\n        Context\n        );\n\n    if (FAILED(status))\n        goto CleanupExit;\n\n    if ((systemIdPublisherStatus = __x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationStatics_GetSystemIdForPublisher(\n        systemIdStatics,\n        &systemIdPublisher\n        )) == S_OK)\n    {\n        systemIdForPublisherString = PhSystemIdentificationToString(systemIdPublisher);\n        __x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationInfo_Release(systemIdPublisher);\n    }\n\n    if ((systemIdForUserStatus = __x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationStatics_GetSystemIdForUser(\n        systemIdStatics,\n        NULL,\n        &systemIdUser\n        )) == S_OK)\n    {\n        systemIdForUserString = PhSystemIdentificationToString(systemIdUser);\n        __x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationInfo_Release(systemIdUser);\n    }\n\nCleanupExit:\n    if (systemIdStatics)\n    {\n        __x_ABI_CWindows_CSystem_CProfile_CISystemIdentificationStatics_Release(systemIdStatics);\n        systemIdStatics = NULL;\n    }\n\n    if (tokenHandle)\n    {\n        if (revertImpersonationToken)\n            PhRevertImpersonationToken(NtCurrentThread());\n\n        NtClose(tokenHandle);\n        tokenHandle = NULL;\n    }\n\n    PhDetoursPackageSystemIdentificationDelete();\n\n    *SystemIdForPublisher = NULL;\n    *SystemIdForUser = NULL;\n\n    // Note: Load messages after reverting impersonation otherwise the kernel32.dll message table doesn't get mapped.\n    // Errors will be from the process token missing the \"userSystemId\" capability or limited process token privileges. (dmex)\n\n    if (HR_SUCCESS(systemIdPublisherStatus))\n    {\n        *SystemIdForPublisher = systemIdForPublisherString;\n    }\n    else\n    {\n        //if (HRESULT_FACILITY(systemIdPublisherStatus) == FACILITY_NT_BIT >> NT_FACILITY_SHIFT)\n        //{\n        //    ClearFlag(systemIdPublisherStatus, FACILITY_NT_BIT); // 0xD0000022 -> 0xC0000022\n        //}\n\n        if (HRESULT_NTSTATUS(systemIdForUserStatus))\n        {\n            *SystemIdForPublisher = PhGetStatusMessage(PhNtStatusFromHResult(systemIdPublisherStatus), 0);\n        }\n\n        if (PhIsNullOrEmptyString(*SystemIdForPublisher))\n        {\n            *SystemIdForPublisher = PhGetStatusMessage(0, HRESULT_CODE(systemIdPublisherStatus));\n        }\n    }\n\n    if (HR_SUCCESS(systemIdForUserStatus))\n    {\n        *SystemIdForUser = systemIdForUserString;\n    }\n    else\n    {\n        //if (HRESULT_FACILITY(systemIdForUserStatus) == FACILITY_NT_BIT >> NT_FACILITY_SHIFT)\n        //{\n        //    ClearFlag(systemIdForUserStatus, FACILITY_NT_BIT); // 0xD0000022 -> 0xC0000022\n        //}\n\n        if (HRESULT_NTSTATUS(systemIdForUserStatus))\n        {\n            *SystemIdForUser = PhGetStatusMessage(PhNtStatusFromHResult(systemIdForUserStatus), 0);\n        }\n\n        if (PhIsNullOrEmptyString(*SystemIdForUser))\n        {\n            *SystemIdForUser = PhGetStatusMessage(0, HRESULT_CODE(systemIdForUserStatus));\n        }\n    }\n\n    return status;\n}\n\n_Function_class_(PH_ENUM_NEXT_THREAD)\nstatic NTSTATUS NTAPI PhEnumNextThreadSystemIdentification(\n    _In_ HANDLE ThreadHandle,\n    _Inout_ HANDLE* Context\n    )\n{\n    *Context = ThreadHandle;\n    return STATUS_NO_MORE_ENTRIES;\n}\n\nHRESULT PhGetProcessSystemIdentification(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING* SystemIdForPublisher,\n    _Out_ PPH_STRING* SystemIdForUser\n    )\n{\n    HRESULT status;\n    HANDLE processHandle;\n    HANDLE threadHandle = NULL;\n    HANDLE threadId = NULL;\n    PVOID processes;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_LIMITED_INFORMATION,\n        ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        *SystemIdForPublisher = NULL;\n        *SystemIdForUser = NULL;\n\n        return HRESULT_FROM_NT(status);\n    }\n\n    status = PhEnumNextThread(\n        processHandle,\n        NULL,\n        THREAD_QUERY_LIMITED_INFORMATION,\n        PhEnumNextThreadSystemIdentification,\n        &threadHandle\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        if (NT_SUCCESS(PhEnumProcesses(&processes)))\n        {\n            PSYSTEM_PROCESS_INFORMATION process;\n\n            if (process = PhFindProcessInformation(processes, ProcessId))\n            {\n                for (ULONG i = 0; i < process->NumberOfThreads; i++)\n                {\n                    HANDLE tempThreadHandle;\n\n                    threadId = process->Threads[i].ClientId.UniqueThread;\n\n                    if (NT_SUCCESS(PhOpenThread(\n                        &tempThreadHandle,\n                        THREAD_QUERY_LIMITED_INFORMATION,\n                        threadId\n                        )))\n                    {\n                        threadHandle = tempThreadHandle;\n                        break;\n                    }\n                }\n            }\n\n            PhFree(processes);\n        }\n    }\n\n    if (!threadHandle)\n    {\n        status = HRESULT_FROM_NT(STATUS_UNSUCCESSFUL);\n        goto CleanupExit;\n    }\n\n    {\n        PH_APPHWID_QUERY_CONTEXT queryContext;\n\n        memset(&queryContext, 0, sizeof(PH_APPHWID_QUERY_CONTEXT));\n        queryContext.ProcessId = ProcessId;\n        queryContext.ProcessHandle = processHandle;\n        queryContext.ThreadId = threadId;\n        queryContext.ThreadHandle = threadHandle;\n\n        status = PhQueryProcessSystemIdentification(&queryContext, SystemIdForPublisher, SystemIdForUser);\n    }\n\nCleanupExit:\n    if (threadHandle)\n    {\n        NtClose(threadHandle);\n    }\n\n    if (processHandle)\n    {\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\n#pragma endregion\n\n#pragma region Display Information\n\n// BED112AE-ADC3-4DC9-AE65-851F4D7D4799\nDEFINE_GUID(IID_IDisplayInformation, 0xBED112AE, 0xADC3, 0x4DC9, 0xAE, 0x65, 0x85, 0x1F, 0x4D, 0x7D, 0x47, 0x99);\n// C6A02A6C-D452-44DC-BA07-96F3C6ADF9D1\nDEFINE_GUID(IID_IDisplayInformationStatics, 0xc6a02a6c, 0xd452, 0x44dc, 0xba, 0x07, 0x96, 0xf3, 0xc6, 0xad, 0xf9, 0xd1);\n// 6937ED8D-30EA-4DED-8271-4553FF02F68A\nDEFINE_GUID(IID_IDisplayPropertiesStatics, 0x6937ed8d, 0x30ea, 0x4ded, 0x82, 0x71, 0x45, 0x53, 0xff, 0x02, 0xf6, 0x8a);\n\nFLOAT PhGetDisplayLogicalDpi(\n    VOID\n    )\n{\n    FLOAT displayLogicalDpi = 0;\n    __x_ABI_CWindows_CGraphics_CDisplay_CIDisplayPropertiesStatics* displayProperties;\n    HRESULT status;\n\n    status = PhGetActivationFactory(\n        L\"Windows.Graphics.dll\",\n        RuntimeClass_Windows_Graphics_Display_DisplayProperties,\n        &IID_IDisplayPropertiesStatics,\n        &displayProperties\n        );\n\n    if (SUCCEEDED(status))\n    {\n        FLOAT value;\n\n        status = __x_ABI_CWindows_CGraphics_CDisplay_CIDisplayPropertiesStatics_get_LogicalDpi(displayProperties, &value);\n\n        if (SUCCEEDED(status))\n        {\n            displayLogicalDpi = value;\n        }\n    }\n\n    // Requires IWindowsXamlManagerStatics_InitializeForCurrentThread (dmex)\n    //\n    //__x_ABI_CWindows_CGraphics_CDisplay_CIDisplayInformationStatics* displayInformation;\n    //status = PhGetActivationFactory(\n    //    L\"Windows.Graphics.dll\",\n    //    RuntimeClass_Windows_Graphics_Display_DisplayInformation,\n    //    &IID_IDisplayInformationStatics,\n    //    &displayInformation\n    //    );\n    //\n    //if (SUCCEEDED(status))\n    //{\n    //    __x_ABI_CWindows_CGraphics_CDisplay_CIDisplayInformation* display_information;\n    //    __x_ABI_CWindows_CGraphics_CDisplay_CResolutionScale resolution_scale;\n    //\n    //    if (SUCCEEDED(__x_ABI_CWindows_CGraphics_CDisplay_CIDisplayInformationStatics_GetForCurrentView(displayInformation, &display_information)))\n    //    {\n    //        if (SUCCEEDED(__x_ABI_CWindows_CGraphics_CDisplay_CIDisplayInformation_get_ResolutionScale(display_information, &resolution_scale)))\n    //        {\n    //            float scale = (float)(resolution_scale / 100.0f);\n    //        }\n    //    }\n    //}\n\n    return displayLogicalDpi;\n}\n\n#pragma endregion\n\n#pragma region Package Manager\n\n#include <appmodel.h>\n#include <Windows.Management.Deployment.h>\n\n// 9a7d4b65-5e8f-4fc7-a2e5-7f6925cb8b53\nDEFINE_GUID(IID_IPackageManager, 0x9A7D4B65, 0x5E8F, 0x4FC7, 0xA2, 0xE5, 0x7F, 0x69, 0x25, 0xCB, 0x8B, 0x53);\n// a6612fb6-7688-4ace-95fb-359538e7aa01\nDEFINE_GUID(IID_IPackage2, 0xA6612FB6, 0x7688, 0x4ACE, 0x95, 0xFB, 0x35, 0x95, 0x38, 0xE7, 0xAA, 0x01);\n// 2c584f7b-ce2a-4be6-a093-77cfbb2a7ea1\nDEFINE_GUID(IID_IPackage8, 0x2c584f7b, 0xce2a, 0x4be6, 0xa0, 0x93, 0x77, 0xcf, 0xbb, 0x2a, 0x7e, 0xa1);\n// d0a618ad-bf35-42ac-ac06-86eeeb41d04b\nDEFINE_GUID(IID_IAppListEntry2, 0xd0a618ad, 0xbf35, 0x42ac, 0xac, 0x06, 0x86, 0xee, 0xeb, 0x41, 0xd0, 0x4b);\n// cf7f59b3-6a09-4de8-a6c0-5792d56880d1\nDEFINE_GUID(IID_IAppInfo, 0xcf7f59b3, 0x6a09, 0x4de8, 0xa6, 0xc0, 0x57, 0x92, 0xd5, 0x68, 0x80, 0xd1);\n// 4207a996-ca2f-42f7-bde8-8b10457a7f30\nDEFINE_GUID(IID_IStorageItem, 0x4207a996, 0xca2f, 0x42f7, 0xbd, 0xe8, 0x8b, 0x10, 0x45, 0x7a, 0x7f, 0x30);\n\nstatic typeof(&OpenPackageInfoByFullNameForUser) OpenPackageInfoByFullNameForUser_I = NULL;\nstatic typeof(&GetPackageApplicationIds) GetPackageApplicationIds_I = NULL;\nstatic typeof(&ClosePackageInfo) ClosePackageInfo_I = NULL;\n\nstatic BOOLEAN PhPackageImportsInitialized(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOLEAN initialized = FALSE;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhGetLoaderEntryDllBaseZ(L\"kernelbase.dll\"))\n        {\n            OpenPackageInfoByFullNameForUser_I = PhGetDllBaseProcedureAddress(baseAddress, \"OpenPackageInfoByFullNameForUser\", 0);\n            GetPackageApplicationIds_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetPackageApplicationIds\", 0);\n            ClosePackageInfo_I = PhGetDllBaseProcedureAddress(baseAddress, \"ClosePackageInfo\", 0);\n        }\n\n        if (\n            OpenPackageInfoByFullNameForUser_I &&\n            GetPackageApplicationIds_I &&\n            ClosePackageInfo_I\n            )\n        {\n            initialized = TRUE;\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return initialized;\n}\n\n_Success_(return)\nBOOLEAN PhGetPackageApplicationIds(\n    _In_ PCWSTR PackageFullName,\n    _Out_ PWSTR** ApplicationUserModelIds,\n    _Out_ PULONG ApplicationUserModelIdsCount\n    )\n{\n    BOOLEAN success = FALSE;\n    ULONG status;\n    PACKAGE_INFO_REFERENCE packageHandle;\n    ULONG bufferCount = 0;\n    ULONG bufferLength = 0;\n    PBYTE buffer = NULL;\n\n    if (!PhPackageImportsInitialized())\n        return FALSE;\n\n    status = OpenPackageInfoByFullNameForUser_I(\n        NULL,\n        PackageFullName,\n        0,\n        &packageHandle\n        );\n\n    if (status != ERROR_SUCCESS)\n        return FALSE;\n\n    status = GetPackageApplicationIds_I(\n        packageHandle,\n        &bufferLength,\n        NULL,\n        NULL\n        );\n\n    if (status != ERROR_INSUFFICIENT_BUFFER)\n        goto CleanupExit;\n\n    buffer = PhAllocate(bufferLength);\n    memset(buffer, 0, bufferLength);\n\n    status = GetPackageApplicationIds_I(\n        packageHandle,\n        &bufferLength,\n        buffer,\n        &bufferCount\n        );\n\n    if (status != ERROR_SUCCESS)\n        goto CleanupExit;\n\n    success = TRUE;\n\nCleanupExit:\n\n    ClosePackageInfo_I(packageHandle);\n\n    if (success)\n    {\n        *ApplicationUserModelIds = (PWSTR*)buffer;\n        *ApplicationUserModelIdsCount = bufferCount;\n    }\n    else\n    {\n        if (buffer)\n        {\n            PhFree(buffer);\n        }\n    }\n\n    return success;\n}\n\ntypedef enum _PH_QUERY_PACKAGE_INFO_TYPE\n{\n    PH_QUERY_PACKAGE_INFO_NAME = 1,\n    PH_QUERY_PACKAGE_INFO_FULLNAME = 2,\n    PH_QUERY_PACKAGE_INFO_FAMILYNAME = 4,\n    PH_QUERY_PACKAGE_INFO_DISPLAYNAME = 8,\n    PH_QUERY_PACKAGE_INFO_VERSION = 16,\n    PH_QUERY_PACKAGE_INFO_LOGO = 32,\n    PH_QUERY_PACKAGE_INFO_LOCATION = 64,\n} PH_QUERY_PACKAGE_INFO_TYPE;\n\nBOOLEAN PhQueryApplicationModelPackageInformation(\n    _In_ PPH_LIST PackageList,\n    _In_ __x_ABI_CWindows_CApplicationModel_CIPackage* AppPackage,\n    _In_ __x_ABI_CWindows_CApplicationModel_CIPackage2* AppPackage2,\n    _In_ PH_QUERY_PACKAGE_INFO_TYPE FilterType\n    )\n{\n    __x_ABI_CWindows_CStorage_CIStorageFolder* appPackageFolder;\n    __x_ABI_CWindows_CStorage_CIStorageItem* appPackageFolderItem;\n    __x_ABI_CWindows_CApplicationModel_CIPackageId* appPackageID;\n    __x_ABI_CWindows_CFoundation_CIUriRuntimeClass* appPackageLogo;\n    PPH_STRING packageInstallLocationString = NULL;\n    PPH_STRING packageNameString = NULL;\n    PPH_STRING packageFullNameString = NULL;\n    PPH_STRING packageFamilyNameString = NULL;\n    PPH_STRING packageDisplayNameString = NULL;\n    PPH_STRING packageLogoString = NULL;\n    PPH_STRING packageVersionString = NULL;\n    HSTRING stringHandle = NULL;\n\n    if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackage_get_Id(AppPackage, &appPackageID)))\n    {\n        if (FlagOn(FilterType, PH_QUERY_PACKAGE_INFO_NAME))\n        {\n            if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackageId_get_Name(appPackageID, &stringHandle)))\n            {\n                if (PhGetWindowsRuntimeStringLength(stringHandle))\n                {\n                    packageNameString = PhCreateStringFromWindowsRuntimeString(stringHandle);\n                }\n\n                PhDeleteWindowsRuntimeString(stringHandle);\n            }\n        }\n\n        if (FlagOn(FilterType, PH_QUERY_PACKAGE_INFO_FULLNAME))\n        {\n            if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackageId_get_FullName(appPackageID, &stringHandle)))\n            {\n                if (PhGetWindowsRuntimeStringLength(stringHandle))\n                {\n                    packageFullNameString = PhCreateStringFromWindowsRuntimeString(stringHandle);\n                }\n\n                PhDeleteWindowsRuntimeString(stringHandle);\n            }\n        }\n\n        if (FlagOn(FilterType, PH_QUERY_PACKAGE_INFO_FAMILYNAME))\n        {\n            if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackageId_get_FamilyName(appPackageID, &stringHandle)))\n            {\n                if (PhGetWindowsRuntimeStringLength(stringHandle))\n                {\n                    packageFamilyNameString = PhCreateStringFromWindowsRuntimeString(stringHandle);\n                }\n\n                PhDeleteWindowsRuntimeString(stringHandle);\n            }\n        }\n\n        if (FlagOn(FilterType, PH_QUERY_PACKAGE_INFO_VERSION))\n        {\n            __x_ABI_CWindows_CApplicationModel_CPackageVersion appPackageVersion = { 0 };\n\n            if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackageId_get_Version(appPackageID, &appPackageVersion)))\n            {\n                PH_FORMAT format[7];\n\n                PhInitFormatU(&format[0], appPackageVersion.Major);\n                PhInitFormatC(&format[1], L'.');\n                PhInitFormatU(&format[2], appPackageVersion.Minor);\n                PhInitFormatC(&format[3], L'.');\n                PhInitFormatU(&format[4], appPackageVersion.Revision);\n                PhInitFormatC(&format[5], L'.');\n                PhInitFormatU(&format[6], appPackageVersion.Build);\n\n                packageVersionString = PhFormat(format,RTL_NUMBER_OF(format), 0);\n            }\n        }\n\n        __x_ABI_CWindows_CApplicationModel_CIPackageId_Release(appPackageID);\n    }\n\n    if (FlagOn(FilterType, PH_QUERY_PACKAGE_INFO_DISPLAYNAME))\n    {\n        if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackage2_get_DisplayName(AppPackage2, &stringHandle)))\n        {\n            if (PhGetWindowsRuntimeStringLength(stringHandle))\n            {\n                packageDisplayNameString = PhCreateStringFromWindowsRuntimeString(stringHandle);\n            }\n\n            PhDeleteWindowsRuntimeString(stringHandle);\n        }\n    }\n\n    if (FlagOn(FilterType, PH_QUERY_PACKAGE_INFO_LOGO))\n    {\n        if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackage2_get_Logo(AppPackage2, &appPackageLogo)))\n        {\n            if (SUCCEEDED(__x_ABI_CWindows_CFoundation_CIUriRuntimeClass_get_RawUri(appPackageLogo, &stringHandle)))\n            {\n                packageLogoString = PhCreateStringFromWindowsRuntimeString(stringHandle);\n                PhDeleteWindowsRuntimeString(stringHandle);\n            }\n\n            __x_ABI_CWindows_CFoundation_CIUriRuntimeClass_Release(appPackageLogo);\n        }\n    }\n\n    if (FlagOn(FilterType, PH_QUERY_PACKAGE_INFO_LOCATION))\n    {\n        if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackage_get_InstalledLocation(AppPackage, &appPackageFolder)))\n        {\n            if (SUCCEEDED(__x_ABI_CWindows_CStorage_CIStorageFolder_QueryInterface(appPackageFolder, &IID_IStorageItem, &appPackageFolderItem)))\n            {\n                if (SUCCEEDED(__x_ABI_CWindows_CStorage_CIStorageItem_get_Path(appPackageFolderItem, &stringHandle)))\n                {\n                    if (PhGetWindowsRuntimeStringLength(stringHandle))\n                    {\n                        packageInstallLocationString = PhCreateStringFromWindowsRuntimeString(stringHandle);\n                    }\n                    PhDeleteWindowsRuntimeString(stringHandle);\n                }\n\n                __x_ABI_CWindows_CStorage_CIStorageItem_Release(appPackageFolderItem);\n            }\n\n            __x_ABI_CWindows_CStorage_CIStorageFolder_Release(appPackageFolder);\n        }\n    }\n\n    if (packageFullNameString)\n    {\n        ULONG applicationUserModelIdsCount;\n        PWSTR* applicationUserModelIdsBuffer;\n\n        if (PhGetPackageApplicationIds(\n            PhGetString(packageFullNameString),\n            &applicationUserModelIdsBuffer,\n            &applicationUserModelIdsCount\n            ))\n        {\n            for (ULONG i = 0; i < applicationUserModelIdsCount; ++i)\n            {\n                PPH_APPUSERMODELID_ENUM_ENTRY entry;\n\n                entry = PhAllocateZero(sizeof(PH_APPUSERMODELID_ENUM_ENTRY));\n                entry->AppUserModelId = PhCreateString(applicationUserModelIdsBuffer[i]);\n                PhSetReference(&entry->PackageName, packageNameString);\n                PhSetReference(&entry->PackageDisplayName, packageDisplayNameString);\n                PhSetReference(&entry->PackageFamilyName, packageFamilyNameString);\n                PhSetReference(&entry->PackageInstallPath, packageInstallLocationString);\n                PhSetReference(&entry->PackageFullName, packageFullNameString);\n                PhSetReference(&entry->PackageVersion, packageVersionString);\n                PhSetReference(&entry->SmallLogoPath, packageLogoString);\n\n                PhAddItemList(PackageList, entry);\n            }\n        }\n    }\n\n    PhClearReference(&packageLogoString);\n    PhClearReference(&packageVersionString);\n    PhClearReference(&packageFullNameString);\n    PhClearReference(&packageInstallLocationString);\n    PhClearReference(&packageFamilyNameString);\n    PhClearReference(&packageDisplayNameString);\n    PhClearReference(&packageNameString);\n\n    return TRUE;\n}\n\nPPH_LIST PhEnumPackageApplicationUserModelIds(\n    VOID\n    )\n{\n    HRESULT status;\n    PPH_LIST list = NULL;\n    __x_ABI_CWindows_CManagement_CDeployment_CIPackageManager* packageManager = NULL;\n    __FIIterable_1_Windows__CApplicationModel__CPackage* enumPackages = NULL;\n    __FIIterator_1_Windows__CApplicationModel__CPackage* enumPackage = NULL;\n    __x_ABI_CWindows_CApplicationModel_CIPackage* currentPackage = NULL;\n    __x_ABI_CWindows_CApplicationModel_CIPackage2* currentPackage2 = NULL;\n    boolean haveCurrentPackage = FALSE;\n\n    status = PhActivateInstance(\n        L\"AppXDeploymentClient.dll\",\n        RuntimeClass_Windows_Management_Deployment_PackageManager,\n        &IID_IPackageManager,\n        &packageManager\n        );\n\n    if (HR_FAILED(status))\n        return NULL;\n\n    if (PhGetOwnTokenAttributes().Elevated)\n        status = __x_ABI_CWindows_CManagement_CDeployment_CIPackageManager_FindPackages(packageManager, &enumPackages);\n    else\n        status = __x_ABI_CWindows_CManagement_CDeployment_CIPackageManager_FindPackagesByUserSecurityId(packageManager, NULL, &enumPackages);\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = __FIIterable_1_Windows__CApplicationModel__CPackage_First(enumPackages, &enumPackage);\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = __FIIterator_1_Windows__CApplicationModel__CPackage_get_HasCurrent(enumPackage, &haveCurrentPackage);\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    list = PhCreateList(10);\n\n    while (haveCurrentPackage)\n    {\n        status = __FIIterator_1_Windows__CApplicationModel__CPackage_get_Current(enumPackage, &currentPackage);\n\n        if (HR_SUCCESS(status))\n        {\n            status = __x_ABI_CWindows_CApplicationModel_CIPackage_QueryInterface(currentPackage, &IID_IPackage2, &currentPackage2);\n\n            if (HR_SUCCESS(status))\n            {\n                PhQueryApplicationModelPackageInformation(\n                    list,\n                    currentPackage,\n                    currentPackage2,\n                    PH_QUERY_PACKAGE_INFO_NAME | PH_QUERY_PACKAGE_INFO_FULLNAME | PH_QUERY_PACKAGE_INFO_FAMILYNAME |\n                    PH_QUERY_PACKAGE_INFO_DISPLAYNAME | PH_QUERY_PACKAGE_INFO_LOGO\n                    );\n\n                // Note: GetPackageApplicationIds returns all identifiers while the IAppListEntry2_get_AppUserModelId interface only returns a single entry (dmex)\n                //if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackage_QueryInterface(currentPackage, &IID_IPackage8, &currentPackage8)))\n                //if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CIPackage8_GetAppListEntries(currentPackage8, &packageAppListEntryArray)))\n                //if (SUCCEEDED(__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry_get_Size(packageAppListEntryArray, &packageAppListEntryCount)))\n                //for (UINT32 i = 0; i < packageAppListEntryCount; i++)\n                //if (SUCCEEDED(__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry_GetAt(packageAppListEntryArray, i, &packageAppListEntry)))\n                //if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CCore_CIAppListEntry_QueryInterface(packageAppListEntry, &IID_IAppListEntry2, &packageAppListEntry2)))\n                //if (SUCCEEDED(__x_ABI_CWindows_CApplicationModel_CCore_CIAppListEntry2_get_AppUserModelId(packageAppListEntry2, &packageAppUserModelIdString)))\n\n                __x_ABI_CWindows_CApplicationModel_CIPackage2_Release(currentPackage2);\n            }\n\n            __FIIterator_1_Windows__CApplicationModel__CPackage_Release(currentPackage);\n        }\n\n        if (HR_FAILED(status))\n            break;\n\n        status = __FIIterator_1_Windows__CApplicationModel__CPackage_MoveNext(enumPackage, &haveCurrentPackage);\n\n        if (HR_FAILED(status))\n            break;\n    }\n\nCleanupExit:\n    if (enumPackage)\n        __FIIterator_1_Windows__CApplicationModel__CPackage_Release(enumPackage);\n    if (enumPackages)\n        __FIIterable_1_Windows__CApplicationModel__CPackage_Release(enumPackages);\n    __x_ABI_CWindows_CManagement_CDeployment_CIPackageManager_Release(packageManager);\n\n    return list;\n}\n\nVOID PhDestroyEnumPackageApplicationUserModelIds(\n    _In_ PPH_LIST PackageList\n    )\n{\n    if (!PackageList)\n        return;\n\n    for (ULONG i = 0; i < PackageList->Count; i++)\n    {\n        PPH_APPUSERMODELID_ENUM_ENTRY entry = PackageList->Items[i];\n\n        PhClearReference(&entry->AppUserModelId);\n        PhClearReference(&entry->PackageName);\n        PhClearReference(&entry->PackageDisplayName);\n        PhClearReference(&entry->PackageFamilyName);\n        PhClearReference(&entry->PackageInstallPath);\n        PhClearReference(&entry->PackageFullName);\n        PhClearReference(&entry->PackageVersion);\n        PhClearReference(&entry->SmallLogoPath);\n\n        PhFree(entry);\n    }\n\n    PhDereferenceObject(PackageList);\n}\n\n#pragma endregion\n"
  },
  {
    "path": "phlib/avltree.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#include <phbase.h>\n\n/**\n * Initializes an AVL tree.\n *\n * \\param Tree The tree.\n * \\param CompareFunction A function used to compare tree elements.\n */\nVOID PhInitializeAvlTree(\n    _Out_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_TREE_COMPARE_FUNCTION CompareFunction\n    )\n{\n    Tree->Root.Parent = NULL;\n    Tree->Root.Left = NULL;\n    Tree->Root.Right = NULL;\n    Tree->Root.Balance = 0;\n    Tree->Count = 0;\n\n    Tree->CompareFunction = CompareFunction;\n}\n\n/**\n * Finds an element in an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n * \\param Result The result of the search.\n */\nFORCEINLINE PPH_AVL_LINKS PhpFindElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element,\n    _Out_ PLONG Result\n    )\n{\n    PPH_AVL_LINKS links;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n\n    if (!links)\n    {\n        *Result = 1;\n        return &Tree->Root;\n    }\n\n    while (TRUE)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result == 0)\n        {\n            *Result = 0;\n            return links;\n        }\n        else if (result < 0)\n        {\n            if (links->Left)\n            {\n                links = links->Left;\n            }\n            else\n            {\n                *Result = -1;\n                return links;\n            }\n        }\n        else\n        {\n            if (links->Right)\n            {\n                links = links->Right;\n            }\n            else\n            {\n                *Result = 1;\n                return links;\n            }\n        }\n    }\n}\n\nFORCEINLINE VOID PhpRotateLeftAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS Q;\n\n    //    P\n    //  |   |\n    //  A   Q\n    //     | |\n    //     B C\n    //\n    // becomes\n    //\n    //    Q\n    //  |   |\n    //  P   C\n    // | |\n    // A B\n    //\n    // P and Q must exist.\n    // B may not exist.\n    // A and C are not affected.\n\n    P = *Root;\n    Q = P->Right;\n\n    // The new root is Q\n\n    *Root = Q;\n    Q->Parent = P->Parent;\n\n    // P.Right = Q.Left (transfer B)\n\n    P->Right = Q->Left;\n\n    if (P->Right)\n        P->Right->Parent = P;\n\n    // Q.Left = P\n\n    Q->Left = P;\n    P->Parent = Q;\n}\n\nFORCEINLINE VOID PhpRotateLeftTwiceAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS Q;\n    PPH_AVL_LINKS R;\n\n    //     P\n    //  |     |\n    //  A     Q\n    //      |   |\n    //      R   D\n    //     | |\n    //     B C\n    //\n    // becomes\n    //\n    //     R\n    //  |     |\n    //  P     Q\n    // | |   | |\n    // A B   C D\n    //\n    // P, Q, and R must exist.\n    // B and C may not exist.\n    // A and D are not affected.\n\n    // PhpRotateRightAvlLinks(&(*Root)->Right);\n    // PhpRotateLeftAvlLinks(Root);\n\n    // P is the current root\n    // Q is P.Right\n    // R is Q.Left (P.Right.Left)\n\n    P = *Root;\n    Q = P->Right;\n    R = Q->Left;\n\n    // The new root is R\n\n    *Root = R;\n    R->Parent = P->Parent;\n\n    // Q.Left = R.Right (transfer C)\n\n    Q->Left = R->Right;\n\n    if (Q->Left)\n        Q->Left->Parent = Q;\n\n    // R.Right = Q\n\n    R->Right = Q;\n    Q->Parent = R;\n\n    // P.Right = R.Left (transfer B)\n\n    P->Right = R->Left;\n\n    if (P->Right)\n        P->Right->Parent = P;\n\n    // R.Left = P\n\n    R->Left = P;\n    P->Parent = R;\n}\n\nFORCEINLINE VOID PhpRotateRightAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS Q;\n    PPH_AVL_LINKS P;\n\n    //    Q\n    //  |   |\n    //  P   C\n    // | |\n    // A B\n    //\n    // becomes\n    //\n    //    P\n    //  |   |\n    //  A   Q\n    //     | |\n    //     B C\n    //\n    // Q and P must exist.\n    // B may not exist.\n    // A and C are not affected.\n\n    Q = *Root;\n    P = Q->Left;\n\n    // The new root is P\n\n    *Root = P;\n    P->Parent = Q->Parent;\n\n    // Q.Left = P.Right (transfer B)\n\n    Q->Left = P->Right;\n\n    if (Q->Left)\n        Q->Left->Parent = Q;\n\n    // P.Right = Q\n\n    P->Right = Q;\n    Q->Parent = P;\n}\n\nFORCEINLINE VOID PhpRotateRightTwiceAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS Q;\n    PPH_AVL_LINKS R;\n\n    //       P\n    //    |     |\n    //    Q     D\n    //  |   |\n    //  A   R\n    //     | |\n    //     B C\n    //\n    // becomes\n    //\n    //     R\n    //  |     |\n    //  Q     P\n    // | |   | |\n    // A B   C D\n    //\n    // P, Q, and R must exist.\n    // B and C may not exist.\n    // A and D are not affected.\n\n    // PhpRotateLeftAvlLinks(&(*Root)->Left);\n    // PhpRotateRightAvlLinks(Root);\n\n    // P is the current root\n    // Q is P.Left\n    // R is Q.Right (P.Left.Right)\n\n    P = *Root;\n    Q = P->Left;\n    R = Q->Right;\n\n    // The new root is R\n\n    *Root = R;\n    R->Parent = P->Parent;\n\n    // Q.Right = R.Left (transfer B)\n\n    Q->Right = R->Left;\n\n    if (Q->Right)\n        Q->Right->Parent = Q;\n\n    // R.Left = Q\n\n    R->Left = Q;\n    Q->Parent = R;\n\n    // P.Left = R.Right (transfer C)\n\n    P->Left = R->Right;\n\n    if (P->Left)\n        P->Left->Parent = P;\n\n    // R.Right = P\n\n    R->Right = P;\n    P->Parent = R;\n}\n\nULONG PhpRebalanceAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS Q;\n    PPH_AVL_LINKS R;\n\n    P = *Root;\n\n    if (P->Balance == -1)\n    {\n        Q = P->Left;\n\n        if (Q->Balance == -1)\n        {\n            // Left-left\n\n            PhpRotateRightAvlLinks(Root);\n\n            P->Balance = 0;\n            Q->Balance = 0;\n\n            return 1;\n        }\n        else if (Q->Balance == 1)\n        {\n            // Left-right\n\n            R = Q->Right;\n\n            PhpRotateRightTwiceAvlLinks(Root);\n\n            if (R->Balance == -1)\n            {\n                P->Balance = 1;\n                Q->Balance = 0;\n            }\n            else if (R->Balance == 1)\n            {\n                P->Balance = 0;\n                Q->Balance = -1;\n            }\n            else\n            {\n                P->Balance = 0;\n                Q->Balance = 0;\n            }\n\n            R->Balance = 0;\n\n            return 2;\n        }\n        else\n        {\n            // Special (only occurs when removing)\n\n            //    D\n            //  |   |\n            //  B   E\n            // | |\n            // A C\n            //\n            // Removing E results in:\n            //\n            //    D\n            //  |\n            //  B\n            // | |\n            // A C\n            //\n            // which is unbalanced. Rotating right at B results in:\n            //\n            //   B\n            // |   |\n            // A   D\n            //    |\n            //    C\n            //\n            // The same applies for the mirror case.\n\n            PhpRotateRightAvlLinks(Root);\n\n            Q->Balance = 1;\n\n            return 3;\n        }\n    }\n    else\n    {\n        Q = P->Right;\n\n        if (Q->Balance == 1)\n        {\n            // Right-right\n\n            PhpRotateLeftAvlLinks(Root);\n\n            P->Balance = 0;\n            Q->Balance = 0;\n\n            return 1;\n        }\n        else if (Q->Balance == -1)\n        {\n            // Right-left\n\n            R = Q->Left;\n\n            PhpRotateLeftTwiceAvlLinks(Root);\n\n            if (R->Balance == -1)\n            {\n                P->Balance = 0;\n                Q->Balance = 1;\n            }\n            else if (R->Balance == 1)\n            {\n                P->Balance = -1;\n                Q->Balance = 0;\n            }\n            else\n            {\n                P->Balance = 0;\n                Q->Balance = 0;\n            }\n\n            R->Balance = 0;\n\n            return 2;\n        }\n        else\n        {\n            // Special (only occurs when removing)\n\n            PhpRotateLeftAvlLinks(Root);\n\n            Q->Balance = -1;\n\n            return 3;\n        }\n    }\n}\n\n/**\n * Adds an element to an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Element The element to add.\n *\n * \\return NULL if the element was added, or an existing element.\n */\nPPH_AVL_LINKS PhAddElementAvlTree(\n    _Inout_ PPH_AVL_TREE Tree,\n    _Out_ PPH_AVL_LINKS Element\n    )\n{\n    LONG result;\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS root;\n    LONG balance;\n\n    P = PhpFindElementAvlTree(Tree, Element, &result);\n\n    if (result < 0)\n        P->Left = Element;\n    else if (result > 0)\n        P->Right = Element;\n    else\n        return P;\n\n    Element->Parent = P;\n    Element->Left = NULL;\n    Element->Right = NULL;\n    Element->Balance = 0;\n\n    // Balance the tree.\n\n    P = Element;\n    root = PhRootElementAvlTree(Tree);\n\n    while (P != root)\n    {\n        // In this implementation, the balance factor is the right height minus left height.\n\n        if (P->Parent->Left == P)\n            balance = -1;\n        else\n            balance = 1;\n\n        P = P->Parent;\n\n        if (P->Balance == 0)\n        {\n            // The balance becomes -1 or 1. Rotations are not needed\n            // yet, but we should keep tracing upwards.\n\n            P->Balance = balance;\n        }\n        else if (P->Balance != balance)\n        {\n            // The balance is opposite the new balance, so it now\n            // becomes 0.\n\n            P->Balance = 0;\n\n            break;\n        }\n        else\n        {\n            PPH_AVL_LINKS *ref;\n\n            // The balance is the same as the new balance, meaning\n            // it now becomes -2 or 2. Rotations are needed.\n\n            if (P->Parent->Left == P)\n                ref = &P->Parent->Left;\n            else\n                ref = &P->Parent->Right;\n\n            PhpRebalanceAvlLinks(ref);\n\n            break;\n        }\n    }\n\n    Tree->Count++;\n\n    return NULL;\n}\n\n/**\n * Removes an element from an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Element An element already present in the tree.\n */\nVOID PhRemoveElementAvlTree(\n    _Inout_ PPH_AVL_TREE Tree,\n    _Inout_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS newElement;\n    PPH_AVL_LINKS *replace;\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS root;\n    LONG balance;\n\n    if (!Element->Left || !Element->Right)\n    {\n        newElement = Element;\n    }\n    else if (Element->Balance >= 0) // Pick the side depending on the balance to minimize rebalances\n    {\n        newElement = Element->Right;\n\n        while (newElement->Left)\n            newElement = newElement->Left;\n    }\n    else\n    {\n        newElement = Element->Left;\n\n        while (newElement->Right)\n            newElement = newElement->Right;\n    }\n\n    if (newElement->Parent->Left == newElement)\n    {\n        replace = &newElement->Parent->Left;\n        balance = -1;\n    }\n    else\n    {\n        replace = &newElement->Parent->Right;\n        balance = 1;\n    }\n\n    if (!newElement->Right)\n    {\n        *replace = newElement->Left;\n\n        if (newElement->Left)\n            newElement->Left->Parent = newElement->Parent;\n    }\n    else\n    {\n        *replace = newElement->Right;\n        newElement->Right->Parent = newElement->Parent; // we know Right exists\n    }\n\n    P = newElement->Parent;\n    root = &Tree->Root;\n\n    while (P != root)\n    {\n        if (P->Balance == balance)\n        {\n            // The balance is cancelled by the remove operation and becomes 0.\n            // Rotations are not needed yet, but we should keep tracing upwards.\n\n            P->Balance = 0;\n        }\n        else if (P->Balance == 0)\n        {\n            // The balance is 0, so it now becomes -1 or 1.\n\n            P->Balance = -balance;\n\n            break;\n        }\n        else\n        {\n            PPH_AVL_LINKS *ref;\n\n            // The balance is the same as the new balance, meaning\n            // it now becomes -2 or 2. Rotations are needed.\n\n            if (P->Parent->Left == P)\n                ref = &P->Parent->Left;\n            else\n                ref = &P->Parent->Right;\n\n            // We can stop tracing if we have a special case rotation.\n            if (PhpRebalanceAvlLinks(ref) == 3)\n                break;\n\n            P = P->Parent;\n        }\n\n        if (P->Parent->Left == P)\n            balance = -1;\n        else\n            balance = 1;\n\n        P = P->Parent;\n    }\n\n    if (newElement != Element)\n    {\n        // Replace the subject with the new subject.\n\n        *newElement = *Element;\n\n        if (Element->Parent->Left == Element)\n            newElement->Parent->Left = newElement;\n        else\n            newElement->Parent->Right = newElement;\n\n        if (newElement->Left)\n            newElement->Left->Parent = newElement;\n        if (newElement->Right)\n            newElement->Right->Parent = newElement;\n    }\n\n    Tree->Count--;\n}\n\n/**\n * Finds an element in an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Element An element to find.\n *\n * \\return The element, or NULL if it could not be found.\n */\nPPH_AVL_LINKS PhFindElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    LONG result;\n\n    links = PhpFindElementAvlTree(Tree, Element, &result);\n\n    if (result == 0)\n        return links;\n    else\n        return NULL;\n}\n\n/**\n * Finds the first element in an AVL tree that is greater than or equal to the specified element.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n *\n * \\return The bound element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhLowerBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    PPH_AVL_LINKS closest;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n    closest = NULL;\n\n    while (links)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result > 0)\n        {\n            links = links->Right;\n        }\n        else\n        {\n            closest = links;\n            links = links->Left;\n        }\n    }\n\n    return closest;\n}\n\n/**\n * Finds the first element in an AVL tree that is greater than the specified element.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n *\n * \\return The bound element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhUpperBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    PPH_AVL_LINKS closest;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n    closest = NULL;\n\n    while (links)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result >= 0)\n        {\n            links = links->Right;\n        }\n        else\n        {\n            closest = links;\n            links = links->Left;\n        }\n    }\n\n    return closest;\n}\n\n/**\n * Finds the last element in an AVL tree that is less than the specified element.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n *\n * \\return The bound element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhLowerDualBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    PPH_AVL_LINKS closest;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n    closest = NULL;\n\n    while (links)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result > 0)\n        {\n            closest = links;\n            links = links->Right;\n        }\n        else\n        {\n            links = links->Left;\n        }\n    }\n\n    return closest;\n}\n\n/**\n * Finds the last element in an AVL tree that is less than or equal to the specified element.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n *\n * \\return The bound element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhUpperDualBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    PPH_AVL_LINKS closest;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n    closest = NULL;\n\n    while (links)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result >= 0)\n        {\n            closest = links;\n            links = links->Right;\n        }\n        else\n        {\n            links = links->Left;\n        }\n    }\n\n    return closest;\n}\n\n/**\n * Finds the smallest element in an AVL tree.\n *\n * \\param Tree The tree.\n *\n * \\return An element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhMinimumElementAvlTree(\n    _In_ PPH_AVL_TREE Tree\n    )\n{\n    PPH_AVL_LINKS links;\n\n    links = PhRootElementAvlTree(Tree);\n\n    if (!links)\n        return NULL;\n\n    while (links->Left)\n        links = links->Left;\n\n    return links;\n}\n\n/**\n * Finds the biggest element in an AVL tree.\n *\n * \\param Tree The tree.\n *\n * \\return An element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhMaximumElementAvlTree(\n    _In_ PPH_AVL_TREE Tree\n    )\n{\n    PPH_AVL_LINKS links;\n\n    links = PhRootElementAvlTree(Tree);\n\n    if (!links)\n        return NULL;\n\n    while (links->Right)\n        links = links->Right;\n\n    return links;\n}\n\n/**\n * Finds the next element in an AVL tree.\n *\n * \\param Element The element.\n *\n * \\return The next element, or NULL if there are no more elements.\n */\nPPH_AVL_LINKS PhSuccessorElementAvlTree(\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n\n    if (Element->Right)\n    {\n        Element = Element->Right;\n\n        while (Element->Left)\n            Element = Element->Left;\n\n        return Element;\n    }\n    else\n    {\n        // Trace back to the next vertical level. Note\n        // that this code does in fact return NULL when there\n        // are no more elements because of the way the root\n        // element is constructed.\n\n        links = Element->Parent;\n\n        while (links && links->Right == Element)\n        {\n            Element = links;\n            links = links->Parent;\n        }\n\n        return links;\n    }\n}\n\n/**\n * Finds the previous element in an AVL tree.\n *\n * \\param Element The element.\n *\n * \\return The previous element, or NULL if there are no more elements.\n */\nPPH_AVL_LINKS PhPredecessorElementAvlTree(\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n\n    if (Element->Left)\n    {\n        Element = Element->Left;\n\n        while (Element->Right)\n            Element = Element->Right;\n\n        return Element;\n    }\n    else\n    {\n        links = Element->Parent;\n\n        while (links && links->Left == Element)\n        {\n            Element = links;\n            links = links->Parent;\n        }\n\n        if (links)\n        {\n            // We need an additional check because the tree root is\n            // stored in Root.Right, not Left.\n            if (!links->Parent)\n                return NULL; // reached Root, so no more elements\n        }\n\n        return links;\n    }\n}\n\n/**\n * Enumerates the elements in an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Order The enumeration order.\n * \\param Callback The callback function.\n * \\param Context A user-defined value to pass to the callback function.\n */\nVOID PhEnumAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PH_TREE_ENUMERATION_ORDER Order,\n    _In_ PPH_ENUM_AVL_TREE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    // The maximum height of an AVL tree is around 1.44 * log2(n).\n    // The maximum number of elements in this implementation is 2^32, so the maximum height is\n    // around 46.08.\n    PPH_AVL_LINKS stackBase[47];\n    PPH_AVL_LINKS *stack;\n    PPH_AVL_LINKS links;\n\n    stack = stackBase;\n\n    switch (Order)\n    {\n    case TreeEnumerateInOrder:\n        links = PhRootElementAvlTree(Tree);\n\n        while (links)\n        {\n            *stack++ = links;\n            links = links->Left;\n        }\n\n        while (stack != stackBase)\n        {\n            links = *--stack;\n\n            if (!Callback(Tree, links, Context))\n                break;\n\n            links = links->Right;\n\n            while (links)\n            {\n                *stack++ = links;\n                links = links->Left;\n            }\n        }\n\n        break;\n    case TreeEnumerateInReverseOrder:\n        links = PhRootElementAvlTree(Tree);\n\n        while (links)\n        {\n            *stack++ = links;\n            links = links->Right;\n        }\n\n        while (stack != stackBase)\n        {\n            links = *--stack;\n\n            if (!Callback(Tree, links, Context))\n                break;\n\n            links = links->Left;\n\n            while (links)\n            {\n                *stack++ = links;\n                links = links->Right;\n            }\n        }\n\n        break;\n    }\n}\n"
  },
  {
    "path": "phlib/basestring.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2019-2023\n *\n */\n\n#include <phbase.h>\n#include <phintrnl.h>\n#include <phintrin.h>\n#include <phnative.h>\n#include <circbuf.h>\n#include <thirdparty.h>\n#include <ntintsafe.h>\n\n#include <trace.h>\n\n#ifndef PH_NATIVE_STRING_CONVERSION\n#define PH_NATIVE_STRING_CONVERSION 1\n#endif\n\n#ifndef PH_NATIVE_STRING_IN_STRING\n#define PH_NATIVE_STRING_IN_STRING 1\n#endif\n\n/**\n * Determines the length of the specified string, in characters.\n *\n * \\param String The string.\n */\nSIZE_T PhCountStringZ(\n    _In_ PCWSTR String\n    )\n{\n#ifndef _ARM64_\n    if (PhHasAVX)\n    {\n        PWSTR p;\n        ULONG unaligned;\n        __m256i b;\n        __m256i z;\n        ULONG mask;\n        ULONG index;\n\n        p = (PWSTR)((ULONG_PTR)String & ~0x1f);\n        unaligned = (ULONG_PTR)String & 0x1f;\n        z = _mm256_setzero_si256();\n\n        if (unaligned != 0)\n        {\n            b = _mm256_loadu_si256((__m256i const*)p);\n            b = _mm256_cmpeq_epi16(b, z);\n            mask = _mm256_movemask_epi8(b) >> unaligned;\n\n            if (_BitScanForward(&index, mask))\n            {\n                _mm256_zeroupper();\n                return index / sizeof(WCHAR);\n            }\n\n            p += 32 / sizeof(WCHAR);\n        }\n\n        while (TRUE)\n        {\n            b = _mm256_load_si256((__m256i const*)p);\n            b = _mm256_cmpeq_epi16(b, z);\n            mask = _mm256_movemask_epi8(b);\n\n            if (_BitScanForward(&index, mask))\n            {\n                _mm256_zeroupper();\n                return (SIZE_T)(p - String) + index / sizeof(WCHAR);\n            }\n\n            p += 32 / sizeof(WCHAR);\n        }\n    }\n    else\n#endif\n    if (PhHasIntrinsics)\n    {\n        PWSTR p;\n        ULONG unaligned;\n        PH_INT128 b;\n        PH_INT128 z;\n        ULONG mask;\n        ULONG index;\n\n        p = (PWSTR)((ULONG_PTR)String & ~0xf);\n        unaligned = (ULONG_PTR)String & 0xf;\n        z = PhSetZeroINT128();\n\n        if (unaligned != 0)\n        {\n            b = PhLoadINT128U((PLONG)p);\n            b = PhCompareEqINT128by16(b, z);\n            mask = PhMoveMaskINT128by8(b) >> unaligned;\n\n            if (_BitScanForward(&index, mask))\n            {\n                return index / sizeof(WCHAR);\n            }\n\n            p += 16 / sizeof(WCHAR);\n        }\n\n        while (TRUE)\n        {\n            b = PhLoadINT128((PLONG)p);\n            b = PhCompareEqINT128by16(b, z);\n            mask = PhMoveMaskINT128by8(b);\n\n            if (_BitScanForward(&index, mask))\n            {\n                return (SIZE_T)(p - String) + index / sizeof(WCHAR);\n            }\n\n            p += 16 / sizeof(WCHAR);\n        }\n    }\n    else\n    {\n        return wcslen(String);\n    }\n}\n\n/**\n * Allocates space for and copies a byte string.\n *\n * \\param String The string to duplicate.\n *\n * \\return The new string, which can be freed using PhFree().\n */\n_Use_decl_annotations_\nPSTR PhDuplicateBytesZ(\n    _In_ PCSTR String\n    )\n{\n    PSTR newString;\n    SIZE_T length;\n\n    length = strlen(String) + sizeof(ANSI_NULL); // include the null terminator\n\n    newString = PhAllocate(length);\n    memcpy(newString, String, length);\n\n    return newString;\n}\n\n/**\n * Allocates space for and copies a byte string.\n *\n * \\param String The string to duplicate.\n *\n * \\return The new string, which can be freed using PhFree(), or NULL if storage could not be\n * allocated.\n */\n_Use_decl_annotations_\nPSTR PhDuplicateBytesZSafe(\n    _In_ PCSTR String\n    )\n{\n    PSTR newString;\n    SIZE_T length;\n\n    length = strlen(String) + sizeof(ANSI_NULL); // include the null terminator\n\n    newString = PhAllocateSafe(length);\n\n    if (!newString)\n        return NULL;\n\n    memcpy(newString, String, length);\n\n    return newString;\n}\n\n/**\n * Allocates space for and copies a 16-bit string.\n *\n * \\param String The string to duplicate.\n *\n * \\return The new string, which can be freed using PhFree().\n */\n_Use_decl_annotations_\nPWSTR PhDuplicateStringZ(\n    _In_ PCWSTR String\n    )\n{\n    PWSTR newString;\n    SIZE_T length;\n\n    length = PhCountStringZ(String) * sizeof(WCHAR) + sizeof(UNICODE_NULL); // include the null terminator\n\n    newString = PhAllocate(length);\n    memcpy(newString, String, length);\n\n    return newString;\n}\n\n/**\n * Copies a string with optional null termination and a maximum number of characters.\n *\n * \\param InputBuffer A pointer to the input string.\n * \\param InputCount The maximum number of characters to copy, not including the null terminator.\n * Specify -1 for no limit.\n * \\param OutputBuffer A pointer to the output buffer.\n * \\param OutputCount The number of characters in the output buffer, including the null terminator.\n * \\param ReturnCount A variable which receives the number of characters required to contain the\n * input string, including the null terminator. If the function returns TRUE, this variable contains\n * the number of characters written to the output buffer.\n * \\return TRUE if the input string was copied to the output string, otherwise FALSE.\n * \\remarks The function stops copying when it encounters the first null character in the input\n * string. It will also stop copying when it reaches the character count specified in \\a InputCount,\n * if \\a InputCount is not -1.\n */\nNTSTATUS PhCopyBytesZ(\n    _In_ PCSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    )\n{\n    NTSTATUS status;\n    SIZE_T i;\n\n    // Determine the length of the input string.\n\n    if (InputCount != SIZE_MAX)\n    {\n        i = 0;\n\n        while (i < InputCount && InputBuffer[i])\n            i++;\n    }\n    else\n    {\n        i = strlen(InputBuffer);\n    }\n\n    // Copy the string if there is enough room.\n\n    if (OutputBuffer && OutputCount >= i + sizeof(ANSI_NULL)) // need one character for null terminator\n    {\n        memcpy(OutputBuffer, InputBuffer, i);\n        OutputBuffer[i] = ANSI_NULL;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n    }\n\n    if (ReturnCount)\n    {\n        *ReturnCount = i + sizeof(ANSI_NULL);\n    }\n\n    return status;\n}\n\n/**\n * Copies a string with optional null termination and a maximum number of characters.\n *\n * \\param InputBuffer A pointer to the input string.\n * \\param InputCount The maximum number of characters to copy, not including the null terminator.\n * Specify -1 for no limit.\n * \\param OutputBuffer A pointer to the output buffer.\n * \\param OutputCount The number of characters in the output buffer, including the null terminator.\n * \\param ReturnCount A variable which receives the number of characters required to contain the\n * input string, including the null terminator. If the function returns TRUE, this variable contains\n * the number of characters written to the output buffer.\n * \\return TRUE if the input string was copied to the output string, otherwise FALSE.\n * \\remarks The function stops copying when it encounters the first null character in the input\n * string. It will also stop copying when it reaches the character count specified in \\a InputCount,\n * if \\a InputCount is not -1.\n */\nNTSTATUS PhCopyStringZ(\n    _In_ PCWSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    )\n{\n    NTSTATUS status;\n    SIZE_T i;\n\n    // Determine the length of the input string.\n\n    if (InputCount != SIZE_MAX)\n    {\n        i = 0;\n\n        while (i < InputCount && InputBuffer[i])\n            i++;\n    }\n    else\n    {\n        i = PhCountStringZ(InputBuffer);\n    }\n\n    // Copy the string if there is enough room.\n\n    if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator\n    {\n        memcpy(OutputBuffer, InputBuffer, i * sizeof(WCHAR));\n        OutputBuffer[i] = UNICODE_NULL;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n    }\n\n    if (ReturnCount)\n    {\n        *ReturnCount = i + 1;\n    }\n\n    return status;\n}\n\n/**\n * Copies a string with optional null termination and a maximum number of characters.\n *\n * \\param InputBuffer A pointer to the input string.\n * \\param InputCount The maximum number of characters to copy, not including the null terminator.\n * Specify -1 for no limit.\n * \\param OutputBuffer A pointer to the output buffer.\n * \\param OutputCount The number of characters in the output buffer, including the null terminator.\n * \\param ReturnCount A variable which receives the number of characters required to contain the\n * input string, including the null terminator. If the function returns TRUE, this variable contains\n * the number of characters written to the output buffer.\n * \\return TRUE if the input string was copied to the output string, otherwise FALSE.\n * \\remarks The function stops copying when it encounters the first null character in the input\n * string. It will also stop copying when it reaches the character count specified in \\a InputCount,\n * if \\a InputCount is not -1.\n */\nNTSTATUS PhCopyStringZFromBytes(\n    _In_ PCSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    )\n{\n    NTSTATUS status;\n    SIZE_T i;\n\n    // Determine the length of the input string.\n\n    if (InputCount != SIZE_MAX)\n    {\n        i = 0;\n\n        while (i < InputCount && InputBuffer[i])\n            i++;\n    }\n    else\n    {\n        i = strlen(InputBuffer);\n    }\n\n    // Copy the string if there is enough room.\n\n    if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator\n    {\n        PhZeroExtendToUtf16Buffer(InputBuffer, i, OutputBuffer);\n        OutputBuffer[i] = UNICODE_NULL;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n    }\n\n    if (ReturnCount)\n    {\n        *ReturnCount = i + 1;\n    }\n\n    return status;\n}\n\n/**\n * Copies a string with optional null termination and a maximum number of characters.\n *\n * \\param InputBuffer A pointer to the input string.\n * \\param InputCount The maximum number of characters to copy, not including the null terminator.\n * Specify -1 for no limit.\n * \\param OutputBuffer A pointer to the output buffer.\n * \\param OutputCount The number of characters in the output buffer, including the null terminator.\n * \\param ReturnCount A variable which receives the number of characters required to contain the\n * input string, including the null terminator. If the function returns TRUE, this variable contains\n * the number of characters written to the output buffer.\n * \\return TRUE if the input string was copied to the output string, otherwise FALSE.\n * \\remarks The function stops copying when it encounters the first null character in the input\n * string. It will also stop copying when it reaches the character count specified in \\a InputCount,\n * if \\a InputCount is not -1.\n */\nNTSTATUS PhCopyStringZFromMultiByte(\n    _In_ PCSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    )\n{\n    NTSTATUS status;\n    SIZE_T i;\n    ULONG inputBytes;\n    ULONG unicodeBytes;\n\n    // Determine the length of the input string.\n\n    if (InputCount != SIZE_MAX)\n    {\n        i = 0;\n\n        while (i < InputCount && InputBuffer[i])\n            i++;\n    }\n    else\n    {\n        i = strlen(InputBuffer);\n    }\n\n    status = RtlSizeTToULong(i, &inputBytes);\n\n    if (!NT_SUCCESS(status))\n    {\n        if (ReturnCount)\n            *ReturnCount = SIZE_MAX;\n\n        return status;\n    }\n\n    // Determine the length of the output string.\n\n    status = RtlMultiByteToUnicodeSize(\n        &unicodeBytes,\n        InputBuffer,\n        inputBytes\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        if (ReturnCount)\n            *ReturnCount = SIZE_MAX;\n\n        return status;\n    }\n\n    // Convert the string to Unicode if there is enough room.\n\n    if (OutputBuffer && OutputCount >= (unicodeBytes + sizeof(UNICODE_NULL)) / sizeof(WCHAR))\n    {\n        status = RtlMultiByteToUnicodeN(\n            OutputBuffer,\n            unicodeBytes,\n            NULL,\n            InputBuffer,\n            inputBytes\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // RtlMultiByteToUnicodeN doesn't null terminate the string.\n            *(PWCHAR)PTR_ADD_OFFSET(OutputBuffer, unicodeBytes) = UNICODE_NULL;\n        }\n    }\n    else\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n    }\n\n    if (ReturnCount)\n    {\n        *ReturnCount = (unicodeBytes + sizeof(UNICODE_NULL)) / sizeof(WCHAR);\n    }\n\n    return status;\n}\n\n/**\n * Copies a UTF-8 encoded string to a wide-character (UTF-16) string buffer.\n *\n * \\param InputBuffer Pointer to the input UTF-8 string buffer.\n * \\param InputCount Size, in bytes, of the input buffer.\n * \\param OutputBuffer Pointer to the output wide-character string buffer. Can be NULL if OutputCount is 0.\n * \\param OutputCount Size, in characters, of the output buffer.\n * \\param ReturnCount Optional pointer to receive the number of characters written to the output buffer (excluding the null terminator).\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The output buffer will be null-terminated if OutputCount is greater than zero.\n */\nNTSTATUS PhCopyStringZFromUtf8(\n    _In_ PCSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    )\n{\n    NTSTATUS status;\n    SIZE_T i;\n    ULONG inputBytes;\n    ULONG unicodeBytes;\n\n    // Determine the length of the input string.\n\n    if (InputCount != SIZE_MAX)\n    {\n        i = 0;\n\n        while (i < InputCount && InputBuffer[i])\n            i++;\n    }\n    else\n    {\n        i = strlen(InputBuffer);\n    }\n\n    status = RtlSizeTToULong(i, &inputBytes);\n\n    if (!NT_SUCCESS(status))\n    {\n        if (ReturnCount)\n            *ReturnCount = SIZE_MAX;\n\n        return status;\n    }\n\n    // Determine the length of the output string.\n\n    status = RtlUTF8ToUnicodeN(\n        NULL,\n        0,\n        &unicodeBytes,\n        InputBuffer,\n        inputBytes\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        if (ReturnCount)\n            *ReturnCount = SIZE_MAX;\n\n        return status;\n    }\n\n    // Convert the string to Unicode if there is enough room.\n\n    if (OutputBuffer && OutputCount >= (unicodeBytes + sizeof(UNICODE_NULL)) / sizeof(WCHAR))\n    {\n        status = RtlUTF8ToUnicodeN(\n            OutputBuffer,\n            unicodeBytes,\n            NULL,\n            InputBuffer,\n            inputBytes\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // RtlUTF8ToUnicodeN doesn't null terminate the string.\n            *(PWCHAR)PTR_ADD_OFFSET(OutputBuffer, unicodeBytes) = UNICODE_NULL;\n        }\n    }\n    else\n    {\n        status = STATUS_BUFFER_TOO_SMALL;\n    }\n\n    if (ReturnCount)\n    {\n        *ReturnCount = (unicodeBytes + sizeof(UNICODE_NULL)) / sizeof(WCHAR);\n    }\n\n    return status;\n}\n\nFORCEINLINE LONG PhpCompareRightNatural(\n    _In_ PCWSTR A,\n    _In_ PCWSTR B\n    )\n{\n    LONG bias = 0;\n\n    for (; ; A++, B++)\n    {\n        if (!PhIsDigitCharacter(*A) && !PhIsDigitCharacter(*B))\n        {\n            return bias;\n        }\n        else if (!PhIsDigitCharacter(*A))\n        {\n            return -1;\n        }\n        else if (!PhIsDigitCharacter(*B))\n        {\n            return 1;\n        }\n        else if (*A < *B)\n        {\n            if (bias == 0)\n                bias = -1;\n        }\n        else if (*A > *B)\n        {\n            if (bias == 0)\n                bias = 1;\n        }\n        else if (!*A && !*B)\n        {\n            return bias;\n        }\n    }\n\n    return 0;\n}\n\nFORCEINLINE LONG PhpCompareLeftNatural(\n    _In_ PCWSTR A,\n    _In_ PCWSTR B\n    )\n{\n    for (; ; A++, B++)\n    {\n        if (!PhIsDigitCharacter(*A) && !PhIsDigitCharacter(*B))\n        {\n            return 0;\n        }\n        else if (!PhIsDigitCharacter(*A))\n        {\n            return -1;\n        }\n        else if (!PhIsDigitCharacter(*B))\n        {\n            return 1;\n        }\n        else if (*A < *B)\n        {\n            return -1;\n        }\n        else if (*A > *B)\n        {\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\nFORCEINLINE LONG PhpCompareStringZNatural(\n    _In_ PCWSTR A,\n    _In_ PCWSTR B,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    /*  strnatcmp.c -- Perform 'natural order' comparisons of strings in C.\n        Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>\n\n        This software is provided 'as-is', without any express or implied\n        warranty.  In no event will the authors be held liable for any damages\n        arising from the use of this software.\n\n        Permission is granted to anyone to use this software for any purpose,\n        including commercial applications, and to alter it and redistribute it\n        freely, subject to the following restrictions:\n\n        1. The origin of this software must not be misrepresented; you must not\n         claim that you wrote the original software. If you use this software\n         in a product, an acknowledgment in the product documentation would be\n         appreciated but is not required.\n        2. Altered source versions must be plainly marked as such, and must not be\n         misrepresented as being the original software.\n        3. This notice may not be removed or altered from any source distribution.\n\n        This code has been modified for System Informer.\n     */\n\n    ULONG ai, bi;\n    WCHAR ca, cb;\n    LONG result;\n    BOOLEAN fractional;\n\n    ai = 0;\n    bi = 0;\n\n    while (TRUE)\n    {\n        ca = A[ai];\n        cb = B[bi];\n\n        /* Skip over leading spaces. */\n\n        while (ca == ' ')\n            ca = A[++ai];\n\n        while (cb == ' ')\n            cb = B[++bi];\n\n        /* Process run of digits. */\n        if (PhIsDigitCharacter(ca) && PhIsDigitCharacter(cb))\n        {\n            fractional = (ca == '0' || cb == '0');\n\n            if (fractional)\n            {\n                if ((result = PhpCompareLeftNatural(A + ai, B + bi)) != 0)\n                    return result;\n            }\n            else\n            {\n                if ((result = PhpCompareRightNatural(A + ai, B + bi)) != 0)\n                    return result;\n            }\n\n            while (PhIsDigitCharacter(A[ai]))\n                ai++;\n            while (PhIsDigitCharacter(B[bi]))\n                bi++;\n\n            continue;\n        }\n\n        if (!ca && !cb)\n        {\n            /* Strings are considered the same. */\n            return 0;\n        }\n\n        if (IgnoreCase)\n        {\n            ca = PhUpcaseUnicodeChar(ca);\n            cb = PhUpcaseUnicodeChar(cb);\n        }\n\n        if (ca < cb)\n            return -1;\n        else if (ca > cb)\n            return 1;\n\n        ai++;\n        bi++;\n    }\n}\n\n/**\n * Compares two strings in natural sort order.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase TRUE to perform a case-insensitive comparison, otherwise FALSE.\n * \\return A value less than zero if \\a String1 is less than \\a String2, a value greater than zero if\n * \\a String1 is greater than \\a String2, or zero if the strings are equal.\n */\nLONG PhCompareStringZNatural(\n    _In_ PCWSTR String1,\n    _In_ PCWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    return PhpCompareStringZNatural(String1, String2, IgnoreCase);\n}\n\n/**\n * Compares two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase TRUE to perform a case-insensitive comparison, otherwise FALSE.\n * \\return A value less than zero if \\a String1 is less than \\a String2, a value greater than zero if\n * \\a String1 is greater than \\a String2, or zero if the strings are equal.\n */\nLONG PhCompareStringRef(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    SIZE_T l1;\n    SIZE_T l2;\n    PWCHAR s1;\n    PWCHAR s2;\n    WCHAR c1;\n    WCHAR c2;\n    PWCHAR end;\n\n    // Note: this function assumes that the difference between the lengths of the two strings can\n    // fit inside a LONG.\n\n    l1 = String1->Length;\n    l2 = String2->Length;\n    assert(!(l1 & 1));\n    assert(!(l2 & 1));\n    s1 = String1->Buffer;\n    s2 = String2->Buffer;\n\n    if (PhHasIntrinsics)\n    {\n        SIZE_T commonLength = l1 <= l2 ? l1 : l2;\n\n#ifndef _ARM64_\n        if (PhHasAVX)\n        {\n            SIZE_T length = commonLength / 32;\n\n            if (length != 0)\n            {\n                if (IgnoreCase)\n                {\n                    do\n                    {\n                        __m256i b1 = _mm256_loadu_si256((__m256i const*)s1);\n                        __m256i b2 = _mm256_loadu_si256((__m256i const*)s2);\n\n                        // SIMD uppercase conversion\n                        __m256i ub1 = PhUppercaseLatin1INT256by16(b1);\n                        __m256i ub2 = PhUppercaseLatin1INT256by16(b2);\n\n                        // Compare uppercased values\n                        __m256i cmp = _mm256_cmpeq_epi16(ub1, ub2);\n                        if ((ULONG)_mm256_movemask_epi8(cmp) != 0xffffffff)\n                        {\n                            _mm256_zeroupper();\n                            goto CompareCharacters;\n                        }\n\n                        s1 += 32 / sizeof(WCHAR);\n                        s2 += 32 / sizeof(WCHAR);\n                    } while (--length != 0);\n\n                    _mm256_zeroupper();\n                }\n                else\n                {\n                    do\n                    {\n                        __m256i b1 = _mm256_loadu_si256((__m256i const*)s1);\n                        __m256i b2 = _mm256_loadu_si256((__m256i const*)s2);\n                        __m256i cmp = _mm256_cmpeq_epi16(b1, b2);\n\n                        if ((ULONG)_mm256_movemask_epi8(cmp) != 0xffffffff)\n                        {\n                            _mm256_zeroupper();\n                            goto CompareCharacters;\n                        }\n\n                        s1 += 32 / sizeof(WCHAR);\n                        s2 += 32 / sizeof(WCHAR);\n                    } while (--length != 0);\n\n                    _mm256_zeroupper();\n                }\n            }\n        }\n        else\n#endif\n        if (IgnoreCase)\n        {\n            SIZE_T length = commonLength / 16;\n\n            if (length != 0)\n            {\n                do\n                {\n                    PH_INT128 b1 = PhLoadINT128U((PLONG)s1);\n                    PH_INT128 b2 = PhLoadINT128U((PLONG)s2);\n\n                    // SIMD uppercase conversion\n                    PH_INT128 ub1 = PhUppercaseLatin1INT128by16(b1);\n                    PH_INT128 ub2 = PhUppercaseLatin1INT128by16(b2);\n\n                    // Compare uppercased values\n                    PH_INT128 cmp = PhCompareEqINT128by16(ub1, ub2);\n                    if (PhMoveMaskINT128by8(cmp) != 0xffff)\n                    {\n                        goto CompareCharacters;\n                    }\n\n                    s1 += 16 / sizeof(WCHAR);\n                    s2 += 16 / sizeof(WCHAR);\n                } while (--length != 0);\n            }\n        }\n        else\n        {\n            SIZE_T length = commonLength / 16;\n\n            if (length != 0)\n            {\n                do\n                {\n                    PH_INT128 b1 = PhLoadINT128U((PLONG)s1);\n                    PH_INT128 b2 = PhLoadINT128U((PLONG)s2);\n                    PH_INT128 cmp = PhCompareEqINT128by16(b1, b2);\n\n                    if (PhMoveMaskINT128by8(cmp) != 0xffff)\n                    {\n                        goto CompareCharacters;\n                    }\n\n                    s1 += 16 / sizeof(WCHAR);\n                    s2 += 16 / sizeof(WCHAR);\n                } while (--length != 0);\n            }\n        }\n    }\n\nCompareCharacters:\n    end = PTR_ADD_OFFSET(String1->Buffer, l1 <= l2 ? l1 : l2);\n\n    if (IgnoreCase)\n    {\n        while (s1 != end)\n        {\n            c1 = *s1;\n            c2 = *s2;\n\n            if (c1 != c2)\n            {\n                c1 = PhUpcaseUnicodeChar(c1);\n                c2 = PhUpcaseUnicodeChar(c2);\n\n                if (c1 != c2)\n                    return (LONG)c1 - (LONG)c2;\n            }\n\n            s1++;\n            s2++;\n        }\n    }\n    else\n    {\n        while (s1 != end)\n        {\n            c1 = *s1;\n            c2 = *s2;\n\n            if (c1 != c2)\n                return (LONG)c1 - (LONG)c2;\n\n            s1++;\n            s2++;\n        }\n    }\n\n    return (LONG)(l1 - l2);\n}\n\n/**\n * Determines if two strings are equal.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase TRUE to perform a case-insensitive comparison, otherwise FALSE.\n * \\return TRUE if the strings are equal, otherwise FALSE\n */\nBOOLEAN PhEqualStringRef(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    SIZE_T l1;\n    SIZE_T l2;\n    PWSTR s1;\n    PWSTR s2;\n    WCHAR c1;\n    WCHAR c2;\n    SIZE_T length;\n\n    l1 = String1->Length;\n    l2 = String2->Length;\n    assert(!(l1 & 1));\n    assert(!(l2 & 1));\n\n    if (l1 != l2)\n        return FALSE;\n\n    s1 = String1->Buffer;\n    s2 = String2->Buffer;\n\n    if (PhHasIntrinsics)\n    {\n#ifndef _ARM64_\n        if (PhHasAVX)\n        {\n            if (IgnoreCase)\n            {\n                length = l1 / 32;\n\n                if (length != 0)\n                {\n                    do\n                    {\n                        __m256i b1 = _mm256_loadu_si256((__m256i const*)s1);\n                        __m256i b2 = _mm256_loadu_si256((__m256i const*)s2);\n\n                        // SIMD uppercase conversion\n                        b1 = PhUppercaseLatin1INT256by16(b1);\n                        b2 = PhUppercaseLatin1INT256by16(b2);\n\n                        // Compare uppercased values\n                        __m256i cmp = _mm256_cmpeq_epi16(b1, b2);\n                        if ((ULONG)_mm256_movemask_epi8(cmp) != 0xffffffff)\n                        {\n                            _mm256_zeroupper();\n                            l1 = (String1->Length / sizeof(WCHAR)) - (s1 - String1->Buffer);\n                            goto CompareCharacters;\n                        }\n\n                        s1 += 32 / sizeof(WCHAR);\n                        s2 += 32 / sizeof(WCHAR);\n                    } while (--length != 0);\n\n                    _mm256_zeroupper();\n                }\n\n                l1 = (l1 & 31) / sizeof(WCHAR);\n            }\n            else\n            {\n                length = l1 / 32;\n\n                if (length != 0)\n                {\n                    do\n                    {\n                        __m256i b1 = _mm256_loadu_si256((__m256i const*)s1);\n                        __m256i b2 = _mm256_loadu_si256((__m256i const*)s2);\n                        __m256i cmp = _mm256_cmpeq_epi16(b1, b2);\n\n                        if ((ULONG)_mm256_movemask_epi8(cmp) != 0xffffffff)\n                        {\n                            _mm256_zeroupper();\n                            return FALSE;\n                        }\n\n                        s1 += 32 / sizeof(WCHAR);\n                        s2 += 32 / sizeof(WCHAR);\n                    } while (--length != 0);\n\n                    _mm256_zeroupper();\n                }\n\n                l1 = (l1 & 31) / sizeof(WCHAR);\n            }\n        }\n        else\n#endif\n        if (IgnoreCase)\n        {\n            length = l1 / 16;\n\n            if (length != 0)\n            {\n                do\n                {\n                    PH_INT128 b1 = PhLoadINT128U((PLONG)s1);\n                    PH_INT128 b2 = PhLoadINT128U((PLONG)s2);\n\n                    // SIMD uppercase conversion\n                    b1 = PhUppercaseLatin1INT128by16(b1);\n                    b2 = PhUppercaseLatin1INT128by16(b2);\n\n                    // Compare uppercased values\n                    PH_INT128 cmp = PhCompareEqINT128by16(b1, b2);\n                    if (PhMoveMaskINT128by8(cmp) != 0xffff)\n                    {\n                        // Mismatch - fall back to scalar\n                        l1 = (String1->Length / sizeof(WCHAR)) - (s1 - String1->Buffer);\n                        goto CompareCharacters;\n                    }\n\n                    s1 += 16 / sizeof(WCHAR);\n                    s2 += 16 / sizeof(WCHAR);\n                } while (--length != 0);\n            }\n\n            // Compare character-by-character because we have no more 16-byte blocks to compare.\n            l1 = (l1 & 15) / sizeof(WCHAR);\n        }\n        else\n        {\n            length = l1 / 16;\n\n            if (length != 0)\n            {\n                PH_INT128 b1;\n                PH_INT128 b2;\n\n                do\n                {\n                    b1 = PhLoadINT128U((PLONG)s1);\n                    b2 = PhLoadINT128U((PLONG)s2);\n                    b1 = PhCompareEqINT128by32(b1, b2);\n\n                    if (PhMoveMaskINT128by8(b1) != 0xffff)\n                    {\n                        l1 = (String1->Length / sizeof(WCHAR)) - (s1 - String1->Buffer);\n                        goto CompareCharacters;\n                    }\n\n                    s1 += 16 / sizeof(WCHAR);\n                    s2 += 16 / sizeof(WCHAR);\n                } while (--length != 0);\n            }\n\n            // Compare character-by-character because we have no more 16-byte blocks to compare.\n            l1 = (l1 & 15) / sizeof(WCHAR);\n        }\n    }\n    else\n    {\n        length = l1 / sizeof(ULONG_PTR);\n\n        if (length != 0)\n        {\n            do\n            {\n                if (*(PULONG_PTR)s1 != *(PULONG_PTR)s2)\n                {\n                    l1 = (String1->Length / sizeof(WCHAR)) - (s1 - String1->Buffer);\n                    goto CompareCharacters;\n                }\n\n                s1 += sizeof(ULONG_PTR) / sizeof(WCHAR);\n                s2 += sizeof(ULONG_PTR) / sizeof(WCHAR);\n            } while (--length != 0);\n        }\n\n        // Compare character-by-character because we have no more ULONG_PTR blocks to compare.\n        l1 = (l1 & (sizeof(ULONG_PTR) - 1)) / sizeof(WCHAR);\n    }\n\nCompareCharacters:\n    if (l1 != 0)\n    {\n        if (IgnoreCase)\n        {\n            do\n            {\n                c1 = *s1;\n                c2 = *s2;\n\n                if (c1 != c2)\n                {\n                    c1 = PhUpcaseUnicodeChar(c1);\n                    c2 = PhUpcaseUnicodeChar(c2);\n\n                    if (c1 != c2)\n                        return FALSE;\n                }\n\n                s1++;\n                s2++;\n            } while (--l1 != 0);\n        }\n        else\n        {\n            do\n            {\n                c1 = *s1;\n                c2 = *s2;\n\n                if (c1 != c2)\n                    return FALSE;\n\n                s1++;\n                s2++;\n            } while (--l1 != 0);\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Locates a character in a string.\n *\n * \\param String The string to search.\n * \\param Character The character to search for.\n * \\param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE.\n * \\return The index, in characters, of the first occurrence of \\a Character in \\a String1. If\n * \\a Character was not found, -1 is returned.\n */\nULONG_PTR PhFindCharInStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ WCHAR Character,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PWSTR buffer;\n    SIZE_T length;\n\n    buffer = String->Buffer;\n    length = String->Length / sizeof(WCHAR);\n\n    if (IgnoreCase)\n    {\n        if (Character <= 0xFF && Character != 0x00DF)\n        {\n#ifndef _ARM64_\n            if (PhHasAVX)\n            {\n                SIZE_T length32;\n\n                length32 = String->Length / 32;\n                length &= 15;\n\n                if (length32 != 0)\n                {\n                    __m256i pattern;\n                    __m256i block;\n                    ULONG mask;\n                    ULONG index;\n                    WCHAR upC = PhUpcaseUnicodeChar(Character);\n\n                    pattern = _mm256_set1_epi16(upC);\n\n                    do\n                    {\n                        block = _mm256_loadu_si256((__m256i*)buffer);\n                        block = PhUppercaseLatin1INT256by16(block);\n                        block = _mm256_cmpeq_epi16(block, pattern);\n                        mask = _mm256_movemask_epi8(block);\n\n                        if (mask != 0)\n                        {\n                            if (_BitScanForward(&index, mask))\n                            {\n                                _mm256_zeroupper();\n                                return (buffer - String->Buffer) + index / 2;\n                            }\n                        }\n\n                        buffer += 16;\n                    } while (--length32 != 0);\n\n                    _mm256_zeroupper();\n                }\n            }\n            else\n#endif\n            if (PhHasIntrinsics)\n            {\n                SIZE_T length16;\n\n                length16 = String->Length / 16;\n                length &= 7;\n\n                if (length16 != 0)\n                {\n                    PH_INT128 pattern;\n                    PH_INT128 block;\n                    ULONG mask;\n                    ULONG index;\n                    WCHAR upC = PhUpcaseUnicodeChar(Character);\n\n                    pattern = PhSetINT128by16(upC);\n\n                    do\n                    {\n                        block = PhLoadINT128U((PLONG)buffer);\n                        block = PhUppercaseLatin1INT128by16(block);\n                        block = PhCompareEqINT128by16(block, pattern);\n                        mask = PhMoveMaskINT128by8(block);\n\n                        if (_BitScanForward(&index, mask))\n                        {\n                            return (buffer - String->Buffer) + index / 2;\n                        }\n\n                        buffer += 8;\n                    } while (--length16 != 0);\n                }\n            }\n        }\n        else\n        {\n            WCHAR upC = PhUpcaseUnicodeChar(Character);\n            WCHAR lowC = PhDowncaseUnicodeChar(Character);\n\n            if (upC == lowC)\n            {\n                // Not a casing character, use standard path.\n                return PhFindCharInStringRef(String, Character, FALSE);\n            }\n\n#ifndef _ARM64_\n            if (PhHasAVX)\n            {\n                SIZE_T length32;\n\n                length32 = String->Length / 32;\n                length &= 15;\n\n                if (length32 != 0)\n                {\n                    __m256i patUp;\n                    __m256i patLow;\n                    __m256i block;\n                    ULONG mask;\n                    ULONG index;\n\n                    patUp = _mm256_set1_epi16(upC);\n                    patLow = _mm256_set1_epi16(lowC);\n\n                    do\n                    {\n                        block = _mm256_loadu_si256((__m256i*)buffer);\n                        block = _mm256_or_si256(_mm256_cmpeq_epi16(block, patUp), _mm256_cmpeq_epi16(block, patLow));\n                        mask = _mm256_movemask_epi8(block);\n\n                        if (mask != 0)\n                        {\n                            if (_BitScanForward(&index, mask))\n                            {\n                                _mm256_zeroupper();\n                                return (buffer - String->Buffer) + index / 2;\n                            }\n                        }\n\n                        buffer += 16;\n                    } while (--length32 != 0);\n\n                    _mm256_zeroupper();\n                }\n            }\n            else\n#endif\n            if (PhHasIntrinsics)\n            {\n                SIZE_T length16;\n\n                length16 = String->Length / 16;\n                length &= 7;\n\n                if (length16 != 0)\n                {\n                    PH_INT128 patUp;\n                    PH_INT128 patLow;\n                    PH_INT128 block;\n                    ULONG mask;\n                    ULONG index;\n\n                    patUp = PhSetINT128by16(upC);\n                    patLow = PhSetINT128by16(lowC);\n\n                    do\n                    {\n                        block = PhLoadINT128U((PLONG)buffer);\n                        block = PhOrINT128(PhCompareEqINT128by16(block, patUp), PhCompareEqINT128by16(block, patLow));\n                        mask = PhMoveMaskINT128by8(block);\n\n                        if (_BitScanForward(&index, mask))\n                        {\n                            return (buffer - String->Buffer) + index / 2;\n                        }\n\n                        buffer += 8;\n                    } while (--length16 != 0);\n                }\n            }\n        }\n\n        if (length != 0)\n        {\n            WCHAR c;\n\n            c = PhUpcaseUnicodeChar(Character);\n\n            do\n            {\n                if (PhUpcaseUnicodeChar(*buffer) == c)\n                {\n                    return (ULONG_PTR)(buffer - String->Buffer);\n                }\n\n                buffer++;\n            } while (--length != 0);\n        }\n    }\n    else\n    {\n#ifndef _ARM64_\n        if (PhHasAVX)\n        {\n            SIZE_T length32;\n\n            length32 = String->Length / 32;\n            length &= 15;\n\n            if (length32 != 0)\n            {\n                __m256i pattern;\n                __m256i block;\n                ULONG mask;\n                ULONG index;\n\n                pattern = _mm256_set1_epi16(Character);\n\n                do\n                {\n                    block = _mm256_loadu_si256((__m256i*)buffer);\n                    block = _mm256_cmpeq_epi16(block, pattern);\n                    mask = _mm256_movemask_epi8(block);\n\n                    if (_BitScanForward(&index, mask))\n                    {\n                        _mm256_zeroupper();\n                        return (buffer - String->Buffer) + index / 2;\n                    }\n\n                    buffer += 16;\n                } while (--length32 != 0);\n\n                _mm256_zeroupper();\n            }\n        }\n        else\n#endif\n        if (PhHasIntrinsics)\n        {\n            SIZE_T length16;\n\n            length16 = String->Length / 16;\n            length &= 7;\n\n            if (length16 != 0)\n            {\n                PH_INT128 pattern;\n                PH_INT128 block;\n                ULONG mask;\n                ULONG index;\n\n                pattern = PhSetINT128by16(Character);\n\n                do\n                {\n                    block = PhLoadINT128U((PLONG)buffer);\n                    block = PhCompareEqINT128by16(block, pattern);\n                    mask = PhMoveMaskINT128by8(block);\n\n                    if (_BitScanForward(&index, mask))\n                    {\n                        return (buffer - String->Buffer) + index / 2;\n                    }\n\n                    buffer += 16 / sizeof(WCHAR);\n                } while (--length16 != 0);\n            }\n        }\n\n        if (length != 0)\n        {\n            do\n            {\n                if (*buffer == Character)\n                    return (ULONG_PTR)(buffer - String->Buffer);\n\n                buffer++;\n            } while (--length != 0);\n        }\n    }\n\n    return SIZE_MAX;\n}\n\n/**\n * Locates a character in a string, searching backwards.\n *\n * \\param String The string to search.\n * \\param Character The character to search for.\n * \\param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE.\n * \\return The index, in characters, of the last occurrence of \\a Character in \\a String1. If\n * \\a Character was not found, -1 is returned.\n */\nULONG_PTR PhFindLastCharInStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ WCHAR Character,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PWCHAR buffer;\n    SIZE_T length;\n\n    buffer = PTR_ADD_OFFSET(String->Buffer, String->Length);\n    length = String->Length / sizeof(WCHAR);\n\n    if (IgnoreCase)\n    {\n        if (Character <= 0xFF && Character != 0x00DF)\n        {\n#ifndef _ARM64_\n            if (PhHasAVX)\n            {\n                SIZE_T length32;\n\n                length32 = String->Length / 32;\n                length &= 15;\n\n                if (length32 != 0)\n                {\n                    __m256i pattern;\n                    __m256i block;\n                    ULONG mask;\n                    ULONG index;\n                    WCHAR upC = PhUpcaseUnicodeChar(Character);\n\n                    pattern = _mm256_set1_epi16(upC);\n\n                    do\n                    {\n                        buffer -= 16;\n                        block = _mm256_loadu_si256((__m256i*)buffer);\n                        block = PhUppercaseLatin1INT256by16(block);\n                        block = _mm256_cmpeq_epi16(block, pattern);\n                        mask = _mm256_movemask_epi8(block);\n\n                        if (mask != 0)\n                        {\n                            if (_BitScanReverse(&index, mask))\n                            {\n                                _mm256_zeroupper();\n                                return (buffer - String->Buffer) + index / 2;\n                            }\n                        }\n                    } while (--length32 != 0);\n\n                    _mm256_zeroupper();\n                }\n            }\n            else\n#endif\n            if (PhHasIntrinsics)\n            {\n                SIZE_T length16;\n\n                length16 = String->Length / 16;\n                length &= 7;\n\n                if (length16 != 0)\n                {\n                    PH_INT128 pattern;\n                    PH_INT128 block;\n                    ULONG mask;\n                    ULONG index;\n                    WCHAR upC = PhUpcaseUnicodeChar(Character);\n\n                    pattern = PhSetINT128by16(upC);\n\n                    do\n                    {\n                        buffer -= 8;\n                        block = PhLoadINT128U((PLONG)buffer);\n                        block = PhUppercaseLatin1INT128by16(block);\n                        block = PhCompareEqINT128by16(block, pattern);\n                        mask = PhMoveMaskINT128by8(block);\n\n                        if (mask != 0)\n                        {\n                            if (_BitScanReverse(&index, mask))\n                            {\n                                return (buffer - String->Buffer) + index / 2;\n                            }\n                        }\n                    } while (--length16 != 0);\n                }\n            }\n        }\n        else\n        {\n            WCHAR upC = PhUpcaseUnicodeChar(Character);\n            WCHAR lowC = PhDowncaseUnicodeChar(Character);\n\n            if (upC == lowC)\n            {\n                // Not a casing character, use standard path.\n                return PhFindLastCharInStringRef(String, Character, FALSE);\n            }\n\n#ifndef _ARM64_\n            if (PhHasAVX)\n            {\n                SIZE_T length32;\n\n                length32 = String->Length / 32;\n                length &= 15;\n\n                if (length32 != 0)\n                {\n                    __m256i patUp;\n                    __m256i patLow;\n                    __m256i block;\n                    ULONG mask;\n                    ULONG index;\n\n                    patUp = _mm256_set1_epi16(upC);\n                    patLow = _mm256_set1_epi16(lowC);\n\n                    do\n                    {\n                        buffer -= 16;\n                        block = _mm256_loadu_si256((__m256i*)buffer);\n                        block = _mm256_or_si256(_mm256_cmpeq_epi16(block, patUp), _mm256_cmpeq_epi16(block, patLow));\n                        mask = _mm256_movemask_epi8(block);\n\n                        if (mask != 0)\n                        {\n                            if (_BitScanReverse(&index, mask))\n                            {\n                                _mm256_zeroupper();\n                                return (buffer - String->Buffer) + index / 2;\n                            }\n                        }\n                    } while (--length32 != 0);\n\n                    _mm256_zeroupper();\n                }\n            }\n            else\n#endif\n            if (PhHasIntrinsics)\n            {\n                SIZE_T length16;\n\n                length16 = String->Length / 16;\n                length &= 7;\n\n                if (length16 != 0)\n                {\n                    PH_INT128 patUp;\n                    PH_INT128 patLow;\n                    PH_INT128 block;\n                    ULONG mask;\n                    ULONG index;\n\n                    patUp = PhSetINT128by16(upC);\n                    patLow = PhSetINT128by16(lowC);\n\n                    do\n                    {\n                        buffer -= 8;\n                        block = PhLoadINT128U((PLONG)buffer);\n                        block = PhOrINT128(PhCompareEqINT128by16(block, patUp), PhCompareEqINT128by16(block, patLow));\n                        mask = PhMoveMaskINT128by8(block);\n\n                        if (mask != 0)\n                        {\n                            if (_BitScanReverse(&index, mask))\n                            {\n                                return (buffer - String->Buffer) + index / 2;\n                            }\n                        }\n                    } while (--length16 != 0);\n                }\n            }\n        }\n\n        if (length != 0)\n        {\n            WCHAR c;\n\n            c = PhUpcaseUnicodeChar(Character);\n            buffer--;\n\n            do\n            {\n                if (PhUpcaseUnicodeChar(*buffer) == c)\n                    return (ULONG_PTR)(buffer - String->Buffer);\n\n                buffer--;\n            } while (--length != 0);\n        }\n    }\n    else\n    {\n#ifndef _ARM64_\n        if (PhHasAVX)\n        {\n            SIZE_T length32;\n\n            length32 = String->Length / 32;\n            length &= 15;\n\n            if (length32 != 0)\n            {\n                __m256i pattern;\n                __m256i block;\n                ULONG mask;\n                ULONG index;\n\n                pattern = _mm256_set1_epi16(Character);\n\n                do\n                {\n                    buffer -= 16;\n                    block = _mm256_loadu_si256((__m256i*)buffer);\n                    block = _mm256_cmpeq_epi16(block, pattern);\n                    mask = _mm256_movemask_epi8(block);\n\n                    if (_BitScanReverse(&index, mask))\n                    {\n                        _mm256_zeroupper();\n                        return (buffer - String->Buffer) + index / 2;\n                    }\n                    \n                } while (--length32 != 0);\n\n                _mm256_zeroupper();\n            }\n        }\n        else\n#endif\n        if (PhHasIntrinsics)\n        {\n            SIZE_T length16;\n\n            length16 = String->Length / 16;\n            length &= 7;\n\n            if (length16 != 0)\n            {\n                PH_INT128 pattern;\n                PH_INT128 block;\n                ULONG mask;\n                ULONG index;\n\n                pattern = PhSetINT128by16(Character);\n\n                do\n                {\n                    buffer -= 8;\n                    block = PhLoadINT128U((PLONG)buffer);\n                    block = PhCompareEqINT128by16(block, pattern);\n                    mask = PhMoveMaskINT128by8(block);\n\n                    if (_BitScanReverse(&index, mask))\n                    {\n                        return (buffer - String->Buffer) + index / 2;\n                    }\n                    \n                } while (--length16 != 0);\n            }\n        }\n\n        if (length != 0)\n        {\n            buffer--;\n\n            do\n            {\n                if (*buffer == Character)\n                    return (ULONG_PTR)(buffer - String->Buffer);\n\n                buffer--;\n            } while (--length != 0);\n        }\n    }\n\n    return SIZE_MAX;\n}\n\n/**\n * Locates a string in a string.\n *\n * \\param String The string to search.\n * \\param SubString The string to search for.\n * \\param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE.\n * \\return The index, in characters, of the first occurrence of \\a SubString in \\a String. If\n * \\a SubString was not found, -1 is returned.\n */\nULONG_PTR PhFindStringInStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ PCPH_STRINGREF SubString,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    SIZE_T length1;\n    SIZE_T length2;\n\n    length1 = String->Length / sizeof(WCHAR);\n    length2 = SubString->Length / sizeof(WCHAR);\n\n    // Can't be a substring if it's bigger than the first string.\n    if (length2 > length1)\n        return SIZE_MAX;\n    // We always get a match if the substring is zero-length.\n    if (length2 == 0)\n        return 0;\n\n#if defined(PH_NATIVE_STRING_IN_STRING)\n    {\n        PH_STRINGREF haystackRef;\n        PH_STRINGREF sr1;\n        PH_STRINGREF sr2;\n        WCHAR c;\n        PWSTR haystack;\n        SIZE_T haystackCount;\n\n        if (length2 == 1)\n            return PhFindCharInStringRef(String, SubString->Buffer[0], IgnoreCase);\n\n        haystack = String->Buffer;\n        haystackCount = length1 - length2 + 1;\n\n        sr2.Buffer = SubString->Buffer + 1;\n        sr2.Length = SubString->Length - sizeof(WCHAR);\n        sr1.Length = sr2.Length;\n\n        if (IgnoreCase)\n        {\n            c = PhUpcaseUnicodeChar(SubString->Buffer[0]);\n\n            while (haystackCount > 0)\n            {\n                haystackRef.Buffer = haystack;\n                haystackRef.Length = haystackCount * sizeof(WCHAR);\n\n                ULONG_PTR offset = PhFindCharInStringRef(&haystackRef, c, TRUE);\n                if (offset == SIZE_MAX)\n                    break;\n\n                haystack += offset;\n                haystackCount -= offset;\n\n                sr1.Buffer = haystack + 1;\n                if (PhEqualStringRef(&sr1, &sr2, TRUE))\n                    return (ULONG_PTR)(haystack - String->Buffer);\n\n                haystack++;\n                haystackCount--;\n            }\n        }\n        else\n        {\n            c = SubString->Buffer[0];\n\n            while (haystackCount > 0)\n            {\n                haystackRef.Buffer = haystack;\n                haystackRef.Length = haystackCount * sizeof(WCHAR);\n\n                ULONG_PTR offset = PhFindCharInStringRef(&haystackRef, c, FALSE);\n                if (offset == SIZE_MAX)\n                    break;\n\n                haystack += offset;\n                haystackCount -= offset;\n\n                sr1.Buffer = haystack + 1;\n                if (PhEqualStringRef(&sr1, &sr2, FALSE))\n                    return (ULONG_PTR)(haystack - String->Buffer);\n\n                haystack++;\n                haystackCount--;\n            }\n        }\n    }\n#else\n    {\n        PH_STRINGREF sr1;\n        PH_STRINGREF sr2;\n        WCHAR c;\n        SIZE_T i;\n\n        sr1.Buffer = String->Buffer;\n        sr1.Length = SubString->Length - sizeof(WCHAR);\n        sr2.Buffer = SubString->Buffer;\n        sr2.Length = SubString->Length - sizeof(WCHAR);\n\n        if (IgnoreCase)\n        {\n            c = PhUpcaseUnicodeChar(*sr2.Buffer++);\n\n            for (i = length1 - length2 + 1; i != 0; i--)\n            {\n                if (PhUpcaseUnicodeChar(*sr1.Buffer++) == c && PhEqualStringRef(&sr1, &sr2, TRUE))\n                {\n                    goto FoundUString;\n                }\n            }\n        }\n        else\n        {\n            c = *sr2.Buffer++;\n\n            for (i = length1 - length2 + 1; i != 0; i--)\n            {\n                if (*sr1.Buffer++ == c && PhEqualStringRef(&sr1, &sr2, FALSE))\n                {\n                    goto FoundUString;\n                }\n            }\n        }\n\n        return SIZE_MAX;\nFoundUString:\n        return (ULONG_PTR)(sr1.Buffer - String->Buffer - 1);\n    }\n#endif\n\n    return SIZE_MAX;\n}\n\n/**\n * Splits a string.\n *\n * \\param Input The input string.\n * \\param Separator The character to split at.\n * \\param FirstPart A variable which receives the part of \\a Input before the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * \\a Input.\n * \\param SecondPart A variable which receives the part of \\a Input after the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * an empty string.\n * \\return TRUE if \\a Separator was found in \\a Input, otherwise FALSE.\n */\nBOOLEAN PhSplitStringRefAtChar(\n    _In_ PCPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    )\n{\n    PH_STRINGREF input;\n    ULONG_PTR index;\n\n    input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input\n    index = PhFindCharInStringRef(Input, Separator, FALSE);\n\n    if (index == SIZE_MAX)\n    {\n        // The separator was not found.\n\n        FirstPart->Buffer = Input->Buffer;\n        FirstPart->Length = Input->Length;\n        SecondPart->Buffer = NULL;\n        SecondPart->Length = 0;\n\n        return FALSE;\n    }\n\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = index * sizeof(WCHAR);\n    SecondPart->Buffer = PTR_ADD_OFFSET(input.Buffer, index * sizeof(WCHAR) + sizeof(UNICODE_NULL));\n    SecondPart->Length = input.Length - index * sizeof(WCHAR) - sizeof(UNICODE_NULL);\n\n    return TRUE;\n}\n\n/**\n * Splits a string at the last occurrence of a character.\n *\n * \\param Input The input string.\n * \\param Separator The character to split at.\n * \\param FirstPart A variable which receives the part of \\a Input before the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * \\a Input.\n * \\param SecondPart A variable which receives the part of \\a Input after the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * an empty string.\n * \\return TRUE if \\a Separator was found in \\a Input, otherwise FALSE.\n */\nBOOLEAN PhSplitStringRefAtLastChar(\n    _In_ PCPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    )\n{\n    PH_STRINGREF input;\n    ULONG_PTR index;\n\n    input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input\n    index = PhFindLastCharInStringRef(Input, Separator, FALSE);\n\n    if (index == SIZE_MAX)\n    {\n        // The separator was not found.\n\n        FirstPart->Buffer = Input->Buffer;\n        FirstPart->Length = Input->Length;\n        SecondPart->Buffer = NULL;\n        SecondPart->Length = 0;\n\n        return FALSE;\n    }\n\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = index * sizeof(WCHAR);\n    SecondPart->Buffer = PTR_ADD_OFFSET(input.Buffer, (index + 1) * sizeof(WCHAR));\n    SecondPart->Length = input.Length - (index + 1) * sizeof(WCHAR);\n\n    return TRUE;\n}\n\n/**\n * Splits a string.\n *\n * \\param Input The input string.\n * \\param Separator The string to split at.\n * \\param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE.\n * \\param FirstPart A variable which receives the part of \\a Input before the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * \\a Input.\n * \\param SecondPart A variable which receives the part of \\a Input after the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * an empty string.\n * \\return TRUE if \\a Separator was found in \\a Input, otherwise FALSE.\n */\nBOOLEAN PhSplitStringRefAtString(\n    _In_ PCPH_STRINGREF Input,\n    _In_ PCPH_STRINGREF Separator,\n    _In_ BOOLEAN IgnoreCase,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    )\n{\n    PH_STRINGREF input;\n    ULONG_PTR index;\n\n    input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input\n    index = PhFindStringInStringRef(Input, Separator, IgnoreCase);\n\n    if (index == SIZE_MAX)\n    {\n        // The separator was not found.\n\n        FirstPart->Buffer = Input->Buffer;\n        FirstPart->Length = Input->Length;\n        SecondPart->Buffer = NULL;\n        SecondPart->Length = 0;\n\n        return FALSE;\n    }\n\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = index * sizeof(WCHAR);\n    SecondPart->Buffer = PTR_ADD_OFFSET(input.Buffer, index * sizeof(WCHAR) + Separator->Length);\n    SecondPart->Length = input.Length - index * sizeof(WCHAR) - Separator->Length;\n\n    return TRUE;\n}\n\n/**\n * Splits a string.\n *\n * \\param Input The input string.\n * \\param Separator The character set, string or range to split at.\n * \\param Flags A combination of flags.\n * \\li \\c PH_SPLIT_AT_CHAR_SET \\a Separator specifies a character set. \\a Input will be split at a\n * character which is contained in \\a Separator.\n * \\li \\c PH_SPLIT_AT_STRING \\a Separator specifies a string. \\a Input will be split an occurrence\n * of \\a Separator.\n * \\li \\c PH_SPLIT_AT_RANGE \\a Separator specifies a range. The \\a Buffer field contains a character\n * index cast to \\c PWSTR and the \\a Length field contains the length of the range, in bytes.\n * \\li \\c PH_SPLIT_CASE_INSENSITIVE Specifies a case-insensitive search.\n * \\li \\c PH_SPLIT_COMPLEMENT_CHAR_SET If used with \\c PH_SPLIT_AT_CHAR_SET, the separator is a\n * character which is not contained in \\a Separator.\n * \\li \\c PH_SPLIT_START_AT_END If used with \\c PH_SPLIT_AT_CHAR_SET, the search is performed\n * starting from the end of the string.\n * \\li \\c PH_SPLIT_CHAR_SET_IS_UPPERCASE If used with \\c PH_SPLIT_CASE_INSENSITIVE, specifies that\n * the character set in \\a Separator contains only uppercase characters.\n * \\param FirstPart A variable which receives the part of \\a Input before the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * \\a Input.\n * \\param SecondPart A variable which receives the part of \\a Input after the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * an empty string.\n * \\param SeparatorPart A variable which receives the part of \\a Input that is the separator. If the\n * separator is not found in \\a Input, this variable is set to an empty string.\n * \\return TRUE if a separator was found in \\a Input, otherwise FALSE.\n */\nBOOLEAN PhSplitStringRefEx(\n    _In_ PCPH_STRINGREF Input,\n    _In_ PCPH_STRINGREF Separator,\n    _In_ ULONG Flags,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart,\n    _Out_opt_ PPH_STRINGREF SeparatorPart\n    )\n{\n    PH_STRINGREF input;\n    SIZE_T separatorIndex;\n    SIZE_T separatorLength;\n    PWCHAR charSet;\n    SIZE_T charSetCount;\n    BOOLEAN charSetTable[256];\n    BOOLEAN charSetTableComplete;\n    SIZE_T i;\n    SIZE_T j;\n    USHORT c;\n    PWCHAR s;\n    LONG_PTR direction;\n\n    input = *Input; // Get a copy of the input because FirstPart/SecondPart/SeparatorPart may alias Input\n\n    if (Flags & PH_SPLIT_AT_RANGE)\n    {\n        separatorIndex = (SIZE_T)Separator->Buffer;\n        separatorLength = Separator->Length;\n\n        if (separatorIndex == SIZE_MAX)\n            goto SeparatorNotFound;\n\n        goto SeparatorFound;\n    }\n    else if (Flags & PH_SPLIT_AT_STRING)\n    {\n        if (Flags & PH_SPLIT_START_AT_END)\n        {\n            // not implemented\n            goto SeparatorNotFound;\n        }\n\n        separatorIndex = PhFindStringInStringRef(Input, Separator, !!(Flags & PH_SPLIT_CASE_INSENSITIVE));\n\n        if (separatorIndex == SIZE_MAX)\n            goto SeparatorNotFound;\n\n        separatorLength = Separator->Length;\n        goto SeparatorFound;\n    }\n\n    // Special case for character sets with only one character.\n    if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET) && Separator->Length == sizeof(WCHAR))\n    {\n        if (!(Flags & PH_SPLIT_START_AT_END))\n            separatorIndex = PhFindCharInStringRef(Input, Separator->Buffer[0], !!(Flags & PH_SPLIT_CASE_INSENSITIVE));\n        else\n            separatorIndex = PhFindLastCharInStringRef(Input, Separator->Buffer[0], !!(Flags & PH_SPLIT_CASE_INSENSITIVE));\n\n        if (separatorIndex == SIZE_MAX)\n            goto SeparatorNotFound;\n\n        separatorLength = sizeof(WCHAR);\n        goto SeparatorFound;\n    }\n\n    if (input.Length == 0)\n        goto SeparatorNotFound;\n\n    // Build the character set lookup table.\n\n    charSet = Separator->Buffer;\n    charSetCount = Separator->Length / sizeof(WCHAR);\n    memset(charSetTable, 0, sizeof(charSetTable));\n    charSetTableComplete = TRUE;\n\n    for (i = 0; i < charSetCount; i++)\n    {\n        c = charSet[i];\n\n        if (Flags & PH_SPLIT_CASE_INSENSITIVE)\n            c = PhUpcaseUnicodeChar(c);\n\n        charSetTable[c & 0xff] = TRUE;\n\n        if (c >= 256)\n            charSetTableComplete = FALSE;\n    }\n\n    // Perform the search.\n\n    i = input.Length / sizeof(WCHAR);\n    separatorLength = sizeof(WCHAR);\n\n    if (!(Flags & PH_SPLIT_START_AT_END))\n    {\n        s = input.Buffer;\n        direction = 1;\n    }\n    else\n    {\n        s = PTR_ADD_OFFSET(input.Buffer, input.Length - sizeof(WCHAR));\n        direction = -1;\n    }\n\n    do\n    {\n        c = *s;\n\n        if (Flags & PH_SPLIT_CASE_INSENSITIVE)\n            c = PhUpcaseUnicodeChar(c);\n\n        if (c < 256 && charSetTableComplete)\n        {\n            if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET))\n            {\n                if (charSetTable[c])\n                    goto CharFound;\n            }\n            else\n            {\n                if (!charSetTable[c])\n                    goto CharFound;\n            }\n        }\n        else\n        {\n            if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET))\n            {\n                if (charSetTable[c & 0xff])\n                {\n                    if (!(Flags & PH_SPLIT_CASE_INSENSITIVE) || (Flags & PH_SPLIT_CHAR_SET_IS_UPPERCASE))\n                    {\n                        for (j = 0; j < charSetCount; j++)\n                        {\n                            if (charSet[j] == c)\n                                goto CharFound;\n                        }\n                    }\n                    else\n                    {\n                        for (j = 0; j < charSetCount; j++)\n                        {\n                            if (PhUpcaseUnicodeChar(charSet[j]) == c)\n                                goto CharFound;\n                        }\n                    }\n                }\n            }\n            else\n            {\n                if (charSetTable[c & 0xff])\n                {\n                    if (!(Flags & PH_SPLIT_CASE_INSENSITIVE) || (Flags & PH_SPLIT_CHAR_SET_IS_UPPERCASE))\n                    {\n                        for (j = 0; j < charSetCount; j++)\n                        {\n                            if (charSet[j] == c)\n                                break;\n                        }\n                    }\n                    else\n                    {\n                        for (j = 0; j < charSetCount; j++)\n                        {\n                            if (PhUpcaseUnicodeChar(charSet[j]) == c)\n                                break;\n                        }\n                    }\n\n                    if (j == charSetCount)\n                        goto CharFound;\n                }\n                else\n                {\n                    goto CharFound;\n                }\n            }\n        }\n\n        s += direction;\n    } while (--i != 0);\n\n    goto SeparatorNotFound;\n\nCharFound:\n    separatorIndex = s - input.Buffer;\n\nSeparatorFound:\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = separatorIndex * sizeof(WCHAR);\n    SecondPart->Buffer = PTR_ADD_OFFSET(input.Buffer, separatorIndex * sizeof(WCHAR) + separatorLength);\n    SecondPart->Length = input.Length - separatorIndex * sizeof(WCHAR) - separatorLength;\n\n    if (SeparatorPart)\n    {\n        SeparatorPart->Buffer = input.Buffer + separatorIndex;\n        SeparatorPart->Length = separatorLength;\n    }\n\n    return TRUE;\n\nSeparatorNotFound:\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = input.Length;\n    SecondPart->Buffer = NULL;\n    SecondPart->Length = 0;\n\n    if (SeparatorPart)\n    {\n        SeparatorPart->Buffer = NULL;\n        SeparatorPart->Length = 0;\n    }\n\n    return FALSE;\n}\n\nVOID PhSplitStringRef(\n    _In_ PCPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PVOID **Strings,\n    _Out_ PULONG NumberOfStrings\n    )\n{\n    PH_ARRAY array;\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF part;\n\n    PhInitializeArray(&array, sizeof(PPH_STRING), 4);\n    remainingPart = *Input;\n\n    while (PhSplitStringRefAtChar(&remainingPart, Separator, &part, &remainingPart))\n    {\n        if (part.Length > 0)\n        {\n            PPH_STRING string = PhCreateString2(&part);\n            PhAddItemArray(&array, &string);\n        }\n    }\n\n    if (remainingPart.Length > 0)\n    {\n        PPH_STRING string = PhCreateString2(&remainingPart);\n        PhAddItemArray(&array, &string);\n    }\n\n    *NumberOfStrings = (ULONG)PhFinalArrayCount(&array);\n    *Strings = (PVOID *)PhFinalArrayItems(&array);\n}\n\nVOID PhFreeStringArray(\n    _In_ PVOID *Strings,\n    _In_ ULONG NumberOfStrings\n    )\n{\n    for (ULONG i = 0; i < NumberOfStrings; i++)\n    {\n        PhDereferenceObject(Strings[i]);\n    }\n\n    PhFree(Strings);\n}\n\n/**\n * Trims characters from the beginning and/or end of a string reference.\n *\n * \\param String Pointer to a PH_STRINGREF structure representing the string to be trimmed. The string is modified in place.\n * \\param CharSet Pointer to a PH_STRINGREF structure containing the set of characters to trim from the string.\n * \\param Flags Specifies trimming options. Can be used to indicate whether to trim from the left, right, or both ends.\n * \\remarks This function removes all characters specified in CharSet from the start and/or end of the string referenced by String,\n * depending on the Flags provided.\n */\nVOID PhTrimStringRef(\n    _Inout_ PPH_STRINGREF String,\n    _In_ PCPH_STRINGREF CharSet,\n    _In_ ULONG Flags\n    )\n{\n    PWCHAR charSet;\n    SIZE_T charSetCount;\n    BOOLEAN charSetTable[256];\n    BOOLEAN charSetTableComplete;\n    SIZE_T i;\n    SIZE_T j;\n    USHORT c;\n    SIZE_T trimCount;\n    SIZE_T count;\n    PWCHAR s;\n\n    if (!String->Buffer || String->Length == 0 || CharSet->Length == 0)\n        return;\n\n    if (CharSet->Length == sizeof(WCHAR))\n    {\n        c = CharSet->Buffer[0];\n\n        if (!(Flags & PH_TRIM_END_ONLY))\n        {\n            trimCount = 0;\n            count = String->Length / sizeof(WCHAR);\n            s = String->Buffer;\n\n            while (count-- != 0)\n            {\n                if (*s++ != c)\n                    break;\n\n                trimCount++;\n            }\n\n            PhSkipStringRef(String, trimCount * sizeof(WCHAR));\n        }\n\n        if (!(Flags & PH_TRIM_START_ONLY))\n        {\n            trimCount = 0;\n            count = String->Length / sizeof(WCHAR);\n            s = PTR_ADD_OFFSET(String->Buffer, String->Length - sizeof(WCHAR));\n\n            while (count-- != 0)\n            {\n                if (*s-- != c)\n                    break;\n\n                trimCount++;\n            }\n\n            String->Length -= trimCount * sizeof(WCHAR);\n        }\n\n        return;\n    }\n\n    // Build the character set lookup table.\n\n    charSet = CharSet->Buffer;\n    charSetCount = CharSet->Length / sizeof(WCHAR);\n    memset(charSetTable, 0, sizeof(charSetTable));\n    charSetTableComplete = TRUE;\n\n    for (i = 0; i < charSetCount; i++)\n    {\n        c = charSet[i];\n        charSetTable[c & 0xff] = TRUE;\n\n        if (c >= 256)\n            charSetTableComplete = FALSE;\n    }\n\n    // Trim the string.\n\n    if (!(Flags & PH_TRIM_END_ONLY))\n    {\n        trimCount = 0;\n        count = String->Length / sizeof(WCHAR);\n        s = String->Buffer;\n\n        while (count-- != 0)\n        {\n            c = *s++;\n\n            if (!charSetTable[c & 0xff])\n                break;\n\n            if (!charSetTableComplete)\n            {\n                for (j = 0; j < charSetCount; j++)\n                {\n                    if (charSet[j] == c)\n                        goto CharFound;\n                }\n\n                break;\n            }\n\nCharFound:\n            trimCount++;\n        }\n\n        PhSkipStringRef(String, trimCount * sizeof(WCHAR));\n    }\n\n    if (!(Flags & PH_TRIM_START_ONLY))\n    {\n        trimCount = 0;\n        count = String->Length / sizeof(WCHAR);\n        s = PTR_ADD_OFFSET(String->Buffer, String->Length - sizeof(WCHAR));\n\n        while (count-- != 0)\n        {\n            c = *s--;\n\n            if (!charSetTable[c & 0xff])\n                break;\n\n            if (!charSetTableComplete)\n            {\n                for (j = 0; j < charSetCount; j++)\n                {\n                    if (charSet[j] == c)\n                        goto CharFound2;\n                }\n\n                break;\n            }\n\nCharFound2:\n            trimCount++;\n        }\n\n        String->Length -= trimCount * sizeof(WCHAR);\n    }\n}\n\n/**\n * Creates a string object using a specified length.\n *\n * \\param Buffer A null-terminated Unicode string.\n * \\param Length The length, in bytes, of the string.\n */\n_Use_decl_annotations_\nPPH_STRING PhCreateStringEx(\n    _In_reads_bytes_opt_(Length) PCWCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    PPH_STRING string;\n\n    string = PhCreateObject(\n        UFIELD_OFFSET(PH_STRING, Data) + Length + sizeof(UNICODE_NULL),\n        PhStringType\n        );\n\n    assert(!(Length & 1));\n    string->Length = Length;\n    string->Buffer = string->Data;\n    *(PWCHAR)PTR_ADD_OFFSET(string->Buffer, Length) = UNICODE_NULL;\n\n    if (Buffer)\n    {\n        memcpy(string->Buffer, Buffer, Length);\n    }\n\n    return string;\n}\n\n/**\n * Creates a string object using a specified length and mode.\n *\n * \\param String A string reference to create a new string object from.\n * \\param Flags A combination of PH_STRING flags.\n * \\param TrimCharSet A string containing characters to trim. If NULL, no trimming is performed.\n */\n_Use_decl_annotations_\nPPH_STRING PhCreateString3(\n    _In_ PCPH_STRINGREF String,\n    _In_ ULONG Flags,\n    _In_opt_ PCPH_STRINGREF TrimCharSet\n    )\n{\n    PPH_STRING string;\n    PH_STRINGREF sr;\n\n    sr = *String;\n    if (TrimCharSet)\n        PhTrimStringRef(&sr, TrimCharSet, Flags & PH_STRING_TRIM_MASK);\n\n    string = PhCreateObject(\n        UFIELD_OFFSET(PH_STRING, Data) + sr.Length + sizeof(UNICODE_NULL), // Null terminator for compatibility\n        PhStringType\n        );\n\n    assert(!(sr.Length & 1));\n    string->Length = sr.Length;\n    string->Buffer = string->Data;\n    *(PWCHAR)PTR_ADD_OFFSET(string->Buffer, sr.Length) = UNICODE_NULL;\n\n    if (!sr.Buffer)\n        return string;\n\n    if (!(Flags & PH_STRING_CASE_MASK))\n    {\n        memcpy(string->Buffer, sr.Buffer, sr.Length);\n        return string;\n    }\n\n    if (Flags & PH_STRING_UPPER_CASE)\n        PhUpperStringRefInto(&string->sr, &sr);\n    else\n        PhLowerStringRefInto(&string->sr, &sr);\n\n    return string;\n}\n\n/**\n * Obtains a reference to a zero-length string.\n */\nPPH_STRING PhReferenceEmptyString(\n    VOID\n    )\n{\n    PPH_STRING string;\n    PPH_STRING newString;\n\n    // Initial lightweight atomic read\n    string = ReadPointerAcquire(&PhSharedEmptyString);\n\n    if (!string)\n    {\n        newString = PhCreateStringEx(NULL, 0);\n\n        // Final atomic compare-and-swap\n        string = InterlockedCompareExchangePointer(\n            &PhSharedEmptyString,\n            newString,\n            NULL\n            );\n\n        if (string)\n        {\n            PhDereferenceObject(newString);\n        }\n        else\n        {\n            string = newString; // success\n        }\n    }\n\n    return PhReferenceObject(string);\n}\n\n/**\n * Concatenates multiple strings.\n *\n * \\param Count The number of strings to concatenate.\n * \\param ... The list of strings.\n */\n_Use_decl_annotations_\nPPH_STRING PhConcatStrings(\n    _In_ ULONG Count,\n    ...\n    )\n{\n    PPH_STRING string;\n    va_list argptr;\n\n    va_start(argptr, Count);\n    string = PhConcatStrings_V(Count, argptr);\n    va_end(argptr);\n\n    return string;\n}\n\n/**\n * Concatenates multiple strings.\n *\n * \\param Count The number of strings to concatenate.\n * \\param ArgPtr A pointer to an array of strings.\n */\n_Use_decl_annotations_\nPPH_STRING PhConcatStrings_V(\n    _In_ ULONG Count,\n    _In_ va_list ArgPtr\n    )\n{\n    va_list argptr;\n    ULONG i;\n    SIZE_T totalLength = 0;\n    SIZE_T stringLength;\n    SIZE_T cachedLengths[PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE];\n    PWSTR arg;\n    PPH_STRING string;\n\n    // Compute the total length, in bytes, of the strings.\n\n    argptr = ArgPtr;\n\n    for (i = 0; i < Count; i++)\n    {\n        arg = va_arg(argptr, PWSTR);\n        stringLength = PhCountStringZ(arg) * sizeof(WCHAR);\n        totalLength += stringLength;\n\n        if (i < PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE)\n            cachedLengths[i] = stringLength;\n    }\n\n    // Create the string.\n\n    string = PhCreateStringEx(NULL, totalLength);\n    totalLength = 0;\n\n    // Append the strings one by one.\n\n    argptr = ArgPtr;\n\n    for (i = 0; i < Count; i++)\n    {\n        arg = va_arg(argptr, PWSTR);\n\n        if (i < PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE)\n            stringLength = cachedLengths[i];\n        else\n            stringLength = PhCountStringZ(arg) * sizeof(WCHAR);\n\n        memcpy(\n            PTR_ADD_OFFSET(string->Buffer, totalLength),\n            arg,\n            stringLength\n            );\n        totalLength += stringLength;\n    }\n\n    return string;\n}\n\n/**\n * Concatenates two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n */\n_Use_decl_annotations_\nPPH_STRING PhConcatStrings2(\n    _In_ PCWSTR String1,\n    _In_ PCWSTR String2\n    )\n{\n    PPH_STRING string;\n    SIZE_T length1;\n    SIZE_T length2;\n\n    length1 = PhCountStringZ(String1) * sizeof(WCHAR);\n    length2 = PhCountStringZ(String2) * sizeof(WCHAR);\n    string = PhCreateStringEx(NULL, length1 + length2);\n    memcpy(\n        string->Buffer,\n        String1,\n        length1\n        );\n    memcpy(\n        PTR_ADD_OFFSET(string->Buffer, length1),\n        String2,\n        length2\n        );\n\n    return string;\n}\n\n/**\n * Concatenates two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n */\n_Use_decl_annotations_\nPPH_STRING PhConcatStringRef2(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2\n    )\n{\n    PPH_STRING string;\n\n    assert(!(String1->Length & 1));\n    assert(!(String2->Length & 1));\n\n    string = PhCreateStringEx(NULL, String1->Length + String2->Length);\n\n    memcpy(\n        string->Buffer,\n        String1->Buffer,\n        String1->Length\n        );\n    memcpy(\n        PTR_ADD_OFFSET(string->Buffer, String1->Length),\n        String2->Buffer,\n        String2->Length\n        );\n\n    return string;\n}\n\n/**\n * Concatenates three strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param String3 The third string.\n */\n_Use_decl_annotations_\nPPH_STRING PhConcatStringRef3(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2,\n    _In_ PCPH_STRINGREF String3\n    )\n{\n    PPH_STRING string;\n    PCHAR buffer;\n\n    assert(!(String1->Length & 1));\n    assert(!(String2->Length & 1));\n    assert(!(String3->Length & 1));\n\n    string = PhCreateStringEx(NULL, String1->Length + String2->Length + String3->Length);\n\n    buffer = (PCHAR)string->Buffer;\n    memcpy(buffer, String1->Buffer, String1->Length);\n\n    buffer += String1->Length;\n    memcpy(buffer, String2->Buffer, String2->Length);\n\n    buffer += String2->Length;\n    memcpy(buffer, String3->Buffer, String3->Length);\n\n    return string;\n}\n\n/**\n * Concatenates four strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param String3 The third string.\n * \\param String4 The forth string.\n */\n_Use_decl_annotations_\nPPH_STRING PhConcatStringRef4(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2,\n    _In_ PCPH_STRINGREF String3,\n    _In_ PCPH_STRINGREF String4\n    )\n{\n    PPH_STRING string;\n    PCHAR buffer;\n\n    assert(!(String1->Length & 1));\n    assert(!(String2->Length & 1));\n    assert(!(String3->Length & 1));\n    assert(!(String4->Length & 1));\n\n    string = PhCreateStringEx(NULL, String1->Length + String2->Length + String3->Length + String4->Length);\n\n    buffer = (PCHAR)string->Buffer;\n    memcpy(buffer, String1->Buffer, String1->Length);\n\n    buffer += String1->Length;\n    memcpy(buffer, String2->Buffer, String2->Length);\n\n    buffer += String2->Length;\n    memcpy(buffer, String3->Buffer, String3->Length);\n\n    buffer += String3->Length;\n    memcpy(buffer, String4->Buffer, String4->Length);\n\n    return string;\n}\n\n/**\n * Creates a string using format specifiers.\n *\n * \\param Format The format-control string.\n * \\param ... The list of arguments.\n */\n_Use_decl_annotations_\nPPH_STRING PhFormatString(\n    _In_ _Printf_format_string_ PCWSTR Format,\n    ...\n    )\n{\n    PPH_STRING string;\n    va_list argptr;\n\n    va_start(argptr, Format);\n    string = PhFormatString_V(Format, argptr);\n    va_end(argptr);\n\n    return string;\n}\n\n/**\n * Creates a string using format specifiers.\n *\n * \\param Format The format-control string.\n * \\param ArgPtr A pointer to the list of arguments.\n */\n_Use_decl_annotations_\nPPH_STRING PhFormatString_V(\n    _In_ _Printf_format_string_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    PPH_STRING string;\n    LONG length;\n\n    length = _vscwprintf(Format, ArgPtr);\n\n    if (length == INT_ERROR)\n        return NULL;\n\n    string = PhCreateStringEx(NULL, length * sizeof(WCHAR));\n    _vsnwprintf(string->Buffer, length, Format, ArgPtr);\n\n    return string;\n}\n\n/**\n * Creates a bytes object.\n *\n * \\param Buffer An array of bytes.\n * \\param Length The length of \\a Buffer, in bytes.\n */\nPPH_BYTES PhCreateBytesEx(\n    _In_opt_ PCCH Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    PPH_BYTES bytes;\n\n    bytes = PhCreateObject(\n        UFIELD_OFFSET(PH_BYTES, Data) + Length + sizeof(ANSI_NULL), // Null terminator for compatibility\n        PhBytesType\n        );\n\n    bytes->Length = Length;\n    bytes->Buffer = bytes->Data;\n    bytes->Buffer[Length] = ANSI_NULL;\n\n    if (Buffer)\n    {\n        memcpy(bytes->Buffer, Buffer, Length);\n    }\n\n    return bytes;\n}\n\n/**\n * Formats a string using the specified format and argument list.\n *\n * \\param Format A printf-style format string.\n * \\param ArgPtr A va_list containing the arguments to format.\n * \\return A pointer to a PPH_BYTES structure containing the formatted string.\n */\nPPH_BYTES PhFormatBytes_V(\n    _In_ _Printf_format_string_ PCSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    PPH_BYTES string;\n    LONG length;\n\n    length = _vscprintf(Format, ArgPtr);\n\n    if (length == INT_ERROR)\n        return NULL;\n\n    string = PhCreateBytesEx(NULL, length * sizeof(CHAR));\n    _vsnprintf(string->Buffer, length, Format, ArgPtr);\n\n    return string;\n}\n\n/**\n * Formats a sequence of bytes according to a specified format string.\n *\n * \\param Format A printf-style format string that specifies how the bytes should be formatted.\n * \\param ... Additional arguments required by the format string.\n * \\return A pointer to a PPH_BYTES structure containing the formatted bytes.\n */\nPPH_BYTES PhFormatBytes(\n    _In_ _Printf_format_string_ PCSTR Format,\n    ...\n    )\n{\n    PPH_BYTES string;\n    va_list argptr;\n\n    va_start(argptr, Format);\n    string = PhFormatBytes_V(Format, argptr);\n    va_end(argptr);\n\n    return string;\n}\n\nBOOLEAN PhWriteUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _In_ ULONG CodeUnit\n    )\n{\n    switch (Decoder->Encoding)\n    {\n    case PH_UNICODE_UTF8:\n        if (Decoder->InputCount >= 4)\n            return FALSE;\n        Decoder->u.Utf8.Input[Decoder->InputCount] = (UCHAR)CodeUnit;\n        Decoder->InputCount++;\n        return TRUE;\n    case PH_UNICODE_UTF16:\n        if (Decoder->InputCount >= 2)\n            return FALSE;\n        Decoder->u.Utf16.Input[Decoder->InputCount] = (USHORT)CodeUnit;\n        Decoder->InputCount++;\n        return TRUE;\n    case PH_UNICODE_UTF32:\n        if (Decoder->InputCount >= 1)\n            return FALSE;\n        Decoder->u.Utf32.Input = CodeUnit;\n        Decoder->InputCount = 1;\n        return TRUE;\n    default:\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n    }\n}\n\n_Success_(return)\nBOOLEAN PhpReadUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _Out_ PULONG CodeUnit\n    )\n{\n    switch (Decoder->Encoding)\n    {\n    case PH_UNICODE_UTF8:\n        if (Decoder->InputCount == 0)\n            return FALSE;\n        *CodeUnit = Decoder->u.Utf8.Input[0];\n        Decoder->u.Utf8.Input[0] = Decoder->u.Utf8.Input[1];\n        Decoder->u.Utf8.Input[1] = Decoder->u.Utf8.Input[2];\n        Decoder->u.Utf8.Input[2] = Decoder->u.Utf8.Input[3];\n        Decoder->InputCount--;\n        return TRUE;\n    case PH_UNICODE_UTF16:\n        if (Decoder->InputCount == 0)\n            return FALSE;\n        *CodeUnit = Decoder->u.Utf16.Input[0];\n        Decoder->u.Utf16.Input[0] = Decoder->u.Utf16.Input[1];\n        Decoder->InputCount--;\n        return TRUE;\n    case PH_UNICODE_UTF32:\n        if (Decoder->InputCount == 0)\n            return FALSE;\n        *CodeUnit = Decoder->u.Utf32.Input;\n        Decoder->InputCount--;\n        return TRUE;\n    default:\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n    }\n}\n\nVOID PhpUnreadUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _In_ ULONG CodeUnit\n    )\n{\n    switch (Decoder->Encoding)\n    {\n    case PH_UNICODE_UTF8:\n        if (Decoder->InputCount >= 4)\n            PhRaiseStatus(STATUS_UNSUCCESSFUL);\n        Decoder->u.Utf8.Input[3] = Decoder->u.Utf8.Input[2];\n        Decoder->u.Utf8.Input[2] = Decoder->u.Utf8.Input[1];\n        Decoder->u.Utf8.Input[1] = Decoder->u.Utf8.Input[0];\n        Decoder->u.Utf8.Input[0] = (UCHAR)CodeUnit;\n        Decoder->InputCount++;\n        break;\n    case PH_UNICODE_UTF16:\n        if (Decoder->InputCount >= 2)\n            PhRaiseStatus(STATUS_UNSUCCESSFUL);\n        Decoder->u.Utf16.Input[1] = Decoder->u.Utf16.Input[0];\n        Decoder->u.Utf16.Input[0] = (USHORT)CodeUnit;\n        Decoder->InputCount++;\n        break;\n    case PH_UNICODE_UTF32:\n        if (Decoder->InputCount >= 1)\n            PhRaiseStatus(STATUS_UNSUCCESSFUL);\n        Decoder->u.Utf32.Input = CodeUnit;\n        Decoder->InputCount = 1;\n        break;\n    default:\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n    }\n}\n\nBOOLEAN PhpDecodeUtf8Error(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _Out_ PULONG CodePoint,\n    _In_ ULONG Which\n    )\n{\n    if (Which >= 4)\n        PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit4);\n    if (Which >= 3)\n        PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit3);\n    if (Which >= 2)\n        PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit2);\n\n    *CodePoint = (ULONG)Decoder->u.Utf8.CodeUnit1 + 0xdc00;\n    Decoder->State = 0;\n\n    return TRUE;\n}\n\n_Use_decl_annotations_\nBOOLEAN PhDecodeUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _Out_ PULONG CodePoint\n    )\n{\n    ULONG codeUnit;\n\n    while (TRUE)\n    {\n        switch (Decoder->Encoding)\n        {\n        case PH_UNICODE_UTF8:\n            if (!PhpReadUnicodeDecoder(Decoder, &codeUnit))\n                return FALSE;\n\n            switch (Decoder->State)\n            {\n            case 0:\n                Decoder->u.Utf8.CodeUnit1 = (UCHAR)codeUnit;\n\n                if (codeUnit < 0x80)\n                {\n                    *CodePoint = codeUnit;\n                    return TRUE;\n                }\n                else if (codeUnit < 0xc2)\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 1);\n                }\n                else if (codeUnit < 0xe0)\n                {\n                    Decoder->State = 1; // 2 byte sequence\n                    continue;\n                }\n                else if (codeUnit < 0xf0)\n                {\n                    Decoder->State = 2; // 3 byte sequence\n                    continue;\n                }\n                else if (codeUnit < 0xf5)\n                {\n                    Decoder->State = 3; // 4 byte sequence\n                    continue;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 1);\n                }\n\n                break;\n            case 1: // 2 byte sequence\n                Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit;\n\n                if ((codeUnit & 0xc0) == 0x80)\n                {\n                    *CodePoint = ((ULONG)Decoder->u.Utf8.CodeUnit1 << 6) + codeUnit - 0x3080;\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 2);\n                }\n\n                break;\n            case 2: // 3 byte sequence (1)\n                Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit;\n\n                if (((codeUnit & 0xc0) == 0x80) &&\n                    (Decoder->u.Utf8.CodeUnit1 != 0xe0 || codeUnit >= 0xa0))\n                {\n                    Decoder->State = 4; // 3 byte sequence (2)\n                    continue;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 2);\n                }\n\n                break;\n            case 3: // 4 byte sequence (1)\n                Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit;\n\n                if (((codeUnit & 0xc0) == 0x80) &&\n                    (Decoder->u.Utf8.CodeUnit1 != 0xf0 || codeUnit >= 0x90) &&\n                    (Decoder->u.Utf8.CodeUnit1 != 0xf4 || codeUnit < 0x90))\n                {\n                    Decoder->State = 5; // 4 byte sequence (2)\n                    continue;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 2);\n                }\n\n                break;\n            case 4: // 3 byte sequence (2)\n                Decoder->u.Utf8.CodeUnit3 = (UCHAR)codeUnit;\n\n                if ((codeUnit & 0xc0) == 0x80)\n                {\n                    *CodePoint =\n                        ((ULONG)Decoder->u.Utf8.CodeUnit1 << 12) +\n                        ((ULONG)Decoder->u.Utf8.CodeUnit2 << 6) +\n                        codeUnit - 0xe2080;\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 3);\n                }\n\n                break;\n            case 5: // 4 byte sequence (2)\n                Decoder->u.Utf8.CodeUnit3 = (UCHAR)codeUnit;\n\n                if ((codeUnit & 0xc0) == 0x80)\n                {\n                    Decoder->State = 6; // 4 byte sequence (3)\n                    continue;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 3);\n                }\n\n                break;\n            case 6: // 4 byte sequence (3)\n                Decoder->u.Utf8.CodeUnit4 = (UCHAR)codeUnit;\n\n                if ((codeUnit & 0xc0) == 0x80)\n                {\n                    *CodePoint =\n                        ((ULONG)Decoder->u.Utf8.CodeUnit1 << 18) +\n                        ((ULONG)Decoder->u.Utf8.CodeUnit2 << 12) +\n                        ((ULONG)Decoder->u.Utf8.CodeUnit3 << 6) +\n                        codeUnit - 0x3c82080;\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 4);\n                }\n\n                break;\n            }\n\n            return FALSE;\n        case PH_UNICODE_UTF16:\n            if (!PhpReadUnicodeDecoder(Decoder, &codeUnit))\n                return FALSE;\n\n            switch (Decoder->State)\n            {\n            case 0:\n                if (PH_UNICODE_UTF16_IS_HIGH_SURROGATE(codeUnit))\n                {\n                    Decoder->u.Utf16.CodeUnit = (USHORT)codeUnit;\n                    Decoder->State = 1;\n                    continue;\n                }\n                else\n                {\n                    *CodePoint = codeUnit;\n                    return TRUE;\n                }\n                break;\n            case 1:\n                if (PH_UNICODE_UTF16_IS_LOW_SURROGATE(codeUnit))\n                {\n                    *CodePoint = PH_UNICODE_UTF16_TO_CODE_POINT(Decoder->u.Utf16.CodeUnit, codeUnit);\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                else\n                {\n                    *CodePoint = Decoder->u.Utf16.CodeUnit;\n                    PhpUnreadUnicodeDecoder(Decoder, codeUnit);\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                break;\n            }\n\n            return FALSE;\n        case PH_UNICODE_UTF32:\n            if (PhpReadUnicodeDecoder(Decoder, CodePoint))\n                return TRUE;\n            return FALSE;\n        default:\n            return FALSE;\n        }\n    }\n}\n\n_Use_decl_annotations_\nBOOLEAN PhEncodeUnicode(\n    _In_ UCHAR Encoding,\n    _In_ ULONG CodePoint,\n    _Out_opt_ PVOID CodeUnits,\n    _Out_ PULONG NumberOfCodeUnits\n    )\n{\n    switch (Encoding)\n    {\n    case PH_UNICODE_UTF8:\n        {\n            PUCHAR codeUnits = CodeUnits;\n\n            if (CodePoint < 0x80)\n            {\n                *NumberOfCodeUnits = 1;\n\n                if (codeUnits)\n                    codeUnits[0] = (UCHAR)CodePoint;\n            }\n            else if (CodePoint <= 0x7ff)\n            {\n                *NumberOfCodeUnits = 2;\n\n                if (codeUnits)\n                {\n                    codeUnits[0] = (UCHAR)(CodePoint >> 6) + 0xc0;\n                    codeUnits[1] = (UCHAR)(CodePoint & 0x3f) + 0x80;\n                }\n            }\n            else if (CodePoint <= 0xffff)\n            {\n                *NumberOfCodeUnits = 3;\n\n                if (codeUnits)\n                {\n                    codeUnits[0] = (UCHAR)(CodePoint >> 12) + 0xe0;\n                    codeUnits[1] = (UCHAR)((CodePoint >> 6) & 0x3f) + 0x80;\n                    codeUnits[2] = (UCHAR)(CodePoint & 0x3f) + 0x80;\n                }\n            }\n            else if (CodePoint <= PH_UNICODE_MAX_CODE_POINT)\n            {\n                *NumberOfCodeUnits = 4;\n\n                if (codeUnits)\n                {\n                    codeUnits[0] = (UCHAR)(CodePoint >> 18) + 0xf0;\n                    codeUnits[1] = (UCHAR)((CodePoint >> 12) & 0x3f) + 0x80;\n                    codeUnits[2] = (UCHAR)((CodePoint >> 6) & 0x3f) + 0x80;\n                    codeUnits[3] = (UCHAR)(CodePoint & 0x3f) + 0x80;\n                }\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case PH_UNICODE_UTF16:\n        {\n            PUSHORT codeUnits = CodeUnits;\n\n            if (CodePoint < 0x10000)\n            {\n                *NumberOfCodeUnits = 1;\n\n                if (codeUnits)\n                    codeUnits[0] = (USHORT)CodePoint;\n            }\n            else if (CodePoint <= PH_UNICODE_MAX_CODE_POINT)\n            {\n                *NumberOfCodeUnits = 2;\n\n                if (codeUnits)\n                {\n                    codeUnits[0] = PH_UNICODE_UTF16_TO_HIGH_SURROGATE(CodePoint);\n                    codeUnits[1] = PH_UNICODE_UTF16_TO_LOW_SURROGATE(CodePoint);\n                }\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case PH_UNICODE_UTF32:\n        *NumberOfCodeUnits = 1;\n        if (CodeUnits)\n            *(PULONG)CodeUnits = CodePoint;\n        return TRUE;\n    default:\n        return FALSE;\n    }\n}\n\n/**\n * Converts an ASCII string to a UTF-16 string by zero-extending each byte.\n *\n * \\param Input The original ASCII string.\n * \\param InputLength The length of \\a Input.\n * \\param Output A buffer which will contain the converted string.\n */\nVOID PhZeroExtendToUtf16Buffer(\n    _In_reads_bytes_(InputLength) PCCH Input,\n    _In_ SIZE_T InputLength,\n    _Out_writes_bytes_(InputLength * sizeof(WCHAR)) PWCH Output\n    )\n{\n    SIZE_T inputLength;\n\n    inputLength = InputLength & -4;\n\n    if (inputLength)\n    {\n        do\n        {\n            Output[0] = C_1uTo2(Input[0]);\n            Output[1] = C_1uTo2(Input[1]);\n            Output[2] = C_1uTo2(Input[2]);\n            Output[3] = C_1uTo2(Input[3]);\n            Input += 4;\n            Output += 4;\n            inputLength -= 4;\n        } while (inputLength != 0);\n    }\n\n    switch (InputLength & 3)\n    {\n    case 3:\n        *Output++ = C_1uTo2(*Input++);\n    case 2:\n        *Output++ = C_1uTo2(*Input++);\n    case 1:\n        *Output++ = C_1uTo2(*Input++);\n    }\n}\n\n/**\n * Converts a zero-terminated ANSI string to a UTF-16 string, extending the input as needed.\n *\n * \\param Input Pointer to the input ANSI string.\n * \\param InputLength Length of the input string in bytes.\n * \\return A pointer to a PPH_STRING containing the UTF-16 representation of the input string.\n */\nPPH_STRING PhZeroExtendToUtf16Ex(\n    _In_reads_bytes_(InputLength) PCCH Input,\n    _In_ SIZE_T InputLength\n    )\n{\n    PPH_STRING string;\n\n    string = PhCreateStringEx(NULL, InputLength * sizeof(WCHAR));\n    PhZeroExtendToUtf16Buffer(Input, InputLength, string->Buffer);\n\n    return string;\n}\n\n/**\n * Converts a UTF-16 string to an ASCII byte array.\n *\n * \\param Buffer Pointer to the UTF-16 string buffer to convert.\n * \\param Length Length of the UTF-16 string, in characters.\n * \\param Replacement Optional character to use when a UTF-16 character cannot be represented in ASCII.\n * \\return Pointer to a PPH_BYTES structure containing the converted ASCII bytes.\n */\nPPH_BYTES PhConvertUtf16ToAsciiEx(\n    _In_ PCWCH Buffer,\n    _In_ SIZE_T Length,\n    _In_opt_ CHAR Replacement\n    )\n{\n    PPH_BYTES bytes;\n    PH_UNICODE_DECODER decoder;\n    PWCH in;\n    SIZE_T inRemaining;\n    PCH out;\n    SIZE_T outLength;\n    ULONG codePoint;\n\n    bytes = PhCreateBytesEx(NULL, Length / sizeof(WCHAR));\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16);\n    in = (PWCH)Buffer;\n    inRemaining = Length / sizeof(WCHAR);\n    out = bytes->Buffer;\n    outLength = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (USHORT)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (codePoint < 0x80)\n            {\n                *out++ = (CHAR)codePoint;\n                outLength++;\n            }\n            else if (Replacement)\n            {\n                *out++ = Replacement;\n                outLength++;\n            }\n        }\n    }\n\n    bytes->Length = outLength;\n    bytes->Buffer[outLength] = ANSI_NULL;\n\n    return bytes;\n}\n\n/**\n * Creates a string object from an existing null-terminated multi-byte string.\n *\n * \\param Buffer A null-terminated multi-byte string.\n */\nPPH_STRING PhConvertMultiByteToUtf16(\n    _In_ PCSTR Buffer\n    )\n{\n    return PhConvertMultiByteToUtf16Ex(\n        Buffer,\n        strlen(Buffer)\n        );\n}\n\n/**\n * Creates a string object from an existing null-terminated multi-byte string.\n *\n * \\param Buffer A null-terminated multi-byte string.\n * \\param Length The number of bytes to use.\n */\nPPH_STRING PhConvertMultiByteToUtf16Ex(\n    _In_ PCSTR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n    ULONG bufferLength;\n    ULONG unicodeBytes;\n\n    status = RtlSizeTToULong(Length, &bufferLength);\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    status = RtlMultiByteToUnicodeSize(\n        &unicodeBytes,\n        Buffer,\n        bufferLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    string = PhCreateStringEx(NULL, unicodeBytes);\n    status = RtlMultiByteToUnicodeN(\n        string->Buffer,\n        (ULONG)string->Length,\n        NULL,\n        Buffer,\n        bufferLength\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    return string;\n}\n\n/**\n * Creates a multi-byte string from an existing null-terminated UTF-16 string.\n *\n * \\param Buffer A null-terminated UTF-16 string.\n */\nPPH_BYTES PhConvertUtf16ToMultiByte(\n    _In_ PCWSTR Buffer\n    )\n{\n    return PhConvertUtf16ToMultiByteEx(\n        Buffer,\n        PhCountStringZ(Buffer) * sizeof(WCHAR)\n        );\n}\n\n/**\n * Creates a multi-byte string from an existing null-terminated UTF-16 string.\n *\n * \\param Buffer A null-terminated UTF-16 string.\n * \\param Length The number of bytes to use.\n */\nPPH_BYTES PhConvertUtf16ToMultiByteEx(\n    _In_ PCWCH Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    NTSTATUS status;\n    PPH_BYTES bytes;\n    ULONG bufferLength;\n    ULONG multiByteLength;\n\n    status = RtlSizeTToULong(Length, &bufferLength);\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    status = RtlUnicodeToMultiByteSize(\n        &multiByteLength,\n        Buffer,\n        bufferLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    bytes = PhCreateBytesEx(NULL, multiByteLength);\n    status = RtlUnicodeToMultiByteN(\n        bytes->Buffer,\n        (ULONG)bytes->Length,\n        NULL,\n        Buffer,\n        bufferLength\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(bytes);\n        return NULL;\n    }\n\n    return bytes;\n}\n\n/**\n * Converts a UTF-8 encoded string to its UTF-16 equivalent and calculates the size in bytes of the resulting UTF-16 string.\n *\n * \\param BytesInUtf16String Pointer to a variable that receives the size in bytes of the UTF-16 string.\n * \\param Utf8String Pointer to the UTF-8 encoded input string.\n * \\param BytesInUtf8String The size in bytes of the UTF-8 input string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhConvertUtf8ToUtf16Size(\n    _Out_ PSIZE_T BytesInUtf16String,\n    _In_reads_bytes_(BytesInUtf8String) PCCH Utf8String,\n    _In_ SIZE_T BytesInUtf8String\n    )\n{\n#if defined(PH_NATIVE_STRING_CONVERSION)\n    NTSTATUS status;\n    ULONG bytesInUtf16String = 0;\n\n    status = RtlUTF8ToUnicodeN(\n        NULL,\n        0,\n        &bytesInUtf16String,\n        Utf8String,\n        (ULONG)BytesInUtf8String\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (BytesInUtf16String)\n        {\n            *BytesInUtf16String = bytesInUtf16String;\n        }\n    }\n\n    return status;\n#else\n    NTSTATUS status;\n    PH_UNICODE_DECODER decoder;\n    PCH in;\n    SIZE_T inRemaining;\n    SIZE_T bytesInUtf16String;\n    ULONG codePoint;\n    ULONG numberOfCodeUnits;\n\n    status = STATUS_SUCCESS;\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF8);\n    in = Utf8String;\n    inRemaining = BytesInUtf8String;\n    bytesInUtf16String = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (UCHAR)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (PhEncodeUnicode(PH_UNICODE_UTF16, codePoint, NULL, &numberOfCodeUnits))\n            {\n                bytesInUtf16String += numberOfCodeUnits * sizeof(WCHAR);\n            }\n            else\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n                break;\n            }\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n    }\n\n    *BytesInUtf16String = bytesInUtf16String;\n\n    return status;\n#endif\n}\n\n/**\n * Converts a UTF-8 encoded string to a UTF-16 encoded buffer.\n *\n * \\param Utf16String Pointer to the buffer that receives the converted UTF-16 string.\n * \\param MaxBytesInUtf16String The maximum number of bytes that can be written to Utf16String.\n * \\param BytesInUtf16String Optional pointer that receives the number of bytes written to Utf16String.\n * \\param Utf8String Pointer to the UTF-8 encoded input string.\n * \\param BytesInUtf8String The number of bytes in the input UTF-8 string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhConvertUtf8ToUtf16Buffer(\n    _Out_writes_bytes_to_(MaxBytesInUtf16String, *BytesInUtf16String) PWCH Utf16String,\n    _In_ SIZE_T MaxBytesInUtf16String,\n    _Out_opt_ PSIZE_T BytesInUtf16String,\n    _In_reads_bytes_(BytesInUtf8String) PCCH Utf8String,\n    _In_ SIZE_T BytesInUtf8String\n    )\n{\n#if defined(PH_NATIVE_STRING_CONVERSION)\n    NTSTATUS status;\n    ULONG bytesInUtf16String = 0;\n\n    status = RtlUTF8ToUnicodeN(\n        Utf16String,\n        (ULONG)MaxBytesInUtf16String,\n        &bytesInUtf16String,\n        Utf8String,\n        (ULONG)BytesInUtf8String\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (BytesInUtf16String)\n        {\n            *BytesInUtf16String = bytesInUtf16String;\n        }\n    }\n\n    return status;\n#else\n    NTSTATUS status;\n    PH_UNICODE_DECODER decoder;\n    PCH in;\n    SIZE_T inRemaining;\n    PWCH out;\n    SIZE_T outRemaining;\n    SIZE_T bytesInUtf16String;\n    ULONG codePoint;\n    USHORT codeUnits[2];\n    ULONG numberOfCodeUnits;\n\n    status = STATUS_SUCCESS;\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF8);\n    in = Utf8String;\n    inRemaining = BytesInUtf8String;\n    out = Utf16String;\n    outRemaining = MaxBytesInUtf16String / sizeof(WCHAR);\n    bytesInUtf16String = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (UCHAR)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (PhEncodeUnicode(PH_UNICODE_UTF16, codePoint, codeUnits, &numberOfCodeUnits))\n            {\n                bytesInUtf16String += numberOfCodeUnits * sizeof(WCHAR);\n\n                if (outRemaining >= numberOfCodeUnits)\n                {\n                    *out++ = codeUnits[0];\n\n                    if (numberOfCodeUnits >= 2)\n                        *out++ = codeUnits[1];\n\n                    outRemaining -= numberOfCodeUnits;\n                }\n                else\n                {\n                    status = STATUS_BUFFER_TOO_SMALL;\n                    break;\n                }\n            }\n            else\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n                break;\n            }\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n    }\n\n    if (BytesInUtf16String)\n        *BytesInUtf16String = bytesInUtf16String;\n\n    return status;\n#endif\n}\n\n/**\n * Converts a UTF-8 encoded string to a UTF-16 encoded string.\n *\n * \\param Buffer A pointer to a null-terminated UTF-8 encoded string.\n * \\return A pointer to a PPH_STRING containing the converted UTF-16 string.\n * \\remarks Returns NULL if the conversion fails.\n */\n_Use_decl_annotations_\nPPH_STRING PhConvertUtf8ToUtf16(\n    _In_ PCSTR Buffer\n    )\n{\n    return PhConvertUtf8ToUtf16Ex(\n        Buffer,\n        strlen(Buffer)\n        );\n}\n\n/**\n * Converts a UTF-8 encoded string to a UTF-16 string.\n *\n * \\param Buffer Pointer to the UTF-8 encoded input buffer.\n * \\param Length Length of the input buffer in bytes.\n * \\return A pointer to a PPH_STRING containing the converted UTF-16 string.\n * \\remarks Returns NULL if the conversion fails.\n */\n_Use_decl_annotations_\nPPH_STRING PhConvertUtf8ToUtf16Ex(\n    _In_ PCCH Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n    SIZE_T utf16Bytes;\n\n    status = PhConvertUtf8ToUtf16Size(\n        &utf16Bytes,\n        Buffer,\n        Length\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    string = PhCreateStringEx(NULL, utf16Bytes);\n    status = PhConvertUtf8ToUtf16Buffer(\n        string->Buffer,\n        string->Length,\n        NULL,\n        Buffer,\n        Length\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    return string;\n}\n\n/**\n * Calculates the size in bytes required to store the UTF-8 encoded version of a given UTF-16 string.\n *\n * \\param BytesInUtf8String Pointer to a variable that receives the required size in bytes for the UTF-8 string.\n * \\param Utf16String Pointer to the UTF-16 string to be converted.\n * \\param BytesInUtf16String The size in bytes of the input UTF-16 string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhConvertUtf16ToUtf8Size(\n    _Out_ PSIZE_T BytesInUtf8String,\n    _In_reads_bytes_(BytesInUtf16String) PCWCH Utf16String,\n    _In_ SIZE_T BytesInUtf16String\n    )\n{\n#if defined(PH_NATIVE_STRING_CONVERSION)\n    NTSTATUS status;\n    ULONG bytesInUtf8String = 0;\n\n    status = RtlUnicodeToUTF8N(\n        NULL,\n        0,\n        &bytesInUtf8String,\n        Utf16String,\n        (ULONG)BytesInUtf16String\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (BytesInUtf8String)\n        {\n            *BytesInUtf8String = bytesInUtf8String;\n        }\n    }\n\n    return status;\n#else\n    NTSTATUS status;\n    PH_UNICODE_DECODER decoder;\n    PWCH in;\n    SIZE_T inRemaining;\n    SIZE_T bytesInUtf8String;\n    ULONG codePoint;\n    ULONG numberOfCodeUnits;\n\n    status = STATUS_SUCCESS;\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16);\n    in = Utf16String;\n    inRemaining = BytesInUtf16String / sizeof(WCHAR);\n    bytesInUtf8String = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (USHORT)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (PhEncodeUnicode(PH_UNICODE_UTF8, codePoint, NULL, &numberOfCodeUnits))\n            {\n                bytesInUtf8String += numberOfCodeUnits;\n            }\n            else\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n                break;\n            }\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n    }\n\n    *BytesInUtf8String = bytesInUtf8String;\n\n    return status;\n#endif\n}\n\n/**\n * Converts a UTF-16 encoded string to a UTF-8 encoded buffer.\n *\n * \\param Utf8String A pointer to the buffer that receives the UTF-8 encoded string. *\n * \\param MaxBytesInUtf8String The maximum number of bytes that can be written to the Utf8String buffer.\n * \\param BytesInUtf8String Optional pointer to a variable that receives the number of bytes written to Utf8String.\n * \\param Utf16String A pointer to the UTF-16 encoded input string.\n * \\param BytesInUtf16String The number of bytes in the UTF-16 encoded input string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhConvertUtf16ToUtf8Buffer(\n    _Out_writes_bytes_to_(MaxBytesInUtf8String, *BytesInUtf8String) PCH Utf8String,\n    _In_ SIZE_T MaxBytesInUtf8String,\n    _Out_opt_ PSIZE_T BytesInUtf8String,\n    _In_reads_bytes_(BytesInUtf16String) PCWCH Utf16String,\n    _In_ SIZE_T BytesInUtf16String\n    )\n{\n#if defined(PH_NATIVE_STRING_CONVERSION)\n    NTSTATUS status;\n    ULONG bytesInUtf8String = 0;\n\n    status = RtlUnicodeToUTF8N(\n        Utf8String,\n        (ULONG)MaxBytesInUtf8String,\n        &bytesInUtf8String,\n        Utf16String,\n        (ULONG)BytesInUtf16String\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (BytesInUtf8String)\n        {\n            *BytesInUtf8String = bytesInUtf8String;\n        }\n    }\n\n    return status;\n#else\n    NTSTATUS status;\n    PH_UNICODE_DECODER decoder;\n    PWCH in;\n    SIZE_T inRemaining;\n    PCH out;\n    SIZE_T outRemaining;\n    SIZE_T bytesInUtf8String;\n    ULONG codePoint;\n    UCHAR codeUnits[4];\n    ULONG numberOfCodeUnits;\n\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16);\n    in = Utf16String;\n    inRemaining = BytesInUtf16String / sizeof(WCHAR);\n    out = Utf8String;\n    outRemaining = MaxBytesInUtf8String;\n    bytesInUtf8String = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (USHORT)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (PhEncodeUnicode(PH_UNICODE_UTF8, codePoint, codeUnits, &numberOfCodeUnits))\n            {\n                bytesInUtf8String += numberOfCodeUnits;\n\n                if (outRemaining >= numberOfCodeUnits)\n                {\n                    *out++ = codeUnits[0];\n\n                    if (numberOfCodeUnits >= 2)\n                        *out++ = codeUnits[1];\n                    if (numberOfCodeUnits >= 3)\n                        *out++ = codeUnits[2];\n                    if (numberOfCodeUnits >= 4)\n                        *out++ = codeUnits[3];\n\n                    outRemaining -= numberOfCodeUnits;\n                }\n                else\n                {\n                    status = STATUS_BUFFER_TOO_SMALL;\n                    break;\n                }\n            }\n            else\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n                break;\n            }\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n    }\n\n    if (BytesInUtf8String)\n    {\n        *BytesInUtf8String = bytesInUtf8String;\n    }\n\n    return status;\n#endif\n}\n\n/**\n * Converts a UTF-16 encoded wide string to a UTF-8 encoded byte array.\n *\n * \\param Buffer Pointer to a null-terminated UTF-16 string (PCWSTR) to be converted.\n * \\return A pointer to a PPH_BYTES structure containing the UTF-8 encoded result.\n * \\remarks Returns NULL if the conversion fails.\n */\n _Use_decl_annotations_\nPPH_BYTES PhConvertUtf16ToUtf8(\n    _In_ PCWSTR Buffer\n    )\n{\n    return PhConvertUtf16ToUtf8Ex(\n        Buffer,\n        PhCountStringZ(Buffer) * sizeof(WCHAR)\n        );\n}\n\n_Use_decl_annotations_\nPPH_BYTES PhConvertUtf16ToUtf8Ex(\n    _In_ PCWCH Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    NTSTATUS status;\n    PPH_BYTES bytes;\n    SIZE_T utf8Bytes;\n\n    status = PhConvertUtf16ToUtf8Size(\n        &utf8Bytes,\n        Buffer,\n        Length\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    bytes = PhCreateBytesEx(NULL, utf8Bytes);\n    status = PhConvertUtf16ToUtf8Buffer(\n        bytes->Buffer,\n        bytes->Length,\n        NULL,\n        Buffer,\n        Length\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(bytes);\n        return NULL;\n    }\n\n    return bytes;\n}\n\n/**\n * Initializes a string builder object.\n *\n * \\param StringBuilder A string builder object.\n * \\param InitialCapacity The number of bytes to allocate initially.\n */\nVOID PhInitializeStringBuilder(\n    _Out_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T InitialCapacity\n    )\n{\n    // Make sure the initial capacity is even, as required for all string objects.\n    if (InitialCapacity & 1)\n        InitialCapacity++;\n\n    StringBuilder->AllocatedLength = InitialCapacity;\n\n    // Allocate a PH_STRING for the string builder.\n    // We will dereference it and allocate a new one when we need to resize the string.\n\n    StringBuilder->String = PhCreateStringEx(NULL, StringBuilder->AllocatedLength);\n\n    // We will keep modifying the Length field of the string so that:\n    // 1. We know how much of the string is used, and\n    // 2. The user can simply get a reference to the string and use it as-is.\n\n    StringBuilder->String->Length = 0;\n\n    // Write the null terminator.\n    StringBuilder->String->Buffer[0] = UNICODE_NULL;\n\n    PHLIB_INC_STATISTIC(BaseStringBuildersCreated);\n}\n\n/**\n * Frees resources used by a string builder object.\n *\n * \\param StringBuilder A string builder object.\n */\nVOID PhDeleteStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    )\n{\n    PhDereferenceObject(StringBuilder->String);\n}\n\n/**\n * Obtains a reference to the string constructed by a string builder object and frees resources used\n * by the object.\n *\n * \\param StringBuilder A string builder object.\n *\n * \\return A pointer to a string. You must free the string using PhDereferenceObject() when you no\n * longer need it.\n */\nPPH_STRING PhFinalStringBuilderString(\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    )\n{\n    return StringBuilder->String;\n}\n\nVOID PhpResizeStringBuilder(\n    _In_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T NewCapacity\n    )\n{\n    PPH_STRING newString;\n\n    // Double the string size. If that still isn't enough room, just use the new length.\n\n    StringBuilder->AllocatedLength *= 2;\n\n    if (StringBuilder->AllocatedLength < NewCapacity)\n        StringBuilder->AllocatedLength = NewCapacity;\n\n    // Allocate a new string.\n    newString = PhCreateStringEx(NULL, StringBuilder->AllocatedLength);\n\n    // Copy the old string to the new string.\n    memcpy(\n        newString->Buffer,\n        StringBuilder->String->Buffer,\n        StringBuilder->String->Length + sizeof(UNICODE_NULL) // Include null terminator\n        );\n\n    // Copy the old string length.\n    newString->Length = StringBuilder->String->Length;\n\n    // Dereference the old string and replace it with the new string.\n    PhMoveReference(&StringBuilder->String, newString);\n\n    PHLIB_INC_STATISTIC(BaseStringBuildersResized);\n}\n\nFORCEINLINE VOID PhpWriteNullTerminatorStringBuilder(\n    _In_ PPH_STRING_BUILDER StringBuilder\n    )\n{\n    assert(!(StringBuilder->String->Length & 1));\n    *(PWCHAR)PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length) = UNICODE_NULL;\n}\n\n/**\n * Appends a string to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param String The string to append. Specify NULL to simply reserve \\a Length bytes.\n * \\param Length The number of bytes to append.\n */\nVOID PhAppendStringBuilderEx(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_opt_ PWCHAR String,\n    _In_ SIZE_T Length\n    )\n{\n    if (Length == 0)\n        return;\n\n    // See if we need to re-allocate the string.\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Length)\n    {\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Length);\n    }\n\n    // Copy the string, add the length, then write the null terminator.\n\n    if (String)\n    {\n        memcpy(\n            PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length),\n            String,\n            Length\n            );\n    }\n\n    StringBuilder->String->Length += Length;\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Appends a character to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Character The character to append.\n */\nVOID PhAppendCharStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ WCHAR Character\n    )\n{\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + sizeof(WCHAR))\n    {\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + sizeof(WCHAR));\n    }\n\n    *(PWCHAR)PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length) = Character;\n    StringBuilder->String->Length += sizeof(WCHAR);\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Appends a number of characters to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Character The character to append.\n * \\param Count The number of times to append the character.\n */\nVOID PhAppendCharStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ WCHAR Character,\n    _In_ SIZE_T Count\n    )\n{\n    if (Count == 0)\n        return;\n\n    // See if we need to re-allocate the string.\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Count * sizeof(WCHAR))\n    {\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Count * sizeof(WCHAR));\n    }\n\n    wmemset(\n        PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length),\n        Character,\n        Count\n        );\n\n    StringBuilder->String->Length += Count * sizeof(WCHAR);\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Appends a formatted string to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Format The format-control string.\n * \\param ... The list of strings.\n */\nVOID PhAppendFormatStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ _Printf_format_string_ PCWSTR Format,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Format);\n    PhAppendFormatStringBuilder_V(StringBuilder, Format, argptr);\n    va_end(argptr);\n}\n\n/**\n * Appends a formatted string to the specified string builder using a variable argument list.\n *\n * \\param StringBuilder A pointer to the string builder to which the formatted string will be appended.\n * \\param Format A printf-style format string that specifies how to format the arguments.\n * \\param ArgPtr A va_list containing the arguments to format according to the format string.\n */\nVOID PhAppendFormatStringBuilder_V(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ _Printf_format_string_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    LONG length;\n    SIZE_T lengthInBytes;\n\n    length = _vscwprintf(Format, ArgPtr);\n\n    if (length == INT_ERROR || length == 0)\n        return;\n\n    lengthInBytes = length * sizeof(WCHAR);\n\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + lengthInBytes)\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + lengthInBytes);\n\n    _vsnwprintf(\n        PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length),\n        length,\n        Format,\n        ArgPtr\n        );\n\n    StringBuilder->String->Length += lengthInBytes;\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Inserts a string into a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Index The index, in characters, at which to insert the string.\n * \\param String The string to insert.\n */\nVOID PhInsertStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_ PCPH_STRINGREF String\n    )\n{\n    PhInsertStringBuilderEx(\n        StringBuilder,\n        Index,\n        String->Buffer,\n        String->Length\n        );\n}\n\n/**\n * Inserts a string into a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Index The index, in characters, at which to insert the string.\n * \\param String The string to insert.\n */\nVOID PhInsertStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_ PCWSTR String\n    )\n{\n    PhInsertStringBuilderEx(\n        StringBuilder,\n        Index,\n        String,\n        PhCountStringZ(String) * sizeof(WCHAR)\n        );\n}\n\n/**\n * Inserts a string into a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Index The index, in characters, at which to insert the string.\n * \\param String The string to insert. Specify NULL to simply reserve \\a Length bytes at \\a Index.\n * \\param Length The number of bytes to insert.\n */\nVOID PhInsertStringBuilderEx(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_opt_ PCWCHAR String,\n    _In_ SIZE_T Length\n    )\n{\n    if (Length == 0)\n        return;\n\n    // See if we need to re-allocate the string.\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Length)\n    {\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Length);\n    }\n\n    if (Index * sizeof(WCHAR) < StringBuilder->String->Length)\n    {\n        // Create some space for the string.\n        memmove(\n            &StringBuilder->String->Buffer[Index + Length / sizeof(WCHAR)],\n            &StringBuilder->String->Buffer[Index],\n            StringBuilder->String->Length - Index * sizeof(WCHAR)\n            );\n    }\n\n    if (String)\n    {\n        // Copy the new string.\n        memcpy(\n            &StringBuilder->String->Buffer[Index],\n            String,\n            Length\n            );\n    }\n\n    StringBuilder->String->Length += Length;\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Removes characters from a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param StartIndex The index, in characters, at which to begin removing characters.\n * \\param Count The number of characters to remove.\n */\nVOID PhRemoveStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    )\n{\n    // Overwrite the removed part with the part\n    // behind it.\n\n    memmove(\n        &StringBuilder->String->Buffer[StartIndex],\n        &StringBuilder->String->Buffer[StartIndex + Count],\n        StringBuilder->String->Length - (Count + StartIndex) * sizeof(WCHAR)\n        );\n    StringBuilder->String->Length -= Count * sizeof(WCHAR);\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Initializes a byte string builder object.\n *\n * \\param BytesBuilder A byte string builder object.\n * \\param InitialCapacity The number of bytes to allocate initially.\n */\nVOID PhInitializeBytesBuilder(\n    _Out_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ SIZE_T InitialCapacity\n    )\n{\n    BytesBuilder->AllocatedLength = InitialCapacity;\n    BytesBuilder->Bytes = PhCreateBytesEx(NULL, BytesBuilder->AllocatedLength);\n    BytesBuilder->Bytes->Length = 0;\n    BytesBuilder->Bytes->Buffer[0] = ANSI_NULL;\n}\n\n/**\n * Frees resources used by a byte string builder object.\n *\n * \\param BytesBuilder A byte string builder object.\n */\nVOID PhDeleteBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder\n    )\n{\n    PhDereferenceObject(BytesBuilder->Bytes);\n}\n\n/**\n * Obtains a reference to the byte string constructed by a byte string builder object and frees\n * resources used by the object.\n *\n * \\param BytesBuilder A byte string builder object.\n * \\return A pointer to a byte string. You must free the byte string using PhDereferenceObject()\n * when you no longer need it.\n */\nPPH_BYTES PhFinalBytesBuilderBytes(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder\n    )\n{\n    return BytesBuilder->Bytes;\n}\n\nVOID PhpResizeBytesBuilder(\n    _In_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ SIZE_T NewCapacity\n    )\n{\n    PPH_BYTES newBytes;\n\n    // Double the byte string size. If that still isn't enough room, just use the new length.\n\n    BytesBuilder->AllocatedLength *= 2;\n\n    if (BytesBuilder->AllocatedLength < NewCapacity)\n        BytesBuilder->AllocatedLength = NewCapacity;\n\n    // Allocate a new byte string.\n    newBytes = PhCreateBytesEx(NULL, BytesBuilder->AllocatedLength);\n\n    // Copy the old byte string to the new byte string.\n    memcpy(\n        newBytes->Buffer,\n        BytesBuilder->Bytes->Buffer,\n        BytesBuilder->Bytes->Length + sizeof(ANSI_NULL) // Include null terminator\n        );\n\n    // Copy the old byte string length.\n    newBytes->Length = BytesBuilder->Bytes->Length;\n\n    // Dereference the old byte string and replace it with the new byte string.\n    PhMoveReference(&BytesBuilder->Bytes, newBytes);\n}\n\nFORCEINLINE VOID PhpWriteNullTerminatorBytesBuilder(\n    _In_ PPH_BYTES_BUILDER BytesBuilder\n    )\n{\n    BytesBuilder->Bytes->Buffer[BytesBuilder->Bytes->Length] = ANSI_NULL;\n}\n\n/**\n * Appends a byte string to the end of a byte string builder string.\n *\n * \\param BytesBuilder A byte string builder object.\n * \\param Bytes The byte string to append.\n */\nVOID PhAppendBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ PPH_BYTESREF Bytes\n    )\n{\n    PhAppendBytesBuilderEx(\n        BytesBuilder,\n        Bytes->Buffer,\n        Bytes->Length,\n        0,\n        NULL\n        );\n}\n\n/**\n * Appends a byte string to the end of a byte string builder string.\n *\n * \\param BytesBuilder A byte string builder object.\n * \\param Buffer The byte string to append. Specify NULL to simply reserve \\a Length bytes.\n * \\param Length The number of bytes to append.\n * \\param Alignment The required alignment. This should not be greater than 8.\n * \\param Offset A variable which receives the byte offset of the appended or reserved bytes in the\n * byte string builder string.\n *\n * \\return A pointer to the appended or reserved bytes.\n */\nPVOID PhAppendBytesBuilderEx(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_opt_ PVOID Buffer,\n    _In_ SIZE_T Length,\n    _In_opt_ SIZE_T Alignment,\n    _Out_opt_ PSIZE_T Offset\n    )\n{\n    SIZE_T currentLength;\n\n    currentLength = BytesBuilder->Bytes->Length;\n\n    if (Length == 0)\n        goto Done;\n\n    if (Alignment)\n        currentLength = ALIGN_UP_BY(currentLength, Alignment);\n\n    // See if we need to re-allocate the byte string.\n    if (BytesBuilder->AllocatedLength < currentLength + Length)\n        PhpResizeBytesBuilder(BytesBuilder, currentLength + Length);\n\n    // Copy the byte string, add the length, then write the null terminator.\n\n    if (Buffer)\n        memcpy(BytesBuilder->Bytes->Buffer + currentLength, Buffer, Length);\n\n    BytesBuilder->Bytes->Length = currentLength + Length;\n    PhpWriteNullTerminatorBytesBuilder(BytesBuilder);\n\nDone:\n    if (Offset)\n        *Offset = currentLength;\n\n    return BytesBuilder->Bytes->Buffer + currentLength;\n}\n\n/**\n * Appends formatted data to a bytes builder using a variable argument list.\n *\n * \\param BytesBuilder Pointer to the bytes builder structure to which the formatted data will be appended.\n * \\param Format A printf-style format string specifying how to format the data.\n * \\param ArgPtr A variable argument list containing the values to format according to the Format string.\n */\nVOID PhAppendFormatBytesBuilder_V(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ _Printf_format_string_ PCSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    LONG length;\n    SIZE_T lengthInBytes;\n\n    length = _vscprintf(Format, ArgPtr);\n\n    if (length == INT_ERROR || length == 0)\n        return;\n\n    lengthInBytes = length * sizeof(CHAR);\n\n    if (BytesBuilder->AllocatedLength < BytesBuilder->Bytes->Length + lengthInBytes)\n        PhpResizeBytesBuilder(BytesBuilder, BytesBuilder->Bytes->Length + lengthInBytes);\n\n    _vsnprintf(\n        PTR_ADD_OFFSET(BytesBuilder->Bytes->Buffer, BytesBuilder->Bytes->Length),\n        length,\n        Format,\n        ArgPtr\n        );\n\n    BytesBuilder->Bytes->Length += lengthInBytes;\n    PhpWriteNullTerminatorBytesBuilder(BytesBuilder);\n}\n\n/**\n * Appends formatted data to a bytes builder.\n *\n * This function formats a string using the specified format and arguments,\n * then appends the resulting bytes to the provided bytes builder.\n *\n * \\param BytesBuilder A pointer to the bytes builder structure to which the formatted bytes will be appended.\n * \\param Format A printf-style format string specifying how to format the data.\n * \\param ... Additional arguments to be formatted according to the format string.\n */\nVOID PhAppendFormatBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ _Printf_format_string_ PCSTR Format,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Format);\n    PhAppendFormatBytesBuilder_V(BytesBuilder, Format, argptr);\n    va_end(argptr);\n}\n\n/**\n * Generates a hash code for a string.\n *\n * \\param String The string to hash.\n * \\param IgnoreCase TRUE for a case-insensitive hash function, otherwise FALSE.\n */\nULONG PhHashStringRefOriginal(\n    _In_ PCPH_STRINGREF String,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    ULONG hash = 0;\n    SIZE_T count;\n    PWCHAR p;\n\n    if (String->Length == 0)\n        return 0;\n\n    count = String->Length / sizeof(WCHAR);\n    p = String->Buffer;\n\n    if (IgnoreCase)\n    {\n        while (count-- != 0)\n        {\n            hash ^= (USHORT)PhUpcaseUnicodeChar(*p++);\n            hash *= 0x01000193;\n        }\n    }\n    else\n    {\n        return PhHashBytes((PUCHAR)String->Buffer, String->Length);\n    }\n\n    return hash;\n}\n\n/**\n * Generates a hash code for a string.\n *\n * \\param String The string to hash.\n * \\param IgnoreCase TRUE for a case-insensitive hash function, otherwise FALSE.\n */\nULONG PhHashStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    ULONG hash = 0;\n    SIZE_T count;\n    PWCHAR p;\n\n    if (String->Length == 0)\n        return 0;\n\n    count = String->Length / sizeof(WCHAR);\n    p = String->Buffer;\n\n    if (IgnoreCase)\n    {\n#ifndef _ARM64_\n        if (PhHasAVX && count >= 16)\n        {\n            // AVX hash path for case-insensitive\n            SIZE_T length32 = count / 16;\n            WCHAR uppercased[16];\n\n            for (SIZE_T i = 0; i < length32; i++)\n            {\n                __m256i chunk;\n\n                chunk = _mm256_loadu_si256((__m256i const*)p);\n                chunk = PhUppercaseLatin1INT256by16(chunk);\n                _mm256_storeu_si256((__m256i*)uppercased, chunk);\n\n                // Hash 16 uppercased characters\n                for (ULONG j = 0; j < 16; j++)\n                {\n                    hash ^= (USHORT)uppercased[j];\n                    hash *= 0x01000193;\n                }\n\n                p += 16;\n            }\n\n            _mm256_zeroupper();\n            count %= 16;\n        }\n#endif\n\n        if (PhHasIntrinsics && count >= 8)\n        {\n            // SIMD hash path for case-insensitive\n            SIZE_T length16 = count / 8;\n            WCHAR uppercased[8];\n\n            for (SIZE_T i = 0; i < length16; i++)\n            {\n                PH_INT128 chunk;\n\n                chunk = PhLoadINT128U((PLONG)p);\n                chunk = PhUppercaseLatin1INT128by16(chunk);\n                PhStoreINT128U((PLONG)uppercased, chunk);\n\n                // Hash 8 uppercased characters\n                for (ULONG j = 0; j < 8; j++)\n                {\n                    hash ^= (USHORT)uppercased[j];\n                    hash *= 0x01000193;\n                }\n\n                p += 8;\n            }\n\n            count %= 8;\n        }\n\n        while (count-- != 0)\n        {\n            hash ^= (USHORT)PhUpcaseUnicodeChar(*p++);\n            hash *= 0x01000193;\n        }\n    }\n    else\n    {\n        return PhHashBytes((PUCHAR)String->Buffer, String->Length);\n    }\n\n    return hash;\n}\n\n/**\n * Computes a hash value for the specified string reference using the given hash algorithm.\n *\n * \\param String Pointer to a PH_STRINGREF structure representing the string to hash.\n * \\param IgnoreCase If TRUE, the hash computation ignores case differences; otherwise, case is considered.\n * \\param HashAlgorithm The hash algorithm to use for computing the hash value.\n * \\return The computed hash value as an unsigned long.\n */\nULONG PhHashStringRefEx(\n    _In_ PCPH_STRINGREF String,\n    _In_ BOOLEAN IgnoreCase,\n    _In_ PH_STRING_HASH HashAlgorithm\n    )\n{\n    switch (HashAlgorithm)\n    {\n    case PH_STRING_HASH_DEFAULT:\n    case PH_STRING_HASH_FNV1A:\n        return PhHashStringRef(String, IgnoreCase);\n    case PH_STRING_HASH_X65599:\n        {\n            ULONG hash = 0;\n            PWCHAR end;\n            PWCHAR p;\n\n            if (String->Length == 0)\n                return 0;\n\n            end = String->Buffer + (String->Length / sizeof(WCHAR));\n            p = String->Buffer;\n\n            if (IgnoreCase)\n            {\n#ifndef _ARM64_\n                if (PhHasAVX && (end - p) >= 16)\n                {\n                    // AVX hash path for case-insensitive\n                    SIZE_T count = (end - p) / 16;\n                    WCHAR uppercased[16];\n\n                    for (SIZE_T i = 0; i < count; i++)\n                    {\n                        __m256i chunk;\n\n                        chunk = _mm256_loadu_si256((__m256i const*)p);\n                        chunk = PhUppercaseLatin1INT256by16(chunk);\n                        _mm256_storeu_si256((__m256i*)uppercased, chunk);\n\n                        // Hash 16 uppercased characters\n                        for (ULONG j = 0; j < 16; j++)\n                        {\n                            hash = ((65599 * (hash)) + (ULONG)uppercased[j]);\n                        }\n\n                        p += 16;\n                    }\n\n                    _mm256_zeroupper();\n                }\n#endif\n                for (; p != end; p++)\n                {\n                    hash = ((65599 * (hash)) + (ULONG)(((*p) >= L'a' && (*p) <= L'z') ? (*p) - L'a' + L'A' : (*p)));\n                }\n\n                // Medium fast\n                //UNICODE_STRING unicodeString;\n                //\n                //if (!PhStringRefToUnicodeString(String, &unicodeString))\n                //    return 0;\n                //\n                //if (!NT_SUCCESS(RtlHashUnicodeString(&unicodeString, TRUE, HASH_STRING_ALGORITHM_X65599, &hash)))\n                //    return 0;\n                //\n                // Slower than the above two (based on PhHashBytes) (dmex)\n                //SIZE_T count = String->Length / sizeof(WCHAR);\n                //PWCHAR p = String->Buffer;\n                //do\n                //{\n                //    hash += (USHORT)PhUpcaseUnicodeChar(*p++); // __ascii_towupper(*p++);\n                //    hash *= 0x1003F;\n                //} while (--count != 0);\n            }\n            else\n            {\n#ifndef _ARM64_\n                if (PhHasAVX && (end - p) >= 16)\n                {\n                    // AVX hash path for case-sensitive\n                    SIZE_T count = (end - p) / 16;\n                    WCHAR buffer[16];\n\n                    for (SIZE_T i = 0; i < count; i++)\n                    {\n                        __m256i chunk;\n\n                        chunk = _mm256_loadu_si256((__m256i const*)p);\n                        _mm256_storeu_si256((__m256i*)buffer, chunk);\n\n                        // Hash 16 characters\n                        for (ULONG j = 0; j < 16; j++)\n                        {\n                            hash = ((65599 * (hash)) + (ULONG)buffer[j]);\n                        }\n\n                        p += 16;\n                    }\n\n                    _mm256_zeroupper();\n                }\n#endif\n                for (; p != end; p++)\n                {\n                    hash = ((65599 * (hash)) + (ULONG)(*p));\n                }\n            }\n\n            return hash;\n        }\n    case PH_STRING_HASH_XXH32:\n        {\n            if (String->Length == 0)\n                return 0;\n\n            return PhHashXXH32(String->Buffer, String->Length, 0);\n        }\n    }\n\n    return 0;\n}\n\n/**\n * Converts a sequence of hexadecimal digits into a byte array.\n *\n * \\param String A string containing hexadecimal digits to convert. The string must have an even\n * number of digits, because each pair of hexadecimal digits represents one byte. Example:\n * \"129a2eff5c0b\".\n * \\param Buffer The output buffer.\n * \\return TRUE if the string was successfully converted, otherwise FALSE.\n */\nBOOLEAN PhHexStringToBuffer(\n    _In_ PCPH_STRINGREF String,\n    _Out_writes_bytes_(String->Length / sizeof(WCHAR) / 2) PUCHAR Buffer\n    )\n{\n    SIZE_T i;\n    SIZE_T length;\n\n    // The string must have an even length.\n    if ((String->Length / sizeof(WCHAR)) & 1)\n        return FALSE;\n\n    length = String->Length / sizeof(WCHAR) / 2;\n\n    for (i = 0; i < length; i++)\n    {\n        Buffer[i] =\n            (UCHAR)(PhCharToInteger[(UCHAR)String->Buffer[i * sizeof(WCHAR)]] << 4) +\n            (UCHAR)PhCharToInteger[(UCHAR)String->Buffer[i * sizeof(WCHAR) + 1]];\n    }\n\n    return TRUE;\n}\n\n/**\n * Converts a hexadecimal string to a binary buffer.\n *\n * \\param String Pointer to a PH_STRINGREF structure containing the hexadecimal string to convert.\n * \\param BufferLength The length, in bytes, of the output buffer.\n * \\param Buffer Pointer to the buffer that receives the converted binary data. Must be at least BufferLength bytes.\n * \\return TRUE if the conversion was successful; FALSE otherwise.\n */\nBOOLEAN PhHexStringToBufferEx(\n    _In_ PCPH_STRINGREF String,\n    _In_ SIZE_T BufferLength,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer\n    )\n{\n    SIZE_T length;\n    SIZE_T i;\n\n    if ((String->Length / sizeof(WCHAR)) & 1)\n        return FALSE;\n\n    length = String->Length / sizeof(WCHAR) / 2;\n\n    if (length > BufferLength)\n        return FALSE;\n\n    for (i = 0; i < length; i++)\n    {\n        ((PBYTE)Buffer)[i] =\n            (BYTE)(PhCharToInteger[(BYTE)String->Buffer[i * sizeof(WCHAR)]] << 4) +\n            (BYTE)PhCharToInteger[(BYTE)String->Buffer[i * sizeof(WCHAR) + 1]];\n    }\n\n    return TRUE;\n}\n\n/**\n * Converts a byte array into a sequence of hexadecimal digits.\n *\n * \\param Buffer The input buffer.\n * \\param Length The number of bytes to convert.\n * \\return A string containing a sequence of hexadecimal digits.\n */\n_Use_decl_annotations_\nPPH_STRING PhBufferToHexString(\n    _In_reads_bytes_(Length) PUCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    return PhBufferToHexStringEx(Buffer, Length, FALSE);\n}\n\n/**\n * Converts a byte array into a sequence of hexadecimal digits.\n *\n * \\param Buffer The input buffer.\n * \\param Length The number of bytes to convert.\n * \\param UpperCase TRUE to use uppercase characters, otherwise FALSE.\n * \\return A string containing a sequence of hexadecimal digits.\n */\n_Use_decl_annotations_\nPPH_STRING PhBufferToHexStringEx(\n    _In_reads_bytes_(Length) PUCHAR Buffer,\n    _In_ SIZE_T Length,\n    _In_ BOOLEAN UpperCase\n    )\n{\n    PPH_STRING string;\n    PCCH table;\n    SIZE_T i;\n\n    if (UpperCase)\n        table = PhIntegerToCharUpper;\n    else\n        table = PhIntegerToChar;\n\n    string = PhCreateStringEx(NULL, Length * sizeof(WCHAR) * 2);\n\n    for (i = 0; i < Length; i++)\n    {\n        string->Buffer[i * sizeof(WCHAR)] = table[Buffer[i] >> 4];\n        string->Buffer[i * sizeof(WCHAR) + 1] = table[Buffer[i] & 0xf];\n    }\n\n    return string;\n}\n\n/**\n * Converts a binary buffer to a hexadecimal string representation.\n *\n * \\param InputBuffer Pointer to the input buffer containing binary data.\n * \\param InputLength Length of the input buffer, in bytes.\n * \\param UpperCase If TRUE, output hex digits in uppercase; otherwise, lowercase.\n * \\param OutputBuffer Pointer to the buffer that receives the hexadecimal string.\n * \\param OutputLength Size of the output buffer, in bytes.\n * \\param ReturnLength Optional pointer to receive the number of bytes written to OutputBuffer.\n * \\return TRUE if the conversion was successful and the output buffer was large enough; FALSE otherwise.\n */\n_Use_decl_annotations_\nBOOLEAN PhBufferToHexStringBuffer(\n    _In_reads_bytes_(InputLength) PUCHAR InputBuffer,\n    _In_ SIZE_T InputLength,\n    _In_ BOOLEAN UpperCase,\n    _Out_writes_bytes_to_(OutputLength, *ReturnLength) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    PCCH table;\n    ULONG i;\n\n    if (OutputLength < InputLength * sizeof(WCHAR) * 2)\n    {\n        if (ReturnLength)\n            *ReturnLength = InputLength * sizeof(WCHAR) * 2;\n        return FALSE;\n    }\n\n    if (UpperCase)\n        table = PhIntegerToCharUpper;\n    else\n        table = PhIntegerToChar;\n\n    for (i = 0; i < InputLength; i++)\n    {\n        OutputBuffer[i * sizeof(WCHAR)] = table[InputBuffer[i] >> 4];\n        OutputBuffer[i * sizeof(WCHAR) + 1] = table[InputBuffer[i] & 0xf];\n    }\n\n    OutputBuffer[i * sizeof(WCHAR)] = UNICODE_NULL;\n\n    if (ReturnLength)\n        *ReturnLength = i * sizeof(WCHAR) * 2;\n\n    return TRUE;\n}\n\n/**\n * Converts a string to an integer.\n *\n * \\param String The string to process.\n * \\param Base The base which the string uses to represent the integer. The maximum value is 69.\n * \\param Integer The resulting integer.\n */\nBOOLEAN PhpStringToInteger64(\n    _In_ PCPH_STRINGREF String,\n    _In_ ULONG Base,\n    _Out_opt_ PULONG64 Integer\n    )\n{\n    BOOLEAN valid = TRUE;\n    ULONG64 result;\n    SIZE_T length;\n    SIZE_T i;\n\n    length = String->Length / sizeof(WCHAR);\n    result = 0;\n\n    for (i = 0; i < length; i++)\n    {\n        ULONG value;\n\n        value = PhCharToInteger[(UCHAR)String->Buffer[i]];\n\n        if (value < Base)\n            result = result * Base + value;\n        else\n            valid = FALSE;\n    }\n\n    if (Integer)\n    {\n        *Integer = result;\n    }\n\n    return valid;\n}\n\n/**\n * Converts a string to an integer.\n *\n * \\param String The string to process.\n * \\param Base The base which the string uses to represent the integer. The maximum value is 69. If\n * the parameter is 0, the base is inferred from the string.\n * \\param Integer The resulting integer.\n *\n * \\remarks If \\a Base is 0, the following prefixes may be used to indicate bases:\n *\n * \\li \\c 0x Base 16.\n * \\li \\c 0o Base 8.\n * \\li \\c 0b Base 2.\n * \\li \\c 0t Base 3.\n * \\li \\c 0q Base 4.\n * \\li \\c 0w Base 12.\n * \\li \\c 0r Base 32.\n *\n * If there is no recognized prefix, base 10 is used.\n */\n_Use_decl_annotations_\nBOOLEAN PhStringToInteger64(\n    _In_ PCPH_STRINGREF String,\n    _In_opt_ ULONG Base,\n    _Out_opt_ PLONG64 Integer\n    )\n{\n    BOOLEAN valid;\n    ULONG64 result;\n    PH_STRINGREF string;\n    BOOLEAN negative;\n    ULONG base;\n\n    if (Base > 69)\n        return FALSE;\n\n    string = *String;\n    negative = FALSE;\n\n    if (string.Length != 0 && (string.Buffer[0] == L'-' || string.Buffer[0] == L'+'))\n    {\n        if (string.Buffer[0] == L'-')\n            negative = TRUE;\n\n        PhSkipStringRef(&string, sizeof(WCHAR));\n    }\n\n    // If the caller specified a base, don't perform any additional processing.\n\n    if (Base)\n    {\n        base = Base;\n    }\n    else\n    {\n        base = 10;\n\n        if (string.Length >= 2 * sizeof(WCHAR) && string.Buffer[0] == L'0')\n        {\n            switch (string.Buffer[1])\n            {\n            case L'x':\n            case L'X':\n                base = 16;\n                break;\n            case L'o':\n            case L'O':\n                base = 8;\n                break;\n            case L'b':\n            case L'B':\n                base = 2;\n                break;\n            case L't': // ternary\n            case L'T':\n                base = 3;\n                break;\n            case L'q': // quaternary\n            case L'Q':\n                base = 4;\n                break;\n            case L'w': // base 12\n            case L'W':\n                base = 12;\n                break;\n            case L'r': // base 32\n            case L'R':\n                base = 32;\n                break;\n            }\n\n            if (base != 10)\n                PhSkipStringRef(&string, 2 * sizeof(WCHAR));\n        }\n    }\n\n    valid = PhpStringToInteger64(&string, base, &result);\n\n    if (Integer)\n        *Integer = negative ? -(LONG64)result : result;\n\n    return valid;\n}\n\n/**\n * Converts a string reference to an unsigned 64-bit integer.\n *\n * \\param String Pointer to a PH_STRINGREF structure containing the string to convert.\n * \\param Base Optional base for conversion (e.g., 10 for decimal, 16 for hexadecimal).\n * \\param Integer Optional pointer to a ULONG64 variable that receives the converted value.\n * \\return TRUE if the conversion was successful; otherwise, FALSE.\n */\n_Use_decl_annotations_\nBOOLEAN PhStringToUInt64(\n    _In_ PCPH_STRINGREF String,\n    _In_opt_ ULONG Base,\n    _Out_opt_ PULONG64 Integer\n    )\n{\n    PH_STRINGREF string;\n    ULONG base;\n\n    if (Base > 69)\n        return FALSE;\n\n    string = *String;\n\n    if (string.Length != 0 && (string.Buffer[0] == L'-' || string.Buffer[0] == L'+'))\n    {\n        PhSkipStringRef(&string, sizeof(WCHAR));\n    }\n\n    // If the caller specified a base, don't perform any additional processing.\n\n    if (Base)\n    {\n        base = Base;\n    }\n    else\n    {\n        base = 10;\n\n        if (string.Length >= 2 * sizeof(WCHAR) && string.Buffer[0] == L'0')\n        {\n            switch (string.Buffer[1])\n            {\n            case L'x':\n            case L'X':\n                base = 16;\n                break;\n            case L'o':\n            case L'O':\n                base = 8;\n                break;\n            case L'b':\n            case L'B':\n                base = 2;\n                break;\n            case L't': // ternary\n            case L'T':\n                base = 3;\n                break;\n            case L'q': // quaternary\n            case L'Q':\n                base = 4;\n                break;\n            case L'w': // base 12\n            case L'W':\n                base = 12;\n                break;\n            case L'r': // base 32\n            case L'R':\n                base = 32;\n                break;\n            }\n\n            if (base != 10)\n                PhSkipStringRef(&string, 2 * sizeof(WCHAR));\n        }\n    }\n\n    return PhpStringToInteger64(&string, base, Integer);\n}\n\nBOOLEAN PhpStringToDouble(\n    _In_ PCPH_STRINGREF String,\n    _In_ ULONG Base,\n    _Out_ DOUBLE *Double\n    )\n{\n    BOOLEAN valid = TRUE;\n    BOOLEAN dotSeen = FALSE;\n    DOUBLE result;\n    DOUBLE fraction;\n    SIZE_T length;\n    SIZE_T i;\n\n    length = String->Length / sizeof(WCHAR);\n    result = 0;\n    fraction = 1;\n\n    for (i = 0; i < length; i++)\n    {\n        if (String->Buffer[i] == L'.')\n        {\n            if (!dotSeen)\n                dotSeen = TRUE;\n            else\n                valid = FALSE;\n        }\n        else\n        {\n            ULONG value;\n\n            value = PhCharToInteger[(UCHAR)String->Buffer[i]];\n\n            if (value < Base)\n            {\n                if (!dotSeen)\n                {\n                    result = result * Base + value;\n                }\n                else\n                {\n                    fraction /= Base;\n                    result = result + value * fraction;\n                }\n            }\n            else\n            {\n                valid = FALSE;\n            }\n        }\n    }\n\n    *Double = result;\n\n    return valid;\n}\n\n/**\n * Converts a string to a double-precision floating point value.\n *\n * \\param String The string to process.\n * \\param Base Reserved.\n * \\param Double The resulting double value.\n */\nBOOLEAN PhStringToDouble(\n    _In_ PCPH_STRINGREF String,\n    _Reserved_ ULONG Base,\n    _Out_opt_ DOUBLE *Double\n    )\n{\n    BOOLEAN valid;\n    DOUBLE result;\n    PH_STRINGREF string;\n    BOOLEAN negative;\n\n    string = *String;\n    negative = FALSE;\n\n    if (string.Length != 0 && (string.Buffer[0] == L'-' || string.Buffer[0] == L'+'))\n    {\n        if (string.Buffer[0] == L'-')\n            negative = TRUE;\n\n        PhSkipStringRef(&string, sizeof(WCHAR));\n    }\n\n    valid = PhpStringToDouble(&string, 10, &result);\n\n    if (Double)\n        *Double = negative ? -result : result;\n\n    return valid;\n}\n\n/**\n * Converts an integer to a string.\n *\n * \\param Integer The integer to process.\n * \\param Base The base which the integer is represented with. The maximum value is 69. The base\n * cannot be 1. If the parameter is 0, the base used is 10.\n * \\param Signed TRUE if \\a Integer is a signed value, otherwise FALSE.\n *\n * \\return The resulting string, or NULL if an error occurred.\n */\n_Use_decl_annotations_\nPPH_STRING PhIntegerToString64(\n    _In_ LONG64 Integer,\n    _In_opt_ ULONG Base,\n    _In_ BOOLEAN Signed\n    )\n{\n    PH_FORMAT format;\n\n    if (Base == 1 || Base > 69)\n        return NULL;\n\n    if (Signed)\n        PhInitFormatI64D(&format, Integer);\n    else\n        PhInitFormatI64U(&format, Integer);\n\n    if (Base != 0)\n    {\n        format.Type |= FormatUseRadix;\n        format.Radix = (UCHAR)Base;\n    }\n\n    return PhFormat(&format, 1, 0);\n}\n\n// PhDoesNameContainWildCards and PhIsNameInExpression compared to\n// RtlDoesNameContainWildCards and RtlIsNameInExpression (dmex)\n// - Full wildcard support:\n// - * -Standard wildcard - zero or more any chars\n// - ? -Single character wildcard\n// - < (ANSI_DOS_STAR) - Zero or more chars until dot\n// - > (ANSI_DOS_QM) - Zero or one char (not dot)\n// - \" (ANSI_DOS_DOT) - Zero or one dot\n// - DOS semantics:\n// -  -DOS_STAR(<) stops matching at dots (for filename matching like file<.txt)\n// -  -DOS_QM(>) matches 0 or 1 non-dot character.\n// -  -DOS_DOT(\") matches optional dot character.\n//\n// Example patterns:\n// - *chrome* - matches anything with \"chrome\"\n// - chrome.??? - matches chrome.exe, chrome.dll(3 - char extension)\n// - file<.txt - matches file.txt, fileabc.txt(< stops at dot)\n// - test>\" - matches test, testa, test. (> is 0-1 char, \" is optional dot)\n\n// replacement RtlDoesNameContainWildCards (dmex)\n/**\n * Determines whether a string contains wildcard characters.\n *\n * \\param Expression A pointer to the string to be checked.\n * \\return TRUE if one or more wildcard characters were found, FALSE otherwise.\n * \\remarks The following are wildcard characters: *, ?, ANSI_DOS_STAR (<), ANSI_DOS_DOT (\"), and ANSI_DOS_QM (>).\n */\nBOOLEAN PhDoesNameContainWildCards(\n    _In_ PCPH_STRINGREF Expression\n    )\n{\n    for (SIZE_T i = 0; i < Expression->Length / sizeof(WCHAR); i++)\n    {\n        WCHAR c = Expression->Buffer[i];\n        \n        if (c == L'*' ||\n            c == L'?' || \n            c == ANSI_DOS_STAR_W ||\n            c == ANSI_DOS_DOT_W ||\n            c == ANSI_DOS_QM_W\n            )\n        {\n            return TRUE;\n        }\n    }\n    \n    return FALSE;\n}\n\n// replacement RtlIsNameInExpression (dmex)\n/**\n * Determines whether a string matches the specified wildcard pattern.\n *\n * \\param Expression A pointer to the pattern string. Can contain wildcards: *, ?, < (DOS_STAR), > (DOS_QM), \" (DOS_DOT).\n * \\param Name A pointer to the string to match against the pattern.\n * \\param IgnoreCase TRUE for case-insensitive matching, FALSE for case-sensitive matching.\n * \\return TRUE if the string matches the pattern, FALSE otherwise.\n * \\remarks Wildcard semantics:\n *   * - Matches zero or more characters\n *   ? - Matches exactly one character\n *   < (ANSI_DOS_STAR) - Matches zero or more characters until dot or end\n *   > (ANSI_DOS_QM) - Matches zero or one character (not dot)\n *   \" (ANSI_DOS_DOT) - Matches zero or one dot\n */\nBOOLEAN PhIsNameInExpression(\n    _In_ PCPH_STRINGREF Expression,\n    _In_ PCPH_STRINGREF Name,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    SIZE_T exprLen = Expression->Length / sizeof(WCHAR);\n    SIZE_T nameLen = Name->Length / sizeof(WCHAR);\n    SIZE_T e = 0; // expression index\n    SIZE_T n = 0; // name index\n    SIZE_T starE = SIZE_MAX; // last * or < position in expression\n    SIZE_T starN = SIZE_MAX; // name position when * or < was encountered\n    BOOLEAN dosStarMode = FALSE; // TRUE if last star was DOS_STAR (<)\n\n    while (n < nameLen)\n    {\n        if (e < exprLen)\n        {\n            WCHAR exprChar = Expression->Buffer[e];\n            WCHAR nameChar = Name->Buffer[n];\n            WCHAR exprCharUpper = IgnoreCase ? PhUpcaseUnicodeChar(exprChar) : exprChar;\n            WCHAR nameCharUpper = IgnoreCase ? PhUpcaseUnicodeChar(nameChar) : nameChar;\n\n            // * - matches zero or more of any character\n            if (exprChar == L'*')\n            {\n                starE = e++;\n                starN = n;\n                dosStarMode = FALSE;\n                continue;\n            }\n            // < (ANSI_DOS_STAR) - matches zero or more characters until dot or end\n            else if (exprChar == ANSI_DOS_STAR_W)\n            {\n                starE = e++;\n                starN = n;\n                dosStarMode = TRUE;\n                continue;\n            }\n            // \" (ANSI_DOS_DOT) - matches zero or one dot\n            else if (exprChar == ANSI_DOS_DOT_W)\n            {\n                if (nameChar == L'.')\n                {\n                    e++;\n                    n++;\n                }\n                else\n                {\n                    e++; // skip the DOS_DOT, match zero dots\n                }\n                continue;\n            }\n            // > (ANSI_DOS_QM) - matches zero or one character (not dot)\n            else if (exprChar == ANSI_DOS_QM_W)\n            {\n                if (nameChar != L'.')\n                {\n                    e++;\n                    n++; // consume one character\n                }\n                else\n                {\n                    e++; // skip DOS_QM, match zero characters\n                }\n                continue;\n            }\n            // ? - matches exactly one character\n            else if (exprChar == L'?')\n            {\n                e++;\n                n++;\n                continue;\n            }\n            // Exact character match\n            else if (exprCharUpper == nameCharUpper)\n            {\n                e++;\n                n++;\n                continue;\n            }\n        }\n\n        // Mismatch - backtrack if we saw a * or <\n        if (starE != SIZE_MAX)\n        {\n            e = starE + 1;\n            n = ++starN;\n\n            // If in DOS_STAR mode, stop backtracking at dot\n            if (dosStarMode && starN < nameLen && Name->Buffer[starN] == L'.')\n            {\n                dosStarMode = FALSE;\n                starE = SIZE_MAX; // can't backtrack past dot\n            }\n            continue;\n        }\n\n        return FALSE;\n    }\n\n    // Consume remaining wildcards in expression\n    while (e < exprLen)\n    {\n        WCHAR c = Expression->Buffer[e];\n        \n        if (\n            c == L'*' ||\n            c == ANSI_DOS_STAR_W ||\n            c == ANSI_DOS_DOT_W ||\n            c == ANSI_DOS_QM_W\n            )\n        {\n            e++;\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    return e == exprLen;\n}\n\n/**\n * Performs fuzzy matching between a pattern and a text string.\n *\n * \\param Pattern A pointer to the search pattern.\n * \\param Text A pointer to the text to match against.\n * \\param IgnoreCase TRUE for case-insensitive matching, FALSE for case-sensitive matching.\n * \\return TRUE if the text fuzzy-matches the pattern, FALSE otherwise.\n * \\remarks Fuzzy matching allows characters from the pattern to appear in order\n * in the text, but not necessarily consecutively. his is useful for quick\n * filtering where users type a few key characters.\n */\nBOOLEAN PhStringFuzzyMatch(\n    _In_ PCPH_STRINGREF Pattern,\n    _In_ PCPH_STRINGREF Text,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    SIZE_T patternLength = Pattern->Length / sizeof(WCHAR);\n    SIZE_T textLength = Text->Length / sizeof(WCHAR);\n    SIZE_T p = 0; // pattern index\n    SIZE_T t = 0; // text index\n\n    if (patternLength == 0)\n        return TRUE;\n    if (textLength == 0)\n        return FALSE;\n\n    while (t < textLength && p < patternLength)\n    {\n        WCHAR pattern = Pattern->Buffer[p];\n        WCHAR text = Text->Buffer[t];\n\n        if (IgnoreCase)\n        {\n            pattern = PhUpcaseUnicodeChar(pattern);\n            text = PhUpcaseUnicodeChar(text);\n        }\n\n        if (pattern == text)\n        {\n            p++; // advance on match\n        }\n\n        t++; // always advance text\n    }\n\n    // Match succeeds if entire pattern was consumed\n    return (p == patternLength);\n}\n\n/**\n * Validate the string does not contain control or formatting content.\n *\n * Returns FALSE if the string is NULL, empty, all whitespace, or contains\n * control/formatting characters (RTLO, zero-width chars, etc.).\n *\n * \\param String The string to validate.\n * \\return TRUE if the string is valid; otherwise, FALSE.\n */\nBOOLEAN PhIsControlOrFormattingString(\n    _In_opt_ PPH_STRING String\n    )\n{\n    SIZE_T length;\n    BOOLEAN hasVisibleContent = FALSE;\n    \n    if (!String || String->Length == 0)\n        return FALSE;\n    \n    length = String->Length / sizeof(WCHAR);\n    \n    for (SIZE_T i = 0; i < length; i++)\n    {\n        WCHAR c = String->Buffer[i];\n        \n        // Reject strings with control/formatting characters.\n        if (PhIsControlOrFormattingUnicodeChar(c))\n            return FALSE;\n        \n        // Check if we have non-whitespace content.\n        if (!PhIsWhiteSpaceUnicodeChar(c))\n        {\n            hasVisibleContent = TRUE;\n        }\n    }\n    \n    // String must have at least one visible character\n    return hasVisibleContent;\n}\n\n/**\n * Sanitizes a string in-place by replacing control and formatting characters.\n *\n * Replaces unicode characters (RTLO, zero-width chars, control chars, etc.)\n * with a visible replacement character directly in the string buffer.\n *\n * \\param String The string to sanitize in-place.\n * \\param ReplacementChar The character to use as a replacement (e.g., L'?' or PH_UNICODE_REPLACEMENT_CHARACTER).\n * \\return The number of characters replaced.\n */\nULONG PhFilterControlOrFormattingString(\n    _Inout_ PPH_STRINGREF String,\n    _In_ WCHAR ReplacementChar\n    )\n{\n    SIZE_T length;\n    ULONG replaced = 0;\n    \n    if (!String || String->Length == 0)\n        return 0;\n    \n    length = String->Length / sizeof(WCHAR);\n    \n    for (SIZE_T i = 0; i < length; i++)\n    {\n        if (PhIsControlOrFormattingUnicodeChar(String->Buffer[i]))\n        {\n            String->Buffer[i] = PH_UNICODE_REPLACEMENT_CHARACTER;\n            replaced++;\n        }\n    }\n    \n    return replaced;\n}\n"
  },
  {
    "path": "phlib/basesup.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2019-2023\n *\n */\n\n/*\n * This file contains basic low-level code as well as general algorithms and data structures.\n *\n * Memory allocation. PhAllocate is a wrapper around RtlAllocateHeap, and always allocates from the\n * phlib heap. PhAllocatePage is a wrapper around NtAllocateVirtualMemory and allocates pages.\n *\n * Null-terminated strings. The Ph*StringZ functions manipulate null-terminated strings. The copying\n * functions provide a simple way to copy strings which may not be null-terminated, but have a\n * specified limit.\n *\n * String. The design of the string object was chosen for maximum compatibility. As such each string\n * buffer must be null-terminated, and each object contains an embedded PH_STRINGREF structure. Note\n * that efficient sub-string creation (no copying, only references the parent string object) could\n * not be implemented due to the mandatory null-termination. String objects must be regarded as\n * immutable (for thread-safety reasons) unless the object has just been created and no references\n * have been shared.\n *\n * String builder. This is a set of functions which allow for efficient modification of strings. For\n * performance reasons, these functions modify string objects directly, even though they are\n * normally immutable.\n *\n * List. A simple PVOID list that resizes itself when needed.\n *\n * Pointer list. Similar to the normal list object, but uses a free list in order to support\n * constant time insertion and deletion. In order for the free list to work, normal entries have\n * their lowest bit clear while free entries have their lowest bit set, with the index of the next\n * free entry in the upper bits.\n *\n * Hashtable. A hashtable with power-of-two bucket sizes and with all entries stored in a single\n * array. This improves locality but may be inefficient when resizing the hashtable. It is a good\n * idea to store pointers to objects as entries, as opposed to the objects themselves.\n *\n * Simple hashtable. A wrapper around the normal hashtable, with PVOID keys and PVOID values.\n *\n * Free list. A thread-safe memory allocation method where freed blocks are stored in a S-list, and\n * allocations are made from this list whenever possible.\n *\n * Callback. A thread-safe notification mechanism where clients can register callback functions\n * which are then invoked by other code.\n */\n\n#include <phbase.h>\n#include <phintrnl.h>\n#include <phintrin.h>\n#include <phnative.h>\n#include <circbuf.h>\n#include <thirdparty.h>\n#include <ntintsafe.h>\n\n#include <trace.h>\n\n#ifndef PH_NATIVE_THREAD_CREATE\n#define PH_NATIVE_THREAD_CREATE 1\n#endif\n\n#ifndef PHNT_NATIVE_TIME\n#define PHNT_NATIVE_TIME 1\n#endif\n\ntypedef struct _PHP_BASE_THREAD_CONTEXT\n{\n    PUSER_THREAD_START_ROUTINE StartAddress;\n    PVOID Parameter;\n} PHP_BASE_THREAD_CONTEXT, *PPHP_BASE_THREAD_CONTEXT;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpListDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpPointerListDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpHashtableDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n// Types\n\nPPH_OBJECT_TYPE PhStringType = NULL;\nPPH_OBJECT_TYPE PhBytesType = NULL;\nPPH_OBJECT_TYPE PhListType = NULL;\nPPH_OBJECT_TYPE PhPointerListType = NULL;\nPPH_OBJECT_TYPE PhHashtableType = NULL;\n\n// Misc.\n\nPPH_STRING PhSharedEmptyString = NULL;\n\n// Threads\n\nstatic PH_FREE_LIST PhpBaseThreadContextFreeList;\n#ifdef DEBUG\nULONG PhDbgThreadDbgTlsIndex;\nRTL_STATIC_LIST_HEAD(PhDbgThreadListHead);\nPH_QUEUED_LOCK PhDbgThreadListLock = PH_QUEUED_LOCK_INIT;\n#endif\n\n// Data\n\nstatic CONST ULONG PhpPrimeNumbers[] =\n{\n    0x3, 0x7, 0xb, 0x11, 0x17, 0x1d, 0x25, 0x2f, 0x3b, 0x47, 0x59, 0x6b, 0x83,\n    0xa3, 0xc5, 0xef, 0x125, 0x161, 0x1af, 0x209, 0x277, 0x2f9, 0x397, 0x44f,\n    0x52f, 0x63d, 0x78b, 0x91d, 0xaf1, 0xd2b, 0xfd1, 0x12fd, 0x16cf, 0x1b65,\n    0x20e3, 0x2777, 0x2f6f, 0x38ff, 0x446f, 0x521f, 0x628d, 0x7655, 0x8e01,\n    0xaa6b, 0xcc89, 0xf583, 0x126a7, 0x1619b, 0x1a857, 0x1fd3b, 0x26315, 0x2dd67,\n    0x3701b, 0x42023, 0x4f361, 0x5f0ed, 0x72125, 0x88e31, 0xa443b, 0xc51eb,\n    0xec8c1, 0x11bdbf, 0x154a3f, 0x198c4f, 0x1ea867, 0x24ca19, 0x2c25c1, 0x34fa1b,\n    0x3f928f, 0x4c4987, 0x5b8b6f, 0x6dda89\n};\n\n/**\n * Initializes the base support module.\n */\nNTSTATUS PhBaseInitialization(\n    VOID\n    )\n{\n    PH_OBJECT_TYPE_PARAMETERS parameters;\n\n    PhStringType = PhCreateObjectType(L\"String\", 0, NULL);\n    PhBytesType = PhCreateObjectType(L\"Bytes\", 0, NULL);\n\n    memset(&parameters, 0, sizeof(PH_OBJECT_TYPE_PARAMETERS));\n    parameters.FreeListSize = sizeof(PH_LIST);\n    parameters.FreeListCount = 128;\n\n    PhListType = PhCreateObjectTypeEx(L\"List\", PH_OBJECT_TYPE_USE_FREE_LIST, PhpListDeleteProcedure, &parameters);\n    PhPointerListType = PhCreateObjectType(L\"PointerList\", 0, PhpPointerListDeleteProcedure);\n\n    memset(&parameters, 0, sizeof(PH_OBJECT_TYPE_PARAMETERS));\n    parameters.FreeListSize = sizeof(PH_HASHTABLE);\n    parameters.FreeListCount = 64;\n\n    PhHashtableType = PhCreateObjectTypeEx(L\"Hashtable\", PH_OBJECT_TYPE_USE_FREE_LIST, PhpHashtableDeleteProcedure, &parameters);\n\n    PhInitializeFreeList(&PhpBaseThreadContextFreeList, sizeof(PHP_BASE_THREAD_CONTEXT), 16);\n\n#ifdef DEBUG\n    PhDbgThreadDbgTlsIndex = PhTlsAlloc();\n\n    if (PhDbgThreadDbgTlsIndex == TLS_OUT_OF_INDEXES)\n        return STATUS_NO_MEMORY;\n#endif\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Entry point for a base thread in the system.\n *\n * This function serves as the start routine for a user thread. It initializes COM for the thread,\n * sets up debugging information (in debug builds), and invokes the user-supplied thread function.\n * After the user function returns, it performs necessary cleanup, including COM uninitialization\n * and removal of debugging information.\n * \\param Parameter Pointer to a PHP_BASE_THREAD_CONTEXT structure containing the user-supplied\n *        thread start address and parameter.\n * \\return NTSTATUS Status code returned by the user-supplied thread function.\n */\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpBaseThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    HRESULT result;\n    PHP_BASE_THREAD_CONTEXT context;\n#ifdef DEBUG\n    PHP_BASE_THREAD_DBG dbg;\n#endif\n\n    context = *(PPHP_BASE_THREAD_CONTEXT)Parameter;\n    PhFreeToFreeList(&PhpBaseThreadContextFreeList, Parameter);\n\n#ifdef DEBUG\n    memset(&dbg, 0, sizeof(PHP_BASE_THREAD_DBG));\n    dbg.ClientId = NtCurrentTeb()->ClientId;\n    dbg.StartAddress = context.StartAddress;\n    dbg.Parameter = context.Parameter;\n    dbg.CurrentAutoPool = NULL;\n\n    PhAcquireQueuedLockExclusive(&PhDbgThreadListLock);\n    InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry);\n    PhReleaseQueuedLockExclusive(&PhDbgThreadListLock);\n\n    PhTlsSetValue(PhDbgThreadDbgTlsIndex, &dbg);\n#endif\n\n    // Initialization code\n\n    result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);\n\n    // Call the user-supplied function.\n\n    status = context.StartAddress(context.Parameter);\n\n    // De-initialization code\n\n    if (result == S_OK || result == S_FALSE)\n        CoUninitialize();\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgThreadListLock);\n    RemoveEntryList(&dbg.ListEntry);\n    PhReleaseQueuedLockExclusive(&PhDbgThreadListLock);\n#endif\n\n    return status;\n}\n\n/**\n * Creates a thread.\n *\n * \\param ProcessHandle A handle to the process in which the thread is to be created.\n * \\param ThreadSecurityDescriptor A pointer to a security descriptor for the new thread and\n * \\a determines whether child processes can inherit the thread handle.\n * \\param DesiredAccess The desired access to the thread.\n * \\param CreateFlags The flags that control the creation of the thread.\n * \\param ZeroBits The number of high-order address bits that must be zero.\n * \\a If this parameter is zero, the new thread uses the default for the executable.\n * \\param StackSize The initial size of the stack, in bytes. The system rounds this value to the nearest page.\n * \\a If this parameter is zero, the new thread uses the default size for the executable.\n * \\param MaximumStackSize The maximum size of the stack, in bytes. The system rounds this value to the nearest page.\n * \\a If this parameter is zero, the new thread uses the default maximum for the executable.\n * \\param StartRoutine A pointer to the starting address of the thread.\n * \\param Argument A pointer to a variable to be passed to the StartRoutine.\n * \\param ThreadHandle A pointer to a variable that receives a handle to the new thread.\n * \\param ClientId A pointer to a variable that receives the thread identifier.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateUserThread(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG CreateFlags,\n    _In_opt_ SIZE_T ZeroBits,\n    _In_opt_ SIZE_T StackSize,\n    _In_opt_ SIZE_T MaximumStackSize,\n    _In_ PUSER_THREAD_START_ROUTINE StartRoutine,\n    _In_opt_ PVOID Argument,\n    _Out_opt_ PHANDLE ThreadHandle,\n    _Out_opt_ PCLIENT_ID ClientId\n    )\n{\n#if defined(PH_NATIVE_THREAD_CREATE)\n    NTSTATUS status;\n    HANDLE threadHandle;\n    OBJECT_ATTRIBUTES objectAttributes;\n    UCHAR buffer[FIELD_OFFSET(PS_ATTRIBUTE_LIST, Attributes) + sizeof(PS_ATTRIBUTE[1])] = { 0 };\n    PPS_ATTRIBUTE_LIST attributeList = (PPS_ATTRIBUTE_LIST)buffer;\n    CLIENT_ID clientId = { NULL, NULL };\n\n    InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, ThreadSecurityDescriptor);\n    attributeList->TotalLength = sizeof(buffer);\n    attributeList->Attributes[0].Attribute = PS_ATTRIBUTE_CLIENT_ID;\n    attributeList->Attributes[0].Size = sizeof(CLIENT_ID);\n    attributeList->Attributes[0].ValuePtr = &clientId;\n    attributeList->Attributes[0].ReturnLength = NULL;\n\n    status = NtCreateThreadEx(\n        &threadHandle,\n        DesiredAccess,\n        &objectAttributes,\n        ProcessHandle,\n        StartRoutine,\n        Argument,\n        CreateFlags,\n        ZeroBits,\n        StackSize,\n        MaximumStackSize,\n        attributeList\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (ThreadHandle)\n        {\n            *ThreadHandle = threadHandle;\n        }\n        else if (threadHandle)\n        {\n            NtClose(threadHandle);\n        }\n\n        if (ClientId)\n        {\n            *ClientId = clientId;\n        }\n    }\n\n    return status;\n#else\n    return RtlCreateUserThread(\n        ProcessHandle,\n        ThreadSecurityDescriptor,\n        BooleanFlagOn(CreateFlags, THREAD_CREATE_FLAGS_CREATE_SUSPENDED),\n        (ULONG)ZeroBits,\n        MaximumStackSize,\n        StackSize,\n        StartRoutine,\n        Argument,\n        ThreadHandle,\n        ClientId\n        );\n#endif\n}\n\n/**\n * Creates a thread.\n *\n * \\param StackSize The initial stack size of the thread.\n * \\param StartAddress The function to execute in the thread.\n * \\param Parameter A user-defined value to pass to the function.\n * \\return HANDLE A handle to the new thread.\n */\nHANDLE PhCreateThread(\n    _In_opt_ SIZE_T StackSize,\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n    PPHP_BASE_THREAD_CONTEXT context;\n\n    context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList);\n    context->StartAddress = StartAddress;\n    context->Parameter = Parameter;\n\n    status = PhCreateUserThread(\n        NtCurrentProcess(),\n        NULL,\n        THREAD_ALL_ACCESS,\n        0,\n        0,\n        0,\n        StackSize,\n        PhpBaseThreadStart,\n        context,\n        &threadHandle,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreated);\n        return threadHandle;\n    }\n    else\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreateFailed);\n        PhFreeToFreeList(&PhpBaseThreadContextFreeList, context);\n        return NULL;\n    }\n}\n\n/**\n * Creates a new thread in the current process.\n *\n * \\param ThreadHandle Pointer to a variable that receives the handle of the newly created thread.\n * \\param StartAddress Pointer to the function to be executed by the thread.\n * \\param Parameter Optional parameter to be passed to the thread function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateThreadEx(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n    PPHP_BASE_THREAD_CONTEXT context;\n\n    context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList);\n    context->StartAddress = StartAddress;\n    context->Parameter = Parameter;\n\n    status = PhCreateUserThread(\n        NtCurrentProcess(),\n        NULL,\n        THREAD_ALL_ACCESS,\n        0,\n        0,\n        0,\n        0,\n        PhpBaseThreadStart,\n        context,\n        &threadHandle,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreated);\n        *ThreadHandle = threadHandle;\n    }\n    else\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreateFailed);\n        PhFreeToFreeList(&PhpBaseThreadContextFreeList, context);\n    }\n\n    return status;\n}\n\n/**\n * Creates a new thread and begins execution at the specified start address.\n *\n * \\param StartAddress Pointer to the function to be executed by the new thread.\n * \\param Parameter Optional parameter to be passed to the thread function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateThread2(\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PPHP_BASE_THREAD_CONTEXT context;\n\n    context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList);\n    context->StartAddress = StartAddress;\n    context->Parameter = Parameter;\n\n    status = PhCreateUserThread(\n        NtCurrentProcess(),\n        NULL,\n        THREAD_ALL_ACCESS,\n        0,\n        0,\n        0,\n        0,\n        PhpBaseThreadStart,\n        context,\n        NULL,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreated);\n    }\n    else\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreateFailed);\n        PhFreeToFreeList(&PhpBaseThreadContextFreeList, context);\n    }\n\n    return status;\n}\n\n/**\n * Callback function that starts a queued base thread.\n *\n * This function is called by the thread pool when a work item is dequeued.\n * It retrieves the thread context, frees the context structure, and invokes\n * the user-supplied start address with the provided parameter.\n * \\param Instance Pointer to the thread pool callback instance.\n * \\param Context Pointer to a PHP_BASE_THREAD_CONTEXT structure, which will be freed.\n */\n_Function_class_(TP_CALLBACK_ROUTINE)\nVOID PhpBaseThreadQueueStart(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _In_ _Frees_ptr_ PVOID Context\n    )\n{\n    PHP_BASE_THREAD_CONTEXT context;\n\n    context = *(PPHP_BASE_THREAD_CONTEXT)Context;\n    PhFreeToFreeList(&PhpBaseThreadContextFreeList, Context);\n\n    context.StartAddress(context.Parameter);\n}\n\n/**\n * Queues a callback to be executed by a thread pool thread.\n *\n * This function allocates a thread context, initializes a callback environment,\n * and posts the work item to a thread pool. If the operation succeeds, a statistic\n * for created threads is incremented; otherwise, a failure statistic is incremented\n * and the context is freed.\n * \\param StartRoutine Pointer to the user-defined thread start routine to execute.\n * \\param Parameter Optional parameter to pass to the start routine.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueueUserWorkItem(\n    _In_ PUSER_THREAD_START_ROUTINE StartRoutine,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    PPHP_BASE_THREAD_CONTEXT context;\n    TP_CALLBACK_ENVIRON environment;\n\n    context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList);\n    context->StartAddress = StartRoutine;\n    context->Parameter = Parameter;\n\n    TpInitializeCallbackEnviron(&environment);\n    TpSetCallbackLongFunction(&environment);\n    TpSetCallbackPriority(&environment, TP_CALLBACK_PRIORITY_NORMAL);\n\n    status = TpSimpleTryPost(PhpBaseThreadQueueStart, context, &environment);\n\n    if (NT_SUCCESS(status))\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreated);\n    }\n    else\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreateFailed);\n        PhFreeToFreeList(&PhpBaseThreadContextFreeList, context);\n    }\n\n    return status;\n}\n\nDOUBLE PhReadTimeStampFrequency(\n    VOID\n    )\n{\n    LARGE_INTEGER frequency;\n    LARGE_INTEGER start;\n    LARGE_INTEGER end;\n    ULONG_PTR old_affinity = 0;\n    DOUBLE elapsed_qpc;\n    ULONG64 elapsed_tsc;\n    DOUBLE tsc_freq;\n    ULONG64 tsc_start;\n    ULONG64 tsc_end;\n\n    // Wait interval (in QPC ticks)\n    PhQueryPerformanceFrequency(&frequency);\n    const LONGLONG interval_ms = 100; // 100 ms\n    const LONGLONG interval_ticks = (frequency.QuadPart * interval_ms) / 1000;\n\n    // Warm up\n    for (volatile ULONG i = 0UL; i < 1000000UL; ++i) {}\n\n    // Pin thread to one CPU (optional, for best accuracy)\n    PhGetThreadAffinityMask(NtCurrentThread(), &old_affinity);\n    PhSetThreadAffinityMask(NtCurrentThread(), 1);\n\n    PhQueryPerformanceCounter(&start);\n    SpeculationFence();\n    tsc_start = ReadTimeStampCounter();\n    SpeculationFence();\n\n    // Wait for interval\n    for (;;)\n    {\n        PhQueryPerformanceCounter(&end);\n\n        if ((end.QuadPart - start.QuadPart) >= interval_ticks)\n            break;\n\n        YieldProcessor();\n    }\n\n    SpeculationFence();\n    tsc_end = ReadTimeStampCounter();\n    SpeculationFence();\n\n    if (old_affinity)\n    {\n        PhSetThreadAffinityMask(NtCurrentThread(), old_affinity);\n    }\n\n    elapsed_qpc = (DOUBLE)(end.QuadPart - start.QuadPart) / frequency.QuadPart;\n    elapsed_tsc = tsc_end - tsc_start;\n    tsc_freq = elapsed_tsc / elapsed_qpc;\n    return tsc_freq;\n}\n\n/**\n * Reads the time stamp counter.\n *\n * This function reads the time stamp counter using the `__rdtscp` instruction,\n * which is a serializing variant of the `rdtsc` instruction. It also includes\n * a memory fence to ensure proper ordering of memory operations.\n * \\return The current value of the time stamp counter.\n */\nULONG64 PhReadTimeStampCounter(\n    VOID\n    )\n{\n#if defined(PHNT_RDTSCP)\n    unsigned int processorIndex;\n    ULONG64 value = __rdtscp(&processorIndex);\n    SpeculationFence();\n    return value;\n#else\n    MemoryBarrier();\n    ULONG64 value = ReadTimeStampCounter();\n    MemoryBarrier();\n    return value;\n#endif\n}\n\n// rev from QueryPerformanceCounter (dmex)\n/**\n * Retrieves the current value of the performance counter, which is a high resolution (<1us) time stamp that can be used for time-interval measurements.\n *\n * \\param PerformanceCounter A pointer to a variable that receives the current performance-counter value, in counts.\n * \\return Successful or errant status.\n * \\remarks On systems that run Windows XP or later, the function will always succeed and will thus never return zero.\n */\nBOOLEAN PhQueryPerformanceCounter(\n    _Out_ PLARGE_INTEGER PerformanceCounter\n    )\n{\n#if defined(PH_WIN32_PERFCOUNTER)\n    return !!QueryPerformanceCounter(PerformanceCounter);\n#elif defined(PH_NATIVE_PERFCOUNTER)\n    return NT_SUCCESS(NtQueryPerformanceCounter(PerformanceCounter, NULL));\n#else\n    return !!RtlQueryPerformanceCounter(PerformanceCounter);\n#endif\n}\n\n// rev from QueryPerformanceFrequency (dmex)\n/**\n * Retrieves the frequency of the performance counter.\n * The frequency of the performance counter is fixed at system boot and is consistent across all processors.\n * Therefore, the frequency need only be queried upon application initialization, and the result can be cached.\n *\n * \\param PerformanceFrequency A pointer to a variable that receives the current performance-counter frequency, in counts per second.\n * \\return Successful or errant status.\n * \\remarks On systems that run Windows XP or later, the function will always succeed and will thus never return zero.\n */\nBOOLEAN PhQueryPerformanceFrequency(\n    _Out_ PLARGE_INTEGER PerformanceFrequency\n    )\n{\n#if defined(PH_WIN32_PERFCOUNTER)\n    return !!QueryPerformanceFrequency(PerformanceFrequency);\n#elif defined(PH_NATIVE_PERFCOUNTER)\n    LARGE_INTEGER performanceCounter;\n    return NT_SUCCESS(NtQueryPerformanceCounter(&performanceCounter, PerformanceFrequency));\n#else\n    return !!RtlQueryPerformanceFrequency(PerformanceFrequency);\n#endif\n}\n\n/**\n * Gets the current interrupt-time count.\n */\nVOID PhQueryInterruptTime(\n    _Out_ PLARGE_INTEGER InterruptTime\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n\n    while (TRUE)\n    {\n        InterruptTime->HighPart = USER_SHARED_DATA->InterruptTime.High1Time;\n        InterruptTime->LowPart = USER_SHARED_DATA->InterruptTime.LowPart;\n\n        if (InterruptTime->HighPart == USER_SHARED_DATA->InterruptTime.High2Time)\n            break;\n\n        YieldProcessor();\n    }\n\n#elif defined(PHNT_SYSTEM_TIME)\n\n    ULONGLONG interruptTime;\n\n    QueryInterruptTime(&interruptTime);\n\n    InterruptTime->QuadPart = interruptTime;\n\n#else\n\n    do\n    {\n        InterruptTime->HighPart = USER_SHARED_DATA->InterruptTime.High1Time;\n        InterruptTime->LowPart = USER_SHARED_DATA->InterruptTime.LowPart;\n    } while (InterruptTime->HighPart != USER_SHARED_DATA->InterruptTime.High2Time);\n\n#endif\n}\n\n/**\n * Gets the current system time (UTC).\n *\n * \\remarks Use this function instead of NtQuerySystemTime() because no system calls are involved.\n */\nVOID PhQuerySystemTime(\n    _Out_ PLARGE_INTEGER SystemTime\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n\n    while (TRUE)\n    {\n        SystemTime->HighPart = USER_SHARED_DATA->SystemTime.High1Time;\n        SystemTime->LowPart = USER_SHARED_DATA->SystemTime.LowPart;\n\n        if (SystemTime->HighPart == USER_SHARED_DATA->SystemTime.High2Time)\n            break;\n\n        YieldProcessor();\n    }\n\n#elif defined(PHNT_SYSTRM_TIME)\n\n    SYSTEMTIME systemTime;\n    FILETIME fileTime;\n\n    GetSystemTime(&systemTime);\n    SystemTimeToFileTime(&systemTime, &fileTime);\n\n    SystemTime->LowPart = fileTime.dwLowDateTime;\n    SystemTime->HighPart = fileTime.dwHighDateTime;\n\n#else\n\n    do\n    {\n        SystemTime->HighPart = USER_SHARED_DATA->SystemTime.High1Time;\n        SystemTime->LowPart = USER_SHARED_DATA->SystemTime.LowPart;\n    } while (SystemTime->HighPart != USER_SHARED_DATA->SystemTime.High2Time);\n\n#endif\n}\n\n/**\n * Gets the offset of the current time zone from UTC.\n *\n * \\remarks Use this function instead of GetTimeZoneInformation() because no system calls are involved.\n */\nNTSTATUS PhQueryTimeZoneBias(\n    _Out_ PLARGE_INTEGER TimeZoneBias\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n\n    while (TRUE)\n    {\n        TimeZoneBias->HighPart = USER_SHARED_DATA->TimeZoneBias.High1Time;\n        TimeZoneBias->LowPart = USER_SHARED_DATA->TimeZoneBias.LowPart;\n\n        if (TimeZoneBias->HighPart == USER_SHARED_DATA->TimeZoneBias.High2Time)\n            break;\n\n        YieldProcessor();\n    }\n\n    return STATUS_SUCCESS;\n#elif defined(PHNT_SYSTEM_TIME)\n    NTSTATUS status;\n    SYSTEM_TIMEOFDAY_INFORMATION timeOfDayInfo = { 0 };\n\n    status = NtQuerySystemInformation(\n        SystemTimeOfDayInformation,\n        &timeOfDayInfo,\n        sizeof(SYSTEM_TIMEOFDAY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        TimeZoneBias->QuadPart = timeOfDayInfo.TimeZoneBias.QuadPart;\n    }\n\n    return status;\n#else\n\n    do\n    {\n        TimeZoneBias->HighPart = USER_SHARED_DATA->TimeZoneBias.High1Time;\n        TimeZoneBias->LowPart = USER_SHARED_DATA->TimeZoneBias.LowPart;\n    } while (TimeZoneBias->HighPart != USER_SHARED_DATA->TimeZoneBias.High2Time);\n\n    return STATUS_SUCCESS;\n#endif\n}\n\n/**\n * Converts system time to local time.\n *\n * \\param SystemTime A UTC time value.\n * \\param LocalTime A variable which receives the local time value. This may be the same variable as\n * \\a SystemTime.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Use this function instead of RtlSystemTimeToLocalTime() because no system calls are\n * involved.\n */\nNTSTATUS PhSystemTimeToLocalTime(\n    _In_ PLARGE_INTEGER SystemTime,\n    _Out_ PLARGE_INTEGER LocalTime\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n    NTSTATUS status;\n    LARGE_INTEGER timeZoneBias;\n\n    status = PhQueryTimeZoneBias(&timeZoneBias);\n\n    if (NT_SUCCESS(status))\n    {\n        LocalTime->QuadPart = SystemTime->QuadPart - timeZoneBias.QuadPart;\n    }\n\n    return status;\n#else\n    return RtlSystemTimeToLocalTime(SystemTime, LocalTime);\n#endif\n}\n\n/**\n * Converts local time to system time.\n *\n * \\param LocalTime A local time value.\n * \\param SystemTime A variable which receives the UTC time value. This may be the same variable as\n * \\a LocalTime.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Use this function instead of RtlLocalTimeToSystemTime() because no system calls are\n * involved.\n */\nNTSTATUS PhLocalTimeToSystemTime(\n    _In_ PLARGE_INTEGER LocalTime,\n    _Out_ PLARGE_INTEGER SystemTime\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n    NTSTATUS status;\n    LARGE_INTEGER timeZoneBias;\n\n    status = PhQueryTimeZoneBias(&timeZoneBias);\n\n    if (NT_SUCCESS(status))\n    {\n        SystemTime->QuadPart = LocalTime->QuadPart + timeZoneBias.QuadPart;\n    }\n\n    return status;\n#else\n    return RtlLocalTimeToSystemTime(LocalTime, SystemTime);\n#endif\n}\n\n/**\n * Converts a system time value to the number of seconds elapsed since January 1, 1980 (the DOS epoch).\n *\n * \\param Time Pointer to a LARGE_INTEGER representing the system time (in 100-nanosecond intervals since January 1, 1601 UTC).\n * \\param ElapsedSeconds Pointer to a ULONG that receives the number of seconds since January 1, 1980.\n * \\return TRUE if the conversion was successful and the result fits in a ULONG; FALSE otherwise.\n */\nBOOLEAN PhTimeToSecondsSince1980(\n    _In_ PLARGE_INTEGER Time,\n    _Out_ PULONG ElapsedSeconds\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n    LARGE_INTEGER time;\n\n    time.QuadPart = Time->QuadPart - (SecondsToStartOf1980 * PH_TICKS_PER_SEC);\n    time.QuadPart /= PH_TICKS_PER_SEC;\n\n    if (time.HighPart)\n    {\n        *ElapsedSeconds = 0;\n        return FALSE;\n    }\n\n    *ElapsedSeconds = time.LowPart;\n    return TRUE;\n#else\n    return RtlTimeToSecondsSince1980(Time, ElapsedSeconds);\n#endif\n}\n\n/**\n * Converts a system time value to the number of seconds elapsed since January 1, 1970 (the Unix epoch).\n *\n * \\param Time Pointer to a LARGE_INTEGER representing the system time (in 100-nanosecond intervals since January 1, 1601 UTC).\n * \\param ElapsedSeconds Pointer to a ULONG that receives the number of seconds since January 1, 1970.\n * \\return TRUE if the conversion was successful and the result fits in a ULONG; FALSE otherwise.\n */\nBOOLEAN PhTimeToSecondsSince1970(\n    _In_ PLARGE_INTEGER Time,\n    _Out_ PULONG ElapsedSeconds\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n    LARGE_INTEGER time;\n\n    time.QuadPart = Time->QuadPart - (SecondsToStartOf1970 * PH_TICKS_PER_SEC);\n    time.QuadPart /= PH_TICKS_PER_SEC;\n\n    if (time.HighPart)\n    {\n        *ElapsedSeconds = 0;\n        return FALSE;\n    }\n\n    *ElapsedSeconds = time.LowPart;\n    return TRUE;\n#else\n    return RtlTimeToSecondsSince1970(Time, ElapsedSeconds);\n#endif\n}\n\n/**\n * Converts the number of seconds elapsed since 1980 to a system time value.\n *\n * \\param ElapsedSeconds The number of seconds since January 1, 1980.\n * \\param Time Pointer to a LARGE_INTEGER that receives the converted time value.\n */\nVOID PhSecondsSince1980ToTime(\n    _In_ ULONG ElapsedSeconds,\n    _Out_ PLARGE_INTEGER Time\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n    Time->QuadPart = PH_TICKS_PER_SEC * (SecondsToStartOf1980 + ElapsedSeconds);\n#else\n    RtlSecondsSince1980ToTime(ElapsedSeconds, Time);\n#endif\n}\n\n/**\n * Converts the number of seconds elapsed since January 1, 1970 (the Unix epoch)\n * to a Windows FILETIME-compatible 64-bit time value.\n *\n * \\param ElapsedSeconds The number of seconds since January 1, 1970.\n * \\param Time Pointer to a LARGE_INTEGER that receives the converted time value.\n */\nVOID PhSecondsSince1970ToTime(\n    _In_ ULONG ElapsedSeconds,\n    _Out_ PLARGE_INTEGER Time\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n    Time->QuadPart = PH_TICKS_PER_SEC * (SecondsToStartOf1970 + ElapsedSeconds);\n#else\n    RtlSecondsSince1970ToTime(ElapsedSeconds, Time);\n#endif\n}\n\n/**\n * Allocates a block of memory.\n *\n * \\param Size The number of bytes to allocate.\n * \\return A pointer to the allocated block of memory.\n * \\remarks If the function fails to allocate the block of memory, it raises an exception. The block\n * is guaranteed to be aligned at MEMORY_ALLOCATION_ALIGNMENT bytes.\n */\n_Use_decl_annotations_\nPVOID PhAllocate(\n    _In_ SIZE_T Size\n    )\n{\n    assert(Size > 0 && Size < PH_LARGE_BUFFER_SIZE);\n#if defined(PH_DEBUG_HEAP)\n    return malloc(Size);\n#else\n    return RtlAllocateHeap(PhHeapHandle, HEAP_GENERATE_EXCEPTIONS, Size);\n#endif\n}\n\n/**\n * Allocates a block of memory.\n *\n * \\param Size The number of bytes to allocate.\n * \\return A pointer to the allocated block of memory,\n * or NULL if the block could not be allocated.\n */\n_Use_decl_annotations_\nPVOID PhAllocateSafe(\n    _In_ SIZE_T Size\n    )\n{\n    assert(Size > 0 && Size < PH_LARGE_BUFFER_SIZE);\n#if defined(PH_DEBUG_HEAP)\n    return malloc(Size);\n#else\n    return RtlAllocateHeap(PhHeapHandle, 0, Size);\n#endif\n}\n\n/**\n * Allocates a block of memory.\n *\n * \\param Size The number of bytes to allocate.\n * \\param Flags Flags controlling the allocation.\n * \\return A pointer to the allocated block of memory,\n * or NULL if the block could not be allocated.\n */\n_Use_decl_annotations_\nPVOID PhAllocateExSafe(\n    _In_ SIZE_T Size,\n    _In_ ULONG Flags\n    )\n{\n    assert(Size > 0 && Size < PH_LARGE_BUFFER_SIZE);\n#if defined(PH_DEBUG_HEAP)\n    return malloc(Size);\n#else\n    return RtlAllocateHeap(PhHeapHandle, Flags, Size);\n#endif\n}\n\n/**\n * Frees a block of memory allocated with PhAllocate().\n *\n * \\param Memory A pointer to a block of memory.\n */\n_Use_decl_annotations_\nVOID PhFree(\n    _In_opt_ _Frees_ptr_opt_ _Post_invalid_ PVOID Memory\n    )\n{\n#if defined(PH_DEBUG_HEAP)\n    free(Memory);\n#else\n    RtlFreeHeap(PhHeapHandle, 0, Memory);\n#endif\n}\n\n/**\n * Re-allocates a block of memory originally allocated with PhAllocate().\n *\n * \\param Memory A pointer to a block of memory.\n * \\param Size The new size of the memory block, in bytes.\n * \\return A pointer to the new block of memory. The existing contents of the memory block are\n * copied to the new block.\n * \\remarks If the function fails to allocate the block of memory, it raises an exception.\n */\n_Use_decl_annotations_\nPVOID PhReAllocate(\n    _In_opt_ _Frees_ptr_opt_ PVOID Memory,\n    _In_ SIZE_T Size\n    )\n{\n    assert(Size > 0 && Size < PH_LARGE_BUFFER_SIZE);\n#if defined(PH_DEBUG_HEAP)\n    return realloc(Memory, Size);\n#else\n    if (Size == 0)\n    {\n        if (Memory)\n            PhFree(Memory);\n        return NULL;\n    }\n    if (Memory)\n    {\n        return RtlReAllocateHeap(PhHeapHandle, HEAP_GENERATE_EXCEPTIONS, Memory, Size);\n    }\n\n    return RtlAllocateHeap(PhHeapHandle, HEAP_GENERATE_EXCEPTIONS, Size);\n#endif\n}\n\n/**\n * Re-allocates a block of memory originally allocated with PhAllocate().\n *\n * \\param Memory A pointer to a block of memory.\n * \\param Size The new size of the memory block, in bytes.\n * \\return A pointer to the new block of memory, or NULL if the block could not be allocated. The\n * existing contents of the memory block are copied to the new block.\n */\n_Use_decl_annotations_\nPVOID PhReAllocateSafe(\n    _In_opt_ _Frees_ptr_opt_ PVOID Memory,\n    _In_ SIZE_T Size\n    )\n{\n    assert(Size > 0 && Size < PH_LARGE_BUFFER_SIZE);\n#if defined(PH_DEBUG_HEAP)\n    return realloc(Memory, Size);\n#else\n    if (Size == 0)\n    {\n        if (Memory)\n            PhFree(Memory);\n        return NULL;\n    }\n    if (Memory)\n    {\n        return RtlReAllocateHeap(PhHeapHandle, 0, Memory, Size);\n    }\n\n    return RtlAllocateHeap(PhHeapHandle, 0, Size);\n#endif\n}\n\n_Use_decl_annotations_\nSIZE_T PhSizeHeap(\n    _In_ PVOID Memory\n    )\n{\n#if defined(PH_DEBUG_HEAP)\n    return _msize(Memory);\n#else\n    return RtlSizeHeap(PhHeapHandle, 0, Memory);\n#endif\n}\n\n/**\n * Allocates pages of memory.\n *\n * \\param Size The number of bytes to allocate. The number of pages allocated will be large enough\n * to contain \\a Size bytes.\n * \\param NewSize The number of bytes actually allocated. This is \\a Size rounded up to the next\n * multiple of PAGE_SIZE.\n * \\return A pointer to the allocated block of memory, or NULL if the block could not be allocated.\n */\n_Use_decl_annotations_\nPVOID PhAllocatePage(\n    _In_ SIZE_T Size,\n    _Out_opt_ PSIZE_T NewSize\n    )\n{\n    PVOID baseAddress;\n    SIZE_T regionSize;\n\n    baseAddress = NULL;\n    regionSize = Size;\n\n    if (NT_SUCCESS(NtAllocateVirtualMemory(\n        NtCurrentProcess(),\n        &baseAddress,\n        0,\n        &regionSize,\n        MEM_COMMIT,\n        PAGE_READWRITE\n        )))\n    {\n        if (NewSize)\n            *NewSize = regionSize;\n\n        return baseAddress;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\n/**\n * Frees pages of memory allocated with PhAllocatePage().\n *\n * \\param Memory A pointer to a block of memory.\n */\nVOID PhFreePage(\n    _In_opt_ _Frees_ptr_opt_ _Post_invalid_ PVOID Memory\n    )\n{\n    PhFreeVirtualMemory(NtCurrentProcess(), Memory, MEM_RELEASE);\n}\n\n/**\n * Allocates pages of memory.\n *\n * \\param Size The number of bytes to allocate. The number of pages allocated will be large enough to contain \\a Size bytes.\n * \\param Alignment The alignment value, which must be an integer power of 2.\n * \\return A pointer to the allocated block of memory, or NULL if the block could not be allocated.\n */\n_Use_decl_annotations_\nPVOID PhAllocatePageAligned(\n    _In_ SIZE_T Size,\n    _In_ SIZE_T Alignment\n    )\n{\n    return _aligned_malloc(Size, Alignment);\n\n    //NTSTATUS status;\n    //PVOID baseAddress = NULL;\n    //MEM_EXTENDED_PARAMETER extended[1];\n    //MEM_ADDRESS_REQUIREMENTS requirements;\n    //\n    //memset(&requirements, 0, sizeof(MEM_ADDRESS_REQUIREMENTS));\n    ////requirements.HighestEndingAddress = (PVOID)(ULONG_PTR)0x7fffffff; // Below 2GB\n    //requirements.Alignment = Alignment;\n    //\n    //memset(extended, 0, sizeof(extended));\n    //extended[0].Type = MemExtendedParameterAddressRequirements;\n    //extended[0].Pointer = &requirements;\n    //\n    //status = NtAllocateVirtualMemoryEx(\n    //    NtCurrentProcess(),\n    //    &baseAddress,\n    //    &Size,\n    //    MEM_RESERVE | MEM_COMMIT,\n    //    PAGE_READWRITE,\n    //    extended,\n    //    RTL_NUMBER_OF(extended)\n    //    );\n    //\n    //if (NT_SUCCESS(status))\n    //{\n    //    if (NewSize)\n    //        *NewSize = Size;\n    //    if (BaseAddress)\n    //        *BaseAddress = baseAddress;\n    //}\n    //\n    //return status;\n}\n\n/**\n * Frees pages of memory allocated with PhAllocatePageAligned().\n *\n * \\param Memory A pointer to a block of memory.\n */\nVOID PhFreePageAligned(\n    _In_opt_ _Frees_ptr_opt_ _Post_invalid_ PVOID Memory\n    )\n{\n    _aligned_free(Memory);\n}\n\n/**\n * Reserves, commits, or both, a region of pages within the user-mode virtual address space of a specified process.\n *\n * \\param ProcessHandle A handle to the process.\n * \\param BaseAddress The pointer that specifies a desired starting address for the region of pages that you want to allocate.\n * If you are reserving memory, the function rounds this address down to the nearest multiple of the allocation granularity.\n * If you are committing memory that is already reserved, the function rounds this address down to the nearest page boundary.\n * \\param AllocationSize The size of the region of memory to allocate, in bytes. If BaseAddress is NULL, the function rounds Size up to the next page boundary.\n * \\param AllocationType The type of memory allocation.\n * \\param Protection The type of memory protection.\n * \\return Successful or errant status.\n */\nNTSTATUS PhAllocateVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Outptr_result_bytebuffer_(AllocationSize) PVOID* BaseAddress,\n    _In_ SIZE_T AllocationSize,\n    _In_ ULONG AllocationType,\n    _In_ ULONG Protection\n    )\n{\n    NTSTATUS status;\n    PVOID baseAddress = NULL;\n    SIZE_T allocationSize = AllocationSize;\n\n    status = NtAllocateVirtualMemory(\n        ProcessHandle,\n        &baseAddress,\n        0,\n        &allocationSize,\n        AllocationType,\n        Protection\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *BaseAddress = baseAddress;\n    }\n\n    return status;\n}\n\n/**\n * Releases, decommits, or both releases and decommits, a region of pages within the virtual address space of a specified process.\n *\n * \\param ProcessHandle A handle to the process.\n * \\param BaseAddress The pointer that specifies a desired starting address for the region of pages that you want to allocate.\n * \\param FreeType A bitmask containing flags that describe the type of free operation.\n * \\return Successful or errant status.\n */\nNTSTATUS PhFreeVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG FreeType\n    )\n{\n    NTSTATUS status;\n    PVOID regionAddress = BaseAddress;\n    SIZE_T regionSize = 0;\n\n    status = NtFreeVirtualMemory(\n        ProcessHandle,\n        &regionAddress,\n        &regionSize,\n        FreeType\n        );\n\n    //if (status == STATUS_INVALID_PAGE_PROTECTION)\n    //{\n    //    if (RtlFlushSecureMemoryCache(regionAddress, regionSize))\n    //    {\n    //        status = NtFreeVirtualMemory(\n    //            ProcessHandle,\n    //            &regionAddress,\n    //            &regionSize,\n    //            FreeType\n    //            );\n    //    }\n    //}\n\n    return status;\n}\n\nNTSTATUS PhProtectVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize,\n    _In_ ULONG NewProtection,\n    _Out_opt_ PULONG OldProtection\n    )\n{\n    NTSTATUS status;\n    PVOID regionAddress = BaseAddress;\n    SIZE_T regionSize = RegionSize;\n    ULONG oldProtection = 0;\n\n    status = NtProtectVirtualMemory(\n        ProcessHandle,\n        &regionAddress,\n        &regionSize,\n        NewProtection,\n        &oldProtection\n        );\n\n    if (NT_SUCCESS(status) && OldProtection)\n    {\n        *OldProtection = oldProtection;\n        return STATUS_SUCCESS;\n    }\n\n    //if (status == STATUS_INVALID_PAGE_PROTECTION)\n    //{\n    //    if (RtlFlushSecureMemoryCache(regionAddress, regionSize))\n    //    {\n    //        status = NtProtectVirtualMemory(\n    //            ProcessHandle,\n    //            &regionAddress,\n    //            &regionSize,\n    //            NewProtection,\n    //            &oldProtection\n    //            );\n    //\n    //        if (NT_SUCCESS(status) && OldProtection)\n    //        {\n    //            *OldProtection = oldProtection;\n    //            return STATUS_SUCCESS;\n    //        }\n    //    }\n    //}\n\n    return status;\n}\n\n/**\n * Reads virtual memory from a specified process.\n *\n * \\param ProcessHandle Handle to the process from which the memory is to be read.\n * \\param BaseAddress Optional pointer to the base address in the specified process from which to read.\n * \\param Buffer Pointer to a buffer that receives the contents from the address space of the specified process.\n * \\param BufferSize Size of the buffer, in bytes.\n * \\param NumberOfBytesRead Optional pointer to a variable that receives the number of bytes read into the buffer.\n * \\return Successful or errant status.\n */\nNTSTATUS PhReadVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    )\n{\n    NTSTATUS status;\n    SIZE_T numberOfBytesRead;\n\n    if (ProcessHandle == NtCurrentProcess())\n    {\n        RtlMoveMemory(Buffer, BaseAddress, BufferSize);\n        if (NumberOfBytesRead)\n            *NumberOfBytesRead = BufferSize;\n        return STATUS_SUCCESS;\n    }\n\n    numberOfBytesRead = 0;\n    status = NtReadVirtualMemory(\n        ProcessHandle,\n        BaseAddress,\n        Buffer,\n        BufferSize,\n        &numberOfBytesRead\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        assert(BufferSize == numberOfBytesRead);\n    }\n\n    if (NumberOfBytesRead)\n    {\n        *NumberOfBytesRead = numberOfBytesRead;\n    }\n\n    return status;\n}\n\n/**\n * Writes virtual memory to the specified process.\n *\n * \\param ProcessHandle Handle to the process from which the memory is to be read.\n * \\param BaseAddress Optional pointer to the base address in the specified process from which to read.\n * \\param Buffer Pointer to a buffer that receives the contents from the address space of the specified process.\n * \\param NumberOfBytesToWrite The number of bytes to be written to the specified process.\n * \\param NumberOfBytesWritten A pointer to a variable that receives the number of bytes transferred into the specified buffer.\n * \\return Successful or errant status.\n */\nNTSTATUS PhWriteVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_reads_bytes_(NumberOfBytesToWrite) PVOID Buffer,\n    _In_ SIZE_T NumberOfBytesToWrite,\n    _Out_opt_ PSIZE_T NumberOfBytesWritten\n    )\n{\n    NTSTATUS status;\n    SIZE_T numberOfBytesWritten;\n\n    numberOfBytesWritten = 0;\n    status = NtWriteVirtualMemory(\n        ProcessHandle,\n        BaseAddress,\n        Buffer,\n        NumberOfBytesToWrite,\n        &numberOfBytesWritten\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        assert(NumberOfBytesToWrite == numberOfBytesWritten);\n    }\n\n    if (NumberOfBytesWritten)\n    {\n        *NumberOfBytesWritten = numberOfBytesWritten;\n    }\n\n    return status;\n}\n\n/**\n * Creates an array object.\n *\n * \\param Array An array object.\n * \\param ItemSize The size of each item, in bytes.\n * \\param InitialCapacity The number of elements to allocate storage for, initially.\n */\nVOID PhInitializeArray(\n    _Out_ PPH_ARRAY Array,\n    _In_ SIZE_T ItemSize,\n    _In_ SIZE_T InitialCapacity\n    )\n{\n    // Initial capacity of 0 is not allowed.\n    if (InitialCapacity == 0)\n        InitialCapacity = 1;\n\n    Array->Count = 0;\n    Array->AllocatedCount = InitialCapacity;\n    Array->ItemSize = ItemSize;\n    Array->Items = PhAllocate(Array->AllocatedCount * ItemSize);\n}\n\n/**\n * Frees resources used by an array object.\n *\n * \\param Array An array object.\n */\nVOID PhDeleteArray(\n    _Inout_ PPH_ARRAY Array\n    )\n{\n    PhFree(Array->Items);\n}\n\n/**\n * Resizes an array.\n *\n * \\param Array An array object.\n * \\param NewCapacity The new required number of elements for which storage has been reserved. This\n * must not be smaller than the current number of items in the array.\n */\nVOID PhResizeArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T NewCapacity\n    )\n{\n    if (Array->Count > NewCapacity)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    Array->AllocatedCount = NewCapacity;\n    Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize);\n}\n\n/**\n * Adds an item to an array.\n *\n * \\param Array An array object.\n * \\param Item The item to add.\n */\nVOID PhAddItemArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ PVOID Item\n    )\n{\n    // See if we need to resize the list.\n    if (Array->Count == Array->AllocatedCount)\n    {\n        Array->AllocatedCount *= 2;\n        Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize);\n    }\n\n    memcpy(PhItemArray(Array, Array->Count), Item, Array->ItemSize);\n    Array->Count++;\n}\n\n/**\n * Adds items to an array.\n *\n * \\param Array An array object.\n * \\param Items An array containing the items to add.\n * \\param Count The number of items to add.\n */\nVOID PhAddItemsArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ PVOID Items,\n    _In_ SIZE_T Count\n    )\n{\n    // See if we need to resize the list.\n    if (Array->AllocatedCount < Array->Count + Count)\n    {\n        Array->AllocatedCount *= 2;\n\n        if (Array->AllocatedCount < Array->Count + Count)\n            Array->AllocatedCount = Array->Count + Count;\n\n        Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize);\n    }\n\n    memcpy(\n        PhItemArray(Array, Array->Count),\n        Items,\n        Count * Array->ItemSize\n        );\n    Array->Count += Count;\n}\n\n/**\n * Clears an array.\n *\n * \\param Array An array object.\n */\nVOID PhClearArray(\n    _Inout_ PPH_ARRAY Array\n    )\n{\n    Array->Count = 0;\n}\n\n/**\n * Removes an item from an array.\n *\n * \\param Array An array object.\n * \\param Index The index of the item.\n */\nVOID PhRemoveItemArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T Index\n    )\n{\n    PhRemoveItemsArray(Array, Index, 1);\n}\n\n/**\n * Removes items from an array.\n *\n * \\param Array An array object.\n * \\param StartIndex The index at which to begin removing items.\n * \\param Count The number of items to remove.\n */\nVOID PhRemoveItemsArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    )\n{\n    // Shift the items after the items forward.\n    memmove(\n        PhItemArray(Array, StartIndex),\n        PhItemArray(Array, StartIndex + Count),\n        (Array->Count - StartIndex - Count) * Array->ItemSize\n        );\n    Array->Count -= Count;\n}\n\n/**\n * Creates a list object.\n *\n * \\param InitialCapacity The number of elements to allocate storage for, initially.\n */\nPPH_LIST PhCreateList(\n    _In_ ULONG InitialCapacity\n    )\n{\n    PPH_LIST list;\n\n    list = PhCreateObject(sizeof(PH_LIST), PhListType);\n\n    // Initial capacity of 0 is not allowed.\n    if (InitialCapacity == 0)\n        InitialCapacity = 1;\n\n    list->Count = 0;\n    list->AllocatedCount = InitialCapacity;\n    list->Items = PhAllocate(list->AllocatedCount * sizeof(PVOID));\n\n    return list;\n}\n\n_Use_decl_annotations_\nVOID PhpListDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_LIST list = (PPH_LIST)Object;\n\n    PhFree(list->Items);\n}\n\n/**\n * Resizes a list.\n *\n * \\param List A list object.\n * \\param NewCapacity The new required number of elements for which storage has been reserved. This\n * must not be smaller than the current number of items in the list.\n */\nVOID PhResizeList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG NewCapacity\n    )\n{\n    if (List->Count > NewCapacity)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    List->AllocatedCount = NewCapacity;\n    List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID));\n}\n\n/**\n * Adds an item to a list.\n *\n * \\param List A list object.\n * \\param Item The item to add.\n */\nVOID PhAddItemList(\n    _Inout_ PPH_LIST List,\n    _In_ PVOID Item\n    )\n{\n    // See if we need to resize the list.\n    if (List->Count == List->AllocatedCount)\n    {\n        List->AllocatedCount *= 2;\n        List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID));\n    }\n\n    List->Items[List->Count++] = Item;\n}\n\n/**\n * Adds items to a list.\n *\n * \\param List A list object.\n * \\param Items An array containing the items to add.\n * \\param Count The number of items to add.\n */\nVOID PhAddItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ PVOID *Items,\n    _In_ ULONG Count\n    )\n{\n    // See if we need to resize the list.\n    if (List->AllocatedCount < List->Count + Count)\n    {\n        List->AllocatedCount *= 2;\n\n        if (List->AllocatedCount < List->Count + Count)\n            List->AllocatedCount = List->Count + Count;\n\n        List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID));\n    }\n\n    memcpy(\n        &List->Items[List->Count],\n        Items,\n        Count * sizeof(PVOID)\n        );\n    List->Count += Count;\n}\n\n/**\n * Clears a list.\n *\n * \\param List A list object.\n */\nVOID PhClearList(\n    _Inout_ PPH_LIST List\n    )\n{\n    List->Count = 0;\n}\n\n/**\n * Locates an item in a list.\n *\n * \\param List A list object.\n * \\param Item The item to search for.\n *\n * \\return The index of the item. If the\n * item was not found, -1 is returned.\n */\n_Use_decl_annotations_\nULONG PhFindItemList(\n    _In_ PPH_LIST List,\n    _In_ PVOID Item\n    )\n{\n    for (ULONG i = 0; i < List->Count; i++)\n    {\n        if (List->Items[i] == Item)\n            return i;\n    }\n\n    return ULONG_MAX;\n}\n\n/**\n * Inserts an item into a list.\n *\n * \\param List A list object.\n * \\param Index The index at which to insert the item.\n * \\param Item The item to add.\n */\nVOID PhInsertItemList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index,\n    _In_ PVOID Item\n    )\n{\n    PhInsertItemsList(List, Index, &Item, 1);\n}\n\n/**\n * Inserts items into a list.\n *\n * \\param List A list object.\n * \\param Index The index at which to insert the items.\n * \\param Items An array containing the items to add.\n * \\param Count The number of items to add.\n */\nVOID PhInsertItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index,\n    _In_ PVOID *Items,\n    _In_ ULONG Count\n    )\n{\n    // See if we need to resize the list.\n    if (List->AllocatedCount < List->Count + Count)\n    {\n        List->AllocatedCount *= 2;\n\n        if (List->AllocatedCount < List->Count + Count)\n            List->AllocatedCount = List->Count + Count;\n\n        List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID));\n    }\n\n    if (Index < List->Count)\n    {\n        // Shift the existing items backward.\n        memmove(\n            &List->Items[Index + Count],\n            &List->Items[Index],\n            (List->Count - Index) * sizeof(PVOID)\n            );\n    }\n\n    // Copy the new items into the list.\n    memcpy(\n        &List->Items[Index],\n        Items,\n        Count * sizeof(PVOID)\n        );\n\n    List->Count += Count;\n}\n\n/**\n * Removes an item from a list.\n *\n * \\param List A list object.\n * \\param Index The index of the item.\n */\nVOID PhRemoveItemList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index\n    )\n{\n    PhRemoveItemsList(List, Index, 1);\n}\n\n/**\n * Removes items from a list.\n *\n * \\param List A list object.\n * \\param StartIndex The index at which to begin removing items.\n * \\param Count The number of items to remove.\n */\nVOID PhRemoveItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG StartIndex,\n    _In_ ULONG Count\n    )\n{\n    // Shift the items after the items forward.\n    memmove(\n        &List->Items[StartIndex],\n        &List->Items[StartIndex + Count],\n        (List->Count - StartIndex - Count) * sizeof(PVOID)\n        );\n    List->Count -= Count;\n}\n\n/**\n * Creates a pointer list object.\n *\n * \\param InitialCapacity The number of elements to allocate storage for initially.\n */\nPPH_POINTER_LIST PhCreatePointerList(\n    _In_ ULONG InitialCapacity\n    )\n{\n    PPH_POINTER_LIST pointerList;\n\n    pointerList = PhCreateObject(sizeof(PH_POINTER_LIST), PhPointerListType);\n\n    // Initial capacity of 0 is not allowed.\n    if (InitialCapacity == 0)\n        InitialCapacity = 1;\n\n    pointerList->Count = 0;\n    pointerList->AllocatedCount = InitialCapacity;\n    pointerList->FreeEntry = ULONG_MAX;\n    pointerList->NextEntry = 0;\n    pointerList->Items = PhAllocate(pointerList->AllocatedCount * sizeof(PVOID));\n\n    return pointerList;\n}\n\n_Use_decl_annotations_\nVOID NTAPI PhpPointerListDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_POINTER_LIST pointerList = (PPH_POINTER_LIST)Object;\n\n    PhFree(pointerList->Items);\n}\n\n/**\n * Decodes an index stored in a free entry.\n */\nFORCEINLINE ULONG PhpDecodePointerListIndex(\n    _In_ PVOID Index\n    )\n{\n    // At least with Microsoft's compiler, shift right on a signed value preserves the sign. This is\n    // important because we want decode(encode(-1)) = ((-1 << 1) | 1) >> 1 = -1.\n    return (ULONG)((LONG_PTR)Index >> 1);\n}\n\n/**\n * Encodes an index for storage in a free entry.\n */\nFORCEINLINE PVOID PhpEncodePointerListIndex(\n    _In_ ULONG Index\n    )\n{\n    return (PVOID)(((ULONG_PTR)Index << 1) | 0x1);\n}\n\nFORCEINLINE HANDLE PhpPointerListIndexToHandle(\n    _In_ ULONG Index\n    )\n{\n    // Add one to allow NULL handles to indicate failure/an invalid index.\n    return UlongToHandle(Index + 1);\n}\n\nFORCEINLINE ULONG PhpPointerListHandleToIndex(\n    _In_ HANDLE Handle\n    )\n{\n    return HandleToUlong(Handle) - 1;\n}\n\n/**\n * Adds a pointer to a pointer list.\n *\n * \\param PointerList A pointer list object.\n * \\param Pointer The pointer to add. The pointer must be at least 2 byte aligned.\n * \\return A handle to the pointer, valid until the pointer is removed from the pointer list.\n */\nHANDLE PhAddItemPointerList(\n    _Inout_ PPH_POINTER_LIST PointerList,\n    _In_ PVOID Pointer\n    )\n{\n    ULONG index;\n\n    assert(PH_IS_LIST_POINTER_VALID(Pointer));\n\n    // Use a free entry if possible.\n    if (PointerList->FreeEntry != ULONG_MAX)\n    {\n        PVOID oldPointer;\n\n        index = PointerList->FreeEntry;\n        oldPointer = PointerList->Items[index];\n        PointerList->Items[index] = Pointer;\n        PointerList->FreeEntry = PhpDecodePointerListIndex(oldPointer);\n    }\n    else\n    {\n        // Use the next entry.\n        if (PointerList->NextEntry == PointerList->AllocatedCount)\n        {\n            PointerList->AllocatedCount *= 2;\n            PointerList->Items = PhReAllocate(PointerList->Items, PointerList->AllocatedCount * sizeof(PVOID));\n        }\n\n        index = PointerList->NextEntry++;\n        PointerList->Items[index] = Pointer;\n    }\n\n    PointerList->Count++;\n\n    return PhpPointerListIndexToHandle(index);\n}\n\n/**\n * Enumerates the next pointer in a pointer list.\n *\n * \\param PointerList A pointer to the pointer list to enumerate.\n * \\param EnumerationKey A pointer to a variable that maintains the enumeration state.\n * This should be initialized to zero before the first call.\n * \\param Pointer Receives the next pointer in the list.\n * \\param PointerHandle Receives the handle associated with the pointer, if any.\n * \\return TRUE if a pointer was successfully enumerated; FALSE if there are no more pointers.\n */\n_Use_decl_annotations_\nBOOLEAN PhEnumPointerListEx(\n    _In_ PPH_POINTER_LIST PointerList,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PVOID *Pointer,\n    _Out_ PHANDLE PointerHandle\n    )\n{\n    ULONG index;\n\n    while ((index = *EnumerationKey) < PointerList->NextEntry)\n    {\n        PVOID pointer = PointerList->Items[index];\n\n        (*EnumerationKey)++;\n\n        if (PH_IS_LIST_POINTER_VALID(pointer))\n        {\n            *Pointer = pointer;\n            *PointerHandle = PhpPointerListIndexToHandle(index);\n\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Locates a pointer in a pointer list.\n *\n * \\param PointerList A pointer list object.\n * \\param Pointer The pointer to find. The pointer must be at least 2 byte aligned.\n * \\return A handle to the pointer, valid until the pointer is removed from the pointer list. If the\n * pointer is not contained in the pointer list, NULL is returned.\n */\nHANDLE PhFindItemPointerList(\n    _In_ PPH_POINTER_LIST PointerList,\n    _In_ PVOID Pointer\n    )\n{\n    ULONG i;\n\n    assert(PH_IS_LIST_POINTER_VALID(Pointer));\n\n    for (i = 0; i < PointerList->NextEntry; i++)\n    {\n        if (PointerList->Items[i] == Pointer)\n            return PhpPointerListIndexToHandle(i);\n    }\n\n    return NULL;\n}\n\n/**\n * Removes a pointer from a pointer list.\n *\n * \\param PointerList A pointer list object.\n * \\param PointerHandle A handle to the pointer to remove.\n * \\remarks No checking is performed on the pointer handle. Make sure the handle is valid before\n * calling the function.\n */\nVOID PhRemoveItemPointerList(\n    _Inout_ PPH_POINTER_LIST PointerList,\n    _In_ HANDLE PointerHandle\n    )\n{\n    ULONG index;\n\n    assert(PointerHandle);\n\n    index = PhpPointerListHandleToIndex(PointerHandle);\n\n    PointerList->Items[index] = PhpEncodePointerListIndex(PointerList->FreeEntry);\n    PointerList->FreeEntry = index;\n\n    PointerList->Count--;\n}\n\nFORCEINLINE ULONG PhpValidateHash(\n    _In_ ULONG Hash\n    )\n{\n    // No point in using a full hash when we're going to AND with size minus one anyway.\n#if defined(PH_HASHTABLE_FULL_HASH) && !defined(PH_HASHTABLE_POWER_OF_TWO_SIZE)\n    if (Hash != ULONG_MAX)\n        return Hash;\n    else\n        return 0;\n#else\n    return Hash & MAXLONG;\n#endif\n}\n\nFORCEINLINE ULONG PhpIndexFromHash(\n    _In_ PPH_HASHTABLE Hashtable,\n    _In_ ULONG Hash\n    )\n{\n#ifdef PH_HASHTABLE_POWER_OF_TWO_SIZE\n    return Hash & (Hashtable->AllocatedBuckets - 1);\n#else\n    return Hash % Hashtable->AllocatedBuckets;\n#endif\n}\n\nFORCEINLINE ULONG PhpGetNumberOfBuckets(\n    _In_ ULONG Capacity\n    )\n{\n#ifdef PH_HASHTABLE_POWER_OF_TWO_SIZE\n    return PhRoundUpToPowerOfTwo(Capacity);\n#else\n    return PhGetPrimeNumber(Capacity);\n#endif\n}\n\n/**\n * Creates a hashtable object.\n *\n * \\param EntrySize The size of each hashtable entry, in bytes.\n * \\param EqualFunction A comparison function that is executed to compare two hashtable entries.\n * \\param HashFunction A hash function that is executed to generate a hash code for a hashtable entry.\n * \\param InitialCapacity The number of entries to allocate storage for initially.\n */\nPPH_HASHTABLE PhCreateHashtable(\n    _In_ ULONG EntrySize,\n    _In_ PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction,\n    _In_ PPH_HASHTABLE_HASH_FUNCTION HashFunction,\n    _In_ ULONG InitialCapacity\n    )\n{\n    PPH_HASHTABLE hashtable;\n\n    hashtable = PhCreateObject(sizeof(PH_HASHTABLE), PhHashtableType);\n\n    // Initial capacity of 0 is not allowed.\n    if (InitialCapacity == 0)\n        InitialCapacity = 1;\n\n    hashtable->EntrySize = EntrySize;\n    hashtable->EqualFunction = EqualFunction;\n    hashtable->HashFunction = HashFunction;\n\n    // Allocate the buckets.\n    hashtable->AllocatedBuckets = PhpGetNumberOfBuckets(InitialCapacity);\n    hashtable->Buckets = PhAllocate(sizeof(ULONG) * hashtable->AllocatedBuckets);\n    // Set all bucket values to -1.\n    memset(hashtable->Buckets, 0xff, sizeof(ULONG) * hashtable->AllocatedBuckets);\n\n    // Allocate the entries.\n    hashtable->AllocatedEntries = hashtable->AllocatedBuckets;\n    hashtable->Entries = PhAllocate(PH_HASHTABLE_ENTRY_SIZE(EntrySize) * hashtable->AllocatedEntries);\n\n    hashtable->Count = 0;\n    hashtable->FreeEntry = ULONG_MAX;\n    hashtable->NextEntry = 0;\n\n    return hashtable;\n}\n\n_Use_decl_annotations_\nVOID PhpHashtableDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_HASHTABLE hashtable = (PPH_HASHTABLE)Object;\n\n    PhFree(hashtable->Buckets);\n    PhFree(hashtable->Entries);\n}\n\nVOID PhpResizeHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ ULONG NewCapacity\n    )\n{\n    PPH_HASHTABLE_ENTRY entry;\n    ULONG i;\n\n    // Re-allocate the buckets. Note that we don't need to keep the contents.\n    Hashtable->AllocatedBuckets = PhpGetNumberOfBuckets(NewCapacity);\n    PhFree(Hashtable->Buckets);\n    Hashtable->Buckets = PhAllocate(sizeof(ULONG) * Hashtable->AllocatedBuckets);\n    // Set all bucket values to -1.\n    memset(Hashtable->Buckets, 0xff, sizeof(ULONG) * Hashtable->AllocatedBuckets);\n\n    // Re-allocate the entries.\n    Hashtable->AllocatedEntries = Hashtable->AllocatedBuckets;\n    Hashtable->Entries = PhReAllocate(\n        Hashtable->Entries,\n        PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize) * Hashtable->AllocatedEntries\n        );\n\n    // Re-distribute the entries among the buckets.\n\n    // PH_HASHTABLE_GET_ENTRY is quite slow (it involves a multiply), so we use a pointer here.\n    entry = Hashtable->Entries;\n\n    for (i = 0; i < Hashtable->NextEntry; i++)\n    {\n        if (entry->HashCode != ULONG_MAX)\n        {\n            ULONG index = PhpIndexFromHash(Hashtable, entry->HashCode);\n\n            entry->Next = Hashtable->Buckets[index];\n            Hashtable->Buckets[index] = i;\n        }\n\n        entry = PTR_ADD_OFFSET(entry, PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize));\n    }\n}\n\nFORCEINLINE PVOID PhpAddEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry,\n    _In_ BOOLEAN CheckForDuplicate,\n    _Out_opt_ PBOOLEAN Added\n    )\n{\n    ULONG hashCode; // hash code of the new entry\n    ULONG index; // bucket index of the new entry\n    ULONG freeEntry; // index of new entry in entry array\n    PPH_HASHTABLE_ENTRY entry; // pointer to new entry in entry array\n\n    hashCode = PhpValidateHash(Hashtable->HashFunction(Entry));\n    index = PhpIndexFromHash(Hashtable, hashCode);\n\n    if (CheckForDuplicate)\n    {\n        ULONG i;\n\n        for (i = Hashtable->Buckets[index]; i != ULONG_MAX; i = entry->Next)\n        {\n            entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i);\n\n            if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry))\n            {\n                if (Added)\n                    *Added = FALSE;\n\n                return &entry->Body;\n            }\n        }\n    }\n\n    // Use a free entry if possible.\n    if (Hashtable->FreeEntry != ULONG_MAX)\n    {\n        freeEntry = Hashtable->FreeEntry;\n        entry = PH_HASHTABLE_GET_ENTRY(Hashtable, freeEntry);\n        Hashtable->FreeEntry = entry->Next;\n    }\n    else\n    {\n        // Use the next entry in the entry array.\n\n        if (Hashtable->NextEntry == Hashtable->AllocatedEntries)\n        {\n            // Resize the hashtable.\n            PhpResizeHashtable(Hashtable, Hashtable->AllocatedBuckets * 2);\n            index = PhpIndexFromHash(Hashtable, hashCode);\n        }\n\n        freeEntry = Hashtable->NextEntry++;\n        entry = PH_HASHTABLE_GET_ENTRY(Hashtable, freeEntry);\n    }\n\n    // Initialize the entry.\n    entry->HashCode = hashCode;\n    entry->Next = Hashtable->Buckets[index];\n    Hashtable->Buckets[index] = freeEntry;\n    // Copy the user-supplied data to the entry.\n    memcpy(&entry->Body, Entry, Hashtable->EntrySize);\n\n    Hashtable->Count++;\n\n    if (Added)\n        *Added = TRUE;\n\n    return &entry->Body;\n}\n\n/**\n * Adds an entry to a hashtable.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry The entry to add.\n * \\return A pointer to the entry as stored in the hashtable. This pointer is valid until the\n * hashtable is modified. If the hashtable already contained an equal entry, NULL is returned.\n * \\remarks Entries are only guaranteed to be 8 byte aligned, even on 64-bit systems.\n */\nPVOID PhAddEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    )\n{\n    PVOID entry;\n    BOOLEAN added;\n\n    entry = PhpAddEntryHashtable(Hashtable, Entry, TRUE, &added);\n\n    if (added)\n        return entry;\n    else\n        return NULL;\n}\n\n/**\n * Adds an entry to a hashtable or returns an existing one.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry The entry to add.\n * \\param Added A variable which receives TRUE if a new entry was created, and FALSE if an existing\n * entry was returned.\n * \\return A pointer to the entry as stored in the hashtable. This pointer is valid until the\n * hashtable is modified. If the hashtable already contained an equal entry, the existing entry is\n * returned. Check the value of \\a Added to determine whether the returned entry is new or existing.\n * \\remarks Entries are only guaranteed to be 8 byte aligned, even on 64-bit systems.\n */\nPVOID PhAddEntryHashtableEx(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry,\n    _Out_opt_ PBOOLEAN Added\n    )\n{\n    return PhpAddEntryHashtable(Hashtable, Entry, TRUE, Added);\n}\n\n/**\n * Clears a hashtable.\n *\n * \\param Hashtable A hashtable object.\n */\nVOID PhClearHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable\n    )\n{\n    if (Hashtable->Count > 0)\n    {\n        memset(Hashtable->Buckets, 0xff, sizeof(ULONG) * Hashtable->AllocatedBuckets);\n        Hashtable->Count = 0;\n        Hashtable->FreeEntry = ULONG_MAX;\n        Hashtable->NextEntry = 0;\n    }\n}\n\n/**\n * Enumerates the entries in a hashtable.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry A variable which receives a pointer to the hashtable entry. The pointer is valid\n * until the hashtable is modified.\n * \\param EnumerationKey A variable which is initialized to 0 before first calling this function.\n * \\return TRUE if an entry pointer was stored in \\a Entry, FALSE if there are no more entries.\n * \\remarks Do not modify the hashtable while the hashtable is being enumerated (between calls to\n * this function). Otherwise, the function may behave unexpectedly. You may reset the\n * \\a EnumerationKey variable to 0 if you wish to restart the enumeration.\n */\n_Use_decl_annotations_\nBOOLEAN PhEnumHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _Out_ PVOID *Entry,\n    _Inout_ PULONG EnumerationKey\n    )\n{\n    while (*EnumerationKey < Hashtable->NextEntry)\n    {\n        PPH_HASHTABLE_ENTRY entry = PH_HASHTABLE_GET_ENTRY(Hashtable, *EnumerationKey);\n\n        (*EnumerationKey)++;\n\n        if (entry->HashCode != ULONG_MAX)\n        {\n            *Entry = &entry->Body;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Locates an entry in a hashtable.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry An entry representing the entry to find.\n * \\return A pointer to the entry as stored in the hashtable. This pointer is valid until the\n * hashtable is modified. If the entry could not be found, NULL is returned.\n * \\remarks The entry specified in \\a Entry can be a partial entry that is filled in enough so that\n * the comparison and hash functions can work with them.\n */\nPVOID PhFindEntryHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    )\n{\n    ULONG hashCode;\n    ULONG index;\n    ULONG i;\n    PPH_HASHTABLE_ENTRY entry;\n\n    hashCode = PhpValidateHash(Hashtable->HashFunction(Entry));\n    index = PhpIndexFromHash(Hashtable, hashCode);\n\n    for (i = Hashtable->Buckets[index]; i != ULONG_MAX; i = entry->Next)\n    {\n        entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i);\n\n        if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry))\n        {\n            return &entry->Body;\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Removes an entry from a hashtable.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry The entry to remove.\n * \\return TRUE if the entry was removed, FALSE if the entry could not be found.\n * \\remarks The entry specified in \\a Entry can be an actual entry pointer returned by\n * PhFindEntryHashtable, or a partial entry.\n */\nBOOLEAN PhRemoveEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    )\n{\n    ULONG hashCode;\n    ULONG index;\n    ULONG i;\n    ULONG previousIndex;\n    PPH_HASHTABLE_ENTRY entry;\n\n    hashCode = PhpValidateHash(Hashtable->HashFunction(Entry));\n    index = PhpIndexFromHash(Hashtable, hashCode);\n    previousIndex = ULONG_MAX;\n\n    for (i = Hashtable->Buckets[index]; i != ULONG_MAX; i = entry->Next)\n    {\n        entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i);\n\n        if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry))\n        {\n            // Unlink the entry from the bucket.\n            if (previousIndex == ULONG_MAX)\n            {\n                Hashtable->Buckets[index] = entry->Next;\n            }\n            else\n            {\n                PH_HASHTABLE_GET_ENTRY(Hashtable, previousIndex)->Next = entry->Next;\n            }\n\n            entry->HashCode = ULONG_MAX; // indicates the entry is not being used\n            entry->Next = Hashtable->FreeEntry;\n            Hashtable->FreeEntry = i;\n\n            Hashtable->Count--;\n\n            return TRUE;\n        }\n\n        previousIndex = i;\n    }\n\n    return FALSE;\n}\n\n/**\n * Generates a hash code for a sequence of bytes.\n *\n * \\param Bytes A pointer to a byte array.\n * \\param Length The number of bytes to hash.\n */\nULONG PhHashBytes(\n    _In_reads_(Length) PUCHAR Bytes,\n    _In_ SIZE_T Length\n    )\n{\n    ULONG hash = 0;\n\n    if (Length == 0)\n        return hash;\n\n    // FNV-1a algorithm: http://www.isthe.com/chongo/src/fnv/hash_32a.c\n\n    while (Length-- != 0)\n    {\n        hash ^= *Bytes++;\n        hash *= 0x01000193;\n    }\n\n    return hash;\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PhpSimpleHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_KEY_VALUE_PAIR entry1 = Entry1;\n    PPH_KEY_VALUE_PAIR entry2 = Entry2;\n\n    return entry1->Key == entry2->Key;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpSimpleHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_KEY_VALUE_PAIR entry = Entry;\n\n    return PhHashIntPtr((ULONG_PTR)entry->Key);\n}\n\n/**\n * Creates a simple hash table with the specified initial capacity.\n *\n * \\param InitialCapacity The initial number of buckets to allocate for the hash table.\n * \\return A pointer to the newly created hash table (PPH_HASHTABLE), or NULL if allocation fails.\n */\nPPH_HASHTABLE PhCreateSimpleHashtable(\n    _In_ ULONG InitialCapacity\n    )\n{\n    return PhCreateHashtable(\n        sizeof(PH_KEY_VALUE_PAIR),\n        PhpSimpleHashtableEqualFunction,\n        PhpSimpleHashtableHashFunction,\n        InitialCapacity\n        );\n}\n\n/**\n * Adds an item to a simple hashtable.\n *\n * \\param SimpleHashtable Pointer to the hashtable to which the item will be added.\n * \\param Key Optional pointer to the key for the item.\n * \\param Value Optional pointer to the value to associate with the key.\n * \\return Returns a pointer to the added item, or NULL if the operation fails.\n */\nPVOID PhAddItemSimpleHashtable(\n    _Inout_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key,\n    _In_opt_ PVOID Value\n    )\n{\n    PH_KEY_VALUE_PAIR entry;\n\n    entry.Key = Key;\n    entry.Value = Value;\n\n    if (PhAddEntryHashtable(SimpleHashtable, &entry))\n        return Value;\n    else\n        return NULL;\n}\n\n/**\n * Finds an item in a simple hashtable by its key.\n *\n * \\param SimpleHashtable A pointer to the hashtable to search.\n * \\param Key An optional pointer to the key to search for. If NULL, the function may behave differently depending on implementation.\n * \\return A pointer to the found item, or NULL if the key is not present in the hashtable.\n */\nPVOID *PhFindItemSimpleHashtable(\n    _In_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    )\n{\n    PH_KEY_VALUE_PAIR lookupEntry;\n    PPH_KEY_VALUE_PAIR entry;\n\n    lookupEntry.Key = Key;\n    entry = PhFindEntryHashtable(SimpleHashtable, &lookupEntry);\n\n    if (entry)\n        return &entry->Value;\n    else\n        return NULL;\n}\n\n/**\n * Removes an item from a simple hashtable.\n *\n * \\param SimpleHashtable Pointer to the hashtable from which the item will be removed.\n * \\param Key Optional pointer to the key of the item to remove. If NULL, no item is removed.\n * \\return TRUE if the item was successfully removed; FALSE otherwise.\n */\nBOOLEAN PhRemoveItemSimpleHashtable(\n    _Inout_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    )\n{\n    PH_KEY_VALUE_PAIR lookupEntry;\n\n    lookupEntry.Key = Key;\n\n    return PhRemoveEntryHashtable(SimpleHashtable, &lookupEntry);\n}\n\n/**\n * Initializes a free list object.\n *\n * \\param FreeList A pointer to the free list object.\n * \\param Size The number of bytes in each allocation.\n * \\param MaximumCount The number of unused allocations to store.\n */\nVOID PhInitializeFreeList(\n    _Out_ PPH_FREE_LIST FreeList,\n    _In_ SIZE_T Size,\n    _In_ ULONG MaximumCount\n    )\n{\n    PhInitializeSListHead(&FreeList->ListHead);\n    FreeList->Count = 0;\n    FreeList->MaximumCount = MaximumCount;\n    FreeList->Size = Size;\n}\n\n/**\n * Frees resources used by a free list object.\n *\n * \\param FreeList A pointer to the free list object.\n */\nVOID PhDeleteFreeList(\n    _Inout_ PPH_FREE_LIST FreeList\n    )\n{\n    PPH_FREE_LIST_ENTRY entry;\n    PSLIST_ENTRY listEntry;\n\n    listEntry = RtlInterlockedFlushSList(&FreeList->ListHead);\n\n    while (listEntry)\n    {\n        entry = CONTAINING_RECORD(listEntry, PH_FREE_LIST_ENTRY, ListEntry);\n        listEntry = listEntry->Next;\n        PhFree(entry);\n    }\n}\n\n/**\n * Allocates a block of memory from a free list.\n *\n * \\param FreeList A pointer to a free list object.\n *\n * \\return A pointer to the allocated block of memory. The memory must be freed using\n * PhFreeToFreeList(). The block is guaranteed to be aligned at MEMORY_ALLOCATION_ALIGNMENT bytes.\n */\nPVOID PhAllocateFromFreeList(\n    _Inout_ PPH_FREE_LIST FreeList\n    )\n{\n    PPH_FREE_LIST_ENTRY entry;\n    PSLIST_ENTRY listEntry;\n\n    listEntry = RtlInterlockedPopEntrySList(&FreeList->ListHead);\n\n    if (listEntry)\n    {\n        _InterlockedDecrement((PLONG)&FreeList->Count);\n        entry = CONTAINING_RECORD(listEntry, PH_FREE_LIST_ENTRY, ListEntry);\n    }\n    else\n    {\n        entry = PhAllocate(UFIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) + FreeList->Size);\n    }\n\n    return &entry->Body;\n}\n\n/**\n * Frees a block of memory to a free list.\n *\n * \\param FreeList A pointer to a free list object.\n * \\param Memory A pointer to a block of memory.\n */\nVOID PhFreeToFreeList(\n    _Inout_ PPH_FREE_LIST FreeList,\n    _In_ _Post_invalid_ PVOID Memory\n    )\n{\n    PPH_FREE_LIST_ENTRY entry;\n\n    entry = CONTAINING_RECORD(Memory, PH_FREE_LIST_ENTRY, Body);\n\n    // We don't enforce Count <= MaximumCount (that would require locking),\n    // but we do check it.\n    if (FreeList->Count < FreeList->MaximumCount)\n    {\n        RtlInterlockedPushEntrySList(&FreeList->ListHead, &entry->ListEntry);\n        _InterlockedIncrement((PLONG)&FreeList->Count);\n    }\n    else\n    {\n        PhFree(entry);\n    }\n}\n\n/**\n * Initializes a callback object.\n *\n * \\param Callback A pointer to a callback object.\n */\nVOID PhInitializeCallback(\n    _Out_ PPH_CALLBACK Callback\n    )\n{\n    InitializeListHead(&Callback->ListHead);\n    PhInitializeQueuedLock(&Callback->ListLock);\n    PhInitializeCondition(&Callback->BusyCondition);\n}\n\n/**\n * Frees resources used by a callback object.\n *\n * \\param Callback A pointer to a callback object.\n */\nVOID PhDeleteCallback(\n    _Inout_ PPH_CALLBACK Callback\n    )\n{\n    PhAcquireQueuedLockExclusive(&Callback->ListLock);\n    \n    // Assert that all callbacks have been unregistered\n    assert(IsListEmpty(&Callback->ListHead));\n    \n    PhReleaseQueuedLockExclusive(&Callback->ListLock);\n}\n\n/**\n * Registers a callback function to be notified.\n *\n * \\param Callback A pointer to a callback object.\n * \\param Function The callback function.\n * \\param Context A user-defined value to pass to the callback function.\n * \\param Registration A variable which receives registration information for the callback. Do not\n * modify the contents of this structure and do not free the storage for this structure until you\n * have unregistered the callback.\n */\nVOID PhRegisterCallback(\n    _Inout_ PPH_CALLBACK Callback,\n    _In_ PPH_CALLBACK_FUNCTION Function,\n    _In_opt_ PVOID Context,\n    _Out_ PPH_CALLBACK_REGISTRATION Registration\n    )\n{\n    PhRegisterCallbackEx(\n        Callback,\n        Function,\n        Context,\n        0,\n        Registration\n        );\n}\n\n/**\n * Registers a callback function to be notified.\n *\n * \\param Callback A pointer to a callback object.\n * \\param Function The callback function.\n * \\param Context A user-defined value to pass to the callback function.\n * \\param Flags A combination of flags controlling the callback. Set this parameter to 0.\n * \\param Registration A variable which receives registration information for the callback. Do not\n * modify the contents of this structure and do not free the storage for this structure until you\n * have unregistered the callback.\n */\nVOID PhRegisterCallbackEx(\n    _Inout_ PPH_CALLBACK Callback,\n    _In_ PPH_CALLBACK_FUNCTION Function,\n    _In_opt_ PVOID Context,\n    _In_ USHORT Flags,\n    _Out_ PPH_CALLBACK_REGISTRATION Registration\n    )\n{\n    Registration->Function = Function;\n    Registration->Context = Context;\n    Registration->Busy = 0;\n    Registration->Unregistering = FALSE;\n    Registration->Flags = Flags;\n\n    PhAcquireQueuedLockExclusive(&Callback->ListLock);\n    InsertTailList(&Callback->ListHead, &Registration->ListEntry);\n    PhReleaseQueuedLockExclusive(&Callback->ListLock);\n}\n\n/**\n * Unregisters a callback function.\n *\n * \\param Callback A pointer to a callback object.\n * \\param Registration The structure returned by PhRegisterCallback().\n *\n * \\remarks It is guaranteed that the callback function will not be in execution once this function\n * returns. Attempting to unregister a callback function from within the same function will result\n * in a deadlock.\n */\nVOID PhUnregisterCallback(\n    _Inout_ PPH_CALLBACK Callback,\n    _Inout_ PPH_CALLBACK_REGISTRATION Registration\n    )\n{\n    Registration->Unregistering = TRUE;\n\n    PhAcquireQueuedLockExclusive(&Callback->ListLock);\n\n    // Wait for the callback to be unbusy.\n    while (Registration->Busy)\n        PhWaitForCondition(&Callback->BusyCondition, &Callback->ListLock, NULL);\n\n    RemoveEntryList(&Registration->ListEntry);\n\n    PhReleaseQueuedLockExclusive(&Callback->ListLock);\n}\n\n/**\n * Notifies all registered callback functions.\n *\n * \\param Callback A pointer to a callback object.\n * \\param Parameter A value to pass to all callback functions.\n */\nVOID PhInvokeCallback(\n    _In_ PPH_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PLIST_ENTRY listEntry;\n\n    PhTraceFuncEnter(\"Invoke callback %p\", Callback);\n\n    PhAcquireQueuedLockShared(&Callback->ListLock);\n\n    for (listEntry = Callback->ListHead.Flink; listEntry != &Callback->ListHead; listEntry = listEntry->Flink)\n    {\n        PPH_CALLBACK_REGISTRATION registration;\n        LONG busy;\n\n        registration = CONTAINING_RECORD(listEntry, PH_CALLBACK_REGISTRATION, ListEntry);\n\n        // Don't bother executing the callback function if it is being unregistered.\n        if (registration->Unregistering)\n            continue;\n\n        _InterlockedIncrement(&registration->Busy);\n\n        // Execute the callback function.\n\n        PhReleaseQueuedLockShared(&Callback->ListLock);\n        registration->Function(\n            Parameter,\n            registration->Context\n            );\n        PhAcquireQueuedLockShared(&Callback->ListLock);\n\n        busy = _InterlockedDecrement(&registration->Busy);\n\n        if (registration->Unregistering && busy == 0)\n        {\n            // Someone started unregistering while the callback function was executing, and we must\n            // wake them.\n            PhPulseAllCondition(&Callback->BusyCondition);\n        }\n    }\n\n    PhReleaseQueuedLockShared(&Callback->ListLock);\n\n    PhTraceFuncExit(\"Invoke callback %p\", Callback);\n}\n\n/**\n * Retrieves a prime number bigger than or equal to the specified number.\n */\nULONG PhGetPrimeNumber(\n    _In_ ULONG Minimum\n    )\n{\n    ULONG i, j;\n\n    for (i = 0; i < sizeof(PhpPrimeNumbers) / sizeof(ULONG); i++)\n    {\n        if (PhpPrimeNumbers[i] >= Minimum)\n            return PhpPrimeNumbers[i];\n    }\n\n    for (i = Minimum | 1; i < MAXLONG; i += 2)\n    {\n        ULONG sqrtI = (ULONG)sqrt(i);\n\n        for (j = 3; j <= sqrtI; j += 2)\n        {\n            if (i % j == 0)\n            {\n                // Not a prime.\n                goto NextPrime;\n            }\n        }\n\n        // Success.\n        return i;\nNextPrime:\n        NOTHING;\n    }\n\n    return Minimum;\n}\n\n/**\n * Rounds up a number to the next power of two.\n */\nULONG PhRoundUpToPowerOfTwo(\n    _In_ ULONG Number\n    )\n{\n    Number--;\n    Number |= Number >> 1;\n    Number |= Number >> 2;\n    Number |= Number >> 4;\n    Number |= Number >> 8;\n    Number |= Number >> 16;\n    Number++;\n\n    return Number;\n}\n\n/**\n * Performs exponentiation.\n */\nULONG PhExponentiate(\n    _In_ ULONG Base,\n    _In_ ULONG Exponent\n    )\n{\n    ULONG result = 1;\n\n    while (Exponent)\n    {\n        if (Exponent & 1)\n            result *= Base;\n\n        Exponent >>= 1;\n        Base *= Base;\n    }\n\n    return result;\n}\n\n/**\n * Performs 64-bit exponentiation.\n */\nULONG64 PhExponentiate64(\n    _In_ ULONG64 Base,\n    _In_ ULONG Exponent\n    )\n{\n    ULONG64 result = 1;\n\n    while (Exponent)\n    {\n        if (Exponent & 1)\n            result *= Base;\n\n        Exponent >>= 1;\n        Base *= Base;\n    }\n\n    return result;\n}\n\n/**\n * Formats a time span, specified in ticks, into a human-readable string.\n *\n * \\param Destination A pointer to a buffer that receives the formatted time span string.\n * \\param Ticks The time span to format, in ticks.\n * \\param Mode Optional formatting mode. If specified, determines the output format.\n */\nVOID PhPrintTimeSpan(\n    _Out_writes_(PH_TIMESPAN_STR_LEN_1) PWSTR Destination,\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode\n    )\n{\n    PhPrintTimeSpanToBuffer(\n        Ticks,\n        Mode,\n        Destination,\n        PH_TIMESPAN_STR_LEN_1 * sizeof(WCHAR),\n        NULL\n        );\n}\n\n/**\n * Converts a time span specified in ticks to a human-readable string and writes it to the provided buffer.\n *\n * \\param Ticks The time span to print, in ticks (typically 100-nanosecond intervals).\n * \\param Mode mode specifying the formatting style. Can be NULL for default formatting.\n * \\param Buffer Pointer to the buffer that receives the formatted time span string.\n * \\param BufferLength Size of the buffer, in bytes.\n * \\param ReturnLength Optional pointer that receives the number of characters written to the buffer (excluding the null terminator).\n * \\return TRUE if the time span was successfully formatted and written to the buffer; FALSE otherwise.\n */\nBOOLEAN PhPrintTimeSpanToBuffer(\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    switch (Mode)\n    {\n    case PH_TIMESPAN_HMSM:\n        {\n            PH_FORMAT format[7];\n\n            // %02I64u:%02I64u:%02I64u.%03I64u\n            PhInitFormatI64UWithWidth(&format[0], PH_TICKS_PARTIAL_HOURS(Ticks), 2);\n            PhInitFormatC(&format[1], L':');\n            PhInitFormatI64UWithWidth(&format[2], PH_TICKS_PARTIAL_MIN(Ticks), 2);\n            PhInitFormatC(&format[3], L':');\n            PhInitFormatI64UWithWidth(&format[4], PH_TICKS_PARTIAL_SEC(Ticks), 2);\n            PhInitFormatC(&format[5], L'.');\n            PhInitFormatI64UWithWidth(&format[6], PH_TICKS_PARTIAL_MS(Ticks), 3);\n\n            return PhFormatToBuffer(format, RTL_NUMBER_OF(format), Buffer, BufferLength, ReturnLength);\n        }\n        break;\n    case PH_TIMESPAN_DHMS:\n        {\n            PH_FORMAT format[7];\n\n            // %llu:%02I64u:%02I64u:%02I64u\n            PhInitFormatI64U(&format[0], PH_TICKS_PARTIAL_DAYS(Ticks));\n            PhInitFormatC(&format[1], L':');\n            PhInitFormatI64UWithWidth(&format[2], PH_TICKS_PARTIAL_HOURS(Ticks), 2);\n            PhInitFormatC(&format[3], L':');\n            PhInitFormatI64UWithWidth(&format[4], PH_TICKS_PARTIAL_MIN(Ticks), 2);\n            PhInitFormatC(&format[5], L':');\n            PhInitFormatI64UWithWidth(&format[6], PH_TICKS_PARTIAL_SEC(Ticks), 2);\n\n            return PhFormatToBuffer(format, RTL_NUMBER_OF(format), Buffer, BufferLength, ReturnLength);\n        }\n        break;\n    case PH_TIMESPAN_DHMSM:\n        {\n            PH_FORMAT format[9];\n\n            // %llu:%02I64u:%02I64u:%02I64u\n            PhInitFormatI64U(&format[0], PH_TICKS_PARTIAL_DAYS(Ticks));\n            PhInitFormatC(&format[1], L':');\n            PhInitFormatI64UWithWidth(&format[2], PH_TICKS_PARTIAL_HOURS(Ticks), 2);\n            PhInitFormatC(&format[3], L':');\n            PhInitFormatI64UWithWidth(&format[4], PH_TICKS_PARTIAL_MIN(Ticks), 2);\n            PhInitFormatC(&format[5], L':');\n            PhInitFormatI64UWithWidth(&format[6], PH_TICKS_PARTIAL_SEC(Ticks), 2);\n            PhInitFormatC(&format[7], L':');\n            PhInitFormatI64UWithWidth(&format[8], PH_TICKS_PARTIAL_MS(Ticks), 3);\n\n            return PhFormatToBuffer(format, RTL_NUMBER_OF(format), Buffer, BufferLength, ReturnLength);\n        }\n        break;\n    default:\n        {\n            PH_FORMAT format[5];\n\n            // %02I64u:%02I64u:%02I64u\n            PhInitFormatI64UWithWidth(&format[0], PH_TICKS_PARTIAL_HOURS(Ticks), 2);\n            PhInitFormatC(&format[1], L':');\n            PhInitFormatI64UWithWidth(&format[2], PH_TICKS_PARTIAL_MIN(Ticks), 2);\n            PhInitFormatC(&format[3], L'.');\n            PhInitFormatI64UWithWidth(&format[4], PH_TICKS_PARTIAL_SEC(Ticks), 2);\n\n            return PhFormatToBuffer(format, RTL_NUMBER_OF(format), Buffer, BufferLength, ReturnLength);\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n * Calculates the entropy, mean, and variance of a given buffer.\n *\n * \\param Buffer Pointer to the buffer containing data to analyze.\n * \\param BufferLength Length of the buffer in bytes.\n * \\param Entropy Optional pointer to a FLOAT to receive the calculated entropy.\n * \\param Mean Optional pointer to a FLOAT to receive the calculated mean.\n * \\param Variance Optional pointer to a FLOAT to receive the calculated variance.\n * \\return TRUE if the calculation was successful, FALSE otherwise.\n */\nBOOLEAN PhCalculateEntropy(\n    _In_ PBYTE Buffer,\n    _In_ ULONG64 BufferLength,\n    _Out_opt_ PFLOAT Entropy,\n    _Out_opt_ PFLOAT Mean,\n    _Out_opt_ PFLOAT Variance\n    )\n{\n    FLOAT bufferEntropy = 0.f;\n    FLOAT bufferMeanValue = 0.f;\n    FLOAT bufferVarianceValue = 0.f;\n    ULONG64 bufferOffset = 0;\n    ULONG64 bufferSumValue = 0;\n    ULONG64 counts[UCHAR_MAX + 1];\n\n    memset(counts, 0, sizeof(counts));\n\n    while (bufferOffset < BufferLength)\n    {\n        BYTE value = *(PBYTE)PTR_ADD_OFFSET(Buffer, bufferOffset++);\n\n        bufferSumValue += value;\n        counts[value]++;\n    }\n\n    // Calculate entropy\n    for (ULONG i = 0; i < RTL_NUMBER_OF(counts); i++)\n    {\n        FLOAT value = (FLOAT)counts[i] / (FLOAT)BufferLength;\n\n        if (value > 0.f)\n            bufferEntropy -= value * log2f(value);\n    }\n\n    bufferMeanValue = (FLOAT)bufferSumValue / (FLOAT)BufferLength;\n\n    // Calculate variance\n    if (BufferLength > 0)\n    {\n        for (ULONG i = 0; i < RTL_NUMBER_OF(counts); i++)\n        {\n            FLOAT diff = (FLOAT)i - bufferMeanValue;\n            bufferVarianceValue += counts[i] * diff * diff;\n        }\n        bufferVarianceValue /= (FLOAT)BufferLength;\n    }\n\n    if (Entropy)\n        *Entropy = bufferEntropy;\n    if (Mean)\n        *Mean = bufferMeanValue;\n    if (Variance)\n        *Variance = bufferVarianceValue;\n\n    return TRUE;\n}\n\n/**\n * Formats entropy, mean, and variance values into a string representation with specified precision.\n *\n * \\param Entropy The entropy value to format.\n * \\param EntropyPrecision The number of decimal places for the entropy value.\n * \\param Mean (Optional) The mean value to format.\n * \\param MeanPrecision (Optional) The number of decimal places for the mean value.\n * \\param Variance (Optional) The variance value to format.\n * \\param VariancePrecision (Optional) The number of decimal places for the variance value.\n * \\return A pointer to a PPH_STRING containing the formatted string.\n */\nPPH_STRING PhFormatEntropy(\n    _In_ FLOAT Entropy,\n    _In_ USHORT EntropyPrecision,\n    _In_opt_ FLOAT Mean,\n    _In_opt_ USHORT MeanPrecision,\n    _In_opt_ FLOAT Variance,\n    _In_opt_ USHORT VariancePrecision\n    )\n{\n    if (Mean && Variance)\n    {\n        PH_FORMAT format[6];\n\n        // %s S (%s X)\n        format[0].Type = SingleFormatType | FormatUsePrecision | FormatCropZeros;\n        format[0].u.Single = Entropy;\n        format[0].Precision = EntropyPrecision;\n        PhInitFormatS(&format[1], L\" S (\");\n        format[2].Type = SingleFormatType | FormatUsePrecision | FormatCropZeros;\n        format[2].u.Single = Mean;\n        format[2].Precision = MeanPrecision;\n        PhInitFormatS(&format[3], L\" M) (\");\n        format[4].Type = SingleFormatType | FormatUsePrecision | FormatCropZeros;\n        format[4].u.Single = Variance;\n        format[4].Precision = VariancePrecision;\n        PhInitFormatS(&format[5], L\" X)\");\n\n        return PhFormat(format, ARRAYSIZE(format), 0);\n    }\n    else if (Variance)\n    {\n        PH_FORMAT format[4];\n\n        // %s S (%s X)\n        format[0].Type = SingleFormatType | FormatUsePrecision | FormatCropZeros;\n        format[0].u.Single = Entropy;\n        format[0].Precision = EntropyPrecision;\n        PhInitFormatS(&format[1], L\" S (\");\n        format[2].Type = SingleFormatType | FormatUsePrecision | FormatCropZeros;\n        format[2].u.Single = Variance;\n        format[2].Precision = VariancePrecision;\n        PhInitFormatS(&format[3], L\" X)\");\n\n        return PhFormat(format, ARRAYSIZE(format), 0);\n    }\n    else\n    {\n        PH_FORMAT format;\n\n        format.Type = SingleFormatType | FormatUsePrecision | FormatCropZeros;\n        format.u.Single = Entropy;\n        format.Precision = EntropyPrecision;\n\n        return PhFormat(&format, 1, 0);\n    }\n}\n\n/**\n * Fills a memory block with a ULONG pattern.\n *\n * \\param Memory The memory block. The block must be 4 byte aligned.\n * \\param Value The ULONG pattern.\n * \\param Count The number of elements.\n */\nVOID PhFillMemoryUlongOriginal(\n    _Inout_updates_(Count) PULONG Memory,\n    _In_ ULONG Value,\n    _In_ SIZE_T Count\n    )\n{\n    PH_INT128 pattern;\n    SIZE_T count;\n\n    if (!PhHasIntrinsics)\n    {\n        if (Count != 0)\n        {\n            do\n            {\n                *Memory++ = Value;\n            } while (--Count != 0);\n        }\n\n        return;\n    }\n\n    if ((ULONG_PTR)Memory & 0xf)\n    {\n        switch ((ULONG_PTR)Memory & 0xf)\n        {\n        case 0x4:\n            if (Count >= 1)\n            {\n                *Memory++ = Value;\n                Count--;\n            }\n            __fallthrough;\n        case 0x8:\n            if (Count >= 1)\n            {\n                *Memory++ = Value;\n                Count--;\n            }\n            __fallthrough;\n        case 0xc:\n            if (Count >= 1)\n            {\n                *Memory++ = Value;\n                Count--;\n            }\n            break;\n        }\n    }\n\n    pattern = PhSetINT128by32(Value);\n    count = Count / 4;\n\n    if (count != 0)\n    {\n        do\n        {\n            PhStoreINT128((PLONG)Memory, pattern);\n            Memory += 4;\n        } while (--count != 0);\n    }\n\n    switch (Count & 0x3)\n    {\n    case 0x3:\n        *Memory++ = Value;\n        __fallthrough;\n    case 0x2:\n        *Memory++ = Value;\n        __fallthrough;\n    case 0x1:\n        *Memory++ = Value;\n        break;\n    }\n}\n\n/**\n * Fills a memory block with a ULONG pattern.\n *\n * \\param Memory The memory block. The block must be 4 byte aligned.\n * \\param Value The ULONG pattern.\n * \\param Count The number of elements.\n */\nVOID PhFillMemoryUlong(\n    _Inout_updates_(Count) PULONG Memory,\n    _In_ ULONG Value,\n    _In_ SIZE_T Count\n    )\n{\n    if (Count == 0)\n        return;\n\n#ifndef _ARM64_\n    if (PhHasAVX && IS_ALIGNED(Memory, 32))\n    {\n        SIZE_T count = Count & ~0x7;\n\n        if (count != 0)\n        {\n            PULONG end;\n            __m256i pattern;\n\n            end = (PULONG)(ULONG_PTR)(Memory + count);\n            pattern = _mm256_set1_epi32(Value);\n\n            while (Memory != end)\n            {\n                _mm256_store_si256((__m256i*)Memory, pattern);\n                Memory += 8;\n            }\n\n            _mm256_zeroupper();\n\n            Count &= 0x7;\n        }\n    }\n#endif\n\n    if (PhHasIntrinsics && IS_ALIGNED(Memory, 16))\n    {\n        SIZE_T count = Count & ~0x3;\n\n        if (count != 0)\n        {\n            PULONG end;\n            PH_INT128 pattern;\n\n            end = (PULONG)(ULONG_PTR)(Memory + count);\n            pattern = PhSetINT128by32(Value);\n\n            while (Memory != end)\n            {\n                PhStoreINT128((PLONG)Memory, pattern);\n                Memory += 4;\n            }\n\n            Count &= 0x3;\n        }\n    }\n\n    while (Count-- != 0)\n    {\n        *Memory++ = Value;\n    }\n}\n\n/**\n * Divides an array of numbers by a number.\n *\n * \\param A The destination array, divided by \\a B.\n * \\param B The number.\n * \\param Count The number of elements.\n */\nVOID PhDivideSinglesBySingleOriginal(\n    _Inout_updates_(Count) PFLOAT A,\n    _In_ FLOAT B,\n    _In_ SIZE_T Count\n    )\n{\n    PFLOAT endA;\n    PH_FLOAT128 b;\n\n    if (!PhHasIntrinsics)\n    {\n        while (Count--)\n            *A++ /= B;\n\n        return;\n    }\n\n    if ((ULONG_PTR)A & 0xf)\n    {\n        switch ((ULONG_PTR)A & 0xf)\n        {\n        case 0x4:\n            if (Count >= 1)\n            {\n                *A++ /= B;\n                Count--;\n            }\n            __fallthrough;\n        case 0x8:\n            if (Count >= 1)\n            {\n                *A++ /= B;\n                Count--;\n            }\n            __fallthrough;\n        case 0xc:\n            if (Count >= 1)\n            {\n                *A++ /= B;\n                Count--;\n            }\n            else\n            {\n                return; // essential; A may not be aligned properly\n            }\n            break;\n        }\n    }\n\n    endA = (PFLOAT)((ULONG_PTR)(A + Count) & ~0xf);\n    b = PhSetFLOAT128by32(B);\n\n    while (A != endA)\n    {\n        PH_FLOAT128 a;\n\n        a = PhLoadFLOAT128(A);\n        a = PhDivideFLOAT128(a, b);\n        PhStoreFLOAT128(A, a);\n\n        A += 4;\n    }\n\n    switch (Count & 0x3)\n    {\n    case 0x3:\n        *A++ /= B;\n        __fallthrough;\n    case 0x2:\n        *A++ /= B;\n        __fallthrough;\n    case 0x1:\n        *A++ /= B;\n        break;\n    }\n}\n\n/**\n * Divides an array of numbers by a number.\n *\n * \\param A The destination array, divided by \\a B.\n * \\param B The number.\n * \\param Count The number of elements.\n */\nVOID PhDivideSinglesBySingle(\n    _Inout_updates_(Count) PFLOAT A,\n    _In_ FLOAT B,\n    _In_ SIZE_T Count\n    )\n{\n    if (Count == 0)\n        return;\n    if (B == 1.0f || B == 0.0f)\n        return;\n\n    // Note: This uses reciprocal multiply since it's faster than per-element divides\n    // and preserves IEEE-754 behavior for +/-0, +/-INF, and NaN (0/0 -> NaN, x/0 -> +/-INF). (dmex)\n    const FLOAT invB = 1.0f / B;\n\n#ifndef _ARM64_\n    if (PhHasAVX && IS_ALIGNED(A, 32))\n    {\n        SIZE_T count = Count & ~0x7;\n\n        if (count != 0)\n        {\n            PFLOAT end;\n            __m256 a;\n            __m256 b;\n\n            end = (PFLOAT)(ULONG_PTR)(A + count);\n            b = _mm256_set1_ps(invB); // _mm256_broadcast_ss(&B);\n\n            while (A != end)\n            {\n                a = _mm256_load_ps(A);\n                a = _mm256_mul_ps(a, b); // _mm256_div_ps(a, b);\n                _mm256_store_ps(A, a);\n\n                A += 8;\n            }\n\n            Count &= 0x7;\n        }\n    }\n#endif\n\n    if (PhHasIntrinsics && IS_ALIGNED(A, 16))\n    {\n        SIZE_T count = Count & ~0x3;\n\n        if (count != 0)\n        {\n            PFLOAT end;\n            PH_FLOAT128 a;\n            PH_FLOAT128 b;\n\n            end = A + count;\n            b = PhSetFLOAT128by32(invB); // PhSetFLOAT128by32(B);\n\n            while (A != end)\n            {\n                a = PhLoadFLOAT128(A);\n                a = PhMultiplyFLOAT128(a, b); // PhDivideFLOAT128(a, b);\n                PhStoreFLOAT128(A, a);\n\n                A += 4;\n            }\n\n            Count &= 0x3;\n        }\n    }\n\n    while (Count--)\n    {\n        *A++ *= invB;\n    }\n}\n\n/**\n * Adds one array of integers to another.\n *\n * \\param A The destination array to which the source\n * array is added. The array must be 16 byte aligned.\n * \\param B The source array. The array must be 16\n * byte aligned.\n * \\param Count The number of elements.\n */\nVOID PhAddMemoryUlongOriginal(\n    _Inout_ PULONG A,\n    _In_ PULONG B,\n    _In_ ULONG Count\n    )\n{\n#ifndef _ARM64_\n    if (PhHasIntrinsics)\n    {\n        while (Count >= 4)\n        {\n            __m128i a;\n            __m128i b;\n\n            a = _mm_load_si128((__m128i*)A);\n            b = _mm_load_si128((__m128i*)B);\n            a = _mm_add_epi32(a, b);\n            _mm_store_si128((__m128i*)A, a);\n\n            A += 4;\n            B += 4;\n            Count -= 4;\n        }\n\n        switch (Count & 0x3)\n        {\n        case 0x3:\n            *A++ += *B++;\n            __fallthrough;\n        case 0x2:\n            *A++ += *B++;\n            __fallthrough;\n        case 0x1:\n            *A++ += *B++;\n            break;\n        }\n    }\n    else\n#endif\n    {\n        while (Count--)\n            *A++ += *B++;\n    }\n}\n\n/**\n * Returns the maximum value of an array of floats.\n *\n * \\param A The array.\n * \\param Count The total number of array elements.\n * \\return The maximum of any single element.\n */\nFLOAT PhMaxMemorySingles(\n    _In_ PFLOAT A,\n    _In_ SIZE_T Count\n    )\n{\n    FLOAT maximum = 0.0f;\n\n    if (Count == 0)\n        return maximum;\n\n#ifndef _ARM64_\n    if (PhHasAVX && IS_ALIGNED(A, 32))\n    {\n        SIZE_T count = Count & ~0x7;\n\n        if (count != 0)\n        {\n            PFLOAT end;\n            __m256 a;\n            __m256 c;\n            __m128 hi;\n            __m128 lo;\n            __m128 d;\n\n            end = (PFLOAT)(ULONG_PTR)(A + count);\n            c = _mm256_setzero_ps();\n\n            while (A != end)\n            {\n                a = _mm256_load_ps(A);\n                c = _mm256_max_ps(c, a);\n\n                A += 8;\n            }\n\n            c = _mm256_max_ps(c, _mm256_permute_ps(c, _MM_SHUFFLE(2, 3, 0, 1)));  // swap neighbors\n            c = _mm256_max_ps(c, _mm256_permute_ps(c, _MM_SHUFFLE(1, 0, 3, 2)));  // swap pairs\n\n            lo = _mm256_castps256_ps128(c);\n            hi = _mm256_extractf128_ps(c, 1);\n            d = _mm_max_ps(lo, hi);\n\n            d = _mm_max_ps(d, _mm_shuffle_ps(d, d, _MM_SHUFFLE(2, 3, 0, 1)));\n            d = _mm_max_ps(d, _mm_shuffle_ps(d, d, _MM_SHUFFLE(1, 0, 3, 2)));\n            maximum = _mm_cvtss_f32(d);\n\n            _mm256_zeroupper();\n\n            Count &= 0x7;\n        }\n    }\n#endif\n\n    if (PhHasIntrinsics && IS_ALIGNED(A, 16))\n    {\n        SIZE_T count = Count & ~0x3;\n\n        if (count != 0)\n        {\n            FLOAT value;\n            PFLOAT end;\n            PH_FLOAT128 a;\n            PH_FLOAT128 c;\n\n            end = (PFLOAT)(ULONG_PTR)(A + count);\n            c = PhZeroFLOAT128();\n\n            while (A != end)\n            {\n                a = PhLoadFLOAT128(A);\n                c = PhMaxFLOAT128(c, a);\n\n                A += 4;\n            }\n\n            // Compare adjacent pairs (swap elements within pairs)\n            c = PhMaxFLOAT128(c, PhShuffleFLOAT128_2301(c, c));\n            // Compare results (swap pairs themselves)\n            c = PhMaxFLOAT128(c, PhShuffleFLOAT128_1032(c, c));\n            PhStoreFLOAT128LowSingle(&value, c);\n\n            if (maximum < value)\n                maximum = value;\n\n            Count &= 0x3;\n        }\n    }\n\n    while (Count--)\n    {\n        FLOAT value = *A++;\n\n        if (maximum < value)\n            maximum = value;\n    }\n\n    return maximum;\n}\n\n/**\n * Adds one array of floats to another and returns the maximum.\n *\n * \\param A The first array.\n * \\param B The second array.\n * \\param Count The total number of array elements.\n * \\return The maximum of any single element.\n */\nFLOAT PhAddPlusMaxMemorySingles(\n    _Inout_updates_(Count) PFLOAT A,\n    _Inout_updates_(Count) PFLOAT B,\n    _In_ SIZE_T Count\n    )\n{\n    FLOAT maximum = 0.0f;\n\n    if (Count == 0)\n        return maximum;\n\n#ifndef _ARM64_\n    if (PhHasAVX && (IS_ALIGNED(A, 32) && IS_ALIGNED(B, 32)))\n    {\n        SIZE_T count = Count & ~0x7;\n\n        if (count != 0)\n        {\n            PFLOAT end;\n            __m256 a;\n            __m256 b;\n            __m256 c;\n            __m128 lo;\n            __m128 hi;\n            __m128 d;\n\n            end = (PFLOAT)(ULONG_PTR)(A + count);\n            c = _mm256_setzero_ps();\n\n            while (A != end)\n            {\n                a = _mm256_load_ps(A);\n                b = _mm256_load_ps(B);\n                a = _mm256_add_ps(b, a);\n                c = _mm256_max_ps(c, a);\n\n                A += 8;\n                B += 8;\n            }\n\n            c = _mm256_max_ps(c, _mm256_permute_ps(c, _MM_SHUFFLE(2, 3, 0, 1)));\n            c = _mm256_max_ps(c, _mm256_permute_ps(c, _MM_SHUFFLE(1, 0, 3, 2)));\n\n            lo = _mm256_castps256_ps128(c);\n            hi = _mm256_extractf128_ps(c, 1);\n            d = _mm_max_ps(lo, hi);\n\n            d = _mm_max_ps(d, _mm_shuffle_ps(d, d, _MM_SHUFFLE(2, 3, 0, 1)));\n            d = _mm_max_ps(d, _mm_shuffle_ps(d, d, _MM_SHUFFLE(1, 0, 3, 2)));\n            maximum = _mm_cvtss_f32(d);\n\n            _mm256_zeroupper();\n\n            Count &= 0x7;\n        }\n    }\n#endif\n\n    if (PhHasIntrinsics && (IS_ALIGNED(A, 16) && IS_ALIGNED(B, 16)))\n    {\n        SIZE_T count = Count & ~0x3;\n\n        if (count != 0)\n        {\n            FLOAT value;\n            PFLOAT end;\n            PH_FLOAT128 a;\n            PH_FLOAT128 b;\n            PH_FLOAT128 c;\n\n            end = (PFLOAT)(ULONG_PTR)(A + count);\n            c = PhZeroFLOAT128();\n\n            while (A != end)\n            {\n                a = PhLoadFLOAT128(A);\n                b = PhLoadFLOAT128(B);\n                a = PhAddFLOAT128(b, a);\n                c = PhMaxFLOAT128(c, a);\n\n                A += 4;\n                B += 4;\n            }\n\n            c = PhMaxFLOAT128(c, PhShuffleFLOAT128_2301(c, c));  // swap neighbors\n            c = PhMaxFLOAT128(c, PhShuffleFLOAT128_1032(c, c));  // swap pairs\n            PhStoreFLOAT128LowSingle(&value, c);\n\n            if (maximum < value)\n                maximum = value;\n\n            Count &= 0x3;\n        }\n    }\n\n    while (Count--)\n    {\n        FLOAT value = *A++ + *B++;\n\n        if (maximum < value)\n            maximum = value;\n    }\n\n    return maximum;\n}\n\n/**\n * Converts an array of integers to floats.\n *\n * \\param From The source integers.\n * \\param To The destination floats.\n * \\param Count The number of elements.\n */\nVOID PhConvertCopyMemoryUlong(\n    _Inout_updates_(Count) PULONG From,\n    _Inout_updates_(Count) PFLOAT To,\n    _In_ SIZE_T Count\n    )\n{\n    if (Count == 0)\n        return;\n\n#ifndef _ARM64_\n    if (PhHasAVX && IS_ALIGNED(From, 32) && IS_ALIGNED(To, 32))\n    {\n        SIZE_T count = Count & ~0x7;\n\n        if (count != 0)\n        {\n            PULONG end;\n            __m256i a;\n            __m256 b;\n\n            end = (PULONG)(ULONG_PTR)(From + count);\n\n            while (From != end)\n            {\n                a = _mm256_load_si256((__m256i const*)From);\n                b = _mm256_cvtf_epu32(a); // _mm256_cvtepi32_ps\n                _mm256_store_ps(To, b);\n\n                From += 8;\n                To += 8;\n            }\n\n            _mm256_zeroupper();\n\n            Count &= 0x7;\n        }\n    }\n#endif\n\n    if (PhHasIntrinsics && IS_ALIGNED(From, 16) && IS_ALIGNED(To, 16))\n    {\n        SIZE_T count = Count & ~0x3;\n\n        if (count != 0)\n        {\n            PULONG end;\n            PH_INT128 a;\n            PH_FLOAT128 b;\n\n            end = (PULONG)(ULONG_PTR)(From + count);\n\n            while (From != end)\n            {\n                a = PhLoadINT128(From); // _mm_loadl_epi64\n                b = PhConvertUINT128ToFLOAT128(a); // _mm_cvtepi32_ps // _mm_cvtepu32_ps\n                PhStoreFLOAT128(To, b);\n\n                From += 4;\n                To += 4;\n            }\n\n            Count &= 0x3;\n        }\n    }\n\n    while (Count--)\n    {\n        *To++ = (FLOAT)*From++;\n    }\n}\n\n/**\n * Converts an array of 64-bit unsigned integers to floats.\n *\n * \\param From The source 64-bit integers.\n * \\param To The destination floats.\n * \\param Count The number of elements.\n */\nVOID PhConvertCopyMemoryUlong64(\n    _Inout_updates_(Count) PULONG64 From,\n    _Inout_updates_(Count) PFLOAT To,\n    _In_ SIZE_T Count\n    )\n{\n    if (Count == 0)\n        return;\n\n#ifndef _ARM64_\n#if defined(PH_NATIVE_AVX512)\n    if (PhHasAVX512)\n    {\n        SIZE_T count = Count & ~0xF;\n    \n        if (count)\n        {\n            PULONG64 end = From + count;\n    \n            // Convert 16 × uint64 → 16 × float in single iteration\n            while (From != end)\n            {\n                // Load 16 × uint64 (2 × 512-bit loads = 128 bytes)\n                __m512i v0 = _mm512_load_si512((__m512i const*)From);       // 8 × uint64\n                __m512i v1 = _mm512_load_si512((__m512i const*)(From + 8)); // 8 × uint64\n    \n                // Direct uint64 → double conversion (AVX-512 DQ)\n                __m512d d0 = _mm512_cvtepu64_pd(v0);  // 8 × double\n                __m512d d1 = _mm512_cvtepu64_pd(v1);  // 8 × double\n    \n                // Double → float conversion with rounding\n                __m256 f0 = _mm512_cvtpd_ps(d0);  // 8 × float\n                __m256 f1 = _mm512_cvtpd_ps(d1);  // 8 × float\n    \n                // Combine into single 512-bit register\n                __m512 result = _mm512_insertf32x8(_mm512_castps256_ps512(f0), f1, 1);\n    \n                // Store 16 floats\n                _mm512_storeu_ps(To, result);\n    \n                From += 16;\n                To += 16;\n            }\n    \n            Count &= 0xF;\n        }\n    }\n#endif\n\n    if (PhHasAVX && IS_ALIGNED(From, 32) && IS_ALIGNED(To, 32))\n    {\n        SIZE_T count = Count & ~0x7;\n\n        if (count)\n        {\n            PULONG64 end = From + count;\n            // Constant for reconstructing float from high/low 32-bit parts.\n            const __m256 ps2p32 = _mm256_set1_ps(4294967296.0f); // 2^32\n            // Mask to de-interleave low and high 32-bit words from 64-bit lanes.\n            const __m256i deinterleave_mask = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7);\n\n            while (From != end)\n            {\n                // Load 8 uint64_t values into two 256-bit registers.\n                __m256i v0 = _mm256_load_si256((__m256i const*)From);       // u0, u1, u2, u3\n                __m256i v1 = _mm256_load_si256((__m256i const*)(From + 4)); // u4, u5, u6, u7\n\n                // Within each register, shuffle to group low 32-bit parts and high 32-bit parts.\n                // shuf0 becomes [u0_lo, u1_lo, u2_lo, u3_lo, u0_hi, u1_hi, u2_hi, u3_hi]\n                __m256i shuf0 = _mm256_permutevar8x32_epi32(v0, deinterleave_mask);\n                // shuf1 becomes [u4_lo, u5_lo, u6_lo, u7_lo, u4_hi, u5_hi, u6_hi, u7_hi]\n                __m256i shuf1 = _mm256_permutevar8x32_epi32(v1, deinterleave_mask);\n\n                // Combine the parts from both registers to get two vectors:\n                // one with all 8 low parts, and one with all 8 high parts.\n                __m256i all_los = _mm256_permute2x128_si256(shuf0, shuf1, 0x20); // combines low(shuf0), low(shuf1)\n                __m256i all_his = _mm256_permute2x128_si256(shuf0, shuf1, 0x31); // combines high(shuf0), high(shuf1)\n\n                // Convert the two vectors of 8 unsigned 32-bit integers to floats\n                // using the helper from phintrin.h.\n                __m256 los_ps = _mm256_cvtf_epu32(all_los);\n                __m256 his_ps = _mm256_cvtf_epu32(all_his);\n\n                // Reconstruct the float representation of the original uint64_t values.\n                // float(u64) approx= float(low32) + float(high32) * 2^32\n                // FMA (fused multiply-add) is used for better performance.\n                __m256 val = _mm256_fmadd_ps(his_ps, ps2p32, los_ps);\n\n                // Store the 8 resulting floats.\n                _mm256_storeu_ps(To, val);\n\n                From += 8;\n                To += 8;\n            }\n\n            _mm256_zeroupper();\n\n            Count &= 0x7;\n        }\n    }\n\n//#ifndef _ARM64_\n//    if(PhHasAVX)\n//    {\n//        SIZE_T count = Count & ~0x3;\n//\n//        if (count)\n//        {\n//            PULONG64 end = From + count;\n//            const __m256i MaskLo32_64 = _mm256_set1_epi64x(0xFFFFFFFFULL); // for AND on 64-bit lanes\n//            const __m256i PackIdx = _mm256_setr_epi32(0, 2, 4, 6, 0, 0, 0, 0);  // take elements 0,2,4,6 into lower 128\n//            const __m128  Ps2p31 = _mm_set1_ps(2147483648.0f); // 2^31\n//            const __m128  Ps2p32 = _mm_set1_ps(4294967296.0f); // 2^32 (exact power of two)\n//            const __m128i Mask7fffffff = _mm_set1_epi32(0x7FFFFFFF);\n//\n//            while (From != end)\n//            {\n//                // Load 4x uint64_t (256 bits)\n//                __m256i v = _mm256_loadu_si256((__m256i const*)From);\n//\n//                // Split each 64-bit lane into its low/high 32-bit halves (still in 64-bit lanes)\n//                __m256i lo32_64 = _mm256_and_si256(v, MaskLo32_64);   // [u0_lo,0, u1_lo,0, u2_lo,0, u3_lo,0]\n//                __m256i hi32_64 = _mm256_srli_epi64(v, 32);           // [u0_hi,0, u1_hi,0, u2_hi,0, u3_hi,0]\n//\n//                // Pack 32-bit elements (indices 0,2,4,6) into lower 128 as contiguous 4x int32\n//                __m256i loPacked = _mm256_permutevar8x32_epi32(lo32_64, PackIdx);\n//                __m256i hiPacked = _mm256_permutevar8x32_epi32(hi32_64, PackIdx);\n//\n//                __m128i lo128 = _mm256_castsi256_si128(loPacked); // [u0_lo, u1_lo, u2_lo, u3_lo]\n//                __m128i hi128 = _mm256_castsi256_si128(hiPacked); // [u0_hi, u1_hi, u2_hi, u3_hi]\n//\n//                // Convert unsigned 32 -> float:\n//                //   f = float(x & 0x7fffffff) + float(x >> 31) * 2^31\n//                __m128i loCarryI = _mm_srli_epi32(lo128, 31);\n//                __m128  loPs = _mm_cvtepi32_ps(_mm_and_si128(lo128, Mask7fffffff));\n//                loPs = _mm_add_ps(loPs, _mm_mul_ps(_mm_cvtepi32_ps(loCarryI), Ps2p31));\n//\n//                __m128i hiCarryI = _mm_srli_epi32(hi128, 31);\n//                __m128  hiPs = _mm_cvtepi32_ps(_mm_and_si128(hi128, Mask7fffffff));\n//                hiPs = _mm_add_ps(hiPs, _mm_mul_ps(_mm_cvtepi32_ps(hiCarryI), Ps2p31));\n//\n//                // Reconstruct: float(u64) = float(low32) + float(high32) * 2^32\n//                // (Use FMA if you dispatch it)\n//                __m128 val = _mm_add_ps(loPs, _mm_mul_ps(hiPs, Ps2p32));\n//\n//                _mm_storeu_ps(To, val); // store exactly 4 floats\n//\n//                From += 4;\n//                To   += 4;\n//            }\n//\n//            Count &= 0x3;\n//        }\n//    }\n//#endif\n\n    if (PhHasIntrinsics && IS_ALIGNED(From, 16) && IS_ALIGNED(To, 16))\n    {\n        SIZE_T count = Count & ~0x3;  // Process 4 at a time\n\n        if (count)\n        {\n            PULONG64 end = From + count;\n            const __m128d scale = _mm_set1_pd(4294967296.0);\n\n            while (From != end)\n            {\n                // Load 4 × uint64 as 2 × __m128i\n                __m128i v0 = _mm_load_si128((__m128i const*)From);       // 2 × uint64\n                __m128i v1 = _mm_load_si128((__m128i const*)(From + 2)); // 2 × uint64\n\n                // Split low/high 32-bit\n                __m128i mask = _mm_set1_epi64x(0xFFFFFFFFULL);\n                __m128i v0_lo = _mm_and_si128(v0, mask);\n                __m128i v0_hi = _mm_srli_epi64(v0, 32);\n                __m128i v1_lo = _mm_and_si128(v1, mask);\n                __m128i v1_hi = _mm_srli_epi64(v1, 32);\n\n                // Convert uint32 → double (exact)\n                __m128d d0_lo = _mm_cvtepi32_pd(_mm_shuffle_epi32(v0_lo, 0x08));\n                __m128d d0_hi = _mm_cvtepi32_pd(_mm_shuffle_epi32(v0_hi, 0x08));\n                __m128d d1_lo = _mm_cvtepi32_pd(_mm_shuffle_epi32(v1_lo, 0x08));\n                __m128d d1_hi = _mm_cvtepi32_pd(_mm_shuffle_epi32(v1_hi, 0x08));\n\n                // Reconstruct\n                __m128d d0 = _mm_add_pd(d0_lo, _mm_mul_pd(d0_hi, scale));\n                __m128d d1 = _mm_add_pd(d1_lo, _mm_mul_pd(d1_hi, scale));\n\n                // Double → float\n                __m128 f0 = _mm_cvtpd_ps(d0);  // 2 floats in low 64 bits\n                __m128 f1 = _mm_cvtpd_ps(d1);  // 2 floats in low 64 bits\n\n                // Combine into 4 floats\n                __m128 result = _mm_movelh_ps(f0, f1);\n\n                // Store 4 floats\n                _mm_storeu_ps(To, result);\n\n                From += 4;\n                To += 4;\n            }\n\n            Count &= 0x3;\n        }\n    }\n#endif\n\n    while (Count--)\n    {\n        *To++ = (FLOAT)*From++;\n    }\n}\n\n/**\n * Converts an array of floats to integers.\n *\n * \\param From The source floats.\n * \\param To The destination integers.\n * \\param Count The number of elements.\n */\nVOID PhConvertCopyMemorySingles(\n    _Inout_updates_(Count) PFLOAT From,\n    _Inout_updates_(Count) PULONG To,\n    _In_ SIZE_T Count\n    )\n{\n    if (Count == 0)\n        return;\n\n#ifndef _ARM64_\n    if (PhHasAVX && IS_ALIGNED(From, 32) && IS_ALIGNED(To, 32))\n    {\n        SIZE_T count = Count & ~0x7;\n\n        if (count != 0)\n        {\n            PFLOAT end = From + count;\n\n            __m256 a;\n            __m256i b;\n\n            while (From != end)\n            {\n                a = _mm256_load_ps(From);\n                // Truncate toward zero to match scalar (C cast) semantics.\n                b = _mm256_cvttps_epi32(a); // _mm256_cvtps_epi32 // _mm256_cvtps_epu32\n                _mm256_store_si256((__m256i*)To, b);\n\n                From += 8;\n                To += 8;\n            }\n\n            _mm256_zeroupper();\n\n            Count &= 0x7;\n        }\n    }\n#endif\n\n    if (PhHasIntrinsics && IS_ALIGNED(From, 16) && IS_ALIGNED(To, 16))\n    {\n        SIZE_T count = Count & ~0x3;\n\n        if (count != 0)\n        {\n            PFLOAT end;\n            PH_FLOAT128 a;\n            PH_INT128 b;\n\n            end = (PFLOAT)(ULONG_PTR)(From + count);\n\n            while (From != end)\n            {\n                a = PhLoadFLOAT128(From);\n                b = PhConvertFLOAT128ToUINT128(a);\n                PhStoreINT128(To, b);\n\n                From += 4;\n                To += 4;\n            }\n\n            Count &= 0x3;\n        }\n    }\n\n    while (Count--)\n    {\n        *To++ = (ULONG)*From++;\n    }\n}\n\n// based on PhCopyCircularBuffer (FLOAT) (\\phlib\\circbuf_i.h) (dmex)\nVOID PhCopyConvertCircularBufferULONG(\n    _Inout_ PPH_CIRCULAR_BUFFER_ULONG Buffer,\n    _Out_writes_(Count) FLOAT* Destination,\n    _In_ ULONG Count\n    )\n{\n    ULONG tailSize;\n    ULONG headSize;\n\n    tailSize = (ULONG)(Buffer->Size - Buffer->Index);\n    headSize = Buffer->Count - tailSize;\n\n    if (Count > Buffer->Count)\n        Count = Buffer->Count;\n\n    if (tailSize >= Count)\n    {\n        // Convert and copy only a part of the tail.\n        PhConvertCopyMemoryUlong(&Buffer->Data[Buffer->Index], Destination, Count);\n    }\n    else\n    {\n        // Convert and copy the tail, then only part of the head.\n        PhConvertCopyMemoryUlong(&Buffer->Data[Buffer->Index], Destination, tailSize);\n        PhConvertCopyMemoryUlong(Buffer->Data, &Destination[tailSize], (Count - tailSize));\n    }\n}\n\nVOID PhCopyConvertCircularBufferULONG64(\n    _Inout_ PPH_CIRCULAR_BUFFER_ULONG64 Buffer,\n    _Out_writes_(Count) FLOAT* Destination,\n    _In_ ULONG Count\n    )\n{\n    ULONG tailSize;\n    ULONG headSize;\n\n    tailSize = (ULONG)(Buffer->Size - Buffer->Index);\n    headSize = Buffer->Count - tailSize;\n\n    if (Count > Buffer->Count)\n        Count = Buffer->Count;\n\n    if (tailSize >= Count)\n    {\n        // Convert and copy only a part of the tail.\n        PhConvertCopyMemoryUlong64(&Buffer->Data[Buffer->Index], Destination, Count);\n    }\n    else\n    {\n        // Convert and copy the tail, then only part of the head.\n        PhConvertCopyMemoryUlong64(&Buffer->Data[Buffer->Index], Destination, tailSize);\n        PhConvertCopyMemoryUlong64(Buffer->Data, &Destination[tailSize], (Count - tailSize));\n    }\n}\n\n/**\n * Counts the number of set bits (1s) in the given 32-bit unsigned integer value.\n *\n * \\param Value The 32-bit unsigned integer whose bits are to be counted.\n * \\return The number of bits set to 1 in the input value.\n */\nULONG PhCountBits(\n    _In_ ULONG Value\n    )\n{\n    if (PhHasPopulationCount)\n    {\n        return PhPopulationCount32(Value);\n    }\n    else\n    {\n        #undef T\n        #define T ULONG\n        ULONG count;\n\n        // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel\n        Value = Value - ((Value >> 1) & (T)~(T)0 / 3);\n        Value = (Value & (T)~(T)0 / 15 * 3) + ((Value >> 2) & (T)~(T)0 / 15 * 3);\n        Value = (Value + (Value >> 4)) & (T)~(T)0 / 255 * 15;\n        count = (T)(Value * ((T)~(T)0 / 255)) >> (sizeof(T) - 1) * CHAR_BIT;\n\n        return count;\n\n        //ULONG count = 0;\n        //\n        //while (Value)\n        //{\n        //    count++;\n        //    Value &= Value - 1;\n        //}\n        //\n        //return count;\n    }\n}\n\n/**\n * Counts the number of set bits (1s) in the specified ULONG_PTR value.\n *\n * \\param Value The ULONG_PTR value whose bits are to be counted.\n * \\return The number of bits set to 1 in the input value.\n */\nULONG PhCountBitsUlongPtr(\n    _In_ ULONG_PTR Value\n    )\n{\n#if defined(PH_NATIVE_COUNTBITS)\n    return RtlNumberOfSetBitsUlongPtr(Value);\n#else\n#ifdef _WIN64\n    if (PhHasPopulationCount)\n    {\n        return (ULONG)PhPopulationCount64(Value);\n    }\n    else\n#endif\n    {\n        #undef T\n        #define T ULONG\n        ULONG count;\n\n        // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel\n        Value = Value - ((Value >> 1) & (T)~(T)0 / 3);\n        Value = (Value & (T)~(T)0 / 15 * 3) + ((Value >> 2) & (T)~(T)0 / 15 * 3);\n        Value = (Value + (Value >> 4)) & (T)~(T)0 / 255 * 15;\n        count = (T)(Value * ((T)~(T)0 / 255)) >> (sizeof(T) - 1) * CHAR_BIT;\n\n        return count;\n\n        //ULONG count = 0;\n        //\n        //while (Value)\n        //{\n        //    count++;\n        //    Value &= Value - 1;\n        //}\n        //\n        //return count;\n    }\n#endif\n}\n\n#pragma region Thread Local Storage (TLS)\n\n/**\n * Allocates a new TLS (Thread Local Storage) index.\n *\n * \\return Returns the allocated TLS index as an ULONG value.\n */\nULONG PhTlsAlloc(\n    VOID\n    )\n{\n    if (WindowsVersion < WINDOWS_NEW)\n    {\n        PTEB currentTeb;\n        PPEB currentPeb;\n        ULONG i;\n\n        currentTeb = NtCurrentTeb();\n        currentPeb = currentTeb->ProcessEnvironmentBlock;\n        RtlAcquirePebLock();\n\n        for (\n            i = RtlFindClearBitsAndSet(currentPeb->TlsBitmap, 1, 0);\n            ;\n            i = RtlFindClearBitsAndSet(currentPeb->TlsBitmap, 1, 0)\n            )\n        {\n            if (i != ULONG_MAX)\n            {\n                RtlReleasePebLock();\n                currentTeb->TlsSlots[i] = NULL;\n                return i;\n            }\n\n            if (currentTeb->TlsExpansionSlots)\n                break;\n\n            RtlReleasePebLock();\n            currentTeb->TlsExpansionSlots = (PVOID*)RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, TLS_EXPANSION_SLOTS * sizeof(PVOID));\n            if (!currentTeb->TlsExpansionSlots) goto CleanupExit;\n            RtlAcquirePebLock();\n        }\n\n        i = RtlFindClearBitsAndSet(currentPeb->TlsExpansionBitmap, 1, 0);\n        RtlReleasePebLock();\n\n        if (i != ULONG_MAX)\n        {\n            currentTeb->TlsExpansionSlots[i] = NULL;\n            return i + TLS_MINIMUM_AVAILABLE;\n        }\n    }\n\nCleanupExit:\n    //RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_NO_MEMORY);\n    //return ULONG_MAX;\n    return TlsAlloc();\n}\n\n/**\n * Frees a thread-local storage (TLS) slot previously allocated.\n *\n * \\param Index The index of the TLS slot to be freed.\n * \\return Returns an NTSTATUS code indicating success or failure of the operation.\n */\nNTSTATUS PhTlsFree(\n    _In_ ULONG Index\n    )\n{\n    NTSTATUS status;\n\n    if (WindowsVersion < WINDOWS_NEW)\n    {\n        PTEB currentTeb;\n        PPEB currentPeb;\n        PRTL_BITMAP bitmap;\n        ULONG i;\n\n        currentTeb = NtCurrentTeb();\n        currentPeb = currentTeb->ProcessEnvironmentBlock;\n\n        if (Index >= TLS_MINIMUM_AVAILABLE)\n        {\n            i = Index - TLS_MINIMUM_AVAILABLE;\n\n            if (i >= TLS_EXPANSION_SLOTS)\n            {\n                return STATUS_INVALID_PARAMETER;\n            }\n\n            bitmap = currentPeb->TlsExpansionBitmap;\n            Index = i;\n        }\n        else\n        {\n            bitmap = currentPeb->TlsBitmap;\n        }\n\n        RtlAcquirePebLock();\n\n        if (RtlAreBitsSet(bitmap, Index, 1))\n        {\n            status = NtSetInformationThread(\n                NtCurrentThread(),\n                ThreadZeroTlsCell,\n                &Index,\n                sizeof(ULONG)\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                RtlClearBits(bitmap, Index, 1);\n            }\n            else\n            {\n                status = STATUS_INVALID_PARAMETER;\n            }\n        }\n        else\n        {\n            status = STATUS_INVALID_PARAMETER;\n        }\n\n        RtlReleasePebLock();\n\n        return status;\n    }\n    else\n    {\n        if (TlsFree(Index))\n            status = STATUS_SUCCESS;\n        else\n            status = PhGetLastWin32ErrorAsNtStatus();\n\n        return status;\n    }\n}\n\n/**\n * Retrieves the value stored in the thread-local storage (TLS) slot specified by the given index.\n *\n * \\param Index The index of the TLS slot to retrieve the value from.\n * \\return A pointer to the value stored in the specified TLS slot, or NULL if no value is set.\n */\nPVOID PhTlsGetValue(\n    _In_ ULONG Index\n    )\n{\n    if (WindowsVersion < WINDOWS_NEW && Index < TLS_MINIMUM_AVAILABLE)\n    {\n        return NtCurrentTeb()->TlsSlots[Index];\n    }\n\n    return TlsGetValue(Index);\n}\n\n/**\n * Retrieves the value stored in the thread-local storage (TLS) slot specified by the given index.\n *\n * \\param Index The index of the TLS slot to retrieve the value from.\n * \\param Value A pointer to a variable that receives the value stored in the specified TLS slot.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhTlsGetValueEx(\n    _In_ ULONG Index,\n    _Out_ PVOID* Value\n    )\n{\n    if (WindowsVersion < WINDOWS_NEW && Index < TLS_MINIMUM_AVAILABLE)\n    {\n        *Value = NtCurrentTeb()->TlsSlots[Index];\n        return STATUS_SUCCESS;\n    }\n\n    *Value = TlsGetValue(Index);\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Sets the value for a thread-local storage (TLS) slot identified by the specified index.\n *\n * \\param Index The index of the TLS slot to set the value for.\n * \\param Value The value to set for the TLS slot. Can be NULL.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhTlsSetValue(\n    _In_ ULONG Index,\n    _In_opt_ PVOID Value\n    )\n{\n    if (WindowsVersion < WINDOWS_NEW && Index < TLS_MINIMUM_AVAILABLE)\n    {\n        NtCurrentTeb()->TlsSlots[Index] = Value;\n        return STATUS_SUCCESS;\n    }\n\n    if (TlsSetValue(Index, Value))\n        return STATUS_SUCCESS;\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n#pragma endregion\n\n/**\n * Retrieves the last error code generated by the system or the current thread.\n *\n * \\return The last error code as an unsigned long value.\n */\nULONG PhGetLastError(\n    VOID\n    )\n{\n    if (WindowsVersion < WINDOWS_NEW)\n        return NtReadCurrentTebUlong(FIELD_OFFSET(TEB, LastErrorValue)); // NtCurrentTeb()->LastErrorValue\n    return GetLastError();\n}\n\n/**\n * Sets the last error value for the current thread.\n *\n * \\param ErrorValue The error code to set as the last error.\n */\nVOID PhSetLastError(\n    _In_ ULONG ErrorValue\n    )\n{\n    if (WindowsVersion < WINDOWS_NEW)\n        NtCurrentTeb()->LastErrorValue = ErrorValue;\n    else\n        SetLastError(ErrorValue);\n}\n"
  },
  {
    "path": "phlib/bcd.cpp",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2021-2023\n *\n */\n\n#include <ph.h>\n#include <bcd.h>\n#include <mapldr.h>\n\nstatic PVOID BcdDllBaseAddress = nullptr;\nstatic decltype(&BcdOpenSystemStore) BcdOpenSystemStore_I = nullptr;\nstatic decltype(&BcdCloseStore) BcdCloseStore_I = nullptr;\nstatic decltype(&BcdOpenObject) BcdOpenObject_I = nullptr;\nstatic decltype(&BcdCloseObject) BcdCloseObject_I = nullptr;\nstatic decltype(&BcdGetElementData) BcdGetElementData_I = nullptr;\nstatic decltype(&BcdSetElementData) BcdSetElementData_I = nullptr;\n//static decltype(&BcdDeleteElement) BcdDeleteElement_I = nullptr;\nstatic decltype(&BcdEnumerateObjects) BcdEnumerateObjects_I = nullptr;\n\n/**\n * Ensures the BCD API (bcd.dll) is loaded and the required procedure\n * pointers are initialized and cached.\n *\n * \\return TRUE if the BCD API is available and initialized, FALSE otherwise.\n */\nstatic BOOLEAN PhpBcdApiInitialized(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOLEAN bcdInitialized = FALSE;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (BcdDllBaseAddress = PhLoadLibrary(L\"bcd.dll\"))\n        {\n            BcdOpenSystemStore_I = reinterpret_cast<decltype(&BcdOpenSystemStore)>(PhGetDllBaseProcedureAddress(BcdDllBaseAddress, \"BcdOpenSystemStore\", 0));\n            BcdCloseStore_I = reinterpret_cast<decltype(&BcdCloseStore)>(PhGetDllBaseProcedureAddress(BcdDllBaseAddress, \"BcdCloseStore\", 0));\n            BcdOpenObject_I = reinterpret_cast<decltype(&BcdOpenObject)>(PhGetDllBaseProcedureAddress(BcdDllBaseAddress, \"BcdOpenObject\", 0));\n            BcdCloseObject_I = reinterpret_cast<decltype(&BcdCloseObject)>(PhGetDllBaseProcedureAddress(BcdDllBaseAddress, \"BcdCloseObject\", 0));\n            BcdGetElementData_I = reinterpret_cast<decltype(&BcdGetElementData)>(PhGetDllBaseProcedureAddress(BcdDllBaseAddress, \"BcdGetElementData\", 0));\n            BcdSetElementData_I = reinterpret_cast<decltype(&BcdSetElementData)>(PhGetDllBaseProcedureAddress(BcdDllBaseAddress, \"BcdSetElementData\", 0));\n            //BcdDeleteElement_I = reinterpret_cast<decltype(&BcdDeleteElement)>(PhGetDllBaseProcedureAddress(BcdDllBaseAddress, \"BcdDeleteElement\", 0));\n        }\n\n        if (\n            BcdOpenSystemStore_I &&\n            BcdCloseStore_I &&\n            BcdOpenObject_I &&\n            BcdCloseObject_I &&\n            BcdGetElementData_I &&\n            BcdSetElementData_I\n            )\n        {\n            bcdInitialized = TRUE;\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return bcdInitialized;\n}\n\n/**\n * Opens the system BCD store.\n *\n * \\param StoreHandle Receives the handle to the opened BCD store on success.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdOpenSystemStore(\n    _Out_ PHANDLE StoreHandle\n    )\n{\n    NTSTATUS status;\n    HANDLE bcdStoreHandle;\n\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    status = BcdOpenSystemStore_I(\n        &bcdStoreHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *StoreHandle = bcdStoreHandle;\n    }\n\n    return status;\n}\n\n/**\n * Closes a previously opened BCD store handle.\n *\n * \\param StoreHandle The handle to the BCD store to close.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdCloseStore(\n    _In_ HANDLE StoreHandle\n    )\n{\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    return BcdCloseStore_I(StoreHandle);\n}\n\n/**\n * Opens a BCD object identified by \\p Identifier from the specified store.\n *\n * \\param StoreHandle Handle to the BCD store.\n * \\param Identifier Pointer to the GUID that identifies the BCD object to open.\n * \\param ObjectHandle Receives the opened object handle on success.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdOpenObject(\n    _In_ HANDLE StoreHandle,\n    _In_ PCGUID Identifier,\n    _Out_ PHANDLE ObjectHandle\n    )\n{\n    NTSTATUS status;\n    HANDLE bcdObjectHandle;\n\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    status = BcdOpenObject_I(\n        StoreHandle,\n        Identifier,\n        &bcdObjectHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ObjectHandle = bcdObjectHandle;\n    }\n\n    return status;\n}\n\n/**\n * Closes a previously opened BCD object handle.\n *\n * \\param ObjectHandle The handle to the BCD object to close.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdCloseObject(\n    _In_ HANDLE ObjectHandle\n    )\n{\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    return BcdCloseObject_I(ObjectHandle);\n}\n\n/**\n * Retrieves element data from a BCD object.\n *\n * \\param ObjectHandle Handle to the BCD object.\n * \\param ElementType The element type to retrieve.\n * \\param Buffer Buffer to receive the element data; may be NULL to query size.\n * \\param BufferSize On input the size of \\p Buffer; on output receives the number of bytes written or required.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdGetElementData(\n    _In_ HANDLE ObjectHandle,\n    _In_ ULONG ElementType,\n    _Out_writes_bytes_opt_(*BufferSize) PVOID Buffer,\n    _Inout_ PULONG BufferSize\n    )\n{\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    return BcdGetElementData_I(\n        ObjectHandle,\n        ElementType,\n        Buffer,\n        BufferSize\n        );\n}\n\n/**\n * Sets element data on a BCD object.\n *\n * \\param ObjectHandle Handle to the BCD object.\n * \\param ElementType The element type to set.\n * \\param Buffer Buffer containing the element data.\n * \\param BufferSize Size of \\p Buffer in bytes.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdSetElementData(\n    _In_ HANDLE ObjectHandle,\n    _In_ ULONG ElementType,\n    _In_reads_bytes_opt_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize\n    )\n{\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    return BcdSetElementData_I(\n        ObjectHandle,\n        ElementType,\n        Buffer,\n        BufferSize\n        );\n}\n\n//NTSTATUS PhBcdDeleteElement(\n//    _In_ HANDLE ObjectHandle,\n//    _In_ ULONG ElementType\n//    )\n//{\n//    if (!PhpBcdApiInitialized())\n//        return STATUS_UNSUCCESSFUL;\n//\n//    return BcdDeleteElement_I(\n//        ObjectHandle,\n//        ElementType\n//        );\n//}\n\n/**\n * Enumerates BCD objects in the provided store that match \\p EnumDescriptor.\n *\n * \\param StoreHandle Handle to the BCD store.\n * \\param EnumDescriptor Descriptor used to filter the enumeration.\n * \\param Buffer Buffer to receive enumeration results; may be NULL to query size.\n * \\param BufferSize On input the size of \\p Buffer; on output receives the number of bytes written or required.\n * \\param ObjectCount Receives the number of objects returned.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdEnumerateObjects(\n    _In_ HANDLE StoreHandle,\n    _In_ PBCD_OBJECT_DESCRIPTION EnumDescriptor,\n    _Out_writes_bytes_opt_(*BufferSize) PVOID Buffer,\n    _Inout_ PULONG BufferSize,\n    _Out_ PULONG ObjectCount\n    )\n{\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    if (!BcdEnumerateObjects_I)\n    {\n        BcdEnumerateObjects_I = reinterpret_cast<decltype(&BcdEnumerateObjects)>(\n            PhGetDllBaseProcedureAddress(BcdDllBaseAddress, \"BcdEnumerateObjects\", 0));\n    }\n\n    if (!BcdEnumerateObjects_I)\n        return STATUS_UNSUCCESSFUL;\n\n    return BcdEnumerateObjects_I(\n        StoreHandle,\n        EnumDescriptor,\n        Buffer,\n        BufferSize,\n        ObjectCount\n        );\n}\n\n/**\n * Retrieves a string element from a BCD object into a newly allocated PH_STRING.\n *\n * \\param ObjectHandle Handle to the BCD object.\n * \\param ElementType The element type to retrieve (must be string format).\n * \\param ElementString On success receives a referenced PH_STRING; caller must dereference when finished. May be NULL.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdGetElementString(\n    _In_ HANDLE ObjectHandle,\n    _In_ ULONG ElementType,\n    _Out_opt_ PPH_STRING* ElementString\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n    ULONG stringLength;\n\n    assert(GET_BCDE_DATA_FORMAT(ElementType) == BCD_ELEMENT_DATATYPE_FORMAT_STRING);\n\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    stringLength = 0x80;\n    string = PhCreateStringEx(nullptr, stringLength);\n    status = PhBcdGetElementData(\n        ObjectHandle,\n        ElementType,\n        string->Buffer,\n        &stringLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhDereferenceObject(string);\n        string = PhCreateStringEx(nullptr, stringLength);\n\n        status = PhBcdGetElementData(\n            ObjectHandle,\n            ElementType,\n            string->Buffer,\n            &stringLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        string->Length = stringLength - sizeof(UNICODE_NULL);\n\n        if (ElementString)\n            *ElementString = string;\n        else\n            PhDereferenceObject(string);\n\n        return STATUS_SUCCESS;\n    }\n\n    PhDereferenceObject(string);\n\n    return status;\n}\n\n/**\n * Retrieves a 64-bit integer element from a BCD object.\n *\n * \\param ObjectHandle Handle to the BCD object.\n * \\param ElementType The element type to retrieve (must be integer format).\n * \\param ElementValue Receives the 64-bit value on success.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdGetElementUlong64(\n    _In_ HANDLE ObjectHandle,\n    _In_ ULONG ElementType,\n    _Out_ PULONG64 ElementValue\n    )\n{\n    NTSTATUS status;\n    ULONG valueLength = sizeof(ULONG64);\n    ULONG64 valueBuffer = 0;\n\n    assert(GET_BCDE_DATA_FORMAT(ElementType) == BCD_ELEMENT_DATATYPE_FORMAT_INTEGER);\n\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    status = PhBcdGetElementData(\n        ObjectHandle,\n        ElementType,\n        &valueBuffer,\n        &valueLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ElementValue = valueBuffer;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves a boolean element from a BCD object.\n *\n * \\param ObjectHandle Handle to the BCD object.\n * \\param ElementType The element type to retrieve (must be boolean format).\n * \\param ElementValue Receives the boolean value on success.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdGetElementBoolean(\n    _In_ HANDLE ObjectHandle,\n    _In_ ULONG ElementType,\n    _Out_ PBOOLEAN ElementValue\n    )\n{\n    NTSTATUS status;\n    ULONG valueLength = sizeof(BOOLEAN);\n    BOOLEAN valueBuffer = FALSE;\n\n    assert(GET_BCDE_DATA_FORMAT(ElementType) == BCD_ELEMENT_DATATYPE_FORMAT_BOOLEAN);\n\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    status = PhBcdGetElementData(\n        ObjectHandle,\n        ElementType,\n        &valueBuffer,\n        &valueLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ElementValue = valueBuffer;\n    }\n\n    return status;\n}\n\n/**\n * Helper that opens the system store and the current boot entry and retrieves an element's data.\n *\n * \\param ElementType The element type to retrieve.\n * \\param Buffer Buffer to receive the element data; may be NULL to query size.\n * \\param BufferSize On input the size of \\p Buffer; on output receives the number of bytes written or required.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdGetElementData2(\n    _In_ ULONG ElementType,\n    _Out_writes_bytes_opt_(*BufferSize) PVOID Buffer,\n    _Inout_ PULONG BufferSize\n    )\n{\n    NTSTATUS status;\n    HANDLE storeHandle = nullptr;\n    HANDLE objectHandle = nullptr;\n\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    status = BcdOpenSystemStore_I(\n        &storeHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = BcdOpenObject_I(\n        storeHandle,\n        &GUID_CURRENT_BOOT_ENTRY,\n        &objectHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = BcdGetElementData_I(\n        objectHandle,\n        ElementType,\n        Buffer,\n        BufferSize\n        );\n\nCleanupExit:\n    if (objectHandle)\n        PhBcdCloseObject(objectHandle);\n    if (storeHandle)\n        PhBcdCloseStore(storeHandle);\n\n    return status;\n}\n\n/**\n * Helper that opens the system store and the current boot entry and sets an element's data.\n *\n * \\param ElementType The element type to set.\n * \\param Buffer Buffer containing the element data.\n * \\param BufferSize Size of \\p Buffer in bytes.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdSetElementData2(\n    _In_ ULONG ElementType,\n    _In_reads_bytes_opt_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize\n    )\n{\n    NTSTATUS status;\n    HANDLE storeHandle = nullptr;\n    HANDLE objectHandle = nullptr;\n\n    if (!PhpBcdApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    status = BcdOpenSystemStore_I(\n        &storeHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = BcdOpenObject_I(\n        storeHandle,\n        &GUID_CURRENT_BOOT_ENTRY,\n        &objectHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = BcdSetElementData_I(\n        objectHandle,\n        ElementType,\n        Buffer,\n        BufferSize\n        );\n\nCleanupExit:\n    if (objectHandle)\n        BcdCloseObject_I(objectHandle);\n    if (storeHandle)\n        BcdCloseStore_I(storeHandle);\n\n    return status;\n}\n\n/**\n * Sets or clears the \"Advanced Options One Time\" flag for the current boot entry.\n *\n * \\param Enable TRUE to enable the one-time advanced options, FALSE to disable.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdSetAdvancedOptionsOneTime(\n    _In_ BOOLEAN Enable\n    )\n{\n    NTSTATUS status;\n    HANDLE storeHandle = nullptr;\n    HANDLE objectHandle = nullptr;\n\n    status = PhBcdOpenSystemStore(&storeHandle);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhBcdOpenObject(\n        storeHandle,\n        &GUID_CURRENT_BOOT_ENTRY,\n        &objectHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhBcdSetElementData(\n        objectHandle,\n        BcdOSLoaderBoolean_AdvancedOptionsOneTime,\n        &Enable,\n        sizeof(BOOLEAN)\n        );\n\nCleanupExit:\n    if (objectHandle)\n        PhBcdCloseObject(objectHandle);\n    if (storeHandle)\n        PhBcdCloseStore(storeHandle);\n\n    return status;\n}\n\n/**\n * Sets the Windows boot manager's one-time boot application and optionally synchronizes the firmware one-time entry.\n *\n * \\param Identifier GUID of the boot application to set as one-time.\n * \\param UpdateOneTimeFirmware If TRUE attempt to update the firmware boot manager's one-time entry for a seamless reboot.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdSetBootApplicationOneTime(\n    _In_ PCGUID Identifier,\n    _In_opt_ BOOLEAN UpdateOneTimeFirmware\n    )\n{\n    NTSTATUS status;\n    HANDLE storeHandle = nullptr;\n    HANDLE objectHandle = nullptr;\n    BCD_ELEMENT_OBJECT_LIST objectElementList[1];\n\n    status = PhBcdOpenSystemStore(&storeHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (UpdateOneTimeFirmware)\n    {\n        HANDLE objectFirmwareHandle;\n\n        // The user might have a third party boot loader where the Windows NT {bootmgr}\n        // is NOT the default {fwbootmgr} entry. So make the reboot seamless/effortless by\n        // synchronizing the {fwbootmgr} one-time option to the Windows NT {bootmgr}.\n        // This is a QOL optimization so you don't have to manually select Windows\n        // first for it to then launch the boot application we already selected. (dmex)\n\n        if (NT_SUCCESS(PhBcdOpenObject(\n            storeHandle,\n            &GUID_FIRMWARE_BOOTMGR,\n            &objectFirmwareHandle\n            )))\n        {\n            BCD_ELEMENT_OBJECT_LIST objectFirmwareList[32]; // dynamic?\n            ULONG objectFirmwareListLength;\n\n            memset(objectFirmwareList, 0, sizeof(objectFirmwareList));\n            objectFirmwareListLength = sizeof(objectFirmwareList);\n\n            if (NT_SUCCESS(PhBcdGetElementData(\n                objectFirmwareHandle,\n                BcdBootMgrObjectList_DisplayOrder,\n                objectFirmwareList,\n                &objectFirmwareListLength\n                )))\n            {\n                // Check if the default entry is some third party application.\n                if (!IsEqualGUID(objectFirmwareList->ObjectList[0], GUID_WINDOWS_BOOTMGR))\n                {\n                    BCD_ELEMENT_OBJECT_LIST firmwareOneTimeBootEntry[1];\n\n                    firmwareOneTimeBootEntry->ObjectList[0] = GUID_WINDOWS_BOOTMGR;\n\n                    // Set the Windows NT {bootmgr} the one-time {fwbootmgr} entry.\n                    status = PhBcdSetElementData(\n                        objectFirmwareHandle,\n                        BcdBootMgrObjectList_BootSequence,\n                        firmwareOneTimeBootEntry,\n                        sizeof(firmwareOneTimeBootEntry)\n                        );\n                }\n            }\n\n            PhBcdCloseObject(objectFirmwareHandle);\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhBcdOpenObject(\n        storeHandle,\n        &GUID_WINDOWS_BOOTMGR,\n        &objectHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    memcpy(&objectElementList->ObjectList[0], Identifier, sizeof(GUID));\n\n    status = PhBcdSetElementData(\n        objectHandle,\n        BcdBootMgrObjectList_BootSequence,\n        objectElementList,\n        sizeof(objectElementList)\n        );\n\nCleanupExit:\n    if (objectHandle)\n        PhBcdCloseObject(objectHandle);\n    if (storeHandle)\n        PhBcdCloseStore(storeHandle);\n\n    return status;\n}\n\n/**\n * Sets the firmware boot manager's one-time boot application.\n *\n * \\param Identifier GUID of the firmware boot application to set as one-time.\n * \\return NTSTATUS result code.\n */\nNTSTATUS PhBcdSetFirmwareBootApplicationOneTime(\n    _In_ PCGUID Identifier\n    )\n{\n    NTSTATUS status;\n    HANDLE storeHandle = nullptr;\n    HANDLE objectHandle = nullptr;\n    BCD_ELEMENT_OBJECT_LIST objectElementList[1];\n\n    status = PhBcdOpenSystemStore(&storeHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhBcdOpenObject(\n        storeHandle,\n        &GUID_FIRMWARE_BOOTMGR,\n        &objectHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    memcpy(&objectElementList->ObjectList[0], Identifier, sizeof(GUID));\n\n    status = PhBcdSetElementData(\n        objectHandle,\n        BcdBootMgrObjectList_BootSequence,\n        objectElementList,\n        sizeof(objectElementList)\n        );\n\nCleanupExit:\n    if (objectHandle)\n        PhBcdCloseObject(objectHandle);\n    if (storeHandle)\n        PhBcdCloseStore(storeHandle);\n\n    return status;\n}\n\n/**\n * Enumerates OS loader BCD objects and appends entries to the provided list.\n *\n * \\param StoreHandle Handle to the BCD store to enumerate.\n * \\param ObjectList List that receives PPH_BCD_OBJECT_LIST entries.\n */\nstatic VOID PhpBcdEnumerateOsLoaderList(\n    _In_ HANDLE StoreHandle,\n    _In_ PPH_LIST ObjectList\n    )\n{\n    NTSTATUS status;\n    ULONG objectCount = 0;\n    ULONG objectSize = 0;\n    PBCD_OBJECT object = nullptr;\n    BCD_OBJECT_DESCRIPTION description;\n\n    description.Version = BCD_OBJECT_DESCRIPTION_VERSION;\n    description.Type = BCD_OBJECT_OSLOADER_TYPE; // restrict enumeration to OSLOADER types\n\n    status = PhBcdEnumerateObjects(\n        StoreHandle,\n        &description,\n        object,\n        &objectSize,\n        &objectCount\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        object = static_cast<PBCD_OBJECT>(PhAllocate(objectSize));\n        memset(object, 0, objectSize);\n\n        status = PhBcdEnumerateObjects(\n            StoreHandle,\n            &description,\n            object,\n            &objectSize,\n            &objectCount\n            );\n    }\n\n    if (!NT_SUCCESS(status) || !object)\n    {\n        if (object)\n            PhFree(object);\n        return;\n    }\n\n    for (ULONG i = 0; i < objectCount; i++)\n    {\n        HANDLE objectHandle;\n        PPH_STRING objectDescription;\n\n        if (!NT_SUCCESS(PhBcdOpenObject(\n            StoreHandle,\n            &object[i].Identifier,\n            &objectHandle\n            )))\n        {\n            continue;\n        }\n\n        if (NT_SUCCESS(PhBcdGetElementString(\n            objectHandle,\n            BcdLibraryString_Description,\n            &objectDescription\n            )))\n        {\n            PPH_BCD_OBJECT_LIST entry;\n\n            entry = static_cast<PPH_BCD_OBJECT_LIST>(PhAllocateZero(sizeof(PH_BCD_OBJECT_LIST)));\n            memcpy(&entry->ObjectGuid, &object[i].Identifier, sizeof(GUID));\n            entry->ObjectName = objectDescription;\n\n            PhAddItemList(ObjectList, entry);\n        }\n\n        PhBcdCloseObject(objectHandle);\n    }\n\n    {\n        HANDLE objectHandle;\n        PPH_STRING objectDescription;\n\n        // Manually add the memory test application since it's a separate guid. (dmex)\n\n        if (NT_SUCCESS(PhBcdOpenObject(StoreHandle, &GUID_WINDOWS_MEMORY_TESTER, &objectHandle)))\n        {\n            if (NT_SUCCESS(PhBcdGetElementString(objectHandle, BcdLibraryString_Description, &objectDescription)))\n            {\n                PPH_BCD_OBJECT_LIST entry;\n\n                entry = static_cast<PPH_BCD_OBJECT_LIST>(PhAllocateZero(sizeof(PH_BCD_OBJECT_LIST)));\n                memcpy(&entry->ObjectGuid, &GUID_WINDOWS_MEMORY_TESTER, sizeof(GUID));\n                entry->ObjectName = objectDescription;\n\n                PhAddItemList(ObjectList, entry);\n            }\n\n            PhBcdCloseObject(objectHandle);\n        }\n    }\n\n    PhFree(object);\n}\n\n/**\n * Enumerates object lists from a boot manager entry and appends entries to the provided list.\n *\n * \\param StoreHandle Handle to the BCD store.\n * \\param Identifier GUID of the object whose list will be enumerated.\n * \\param ElementType The element type that contains the object list.\n * \\param ObjectList List that receives PPH_BCD_OBJECT_LIST entries.\n */\nstatic VOID PhpBcdEnumerateBootMgrList(\n    _In_ HANDLE StoreHandle,\n    _In_ PCGUID Identifier,\n    _In_ ULONG ElementType,\n    _In_ PPH_LIST ObjectList\n    )\n{\n    NTSTATUS status;\n    HANDLE objectHandle = nullptr;\n    BCD_ELEMENT_OBJECT_LIST objectElementList[32] = { }; // dynamic?\n    ULONG objectListLength = sizeof(objectElementList);\n\n    status = PhBcdOpenObject(\n        StoreHandle,\n        Identifier,\n        &objectHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhBcdGetElementData(\n        objectHandle,\n        ElementType,\n        objectElementList,\n        &objectListLength\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    for (ULONG i = 0; i < objectListLength / sizeof(BCD_ELEMENT_OBJECT_LIST); i++)\n    {\n        HANDLE objectEntryHandle;\n        PPH_STRING objectEntryDescription;\n\n        if (!NT_SUCCESS(PhBcdOpenObject(\n            StoreHandle,\n            &objectElementList->ObjectList[i],\n            &objectEntryHandle\n            )))\n        {\n            continue;\n        }\n\n        if (NT_SUCCESS(PhBcdGetElementString(\n            objectEntryHandle,\n            BcdLibraryString_Description,\n            &objectEntryDescription\n            )))\n        {\n            PPH_BCD_OBJECT_LIST entry;\n\n            entry = static_cast<PPH_BCD_OBJECT_LIST>(PhAllocateZero(sizeof(PH_BCD_OBJECT_LIST)));\n            memcpy(&entry->ObjectGuid, &objectElementList->ObjectList[i], sizeof(GUID));\n            entry->ObjectName = objectEntryDescription;\n\n            PhAddItemList(ObjectList, entry);\n        }\n\n        PhBcdCloseObject(objectEntryHandle);\n    }\n\nCleanupExit:\n    if (objectHandle)\n        PhBcdCloseObject(objectHandle);\n}\n\n/**\n * Queries and returns a list of boot applications.\n *\n * \\param EnumerateAllObjects TRUE to enumerate all OS loader objects; FALSE to use the boot manager display and tools order.\n * \\return A referenced PPH_LIST containing PPH_BCD_OBJECT_LIST entries on success, or NULL on failure.\n */\nPPH_LIST PhBcdQueryBootApplicationList(\n    _In_ BOOLEAN EnumerateAllObjects\n    )\n{\n    NTSTATUS status;\n    HANDLE storeHandle;\n    PPH_LIST objectApplicationList;\n\n    status = PhBcdOpenSystemStore(&storeHandle);\n\n    if (!NT_SUCCESS(status))\n        return nullptr;\n\n    objectApplicationList = PhCreateList(5);\n\n    if (EnumerateAllObjects)\n    {\n        PhpBcdEnumerateOsLoaderList(\n            storeHandle,\n            objectApplicationList\n            );\n    }\n    else\n    {\n        PhpBcdEnumerateBootMgrList(\n            storeHandle,\n            &GUID_WINDOWS_BOOTMGR,\n            BcdBootMgrObjectList_DisplayOrder,\n            objectApplicationList\n            );\n\n        PhpBcdEnumerateBootMgrList(\n            storeHandle,\n            &GUID_WINDOWS_BOOTMGR,\n            BcdBootMgrObjectList_ToolsDisplayOrder,\n            objectApplicationList\n            );\n    }\n\n    PhBcdCloseStore(storeHandle);\n\n    return objectApplicationList;\n}\n\n/**\n * Queries and returns a list of firmware boot applications from the firmware boot manager.\n *\n * \\return A referenced PPH_LIST containing PPH_BCD_OBJECT_LIST entries on success, or NULL on failure.\n */\nPPH_LIST PhBcdQueryFirmwareBootApplicationList(\n    VOID\n    )\n{\n    NTSTATUS status;\n    HANDLE storeHandle;\n    PPH_LIST objectApplicationList;\n\n    status = PhBcdOpenSystemStore(&storeHandle);\n\n    if (!NT_SUCCESS(status))\n        return nullptr;\n\n    objectApplicationList = PhCreateList(5);\n\n    PhpBcdEnumerateBootMgrList(\n        storeHandle,\n        &GUID_FIRMWARE_BOOTMGR,\n        BcdBootMgrObjectList_DisplayOrder,\n        objectApplicationList\n        );\n    PhpBcdEnumerateBootMgrList(\n        storeHandle,\n        &GUID_FIRMWARE_BOOTMGR,\n        BcdBootMgrObjectList_ToolsDisplayOrder,\n        objectApplicationList\n        );\n\n    PhBcdCloseStore(storeHandle);\n\n    return objectApplicationList;\n}\n\n/**\n * Destroys a boot application list and frees associated entries and references.\n *\n * \\param ObjectApplicationList The list to destroy and free.\n */\nVOID PhBcdDestroyBootApplicationList(\n    _In_ PPH_LIST ObjectApplicationList\n    )\n{\n    for (ULONG i = 0; i < ObjectApplicationList->Count; i++)\n    {\n        PPH_BCD_OBJECT_LIST entry = static_cast<PPH_BCD_OBJECT_LIST>(ObjectApplicationList->Items[i]);\n\n        PhDereferenceObject(entry->ObjectName);\n        PhFree(entry);\n    }\n\n    PhDereferenceObject(ObjectApplicationList);\n}\n"
  },
  {
    "path": "phlib/circbuf.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2025\n *\n */\n\n#include <phbase.h>\n#include <circbuf.h>\n\n#pragma push_macro(\"T\")\n\n#undef T\n#define T ULONG\n#include \"circbuf_i.h\"\n\n#undef T\n#define T ULONG64\n#include \"circbuf_i.h\"\n\n#undef T\n#define T PVOID\n#include \"circbuf_i.h\"\n\n#undef T\n#define T SIZE_T\n#include \"circbuf_i.h\"\n\n#undef T\n#define T FLOAT\n#include \"circbuf_i.h\"\n\n#undef T\n#define T DOUBLE\n#include \"circbuf_i.h\"\n\n#undef T\n\n#pragma pop_macro(\"T\")\n"
  },
  {
    "path": "phlib/circbuf_i.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#ifdef T\n\n#include <templ.h>\n\nVOID T___(PhInitializeCircularBuffer, T)(\n    _Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ ULONG Size\n    )\n{\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    Buffer->Size = PhRoundUpToPowerOfTwo(Size);\n    Buffer->SizeMinusOne = Buffer->Size - 1;\n#else\n    Buffer->Size = Size;\n#endif\n\n    Buffer->Count = 0;\n    Buffer->Index = 0;\n    Buffer->Data = PhAllocate(sizeof(T) * Buffer->Size);\n}\n\nVOID T___(PhDeleteCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer\n    )\n{\n    PhFree(Buffer->Data);\n}\n\nVOID T___(PhResizeCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ ULONG NewSize\n    )\n{\n    T *newData;\n    ULONG tailSize;\n    ULONG headSize;\n\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    NewSize = PhRoundUpToPowerOfTwo(NewSize);\n#endif\n\n    // If we're not actually resizing it, return.\n    if (NewSize == Buffer->Size)\n        return;\n\n    newData = PhAllocate(sizeof(T) * NewSize);\n    tailSize = (ULONG)(Buffer->Size - Buffer->Index);\n    headSize = Buffer->Count - tailSize;\n\n    if (NewSize > Buffer->Size)\n    {\n        // Copy the tail, then the head.\n        memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize);\n        memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * headSize);\n        Buffer->Index = 0;\n    }\n    else\n    {\n        if (tailSize >= NewSize)\n        {\n            // Copy only a part of the tail.\n            memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * NewSize);\n            Buffer->Index = 0;\n        }\n        else\n        {\n            // Copy the tail, then only part of the head.\n            memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize);\n            memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * (NewSize - tailSize));\n            Buffer->Index = 0;\n        }\n\n        // Since we're making the circular buffer smaller, limit the count.\n        if (Buffer->Count > NewSize)\n            Buffer->Count = NewSize;\n    }\n\n    Buffer->Data = newData;\n    Buffer->Size = NewSize;\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    Buffer->SizeMinusOne = NewSize - 1;\n#endif\n}\n\nVOID T___(PhClearCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer\n    )\n{\n    Buffer->Count = 0;\n    Buffer->Index = 0;\n}\n\nVOID T___(PhCopyCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _Out_writes_(Count) T *Destination,\n    _In_ ULONG Count\n    )\n{\n    ULONG tailSize;\n    ULONG headSize;\n\n    tailSize = (ULONG)(Buffer->Size - Buffer->Index);\n    headSize = Buffer->Count - tailSize;\n\n    if (Count > Buffer->Count)\n        Count = Buffer->Count;\n\n    if (tailSize >= Count)\n    {\n        // Copy only a part of the tail.\n        memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * Count);\n    }\n    else\n    {\n        // Copy the tail, then only part of the head.\n        memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize);\n        memcpy(&Destination[tailSize], Buffer->Data, sizeof(T) * (Count - tailSize));\n    }\n}\n\n#endif\n"
  },
  {
    "path": "phlib/colorbox.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <colorbox.h>\n#include <guisup.h>\n#include <commdlg.h>\n\ntypedef struct _PH_COLORBOX_CONTEXT\n{\n    COLORREF SelectedColor;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Hot : 1;\n            ULONG HasFocus : 1;\n            ULONG EnableThemeSupport : 1;\n            ULONG Spare : 29;\n        };\n    };\n} PH_COLORBOX_CONTEXT, *PPH_COLORBOX_CONTEXT;\n\nLRESULT CALLBACK PhColorBoxWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nRTL_ATOM PhColorBoxInitialization(\n    VOID\n    )\n{\n    WNDCLASSEX wcex;\n\n    memset(&wcex, 0, sizeof(WNDCLASSEX));\n    wcex.cbSize = sizeof(WNDCLASSEX);\n    wcex.style = CS_GLOBALCLASS;\n    wcex.lpfnWndProc = PhColorBoxWndProc;\n    wcex.cbClsExtra = 0;\n    wcex.cbWndExtra = sizeof(PVOID);\n    wcex.hInstance = NtCurrentImageBase();\n    wcex.hCursor = PhLoadCursor(NULL, IDC_ARROW);\n    wcex.lpszClassName = PH_COLORBOX_CLASSNAME;\n\n    return RegisterClassEx(&wcex);\n}\n\nPPH_COLORBOX_CONTEXT PhCreateColorBoxContext(\n    VOID\n    )\n{\n    PPH_COLORBOX_CONTEXT context;\n\n    context = PhAllocate(sizeof(PH_COLORBOX_CONTEXT));\n    memset(context, 0, sizeof(PH_COLORBOX_CONTEXT));\n\n    return context;\n}\n\nVOID PhFreeColorBoxContext(\n    _In_ _Post_invalid_ PPH_COLORBOX_CONTEXT Context\n    )\n{\n    PhFree(Context);\n}\n\nUINT_PTR CALLBACK PhpColorBoxDlgHookProc(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case WM_INITDIALOG:\n        {\n            LPCHOOSECOLOR chooseColor = (LPCHOOSECOLOR)lParam;\n            PPH_COLORBOX_CONTEXT context = (PPH_COLORBOX_CONTEXT)chooseColor->lCustData;\n\n            PhCenterWindow(hwndDlg, GetParent(hwndDlg));\n\n            PhInitializeWindowTheme(hwndDlg, !!context->EnableThemeSupport);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n        return HANDLE_WM_CTLCOLORBTN(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORDLG:\n        return HANDLE_WM_CTLCOLORDLG(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    case WM_CTLCOLORSTATIC:\n        return HANDLE_WM_CTLCOLORSTATIC(hwndDlg, wParam, lParam, PhWindowThemeControlColor);\n    }\n\n    return FALSE;\n}\n\nVOID PhpChooseColor(\n    _In_ HWND hwnd,\n    _In_ PPH_COLORBOX_CONTEXT Context\n    )\n{\n    CHOOSECOLOR chooseColor = { sizeof(chooseColor) };\n    COLORREF customColors[16] = { 0 };\n\n    chooseColor.hwndOwner = hwnd;\n    chooseColor.rgbResult = Context->SelectedColor;\n    chooseColor.lpCustColors = customColors;\n    chooseColor.lCustData = (LPARAM)Context;\n    chooseColor.lpfnHook = PhpColorBoxDlgHookProc;\n    chooseColor.Flags = CC_ANYCOLOR | CC_ENABLEHOOK | CC_FULLOPEN | CC_RGBINIT;\n\n    if (ChooseColor(&chooseColor))\n    {\n        Context->SelectedColor = chooseColor.rgbResult;\n        InvalidateRect(hwnd, NULL, TRUE);\n        UpdateWindow(hwnd);\n    }\n}\n\nLRESULT CALLBACK PhColorBoxWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_COLORBOX_CONTEXT context = PhGetWindowContextEx(hwnd);\n\n    switch (uMsg)\n    {\n    case WM_NCCREATE:\n        {\n            context = PhCreateColorBoxContext();\n            PhSetWindowContextEx(hwnd, context);\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContextEx(hwnd);\n            PhFreeColorBoxContext(context);\n        }\n        break;\n    case WM_PAINT:\n        {\n            PAINTSTRUCT paintStruct;\n            RECT updateRect;\n            HBRUSH oldBrush;\n            HPEN oldPen;\n            HDC hdc;\n\n            if (hdc = BeginPaint(hwnd, &paintStruct))\n            {\n                updateRect = paintStruct.rcPaint;\n\n                // Border color\n                oldPen = SelectPen(hdc, PhGetStockPen(DC_PEN));\n                SetDCPenColor(hdc, RGB(0x44, 0x44, 0x44));\n\n                // Select the border and fill.\n                oldBrush = SelectBrush(hdc, PhGetStockBrush(DC_BRUSH));\n                // Fill color\n                if (!context->Hot && !context->HasFocus)\n                    SetDCBrushColor(hdc, context->SelectedColor);\n                else\n                    SetDCBrushColor(hdc, PhMakeColorBrighter(context->SelectedColor, 64));\n\n                // Draw the border and fill.\n                Rectangle(hdc, updateRect.left, updateRect.top, updateRect.right, updateRect.bottom);\n\n                // Restore the original border and fill.\n                SelectBrush(hdc, oldBrush);\n                SelectPen(hdc, oldPen);\n\n                EndPaint(hwnd, &paintStruct);\n            }\n        }\n        return 0;\n    case WM_ERASEBKGND:\n        return 1;\n    case WM_MOUSEMOVE:\n        {\n            if (!context->Hot)\n            {\n                TRACKMOUSEEVENT trackMouseEvent = { sizeof(trackMouseEvent) };\n\n                context->Hot = TRUE;\n                InvalidateRect(hwnd, NULL, TRUE);\n\n                trackMouseEvent.dwFlags = TME_LEAVE;\n                trackMouseEvent.hwndTrack = hwnd;\n                TrackMouseEvent(&trackMouseEvent);\n            }\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            context->Hot = FALSE;\n            InvalidateRect(hwnd, NULL, TRUE);\n        }\n        break;\n    case WM_LBUTTONDOWN:\n        {\n            PhpChooseColor(hwnd, context);\n        }\n        break;\n    case WM_SETFOCUS:\n        {\n            context->HasFocus = TRUE;\n            InvalidateRect(hwnd, NULL, TRUE);\n        }\n        return 0;\n    case WM_KILLFOCUS:\n        {\n            context->HasFocus = FALSE;\n            InvalidateRect(hwnd, NULL, TRUE);\n        }\n        return 0;\n    case WM_GETDLGCODE:\n        if (wParam == VK_RETURN)\n            return DLGC_WANTMESSAGE;\n        return 0;\n    case WM_KEYDOWN:\n        {\n            switch (wParam)\n            {\n            case VK_SPACE:\n            case VK_RETURN:\n                PhpChooseColor(hwnd, context);\n                break;\n            }\n        }\n        break;\n    case CBCM_SETCOLOR:\n        context->SelectedColor = (COLORREF)wParam;\n        return TRUE;\n    case CBCM_GETCOLOR:\n        return (LRESULT)context->SelectedColor;\n    case CBCM_THEMESUPPORT:\n        context->EnableThemeSupport = (BOOLEAN)wParam;\n        return TRUE;\n    }\n\n    return DefWindowProc(hwnd, uMsg, wParam, lParam);\n}\n"
  },
  {
    "path": "phlib/cpysave.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2012\n *     dmex    2018-2023\n *\n */\n\n#include <ph.h>\n#include <cpysave.h>\n\n#include <guisup.h>\n#include <treenew.h>\n\n#define TAB_SIZE 8\n\nVOID PhpEscapeStringForCsv(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PPH_STRING String\n    )\n{\n    SIZE_T i;\n    SIZE_T length;\n    PWCHAR runStart;\n    SIZE_T runLength;\n\n    length = String->Length / sizeof(WCHAR);\n    runStart = NULL;\n    runLength = 0;\n\n    for (i = 0; i < length; i++)\n    {\n        switch (String->Buffer[i])\n        {\n        case L'\\\"':\n            if (runStart)\n            {\n                PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR));\n                runStart = NULL;\n            }\n\n            PhAppendStringBuilder2(StringBuilder, L\"\\\"\\\"\");\n\n            break;\n        case L',':\n            if (runStart)\n            {\n                PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR));\n                runStart = NULL;\n            }\n\n            // Note: There doesn't seem to be a proper way to escape\n            // commas for some locales in a way that works with all\n            // third party software. For now we'll swap commas\n            // for full stops. This works but prevents formatting\n            // integers with the correct decimal separator. (dmex)\n\n            PhAppendStringBuilder2(StringBuilder, L\".\");\n\n            break;\n        default:\n            if (runStart)\n            {\n                runLength++;\n            }\n            else\n            {\n                runStart = &String->Buffer[i];\n                runLength = 1;\n            }\n\n            break;\n        }\n    }\n\n    if (runStart)\n        PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR));\n}\n\n/**\n * Allocates a text table.\n *\n * \\param Table A variable which receives a pointer to the text table.\n * \\param Rows The number of rows in the table.\n * \\param Columns The number of columns in the table.\n */\nVOID PhaCreateTextTable(\n    _Out_ PPH_STRING ***Table,\n    _In_ ULONG Rows,\n    _In_ ULONG Columns\n    )\n{\n    PPH_STRING **table;\n    ULONG i;\n\n    table = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING *) * Rows));\n\n    for (i = 0; i < Rows; i++)\n    {\n        table[i] = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING) * Columns));\n        memset(table[i], 0, sizeof(PPH_STRING) * Columns);\n    }\n\n    *Table = table;\n}\n\n/**\n * Formats a text table to a list of lines.\n *\n * \\param Table A pointer to the text table.\n * \\param Rows The number of rows in the table.\n * \\param Columns The number of columns in the table.\n * \\param Mode The export formatting mode.\n *\n * \\return A list of strings for each line in the output. The list object and\n * string objects are not auto-dereferenced.\n */\nPPH_LIST PhaFormatTextTable(\n    _In_ PPH_STRING **Table,\n    _In_ ULONG Rows,\n    _In_ ULONG Columns,\n    _In_ ULONG Mode\n    )\n{\n    PPH_LIST lines;\n    // The tab count array contains the number of tabs need to fill the biggest\n    // row cell in each column.\n    PULONG tabCount = NULL;\n    ULONG i;\n    ULONG j;\n\n    if (Mode == PH_EXPORT_MODE_TABS || Mode == PH_EXPORT_MODE_SPACES)\n    {\n        // Create the tab count array.\n\n        tabCount = PH_AUTO(PhCreateAlloc(sizeof(ULONG) * Columns));\n        memset(tabCount, 0, sizeof(ULONG) * Columns); // zero all values\n\n        for (i = 0; i < Rows; i++)\n        {\n            for (j = 0; j < Columns; j++)\n            {\n                ULONG newCount;\n\n                if (Table[i][j])\n                    newCount = (ULONG)(Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE);\n                else\n                    newCount = 0;\n\n                // Replace the existing count if this tab count is bigger.\n                if (tabCount[j] < newCount)\n                    tabCount[j] = newCount;\n            }\n        }\n    }\n\n    // Create the final list of lines by going through each cell and appending\n    // the proper tab count (if we are using tabs). This will make sure each column\n    // is properly aligned.\n\n    lines = PhCreateList(Rows);\n\n    for (i = 0; i < Rows; i++)\n    {\n        PH_STRING_BUILDER stringBuilder;\n\n        PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n        switch (Mode)\n        {\n        case PH_EXPORT_MODE_TABS:\n            {\n                for (j = 0; j < Columns; j++)\n                {\n                    ULONG k;\n\n                    if (Table[i][j])\n                    {\n                        // Calculate the number of tabs needed.\n                        k = (ULONG)(tabCount[j] + 1 - Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE);\n\n                        PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr);\n                    }\n                    else\n                    {\n                        k = tabCount[j] + 1;\n                    }\n\n                    PhAppendCharStringBuilder2(&stringBuilder, L'\\t', k);\n                }\n            }\n            break;\n        case PH_EXPORT_MODE_SPACES:\n            {\n                for (j = 0; j < Columns; j++)\n                {\n                    ULONG k;\n\n                    if (Table[i][j])\n                    {\n                        // Calculate the number of spaces needed.\n                        k = (ULONG)((tabCount[j] + 1) * TAB_SIZE - Table[i][j]->Length / sizeof(WCHAR));\n\n                        PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr);\n                    }\n                    else\n                    {\n                        k = (tabCount[j] + 1) * TAB_SIZE;\n                    }\n\n                    PhAppendCharStringBuilder2(&stringBuilder, L' ', k);\n                }\n            }\n            break;\n        case PH_EXPORT_MODE_CSV:\n            {\n                for (j = 0; j < Columns; j++)\n                {\n                    PhAppendCharStringBuilder(&stringBuilder, L'\\\"');\n\n                    if (Table[i][j])\n                    {\n                        PhpEscapeStringForCsv(&stringBuilder, Table[i][j]);\n                    }\n\n                    PhAppendCharStringBuilder(&stringBuilder, L'\\\"');\n\n                    if (j != Columns - 1)\n                        PhAppendCharStringBuilder(&stringBuilder, L',');\n                }\n            }\n            break;\n        }\n\n        PhAddItemList(lines, PhFinalStringBuilderString(&stringBuilder));\n    }\n\n    return lines;\n}\n\n_Use_decl_annotations_\nBOOLEAN PhMapDisplayIndexTreeNew(\n    _In_ HWND TreeNewHandle,\n    _Out_opt_ PULONG *DisplayToId,\n    _Out_opt_ PWSTR **DisplayToText,\n    _Out_ PULONG NumberOfColumns\n    )\n{\n    BOOLEAN result = TRUE;\n    PPH_TREENEW_COLUMN fixedColumn;\n    ULONG numberOfColumns;\n    PULONG displayToId;\n    PWSTR *displayToText;\n    ULONG i;\n    PH_TREENEW_COLUMN column;\n\n    fixedColumn = TreeNew_GetFixedColumn(TreeNewHandle);\n    numberOfColumns = TreeNew_GetVisibleColumnCount(TreeNewHandle);\n\n    displayToId = PhAllocate(numberOfColumns * sizeof(ULONG));\n\n    if (fixedColumn)\n    {\n        TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns - 1, displayToId + 1);\n        displayToId[0] = fixedColumn->Id;\n    }\n    else\n    {\n        TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns, displayToId);\n    }\n\n    if (DisplayToText)\n    {\n        displayToText = PhAllocate(numberOfColumns * sizeof(PWSTR));\n\n        for (i = 0; i < numberOfColumns; i++)\n        {\n            if (TreeNew_GetColumn(TreeNewHandle, displayToId[i], &column))\n            {\n                displayToText[i] = (PWSTR)column.Text;\n            }\n            else\n            {\n                result = FALSE;\n                break;\n            }\n        }\n\n        *DisplayToText = displayToText;\n    }\n\n    if (result)\n    {\n        if (DisplayToId)\n            *DisplayToId = displayToId;\n        else\n            PhFree(displayToId);\n\n        *NumberOfColumns = numberOfColumns;\n        return TRUE;\n    }\n\n    PhFree(displayToId);\n    return FALSE;\n}\n\nPPH_STRING PhGetTreeNewText(\n    _In_ HWND TreeNewHandle,\n    _Reserved_ ULONG Reserved\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    PULONG displayToId;\n    ULONG rows;\n    ULONG columns;\n    ULONG i;\n    ULONG j;\n\n    PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, NULL, &columns);\n    rows = TreeNew_GetFlatNodeCount(TreeNewHandle);\n\n    PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n    for (i = 0; i < rows; i++)\n    {\n        PH_TREENEW_GET_CELL_TEXT getCellText;\n\n        getCellText.Node = TreeNew_GetFlatNode(TreeNewHandle, i);\n        assert(getCellText.Node);\n\n        if (!getCellText.Node->Selected)\n            continue;\n\n        for (j = 0; j < columns; j++)\n        {\n            getCellText.Id = displayToId[j];\n            PhInitializeEmptyStringRef(&getCellText.Text);\n            TreeNew_GetCellText(TreeNewHandle, &getCellText);\n\n            // Ignore empty columns. (dmex)\n            if (getCellText.Text.Length != 0)\n            {\n                PhAppendStringBuilder(&stringBuilder, &getCellText.Text);\n            }\n\n            PhAppendStringBuilder2(&stringBuilder, L\", \");\n        }\n\n        // Remove the trailing comma and space.\n        if (stringBuilder.String->Length != 0)\n            PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    }\n\n    PhFree(displayToId);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nPPH_LIST PhGetGenericTreeNewLines(\n    _In_ HWND TreeNewHandle,\n    _In_ ULONG Mode\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_LIST lines;\n    ULONG rows;\n    ULONG columns;\n    ULONG numberOfNodes;\n    PULONG displayToId;\n    PWSTR *displayToText;\n    PPH_STRING **table;\n    ULONG i;\n    ULONG j;\n\n    PhInitializeAutoPool(&autoPool);\n\n    numberOfNodes = TreeNew_GetFlatNodeCount(TreeNewHandle);\n\n    rows = numberOfNodes + 1;\n    PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, &displayToText, &columns);\n\n    PhaCreateTextTable(&table, rows, columns);\n\n    for (i = 0; i < columns; i++)\n        table[0][i] = PhaCreateString(displayToText[i]);\n\n    for (i = 0; i < numberOfNodes; i++)\n    {\n        PPH_TREENEW_NODE node;\n\n        node = TreeNew_GetFlatNode(TreeNewHandle, i);\n\n        if (node)\n        {\n            for (j = 0; j < columns; j++)\n            {\n                PH_TREENEW_GET_CELL_TEXT getCellText;\n\n                getCellText.Node = node;\n                getCellText.Id = displayToId[j];\n                PhInitializeEmptyStringRef(&getCellText.Text);\n                TreeNew_GetCellText(TreeNewHandle, &getCellText);\n\n                table[i + 1][j] = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length);\n            }\n        }\n        else\n        {\n            for (j = 0; j < columns; j++)\n            {\n                table[i + 1][j] = PH_AUTO(PhReferenceEmptyString());\n            }\n        }\n    }\n\n    PhFree(displayToText);\n    PhFree(displayToId);\n\n    lines = PhaFormatTextTable(table, rows, columns, Mode);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return lines;\n}\n\n_Use_decl_annotations_\nBOOLEAN PhaMapDisplayIndexListView(\n    _In_ HWND ListViewHandle,\n    _Out_writes_(Count) PULONG DisplayToId,\n    _Out_writes_opt_(Count) PPH_STRING *DisplayToText,\n    _In_ ULONG Count,\n    _Out_ PULONG NumberOfColumns\n    )\n{\n    LVCOLUMN lvColumn;\n    ULONG i;\n    ULONG count;\n    WCHAR buffer[128];\n\n    count = 0;\n    lvColumn.mask = LVCF_ORDER | LVCF_TEXT;\n    lvColumn.pszText = buffer;\n    lvColumn.cchTextMax = sizeof(buffer) / sizeof(WCHAR);\n\n    for (i = 0; i < Count; i++)\n    {\n        if (ListView_GetColumn(ListViewHandle, i, &lvColumn))\n        {\n            ULONG displayIndex;\n\n            displayIndex = (ULONG)lvColumn.iOrder;\n            assert(displayIndex < Count);\n            DisplayToId[displayIndex] = i;\n\n            if (DisplayToText)\n                DisplayToText[displayIndex] = PhaCreateString(buffer);\n\n            count++;\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    *NumberOfColumns = count;\n    return TRUE;\n}\n\nPPH_STRING PhGetListViewItemText(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex\n    )\n{\n    PPH_STRING buffer;\n    SIZE_T allocatedCount;\n    SIZE_T count;\n    LVITEM lvItem;\n\n    // Unfortunately LVM_GETITEMTEXT doesn't want to return the actual length of the text.\n    // Keep doubling the buffer size until we get a return count that is strictly less than\n    // the amount we allocated.\n\n    buffer = NULL;\n    allocatedCount = 256;\n    count = allocatedCount;\n\n    while (count >= allocatedCount)\n    {\n        allocatedCount *= 2;\n        if (buffer) PhDereferenceObject(buffer);\n        buffer = PhCreateStringEx(NULL, (allocatedCount + 1) * sizeof(WCHAR));\n\n        lvItem.iSubItem = SubItemIndex;\n        lvItem.cchTextMax = (LONG)allocatedCount;\n        lvItem.pszText = buffer->Buffer;\n        count = SendMessage(ListViewHandle, LVM_GETITEMTEXT, Index, (LPARAM)&lvItem);\n    }\n\n    PhTrimToNullTerminatorString(buffer);\n\n    return buffer;\n}\n\n//PPH_STRING PhGetListViewItemText(\n//    _In_ HWND ListViewHandle,\n//    _In_ INT Index,\n//    _In_ INT SubIndex\n//    )\n//{\n//    WCHAR buffer[DOS_MAX_PATH_LENGTH] = L\"\";\n//    LVITEM item;\n//\n//    item.mask = LVIF_TEXT;\n//    item.iItem = Index;\n//    item.iSubItem = SubIndex;\n//    item.pszText = buffer;\n//    item.cchTextMax = RTL_NUMBER_OF(buffer);\n//\n//    if (ListView_GetItem(ListViewHandle, &item))\n//    {\n//        return PhCreateString(buffer);\n//    }\n//\n//    return NULL;\n//}\n\nPPH_STRING PhGetListViewSelectedItemText(\n    _In_ HWND ListViewHandle\n    )\n{\n    LONG index;\n\n    index = PhFindListViewItemByFlags(\n        ListViewHandle,\n        INT_ERROR,\n        LVNI_SELECTED\n        );\n\n    if (index != INT_ERROR)\n    {\n        return PhGetListViewItemText(ListViewHandle, index, 0);\n    }\n\n    return NULL;\n}\n\nPPH_STRING PhaGetListViewItemText(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex\n    )\n{\n    PPH_STRING value;\n\n    if (value = PhGetListViewItemText(ListViewHandle, Index, SubItemIndex))\n    {\n        PH_AUTO(value);\n\n        return value;\n    }\n\n    return NULL;\n}\n\nPPH_STRING PhGetListViewText(\n    _In_ HWND ListViewHandle\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PH_STRING_BUILDER stringBuilder;\n    ULONG displayToId[100];\n    ULONG rows;\n    ULONG columns;\n    ULONG i;\n    ULONG j;\n\n    PhInitializeAutoPool(&autoPool);\n\n    PhaMapDisplayIndexListView(ListViewHandle, displayToId, NULL, 100, &columns);\n    rows = ListView_GetItemCount(ListViewHandle);\n\n    PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n    for (i = 0; i < rows; i++)\n    {\n        if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED))\n            continue;\n\n        for (j = 0; j < columns; j++)\n        {\n            PhAppendStringBuilder(&stringBuilder, &PhaGetListViewItemText(ListViewHandle, i, j)->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\", \");\n        }\n\n        // Remove the trailing comma and space.\n        if (stringBuilder.String->Length != 0)\n            PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    }\n\n    PhDeleteAutoPool(&autoPool);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nPPH_LIST PhGetListViewLines(\n    _In_ HWND ListViewHandle,\n    _In_ ULONG Mode\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_LIST lines;\n    ULONG rows;\n    ULONG columns;\n    ULONG displayToId[100];\n    PPH_STRING displayToText[100];\n    PPH_STRING **table;\n    ULONG i;\n    ULONG j;\n\n    PhInitializeAutoPool(&autoPool);\n\n    rows = ListView_GetItemCount(ListViewHandle) + 1; // +1 for column headers\n\n    // Create the display index/text to ID map.\n    PhaMapDisplayIndexListView(ListViewHandle, displayToId, displayToText, 100, &columns);\n\n    PhaCreateTextTable(&table, rows, columns);\n\n    // Populate the first row with the column headers.\n    for (i = 0; i < columns; i++)\n        table[0][i] = displayToText[i];\n\n    // Populate the other rows with text.\n    for (i = 1; i < rows; i++)\n    {\n        for (j = 0; j < columns; j++)\n        {\n            // Important: use this to bypass extlv's hooking.\n            // extlv only hooks LVM_GETITEM, not LVM_GETITEMTEXT.\n            table[i][j] = PhaGetListViewItemText(ListViewHandle, i - 1, j);\n        }\n    }\n\n    lines = PhaFormatTextTable(table, rows, columns, Mode);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return lines;\n}\n"
  },
  {
    "path": "phlib/data.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2026\n *\n */\n\n#include <ph.h>\n#include <phdata.h>\n\n// SIDs\n\nCONST SID PhSeNobodySid = { SID_REVISION, 1, SECURITY_NULL_SID_AUTHORITY, { SECURITY_NULL_RID } };\n\nCONST SID PhSeEveryoneSid = { SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, { SECURITY_WORLD_RID } };\n\nCONST SID PhSeLocalSid = { SID_REVISION, 1, SECURITY_LOCAL_SID_AUTHORITY, { SECURITY_LOCAL_RID } };\n\nCONST SID PhSeCreatorOwnerSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_OWNER_RID } };\nCONST SID PhSeCreatorGroupSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_GROUP_RID } };\n\nCONST SID PhSeDialupSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_DIALUP_RID } };\nCONST SID PhSeNetworkSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_RID } };\nCONST SID PhSeBatchSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_BATCH_RID } };\nCONST SID PhSeInteractiveSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_INTERACTIVE_RID } };\nCONST SID PhSeServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_SERVICE_RID } };\nCONST SID PhSeAnonymousLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_ANONYMOUS_LOGON_RID } };\nCONST SID PhSeProxySid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_PROXY_RID } };\nCONST SID PhSeAuthenticatedUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_AUTHENTICATED_USER_RID } };\nCONST SID PhSeRestrictedCodeSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_RESTRICTED_CODE_RID } };\nCONST SID PhSeTerminalServerUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_TERMINAL_SERVER_RID } };\nCONST SID PhSeRemoteInteractiveLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_REMOTE_LOGON_RID } };\nCONST SID PhSeLocalSystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } };\nCONST SID PhSeLocalServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SERVICE_RID } };\nCONST SID PhSeNetworkServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_SERVICE_RID } };\n\nPSID PhSeAdministratorsSid( // WinBuiltinAdministratorsSid (dmex)\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG[2])];\n    static SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;\n    PSID administratorsSid = (PSID)administratorsSidBuffer;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeSid(administratorsSid, &authority, 2);\n        *PhSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;\n        *PhSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS;\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    assert(PhLengthSid(administratorsSid) == sizeof(administratorsSidBuffer));\n\n    return administratorsSid;\n}\n\nPSID PhSeUsersSid( // WinBuiltinUsersSid (dmex)\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static UCHAR usersSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG[2])];\n    static SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;\n    PSID usersSid = (PSID)usersSidBuffer;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeSid(usersSid, &authority, 2);\n        *PhSubAuthoritySid(usersSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;\n        *PhSubAuthoritySid(usersSid, 1) = DOMAIN_ALIAS_RID_USERS;\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    assert(PhLengthSid(usersSid) == sizeof(usersSidBuffer));\n\n    return usersSid;\n}\n\nPSID PhSeAnyPackageSid( // WinBuiltinAnyPackageSid (dmex)\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static UCHAR anyAppPackagesSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG[2])];\n    static SID_IDENTIFIER_AUTHORITY authority = SECURITY_APP_PACKAGE_AUTHORITY;\n    PSID anyAppPackagesSid = (PSID)anyAppPackagesSidBuffer;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeSid(anyAppPackagesSid, &authority, SECURITY_BUILTIN_APP_PACKAGE_RID_COUNT);\n        *PhSubAuthoritySid(anyAppPackagesSid, 0) = SECURITY_APP_PACKAGE_BASE_RID;\n        *PhSubAuthoritySid(anyAppPackagesSid, 1) = SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE;\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    assert(PhLengthSid(anyAppPackagesSid) == sizeof(anyAppPackagesSidBuffer));\n\n    return anyAppPackagesSid;\n}\n\nPSID PhSeInternetExplorerSid( // S-1-15-3-4096 (dmex)\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static UCHAR internetExplorerSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG[2])];\n    static SID_IDENTIFIER_AUTHORITY authority = SECURITY_APP_PACKAGE_AUTHORITY;\n    PSID internetExplorerSid = (PSID)internetExplorerSidBuffer;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeSid(internetExplorerSid, &authority, SECURITY_BUILTIN_APP_PACKAGE_RID_COUNT);\n        *PhSubAuthoritySid(internetExplorerSid, 0) = SECURITY_CAPABILITY_BASE_RID;\n        *PhSubAuthoritySid(internetExplorerSid, 1) = SECURITY_CAPABILITY_INTERNET_EXPLORER;\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    assert(PhLengthSid(internetExplorerSid) == sizeof(internetExplorerSidBuffer));\n\n    return internetExplorerSid;\n}\n\nPSID PhSeCloudActiveDirectorySid( // S-1-12-1 (dmex)\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static UCHAR activeDirectorySidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG[1])];\n    static SID_IDENTIFIER_AUTHORITY authority = { 0, 0, 0, 0, 0, 12 };\n    PSID activeDirectorySid = (PSID)activeDirectorySidBuffer;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeSid(activeDirectorySid, &authority, 1);\n        *PhSubAuthoritySid(activeDirectorySid, 0) = 1;\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    assert(PhLengthSid(activeDirectorySid) == sizeof(activeDirectorySidBuffer));\n\n    return activeDirectorySid;\n}\n\nPSID PhSeLogonIdSid(\n    _In_ ULONG LogonId\n    )\n{\n    static UCHAR logonSessionSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG[SECURITY_LOGON_IDS_RID_COUNT])];\n    static SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;\n    PSID logonSessionSid = (PSID)logonSessionSidBuffer;\n\n    PhInitializeSid(logonSessionSid, &authority, SECURITY_LOGON_IDS_RID_COUNT);\n    *PhSubAuthoritySid(logonSessionSid, 0) = SECURITY_LOGON_IDS_RID;\n    *PhSubAuthoritySid(logonSessionSid, 1) = 0;\n    *PhSubAuthoritySid(logonSessionSid, 2) = LogonId;\n\n    return logonSessionSid;\n}\n\n\n// Unicode\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhUnicodeByteOrderMark = PH_STRINGREF_INIT(L\"\\ufeff\");\n\n// Characters\n\nDECLSPEC_SELECTANY CONST\nBOOLEAN PhCharIsPrintable[256] =\n{\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 - 15 */ // TAB, LF and CR are printable\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ' ' - '/' */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* '0' - '9' */\n    1, 1, 1, 1, 1, 1, 1, /* ':' - '@' */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'A' - 'Z' */\n    1, 1, 1, 1, 1, 1, /* '[' - '`' */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'a' - 'z' */\n    1, 1, 1, 1, 0, /* '{' - 127 */ // DEL is not printable\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 - 143 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 - 159 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160 - 175 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176 - 191 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 - 207 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208 - 223 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224 - 239 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 240 - 255 */\n};\n\nDECLSPEC_SELECTANY CONST\nBOOLEAN PhCharIsPrintableEx[256] =\n{\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 - 15 */ // TAB, LF and CR are printable\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ' ' - '/' */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* '0' - '9' */\n    1, 1, 1, 1, 1, 1, 1, /* ':' - '@' */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'A' - 'Z' */\n    1, 1, 1, 1, 1, 1, /* '[' - '`' */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'a' - 'z' */\n    1, 1, 1, 1, 0, /* '{' - 127 */ // DEL is not printable\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 - 143 (excluded by iswprint) */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 - 159 (excluded by iswprint) */\n    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 160 - 175 */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 176 - 191 */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 192 - 207 */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 208 - 223 */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 224 - 239 */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  /* 240 - 255 */\n};\n\n/**\n * Table mapping ASCII character codes to their corresponding integer values.\n *\n * This table is used for fast character-to-integer conversion, supporting:\n * - Decimal digits ('0'-'9') mapped to 0-9\n * - Uppercase letters ('A'-'Z') and lowercase letters ('a'-'z') mapped to 10-35\n * - Common printable symbols mapped to 36-68\n * - All other values are set to -1 (invalid)\n *\n * Example usage:\n *   LONG value = PhCharToInteger['A']; // value == 10\n *\n * \\note\n *  - Indices 0-255 correspond to all possible unsigned char values.\n *  - Non-mapped characters (including control codes) return -1.\n */\nDECLSPEC_SELECTANY CONST\nLONG PhCharToInteger[256] =\n{\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 15 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 16 - 31 */\n    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, /* ' ' - '/' */\n    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */\n    52, 53, 54, 55, 56, 57, 58, /* ':' - '@' */\n    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, /* 'A' - 'Z' */\n    59, 60, 61, 62, 63, 64, /* '[' - '`' */\n    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, /* 'a' - 'z' */\n    65, 66, 67, 68, -1, /* '{' - 127 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 128 - 143 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 - 159 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 - 175 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 - 191 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 - 207 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 - 223 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 - 239 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 240 - 255 */\n};\n\n// UTF-16 Validation Tables\n//\n// UTF-16 encodes Unicode using 16-bit code units:\n// - BMP (U+0000 to U+FFFF): Single 16-bit unit, excluding surrogate range (0xD800-0xDFFF)\n// - Supplementary planes (U+10000 to U+10FFFF): Surrogate pairs\n//   * High surrogate: 0xD800-0xDBFF (high byte: 0xD8-0xDB)\n//   * Low surrogate:  0xDC00-0xDFFF (high byte: 0xDC-0xDF)\n//\n// For memory scanning:\n// 1. Check if high byte is a high surrogate (0xD8-0xDB) - must be followed by low surrogate\n// 2. Check if high byte is a low surrogate (0xDC-0xDF) - must be preceded by high surrogate\n// 3. All other high bytes (0x00-0xD7, 0xE0-0xFF) represent valid single-unit characters\n\n// Valid UTF-16 high surrogate high bytes (0xD8, 0xD9, 0xDA, 0xDB)\nDECLSPEC_SELECTANY CONST\nBOOLEAN PhIsUTF16HighSurrogateHighByte[256] =\n{\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xCF */\n    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /* 0xD0 - 0xDF (0xD8-0xDB are high surrogates) */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xF0 - 0xFF */\n};\n\n// Valid UTF-16 low surrogate high bytes (0xDC, 0xDD, 0xDE, 0xDF)\nDECLSPEC_SELECTANY CONST\nBOOLEAN PhIsUTF16LowSurrogateHighByte[256] =\n{\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xCF */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 0xD0 - 0xDF (0xDC-0xDF are low surrogates) */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xF0 - 0xFF */\n};\n\n// Valid standalone character high bytes (excludes surrogate range 0xD8-0xDF)\n// These can appear as standalone UTF-16 characters\nDECLSPEC_SELECTANY CONST\nBOOLEAN PhIsUTF16StandaloneHighByte[256] =\n{\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 - 0x0F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 - 0x1F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 - 0x2F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x30 - 0x3F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9F */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xA0 - 0xAF */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xB0 - 0xBF */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */\n    1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF (0xD8-0xDF are surrogates) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xE0 - 0xEF */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  /* 0xF0 - 0xFF */\n};\n\n// Printable character high bytes (common printable ranges)\n// Based on Unicode categories: Latin, punctuation, symbols, CJK, etc.\n// Non-printable: C0/C1 controls (0x00-0x1F, 0x7F-0x9F), private use, specials\nDECLSPEC_SELECTANY CONST\nBOOLEAN PhIsUTF16PrintableHighByte[256] =\n{\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0F (C0 controls) */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F (C0 controls) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 - 0x2F (Latin-1, punctuation) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x30 - 0x3F (Latin Extended, IPA) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F (Cyrillic, Armenian, Hebrew) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5F (Arabic, Devanagari, Bengali) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F (Thai, Lao, Tibetan) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7F (Georgian, Hangul Jamo) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8F (Latin Extended Additional) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9F (Greek Extended) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xA0 - 0xAF (Punctuation, Currency, Letterlike) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xB0 - 0xBF (Arrows, Math, Technical) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF (Box Drawing, Block Elements, CJK) */\n    1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF (Hangul Syllables / surrogates) */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF (Private Use Area) */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0  /* 0xF0 - 0xFF (CJK Compatibility, Specials) */\n};\n\nDECLSPEC_SELECTANY CONST\nCHAR PhIntegerToChar[69] =\n    \"0123456789\" /* 0 - 9 */\n    \"abcdefghijklmnopqrstuvwxyz\" /* 10 - 35 */\n    \" !\\\"#$%&'()*+,-./\" /* 36 - 51 */\n    \":;<=>?@\" /* 52 - 58 */\n    \"[\\\\]^_`\" /* 59 - 64 */\n    \"{|}~\" /* 65 - 68 */\n    ;\n\nDECLSPEC_SELECTANY CONST\nCHAR PhIntegerToCharUpper[69] =\n    \"0123456789\" /* 0 - 9 */\n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\" /* 10 - 35 */\n    \" !\\\"#$%&'()*+,-./\" /* 36 - 51 */\n    \":;<=>?@\" /* 52 - 58 */\n    \"[\\\\]^_`\" /* 59 - 64 */\n    \"{|}~\" /* 65 - 68 */\n   ;\n\n// CRC32 (IEEE 802.3)\n\nDECLSPEC_SELECTANY CONST\nULONG PhCrc32Table[256] =\n{\n    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,\n    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,\n    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,\n    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,\n    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,\n    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,\n    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,\n    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,\n    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,\n    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,\n    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,\n    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,\n    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,\n    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,\n    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,\n    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,\n    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,\n    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\n};\n\n// Enums\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhIoPriorityHintNames[] =\n{\n    PH_STRINGREF_INIT(L\"Very low\"),\n    PH_STRINGREF_INIT(L\"Low\"),\n    PH_STRINGREF_INIT(L\"Normal\"),\n    PH_STRINGREF_INIT(L\"High\"),\n    PH_STRINGREF_INIT(L\"Critical\"),\n};\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhPagePriorityNames[] =\n{\n    PH_STRINGREF_INIT(L\"Lowest\"),\n    PH_STRINGREF_INIT(L\"Very low\"),\n    PH_STRINGREF_INIT(L\"Low\"),\n    PH_STRINGREF_INIT(L\"Medium\"),\n    PH_STRINGREF_INIT(L\"Below normal\"),\n    PH_STRINGREF_INIT(L\"Normal\"),\n};\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhKThreadStateNames[] =\n{\n    PH_STRINGREF_INIT(L\"Initialized\"),\n    PH_STRINGREF_INIT(L\"Ready\"),\n    PH_STRINGREF_INIT(L\"Running\"),\n    PH_STRINGREF_INIT(L\"Standby\"),\n    PH_STRINGREF_INIT(L\"Terminated\"),\n    PH_STRINGREF_INIT(L\"Waiting\"),\n    PH_STRINGREF_INIT(L\"Transition\"),\n    PH_STRINGREF_INIT(L\"DeferredReady\"),\n    PH_STRINGREF_INIT(L\"GateWait\"),\n    PH_STRINGREF_INIT(L\"WaitingForProcessInSwap\"),\n};\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhKWaitReasonNames[] =\n{\n    PH_STRINGREF_INIT(L\"Executive\"),\n    PH_STRINGREF_INIT(L\"FreePage\"),\n    PH_STRINGREF_INIT(L\"PageIn\"),\n    PH_STRINGREF_INIT(L\"PoolAllocation\"),\n    PH_STRINGREF_INIT(L\"DelayExecution\"),\n    PH_STRINGREF_INIT(L\"Suspended\"),\n    PH_STRINGREF_INIT(L\"UserRequest\"),\n    PH_STRINGREF_INIT(L\"WrExecutive\"),\n    PH_STRINGREF_INIT(L\"WrFreePage\"),\n    PH_STRINGREF_INIT(L\"WrPageIn\"),\n    PH_STRINGREF_INIT(L\"WrPoolAllocation\"),\n    PH_STRINGREF_INIT(L\"WrDelayExecution\"),\n    PH_STRINGREF_INIT(L\"WrSuspended\"),\n    PH_STRINGREF_INIT(L\"WrUserRequest\"),\n    PH_STRINGREF_INIT(L\"WrEventPair\"),\n    PH_STRINGREF_INIT(L\"WrQueue\"),\n    PH_STRINGREF_INIT(L\"WrLpcReceive\"),\n    PH_STRINGREF_INIT(L\"WrLpcReply\"),\n    PH_STRINGREF_INIT(L\"WrVirtualMemory\"),\n    PH_STRINGREF_INIT(L\"WrPageOut\"),\n    PH_STRINGREF_INIT(L\"WrRendezvous\"),\n    PH_STRINGREF_INIT(L\"WrKeyedEvent\"),\n    PH_STRINGREF_INIT(L\"WrTerminated\"),\n    PH_STRINGREF_INIT(L\"WrProcessInSwap\"),\n    PH_STRINGREF_INIT(L\"WrCpuRateControl\"),\n    PH_STRINGREF_INIT(L\"WrCalloutStack\"),\n    PH_STRINGREF_INIT(L\"WrKernel\"),\n    PH_STRINGREF_INIT(L\"WrResource\"),\n    PH_STRINGREF_INIT(L\"WrPushLock\"),\n    PH_STRINGREF_INIT(L\"WrMutex\"),\n    PH_STRINGREF_INIT(L\"WrQuantumEnd\"),\n    PH_STRINGREF_INIT(L\"WrDispatchInt\"),\n    PH_STRINGREF_INIT(L\"WrPreempted\"),\n    PH_STRINGREF_INIT(L\"WrYieldExecution\"),\n    PH_STRINGREF_INIT(L\"WrFastMutex\"),\n    PH_STRINGREF_INIT(L\"WrGuardedMutex\"),\n    PH_STRINGREF_INIT(L\"WrRundown\"),\n    PH_STRINGREF_INIT(L\"WrAlertByThreadId\"),\n    PH_STRINGREF_INIT(L\"WrDeferredPreempt\"),\n    PH_STRINGREF_INIT(L\"WrPhysicalFault\"),\n    PH_STRINGREF_INIT(L\"WrIoRing\"),\n    PH_STRINGREF_INIT(L\"WrMdlCache\"),\n    PH_STRINGREF_INIT(L\"WrRcu\"),\n};\n\nstatic_assert(ARRAYSIZE(PhIoPriorityHintNames) == MaxIoPriorityTypes, \"PhIoPriorityHintNames must equal MaxIoPriorityTypes\");\nstatic_assert(ARRAYSIZE(PhPagePriorityNames) == MEMORY_PRIORITY_NORMAL + 1, \"PhPagePriorityNames must equal MEMORY_PRIORITY\");\nstatic_assert(ARRAYSIZE(PhKThreadStateNames) == MaximumThreadState, \"PhKThreadStateNames must equal MaximumThreadState\");\nstatic_assert(ARRAYSIZE(PhKWaitReasonNames) == MaximumWaitReason, \"PhKWaitReasonNames must equal MaximumWaitReason\");\n\n// File aliases (Windows 11 25H2)\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhHalFileAliasList[] =\n{\n    PH_STRINGREF_INIT(L\"hal.dll\"),\n    PH_STRINGREF_INIT(L\"halaacpi.dll\"),\n    PH_STRINGREF_INIT(L\"halacpi.dll\"),\n    PH_STRINGREF_INIT(L\"halapic.dll\"),\n    PH_STRINGREF_INIT(L\"halmacpi.dll\"),\n    PH_STRINGREF_INIT(L\"halmps.dll\"),\n    PH_STRINGREF_INIT(L\"hal486c.dll\"),\n    PH_STRINGREF_INIT(L\"halborg.dll\"),\n    PH_STRINGREF_INIT(L\"halsp.dll\"),\n    PH_STRINGREF_INIT(L\"halomap.dll\"),\n    PH_STRINGREF_INIT(L\"halomap4.dll\"),\n    PH_STRINGREF_INIT(L\"haltegra2.dll\"),\n};\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhKernelFileAliasList[] =\n{\n    PH_STRINGREF_INIT(L\"ntkrnlmp.exe\"),\n    PH_STRINGREF_INIT(L\"ntoskrnl.exe\"),\n    PH_STRINGREF_INIT(L\"ntkrnlup.exe\"),\n    PH_STRINGREF_INIT(L\"ntkrnlpa.exe\"),\n    PH_STRINGREF_INIT(L\"ntkrpamp.exe\"),\n    PH_STRINGREF_INIT(L\"xboxkrnlc.exe\"),\n};\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhSecureKernelFileAliasList[] =\n{\n    PH_STRINGREF_INIT(L\"securekernel.exe\"),\n    PH_STRINGREF_INIT(L\"securekernella57.exe\"),\n};\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhHypervisorFileAliasList[] =\n{\n    PH_STRINGREF_INIT(L\"hvix64.exe\"),\n    PH_STRINGREF_INIT(L\"hvax64.exe\"),\n    PH_STRINGREF_INIT(L\"hvaa64.exe\"),\n};\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhOsLoaderFileAliasList[] =\n{\n    PH_STRINGREF_INIT(L\"winload.efi\"),\n    PH_STRINGREF_INIT(L\"winload_prod.efi\"),\n};\n\nDECLSPEC_SELECTANY CONST\nPH_STRINGREF PhOsBootFileAliasList[] =\n{\n    PH_STRINGREF_INIT(L\"bootmgfw.efi\"),\n    PH_STRINGREF_INIT(L\"bootaa64.efi\"),\n    PH_STRINGREF_INIT(L\"bootarm.efi\"),\n    PH_STRINGREF_INIT(L\"bootmgr.efi\"),\n    PH_STRINGREF_INIT(L\"bootia32.efi\"),\n};\n"
  },
  {
    "path": "phlib/directdraw.cpp",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2022-2023\n *\n */\n\n#include <ph.h>\n#include <guisup.h>\n#include <settings.h>\n\n#define GDIPVER 0x0110\n#include <unknwn.h>\n//#include <wtypes.h>\n#include <gdiplus.h>\n\nusing namespace Gdiplus;\n\n//std::unique_ptr<Bitmap> make_bitmap(\n//    _In_ LONG Width,\n//    _In_ LONG Height,\n//    _In_ PixelFormat Format\n//    )\n//{\n//    return std::make_unique<Bitmap>(Width, Height, Format);\n//}\n//\n//std::unique_ptr<Bitmap> make_bitmap(\n//    _In_ LONG Width,\n//    _In_ LONG Height,\n//    _In_ LONG Stride,\n//    _In_ PixelFormat Format,\n//    _In_reads_opt_(_Inexpressible_(\"height * stride\")) PBYTE Buffer\n//    )\n//{\n//    return std::make_unique<Bitmap>(Width, Height, Stride, Format, Buffer);\n//}\n//\n//std::unique_ptr<Graphics> make_graphics(\n//    _In_ const std::unique_ptr<Bitmap>& image\n//    )\n//{\n//    return std::unique_ptr<Graphics>(Graphics::FromImage(image.get()));\n//}\n\nBOOLEAN PhInitializeGDIPlus(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOLEAN initialized = FALSE;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        static ULONG_PTR gdiplusToken = 0;\n        static GdiplusStartupInput gdiplusStartupInput = { nullptr, false, true };\n\n        if (GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr) == Status::Ok)\n        {\n            initialized = TRUE;\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return initialized;\n}\n\nstatic Bitmap* PhGdiplusCreateBitmapFromDIB(\n    _In_ HBITMAP OriginalBitmap\n    )\n{\n    DIBSECTION dib = {};\n\n    if (GetObject(OriginalBitmap, sizeof(DIBSECTION), &dib) == sizeof(DIBSECTION))\n    {\n        LONG width = dib.dsBmih.biWidth;\n        LONG height = dib.dsBmih.biHeight;\n        LONG pitch = dib.dsBm.bmWidthBytes;\n        BYTE* bitmapBuffer = static_cast<BYTE*>(dib.dsBm.bmBits);\n\n        return new Bitmap(width, height, pitch, PixelFormat32bppARGB, bitmapBuffer);\n    }\n\n    return nullptr;\n}\n\n// Note: This function is used to draw bitmaps with the current accent color\n// as the background of the bitmap similar to what Task Manager does (dmex)\nHICON PhGdiplusConvertBitmapToIcon(\n    _In_ HBITMAP OriginalBitmap,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_ COLORREF Background\n    )\n{\n    HICON icon;\n\n    if (PhInitializeGDIPlus())\n    {\n        DIBSECTION dib;\n\n        RtlZeroMemory(&dib, sizeof(DIBSECTION));\n\n        if (GetObject(OriginalBitmap, sizeof(DIBSECTION), &dib) != sizeof(DIBSECTION))\n            return nullptr;\n\n        LONG width = dib.dsBmih.biWidth;\n        LONG height = dib.dsBmih.biHeight;\n        LONG pitch = dib.dsBm.bmWidthBytes;\n        BYTE* bitmapBuffer = static_cast<BYTE*>(dib.dsBm.bmBits);\n\n        Bitmap image(width, height, pitch, PixelFormat32bppARGB, bitmapBuffer);\n        Bitmap buffer(Width, Height, PixelFormat32bppARGB);\n        Graphics graphics(&buffer);\n\n        if (Background)\n        {\n            Color color(Color::DodgerBlue);\n            color.SetFromCOLORREF(Background);\n            graphics.Clear(color);\n        }\n        else\n        {\n            graphics.Clear(Color::DodgerBlue);\n        }\n\n        if (graphics.DrawImage(&image, 0, 0) == Status::Ok)\n        {\n            if (buffer.GetHICON(&icon) == Status::Ok)\n            {\n                return icon;\n            }\n        }\n    }\n\n    return nullptr;\n}\n\nHICON PhGdiplusConvertHBitmapToHIcon(\n    _In_ HBITMAP BitmapHandle\n    )\n{\n    HICON iconHandle = nullptr;\n\n    if (PhInitializeGDIPlus())\n    {\n        Bitmap bitmap(BitmapHandle, nullptr);\n\n        bitmap.GetHICON(&iconHandle);\n    }\n\n    return iconHandle;\n}\n\n\n#ifdef PHNT_TRANSPARENT_BITMAP\n#include <uxtheme.h>\n#pragma comment(lib, \"uxtheme.lib\")\n\nVOID PhUpdateTransparentBackgroundWindow(\n    _In_ HWND WindowHandle,\n    _In_ PRECT ClientRect\n    )\n{\n    HDC hdc;\n    SIZE windowSize;\n    POINT windowPoint = { 0, 0 };\n    BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };\n    BP_PAINTPARAMS paintParams = { sizeof(paintParams) };\n    HDC bufferHdc;\n    HPAINTBUFFER paintBuffer;\n\n    hdc = GetDC(WindowHandle);\n\n    windowSize.cx = ClientRect->right - ClientRect->left;\n    windowSize.cy = ClientRect->bottom - ClientRect->top;\n\n    paintParams.dwFlags = BPPF_ERASE; // Clear rectangle to ARGB 0,0,0,0\n    paintParams.pBlendFunction = &blendFunction;\n\n    if (paintBuffer = BeginBufferedPaint(hdc, ClientRect, BPBF_TOPDOWNDIB, &paintParams, &bufferHdc))\n    {\n        BufferedPaintSetAlpha(paintBuffer, ClientRect, 128);\n\n        UpdateLayeredWindow(\n            WindowHandle,\n            nullptr,\n            &windowPoint,\n            &windowSize,\n            bufferHdc,\n            &windowPoint,\n            0,\n            &blendFunction,\n            ULW_ALPHA\n            );\n\n        EndBufferedPaint(paintBuffer, FALSE);\n    }\n    else\n    {\n        static PH_INITONCE initOnce = PH_INITONCE_INIT;\n        static BOOLEAN initialized = FALSE;\n        HBITMAP bitmapHandle;\n        HGDIOBJ oldBitmapHandle;\n\n        if (PhBeginInitOnce(&initOnce))\n        {\n            ULONG_PTR gdiplusToken = 0;\n            GdiplusStartupInput gdiplusStartupInput{};\n\n            if (GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr) == Status::Ok)\n            {\n                initialized = TRUE;\n            }\n\n            PhEndInitOnce(&initOnce);\n        }\n\n        bufferHdc = CreateCompatibleDC(hdc);\n        bitmapHandle = CreateCompatibleBitmap(hdc, ClientRect->right, ClientRect->bottom);\n        oldBitmapHandle = SelectBitmap(bufferHdc, bitmapHandle);\n\n        if (initialized)\n        {\n            Graphics graphics(bufferHdc);\n            graphics.Clear(Color(128, 0, 0, 0));\n        }\n\n        UpdateLayeredWindow(\n            WindowHandle,\n            nullptr,\n            &windowPoint,\n            &windowSize,\n            bufferHdc,\n            &windowPoint,\n            0,\n            &blendFunction,\n            ULW_ALPHA\n            );\n\n        SelectBitmap(bufferHdc, oldBitmapHandle);\n        DeleteBitmap(bitmapHandle);\n        DeleteDC(bufferHdc);\n    }\n\n    ReleaseDC(WindowHandle, hdc);\n}\n#endif\n\nLRESULT CALLBACK PhTransparentBackgroundWindowCallback(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (WindowMessage)\n    {\n    case WM_CREATE:\n        {\n            LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);\n\n            if (PhGetIntegerSetting(L\"EnableStreamerMode\"))\n            {\n                SetWindowDisplayAffinity(WindowHandle, WDA_EXCLUDEFROMCAPTURE);\n            }\n\n            if (createStruct->hwndParent)\n            {\n                HMENU menu = GetMenu(createStruct->hwndParent);\n\n                if (menu)\n                {\n                    PhSetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT, menu);\n                    SetMenu(createStruct->hwndParent, nullptr);\n                }\n            }\n\n#ifdef PHNT_TRANSPARENT_BITMAP\n            RECT clientRect;\n\n            clientRect.left = 0;\n            clientRect.top = 0;\n            clientRect.right = createStruct->cx;\n            clientRect.bottom = createStruct->cy;\n\n            PhUpdateTransparentBackgroundWindow(WindowHandle, &clientRect);\n#else\n            constexpr ULONG OpacityPercent = 50;\n\n            // The opacity value is backwards - 0 means opaque, 100 means transparent.\n            SetLayeredWindowAttributes(\n                WindowHandle,\n                0,\n                static_cast<BYTE>(255 * (100 - OpacityPercent) / 100),\n                LWA_ALPHA\n                );\n#endif\n        }\n        break;\n    case WM_DESTROY:\n        {\n            HMENU menu = static_cast<HMENU>(PhGetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT));\n\n            if (menu)\n            {\n                SetMenu(GetParent(WindowHandle), menu);\n            }\n\n            PhRemoveWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT);\n        }\n        break;\n#ifndef PHNT_TRANSPARENT_BITMAP\n    case WM_ERASEBKGND:\n        {\n            HDC hdc = reinterpret_cast<HDC>(wParam);\n            RECT clientRect;\n\n            if (!PhGetClientRect(WindowHandle, &clientRect))\n                break;\n\n            FillRect(hdc, &clientRect, PhGetStockBrush(BLACK_BRUSH));\n        }\n        return TRUE;\n#endif\n    }\n\n    return DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n}\n\nRTL_ATOM PhInitializeBackgroundWindowClass(\n    VOID\n    )\n{\n    WNDCLASSEX wcex;\n\n    memset(&wcex, 0, sizeof(WNDCLASSEX));\n    wcex.cbSize = sizeof(WNDCLASSEX);\n    wcex.lpfnWndProc = PhTransparentBackgroundWindowCallback;\n    wcex.hCursor = PhLoadCursor(nullptr, IDC_ARROW);\n    wcex.lpszClassName = L\"TransparentBackgroundWindowClass\";\n\n    return RegisterClassEx(&wcex);\n}\n\nHWND PhCreateBackgroundWindow(\n    _In_ HWND ParentWindowHandle,\n    _In_ BOOLEAN DesktopWindow\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static RTL_ATOM windowAtom = 0;\n    HWND windowHandle;\n    RECT windowRect = { 0 };\n\n    if (WindowsVersion < WINDOWS_8)\n        return nullptr;\n\n    if (!PhGetClientRect(ParentWindowHandle, &windowRect))\n        return nullptr;\n\n    {\n        MENUBARINFO menuInfo;\n\n        memset(&menuInfo, 0, sizeof(MENUBARINFO));\n        menuInfo.cbSize = sizeof(MENUBARINFO);\n\n        if (GetMenuBarInfo(ParentWindowHandle, OBJID_MENU, 0, &menuInfo))\n        {\n            windowRect.bottom += menuInfo.rcBar.bottom;\n        }\n    }\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        windowAtom = PhInitializeBackgroundWindowClass();\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (windowAtom == INVALID_ATOM)\n        return nullptr;\n\n    windowHandle = CreateWindowEx(\n#ifdef PHNT_TRANSPARENT_BITMAP\n        WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP,\n#else\n        WS_EX_LAYERED,\n#endif\n        MAKEINTATOM(windowAtom),\n        nullptr,\n        DesktopWindow ? WS_POPUPWINDOW : WS_CHILD,\n        0,\n        0,\n        windowRect.right,\n        windowRect.bottom,\n        DesktopWindow ? nullptr : ParentWindowHandle,\n        nullptr,\n        nullptr,\n        nullptr\n        );\n\n    SetWindowPos(\n        windowHandle,\n        HWND_TOP,\n        0,\n        0,\n        0,\n        0,\n        SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW\n        );\n\n    return windowHandle;\n}\n\n//#pragma comment(lib, \"d2d1.lib\")\n//#pragma comment(lib, \"dwrite.lib\")\n//\n//#include <d2d1.h>\n//#include <dwrite.h>\n//#include <d2d1_3.h>\n//\n//static IDWriteTextFormat* PhDirectWriteTextFormat = nullptr;\n//static ID2D1DCRenderTarget* PhDirectWriteRenderTarget = nullptr;\n//static ID2D1SolidColorBrush* PhDirectWriteSolidBrush = nullptr;\n//\n//BOOLEAN PhCreateDirectWriteTextResources(\n//    VOID\n//    )\n//{\n//    D2D1_RENDER_TARGET_PROPERTIES render_target_properties =\n//    {\n//        .type = D2D1_RENDER_TARGET_TYPE_SOFTWARE,\n//        .pixelFormat =\n//        {\n//            .format = DXGI_FORMAT_B8G8R8A8_UNORM,\n//            .alphaMode = D2D1_ALPHA_MODE_IGNORE, // D2D1_ALPHA_MODE_PREMULTIPLIED\n//        },\n//        .dpiX = 0, .dpiY = 0,\n//        .usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,\n//        .minLevel = D2D1_FEATURE_LEVEL_DEFAULT\n//    };\n//    HRESULT status;\n//    ID2D1Factory* directFactory = nullptr;\n//    IDWriteFactory* dwriteFactory = nullptr;\n//\n//    status = DWriteCreateFactory(\n//        DWRITE_FACTORY_TYPE_SHARED,\n//        __uuidof(IDWriteFactory),\n//        reinterpret_cast<IUnknown**>(&dwriteFactory)\n//        );\n//\n//    if (FAILED(status))\n//        return FALSE;\n//\n//    status = dwriteFactory->CreateTextFormat(\n//        L\"Segoe UI\",\n//        nullptr,\n//        DWRITE_FONT_WEIGHT_NORMAL,\n//        DWRITE_FONT_STYLE_NORMAL,\n//        DWRITE_FONT_STRETCH_NORMAL,\n//        12,\n//        L\"\", // locale\n//        &PhDirectWriteTextFormat\n//        );\n//\n//    if (FAILED(status))\n//        return FALSE;\n//\n//    status = D2D1CreateFactory(\n//        D2D1_FACTORY_TYPE_SINGLE_THREADED,\n//        reinterpret_cast<IUnknown**>(&directFactory)\n//        );\n//\n//    if (FAILED(status))\n//        return FALSE;\n//\n//    status = directFactory->CreateDCRenderTarget(\n//        &render_target_properties,\n//        &PhDirectWriteRenderTarget\n//        );\n//\n//    if (FAILED(status))\n//        return FALSE;\n//\n//    status = PhDirectWriteRenderTarget->CreateSolidColorBrush(\n//        D2D1::ColorF(D2D1::ColorF::Black, 1.0f),\n//        &PhDirectWriteSolidBrush\n//        );\n//\n//    if (FAILED(status))\n//        return FALSE;\n//\n//    return TRUE;\n//}\n//\n//VOID DirectWriteDrawText(\n//    _In_ HDC Hdc,\n//    _In_ PRECT ClientRect,\n//    _In_ PWSTR Text,\n//    _In_ SIZE_T TextLength\n//    )\n//{\n//    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n//\n//    if (PhBeginInitOnce(&initOnce))\n//    {\n//        PhCreateDirectWriteTextResources();\n//        PhEndInitOnce(&initOnce);\n//    }\n//\n//    if (FAILED(PhDirectWriteRenderTarget->BindDC(Hdc, ClientRect)))\n//        return;\n//\n//    PhDirectWriteRenderTarget->BeginDraw();\n//    PhDirectWriteRenderTarget->DrawText(\n//        Text,\n//        static_cast<UINT32>(TextLength),\n//        PhDirectWriteTextFormat,\n//        D2D1::RectF(0, 0, static_cast<FLOAT>(ClientRect->right), static_cast<FLOAT>(ClientRect->bottom)),\n//        PhDirectWriteSolidBrush,\n//        D2D1_DRAW_TEXT_OPTIONS_CLIP,\n//        DWRITE_MEASURING_MODE_GDI_CLASSIC\n//        );\n//    PhDirectWriteRenderTarget->EndDraw();\n//}\n"
  },
  {
    "path": "phlib/dspick.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *\n */\n\n#include <ph.h>\n#include <dspick.h>\n#include <lsasup.h>\n\n#include <ole2.h>\n#include <objsel.h>\n\n//#define IDataObject_AddRef(This) ((This)->lpVtbl->AddRef(This))\n//#define IDataObject_Release(This) ((This)->lpVtbl->Release(This))\n//#define IDataObject_GetData(This, pformatetcIn, pmedium) ((This)->lpVtbl->GetData(This, pformatetcIn, pmedium))\n\n#define IDsObjectPicker_QueryInterface(This, riid, ppvObject) ((This)->lpVtbl->QueryInterface(This, riid, ppvObject))\n#define IDsObjectPicker_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IDsObjectPicker_Release(This) ((This)->lpVtbl->Release(This))\n#define IDsObjectPicker_Initialize(This, pInitInfo) ((This)->lpVtbl->Initialize(This, pInitInfo))\n#define IDsObjectPicker_InvokeDialog(This, hwndParent, ppdoSelections) ((This)->lpVtbl->InvokeDialog(This, hwndParent, ppdoSelections))\n\nIDsObjectPicker *PhpCreateDsObjectPicker(\n    VOID\n    )\n{\n    IDsObjectPicker *picker;\n\n    if (SUCCEEDED(PhGetClassObject(\n        L\"objsel.dll\",\n        &CLSID_DsObjectPicker,\n        &IID_IDsObjectPicker,\n        &picker\n        )))\n    {\n        return picker;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\nVOID PhFreeDsObjectPickerDialog(\n    _In_ PVOID PickerDialog\n    )\n{\n    IDsObjectPicker_Release((IDsObjectPicker *)PickerDialog);\n}\n\nPVOID PhCreateDsObjectPickerDialog(\n    _In_ ULONG Flags\n    )\n{\n    IDsObjectPicker *picker;\n    DSOP_INIT_INFO initInfo;\n    DSOP_SCOPE_INIT_INFO scopeInit[1];\n\n    picker = PhpCreateDsObjectPicker();\n\n    if (!picker)\n        return NULL;\n\n    memset(scopeInit, 0, sizeof(scopeInit));\n\n    scopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);\n    scopeInit[0].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER;\n    scopeInit[0].flScope =\n        DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT |\n        DSOP_SCOPE_FLAG_WANT_SID_PATH |\n        DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS |\n        DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;\n    scopeInit[0].FilterFlags.Uplevel.flBothModes =\n        DSOP_FILTER_INCLUDE_ADVANCED_VIEW |\n        DSOP_FILTER_USERS |\n        DSOP_FILTER_BUILTIN_GROUPS |\n        DSOP_FILTER_WELL_KNOWN_PRINCIPALS;\n    scopeInit[0].FilterFlags.flDownlevel =\n        DSOP_DOWNLEVEL_FILTER_USERS |\n        DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS |\n        DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS |\n        DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS;\n\n    memset(&initInfo, 0, sizeof(DSOP_INIT_INFO));\n    initInfo.cbSize = sizeof(DSOP_INIT_INFO);\n    initInfo.pwzTargetComputer = NULL;\n    initInfo.cDsScopeInfos = 1;\n    initInfo.aDsScopeInfos = scopeInit;\n    initInfo.flOptions = DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK;\n\n    if (Flags & PH_DSPICK_MULTISELECT)\n        initInfo.flOptions |= DSOP_FLAG_MULTISELECT;\n\n    if (!SUCCEEDED(IDsObjectPicker_Initialize(picker, &initInfo)))\n    {\n        IDsObjectPicker_Release(picker);\n        return NULL;\n    }\n\n    return picker;\n}\n\nPDS_SELECTION_LIST PhpGetDsSelectionList(\n    _In_ IDataObject *Selections\n    )\n{\n    FORMATETC format;\n    STGMEDIUM medium;\n\n    format.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(L\"CFSTR_DSOP_DS_SELECTION_LIST\");\n    format.ptd = NULL;\n    format.dwAspect = ULONG_MAX;\n    format.lindex = -1;\n    format.tymed = TYMED_HGLOBAL;\n\n    if (SUCCEEDED(IDataObject_GetData(Selections, &format, &medium)))\n    {\n        if (medium.tymed != TYMED_HGLOBAL)\n            return NULL;\n\n        return (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal);\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\n_Success_(return)\nBOOLEAN PhShowDsObjectPickerDialog(\n    _In_ HWND hWnd,\n    _In_ PVOID PickerDialog,\n    _Out_ PPH_DSPICK_OBJECTS *Objects\n    )\n{\n    IDsObjectPicker *picker;\n    IDataObject *dataObject;\n    PDS_SELECTION_LIST selections;\n    PPH_DSPICK_OBJECTS objects;\n    ULONG i;\n\n    picker = (IDsObjectPicker *)PickerDialog;\n\n    if (!SUCCEEDED(IDsObjectPicker_InvokeDialog(picker, hWnd, &dataObject)))\n        return FALSE;\n\n    if (!dataObject)\n        return FALSE;\n\n    selections = PhpGetDsSelectionList(dataObject);\n    IDataObject_Release(dataObject);\n\n    if (!selections)\n        return FALSE;\n\n    objects = PhAllocate(\n        FIELD_OFFSET(PH_DSPICK_OBJECTS, Objects) +\n        selections->cItems * sizeof(PH_DSPICK_OBJECT)\n        );\n\n    objects->NumberOfObjects = selections->cItems;\n\n    for (i = 0; i < selections->cItems; i++)\n    {\n        PDS_SELECTION selection;\n        PSID sid;\n        PH_STRINGREF path;\n        PH_STRINGREF prefix;\n\n        selection = &selections->aDsSelection[i];\n\n        objects->Objects[i].Name = PhCreateString(selection->pwzName);\n        objects->Objects[i].Sid = NULL;\n\n        if (selection->pwzADsPath && selection->pwzADsPath[0] != 0)\n        {\n            PhInitializeStringRef(&path, selection->pwzADsPath);\n            PhInitializeStringRef(&prefix, L\"LDAP://<SID=\");\n\n            if (PhStartsWithStringRef(&path, &prefix, TRUE))\n            {\n                PhSkipStringRef(&path, prefix.Length);\n                path.Length -= sizeof(WCHAR); // Ignore \">\" at end\n\n                sid = PhAllocate(path.Length / sizeof(WCHAR) / 2);\n\n                if (PhHexStringToBuffer(&path, (PUCHAR)sid))\n                {\n                    if (PhValidSid(sid))\n                        objects->Objects[i].Sid = sid;\n                    else\n                        PhFree(sid);\n                }\n                else\n                {\n                    PhFree(sid);\n                }\n            }\n        }\n        else\n        {\n            // Try to get the SID.\n            PhLookupName(&objects->Objects[i].Name->sr, &objects->Objects[i].Sid, NULL, NULL);\n        }\n    }\n\n    *Objects = objects;\n\n    return TRUE;\n}\n\nVOID PhFreeDsObjectPickerObjects(\n    _In_ PPH_DSPICK_OBJECTS Objects\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Objects->NumberOfObjects; i++)\n    {\n        PhDereferenceObject(Objects->Objects[i].Name);\n\n        if (Objects->Objects[i].Sid)\n            PhFree(Objects->Objects[i].Sid);\n    }\n\n    PhFree(Objects);\n}\n"
  },
  {
    "path": "phlib/emenu.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *     dmex    2019-2023\n *\n */\n\n#include <ph.h>\n#include <emenu.h>\n#include <guisup.h>\n\nstatic const PH_FLAG_MAPPING EMenuTypeMappings[] =\n{\n    { PH_EMENU_MENUBARBREAK, MFT_MENUBARBREAK },\n    { PH_EMENU_MENUBREAK, MFT_MENUBREAK },\n    { PH_EMENU_RADIOCHECK, MFT_RADIOCHECK },\n    { PH_EMENU_RIGHTORDER, MFT_RIGHTORDER },\n};\n\nstatic const PH_FLAG_MAPPING EMenuStateMappings[] =\n{\n    { PH_EMENU_CHECKED, MFS_CHECKED },\n    { PH_EMENU_DEFAULT, MFS_DEFAULT },\n    { PH_EMENU_DISABLED, MFS_DISABLED },\n    { PH_EMENU_HIGHLIGHT, MFS_HILITE }\n};\n\n/**\n * Creates a menu item.\n *\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_DISABLED The menu item is greyed and cannot be selected.\n * \\li \\c PH_EMENU_CHECKED A check mark is displayed.\n * \\li \\c PH_EMENU_HIGHLIGHT The menu item is highlighted.\n * \\li \\c PH_EMENU_MENUBARBREAK Places the menu item in a new column, separated by a vertical line.\n * \\li \\c PH_EMENU_MENUBREAK Places the menu item in a new column, with no vertical line.\n * \\li \\c PH_EMENU_DEFAULT The menu item is displayed as the default item. This causes the text to\n * be bolded.\n * \\li \\c PH_EMENU_RADIOCHECK Uses a radio-button mark instead of a check mark.\n * \\param Id A unique identifier for the menu item.\n * \\param Text The text displayed for the menu item.\n * \\param Bitmap A bitmap image for the menu item.\n * \\param Context A user-defined value.\n */\nPPH_EMENU_ITEM PhCreateEMenuItem(\n    _In_ ULONG Flags,\n    _In_ ULONG Id,\n    _In_opt_ PCWSTR Text,\n    _In_opt_ HBITMAP Bitmap,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_EMENU_ITEM item;\n\n    item = PhAllocate(sizeof(PH_EMENU_ITEM));\n    memset(item, 0, sizeof(PH_EMENU_ITEM));\n\n    item->Flags = Flags;\n    item->Id = Id;\n    item->Text = (PWSTR)Text;\n    item->Bitmap = Bitmap;\n    item->Context = Context;\n\n    return item;\n}\n\nPPH_EMENU_ITEM PhCreateEMenuItemCallback(\n    _In_ ULONG Flags,\n    _In_ ULONG Id,\n    _In_opt_ PCWSTR Text,\n    _In_opt_ HBITMAP Bitmap,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_EMENU_ITEM_DELAY_FUNCTION DelayFunction\n    )\n{\n    PPH_EMENU_ITEM item;\n    PPH_EMENU_ITEM delay;\n\n    item = PhAllocateZero(sizeof(PH_EMENU_ITEM));\n    item->Flags = Flags;\n    item->Id = Id;\n    item->Text = (PWSTR)Text;\n    item->Bitmap = Bitmap;\n    item->Context = Context;\n    item->DelayFunction = DelayFunction;\n\n    delay = PhCreateEMenuItem(0, USHRT_MAX, L\" \", NULL, NULL);\n    PhInsertEMenuItem(item, delay, ULONG_MAX);\n\n    return item;\n}\n\n/**\n * Frees resources used by a menu item and its children.\n *\n * \\param Item The menu item.\n * \\remarks The menu item is NOT automatically removed from its parent. It is safe to call this\n * function while enumerating menu items.\n */\nVOID PhpDestroyEMenuItem(\n    _In_ _Post_invalid_ PPH_EMENU_ITEM Item\n    )\n{\n    if (Item->DeleteFunction)\n        Item->DeleteFunction(Item);\n\n    if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text)\n        PhFree(Item->Text);\n    if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap)\n        DeleteBitmap(Item->Bitmap);\n\n    if (Item->Items)\n    {\n        for (ULONG i = 0; i < Item->Items->Count; i++)\n            PhpDestroyEMenuItem(PhItemList(Item->Items, i));\n\n        PhDereferenceObject(Item->Items);\n    }\n\n    PhFree(Item);\n}\n\n/**\n * Frees resources used by a menu item and its children.\n *\n * \\param Item The menu item.\n * \\remarks The menu item is automatically removed from its parent.\n */\nVOID PhDestroyEMenuItem(\n    _In_ _Post_invalid_ PPH_EMENU_ITEM Item\n    )\n{\n    // Remove the item from its parent, if it has one.\n    if (Item->Parent)\n        PhRemoveEMenuItem(NULL, Item, ULONG_MAX);\n\n    PhpDestroyEMenuItem(Item);\n}\n\n/**\n * Finds a child menu item.\n *\n * \\param Item The parent menu item.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_FIND_DESCEND Searches recursively within child menu items.\n * \\li \\c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search.\n * \\li \\c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters\n * (ampersands).\n * \\param Text The text of the menu item to find. If NULL, the text is ignored.\n * \\param Id The identifier of the menu item to find. If 0, the identifier is ignored.\n * \\return The found menu item, or NULL if the menu item could not be found.\n */\n_Use_decl_annotations_\nPPH_EMENU_ITEM PhFindEMenuItem(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Flags,\n    _In_opt_ PCWSTR Text,\n    _In_ ULONG Id\n    )\n{\n    return PhFindEMenuItemEx(Item, Flags, Text, Id, NULL, NULL);\n}\n\n/**\n * Finds a child menu item.\n *\n * \\param Item The parent menu item.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_FIND_DESCEND Searches recursively within child menu items.\n * \\li \\c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search.\n * \\li \\c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters\n * (ampersands).\n * \\param Text The text of the menu item to find. If NULL, the text is ignored.\n * \\param Id The identifier of the menu item to find. If 0, the identifier is ignored.\n * \\param FoundParent A variable which receives the parent of the found menu item.\n * \\param FoundIndex A variable which receives the index of the found menu item.\n * \\return The found menu item, or NULL if the menu item could not be found.\n */\n_Use_decl_annotations_\nPPH_EMENU_ITEM PhFindEMenuItemEx(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Flags,\n    _In_opt_ PCWSTR Text,\n    _In_ ULONG Id,\n    _Out_opt_ PPH_EMENU_ITEM *FoundParent,\n    _Out_opt_ PULONG FoundIndex\n    )\n{\n    PH_STRINGREF searchText;\n    ULONG i;\n    PPH_EMENU_ITEM item;\n\n    if (!Item->Items)\n        return NULL;\n\n    if (Text && (Flags & PH_EMENU_FIND_LITERAL))\n        PhInitializeStringRefLongHint(&searchText, Text);\n\n    for (i = 0; i < Item->Items->Count; i++)\n    {\n        item = PhItemList(Item->Items, i);\n\n        if (Text)\n        {\n            if (Flags & PH_EMENU_FIND_LITERAL)\n            {\n                PH_STRINGREF text;\n\n                PhInitializeStringRefLongHint(&text, item->Text);\n\n                if (Flags & PH_EMENU_FIND_STARTSWITH)\n                {\n                    if (PhStartsWithStringRef(&text, &searchText, TRUE))\n                        goto FoundItemHere;\n                }\n                else\n                {\n                    if (PhEqualStringRef(&text, &searchText, TRUE))\n                        goto FoundItemHere;\n                }\n            }\n            else\n            {\n                if (PhCompareUnicodeStringZIgnoreMenuPrefix(\n                    Text,\n                    item->Text,\n                    TRUE,\n                    !!(Flags & PH_EMENU_FIND_STARTSWITH\n                    )) == 0)\n                {\n                    goto FoundItemHere;\n                }\n            }\n        }\n\n        if (Id && item->Id == Id)\n            goto FoundItemHere;\n\n        if (Flags & PH_EMENU_FIND_DESCEND)\n        {\n            PPH_EMENU_ITEM foundItem = NULL;\n            PPH_EMENU_ITEM foundParent = NULL;\n            ULONG foundIndex = 0;\n\n            foundItem = PhFindEMenuItemEx(item, Flags, Text, Id, &foundParent, &foundIndex);\n\n            if (foundItem)\n            {\n                if (FoundParent)\n                    *FoundParent = foundParent;\n                if (FoundIndex)\n                    *FoundIndex = foundIndex;\n\n                return foundItem;\n            }\n        }\n    }\n\n    return NULL;\n\nFoundItemHere:\n    if (FoundParent)\n        *FoundParent = Item;\n    if (FoundIndex)\n        *FoundIndex = i;\n\n    return item;\n}\n\n/**\n * Determines the index of a menu item.\n *\n * \\param Parent The parent menu item.\n * \\param Item The child menu item.\n *\n * \\return The index of the menu item, or -1 if the menu item was not found in the parent menu item.\n */\nULONG PhIndexOfEMenuItem(\n    _In_ PPH_EMENU_ITEM Parent,\n    _In_ PPH_EMENU_ITEM Item\n    )\n{\n    if (!Parent->Items)\n        return ULONG_MAX;\n\n    return PhFindItemList(Parent->Items, Item);\n}\n\n/**\n * Inserts a menu item into a parent menu item.\n *\n * \\param Parent The parent menu item.\n * \\param Item The menu item to insert.\n * \\param Index The index at which to insert the menu item. If the index is too large, the menu item\n * is inserted at the last position.\n */\nVOID PhInsertEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Parent,\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Index\n    )\n{\n    // Remove the item from its old parent if it has one.\n    if (Item->Parent)\n        PhRemoveEMenuItem(Item->Parent, Item, 0);\n\n    if (!Parent->Items)\n        Parent->Items = PhCreateList(5);\n\n    if (Index > Parent->Items->Count)\n        Index = Parent->Items->Count;\n\n    if (Index == ULONG_MAX)\n        PhAddItemList(Parent->Items, Item);\n    else\n        PhInsertItemList(Parent->Items, Index, Item);\n\n    Item->Parent = Parent;\n}\n\n/**\n * Removes a menu item from its parent.\n *\n * \\param Parent The parent menu item. If \\a Item is NULL, this parameter must be specified.\n * \\param Item The child menu item. This may be NULL if \\a Index is specified.\n * \\param Index The index of the menu item to remove. If \\a Item is specified, this parameter is\n * ignored.\n */\nBOOLEAN PhRemoveEMenuItem(\n    _Inout_opt_ PPH_EMENU_ITEM Parent,\n    _In_opt_ PPH_EMENU_ITEM Item,\n    _In_opt_ ULONG Index\n    )\n{\n    if (Item)\n    {\n        if (!Parent)\n            Parent = Item->Parent;\n        if (!Parent->Items)\n            return FALSE;\n\n        Index = PhFindItemList(Parent->Items, Item);\n\n        if (Index == ULONG_MAX)\n            return FALSE;\n    }\n    else\n    {\n        if (!Parent)\n            return FALSE;\n        if (!Parent->Items)\n            return FALSE;\n    }\n\n    Item = PhItemList(Parent->Items, Index);\n    PhRemoveItemList(Parent->Items, Index);\n    Item->Parent = NULL;\n\n    return TRUE;\n}\n\n/**\n * Removes all children from a menu item.\n *\n * \\param Parent The parent menu item.\n */\nVOID PhRemoveAllEMenuItems(\n    _Inout_ PPH_EMENU_ITEM Parent\n    )\n{\n    ULONG i;\n\n    if (!Parent->Items)\n        return;\n\n    for (i = 0; i < Parent->Items->Count; i++)\n    {\n        PhpDestroyEMenuItem(PhItemList(Parent->Items, i));\n    }\n\n    PhClearList(Parent->Items);\n}\n\n/**\n * Creates a root menu.\n */\nPPH_EMENU PhCreateEMenu(\n    VOID\n    )\n{\n    PPH_EMENU menu;\n\n    menu = PhAllocate(sizeof(PH_EMENU));\n    memset(menu, 0, sizeof(PH_EMENU));\n    menu->Items = PhCreateList(5);\n\n    return menu;\n}\n\n/**\n * Frees resources used by a root menu and its children.\n *\n * \\param Menu A root menu.\n */\nVOID PhDestroyEMenu(\n    _In_ PPH_EMENU Menu\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Menu->Items->Count; i++)\n    {\n        PhpDestroyEMenuItem(PhItemList(Menu->Items, i));\n    }\n\n    PhDereferenceObject(Menu->Items);\n    PhFree(Menu);\n}\n\n/**\n * Initializes a data structure containing additional information resulting from a call to\n * PhEMenuToHMenu().\n */\nVOID PhInitializeEMenuData(\n    _Out_ PPH_EMENU_DATA Data\n    )\n{\n    Data->IdToItem = PhCreateList(5);\n}\n\n/**\n * Frees resources used by a data structure initialized by PhInitializeEMenuData().\n */\nVOID PhDeleteEMenuData(\n    _Inout_ PPH_EMENU_DATA Data\n    )\n{\n    PhDereferenceObject(Data->IdToItem);\n}\n\n/**\n * Converts an EMENU to a Windows menu object.\n *\n * \\param Menu The menu item to convert.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item.\n * The resulting mappings are placed in \\a Data.\n * \\param Data Additional data resulting from the conversion. The data structure must be initialized\n * by PhInitializeEMenuData() prior to calling this function.\n *\n * \\return A menu handle. The menu object must be destroyed using DestroyMenu() when it is no longer\n * needed.\n */\nHMENU PhEMenuToHMenu(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG Flags,\n    _Inout_opt_ PPH_EMENU_DATA Data\n    )\n{\n    HMENU menuHandle;\n\n    if ((Menu->Flags & PH_EMENU_MAINMENU) == PH_EMENU_MAINMENU)\n    {\n        if (!(menuHandle = CreateMenu()))\n            return NULL;\n    }\n    else\n    {\n        if (!(menuHandle = CreatePopupMenu()))\n            return NULL;\n    }\n\n    PhEMenuToHMenu2(menuHandle, Menu, Flags, Data);\n\n    if (!(Menu->Flags & PH_EMENU_SEPARATECHECKSPACE))\n    {\n        MENUINFO menuInfo;\n\n        memset(&menuInfo, 0, sizeof(MENUINFO));\n        menuInfo.cbSize = sizeof(MENUINFO);\n        menuInfo.fMask = MIM_STYLE;\n        menuInfo.dwStyle = MNS_CHECKORBMP;\n\n        if ((WindowsVersion < WINDOWS_10_19H2 || PhEnableThemeAcrylicSupport) && PhEnableThemeSupport)\n        {\n            menuInfo.fMask |= MIM_BACKGROUND | MIM_APPLYTOSUBMENUS;\n            menuInfo.hbrBack = PhThemeWindowBackgroundBrush;\n        }\n\n        SetMenuInfo(menuHandle, &menuInfo);\n    }\n\n    return menuHandle;\n}\n\n/**\n * Converts an EMENU to a Windows menu object.\n *\n * \\param MenuHandle A handle to a Windows menu object.\n * \\param Menu The menu item to convert. The items are appended to \\a MenuHandle.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item.\n * The resulting mappings are placed in \\a Data.\n * \\param Data Additional data resulting from the conversion. The data structure must be initialized\n * by PhInitializeEMenuData() prior to calling this function.\n */\nVOID PhEMenuToHMenu2(\n    _In_ HMENU MenuHandle,\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG Flags,\n    _Inout_opt_ PPH_EMENU_DATA Data\n    )\n{\n    ULONG i;\n    PPH_EMENU_ITEM item;\n    MENUITEMINFO menuItemInfo;\n\n    for (i = 0; i < Menu->Items->Count; i++)\n    {\n        item = PhItemList(Menu->Items, i);\n\n        memset(&menuItemInfo, 0, sizeof(MENUITEMINFO));\n        menuItemInfo.cbSize = sizeof(MENUITEMINFO);\n\n        // Type\n\n        menuItemInfo.fMask = MIIM_FTYPE | MIIM_STATE;\n\n        if (FlagOn(item->Flags, PH_EMENU_SEPARATOR))\n        {\n            menuItemInfo.fType = MFT_SEPARATOR;\n        }\n        else\n        {\n            menuItemInfo.fType = MFT_STRING;\n            menuItemInfo.fMask |= MIIM_STRING;\n            menuItemInfo.dwTypeData = item->Text;\n        }\n\n        PhMapFlags1(\n            &menuItemInfo.fType,\n            item->Flags,\n            EMenuTypeMappings,\n            sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING)\n            );\n\n        // Bitmap\n\n        if (item->Bitmap)\n        {\n            menuItemInfo.hbmpItem = item->Bitmap;\n\n            if (WindowsVersion < WINDOWS_10_19H2)\n            {\n                if (!PhEnableThemeSupport)\n                {\n                    SetFlag(menuItemInfo.fMask, MIIM_BITMAP);\n                }\n            }\n            else\n            {\n                SetFlag(menuItemInfo.fMask, MIIM_BITMAP);\n            }\n        }\n\n        // Id\n\n        if (FlagOn(Flags, PH_EMENU_CONVERT_ID))\n        {\n            if (Data)\n            {\n                ULONG id;\n\n                PhAddItemList(Data->IdToItem, item);\n                id = Data->IdToItem->Count;\n\n                menuItemInfo.fMask |= MIIM_ID;\n                menuItemInfo.wID = id;\n            }\n        }\n        else\n        {\n            if (!FlagOn(Menu->Flags, PH_EMENU_SEPARATOR) && !FlagOn(Menu->Flags, PH_EMENU_MAINMENU))\n            {\n                if (item->Id)\n                {\n                    menuItemInfo.fMask |= MIIM_ID;\n                    menuItemInfo.wID = item->Id;\n                }\n            }\n        }\n\n        // State\n\n        PhMapFlags1(\n            &menuItemInfo.fState,\n            item->Flags,\n            EMenuStateMappings,\n            sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING)\n            );\n\n        // Context\n\n        menuItemInfo.fMask |= MIIM_DATA;\n        menuItemInfo.dwItemData = (ULONG_PTR)item;\n\n        // Submenu\n\n        if (item->Items && item->Items->Count != 0)\n        {\n            menuItemInfo.fMask |= MIIM_SUBMENU;\n            menuItemInfo.hSubMenu = PhEMenuToHMenu(item, Flags, Data);\n        }\n\n        // Themes\n        if (WindowsVersion < WINDOWS_10_19H2)\n        {\n            if (PhEnableThemeSupport)\n            {\n                SetFlag(menuItemInfo.fType, MFT_OWNERDRAW);\n            }\n        }\n        else\n        {\n            if (FlagOn(item->Flags, PH_EMENU_MAINMENU))\n            {\n                if (PhEnableThemeSupport)\n                {\n                    SetFlag(menuItemInfo.fType, MFT_OWNERDRAW);\n                }\n            }\n        }\n\n        if (FlagOn(Flags, PH_EMENU_RIGHTORDER))\n        {\n            SetFlag(menuItemInfo.fType, MFT_RIGHTORDER);\n        }\n\n        InsertMenuItem(MenuHandle, ULONG_MAX, TRUE, &menuItemInfo);\n    }\n}\n\n/**\n * Converts a Windows menu object to an EMENU.\n *\n * \\param MenuItem The menu item in which the converted menu items will be placed.\n * \\param MenuHandle A menu handle.\n */\nVOID PhHMenuToEMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem,\n    _In_ HMENU MenuHandle\n    )\n{\n    INT i;\n    INT count;\n\n    count = GetMenuItemCount(MenuHandle);\n\n    if (count == INT_ERROR)\n        return;\n\n    for (i = 0; i < count; i++)\n    {\n        MENUITEMINFO menuItemInfo;\n        PPH_EMENU_ITEM menuItem;\n        WCHAR buffer[MAX_PATH] = L\"\";\n\n        menuItemInfo.cbSize = sizeof(menuItemInfo);\n        menuItemInfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU;\n        menuItemInfo.cch = RTL_NUMBER_OF(buffer);\n        menuItemInfo.dwTypeData = buffer;\n\n        if (!GetMenuItemInfo(MenuHandle, i, TRUE, &menuItemInfo))\n            continue;\n\n        menuItem = PhCreateEMenuItem(\n            PH_EMENU_TEXT_OWNED,\n            menuItemInfo.wID,\n            PhDuplicateStringZ(buffer),\n            NULL,\n            NULL\n            );\n\n        if (menuItemInfo.fType & MFT_SEPARATOR)\n            menuItem->Flags |= PH_EMENU_SEPARATOR;\n\n        PhMapFlags2(\n            &menuItem->Flags,\n            menuItemInfo.fType,\n            EMenuTypeMappings,\n            RTL_NUMBER_OF(EMenuTypeMappings)\n            );\n        PhMapFlags2(\n            &menuItem->Flags,\n            menuItemInfo.fState,\n            EMenuStateMappings,\n            RTL_NUMBER_OF(EMenuStateMappings)\n            );\n\n        if (menuItemInfo.hSubMenu)\n            PhHMenuToEMenuItem(menuItem, menuItemInfo.hSubMenu);\n\n        PhInsertEMenuItem(MenuItem, menuItem, ULONG_MAX);\n    }\n}\n\n/**\n * Loads a menu resource and converts it to an EMENU.\n *\n * \\param MenuItem The menu item in which the converted menu items will be placed.\n * \\param InstanceHandle The module containing the menu resource.\n * \\param Resource The resource identifier.\n * \\param SubMenuIndex The index of the sub menu to use, or -1 to use the root menu.\n */\nVOID PhLoadResourceEMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem,\n    _In_ HINSTANCE InstanceHandle,\n    _In_ PCWSTR Resource,\n    _In_ LONG SubMenuIndex\n    )\n{\n    HMENU menu;\n    HMENU realMenu;\n\n    menu = PhLoadMenu(InstanceHandle, Resource);\n\n    if (SubMenuIndex != INT_ERROR)\n        realMenu = GetSubMenu(menu, SubMenuIndex);\n    else\n        realMenu = menu;\n\n    PhHMenuToEMenuItem(MenuItem, realMenu);\n\n    DestroyMenu(menu);\n}\n\n/**\n * Displays a menu.\n *\n * \\param Menu A menu.\n * \\param WindowHandle The window that owns the popup menu.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_SHOW_SEND_COMMAND A WM_COMMAND message is sent to the window when the user clicks\n * on a menu item.\n * \\li \\c PH_EMENU_SHOW_LEFTRIGHT The user can select menu items with both the left and right mouse\n * buttons.\n * \\param Align The alignment of the menu.\n * \\param X The horizontal location of the menu.\n * \\param Y The vertical location of the menu.\n * \\return The selected menu item, or NULL if the menu was cancelled.\n */\nPPH_EMENU_ITEM PhShowEMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG Align,\n    _In_ ULONG X,\n    _In_ ULONG Y\n    )\n{\n    PPH_EMENU_ITEM selectedItem;\n    ULONG result;\n    ULONG flags;\n    PH_EMENU_DATA data;\n    HMENU popupMenu;\n\n    selectedItem = NULL;\n    flags = TPM_RETURNCMD | TPM_NONOTIFY;\n\n    // Flags\n\n    if (Flags & PH_EMENU_SHOW_LEFTRIGHT)\n        flags |= TPM_RIGHTBUTTON;\n    else\n        flags |= TPM_LEFTBUTTON;\n\n    // Align\n\n    if (Align & PH_ALIGN_LEFT)\n        flags |= TPM_LEFTALIGN;\n    else if (Align & PH_ALIGN_RIGHT)\n        flags |= TPM_RIGHTALIGN;\n    else\n        flags |= TPM_CENTERALIGN;\n\n    if (Align & PH_ALIGN_TOP)\n        flags |= TPM_TOPALIGN;\n    else if (Align & PH_ALIGN_BOTTOM)\n        flags |= TPM_BOTTOMALIGN;\n    else\n        flags |= TPM_VCENTERALIGN;\n\n    PhInitializeEMenuData(&data);\n\n    if (popupMenu = PhEMenuToHMenu(Menu, PH_EMENU_CONVERT_ID, &data))\n    {\n        result = TrackPopupMenu(\n            popupMenu,\n            flags,\n            X,\n            Y,\n            0,\n            WindowHandle,\n            NULL\n            );\n\n        if (result != 0)\n        {\n            selectedItem = PhItemList(data.IdToItem, result - 1);\n        }\n\n        DestroyMenu(popupMenu);\n    }\n\n    PhDeleteEMenuData(&data);\n\n    if ((Flags & PH_EMENU_SHOW_SEND_COMMAND) && selectedItem && selectedItem->Id != 0)\n        SendMessage(WindowHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, 0), 0);\n\n    return selectedItem;\n}\n\n/**\n * Sets the flags of a menu item.\n *\n * \\param Item The parent menu item.\n * \\param Id The identifier of the child menu item.\n * \\param Mask The flags to modify.\n * \\param Value The new value of the flags.\n */\nBOOLEAN PhSetFlagsEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Id,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    )\n{\n    PPH_EMENU_ITEM item;\n\n    item = PhFindEMenuItem(Item, PH_EMENU_FIND_DESCEND, NULL, Id);\n\n    if (item)\n    {\n        item->Flags &= ~Mask;\n        item->Flags |= Value;\n\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\n/**\n * Sets flags for all children of a menu item.\n *\n * \\param Item The parent menu item.\n * \\param Mask The flags to modify.\n * \\param Value The new value of the flags.\n */\nVOID PhSetFlagsAllEMenuItems(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Item->Items->Count; i++)\n    {\n        PPH_EMENU_ITEM item = PhItemList(Item->Items, i);\n\n        item->Flags &= ~Mask;\n        item->Flags |= Value;\n    }\n}\n\nVOID PhModifyEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG ModifyFlags,\n    _In_ ULONG OwnedFlags,\n    _In_opt_ PWSTR Text,\n    _In_opt_ HBITMAP Bitmap\n    )\n{\n    if (ModifyFlags & PH_EMENU_MODIFY_TEXT)\n    {\n        if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text)\n            PhFree(Item->Text);\n\n        Item->Text = Text;\n        Item->Flags &= ~PH_EMENU_TEXT_OWNED;\n        Item->Flags |= OwnedFlags & PH_EMENU_TEXT_OWNED;\n    }\n\n    if (ModifyFlags & PH_EMENU_MODIFY_BITMAP)\n    {\n        if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap)\n            DeleteBitmap(Item->Bitmap);\n\n        Item->Bitmap = Bitmap;\n        Item->Flags &= ~PH_EMENU_BITMAP_OWNED;\n        Item->Flags |= OwnedFlags & PH_EMENU_BITMAP_OWNED;\n    }\n}\n\nVOID PhSetHMenuStyle(\n    _In_ HMENU Menu,\n    _In_ BOOLEAN MainMenu\n    )\n{\n    MENUINFO menuInfo;\n\n    memset(&menuInfo, 0, sizeof(MENUINFO));\n    menuInfo.cbSize = sizeof(MENUINFO);\n    menuInfo.fMask = MIM_STYLE;\n    menuInfo.dwStyle = MNS_CHECKORBMP;\n\n    if (MainMenu)\n    {\n        if (PhEnableThemeSupport)\n        {\n            menuInfo.fMask |= MIM_BACKGROUND;\n            menuInfo.hbrBack = PhThemeWindowBackgroundBrush;\n        }\n    }\n    else\n    {\n        if ((WindowsVersion < WINDOWS_10_19H2 || PhEnableThemeAcrylicSupport) && PhEnableThemeSupport)\n        {\n            menuInfo.fMask |= MIM_BACKGROUND | MIM_APPLYTOSUBMENUS;\n            menuInfo.hbrBack = PhThemeWindowBackgroundBrush;\n        }\n    }\n\n    SetMenuInfo(Menu, &menuInfo);\n}\n\nBOOLEAN PhSetHMenuWindow(\n    _In_ HWND WindowHandle,\n    _In_ HMENU MenuHandle\n    )\n{\n    return !!SetMenu(WindowHandle, MenuHandle);\n}\n\nBOOLEAN PhSetHMenuNotify(\n    _In_ HMENU MenuHandle\n    )\n{\n    MENUINFO menuInfo;\n\n    memset(&menuInfo, 0, sizeof(MENUINFO));\n    menuInfo.cbSize = sizeof(MENUINFO);\n    menuInfo.fMask = MIM_STYLE;\n    menuInfo.dwStyle = MNS_NOTIFYBYPOS;\n\n    return !!SetMenuInfo(MenuHandle, &menuInfo);\n}\n\nVOID PhDeleteHMenu(\n    _In_ HMENU Menu\n    )\n{\n    while (DeleteMenu(Menu, 0, MF_BYPOSITION))\n        NOTHING;\n}\n\n_Success_(return)\nBOOLEAN PhGetHMenuStringToBuffer(\n    _In_ HMENU Menu,\n    _In_ ULONG Id,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    MENUITEMINFO menuInfo;\n\n    memset(&menuInfo, 0, sizeof(MENUITEMINFO));\n    menuInfo.cbSize = sizeof(MENUITEMINFO);\n    menuInfo.fMask = MIIM_STRING;\n    menuInfo.dwTypeData = Buffer;\n    menuInfo.cch = (ULONG)BufferLength / sizeof(WCHAR);\n\n    if (GetMenuItemInfo(Menu, Id, TRUE, &menuInfo))\n    {\n        if (ReturnLength) *ReturnLength = menuInfo.cch;\n        Buffer[menuInfo.cch] = UNICODE_NULL;\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nPPH_EMENU_ITEM PhGetMenuData(\n    _In_ HMENU Menu,\n    _In_ ULONG Index\n    )\n{\n    MENUITEMINFO menuItemInfo;\n\n    memset(&menuItemInfo, 0, sizeof(MENUITEMINFO));\n    menuItemInfo.cbSize = sizeof(MENUITEMINFO);\n    menuItemInfo.fMask = MIIM_ID | MIIM_DATA;\n    menuItemInfo.wID = 0;\n\n    if (GetMenuItemInfo(Menu, Index, TRUE, &menuItemInfo))\n    {\n        return (PPH_EMENU_ITEM)menuItemInfo.dwItemData;\n    }\n\n    return NULL;\n}\n\nVOID PhMenuCallbackDispatch(\n    _In_ HMENU Menu,\n    _In_ ULONG Index\n    )\n{\n    PPH_EMENU_ITEM item;\n    HMENU menu;\n\n    if (item = PhGetMenuData(Menu, Index))\n    {\n        if (!FlagOn(item->Flags, PH_EMENU_CALLBACK))\n        {\n            SetFlag(item->Flags, PH_EMENU_CALLBACK);\n\n            if (item->DelayFunction)\n            {\n                if (menu = GetSubMenu(Menu, Index))\n                {\n                    item->DelayFunction(menu, item);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "phlib/error.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *     dmex    2018-2024\n *\n */\n\n#include <phbase.h>\n\n/**\n * Converts a NTSTATUS value to a Win32 error code.\n *\n * \\remarks This function handles FACILITY_NTWIN32 status values properly, unlike\n * RtlNtStatusToDosError.\n */\nULONG PhNtStatusToDosError(\n    _In_ NTSTATUS Status\n    )\n{\n    if (NT_NTWIN32(Status)) // RtlNtStatusToDosError doesn't seem to handle these cases correctly\n        return WIN32_FROM_NTSTATUS(Status);\n    else\n        return RtlNtStatusToDosErrorNoTeb(Status);\n}\n\n/**\n * Converts a NTSTATUS value to a Win32 service error code.\n */\nULONG PhNtStatusToServiceStatus(\n    _In_ NTSTATUS Status\n    )\n{\n    switch (Status)\n    {\n    case STATUS_SUCCESS: return ERROR_SUCCESS;\n    case STATUS_SERVICE_NOTIFICATION: return ERROR_SERVICE_NOTIFICATION;\n    case STATUS_UNSATISFIED_DEPENDENCIES: return ERROR_DEPENDENT_SERVICES_RUNNING;\n    case STATUS_IMAGE_ALREADY_LOADED: return ERROR_SERVICE_ALREADY_RUNNING;\n    case STATUS_ACCOUNT_DISABLED: return ERROR_SERVICE_DISABLED;\n    case STATUS_OBJECT_NAME_NOT_FOUND: return ERROR_SERVICE_DOES_NOT_EXIST;\n    case STATUS_OBJECT_NAME_COLLISION: return ERROR_SERVICE_EXISTS;\n    case STATUS_OBJECT_NAME_EXISTS: return ERROR_DUPLICATE_SERVICE_NAME;\n    case STATUS_OBJECT_PATH_INVALID: return ERROR_SERVICE_NOT_FOUND;\n    case STATUS_SERVICES_FAILED_AUTOSTART: return ERROR_SERVICES_FAILED_AUTOSTART;\n    case STATUS_THREAD_NOT_RUNNING: return ERROR_SERVICE_NEVER_STARTED;\n    default: { return ERROR_MR_MID_NOT_FOUND; }\n    }\n}\n\n/**\n * Converts a Win32 error code to a NTSTATUS value.\n *\n * \\remarks Only a small number of cases are currently supported. Other status values are wrapped\n * using FACILITY_NTWIN32.\n */\nNTSTATUS PhDosErrorToNtStatus(\n    _In_ ULONG DosError\n    )\n{\n    if (NT_CUSTOMER(DosError))\n        return DosError;\n\n    switch (DosError)\n    {\n    case ERROR_SUCCESS: return STATUS_SUCCESS;\n    case ERROR_INVALID_FUNCTION: return STATUS_ILLEGAL_FUNCTION;\n    case ERROR_FILE_NOT_FOUND: return STATUS_NO_SUCH_FILE;\n    case ERROR_PATH_NOT_FOUND: return STATUS_OBJECT_PATH_NOT_FOUND;\n    case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;\n    case ERROR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;\n    case ERROR_INVALID_DATA: return STATUS_DATA_ERROR;\n    case ERROR_NO_MORE_FILES: return STATUS_NO_MORE_FILES;\n    case ERROR_BAD_LENGTH: return STATUS_INFO_LENGTH_MISMATCH;\n    case ERROR_SHARING_VIOLATION: return STATUS_SHARING_VIOLATION;\n    case ERROR_HANDLE_EOF: return STATUS_END_OF_FILE;\n    case ERROR_NOT_SUPPORTED: return STATUS_NOT_SUPPORTED;\n    case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;\n    case ERROR_INSUFFICIENT_BUFFER: return STATUS_BUFFER_TOO_SMALL;\n    case ERROR_INVALID_NAME: return STATUS_OBJECT_NAME_INVALID;\n    case ERROR_MOD_NOT_FOUND: return STATUS_DLL_NOT_FOUND;\n    case ERROR_PROC_NOT_FOUND: return STATUS_PROCEDURE_NOT_FOUND;\n    case ERROR_NOT_LOCKED: return STATUS_NOT_LOCKED;\n    case ERROR_BAD_PATHNAME: return STATUS_OBJECT_PATH_INVALID;\n    case ERROR_INVALID_ORDINAL: return STATUS_ORDINAL_NOT_FOUND;\n    case ERROR_ALREADY_EXISTS: return STATUS_OBJECT_NAME_COLLISION;\n    case ERROR_BAD_EXE_FORMAT: return STATUS_INVALID_IMAGE_FORMAT;\n    case ERROR_DELETE_PENDING: return STATUS_DELETE_PENDING;\n    case ERROR_MORE_DATA: return STATUS_MORE_ENTRIES;\n    case ERROR_NO_MORE_ITEMS: return STATUS_NO_MORE_ENTRIES;\n    case ERROR_PARTIAL_COPY: return STATUS_PARTIAL_COPY;\n    case ERROR_INVALID_IMAGE_HASH: return STATUS_INVALID_IMAGE_HASH;\n    case ERROR_NOINTERFACE: return STATUS_NOINTERFACE;\n    case ERROR_SERVICE_NOTIFICATION: return STATUS_SERVICE_NOTIFICATION;\n    case ERROR_ALERTED: return STATUS_ALERTED;\n    case ERROR_ELEVATION_REQUIRED: return STATUS_ELEVATION_REQUIRED;\n    case ERROR_NOACCESS: return STATUS_ACCESS_VIOLATION;\n    case ERROR_STACK_OVERFLOW: return STATUS_STACK_OVERFLOW;\n    case ERROR_NO_TOKEN: return STATUS_NO_TOKEN;\n    case ERROR_DEPENDENT_SERVICES_RUNNING: return STATUS_UNSATISFIED_DEPENDENCIES;\n    case ERROR_SERVICE_ALREADY_RUNNING: return STATUS_IMAGE_ALREADY_LOADED;\n    case ERROR_SERVICE_DISABLED: return STATUS_ILL_FORMED_SERVICE_ENTRY; // STATUS_INVALID_CONFIG_VALUE\n    case ERROR_SERVICE_DOES_NOT_EXIST: return STATUS_OBJECT_NAME_NOT_FOUND;\n    case ERROR_SERVICE_EXISTS: return STATUS_OBJECT_NAME_COLLISION;\n    case ERROR_SERVICE_NEVER_STARTED: return STATUS_THREAD_NOT_RUNNING;\n    case ERROR_PROCESS_ABORTED: return STATUS_FATAL_APP_EXIT;\n    case ERROR_DUPLICATE_SERVICE_NAME: return STATUS_OBJECT_NAME_EXISTS;\n    case ERROR_DLL_INIT_FAILED: return STATUS_DLL_INIT_FAILED;\n    case ERROR_NOT_FOUND: return STATUS_NOT_FOUND;\n    case ERROR_CANCELLED: return STATUS_CANCELLED;\n    case ERROR_SERVICE_NOT_FOUND: return STATUS_OBJECT_PATH_INVALID;\n    case ERROR_SOME_NOT_MAPPED: return STATUS_SOME_NOT_MAPPED;\n    case ERROR_PRIVILEGE_NOT_HELD: return STATUS_PRIVILEGE_NOT_HELD;\n    case ERROR_LOGON_FAILURE: return STATUS_LOGON_FAILURE;\n    case ERROR_ACCOUNT_RESTRICTION: return STATUS_ACCOUNT_RESTRICTION;\n    case ERROR_ACCOUNT_DISABLED: return STATUS_ACCOUNT_DISABLED;\n    case ERROR_NONE_MAPPED: return STATUS_NONE_MAPPED;\n    case ERROR_NO_SUCH_DOMAIN: return STATUS_NO_SUCH_DOMAIN;\n    case ERROR_INTERNAL_ERROR: return STATUS_INTERNAL_ERROR;\n    case ERROR_INVALID_WINDOW_HANDLE: return STATUS_INVALID_HANDLE;\n    case ERROR_NO_SYSTEM_RESOURCES: return STATUS_INSUFFICIENT_RESOURCES;\n    case ERROR_TIMEOUT: return STATUS_TIMEOUT;\n    case ERROR_INVALID_MONITOR_HANDLE: return STATUS_INVALID_HANDLE;\n    case ERROR_DYNAMIC_CODE_BLOCKED: return STATUS_DYNAMIC_CODE_BLOCKED;\n    case ERROR_STRICT_CFG_VIOLATION: return STATUS_STRICT_CFG_VIOLATION;\n    case ERROR_RESOURCE_TYPE_NOT_FOUND: return STATUS_RESOURCE_TYPE_NOT_FOUND;\n    case ERROR_RESOURCE_NAME_NOT_FOUND: return STATUS_RESOURCE_NAME_NOT_FOUND;\n    case ERROR_RESOURCE_LANG_NOT_FOUND: return STATUS_RESOURCE_LANG_NOT_FOUND;\n    case ERROR_NOT_ENOUGH_QUOTA: return STATUS_QUOTA_EXCEEDED;\n    case ERROR_INVALID_TIME: return STATUS_INVALID_PARAMETER;\n    case ERROR_WMI_GUID_NOT_FOUND: return STATUS_WMI_GUID_NOT_FOUND;\n    case ERROR_WMI_INSTANCE_NOT_FOUND: return STATUS_WMI_INSTANCE_NOT_FOUND;\n    case ERROR_ACTIVE_CONNECTIONS: return STATUS_ALREADY_DISCONNECTED;\n    case ERROR_CTX_CLOSE_PENDING: return STATUS_CTX_CLOSE_PENDING;\n    case ERROR_SERVICES_FAILED_AUTOSTART: return STATUS_SERVICES_FAILED_AUTOSTART;\n    case ERROR_INVALID_SERVICE_CONTROL: return STATUS_INVALID_DEVICE_REQUEST;\n    case ERROR_MUI_FILE_NOT_FOUND: return STATUS_MUI_FILE_NOT_FOUND;\n    case ERROR_MUI_INVALID_FILE: return STATUS_MUI_INVALID_FILE;\n    case ERROR_MUI_INVALID_RC_CONFIG: return STATUS_MUI_INVALID_RC_CONFIG;\n    case ERROR_MUI_INVALID_LOCALE_NAME: return STATUS_MUI_INVALID_LOCALE_NAME;\n    case ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME: return STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME;\n    case ERROR_MUI_FILE_NOT_LOADED: return STATUS_MUI_FILE_NOT_LOADED;\n    case ERROR_RESOURCE_ENUM_USER_STOP: return STATUS_RESOURCE_ENUM_USER_STOP;\n    case NTE_INVALID_HANDLE: return STATUS_INVALID_HANDLE;\n    case NTE_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;\n    case NTE_BUFFER_TOO_SMALL: return STATUS_BUFFER_TOO_SMALL;\n    default:\n        {\n            assert(FALSE); // Update the table. (dmex)\n            return NTSTATUS_FROM_WIN32(DosError);\n        }\n    }\n}\n\n/**\n * Determines whether a NTSTATUS value indicates that a file cannot be not found.\n */\nBOOLEAN PhNtStatusFileNotFound(\n    _In_ NTSTATUS Status\n    )\n{\n    switch (Status)\n    {\n    case STATUS_NO_SUCH_FILE:\n        return TRUE;\n    case STATUS_OBJECT_NAME_INVALID:\n        return TRUE;\n    case STATUS_OBJECT_NAME_NOT_FOUND:\n        return TRUE;\n    case STATUS_OBJECT_NO_LONGER_EXISTS:\n        return TRUE;\n    case STATUS_OBJECT_PATH_INVALID:\n        return TRUE;\n    case STATUS_OBJECT_PATH_NOT_FOUND:\n        return TRUE;\n    default: return FALSE;\n    }\n}\n\n/**\n * Determines whether a HRESULT value was converted from a NTSTATUS and returns the original error code.\n */\nNTSTATUS PhNtStatusFromHResult(\n    _In_ HRESULT Result\n    )\n{\n    if (HRESULT_CUSTOMER(Result))\n    {\n        NOTHING;\n    }\n    else if (HRESULT_NTSTATUS(Result)) // if (FlagOn(Result, FACILITY_NT_BIT))\n    {\n        ClearFlag(Result, FACILITY_NT_BIT); // reverse HRESULT_FROM_NT (dmex)\n    }\n    else if (\n        HRESULT_FACILITY(Result) == FACILITY_WIN32 ||\n        HRESULT_FACILITY(Result) == FACILITY_WINDOWS\n        )\n    {\n        Result = PhDosErrorToNtStatus(HRESULT_CODE(Result));\n    }\n\n    return Result;\n}\n"
  },
  {
    "path": "phlib/extlv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2012\n *     dmex    2017-2024\n *\n */\n\n/*\n * The extended list view adds some functionality to the default list view control, such as sorting,\n * item colors and fonts, better redraw disabling, and the ability to change the cursor. This is\n * currently implemented by hooking the window procedure.\n */\n\n#include <ph.h>\n#include <guisup.h>\n#include <emenu.h>\n\n#define PH_MAX_COMPARE_FUNCTIONS 16\n\ntypedef struct _PH_EXTLV_CONTEXT\n{\n    HWND Handle;\n    WNDPROC OldWndProc;\n    PVOID Context;\n\n    // Sorting\n\n    BOOLEAN TriState;\n    LONG SortColumn;\n    LONG DefaultSortColumn;\n    PH_SORT_ORDER SortOrder;\n    PH_SORT_ORDER DefaultSortOrder;\n    BOOLEAN SortFast;\n\n    _Function_class_(PH_COMPARE_FUNCTION)\n    PPH_COMPARE_FUNCTION TriStateCompareFunction;\n    _Function_class_(PH_COMPARE_FUNCTION)\n    PPH_COMPARE_FUNCTION CompareFunctions[PH_MAX_COMPARE_FUNCTIONS];\n\n    ULONG FallbackColumns[PH_MAX_COMPARE_FUNCTIONS];\n    ULONG NumberOfFallbackColumns;\n\n    // Color and Font\n    PPH_EXTLV_GET_ITEM_COLOR ItemColorFunction;\n    PPH_EXTLV_GET_ITEM_FONT ItemFontFunction;\n\n    // Misc.\n\n    LONG EnableRedraw;\n    LONG WindowDpi;\n    HCURSOR Cursor;\n    PPH_LISTVIEW_CONTEXT ListViewContext;\n} PH_EXTLV_CONTEXT, *PPH_EXTLV_CONTEXT;\n\nLRESULT CALLBACK PhpExtendedListViewWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nLONG PhpExtendedListViewCompareFunc(\n    _In_ LPARAM lParam1,\n    _In_ LPARAM lParam2,\n    _In_ LPARAM lParamSort\n    );\n\nLONG PhpExtendedListViewCompareFastFunc(\n    _In_ LPARAM lParam1,\n    _In_ LPARAM lParam2,\n    _In_ LPARAM lParamSort\n    );\n\nLONG PhpCompareListViewItems(\n    _In_ PPH_EXTLV_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _In_ PVOID XParam,\n    _In_ PVOID YParam,\n    _In_ ULONG Column,\n    _In_ BOOLEAN EnableDefault\n    );\n\nLONG PhpDefaultCompareListViewItems(\n    _In_ PPH_EXTLV_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _In_ ULONG Column\n    );\n\n/**\n * Enables extended list view support for a list view control.\n *\n * \\param WindowHandle A handle to the list view control.\n */\nVOID PhSetExtendedListView(\n    _In_ HWND WindowHandle\n    )\n{\n    PhSetExtendedListViewEx(WindowHandle, 0, AscendingSortOrder);\n}\n\nVOID PhSetExtendedListViewEx(\n    _In_ HWND WindowHandle,\n    _In_ ULONG SortColumn,\n    _In_ ULONG SortOrder\n    )\n{\n    PPH_EXTLV_CONTEXT context;\n\n    context = PhAllocateZero(sizeof(PH_EXTLV_CONTEXT));\n    context->Handle = WindowHandle;\n    context->Context = NULL;\n    context->TriState = FALSE;\n    context->SortColumn = SortColumn;\n    context->DefaultSortColumn = SortColumn;\n    context->SortOrder = SortOrder;\n    context->DefaultSortOrder = SortOrder;\n    context->SortFast = FALSE;\n    context->TriStateCompareFunction = NULL;\n    context->NumberOfFallbackColumns = 0;\n    context->ItemColorFunction = NULL;\n    context->ItemFontFunction = NULL;\n    context->EnableRedraw = 1;\n    context->Cursor = NULL;\n\n    context->ListViewContext = PhListView_Initialize(WindowHandle);\n\n    context->OldWndProc = PhGetWindowProcedure(WindowHandle);\n    PhSetWindowContext(WindowHandle, MAXCHAR, context);\n    PhSetWindowProcedure(WindowHandle, PhpExtendedListViewWndProc);\n\n    ExtendedListView_Init(WindowHandle);\n}\n\nLRESULT CALLBACK PhpExtendedListViewWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_EXTLV_CONTEXT context;\n    WNDPROC oldWndProc;\n\n    context = PhGetWindowContext(WindowHandle, MAXCHAR);\n\n    if (!context)\n        return 0;\n\n    oldWndProc = context->OldWndProc;\n\n    switch (WindowMessage)\n    {\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, MAXCHAR);\n            PhSetWindowProcedure(WindowHandle, oldWndProc);\n\n            PhListView_Destroy(context->ListViewContext);\n\n            PhFree(context);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case HDN_ITEMCLICK:\n                {\n                    HWND headerHandle;\n\n                    if (!PhListView_GetHeader(context->ListViewContext, &headerHandle))\n                        break;\n\n                    if (header->hwndFrom == headerHandle)\n                    {\n                        LPNMHEADER header2 = (LPNMHEADER)header;\n\n                        if (header2->iItem == context->SortColumn)\n                        {\n                            if (context->TriState)\n                            {\n                                if (context->SortOrder == AscendingSortOrder)\n                                    context->SortOrder = DescendingSortOrder;\n                                else if (context->SortOrder == DescendingSortOrder)\n                                    context->SortOrder = NoSortOrder;\n                                else\n                                    context->SortOrder = AscendingSortOrder;\n                            }\n                            else\n                            {\n                                if (context->SortOrder == AscendingSortOrder)\n                                    context->SortOrder = DescendingSortOrder;\n                                else\n                                    context->SortOrder = AscendingSortOrder;\n                            }\n                        }\n                        else\n                        {\n                            context->SortColumn = header2->iItem;\n                            context->SortOrder = AscendingSortOrder;\n                        }\n\n                        PhSetHeaderSortIcon(headerHandle, context->SortColumn, context->SortOrder);\n                        ExtendedListView_SortItems(WindowHandle);\n                    }\n                }\n                break;\n            case NM_RCLICK:\n                {\n                    LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)lParam;\n                    HWND headerHandle;\n                    PPH_EMENU menu;\n                    PPH_EMENU_ITEM selectedItem;\n                    POINT position;\n\n                    if (!PhListView_GetHeader(context->ListViewContext, &headerHandle))\n                        break;\n\n                    if (header->hwndFrom != headerHandle)\n                        break;\n\n                    if (!PhGetMessagePos(&position))\n                        break;\n\n                    menu = PhCreateEMenu();\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L\"Size column to fit\", NULL, NULL), ULONG_MAX);\n                    PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 2, L\"Size all columns to fit\", NULL, NULL), ULONG_MAX);\n\n                    if (context->SortOrder != context->DefaultSortOrder || context->SortColumn != context->DefaultSortColumn)\n                    {\n                        PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n                        PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 3, L\"Reset sort\", NULL, NULL), ULONG_MAX);\n                    }\n\n                    selectedItem = PhShowEMenu(\n                        menu,\n                        WindowHandle,\n                        PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                        PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                        position.x,\n                        position.y\n                        );\n\n                    if (selectedItem && selectedItem->Id)\n                    {\n                        switch (selectedItem->Id)\n                        {\n                        case 1:\n                            {\n                                LONG headerCount;\n\n                                headerCount = Header_GetItemCount(headerHandle);\n\n                                if (headerCount != INT_ERROR)\n                                {\n                                    if (!PhScreenToClient(WindowHandle, &position))\n                                        break;\n\n                                    for (LONG i = 0; i < headerCount; ++i)\n                                    {\n                                        RECT headerRect;\n\n                                        if (Header_GetItemRect(headerHandle, i, &headerRect) && PhPtInRect(&headerRect, &position))\n                                        {\n                                            CallWindowProc(oldWndProc, WindowHandle, LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE);\n                                            break;\n                                        }\n                                    }\n                                }\n                            }\n                            break;\n                        case 2:\n                            {\n                                LONG headerCount;\n\n                                headerCount = Header_GetItemCount(headerHandle);\n\n                                if (headerCount != INT_ERROR)\n                                {\n                                    for (LONG i = 0; i < headerCount; i++)\n                                    {\n                                        HDITEM item;\n\n                                        item.mask = HDI_ORDER;\n\n                                        if (Header_GetItem(headerHandle, i, &item))\n                                        {\n                                            CallWindowProc(oldWndProc, WindowHandle, LVM_SETCOLUMNWIDTH, item.iOrder, LVSCW_AUTOSIZE);\n                                        }\n                                    }\n                                }\n                            }\n                            break;\n                        case 3:\n                            {\n                                ExtendedListView_SetSort(WindowHandle, context->DefaultSortColumn, context->DefaultSortOrder);\n                                ExtendedListView_SortItems(WindowHandle);\n                            }\n                            break;\n                        }\n                    }\n\n                    PhDestroyEMenu(menu);\n                }\n                return 1;\n            }\n        }\n        break;\n    case WM_REFLECT + WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case NM_CUSTOMDRAW:\n                {\n                    if (header->hwndFrom == WindowHandle)\n                    {\n                        LPNMLVCUSTOMDRAW customDraw = (LPNMLVCUSTOMDRAW)header;\n\n                        switch (customDraw->nmcd.dwDrawStage)\n                        {\n                        case CDDS_PREPAINT:\n                            return CDRF_NOTIFYITEMDRAW;\n                        case CDDS_ITEMPREPAINT:\n                            {\n                                BOOLEAN colorChanged = FALSE;\n                                BOOLEAN selected = FALSE;\n                                HFONT newFont = NULL;\n\n                                if (context->ItemColorFunction)\n                                {\n                                    customDraw->clrTextBk = context->ItemColorFunction(\n                                        (LONG)customDraw->nmcd.dwItemSpec,\n                                        (PVOID)customDraw->nmcd.lItemlParam,\n                                        context->Context\n                                        );\n                                    colorChanged = TRUE;\n                                }\n\n                                if (context->ItemFontFunction)\n                                {\n                                    newFont = context->ItemFontFunction(\n                                        (LONG)customDraw->nmcd.dwItemSpec,\n                                        (PVOID)customDraw->nmcd.lItemlParam,\n                                        context->Context\n                                        );\n                                }\n\n                                if (newFont)\n                                    SelectFont(customDraw->nmcd.hdc, newFont);\n\n                                // Fix text readability for hot and selected colored items (Dart Vanya)\n\n                                if (PhEnableThemeSupport)\n                                {\n                                    ULONG state;\n\n                                    if (context->ListViewContext && PhListView_GetItemState(\n                                        context->ListViewContext,\n                                        (LONG)customDraw->nmcd.dwItemSpec,\n                                        LVIS_SELECTED,\n                                        &state\n                                        ))\n                                    {\n                                        if (FlagOn(customDraw->nmcd.uItemState, CDIS_HOT) || FlagOn(state, LVIS_SELECTED))\n                                        {\n                                            selected = TRUE;\n                                        }\n                                    }\n                                    else\n                                    {\n                                        if (FlagOn(customDraw->nmcd.uItemState, CDIS_HOT) || FlagOn(CallWindowProc(\n                                            oldWndProc,\n                                            WindowHandle,\n                                            LVM_GETITEMSTATE,\n                                            customDraw->nmcd.dwItemSpec,\n                                            LVIS_SELECTED\n                                            ), LVIS_SELECTED))\n                                        {\n                                            selected = TRUE;\n                                        }\n                                    }\n                                }\n\n                                if (selected)\n                                {\n                                    customDraw->clrText = PhThemeWindowTextColor;\n                                }\n                                else if (colorChanged)\n                                {\n                                    if (PhGetColorBrightness(customDraw->clrTextBk) > 100) // slightly less than half\n                                        customDraw->clrText = RGB(0x00, 0x00, 0x00);\n                                    else\n                                        customDraw->clrText = RGB(0xff, 0xff, 0xff);\n                                }\n\n                                if (newFont)\n                                    return CDRF_NEWFONT;\n                                else\n                                    return CDRF_DODEFAULT;\n                            }\n                            break;\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_SETCURSOR:\n        {\n            if (context->Cursor)\n            {\n                PhSetCursor(context->Cursor);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_UPDATEUISTATE:\n        {\n            // Disable focus rectangles by setting or masking out the flag where appropriate.\n            switch (LOWORD(wParam))\n            {\n            case UIS_SET:\n                wParam |= UISF_HIDEFOCUS << 16;\n                break;\n            case UIS_CLEAR:\n            case UIS_INITIALIZE:\n                wParam &= ~(UISF_HIDEFOCUS << 16);\n                break;\n            }\n        }\n        break;\n    case ELVM_ADDFALLBACKCOLUMN:\n        {\n            if (context->NumberOfFallbackColumns < PH_MAX_COMPARE_FUNCTIONS)\n                context->FallbackColumns[context->NumberOfFallbackColumns++] = (ULONG)wParam;\n            else\n                return FALSE;\n        }\n        return TRUE;\n    case ELVM_ADDFALLBACKCOLUMNS:\n        {\n            ULONG numberOfColumns = (ULONG)wParam;\n            PULONG columns = (PULONG)lParam;\n\n            if (context->NumberOfFallbackColumns + numberOfColumns <= PH_MAX_COMPARE_FUNCTIONS)\n            {\n                memcpy(\n                    &context->FallbackColumns[context->NumberOfFallbackColumns],\n                    columns,\n                    numberOfColumns * sizeof(ULONG)\n                    );\n                context->NumberOfFallbackColumns += numberOfColumns;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case ELVM_INIT:\n        {\n            HWND windowHandle;\n\n            context->WindowDpi = PhGetWindowDpi(WindowHandle);\n\n            if (PhListView_GetHeader(context->ListViewContext, &windowHandle))\n            {\n                PhSetHeaderSortIcon(windowHandle, context->SortColumn, context->SortOrder);\n            }\n\n            if (PhListView_GetToolTip(context->ListViewContext, &windowHandle))\n            {\n                // Fix tooltips showing behind Always On Top windows.\n                SetWindowPos(windowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);\n            }\n\n            // Make sure focus rectangles are disabled.\n            SendMessage(WindowHandle, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0);\n        }\n        return TRUE;\n    case ELVM_SETCOLUMNWIDTH:\n        {\n            ULONG column = (ULONG)wParam;\n            LONG width = (LONG)lParam;\n\n            if (width == ELVSCW_AUTOSIZE_REMAININGSPACE)\n            {\n                RECT clientRect;\n                LONG availableWidth;\n                ULONG i;\n                LVCOLUMN lvColumn;\n\n                if (!PhGetClientRect(WindowHandle, &clientRect))\n                    break;\n\n                availableWidth = clientRect.right;\n                i = 0;\n                lvColumn.mask = LVCF_WIDTH;\n\n                while (TRUE)\n                {\n                    if (i != column)\n                    {\n                        if (context->ListViewContext)\n                        {\n                            if (PhListView_GetColumn(context->ListViewContext, i, &lvColumn))\n                            {\n                                availableWidth -= lvColumn.cx;\n                            }\n                            else\n                            {\n                                break;\n                            }\n                        }\n                        else\n                        {\n                            if (CallWindowProc(oldWndProc, WindowHandle, LVM_GETCOLUMN, i, (LPARAM)&lvColumn))\n                            {\n                                availableWidth -= lvColumn.cx;\n                            }\n                            else\n                            {\n                                break;\n                            }\n                        }\n                    }\n\n                    i++;\n                }\n\n                if (availableWidth >= 40)\n                {\n                    if (context->ListViewContext && PhListView_SetColumnWidth(context->ListViewContext, column, availableWidth))\n                        return TRUE;\n\n                    return CallWindowProc(oldWndProc, WindowHandle, LVM_SETCOLUMNWIDTH, column, availableWidth);\n                }\n            }\n\n            if (context->ListViewContext && PhListView_SetColumnWidth(context->ListViewContext, column, width))\n                return TRUE;\n\n            return CallWindowProc(oldWndProc, WindowHandle, LVM_SETCOLUMNWIDTH, column, width);\n        }\n        break;\n    case ELVM_SETCOMPAREFUNCTION:\n        {\n            PPH_COMPARE_FUNCTION compareFunction = (PPH_COMPARE_FUNCTION)lParam;\n            ULONG column = (ULONG)wParam;\n\n            if (column >= PH_MAX_COMPARE_FUNCTIONS)\n                return FALSE;\n\n            context->CompareFunctions[column] = compareFunction;\n        }\n        return TRUE;\n    case ELVM_SETCONTEXT:\n        {\n            context->Context = (PVOID)lParam;\n        }\n        return TRUE;\n    case ELVM_SETCURSOR:\n        {\n            context->Cursor = (HCURSOR)lParam;\n        }\n        return TRUE;\n    case ELVM_SETITEMCOLORFUNCTION:\n        {\n            context->ItemColorFunction = (PPH_EXTLV_GET_ITEM_COLOR)lParam;\n        }\n        return TRUE;\n    case ELVM_SETITEMFONTFUNCTION:\n        {\n            context->ItemFontFunction = (PPH_EXTLV_GET_ITEM_FONT)lParam;\n        }\n        return TRUE;\n    case ELVM_SETREDRAW:\n        {\n            if (wParam)\n                context->EnableRedraw++;\n            else\n                context->EnableRedraw--;\n\n            if (context->EnableRedraw == 1)\n            {\n                CallWindowProc(oldWndProc, WindowHandle, WM_SETREDRAW, TRUE, 0);\n                InvalidateRect(WindowHandle, NULL, FALSE);\n            }\n            else if (context->EnableRedraw == 0)\n            {\n                CallWindowProc(oldWndProc, WindowHandle, WM_SETREDRAW, FALSE, 0);\n            }\n        }\n        return TRUE;\n    case ELVM_GETSORT:\n        {\n            PULONG sortColumn = (PULONG)wParam;\n            PPH_SORT_ORDER sortOrder = (PPH_SORT_ORDER)lParam;\n\n            if (sortColumn)\n                *sortColumn = context->SortColumn;\n            if (sortOrder)\n                *sortOrder = context->SortOrder;\n        }\n        return TRUE;\n    case ELVM_SETSORT:\n        {\n            HWND windowHandle;\n\n            context->SortColumn = (ULONG)wParam;\n            context->SortOrder = (PH_SORT_ORDER)lParam;\n\n            if (PhListView_GetHeader(context->ListViewContext, &windowHandle))\n            {\n                PhSetHeaderSortIcon(windowHandle, context->SortColumn, context->SortOrder);\n            }\n        }\n        return TRUE;\n    case ELVM_SETSORTFAST:\n        {\n            context->SortFast = !!wParam;\n        }\n        return TRUE;\n    case ELVM_SETTRISTATE:\n        {\n            context->TriState = !!wParam;\n        }\n        return TRUE;\n    case ELVM_SETTRISTATECOMPAREFUNCTION:\n        {\n            PPH_EXTLV_SETCOMPAREFUNCTION compare = (PPH_EXTLV_SETCOMPAREFUNCTION)lParam;\n\n            context->TriStateCompareFunction = compare->CompareFunction;\n        }\n        return TRUE;\n    case ELVM_SORTITEMS:\n        {\n            BOOL result;\n\n            if (context->SortFast)\n            {\n                // This sort method is faster than the normal sort because our comparison function\n                // doesn't have to call the list view window procedure to get the item lParam\n                // values. The disadvantage of this method is that default sorting is not available\n                // - if a column doesn't have a comparison function, it doesn't get sorted at all.\n\n                if (context->ListViewContext)\n                {\n                    result = !!PhListView_SortItems(\n                        context->ListViewContext,\n                        FALSE,\n                        (PFNLVCOMPARE)PhpExtendedListViewCompareFastFunc,\n                        context\n                        );\n                }\n                else\n                {\n                    result = (BOOL)CallWindowProc( // ListView_SortItems\n                        oldWndProc,\n                        WindowHandle,\n                        LVM_SORTITEMS,\n                        (WPARAM)context,\n                        (LPARAM)(PFNLVCOMPARE)PhpExtendedListViewCompareFastFunc\n                        );\n                }\n            }\n            else\n            {\n                if (context->ListViewContext)\n                {\n                    result = !!PhListView_SortItems(\n                        context->ListViewContext,\n                        TRUE,\n                        (PFNLVCOMPARE)PhpExtendedListViewCompareFunc,\n                        context\n                        );\n                }\n                else\n                {\n                    result = (BOOL)CallWindowProc( // ListView_SortItemsEx\n                        oldWndProc,\n                        WindowHandle,\n                        LVM_SORTITEMSEX,\n                        (WPARAM)context,\n                        (LPARAM)(PFNLVCOMPARE)PhpExtendedListViewCompareFunc\n                        );\n                }\n            }\n\n            return result;\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            LONG listviewDpi;\n            LVCOLUMN lvColumn;\n            ULONG i;\n\n            i = 0;\n            lvColumn.mask = LVCF_WIDTH;\n            listviewDpi = PhGetWindowDpi(WindowHandle);\n\n            if (context->WindowDpi == 0)\n                break;\n\n            // Workaround the ListView using incorrect widths for header columns by re-setting the width. (dmex)\n            // Note: This resets the width a second time after the header control has already set the width.\n\n            ExtendedListView_SetRedraw(WindowHandle, FALSE);\n\n            while (TRUE)\n            {\n                if (context->ListViewContext)\n                {\n                    if (PhListView_GetColumn(context->ListViewContext, i, &lvColumn))\n                    {\n                        lvColumn.cx = PhMultiplyDivideSigned(lvColumn.cx, listviewDpi, context->WindowDpi);\n\n                        PhListView_SetColumn(context->ListViewContext, i, &lvColumn);\n                    }\n                    else\n                    {\n                        break;\n                    }\n                }\n                else\n                {\n                    if (CallWindowProc(oldWndProc, WindowHandle, LVM_GETCOLUMN, i, (LPARAM)&lvColumn))\n                    {\n                        lvColumn.cx = PhMultiplyDivideSigned(lvColumn.cx, listviewDpi, context->WindowDpi);\n\n                        CallWindowProc(oldWndProc, WindowHandle, LVM_SETCOLUMN, i, (WPARAM)&lvColumn);\n                    }\n                    else\n                    {\n                        break;\n                    }\n                }\n\n                i++;\n            }\n\n            ExtendedListView_SetRedraw(WindowHandle, TRUE);\n\n            context->WindowDpi = listviewDpi;\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n}\n\n/**\n * Visually indicates the sort order of a header control item.\n *\n * \\param WindowHandle A handle to the header control.\n * \\param Index The index of the item.\n * \\param Order The sort order of the item.\n */\nVOID PhSetHeaderSortIcon(\n    _In_ HWND WindowHandle,\n    _In_ LONG Index,\n    _In_ PH_SORT_ORDER Order\n    )\n{\n    LONG count;\n    LONG i;\n\n    count = Header_GetItemCount(WindowHandle);\n\n    if (count == INT_ERROR)\n        return;\n\n    for (i = 0; i < count; i++)\n    {\n        HDITEM item;\n\n        item.mask = HDI_FORMAT;\n        Header_GetItem(WindowHandle, i, &item);\n\n        if (Order != NoSortOrder && i == Index)\n        {\n            if (Order == AscendingSortOrder)\n            {\n                item.fmt &= ~HDF_SORTDOWN;\n                item.fmt |= HDF_SORTUP;\n            }\n            else if (Order == DescendingSortOrder)\n            {\n                item.fmt &= ~HDF_SORTUP;\n                item.fmt |= HDF_SORTDOWN;\n            }\n        }\n        else\n        {\n            item.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\n        }\n\n        Header_SetItem(WindowHandle, i, &item);\n    }\n}\n\nLONG PhpExtendedListViewCompareFunc(\n    _In_ LPARAM lParam1,\n    _In_ LPARAM lParam2,\n    _In_ LPARAM lParamSort\n    )\n{\n    PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort;\n    LONG result;\n    LONG x = (LONG)lParam1;\n    LONG y = (LONG)lParam2;\n    ULONG i;\n    PULONG fallbackColumns;\n    LVITEM xItem;\n    LVITEM yItem;\n\n    // Get the param values.\n\n    xItem.mask = LVIF_PARAM | LVIF_STATE;\n    xItem.iItem = x;\n    xItem.iSubItem = 0;\n\n    yItem.mask = LVIF_PARAM | LVIF_STATE;\n    yItem.iItem = y;\n    yItem.iSubItem = 0;\n\n    if (context->ListViewContext)\n    {\n        if (!PhListView_GetItem(context->ListViewContext, &xItem))\n            return 0;\n        if (!PhListView_GetItem(context->ListViewContext, &yItem))\n            return 0;\n    }\n    else\n    {\n        if (!CallWindowProc(context->OldWndProc, context->Handle, LVM_GETITEM, 0, (LPARAM)&xItem))\n            return 0;\n        if (!CallWindowProc(context->OldWndProc, context->Handle, LVM_GETITEM, 0, (LPARAM)&yItem))\n            return 0;\n    }\n\n    // First, do tri-state sorting.\n\n    if (\n        context->TriState &&\n        context->SortOrder == NoSortOrder &&\n        context->TriStateCompareFunction\n        )\n    {\n        result = context->TriStateCompareFunction(\n            (PVOID)xItem.lParam,\n            (PVOID)yItem.lParam,\n            context->Context\n            );\n\n        if (result != 0)\n            return result;\n    }\n\n    // Compare using the user-selected column and move on to the fallback columns if necessary.\n\n    result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, context->SortColumn, TRUE);\n\n    if (result != 0)\n        return result;\n\n    fallbackColumns = context->FallbackColumns;\n\n    for (i = context->NumberOfFallbackColumns; i != 0; i--)\n    {\n        ULONG fallbackColumn = *fallbackColumns++;\n\n        if (fallbackColumn == context->SortColumn)\n            continue;\n\n        result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, fallbackColumn, TRUE);\n\n        if (result != 0)\n            return result;\n    }\n\n    return 0;\n}\n\nLONG PhpExtendedListViewCompareFastFunc(\n    _In_ LPARAM lParam1,\n    _In_ LPARAM lParam2,\n    _In_ LPARAM lParamSort\n    )\n{\n    PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort;\n    LONG result;\n    ULONG i;\n    PULONG fallbackColumns;\n\n    if (!lParam1 || !lParam2)\n        return 0;\n\n    // First, do tri-state sorting.\n\n    if (\n        context->TriState &&\n        context->SortOrder == NoSortOrder &&\n        context->TriStateCompareFunction\n        )\n    {\n        result = context->TriStateCompareFunction(\n            (PVOID)lParam1,\n            (PVOID)lParam2,\n            context->Context\n            );\n\n        if (result != 0)\n            return result;\n    }\n\n    // Compare using the user-selected column and move on to the fallback columns if necessary.\n\n    result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, context->SortColumn, FALSE);\n\n    if (result != 0)\n        return result;\n\n    fallbackColumns = context->FallbackColumns;\n\n    for (i = context->NumberOfFallbackColumns; i != 0; i--)\n    {\n        ULONG fallbackColumn = *fallbackColumns++;\n\n        if (fallbackColumn == context->SortColumn)\n            continue;\n\n        result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, fallbackColumn, FALSE);\n\n        if (result != 0)\n            return result;\n    }\n\n    return 0;\n}\n\nFORCEINLINE LONG PhpCompareListViewItems(\n    _In_ PPH_EXTLV_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _In_ PVOID XParam,\n    _In_ PVOID YParam,\n    _In_ ULONG Column,\n    _In_ BOOLEAN EnableDefault\n    )\n{\n    if (\n        Column < PH_MAX_COMPARE_FUNCTIONS &&\n        Context->CompareFunctions[Column]\n        )\n    {\n        LONG result;\n\n        result = PhModifySort(\n            Context->CompareFunctions[Column](XParam, YParam, Context->Context),\n            Context->SortOrder\n            );\n\n        if (result != 0)\n            return result;\n    }\n\n    if (EnableDefault)\n    {\n        return PhModifySort(\n            PhpDefaultCompareListViewItems(Context, X, Y, Column),\n            Context->SortOrder\n            );\n    }\n    else\n    {\n        return 0;\n    }\n}\n\nLONG PhpDefaultCompareListViewItems(\n    _In_ PPH_EXTLV_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _In_ ULONG Column\n    )\n{\n    WCHAR xText[MAX_PATH + 1];\n    WCHAR yText[MAX_PATH + 1];\n    LVITEM item;\n\n    // Get the X item text.\n\n    item.mask = LVIF_TEXT;\n    item.iItem = X;\n    item.iSubItem = Column;\n    item.pszText = xText;\n    item.cchTextMax = MAX_PATH;\n\n    xText[0] = UNICODE_NULL;\n\n    if (Context->ListViewContext)\n        PhListView_GetItem(Context->ListViewContext, &item);\n    else\n        CallWindowProc(Context->OldWndProc, Context->Handle, LVM_GETITEM, 0, (LPARAM)&item);\n\n    // Get the Y item text.\n\n    item.iItem = Y;\n    item.pszText = yText;\n    item.cchTextMax = MAX_PATH;\n\n    yText[0] = UNICODE_NULL;\n\n    if (Context->ListViewContext)\n        PhListView_GetItem(Context->ListViewContext, &item);\n    else\n        CallWindowProc(Context->OldWndProc, Context->Handle, LVM_GETITEM, 0, (LPARAM)&item);\n\n    // Compare them.\n\n#if 1\n    return PhCompareStringZNatural(xText, yText, TRUE);\n#else\n    return _wcsicmp(xText, yText);\n#endif\n}\n"
  },
  {
    "path": "phlib/fastlock.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2010\n *\n */\n\n#include <phbase.h>\n#include <fastlock.h>\n\n// FastLock is a fast resource (reader-writer) lock.\n//\n// The code is a direct port of FastResourceLock from PH 1.x. Please see FastResourceLock.cs in PH\n// 1.x for details.\n//\n// The fast lock is around 7% faster than the critical section when there is no contention, when\n// used solely for mutual exclusion. It is also much smaller than the critical section.\n//\n// There are three types of acquire methods:\n// * Normal methods (AcquireExclusive, AcquireShared) are preferred for general purpose use.\n// * Busy wait methods (SpinAcquireExclusive, SpinAcquireShared) are preferred if\n// very little time is spent while the lock is acquired. However, these do not give exclusive\n// acquires precedence over shared acquires.\n// * Try methods (TryAcquireExclusive, TryAcquireShared) can be used to quickly test if the lock is available.\n// \n// Note that all three types of functions can be used concurrently by the same FastLock instance.\n//\n// Details\n//\n// Resource lock value width: 32 bits.\n// Lock owned (either exclusive or shared): L (1 bit).\n// Exclusive waking: W (1 bit).\n// Shared owners count: SC (10 bits).\n// Shared waiters count: SW (10 bits).\n// Exclusive waiters count: EW (10 bits).\n//\n// Acquire exclusive:\n// {L=0,W=0,SC=0,SW,EW=0} -> {L=1,W=0,SC=0,SW,EW=0}\n// {L=0,W=1,SC=0,SW,EW} or {L=1,W,SC,SW,EW} ->\n//     {L,W,SC,SW,EW+1},\n//     wait on event,\n//     {L=0,W=1,SC=0,SW,EW} -> {L=1,W=0,SC=0,SW,EW}\n//\n// Acquire shared:\n// {L=0,W=0,SC=0,SW,EW=0} -> {L=1,W=0,SC=1,SW,EW=0}\n// {L=1,W=0,SC>0,SW,EW=0} -> {L=1,W=0,SC+1,SW,EW=0}\n// {L=1,W=0,SC=0,SW,EW=0} or {L,W=1,SC,SW,EW} or\n//     {L,W,SC,SW,EW>0} -> {L,W,SC,SW+1,EW},\n//     wait on event,\n//     retry.\n//\n// Release exclusive:\n// {L=1,W=0,SC=0,SW,EW>0} ->\n//     {L=0,W=1,SC=0,SW,EW-1},\n//     release one exclusive waiter.\n// {L=1,W=0,SC=0,SW,EW=0} ->\n//     {L=0,W=0,SC=0,SW=0,EW=0},\n//     release all shared waiters.\n//\n// Note that we never do a direct acquire when W=1 \n// (i.e. L=0 if W=1), so here we don't have to check \n// the value of W.\n//\n// Release shared:\n// {L=1,W=0,SC>1,SW,EW} -> {L=1,W=0,SC-1,SW,EW}\n// {L=1,W=0,SC=1,SW,EW=0} -> {L=0,W=0,SC=0,SW,EW=0}\n// {L=1,W=0,SC=1,SW,EW>0} ->\n//     {L=0,W=1,SC=0,SW,EW-1},\n//     release one exclusive waiter.\n//\n// Again, we don't need to check the value of W.\n//\n// Convert exclusive to shared:\n// {L=1,W=0,SC=0,SW,EW} ->\n//     {L=1,W=0,SC=1,SW=0,EW},\n//     release all shared waiters.\n//\n// Convert shared to exclusive:\n// {L=1,W=0,SC=1,SW,EW} ->\n//     {L=1,W=0,SC=0,SW,EW}\n//\n\n// Lock owned: 1 bit.\n#define PH_LOCK_OWNED 0x1\n// Exclusive waking: 1 bit.\n#define PH_LOCK_EXCLUSIVE_WAKING 0x2\n// Shared owners count: 10 bits.\n#define PH_LOCK_SHARED_OWNERS_SHIFT 2\n#define PH_LOCK_SHARED_OWNERS_MASK 0x3fful\n#define PH_LOCK_SHARED_OWNERS_INC 0x4\n// Shared waiters count: 10 bits.\n#define PH_LOCK_SHARED_WAITERS_SHIFT 12\n#define PH_LOCK_SHARED_WAITERS_MASK 0x3fful\n#define PH_LOCK_SHARED_WAITERS_INC 0x1000\n// Exclusive waiters count: 10 bits.\n#define PH_LOCK_EXCLUSIVE_WAITERS_SHIFT 22\n#define PH_LOCK_EXCLUSIVE_WAITERS_MASK 0x3fful\n#define PH_LOCK_EXCLUSIVE_WAITERS_INC 0x400000\n\n#define PH_LOCK_EXCLUSIVE_MASK \\\n    (PH_LOCK_EXCLUSIVE_WAKING | \\\n    (PH_LOCK_EXCLUSIVE_WAITERS_MASK << PH_LOCK_EXCLUSIVE_WAITERS_SHIFT))\n\nVOID PhInitializeFastLock(\n    _Out_ PPH_FAST_LOCK FastLock\n    )\n{\n    FastLock->Value = 0;\n    FastLock->ExclusiveWakeEvent = NULL;\n    FastLock->SharedWakeEvent = NULL;\n}\n\nVOID PhDeleteFastLock(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    if (FastLock->ExclusiveWakeEvent)\n    {\n        NtClose(FastLock->ExclusiveWakeEvent);\n        FastLock->ExclusiveWakeEvent = NULL;\n    }\n\n    if (FastLock->SharedWakeEvent)\n    {\n        NtClose(FastLock->SharedWakeEvent);\n        FastLock->SharedWakeEvent = NULL;\n    }\n}\n\nFORCEINLINE VOID PhpEnsureEventCreated(\n    _Inout_ PHANDLE Handle\n    )\n{\n    HANDLE semaphoreHandle;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (ReadPointerAcquire(Handle))\n        return;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        NULL,\n        OBJ_EXCLUSIVE,\n        NULL,\n        NULL\n        );\n\n    NtCreateSemaphore(\n        &semaphoreHandle,\n        SEMAPHORE_ALL_ACCESS,\n        &objectAttributes,\n        0,\n        MAXLONG\n        );\n\n    assert(semaphoreHandle);\n\n    if (_InterlockedCompareExchangePointer(\n        Handle,\n        semaphoreHandle,\n        NULL\n        ) != NULL)\n    {\n        NtClose(semaphoreHandle);\n    }\n}\n\nFORCEINLINE ULONG PhpGetSpinCount(\n    VOID\n    )\n{\n    if (PhSystemBasicInformation.NumberOfProcessors > 1)\n        return 4000;\n    else\n        return 0;\n}\n\n_May_raise_\n_Acquires_exclusive_lock_(*FastLock)\nVOID FASTCALL PhfAcquireFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n    ULONG i = 0;\n    ULONG spinCount;\n\n    spinCount = PhpGetSpinCount();\n\n    while (TRUE)\n    {\n        value = ReadULongAcquire(&FastLock->Value);\n\n        if (!(value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING)))\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_OWNED,\n                value\n                ) == value)\n                break;\n        }\n        else if (i >= spinCount)\n        {\n            PhpEnsureEventCreated(&FastLock->ExclusiveWakeEvent);\n\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_EXCLUSIVE_WAITERS_INC,\n                value\n                ) == value)\n            {\n                if (NtWaitForSingleObject(\n                    FastLock->ExclusiveWakeEvent,\n                    FALSE,\n                    NULL\n                    ) != STATUS_WAIT_0)\n                    PhRaiseStatus(STATUS_UNSUCCESSFUL);\n\n                do\n                {\n                    value = FastLock->Value;\n                } while (_InterlockedCompareExchange(\n                    &FastLock->Value,\n                    value + PH_LOCK_OWNED - PH_LOCK_EXCLUSIVE_WAKING,\n                    value\n                    ) != value);\n\n                break;\n            }\n        }\n\n        i++;\n        YieldProcessor();\n    }\n}\n\n_May_raise_\n_Acquires_shared_lock_(*FastLock)\nVOID FASTCALL PhfAcquireFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n    ULONG i = 0;\n    ULONG spinCount;\n\n    spinCount = PhpGetSpinCount();\n\n    while (TRUE)\n    {\n        value = ReadULongAcquire(&FastLock->Value);\n\n        if (!(value & (\n            PH_LOCK_OWNED |\n            (PH_LOCK_SHARED_OWNERS_MASK << PH_LOCK_SHARED_OWNERS_SHIFT) |\n            PH_LOCK_EXCLUSIVE_MASK\n            )))\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC,\n                value\n                ) == value)\n                break;\n        }\n        else if (\n            (value & PH_LOCK_OWNED) &&\n            ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 0 &&\n            !(value & PH_LOCK_EXCLUSIVE_MASK)\n            )\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_SHARED_OWNERS_INC,\n                value\n                ) == value)\n                break;\n        }\n        else if (i >= spinCount)\n        {\n            PhpEnsureEventCreated(&FastLock->SharedWakeEvent);\n\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_SHARED_WAITERS_INC,\n                value\n                ) == value)\n            {\n                if (NtWaitForSingleObject(\n                    FastLock->SharedWakeEvent,\n                    FALSE,\n                    NULL\n                    ) != STATUS_WAIT_0)\n                    PhRaiseStatus(STATUS_UNSUCCESSFUL);\n\n                continue;\n            }\n        }\n\n        i++;\n        YieldProcessor();\n    }\n}\n\n_Releases_exclusive_lock_(*FastLock)\nVOID FASTCALL PhfReleaseFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n\n    while (TRUE)\n    {\n        value = ReadULongAcquire(&FastLock->Value);\n\n        if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK)\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING - PH_LOCK_EXCLUSIVE_WAITERS_INC,\n                value\n                ) == value)\n            {\n                NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL);\n\n                break;\n            }\n        }\n        else\n        {\n            ULONG sharedWaiters;\n\n            sharedWaiters = (value >> PH_LOCK_SHARED_WAITERS_SHIFT) & PH_LOCK_SHARED_WAITERS_MASK;\n\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value & ~(PH_LOCK_OWNED | (PH_LOCK_SHARED_WAITERS_MASK << PH_LOCK_SHARED_WAITERS_SHIFT)),\n                value\n                ) == value)\n            {\n                if (sharedWaiters)\n                    NtReleaseSemaphore(FastLock->SharedWakeEvent, sharedWaiters, 0);\n\n                break;\n            }\n        }\n\n        YieldProcessor();\n    }\n}\n\n_Releases_shared_lock_(*FastLock)\nVOID FASTCALL PhfReleaseFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n\n    while (TRUE)\n    {\n        value = ReadULongAcquire(&FastLock->Value);\n\n        if (((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 1)\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value - PH_LOCK_SHARED_OWNERS_INC,\n                value\n                ) == value)\n                break;\n        }\n        else if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK)\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING -\n                PH_LOCK_SHARED_OWNERS_INC - PH_LOCK_EXCLUSIVE_WAITERS_INC,\n                value\n                ) == value)\n            {\n                NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL);\n\n                break;\n            }\n        }\n        else\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value - PH_LOCK_OWNED - PH_LOCK_SHARED_OWNERS_INC,\n                value\n                ) == value)\n                break;\n        }\n\n        YieldProcessor();\n    }\n}\n\n_When_(return != 0, _Acquires_exclusive_lock_(*FastLock))\nBOOLEAN FASTCALL PhfTryAcquireFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n\n    value = ReadULongAcquire(&FastLock->Value);\n\n    if (value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING))\n        return FALSE;\n\n    return _InterlockedCompareExchange(\n        &FastLock->Value,\n        value + PH_LOCK_OWNED,\n        value\n        ) == value;\n}\n\n_When_(return != 0, _Acquires_shared_lock_(*FastLock))\nBOOLEAN FASTCALL PhfTryAcquireFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n\n    value = ReadULongAcquire(&FastLock->Value);\n\n    if (value & PH_LOCK_EXCLUSIVE_MASK)\n        return FALSE;\n\n    if (!(value & PH_LOCK_OWNED))\n    {\n        return _InterlockedCompareExchange(\n            &FastLock->Value,\n            value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC,\n            value\n            ) == value;\n    }\n    else if ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK)\n    {\n        return _InterlockedCompareExchange(\n            &FastLock->Value,\n            value + PH_LOCK_SHARED_OWNERS_INC,\n            value\n            ) == value;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n"
  },
  {
    "path": "phlib/filepool.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011\n *\n */\n\n/*\n * File pool allows blocks of storage to be allocated from a file. Each file looks like this:\n *\n * Segment 0 __________________________________________________________\n * |              |                |              |                |\n * | Block Header |  File Header   | Block Header | Segment Header |\n * |______________|________________|______________|________________|\n * |              |                |              |                |\n * | Block Header |    User Data   | Block Header |    User Data   |\n * |______________|________________|______________|________________|\n * |              |                |              |                |\n * |      ...     |       ...      |     ...      |      ...       |\n * |______________|________________|______________|________________|\n * Segment 1 __________________________________________________________\n * |              |                |              |                |\n * | Block Header | Segment Header | Block Header |    User Data   |\n * |______________|________________|______________|________________|\n * |              |                |              |                |\n * |      ...     |       ...      |     ...      |      ...       |\n * |______________|________________|______________|________________|\n * Segment 2 __________________________________________________________\n * |              |                |              |                |\n * |      ...     |       ...      |     ...      |      ...       |\n * |______________|________________|______________|________________|\n *\n */\n\n/*\n * A file consists of a variable number of segments, with the segment size specified as a power of\n * two. Each segment contains a fixed number of blocks, leading to a variable block size. Every\n * allocation made by the user is an allocation of a certain number of blocks, with enough space for\n * the block header. This is placed at the beginning of each allocation and contains the number of\n * blocks in the allocation (a better name for it would be the allocation header).\n *\n * Block management in each segment is handled by a bitmap which is stored in the segment header at\n * the beginning of each segment. The first segment (segment 0) is special with the file header\n * being placed immediately after an initial block header. This is because the segment size is\n * stored in the file header, and without it we cannot calculate the block size, which is used to\n * locate everything else in the file.\n *\n * To speed up allocations a number of free lists are maintained which categorize each segment based\n * on how many free blocks they have. This means we can avoid trying to allocate from every existing\n * segment before finding out we have to allocate a new segment, or trying to allocate from segments\n * without the required number of free blocks. The downside of this technique is that it doesn't\n * account for fragmentation within the allocation bitmap.\n *\n * Each segment is mapped in separately, and each view is cached. Even after a view becomes inactive\n * (has a reference count of 0) it remains mapped in until the maximum number of inactive views is\n * reached.\n */\n\n#include <ph.h>\n#include <filepool.h>\n\n#include <filepoolp.h>\n\n/**\n * Creates or opens a file pool.\n *\n * \\param Pool A variable which receives the file pool instance.\n * \\param FileHandle A handle to the file.\n * \\param ReadOnly TRUE to disallow writes to the file.\n * \\param Parameters Parameters for on-disk and runtime structures.\n */\nNTSTATUS PhCreateFilePool(\n    _Out_ PPH_FILE_POOL *Pool,\n    _In_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status;\n    PPH_FILE_POOL pool;\n    LARGE_INTEGER fileSize;\n    PH_FILE_POOL_PARAMETERS localParameters;\n    BOOLEAN creating;\n    HANDLE sectionHandle;\n    PPH_FP_BLOCK_HEADER initialBlock;\n    PPH_FP_FILE_HEADER header;\n    ULONG i;\n\n    if (Parameters)\n    {\n        PhpValidateFilePoolParameters(Parameters);\n    }\n    else\n    {\n        PhpSetDefaultFilePoolParameters(&localParameters);\n        Parameters = &localParameters;\n    }\n\n    pool = PhAllocate(sizeof(PH_FILE_POOL));\n    memset(pool, 0, sizeof(PH_FILE_POOL));\n\n    pool->FileHandle = FileHandle;\n    pool->ReadOnly = ReadOnly;\n\n    if (!NT_SUCCESS(status = PhGetFileSize(FileHandle, &fileSize)))\n        goto CleanupExit;\n\n    creating = FALSE;\n\n    // If the file is smaller than the page size, assume we're creating a new file.\n    if (fileSize.QuadPart < PAGE_SIZE)\n    {\n        if (ReadOnly)\n        {\n            status = STATUS_BAD_FILE_TYPE;\n            goto CleanupExit;\n        }\n\n        fileSize.QuadPart = PAGE_SIZE;\n\n        if (!NT_SUCCESS(status = PhSetFileSize(FileHandle, &fileSize)))\n            goto CleanupExit;\n\n        creating = TRUE;\n    }\n\n    // Create a section.\n    status = PhCreateSection(\n        &sectionHandle,\n        SECTION_ALL_ACCESS,\n        &fileSize,\n        !ReadOnly ? PAGE_READWRITE : PAGE_READONLY,\n        SEC_COMMIT,\n        FileHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    pool->SectionHandle = sectionHandle;\n\n    // Map in the first segment, set up initial parameters, then remap the first segment.\n\n    if (!NT_SUCCESS(status = PhFppMapRange(pool, 0, PAGE_SIZE, &initialBlock)))\n        goto CleanupExit;\n\n    header = (PPH_FP_FILE_HEADER)&initialBlock->Body;\n\n    if (creating)\n    {\n        header->Magic = PH_FP_MAGIC;\n        header->SegmentShift = Parameters->SegmentShift;\n        header->SegmentCount = 1;\n\n        for (i = 0; i < PH_FP_FREE_LIST_COUNT; i++)\n            header->FreeLists[i] = ULONG_MAX;\n    }\n    else\n    {\n        if (header->Magic != PH_FP_MAGIC)\n        {\n            PhFppUnmapRange(pool, initialBlock);\n            status = STATUS_BAD_FILE_TYPE;\n            goto CleanupExit;\n        }\n    }\n\n    pool->SegmentShift = header->SegmentShift;\n    pool->SegmentSize = 1 << pool->SegmentShift;\n\n    pool->BlockShift = pool->SegmentShift - PH_FP_BLOCK_COUNT_SHIFT;\n    pool->BlockSize = 1 << pool->BlockShift;\n    pool->FileHeaderBlockSpan = (sizeof(PH_FP_FILE_HEADER) + pool->BlockSize - 1) >> pool->BlockShift;\n    pool->SegmentHeaderBlockSpan = (sizeof(PH_FP_SEGMENT_HEADER) + pool->BlockSize - 1) >> pool->BlockShift;\n\n    // Unmap the first segment and remap with the new segment size.\n\n    PhFppUnmapRange(pool, initialBlock);\n\n    if (creating)\n    {\n        // Extend the section so it fits the entire first segment.\n        if (!NT_SUCCESS(status = PhFppExtendRange(pool, pool->SegmentSize)))\n            goto CleanupExit;\n    }\n\n    // Runtime structure initialization\n\n    PhInitializeFreeList(&pool->ViewFreeList, sizeof(PH_FILE_POOL_VIEW), 32);\n    pool->ByIndexSize = 32;\n    pool->ByIndexBuckets = PhAllocate(sizeof(PPH_FILE_POOL_VIEW) * pool->ByIndexSize);\n    memset(pool->ByIndexBuckets, 0, sizeof(PPH_FILE_POOL_VIEW) * pool->ByIndexSize);\n    PhInitializeAvlTree(&pool->ByBaseSet, PhpFilePoolViewByBaseCompareFunction);\n\n    pool->MaximumInactiveViews = Parameters->MaximumInactiveViews;\n    InitializeListHead(&pool->InactiveViewsListHead);\n\n    // File structure initialization\n\n    pool->FirstBlockOfFirstSegment = PhFppReferenceSegment(pool, 0);\n    pool->Header = (PPH_FP_FILE_HEADER)&pool->FirstBlockOfFirstSegment->Body;\n\n    if (creating)\n    {\n        PPH_FP_BLOCK_HEADER segmentHeaderBlock;\n\n        // Set up the first segment properly.\n\n        pool->FirstBlockOfFirstSegment->Span = pool->FileHeaderBlockSpan;\n        segmentHeaderBlock = (PPH_FP_BLOCK_HEADER)PTR_ADD_OFFSET(pool->FirstBlockOfFirstSegment, (pool->FileHeaderBlockSpan << pool->BlockShift));\n        PhFppInitializeSegment(pool, segmentHeaderBlock, pool->FileHeaderBlockSpan);\n\n        pool->Header->FreeLists[1] = 0;\n    }\n\nCleanupExit:\n    if (NT_SUCCESS(status))\n    {\n        *Pool = pool;\n    }\n    else\n    {\n        // Don't close the file handle the user passed in.\n        pool->FileHandle = NULL;\n        PhDestroyFilePool(pool);\n    }\n\n    return status;\n}\n\n/**\n * Creates or opens a file pool.\n *\n * \\param Pool A variable which receives the file pool instance.\n * \\param FileName The file name of the file pool.\n * \\param ReadOnly TRUE to disallow writes to the file.\n * \\param ShareAccess The file access granted to other threads.\n * \\param CreateDisposition The action to perform if the file does or does not exist. See\n * PhCreateFileWin32() for more information.\n * \\param Parameters Parameters for on-disk and runtime structures.\n */\nNTSTATUS PhCreateFilePool2(\n    _Out_ PPH_FILE_POOL *Pool,\n    _In_ PCWSTR FileName,\n    _In_ BOOLEAN ReadOnly,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status;\n    PPH_FILE_POOL pool;\n    HANDLE fileHandle;\n    ULONG createStatus;\n\n    if (!NT_SUCCESS(status = PhCreateFileWin32Ex(\n        &fileHandle,\n        FileName,\n        !ReadOnly ? (FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE) : FILE_GENERIC_READ,\n        NULL,\n        FILE_ATTRIBUTE_NORMAL,\n        ShareAccess,\n        CreateDisposition,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        &createStatus\n        )))\n    {\n        return status;\n    }\n\n    status = PhCreateFilePool(&pool, fileHandle, ReadOnly, Parameters);\n\n    if (NT_SUCCESS(status))\n    {\n        *Pool = pool;\n    }\n    else\n    {\n        if (!ReadOnly && createStatus == FILE_CREATED)\n        {\n            FILE_DISPOSITION_INFORMATION dispositionInfo;\n            IO_STATUS_BLOCK isb;\n\n            dispositionInfo.DeleteFile = TRUE;\n            NtSetInformationFile(fileHandle, &isb, &dispositionInfo, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation);\n        }\n\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\n/**\n * Frees resources used by a file pool instance.\n *\n * \\param Pool The file pool.\n */\nVOID PhDestroyFilePool(\n    _In_ _Post_invalid_ PPH_FILE_POOL Pool\n    )\n{\n    ULONG i;\n    PLIST_ENTRY head;\n    PLIST_ENTRY entry;\n    PPH_FILE_POOL_VIEW view;\n\n    // Unmap all views.\n    for (i = 0; i < Pool->ByIndexSize; i++)\n    {\n        if (head = Pool->ByIndexBuckets[i])\n        {\n            entry = head;\n\n            do\n            {\n                view = CONTAINING_RECORD(entry, PH_FILE_POOL_VIEW, ByIndexListEntry);\n                entry = entry->Flink;\n                PhFppUnmapRange(Pool, view->Base);\n                PhFreeToFreeList(&Pool->ViewFreeList, view);\n            } while (entry != head);\n        }\n    }\n\n    if (Pool->ByIndexBuckets)\n        PhFree(Pool->ByIndexBuckets);\n\n    PhDeleteFreeList(&Pool->ViewFreeList);\n\n    if (Pool->SectionHandle)\n        NtClose(Pool->SectionHandle);\n    if (Pool->FileHandle)\n        NtClose(Pool->FileHandle);\n\n    PhFree(Pool);\n}\n\n/**\n * Validates and corrects file pool parameters.\n *\n * \\param Parameters The parameters structure which is validated and modified if necessary.\n */\nNTSTATUS PhpValidateFilePoolParameters(\n    _Inout_ PPH_FILE_POOL_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    // 16 <= SegmentShift <= 28\n\n    if (Parameters->SegmentShift < 16)\n    {\n        Parameters->SegmentShift = 16;\n        status = STATUS_SOME_NOT_MAPPED;\n    }\n\n    if (Parameters->SegmentShift > 28)\n    {\n        Parameters->SegmentShift = 28;\n        status = STATUS_SOME_NOT_MAPPED;\n    }\n\n    return status;\n}\n\n/**\n * Creates default file pool parameters.\n *\n * \\param Parameters The parameters structure which receives the default parameter values.\n */\nVOID PhpSetDefaultFilePoolParameters(\n    _Out_ PPH_FILE_POOL_PARAMETERS Parameters\n    )\n{\n    Parameters->SegmentShift = 18; // 256kB\n    Parameters->MaximumInactiveViews = 128;\n}\n\n/**\n * Allocates a block from a file pool.\n *\n * \\param Pool The file pool.\n * \\param Size The number of bytes to allocate.\n * \\param Rva A variable which receives the relative virtual address of the allocated block.\n *\n * \\return A pointer to the allocated block. You must call PhDereferenceFilePool() or\n * PhDereferenceFilePoolByRva() when you no longer need a reference to the block.\n *\n * \\remarks The returned pointer is not valid beyond the lifetime of the file pool instance. Use the\n * relative virtual address if you need a permanent reference to the allocated block.\n */\nPVOID PhAllocateFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Size,\n    _Out_opt_ PULONG Rva\n    )\n{\n    PPH_FP_BLOCK_HEADER blockHeader;\n    ULONG numberOfBlocks;\n    PPH_FP_BLOCK_HEADER firstBlock;\n    PPH_FP_SEGMENT_HEADER segmentHeader;\n    ULONG freeListIndex;\n    ULONG freeListLimit;\n    ULONG segmentIndex;\n    ULONG nextSegmentIndex;\n    ULONG newFreeListIndex;\n\n    // Calculate the number of blocks needed for the allocation.\n    numberOfBlocks = (FIELD_OFFSET(PH_FP_BLOCK_HEADER, Body) + Size + Pool->BlockSize - 1) >> Pool->BlockShift;\n\n    if (numberOfBlocks > PH_FP_BLOCK_COUNT - Pool->SegmentHeaderBlockSpan)\n    {\n        // TODO: Perform a large allocation.\n        return NULL;\n    }\n\n    // Scan each applicable free list and try to allocate from those segments.\n\n    freeListLimit = PhFppComputeFreeListIndex(Pool, numberOfBlocks);\n\n    for (freeListIndex = 0; freeListIndex <= freeListLimit; freeListIndex++)\n    {\n        segmentIndex = Pool->Header->FreeLists[freeListIndex];\n\n        while (segmentIndex != ULONG_MAX)\n        {\n            firstBlock = PhFppReferenceSegment(Pool, segmentIndex);\n\n            if (!firstBlock)\n                return NULL;\n\n            segmentHeader = PhFppGetHeaderSegment(Pool, firstBlock);\n            nextSegmentIndex = segmentHeader->FreeFlink;\n\n            blockHeader = PhFppAllocateBlocks(Pool, firstBlock, segmentHeader, numberOfBlocks);\n\n            if (blockHeader)\n                goto BlockAllocated;\n\n            PhFppDereferenceSegment(Pool, segmentIndex);\n            segmentIndex = nextSegmentIndex;\n        }\n    }\n\n    // No segments have the required number of contiguous free blocks. Allocate a new one.\n\n    firstBlock = PhFppAllocateSegment(Pool, &segmentIndex);\n\n    if (!firstBlock)\n        return NULL;\n\n    freeListIndex = 0;\n    segmentHeader = PhFppGetHeaderSegment(Pool, firstBlock);\n    blockHeader = PhFppAllocateBlocks(Pool, firstBlock, segmentHeader, numberOfBlocks);\n\n    if (!blockHeader)\n    {\n        PhFppDereferenceSegment(Pool, segmentIndex);\n        return NULL;\n    }\n\nBlockAllocated:\n\n    // Compute the new free list index of the segment and move it to another free list if necessary.\n\n    newFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks);\n\n    if (newFreeListIndex != freeListIndex)\n    {\n        PhFppRemoveFreeList(Pool, freeListIndex, segmentIndex, segmentHeader);\n        PhFppInsertFreeList(Pool, newFreeListIndex, segmentIndex, segmentHeader);\n    }\n\n    if (Rva)\n    {\n        *Rva = PhFppEncodeRva(Pool, segmentIndex, firstBlock, &blockHeader->Body);\n    }\n\n    return &blockHeader->Body;\n}\n\n/**\n * Frees a block.\n *\n * \\param Pool The file pool.\n * \\param SegmentIndex The index of the segment containing the block.\n * \\param FirstBlock The first block of the segment containing the block.\n * \\param Block A pointer to the block.\n */\nVOID PhpFreeFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _In_ PVOID Block\n    )\n{\n    PPH_FP_SEGMENT_HEADER segmentHeader;\n    ULONG oldFreeListIndex;\n    ULONG newFreeListIndex;\n\n    segmentHeader = PhFppGetHeaderSegment(Pool, FirstBlock);\n    oldFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks);\n    PhFppFreeBlocks(Pool, FirstBlock, segmentHeader, PhFppGetHeaderBlock(Pool, Block));\n    newFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks);\n\n    // Move the segment into another free list if needed.\n    if (newFreeListIndex != oldFreeListIndex)\n    {\n        PhFppRemoveFreeList(Pool, oldFreeListIndex, SegmentIndex, segmentHeader);\n        PhFppInsertFreeList(Pool, newFreeListIndex, SegmentIndex, segmentHeader);\n    }\n}\n\n/**\n * Frees a block allocated by PhAllocateFilePool().\n *\n * \\param Pool The file pool.\n * \\param Block A pointer to the block. The pointer is no longer valid after you call this function.\n * Do not use PhDereferenceFilePool() or PhDereferenceFilePoolByRva().\n */\nVOID PhFreeFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Block\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n    PPH_FP_BLOCK_HEADER firstBlock;\n\n    view = PhFppFindViewByBase(Pool, Block);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    firstBlock = view->Base;\n    PhpFreeFilePool(Pool, view->SegmentIndex, firstBlock, Block);\n    PhFppDereferenceView(Pool, view);\n}\n\n/**\n * Frees a block allocated by PhAllocateFilePool().\n *\n * \\param Pool The file pool.\n * \\param Rva The relative virtual address of the block.\n */\nBOOLEAN PhFreeFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    )\n{\n    ULONG segmentIndex;\n    ULONG offset;\n    PPH_FP_BLOCK_HEADER firstBlock;\n\n    offset = PhFppDecodeRva(Pool, Rva, &segmentIndex);\n\n    if (offset == ULONG_MAX)\n        return FALSE;\n\n    firstBlock = PhFppReferenceSegment(Pool, segmentIndex);\n\n    if (!firstBlock)\n        return FALSE;\n\n    PhpFreeFilePool(Pool, segmentIndex, firstBlock, PTR_ADD_OFFSET(firstBlock, offset));\n    PhFppDereferenceSegment(Pool, segmentIndex);\n\n    return TRUE;\n}\n\n/**\n * Increments the reference count for the specified address.\n *\n * \\param Pool The file pool.\n * \\param Address An address.\n */\nVOID PhReferenceFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    )\n{\n    PhFppReferenceSegmentByBase(Pool, Address);\n}\n\n/**\n * Decrements the reference count for the specified address.\n *\n * \\param Pool The file pool.\n * \\param Address An address.\n */\nVOID PhDereferenceFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    )\n{\n    PhFppDereferenceSegmentByBase(Pool, Address);\n}\n\n/**\n * Obtains a pointer for a relative virtual address, incrementing the reference count of the\n * address.\n *\n * \\param Pool The file pool.\n * \\param Rva A relative virtual address.\n */\nPVOID PhReferenceFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    )\n{\n    ULONG segmentIndex;\n    ULONG offset;\n    PPH_FP_BLOCK_HEADER firstBlock;\n\n    if (Rva == 0)\n        return NULL;\n\n    offset = PhFppDecodeRva(Pool, Rva, &segmentIndex);\n\n    if (offset == ULONG_MAX)\n        return NULL;\n\n    firstBlock = PhFppReferenceSegment(Pool, segmentIndex);\n\n    if (!firstBlock)\n        return NULL;\n\n    return PTR_ADD_OFFSET(firstBlock, offset);\n}\n\n/**\n * Decrements the reference count for the specified relative virtual address.\n *\n * \\param Pool The file pool.\n * \\param Rva A relative virtual address.\n */\nBOOLEAN PhDereferenceFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    )\n{\n    ULONG segmentIndex;\n    ULONG offset;\n\n    offset = PhFppDecodeRva(Pool, Rva, &segmentIndex);\n\n    if (offset == ULONG_MAX)\n        return FALSE;\n\n    PhFppDereferenceSegment(Pool, segmentIndex);\n\n    return TRUE;\n}\n\n/**\n * Obtains a relative virtual address for a pointer.\n *\n * \\param Pool The file pool.\n * \\param Address A pointer.\n *\n * \\return The relative virtual address.\n *\n * \\remarks No reference counts are changed.\n */\nULONG PhEncodeRvaFilePool(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    if (!Address)\n        return 0;\n\n    view = PhFppFindViewByBase(Pool, Address);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    return PhFppEncodeRva(Pool, view->SegmentIndex, view->Base, Address);\n}\n\n/**\n * Retrieves user data.\n *\n * \\param Pool The file pool.\n * \\param Context A variable which receives the user data.\n */\nVOID PhGetUserContextFilePool(\n    _In_ PPH_FILE_POOL Pool,\n    _Out_ PULONGLONG Context\n    )\n{\n    *Context = Pool->Header->UserContext;\n}\n\n/**\n * Stores user data.\n *\n * \\param Pool The file pool.\n * \\param Context A variable which contains the user data.\n */\nVOID PhSetUserContextFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PULONGLONG Context\n    )\n{\n    Pool->Header->UserContext = *Context;\n}\n\n/**\n * Extends a file pool.\n *\n * \\param Pool The file pool.\n * \\param NewSize The new size of the file, in bytes.\n */\nNTSTATUS PhFppExtendRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG NewSize\n    )\n{\n    LARGE_INTEGER newSectionSize;\n\n    newSectionSize.QuadPart = NewSize;\n\n    return NtExtendSection(Pool->SectionHandle, &newSectionSize);\n}\n\n/**\n * Maps in a view of a file pool.\n *\n * \\param Pool The file pool.\n * \\param Offset The offset of the view, in bytes.\n * \\param Size The size of the view, in bytes.\n * \\param Base A variable which receives the base address of the view.\n */\nNTSTATUS PhFppMapRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Offset,\n    _In_ ULONG Size,\n    _Out_ PVOID *Base\n    )\n{\n    NTSTATUS status;\n    PVOID baseAddress;\n    LARGE_INTEGER sectionOffset;\n    SIZE_T viewSize;\n\n    baseAddress = NULL;\n    sectionOffset.QuadPart = Offset;\n    viewSize = Size;\n\n    status = PhMapViewOfSection(\n        Pool->SectionHandle,\n        NtCurrentProcess(),\n        &baseAddress,\n        viewSize,\n        &sectionOffset,\n        &viewSize,\n        ViewUnmap,\n        0,\n        !Pool->ReadOnly ? PAGE_READWRITE : PAGE_READONLY\n        );\n\n    if (NT_SUCCESS(status))\n        *Base = baseAddress;\n\n    return status;\n}\n\n/**\n * Unmaps a view of a file pool.\n *\n * \\param Pool The file pool.\n * \\param Base The base address of the view.\n */\nNTSTATUS PhFppUnmapRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    )\n{\n    return PhUnmapViewOfSection(NtCurrentProcess(), Base);\n}\n\n/**\n * Initializes a segment.\n *\n * \\param Pool The file pool.\n * \\param BlockOfSegmentHeader The block header of the span containing the segment header.\n * \\param AdditionalBlocksUsed The number of blocks already allocated from the segment, excluding\n * the blocks comprising the segment header.\n */\nVOID PhFppInitializeSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Out_ PPH_FP_BLOCK_HEADER BlockOfSegmentHeader,\n    _In_ ULONG AdditionalBlocksUsed\n    )\n{\n    PPH_FP_SEGMENT_HEADER segmentHeader;\n    RTL_BITMAP bitmap;\n\n    BlockOfSegmentHeader->Span = Pool->SegmentHeaderBlockSpan;\n    segmentHeader = (PPH_FP_SEGMENT_HEADER)&BlockOfSegmentHeader->Body;\n\n    RtlInitializeBitMap(&bitmap, segmentHeader->Bitmap, PH_FP_BLOCK_COUNT);\n    RtlSetBits(&bitmap, 0, Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed);\n    segmentHeader->FreeBlocks = PH_FP_BLOCK_COUNT - (Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed);\n    segmentHeader->FreeFlink = ULONG_MAX;\n    segmentHeader->FreeBlink = ULONG_MAX;\n}\n\n/**\n * Allocates a segment.\n *\n * \\param Pool The file pool.\n * \\param NewSegmentIndex A variable which receives the index of the new segment.\n *\n * \\return A pointer to the first block of the segment.\n */\nPPH_FP_BLOCK_HEADER PhFppAllocateSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Out_ PULONG NewSegmentIndex\n    )\n{\n    ULONG newSize;\n    ULONG segmentIndex;\n    PPH_FP_BLOCK_HEADER firstBlock;\n    PPH_FP_SEGMENT_HEADER segmentHeader;\n\n    newSize = (Pool->Header->SegmentCount + 1) << Pool->SegmentShift;\n\n    if (!NT_SUCCESS(PhFppExtendRange(Pool, newSize)))\n        return NULL;\n\n    segmentIndex = Pool->Header->SegmentCount++;\n    firstBlock = PhFppReferenceSegment(Pool, segmentIndex);\n    PhFppInitializeSegment(Pool, firstBlock, 0);\n    segmentHeader = (PPH_FP_SEGMENT_HEADER)&firstBlock->Body;\n\n    PhFppInsertFreeList(Pool, 0, segmentIndex, segmentHeader);\n\n    *NewSegmentIndex = segmentIndex;\n\n    return firstBlock;\n}\n\n/**\n * Retrieves the header of a segment.\n *\n * \\param Pool The file pool.\n * \\param FirstBlock The first block of the segment.\n */\nPPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock\n    )\n{\n    if (FirstBlock != Pool->FirstBlockOfFirstSegment)\n    {\n        return (PPH_FP_SEGMENT_HEADER)&FirstBlock->Body;\n    }\n    else\n    {\n        // In the first segment, the segment header is after the file header.\n        return (PPH_FP_SEGMENT_HEADER)&((PPH_FP_BLOCK_HEADER)PTR_ADD_OFFSET(FirstBlock, (Pool->FileHeaderBlockSpan << Pool->BlockShift)))->Body;\n    }\n}\n\nVOID PhFppAddViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    ULONG index;\n    PLIST_ENTRY head;\n\n    index = View->SegmentIndex & (Pool->ByIndexSize - 1);\n    head = Pool->ByIndexBuckets[index];\n\n    if (head)\n    {\n        InsertHeadList(head, &View->ByIndexListEntry);\n    }\n    else\n    {\n        InitializeListHead(&View->ByIndexListEntry);\n        Pool->ByIndexBuckets[index] = &View->ByIndexListEntry;\n    }\n}\n\nVOID PhFppRemoveViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    ULONG index;\n    PLIST_ENTRY head;\n\n    index = View->SegmentIndex & (Pool->ByIndexSize - 1);\n    head = Pool->ByIndexBuckets[index];\n    assert(head);\n\n    // Unlink the entry from the chain.\n    RemoveEntryList(&View->ByIndexListEntry);\n\n    if (&View->ByIndexListEntry == head)\n    {\n        // This entry is currently the chain head.\n\n        // If this was the last entry in the chain, then indicate that the chain is empty.\n        // Otherwise, choose a new head.\n\n        if (IsListEmpty(head))\n            Pool->ByIndexBuckets[index] = NULL;\n        else\n            Pool->ByIndexBuckets[index] = head->Flink;\n    }\n}\n\n/**\n * Finds a view for the specified segment.\n *\n * \\param Pool The file pool.\n * \\param SegmentIndex The index of the segment.\n *\n * \\return The view for the segment, or NULL if no view is present for the segment.\n */\nPPH_FILE_POOL_VIEW PhFppFindViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    )\n{\n    ULONG index;\n    PLIST_ENTRY head;\n    PLIST_ENTRY entry;\n    PPH_FILE_POOL_VIEW view;\n\n    index = SegmentIndex & (Pool->ByIndexSize - 1);\n    head = Pool->ByIndexBuckets[index];\n\n    if (!head)\n        return NULL;\n\n    entry = head;\n\n    do\n    {\n        view = CONTAINING_RECORD(entry, PH_FILE_POOL_VIEW, ByIndexListEntry);\n\n        if (view->SegmentIndex == SegmentIndex)\n            return view;\n\n        entry = entry->Flink;\n    } while (entry != head);\n\n    return NULL;\n}\n\n_Function_class_(PH_AVL_TREE_COMPARE_FUNCTION)\nLONG NTAPI PhpFilePoolViewByBaseCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    )\n{\n    PPH_FILE_POOL_VIEW view1 = CONTAINING_RECORD(Links1, PH_FILE_POOL_VIEW, ByBaseLinks);\n    PPH_FILE_POOL_VIEW view2 = CONTAINING_RECORD(Links2, PH_FILE_POOL_VIEW, ByBaseLinks);\n\n    return uintptrcmp((ULONG_PTR)view1->Base, (ULONG_PTR)view2->Base);\n}\n\nVOID PhFppAddViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    PhAddElementAvlTree(&Pool->ByBaseSet, &View->ByBaseLinks);\n}\n\nVOID PhFppRemoveViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    PhRemoveElementAvlTree(&Pool->ByBaseSet, &View->ByBaseLinks);\n}\n\n/**\n * Finds a view containing the specified address.\n *\n * \\param Pool The file pool.\n * \\param Base The address.\n *\n * \\return The view containing the address, or NULL if no view is present for the address.\n */\nPPH_FILE_POOL_VIEW PhFppFindViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n    PPH_AVL_LINKS links;\n    PH_FILE_POOL_VIEW lookupView;\n\n    // This is an approximate search to find the target view in which the specified address lies.\n\n    lookupView.Base = Base;\n    links = PhUpperDualBoundElementAvlTree(&Pool->ByBaseSet, &lookupView.ByBaseLinks);\n\n    if (!links)\n        return NULL;\n\n    view = CONTAINING_RECORD(links, PH_FILE_POOL_VIEW, ByBaseLinks);\n\n    if ((ULONG_PTR)Base < (ULONG_PTR)view->Base + Pool->SegmentSize)\n        return view;\n\n    return NULL;\n}\n\nPPH_FILE_POOL_VIEW PhFppCreateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n    PVOID base;\n\n    // Map in the segment.\n    if (!NT_SUCCESS(PhFppMapRange(Pool, SegmentIndex << Pool->SegmentShift, Pool->SegmentSize, &base)))\n        return NULL;\n\n    // Create and add the view entry.\n\n    view = PhAllocateFromFreeList(&Pool->ViewFreeList);\n    memset(view, 0, sizeof(PH_FILE_POOL_VIEW));\n\n    view->RefCount = 1;\n    view->SegmentIndex = SegmentIndex;\n    view->Base = base;\n\n    PhFppAddViewByIndex(Pool, view);\n    PhFppAddViewByBase(Pool, view);\n\n    return view;\n}\n\nVOID PhFppDestroyView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    PhFppUnmapRange(Pool, View->Base);\n    PhFppRemoveViewByIndex(Pool, View);\n    PhFppRemoveViewByBase(Pool, View);\n\n    PhFreeToFreeList(&Pool->ViewFreeList, View);\n}\n\nVOID PhFppActivateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    RemoveEntryList(&View->InactiveViewsListEntry);\n    Pool->NumberOfInactiveViews--;\n}\n\nVOID PhFppDeactivateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    InsertHeadList(&Pool->InactiveViewsListHead, &View->InactiveViewsListEntry);\n    Pool->NumberOfInactiveViews++;\n\n    // If we have too many inactive views, destroy the least recent ones.\n    while (Pool->NumberOfInactiveViews > Pool->MaximumInactiveViews)\n    {\n        PLIST_ENTRY lruEntry;\n        PPH_FILE_POOL_VIEW lruView;\n\n        lruEntry = RemoveTailList(&Pool->InactiveViewsListHead);\n        Pool->NumberOfInactiveViews--;\n\n        assert(lruEntry != &Pool->InactiveViewsListHead);\n        lruView = CONTAINING_RECORD(lruEntry, PH_FILE_POOL_VIEW, InactiveViewsListEntry);\n        PhFppDestroyView(Pool, lruView);\n    }\n}\n\nVOID PhFppReferenceView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    if (View->RefCount == 0)\n    {\n        // The view is inactive, so make it active.\n        PhFppActivateView(Pool, View);\n    }\n\n    View->RefCount++;\n}\n\nVOID PhFppDereferenceView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    if (--View->RefCount == 0)\n    {\n        if (View->SegmentIndex == 0)\n            PhRaiseStatus(STATUS_INTERNAL_ERROR);\n\n        PhFppDeactivateView(Pool, View);\n    }\n}\n\nPPH_FP_BLOCK_HEADER PhFppReferenceSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    // Validate parameters.\n    if (SegmentIndex != 0 && SegmentIndex >= Pool->Header->SegmentCount)\n        return NULL;\n\n    // Try to get a cached view.\n\n    view = PhFppFindViewByIndex(Pool, SegmentIndex);\n\n    if (view)\n    {\n        PhFppReferenceView(Pool, view);\n\n        return (PPH_FP_BLOCK_HEADER)view->Base;\n    }\n\n    // No cached view, so create one.\n\n    view = PhFppCreateView(Pool, SegmentIndex);\n\n    if (!view)\n        return NULL;\n\n    return (PPH_FP_BLOCK_HEADER)view->Base;\n}\n\nVOID PhFppDereferenceSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    view = PhFppFindViewByIndex(Pool, SegmentIndex);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INTERNAL_ERROR);\n\n    PhFppDereferenceView(Pool, view);\n}\n\nVOID PhFppReferenceSegmentByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    view = PhFppFindViewByBase(Pool, Base);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INTERNAL_ERROR);\n\n    PhFppReferenceView(Pool, view);\n}\n\nVOID PhFppDereferenceSegmentByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    view = PhFppFindViewByBase(Pool, Base);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INTERNAL_ERROR);\n\n    PhFppDereferenceView(Pool, view);\n}\n\n/**\n * Allocates blocks from a segment.\n *\n * \\param Pool The file pool.\n * \\param FirstBlock The first block of the segment.\n * \\param SegmentHeader The header of the segment.\n * \\param NumberOfBlocks The number of blocks to allocate.\n *\n * \\return The header of the allocated span, or NULL if there is an insufficient number of\n * contiguous free blocks for the allocation.\n */\nPPH_FP_BLOCK_HEADER PhFppAllocateBlocks(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,\n    _In_ ULONG NumberOfBlocks\n    )\n{\n    RTL_BITMAP bitmap;\n    ULONG hintIndex;\n    ULONG foundIndex;\n    PPH_FP_BLOCK_HEADER blockHeader;\n\n    if (FirstBlock != Pool->FirstBlockOfFirstSegment)\n        hintIndex = Pool->SegmentHeaderBlockSpan;\n    else\n        hintIndex = Pool->SegmentHeaderBlockSpan + Pool->FileHeaderBlockSpan;\n\n    RtlInitializeBitMap(&bitmap, SegmentHeader->Bitmap, PH_FP_BLOCK_COUNT);\n\n    // Find a range of free blocks and mark them as in-use.\n    foundIndex = RtlFindClearBitsAndSet(&bitmap, NumberOfBlocks, hintIndex);\n\n    if (foundIndex == ULONG_MAX)\n    {\n        // No more space.\n        return NULL;\n    }\n\n    SegmentHeader->FreeBlocks -= NumberOfBlocks;\n\n    blockHeader = (PPH_FP_BLOCK_HEADER)PTR_ADD_OFFSET(FirstBlock, (foundIndex << Pool->BlockShift));\n    blockHeader->Flags = 0;\n    blockHeader->Span = NumberOfBlocks;\n\n    return blockHeader;\n}\n\n/**\n * Frees blocks in a segment.\n *\n * \\param Pool The file pool.\n * \\param FirstBlock The first block of the segment.\n * \\param SegmentHeader The header of the segment.\n * \\param BlockHeader The header of the allocated span.\n */\nVOID PhFppFreeBlocks(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,\n    _In_ PPH_FP_BLOCK_HEADER BlockHeader\n    )\n{\n    RTL_BITMAP bitmap;\n    ULONG startIndex;\n    ULONG blockSpan;\n\n    RtlInitializeBitMap(&bitmap, SegmentHeader->Bitmap, PH_FP_BLOCK_COUNT);\n\n    // Mark the blocks as free.\n    startIndex = PtrToUlong(PTR_SUB_OFFSET(BlockHeader, FirstBlock)) >> Pool->BlockShift;\n    blockSpan = BlockHeader->Span;\n    RtlClearBits(&bitmap, startIndex, blockSpan);\n    SegmentHeader->FreeBlocks += blockSpan;\n}\n\n/**\n * Computes the free list index (category) for a specified number of blocks.\n *\n * \\param Pool The file pool.\n * \\param NumberOfBlocks The number of free or required blocks.\n */\nULONG PhFppComputeFreeListIndex(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG NumberOfBlocks\n    )\n{\n    // Use a binary tree to speed up comparison.\n\n    if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 64)\n    {\n        if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 2)\n        {\n            if (NumberOfBlocks >= PH_FP_BLOCK_COUNT - Pool->SegmentHeaderBlockSpan)\n                return 0;\n            else\n                return 1;\n        }\n        else\n        {\n            if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 16)\n                return 2;\n            else\n                return 3;\n        }\n    }\n    else\n    {\n        if (NumberOfBlocks >= 4)\n        {\n            if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 256)\n                return 4;\n            else\n                return 5;\n        }\n        else\n        {\n            if (NumberOfBlocks >= 1)\n                return 6;\n            else\n                return 7;\n        }\n    }\n}\n\n/**\n * Inserts a segment into a free list.\n *\n * \\param Pool The file pool.\n * \\param FreeListIndex The index of a free list.\n * \\param SegmentIndex The index of the segment.\n * \\param SegmentHeader The header of the segment.\n */\nBOOLEAN PhFppInsertFreeList(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG FreeListIndex,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_SEGMENT_HEADER SegmentHeader\n    )\n{\n    ULONG oldSegmentIndex;\n    PPH_FP_BLOCK_HEADER oldSegmentFirstBlock = NULL;\n    PPH_FP_SEGMENT_HEADER oldSegmentHeader;\n\n    oldSegmentIndex = Pool->Header->FreeLists[FreeListIndex];\n\n    // Try to reference the segment before we commit any changes.\n\n    if (oldSegmentIndex != ULONG_MAX)\n    {\n        oldSegmentFirstBlock = PhFppReferenceSegment(Pool, oldSegmentIndex);\n\n        if (!oldSegmentFirstBlock)\n            return FALSE;\n    }\n\n    // Insert the segment into the list.\n\n    SegmentHeader->FreeBlink = ULONG_MAX;\n    SegmentHeader->FreeFlink = oldSegmentIndex;\n    Pool->Header->FreeLists[FreeListIndex] = SegmentIndex;\n\n    if (oldSegmentIndex != ULONG_MAX)\n    {\n        oldSegmentHeader = PhFppGetHeaderSegment(Pool, oldSegmentFirstBlock);\n        oldSegmentHeader->FreeBlink = SegmentIndex;\n        PhFppDereferenceSegment(Pool, oldSegmentIndex);\n    }\n\n    return TRUE;\n}\n\n/**\n * Removes a segment from a free list.\n *\n * \\param Pool The file pool.\n * \\param FreeListIndex The index of a free list.\n * \\param SegmentIndex The index of the segment.\n * \\param SegmentHeader The header of the segment.\n */\nBOOLEAN PhFppRemoveFreeList(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG FreeListIndex,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_SEGMENT_HEADER SegmentHeader\n    )\n{\n    ULONG flinkSegmentIndex;\n    PPH_FP_BLOCK_HEADER flinkSegmentFirstBlock = NULL;\n    PPH_FP_SEGMENT_HEADER flinkSegmentHeader = NULL;\n    ULONG blinkSegmentIndex;\n    PPH_FP_BLOCK_HEADER blinkSegmentFirstBlock = NULL;\n    PPH_FP_SEGMENT_HEADER blinkSegmentHeader = NULL;\n\n    flinkSegmentIndex = SegmentHeader->FreeFlink;\n    blinkSegmentIndex = SegmentHeader->FreeBlink;\n\n    // Try to reference the segments before we commit any changes.\n\n    if (flinkSegmentIndex != ULONG_MAX)\n    {\n        flinkSegmentFirstBlock = PhFppReferenceSegment(Pool, flinkSegmentIndex);\n\n        if (!flinkSegmentFirstBlock)\n            return FALSE;\n    }\n\n    if (blinkSegmentIndex != ULONG_MAX)\n    {\n        blinkSegmentFirstBlock = PhFppReferenceSegment(Pool, blinkSegmentIndex);\n\n        if (!blinkSegmentFirstBlock)\n        {\n            if (flinkSegmentIndex != ULONG_MAX)\n                PhFppDereferenceSegment(Pool, flinkSegmentIndex);\n\n            return FALSE;\n        }\n    }\n\n    // Unlink the segment from the list.\n\n    if (flinkSegmentIndex != ULONG_MAX)\n    {\n        flinkSegmentHeader = PhFppGetHeaderSegment(Pool, flinkSegmentFirstBlock);\n        flinkSegmentHeader->FreeBlink = blinkSegmentIndex;\n        PhFppDereferenceSegment(Pool, flinkSegmentIndex);\n    }\n\n    if (blinkSegmentIndex != ULONG_MAX)\n    {\n        blinkSegmentHeader = PhFppGetHeaderSegment(Pool, blinkSegmentFirstBlock);\n        blinkSegmentHeader->FreeFlink = flinkSegmentIndex;\n        PhFppDereferenceSegment(Pool, blinkSegmentIndex);\n    }\n    else\n    {\n        // The segment was the list head; select a new one.\n        Pool->Header->FreeLists[FreeListIndex] = flinkSegmentIndex;\n    }\n\n    return TRUE;\n}\n\n/**\n * Retrieves the header of a block.\n *\n * \\param Pool The file pool.\n * \\param Block A pointer to the body of the block.\n */\nPPH_FP_BLOCK_HEADER PhFppGetHeaderBlock(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ PVOID Block\n    )\n{\n    return CONTAINING_RECORD(Block, PH_FP_BLOCK_HEADER, Body);\n}\n\n/**\n * Creates a relative virtual address.\n *\n * \\param Pool The file pool.\n * \\param SegmentIndex The index of the segment containing \\a Address.\n * \\param FirstBlock The first block of the segment containing \\a Address.\n * \\param Address An address.\n */\nULONG PhFppEncodeRva(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _In_ PVOID Address\n    )\n{\n    return (SegmentIndex << Pool->SegmentShift) + PtrToUlong(PTR_SUB_OFFSET(Address, FirstBlock));\n}\n\n/**\n * Decodes a relative virtual address.\n *\n * \\param Pool The file pool.\n * \\param Rva The relative virtual address.\n * \\param SegmentIndex A variable which receives the segment index.\n *\n * \\return An offset into the segment specified by \\a SegmentIndex, or -1 if \\a Rva is invalid.\n */\nULONG PhFppDecodeRva(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva,\n    _Out_ PULONG SegmentIndex\n    )\n{\n    ULONG segmentIndex;\n\n    segmentIndex = Rva >> Pool->SegmentShift;\n\n    if (segmentIndex >= Pool->Header->SegmentCount)\n        return ULONG_MAX;\n\n    *SegmentIndex = segmentIndex;\n\n    return Rva & (Pool->SegmentSize - 1);\n}\n"
  },
  {
    "path": "phlib/filestream.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *\n */\n\n#include <ph.h>\n#include <filestream.h>\n#include <filestreamp.h>\n\nPPH_OBJECT_TYPE PhFileStreamType = NULL;\n\n/**\n * Creates a file stream from a file path.\n *\n * \\param FileStream Receives the new file stream object.\n * \\param FileName Path to the file to open.\n * \\param DesiredAccess Requested access mask.\n * \\param ShareAccess Share access flags.\n * \\param CreateDisposition Create/open disposition for the file.\n * \\param Flags Stream creation flags (buffering, append, asynchronous, etc.)\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateFileStream(\n    _Out_ PPH_FILE_STREAM *FileStream,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    PPH_FILE_STREAM fileStream;\n    HANDLE fileHandle;\n    ULONG createOptions;\n\n    if (Flags & PH_FILE_STREAM_ASYNCHRONOUS)\n        createOptions = FILE_NON_DIRECTORY_FILE;\n    else\n        createOptions = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT;\n\n    if (!NT_SUCCESS(status = PhCreateFileWin32(\n        &fileHandle,\n        FileName,\n        DesiredAccess,\n        FILE_ATTRIBUTE_NORMAL,\n        ShareAccess,\n        CreateDisposition,\n        createOptions\n        )))\n        return status;\n\n    if (!NT_SUCCESS(status = PhCreateFileStream2(\n        &fileStream,\n        fileHandle,\n        Flags,\n        PAGE_SIZE\n        )))\n    {\n        NtClose(fileHandle);\n        return status;\n    }\n\n    if (Flags & PH_FILE_STREAM_APPEND)\n    {\n        LARGE_INTEGER zero;\n\n        zero.QuadPart = 0;\n\n        if (!NT_SUCCESS(status = PhSeekFileStream(\n            fileStream,\n            &zero,\n            SeekEnd\n            )))\n        {\n            PhDereferenceObject(fileStream);\n            return status;\n        }\n    }\n\n    *FileStream = fileStream;\n\n    return status;\n}\n\n/**\n * Creates a file stream from an existing file handle.\n *\n * \\param FileStream Receives the new file stream object.\n * \\param FileHandle Open file handle (ownership depends on flags).\n * \\param Flags Stream flags (buffering, unowned handle, etc.)\n * \\param BufferLength Buffer size used for buffered operations.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateFileStream2(\n    _Out_ PPH_FILE_STREAM *FileStream,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG BufferLength\n    )\n{\n    static PH_INITONCE fileStreamInitOnce = PH_INITONCE_INIT;\n    PPH_FILE_STREAM fileStream;\n\n    if (PhBeginInitOnce(&fileStreamInitOnce))\n    {\n        PH_OBJECT_TYPE_PARAMETERS parameters;\n\n        parameters.FreeListSize = sizeof(PH_FILE_STREAM);\n        parameters.FreeListCount = 16;\n\n        PhFileStreamType = PhCreateObjectTypeEx(\n            L\"FileStream\",\n            PH_OBJECT_TYPE_USE_FREE_LIST,\n            PhpFileStreamDeleteProcedure,\n            &parameters\n            );\n\n        PhEndInitOnce(&fileStreamInitOnce);\n    }\n\n    fileStream = PhCreateObject(sizeof(PH_FILE_STREAM), PhFileStreamType);\n    fileStream->FileHandle = FileHandle;\n    fileStream->Flags = Flags;\n    fileStream->Position.QuadPart = 0;\n\n    if (!(Flags & PH_FILE_STREAM_UNBUFFERED))\n    {\n        fileStream->Buffer = NULL;\n        fileStream->BufferLength = BufferLength;\n    }\n    else\n    {\n        fileStream->Buffer = NULL;\n        fileStream->BufferLength = 0;\n    }\n\n    fileStream->ReadPosition = 0;\n    fileStream->ReadLength = 0;\n    fileStream->WritePosition = 0;\n\n    *FileStream = fileStream;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * The object delete procedure for file stream objects ensures\n * buffers are flushed, closes the handle if owned, and frees the buffer.\n *\n * \\param Object The file stream object being deleted.\n * \\param Flags Delete flags (unused).\n */\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpFileStreamDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_FILE_STREAM fileStream = (PPH_FILE_STREAM)Object;\n\n    PhFlushFileStream(fileStream, FALSE);\n\n    if (!(fileStream->Flags & PH_FILE_STREAM_HANDLE_UNOWNED))\n        NtClose(fileStream->FileHandle);\n\n    if (fileStream->Buffer)\n        PhFreePage(fileStream->Buffer);\n}\n\n/**\n * Verifies that a file stream's position matches the position held by the file object.\n */\nVOID PhVerifyFileStream(\n    _In_ PPH_FILE_STREAM FileStream\n    )\n{\n    NTSTATUS status;\n\n    // If the file object is asynchronous, the file object doesn't maintain its position.\n    if (!(FileStream->Flags & (\n        PH_FILE_STREAM_OWN_POSITION |\n        PH_FILE_STREAM_ASYNCHRONOUS\n        )))\n    {\n        FILE_POSITION_INFORMATION positionInfo;\n        IO_STATUS_BLOCK isb;\n\n        if (!NT_SUCCESS(status = NtQueryInformationFile(\n            FileStream->FileHandle,\n            &isb,\n            &positionInfo,\n            sizeof(FILE_POSITION_INFORMATION),\n            FilePositionInformation\n            )))\n            PhRaiseStatus(status);\n\n        if (FileStream->Position.QuadPart != positionInfo.CurrentByteOffset.QuadPart)\n            PhRaiseStatus(STATUS_INTERNAL_ERROR);\n    }\n}\n\n/**\n * Allocates the page-aligned buffer for a buffered file stream.\n *\n * \\param FileStream Stream requiring a buffer.\n * \\return STATUS_SUCCESS on success or STATUS_NO_MEMORY.\n */\nNTSTATUS PhpAllocateBufferFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    )\n{\n    FileStream->Buffer = PhAllocatePage(FileStream->BufferLength, NULL);\n\n    if (FileStream->Buffer)\n        return STATUS_SUCCESS;\n    else\n        return STATUS_NO_MEMORY;\n}\n\n/**\n * Performs a raw read from the underlying file object (unbuffered).\n *\n * \\param FileStream Stream to read from.\n * \\param Buffer Destination buffer.\n * \\param Length Number of bytes to read.\n * \\param ReadLength Receives number of bytes actually read (optional).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReadLength\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PLARGE_INTEGER position;\n\n    position = NULL;\n\n    if (FileStream->Flags & PH_FILE_STREAM_OWN_POSITION)\n        position = &FileStream->Position;\n\n    status = NtReadFile(\n        FileStream->FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        Buffer,\n        Length,\n        position,\n        NULL\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        // Wait for the operation to finish. This probably means we got called on an asynchronous\n        // file object.\n        status = NtWaitForSingleObject(FileStream->FileHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        FileStream->Position.QuadPart += isb.Information;\n\n        if (ReadLength)\n            *ReadLength = (ULONG)isb.Information;\n    }\n\n    return status;\n}\n\n/**\n * Reads from a file stream with optional buffering. If the stream is unbuffered\n * this forwards to the raw read routine. For buffered streams it satisfies\n * reads from the internal buffer where possible and fills it as needed.\n *\n * \\param FileStream Stream to read from.\n * \\param Buffer Destination buffer.\n * \\param Length Number of bytes to read.\n * \\param ReadLength Receives number of bytes read (optional).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReadLength\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    ULONG availableLength;\n    ULONG readLength;\n\n    if (FileStream->Flags & PH_FILE_STREAM_UNBUFFERED)\n    {\n        return PhpReadFileStream(\n            FileStream,\n            Buffer,\n            Length,\n            ReadLength\n            );\n    }\n\n    // How much do we have available to copy out of the buffer?\n    availableLength = FileStream->ReadLength - FileStream->ReadPosition;\n\n    if (availableLength == 0)\n    {\n        // Make sure buffered writes are flushed.\n        if (FileStream->WritePosition != 0)\n        {\n            if (!NT_SUCCESS(status = PhpFlushWriteFileStream(FileStream)))\n                return status;\n        }\n\n        // If this read is too big, pass it through.\n        if (Length >= FileStream->BufferLength)\n        {\n            // These are now invalid.\n            FileStream->ReadPosition = 0;\n            FileStream->ReadLength = 0;\n\n            return PhpReadFileStream(\n                FileStream,\n                Buffer,\n                Length,\n                ReadLength\n                );\n        }\n\n        if (!FileStream->Buffer)\n        {\n            if (!NT_SUCCESS(status = PhpAllocateBufferFileStream(FileStream)))\n                return status;\n        }\n\n        // Read as much as we can into our buffer.\n        if (!NT_SUCCESS(status = PhpReadFileStream(\n            FileStream,\n            FileStream->Buffer,\n            FileStream->BufferLength,\n            &readLength\n            )))\n            return status;\n\n        if (readLength == 0)\n        {\n            // No data read.\n            if (ReadLength)\n                *ReadLength = readLength;\n\n            return status;\n        }\n\n        FileStream->ReadPosition = 0;\n        FileStream->ReadLength = readLength;\n    }\n    else\n    {\n        readLength = availableLength;\n    }\n\n    if (readLength > Length)\n        readLength = Length;\n\n    // Try to satisfy the request from the buffer.\n    memcpy(\n        Buffer,\n        PTR_ADD_OFFSET(FileStream->Buffer, FileStream->ReadPosition),\n        readLength\n        );\n    FileStream->ReadPosition += readLength;\n\n    // If we didn't completely satisfy the request, read some more.\n    if (\n        readLength < Length &&\n        // Don't try to read more if the buffer wasn't even filled up last time. (No more to read.)\n        FileStream->ReadLength == FileStream->BufferLength\n        )\n    {\n        ULONG readLength2;\n\n        if (NT_SUCCESS(status = PhpReadFileStream(\n            FileStream,\n            PTR_ADD_OFFSET(Buffer, readLength),\n            Length - readLength,\n            &readLength2\n            )))\n        {\n            readLength += readLength2;\n            // These are now invalid.\n            FileStream->ReadPosition = 0;\n            FileStream->ReadLength = 0;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (ReadLength)\n            *ReadLength = readLength;\n    }\n\n    return status;\n}\n\n/**\n * Performs a raw write to the underlying file object (unbuffered).\n *\n * \\param FileStream Stream to write to.\n * \\param Buffer Source buffer.\n * \\param Length Number of bytes to write.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PLARGE_INTEGER position;\n\n    position = NULL;\n\n    if (FileStream->Flags & PH_FILE_STREAM_OWN_POSITION)\n        position = &FileStream->Position;\n\n    status = NtWriteFile(\n        FileStream->FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        Buffer,\n        Length,\n        position,\n        NULL\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        // Wait for the operation to finish. This probably means we got called on an asynchronous\n        // file object.\n        status = NtWaitForSingleObject(FileStream->FileHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        FileStream->Position.QuadPart += isb.Information;\n        FileStream->Flags |= PH_FILE_STREAM_WRITTEN;\n    }\n\n    return status;\n}\n\n/**\n * Writes to a file stream with optional buffering. For buffered streams\n * this will append to the internal buffer and flush as needed. For\n * unbuffered streams this forwards to the raw write routine.\n *\n * \\param FileStream Stream to write to.\n * \\param Buffer Source buffer.\n * \\param Length Number of bytes to write.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    ULONG availableLength;\n    ULONG writtenLength;\n\n    if (FileStream->Flags & PH_FILE_STREAM_UNBUFFERED)\n    {\n        return PhpWriteFileStream(\n            FileStream,\n            Buffer,\n            Length\n            );\n    }\n\n    if (FileStream->WritePosition == 0)\n    {\n        // Make sure buffered reads are flushed.\n        if (!NT_SUCCESS(status = PhpFlushReadFileStream(FileStream)))\n            return status;\n    }\n\n    if (FileStream->WritePosition != 0)\n    {\n        availableLength = FileStream->BufferLength - FileStream->WritePosition;\n\n        // Try to satisfy the request by copying the data to the buffer.\n        if (availableLength != 0)\n        {\n            writtenLength = availableLength;\n\n            if (writtenLength > Length)\n                writtenLength = Length;\n\n            memcpy(\n                PTR_ADD_OFFSET(FileStream->Buffer, FileStream->WritePosition),\n                Buffer,\n                writtenLength\n                );\n            FileStream->WritePosition += writtenLength;\n\n            if (writtenLength == Length)\n            {\n                // The request has been completely satisfied.\n                return status;\n            }\n\n            Buffer = PTR_ADD_OFFSET(Buffer, writtenLength);\n            Length -= writtenLength;\n        }\n\n        // If we didn't completely satisfy the request, it's because the buffer is full. Flush it.\n        if (!NT_SUCCESS(status = PhpWriteFileStream(\n            FileStream,\n            FileStream->Buffer,\n            FileStream->WritePosition\n            )))\n            return status;\n\n        FileStream->WritePosition = 0;\n    }\n\n    // If the write is too big, pass it through.\n    if (Length >= FileStream->BufferLength)\n    {\n        if (!NT_SUCCESS(status = PhpWriteFileStream(\n            FileStream,\n            Buffer,\n            Length\n            )))\n            return status;\n    }\n    else if (Length != 0)\n    {\n        if (!FileStream->Buffer)\n        {\n            if (!NT_SUCCESS(status = PhpAllocateBufferFileStream(FileStream)))\n                return status;\n        }\n\n        // Completely satisfy the request by copying the data to the buffer.\n        memcpy(\n            FileStream->Buffer,\n            Buffer,\n            Length\n            );\n        FileStream->WritePosition = Length;\n    }\n\n    return status;\n}\n\n/**\n * Flushes any buffered read state back to the file position. If there is unread\n * buffered data the stream position is moved backward to the first unread byte\n * and subsequent reads align with the file object.\n *\n * \\param FileStream Stream to flush read buffer from.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpFlushReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    if (FileStream->ReadLength - FileStream->ReadPosition != 0)\n    {\n        LARGE_INTEGER offset;\n\n        // We have some buffered read data, so our position is too far ahead. We need to move it\n        // back to the first unused byte.\n        offset.QuadPart = -(LONG)(FileStream->ReadLength - FileStream->ReadPosition);\n\n        if (!NT_SUCCESS(status = PhpSeekFileStream(\n            FileStream,\n            &offset,\n            SeekCurrent\n            )))\n            return status;\n    }\n\n    FileStream->ReadPosition = 0;\n    FileStream->ReadLength = 0;\n\n    return status;\n}\n\n/**\n * Flushes any buffered write data to the underlying file.\n *\n * \\param FileStream Stream to flush.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpFlushWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    if (!NT_SUCCESS(status = PhpWriteFileStream(\n        FileStream,\n        FileStream->Buffer,\n        FileStream->WritePosition\n        )))\n        return status;\n\n    FileStream->WritePosition = 0;\n\n    return status;\n}\n\n/**\n * Flushes the file stream buffers and optionally flushes the file through the OS.\n *\n * \\param FileStream A file stream object.\n * \\param Full TRUE to flush the file object through the operating system, otherwise FALSE to only\n * ensure the buffer is flushed to the operating system.\n */\nNTSTATUS PhFlushFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ BOOLEAN Full\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    if (FileStream->WritePosition != 0)\n    {\n        if (!NT_SUCCESS(status = PhpFlushWriteFileStream(FileStream)))\n            return status;\n    }\n\n    if (FileStream->ReadPosition != 0)\n    {\n        if (!NT_SUCCESS(status = PhpFlushReadFileStream(FileStream)))\n            return status;\n    }\n\n    if (Full && (FileStream->Flags & PH_FILE_STREAM_WRITTEN))\n    {\n        IO_STATUS_BLOCK isb;\n\n        if (!NT_SUCCESS(status = NtFlushBuffersFile(\n            FileStream->FileHandle,\n            &isb\n            )))\n            return status;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the logical position within the stream (taking buffered state into account).\n *\n * \\param FileStream Stream to query.\n * \\param Position Receives the calculated position.\n */\nVOID PhGetPositionFileStream(\n    _In_ PPH_FILE_STREAM FileStream,\n    _Out_ PLARGE_INTEGER Position\n    )\n{\n    Position->QuadPart =\n        FileStream->Position.QuadPart +\n        (FileStream->ReadPosition - FileStream->ReadLength) +\n        FileStream->WritePosition;\n}\n\n/**\n * Performs a seek operation that updates the internal position variable and, if required,\n * writes the position to the underlying file object. This does not account for buffered\n * read/write state; use PhSeekFileStream to handle buffers.\n *\n * \\param FileStream Stream to seek.\n * \\param Offset Offset value (interpretation per Origin).\n * \\param Origin Seek origin (SeekStart, SeekCurrent, SeekEnd).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpSeekFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Offset,\n    _In_ PH_SEEK_ORIGIN Origin\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    switch (Origin)\n    {\n    case SeekStart:\n        {\n            FileStream->Position = *Offset;\n        }\n        break;\n    case SeekCurrent:\n        {\n            FileStream->Position.QuadPart += Offset->QuadPart;\n        }\n        break;\n    case SeekEnd:\n        {\n            if (!NT_SUCCESS(status = PhGetFileSize(\n                FileStream->FileHandle,\n                &FileStream->Position\n                )))\n                return status;\n\n            FileStream->Position.QuadPart += Offset->QuadPart;\n        }\n        break;\n    }\n\n    if (!(FileStream->Flags & PH_FILE_STREAM_OWN_POSITION))\n    {\n        FILE_POSITION_INFORMATION positionInfo;\n        IO_STATUS_BLOCK isb;\n\n        positionInfo.CurrentByteOffset = FileStream->Position;\n\n        if (!NT_SUCCESS(status = NtSetInformationFile(\n            FileStream->FileHandle,\n            &isb,\n            &positionInfo,\n            sizeof(FILE_POSITION_INFORMATION),\n            FilePositionInformation\n            )))\n            return status;\n    }\n\n    return status;\n}\n\n/**\n * Public seek that handles buffered state (flushes writes, adjusts for buffered reads).\n *\n * \\param FileStream Stream to seek.\n * \\param Offset Offset value (interpretation per Origin).\n * \\param Origin Seek origin (SeekStart, SeekCurrent, SeekEnd).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSeekFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Offset,\n    _In_ PH_SEEK_ORIGIN Origin\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    LARGE_INTEGER offset;\n\n    offset = *Offset;\n\n    if (FileStream->WritePosition != 0)\n    {\n        if (!NT_SUCCESS(status = PhpFlushWriteFileStream(FileStream)))\n            return status;\n    }\n    else if (FileStream->ReadPosition != 0)\n    {\n        if (Origin == SeekCurrent)\n        {\n            // We have buffered read data, which means our position is too far ahead. Subtract this\n            // difference from the offset (which will affect the position accordingly).\n            offset.QuadPart -= FileStream->ReadLength - FileStream->ReadPosition;\n        }\n\n        // TODO: Try to keep some of the read buffer.\n        FileStream->ReadPosition = 0;\n        FileStream->ReadLength = 0;\n    }\n\n    if (!NT_SUCCESS(status = PhpSeekFileStream(\n        FileStream,\n        &offset,\n        Origin\n        )))\n        return status;\n\n    return status;\n}\n\n/**\n * Locks a byte range in the file.\n *\n * \\param FileStream Stream containing the file handle.\n * \\param Position Starting byte offset to lock.\n * \\param Length Length of the region to lock.\n * \\param Wait If TRUE, wait for the lock; otherwise return immediately if unavailable.\n * \\param Shared If TRUE, acquire a shared lock; otherwise exclusive.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhLockFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Position,\n    _In_ PLARGE_INTEGER Length,\n    _In_ BOOLEAN Wait,\n    _In_ BOOLEAN Shared\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtLockFile(\n        FileStream->FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        Position,\n        Length,\n        0,\n        !Wait,\n        !Shared\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        // Wait for the operation to finish. This probably means we got called on an asynchronous\n        // file object.\n        NtWaitForSingleObject(FileStream->FileHandle, FALSE, NULL);\n        status = isb.Status;\n    }\n\n    return status;\n}\n\n/**\n * Unlocks a previously locked byte range.\n *\n * \\param FileStream Stream containing the file handle.\n * \\param Position Starting byte offset of the locked region.\n * \\param Length Length of the region to unlock.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhUnlockFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Position,\n    _In_ PLARGE_INTEGER Length\n    )\n{\n    IO_STATUS_BLOCK isb;\n\n    return NtUnlockFile(\n        FileStream->FileHandle,\n        &isb,\n        Position,\n        Length,\n        0\n        );\n}\n\n/**\n * Sets the allocation and end-of-file size for the file.\n *\n * \\param FileStream Stream containing the file handle.\n * \\param AllocationSize Desired allocation / end-of-file size.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetAllocationSizeFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER AllocationSize\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    FILE_END_OF_FILE_INFORMATION endOfFileInfo;\n    FILE_ALLOCATION_INFORMATION allocationInfo;\n\n    memset(&endOfFileInfo, 0, sizeof(FILE_END_OF_FILE_INFORMATION));\n    endOfFileInfo.EndOfFile.QuadPart = AllocationSize->QuadPart;\n\n    if (!NT_SUCCESS(status = NtSetInformationFile(\n        FileStream->FileHandle,\n        &isb,\n        &endOfFileInfo,\n        sizeof(FILE_END_OF_FILE_INFORMATION),\n        FileEndOfFileInformation\n        )))\n        return status;\n\n    memset(&allocationInfo, 0, sizeof(FILE_ALLOCATION_INFORMATION));\n    allocationInfo.AllocationSize.QuadPart = AllocationSize->QuadPart;\n\n    if (!NT_SUCCESS(status = NtSetInformationFile(\n        FileStream->FileHandle,\n        &isb,\n        &allocationInfo,\n        sizeof(FILE_ALLOCATION_INFORMATION),\n        FileAllocationInformation\n        )))\n        return status;\n\n    return status;\n}\n\n/**\n * Writes a Unicode string as UTF-8 to the stream.\n *\n * \\param FileStream Stream to write to.\n * \\param String String reference to write.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhWriteStringAsUtf8FileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PPH_STRINGREF String\n    )\n{\n    return PhWriteStringAsUtf8FileStreamEx(FileStream, String->Buffer, String->Length);\n}\n\n/**\n * Writes a UTF-16 buffer as UTF-8 to the stream, handling large buffers in chunks.\n *\n * \\param FileStream Stream to write to.\n * \\param Buffer UTF-16 buffer to convert and write.\n * \\param Length The length of Buffer in bytes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhWriteStringAsUtf8FileStreamEx(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PCWSTR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    PH_STRINGREF block;\n    SIZE_T inPlaceUtf8Size = 0;\n    PCHAR inPlaceUtf8 = NULL;\n    PPH_BYTES utf8 = NULL;\n\n    if (Length > PAGE_SIZE)\n    {\n        // In UTF-8, the maximum number of bytes per code point is 4.\n        inPlaceUtf8Size = PAGE_SIZE / sizeof(WCHAR) * 4;\n        inPlaceUtf8 = PhAllocatePage(inPlaceUtf8Size, NULL);\n    }\n\n    while (Length != 0)\n    {\n        block.Buffer = (PWCH)Buffer;\n        block.Length = PAGE_SIZE;\n\n        if (block.Length > Length)\n            block.Length = Length;\n\n        if (inPlaceUtf8)\n        {\n            SIZE_T bytesInUtf8String;\n\n            status = PhConvertUtf16ToUtf8Buffer(\n                inPlaceUtf8,\n                inPlaceUtf8Size,\n                &bytesInUtf8String,\n                block.Buffer,\n                block.Length\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhWriteFileStream(FileStream, inPlaceUtf8, (ULONG)bytesInUtf8String);\n        }\n        else\n        {\n            utf8 = PhConvertUtf16ToUtf8Ex(block.Buffer, block.Length);\n\n            if (!utf8)\n            {\n                status = STATUS_INVALID_PARAMETER;\n                goto CleanupExit;\n            }\n\n            status = PhWriteFileStream(FileStream, utf8->Buffer, (ULONG)utf8->Length);\n            PhDereferenceObject(utf8);\n        }\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        Buffer += block.Length / sizeof(WCHAR);\n        Length -= block.Length;\n    }\n\nCleanupExit:\n    if (inPlaceUtf8)\n        PhFreePage(inPlaceUtf8);\n\n    return status;\n}\n\n/**\n * Formats a Unicode string (va_list) and writes it as UTF-8 to the stream.\n *\n * \\param FileStream Stream to write to.\n * \\param Format printf-style format string.\n * \\param ArgPtr Variadic arguments (va_list).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhWriteStringFormatAsUtf8FileStream_V(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ _Printf_format_string_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n\n    string = PhFormatString_V(Format, ArgPtr);\n    status = PhWriteStringAsUtf8FileStream(FileStream, &string->sr);\n    PhDereferenceObject(string);\n\n    return status;\n}\n\n/**\n * Formats a Unicode string and writes it as UTF-8 to the stream.\n *\n * \\param FileStream Stream to write to.\n * \\param Format printf-style format string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhWriteStringFormatAsUtf8FileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ _Printf_format_string_ PCWSTR Format,\n    ...\n    )\n{\n    NTSTATUS status;\n    va_list argptr;\n\n    va_start(argptr, Format);\n    status = PhWriteStringFormatAsUtf8FileStream_V(FileStream, Format, argptr);\n    va_end(argptr);\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/firmware.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025\n *\n */\n\n#include <ph.h>\n\n#include <phfirmware.h>\n#include <ntintsafe.h>\n\n// https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/feature-discovery\n// private\ntypedef enum _HV_CPUID_FUNCTION\n{\n    HvCpuIdFunctionVersionAndFeatures = 0x00000001, // CPUID.01h.ECX:31 // if set, virtualization present\n    HvCpuIdFunctionHvVendorAndMaxFunction = 0x40000000, // HV_VENDOR_AND_MAX_FUNCTION\n    HvCpuIdFunctionHvInterface = 0x40000001, // HV_HYPERVISOR_INTERFACE_INFO\n    HvCpuIdFunctionMsHvVersion = 0x40000002, // HV_HYPERVISOR_VERSION_INFO\n    HvCpuIdFunctionMsHvFeatures = 0x40000003, // HV_HYPERVISOR_FEATURES/HV_X64_HYPERVISOR_FEATURES\n    HvCpuIdFunctionMsHvEnlightenmentInformation = 0x40000004, // HV_ENLIGHTENMENT_INFORMATION\n    HvCpuIdFunctionMsHvImplementationLimits = 0x40000005, // HV_IMPLEMENTATION_LIMITS\n    HvCpuIdFunctionMsHvHardwareFeatures = 0x40000006, // HV_X64_HYPERVISOR_HARDWARE_FEATURES\n    HvCpuIdFunctionMsHvCpuManagementFeatures = 0x40000007, // HV_X64_HYPERVISOR_CPU_MANAGEMENT_FEATURES\n    HvCpuIdFunctionMsHvSvmFeatures = 0x40000008, // HV_HYPERVISOR_SVM_FEATURES\n    HvCpuIdFunctionMsHvSkipLevelFeatures = 0x40000009, // HV_HYPERVISOR_SKIP_LEVEL_FEATURES // 1511+\n    HvCpuidFunctionMsHvNestedVirtFeatures = 0x4000000A, // HV_HYPERVISOR_NESTED_VIRT_FEATURES\n    HvCpuidFunctionMsHvIptFeatures = 0x4000000B, // HV_HYPERVISOR_IPT_FEATURES // 1903+\n    HvCpuIdFunctionMaxReserved\n} HV_CPUID_FUNCTION, *PHV_CPUID_FUNCTION;\n\n// https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/datatypes/hv_partition_privilege_mask\ntypedef union _HV_PARTITION_PRIVILEGE_MASK\n{\n    struct\n    {\n        // Access to virtual MSRs\n        UINT64 AccessVpRunTimeReg : 1;\n        UINT64 AccessPartitionReferenceCounter : 1;\n        UINT64 AccessSynicRegs : 1;\n        UINT64 AccessSyntheticTimerRegs : 1;\n        UINT64 AccessIntrCtrlRegs : 1;\n        UINT64 AccessHypercallMsrs : 1;\n        UINT64 AccessVpIndex : 1;\n        UINT64 AccessResetReg : 1;\n        UINT64 AccessStatsReg : 1;\n        UINT64 AccessPartitionReferenceTsc : 1;\n        UINT64 AccessGuestIdleReg : 1;\n        UINT64 AccessFrequencyRegs : 1;\n        UINT64 AccessDebugRegs : 1;\n        UINT64 AccessReenlightenmentControls : 1;\n        UINT64 Reserved1 : 18;\n\n        // Access to hypercalls\n        UINT64 CreatePartitions : 1;\n        UINT64 AccessPartitionId : 1;\n        UINT64 AccessMemoryPool : 1;\n        UINT64 Reserved2 : 1;\n        UINT64 PostMessages : 1;\n        UINT64 SignalEvents : 1;\n        UINT64 CreatePort : 1;\n        UINT64 ConnectPort : 1;\n        UINT64 AccessStats : 1;\n        UINT64 Reserved3 : 2;\n        UINT64 Debugging : 1;\n        UINT64 CpuManagement : 1;\n        UINT64 Reserved4 : 1;\n        UINT64 Reserved5 : 1;\n        UINT64 Reserved6 : 1;\n        UINT64 AccessVSM : 1;\n        UINT64 AccessVpRegisters : 1;\n        UINT64 Reserved7 : 1;\n        UINT64 Reserved8 : 1;\n        UINT64 EnableExtendedHypercalls : 1;\n        UINT64 StartVirtualProcessor : 1;\n        UINT64 Reserved9 : 10;\n    };\n\n    UINT32 LowPart;\n    UINT32 HighPart;\n} HV_PARTITION_PRIVILEGE_MASK, *PHV_PARTITION_PRIVILEGE_MASK;\n\n// private\ntypedef struct _HV_VENDOR_AND_MAX_FUNCTION\n{\n    //\n    // Eax\n    //\n    UINT32 MaxFunctions;\n\n    //\n    // Ebx, Ecx, and Edx\n    //\n    UINT8 VendorName[12];\n} HV_VENDOR_AND_MAX_FUNCTION, *PHV_VENDOR_AND_MAX_FUNCTION;\nstatic_assert(sizeof(HV_VENDOR_AND_MAX_FUNCTION) == 16);\n\n// private\ntypedef enum _HV_HYPERVISOR_INTERFACE\n{\n    HvMicrosoftHypervisorInterface = 0x31237648, // '1#vH'\n    HvMicrosoftXboxNanovisor = 0x766E6258 ,      // 'vnbX'\n} HV_HYPERVISOR_INTERFACE, *PHV_HYPERVISOR_INTERFACE;\n\n// private\ntypedef struct _HV_HYPERVISOR_INTERFACE_INFO\n{\n    //\n    // Eax\n    //\n    UINT32 Interface; // HV_HYPERVISOR_INTERFACE\n\n    //\n    // Ebx\n    //\n    UINT32 Reserved1;\n\n    //\n    // Ecx\n    //\n    UINT32 Reserved2;\n\n    //\n    // Edx\n    //\n    UINT32 Reserved3;\n} HV_HYPERVISOR_INTERFACE_INFO, *PHV_HYPERVISOR_INTERFACE_INFO;\nstatic_assert(sizeof(HV_HYPERVISOR_INTERFACE_INFO) == 16);\n\n// private\ntypedef struct _HV_HYPERVISOR_VERSION_INFO\n{\n    //\n    // Eax\n    //\n    UINT32 BuildNumber;\n\n    //\n    // Ebx\n    //\n    UINT32 MinorVersion : 16;\n    UINT32 MajorVersion : 16;\n\n    //\n    // Ecx\n    //\n    UINT32 ServicePack;\n\n    //\n    // Edx\n    //\n    UINT32 ServiceNumber : 24;\n    UINT32 ServiceBranch : 8;\n} HV_HYPERVISOR_VERSION_INFO, *PHV_HYPERVISOR_VERSION_INFO;\nstatic_assert(sizeof(HV_HYPERVISOR_VERSION_INFO) == 16);\n\n// private\ntypedef struct _HV_HYPERVISOR_FEATURES\n{\n    //\n    // Eax and Ebx\n    //\n    HV_PARTITION_PRIVILEGE_MASK PartitionPrivileges;\n\n    //\n    // Ecx\n    //\n    UINT32 MaxSupportedCState : 4;\n    UINT32 HpetNeededForC3PowerState_Deprecated : 1;\n    UINT32 Reserved : 27;\n\n    //\n    // Edx\n    //\n    UINT32 MwaitAvailable_Deprecated : 1;\n    UINT32 GuestDebuggingAvailable : 1;\n    UINT32 PerformanceMonitorsAvailable : 1;\n    UINT32 CpuDynamicPartitioningAvailable : 1;\n    UINT32 XmmRegistersForFastHypercallAvailable : 1;\n    UINT32 GuestIdleAvailable : 1;\n    UINT32 HypervisorSleepStateSupportAvailable : 1;\n    UINT32 NumaDistanceQueryAvailable : 1;\n    UINT32 FrequencyRegsAvailable : 1;\n    UINT32 SyntheticMachineCheckAvailable : 1;\n    UINT32 GuestCrashRegsAvailable : 1;\n    UINT32 DebugRegsAvailable : 1;\n    UINT32 Npiep1Available : 1;\n    UINT32 DisableHypervisorAvailable : 1;\n    UINT32 Reserved1 : 18;\n} HV_HYPERVISOR_FEATURES, *PHV_HYPERVISOR_FEATURES;\nstatic_assert(sizeof(HV_HYPERVISOR_FEATURES) == 16);\n\n// private\ntypedef struct _HV_X64_HYPERVISOR_FEATURES\n{\n    //\n    // Eax and Ebx\n    //\n    HV_PARTITION_PRIVILEGE_MASK PartitionPrivileges;\n\n    //\n    // Ecx\n    //\n    UINT32 MaxSupportedCState : 4;\n    UINT32 HpetNeededForC3PowerState_Deprecated : 1;\n    UINT32 Reserved : 27;\n\n    //\n    // Edx\n    //\n    UINT32 MwaitAvailable_Deprecated : 1;\n    UINT32 GuestDebuggingAvailable : 1;\n    UINT32 PerformanceMonitorsAvailable : 1;\n    UINT32 CpuDynamicPartitioningAvailable : 1;\n    UINT32 XmmRegistersForFastHypercallAvailable : 1;\n    UINT32 GuestIdleAvailable : 1;\n    UINT32 HypervisorSleepStateSupportAvailable : 1;\n    UINT32 NumaDistanceQueryAvailable : 1;\n    UINT32 FrequencyRegsAvailable : 1;\n    UINT32 SyntheticMachineCheckAvailable : 1;\n    UINT32 GuestCrashRegsAvailable : 1;\n    UINT32 DebugRegsAvailable : 1;\n    UINT32 Npiep1Available : 1;\n    UINT32 DisableHypervisorAvailable : 1;\n    UINT32 ExtendedGvaRangesForFlushVirtualAddressListAvailable : 1;\n    UINT32 FastHypercallOutputAvailable : 1;\n    UINT32 SvmFeaturesAvailable : 1;\n    UINT32 SintPollingModeAvailable : 1;\n    UINT32 HypercallMsrLockAvailable : 1; // 1511+\n    UINT32 DirectSyntheticTimers : 1; // 1607+\n    UINT32 RegisterPatAvailable : 1; // 1703+\n    UINT32 RegisterBndcfgsAvailable : 1;\n    UINT32 WatchdogTimerAvailable : 1;\n    UINT32 SyntheticTimeUnhaltedTimerAvailable : 1; // 1709+\n    UINT32 DeviceDomainsAvailable : 1;\n    UINT32 S1DeviceDomainsAvailable : 1; // 1803+\n    UINT32 LbrAvailable : 1; // 1809+\n    UINT32 IptAvailable : 1; // 1903+\n    UINT32 CrossVtlFlushAvailable : 1;\n    UINT32 IdleSpecCtrlAvailable : 1; // 2004+\n    UINT32 Reserved1 : 2;\n} HV_X64_HYPERVISOR_FEATURES, *PHV_X64_HYPERVISOR_FEATURES;\nstatic_assert(sizeof(HV_X64_HYPERVISOR_FEATURES) == 16);\n\n// private\ntypedef struct _HV_ENLIGHTENMENT_INFORMATION\n{\n    //\n    // Eax\n    //\n    UINT32 UseHypercallForAddressSpaceSwitch : 1;\n    UINT32 UseHypercallForLocalFlush : 1;\n    UINT32 UseHypercallForRemoteFlush : 1;\n    UINT32 UseApicMsrs : 1; // UseMsrForApicAccess\n    UINT32 UseMsrForReset : 1;\n    UINT32 UseRelaxedTiming : 1;\n    UINT32 UseDmaRemapping : 1;\n    UINT32 UseInterruptRemapping : 1;\n    UINT32 UseX2ApicMsrs : 1;\n    UINT32 DeprecateAutoEoi : 1;\n    UINT32 Reserved : 22;\n\n    //\n    // Ebx\n    //\n    UINT32 LongSpinWaitCount;\n\n    //\n    // Ecx\n    //\n    UINT32 ReservedEcx;\n\n    //\n    // Edx\n    //\n    UINT32 ReservedEdx;\n} HV_ENLIGHTENMENT_INFORMATION, *PHV_ENLIGHTENMENT_INFORMATION;\nstatic_assert(sizeof(HV_ENLIGHTENMENT_INFORMATION) == 16);\n\n// private\ntypedef struct _HV_IMPLEMENTATION_LIMITS\n{\n    //\n    // Eax\n    //\n    UINT32 MaxVirtualProcessorCount;\n\n    //\n    // Ebx\n    //\n    UINT32 MaxLogicalProcessorCount;\n\n    //\n    // Ecx\n    //\n    UINT32 MaxInterruptMappingCount;\n\n    //\n    // Edx\n    //\n    UINT32 Reserved;\n} HV_IMPLEMENTATION_LIMITS, *PHV_IMPLEMENTATION_LIMITS;\nstatic_assert(sizeof(HV_IMPLEMENTATION_LIMITS) == 16);\n\n// private\ntypedef struct _HV_X64_HYPERVISOR_HARDWARE_FEATURES\n{\n    //\n    // Eax\n    //\n    UINT32 ApicOverlayAssistInUse : 1;\n    UINT32 MsrBitmapsInUse : 1;\n    UINT32 ArchitecturalPerformanceCountersInUse : 1;\n    UINT32 SecondLevelAddressTranslationInUse : 1;\n    UINT32 DmaRemappingInUse : 1;\n    UINT32 InterruptRemappingInUse : 1;\n    UINT32 MemoryPatrolScrubberPresent : 1;\n    UINT32 DmaProtectionInUse : 1;\n    UINT32 HpetRequested : 1;\n    UINT32 SyntheticTimersVolatile : 1;\n    UINT32 HypervisorLevel : 4;\n    UINT32 PhysicalDestinationModeRequired : 1;\n    UINT32 UseVmfuncForAliasMapSwitch : 1;\n    UINT32 HvRegisterForMemoryZeroingSupported : 1;\n    UINT32 UnrestrictedGuestSupported : 1;\n    UINT32 RdtAFeaturesSupported : 1;\n    UINT32 RdtMFeaturesSupported : 1;\n    UINT32 ChildPerfmonPmuSupported : 1;\n    UINT32 ChildPerfmonLbrSupported : 1;\n    UINT32 ChildPerfmonIptSupported : 1;\n    UINT32 ApicEmulationSupported : 1;\n    UINT32 ChildX2ApicRecommended : 1;\n    UINT32 HardwareWatchdogReserved : 1;\n    UINT32 DeviceAccessTrackingSupported : 1;\n    UINT32 Reserved : 5;\n\n    //\n    // Ebx\n    //\n    UINT32 DeviceDomainInputWidth : 8;\n    UINT32 ReservedEbx : 24;\n\n    //\n    // Ecx\n    //\n    UINT32 ReservedEcx;\n\n    //\n    // Edx\n    //\n    UINT32 ReservedEdx;\n} HV_X64_HYPERVISOR_HARDWARE_FEATURES, *PHV_X64_HYPERVISOR_HARDWARE_FEATURES;\nstatic_assert(sizeof(HV_X64_HYPERVISOR_HARDWARE_FEATURES) == 16);\n\n#undef LogicalProcessorIdling\n// private\ntypedef struct _HV_X64_HYPERVISOR_CPU_MANAGEMENT_FEATURES\n{\n    //\n    // Eax\n    //\n    UINT32 StartLogicalProcessor : 1;\n    UINT32 CreateRootVirtualProcessor : 1;\n    UINT32 PerformanceCounterSync : 1; // 1703+\n    UINT32 Reserved0 : 28;\n    UINT32 ReservedIdentityBit : 1;\n\n    //\n    // Ebx\n    //\n    UINT32 ProcessorPowerManagement : 1;\n    UINT32 MwaitIdleStates : 1;\n    UINT32 LogicalProcessorIdling : 1;\n    UINT32 Reserved1 : 29;\n\n    //\n    // Ecx\n    //\n    UINT32 RemapGuestUncached : 1; // 1803+\n    UINT32 ReservedZ2 : 31;\n\n    //\n    // Edx\n    //\n    UINT32 ReservedEdx;\n} HV_X64_HYPERVISOR_CPU_MANAGEMENT_FEATURES, *PHV_X64_HYPERVISOR_CPU_MANAGEMENT_FEATURES;\nstatic_assert(sizeof(HV_X64_HYPERVISOR_CPU_MANAGEMENT_FEATURES) == 16);\n\n// private\ntypedef struct _HV_HYPERVISOR_SVM_FEATURES\n{\n    //\n    // Eax\n    //\n    UINT32 SvmSupported : 1;\n    UINT32 Reserved0 : 10;\n    UINT32 MaxPasidSpacePasidCount : 21;\n\n    //\n    // Ebx\n    //\n    UINT32 MaxPasidSpaceCount;\n\n    //\n    // Ecx\n    //\n    UINT32 MaxDevicePrqSize;\n\n    //\n    // Edx\n    //\n    UINT32 Reserved1;\n} HV_HYPERVISOR_SVM_FEATURES, *PHV_HYPERVISOR_SVM_FEATURES;\nstatic_assert(sizeof(HV_HYPERVISOR_SVM_FEATURES) == 16);\n\n// private\ntypedef struct _HV_HYPERVISOR_SKIP_LEVEL_FEATURES\n{\n    //\n    // Eax\n    //\n    UINT32 Reserved0 : 2;\n    UINT32 AccessSynicRegs : 1;\n    UINT32 Reserved1 : 1;\n    UINT32 AccessIntrCtrlRegs : 1;\n    UINT32 AccessHypercallMsrs : 1;\n    UINT32 AccessVpIndex : 1;\n    UINT32 Reserved2 : 5;\n    UINT32 AccessReenlightenmentControls : 1;\n    UINT32 Reserved3 : 19;\n\n    //\n    // Ebx\n    //\n    UINT32 ReservedEbx;\n\n    //\n    // Ecx\n    //\n    UINT32 ReservedEcx;\n\n    //\n    // Edx\n    //\n    UINT32 Reserved4 : 4;\n    UINT32 XmmRegistersForFastHypercallAvailable : 1;\n    UINT32 Reserved5 : 10;\n    UINT32 FastHypercallOutputAvailable : 1;\n    UINT32 Reserved6 : 1;\n    UINT32 SintPollingModeAvailable : 1;\n    UINT32 Reserved7 : 14;\n} HV_HYPERVISOR_SKIP_LEVEL_FEATURES, *PHV_HYPERVISOR_SKIP_LEVEL_FEATURES;\nstatic_assert(sizeof(HV_HYPERVISOR_SKIP_LEVEL_FEATURES) == 16);\n\n// private\ntypedef struct _HV_HYPERVISOR_NESTED_VIRT_FEATURES\n{\n    //\n    // Eax\n    //\n    UINT32 EnlightedVmcsVersionLow : 8;\n    UINT32 EnlightedVmcsVesionHigh : 8;\n    UINT32 FlushGuestPhysicalHypercall_Deprecated : 1; // 1607+\n    UINT32 NestedFlushVirtualHypercall : 1;\n    UINT32 FlushGuestPhysicalHypercall : 1;\n    UINT32 MsrBitmap : 1;\n    UINT32 VirtualizationException : 1; // 1709+\n    UINT32 DebugCtl : 1; // 2004+\n    UINT32 Reserved0 : 10;\n\n    //\n    // Ebx\n    //\n    UINT32 PerfGlobalCtrl : 1;\n    UINT32 Reserved1 : 31;\n\n    //\n    // Ecx\n    //\n    UINT32 ReservedEcx;\n\n    //\n    // Edx\n    //\n    UINT32 ReservedEdx;\n} HV_HYPERVISOR_NESTED_VIRT_FEATURES, *PHV_HYPERVISOR_NESTED_VIRT_FEATURES;\nstatic_assert(sizeof(HV_HYPERVISOR_NESTED_VIRT_FEATURES) == 16);\n\n// private\ntypedef struct _HV_HYPERVISOR_IPT_FEATURES\n{\n    //\n    // Eax\n    //\n    UINT32 ChainedToPA : 1;\n    UINT32 Enlightened : 1;\n    UINT32 Reserved0 : 10;\n    UINT32 MaxTraceBufferSizePerVtl : 20;\n\n    //\n    // Ebx\n    //\n    UINT32 Reserved1;\n\n    //\n    // Ecx\n    //\n    UINT32 Reserved2;\n\n    //\n    // Ecx\n    //\n    UINT32 HypervisorIpt : 1; // 2004+\n    UINT32 Reserved3 : 31;\n} HV_HYPERVISOR_IPT_FEATURES, *PHV_HYPERVISOR_IPT_FEATURES;\nstatic_assert(sizeof(HV_HYPERVISOR_IPT_FEATURES) == 16);\n\n// private\ntypedef struct _HV_X64_PLATFORM_CAPABILITIES\n{\n    UINT64 AsUINT64[2];\n\n    struct\n    {\n        //\n        // Eax\n        //\n        UINT AllowRedSignedCode : 1;\n        UINT AllowKernelModeDebugging : 1;\n        UINT AllowUserModeDebugging : 1;\n        UINT AllowTelnetServer : 1;\n        UINT AllowIOPorts : 1;\n        UINT AllowFullMsrSpace : 1;\n        UINT AllowPerfCounters : 1;\n        UINT AllowHost512MB : 1;\n        UINT AllowRemoteRecovery : 1;\n        UINT AllowStreaming : 1;\n        UINT AllowPushDeployment : 1;\n        UINT AllowPullDeployment : 1;\n        UINT AllowProfiling : 1;\n        UINT AllowJsProfiling : 1;\n        UINT AllowCrashDump : 1;\n        UINT AllowVsCrashDump : 1;\n        UINT AllowToolFileIO : 1;\n        UINT AllowConsoleMgmt : 1;\n        UINT AllowTracing : 1;\n        UINT AllowXStudio : 1;\n        UINT AllowGestureBuilder : 1;\n        UINT AllowSpeechLab : 1;\n        UINT AllowSmartglassStudio : 1;\n        UINT AllowNetworkTools : 1;\n        UINT AllowTcrTool : 1;\n        UINT AllowHostNetworkStack : 1;\n        UINT AllowSystemUpdateTest : 1;\n        UINT AllowOffChipPerfCtrStreaming : 1;\n        UINT AllowToolingMemory : 1;\n        UINT AllowSystemDowngrade : 1;\n        UINT AllowGreenDiskLicenses : 1;\n\n        //\n        // Ebx\n        //\n        UINT IsLiveConnected : 1;\n        UINT IsMteBoosted : 1;\n        UINT IsQaSlt : 1;\n        UINT IsStockImage : 1;\n        UINT IsMsTestLab : 1;\n        UINT IsRetailDebugger : 1;\n        UINT IsXvdSort : 1;\n        UINT IsGreenDebug : 1;\n        UINT IsHwDevTest : 1;\n        UINT AllowDiskLicenses : 1; // 1511+\n        UINT AllowInstrumentation : 1;\n        UINT AllowWifiTester : 1;\n        UINT AllowWifiTesterDFS : 1;\n        UINT IsHwTest : 1;\n        UINT AllowHostOddTest : 1;\n        UINT IsLiveUnrestricted : 1;\n        UINT AllowDiscLicensesWithoutMediaAuth : 1;\n        UINT ReservedEbx : 15;\n\n        //\n        // Ecx\n        //\n        UINT ReservedEcx;\n\n        //\n        // Edx\n        //\n        UINT ReservedEdx : 31;\n        UINT UseAlternateXvd : 1;\n    };\n} HV_X64_PLATFORM_CAPABILITIES, *PHV_X64_PLATFORM_CAPABILITIES;\nstatic_assert(sizeof(HV_X64_PLATFORM_CAPABILITIES) == 32);\n\n#if defined(_M_IX86) || defined(_M_AMD64)\ntypedef union _PH_CPUID\n{\n    struct\n    {\n        ULONG EAX;\n        ULONG EBX;\n        ULONG ECX;\n        ULONG EDX;\n    };\n\n    struct\n    {\n        ULONG64 LowPart;\n        ULONG64 HighPart;\n    };\n\n    INT32 Data[4];\n} PH_CPUID, *PPH_CPUID;\n\nVOID PhCpuId(\n    _Out_ PPH_CPUID CpuId,\n    _In_ ULONG Function,\n    _In_ ULONG SubFunction\n    )\n{\n    CpuId->LowPart = 0;\n    CpuId->HighPart = 0;\n    CpuIdEx(CpuId->Data, Function, SubFunction);\n}\n\nBOOLEAN PhCpuIsIntel(\n    VOID\n    )\n{\n    PH_CPUID cpuid;\n\n    PhCpuId(&cpuid, 0, 0);\n\n    // GenuineIntel\n    if (cpuid.EBX == 'uneG' && cpuid.EDX == 'Ieni' && cpuid.ECX == 'letn')\n        return TRUE;\n\n    return FALSE;\n}\n\nBOOLEAN PhCpuIsAMD(\n    VOID\n    )\n{\n    PH_CPUID cpuid;\n\n    PhCpuId(&cpuid, 0, 0);\n\n    // AuthenticAMD\n    if (cpuid.EBX == 'htuA' && cpuid.EDX == 'itne' && cpuid.ECX == 'DMAc')\n        return TRUE;\n\n    return FALSE;\n}\n\nBOOLEAN PhHypervisorIsPresent(\n    VOID\n    )\n{\n\n    PH_CPUID cpuid;\n\n    PhCpuId(&cpuid, HvCpuIdFunctionVersionAndFeatures, 0);\n\n    // https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/feature-discovery#hypervisor-discovery\n    if (cpuid.ECX & 0x80000000)\n        return TRUE;\n\n    return FALSE;\n}\n\nBOOLEAN PhVCpuIsMicrosoftHyperV(\n    VOID\n    )\n{\n    PH_CPUID cpuid;\n\n    PhCpuId(&cpuid, HvCpuIdFunctionHvVendorAndMaxFunction, 0);\n\n    // Microsoft Hv\n    if (cpuid.EBX == 'rciM' && cpuid.ECX == 'foso' && cpuid.EDX == 'vH t')\n        return TRUE;\n\n    return FALSE;\n}\n\nVOID PhGetHvPartitionPrivilegeMask(\n    _Out_ PHV_PARTITION_PRIVILEGE_MASK Mask\n    )\n{\n    PH_CPUID cpuid;\n\n    PhCpuId(&cpuid, HvCpuIdFunctionMsHvFeatures, 0);\n\n    Mask->LowPart = cpuid.EAX;\n    Mask->HighPart = cpuid.EBX;\n}\n#endif\n\nNTSTATUS PhGetHypervisorVendorId(\n    _Out_ PULONG VendorId\n    )\n{\n    NTSTATUS status;\n    SYSTEM_HYPERVISOR_DETAIL_INFORMATION info;\n\n    *VendorId = 0;\n\n    if (!NT_SUCCESS(status = NtQuerySystemInformation(\n        SystemHypervisorDetailInformation,\n        &info,\n        sizeof(info),\n        NULL\n        )))\n        return status;\n\n    *VendorId = info.HvVendorAndMaxFunction.Data[1];\n\n    return STATUS_SUCCESS;\n}\n\nPH_VIRTUAL_STATUS PhGetVirtualStatus(\n    VOID\n    )\n{\n#if defined(_ARM64_)\n    ULONG vendorId;\n\n    if (NT_SUCCESS(PhGetHypervisorVendorId(&vendorId)))\n    {\n        if (vendorId == 'MOCQ')\n        {\n            if (USER_SHARED_DATA->QcSlIsSupported)\n            {\n                return PhVirtualStatusEnabledFirmware;\n            }\n\n            return PhVirtualStatusNotCapable;\n        }\n        else\n        {\n            SYSTEM_HYPERVISOR_DETAIL_INFORMATION info;\n\n            if (NT_SUCCESS(NtQuerySystemInformation(\n                SystemHypervisorDetailInformation,\n                &info,\n                sizeof(info),\n                NULL\n                )))\n            {\n                if (info.HvFeatures.Data[1] & 0x1000)\n                {\n                    return PhVirtualStatusEnabledHyperV;\n                }\n            }\n\n            return PhVirtualStatusVirtualMachine;\n        }\n    }\n\n    if (USER_SHARED_DATA->ArchStartedInEl2 || USER_SHARED_DATA->QcSlIsSupported)\n    {\n        return PhVirtualStatusEnabledFirmware;\n    }\n\n    return PhVirtualStatusNotCapable;\n#else\n    if (PhHypervisorIsPresent())\n    {\n        if (PhVCpuIsMicrosoftHyperV())\n        {\n            HV_PARTITION_PRIVILEGE_MASK mask;\n\n            PhGetHvPartitionPrivilegeMask(&mask);\n\n            if (mask.AccessVpRunTimeReg)\n            {\n                return PhVirtualStatusEnabledHyperV;\n            }\n        }\n\n        return PhVirtualStatusVirtualMachine;\n    }\n\n    if (PhCpuIsIntel())\n    {\n        PH_CPUID cpuid;\n\n        PhCpuId(&cpuid, 1, 0);\n\n        // Virtual Machine Extensions (VMX)\n        if (!(cpuid.ECX & 0x20))\n        {\n            return PhVirtualStatusNotCapable;\n        }\n    }\n    else if (PhCpuIsAMD())\n    {\n        PH_CPUID cpuid;\n\n        PhCpuId(&cpuid, 0x80000001, 0);\n\n        // Secure Virtual Machine (SVM)\n        if (!(cpuid.ECX & 0x2))\n        {\n            return PhVirtualStatusNotCapable;\n        }\n    }\n    else\n    {\n        //return PhVirtualStatusUnknown;\n        return PhVirtualStatusNotCapable;\n    }\n\n    if (USER_SHARED_DATA->ProcessorFeatures[PF_VIRT_FIRMWARE_ENABLED])\n    {\n        return PhVirtualStatusEnabledFirmware;\n    }\n\n    if (USER_SHARED_DATA->ProcessorFeatures[PF_SECOND_LEVEL_ADDRESS_TRANSLATION] &&\n        USER_SHARED_DATA->ProcessorFeatures[PF_NX_ENABLED])\n    {\n        return PhVirtualStatusDisabledWithHyperV;\n    }\n\n    return PhVirtualStatusDisabled;\n#endif\n}\n\ntypedef struct _PH_SMBIOS_STRINGREF\n{\n    USHORT Length;\n    PSTR Buffer;\n} PH_SMBIOS_STRINGREF, *PPH_SMBIOS_STRINGREF;\n\ntypedef struct _PH_SMBIOS_PARSE_CONTEXT\n{\n    PRAW_SMBIOS_DATA Data;\n    PVOID End;\n    PH_SMBIOS_STRINGREF Strings[256];\n} PH_SMBIOS_PARSE_CONTEXT, *PPH_SMBIOS_PARSE_CONTEXT;\n\nNTSTATUS PhpParseSMBIOS(\n    _In_ PPH_SMBIOS_PARSE_CONTEXT Context,\n    _In_ PSMBIOS_HEADER Current,\n    _Out_ PSMBIOS_HEADER* Next\n    )\n{\n    NTSTATUS status;\n    PSTR pointer;\n    PSTR string;\n    UCHAR nulls;\n    USHORT length;\n    UCHAR count;\n\n    *Next = NULL;\n\n    memset(Context->Strings, 0, sizeof(Context->Strings));\n\n    pointer = SMBIOS_STRING_TABLE(Current);\n    string = pointer;\n\n    if ((ULONG_PTR)pointer >= (ULONG_PTR)Context->End)\n        return STATUS_BUFFER_OVERFLOW;\n\n    nulls = 0;\n    length = 0;\n    count = 0;\n\n    while ((ULONG_PTR)pointer < (ULONG_PTR)Context->End)\n    {\n        if (*pointer++ != ANSI_NULL)\n        {\n            if (!NT_SUCCESS(status = RtlUShortAdd(length, 1, &length)))\n                return status;\n\n            nulls = 0;\n            continue;\n        }\n\n        if (nulls++)\n            break;\n\n        Context->Strings[count].Length = length;\n        Context->Strings[count].Buffer = string;\n\n        count++;\n        string = pointer;\n        length = 0;\n    }\n\n    if (nulls != 2)\n        return STATUS_INVALID_ADDRESS;\n\n    if (Current->Type != SMBIOS_END_OF_TABLE_TYPE)\n        *Next = (PSMBIOS_HEADER)pointer;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhpEnumSMBIOS(\n    _In_ PRAW_SMBIOS_DATA Data,\n    _In_ PPH_ENUM_SMBIOS_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PH_SMBIOS_PARSE_CONTEXT context;\n    PSMBIOS_HEADER current;\n    PSMBIOS_HEADER next;\n\n    memset(&context, 0, sizeof(context));\n    context.Data = Data;\n    context.End = PTR_ADD_OFFSET(Data->SMBIOSTableData, Data->Length);\n\n    current = (PSMBIOS_HEADER)Data->SMBIOSTableData;\n    next = NULL;\n\n    while (NT_SUCCESS(status = PhpParseSMBIOS(&context, current, &next)))\n    {\n        if (Callback(\n            (ULONG_PTR)&context,\n            Data->SMBIOSMajorVersion,\n            Data->SMBIOSMinorVersion,\n            (PPH_SMBIOS_ENTRY)current,\n            Context\n            ))\n            break;\n\n        if (!next)\n            break;\n\n        current = next;\n    }\n\n    return status;\n}\n\nNTSTATUS PhEnumSMBIOS(\n    _In_ PPH_ENUM_SMBIOS_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    static volatile ULONG cachedLength = sizeof(SYSTEM_FIRMWARE_TABLE_INFORMATION) + 64;\n    NTSTATUS status;\n    ULONG length;\n    PSYSTEM_FIRMWARE_TABLE_INFORMATION info;\n\n    length = ReadULongAcquire(&cachedLength);\n\n    if (!(info = PhAllocateStack(length)))\n        return STATUS_NO_MEMORY;\n\n    RtlZeroMemory(info, length);\n    info->ProviderSignature = 'RSMB';\n    info->TableID = 0;\n    info->Action = SystemFirmwareTableGet;\n    info->TableBufferLength = length - sizeof(SYSTEM_FIRMWARE_TABLE_INFORMATION);\n\n    status = NtQuerySystemInformation(\n        SystemFirmwareTableInformation,\n        info,\n        length,\n        &length\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhFreeStack(info);\n\n        if (!(info = PhAllocateStack(length)))\n            return STATUS_NO_MEMORY;\n\n        RtlZeroMemory(info, length);\n        info->ProviderSignature = 'RSMB';\n        info->TableID = 0;\n        info->Action = SystemFirmwareTableGet;\n        info->TableBufferLength = length - sizeof(SYSTEM_FIRMWARE_TABLE_INFORMATION);\n\n        status = NtQuerySystemInformation(\n            SystemFirmwareTableInformation,\n            info,\n            length,\n            &length\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            WriteULongRelease(&cachedLength, length);\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhpEnumSMBIOS(\n            (PRAW_SMBIOS_DATA)info->TableBuffer,\n            Callback,\n            Context\n            );\n    }\n\n    PhFreeStack(info);\n\n    return status;\n}\n\nNTSTATUS PhGetSMBIOSString(\n    _In_ ULONG_PTR EnumHandle,\n    _In_ UCHAR Index,\n    _Out_ PPH_STRING* String\n    )\n{\n    PPH_SMBIOS_PARSE_CONTEXT context;\n    PPH_SMBIOS_STRINGREF string;\n\n    context = (PPH_SMBIOS_PARSE_CONTEXT)EnumHandle;\n\n    *String = NULL;\n\n    if (Index == SMBIOS_INVALID_STRING)\n        return STATUS_INVALID_PARAMETER;\n\n    string = &context->Strings[Index - 1];\n    if (!string->Buffer)\n        return STATUS_INVALID_PARAMETER;\n\n    *String = PhConvertUtf8ToUtf16Ex(string->Buffer, string->Length);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "phlib/format.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2020\n *\n */\n\n/*\n * This module provides a high-performance string formatting mechanism. Instead of using format\n * strings, the user supplies an array of structures. This system is 2-5 times faster than\n * printf-based functions.\n *\n * This file contains the public interfaces, while including the real formatting code from\n * elsewhere. There are currently two functions: PhFormat, which returns a string object containing\n * the formatted string, and PhFormatToBuffer, which writes the formatted string to a buffer. The\n * latter is a bit faster due to the lack of resizing logic.\n */\n\n#include <phbase.h>\n\n#include <locale.h>\n\nextern ULONG PhMaxSizeUnit;\n\n#define SMALL_BUFFER_LENGTH (PH_OBJECT_SMALL_OBJECT_SIZE - FIELD_OFFSET(PH_STRING, Data) - sizeof(WCHAR))\n#define BUFFER_SIZE 512\n\n#define PHP_FORMAT_NEGATIVE 0x1\n#define PHP_FORMAT_POSITIVE 0x2\n#define PHP_FORMAT_PAD 0x4\n\n// Keep in sync with PhSizeUnitNames\nCONST PH_STRINGREF PhSizeUnitNamesCounted[7] =\n{\n    PH_STRINGREF_INIT(L\"B\"),\n    PH_STRINGREF_INIT(L\"kB\"),\n    PH_STRINGREF_INIT(L\"MB\"),\n    PH_STRINGREF_INIT(L\"GB\"),\n    PH_STRINGREF_INIT(L\"TB\"),\n    PH_STRINGREF_INIT(L\"PB\"),\n    PH_STRINGREF_INIT(L\"EB\")\n};\nCONST PH_STRINGREF PhPrefixUnitNamesCounted[7] =\n{\n    PH_STRINGREF_INIT(L\"b\"),\n    PH_STRINGREF_INIT(L\"k\"),\n    PH_STRINGREF_INIT(L\"M\"),\n    PH_STRINGREF_INIT(L\"B\"),\n    PH_STRINGREF_INIT(L\"T\"),\n    PH_STRINGREF_INIT(L\"P\"),\n    PH_STRINGREF_INIT(L\"E\")\n};\nCONST PH_STRINGREF PhSiPrefixUnitNamesCounted[7] =\n{\n    PH_STRINGREF_INIT(L\" Bps\"),\n    PH_STRINGREF_INIT(L\" Kbps\"),\n    PH_STRINGREF_INIT(L\" Mbps\"),\n    PH_STRINGREF_INIT(L\" Gbps\"),\n    PH_STRINGREF_INIT(L\" Tbps\"),\n    PH_STRINGREF_INIT(L\" Pbps\"),\n    PH_STRINGREF_INIT(L\" Ebps\")\n};\nstatic PH_INITONCE PhpFormatInitOnce = PH_INITONCE_INIT;\nstatic WCHAR PhpFormatDecimalSeparator = L'.';\nstatic WCHAR PhpFormatThousandSeparator = L',';\nstatic _locale_t PhpFormatUserLocale = NULL;\n\nVOID PhpFormatSingleToUtf8Locale(\n    _In_ FLOAT Value,\n    _In_ ULONG Type,\n    _In_ LONG Precision,\n    _Out_writes_bytes_(BufferLength) PSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    if (!NT_SUCCESS(PhFormatSingleToUtf8(\n        Value,\n        Type,\n        Precision,\n        Buffer,\n        BufferLength,\n        ReturnLength\n        )))\n    {\n        if (Buffer)\n            *Buffer = ANSI_NULL;\n        if (ReturnLength)\n            *ReturnLength = 0;\n        return;\n    }\n\n    if (PhpFormatUserLocale && Buffer)\n    {\n        for (PCH c = Buffer; *c; ++c)\n        {\n            if (*c == '.')\n            {\n                *c = (CHAR)PhpFormatDecimalSeparator;\n                break;\n            }\n        }\n    }\n\n    if (Type & FormatUpperCase)\n    {\n        if (PhpFormatUserLocale)\n            _strupr_l(Buffer, PhpFormatUserLocale);\n        else\n            _strupr(Buffer);\n\n        //for (PCH c = Buffer; *c; ++c)\n        //    *c = RtlUpperChar(*c);\n    }\n}\n\nVOID PhpFormatDoubleToUtf8Locale(\n    _In_ DOUBLE Value,\n    _In_ ULONG Type,\n    _In_ LONG Precision,\n    _Out_writes_bytes_(BufferLength) PSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    if (!NT_SUCCESS(PhFormatDoubleToUtf8(\n        Value,\n        Type,\n        Precision,\n        Buffer,\n        BufferLength,\n        ReturnLength\n        )))\n    {\n        if (Buffer)\n            *Buffer = ANSI_NULL;\n        if (ReturnLength)\n            *ReturnLength = 0;\n        return;\n    }\n\n    if (PhpFormatUserLocale && Buffer)\n    {\n        for (PCH c = Buffer; *c; ++c)\n        {\n            if (*c == '.')\n            {\n                *c = (CHAR)PhpFormatDecimalSeparator;\n                break;\n            }\n        }\n    }\n\n    if (Type & FormatUpperCase)\n    {\n        if (PhpFormatUserLocale)\n            _strupr_l(Buffer, PhpFormatUserLocale);\n        else\n            _strupr(Buffer);\n\n        //for (PCH c = Buffer; *c; ++c)\n        //    *c = RtlUpperChar(*c);\n    }\n}\n\n// From Source\\10.0.10150.0\\ucrt\\inc\\corecrt_internal_stdio_output.h in SDK v10.\nVOID PhpCropZeros(\n    _Inout_ PCHAR Buffer\n    )\n{\n    CHAR decimalSeparator = (CHAR)PhpFormatDecimalSeparator;\n\n    while (*Buffer && *Buffer != decimalSeparator)\n        ++Buffer;\n\n    if (*Buffer++)\n    {\n        while (*Buffer && *Buffer != 'e' && *Buffer != 'E')\n            ++Buffer;\n\n        PCHAR stop = Buffer--;\n\n        while (*Buffer == '0')\n            --Buffer;\n\n        if (*Buffer == decimalSeparator)\n            --Buffer;\n\n        while ((*++Buffer = *stop++) != ANSI_NULL)\n            NOTHING;\n    }\n}\n\nPPH_STRING PhpResizeFormatBuffer(\n    _In_ PPH_STRING String,\n    _Inout_ PSIZE_T AllocatedLength,\n    _In_ SIZE_T UsedLength,\n    _In_ SIZE_T NeededLength\n    )\n{\n    PPH_STRING newString;\n    SIZE_T allocatedLength;\n\n    allocatedLength = *AllocatedLength;\n    allocatedLength *= 2;\n\n    if (allocatedLength < UsedLength + NeededLength)\n        allocatedLength = UsedLength + NeededLength;\n\n    newString = PhCreateStringEx(NULL, allocatedLength);\n    memcpy(newString->Buffer, String->Buffer, UsedLength);\n    PhDereferenceObject(String);\n\n    *AllocatedLength = allocatedLength;\n\n    return newString;\n}\n\n/**\n * Creates a formatted string.\n *\n * \\param Format An array of format structures.\n * \\param Count The number of structures supplied in \\a Format.\n * \\param InitialCapacity The number of bytes to reserve initially for the string. If 0 is\n * specified, a default value is used.\n */\nPPH_STRING PhFormat(\n    _In_reads_(Count) PPH_FORMAT Format,\n    _In_ ULONG Count,\n    _In_opt_ SIZE_T InitialCapacity\n    )\n{\n    PPH_STRING string;\n    SIZE_T allocatedLength;\n    PWSTR buffer;\n    SIZE_T usedLength;\n\n    // Set up the buffer.\n\n    // If the specified initial capacity is too small (or zero), use the largest buffer size which\n    // will still be eligible for allocation from the small object free list.\n    if (InitialCapacity < SMALL_BUFFER_LENGTH)\n        InitialCapacity = SMALL_BUFFER_LENGTH;\n\n    string = PhCreateStringEx(NULL, InitialCapacity);\n    allocatedLength = InitialCapacity;\n    buffer = string->Buffer;\n    usedLength = 0;\n\n#undef ENSURE_BUFFER\n#undef OK_BUFFER\n#undef ADVANCE_BUFFER\n\n#define ENSURE_BUFFER(NeededLength) \\\n    do { \\\n        if (allocatedLength < usedLength + (NeededLength)) \\\n        { \\\n            string = PhpResizeFormatBuffer(string, &allocatedLength, usedLength, (NeededLength)); \\\n            buffer = string->Buffer + usedLength / sizeof(WCHAR); \\\n        } \\\n    } while (0)\n\n#define OK_BUFFER (TRUE)\n\n#define ADVANCE_BUFFER(Length) \\\n    do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0)\n\n#include \"format_i.h\"\n\n    string->Length = usedLength;\n    // Null-terminate the string.\n    string->Buffer[usedLength / sizeof(WCHAR)] = UNICODE_NULL;\n\n    return string;\n}\n\n/**\n * Writes a formatted string to a buffer.\n *\n * \\param Format An array of format structures.\n * \\param Count The number of structures supplied in \\a Format.\n * \\param Buffer A buffer. If NULL, no data is written.\n * \\param BufferLength The number of bytes available in \\a Buffer, including space for the null\n * terminator.\n * \\param ReturnLength The number of bytes required to hold the string, including the null\n * terminator.\n *\n * \\return TRUE if the buffer was large enough and the string was written (i.e. \\a BufferLength >=\n * \\a ReturnLength), otherwise FALSE. In either case, the required number of bytes is stored in\n * \\a ReturnLength.\n *\n * \\remarks If the function fails but \\a BufferLength != 0, a single null byte is written to the\n * start of \\a Buffer.\n */\nBOOLEAN PhFormatToBuffer(\n    _In_reads_(Count) PPH_FORMAT Format,\n    _In_ ULONG Count,\n    _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    PWSTR buffer;\n    SIZE_T usedLength;\n    BOOLEAN overrun;\n\n    buffer = Buffer;\n    usedLength = 0;\n    overrun = FALSE;\n\n    // Make sure we don't try to write anything if we don't have a buffer.\n    if (!Buffer)\n        overrun = TRUE;\n\n#undef ENSURE_BUFFER\n#undef OK_BUFFER\n#undef ADVANCE_BUFFER\n\n#define ENSURE_BUFFER(NeededLength) \\\n    do { \\\n        if (!overrun && (BufferLength < usedLength + (NeededLength))) \\\n            overrun = TRUE; \\\n    } while (0)\n\n#define OK_BUFFER (!overrun)\n\n#define ADVANCE_BUFFER(Length) \\\n    do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0)\n\n#include \"format_i.h\"\n\n    // Write the null-terminator.\n    ENSURE_BUFFER(sizeof(WCHAR));\n    if (OK_BUFFER)\n        *buffer = UNICODE_NULL;\n    else if (Buffer && BufferLength != 0) // try to null-terminate even if this function fails\n        *Buffer = UNICODE_NULL;\n    ADVANCE_BUFFER(sizeof(WCHAR));\n\n    if (ReturnLength)\n        *ReturnLength = usedLength;\n\n    return OK_BUFFER;\n}\n"
  },
  {
    "path": "phlib/format_i.h",
    "content": "/*\n * This file contains the actual formatting code used by various public interface functions.\n *\n * There are three macros defined by the parent function which control how this code writes the\n * formatted string:\n * * ENSURE_BUFFER - This macro is passed the number of bytes required whenever characters need to\n *   be written to the buffer. The macro can resize the buffer if needed.\n * * OK_BUFFER - This macro returns TRUE if it is OK to write to the buffer, otherwise FALSE when\n *   the buffer is too large, is not specified, or some other error has occurred.\n * * ADVANCE_BUFFER - This macro is passed the number of bytes written to the buffer and should\n *   increment the \"buffer\" pointer and \"usedLength\" counter.\n * In addition to these macros, the \"buffer\" and \"usedLength\" variables are assumed to be present.\n *\n * The below code defines many macros; this is so that composite formatting types can be constructed\n * (e.g. the \"size\" type).\n */\n\n{\n    if (PhBeginInitOnce(&PhpFormatInitOnce))\n    {\n        WCHAR localeBuffer[4];\n\n        if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SDECIMAL, localeBuffer, 4))\n        {\n            PhpFormatDecimalSeparator = localeBuffer[0];\n        }\n\n        if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_STHOUSAND, localeBuffer, 4))\n        {\n            PhpFormatThousandSeparator = localeBuffer[0];\n        }\n\n        if (PhpFormatDecimalSeparator != L'.')\n            PhpFormatUserLocale = _wcreate_locale(LC_ALL, L\"\");\n\n        PhEndInitOnce(&PhpFormatInitOnce);\n    }\n\n    while (Count--)\n    {\n        PPH_FORMAT format;\n        SIZE_T partLength;\n        WCHAR tempBuffer[BUFFER_SIZE];\n        ULONG flags;\n        ULONG int32;\n        ULONG64 int64;\n\n        format = Format++;\n\n        // Save the currently used length so we can compute the part length later.\n        partLength = usedLength;\n\n        flags = 0;\n\n        switch (format->Type & FormatTypeMask)\n        {\n\n        // Characters and Strings\n\n        case CharFormatType:\n            ENSURE_BUFFER(sizeof(WCHAR));\n            if (OK_BUFFER)\n                *buffer = format->u.Char;\n            ADVANCE_BUFFER(sizeof(WCHAR));\n            break;\n        case StringFormatType:\n            ENSURE_BUFFER(format->u.String.Length);\n            if (OK_BUFFER)\n                memcpy(buffer, format->u.String.Buffer, format->u.String.Length);\n            ADVANCE_BUFFER(format->u.String.Length);\n            break;\n        case StringZFormatType:\n            {\n                SIZE_T count;\n\n                count = PhCountStringZ(format->u.StringZ);\n                ENSURE_BUFFER(count * sizeof(WCHAR));\n                if (OK_BUFFER)\n                    memcpy(buffer, format->u.StringZ, count * sizeof(WCHAR));\n                ADVANCE_BUFFER(count * sizeof(WCHAR));\n            }\n            break;\n        case MultiByteStringFormatType:\n        case MultiByteStringZFormatType:\n            {\n                ULONG bytesInUnicodeString;\n                PSTR multiByteBuffer;\n                SIZE_T multiByteLength;\n\n                if (format->Type == MultiByteStringFormatType)\n                {\n                    multiByteBuffer = format->u.MultiByteString.Buffer;\n                    multiByteLength = format->u.MultiByteString.Length;\n                }\n                else\n                {\n                    multiByteBuffer = format->u.MultiByteStringZ;\n                    multiByteLength = strlen(multiByteBuffer);\n                }\n\n                if (NT_SUCCESS(RtlMultiByteToUnicodeSize(\n                    &bytesInUnicodeString,\n                    multiByteBuffer,\n                    (ULONG)multiByteLength\n                    )))\n                {\n                    ENSURE_BUFFER(bytesInUnicodeString);\n\n                    if (!OK_BUFFER || NT_SUCCESS(RtlMultiByteToUnicodeN(\n                        buffer,\n                        bytesInUnicodeString,\n                        NULL,\n                        multiByteBuffer,\n                        (ULONG)multiByteLength\n                        )))\n                    {\n                        ADVANCE_BUFFER(bytesInUnicodeString);\n                    }\n                }\n            }\n            break;\n\n        // Integers\n\n#define PROCESS_DIGIT(Input) \\\n    do { \\\n        r = (ULONG)(Input % radix); \\\n        Input /= radix; \\\n        *temp-- = integerToChar[r]; \\\n        tempCount++; \\\n    } while (0)\n\n#define COMMON_INTEGER_FORMAT(Input, Format) \\\n    do { \\\n        ULONG radix; \\\n        PCCH integerToChar; \\\n        PWSTR temp; \\\n        ULONG tempCount; \\\n        ULONG r; \\\n        ULONG preCount; \\\n        ULONG padCount; \\\n        \\\n        radix = 10; \\\n        if (((Format)->Type & FormatUseRadix) && (Format)->Radix >= 2 && (Format)->Radix <= 69) \\\n            radix = (Format)->Radix; \\\n        integerToChar = PhIntegerToChar; \\\n        if ((Format)->Type & FormatUpperCase) \\\n            integerToChar = PhIntegerToCharUpper; \\\n        temp = tempBuffer + BUFFER_SIZE - 1; \\\n        tempCount = 0; \\\n        \\\n        if (Input != 0) \\\n        { \\\n            if ((Format)->Type & FormatGroupDigits) \\\n            { \\\n                ULONG needsSep = 0; \\\n                \\\n                do \\\n                { \\\n                    PROCESS_DIGIT(Input); \\\n                    \\\n                    if (++needsSep == 3 && Input != 0) /* get rid of trailing separator */ \\\n                    { \\\n                        *temp-- = PhpFormatThousandSeparator; \\\n                        tempCount++; \\\n                        needsSep = 0; \\\n                    } \\\n                } while (Input != 0); \\\n            } \\\n            else \\\n            { \\\n                do \\\n                { \\\n                    PROCESS_DIGIT(Input); \\\n                } while (Input != 0); \\\n            } \\\n        } \\\n        else \\\n        { \\\n            *temp-- = '0'; \\\n            tempCount++; \\\n        } \\\n        \\\n        preCount = 0; \\\n        \\\n        if (flags & PHP_FORMAT_NEGATIVE) \\\n            preCount++; \\\n        else if ((Format)->Type & FormatPrefixSign) \\\n            preCount++; \\\n        \\\n        if (((Format)->Type & FormatPadZeros) && !((Format)->Type & FormatGroupDigits)) \\\n        { \\\n            if (preCount + tempCount < (Format)->Width) \\\n            { \\\n                flags |= PHP_FORMAT_PAD; \\\n                padCount = (Format)->Width - (preCount + tempCount); \\\n                preCount += padCount; \\\n            } \\\n        } \\\n        \\\n        temp++; \\\n        ENSURE_BUFFER((preCount + tempCount) * sizeof(WCHAR)); \\\n        if (OK_BUFFER) \\\n        { \\\n            if (flags & PHP_FORMAT_NEGATIVE) \\\n                *buffer++ = L'-'; \\\n            else if ((Format)->Type & FormatPrefixSign) \\\n                *buffer++ = L'+'; \\\n            \\\n            if (flags & PHP_FORMAT_PAD) \\\n            { \\\n                wmemset(buffer, '0', padCount); \\\n                buffer += padCount; \\\n            } \\\n            \\\n            memcpy(buffer, temp, tempCount * sizeof(WCHAR)); \\\n            buffer += tempCount; \\\n        } \\\n        usedLength += (preCount + tempCount) * sizeof(WCHAR); \\\n    } while (0)\n\n#ifndef _WIN64\n        case IntPtrFormatType:\n            int32 = format->u.IntPtr;\n            goto CommonMaybeNegativeInt32Format;\n#endif\n        case Int32FormatType:\n            int32 = format->u.Int32;\n\n#ifndef _WIN64\nCommonMaybeNegativeInt32Format:\n#endif\n            if ((LONG)int32 < 0)\n            {\n                int32 = -(LONG)int32;\n                flags |= PHP_FORMAT_NEGATIVE;\n            }\n\n            goto CommonInt32Format;\n#ifndef _WIN64\n        case UIntPtrFormatType:\n            int32 = format->u.UIntPtr;\n            goto CommonInt32Format;\n#endif\n        case UInt32FormatType:\n            int32 = format->u.UInt32;\nCommonInt32Format:\n            COMMON_INTEGER_FORMAT(int32, format);\n            break;\n#ifdef _WIN64\n        case IntPtrFormatType:\n            int64 = format->u.IntPtr;\n            goto CommonMaybeNegativeInt64Format;\n#endif\n        case Int64FormatType:\n            int64 = format->u.Int64;\n\n#ifdef _WIN64\nCommonMaybeNegativeInt64Format:\n#endif\n            if ((LONG64)int64 < 0)\n            {\n                int64 = -(LONG64)int64;\n                flags |= PHP_FORMAT_NEGATIVE;\n            }\n\n            goto CommonInt64Format;\n#ifdef _WIN64\n        case UIntPtrFormatType:\n            int64 = format->u.UIntPtr;\n            goto CommonInt64Format;\n#endif\n        case UInt64FormatType:\n            int64 = format->u.UInt64;\nCommonInt64Format:\n            COMMON_INTEGER_FORMAT(int64, format);\n            break;\n\n        // Floating point numbers\n\n#define COMMON_DOUBLE_FORMAT(DataType, Format, FormatType, FormatToBufferUtf8) \\\n    do { \\\n        ULONG precision; \\\n        DataType value; \\\n        PSTR temp; \\\n        ULONG length; \\\n        SIZE_T returnLength; \\\n        \\\n        if ((Format)->Type & FormatUsePrecision) \\\n        { \\\n            precision = (Format)->Precision; \\\n            \\\n            if (precision > BUFFER_SIZE - 1 - _CVTBUFSIZE) \\\n                precision = BUFFER_SIZE - 1 - _CVTBUFSIZE; \\\n        } \\\n        else \\\n        { \\\n            precision = 6; \\\n        } \\\n        \\\n        value = (Format)->u.FormatType; \\\n        temp = (PSTR)tempBuffer + 1; /* leave one character so we can insert a prefix if needed */ \\\n        returnLength = 0; \\\n        FormatToBufferUtf8( \\\n            value, \\\n            (Format)->Type, \\\n            precision, \\\n            temp, \\\n            sizeof(tempBuffer) - 1, \\\n            &returnLength \\\n            ); \\\n        \\\n        /* if (((Format)->Type & FormatForceDecimalPoint) && precision == 0) */ \\\n             /* _forcdecpt_l(tempBufferAnsi, PhpFormatUserLocale); */ \\\n        if ((Format)->Type & FormatCropZeros) \\\n        { \\\n            PhpCropZeros(temp); \\\n            \\\n            length = (ULONG)strlen(temp); \\\n        } \\\n        else \\\n        { \\\n            length = (ULONG)returnLength; \\\n        } \\\n        \\\n        if (temp[0] == '-') \\\n        { \\\n            flags |= PHP_FORMAT_NEGATIVE; \\\n            temp++; \\\n            length--; \\\n        } \\\n        else if ((Format)->Type & FormatPrefixSign) \\\n        { \\\n            flags |= PHP_FORMAT_POSITIVE; \\\n        } \\\n        \\\n        if (((Format)->Type & FormatGroupDigits) && !((Format)->Type & (FormatStandardForm | FormatHexadecimalForm))) \\\n        { \\\n            PSTR whole; \\\n            PSTR decimalPoint; \\\n            ULONG wholeCount; \\\n            ULONG sepsCount; \\\n            ULONG ensureLength; \\\n            ULONG copyCount; \\\n            ULONG needsSep; \\\n            \\\n            /* Find the first non-digit character and assume that is the */ \\\n            /* decimal point (or the end of the string). */ \\\n            \\\n            whole = temp; \\\n            decimalPoint = temp; \\\n            \\\n            while ((UCHAR)(*decimalPoint - '0') < 10) \\\n                decimalPoint++; \\\n            \\\n            /* Copy the characters to the output buffer, and at the same time */ \\\n            /* insert the separators. */ \\\n            \\\n            wholeCount = (ULONG)(decimalPoint - temp); \\\n            \\\n            if (wholeCount != 0) \\\n                sepsCount = (wholeCount + 2) / 3 - 1; \\\n            else \\\n                sepsCount = 0; \\\n            \\\n            ensureLength = (length + sepsCount) * sizeof(WCHAR); \\\n            if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \\\n                ensureLength += sizeof(WCHAR); \\\n            ENSURE_BUFFER(ensureLength); \\\n            \\\n            copyCount = wholeCount; \\\n            needsSep = (wholeCount + 2) % 3; \\\n            \\\n            if (OK_BUFFER) \\\n            { \\\n                if (flags & PHP_FORMAT_NEGATIVE) \\\n                    *buffer++ = L'-'; \\\n                else if (flags & PHP_FORMAT_POSITIVE) \\\n                    *buffer++ = L'+'; \\\n                \\\n                while (copyCount--) \\\n                { \\\n                    *buffer++ = *whole++; \\\n                    \\\n                    if (needsSep-- == 0 && copyCount != 0) /* get rid of trailing separator */ \\\n                    { \\\n                        *buffer++ = PhpFormatThousandSeparator; \\\n                        needsSep = 2; \\\n                    } \\\n                } \\\n            } \\\n            \\\n            if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \\\n                usedLength += sizeof(WCHAR); \\\n            usedLength += (wholeCount + sepsCount) * sizeof(WCHAR); \\\n            \\\n            /* Copy the rest. */ \\\n            \\\n            copyCount = length - wholeCount; \\\n            \\\n            if (OK_BUFFER) \\\n            { \\\n                PhZeroExtendToUtf16Buffer(decimalPoint, copyCount, buffer); \\\n                ADVANCE_BUFFER(copyCount * sizeof(WCHAR)); \\\n            } \\\n        } \\\n        else \\\n        { \\\n            SIZE_T preLength; \\\n            SIZE_T padLength; \\\n            \\\n            /* Take care of the sign and zero padding. */ \\\n            preLength = 0; \\\n            \\\n            if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \\\n                preLength++; \\\n            \\\n            if ((Format)->Type & FormatPadZeros) \\\n            { \\\n                if (preLength + length < (Format)->Width) \\\n                { \\\n                    flags |= PHP_FORMAT_PAD; \\\n                    padLength = (Format)->Width - (preLength + length); \\\n                    preLength += padLength; \\\n                } \\\n            } \\\n            /* We don't need to group digits, so directly copy the characters */ \\\n            /* to the output buffer. */ \\\n            \\\n            ENSURE_BUFFER((preLength + length) * sizeof(WCHAR)); \\\n            \\\n            if (OK_BUFFER) \\\n            { \\\n                if (flags & PHP_FORMAT_NEGATIVE) \\\n                    *buffer++ = L'-'; \\\n                else if (flags & PHP_FORMAT_POSITIVE) \\\n                    *buffer++ = L'+'; \\\n                \\\n                if (flags & PHP_FORMAT_PAD) \\\n                { \\\n                    wmemset(buffer, '0', padLength); \\\n                    buffer += padLength; \\\n                } \\\n            } \\\n            \\\n            usedLength += preLength * sizeof(WCHAR); \\\n            \\\n            if (OK_BUFFER) \\\n            { \\\n                PhZeroExtendToUtf16Buffer(temp, length, buffer); \\\n                ADVANCE_BUFFER(length * sizeof(WCHAR)); \\\n            } \\\n        } \\\n    } while (0)\n\n        case SingleFormatType:\n            flags = 0;\n            COMMON_DOUBLE_FORMAT(FLOAT, format, Single, PhpFormatSingleToUtf8Locale);\n            break;\n\n        case DoubleFormatType:\n            flags = 0;\n            COMMON_DOUBLE_FORMAT(DOUBLE, format, Double, PhpFormatDoubleToUtf8Locale);\n            break;\n\n        // Additional types\n\n        case SizeFormatType:\n            {\n                ULONG i = 0;\n                ULONG maxSizeUnit;\n                DOUBLE s;\n                PH_FORMAT doubleFormat;\n\n                s = (DOUBLE)format->u.Size;\n\n                if (format->u.Size == 0)\n                {\n                    ENSURE_BUFFER(sizeof(WCHAR));\n                    if (OK_BUFFER)\n                        *buffer = '0';\n                    ADVANCE_BUFFER(sizeof(WCHAR));\n                    goto ContinueLoop;\n                }\n\n                if (format->Type & FormatUseRadix)\n                    maxSizeUnit = format->Radix;\n                else\n                    maxSizeUnit = PhMaxSizeUnit;\n\n                while (\n                    s >= 1000 &&\n                    i < sizeof(PhSizeUnitNamesCounted) / sizeof(PH_STRINGREF) &&\n                    i < maxSizeUnit\n                    )\n                {\n                    s /= 1024;\n                    i++;\n                }\n\n                // Format the number, then append the unit name.\n\n                doubleFormat.Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros | FormatGroupDigits;\n                doubleFormat.Precision = (format->Type & FormatUsePrecision) ? format->Precision : 2;\n                doubleFormat.Width = 0; // stupid compiler\n                doubleFormat.u.Double = s;\n                flags = 0;\n                COMMON_DOUBLE_FORMAT(DOUBLE, &doubleFormat, Double, PhpFormatDoubleToUtf8Locale);\n\n                ENSURE_BUFFER(sizeof(WCHAR) + PhSizeUnitNamesCounted[i].Length);\n                if (OK_BUFFER)\n                {\n                    *buffer = L' ';\n                    memcpy(buffer + 1, PhSizeUnitNamesCounted[i].Buffer, PhSizeUnitNamesCounted[i].Length);\n                }\n                ADVANCE_BUFFER(sizeof(WCHAR) + PhSizeUnitNamesCounted[i].Length);\n            }\n            break;\n        }\n\nContinueLoop:\n        partLength = usedLength - partLength;\n\n        if (format->Type & (FormatLeftAlign | FormatRightAlign))\n        {\n            SIZE_T newLength;\n            SIZE_T addLength;\n\n            newLength = format->Width * sizeof(WCHAR);\n\n            // We only pad and never truncate.\n            if (partLength < newLength)\n            {\n                addLength = newLength - partLength;\n                ENSURE_BUFFER(addLength);\n\n                if (OK_BUFFER)\n                {\n                    WCHAR pad;\n\n                    if (format->Type & FormatUsePad)\n                        pad = format->Pad;\n                    else\n                        pad = L' ';\n\n                    if (format->Type & FormatLeftAlign)\n                    {\n                        // Left alignment is easy; we just fill the remaining space with the pad\n                        // character.\n                        wmemset(buffer, pad, addLength / sizeof(WCHAR));\n                    }\n                    else\n                    {\n                        PWSTR start;\n\n                        // Right alignment is much slower and involves moving the text forward, then\n                        // filling in the space before it.\n                        start = buffer - partLength / sizeof(WCHAR);\n                        memmove(start + addLength / sizeof(WCHAR), start, partLength);\n                        wmemset(start, pad, addLength / sizeof(WCHAR));\n                    }\n                }\n\n                ADVANCE_BUFFER(addLength);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "phlib/format_std.cpp",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2020-2024\n *\n */\n\n#include <phbase.h>\n#include <charconv>\n\nextern NTSTATUS PhErrcToNtStatus(\n    _In_ std::errc ec\n    );\n\nNTSTATUS PhFormatSingleToUtf8(\n    _In_ FLOAT Value,\n    _In_ ULONG Type,\n    _In_ LONG Precision,\n    _Out_writes_bytes_(BufferLength) PSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n#if defined(PH_TOCHARS_BUFFER)\n    chars_format format = chars_format::fixed;\n    to_chars_result result;\n    SIZE_T returnLength;\n    CHAR buffer[_CVTBUFSIZE + 1];\n\n    if (Type & FormatStandardForm)\n        format = chars_format::general;\n    else if (Type & FormatHexadecimalForm)\n        format = chars_format::hex;\n\n    result = std::to_chars(\n        buffer,\n        Buffer + BufferLength - sizeof(ANSI_NULL), // Reserve space for null terminator // end(buffer)\n        Value,\n        format,\n        Precision\n        );\n\n    if (result.ec != static_cast<std::errc>(0))\n        return PhErrcToNtStatus(result.ec);\n\n    returnLength = result.ptr - buffer;\n\n    if (returnLength == 0)\n        return STATUS_UNSUCCESSFUL;\n\n    // This could be removed in favor of directly passing the input buffer to std:to_chars but\n    // for now use memcpy so that failures writing a value don't touch the input buffer (dmex)\n    memcpy_s(Buffer, BufferLength, buffer, returnLength);\n    Buffer[returnLength] = ANSI_NULL;\n\n    if (ReturnLength)\n        *ReturnLength = returnLength;\n\n    return STATUS_SUCCESS;\n#else\n    std::chars_format format;\n    std::to_chars_result result;\n    SIZE_T returnLength;\n\n    if (Precision < 0)\n    {\n        // This overload finds the shortest string that converts back to the exact same double.\n        // It is roughly 2x faster than the version with explicit precision.\n        result = std::to_chars(\n            Buffer,\n            Buffer + BufferLength - sizeof(ANSI_NULL),\n            Value\n            );\n    }\n    else\n    {\n        if (FlagOn(Type, FormatStandardForm))\n            format = std::chars_format::general;\n        else if (FlagOn(Type, FormatHexadecimalForm))\n            format = std::chars_format::hex;\n        else\n            format = std::chars_format::fixed;\n\n        result = std::to_chars(\n            Buffer,\n            Buffer + BufferLength - sizeof(ANSI_NULL), // Reserve space for null terminator // end(buffer)\n            Value,\n            format,\n            Precision\n            );\n    }\n\n    if (result.ec != static_cast<std::errc>(0))\n        return PhErrcToNtStatus(result.ec);\n\n    returnLength = result.ptr - Buffer;\n\n    if (ReturnLength)\n    {\n        *ReturnLength = returnLength;\n    }\n\n    Buffer[returnLength] = ANSI_NULL;\n\n    return STATUS_SUCCESS;\n#endif\n}\n\nNTSTATUS PhFormatDoubleToUtf8(\n    _In_ DOUBLE Value,\n    _In_ ULONG Type,\n    _In_ LONG Precision,\n    _Out_writes_bytes_(BufferLength) PSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n#if defined(PH_TOCHARS_BUFFER)\n    chars_format format = chars_format::fixed;\n    to_chars_result result;\n    SIZE_T returnLength;\n    CHAR buffer[_CVTBUFSIZE + 1];\n\n    if (Precision < 0)\n    {\n        // This overload finds the shortest string that converts back to the exact same double.\n        // It is roughly 2x faster than the version with explicit precision.\n        result = std::to_chars(\n            Buffer,\n            Buffer + BufferLength - sizeof(ANSI_NULL),\n            Value\n            );\n    }\n    else\n    {\n        if (FlagOn(Type, FormatStandardForm))\n            format = std::chars_format::general;\n        else if (FlagOn(Type, FormatHexadecimalForm))\n            format = std::chars_format::hex;\n        else\n            format = std::chars_format::fixed;\n\n        result = to_chars(\n            buffer,\n            Buffer + BufferLength - sizeof(ANSI_NULL), // end(buffer)\n            Value,\n            format,\n            Precision\n            );\n    }\n\n    if (result.ec != static_cast<std::errc>(0))\n        return STATUS_UNSUCCESSFUL;\n\n    returnLength = result.ptr - buffer;\n\n    if (returnLength == 0)\n        return STATUS_UNSUCCESSFUL;\n\n    // This could be removed in favor of directly passing the input buffer to std:to_chars but\n    // for now use memcpy so that failures writing a value don't touch the input buffer (dmex)\n    memcpy_s(Buffer, BufferLength, buffer, returnLength);\n    Buffer[returnLength] = ANSI_NULL;\n\n    if (ReturnLength)\n        *ReturnLength = returnLength;\n\n    return STATUS_SUCCESS;\n#else\n    std::chars_format format;\n    std::to_chars_result result;\n    SIZE_T returnLength;\n\n    if (Precision < 0)\n    {\n        // This overload finds the shortest string that converts back to the exact same double.\n        // It is roughly 2x faster than the version with explicit precision.\n        result = std::to_chars(\n            Buffer,\n            Buffer + BufferLength - sizeof(ANSI_NULL),\n            Value\n            );\n    }\n    else\n    {\n        if (FlagOn(Type, FormatStandardForm))\n            format = std::chars_format::general;\n        else if (FlagOn(Type, FormatHexadecimalForm))\n            format = std::chars_format::hex;\n        else\n            format = std::chars_format::fixed;\n\n        result = std::to_chars(\n            Buffer,\n            Buffer + BufferLength - sizeof(ANSI_NULL), // Reserve space for null terminator\n            Value,\n            format,\n            Precision\n            );\n    }\n\n    if (result.ec != static_cast<std::errc>(0))\n        return PhErrcToNtStatus(result.ec);\n\n    returnLength = result.ptr - Buffer;\n\n    if (ReturnLength)\n    {\n        *ReturnLength = returnLength;\n    }\n\n    Buffer[returnLength] = ANSI_NULL;\n\n    return STATUS_SUCCESS;\n#endif\n}\n\n/**\n * Converts an integer to a UTF-8 string buffer (Replicates PhIntegerToString64).\n * \n * \\param Integer The integer to convert.\n * \\param Base The radix (e.g., 10, 16, 8). If 0, defaults to 10.\n * \\param Signed TRUE to treat as signed int64, FALSE for unsigned int64.\n * \\param Buffer The output buffer.\n * \\param BufferLength The size of the buffer in bytes.\n * \\param ReturnLength Contains the number of bytes written (excluding null terminator).\n */\nNTSTATUS PhIntegerToUtf8Buffer(\n    _In_ LONG64 Integer,\n    _In_opt_ ULONG Base,\n    _In_ BOOLEAN Signed,\n    _Out_writes_bytes_(BufferLength) PSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    std::to_chars_result result;\n    INT radix = (Base == 0) ? 10 : (INT)Base;\n\n    if (!Buffer || BufferLength == 0)\n        return STATUS_BUFFER_TOO_SMALL;\n    if (radix < 2 || radix > 36)\n        return STATUS_INVALID_PARAMETER;\n\n    // Reserve 1 byte for null terminator\n    PSTR endBuffer = Buffer + BufferLength - sizeof(ANSI_NULL);\n\n    if (Signed)\n    {\n        result = std::to_chars(\n            Buffer, \n            endBuffer, \n            (long long)Integer, \n            radix\n            );\n    }\n    else\n    {\n        result = std::to_chars(\n            Buffer, \n            endBuffer, \n            (unsigned long long)Integer, \n            radix\n            );\n    }\n\n    if (result.ec != std::errc())\n    {\n        if (result.ec == std::errc::value_too_large)\n            return STATUS_BUFFER_OVERFLOW;\n        \n        return STATUS_UNSUCCESSFUL;\n    }\n\n    *result.ptr = ANSI_NULL; //Null-terminate\n\n    if (ReturnLength)\n    {\n        SIZE_T length = result.ptr - Buffer; // Calculate written length\n\n        *ReturnLength = length;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhErrcToNtStatus(\n    _In_ std::errc ec\n    )\n{\n    switch (ec)\n    {\n    case std::errc::address_family_not_supported:\n        return STATUS_NOT_SUPPORTED;\n    case std::errc::address_in_use:\n        return STATUS_ADDRESS_ALREADY_ASSOCIATED;\n    case std::errc::address_not_available:\n        return STATUS_ADDRESS_NOT_ASSOCIATED;\n    case std::errc::already_connected:\n        return STATUS_CONNECTION_ACTIVE;\n    case std::errc::argument_list_too_long:\n    case std::errc::argument_out_of_domain:\n        return STATUS_INVALID_PARAMETER;\n    case std::errc::bad_address:\n        return STATUS_INVALID_ADDRESS;\n    case std::errc::bad_file_descriptor:\n        return STATUS_INVALID_HANDLE;\n    case std::errc::bad_message:\n        return STATUS_DATA_ERROR;\n    case std::errc::broken_pipe:\n        return STATUS_PIPE_BROKEN;\n    case std::errc::connection_aborted:\n        return STATUS_CONNECTION_ABORTED;\n    case std::errc::connection_already_in_progress:\n        return STATUS_CONNECTION_ACTIVE;\n    case std::errc::connection_refused:\n        return STATUS_CONNECTION_REFUSED;\n    case std::errc::connection_reset:\n        return STATUS_CONNECTION_RESET;\n    case std::errc::cross_device_link:\n        return STATUS_NOT_SAME_DEVICE;\n    case std::errc::destination_address_required:\n        return STATUS_DESTINATION_ELEMENT_FULL;\n    case std::errc::device_or_resource_busy:\n        return STATUS_DEVICE_BUSY;\n    case std::errc::directory_not_empty:\n        return STATUS_DIRECTORY_NOT_EMPTY;\n    case std::errc::executable_format_error:\n        return STATUS_INVALID_IMAGE_FORMAT;\n    case std::errc::file_exists:\n        return STATUS_OBJECT_NAME_COLLISION;\n    case std::errc::file_too_large:\n        return STATUS_FILE_TOO_LARGE;\n    case std::errc::filename_too_long:\n        return STATUS_NAME_TOO_LONG;\n    case std::errc::function_not_supported:\n        return STATUS_NOT_SUPPORTED;\n    case std::errc::host_unreachable:\n        return STATUS_HOST_UNREACHABLE;\n    case std::errc::identifier_removed:\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n    case std::errc::illegal_byte_sequence:\n        return STATUS_ILLEGAL_CHARACTER;\n    case std::errc::inappropriate_io_control_operation:\n        return STATUS_INVALID_DEVICE_REQUEST;\n    case std::errc::interrupted:\n        return STATUS_ALERTED;\n    case std::errc::invalid_argument:\n    case std::errc::invalid_seek:\n        return STATUS_INVALID_PARAMETER;\n    case std::errc::io_error:\n        return STATUS_IO_DEVICE_ERROR;\n    case std::errc::is_a_directory:\n        return STATUS_FILE_IS_A_DIRECTORY;\n    case std::errc::message_size:\n        return STATUS_BUFFER_OVERFLOW;\n    case std::errc::network_down:\n        return STATUS_NETWORK_UNREACHABLE;\n    case std::errc::network_reset:\n        return STATUS_CONNECTION_RESET;\n    case std::errc::network_unreachable:\n        return STATUS_NETWORK_UNREACHABLE;\n    case std::errc::no_buffer_space:\n        return STATUS_INSUFFICIENT_RESOURCES;\n    case std::errc::no_child_process:\n        return STATUS_INVALID_CID;\n    case std::errc::no_link:\n        return STATUS_NOT_FOUND;\n    case std::errc::no_lock_available:\n        return STATUS_LOCK_NOT_GRANTED;\n    case std::errc::no_message:\n        return STATUS_NO_DATA_DETECTED;\n    case std::errc::no_protocol_option:\n        return STATUS_PROTOCOL_UNREACHABLE;\n    case std::errc::no_space_on_device:\n        return STATUS_DISK_FULL;\n    case std::errc::no_such_device_or_address:\n        return STATUS_INVALID_ADDRESS;\n    case std::errc::no_such_device:\n        return STATUS_NO_SUCH_DEVICE;\n    case std::errc::no_such_file_or_directory:\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n    case std::errc::no_such_process:\n        return STATUS_INVALID_CID;\n    case std::errc::not_a_directory:\n        return STATUS_NOT_A_DIRECTORY;\n    case std::errc::not_a_socket:\n        return STATUS_OBJECT_TYPE_MISMATCH;\n    case std::errc::not_connected:\n        return STATUS_CONNECTION_DISCONNECTED;\n    case std::errc::not_enough_memory:\n        return STATUS_NO_MEMORY;\n    case std::errc::not_supported:\n        return STATUS_NOT_SUPPORTED;\n    case std::errc::operation_canceled:\n        return STATUS_CANCELLED;\n    case std::errc::operation_in_progress:\n        return STATUS_PENDING;\n    case std::errc::operation_not_permitted:\n        return STATUS_PRIVILEGE_NOT_HELD;\n    case std::errc::operation_not_supported:\n        return STATUS_NOT_SUPPORTED;\n    case std::errc::operation_would_block:\n        return STATUS_DEVICE_BUSY;\n    case std::errc::owner_dead:\n        return STATUS_INVALID_CID;\n    case std::errc::permission_denied:\n        return STATUS_ACCESS_DENIED;\n    case std::errc::protocol_error:\n    case std::errc::protocol_not_supported:\n        return STATUS_PROTOCOL_UNREACHABLE;\n    case std::errc::read_only_file_system:\n        return STATUS_MEDIA_WRITE_PROTECTED;\n    case std::errc::resource_deadlock_would_occur:\n        return STATUS_POSSIBLE_DEADLOCK;\n    case std::errc::resource_unavailable_try_again:\n        return STATUS_DEVICE_BUSY;\n    case std::errc::result_out_of_range:\n        return STATUS_INTEGER_OVERFLOW;\n    case std::errc::state_not_recoverable:\n        return STATUS_UNSUCCESSFUL;\n    case std::errc::text_file_busy:\n        return STATUS_FILE_LOCK_CONFLICT;\n    case std::errc::timed_out:\n        return STATUS_TIMEOUT;\n    case std::errc::too_many_files_open_in_system:\n    case std::errc::too_many_files_open:\n        return STATUS_TOO_MANY_OPENED_FILES;\n    case std::errc::too_many_links:\n    case std::errc::too_many_symbolic_link_levels:\n        return STATUS_TOO_MANY_LINKS;\n    case std::errc::value_too_large:\n        return STATUS_INTEGER_OVERFLOW;\n    case std::errc::wrong_protocol_type:\n        return STATUS_PROTOCOL_UNREACHABLE;\n    case std::errc():\n        return STATUS_SUCCESS;\n    default:\n        return STATUS_UNSUCCESSFUL;\n    }\n}\n"
  },
  {
    "path": "phlib/global.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2013\n *     dmex    2017-2023\n *\n */\n\n#include <ph.h>\n#include <phintrnl.h>\n#include <trace.h>\n\nPVOID PhInstanceHandle = NULL;\nPCWSTR PhApplicationName = NULL;\nHANDLE PhHeapHandle = NULL;\nRTL_OSVERSIONINFOEX PhOsVersion = { 0 };\nPHLIBAPI PH_SYSTEM_BASIC_INFORMATION PhSystemBasicInformation = { 0 };\nPH_SYSTEM_PROCESSOR_INFORMATION PhSystemProcessorInformation = { 0 };\nULONG WindowsVersion = WINDOWS_NEW;\n\n// Internal data\n#ifdef DEBUG\nPHLIB_STATISTICS_BLOCK PhLibStatisticsBlock;\n#endif\n\nNTSTATUS PhInitializePhLib(\n    _In_ PCWSTR ApplicationName\n    )\n{\n    NTSTATUS status;\n\n    WPP_INIT_TRACING(ApplicationName);\n\n    PhTraceInfo(\"%ls initializing\", ApplicationName);\n\n    PhApplicationName = ApplicationName;\n    PhInstanceHandle = NtCurrentImageBase();\n\n    PhInitializeRuntimeInformation();\n    PhInitializeWindowsInformation();\n    PhInitializeSystemInformation();\n\n    if (!NT_SUCCESS(status = PhHeapInitialization()))\n        return status;\n    if (!NT_SUCCESS(status = PhQueuedLockInitialization()))\n        return status;\n    if (!NT_SUCCESS(status = PhRefInitialization()))\n        return status;\n    if (!NT_SUCCESS(status = PhBaseInitialization()))\n        return status;\n\n    PhInitializeProcessorInformation();\n\n    return STATUS_SUCCESS;\n}\n\nBOOLEAN PhIsExecutingInWow64(\n    VOID\n    )\n{\n#ifndef _WIN64\n    static volatile BOOLEAN valid = FALSE;\n    static BOOLEAN isWow64 = FALSE;\n\n    if (!ReadBooleanAcquire(&valid))\n    {\n        PhGetProcessIsWow64(NtCurrentProcess(), &isWow64);\n        WriteBooleanRelease(&valid, TRUE);\n    }\n\n    return isWow64;\n#else\n    return FALSE;\n#endif\n}\n\nNTSTATUS PhInitializeRuntimeInformation(\n    VOID\n    )\n{\n#if defined _M_IX86\n    // Enable SSE2 CRT support.\n    _set_SSE2_enable(1);\n#endif\n\n    // Enable UTF8 CRT support.\n    //_wsetlocale(LC_ALL, L\".UTF8\");\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhInitializeSystemInformation(\n    VOID\n    )\n{\n    NTSTATUS status;\n    SYSTEM_BASIC_INFORMATION basicInfo = { 0 };\n\n    PhSystemBasicInformation.PageSize = PAGE_SIZE;\n    PhSystemBasicInformation.NumberOfProcessors = 1;\n    PhSystemBasicInformation.NumberOfPhysicalPages = ULONG_MAX;\n    PhSystemBasicInformation.MaximumTimerResolution = 0x2625A;\n    PhSystemBasicInformation.AllocationGranularity = 0x10000;\n    PhSystemBasicInformation.MaximumUserModeAddress = 0x10000;\n    PhSystemBasicInformation.ActiveProcessorsAffinityMask = USHRT_MAX;\n\n    status = NtQuerySystemInformation(\n        SystemBasicInformation,\n        &basicInfo,\n        sizeof(SYSTEM_BASIC_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PhSystemBasicInformation.PageSize = (USHORT)basicInfo.PageSize;\n        PhSystemBasicInformation.NumberOfProcessors = (USHORT)basicInfo.NumberOfProcessors;\n        PhSystemBasicInformation.NumberOfPhysicalPages = basicInfo.NumberOfPhysicalPages;\n        PhSystemBasicInformation.MaximumTimerResolution = basicInfo.TimerResolution;\n        PhSystemBasicInformation.AllocationGranularity = basicInfo.AllocationGranularity;\n        PhSystemBasicInformation.MaximumUserModeAddress = basicInfo.MaximumUserModeAddress;\n        PhSystemBasicInformation.ActiveProcessorsAffinityMask = basicInfo.ActiveProcessorsAffinityMask;\n    }\n\n    PhTraceInfo(\"InitializeSystemInformation: %!STATUS!\", status);\n\n    return status;\n}\n\nNTSTATUS PhInitializeWindowsInformation(\n    VOID\n    )\n{\n    NTSTATUS status;\n    RTL_OSVERSIONINFOEX versionInfo;\n    ULONG majorVersion;\n    ULONG minorVersion;\n    ULONG buildVersion;\n\n    memset(&versionInfo, 0, sizeof(RTL_OSVERSIONINFOEX));\n    versionInfo.OSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEX);\n\n    if (!NT_SUCCESS(status = RtlGetVersion(&versionInfo)))\n    {\n        WindowsVersion = WINDOWS_ANCIENT;\n        return status;\n    }\n\n    memcpy(&PhOsVersion, &versionInfo, sizeof(RTL_OSVERSIONINFOEX));\n    majorVersion = versionInfo.MajorVersion;\n    minorVersion = versionInfo.MinorVersion;\n    buildVersion = versionInfo.BuildNumber;\n\n    if (majorVersion == 6 && minorVersion < 1 || majorVersion < 6)\n    {\n        WindowsVersion = WINDOWS_ANCIENT;\n    }\n    // Windows 7, Windows Server 2008 R2\n    else if (majorVersion == 6 && minorVersion == 1)\n    {\n        WindowsVersion = WINDOWS_7;\n    }\n    // Windows 8, Windows Server 2012\n    else if (majorVersion == 6 && minorVersion == 2)\n    {\n        WindowsVersion = WINDOWS_8;\n    }\n    // Windows 8.1, Windows Server 2012 R2\n    else if (majorVersion == 6 && minorVersion == 3)\n    {\n        WindowsVersion = WINDOWS_8_1;\n    }\n    // Windows 10, Windows Server 2016\n    else if (majorVersion == 10 && minorVersion == 0)\n    {\n        if (buildVersion > 28000)\n        {\n            WindowsVersion = WINDOWS_NEW;\n        }\n        else if (buildVersion >= 28000)\n        {\n            WindowsVersion = WINDOWS_11_26H1;\n        }\n        else if (buildVersion >= 26200)\n        {\n            WindowsVersion = WINDOWS_11_25H2;\n        }\n        else if (buildVersion >= 26100)\n        {\n            WindowsVersion = WINDOWS_11_24H2;\n        }\n        else if (buildVersion >= 22631)\n        {\n            WindowsVersion = WINDOWS_11_23H2;\n        }\n        else if (buildVersion >= 22621)\n        {\n            WindowsVersion = WINDOWS_11_22H2;\n        }\n        else if (buildVersion >= 22000)\n        {\n            WindowsVersion = WINDOWS_11;\n        }\n        else if (buildVersion >= 19045)\n        {\n            WindowsVersion = WINDOWS_10_22H2;\n        }\n        else if (buildVersion >= 19044)\n        {\n            WindowsVersion = WINDOWS_10_21H2;\n        }\n        else if (buildVersion >= 19043)\n        {\n            WindowsVersion = WINDOWS_10_21H1;\n        }\n        else if (buildVersion >= 19042)\n        {\n            WindowsVersion = WINDOWS_10_20H2;\n        }\n        else if (buildVersion >= 19041)\n        {\n            WindowsVersion = WINDOWS_10_20H1;\n        }\n        else if (buildVersion >= 18363)\n        {\n            WindowsVersion = WINDOWS_10_19H2;\n        }\n        else if (buildVersion >= 18362)\n        {\n            WindowsVersion = WINDOWS_10_19H1;\n        }\n        else if (buildVersion >= 17763)\n        {\n            WindowsVersion = WINDOWS_10_RS5;\n        }\n        else if (buildVersion >= 17134)\n        {\n            WindowsVersion = WINDOWS_10_RS4;\n        }\n        else if (buildVersion >= 16299)\n        {\n            WindowsVersion = WINDOWS_10_RS3;\n        }\n        else if (buildVersion >= 15063)\n        {\n            WindowsVersion = WINDOWS_10_RS2;\n        }\n        else if (buildVersion >= 14393)\n        {\n            WindowsVersion = WINDOWS_10_RS1;\n        }\n        else if (buildVersion >= 10586)\n        {\n            WindowsVersion = WINDOWS_10_TH2;\n        }\n        else if (buildVersion >= 10240)\n        {\n            WindowsVersion = WINDOWS_10;\n        }\n        else\n        {\n            WindowsVersion = WINDOWS_10;\n        }\n    }\n    else\n    {\n        WindowsVersion = WINDOWS_NEW;\n    }\n\n    return status;\n}\n\nNTSTATUS PhHeapInitialization(\n    VOID\n    )\n{\n#if !defined(PH_DEBUG_HEAP)\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        if (PhHeapHandle = RtlCreateHeap(\n            HEAP_GROWABLE | HEAP_CREATE_SEGMENT_HEAP | HEAP_CLASS_1,\n            NULL,\n            0,\n            0,\n            NULL,\n            NULL\n            ))\n        {\n            status = STATUS_SUCCESS;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        if (PhHeapHandle = RtlCreateHeap(\n            HEAP_GROWABLE | HEAP_CLASS_1,\n            NULL,\n            2 * 1024 * 1024, // 2 MB\n            1024 * 1024, // 1 MB\n            NULL,\n            NULL\n            ))\n        {\n            status = STATUS_SUCCESS;\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            const ULONG defaultHeapCompatibilityMode = HEAP_COMPATIBILITY_MODE_LFH;\n            RtlSetHeapInformation(\n                PhHeapHandle,\n                HeapCompatibilityInformation,\n                &defaultHeapCompatibilityMode,\n                sizeof(ULONG)\n                );\n        }\n    }\n\n    PhTraceInfo(\"HeapInitialization: %!STATUS!\", status);\n    return status;\n#else\n    PhHeapHandle = RtlProcessHeap();\n    return STATUS_SUCCESS;\n#endif\n}\n\nNTSTATUS PhInitializeProcessorInformation(\n    VOID\n    )\n{\n    if (\n        USER_SHARED_DATA->ActiveGroupCount == 1 && // optimization (dmex)\n        USER_SHARED_DATA->ActiveProcessorCount > 0 &&\n        USER_SHARED_DATA->ActiveProcessorCount <= MAXIMUM_PROC_PER_GROUP\n        )\n    {\n        PhSystemProcessorInformation.SingleProcessorGroup = TRUE;\n        PhSystemProcessorInformation.NumberOfProcessors = PhSystemBasicInformation.NumberOfProcessors;\n        PhSystemProcessorInformation.NumberOfProcessorGroups = 1;\n        PhSystemProcessorInformation.ActiveProcessorsAffinityMasks = &PhSystemBasicInformation.ActiveProcessorsAffinityMask;\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        NTSTATUS status;\n        PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX processorInformation;\n        ULONG processorInformationLength;\n        USHORT numberOfProcessorGroups = 0;\n        USHORT numberOfProcessors = 0;\n        USHORT i;\n\n        status = PhGetSystemLogicalProcessorInformation(\n            RelationGroup,\n            &processorInformation,\n            &processorInformationLength\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            numberOfProcessorGroups = processorInformation->Group.ActiveGroupCount;\n\n            for (i = 0; i < numberOfProcessorGroups; i++)\n            {\n                numberOfProcessors += processorInformation->Group.GroupInfo[i].ActiveProcessorCount;\n            }\n\n            if (numberOfProcessorGroups > 1)\n            {\n                PhSystemProcessorInformation.ActiveProcessorCount = PhAllocate(numberOfProcessorGroups * sizeof(USHORT));\n                PhSystemProcessorInformation.ActiveProcessorsAffinityMasks = PhAllocate(numberOfProcessorGroups * sizeof(KAFFINITY));\n\n                for (i = 0; i < numberOfProcessorGroups; i++)\n                {\n                    PhSystemProcessorInformation.ActiveProcessorCount[i] = processorInformation->Group.GroupInfo[i].ActiveProcessorCount;\n                    PhSystemProcessorInformation.ActiveProcessorsAffinityMasks[i] = processorInformation->Group.GroupInfo[i].ActiveProcessorMask;\n                }\n            }\n\n            PhFree(processorInformation);\n        }\n\n        assert(numberOfProcessorGroups == USER_SHARED_DATA->ActiveGroupCount);\n        assert(numberOfProcessors == USER_SHARED_DATA->ActiveProcessorCount);\n\n        if (numberOfProcessorGroups > 1 && numberOfProcessors)\n        {\n            PhSystemProcessorInformation.SingleProcessorGroup = FALSE;\n            PhSystemProcessorInformation.NumberOfProcessors = numberOfProcessors;\n            PhSystemProcessorInformation.NumberOfProcessorGroups = numberOfProcessorGroups;\n        }\n        else\n        {\n            PhSystemProcessorInformation.SingleProcessorGroup = TRUE;\n            PhSystemProcessorInformation.NumberOfProcessors = PhSystemBasicInformation.NumberOfProcessors;\n            PhSystemProcessorInformation.NumberOfProcessorGroups = 1;\n            PhSystemProcessorInformation.ActiveProcessorsAffinityMasks = &PhSystemBasicInformation.ActiveProcessorsAffinityMask;\n        }\n\n        PhTraceInfo(\"InitializeProcessorInformation: %!STATUS!\", status);\n\n        return status;\n    }\n}\n\n#define WORKAROUND_CRTBUG_EXITPROCESS\n#ifdef WORKAROUND_CRTBUG_EXITPROCESS\nPH_CLANG_DIAGNOSTIC_PUSH();\nPH_CLANG_DIAGNOSTIC_IGNORED(\"-Winvalid-noreturn\");\n#endif\n_Use_decl_annotations_\nVOID PhExitApplication(\n    _In_ NTSTATUS Status\n    )\n{\n    PhTraceInfo(\"%ls exiting: %!STATUS!\", PhApplicationName, Status);\n\n    WPP_CLEANUP();\n\n#ifdef WORKAROUND_CRTBUG_EXITPROCESS\n    //HANDLE standardHandle;\n    //\n    //if (standardHandle = PhGetStdHandle(STD_OUTPUT_HANDLE))\n    //{\n    //    DEVICE_TYPE deviceType;\n    //\n    //    if (NT_SUCCESS(PhGetDeviceType(NtCurrentProcess(), standardHandle, &deviceType)))\n    //    {\n    //        if (deviceType == FILE_DEVICE_CONSOLE)\n    //        {\n    //            FlushFileBuffers(standardHandle);\n    //        }\n    //    }\n    //}\n\n    NtTerminateProcess(NtCurrentProcess(), Status);\n#else\n    RtlExitUserProcess(Status);\n#endif\n}\n#ifdef WORKAROUND_CRTBUG_EXITPROCESS\nPH_CLANG_DIAGNOSTIC_POP();\n#endif\n"
  },
  {
    "path": "phlib/graph.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <ph.h>\n#include <math.h>\n#include <graph.h>\n#include <guisup.h>\n\n#define COLORREF_TO_BITS(Color) (_byteswap_ulong(Color) >> 8)\n\ntypedef struct _PHP_GRAPH_CONTEXT\n{\n    HWND Handle;\n    HWND ParentHandle;\n    ULONG Style;\n    ULONG ExStyle;\n    ULONG_PTR Id;\n    PH_GRAPH_DRAW_INFO DrawInfo;\n    PH_GRAPH_OPTIONS Options;\n\n    union\n    {\n        USHORT Flags;\n        struct\n        {\n            USHORT NeedsUpdate : 1;\n            USHORT NeedsDraw : 1;\n            USHORT Hot : 1;\n            USHORT Spare : 13;\n        };\n    };\n\n    HDC BufferedContext;\n    HBITMAP BufferedOldBitmap;\n    HBITMAP BufferedBitmap;\n    PVOID BufferedBits;\n    RECT BufferedContextRect;\n\n    HDC FadeOutContext;\n    HBITMAP FadeOutOldBitmap;\n    HBITMAP FadeOutBitmap;\n    PVOID FadeOutBits;\n    RECT FadeOutContextRect;\n\n    HWND TooltipHandle;\n    WNDPROC TooltipOldWndProc;\n    POINT LastCursorLocation;\n\n    PPH_GRAPH_MESSAGE_CALLBACK Callback;\n    PVOID Context;\n} PHP_GRAPH_CONTEXT, *PPHP_GRAPH_CONTEXT;\n\nLRESULT CALLBACK PhpGraphWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nRECT PhNormalGraphTextMargin = { 5, 5, 5, 5 };\nRECT PhNormalGraphTextPadding = { 3, 3, 3, 3 };\n\nRTL_ATOM PhGraphControlInitialization(\n    )\n{\n    WNDCLASSEX wcex;\n\n    memset(&wcex, 0, sizeof(WNDCLASSEX));\n    wcex.cbSize = sizeof(WNDCLASSEX);\n    wcex.style = CS_GLOBALCLASS | CS_DBLCLKS;\n    wcex.lpfnWndProc = PhpGraphWndProc;\n    wcex.cbClsExtra = 0;\n    wcex.cbWndExtra = sizeof(PVOID);\n    wcex.hInstance = NtCurrentImageBase();\n    wcex.hCursor = PhLoadCursor(NULL, IDC_ARROW);\n    wcex.lpszClassName = PH_GRAPH_CLASSNAME;\n\n    return RegisterClassEx(&wcex);\n}\n\nFORCEINLINE VOID PhpGetGraphPoint(\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG Index,\n    _Out_ PULONG H1,\n    _Out_ PULONG H2\n    )\n{\n    if (Index < DrawInfo->LineDataCount)\n    {\n        FLOAT f1;\n        FLOAT f2;\n\n        f1 = DrawInfo->LineData1[Index];\n\n        if (f1 < 0)\n            f1 = 0;\n        if (f1 > 1)\n            f1 = 1;\n\n        *H1 = (ULONG)(f1 * (DrawInfo->Height - 1));\n\n        if (DrawInfo->Flags & PH_GRAPH_USE_LINE_2)\n        {\n            f2 = f1 + DrawInfo->LineData2[Index];\n\n            if (f2 < 0)\n                f2 = 0;\n            if (f2 > 1)\n                f2 = 1;\n\n            *H2 = (ULONG)(f2 * (DrawInfo->Height - 1));\n        }\n        else\n        {\n            *H2 = *H1;\n        }\n    }\n    else\n    {\n        *H1 = 0;\n        *H2 = 0;\n    }\n}\n\n/**\n * Draws a graph directly to memory.\n *\n * \\param hdc The DC to draw to. This is only used when drawing text.\n * \\param Bits The bits in a bitmap.\n * \\param DrawInfo A structure which contains graphing information.\n *\n * \\remarks The following information is fixed:\n * \\li The graph is fixed to the origin (0, 0).\n * \\li The total size of the bitmap is assumed to be \\a Width and \\a Height in \\a DrawInfo.\n * \\li \\a Step is fixed at 2.\n * \\li If \\ref PH_GRAPH_USE_LINE_2 is specified in \\a Flags, \\ref PH_GRAPH_OVERLAY_LINE_2 is never\n * used.\n */\nVOID PhDrawGraphDirect(\n    _In_ HDC hdc,\n    _In_ PVOID Bits,\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo\n    )\n{\n    PULONG bits = Bits;\n    LONG width = DrawInfo->Width;\n    LONG height = DrawInfo->Height;\n    LONG numberOfPixels = width * height;\n    ULONG flags = DrawInfo->Flags;\n    LONG i;\n    LONG x;\n\n    BOOLEAN intermediate = FALSE; // whether we are currently between two data positions\n    ULONG dataIndex = 0; // the data index of the current position\n    ULONG h1_i; // the line 1 height value to the left of the current position\n    ULONG h1_o; // the line 1 height value at the current position\n    ULONG h2_i; // the line 1 + line 2 height value to the left of the current position\n    ULONG h2_o; // the line 1 + line 2 height value at the current position\n    ULONG h1; // current pixel\n    ULONG h1_left; // current pixel\n    ULONG h2; // current pixel\n    ULONG h2_left; // current pixel\n\n    LONG mid;\n    LONG h1_low1;\n    LONG h1_high1;\n    LONG h1_low2;\n    LONG h1_high2;\n    LONG h2_low1;\n    LONG h2_high1;\n    LONG h2_low2;\n    LONG h2_high2;\n    LONG old_low2;\n    LONG old_high2;\n\n    ULONG lineColor1;\n    ULONG lineBackColor1;\n    ULONG lineColor2;\n    ULONG lineBackColor2;\n    FLOAT gridHeight;\n    LONG gridYThreshold;\n    ULONG gridYCounter;\n    ULONG gridColor;\n    FLOAT gridBase;\n    FLOAT gridLevel;\n\n    ULONG yLabelMax;\n    ULONG yLabelDataIndex;\n\n    lineColor1 = COLORREF_TO_BITS(DrawInfo->LineColor1);\n    lineBackColor1 = COLORREF_TO_BITS(DrawInfo->LineBackColor1);\n    lineColor2 = COLORREF_TO_BITS(DrawInfo->LineColor2);\n    lineBackColor2 = COLORREF_TO_BITS(DrawInfo->LineBackColor2);\n\n    if (DrawInfo->BackColor == 0)\n    {\n        memset(bits, 0, numberOfPixels * sizeof(RGBQUAD));\n    }\n    else\n    {\n        PhFillMemoryUlong(bits, COLORREF_TO_BITS(DrawInfo->BackColor), numberOfPixels);\n    }\n\n    x = width - 1;\n    h1_low2 = MAXLONG;\n    h1_high2 = 0;\n    h2_low2 = MAXLONG;\n    h2_high2 = 0;\n\n    PhpGetGraphPoint(DrawInfo, 0, &h1_i, &h2_i);\n\n    if (flags & (PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y))\n    {\n        gridHeight = max(DrawInfo->GridHeight, 0);\n        gridLevel = gridHeight;\n        gridYThreshold = DrawInfo->GridYThreshold;\n        gridYCounter = DrawInfo->GridWidth - (DrawInfo->GridXOffset * DrawInfo->Step) % DrawInfo->GridWidth - 1;\n        gridColor = COLORREF_TO_BITS(DrawInfo->GridColor);\n    }\n\n    if ((flags & (PH_GRAPH_USE_GRID_Y | PH_GRAPH_LOGARITHMIC_GRID_Y)) == (PH_GRAPH_USE_GRID_Y | PH_GRAPH_LOGARITHMIC_GRID_Y))\n    {\n        // Pre-process to find the largest integer n such that GridHeight*GridBase^n < 1.\n\n        gridBase = DrawInfo->GridBase;\n\n        if (gridBase > 1)\n        {\n            DOUBLE logBase;\n            DOUBLE exponent;\n            DOUBLE high;\n\n            logBase = log(gridBase);\n            exponent = ceil(-log(gridHeight) / logBase) - 1; // Works for both GridHeight > 1 and GridHeight < 1\n            high = exp(exponent * logBase);\n            gridLevel = (FLOAT)(gridHeight * high);\n\n            if (gridLevel < 0 || !isfinite(gridLevel))\n                gridLevel = 0;\n            if (gridLevel > 1)\n                gridLevel = 1;\n        }\n        else\n        {\n            // This is an error.\n            gridLevel = 0;\n        }\n    }\n\n    if (flags & PH_GRAPH_LABEL_MAX_Y)\n    {\n        yLabelMax = h2_i;\n        yLabelDataIndex = 0;\n    }\n\n    while (x >= 0)\n    {\n        // Calculate the height of the graph at this point.\n\n        if (!intermediate)\n        {\n            h1_o = h1_i;\n            h2_o = h2_i;\n\n            // Pull in new data.\n            dataIndex++;\n            PhpGetGraphPoint(DrawInfo, dataIndex, &h1_i, &h2_i);\n\n            h1 = h1_o;\n            h1_left = (h1_i + h1_o) / 2;\n            h2 = h2_o;\n            h2_left = (h2_i + h2_o) / 2;\n\n            if ((flags & PH_GRAPH_LABEL_MAX_Y) && dataIndex < DrawInfo->LabelMaxYIndexLimit)\n            {\n                if (yLabelMax <= h2_i)\n                {\n                    yLabelMax = h2_i;\n                    yLabelDataIndex = dataIndex;\n                }\n            }\n        }\n        else\n        {\n            h1 = h1_left;\n            h1_left = h1_i;\n            h2 = h2_left;\n            h2_left = h2_i;\n        }\n\n        // The graph is drawn right-to-left. There is one iteration of the loop per horizontal pixel.\n        // There is a fixed step value of 2, so every other iteration is a mid-point (intermediate)\n        // iteration with a height value of (left + right) / 2. In order to rasterize the outline,\n        // effectively in each iteration half of the line is drawn at the current column and the other\n        // half is drawn in the column to the left.\n\n        // Rasterize the data outline.\n        // h?_low2 to h?_high2 is the vertical line to the left of the current pixel.\n        // h?_low1 to h?_high1 is the vertical line at the current pixel.\n        // We merge (union) the old h?_low2 to h?_high2 line with the current line in each iteration.\n        //\n        // For example:\n        //\n        // X represents a data point. M represents the mid-point between two data points (\"intermediate\").\n        // X, M and x are all part of the outline. # represents the background filled in during\n        // the current loop iteration.\n        //\n        // slope > 0:                                     slope < 0:\n        //\n        //     X  < high1                                   X    < high2 (of next loop iteration)\n        //     x                                            x\n        //     x  < low1                                    x    < low2 (of next loop iteration)\n        //    x#  < high2                                    x   < high1 (of next loop iteration)\n        //    M#  < low2                                     M   < low1 (of next loop iteration)\n        //    x#  < high1 (of next loop iteration)           x   < high2\n        //    x#  < low1 (of next loop iteration)            x   < low2\n        //   x #  < high2 (of next loop iteration)            x  < high1\n        //   x #                                              x\n        //   X #  < low2 (of next loop iteration)             X  < low1\n        //     #                                              #\n        //     ^                                              ^\n        //    ^| current pixel                               ^| current pixel\n        //    |                                              |\n        //    | left of current pixel                        | left of current pixel\n        //\n        // In both examples above, the line low2-high2 will be merged with the line low1-high1 of\n        // the next iteration.\n\n        mid = ((h1_left + h1) / 2) * width;\n        old_low2 = h1_low2;\n        old_high2 = h1_high2;\n\n        if (h1_left < h1) // slope > 0\n        {\n            h1_low2 = h1_left * width;\n            h1_high2 = mid;\n            h1_low1 = mid + width;\n            h1_high1 = h1 * width;\n        }\n        else // slope < 0\n        {\n            h1_high2 = h1_left * width;\n            h1_low2 = mid + width;\n            h1_high1 = mid;\n            h1_low1 = h1 * width;\n        }\n\n        // Merge the lines.\n        if (h1_low1 > old_low2)\n            h1_low1 = old_low2;\n        if (h1_high1 < old_high2)\n            h1_high1 = old_high2;\n\n        // Fix up values for the current horizontal offset.\n        h1_low1 += x;\n        h1_high1 += x;\n\n        if (flags & PH_GRAPH_USE_LINE_2)\n        {\n            mid = ((h2_left + h2) / 2) * width;\n            old_low2 = h2_low2;\n            old_high2 = h2_high2;\n\n            if (h2_left < h2) // slope > 0\n            {\n                h2_low2 = h2_left * width;\n                h2_high2 = mid;\n                h2_low1 = mid + width;\n                h2_high1 = h2 * width;\n            }\n            else // slope < 0\n            {\n                h2_high2 = h2_left * width;\n                h2_low2 = mid + width;\n                h2_high1 = mid;\n                h2_low1 = h2 * width;\n            }\n\n            // Merge the lines.\n            if (h2_low1 > old_low2)\n                h2_low1 = old_low2;\n            if (h2_high1 < old_high2)\n                h2_high1 = old_high2;\n\n            // Fix up values for the current horizontal offset.\n            h2_low1 += x;\n            h2_high1 += x;\n        }\n\n        // Fill in the background.\n\n        if (flags & PH_GRAPH_USE_LINE_2)\n        {\n            for (i = h1_high1 + width; i < h2_low1; i += width)\n            {\n                bits[i] = lineBackColor2;\n            }\n        }\n\n        for (i = x; i < h1_low1; i += width)\n        {\n            bits[i] = lineBackColor1;\n        }\n\n        // Draw the grid.\n\n        if (flags & PH_GRAPH_USE_GRID_X)\n        {\n            // Draw the vertical grid line.\n            if (gridYCounter == 0)\n            {\n                for (i = x; i < numberOfPixels; i += width)\n                {\n                    bits[i] = gridColor;\n                }\n            }\n\n            gridYCounter++;\n\n            if (gridYCounter == DrawInfo->GridWidth)\n                gridYCounter = 0;\n        }\n\n        if (flags & PH_GRAPH_USE_GRID_Y)\n        {\n            FLOAT level;\n            LONG h;\n            LONG h_last;\n\n            // Draw the horizontal grid line.\n            if (flags & PH_GRAPH_LOGARITHMIC_GRID_Y)\n            {\n                level = gridLevel;\n                h = (LONG)(level * (height - 1));\n                h_last = height + gridYThreshold - 1;\n\n                while (TRUE)\n                {\n                    if (h <= h_last - gridYThreshold)\n                    {\n                        bits[x + h * width] = gridColor;\n                        h_last = h;\n                    }\n                    else\n                    {\n                        break;\n                    }\n\n                    level /= gridBase;\n                    h = (LONG)(level * (height - 1));\n                }\n            }\n            else\n            {\n                level = gridHeight;\n                h = (LONG)(level * (height - 1));\n                h_last = 0;\n\n                while (h < height - 1)\n                {\n                    if (h >= h_last + gridYThreshold)\n                    {\n                        bits[x + h * width] = gridColor;\n                        h_last = h;\n                    }\n\n                    level += gridHeight;\n                    h = (LONG)(level * (height - 1));\n                }\n            }\n        }\n\n        // Draw the outline (line 1 is allowed to paint over line 2).\n\n        if (flags & PH_GRAPH_USE_LINE_2)\n        {\n            for (i = h2_low1; i <= h2_high1; i += width) // exclude pixel in the middle\n            {\n                bits[i] = lineColor2;\n            }\n        }\n\n        for (i = h1_low1; i <= h1_high1; i += width)\n        {\n            bits[i] = lineColor1;\n        }\n\n        intermediate = !intermediate;\n        x--;\n    }\n\n    if ((flags & PH_GRAPH_LABEL_MAX_Y) && yLabelDataIndex < DrawInfo->LineDataCount)\n    {\n        FLOAT value;\n        PPH_STRING label;\n\n        value = DrawInfo->LineData1[yLabelDataIndex];\n\n        if (flags & PH_GRAPH_USE_LINE_2)\n            value += DrawInfo->LineData2[yLabelDataIndex];\n\n        if (label = DrawInfo->LabelYFunction(DrawInfo, yLabelDataIndex, value, DrawInfo->LabelYFunctionParameter))\n        {\n            HFONT oldFont = NULL;\n            SIZE textSize;\n            RECT rect;\n\n            if (DrawInfo->LabelYFont)\n                oldFont = SelectFont(hdc, DrawInfo->LabelYFont);\n\n            SetTextColor(hdc, DrawInfo->LabelYColor);\n            SetBkMode(hdc, TRANSPARENT);\n\n            GetTextExtentPoint32(hdc, label->Buffer, (ULONG)label->Length / sizeof(WCHAR), &textSize);\n\n            rect.bottom = height - yLabelMax - PhNormalGraphTextPadding.top;\n            rect.top = rect.bottom - textSize.cy;\n\n            if (rect.top < PhNormalGraphTextPadding.top)\n            {\n                rect.top = PhNormalGraphTextPadding.top;\n                rect.bottom = rect.top + textSize.cy;\n            }\n\n            rect.left = 0;\n            rect.right = width - min((LONG)yLabelDataIndex * 2, width) - PhNormalGraphTextPadding.right;\n            DrawText(hdc, label->Buffer, (ULONG)label->Length / sizeof(WCHAR), &rect, DT_NOCLIP | DT_RIGHT);\n\n            if (oldFont)\n                SelectFont(hdc, oldFont);\n\n            PhDereferenceObject(label);\n        }\n    }\n\n    if (DrawInfo->Text.Buffer)\n    {\n        HFONT oldFont = NULL;\n        HBRUSH brush;\n\n        if (DrawInfo->TextFont)\n            oldFont = SelectFont(hdc, DrawInfo->TextFont);\n\n        SetBkMode(hdc, TRANSPARENT);\n\n        // Fill in the text box.\n        brush = PhGetStockBrush(DC_BRUSH);\n        SelectBrush(hdc, brush);\n        SetDCBrushColor(hdc, DrawInfo->TextBoxColor);\n        FillRect(hdc, &DrawInfo->TextBoxRect, brush);\n\n        // Draw the text.\n        SetTextColor(hdc, DrawInfo->TextColor);\n        DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / sizeof(WCHAR), &DrawInfo->TextRect, DT_NOCLIP);\n\n        if (oldFont)\n            SelectFont(hdc, oldFont);\n    }\n\n    if (DrawInfo->Text2.Buffer)\n    {\n        HFONT oldFont = NULL;\n\n        if (DrawInfo->TextFont)\n            oldFont = SelectFont(hdc, DrawInfo->TextFont);\n\n        //SetBkMode(hdc, TRANSPARENT);\n\n        // Fill in the text box.\n        SetDCBrushColor(hdc, DrawInfo->TextBoxColor);\n        FillRect(hdc, &DrawInfo->TextBoxRect2, PhGetStockBrush(DC_BRUSH));\n\n        // Draw the text.\n        SetTextColor(hdc, DrawInfo->TextColor);\n        DrawText(hdc, DrawInfo->Text2.Buffer, (ULONG)DrawInfo->Text2.Length / sizeof(WCHAR), &DrawInfo->TextRect2, DT_NOCLIP);\n\n        if (oldFont)\n            SelectFont(hdc, oldFont);\n    }\n}\n\n/**\n * Sets the text in a graphing information structure.\n *\n * \\param hdc The DC to perform calculations from.\n * \\param DrawInfo A structure which contains graphing information. The structure is modified to\n * contain the new text information.\n * \\param Text The text.\n * \\param Margin The margins of the text box from the edges of the graph.\n * \\param Padding The padding within the text box.\n * \\param Align The alignment of the text box.\n */\nVOID PhSetGraphText(\n    _In_ HDC hdc,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text,\n    _In_ PRECT Margin,\n    _In_ PRECT Padding,\n    _In_ ULONG Align\n    )\n{\n    HFONT oldFont = NULL;\n    SIZE textSize;\n    PH_RECTANGLE boxRectangle;\n    PH_RECTANGLE textRectangle;\n\n    if (DrawInfo->TextFont)\n        oldFont = SelectFont(hdc, DrawInfo->TextFont);\n\n    DrawInfo->Text = *Text;\n    GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / sizeof(WCHAR), &textSize);\n\n    if (oldFont)\n        SelectFont(hdc, oldFont);\n\n    // Calculate the box rectangle.\n\n    boxRectangle.Width = textSize.cx + Padding->left + Padding->right;\n    boxRectangle.Height = textSize.cy + Padding->top + Padding->bottom;\n\n    if (Align & PH_ALIGN_LEFT)\n        boxRectangle.Left = Margin->left;\n    else if (Align & PH_ALIGN_RIGHT)\n        boxRectangle.Left = DrawInfo->Width - boxRectangle.Width - Margin->right;\n    else\n        boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / 2;\n\n    if (Align & PH_ALIGN_TOP)\n        boxRectangle.Top = Margin->top;\n    else if (Align & PH_ALIGN_BOTTOM)\n        boxRectangle.Top = DrawInfo->Height - boxRectangle.Height - Margin->bottom;\n    else\n        boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / 2;\n\n    // Calculate the text rectangle.\n\n    textRectangle.Left = boxRectangle.Left + Padding->left;\n    textRectangle.Top = boxRectangle.Top + Padding->top;\n    textRectangle.Width = textSize.cx;\n    textRectangle.Height = textSize.cy;\n\n    // Save the rectangles.\n    PhRectangleToRect(&DrawInfo->TextRect, &textRectangle);\n    PhRectangleToRect(&DrawInfo->TextBoxRect, &boxRectangle);\n}\n\nVOID PhSetGraphText2(\n    _In_ HDC hdc,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text,\n    _In_ PRECT Margin,\n    _In_ PRECT Padding,\n    _In_ ULONG Align\n    )\n{\n    HFONT oldFont = NULL;\n    RECT calcRect = { 0, 0, DrawInfo->Width, DrawInfo->Height };\n    UINT flags = DT_NOPREFIX | DT_WORDBREAK | DT_EDITCONTROL;\n    PH_RECTANGLE boxRectangle;\n    PH_RECTANGLE textRectangle;\n\n    // Horizontal alignment\n    if (FlagOn(Align, PH_ALIGN_LEFT))\n        flags |= DT_LEFT;\n    else if (FlagOn(Align, PH_ALIGN_RIGHT))\n        flags |= DT_RIGHT;\n    else\n        flags |= DT_CENTER;\n\n    // Vertical alignment (handled manually after measuring)\n    // DT_TOP is default; DT_VCENTER/DT_BOTTOM don't work with CALCRECT\n    flags |= DT_TOP;\n\n    // Select font for measurement\n    if (DrawInfo->TextFont)\n        oldFont = SelectFont(hdc, DrawInfo->TextFont);\n\n    // Measure multi-line text\n    DrawInfo->Text = *Text;\n    DrawText(\n        hdc,\n        Text->Buffer,\n        (LONG)(Text->Length / sizeof(WCHAR)),\n        &calcRect,\n        flags | DT_CALCRECT\n        );\n\n    if (oldFont)\n        SelectFont(hdc, oldFont);\n\n    // Compute box size\n    LONG textWidth = calcRect.right - calcRect.left;\n    LONG textHeight = calcRect.bottom - calcRect.top;\n\n    boxRectangle.Width = textWidth + Padding->left + Padding->right;\n    boxRectangle.Height = textHeight + Padding->top + Padding->bottom;\n\n    // Horizontal positioning\n    if (FlagOn(Align, PH_ALIGN_LEFT))\n        boxRectangle.Left = Margin->left;\n    else if (FlagOn(Align, PH_ALIGN_RIGHT))\n        boxRectangle.Left = DrawInfo->Width - boxRectangle.Width - Margin->right;\n    else\n        boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / 2;\n\n    // Vertical positioning\n    if (FlagOn(Align, PH_ALIGN_TOP))\n        boxRectangle.Top = Margin->top;\n    else if (FlagOn(Align, PH_ALIGN_BOTTOM))\n        boxRectangle.Top = DrawInfo->Height - boxRectangle.Height - Margin->bottom;\n    else\n        boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / 2;\n\n    // Compute final text rectangle\n    textRectangle.Left = boxRectangle.Left + Padding->left;\n    textRectangle.Top = boxRectangle.Top + Padding->top;\n    textRectangle.Width = textWidth;\n    textRectangle.Height = textHeight;\n\n    // Save rectangles\n    PhRectangleToRect(&DrawInfo->TextRect, &textRectangle);\n    PhRectangleToRect(&DrawInfo->TextBoxRect, &boxRectangle);\n}\n\nPPHP_GRAPH_CONTEXT PhCreateGraphContext(\n    VOID\n    )\n{\n    PPHP_GRAPH_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_GRAPH_CONTEXT));\n    memset(context, 0, sizeof(PHP_GRAPH_CONTEXT));\n\n    context->DrawInfo.Width = 3;\n    context->DrawInfo.Height = 3;\n    context->DrawInfo.Flags = PH_GRAPH_USE_GRID_X;\n    context->DrawInfo.Step = 2;\n    context->DrawInfo.BackColor = RGB(0xef, 0xef, 0xef);\n    context->DrawInfo.LineDataCount = 0;\n    context->DrawInfo.LineData1 = NULL;\n    context->DrawInfo.LineData2 = NULL;\n    context->DrawInfo.LineColor1 = RGB(0x00, 0xff, 0x00);\n    context->DrawInfo.LineColor2 = RGB(0xff, 0x00, 0x00);\n    context->DrawInfo.LineBackColor1 = RGB(0x00, 0x77, 0x00);\n    context->DrawInfo.LineBackColor2 = RGB(0x77, 0x00, 0x00);\n    context->DrawInfo.GridColor = RGB(0xc7, 0xc7, 0xc7);\n    context->DrawInfo.GridWidth = 20;\n    context->DrawInfo.GridHeight = 0.25f;\n    context->DrawInfo.GridXOffset = 0;\n    context->DrawInfo.GridYThreshold = 10;\n    context->DrawInfo.GridBase = 2.0f;\n    context->DrawInfo.LabelYColor = RGB(0x77, 0x77, 0x77);\n    context->DrawInfo.LabelMaxYIndexLimit = -1;\n    context->DrawInfo.TextColor = RGB(0x00, 0xff, 0x00);\n    context->DrawInfo.TextBoxColor = RGB(0x00, 0x22, 0x00);\n\n    context->Options.FadeOutBackColor = RGB(0xef, 0xef, 0xef);\n    context->Options.FadeOutWidth = 100;\n\n    return context;\n}\n\nVOID PhpFreeGraphContext(\n    _Inout_ _Post_invalid_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    PhFree(Context);\n}\n\nstatic VOID PhpDeleteBufferedContext(\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    if (Context->BufferedContext && Context->BufferedOldBitmap)\n    {\n        SelectBitmap(Context->BufferedContext, Context->BufferedOldBitmap);\n        Context->BufferedOldBitmap = NULL;\n    }\n\n    if (Context->BufferedBitmap)\n    {\n        DeleteBitmap(Context->BufferedBitmap);\n        Context->BufferedBitmap = NULL;\n    }\n\n    if (Context->BufferedContext)\n    {\n        DeleteDC(Context->BufferedContext);\n        Context->BufferedContext = NULL;\n    }\n\n    Context->BufferedBits = NULL;\n}\n\nstatic VOID PhpCreateBufferedContext(\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    PhpDeleteBufferedContext(Context);\n\n    if (!PhGetClientRect(Context->Handle, &Context->BufferedContextRect))\n        return;\n\n    Context->BufferedContext = CreateCompatibleDC(NULL);\n\n    if (!Context->BufferedContext)\n        return;\n\n    Context->BufferedBitmap = PhCreateDIBSection(\n        Context->BufferedContext,\n        PHBF_DIB,\n        Context->BufferedContextRect.right,\n        Context->BufferedContextRect.bottom,\n        &Context->BufferedBits\n        );\n\n    if (!Context->BufferedBitmap)\n        return;\n\n    Context->BufferedOldBitmap = SelectBitmap(\n        Context->BufferedContext,\n        Context->BufferedBitmap\n        );\n}\n\nstatic VOID PhpDeleteFadeOutContext(\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    if (Context->FadeOutContext && Context->FadeOutOldBitmap)\n    {\n        SelectBitmap(Context->FadeOutContext, Context->FadeOutOldBitmap);\n        Context->FadeOutOldBitmap = NULL;\n    }\n\n    if (Context->FadeOutBitmap)\n    {\n        DeleteBitmap(Context->FadeOutBitmap);\n        Context->FadeOutBitmap = NULL;\n    }\n\n    if (Context->FadeOutContext)\n    {\n        DeleteDC(Context->FadeOutContext);\n        Context->FadeOutContext = NULL;\n    }\n\n    Context->FadeOutBits = NULL;\n}\n\nstatic VOID PhpCreateFadeOutContext(\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    ULONG i;\n    ULONG j;\n    ULONG height;\n    COLORREF backColor;\n    ULONG fadeOutWidth;\n    FLOAT fadeOutWidthSquared;\n    ULONG currentAlpha;\n    ULONG currentColor;\n\n    PhpDeleteFadeOutContext(Context);\n\n    if (!PhGetClientRect(Context->Handle, &Context->FadeOutContextRect))\n        return;\n    Context->FadeOutContextRect.right = Context->Options.FadeOutWidth;\n\n    Context->FadeOutContext = CreateCompatibleDC(NULL);\n\n    if (!Context->FadeOutContext)\n        return;\n\n    Context->FadeOutBitmap = PhCreateDIBSection(\n        Context->FadeOutContext,\n        PHBF_DIB,\n        Context->FadeOutContextRect.right,\n        Context->FadeOutContextRect.bottom,\n        &Context->FadeOutBits\n        );\n\n    if (!Context->FadeOutBitmap || !Context->FadeOutBits)\n        return;\n\n    Context->FadeOutOldBitmap = SelectBitmap(Context->FadeOutContext, Context->FadeOutBitmap);\n\n    if (!Context->FadeOutOldBitmap)\n        return;\n\n    height = Context->FadeOutContextRect.bottom;\n    backColor = Context->Options.FadeOutBackColor;\n    fadeOutWidth = Context->Options.FadeOutWidth;\n    fadeOutWidthSquared = (FLOAT)fadeOutWidth * fadeOutWidth;\n\n    for (i = 0; i < fadeOutWidth; i++)\n    {\n        currentAlpha = 255 - (ULONG)((FLOAT)(i * i) / fadeOutWidthSquared * 255);\n        currentColor =\n            ((backColor & 0xff) * currentAlpha / 255) +\n            ((((backColor >> 8) & 0xff) * currentAlpha / 255) << 8) +\n            ((((backColor >> 16) & 0xff) * currentAlpha / 255) << 16) +\n            (currentAlpha << 24);\n\n        for (j = i; j < height * fadeOutWidth; j += fadeOutWidth)\n        {\n            ((PULONG)Context->FadeOutBits)[j] = currentColor;\n        }\n    }\n}\n\nVOID PhpUpdateDrawInfo(\n    _In_ HWND hwnd,\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    PH_GRAPH_GETDRAWINFO getDrawInfo;\n\n    if (!(Context->BufferedContextRect.right && Context->BufferedContextRect.bottom))\n        return;\n\n    Context->DrawInfo.Width = Context->BufferedContextRect.right;\n    Context->DrawInfo.Height = Context->BufferedContextRect.bottom;\n\n    memset(&getDrawInfo, 0, sizeof(PH_GRAPH_GETDRAWINFO));\n    getDrawInfo.Header.hwndFrom = hwnd;\n    getDrawInfo.Header.idFrom = Context->Id;\n    getDrawInfo.Header.code = GCN_GETDRAWINFO;\n    getDrawInfo.DrawInfo = &Context->DrawInfo;\n\n    if (Context->Callback)\n        Context->Callback(hwnd, GCN_GETDRAWINFO, &getDrawInfo, NULL, Context->Context);\n    else\n        SendMessage(Context->ParentHandle, WM_NOTIFY, 0, (LPARAM)&getDrawInfo);\n}\n\nVOID PhpDrawGraphControl(\n    _In_ HWND hwnd,\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    if (Context->BufferedBits)\n        PhDrawGraphDirect(Context->BufferedContext, Context->BufferedBits, &Context->DrawInfo);\n\n    if (Context->Style & GC_STYLE_FADEOUT)\n    {\n        BLENDFUNCTION blendFunction;\n\n        if (!Context->FadeOutContext)\n            PhpCreateFadeOutContext(Context);\n\n        blendFunction.BlendOp = AC_SRC_OVER;\n        blendFunction.BlendFlags = 0;\n        blendFunction.SourceConstantAlpha = 255;\n        blendFunction.AlphaFormat = AC_SRC_ALPHA;\n\n        if (Context->FadeOutContext)\n        {\n            GdiAlphaBlend(\n                Context->BufferedContext,\n                0,\n                0,\n                Context->Options.FadeOutWidth,\n                Context->FadeOutContextRect.bottom,\n                Context->FadeOutContext,\n                0,\n                0,\n                Context->Options.FadeOutWidth,\n                Context->FadeOutContextRect.bottom,\n                blendFunction\n                );\n        }\n    }\n\n    if (Context->Style & GC_STYLE_DRAW_PANEL)\n    {\n        PH_GRAPH_DRAWPANEL drawPanel;\n\n        memset(&drawPanel, 0, sizeof(PH_GRAPH_DRAWPANEL));\n        drawPanel.Header.hwndFrom = hwnd;\n        drawPanel.Header.idFrom = Context->Id;\n        drawPanel.Header.code = GCN_DRAWPANEL;\n        drawPanel.hdc = Context->BufferedContext;\n        drawPanel.Rect = Context->BufferedContextRect;\n\n        if (Context->Callback)\n            Context->Callback(hwnd, GCN_DRAWPANEL, &drawPanel, NULL, Context->Context);\n        else\n            SendMessage(Context->ParentHandle, WM_NOTIFY, 0, (LPARAM)&drawPanel);\n    }\n}\n\nLRESULT CALLBACK PhpGraphWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_GRAPH_CONTEXT context;\n\n    if (uMsg == WM_NCCREATE)\n    {\n        context = PhCreateGraphContext();\n        PhSetWindowContextEx(hwnd, context);\n    }\n    else\n    {\n        context = PhGetWindowContextEx(hwnd);\n    }\n\n    switch (uMsg)\n    {\n    case WM_NCCREATE:\n        {\n            CREATESTRUCT *createStruct = (CREATESTRUCT *)lParam;\n\n            context->Handle = hwnd;\n            context->ParentHandle = createStruct->hwndParent;\n            context->Style = createStruct->style;\n            context->Id = (ULONG_PTR)createStruct->hMenu;\n\n            if (createStruct->lpCreateParams)\n            {\n                PPH_GRAPH_CREATEPARAMS params = createStruct->lpCreateParams;\n\n                if (RTL_CONTAINS_FIELD(params, params->Size, Options))\n                {\n                    if (params->Options.DefaultCursor || params->Options.FadeOutBackColor || params->Options.FadeOutWidth)\n                    {\n                        memcpy(&context->Options, &params->Options, sizeof(PH_GRAPH_OPTIONS));\n                    }\n                }\n\n                if (RTL_CONTAINS_FIELD(params, params->Size, Callback))\n                {\n                    if (params->Callback)\n                    {\n                        context->Callback = params->Callback;\n                    }\n                }\n\n                if (RTL_CONTAINS_FIELD(params, params->Size, Context))\n                {\n                    if (params->Context)\n                    {\n                        context->Context = params->Context;\n                    }\n                }\n            }\n\n            PhSetWindowContextEx(hwnd, context);\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContextEx(hwnd);\n\n            if (context->TooltipHandle)\n                DestroyWindow(context->TooltipHandle);\n\n            PhpDeleteFadeOutContext(context);\n            PhpDeleteBufferedContext(context);\n            PhpFreeGraphContext(context);\n        }\n        break;\n    case WM_STYLECHANGED:\n        {\n            STYLESTRUCT *styleStruct = (STYLESTRUCT *)lParam;\n\n            if (wParam == GWL_STYLE)\n            {\n                context->Style = styleStruct->styleNew;\n                context->NeedsDraw = TRUE;\n            }\n\n            if (wParam == GWL_EXSTYLE)\n            {\n                context->ExStyle = styleStruct->styleNew;\n                context->NeedsDraw = TRUE;\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            // Force a re-create of the buffered context.\n            PhpDeleteBufferedContext(context);\n            PhpCreateBufferedContext(context);\n            PhpDeleteFadeOutContext(context);\n\n            PhpUpdateDrawInfo(hwnd, context);\n            context->NeedsDraw = TRUE;\n            InvalidateRect(hwnd, NULL, FALSE);\n\n            if (context->TooltipHandle)\n            {\n                TOOLINFO toolInfo;\n\n                memset(&toolInfo, 0, sizeof(TOOLINFO));\n                toolInfo.cbSize = sizeof(TOOLINFO);\n                toolInfo.hwnd = hwnd;\n                toolInfo.uId = 1;\n\n                if (PhGetClientRect(hwnd, &toolInfo.rect))\n                {\n                    SendMessage(context->TooltipHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo);\n                }\n            }\n        }\n        break;\n    case WM_PAINT:\n        {\n            PAINTSTRUCT paintStruct;\n            HDC hdc;\n\n            if (hdc = BeginPaint(hwnd, &paintStruct))\n            {\n                if (!context->BufferedContext)\n                    PhpCreateBufferedContext(context);\n\n                if (context->NeedsUpdate)\n                {\n                    PhpUpdateDrawInfo(hwnd, context);\n                    context->NeedsUpdate = FALSE;\n                }\n\n                if (context->NeedsDraw)\n                {\n                    PhpDrawGraphControl(hwnd, context);\n                    context->NeedsDraw = FALSE;\n                }\n\n                BitBlt(\n                    hdc,\n                    paintStruct.rcPaint.left,\n                    paintStruct.rcPaint.top,\n                    paintStruct.rcPaint.right - paintStruct.rcPaint.left,\n                    paintStruct.rcPaint.bottom - paintStruct.rcPaint.top,\n                    context->BufferedContext,\n                    paintStruct.rcPaint.left,\n                    paintStruct.rcPaint.top,\n                    SRCCOPY\n                    );\n\n                EndPaint(hwnd, &paintStruct);\n            }\n        }\n        return 0;\n    case WM_ERASEBKGND:\n        return 1;\n    //case WM_NCPAINT:\n    //    {\n    //        HRGN updateRegion;\n    //\n    //        updateRegion = (HRGN)wParam;\n    //\n    //        if (updateRegion == HRGN_FULL)\n    //            updateRegion = NULL;\n    //\n    //        // Themed border\n    //        if (context->Style & WS_BORDER)\n    //        {\n    //            HDC hdc;\n    //            ULONG flags;\n    //            RECT rect;\n    //\n    //            // Note the use of undocumented flags below. GetDCEx doesn't work without these.\n    //\n    //            flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000;\n    //\n    //            if (updateRegion)\n    //                flags |= DCX_INTERSECTRGN | 0x40000;\n    //\n    //            if (hdc = GetDCEx(hwnd, updateRegion, flags))\n    //            {\n    //                GetClientRect(hwnd, &rect);\n    //                rect.right += 2;\n    //                rect.bottom += 2;\n    //                SetDCBrushColor(hdc, RGB(0x8f, 0x8f, 0x8f));\n    //                FrameRect(hdc, &rect, PhGetStockBrush(DC_BRUSH));\n    //\n    //                ReleaseDC(hwnd, hdc);\n    //                return 0;\n    //            }\n    //        }\n    //    }\n    //    break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            if (!context->TooltipHandle)\n                break;\n\n            if (header->hwndFrom == context->TooltipHandle)\n            {\n                switch (header->code)\n                {\n                case TTN_GETDISPINFO:\n                    {\n                        LPNMTTDISPINFO dispInfo = (LPNMTTDISPINFO)header;\n                        POINT point;\n                        RECT clientRect;\n                        PH_GRAPH_GETTOOLTIPTEXT getTooltipText;\n\n                        if (!PhGetClientPos(hwnd, &point))\n                            break;\n                        if (!PhGetClientRect(hwnd, &clientRect))\n                            break;\n\n                        memset(&getTooltipText, 0, sizeof(PH_GRAPH_GETTOOLTIPTEXT));\n                        getTooltipText.Header.hwndFrom = hwnd;\n                        getTooltipText.Header.idFrom = context->Id;\n                        getTooltipText.Header.code = GCN_GETTOOLTIPTEXT;\n                        getTooltipText.Index = (clientRect.right - point.x - 1) / context->DrawInfo.Step;\n                        getTooltipText.TotalCount = context->DrawInfo.LineDataCount;\n                        getTooltipText.Text.Buffer = NULL;\n                        getTooltipText.Text.Length = 0;\n\n                        if (context->Callback)\n                            context->Callback(hwnd, GCN_GETTOOLTIPTEXT, &getTooltipText, NULL, context->Context);\n                        else\n                            SendMessage(context->ParentHandle, WM_NOTIFY, 0, (LPARAM)&getTooltipText);\n\n                        if (getTooltipText.Text.Buffer)\n                        {\n                            dispInfo->lpszText = getTooltipText.Text.Buffer;\n                        }\n                    }\n                    break;\n                }\n            }\n        }\n        break;\n    case WM_SETCURSOR:\n        {\n            if (context->Options.DefaultCursor)\n            {\n                PhSetCursor(context->Options.DefaultCursor);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_MOUSEMOVE:\n        {\n            POINT cursorPos;\n\n            cursorPos.x = GET_X_LPARAM(lParam);\n            cursorPos.y = GET_Y_LPARAM(lParam);\n\n            if (context->TooltipHandle)\n            {\n                MSG message;\n\n                memset(&message, 0, sizeof(message));\n                message.hwnd = hwnd;\n                message.message = uMsg;\n                message.wParam = wParam;\n                message.lParam = lParam;\n\n                SendMessage(context->TooltipHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n\n            if (context->LastCursorLocation.x != cursorPos.x || context->LastCursorLocation.y != cursorPos.y)\n            {\n                if (context->TooltipHandle)\n                    SendMessage(context->TooltipHandle, TTM_UPDATE, 0, 0);\n\n                context->LastCursorLocation = cursorPos;\n            }\n\n            if (!context->Hot)\n            {\n                TRACKMOUSEEVENT trackMouseEvent;\n\n                context->Hot = TRUE;\n\n                memset(&trackMouseEvent, 0, sizeof(TRACKMOUSEEVENT));\n                trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);\n                trackMouseEvent.dwFlags = TME_LEAVE;\n                trackMouseEvent.hwndTrack = hwnd;\n                trackMouseEvent.dwHoverTime = 0;\n\n                TrackMouseEvent(&trackMouseEvent);\n            }\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            context->Hot = FALSE;\n\n            if (context->TooltipHandle)\n            {\n                SendMessage(context->TooltipHandle, TTM_POP, 0, 0);\n            }\n        }\n        break;\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_LBUTTONDBLCLK:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_RBUTTONDBLCLK:\n        {\n            PH_GRAPH_MOUSEEVENT mouseEvent;\n            RECT clientRect;\n\n            if (context->TooltipHandle)\n            {\n                MSG message;\n\n                memset(&message, 0, sizeof(message));\n                message.hwnd = hwnd;\n                message.message = uMsg;\n                message.wParam = wParam;\n                message.lParam = lParam;\n\n                SendMessage(context->TooltipHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n\n            if (!PhGetClientRect(hwnd, &clientRect))\n                break;\n\n            memset(&mouseEvent, 0, sizeof(PH_GRAPH_MOUSEEVENT));\n            mouseEvent.Header.hwndFrom = hwnd;\n            mouseEvent.Header.idFrom = context->Id;\n            mouseEvent.Header.code = GCN_MOUSEEVENT;\n            mouseEvent.Message = uMsg;\n            mouseEvent.Keys = (ULONG)wParam;\n            mouseEvent.Point.x = GET_X_LPARAM(lParam);\n            mouseEvent.Point.y = GET_Y_LPARAM(lParam);\n\n            mouseEvent.Index = (clientRect.right - mouseEvent.Point.x - 1) / context->DrawInfo.Step;\n            mouseEvent.TotalCount = context->DrawInfo.LineDataCount;\n\n            if (context->Callback)\n                context->Callback(hwnd, GCN_MOUSEEVENT, &mouseEvent, NULL, context->Context);\n            else\n                SendMessage(context->ParentHandle, WM_NOTIFY, 0, (LPARAM)&mouseEvent);\n        }\n        break;\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n        {\n            if (context->TooltipHandle)\n            {\n                MSG message;\n\n                memset(&message, 0, sizeof(message));\n                message.hwnd = hwnd;\n                message.message = uMsg;\n                message.wParam = wParam;\n                message.lParam = lParam;\n\n                SendMessage(context->TooltipHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n        }\n        break;\n    case GCM_GETDRAWINFO:\n        {\n            PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)lParam;\n\n            memcpy(drawInfo, &context->DrawInfo, sizeof(PH_GRAPH_DRAW_INFO));\n        }\n        return TRUE;\n    case GCM_SETDRAWINFO:\n        {\n            PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)lParam;\n            ULONG width;\n            ULONG height;\n\n            width = context->DrawInfo.Width;\n            height = context->DrawInfo.Height;\n            memcpy(&context->DrawInfo, drawInfo, sizeof(PH_GRAPH_DRAW_INFO));\n            context->DrawInfo.Width = width;\n            context->DrawInfo.Height = height;\n        }\n        return TRUE;\n    case GCM_DRAW:\n        {\n            PhpUpdateDrawInfo(hwnd, context);\n            context->NeedsDraw = TRUE;\n        }\n        return TRUE;\n    case GCM_MOVEGRID:\n        {\n            LONG increment = (LONG)wParam;\n\n            context->DrawInfo.GridXOffset += increment;\n        }\n        return TRUE;\n    case GCM_GETBUFFEREDCONTEXT:\n        return (LRESULT)context->BufferedContext;\n    case GCM_SETTOOLTIP:\n        {\n            if (wParam)\n            {\n                TOOLINFO toolInfo;\n\n                context->TooltipHandle = PhCreateWindowEx(\n                    TOOLTIPS_CLASS,\n                    NULL,\n                    WS_POPUP | TTS_NOPREFIX | TTS_NOANIMATE | TTS_NOFADE | TTS_ALWAYSTIP,\n                    WS_EX_TOPMOST | WS_EX_TRANSPARENT,\n                    CW_USEDEFAULT,\n                    CW_USEDEFAULT,\n                    CW_USEDEFAULT,\n                    CW_USEDEFAULT,\n                    NULL,\n                    NULL,\n                    NULL,\n                    NULL\n                    );\n\n                SetWindowPos(context->TooltipHandle, HWND_TOPMOST, 0, 0, 0, 0,\n                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);\n\n                memset(&toolInfo, 0, sizeof(TOOLINFO));\n                toolInfo.cbSize = sizeof(TOOLINFO);\n                toolInfo.uFlags = 0;\n                toolInfo.hwnd = hwnd;\n                toolInfo.uId = 1;\n                toolInfo.lpszText = LPSTR_TEXTCALLBACK;\n\n                SendMessage(context->TooltipHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);\n                SendMessage(context->TooltipHandle, TTM_SETDELAYTIME, TTDT_INITIAL, 0);\n                SendMessage(context->TooltipHandle, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);\n                // Allow newlines (-1 doesn't work)\n                SendMessage(context->TooltipHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT);\n\n                if (PhEnableThemeSupport)\n                {\n                    PhSetControlTheme(context->TooltipHandle, L\"DarkMode_Explorer\");\n                    //SendMessage(context->TooltipHandle, TTM_SETWINDOWTHEME, 0, (LPARAM)L\"DarkMode_Explorer\");\n                }\n            }\n            else\n            {\n                if (context->TooltipHandle)\n                {\n                    DestroyWindow(context->TooltipHandle);\n                    context->TooltipHandle = NULL;\n                }\n            }\n        }\n        return TRUE;\n    case GCM_UPDATETOOLTIP:\n        {\n            if (!context->TooltipHandle)\n                return FALSE;\n\n            SendMessage(context->TooltipHandle, TTM_UPDATE, 0, 0);\n        }\n        return TRUE;\n    case GCM_GETOPTIONS:\n        memcpy((PPH_GRAPH_OPTIONS)lParam, &context->Options, sizeof(PH_GRAPH_OPTIONS));\n        return TRUE;\n    case GCM_SETOPTIONS:\n        memcpy(&context->Options, (PPH_GRAPH_OPTIONS)lParam, sizeof(PH_GRAPH_OPTIONS));\n        PhpDeleteFadeOutContext(context);\n        return TRUE;\n    case GCM_UPDATE:\n        {\n            #define INCREMENT_OFFSET 1\n\n            // GCM_MOVEGRID\n\n            context->DrawInfo.GridXOffset += INCREMENT_OFFSET;\n\n            // GCM_DRAW\n\n            PhpUpdateDrawInfo(hwnd, context);\n            context->NeedsDraw = TRUE;\n\n            // GCM_UPDATETOOLTIP\n\n            if (context->TooltipHandle)\n            {\n                SendMessage(context->TooltipHandle, TTM_UPDATE, 0, 0);\n            }\n\n            InvalidateRect(hwnd, NULL, FALSE);\n        }\n        return TRUE;\n    case GCM_SETCALLBACK:\n        {\n            context->Callback = (PVOID)wParam;\n            context->Context = (PVOID)lParam;\n        }\n        return TRUE;\n    }\n\n    return DefWindowProc(hwnd, uMsg, wParam, lParam);\n}\n\n/**\n * Initializes a graph buffer management structure.\n *\n * \\param Buffers The buffer management structure.\n */\nVOID PhInitializeGraphBuffers(\n    _Out_ PPH_GRAPH_BUFFERS Buffers\n    )\n{\n    Buffers->AllocatedCount = 0;\n    Buffers->Data1 = NULL;\n    Buffers->Data2 = NULL;\n    Buffers->Valid = FALSE;\n}\n\n/**\n * Frees resources used by a graph buffer management structure.\n *\n * \\param Buffers The buffer management structure.\n */\nVOID PhDeleteGraphBuffers(\n    _Inout_ PPH_GRAPH_BUFFERS Buffers\n    )\n{\n    if (Buffers->Data1) PhFree(Buffers->Data1);\n    if (Buffers->Data2) PhFree(Buffers->Data2);\n\n    Buffers->AllocatedCount = 0;\n    Buffers->Data1 = NULL;\n    Buffers->Data2 = NULL;\n    Buffers->Valid = FALSE;\n}\n\n/**\n * Sets up a graphing information structure with information from a graph buffer management\n * structure.\n *\n * \\param Buffers The buffer management structure.\n * \\param DrawInfo The graphing information structure.\n * \\param DataCount The number of data points currently required. The buffers are resized if needed.\n */\nVOID PhGetDrawInfoGraphBuffers(\n    _Inout_ PPH_GRAPH_BUFFERS Buffers,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataCount\n    )\n{\n    DrawInfo->LineDataCount = min(DataCount, PH_GRAPH_DATA_COUNT(DrawInfo->Width, DrawInfo->Step));\n\n    // Do we need to allocate or re-allocate the data buffers?\n    if (Buffers->AllocatedCount < DrawInfo->LineDataCount)\n    {\n        if (Buffers->Data1)\n            PhFree(Buffers->Data1);\n        if ((DrawInfo->Flags & PH_GRAPH_USE_LINE_2) && Buffers->Data2)\n            PhFree(Buffers->Data2);\n\n        Buffers->AllocatedCount *= 2;\n\n        if (Buffers->AllocatedCount < DrawInfo->LineDataCount)\n            Buffers->AllocatedCount = DrawInfo->LineDataCount;\n\n        Buffers->Data1 = PhAllocate(Buffers->AllocatedCount * sizeof(FLOAT));\n\n        if (DrawInfo->Flags & PH_GRAPH_USE_LINE_2)\n        {\n            Buffers->Data2 = PhAllocate(Buffers->AllocatedCount * sizeof(FLOAT));\n        }\n\n        Buffers->Valid = FALSE;\n    }\n\n    DrawInfo->LineData1 = Buffers->Data1;\n    DrawInfo->LineData2 = Buffers->Data2;\n}\n\nVOID PhInitializeGraphState(\n    _Out_ PPH_GRAPH_STATE State\n    )\n{\n    PhInitializeGraphBuffers(&State->Buffers);\n    State->Text = NULL;\n    State->TooltipText = NULL;\n    State->TooltipIndex = ULONG_MAX;\n    State->TextLine2 = NULL;\n}\n\nVOID PhDeleteGraphState(\n    _Inout_ PPH_GRAPH_STATE State\n    )\n{\n    PhDeleteGraphBuffers(&State->Buffers);\n    if (State->Text) PhDereferenceObject(State->Text);\n    if (State->TooltipText) PhDereferenceObject(State->TooltipText);\n    if (State->TextLine2) PhDereferenceObject(State->TextLine2);\n}\n\nVOID PhGraphStateGetDrawInfo(\n    _Inout_ PPH_GRAPH_STATE State,\n    _In_ PPH_GRAPH_GETDRAWINFO GetDrawInfo,\n    _In_ ULONG DataCount\n    )\n{\n    PhGetDrawInfoGraphBuffers(&State->Buffers, GetDrawInfo->DrawInfo, DataCount);\n}\n"
  },
  {
    "path": "phlib/guisup.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <guisup.h>\n#include <mapimg.h>\n#include <mapldr.h>\n#include <settings.h>\n#include <guisupp.h>\n\n#include <commoncontrols.h>\n#include <shellscalingapi.h>\n#include <wincodec.h>\n#include <uxtheme.h>\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PhpWindowContextHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpWindowContextHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PhpWindowCallbackHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhpWindowCallbackHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\nVOID NTAPI PhWindowFlsCallback(\n    _In_ PVOID FlsData\n    );\n\ntypedef struct _PH_WINDOW_PROPERTY_CONTEXT\n{\n    ULONG PropertyHash;\n    HWND WindowHandle;\n    PVOID Context;\n} PH_WINDOW_PROPERTY_CONTEXT, *PPH_WINDOW_PROPERTY_CONTEXT;\n\nHFONT PhApplicationFont = NULL;\nHFONT PhTreeWindowFont = NULL;\nHFONT PhMonospaceFont = NULL;\nLONG PhFontQuality = 0;\nLONG PhSystemDpi = USER_DEFAULT_SCREEN_DPI;\nPH_INTEGER_PAIR PhSmallIconSize = { 16, 16 };\nPH_INTEGER_PAIR PhLargeIconSize = { 32, 32 };\n\nstatic PH_INITONCE SharedIconCacheInitOnce = PH_INITONCE_INIT;\nstatic PPH_HASHTABLE SharedIconCacheHashtable;\nstatic PH_QUEUED_LOCK SharedIconCacheLock = PH_QUEUED_LOCK_INIT;\n\nstatic PPH_HASHTABLE WindowCallbackHashTable = NULL;\nstatic PH_QUEUED_LOCK WindowCallbackListLock = PH_QUEUED_LOCK_INIT;\nstatic ULONG WindowCallbackFlsIndex = FLS_OUT_OF_INDEXES;\n\nstatic typeof(&OpenThemeDataForDpi) OpenThemeDataForDpi_I = NULL;\nstatic typeof(&OpenThemeData) OpenThemeData_I = NULL;\nstatic typeof(&CloseThemeData) CloseThemeData_I = NULL;\nstatic typeof(&SetWindowTheme) SetWindowTheme_I = NULL;\nstatic typeof(&IsThemeActive) IsThemeActive_I = NULL;\nstatic typeof(&IsAppThemed) IsAppThemed_I = NULL;\nstatic typeof(&IsThemePartDefined) IsThemePartDefined_I = NULL;\nstatic _GetThemeClass GetThemeClass_I = NULL;\nstatic typeof(&GetThemeColor) GetThemeColor_I = NULL;\nstatic typeof(&GetThemeInt) GetThemeInt_I = NULL;\nstatic typeof(&GetThemePartSize) GetThemePartSize_I = NULL;\nstatic typeof(&GetThemeMargins) GetThemeMargins_I = NULL;\nstatic typeof(&DrawThemeBackground) DrawThemeBackground_I = NULL;\nstatic _AllowDarkModeForWindow AllowDarkModeForWindow_I = NULL; // Win10-RS5 (uxtheme.dll ordinal 133)\nstatic _IsDarkModeAllowedForWindow IsDarkModeAllowedForWindow_I = NULL; // Win10-RS5 (uxtheme.dll ordinal 137)\nstatic typeof(&GetDpiForMonitor) GetDpiForMonitor_I = NULL; // win81+\nstatic typeof(&GetDpiForWindow) GetDpiForWindow_I = NULL; // win10rs1+\nstatic typeof(&GetDpiForSystem) GetDpiForSystem_I = NULL; // win10rs1+\n//static _GetDpiForSession GetDpiForSession_I = NULL; // ordinal 2713\nstatic typeof(&GetSystemMetricsForDpi) GetSystemMetricsForDpi_I = NULL;\nstatic typeof(&SystemParametersInfoForDpi) SystemParametersInfoForDpi_I = NULL;\nstatic _CreateMRUList CreateMRUList_I = NULL;\nstatic _AddMRUString AddMRUString_I = NULL;\nstatic _EnumMRUList EnumMRUList_I = NULL;\nstatic _FreeMRUList FreeMRUList_I = NULL;\n\n/**\n * Initializes the GUI support layer used by the support library.\n *\n * Loads optional GUI-related DLLs (uxtheme, shcore, user32 variants) and\n * resolves optional function pointers used for theme/DPI operations.\n * Also initializes internal structures such as the WindowCallback FLS slot\n * and the shared icon cache.\n */\nVOID PhGuiSupportInitialization(\n    VOID\n    )\n{\n    PVOID baseAddress;\n\n    WindowCallbackFlsIndex = FlsAlloc(PhWindowFlsCallback);\n    WindowCallbackHashTable = PhCreateHashtable(\n        sizeof(PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION),\n        PhpWindowCallbackHashtableEqualFunction,\n        PhpWindowCallbackHashtableHashFunction,\n        10\n        );\n\n    if (baseAddress = PhLoadLibrary(L\"uxtheme.dll\"))\n    {\n        OpenThemeDataForDpi_I = PhGetDllBaseProcedureAddress(baseAddress, \"OpenThemeDataForDpi\", 0);\n        OpenThemeData_I = PhGetDllBaseProcedureAddress(baseAddress, \"OpenThemeData\", 0);\n        CloseThemeData_I = PhGetDllBaseProcedureAddress(baseAddress, \"CloseThemeData\", 0);\n        SetWindowTheme_I = PhGetDllBaseProcedureAddress(baseAddress, \"SetWindowTheme\", 0);\n        IsThemeActive_I = PhGetDllBaseProcedureAddress(baseAddress, \"IsThemeActive\", 0);\n        IsAppThemed_I = PhGetDllBaseProcedureAddress(baseAddress, \"IsAppThemed\", 0);\n        IsThemePartDefined_I = PhGetDllBaseProcedureAddress(baseAddress, \"IsThemePartDefined\", 0);\n        GetThemeColor_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetThemeColor\", 0);\n        GetThemeInt_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetThemeInt\", 0);\n        GetThemePartSize_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetThemePartSize\", 0);\n        GetThemeMargins_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetThemeMargins\", 0);\n        DrawThemeBackground_I = PhGetDllBaseProcedureAddress(baseAddress, \"DrawThemeBackground\", 0);\n\n        if (WindowsVersion >= WINDOWS_11)\n        {\n            GetThemeClass_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 74);\n        }\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            AllowDarkModeForWindow_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 133);\n            IsDarkModeAllowedForWindow_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 137);\n        }\n    }\n\n    if (WindowsVersion >= WINDOWS_8_1)\n    {\n        if (baseAddress = PhLoadLibrary(L\"shcore.dll\"))\n        {\n            GetDpiForMonitor_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetDpiForMonitor\", 0);\n        }\n    }\n\n    if (WindowsVersion >= WINDOWS_10_RS1)\n    {\n        if (baseAddress = PhLoadLibrary(L\"user32.dll\"))\n        {\n            GetDpiForWindow_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetDpiForWindow\", 0);\n            GetDpiForSystem_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetDpiForSystem\", 0);\n            GetSystemMetricsForDpi_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetSystemMetricsForDpi\", 0);\n            SystemParametersInfoForDpi_I = PhGetDllBaseProcedureAddress(baseAddress, \"SystemParametersInfoForDpi\", 0);\n        }\n    }\n\n    PhGuiSupportUpdateSystemMetrics(NULL, 0);\n}\n\n/**\n * Updates system metrics cached by the GUI support layer.\n *\n * \\param WindowHandle Optional window handle used to determine DPI for metrics update.\n * \\param WindowDpi Optional DPI override; if non-zero it is used instead of querying the window/system DPI.\n */\nVOID PhGuiSupportUpdateSystemMetrics(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ LONG WindowDpi\n    )\n{\n    PhSystemDpi = WindowDpi ? WindowDpi : (WindowHandle ? PhGetWindowDpi(WindowHandle) : PhGetSystemDpi());\n    PhSmallIconSize.X = PhGetSystemMetrics(SM_CXSMICON, PhSystemDpi);\n    PhSmallIconSize.Y = PhGetSystemMetrics(SM_CYSMICON, PhSystemDpi);\n    PhLargeIconSize.X = PhGetSystemMetrics(SM_CXICON, PhSystemDpi);\n    PhLargeIconSize.Y = PhGetSystemMetrics(SM_CYICON, PhSystemDpi);\n}\n\n/**\n * Maps a font quality setting to the corresponding GDI constant.\n * \n * \\param FontQuality The font quality setting (0-6).\n * \\return The corresponding GDI font quality constant.\n */\nLONG PhGetFontQualitySetting(\n    _In_ LONG FontQuality\n    )\n{\n    switch (FontQuality)\n    {\n    case 0: return DEFAULT_QUALITY;\n    case 1: return DRAFT_QUALITY;\n    case 2: return PROOF_QUALITY;\n    case 3: return NONANTIALIASED_QUALITY;\n    case 4: return ANTIALIASED_QUALITY;\n    case 5: return CLEARTYPE_QUALITY;\n    case 6: return CLEARTYPE_NATURAL_QUALITY;\n    }\n\n    return DEFAULT_QUALITY;\n}\n\n/**\n * Creates a font with specified properties.\n * \n * \\param Name Optional pointer to the font name (typeface).\n * \\param Size The desired font size in points.\n * \\param Weight The font weight (e.g., FW_NORMAL, FW_BOLD). \n * \\param PitchAndFamily The pitch and family of the font.\n * \\param Dpi The dots per inch (DPI) value for scaling.\n * \\return Handle to the created font, or NULL if creation fails.\n */\nHFONT PhCreateFont(\n    _In_opt_ PCWSTR Name,\n    _In_ LONG Size,\n    _In_ LONG Weight,\n    _In_ LONG PitchAndFamily,\n    _In_ LONG Dpi\n    )\n{\n    return CreateFont(\n        -(LONG)PhMultiplyDivide(Size, Dpi, 72),\n        0,\n        0,\n        0,\n        Weight,\n        FALSE,\n        FALSE,\n        FALSE,\n        ANSI_CHARSET,\n        OUT_DEFAULT_PRECIS,\n        CLIP_DEFAULT_PRECIS,\n        PhFontQuality,\n        PitchAndFamily,\n        Name\n        );\n}\n\n/**\n * Creates a common font with the specified size and weight.\n *\n * \\param Size The font size in logical units.\n * \\param Weight The font weight (e.g., FW_NORMAL, FW_BOLD).\n * \\param WindowHandle Optional handle to a window for DPI awareness. If NULL, uses system DPI.\n * \\param WindowDpi The DPI of the target window for scaling calculations.\n * \\return A handle to the created font object, or NULL if the operation fails.\n */\nHFONT PhCreateCommonFont(\n    _In_ LONG Size,\n    _In_ LONG Weight,\n    _In_opt_ HWND WindowHandle,\n    _In_ LONG WindowDpi\n    )\n{\n    HFONT fontHandle;\n    LOGFONT logFont;\n\n    if (!PhGetSystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, WindowDpi))\n        return NULL;\n\n    fontHandle = CreateFont(\n        -PhMultiplyDivideSigned(Size, WindowDpi, 72),\n        0,\n        0,\n        0,\n        Weight,\n        FALSE,\n        FALSE,\n        FALSE,\n        ANSI_CHARSET,\n        OUT_DEFAULT_PRECIS,\n        CLIP_DEFAULT_PRECIS,\n        PhFontQuality,\n        DEFAULT_PITCH,\n        logFont.lfFaceName\n        );\n\n    if (!fontHandle)\n        return NULL;\n\n    if (WindowHandle)\n    {\n        SetWindowFont(WindowHandle, fontHandle, TRUE);\n    }\n\n    return fontHandle;\n}\n\nHFONT PhCreateIconTitleFont(\n    _In_opt_ LONG WindowDpi\n    )\n{\n    LOGFONT logFont;\n\n    if (PhGetSystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, WindowDpi))\n    {\n        logFont.lfQuality = (UCHAR)PhFontQuality;\n        return CreateFontIndirect(&logFont);\n    }\n\n    return NULL;\n}\n\nHFONT PhCreateMessageFont(\n    _In_opt_ LONG WindowDpi\n    )\n{\n    NONCLIENTMETRICS metrics = { sizeof(metrics) };\n\n    if (PhGetSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, WindowDpi))\n    {\n        metrics.lfMessageFont.lfQuality = (UCHAR)PhFontQuality;\n        return CreateFontIndirect(&metrics.lfMessageFont);\n    }\n\n    return NULL;\n}\n\nHFONT PhDuplicateFont(\n    _In_ HFONT Font\n    )\n{\n    LOGFONT logFont;\n\n    if (GetObject(Font, sizeof(LOGFONT), &logFont))\n    {\n        logFont.lfQuality = (UCHAR)PhFontQuality;\n        return CreateFontIndirect(&logFont);\n    }\n\n    return NULL;\n}\n\nHFONT PhDuplicateFontWithNewWeight(\n    _In_ HFONT Font,\n    _In_ LONG NewWeight\n    )\n{\n    LOGFONT logFont;\n\n    if (GetObject(Font, sizeof(LOGFONT), &logFont))\n    {\n        logFont.lfWeight = NewWeight;\n        logFont.lfQuality = (UCHAR)PhFontQuality;\n        return CreateFontIndirect(&logFont);\n    }\n\n    return NULL;\n}\n\nHFONT PhDuplicateFontWithNewHeight(\n    _In_ HFONT Font,\n    _In_ LONG NewHeight,\n    _In_ LONG dpiValue\n    )\n{\n    LOGFONT logFont;\n\n    if (GetObject(Font, sizeof(LOGFONT), &logFont))\n    {\n        logFont.lfHeight = PhGetDpi(NewHeight, dpiValue);\n        logFont.lfQuality = (UCHAR)PhFontQuality;\n        return CreateFontIndirect(&logFont);\n    }\n\n    return NULL;\n}\n\n\nHFONT PhInitializeFont(\n    _In_ LONG WindowDpi\n    )\n{\n    HFONT fontHandle;\n\n    if (fontHandle = PhCreateFont(L\"Microsoft Sans Serif\", 8, FW_NORMAL, DEFAULT_PITCH, WindowDpi))\n        return fontHandle;\n    if (fontHandle = PhCreateFont(L\"Tahoma\", 8, FW_NORMAL, DEFAULT_PITCH, WindowDpi))\n        return fontHandle;\n    if (fontHandle = PhCreateMessageFont(WindowDpi))\n        return fontHandle;\n\n    return GetStockFont(DEFAULT_GUI_FONT);\n}\n\nHFONT PhInitializeMonospaceFont(\n    _In_ LONG WindowDpi\n    )\n{\n    HFONT fontHandle;\n\n    if (fontHandle = PhCreateFont(L\"Lucida Console\", 9, FW_DONTCARE, FF_MODERN, WindowDpi))\n        return fontHandle;\n    if (fontHandle = PhCreateFont(L\"Courier New\", 9, FW_DONTCARE, FF_MODERN, WindowDpi))\n        return fontHandle;\n    if (fontHandle = PhCreateFont(NULL, 9, FW_DONTCARE, FF_MODERN, WindowDpi))\n        return fontHandle;\n\n    //{\n    //    NONCLIENTMETRICS metrics;\n    //\n    //    memset(&metrics, 0, sizeof(NONCLIENTMETRICS));\n    //    metrics.cbSize = sizeof(NONCLIENTMETRICS);\n    //\n    //    if (PhGetSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, WindowDpi))\n    //    {\n    //        return CreateFontIndirect(&metrics.lfMessageFont);\n    //    }\n    //}\n\n    LOGFONT logFont;\n\n    fontHandle = GetStockFont(SYSTEM_FIXED_FONT);\n\n    if (GetObject(fontHandle, sizeof(LOGFONT), &logFont))\n    {\n        logFont.lfWeight = -(LONG)PhMultiplyDivide(logFont.lfWeight, WindowDpi, 72);\n        return CreateFontIndirect(&logFont);\n    }\n\n    return fontHandle;\n}\n\n/**\n * The PhGetDC function retrieves a handle to a device context (DC).\n * \\return The handle to the requested stock object.\n */\nHDC PhGetDC(\n    _In_opt_ HWND WindowHandle\n    )\n{\n    return GetDC(WindowHandle);\n}\n\n/**\n * Releases a device context previously obtained via PhGetDC.\n *\n * \\param WindowHandle The window handle associated with the DC; may be NULL to indicate the desktop.\n * \\param Hdc The HDC to release. After this call the handle is no longer valid for the caller.\n */\nVOID PhReleaseDC(\n    _In_opt_ HWND WindowHandle,\n    _In_ _Frees_ptr_ HDC Hdc\n    )\n{\n    ReleaseDC(WindowHandle, Hdc);\n}\n\n/**\n * The PhGetStockBrush function retrieves a handle to one of the stock pens, brushes, fonts, or palettes.\n *\n * \\param Index The type of stock object.\n * \\return The handle to the requested stock object.\n */\nHGDIOBJ PhGetStockObject(\n    _In_ LONG Index\n    )\n{\n    return GetStockObject(Index);\n}\n\n/**\n * Opens the theme data for the specified window handle, class list, and window DPI.\n *\n * \\param WindowHandle The handle to the window for which to open the theme data. Can be NULL.\n * \\param ClassList The class list of the theme to open.\n * \\param WindowDpi The DPI of the window.\n * \\return The handle to the opened theme data, or NULL if the theme data could not be opened.\n */\nHTHEME PhOpenThemeData(\n    _In_opt_ HWND WindowHandle,\n    _In_ PCWSTR ClassList,\n    _In_ LONG WindowDpi\n    )\n{\n    if (OpenThemeDataForDpi_I && WindowDpi)\n    {\n        return OpenThemeDataForDpi_I(WindowHandle, ClassList, WindowDpi);\n    }\n\n    if (OpenThemeData_I)\n    {\n        return OpenThemeData_I(WindowHandle, ClassList);\n    }\n\n    return NULL;\n}\n\n/**\n * Closes theme data opened with PhOpenThemeData.\n *\n * \\param ThemeHandle Theme handle previously returned by PhOpenThemeData.\n */\nVOID PhCloseThemeData(\n    _In_ HTHEME ThemeHandle\n    )\n{\n    if (CloseThemeData_I)\n    {\n        CloseThemeData_I(ThemeHandle);\n    }\n}\n\n/**\n * Applies a theme class to a control (wrapper around SetWindowTheme).\n *\n * \\param Handle Handle to the control window.\n * \\param Theme Optional class list string to apply, or NULL to remove theme.\n */\nVOID PhSetControlTheme(\n    _In_ HWND Handle,\n    _In_opt_ PCWSTR Theme\n    )\n{\n    if (SetWindowTheme_I)\n    {\n        SetWindowTheme_I(Handle, Theme, NULL);\n    }\n}\n\n/**\n * Queries whether visual themes are active on the system.\n *\n * \\return TRUE if themes are active, otherwise FALSE.\n */\nBOOLEAN PhIsThemeActive(\n    VOID\n    )\n{\n    if (!IsThemeActive_I)\n        return FALSE;\n\n    return !!IsThemeActive_I();\n}\n\nBOOLEAN PhIsAppThemed(\n    VOID\n    )\n{\n    if (!IsAppThemed_I)\n        return FALSE;\n\n    return !!IsAppThemed_I();\n}\n\n/**\n * Determines whether a theme part/state is defined for the given theme data.\n *\n * \\param ThemeHandle Theme handle returned by PhOpenThemeData.\n * \\param PartId Part identifier.\n * \\param StateId State identifier.\n * \\return TRUE if the part/state is defined, otherwise FALSE.\n */\nBOOLEAN PhIsThemePartDefined(\n    _In_ HTHEME ThemeHandle,\n    _In_ LONG PartId,\n    _In_ LONG StateId\n    )\n{\n    if (!IsThemePartDefined_I)\n        return FALSE;\n\n    return !!IsThemePartDefined_I(ThemeHandle, PartId, StateId);\n}\n\n/**\n * Retrieves the class name associated with theme data.\n *\n * \\param ThemeHandle Theme handle.\n * \\param Class Buffer that receives the class name (null-terminated).\n * \\param ClassLength Length of the Class buffer in characters.\n * \\return TRUE on success, FALSE on failure or if API not present.\n */\n_Success_(return)\nBOOLEAN PhGetThemeClass(\n    _In_ HTHEME ThemeHandle,\n    _Out_writes_z_(ClassLength) PWSTR Class,\n    _In_ ULONG ClassLength\n    )\n{\n    if (!GetThemeClass_I)\n        return FALSE;\n\n    return SUCCEEDED(GetThemeClass_I(ThemeHandle, Class, ClassLength));\n}\n\n/**\n * Retrieves a color value from theme data.\n *\n * \\param ThemeHandle Theme handle.\n * \\param PartId Part identifier.\n * \\param StateId State identifier.\n * \\param PropId Property identifier to query.\n * \\param Color Receives the COLORREF value on success.\n * \\return TRUE on success, FALSE on failure or if API not present.\n */\n_Success_(return)\nBOOLEAN PhGetThemeColor(\n    _In_ HTHEME ThemeHandle,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_ LONG PropId,\n    _Out_ COLORREF* Color\n    )\n{\n    if (!GetThemeColor_I)\n        return FALSE;\n\n    return SUCCEEDED(GetThemeColor_I(ThemeHandle, PartId, StateId, PropId, Color));\n}\n\n/**\n * Retrieves an integer property from theme data.\n *\n * \\param ThemeHandle Theme handle.\n * \\param PartId Part identifier.\n * \\param StateId State identifier.\n * \\param PropId Property identifier to query.\n * \\param Value Receives the integer value on success.\n * \\return TRUE on success, FALSE on failure or if API not present.\n */\n_Success_(return)\nBOOLEAN PhGetThemeInt(\n    _In_ HTHEME ThemeHandle,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_ LONG PropId,\n    _Out_ PLONG Value\n    )\n{\n    if (!GetThemeInt_I)\n        return FALSE;\n\n    return SUCCEEDED(GetThemeInt_I(ThemeHandle, PartId, StateId, PropId, (PLONG)Value));\n}\n\n/**\n * Retrieves the size of a theme part.\n *\n * \\param ThemeHandle Theme handle.\n * \\param hdc Optional device context for size calculation.\n * \\param PartId Part identifier.\n * \\param StateId State identifier.\n * \\param Rect Optional bounding rect used by some parts.\n * \\param Flags THEMEPARTSIZE selector (min/actual/true).\n * \\param Size Receives the part size on success.\n * \\return TRUE on success, FALSE on failure or if API not present.\n */\n_Success_(return)\nBOOLEAN PhGetThemePartSize(\n    _In_ HTHEME ThemeHandle,\n    _In_opt_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_opt_ LPCRECT Rect,\n    _In_ THEMEPARTSIZE Flags,\n    _Out_ PSIZE Size\n    )\n{\n    if (!GetThemePartSize_I)\n        return FALSE;\n\n    return SUCCEEDED(GetThemePartSize_I(ThemeHandle, hdc, PartId, StateId, Rect, (enum THEMESIZE)Flags, Size));\n}\n\n/**\n * Retrieves theme margins for a part/property.\n *\n * \\param ThemeHandle Theme handle.\n * \\param hdc Optional device context.\n * \\param PartId Part identifier.\n * \\param StateId State identifier.\n * \\param PropId Margin property identifier.\n * \\param Rect Optional bounding rect used by some margin queries.\n * \\param Margins Receives the THEMEMARGINS on success.\n * \\return TRUE on success, FALSE on failure or if API not present.\n */\n_Success_(return)\nBOOLEAN PhGetThemeMargins(\n    _In_ HTHEME ThemeHandle,\n    _In_opt_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_ LONG PropId,\n    _In_opt_ LPCRECT Rect,\n    _Out_ PTHEMEMARGINS Margins\n    )\n{\n    if (!GetThemeMargins_I)\n        return FALSE;\n\n    return SUCCEEDED(GetThemeMargins_I(ThemeHandle, hdc, PartId, StateId, PropId, Rect, (PMARGINS)Margins));\n}\n\n/**\n * Draws a themed background for a part/state into the specified DC.\n *\n * \\param ThemeHandle Theme handle.\n * \\param hdc Destination device context.\n * \\param PartId Part identifier.\n * \\param StateId State identifier.\n * \\param Rect Destination rectangle.\n * \\param ClipRect Optional clip rectangle.\n * \\return TRUE on success, FALSE on failure or if API not present.\n */\nBOOLEAN PhDrawThemeBackground(\n    _In_ HTHEME ThemeHandle,\n    _In_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_ LPCRECT Rect,\n    _In_opt_ LPCRECT ClipRect\n    )\n{\n    if (!DrawThemeBackground_I)\n        return FALSE;\n\n    return SUCCEEDED(DrawThemeBackground_I(ThemeHandle, hdc, PartId, StateId, Rect, ClipRect));\n}\n\n/**\n * Draws themed text for a part/state.\n *\n * \\param ThemeHandle Theme handle.\n * \\param hdc Destination device context.\n * \\param PartId Part identifier.\n * \\param StateId State identifier.\n * \\param Text Pointer to the text buffer.\n * \\param cchText Number of characters in Text.\n * \\param TextFlags Text drawing flags for DrawThemeText.\n * \\param Rect Destination rectangle.\n * \\return TRUE on success, FALSE on failure or if API not present.\n */\nBOOLEAN PhDrawThemeText(\n    _In_ HTHEME ThemeHandle,\n    _In_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_reads_(cchText) PCWSTR Text,\n    _In_ LONG cchText,\n    _In_ ULONG TextFlags,\n    _In_ LPCRECT Rect\n    )\n{\n    static typeof(&DrawThemeText) DrawThemeText_I = NULL;\n\n    if (!DrawThemeText_I)\n        DrawThemeText_I = PhGetModuleProcAddress(L\"uxtheme.dll\", \"DrawThemeText\");\n\n    if (!DrawThemeText_I)\n        return FALSE;\n\n    return HR_SUCCESS(DrawThemeText_I(ThemeHandle, hdc, PartId, StateId, Text, cchText, TextFlags, 0, Rect));\n}\n\n/**\n * Draws themed text for a part/state with extended options (DrawThemeTextEx).\n *\n * \\param ThemeHandle Theme handle.\n * \\param hdc Destination device context.\n * \\param PartId Part identifier.\n * \\param StateId State identifier.\n * \\param Text Pointer to the text buffer.\n * \\param cchText Number of characters in Text.\n * \\param TextFlags Text drawing flags.\n * \\param Rect In/out destination rectangle; may be modified by the call.\n * \\param Options Optional pointer to DTTOPTS structure.\n * \\return TRUE on success, FALSE on failure or if API not present.\n */\nBOOLEAN PhDrawThemeTextEx(\n    _In_ HTHEME ThemeHandle,\n    _In_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_reads_(cchText) PCWSTR Text,\n    _In_ LONG cchText,\n    _In_ ULONG TextFlags,\n    _Inout_ LPRECT Rect,\n    _In_opt_ const PVOID Options // DTTOPTS*\n    )\n{\n    static typeof(&DrawThemeTextEx) DrawThemeTextEx_I = NULL;\n\n    if (!DrawThemeTextEx_I)\n        DrawThemeTextEx_I = PhGetModuleProcAddress(L\"uxtheme.dll\", \"DrawThemeTextEx\");\n\n    if (!DrawThemeTextEx_I)\n        return FALSE;\n\n    return HR_SUCCESS(DrawThemeTextEx_I(ThemeHandle, hdc, PartId, StateId, Text, cchText, TextFlags, Rect, Options));\n}\n\n/**\n * Tests whether a theme background is partially transparent for a given part/state.\n *\n * \\param ThemeHandle Theme handle.\n * \\param PartId Part identifier.\n * \\param StateId State identifier.\n * \\return TRUE if the theme background is partially transparent, otherwise FALSE.\n */\nBOOLEAN PhIsThemeBackgroundPartiallyTransparent(\n    _In_ HTHEME ThemeHandle,\n    _In_ LONG PartId,\n    _In_ LONG StateId\n    )\n{\n    static typeof(&IsThemeBackgroundPartiallyTransparent) IsThemeBackgroundPartiallyTransparent_I = NULL;\n\n    if (!IsThemeBackgroundPartiallyTransparent_I)\n        IsThemeBackgroundPartiallyTransparent_I = PhGetModuleProcAddress(L\"uxtheme.dll\", \"IsThemeBackgroundPartiallyTransparent\");\n\n    if (!IsThemeBackgroundPartiallyTransparent_I)\n        return FALSE;\n\n    return !!IsThemeBackgroundPartiallyTransparent_I(ThemeHandle, PartId, StateId);\n}\n\n/**\n * Draws the parent background for a window using theme APIs.\n *\n * \\param WindowHandle Window handle whose parent background will be drawn.\n * \\param Hdc Destination device context.\n * \\param Rect Optional rectangle within the window to draw.\n * \\return TRUE on success, FALSE on failure or if API not present.\n */\nBOOLEAN PhDrawThemeParentBackground(\n    _In_ HWND WindowHandle,\n    _In_ HDC Hdc,\n    _In_opt_ const PRECT Rect\n    )\n{\n    static typeof(&DrawThemeParentBackground) DrawThemeParentBackground_I = NULL;\n\n    if (!DrawThemeParentBackground_I)\n        DrawThemeParentBackground_I = PhGetModuleProcAddress(L\"uxtheme.dll\", \"DrawThemeParentBackground\");\n\n    if (!DrawThemeParentBackground_I)\n        return FALSE;\n\n    return HR_SUCCESS(DrawThemeParentBackground_I(WindowHandle, Hdc, Rect));\n}\n\n/**\n * Enables or disables dark mode for a window (when supported).\n *\n * \\param WindowHandle Handle of the window.\n * \\param Enabled TRUE to enable dark mode, FALSE to disable.\n * \\return TRUE on success, FALSE if API not present or call failed.\n */\nBOOLEAN PhAllowDarkModeForWindow(\n    _In_ HWND WindowHandle,\n    _In_ BOOL Enabled\n    )\n{\n    if (!AllowDarkModeForWindow_I)\n        return FALSE;\n\n    return !!AllowDarkModeForWindow_I(WindowHandle, Enabled);\n}\n\n/**\n * Queries whether dark mode is allowed for a given window.\n *\n * \\param WindowHandle Handle of the window to test.\n * \\return TRUE if dark mode is allowed, otherwise FALSE.\n */\nBOOLEAN PhIsDarkModeAllowedForWindow(\n    _In_ HWND WindowHandle\n    )\n{\n    if (!IsDarkModeAllowedForWindow_I)\n        return FALSE;\n\n    return !!IsDarkModeAllowedForWindow_I(WindowHandle);\n}\n\n// rev from EtwRundown.dll!EtwpLogDPISettingsInfo (dmex)\n//LONG PhGetUserOrMachineDpi(\n//    VOID\n//    )\n//{\n//    static PH_STRINGREF machineKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Hardware Profiles\\\\Current\\\\Software\\\\Fonts\");\n//    static PH_STRINGREF userKeyName = PH_STRINGREF_INIT(L\"Control Panel\\\\Desktop\");\n//    HANDLE keyHandle;\n//    LONG dpi = 0;\n//\n//    if (NT_SUCCESS(PhOpenKey(&keyHandle, KEY_QUERY_VALUE, PH_KEY_USERS, &userKeyName, 0)))\n//    {\n//        dpi = PhQueryRegistryUlongZ(keyHandle, L\"LogPixels\");\n//        NtClose(keyHandle);\n//    }\n//\n//    if (dpi == 0)\n//    {\n//        if (NT_SUCCESS(PhOpenKey(&keyHandle, KEY_QUERY_VALUE, PH_KEY_LOCAL_MACHINE, &machineKeyName, 0)))\n//        {\n//            dpi = PhQueryRegistryUlongZ(keyHandle, L\"LogPixels\");\n//            NtClose(keyHandle);\n//        }\n//    }\n//\n//    return dpi;\n//}\n\n/**\n * Retrieves the client rectangle adjusted for scroll range/position.\n *\n * \\param WindowHandle The window whose client rectangle is queried.\n * \\param ClientRect Receives the adjusted client rectangle.\n * \\return TRUE on success, FALSE on failure or empty client rect.\n */\nBOOLEAN PhGetClientRectOffsetScroll(\n    _In_ HWND WindowHandle,\n    _Out_ PRECT ClientRect\n    )\n{\n    LONG scrollRangeMax;\n    LONG scrollRangeMin;\n    LONG scrollPosition;\n\n    if (!PhGetClientRect(WindowHandle, ClientRect))\n        return FALSE;\n\n    if (!(ClientRect->right && ClientRect->bottom))\n        return FALSE;\n\n    ULONG windowStyle = PhGetWindowStyle(WindowHandle);\n\n    if (FlagOn(windowStyle, WS_HSCROLL))\n    {\n        if (GetScrollRange(WindowHandle, SB_HORZ, &scrollRangeMin, &scrollRangeMax))\n        {\n            scrollPosition = GetScrollPos(WindowHandle, SB_HORZ);\n            ClientRect->right = ClientRect->left + scrollRangeMax;\n            PhOffsetRect(ClientRect, -scrollPosition, 0);\n        }\n    }\n\n    if (FlagOn(windowStyle, WS_VSCROLL))\n    {\n        if (GetScrollRange(WindowHandle, SB_VERT, &scrollRangeMin, &scrollRangeMax))\n        {\n            scrollPosition = GetScrollPos(WindowHandle, SB_VERT);\n            ClientRect->bottom = ClientRect->top + scrollRangeMax;\n            PhOffsetRect(ClientRect, 0, -scrollPosition);\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Determines whether a window belongs to a hung (non-responsive) application.\n *\n * \\param WindowHandle Handle to the window to test. May be NULL (result will be FALSE).\n * \\return TRUE if the system reports the window is hung (not responding), otherwise FALSE.\n */\nBOOLEAN PhIsHungAppWindow(\n    _In_ HWND WindowHandle\n    )\n{\n    return !!IsHungAppWindow(WindowHandle);\n}\n\n/**\n * Returns the shell (desktop) window handle.\n *\n * \\return HWND of the shell window (may be NULL).\n */\nHWND PhGetShellWindow(\n    VOID\n    )\n{\n    return GetShellWindow();\n}\n\n/**\n * Marks a child window so it doesn't activate when created.\n *\n * \\param WindowHandle Child window handle.\n * \\param ThreadId Currently ignored; retained for compatibility.\n * \\return TRUE on success, FALSE if API not present or call fails.\n */\nBOOLEAN PhSetChildWindowNoActivate(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ThreadId\n    )\n{\n    typedef ULONG (WINAPI* SetChildWindowNoActivate)(\n        _In_ HWND WindowHandle\n        );\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(SetChildWindowNoActivate) SetChildWindowNoActivate_I = NULL; // NtUserSetChildWindowNoActivate\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"user32.dll\"))\n        {\n            SetChildWindowNoActivate_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 2005);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!SetChildWindowNoActivate_I)\n        return FALSE;\n\n    return !!SetChildWindowNoActivate_I(WindowHandle);\n}\n\n/**\n * Checks whether the given window belongs to the specified thread's desktop.\n *\n * \\param WindowHandle The window to check.\n * \\param ThreadId Thread id owning the desktop to check.\n * \\return TRUE if the window belongs to the thread's desktop, otherwise FALSE.\n */\nBOOLEAN PhCheckWindowThreadDesktop(\n    _In_ HWND WindowHandle,\n    _In_ HANDLE ThreadId\n    )\n{\n    typedef LOGICAL (WINAPI* CheckWindowThreadDesktop)(\n        _In_ HWND WindowHandle,\n        _In_ ULONG ThreadId\n        );\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static CheckWindowThreadDesktop CheckWindowThreadDesktop_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"user32.dll\"))\n        {\n            CheckWindowThreadDesktop_I = PhGetDllBaseProcedureAddress(baseAddress, \"CheckWindowThreadDesktop\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!CheckWindowThreadDesktop_I)\n        return FALSE;\n\n    return !!CheckWindowThreadDesktop_I(WindowHandle, HandleToUlong(ThreadId));\n}\n\n/**\n * Gets an effective DPI for a monitor/window rectangle.\n *\n * \\param WindowHandle Optional window handle used to locate a monitor.\n * \\param WindowRect Optional rectangle used to locate a monitor.\n * \\return DPI (horizontal) for the monitor or USER_DEFAULT_SCREEN_DPI on failure.\n */\nLONG PhGetMonitorDpi(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PRECT WindowRect\n    )\n{\n    if (WindowRect && GetDpiForMonitor_I)\n    {\n        LONG dpi_x, dpi_y;\n        HMONITOR monitor;\n\n        monitor = MonitorFromRect(WindowRect, MONITOR_DEFAULTTONEAREST);\n\n        if (HR_SUCCESS(GetDpiForMonitor_I(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y)))\n            return dpi_x;\n    }\n    else if (WindowHandle && GetDpiForMonitor_I)\n    {\n        LONG dpi_x, dpi_y;\n        HMONITOR monitor;\n\n        monitor = MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTONEAREST);\n\n        if (HR_SUCCESS(GetDpiForMonitor_I(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y)))\n            return dpi_x;\n    }\n\n    return USER_DEFAULT_SCREEN_DPI;\n}\n\n/**\n * Attempts to discover the system DPI using a sequence of fallbacks.\n *\n * \\return Effective system DPI (pixels per inch) or USER_DEFAULT_SCREEN_DPI on failure.\n */\nLONG PhGetSystemDpi(\n    VOID\n    )\n{\n    LONG dpi;\n\n    if (dpi = PhGetTaskbarDpi())\n        return dpi;\n\n    if (dpi = PhGetDpiValue(NULL, NULL))\n        return dpi;\n\n    return USER_DEFAULT_SCREEN_DPI;\n}\n\n// rev from GetDpiForShellUIComponent (dmex)\n//LONG PhGetShellDpi(\n//    VOID\n//    )\n//{\n//    static HWND trayWindow = NULL;\n//    HWND windowHandle;\n//    LONG dpi = 0;\n//\n//    if (IsWindow(trayWindow))\n//    {\n//        windowHandle = trayWindow;\n//    }\n//    else\n//    {\n//        windowHandle = trayWindow = FindWindow(L\"Shell_TrayWnd\", NULL);\n//    }\n//\n//    if (windowHandle)\n//    {\n//        dpi = HandleToLong(GetProp(windowHandle, L\"TaskbarDPI_NotificationArea\"));\n//    }\n//\n//    //if (dpi == 0)\n//    //{\n//    //    dpi = GetDpiForShellUIComponent(SHELL_UI_COMPONENT_NOTIFICATIONAREA);\n//    //}\n//\n//    if (dpi == 0)\n//    {\n//        dpi = USER_DEFAULT_SCREEN_DPI;\n//    }\n//\n//    return dpi;\n//}\n\n/**\n * Retrieves an effective DPI for the taskbar area (used as a reasonable\n * approximation for shell UI DPI). The function attempts several fallbacks\n * shell window bounds -> monitor DPI, then DpiValue from other sources,\n * and finally USER_DEFAULT_SCREEN_DPI.\n *\n * \\return Effective taskbar DPI (pixels per inch) or USER_DEFAULT_SCREEN_DPI on failure.\n */\nLONG PhGetTaskbarDpi(\n    VOID\n    )\n{\n    LONG dpi = 0;\n    HWND windowHandle;\n    RECT windowRect = { 0 };\n\n    if (windowHandle = PhGetShellWindow())\n    {\n        PhGetWindowRect(windowHandle, &windowRect);\n    }\n\n    if (PhRectEmpty(&windowRect))\n    {\n        if (windowHandle = GetDesktopWindow())\n        {\n            PhGetWindowRect(windowHandle, &windowRect);\n        }\n    }\n\n    //if (PhRectEmpty(&windowRect))\n    //{\n    //    APPBARDATA appbarData = { sizeof(APPBARDATA) };\n    //\n    //    if (SHAppBarMessage(ABM_GETTASKBARPOS, &appbarData))\n    //    {\n    //        windowRect = appbarData.rc;\n    //    }\n    //}\n\n    if (!PhRectEmpty(&windowRect))\n    {\n        dpi = PhGetMonitorDpi(NULL, &windowRect);\n    }\n\n    if (dpi == 0)\n    {\n        dpi = PhGetDpiValue(NULL, NULL);\n    }\n\n    //if (dpi == 0)\n    //{\n    //    dpi = PhGetShellDpi();\n    //}\n\n    if (dpi == 0)\n    {\n        dpi = USER_DEFAULT_SCREEN_DPI;\n    }\n\n    return dpi;\n}\n\n/**\n * Retrieves the DPI for the specified window.\n *\n * Uses multiple strategies depending on OS version:\n * - On Windows 10+: queries per-window/per-monitor values.\n * - On older systems: queries device context LOGPIXELSX.\n *\n * \\param WindowHandle Window handle to query DPI for.\n * \\return DPI (horizontal) for the window or USER_DEFAULT_SCREEN_DPI on failure.\n */\nLONG PhGetWindowDpi(\n    _In_ HWND WindowHandle\n    )\n{\n    if (WindowsVersion >= WINDOWS_10)\n    {\n        LONG dpi;\n        RECT windowRect;\n\n        if (dpi = PhGetDpiValue(WindowHandle, NULL))\n            return dpi;\n\n        if (PhGetWindowRect(WindowHandle, &windowRect))\n        {\n            if (dpi = PhGetDpiValue(NULL, &windowRect))\n                return dpi;\n        }\n    }\n    else // Windows 7 and Windows 8\n    {\n        LONG dpi;\n        HDC screenHdc;\n\n        if (screenHdc = PhGetDC(WindowHandle))\n        {\n            dpi = GetDeviceCaps(screenHdc, LOGPIXELSX);\n            PhReleaseDC(WindowHandle, screenHdc);\n            return dpi;\n        }\n    }\n\n    return USER_DEFAULT_SCREEN_DPI;\n}\n\n/**\n * Attempts to determine DPI using modern APIs and fallbacks.\n *\n * \\param WindowHandle Optional window handle to query.\n * \\param WindowRect Optional rectangle used to locate a monitor.\n * \\return Determined DPI or USER_DEFAULT_SCREEN_DPI on failure.\n */\nLONG PhGetDpiValue(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PRECT WindowRect\n    )\n{\n    LONG dpi;\n\n    // Windows 10 (RS1)\n    if (WindowHandle && GetDpiForWindow_I)\n    {\n        if (dpi = GetDpiForWindow_I(WindowHandle))\n            return dpi;\n    }\n\n    // Windows 8.1\n    if (WindowRect && GetDpiForMonitor_I)\n    {\n        if (dpi = PhGetMonitorDpi(NULL, WindowRect))\n            return dpi;\n    }\n\n    if (WindowHandle && GetDpiForMonitor_I)\n    {\n        if (dpi = PhGetMonitorDpi(WindowHandle, NULL))\n            return dpi;\n    }\n\n    // Windows 10 (RS1)\n    {\n        if (GetDpiForSystem_I)\n        {\n            return GetDpiForSystem_I();\n        }\n    }\n\n    // Windows 7 and Windows 8\n    {\n        HDC screenHdc;\n\n        if (screenHdc = PhGetDC(NULL))\n        {\n            dpi = GetDeviceCaps(screenHdc, LOGPIXELSX);\n            PhReleaseDC(NULL, screenHdc);\n            if (dpi) { return dpi; }\n        }\n    }\n\n    return USER_DEFAULT_SCREEN_DPI;\n}\n\n/**\n * Retrieves the system metrics for the specified index.\n *\n * \\param Index The index of the system metric to retrieve.\n * \\param DpiValue The DPI value to use for retrieving the system metric. If not provided, the default DPI value will be used.\n * \\return The value of the system metric.\n */\nLONG PhGetSystemMetrics(\n    _In_ LONG Index,\n    _In_opt_ LONG DpiValue\n    )\n{\n    if (DpiValue > 0 && GetSystemMetricsForDpi_I)\n    {\n        return GetSystemMetricsForDpi_I(Index, DpiValue);\n    }\n\n    return GetSystemMetrics(Index);\n}\n\n/**\n * Queries whether the system is running in Safe Boot (clean boot) mode.\n *\n * \\return TRUE if the system is in Safe Boot mode, otherwise FALSE.\n */\nBOOLEAN PhGetSystemSafeBootMode(\n    VOID\n    )\n{\n    if (WindowsVersion < WINDOWS_NEW)\n    {\n        return !!USER_SHARED_DATA->SafeBootMode;\n    }\n\n    return !!PhGetSystemMetrics(SM_CLEANBOOT, 0);\n}\n\n/**\n * Wrapper for SystemParametersInfo that supports a DPI-aware variant when available.\n *\n * \\param Action The SPI_* action to perform.\n * \\param Param1 Additional parameter for the action (see SystemParametersInfo docs).\n * \\param Param2 Pointer to or buffer for action-specific data.\n * \\param DpiValue Optional DPI to pass to SystemParametersInfoForDpi when supported (>0).\n * \\return BOOL nonzero on success, zero on failure.\n */\nBOOL PhGetSystemParametersInfo(\n    _In_ LONG Action,\n    _In_ ULONG Param1,\n    _Pre_maybenull_ _Post_valid_ PVOID Param2,\n    _In_opt_ LONG DpiValue\n    )\n{\n    if (DpiValue > 0 && SystemParametersInfoForDpi_I)\n    {\n        return SystemParametersInfoForDpi_I(Action, Param1, Param2, 0, DpiValue);\n    }\n\n    return SystemParametersInfo(Action, Param1, Param2, 0);\n}\n\n/**\n * Inserts a tab into a tab control at the specified index with given text.\n *\n * \\param TabControlHandle Handle to the tab control.\n * \\param Index Zero-based index to insert the new tab at.\n * \\param Text Text label for the new tab.\n * \\return Index of the inserted item on success, or an error value on failure.\n */\nLONG PhAddTabControlTab(\n    _In_ HWND TabControlHandle,\n    _In_ LONG Index,\n    _In_ PCWSTR Text\n    )\n{\n    TCITEM item;\n\n    item.mask = TCIF_TEXT;\n    item.pszText = (PWSTR)Text;\n\n    return TabCtrl_InsertItem(TabControlHandle, Index, &item);\n}\n\n/**\n * Retrieves the window text as a referenced PPH_STRING object.\n *\n * This is a convenience wrapper around PhGetWindowTextEx that requests\n * the default behavior (no special flags).\n *\n * \\param WindowHandle Window handle whose text is requested.\n * \\return A reference to a PPH_STRING. Caller should PhDereferenceObject when done.\n */\nPPH_STRING PhGetWindowText(\n    _In_ HWND WindowHandle\n    )\n{\n    PPH_STRING text;\n\n    PhGetWindowTextEx(WindowHandle, 0, &text);\n    return text;\n}\n\n/**\n * Retrieves window text with extended options.\n *\n * If PH_GET_WINDOW_TEXT_INTERNAL is specified the function uses InternalGetWindowText.\n * If PH_GET_WINDOW_TEXT_LENGTH_ONLY is specified only the length is retrieved.\n *\n * \\param WindowHandle Window handle to query.\n * \\param Flags Combination of PH_GET_WINDOW_TEXT_* flags that control behavior.\n * \\param Text Optional out parameter that receives a referenced PPH_STRING when provided.\n * \\return Number of characters in the retrieved text (not including terminating NULL).\n */\nULONG PhGetWindowTextEx(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags,\n    _Out_opt_ PPH_STRING *Text\n    )\n{\n    PPH_STRING string;\n    ULONG length;\n\n    if (Flags & PH_GET_WINDOW_TEXT_INTERNAL)\n    {\n        if (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY)\n        {\n            WCHAR buffer[32];\n            length = InternalGetWindowText(WindowHandle, buffer, sizeof(buffer) / sizeof(WCHAR));\n            if (Text) *Text = NULL;\n        }\n        else\n        {\n            // TODO: Resize the buffer until we get the entire thing.\n            string = PhCreateStringEx(NULL, 256 * sizeof(WCHAR));\n            length = InternalGetWindowText(WindowHandle, string->Buffer, (ULONG)string->Length / sizeof(WCHAR) + 1);\n            string->Length = length * sizeof(WCHAR);\n\n            if (Text)\n                *Text = string;\n            else\n                PhDereferenceObject(string);\n        }\n\n        return length;\n    }\n    else\n    {\n        length = GetWindowTextLength(WindowHandle);\n\n        if (length == 0 || (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY))\n        {\n            if (Text)\n                *Text = PhReferenceEmptyString();\n\n            return length;\n        }\n\n        string = PhCreateStringEx(NULL, length * sizeof(WCHAR));\n\n        if (GetWindowText(WindowHandle, string->Buffer, (ULONG)string->Length / sizeof(WCHAR) + 1))\n        {\n            if (Text)\n                *Text = string;\n            else\n                PhDereferenceObject(string);\n\n            return length;\n        }\n        else\n        {\n            if (Text)\n                *Text = PhReferenceEmptyString();\n\n            PhDereferenceObject(string);\n\n            return 0;\n        }\n    }\n}\n\n/**\n * Retrieves window text into a caller-supplied buffer.\n *\n * \\param WindowHandle Window handle to query.\n * \\param Flags PH_GET_WINDOW_TEXT_INTERNAL to use internal API; otherwise uses GetWindowText.\n * \\param Buffer Buffer that receives the text (may be NULL if BufferLength is 0).\n * \\param BufferLength Size of Buffer in characters.\n * \\param ReturnLength Optional receives the number of characters written (not including NULL).\n * \\return STATUS_SUCCESS on success or an appropriate NTSTATUS error code.\n */\nNTSTATUS PhGetWindowTextToBuffer(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_opt_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    ULONG length;\n\n    if (Flags & PH_GET_WINDOW_TEXT_INTERNAL)\n        length = InternalGetWindowText(WindowHandle, Buffer, BufferLength);\n    else\n        length = GetWindowText(WindowHandle, Buffer, BufferLength);\n\n    if (length == 0)\n        status = PhGetLastWin32ErrorAsNtStatus();\n    else\n        status = STATUS_SUCCESS;\n\n    if (ReturnLength)\n        *ReturnLength = length;\n\n    return status;\n}\n\n/**\n * Retrieves the class name of a window.\n *\n * \\param WindowHandle Window handle to query.\n * \\param Buffer Buffer that receives the class name (wide string).\n * \\param BufferLength Length of Buffer in characters.\n * \\param ReturnLength Optional receives the number of characters written (not including NULL).\n * \\return STATUS_SUCCESS on success or an NTSTATUS error on failure.\n */\nNTSTATUS PhGetClassName(\n    _In_ HWND WindowHandle,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    LONG length;\n\n    length = GetClassName(WindowHandle, Buffer, BufferLength);\n\n    if (length == 0)\n        status = PhGetLastWin32ErrorAsNtStatus();\n    else\n        status = STATUS_SUCCESS;\n\n    if (ReturnLength)\n        *ReturnLength = length;\n\n    return status;\n}\n\n/**\n * Retrieves the string for a combobox item.\n *\n * \\param WindowHandle Handle of the combobox control.\n * \\param Index Zero-based item index or INT_ERROR to use current selection.\n * \\return A referenced PPH_STRING on success, PhReferenceEmptyString() for empty string, or NULL on error.\n * \\remarks If Index is INT_ERROR the current selection is used.\n */\nPPH_STRING PhGetComboBoxString(\n    _In_ HWND WindowHandle,\n    _In_ LONG Index\n    )\n{\n    PPH_STRING string;\n    LONG length;\n\n    if (Index == INT_ERROR)\n    {\n        Index = ComboBox_GetCurSel(WindowHandle);\n\n        if (Index == CB_ERR)\n            return NULL;\n    }\n\n    length = ComboBox_GetLBTextLen(WindowHandle, Index);\n\n    if (length == CB_ERR)\n        return NULL;\n    if (length == 0)\n        return PhReferenceEmptyString();\n\n    string = PhCreateStringEx(NULL, length * sizeof(WCHAR));\n\n    if (ComboBox_GetLBText(WindowHandle, Index, string->Buffer) != CB_ERR)\n    {\n        return string;\n    }\n    else\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n}\n\n/**\n * Selects a string in a combobox.\n *\n * \\param WindowHandle Handle of the combobox control.\n * \\param String String to select.\n * \\param Partial If TRUE, selects the first item that matches partially; otherwise performs exact match.\n * \\return Index of the selected item, or CB_ERR if not found.\n */\nLONG PhSelectComboBoxString(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR String,\n    _In_ BOOLEAN Partial\n    )\n{\n    if (Partial)\n    {\n        return ComboBox_SelectString(WindowHandle, INT_ERROR, String);\n    }\n    else\n    {\n        LONG index;\n\n        index = ComboBox_FindStringExact(WindowHandle, INT_ERROR, String);\n\n        if (index == CB_ERR)\n            return CB_ERR;\n\n        ComboBox_SetCurSel(WindowHandle, index);\n\n        InvalidateRect(WindowHandle, NULL, TRUE);\n\n        return index;\n    }\n}\n\n/**\n * Deletes all strings from a combobox.\n *\n * \\param ComboBoxHandle Handle to the combobox control.\n * \\param ResetContent If TRUE, calls ComboBox_ResetContent after deleting individual strings.\n */\nVOID PhDeleteComboBoxStrings(\n    _In_ HWND ComboBoxHandle,\n    _In_ BOOLEAN ResetContent\n    )\n{\n    LONG total;\n\n    if ((total = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR)\n        return;\n\n    for (LONG i = 0; i < total; i++)\n    {\n        ComboBox_DeleteString(ComboBoxHandle, i);\n    }\n\n    if (ResetContent)\n    {\n        ComboBox_ResetContent(ComboBoxHandle);\n    }\n}\n\n/**\n * Retrieves the string for a listbox item.\n *\n * \\param WindowHandle Handle of the listbox control.\n * \\param Index Zero-based item index or INT_ERROR to use current selection.\n * \\return A newly created PPH_STRING on success, or NULL on error/empty. Caller must PhDereferenceObject when done.\n * \\remarks If Index is INT_ERROR the current selection is used.\n */\nPPH_STRING PhGetListBoxString(\n    _In_ HWND WindowHandle,\n    _In_ LONG Index\n    )\n{\n    PPH_STRING string;\n    LONG length;\n\n    if (Index == INT_ERROR)\n    {\n        Index = ListBox_GetCurSel(WindowHandle);\n\n        if (Index == LB_ERR)\n            return NULL;\n    }\n\n    length = ListBox_GetTextLen(WindowHandle, Index);\n\n    if (length == LB_ERR)\n        return NULL;\n    if (length == 0)\n        return NULL;\n\n    string = PhCreateStringEx(NULL, length * sizeof(WCHAR));\n\n    if (ListBox_GetText(WindowHandle, Index, string->Buffer) != LB_ERR)\n    {\n        return string;\n    }\n    else\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n}\n\n/**\n * Loads a bitmap resource and replaces the specified imagelist entry with it.\n *\n * \\param ImageList HIMAGELIST to update.\n * \\param Index Index of the image to replace.\n * \\param InstanceHandle Module instance handle containing the bitmap.\n * \\param BitmapName Resource name of the bitmap.\n */\nVOID PhSetImageListBitmap(\n    _In_ HIMAGELIST ImageList,\n    _In_ LONG Index,\n    _In_ HINSTANCE InstanceHandle,\n    _In_ PCWSTR BitmapName\n    )\n{\n    HBITMAP bitmap;\n\n    bitmap = LoadImage(InstanceHandle, BitmapName, IMAGE_BITMAP, 0, 0, 0);\n\n    if (bitmap)\n    {\n        PhImageListReplace(ImageList, Index, bitmap, NULL);\n        DeleteBitmap(bitmap);\n    }\n}\n\n/**\n * Hashtable equality function used for shared icon cache.\n *\n * Compares two icon cache entries by instance handle, dimensions, DPI and\n * resource/name. Handles both string and integer resource identifiers.\n *\n * \\param Entry1 Pointer to first PHP_ICON_ENTRY.\n * \\param Entry2 Pointer to second PHP_ICON_ENTRY.\n * \\return TRUE if entries represent the same icon lookup key, otherwise FALSE.\n */\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nstatic BOOLEAN SharedIconCacheHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPHP_ICON_ENTRY entry1 = Entry1;\n    PPHP_ICON_ENTRY entry2 = Entry2;\n\n    if (entry1->InstanceHandle != entry2->InstanceHandle ||\n        entry1->Width != entry2->Width ||\n        entry1->Height != entry2->Height ||\n        entry1->DpiValue != entry2->DpiValue)\n    {\n        return FALSE;\n    }\n\n    if (IS_INTRESOURCE(entry1->Name))\n    {\n        if (IS_INTRESOURCE(entry2->Name))\n            return PtrToUlong(entry1->Name) == PtrToUlong(entry2->Name);\n        else\n            return FALSE;\n    }\n    else\n    {\n        if (!IS_INTRESOURCE(entry2->Name))\n            return PhEqualStringZ(entry1->Name, entry2->Name, FALSE);\n        else\n            return FALSE;\n    }\n}\n\n/**\n * Hashtable hash function used for shared icon cache.\n *\n * Computes a hash for a PHP_ICON_ENTRY by mixing the name (or resource id),\n * instance handle, dimensions and DPI value.\n *\n * \\param Entry Pointer to PHP_ICON_ENTRY.\n * \\return Computed hash value.\n */\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nstatic ULONG SharedIconCacheHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPHP_ICON_ENTRY entry = Entry;\n    ULONG nameHash;\n\n    if (IS_INTRESOURCE(entry->Name))\n        nameHash = PtrToUlong(entry->Name);\n    else\n        nameHash = PhHashBytes((PUCHAR)entry->Name, PhCountStringZ(entry->Name));\n\n    return nameHash ^ (PtrToUlong(entry->InstanceHandle) >> 5) ^ (entry->Width << 3) ^ entry->Height ^ entry->DpiValue;\n}\n\n/**\n * Loads or returns a shared icon from cache.\n *\n * If PH_LOAD_ICON_SHARED is specified the function will attempt to return\n * a cached shared icon handle. If not found it will load, possibly scale,\n * and optionally insert the icon into the shared cache.\n *\n * \\param ImageBaseAddress Optional module base to load the icon from.\n * \\param Name The resource name or identifier.\n * \\param Flags Flags controlling loading behavior (size, shared, strict, ...).\n * \\param Width Desired width (or 0 to use defaults).\n * \\param Height Desired height (or 0 to use defaults).\n * \\param SystemDpi DPI value for scaling.\n * \\return Handle to an HICON on success, otherwise NULL.\n */\nHICON PhLoadIcon(\n    _In_opt_ PVOID ImageBaseAddress,\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ LONG Width,\n    _In_opt_ LONG Height,\n    _In_opt_ LONG SystemDpi\n    )\n{\n    PHP_ICON_ENTRY entry;\n    PPHP_ICON_ENTRY actualEntry;\n    HICON icon = NULL;\n    LONG width;\n    LONG height;\n\n    if (PhBeginInitOnce(&SharedIconCacheInitOnce))\n    {\n        SharedIconCacheHashtable = PhCreateHashtable(sizeof(PHP_ICON_ENTRY),\n            SharedIconCacheHashtableEqualFunction, SharedIconCacheHashtableHashFunction, 10);\n        PhEndInitOnce(&SharedIconCacheInitOnce);\n    }\n\n    if (Flags & PH_LOAD_ICON_SHARED)\n    {\n        PhAcquireQueuedLockExclusive(&SharedIconCacheLock);\n\n        entry.InstanceHandle = ImageBaseAddress;\n        entry.Name = Name;\n        entry.Width = PhpGetIconEntrySize(Width, Flags);\n        entry.Height = PhpGetIconEntrySize(Height, Flags);\n        entry.DpiValue = SystemDpi;\n        actualEntry = PhFindEntryHashtable(SharedIconCacheHashtable, &entry);\n\n        if (actualEntry)\n        {\n            icon = actualEntry->Icon;\n            PhReleaseQueuedLockExclusive(&SharedIconCacheLock);\n            return icon;\n        }\n    }\n\n    if (Flags & (PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_SIZE_LARGE))\n    {\n        if (Flags & PH_LOAD_ICON_SIZE_SMALL)\n        {\n            width = PhGetSystemMetrics(SM_CXSMICON, SystemDpi);\n            height = PhGetSystemMetrics(SM_CYSMICON, SystemDpi);\n        }\n        else\n        {\n            width = PhGetSystemMetrics(SM_CXICON, SystemDpi);\n            height = PhGetSystemMetrics(SM_CYICON, SystemDpi);\n        }\n\n        LoadIconWithScaleDown(ImageBaseAddress, Name, width, height, &icon);\n    }\n    else\n    {\n        LoadIconWithScaleDown(ImageBaseAddress, Name, Width, Height, &icon);\n    }\n\n    if (!icon && !(Flags & PH_LOAD_ICON_STRICT))\n    {\n        if (Flags & PH_LOAD_ICON_SIZE_SMALL)\n        {\n            width = PhGetSystemMetrics(SM_CXSMICON, SystemDpi);\n            height = PhGetSystemMetrics(SM_CYSMICON, SystemDpi);\n        }\n        else\n        {\n            width = PhGetSystemMetrics(SM_CXICON, SystemDpi);\n            height = PhGetSystemMetrics(SM_CYICON, SystemDpi);\n        }\n\n        icon = LoadImage(ImageBaseAddress, Name, IMAGE_ICON, width, height, 0);\n    }\n\n    if (Flags & PH_LOAD_ICON_SHARED)\n    {\n        if (icon)\n        {\n            if (!IS_INTRESOURCE(Name))\n                entry.Name = PhDuplicateStringZ(Name);\n            entry.Icon = icon;\n            PhAddEntryHashtable(SharedIconCacheHashtable, &entry);\n        }\n\n        PhReleaseQueuedLockExclusive(&SharedIconCacheLock);\n    }\n\n    return icon;\n}\n\n/**\n * Gets the default icon used for executable files.\n *\n * \\param SmallIcon A variable which receives the small default executable icon. Do not destroy the\n * icon using DestroyIcon(); it is shared between callers.\n * \\param LargeIcon A variable which receives the large default executable icon. Do not destroy the\n * icon using DestroyIcon(); it is shared between callers.\n */\nVOID PhGetStockApplicationIcon(\n    _Out_opt_ HICON *SmallIcon,\n    _Out_opt_ HICON *LargeIcon\n    )\n{\n    static HICON smallIcon = NULL;\n    static HICON largeIcon = NULL;\n    static LONG systemDpi = 0;\n\n    if (systemDpi != PhSystemDpi)\n    {\n        if (smallIcon)\n        {\n            DestroyIcon(smallIcon);\n            smallIcon = NULL;\n        }\n        if (largeIcon)\n        {\n            DestroyIcon(largeIcon);\n            largeIcon = NULL;\n        }\n\n        systemDpi = PhSystemDpi;\n    }\n\n    // This no longer uses SHGetFileInfo because it is *very* slow and causes many other DLLs to be\n    // loaded, increasing memory usage. The worst thing about it, however, is that it is horribly\n    // incompatible with multi-threading. The first time it is called, it tries to perform some\n    // one-time initialization. It guards this with a lock, but when multiple threads try to call\n    // the function at the same time, instead of waiting for initialization to finish it simply\n    // fails the other threads.\n\n    if (!smallIcon || !largeIcon)\n    {\n        if (WindowsVersion < WINDOWS_10)\n        {\n            PPH_STRING systemDirectory;\n            PPH_STRING dllFileName;\n\n            // imageres,11 (Windows 10 and above), user32,0 (Vista and above) or shell32,2 (XP) contains\n            // the default application icon.\n\n            if (systemDirectory = PhGetSystemDirectory())\n            {\n                dllFileName = PhConcatStringRefZ(&systemDirectory->sr, L\"\\\\user32.dll\");\n\n                PhExtractIcon(\n                    dllFileName->Buffer,\n                    &largeIcon,\n                    &smallIcon\n                    );\n\n                PhDereferenceObject(dllFileName);\n                PhDereferenceObject(systemDirectory);\n            }\n        }\n        else\n        {\n            static CONST PH_STRINGREF imageFileName = PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\imageres.dll\");\n\n            PhExtractIconEx(\n                &imageFileName,\n                TRUE,\n                11,\n                PhGetSystemMetrics(SM_CXICON, systemDpi),\n                PhGetSystemMetrics(SM_CYICON, systemDpi),\n                PhGetSystemMetrics(SM_CXSMICON, systemDpi),\n                PhGetSystemMetrics(SM_CYSMICON, systemDpi),\n                &largeIcon,\n                &smallIcon\n                );\n        }\n    }\n\n    if (!smallIcon)\n        smallIcon = PhLoadIcon(NULL, IDI_APPLICATION, PH_LOAD_ICON_SIZE_SMALL, 0, 0, systemDpi);\n    if (!largeIcon)\n        largeIcon = PhLoadIcon(NULL, IDI_APPLICATION, PH_LOAD_ICON_SIZE_LARGE, 0, 0, systemDpi);\n\n    if (SmallIcon)\n        *SmallIcon = smallIcon;\n    if (LargeIcon)\n        *LargeIcon = largeIcon;\n}\n\n//HICON PhGetFileShellIcon(\n//    _In_opt_ PWSTR FileName,\n//    _In_opt_ PWSTR DefaultExtension,\n//    _In_ BOOLEAN LargeIcon\n//    )\n//{\n//    SHFILEINFO fileInfo;\n//    ULONG iconFlag;\n//    HICON icon;\n//\n//    if (DefaultExtension && PhEqualStringZ(DefaultExtension, L\".exe\", TRUE))\n//    {\n//        // Special case for executable files (see above for reasoning).\n//\n//        icon = NULL;\n//\n//        if (FileName)\n//        {\n//            PhExtractIcon(\n//                FileName,\n//                LargeIcon ? &icon : NULL,\n//                !LargeIcon ? &icon : NULL\n//                );\n//        }\n//\n//        if (!icon)\n//        {\n//            PhGetStockApplicationIcon(\n//                !LargeIcon ? &icon : NULL,\n//                LargeIcon ? &icon : NULL\n//                );\n//\n//            if (icon)\n//                icon = CopyIcon(icon);\n//        }\n//\n//        return icon;\n//    }\n//\n//    iconFlag = LargeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON;\n//    icon = NULL;\n//    memset(&fileInfo, 0, sizeof(SHFILEINFO));\n//\n//    if (FileName && SHGetFileInfo(\n//        FileName,\n//        0,\n//        &fileInfo,\n//        sizeof(SHFILEINFO),\n//        SHGFI_ICON | iconFlag\n//        ))\n//    {\n//        icon = fileInfo.hIcon;\n//    }\n//\n//    if (!icon && DefaultExtension)\n//    {\n//        memset(&fileInfo, 0, sizeof(SHFILEINFO));\n//\n//        if (SHGetFileInfo(\n//            DefaultExtension,\n//            FILE_ATTRIBUTE_NORMAL,\n//            &fileInfo,\n//            sizeof(SHFILEINFO),\n//            SHGFI_ICON | iconFlag | SHGFI_USEFILEATTRIBUTES\n//            ))\n//            icon = fileInfo.hIcon;\n//    }\n//\n//    return icon;\n//}\n\n/**\n * Sets clipboard data for the specified format.\n *\n * \\param WindowHandle Owner window for OpenClipboard (may be NULL).\n * \\param Format Clipboard format identifier (e.g. CF_UNICODETEXT).\n * \\param Data Handle to  the data to place on the clipboard.\n */\nVOID PhpSetClipboardData(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Format,\n    _In_ HANDLE Data\n    )\n{\n    if (OpenClipboard(WindowHandle))\n    {\n        if (!EmptyClipboard())\n            goto Fail;\n\n        if (!SetClipboardData(Format, Data))\n            goto Fail;\n\n        CloseClipboard();\n\n        return;\n    }\n\nFail:\n    GlobalFree(Data);\n}\n\n/**\n * Copies a unicode string into the clipboard as CF_UNICODETEXT.\n *\n * \\param WindowHandle Owner window used for OpenClipboard (may be NULL).\n * \\param String Pointer to a PH_STRINGREF describing the unicode buffer and length in bytes.\n */\nVOID PhSetClipboardString(\n    _In_ HWND WindowHandle,\n    _In_ PCPH_STRINGREF String\n    )\n{\n    HANDLE data;\n    PVOID memory;\n\n    data = GlobalAlloc(GMEM_MOVEABLE, String->Length + sizeof(UNICODE_NULL));\n    memory = GlobalLock(data);\n\n    memcpy(memory, String->Buffer, String->Length);\n    *(PWCHAR)PTR_ADD_OFFSET(memory, String->Length) = UNICODE_NULL;\n\n    GlobalUnlock(memory);\n\n    PhpSetClipboardData(WindowHandle, CF_UNICODETEXT, data);\n}\n\n/**\n * Retrieves a unicode string from the clipboard (CF_UNICODETEXT). If the clipboard does not\n * contain CF_UNICODETEXT, or it cannot be opened, a reference to the empty string is returned.\n *\n * \\param WindowHandle Owner window used for OpenClipboard (may be NULL).\n * \\return Referenced PPH_STRING containing the clipboard text.\n */\nPPH_STRING PhGetClipboardString(\n    _In_ HWND WindowHandle\n    )\n{\n    PPH_STRING string;\n    HGLOBAL data;\n\n    string = PhReferenceEmptyString();\n\n    if (!IsClipboardFormatAvailable(CF_UNICODETEXT))\n        return string;\n\n    if (!OpenClipboard(WindowHandle))\n        return string;\n\n    data = GetClipboardData(CF_UNICODETEXT);\n    if (data)\n    {\n        PVOID str;\n\n        str = GlobalLock(data);\n        if (str)\n        {\n            PhMoveReference(&string, PhCreateString(str));\n            GlobalUnlock(data);\n        }\n    }\n\n    CloseClipboard();\n\n    return string;\n}\n\n/**\n * Creates a dialog from a dialog-template resource copying the template.\n *\n * This allows modifying the copied template (style) prior to creating the\n * dialog. The allocated template copy is freed after CreateDialogIndirectParam\n * returns.\n *\n * \\param Parent Parent window handle for the dialog.\n * \\param Style Style bits to apply to the dialog template.\n * \\param Instance Module instance whose resources contain the template.\n * \\param Template Resource name of the dialog template.\n * \\param DialogProc Dialog procedure for the new dialog.\n * \\param Parameter Optional parameter passed to DialogProc via lParam.\n * \\return HWND of the created dialog on success, or NULL on failure.\n */\nHWND PhCreateDialogFromTemplate(\n    _In_ HWND Parent,\n    _In_ ULONG Style,\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_ DLGPROC DialogProc,\n    _In_ PVOID Parameter\n    )\n{\n    PDLGTEMPLATEEX dialogTemplate;\n    HWND dialogHandle;\n\n    if (!NT_SUCCESS(PhLoadResourceCopy(Instance, Template, RT_DIALOG, NULL, &dialogTemplate)))\n        return NULL;\n\n    if (dialogTemplate->signature == USHRT_MAX)\n    {\n        dialogTemplate->style = Style;\n    }\n    else\n    {\n        ((DLGTEMPLATE *)dialogTemplate)->style = Style;\n    }\n\n    dialogHandle = CreateDialogIndirectParam(\n        Instance,\n        (DLGTEMPLATE *)dialogTemplate,\n        Parent,\n        DialogProc,\n        (LPARAM)Parameter\n        );\n\n    PhFree(dialogTemplate);\n\n    return dialogHandle;\n}\n\n/**\n * Creates a dialog from a dialog-template resource.\n *\n * \\param Instance Module instance whose resources contain the dialog template.\n * \\param Template Resource name of the dialog template.\n * \\param ParentWindow Optional parent window handle.\n * \\param DialogProc Dialog procedure for the dialog.\n * \\param Parameter Optional parameter passed to DialogProc via lParam.\n * \\return HWND of the created dialog on success, or NULL on failure.\n */\nHWND PhCreateDialog(\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_opt_ HWND ParentWindow,\n    _In_ DLGPROC DialogProc,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PDLGTEMPLATEEX dialogTemplate;\n    HWND dialogHandle;\n\n    if (!NT_SUCCESS(PhLoadResource(Instance, Template, RT_DIALOG, NULL, &dialogTemplate)))\n        return NULL;\n\n    dialogHandle = CreateDialogIndirectParam(\n        Instance,\n        (LPDLGTEMPLATE)dialogTemplate,\n        ParentWindow,\n        DialogProc,\n        (LPARAM)Parameter\n        );\n\n    return dialogHandle;\n}\n\n/**\n * Creates a window with extended styles.\n *\n * \\param ClassName Window class name.\n * \\param WindowName Window title (may be NULL).\n * \\param Style Window style flags.\n * \\param ExStyle Extended window style flags.\n * \\param X Initial x position.\n * \\param Y Initial y position.\n * \\param Width Initial width.\n * \\param Height Initial height.\n * \\param ParentWindow Optional parent or owner window handle.\n * \\param MenuHandle Optional menu or child-control identifier.\n * \\param InstanceHandle Optional module instance handle.\n * \\param Parameter Optional creation parameter passed to WM_CREATE.\n * \\return HWND of the created window, or NULL on failure.\n */\nHWND PhCreateWindowEx(\n    _In_ PCWSTR ClassName,\n    _In_opt_ PCWSTR WindowName,\n    _In_ ULONG Style,\n    _In_ ULONG ExStyle,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_opt_ HWND ParentWindow,\n    _In_opt_ HMENU MenuHandle,\n    _In_opt_ PVOID InstanceHandle,\n    _In_opt_ PVOID Parameter\n    )\n{\n    HWND windowHandle;\n\n    windowHandle = CreateWindowEx(\n        ExStyle,\n        ClassName,\n        WindowName,\n        Style,\n        X,\n        Y,\n        Width,\n        Height,\n        ParentWindow,\n        MenuHandle,\n        InstanceHandle,\n        Parameter\n        );\n\n    return windowHandle;\n}\n\n/**\n * Creates a message-only window.\n *\n * \\return HWND of the created message window or NULL on failure.\n */\nHWND PhCreateMessageWindow(\n    VOID\n    )\n{\n    HWND windowHandle;\n\n    windowHandle = CreateWindowEx(\n        0,\n        L\"Message\",\n        NULL,\n        0,\n        0, 0, 0, 0,\n        HWND_MESSAGE,\n        NULL,\n        NULL,\n        NULL\n        );\n\n    return windowHandle;\n}\n\n/**\n * Displays a modal dialog box from a dialog-template resource.\n *\n * \\param Instance Module instance whose resources contain the dialog template.\n * \\param Template Resource name of the dialog template.\n * \\param ParentWindow Optional parent window handle.\n * \\param DialogProc Dialog procedure for the dialog.\n * \\param Parameter Optional parameter passed to DialogProc via lParam.\n * \\return Dialog result (as returned by DialogBoxIndirectParam) or INT_ERROR on failure.\n */\nINT_PTR PhDialogBox(\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_opt_ HWND ParentWindow,\n    _In_ DLGPROC DialogProc,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PDLGTEMPLATEEX dialogTemplate;\n    INT_PTR dialogResult;\n\n    if (!NT_SUCCESS(PhLoadResource(Instance, Template, RT_DIALOG, NULL, &dialogTemplate)))\n        return INT_ERROR;\n\n    dialogResult = DialogBoxIndirectParam(\n        Instance,\n        (LPDLGTEMPLATE)dialogTemplate,\n        ParentWindow,\n        DialogProc,\n        (LPARAM)Parameter\n        );\n\n    return dialogResult;\n}\n\n/**\n * Loads a menu resource by name from a module.\n *\n * \\param DllBase Module base (mapped image or HMODULE) containing the menu resource.\n * \\param MenuName Resource name of the menu to load.\n * \\return HMENU created from the menu template, or NULL on failure.\n */\nHMENU PhLoadMenu(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR MenuName\n    )\n{\n    LPMENUTEMPLATE templateBuffer;\n\n    if (NT_SUCCESS(PhLoadResource(\n        DllBase,\n        MenuName,\n        RT_MENU,\n        NULL,\n        &templateBuffer\n        )))\n    {\n        return LoadMenuIndirect(templateBuffer);\n    }\n\n    return NULL;\n}\n\n/**\n * Property-sheet window procedure used to provide consistent behaviour across\n * property-sheets created by the library.\n *\n * This procedure is installed as a wrapper that:\n * - Restores the previous window procedure on WM_NCDESTROY.\n * - Forwards WM_KEYDOWN messages to the current page to allow page-level key handling.\n * - Prevents the hidden OK button from closing the dialog when activated.\n *\n * \\param hwnd Property sheet window handle.\n * \\param uMsg Window message.\n * \\param wParam WPARAM.\n * \\param lParam LPARAM.\n * \\return Result from the original window procedure or message-specific result.\n */\nLRESULT CALLBACK PhDefaultPropSheetWindowProcedure(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    WNDPROC oldWndProc;\n\n    oldWndProc = PhGetWindowContext(hwnd, 0xF);\n\n    if (!oldWndProc)\n        return 0;\n\n    switch (uMsg)\n    {\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContext(hwnd, 0xF);\n            PhSetWindowProcedure(hwnd, oldWndProc);\n        }\n        break;\n    case WM_SYSCOMMAND:\n        {\n            switch (wParam & 0xFFF0)\n            {\n            case SC_CLOSE:\n                {\n                    PostMessage(hwnd, WM_CLOSE, 0, 0);\n                    return 0;\n                }\n                break;\n            }\n        }\n        break;\n    case WM_COMMAND:\n        {\n            switch (GET_WM_COMMAND_ID(wParam, lParam))\n            {\n            case IDOK:\n                // Prevent the OK button from working (even though\n                // it's already hidden). This prevents the Enter\n                // key from closing the dialog box.\n                return 0;\n            }\n        }\n        break;\n    case WM_KEYDOWN: // forward key messages\n        {\n            HWND pageWindowHandle;\n\n            if (pageWindowHandle = PropSheet_GetCurrentPageHwnd(hwnd))\n            {\n                if (SendMessage(pageWindowHandle, uMsg, wParam, lParam))\n                {\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);\n}\n\n/**\n * Property-sheet callback used to initialise property-sheets created by the\n * library. Sets up the wrapper window procedure and hides the OK button.\n *\n * \\param hwndDlg Property sheet window handle.\n * \\param uMsg Callback message (PSCB_INITIALIZED expected).\n * \\param lParam Additional parameter (unused).\n * \\return 0 always.\n */\nINT CALLBACK PhModalPropSheetWindowProcedure(\n    _In_ HWND hwndDlg,\n    _In_ UINT uMsg,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uMsg)\n    {\n    case PSCB_INITIALIZED:\n        {\n            PhSetWindowContext(hwndDlg, 0xF, (PVOID)PhGetWindowProcedure(hwndDlg));\n            PhSetWindowProcedure(hwndDlg, PhDefaultPropSheetWindowProcedure);\n\n            // Hide the OK button.\n            ShowWindow(GetDlgItem(hwndDlg, IDOK), SW_HIDE);\n            // Set the Cancel button's text to \"Close\".\n            PhSetDialogItemText(hwndDlg, IDCANCEL, L\"Close\");\n        }\n        break;\n    }\n\n    return 0;\n}\n\n/**\n * Displays a property sheet using a custom message loop to avoid a known\n * PropertySheet bug which may discard WM_QUIT in rare cases.\n *\n * The function temporarily disables/enables the top level owner window and\n * pumps messages until the sheet closes. An automatic pool is created and\n * drained on each loop iteration to manage transient allocations.\n *\n * \\param Header Pointer to a PROPSHEETHEADER structure describing the property sheet.\n * \\return TRUE on success, FALSE on failure.\n */\nBOOLEAN PhModalPropertySheet(\n    _Inout_ PROPSHEETHEADER *Header\n    )\n{\n    // PropertySheet incorrectly discards WM_QUIT messages in certain cases, so we will use our own\n    // message loop. An example of this is when GetMessage (called by PropertySheet's message loop)\n    // dispatches a message directly from kernel-mode that causes the property sheet to close. In\n    // that case PropertySheet will retrieve the WM_QUIT message but will ignore it because of its\n    // buggy logic.\n\n    // This is also a good opportunity to introduce an auto-pool.\n\n    PH_AUTO_POOL autoPool;\n    HWND oldFocus;\n    HWND topLevelOwner;\n    HWND hwnd;\n    BOOL result;\n    MSG message;\n\n    PhInitializeAutoPool(&autoPool);\n\n    oldFocus = GetFocus();\n    topLevelOwner = Header->hwndParent;\n\n    while (topLevelOwner && (PhGetWindowStyle(topLevelOwner) & WS_CHILD))\n        topLevelOwner = GetParent(topLevelOwner);\n\n    if (topLevelOwner && (topLevelOwner == GetDesktopWindow() || EnableWindow(topLevelOwner, FALSE)))\n        topLevelOwner = NULL;\n\n    Header->dwFlags |= PSH_MODELESS;\n    // Allow to close other modeless property sheets (ex. Handle properties) by clicking the X on\n    // the taskbar window thumbnail, also forward key messages (Dart Vanya)\n    if (!Header->pfnCallback)\n    {\n        Header->dwFlags |= PSH_USECALLBACK;\n        Header->pfnCallback = PhModalPropSheetWindowProcedure;\n    }\n    hwnd = (HWND)PropertySheet(Header);\n\n    if (!hwnd)\n    {\n        if (topLevelOwner)\n            EnableWindow(topLevelOwner, TRUE);\n\n        return FALSE;\n    }\n\n    while (result = GetMessage(&message, NULL, 0, 0))\n    {\n        BOOLEAN processed = FALSE;\n\n        if (result == INT_ERROR)\n            break;\n\n        if (!processed)\n        {\n            if (!PropSheet_IsDialogMessage(hwnd, &message))\n            {\n                TranslateMessage(&message);\n                DispatchMessage(&message);\n            }\n        }\n\n        PhDrainAutoPool(&autoPool);\n\n        // Destroy the window when necessary.\n        if (!PropSheet_GetCurrentPageHwnd(hwnd))\n            break;\n    }\n\n    if (result == 0)\n        PostQuitMessage((INT)message.wParam);\n    if (Header->hwndParent && GetActiveWindow() == hwnd)\n        SetActiveWindow(Header->hwndParent);\n    if (topLevelOwner)\n        EnableWindow(topLevelOwner, TRUE);\n    if (oldFocus && IsWindow(oldFocus))\n        SetFocus(oldFocus);\n\n    DestroyWindow(hwnd);\n    PhDeleteAutoPool(&autoPool);\n\n    return TRUE;\n}\n\n/**\n * Initializes a the root layout item instance for the specified window.\n *\n * \\param Manager Pointer to the PH_LAYOUT_MANAGER to initialize.\n * \\param RootWindowHandle Handle of the root window for layout operations.\n * \\return TRUE on success, FALSE on failure.\n */\nBOOLEAN PhInitializeLayoutManager(\n    _Out_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND RootWindowHandle\n    )\n{\n    memset(Manager, 0, sizeof(PH_LAYOUT_MANAGER));\n\n    Manager->List = PhCreateList(4);\n    if (!Manager->List)\n        return FALSE;\n\n    Manager->WindowDpi = PhGetWindowDpi(RootWindowHandle);\n\n    Manager->RootItem.Handle = RootWindowHandle;\n    Manager->RootItem.ParentItem = NULL;\n    Manager->RootItem.LayoutParentItem = NULL;\n    Manager->RootItem.LayoutNumber = 0;\n    Manager->RootItem.NumberOfChildren = 0;\n    Manager->RootItem.DeferHandle = NULL;\n\n    if (PhGetClientRect(RootWindowHandle, &Manager->RootItem.Rect))\n    {\n        PhGetSizeDpiValue(&Manager->RootItem.Rect, Manager->WindowDpi, FALSE);\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Destroys a layout manager created by PhInitializeLayoutManager.\n * \\param Manager Pointer to the PH_LAYOUT_MANAGER to delete.\n */\nVOID PhDeleteLayoutManager(\n    _Inout_ PPH_LAYOUT_MANAGER Manager\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Manager->List->Count; i++)\n        PhFree(Manager->List->Items[i]);\n\n    PhDereferenceObject(Manager->List);\n}\n\n// HACK: The math below is all horribly broken, especially the HACK for multiline tab controls.\n\n/**\n * Adds a layout item for a window using default margin (zero).\n *\n * Convenience wrapper around PhAddLayoutItemEx which passes a zero margin.\n *\n * \\param Manager Pointer to the layout manager.\n * \\param Handle Window handle to manage.\n * \\param ParentItem Optional parent layout item; if NULL the root item is used.\n * \\param Anchor Anchor flags controlling layout behaviour.\n * \\return Pointer to the newly created PPH_LAYOUT_ITEM.\n */\nPPH_LAYOUT_ITEM PhAddLayoutItem(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_opt_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor\n    )\n{\n    PPH_LAYOUT_ITEM layoutItem;\n    RECT dummy = { 0 };\n\n    layoutItem = PhAddLayoutItemEx(\n        Manager,\n        Handle,\n        ParentItem,\n        Anchor,\n        &dummy\n        );\n\n    layoutItem->Margin = layoutItem->Rect;\n    PhConvertRect(&layoutItem->Margin, &layoutItem->ParentItem->Rect);\n\n    if (layoutItem->ParentItem != layoutItem->LayoutParentItem)\n    {\n        // Fix the margin because the item has a dummy parent. They share the same layout parent\n        // item.\n        layoutItem->Margin.top -= layoutItem->ParentItem->Rect.top;\n        layoutItem->Margin.left -= layoutItem->ParentItem->Rect.left;\n        layoutItem->Margin.right = layoutItem->ParentItem->Margin.right;\n        layoutItem->Margin.bottom = layoutItem->ParentItem->Margin.bottom;\n    }\n\n    return layoutItem;\n}\n\n/**\n * Adds a layout item with explicit margin values.\n *\n * \\param Manager Pointer to the layout manager.\n * \\param Handle Window handle to manage.\n * \\param ParentItem Optional parent layout item; if NULL the root item is used.\n * \\param Anchor Anchor flags controlling layout behaviour.\n * \\param Margin Pointer to a RECT that specifies the margin for the item.\n * \\return Pointer to the newly created PPH_LAYOUT_ITEM.\n */\nPPH_LAYOUT_ITEM PhAddLayoutItemEx(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_opt_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor,\n    _In_ PRECT Margin\n    )\n{\n    PPH_LAYOUT_ITEM item;\n\n    if (!ParentItem)\n        ParentItem = &Manager->RootItem;\n\n    item = PhAllocateZero(sizeof(PH_LAYOUT_ITEM));\n    item->Handle = Handle;\n    item->ParentItem = ParentItem;\n    item->LayoutNumber = Manager->LayoutNumber;\n    item->NumberOfChildren = 0;\n    item->DeferHandle = NULL;\n    item->Anchor = Anchor;\n\n    item->Rect = (RECT){ 0 };\n\n    item->LayoutParentItem = item->ParentItem;\n\n    while ((item->LayoutParentItem->Anchor & PH_LAYOUT_DUMMY_MASK) &&\n        item->LayoutParentItem->LayoutParentItem)\n    {\n        item->LayoutParentItem = item->LayoutParentItem->LayoutParentItem;\n    }\n\n    item->LayoutParentItem->NumberOfChildren++;\n\n    PhGetWindowRect(Handle, &item->Rect);\n    MapWindowRect(HWND_DESKTOP, item->LayoutParentItem->Handle, &item->Rect);\n\n    if (item->Anchor & PH_LAYOUT_TAB_CONTROL)\n    {\n        // We want to convert the tab control rectangle to the tab page display rectangle.\n        TabCtrl_AdjustRect(Handle, FALSE, &item->Rect);\n    }\n\n    PhGetSizeDpiValue(&item->Rect, Manager->WindowDpi, FALSE);\n    item->Margin = *Margin;\n    PhGetSizeDpiValue(&item->Margin, Manager->WindowDpi, FALSE);\n\n    PhAddItemList(Manager->List, item);\n\n    return item;\n}\n\n/**\n * Performs layout calculations for a single layout item and its parents.\n *\n * \\param Manager Pointer to the layout manager.\n * \\param Item Pointer to the layout item to layout.\n */\nVOID PhpLayoutItemLayout(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _Inout_ PPH_LAYOUT_ITEM Item\n    )\n{\n    RECT margin;\n    RECT rect;\n    ULONG diff;\n    BOOLEAN hasDummyParent;\n\n    if (Item->NumberOfChildren > 0 && !Item->DeferHandle)\n        Item->DeferHandle = BeginDeferWindowPos(Item->NumberOfChildren);\n\n    if (Item->LayoutNumber == Manager->LayoutNumber)\n        return;\n\n    // If this is the root item we must stop here.\n    if (!Item->ParentItem)\n        return;\n\n    PhpLayoutItemLayout(Manager, Item->ParentItem);\n\n    if (Item->ParentItem != Item->LayoutParentItem)\n    {\n        PhpLayoutItemLayout(Manager, Item->LayoutParentItem);\n        hasDummyParent = TRUE;\n    }\n    else\n    {\n        hasDummyParent = FALSE;\n    }\n\n    if (!PhGetWindowRect(Item->Handle, &Item->Rect))\n        return;\n\n    MapWindowRect(HWND_DESKTOP, Item->LayoutParentItem->Handle, &Item->Rect);\n\n    if (Item->Anchor & PH_LAYOUT_TAB_CONTROL)\n    {\n        // We want to convert the tab control rectangle to the tab page display rectangle.\n        TabCtrl_AdjustRect(Item->Handle, FALSE, &Item->Rect);\n    }\n\n    PhGetSizeDpiValue(&Item->Rect, Manager->WindowDpi, FALSE);\n\n    if (!(Item->Anchor & PH_LAYOUT_DUMMY_MASK))\n    {\n        margin = Item->Margin;\n        rect = Item->Rect;\n\n        // Convert right/bottom into margins to make the calculations\n        // easier.\n        PhConvertRect(&rect, &Item->LayoutParentItem->Rect);\n\n        if (!(Item->Anchor & (PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT)))\n        {\n            // TODO\n            PhRaiseStatus(STATUS_NOT_IMPLEMENTED);\n        }\n        else if (Item->Anchor & PH_ANCHOR_RIGHT)\n        {\n            if (Item->Anchor & PH_ANCHOR_LEFT)\n            {\n                rect.left = (hasDummyParent ? Item->ParentItem->Rect.left : 0) + margin.left;\n                rect.right = margin.right;\n            }\n            else\n            {\n                diff = margin.right - rect.right;\n\n                rect.left -= diff;\n                rect.right += diff;\n            }\n        }\n\n        if (!(Item->Anchor & (PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM)))\n        {\n            // TODO\n            PhRaiseStatus(STATUS_NOT_IMPLEMENTED);\n        }\n        else if (Item->Anchor & PH_ANCHOR_BOTTOM)\n        {\n            if (Item->Anchor & PH_ANCHOR_TOP)\n            {\n                // tab control hack\n                rect.top = (hasDummyParent ? Item->ParentItem->Rect.top : 0) + margin.top;\n                rect.bottom = margin.bottom;\n            }\n            else\n            {\n                diff = margin.bottom - rect.bottom;\n\n                rect.top -= diff;\n                rect.bottom += diff;\n            }\n        }\n\n        // Convert the right/bottom back into co-ordinates.\n        PhConvertRect(&rect, &Item->LayoutParentItem->Rect);\n        Item->Rect = rect;\n        PhGetSizeDpiValue(&rect, Manager->WindowDpi, TRUE);\n\n        if (!(Item->Anchor & PH_LAYOUT_IMMEDIATE_RESIZE))\n        {\n            Item->LayoutParentItem->DeferHandle = DeferWindowPos(\n                Item->LayoutParentItem->DeferHandle, Item->Handle,\n                NULL, rect.left, rect.top,\n                rect.right - rect.left, rect.bottom - rect.top,\n                SWP_NOACTIVATE | SWP_NOZORDER\n                );\n        }\n        else\n        {\n            // This is needed for tab controls, so that TabCtrl_AdjustRect will give us an\n            // up-to-date result.\n            SetWindowPos(\n                Item->Handle,\n                NULL, rect.left, rect.top,\n                rect.right - rect.left, rect.bottom - rect.top,\n                SWP_NOACTIVATE | SWP_NOZORDER\n                );\n        }\n    }\n\n    Item->LayoutNumber = Manager->LayoutNumber;\n}\n\n/**\n * Performs a layout pass for all items managed by the layout manager.\n *\n * \\param Manager Pointer to the layout manager.\n */\nVOID PhLayoutManagerLayout(\n    _Inout_ PPH_LAYOUT_MANAGER Manager\n    )\n{\n    ULONG count = Manager->List->Count;\n    PPH_LAYOUT_ITEM* items = (PPH_LAYOUT_ITEM*)Manager->List->Items;\n\n    Manager->LayoutNumber++;\n\n    if (!PhGetClientRect(Manager->RootItem.Handle, &Manager->RootItem.Rect))\n        return;\n\n    PhGetSizeDpiValue(&Manager->RootItem.Rect, Manager->WindowDpi, FALSE);\n\n    // BeginDeferWindowPos before the child items are laid out.\n    for (ULONG i = 0; i < count; i++)\n    {\n        PhpLayoutItemLayout(Manager, items[i]);\n    }\n\n    // EndDeferWindowPos after all child items are laid out.\n    for (ULONG i = 0; i < count; i++)\n    {\n        PPH_LAYOUT_ITEM item = items[i];\n\n        if (item->DeferHandle)\n        {\n            EndDeferWindowPos(item->DeferHandle);\n            item->DeferHandle = NULL;\n        }\n\n        if (item->Anchor & PH_LAYOUT_FORCE_INVALIDATE)\n        {\n            InvalidateRect(item->Handle, NULL, FALSE);\n        }\n    }\n\n    if (Manager->RootItem.DeferHandle)\n    {\n        EndDeferWindowPos(Manager->RootItem.DeferHandle);\n        Manager->RootItem.DeferHandle = NULL;\n    }\n}\n\n/**\n * Updates the layout manager's DPI value.\n *\n * If WindowDpi is non-zero it is used directly; otherwise the DPI for the\n * manager's root window is queried.\n *\n * \\param Manager Pointer to the layout manager.\n * \\param WindowDpi New DPI value or 0 to query the root window DPI.\n */\nVOID PhLayoutManagerUpdate(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ LONG WindowDpi\n    )\n{\n    if (WindowDpi)\n        Manager->WindowDpi = WindowDpi;\n    else\n        Manager->WindowDpi = PhGetWindowDpi(Manager->RootItem.Handle);\n}\n\n/**\n * Window property context hashtable equality function.\n *\n * Compares two PH_WINDOW_PROPERTY_CONTEXT entries for equality by\n * comparing the window handle and property hash.\n *\n * \\param Entry1 First entry pointer.\n * \\param Entry2 Second entry pointer.\n * \\return TRUE if the entries are equal, otherwise FALSE.\n */\n_Use_decl_annotations_\nBOOLEAN NTAPI PhpWindowContextHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_WINDOW_PROPERTY_CONTEXT entry1 = Entry1;\n    PPH_WINDOW_PROPERTY_CONTEXT entry2 = Entry2;\n\n    return\n        entry1->WindowHandle == entry2->WindowHandle &&\n        entry1->PropertyHash == entry2->PropertyHash;\n}\n\n/**\n * Window property context hashtable hash function.\n *\n * Produces a hash for a PH_WINDOW_PROPERTY_CONTEXT entry by combining\n * the window handle and the property hash to produce an unsigned value.\n *\n * \\param Entry Entry pointer.\n * \\return Computed hash value.\n */\n_Use_decl_annotations_\nULONG NTAPI PhpWindowContextHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_WINDOW_PROPERTY_CONTEXT entry = Entry;\n\n    return PhHashIntPtr((ULONG_PTR)entry->WindowHandle) ^ entry->PropertyHash; // PhHashInt32\n}\n\nVOID NTAPI PhWindowFlsCallback(\n    _In_ PVOID FlsData\n    )\n{\n    PPH_HASHTABLE hashtable = (PPH_HASHTABLE)FlsData;\n\n    PhClearReference(&hashtable);\n}\n\n/**\n * Returns or creates the per-thread window-context hashtable stored in FLS.\n *\n * If the hashtable does not exist for the current thread it is created and\n * stored in the thread's FLS slot. On failure the function will fail-fast.\n *\n * \\return Pointer to the per-thread PPH_HASHTABLE.\n */\nstatic PPH_HASHTABLE PhGetWindowContextHashTable(\n    VOID\n    )\n{\n    PPH_HASHTABLE hashtable;\n\n    if (hashtable = FlsGetValue(WindowCallbackFlsIndex))\n        return hashtable;\n\n    hashtable = PhCreateHashtable(\n        sizeof(PH_WINDOW_PROPERTY_CONTEXT),\n        PhpWindowContextHashtableEqualFunction,\n        PhpWindowContextHashtableHashFunction,\n        5\n        );\n\n    if (!FlsSetValue(WindowCallbackFlsIndex, hashtable))\n    {\n        PhShowStatus(NULL, L\"Unable to create the window context.\", 0, PhGetLastError());\n        RtlFailFast(FAST_FAIL_INVALID_FLS_DATA);\n    }\n\n    return hashtable;\n}\n\n/**\n * Retrieves a stored context pointer for a window and property hash.\n *\n * \\param WindowHandle The window handle.\n * \\param PropertyHash The property hash key.\n * \\return The stored context pointer, or NULL if not found.\n */\nPVOID PhGetWindowContext(\n    _In_ HWND WindowHandle,\n    _In_ ULONG PropertyHash\n    )\n{\n    PH_WINDOW_PROPERTY_CONTEXT lookupEntry;\n    PPH_WINDOW_PROPERTY_CONTEXT entry;\n\n    lookupEntry.WindowHandle = WindowHandle;\n    lookupEntry.PropertyHash = PropertyHash;\n\n    entry = PhFindEntryHashtable(PhGetWindowContextHashTable(), &lookupEntry);\n\n    if (entry)\n        return entry->Context;\n    else\n        return NULL;\n}\n\n/**\n * Stores a window context value associated with a property hash.\n *\n * If an entry for the given window/property pair already exists it will be\n * updated by PhAddEntryHashtable semantics.\n *\n * \\param WindowHandle The window handle.\n * \\param PropertyHash The property hash key.\n * \\param Context The context pointer to store.\n */\nVOID PhSetWindowContext(\n    _In_ HWND WindowHandle,\n    _In_ ULONG PropertyHash,\n    _In_ PVOID Context\n    )\n{\n    PH_WINDOW_PROPERTY_CONTEXT entry;\n\n    memset(&entry, 0, sizeof(PH_WINDOW_PROPERTY_CONTEXT));\n    entry.WindowHandle = WindowHandle;\n    entry.PropertyHash = PropertyHash;\n    entry.Context = Context;\n\n    PhAddEntryHashtable(PhGetWindowContextHashTable(), &entry);\n}\n\n/**\n * Removes a stored window context entry.\n *\n * \\param WindowHandle The window handle.\n * \\param PropertyHash The property hash key to remove.\n */\nVOID PhRemoveWindowContext(\n    _In_ HWND WindowHandle,\n    _In_ ULONG PropertyHash\n    )\n{\n    PH_WINDOW_PROPERTY_CONTEXT lookupEntry;\n\n    lookupEntry.WindowHandle = WindowHandle;\n    lookupEntry.PropertyHash = PropertyHash;\n\n    PhRemoveEntryHashtable(PhGetWindowContextHashTable(), &lookupEntry);\n}\n\ntypedef struct _PH_WINDOW_ENUM_CONTEXT\n{\n    _Function_class_(PH_WINDOW_ENUM_CALLBACK)\n    _In_ PPH_WINDOW_ENUM_CALLBACK Callback;\n    _In_opt_ PVOID Context;\n    BOOLEAN StopSearch;\n} PH_WINDOW_ENUM_CONTEXT, *PPH_WINDOW_ENUM_CONTEXT;\n\nstatic BOOL CALLBACK PhEnumWindowsCallback(\n    _In_ HWND WindowHandle,\n    _In_opt_ LPARAM Context\n    )\n{\n    PPH_WINDOW_ENUM_CONTEXT context = (PPH_WINDOW_ENUM_CONTEXT)Context;\n\n    if (context->Callback(WindowHandle, context->Context))\n        return TRUE;\n\n    context->StopSearch = TRUE;\n    // Note: If EnumWindowsProc returns zero, the return value is also zero.\n    // The callback should call SetLastError, but we can check StopSearch (dmex)\n    return FALSE;\n}\n\n/**\n * Enumerates all top-level windows on the screen.\n *\n * \\param Callback The callback function to be called for each child window.\n * \\param Context An optional context parameter to be passed to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumWindows(\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_WINDOW_ENUM_CONTEXT context;\n\n    memset(&context, 0, sizeof(PH_WINDOW_ENUM_CONTEXT));\n    context.Callback = Callback;\n    context.Context = Context;\n\n    if (EnumWindows(PhEnumWindowsCallback, (LPARAM)&context) || context.StopSearch)\n        return STATUS_SUCCESS;\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Enumerates windows using FindWindowEx.\n * This function enumerates windows that EnumWindows may miss, such as UWP/Metro apps.\n *\n * \\param ParentWindow The parent window to enumerate children of. If NULL, enumerates all top-level windows.\n * \\param Callback The callback function to be called for each window.\n * \\param Context An optional context parameter to be passed to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumWindowsEx(\n    _In_opt_ HWND ParentWindow,\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    HWND windowHandle = NULL;\n    ULONG i = 0;\n\n    while (i < 0x8000 && (windowHandle = FindWindowEx(ParentWindow, windowHandle, NULL, NULL)))\n    {\n        if (!Callback(windowHandle, Context))\n            return STATUS_SUCCESS;\n\n        i++;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Walks the window chain using GetWindow, enumerating windows in their exact Z-order.\n * This is a flexible function that can enumerate windows using any command:\n *\n * - GW_HWNDFIRST - First sibling\n * - GW_HWNDLAST - Last sibling\n * - GW_HWNDNEXT - Next sibling\n * - GW_HWNDPREV - Previous sibling\n * - GW_OWNER - Owner window\n * - GW_CHILD - First child\n *\n * Usage example:\n *\n * // Enumerate all siblings of a window\n * PhEnumGetWindow(hwnd, GW_HWNDNEXT, 1000, MyCallback, context);\n * \n * // Enumerate children\n * PhEnumGetWindow(hwnd, GW_CHILD, 1000, MyCallback, context);\n *\n * \\param StartWindow The window to start enumeration from. If NULL, starts with the first top-level window.\n * \\param Command The GetWindow command (GW_HWNDFIRST, GW_HWNDLAST, GW_HWNDNEXT, GW_HWNDPREV, GW_OWNER, GW_CHILD).\n * \\param Callback The callback function to be called for each window.\n * \\param Context An optional context parameter to be passed to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumGetWindow(\n    _In_opt_ HWND StartWindow,\n    _In_ ULONG Command,\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    HWND windowHandle;\n    ULONG i = 0;\n\n    if (StartWindow)\n    {\n        windowHandle = StartWindow;\n    }\n    else\n    {\n        // Get the first window if StartWindow is NULL\n        windowHandle = GetWindow(GetDesktopWindow(), GW_CHILD);\n    }\n\n    if (!windowHandle)\n    {\n        return STATUS_SUCCESS;\n    }\n\n    while (i < 0x8000 && windowHandle)\n    {\n        HWND nextWindow;\n\n        if (!Callback(windowHandle, Context))\n            break;\n\n        // Get the next window before incrementing, in case callback modifies window\n        nextWindow = GetWindow(windowHandle, Command);\n        \n        // Break if we've looped back to the start (shouldn't happen but safety check)\n        if (nextWindow == StartWindow || (i > 0 && nextWindow == windowHandle))\n            break;\n\n        windowHandle = nextWindow;\n        i++;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Enumerates all top-level windows in Z-order (top to bottom).\n * This is a convenience wrapper around PhEnumGetWindow that enumerates top-level windows.\n *\n * \\param Callback The callback function to be called for each window.\n * \\param Context An optional context parameter to be passed to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumWindowsZOrder(\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    HWND windowHandle;\n    ULONG i = 0;\n\n    // Get the first top-level window\n    windowHandle = GetWindow(GetDesktopWindow(), GW_CHILD);\n\n    if (!windowHandle)\n    {\n        return STATUS_SUCCESS;\n    }\n\n    // Enumerate all top-level windows in Z-order\n    while (i < 0x8000 && windowHandle)\n    {\n        HWND nextWindow;\n\n        if (!Callback(windowHandle, Context))\n            return STATUS_SUCCESS;\n\n        nextWindow = GetWindow(windowHandle, GW_HWNDNEXT);\n        windowHandle = nextWindow;\n        i++;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Enumerates the child windows of the specified window handle.\n *\n * \\param WindowHandle The handle of the parent window.\n * \\param Callback The callback function to be called for each child window.\n * \\param Context An optional context parameter to be passed to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumChildWindows(\n    _In_opt_ HWND WindowHandle,\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_WINDOW_ENUM_CONTEXT context;\n\n    memset(&context, 0, sizeof(PH_WINDOW_ENUM_CONTEXT));\n    context.Callback = Callback;\n    context.Context = Context;\n\n    if (EnumChildWindows(WindowHandle, PhEnumWindowsCallback, (LPARAM)&context))\n        return STATUS_SUCCESS;\n\n    //HWND childWindow = NULL;\n    //ULONG i = 0;\n    //\n    //while (i < Limit && (childWindow = FindWindowEx(WindowHandle, childWindow, NULL, NULL)))\n    //{\n    //    if (!Callback(childWindow, Context))\n    //        return;\n    //\n    //    i++;\n    //}\n   \n    // Note: EnumChildWindows doesn't support GetLastError. (dmex)\n    return STATUS_UNSUCCESSFUL;\n}\n\n/**\n * Builds a list of window handles and returns a pointer to a contiguous array of HWND values.\n *\n * \\param DesktopHandle Optional desktop handle. If NULL, the current desktop is used.\n * \\param ParentWindowHandle Optional parent window handle. If NULL, enumerates top-level windows.\n * \\param IncludeChildren When TRUE, includes child windows in the result list.\n * \\param ExcludeImmersive When TRUE, excludes immersive (UWP/Metro) windows.\n * \\param ThreadId Optional GUI thread identifier to filter results. If NULL, windows from all threads are returned.\n * \\param NumberOfHandles Receives the number of HWND entries in \\a Handles.\n * \\param Handles Receives a pointer to an array of HWND values. The caller must free the returned buffer using PhFree().\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhBuildHwndList(\n    _In_opt_ HANDLE DesktopHandle,\n    _In_opt_ HWND ParentWindowHandle,\n    _In_ BOOLEAN IncludeChildren,\n    _In_ BOOLEAN ExcludeImmersive,\n    _In_opt_ HANDLE ThreadId,\n    _Out_ PULONG NumberOfHandles,\n    _Outptr_result_buffer_(*NumberOfHandles) HWND** Handles\n    )\n{\n    NTSTATUS status;\n    PVOID buffer = NULL;\n    ULONG bufferSize = 0x1000;\n    ULONG returnLength = 0;\n\n    if (!NtUserBuildHwndList_Import())\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtUserBuildHwndList_Import()(\n            DesktopHandle,\n            ParentWindowHandle,\n            IncludeChildren,\n            ExcludeImmersive,\n            HandleToUlong(ThreadId),\n            bufferSize,\n            buffer,\n            &returnLength\n            );\n\n        if (status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFree(buffer);\n            bufferSize = returnLength;\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status) && status != STATUS_INVALID_HANDLE)\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    //if (returnLength < sizeof(HWND) || (returnLength % sizeof(HWND)) != 0)\n    //{\n    //    PhFree(buffer);\n    //    return STATUS_INVALID_THREAD;\n    //}\n\n    *NumberOfHandles = returnLength / sizeof(HWND);\n    *Handles = PTR_ADD_OFFSET(buffer, 0);\n    return STATUS_SUCCESS;\n}\n\ntypedef struct _GET_PROCESS_MAIN_WINDOW_CONTEXT\n{\n    HWND Window;\n    HWND ImmersiveWindow;\n    HANDLE ProcessId;\n    BOOLEAN IsImmersive;\n    BOOLEAN SkipInvisible;\n} GET_PROCESS_MAIN_WINDOW_CONTEXT, *PGET_PROCESS_MAIN_WINDOW_CONTEXT;\n\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nBOOLEAN CALLBACK PhpGetProcessMainWindowEnumWindowsProc(\n    _In_ HWND WindowHandle,\n    _In_ PVOID Context\n    )\n{\n    PGET_PROCESS_MAIN_WINDOW_CONTEXT context = (PGET_PROCESS_MAIN_WINDOW_CONTEXT)Context;\n    CLIENT_ID clientId;\n    WINDOWINFO windowInfo;\n\n    if (context->SkipInvisible && !IsWindowVisible(WindowHandle))\n        return TRUE;\n\n    if (!NT_SUCCESS(PhGetWindowClientId(WindowHandle, &clientId)))\n        return TRUE;\n\n    //if (UlongToHandle(processId) == context->ProcessId && (context->SkipInvisible ?\n    //    !((parentWindow = GetParent(WindowHandle)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent\n    //    PhGetWindowTextEx(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0 : TRUE)) // skip windows with no title\n\n    if (clientId.UniqueProcess == context->ProcessId)\n    {\n        if (!context->ImmersiveWindow && context->IsImmersive &&\n            GetProp(WindowHandle, L\"Windows.ImmersiveShell.IdentifyAsMainCoreWindow\"))\n        {\n            context->ImmersiveWindow = WindowHandle;\n        }\n\n        windowInfo.cbSize = sizeof(WINDOWINFO);\n\n        if (!context->Window && GetWindowInfo(WindowHandle, &windowInfo) && (windowInfo.dwStyle & WS_DLGFRAME))\n        {\n            context->Window = WindowHandle;\n\n            // If we're not looking at an immersive process, there's no need to search any more windows.\n            if (!context->IsImmersive)\n                return FALSE;\n        }\n    }\n\n    return TRUE;\n}\n\nHWND PhGetProcessMainWindow(\n    _In_opt_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle\n    )\n{\n    return PhGetProcessMainWindowEx(ProcessId, ProcessHandle, TRUE);\n}\n\nHWND PhGetProcessMainWindowEx(\n    _In_opt_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ BOOLEAN SkipInvisible\n    )\n{\n    GET_PROCESS_MAIN_WINDOW_CONTEXT context;\n    HANDLE processHandle = NULL;\n\n    memset(&context, 0, sizeof(GET_PROCESS_MAIN_WINDOW_CONTEXT));\n    context.ProcessId = ProcessId;\n    context.SkipInvisible = SkipInvisible;\n\n    if (ProcessHandle)\n        processHandle = ProcessHandle;\n    else\n        PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessId);\n\n    if (processHandle && WindowsVersion >= WINDOWS_8)\n        context.IsImmersive = PhIsImmersiveProcess(processHandle);\n\n    PhEnumWindows(PhpGetProcessMainWindowEnumWindowsProc, &context);\n    //PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, &context);\n\n    if (!ProcessHandle && processHandle)\n        NtClose(processHandle);\n\n    return context.ImmersiveWindow ? context.ImmersiveWindow : context.Window;\n}\n\nULONG PhGetDialogItemValue(\n    _In_ HWND WindowHandle,\n    _In_ LONG ControlID\n    )\n{\n    ULONG64 controlValue = 0;\n    HWND controlHandle;\n    PPH_STRING controlText;\n\n    if (controlHandle = GetDlgItem(WindowHandle, ControlID))\n    {\n        if (controlText = PhGetWindowText(controlHandle))\n        {\n            PhStringToInteger64(&controlText->sr, 10, &controlValue);\n            PhDereferenceObject(controlText);\n        }\n    }\n\n    return (ULONG)controlValue;\n}\n\n/**\n * Sets the text of a control in a dialog box to the string representation of a specified integer value.\n *\n * \\param WindowHandle The handle of the parent window.\n * \\param ControlID The control to be changed.\n * \\param Value The integer value used to generate the item text.\n * \\param Signed Indicates whether the Value parameter is signed or unsigned.\n */\nVOID PhSetDialogItemValue(\n    _In_ HWND WindowHandle,\n    _In_ LONG ControlID,\n    _In_ ULONG Value,\n    _In_ BOOLEAN Signed\n    )\n{\n    HWND controlHandle;\n    WCHAR valueString[PH_INT32_STR_LEN_1];\n\n    if (Signed)\n        PhPrintInt32(valueString, (LONG)Value);\n    else\n        PhPrintUInt32(valueString, Value);\n\n    if (controlHandle = GetDlgItem(WindowHandle, ControlID))\n    {\n        PhSetWindowText(controlHandle, valueString);\n    }\n}\n\n/**\n * Sets the title or text of a control in a dialog box.\n *\n * \\param WindowHandle The handle of the parent window.\n * \\param ControlID The control with a title or text to be set.\n * \\param WindowText The text to be copied to the control.\n */\nBOOLEAN PhSetDialogItemText(\n    _In_ HWND WindowHandle,\n    _In_ LONG ControlID,\n    _In_ PCWSTR WindowText\n    )\n{\n    HWND controlHandle;\n\n    if (controlHandle = GetDlgItem(WindowHandle, ControlID))\n    {\n        if (PhSetWindowText(controlHandle, WindowText))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Sets the title or text of a control.\n *\n * \\param WindowHandle The handle of the parent window.\n * \\param WindowText The text to be copied to the control.\n */\nBOOLEAN PhSetWindowText(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR WindowText\n    )\n{\n    ULONG_PTR result = 0;\n\n    if (SendMessageTimeout(\n        WindowHandle,\n        WM_SETTEXT,\n        0,\n        (LPARAM)WindowText,\n        SMTO_ABORTIFHUNG | SMTO_BLOCK,\n        1000,\n        &result\n        ) && result > 0)\n    {\n        return TRUE;\n    }\n\n    //if (SendMessage(WindowHandle, WM_SETTEXT, 0, (LPARAM)WindowText) > 0)\n    //{\n    //    return TRUE;\n    //}\n\n    //if (DefWindowProc(WindowHandle, WM_SETTEXT, 0, (LPARAM)WindowText) > 0)\n    //{\n    //    return TRUE;\n    //}\n\n    return FALSE;\n}\n\nVOID PhSetGroupBoxText(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR WindowText\n    )\n{\n    // Suspend the groupbox when setting the text otherwise\n    // the groupbox doesn't paint the text with dark theme colors. (dmex)\n\n    SendMessage(WindowHandle, WM_SETREDRAW, FALSE, 0);\n    PhSetWindowText(WindowHandle, WindowText);\n    SendMessage(WindowHandle, WM_SETREDRAW, TRUE, 0);\n\n    InvalidateRect(WindowHandle, NULL, FALSE);\n}\n\nVOID PhSetWindowAlwaysOnTop(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN AlwaysOnTop\n    )\n{\n    SetFocus(WindowHandle); // HACK - SetWindowPos doesn't work properly without this (wj32)\n    SetWindowPos(\n        WindowHandle,\n        AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\n        0, 0, 0, 0,\n        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE\n        );\n}\n\n_Success_(return)\nBOOLEAN PhSendMessageTimeout(\n    _In_ HWND WindowHandle,\n    _In_ ULONG WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ ULONG Timeout,\n    _Out_opt_ PULONG_PTR Result\n    )\n{\n    ULONG_PTR result = 0;\n\n    if (SendMessageTimeout(\n        WindowHandle,\n        WindowMessage,\n        wParam,\n        lParam,\n        SMTO_ABORTIFHUNG | SMTO_BLOCK,\n        Timeout,\n        &result\n        ) && result > 0)\n    {\n        if (Result)\n        {\n            *Result = result;\n        }\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Window-callback registration equality function.\n *\n * Compares two  window-callback registration entries by window handle.\n *\n * \\param Entry1 First entry pointer.\n * \\param Entry2 Second entry pointer.\n * \\return TRUE if the window handles match, otherwise FALSE.\n */\n_Use_decl_annotations_\nBOOLEAN NTAPI PhpWindowCallbackHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    return\n        ((PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION)Entry1)->WindowHandle ==\n        ((PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION)Entry2)->WindowHandle;\n}\n\n/**\n * Window-callback registration hash function.\n *\n * Returns a hash derived from the window handle member of the registration.\n *\n * \\param Entry Entry pointer.\n * \\return Computed hash value.\n */\n_Use_decl_annotations_\nULONG NTAPI PhpWindowCallbackHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashIntPtr((ULONG_PTR)((PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION)Entry)->WindowHandle);\n}\n\nVOID PhRegisterWindowCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION entry;\n\n    entry.WindowHandle = WindowHandle;\n    entry.Type = Type;\n\n    switch (Type) // HACK\n    {\n    case PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST:\n        if (PhGetIntegerSetting(L\"MainWindowAlwaysOnTop\"))\n            PhSetWindowAlwaysOnTop(WindowHandle, TRUE);\n        break;\n    }\n\n    PhAcquireQueuedLockExclusive(&WindowCallbackListLock);\n    PhAddEntryHashtable(WindowCallbackHashTable, &entry);\n    PhReleaseQueuedLockExclusive(&WindowCallbackListLock);\n}\n\nVOID PhUnregisterWindowCallback(\n    _In_ HWND WindowHandle\n    )\n{\n    PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION lookupEntry;\n    PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION entry;\n\n    lookupEntry.WindowHandle = WindowHandle;\n\n    PhAcquireQueuedLockExclusive(&WindowCallbackListLock);\n    entry = PhFindEntryHashtable(WindowCallbackHashTable, &lookupEntry);\n    assert(entry);\n    PhRemoveEntryHashtable(WindowCallbackHashTable, entry);\n    PhReleaseQueuedLockExclusive(&WindowCallbackListLock);\n}\n\nVOID PhWindowNotifyTopMostEvent(\n    _In_ BOOLEAN TopMost\n    )\n{\n    PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION entry;\n    ULONG i = 0;\n\n    PhAcquireQueuedLockExclusive(&WindowCallbackListLock);\n\n    while (PhEnumHashtable(WindowCallbackHashTable, &entry, &i))\n    {\n        if (entry->Type & PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST)\n        {\n            PhSetWindowAlwaysOnTop(entry->WindowHandle, TopMost);\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&WindowCallbackListLock);\n}\n\n/**\n * Retrieves the environment variables for the specified user.\n *\n * \\param Environment A pointer to the new environment block. \n * \\param TokenHandle Token to query for user environment variables.\n * If this is a primary token, the token must have TOKEN_QUERY and TOKEN_DUPLICATE access.\n * If the token is an impersonation token, it must have TOKEN_QUERY access.\n * If this parameter is NULL, the returned environment block contains system variables only.\n * \\param Inherit Specifies whether to inherit variables from the current process' environment. If this value is TRUE, the process inherits the current process' environment. \n * \\return A pointer to the imported procedure, or NULL if the procedure could not be imported.\n * \\remarks User-specific environment variables such as %USERPROFILE% are set only when the user's profile is loaded. To load a user's profile, call the LoadUserProfile function.\n */\nNTSTATUS PhCreateEnvironmentBlock(\n    _Out_ PVOID* Environment,\n    _In_opt_ HANDLE TokenHandle,\n    _In_ BOOLEAN Inherit\n    )\n{\n    //#include <UserEnv.h>\n    //HANDLE profileHandle;\n    //\n    //if (TokenHandle)\n    //{\n    //    PROFILEINFO profileInfo = { sizeof(PROFILEINFO) };\n    //    LoadUserProfile(TokenHandle, &profileInfo);\n    //    profileHandle = profileInfo.hProfile;\n    //}\n\n    *Environment = NULL;\n\n    if (CreateEnvironmentBlock_Import()(Environment, TokenHandle, Inherit))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    //if (TokenHandle && profileHandle)\n    //{\n    //    UnloadUserProfile(TokenHandle, profileHandle);\n    //}\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Frees environment variables created by the CreateEnvironmentBlock function.\n *\n * \\param Environment A pointer to the new environment block.\n */\nVOID PhDestroyEnvironmentBlock(\n    _In_ _Post_invalid_ PVOID Environment\n    )\n{\n    DestroyEnvironmentBlock_Import()(Environment);\n}\n\n_Success_(return)\nBOOLEAN PhRegenerateUserEnvironment(\n    _Out_opt_ PVOID* NewEnvironment,\n    _In_ BOOLEAN UpdateCurrentEnvironment\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOL (WINAPI *RegenerateUserEnvironment_I)(\n        _Out_ PVOID* NewEnvironment,\n        _In_ BOOL UpdateCurrentEnvironment\n        ) = NULL;\n    PVOID environment;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID shell32Handle;\n\n        if (shell32Handle = PhLoadLibrary(L\"shell32.dll\"))\n        {\n            RegenerateUserEnvironment_I = PhGetDllBaseProcedureAddress(shell32Handle, \"RegenerateUserEnvironment\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!RegenerateUserEnvironment_I)\n        return FALSE;\n\n    if (RegenerateUserEnvironment_I(&environment, UpdateCurrentEnvironment))\n    {\n        if (NewEnvironment)\n        {\n            *NewEnvironment = environment;\n        }\n        else\n        {\n            if (DestroyEnvironmentBlock_Import() && !UpdateCurrentEnvironment)\n            {\n                DestroyEnvironmentBlock_Import()(environment);\n            }\n        }\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nHICON PhGetInternalWindowIcon(\n    _In_ HWND WindowHandle,\n    _In_ UINT Type\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static HICON (WINAPI *InternalGetWindowIcon_I)(\n        _In_ HWND WindowHandle,\n        _In_ ULONG Type\n        ) = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID shell32Handle;\n\n        if (shell32Handle = PhLoadLibrary(L\"shell32.dll\"))\n        {\n            InternalGetWindowIcon_I = PhGetDllBaseProcedureAddress(shell32Handle, \"InternalGetWindowIcon\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!InternalGetWindowIcon_I)\n        return NULL;\n\n    return InternalGetWindowIcon_I(WindowHandle, Type);\n}\n\nBOOLEAN PhIsImmersiveProcess(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&IsImmersiveProcess) IsImmersiveProcess_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion >= WINDOWS_8)\n            IsImmersiveProcess_I = PhGetDllProcedureAddressZ(L\"user32.dll\", \"IsImmersiveProcess\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!IsImmersiveProcess_I)\n        return FALSE;\n\n    return !!IsImmersiveProcess_I(ProcessHandle);\n}\n\n_Success_(return)\nBOOLEAN PhGetProcessUIContextInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_UICONTEXT_INFORMATION UIContext\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&GetProcessUIContextInformation) GetProcessUIContextInformation_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion >= WINDOWS_8)\n            GetProcessUIContextInformation_I = PhGetDllProcedureAddressZ(L\"user32.dll\", \"GetProcessUIContextInformation\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!GetProcessUIContextInformation_I)\n        return FALSE;\n\n    return !!GetProcessUIContextInformation_I(ProcessHandle, UIContext);\n}\n\n_Success_(return)\nBOOLEAN PhGetProcessDpiAwareness(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_DPI_AWARENESS ProcessDpiAwareness\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&GetDpiAwarenessContextForProcess) GetDpiAwarenessContextForProcess_I = NULL;\n    static typeof(&AreDpiAwarenessContextsEqual) AreDpiAwarenessContextsEqual_I = NULL;\n    static BOOL (WINAPI* GetProcessDpiAwarenessInternal_I)(_In_ HANDLE hprocess, _Out_ PROCESS_DPI_AWARENESS* value) = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhGetLoaderEntryDllBaseZ(L\"user32.dll\"))\n        {\n            if (WindowsVersion >= WINDOWS_10_RS1)\n            {\n                GetDpiAwarenessContextForProcess_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetDpiAwarenessContextForProcess\", 0);\n                AreDpiAwarenessContextsEqual_I = PhGetDllBaseProcedureAddress(baseAddress, \"AreDpiAwarenessContextsEqual\", 0);\n            }\n\n            if (!(GetDpiAwarenessContextForProcess_I && AreDpiAwarenessContextsEqual_I))\n            {\n                GetProcessDpiAwarenessInternal_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetProcessDpiAwarenessInternal\", 0);\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (GetDpiAwarenessContextForProcess_I && AreDpiAwarenessContextsEqual_I)\n    {\n        DPI_AWARENESS_CONTEXT context = GetDpiAwarenessContextForProcess_I(ProcessHandle);\n\n        if (AreDpiAwarenessContextsEqual_I(context, DPI_AWARENESS_CONTEXT_UNAWARE))\n        {\n            *ProcessDpiAwareness = PH_PROCESS_DPI_AWARENESS_UNAWARE;\n            return TRUE;\n        }\n\n        if (AreDpiAwarenessContextsEqual_I(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))\n        {\n            *ProcessDpiAwareness = PH_PROCESS_DPI_AWARENESS_SYSTEM_DPI_AWARE;\n            return TRUE;\n        }\n\n        if (AreDpiAwarenessContextsEqual_I(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))\n        {\n            *ProcessDpiAwareness = PH_PROCESS_DPI_AWARENESS_PER_MONITOR_DPI_AWARE;\n            return TRUE;\n        }\n\n        if (AreDpiAwarenessContextsEqual_I(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))\n        {\n            *ProcessDpiAwareness = PH_PROCESS_DPI_AWARENESS_PER_MONITOR_AWARE_V2;\n            return TRUE;\n        }\n\n        if (AreDpiAwarenessContextsEqual_I(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED))\n        {\n            *ProcessDpiAwareness = PH_PROCESS_DPI_AWARENESS_UNAWARE_GDISCALED;\n            return TRUE;\n        }\n    }\n\n    if (GetProcessDpiAwarenessInternal_I)\n    {\n        PROCESS_DPI_AWARENESS dpiAwareness = PROCESS_DPI_UNAWARE;\n\n        if (GetProcessDpiAwarenessInternal_I(ProcessHandle, &dpiAwareness))\n        {\n            switch (dpiAwareness)\n            {\n            case PROCESS_DPI_UNAWARE:\n                *ProcessDpiAwareness = PH_PROCESS_DPI_AWARENESS_UNAWARE;\n                return TRUE;\n            case PROCESS_SYSTEM_DPI_AWARE:\n                *ProcessDpiAwareness = PH_PROCESS_DPI_AWARENESS_SYSTEM_DPI_AWARE;\n                return TRUE;\n            case PROCESS_PER_MONITOR_DPI_AWARE:\n                *ProcessDpiAwareness = PH_PROCESS_DPI_AWARENESS_PER_MONITOR_DPI_AWARE;\n                return TRUE;\n            }\n        }\n    }\n\n    return FALSE;\n}\n\nNTSTATUS PhGetPhysicallyInstalledSystemMemory(\n    _Out_ PULONGLONG TotalMemory,\n    _Out_ PULONGLONG ReservedMemory\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&GetPhysicallyInstalledSystemMemory) GetPhysicallyInstalledSystemMemory_I = NULL;\n    ULONGLONG physicallyInstalledSystemMemory = 0;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        GetPhysicallyInstalledSystemMemory_I = PhGetDllProcedureAddressZ(L\"kernel32.dll\", \"GetPhysicallyInstalledSystemMemory\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!GetPhysicallyInstalledSystemMemory_I)\n    {\n        return STATUS_PROCEDURE_NOT_FOUND;\n    }\n\n    if (GetPhysicallyInstalledSystemMemory_I(&physicallyInstalledSystemMemory))\n    {\n        *TotalMemory = physicallyInstalledSystemMemory * 1024ULL;\n        *ReservedMemory = physicallyInstalledSystemMemory * 1024ULL - UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE);\n        return STATUS_SUCCESS;\n    }\n\n    *TotalMemory = 0;\n    *ReservedMemory = 0;\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Retrieves the GUI resources used by a session.\n *\n * \\param Flags The flags to be used for retrieving the GUI resources.\n * \\param Total Pointer to a variable that will receive the total number of GUI resources.\n * \\return Returns the status code indicating the success or failure of the operation.\n */\nNTSTATUS PhGetSessionGuiResources(\n    _In_ ULONG Flags,\n    _Out_ PULONG Total\n    )\n{\n    return PhGetProcessGuiResources(GR_GLOBAL, Flags, Total);\n}\n\n/**\n * Retrieves the GUI resources used by a process.\n *\n * \\param ProcessHandle The handle to the process for which to retrieve the GUI resources.\n * \\param Flags The flags to be used for retrieving the GUI resources.\n * \\param Total Pointer to a variable that will receive the total number of GUI resources.\n * \\return Returns the status code indicating the success or failure of the operation.\n */\nNTSTATUS PhGetProcessGuiResources(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _Out_ PULONG Total\n    )\n{\n    if (*Total = GetGuiResources(ProcessHandle, Flags))\n        return STATUS_SUCCESS;\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Retrieves information about the active window or a specified GUI thread.\n *\n * \\param ThreadId The identifier for the thread for which information is to be retrieved. If this parameter is NULL, the function returns information for the foreground thread.\n * \\param ThreadInfo A pointer to a GUITHREADINFO structure that receives information describing the thread.\n * \\return Returns the status code indicating the success or failure of the operation.\n */\nNTSTATUS PhGetGUIThreadInfo(\n    _In_opt_ HANDLE ThreadId,\n    _Out_ PGUITHREADINFO ThreadInfo\n    )\n{\n    ThreadInfo->cbSize = sizeof(GUITHREADINFO);\n\n    if (GetGUIThreadInfo(HandleToUlong(ThreadId), ThreadInfo))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\nBOOLEAN PhGetThreadWin32Thread(\n    _In_ HANDLE ThreadId\n    )\n{\n    GUITHREADINFO info;\n\n    return NT_SUCCESS(PhGetGUIThreadInfo(ThreadId, &info));\n}\n\nNTSTATUS PhGetSendMessageReceiver(\n    _In_ HANDLE ThreadId,\n    _Out_ HWND *WindowHandle\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&GetSendMessageReceiver) GetSendMessageReceiver_I = NULL;\n    HWND windowHandle;\n\n    // GetSendMessageReceiver is an undocumented function exported by\n    // user32.dll. It retrieves the handle of the window which a thread\n    // is sending a message to. (wj32)\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        GetSendMessageReceiver_I = PhGetDllProcedureAddressZ(L\"user32.dll\", \"GetSendMessageReceiver\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!GetSendMessageReceiver_I)\n    {\n        return STATUS_PROCEDURE_NOT_FOUND;\n    }\n\n    if (windowHandle = GetSendMessageReceiver_I(ThreadId))\n    {\n        *WindowHandle = windowHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n// rev from ExtractIconExW\n_Success_(return)\nBOOLEAN PhExtractIcon(\n    _In_ PCWSTR FileName,\n    _Out_opt_ HICON *IconLarge,\n    _Out_opt_ HICON *IconSmall\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static LONG (WINAPI *PrivateExtractIconExW)(\n        _In_ PCWSTR FileName,\n        _In_ LONG IconIndex,\n        _Out_opt_ HICON* IconLarge,\n        _Out_opt_ HICON* IconSmall,\n        _In_ LONG IconCount\n        ) = NULL;\n    HICON iconLarge = NULL;\n    HICON iconSmall = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PrivateExtractIconExW = PhGetDllProcedureAddressZ(L\"user32.dll\", \"PrivateExtractIconExW\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!PrivateExtractIconExW)\n        return FALSE;\n\n    if (PrivateExtractIconExW(\n        FileName,\n        0,\n        IconLarge ? &iconLarge : NULL,\n        IconSmall ? &iconSmall : NULL,\n        1\n        ) > 0)\n    {\n        if (IconLarge)\n            *IconLarge = iconLarge;\n        if (IconSmall)\n            *IconSmall = iconSmall;\n\n        return TRUE;\n    }\n\n    if (iconLarge)\n        DestroyIcon(iconLarge);\n    if (iconSmall)\n        DestroyIcon(iconSmall);\n\n    return FALSE;\n}\n\n#ifndef MAKEFOURCC\n#define MAKEFOURCC(ch0, ch1, ch2, ch3) \\\n ((ULONG)(BYTE)(ch0) | ((ULONG)(BYTE)(ch1) << 8) | \\\n ((ULONG)(BYTE)(ch2) << 16) | ((ULONG)(BYTE)(ch3) << 24 ))\n#endif\n\n// https://docs.microsoft.com/en-us/windows/win32/menurc/newheader\n// One or more RESDIR structures immediately follow the NEWHEADER structure.\ntypedef struct _NEWHEADER\n{\n    USHORT Reserved;\n    USHORT ResourceType;\n    USHORT ResourceCount;\n} NEWHEADER, *PNEWHEADER;\n\n/**\n * Creates an icon handle from a resource directory within a mapped image.\n *\n * \\param MappedImage Pointer to a mapped image structure containing the resource data.\n * \\param ResourceDirectory Pointer to the resource directory within the mapped image.\n * \\param IconDirectory Pointer to the icon directory structure.\n * \\param Width The desired width of the icon in pixels.\n * \\param Height The desired height of the icon in pixels.\n * \\param Flags Flags that control the icon creation behavior.\n * \\param IconHandle Pointer to an HICON variable that receives the handle to the created icon.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateIconFromResourceDirectory(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PVOID ResourceDirectory,\n    _In_ PVOID IconDirectory,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_ ULONG Flags,\n    _Out_ HICON* IconHandle\n    )\n{\n    NTSTATUS status;\n    HICON iconHandle;\n    LONG iconResourceId;\n    ULONG iconResourceLength;\n    PVOID iconResourceBuffer;\n\n    if (!(iconResourceId = LookupIconIdFromDirectoryEx(\n        IconDirectory,\n        TRUE,\n        Width,\n        Height,\n        Flags\n        )))\n    {\n        return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    status = PhGetMappedImageResourceIndex(\n        MappedImage,\n        ResourceDirectory,\n        -iconResourceId,\n        RT_ICON,\n        &iconResourceLength,\n        &iconResourceBuffer\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (\n        ((PBITMAPINFOHEADER)iconResourceBuffer)->biSize != sizeof(BITMAPINFOHEADER) &&\n        ((PBITMAPCOREHEADER)iconResourceBuffer)->bcSize != sizeof(BITMAPCOREHEADER) &&\n        ((PBITMAPCOREHEADER)iconResourceBuffer)->bcSize != MAKEFOURCC(137, 'P', 'N', 'G') &&\n        ((PBITMAPCOREHEADER)iconResourceBuffer)->bcSize != MAKEFOURCC('J', 'P', 'E', 'G')\n        )\n    {\n        return STATUS_RESOURCE_TYPE_NOT_FOUND;\n    }\n\n    if (!(iconHandle = CreateIconFromResourceEx(\n        iconResourceBuffer,\n        iconResourceLength,\n        TRUE,\n        0x30000,\n        Width,\n        Height,\n        Flags\n        )))\n    {\n        return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    *IconHandle = iconHandle;\n    return STATUS_SUCCESS;\n}\n\n// rev from LdrLoadAlternateResourceModuleEx and GetMunResourceModuleForEnumIfExist (dmex)\n/**\n * Retrieves the filename of the \\SystemResources\\.mun alternate resource (mandatory on 19H1 and later).\n *\n * \\param FileName A string containing a file name.\n * \\param NativeFileName The type of name format.\n * \\param FilePathType\n * \\param ResourceFileName A pointer to the MUN filename.\n * \\return Successful or errant status.\n * \\remarks LdrLoadAlternateResourceModuleEx and GetMunResourceModuleForEnumIfExist always search the parent directory\n * and this function has the same logic and semantics. For example: C:\\Windows\\explorer.exe -> C:\\SystemResources\\explorer.exe.mun\n */\nNTSTATUS PhGetSystemResourcesFileName(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName,\n    _In_ RTL_PATH_TYPE FilePathType,\n    _Out_ PPH_STRING* ResourceFileName\n    )\n{\n    static CONST PH_STRINGREF directoryName = PH_STRINGREF_INIT(L\"\\\\SystemResources\\\\\");\n    static CONST PH_STRINGREF extensionName = PH_STRINGREF_INIT(L\".mun\");\n    PPH_STRING fileName;\n    PH_STRINGREF directoryPart;\n    PH_STRINGREF fileNamePart;\n    PH_STRINGREF baseNamePart;\n\n    if (WindowsVersion < WINDOWS_10_19H1)\n        return STATUS_UNSUCCESSFUL;\n    if (FilePathType == RtlPathTypeUncAbsolute)\n        return STATUS_OBJECT_PATH_SYNTAX_BAD;\n    if (!PhGetBasePath(FileName, &directoryPart, &fileNamePart))\n        return STATUS_OBJECT_PATH_INVALID;\n\n    if (directoryPart.Length && fileNamePart.Length)\n    {\n        if (!PhGetBasePath(&directoryPart, &baseNamePart, NULL))\n            return STATUS_OBJECT_PATH_INVALID;\n\n        fileName = PhConcatStringRef4(\n            &baseNamePart,\n            &directoryName,\n            &fileNamePart,\n            &extensionName\n            );\n\n        if (NativeFileName)\n        {\n            if (PhDoesFileExist(&fileName->sr))\n            {\n                *ResourceFileName = fileName;\n                return STATUS_SUCCESS;\n            }\n        }\n        else\n        {\n            if (PhDoesFileExistWin32(PhGetString(fileName)))\n            {\n                *ResourceFileName = fileName;\n                return STATUS_SUCCESS;\n            }\n        }\n\n        PhClearReference(&fileName);\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n/**\n * Extracts icons from the specified executable file.\n *\n * \\param FileName A string containing a file name.\n * \\param NativeFileName The type of name format.\n * \\param IconIndex The zero-based index of the icon within the group or a negative number for a specific resource identifier.\n * \\param IconLargeWidth\n * \\param IconLargeHeight\n * \\param IconSmallWidth\n * \\param IconSmallHeight\n * \\param IconLarge A handle to the large icon within the group or handle to the an icon from the resource identifier.\n * \\param IconSmall A handle to the small icon within the group or handle to the an icon from the resource identifier.\n * \\return Successful or errant status.\n * \\remarks Use this function instead of PrivateExtractIconExW() because images are mapped with SEC_COMMIT and READONLY\n * while PrivateExtractIconExW loads images with EXECUTE and SEC_IMAGE (section allocations and relocation processing).\n */\nNTSTATUS PhExtractIconEx(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName,\n    _In_ LONG IconIndex,\n    _In_ LONG IconLargeWidth,\n    _In_ LONG IconLargeHeight,\n    _In_ LONG IconSmallWidth,\n    _In_ LONG IconSmallHeight,\n    _Out_opt_ HICON *IconLarge,\n    _Out_opt_ HICON *IconSmall\n    )\n{\n    NTSTATUS status;\n    HICON iconLarge = NULL;\n    HICON iconSmall = NULL;\n    PPH_STRING resourceFileName = NULL;\n    PH_STRINGREF fileName;\n    PH_MAPPED_IMAGE mappedImage;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_RESOURCE_DIRECTORY resourceDirectory;\n    ULONG iconDirectoryResourceLength;\n    PNEWHEADER iconDirectoryResource;\n    RTL_PATH_TYPE fileNameType;\n\n    fileNameType = PhDetermineDosPathNameType(FileName);\n\n    if (!(fileNameType == RtlPathTypeRooted || fileNameType == RtlPathTypeDriveAbsolute))\n        return STATUS_OBJECT_PATH_SYNTAX_BAD;\n\n    status = PhGetSystemResourcesFileName(\n        FileName,\n        NativeFileName,\n        fileNameType,\n        &resourceFileName\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        fileName.Buffer = resourceFileName->Buffer;\n        fileName.Length = resourceFileName->Length;\n    }\n    else\n    {\n        fileName.Buffer = FileName->Buffer;\n        fileName.Length = FileName->Length;\n    }\n\n    if (PhIsNullOrEmptyStringRef(&fileName))\n    {\n        PhClearReference(&resourceFileName);\n        return FALSE;\n    }\n\n    __try\n    {\n        if (NativeFileName)\n        {\n            status = PhLoadMappedImageEx(\n                &fileName,\n                NULL,\n                &mappedImage\n                );\n        }\n        else\n        {\n            status = PhLoadMappedImage(\n                PhGetStringRefZ(&fileName),\n                NULL,\n                &mappedImage\n                );\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhClearReference(&resourceFileName);\n            return FALSE;\n        }\n\n        status = PhGetMappedImageDataDirectory(\n            &mappedImage,\n            IMAGE_DIRECTORY_ENTRY_RESOURCE,\n            &dataDirectory\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        resourceDirectory = PhMappedImageRvaToVa(\n            &mappedImage,\n            dataDirectory->VirtualAddress,\n            NULL\n            );\n\n        if (!resourceDirectory)\n            goto CleanupExit;\n\n        status = PhGetMappedImageResourceIndex(\n            &mappedImage,\n            resourceDirectory,\n            IconIndex,\n            RT_GROUP_ICON,\n            &iconDirectoryResourceLength,\n            &iconDirectoryResource\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        if (iconDirectoryResource->ResourceType != RES_ICON)\n            goto CleanupExit;\n\n        if (IconLarge)\n        {\n            status = PhCreateIconFromResourceDirectory(\n                &mappedImage,\n                resourceDirectory,\n                iconDirectoryResource,\n                IconLargeWidth,\n                IconLargeHeight,\n                LR_DEFAULTCOLOR,\n                &iconLarge\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n        }\n\n        if (IconSmall)\n        {\n            status = PhCreateIconFromResourceDirectory(\n                &mappedImage,\n                resourceDirectory,\n                iconDirectoryResource,\n                IconSmallWidth,\n                IconSmallHeight,\n                LR_DEFAULTCOLOR,\n                &iconSmall\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n    }\n\nCleanupExit:\n\n    PhUnloadMappedImage(&mappedImage);\n    PhClearReference(&resourceFileName);\n\n    if (IconLarge && IconSmall)\n    {\n        if (iconLarge && iconSmall)\n        {\n            *IconLarge = iconLarge;\n            *IconSmall = iconSmall;\n            return TRUE;\n        }\n\n        if (iconLarge)\n            DestroyIcon(iconLarge);\n        if (iconSmall)\n            DestroyIcon(iconSmall);\n\n        return FALSE;\n    }\n\n    if (IconLarge && iconLarge)\n    {\n        *IconLarge = iconLarge;\n        return TRUE;\n    }\n\n    if (IconSmall && iconSmall)\n    {\n        *IconSmall = iconSmall;\n        return TRUE;\n    }\n\n    if (iconLarge)\n        DestroyIcon(iconLarge);\n    if (iconSmall)\n        DestroyIcon(iconSmall);\n\n    return FALSE;\n}\n\n// Imagelist support\n\nHIMAGELIST PhImageListCreate(\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_ LONG Flags,\n    _In_ LONG InitialCount,\n    _In_ LONG GrowCount\n    )\n{\n    HRESULT status;\n    IImageList2* imageList;\n\n    status = ImageList_CoCreateInstance(\n        &CLSID_ImageList,\n        NULL,\n        &IID_IImageList2,\n        &imageList\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IImageList2_Initialize(\n            imageList,\n            Width,\n            Height,\n            Flags,\n            InitialCount,\n            GrowCount\n            );\n    }\n\n    //if (FAILED(status))\n    //{\n    //    status = ImageList_CoCreateInstance(\n    //        &CLSID_ImageList,\n    //        NULL,\n    //        &IID_IImageList,\n    //        &imageList\n    //        );\n    //}\n\n    if (FAILED(status))\n        return NULL;\n\n    return IImageListToHIMAGELIST(imageList);\n}\n\nBOOLEAN PhImageListDestroy(\n    _In_opt_ HIMAGELIST ImageListHandle\n    )\n{\n    if (!ImageListHandle)\n        return TRUE;\n\n    return SUCCEEDED(IImageList2_Release((IImageList2*)ImageListHandle));\n}\n\nBOOLEAN PhImageListSetImageCount(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ ULONG Count\n    )\n{\n    return SUCCEEDED(IImageList2_SetImageCount((IImageList2*)ImageListHandle, Count));\n}\n\nBOOLEAN PhImageListGetImageCount(\n    _In_ HIMAGELIST ImageListHandle,\n    _Out_ PLONG Count\n    )\n{\n    return SUCCEEDED(IImageList2_GetImageCount((IImageList2*)ImageListHandle, Count));\n}\n\nBOOLEAN PhImageListSetBkColor(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ COLORREF BackgroundColor\n    )\n{\n    COLORREF previousColor = 0;\n\n    return SUCCEEDED(IImageList2_SetBkColor(\n        (IImageList2*)ImageListHandle,\n        BackgroundColor,\n        &previousColor\n        ));\n}\n\nLONG PhImageListAddIcon(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ HICON IconHandle\n    )\n{\n    LONG index = INT_ERROR;\n\n    IImageList2_ReplaceIcon(\n        (IImageList2*)ImageListHandle,\n        INT_ERROR,\n        IconHandle,\n        &index\n        );\n\n    return index;\n}\n\nLONG PhImageListAddBitmap(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ HBITMAP BitmapImage,\n    _In_opt_ HBITMAP BitmapMask\n    )\n{\n    LONG index = INT_ERROR;\n\n    IImageList2_Add(\n        (IImageList2*)ImageListHandle,\n        BitmapImage,\n        BitmapMask,\n        &index\n        );\n\n    return index;\n}\n\nBOOLEAN PhImageListRemoveIcon(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index\n    )\n{\n    return SUCCEEDED(IImageList2_Remove(\n        (IImageList2*)ImageListHandle,\n        Index\n        ));\n}\n\nHICON PhImageListGetIcon(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index,\n    _In_ ULONG Flags\n    )\n{\n    HICON iconhandle = NULL;\n\n    IImageList2_GetIcon(\n        (IImageList2*)ImageListHandle,\n        Index,\n        Flags,\n        &iconhandle\n        );\n\n    return iconhandle;\n}\n\nBOOLEAN PhImageListGetIconSize(\n    _In_ HIMAGELIST ImageListHandle,\n    _Out_ PLONG cx,\n    _Out_ PLONG cy\n    )\n{\n    return SUCCEEDED(IImageList2_GetIconSize(\n        (IImageList2*)ImageListHandle,\n        cx,\n        cy\n        ));\n}\n\nBOOLEAN PhImageListReplace(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index,\n    _In_ HBITMAP BitmapImage,\n    _In_opt_ HBITMAP BitmapMask\n    )\n{\n    return SUCCEEDED(IImageList2_Replace(\n        (IImageList2*)ImageListHandle,\n        Index,\n        BitmapImage,\n        BitmapMask\n        ));\n}\n\nBOOLEAN PhImageListDrawIcon(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index,\n    _In_ HDC Hdc,\n    _In_ LONG x,\n    _In_ LONG y,\n    _In_ UINT32 Style,\n    _In_ BOOLEAN Disabled\n    )\n{\n    return PhImageListDrawEx(\n        ImageListHandle,\n        Index,\n        Hdc,\n        x,\n        y,\n        0,\n        0,\n        CLR_DEFAULT,\n        CLR_DEFAULT,\n        Style,\n        Disabled ? ILS_SATURATE : ILS_NORMAL\n        );\n}\n\nBOOLEAN PhImageListDrawEx(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index,\n    _In_ HDC Hdc,\n    _In_ LONG x,\n    _In_ LONG y,\n    _In_ LONG dx,\n    _In_ LONG dy,\n    _In_ COLORREF BackColor,\n    _In_ COLORREF ForeColor,\n    _In_ UINT32 Style,\n    _In_ ULONG State\n    )\n{\n    IMAGELISTDRAWPARAMS imagelistDraw;\n\n    memset(&imagelistDraw, 0, sizeof(IMAGELISTDRAWPARAMS));\n    imagelistDraw.cbSize = sizeof(IMAGELISTDRAWPARAMS);\n    imagelistDraw.himl = ImageListHandle;\n    imagelistDraw.hdcDst = Hdc;\n    imagelistDraw.i = Index;\n    imagelistDraw.x = x;\n    imagelistDraw.y = y;\n    imagelistDraw.cx = dx;\n    imagelistDraw.cy = dy;\n    imagelistDraw.rgbBk = BackColor;\n    imagelistDraw.rgbFg = ForeColor;\n    imagelistDraw.fStyle = Style;\n    imagelistDraw.fState = State;\n\n    return SUCCEEDED(IImageList2_Draw((IImageList2*)ImageListHandle, &imagelistDraw));\n}\n\nBOOLEAN PhImageListSetIconSize(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG cx,\n    _In_ LONG cy\n    )\n{\n    return SUCCEEDED(IImageList2_SetIconSize((IImageList2*)ImageListHandle, cx, cy));\n}\n\nstatic const PH_FLAG_MAPPING PhpInitiateShutdownMappings[] =\n{\n    { PH_SHUTDOWN_RESTART, SHUTDOWN_RESTART },\n    { PH_SHUTDOWN_POWEROFF, SHUTDOWN_POWEROFF },\n    { PH_SHUTDOWN_INSTALL_UPDATES, SHUTDOWN_INSTALL_UPDATES },\n    { PH_SHUTDOWN_HYBRID, SHUTDOWN_HYBRID },\n    { PH_SHUTDOWN_RESTART_BOOTOPTIONS, SHUTDOWN_RESTART_BOOTOPTIONS },\n    { PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, EXTENDED_STARTUPINFO_PRESENT },\n};\n\nULONG PhInitiateShutdown(\n    _In_ ULONG Flags\n    )\n{\n    ULONG status;\n    ULONG newFlags;\n\n    newFlags = 0;\n    PhMapFlags1(&newFlags, Flags, PhpInitiateShutdownMappings, ARRAYSIZE(PhpInitiateShutdownMappings));\n\n    status = InitiateShutdown(\n        NULL,\n        NULL,\n        0,\n        SHUTDOWN_FORCE_OTHERS | newFlags,\n        SHTDN_REASON_FLAG_PLANNED\n        );\n\n    return status;\n}\n\n/**\n * Sets shutdown parameters for the current process relative to the other processes in the system.\n *\n * \\param Level The shutdown priority for the current process.\n * \\param Flags Optional flags for terminating the current process.\n *\n * \\return Successful or errant status.\n */\nBOOLEAN PhSetProcessShutdownParameters(\n    _In_ ULONG Level,\n    _In_ ULONG Flags\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&SetProcessShutdownParameters) SetProcessShutdownParameters_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"kernel32.dll\"))\n        {\n            SetProcessShutdownParameters_I = PhGetDllBaseProcedureAddress(baseAddress, \"SetProcessShutdownParameters\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!SetProcessShutdownParameters_I)\n        return FALSE;\n\n    return !!SetProcessShutdownParameters_I(Level, Flags);\n}\n\n// Timeline drawing support\n\nVOID PhCustomDrawTreeTimeLine(\n    _In_ HDC Hdc,\n    _In_ PRECT CellRect,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER StartTime,\n    _In_ PLARGE_INTEGER CreateTime\n    )\n{\n    RECT drawRect = *CellRect;\n    LONG percent;\n    LARGE_INTEGER systemTime;\n    LARGE_INTEGER startTime;\n    LARGE_INTEGER createTime;\n\n    if (StartTime)\n    {\n        PhQuerySystemTime(&systemTime);\n        startTime.QuadPart = systemTime.QuadPart - StartTime->QuadPart;\n        createTime.QuadPart = systemTime.QuadPart - CreateTime->QuadPart;\n    }\n    else\n    {\n        static LARGE_INTEGER bootTime = { 0 };\n\n        if (bootTime.QuadPart == 0)\n        {\n            PhGetSystemBootTime(&bootTime);\n        }\n\n        PhQuerySystemTime(&systemTime);\n        startTime.QuadPart = systemTime.QuadPart - bootTime.QuadPart;\n        createTime.QuadPart = systemTime.QuadPart - CreateTime->QuadPart;\n    }\n\n    // Clamp percent between 0 and 100, avoid division by zero.\n    if (createTime.QuadPart > startTime.QuadPart || startTime.QuadPart == 0)\n    {\n        SetFlag(Flags, PH_DRAW_TIMELINE_OVERFLOW);\n        percent = 100;\n    }\n    else\n    {\n        percent = (LONG)((createTime.QuadPart * 100) / startTime.QuadPart);\n        if (percent < 0) percent = 0;\n        else if (percent > 100) percent = 100;\n    }\n\n    // Fill background and set brush color.\n    if (FlagOn(Flags, PH_DRAW_TIMELINE_DARKTHEME))\n    {\n        FillRect(Hdc, CellRect, PhThemeWindowBackgroundBrush);\n        SetDCBrushColor(Hdc, FlagOn(Flags, PH_DRAW_TIMELINE_OVERFLOW) ? RGB(128, 128, 128) : RGB(0, 130, 135));\n        SelectBrush(Hdc, PhGetStockBrush(DC_BRUSH));\n    }\n    else\n    {\n        FillRect(Hdc, CellRect, (HBRUSH)(COLOR_BTNFACE + 1));\n        SetDCBrushColor(Hdc, FlagOn(Flags, PH_DRAW_TIMELINE_OVERFLOW) ? RGB(128, 128, 128) : RGB(158, 202, 158));\n        SelectBrush(Hdc, PhGetStockBrush(DC_BRUSH));\n    }\n\n    PhInflateRect(&drawRect, -1, -1);\n    drawRect.bottom += 1;\n\n    //RECT fillRect = *CellRect;\n    //fillRect.right = fillRect.left + ((fillRect.right - fillRect.left) * percent) / 100;\n    //PatBlt(\n    //    Hdc,\n    //    fillRect.left,\n    //    fillRect.top,\n    //    fillRect.right - fillRect.left,\n    //    fillRect.bottom - fillRect.top,\n    //    PATCOPY\n    //    );\n    //\n    //LONG left = CellRect->right - PhMultiplyDivideSigned(CellRect->right - CellRect->left, percent, 100);\n    //PatBlt(\n    //    Hdc,\n    //    left,\n    //    CellRect->top,\n    //    CellRect->right - left,\n    //    CellRect->bottom - CellRect->top,\n    //    PATCOPY\n    //    );\n\n    LONG width = CellRect->right - CellRect->left;\n    LONG left = CellRect->right - ((width * percent) / 100);\n    PatBlt(\n        Hdc,\n        left,\n        CellRect->top,\n        width - (left - CellRect->left),\n        CellRect->bottom - CellRect->top,\n        PATCOPY\n        );\n\n    FrameRect(Hdc, CellRect, PhGetStockBrush(GRAY_BRUSH));\n}\n\n// Windows Imaging Component (WIC) bitmap support\n\nHBITMAP PhCreateDIBSection(\n    _In_ HDC Hdc,\n    _In_ PH_BUFFERFORMAT Format,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _Out_opt_ PVOID* Bits\n    )\n{\n    if (Bits)\n    {\n        *Bits = NULL;\n    }\n\n    switch (Format)\n    {\n    case PHBF_COMPATIBLEBITMAP:\n        {\n            return CreateCompatibleBitmap(Hdc, Width, Height);\n        }\n        break;\n    case PHBF_DIB:\n    case PHBF_TOPDOWNDIB:\n    case PHBF_TOPDOWNMONODIB:\n        {\n            BITMAPINFO bitmapInfo;\n\n            memset(&bitmapInfo, 0, sizeof(BITMAPINFOHEADER));\n            bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n            bitmapInfo.bmiHeader.biWidth = Width;\n            bitmapInfo.bmiHeader.biHeight = Format == PHBF_TOPDOWNDIB ? -Height : Height;\n            bitmapInfo.bmiHeader.biPlanes = 1;\n            bitmapInfo.bmiHeader.biBitCount = Format == PHBF_TOPDOWNMONODIB ? 1 : 32;\n            bitmapInfo.bmiHeader.biCompression = BI_RGB;\n\n            return CreateDIBSection(Hdc, &bitmapInfo, DIB_RGB_COLORS, Bits, NULL, 0);\n        }\n        break;\n    }\n\n    return NULL;\n}\n\nHBITMAP PhCreateBitmapHandle(\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _Outptr_opt_ _When_(return != NULL, _Notnull_) PVOID* Bits\n    )\n{\n    HDC hdc;\n    HBITMAP bitmapHandle;\n    BITMAPINFO bitmapInfo;\n\n    memset(&bitmapInfo, 0, sizeof(BITMAPINFO));\n    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n    bitmapInfo.bmiHeader.biWidth = Width;\n    bitmapInfo.bmiHeader.biHeight = -Height;\n    bitmapInfo.bmiHeader.biPlanes = 1;\n    bitmapInfo.bmiHeader.biBitCount = 32;\n    bitmapInfo.bmiHeader.biCompression = BI_RGB;\n\n    hdc = PhGetDC(NULL);\n    bitmapHandle = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, Bits, NULL, 0);\n    PhReleaseDC(NULL, hdc);\n\n    return bitmapHandle;\n}\n\nstatic PCGUID PhpGetImageFormatDecoderType(\n    _In_ PH_IMAGE_FORMAT_TYPE Format\n    )\n{\n    switch (Format)\n    {\n    case PH_IMAGE_FORMAT_TYPE_ICO:\n        return &GUID_ContainerFormatIco;\n    case PH_IMAGE_FORMAT_TYPE_BMP:\n        return &GUID_ContainerFormatBmp;\n    case PH_IMAGE_FORMAT_TYPE_JPG:\n        return &GUID_ContainerFormatJpeg;\n    case PH_IMAGE_FORMAT_TYPE_PNG:\n        return &GUID_ContainerFormatPng;\n    }\n\n    return &GUID_ContainerFormatRaw;\n}\n\nHBITMAP PhLoadImageFormatFromResource(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _In_ PH_IMAGE_FORMAT_TYPE Format,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    BOOLEAN success = FALSE;\n    HBITMAP bitmapHandle = NULL;\n    ULONG resourceLength = 0;\n    WICInProcPointer resourceBuffer = NULL;\n    PVOID bitmapBuffer = NULL;\n    IWICImagingFactory* wicImagingFactory = NULL;\n    IWICStream* wicBitmapStream = NULL;\n    IWICBitmapSource* wicBitmapSource = NULL;\n    IWICBitmapDecoder* wicBitmapDecoder = NULL;\n    IWICBitmapFrameDecode* wicBitmapFrame = NULL;\n    WICPixelFormatGUID pixelFormat;\n    UINT sourceWidth = 0;\n    UINT sourceHeight = 0;\n\n    if (!NT_SUCCESS(PhLoadResource(DllBase, Name, Type, &resourceLength, &resourceBuffer)))\n        goto CleanupExit;\n\n    if (FAILED(PhGetClassObject(L\"windowscodecs.dll\", &CLSID_WICImagingFactory, &IID_IWICImagingFactory, &wicImagingFactory)))\n        goto CleanupExit;\n    if (FAILED(IWICImagingFactory_CreateStream(wicImagingFactory, &wicBitmapStream)))\n        goto CleanupExit;\n    if (FAILED(IWICStream_InitializeFromMemory(wicBitmapStream, resourceBuffer, resourceLength)))\n        goto CleanupExit;\n    if (FAILED(IWICImagingFactory_CreateDecoder(wicImagingFactory, PhpGetImageFormatDecoderType(Format), &GUID_VendorMicrosoftBuiltIn, &wicBitmapDecoder)))\n        goto CleanupExit;\n    if (FAILED(IWICBitmapDecoder_Initialize(wicBitmapDecoder, (IStream*)wicBitmapStream, WICDecodeMetadataCacheOnDemand)))\n        goto CleanupExit;\n    if (FAILED(IWICBitmapDecoder_GetFrame(wicBitmapDecoder, 0, &wicBitmapFrame)))\n        goto CleanupExit;\n    if (FAILED(IWICBitmapFrameDecode_GetPixelFormat(wicBitmapFrame, &pixelFormat)))\n        goto CleanupExit;\n\n    if (IsEqualGUID(&pixelFormat, &GUID_WICPixelFormat32bppBGRA)) // CreateDIBSection format\n    {\n        if (FAILED(IWICBitmapFrameDecode_QueryInterface(wicBitmapFrame, &IID_IWICBitmapSource, &wicBitmapSource)))\n            goto CleanupExit;\n    }\n    else\n    {\n        IWICFormatConverter* wicFormatConverter = NULL;\n\n        if (FAILED(IWICImagingFactory_CreateFormatConverter(wicImagingFactory, &wicFormatConverter)))\n            goto CleanupExit;\n\n        if (FAILED(IWICFormatConverter_Initialize(\n            wicFormatConverter,\n            (IWICBitmapSource*)wicBitmapFrame,\n            &GUID_WICPixelFormat32bppBGRA,\n            WICBitmapDitherTypeNone,\n            NULL,\n            0.0f,\n            WICBitmapPaletteTypeCustom\n            )))\n        {\n            IWICFormatConverter_Release(wicFormatConverter);\n            goto CleanupExit;\n        }\n\n        if (FAILED(IWICFormatConverter_QueryInterface(wicFormatConverter, &IID_IWICBitmapSource, &wicBitmapSource)))\n            goto CleanupExit;\n\n        IWICFormatConverter_Release(wicFormatConverter);\n    }\n\n    if (!(bitmapHandle = PhCreateBitmapHandle(Width, Height, &bitmapBuffer)))\n        goto CleanupExit;\n\n    if (SUCCEEDED(IWICBitmapSource_GetSize(wicBitmapSource, &sourceWidth, &sourceHeight)) && sourceWidth == Width && sourceHeight == Height)\n    {\n        if (SUCCEEDED(IWICBitmapSource_CopyPixels(\n            wicBitmapSource,\n            NULL,\n            Width * sizeof(RGBQUAD),\n            Width * Height * sizeof(RGBQUAD),\n            bitmapBuffer\n            )))\n        {\n            success = TRUE;\n        }\n    }\n    else\n    {\n        IWICBitmapScaler* wicBitmapScaler = NULL;\n\n        if (SUCCEEDED(IWICImagingFactory_CreateBitmapScaler(wicImagingFactory, &wicBitmapScaler)))\n        {\n            if (SUCCEEDED(IWICBitmapScaler_Initialize(\n                wicBitmapScaler,\n                wicBitmapSource,\n                Width,\n                Height,\n                WindowsVersion < WINDOWS_10 ? WICBitmapInterpolationModeFant : WICBitmapInterpolationModeHighQualityCubic\n                )))\n            {\n                if (SUCCEEDED(IWICBitmapScaler_CopyPixels(\n                    wicBitmapScaler,\n                    NULL,\n                    Width * sizeof(RGBQUAD),\n                    Width * Height * sizeof(RGBQUAD),\n                    bitmapBuffer\n                    )))\n                {\n                    success = TRUE;\n                }\n            }\n\n            IWICBitmapScaler_Release(wicBitmapScaler);\n        }\n    }\n\nCleanupExit:\n\n    if (wicBitmapSource)\n        IWICBitmapSource_Release(wicBitmapSource);\n    if (wicBitmapDecoder)\n        IWICBitmapDecoder_Release(wicBitmapDecoder);\n    if (wicBitmapFrame)\n        IWICBitmapFrameDecode_Release(wicBitmapFrame);\n    if (wicBitmapStream)\n        IWICStream_Release(wicBitmapStream);\n    if (wicImagingFactory)\n        IWICImagingFactory_Release(wicImagingFactory);\n\n    if (!success)\n    {\n        if (bitmapHandle) DeleteBitmap(bitmapHandle);\n        return NULL;\n    }\n\n    return bitmapHandle;\n}\n\nHBITMAP PhLoadImageFromAddress(\n    _In_ PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    BOOLEAN success = FALSE;\n    HBITMAP bitmapHandle = NULL;\n    PVOID bitmapBuffer = NULL;\n    IWICImagingFactory* wicImagingFactory = NULL;\n    IWICStream* wicBitmapStream = NULL;\n    IWICBitmapSource* wicBitmapSource = NULL;\n    IWICBitmapDecoder* wicBitmapDecoder = NULL;\n    IWICBitmapFrameDecode* wicBitmapFrame = NULL;\n    WICPixelFormatGUID pixelFormat;\n    UINT sourceWidth = 0;\n    UINT sourceHeight = 0;\n\n    if (FAILED(PhGetClassObject(L\"windowscodecs.dll\", &CLSID_WICImagingFactory1, &IID_IWICImagingFactory, &wicImagingFactory)))\n        goto CleanupExit;\n    if (FAILED(IWICImagingFactory_CreateStream(wicImagingFactory, &wicBitmapStream)))\n        goto CleanupExit;\n    if (FAILED(IWICStream_InitializeFromMemory(wicBitmapStream, Buffer, BufferLength)))\n        goto CleanupExit;\n    if (FAILED(IWICImagingFactory_CreateDecoderFromStream(wicImagingFactory, (IStream*)wicBitmapStream, &GUID_VendorMicrosoftBuiltIn, WICDecodeMetadataCacheOnDemand, &wicBitmapDecoder)))\n        goto CleanupExit;\n    if (FAILED(IWICBitmapDecoder_GetFrame(wicBitmapDecoder, 0, &wicBitmapFrame)))\n        goto CleanupExit;\n    if (FAILED(IWICBitmapFrameDecode_GetPixelFormat(wicBitmapFrame, &pixelFormat)))\n        goto CleanupExit;\n\n    if (IsEqualGUID(&pixelFormat, &GUID_WICPixelFormat32bppBGRA))\n    {\n        if (FAILED(IWICBitmapFrameDecode_QueryInterface(wicBitmapFrame, &IID_IWICBitmapSource, &wicBitmapSource)))\n            goto CleanupExit;\n    }\n    else\n    {\n        IWICFormatConverter* wicFormatConverter = NULL;\n\n        if (FAILED(IWICImagingFactory_CreateFormatConverter(wicImagingFactory, &wicFormatConverter)))\n            goto CleanupExit;\n\n        if (FAILED(IWICFormatConverter_Initialize(\n            wicFormatConverter,\n            (IWICBitmapSource*)wicBitmapFrame,\n            &GUID_WICPixelFormat32bppBGRA,\n            WICBitmapDitherTypeNone,\n            NULL,\n            0.0f,\n            WICBitmapPaletteTypeCustom\n            )))\n        {\n            IWICFormatConverter_Release(wicFormatConverter);\n            goto CleanupExit;\n        }\n\n        if (FAILED(IWICFormatConverter_QueryInterface(wicFormatConverter, &IID_IWICBitmapSource, &wicBitmapSource)))\n            goto CleanupExit;\n\n        IWICFormatConverter_Release(wicFormatConverter);\n    }\n\n    if (!(bitmapHandle = PhCreateBitmapHandle(Width, Height, &bitmapBuffer)))\n        goto CleanupExit;\n\n    if (SUCCEEDED(IWICBitmapSource_GetSize(wicBitmapSource, &sourceWidth, &sourceHeight)) && sourceWidth == Width && sourceHeight == Height)\n    {\n        if (SUCCEEDED(IWICBitmapSource_CopyPixels(\n            wicBitmapSource,\n            NULL,\n            Width * sizeof(RGBQUAD),\n            Width * Height * sizeof(RGBQUAD),\n            bitmapBuffer\n            )))\n        {\n            success = TRUE;\n        }\n    }\n    else\n    {\n        IWICBitmapScaler* wicBitmapScaler = NULL;\n\n        if (SUCCEEDED(IWICImagingFactory_CreateBitmapScaler(wicImagingFactory, &wicBitmapScaler)))\n        {\n            if (SUCCEEDED(IWICBitmapScaler_Initialize(\n                wicBitmapScaler,\n                wicBitmapSource,\n                Width,\n                Height,\n                WindowsVersion < WINDOWS_10 ? WICBitmapInterpolationModeFant : WICBitmapInterpolationModeHighQualityCubic\n                )))\n            {\n                if (SUCCEEDED(IWICBitmapScaler_CopyPixels(\n                    wicBitmapScaler,\n                    NULL,\n                    Width * sizeof(RGBQUAD),\n                    Width * Height * sizeof(RGBQUAD),\n                    bitmapBuffer\n                    )))\n                {\n                    success = TRUE;\n                }\n            }\n\n            IWICBitmapScaler_Release(wicBitmapScaler);\n        }\n    }\n\nCleanupExit:\n\n    if (wicBitmapSource)\n        IWICBitmapSource_Release(wicBitmapSource);\n    if (wicBitmapDecoder)\n        IWICBitmapDecoder_Release(wicBitmapDecoder);\n    if (wicBitmapFrame)\n        IWICBitmapFrameDecode_Release(wicBitmapFrame);\n    if (wicBitmapStream)\n        IWICStream_Release(wicBitmapStream);\n    if (wicImagingFactory)\n        IWICImagingFactory_Release(wicImagingFactory);\n\n    if (!success)\n    {\n        if (bitmapHandle) DeleteBitmap(bitmapHandle);\n        return NULL;\n    }\n\n    return bitmapHandle;\n}\n\n// Load image and auto-detect the format (dmex)\nHBITMAP PhLoadImageFromResource(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    ULONG resourceLength;\n    WICInProcPointer resourceBuffer;\n\n    if (NT_SUCCESS(PhLoadResource(DllBase, Name, Type, &resourceLength, &resourceBuffer)))\n    {\n        return PhLoadImageFromAddress(resourceBuffer, resourceLength, Width, Height);\n    }\n\n    return NULL;\n}\n\n// Load image and auto-detect the format (dmex)\nHBITMAP PhLoadImageFromFile(\n    _In_ PCWSTR FileName,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    BOOLEAN success = FALSE;\n    HBITMAP bitmapHandle = NULL;\n    PVOID bitmapBuffer = NULL;\n    IWICImagingFactory* wicImagingFactory = NULL;\n    IWICBitmapSource* wicBitmapSource = NULL;\n    IWICBitmapDecoder* wicBitmapDecoder = NULL;\n    IWICBitmapFrameDecode* wicBitmapFrame = NULL;\n    WICPixelFormatGUID pixelFormat;\n    UINT sourceWidth = 0;\n    UINT sourceHeight = 0;\n\n    if (FAILED(PhGetClassObject(L\"windowscodecs.dll\", &CLSID_WICImagingFactory1, &IID_IWICImagingFactory, &wicImagingFactory)))\n        goto CleanupExit;\n    if (FAILED(IWICImagingFactory_CreateDecoderFromFilename(wicImagingFactory, FileName, &GUID_VendorMicrosoftBuiltIn, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &wicBitmapDecoder)))\n        goto CleanupExit;\n    if (FAILED(IWICBitmapDecoder_GetFrame(wicBitmapDecoder, 0, &wicBitmapFrame)))\n        goto CleanupExit;\n    if (FAILED(IWICBitmapFrameDecode_GetPixelFormat(wicBitmapFrame, &pixelFormat)))\n        goto CleanupExit;\n\n    if (IsEqualGUID(&pixelFormat, &GUID_WICPixelFormat32bppBGRA))\n    {\n        if (FAILED(IWICBitmapFrameDecode_QueryInterface(wicBitmapFrame, &IID_IWICBitmapSource, &wicBitmapSource)))\n            goto CleanupExit;\n    }\n    else\n    {\n        IWICFormatConverter* wicFormatConverter = NULL;\n\n        if (FAILED(IWICImagingFactory_CreateFormatConverter(wicImagingFactory, &wicFormatConverter)))\n            goto CleanupExit;\n\n        if (FAILED(IWICFormatConverter_Initialize(\n            wicFormatConverter,\n            (IWICBitmapSource*)wicBitmapFrame,\n            &GUID_WICPixelFormat32bppBGRA,\n            WICBitmapDitherTypeNone,\n            NULL,\n            0.0f,\n            WICBitmapPaletteTypeCustom\n            )))\n        {\n            IWICFormatConverter_Release(wicFormatConverter);\n            goto CleanupExit;\n        }\n\n        if (FAILED(IWICFormatConverter_QueryInterface(wicFormatConverter, &IID_IWICBitmapSource, &wicBitmapSource)))\n            goto CleanupExit;\n\n        IWICFormatConverter_Release(wicFormatConverter);\n    }\n\n    if (!(bitmapHandle = PhCreateBitmapHandle(Width, Height, &bitmapBuffer)))\n        goto CleanupExit;\n\n    if (SUCCEEDED(IWICBitmapSource_GetSize(wicBitmapSource, &sourceWidth, &sourceHeight)) && sourceWidth == Width && sourceHeight == Height)\n    {\n        if (SUCCEEDED(IWICBitmapSource_CopyPixels(\n            wicBitmapSource,\n            NULL,\n            Width * sizeof(RGBQUAD),\n            Width * Height * sizeof(RGBQUAD),\n            bitmapBuffer\n            )))\n        {\n            success = TRUE;\n        }\n    }\n    else\n    {\n        IWICBitmapScaler* wicBitmapScaler = NULL;\n\n        if (SUCCEEDED(IWICImagingFactory_CreateBitmapScaler(wicImagingFactory, &wicBitmapScaler)))\n        {\n            if (SUCCEEDED(IWICBitmapScaler_Initialize(\n                wicBitmapScaler,\n                wicBitmapSource,\n                Width,\n                Height,\n                WindowsVersion < WINDOWS_10 ? WICBitmapInterpolationModeFant : WICBitmapInterpolationModeHighQualityCubic\n                )))\n            {\n                if (SUCCEEDED(IWICBitmapScaler_CopyPixels(\n                    wicBitmapScaler,\n                    NULL,\n                    Width * sizeof(RGBQUAD),\n                    Width * Height * sizeof(RGBQUAD),\n                    bitmapBuffer\n                    )))\n                {\n                    success = TRUE;\n                }\n            }\n\n            IWICBitmapScaler_Release(wicBitmapScaler);\n        }\n    }\n\nCleanupExit:\n\n    if (wicBitmapSource)\n        IWICBitmapSource_Release(wicBitmapSource);\n    if (wicBitmapDecoder)\n        IWICBitmapDecoder_Release(wicBitmapDecoder);\n    if (wicBitmapFrame)\n        IWICBitmapFrameDecode_Release(wicBitmapFrame);\n    if (wicImagingFactory)\n        IWICImagingFactory_Release(wicImagingFactory);\n\n    if (!success)\n    {\n        if (bitmapHandle) DeleteBitmap(bitmapHandle);\n        return NULL;\n    }\n\n    return bitmapHandle;\n}\n\nNTSTATUS PhGetWindowCompositionAttribute(\n    _In_ HWND WindowHandle,\n    _Inout_ PWINDOWCOMPOSITIONATTRIBUTEDATA AttributeData\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOL (WINAPI* GetWindowCompositionAttribute_I)(\n        _In_ HWND WindowHandle,\n        _Inout_ PWINDOWCOMPOSITIONATTRIBUTEDATA AttributeData\n        ) = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        GetWindowCompositionAttribute_I = PhGetDllProcedureAddressZ(L\"user32.dll\", \"GetWindowCompositionAttribute\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (GetWindowCompositionAttribute_I)\n    {\n        if (GetWindowCompositionAttribute_I(WindowHandle, AttributeData))\n        {\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\nNTSTATUS PhSetWindowCompositionAttribute(\n    _In_ HWND WindowHandle,\n    _In_ PWINDOWCOMPOSITIONATTRIBUTEDATA AttributeData\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOL (WINAPI* SetWindowCompositionAttribute_I)(\n        _In_ HWND WindowHandle,\n        _In_ PWINDOWCOMPOSITIONATTRIBUTEDATA AttributeData\n        ) = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        SetWindowCompositionAttribute_I = PhGetDllProcedureAddressZ(L\"user32.dll\", \"SetWindowCompositionAttribute\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (SetWindowCompositionAttribute_I)\n    {\n        if (SetWindowCompositionAttribute_I(WindowHandle, AttributeData))\n        {\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\nNTSTATUS PhSetWindowAcrylicCompositionColor(\n    _In_ HWND WindowHandle,\n    _In_ ULONG GradientColor\n    )\n{\n    ACCENT_POLICY policy =\n    {\n        ACCENT_ENABLE_ACRYLICBLURBEHIND,\n        ACCENT_WINDOWS11_LUMINOSITY | ACCENT_BORDER_ALL,\n        GradientColor,\n        0\n    };\n    WINDOWCOMPOSITIONATTRIBUTEDATA attribute =\n    {\n        WCA_ACCENT_POLICY,\n        &policy,\n        sizeof(ACCENT_POLICY)\n    };\n\n    return PhSetWindowCompositionAttribute(WindowHandle, &attribute);\n}\n\nHCURSOR PhLoadArrowCursor(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static HCURSOR arrowCursorHandle = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        arrowCursorHandle = PhLoadCursor(NULL, IDC_ARROW);\n        PhEndInitOnce(&initOnce);\n    }\n\n    return arrowCursorHandle;\n}\n\nHCURSOR PhLoadDividerCursor(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static HCURSOR dividerCursorHandle = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        //dividerCursorHandle = PhLoadCursor(NULL, IDC_SIZEWE);\n\n        if (baseAddress = PhGetLoaderEntryDllBaseZ(L\"comctl32.dll\"))\n        {\n            dividerCursorHandle = PhLoadCursor(baseAddress, IDC_DIVIDER);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return dividerCursorHandle;\n}\n\nNTSTATUS PhGetUserObjectInformation(\n    _In_ HANDLE Handle,\n    _In_ LONG Index,\n    _Out_writes_bytes_opt_(UserObjectInformationLength) PVOID UserObjectInformation,\n    _In_ ULONG UserObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    if (GetUserObjectInformation(\n        Handle,\n        Index,\n        UserObjectInformation,\n        UserObjectInformationLength,\n        ReturnLength\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\nNTSTATUS PhIsInteractiveUserSession(\n    VOID\n    )\n{\n    NTSTATUS status;\n    USEROBJECTFLAGS flags;\n\n    memset(&flags, 0, sizeof(USEROBJECTFLAGS));\n\n    status = PhGetUserObjectInformation(\n        GetProcessWindowStation(),\n        UOI_FLAGS,\n        &flags,\n        sizeof(USEROBJECTFLAGS),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (BooleanFlagOn(flags.dwFlags, WSF_VISIBLE))\n            return STATUS_SUCCESS;\n\n        return STATUS_NOT_GUI_PROCESS;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetUserObjectNameInformation(\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING* String\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n    ULONG returnLength;\n\n    status = PhGetUserObjectInformation(\n        Handle,\n        UOI_NAME,\n        NULL,\n        0,\n        &returnLength\n        );\n\n    if (status != STATUS_BUFFER_TOO_SMALL)\n        return STATUS_INVALID_BUFFER_SIZE;\n    if (!(returnLength % sizeof(WCHAR)) == 0 && returnLength > sizeof(UNICODE_NULL))\n        return STATUS_INVALID_BUFFER_SIZE;\n\n    string = PhCreateStringEx(NULL, returnLength - sizeof(UNICODE_NULL));\n\n    status = PhGetUserObjectInformation(\n        Handle,\n        UOI_NAME,\n        string->Buffer,\n        (ULONG)string->Length + sizeof(UNICODE_NULL),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(string);\n        goto CleanupExit;\n    }\n\n    PhTrimToNullTerminatorString(string);\n    *String = string;\n    return STATUS_SUCCESS;\n\nCleanupExit:\n    return status;\n}\n\nNTSTATUS PhGetUserObjectTypeInformation(\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING* String\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n    ULONG returnLength;\n\n    status = PhGetUserObjectInformation(\n        Handle,\n        UOI_TYPE,\n        NULL,\n        0,\n        &returnLength\n        );\n\n    if (status != STATUS_BUFFER_TOO_SMALL)\n        return STATUS_INVALID_BUFFER_SIZE;\n    if (!(returnLength % sizeof(WCHAR)) == 0 && returnLength > sizeof(UNICODE_NULL))\n        return STATUS_INVALID_BUFFER_SIZE;\n\n    string = PhCreateStringEx(NULL, returnLength - sizeof(UNICODE_NULL));\n\n    status = PhGetUserObjectInformation(\n        Handle,\n        UOI_TYPE,\n        string->Buffer,\n        (ULONG)string->Length + sizeof(UNICODE_NULL),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(string);\n        goto CleanupExit;\n    }\n\n    PhTrimToNullTerminatorString(string);\n    *String = string;\n    return STATUS_SUCCESS;\n\nCleanupExit:\n    return status;\n}\n\nNTSTATUS PhGetUserObjectSidInformationToBuffer(\n    _In_ HANDLE Handle,\n    _Out_ PPH_USER_OBJECT_SID ObjectSid,\n    _In_ ULONG ObjectSidLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n\n    status = PhGetUserObjectInformation(\n        Handle,\n        UOI_USER_SID,\n        ObjectSid,\n        ObjectSidLength,\n        ReturnLength\n        );\n\n    return status;\n}\n\nNTSTATUS PhGetUserObjectSidInformationCopy(\n    _In_ HANDLE Handle,\n    _Out_ PSID* ObjectSid\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    UCHAR objectSidBuffer[SECURITY_MAX_SID_SIZE];\n    PSID objectSid = (PSID)objectSidBuffer;\n\n    status = PhGetUserObjectInformation(\n        Handle,\n        UOI_USER_SID,\n        objectSidBuffer,\n        sizeof(objectSidBuffer),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ObjectSid = PhAllocateCopy(objectSid, PhLengthSid(objectSid));\n    }\n\n    return status;\n}\n\nPPH_STRING PhGetCurrentWindowStationName(\n    VOID\n    )\n{\n    PPH_STRING string;\n\n    if (NT_SUCCESS(PhGetUserObjectNameInformation(\n        GetProcessWindowStation(),\n        &string\n        )))\n    {\n        return string;\n    }\n\n    return PhCreateString(L\"WinSta0\"); // assume the current window station is WinSta0\n}\n\nPPH_STRING PhGetCurrentThreadDesktopName(\n    VOID\n    )\n{\n    HDESK desktopHandle;\n    PPH_STRING string;\n\n    if (desktopHandle = GetThreadDesktop(HandleToUlong(NtCurrentThreadId())))\n    {\n        if (NT_SUCCESS(PhGetUserObjectNameInformation(desktopHandle, &string)))\n        {\n            return string;\n        }\n    }\n\n    return PhCreateString(L\"Default\"); // assume the current thread desktop is Default\n}\n\nstatic BOOLEAN PhpInitializeMRUList(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID comctl32ModuleHandle = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (comctl32ModuleHandle = PhLoadLibrary(L\"comctl32.dll\"))\n        {\n            CreateMRUList_I = PhGetDllBaseProcedureAddress(comctl32ModuleHandle, \"CreateMRUListW\", 0);\n            AddMRUString_I = PhGetDllBaseProcedureAddress(comctl32ModuleHandle, \"AddMRUStringW\", 0);\n            EnumMRUList_I = PhGetDllBaseProcedureAddress(comctl32ModuleHandle, \"EnumMRUListW\", 0);\n            FreeMRUList_I = PhGetDllBaseProcedureAddress(comctl32ModuleHandle, \"FreeMRUList\", 0);\n\n            if (!(CreateMRUList_I && AddMRUString_I && EnumMRUList_I && FreeMRUList_I))\n            {\n                PhFreeLibrary(comctl32ModuleHandle);\n                comctl32ModuleHandle = NULL;\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (comctl32ModuleHandle)\n        return TRUE;\n\n    return FALSE;\n}\n\nBOOLEAN PhRecentListAddCommand(\n    _In_ PPH_STRINGREF Command\n)\n{\n    static CONST PH_STRINGREF prefixSr = PH_STRINGREF_INIT(L\"\\\\1\");\n    BOOLEAN result = FALSE;\n    MRUINFO info;\n    HANDLE listHandle;\n\n    if (!PhpInitializeMRUList())\n        return FALSE;\n\n    memset(&info, 0, sizeof(MRUINFO));\n    info.cbSize = sizeof(MRUINFO);\n    info.uMaxItems = UINT_MAX;\n    info.hKey = HKEY_CURRENT_USER;\n    info.lpszSubKey = L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Explorer\\\\RunMRU\";\n\n    if (listHandle = CreateMRUList_I(&info))\n    {\n        PPH_STRING command = PhConcatStringRef2(Command, &prefixSr);\n\n        if (AddMRUString_I(listHandle, PhGetString(command)) != INT_ERROR)\n        {\n            result = TRUE;\n        }\n\n        PhDereferenceObject(command);\n\n        FreeMRUList_I(listHandle);\n    }\n\n    return result;\n}\n\nVOID PhEnumerateRecentList(\n    _In_ PPH_ENUM_MRULIST_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    MRUINFO info;\n    HANDLE listHandle;\n    LONG listCount;\n\n    if (!PhpInitializeMRUList())\n        return;\n\n    memset(&info, 0, sizeof(MRUINFO));\n    info.cbSize = sizeof(MRUINFO);\n    info.uMaxItems = UINT_MAX;\n    info.hKey = HKEY_CURRENT_USER;\n    info.lpszSubKey = L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Explorer\\\\RunMRU\";\n\n    if (!(listHandle = CreateMRUList_I(&info)))\n        return;\n\n    listCount = EnumMRUList_I(\n        listHandle,\n        MAXINT,\n        NULL,\n        0\n        );\n\n    for (LONG i = 0; i < listCount; i++)\n    {\n        PH_STRINGREF string;\n        SIZE_T returnLength;\n        WCHAR buffer[DOS_MAX_PATH_LENGTH] = L\"\";\n\n        returnLength = EnumMRUList_I(\n            listHandle,\n            i,\n            buffer,\n            RTL_NUMBER_OF(buffer)\n            );\n\n        if (returnLength >= RTL_NUMBER_OF(buffer))\n            continue;\n        if (returnLength < sizeof(UNICODE_NULL))\n            continue;\n\n        buffer[returnLength] = UNICODE_NULL;\n\n        string.Buffer = buffer;\n        string.Length = returnLength * sizeof(WCHAR);\n\n        // trim \\\\1 (dmex)\n        if (string.Buffer[returnLength - 1] == L'1' && string.Buffer[returnLength - 2] == L'\\\\')\n        {\n            string.Buffer[returnLength - 2] = UNICODE_NULL;\n            string.Length -= 4;\n        }\n\n        if (!Callback(&string, Context))\n            break;\n    }\n\n    FreeMRUList_I(listHandle);\n}\n\n/**\n * Forcibly closes the specified window.\n *\n * \\param WindowHandle A handle to the window to be closed.\n * \\param Force If TRUE, force the destruction of the window if an initial attempt to gently close the window using WM_CLOSE fails. If FALSE, only WM_CLOSE is attempted.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-endtask\n */\nNTSTATUS PhTerminateWindow(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN Force\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOL (WINAPI* EndTask_I)(_In_ HWND hWnd, _In_ BOOL fShutDown, _In_ BOOL fForce) = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        EndTask_I = PhGetDllProcedureAddressZ(L\"user32.dll\", \"EndTask\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!EndTask_I)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    if (EndTask_I(WindowHandle, FALSE, !!Force))\n        return STATUS_SUCCESS;\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Queries information for a window using the user subsystem entry NtUserQueryWindow.\n *\n * \\param WindowHandle A handle to the target window.\n * \\param WindowInfo The WINDOWINFOCLASS selector describing which piece of information to query.\n * \\return The value returned by NtUserQueryWindow on success. Returns 0 (NULL) if the\n * function is unavailable or the call fails.\n */\nULONG_PTR PhUserQueryWindow(\n    _In_ HWND WindowHandle,\n    _In_ WINDOWINFOCLASS WindowInfo\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&NtUserQueryWindow) NtUserQueryWindow_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhGetDllHandle(L\"win32u.dll\"))\n        {\n            NtUserQueryWindow_I = PhGetDllBaseProcedureAddress(baseAddress, \"NtUserQueryWindow\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (NtUserQueryWindow_I)\n    {\n        return NtUserQueryWindow_I(WindowHandle, WindowInfo);\n    }\n\n    return 0;\n}\n\n/**\n * Opens a handle to the process associated with the specified window.\n *\n * \\param ProcessHandle Pointer to a variable that receives the process handle.\n * \\param DesiredAccess The access rights requested for the process handle.\n * \\param WindowHandle Handle to the window whose associated process is to be opened.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenWindowProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HWND WindowHandle\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&NtUserGetWindowProcessHandle) NtUserGetWindowProcessHandle_I = NULL;\n    HANDLE processHandle;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhGetDllHandle(L\"win32u.dll\"))\n        {\n            NtUserGetWindowProcessHandle_I = PhGetDllBaseProcedureAddress(baseAddress, \"NtUserGetWindowProcessHandle\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!NtUserGetWindowProcessHandle_I)\n    {\n        return STATUS_PROCEDURE_NOT_FOUND;\n    }\n\n    if (processHandle = NtUserGetWindowProcessHandle_I(WindowHandle, DesiredAccess))\n    {\n        *ProcessHandle = processHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Retrieves the source of the input message.\n *\n * \\param InputMessageSource The INPUT_MESSAGE_SOURCE that holds the device type and the ID of the input message source.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcurrentinputmessagesource\n */\nNTSTATUS PhGetInputMessageSource(\n    _Out_ INPUT_MESSAGE_SOURCE* InputMessageSource\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&GetCurrentInputMessageSource) GetCurrentInputMessageSource_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhGetDllHandle(L\"user32.dll\"))\n        {\n            GetCurrentInputMessageSource_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetCurrentInputMessageSource\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (GetCurrentInputMessageSource_I)\n    {\n        if (GetCurrentInputMessageSource_I(InputMessageSource))\n        {\n            return STATUS_SUCCESS;\n        }\n\n        return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    return STATUS_PROCEDURE_NOT_FOUND;\n}\n\n/**\n * Retrieves the source of the input message (GetCurrentInputMessageSourceInSendMessage).\n *\n * \\param InputMessageSource The INPUT_MESSAGE_SOURCE that holds the device type and the ID of the input message source.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcimssm\n */\nNTSTATUS PhGetInputMessageSourceSM(\n    _Out_ INPUT_MESSAGE_SOURCE* InputMessageSource\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&GetCIMSSM) GetCIMSSM_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhGetDllHandle(L\"user32.dll\"))\n        {\n            GetCIMSSM_I = PhGetDllBaseProcedureAddress(baseAddress, \"GetCIMSSM\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (GetCIMSSM_I)\n    {\n        if (GetCIMSSM_I(InputMessageSource))\n        {\n            return STATUS_SUCCESS;\n        }\n\n        return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    return STATUS_PROCEDURE_NOT_FOUND;\n}\n"
  },
  {
    "path": "phlib/guisuplistview.cpp",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <guisup.h>\n#include <guisupview.h>\n\n#include <commoncontrols.h>\n#include <wincodec.h>\n#include <uxtheme.h>\n\nLONG PhAddListViewColumnDpi(\n    _In_ HWND ListViewHandle,\n    _In_ LONG ListViewDpi,\n    _In_ LONG Index,\n    _In_ LONG DisplayIndex,\n    _In_ LONG SubItemIndex,\n    _In_ LONG Format,\n    _In_ LONG Width,\n    _In_ PCWSTR Text\n    )\n{\n    LVCOLUMN column;\n\n    memset(&column, 0, sizeof(LVCOLUMN));\n    column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;\n    column.fmt = Format;\n    column.cx = WindowsVersion < WINDOWS_10 ? Width : PhGetDpi(Width, ListViewDpi);\n    column.pszText = const_cast<PWSTR>(Text);\n    column.iSubItem = SubItemIndex;\n    column.iOrder = DisplayIndex;\n\n    return ListView_InsertColumn(ListViewHandle, Index, &column);\n}\n\nLONG PhAddIListViewColumnDpi(\n    _In_ IListView* ListView,\n    _In_ LONG ListViewDpi,\n    _In_ LONG Index,\n    _In_ LONG DisplayIndex,\n    _In_ LONG SubItemIndex,\n    _In_ LONG Format,\n    _In_ LONG Width,\n    _In_ PCWSTR Text\n    )\n{\n    LVCOLUMN column;\n    LONG index;\n\n    memset(&column, 0, sizeof(LVCOLUMN));\n    column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;\n    column.fmt = Format;\n    column.cx = WindowsVersion < WINDOWS_10 ? Width : PhGetDpi(Width, ListViewDpi);\n    column.pszText = const_cast<PWSTR>(Text);\n    column.iSubItem = SubItemIndex;\n    column.iOrder = DisplayIndex;\n\n    if (SUCCEEDED(ListView->InsertColumn(Index, &column, &index)))\n        return index;\n\n    return INT_ERROR;\n}\n\nLONG PhAddListViewColumn(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG DisplayIndex,\n    _In_ LONG SubItemIndex,\n    _In_ LONG Format,\n    _In_ LONG Width,\n    _In_ PCWSTR Text\n    )\n{\n    LONG dpiValue;\n\n    dpiValue = PhGetWindowDpi(ListViewHandle);\n\n    return PhAddListViewColumnDpi(\n        ListViewHandle,\n        dpiValue,\n        Index,\n        DisplayIndex,\n        SubItemIndex,\n        Format,\n        Width,\n        Text\n        );\n}\n\nLONG PhAddIListViewColumn(\n    _In_ IListView* ListView,\n    _In_ LONG Index,\n    _In_ LONG DisplayIndex,\n    _In_ LONG SubItemIndex,\n    _In_ LONG Format,\n    _In_ LONG Width,\n    _In_ PCWSTR Text\n    )\n{\n    LONG dpiValue;\n    HWND windowHandle;\n\n    if (!SUCCEEDED(ListView->GetHeaderControl(&windowHandle)))\n        return INT_ERROR;\n\n    dpiValue = PhGetWindowDpi(windowHandle);\n\n    return PhAddIListViewColumnDpi(\n        ListView,\n        dpiValue,\n        Index,\n        DisplayIndex,\n        SubItemIndex,\n        Format,\n        Width,\n        Text\n        );\n}\n\nLONG PhAddListViewItem(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_TEXT | LVIF_PARAM;\n    item.iItem = Index;\n    item.iSubItem = 0;\n    item.pszText = const_cast<PWSTR>(Text);\n    item.lParam = reinterpret_cast<LPARAM>(Param);\n\n    return ListView_InsertItem(ListViewHandle, &item);\n}\n\nLONG PhAddIListViewItem(\n    _In_ IListView* ListView,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    )\n{\n    LVITEM item;\n    LONG index;\n\n    item.mask = LVIF_TEXT | LVIF_PARAM;\n    item.iItem = Index;\n    item.iSubItem = 0;\n    item.pszText = const_cast<PWSTR>(Text);\n    item.lParam = reinterpret_cast<LPARAM>(Param);\n\n    if (SUCCEEDED(ListView->InsertItem(&item, &index)))\n        return index;\n\n    return INT_ERROR;\n}\n\nLONG PhFindListViewItemByFlags(\n    _In_ HWND ListViewHandle,\n    _In_ LONG StartIndex,\n    _In_ ULONG Flags\n    )\n{\n    return ListView_GetNextItem(ListViewHandle, StartIndex, Flags);\n}\n\nLONG PhFindIListViewItemByFlags(\n    _In_ IListView* ListView,\n    _In_ LONG StartIndex,\n    _In_ ULONG Flags\n    )\n{\n    LVITEMINDEX itemIndex;\n    LVITEMINDEX nextItemIndex;\n\n    itemIndex.iItem = StartIndex;\n    itemIndex.iGroup = INT_ERROR;\n\n    if (SUCCEEDED(ListView->GetNextItem(itemIndex, Flags, &nextItemIndex)))\n        return nextItemIndex.iItem;\n\n    return INT_ERROR;\n}\n\nLONG PhFindListViewItemByParam(\n    _In_ HWND ListViewHandle,\n    _In_ LONG StartIndex,\n    _In_opt_ PVOID Param\n    )\n{\n    LVFINDINFO findInfo;\n\n    findInfo.flags = LVFI_PARAM;\n    findInfo.lParam = reinterpret_cast<LPARAM>(Param);\n\n    return ListView_FindItem(ListViewHandle, StartIndex, &findInfo);\n}\n\nLONG PhFindIListViewItemByParam(\n    _In_ IListView* ListView,\n    _In_ LONG StartIndex,\n    _In_opt_ PVOID Param\n    )\n{\n    LVITEMINDEX itemIndex;\n    LVITEMINDEX foundIndex;\n    LVFINDINFO findInfo;\n\n    itemIndex.iItem = StartIndex;\n    itemIndex.iGroup = INT_ERROR;\n\n    findInfo.flags = LVFI_PARAM;\n    findInfo.lParam = reinterpret_cast<LPARAM>(Param);\n\n    if (SUCCEEDED(ListView->FindItem(itemIndex, &findInfo, &foundIndex)))\n    {\n#if DEBUG\n        HWND windowHandle = nullptr;\n        ListView->GetHeaderControl(&windowHandle);\n        windowHandle = GetParent(windowHandle);\n        LONG index = PhFindListViewItemByParam(windowHandle, StartIndex, Param);\n        assert(index == foundIndex.iItem); // Items changed during enumeration. (dmex)\n#endif\n\n        return foundIndex.iItem;\n    }\n\n    return INT_ERROR;\n}\n\n_Success_(return)\nBOOLEAN PhGetListViewItemImageIndex(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _Out_ PLONG ImageIndex\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_IMAGE;\n    item.iItem = Index;\n    item.iSubItem = 0;\n\n    if (!ListView_GetItem(ListViewHandle, &item))\n        return FALSE;\n\n    *ImageIndex = item.iImage;\n\n    return TRUE;\n}\n\n_Success_(return)\nBOOLEAN PhGetIListViewItemImageIndex(\n    _In_ IListView* ListView,\n    _In_ LONG Index,\n    _Out_ PLONG ImageIndex\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_IMAGE;\n    item.iItem = Index;\n    item.iSubItem = 0;\n\n    if (!SUCCEEDED(ListView->GetItem(&item)))\n        return FALSE;\n\n    *ImageIndex = item.iImage;\n\n    return TRUE;\n}\n\n_Success_(return)\nBOOLEAN PhGetListViewItemParam(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _Outptr_ PVOID* Param\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_PARAM;\n    item.iItem = Index;\n    item.iSubItem = 0;\n\n    if (!ListView_GetItem(ListViewHandle, &item))\n        return FALSE;\n\n    *Param = reinterpret_cast<PVOID>(item.lParam);\n\n    return TRUE;\n}\n\n_Success_(return)\nBOOLEAN PhGetIListViewItemParam(\n    _In_ IListView* ListView,\n    _In_ LONG Index,\n    _Outptr_ PVOID* Param\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_PARAM;\n    item.iItem = Index;\n    item.iSubItem = 0;\n\n    if (!SUCCEEDED(ListView->GetItem(&item)))\n        return FALSE;\n\n    *Param = reinterpret_cast<PVOID>(item.lParam);\n\n    return TRUE;\n}\n\nBOOLEAN PhSetListViewItemParam(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ PVOID Param\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_PARAM;\n    item.iItem = Index;\n    item.lParam = reinterpret_cast<LPARAM>(Param);\n\n    return !!ListView_SetItem(ListViewHandle, &item);\n}\n\nBOOLEAN PhSetIListViewItemParam(\n    _In_ IListView* ListView,\n    _In_ LONG Index,\n    _In_ PVOID Param\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_PARAM;\n    item.iItem = Index;\n    item.lParam = reinterpret_cast<LPARAM>(Param);\n\n    return SUCCEEDED(ListView->SetItem(&item));\n}\n\nVOID PhRemoveListViewItem(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index\n    )\n{\n    ListView_DeleteItem(ListViewHandle, Index);\n}\n\nVOID PhRemoveIListViewItem(\n    _In_ IListView* ListView,\n    _In_ LONG Index\n    )\n{\n    ListView->DeleteItem(Index);\n}\n\nVOID PhSetListViewItemImageIndex(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG ImageIndex\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_IMAGE;\n    item.iItem = Index;\n    item.iSubItem = 0;\n    item.iImage = ImageIndex;\n\n    ListView_SetItem(ListViewHandle, &item);\n}\n\nVOID PhSetIListViewItemImageIndex(\n    _In_ IListView* ListView,\n    _In_ LONG Index,\n    _In_ LONG ImageIndex\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_IMAGE;\n    item.iItem = Index;\n    item.iSubItem = 0;\n    item.iImage = ImageIndex;\n\n    ListView->SetItem(&item);\n}\n\nVOID PhSetListViewSubItem(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex,\n    _In_ PCWSTR Text\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_TEXT;\n    item.iItem = Index;\n    item.iSubItem = SubItemIndex;\n    item.pszText = const_cast<PWSTR>(Text);\n\n    ListView_SetItem(ListViewHandle, &item);\n}\n\nVOID PhSetIListViewSubItem(\n    _In_ IListView* ListView,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex,\n    _In_ PCWSTR Text\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_TEXT;\n    item.iItem = Index;\n    item.iSubItem = SubItemIndex;\n    item.pszText = const_cast<PWSTR>(Text);\n\n    ListView->SetItem(&item);\n}\n\nVOID PhRedrawListViewItems(\n    _In_ HWND ListViewHandle\n    )\n{\n    ListView_RedrawItems(ListViewHandle, 0, INT_MAX);\n    // Note: UpdateWindow() is a workaround for ListView_RedrawItems() failing to send LVN_GETDISPINFO\n    // and fixes RedrawItems() graphical artifacts when the listview doesn't have foreground focus. (dmex)\n    UpdateWindow(ListViewHandle);\n}\n\nVOID PhRedrawIListViewItems(\n    _In_ IListView* ListView,\n    _In_ HWND ListViewHandle\n    )\n{\n    ListView->RedrawItems(0, INT_MAX);\n    // Note: UpdateWindow() is a workaround for ListView_RedrawItems() failing to send LVN_GETDISPINFO\n    // and fixes RedrawItems() graphical artifacts when the listview doesn't have foreground focus. (dmex)\n    UpdateWindow(ListViewHandle);\n}\n\nLONG PhAddListViewGroup(\n    _In_ HWND ListViewHandle,\n    _In_ LONG GroupId,\n    _In_ PCWSTR Text\n    )\n{\n    LVGROUP group;\n\n    memset(&group, 0, sizeof(LVGROUP));\n    group.cbSize = sizeof(LVGROUP);\n    group.mask = LVGF_HEADER | LVGF_ALIGN | LVGF_STATE | LVGF_GROUPID;\n    group.uAlign = LVGA_HEADER_LEFT;\n    group.state = LVGS_COLLAPSIBLE;\n    group.iGroupId = GroupId;\n    group.pszHeader = const_cast<PWSTR>(Text);\n\n    return static_cast<LONG>(ListView_InsertGroup(ListViewHandle, MAXUINT, &group));\n}\n\nLONG PhAddIListViewGroup(\n    _In_ IListView* ListView,\n    _In_ LONG GroupId,\n    _In_ PCWSTR Text\n    )\n{\n    LVGROUP group;\n    LONG index = 0;\n\n    memset(&group, 0, sizeof(LVGROUP));\n    group.cbSize = sizeof(LVGROUP);\n    group.mask = LVGF_HEADER | LVGF_ALIGN | LVGF_STATE | LVGF_GROUPID;\n    group.uAlign = LVGA_HEADER_LEFT;\n    group.state = LVGS_COLLAPSIBLE;\n    group.iGroupId = GroupId;\n    group.pszHeader = const_cast<PWSTR>(Text);\n\n    if (SUCCEEDED(ListView->InsertGroup(MAXUINT, &group, &index)))\n        return index;\n\n    return INT_ERROR;\n}\n\nLONG PhAddListViewGroupItem(\n    _In_ HWND ListViewHandle,\n    _In_ LONG GroupId,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_TEXT | LVIF_GROUPID;\n    item.iItem = Index;\n    item.iSubItem = 0;\n    item.pszText = const_cast<PWSTR>(Text);\n    item.iGroupId = GroupId;\n\n    if (Param)\n    {\n        item.mask |= LVIF_PARAM;\n        item.lParam = reinterpret_cast<LPARAM>(Param);\n    }\n\n    return ListView_InsertItem(ListViewHandle, &item);\n}\n\nLONG PhAddIListViewGroupItem(\n    _In_ IListView* ListView,\n    _In_ LONG GroupId,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    )\n{\n    LVITEM item;\n    LONG index;\n\n    item.mask = LVIF_TEXT | LVIF_GROUPID;\n    item.iItem = Index;\n    item.iSubItem = 0;\n    item.pszText = const_cast<PWSTR>(Text);\n    item.iGroupId = GroupId;\n\n    if (Param)\n    {\n        item.mask |= LVIF_PARAM;\n        item.lParam = reinterpret_cast<LPARAM>(Param);\n    }\n\n    if (SUCCEEDED(ListView->InsertItem(&item, &index)))\n        return index;\n\n    return INT_ERROR;\n}\n\nVOID PhSetStateAllListViewItems(\n    _In_ HWND WindowHandle,\n    _In_ ULONG State,\n    _In_ ULONG Mask\n    )\n{\n    LONG i;\n    LONG count;\n\n    count = ListView_GetItemCount(WindowHandle);\n\n    if (count <= 0)\n        return;\n\n    for (i = 0; i < count; i++)\n    {\n        ListView_SetItemState(WindowHandle, i, State, Mask);\n    }\n}\n\nPVOID PhGetSelectedListViewItemParam(\n    _In_ HWND WindowHandle\n    )\n{\n    LONG index;\n    PVOID param;\n\n    index = PhFindListViewItemByFlags(\n        WindowHandle,\n        INT_ERROR,\n        LVNI_SELECTED\n        );\n\n    if (index != INT_ERROR)\n    {\n        if (PhGetListViewItemParam(\n            WindowHandle,\n            index,\n            &param\n            ))\n        {\n            return param;\n        }\n    }\n\n    return nullptr;\n}\n\nVOID PhGetSelectedListViewItemParams(\n    _In_ HWND WindowHandle,\n    _Out_ PVOID **Items,\n    _Out_ PULONG NumberOfItems\n    )\n{\n    PH_ARRAY array;\n    LONG index;\n    PVOID param;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n    index = INT_ERROR;\n\n    while ((index = PhFindListViewItemByFlags(\n        WindowHandle,\n        index,\n        LVNI_SELECTED\n        )) != INT_ERROR)\n    {\n        if (PhGetListViewItemParam(WindowHandle, index, &param))\n            PhAddItemArray(&array, &param);\n    }\n\n    *NumberOfItems = static_cast<ULONG>(PhFinalArrayCount(&array));\n    *Items = static_cast<PVOID*>(PhFinalArrayItems(&array));\n}\n\nVOID PhGetSelectedIListViewItemParams(\n    _In_ IListView* ListView,\n    _Out_ PVOID **Items,\n    _Out_ PULONG NumberOfItems\n    )\n{\n    PH_ARRAY array;\n    LONG index;\n    PVOID param;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n    index = INT_ERROR;\n\n    while ((index = PhFindIListViewItemByFlags(\n        ListView,\n        index,\n        LVNI_SELECTED\n        )) != INT_ERROR)\n    {\n        if (PhGetIListViewItemParam(ListView, index, &param))\n            PhAddItemArray(&array, &param);\n    }\n\n    *NumberOfItems = static_cast<ULONG>(PhFinalArrayCount(&array));\n    *Items = static_cast<PVOID*>(PhFinalArrayItems(&array));\n}\n\nBOOLEAN PhGetIListViewClientRect(\n    _In_ IListView* ListView,\n    _Inout_ PRECT ClientRect\n    )\n{\n    return SUCCEEDED(ListView->GetClientRect(FALSE, ClientRect));\n}\n\nBOOLEAN PhGetIListViewItemRect(\n    _In_ IListView* ListView,\n    _In_ LONG StartIndex,\n    _In_ ULONG Flags, // LVIR_SELECTBOUNDS | LVIR_BOUNDS\n    _Inout_ PRECT ItemRect\n    )\n{\n    LVITEMINDEX itemIndex;\n\n    itemIndex.iItem = StartIndex;\n    itemIndex.iGroup = -1;\n\n    return SUCCEEDED(ListView->GetItemRect(itemIndex, Flags, ItemRect));\n}\n\nPPH_LISTVIEW_CONTEXT PhListView_Initialize(\n    _In_ HWND ListViewHandle\n    )\n{\n    PPH_LISTVIEW_CONTEXT context;\n    IListView* listviewInterface;\n\n    context = (PPH_LISTVIEW_CONTEXT)PhAllocateZero(sizeof(PH_LISTVIEW_CONTEXT));\n    context->ListViewHandle = ListViewHandle;\n    context->ThreadId = UlongToHandle(GetWindowThreadProcessId(ListViewHandle, nullptr));\n\n    if (listviewInterface = PhGetListViewInterface(ListViewHandle))\n    {\n        context->ListViewInterface = listviewInterface;\n    }\n\n    return context;\n}\n\nVOID PhListView_Destroy(\n    _In_ PPH_LISTVIEW_CONTEXT Context\n    )\n{\n    if (Context->ListViewInterface)\n    {\n        Context->ListViewInterface->Release();\n        Context->ListViewInterface = NULL;\n    }\n\n    PhFree(Context);\n}\n\n_Use_decl_annotations_\nBOOLEAN PhListView_GetItemCount(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ PLONG ItemCount\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->GetItemCount(ItemCount)))\n        {\n            return TRUE;\n        }\n    }\n    else\n    {\n        LONG count = ListView_GetItemCount(Context->ListViewHandle);\n\n        if (count != INT_ERROR)\n        {\n            *ItemCount = count;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_SetItemCount(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemCount,\n    _In_ ULONG Flags\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->SetItemCount(ItemCount, Flags)))\n        {\n            return TRUE;\n        }\n    }\n    else\n    {\n        if (ListView_SetItemCountEx(Context->ListViewHandle, ItemCount, Flags))\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_GetItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Inout_ LVITEM* Item\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->GetItem(Item)))\n            return TRUE;\n    }\n    else\n    {\n        if (ListView_GetItem(Context->ListViewHandle, Item))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_SetItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LVITEM* Item\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->SetItem(Item)))\n            return TRUE;\n    }\n    else\n    {\n        if (ListView_SetItem(Context->ListViewHandle, Item))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Use_decl_annotations_\nBOOLEAN PhListView_GetItemText(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ LONG SubItemIndex,\n    _Out_writes_(BufferSize) PWSTR Buffer,\n    _In_ LONG BufferSize\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->GetItemText(\n            ItemIndex,\n            SubItemIndex,\n            Buffer,\n            BufferSize\n            )))\n        {\n            return TRUE;\n        }\n    }\n    else\n    {\n        LVITEM item;\n\n        ZeroMemory(&item, sizeof(LVITEM));\n        item.iSubItem = SubItemIndex;\n        item.cchTextMax = BufferSize;\n        item.pszText = Buffer;\n\n        if (SendMessage(Context->ListViewHandle, LVM_GETITEMTEXTW, ItemIndex, (LPARAM)&item))\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_SetItemText(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ LONG SubItemIndex,\n    _In_ PWSTR Text\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->SetItemText(ItemIndex, SubItemIndex, Text)))\n        {\n            return TRUE;\n        }\n    }\n    else\n    {\n        LVITEM item;\n\n        ZeroMemory(&item, sizeof(LVITEM));\n        item.iSubItem = SubItemIndex;\n        item.pszText = Text;\n\n        if (SendMessage(Context->ListViewHandle, LVM_SETITEMTEXTW, ItemIndex, (LPARAM)&item))\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_DeleteItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->DeleteItem(ItemIndex)))\n        {\n            return TRUE;\n        }\n    }\n    else\n    {\n        if (ListView_DeleteItem(Context->ListViewHandle, ItemIndex))\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_DeleteAllItems(\n    _In_ PPH_LISTVIEW_CONTEXT Context\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->DeleteAllItems()))\n            return TRUE;\n    }\n    else\n    {\n        if (ListView_DeleteAllItems(Context->ListViewHandle))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Use_decl_annotations_\nBOOLEAN PhListView_InsertItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LVITEMW* Item,\n    _Out_opt_ PLONG ItemIndex\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->InsertItem(Item, ItemIndex)))\n            return TRUE;\n    }\n    else\n    {\n        LONG index = ListView_InsertItem(Context->ListViewHandle, Item);\n\n        if (index != INT_ERROR)\n        {\n            if (ItemIndex)\n            {\n                *ItemIndex = index;\n            }\n\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n_Use_decl_annotations_\nBOOLEAN PhListView_InsertGroup(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG InsertAt,\n    _In_ LVGROUP* Group,\n    _Out_opt_ PLONG GroupId\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->InsertGroup(InsertAt, Group, GroupId)))\n            return TRUE;\n    }\n    else\n    {\n        LONG index = (LONG)ListView_InsertGroup(Context->ListViewHandle, InsertAt, Group);\n\n        if (index != INT_ERROR)\n        {\n            if (GroupId)\n            {\n                *GroupId = index;\n            }\n\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n_Use_decl_annotations_\nBOOLEAN PhListView_GetItemState(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ ULONG Mask,\n    _Out_ PULONG State\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        ULONG state = 0;\n\n        if (HR_SUCCESS(Context->ListViewInterface->GetItemState(ItemIndex, 0, Mask, &state)))\n        {\n            *State = state;\n            return TRUE;\n        }\n    }\n    else\n    {\n        *State = ListView_GetItemState(Context->ListViewHandle, ItemIndex, Mask);\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_SetItemState(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ ULONG State,\n    _In_ ULONG Mask\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->SetItemState(ItemIndex, 0, State, Mask)))\n            return TRUE;\n    }\n    else\n    {\n        LVITEM item;\n\n        ZeroMemory(&item, sizeof(LVITEM));\n        item.state = State;\n        item.stateMask = Mask;\n        item.mask = LVIF_STATE;\n        item.iItem = ItemIndex;\n\n        if (SendMessage(Context->ListViewHandle, LVM_SETITEMSTATE, ItemIndex, (LPARAM)&item))\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_SortItems(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ BOOL SortingByIndex,\n    _In_ PFNLVCOMPARE Compare,\n    _In_ PVOID CompareContext\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->SortItems(\n            SortingByIndex,\n            (LPARAM)CompareContext,\n            Compare\n            )))\n        {\n            return TRUE;\n        }\n    }\n    else\n    {\n        if (SortingByIndex)\n        {\n            if (ListView_SortItemsEx(\n                Context->ListViewHandle,\n                Compare,\n                CompareContext\n                ))\n            {\n                return TRUE;\n            }\n        }\n        else\n        {\n            if (ListView_SortItems(\n                Context->ListViewHandle,\n                Compare,\n                CompareContext\n                ))\n            {\n                return TRUE;\n            }\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_GetColumn(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ ULONG ColumnIndex,\n    _Inout_ LV_COLUMN* Column\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->GetColumn(ColumnIndex, Column)))\n            return TRUE;\n    }\n    else\n    {\n        if (ListView_GetColumn(Context->ListViewHandle, ColumnIndex, Column))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_SetColumn(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ ULONG ColumnIndex,\n    _In_ LV_COLUMN* Column\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->SetColumn(ColumnIndex, Column)))\n            return TRUE;\n    }\n    else\n    {\n        if (ListView_SetColumn(Context->ListViewHandle, ColumnIndex, Column))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_SetColumnWidth(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ ULONG ColumnIndex,\n    _In_ ULONG Width\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        if (HR_SUCCESS(Context->ListViewInterface->SetColumnWidth(ColumnIndex, Width)))\n            return TRUE;\n    }\n    else\n    {\n        if (ListView_SetColumnWidth(Context->ListViewHandle, ColumnIndex, Width))\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_GetHeader(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ HWND* WindowHandle\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        HWND headerWindowHandle = nullptr;\n\n        if (HR_SUCCESS(Context->ListViewInterface->GetHeaderControl(&headerWindowHandle)))\n        {\n            *WindowHandle = headerWindowHandle;\n            return TRUE;\n        }\n    }\n    else\n    {\n        HWND headerWindowHandle;\n\n        if (headerWindowHandle = ListView_GetHeader(Context->ListViewHandle))\n        {\n            *WindowHandle = headerWindowHandle;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhListView_GetToolTip(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ HWND* WindowHandle\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        HWND tooltipWindowHandle = nullptr;\n\n        if (HR_SUCCESS(Context->ListViewInterface->GetToolTip(&tooltipWindowHandle)))\n        {\n            *WindowHandle = tooltipWindowHandle;\n            return TRUE;\n        }\n    }\n    else\n    {\n        HWND tooltipWindowHandle;\n\n        if (tooltipWindowHandle = ListView_GetToolTips(Context->ListViewHandle))\n        {\n            *WindowHandle = tooltipWindowHandle;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nLONG PhListView_AddColumn(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ LONG DisplayIndex,\n    _In_ LONG SubItemIndex,\n    _In_ LONG Format,\n    _In_ LONG Width,\n    _In_ PCWSTR Text\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return PhAddIListViewColumn(Context->ListViewInterface, Index, DisplayIndex, SubItemIndex, Format, Width, Text);\n    }\n    else\n    {\n        return PhAddListViewColumn(Context->ListViewHandle, Index, DisplayIndex, SubItemIndex, Format, Width, Text);\n    }\n}\n\nLONG PhListView_AddItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return PhAddIListViewItem(Context->ListViewInterface, Index, Text, Param);\n    }\n    else\n    {\n        return PhAddListViewItem(Context->ListViewHandle, Index, Text, Param);\n    }\n}\n\nLONG PhListView_FindItemByFlags(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG StartIndex,\n    _In_ ULONG Flags\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return PhFindIListViewItemByFlags(Context->ListViewInterface, StartIndex, Flags);\n    }\n    else\n    {\n        return PhFindListViewItemByFlags(Context->ListViewHandle, StartIndex, Flags);\n    }\n}\n\nLONG PhListView_FindItemByParam(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG StartIndex,\n    _In_opt_ PVOID Param\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return PhFindIListViewItemByParam(Context->ListViewInterface, StartIndex, Param);\n    }\n    else\n    {\n        return PhFindListViewItemByParam(Context->ListViewHandle, StartIndex, Param);\n    }\n}\n\n_Success_(return)\nBOOLEAN PhListView_GetItemParam(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG Index,\n    _Outptr_ PVOID* Param\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return PhGetIListViewItemParam(Context->ListViewInterface, Index, Param);\n    }\n    else\n    {\n        return PhGetListViewItemParam(Context->ListViewHandle, Index, Param);\n    }\n}\n\nVOID PhListView_SetSubItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex,\n    _In_ PCWSTR Text\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        PhSetIListViewSubItem(Context->ListViewInterface, Index, SubItemIndex, Text);\n    }\n    else\n    {\n        PhSetListViewSubItem(Context->ListViewHandle, Index, SubItemIndex, Text);\n    }\n}\n\nVOID PhListView_RedrawItems(\n    _In_ PPH_LISTVIEW_CONTEXT Context\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        PhRedrawIListViewItems(Context->ListViewInterface, Context->ListViewHandle);\n    }\n    else\n    {\n        PhRedrawListViewItems(Context->ListViewHandle);\n    }\n}\n\nLONG PhListView_AddGroup(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG GroupId,\n    _In_ PCWSTR Text\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return PhAddIListViewGroup(Context->ListViewInterface, GroupId, Text);\n    }\n    else\n    {\n        return PhAddListViewGroup(Context->ListViewHandle, GroupId, Text);\n    }\n}\n\nLONG PhListView_AddGroupItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG GroupId,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return PhAddIListViewGroupItem(Context->ListViewInterface, GroupId, Index, Text, Param);\n    }\n    else\n    {\n        return PhAddListViewGroupItem(Context->ListViewHandle, GroupId, Index, Text, Param);\n    }\n}\n\nVOID PhListView_SetStateAllItems(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ ULONG State,\n    _In_ ULONG Mask\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        LONG i;\n        LONG count;\n\n        if (HR_SUCCESS(Context->ListViewInterface->GetItemCount(&count)))\n        {\n            for (i = 0; i < count; i++)\n            {\n                Context->ListViewInterface->SetItemState(i, 0, Mask, State);\n            }\n        }\n    }\n    else\n    {\n        PhSetStateAllListViewItems(Context->ListViewHandle, State, Mask);\n    }\n}\n\nPVOID PhListView_GetSelectedItemParam(\n    _In_ PPH_LISTVIEW_CONTEXT Context\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        LONG index;\n        PVOID param;\n\n        index = PhFindIListViewItemByFlags(\n            Context->ListViewInterface,\n            INT_ERROR,\n            LVNI_SELECTED\n            );\n\n        if (index != INT_ERROR)\n        {\n            if (PhGetIListViewItemParam(Context->ListViewInterface, index, &param))\n                return param;\n        }\n\n        return nullptr;\n    }\n    else\n    {\n        return PhGetSelectedListViewItemParam(Context->ListViewHandle);\n    }\n}\n\n_Success_(return)\nBOOLEAN PhListView_GetSelectedCount(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ PLONG SelectedCount\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return HR_SUCCESS(Context->ListViewInterface->GetSelectedCount(SelectedCount));\n    }\n    else\n    {\n        LONG count = ListView_GetSelectedCount(Context->ListViewHandle);\n        \n        if (count != INT_ERROR)\n        {\n            *SelectedCount = count;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nVOID PhListView_GetSelectedItemParams(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ PVOID** Items,\n    _Out_ PULONG NumberOfItems\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        PhGetSelectedIListViewItemParams(Context->ListViewInterface, Items, NumberOfItems);\n    }\n    else\n    {\n        PhGetSelectedListViewItemParams(Context->ListViewHandle, Items, NumberOfItems);\n    }\n}\n\nBOOLEAN PhListView_GetClientRect(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Inout_ PRECT ClientRect\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return PhGetIListViewClientRect(Context->ListViewInterface, ClientRect);\n    }\n    else\n    {\n        return !!GetClientRect(Context->ListViewHandle, ClientRect);\n    }\n}\n\nBOOLEAN PhListView_GetItemRect(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG StartIndex,\n    _In_ ULONG Flags,\n    _Inout_ PRECT ItemRect\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return PhGetIListViewItemRect(Context->ListViewInterface, StartIndex, Flags, ItemRect);\n    }\n    else\n    {\n        return !!ListView_GetItemRect(Context->ListViewHandle, StartIndex, ItemRect, Flags);\n    }\n}\n \nBOOLEAN PhListView_EnableGroupView(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ BOOLEAN Enable\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return HR_SUCCESS(Context->ListViewInterface->EnableGroupView(Enable));\n    }\n    else\n    {\n        return !!ListView_EnableGroupView(Context->ListViewHandle, Enable);\n    }\n}\n\nBOOLEAN PhListView_EnsureItemVisible(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ BOOLEAN PartialOk\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        LVITEMINDEX itemIndex;\n        \n        itemIndex.iItem = ItemIndex;\n        itemIndex.iGroup = INT_ERROR;\n        \n        return SUCCEEDED(Context->ListViewInterface->EnsureItemVisible(itemIndex, PartialOk));\n    }\n    else\n    {\n        return !!ListView_EnsureVisible(Context->ListViewHandle, ItemIndex, PartialOk);\n    }\n}\n\nBOOLEAN PhListView_IsItemVisible(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _Out_ PBOOLEAN Visible\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        LVITEMINDEX itemIndex;\n        BOOL visible;\n        \n        itemIndex.iItem = ItemIndex;\n        itemIndex.iGroup = INT_ERROR;\n        \n        if (SUCCEEDED(Context->ListViewInterface->IsItemVisible(itemIndex, &visible)))\n        {\n            *Visible = !!visible;\n            return TRUE;\n        }\n        \n        return FALSE;\n    }\n    else\n    {\n        RECT itemRect;\n        RECT clientRect;\n        \n        if (!ListView_GetItemRect(Context->ListViewHandle, ItemIndex, &itemRect, LVIR_BOUNDS))\n            return FALSE;\n        \n        if (!GetClientRect(Context->ListViewHandle, &clientRect))\n            return FALSE;\n        \n        // Check if the item rectangle intersects with the client area\n        *Visible = (itemRect.top < clientRect.bottom && itemRect.bottom > clientRect.top);\n        return TRUE;\n    }\n}\n\nBOOLEAN PhListView_HitTestSubItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Inout_ LVHITTESTINFO* HitTestInfo\n    )\n{\n    if (Context->ListViewInterface && NtCurrentThreadId() == Context->ThreadId)\n    {\n        return HR_SUCCESS(Context->ListViewInterface->HitTestSubItem(HitTestInfo));\n    }\n    else\n    {\n        return ListView_SubItemHitTest(Context->ListViewHandle, HitTestInfo) != INT_ERROR;\n    }\n}\n"
  },
  {
    "path": "phlib/handle.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *\n */\n\n#include <phbase.h>\n#include <handle.h>\n#include <handlep.h>\n\nstatic PH_INITONCE PhHandleTableInitOnce = PH_INITONCE_INIT;\nstatic PH_FREE_LIST PhHandleTableLevel0FreeList;\nstatic PH_FREE_LIST PhHandleTableLevel1FreeList;\n\nPPH_HANDLE_TABLE PhCreateHandleTable(\n    VOID\n    )\n{\n    PPH_HANDLE_TABLE handleTable;\n    ULONG i;\n\n    if (PhBeginInitOnce(&PhHandleTableInitOnce))\n    {\n        PhInitializeFreeList(\n            &PhHandleTableLevel0FreeList,\n            sizeof(PH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES,\n            64\n            );\n        PhInitializeFreeList(\n            &PhHandleTableLevel1FreeList,\n            sizeof(PPH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES,\n            64\n            );\n        PhEndInitOnce(&PhHandleTableInitOnce);\n    }\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    handleTable = PhAllocateSafe(sizeof(PH_HANDLE_TABLE));\n\n    if (!handleTable)\n        return NULL;\n#else\n    handleTable = PhAllocate(sizeof(PH_HANDLE_TABLE));\n#endif\n\n    PhInitializeQueuedLock(&handleTable->Lock);\n    PhInitializeWakeEvent(&handleTable->HandleWakeEvent);\n\n    handleTable->NextValue = 0;\n\n    handleTable->Count = 0;\n    handleTable->TableValue = (ULONG_PTR)PhpCreateHandleTableLevel0(handleTable, TRUE);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    if (!handleTable->TableValue)\n    {\n        PhFree(handleTable);\n        return NULL;\n    }\n#endif\n\n    // We have now created the level 0 table. The free list can now be set up to point to handle 0,\n    // which points to the rest of the free list (1 -> 2 -> 3 -> ...). The next batch of handles\n    // that need to be created start at PH_HANDLE_TABLE_LEVEL_ENTRIES.\n\n    handleTable->FreeValue = 0;\n    handleTable->NextValue = PH_HANDLE_TABLE_LEVEL_ENTRIES;\n\n    handleTable->FreeValueAlt = PH_HANDLE_VALUE_INVALID; // no entries in alt. free list\n\n    handleTable->Flags = 0;\n\n    for (i = 0; i < PH_HANDLE_TABLE_LOCKS; i++)\n        PhInitializeQueuedLock(&handleTable->Locks[i]);\n\n    return handleTable;\n}\n\nVOID PhDestroyHandleTable(\n    _In_ _Post_invalid_ PPH_HANDLE_TABLE HandleTable\n    )\n{\n    ULONG_PTR tableValue;\n    ULONG tableLevel;\n    PPH_HANDLE_TABLE_ENTRY table0;\n    PPH_HANDLE_TABLE_ENTRY *table1;\n    PPH_HANDLE_TABLE_ENTRY **table2;\n    ULONG i;\n    ULONG j;\n\n    tableValue = HandleTable->TableValue;\n    tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK;\n    tableValue -= tableLevel;\n\n    switch (tableLevel)\n    {\n    case 0:\n        {\n            table0 = (PPH_HANDLE_TABLE_ENTRY)tableValue;\n\n            PhpFreeHandleTableLevel0(table0);\n        }\n        break;\n    case 1:\n        {\n            table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue;\n\n            for (i = 0; i < PH_HANDLE_TABLE_LEVEL_ENTRIES; i++)\n            {\n                if (!table1[i])\n                    break;\n\n                PhpFreeHandleTableLevel0(table1[i]);\n            }\n\n            PhpFreeHandleTableLevel1(table1);\n        }\n        break;\n    case 2:\n        {\n            table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue;\n\n            for (i = 0; i < PH_HANDLE_TABLE_LEVEL_ENTRIES; i++)\n            {\n                if (!table2[i])\n                    break;\n\n                for (j = 0; j < PH_HANDLE_TABLE_LEVEL_ENTRIES; j++)\n                {\n                    if (!table2[i][j])\n                        break;\n\n                    PhpFreeHandleTableLevel0(table2[i][j]);\n                }\n\n                PhpFreeHandleTableLevel1(table2[i]);\n            }\n\n            PhpFreeHandleTableLevel2(table2);\n        }\n        break;\n    default:\n        ASSUME_NO_DEFAULT;\n    }\n\n    PhFree(HandleTable);\n}\n\nVOID PhpBlockOnLockedHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n    ULONG_PTR value;\n\n    PhQueueWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock);\n\n    value = HandleTableEntry->Value;\n\n    if (\n        (value & PH_HANDLE_TABLE_ENTRY_TYPE) != PH_HANDLE_TABLE_ENTRY_IN_USE ||\n        (value & PH_HANDLE_TABLE_ENTRY_LOCKED)\n        )\n    {\n        // Entry is not in use or has been unlocked; cancel the wait.\n        PhSetWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock);\n    }\n    else\n    {\n        PhWaitForWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock, TRUE, NULL);\n    }\n}\n\nBOOLEAN PhLockHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    ULONG_PTR value;\n\n    while (TRUE)\n    {\n        value = HandleTableEntry->Value;\n\n        if ((value & PH_HANDLE_TABLE_ENTRY_TYPE) != PH_HANDLE_TABLE_ENTRY_IN_USE)\n            return FALSE;\n\n        if (value & PH_HANDLE_TABLE_ENTRY_LOCKED)\n        {\n            if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&HandleTableEntry->Value,\n                (PVOID)(value - PH_HANDLE_TABLE_ENTRY_LOCKED),\n                (PVOID)value\n                ) == value)\n            {\n                return TRUE;\n            }\n        }\n\n        PhpBlockOnLockedHandleTableEntry(HandleTable, HandleTableEntry);\n    }\n}\n\nVOID PhUnlockHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    _interlockedbittestandset(\n        (PLONG)&HandleTableEntry->Value,\n        PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT\n        );\n    PhSetWakeEvent(&HandleTable->HandleWakeEvent, NULL);\n}\n\nHANDLE PhCreateHandle(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY entry;\n    ULONG handleValue;\n\n    entry = PhpAllocateHandleTableEntry(HandleTable, &handleValue);\n\n    if (!entry)\n        return NULL;\n\n    // Copy the given handle table entry to the allocated entry.\n\n    // All free entries have the Free type and have the (not) locked bit clear. There is no problem\n    // with setting the Type now; the entry is still locked, so they will block.\n    entry->TypeAndValue.Type = PH_HANDLE_TABLE_ENTRY_IN_USE;\n    entry->TypeAndValue.Value = HandleTableEntry->TypeAndValue.Value;\n    entry->Value2 = HandleTableEntry->Value2;\n\n    // Now we unlock this entry, waking anyone who was caught back there before we had finished\n    // setting up the entry.\n    PhUnlockHandleTableEntry(HandleTable, entry);\n\n    return PhpEncodeHandle(handleValue);\n}\n\nBOOLEAN PhDestroyHandle(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle,\n    _In_opt_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    ULONG handleValue;\n\n    handleValue = PhpDecodeHandle(Handle);\n\n    if (!HandleTableEntry)\n    {\n        HandleTableEntry = PhpLookupHandleTableEntry(HandleTable, handleValue);\n\n        if (!HandleTableEntry)\n            return FALSE;\n\n        if (!PhLockHandleTableEntry(HandleTable, HandleTableEntry))\n            return FALSE;\n    }\n\n    _InterlockedExchangePointer(\n        (PVOID *)&HandleTableEntry->Value,\n        (PVOID)PH_HANDLE_TABLE_ENTRY_FREE\n        );\n\n    // The handle table entry is now free; wake any waiters because they can't lock the entry now.\n    // Any future lock attempts will fail because the entry is marked as being free.\n    PhSetWakeEvent(&HandleTable->HandleWakeEvent, NULL);\n\n    PhpFreeHandleTableEntry(HandleTable, handleValue, HandleTableEntry);\n\n    return TRUE;\n}\n\nPPH_HANDLE_TABLE_ENTRY PhLookupHandleTableEntry(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY entry;\n\n    entry = PhpLookupHandleTableEntry(HandleTable, PhpDecodeHandle(Handle));\n\n    if (!entry)\n        return NULL;\n\n    if (!PhLockHandleTableEntry(HandleTable, entry))\n        return NULL;\n\n    return entry;\n}\n\nVOID PhEnumHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG handleValue;\n    PPH_HANDLE_TABLE_ENTRY entry;\n    BOOLEAN cont;\n\n    handleValue = 0;\n\n    while (entry = PhpLookupHandleTableEntry(HandleTable, handleValue))\n    {\n        if (PhLockHandleTableEntry(HandleTable, entry))\n        {\n            cont = Callback(\n                HandleTable,\n                PhpEncodeHandle(handleValue),\n                entry,\n                Context\n                );\n            PhUnlockHandleTableEntry(HandleTable, entry);\n\n            if (!cont)\n                break;\n        }\n\n        handleValue++;\n    }\n}\n\nVOID PhSweepHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG handleValue;\n    PPH_HANDLE_TABLE_ENTRY entry;\n    BOOLEAN cont;\n\n    handleValue = 0;\n\n    while (entry = PhpLookupHandleTableEntry(HandleTable, handleValue))\n    {\n        if (entry->TypeAndValue.Type == PH_HANDLE_TABLE_ENTRY_IN_USE)\n        {\n            cont = Callback(\n                HandleTable,\n                PhpEncodeHandle(handleValue),\n                entry,\n                Context\n                );\n\n            if (!cont)\n                break;\n        }\n\n        handleValue++;\n    }\n}\n\nNTSTATUS PhQueryInformationHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,\n    _Out_writes_bytes_opt_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    ULONG returnLength;\n\n    switch (InformationClass)\n    {\n    case HandleTableBasicInformation:\n        {\n            PPH_HANDLE_TABLE_BASIC_INFORMATION basicInfo = Buffer;\n\n            if (BufferLength == sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION))\n            {\n                basicInfo->Count = HandleTable->Count;\n                basicInfo->Flags = HandleTable->Flags;\n                basicInfo->TableLevel = HandleTable->TableValue & PH_HANDLE_TABLE_LEVEL_MASK;\n            }\n            else\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n            }\n\n            returnLength = sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION);\n        }\n        break;\n    case HandleTableFlagsInformation:\n        {\n            PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer;\n\n            if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION))\n            {\n                flagsInfo->Flags = HandleTable->Flags;\n            }\n            else\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n            }\n\n            returnLength = sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION);\n        }\n        break;\n    default:\n        status = STATUS_INVALID_INFO_CLASS;\n        returnLength = 0;\n        break;\n    }\n\n    if (ReturnLength)\n        *ReturnLength = returnLength;\n\n    return status;\n}\n\nNTSTATUS PhSetInformationHandleTable(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,\n    _In_reads_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    switch (InformationClass)\n    {\n    case HandleTableFlagsInformation:\n        {\n            PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer;\n            ULONG flags;\n\n            if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION))\n            {\n                flags = flagsInfo->Flags;\n\n                if ((flags & PH_HANDLE_TABLE_VALID_FLAGS) == flags)\n                    HandleTable->Flags = flags;\n                else\n                    status = STATUS_INVALID_PARAMETER;\n            }\n            else\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n            }\n        }\n        break;\n    default:\n        status = STATUS_INVALID_INFO_CLASS;\n    }\n\n    return status;\n}\n\nPPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Out_ PULONG HandleValue\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY entry;\n    ULONG freeValue;\n    ULONG lockIndex;\n    ULONG nextFreeValue;\n    ULONG oldFreeValue;\n    BOOLEAN result;\n\n    while (TRUE)\n    {\n        freeValue = HandleTable->FreeValue;\n\n        while (freeValue == PH_HANDLE_VALUE_INVALID)\n        {\n            PhAcquireQueuedLockExclusive(&HandleTable->Lock);\n\n            // Check again to see if we have free handles.\n\n            freeValue = HandleTable->FreeValue;\n\n            if (freeValue != PH_HANDLE_VALUE_INVALID)\n            {\n                PhReleaseQueuedLockExclusive(&HandleTable->Lock);\n                break;\n            }\n\n            // Move handles from the alt. free list to the main free list, and check again.\n\n            freeValue = PhpMoveFreeHandleTableEntries(HandleTable);\n\n            if (freeValue != PH_HANDLE_VALUE_INVALID)\n            {\n                PhReleaseQueuedLockExclusive(&HandleTable->Lock);\n                break;\n            }\n\n            result = PhpAllocateMoreHandleTableEntries(HandleTable, TRUE);\n\n            PhReleaseQueuedLockExclusive(&HandleTable->Lock);\n\n            freeValue = HandleTable->FreeValue;\n\n            // Note that PhpAllocateMoreHandleTableEntries only returns FALSE if it failed to\n            // allocate memory. Success does not guarantee a free handle to be allocated, as they\n            // may have been all used up (however unlikely) when we reach this point. Success simply\n            // means to retry the allocation using the fast path.\n\n            if (!result && freeValue == PH_HANDLE_VALUE_INVALID)\n                return NULL;\n        }\n\n        entry = PhpLookupHandleTableEntry(HandleTable, freeValue);\n        lockIndex = PH_HANDLE_TABLE_LOCK_INDEX(freeValue);\n\n        // To avoid the ABA problem, we would ideally have one queued lock per handle table entry.\n        // That would make the overhead too large, so instead there is a fixed number of locks,\n        // indexed by the handle value (mod no. locks).\n\n        // Possibilities at this point:\n        // 1. freeValue != A (our copy), but the other thread has freed A, so FreeValue = A. No ABA\n        // problem since freeValue != A.\n        // 2. freeValue != A, and FreeValue != A. No ABA problem.\n        // 3. freeValue = A, and the other thread has freed A, so FreeValue = A. No ABA problem\n        // since we haven't read NextFreeValue yet.\n        // 4. freeValue = A, and FreeValue != A. No problem if this stays the same later, as the CAS\n        // will take care of it.\n\n        PhpLockHandleTableShared(HandleTable, lockIndex);\n\n        if (HandleTable->FreeValue != freeValue)\n        {\n            PhpUnlockHandleTableShared(HandleTable, lockIndex);\n            continue;\n        }\n\n        MemoryBarrier();\n\n        nextFreeValue = entry->NextFreeValue;\n\n        // Possibilities/non-possibilities at this point:\n        // 1. freeValue != A (our copy), but the other thread has freed A, so FreeValue = A. This is\n        // actually impossible since we have acquired the lock on A and the free code checks that\n        // and uses the alt. free list instead.\n        // 2. freeValue != A, and FreeValue != A. No ABA problem.\n        // 3. freeValue = A, and the other thread has freed A, so FreeValue = A. Impossible like\n        // above. This is *the* ABA problem which we have now prevented.\n        // 4. freeValue = A, and FreeValue != A. CAS will take care of it.\n\n        oldFreeValue = _InterlockedCompareExchange(\n            &HandleTable->FreeValue,\n            nextFreeValue,\n            freeValue\n            );\n\n        PhpUnlockHandleTableShared(HandleTable, lockIndex);\n\n        if (oldFreeValue == freeValue)\n            break;\n    }\n\n    _InterlockedIncrement((PLONG)&HandleTable->Count);\n\n    *HandleValue = freeValue;\n\n    return entry;\n}\n\nVOID PhpFreeHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG HandleValue,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    PULONG freeList;\n    ULONG flags;\n    ULONG oldValue;\n\n    _InterlockedDecrement((PLONG)&HandleTable->Count);\n\n    flags = HandleTable->Flags;\n\n    // Choose the free list to use depending on whether someone is popping from the main free list\n    // (see PhpAllocateHandleTableEntry for details). We always use the alt. free list if strict\n    // FIFO is enabled.\n    if (!(flags & PH_HANDLE_TABLE_STRICT_FIFO) &&\n        PhTryAcquireReleaseQueuedLockExclusive(\n        &HandleTable->Locks[PH_HANDLE_TABLE_LOCK_INDEX(HandleValue)]))\n    {\n        freeList = &HandleTable->FreeValue;\n    }\n    else\n    {\n        freeList = &HandleTable->FreeValueAlt;\n    }\n\n    while (TRUE)\n    {\n        oldValue = *freeList;\n        HandleTableEntry->NextFreeValue = oldValue;\n\n        if (_InterlockedCompareExchange(\n            freeList,\n            HandleValue,\n            oldValue\n            ) == oldValue)\n        {\n            break;\n        }\n    }\n}\n\nBOOLEAN PhpAllocateMoreHandleTableEntries(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ BOOLEAN Initialize\n    )\n{\n    ULONG_PTR tableValue;\n    ULONG tableLevel;\n    PPH_HANDLE_TABLE_ENTRY table0 = NULL;\n    PPH_HANDLE_TABLE_ENTRY *table1;\n    PPH_HANDLE_TABLE_ENTRY **table2;\n    ULONG i;\n    ULONG j;\n    ULONG oldNextValue;\n    ULONG freeValue;\n\n    // Get a pointer to the table, and its level.\n\n    tableValue = HandleTable->TableValue;\n    tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK;\n    tableValue -= tableLevel;\n\n    switch (tableLevel)\n    {\n    case 0:\n        {\n            // Create a level 1 table.\n\n            table1 = PhpCreateHandleTableLevel1(HandleTable);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n            if (!table1)\n                return FALSE;\n#endif\n\n            // Create a new level 0 table and move the existing level into the new level 1 table.\n\n            table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n            if (!table0)\n            {\n                PhpFreeHandleTableLevel1(table1);\n                return FALSE;\n            }\n#endif\n\n            table1[0] = (PPH_HANDLE_TABLE_ENTRY)tableValue;\n            table1[1] = table0;\n\n            tableValue = (ULONG_PTR)table1 | 1;\n            //_InterlockedExchangePointer((PVOID *)&HandleTable->TableValue, (PVOID)tableValue);\n            HandleTable->TableValue = tableValue;\n        }\n        break;\n    case 1:\n        {\n            table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue;\n\n            // Determine whether we need to create a new level 0 table or create a level 2 table.\n\n            i = HandleTable->NextValue / PH_HANDLE_TABLE_LEVEL_ENTRIES;\n\n            if (i < PH_HANDLE_TABLE_LEVEL_ENTRIES)\n            {\n                table0 = PhpCreateHandleTableLevel0(HandleTable, TRUE);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table0)\n                    return FALSE;\n#endif\n\n                //_InterlockedExchangePointer((PVOID *)&table1[i], table0);\n                table1[i] = table0;\n            }\n            else\n            {\n                // Create a level 2 table.\n\n                table2 = PhpCreateHandleTableLevel2(HandleTable);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table2)\n                    return FALSE;\n#endif\n\n                // Create a new level 1 table and move the existing level into the new level 2\n                // table.\n\n                table1 = PhpCreateHandleTableLevel1(HandleTable);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table1)\n                {\n                    PhpFreeHandleTableLevel2(table2);\n                    return FALSE;\n                }\n#endif\n\n                table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table0)\n                {\n                    PhpFreeHandleTableLevel1(table1);\n                    PhpFreeHandleTableLevel2(table2);\n                    return FALSE;\n                }\n#endif\n\n                table1[0] = table0;\n\n                table2[0] = (PPH_HANDLE_TABLE_ENTRY *)tableValue;\n                table2[1] = table1;\n\n                tableValue = (ULONG_PTR)table2 | 2;\n                //_InterlockedExchangePointer((PVOID *)&HandleTable->TableValue, (PVOID)tableValue);\n                HandleTable->TableValue = tableValue;\n            }\n        }\n        break;\n    case 2:\n        {\n            table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue;\n\n            i = HandleTable->NextValue /\n                (PH_HANDLE_TABLE_LEVEL_ENTRIES * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n            // i contains an index into the level 2 table, of the containing level 1 table.\n\n            // Check if we have exceeded the maximum number of handles.\n\n            if (i >= PH_HANDLE_TABLE_LEVEL_ENTRIES)\n                return FALSE;\n\n            // Check if we should create a new level 0 table or a new level 2 table.\n            if (table2[i])\n            {\n                table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table0)\n                    return FALSE;\n#endif\n\n                // Same as j = HandleTable->NextValue % (no. entries * no. entries), but we already\n                // calculated i so just use it.\n                j = HandleTable->NextValue - i *\n                    (PH_HANDLE_TABLE_LEVEL_ENTRIES * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n                j /= PH_HANDLE_TABLE_LEVEL_ENTRIES;\n                // j now contains an index into the level 1 table, of the containing level 0 table\n                // (the one which was created).\n\n                //_InterlockedExchangePointer((PVOID *)&table2[i][j], table0);\n                table2[i][j] = table0;\n            }\n            else\n            {\n                table1 = PhpCreateHandleTableLevel1(HandleTable);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table1)\n                    return FALSE;\n#endif\n\n                table0 = PhpCreateHandleTableLevel0(HandleTable, TRUE);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table0)\n                {\n                    PhpFreeHandleTableLevel1(table1);\n                    return FALSE;\n                }\n#endif\n\n                table1[0] = table0;\n\n                //_InterlockedExchangePointer((PVOID *)&table2[i], table1);\n                table2[i] = table1;\n            }\n        }\n        break;\n    default:\n        ASSUME_NO_DEFAULT;\n    }\n\n    // In each of the cases above, we allocated one additional level 0 table.\n    oldNextValue = _InterlockedExchangeAdd(\n        (PLONG)&HandleTable->NextValue,\n        PH_HANDLE_TABLE_LEVEL_ENTRIES\n        );\n\n    if (Initialize)\n    {\n        // No ABA problem since these are new handles being pushed.\n\n        while (TRUE)\n        {\n            freeValue = HandleTable->FreeValue;\n            table0[PH_HANDLE_TABLE_LEVEL_ENTRIES - 1].NextFreeValue = freeValue;\n\n            if (_InterlockedCompareExchange(\n                &HandleTable->FreeValue,\n                oldNextValue,\n                freeValue\n                ) == freeValue)\n            {\n                break;\n            }\n        }\n    }\n\n    return TRUE;\n}\n\nPPH_HANDLE_TABLE_ENTRY PhpLookupHandleTableEntry(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG HandleValue\n    )\n{\n    ULONG_PTR tableValue;\n    ULONG tableLevel;\n    PPH_HANDLE_TABLE_ENTRY table0;\n    PPH_HANDLE_TABLE_ENTRY *table1;\n    PPH_HANDLE_TABLE_ENTRY **table2;\n    PPH_HANDLE_TABLE_ENTRY entry = NULL;\n\n    if (HandleValue >= HandleTable->NextValue)\n        return NULL;\n\n    // Get a pointer to the table, and its level.\n\n    tableValue = HandleTable->TableValue;\n    tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK;\n    tableValue -= tableLevel;\n\n    // No additional checking needed; already checked against NextValue.\n\n    switch (tableLevel)\n    {\n    case 0:\n        {\n            table0 = (PPH_HANDLE_TABLE_ENTRY)tableValue;\n            entry = &table0[HandleValue];\n        }\n        break;\n    case 1:\n        {\n            table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue;\n            table0 = table1[PH_HANDLE_VALUE_LEVEL1_U(HandleValue)];\n            entry = &table0[PH_HANDLE_VALUE_LEVEL0(HandleValue)];\n        }\n        break;\n    case 2:\n        {\n            table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue;\n            table1 = table2[PH_HANDLE_VALUE_LEVEL2_U(HandleValue)];\n            table0 = table1[PH_HANDLE_VALUE_LEVEL1(HandleValue)];\n            entry = &table0[PH_HANDLE_VALUE_LEVEL0(HandleValue)];\n        }\n        break;\n    default:\n        ASSUME_NO_DEFAULT;\n    }\n\n    return entry;\n}\n\nULONG PhpMoveFreeHandleTableEntries(\n    _Inout_ PPH_HANDLE_TABLE HandleTable\n    )\n{\n    ULONG freeValueAlt;\n    ULONG flags;\n    ULONG i;\n    ULONG index;\n    ULONG nextIndex;\n    ULONG lastIndex;\n    PPH_HANDLE_TABLE_ENTRY entry;\n    PPH_HANDLE_TABLE_ENTRY firstEntry = NULL;\n    ULONG count;\n    ULONG freeValue;\n\n    // Remove all entries from the alt. free list.\n    freeValueAlt = _InterlockedExchange(&HandleTable->FreeValueAlt, PH_HANDLE_VALUE_INVALID);\n\n    if (freeValueAlt == PH_HANDLE_VALUE_INVALID)\n    {\n        // No handles on the alt. free list.\n        return PH_HANDLE_VALUE_INVALID;\n    }\n\n    // Avoid the ABA problem by testing all locks (see PhpAllocateHandleTableEntry for details).\n    // Unlike in PhpFreeHandleTableEntry we have no \"alternative\" list, so we must allow blocking.\n    for (i = 0; i < PH_HANDLE_TABLE_LOCKS; i++)\n        PhAcquireReleaseQueuedLockExclusive(&HandleTable->Locks[i]);\n\n    flags = HandleTable->Flags;\n\n    if (!(flags & PH_HANDLE_TABLE_STRICT_FIFO))\n    {\n        // Shortcut: if there are no entries in the main free list and we don't need to reverse the\n        // chain, just return.\n        if (_InterlockedCompareExchange(\n            &HandleTable->FreeValue,\n            freeValueAlt,\n            PH_HANDLE_VALUE_INVALID\n            ) == PH_HANDLE_VALUE_INVALID)\n            return freeValueAlt;\n    }\n\n    // Reverse the chain (even if strict FIFO is off; we have to traverse the list to find the last\n    // entry, so we might as well reverse it along the way).\n\n    index = freeValueAlt;\n    lastIndex = PH_HANDLE_VALUE_INVALID;\n    count = 0;\n\n    while (TRUE)\n    {\n        entry = PhpLookupHandleTableEntry(HandleTable, index);\n        count++;\n\n        if (lastIndex == PH_HANDLE_VALUE_INVALID)\n            firstEntry = entry;\n\n        nextIndex = entry->NextFreeValue;\n        entry->NextFreeValue = lastIndex;\n        lastIndex = index;\n\n        if (nextIndex == PH_HANDLE_VALUE_INVALID)\n            break;\n\n        index = nextIndex;\n    }\n\n    // Note that firstEntry actually contains the last free entry, since we reversed the list.\n    // Similarly index/lastIndex both contain the index of the first free entry.\n\n    // Push the entries onto the free list.\n    while (TRUE)\n    {\n        freeValue = HandleTable->FreeValue;\n        firstEntry->NextFreeValue = freeValue;\n\n        if (_InterlockedCompareExchange(\n            &HandleTable->FreeValue,\n            index,\n            freeValue\n            ) == freeValue)\n            break;\n    }\n\n    // Force expansion if we don't have enough free handles.\n    if (\n        (flags & PH_HANDLE_TABLE_STRICT_FIFO) &&\n        count < PH_HANDLE_TABLE_FREE_COUNT\n        )\n    {\n        index = PH_HANDLE_VALUE_INVALID;\n    }\n\n    return index;\n}\n\nPPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ BOOLEAN Initialize\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY table;\n    PPH_HANDLE_TABLE_ENTRY entry;\n    ULONG baseValue;\n    ULONG i;\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    __try\n    {\n        table = PhAllocateFromFreeList(&PhHandleTableLevel0FreeList);\n    }\n    __except (SIMPLE_EXCEPTION_FILTER(GetExceptionCode() == STATUS_NO_MEMORY))\n    {\n        return NULL;\n    }\n#else\n    table = PhAllocateFromFreeList(&PhHandleTableLevel0FreeList);\n#endif\n\n    if (Initialize)\n    {\n        entry = &table[0];\n        baseValue = HandleTable->NextValue;\n\n        for (i = baseValue + 1; i < baseValue + PH_HANDLE_TABLE_LEVEL_ENTRIES; i++)\n        {\n            entry->Value = PH_HANDLE_TABLE_ENTRY_FREE;\n            entry->NextFreeValue = i;\n            entry++;\n        }\n\n        entry->Value = PH_HANDLE_TABLE_ENTRY_FREE;\n        entry->NextFreeValue = PH_HANDLE_VALUE_INVALID;\n    }\n\n    return table;\n}\n\nVOID PhpFreeHandleTableLevel0(\n    _In_ PPH_HANDLE_TABLE_ENTRY Table\n    )\n{\n    PhFreeToFreeList(&PhHandleTableLevel0FreeList, Table);\n}\n\nPPH_HANDLE_TABLE_ENTRY *PhpCreateHandleTableLevel1(\n    _In_ PPH_HANDLE_TABLE HandleTable\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY *table;\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    __try\n    {\n        table = PhAllocateFromFreeList(&PhHandleTableLevel1FreeList);\n    }\n    __except (SIMPLE_EXCEPTION_FILTER(GetExceptionCode() == STATUS_NO_MEMORY))\n    {\n        return NULL;\n    }\n#else\n    table = PhAllocateFromFreeList(&PhHandleTableLevel1FreeList);\n#endif\n\n    memset(table, 0, sizeof(PPH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n\n    return table;\n}\n\nVOID PhpFreeHandleTableLevel1(\n    _In_ PPH_HANDLE_TABLE_ENTRY *Table\n    )\n{\n    PhFreeToFreeList(&PhHandleTableLevel1FreeList, Table);\n}\n\nPPH_HANDLE_TABLE_ENTRY **PhpCreateHandleTableLevel2(\n    _In_ PPH_HANDLE_TABLE HandleTable\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY **table;\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    table = PhAllocateSafe(sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n\n    if (!table)\n        return NULL;\n#else\n    table = PhAllocate(sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n#endif\n\n    memset(table, 0, sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n\n    return table;\n}\n\nVOID PhpFreeHandleTableLevel2(\n    _In_ PPH_HANDLE_TABLE_ENTRY **Table\n    )\n{\n    PhFree(Table);\n}\n"
  },
  {
    "path": "phlib/hexedit.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2023\n *\n */\n\n#include <ph.h>\n#include <hexedit.h>\n#include <guisup.h>\n#include <hexeditp.h>\n\n// Code originally from http://www.codeguru.com/Cpp/controls/editctrl/article.php/c539\n\nRTL_ATOM PhHexEditInitialization(\n    VOID\n    )\n{\n    WNDCLASSEX wcex;\n\n    memset(&wcex, 0, sizeof(WNDCLASSEX));\n    wcex.cbSize = sizeof(WNDCLASSEX);\n    wcex.style = CS_GLOBALCLASS | CS_DBLCLKS;\n    wcex.lpfnWndProc = PhpHexEditWndProc;\n    wcex.cbClsExtra = 0;\n    wcex.cbWndExtra = sizeof(PVOID);\n    wcex.hInstance = NtCurrentImageBase();\n    wcex.hCursor = PhLoadCursor(NULL, IDC_ARROW);\n    wcex.lpszClassName = PH_HEXEDIT_CLASSNAME;\n\n    return RegisterClassEx(&wcex);\n}\n\nPPHP_HEXEDIT_CONTEXT PhpCreateHexEditContext(\n    VOID\n    )\n{\n    PPHP_HEXEDIT_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_HEXEDIT_CONTEXT));\n    memset(context, 0, sizeof(PHP_HEXEDIT_CONTEXT)); // important, set NullWidth to 0\n\n    context->Data = NULL;\n    context->Length = 0;\n    context->TopIndex = 0;\n    context->BytesPerRow = 16;\n    context->LinesPerPage = 1;\n\n    context->ShowHex = TRUE;\n    context->ShowAscii = TRUE;\n    context->ShowAddress = TRUE;\n    context->AddressIsWide = TRUE;\n    context->AllowLengthChange = FALSE;\n\n    context->AddressOffset = 0;\n    context->HexOffset = 0;\n    context->AsciiOffset = 0;\n\n    context->Update = TRUE;\n    context->NoAddressChange = FALSE;\n    context->CurrentMode = EDIT_NONE;\n\n    context->EditPosition.x = 0;\n    context->EditPosition.y = 0;\n    context->CurrentAddress = 0;\n    context->HalfPage = TRUE;\n\n    context->SelStart = -1;\n    context->SelEnd = -1;\n\n    return context;\n}\n\nVOID PhpFreeHexEditContext(\n    _In_ _Post_invalid_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (!Context->UserBuffer && Context->Data) PhFree(Context->Data);\n    if (Context->CharBuffer) PhFree(Context->CharBuffer);\n    if (Context->Font) DeleteFont(Context->Font);\n    PhFree(Context);\n}\n\nLRESULT CALLBACK PhpHexEditWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_HEXEDIT_CONTEXT context;\n\n    context = PhGetWindowContextEx(hwnd);\n\n    if (uMsg == WM_NCCREATE)\n    {\n        context = PhpCreateHexEditContext();\n        PhSetWindowContextEx(hwnd, context);\n    }\n\n    if (!context)\n        return DefWindowProc(hwnd, uMsg, wParam, lParam);\n\n    switch (uMsg)\n    {\n    case WM_CREATE:\n        {\n            context->WindowDpi = PhGetWindowDpi(hwnd);\n\n            context->Font = CreateFont(\n                -(LONG)PhGetDpi(12, context->WindowDpi),\n                0,\n                0,\n                0,\n                0,\n                0,\n                0,\n                0,\n                0,\n                0,\n                0,\n                0,\n                0,\n                L\"Courier New\"\n                );\n        }\n        break;\n    case WM_DESTROY:\n        {\n            PhRemoveWindowContextEx(hwnd);\n            PhpFreeHexEditContext(context);\n        }\n        break;\n    case WM_PAINT:\n        {\n            PAINTSTRUCT paintStruct;\n            HDC hdc;\n\n            if (hdc = BeginPaint(hwnd, &paintStruct))\n            {\n                PhpHexEditOnPaint(hwnd, context, &paintStruct, hdc);\n                EndPaint(hwnd, &paintStruct);\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhpHexEditUpdateMetrics(hwnd, context, FALSE, NULL);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            context->WindowDpi = PhGetWindowDpi(hwnd);\n        }\n        break;\n    case WM_SETFOCUS:\n        {\n            if (context->Data && !PhpHexEditHasSelected(context))\n            {\n                if (context->EditPosition.x == 0 && context->ShowAddress)\n                    PhpHexEditCreateAddressCaret(hwnd, context);\n                else\n                    PhpHexEditCreateEditCaret(hwnd, context);\n\n                SetCaretPos(context->EditPosition.x, context->EditPosition.y);\n                ShowCaret(hwnd);\n            }\n        }\n        break;\n    case WM_KILLFOCUS:\n        {\n            DestroyCaret();\n        }\n        break;\n    case WM_VSCROLL:\n        {\n            SHORT scrollRequest = LOWORD(wParam);\n            LONG currentPosition;\n            LONG originalTopIndex;\n            SCROLLINFO scrollInfo = { sizeof(scrollInfo) };\n\n            originalTopIndex = context->TopIndex;\n\n            scrollInfo.fMask = SIF_TRACKPOS;\n            GetScrollInfo(hwnd, SB_VERT, &scrollInfo);\n            currentPosition = scrollInfo.nTrackPos;\n\n            if (context->Data)\n            {\n                LONG mult;\n\n                mult = context->LinesPerPage * context->BytesPerRow;\n\n                switch (scrollRequest)\n                {\n                case SB_LINEDOWN:\n                    if (context->TopIndex < context->Length - mult)\n                    {\n                        context->TopIndex += context->BytesPerRow;\n                        REDRAW_WINDOW(hwnd);\n                    }\n                    break;\n                case SB_LINEUP:\n                    if (context->TopIndex >= context->BytesPerRow)\n                    {\n                        context->TopIndex -= context->BytesPerRow;\n                        REDRAW_WINDOW(hwnd);\n                    }\n                    break;\n                case SB_PAGEDOWN:\n                    if (context->TopIndex < context->Length - mult)\n                    {\n                        LONG pageEnd = 0;\n\n                        while (pageEnd < context->Length - mult)\n                            pageEnd += context->BytesPerRow;\n\n                        context->TopIndex += mult;\n\n                        if (context->TopIndex > pageEnd)\n                            context->TopIndex = pageEnd;\n\n                        REDRAW_WINDOW(hwnd);\n                    }\n                    break;\n                case SB_PAGEUP:\n                    if (context->TopIndex > 0)\n                    {\n                        context->TopIndex -= mult;\n\n                        if (context->TopIndex < 0)\n                            context->TopIndex = 0;\n\n                        REDRAW_WINDOW(hwnd);\n                    }\n                    break;\n                case SB_THUMBTRACK:\n                    context->TopIndex = currentPosition * context->BytesPerRow;\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                case SB_TOP:\n                    context->TopIndex = 0;\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                case SB_BOTTOM:\n                    while (context->TopIndex < context->Length - mult)\n                        context->TopIndex += context->BytesPerRow;\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n\n                SetScrollPos(hwnd, SB_VERT, context->TopIndex / context->BytesPerRow, TRUE);\n\n                if (!context->NoAddressChange && FALSE) // this behaviour sucks, so just leave it out\n                    context->CurrentAddress += context->TopIndex - originalTopIndex;\n\n                PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress);\n            }\n        }\n        break;\n    case WM_MOUSEWHEEL:\n        {\n            SHORT wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam);\n\n            if (context->Data)\n            {\n                ULONG wheelScrollLines;\n\n                if (!PhGetSystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScrollLines, 0))\n                {\n                    wheelScrollLines = PhGetDpi(3, context->WindowDpi);\n                }\n\n                context->TopIndex += context->BytesPerRow * (LONG)wheelScrollLines * -wheelDelta / WHEEL_DELTA;\n\n                if (context->TopIndex < 0)\n                    context->TopIndex = 0;\n\n                if (context->Length >= context->LinesPerPage * context->BytesPerRow)\n                {\n                    if (context->TopIndex > context->Length - context->LinesPerPage * context->BytesPerRow)\n                        context->TopIndex = context->Length - context->LinesPerPage * context->BytesPerRow;\n                }\n\n                REDRAW_WINDOW(hwnd);\n\n                SetScrollPos(hwnd, SB_VERT, context->TopIndex / context->BytesPerRow, TRUE);\n\n                PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress);\n            }\n        }\n        break;\n    case WM_GETDLGCODE:\n        if (wParam != VK_ESCAPE)\n            return DLGC_WANTALLKEYS;\n        break;\n    case WM_ERASEBKGND:\n        return 1;\n    case WM_LBUTTONDOWN:\n        {\n            ULONG flags = (ULONG)wParam;\n            POINT cursorPos;\n\n            cursorPos.x = GET_X_LPARAM(lParam);\n            cursorPos.y = GET_Y_LPARAM(lParam);\n\n            SetFocus(hwnd);\n\n            if (context->Data)\n            {\n                POINT point;\n\n                if (wParam & MK_SHIFT)\n                    context->SelStart = context->CurrentAddress;\n\n                PhpHexEditCalculatePosition(hwnd, context, cursorPos.x, cursorPos.y, &point);\n\n                if (point.x > -1)\n                {\n                    context->EditPosition = point;\n\n                    point.x *= context->NullWidth;\n                    point.y *= context->LineHeight;\n\n                    if (point.x == 0 && context->ShowAddress)\n                        PhpHexEditCreateAddressCaret(hwnd, context);\n                    else\n                        PhpHexEditCreateEditCaret(hwnd, context);\n\n                    SetCaretPos(point.x, point.y);\n\n                    if (flags & MK_SHIFT)\n                    {\n                        context->SelEnd = context->CurrentAddress;\n\n                        if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW)\n                            context->SelEnd++;\n\n                        REDRAW_WINDOW(hwnd);\n                    }\n                }\n\n                if (!(flags & MK_SHIFT))\n                {\n                    if (DragDetect(hwnd, cursorPos))\n                    {\n                        context->SelStart = context->CurrentAddress;\n                        context->SelEnd = context->SelStart;\n                        SetCapture(hwnd);\n                        context->HasCapture = TRUE;\n                    }\n                    else\n                    {\n                        BOOLEAN selected;\n\n                        selected = context->SelStart != -1;\n                        context->SelStart = -1;\n                        context->SelEnd = -1;\n\n                        if (selected)\n                            REDRAW_WINDOW(hwnd);\n                    }\n                }\n\n                if (!PhpHexEditHasSelected(context))\n                    ShowCaret(hwnd);\n            }\n        }\n        break;\n    case WM_LBUTTONUP:\n        {\n            if (context->HasCapture && PhpHexEditHasSelected(context))\n                ReleaseCapture();\n\n            context->HasCapture = FALSE;\n        }\n        break;\n    case WM_MOUSEMOVE:\n        {\n            ULONG flags = (ULONG)wParam;\n            POINT cursorPos;\n\n            cursorPos.x = GET_X_LPARAM(lParam);\n            cursorPos.y = GET_Y_LPARAM(lParam);\n\n            if (\n                context->Data &&\n                context->HasCapture &&\n                context->SelStart != -1\n                )\n            {\n                RECT rect;\n                POINT point;\n                ULONG oldSelEnd;\n\n                // User is dragging.\n\n                GetClientRect(hwnd, &rect);\n\n                if (!PhPtInRect(&rect, &cursorPos))\n                {\n                    if (cursorPos.y < 0)\n                    {\n                        SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);\n                        cursorPos.y = 0;\n                    }\n                    else if (cursorPos.y > rect.bottom)\n                    {\n                        SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);\n                        cursorPos.y = rect.bottom - 1;\n                    }\n                }\n\n                oldSelEnd = context->SelEnd;\n                PhpHexEditCalculatePosition(hwnd, context, cursorPos.x, cursorPos.y, &point);\n\n                if (point.x > -1)\n                {\n                    context->SelEnd = context->CurrentAddress;\n\n                    if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW)\n                        context->SelEnd++;\n                }\n\n                if (PhpHexEditHasSelected(context))\n                    DestroyCaret();\n\n                if (context->SelEnd != oldSelEnd)\n                    REDRAW_WINDOW(hwnd);\n            }\n        }\n        break;\n    case WM_CHAR:\n        {\n            ULONG c = (ULONG)wParam;\n\n            if (!context->Data)\n                goto DefaultHandler;\n            if (c == '\\t')\n                goto DefaultHandler;\n\n            if (GetKeyState(VK_CONTROL) < 0)\n            {\n                switch (c)\n                {\n                case 0x3:\n                    if (PhpHexEditHasSelected(context))\n                        PhpHexEditCopyEdit(hwnd, context);\n                    goto DefaultHandler;\n                case 0x16:\n                    PhpHexEditPasteEdit(hwnd, context);\n                    goto DefaultHandler;\n                case 0x18:\n                    if (PhpHexEditHasSelected(context))\n                        PhpHexEditCutEdit(hwnd, context);\n                    goto DefaultHandler;\n                case 0x1a:\n                    PhpHexEditUndoEdit(hwnd, context);\n                    goto DefaultHandler;\n                }\n            }\n\n            // Disallow editing beyond the end of the data.\n            if (context->CurrentAddress >= context->Length)\n                goto DefaultHandler;\n\n            if (c == 0x8)\n            {\n                if (context->CurrentAddress != 0)\n                {\n                    context->CurrentAddress--;\n                    PhpHexEditSelDelete(hwnd, context, context->CurrentAddress, context->CurrentAddress + 1);\n                    PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress);\n                    REDRAW_WINDOW(hwnd);\n                }\n\n                goto DefaultHandler;\n            }\n\n            PhpHexEditSetSel(hwnd, context, -1, -1);\n\n            switch (context->CurrentMode)\n            {\n            case EDIT_NONE:\n                goto DefaultHandler;\n            case EDIT_HIGH:\n            case EDIT_LOW:\n                if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))\n                {\n                    ULONG b = c - '0';\n\n                    if (b > 9)\n                        b = 10 + c - 'a';\n\n                    if (context->CurrentMode == EDIT_HIGH)\n                    {\n                        context->Data[context->CurrentAddress] =\n                            (UCHAR)((context->Data[context->CurrentAddress] & 0x0f) | (b << 4));\n                    }\n                    else\n                    {\n                        context->Data[context->CurrentAddress] =\n                            (UCHAR)((context->Data[context->CurrentAddress] & 0xf0) | b);\n                    }\n\n                    PhpHexEditMove(hwnd, context, 1, 0);\n                }\n                break;\n            case EDIT_ASCII:\n                context->Data[context->CurrentAddress] = (UCHAR)c;\n                PhpHexEditMove(hwnd, context, 1, 0);\n                break;\n            }\n\n            REDRAW_WINDOW(hwnd);\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            ULONG vk = (ULONG)wParam;\n            BOOLEAN shift = GetKeyState(VK_SHIFT) < 0;\n            BOOLEAN oldNoAddressChange = context->NoAddressChange;\n            BOOLEAN noScrollIntoView = FALSE;\n\n            context->NoAddressChange = TRUE;\n\n            switch (vk)\n            {\n            case VK_DOWN:\n                if (context->CurrentMode != EDIT_NONE)\n                {\n                    if (shift)\n                    {\n                        if (!PhpHexEditHasSelected(context))\n                            context->SelStart = context->CurrentAddress;\n\n                        PhpHexEditMove(hwnd, context, 0, 1);\n                        context->SelEnd = context->CurrentAddress;\n\n                        if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW)\n                            context->SelEnd++;\n\n                        REDRAW_WINDOW(hwnd);\n                        break;\n                    }\n                    else\n                    {\n                        PhpHexEditSetSel(hwnd, context, -1, -1);\n                    }\n\n                    PhpHexEditMove(hwnd, context, 0, 1);\n                    noScrollIntoView = TRUE;\n                }\n                else\n                {\n                    PhpHexEditMove(hwnd, context, 0, 1);\n                }\n                break;\n            case VK_UP:\n                if (context->CurrentMode != EDIT_NONE)\n                {\n                    if (shift)\n                    {\n                        if (!PhpHexEditHasSelected(context))\n                            context->SelStart = context->CurrentAddress;\n\n                        PhpHexEditMove(hwnd, context, 0, -1);\n                        context->SelEnd = context->CurrentAddress;\n\n                        REDRAW_WINDOW(hwnd);\n                        break;\n                    }\n                    else\n                    {\n                        PhpHexEditSetSel(hwnd, context, -1, -1);\n                    }\n\n                    PhpHexEditMove(hwnd, context, 0, -1);\n                    noScrollIntoView = TRUE;\n                }\n                else\n                {\n                    PhpHexEditMove(hwnd, context, 0, -1);\n                }\n                break;\n            case VK_LEFT:\n                if (context->CurrentMode != EDIT_NONE)\n                {\n                    if (shift)\n                    {\n                        if (!PhpHexEditHasSelected(context))\n                            context->SelStart = context->CurrentAddress;\n\n                        PhpHexEditMove(hwnd, context, -1, 0);\n                        context->SelEnd = context->CurrentAddress;\n\n                        REDRAW_WINDOW(hwnd);\n                        break;\n                    }\n                    else\n                    {\n                        PhpHexEditSetSel(hwnd, context, -1, -1);\n                    }\n\n                    PhpHexEditMove(hwnd, context, -1, 0);\n                    noScrollIntoView = TRUE;\n                }\n                break;\n            case VK_RIGHT:\n                if (context->CurrentMode != EDIT_NONE)\n                {\n                    if (shift)\n                    {\n                        if (!PhpHexEditHasSelected(context))\n                            context->SelStart = context->CurrentAddress;\n\n                        PhpHexEditMove(hwnd, context, 1, 0);\n                        context->SelEnd = context->CurrentAddress;\n\n                        if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW)\n                            context->SelEnd++;\n\n                        REDRAW_WINDOW(hwnd);\n                        break;\n                    }\n                    else\n                    {\n                        PhpHexEditSetSel(hwnd, context, -1, -1);\n                    }\n\n                    PhpHexEditMove(hwnd, context, 1, 0);\n                    noScrollIntoView = TRUE;\n                }\n                break;\n            case VK_PRIOR:\n                if (shift)\n                {\n                    if (!PhpHexEditHasSelected(context))\n                        context->SelStart = context->CurrentAddress;\n\n                    SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);\n                    PhpHexEditMove(hwnd, context, 0, 0);\n                    context->SelEnd = context->CurrentAddress;\n\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n                else\n                {\n                    PhpHexEditSetSel(hwnd, context, -1, -1);\n                }\n\n                SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);\n                PhpHexEditMove(hwnd, context, 0, 0);\n                noScrollIntoView = TRUE;\n                break;\n            case VK_NEXT:\n                if (shift)\n                {\n                    if (!PhpHexEditHasSelected(context))\n                        context->SelStart = context->CurrentAddress;\n\n                    SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);\n                    PhpHexEditMove(hwnd, context, 0, 0);\n                    context->SelEnd = context->CurrentAddress;\n\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n                else\n                {\n                    PhpHexEditSetSel(hwnd, context, -1, -1);\n                }\n\n                SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);\n                PhpHexEditMove(hwnd, context, 0, 0);\n                noScrollIntoView = TRUE;\n                break;\n            case VK_HOME:\n                if (shift)\n                {\n                    if (!PhpHexEditHasSelected(context))\n                        context->SelStart = context->CurrentAddress;\n\n                    if (GetKeyState(VK_CONTROL) < 0)\n                    {\n                        SendMessage(hwnd, WM_VSCROLL, SB_THUMBTRACK, 0);\n                    }\n                    else\n                    {\n                        // Round down.\n                        context->CurrentAddress /= context->BytesPerRow;\n                        context->CurrentAddress *= context->BytesPerRow;\n                    }\n\n                    PhpHexEditMove(hwnd, context, 0, 0);\n                    context->SelEnd = context->CurrentAddress;\n\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n                else\n                {\n                    PhpHexEditSetSel(hwnd, context, -1, -1);\n                }\n\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    SendMessage(hwnd, WM_VSCROLL, SB_THUMBTRACK, 0);\n                    context->CurrentAddress = 0;\n                }\n                else\n                {\n                    // Round down.\n                    context->CurrentAddress /= context->BytesPerRow;\n                    context->CurrentAddress *= context->BytesPerRow;\n                }\n\n                PhpHexEditMove(hwnd, context, 0, 0);\n                noScrollIntoView = TRUE;\n\n                break;\n            case VK_END:\n                if (shift)\n                {\n                    if (!PhpHexEditHasSelected(context))\n                        context->SelStart = context->CurrentAddress;\n\n                    if (GetKeyState(VK_CONTROL) < 0)\n                    {\n                        context->CurrentAddress = context->Length - 1;\n                        SendMessage(hwnd, WM_VSCROLL,\n                            MAKEWPARAM(SB_THUMBTRACK, ((context->Length + (context->BytesPerRow / 2)) / context->BytesPerRow) - context->LinesPerPage),\n                            0);\n                    }\n                    else\n                    {\n                        context->CurrentAddress /= context->BytesPerRow;\n                        context->CurrentAddress *= context->BytesPerRow;\n                        context->CurrentAddress += context->BytesPerRow - 1;\n\n                        if (context->CurrentAddress > context->Length)\n                            context->CurrentAddress = context->Length - 1;\n                    }\n\n                    PhpHexEditMove(hwnd, context, 0, 0);\n                    context->SelEnd = context->CurrentAddress;\n\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n                else\n                {\n                    PhpHexEditSetSel(hwnd, context, -1, -1);\n                }\n\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    context->CurrentAddress = context->Length - 1;\n\n                    if (context->HalfPage)\n                    {\n                        SendMessage(hwnd, WM_VSCROLL, 0, 0);\n                    }\n                    else\n                    {\n                        SendMessage(hwnd, WM_VSCROLL,\n                            MAKEWPARAM(SB_THUMBTRACK, ((context->Length + (context->BytesPerRow / 2)) / context->BytesPerRow) - context->LinesPerPage),\n                            0);\n                    }\n                }\n                else\n                {\n                    context->CurrentAddress /= context->BytesPerRow;\n                    context->CurrentAddress *= context->BytesPerRow;\n                    context->CurrentAddress += context->BytesPerRow - 1;\n\n                    if (context->CurrentAddress > context->Length)\n                        context->CurrentAddress = context->Length - 1;\n                }\n\n                PhpHexEditMove(hwnd, context, 0, 0);\n                noScrollIntoView = TRUE;\n\n                break;\n            case VK_INSERT:\n                PhpHexEditSelInsert(hwnd, context, context->CurrentAddress,\n                    max(1, context->SelEnd - context->SelStart));\n                REDRAW_WINDOW(hwnd);\n                break;\n            case VK_DELETE:\n                if (PhpHexEditHasSelected(context))\n                {\n                    PhpHexEditClearEdit(hwnd, context);\n                }\n                else\n                {\n                   PhpHexEditSelDelete(hwnd, context, context->CurrentAddress, context->CurrentAddress + 1);\n                   REDRAW_WINDOW(hwnd);\n                }\n                break;\n            case '\\t':\n                switch (context->CurrentMode)\n                {\n                case EDIT_NONE:\n                    context->CurrentMode = EDIT_HIGH;\n                    break;\n                case EDIT_HIGH:\n                case EDIT_LOW:\n                    context->CurrentMode = EDIT_ASCII;\n                    break;\n                case EDIT_ASCII:\n                    context->CurrentMode = EDIT_HIGH;\n                    break;\n                }\n\n                PhpHexEditMove(hwnd, context, 0, 0);\n\n                break;\n            }\n\n            // Scroll into view if not in view.\n            if (\n                !noScrollIntoView &&\n                (context->CurrentAddress < context->TopIndex ||\n                context->CurrentAddress >= context->TopIndex + context->LinesPerPage * context->BytesPerRow)\n                )\n            {\n                PhpHexEditScrollTo(hwnd, context, context->CurrentAddress);\n            }\n\n            context->NoAddressChange = oldNoAddressChange;\n        }\n        break;\n    case HEM_SETBUFFER:\n        {\n            PhpHexEditSetBuffer(hwnd, context, (PUCHAR)lParam, (ULONG)wParam);\n        }\n        return TRUE;\n    case HEM_SETDATA:\n        {\n            PhpHexEditSetData(hwnd, context, (PUCHAR)lParam, (ULONG)wParam);\n        }\n        return TRUE;\n    case HEM_GETBUFFER:\n        {\n            PULONG length = (PULONG)wParam;\n\n            if (length)\n                *length = context->Length;\n\n            return (LPARAM)context->Data;\n        }\n    case HEM_SETSEL:\n        {\n            LONG selStart = (LONG)wParam;\n            LONG selEnd = (LONG)lParam;\n\n            if (selStart <= 0)\n                return FALSE;\n            if (selEnd > context->Length)\n                return FALSE;\n\n            PhpHexEditScrollTo(hwnd, context, selStart);\n            PhpHexEditSetSel(hwnd, context, selStart, selEnd);\n            PhpHexEditRepositionCaret(hwnd, context, selStart);\n            REDRAW_WINDOW(hwnd);\n        }\n        return TRUE;\n    case HEM_SETEDITMODE:\n        {\n            context->CurrentMode = (LONG)wParam;\n            REDRAW_WINDOW(hwnd);\n        }\n        return TRUE;\n    case HEM_SETBYTESPERROW:\n        {\n            LONG bytesPerRow = (LONG)wParam;\n\n            if (bytesPerRow >= 4)\n            {\n                context->BytesPerRow = bytesPerRow;\n                PhpHexEditUpdateMetrics(hwnd, context, TRUE, NULL);\n                PhpHexEditUpdateScrollbars(hwnd, context);\n                PhpHexEditScrollTo(hwnd, context, context->CurrentAddress);\n                PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress);\n                REDRAW_WINDOW(hwnd);\n            }\n        }\n        return TRUE;\n    case HEM_SETEXTENDEDUNICODE:\n        {\n            context->ExtendedUnicode = !!(LONG)wParam;\n        }\n        return TRUE;\n    }\n\nDefaultHandler:\n    return DefWindowProc(hwnd, uMsg, wParam, lParam);\n}\n\nFORCEINLINE INT PhpIsPrintable(\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ UCHAR Byte\n    )\n{\n    if (Context->ExtendedUnicode)\n        return iswctype(Byte, _PUNCT | _ALPHA | _DIGIT); // iswprint\n    else\n        return ((ULONG)((Byte)-' ') <= (ULONG)('~' - ' '));\n}\n\nFORCEINLINE VOID PhpPrintHex(\n    _In_ HDC hdc,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _Inout_ PWCHAR Buffer,\n    _In_ UCHAR Byte,\n    _Inout_ PLONG X,\n    _Inout_ PLONG Y,\n    _Inout_ PULONG N\n    )\n{\n    PWCHAR p = Buffer;\n\n    TO_HEX(p, Byte);\n    *p++ = ' ';\n    TextOut(hdc, *X, *Y, Buffer, 3);\n    *X += Context->NullWidth * 3;\n    (*N)++;\n\n    if (*N == Context->BytesPerRow)\n    {\n        *N = 0;\n        *X = Context->HexOffset;\n        *Y += Context->LineHeight;\n    }\n}\n\nFORCEINLINE VOID PhpPrintAscii(\n    _In_ HDC hdc,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ UCHAR Byte,\n    _Inout_ PLONG X,\n    _Inout_ PLONG Y,\n    _Inout_ PULONG N\n    )\n{\n    WCHAR c;\n\n    c = PhpIsPrintable(Context, Byte) ? Byte : '.';\n    TextOut(hdc, *X, *Y, &c, 1);\n    *X += Context->NullWidth;\n    (*N)++;\n\n    if (*N == Context->BytesPerRow)\n    {\n        *N = 0;\n        *X = Context->AsciiOffset;\n        *Y += Context->LineHeight;\n    }\n}\n\nFORCEINLINE COLORREF GetLighterHighlightColor(\n    VOID\n    )\n{\n    COLORREF color;\n    UCHAR r;\n    UCHAR g;\n    UCHAR b;\n\n    color = GetSysColor(COLOR_HIGHLIGHT);\n    r = (UCHAR)color;\n    g = (UCHAR)(color >> 8);\n    b = (UCHAR)(color >> 16);\n\n    if (r <= 255 - 64)\n        r += 64;\n    else\n        r = 255;\n\n    if (g <= 255 - 64)\n        g += 64;\n    else\n        g = 255;\n\n    if (b <= 255 - 64)\n        b += 64;\n    else\n        b = 255;\n\n    return RGB(r, g, b);\n}\n\nVOID PhpHexEditUpdateMetrics(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ BOOLEAN UpdateLineHeight,\n    _In_opt_ HDC hdc\n    )\n{\n    BOOLEAN freeHdc = FALSE;\n    RECT clientRect;\n    SIZE size;\n\n    if (!hdc && UpdateLineHeight)\n    {\n        hdc = CreateCompatibleDC(hdc);\n        SelectFont(hdc, Context->Font);\n        freeHdc = TRUE;\n    }\n\n    GetClientRect(hwnd, &clientRect);\n\n    if (UpdateLineHeight)\n    {\n        GetCharWidth(hdc, '0', '0', &Context->NullWidth);\n        GetTextExtentPoint32(hdc, L\"0\", 1, &size);\n        Context->LineHeight = size.cy;\n    }\n\n    Context->HexOffset = Context->ShowAddress ? (Context->AddressIsWide ? Context->NullWidth * 9 : Context->NullWidth * 5) : 0;\n    Context->AsciiOffset = Context->HexOffset + (Context->ShowHex ? (Context->BytesPerRow * 3 * Context->NullWidth) : 0);\n\n    if (Context->LineHeight != 0)\n    {\n        Context->LinesPerPage = clientRect.bottom / Context->LineHeight;\n        Context->HalfPage = FALSE;\n\n        if (Context->LinesPerPage * Context->BytesPerRow > Context->Length)\n        {\n            Context->LinesPerPage = (Context->Length + Context->BytesPerRow / 2) / Context->BytesPerRow;\n\n            if (Context->Length % Context->BytesPerRow != 0)\n            {\n                Context->HalfPage = TRUE;\n                Context->LinesPerPage++;\n            }\n        }\n    }\n\n    if (freeHdc && hdc)\n        DeleteDC(hdc);\n}\n\nVOID PhpHexEditOnPaint(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PAINTSTRUCT *PaintStruct,\n    _In_ HDC hdc\n    )\n{\n    RECT clientRect;\n    HDC bufferDc;\n    HBITMAP bufferBitmap;\n    HBITMAP oldBufferBitmap;\n    LONG height;\n    LONG x;\n    LONG y;\n    LONG i;\n    ULONG requiredBufferLength;\n    PWCHAR buffer;\n\n    GetClientRect(hwnd, &clientRect);\n\n    bufferDc = CreateCompatibleDC(hdc);\n    bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom);\n    oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap);\n\n    SetDCBrushColor(bufferDc, GetSysColor(COLOR_WINDOW));\n    FillRect(bufferDc, &clientRect, PhGetStockBrush(DC_BRUSH));\n    SelectFont(bufferDc, Context->Font);\n    SetBoundsRect(bufferDc, &clientRect, DCB_DISABLE);\n\n    requiredBufferLength = (max(8, Context->BytesPerRow * 3) + 1) * sizeof(WCHAR);\n\n    if (Context->CharBufferLength < requiredBufferLength)\n    {\n        if (Context->CharBuffer)\n            PhFree(Context->CharBuffer);\n\n        Context->CharBuffer = PhAllocate(requiredBufferLength);\n        Context->CharBufferLength = requiredBufferLength;\n        buffer = Context->CharBuffer;\n    }\n\n    buffer = Context->CharBuffer;\n\n    if (Context->Data)\n    {\n        // Get character dimensions.\n        if (Context->Update)\n        {\n            PhpHexEditUpdateMetrics(hwnd, Context, TRUE, bufferDc);\n            Context->Update = FALSE;\n            PhpHexEditUpdateScrollbars(hwnd, Context);\n        }\n\n        height = (clientRect.bottom + Context->LineHeight - 1) / Context->LineHeight * Context->LineHeight; // round up to height\n\n        if (Context->ShowAddress)\n        {\n            PH_FORMAT format;\n            ULONG w;\n            RECT rect;\n\n            PhInitFormatX(&format, 0);\n            format.Type |= FormatPadZeros;\n            format.Width = Context->AddressIsWide ? 8 : 4;\n\n            w = Context->AddressIsWide ? 8 : 4;\n\n            rect = clientRect;\n            rect.left = Context->AddressOffset;\n            rect.top = 0;\n\n            for (i = Context->TopIndex; i < Context->Length && rect.top < height; i += Context->BytesPerRow)\n            {\n                format.u.Int32 = i;\n                PhFormatToBuffer(&format, 1, buffer, requiredBufferLength, NULL);\n                DrawText(bufferDc, buffer, w, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);\n                rect.top += Context->LineHeight;\n            }\n        }\n\n        if (Context->ShowHex)\n        {\n            RECT rect;\n            LONG n = 0;\n\n            x = Context->HexOffset;\n            y = 0;\n            rect = clientRect;\n            rect.left = x;\n            rect.top = 0;\n\n            if (Context->SelStart != -1)\n            {\n                COLORREF highlightColor;\n                LONG selStart;\n                LONG selEnd;\n\n                if (Context->CurrentMode == EDIT_HIGH || Context->CurrentMode == EDIT_LOW)\n                    highlightColor = GetSysColor(COLOR_HIGHLIGHT);\n                else\n                    highlightColor = GetLighterHighlightColor();\n\n                selStart = Context->SelStart;\n                selEnd = Context->SelEnd;\n\n                if (selStart > selEnd)\n                {\n                    ULONG t;\n\n                    t = selEnd;\n                    selEnd = selStart;\n                    selStart = t;\n                }\n\n                if (selStart >= Context->Length)\n                    selStart = Context->Length - 1;\n                if (selEnd > Context->Length)\n                    selEnd = Context->Length;\n\n                // Bytes before the selection\n\n                for (i = Context->TopIndex; i < selStart && y < height; i++)\n                {\n                    PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n);\n                }\n\n                // Bytes in the selection\n\n                SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                SetBkColor(bufferDc, highlightColor);\n\n                for (; i < selEnd && i < Context->Length && y < height; i++)\n                {\n                    PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n);\n                }\n\n                // Bytes after the selection\n\n                SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT));\n                SetBkColor(bufferDc, GetSysColor(COLOR_WINDOW));\n\n                for (; i < Context->Length && y < height; i++)\n                {\n                    PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n);\n                }\n            }\n            else\n            {\n                i = Context->TopIndex;\n\n                while (i < Context->Length && rect.top < height)\n                {\n                    PWCHAR p = buffer;\n\n                    for (n = 0; n < Context->BytesPerRow && i < Context->Length; n++)\n                    {\n                        TO_HEX(p, Context->Data[i]);\n                        *p++ = ' ';\n                        i++;\n                    }\n\n                    while (n < Context->BytesPerRow)\n                    {\n                        p[0] = ' ';\n                        p[1] = ' ';\n                        p[2] = ' ';\n                        p += 3;\n                        n++;\n                    }\n\n                    DrawText(bufferDc, buffer, Context->BytesPerRow * 3, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);\n                    rect.top += Context->LineHeight;\n                }\n            }\n        }\n\n        if (Context->ShowAscii)\n        {\n            RECT rect;\n            LONG n = 0;\n\n            x = Context->AsciiOffset;\n            y = 0;\n            rect = clientRect;\n            rect.left = x;\n            rect.top = 0;\n\n            if (Context->SelStart != -1)\n            {\n                COLORREF highlightColor;\n                LONG selStart;\n                LONG selEnd;\n\n                if (Context->CurrentMode == EDIT_ASCII)\n                    highlightColor = GetSysColor(COLOR_HIGHLIGHT);\n                else\n                    highlightColor = GetLighterHighlightColor();\n\n                selStart = Context->SelStart;\n                selEnd = Context->SelEnd;\n\n                if (selStart > selEnd)\n                {\n                    LONG t;\n\n                    t = selEnd;\n                    selEnd = selStart;\n                    selStart = t;\n                }\n\n                if (selStart >= Context->Length)\n                    selStart = Context->Length - 1;\n                if (selEnd > Context->Length)\n                    selEnd = Context->Length;\n\n                // Bytes before the selection\n\n                for (i = Context->TopIndex; i < selStart && y < height; i++)\n                {\n                    PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n);\n                }\n\n                // Bytes in the selection\n\n                SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                SetBkColor(bufferDc, highlightColor);\n\n                for (; i < selEnd && i < Context->Length && y < height; i++)\n                {\n                    PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n);\n                }\n\n                // Bytes after the selection\n\n                SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT));\n                SetBkColor(bufferDc, GetSysColor(COLOR_WINDOW));\n\n                for (; i < Context->Length && y < height; i++)\n                {\n                    PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n);\n                }\n            }\n            else\n            {\n                i = Context->TopIndex;\n\n                while (i < Context->Length && rect.top < height)\n                {\n                    PWCHAR p = buffer;\n\n                    for (n = 0; n < Context->BytesPerRow && i < Context->Length; n++)\n                    {\n                        *p++ = PhpIsPrintable(Context, Context->Data[i]) ? Context->Data[i] : '.'; // 1\n                        i++;\n                    }\n\n                    DrawText(bufferDc, buffer, n, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);\n                    rect.top += Context->LineHeight;\n                }\n            }\n        }\n    }\n\n    BitBlt(hdc, 0, 0, clientRect.right, clientRect.bottom, bufferDc, 0, 0, SRCCOPY);\n    SelectBitmap(bufferDc, oldBufferBitmap);\n    DeleteBitmap(bufferBitmap);\n    DeleteDC(bufferDc);\n}\n\nVOID PhpHexEditUpdateScrollbars(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    SCROLLINFO si = { sizeof(si) };\n\n    si.fMask = SIF_ALL;\n    si.nMin = 0;\n    si.nMax = Context->Length / Context->BytesPerRow;\n    si.nPage = Context->LinesPerPage;\n    si.nPos = Context->TopIndex / Context->BytesPerRow;\n    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);\n\n    if (si.nMax > (LONG)si.nPage - 1)\n        EnableScrollBar(hwnd, SB_VERT, ESB_ENABLE_BOTH);\n\n    // No horizontal scrollbar please.\n    /*si.nMin = 0;\n    si.nMax = ((Context->ShowAddress ? (Context->AddressIsWide ? 8 : 4) : 0) +\n        (Context->ShowHex ? Context->BytesPerRow * 3 : 0) +\n        (Context->ShowAscii ? Context->BytesPerRow : 0)) * Context->NullWidth;\n    si.nPage = 1;\n    si.nPos = 0;\n    SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);*/\n}\n\nVOID PhpHexEditCreateAddressCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    DestroyCaret();\n    CreateCaret(hwnd, NULL, Context->NullWidth * (Context->AddressIsWide ? 8 : 4), Context->LineHeight);\n}\n\nVOID PhpHexEditCreateEditCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    DestroyCaret();\n    CreateCaret(hwnd, NULL, Context->NullWidth, Context->LineHeight);\n}\n\nVOID PhpHexEditRepositionCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG Position\n    )\n{\n    ULONG x;\n    ULONG y;\n    RECT rect;\n\n    x = (Position - Context->TopIndex) % Context->BytesPerRow;\n    y = (Position - Context->TopIndex) / Context->BytesPerRow;\n\n    switch (Context->CurrentMode)\n    {\n    case EDIT_NONE:\n        PhpHexEditCreateAddressCaret(hwnd, Context);\n        x = 0;\n        break;\n    case EDIT_HIGH:\n        PhpHexEditCreateEditCaret(hwnd, Context);\n        x *= Context->NullWidth * 3;\n        x += Context->HexOffset;\n        break;\n    case EDIT_LOW:\n        PhpHexEditCreateEditCaret(hwnd, Context);\n        x *= Context->NullWidth * 3;\n        x += Context->NullWidth;\n        x += Context->HexOffset;\n        break;\n    case EDIT_ASCII:\n        PhpHexEditCreateEditCaret(hwnd, Context);\n        x *= Context->NullWidth;\n        x += Context->AsciiOffset;\n        break;\n    }\n\n    Context->EditPosition.x = x;\n    Context->EditPosition.y = y * Context->LineHeight;\n\n    GetClientRect(hwnd, &rect);\n\n    if (PhPtInRect(&rect, &Context->EditPosition))\n    {\n        SetCaretPos(Context->EditPosition.x, Context->EditPosition.y);\n        ShowCaret(hwnd);\n    }\n}\n\nVOID PhpHexEditCalculatePosition(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _Out_ POINT *Point\n    )\n{\n    LONG xp;\n\n    Y /= Context->LineHeight;\n\n    if (Y < 0 || Y >= Context->LinesPerPage)\n    {\n        Point->x = -1;\n        Point->y = -1;\n        return;\n    }\n\n    if (Y * Context->BytesPerRow >= Context->Length)\n    {\n        Point->x = -1;\n        Point->y = -1;\n        return;\n    }\n\n    X += Context->NullWidth;\n    X /= Context->NullWidth;\n\n    if (Context->ShowAddress && X <= (Context->AddressIsWide ? 8 : 4))\n    {\n        Context->CurrentAddress = Context->TopIndex + Context->BytesPerRow * Y;\n        Context->CurrentMode = EDIT_NONE;\n\n        Point->x = 0;\n        Point->y = Y;\n        return;\n    }\n\n    xp = Context->HexOffset / Context->NullWidth + Context->BytesPerRow * 3;\n\n    if (Context->ShowHex && X < xp)\n    {\n        if (X % 3)\n            X--;\n\n        Context->CurrentAddress = Context->TopIndex +\n            Context->BytesPerRow * Y +\n            (X - (Context->HexOffset / Context->NullWidth)) / 3;\n        Context->CurrentMode = ((X % 3) & 1) ? EDIT_LOW : EDIT_HIGH;\n\n        Point->x = X;\n        Point->y = Y;\n        return;\n    }\n\n    X--; // fix selection problem\n\n    xp = Context->AsciiOffset / Context->NullWidth + Context->BytesPerRow;\n\n    if (Context->ShowAscii && X * Context->NullWidth >= Context->AsciiOffset && X <= xp)\n    {\n        Context->CurrentAddress = Context->TopIndex +\n            Context->BytesPerRow * Y +\n            (X - (Context->AsciiOffset / Context->NullWidth));\n        Context->CurrentMode = EDIT_ASCII;\n\n        Point->x = X;\n        Point->y = Y;\n        return;\n    }\n\n    Point->x = -1;\n    Point->y = -1;\n}\n\nVOID PhpHexEditMove(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y\n    )\n{\n    switch (Context->CurrentMode)\n    {\n    case EDIT_NONE:\n        Context->CurrentAddress += Y * Context->BytesPerRow;\n        break;\n    case EDIT_HIGH:\n        if (X != 0)\n            Context->CurrentMode = EDIT_LOW;\n        if (X == -1)\n            Context->CurrentAddress--;\n        Context->CurrentAddress += Y * Context->BytesPerRow;\n        break;\n    case EDIT_LOW:\n        if (X != 0)\n            Context->CurrentMode = EDIT_HIGH;\n        if (X == 1)\n            Context->CurrentAddress++;\n        Context->CurrentAddress += Y * Context->BytesPerRow;\n        break;\n    case EDIT_ASCII:\n        Context->CurrentAddress += X;\n        Context->CurrentAddress += Y * Context->BytesPerRow;\n        break;\n    }\n\n    if (Context->CurrentAddress < 0)\n        Context->CurrentAddress = 0;\n\n    if (Context->CurrentAddress >= Context->Length)\n    {\n        Context->CurrentAddress -= X;\n        Context->CurrentAddress -= Y * Context->BytesPerRow;\n    }\n\n    Context->NoAddressChange = TRUE;\n\n    if (Context->CurrentAddress < Context->TopIndex)\n        SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);\n    if (Context->CurrentAddress >= Context->TopIndex + Context->LinesPerPage * Context->BytesPerRow)\n        SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);\n\n    Context->NoAddressChange = FALSE;\n    PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress);\n}\n\nVOID PhpHexEditSetSel(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG E\n    )\n{\n    DestroyCaret();\n    Context->SelStart = S;\n    Context->SelEnd = E;\n    REDRAW_WINDOW(hwnd);\n\n    if (S != -1 && E != -1)\n    {\n        Context->CurrentAddress = S;\n    }\n    else\n    {\n        if (Context->EditPosition.x == 0 && Context->ShowAddress)\n            PhpHexEditCreateAddressCaret(hwnd, Context);\n        else\n            PhpHexEditCreateEditCaret(hwnd, Context);\n\n        SetCaretPos(Context->EditPosition.x, Context->EditPosition.y);\n        ShowCaret(hwnd);\n    }\n}\n\nVOID PhpHexEditScrollTo(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG Position\n    )\n{\n    if (Position < Context->TopIndex || Position > Context->TopIndex + Context->LinesPerPage * Context->BytesPerRow)\n    {\n        Context->TopIndex = Position / Context->BytesPerRow * Context->BytesPerRow; // round down\n        Context->TopIndex -= Context->LinesPerPage / 3 * Context->BytesPerRow;\n\n        if (Context->TopIndex < 0)\n            Context->TopIndex = 0;\n\n        if (Context->Length >= Context->LinesPerPage * Context->BytesPerRow)\n        {\n            if (Context->TopIndex > Context->Length - Context->LinesPerPage * Context->BytesPerRow)\n                Context->TopIndex = Context->Length - Context->LinesPerPage * Context->BytesPerRow;\n        }\n\n        PhpHexEditUpdateScrollbars(hwnd, Context);\n        REDRAW_WINDOW(hwnd);\n    }\n}\n\nVOID PhpHexEditClearEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (Context->AllowLengthChange)\n    {\n        Context->CurrentAddress = Context->SelStart;\n        PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd);\n        PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress);\n        REDRAW_WINDOW(hwnd);\n    }\n}\n\nVOID PhpHexEditCopyEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (OpenClipboard(hwnd))\n    {\n        EmptyClipboard();\n        PhpHexEditNormalizeSel(hwnd, Context);\n\n        if (Context->CurrentMode != EDIT_ASCII)\n        {\n            ULONG length = Context->SelEnd - Context->SelStart;\n            HGLOBAL binaryMemory;\n            HGLOBAL hexMemory;\n\n            binaryMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length);\n\n            if (binaryMemory)\n            {\n                PUCHAR p = GlobalLock(binaryMemory);\n                memcpy(p, &Context->Data[Context->SelStart], length);\n                GlobalUnlock(binaryMemory);\n\n                hexMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (length * 3 + 1) * sizeof(WCHAR));\n\n                if (hexMemory)\n                {\n                    PWCHAR pw;\n                    ULONG i;\n\n                    pw = GlobalLock(hexMemory);\n\n                    for (i = 0; i < length; i++)\n                    {\n                        TO_HEX(pw, Context->Data[Context->SelStart + i]);\n                        *pw++ = ' ';\n                    }\n                    *pw = 0;\n\n                    GlobalUnlock(hexMemory);\n\n                    SetClipboardData(CF_UNICODETEXT, hexMemory);\n                }\n\n                SetClipboardData(RegisterClipboardFormat(L\"BinaryData\"), binaryMemory);\n            }\n        }\n        else\n        {\n            ULONG length = Context->SelEnd - Context->SelStart;\n            HGLOBAL binaryMemory;\n            HGLOBAL asciiMemory;\n\n            binaryMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length);\n            asciiMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length + 1);\n\n            if (binaryMemory)\n            {\n                PUCHAR p = GlobalLock(binaryMemory);\n                memcpy(p, &Context->Data[Context->SelStart], length);\n                GlobalUnlock(binaryMemory);\n\n                if (asciiMemory)\n                {\n                    ULONG i;\n\n                    p = GlobalLock(asciiMemory);\n                    memcpy(p, &Context->Data[Context->SelStart], length);\n\n                    for (i = 0; i < length; i++)\n                    {\n                        if (!PhpIsPrintable(Context, *p))\n                            *p = '.';\n                        p++;\n                    }\n                    *p = 0;\n\n                    GlobalUnlock(asciiMemory);\n\n                    SetClipboardData(CF_TEXT, asciiMemory);\n                }\n\n                SetClipboardData(RegisterClipboardFormat(L\"BinaryData\"), binaryMemory);\n            }\n        }\n\n        CloseClipboard();\n    }\n}\n\nVOID PhpHexEditCutEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (Context->AllowLengthChange)\n    {\n        PhpHexEditCopyEdit(hwnd, Context);\n        PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd);\n        REDRAW_WINDOW(hwnd);\n    }\n}\n\nVOID PhpHexEditPasteEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (OpenClipboard(hwnd))\n    {\n        HANDLE memory;\n\n        memory = GetClipboardData(RegisterClipboardFormat(L\"BinaryData\"));\n\n        if (!memory)\n            memory = GetClipboardData(CF_TEXT);\n\n        if (memory)\n        {\n            PUCHAR p = GlobalLock(memory);\n            ULONG length = (ULONG)GlobalSize(memory);\n            ULONG paste;\n            ULONG oldCurrentAddress = Context->CurrentAddress;\n\n            PhpHexEditNormalizeSel(hwnd, Context);\n\n            if (Context->AllowLengthChange)\n            {\n                if (Context->SelStart == -1)\n                {\n                    if (Context->CurrentMode == EDIT_LOW)\n                        Context->CurrentAddress++;\n\n                    paste = Context->CurrentAddress;\n                    PhpHexEditSelInsert(hwnd, Context, Context->CurrentAddress, length);\n                }\n                else\n                {\n                    paste = Context->SelStart;\n                    PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd);\n                    PhpHexEditSelInsert(hwnd, Context, paste, length);\n                    PhpHexEditSetSel(hwnd, Context, -1, -1);\n                }\n            }\n            else\n            {\n                if (Context->SelStart == -1)\n                {\n                    if (Context->CurrentMode == EDIT_LOW)\n                        Context->CurrentAddress++;\n\n                    paste = Context->CurrentAddress;\n                }\n                else\n                {\n                    paste = Context->SelStart;\n                }\n\n                if (length > Context->Length - paste)\n                    length = Context->Length - paste;\n            }\n\n            memcpy(&Context->Data[paste], p, length);\n            GlobalUnlock(memory);\n\n            Context->CurrentAddress = oldCurrentAddress;\n            REDRAW_WINDOW(hwnd);\n        }\n\n        CloseClipboard();\n    }\n}\n\nVOID PhpHexEditSelectAll(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    Context->SelStart = 0;\n    Context->SelEnd = Context->Length;\n    DestroyCaret();\n    REDRAW_WINDOW(hwnd);\n}\n\nVOID PhpHexEditUndoEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    // TODO\n}\n\nVOID PhpHexEditNormalizeSel(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (Context->SelStart > Context->SelEnd)\n    {\n        LONG t;\n\n        t = Context->SelEnd;\n        Context->SelEnd = Context->SelStart;\n        Context->SelStart = t;\n    }\n}\n\nVOID PhpHexEditSelDelete(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG E\n    )\n{\n    if (Context->AllowLengthChange && Context->Length > 0)\n    {\n        PUCHAR p = PhAllocate(Context->Length - (E - S) + 1);\n\n        memcpy(p, Context->Data, S);\n\n        if (S < Context->Length - (E - S))\n            memcpy(&p[S], &Context->Data[E], Context->Length - E);\n\n        PhFree(Context->Data);\n        Context->Data = p;\n        PhpHexEditSetSel(hwnd, Context, -1, -1);\n        Context->Length -= E - S;\n\n        if (Context->CurrentAddress > Context->Length)\n        {\n            Context->CurrentAddress = Context->Length;\n            PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress);\n        }\n\n        Context->Update = TRUE;\n    }\n}\n\nVOID PhpHexEditSelInsert(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG L\n    )\n{\n    if (Context->AllowLengthChange)\n    {\n        PUCHAR p = PhAllocate(Context->Length + L);\n\n        memset(p, 0, Context->Length + L);\n        memcpy(p, Context->Data, S);\n        memcpy(&p[S + L], &Context->Data[S], Context->Length - S);\n\n        PhFree(Context->Data);\n        Context->Data = p;\n        PhpHexEditSetSel(hwnd, Context, -1, -1);\n        Context->Length += L;\n\n        Context->Update = TRUE;\n    }\n}\n\nVOID PhpHexEditSetBuffer(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PUCHAR Data,\n    _In_ ULONG Length\n    )\n{\n    Context->Data = Data;\n    PhpHexEditSetSel(hwnd, Context, -1, -1);\n    Context->Length = Length;\n    Context->CurrentAddress = 0;\n    Context->EditPosition.x = Context->EditPosition.y = 0;\n    Context->CurrentMode = EDIT_HIGH;\n    Context->TopIndex = 0;\n    Context->Update = TRUE;\n\n    Context->UserBuffer = TRUE;\n    Context->AllowLengthChange = FALSE;\n}\n\nVOID PhpHexEditSetData(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PUCHAR Data,\n    _In_ ULONG Length\n    )\n{\n    if (Context->Data) PhFree(Context->Data);\n    Context->Data = PhAllocate(Length);\n    memcpy(Context->Data, Data, Length);\n    PhpHexEditSetBuffer(hwnd, Context, Context->Data, Length);\n    Context->UserBuffer = FALSE;\n    Context->AllowLengthChange = TRUE;\n}\n"
  },
  {
    "path": "phlib/hndlinfo.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <hndlinfo.h>\n#include <json.h>\n#include <kphuser.h>\n#include <lsasup.h>\n\n#include <devquery.h>\n#include <devpkey.h>\n#include <phafd.h>\n\n#define PH_QUERY_HACK_MAX_THREADS 20\n\ntypedef struct _PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT\n{\n    SLIST_ENTRY ListEntry;\n\n    PUSER_THREAD_START_ROUTINE Routine;\n    PVOID Context;\n\n    HANDLE StartEventHandle;\n    HANDLE CompletedEventHandle;\n    HANDLE ThreadHandle;\n} PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT, *PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT;\n\ntypedef enum _PHP_QUERY_OBJECT_WORK\n{\n    NtQueryObjectWork,\n    NtQuerySecurityObjectWork,\n    NtSetSecurityObjectWork,\n    NtQueryFileInformationWork,\n    KphQueryFileInformationWork\n} PHP_QUERY_OBJECT_WORK;\n\ntypedef struct _PHP_QUERY_OBJECT_COMMON_CONTEXT\n{\n    PHP_QUERY_OBJECT_WORK Work;\n    NTSTATUS Status;\n\n    union\n    {\n        struct\n        {\n            HANDLE Handle;\n            OBJECT_INFORMATION_CLASS ObjectInformationClass;\n            PVOID ObjectInformation;\n            ULONG ObjectInformationLength;\n            PULONG ReturnLength;\n        } NtQueryObject;\n        struct\n        {\n            HANDLE Handle;\n            SECURITY_INFORMATION SecurityInformation;\n            PSECURITY_DESCRIPTOR SecurityDescriptor;\n            ULONG Length;\n            PULONG LengthNeeded;\n        } NtQuerySecurityObject;\n        struct\n        {\n            HANDLE Handle;\n            SECURITY_INFORMATION SecurityInformation;\n            PSECURITY_DESCRIPTOR SecurityDescriptor;\n        } NtSetSecurityObject;\n        struct\n        {\n            HANDLE Handle;\n            FILE_INFORMATION_CLASS FileInformationClass;\n            PVOID FileInformation;\n            ULONG FileInformationLength;\n        } NtQueryFileInformation;\n        struct\n        {\n            HANDLE ProcessHandle;\n            HANDLE Handle;\n            FILE_INFORMATION_CLASS FileInformationClass;\n            PVOID FileInformation;\n            ULONG FileInformationLength;\n        } KphQueryFileInformation;\n\n    } u;\n} PHP_QUERY_OBJECT_COMMON_CONTEXT, *PPHP_QUERY_OBJECT_COMMON_CONTEXT;\n\nPPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread(\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nVOID PhpReleaseCallWithTimeoutThread(\n    _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext\n    );\n\nNTSTATUS PhpCallWithTimeout(\n    _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext,\n    _In_ PUSER_THREAD_START_ROUTINE Routine,\n    _In_opt_ PVOID Context,\n    _In_ PLARGE_INTEGER Timeout\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpCallWithTimeoutThreadStart(\n    _In_ PVOID Parameter\n    );\n\nBOOLEAN PhEnableProcessHandlePnPDeviceNameSupport = FALSE;\n\nstatic PPH_STRING PhObjectTypeNames[MAX_OBJECT_TYPE_NUMBER] = { 0 };\nstatic PPH_GET_CLIENT_ID_NAME PhHandleGetClientIdName = PhStdGetClientIdName;\n\nstatic SLIST_HEADER PhpCallWithTimeoutThreadListHead;\nstatic PH_WAKE_EVENT PhpCallWithTimeoutThreadReleaseEvent = PH_WAKE_EVENT_INIT;\n\nPPH_GET_CLIENT_ID_NAME PhSetHandleClientIdFunction(\n    _In_ PPH_GET_CLIENT_ID_NAME GetClientIdName\n    )\n{\n    return _InterlockedExchangePointer(\n        (PVOID *)&PhHandleGetClientIdName,\n        GetClientIdName\n        );\n}\n\nNTSTATUS PhGetObjectBasicInformation(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _Out_ POBJECT_BASIC_INFORMATION BasicInformation\n    )\n{\n    NTSTATUS status;\n\n    if (KsiLevel() >= KphLevelMed && ProcessHandle)\n    {\n        status = KphQueryInformationObject(\n            ProcessHandle,\n            Handle,\n            KphObjectBasicInformation,\n            BasicInformation,\n            sizeof(OBJECT_BASIC_INFORMATION),\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // The object was referenced in KSystemInformer, so we need to subtract 1 from the\n            // pointer count.\n            BasicInformation->PointerCount -= 1;\n        }\n    }\n    else\n    {\n        ULONG returnLength;\n\n        status = NtQueryObject(\n            Handle,\n            ObjectBasicInformation,\n            BasicInformation,\n            sizeof(OBJECT_BASIC_INFORMATION),\n            &returnLength\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // The object was referenced in NtQueryObject and a handle was opened to the object. We\n            // need to subtract 1 from the pointer count, then subtract 1 from both counts.\n            BasicInformation->HandleCount -= 1;\n            BasicInformation->PointerCount -= 2;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetObjectTypeName(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Out_ PPH_STRING *TypeName\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    PPH_STRING typeName = NULL;\n\n    // Enumerate the available object types and pre-cache the object type name. (dmex)\n    if (WindowsVersion >= WINDOWS_8_1)\n    {\n        static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n        if (PhBeginInitOnce(&initOnce))\n        {\n            POBJECT_TYPES_INFORMATION objectTypes;\n            POBJECT_TYPE_INFORMATION objectType;\n\n            if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes)))\n            {\n                objectType = PH_FIRST_OBJECT_TYPE(objectTypes);\n\n                for (ULONG i = 0; i < objectTypes->NumberOfTypes; i++)\n                {\n                    PhMoveReference(\n                        &PhObjectTypeNames[objectType->TypeIndex],\n                        PhCreateStringFromUnicodeString(&objectType->TypeName)\n                        );\n\n                    objectType = PH_NEXT_OBJECT_TYPE(objectType);\n                }\n\n                PhFree(objectTypes);\n            }\n\n            PhEndInitOnce(&initOnce);\n        }\n    }\n\n    // If the cache contains the object type name, use it. Otherwise, query the type name. (dmex)\n\n    if (ObjectTypeNumber != ULONG_MAX && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER)\n        typeName = PhObjectTypeNames[ObjectTypeNumber];\n\n    if (typeName)\n    {\n        PhReferenceObject(typeName);\n    }\n    else\n    {\n        POBJECT_TYPE_INFORMATION buffer;\n        ULONG returnLength = 0;\n        PPH_STRING oldTypeName;\n        KPH_LEVEL level;\n\n        level = KsiLevel();\n\n        // Get the needed buffer size.\n        if (level >= KphLevelMed)\n        {\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectTypeInformation,\n                NULL,\n                0,\n                &returnLength\n                );\n        }\n        else\n        {\n            status = NtQueryObject(\n                Handle,\n                ObjectTypeInformation,\n                NULL,\n                0,\n                &returnLength\n                );\n        }\n\n        if (returnLength == 0)\n            return STATUS_UNSUCCESSFUL;\n\n        buffer = PhAllocate(returnLength);\n\n        if (level >= KphLevelMed)\n        {\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectTypeInformation,\n                buffer,\n                returnLength,\n                &returnLength\n                );\n        }\n        else\n        {\n            status = NtQueryObject(\n                Handle,\n                ObjectTypeInformation,\n                buffer,\n                returnLength,\n                &returnLength\n                );\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhFree(buffer);\n            return status;\n        }\n\n        // Create a copy of the type name.\n        typeName = PhCreateStringFromUnicodeString(&buffer->TypeName);\n\n        if (ObjectTypeNumber != ULONG_MAX && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER)\n        {\n            // Try to store the type name in the cache.\n            oldTypeName = _InterlockedCompareExchangePointer(\n                &PhObjectTypeNames[ObjectTypeNumber],\n                typeName,\n                NULL\n                );\n\n            // Add a reference if we stored the type name successfully.\n            if (PhIsNullOrEmptyString(oldTypeName))\n            {\n                PhReferenceObject(typeName);\n            }\n        }\n\n        PhFree(buffer);\n    }\n\n    // At this point typeName should contain a type name with one additional reference.\n\n    *TypeName = typeName;\n\n    return status;\n}\n\nNTSTATUS PhGetObjectName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ BOOLEAN WithTimeout,\n    _Out_ PPH_STRING *ObjectName\n    )\n{\n    NTSTATUS status;\n    POBJECT_NAME_INFORMATION buffer;\n    ULONG bufferSize;\n    ULONG attempts = 8;\n\n    bufferSize = sizeof(OBJECT_NAME_INFORMATION) + (MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR));\n    buffer = PhAllocate(bufferSize);\n\n    // A loop is needed because the I/O subsystem likes to give us the wrong return lengths... (wj32)\n    do\n    {\n        if (KsiLevel() >= KphLevelMed)\n        {\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectNameInformation,\n                buffer,\n                bufferSize,\n                &bufferSize\n                );\n        }\n        else\n        {\n            if (WithTimeout)\n            {\n                status = PhCallNtQueryObjectWithTimeout(\n                    Handle,\n                    ObjectNameInformation,\n                    buffer,\n                    bufferSize,\n                    &bufferSize\n                    );\n            }\n            else\n            {\n                status = NtQueryObject(\n                    Handle,\n                    ObjectNameInformation,\n                    buffer,\n                    bufferSize,\n                    &bufferSize\n                    );\n            }\n        }\n\n        if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH ||\n            status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    } while (--attempts);\n\n    if (NT_SUCCESS(status))\n    {\n        if (RtlIsNullOrEmptyUnicodeString(&buffer->Name))\n        {\n            status = STATUS_OBJECT_NAME_INVALID;\n        }\n        else\n        {\n            *ObjectName = PhCreateStringFromUnicodeString(&buffer->Name);\n        }\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\nNTSTATUS PhQueryObjectName(\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING *ObjectName\n    )\n{\n    if (Handle == NULL || Handle == NtCurrentProcess() || Handle == NtCurrentThread())\n        return STATUS_INVALID_HANDLE;\n\n    return PhGetObjectName(NtCurrentProcess(), Handle, FALSE, ObjectName);\n}\n\nNTSTATUS PhQueryObjectBasicInformation(\n    _In_ HANDLE Handle,\n    _Out_ POBJECT_BASIC_INFORMATION BasicInformation\n    )\n{\n    if (Handle == NULL || Handle == NtCurrentProcess() || Handle == NtCurrentThread())\n        return STATUS_INVALID_HANDLE;\n\n    return PhGetObjectBasicInformation(NtCurrentProcess(), Handle, BasicInformation);\n}\n\nNTSTATUS PhQueryCloseHandle(\n    _In_ _Post_ptr_invalid_ HANDLE Handle\n    )\n{\n    NTSTATUS status;\n    OBJECT_HANDLE_FLAG_INFORMATION objectInfo = { 0 };\n\n    status = NtQueryObject(\n        Handle,\n        ObjectHandleFlagInformation,\n        &objectInfo,\n        sizeof(objectInfo),\n        NULL\n        );\n\n    if (NT_SUCCESS(status) && objectInfo.ProtectFromClose)\n    {\n        objectInfo.ProtectFromClose = FALSE;\n        NtSetInformationObject(\n            Handle,\n            ObjectHandleFlagInformation,\n            &objectInfo,\n            sizeof(objectInfo)\n            );\n    }\n\n    status = NtClose(Handle);\n    return status;\n}\n\nNTSTATUS PhCompareObjects(\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle\n    )\n{\n    NTSTATUS status;\n\n    if (NtCompareObjects_Import())\n    {\n        status = NtCompareObjects_Import()(\n            FirstObjectHandle,\n            SecondObjectHandle\n            );\n    }\n    else\n    {\n        status = STATUS_NOT_SUPPORTED;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetEtwObjectName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING *ObjectName\n    )\n{\n    NTSTATUS status;\n    KPH_ETWREG_BASIC_INFORMATION basicInfo;\n\n    if (KsiLevel() >= KphLevelMed)\n    {\n        status = KphQueryInformationObject(\n            ProcessHandle,\n            Handle,\n            KphObjectEtwRegBasicInformation,\n            &basicInfo,\n            sizeof(KPH_ETWREG_BASIC_INFORMATION),\n            NULL\n            );\n    }\n    else\n    {\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *ObjectName = PhFormatGuid(&basicInfo.Guid);\n    }\n\n    return status;\n}\n\ntypedef struct _PH_ETW_TRACEGUID_ENTRY\n{\n    PPH_STRING Name;\n    PGUID Guid;\n} PH_ETW_TRACEGUID_ENTRY, *PPH_ETW_TRACEGUID_ENTRY;\n\nVOID PhInitializeEtwTraceGuidCache(\n    _Inout_ PPH_ARRAY EtwTraceGuidArrayList\n    )\n{\n    PPH_BYTES guidListString = NULL;\n    PPH_STRING guidListFileName;\n    PVOID jsonObject;\n    ULONG arrayLength;\n\n    if (guidListFileName = PhGetApplicationDirectoryFileNameZ(L\"Resources\\\\EtwGuids.txt\", TRUE))\n    {\n        PhFileReadAllText(&guidListString, &guidListFileName->sr, TRUE);\n        PhDereferenceObject(guidListFileName);\n    }\n\n    if (!guidListString)\n        return;\n\n    PhInitializeArray(EtwTraceGuidArrayList, sizeof(PH_ETW_TRACEGUID_ENTRY), 2000);\n\n    if (!NT_SUCCESS(PhCreateJsonParserEx(&jsonObject, guidListString, FALSE)))\n        return;\n\n    if (!(arrayLength = PhGetJsonArrayLength(jsonObject)))\n    {\n        PhFreeJsonObject(jsonObject);\n        return;\n    }\n\n    for (ULONG i = 0; i < arrayLength; i++)\n    {\n        PVOID jsonArrayObject;\n        PPH_STRING guidString;\n        PPH_STRING guidName;\n        GUID guid;\n        PH_ETW_TRACEGUID_ENTRY result;\n\n        if (!(jsonArrayObject = PhGetJsonArrayIndexObject(jsonObject, i)))\n            continue;\n\n        guidString = PhGetJsonValueAsString(jsonArrayObject, \"guid\");\n        guidName = PhGetJsonValueAsString(jsonArrayObject, \"name\");\n        //guidGroup = PhGetJsonValueAsString(jsonArrayObject, \"group\");\n\n        if (!NT_SUCCESS(PhStringToGuid(&guidString->sr, &guid)))\n        {\n            PhDereferenceObject(guidName);\n            PhDereferenceObject(guidString);\n            continue;\n        }\n\n        result.Name = guidName;\n        result.Guid = PhAllocateCopy(&guid, sizeof(GUID));\n\n        PhAddItemArray(EtwTraceGuidArrayList, &result);\n\n        PhDereferenceObject(guidString);\n    }\n\n    PhFreeJsonObject(jsonObject);\n    PhDereferenceObject(guidListString);\n}\n\nPPH_STRING PhGetEtwTraceGuidName(\n    _In_ PGUID Guid\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PH_ARRAY etwTraceGuidArrayList;\n    PPH_ETW_TRACEGUID_ENTRY entry;\n    SIZE_T i;\n\n    if (WindowsVersion < WINDOWS_8)\n        return NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeEtwTraceGuidCache(&etwTraceGuidArrayList);\n        PhEndInitOnce(&initOnce);\n    }\n\n    for (i = 0; i < etwTraceGuidArrayList.Count; i++)\n    {\n        entry = PhItemArray(&etwTraceGuidArrayList, i);\n\n        if (IsEqualGUID(entry->Guid, Guid))\n        {\n            return PhReferenceObject(entry->Name);\n        }\n    }\n\n    return NULL;\n}\n\nPPH_STRING PhGetEtwPublisherName(\n    _In_ PGUID Guid\n    )\n{\n    static CONST PH_STRINGREF publishersKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\WINEVT\\\\Publishers\\\\\");\n    PPH_STRING guidString;\n    PPH_STRING keyName;\n    HANDLE keyHandle;\n    PPH_STRING publisherName = NULL;\n\n    guidString = PhFormatGuid(Guid);\n\n    // We should perform a lookup on the GUID to get the publisher name. (wj32)\n\n    keyName = PhConcatStringRef2(&publishersKeyName, &guidString->sr);\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &keyName->sr,\n        0\n        )))\n    {\n        publisherName = PhQueryRegistryString(keyHandle, NULL);\n\n        if (publisherName && publisherName->Length == 0)\n        {\n            PhDereferenceObject(publisherName);\n            publisherName = NULL;\n        }\n\n        PhQueryCloseHandle(keyHandle);\n    }\n\n    PhDereferenceObject(keyName);\n\n    if (publisherName)\n    {\n        PhDereferenceObject(guidString);\n        return publisherName;\n    }\n    else\n    {\n        if (publisherName = PhGetEtwTraceGuidName(Guid))\n        {\n            PhDereferenceObject(guidString);\n            return publisherName;\n        }\n\n        return guidString;\n    }\n}\n\nPPH_STRING PhGetPnPDeviceName(\n    _In_ PPH_STRING ObjectName\n    )\n{\n    PPH_STRING objectPnPDeviceName = NULL;\n    ULONG deviceCount = 0;\n    PDEV_OBJECT deviceObjects = NULL;\n    DEVPROPCOMPKEY deviceProperties[2];\n    DEVPROP_FILTER_EXPRESSION deviceFilter[1];\n    DEVPROPERTY deviceFilterProperty;\n    DEVPROPCOMPKEY deviceFilterCompoundProp;\n\n    memset(deviceProperties, 0, sizeof(deviceProperties));\n    deviceProperties[0].Key = DEVPKEY_NAME;\n    deviceProperties[0].Store = DEVPROP_STORE_SYSTEM;\n    deviceProperties[1].Key = DEVPKEY_Device_BusReportedDeviceDesc;\n    deviceProperties[1].Store = DEVPROP_STORE_SYSTEM;\n\n    memset(&deviceFilterCompoundProp, 0, sizeof(deviceFilterCompoundProp));\n    deviceFilterCompoundProp.Key = DEVPKEY_Device_PDOName;\n    deviceFilterCompoundProp.Store = DEVPROP_STORE_SYSTEM;\n    deviceFilterCompoundProp.LocaleName = NULL;\n\n    memset(&deviceFilterProperty, 0, sizeof(deviceFilterProperty));\n    deviceFilterProperty.CompKey = deviceFilterCompoundProp;\n    deviceFilterProperty.Type = DEVPROP_TYPE_STRING;\n    deviceFilterProperty.BufferSize = (ULONG)ObjectName->Length + sizeof(UNICODE_NULL);\n    deviceFilterProperty.Buffer = ObjectName->Buffer;\n\n    memset(deviceFilter, 0, sizeof(deviceFilter));\n    deviceFilter[0].Operator = DEVPROP_OPERATOR_EQUALS_IGNORE_CASE;\n    deviceFilter[0].Property = deviceFilterProperty;\n\n    if (HR_SUCCESS(PhDevGetObjects(\n        DevObjectTypeDevice,\n        DevQueryFlagNone,\n        RTL_NUMBER_OF(deviceProperties),\n        deviceProperties,\n        RTL_NUMBER_OF(deviceFilter),\n        deviceFilter,\n        &deviceCount,\n        &deviceObjects\n        )))\n    {\n        // Note: We can get a success with 0 results.\n        if (deviceCount > 0)\n        {\n            DEV_OBJECT device = deviceObjects[0];\n            PPH_STRING deviceName = NULL;\n            PPH_STRING deviceDesc = NULL;\n            PH_STRINGREF displayName;\n            PH_STRINGREF displayDesc;\n            PH_STRINGREF firstPart;\n            PH_STRINGREF secondPart;\n\n            displayName.Length = device.pProperties[0].BufferSize;\n            displayName.Buffer = device.pProperties[0].Buffer;\n            displayDesc.Length = device.pProperties[1].BufferSize;\n            displayDesc.Buffer = device.pProperties[1].Buffer;\n\n            if (PhSplitStringRefAtLastChar(&displayName, L';', &firstPart, &secondPart))\n                deviceName = PhCreateString2(&secondPart);\n            else\n                deviceName = PhCreateString2(&displayName);\n\n            if (PhSplitStringRefAtLastChar(&displayDesc, L';', &firstPart, &secondPart))\n                deviceDesc = PhCreateString2(&secondPart);\n            else\n                deviceDesc = PhCreateString2(&displayDesc);\n\n            if (deviceName->Length >= sizeof(UNICODE_NULL) && deviceName->Buffer[deviceName->Length / sizeof(WCHAR)] == UNICODE_NULL)\n                deviceName->Length -= sizeof(UNICODE_NULL); // PhTrimToNullTerminatorString(deviceName);\n            if (deviceDesc->Length >= sizeof(UNICODE_NULL) && deviceDesc->Buffer[deviceDesc->Length / sizeof(WCHAR)] == UNICODE_NULL)\n                deviceDesc->Length -= sizeof(UNICODE_NULL); // PhTrimToNullTerminatorString(deviceDesc);\n\n            if (!PhIsNullOrEmptyString(deviceDesc))\n            {\n                PH_FORMAT format[4];\n\n                PhInitFormatSR(&format[0], deviceDesc->sr);\n                PhInitFormatS(&format[1], L\" (PDO: \");\n                PhInitFormatSR(&format[2], ObjectName->sr);\n                PhInitFormatC(&format[3], ')');\n\n                PhSetReference(&objectPnPDeviceName, PhFormat(format, RTL_NUMBER_OF(format), 0));\n            }\n            else if (!PhIsNullOrEmptyString(deviceName))\n            {\n                PH_FORMAT format[4];\n\n                PhInitFormatSR(&format[0], deviceName->sr);\n                PhInitFormatS(&format[1], L\" (PDO: \");\n                PhInitFormatSR(&format[2], ObjectName->sr);\n                PhInitFormatC(&format[3], ')');\n\n                PhSetReference(&objectPnPDeviceName, PhFormat(format, RTL_NUMBER_OF(format), 0));\n            }\n\n            if (deviceDesc)\n                PhDereferenceObject(deviceDesc);\n            if (deviceName)\n                PhDereferenceObject(deviceName);\n        }\n\n        PhDevFreeObjects(deviceCount, deviceObjects);\n    }\n\n    return objectPnPDeviceName;\n}\n\nPPH_STRING PhFormatNativeKeyName(\n    _In_ PPH_STRING Name\n    )\n{\n    static CONST PH_STRINGREF hklmPrefix = PH_STRINGREF_INIT(L\"\\\\Registry\\\\Machine\");\n    static CONST PH_STRINGREF hkcrPrefix = PH_STRINGREF_INIT(L\"\\\\Registry\\\\Machine\\\\Software\\\\Classes\");\n    static CONST PH_STRINGREF hkuPrefix = PH_STRINGREF_INIT(L\"\\\\Registry\\\\User\");\n    static PPH_STRING hkcuPrefix;\n    static PPH_STRING hkcucrPrefix;\n\n    static CONST PH_STRINGREF hklmString = PH_STRINGREF_INIT(L\"HKLM\");\n    static CONST PH_STRINGREF hkcrString = PH_STRINGREF_INIT(L\"HKCR\");\n    static CONST PH_STRINGREF hkuString = PH_STRINGREF_INIT(L\"HKU\");\n    static CONST PH_STRINGREF hkcuString = PH_STRINGREF_INIT(L\"HKCU\");\n    static CONST PH_STRINGREF hkcucrString = PH_STRINGREF_INIT(L\"HKCU\\\\Software\\\\Classes\");\n\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    PPH_STRING newName;\n    PH_STRINGREF name;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PH_TOKEN_USER tokenUser;\n        PPH_STRING stringSid = NULL;\n\n        if (NT_SUCCESS(PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &tokenUser)))\n        {\n            stringSid = PhSidToStringSid(tokenUser.User.Sid);\n        }\n\n        if (stringSid)\n        {\n            static CONST PH_STRINGREF registryUserPrefix = PH_STRINGREF_INIT(L\"\\\\Registry\\\\User\\\\\");\n            static CONST PH_STRINGREF classesString = PH_STRINGREF_INIT(L\"_Classes\");\n\n            hkcuPrefix = PhConcatStringRef2(&registryUserPrefix, &stringSid->sr);\n            hkcucrPrefix = PhConcatStringRef2(&hkcuPrefix->sr, &classesString);\n\n            PhDereferenceObject(stringSid);\n        }\n        else\n        {\n            hkcuPrefix = PhCreateString(L\"...\"); // some random string that won't ever get matched\n            hkcucrPrefix = PhCreateString(L\"...\");\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    name = Name->sr;\n\n    if (PhStartsWithStringRef(&name, &hkcrPrefix, TRUE))\n    {\n        PhSkipStringRef(&name, hkcrPrefix.Length);\n        newName = PhConcatStringRef2(&hkcrString, &name);\n    }\n    else if (PhStartsWithStringRef(&name, &hklmPrefix, TRUE))\n    {\n        PhSkipStringRef(&name, hklmPrefix.Length);\n        newName = PhConcatStringRef2(&hklmString, &name);\n    }\n    else if (PhStartsWithStringRef(&name, &hkcucrPrefix->sr, TRUE))\n    {\n        PhSkipStringRef(&name, hkcucrPrefix->Length);\n        newName = PhConcatStringRef2(&hkcucrString, &name);\n    }\n    else if (PhStartsWithStringRef(&name, &hkcuPrefix->sr, TRUE))\n    {\n        PhSkipStringRef(&name, hkcuPrefix->Length);\n        newName = PhConcatStringRef2(&hkcuString, &name);\n    }\n    else if (PhStartsWithStringRef(&name, &hkuPrefix, TRUE))\n    {\n        PhSkipStringRef(&name, hkuPrefix.Length);\n        newName = PhConcatStringRef2(&hkuString, &name);\n    }\n    else\n    {\n        PhSetReference(&newName, Name);\n    }\n\n    return newName;\n}\n\nNTSTATUS PhGetSectionFileName(\n    _In_ HANDLE SectionHandle,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    SIZE_T viewSize;\n    PVOID viewBase;\n\n    viewSize = PAGE_SIZE;\n    viewBase = NULL;\n\n    status = PhMapViewOfSection(\n        SectionHandle,\n        NtCurrentProcess(),\n        &viewBase,\n        0,\n        NULL,\n        &viewSize,\n        ViewUnmap,\n        WindowsVersion >= WINDOWS_10_RS2 ? MEM_MAPPED : 0,\n        PAGE_READONLY\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetProcessMappedFileName(NtCurrentProcess(), viewBase, FileName);\n    PhUnmapViewOfSection(NtCurrentProcess(), viewBase);\n\n    return status;\n}\n\n_Callback_ PPH_STRING PhStdGetClientIdName(\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    return PhStdGetClientIdNameEx(ClientId, NULL);\n}\n\nPPH_STRING PhStdGetClientIdNameEx(\n    _In_ PCLIENT_ID ClientId,\n    _In_opt_ PPH_STRING ProcessName\n    )\n{\n    PPH_STRING result;\n    PPH_STRING processName = NULL;\n    PPH_STRING threadName = NULL;\n    PH_STRINGREF processNameStringRef;\n    PH_STRINGREF threadNameStringRef;\n    BOOLEAN processIsTerminated = FALSE;\n    BOOLEAN threadIsTerminated = FALSE;\n\n    PhInitializeStringRef(&processNameStringRef, L\"unknown process\");\n    PhInitializeStringRef(&threadNameStringRef, L\"unnamed thread\");\n\n    if (PhIsNullOrEmptyString(ProcessName))\n    {\n        if (ClientId->UniqueProcess == SYSTEM_PROCESS_ID)\n        {\n            if (processName = PhGetKernelFileName())\n            {\n                PhMoveReference(&processName, PhGetBaseName(processName));\n                processNameStringRef.Length = processName->Length;\n                processNameStringRef.Buffer = processName->Buffer;\n            }\n        }\n        else\n        {\n            // Determine the name of the process ourselves (diversenok)\n            if (ClientId->UniqueProcess && NT_SUCCESS(PhGetProcessImageFileNameById(\n                ClientId->UniqueProcess,\n                NULL,\n                &processName\n                )))\n            {\n                processNameStringRef.Length = processName->Length;\n                processNameStringRef.Buffer = processName->Buffer;\n            }\n        }\n    }\n    else\n    {\n        processNameStringRef.Length = ProcessName->Length;\n        processNameStringRef.Buffer = ProcessName->Buffer;\n    }\n\n    if (ClientId->UniqueProcess)\n    {\n        HANDLE processHandle;\n\n        if (NT_SUCCESS(PhOpenProcessClientId(\n            &processHandle,\n            SYNCHRONIZE, // PROCESS_QUERY_LIMITED_INFORMATION\n            ClientId\n            )))\n        {\n            // Check if the process is alive\n            PhGetProcessIsTerminated(processHandle, &processIsTerminated);\n\n            // Use the name of the process if available\n            //if (PhIsNullOrEmptyString(ProcessName) && NT_SUCCESS(PhGetProcessImageFileName(processHandle, &processName)))\n            //{\n            //    processNameStringRef.Length = processName->Length;\n            //    processNameStringRef.Buffer = processName->Buffer;\n            //}\n\n            NtClose(processHandle);\n        }\n    }\n\n    if (ClientId->UniqueThread)\n    {\n        HANDLE threadHandle;\n\n        if (NT_SUCCESS(PhOpenThreadClientId(\n            &threadHandle,\n            THREAD_QUERY_LIMITED_INFORMATION,\n            ClientId\n            )))\n        {\n            // Check if the thread is alive\n            PhGetThreadIsTerminated(threadHandle, &threadIsTerminated);\n\n            // Use the name of the thread if available\n            if (NT_SUCCESS(PhGetThreadName(threadHandle, &threadName)))\n            {\n                threadNameStringRef.Length = threadName->Length;\n                threadNameStringRef.Buffer = threadName->Buffer;\n            }\n\n            NtClose(threadHandle);\n        }\n    }\n\n    // Combine everything\n\n    if (ClientId->UniqueThread)\n    {\n        PH_FORMAT format[10];\n\n        // L\"%s%.*s (%lu): %s%.*s (%lu)\"\n        PhInitFormatS(&format[0], processIsTerminated ? L\"Terminated \" : L\"\");\n        PhInitFormatSR(&format[1], processNameStringRef);\n        PhInitFormatS(&format[2], L\" (\");\n        PhInitFormatU(&format[3], HandleToUlong(ClientId->UniqueProcess));\n        PhInitFormatS(&format[4], L\"): \");\n        PhInitFormatS(&format[5], threadIsTerminated ? L\"Terminated \" : L\"\");\n        PhInitFormatSR(&format[6], threadNameStringRef);\n        PhInitFormatS(&format[7], L\" (\");\n        PhInitFormatU(&format[8], HandleToUlong(ClientId->UniqueThread));\n        PhInitFormatC(&format[9], L')');\n\n        result = PhFormat(format, RTL_NUMBER_OF(format), 0);\n    }\n    else\n    {\n        PH_FORMAT format[5];\n\n        // L\"%s%.*s (%lu)\"\n        PhInitFormatS(&format[0], processIsTerminated ? L\"Terminated \" : L\"\");\n        PhInitFormatSR(&format[1], processNameStringRef);\n        PhInitFormatS(&format[2], L\" (\");\n        PhInitFormatU(&format[3], HandleToUlong(ClientId->UniqueProcess));\n        PhInitFormatC(&format[4], L')');\n\n        result = PhFormat(format, RTL_NUMBER_OF(format), 0);\n    }\n\n    //result = PhFormatString(\n    //    ClientId->UniqueThread ? L\"%s%.*s (%lu): %s%.*s (%lu)\" : L\"%s%.*s (%lu)\",\n    //    processIsTerminated ? L\"Terminated \" : L\"\",\n    //    processNameStringRef.Length / sizeof(WCHAR),\n    //    processNameStringRef.Buffer,\n    //    HandleToUlong(ClientId->UniqueProcess),\n    //    threadIsTerminated ? L\"terminated \" : L\"\",\n    //    threadNameStringRef.Length / sizeof(WCHAR),\n    //    threadNameStringRef.Buffer,\n    //    HandleToUlong(ClientId->UniqueThread)\n    //    );\n\n    PhClearReference(&processName);\n    PhClearReference(&threadName);\n\n    return result;\n}\n\nNTSTATUS PhpGetBestObjectName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ PPH_STRING ObjectName,\n    _In_ PPH_STRING TypeName,\n    _Out_ PPH_STRING *BestObjectName,\n    _Out_ PPH_STRING *ResolvedObjectName\n    )\n{\n    NTSTATUS status;\n    PPH_STRING bestObjectName = NULL;\n    PPH_GET_CLIENT_ID_NAME handleGetClientIdName = PhHandleGetClientIdName;\n\n    PhSetReference(ResolvedObjectName, ObjectName);\n\n    if (PhEqualString2(TypeName, L\"EtwRegistration\", TRUE))\n    {\n        if (KsiLevel() >= KphLevelMed)\n        {\n            KPH_ETWREG_BASIC_INFORMATION basicInfo;\n\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectEtwRegBasicInformation,\n                &basicInfo,\n                sizeof(KPH_ETWREG_BASIC_INFORMATION),\n                NULL\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                bestObjectName = PhGetEtwPublisherName(&basicInfo.Guid);\n            }\n        }\n    }\n    else if (PhEqualString2(TypeName, L\"File\", TRUE))\n    {\n        // Use the socket address for AFD handles\n        if (PhAfdIsSocketObjectName(ObjectName))\n        {\n            HANDLE dupHandle;\n\n            status = NtDuplicateObject(\n                ProcessHandle,\n                Handle,\n                NtCurrentProcess(),\n                &dupHandle,\n                0,\n                0,\n                DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                bestObjectName = PhAfdFormatSocketBestName(dupHandle);\n                PhQueryCloseHandle(dupHandle);\n            }\n        }\n\n        if (PhIsNullOrEmptyString(bestObjectName))\n        {\n            // Convert the file name to a DOS file name.\n            bestObjectName = PhResolveDevicePrefix(&ObjectName->sr);\n\n            if (PhIsNullOrEmptyString(bestObjectName))\n            {\n                if (PhEnableProcessHandlePnPDeviceNameSupport)\n                {\n                    if (PhStartsWithString2(ObjectName, L\"\\\\Device\\\\\", TRUE))\n                    {\n                        // The device might be a PDO... Query the PnP manager for the friendly name of the device. (dmex)\n                        bestObjectName = PhGetPnPDeviceName(ObjectName);\n                    }\n                }\n\n                if (PhIsNullOrEmptyString(bestObjectName))\n                {\n                    // The file doesn't have a DOS filename and doesn't have a PnP friendly name.\n                    PhSetReference(&bestObjectName, ObjectName);\n                }\n            }\n        }\n\n        if (PhIsNullOrEmptyString(bestObjectName) && (KsiLevel() >= KphLevelMed))\n        {\n            HANDLE fileObjectDriver;\n            PPH_STRING driverName;\n\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectFileObjectDriver,\n                &fileObjectDriver,\n                sizeof(HANDLE),\n                NULL\n                );\n\n            if (NT_SUCCESS(status) && fileObjectDriver)\n            {\n                if (NT_SUCCESS(PhGetDriverName(fileObjectDriver, &driverName)))\n                {\n                    static CONST PH_STRINGREF prefix = PH_STRINGREF_INIT(L\"Unnamed file: \");\n\n                    PhMoveReference(&bestObjectName, PhConcatStringRef2(&prefix, &driverName->sr));\n                    PhDereferenceObject(driverName);\n                }\n\n                PhQueryCloseHandle(fileObjectDriver);\n            }\n        }\n    }\n    else if (PhEqualString2(TypeName, L\"Job\", TRUE))\n    {\n        HANDLE dupHandle;\n        PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList;\n\n        // Skip when we already have a valid job object name. (dmex)\n        if (!PhIsNullOrEmptyString(ObjectName))\n            goto CleanupExit;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            JOB_OBJECT_QUERY,\n            0,\n            DUPLICATE_SAME_ATTRIBUTES\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        if (handleGetClientIdName && NT_SUCCESS(PhGetJobProcessIdList(dupHandle, &processIdList)))\n        {\n            PH_STRING_BUILDER sb;\n            ULONG i;\n            CLIENT_ID clientId;\n            PPH_STRING name;\n\n            PhInitializeStringBuilder(&sb, 40);\n            clientId.UniqueThread = NULL;\n\n            for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++)\n            {\n                clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i];\n                name = handleGetClientIdName(&clientId);\n\n                if (name)\n                {\n                    PhAppendStringBuilder(&sb, &name->sr);\n                    PhAppendStringBuilder2(&sb, L\"; \");\n                    PhDereferenceObject(name);\n                }\n            }\n\n            PhFree(processIdList);\n\n            if (sb.String->Length != 0)\n                PhRemoveEndStringBuilder(&sb, 2);\n\n            if (sb.String->Length == 0)\n                PhAppendStringBuilder2(&sb, L\"(No processes)\");\n\n            bestObjectName = PhFinalStringBuilderString(&sb);\n        }\n\n        PhQueryCloseHandle(dupHandle);\n    }\n    else if (PhEqualString2(TypeName, L\"Key\", TRUE))\n    {\n        bestObjectName = PhFormatNativeKeyName(ObjectName);\n    }\n    else if (PhEqualString2(TypeName, L\"Process\", TRUE))\n    {\n        CLIENT_ID clientId;\n\n        clientId.UniqueThread = NULL;\n\n        if (KsiLevel() >= KphLevelMed)\n        {\n            PROCESS_BASIC_INFORMATION basicInfo;\n\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectProcessBasicInformation,\n                &basicInfo,\n                sizeof(PROCESS_BASIC_INFORMATION),\n                NULL\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            clientId.UniqueProcess = basicInfo.UniqueProcessId;\n        }\n        else\n        {\n            HANDLE dupHandle;\n            PROCESS_BASIC_INFORMATION basicInfo;\n\n            status = NtDuplicateObject(\n                ProcessHandle,\n                Handle,\n                NtCurrentProcess(),\n                &dupHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION,\n                0,\n                DUPLICATE_SAME_ATTRIBUTES\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhGetProcessBasicInformation(dupHandle, &basicInfo);\n            PhQueryCloseHandle(dupHandle);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            clientId.UniqueProcess = basicInfo.UniqueProcessId;\n        }\n\n        if (handleGetClientIdName)\n            bestObjectName = handleGetClientIdName(&clientId);\n    }\n    else if (PhEqualString2(TypeName, L\"Section\", TRUE))\n    {\n        HANDLE dupHandle = NULL;\n        PPH_STRING fileName = NULL;\n\n        if (!PhIsNullOrEmptyString(ObjectName))\n            goto CleanupExit;\n\n        if (KsiLevel() >= KphLevelMed)\n        {\n            ULONG returnLength;\n            ULONG bufferSize;\n            PUNICODE_STRING buffer;\n\n            bufferSize = 0x100;\n            buffer = PhAllocate(bufferSize);\n\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectSectionFileName,\n                buffer,\n                bufferSize,\n                &returnLength\n                );\n            if (status == STATUS_BUFFER_OVERFLOW && returnLength > 0)\n            {\n                PhFree(buffer);\n                bufferSize = returnLength;\n                buffer = PhAllocate(bufferSize);\n\n                status = KphQueryInformationObject(\n                    ProcessHandle,\n                    Handle,\n                    KphObjectSectionFileName,\n                    buffer,\n                    bufferSize,\n                    &returnLength\n                    );\n            }\n\n            if (NT_SUCCESS(status))\n                fileName = PhCreateStringFromUnicodeString(buffer);\n\n            PhFree(buffer);\n        }\n        else\n        {\n            status = NtDuplicateObject(\n                ProcessHandle,\n                Handle,\n                NtCurrentProcess(),\n                &dupHandle,\n                SECTION_QUERY | SECTION_MAP_READ,\n                0,\n                DUPLICATE_SAME_ATTRIBUTES\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhGetSectionFileName(dupHandle, &fileName);\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            bestObjectName = PhResolveDevicePrefix(&fileName->sr);\n            PhDereferenceObject(fileName);\n        }\n        else\n        {\n            SECTION_BASIC_INFORMATION basicInfo = { NULL };\n\n            if (KsiLevel() >= KphLevelMed)\n            {\n                status = KphQueryInformationObject(\n                    ProcessHandle,\n                    Handle,\n                    KphObjectSectionBasicInformation,\n                    &basicInfo,\n                    sizeof(basicInfo),\n                    NULL\n                    );\n            }\n            else if (dupHandle)\n            {\n                status = PhGetSectionBasicInformation(dupHandle, &basicInfo);\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                PH_FORMAT format[4];\n                PCWSTR sectionType = L\"Unknown\";\n\n                if (basicInfo.AllocationAttributes & SEC_COMMIT)\n                    sectionType = L\"Commit\";\n                else if (basicInfo.AllocationAttributes & SEC_FILE)\n                    sectionType = L\"File\";\n                else if (basicInfo.AllocationAttributes & SEC_IMAGE)\n                    sectionType = L\"Image\";\n                else if (basicInfo.AllocationAttributes & SEC_RESERVE)\n                    sectionType = L\"Reserve\";\n\n                PhInitFormatS(&format[0], sectionType);\n                PhInitFormatS(&format[1], L\" (\");\n                PhInitFormatSize(&format[2], basicInfo.MaximumSize.QuadPart);\n                PhInitFormatC(&format[3], ')');\n                bestObjectName = PhFormat(format, RTL_NUMBER_OF(format), 0);\n            }\n        }\n\n        if (dupHandle)\n            PhQueryCloseHandle(dupHandle);\n    }\n    else if (PhEqualString2(TypeName, L\"Thread\", TRUE))\n    {\n        CLIENT_ID clientId;\n\n        if (KsiLevel() >= KphLevelMed)\n        {\n            THREAD_BASIC_INFORMATION basicInfo;\n\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectThreadBasicInformation,\n                &basicInfo,\n                sizeof(THREAD_BASIC_INFORMATION),\n                NULL\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            clientId = basicInfo.ClientId;\n        }\n        else\n        {\n            HANDLE dupHandle;\n            THREAD_BASIC_INFORMATION basicInfo;\n\n            status = NtDuplicateObject(\n                ProcessHandle,\n                Handle,\n                NtCurrentProcess(),\n                &dupHandle,\n                THREAD_QUERY_LIMITED_INFORMATION,\n                0,\n                DUPLICATE_SAME_ATTRIBUTES\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhGetThreadBasicInformation(dupHandle, &basicInfo);\n            PhQueryCloseHandle(dupHandle);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            clientId = basicInfo.ClientId;\n        }\n\n        if (handleGetClientIdName)\n            bestObjectName = handleGetClientIdName(&clientId);\n    }\n    else if (PhEqualString2(TypeName, L\"TmEn\", TRUE))\n    {\n        HANDLE dupHandle;\n        ENLISTMENT_BASIC_INFORMATION basicInfo;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            ENLISTMENT_QUERY_INFORMATION,\n            0,\n            DUPLICATE_SAME_ATTRIBUTES\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetEnlistmentBasicInformation(dupHandle, &basicInfo);\n        PhQueryCloseHandle(dupHandle);\n\n        if (NT_SUCCESS(status))\n        {\n            bestObjectName = PhFormatGuid(&basicInfo.EnlistmentId);\n        }\n    }\n    else if (PhEqualString2(TypeName, L\"TmRm\", TRUE))\n    {\n        HANDLE dupHandle;\n        GUID guid;\n        PPH_STRING description;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            RESOURCEMANAGER_QUERY_INFORMATION,\n            0,\n            DUPLICATE_SAME_ATTRIBUTES\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetResourceManagerBasicInformation(\n            dupHandle,\n            &guid,\n            &description\n            );\n        PhQueryCloseHandle(dupHandle);\n\n        if (NT_SUCCESS(status))\n        {\n            if (!PhIsNullOrEmptyString(description))\n            {\n                bestObjectName = description;\n            }\n            else\n            {\n                bestObjectName = PhFormatGuid(&guid);\n\n                if (description)\n                    PhDereferenceObject(description);\n            }\n        }\n    }\n    else if (PhEqualString2(TypeName, L\"TmTm\", TRUE))\n    {\n        HANDLE dupHandle;\n        PPH_STRING logFileName = NULL;\n        TRANSACTIONMANAGER_BASIC_INFORMATION basicInfo;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            TRANSACTIONMANAGER_QUERY_INFORMATION,\n            0,\n            DUPLICATE_SAME_ATTRIBUTES\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetTransactionManagerLogFileName(\n            dupHandle,\n            &logFileName\n            );\n\n        if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(logFileName))\n        {\n            bestObjectName = PhGetFileName(logFileName);\n            PhDereferenceObject(logFileName);\n        }\n        else\n        {\n            if (logFileName)\n                PhDereferenceObject(logFileName);\n\n            status = PhGetTransactionManagerBasicInformation(\n                dupHandle,\n                &basicInfo\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                bestObjectName = PhFormatGuid(&basicInfo.TmIdentity);\n            }\n        }\n\n        PhQueryCloseHandle(dupHandle);\n    }\n    else if (PhEqualString2(TypeName, L\"TmTx\", TRUE))\n    {\n        HANDLE dupHandle;\n        PPH_STRING description = NULL;\n        TRANSACTION_BASIC_INFORMATION basicInfo;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            TRANSACTION_QUERY_INFORMATION,\n            0,\n            DUPLICATE_SAME_ATTRIBUTES\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetTransactionPropertiesInformation(\n            dupHandle,\n            NULL,\n            NULL,\n            &description\n            );\n\n        if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(description))\n        {\n            bestObjectName = description;\n        }\n        else\n        {\n            if (description)\n                PhDereferenceObject(description);\n\n            status = PhGetTransactionBasicInformation(\n                dupHandle,\n                &basicInfo\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                bestObjectName = PhFormatGuid(&basicInfo.TransactionId);\n            }\n        }\n\n        PhQueryCloseHandle(dupHandle);\n    }\n    else if (PhEqualString2(TypeName, L\"Token\", TRUE))\n    {\n        HANDLE dupHandle;\n        PH_TOKEN_USER tokenUser = { 0 };\n        TOKEN_STATISTICS statistics = { 0 };\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            TOKEN_QUERY,\n            0,\n            DUPLICATE_SAME_ATTRIBUTES\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetTokenUser(dupHandle, &tokenUser);\n        PhGetTokenStatistics(dupHandle, &statistics);\n\n        if (NT_SUCCESS(status))\n        {\n            PPH_STRING fullName;\n\n            fullName = PhGetSidFullName(tokenUser.User.Sid, TRUE, NULL);\n\n            if (fullName)\n            {\n                PH_FORMAT format[4];\n\n                PhInitFormatSR(&format[0], fullName->sr);\n                PhInitFormatS(&format[1], L\": 0x\");\n                PhInitFormatX(&format[2], statistics.AuthenticationId.LowPart);\n                PhInitFormatS(&format[3], statistics.TokenType == TokenPrimary ? L\" (Primary)\" : L\" (Impersonation)\");\n\n                bestObjectName = PhFormat(format, RTL_NUMBER_OF(format), fullName->Length + 8 + 16 + 16);\n                PhDereferenceObject(fullName);\n            }\n        }\n\n        PhQueryCloseHandle(dupHandle);\n    }\n    else if (PhEqualString2(TypeName, L\"ALPC Port\", TRUE))\n    {\n        PROCESS_BASIC_INFORMATION processInfo;\n        KPH_ALPC_COMMUNICATION_INFORMATION commsInfo;\n        PKPH_ALPC_COMMUNICATION_NAMES_INFORMATION namesInfo;\n        USHORT formatCount = 0;\n        PH_FORMAT format[5];\n        PPH_STRING name = NULL;\n        CLIENT_ID clientId;\n\n        if (KsiLevel() < KphLevelMed)\n            goto CleanupExit;\n\n        status = PhGetProcessBasicInformation(ProcessHandle, &processInfo);\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = KphAlpcQueryInformation(\n            ProcessHandle,\n            Handle,\n            KphAlpcCommunicationInformation,\n            &commsInfo,\n            sizeof(commsInfo),\n            NULL\n            );\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        if (!NT_SUCCESS(KphAlpcQueryCommunicationsNamesInfo(ProcessHandle, Handle, &namesInfo)))\n        {\n            namesInfo = NULL;\n        }\n\n        if (commsInfo.ClientCommunicationPort.OwnerProcessId == processInfo.UniqueProcessId)\n        {\n            PhInitFormatS(&format[formatCount++], L\"Client: \");\n            if (commsInfo.ServerCommunicationPort.OwnerProcessId)\n            {\n                PhInitFormatS(&format[formatCount++], L\"Connection to \");\n                clientId.UniqueProcess = commsInfo.ServerCommunicationPort.OwnerProcessId;\n                clientId.UniqueThread = 0;\n                name = PhStdGetClientIdName(&clientId);\n            }\n            else if (commsInfo.ClientCommunicationPort.ConnectionRefused)\n            {\n                PhInitFormatS(&format[formatCount++], L\"Refused \");\n            }\n            else if (commsInfo.ClientCommunicationPort.Closed)\n            {\n                PhInitFormatS(&format[formatCount++], L\"Closed \");\n            }\n            else if (commsInfo.ClientCommunicationPort.Disconnected)\n            {\n                PhInitFormatS(&format[formatCount++], L\"Disconnected \");\n            }\n            else if (commsInfo.ClientCommunicationPort.ConnectionPending)\n            {\n                PhInitFormatS(&format[formatCount++], L\"Pending \");\n            }\n        }\n        else if (commsInfo.ServerCommunicationPort.OwnerProcessId == processInfo.UniqueProcessId)\n        {\n            PhInitFormatS(&format[formatCount++], L\"Server: \");\n            if (commsInfo.ClientCommunicationPort.OwnerProcessId)\n            {\n                PhInitFormatS(&format[formatCount++], L\" Connection from \");\n                clientId.UniqueProcess = commsInfo.ClientCommunicationPort.OwnerProcessId;\n                clientId.UniqueThread = 0;\n                name = PhStdGetClientIdName(&clientId);\n            }\n            else if (commsInfo.ClientCommunicationPort.ConnectionRefused)\n            {\n                PhInitFormatS(&format[formatCount++], L\"Refused \");\n            }\n            else if (commsInfo.ServerCommunicationPort.Closed)\n            {\n                PhInitFormatS(&format[formatCount++], L\"Closed \");\n            }\n            else if (commsInfo.ServerCommunicationPort.Disconnected)\n            {\n                PhInitFormatS(&format[formatCount++], L\"Disconnected \");\n            }\n            else if (commsInfo.ServerCommunicationPort.ConnectionPending)\n            {\n                PhInitFormatS(&format[formatCount++], L\"Pending \");\n            }\n        }\n        else if (commsInfo.ConnectionPort.OwnerProcessId == processInfo.UniqueProcessId)\n        {\n            PhInitFormatS(&format[formatCount++], L\"Connection: \");\n        }\n\n        if (name)\n        {\n            PhInitFormatSR(&format[formatCount++], name->sr);\n\n            if (namesInfo && namesInfo->ConnectionPort.Length > 0)\n            {\n                PhInitFormatS(&format[formatCount++], L\" on \");\n            }\n        }\n\n        if (namesInfo && namesInfo->ConnectionPort.Length > 0)\n        {\n            PhInitFormatUCS(&format[formatCount++], &namesInfo->ConnectionPort);\n\n            if (PhIsNullOrEmptyString(*ResolvedObjectName))\n                PhMoveReference(ResolvedObjectName, PhCreateStringFromUnicodeString(&namesInfo->ConnectionPort));\n        }\n\n        if (formatCount > 0)\n            bestObjectName = PhFormat(format, formatCount, 0);\n\n        if (name)\n            PhDereferenceObject(name);\n\n        if (namesInfo)\n            PhFree(namesInfo);\n    }\n\nCleanupExit:\n\n    if (PhIsNullOrEmptyString(bestObjectName))\n    {\n        PhSetReference(&bestObjectName, ObjectName);\n    }\n\n    *BestObjectName = bestObjectName;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Gets information for a handle.\n *\n * \\param ProcessHandle A handle to the process in which the handle resides.\n * \\param Handle The handle value.\n * \\param ObjectTypeNumber The object type number of the handle. You can specify -1 for this\n * parameter if the object type number is not known.\n * \\param BasicInformation A variable which receives basic information about the object.\n * \\param TypeName A variable which receives the object type name.\n * \\param ObjectName A variable which receives the object name.\n * \\param BestObjectName A variable which receives the formatted object name.\n *\n * \\retval STATUS_INVALID_HANDLE The handle specified in \\c ProcessHandle or \\c Handle is invalid.\n * \\retval STATUS_INVALID_PARAMETER_3 The value specified in \\c ObjectTypeNumber is invalid.\n */\nNTSTATUS PhGetHandleInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,\n    _Out_opt_ PPH_STRING *TypeName,\n    _Out_opt_ PPH_STRING *ObjectName,\n    _Out_opt_ PPH_STRING *BestObjectName\n    )\n{\n    NTSTATUS status;\n    NTSTATUS subStatus;\n\n    status = PhGetHandleInformationEx(\n        ProcessHandle,\n        Handle,\n        ObjectTypeNumber,\n        0,\n        &subStatus,\n        BasicInformation,\n        TypeName,\n        ObjectName,\n        BestObjectName,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Fail if any component failed, for compatibility reasons.\n    if (!NT_SUCCESS(subStatus))\n    {\n        if (TypeName)\n            PhClearReference(TypeName);\n        if (ObjectName)\n            PhClearReference(ObjectName);\n        if (BestObjectName)\n            PhClearReference(BestObjectName);\n\n        return subStatus;\n    }\n\n    return status;\n}\n\n/**\n * Gets information for a handle.\n *\n * \\param ProcessHandle A handle to the process in which the handle resides.\n * \\param Handle The handle value.\n * \\param ObjectTypeNumber The object type number of the handle. You can specify -1 for this\n * parameter if the object type number is not known.\n * \\param Flags Reserved.\n * \\param SubStatus A variable which receives the NTSTATUS value of the last component that fails.\n * If all operations succeed, the value will be STATUS_SUCCESS. If the function returns an error\n * status, this variable is not set.\n * \\param BasicInformation A variable which receives basic information about the object.\n * \\param TypeName A variable which receives the object type name.\n * \\param ObjectName A variable which receives the object name.\n * \\param BestObjectName A variable which receives the formatted object name.\n * \\param ExtraInformation Reserved.\n *\n * \\retval STATUS_INVALID_HANDLE The handle specified in \\c ProcessHandle or \\c Handle is invalid.\n * \\retval STATUS_INVALID_PARAMETER_3 The value specified in \\c ObjectTypeNumber is invalid.\n *\n * \\remarks If \\a BasicInformation or \\a TypeName are specified, the function will fail if either\n * cannot be queried. \\a ObjectName, \\a BestObjectName and \\a ExtraInformation will be NULL if they\n * cannot be queried.\n */\nNTSTATUS PhGetHandleInformationEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Reserved_ ULONG Flags,\n    _Out_opt_ PNTSTATUS SubStatus,\n    _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,\n    _Out_opt_ PPH_STRING *TypeName,\n    _Out_opt_ PPH_STRING *ObjectName,\n    _Out_opt_ PPH_STRING *BestObjectName,\n    _Reserved_ PVOID *ExtraInformation\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    NTSTATUS subStatus = STATUS_SUCCESS;\n    HANDLE objectHandle = NULL;\n    PPH_STRING typeName = NULL;\n    PPH_STRING objectName = NULL;\n    PPH_STRING bestObjectName = NULL;\n    PPH_STRING resolvedObjectName = NULL;\n    BOOLEAN ksienabled;\n\n    if (ProcessHandle == NULL || Handle == NULL || Handle == NtCurrentProcess() || Handle == NtCurrentThread())\n        return STATUS_INVALID_HANDLE;\n    if (ObjectTypeNumber != ULONG_MAX && ObjectTypeNumber >= MAX_OBJECT_TYPE_NUMBER)\n        return STATUS_INVALID_PARAMETER_3;\n\n    ksienabled = (KsiLevel() >= KphLevelMed);\n\n    if (ProcessHandle == NtCurrentProcess() || ksienabled)\n    {\n        objectHandle = Handle;\n    }\n    else\n    {\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &objectHandle,\n            0,\n            0,\n            DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n\n    // Get basic information.\n    if (BasicInformation)\n    {\n        status = PhGetObjectBasicInformation(\n            ProcessHandle,\n            objectHandle,\n            BasicInformation\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    // Exit early if we don't need to get any other information.\n    if (!TypeName && !ObjectName && !BestObjectName)\n        goto CleanupExit;\n\n    // Get the type name.\n    status = PhGetObjectTypeName(\n        ProcessHandle,\n        objectHandle,\n        ObjectTypeNumber,\n        &typeName\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Exit early if we don't need to get the object name.\n    if (!ObjectName && !BestObjectName)\n        goto CleanupExit;\n\n    // Get the object name.\n    // If we're dealing with a file handle we must take special precautions so we don't hang.\n    if (PhEqualString2(typeName, L\"File\", TRUE) && !ksienabled)\n    {\n        status = PhGetObjectName(\n            ProcessHandle,\n            objectHandle,\n            TRUE,\n            &objectName\n            );\n    }\n    else if (PhEqualString2(typeName, L\"EtwRegistration\", TRUE))\n    {\n        status = PhGetEtwObjectName(\n            ProcessHandle,\n            Handle,\n            &objectName\n            );\n    }\n    else\n    {\n        // Query the object normally.\n        status = PhGetObjectName(\n            ProcessHandle,\n            objectHandle,\n            FALSE,\n            &objectName\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        if (\n            (ksienabled && PhEqualString2(typeName, L\"File\", TRUE)) ||\n            PhEqualString2(typeName, L\"EtwRegistration\", TRUE) ||\n            PhEqualString2(typeName, L\"Process\", TRUE) ||\n            PhEqualString2(typeName, L\"Thread\", TRUE) ||\n            PhEqualString2(typeName, L\"Token\", TRUE) ||\n            PhEqualString2(typeName, L\"ALPC Port\", TRUE) ||\n            PhEqualString2(typeName, L\"Section\", TRUE)\n            )\n        {\n            // PhpGetBestObjectName can provide us with a name.\n            objectName = PhReferenceEmptyString();\n            status = STATUS_SUCCESS;\n        }\n        else\n        {\n            subStatus = status;\n            status = STATUS_SUCCESS;\n            goto CleanupExit;\n        }\n    }\n\n    // Exit early if we don't need to get the best object name.\n    if (!BestObjectName)\n        goto CleanupExit;\n\n    status = PhpGetBestObjectName(\n        ProcessHandle,\n        Handle,\n        objectName,\n        typeName,\n        &bestObjectName,\n        &resolvedObjectName\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        subStatus = status;\n        status = STATUS_SUCCESS;\n        goto CleanupExit;\n    }\n\n    PhMoveReference(&objectName, resolvedObjectName);\n\nCleanupExit:\n\n    if (NT_SUCCESS(status))\n    {\n        if (SubStatus)\n            *SubStatus = subStatus;\n        if (TypeName)\n            PhSetReference(TypeName, typeName);\n        if (ObjectName)\n            PhSetReference(ObjectName, objectName);\n        if (BestObjectName)\n            PhSetReference(BestObjectName, bestObjectName);\n    }\n\n    if (!ksienabled && objectHandle && ProcessHandle != NtCurrentProcess())\n    {\n        PhQueryCloseHandle(objectHandle);\n    }\n\n    PhClearReference(&typeName);\n    PhClearReference(&objectName);\n    PhClearReference(&bestObjectName);\n\n    return status;\n}\n\nNTSTATUS PhEnumObjectTypes(\n    _Out_ POBJECT_TYPES_INFORMATION *ObjectTypes\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG returnLength;\n\n    bufferSize = 0x1000;\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQueryObject(\n        NULL,\n        ObjectTypesInformation,\n        buffer,\n        bufferSize,\n        &returnLength\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *ObjectTypes = (POBJECT_TYPES_INFORMATION)buffer;\n\n    return status;\n}\n\nNTSTATUS PhGetObjectTypeMask(\n    _In_ PPH_STRINGREF TypeName,\n    _Out_ PGENERIC_MAPPING GenericMapping\n    )\n{\n    NTSTATUS status = STATUS_NOT_FOUND;\n    POBJECT_TYPES_INFORMATION objectTypes;\n    POBJECT_TYPE_INFORMATION objectType;\n\n    if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes)))\n    {\n        objectType = PH_FIRST_OBJECT_TYPE(objectTypes);\n\n        for (ULONG i = 0; i < objectTypes->NumberOfTypes; i++)\n        {\n            PH_STRINGREF typeName;\n\n            PhUnicodeStringToStringRef(&objectType->TypeName, &typeName);\n\n            if (PhEqualStringRef(&typeName, TypeName, TRUE))\n            {\n                *GenericMapping = objectType->GenericMapping;\n                status = STATUS_SUCCESS;\n                break;\n            }\n\n            objectType = PH_NEXT_OBJECT_TYPE(objectType);\n        }\n\n        PhFree(objectTypes);\n    }\n\n    return status;\n}\n\nULONG PhGetObjectTypeNumber(\n    _In_ PPH_STRINGREF TypeName\n    )\n{\n    POBJECT_TYPES_INFORMATION objectTypes;\n    POBJECT_TYPE_INFORMATION objectType;\n    ULONG objectIndex = ULONG_MAX;\n    ULONG i;\n\n    if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes)))\n    {\n        objectType = PH_FIRST_OBJECT_TYPE(objectTypes);\n\n        for (i = 0; i < objectTypes->NumberOfTypes; i++)\n        {\n            PH_STRINGREF typeNameSr;\n\n            PhUnicodeStringToStringRef(&objectType->TypeName, &typeNameSr);\n\n            if (PhEqualStringRef(&typeNameSr, TypeName, TRUE))\n            {\n                if (WindowsVersion >= WINDOWS_8_1)\n                {\n                    objectIndex = objectType->TypeIndex;\n                    break;\n                }\n                else\n                {\n                    objectIndex = i + 2;\n                    break;\n                }\n            }\n\n            objectType = PH_NEXT_OBJECT_TYPE(objectType);\n        }\n\n        PhFree(objectTypes);\n    }\n\n    return objectIndex;\n}\n\nPPH_STRING PhGetObjectTypeIndexName(\n    _In_ ULONG TypeIndex\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static POBJECT_TYPES_INFORMATION objectTypes = NULL;\n    POBJECT_TYPE_INFORMATION objectType;\n    PPH_STRING objectTypeName = NULL;\n    ULONG i;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhEnumObjectTypes(&objectTypes);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (objectTypes)\n    {\n        objectType = PH_FIRST_OBJECT_TYPE(objectTypes);\n\n        for (i = 0; i < objectTypes->NumberOfTypes; i++)\n        {\n            if (WindowsVersion >= WINDOWS_8_1)\n            {\n                if (TypeIndex == objectType->TypeIndex)\n                {\n                    objectTypeName = PhCreateStringFromUnicodeString(&objectType->TypeName);\n                    break;\n                }\n            }\n            else\n            {\n                if (TypeIndex == (i + 2))\n                {\n                    objectTypeName = PhCreateStringFromUnicodeString(&objectType->TypeName);\n                    break;\n                }\n            }\n\n            objectType = PH_NEXT_OBJECT_TYPE(objectType);\n        }\n    }\n\n    return objectTypeName;\n}\n\nPPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread(\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext;\n    PSLIST_ENTRY listEntry;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        ULONG i;\n\n        PhInitializeSListHead(&PhpCallWithTimeoutThreadListHead);\n\n        for (i = 0; i < PH_QUERY_HACK_MAX_THREADS; i++)\n        {\n            threadContext = PhAllocate(sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT));\n            memset(threadContext, 0, sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT));\n            RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &threadContext->ListEntry);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    while (TRUE)\n    {\n        if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead))\n            break;\n\n        if (!Timeout || Timeout->QuadPart != 0)\n        {\n            PhQueueWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock);\n\n            if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead))\n            {\n                // A new entry has just become available; cancel the wait.\n                PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock);\n                break;\n            }\n            else\n            {\n                PhWaitForWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock, FALSE, Timeout);\n                // TODO: Recompute the timeout value.\n            }\n        }\n        else\n        {\n            return NULL;\n        }\n    }\n\n    return CONTAINING_RECORD(listEntry, PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT, ListEntry);\n}\n\nVOID PhpReleaseCallWithTimeoutThread(\n    _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext\n    )\n{\n    RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &ThreadContext->ListEntry);\n    PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, NULL);\n}\n\nNTSTATUS PhpCallWithTimeout(\n    _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext,\n    _In_ PUSER_THREAD_START_ROUTINE Routine,\n    _In_opt_ PVOID Context,\n    _In_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n\n    // Create objects if necessary.\n\n    if (!ThreadContext->StartEventHandle)\n    {\n        if (!NT_SUCCESS(status = PhCreateEvent(&ThreadContext->StartEventHandle, EVENT_ALL_ACCESS, SynchronizationEvent, FALSE)))\n            return status;\n    }\n\n    if (!ThreadContext->CompletedEventHandle)\n    {\n        if (!NT_SUCCESS(status = PhCreateEvent(&ThreadContext->CompletedEventHandle, EVENT_ALL_ACCESS, SynchronizationEvent, FALSE)))\n            return status;\n    }\n\n    // Create a query thread if we don't have one.\n    if (!ThreadContext->ThreadHandle)\n    {\n        CLIENT_ID clientId;\n\n        NtClearEvent(ThreadContext->StartEventHandle);\n        NtClearEvent(ThreadContext->CompletedEventHandle);\n\n        if (!NT_SUCCESS(status = PhCreateUserThread(\n            NtCurrentProcess(),\n            NULL,\n            THREAD_ALL_ACCESS,\n            0,\n            0,\n            UInt32x32To64(32, 1024),\n            0,\n            PhpCallWithTimeoutThreadStart,\n            ThreadContext,\n            &ThreadContext->ThreadHandle,\n            &clientId\n            )))\n        {\n            return status;\n        }\n\n        // Wait for the thread to initialize.\n        NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, NULL);\n    }\n\n    ThreadContext->Routine = Routine;\n    ThreadContext->Context = Context;\n\n    NtSetEvent(ThreadContext->StartEventHandle, NULL);\n    status = NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, Timeout);\n\n    ThreadContext->Routine = NULL;\n    MemoryBarrier();\n    ThreadContext->Context = NULL;\n\n    if (status != STATUS_WAIT_0)\n    {\n        // The operation timed out, or there was an error. Kill the thread. On Vista and above, the\n        // thread stack is freed automatically.\n        NtTerminateThread(ThreadContext->ThreadHandle, STATUS_UNSUCCESSFUL);\n        status = NtWaitForSingleObject(ThreadContext->ThreadHandle, FALSE, NULL);\n        NtClose(ThreadContext->ThreadHandle);\n        ThreadContext->ThreadHandle = NULL;\n\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    return status;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpCallWithTimeoutThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext = Parameter;\n\n    NtSetEvent(threadContext->CompletedEventHandle, NULL);\n\n    while (TRUE)\n    {\n        if (NtWaitForSingleObject(threadContext->StartEventHandle, FALSE, NULL) != STATUS_WAIT_0)\n            continue;\n\n        if (threadContext->Routine)\n            threadContext->Routine(threadContext->Context);\n\n        NtSetEvent(threadContext->CompletedEventHandle, NULL);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhCallWithTimeout(\n    _In_ PUSER_THREAD_START_ROUTINE Routine,\n    _In_opt_ PVOID Context,\n    _In_opt_ PLARGE_INTEGER AcquireTimeout,\n    _In_ PLARGE_INTEGER CallTimeout\n    )\n{\n    NTSTATUS status;\n    PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext;\n\n    if (threadContext = PhpAcquireCallWithTimeoutThread(AcquireTimeout))\n    {\n        status = PhpCallWithTimeout(threadContext, Routine, Context, CallTimeout);\n        PhpReleaseCallWithTimeoutThread(threadContext);\n    }\n    else\n    {\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    return status;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpCommonQueryObjectRoutine(\n    _In_ PVOID Parameter\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context = Parameter;\n    IO_STATUS_BLOCK isb;\n\n    switch (context->Work)\n    {\n    case NtQueryObjectWork:\n        context->Status = NtQueryObject(\n            context->u.NtQueryObject.Handle,\n            context->u.NtQueryObject.ObjectInformationClass,\n            context->u.NtQueryObject.ObjectInformation,\n            context->u.NtQueryObject.ObjectInformationLength,\n            context->u.NtQueryObject.ReturnLength\n            );\n        break;\n    case NtQuerySecurityObjectWork:\n        context->Status = NtQuerySecurityObject(\n            context->u.NtQuerySecurityObject.Handle,\n            context->u.NtQuerySecurityObject.SecurityInformation,\n            context->u.NtQuerySecurityObject.SecurityDescriptor,\n            context->u.NtQuerySecurityObject.Length,\n            context->u.NtQuerySecurityObject.LengthNeeded\n            );\n        break;\n    case NtSetSecurityObjectWork:\n        context->Status = NtSetSecurityObject(\n            context->u.NtSetSecurityObject.Handle,\n            context->u.NtSetSecurityObject.SecurityInformation,\n            context->u.NtSetSecurityObject.SecurityDescriptor\n            );\n        break;\n    case NtQueryFileInformationWork:\n        {\n            context->Status = NtQueryInformationFile(\n                context->u.NtQueryFileInformation.Handle,\n                &isb,\n                context->u.NtQueryFileInformation.FileInformation,\n                context->u.NtQueryFileInformation.FileInformationLength,\n                context->u.NtQueryFileInformation.FileInformationClass\n                );\n        }\n        break;\n    case KphQueryFileInformationWork:\n        {\n            context->Status = KphQueryInformationFile(\n                context->u.KphQueryFileInformation.ProcessHandle,\n                context->u.KphQueryFileInformation.Handle,\n                context->u.KphQueryFileInformation.FileInformationClass,\n                context->u.KphQueryFileInformation.FileInformation,\n                context->u.KphQueryFileInformation.FileInformationLength,\n                &isb\n                );\n        }\n        break;\n    default:\n        context->Status = STATUS_INVALID_PARAMETER;\n        break;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhpCommonQueryObjectWithTimeout(\n    _In_ PPHP_QUERY_OBJECT_COMMON_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER timeout;\n\n    timeout.QuadPart = -(LONGLONG)UInt32x32To64(1, PH_TIMEOUT_SEC);\n    status = PhCallWithTimeout(PhpCommonQueryObjectRoutine, Context, NULL, &timeout);\n\n    if (NT_SUCCESS(status))\n        status = Context->Status;\n\n    PhFree(Context);\n\n    return status;\n}\n\nNTSTATUS PhCallNtQueryObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));\n    context->Work = NtQueryObjectWork;\n    context->Status = STATUS_UNSUCCESSFUL;\n    context->u.NtQueryObject.Handle = Handle;\n    context->u.NtQueryObject.ObjectInformationClass = ObjectInformationClass;\n    context->u.NtQueryObject.ObjectInformation = ObjectInformation;\n    context->u.NtQueryObject.ObjectInformationLength = ObjectInformationLength;\n    context->u.NtQueryObject.ReturnLength = ReturnLength;\n\n    return PhpCommonQueryObjectWithTimeout(context);\n}\n\nNTSTATUS PhCallNtQuerySecurityObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ULONG Length,\n    _Out_ PULONG LengthNeeded\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));\n    context->Work = NtQuerySecurityObjectWork;\n    context->Status = STATUS_UNSUCCESSFUL;\n    context->u.NtQuerySecurityObject.Handle = Handle;\n    context->u.NtQuerySecurityObject.SecurityInformation = SecurityInformation;\n    context->u.NtQuerySecurityObject.SecurityDescriptor = SecurityDescriptor;\n    context->u.NtQuerySecurityObject.Length = Length;\n    context->u.NtQuerySecurityObject.LengthNeeded = LengthNeeded;\n\n    return PhpCommonQueryObjectWithTimeout(context);\n}\n\nNTSTATUS PhCallNtSetSecurityObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));\n    context->Work = NtSetSecurityObjectWork;\n    context->Status = STATUS_UNSUCCESSFUL;\n    context->u.NtSetSecurityObject.Handle = Handle;\n    context->u.NtSetSecurityObject.SecurityInformation = SecurityInformation;\n    context->u.NtSetSecurityObject.SecurityDescriptor = SecurityDescriptor;\n\n    return PhpCommonQueryObjectWithTimeout(context);\n}\n\nNTSTATUS PhCallNtQueryFileInformationWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_writes_bytes_opt_(FileInformationLength) PVOID FileInformation,\n    _In_ ULONG FileInformationLength\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));\n    context->Work = NtQueryFileInformationWork;\n    context->Status = STATUS_UNSUCCESSFUL;\n    context->u.NtQueryFileInformation.Handle = Handle;\n    context->u.NtQueryFileInformation.FileInformationClass = FileInformationClass;\n    context->u.NtQueryFileInformation.FileInformation = FileInformation;\n    context->u.NtQueryFileInformation.FileInformationLength = FileInformationLength;\n\n    return PhpCommonQueryObjectWithTimeout(context);\n}\n\nNTSTATUS PhCallKphQueryFileInformationWithTimeout(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_writes_bytes_opt_(FileInformationLength) PVOID FileInformation,\n    _In_ ULONG FileInformationLength\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));\n    context->Work = KphQueryFileInformationWork;\n    context->Status = STATUS_UNSUCCESSFUL;\n    context->u.KphQueryFileInformation.ProcessHandle = ProcessHandle;\n    context->u.KphQueryFileInformation.Handle = Handle;\n    context->u.KphQueryFileInformation.FileInformationClass = FileInformationClass;\n    context->u.KphQueryFileInformation.FileInformation = FileInformation;\n    context->u.KphQueryFileInformation.FileInformationLength = FileInformationLength;\n\n    return PhpCommonQueryObjectWithTimeout(context);\n}\n\n"
  },
  {
    "path": "phlib/http.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017-2023\n *\n */\n\n#include <ph.h>\n#include <phnet.h>\n\n#include <winhttp.h>\n#include <apiimport.h>\n#include <mapldr.h>\n\nstatic const PH_FLAG_MAPPING PhpHttpRequestFlagMappings[] =\n{\n    { PH_HTTP_FLAG_SECURE, WINHTTP_FLAG_SECURE },\n    { PH_HTTP_FLAG_REFRESH, WINHTTP_FLAG_REFRESH }\n};\n\nstatic const PH_FLAG_MAPPING PhpHttpHeaderQueryMappings[] =\n{\n    { PH_HTTP_QUERY_CONTENT_LENGTH, WINHTTP_QUERY_CONTENT_LENGTH },\n    { PH_HTTP_QUERY_STATUS_CODE, WINHTTP_QUERY_STATUS_CODE },\n};\n\nstatic const PH_FLAG_MAPPING PhpHttpFeatureMappings[] =\n{\n    { PH_HTTP_FEATURE_REDIRECTS, WINHTTP_DISABLE_REDIRECTS },\n    { PH_HTTP_FEATURE_KEEP_ALIVE, WINHTTP_DISABLE_KEEP_ALIVE },\n};\n\nstatic const PH_FLAG_MAPPING PhpHttpSecurityFlagsMappings[] =\n{\n    { PH_HTTP_SECURITY_IGNORE_UNKNOWN_CA, SECURITY_FLAG_IGNORE_UNKNOWN_CA },\n    { PH_HTTP_SECURITY_IGNORE_CERT_DATE_INVALID, SECURITY_FLAG_IGNORE_CERT_DATE_INVALID },\n};\n\nNTSTATUS PhHttpErrorToNtStatus(\n    _In_ ULONG WinhttpError\n    );\n\nVOID CALLBACK PhWinHttpStatusCallback(\n    _In_ HINTERNET InternetHandle,\n    _In_ ULONG_PTR Context,\n    _In_ ULONG InternetStatus,\n    _In_opt_ PVOID StatusInformation,\n    _In_ ULONG StatusInformationLength\n    );\n\nNTSTATUS PhGetLastWinHttpErrorAsNtStatus(\n    VOID\n    )\n{\n    return PhHttpErrorToNtStatus(PhGetLastError());\n}\n\nPPH_STRING PhWinHttpUserAgentString(\n    VOID\n    )\n{\n    PH_FORMAT format[4];\n    SIZE_T returnLength;\n    WCHAR formatBuffer[260];\n\n#ifndef PHAPP_VERSION_MAJOR\n#define PHAPP_VERSION_MAJOR 0\n#endif\n\n#ifndef PHAPP_VERSION_MINOR\n#define PHAPP_VERSION_MINOR 0\n#endif\n\n    PhInitFormatS(&format[0], L\"SystemInformer_A2D1C96D_D25915D9_\");\n    PhInitFormatU(&format[1], PHAPP_VERSION_MAJOR);\n    PhInitFormatC(&format[2], L'_');\n    PhInitFormatU(&format[3], PHAPP_VERSION_MINOR);\n\n    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), &returnLength))\n    {\n        PH_STRINGREF stringFormat;\n\n        stringFormat.Buffer = formatBuffer;\n        stringFormat.Length = returnLength - sizeof(UNICODE_NULL);\n\n        return PhCreateString2(&stringFormat);\n    }\n\n    return PhFormat(format, RTL_NUMBER_OF(format), 0);\n}\n\nstatic NTSTATUS PhWinHttpOpen(\n    _Out_ HINTERNET* SessionHandle\n    )\n{\n    NTSTATUS status;\n    HINTERNET sessionHandle;\n    PPH_STRING httpUserAgent;\n    ULONG httpAccessType;\n\n    httpUserAgent = PhWinHttpUserAgentString();\n\n    if (WindowsVersion >= WINDOWS_8_1)\n        httpAccessType = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY;\n    else\n        httpAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;\n\n    if (sessionHandle = WinHttpOpen(\n        PhGetString(httpUserAgent),\n        httpAccessType,\n        WINHTTP_NO_PROXY_NAME,\n        WINHTTP_NO_PROXY_BYPASS,\n        0\n        ))\n    {\n        *SessionHandle = sessionHandle;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *SessionHandle = NULL;\n        status = PhGetLastWinHttpErrorAsNtStatus();\n    }\n\n    PhDereferenceObject(httpUserAgent);\n\n    return status;\n}\n\nstatic NTSTATUS PhWinHttpConnect(\n    _In_ HINTERNET SessionHandle,\n    _In_ PCWSTR ServerName,\n    _In_ USHORT ServerPort,\n    _Out_ HINTERNET* ConnectionHandle\n    )\n{\n    HINTERNET connectionHandle;\n\n    if (connectionHandle = WinHttpConnect(\n        SessionHandle,\n        ServerName,\n        ServerPort,\n        0\n        ))\n    {\n        *ConnectionHandle = connectionHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nstatic NTSTATUS PhWinHttpOpenRequest(\n    _In_ HINTERNET ConnectionHandle,\n    _In_ PCWSTR RequestMethod,\n    _In_ PCWSTR RequestPath,\n    _In_ ULONG Flags,\n    _Out_ HINTERNET* RequestHandle\n    )\n{\n    HINTERNET requestHandle;\n    ULONG httpFlags = 0;\n    //ULONG httpOptions;\n\n    PhMapFlags1(\n        &httpFlags,\n        Flags,\n        PhpHttpRequestFlagMappings,\n        RTL_NUMBER_OF(PhpHttpRequestFlagMappings)\n        );\n\n    if (requestHandle = WinHttpOpenRequest(\n        ConnectionHandle,\n        RequestMethod,\n        RequestPath,\n        NULL,\n        WINHTTP_NO_REFERER,\n        WINHTTP_DEFAULT_ACCEPT_TYPES,\n        httpFlags\n        ))\n    {\n        *RequestHandle = requestHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpInitialize(\n    _Out_ PPH_HTTP_CONTEXT *HttpContext\n    )\n{\n    NTSTATUS status;\n    PPH_HTTP_CONTEXT httpContext;\n    HINTERNET sessionHandle;\n\n    status = PhWinHttpOpen(&sessionHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    httpContext = PhAllocateZero(sizeof(PH_HTTP_CONTEXT));\n    httpContext->SessionHandle = sessionHandle;\n\n    if (WindowsVersion < WINDOWS_8_1)\n    {\n        PhHttpSetOption(sessionHandle, WINHTTP_OPTION_SECURE_PROTOCOLS, WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2);\n    }\n    else\n    {\n        PhHttpSetOption(sessionHandle, WINHTTP_OPTION_SECURE_PROTOCOLS, WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3);\n        PhHttpSetOption(sessionHandle, WINHTTP_OPTION_DECOMPRESSION, WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE);\n        PhHttpSetOption(sessionHandle, WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS, TRUE);\n\n        if (WindowsVersion >= WINDOWS_10)\n        {\n            PhHttpSetOption(sessionHandle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, WINHTTP_PROTOCOL_FLAG_HTTP2);\n            //PhHttpSetOption(sessionHandle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, WINHTTP_PROTOCOL_FLAG_HTTP2 | WINHTTP_PROTOCOL_FLAG_HTTP3);\n        }\n\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            PhHttpSetOption(sessionHandle, WINHTTP_OPTION_IPV6_FAST_FALLBACK, TRUE);\n            PhHttpSetOption(sessionHandle, WINHTTP_OPTION_DISABLE_STREAM_QUEUE, TRUE);\n        }\n\n        if (WindowsVersion >= WINDOWS_11)\n        {\n            PhHttpSetOption(sessionHandle, WINHTTP_OPTION_DISABLE_GLOBAL_POOLING, TRUE);\n            PhHttpSetOption(sessionHandle, WINHTTP_OPTION_TLS_FALSE_START, TRUE);\n            PhHttpSetOption(sessionHandle, WINHTTP_OPTION_TCP_FAST_OPEN, TRUE);\n        }\n\n        if (WindowsVersion >= WINDOWS_11_24H2)\n        {\n            PhHttpSetOption(sessionHandle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, WINHTTP_PROTOCOL_FLAG_HTTP2 | WINHTTP_PROTOCOL_FLAG_HTTP3);\n            PhHttpSetOption(sessionHandle, WINHTTP_OPTION_HTTP3_HANDSHAKE_TIMEOUT, 5000); // 5 second timeout before reverting to HTTP2\n        }\n    }\n\n    *HttpContext = httpContext;\n    return STATUS_SUCCESS;\n}\n\nVOID PhHttpDestroy(\n    _In_ _Maybenull_ _Frees_ptr_ PPH_HTTP_CONTEXT HttpContext\n    )\n{\n    if (!HttpContext)\n        return;\n\n    // if (HttpContext->SessionHandle && HttpContext->EventCallbackRegistered)\n    // {\n    //     // WinHTTP does not synchronize WinHttpSetStatusCallback with worker threads.\n    //     // If a callback originating in another thread is in progress when an application calls WinHttpSetStatusCallback,\n    //     // the application still receives a callback notification even after WinHttpSetStatusCallback successfully\n    //     // sets the callback function to NULL and returns.\n    //\n    //     PhHttpSetCallback(HttpContext->SessionHandle, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS);\n    // }\n\n    PhHttpClose(HttpContext, ULONG_MAX);\n\n    PhFree(HttpContext);\n}\n\nVOID PhHttpClose(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PH_HTTP_SOCKET_CLOSE_TYPE Type\n    )\n{\n    if (Type & PH_HTTP_SOCKET_CLOSE_SESSION)\n    {\n        if (HttpContext->SessionHandle)\n        {\n            WinHttpCloseHandle(HttpContext->SessionHandle);\n            HttpContext->SessionHandle = NULL;\n        }\n    }\n\n    if (Type & PH_HTTP_SOCKET_CLOSE_CONNECTION)\n    {\n        if (HttpContext->ConnectionHandle)\n        {\n            WinHttpCloseHandle(HttpContext->ConnectionHandle);\n            HttpContext->ConnectionHandle = NULL;\n        }\n    }\n\n    if (Type & PH_HTTP_SOCKET_CLOSE_REQUEST)\n    {\n        if (HttpContext->RequestHandle)\n        {\n            WinHttpCloseHandle(HttpContext->RequestHandle);\n            HttpContext->RequestHandle = NULL;\n        }\n    }\n}\n\nNTSTATUS PhHttpConnect(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PCWSTR ServerName,\n    _In_ USHORT ServerPort\n    )\n{\n    NTSTATUS status;\n    HINTERNET connectionHandle;\n\n    if (HttpContext->Callback)\n    {\n        HttpContext->Callback(PHHTTP_EVENT_CONNECTING, NULL, HttpContext->Context);\n    }\n\n    status = PhWinHttpConnect(\n        HttpContext->SessionHandle,\n        ServerName,\n        ServerPort,\n        &connectionHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        HttpContext->ConnectionHandle = connectionHandle;\n    }\n\n    //PDNS_RECORD dnsRecordList = PhDnsQuery(ServerName, DNS_TYPE_A);\n    //\n    //if (dnsRecordList)\n    //{\n    //    for (PDNS_RECORD dnsRecord = dnsRecordList; dnsRecord; dnsRecord = dnsRecord->pNext)\n    //    {\n    //        switch (dnsRecord->wType)\n    //        {\n    //        case DNS_TYPE_A:\n    //            {\n    //                WCHAR ipAddressString[INET_ADDRSTRLEN];\n    //\n    //                RtlIpv4AddressToString((PIN_ADDR)&dnsRecord->Data.A.IpAddress, ipAddressString);\n    //\n    //                HttpContext->ServerName = ServerName;\n    //                HttpContext->ConnectionHandle = WinHttpConnect(\n    //                    HttpContext->SessionHandle,\n    //                    ipAddressString,\n    //                    ServerPort,\n    //                    0\n    //                    );\n    //            }\n    //            break;\n    //        case DNS_TYPE_AAAA:\n    //            {\n    //                WCHAR ipAddressString[INET6_ADDRSTRLEN];\n    //\n    //                RtlIpv6AddressToString((PIN6_ADDR)&dnsRecord->Data.AAAA.Ip6Address, ipAddressString);\n    //\n    //                HttpContext->ServerName = ServerName;\n    //                HttpContext->ConnectionHandle = WinHttpConnect(\n    //                    HttpContext->SessionHandle,\n    //                    ipAddressString,\n    //                    ServerPort,\n    //                    0\n    //                    );\n    //            }\n    //            break;\n    //        }\n    //    }\n    //\n    //    DnsFree(dnsRecordList, DnsFreeRecordList);\n    //}\n\n    return status;\n}\n\nNTSTATUS PhHttpBeginRequest(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_opt_ PCWSTR RequestMethod,\n    _In_ PCWSTR RequestPath,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    HINTERNET requestHandle;\n\n    status = PhWinHttpOpenRequest(\n        HttpContext->ConnectionHandle,\n        RequestMethod,\n        RequestPath,\n        Flags,\n        &requestHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        HttpContext->RequestHandle = requestHandle;\n\n        //PhHttpSetContext(requestHandle, HttpContext);\n    }\n\n    return status;\n}\n\nNTSTATUS PhHttpSendRequest(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_opt_ PCWSTR HeadersBuffer,\n    _In_ ULONG HeadersLength,\n    _In_opt_ PVOID OptionalBuffer,\n    _In_ ULONG OptionalLength,\n    _In_ ULONG TotalLength\n    )\n{\n    if (HttpContext->Callback)\n    {\n        HttpContext->Callback(PHHTTP_EVENT_SENDING_REQUEST, NULL, HttpContext->Context);\n    }\n\n    if (WinHttpSendRequest(\n        HttpContext->RequestHandle,\n        HeadersBuffer,\n        HeadersLength,\n        OptionalBuffer,\n        OptionalLength,\n        TotalLength,\n        (ULONG_PTR)HttpContext\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpReceiveResponse(\n    _In_ PPH_HTTP_CONTEXT HttpContext\n    )\n{\n    if (WinHttpReceiveResponse(HttpContext->RequestHandle, NULL))\n    {\n        //ULONG connectionInfoLength;\n        //WINHTTP_CONNECTION_INFO connectionInfo;\n        //\n        //connectionInfoLength = sizeof(WINHTTP_CONNECTION_INFO);\n        //memset(&connectionInfo, 0, connectionInfoLength);\n        //connectionInfo.cbSize = connectionInfoLength;\n        //\n        //if (WinHttpQueryOption(\n        //    HttpContext->RequestHandle,\n        //    WINHTTP_OPTION_CONNECTION_INFO,\n        //    &connectionInfo,\n        //    &connectionInfoLength\n        //    ))\n        //{\n        //\n        //}\n#if DEBUG\n        {\n            ULONG option = 0;\n            ULONG optionLength = sizeof(ULONG);\n\n            if (WinHttpQueryOption(\n                HttpContext->RequestHandle,\n                WINHTTP_OPTION_HTTP_PROTOCOL_USED,\n                &option,\n                &optionLength\n                ))\n            {\n                if (option & WINHTTP_PROTOCOL_FLAG_HTTP3)\n                {\n                    dprintf(\"[PH_HTTP] %s\", \"HTTP3 socket\\n\");\n                }\n\n                if (option & WINHTTP_PROTOCOL_FLAG_HTTP2)\n                {\n                    dprintf(\"[PH_HTTP] %s\", \"HTTP2 socket\\n\");\n                }\n            }\n        }\n#endif\n\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpReadData(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG BytesCopied\n    )\n{\n    if (WinHttpReadData(\n        HttpContext->RequestHandle,\n        Buffer,\n        BufferLength,\n        BytesCopied\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpWriteData(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG BytesCopied\n    )\n{\n    if (WinHttpWriteData(\n        HttpContext->RequestHandle,\n        Buffer,\n        BufferLength,\n        BytesCopied\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpAddRequestHeaders(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PCWSTR Headers,\n    _In_opt_ ULONG HeadersLength\n    )\n{\n    if (WinHttpAddRequestHeaders(\n        HttpContext->RequestHandle,\n        Headers,\n        HeadersLength ? HeadersLength : ULONG_MAX,\n        WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nPPH_STRING PhHttpQueryHeaders(\n    _In_ PPH_HTTP_CONTEXT HttpContext\n    )\n{\n    ULONG bufferLength = 0;\n    PPH_STRING stringBuffer;\n\n    if (!WinHttpQueryHeaders(\n        HttpContext->RequestHandle,\n        WINHTTP_QUERY_RAW_HEADERS_CRLF,\n        NULL,\n        WINHTTP_NO_OUTPUT_BUFFER,\n        &bufferLength,\n        WINHTTP_NO_HEADER_INDEX\n        ))\n    {\n        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)\n            return NULL;\n    }\n\n    stringBuffer = PhCreateStringEx(NULL, bufferLength);\n\n    if (!WinHttpQueryHeaders(\n        HttpContext->RequestHandle,\n        WINHTTP_QUERY_RAW_HEADERS_CRLF,\n        NULL,\n        stringBuffer->Buffer,\n        &bufferLength,\n        WINHTTP_NO_HEADER_INDEX\n        ))\n    {\n        PhDereferenceObject(stringBuffer);\n        return NULL;\n    }\n\n    return stringBuffer;\n}\n\nPPH_STRING PhHttpQueryHeaderString(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PCWSTR HeaderString\n    )\n{\n    ULONG bufferLength = 0;\n    PPH_STRING stringBuffer;\n\n    if (!WinHttpQueryHeaders(\n        HttpContext->RequestHandle,\n        WINHTTP_QUERY_CUSTOM,\n        HeaderString,\n        WINHTTP_NO_OUTPUT_BUFFER,\n        &bufferLength, // includes null\n        WINHTTP_NO_HEADER_INDEX\n        ))\n    {\n        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)\n            return NULL;\n    }\n\n    stringBuffer = PhCreateStringEx(NULL, bufferLength);\n\n    if (!WinHttpQueryHeaders(\n        HttpContext->RequestHandle,\n        WINHTTP_QUERY_CUSTOM,\n        HeaderString,\n        stringBuffer->Buffer,\n        &bufferLength, // excludes null\n        WINHTTP_NO_HEADER_INDEX\n        ))\n    {\n        PhDereferenceObject(stringBuffer);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(stringBuffer);\n    //stringBuffer->Length = bufferLength;\n\n    return stringBuffer;\n}\n\nNTSTATUS PhHttpQueryHeaderUlong(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG QueryValue,\n    _Out_ PULONG HeaderValue\n    )\n{\n    //ULONG queryFlags = 0;\n    //ULONG headerValue = 0;\n    //ULONG valueLength = sizeof(ULONG);\n    //\n    //PhMapFlags1(\n    //    &queryFlags,\n    //    QueryValue,\n    //    PhpHttpHeaderQueryMappings,\n    //    RTL_NUMBER_OF(PhpHttpHeaderQueryMappings)\n    //    );\n    //\n    //if (WinHttpQueryHeaders(\n    //    HttpContext->RequestHandle,\n    //    queryFlags | WINHTTP_QUERY_FLAG_NUMBER,\n    //    WINHTTP_HEADER_NAME_BY_INDEX,\n    //    &headerValue,\n    //    &valueLength,\n    //    WINHTTP_NO_HEADER_INDEX\n    //    ))\n    //{\n    //    *HeaderValue = headerValue;\n    //    return TRUE;\n    //}\n\n    NTSTATUS status;\n    ULONG64 headerValue;\n\n    status = PhHttpQueryHeaderUlong64(\n        HttpContext,\n        QueryValue,\n        &headerValue\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (headerValue <= ULONG_MAX)\n        {\n            *HeaderValue = (ULONG)headerValue;\n            status = STATUS_SUCCESS;\n        }\n        else\n        {\n            status = STATUS_INTEGER_OVERFLOW;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhHttpQueryHeaderUlong64(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG QueryValue,\n    _Out_ PULONG64 HeaderValue\n    )\n{\n    ULONG queryFlags = 0;\n    ULONG valueLength = 0x100;\n    WCHAR valueBuffer[0x100];\n\n    PhMapFlags1(\n        &queryFlags,\n        QueryValue,\n        PhpHttpHeaderQueryMappings,\n        RTL_NUMBER_OF(PhpHttpHeaderQueryMappings)\n        );\n\n    // Note: The WINHTTP_QUERY_FLAG_NUMBER flag returns invalid integers when\n    // querying some types with ULONG64 like WINHTTP_QUERY_STATUS_CODE. So we'll\n    // do the conversion for improved reliability and performance. (dmex)\n\n    if (WinHttpQueryHeaders(\n        HttpContext->RequestHandle,\n        queryFlags,\n        WINHTTP_HEADER_NAME_BY_INDEX,\n        valueBuffer,\n        &valueLength,\n        WINHTTP_NO_HEADER_INDEX\n        ))\n    {\n        if (valueLength != 0)\n        {\n            PH_STRINGREF string;\n            ULONG64 integer;\n\n            string.Buffer = valueBuffer;\n            string.Length = valueLength;\n\n            if (PhStringToUInt64(&string, 10, &integer))\n            {\n                *HeaderValue = integer;\n                return STATUS_SUCCESS;\n            }\n            else\n            {\n                return STATUS_INTEGER_OVERFLOW;\n            }\n        }\n        else\n        {\n            return STATUS_DATA_LATE_ERROR;\n        }\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\n//ULONG PhHttpQueryStatusCode(\n//    _In_ PPH_HTTP_CONTEXT HttpContext\n//    )\n//{\n//    ULONG headerValue = 0;\n//    ULONG valueLength = sizeof(ULONG);\n//\n//    if (WinHttpQueryHeaders(\n//        HttpContext->RequestHandle,\n//        WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,\n//        WINHTTP_HEADER_NAME_BY_INDEX,\n//        &headerValue,\n//        &valueLength,\n//        WINHTTP_NO_HEADER_INDEX\n//        ))\n//    {\n//        return headerValue;\n//    }\n//\n//    return ULONG_MAX;\n//}\n\nULONG PhHttpQueryStatusCode(\n    _In_ PPH_HTTP_CONTEXT HttpContext\n    )\n{\n    ULONG headerValue = 0;\n    ULONG valueLength = sizeof(ULONG);\n\n    // Retrieves additional information about the status of a response that might not be reflected by the response status code.\n\n    if (WinHttpQueryHeaders(\n        HttpContext->RequestHandle,\n        WINHTTP_QUERY_WARNING,\n        WINHTTP_HEADER_NAME_BY_INDEX,\n        &headerValue,\n        &valueLength,\n        WINHTTP_NO_HEADER_INDEX\n        ))\n    {\n        return headerValue;\n    }\n\n    return ULONG_MAX;\n}\n\nPVOID PhHttpQueryOption(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ BOOLEAN SessionOption,\n    _In_ ULONG QueryOption\n    )\n{\n    HINTERNET queryHandle;\n    ULONG bufferLength = 0;\n    PVOID optionBuffer;\n\n    if (SessionOption)\n        queryHandle = HttpContext->SessionHandle;\n    else\n        queryHandle = HttpContext->RequestHandle;\n\n    if (!WinHttpQueryOption(\n        queryHandle,\n        QueryOption,\n        NULL,\n        &bufferLength\n        ))\n    {\n        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)\n            return NULL;\n    }\n\n    optionBuffer = PhAllocate(bufferLength);\n    memset(optionBuffer, 0, bufferLength);\n\n    if (!WinHttpQueryOption(\n        queryHandle,\n        QueryOption,\n        optionBuffer,\n        &bufferLength\n        ))\n    {\n        PhFree(optionBuffer);\n        return NULL;\n    }\n\n    return optionBuffer;\n}\n\nPPH_STRING PhHttpQueryOptionString(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ BOOLEAN SessionOption,\n    _In_ ULONG QueryOption\n    )\n{\n    PVOID optionBuffer;\n    PPH_STRING stringBuffer = NULL;\n\n    optionBuffer = PhHttpQueryOption(\n        HttpContext,\n        SessionOption,\n        QueryOption\n        );\n\n    if (optionBuffer)\n    {\n        stringBuffer = PhCreateString(optionBuffer);\n        PhFree(optionBuffer);\n    }\n\n    return stringBuffer;\n}\n\nNTSTATUS PhHttpReadDataToBuffer(\n    _In_ PVOID RequestHandle,\n    _Out_ PVOID *Buffer,\n    _Out_ ULONG *BufferLength\n    )\n{\n    PSTR data;\n    ULONG allocatedLength;\n    ULONG dataLength;\n    ULONG returnLength;\n    BYTE buffer[PAGE_SIZE];\n\n    allocatedLength = sizeof(buffer);\n    data = (PSTR)PhAllocate(allocatedLength);\n    dataLength = 0;\n\n    while (WinHttpReadData(RequestHandle, buffer, PAGE_SIZE, &returnLength))\n    {\n        if (returnLength == 0)\n            break;\n\n        if (allocatedLength < dataLength + returnLength)\n        {\n            allocatedLength *= 2;\n            data = PhReAllocate(data, allocatedLength);\n        }\n\n        memcpy(data + dataLength, buffer, returnLength);\n\n        dataLength += returnLength;\n    }\n\n    if (allocatedLength < dataLength + 1)\n    {\n        allocatedLength++;\n        data = PhReAllocate(data, allocatedLength);\n    }\n\n    data[dataLength] = ANSI_NULL;\n\n    if (dataLength)\n    {\n        if (Buffer)\n            *Buffer = data;\n        else\n            PhFree(data);\n\n        if (BufferLength)\n            *BufferLength = dataLength;\n\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        PhFree(data);\n\n        return STATUS_UNSUCCESSFUL;\n    }\n}\n\nNTSTATUS PhHttpDownloadString(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ BOOLEAN Unicode,\n    _Out_ PVOID* StringBuffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferLength;\n\n    status = PhHttpReadDataToBuffer(\n        HttpContext->RequestHandle,\n        &buffer,\n        &bufferLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (Unicode)\n            *StringBuffer = PhConvertUtf8ToUtf16Ex(buffer, bufferLength);\n        else\n            *StringBuffer = PhCreateBytesEx(buffer, bufferLength);\n\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\nNTSTATUS PhHttpDownloadToFile(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PPH_STRINGREF FileName,\n    _In_ PPH_HTTPDOWNLOAD_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_HTTPDOWNLOAD_CONTEXT context = { 0 };\n    NTSTATUS status;\n    HANDLE fileHandle;\n    LARGE_INTEGER fileSize;\n    ULONG64 numberOfBytesTotal = 0;\n    ULONG numberOfBytesRead = 0;\n    ULONG64 numberOfBytesReadTotal = 0;\n    ULONG64 timeTicks;\n    LARGE_INTEGER timeNow;\n    LARGE_INTEGER timeStart;\n    PPH_STRING fileName;\n    IO_STATUS_BLOCK isb;\n    BYTE buffer[PAGE_SIZE];\n\n    PhQuerySystemTime(&timeStart);\n\n    status = PhHttpQueryHeaderUlong64(\n        HttpContext,\n        PH_HTTP_QUERY_CONTENT_LENGTH,\n        &numberOfBytesTotal\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (numberOfBytesTotal == 0)\n        return STATUS_UNSUCCESSFUL;\n\n    fileName = PhGetTemporaryDirectoryRandomAlphaFileName();\n    fileSize.QuadPart = (LONGLONG)numberOfBytesTotal;\n\n    if (PhIsNullOrEmptyString(fileName))\n        return STATUS_UNSUCCESSFUL;\n\n    status = PhCreateFileWin32Ex(\n        &fileHandle,\n        PhGetString(fileName),\n        FILE_GENERIC_WRITE,\n        &fileSize,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_CREATE,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(fileName);\n        return status;\n    }\n\n    memset(buffer, 0, sizeof(buffer));\n\n    while (TRUE)\n    {\n        status = PhHttpReadData(\n            HttpContext,\n            buffer,\n            PAGE_SIZE,\n            &numberOfBytesRead\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n        if (numberOfBytesRead == 0)\n            break;\n\n        status = NtWriteFile(\n            fileHandle,\n            NULL,\n            NULL,\n            NULL,\n            &isb,\n            buffer,\n            numberOfBytesRead,\n            NULL,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n        if (isb.Information == 0)\n            break;\n\n        if (numberOfBytesRead != isb.Information)\n        {\n            status = STATUS_UNSUCCESSFUL;\n            break;\n        }\n\n        if (Callback)\n        {\n            PhQuerySystemTime(&timeNow);\n            timeTicks = (timeNow.QuadPart - timeStart.QuadPart) / PH_TICKS_PER_SEC;\n\n            numberOfBytesReadTotal += isb.Information;\n            context.ReadLength = numberOfBytesReadTotal;\n            context.TotalLength = numberOfBytesTotal;\n            context.BitsPerSecond = numberOfBytesReadTotal / __max(timeTicks, 1);\n            context.Percent = (((DOUBLE)numberOfBytesReadTotal / (DOUBLE)numberOfBytesTotal) * 100);\n\n            if (!Callback(&context, Context))\n                break;\n        }\n    }\n\n    if (numberOfBytesReadTotal != numberOfBytesTotal)\n    {\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    if (status != STATUS_SUCCESS)\n    {\n        PhSetFileDelete(fileHandle);\n    }\n\n    NtClose(fileHandle);\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhCreateDirectoryFullPathWin32(FileName);\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhMoveFileWin32(PhGetString(fileName), PhGetStringRefZ(FileName), FALSE);\n        }\n    }\n\n    PhDereferenceObject(fileName);\n\n    return status;\n}\n\nNTSTATUS PhHttpSetFeature(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG Feature,\n    _In_ BOOLEAN Enable\n    )\n{\n    ULONG featureValue = 0;\n\n    PhMapFlags1(\n        &featureValue,\n        Feature,\n        PhpHttpFeatureMappings,\n        RTL_NUMBER_OF(PhpHttpFeatureMappings)\n        );\n\n    if (WinHttpSetOption(\n        HttpContext->RequestHandle,\n        Enable ? WINHTTP_OPTION_ENABLE_FEATURE : WINHTTP_OPTION_DISABLE_FEATURE,\n        &featureValue,\n        sizeof(ULONG)\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpSetOption(\n    _In_ PVOID HttpHandle,\n    _In_ ULONG Option,\n    _In_ ULONG Value\n    )\n{\n    ULONG optionValue = Value;\n\n    if (WinHttpSetOption(\n        HttpHandle,\n        Option,\n        &optionValue,\n        sizeof(ULONG)\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpSetOptionString(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG Option,\n    _In_ PPH_STRINGREF Value\n    )\n{\n    ULONG optionLength = (ULONG)Value->Length;\n\n    if (WinHttpSetOption(\n        HttpContext->RequestHandle,\n        Option,\n        Value->Buffer,\n        optionLength\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpSetCallback(\n    _In_ PVOID HttpHandle,\n    _In_ PPH_HTTP_STATUS_CALLBACK Callback,\n    _In_ ULONG NotificationFlags\n    )\n{\n    PPH_HTTP_STATUS_CALLBACK previousCallback;\n\n    previousCallback = WinHttpSetStatusCallback(\n        HttpHandle,\n        Callback,\n        NotificationFlags,\n        0\n        );\n\n    if (previousCallback == WINHTTP_INVALID_STATUS_CALLBACK)\n    {\n        return PhGetLastWinHttpErrorAsNtStatus();\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhHttpGetContext(\n    _In_ PVOID HttpHandle,\n    _In_ PVOID Context\n    )\n{\n    ULONG bufferLength = sizeof(ULONG_PTR);\n\n    if (WinHttpQueryOption(HttpHandle, WINHTTP_OPTION_CONTEXT_VALUE, Context, &bufferLength))\n        return STATUS_SUCCESS;\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpSetContext(\n    _In_ PVOID HttpHandle,\n    _In_ PVOID Context\n    )\n{\n    if (WinHttpSetOption(HttpHandle, WINHTTP_OPTION_CONTEXT_VALUE, Context, sizeof(ULONG_PTR)))\n        return STATUS_SUCCESS;\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpSetSecurity(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG Feature\n    )\n{\n    ULONG featureValue = 0;\n\n    PhMapFlags1(\n        &featureValue,\n        Feature,\n        PhpHttpSecurityFlagsMappings,\n        RTL_NUMBER_OF(PhpHttpSecurityFlagsMappings)\n        );\n\n    if (WinHttpSetOption(\n        HttpContext->RequestHandle,\n        WINHTTP_OPTION_SECURITY_FLAGS,\n        &featureValue,\n        sizeof(ULONG)\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpSetProtocol(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ BOOLEAN Session,\n    _In_ ULONG Protocol,\n    _In_ ULONG Timeout\n    )\n{\n    NTSTATUS status;\n\n    if (Session)\n    {\n        status = PhHttpSetOption(HttpContext->SessionHandle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, Protocol);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (FlagOn(Protocol, PH_HTTP_PROTOCOL_FLAG_HTTP3))\n        {\n            status = PhHttpSetOption(HttpContext->SessionHandle, WINHTTP_OPTION_HTTP3_HANDSHAKE_TIMEOUT, Timeout);\n        }\n    }\n    else\n    {\n        status = PhHttpSetOption(HttpContext->RequestHandle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, Protocol);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (FlagOn(Protocol, PH_HTTP_PROTOCOL_FLAG_HTTP3))\n        {\n            status = PhHttpSetOption(HttpContext->RequestHandle, WINHTTP_OPTION_HTTP3_HANDSHAKE_TIMEOUT, Timeout);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhHttpCrackUrl(\n    _In_ PPH_STRING Url,\n    _Out_ PPH_STRING *HostPart,\n    _Out_ PPH_STRING *PathPart,\n    _Out_ PUSHORT PortPart\n    )\n{\n    URL_COMPONENTS httpParts;\n    PPH_STRING hostPart = NULL;\n    PPH_STRING pathPart = NULL;\n\n    memset(&httpParts, 0, sizeof(URL_COMPONENTS));\n    httpParts.dwStructSize = sizeof(URL_COMPONENTS);\n    httpParts.dwHostNameLength = ULONG_MAX;\n    httpParts.dwUrlPathLength = ULONG_MAX;\n\n    if (!WinHttpCrackUrl(\n        Url->Buffer,\n        (ULONG)Url->Length / sizeof(WCHAR),\n        0,\n        &httpParts\n        ))\n    {\n        return PhGetLastWinHttpErrorAsNtStatus();\n    }\n\n    if (httpParts.dwHostNameLength)\n    {\n        hostPart = PhCreateStringEx(httpParts.lpszHostName, httpParts.dwHostNameLength * sizeof(WCHAR));\n    }\n\n    if (httpParts.dwUrlPathLength)\n    {\n        pathPart = PhCreateStringEx(httpParts.lpszUrlPath, httpParts.dwUrlPathLength * sizeof(WCHAR));\n    }\n\n    if (hostPart && pathPart)\n    {\n        *HostPart = hostPart;\n        *PathPart = pathPart;\n\n        if (PortPart)\n        {\n            *PortPart = httpParts.nPort;\n        }\n\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        PhClearReference(&hostPart);\n        PhClearReference(&pathPart);\n        return STATUS_UNSUCCESSFUL;\n    }\n}\n\nPPH_STRING PhHttpGetErrorMessage(\n    _In_ ULONG ErrorCode\n    )\n{\n    PVOID winhttpHandle;\n    PPH_STRING message = NULL;\n\n    if (!(winhttpHandle = PhGetLoaderEntryDllBaseZ(L\"winhttp.dll\")))\n        return NULL;\n\n    if (message = PhGetMessage(winhttpHandle, 0xb, PhGetUserDefaultLangID(), ErrorCode))\n    {\n        PhTrimToNullTerminatorString(message);\n    }\n\n    // Remove any trailing newline\n    if (message && message->Length >= 2 * sizeof(WCHAR) &&\n        message->Buffer[message->Length / sizeof(WCHAR) - 2] == L'\\r' &&\n        message->Buffer[message->Length / sizeof(WCHAR) - 1] == L'\\n')\n    {\n        PhMoveReference(&message, PhCreateStringEx(message->Buffer, message->Length - 2 * sizeof(WCHAR)));\n    }\n\n    return message;\n}\n\nNTSTATUS PhHttpGetCertificateInfo(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _Out_ PPH_HTTP_CERTIFICATE_INFO Certificate\n    )\n{\n    ULONG certificateInfoLength;\n    WINHTTP_CERTIFICATE_INFO certificateInfoBuffer;\n\n    certificateInfoLength = sizeof(WINHTTP_CERTIFICATE_INFO);\n    RtlZeroMemory(&certificateInfoBuffer, sizeof(WINHTTP_CERTIFICATE_INFO));\n\n    if (WinHttpQueryOption(\n        HttpContext->SessionHandle,\n        WINHTTP_OPTION_EXTENDED_ERROR,\n        &certificateInfoBuffer,\n        &certificateInfoLength\n        ))\n    {\n        RtlZeroMemory(Certificate, sizeof(PH_HTTP_CERTIFICATE_INFO));\n        Certificate->Expiry.LowPart = certificateInfoBuffer.ftExpiry.dwLowDateTime;\n        Certificate->Expiry.HighPart = certificateInfoBuffer.ftExpiry.dwHighDateTime;\n        Certificate->Start.LowPart = certificateInfoBuffer.ftStart.dwLowDateTime;\n        Certificate->Start.HighPart = certificateInfoBuffer.ftStart.dwHighDateTime;\n        Certificate->SubjectInfo = certificateInfoBuffer.lpszSubjectInfo;\n        Certificate->IssuerInfo = certificateInfoBuffer.lpszIssuerInfo;\n        Certificate->ProtocolName = certificateInfoBuffer.lpszProtocolName;\n        Certificate->SignatureAlgName = certificateInfoBuffer.lpszSignatureAlgName;\n        Certificate->EncryptionAlgName = certificateInfoBuffer.lpszEncryptionAlgName;\n        Certificate->KeySize = certificateInfoBuffer.dwKeySize;\n\n        return STATUS_SUCCESS;\n    }\n\n    RtlZeroMemory(Certificate, sizeof(PH_HTTP_CERTIFICATE_INFO));\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpGetTimingInfo(\n    _In_ PPH_HTTP_CONTEXT HttpContext\n    )\n{\n    ULONG requestTimeLength;\n    WINHTTP_REQUEST_TIMES requestTimeBuffer;\n\n    requestTimeLength = sizeof(WINHTTP_REQUEST_TIMES);\n    memset(&requestTimeBuffer, 0, sizeof(WINHTTP_REQUEST_TIMES));\n    requestTimeBuffer.cTimes = WinHttpRequestTimeMax;\n\n    if (WinHttpQueryOption(\n        HttpContext->SessionHandle,\n        WINHTTP_OPTION_REQUEST_TIMES,\n        &requestTimeBuffer,\n        &requestTimeLength\n        ))\n    {\n        for (ULONG i = 0; i < WinHttpRequestTimeMax; i++)\n        {\n            dprintf(\"%lu: %lu\\n\", i, requestTimeBuffer.rgullTimes[i]);\n        }\n\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpGetStatistics(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    )\n{\n    // WINHTTP_OPTION_CONNECTION_STATS_V0\n    // WINHTTP_OPTION_CONNECTION_STATS_V1\n    // WINHTTP_OPTION_CONNECTION_STATS_V2\n\n    if (WinHttpQueryOption(\n        HttpContext->SessionHandle,\n        WINHTTP_OPTION_CONNECTION_STATS_V0,\n        Buffer,\n        BufferLength\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n\n    //ULONG statisticsInfoLength = sizeof(TCP_INFO_v0);\n    //TCP_INFO_v0 statisticsInfo = { 0 };\n    //dprintf(\"State: %d\\n\", statisticsInfo.State);\n    //dprintf(\"Mss: %lu\\n\", statisticsInfo.Mss);\n    //dprintf(\"ConnectionTimeMs: %llu\\n\", statisticsInfo.ConnectionTimeMs);\n    //dprintf(\"TimestampsEnabled: %d\\n\", statisticsInfo.TimestampsEnabled);\n    //dprintf(\"RttUs: %lu\\n\", statisticsInfo.RttUs);\n    //dprintf(\"MinRttUs: %lu\\n\", statisticsInfo.MinRttUs);\n    //dprintf(\"BytesInFlight: %lu\\n\", statisticsInfo.BytesInFlight);\n    //dprintf(\"Cwnd: %lu\\n\", statisticsInfo.Cwnd);\n    //dprintf(\"SndWnd: %lu\\n\", statisticsInfo.SndWnd);\n    //dprintf(\"RcvWnd: %lu\\n\", statisticsInfo.RcvWnd);\n    //dprintf(\"RcvBuf: %lu\\n\", statisticsInfo.RcvBuf);\n    //dprintf(\"BytesOut: %llu\\n\", statisticsInfo.BytesOut);\n    //dprintf(\"BytesIn: %llu\\n\", statisticsInfo.BytesIn);\n    //dprintf(\"BytesReordered: %lu\\n\", statisticsInfo.BytesReordered);\n    //dprintf(\"BytesRetrans: %lu\\n\", statisticsInfo.BytesRetrans);\n    //dprintf(\"FastRetrans: %lu\\n\", statisticsInfo.FastRetrans);\n    //dprintf(\"DupAcksIn: %lu\\n\", statisticsInfo.DupAcksIn);\n    //dprintf(\"TimeoutEpisodes: %lu\\n\", statisticsInfo.TimeoutEpisodes);\n    //dprintf(\"SynRetrans: %u\\n\", statisticsInfo.SynRetrans);\n}\n\nULONG PhHttpGetExtendedStatusCode(\n    _In_ PPH_HTTP_CONTEXT HttpContext\n    )\n{\n    ULONG bufferLength = sizeof(ULONG);\n    ULONG socketcode = ULONG_MAX;\n\n    WinHttpQueryOption(\n        HttpContext->SessionHandle,\n        WINHTTP_OPTION_EXTENDED_ERROR,\n        &socketcode,\n        &bufferLength\n        );\n\n    return socketcode;\n}\n\nNTSTATUS PhHttpSetCredentials(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Value\n    )\n{\n    if (WinHttpSetCredentials(\n        HttpContext->RequestHandle,\n        WINHTTP_AUTH_TARGET_SERVER,\n        WINHTTP_AUTH_SCHEME_BASIC,\n        Name,\n        Value,\n        NULL\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWinHttpErrorAsNtStatus();\n}\n\nNTSTATUS PhHttpSetEventCallback(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PPH_HTTP_EVENT_CALLBACK EventCallback,\n    _In_opt_ PVOID Context\n    )\n{\n    HttpContext->Callback = EventCallback;\n    HttpContext->Context = Context;\n\n    //PhHttpSetContext(HttpContext->SessionHandle, HttpContext);\n    //PhHttpSetCallback(HttpContext->SessionHandle, PhWinHttpStatusCallback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS);\n\n    if (HttpContext->Callback)\n    {\n        HttpContext->Callback(PHHTTP_EVENT_INITIALIZING, NULL, Context);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nVOID CALLBACK PhWinHttpStatusCallback(\n    _In_ HINTERNET InternetHandle,\n    _In_ ULONG_PTR Context,\n    _In_ ULONG InternetStatus,\n    _In_opt_ PVOID StatusInformation,\n    _In_ ULONG StatusInformationLength\n    )\n{\n    PPH_HTTP_CONTEXT context = NULL;\n\n    if (!Context)\n    {\n        PVOID httpContext;\n\n        if (NT_SUCCESS(PhHttpGetContext(InternetHandle, &httpContext)))\n        {\n            context = (PPH_HTTP_CONTEXT)httpContext;\n        }\n    }\n    else\n    {\n        context = (PPH_HTTP_CONTEXT)Context;\n    }\n\n    switch (InternetStatus)\n    {\n    case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME:\n        {\n            PH_STRINGREF string;\n\n            string.Buffer = (PWSTR)StatusInformation;\n            string.Length = (StatusInformationLength - 1) * sizeof(WCHAR);\n\n            if (context->Callback)\n            {\n                context->Callback(PHHTTP_EVENT_RESOLVING_NAME, &string, context->Context);\n            }\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED:\n        {\n            PH_STRINGREF string;\n\n            string.Buffer = (PWSTR)StatusInformation;\n            string.Length = (StatusInformationLength - 1) * sizeof(WCHAR);\n\n            if (context->Callback)\n            {\n                context->Callback(PHHTTP_EVENT_NAME_RESOLVED, &string, context->Context);\n            }\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER:\n        {\n            PH_STRINGREF string;\n\n            string.Buffer = (PWSTR)StatusInformation;\n            string.Length = (StatusInformationLength - 1) * sizeof(WCHAR);\n\n            if (context->Callback)\n            {\n                context->Callback(PHHTTP_EVENT_CONNECTING, &string, context->Context);\n            }\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER:\n        {\n            PH_STRINGREF string;\n\n            string.Buffer = (PWSTR)StatusInformation;\n            string.Length = (StatusInformationLength - 1) * sizeof(WCHAR);\n\n            if (context->Callback)\n            {\n                context->Callback(InternetStatus, &string, context->Context);\n            }\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_SENDING_REQUEST\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_REQUEST_SENT:\n        {\n            ULONG numberOfBytesSent = *(PULONG)StatusInformation;\n            dprintf(\"WINHTTP_CALLBACK_STATUS_REQUEST_SENT: %lu\\n\", numberOfBytesSent);\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED:\n        {\n            ULONG numberOfBytesReceived = *(PULONG)StatusInformation;\n            dprintf(\"WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED: %lu\\n\", numberOfBytesReceived);\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_HANDLE_CREATED:\n        {\n            HINTERNET handle = (HINTERNET)*(PULONG_PTR)StatusInformation;\n            ULONG option = 0;\n            ULONG optionLength = sizeof(ULONG);\n\n            dprintf(\"WINHTTP_CALLBACK_STATUS_HANDLE_CREATED: 0x%llx \", handle);\n\n            if (WinHttpQueryOption(\n                handle,\n                WINHTTP_OPTION_HANDLE_TYPE,\n                &option,\n                &optionLength\n                ))\n            {\n                switch (option)\n                {\n                case WINHTTP_HANDLE_TYPE_SESSION:\n                    dprintf(\"[%s]\\n\", \"Session handle\");\n                    break;\n                case WINHTTP_HANDLE_TYPE_CONNECT:\n                    dprintf(\"[%s]\\n\", \"Connect handle\");\n                    break;\n                case WINHTTP_HANDLE_TYPE_REQUEST:\n                    dprintf(\"[%s]\\n\", \"Request handle\");\n                    break;\n                case WINHTTP_HANDLE_TYPE_PROXY_RESOLVER:\n                    dprintf(\"[%s]\\n\", \"Proxy handle\");\n                    break;\n                case WINHTTP_HANDLE_TYPE_WEBSOCKET:\n                    dprintf(\"[%s]\\n\", \"Websocket handle\");\n                    break;\n                case WINHTTP_HANDLE_TYPE_PROTOCOL:\n                    dprintf(\"[%s]\\n\", \"Protocol handle\");\n                    break;\n                }\n            }\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:\n        {\n            HINTERNET handle = (HINTERNET)*(PULONG_PTR)StatusInformation;\n\n            dprintf(\"WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING: 0x%llx\\n\", handle);\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_DETECTING_PROXY:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_DETECTING_PROXY\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_REDIRECT:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_REDIRECT\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_SECURE_FAILURE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_READ_COMPLETE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_REQUEST_ERROR\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_GETPROXYSETTINGS_COMPLETE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_GETPROXYSETTINGS_COMPLETE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE\\n\");\n        }\n        break;\n    case WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE:\n        {\n            dprintf(\"WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE\\n\");\n        }\n        break;\n    }\n}\n\nNTSTATUS PhHttpErrorToNtStatus(\n    _In_ ULONG WinhttpError\n    )\n{\n    switch (WinhttpError)\n    {\n    case ERROR_WINHTTP_OUT_OF_HANDLES: return STATUS_NO_MEMORY;\n    case ERROR_WINHTTP_TIMEOUT: return STATUS_TIMEOUT;\n    case ERROR_WINHTTP_INTERNAL_ERROR: return STATUS_INTERNAL_ERROR;\n    case ERROR_WINHTTP_INVALID_URL: return STATUS_OBJECT_PATH_INVALID;\n    case ERROR_WINHTTP_UNRECOGNIZED_SCHEME: return STATUS_OBJECT_NAME_INVALID;\n    case ERROR_WINHTTP_NAME_NOT_RESOLVED: return STATUS_OBJECT_NAME_NOT_FOUND;\n    case ERROR_WINHTTP_INVALID_OPTION:\n    case ERROR_WINHTTP_OPTION_NOT_SETTABLE: return STATUS_INVALID_DEVICE_REQUEST;\n    case ERROR_WINHTTP_SHUTDOWN:  return STATUS_SYSTEM_SHUTDOWN;\n    case ERROR_WINHTTP_LOGIN_FAILURE: return STATUS_LOGON_FAILURE;\n    case ERROR_WINHTTP_OPERATION_CANCELLED: return STATUS_CANCELLED;\n    case ERROR_WINHTTP_INCORRECT_HANDLE_TYPE:\n    case ERROR_WINHTTP_INCORRECT_HANDLE_STATE: return STATUS_INVALID_HANDLE;\n    case ERROR_WINHTTP_CANNOT_CONNECT: return STATUS_CONNECTION_REFUSED;\n    case ERROR_WINHTTP_CONNECTION_ERROR: return STATUS_CONNECTION_ABORTED;\n    case ERROR_WINHTTP_RESEND_REQUEST: return STATUS_RETRY;\n    case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED: return STATUS_PKINIT_FAILURE;\n    case ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN:\n    case ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND:\n    case ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND:\n    case ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN: return STATUS_INVALID_DEVICE_STATE;\n    case ERROR_WINHTTP_HEADER_NOT_FOUND: return STATUS_OBJECT_NAME_NOT_FOUND;\n    case ERROR_WINHTTP_INVALID_SERVER_RESPONSE: return STATUS_INVALID_NETWORK_RESPONSE;\n    case ERROR_WINHTTP_INVALID_HEADER:\n    case ERROR_WINHTTP_INVALID_QUERY_REQUEST: return STATUS_INVALID_PARAMETER;\n    case ERROR_WINHTTP_HEADER_ALREADY_EXISTS: return STATUS_OBJECT_NAME_COLLISION;\n    case ERROR_WINHTTP_REDIRECT_FAILED: return STATUS_UNSUCCESSFUL;\n    case ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR: return STATUS_LOGON_FAILURE;\n    case ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT:\n    case ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT:\n    case ERROR_WINHTTP_UNHANDLED_SCRIPT_TYPE:\n    case ERROR_WINHTTP_SCRIPT_EXECUTION_ERROR: return STATUS_INVALID_PARAMETER;\n    case ERROR_WINHTTP_NOT_INITIALIZED: return STATUS_INVALID_DEVICE_STATE;\n    case ERROR_WINHTTP_SECURE_FAILURE: return STATUS_ENCRYPTION_FAILED;\n    case ERROR_WINHTTP_SECURE_CERT_DATE_INVALID:\n    case ERROR_WINHTTP_SECURE_CERT_CN_INVALID:\n    case ERROR_WINHTTP_SECURE_INVALID_CA:\n    case ERROR_WINHTTP_SECURE_CERT_REV_FAILED:\n    case ERROR_WINHTTP_SECURE_CHANNEL_ERROR:\n    case ERROR_WINHTTP_SECURE_INVALID_CERT:\n    case ERROR_WINHTTP_SECURE_CERT_REVOKED:\n    case ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE:\n    case ERROR_WINHTTP_AUTODETECTION_FAILED: return STATUS_NO_SECURITY_CONTEXT;\n    case ERROR_WINHTTP_HEADER_COUNT_EXCEEDED:\n    case ERROR_WINHTTP_HEADER_SIZE_OVERFLOW:\n    case ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW:\n    case ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW: return STATUS_BUFFER_OVERFLOW;\n    case ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY:\n    case ERROR_WINHTTP_CLIENT_CERT_NO_ACCESS_PRIVATE_KEY: return STATUS_INVALID_PARAMETER;\n    case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED_PROXY: return STATUS_NO_SECURITY_CONTEXT;\n    case ERROR_WINHTTP_SECURE_FAILURE_PROXY:\n    case ERROR_WINHTTP_RESERVED_189:\n    case ERROR_WINHTTP_HTTP_PROTOCOL_MISMATCH:\n    case ERROR_WINHTTP_GLOBAL_CALLBACK_FAILED: return STATUS_INVALID_PARAMETER;\n    case ERROR_WINHTTP_FEATURE_DISABLED:\n    case ERROR_WINHTTP_FAST_FORWARDING_NOT_SUPPORTED: return STATUS_NOT_SUPPORTED;\n    }\n\n    if (\n        WinhttpError < WINHTTP_ERROR_BASE ||\n        WinhttpError > ERROR_WINHTTP_FAST_FORWARDING_NOT_SUPPORTED\n        )\n    {\n        return PhDosErrorToNtStatus(WinhttpError);\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n//\n// IPv4 and IPv6\n//\n\nNTSTATUS PhIpv4AddressToString(\n    _In_ PCIN_ADDR Address,\n    _In_ USHORT Port,\n    _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString,\n    _Inout_ PULONG AddressStringLength\n    )\n{\n    return RtlIpv4AddressToStringEx(Address, Port, AddressString, AddressStringLength);\n}\n\nNTSTATUS PhIpv4StringToAddress(\n    _In_ PCWSTR AddressString,\n    _In_ BOOLEAN Strict,\n    _Out_ PIN_ADDR Address,\n    _Out_ PUSHORT Port\n    )\n{\n    return RtlIpv4StringToAddressEx(AddressString, Strict, Address, Port);\n}\n\nNTSTATUS PhIpv6AddressToString(\n    _In_ PCIN6_ADDR Address,\n    _In_ ULONG ScopeId,\n    _In_ USHORT Port,\n    _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString,\n    _Inout_ PULONG AddressStringLength\n    )\n{\n    return RtlIpv6AddressToStringEx(Address, ScopeId, Port, AddressString, AddressStringLength);\n}\n\nNTSTATUS PhIpv6StringToAddress(\n    _In_ PCWSTR AddressString,\n    _Out_ PIN6_ADDR Address,\n    _Out_ PULONG ScopeId,\n    _Out_ PUSHORT Port\n    )\n{\n    return RtlIpv6StringToAddressEx(AddressString, Address, ScopeId, Port);\n}\n\n//\n// DOH\n//\n\nHINTERNET PhCreateDohConnectionHandle(\n    _In_opt_ PCWSTR DnsServerAddress\n    )\n{\n    static HINTERNET httpSessionHandle = NULL;\n    static HINTERNET httpConnectionHandle = NULL;\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        NTSTATUS status;\n\n        status = PhWinHttpOpen(&httpSessionHandle);\n\n        if (NT_SUCCESS(status))\n        {\n            if (WindowsVersion < WINDOWS_8_1)\n            {\n                PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_SECURE_PROTOCOLS, WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2);\n            }\n            else\n            {\n                PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_SECURE_PROTOCOLS, WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3);\n                PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE);\n\n                if (WindowsVersion >= WINDOWS_10)\n                {\n                    PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, WINHTTP_PROTOCOL_FLAG_HTTP2);\n                    //PhHttpSetOption(sessionHandle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, WINHTTP_PROTOCOL_FLAG_HTTP2 | WINHTTP_PROTOCOL_FLAG_HTTP3);\n                }\n\n                if (WindowsVersion >= WINDOWS_10_RS5)\n                {\n                    PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_IPV6_FAST_FALLBACK, TRUE);\n                    PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DISABLE_STREAM_QUEUE, TRUE);\n                }\n\n                if (WindowsVersion >= WINDOWS_11)\n                {\n                    PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DISABLE_GLOBAL_POOLING, TRUE);\n                    PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_TLS_FALSE_START, TRUE);\n                    PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_TCP_FAST_OPEN, TRUE);\n                }\n\n                if (WindowsVersion >= WINDOWS_11_24H2)\n                {\n                    PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, WINHTTP_PROTOCOL_FLAG_HTTP2 | WINHTTP_PROTOCOL_FLAG_HTTP3);\n                    PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_HTTP3_HANDSHAKE_TIMEOUT, 5000); // 5 second timeout before reverting to HTTP2\n                }\n            }\n\n            PhHttpSetOption(httpSessionHandle, WINHTTP_OPTION_MAX_CONNS_PER_SERVER, 1);\n\n            if (WindowsVersion >= WINDOWS_10)\n            {\n                httpConnectionHandle = WinHttpConnect(\n                    httpSessionHandle,\n                    DnsServerAddress ? DnsServerAddress : L\"1.1.1.1\",\n                    INTERNET_DEFAULT_HTTPS_PORT,\n                    0\n                    );\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (WindowsVersion < WINDOWS_10)\n    {\n        httpConnectionHandle = WinHttpConnect(\n            httpSessionHandle,\n            DnsServerAddress ? DnsServerAddress : L\"1.1.1.1\",\n            INTERNET_DEFAULT_HTTPS_PORT,\n            0\n            );\n    }\n\n    return httpConnectionHandle;\n}\n\nHINTERNET PhCreateDohRequestHandle(\n    _In_ HINTERNET HttpConnectionHandle\n    )\n{\n    static PCWSTR httpAcceptTypes[2] = { L\"application/dns-message\", NULL };\n    HINTERNET httpRequestHandle;\n    ULONG httpOptions;\n\n    if (!(httpRequestHandle = WinHttpOpenRequest(\n        HttpConnectionHandle,\n        L\"POST\",\n        L\"/dns-query\",\n        NULL,\n        WINHTTP_NO_REFERER,\n        httpAcceptTypes,\n        WINHTTP_FLAG_SECURE\n        )))\n    {\n        return NULL;\n    }\n\n    WinHttpAddRequestHeaders(\n        httpRequestHandle,\n        L\"Content-Type: application/dns-message\",\n        ULONG_MAX,\n        WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE\n        );\n\n    if (WindowsVersion <= WINDOWS_8)\n    {\n        // Winhttp on Windows 7 doesn't correctly validate the certificate CN for connections using an IP address. (dmex)\n        httpOptions = SECURITY_FLAG_IGNORE_CERT_CN_INVALID;\n\n        WinHttpSetOption(\n            httpRequestHandle,\n            WINHTTP_OPTION_SECURITY_FLAGS,\n            &httpOptions,\n            sizeof(ULONG)\n            );\n    }\n\n    return httpRequestHandle;\n}\n\nPPH_STRING PhDnsReverseLookupNameFromAddress(\n    _In_ ULONG Type,\n    _In_ PVOID Address\n    )\n{\n#define IP4_REVERSE_DOMAIN_STRING_LENGTH (IP4_ADDRESS_STRING_LENGTH + sizeof(DNS_IP4_REVERSE_DOMAIN_STRING_W) + 1)\n#define IP6_REVERSE_DOMAIN_STRING_LENGTH (IP6_ADDRESS_STRING_LENGTH + sizeof(DNS_IP6_REVERSE_DOMAIN_STRING_W) + 1)\n\n    switch (Type)\n    {\n    case PH_NETWORK_TYPE_IPV4:\n        {\n            static CONST PH_STRINGREF reverseLookupDomainName = PH_STRINGREF_INIT(DNS_IP4_REVERSE_DOMAIN_STRING);\n            PIN_ADDR inAddrV4 = Address;\n            PH_FORMAT format[9];\n            SIZE_T returnLength;\n            WCHAR reverseNameBuffer[IP4_REVERSE_DOMAIN_STRING_LENGTH];\n\n            PhInitFormatU(&format[0], inAddrV4->s_impno);\n            PhInitFormatC(&format[1], L'.');\n            PhInitFormatU(&format[2], inAddrV4->s_lh);\n            PhInitFormatC(&format[3], L'.');\n            PhInitFormatU(&format[4], inAddrV4->s_host);\n            PhInitFormatC(&format[5], L'.');\n            PhInitFormatU(&format[6], inAddrV4->s_net);\n            PhInitFormatC(&format[7], L'.');\n            PhInitFormatSR(&format[8], reverseLookupDomainName);\n\n            if (PhFormatToBuffer(\n                format,\n                RTL_NUMBER_OF(format),\n                reverseNameBuffer,\n                sizeof(reverseNameBuffer),\n                &returnLength\n                ))\n            {\n                PH_STRINGREF reverseNameString;\n\n                reverseNameString.Buffer = reverseNameBuffer;\n                reverseNameString.Length = returnLength - sizeof(UNICODE_NULL);\n\n                return PhCreateString2(&reverseNameString);\n            }\n            else\n            {\n                return PhFormat(format, RTL_NUMBER_OF(format), IP4_REVERSE_DOMAIN_STRING_LENGTH);\n            }\n        }\n    case PH_NETWORK_TYPE_IPV6:\n        {\n            static CONST PH_STRINGREF reverseLookupDomainName = PH_STRINGREF_INIT(DNS_IP6_REVERSE_DOMAIN_STRING);\n            PIN6_ADDR inAddrV6 = Address;\n            PH_STRING_BUILDER stringBuilder;\n\n            // DNS_MAX_IP6_REVERSE_NAME_LENGTH\n            PhInitializeStringBuilder(&stringBuilder, IP6_REVERSE_DOMAIN_STRING_LENGTH);\n\n            for (LONG i = sizeof(IN6_ADDR) - 1; i >= 0; i--)\n            {\n                PH_FORMAT format[4];\n                SIZE_T returnLength;\n                WCHAR reverseNameBuffer[IP6_REVERSE_DOMAIN_STRING_LENGTH];\n\n                PhInitFormatX(&format[0], inAddrV6->s6_addr[i] & 0xF);\n                PhInitFormatC(&format[1], L'.');\n                PhInitFormatX(&format[2], (inAddrV6->s6_addr[i] >> 4) & 0xF);\n                PhInitFormatC(&format[3], L'.');\n\n                if (PhFormatToBuffer(\n                    format,\n                    RTL_NUMBER_OF(format),\n                    reverseNameBuffer,\n                    sizeof(reverseNameBuffer),\n                    &returnLength\n                    ))\n                {\n                    PhAppendStringBuilderEx(\n                        &stringBuilder,\n                        reverseNameBuffer,\n                        returnLength - sizeof(UNICODE_NULL)\n                        );\n                }\n                else\n                {\n                    PhAppendFormatStringBuilder(\n                        &stringBuilder,\n                        L\"%hhx.%hhx.\",\n                        inAddrV6->s6_addr[i] & 0xF,\n                        (inAddrV6->s6_addr[i] >> 4) & 0xF\n                        );\n                }\n            }\n\n            PhAppendStringBuilder(&stringBuilder, &reverseLookupDomainName);\n\n            return PhFinalStringBuilderString(&stringBuilder);\n        }\n    default:\n        return NULL;\n    }\n}\n\nstatic typeof(&DnsQuery_W) DnsQuery_W_I = NULL;\n#if defined(PHNT_DNSQUERY_FUTURE)\nstatic typeof(&DnsQueryEx) DnsQueryEx_I = NULL;\nstatic typeof(&DnsCancelQuery) DnsCancelQuery_I = NULL;\n#endif\nstatic typeof(&DnsExtractRecordsFromMessage_W) DnsExtractRecordsFromMessage_W_I = NULL;\nstatic typeof(&DnsWriteQuestionToBuffer_W) DnsWriteQuestionToBuffer_W_I = NULL;\nstatic typeof(&DnsFree) DnsFree_I = NULL;\n\nstatic BOOLEAN PhDnsApiInitialized(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOLEAN initialized = FALSE;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"dnsapi.dll\"))\n        {\n            DnsQuery_W_I = PhGetDllBaseProcedureAddress(baseAddress, \"DnsQuery_W\", 0);\n#if defined(PHNT_DNSQUERY_FUTURE)\n            DnsQueryEx_I = PhGetDllBaseProcedureAddress(baseAddress, \"DnsQueryEx\", 0);\n            DnsCancelQuery_I = PhGetDllBaseProcedureAddress(baseAddress, \"DnsCancelQuery\", 0);\n#endif\n            DnsExtractRecordsFromMessage_W_I = PhGetDllBaseProcedureAddress(baseAddress, \"DnsExtractRecordsFromMessage_W\", 0);\n            DnsWriteQuestionToBuffer_W_I = PhGetDllBaseProcedureAddress(baseAddress, \"DnsWriteQuestionToBuffer_W\", 0);\n            DnsFree_I = PhGetDllBaseProcedureAddress(baseAddress, \"DnsFree\", 0);\n        }\n\n        if (\n            DnsQuery_W_I &&\n#if defined(PHNT_DNSQUERY_FUTURE)\n            DnsQueryEx_I &&\n            DnsCancelQuery_I &&\n#endif\n            DnsExtractRecordsFromMessage_W_I &&\n            DnsWriteQuestionToBuffer_W_I &&\n            DnsFree_I\n            )\n        {\n            initialized = TRUE;\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return initialized;\n}\n\n_Success_(return)\nstatic NTSTATUS PhCreateDnsMessageBuffer(\n    _In_ PCWSTR Message,\n    _In_ USHORT MessageType,\n    _In_ USHORT MessageId,\n    _Outptr_opt_result_maybenull_ PVOID* Buffer,\n    _Out_opt_ ULONG* BufferLength\n    )\n{\n    BOOLEAN status;\n    ULONG dnsBufferLength;\n    PDNS_MESSAGE_BUFFER dnsBuffer;\n\n    dnsBufferLength = PAGE_SIZE;\n    dnsBuffer = PhAllocate(dnsBufferLength);\n\n    if (!(status = !!DnsWriteQuestionToBuffer_W_I(\n        dnsBuffer,\n        &dnsBufferLength,\n        Message,\n        MessageType,\n        MessageId,\n        TRUE\n        )))\n    {\n        PhFree(dnsBuffer);\n        dnsBuffer = PhAllocate(dnsBufferLength);\n\n        status = !!DnsWriteQuestionToBuffer_W_I(\n            dnsBuffer,\n            &dnsBufferLength,\n            Message,\n            MessageType,\n            MessageId,\n            TRUE\n            );\n    }\n\n    if (status)\n    {\n        if (Buffer)\n            *Buffer = dnsBuffer;\n        else\n            PhFree(dnsBuffer);\n\n        if (BufferLength)\n            *BufferLength = dnsBufferLength;\n\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        if (dnsBuffer)\n            PhFree(dnsBuffer);\n\n        return STATUS_UNSUCCESSFUL;\n    }\n}\n\n_Success_(return)\nstatic NTSTATUS PhParseDnsMessageBuffer(\n    _In_ USHORT Xid,\n    _In_ PDNS_MESSAGE_BUFFER DnsReplyBuffer,\n    _In_ ULONG DnsReplyBufferLength,\n    _Outptr_opt_result_maybenull_ PVOID* DnsRecordList\n    )\n{\n    DNS_STATUS status;\n    PDNS_RECORD dnsRecordList = NULL;\n    PDNS_HEADER dnsRecordHeader;\n\n    if (DnsReplyBufferLength > USHRT_MAX)\n        return STATUS_NO_MEMORY;\n\n    // DNS_BYTE_FLIP_HEADER_COUNTS\n    dnsRecordHeader = &DnsReplyBuffer->MessageHead;\n    dnsRecordHeader->Xid = _byteswap_ushort(dnsRecordHeader->Xid);\n    dnsRecordHeader->QuestionCount = _byteswap_ushort(dnsRecordHeader->QuestionCount);\n    dnsRecordHeader->AnswerCount = _byteswap_ushort(dnsRecordHeader->AnswerCount);\n    dnsRecordHeader->NameServerCount = _byteswap_ushort(dnsRecordHeader->NameServerCount);\n    dnsRecordHeader->AdditionalCount = _byteswap_ushort(dnsRecordHeader->AdditionalCount);\n\n    if (dnsRecordHeader->Xid != Xid)\n        return STATUS_FAIL_CHECK;\n\n    status = DnsExtractRecordsFromMessage_W_I(\n        DnsReplyBuffer,\n        (USHORT)DnsReplyBufferLength,\n        &dnsRecordList\n        );\n\n    //status == ERROR_SUCCESS\n    //status == DNS_ERROR_RCODE_NAME_ERROR\n\n    if (dnsRecordList)\n    {\n        if (DnsRecordList)\n            *DnsRecordList = dnsRecordList;\n\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n// Cloudflare DNS over HTTPs (DoH)\n// https://developers.cloudflare.com/1.1.1.1/dns-over-https/wireformat/\n// host: cloudflare-dns.com\n// host: one.one.one.one\n// 1.1.1.1\n// 1.0.0.1\n// 2606:4700:4700::1111\n// 2606:4700:4700::1001\n//\n// Google DNS over HTTPs (DoH)\n// https://developers.google.com/speed/public-dns/docs/doh/\n// host: dns.google\n// 8.8.4.4\n// 8.8.8.8\n// 2001:4860:4860::8888\n// 2001:4860:4860::8844\n//\nNTSTATUS PhHttpDnsQuery(\n    _In_opt_ PCWSTR DnsServerAddress,\n    _In_ PCWSTR DnsQueryMessage,\n    _In_ USHORT DnsQueryMessageType,\n    _Out_ PDNS_RECORD* DnsQueryRecord\n    )\n{\n    static volatile USHORT seed = 0;\n    NTSTATUS status;\n    HINTERNET httpConnectionHandle = NULL;\n    HINTERNET httpRequestHandle = NULL;\n    PDNS_MESSAGE_BUFFER dnsSendBuffer = NULL;\n    PDNS_MESSAGE_BUFFER dnsReceiveBuffer = NULL;\n    PDNS_RECORD dnsRecordList = NULL;\n    ULONG dnsSendBufferLength;\n    ULONG dnsReceiveBufferLength;\n    USHORT dnsQueryId;\n\n    if (!PhDnsApiInitialized())\n        return STATUS_UNSUCCESSFUL;\n\n    dnsQueryId = _InterlockedIncrement16(&seed);\n\n    status = PhCreateDnsMessageBuffer(\n        DnsQueryMessage,\n        DnsQueryMessageType,\n        dnsQueryId,\n        &dnsSendBuffer,\n        &dnsSendBufferLength\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (!(httpConnectionHandle = PhCreateDohConnectionHandle(DnsServerAddress)))\n        goto CleanupExit;\n\n    if (!(httpRequestHandle = PhCreateDohRequestHandle(httpConnectionHandle)))\n        goto CleanupExit;\n\n    if (!WinHttpSendRequest(\n        httpRequestHandle,\n        WINHTTP_NO_ADDITIONAL_HEADERS,\n        0,\n        dnsSendBuffer,\n        dnsSendBufferLength,\n        dnsSendBufferLength,\n        0\n        ))\n    {\n        status = PhGetLastWinHttpErrorAsNtStatus();\n        goto CleanupExit;\n    }\n\n    if (!WinHttpReceiveResponse(httpRequestHandle, NULL))\n    {\n        status = PhGetLastWinHttpErrorAsNtStatus();\n        goto CleanupExit;\n    }\n\n#if DEBUG\n    {\n        ULONG option = 0;\n        ULONG optionLength = sizeof(ULONG);\n\n        if (WinHttpQueryOption(\n            httpRequestHandle,\n            WINHTTP_OPTION_HTTP_PROTOCOL_USED,\n            &option,\n            &optionLength\n            ))\n        {\n            if (option & WINHTTP_PROTOCOL_FLAG_HTTP3)\n            {\n                dprintf(\"[DOH] %s\", \"HTTP3 socket\\n\");\n            }\n\n            if (option & WINHTTP_PROTOCOL_FLAG_HTTP2)\n            {\n                dprintf(\"[DOH] %s\", \"HTTP2 socket\\n\");\n            }\n        }\n    }\n#endif\n\n    status = PhHttpReadDataToBuffer(\n        httpRequestHandle,\n        &dnsReceiveBuffer,\n        &dnsReceiveBufferLength\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhParseDnsMessageBuffer(\n        dnsQueryId,\n        dnsReceiveBuffer,\n        dnsReceiveBufferLength,\n        &dnsRecordList\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\nCleanupExit:\n    if (httpRequestHandle)\n        WinHttpCloseHandle(httpRequestHandle);\n    if (dnsReceiveBuffer)\n        PhFree(dnsReceiveBuffer);\n    if (dnsSendBuffer)\n        PhFree(dnsSendBuffer);\n\n    if (NT_SUCCESS(status))\n    {\n        *DnsQueryRecord = dnsRecordList;\n    }\n\n    return status;\n}\n\nPDNS_RECORD PhDnsQuery(\n    _In_opt_ PCWSTR DnsServerAddress,\n    _In_ PCWSTR DnsQueryMessage,\n    _In_ USHORT DnsQueryMessageType\n    )\n{\n    NTSTATUS status;\n    PDNS_RECORD dnsRecordList = NULL;\n\n    if (!PhDnsApiInitialized())\n        return NULL;\n\n    status = PhHttpDnsQuery(\n        DnsServerAddress,\n        DnsQueryMessage,\n        DnsQueryMessageType,\n        &dnsRecordList\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        if (DnsServerAddress)\n        {\n            IP4_ARRAY dnsServerAddressList;\n            IN_ADDR dnsQueryServerAddressIpv4;\n            USHORT dnsQueryServerAddressPort;\n\n            status = RtlIpv4StringToAddressEx(\n                DnsServerAddress,\n                TRUE,\n                &dnsQueryServerAddressIpv4,\n                &dnsQueryServerAddressPort\n                );\n            dnsServerAddressList.AddrCount = !!NT_SUCCESS(status);\n            dnsServerAddressList.AddrArray[0] = dnsQueryServerAddressIpv4.s_addr;\n\n            DnsQuery_W_I(\n                DnsQueryMessage,\n                DnsQueryMessageType,\n                DNS_QUERY_BYPASS_CACHE | DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_NO_MULTICAST,\n                &dnsServerAddressList,\n                &dnsRecordList,\n                NULL\n                );\n        }\n        else\n        {\n            DnsQuery_W_I(\n                DnsQueryMessage,\n                DnsQueryMessageType,\n                DNS_QUERY_BYPASS_CACHE | DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_NO_MULTICAST,\n                NULL,\n                &dnsRecordList,\n                NULL\n                );\n        }\n    }\n\n    return dnsRecordList;\n}\n\nPDNS_RECORD PhDnsQuery2(\n    _In_opt_ PCWSTR DnsServerAddress,\n    _In_ PCWSTR DnsQueryMessage,\n    _In_ USHORT DnsQueryMessageType,\n    _In_ USHORT DnsQueryMessageOptions\n    )\n{\n    PDNS_RECORD dnsRecordList = NULL;\n\n    if (PhDnsApiInitialized())\n    {\n        if (DnsServerAddress)\n        {\n            NTSTATUS status;\n            IP4_ARRAY dnsServerAddressList;\n            IN_ADDR dnsQueryServerAddressIpv4 = { 0 };\n            USHORT dnsQueryServerAddressPort = 0;\n\n            status = RtlIpv4StringToAddressEx(\n                DnsServerAddress,\n                FALSE,\n                &dnsQueryServerAddressIpv4,\n                &dnsQueryServerAddressPort\n                );\n            dnsServerAddressList.AddrCount = !!NT_SUCCESS(status);\n            dnsServerAddressList.AddrArray[0] = dnsQueryServerAddressIpv4.s_addr;\n\n            DnsQuery_W_I(\n                DnsQueryMessage,\n                DnsQueryMessageType,\n                DNS_QUERY_BYPASS_CACHE | DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_NO_MULTICAST,\n                &dnsServerAddressList,\n                &dnsRecordList,\n                NULL\n                );\n        }\n        else\n        {\n            DnsQuery_W_I(\n                DnsQueryMessage,\n                DnsQueryMessageType,\n                DnsQueryMessageOptions | DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_NO_MULTICAST,\n                NULL,\n                &dnsRecordList,\n                NULL\n                );\n        }\n    }\n\n    return dnsRecordList;\n}\n\nVOID PhDnsFree(\n    _In_ PDNS_RECORD DnsRecordList\n    )\n{\n    if (!PhDnsApiInitialized())\n        return;\n\n    DnsFree_I(DnsRecordList, DnsFreeRecordList);\n}\n\n#if defined(PHNT_DNSQUERY_FUTURE)\ntypedef struct _PH_DNS_QUERY_CONTEXT\n{\n    volatile LONG RefCount;\n    DNS_QUERY_RESULT QueryResults;\n    DNS_QUERY_CANCEL QueryCancelContext;\n    HANDLE QueryCompletedEvent;\n    PDNS_RECORD QueryRecords;\n} PH_DNS_QUERY_CONTEXT, *PPH_DNS_QUERY_CONTEXT;\n\nVOID PhDnsAddReferenceQueryContext(\n    _Inout_ PPH_DNS_QUERY_CONTEXT QueryContext\n    )\n{\n    InterlockedIncrement(&QueryContext->RefCount);\n}\n\nVOID PhDnsDeReferenceQueryContext(\n    _Inout_ PPH_DNS_QUERY_CONTEXT* QueryContext\n    )\n{\n    PPH_DNS_QUERY_CONTEXT dnsQueryContext = *QueryContext;\n\n    if (InterlockedDecrement(&dnsQueryContext->RefCount) == 0)\n    {\n        if (dnsQueryContext->QueryCompletedEvent)\n        {\n            NtClose(dnsQueryContext->QueryCompletedEvent);\n        }\n\n        PhFree(dnsQueryContext);\n        *QueryContext = NULL;\n    }\n}\n\nNTSTATUS PhDnsAllocateQueryContext(\n    _Out_ PPH_DNS_QUERY_CONTEXT* QueryContext\n    )\n{\n    NTSTATUS status;\n    PPH_DNS_QUERY_CONTEXT context;\n    HANDLE eventHandle;\n\n    status = PhCreateEvent(\n        &eventHandle,\n        EVENT_ALL_ACCESS,\n        SynchronizationEvent,\n        FALSE\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    context = PhAllocateZero(sizeof(PH_DNS_QUERY_CONTEXT));\n    PhDnsAddReferenceQueryContext(context);\n    context->QueryResults.Version = DNS_QUERY_RESULTS_VERSION1;\n    context->QueryCompletedEvent = eventHandle;\n\n    *QueryContext = context;\n    return status;\n}\n\nNTSTATUS PhDnsCreateDnsServerList(\n    _In_ PCWSTR AddressString,\n    _Inout_ PDNS_ADDR_ARRAY DnsQueryServerList)\n{\n    NTSTATUS status;\n    IN_ADDR dnsQueryServerAddressIpv4;\n    IN6_ADDR dnsQueryServerAddressIpv6;\n    ULONG dnsQueryServerAddressScope;\n    USHORT dnsQueryServerAddressPort;\n\n    status = RtlIpv4StringToAddressEx(\n        AddressString,\n        TRUE,\n        &dnsQueryServerAddressIpv4,\n        &dnsQueryServerAddressPort\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        memset(DnsQueryServerList, 0, sizeof(DNS_ADDR_ARRAY));\n        DnsQueryServerList->MaxCount = 1;\n        DnsQueryServerList->AddrCount = 1;\n\n        ((PSOCKADDR_IN)&DnsQueryServerList->AddrArray[0])->sin_family = AF_INET;\n        ((PSOCKADDR_IN)&DnsQueryServerList->AddrArray[0])->sin_addr = dnsQueryServerAddressIpv4;\n        return status;\n    }\n\n    status = RtlIpv6StringToAddressEx(\n        AddressString,\n        &dnsQueryServerAddressIpv6,\n        &dnsQueryServerAddressScope,\n        &dnsQueryServerAddressPort\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        memset(DnsQueryServerList, 0, sizeof(DNS_ADDR_ARRAY));\n        DnsQueryServerList->MaxCount = 1;\n        DnsQueryServerList->AddrCount = 1;\n\n        ((PSOCKADDR_IN6)&DnsQueryServerList->AddrArray[0])->sin6_family = AF_INET6;\n        ((PSOCKADDR_IN6)&DnsQueryServerList->AddrArray[0])->sin6_addr = dnsQueryServerAddressIpv6;\n        return status;\n    }\n\n    return status;\n}\n// HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Dnscache\\Parameters\\DohWellKnownServers\nNTSTATUS PhDnsCreateCustomDnsServerList(\n    _In_ PCWSTR AddressString,\n    _Inout_ DNS_CUSTOM_SERVER* DnsCustomServerList\n    )\n{\n    NTSTATUS status;\n    IN_ADDR dnsQueryServerAddressIpv4;\n    IN6_ADDR dnsQueryServerAddressIpv6;\n    ULONG dnsQueryServerAddressScope;\n    USHORT dnsQueryServerAddressPort;\n\n    memset(DnsCustomServerList, 0, sizeof(DNS_CUSTOM_SERVER));\n    DnsCustomServerList->dwServerType = DNS_CUSTOM_SERVER_TYPE_DOH;\n    DnsCustomServerList->ullFlags = DNS_CUSTOM_SERVER_UDP_FALLBACK;\n    DnsCustomServerList->pwszTemplate = L\"https://cloudflare-dns.com/dns-query\";\n\n    status = RtlIpv4StringToAddressEx(\n        AddressString,\n        TRUE,\n        &dnsQueryServerAddressIpv4,\n        &dnsQueryServerAddressPort\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        DnsCustomServerList->ServerAddr.si_family = AF_INET;\n        DnsCustomServerList->ServerAddr.Ipv4.sin_family = AF_INET;\n        DnsCustomServerList->ServerAddr.Ipv4.sin_addr = dnsQueryServerAddressIpv4;\n        return status;\n    }\n\n    status = RtlIpv6StringToAddressEx(\n        AddressString,\n        &dnsQueryServerAddressIpv6,\n        &dnsQueryServerAddressScope,\n        &dnsQueryServerAddressPort\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        DnsCustomServerList->ServerAddr.si_family = AF_INET6;\n        DnsCustomServerList->ServerAddr.Ipv6.sin6_family = AF_INET6;\n        DnsCustomServerList->ServerAddr.Ipv6.sin6_addr = dnsQueryServerAddressIpv6;\n        return status;\n    }\n\n    return status;\n}\n\nVOID WINAPI PhDnsQueryCompleteCallback(\n    _In_ PVOID Context,\n    _Inout_ PDNS_QUERY_RESULT QueryResults\n    )\n{\n    PPH_DNS_QUERY_CONTEXT context = (PPH_DNS_QUERY_CONTEXT)Context;\n\n    context->QueryRecords = QueryResults->pQueryRecords;\n\n    //if (QueryResults->QueryStatus != ERROR_SUCCESS)\n    //{\n    //    dprintf(\"DnsQuery failed: %%lu\\n\", QueryResults->QueryStatus);\n    //}\n    //\n    //if (QueryResults->pQueryRecords)\n    //{\n    //    DnsRecordListFree(QueryResults->pQueryRecords, DnsFreeRecordList);\n    //}\n\n    NtSetEvent(context->QueryCompletedEvent, NULL);\n\n    PhDnsDeReferenceQueryContext(&context);\n}\n\nPDNS_RECORD PhDnsQuery3(\n    _In_opt_ PCWSTR DnsServerAddress,\n    _In_ PCWSTR DnsQueryMessage,\n    _In_ USHORT DnsQueryMessageType,\n    _In_ USHORT DnsQueryMessageOptions\n    )\n{\n    ULONG status;\n    PDNS_RECORD dnsQueryRecords = NULL;\n    PPH_DNS_QUERY_CONTEXT dnsQueryContext = NULL;\n    DNS_ADDR_ARRAY dnsQueryServerList;\n    DNS_CUSTOM_SERVER dnsCustomServerList;\n    DNS_QUERY_REQUEST3 dnsQueryRequest;\n    LARGE_INTEGER timeout;\n\n    status = PhDnsAllocateQueryContext(&dnsQueryContext);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    memset(&dnsQueryRequest, 0, sizeof(dnsQueryRequest));\n    dnsQueryRequest.Version = WindowsVersion < WINDOWS_11_22H2 ? DNS_QUERY_REQUEST_VERSION1 : DNS_QUERY_REQUEST_VERSION3;\n    dnsQueryRequest.QueryName = DnsQueryMessage;\n    dnsQueryRequest.QueryType = DnsQueryMessageType;\n    dnsQueryRequest.QueryOptions = (ULONG64)DnsQueryMessageOptions;\n    dnsQueryRequest.pQueryContext = dnsQueryContext;\n    dnsQueryRequest.pQueryCompletionCallback = PhDnsQueryCompleteCallback;\n\n    if (DnsServerAddress)\n    {\n        {\n            status = PhDnsCreateDnsServerList(DnsServerAddress, &dnsQueryServerList);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            dnsQueryRequest.pDnsServerList = &dnsQueryServerList;\n        }\n\n        {\n            status = PhDnsCreateCustomDnsServerList(DnsServerAddress, &dnsCustomServerList);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            dnsQueryRequest.cCustomServers = 1; // PhFinalArrayCount()\n            dnsQueryRequest.pCustomServers = &dnsCustomServerList; // PhFinalArrayItems()\n        }\n    }\n\n    PhDnsAddReferenceQueryContext(dnsQueryContext);\n\n    status = DnsQueryEx_I(\n        (PDNS_QUERY_REQUEST)&dnsQueryRequest,\n        &dnsQueryContext->QueryResults,\n        &dnsQueryContext->QueryCancelContext\n        );\n\n    if (status != DNS_REQUEST_PENDING)\n    {\n        PhDnsQueryCompleteCallback(dnsQueryContext, &dnsQueryContext->QueryResults);\n        goto CleanupExit;\n    }\n\n    if (NtWaitForSingleObject(\n        dnsQueryContext->QueryCompletedEvent,\n        FALSE,\n        PhTimeoutFromMilliseconds(&timeout, 5000)\n        ) == WAIT_TIMEOUT)\n    {\n        DnsCancelQuery_I(&dnsQueryContext->QueryCancelContext);\n\n        NtWaitForSingleObject(\n            dnsQueryContext->QueryCompletedEvent,\n            FALSE,\n            PhTimeoutFromMilliseconds(&timeout, INFINITE)\n            );\n    }\n\nCleanupExit:\n\n    dnsQueryRecords = dnsQueryContext->QueryRecords;\n\n    //if (dnsQueryContext->pQueryRecords)\n    //{\n    //    DnsRecordListFree(dnsQueryContext->pQueryRecords, DnsFreeRecordList);\n    //}\n\n    if (dnsQueryContext)\n    {\n        PhDnsDeReferenceQueryContext(&dnsQueryContext);\n    }\n\n    return dnsQueryRecords;\n}\n#endif\n"
  },
  {
    "path": "phlib/hvsocketcontrol.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023-2025\n *\n */\n\n#include <ph.h>\n#include <hvsocketcontrol.h>\n\n#ifdef _WIN64\n\nstatic const UNICODE_STRING HvSocketVmGroupSddlString = RTL_CONSTANT_STRING(L\"D:P(A;;GA;;;BA)(A;;GA;;;SY)(A;;GA;;;S-1-5-83-0)(A;;GA;;;S-1-15-3-1024-2268835264-3721307629-241982045-173645152-1490879176-104643441-2915960892-1612460704)\");\nstatic const UNICODE_STRING HvSocketSystemDevicePath  = RTL_CONSTANT_STRING(L\"\\\\Device\\\\HvSocketSystem\"); // SDDL_DEVOBJ_SYS_ALL_ADM_ALL \"D:P(A;;GA;;;SY)(A;;GA;;;BA)\"\nstatic const UNICODE_STRING HvSocketSystemSymLink     = RTL_CONSTANT_STRING(L\"\\\\DosDevices\\\\HvSocketSystem\");\nstatic const UNICODE_STRING HvSocketVmGroupDevicePath = RTL_CONSTANT_STRING(L\"\\\\Device\\\\HvSocket\"); // HvSocketVmGroupSddlString\nstatic const UNICODE_STRING HvSocketVmGroupSymLink    = RTL_CONSTANT_STRING(L\"\\\\DosDevices\\\\HvSocket\");\nstatic const UNICODE_STRING HvSocketControlName       = RTL_CONSTANT_STRING(L\"HvSocketControl\");\nstatic const UNICODE_STRING HvSocketAddressInfoName   = RTL_CONSTANT_STRING(L\"AddressInfo\");\nstatic const UNICODE_STRING HvSocketControlFileName   = RTL_CONSTANT_STRING(L\"\\\\Device\\\\HvSocketSystem\\\\HvSocketControl\");\n\nstatic const OBJECT_ATTRIBUTES HvSocketSystemDeviceAttributes  = RTL_CONSTANT_OBJECT_ATTRIBUTES(&HvSocketSystemDevicePath, 0);\nstatic const OBJECT_ATTRIBUTES HvSocketVmGroupDeviceAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&HvSocketVmGroupDevicePath, 0);\nstatic const OBJECT_ATTRIBUTES HvSocketControlAttributes       = RTL_CONSTANT_OBJECT_ATTRIBUTES(&HvSocketControlFileName, 0);\n\n#define IOCTL_HVSOCKET_UPDATE_ADDRESS_INFO          CTL_CODE(FILE_DEVICE_TRANSPORT, 0x1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_HVSOCKET_UPDATE_PARTITION_PROPERTIES  CTL_CODE(FILE_DEVICE_TRANSPORT, 0x2, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_HVSOCKET_UPDATE_SERVICE_INFO          CTL_CODE(FILE_DEVICE_TRANSPORT, 0x3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_HVSOCKET_GET_SERVICE_INFO             CTL_CODE(FILE_DEVICE_TRANSPORT, 0x4, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_HVSOCKET_UPDATE_SERVICE_TABLE         CTL_CODE(FILE_DEVICE_TRANSPORT, 0x5, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_HVSOCKET_UPDATE_PROVIDER_PROPERTIES   CTL_CODE(FILE_DEVICE_TRANSPORT, 0x6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_HVSOCKET_GET_PARTITION_LISTENERS      CTL_CODE(FILE_DEVICE_TRANSPORT, 0x7, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_HVSOCKET_GET_PARTITION_CONNECTIONS    CTL_CODE(FILE_DEVICE_TRANSPORT, 0x8, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n\n#define HVSOCKET_SYSTEM_PATH_LENGTH  (sizeof(L\"\\\\Device\\\\HvSocketSystem\") /* \\\\ */ + sizeof(L\"AddressInfo\") /* \\\\ */ + sizeof(L\"{00000000-0000-0000-0000-000000000000}\"))\n\nNTSTATUS PhHvSocketOpenSystemControl(\n    _Out_ PHANDLE SystemHandle,\n    _In_opt_ const GUID* VmId\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    if (VmId)\n    {\n#if defined(PHNT_USE_NATIVE_APPEND)\n        UNICODE_STRING systemPath;\n        UNICODE_STRING guidString;\n        OBJECT_ATTRIBUTES objectAttributes;\n        BYTE buffer[HVSOCKET_SYSTEM_PATH_LENGTH];\n\n        RtlInitEmptyUnicodeString(&systemPath, (PWCHAR)buffer, sizeof(buffer));\n\n        status = RtlAppendUnicodeStringToString(&systemPath, &HvSocketSystemDevicePath);\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = RtlAppendUnicodeToString(&systemPath, L\"\\\\\");\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = RtlAppendUnicodeStringToString(&systemPath, &HvSocketAddressInfoName);\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = RtlAppendUnicodeToString(&systemPath, L\"\\\\\");\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = RtlStringFromGUID((PGUID)VmId, &guidString);\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = RtlAppendUnicodeStringToString(&systemPath, &guidString);\n        RtlFreeUnicodeString(&guidString);\n\n        if (!NT_SUCCESS(status))\n            return status;\n#else\n        PPH_STRING gidString;\n        UNICODE_STRING objectName;\n        OBJECT_ATTRIBUTES objectAttributes;\n        PH_STRINGREF stringRef;\n        SIZE_T returnLength;\n        PH_FORMAT format[5];\n        WCHAR formatBuffer[0x100];\n\n        if (!(gidString = PhFormatGuid((PGUID)VmId)))\n            return STATUS_NO_MEMORY;\n\n        PhInitFormatUCS(&format[0], &HvSocketSystemDevicePath);\n        PhInitFormatSR(&format[1], PhNtPathSeparatorString);\n        PhInitFormatUCS(&format[2], &HvSocketAddressInfoName);\n        PhInitFormatSR(&format[3], PhNtPathSeparatorString);\n        PhInitFormatSR(&format[4], gidString->sr);\n\n        if (!PhFormatToBuffer(format, 1, formatBuffer, sizeof(formatBuffer), &returnLength))\n        {\n            PhDereferenceObject(gidString);\n            return STATUS_NO_MEMORY;\n        }\n\n        PhDereferenceObject(gidString);\n\n        stringRef.Length = returnLength - sizeof(UNICODE_NULL);\n        stringRef.Buffer = formatBuffer;\n\n        if (!PhStringRefToUnicodeString(&stringRef, &objectName))\n            return STATUS_NAME_TOO_LONG;\n#endif\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            &objectName,\n            0,\n            NULL,\n            NULL\n            );\n\n        status = NtCreateFile(\n            SystemHandle,\n            FILE_READ_ACCESS | FILE_WRITE_ACCESS | SYNCHRONIZE,\n            &objectAttributes,\n            &ioStatusBlock,\n            NULL,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_WRITE,\n            FILE_CREATE, // required by hvsocketcontrol.sys\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n            NULL,\n            0\n            );\n    }\n    else\n    {\n        status = NtCreateFile(\n            SystemHandle,\n            FILE_READ_ACCESS | FILE_WRITE_ACCESS | SYNCHRONIZE,\n            &HvSocketControlAttributes,\n            &ioStatusBlock,\n            NULL,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_WRITE,\n            FILE_CREATE, // required by hvsocketcontrol.sys\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n            NULL,\n            0\n            );\n    }\n\n    return status;\n}\n\nNTSTATUS PhHvSocketGetListeners(\n    _In_ HANDLE SystemHandle,\n    _In_ const GUID* VmId,\n    _In_opt_ PHVSOCKET_LISTENERS Listeners,\n    _In_ ULONG ListenersLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    RtlZeroMemory(&ioStatusBlock, sizeof(IO_STATUS_BLOCK));\n\n    status = NtDeviceIoControlFile(\n        SystemHandle,\n        NULL,\n        NULL,\n        NULL,\n        &ioStatusBlock,\n        IOCTL_HVSOCKET_GET_PARTITION_LISTENERS,\n        (PVOID)VmId,\n        sizeof(GUID),\n        Listeners,\n        ListenersLength\n        );\n\n    if (ReturnLength)\n    {\n        *ReturnLength = (ULONG)ioStatusBlock.Information;\n    }\n\n    return status;\n}\n\nNTSTATUS PhHvSocketGetConnections(\n    _In_ HANDLE SystemHandle,\n    _In_ const GUID* VmId,\n    _In_opt_ PHVSOCKET_CONNECTIONS Connections,\n    _In_ ULONG ConnectionsLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    RtlZeroMemory(&ioStatusBlock, sizeof(IO_STATUS_BLOCK));\n\n    status = NtDeviceIoControlFile(\n        SystemHandle,\n        NULL,\n        NULL,\n        NULL,\n        &ioStatusBlock,\n        IOCTL_HVSOCKET_GET_PARTITION_CONNECTIONS,\n        (PVOID)VmId,\n        sizeof(GUID),\n        Connections,\n        ConnectionsLength\n        );\n\n    if (ReturnLength)\n    {\n        *ReturnLength = (ULONG)ioStatusBlock.Information;\n    }\n\n    return status;\n}\n\nNTSTATUS PhHvSocketGetServiceInfo(\n    _In_ HANDLE SystemHandle,\n    _In_ const GUID* ServiceId,\n    _Out_ PHVSOCKET_SERVICE_INFO ServiceInfo\n    )\n{\n    //\n    // This can bug check the system (jxy-s)\n    //\n    //IO_STATUS_BLOCK ioStatusBlock;\n    //\n    //return NtDeviceIoControlFile(\n    //    SystemHandle,\n    //    NULL,\n    //    NULL,\n    //    NULL,\n    //    &ioStatusBlock,\n    //    IOCTL_HVSOCKET_GET_SERVICE_INFO,\n    //    (PVOID)ServiceId,\n    //    sizeof(GUID),\n    //    ServiceInfo,\n    //    sizeof(HVSOCKET_SERVICE_INFO)\n    //    );\n\n    UNREFERENCED_PARAMETER(SystemHandle);\n    UNREFERENCED_PARAMETER(ServiceId);\n    UNREFERENCED_PARAMETER(ServiceInfo);\n    return STATUS_NOT_IMPLEMENTED;\n}\n\n#endif // _WIN64\n\nBOOLEAN PhHvSocketIsVSockTemplate(\n    _In_ PGUID ServiceId\n    )\n{\n    GUID template = *ServiceId;\n\n    template.Data1 = 0;\n\n    return !!IsEqualGUID(&template, &HV_GUID_VSOCK_TEMPLATE);\n}\n\n_Maybenull_\nPPH_STRING PhHvSocketGetVmName(\n    _In_ PGUID VmId\n    )\n{\n    static const PH_STRINGREF hvComputeSystemKey = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\HostComputeService\\\\VolatileStore\\\\ComputeSystem\\\\\");\n    static const PH_STRINGREF trimSet = PH_STRINGREF_INIT(L\"{}\");\n    PPH_STRING vmName = NULL;\n    PPH_STRING guidString;\n    PH_STRINGREF guidStringTrimmed;\n    PPH_STRING keyName;\n    HANDLE keyHandle;\n\n    guidString = PhFormatGuid(VmId);\n    guidStringTrimmed = guidString->sr;\n    PhTrimStringRef(&guidStringTrimmed, &trimSet, 0);\n\n    keyName = PhConcatStringRef2(&hvComputeSystemKey, &guidStringTrimmed);\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_QUERY_VALUE,\n        PH_KEY_LOCAL_MACHINE,\n        &keyName->sr,\n        0\n        )))\n    {\n        PPH_STRING value;\n\n        if (value = PhQueryRegistryStringZ(keyHandle, L\"VmName\"))\n            PhMoveReference(&vmName, value);\n        else if (value = PhQueryRegistryStringZ(keyHandle, L\"VmId\"))\n            PhMoveReference(&vmName, value);\n        else\n            PhMoveReference(&vmName, PhCreateString3(&guidStringTrimmed, PH_STRING_UPPER_CASE, NULL));\n\n        NtClose(keyHandle);\n    }\n\n    PhDereferenceObject(keyName);\n    PhDereferenceObject(guidString);\n\n    return vmName;\n}\n\n_Maybenull_\nPPH_STRING PhHvSocketGetServiceName(\n    _In_ PGUID ServiceId\n    )\n{\n    static const PH_STRINGREF hvGuestServicesKey = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Virtualization\\\\GuestCommunicationServices\\\\\");\n    static const PH_STRINGREF trimSet = PH_STRINGREF_INIT(L\"{}\");\n    PPH_STRING serviceName = NULL;\n    PPH_STRING guidString;\n    PH_STRINGREF guidStringTrimmed;\n    PPH_STRING keyName;\n    HANDLE keyHandle;\n\n    guidString = PhFormatGuid(ServiceId);\n    guidStringTrimmed = guidString->sr;\n    PhTrimStringRef(&guidStringTrimmed, &trimSet, 0);\n\n    keyName = PhConcatStringRef2(&hvGuestServicesKey, &guidStringTrimmed);\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_QUERY_VALUE,\n        PH_KEY_LOCAL_MACHINE,\n        &keyName->sr,\n        0\n        )))\n    {\n        PPH_STRING elementName;\n\n        if (elementName = PhQueryRegistryStringZ(keyHandle, L\"ElementName\"))\n            PhMoveReference(&serviceName, elementName);\n\n        NtClose(keyHandle);\n    }\n\n    // Keep this after element name lookup. Certain services define the VSOCK\n    // template with a specific port (e.g. Docker). (jxy-s)\n    if (!serviceName && PhHvSocketIsVSockTemplate(ServiceId))\n        PhMoveReference(&serviceName, PhCreateString(L\"VSOCK\"));\n\n    PhDereferenceObject(keyName);\n    PhDereferenceObject(guidString);\n\n    return serviceName;\n}\n\nPPH_STRING PhHvSocketAddressString(\n    _In_ PGUID Address\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PPH_STRING wildcardString;\n    static PPH_STRING broadcastString;\n    static PPH_STRING childrenString;\n    static PPH_STRING loopbackString;\n    static PPH_STRING hostString;\n    static PPH_STRING siloHostString;\n    PPH_STRING addressString = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        wildcardString = PhCreateString(L\"*\");\n        broadcastString = PhCreateString(L\"Broadcast\");\n        childrenString = PhCreateString(L\"Children\");\n        loopbackString = PhCreateString(L\"Loopback\");\n        hostString = PhCreateString(L\"Host\");\n        siloHostString = PhCreateString(L\"Silo Host\");\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (IsEqualGUID(Address, &HV_GUID_WILDCARD))\n        return PhReferenceObject(wildcardString);\n    if (IsEqualGUID(Address, &HV_GUID_BROADCAST))\n        return PhReferenceObject(broadcastString);\n    if (IsEqualGUID(Address, &HV_GUID_CHILDREN))\n        return PhReferenceObject(childrenString);\n    if (IsEqualGUID(Address, &HV_GUID_LOOPBACK))\n        return PhReferenceObject(loopbackString);\n    if (IsEqualGUID(Address, &HV_GUID_PARENT))\n        return PhReferenceObject(hostString);\n    if (IsEqualGUID(Address, &HV_GUID_SILOHOST))\n        return PhReferenceObject(siloHostString);\n\n    return PhFormatGuid(Address);\n}\n"
  },
  {
    "path": "phlib/icotobmp.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2016-2023\n *\n */\n\n#include <ph.h>\n#include <uxtheme.h>\n#include <mapldr.h>\n#include <guisup.h>\n\n// code from http://msdn.microsoft.com/en-us/library/bb757020.aspx\n\ntypedef HPAINTBUFFER (WINAPI* _BeginBufferedPaint)(\n    _In_ HDC hdcTarget,\n    _In_ const RECT *prcTarget,\n    _In_ BP_BUFFERFORMAT dwFormat,\n    _In_ BP_PAINTPARAMS *pPaintParams,\n    _Out_ HDC *phdc\n    );\n\ntypedef HRESULT (WINAPI* _EndBufferedPaint)(\n    _In_ HPAINTBUFFER hBufferedPaint,\n    _In_ BOOL fUpdateTarget\n    );\n\ntypedef HRESULT (WINAPI* _GetBufferedPaintBits)(\n    _In_ HPAINTBUFFER hBufferedPaint,\n    _Out_ RGBQUAD **ppbBuffer,\n    _Out_ int *pcxRow\n    );\n\nstatic BOOLEAN ImportsInitialized = FALSE;\nstatic _BeginBufferedPaint BeginBufferedPaint_I = NULL;\nstatic _EndBufferedPaint EndBufferedPaint_I = NULL;\nstatic _GetBufferedPaintBits GetBufferedPaintBits_I = NULL;\n\nstatic HBITMAP PhpCreateBitmap32(\n    _In_ HDC hdc,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _Out_ PVOID *Bits\n    )\n{\n    BITMAPINFO bitmapInfo;\n\n    memset(&bitmapInfo, 0, sizeof(BITMAPINFO));\n    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n    bitmapInfo.bmiHeader.biWidth = Width;\n    bitmapInfo.bmiHeader.biHeight = Height;\n    bitmapInfo.bmiHeader.biPlanes = 1;\n    bitmapInfo.bmiHeader.biBitCount = 32;\n    bitmapInfo.bmiHeader.biCompression = BI_RGB;\n    bitmapInfo.bmiHeader.biSizeImage = Width * Height;\n\n    return CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, Bits, NULL, 0);\n}\n\nstatic BOOLEAN PhpHasAlpha(\n    _In_ PULONG Argb,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_ ULONG RowWidth\n    )\n{\n    ULONG delta;\n    ULONG x;\n    ULONG y;\n\n    delta = RowWidth - Width;\n\n    for (y = Width; y; y--)\n    {\n        for (x = Height; x; x--)\n        {\n            if (*Argb++ & 0xff000000)\n                return TRUE;\n        }\n\n        Argb += delta;\n    }\n\n    return FALSE;\n}\n\nstatic VOID PhpConvertToPArgb32(\n    _In_ HDC hdc,\n    _Inout_ PULONG Argb,\n    _In_ HBITMAP Bitmap,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_ ULONG RowWidth\n    )\n{\n    BITMAPINFO bitmapInfo;\n    PVOID bits;\n\n    memset(&bitmapInfo, 0, sizeof(BITMAPINFO));\n    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n    bitmapInfo.bmiHeader.biWidth = Width;\n    bitmapInfo.bmiHeader.biHeight = Height;\n    bitmapInfo.bmiHeader.biPlanes = 1;\n    bitmapInfo.bmiHeader.biBitCount = 32;\n    bitmapInfo.bmiHeader.biCompression = BI_RGB;\n    bitmapInfo.bmiHeader.biSizeImage = Width * Height;\n\n    bits = PhAllocate(Width * sizeof(RGBQUAD) * Height);\n\n    if (GetDIBits(hdc, Bitmap, 0, Height, bits, &bitmapInfo, DIB_RGB_COLORS) == Height)\n    {\n        PULONG argbMask;\n        ULONG delta;\n        ULONG x;\n        ULONG y;\n\n        argbMask = (PULONG)bits;\n        delta = RowWidth - Width;\n\n        for (y = Height; y; y--)\n        {\n            for (x = Width; x; x--)\n            {\n                if (*argbMask++)\n                {\n                    *Argb++ = 0; // transparent\n                }\n                else\n                {\n                    *Argb++ |= 0xff000000; // opaque\n                }\n            }\n\n            Argb += delta;\n        }\n    }\n\n    PhFree(bits);\n}\n\nstatic VOID PhpConvertToPArgb32IfNeeded(\n    _In_ HPAINTBUFFER PaintBuffer,\n    _In_ HDC hdc,\n    _In_ HICON Icon,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    RGBQUAD *quad;\n    ULONG rowWidth;\n\n    if (SUCCEEDED(GetBufferedPaintBits_I(PaintBuffer, &quad, &rowWidth)))\n    {\n        PULONG argb = (PULONG)quad;\n\n        if (!PhpHasAlpha(argb, Width, Height, rowWidth))\n        {\n            ICONINFO iconInfo;\n\n            if (GetIconInfo(Icon, &iconInfo))\n            {\n                if (iconInfo.hbmMask)\n                {\n                    PhpConvertToPArgb32(hdc, argb, iconInfo.hbmMask, Width, Height, rowWidth);\n                    DeleteBitmap(iconInfo.hbmMask);\n                }\n\n                DeleteBitmap(iconInfo.hbmColor);\n            }\n        }\n    }\n}\n\nHBITMAP PhIconToBitmap(\n    _In_ HICON Icon,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    HBITMAP bitmap;\n    RECT iconRectangle;\n    HDC screenHdc;\n    PVOID bits;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };\n    BP_PAINTPARAMS paintParams = { sizeof(paintParams) };\n    HDC bufferHdc;\n    HPAINTBUFFER bufferedPaint;\n\n    iconRectangle.left = 0;\n    iconRectangle.top = 0;\n    iconRectangle.right = Width;\n    iconRectangle.bottom = Height;\n\n    if (!ImportsInitialized)\n    {\n        PVOID uxtheme;\n\n        uxtheme = PhLoadLibrary(L\"uxtheme.dll\");\n        BeginBufferedPaint_I = PhGetDllBaseProcedureAddress(uxtheme, \"BeginBufferedPaint\", 0);\n        EndBufferedPaint_I = PhGetDllBaseProcedureAddress(uxtheme, \"EndBufferedPaint\", 0);\n        GetBufferedPaintBits_I = PhGetDllBaseProcedureAddress(uxtheme, \"GetBufferedPaintBits\", 0);\n        ImportsInitialized = TRUE;\n    }\n\n    if (!BeginBufferedPaint_I || !EndBufferedPaint_I || !GetBufferedPaintBits_I)\n    {\n        // Probably XP.\n\n        screenHdc = GetDC(NULL);\n        hdc = CreateCompatibleDC(screenHdc);\n        bitmap = CreateCompatibleBitmap(screenHdc, Width, Height);\n        ReleaseDC(NULL, screenHdc);\n\n        oldBitmap = SelectObject(hdc, bitmap);\n        FillRect(hdc, &iconRectangle, (HBRUSH)(COLOR_WINDOW + 1));\n        DrawIconEx(hdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL);\n        SelectObject(hdc, oldBitmap);\n\n        DeleteDC(hdc);\n\n        return bitmap;\n    }\n\n    hdc = CreateCompatibleDC(NULL);\n    bitmap = PhpCreateBitmap32(hdc, Width, Height, &bits);\n    oldBitmap = SelectBitmap(hdc, bitmap);\n\n    paintParams.dwFlags = BPPF_ERASE;\n    paintParams.pBlendFunction = &blendFunction;\n\n    if (bufferedPaint = BeginBufferedPaint_I(hdc, &iconRectangle, BPBF_DIB, &paintParams, &bufferHdc))\n    {\n        DrawIconEx(bufferHdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL);\n        // If the icon did not have an alpha channel, we need to convert the buffer to PARGB.\n        PhpConvertToPArgb32IfNeeded(bufferedPaint, hdc, Icon, Width, Height);\n        // This will write the buffer contents to the destination bitmap.\n        EndBufferedPaint_I(bufferedPaint, TRUE);\n    }\n    else\n    {\n        // Default to unbuffered painting.\n        FillRect(hdc, &iconRectangle, (HBRUSH)(COLOR_WINDOW + 1));\n        DrawIconEx(hdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL);\n    }\n\n    SelectBitmap(hdc, oldBitmap);\n    DeleteDC(hdc);\n\n    return bitmap;\n}\n\n// based on BufferedPaintSetAlpha/BufferedPaintMakeOpaque (dmex)\nVOID PhBitmapSetAlpha(\n    _In_ PVOID Bits,\n    _In_ LONG Width,\n    _In_ LONG Height\n    )\n{\n    ULONG count = Width * Height;\n\n    //RGBQUAD* quad = (RGBQUAD*)Bits;\n    //\n    //for (ULONG i = 0; i < count; i++)\n    //{\n    //    if (quad[i].rgbBlue != 0 || quad[i].rgbGreen != 0 || quad[i].rgbRed != 0)\n    //    {\n    //        quad[i].rgbReserved = 255; // opaque\n    //    }\n    //}\n\n    for (ULONG i = 0; i < count; i++)\n    {\n        if (((PULONG)Bits)[i] != 0)\n        {\n            ((PULONG)Bits)[i] |= 0xff000000; // opaque\n        }\n    }\n}\n"
  },
  {
    "path": "phlib/imgcoherency.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2020-2022\n *     dmex    2021-2023\n *\n */\n\n#include <ph.h>\n#include <mapimg.h>\n#include <kphuser.h>\n\n#define PH_IMGCOHERENCY_NORMAL_SCAN_LIMIT         (40 * (1024 * 1024)) // 40Mib\n#define PH_IMGCOHERENCY_QUICK_SCAN_LIMIT          (PAGE_SIZE * 2)\n#define PH_IMGCOHERENCY_MIN_ENTRY_INSPECT         (PAGE_SIZE * 2)\n\n/**\n* Image coherency context, used during the calculation of the process\n* image coherency.\n*/\ntypedef struct _PH_IMAGE_COHERENCY_CONTEXT\n{\n    PH_IMAGE_COHERENCY_SCAN_TYPE Type;        /**< Type of scan to perform */\n\n    SIZE_T CoherentBytes;                     /**< Updated during inspection, coherent bytes */\n    SIZE_T TotalBytes;                        /**< Updated during inspection, total bytes analyzed */\n    SIZE_T SkippedBytes;                      /**< Bytes skipped during inspection */\n\n    NTSTATUS MappedImageStatus;               /**< Status of initializing MappedImage */\n    PH_MAPPED_IMAGE MappedImage;              /**< On-disk image mapping */\n    PPH_HASHTABLE MappedImageReloc;           /**< On-disk mapped image relocations table */\n    ULONG MappedImageBaseRva;                 /**< On-disk optional header image base RVA. */\n    ULONG MappedImageIatRva;                  /**< On-disk import address table RVA */\n    ULONG MappedImageIatSize;                 /**< On-disk import address table size */\n\n    NTSTATUS RemoteMappedImageStatus;         /**< Status of initializing RemoteMappedImage */\n    PH_REMOTE_MAPPED_IMAGE RemoteMappedImage; /**< Remote image mapping */\n\n    PVOID RemoteImageBase;                    /**< Remote image base address */\n    SIZE_T RemoteImageSize;                   /**< Remote image size */\n    BOOLEAN ImageIsKernelModule;\n} PH_IMAGE_COHERENCY_CONTEXT, *PPH_IMAGE_COHERENCY_CONTEXT;\n\n/**\n* Inspection skip callback type.\n*\n* \\param[in] Rva - Current rva in the range being inspected.\n* \\param[in] Context - Context supplied to this callback.\n* \\return Number of bytes to skip, 0 does not skip bytes.\n*/\ntypedef _Function_class_(PH_IMGCOHERENCY_SKIP_BYTE_CALLBACK)\nULONG CALLBACK PH_IMGCOHERENCY_SKIP_BYTE_CALLBACK(\n    _In_ ULONG Rva,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_IMGCOHERENCY_SKIP_BYTE_CALLBACK *PPH_IMGCOHERENCY_SKIP_BYTE_CALLBACK;\n\n/**\n* Retrieves the size of the section to scan given the scan type.\n*\n* \\param[in] Type - Image coherency scan type.\n* \\param[in] SectionHeader - Image section header.\n* \\return Amount of the section to scan given the scan type.\n*/\nULONG PhpGetSectionScanSize(\n    _In_ PH_IMAGE_COHERENCY_SCAN_TYPE Type,\n    _In_ PIMAGE_SECTION_HEADER SectionHeader\n    )\n{\n    ULONG size;\n\n    size = min(SectionHeader->SizeOfRawData, SectionHeader->Misc.VirtualSize);\n\n    switch (Type)\n    {\n    case PhImageCoherencyQuick:\n        {\n            if (size > PH_IMGCOHERENCY_QUICK_SCAN_LIMIT)\n            {\n                size = PH_IMGCOHERENCY_QUICK_SCAN_LIMIT;\n            }\n        }\n        break;\n    case PhImageCoherencyNormal:\n        {\n            if (size > PH_IMGCOHERENCY_NORMAL_SCAN_LIMIT)\n            {\n                size = PH_IMGCOHERENCY_NORMAL_SCAN_LIMIT;\n            }\n        }\n        break;\n    case PhImageCoherencyFull:\n    default:\n        break;\n    }\n\n    return size;\n}\n\n/**\n* Determines if the section should be scanned given the scan type.\n*\n* \\param[in] Type - Image coherency scan type.\n* \\param[in] SectionHeader - Section header to inspect.\n* \\return TRUE if the section should be scanned for the given scan type, FALSE otherwise.\n*/\nBOOLEAN PhpShouldScanSection(\n    _In_ PH_IMAGE_COHERENCY_SCAN_TYPE Type,\n    _In_ PIMAGE_SECTION_HEADER SectionHeader\n    )\n{\n    switch (Type)\n    {\n    case PhImageCoherencyQuick:\n    case PhImageCoherencyNormal:\n    case PhImageCoherencyFull:\n        {\n            if ((SectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0)\n            {\n                //\n                // Anything marked execute.\n                //\n                return TRUE;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n* Frees the image coherency context.\n*\n* \\param[in] Context - Context to free, may be NULL.\n*/\nVOID PhpFreeImageCoherencyContext(\n    _In_opt_ PPH_IMAGE_COHERENCY_CONTEXT Context\n    )\n{\n    if (Context)\n    {\n        PhUnloadMappedImage(&Context->MappedImage);\n        PhUnloadRemoteMappedImage(&Context->RemoteMappedImage);\n\n        if (Context->MappedImageReloc)\n            PhDereferenceObject(Context->MappedImageReloc);\n\n        PhFree(Context);\n    }\n}\n\nstatic NTSTATUS NTAPI PhImageCoherencyRelocationCallback(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_DATA_DIRECTORY DataDirectory,\n    _In_ PIMAGE_BASE_RELOCATION RelocationDirectory,\n    _In_ PIMAGE_RELOCATION_RECORD Relocations,\n    _In_ ULONG RelocationCount,\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context\n    )\n{\n    for (ULONG i = 0; i < RelocationCount; i++)\n    {\n        PIMAGE_RELOCATION_RECORD entry = &Relocations[i];\n\n        __try\n        {\n            PhMappedImageProbe(MappedImage, entry, sizeof(IMAGE_RELOCATION_RECORD));\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n\n        if (\n            (entry->Type != IMAGE_REL_BASED_ABSOLUTE) &&\n            (entry->Type != IMAGE_REL_BASED_RESERVED)\n            )\n        {\n            PVOID rva = PTR_ADD_OFFSET(RelocationDirectory->VirtualAddress, entry->Offset);\n\n            if (entry->Type == IMAGE_REL_BASED_DIR64)\n            {\n                PhAddItemSimpleHashtable(Context->MappedImageReloc, rva, UlongToPtr(8));\n            }\n            else\n            {\n                //\n                // For now, we're just going to do a 4 byte skip for\n                // all other relocations. This could probably use some\n                // work for higher accuracy.\n                //\n\n                PhAddItemSimpleHashtable(Context->MappedImageReloc, rva, UlongToPtr(4));\n            }\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nstatic NTSTATUS NTAPI PhImageCoherencyDynamicRelocationCallback(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PPH_IMAGE_DYNAMIC_RELOC_ENTRY Entry,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_IMAGE_COHERENCY_CONTEXT context = Context;\n    ULONG_PTR rva = 0;\n    ULONG_PTR size = 0;\n\n    if (Entry->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X)\n    {\n        rva = (ULONG_PTR)Entry->ARM64X.BlockRva + Entry->ARM64X.RecordFixup.Offset;\n        switch (Entry->ARM64X.RecordFixup.Type)\n        {\n        case IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:\n        case IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE:\n            size = (ULONG_PTR)(1ull << Entry->ARM64X.RecordFixup.Size);\n            break;\n        case IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA:\n            size = 4;\n            break;\n        }\n    }\n    else if (Entry->Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_IMPORT_CONTROL_TRANSFER)\n    {\n        rva = (ULONG_PTR)Entry->ImportControl.BlockRva + Entry->ImportControl.Record.PageRelativeOffset;\n        //\n        // 48 FF 15 XX XX XX XX     call qword ptr [_imp_<function>]\n        // 0F 1F 44 00 00           nop\n        //\n        size = 12;\n    }\n    else if (Entry->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64_KERNEL_IMPORT_CALL_TRANSFER)\n    {\n        rva = (ULONG_PTR)Entry->ARM64ImportControl.BlockRva + (Entry->ARM64ImportControl.Record.PageRelativeOffset << 2);\n        //\n        // ARM64 instructions are fixed 4 bytes\n        // Either BR or BLR instruction for indirect call/jump\n        //\n        size = 4;\n    }\n    else if (Entry->Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE)\n    {\n        rva = (ULONG_PTR)Entry->RFPrologue.BlockRva;\n        //\n        // Prologue size is variable, specified in PrologueByteCount\n        //\n        size = Entry->RFPrologue.PrologueByteCount;\n    }\n    else if (Entry->Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE)\n    {\n        rva = (ULONG_PTR)Entry->RFEpilogue.BlockRva;\n        //\n        // Epilogue size is variable\n        // Total size = EpilogueByteCount + (BranchDescriptorElementSize * BranchDescriptorCount) + bitmap\n        //\n        size = (ULONG_PTR)Entry->RFEpilogue.EpilogueByteCount +\n               ((ULONG_PTR)Entry->RFEpilogue.BranchDescriptorElementSize * Entry->RFEpilogue.BranchDescriptorCount) +\n               ((Entry->RFEpilogue.BranchDescriptorCount + 7) / 8);\n    }\n    else if (Entry->Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_INDIR_CONTROL_TRANSFER)\n    {\n        rva = (ULONG_PTR)Entry->IndirControl.BlockRva + Entry->IndirControl.Record.PageRelativeOffset;\n        size = 12;\n    }\n    else if (Entry->Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH)\n    {\n        rva = (ULONG_PTR)Entry->SwitchBranch.BlockRva + Entry->SwitchBranch.Record.PageRelativeOffset;\n        //\n        // FF D0                    jmp rax\n        // CC CC CC                 int 3\n        //\n        size = 5;\n    }\n    else if (Entry->Symbol == IMAGE_DYNAMIC_RELOCATION_FUNCTION_OVERRIDE)\n    {\n        rva = (ULONG_PTR)Entry->FuncOverride.BlockRva + Entry->FuncOverride.Record.Offset;\n        if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n            size = 4;\n        else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n            size = 8;\n    }\n    else\n    {\n        //\n        // This should only be absolute, skipping others.\n        //\n        if (Entry->Other.Record.Type == IMAGE_REL_BASED_ABSOLUTE)\n        {\n            rva = (ULONG_PTR)Entry->Other.BlockRva + Entry->Other.Record.Offset;\n            if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n                size = 4;\n            else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n                size = 8;\n        }\n    }\n\n    if (rva && size)\n        PhAddItemSimpleHashtable(context->MappedImageReloc, (PVOID)rva, (PVOID)size);\n\n    return STATUS_SUCCESS;\n}\n\n_Function_class_(PH_READ_VIRTUAL_MEMORY_CALLBACK)\nstatic NTSTATUS PhImageCoherencyReadVirtualMemoryCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_IMAGE_COHERENCY_CONTEXT context = (PPH_IMAGE_COHERENCY_CONTEXT)Context;\n    if (!context) return STATUS_INVALID_PARAMETER_6;\n\n    if (context->ImageIsKernelModule)\n        return KphReadVirtualMemory(ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead);\n    return PhReadVirtualMemory(ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead);\n}\n\n/**\n* Created the image coherency context. This is done best-effort and\n* the status is stored in the context.\n*\n* \\param[in] Type - Image coherency scan type.\n* \\param[in] FileName - Win32 file name of the image to inspect.\n* \\param[in] ProcessHandle - Handle to process to inspect. Requires\n* PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ.\n* \\param[in] RemoteImageBase - Remove image base address, optional.\n* \\param[in] RemoteImageSize - Remove image size, optional.\n* \\param[in] RemoteImageBaseStatus - If RemoteImageBase is null, this is stored\n* in the context instead of attempting to map the image.\n* \\param[in] ReadVirtualMemoryCallback - Callback to use to read virtual memory.\n* \\return Pointer to newly allocated image coherency context, or NULL on\n* allocation failure. The created context must be passed to\n* PhpFreeImageCoherencyContext to free.\n*/\nPPH_IMAGE_COHERENCY_CONTEXT PhpCreateImageCoherencyContext(\n    _In_ PH_IMAGE_COHERENCY_SCAN_TYPE Type,\n    _In_ PPH_STRING FileName,\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID RemoteImageBase,\n    _In_opt_ SIZE_T RemoteImageSize,\n    _In_ NTSTATUS RemoteImageBaseStatus,\n    _In_ BOOLEAN ImageIsKernelModule\n    )\n{\n    PPH_IMAGE_COHERENCY_CONTEXT context;\n\n    //\n    // This is best-effort context creation, we don't fail if the mapping\n    // fails - the caller of the API may make decisions based on success of\n    // each\n    //\n\n    context = PhAllocateZero(sizeof(PH_IMAGE_COHERENCY_CONTEXT));\n    context->Type = Type;\n    context->ImageIsKernelModule = ImageIsKernelModule;\n\n    if (NT_SUCCESS(RemoteImageBaseStatus))\n    {\n        context->RemoteImageBase = RemoteImageBase;\n        context->RemoteImageSize = RemoteImageSize;\n\n        //\n        // Map the on-disk image\n        //\n        context->MappedImageStatus = PhLoadMappedImageEx(\n            &FileName->sr,\n            NULL,\n            &context->MappedImage\n            );\n\n        if (NT_SUCCESS(context->MappedImageStatus))\n        {\n            PIMAGE_DATA_DIRECTORY directory;\n\n            PhMappedImagePrefetch(&context->MappedImage);\n\n            //\n            // Build a hash table for the relocation entries to skip later.\n            // This hash table will map the RVA to the number of bytes to skip.\n            //\n\n            context->MappedImageReloc = PhCreateSimpleHashtable(50);\n\n            context->MappedImageStatus = PhMappedImageEnumerateRelocations(\n                &context->MappedImage,\n                PhImageCoherencyRelocationCallback,\n                context\n                );\n\n            PhMappedImageEnumerateDynamicRelocations(\n                &context->MappedImage,\n                PhImageCoherencyDynamicRelocationCallback,\n                context\n                );\n\n            if (NT_SUCCESS(PhGetMappedImageDataDirectory(\n                &context->MappedImage,\n                IMAGE_DIRECTORY_ENTRY_IAT,\n                &directory\n                )))\n            {\n                context->MappedImageIatRva = directory->VirtualAddress;\n                context->MappedImageIatSize = directory->Size;\n            }\n\n            if (context->MappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n            {\n                PVOID address;\n                address = &context->MappedImage.NtHeaders32->OptionalHeader.ImageBase;\n                context->MappedImageBaseRva = PtrToUlong(PTR_SUB_OFFSET(address, context->MappedImage.ViewBase));\n            }\n            else if (context->MappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n            {\n                PVOID address;\n                address = &context->MappedImage.NtHeaders->OptionalHeader.ImageBase;\n                context->MappedImageBaseRva = PtrToUlong(PTR_SUB_OFFSET(address, context->MappedImage.ViewBase));\n            }\n            else\n            {\n                context->MappedImageBaseRva = 0;\n            }\n        }\n\n        //\n        // Map the remote image\n        //\n\n        context->RemoteMappedImageStatus = PhInitializeRemoteMappedImage(\n            &context->RemoteMappedImage,\n            PhImageCoherencyReadVirtualMemoryCallback,\n            context\n            );\n\n        if (NT_SUCCESS(context->RemoteMappedImageStatus))\n        {\n            context->RemoteMappedImageStatus = PhLoadRemoteMappedImage(\n                &context->RemoteMappedImage,\n                ProcessHandle,\n                context->RemoteImageBase,\n                context->RemoteImageSize\n                );\n        }\n    }\n    else\n    {\n        context->RemoteMappedImageStatus = RemoteImageBaseStatus;\n    }\n\n    return context;\n}\n\n/**\n* Inspects two buffers and adds them to the coherency calculation.\n*\n* \\param[in] LeftBuffer - First buffer to inspect.\n* \\param[in] LeftCount - Number of bytes in the first buffer.\n* \\param[in] RightBuffer - Second buffer to inspect.\n* \\param[in] RightCount - Number of bytes in the second buffer.\n* \\param[in,out] Context - Context to be updated during inspection.\n* \\param[in] Rva - RVA from which the buffers were retrieved, informs skip callback.\n* \\param[in] SkipCallback - Optional, if provided the skip callback is invoked\n* for each inspected byte, the callback may return any number of bytes to skip.\n* \\param[in] SkipCallbackContext - Optional, callback context passed to the skip callback.\n*/\nNTSTATUS PhpAnalyzeImageCoherencyInspect(\n    _In_opt_ PBYTE LeftBuffer,\n    _In_ ULONG LeftCount,\n    _In_opt_ PBYTE RightBuffer,\n    _In_ ULONG RightCount,\n    _Inout_ PPH_IMAGE_COHERENCY_CONTEXT Context,\n    _In_opt_ ULONG Rva,\n    _In_opt_ PPH_IMGCOHERENCY_SKIP_BYTE_CALLBACK SkipCallback,\n    _In_opt_ PVOID SkipCallbackContext\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    //\n    // For the minimum bytes between the buffers increment the coherent bytes\n    // for each match.\n    //\n    if (LeftBuffer && RightBuffer)\n    {\n        ULONG length = min(LeftCount, RightCount);\n\n        for (ULONG i = 0; i < length; i++)\n        {\n            if (SkipCallback)\n            {\n                ULONG skip = SkipCallback(Rva + i, SkipCallbackContext);\n                if (skip != 0)\n                {\n                    ULONG remaining = length - i;\n                    ULONG effectiveSkip = (skip > remaining) ? remaining : skip;\n\n                    Context->CoherentBytes += effectiveSkip;\n                    Context->SkippedBytes += effectiveSkip;\n                    Context->TotalBytes += effectiveSkip;\n                    i += effectiveSkip;\n                    continue;\n                }\n            }\n\n            Context->TotalBytes++;\n\n            __try\n            {\n                if (LeftBuffer[i] == RightBuffer[i])\n                {\n                    Context->CoherentBytes++;\n                }\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                status = GetExceptionCode();\n                break;\n            }\n        }\n    }\n\n    //\n    // Buffers of mismatched sizes are incoherent over mismatched range.\n    // Include any diff in the total bytes.\n    //\n    if (LeftCount > RightCount)\n    {\n        Context->TotalBytes += ((SIZE_T)LeftCount - (SIZE_T)RightCount);\n    }\n    else if (LeftCount < RightCount)\n    {\n        Context->TotalBytes += ((SIZE_T)RightCount - (SIZE_T)LeftCount);\n    }\n\n    return status;\n}\n\n/**\n* Analyzes the image coherency as if it were a native application.\n*\n* \\param[in] ProcessHandle - Handle to the process requires PROCESS_VM_READ.\n* \\param[in] Rva - Relative virtual address to inspect.\n* \\param[in] Size - Size of data to inspect from the RVA.\n* \\param[in] Context - Image coherency context.\n* \\param[in] SkipCallback - Optional skip callback used to skip analysis.\n* \\param[in] SkipCallbackContext - Context passed to the skip callback.\n*/\nVOID PhpAnalyzeImageCoherencyCommonByRva(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Rva,\n    _In_ ULONG Size,\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context,\n    _In_opt_ PPH_IMGCOHERENCY_SKIP_BYTE_CALLBACK SkipCallback,\n    _In_opt_ PVOID SkipCallbackContext\n    )\n{\n    NTSTATUS status;\n    BYTE buffer[PAGE_SIZE];\n    ULONG remainingBytes;\n    ULONG chunk;\n    PBYTE fileBytes;\n    SIZE_T bytesRead;\n    SIZE_T remainingView;\n    SIZE_T bytes;\n    ULONG rva;\n\n    remainingBytes = Size;\n    rva = Rva;\n\n    while (remainingBytes > 0)\n    {\n        chunk = PAGE_SIZE;\n        if (chunk > remainingBytes)\n        {\n            chunk = remainingBytes;\n        }\n\n        //\n        // Try to read the remote process\n        //\n        if (!NT_SUCCESS(PhImageCoherencyReadVirtualMemoryCallback(\n            ProcessHandle,\n            PTR_ADD_OFFSET(Context->RemoteImageBase, rva),\n            buffer,\n            chunk,\n            &bytesRead,\n            Context\n            )))\n        {\n            //\n            // Force 0, we'll handle this below\n            //\n            bytesRead = 0;\n        }\n\n        fileBytes = PhMappedImageRvaToVa(&Context->MappedImage, rva, NULL);\n        if (fileBytes)\n        {\n            //\n            // Calculate the remaining view from the VA\n            //\n            remainingView = (SIZE_T)PTR_SUB_OFFSET(Context->MappedImage.ViewSize,\n                                                   PTR_SUB_OFFSET(fileBytes,\n                                                                  Context->MappedImage.ViewBase));\n        }\n        else\n        {\n            //\n            // Force 0, we'll handle this below\n            //\n            remainingView = 0;\n        }\n\n        //\n        // We will cast to ULONG below, should never have over PAGE_SIZE here.\n        //\n        bytes = __min(bytesRead, remainingView);\n        assert(bytes <= PAGE_SIZE);\n\n        //\n        // Do the inspection, clamp the bytes to the minimum\n        //\n        status = PhpAnalyzeImageCoherencyInspect(\n            fileBytes,\n            (ULONG)bytes,\n            buffer,\n            (ULONG)bytes,\n            Context,\n            rva,\n            SkipCallback,\n            SkipCallbackContext\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        rva += chunk;\n        remainingBytes -= chunk;\n    }\n}\n\n/**\n* Analyzes the image coherency as if it were a native application. And expects\n* certain bytes over the range, used for code cave scanning.\n*\n* \\param[in] ProcessHandle - Handle to the process requires PROCESS_VM_READ.\n* \\param[in] Rva - Relative virtual address to inspect.\n* \\param[in] Size - Size of data to inspect from the RVA.\n* \\param[in] Context - Image coherency context.\n* \\param[in] ExpectedByte - Expected byte in the entire range.\n*/\nVOID PhpAnalyzeImageCoherencyCommonByRvaExpectBytes(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Rva,\n    _In_ ULONG Size,\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context,\n    _In_ BYTE ExpectedByte\n    )\n{\n    NTSTATUS status;\n    BYTE buffer[PAGE_SIZE];\n    BYTE expected[PAGE_SIZE];\n    ULONG remainingBytes;\n    ULONG chunk;\n    SIZE_T bytesRead;\n    ULONG rva;\n\n    remainingBytes = Size;\n    rva = Rva;\n\n    RtlFillMemory(expected, PAGE_SIZE, ExpectedByte);\n\n    while (remainingBytes > 0)\n    {\n        chunk = PAGE_SIZE;\n        if (chunk > remainingBytes)\n        {\n            chunk = remainingBytes;\n        }\n\n        //\n        // Try to read the remote process\n        //\n        if (NT_SUCCESS(PhImageCoherencyReadVirtualMemoryCallback(\n            ProcessHandle,\n            PTR_ADD_OFFSET(Context->RemoteImageBase, rva),\n            buffer,\n            chunk,\n            &bytesRead,\n            Context\n            )))\n        {\n            assert(bytesRead <= PAGE_SIZE);\n\n            //\n            // Do the inspection\n            //\n            status = PhpAnalyzeImageCoherencyInspect(\n                expected,\n                (ULONG)bytesRead,\n                buffer,\n                (ULONG)bytesRead,\n                Context,\n                rva,\n                NULL,\n                NULL\n                );\n\n            if (!NT_SUCCESS(status))\n                break;\n        }\n\n        rva += chunk;\n        remainingBytes -= chunk;\n    }\n}\n\n/**\n* Skip bytes callback to skip bytes during inspection.\n*\n* \\param[in] Rva - Current rva in the range being inspected.\n* \\param[in] Context - Relocation skip context.\n* \\return Number of bytes to skip, 0 otherwise.\n*/\n_Function_class_(PH_IMGCOHERENCY_SKIP_BYTE_CALLBACK)\nULONG CALLBACK PhpImgCoherencySkip(\n    _In_ ULONG Rva,\n    _In_ PVOID Context\n    )\n{\n    PPH_IMAGE_COHERENCY_CONTEXT context;\n    PVOID* entry;\n\n    context = (PPH_IMAGE_COHERENCY_CONTEXT)Context;\n\n    if (context->MappedImageBaseRva && (context->MappedImageBaseRva == Rva))\n    {\n        if (context->MappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n            return RTL_FIELD_SIZE(IMAGE_OPTIONAL_HEADER32, ImageBase);\n        else if (context->MappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n            return RTL_FIELD_SIZE(IMAGE_OPTIONAL_HEADER64, ImageBase);\n        else\n            return 0;\n    }\n\n    if (context->MappedImageReloc)\n    {\n        //\n        // Look up the RVA in our hash table, if we find one we will skip the\n        // number of bytes stored in the hash table for that entry.\n        //\n        entry = PhFindItemSimpleHashtable(context->MappedImageReloc, PTR_ADD_OFFSET(NULL, Rva));\n        if (entry)\n            return PtrToUlong(*entry);\n    }\n\n    if (context->MappedImageIatRva && (context->MappedImageIatRva == Rva))\n    {\n        //\n        // Skip over the import address table.\n        //\n        return context->MappedImageIatSize;\n    }\n\n    return 0;\n}\n\n/**\n* Analyzes the image coherency as if it were a native application.\n*\n* \\param[in] ProcessHandle - Handle to the process requires PROCESS_VM_READ.\n* \\param[in] Context - Image coherency context.\n*/\nVOID PhpAnalyzeImageCoherencyCommonAsNative(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context\n    )\n{\n    ULONG addressOfEntry = 0;\n    PIMAGE_SECTION_HEADER entrySection;\n\n    switch (Context->MappedImage.Magic)\n    {\n    case IMAGE_NT_OPTIONAL_HDR32_MAGIC:\n        addressOfEntry = Context->MappedImage.NtHeaders32->OptionalHeader.AddressOfEntryPoint;\n        break;\n    case IMAGE_NT_OPTIONAL_HDR64_MAGIC:\n        addressOfEntry = Context->MappedImage.NtHeaders->OptionalHeader.AddressOfEntryPoint;\n        break;\n    default:\n        break;\n    }\n\n    if (addressOfEntry != 0)\n        entrySection = PhMappedImageRvaToSection(&Context->MappedImage, addressOfEntry);\n    else\n        entrySection = NULL;\n\n    //\n    // Here we will inspect each executable section.\n    //\n    for (USHORT i = 0;\n         i < __max(Context->MappedImage.NumberOfSections,\n                   Context->RemoteMappedImage.NumberOfSections);\n         i++)\n    {\n        if ((i < Context->MappedImage.NumberOfSections) &&\n            (i < Context->RemoteMappedImage.NumberOfSections))\n        {\n            PIMAGE_SECTION_HEADER mappedSection;\n            PIMAGE_SECTION_HEADER remoteMappedSection;\n\n            mappedSection = &Context->MappedImage.Sections[i];\n            remoteMappedSection = &Context->RemoteMappedImage.Sections[i];\n\n            if (PhpShouldScanSection(Context->Type, mappedSection) ||\n                PhpShouldScanSection(Context->Type, remoteMappedSection))\n            {\n                ULONG size;\n                SIZE_T prevTotal;\n                SIZE_T bytesInspected;\n                SIZE_T prevSkipped;\n                SIZE_T bytesSkipped;\n\n                size = PhpGetSectionScanSize(Context->Type, mappedSection);\n\n                prevTotal = Context->TotalBytes;\n                prevSkipped = Context->SkippedBytes;\n\n                PhpAnalyzeImageCoherencyCommonByRva(\n                    ProcessHandle,\n                    mappedSection->VirtualAddress,\n                    size,\n                    Context,\n                    PhpImgCoherencySkip,\n                    Context\n                    );\n\n                bytesInspected = (Context->TotalBytes - prevTotal);\n                bytesSkipped = (Context->SkippedBytes - prevSkipped);\n\n                if (entrySection == mappedSection)\n                {\n                    ULONG length;\n                    //\n                    // Make sure we scanned enough of the entry point.\n                    // If not, force scan that part.\n                    //\n                    length = __min(entrySection->SizeOfRawData,\n                                   entrySection->Misc.VirtualSize);\n                    length -= (addressOfEntry - entrySection->VirtualAddress);\n                    if (length > PH_IMGCOHERENCY_MIN_ENTRY_INSPECT)\n                    {\n                        length = PH_IMGCOHERENCY_MIN_ENTRY_INSPECT;\n                    }\n\n                    if ((bytesInspected + bytesSkipped) <\n                        (((ULONGLONG)addressOfEntry - entrySection->VirtualAddress) + length))\n                    {\n                        PhpAnalyzeImageCoherencyCommonByRva(\n                            ProcessHandle,\n                            addressOfEntry,\n                            length,\n                            Context,\n                            PhpImgCoherencySkip,\n                            Context\n                            );\n                    }\n                }\n\n                //\n                // If we're doing a full scan, inspect for possible code caves\n                // beyond on-disk content.\n                // If VirtualAddress is greater than SizeOfRawData the loader\n                // will zero initialize the bytes to extend the mapping.\n                // If there is non-zero content here someone has written\n                // into the code cave.\n                //\n                if ((Context->Type == PhImageCoherencyFull) &&\n                    ((mappedSection->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0) &&\n                    (mappedSection->Misc.VirtualSize > mappedSection->SizeOfRawData))\n                {\n                    PhpAnalyzeImageCoherencyCommonByRvaExpectBytes(\n                        ProcessHandle,\n                        mappedSection->VirtualAddress + mappedSection->SizeOfRawData,\n                        mappedSection->Misc.VirtualSize - mappedSection->SizeOfRawData,\n                        Context,\n                        0x00\n                        );\n                }\n            }\n        }\n        else\n        {\n            //\n            // There are a mismatched number of sections\n            // Inflate the total bytes\n            //\n            if (i < Context->MappedImage.NumberOfSections)\n            {\n                Context->TotalBytes += __min(Context->MappedImage.Sections[i].SizeOfRawData,\n                                             Context->MappedImage.Sections[i].Misc.VirtualSize);\n            }\n            else\n            {\n                Context->TotalBytes += __min(Context->RemoteMappedImage.Sections[i].SizeOfRawData,\n                                             Context->RemoteMappedImage.Sections[i].Misc.VirtualSize);\n            }\n        }\n    }\n}\n\n/**\n* Analyzes the image coherency as if it were a managed (.NET) application.\n*\n* \\param[in] ProcessHandle - Handle to the process requires PROCESS_VM_READ.\n* \\param[in] Context - Image coherency context.\n*/\nVOID PhpAnalyzeImageCoherencyCommonAsManaged(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context\n    )\n{\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_COR20_HEADER dotNet;\n\n    //\n    // We will check for coherency across two blocks here\n    //     1. The COR20 header\n    //     2. The .NET Meta Data\n    //\n\n    //\n    // Get the COM32 directory bytes\n    //\n    if (!NT_SUCCESS(PhGetMappedImageDataDirectory(\n        &Context->MappedImage,\n        IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,\n        &dataDirectory\n        )))\n    {\n        return;\n    }\n\n    //\n    // Inspect the COR20 header\n    //\n    PhpAnalyzeImageCoherencyCommonByRva(\n        ProcessHandle,\n        dataDirectory->VirtualAddress,\n        dataDirectory->Size,\n        Context,\n        NULL,\n        NULL\n        );\n\n    //\n    // Get the .NET MetaData\n    //\n    dotNet = PhMappedImageRvaToVa(&Context->MappedImage, dataDirectory->VirtualAddress, NULL);\n    if (!dotNet ||\n        (dotNet->MetaData.Size == 0) ||\n        !dotNet->MetaData.VirtualAddress)\n    {\n        return;\n    }\n\n    //\n    // Inspect the .NET MetaData\n    //\n    PhpAnalyzeImageCoherencyCommonByRva(\n        ProcessHandle,\n        dotNet->MetaData.VirtualAddress,\n        dotNet->MetaData.Size,\n        Context,\n        NULL,\n        NULL\n        );\n}\n\n/**\n* Checks if the image is a .NET application.\n*\n* \\param[in] Context - Image coherency context.\n*\n* \\return TRUE if the image is a .NET application, FALSE otherwise.\n*/\nBOOLEAN PhpAnalyzeImageCoherencyIsDotNet (\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context\n    )\n{\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_COR20_HEADER dotNet;\n    PULONG dotNetMagic;\n\n    //\n    // Get the com descriptor directly, if it doesn't exist it isn't .NET\n    //\n    if (!NT_SUCCESS(PhGetMappedImageDataDirectory(\n        &Context->MappedImage,\n        IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,\n        &dataDirectory\n        )))\n    {\n        return FALSE;\n    }\n\n    //\n    // Check for the COR20 header\n    //\n    dotNet = PhMappedImageRvaToVa(\n        &Context->MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n    if (!dotNet || (dotNet->cb != sizeof(IMAGE_COR20_HEADER)))\n    {\n        return FALSE;\n    }\n\n    dotNetMagic = PhMappedImageRvaToVa(\n        &Context->MappedImage,\n        dotNet->MetaData.VirtualAddress,\n        NULL\n        );\n    //\n    // If we can locate the magic number and it equal the .NET magic then we\n    // are reasonably confident it is .NET.\n    //\n    return (dotNetMagic && *dotNetMagic == 0x424A5342);\n}\n\n/**\n* Common analysis for image coherency.\n*\n* \\param[in] ProcessHandle - Handle to the process requires PROCESS_VM_READ.\n* \\param[in] Context - Image coherency context.\n*/\nVOID PhpAnalyzeImageCoherencyCommon(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context\n    )\n{\n    //\n    // Loop over the number of sections and include them in the calculation\n    //\n    for (USHORT i = 0;\n         i < __max(Context->MappedImage.NumberOfSections,\n                   Context->RemoteMappedImage.NumberOfSections);\n         i++)\n    {\n        if ((i < Context->MappedImage.NumberOfSections) &&\n            (i < Context->RemoteMappedImage.NumberOfSections))\n        {\n            PhpAnalyzeImageCoherencyInspect(\n                (PBYTE)&Context->MappedImage.Sections[i],\n                IMAGE_SIZEOF_SECTION_HEADER,\n                (PBYTE)&Context->RemoteMappedImage.Sections[i],\n                IMAGE_SIZEOF_SECTION_HEADER,\n                Context,\n                0,\n                NULL,\n                NULL\n                );\n        }\n        else\n        {\n            //\n            // There are a mismatched number of sections\n            // Inflate the total bytes\n            //\n            Context->TotalBytes += IMAGE_SIZEOF_SECTION_HEADER;\n        }\n    }\n\n    //\n    // If we detect the on-disk image is a .NET application use the managed\n    // path, this will assume the remote image is a .NET app, if it isn't\n    // we'll detect lots of incoherent bytes.\n    //\n    // Otherwise use the native path and inspect by the supplied RVAs\n    //\n    if (PhpAnalyzeImageCoherencyIsDotNet(Context))\n        PhpAnalyzeImageCoherencyCommonAsManaged(ProcessHandle, Context);\n    else\n        PhpAnalyzeImageCoherencyCommonAsNative(ProcessHandle, Context);\n}\n\n/**\n* Analyzes image coherency for 32 bit images.\n*\n* \\param[in] ProcessHandle - Handle to the process requires PROCESS_VM_READ.\n* \\param[in] Context - Image coherency context.\n*\n* \\return Success status or failure.\n*/\nNTSTATUS PhpAnalyzeImageCoherencyNt32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context\n    )\n{\n    PIMAGE_OPTIONAL_HEADER32 fileOptHeader;\n    PIMAGE_OPTIONAL_HEADER32 procOptHeader;\n\n    fileOptHeader = (PIMAGE_OPTIONAL_HEADER32)&Context->MappedImage.NtHeaders32->OptionalHeader;\n    procOptHeader = (PIMAGE_OPTIONAL_HEADER32)&Context->RemoteMappedImage.NtHeaders32->OptionalHeader;\n\n    //\n    // Inspect the header\n    //\n    PhpAnalyzeImageCoherencyInspect(\n        (PBYTE)Context->MappedImage.NtHeaders32,\n        UFIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader),\n        (PBYTE)Context->RemoteMappedImage.NtHeaders32,\n        UFIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader),\n        Context,\n        PtrToUlong(PTR_SUB_OFFSET(Context->MappedImage.NtHeaders32, Context->MappedImage.ViewBase)),\n        PhpImgCoherencySkip,\n        Context\n        );\n\n    //\n    // Inspect the optional header\n    //\n    PhpAnalyzeImageCoherencyInspect(\n        (PBYTE)fileOptHeader,\n        sizeof(IMAGE_OPTIONAL_HEADER32),\n        (PBYTE)procOptHeader,\n        sizeof(IMAGE_OPTIONAL_HEADER32),\n        Context,\n        PtrToUlong(PTR_SUB_OFFSET(fileOptHeader, Context->MappedImage.ViewBase)),\n        PhpImgCoherencySkip,\n        Context\n        );\n\n    //\n    // Do the common inspection\n    //\n    PhpAnalyzeImageCoherencyCommon(ProcessHandle, Context);\n\n    if (fileOptHeader->CheckSum != procOptHeader->CheckSum)\n    {\n        return STATUS_INVALID_IMAGE_HASH;\n    }\n    return STATUS_SUCCESS;\n}\n\n/**\n* Analyzes image coherency for 64 bit images.\n*\n* \\param[in] ProcessHandle - Handle to the process requires PROCESS_VM_READ.\n* \\param[in] Context - Image coherency context.\n*\n* \\return Success status or failure.\n*/\nNTSTATUS PhpAnalyzeImageCoherencyNt64(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context\n    )\n{\n    PIMAGE_OPTIONAL_HEADER64 fileOptHeader;\n    PIMAGE_OPTIONAL_HEADER64 procOptHeader;\n\n    fileOptHeader = (PIMAGE_OPTIONAL_HEADER64)&Context->MappedImage.NtHeaders->OptionalHeader;\n    procOptHeader = (PIMAGE_OPTIONAL_HEADER64)&Context->RemoteMappedImage.NtHeaders->OptionalHeader;\n\n    //\n    // Inspect the header\n    //\n    PhpAnalyzeImageCoherencyInspect(\n        (PBYTE)Context->MappedImage.NtHeaders,\n        UFIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader),\n        (PBYTE)Context->RemoteMappedImage.NtHeaders,\n        UFIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader),\n        Context,\n        PtrToUlong(PTR_SUB_OFFSET(Context->MappedImage.NtHeaders, Context->MappedImage.ViewBase)),\n        PhpImgCoherencySkip,\n        Context\n        );\n\n    //\n    // Inspect the optional header\n    //\n    PhpAnalyzeImageCoherencyInspect(\n        (PBYTE)fileOptHeader,\n        sizeof(IMAGE_OPTIONAL_HEADER64),\n        (PBYTE)procOptHeader,\n        sizeof(IMAGE_OPTIONAL_HEADER64),\n        Context,\n        PtrToUlong(PTR_SUB_OFFSET(fileOptHeader, Context->MappedImage.ViewBase)),\n        PhpImgCoherencySkip,\n        Context\n        );\n\n    //\n    // Do the common inspection\n    //\n    PhpAnalyzeImageCoherencyCommon(ProcessHandle, Context);\n\n    if (fileOptHeader->CheckSum != procOptHeader->CheckSum)\n    {\n        //\n        // The optional header checksum doesn't match the in memory checksum\n        // return status to reflect that. We could inflate the TotalBytes here\n        // but choose not.\n        //\n        return STATUS_INVALID_IMAGE_HASH;\n    }\n    return STATUS_SUCCESS;\n}\n\n/**\n* Inspects the process image coherency compared to the file on disk.\n*\n* \\param[in] ProcessHandle - Handle to the process requires PROCESS_VM_READ.\n* \\param[in] Context - Image coherency context.\n* \\param[out] ImageCoherency Image coherency value between 0 and 1. This\n* indicates how similar the image on-disk is compared to what is mapped into\n* the process. A value of 1 means coherent while a value lower than 1\n* indicates how incoherent the image is.\n*\n* \\return Status indicating the coherency calculation, note errors may indicate\n* partial success.\n* STATUS_SUCCESS The coherency calculation was successful.\n* STATUS_INVALID_IMAGE_HASH The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* STATUS_INVALID_IMAGE_FORMAT The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* STATUS_SUBSYSTEM_NOT_PRESENT The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* All other errors are failures to calculate.\n*/\nNTSTATUS PhpInspectForImageCoherency(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_IMAGE_COHERENCY_CONTEXT Context,\n    _Out_ PFLOAT ImageCoherency\n   )\n{\n    NTSTATUS status;\n\n    //\n    // Creating the coherency context is best-effort and will store the status\n    // in the context. We can infer some state if one fails, do so here.\n    //\n    if (!NT_SUCCESS(Context->MappedImageStatus) ||\n        !NT_SUCCESS(Context->RemoteMappedImageStatus))\n    {\n        if (NT_SUCCESS(Context->RemoteMappedImageStatus) &&\n            ((Context->MappedImageStatus == STATUS_INVALID_IMAGE_FORMAT) ||\n             (Context->MappedImageStatus == STATUS_INVALID_IMAGE_HASH) ||\n             (Context->MappedImageStatus == STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT)))\n        {\n            //\n            // If we succeeded to map the remote image but the on-disk image\n            // is inherently incoherent, return the status from the on-disk\n            // mapping.\n            //\n            status = Context->MappedImageStatus;\n        }\n        else\n        {\n            //\n            // If we failed for any other reason, return the error from the\n            // remote mapping.\n            //\n            status = Context->RemoteMappedImageStatus;\n        }\n        goto CleanupExit;\n    }\n\n    if (Context->MappedImage.Magic != Context->RemoteMappedImage.Magic)\n    {\n        //\n        // The image types don't match. This is incoherent but we have one more\n        // case to check. .NET can change this in the loaded PE to run \"AnyCPU\"\n        // in some cases, if it's a .NET mapping do the managed calculation.\n        //\n        if (PhpAnalyzeImageCoherencyIsDotNet(Context))\n            PhpAnalyzeImageCoherencyCommonAsManaged(ProcessHandle, Context);\n        status = STATUS_INVALID_IMAGE_FORMAT;\n        goto CleanupExit;\n    }\n\n    switch (Context->MappedImage.Magic)\n    {\n    case IMAGE_NT_OPTIONAL_HDR32_MAGIC:\n        status = PhpAnalyzeImageCoherencyNt32(ProcessHandle, Context);\n        break;\n    case IMAGE_NT_OPTIONAL_HDR64_MAGIC:\n        status = PhpAnalyzeImageCoherencyNt64(ProcessHandle, Context);\n        break;\n    default:\n        {\n            //\n            // Not supporting ELF for WSL yet. Note however, if the image type\n            // is mismatched above we will still reflect that\n            // (e.g. ELF<->non-ELF). But we don't yet support coherency checks\n            // for ELF<->ELF. The remote image mapping should be updated to\n            // handle remote mapping ELF.\n            //\n            status = STATUS_NOT_IMPLEMENTED;\n        }\n        break;\n    }\n\nCleanupExit:\n\n    if (Context->TotalBytes)\n        *ImageCoherency = (FLOAT)Context->CoherentBytes / (FLOAT)Context->TotalBytes;\n    else\n        *ImageCoherency = 0.0f;\n\n    return status;\n}\n\n/**\n* Inspects a module image coherency compared to the file on disk.\n*\n* \\param[in] FileName Win32 path to the image file on disk.\n* \\param[in] ProcessHandle - Handle to the process where the module is mapped\n* requires PROCESS_VM_READ.\n* \\param[in] RemoteImageBase - Base address of the image.\n* \\param[in] RemoteImageSize - Size of the image.\n* \\param[in] RemoteImageBaseStatus - If RemoteImageBase is null, this is stored\n* in the context instead of attempting to map the image.\n* \\param[in] IsKernelModule - Notes if this is a kernel module.\n* \\param[in] Type - Image coherency scan type.\n* \\param[out] ImageCoherency Image coherency value between 0 and 1. This\n* indicates how similar the image on-disk is compared to what is mapped into\n* the process. A value of 1 means coherent while a value lower than 1\n* indicates how incoherent the image is.\n*\n* \\return Status indicating the coherency calculation, note errors may indicate\n* partial success.\n* STATUS_SUCCESS The coherency calculation was successful.\n* STATUS_INVALID_IMAGE_HASH The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* STATUS_INVALID_IMAGE_FORMAT The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* STATUS_SUBSYSTEM_NOT_PRESENT The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* All other errors are failures to calculate.\n*/\nNTSTATUS PhpGetModuleCoherency(\n    _In_ PPH_STRING FileName,\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID RemoteImageBase,\n    _In_opt_ SIZE_T RemoteImageSize,\n    _In_ NTSTATUS RemoteImageBaseStatus,\n    _In_ BOOLEAN IsKernelModule,\n    _In_ PH_IMAGE_COHERENCY_SCAN_TYPE Type,\n    _Out_ PFLOAT ImageCoherency\n    )\n{\n    NTSTATUS status;\n\n    *ImageCoherency = 0.0f;\n\n    if (Type == PhImageCoherencySharedOriginal)\n    {\n        SIZE_T numberOfPages;\n        SIZE_T numberOfTamperedPages;\n\n        if (!RemoteImageBase || RemoteImageSize < PAGE_SIZE)\n            return STATUS_INVALID_PARAMETER;\n\n        status = PhCheckImagePagesForTampering(\n            ProcessHandle,\n            RemoteImageBase,\n            RemoteImageSize,\n            &numberOfPages,\n            &numberOfTamperedPages\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            *ImageCoherency = (FLOAT)(numberOfPages - numberOfTamperedPages) / (FLOAT)numberOfPages;\n        }\n    }\n    else\n    {\n        PPH_IMAGE_COHERENCY_CONTEXT context;\n\n        context = PhpCreateImageCoherencyContext(\n            Type,\n            FileName,\n            ProcessHandle,\n            RemoteImageBase,\n            RemoteImageSize,\n            RemoteImageBaseStatus,\n            IsKernelModule\n            );\n\n        status = PhpInspectForImageCoherency(ProcessHandle, context, ImageCoherency);\n\n        PhpFreeImageCoherencyContext(context);\n    }\n\n    return status;\n}\n\n/**\n* Inspects the process image coherency compared to the file on disk.\n*\n* \\param[in] FileName Win32 path to the image file on disk.\n* \\param[in] ProcessId Process ID of the active process to compare to.\n* \\param[in] Type - Image coherency scan type.\n* \\param[out] ImageCoherency Image coherency value between 0 and 1. This\n* indicates how similar the image on-disk is compared to what is mapped into\n* the process. A value of 1 means coherent while a value lower than 1\n* indicates how incoherent the image is.\n*\n* \\return Status indicating the coherency calculation, note errors may indicate\n* partial success.\n* STATUS_SUCCESS The coherency calculation was successful.\n* STATUS_INVALID_IMAGE_HASH The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* STATUS_INVALID_IMAGE_FORMAT The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* STATUS_SUBSYSTEM_NOT_PRESENT The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* All other errors are failures to calculate.\n*/\nNTSTATUS PhGetProcessImageCoherency(\n    _In_ PPH_STRING FileName,\n    _In_ HANDLE ProcessId,\n    _In_ PH_IMAGE_COHERENCY_SCAN_TYPE Type,\n    _Out_ PFLOAT ImageCoherency\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    PVOID remoteImageBase;\n    PVOID imageBase;\n    SIZE_T imageSize;\n\n    remoteImageBase = NULL;\n    imageBase = NULL;\n    imageSize = 0;\n\n    *ImageCoherency = 0.0f;\n\n    // Try to get a handle with query information + vm read access.\n    if (!NT_SUCCESS(status = PhOpenProcess(\n        &processHandle,\n        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n        ProcessId\n        )))\n    {\n        // Try to get a handle with query limited information + vm read access.\n        if (!NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n            ProcessId\n            )))\n        {\n            processHandle = NULL;\n            goto CleanupExit;\n        }\n    }\n\n    //\n    // Get the remote image base\n    //\n    status = PhGetProcessImageBaseAddress(processHandle, &remoteImageBase);\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetProcessMappedImageBaseFromAddress(\n            processHandle,\n            remoteImageBase,\n            &imageBase,\n            &imageSize\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhpGetModuleCoherency(\n            FileName,\n            processHandle,\n            imageBase,\n            imageSize,\n            status,\n            FALSE,\n            Type,\n            ImageCoherency\n            );\n    }\n\nCleanupExit:\n\n    if (processHandle)\n    {\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\n/**\n* Inspects a module image coherency compared to the file on disk.\n*\n* \\param[in] FileName Win32 path to the image file on disk.\n* \\param[in] ProcessHandle - Handle to the process where the module is mapped\n* requires PROCESS_VM_READ.\n* \\param[in] ImageBaseAddress - Base address of the image.\n* \\param[in] ImageSize - Size of the image.\n* \\param[in] IsKernelModule - Notes if this is a kernel module.\n* \\param[in] Type - Image coherency scan type.\n* \\param[out] ImageCoherency Image coherency value between 0 and 1. This\n* indicates how similar the image on-disk is compared to what is mapped into\n* the process. A value of 1 means coherent while a value lower than 1\n* indicates how incoherent the image is.\n*\n* \\return Status indicating the coherency calculation, note errors may indicate\n* partial success.\n* STATUS_SUCCESS The coherency calculation was successful.\n* STATUS_INVALID_IMAGE_HASH The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* STATUS_INVALID_IMAGE_FORMAT The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* STATUS_SUBSYSTEM_NOT_PRESENT The coherency calculation was successful or\n* partially successful and unusually incoherent.\n* All other errors are failures to calculate.\n*/\nNTSTATUS PhGetProcessModuleImageCoherency(\n    _In_ PPH_STRING FileName,\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID ImageBaseAddress,\n    _In_ SIZE_T ImageSize,\n    _In_ BOOLEAN IsKernelModule,\n    _In_ PH_IMAGE_COHERENCY_SCAN_TYPE Type,\n    _Out_ PFLOAT ImageCoherency\n    )\n{\n    return PhpGetModuleCoherency(\n        FileName,\n        ProcessHandle,\n        ImageBaseAddress,\n        ImageSize,\n        STATUS_SUCCESS,\n        IsKernelModule,\n        Type,\n        ImageCoherency\n        );\n}\n\n/**\n * \\brief Checks the image pages for tampering.\n *\n * \\details Checkout out or blog for more info:\n * https://windows-internals.com/understanding-a-new-mitigation-module-tampering-protection/\n *\n * \\param[in] ProcessHandle - Handle to the process where the module is mapped.\n * \\param[in] BaseAddress - Base address of the image pages to check.\n * \\param[in] SizeOfImage - Size of the image to check.\n * \\param[out] NumberOfPages - Number of pages checked.\n * \\param[out] NumberOfTamperedPages - Number of tampered pages.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS PhCheckImagePagesForTampering(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T SizeOfImage,\n    _Out_ PSIZE_T NumberOfPages,\n    _Out_ PSIZE_T NumberOfTamperedPages\n    )\n{\n    NTSTATUS status;\n    SIZE_T numberOfPages;\n    ULONG_PTR virtualAddress;\n    MEMORY_WORKING_SET_EX_INFORMATION* info;\n    SIZE_T i;\n\n    *NumberOfPages = 0;\n    *NumberOfTamperedPages = 0;\n\n    numberOfPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, SizeOfImage);\n    virtualAddress = (ULONG_PTR)PAGE_ALIGN(BaseAddress);\n\n    if (!numberOfPages)\n        return STATUS_INVALID_PARAMETER;\n\n    info = PhAllocatePage(numberOfPages * sizeof(MEMORY_WORKING_SET_EX_INFORMATION), NULL);\n\n    if (!info)\n        return STATUS_NO_MEMORY;\n\n    for (i = 0; i < numberOfPages; i++)\n    {\n        info[i].VirtualAddress = (PVOID)virtualAddress;\n        virtualAddress += PAGE_SIZE;\n    }\n\n    status = NtQueryVirtualMemory(\n        ProcessHandle,\n        NULL,\n        MemoryWorkingSetExInformation,\n        info,\n        numberOfPages * sizeof(MEMORY_WORKING_SET_EX_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *NumberOfPages = numberOfPages;\n\n        for (i = 0; i < numberOfPages; i++)\n        {\n            PMEMORY_WORKING_SET_EX_BLOCK page = &info[i].VirtualAttributes;\n\n            if (!page->SharedOriginal)\n            {\n                (*NumberOfTamperedPages)++;\n            }\n        }\n    }\n\n    PhFreePage(info);\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/include/apiimport.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015-2016\n *     dmex    2017-2024\n *\n */\n\n#ifndef _PH_APIIMPORT_H\n#define _PH_APIIMPORT_H\n\n#include <devquery.h>\n#include <sddl.h>\n#include <shlwapi.h>\n#include <userenv.h>\n#include <ntuser.h>\n#include <xmllite.h>\n\nEXTERN_C_START\n\n#define PH_DECLARE_IMPORT(Name) typeof(&(Name)) Name##_Import(VOID)\n\n// Ntdll\n\nPH_DECLARE_IMPORT(NtQueryInformationEnlistment);\nPH_DECLARE_IMPORT(NtQueryInformationResourceManager);\nPH_DECLARE_IMPORT(NtQueryInformationTransaction);\nPH_DECLARE_IMPORT(NtQueryInformationTransactionManager);\nPH_DECLARE_IMPORT(NtCreateProcessStateChange);\nPH_DECLARE_IMPORT(NtChangeProcessState);\nPH_DECLARE_IMPORT(NtCreateThreadStateChange);\nPH_DECLARE_IMPORT(NtChangeThreadState);\nPH_DECLARE_IMPORT(NtCopyFileChunk);\nPH_DECLARE_IMPORT(NtCompareObjects);\nPH_DECLARE_IMPORT(NtCreateTimer2);\nPH_DECLARE_IMPORT(NtSetTimer2);\n\nPH_DECLARE_IMPORT(NtSetInformationVirtualMemory);\nPH_DECLARE_IMPORT(LdrSystemDllInitBlock);\nPH_DECLARE_IMPORT(LdrResFindResource);\nPH_DECLARE_IMPORT(LdrResSearchResource);\n\nPH_DECLARE_IMPORT(RtlDefaultNpAcl);\nPH_DECLARE_IMPORT(RtlDelayExecution);\nPH_DECLARE_IMPORT(RtlDeriveCapabilitySidsFromName);\nPH_DECLARE_IMPORT(RtlDosLongPathNameToNtPathName_U_WithStatus);\nPH_DECLARE_IMPORT(RtlGetTokenNamedObjectPath);\nPH_DECLARE_IMPORT(RtlGetAppContainerNamedObjectPath);\nPH_DECLARE_IMPORT(RtlGetAppContainerSidType);\nPH_DECLARE_IMPORT(RtlGetAppContainerParent);\n\nPH_DECLARE_IMPORT(PssNtCaptureSnapshot);\nPH_DECLARE_IMPORT(PssNtQuerySnapshot);\nPH_DECLARE_IMPORT(PssNtFreeSnapshot);\nPH_DECLARE_IMPORT(PssNtFreeRemoteSnapshot);\nPH_DECLARE_IMPORT(NtPssCaptureVaSpaceBulk);\nPH_DECLARE_IMPORT(TpSetPoolThreadBasePriority);\n\n// Advapi32\n\nPH_DECLARE_IMPORT(ConvertSecurityDescriptorToStringSecurityDescriptorW);\nPH_DECLARE_IMPORT(ConvertStringSecurityDescriptorToSecurityDescriptorW);\n\n// Cfgmgr32\n\nPH_DECLARE_IMPORT(DevGetObjects);\nPH_DECLARE_IMPORT(DevFreeObjects);\nPH_DECLARE_IMPORT(DevGetObjectProperties);\nPH_DECLARE_IMPORT(DevFreeObjectProperties);\nPH_DECLARE_IMPORT(DevCreateObjectQuery);\nPH_DECLARE_IMPORT(DevCloseObjectQuery);\n\n// Shlwapi\n\nPH_DECLARE_IMPORT(SHAutoComplete);\nPH_DECLARE_IMPORT(SHCreateStreamOnFileEx);\n\n// Userenv\n\nPH_DECLARE_IMPORT(CreateEnvironmentBlock);\nPH_DECLARE_IMPORT(DestroyEnvironmentBlock);\nPH_DECLARE_IMPORT(GetAppContainerRegistryLocation);\nPH_DECLARE_IMPORT(GetAppContainerFolderPath);\n\n// User32\n\nPH_DECLARE_IMPORT(ConsoleControl);\nPH_DECLARE_IMPORT(GetCurrentInputMessageSource);\nPH_DECLARE_IMPORT(GetCIMSSM);\nPH_DECLARE_IMPORT(NtUserBuildHwndList);\n\n// Xmllite\n\nPH_DECLARE_IMPORT(CreateXmlReader);\nPH_DECLARE_IMPORT(CreateXmlWriter);\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/appresolver.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_APPRESOLVER_H\n#define _PH_APPRESOLVER_H\n\nEXTERN_C_START\n\nHRESULT PhAppResolverGetAppIdForProcess(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING *ApplicationUserModelId\n    );\n\nHRESULT PhAppResolverGetAppIdForWindow(\n    _In_ HWND WindowHandle,\n    _Out_ PPH_STRING *ApplicationUserModelId\n    );\n\nHRESULT PhAppResolverActivateAppId(\n    _In_ PPH_STRING ApplicationUserModelId,\n    _In_opt_ PCWSTR CommandLine,\n    _Out_opt_ HANDLE *ProcessId\n    );\n\nHRESULT PhAppResolverPackageTerminateProcess(\n    _In_ PCWSTR PackageFullName\n    );\n\ntypedef struct _PH_PACKAGE_TASK_ENTRY\n{\n    PPH_STRING TaskName;\n    GUID TaskGuid;\n} PH_PACKAGE_TASK_ENTRY, *PPH_PACKAGE_TASK_ENTRY;\n\nHRESULT PhAppResolverEnumeratePackageBackgroundTasks(\n    _In_ PCWSTR PackageFullName,\n    _Inout_ PPH_LIST BackgroundTasks\n    );\n\nHRESULT PhAppResolverPackageStopSessionRedirection(\n    _In_ PCWSTR PackageFullName\n    );\n\nPPH_STRING PhGetAppContainerName(\n    _In_ PSID AppContainerSid\n    );\n\nPPH_STRING PhGetAppContainerSidFromName(\n    _In_ PCWSTR AppContainerName\n    );\n\nPPH_STRING PhGetAppContainerPackageName(\n    _In_ PSID Sid\n    );\n\nBOOLEAN PhIsPackageCapabilitySid(\n    _In_ PSID AppContainerSid,\n    _In_ PSID Sid\n    );\n\nPPH_STRING PhGetPackagePath(\n    _In_ PPH_STRING PackageFullName\n    );\n\nPPH_LIST PhGetPackageAssetsFromResourceFile(\n    _In_ PCWSTR FilePath\n    );\n\ntypedef struct _PH_APPUSERMODELID_ENUM_ENTRY\n{\n    PPH_STRING AppUserModelId;\n    PPH_STRING PackageName;\n    PPH_STRING PackageDisplayName;\n    PPH_STRING PackageFamilyName;\n    PPH_STRING PackageInstallPath;\n    PPH_STRING PackageFullName;\n    PPH_STRING PackageVersion;\n    PPH_STRING SmallLogoPath;\n} PH_APPUSERMODELID_ENUM_ENTRY, *PPH_APPUSERMODELID_ENUM_ENTRY;\n\nPPH_LIST PhEnumApplicationUserModelIds(\n    VOID\n    );\n\nHRESULT PhAppResolverGetPackageResourceFilePath(\n    _In_ PCWSTR PackageFullName,\n    _In_ PCWSTR Key,\n    _Out_ PWSTR* FilePath\n    );\n\n_Success_(return)\nBOOLEAN PhAppResolverGetPackageIcon(\n    _In_ HANDLE ProcessId,\n    _In_ PPH_STRING PackageFullName,\n    _Out_opt_ HICON* IconLarge,\n    _Out_opt_ HICON* IconSmall,\n    _In_ LONG SystemDpi\n    );\n\n// Immersive PLM task support\n\nHRESULT PhAppResolverBeginCrashDumpTask(\n    _In_ HANDLE ProcessId,\n    _Out_ HANDLE* TaskHandle\n    );\n\nHRESULT PhAppResolverBeginCrashDumpTaskByHandle(\n    _In_ HANDLE ProcessHandle,\n    _Out_ HANDLE* TaskHandle\n    );\n\nHRESULT PhAppResolverEndCrashDumpTask(\n    _In_ HANDLE TaskHandle\n    );\n\n// Desktop Bridge\n\nHRESULT PhCreateProcessDesktopPackage(\n    _In_ PCWSTR ApplicationUserModelId,\n    _In_ PCWSTR Executable,\n    _In_ PCWSTR Arguments,\n    _In_opt_ PCWSTR Directory,\n    _In_ BOOLEAN PreventBreakaway,\n    _In_opt_ HANDLE ParentProcessId,\n    _Out_opt_ PHANDLE ProcessHandle\n    );\n\n//\n// Windows Runtime\n//\n\n#ifndef __hstring_h__\ntypedef struct HSTRING__* HSTRING;\n#endif\n\n// Note: The HSTRING structures can be found in the Windows SDK\n// \\cppwinrt\\winrt\\base.h under MIT License. (dmex)\n\ntypedef struct _WSTRING_HEADER // HSTRING_HEADER (WinSDK)\n{\n    union\n    {\n        PVOID Reserved1;\n#if defined(_WIN64)\n        char Reserved2[24];\n#else\n        char Reserved2[20];\n#endif\n    } Reserved;\n} WSTRING_HEADER;\n\n#define HSTRING_REFERENCE_FLAG 0x1 // hstring_reference_flag (WinSDK)\n\ntypedef struct _HSTRING_REFERENCE // Stack\n{\n    union\n    {\n        WSTRING_HEADER Header;\n        struct\n        {\n            UINT32 Flags;\n            UINT32 Length;\n            UINT32 Padding1;\n            UINT32 Padding2;\n            PCWSTR Buffer;\n        };\n    };\n} HSTRING_REFERENCE;\n\n#ifdef __hstring_h__\nstatic_assert(sizeof(HSTRING_REFERENCE) == sizeof(HSTRING_HEADER), \"HSTRING_REFERENCE must equal WSTRING_HEADER\");\n#else\nstatic_assert(sizeof(HSTRING_REFERENCE) == sizeof(WSTRING_HEADER), \"HSTRING_REFERENCE must equal WSTRING_HEADER\");\n#endif\n\ntypedef struct _HSTRING_INSTANCE // Heap\n{\n    // Header\n    union\n    {\n        WSTRING_HEADER Header;\n        struct\n        {\n            UINT32 Flags;\n            UINT32 Length;\n            UINT32 Padding1;\n            UINT32 Padding2;\n            PCWSTR Buffer;\n        };\n    };\n\n    // Data\n    volatile LONG ReferenceCount;\n    WCHAR Data[ANYSIZE_ARRAY];\n} HSTRING_INSTANCE;\n\n#define HSTRING_FROM_STRING(Header) \\\n    ((HSTRING)&(Header))\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhCreateStringFromWindowsRuntimeString(\n    _In_ HSTRING String\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhCreateWindowsRuntimeStringReference(\n    _In_ PCWSTR SourceString,\n    _Out_ PVOID String\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhCreateWindowsRuntimeStringReferenceEx(\n    _In_ PCWSTR SourceString,\n    _In_ UINT32 Length,\n    _Out_ PVOID String\n    );\n\nFORCEINLINE\nHRESULT\nNTAPI\nPhCreateWindowsRuntimeStringRef(\n    _In_ PPH_STRINGREF SourceString,\n    _Out_ PVOID String\n    )\n{\n    if (SourceString->Length >= ULONG_MAX)\n    {\n        return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);\n    }\n\n    return PhCreateWindowsRuntimeStringReferenceEx(SourceString->Buffer, (ULONG)SourceString->Length / sizeof(WCHAR), String);\n}\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhCreateWindowsRuntimeString(\n    _In_ PCWSTR SourceString,\n    _Out_ HSTRING* String\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteWindowsRuntimeString(\n    _In_opt_ HSTRING String\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetWindowsRuntimeStringLength(\n    _In_opt_ HSTRING String\n    );\n\nPHLIBAPI\nPCWSTR\nNTAPI\nPhGetWindowsRuntimeStringBuffer(\n    _In_opt_ HSTRING String,\n    _Out_opt_ PULONG Length\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhGetProcessSystemIdentification(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING* SystemIdForPublisher,\n    _Out_ PPH_STRING* SystemIdForUser\n    );\n\nPHLIBAPI\nPPH_LIST\nNTAPI\nPhEnumPackageApplicationUserModelIds(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDestroyEnumPackageApplicationUserModelIds(\n    _In_ PPH_LIST PackageList\n    );\n\n#pragma region Activation Factory\n\n// 00000035-0000-0000-C000-000000000046\nDEFINE_GUID(IID_IActivationFactory, 0x00000035, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);\n// AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90\nDEFINE_GUID(IID_IInspectable, 0xAF86E2E0, 0xB12D, 0x4c6a, 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90);\n\n#ifdef interface\n#ifndef __IInspectable_FWD_DEFINED__\n#define __IInspectable_FWD_DEFINED__\ntypedef interface IInspectable IInspectable;\n#endif\n#ifndef __IInspectable_INTERFACE_DEFINED__\n#define __IInspectable_INTERFACE_DEFINED__\n#if defined(__cplusplus) && !defined(CINTERFACE)\nMIDL_INTERFACE(\"AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90\")\nIInspectable : public IUnknown\n{\npublic:\n    virtual HRESULT STDMETHODCALLTYPE GetIids(\n        __RPC__out ULONG * iidCount,\n        __RPC__deref_out_ecount_full_opt(*iidCount) IID * *iids) = 0;\n    virtual HRESULT STDMETHODCALLTYPE GetRuntimeClassName(\n        __RPC__deref_out_opt HSTRING* className) = 0;\n    virtual HRESULT STDMETHODCALLTYPE GetTrustLevel(\n        __RPC__out ULONG* trustLevel) = 0;\n};\n#else\ntypedef struct IInspectableVtbl\n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IUnknown, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        __RPC__in IInspectable* This,\n        __RPC__in REFIID riid,\n        _COM_Outptr_ void** ppvObject);\n\n    DECLSPEC_XFGVIRT(IUnknown, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        __RPC__in IInspectable* This);\n\n    DECLSPEC_XFGVIRT(IUnknown, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        __RPC__in IInspectable* This);\n\n    DECLSPEC_XFGVIRT(IInspectable, GetIids)\n    HRESULT (STDMETHODCALLTYPE* GetIids)(\n        __RPC__in IInspectable* This,\n        __RPC__out ULONG* iidCount,\n        __RPC__deref_out_ecount_full_opt(*iidCount) IID** iids);\n\n    DECLSPEC_XFGVIRT(IInspectable, GetRuntimeClassName)\n    HRESULT (STDMETHODCALLTYPE* GetRuntimeClassName)(\n        __RPC__in IInspectable* This,\n        __RPC__deref_out_opt HSTRING* className);\n\n    DECLSPEC_XFGVIRT(IInspectable, GetTrustLevel)\n    HRESULT (STDMETHODCALLTYPE* GetTrustLevel)(\n        __RPC__in IInspectable* This,\n        __RPC__out ULONG* trustLevel); // TrustLevel\n\n    END_INTERFACE\n} IInspectableVtbl;\n\ninterface IInspectable\n{\n    CONST_VTBL struct IInspectableVtbl* lpVtbl;\n};\n\n#ifdef COBJMACROS\n#define IInspectable_QueryInterface(This,riid,ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IInspectable_AddRef(This) \\\n    ((This)->lpVtbl->AddRef(This))\n#define IInspectable_Release(This) \\\n    ((This)->lpVtbl->Release(This))\n#define IInspectable_GetIids(This,iidCount,iids) \\\n    ((This)->lpVtbl->GetIids(This,iidCount,iids))\n#define IInspectable_GetRuntimeClassName(This,className) \\\n    ((This)->lpVtbl->GetRuntimeClassName(This,className))\n#define IInspectable_GetTrustLevel(This,trustLevel) \\\n    ((This)->lpVtbl->GetTrustLevel(This,trustLevel))\n#endif\n#endif\n#endif\n\n#ifndef __IActivationFactory_FWD_DEFINED__\n#define __IActivationFactory_FWD_DEFINED__\ntypedef interface IActivationFactory IActivationFactory;\n#endif\n#ifndef __IActivationFactory_INTERFACE_DEFINED__\n#define __IActivationFactory_INTERFACE_DEFINED__\n#if defined(__cplusplus) && !defined(CINTERFACE)\nMIDL_INTERFACE(\"00000035-0000-0000-C000-000000000046\")\nIActivationFactory : public IInspectable\n{\npublic:\n    virtual HRESULT STDMETHODCALLTYPE ActivateInstance(\n        __RPC__deref_out_opt IInspectable * *instance) = 0;\n\n};\n#else\ntypedef struct IActivationFactoryVtbl\n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IUnknown, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        __RPC__in IActivationFactory* This,\n        __RPC__in REFIID riid,\n        _COM_Outptr_ void** ppvObject);\n\n    DECLSPEC_XFGVIRT(IUnknown, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        __RPC__in IActivationFactory* This);\n\n    DECLSPEC_XFGVIRT(IUnknown, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        __RPC__in IActivationFactory* This);\n\n    DECLSPEC_XFGVIRT(IInspectable, GetIids)\n    HRESULT (STDMETHODCALLTYPE* GetIids)(\n        __RPC__in IActivationFactory* This,\n        __RPC__out ULONG* iidCount,\n        __RPC__deref_out_ecount_full_opt(*iidCount) IID** iids);\n\n    DECLSPEC_XFGVIRT(IInspectable, GetRuntimeClassName)\n    HRESULT (STDMETHODCALLTYPE* GetRuntimeClassName)(\n        __RPC__in IActivationFactory* This,\n        __RPC__deref_out_opt HSTRING* className);\n\n    DECLSPEC_XFGVIRT(IInspectable, GetTrustLevel)\n    HRESULT (STDMETHODCALLTYPE* GetTrustLevel)(\n        __RPC__in IActivationFactory* This,\n        __RPC__out ULONG* trustLevel); // TrustLevel enum\n\n    DECLSPEC_XFGVIRT(IActivationFactory, ActivateInstance)\n    HRESULT (STDMETHODCALLTYPE* ActivateInstance)(\n        __RPC__in IActivationFactory* This,\n        __RPC__deref_out_opt IInspectable** instance);\n\n    END_INTERFACE\n} IActivationFactoryVtbl;\n\ninterface IActivationFactory\n{\n    CONST_VTBL struct IActivationFactoryVtbl* lpVtbl;\n};\n\n#ifdef COBJMACROS\n#define IActivationFactory_QueryInterface(This,riid,ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IActivationFactory_AddRef(This) \\\n    ((This)->lpVtbl->AddRef(This))\n#define IActivationFactory_Release(This) \\\n    ((This)->lpVtbl->Release(This))\n#define IActivationFactory_GetIids(This,iidCount,iids) \\\n    ((This)->lpVtbl->GetIids(This,iidCount,iids))\n#define IActivationFactory_GetRuntimeClassName(This,className) \\\n    ((This)->lpVtbl->GetRuntimeClassName(This,className))\n#define IActivationFactory_GetTrustLevel(This,trustLevel) \\\n    ((This)->lpVtbl->GetTrustLevel(This,trustLevel))\n#define IActivationFactory_ActivateInstance(This,instance) \\\n    ((This)->lpVtbl->ActivateInstance(This,instance))\n#endif\n#endif\n#endif\n\n#endif\n\n#pragma endregion\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/appresolverp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_APPRESOLVER_P_H\n#define _PH_APPRESOLVER_P_H\n\n// \"660B90C8-73A9-4B58-8CAE-355B7F55341B\"\nDEFINE_GUID(CLSID_StartMenuCacheAndAppResolver_I, 0x660B90C8, 0x73A9, 0x4B58, 0x8C, 0xAE, 0x35, 0x5B, 0x7F, 0x55, 0x34, 0x1B);\n// \"46A6EEFF-908E-4DC6-92A6-64BE9177B41C\"\nDEFINE_GUID(IID_IApplicationResolver_I, 0x46A6EEFF, 0x908E, 0x4DC6, 0x92, 0xA6, 0x64, 0xBE, 0x91, 0x77, 0xB4, 0x1c);\n// \"DE25675A-72DE-44b4-9373-05170450C140\"\nDEFINE_GUID(IID_IApplicationResolver2_I, 0xDE25675A, 0x72DE, 0x44b4, 0x93, 0x73, 0x05, 0x17, 0x04, 0x50, 0xC1, 0x40);\n// \"33F71155-C2E9-4FFE-9786-A32D98577CFF\"\nDEFINE_GUID(IID_IStartMenuAppItems_I, 0x33F71155, 0xC2E9, 0x4FFE, 0x97, 0x86, 0xA3, 0x2D, 0x98, 0x57, 0x7C, 0xFF);\n// \"02C5CCF3-805F-4654-A7B7-340A74335365\"\nDEFINE_GUID(IID_IStartMenuAppItems2_I, 0x02C5CCF3, 0x805F, 0x4654, 0xA7, 0xB7, 0x34, 0x0A, 0x74, 0x33, 0x53, 0x65);\n\n// ba5a92ae_bfd7_4916_854f_6b3a402b84a8\n// 21cbc515_2dde_4d66_8292_ba34bd25094a\n// 17541a17_f509_4cb6_8d08_651dc68d8227\n// 67383c80_7543_4e04_9e97_c990f5e3878d\n// 3af46105_16ce_776f_43a2_341172b6e95a\n// 6b1d7151_7a17_4c66_abc4_c9b1bc6c0e8d\n// ffd2cca4_adfb_46e9_9a02_49d019db2a68\n// 8dda7cc4_ae71_4e2a_bc8d_7f16ec66f540\n\n// \"ba5a92ae-bfd7-4916-854f-6b3a402b84a8\"\n//DEFINE_GUID(IID_IStartMenuItemsCache, 0xba5a92ae, 0xbfd7, 0x4916, 0x85, 0x4f, 0x6b, 0x3a, 0x40, 0x2b, 0x84, 0xa8);\n// \"21cbc515-2dde-4d66-8292-ba34bd25094a\"\nDEFINE_GUID(IID_IDesktopTileActivator, 0x21cbc515, 0x2dde, 0x4d66, 0x82, 0x92, 0xba, 0x34, 0xbd, 0x25, 0x09, 0x4a);\n// \"17541a17-f509-4cb6-8d08-651dc68d8227\"\nDEFINE_GUID(IID_IAppResolverPinToStart, 0x17541a17, 0xf509, 0x4cb6, 0x8d, 0x08, 0x65, 0x1d, 0xc6, 0x8d, 0x82, 0x27);\n// \"67383c80-7543-4e04-9e97-c990f5e3878d\"\nDEFINE_GUID(IID_ILauncherAppList, 0x67383c80, 0x7543, 0x4e04, 0x9e, 0x97, 0xc9, 0x90, 0xf5, 0xe3, 0x87, 0x8d);\n// \"3af46105-16ce-776f-43a2-341172b6e95a\"\nDEFINE_GUID(IID_IStartMenuRankManager, 0x3af46105, 0x16ce, 0x776f, 0x43, 0xa2, 0x34, 0x11, 0x72, 0xb6, 0xe9, 0x5a);\n// \"6b1d7151-7a17-4c66-abc4-c9b1bc6c0e8d\"\nDEFINE_GUID(IID_IAppResolverCacheAccessor, 0x6b1d7151, 0x7a17, 0x4c66, 0xab, 0xc4, 0xc9, 0xb1, 0xbc, 0x6c, 0x0e, 0x8d);\n// \"ffd2cca4-adfb-46e9-9a02-49d019db2a68\"\nDEFINE_GUID(IID_IAppResolverPinToStartFF, 0xffd2cca4, 0xadfb, 0x46e9, 0x9a, 0x02, 0x49, 0xd0, 0x19, 0xdb, 0x2a, 0x68);\n// \"8dda7cc4-ae71-4e2a-bc8d-7f16ec66f540\"\nDEFINE_GUID(IID_IAppResolverPinToStartF, 0x8dda7cc4, 0xae71, 0x4e2a, 0xbc, 0x8d, 0x7f, 0x16, 0xec, 0x66, 0xf5, 0x40);\n// \"DE25675A-72DE-44b4-9373-05170450C140\"\n\n// IStartMenuItemsCache\n// IDesktopTileActivator\n// IAppResolverPinToStart\n// ILauncherAppList\n// IStartMenuRankManager\n// IAppResolverCacheAccessor\n\n// \"DBCE7E40-7345-439D-B12C-114A11819A09\"\nDEFINE_GUID(CLSID_MrtResourceManager_I, 0xDBCE7E40, 0x7345, 0x439D, 0xB1, 0x2C, 0x11, 0x4A, 0x11, 0x81, 0x9A, 0x09);\n// \"130A2F65-2BE7-4309-9A58-A9052FF2B61C\"\nDEFINE_GUID(IID_IMrtResourceManager_I, 0x130A2F65, 0x2BE7, 0x4309, 0x9A, 0x58, 0xA9, 0x05, 0x2F, 0xF2, 0xB6, 0x1C);\n// \"E3C22B30-8502-4B2F-9133-559674587E51\"\nDEFINE_GUID(IID_IResourceContext_I, 0xE3C22B30, 0x8502, 0x4B2F, 0x91, 0x33, 0x55, 0x96, 0x74, 0x58, 0x7E, 0x51);\n// \"6E21E72B-B9B0-42AE-A686-983CF784EDCD\"\nDEFINE_GUID(IID_IResourceMap_I, 0x6E21E72B, 0xB9B0, 0x42AE, 0xA6, 0x86, 0x98, 0x3C, 0xF7, 0x84, 0xED, 0xCD);\n\nNTSYSAPI\nHRESULT\nNTAPI\nAppContainerDeriveSidFromMoniker( // DeriveAppContainerSidFromAppContainerName\n    _In_ PCWSTR AppContainerName,\n    _Out_ PSID *AppContainerSid\n    );\n\n// Note: LookupAppContainerDisplayName (userenv.dll, ordinal 211) has the same prototype but returns 'PackageName/ContainerName'.\nNTSYSAPI\nHRESULT\nNTAPI\nAppContainerLookupMoniker(\n    _In_ PSID AppContainerSid,\n    _Out_ PWSTR *PackageFamilyName\n    );\n\nNTSYSAPI\nHRESULT\nNTAPI\nAppContainerRegisterSid(\n    _In_ PSID Sid,\n    _In_ PCWSTR AppContainerName,\n    _In_ PCWSTR DisplayName\n    );\n\nNTSYSAPI\nHRESULT\nNTAPI\nAppContainerUnregisterSid(\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nBOOL\nNTAPI\nAppContainerFreeMemory(\n    _Frees_ptr_opt_ PVOID Memory\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nPsmGetKeyFromProcess(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID KeyBuffer,\n    _Inout_ PULONG KeyLength\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nPsmGetKeyFromToken(\n    _In_ HANDLE TokenHandle,\n    _Out_ PVOID KeyBuffer,\n    _Inout_ PULONG KeyLength\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nPsmGetApplicationNameFromKey(\n    _In_ PVOID KeyBuffer,\n    _Out_ PVOID NameBuffer,\n    _Inout_ PULONG NameLength\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nPsmGetPackageFullNameFromKey(\n    _In_ PVOID KeyBuffer,\n    _Out_ PVOID NameBuffer,\n    _Inout_ PULONG NameLength\n    );\n\n// \"168EB462-775F-42AE-9111-D714B2306C2E\"\nDEFINE_GUID(CLSID_IDesktopAppXActivator_I, 0x168EB462, 0x775F, 0x42AE, 0x91, 0x11, 0xD7, 0x14, 0xB2, 0x30, 0x6C, 0x2E);\n// \"72e3a5b0-8fea-485c-9f8b-822b16dba17f\"\nDEFINE_GUID(IID_IDesktopAppXActivator1_I, 0x72e3a5b0, 0x8fea, 0x485c, 0x9f, 0x8b, 0x82, 0x2b, 0x16, 0xdb, 0xa1, 0x7f);\n// \"F158268A-D5A5-45CE-99CF-00D6C3F3FC0A\"\nDEFINE_GUID(IID_IDesktopAppXActivator2_I, 0xF158268A, 0xD5A5, 0x45CE, 0x99, 0xCF, 0x00, 0xD6, 0xC3, 0xF3, 0xFC, 0x0A);\n\ntypedef enum _DESKTOP_APPX_ACTIVATE_OPTIONS\n{\n    DAXAO_NONE = 0,\n    DAXAO_ELEVATE = 1,\n    DAXAO_NONPACKAGED_EXE = 2,\n    DAXAO_NONPACKAGED_EXE_PROCESS_TREE = 4,\n    DAXAO_NONPACKAGED_EXE_FLAGS = 6,\n    DAXAO_NO_ERROR_UI = 8,\n    DAXAO_CHECK_FOR_APPINSTALLER_UPDATES = 16,\n    DAXAO_CENTENNIAL_PROCESS = 32,\n    DAXAO_UNIVERSAL_PROCESS = 64,\n    DAXAO_WIN32ALACARTE_PROCESS = 128,\n    DAXAO_RUNTIME_BEHAVIOR_FLAGS = 224,\n    DAXAO_PARTIAL_TRUST = 256,\n    DAXAO_UNIVERSAL_CONSOLE = 512,\n    DAXAO_APP_SILO = 1024,\n    DAXAO_TRUST_LEVEL_FLAGS = 1280\n} DESKTOP_APPX_ACTIVATE_OPTIONS, *PDESKTOP_APPX_ACTIVATE_OPTIONS;\n\n// IDesktopAppXActivator\n#ifndef __IDesktopAppXActivator_INTERFACE_DEFINED__\n#define __IDesktopAppXActivator_INTERFACE_DEFINED__\n\ntypedef struct IDesktopAppXActivator IDesktopAppXActivator;\n\ntypedef struct IDesktopAppXActivatorVtbl\n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IDesktopAppXActivator, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IDesktopAppXActivator* This,\n        _In_ REFIID riid,\n        _COM_Outptr_ void** ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IDesktopAppXActivator, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IDesktopAppXActivator* This\n        );\n\n    DECLSPEC_XFGVIRT(IDesktopAppXActivator, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IDesktopAppXActivator* This\n        );\n\n    // IDesktopAppXActivator1\n    DECLSPEC_XFGVIRT(IDesktopAppXActivator, Activate)\n    HRESULT (STDMETHODCALLTYPE* Activate)(\n        _In_ IDesktopAppXActivator* This,\n        _In_ PCWSTR ApplicationUserModelId,\n        _In_ PCWSTR PackageRelativeExecutable,\n        _In_ PCWSTR Arguments,\n        _Out_ PHANDLE ProcessHandle\n        );\n\n    DECLSPEC_XFGVIRT(IDesktopAppXActivator, ActivateWithOptions)\n    HRESULT (STDMETHODCALLTYPE* ActivateWithOptions)(\n        _In_ IDesktopAppXActivator* This,\n        _In_ PCWSTR ApplicationUserModelId,\n        _In_ PCWSTR Executable,\n        _In_ PCWSTR Arguments,\n        _In_ ULONG ActivationOptions,\n        _In_opt_ ULONG ParentProcessId,\n        _Out_ PHANDLE ProcessHandle\n        );\n\n    // IDesktopAppXActivator2\n    DECLSPEC_XFGVIRT(IDesktopAppXActivator, ActivateWithOptionsAndArgs)\n    HRESULT (STDMETHODCALLTYPE* ActivateWithOptionsAndArgs)(\n        _In_ IDesktopAppXActivator* This,\n        _In_ PCWSTR ApplicationUserModelId,\n        _In_ PCWSTR Executable,\n        _In_ PCWSTR Arguments,\n        _In_opt_ ULONG ParentProcessId,\n        _In_opt_ PVOID ActivatedEventArgs,\n        _Out_ PHANDLE ProcessHandle\n        );\n\n    DECLSPEC_XFGVIRT(IDesktopAppXActivator, ActivateWithOptionsArgsWorkingDirectoryShowWindow)\n    HRESULT (STDMETHODCALLTYPE* ActivateWithOptionsArgsWorkingDirectoryShowWindow)(\n        _In_ IDesktopAppXActivator* This,\n        _In_ PCWSTR ApplicationUserModelId,\n        _In_ PCWSTR Executable,\n        _In_ PCWSTR Arguments,\n        _In_ ULONG ActivationOptions,\n        _In_opt_ ULONG ParentProcessId,\n        _In_opt_ PVOID ActivatedEventArgs,\n        _In_ PCWSTR WorkingDirectory,\n        _In_ ULONG ShowWindow,\n        _Out_ PHANDLE ProcessHandle\n        );\n\n    END_INTERFACE\n} IDesktopAppXActivatorVtbl;\n\ninterface IDesktopAppXActivator\n{\n    CONST_VTBL struct IDesktopAppXActivatorVtbl* lpVtbl;\n};\n\n#ifdef COBJMACROS\n#define IDesktopAppXActivator_QueryInterface(This,riid,ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IDesktopAppXActivator_AddRef(This) \\\n    ((This)->lpVtbl->AddRef(This))\n#define IDesktopAppXActivator_Release(This) \\\n    ((This)->lpVtbl->Release(This))\n#define IDesktopAppXActivator_Activate(This,AUMID,PRE,Args,ProcessHandle) \\\n    ((This)->lpVtbl->Activate(This,AUMID,PRE,Args,ProcessHandle))\n#define IDesktopAppXActivator_ActivateWithOptions(This,AUMID,Exe,Args,Options,ParentPid,ProcessHandle) \\\n    ((This)->lpVtbl->ActivateWithOptions(This,AUMID,Exe,Args,Options,ParentPid,ProcessHandle))\n#define IDesktopAppXActivator_ActivateWithOptionsAndArgs(This,AUMID,Exe,Args,ParentPid,EventArgs,ProcessHandle) \\\n    ((This)->lpVtbl->ActivateWithOptionsAndArgs(This,AUMID,Exe,Args,ParentPid,EventArgs,ProcessHandle))\n#define IDesktopAppXActivator_ActivateWithOptionsArgsWorkingDirectoryShowWindow(This,AUMID,Exe,Args,Options,ParentPid,EventArgs,WorkingDir,ShowWindow,ProcessHandle) \\\n    ((This)->lpVtbl->ActivateWithOptionsArgsWorkingDirectoryShowWindow(This,AUMID,Exe,Args,Options,ParentPid,EventArgs,WorkingDir,ShowWindow,ProcessHandle))\n#endif // COBJMACROS\n\n#endif // __IDesktopAppXActivator_INTERFACE_DEFINED__\n// \"ba5a92ae-bfd7-4916-854f-6b3a402b84a8\"\nDEFINE_GUID(IID_IStartMenuItemsCache, 0xba5a92ae, 0xbfd7, 0x4916, 0x85, 0x4f, 0x6b, 0x3a, 0x40, 0x2b, 0x84, 0xa8);\n\n// Note: Interface checks GetModuleFileNameW is equal L\"EXPLORER.EXE\",\n// else L\"PPISHELL.EXE\", L\"TE.PROCESSHOST.EXE\" from HKLM \"AppResolverHostProcess\"\n\n// IStartMenuItemsCache\n#ifndef __IStartMenuItemsCache_INTERFACE_DEFINED__\n#define __IStartMenuItemsCache_INTERFACE_DEFINED__\n\ntypedef struct IStartMenuItemsCache IStartMenuItemsCache;\n\ntypedef struct IStartMenuItemsCacheVtbl\n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IStartMenuItemsCache* This,\n        _In_ REFIID riid,\n        _COM_Outptr_ void** ppvObject);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IStartMenuItemsCache* This);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IStartMenuItemsCache* This);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, OnChangeNotify)\n    HRESULT (STDMETHODCALLTYPE* OnChangeNotify)(\n        _In_ IStartMenuItemsCache* This,\n        _In_ ULONG,\n        _In_ LONG,\n        _In_ PCIDLIST_ABSOLUTE,\n        _In_ PCIDLIST_ABSOLUTE);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, RegisterForNotifications)\n    HRESULT (STDMETHODCALLTYPE* RegisterForNotifications)(\n        _In_ IStartMenuItemsCache* This);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, UnregisterForNotifications)\n    HRESULT (STDMETHODCALLTYPE* UnregisterForNotifications)(\n        _In_ IStartMenuItemsCache* This);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, PauseNotifications)\n    HRESULT (STDMETHODCALLTYPE* PauseNotifications)(\n        _In_ IStartMenuItemsCache* This);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, ResumeNotifications)\n    HRESULT (STDMETHODCALLTYPE* ResumeNotifications)(\n        _In_ IStartMenuItemsCache* This);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, RegisterARNotify)\n    HRESULT (STDMETHODCALLTYPE* RegisterARNotify)(\n        _In_ IStartMenuItemsCache* This,\n        _In_ struct IAppResolverNotify* AppResolverNotify);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, RefreshCache)\n    HRESULT (STDMETHODCALLTYPE* RefreshCache)(\n        _In_ IStartMenuItemsCache* This,\n        _In_ enum START_MENU_REFRESH_CACHE_FLAGS Flags);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, ReleaseGlobalCacheObject)\n    HRESULT (STDMETHODCALLTYPE* ReleaseGlobalCacheObject)(\n        _In_ IStartMenuItemsCache* This);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, IsCacheMatchingLanguage)\n    HRESULT (STDMETHODCALLTYPE* IsCacheMatchingLanguage)(\n        _In_ IStartMenuItemsCache* This,\n        _Out_ PLONG LanguageId);\n\n    DECLSPEC_XFGVIRT(IStartMenuItemsCache, EnableAppUsageData)\n    HRESULT (STDMETHODCALLTYPE* EnableAppUsageData)(\n        _In_ IStartMenuItemsCache* This);\n\n    END_INTERFACE\n} IStartMenuItemsCacheVtbl;\n\ninterface IStartMenuItemsCache\n{\n    CONST_VTBL struct IStartMenuItemsCacheVtbl* lpVtbl;\n};\n\n#ifdef COBJMACROS\n#define IStartMenuItemsCache_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IStartMenuItemsCache_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IStartMenuItemsCache_Release(This) ((This)->lpVtbl->Release(This))\n#define IStartMenuItemsCache_OnChangeNotify(This,a,b,c,d) ((This)->lpVtbl->OnChangeNotify(This,a,b,c,d))\n#define IStartMenuItemsCache_RegisterForNotifications(This) ((This)->lpVtbl->RegisterForNotifications(This))\n#define IStartMenuItemsCache_UnregisterForNotifications(This) ((This)->lpVtbl->UnregisterForNotifications(This))\n#define IStartMenuItemsCache_PauseNotifications(This) ((This)->lpVtbl->PauseNotifications(This))\n#define IStartMenuItemsCache_ResumeNotifications(This) ((This)->lpVtbl->ResumeNotifications(This))\n#define IStartMenuItemsCache_RegisterARNotify(This,p) ((This)->lpVtbl->RegisterARNotify(This,p))\n#define IStartMenuItemsCache_RefreshCache(This,Flags) ((This)->lpVtbl->RefreshCache(This,Flags))\n#define IStartMenuItemsCache_ReleaseGlobalCacheObject(This) ((This)->lpVtbl->ReleaseGlobalCacheObject(This))\n#define IStartMenuItemsCache_IsCacheMatchingLanguage(This,pLong) ((This)->lpVtbl->IsCacheMatchingLanguage(This,pLong))\n#define IStartMenuItemsCache_EnableAppUsageData(This) ((This)->lpVtbl->EnableAppUsageData(This))\n#endif // COBJMACROS\n\n#endif // __IStartMenuItemsCache_INTERFACE_DEFINED__\n\n\n\ntypedef enum _START_MENU_APP_ITEMS_FLAGS\n{\n    SMAIF_DEFAULT = 0,\n    SMAIF_EXTENDED = 1,\n    SMAIF_USAGEINFO = 2\n} START_MENU_APP_ITEMS_FLAGS;\n\n\n// IApplicationResolver\n#ifndef __IApplicationResolver_INTERFACE_DEFINED__\n#define __IApplicationResolver_INTERFACE_DEFINED__\n\ntypedef struct IApplicationResolver IApplicationResolver;\n\ntypedef struct IApplicationResolverVtbl {\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IApplicationResolver* This,\n        _In_ REFIID riid,\n        _COM_Outptr_ void** ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IApplicationResolver* This\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IApplicationResolver* This\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, GetAppIDForShortcut)\n    HRESULT (STDMETHODCALLTYPE* GetAppIDForShortcut)(\n        _In_ IApplicationResolver* This,\n        _In_ IShellItem* psi,\n        _Outptr_ PWSTR* ppszAppID\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, GetAppIDForWindow)\n    HRESULT (STDMETHODCALLTYPE* GetAppIDForWindow)(\n        _In_ IApplicationResolver* This,\n        _In_ HWND WindowHandle,\n        _Outptr_ PWSTR* ppszAppID,\n        _Out_opt_ PBOOL pfPinningPrevented,\n        _Out_opt_ PBOOL pfExplicitAppID,\n        _Out_opt_ PBOOL pfEmbeddedShortcutValid\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, GetAppIDForProcess)\n    HRESULT (STDMETHODCALLTYPE* GetAppIDForProcess)(\n        _In_ IApplicationResolver* This,\n        _In_ ULONG dwProcessID,\n        _Outptr_ PWSTR* ppszAppID,\n        _Out_opt_ PBOOL pfPinningPrevented,\n        _Out_opt_ PBOOL pfExplicitAppID,\n        _Out_opt_ PBOOL pfEmbeddedShortcutValid\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, GetShortcutForProcess)\n    HRESULT (STDMETHODCALLTYPE* GetShortcutForProcess)(\n        _In_ IApplicationResolver* This,\n        _In_ ULONG dwProcessID,\n        _Outptr_ IShellItem** ppsi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, GetBestShortcutForAppID)\n    HRESULT (STDMETHODCALLTYPE* GetBestShortcutForAppID)(\n        _In_ IApplicationResolver* This,\n        _In_ PCWSTR pszAppID,\n        _Outptr_ IShellItem** ppsi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, GetBestShortcutAndAppIDForAppPath)\n    HRESULT (STDMETHODCALLTYPE* GetBestShortcutAndAppIDForAppPath)(\n        _In_ IApplicationResolver* This,\n        _In_ PCWSTR pszAppPath,\n        _Outptr_opt_ IShellItem** ppsi,\n        _Outptr_opt_ PWSTR* ppszAppID\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, CanPinApp)\n    HRESULT (STDMETHODCALLTYPE* CanPinApp)(\n        _In_ IApplicationResolver* This,\n        _In_ IShellItem* psi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, GetRelaunchProperties)\n    HRESULT (STDMETHODCALLTYPE* GetRelaunchProperties)(\n        _In_ IApplicationResolver* This,\n        _In_ HWND WindowHandle,\n        _Outptr_opt_result_maybenull_ PWSTR* ppszAppID,\n        _Outptr_opt_result_maybenull_ PWSTR* ppszCmdLine,\n        _Outptr_opt_result_maybenull_ PWSTR* ppszIconResource,\n        _Outptr_opt_result_maybenull_ PWSTR* ppszDisplayNameResource,\n        _Out_opt_ BOOL* pfPinnable\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, GenerateShortcutFromWindowProperties)\n    HRESULT (STDMETHODCALLTYPE* GenerateShortcutFromWindowProperties)(\n        _In_ IApplicationResolver* This,\n        _Outptr_ IShellItem** ppsi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver, GenerateShortcutFromItemProperties)\n    HRESULT (STDMETHODCALLTYPE* GenerateShortcutFromItemProperties)(\n        _In_ IApplicationResolver* This,\n        _In_ IShellItem2* psi2,\n        _Out_opt_ IShellItem** ppsi\n        );\n\n    END_INTERFACE\n} IApplicationResolverVtbl;\n\ninterface IApplicationResolver\n{\n    CONST_VTBL struct IApplicationResolverVtbl* lpVtbl;\n};\n\n#ifdef COBJMACROS\n#define IApplicationResolver_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IApplicationResolver_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IApplicationResolver_Release(This) ((This)->lpVtbl->Release(This))\n#define IApplicationResolver_GetAppIDForShortcut(This,psi,ppszAppID) ((This)->lpVtbl->GetAppIDForShortcut(This,psi,ppszAppID))\n#define IApplicationResolver_GetAppIDForWindow(This,hWnd,ppszAppID,pPrev,pExp,pEmb) ((This)->lpVtbl->GetAppIDForWindow(This,hWnd,ppszAppID,pPrev,pExp,pEmb))\n#define IApplicationResolver_GetAppIDForProcess(This,pid,ppszAppID,pPrev,pExp,pEmb) ((This)->lpVtbl->GetAppIDForProcess(This,pid,ppszAppID,pPrev,pExp,pEmb))\n#define IApplicationResolver_GetShortcutForProcess(This,pid,ppsi) ((This)->lpVtbl->GetShortcutForProcess(This,pid,ppsi))\n#define IApplicationResolver_GetBestShortcutForAppID(This,appId,ppsi) ((This)->lpVtbl->GetBestShortcutForAppID(This,appId,ppsi))\n#define IApplicationResolver_GetBestShortcutAndAppIDForAppPath(This,path,ppsi,ppszAppID) ((This)->lpVtbl->GetBestShortcutAndAppIDForAppPath(This,path,ppsi,ppszAppID))\n#define IApplicationResolver_CanPinApp(This,psi) ((This)->lpVtbl->CanPinApp(This,psi))\n#define IApplicationResolver_GetRelaunchProperties(This,hWnd,ppszAppID,ppszCmd,ppszIcon,ppszDisplay,pPinnable) ((This)->lpVtbl->GetRelaunchProperties(This,hWnd,ppszAppID,ppszCmd,ppszIcon,ppszDisplay,pPinnable))\n#define IApplicationResolver_GenerateShortcutFromWindowProperties(This,ppsi) ((This)->lpVtbl->GenerateShortcutFromWindowProperties(This,ppsi))\n#define IApplicationResolver_GenerateShortcutFromItemProperties(This,psi2,ppsi) ((This)->lpVtbl->GenerateShortcutFromItemProperties(This,psi2,ppsi))\n#endif // COBJMACROS\n\n#endif // __IApplicationResolver_INTERFACE_DEFINED__\n\n\ntypedef enum tagAPP_RESOLVER_ITEM_FILTER_FLAGS\n{\n    ARIFF_NONE = 0,\n    ARIFF_REQUIRE_PREVENT_PINNING_NOT_SET = 1,\n    ARIFF_REQUIRE_PINNABLE = 2,\n} APP_RESOLVER_ITEM_FILTER_FLAGS;\n\n\n// IApplicationResolver2\n#ifndef __IApplicationResolver2_INTERFACE_DEFINED__\n#define __IApplicationResolver2_INTERFACE_DEFINED__\n\ntypedef struct IApplicationResolver2 IApplicationResolver2;\n\ntypedef struct IApplicationResolver2Vtbl \n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IApplicationResolver2* This,\n        _In_ REFIID riid,\n        _COM_Outptr_ void** ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IApplicationResolver2* This\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IApplicationResolver2* This\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetAppIDForShortcut)\n    HRESULT (STDMETHODCALLTYPE* GetAppIDForShortcut)(\n        _In_ IApplicationResolver2* This,\n        _In_ IShellItem* psi,\n        _Outptr_ PWSTR* ppszAppID\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetAppIDForShortcutObject)\n    HRESULT (STDMETHODCALLTYPE* GetAppIDForShortcutObject)(\n        _In_ IApplicationResolver2* This,\n        _In_ IShellLinkW* psl,\n        _In_ IShellItem* psi,\n        _Outptr_ PWSTR* ppszAppID\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetAppIDForWindow)\n    HRESULT (STDMETHODCALLTYPE* GetAppIDForWindow)(\n        _In_ IApplicationResolver2* This,\n        _In_ HWND WindowHandle,\n        _Outptr_ PWSTR* ppszAppID,\n        _Out_opt_ BOOL* pfPinningPrevented,\n        _Out_opt_ BOOL* pfExplicitAppID,\n        _Out_opt_ BOOL* pfEmbeddedShortcutValid\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetAppIDForProcess)\n    HRESULT (STDMETHODCALLTYPE* GetAppIDForProcess)(\n        _In_ IApplicationResolver2* This,\n        _In_ ULONG dwProcessID,\n        _Outptr_ PWSTR* ppszAppID,\n        _Out_opt_ BOOL* pfPinningPrevented,\n        _Out_opt_ BOOL* pfExplicitAppID,\n        _Out_opt_ BOOL* pfEmbeddedShortcutValid\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetShortcutForProcess)\n    HRESULT (STDMETHODCALLTYPE* GetShortcutForProcess)(\n        _In_ IApplicationResolver2* This,\n        _In_ ULONG dwProcessID,\n        _Outptr_ IShellItem** ppsi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetBestShortcutForAppID)\n    HRESULT (STDMETHODCALLTYPE* GetBestShortcutForAppID)(\n        _In_ IApplicationResolver2* This,\n        _In_ PCWSTR pszAppID,\n        _Outptr_ IShellItem** ppsi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetBestShortcutAndAppIDForAppPath)\n    HRESULT (STDMETHODCALLTYPE* GetBestShortcutAndAppIDForAppPath)(\n        _In_ IApplicationResolver2* This,\n        _In_ PCWSTR pszAppPath,\n        _Outptr_opt_ IShellItem** ppsi,\n        _Outptr_opt_ PWSTR* ppszAppID\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, CanPinApp)\n    HRESULT (STDMETHODCALLTYPE* CanPinApp)(\n        _In_ IApplicationResolver2* This,\n        _In_ IShellItem* psi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, CanPinAppShortcut)\n    HRESULT (STDMETHODCALLTYPE* CanPinAppShortcut)(\n        _In_ IApplicationResolver2* This,\n        _In_ IShellLinkW* psl,\n        _In_ IShellItem* psi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetRelaunchProperties)\n    HRESULT (STDMETHODCALLTYPE* GetRelaunchProperties)(\n        _In_ IApplicationResolver2* This,\n        _In_ HWND WindowHandle,\n        _Outptr_opt_result_maybenull_ PWSTR* ppszAppID,\n        _Outptr_opt_result_maybenull_ PWSTR* ppszCmdLine,\n        _Outptr_opt_result_maybenull_ PWSTR* ppszIconResource,\n        _Outptr_opt_result_maybenull_ PWSTR* ppszDisplayNameResource,\n        _Out_opt_ BOOL* pfPinnable\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GenerateShortcutFromWindowProperties)\n    HRESULT (STDMETHODCALLTYPE* GenerateShortcutFromWindowProperties)(\n        _In_ IApplicationResolver2* This,\n        _Outptr_ IShellItem** ppsi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GenerateShortcutFromItemProperties)\n    HRESULT (STDMETHODCALLTYPE* GenerateShortcutFromItemProperties)(\n        _In_ IApplicationResolver2* This,\n        _In_ IShellItem2* psi2,\n        _Out_opt_ IShellItem** ppsi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetLauncherAppIDForItem)\n    HRESULT (STDMETHODCALLTYPE* GetLauncherAppIDForItem)(\n        _In_ IApplicationResolver2* This,\n        _In_ IShellItem* psi,\n        _Outptr_opt_ PWSTR* ppszAppID\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetShortcutForAppID)\n    HRESULT (STDMETHODCALLTYPE* GetShortcutForAppID)(\n        _In_ IApplicationResolver2* This,\n        _In_ PCWSTR ppszAppID,\n        _Out_opt_ IShellItem** ppsi\n        );\n\n    DECLSPEC_XFGVIRT(IApplicationResolver2, GetLauncherAppIDForItemEx)\n    HRESULT (STDMETHODCALLTYPE* GetLauncherAppIDForItemEx)(\n        _In_ IApplicationResolver2* This,\n        _In_ IShellItem* psi,\n        _In_ APP_RESOLVER_ITEM_FILTER_FLAGS Flags,\n        _Outptr_opt_ PWSTR* ppszAppID\n        );\n\n    END_INTERFACE\n} IApplicationResolver2Vtbl;\n\ninterface IApplicationResolver2 \n{ \n    CONST_VTBL struct IApplicationResolver2Vtbl* lpVtbl; \n};\n\n#ifdef COBJMACROS\n#define IApplicationResolver2_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IApplicationResolver2_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IApplicationResolver2_Release(This) ((This)->lpVtbl->Release(This))\n#define IApplicationResolver2_GetAppIDForShortcut(This,psi,ppszAppID) ((This)->lpVtbl->GetAppIDForShortcut(This,psi,ppszAppID))\n#define IApplicationResolver2_GetAppIDForShortcutObject(This,psl,psi,ppszAppID) ((This)->lpVtbl->GetAppIDForShortcutObject(This,psl,psi,ppszAppID))\n#define IApplicationResolver2_GetAppIDForWindow(This,hWnd,ppszAppID,pPrev,pExp,pEmb) ((This)->lpVtbl->GetAppIDForWindow(This,hWnd,ppszAppID,pPrev,pExp,pEmb))\n#define IApplicationResolver2_GetAppIDForProcess(This,pid,ppszAppID,pPrev,pExp,pEmb) ((This)->lpVtbl->GetAppIDForProcess(This,pid,ppszAppID,pPrev,pExp,pEmb))\n#define IApplicationResolver2_GetShortcutForProcess(This,pid,ppsi) ((This)->lpVtbl->GetShortcutForProcess(This,pid,ppsi))\n#define IApplicationResolver2_GetBestShortcutForAppID(This,appId,ppsi) ((This)->lpVtbl->GetBestShortcutForAppID(This,appId,ppsi))\n#define IApplicationResolver2_GetBestShortcutAndAppIDForAppPath(This,path,ppsi,ppszAppID) ((This)->lpVtbl->GetBestShortcutAndAppIDForAppPath(This,path,ppsi,ppszAppID))\n#define IApplicationResolver2_CanPinApp(This,psi) ((This)->lpVtbl->CanPinApp(This,psi))\n#define IApplicationResolver2_CanPinAppShortcut(This,psl,psi) ((This)->lpVtbl->CanPinAppShortcut(This,psl,psi))\n#define IApplicationResolver2_GetRelaunchProperties(This,hWnd,ppszAppID,ppszCmd,ppszIcon,ppszDisplay,pPinnable) ((This)->lpVtbl->GetRelaunchProperties(This,hWnd,ppszAppID,ppszCmd,ppszIcon,ppszDisplay,pPinnable))\n#define IApplicationResolver2_GenerateShortcutFromWindowProperties(This,ppsi) ((This)->lpVtbl->GenerateShortcutFromWindowProperties(This,ppsi))\n#define IApplicationResolver2_GenerateShortcutFromItemProperties(This,psi2,ppsi) ((This)->lpVtbl->GenerateShortcutFromItemProperties(This,psi2,ppsi))\n#define IApplicationResolver2_GetLauncherAppIDForItem(This,psi,ppszAppID) ((This)->lpVtbl->GetLauncherAppIDForItem(This,psi,ppszAppID))\n#define IApplicationResolver2_GetShortcutForAppID(This,appId,ppsi) ((This)->lpVtbl->GetShortcutForAppID(This,appId,ppsi))\n#define IApplicationResolver2_GetLauncherAppIDForItemEx(This,psi,Flags,ppszAppID) ((This)->lpVtbl->GetLauncherAppIDForItemEx(This,psi,Flags,ppszAppID))\n#endif // COBJMACROS\n\n#endif // __IApplicationResolver2_INTERFACE_DEFINED__\n\n\n// IStartMenuAppItems\n#ifndef __IStartMenuAppItems_INTERFACE_DEFINED__\n#define __IStartMenuAppItems_INTERFACE_DEFINED__\n\ntypedef struct IStartMenuAppItems IStartMenuAppItems;\n\ntypedef struct IStartMenuAppItemsVtbl\n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IStartMenuAppItems* This, \n        _In_ REFIID riid,\n        _COM_Outptr_ void** ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IStartMenuAppItems* This);\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IStartMenuAppItems* This\n    );\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems, EnumItems)\n    HRESULT (STDMETHODCALLTYPE* EnumItems)(\n        _In_ IStartMenuAppItems* This, \n        _In_ START_MENU_APP_ITEMS_FLAGS Flags,\n        _In_ REFIID riid,\n         _Outptr_ PVOID* ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems, GetItem)\n    HRESULT (STDMETHODCALLTYPE* GetItem)(\n        _In_ IStartMenuAppItems* This,\n        _In_ START_MENU_APP_ITEMS_FLAGS Flags,\n        _In_ PCWSTR AppUserModelId,\n        _In_ REFIID riid,\n        _Outptr_ PVOID* ppvObject\n        );\n\n    END_INTERFACE\n} IStartMenuAppItemsVtbl;\n\nstruct IStartMenuAppItems\n{ \n    CONST_VTBL struct IStartMenuAppItemsVtbl* lpVtbl; \n};\n\n#ifdef COBJMACROS\n#define IStartMenuAppItems_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IStartMenuAppItems_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IStartMenuAppItems_Release(This) ((This)->lpVtbl->Release(This))\n#define IStartMenuAppItems_EnumItems(This,Flags,riid,ppvObject) ((This)->lpVtbl->EnumItems(This,Flags,riid,ppvObject))\n#define IStartMenuAppItems_GetItem(This,Flags,AUMID,riid,ppvObject) ((This)->lpVtbl->GetItem(This,Flags,AUMID,riid,ppvObject))\n#endif // COBJMACROS\n\n#endif // __IStartMenuAppItems_INTERFACE_DEFINED__\n\n// IStartMenuAppItems2\n#ifndef __IStartMenuAppItems2_INTERFACE_DEFINED__\n#define __IStartMenuAppItems2_INTERFACE_DEFINED__\n\ntypedef struct IStartMenuAppItems2 IStartMenuAppItems2;\n\ntypedef struct IStartMenuAppItems2Vtbl \n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems2, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IStartMenuAppItems2* This,\n        _In_ REFIID riid,\n        _COM_Outptr_ void** ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems2, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IStartMenuAppItems2* This\n        );\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems2, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IStartMenuAppItems2* This\n        );\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems2, EnumItems)\n    HRESULT (STDMETHODCALLTYPE* EnumItems)(\n        _In_ IStartMenuAppItems2* This,\n        _In_ START_MENU_APP_ITEMS_FLAGS Flags,\n        _In_ REFIID riid,\n        _Outptr_ PVOID* ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems2, GetItem)\n    HRESULT (STDMETHODCALLTYPE* GetItem)(\n        _In_ IStartMenuAppItems2* This,\n        _In_ START_MENU_APP_ITEMS_FLAGS Flags,\n        _In_ PCWSTR AppUserModelId,\n        _In_ REFIID riid,\n        _Outptr_ PVOID* ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems2, GetItemByAppPath)\n    HRESULT (STDMETHODCALLTYPE* GetItemByAppPath)(\n        _In_ IStartMenuAppItems2* This,\n        _In_ PCWSTR AppPath,\n        _In_ REFIID riid,\n        _Outptr_ PVOID* ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IStartMenuAppItems2, EnumCachedItems)\n    HRESULT (STDMETHODCALLTYPE* EnumCachedItems)(\n        _In_ IStartMenuAppItems2* This,\n        _In_ PCIDLIST_ABSOLUTE pidl,\n        _In_ REFIID riid,\n        _Outptr_ PVOID* ppvObject\n        );\n\n    END_INTERFACE\n} IStartMenuAppItems2Vtbl;\n\ninterface IStartMenuAppItems2 \n{ \n    CONST_VTBL struct IStartMenuAppItems2Vtbl* lpVtbl;\n};\n\n#ifdef COBJMACROS\n#define IStartMenuAppItems2_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IStartMenuAppItems2_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IStartMenuAppItems2_Release(This) ((This)->lpVtbl->Release(This))\n#define IStartMenuAppItems2_EnumItems(This,Flags,riid,ppvObject) ((This)->lpVtbl->EnumItems(This,Flags,riid,ppvObject))\n#define IStartMenuAppItems2_GetItem(This,Flags,AUMID,riid,ppvObject) ((This)->lpVtbl->GetItem(This,Flags,AUMID,riid,ppvObject))\n#define IStartMenuAppItems2_GetItemByAppPath(This,AppPath,riid,ppvObject) ((This)->lpVtbl->GetItemByAppPath(This,AppPath,riid,ppvObject))\n#define IStartMenuAppItems2_EnumCachedItems(This,pidl,riid,ppvObject) ((This)->lpVtbl->EnumCachedItems(This,pidl,riid,ppvObject))\n#endif // COBJMACROS\n\n#endif // __IStartMenuAppItems2_INTERFACE_DEFINED__\n\n// IMrtResourceManager\n#ifndef __IMrtResourceManager_INTERFACE_DEFINED__\n#define __IMrtResourceManager_INTERFACE_DEFINED__\n\ntypedef struct IMrtResourceManager IMrtResourceManager;\n\ntypedef struct IMrtResourceManagerVtbl\n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(_In_ IMrtResourceManager* This, _In_ REFIID riid, _COM_Outptr_ void** ppvObject);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(_In_ IMrtResourceManager* This);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(_In_ IMrtResourceManager* This);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, Initialize)\n    HRESULT (STDMETHODCALLTYPE* Initialize)(_In_ IMrtResourceManager* This);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, InitializeForCurrentApplication)\n    HRESULT (STDMETHODCALLTYPE* InitializeForCurrentApplication)(_In_ IMrtResourceManager* This);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, InitializeForPackage)\n    HRESULT (STDMETHODCALLTYPE* InitializeForPackage)(_In_ IMrtResourceManager* This, _In_ PCWSTR PackageName);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, InitializeForFile)\n    HRESULT (STDMETHODCALLTYPE* InitializeForFile)(_In_ IMrtResourceManager* This, _In_ PCWSTR FilePath);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, GetMainResourceMap)\n    HRESULT (STDMETHODCALLTYPE* GetMainResourceMap)(_In_ IMrtResourceManager* This, _In_ REFIID riid, _Outptr_ PVOID* ppvObject);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, GetResourceMap)\n    HRESULT (STDMETHODCALLTYPE* GetResourceMap)(_In_ IMrtResourceManager* This, _In_ PCWSTR Name, _In_ REFIID riid, _Outptr_ PVOID* ppvObject);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, GetDefaultContext)\n    HRESULT (STDMETHODCALLTYPE* GetDefaultContext)(_In_ IMrtResourceManager* This, _In_ REFIID riid, _Outptr_ PVOID* ppvObject);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, GetReference)\n    HRESULT (STDMETHODCALLTYPE* GetReference)(_In_ IMrtResourceManager* This, _In_ REFIID riid, _Outptr_ PVOID* ppvObject);\n\n    DECLSPEC_XFGVIRT(IMrtResourceManager, IsResourceReference)\n    HRESULT (STDMETHODCALLTYPE* IsResourceReference)(_In_ IMrtResourceManager* This, _In_ PCWSTR Name, _Out_ BOOL* IsReference);\n\n    END_INTERFACE\n} IMrtResourceManagerVtbl;\n\ninterface IMrtResourceManager \n{ \n    CONST_VTBL struct IMrtResourceManagerVtbl* lpVtbl; \n};\n\n#ifdef COBJMACROS\n#define IMrtResourceManager_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IMrtResourceManager_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IMrtResourceManager_Release(This) ((This)->lpVtbl->Release(This))\n#define IMrtResourceManager_Initialize(This) ((This)->lpVtbl->Initialize(This))\n#define IMrtResourceManager_InitializeForCurrentApplication(This) ((This)->lpVtbl->InitializeForCurrentApplication(This))\n#define IMrtResourceManager_InitializeForPackage(This,PackageName) ((This)->lpVtbl->InitializeForPackage(This,PackageName))\n#define IMrtResourceManager_InitializeForFile(This,FilePath) ((This)->lpVtbl->InitializeForFile(This,FilePath))\n#define IMrtResourceManager_GetMainResourceMap(This,riid,ppvObject) ((This)->lpVtbl->GetMainResourceMap(This,riid,ppvObject))\n#define IMrtResourceManager_GetResourceMap(This,Name,riid,ppvObject) ((This)->lpVtbl->GetResourceMap(This,Name,riid,ppvObject))\n#define IMrtResourceManager_GetDefaultContext(This,riid,ppvObject) ((This)->lpVtbl->GetDefaultContext(This,riid,ppvObject))\n#define IMrtResourceManager_GetReference(This,riid,ppvObject) ((This)->lpVtbl->GetReference(This,riid,ppvObject))\n#define IMrtResourceManager_IsResourceReference(This,Name,IsReference) ((This)->lpVtbl->IsResourceReference(This,Name,IsReference))\n#endif // COBJMACROS\n\n#endif // __IMrtResourceManager_INTERFACE_DEFINED__\n\n\n// IResourceContext\n#ifndef __IResourceContext_INTERFACE_DEFINED__\n#define __IResourceContext_INTERFACE_DEFINED__\n\ntypedef struct IResourceContext IResourceContext;\n\ntypedef struct IResourceContextVtbl \n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IResourceContext, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IResourceContext* This,\n        _In_ REFIID riid,\n        _COM_Outptr_ void** ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IResourceContext* This\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IResourceContext* This\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, GetLanguage)\n    HRESULT (STDMETHODCALLTYPE* GetLanguage)(\n        _In_ IResourceContext* This,\n        _COM_Outptr_result_maybenull_ PWSTR* Language\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, GetHomeRegion)\n    HRESULT (STDMETHODCALLTYPE* GetHomeRegion)(\n        _In_ IResourceContext* This,\n        _COM_Outptr_result_maybenull_ PCWSTR* Region\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, GetLayoutDirection)\n    HRESULT (STDMETHODCALLTYPE* GetLayoutDirection)(\n        _In_ IResourceContext* This,\n        _Out_ ULONG* LayoutDirection\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, GetTargetSize)\n    HRESULT (STDMETHODCALLTYPE* GetTargetSize)(\n        _In_ IResourceContext* This,\n        _Out_ USHORT* TargetSize\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, GetScale)\n    HRESULT (STDMETHODCALLTYPE* GetScale)(\n        _In_ IResourceContext* This,\n        _Out_ ULONG* Scale\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, GetContrast)\n    HRESULT (STDMETHODCALLTYPE* GetContrast)(\n        _In_ IResourceContext* This,\n        _Out_ ULONG* Contrast\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, GetAlternateForm)\n    HRESULT (STDMETHODCALLTYPE* GetAlternateForm)(\n        _In_ IResourceContext* This,\n        _COM_Outptr_result_maybenull_ PCWSTR* AlternateForm\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, GetQualifierValue)\n    HRESULT (STDMETHODCALLTYPE* GetQualifierValue)(\n        _In_ IResourceContext* This,\n        _In_ PCWSTR QualifierName,\n        _COM_Outptr_result_maybenull_ PWSTR* QualifierValue\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, SetLanguage)\n    HRESULT (STDMETHODCALLTYPE* SetLanguage)(\n        _In_ IResourceContext* This,\n        _In_ PCWSTR Language\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, SetHomeRegion)\n    HRESULT (STDMETHODCALLTYPE* SetHomeRegion)(\n        _In_ IResourceContext* This,\n        _In_ PCWSTR Region\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, SetLayoutDirection)\n    HRESULT (STDMETHODCALLTYPE* SetLayoutDirection)(\n        _In_ IResourceContext* This,\n        _In_ ULONG LayoutDirection\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, SetTargetSize)\n    HRESULT (STDMETHODCALLTYPE* SetTargetSize)(\n        _In_ IResourceContext* This,\n        _In_ USHORT TargetSize\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, SetScale)\n    HRESULT (STDMETHODCALLTYPE* SetScale)(\n        _In_ IResourceContext* This,\n        _In_ ULONG Scale\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, SetContrast)\n    HRESULT (STDMETHODCALLTYPE* SetContrast)(\n        _In_ IResourceContext* This,\n        _In_ ULONG Contrast\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, SetAlternateForm)\n    HRESULT (STDMETHODCALLTYPE* SetAlternateForm)(\n        _In_ IResourceContext* This,\n        _In_ PCWSTR AlternateForm\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, SetQualifierValue)\n    HRESULT (STDMETHODCALLTYPE* SetQualifierValue)(\n        _In_ IResourceContext* This,\n        _In_ PCWSTR QualifierName,\n        _In_ PCWSTR QualifierValue\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, TrySetQualifierValue)\n    HRESULT (STDMETHODCALLTYPE* TrySetQualifierValue)(\n        _In_ IResourceContext* This,\n        _In_ PCWSTR QualifierName,\n        _In_ LPCWSTR QualifierValue,\n        _Out_ HRESULT* Result\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, Reset)\n    HRESULT (STDMETHODCALLTYPE* Reset)(\n        _In_ IResourceContext* This\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, ResetQualifierValue)\n    HRESULT (STDMETHODCALLTYPE* ResetQualifierValue)(\n        _In_ IResourceContext* This,\n        _In_ LPCWSTR QualifierName\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, Clone)\n    HRESULT (STDMETHODCALLTYPE* Clone)(\n        _In_ IResourceContext* This,\n        _COM_Outptr_ IResourceContext** CloneContext\n        );\n\n    DECLSPEC_XFGVIRT(IResourceContext, OverrideToMatch)\n    HRESULT (STDMETHODCALLTYPE* OverrideToMatch)(\n        _In_ IResourceContext* This,\n        _In_ struct IResourceCandidate* Candidate\n        );\n\n    END_INTERFACE\n} IResourceContextVtbl;\n\ninterface IResourceContext \n{ \n    CONST_VTBL struct IResourceContextVtbl* lpVtbl; \n};\n\n#ifdef COBJMACROS\n#define IResourceContext_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IResourceContext_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IResourceContext_Release(This) ((This)->lpVtbl->Release(This))\n#define IResourceContext_GetLanguage(This,ppLang) ((This)->lpVtbl->GetLanguage(This,ppLang))\n#define IResourceContext_GetHomeRegion(This,ppRegion) ((This)->lpVtbl->GetHomeRegion(This,ppRegion))\n#define IResourceContext_GetLayoutDirection(This,pDir) ((This)->lpVtbl->GetLayoutDirection(This,pDir))\n#define IResourceContext_GetTargetSize(This,pSize) ((This)->lpVtbl->GetTargetSize(This,pSize))\n#define IResourceContext_GetScale(This,pScale) ((This)->lpVtbl->GetScale(This,pScale))\n#define IResourceContext_GetContrast(This,pContrast) ((This)->lpVtbl->GetContrast(This,pContrast))\n#define IResourceContext_GetAlternateForm(This,ppForm) ((This)->lpVtbl->GetAlternateForm(This,ppForm))\n#define IResourceContext_GetQualifierValue(This,key,ppVal) ((This)->lpVtbl->GetQualifierValue(This,key,ppVal))\n#define IResourceContext_SetLanguage(This,val) ((This)->lpVtbl->SetLanguage(This,val))\n#define IResourceContext_SetHomeRegion(This,val) ((This)->lpVtbl->SetHomeRegion(This,val))\n#define IResourceContext_SetLayoutDirection(This,val) ((This)->lpVtbl->SetLayoutDirection(This,val))\n#define IResourceContext_SetTargetSize(This,val) ((This)->lpVtbl->SetTargetSize(This,val))\n#define IResourceContext_SetScale(This,val) ((This)->lpVtbl->SetScale(This,val))\n#define IResourceContext_SetContrast(This,val) ((This)->lpVtbl->SetContrast(This,val))\n#define IResourceContext_SetAlternateForm(This,val) ((This)->lpVtbl->SetAlternateForm(This,val))\n#define IResourceContext_SetQualifierValue(This,key,val) ((This)->lpVtbl->SetQualifierValue(This,key,val))\n#define IResourceContext_TrySetQualifierValue(This,key,val,pHr) ((This)->lpVtbl->TrySetQualifierValue(This,key,val,pHr))\n#define IResourceContext_Reset(This) ((This)->lpVtbl->Reset(This))\n#define IResourceContext_ResetQualifierValue(This,key) ((This)->lpVtbl->ResetQualifierValue(This,key))\n#define IResourceContext_Clone(This,ppCtx) ((This)->lpVtbl->Clone(This,ppCtx))\n#define IResourceContext_OverrideToMatch(This,pCand) ((This)->lpVtbl->OverrideToMatch(This,pCand))\n#endif // COBJMACROS\n\n#endif // __IResourceContext_INTERFACE_DEFINED__\n\n\n// IResourceMap\n#ifndef __IResourceMap_INTERFACE_DEFINED__\n#define __IResourceMap_INTERFACE_DEFINED__\n\ntypedef struct IResourceMap IResourceMap;\n\ntypedef struct IResourceMapVtbl \n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IResourceMap, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IResourceMap* This,\n        _In_ REFIID riid,\n        _COM_Outptr_ void** ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IResourceMap* This\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IResourceMap* This\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetUri)\n    HRESULT (STDMETHODCALLTYPE* GetUri)(\n        _In_ IResourceMap* This,\n        _COM_Outptr_ PWSTR* UriString\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetSubtree)\n    HRESULT (STDMETHODCALLTYPE* GetSubtree)(\n        _In_ IResourceMap* This,\n        _In_ PCWSTR* Name,\n        _COM_Outptr_ IResourceMap** ResourceMap\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetString)\n    HRESULT (STDMETHODCALLTYPE* GetString)(\n        _In_ IResourceMap* This,\n        _In_ PCWSTR Key,\n        _COM_Outptr_ PWSTR* Value\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetStringForContext)\n    HRESULT (STDMETHODCALLTYPE* GetStringForContext)(\n        _In_ IResourceMap* This,\n        _In_ IResourceContext* Context,\n        _In_ PCWSTR Key,\n        _COM_Outptr_ PWSTR* Value\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetFilePath)\n    HRESULT (STDMETHODCALLTYPE* GetFilePath)(\n        _In_ IResourceMap* This,\n        _In_ PCWSTR Key,\n        _COM_Outptr_ PWSTR* Value\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetFilePathForContext)\n    HRESULT (STDMETHODCALLTYPE* GetFilePathForContext)(\n        _In_ IResourceMap* This,\n        _In_ IResourceContext* Context,\n        _In_ PCWSTR Key,\n        _COM_Outptr_ PWSTR* Value\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetNamedResourceCount)\n    HRESULT (STDMETHODCALLTYPE* GetNamedResourceCount)(\n        _In_ IResourceMap* This,\n        _Out_ PULONG Count\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetNamedResourceUri)\n    HRESULT (STDMETHODCALLTYPE* GetNamedResourceUri)(\n        _In_ IResourceMap* This,\n        _In_ ULONG Index,\n        _COM_Outptr_ PWSTR* UriString\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetNamedResource)\n    HRESULT (STDMETHODCALLTYPE* GetNamedResource)(\n        _In_ IResourceMap* This,\n        _In_ PCWSTR,\n        _In_ REFIID riid,\n        _Outptr_ PVOID* ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetFullyQualifiedReference)\n    HRESULT (STDMETHODCALLTYPE* GetFullyQualifiedReference)(\n        _In_ IResourceMap* This,\n        _In_ LPCWSTR,\n        _In_ LPCWSTR,\n        _COM_Outptr_ PWSTR*\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetFilePathByUri)\n    HRESULT (STDMETHODCALLTYPE* GetFilePathByUri)(\n        _In_ IResourceMap* This,\n        _In_ IUri* Uri,\n        _COM_Outptr_ PWSTR* Path\n        );\n\n    DECLSPEC_XFGVIRT(IResourceMap, GetFilePathForContextByUri)\n    HRESULT (STDMETHODCALLTYPE* GetFilePathForContextByUri)(\n        _In_ IResourceMap* This,\n        _In_ IResourceContext* Context,\n        _In_ IUri* Uri,\n        _COM_Outptr_ PWSTR* Path\n        );\n\n    END_INTERFACE\n} IResourceMapVtbl;\n\ninterface IResourceMap \n{ \n    CONST_VTBL struct IResourceMapVtbl* lpVtbl; \n};\n\n#ifdef COBJMACROS\n#define IResourceMap_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IResourceMap_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IResourceMap_Release(This) ((This)->lpVtbl->Release(This))\n#define IResourceMap_GetUri(This,ppUri) ((This)->lpVtbl->GetUri(This,ppUri))\n#define IResourceMap_GetSubtree(This,pName,ppMap) ((This)->lpVtbl->GetSubtree(This,pName,ppMap))\n#define IResourceMap_GetString(This,key,ppVal) ((This)->lpVtbl->GetString(This,key,ppVal))\n#define IResourceMap_GetStringForContext(This,ctx,key,ppVal) ((This)->lpVtbl->GetStringForContext(This,ctx,key,ppVal))\n#define IResourceMap_GetFilePath(This,key,ppVal) ((This)->lpVtbl->GetFilePath(This,key,ppVal))\n#define IResourceMap_GetFilePathForContext(This,ctx,key,ppVal) ((This)->lpVtbl->GetFilePathForContext(This,ctx,key,ppVal))\n#define IResourceMap_GetNamedResourceCount(This,pCount) ((This)->lpVtbl->GetNamedResourceCount(This,pCount))\n#define IResourceMap_GetNamedResourceUri(This,index,ppName) ((This)->lpVtbl->GetNamedResourceUri(This,index,ppName))\n#define IResourceMap_GetNamedResource(This,name,riid,ppv) ((This)->lpVtbl->GetNamedResource(This,name,riid,ppv))\n#define IResourceMap_GetFullyQualifiedReference(This,a,b,ppRef) ((This)->lpVtbl->GetFullyQualifiedReference(This,a,b,ppRef))\n#define IResourceMap_GetFilePathByUri(This,pUri,ppPath) ((This)->lpVtbl->GetFilePathByUri(This,pUri,ppPath))\n#define IResourceMap_GetFilePathForContextByUri(This,ctx,pUri,ppPath) ((This)->lpVtbl->GetFilePathForContextByUri(This,ctx,pUri,ppPath))\n#endif // COBJMACROS\n\n#endif // __IResourceMap_INTERFACE_DEFINED__\n\n// Note: Documented PKEY_AppUserModel_XYZ keys can be found in propkey.h\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_ID, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 5);\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_HostEnvironment, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 14);\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_PackageInstallPath, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 15);\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_PackageFamilyName, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 17);\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_ParentID, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 19);\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_PackageFullName, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 21);\n// PKEY_AppUserModel_ExcludeFromShowInNewInstall {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 8\n//3 PKEY_AppUserModel_IsDestListSeparator {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 6\n//4 PKEY_AppUserModel_IsDualMode {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 11\n//5 PKEY_AppUserModel_PreventPinning {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 9\n//6 PKEY_AppUserModel_RelaunchCommand {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 2\n//7 PKEY_AppUserModel_RelaunchDisplayNameResource {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 4\n//8 PKEY_AppUserModel_RelaunchIconResource {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 3\n//9 PKEY_AppUserModel_StartPinOption {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 12\n//10 PKEY_AppUserModel_ToastActivatorCLSID {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 26\n//12 PKEY_AppUserModel_RecordState {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 16\n//14 PKEY_AppUserModel_DestListProvidedTitle {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 27\n//15 PKEY_AppUserModel_DestListProvidedDescription {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 28\n//18 PKEY_AppUserModel_Relevance {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 13\n//19 PKEY_AppUserModel_PackageRelativeApplicationID {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 22\n//20 PKEY_AppUserModel_ExcludedFromLauncher {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 23\n//21 PKEY_AppUserModel_DestListLogoUri {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 29\n//22 PKEY_AppUserModel_ActivationContext {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 20\n//24 PKEY_AppUserModel_BestShortcut {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 10\n//25 PKEY_AppUserModel_IsDestListLink {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 7\n//26 PKEY_AppUserModel_InstalledBy {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 18\n//27 PKEY_AppUserModel_RunFlags {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 25\n//28 PKEY_AppUserModel_DestListProvidedGroupName {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 30\nDEFINE_PROPERTYKEY(PKEY_Tile_SmallLogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 2);\nDEFINE_PROPERTYKEY(PKEY_Tile_Background, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 4);\nDEFINE_PROPERTYKEY(PKEY_Tile_Foreground, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 5);\nDEFINE_PROPERTYKEY(PKEY_Tile_LongDisplayName, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 11);\nDEFINE_PROPERTYKEY(PKEY_Tile_Flags, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 14);\nDEFINE_PROPERTYKEY(PKEY_Tile_SuiteDisplayName, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 16);\nDEFINE_PROPERTYKEY(PKEY_Tile_SuiteSortName, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 17);\nDEFINE_PROPERTYKEY(PKEY_Tile_DisplayNameLanguage, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 18);\nDEFINE_PROPERTYKEY(PKEY_Tile_BadgeLogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 15);\nDEFINE_PROPERTYKEY(PKEY_Tile_Square150x150LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 12);\nDEFINE_PROPERTYKEY(PKEY_Tile_Wide310x150LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 13);\nDEFINE_PROPERTYKEY(PKEY_Tile_Square310x310LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 19);\nDEFINE_PROPERTYKEY(PKEY_Tile_Square70x70LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 20);\nDEFINE_PROPERTYKEY(PKEY_Tile_FencePost, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 21);\nDEFINE_PROPERTYKEY(PKEY_Tile_InstallProgress, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 22);\nDEFINE_PROPERTYKEY(PKEY_Tile_EncodedTargetPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 23);\n\n// Immersive PLM task support\n\n// \"07fc2b94-5285-417e-8ac3-c2ce5240b0fa\"\nDEFINE_GUID(CLSID_OSTaskCompletion_I, 0x07fc2b94, 0x5285, 0x417e, 0x8a, 0xc3, 0xc2, 0xce, 0x52, 0x40, 0xb0, 0xfa);\n// \"c7e40572-c36a-43ea-9a40-f3b168da5558\"\nDEFINE_GUID(IID_IOSTaskCompletion_I, 0xc7e40572, 0xc36a, 0x43ea, 0x9a, 0x40, 0xf3, 0xb1, 0x68, 0xda, 0x55, 0x58);\n\ntypedef enum _PLM_TASKCOMPLETION_CATEGORY_FLAGS\n{\n    PT_TC_NONE = 0,\n    PT_TC_PBM = 1,\n    PT_TC_FILEOPENPICKER = 2,\n    PT_TC_SHARING = 4,\n    PT_TC_PRINTING = 8,\n    PT_TC_GENERIC = 16,\n    PT_TC_CAMERA_DCA = 32,\n    PT_TC_PRINTER_DCA = 64,\n    PT_TC_PLAYTO = 128,\n    PT_TC_FILESAVEPICKER = 256,\n    PT_TC_CONTACTPICKER = 512,\n    PT_TC_CACHEDFILEUPDATER_LOCAL = 1024,\n    PT_TC_CACHEDFILEUPDATER_REMOTE = 2048,\n    PT_TC_ERROR_REPORT = 8192,\n    PT_TC_DATA_PACKAGE = 16384,\n    PT_TC_CRASHDUMP = 0x10000,\n    PT_TC_STREAMEDFILE = 0x20000,\n    PT_TC_PBM_COMMUNICATION = 0x80000,\n    PT_TC_HOSTEDAPPLICATION = 0x100000,\n    PT_TC_MEDIA_CONTROLS_ACTIVE = 0x200000,\n    PT_TC_EMPTYHOST = 0x400000,\n    PT_TC_SCANNING = 0x800000,\n    PT_TC_ACTIONS = 0x1000000,\n    PT_TC_KERNEL_MODE = 0x20000000,\n    PT_TC_REALTIMECOMM = 0x40000000,\n    PT_TC_IGNORE_NAV_LEVEL_FOR_CS = 0x80000000\n} PLM_TASKCOMPLETION_CATEGORY_FLAGS;\n\n// IOSTaskCompletion\n#ifndef __IOSTaskCompletion_INTERFACE_DEFINED__\n#define __IOSTaskCompletion_INTERFACE_DEFINED__\n\ntypedef struct IOSTaskCompletion IOSTaskCompletion;\n\ntypedef struct IOSTaskCompletionVtbl \n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IOSTaskCompletion* This,\n        _In_ REFIID riid,\n        _COM_Outptr_ void** ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IOSTaskCompletion* This\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IOSTaskCompletion* This\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion, BeginTask)\n    HRESULT (STDMETHODCALLTYPE* BeginTask)(\n        _In_ IOSTaskCompletion* This,\n        _In_ ULONG ProcessId,\n        _In_ PLM_TASKCOMPLETION_CATEGORY_FLAGS Flags\n    );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion, BeginTaskByHandle)\n    HRESULT (STDMETHODCALLTYPE* BeginTaskByHandle)(\n        _In_ IOSTaskCompletion* This,\n        _In_ HANDLE ProcessHandle,\n        _In_ PLM_TASKCOMPLETION_CATEGORY_FLAGS Flags\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion, EndTask)\n    HRESULT (STDMETHODCALLTYPE* EndTask)(\n        _In_ IOSTaskCompletion* This\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion, ValidateStreamedFileTaskCompletionUsage)\n    ULONG (STDMETHODCALLTYPE* ValidateStreamedFileTaskCompletionUsage)(\n        _In_ IOSTaskCompletion* This,\n        _In_ HANDLE ProcessHandle,\n        _In_ ULONG ProcessId\n        );\n\n    END_INTERFACE\n} IOSTaskCompletionVtbl;\n\ninterface IOSTaskCompletion \n{ \n    CONST_VTBL struct IOSTaskCompletionVtbl* lpVtbl;\n};\n\n#ifdef COBJMACROS\n#define IOSTaskCompletion_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IOSTaskCompletion_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IOSTaskCompletion_Release(This) ((This)->lpVtbl->Release(This))\n#define IOSTaskCompletion_BeginTask(This,pid,Flags) ((This)->lpVtbl->BeginTask(This,pid,Flags))\n#define IOSTaskCompletion_BeginTaskByHandle(This,hProc,Flags) ((This)->lpVtbl->BeginTaskByHandle(This,hProc,Flags))\n#define IOSTaskCompletion_EndTask(This) ((This)->lpVtbl->EndTask(This))\n#define IOSTaskCompletion_ValidateStreamedFileTaskCompletionUsage(This,hProc,pid) ((This)->lpVtbl->ValidateStreamedFileTaskCompletionUsage(This,hProc,pid))\n#endif // COBJMACROS\n\n#endif // __IOSTaskCompletion_INTERFACE_DEFINED__\n\n// IOSTaskCompletion2\n#ifndef __IOSTaskCompletion2_INTERFACE_DEFINED__\n#define __IOSTaskCompletion2_INTERFACE_DEFINED__\n\ntypedef struct IOSTaskCompletion2 IOSTaskCompletion2;\n\ntypedef struct IOSTaskCompletion2Vtbl \n{\n    BEGIN_INTERFACE\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion2, QueryInterface)\n    HRESULT (STDMETHODCALLTYPE* QueryInterface)(\n        _In_ IOSTaskCompletion2* This,\n        _In_ REFIID riid,\n        _COM_Outptr_ PVOID* ppvObject\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion2, AddRef)\n    ULONG (STDMETHODCALLTYPE* AddRef)(\n        _In_ IOSTaskCompletion2* This\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion2, Release)\n    ULONG (STDMETHODCALLTYPE* Release)(\n        _In_ IOSTaskCompletion2* This\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion2, InternalGetTrustLevelStatic)\n    HRESULT (STDMETHODCALLTYPE* InternalGetTrustLevelStatic)(\n        _In_ IOSTaskCompletion2* This\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion2, InternalGetTrustLevelStatic2)\n    HRESULT (STDMETHODCALLTYPE* InternalGetTrustLevelStatic2)(\n        _In_ IOSTaskCompletion2* This\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion2, EndAllTasksAndWait)\n    HRESULT (STDMETHODCALLTYPE* EndAllTasksAndWait)(\n        _In_ IOSTaskCompletion2* This\n        );\n\n    DECLSPEC_XFGVIRT(IOSTaskCompletion2, BeginTaskByHandleEx)\n    HRESULT (STDMETHODCALLTYPE* BeginTaskByHandleEx)(\n        _In_ IOSTaskCompletion2* This,\n        _In_ HANDLE ProcessHandle,\n        _In_ PLM_TASKCOMPLETION_CATEGORY_FLAGS Flags,\n        _In_ enum PLM_TASKCOMPLETION_BEGIN_TASK_FLAGS TaskFlags\n        );\n\n    END_INTERFACE\n} IOSTaskCompletion2Vtbl;\n\ninterface IOSTaskCompletion2 \n{ \n    CONST_VTBL struct IOSTaskCompletion2Vtbl* lpVtbl;\n};\n\n#ifdef COBJMACROS\n#define IOSTaskCompletion2_QueryInterface(This,riid,ppvObject) ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IOSTaskCompletion2_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IOSTaskCompletion2_Release(This) ((This)->lpVtbl->Release(This))\n#define IOSTaskCompletion2_InternalGetTrustLevelStatic(This) ((This)->lpVtbl->InternalGetTrustLevelStatic(This))\n#define IOSTaskCompletion2_InternalGetTrustLevelStatic2(This) ((This)->lpVtbl->InternalGetTrustLevelStatic2(This))\n#define IOSTaskCompletion2_EndAllTasksAndWait(This) ((This)->lpVtbl->EndAllTasksAndWait(This))\n#define IOSTaskCompletion2_BeginTaskByHandleEx(This,hProc,Flags,TaskFlags) ((This)->lpVtbl->BeginTaskByHandleEx(This,hProc,Flags,TaskFlags))\n#endif // COBJMACROS\n\n#endif // __IOSTaskCompletion2_INTERFACE_DEFINED__\n\n// EDP\n\ntypedef enum _EDP_CONTEXT_STATES\n{\n    EDP_CONTEXT_NONE = 0,\n    EDP_CONTEXT_IS_EXEMPT = 1,\n    EDP_CONTEXT_IS_ENLIGHTENED = 2,\n    EDP_CONTEXT_IS_UNENLIGHTENED_ALLOWED = 4,\n    EDP_CONTEXT_IS_PERMISSIVE = 8,\n    EDP_CONTEXT_IS_COPY_EXEMPT = 16,\n    EDP_CONTEXT_IS_DENIED = 32,\n} EDP_CONTEXT_STATES;\n\ntypedef struct _EDP_CONTEXT\n{\n    EDP_CONTEXT_STATES contextStates;\n    ULONG allowedEnterpriseIdCount;\n    PWSTR enterpriseIdForUIEnforcement;\n    WCHAR allowedEnterpriseIds[1];\n} EDP_CONTEXT, *PEDP_CONTEXT;\n\nstatic HRESULT (WINAPI* EdpGetContextForWindow_I)(\n    _In_ HWND WindowHandle,\n    _Out_ PEDP_CONTEXT* EdpContext\n    ) = NULL;\n\nstatic HRESULT (WINAPI* EdpGetContextForProcess_I)(\n    _In_ ULONG ProcessId,\n    _Out_ PEDP_CONTEXT* EdpContext\n    ) = NULL;\n\nstatic VOID (WINAPI* EdpFreeContext_I)(\n    _In_ PEDP_CONTEXT EdpContext\n    ) = NULL;\n\n#endif\n"
  },
  {
    "path": "phlib/include/bcd.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2021\n *\n */\n\n#ifndef _PH_BCD_H\n#define _PH_BCD_H\n\nEXTERN_C_START\n\nNTSTATUS PhBcdOpenObject(\n    _In_ HANDLE StoreHandle,\n    _In_ PCGUID Identifier,\n    _Out_ PHANDLE ObjectHandle\n    );\n\nNTSTATUS PhBcdGetElementData(\n    _In_ HANDLE ObjectHandle,\n    _In_ ULONG ElementType,\n    _Out_writes_bytes_opt_(*BufferSize) PVOID Buffer,\n    _Inout_ PULONG BufferSize\n    );\n\nNTSTATUS PhBcdSetElementData(\n    _In_ HANDLE ObjectHandle,\n    _In_ ULONG ElementType,\n    _In_reads_bytes_opt_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize\n    );\n\nNTSTATUS PhBcdSetAdvancedOptionsOneTime(\n    _In_ BOOLEAN Enable\n    );\n\nNTSTATUS PhBcdSetBootApplicationOneTime(\n    _In_ PCGUID Identifier,\n    _In_opt_ BOOLEAN UpdateOneTimeFirmware\n    );\n\nNTSTATUS PhBcdSetFirmwareBootApplicationOneTime(\n    _In_ PCGUID Identifier\n    );\n\ntypedef struct _PH_BCD_OBJECT_LIST\n{\n    GUID ObjectGuid;\n    PPH_STRING ObjectName;\n} PH_BCD_OBJECT_LIST, *PPH_BCD_OBJECT_LIST;\n\nPPH_LIST PhBcdQueryFirmwareBootApplicationList(\n    VOID\n    );\n\nPPH_LIST PhBcdQueryBootApplicationList(\n    _In_ BOOLEAN EnumerateAllObjects\n    );\n\nVOID PhBcdDestroyBootApplicationList(\n    _In_ PPH_LIST ObjectApplicationList\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/circbuf.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2025\n *\n */\n\n#ifndef _PH_CIRCBUF_H\n#define _PH_CIRCBUF_H\n\n#define PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n\n#undef T\n#define T ULONG\n#include \"circbuf_h.h\"\n\n#undef T\n#define T ULONG64\n#include \"circbuf_h.h\"\n\n#undef T\n#define T PVOID\n#include \"circbuf_h.h\"\n\n#undef T\n#define T SIZE_T\n#include \"circbuf_h.h\"\n\n#undef T\n#define T FLOAT\n#include \"circbuf_h.h\"\n\n#undef T\n#define T DOUBLE\n#include \"circbuf_h.h\"\n\n#undef T\n\n#endif\n"
  },
  {
    "path": "phlib/include/circbuf_h.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#ifdef T\n\n#include <templ.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct T___(_PH_CIRCULAR_BUFFER, T)\n{\n    ULONG Size;\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    ULONG SizeMinusOne;\n#endif\n    ULONG Count;\n    LONG Index;\n    T *Data;\n} T___(PH_CIRCULAR_BUFFER, T), *T___(PPH_CIRCULAR_BUFFER, T);\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhInitializeCircularBuffer, T)(\n    _Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ ULONG Size\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhDeleteCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhResizeCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ ULONG NewSize\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhClearCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhCopyCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _Out_writes_(Count) T *Destination,\n    _In_ ULONG Count\n    );\n\nFORCEINLINE T T___(PhGetItemCircularBuffer, T)(\n    _In_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ LONG Index\n    )\n{\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    return Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne];\n#else\n    ULONG size;\n\n    size = Buffer->Size;\n    // Modulo is dividend-based.\n    return Buffer->Data[(((Buffer->Index + Index) % size) + size) % size];\n#endif\n}\n\nFORCEINLINE VOID T___(PhSetItemCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ LONG Index,\n    _In_ T Value\n    )\n{\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne] = Value;\n#else\n    ULONG size;\n\n    size = Buffer->Size;\n    Buffer->Data[(((Buffer->Index + Index) % size) + size) % size] = Value;\n#endif\n}\n\nFORCEINLINE VOID T___(PhAddItemCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ T Value\n    )\n{\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    Buffer->Data[Buffer->Index = ((Buffer->Index - 1) & Buffer->SizeMinusOne)] = Value;\n#else\n    ULONG size;\n\n    size = Buffer->Size;\n    Buffer->Data[Buffer->Index = (((Buffer->Index - 1) % size) + size) % size] = Value;\n#endif\n\n    if (Buffer->Count < Buffer->Size)\n        Buffer->Count++;\n}\n\nFORCEINLINE T T___(PhAddItemCircularBuffer2, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ T Value\n    )\n{\n    LONG index;\n    T oldValue;\n\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    index = ((Buffer->Index - 1) & Buffer->SizeMinusOne);\n#else\n    ULONG size;\n\n    size = Buffer->Size;\n    index = (((Buffer->Index - 1) % size) + size) % size;\n#endif\n\n    Buffer->Index = index;\n    oldValue = Buffer->Data[index];\n    Buffer->Data[index] = Value;\n\n    if (Buffer->Count < Buffer->Size)\n        Buffer->Count++;\n\n    return oldValue;\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/colorbox.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2021\n *\n */\n\n#ifndef _PH_COLORBOX_H\n#define _PH_COLORBOX_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_COLORBOX_CLASSNAME L\"PhColorBox\"\n\nPHLIBAPI\nRTL_ATOM\nNTAPI\nPhColorBoxInitialization(\n    VOID\n    );\n\n#define CBCM_SETCOLOR (WM_APP + 1501)\n#define CBCM_GETCOLOR (WM_APP + 1502)\n#define CBCM_THEMESUPPORT (WM_APP + 1503)\n\n#define ColorBox_SetColor(hWnd, Color) \\\n    SendMessage((hWnd), CBCM_SETCOLOR, (WPARAM)(Color), 0)\n\n#define ColorBox_GetColor(hWnd) \\\n    ((COLORREF)SendMessage((hWnd), CBCM_GETCOLOR, 0, 0))\n\n#define ColorBox_ThemeSupport(hWnd, Enable) \\\n    SendMessage((hWnd), CBCM_THEMESUPPORT, (WPARAM)(Enable), 0);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/cpysave.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2019\n *\n */\n\n#ifndef _PH_CPYSAVE_H\n#define _PH_CPYSAVE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_EXPORT_MODE_TABS 0\n#define PH_EXPORT_MODE_SPACES 1\n#define PH_EXPORT_MODE_CSV 2\n\nPHLIBAPI\nVOID PhaCreateTextTable(\n    _Out_ PPH_STRING ***Table,\n    _In_ ULONG Rows,\n    _In_ ULONG Columns\n    );\n\nPHLIBAPI\nPPH_LIST PhaFormatTextTable(\n    _In_ PPH_STRING **Table,\n    _In_ ULONG Rows,\n    _In_ ULONG Columns,\n    _In_ ULONG Mode\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhMapDisplayIndexTreeNew(\n    _In_ HWND TreeNewHandle,\n    _Out_opt_ PULONG *DisplayToId,\n    _Out_opt_ PWSTR **DisplayToText,\n    _Out_ PULONG NumberOfColumns\n    );\n\nPHLIBAPI\nPPH_STRING PhGetTreeNewText(\n    _In_ HWND TreeNewHandle,\n    _Reserved_ ULONG Reserved\n    );\n\nPHLIBAPI\nPPH_LIST PhGetGenericTreeNewLines(\n    _In_ HWND TreeNewHandle,\n    _In_ ULONG Mode\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhaMapDisplayIndexListView(\n    _In_ HWND ListViewHandle,\n    _Out_writes_(Count) PULONG DisplayToId,\n    _Out_writes_opt_(Count) PPH_STRING *DisplayToText,\n    _In_ ULONG Count,\n    _Out_ PULONG NumberOfColumns\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetListViewItemText(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetListViewSelectedItemText(\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhaGetListViewItemText(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetListViewText(\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nPPH_LIST PhGetListViewLines(\n    _In_ HWND ListViewHandle,\n    _In_ ULONG Mode\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/dltmgr.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *\n */\n\n#ifndef _PH_DLTMGR_H\n#define _PH_DLTMGR_H\n\ntypedef struct _PH_SINGLE_DELTA\n{\n    FLOAT Value;\n    FLOAT Delta;\n} PH_SINGLE_DELTA, *PPH_SINGLE_DELTA;\n\ntypedef struct _PH_DOUBLE_DELTA\n{\n    DOUBLE Value;\n    DOUBLE Delta;\n} PH_DOUBLE_DELTA, *PPH_DOUBLE_DELTA;\n\ntypedef struct _PH_UINT32_DELTA\n{\n    ULONG Value;\n    ULONG Delta;\n} PH_UINT32_DELTA, *PPH_UINT32_DELTA;\n\ntypedef struct _PH_UINT64_DELTA\n{\n    ULONG64 Value;\n    ULONG64 Delta;\n} PH_UINT64_DELTA, *PPH_UINT64_DELTA;\n\ntypedef struct _PH_UINTPTR_DELTA\n{\n    ULONG_PTR Value;\n    ULONG_PTR Delta;\n} PH_UINTPTR_DELTA, *PPH_UINTPTR_DELTA;\n\n#define PhInitializeDelta(DltMgr) \\\n    ((DltMgr)->Value = 0, (DltMgr)->Delta = 0)\n\n#define PhUpdateDelta(DltMgr, NewValue) \\\n    ((DltMgr)->Delta = (NewValue) - (DltMgr)->Value, \\\n    (DltMgr)->Value = (NewValue), (DltMgr)->Delta)\n\n#define PH_SINGLE_DELTA_INIT { 0.0F, 0.0F }\n#define PH_DOUBLE_DELTA_INIT { 0.0, 0.0 }\n#define PH_UINT32_DELTA_INIT { 0UL, 0UL }\n#define PH_UINT64_DELTA_INIT { 0ULL, 0ULL }\n#define PH_UINTPTR_DELTA_INIT { 0, 0 }\n\n#endif\n"
  },
  {
    "path": "phlib/include/dspick.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#ifndef _PH_DSPICK_H\n#define _PH_DSPICK_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_DSPICK_MULTISELECT 0x1\n\ntypedef struct _PH_DSPICK_OBJECT\n{\n    PPH_STRING Name;\n    PSID Sid;\n} PH_DSPICK_OBJECT, *PPH_DSPICK_OBJECT;\n\ntypedef struct _PH_DSPICK_OBJECTS\n{\n    ULONG NumberOfObjects;\n    PH_DSPICK_OBJECT Objects[1];\n} PH_DSPICK_OBJECTS, *PPH_DSPICK_OBJECTS;\n\nPHLIBAPI\nVOID PhFreeDsObjectPickerDialog(\n    _In_ PVOID PickerDialog\n    );\n\nPHLIBAPI\nPVOID PhCreateDsObjectPickerDialog(\n    _In_ ULONG Flags\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN PhShowDsObjectPickerDialog(\n    _In_ HWND hWnd,\n    _In_ PVOID PickerDialog,\n    _Out_ PPH_DSPICK_OBJECTS *Objects\n    );\n\nPHLIBAPI\nVOID PhFreeDsObjectPickerObjects(\n    _In_ PPH_DSPICK_OBJECTS Objects\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/emenu.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_EMENU_H\n#define _PH_EMENU_H\n\nEXTERN_C_START\n\n#define PH_EMENU_DISABLED 0x1\n#define PH_EMENU_CHECKED 0x2\n#define PH_EMENU_HIGHLIGHT 0x4\n#define PH_EMENU_MENUBARBREAK 0x8\n#define PH_EMENU_MENUBREAK 0x10\n#define PH_EMENU_DEFAULT 0x20\n#define PH_EMENU_MOUSESELECT 0x40\n#define PH_EMENU_RADIOCHECK 0x80\n#define PH_EMENU_RIGHTORDER 0x100\n\n#define PH_EMENU_SEPARATECHECKSPACE 0x100000\n#define PH_EMENU_SEPARATOR 0x200000\n#define PH_EMENU_MAINMENU 0x400000\n#define PH_EMENU_CALLBACK 0x800000\n\n#define PH_EMENU_TEXT_OWNED 0x80000000\n#define PH_EMENU_BITMAP_OWNED 0x40000000\n\ntypedef struct _PH_EMENU_ITEM *PPH_EMENU_ITEM;\n\ntypedef _Function_class_(PH_EMENU_ITEM_DELETE_FUNCTION)\nVOID NTAPI PH_EMENU_ITEM_DELETE_FUNCTION(\n    _In_ PPH_EMENU_ITEM Item\n    );\ntypedef PH_EMENU_ITEM_DELETE_FUNCTION* PPH_EMENU_ITEM_DELETE_FUNCTION;\n\ntypedef _Function_class_(PH_EMENU_ITEM_DELAY_FUNCTION)\nVOID NTAPI PH_EMENU_ITEM_DELAY_FUNCTION(\n    _In_ HMENU Menu,\n    _In_ PPH_EMENU_ITEM Item\n    );\ntypedef PH_EMENU_ITEM_DELAY_FUNCTION* PPH_EMENU_ITEM_DELAY_FUNCTION;\n\ntypedef struct _PH_EMENU_ITEM\n{\n    ULONG Flags;\n    ULONG Id;\n    PWSTR Text;\n    HBITMAP Bitmap;\n\n    PVOID Parameter;\n    PVOID Context;\n\n    PPH_EMENU_ITEM_DELETE_FUNCTION DeleteFunction;\n    PPH_EMENU_ITEM_DELAY_FUNCTION DelayFunction;\n\n    PPH_EMENU_ITEM Parent;\n    PPH_LIST Items;\n} PH_EMENU_ITEM, *PPH_EMENU_ITEM;\n\ntypedef struct _PH_EMENU_ITEM PH_EMENU, *PPH_EMENU;\n\nPHLIBAPI\nPPH_EMENU_ITEM\nNTAPI\nPhCreateEMenuItem(\n    _In_ ULONG Flags,\n    _In_ ULONG Id,\n    _In_opt_ PCWSTR Text,\n    _In_opt_ HBITMAP Bitmap,\n    _In_opt_ PVOID Context\n    );\n\nPPH_EMENU_ITEM\nPhCreateEMenuItemCallback(\n    _In_ ULONG Flags,\n    _In_ ULONG Id,\n    _In_opt_ PCWSTR Text,\n    _In_opt_ HBITMAP Bitmap,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_EMENU_ITEM_DELAY_FUNCTION DelayFunction\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDestroyEMenuItem(\n    _In_ _Post_invalid_ PPH_EMENU_ITEM Item\n    );\n\n#define PH_EMENU_FIND_DESCEND 0x1\n#define PH_EMENU_FIND_STARTSWITH 0x2\n#define PH_EMENU_FIND_LITERAL 0x4\n\n_Success_(return != NULL)\nPHLIBAPI\nPPH_EMENU_ITEM\nNTAPI\nPhFindEMenuItem(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Flags,\n    _In_opt_ PCWSTR Text,\n    _In_ ULONG Id\n    );\n\n_Success_(return != NULL)\nPHLIBAPI\nPPH_EMENU_ITEM\nNTAPI\nPhFindEMenuItemEx(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Flags,\n    _In_opt_ PCWSTR Text,\n    _In_ ULONG Id,\n    _Out_opt_ PPH_EMENU_ITEM *FoundParent,\n    _Out_opt_ PULONG FoundIndex\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhIndexOfEMenuItem(\n    _In_ PPH_EMENU_ITEM Parent,\n    _In_ PPH_EMENU_ITEM Item\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Parent,\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Index\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhRemoveEMenuItem(\n    _Inout_opt_ PPH_EMENU_ITEM Parent,\n    _In_opt_ PPH_EMENU_ITEM Item,\n    _In_opt_ ULONG Index\n    );\n\nPHLIBAPI\nVOID PhRemoveAllEMenuItems(\n    _Inout_ PPH_EMENU_ITEM Parent\n    );\n\nPHLIBAPI\nPPH_EMENU\nNTAPI\nPhCreateEMenu(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDestroyEMenu(\n    _In_ PPH_EMENU Menu\n    );\n\n#define PH_EMENU_CONVERT_ID 0x1\n\ntypedef struct _PH_EMENU_DATA\n{\n    PPH_LIST IdToItem;\n} PH_EMENU_DATA, *PPH_EMENU_DATA;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeEMenuData(\n    _Out_ PPH_EMENU_DATA Data\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteEMenuData(\n    _Inout_ PPH_EMENU_DATA Data\n    );\n\nPHLIBAPI\nHMENU\nNTAPI\nPhEMenuToHMenu(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG Flags,\n    _Inout_opt_ PPH_EMENU_DATA Data\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhEMenuToHMenu2(\n    _In_ HMENU MenuHandle,\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG Flags,\n    _Inout_opt_ PPH_EMENU_DATA Data\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhHMenuToEMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem,\n    _In_ HMENU MenuHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLoadResourceEMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem,\n    _In_ HINSTANCE InstanceHandle,\n    _In_ PCWSTR Resource,\n    _In_ LONG SubMenuIndex\n    );\n\n#define PH_EMENU_SHOW_SEND_COMMAND 0x1\n#define PH_EMENU_SHOW_LEFTRIGHT 0x2\n\nPHLIBAPI\nPPH_EMENU_ITEM\nNTAPI\nPhShowEMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG Align,\n    _In_ ULONG X,\n    _In_ ULONG Y\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSetFlagsEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Id,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetFlagsAllEMenuItems(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    );\n\n#define PH_EMENU_MODIFY_TEXT 0x1\n#define PH_EMENU_MODIFY_BITMAP 0x2\n\nPHLIBAPI\nVOID\nNTAPI\nPhModifyEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG ModifyFlags,\n    _In_ ULONG OwnedFlags,\n    _In_opt_ PWSTR Text,\n    _In_opt_ HBITMAP Bitmap\n    );\n\nVOID PhSetHMenuStyle(\n    _In_ HMENU Menu,\n    _In_ BOOLEAN MainMenu\n    );\n\nBOOLEAN PhSetHMenuWindow(\n    _In_ HWND WindowHandle,\n    _In_ HMENU MenuHandle\n    );\n\nBOOLEAN PhSetHMenuNotify(\n    _In_ HMENU MenuHandle\n    );\n\nVOID PhDeleteHMenu(\n    _In_ HMENU Menu\n    );\n\n_Success_(return)\nBOOLEAN PhGetHMenuStringToBuffer(\n    _In_ HMENU Menu,\n    _In_ ULONG Id,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nPPH_EMENU_ITEM PhGetMenuData(\n    _In_ HMENU Menu,\n    _In_ ULONG Index\n    );\n\nVOID PhMenuCallbackDispatch(\n    _In_ HMENU Menu,\n    _In_ ULONG Index\n    );\n\n// Convenience functions\n\nFORCEINLINE\nPPH_EMENU_ITEM PhCreateEMenuSeparator(\n    VOID\n    )\n{\n    return PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL);\n}\n\nFORCEINLINE\nPPH_EMENU_ITEM PhCreateEMenuItemEmpty(\n    VOID\n    )\n{\n    return PhCreateEMenuItem(0, USHRT_MAX, NULL, NULL, NULL);\n}\n\nFORCEINLINE\nBOOLEAN PhEnableEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Id,\n    _In_ BOOLEAN Enable\n    )\n{\n    return PhSetFlagsEMenuItem(Item, Id, PH_EMENU_DISABLED, Enable ? 0 : PH_EMENU_DISABLED);\n}\n\nFORCEINLINE\nVOID PhSetDisabledEMenuItem(\n    _In_ PPH_EMENU_ITEM Item\n    )\n{\n    Item->Flags |= PH_EMENU_DISABLED;\n}\n\nFORCEINLINE\nVOID PhSetEnabledEMenuItem(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ BOOLEAN Enable\n    )\n{\n    if (Enable)\n        Item->Flags &= ~PH_EMENU_DISABLED;\n    else\n        Item->Flags |= PH_EMENU_DISABLED;\n}\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/exlf.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2018-2023\n *\n */\n\n#ifndef _PH_EXLF_H\n#define _PH_EXLF_H\n\n/*\n * This file contains the required types for ELF binaries.\n *\n * References:\n * http://man7.org/linux/man-pages/man5/elf.5.html\n * http://www.skyfree.org/linux/references/ELF_Format.pdf\n * https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h\n * https://chromium.googlesource.com/chromiumos/chromite/+/HEAD/lib/parseelf.py\n */\n\n#define EI_NIDENT 16\n\n// e_ident[] indexes\n#define EI_MAG0     0\n#define EI_MAG1     1\n#define EI_MAG2     2\n#define EI_MAG3     3\n#define EI_CLASS    4\n#define EI_DATA     5\n#define EI_VERSION  6\n#define EI_OSABI    7\n#define EI_PAD      8\n\n// EI_MAG\n#define ELFMAG0 0x7f\n#define ELFMAG1 'E'\n#define ELFMAG2 'L'\n#define ELFMAG3 'F'\n// EI_CLASS\n#define ELFCLASSNONE 0\n#define ELFCLASS32 1\n#define ELFCLASS64 2\n\n// EI_DATA\n#define ELFDATANONE 0\n#define ELFDATA2LSB 1\n#define ELFDATA2MSB 2\n\n// EI_VERSION and e_version\n#define EV_NONE 0\n#define EV_CURRENT 1\n\n#define ELFOSABI_NONE 0\n#define ELFOSABI_LINUX 3\n\n// e_type\n#define ET_NONE 0\n#define ET_REL 1\n#define ET_EXEC 2\n#define ET_DYN 3\n#define ET_CORE 4\n#define ET_LOPROC 0xff00\n#define ET_HIPROC 0xffff\n\n// e_machine\n#define EM_386 3\n#define EM_X86_64 62\n\n/* segment types */\n#define PT_NULL    0\n#define PT_LOAD    1\n#define PT_DYNAMIC 2\n#define PT_INTERP  3\n#define PT_NOTE    4\n#define PT_SHLIB   5\n#define PT_PHDR    6\n#define PT_TLS     7               /* Thread local storage segment */\n#define PT_LOOS    0x60000000      /* OS-specific */\n#define PT_HIOS    0x6fffffff      /* OS-specific */\n#define PT_LOPROC  0x70000000\n#define PT_HIPROC  0x7fffffff\n#define PT_GNU_EH_FRAME     0x6474e550\n#define PT_GNU_STACK    (PT_LOOS + 0x474e551)\n\n/* permissions on sections in the program header, p_flags. */\n#define PF_NONE 0x0\n#define PF_X 0x1\n#define PF_W 0x2\n#define PF_R 0x4\n\n// sh_type\n#define SHT_NULL 0     // Section header table entry (unused).\n#define SHT_PROGBITS 1 // Program data.\n#define SHT_SYMTAB 2   // Link editing symbol table.\n#define SHT_STRTAB 3   // A string table.\n#define SHT_RELA 4     // Relocation entries with addends.\n#define SHT_HASH 5     // A symbol hash table.\n#define SHT_DYNAMIC 6  // Information for dynamic linking.\n#define SHT_NOTE 7     // Information that marks file.\n#define SHT_NOBITS 8   // Section occupies no space in file.\n#define SHT_REL 9      // Relocation entries, no addends.\n#define SHT_SHLIB 10   // Reserved, unspecified semantics.\n#define SHT_DYNSYM 11  // Dynamic linking symbol table.\n//#define SHT_NUM 12\n#define SHT_INIT_ARRAY 14    // Array of constructors.\n#define SHT_FINI_ARRAY 15    // Array of destructors.\n#define SHT_PREINIT_ARRAY 16 // Array of pre-constructors.\n#define SHT_GROUP 17         // Section group.\n#define SHT_SYMTAB_SHNDX 18  // Extended section indeces.\n#define SHT_NUM 19           // Number of defined types. (dmex: Some tools define this as 19 and others as 12???)\n#define SHT_LOOS 0x60000000 // First of OS specific semantics.\n#define SHT_HIOS 0x6fffffff // Last of OS specific semantics.\n#define SHT_GNU_INCREMENTAL_INPUTS 0x6fff4700 // incremental build data.\n#define SHT_GNU_ATTRIBUTES 0x6ffffff5 // Object attributes.\n#define SHT_GNU_HASH 0x6ffffff6 // GNU style symbol hash table.\n#define SHT_GNU_LIBLIST 0x6ffffff7 // List of prelink dependencies.\n#define SHT_LOPROC 0x70000000\n#define SHT_HIPROC 0x7fffffff\n#define SHT_LOUSER 0x80000000\n#define SHT_HIUSER 0xffffffff\n#define SHT_SUNW_verdef 0x6ffffffd  // Versions defined by file.\n#define SHT_SUNW_verneed 0x6ffffffe // Versions needed by file.\n#define SHT_SUNW_versym 0x6fffffff  // Symbol versions.\n\n// sh_flags\n#define SHF_WRITE 0x1   /* Section contains writable data. */\n#define SHF_ALLOC 0x2   /* Section occupies memory. */\n#define SHF_EXECINSTR 0x4   /* Section contains instructions. */\n#define SHF_MERGE 0x10  /* Section may be merged. */\n#define SHF_STRINGS 0x20    /* Section contains strings. */\n#define SHF_INFO_LINK 0x40  /* sh_info holds section index. */\n#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */\n#define SHF_OS_NONCONFORMING 0x100  /* OS-specific processing required. */\n#define SHF_GROUP 0x200 /* Member of section group. */\n#define SHF_TLS 0x400   /* Section contains TLS data. */\n#define SHF_MASKOS  0x0ff00000  /* OS-specific semantics. */\n#define SHF_MASKPROC    0xf0000000  /* Processor-specific semantics. */\n\n// special section indexes.\n#define SHN_UNDEF 0 // An undefined symbol.\n#define SHN_LORESERVE 0xff00\n#define SHN_LOPROC 0xff00\n#define SHN_HIPROC 0xff1f\n#define SHN_LIVEPATCH 0xff20\n#define SHN_ABS 0xfff1\n#define SHN_COMMON 0xfff2\n#define SHN_HIRESERVE 0xffff\n\n// dynamic section\n#define DT_NULL     0\n#define DT_NEEDED   1\n#define DT_PLTRELSZ 2\n#define DT_PLTGOT   3\n#define DT_HASH     4\n#define DT_STRTAB   5\n#define DT_SYMTAB   6\n#define DT_RELA     7\n#define DT_RELASZ   8\n#define DT_RELAENT  9\n#define DT_STRSZ    10\n#define DT_SYMENT   11\n#define DT_INIT     12\n#define DT_FINI     13\n#define DT_SONAME   14\n#define DT_RPATH    15\n#define DT_SYMBOLIC 16\n#define DT_REL      17\n#define DT_RELSZ    18\n#define DT_RELENT   19\n#define DT_PLTREL   20\n#define DT_DEBUG    21\n#define DT_TEXTREL  22\n#define DT_JMPREL   23\n#define DT_INIT_ARRAY 25\n#define DT_FINI_ARRAY 26\n#define DT_INIT_ARRAYSZ 27\n#define DT_FINI_ARRAYSZ 28\n#define DT_RUNPATH 29\n#define DT_FLAGS 30\n#define DT_PREINIT_ARRAY 32 // DT_ENCODING\n#define DT_PREINIT_ARRAYSZ 33\n#define OLD_DT_LOOS 0x60000000\n#define DT_LOOS 0x6000000d\n#define DT_HIOS 0x6ffff000\n#define DT_VALRNGLO 0x6ffffd00\n#define DT_VALRNGHI 0x6ffffdff\n#define DT_ADDRRNGLO 0x6ffffe00\n#define DT_ADDRRNGHI 0x6ffffeff\n#define DT_GNU_HASH 0x6ffffef5\n#define DT_VERSYM 0x6ffffff0\n#define DT_RELACOUNT 0x6ffffff9\n#define DT_RELCOUNT 0x6ffffffa\n#define DT_FLAGS_1 0x6ffffffb\n#define DT_VERDEF 0x6ffffffc\n#define DT_VERDEFNUM 0x6ffffffd\n#define DT_VERNEED 0x6ffffffe\n#define DT_VERNEEDNUM 0x6fffffff\n#define OLD_DT_HIOS 0x6fffffff\n#define DT_LOPROC 0x70000000\n#define DT_HIPROC 0x7fffffff\n\n// symbol table section\n#define STB_LOCAL 0 /* Local symbol */\n#define STB_GLOBAL 1 /* Global symbol */\n#define STB_WEAK 2 /* Weak symbol */\n#define STB_NUM 3 /* Number of defined types.  */\n#define STB_LOOS 10 /* Start of OS-specific */\n#define STB_GNU_UNIQUE 10 /* Unique symbol.  */\n#define STB_HIOS 12 /* End of OS-specific */\n#define STB_LOPROC 13 /* Start of processor-specific */\n#define STB_HIPROC 15 /* End of processor-specific */\n\n#define STT_NOTYPE  0\n#define STT_OBJECT  1\n#define STT_FUNC    2\n#define STT_SECTION 3\n#define STT_FILE    4\n#define STT_COMMON  5\n#define STT_TLS     6\n#define STT_GNU_IFUNC 10\n#define STT_LOOS      10\n#define STT_HIOS      12\n#define STT_LOPROC    13\n#define STT_HIPROC    15\n\n#define STV_DEFAULT 0 /* Default symbol visibility rules */\n#define STV_INTERNAL 1 /* Processor specific hidden class */\n#define STV_HIDDEN 2 /* Sym unavailable in other modules */\n#define STV_PROTECTED 3 /* Not preemptible, not exported */\n\n#define ELF_ST_BIND(x) ((x) >> 4)\n#define ELF_ST_TYPE(x) ((x) & 0xF)\n#define ELF_ST_VISIBILITY(x) ((x) & 0x03)\n\n#define ELF32_ST_BIND(x) ELF_ST_BIND(x)\n#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)\n#define ELF32_ST_VIS(a) ELF_ST_VISIBILITY(a)\n#define ELF64_ST_BIND(x) ELF_ST_BIND(x)\n#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)\n#define ELF64_ST_VIS(a) ELF_ST_VISIBILITY(a)\n\n// Non-standard ELF definitions (dmex)\n\n#define IMAGE_ELF_SIGNATURE 0x457f // \"\\x7fELF\"\n#define ELFMAG ((BYTE[4]){ELFMAG0,ELFMAG1,ELFMAG2,ELFMAG3})\n\ntypedef struct _ELF_IMAGE_HEADER\n{\n    union\n    {\n        unsigned char e_ident[EI_NIDENT];\n        struct\n        {\n            unsigned char MagicNumber[4];\n            unsigned char Class;\n            unsigned char Data;\n            unsigned char Version;\n            unsigned char Abi;\n            unsigned char AbiVersion;\n            unsigned char Unused[7];\n        };\n    };\n    unsigned short e_type;\n    unsigned short e_machine;\n    unsigned int e_version;\n    //union {\n    //    PELF_IMAGE_HEADER32 Headers32;\n    //    PELF_IMAGE_HEADER64 Headers64;\n    //};\n} ELF_IMAGE_HEADER, *PELF_IMAGE_HEADER;\n\ntypedef struct _ELF_IMAGE_HEADER32\n{\n    // ELF_IMAGE_HEADER Header;\n    unsigned int e_entry; // Entry point virtual address.\n    unsigned int e_phoff; // Program header table file offset.\n    unsigned int e_shoff; // Section header table file offset.\n    unsigned int e_flags; // Processor-specific flags.\n    unsigned short e_ehsize; // ELF header size in bytes.\n    unsigned short e_phentsize; // Program header table entry size.\n    unsigned short e_phnum; // Program header table entry count.\n    unsigned short e_shentsize; // Section header table entry size.\n    unsigned short e_shnum; // Section header table entry count.\n    unsigned short e_shstrndx; // Section header string table index.\n} ELF_IMAGE_HEADER32, *PELF_IMAGE_HEADER32;\n\ntypedef struct _ELF_IMAGE_HEADER64\n{\n    // ELF_IMAGE_HEADER Header;\n    unsigned long long e_entry; // Entry point virtual address.\n    unsigned long long e_phoff; // Program header table file offset.\n    unsigned long long e_shoff; // Section header table file offset.\n    unsigned int e_flags; // Processor-specific flags.\n    unsigned short e_ehsize; // ELF header size in bytes.\n    unsigned short e_phentsize; // Program header table entry size.\n    unsigned short e_phnum; // Program header table entry count.\n    unsigned short e_shentsize; // Section header table entry size.\n    unsigned short e_shnum; // Section header table entry count.\n    unsigned short e_shstrndx; // Section header string table index.\n} ELF_IMAGE_HEADER64, *PELF_IMAGE_HEADER64;\n\ntypedef struct _ELF32_IMAGE_SEGMENT_HEADER\n{\n    unsigned int p_type; // Segment type.\n    unsigned int p_offset; // Segment file offset.\n    unsigned int p_vaddr; // Segment virtual address.\n    unsigned int p_paddr; // Segment physical address.\n    unsigned int p_filesz; // Segment size in file.\n    unsigned int p_memsz; // Segment size in memory.\n    unsigned int p_flags; // Segment flags.\n    unsigned int p_align; // Segment alignment.\n} ELF32_IMAGE_SEGMENT_HEADER;\n\ntypedef struct _ELF64_IMAGE_SEGMENT_HEADER\n{\n    unsigned int p_type; // Segment type.\n    unsigned int p_flags; // Segment flags.\n    unsigned long long p_offset; // Segment file offset.\n    unsigned long long p_vaddr; // Segment virtual address.\n    unsigned long long p_paddr; // Segment physical address.\n    unsigned long long p_filesz; // Segment size in file.\n    unsigned long long p_memsz; // Segment size in memory.\n    unsigned long long p_align; // Segment alignment.\n} ELF64_IMAGE_SEGMENT_HEADER, *PELF64_IMAGE_SEGMENT_HEADER;\n\n#define IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage) \\\n    ((PELF64_IMAGE_SEGMENT_HEADER)PTR_ADD_OFFSET(MappedWslImage->Header, MappedWslImage->Headers64->e_phoff))\n\n#define IMAGE_ELF64_SEGMENT_BY_INDEX(SegmentHeader, Index) \\\n    ((PELF64_IMAGE_SEGMENT_HEADER)PTR_ADD_OFFSET(SegmentHeader, sizeof(ELF64_IMAGE_SEGMENT_HEADER) * Index))\n    //((PELF64_IMAGE_SEGMENT_HEADER)&SegmentHeaderTable[Index])\n\ntypedef struct _ELF32_IMAGE_SECTION_HEADER\n{\n    unsigned int sh_name;\n    unsigned int sh_type;\n    unsigned int sh_flags;\n    unsigned int sh_addr;\n    unsigned int sh_offset;\n    unsigned int sh_size;\n    unsigned int sh_link;\n    unsigned int sh_info;\n    unsigned int sh_addralign;\n    unsigned int sh_entsize;\n} ELF32_IMAGE_SECTION_HEADER;\n\ntypedef struct _ELF64_IMAGE_SECTION_HEADER\n{\n    unsigned int sh_name;            /* Section name, index in string tbl */\n    unsigned int sh_type;            /* Type of section */\n    unsigned long long sh_flags;     /* Miscellaneous section attributes */\n    unsigned long long sh_addr;      /* Section virtual addr at execution */\n    unsigned long long sh_offset;    /* Section file offset */\n    unsigned long long sh_size;      /* Size of section in bytes */\n    unsigned int sh_link;            /* Index of another section */\n    unsigned int sh_info;            /* Additional section information */\n    unsigned long long sh_addralign; /* Section alignment */\n    unsigned long long sh_entsize;   /* Entry size if section holds table */\n} ELF64_IMAGE_SECTION_HEADER, *PELF64_IMAGE_SECTION_HEADER;\n\n#define IMAGE_FIRST_ELF64_SECTION(MappedWslImage) \\\n    ((PELF64_IMAGE_SECTION_HEADER)PTR_ADD_OFFSET(MappedWslImage->Header, MappedWslImage->Headers64->e_shoff))\n\n#define IMAGE_ELF64_SECTION_BY_INDEX(SectionHeader, Index) \\\n    ((PELF64_IMAGE_SECTION_HEADER)PTR_ADD_OFFSET(SectionHeader, sizeof(ELF64_IMAGE_SECTION_HEADER) * Index))\n    // ((PELF64_IMAGE_SECTION_HEADER)&SectionHeaderTable[Index])\n\n// ELF dynamic entries\n\ntypedef struct _ELF32_IMAGE_DYNAMIC_ENTRY // Elf32_Dyn\n{\n    int d_tag;\n    unsigned int d_val;\n} ELF32_IMAGE_DYNAMIC_ENTRY, *PELF32_IMAGE_DYNAMIC_ENTRY;\n\ntypedef struct _ELF64_IMAGE_DYNAMIC_ENTRY // Elf64_Dyn\n{\n    long long d_tag;\n    unsigned long long d_val;\n} ELF64_IMAGE_DYNAMIC_ENTRY, *PELF64_IMAGE_DYNAMIC_ENTRY;\n\n// ELF symbol entries\n\ntypedef struct _ELF_IMAGE_SYMBOL_ENTRY // Elf_Sym\n{\n    unsigned int st_name;\n    unsigned char st_info;\n    unsigned char st_other;\n    unsigned short st_shndx;\n    unsigned long long st_value;\n    unsigned long long st_size;\n} ELF_IMAGE_SYMBOL_ENTRY, *PELF_IMAGE_SYMBOL_ENTRY;\n\n// ELF version entries\n\ntypedef struct _ELF_VERSION_TABLE // Elf_Versym\n{\n    unsigned short vs_vers;\n} ELF_VERSION_TABLE, *PELF_VERSION_TABLE;\n\ntypedef struct\n{\n    unsigned short vd_version;\n    unsigned short vd_flags; // flags (VER_FLG_*).\n    unsigned short vd_ndx; // version index.\n    unsigned short vd_cnt; // number of verdaux entries.\n    unsigned int vd_hash; // hash of name.\n    unsigned int vd_aux; // offset to verdaux entries.\n    unsigned int vd_next; // offset to next verdef.\n} Elf_Verdef;\n\ntypedef struct\n{\n    unsigned int vda_name;  /* string table offset of name */\n    unsigned int vda_next;  /* offset to verdaux */\n} Elf_Verdaux;\n\n// vn_version\n#define VER_NEED_NONE    0 /* No version */\n#define VER_NEED_CURRENT 1 /* Current version */\n#define VER_NEED_NUM     2 /* Given version number */\n\ntypedef struct _ELF_VERSION_NEED // Elf_Verneed\n{\n    unsigned short vn_version;\n    unsigned short vn_cnt;\n    unsigned int vn_file;\n    unsigned int vn_aux;\n    unsigned int vn_next;\n} ELF_VERSION_NEED, *PELF_VERSION_NEED;\n\ntypedef struct _ELF_VERSION_AUX // Elf_Vernaux\n{\n    unsigned int vna_hash; // dependency name hash.\n    unsigned short vna_flags; // flags (VER_FLG_*).\n    unsigned short vna_other;\n    unsigned int vna_name;\n    unsigned int vna_next;\n} ELF_VERSION_AUX, *PELF_VERSION_AUX;\n\n#endif\n"
  },
  {
    "path": "phlib/include/exprodid.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2020-2022\n *\n */\n\n#ifndef _PH_EXPRODID_H\n#define _PH_EXPRODID_H\n\n/*\n * This file contains the required types for the RICH header.\n *\n * References:\n * http://bytepointer.com/articles/the_microsoft_rich_header.htm\n * https://infocon.hackingand.coffee/Hacktivity/Hacktivity%202016/Presentations/George_Webster-and-Julian-Kirsch.pdf\n * https://www.virusbulletin.com/virusbulletin/2020/01/vb2019-paper-rich-headers-leveraging-mysterious-artifact-pe-format/\n */\n\n#define ProdIdTagStart 0x68636952\n#define ProdIdTagEnd 0x536e6144\n\n// private\ntypedef struct PRODITEM\n{\n    ULONG dwProdid; // Product identity\n    ULONG dwCount; // Count of objects built with that product\n} PRODITEM, *PPRODITEM;\n\n// This enum was built from https://github.com/kirschju/richheader licensed under GPL3 (dmex)\ntypedef enum _PRODID\n{\n    prodidUnknown = 0x0000,\n    prodidImport0 = 0x0001, // Linker generated import object version 0\n    prodidLinker510 = 0x0002, // LINK 5.10 (Visual Studio 97 SP3)\n    prodidCvtomf510 = 0x0003, // LINK 5.10 (Visual Studio 97 SP3) OMF to COFF conversion\n    prodidLinker600 = 0x0004, // LINK 6.00 (Visual Studio 98)\n    prodidCvtomf600 = 0x0005, // LINK 6.00 (Visual Studio 98) OMF to COFF conversion\n    prodidCvtres500 = 0x0006, // CVTRES 5.00\n    prodidUtc11_Basic = 0x0007, // VB 5.0 native code\n    prodidUtc11_C = 0x0008, // VC++ 5.0 C/C++\n    prodidUtc12_Basic = 0x0009, // VB 6.0 native code\n    prodidUtc12_C = 0x000A, // VC++ 6.0 C\n    prodidUtc12_CPP = 0x000B, // VC++ 6.0 C++\n    prodidAliasObj60 = 0x000C, // ALIASOBJ.EXE (CRT Tool that builds OLDNAMES.LIB)\n    prodidVisualBasic60 = 0x000D, // VB 6.0 generated object\n    prodidMasm613 = 0x000E, // MASM 6.13\n    prodidMasm701 = 0x000F, // MASM 7.01 (prodidMasm710)\n    prodidLinker511 = 0x0010, // LINK 5.11\n    prodidCvtomf511 = 0x0011, // LINK 5.11 OMF to COFF conversion\n    prodidMasm614 = 0x0012, // MASM 6.14 (MMX2 support)\n    prodidLinker512 = 0x0013, // LINK 5.12\n    prodidCvtomf512 = 0x0014, // LINK 5.12 OMF to COFF conversion\n    prodidUtc12_C_Std = 0x0015,\n    prodidUtc12_CPP_Std = 0x0016,\n    prodidUtc12_C_Book = 0x0017,\n    prodidUtc12_CPP_Book = 0x0018,\n    prodidImplib700 = 0x0019,\n    prodidCvtomf700 = 0x001a,\n    prodidUtc13_Basic = 0x001b,\n    prodidUtc13_C = 0x001c,\n    prodidUtc13_CPP = 0x001d,\n    prodidLinker610 = 0x001e,\n    prodidCvtomf610 = 0x001f,\n    prodidLinker601 = 0x0020,\n    prodidCvtomf601 = 0x0021,\n    prodidUtc12_1_Basic = 0x0022,\n    prodidUtc12_1_C = 0x0023,\n    prodidUtc12_1_CPP = 0x0024,\n    prodidLinker620 = 0x0025,\n    prodidCvtomf620 = 0x0026,\n    prodidAliasObj70 = 0x0027,\n    prodidLinker621 = 0x0028,\n    prodidCvtomf621 = 0x0029,\n    prodidMasm615 = 0x002a,\n    prodidUtc13_LTCG_C = 0x002b,\n    prodidUtc13_LTCG_CPP = 0x002c,\n    prodidMasm620 = 0x002d,\n    prodidILAsm100 = 0x002e,\n    prodidUtc12_2_Basic = 0x002f,\n    prodidUtc12_2_C = 0x0030,\n    prodidUtc12_2_CPP = 0x0031,\n    prodidUtc12_2_C_Std = 0x0032,\n    prodidUtc12_2_CPP_Std = 0x0033,\n    prodidUtc12_2_C_Book = 0x0034,\n    prodidUtc12_2_CPP_Book = 0x0035,\n    prodidImplib622 = 0x0036,\n    prodidCvtomf622 = 0x0037,\n    prodidCvtres501 = 0x0038,\n    prodidUtc13_C_Std = 0x0039,\n    prodidUtc13_CPP_Std = 0x003a,\n    prodidCvtpgd1300 = 0x003b,\n    prodidLinker622 = 0x003c,\n    prodidLinker700 = 0x003d,\n    prodidExport622 = 0x003e,\n    prodidExport700 = 0x003f,\n    prodidMasm700 = 0x0040,\n    prodidUtc13_POGO_I_C = 0x0041,\n    prodidUtc13_POGO_I_CPP = 0x0042,\n    prodidUtc13_POGO_O_C = 0x0043,\n    prodidUtc13_POGO_O_CPP = 0x0044,\n    prodidCvtres700 = 0x0045,\n    prodidCvtres710p = 0x0046,\n    prodidLinker710p = 0x0047,\n    prodidCvtomf710p = 0x0048,\n    prodidExport710p = 0x0049,\n    prodidImplib710p = 0x004a,\n    prodidMasm710p = 0x004b,\n    prodidUtc1310p_C = 0x004c,\n    prodidUtc1310p_CPP = 0x004d,\n    prodidUtc1310p_C_Std = 0x004e,\n    prodidUtc1310p_CPP_Std = 0x004f,\n    prodidUtc1310p_LTCG_C = 0x0050,\n    prodidUtc1310p_LTCG_CPP = 0x0051,\n    prodidUtc1310p_POGO_I_C = 0x0052,\n    prodidUtc1310p_POGO_I_CPP = 0x0053,\n    prodidUtc1310p_POGO_O_C = 0x0054,\n    prodidUtc1310p_POGO_O_CPP = 0x0055,\n    prodidLinker624 = 0x0056,\n    prodidCvtomf624 = 0x0057,\n    prodidExport624 = 0x0058,\n    prodidImplib624 = 0x0059,\n    prodidLinker710 = 0x005a,\n    prodidCvtomf710 = 0x005b,\n    prodidExport710 = 0x005c,\n    prodidImplib710 = 0x005d,\n    prodidCvtres710 = 0x005e,\n    prodidUtc1310_C = 0x005f,\n    prodidUtc1310_CPP = 0x0060,\n    prodidUtc1310_C_Std = 0x0061,\n    prodidUtc1310_CPP_Std = 0x0062,\n    prodidUtc1310_LTCG_C = 0x0063,\n    prodidUtc1310_LTCG_CPP = 0x0064,\n    prodidUtc1310_POGO_I_C = 0x0065,\n    prodidUtc1310_POGO_I_CPP = 0x0066,\n    prodidUtc1310_POGO_O_C = 0x0067,\n    prodidUtc1310_POGO_O_CPP = 0x0068,\n    prodidAliasObj710 = 0x0069,\n    prodidAliasObj710p = 0x006a,\n    prodidCvtpgd1310 = 0x006b,\n    prodidCvtpgd1310p = 0x006c,\n    prodidUtc1400_C = 0x006d,\n    prodidUtc1400_CPP = 0x006e,\n    prodidUtc1400_C_Std = 0x006f,\n    prodidUtc1400_CPP_Std = 0x0070,\n    prodidUtc1400_LTCG_C = 0x0071,\n    prodidUtc1400_LTCG_CPP = 0x0072,\n    prodidUtc1400_POGO_I_C = 0x0073,\n    prodidUtc1400_POGO_I_CPP = 0x0074,\n    prodidUtc1400_POGO_O_C = 0x0075,\n    prodidUtc1400_POGO_O_CPP = 0x0076,\n    prodidCvtpgd1400 = 0x0077,\n    prodidLinker800 = 0x0078,\n    prodidCvtomf800 = 0x0079,\n    prodidExport800 = 0x007a,\n    prodidImplib800 = 0x007b,\n    prodidCvtres800 = 0x007c,\n    prodidMasm800 = 0x007d,\n    prodidAliasObj800 = 0x007e,\n    prodidPhoenixPrerelease = 0x007f,\n    prodidUtc1400_CVTCIL_C = 0x0080,\n    prodidUtc1400_CVTCIL_CPP = 0x0081,\n    prodidUtc1400_LTCG_MSIL = 0x0082,\n    prodidUtc1500_C = 0x0083,\n    prodidUtc1500_CPP = 0x0084,\n    prodidUtc1500_C_Std = 0x0085,\n    prodidUtc1500_CPP_Std = 0x0086,\n    prodidUtc1500_CVTCIL_C = 0x0087,\n    prodidUtc1500_CVTCIL_CPP = 0x0088,\n    prodidUtc1500_LTCG_C = 0x0089,\n    prodidUtc1500_LTCG_CPP = 0x008a,\n    prodidUtc1500_LTCG_MSIL = 0x008b,\n    prodidUtc1500_POGO_I_C = 0x008c,\n    prodidUtc1500_POGO_I_CPP = 0x008d,\n    prodidUtc1500_POGO_O_C = 0x008e,\n    prodidUtc1500_POGO_O_CPP = 0x008f,\n    prodidCvtpgd1500 = 0x0090,\n    prodidLinker900 = 0x0091,\n    prodidExport900 = 0x0092,\n    prodidImplib900 = 0x0093,\n    prodidCvtres900 = 0x0094,\n    prodidMasm900 = 0x0095,\n    prodidAliasObj900 = 0x0096,\n    prodidResource = 0x0097,\n    prodidAliasObj1000 = 0x0098,\n    prodidCvtpgd1600 = 0x0099,\n    prodidCvtres1000 = 0x009a,\n    prodidExport1000 = 0x009b,\n    prodidImplib1000 = 0x009c,\n    prodidLinker1000 = 0x009d,\n    prodidMasm1000 = 0x009e,\n    prodidPhx1600_C = 0x009f,\n    prodidPhx1600_CPP = 0x00a0,\n    prodidPhx1600_CVTCIL_C = 0x00a1,\n    prodidPhx1600_CVTCIL_CPP = 0x00a2,\n    prodidPhx1600_LTCG_C = 0x00a3,\n    prodidPhx1600_LTCG_CPP = 0x00a4,\n    prodidPhx1600_LTCG_MSIL = 0x00a5,\n    prodidPhx1600_POGO_I_C = 0x00a6,\n    prodidPhx1600_POGO_I_CPP = 0x00a7,\n    prodidPhx1600_POGO_O_C = 0x00a8,\n    prodidPhx1600_POGO_O_CPP = 0x00a9,\n    prodidUtc1600_C = 0x00aa,\n    prodidUtc1600_CPP = 0x00ab,\n    prodidUtc1600_CVTCIL_C = 0x00ac,\n    prodidUtc1600_CVTCIL_CPP = 0x00ad,\n    prodidUtc1600_LTCG_C = 0x00ae,\n    prodidUtc1600_LTCG_CPP = 0x00af,\n    prodidUtc1600_LTCG_MSIL = 0x00b0,\n    prodidUtc1600_POGO_I_C = 0x00b1,\n    prodidUtc1600_POGO_I_CPP = 0x00b2,\n    prodidUtc1600_POGO_O_C = 0x00b3,\n    prodidUtc1600_POGO_O_CPP = 0x00b4,\n    prodidAliasObj1010 = 0x00b5,\n    prodidCvtpgd1610 = 0x00b6,\n    prodidCvtres1010 = 0x00b7,\n    prodidExport1010 = 0x00b8,\n    prodidImplib1010 = 0x00b9,\n    prodidLinker1010 = 0x00ba,\n    prodidMasm1010 = 0x00bb,\n    prodidUtc1610_C = 0x00bc,\n    prodidUtc1610_CPP = 0x00bd,\n    prodidUtc1610_CVTCIL_C = 0x00be,\n    prodidUtc1610_CVTCIL_CPP = 0x00bf,\n    prodidUtc1610_LTCG_C = 0x00c0,\n    prodidUtc1610_LTCG_CPP = 0x00c1,\n    prodidUtc1610_LTCG_MSIL = 0x00c2,\n    prodidUtc1610_POGO_I_C = 0x00c3,\n    prodidUtc1610_POGO_I_CPP = 0x00c4,\n    prodidUtc1610_POGO_O_C = 0x00c5,\n    prodidUtc1610_POGO_O_CPP = 0x00c6,\n    prodidAliasObj1100 = 0x00c7,\n    prodidCvtpgd1700 = 0x00c8,\n    prodidCvtres1100 = 0x00c9,\n    prodidExport1100 = 0x00ca,\n    prodidImplib1100 = 0x00cb,\n    prodidLinker1100 = 0x00cc,\n    prodidMasm1100 = 0x00cd,\n    prodidUtc1700_C = 0x00ce,\n    prodidUtc1700_CPP = 0x00cf,\n    prodidUtc1700_CVTCIL_C = 0x00d0,\n    prodidUtc1700_CVTCIL_CPP = 0x00d1,\n    prodidUtc1700_LTCG_C = 0x00d2,\n    prodidUtc1700_LTCG_CPP = 0x00d3,\n    prodidUtc1700_LTCG_MSIL = 0x00d4,\n    prodidUtc1700_POGO_I_C = 0x00d5,\n    prodidUtc1700_POGO_I_CPP = 0x00d6,\n    prodidUtc1700_POGO_O_C = 0x00d7,\n    prodidUtc1700_POGO_O_CPP = 0x00d8,\n    prodidAliasObj1200 = 0x00d9,\n    prodidCvtpgd1800 = 0x00da,\n    prodidCvtres1200 = 0x00db,\n    prodidExport1200 = 0x00dc,\n    prodidImplib1200 = 0x00dd,\n    prodidLinker1200 = 0x00de,\n    prodidMasm1200 = 0x00df,\n    prodidUtc1800_C = 0x00e0,\n    prodidUtc1800_CPP = 0x00e1,\n    prodidUtc1800_CVTCIL_C = 0x00e2,\n    prodidUtc1800_CVTCIL_CPP = 0x00e3, // 0x00d3 ??\n    prodidUtc1800_LTCG_C = 0x00e4,\n    prodidUtc1800_LTCG_CPP = 0x00e5,\n    prodidUtc1800_LTCG_MSIL = 0x00e6,\n    prodidUtc1800_POGO_I_C = 0x00e7,\n    prodidUtc1800_POGO_I_CPP = 0x00e8,\n    prodidUtc1800_POGO_O_C = 0x00e9,\n    prodidUtc1800_POGO_O_CPP = 0x00ea,\n    prodidAliasObj1210 = 0x00eb,\n    prodidCvtpgd1810 = 0x00ec,\n    prodidCvtres1210 = 0x00ed,\n    prodidExport1210 = 0x00ee,\n    prodidImplib1210 = 0x00ef,\n    prodidLinker1210 = 0x00f0,\n    prodidMasm1210 = 0x00f1,\n    prodidUtc1810_C = 0x00f2,\n    prodidUtc1810_CPP = 0x00f3,\n    prodidUtc1810_CVTCIL_C = 0x00f4,\n    prodidUtc1810_CVTCIL_CPP = 0x00f5,\n    prodidUtc1810_LTCG_C = 0x00f6,\n    prodidUtc1810_LTCG_CPP = 0x00f7,\n    prodidUtc1810_LTCG_MSIL = 0x00f8,\n    prodidUtc1810_POGO_I_C = 0x00f9,\n    prodidUtc1810_POGO_I_CPP = 0x00fa,\n    prodidUtc1810_POGO_O_C = 0x00fb,\n    prodidUtc1810_POGO_O_CPP = 0x00fc,\n    prodidAliasObj1400 = 0x00fd,\n    prodidCvtpgd1900 = 0x00fe,\n    prodidCvtres1400 = 0x00ff,\n    prodidExport1400 = 0x0100,\n    prodidImplib1400 = 0x0101,\n    prodidLinker1400 = 0x0102,\n    prodidMasm1400 = 0x0103,\n    prodidUtc1900_C = 0x0104,\n    prodidUtc1900_CPP = 0x0105,\n    prodidUtc1900_CVTCIL_C = 0x0106,\n    prodidUtc1900_CVTCIL_CPP = 0x0107,\n    prodidUtc1900_LTCG_C = 0x0108,\n    prodidUtc1900_LTCG_CPP = 0x0109,\n    prodidUtc1900_LTCG_MSIL = 0x010a,\n    prodidUtc1900_POGO_I_C = 0x010b,\n    prodidUtc1900_POGO_I_CPP = 0x010c,\n    prodidUtc1900_POGO_O_C = 0x010d,\n    prodidUtc1900_POGO_O_CPP = 0x010e\n} PRODID;\n\n#define DwProdidFromProdidWBuild(Prodid, Build) ((((ULONG)(Prodid)) << 16) | (Build))\n#define ProdidFromDwProdid(Prodid) ((PRODID)((Prodid) >> 16))\n#define WBuildFromDwProdid(Prodid) ((Prodid) & 0xFFFF)\n\n#endif\n"
  },
  {
    "path": "phlib/include/fastlock.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2015\n *\n */\n\n#ifndef _PH_FASTLOCK_H\n#define _PH_FASTLOCK_H\n\n// FastLock is a port of FastResourceLock from PH 1.x.\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _PH_FAST_LOCK\n{\n    ULONG Value;\n    HANDLE ExclusiveWakeEvent;\n    HANDLE SharedWakeEvent;\n} PH_FAST_LOCK, *PPH_FAST_LOCK;\n\n#define PH_FAST_LOCK_INIT { 0, NULL, NULL }\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeFastLock(\n    _Out_ PPH_FAST_LOCK FastLock\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteFastLock(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhAcquireFastLockExclusive PhfAcquireFastLockExclusive\n_May_raise_\n_Acquires_exclusive_lock_(*FastLock)\nPHLIBAPI\nVOID\nFASTCALL\nPhfAcquireFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhAcquireFastLockShared PhfAcquireFastLockShared\n_May_raise_\n_Acquires_shared_lock_(*FastLock)\nPHLIBAPI\nVOID\nFASTCALL\nPhfAcquireFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhReleaseFastLockExclusive PhfReleaseFastLockExclusive\n_Releases_exclusive_lock_(*FastLock)\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhReleaseFastLockShared PhfReleaseFastLockShared\n_Releases_shared_lock_(*FastLock)\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhTryAcquireFastLockExclusive PhfTryAcquireFastLockExclusive\n_When_(return != 0, _Acquires_exclusive_lock_(*FastLock))\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfTryAcquireFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhTryAcquireFastLockShared PhfTryAcquireFastLockShared\n_When_(return != 0, _Acquires_shared_lock_(*FastLock))\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfTryAcquireFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/filepool.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *\n */\n\n#ifndef _PH_FILEPOOL_H\n#define _PH_FILEPOOL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// On-disk structures\n\n// Each file has at least one segment. Each segment has a number of blocks, which are allocated from\n// a bitmap. The segment header is always in the first block of each segment, except for the first\n// segment. In the first segment, the file header is in the first few blocks, followed by the\n// segment header.\n//\n// The segments are placed in a particular free list depending on how many blocks they have free;\n// this allows allocators to simply skip the segments which don't have enough segments free, and\n// allocate new segments if necessary. The free list does not however guarantee that a particular\n// segment has a particular number of contiguous blocks free; low performance can still occur when\n// there is fragmentation.\n\n/** The number of 32-bit integers used for each allocation bitmap. */\n#define PH_FP_BITMAP_SIZE 64\n/** The power-of-two index of the bitmap size. */\n#define PH_FP_BITMAP_SIZE_SHIFT 6\n/** The number of blocks that are available in each segment. */\n#define PH_FP_BLOCK_COUNT (PH_FP_BITMAP_SIZE * 32)\n/** The power-of-two index of the block count. */\n#define PH_FP_BLOCK_COUNT_SHIFT (PH_FP_BITMAP_SIZE_SHIFT + 5)\n/** The number of free lists for segments. */\n#define PH_FP_FREE_LIST_COUNT 8\n\n// Block flags\n/** The block is the beginning of a large allocation (one that spans several segments). */\n#define PH_FP_BLOCK_LARGE_ALLOCATION 0x1\n\ntypedef struct _PH_FP_BLOCK_HEADER\n{\n    ULONG Flags; // PH_FP_BLOCK_*\n    /** The number of blocks in the entire logical block, or the number\n     * of segments in a large allocation. */\n    ULONG Span;\n    QUAD_PTR Body;\n} PH_FP_BLOCK_HEADER, *PPH_FP_BLOCK_HEADER;\n\nC_ASSERT((FIELD_OFFSET(PH_FP_BLOCK_HEADER, Body) % MEMORY_ALLOCATION_ALIGNMENT) == 0);\n\ntypedef struct _PH_FP_SEGMENT_HEADER\n{\n    ULONG Bitmap[PH_FP_BITMAP_SIZE];\n    ULONG FreeBlocks;\n    ULONG FreeFlink;\n    ULONG FreeBlink;\n    ULONG Reserved[13];\n} PH_FP_SEGMENT_HEADER, *PPH_FP_SEGMENT_HEADER;\n\n#define PH_FP_MAGIC ('loPF')\n\ntypedef struct _PH_FP_FILE_HEADER\n{\n    ULONG Magic;\n    ULONG SegmentShift;\n    ULONG SegmentCount;\n    ULONGLONG UserContext;\n    ULONG FreeLists[PH_FP_FREE_LIST_COUNT];\n} PH_FP_FILE_HEADER, *PPH_FP_FILE_HEADER;\n\n// Runtime\n\ntypedef struct _PH_FILE_POOL_PARAMETERS\n{\n    // File options\n\n    /**\n     * The base-2 logarithm of the size of each segment. This value must be between 16 and 28,\n     * inclusive.\n     */\n    ULONG SegmentShift;\n\n    // Runtime options\n\n    /** The maximum number of inactive segments to keep mapped. */\n    ULONG MaximumInactiveViews;\n} PH_FILE_POOL_PARAMETERS, *PPH_FILE_POOL_PARAMETERS;\n\ntypedef struct _PH_FILE_POOL\n{\n    HANDLE FileHandle;\n    HANDLE SectionHandle;\n    BOOLEAN ReadOnly;\n\n    PH_FREE_LIST ViewFreeList;\n    PLIST_ENTRY *ByIndexBuckets;\n    ULONG ByIndexSize;\n    PH_AVL_TREE ByBaseSet;\n\n    ULONG MaximumInactiveViews;\n    ULONG NumberOfInactiveViews;\n    LIST_ENTRY InactiveViewsListHead;\n\n    PPH_FP_BLOCK_HEADER FirstBlockOfFirstSegment;\n    PPH_FP_FILE_HEADER Header;\n    ULONG SegmentShift; // The power-of-two size of each segment\n    ULONG SegmentSize; // The size of each segment\n    ULONG BlockShift; // The power-of-two size of each block in each segment\n    ULONG BlockSize; // The size of each block in each segment\n    ULONG FileHeaderBlockSpan; // The number of blocks needed to store a file header\n    ULONG SegmentHeaderBlockSpan; // The number of blocks needed to store a segment header\n} PH_FILE_POOL, *PPH_FILE_POOL;\n\nPHLIBAPI\nNTSTATUS PhCreateFilePool(\n    _Out_ PPH_FILE_POOL *Pool,\n    _In_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nNTSTATUS PhCreateFilePool2(\n    _Out_ PPH_FILE_POOL *Pool,\n    _In_ PCWSTR FileName,\n    _In_ BOOLEAN ReadOnly,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nVOID PhDestroyFilePool(\n    _In_ _Post_invalid_ PPH_FILE_POOL Pool\n    );\n\nPHLIBAPI\nPVOID PhAllocateFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Size,\n    _Out_opt_ PULONG Rva\n    );\n\nPHLIBAPI\nVOID PhFreeFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Block\n    );\n\nPHLIBAPI\nBOOLEAN PhFreeFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    );\n\nPHLIBAPI\nVOID PhReferenceFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    );\n\nPHLIBAPI\nVOID PhDereferenceFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    );\n\nPHLIBAPI\nPVOID PhReferenceFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    );\n\nPHLIBAPI\nBOOLEAN PhDereferenceFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    );\n\nPHLIBAPI\nULONG PhEncodeRvaFilePool(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    );\n\nPHLIBAPI\nVOID PhGetUserContextFilePool(\n    _In_ PPH_FILE_POOL Pool,\n    _Out_ PULONGLONG Context\n    );\n\nPHLIBAPI\nVOID PhSetUserContextFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PULONGLONG Context\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/filepoolp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2013\n *\n */\n\n#ifndef _PH_FILEPOOLP_H\n#define _PH_FILEPOOLP_H\n\ntypedef struct _PH_FILE_POOL_VIEW\n{\n    LIST_ENTRY ByIndexListEntry;\n    PH_AVL_LINKS ByBaseLinks;\n    LIST_ENTRY InactiveViewsListEntry;\n\n    ULONG RefCount;\n    ULONG SegmentIndex;\n    PVOID Base;\n} PH_FILE_POOL_VIEW, *PPH_FILE_POOL_VIEW;\n\nNTSTATUS PhpValidateFilePoolParameters(\n    _Inout_ PPH_FILE_POOL_PARAMETERS Parameters\n    );\n\nVOID PhpSetDefaultFilePoolParameters(\n    _Out_ PPH_FILE_POOL_PARAMETERS Parameters\n    );\n\n// Range mapping\n\nNTSTATUS PhFppExtendRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG NewSize\n    );\n\nNTSTATUS PhFppMapRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Offset,\n    _In_ ULONG Size,\n    _Out_ PVOID *Base\n    );\n\nNTSTATUS PhFppUnmapRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    );\n\n// Segments\n\nVOID PhFppInitializeSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Out_ PPH_FP_BLOCK_HEADER BlockOfSegmentHeader,\n    _In_ ULONG AdditionalBlocksUsed\n    );\n\nPPH_FP_BLOCK_HEADER PhFppAllocateSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Out_ PULONG NewSegmentIndex\n    );\n\nPPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock\n    );\n\n// Views\n\nVOID PhFppAddViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppRemoveViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nPPH_FILE_POOL_VIEW PhFppFindViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    );\n\n_Function_class_(PH_AVL_TREE_COMPARE_FUNCTION)\nLONG NTAPI PhpFilePoolViewByBaseCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    );\n\nVOID PhFppAddViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppRemoveViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nPPH_FILE_POOL_VIEW PhFppFindViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    );\n\nPPH_FILE_POOL_VIEW PhFppCreateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    );\n\nVOID PhFppDestroyView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppActivateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppDeactivateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppReferenceView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppDereferenceView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nPPH_FP_BLOCK_HEADER PhFppReferenceSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    );\n\nVOID PhFppDereferenceSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    );\n\nVOID PhFppReferenceSegmentByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    );\n\nVOID PhFppDereferenceSegmentByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    );\n\n// Bitmap allocation\n\nPPH_FP_BLOCK_HEADER PhFppAllocateBlocks(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,\n    _In_ ULONG NumberOfBlocks\n    );\n\nVOID PhFppFreeBlocks(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,\n    _In_ PPH_FP_BLOCK_HEADER BlockHeader\n    );\n\n// Free list\n\nULONG PhFppComputeFreeListIndex(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG NumberOfBlocks\n    );\n\nBOOLEAN PhFppInsertFreeList(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG FreeListIndex,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_SEGMENT_HEADER SegmentHeader\n    );\n\nBOOLEAN PhFppRemoveFreeList(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG FreeListIndex,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_SEGMENT_HEADER SegmentHeader\n    );\n\n// Misc.\n\nPPH_FP_BLOCK_HEADER PhFppGetHeaderBlock(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ PVOID Block\n    );\n\nULONG PhFppEncodeRva(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _In_ PVOID Address\n    );\n\nULONG PhFppDecodeRva(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva,\n    _Out_ PULONG SegmentIndex\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/filestream.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *\n */\n\n#ifndef _PH_FILESTREAM_H\n#define _PH_FILESTREAM_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Core flags (PhCreateFileStream2)\n/** Indicates that the file stream object should not close the file handle upon deletion. */\n#define PH_FILE_STREAM_HANDLE_UNOWNED 0x1\n/**\n * Indicates that the file stream object should not buffer I/O operations. Note that this does not\n * prevent the operating system from buffering I/O.\n */\n#define PH_FILE_STREAM_UNBUFFERED 0x2\n/**\n * Indicates that the file handle supports asynchronous operations. The file handle must not have\n * been opened with FILE_SYNCHRONOUS_IO_ALERT or FILE_SYNCHRONOUS_IO_NONALERT.\n */\n#define PH_FILE_STREAM_ASYNCHRONOUS 0x4\n/**\n * Indicates that the file stream object should maintain the file position and not use the file\n * object's own file position.\n */\n#define PH_FILE_STREAM_OWN_POSITION 0x8\n\n// Higher-level flags (PhCreateFileStream)\n#define PH_FILE_STREAM_APPEND 0x00010000\n\n// Internal flags\n/** Indicates that at least one write has been issued to the file handle. */\n#define PH_FILE_STREAM_WRITTEN 0x80000000\n\n// Seek\ntypedef enum _PH_SEEK_ORIGIN\n{\n    SeekStart,\n    SeekCurrent,\n    SeekEnd\n} PH_SEEK_ORIGIN;\n\ntypedef struct _PH_FILE_STREAM\n{\n    HANDLE FileHandle;\n    ULONG Flags;\n    LARGE_INTEGER Position; // file object position, *not* the actual position\n\n    PVOID Buffer;\n    ULONG BufferLength;\n\n    ULONG ReadPosition; // read position in buffer\n    ULONG ReadLength; // how much available to read from buffer\n    ULONG WritePosition; // write position in buffer\n} PH_FILE_STREAM, *PPH_FILE_STREAM;\n\nextern PPH_OBJECT_TYPE PhFileStreamType;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileStream(\n    _Out_ PPH_FILE_STREAM* FileStream,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileStream2(\n    _Out_ PPH_FILE_STREAM *FileStream,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG BufferLength\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhVerifyFileStream(\n    _In_ PPH_FILE_STREAM FileStream\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReadLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFlushFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ BOOLEAN Full\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetPositionFileStream(\n    _In_ PPH_FILE_STREAM FileStream,\n    _Out_ PLARGE_INTEGER Position\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSeekFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Offset,\n    _In_ PH_SEEK_ORIGIN Origin\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLockFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Position,\n    _In_ PLARGE_INTEGER Length,\n    _In_ BOOLEAN Wait,\n    _In_ BOOLEAN Shared\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnlockFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Position,\n    _In_ PLARGE_INTEGER Length\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteStringAsUtf8FileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PPH_STRINGREF String\n    );\n\nFORCEINLINE\nNTSTATUS\nPhWriteStringAsUtf8FileStream2(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PCWSTR String\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, String);\n\n    return PhWriteStringAsUtf8FileStream(FileStream, &string);\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteStringAsUtf8FileStreamEx(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PCWSTR Buffer,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteStringFormatAsUtf8FileStream_V(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ _Printf_format_string_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteStringFormatAsUtf8FileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ _Printf_format_string_ PCWSTR Format,\n    ...\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/filestreamp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#ifndef _PH_FILESTREAMP_H\n#define _PH_FILESTREAMP_H\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpFileStreamDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nNTSTATUS PhpAllocateBufferFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    );\n\nNTSTATUS PhpReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReadLength\n    );\n\nNTSTATUS PhpWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nNTSTATUS PhpFlushReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    );\n\nNTSTATUS PhpFlushWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    );\n\nNTSTATUS PhpSeekFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Offset,\n    _In_ PH_SEEK_ORIGIN Origin\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/graph.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2024\n *\n */\n\n#ifndef _PH_GRAPH_H\n#define _PH_GRAPH_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Graph drawing\n\nextern RECT PhNormalGraphTextMargin;\nextern RECT PhNormalGraphTextPadding;\n\n#define PH_GRAPH_USE_GRID_X 0x1\n#define PH_GRAPH_USE_GRID_Y 0x2\n#define PH_GRAPH_LOGARITHMIC_GRID_Y 0x4\n#define PH_GRAPH_USE_LINE_2 0x10\n#define PH_GRAPH_OVERLAY_LINE_2 0x20\n#define PH_GRAPH_LABEL_MAX_Y 0x1000\n\ntypedef struct _PH_GRAPH_DRAW_INFO *PPH_GRAPH_DRAW_INFO;\n\ntypedef _Function_class_(PH_GRAPH_LABEL_Y_FUNCTION)\nPPH_STRING NTAPI PH_GRAPH_LABEL_Y_FUNCTION(\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataIndex,\n    _In_ FLOAT Value,\n    _In_ FLOAT Parameter\n    );\ntypedef PH_GRAPH_LABEL_Y_FUNCTION* PPH_GRAPH_LABEL_Y_FUNCTION;\n\ntypedef struct _PH_GRAPH_DRAW_INFO\n{\n    // Basic\n    LONG Width;\n    LONG Height;\n    ULONG Flags;\n    ULONG Step;\n    COLORREF BackColor;\n\n    // Data/lines\n    ULONG LineDataCount;\n    PFLOAT LineData1;\n    PFLOAT LineData2;\n    COLORREF LineColor1;\n    COLORREF LineColor2;\n    COLORREF LineBackColor1;\n    COLORREF LineBackColor2;\n\n    // Grid\n    COLORREF GridColor;\n    ULONG GridWidth;\n    FLOAT GridHeight;\n    LONG GridXOffset;\n    LONG GridYThreshold;\n    FLOAT GridBase; // Base for logarithmic grid\n\n    // y-axis label\n    PPH_GRAPH_LABEL_Y_FUNCTION LabelYFunction;\n    FLOAT LabelYFunctionParameter;\n    HFONT LabelYFont;\n    COLORREF LabelYColor;\n    ULONG LabelMaxYIndexLimit;\n\n    // Text\n    PH_STRINGREF Text;\n    RECT TextRect;\n    RECT TextBoxRect;\n    HFONT TextFont;\n    COLORREF TextColor;\n    COLORREF TextBoxColor;\n\n    PH_STRINGREF Text2;\n    RECT TextRect2;\n    RECT TextBoxRect2;\n} PH_GRAPH_DRAW_INFO, *PPH_GRAPH_DRAW_INFO;\n\n// Graph control\n\n#define PH_GRAPH_CLASSNAME L\"PhGraph\"\n\nPHLIBAPI\nRTL_ATOM\nNTAPI\nPhGraphControlInitialization(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDrawGraphDirect(\n    _In_ HDC hdc,\n    _In_ PVOID Bits,\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetGraphText(\n    _In_ HDC hdc,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text,\n    _In_ PRECT Margin,\n    _In_ PRECT Padding,\n    _In_ ULONG Align\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetGraphText2(\n    _In_ HDC hdc,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text,\n    _In_ PRECT Margin,\n    _In_ PRECT Padding,\n    _In_ ULONG Align\n    );\n\n// Configuration\n\ntypedef struct _PH_GRAPH_OPTIONS\n{\n    COLORREF FadeOutBackColor;\n    LONG FadeOutWidth;\n    HCURSOR DefaultCursor;\n} PH_GRAPH_OPTIONS, *PPH_GRAPH_OPTIONS;\n\n// Styles\n\n#define GC_STYLE_FADEOUT 0x1\n#define GC_STYLE_DRAW_PANEL 0x2\n\n// Messages\n\n#define GCM_GETDRAWINFO (WM_USER + 1301)\n#define GCM_SETDRAWINFO (WM_USER + 1302)\n#define GCM_DRAW (WM_USER + 1303)\n#define GCM_MOVEGRID (WM_USER + 1304)\n#define GCM_GETBUFFEREDCONTEXT (WM_USER + 1305)\n#define GCM_SETTOOLTIP (WM_USER + 1306)\n#define GCM_UPDATETOOLTIP (WM_USER + 1307)\n#define GCM_GETOPTIONS (WM_USER + 1308)\n#define GCM_SETOPTIONS (WM_USER + 1309)\n#define GCM_UPDATE (WM_USER + 1310)\n#define GCM_SETCALLBACK (WM_USER + 1311)\n\n#define Graph_GetDrawInfo(hWnd, DrawInfo) \\\n    SendMessage((hWnd), GCM_GETDRAWINFO, 0, (LPARAM)(DrawInfo))\n#define Graph_SetDrawInfo(hWnd, DrawInfo) \\\n    SendMessage((hWnd), GCM_SETDRAWINFO, 0, (LPARAM)(DrawInfo))\n#define Graph_Draw(hWnd) \\\n    SendMessage((hWnd), GCM_DRAW, 0, 0)\n#define Graph_MoveGrid(hWnd, Increment) \\\n    SendMessage((hWnd), GCM_MOVEGRID, (WPARAM)(Increment), 0)\n#define Graph_GetBufferedContext(hWnd) \\\n    ((HDC)SendMessage((hWnd), GCM_GETBUFFEREDCONTEXT, 0, 0))\n#define Graph_SetTooltip(hWnd, Enable) \\\n    ((HDC)SendMessage((hWnd), GCM_SETTOOLTIP, (WPARAM)(Enable), 0))\n#define Graph_UpdateTooltip(hWnd) \\\n    ((HDC)SendMessage((hWnd), GCM_UPDATETOOLTIP, 0, 0))\n#define Graph_GetOptions(hWnd, Options) \\\n    SendMessage((hWnd), GCM_GETOPTIONS, 0, (LPARAM)(Options))\n#define Graph_SetOptions(hWnd, Options) \\\n    SendMessage((hWnd), GCM_SETOPTIONS, 0, (LPARAM)(Options))\n#define Graph_Update(hWnd) \\\n    SendMessage((hWnd), GCM_UPDATE, 0, 0)\n#define Graph_SetCallback(hWnd, Callback, Context) \\\n    SendMessage((hWnd), GCM_SETCALLBACK, (LPARAM)(Callback), (WPARAM)(Context))\n\n// Notifications\n\n#define GCN_GETDRAWINFO (WM_USER + 1351)\n#define GCN_GETTOOLTIPTEXT (WM_USER + 1352)\n#define GCN_MOUSEEVENT (WM_USER + 1353)\n#define GCN_DRAWPANEL (WM_USER + 1354)\n\ntypedef _Function_class_(PH_GRAPH_MESSAGE_CALLBACK)\nBOOLEAN NTAPI PH_GRAPH_MESSAGE_CALLBACK(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_GRAPH_MESSAGE_CALLBACK* PPH_GRAPH_MESSAGE_CALLBACK;\n\ntypedef struct _PH_GRAPH_CREATEPARAMS\n{\n    ULONG Size;\n    ULONG Flags;\n    PH_GRAPH_OPTIONS Options;\n    PPH_GRAPH_MESSAGE_CALLBACK Callback;\n    PVOID Context;\n    // Add new fields here.\n} PH_GRAPH_CREATEPARAMS, *PPH_GRAPH_CREATEPARAMS;\n\ntypedef struct _PH_GRAPH_GETDRAWINFO\n{\n    NMHDR Header;\n    PPH_GRAPH_DRAW_INFO DrawInfo;\n} PH_GRAPH_GETDRAWINFO, *PPH_GRAPH_GETDRAWINFO;\n\ntypedef struct _PH_GRAPH_GETTOOLTIPTEXT\n{\n    NMHDR Header;\n    ULONG Index;\n    ULONG TotalCount;\n\n    PH_STRINGREF Text; // must be null-terminated\n} PH_GRAPH_GETTOOLTIPTEXT, *PPH_GRAPH_GETTOOLTIPTEXT;\n\ntypedef struct _PH_GRAPH_MOUSEEVENT\n{\n    NMHDR Header;\n    ULONG Index;\n    ULONG TotalCount;\n\n    ULONG Message;\n    ULONG Keys;\n    POINT Point;\n} PH_GRAPH_MOUSEEVENT, *PPH_GRAPH_MOUSEEVENT;\n\ntypedef struct _PH_GRAPH_DRAWPANEL\n{\n    NMHDR Header;\n    HDC hdc;\n    RECT Rect;\n} PH_GRAPH_DRAWPANEL, *PPH_GRAPH_DRAWPANEL;\n\n// Graph buffer management\n\n#define PH_GRAPH_DATA_COUNT(Width, Step) (((Width) + (Step) - 1) / (Step) + 1) // round up in division\n\ntypedef struct _PH_GRAPH_BUFFERS\n{\n    PFLOAT Data1; // invalidate by setting Valid to FALSE\n    PFLOAT Data2; // invalidate by setting Valid to FALSE\n    ULONG AllocatedCount;\n    BOOLEAN Valid; // indicates the data is valid\n} PH_GRAPH_BUFFERS, *PPH_GRAPH_BUFFERS;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeGraphBuffers(\n    _Out_ PPH_GRAPH_BUFFERS Buffers\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteGraphBuffers(\n    _Inout_ PPH_GRAPH_BUFFERS Buffers\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetDrawInfoGraphBuffers(\n    _Inout_ PPH_GRAPH_BUFFERS Buffers,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataCount\n    );\n\n// Graph control state\n\n// The basic buffer management structure was moved out of this section because\n// the text management is not needed for most cases.\n\ntypedef struct _PH_GRAPH_STATE\n{\n    // Union for compatibility\n    union\n    {\n        struct\n        {\n            PFLOAT Data1; // invalidate by setting Valid to FALSE\n            PFLOAT Data2; // invalidate by setting Valid to FALSE\n            ULONG AllocatedCount;\n            BOOLEAN Valid; // indicates the data is valid\n        };\n        PH_GRAPH_BUFFERS Buffers;\n    };\n\n    PPH_STRING Text;\n    PPH_STRING TooltipText; // invalidate by setting TooltipIndex to -1\n    ULONG TooltipIndex; // indicates the tooltip text is valid for this index\n    PPH_STRING TextLine2;\n} PH_GRAPH_STATE, *PPH_GRAPH_STATE;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeGraphState(\n    _Out_ PPH_GRAPH_STATE State\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteGraphState(\n    _Inout_ PPH_GRAPH_STATE State\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGraphStateGetDrawInfo(\n    _Inout_ PPH_GRAPH_STATE State,\n    _In_ PPH_GRAPH_GETDRAWINFO GetDrawInfo,\n    _In_ ULONG DataCount\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/guisup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_PHGUI_H\n#define _PH_PHGUI_H\n\n#include <commctrl.h>\n#include <guisupview.h>\n\nEXTERN_C_START\n\n// guisup\n\n#define RFF_NOBROWSE 0x0001\n#define RFF_NODEFAULT 0x0002\n#define RFF_CALCDIRECTORY 0x0004\n#define RFF_NOLABEL 0x0008\n#define RFF_NOSEPARATEMEM 0x0020\n#define RFF_OPTRUNAS 0x0040\n\n#define RFN_VALIDATE (-510)\n#define RFN_LIMITEDRUNAS (-511)\n\ntypedef struct _NMRUNFILEDLGW\n{\n    NMHDR hdr;\n    PWSTR lpszFile;\n    PWSTR lpszDirectory;\n    UINT ShowCmd;\n} NMRUNFILEDLGW, *LPNMRUNFILEDLGW, *PNMRUNFILEDLGW;\n\ntypedef NMRUNFILEDLGW NMRUNFILEDLG;\ntypedef PNMRUNFILEDLGW PNMRUNFILEDLG;\ntypedef LPNMRUNFILEDLGW LPNMRUNFILEDLG;\n\n#define RF_OK 0x0000\n#define RF_CANCEL 0x0001\n#define RF_RETRY 0x0002\n\ntypedef HANDLE HTHEME;\n\n#define DCX_USESTYLE 0x00010000\n#define DCX_NODELETERGN 0x00040000\n\n#define HRGN_FULL ((HRGN)1) // passed by WM_NCPAINT even though it's completely undocumented (wj32)\n\nextern LONG PhFontQuality;\nextern LONG PhSystemDpi;\nextern PH_INTEGER_PAIR PhSmallIconSize;\nextern PH_INTEGER_PAIR PhLargeIconSize;\n\nPHLIBAPI\nVOID\nNTAPI\nPhGuiSupportInitialization(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGuiSupportUpdateSystemMetrics(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ LONG WindowDpi\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhGetFontQualitySetting(\n    _In_ LONG FontQuality\n    );\n\nPHLIBAPI\nHFONT\nNTAPI\nPhInitializeFont(\n    _In_ LONG WindowDpi\n    );\n\nPHLIBAPI\nHFONT\nNTAPI\nPhInitializeMonospaceFont(\n    _In_ LONG WindowDpi\n    );\n\nPHLIBAPI\nHDC\nNTAPI\nPhGetDC(\n    _In_opt_ HWND WindowHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhReleaseDC(\n    _In_opt_ HWND WindowHandle,\n    _In_ _Frees_ptr_ HDC Hdc\n    );\n\nPHLIBAPI\nHGDIOBJ\nNTAPI\nPhGetStockObject(\n    _In_ LONG Index\n    );\n\n#define PhGetStockBrush(i) ((HBRUSH)PhGetStockObject(i))\n#define PhGetStockPen(i) ((HPEN)PhGetStockObject(i))\n\nPHLIBAPI\nHTHEME\nNTAPI\nPhOpenThemeData(\n    _In_opt_ HWND WindowHandle,\n    _In_ PCWSTR ClassList,\n    _In_ LONG WindowDpi\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhCloseThemeData(\n    _In_ HTHEME ThemeHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetControlTheme(\n    _In_ HWND Handle,\n    _In_opt_ PCWSTR Theme\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsThemeActive(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsAppThemed(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsThemePartDefined(\n    _In_ HTHEME ThemeHandle,\n    _In_ LONG PartId,\n    _In_ LONG StateId\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetThemeClass(\n    _In_ HTHEME ThemeHandle,\n    _Out_writes_z_(ClassLength) PWSTR Class,\n    _In_ ULONG ClassLength\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetThemeColor(\n    _In_ HTHEME ThemeHandle,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_ LONG PropId,\n    _Out_ COLORREF* Color\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetThemeInt(\n    _In_ HTHEME ThemeHandle,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_ LONG PropId,\n    _Out_ PLONG Value\n    );\n\ntypedef enum _THEMEPARTSIZE\n{\n    THEMEPARTSIZE_MIN, // minimum size\n    THEMEPARTSIZE_TRUE, // size without stretching\n    THEMEPARTSIZE_DRAW // size that theme mgr will use to draw part\n} THEMEPARTSIZE;\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetThemePartSize(\n    _In_ HTHEME ThemeHandle,\n    _In_opt_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_opt_ LPCRECT Rect,\n    _In_ THEMEPARTSIZE Flags,\n    _Out_ PSIZE Size\n    );\n\ntypedef struct _THEMEMARGINS\n{\n    LONG cxLeftWidth;      // width of left border that retains its size\n    LONG cxRightWidth;     // width of right border that retains its size\n    LONG cyTopHeight;      // height of top border that retains its size\n    LONG cyBottomHeight;   // height of bottom border that retains its size\n} THEMEMARGINS, *PTHEMEMARGINS;\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetThemeMargins(\n    _In_ HTHEME ThemeHandle,\n    _In_opt_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_ LONG PropId,\n    _In_opt_ LPCRECT Rect,\n    _Out_ PTHEMEMARGINS Margins\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDrawThemeBackground(\n    _In_ HTHEME ThemeHandle,\n    _In_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_ LPCRECT Rect,\n    _In_opt_ LPCRECT ClipRect\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDrawThemeText(\n    _In_ HTHEME ThemeHandle,\n    _In_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_reads_(cchText) PCWSTR Text,\n    _In_ LONG cchText,\n    _In_ ULONG TextFlags,\n    _In_ LPCRECT Rect\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDrawThemeTextEx(\n    _In_ HTHEME ThemeHandle,\n    _In_ HDC hdc,\n    _In_ LONG PartId,\n    _In_ LONG StateId,\n    _In_reads_(cchText) PCWSTR Text,\n    _In_ LONG cchText,\n    _In_ ULONG TextFlags,\n    _Inout_ LPRECT Rect,\n    _In_opt_ const PVOID Options // DTTOPTS*\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsThemeBackgroundPartiallyTransparent(\n    _In_ HTHEME ThemeHandle,\n    _In_ LONG PartId,\n    _In_ LONG StateId\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDrawThemeParentBackground(\n    _In_ HWND WindowHandle,\n    _In_ HDC Hdc,\n    _In_opt_ const PRECT Rect\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhAllowDarkModeForWindow(\n    _In_ HWND WindowHandle,\n    _In_ BOOL Enabled\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsDarkModeAllowedForWindow(\n    _In_ HWND WindowHandle\n    );\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhRectEmpty(\n    _In_ PRECT Rect\n    )\n{\n#if defined(PHNT_NATIVE_RECT)\n    return !!IsRectEmpty(Rect);\n#else\n    if (Rect)\n    {\n        if (Rect->left >= Rect->right || Rect->top >= Rect->bottom)\n            return TRUE;\n    }\n\n    return FALSE;\n#endif\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhInflateRect(\n    _In_ PRECT Rect,\n    _In_ LONG dx,\n    _In_ LONG dy\n    )\n{\n#if defined(PHNT_NATIVE_RECT)\n    return !!InflateRect(Rect, dx, dy);\n#else\n    Rect->left -= dx;\n    Rect->top -= dy;\n    Rect->right += dx;\n    Rect->bottom += dy;\n    return TRUE;\n#endif\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhOffsetRect(\n    _In_ PRECT Rect,\n    _In_ LONG dx,\n    _In_ LONG dy\n    )\n{\n#if defined(PHNT_NATIVE_RECT)\n    return !!OffsetRect(Rect, dx, dy);\n#else\n    Rect->left += dx;\n    Rect->top += dy;\n    Rect->right += dx;\n    Rect->bottom += dy;\n    return TRUE;\n#endif\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhPtInRect(\n    _In_ PRECT Rect,\n    _In_ PPOINT Point\n    )\n{\n#if defined(PHNT_NATIVE_RECT)\n    return !!PtInRect(Rect, Point);\n#else\n    return Point->x >= Rect->left && Point->x < Rect->right &&\n        Point->y >= Rect->top && Point->y < Rect->bottom;\n#endif\n}\n\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhGetWindowRect(\n    _In_ HWND WindowHandle,\n    _Out_ PRECT WindowRect\n    )\n{\n    // Note: GetWindowRect can return success with either invalid (0,0) or empty rects (40,40) and in some cases\n    // this results in unwanted clipping, performance issues with the CreateCompatibleBitmap double buffering and\n    // issues with MonitorFromRect layout and DPI queries, so ignore the return status and check the rect (dmex)\n\n    if (!GetWindowRect(WindowHandle, WindowRect))\n        return FALSE;\n\n    if (PhRectEmpty(WindowRect))\n        return FALSE;\n\n    return TRUE;\n}\n\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhGetClientRect(\n    _In_ HWND WindowHandle,\n    _Out_ PRECT ClientRect\n    )\n{\n    if (!GetClientRect(WindowHandle, ClientRect))\n        return FALSE;\n\n    if (!(ClientRect->right && ClientRect->bottom))\n        return FALSE;\n\n    return TRUE;\n}\n\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhGetCursorPos(\n    _Out_ PPOINT Point\n    )\n{\n    if (GetCursorPos(Point))\n        return TRUE;\n\n    return FALSE;\n}\n\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhGetMessagePos(\n    _Out_ PPOINT MessagePoint\n    )\n{\n    ULONG position;\n    POINT point;\n\n    position = GetMessagePos();\n    point.x = GET_X_LPARAM(position);\n    point.y = GET_Y_LPARAM(position);\n    memcpy(MessagePoint, &point, sizeof(POINT));\n    return TRUE;\n}\n\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhGetClientPos(\n    _In_ HWND WindowHandle,\n    _Out_ PPOINT ClientPoint\n    )\n{\n    ULONG position;\n    POINT point;\n\n    position = GetMessagePos();\n    point.x = GET_X_LPARAM(position);\n    point.y = GET_Y_LPARAM(position);\n\n    if (ScreenToClient(WindowHandle, &point))\n    {\n        memcpy(ClientPoint, &point, sizeof(POINT));\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhGetScreenPos(\n    _In_ HWND WindowHandle,\n    _Out_ PPOINT ClientPoint\n    )\n{\n    ULONG position;\n    POINT point;\n\n    position = GetMessagePos();\n    point.x = GET_X_LPARAM(position);\n    point.y = GET_Y_LPARAM(position);\n\n    if (ClientToScreen(WindowHandle, &point))\n    {\n        memcpy(ClientPoint, &point, sizeof(POINT));\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhClientToScreen(\n    _In_ HWND WindowHandle,\n    _Inout_ PPOINT Point\n    )\n{\n    if (ClientToScreen(WindowHandle, Point))\n        return TRUE;\n    return FALSE;\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhScreenToClient(\n    _In_ HWND WindowHandle,\n    _Inout_ PPOINT Point\n    )\n{\n    if (ScreenToClient(WindowHandle, Point))\n        return TRUE;\n    return FALSE;\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhClientToScreenRect(\n    _In_ HWND WindowHandle,\n    _Inout_ PRECT Rect\n    )\n{\n    //if (!ClientToScreen(WindowHandle, (PPOINT)Rect))\n    //    return FALSE;\n    //if (!ClientToScreen(WindowHandle, ((PPOINT)Rect) + 1))\n    //    return FALSE;\n\n    if (MapWindowRect(WindowHandle, HWND_DESKTOP, Rect) == 0)\n        return FALSE;\n\n    return TRUE;\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhScreenToClientRect(\n    _In_ HWND WindowHandle,\n    _Inout_ PRECT Rect\n    )\n{\n    if (MapWindowRect(HWND_DESKTOP, WindowHandle, Rect) == 0)\n        return FALSE;\n\n    return TRUE;\n\n    //if (!ScreenToClient(WindowHandle, (PPOINT)Rect))\n    //    return FALSE;\n    //if (!ScreenToClient(WindowHandle, ((PPOINT)Rect) + 1))\n    //    return FALSE;\n    //return TRUE;\n}\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsHungAppWindow(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nHWND\nNTAPI\nPhGetShellWindow(\n    VOID\n    );\n\n/**\n * Converts default logical units (based on 96 DPI) to physical units appropriate for the current current monitor's display DPI.\n * \\param Value The value to scale.\n * \\param Scale The target DPI scale.\n * \\return The scaled value.\n */\nFORCEINLINE\nLONG\nNTAPI\nPhScaleToDisplay(\n    _In_ LONG Value,\n    _In_ LONG Scale\n    )\n{\n    return PhMultiplyDivideSigned(Value, Scale, USER_DEFAULT_SCREEN_DPI);\n}\n\n/**\n * Converts a value from physical units (current DPI) to default logical units (based on 96 DPI).\n *\n * \\param Value The value to convert from physical units.\n * \\param Scale The current DPI scale.\n * \\return The value converted to default logical units (96 DPI).\n */\nFORCEINLINE\nLONG\nNTAPI\nPhScaleToDefault(\n    _In_ LONG Value,\n    _In_ LONG Scale\n    )\n{\n    return PhMultiplyDivideSigned(Value, USER_DEFAULT_SCREEN_DPI, Scale);\n}\n\nFORCEINLINE\nLONG\nNTAPI\nPhGetDpi(\n    _In_ LONG Value,\n    _In_ LONG Scale\n    )\n{\n    return PhMultiplyDivideSigned(Value, Scale, USER_DEFAULT_SCREEN_DPI);\n}\n\nPHLIBAPI\nLONG\nNTAPI\nPhGetMonitorDpi(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PRECT WindowRect\n    );\n\nFORCEINLINE\nLONG\nPhGetMonitorDpiFromRect(\n    _In_ PPH_RECTANGLE Rectangle\n    )\n{\n    RECT rect = { 0 };\n\n    PhRectangleToRect(&rect, Rectangle);\n\n    return PhGetMonitorDpi(NULL, &rect);\n}\n\nPHLIBAPI\nLONG\nNTAPI\nPhGetSystemDpi(\n    VOID\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhGetTaskbarDpi(\n    VOID\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhGetWindowDpi(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhGetDpiValue(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PRECT WindowRect\n    );\n\nFORCEINLINE\nVOID\nPhGetSizeDpiValue(\n    _Inout_ PRECT Rect,\n    _In_ LONG Dpi,\n    _In_ BOOLEAN ScaleToDisplay\n    )\n{\n    PH_RECTANGLE rect;\n\n    if (Dpi == USER_DEFAULT_SCREEN_DPI)\n        return;\n\n    PhRectToRectangle(&rect, Rect);\n\n    if (ScaleToDisplay)\n    {\n        if (rect.Left)\n            rect.Left = PhScaleToDisplay(rect.Left, Dpi);\n        if (rect.Top)\n            rect.Top = PhScaleToDisplay(rect.Top, Dpi);\n        if (rect.Width)\n            rect.Width = PhScaleToDisplay(rect.Width, Dpi);\n        if (rect.Height)\n            rect.Height = PhScaleToDisplay(rect.Height, Dpi);\n    }\n    else\n    {\n        if (rect.Left)\n            rect.Left = PhScaleToDefault(rect.Left, Dpi);\n        if (rect.Top)\n            rect.Top = PhScaleToDefault(rect.Top, Dpi);\n        if (rect.Width)\n            rect.Width = PhScaleToDefault(rect.Width, Dpi);\n        if (rect.Height)\n            rect.Height = PhScaleToDefault(rect.Height, Dpi);\n    }\n\n    PhRectangleToRect(Rect, &rect);\n}\n\nPHLIBAPI\nLONG\nNTAPI\nPhGetSystemMetrics(\n    _In_ LONG Index,\n    _In_opt_ LONG DpiValue\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetSystemSafeBootMode(\n    VOID\n    );\n\nPHLIBAPI\nBOOL\nNTAPI\nPhGetSystemParametersInfo(\n    _In_ LONG Action,\n    _In_ ULONG Param1,\n    _Pre_maybenull_ _Post_valid_ PVOID Param2,\n    _In_opt_ LONG DpiValue\n    );\n\nFORCEINLINE\nULONG\nPhGetClassStyle(\n    _In_ HWND WindowHandle\n    )\n{\n    return (ULONG)GetClassLongPtr(WindowHandle, GCL_STYLE);\n}\n\nFORCEINLINE\nVOID\nPhSetClassStyle(\n    _In_ HWND Handle,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    )\n{\n    ULONG style;\n\n    style = (ULONG)GetClassLongPtr(Handle, GCL_STYLE);\n    style = (style & ~Mask) | (Value & Mask);\n    SetClassLongPtr(Handle, GCL_STYLE, style);\n}\n\nFORCEINLINE\nULONG\nPhGetWindowStyle(\n    _In_ HWND WindowHandle\n    )\n{\n    return (ULONG)GetWindowLongPtr(WindowHandle, GWL_STYLE);\n}\n\nFORCEINLINE\nULONG\nPhGetWindowStyleEx(\n    _In_ HWND WindowHandle\n    )\n{\n    return (ULONG)GetWindowLongPtr(WindowHandle, GWL_EXSTYLE);\n}\n\nFORCEINLINE VOID PhSetWindowStyle(\n    _In_ HWND Handle,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    )\n{\n    ULONG style;\n\n    style = (ULONG)GetWindowLongPtr(Handle, GWL_STYLE);\n    style = (style & ~Mask) | (Value & Mask);\n    SetWindowLongPtr(Handle, GWL_STYLE, style);\n}\n\nFORCEINLINE VOID PhSetWindowExStyle(\n    _In_ HWND Handle,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    )\n{\n    ULONG style;\n\n    style = (ULONG)GetWindowLongPtr(Handle, GWL_EXSTYLE);\n    style = (style & ~Mask) | (Value & Mask);\n    SetWindowLongPtr(Handle, GWL_EXSTYLE, style);\n}\n\nFORCEINLINE WNDPROC PhGetWindowProcedure(\n    _In_ HWND WindowHandle\n    )\n{\n    return (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC);\n}\n\nFORCEINLINE WNDPROC PhSetWindowProcedure(\n    _In_ HWND WindowHandle,\n    _In_ WNDPROC SubclassProcedure\n    )\n{\n    return (WNDPROC)SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)SubclassProcedure);\n}\n\nFORCEINLINE BOOL PhGetClassInfo(\n    _In_opt_ HINSTANCE Instance,\n    _In_ PCWSTR ClassName,\n    _Out_ PWNDCLASS WindowClass\n    )\n{\n    return GetClassInfo(Instance, ClassName, WindowClass);\n}\n\nFORCEINLINE RTL_ATOM PhGetClassInfoEx(\n    _In_opt_ HINSTANCE Instance,\n    _In_ PCWSTR ClassName,\n    _Out_ PWNDCLASSEX WindowClass\n    )\n{\n    // Note: GetClassInfoEx returns BOOL but contains the RTL_ATOM (dmex)\n    return (RTL_ATOM)GetClassInfoEx(Instance, ClassName, WindowClass);\n}\n\n#define PH_WINDOW_TIMER_DEFAULT 0xF\n\nFORCEINLINE ULONG_PTR PhSetTimer(\n    _In_ HWND WindowHandle,\n    _In_ ULONG_PTR TimerID,\n    _In_ ULONG Elapse,\n    _In_opt_ TIMERPROC TimerProcedure\n    )\n{\n    assert(WindowHandle);\n    return SetTimer(WindowHandle, TimerID, Elapse, TimerProcedure);\n}\n\nFORCEINLINE BOOL PhKillTimer(\n    _In_ HWND WindowHandle,\n    _In_ ULONG_PTR TimerID\n    )\n{\n    assert(WindowHandle);\n    return KillTimer(WindowHandle, TimerID);\n}\n\nFORCEINLINE VOID PhBringWindowToTop(\n    _In_ HWND WindowHandle\n    )\n{\n    // Move the window to the top of the Z-order. (dmex)\n    // This is a workaround for a Windows or third party issue breaking\n    // SetForegroundWindow and displaying the main window behind other programs.\n    // https://github.com/winsiderss/systeminformer/issues/639\n\n    SetWindowPos(\n        WindowHandle,\n        HWND_TOP,\n        0, 0, 0, 0,\n        SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE\n        );\n}\n\n#define IDC_DIVIDER MAKEINTRESOURCE(106) // comctl32.dll\n\nFORCEINLINE\nHCURSOR\nNTAPI\nPhLoadCursor(\n    _In_opt_ PVOID BaseAddress,\n    _In_ PCWSTR CursorName\n    )\n{\n    return (HCURSOR)LoadImage((HINSTANCE)BaseAddress, CursorName, IMAGE_CURSOR, 0, 0, LR_SHARED);\n    //return LoadCursor((HINSTANCE)BaseAddress, CursorName);\n}\n\nFORCEINLINE\nHCURSOR\nNTAPI\nPhGetCursor(\n    VOID\n    )\n{\n    return GetCursor();\n}\n\nFORCEINLINE\nHCURSOR\nNTAPI\nPhSetCursor(\n    _In_opt_ HCURSOR CursorHandle\n    )\n{\n    return SetCursor(CursorHandle);\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhGetKeyState(\n    _In_ LONG VirtualKey\n    )\n{\n    return GetKeyState(VirtualKey) < 0;\n}\n\n#ifndef WM_REFLECT\n#define WM_REFLECT 0x2000\n#endif\n\nFORCEINLINE LRESULT PhReflectMessage(\n    _In_ HWND Handle,\n    _In_ ULONG Message,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    if (Message == WM_NOTIFY)\n    {\n        LPNMHDR header = (LPNMHDR)lParam;\n\n        if (header->hwndFrom == Handle)\n            return SendMessage(Handle, WM_REFLECT + Message, wParam, lParam);\n    }\n\n    return 0;\n}\n\n#define REFLECT_MESSAGE(hwnd, msg, wParam, lParam) \\\n    { \\\n        LRESULT result_ = PhReflectMessage(hwnd, msg, wParam, lParam); \\\n        \\\n        if (result_) \\\n            return result_; \\\n    }\n\n#define REFLECT_MESSAGE_DLG(WindowHandle, hwnd, msg, wParam, lParam) \\\n    { \\\n        LRESULT result_ = PhReflectMessage(hwnd, msg, wParam, lParam); \\\n        \\\n        if (result_) \\\n        { \\\n            SetWindowLongPtr(WindowHandle, DWLP_MSGRESULT, result_); \\\n            return TRUE; \\\n        } \\\n    }\n\nFORCEINLINE VOID PhSetListViewStyle(\n    _In_ HWND Handle,\n    _In_ BOOLEAN AllowDragDrop,\n    _In_ BOOLEAN ShowLabelTips\n    )\n{\n    ULONG style;\n\n    style = LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP;\n\n    if (AllowDragDrop)\n        style |= LVS_EX_HEADERDRAGDROP;\n    if (ShowLabelTips)\n        style |= LVS_EX_LABELTIP;\n\n    ListView_SetExtendedListViewStyleEx(\n        Handle,\n        style,\n        INT_ERROR\n        );\n}\n\nPHLIBAPI\nLONG\nNTAPI\nPhAddListViewColumnDpi(\n    _In_ HWND ListViewHandle,\n    _In_ LONG ListViewDpi,\n    _In_ LONG Index,\n    _In_ LONG DisplayIndex,\n    _In_ LONG SubItemIndex,\n    _In_ LONG Format,\n    _In_ LONG Width,\n    _In_ PCWSTR Text\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhAddListViewColumn(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG DisplayIndex,\n    _In_ LONG SubItemIndex,\n    _In_ LONG Format,\n    _In_ LONG Width,\n    _In_ PCWSTR Text\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhAddListViewItem(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhFindListViewItemByFlags(\n    _In_ HWND ListViewHandle,\n    _In_ LONG StartIndex,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhFindListViewItemByParam(\n    _In_ HWND ListViewHandle,\n    _In_ LONG StartIndex,\n    _In_opt_ PVOID Param\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetListViewItemImageIndex(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _Out_ PLONG ImageIndex\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetListViewItemParam(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _Outptr_ PVOID *Param\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSetListViewItemParam(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ PVOID Param\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveListViewItem(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetListViewItemImageIndex(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG ImageIndex\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetListViewSubItem(\n    _In_ HWND ListViewHandle,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex,\n    _In_ PCWSTR Text\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRedrawListViewItems(\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhAddListViewGroup(\n    _In_ HWND ListViewHandle,\n    _In_ LONG GroupId,\n    _In_ PCWSTR Text\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhAddListViewGroupItem(\n    _In_ HWND ListViewHandle,\n    _In_ LONG GroupId,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhAddTabControlTab(\n    _In_ HWND TabControlHandle,\n    _In_ LONG Index,\n    _In_ PCWSTR Text\n    );\n\n#define PhaGetDlgItemText(WindowHandle, id) \\\n    PH_AUTO_T(PH_STRING, PhGetWindowText(GetDlgItem(WindowHandle, id)))\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetWindowText(\n    _In_ HWND WindowHandle\n    );\n\n#define PhaGetWindowText(WindowHandle) \\\n    PH_AUTO_T(PH_STRING, PhGetWindowText(WindowHandle))\n\n#define PH_GET_WINDOW_TEXT_INTERNAL 0x1\n#define PH_GET_WINDOW_TEXT_LENGTH_ONLY 0x2\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetWindowTextEx(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags,\n    _Out_opt_ PPH_STRING *Text\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetWindowTextToBuffer(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_opt_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nFORCEINLINE\nVOID\nNTAPI\nPhAddComboBoxStrings(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR* Strings,\n    _In_ ULONG NumberOfStrings\n    )\n{\n    for (ULONG i = 0; i < NumberOfStrings; i++)\n        ComboBox_AddString(WindowHandle, Strings[i]);\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhAddComboBoxStringRefs(\n    _In_ HWND WindowHandle,\n    _In_ CONST PCPH_STRINGREF* Strings,\n    _In_ ULONG NumberOfStrings\n    )\n{\n    for (ULONG i = 0; i < NumberOfStrings; i++)\n        ComboBox_AddString(WindowHandle, Strings[i]->Buffer);\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetClassName(\n    _In_ HWND WindowHandle,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetComboBoxString(\n    _In_ HWND WindowHandle,\n    _In_ LONG Index\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhSelectComboBoxString(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR String,\n    _In_ BOOLEAN Partial\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteComboBoxStrings(\n    _In_ HWND ComboBoxHandle,\n    _In_ BOOLEAN ResetContent\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetListBoxString(\n    _In_ HWND WindowHandle,\n    _In_ LONG Index\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetStateAllListViewItems(\n    _In_ HWND WindowHandle,\n    _In_ ULONG State,\n    _In_ ULONG Mask\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetSelectedListViewItemParam(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetSelectedListViewItemParams(\n    _In_ HWND WindowHandle,\n    _Out_ PVOID **Items,\n    _Out_ PULONG NumberOfItems\n    );\n\nFORCEINLINE\nIListView*\nNTAPI\nPhGetListViewInterface(\n    _In_ HWND ListViewHandle\n    )\n{\n    IListView* listviewInterface = NULL;\n\n    SendMessage(\n        ListViewHandle,\n        LVM_QUERYINTERFACE,\n        (WPARAM)&IID_IListView,\n        (LPARAM)&listviewInterface\n        );\n\n    return listviewInterface;\n}\n\n#define PhDestroyListViewInterface(ListViewClass) \\\n    if (ListViewClass) IListView_Release((struct IListView*)(ListViewClass));\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetImageListBitmap(\n    _In_ HIMAGELIST ImageList,\n    _In_ LONG Index,\n    _In_ HINSTANCE InstanceHandle,\n    _In_ PCWSTR BitmapName\n    );\n\n#define PH_LOAD_ICON_SHARED 0x1\n#define PH_LOAD_ICON_SIZE_SMALL 0x2\n#define PH_LOAD_ICON_SIZE_LARGE 0x4\n#define PH_LOAD_ICON_STRICT 0x8\n\nPHLIBAPI\nHICON\nNTAPI\nPhLoadIcon(\n    _In_opt_ PVOID ImageBaseAddress,\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ LONG Width,\n    _In_opt_ LONG Height,\n    _In_opt_ LONG SystemDpi\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetStockApplicationIcon(\n    _Out_opt_ HICON *SmallIcon,\n    _Out_opt_ HICON *LargeIcon\n    );\n\n//PHLIBAPI\n//HICON PhGetFileShellIcon(\n//    _In_opt_ PWSTR FileName,\n//    _In_opt_ PWSTR DefaultExtension,\n//    _In_ BOOLEAN LargeIcon\n//    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetClipboardString(\n    _In_ HWND WindowHandle,\n    _In_ PCPH_STRINGREF String\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetClipboardString(\n    _In_ HWND WindowHandle\n    );\n\n#include <pshpack1.h>\ntypedef struct _DLGTEMPLATEEX\n{\n    USHORT dlgVer;\n    USHORT signature;\n    ULONG helpID;\n    ULONG exStyle;\n    ULONG style;\n    USHORT cDlgItems;\n    SHORT x;\n    SHORT y;\n    SHORT cx;\n    SHORT cy;\n    //sz_Or_Ord menu;\n    //sz_Or_Ord windowClass;\n    //WCHAR title[titleLen];\n    //USHORT pointsize;\n    //USHORT weight;\n    //BYTE italic;\n    //BYTE charset;\n    //WCHAR typeface[stringLen];\n} DLGTEMPLATEEX, *PDLGTEMPLATEEX;\n#include <poppack.h>\n\nPHLIBAPI\nHWND\nNTAPI\nPhCreateDialogFromTemplate(\n    _In_ HWND Parent,\n    _In_ ULONG Style,\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_ DLGPROC DialogProc,\n    _In_ PVOID Parameter\n    );\n\nPHLIBAPI\nHWND\nNTAPI\nPhCreateDialog(\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_opt_ HWND ParentWindow,\n    _In_ DLGPROC DialogProc,\n    _In_opt_ PVOID Parameter\n    );\n\nPHLIBAPI\nHWND\nNTAPI\nPhCreateWindowEx(\n    _In_ PCWSTR ClassName,\n    _In_opt_ PCWSTR WindowName,\n    _In_ ULONG Style,\n    _In_ ULONG ExStyle,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_opt_ HWND ParentWindow,\n    _In_opt_ HMENU MenuHandle,\n    _In_opt_ PVOID InstanceHandle,\n    _In_opt_ PVOID Parameter\n    );\n\n#define PhCreateWindow(ClassName, WindowName, Style, X, Y, Width, Height, ParentWindow, MenuHandle, InstanceHandle, Parameter) \\\n    PhCreateWindowEx(ClassName, WindowName, Style, 0, X, Y, Width, Height, ParentWindow, MenuHandle, InstanceHandle, Parameter)\n\n//FORCEINLINE\n//HWND\n//PhCreateWindow(\n//    _In_ PCWSTR ClassName,\n//    _In_opt_ PCWSTR WindowName,\n//    _In_ ULONG Style,\n//    _In_ LONG X,\n//    _In_ LONG Y,\n//    _In_ LONG Width,\n//    _In_ LONG Height,\n//    _In_opt_ HWND ParentWindow,\n//    _In_opt_ HMENU MenuHandle,\n//    _In_opt_ PVOID InstanceHandle,\n//    _In_opt_ PVOID Parameter\n//    )\n//{\n//    return PhCreateWindowEx(\n//        ClassName,\n//        WindowName,\n//        Style,\n//        0,\n//        X,\n//        Y,\n//        Width,\n//        Height,\n//        ParentWindow,\n//        MenuHandle,\n//        InstanceHandle,\n//        Parameter\n//        );\n//}\n\nPHLIBAPI\nINT_PTR\nNTAPI\nPhDialogBox(\n    _In_ PVOID Instance,\n    _In_ PCWSTR Template,\n    _In_opt_ HWND ParentWindow,\n    _In_ DLGPROC DialogProc,\n    _In_opt_ PVOID Parameter\n    );\n\nPHLIBAPI\nHMENU\nNTAPI\nPhLoadMenu(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR MenuName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhModalPropertySheet(\n    _Inout_ PROPSHEETHEADER *Header\n    );\n\n#define PH_ANCHOR_LEFT 0x1\n#define PH_ANCHOR_TOP 0x2\n#define PH_ANCHOR_RIGHT 0x4\n#define PH_ANCHOR_BOTTOM 0x8\n#define PH_ANCHOR_ALL 0xf\n\n// This interface is horrible and should be rewritten, but it works for now.\n\n#define PH_LAYOUT_FORCE_INVALIDATE 0x1000 // invalidate the control when it is resized\n#define PH_LAYOUT_TAB_CONTROL 0x2000 // this is a dummy item, a hack for the tab control\n#define PH_LAYOUT_IMMEDIATE_RESIZE 0x4000 // needed for the tab control hack\n\n#define PH_LAYOUT_DUMMY_MASK (PH_LAYOUT_TAB_CONTROL) // items that don't have a window handle, or don't actually get their window resized\n\ntypedef struct _PH_LAYOUT_ITEM\n{\n    HWND Handle;\n    struct _PH_LAYOUT_ITEM *ParentItem; // for rectangle calculation\n    struct _PH_LAYOUT_ITEM *LayoutParentItem; // for actual resizing\n    ULONG LayoutNumber;\n    ULONG NumberOfChildren;\n    HDWP DeferHandle;\n\n    RECT Rect;\n    RECT Margin;\n    ULONG Anchor;\n} PH_LAYOUT_ITEM, *PPH_LAYOUT_ITEM;\n\ntypedef struct _PH_LAYOUT_MANAGER\n{\n    PPH_LIST List;\n    PH_LAYOUT_ITEM RootItem;\n\n    ULONG LayoutNumber;\n\n    LONG WindowDpi;\n} PH_LAYOUT_MANAGER, *PPH_LAYOUT_MANAGER;\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhInitializeLayoutManager(\n    _Out_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND RootWindowHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteLayoutManager(\n    _Inout_ PPH_LAYOUT_MANAGER Manager\n    );\n\nPHLIBAPI\nPPH_LAYOUT_ITEM\nNTAPI\nPhAddLayoutItem(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_opt_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor\n    );\n\nPHLIBAPI\nPPH_LAYOUT_ITEM\nNTAPI\nPhAddLayoutItemEx(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_opt_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor,\n    _In_ PRECT Margin\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLayoutManagerLayout(\n    _Inout_ PPH_LAYOUT_MANAGER Manager\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLayoutManagerUpdate(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ LONG WindowDpi\n    );\n\n#define PH_WINDOW_CONTEXT_DEFAULT 0xFFFF\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetWindowContext(\n    _In_ HWND WindowHandle,\n    _In_ ULONG PropertyHash\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetWindowContext(\n    _In_ HWND WindowHandle,\n    _In_ ULONG PropertyHash,\n    _In_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveWindowContext(\n    _In_ HWND WindowHandle,\n    _In_ ULONG PropertyHash\n    );\n\n/**\n * Retrieves the window context pointer associated with a window handle.\n *\n * \\param[in] WindowHandle A handle to the window from which to retrieve the context.\n * \\return A pointer to the window context, or NULL if no context has been set. * *\n */\nFORCEINLINE\nPVOID\nNTAPI\nPhGetWindowContextEx(\n    _In_ HWND WindowHandle\n    )\n{\n#if defined(PHNT_WINDOW_CLASS_CONTEXT)\n    return PhGetWindowContext(WindowHandle, MAXCHAR);\n#else\n    //assert(GetClassLongPtr(WindowHandle, GCL_CBWNDEXTRA) == sizeof(PVOID));\n    return (PVOID)GetWindowLongPtr(WindowHandle, 0);\n#endif\n}\n\n/**\n * Sets the extended window context for a window handle.\n * \n * \\param[in] WindowHandle The handle to the window for which to set the context.\n * \\param[in] Context A pointer to the context data to associate with the window.\n * \\return This function does not return a value.\n * \\remarks The window must have sufficient extra bytes allocated to store a PVOID\n * if PHNT_WINDOW_CLASS_CONTEXT is not defined.\n */\nFORCEINLINE\nVOID\nNTAPI\nPhSetWindowContextEx(\n    _In_ HWND WindowHandle,\n    _In_ PVOID Context\n    )\n{\n#if defined(PHNT_WINDOW_CLASS_CONTEXT)\n    PhSetWindowContext(WindowHandle, MAXCHAR, Context);\n#else\n    //assert(GetClassLongPtr(WindowHandle, GCL_CBWNDEXTRA) == sizeof(PVOID));\n    SetWindowLongPtr(WindowHandle, 0, (LONG_PTR)Context);\n#endif\n}\n\n/**\n * Removes the window context from a window handle.\n *\n * \\param[in] WindowHandle The handle to the window from which to remove the context.\n * \\remarks\n * If PHNT_WINDOW_CLASS_CONTEXT is defined, this function delegates to PhRemoveWindowContext\n * with MAXCHAR as the context identifier. Otherwise, it clears the window's extra data by\n * setting the window long pointer at offset 0 to NULL.\n */\nFORCEINLINE\nVOID\nNTAPI\nPhRemoveWindowContextEx(\n    _In_ HWND WindowHandle\n    )\n{\n#if defined(PHNT_WINDOW_CLASS_CONTEXT)\n    PhRemoveWindowContext(WindowHandle, MAXCHAR);\n#else\n    //assert(GetClassLongPtr(WindowHandle, GCL_CBWNDEXTRA) == sizeof(PVOID));\n    SetWindowLongPtr(WindowHandle, 0, (LONG_PTR)NULL);\n#endif\n}\n\nFORCEINLINE\nPVOID\nNTAPI\nPhGetDialogContext(\n    _In_ HWND WindowHandle\n    )\n{\n#if defined(PHNT_WINDOW_CLASS_CONTEXT)\n    return PhGetWindowContext(WindowHandle, MAXCHAR);\n#else\n    return (PVOID)GetWindowLongPtr(WindowHandle, DWLP_USER);\n#endif\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhSetDialogContext(\n    _In_ HWND WindowHandle,\n    _In_ PVOID Context\n    )\n{\n#if defined(PHNT_WINDOW_CLASS_CONTEXT)\n    PhSetWindowContext(WindowHandle, MAXCHAR, Context);\n#else\n    SetWindowLongPtr(WindowHandle, DWLP_USER, (LONG_PTR)Context);\n#endif\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhRemoveDialogContext(\n    _In_ HWND WindowHandle\n    )\n{\n#if defined(PHNT_WINDOW_CLASS_CONTEXT)\n    PhRemoveWindowContext(WindowHandle, MAXCHAR);\n#else\n    SetWindowLongPtr(WindowHandle, DWLP_USER, (LONG_PTR)NULL);\n#endif\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhSetWindowRedraw(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN Enable\n    )\n{\n    SendMessage(WindowHandle, WM_SETREDRAW, Enable, 0);\n}\n\nFORCEINLINE\nBOOL\nNTAPI\nPhInvalidateRect(\n    _In_ HWND WindowHandle,\n    _In_opt_ CONST RECT* Rect,\n    _In_ BOOL Erase\n    )\n{\n    return InvalidateRect(WindowHandle, Rect, Erase);\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhUpdateWindow(\n    _In_ HWND WindowHandle\n    )\n{\n    UpdateWindow(WindowHandle);\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhInvalidateUpdateWindow(\n    _In_ HWND WindowHandle\n    )\n{\n    PhInvalidateRect(WindowHandle, NULL, TRUE);\n    PhUpdateWindow(WindowHandle);\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhRedrawWindow(\n    _In_ HWND WindowHandle\n    )\n{\n    // You should use RedrawWindow with the specified flags, instead of InvalidateRect,\n    // because the former is necessary for some controls that have nonclient area of their own,\n    // or have window styles that cause them to be given a nonclient area (such as WS_THICKFRAME, WS_BORDER, or WS_EX_CLIENTEDGE).\n    // If the control does not have a nonclient area, then RedrawWindow with these flags\n    // will do only as much invalidation as InvalidateRect would.\n    // https://learn.microsoft.com/en-us/windows/win32/gdi/wm-setredraw\n\n    RedrawWindow(WindowHandle, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);\n}\n\ntypedef _Function_class_(PH_WINDOW_ENUM_CALLBACK)\nBOOLEAN NTAPI PH_WINDOW_ENUM_CALLBACK(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_WINDOW_ENUM_CALLBACK* PPH_WINDOW_ENUM_CALLBACK;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumWindows(\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumWindowsEx(\n    _In_opt_ HWND ParentWindow,\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumGetWindow(\n    _In_opt_ HWND StartWindow,\n    _In_ ULONG Command,\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumWindowsZOrder(\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumChildWindows(\n    _In_opt_ HWND WindowHandle,\n    _In_ PH_WINDOW_ENUM_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhBuildHwndList(\n    _In_opt_ HANDLE DesktopHandle,\n    _In_opt_ HWND ParentWindowHandle,\n    _In_ BOOLEAN IncludeChildren,\n    _In_ BOOLEAN ExcludeImmersive,\n    _In_opt_ HANDLE ThreadId,\n    _Out_ PULONG NumberOfHandles,\n    _Outptr_result_buffer_(*NumberOfHandles) HWND** Handles\n    );\n\nHWND\nNTAPI\nPhGetProcessMainWindow(\n    _In_opt_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle\n    );\n\nHWND\nNTAPI\nPhGetProcessMainWindowEx(\n    _In_opt_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ BOOLEAN SkipInvisible\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetDialogItemValue(\n    _In_ HWND WindowHandle,\n    _In_ LONG ControlID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetDialogItemValue(\n    _In_ HWND WindowHandle,\n    _In_ LONG ControlID,\n    _In_ ULONG Value,\n    _In_ BOOLEAN Signed\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSetDialogItemText(\n    _In_ HWND WindowHandle,\n    _In_ LONG ControlID,\n    _In_ PCWSTR WindowText\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSetWindowText(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR WindowText\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetGroupBoxText(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR WindowText\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetWindowAlwaysOnTop(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN AlwaysOnTop\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSendMessageTimeout(\n    _In_ HWND WindowHandle,\n    _In_ ULONG WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ ULONG Timeout,\n    _Out_opt_ PULONG_PTR Result\n    );\n\nFORCEINLINE ULONG PhGetWindowTextLength(\n    _In_ HWND WindowHandle\n    )\n{\n    return (ULONG)SendMessage(WindowHandle, WM_GETTEXTLENGTH, 0, 0); // DefWindowProc\n}\n\nFORCEINLINE VOID PhSetDialogFocus(\n    _In_ HWND WindowHandle,\n    _In_ HWND FocusHandle\n    )\n{\n    // Do not use the SendMessage function to send a WM_NEXTDLGCTL message if your application will\n    // concurrently process other messages that set the focus. Use the PostMessage function instead.\n    SendMessage(WindowHandle, WM_NEXTDLGCTL, (WPARAM)FocusHandle, MAKELPARAM(TRUE, 0));\n}\n\nFORCEINLINE VOID PhResizingMinimumSize(\n    _Inout_ PRECT Rect,\n    _In_ WPARAM Edge,\n    _In_ LONG MinimumWidth,\n    _In_ LONG MinimumHeight\n    )\n{\n    if (Edge == WMSZ_BOTTOMRIGHT || Edge == WMSZ_RIGHT || Edge == WMSZ_TOPRIGHT)\n    {\n        if (Rect->right - Rect->left < MinimumWidth)\n            Rect->right = Rect->left + MinimumWidth;\n    }\n    else if (Edge == WMSZ_BOTTOMLEFT || Edge == WMSZ_LEFT || Edge == WMSZ_TOPLEFT)\n    {\n        if (Rect->right - Rect->left < MinimumWidth)\n            Rect->left = Rect->right - MinimumWidth;\n    }\n\n    if (Edge == WMSZ_BOTTOMRIGHT || Edge == WMSZ_BOTTOM || Edge == WMSZ_BOTTOMLEFT)\n    {\n        if (Rect->bottom - Rect->top < MinimumHeight)\n            Rect->bottom = Rect->top + MinimumHeight;\n    }\n    else if (Edge == WMSZ_TOPRIGHT || Edge == WMSZ_TOP || Edge == WMSZ_TOPLEFT)\n    {\n        if (Rect->bottom - Rect->top < MinimumHeight)\n            Rect->top = Rect->bottom - MinimumHeight;\n    }\n}\n\nFORCEINLINE VOID PhCopyControlRectangle(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND FromControlHandle,\n    _In_ HWND ToControlHandle\n    )\n{\n    RECT windowRect;\n\n    if (!PhGetWindowRect(FromControlHandle, &windowRect))\n        return;\n\n    MapWindowRect(NULL, ParentWindowHandle, &windowRect);\n    MoveWindow(ToControlHandle, windowRect.left, windowRect.top,\n        windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, FALSE);\n}\n\n// icotobmp\n\nPHLIBAPI\nHBITMAP\nNTAPI\nPhIconToBitmap(\n    _In_ HICON Icon,\n    _In_ LONG Width,\n    _In_ LONG Height\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhBitmapSetAlpha(\n    _In_ PVOID Bits,\n    _In_ LONG Width,\n    _In_ LONG Height\n    );\n\n//\n// Extended ListView\n//\n\n#define PH_ALIGN_CENTER 0x0\n#define PH_ALIGN_LEFT 0x1\n#define PH_ALIGN_RIGHT 0x2\n#define PH_ALIGN_TOP 0x4\n#define PH_ALIGN_BOTTOM 0x8\n\n#define PH_ALIGN_MONOSPACE_FONT 0x80000000\n\ntypedef enum _PH_ITEM_STATE\n{\n    // The item is normal. Use the ItemColorFunction to determine the color of the item.\n    NormalItemState = 0,\n    // The item is new. On the next tick, change the state to NormalItemState. When an item is in\n    // this state, highlight it in NewColor.\n    NewItemState,\n    // The item is being removed. On the next tick, delete the item. When an item is in this state,\n    // highlight it in RemovingColor.\n    RemovingItemState\n} PH_ITEM_STATE;\n\ntypedef _Function_class_(PH_EXTLV_GET_ITEM_COLOR)\nCOLORREF NTAPI PH_EXTLV_GET_ITEM_COLOR(\n    _In_ LONG Index,\n    _In_ PVOID Param,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_EXTLV_GET_ITEM_COLOR* PPH_EXTLV_GET_ITEM_COLOR;\n\ntypedef _Function_class_(PH_EXTLV_GET_ITEM_FONT)\nHFONT NTAPI PH_EXTLV_GET_ITEM_FONT(\n    _In_ LONG Index,\n    _In_ PVOID Param,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_EXTLV_GET_ITEM_FONT* PPH_EXTLV_GET_ITEM_FONT;\n\ntypedef struct _PH_EXTLV_SETCOMPAREFUNCTION\n{\n    PPH_COMPARE_FUNCTION CompareFunction;\n} PH_EXTLV_SETCOMPAREFUNCTION, *PPH_EXTLV_SETCOMPAREFUNCTION;\n\ntypedef struct _PH_EXTLV_SETITEMCOLORFUNCTION\n{\n    PPH_EXTLV_GET_ITEM_COLOR ColorFunction;\n} PH_EXTLV_SETITEMCOLORFUNCTION, *PPH_EXTLV_SETITEMCOLORFUNCTION;\n\ntypedef struct _PH_EXTLV_SETITEMFONTFUNCTION\n{\n    PPH_EXTLV_GET_ITEM_FONT FontFunction;\n} PH_EXTLV_SETITEMFONTFUNCTION, *PPH_EXTLV_SETITEMFONTFUNCTION;\n\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetExtendedListView(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetExtendedListViewEx(\n    _In_ HWND WindowHandle,\n    _In_ ULONG SortColumn,\n    _In_ ULONG SortOrder\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetHeaderSortIcon(\n    _In_ HWND hwnd,\n    _In_ LONG Index,\n    _In_ PH_SORT_ORDER Order\n    );\n\n// next 1122\n\n#define ELVM_INIT (WM_APP + 1102)\n#define ELVM_ADDFALLBACKCOLUMN (WM_APP + 1106)\n#define ELVM_ADDFALLBACKCOLUMNS (WM_APP + 1109)\n#define ELVM_RESERVED5 (WM_APP + 1120)\n#define ELVM_SETCOLUMNWIDTH (WM_APP + 1121)\n#define ELVM_SETCOMPAREFUNCTION (WM_APP + 1104)\n#define ELVM_SETCONTEXT (WM_APP + 1103)\n#define ELVM_SETCURSOR (WM_APP + 1114)\n#define ELVM_RESERVED4 (WM_APP + 1118)\n#define ELVM_SETITEMCOLORFUNCTION (WM_APP + 1111)\n#define ELVM_SETITEMFONTFUNCTION (WM_APP + 1117)\n#define ELVM_RESERVED1 (WM_APP + 1112)\n#define ELVM_SETREDRAW (WM_APP + 1116)\n#define ELVM_GETSORT (WM_APP + 1113)\n#define ELVM_SETSORT (WM_APP + 1108)\n#define ELVM_SETSORTFAST (WM_APP + 1119)\n#define ELVM_RESERVED0 (WM_APP + 1110)\n#define ELVM_SETTRISTATE (WM_APP + 1107)\n#define ELVM_SETTRISTATECOMPAREFUNCTION (WM_APP + 1105)\n#define ELVM_SORTITEMS (WM_APP + 1101)\n#define ELVM_RESERVED3 (WM_APP + 1115)\n\n#define ExtendedListView_AddFallbackColumn(hWnd, Column) \\\n    SendMessage((hWnd), ELVM_ADDFALLBACKCOLUMN, (WPARAM)(Column), 0)\n#define ExtendedListView_AddFallbackColumns(hWnd, NumberOfColumns, Columns) \\\n    SendMessage((hWnd), ELVM_ADDFALLBACKCOLUMNS, (WPARAM)(NumberOfColumns), (LPARAM)(Columns))\n#define ExtendedListView_Init(hWnd) \\\n    SendMessage((hWnd), ELVM_INIT, 0, 0)\n#define ExtendedListView_SetColumnWidth(hWnd, Column, Width) \\\n    SendMessage((hWnd), ELVM_SETCOLUMNWIDTH, (WPARAM)(Column), (LPARAM)(Width))\n#define ExtendedListView_SetCompareFunction(hWnd, Column, CompareFunction) \\\n    SendMessage((hWnd), ELVM_SETCOMPAREFUNCTION, (WPARAM)(Column), (LPARAM)(CompareFunction))\n#define ExtendedListView_SetContext(hWnd, Context) \\\n    SendMessage((hWnd), ELVM_SETCONTEXT, 0, (LPARAM)(Context))\n#define ExtendedListView_SetCursor(hWnd, Cursor) \\\n    SendMessage((hWnd), ELVM_SETCURSOR, 0, (LPARAM)(Cursor))\n#define ExtendedListView_SetItemColorFunction(hWnd, ItemColorFunction) \\\n    SendMessage((hWnd), ELVM_SETITEMCOLORFUNCTION, 0, (LPARAM)(ItemColorFunction))\n#define ExtendedListView_SetItemFontFunction(hWnd, ItemFontFunction) \\\n    SendMessage((hWnd), ELVM_SETITEMFONTFUNCTION, 0, (LPARAM)(ItemFontFunction))\n#define ExtendedListView_SetRedraw(hWnd, Redraw) \\\n    SendMessage((hWnd), ELVM_SETREDRAW, (WPARAM)(Redraw), 0)\n#define ExtendedListView_GetSort(hWnd, Column, Order) \\\n    SendMessage((hWnd), ELVM_GETSORT, (WPARAM)(Column), (LPARAM)(Order))\n#define ExtendedListView_SetSort(hWnd, Column, Order) \\\n    SendMessage((hWnd), ELVM_SETSORT, (WPARAM)(Column), (LPARAM)(Order))\n#define ExtendedListView_SetSortFast(hWnd, Fast) \\\n    SendMessage((hWnd), ELVM_SETSORTFAST, (WPARAM)(Fast), 0)\n#define ExtendedListView_SetTriState(hWnd, TriState) \\\n    SendMessage((hWnd), ELVM_SETTRISTATE, (WPARAM)(TriState), 0)\n#define ExtendedListView_SetTriStateCompareFunction(hWnd, CompareFunction) \\\n    SendMessage((hWnd), ELVM_SETTRISTATECOMPAREFUNCTION, 0, (LPARAM)(CompareFunction))\n#define ExtendedListView_SortItems(hWnd) \\\n    SendMessage((hWnd), ELVM_SORTITEMS, 0, 0)\n\n#define ELVSCW_AUTOSIZE (-1)\n#define ELVSCW_AUTOSIZE_USEHEADER (-2)\n#define ELVSCW_AUTOSIZE_REMAININGSPACE (-3)\n\n//\n// Listview Wrappers\n//\n\ntypedef struct _PH_LISTVIEW_CONTEXT\n{\n    HWND ListViewHandle;\n    IListView* ListViewInterface;\n    HANDLE ThreadId;\n} PH_LISTVIEW_CONTEXT, *PPH_LISTVIEW_CONTEXT;\n\nPHLIBAPI\nPPH_LISTVIEW_CONTEXT\nNTAPI\nPhListView_Initialize(\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhListView_Destroy(\n    _In_ PPH_LISTVIEW_CONTEXT Context\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetItemCount(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ PLONG ItemCount\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_SetItemCount(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemCount,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Inout_ LVITEM* Item\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_SetItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LVITEM* Item\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetItemText(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ LONG SubItemIndex,\n    _Out_writes_(BufferSize) PWSTR Buffer,\n    _In_ LONG BufferSize\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_SetItemText(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ LONG SubItemIndex,\n    _In_ PWSTR Text\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_DeleteItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_DeleteAllItems(\n    _In_ PPH_LISTVIEW_CONTEXT Context\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_InsertItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LVITEMW* Item,\n    _Out_opt_ PLONG ItemIndex\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_InsertGroup(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG InsertAt,\n    _In_ LVGROUP* Group,\n    _Out_opt_ PLONG GroupId\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetItemState(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ ULONG Mask,\n    _Out_ PULONG State\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_SetItemState(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ ULONG State,\n    _In_ ULONG Mask\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_SortItems(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ BOOL SortingByIndex,\n    _In_ PFNLVCOMPARE Compare,\n    _In_ PVOID CompareContext\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetColumn(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ ULONG ColumnIndex,\n    _Inout_ LV_COLUMN* Column\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_SetColumn(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ ULONG ColumnIndex,\n    _In_ LV_COLUMN* Column\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_SetColumnWidth(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ ULONG ColumnIndex,\n    _In_ ULONG Width\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetHeader(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ HWND* WindowHandle\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetToolTip(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ HWND* WindowHandle\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhListView_AddColumn(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ LONG DisplayIndex,\n    _In_ LONG SubItemIndex,\n    _In_ LONG Format,\n    _In_ LONG Width,\n    _In_ PCWSTR Text\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhListView_AddItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhListView_FindItemByFlags(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG StartIndex,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhListView_FindItemByParam(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG StartIndex,\n    _In_opt_ PVOID Param\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetItemParam(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG Index,\n    _Outptr_ PVOID* Param\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhListView_SetSubItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG Index,\n    _In_ LONG SubItemIndex,\n    _In_ PCWSTR Text\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhListView_RedrawItems(\n    _In_ PPH_LISTVIEW_CONTEXT Context\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhListView_AddGroup(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG GroupId,\n    _In_ PCWSTR Text\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhListView_AddGroupItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG GroupId,\n    _In_ LONG Index,\n    _In_ PCWSTR Text,\n    _In_opt_ PVOID Param\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhListView_SetStateAllItems(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ ULONG State,\n    _In_ ULONG Mask\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhListView_GetSelectedItemParam(\n    _In_ PPH_LISTVIEW_CONTEXT Context\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetSelectedCount(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ PLONG SelectedCount\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhListView_GetSelectedItemParams(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Out_ PVOID** Items,\n    _Out_ PULONG NumberOfItems\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetClientRect(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Inout_ PRECT ClientRect\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_GetItemRect(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG StartIndex,\n    _In_ ULONG Flags,\n    _Inout_ PRECT ItemRect\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_EnableGroupView(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ BOOLEAN Enable\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_EnsureItemVisible(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _In_ BOOLEAN PartialOk\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_IsItemVisible(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _In_ LONG ItemIndex,\n    _Out_ PBOOLEAN Visible\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhListView_HitTestSubItem(\n    _In_ PPH_LISTVIEW_CONTEXT Context,\n    _Inout_ LVHITTESTINFO * HitTestInfo\n    );\n\n/**\n * Gets the brightness of a color.\n *\n * \\param Color The color.\n *\n * \\return A value ranging from 0 to 255, indicating the brightness of the color.\n */\nFORCEINLINE\nULONG\nPhGetColorBrightness(\n    _In_ COLORREF Color\n    )\n{\n    ULONG r = Color & 0xff;\n    ULONG g = (Color >> 8) & 0xff;\n    ULONG b = (Color >> 16) & 0xff;\n    ULONG min;\n    ULONG max;\n\n    min = r;\n    if (g < min) min = g;\n    if (b < min) min = b;\n\n    max = r;\n    if (g > max) max = g;\n    if (b > max) max = b;\n\n    return (min + max) / 2;\n}\n\nFORCEINLINE\nCOLORREF\nPhHalveColorBrightness(\n    _In_ COLORREF Color\n    )\n{\n    /*return RGB(\n        (UCHAR)Color / 2,\n        (UCHAR)(Color >> 8) / 2,\n        (UCHAR)(Color >> 16) / 2\n        );*/\n    // Since all targets are little-endian, we can use the following method.\n    *((PUCHAR)&Color) /= 2;\n    *((PUCHAR)&Color + 1) /= 2;\n    *((PUCHAR)&Color + 2) /= 2;\n\n    return Color;\n}\n\nFORCEINLINE\nCOLORREF\nPhMakeColorBrighter(\n    _In_ COLORREF Color,\n    _In_ UCHAR Increment\n    )\n{\n    UCHAR r;\n    UCHAR g;\n    UCHAR b;\n\n    r = (UCHAR)Color;\n    g = (UCHAR)(Color >> 8);\n    b = (UCHAR)(Color >> 16);\n\n    if (r <= 255 - Increment)\n        r += Increment;\n    else\n        r = 255;\n\n    if (g <= 255 - Increment)\n        g += Increment;\n    else\n        g = 255;\n\n    if (b <= 255 - Increment)\n        b += Increment;\n    else\n        b = 255;\n\n    return RGB(r, g, b);\n}\n\n// Window support\n\ntypedef enum _PH_PLUGIN_WINDOW_EVENT_TYPE\n{\n    PH_PLUGIN_WINDOW_EVENT_TYPE_NONE,\n    PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST,\n    PH_PLUGIN_WINDOW_EVENT_TYPE_MAX\n} PH_PLUGIN_WINDOW_EVENT_TYPE;\n\ntypedef struct _PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION\n{\n    HWND WindowHandle;\n    PH_PLUGIN_WINDOW_EVENT_TYPE Type;\n} PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION, *PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION;\n\ntypedef struct _PH_PLUGIN_WINDOW_NOTIFY_EVENT\n{\n    PH_PLUGIN_WINDOW_EVENT_TYPE Type;\n    union\n    {\n        BOOLEAN TopMost;\n        //HFONT FontHandle;\n    };\n} PH_PLUGIN_WINDOW_NOTIFY_EVENT, *PPH_PLUGIN_WINDOW_NOTIFY_EVENT;\n\ntypedef struct _PH_PLUGIN_MAINWINDOW_NOTIFY_EVENT\n{\n    PPH_PLUGIN_WINDOW_NOTIFY_EVENT Event;\n    PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION Callback;\n} PH_PLUGIN_MAINWINDOW_NOTIFY_EVENT, *PPH_PLUGIN_MAINWINDOW_NOTIFY_EVENT;\n\nPHLIBAPI\nVOID\nNTAPI\nPhRegisterWindowCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUnregisterWindowCallback(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhWindowNotifyTopMostEvent(\n    _In_ BOOLEAN TopMost\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateEnvironmentBlock(\n    _Out_ PVOID* Environment,\n    _In_opt_ HANDLE TokenHandle,\n    _In_ BOOLEAN Inherit\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDestroyEnvironmentBlock(\n    _In_ _Post_invalid_ PVOID Environment\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhRegenerateUserEnvironment(\n    _Out_opt_ PVOID* NewEnvironment,\n    _In_ BOOLEAN UpdateCurrentEnvironment\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsImmersiveProcess(\n    _In_ HANDLE ProcessHandle\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetProcessUIContextInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_UICONTEXT_INFORMATION UIContext\n    );\n\ntypedef enum _PH_PROCESS_DPI_AWARENESS\n{\n    PH_PROCESS_DPI_AWARENESS_UNAWARE = 0,\n    PH_PROCESS_DPI_AWARENESS_SYSTEM_DPI_AWARE = 1,\n    PH_PROCESS_DPI_AWARENESS_PER_MONITOR_DPI_AWARE = 2,\n    PH_PROCESS_DPI_AWARENESS_PER_MONITOR_AWARE_V2 = 3,\n    PH_PROCESS_DPI_AWARENESS_UNAWARE_GDISCALED = 4,\n} PH_PROCESS_DPI_AWARENESS, *PPH_PROCESS_DPI_AWARENESS;\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetProcessDpiAwareness(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_DPI_AWARENESS ProcessDpiAwareness\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetPhysicallyInstalledSystemMemory(\n    _Out_ PULONGLONG TotalMemory,\n    _Out_ PULONGLONG ReservedMemory\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSessionGuiResources(\n    _In_ ULONG Flags,\n    _Out_ PULONG Total\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessGuiResources(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _Out_ PULONG Total\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetThreadWin32Thread(\n    _In_ HANDLE ThreadId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSendMessageReceiver(\n    _In_ HANDLE ThreadId,\n    _Out_ HWND *WindowHandle\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhExtractIcon(\n    _In_ PCWSTR FileName,\n    _Out_opt_ HICON *IconLarge,\n    _Out_opt_ HICON *IconSmall\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhExtractIconEx(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName,\n    _In_ LONG IconIndex,\n    _In_ LONG IconLargeWidth,\n    _In_ LONG IconLargeHeight,\n    _In_ LONG IconSmallWidth,\n    _In_ LONG IconSmallHeight,\n    _Out_opt_ HICON *IconLarge,\n    _Out_opt_ HICON *IconSmall\n    );\n\n// Imagelist support\n\nPHLIBAPI\nHIMAGELIST\nNTAPI\nPhImageListCreate(\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_ LONG Flags,\n    _In_ LONG InitialCount,\n    _In_ LONG GrowCount\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListDestroy(\n    _In_opt_ HIMAGELIST ImageListHandle\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListSetImageCount(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ ULONG Count\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListGetImageCount(\n    _In_ HIMAGELIST ImageListHandle,\n    _Out_ PLONG Count\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListSetBkColor(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ COLORREF BackgroundColor\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListRemoveIcon(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index\n    );\n\n#define PhImageListRemoveAll(ImageListHandle) \\\n    PhImageListRemoveIcon((ImageListHandle), INT_ERROR)\n\nPHLIBAPI\nLONG\nNTAPI\nPhImageListAddIcon(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ HICON IconHandle\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhImageListAddBitmap(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ HBITMAP BitmapImage,\n    _In_opt_ HBITMAP BitmapMask\n    );\n\nPHLIBAPI\nHICON\nNTAPI\nPhImageListGetIcon(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListGetIconSize(\n    _In_ HIMAGELIST ImageListHandle,\n    _Out_ PLONG cx,\n    _Out_ PLONG cy\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListReplace(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index,\n    _In_ HBITMAP BitmapImage,\n    _In_opt_ HBITMAP BitmapMask\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListDrawIcon(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index,\n    _In_ HDC Hdc,\n    _In_ LONG x,\n    _In_ LONG y,\n    _In_ UINT32 Style,\n    _In_ BOOLEAN Disabled\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListDrawEx(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG Index,\n    _In_ HDC Hdc,\n    _In_ LONG x,\n    _In_ LONG y,\n    _In_ LONG dx,\n    _In_ LONG dy,\n    _In_ COLORREF BackColor,\n    _In_ COLORREF ForeColor,\n    _In_ UINT32 Style,\n    _In_ ULONG State\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhImageListSetIconSize(\n    _In_ HIMAGELIST ImageListHandle,\n    _In_ LONG cx,\n    _In_ LONG cy\n    );\n\n#define PH_SHUTDOWN_RESTART 0x1\n#define PH_SHUTDOWN_POWEROFF 0x2\n#define PH_SHUTDOWN_INSTALL_UPDATES 0x4\n#define PH_SHUTDOWN_HYBRID 0x8\n#define PH_SHUTDOWN_RESTART_BOOTOPTIONS 0x10\n\nPHLIBAPI\nULONG\nNTAPI\nPhInitiateShutdown(\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSetProcessShutdownParameters(\n    _In_ ULONG Level,\n    _In_ ULONG Flags\n    );\n\n#define PH_DRAW_TIMELINE_OVERFLOW 0x1\n#define PH_DRAW_TIMELINE_DARKTHEME 0x2\n\nPHLIBAPI\nVOID\nNTAPI\nPhCustomDrawTreeTimeLine(\n    _In_ HDC Hdc,\n    _In_ PRECT CellRect,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER StartTime,\n    _In_ PLARGE_INTEGER CreateTime\n    );\n\n//\n// Windows Imaging Component (WIC) bitmap support\n//\n\nDEFINE_GUID(IID_IWICBitmapSource, 0x00000120, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94);\nDEFINE_GUID(IID_IWICImagingFactory, 0xec5ec8a9, 0xc395, 0x4314, 0x9c, 0x77, 0x54, 0xd7, 0xa9, 0x35, 0xff, 0x70);\n\ntypedef enum _PH_BUFFERFORMAT\n{\n    PHBF_COMPATIBLEBITMAP,    // Compatible bitmap\n    PHBF_DIB,                 // Device-independent bitmap\n    PHBF_TOPDOWNDIB,          // Top-down device-independent bitmap\n    PHBF_TOPDOWNMONODIB       // Top-down monochrome device-independent bitmap\n} PH_BUFFERFORMAT;\n\nHBITMAP PhCreateDIBSection(\n    _In_ HDC Hdc,\n    _In_ PH_BUFFERFORMAT Format,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _Out_opt_ PVOID* Bits\n    );\n\ntypedef enum _PH_IMAGE_FORMAT_TYPE\n{\n    PH_IMAGE_FORMAT_TYPE_NONE,\n    PH_IMAGE_FORMAT_TYPE_ICO,\n    PH_IMAGE_FORMAT_TYPE_BMP,\n    PH_IMAGE_FORMAT_TYPE_JPG,\n    PH_IMAGE_FORMAT_TYPE_PNG,\n} PH_IMAGE_FORMAT_TYPE, *PPH_IMAGE_FORMAT_TYPE;\n\nPHLIBAPI\nHBITMAP\nNTAPI\nPhLoadImageFormatFromResource(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _In_ PH_IMAGE_FORMAT_TYPE Format,\n    _In_ LONG Width,\n    _In_ LONG Height\n    );\n\nPHLIBAPI\nHBITMAP\nNTAPI\nPhLoadImageFromAddress(\n    _In_ PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _In_ LONG Width,\n    _In_ LONG Height\n    );\n\nPHLIBAPI\nHBITMAP\nNTAPI\nPhLoadImageFromResource(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _In_ LONG Width,\n    _In_ LONG Height\n    );\n\nPHLIBAPI\nHBITMAP\nNTAPI\nPhLoadImageFromFile(\n    _In_ PCWSTR FileName,\n    _In_ LONG Width,\n    _In_ LONG Height\n    );\n\n// Acrylic support\n\ntypedef enum _WINDOWCOMPOSITIONATTRIB\n{\n    WCA_UNDEFINED = 0,\n    WCA_NCRENDERING_ENABLED = 1,                // q: BOOL\n    WCA_NCRENDERING_POLICY = 2,                 // s: ULONG // DWMNCRENDERINGPOLICY\n    WCA_TRANSITIONS_FORCEDISABLED = 3,          // s: BOOL\n    WCA_ALLOW_NCPAINT = 4,                      // s: BOOL\n    WCA_CAPTION_BUTTON_BOUNDS = 5,              // q: RECT\n    WCA_NONCLIENT_RTL_LAYOUT = 6,               // s: BOOL\n    WCA_FORCE_ICONIC_REPRESENTATION = 7,        // s: BOOL\n    WCA_EXTENDED_FRAME_BOUNDS = 8,              // q: RECT\n    WCA_HAS_ICONIC_BITMAP = 9,                  // q: BOOL\n    WCA_THEME_ATTRIBUTES = 10,                  // s: ULONG\n    WCA_NCRENDERING_EXILED = 11,                // q: BOOL\n    WCA_NCADORNMENTINFO = 12,                   // q:\n    WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,         // s: BOOL\n    WCA_VIDEO_OVERLAY_ACTIVE = 14,              // q: BOOL\n    WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,     // s: BOOL\n    WCA_DISALLOW_PEEK = 16,                     // s: BOOL\n    WCA_CLOAK = 17,                             // s: ULONG\n    WCA_CLOAKED = 18,                           // q: ULONG // DWM_CLOAKED_*\n    WCA_ACCENT_POLICY = 19,                     // s: ACCENT_POLICY // since WIN11\n    WCA_FREEZE_REPRESENTATION = 20,             // s: BOOL\n    WCA_EVER_UNCLOAKED = 21,                    // q: BOOL\n    WCA_VISUAL_OWNER = 22,                      // s: HANDLE\n    WCA_HOLOGRAPHIC = 23,                       // q: BOOL\n    WCA_EXCLUDED_FROM_DDA = 24,                 // s: BOOL\n    WCA_PASSIVEUPDATEMODE = 25,                 // s: BOOL\n    WCA_USEDARKMODECOLORS = 26,                 // s: BOOL\n    WCA_CORNER_STYLE = 27,                      // s: ULONG // DWM_WINDOW_CORNER_PREFERENCE\n    WCA_PART_COLOR = 28,                        // s: ULONG // COLORREF\n    WCA_DISABLE_MOVESIZE_FEEDBACK = 29,         // s: BOOL\n    WCA_SYSTEMBACKDROP_TYPE = 30,               // s: ULONG // DWM_SYSTEMBACKDROP_TYPE\n    WCA_SET_TAGGED_WINDOW_RECT = 31,            // s: RECT\n    WCA_CLEAR_TAGGED_WINDOW_RECT = 32,          // s: RECT\n    WCA_REMOTEAPP_POLICY = 33,                  // s: ULONG // since 24H2\n    WCA_HAS_ACCENT_POLICY = 34,                 // q: BOOL\n    WCA_REDIRECTIONBITMAP_FILL_COLOR = 35,      // s: ULONG // COLORREF\n    WCA_REDIRECTIONBITMAP_ALPHA = 36,           // s: UCHAR\n    WCA_BORDER_MARGINS = 37,                    // s: MARGINS\n    WCA_LAST\n} WINDOWCOMPOSITIONATTRIB;\n\ntypedef struct _WINDOWCOMPOSITIONATTRIBUTEDATA\n{\n    WINDOWCOMPOSITIONATTRIB Attribute;\n    PVOID Data;\n    SIZE_T Length;\n} WINDOWCOMPOSITIONATTRIBUTEDATA, *PWINDOWCOMPOSITIONATTRIBUTEDATA;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetWindowCompositionAttribute(\n    _In_ HWND WindowHandle,\n    _Inout_ PWINDOWCOMPOSITIONATTRIBUTEDATA AttributeData\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetWindowCompositionAttribute(\n    _In_ HWND WindowHandle,\n    _In_ PWINDOWCOMPOSITIONATTRIBUTEDATA AttributeData\n    );\n\n// TODO: https://stackoverflow.com/questions/12304848/fast-algorithm-to-invert-an-argb-color-value-to-abgr/42133405#42133405\nFORCEINLINE ULONG MakeARGB(\n    _In_ BYTE a,\n    _In_ BYTE r,\n    _In_ BYTE g,\n    _In_ BYTE b)\n{\n    return (((ULONG)(b) << 0) | ((ULONG)(g) << 8) | ((ULONG)(r) << 16) | ((ULONG)(a) << 24));\n}\n\nFORCEINLINE ULONG MakeABGR(\n    _In_ BYTE a,\n    _In_ BYTE b,\n    _In_ BYTE g,\n    _In_ BYTE r)\n{\n    return (((ULONG)(a) << 24) | ((ULONG)(b) << 16) | ((ULONG)(g) << 8) | ((ULONG)(r) << 0));\n}\n\nFORCEINLINE ULONG MakeARGBFromCOLORREF(_In_ BYTE Alpha, _In_ COLORREF rgb)\n{\n    return MakeARGB(Alpha, GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));\n}\n\nFORCEINLINE ULONG MakeABGRFromCOLORREF(_In_ BYTE Alpha, _In_ COLORREF rgb)\n{\n    return MakeABGR(Alpha, GetBValue(rgb), GetGValue(rgb), GetRValue(rgb));\n}\n\ntypedef enum _ACCENT_STATE\n{\n    ACCENT_DISABLED,\n    ACCENT_ENABLE_GRADIENT = 1,\n    ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,\n    ACCENT_ENABLE_BLURBEHIND = 3,\n    ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,\n    ACCENT_ENABLE_HOSTBACKDROP = 5,\n    ACCENT_INVALID_STATE\n} ACCENT_STATE;\n\ntypedef enum _ACCENT_FLAG\n{\n    ACCENT_NONE,\n    ACCENT_WINDOWS11_LUMINOSITY = 0x2,\n    ACCENT_BORDER_LEFT = 0x20,\n    ACCENT_BORDER_TOP = 0x40,\n    ACCENT_BORDER_RIGHT = 0x80,\n    ACCENT_BORDER_BOTTOM = 0x100,\n    ACCENT_BORDER_ALL = (ACCENT_BORDER_LEFT | ACCENT_BORDER_TOP | ACCENT_BORDER_RIGHT | ACCENT_BORDER_BOTTOM)\n} ACCENT_FLAG;\n\ntypedef struct _ACCENT_POLICY\n{\n    ACCENT_STATE AccentState;\n    ULONG AccentFlags;\n    ULONG GradientColor;\n    ULONG AnimationId;\n} ACCENT_POLICY;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetWindowAcrylicCompositionColor(\n    _In_ HWND WindowHandle,\n    _In_ ULONG GradientColor\n    );\n\nPHLIBAPI\nHCURSOR\nNTAPI\nPhLoadArrowCursor(\n    VOID\n    );\n\nPHLIBAPI\nHCURSOR\nNTAPI\nPhLoadDividerCursor(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhIsInteractiveUserSession(\n    VOID\n    );\n\ntypedef struct _PH_USER_OBJECT_SID\n{\n    union\n    {\n        SID Sid;\n        BYTE Buffer[SECURITY_MAX_SID_SIZE];\n    };\n} PH_USER_OBJECT_SID, *PPH_USER_OBJECT_SID;\n\nstatic_assert(sizeof(PH_USER_OBJECT_SID) == SECURITY_MAX_SID_SIZE, \"sizeof(PH_USER_OBJECT_SID) is invalid.\");\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetUserObjectSidInformationToBuffer(\n    _In_ HANDLE Handle,\n    _Out_ PPH_USER_OBJECT_SID ObjectSid,\n    _In_ ULONG ObjectSidLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetUserObjectSidInformationCopy(\n    _In_ HANDLE Handle,\n    _Out_ PSID* ObjectSid\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetCurrentWindowStationName(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetCurrentThreadDesktopName(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhRecentListAddCommand(\n    _In_ PPH_STRINGREF Command\n    );\n\ntypedef _Function_class_(PH_ENUM_MRULIST_CALLBACK)\nBOOLEAN NTAPI PH_ENUM_MRULIST_CALLBACK(\n    _In_ PPH_STRINGREF Command,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_MRULIST_CALLBACK* PPH_ENUM_MRULIST_CALLBACK;\n\nPHLIBAPI\nVOID\nNTAPI\nPhEnumerateRecentList(\n    _In_ PPH_ENUM_MRULIST_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTerminateWindow(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN Force\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenWindowProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nULONG_PTR\nNTAPI\nPhUserQueryWindow(\n    _In_ HWND WindowHandle,\n    _In_ WINDOWINFOCLASS WindowInfo\n    );\n\nFORCEINLINE\nULONG\nPhQueryWindowRealProcess(\n    _In_ HWND WindowHandle\n    )\n{\n    return (ULONG)PhUserQueryWindow(\n        WindowHandle,\n        WindowRealProcess\n        );\n}\n\nFORCEINLINE\nBOOLEAN\nPhWindowIsHung(\n    _In_ HWND WindowHandle\n    )\n{\n    return (BOOLEAN)(ULONG_PTR)PhUserQueryWindow(\n        WindowHandle,\n        WindowIsHung\n        );\n}\n\n#ifndef DBT_DEVICEARRIVAL\n#define DBT_DEVICEARRIVAL        0x8000  // system detected a new device\n#define DBT_DEVICEREMOVECOMPLETE 0x8004  // device is gone\n#define DBT_DEVTYP_VOLUME        0x00000002  // logical volume\n\ntypedef struct _DEV_BROADCAST_HDR\n{\n    ULONG dbch_size;\n    ULONG dbch_devicetype;\n    ULONG dbch_reserved;\n} DEV_BROADCAST_HDR, *PDEV_BROADCAST_HDR;\n#endif\n\n// theme support (theme.c)\n\nextern HFONT PhApplicationFont;\nextern HFONT PhTreeWindowFont;\nextern HFONT PhMonospaceFont;\nextern HBRUSH PhThemeWindowBackgroundBrush;\nextern BOOLEAN PhEnableThemeSupport;\nextern BOOLEAN PhEnableThemeAcrylicSupport;\nextern BOOLEAN PhEnableThemeAcrylicWindowSupport;\nextern BOOLEAN PhEnableThemeNativeButtons;\nextern BOOLEAN PhEnableThemeListviewBorder;\nextern COLORREF PhThemeWindowForegroundColor;\nextern COLORREF PhThemeWindowBackgroundColor;\nextern COLORREF PhThemeWindowBackground2Color;\nextern COLORREF PhThemeWindowHighlightColor;\nextern COLORREF PhThemeWindowHighlight2Color;\nextern COLORREF PhThemeWindowTextColor;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeWindowTheme(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN EnableThemeSupport\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeWindowThemeEx(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhReInitializeWindowTheme(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeThemeWindowFrame(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nHBRUSH\nNTAPI\nPhWindowThemeControlColor(\n    _In_ HWND WindowHandle,\n    _In_ HDC Hdc,\n    _In_ HWND ChildWindowHandle,\n    _In_ LONG Type\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhThemeWindowDrawItem(\n    _In_ HWND WindowHandle,\n    _In_ PDRAWITEMSTRUCT DrawInfo\n    );\n\nPHLIBAPI\nLRESULT\nNTAPI\nPhThemeWindowDrawButton(\n    _In_ LPNMCUSTOMDRAW DrawInfo\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhThemeWindowMeasureItem(\n    _In_ HWND WindowHandle,\n    _In_ PMEASUREITEMSTRUCT DrawInfo\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeWindowThemeMainMenu(\n    _In_ HMENU MenuHandle\n    );\n\nPHLIBAPI\nLRESULT\nCALLBACK\nPhThemeWindowDrawRebar(\n    _In_ LPNMCUSTOMDRAW DrawInfo\n    );\n\nPHLIBAPI\nLRESULT\nCALLBACK\nPhThemeWindowDrawToolbar(\n    _In_ LPNMTBCUSTOMDRAW DrawInfo\n    );\n\n// Font support\n\nPHLIBAPI\nHFONT\nNTAPI\nPhCreateFont(\n    _In_opt_ PCWSTR Name,\n    _In_ LONG Size,\n    _In_ LONG Weight,\n    _In_ LONG PitchAndFamily,\n    _In_ LONG Dpi\n    );\n\nPHLIBAPI\nHFONT\nNTAPI\nPhCreateCommonFont(\n    _In_ LONG Size,\n    _In_ LONG Weight,\n    _In_opt_ HWND WindowHandle,\n    _In_ LONG WindowDpi\n    );\n\nPHLIBAPI\nHFONT\nNTAPI\nPhCreateIconTitleFont(\n    _In_opt_ LONG WindowDpi\n    );\n\nPHLIBAPI\nHFONT\nNTAPI\nPhCreateMessageFont(\n    _In_opt_ LONG WindowDpi\n    );\n\nPHLIBAPI\nHFONT\nNTAPI\nPhDuplicateFont(\n    _In_ HFONT Font\n    );\n\nPHLIBAPI\nHFONT\nNTAPI\nPhDuplicateFontWithNewWeight(\n    _In_ HFONT Font,\n    _In_ LONG NewWeight\n    );\n\nPHLIBAPI\nHFONT\nNTAPI\nPhDuplicateFontWithNewHeight(\n    _In_ HFONT Font,\n    _In_ LONG NewHeight,\n    _In_ LONG dpiValue\n    );\n\nVOID PhWindowThemeMainMenuBorder(\n    _In_ HWND WindowHandle\n    );\n\n// directdraw.cpp\n\nHICON PhGdiplusConvertBitmapToIcon(\n    _In_ HBITMAP Bitmap,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_ COLORREF Background\n    );\n\nHWND PhCreateBackgroundWindow(\n    _In_ HWND ParentWindowHandle,\n    _In_ BOOLEAN DesktopWindow\n    );\n\nHICON PhGdiplusConvertHBitmapToHIcon(\n    _In_ HBITMAP BitmapHandle\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/guisupp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2016-2023\n *\n */\n\n#ifndef _PH_GUISUPP_H\n#define _PH_GUISUPP_H\n\ntypedef HRESULT (WINAPI* _GetThemeClass)(\n    _In_ HTHEME ThemeHandle,\n    _Out_writes_z_(BufferLength) PWSTR Buffer,\n    _In_ ULONG BufferLength\n    );\n\ntypedef BOOL(WINAPI* _AllowDarkModeForWindow)(\n    _In_ HWND WindowHandle,\n    _In_ BOOL Enabled\n    );\n\ntypedef BOOL(WINAPI* _IsDarkModeAllowedForWindow)(\n    _In_ HWND WindowHandle\n    );\n\ntypedef LONG (WINAPI* _GetDpiForSession)(\n    VOID\n    );\n\n// Comctl32\n\ntypedef LONG (CALLBACK *MRUSTRINGCMPPROC)(PCWSTR String1, PCWSTR String2);\ntypedef LONG (CALLBACK *MRUINARYCMPPROC)(PVOID String1, PVOID String2, ULONG Length);\n\n#define MRU_STRING 0x0000\n#define MRU_BINARY 0x0001\n#define MRU_CACHEWRITE 0x0002\n\ntypedef struct _MRUINFO\n{\n    ULONG cbSize;\n    UINT uMaxItems;\n    UINT uFlags;\n    HANDLE hKey;\n    PCWSTR lpszSubKey;\n    MRUSTRINGCMPPROC lpfnCompare;\n} MRUINFO, *PMRUINFO;\n\ntypedef HANDLE (WINAPI* _CreateMRUList)(\n    _In_ PMRUINFO lpmi\n    );\ntypedef LONG (WINAPI* _AddMRUString)(\n    _In_ HANDLE hMRU,\n    _In_ PCWSTR szString\n    );\ntypedef LONG (WINAPI* _EnumMRUList)(\n    _In_ HANDLE hMRU,\n    _In_ INT nItem,\n    _Out_ PVOID lpData,\n    _In_ UINT uLen\n    );\ntypedef LONG (WINAPI* _FreeMRUList)(\n    _In_ HANDLE hMRU\n    );\n\n// Icons\n\ntypedef struct _PHP_ICON_ENTRY\n{\n    PVOID InstanceHandle;\n    PCWSTR Name;\n    ULONG Width;\n    ULONG Height;\n    HICON Icon;\n    LONG DpiValue;\n} PHP_ICON_ENTRY, *PPHP_ICON_ENTRY;\n\n#define PHP_ICON_ENTRY_SIZE_SMALL (-1)\n#define PHP_ICON_ENTRY_SIZE_LARGE (-2)\n\nFORCEINLINE ULONG PhpGetIconEntrySize(\n    _In_ ULONG InputSize,\n    _In_ ULONG Flags\n    )\n{\n    if (Flags & PH_LOAD_ICON_SIZE_SMALL)\n        return PHP_ICON_ENTRY_SIZE_SMALL;\n    if (Flags & PH_LOAD_ICON_SIZE_LARGE)\n        return PHP_ICON_ENTRY_SIZE_LARGE;\n    return InputSize;\n}\n\n#endif\n"
  },
  {
    "path": "phlib/include/guisupview.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2016-2023\n *\n */\n\n#ifndef _PH_GUISUPPVIEW_H\n#define _PH_GUISUPPVIEW_H\n\n//\n// Listview2 (Undocumented)\n//\n\n#ifndef LVM_QUERYINTERFACE\n#define LVM_QUERYINTERFACE (LVM_FIRST + 189) // IListView, IListView2, IOleWindow, IVisualProperties, IPropertyControlSite, IListViewFooter\n#endif\n\n// {E5B16AF2-3990-4681-A609-1F060CD14269}\nDEFINE_GUID(IID_IListView, 0xE5B16AF2, 0x3990, 0x4681, 0xA6, 0x09, 0x1F, 0x06, 0x0C, 0xD1, 0x42, 0x69);\n// {E6DFF6FD-BCD5-4162-9C65-A3B18C616FDB}\nDEFINE_GUID(IID_IDrawPropertyControl, 0xE6DFF6FD, 0xBCD5, 0x4162, 0x9C, 0x65, 0xA3, 0xB1, 0x8C, 0x61, 0x6F, 0xDB);\n// {1572DD51-443C-44B0-ACE4-38A005FC697E}\nDEFINE_GUID(IID_IDrawPropertyControlWin10, 0x1572DD51, 0x443C, 0x44B0, 0xAC, 0xE4, 0x38, 0xA0, 0x05, 0xFC, 0x69, 0x7E);\n// {F0034DA8-8A22-4151-8F16-2EBA76565BCC}\nDEFINE_GUID(IID_IListViewFooter, 0xF0034DA8, 0x8A22, 0x4151, 0x8F, 0x16, 0x2E, 0xBA, 0x76, 0x56, 0x5B, 0xCC);\n// {88EB9442-913B-4AB4-A741-DD99DCB7558B}\nDEFINE_GUID(IID_IListViewFooterCallback, 0x88EB9442, 0x913B, 0x4AB4, 0xA7, 0x41, 0xDD, 0x99, 0xDC, 0xB7, 0x55, 0x8B);\n// {44C09D56-8D3B-419D-A462-7B956B105B47}\nDEFINE_GUID(IID_IOwnerDataCallback, 0x44C09D56, 0x8D3B, 0x419D, 0xA4, 0x62, 0x7B, 0x95, 0x6B, 0x10, 0x5B, 0x47);\n// {5E82A4DD-9561-476A-8634-1BEBACBA4A38}\nDEFINE_GUID(IID_IPropertyControl, 0x5E82A4DD, 0x9561, 0x476A, 0x86, 0x34, 0x1B, 0xEB, 0xAC, 0xBA, 0x4A, 0x38);\n// {6E71A510-732A-4557-9596-A827E36DAF8F}\nDEFINE_GUID(IID_IPropertyControlBase, 0x6E71A510, 0x732A, 0x4557, 0x95, 0x96, 0xA8, 0x27, 0xE3, 0x6D, 0xAF, 0x8F);\n// {7AF7F355-1066-4E17-B1F2-19FE2F099CD2}\nDEFINE_GUID(IID_IPropertyValue, 0x7AF7F355, 0x1066, 0x4E17, 0xB1, 0xF2, 0x19, 0xFE, 0x2F, 0x09, 0x9C, 0xD2);\n// {11A66240-5489-42C2-AEBF-286FC831524C}\nDEFINE_GUID(IID_ISubItemCallback, 0x11A66240, 0x5489, 0x42C2, 0xAE, 0xBF, 0x28, 0x6F, 0xC8, 0x31, 0x52, 0x4C);\n\n// CLSID_CAsyncSubItemControlsView: {A1DCCC29-7C70-4821-97AE-67F04105EC91}\nDEFINE_GUID(CLSID_CAsyncSubItemControlsView, 0xa1dccc29, 0x7c70, 0x4821, 0x97, 0xae, 0x67, 0xf0, 0x41, 0x5, 0xec, 0x91);\n// CLSID_CFooterAreaView: {EBE684BF-3301-4A6D-83CE-E4D6851BE881}\nDEFINE_GUID(CLSID_CFooterAreaView, 0xebe684bf, 0x3301, 0x4a6d, 0x83, 0xce, 0xe4, 0xd6, 0x85, 0x1b, 0xe8, 0x81);\n// CLSID_CGroupedVirtualModeView: {A08A0F2D-0647-4443-9450-C460F4791046}\nDEFINE_GUID(CLSID_CGroupedVirtualModeView, 0xa08a0f2d, 0x647, 0x4443, 0x94, 0x50, 0xc4, 0x60, 0xf4, 0x79, 0x10, 0x46);\n// CLSID_CGroupSubsetView: {64A11699-104A-482A-9D85-CCFEA2EE3C94}\nDEFINE_GUID(CLSID_CGroupSubsetView, 0x64a11699, 0x104a, 0x482a, 0x9d, 0x85, 0xcc, 0xfe, 0xa2, 0xee, 0x3c, 0x94);\n// CLSID_CSubItemControlsView: {13E88673-D30C-46BA-8F2E-97C5CD024E73}\nDEFINE_GUID(CLSID_CSubItemControlsView, 0x13e88673, 0xd30c, 0x46ba, 0x8f, 0x2e, 0x97, 0xc5, 0xcd, 0x2, 0x4e, 0x73);\n\n// {1E8F0D70-7399-41BF-8598-7949A2DEC898}\nDEFINE_GUID(CLSID_CBooleanControl, 0x1E8F0D70, 0x7399, 0x41BF, 0x85, 0x98, 0x79, 0x49, 0xA2, 0xDE, 0xC8, 0x98);\n// {e2183960-9d58-4e9c-878a-4acc06ca564a}\nDEFINE_GUID(CLSID_CCustomDrawMultiValuePropertyControl, 0xE2183960, 0x9D58, 0x4E9C, 0x87, 0x8A, 0x4A, 0xCC, 0x06, 0xCA, 0x56, 0x4A);\n// {AB517586-73CF-489c-8D8C-5AE0EAD0613A}\nDEFINE_GUID(CLSID_CCustomDrawPercentFullControl, 0xAB517586, 0x73CF, 0x489c, 0x8D, 0x8C, 0x5A, 0xE0, 0xEA, 0xD0, 0x61, 0x3A);\n// {0d81ea0d-13bf-44b2-af1c-fcdf6be7927c}\nDEFINE_GUID(CLSID_CCustomDrawProgressControl, 0x0d81ea0d, 0x13bf, 0x44B2, 0xAF, 0x1C, 0xFC, 0xDF, 0x6B, 0xE7, 0x92, 0x7C);\n// {15756be1-a4ad-449c-b576-df3df0e068d3}\nDEFINE_GUID(CLSID_CHyperlinkControl, 0x15756BE1, 0xA4AD, 0x449C, 0xB5, 0x76, 0xDF, 0x3D, 0xF0, 0xE0, 0x68, 0xD3);\n// {53a01e9d-61cc-4cb0-83b1-31bc8df63156}\nDEFINE_GUID(CLSID_CIconListControl, 0x53A01E9D, 0x61CC, 0x4CB0, 0x83, 0xB1, 0x31, 0xBC, 0x8D, 0xF6, 0x31, 0x56);\n// {6A205B57-2567-4a2c-B881-F787FAB579A3}\nDEFINE_GUID(CLSID_CInPlaceCalendarControl, 0x6A205B57, 0x2567, 0x4A2C, 0xB8, 0x81, 0xF7, 0x87, 0xFA, 0xB5, 0x79, 0xA3);\n// {0EEA25CC-4362-4a12-850B-86EE61B0D3EB}\nDEFINE_GUID(CLSID_CInPlaceDropListComboControl, 0x0EEA25CC, 0x4362, 0x4A12, 0x85, 0x0B, 0x86, 0xEE, 0x61, 0xB0, 0xD3, 0xEB);\n// {A9CF0EAE-901A-4739-A481-E35B73E47F6D}\nDEFINE_GUID(CLSID_CInPlaceEditBoxControl, 0xA9CF0EAE, 0x901A, 0x4739, 0xA4, 0x81, 0xE3, 0x5B, 0x73, 0xE4, 0x7F, 0x6D);\n// {8EE97210-FD1F-4b19-91DA-67914005F020}\nDEFINE_GUID(CLSID_CInPlaceMLEditBoxControl, 0x8EE97210, 0xFD1F, 0x4B19, 0x91, 0xDA, 0x67, 0x91, 0x40, 0x05, 0xF0, 0x20);\n// {8e85d0ce-deaf-4ea1-9410-fd1a2105ceb5}\nDEFINE_GUID(CLSID_CInPlaceMultiValuePropertyControl, 0x8E85D0CE, 0xDEAF, 0x4EA1, 0x94, 0x10, 0xFD, 0x1A, 0x21, 0x05, 0xCE, 0xB5);\n// {85e94d25-0712-47ed-8cde-b0971177c6a1}\nDEFINE_GUID(CLSID_CRatingControl, 0x85e94d25, 0x0712, 0x47ed, 0x8C, 0xDE, 0xB0, 0x97, 0x11, 0x77, 0xC6, 0xA1);\n// {527c9a9b-b9a2-44b0-84f9-f0dc11c2bcfb}\nDEFINE_GUID(CLSID_CStaticPropertyControl, 0x527C9A9B, 0xB9A2, 0x44B0, 0x84, 0xF9, 0xF0, 0xDC, 0x11, 0xC2, 0xBC, 0xFB);\n\n#undef INTERFACE\n#define INTERFACE IOwnerDataCallback\n/**\n * IOwnerDataCallback\n *\n * Callback interface used by owner-data list views to query and set\n * positions and grouping relations of items, and to receive cache hints.\n */\nDECLARE_INTERFACE_(IOwnerDataCallback, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    //\n    // IUnknown\n    //\n\n    DECLSPEC_XFGVIRT(IOwnerDataCallback, QueryInterface)\n    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;\n\n    DECLSPEC_XFGVIRT(IOwnerDataCallback, AddRef)\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IOwnerDataCallback, Release)\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    //\n    // IOwnerDataCallback\n    //\n\n    /**\n     * Retrieves the current position of an item.\n     *\n     * \\param itemIndex The zero-based index of the item.\n     * \\param pPosition Receives the item's position in view coordinates.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IOwnerDataCallback, GetItemPosition)\n    STDMETHOD(GetItemPosition)(THIS_ LONG itemIndex, LPPOINT pPosition) PURE;\n\n    /**\n     * Sets the position of an item.\n     *\n     * \\param itemIndex The zero-based index of the item.\n     * \\param position The desired item position in view coordinates.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IOwnerDataCallback, SetItemPosition)\n    STDMETHOD(SetItemPosition)(THIS_ LONG itemIndex, POINT position) PURE;\n\n    /**\n     * Maps a group-wide index to the control-wide item index.\n     *\n     * \\param groupIndex Zero-based list view group index.\n     * \\param groupWideItemIndex Zero-based index of the item within the group.\n     * \\param pTotalItemIndex Receives the control-wide item index.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IOwnerDataCallback, GetItemInGroup)\n    STDMETHOD(GetItemInGroup)(THIS_ LONG groupIndex, LONG groupWideItemIndex, PLONG pTotalItemIndex) PURE;\n\n    /**\n     * Retrieves the group for a specific occurrence of an item.\n     *\n     * \\param itemIndex Control-wide zero-based item index.\n     * \\param occurenceIndex Zero-based occurrence index of the item.\n     * \\param pGroupIndex Receives the group's zero-based index.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IOwnerDataCallback, GetItemGroup)\n    STDMETHOD(GetItemGroup)(THIS_ LONG itemIndex, LONG occurenceIndex, PLONG pGroupIndex) PURE;\n\n    /**\n     * Retrieves how often an item occurs in the control.\n     *\n     * \\param itemIndex Control-wide zero-based item index.\n     * \\param pOccurenceCount Receives the number of occurrences.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IOwnerDataCallback, GetItemGroupCount)\n    STDMETHOD(GetItemGroupCount)(THIS_ LONG itemIndex, PLONG pOccurenceCount) PURE;\n\n    /**\n     * Provides a cache hint for a range of items.\n     *\n     * \\param firstItem First item to cache (group-wide index).\n     * \\param lastItem Last item to cache (group-wide index).\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IOwnerDataCallback, OnCacheHint)\n    STDMETHOD(OnCacheHint)(THIS_ LVITEMINDEX firstItem, LVITEMINDEX lastItem) PURE;\n\n    END_INTERFACE\n};\n\n#undef INTERFACE\n#define INTERFACE ISubItemCallback\n/**\n * ISubItemCallback\n *\n * Callback interface for subitem operations in a custom list view. Allows\n * retrieving subitem titles, providing editing/controls per subitem or group,\n * and invoking custom verbs.\n */\nDECLARE_INTERFACE_(ISubItemCallback, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    //\n    // IUnknown\n    //\n\n    DECLSPEC_XFGVIRT(ISubItemCallback, QueryInterface)\n    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;\n\n    DECLSPEC_XFGVIRT(ISubItemCallback, AddRef)\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(ISubItemCallback, Release)\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    //\n    // ISubItemCallback\n    //\n\n    /**\n     * Retrieves the title of a subitem.\n     *\n     * \\param subItemIndex Zero-based subitem index.\n     * \\param pBuffer Wide-character buffer to receive the title.\n     * \\param bufferSize Buffer size in characters.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(ISubItemCallback, GetSubItemTitle)\n    STDMETHOD(GetSubItemTitle)(THIS_ LONG subItemIndex, PWSTR pBuffer, LONG bufferSize) PURE;\n\n    /**\n     * Retrieves a control interface for a specific subitem.\n     *\n     * \\param itemIndex Zero-based item index.\n     * \\param subItemIndex Zero-based subitem index.\n     * \\param requiredInterface IID of the required control interface.\n     * \\param ppObject Receives the interface pointer for the subitem control.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(ISubItemCallback, GetSubItemControl)\n    STDMETHOD(GetSubItemControl)(THIS_ LONG itemIndex, LONG subItemIndex, REFIID requiredInterface, void** ppObject) PURE; // IPropertyControl\n\n    /**\n     * Begins editing a subitem.\n     *\n     * \\param itemIndex Zero-based item index.\n     * \\param subItemIndex Zero-based subitem index.\n     * \\param mode Edit mode flags.\n     * \\param requiredInterface IID of the required editing control interface.\n     * \\param ppObject Receives the interface pointer for the editing control.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(ISubItemCallback, BeginSubItemEdit)\n    STDMETHOD(BeginSubItemEdit)(THIS_ LONG itemIndex, LONG subItemIndex, LONG mode, REFIID requiredInterface, void** ppObject) PURE; // IPropertyControl\n\n    /**\n     * Ends editing of a subitem.\n     *\n     * \\param itemIndex Zero-based item index.\n     * \\param subItemIndex Zero-based subitem index.\n     * \\param mode Edit mode flags.\n     * \\param pPropertyControl The property control used during editing.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(ISubItemCallback, EndSubItemEdit)\n    STDMETHOD(EndSubItemEdit)(THIS_ LONG itemIndex, LONG subItemIndex, LONG mode, void** ppObject) PURE; // IPropertyControl\n\n    /**\n     * Begins editing a group.\n     *\n     * \\param groupIndex Zero-based group index.\n     * \\param requiredInterface IID of the required editing control interface.\n     * \\param ppObject Receives the interface pointer for the editing control.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(ISubItemCallback, BeginGroupEdit)\n    STDMETHOD(BeginGroupEdit)(THIS_ LONG groupIndex, REFIID iid, void** ppObject) PURE; // IPropertyControl\n\n    /**\n     * Ends editing of a group.\n     *\n     * \\param groupIndex Zero-based group index.\n     * \\param mode Edit mode flags.\n     * \\param pPropertyControl The property control used during editing.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(ISubItemCallback, EndGroupEdit)\n    STDMETHOD(EndGroupEdit)(THIS_ LONG groupIndex, LONG mode, void** ppObject) PURE; // IPropertyControl\n\n    /**\n     * Invokes a custom verb on a subitem.\n     *\n     * \\param itemIndex Zero-based item index.\n     * \\param pVerb The verb to invoke (wide string).\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(ISubItemCallback, OnInvokeVerb)\n    STDMETHOD(OnInvokeVerb)(THIS_ LONG itemIndex, LPCWSTR pVerb) PURE;\n\n    END_INTERFACE\n};\n\n#undef INTERFACE\n#define INTERFACE IDrawPropertyControl\n/**\n * IDrawPropertyControl\n *\n * This interface defines methods for custom drawing of property controls within the application's\n * graphical user interface. Implementers provide the logic necessary to render the visuals.\n */\nDECLARE_INTERFACE_(IDrawPropertyControl, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    //\n    // IUnknown\n    //\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, QueryInterface)\n    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, AddRef)\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, Release)\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    //\n    // IPropertyControlBase\n    //\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, Initialize)\n    STDMETHOD(Initialize)(THIS_ IUnknown*, ULONG) PURE; // 2/calendar, 3/textbox\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, GetSize)\n    STDMETHOD(GetSize)(THIS_ enum PROPCTL_RECT_TYPE, HDC, SIZE const*, SIZE*) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, SetWindowTheme)\n    STDMETHOD(SetWindowTheme)(THIS_ PCWSTR, PCWSTR) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, SetFont)\n    STDMETHOD(SetFont)(THIS_ HFONT) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, SetForeColor)\n    STDMETHOD(SetForeColor)(THIS_ ULONG) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, GetFlags)\n    STDMETHOD(GetFlags)(THIS_ LONG*) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, SetFlags)\n    STDMETHOD(SetFlags)(THIS_ LONG, LONG) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, AdjustWindowRectPCB)\n    STDMETHOD(AdjustWindowRectPCB)(THIS_ HWND, RECT*, RECT const*, LONG) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, SetValue)\n    STDMETHOD(SetValue)(THIS_ IUnknown*) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, InvokeDefaultAction)\n    STDMETHOD(InvokeDefaultAction)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, Destroy)\n    STDMETHOD(Destroy)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, SetFormatFlags)\n    STDMETHOD(SetFormatFlags)(THIS_ LONG) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, GetFormatFlags)\n    STDMETHOD(GetFormatFlags)(THIS_ LONG*) PURE;\n\n    //\n    // IDrawPropertyControl\n    //\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, GetDrawFlags)\n    STDMETHOD(GetDrawFlags)(THIS_ PLONG Flags) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, WindowlessDraw)\n    STDMETHOD(WindowlessDraw)(THIS_ HDC hDC, RECT pDrawingRectangle, LONG a) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, HasVisibleContent)\n    STDMETHOD(HasVisibleContent)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, GetDisplayText)\n    STDMETHOD(GetDisplayText)(THIS_ PWSTR *Text) PURE;\n\n    DECLSPEC_XFGVIRT(IDrawPropertyControl, GetTooltipInfo)\n    STDMETHOD(GetTooltipInfo)(THIS_ HDC, SIZE const*, PLONG) PURE;\n\n    END_INTERFACE\n};\n\n#undef INTERFACE\n#define INTERFACE IPropertyControl\nDECLARE_INTERFACE_(IPropertyControl, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    //\n    // IUnknown\n    //\n\n    DECLSPEC_XFGVIRT(IPropertyControl, QueryInterface)\n    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;\n\n    DECLSPEC_XFGVIRT(IPropertyControl, AddRef)\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IPropertyControl, Release)\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    //\n    // IPropertyControl\n    //\n\n    DECLSPEC_XFGVIRT(IPropertyControl, GetValue)\n    STDMETHOD(GetValue)(THIS_ REFIID riid, void** ppvObject) PURE;\n\n    DECLSPEC_XFGVIRT(IPropertyControl, Create)\n    STDMETHOD(Create)(THIS_ HWND Parent, RECT const* ItemRectangle, RECT const* Unknown1, int Unknown2) PURE;\n\n    DECLSPEC_XFGVIRT(IPropertyControl, SetPosition)\n    STDMETHOD(SetPosition)(THIS_ RECT const*, RECT const*) PURE;\n\n    DECLSPEC_XFGVIRT(IPropertyControl, IsModified)\n    STDMETHOD(IsModified)(THIS_ PBOOL Modified) PURE;\n\n    DECLSPEC_XFGVIRT(IPropertyControl, SetModified)\n    STDMETHOD(SetModified)(THIS_ BOOL Modified) PURE;\n\n    DECLSPEC_XFGVIRT(IPropertyControl, ValidationFailed)\n    STDMETHOD(ValidationFailed)(THIS_ PCWSTR) PURE;\n\n    DECLSPEC_XFGVIRT(IPropertyControl, GetState)\n    STDMETHOD(GetState)(THIS_ PULONG State) PURE;\n\n    END_INTERFACE\n};\n\n#undef INTERFACE\n#define INTERFACE IListView\nDECLARE_INTERFACE_(IListView, IUnknown) // real name is IListView2\n{\n    BEGIN_INTERFACE\n\n    //\n    // IUnknown\n    //\n\n    DECLSPEC_XFGVIRT(IListView, QueryInterface)\n    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, AddRef)\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, Release)\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    //\n    // IOleWindow\n    //\n\n    DECLSPEC_XFGVIRT(IListView, GetWindow)\n    STDMETHOD(GetWindow)(THIS_ __RPC__in IOleWindow* window, __RPC__deref_out_opt HWND* WindowHandle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, ContextSensitiveHelp)\n    STDMETHOD(ContextSensitiveHelp)(THIS_ __RPC__in IOleWindow* window, _In_ BOOL fEnterMode) PURE;\n\n    //\n    // IListView\n    //\n\n    /**\n     * Retrieves the handle to the image list used by the list view.\n     *\n     * \\param ImageListType The type of image list to retrieve (e.g., normal, small, state).\n     * \\param ImageList Pointer to a variable that receives the handle to the image list.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IListView, GetImageList)\n    STDMETHOD(GetImageList)(THIS_ LONG ImageListType, HIMAGELIST* ImageList) PURE;\n\n    /**\n     * Sets a new image list for the list view and optionally retrieves the handle to the previous image list.\n     *\n     * \\param ImageListType The type of image list to set (e.g., normal, small, state).\n     * \\param NewImageList Handle to the new image list to associate with the list view.\n     * \\param OldImageList Pointer to a variable that receives the handle to the previous image list.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IListView, SetImageList)\n    STDMETHOD(SetImageList)(THIS_ LONG ImageListType, HIMAGELIST NewImageList, HIMAGELIST* OldImageList) PURE;\n\n    /**\n     * Retrieves the current background color of the list view.\n     *\n     * \\param Color Pointer to a variable that receives the background color (COLORREF).\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IListView, GetBackgroundColor)\n    STDMETHOD(GetBackgroundColor)(THIS_ COLORREF* Color) PURE;\n\n    /**\n     * Sets the background color of the list view.\n     *\n     * \\param color The new background color (COLORREF) to set.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IListView, SetBackgroundColor)\n    STDMETHOD(SetBackgroundColor)(THIS_ COLORREF Color) PURE;\n\n    /**\n     * \\brief Retrieves the current text color used by the list view.\n     *\n     * \\param[out] Color Pointer to a COLORREF variable that receives the current text color.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IListView, GetTextColor)\n    STDMETHOD(GetTextColor)(THIS_ COLORREF* Color) PURE;\n\n    /**\n     * \\brief Sets the foreground (text) color for the list view.\n     *\n     * \\param[in] Color The COLORREF value specifying the new text color.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IListView, SetForeColor)\n    STDMETHOD(SetForeColor)(THIS_ COLORREF Color) PURE;\n\n    /**\n     * \\brief Retrieves the current background color used for the text in the list view.\n     *\n     * \\param[out] Color Pointer to a COLORREF variable that receives the current text background color.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IListView, GetTextBackgroundColor)\n    STDMETHOD(GetTextBackgroundColor)(THIS_ COLORREF* Color) PURE;\n\n    /**\n     * \\brief Sets the background color for the text in the list view.\n     *\n     * \\param[in] color The COLORREF value specifying the new text background color.\n     * \\return HRESULT indicating success or failure.\n     */\n    DECLSPEC_XFGVIRT(IListView, SetTextBackgroundColor)\n    STDMETHOD(SetTextBackgroundColor)(THIS_ COLORREF Color) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetHotLightColor)\n    STDMETHOD(GetHotLightColor)(THIS_ COLORREF* Color) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetHotLightColor)\n    STDMETHOD(SetHotLightColor)(THIS_ COLORREF Color) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetItemCount)\n    STDMETHOD(GetItemCount)(THIS_ PLONG ItemCount) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetItemCount)\n    STDMETHOD(SetItemCount)(THIS_ LONG ItemCount, ULONG Flags) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetItem)\n    STDMETHOD(GetItem)(THIS_ LVITEMW* Item) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetItem)\n    STDMETHOD(SetItem)(THIS_ LVITEMW* const Item) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetItemState)\n    STDMETHOD(GetItemState)(THIS_ LONG ItemIndex, LONG SubItemIndex, ULONG Mask, PULONG State) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetItemState)\n    STDMETHOD(SetItemState)(THIS_ LONG ItemIndex, LONG SubItemIndex, ULONG Mask, ULONG State) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetItemText)\n    STDMETHOD(GetItemText)(THIS_ LONG ItemIndex, LONG SubItemIndex, PWSTR Buffer, LONG BufferSize) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetItemText)\n    STDMETHOD(SetItemText)(THIS_ LONG ItemIndex, LONG SubItemIndex, PCWSTR Text) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetBackgroundImage)\n    STDMETHOD(GetBackgroundImage)(THIS_ LVBKIMAGEW* pBkImage) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetBackgroundImage)\n    STDMETHOD(SetBackgroundImage)(THIS_ LVBKIMAGEW* const BkImage) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetFocusedColumn)\n    STDMETHOD(GetFocusedColumn)(THIS_ PLONG ColumnIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetSelectionFlags)\n    STDMETHOD(SetSelectionFlags)(THIS_ LONG Mask, LONG Flags) PURE; // HRESULT SetSelectionFlags (SELECTION_FLAGS, SELECTION_FLAGS);\n\n    DECLSPEC_XFGVIRT(IListView, GetSelectedColumn)\n    STDMETHOD(GetSelectedColumn)(THIS_ PLONG ColumnIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetSelectedColumn)\n    STDMETHOD(SetSelectedColumn)(THIS_ LONG ColumnIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetView)\n    STDMETHOD(GetView)(THIS_ PULONG View) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetView)\n    STDMETHOD(SetView)(THIS_ ULONG View) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, InsertItem)\n    STDMETHOD(InsertItem)(THIS_ LVITEMW* const Item, PLONG ItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, DeleteItem)\n    STDMETHOD(DeleteItem)(THIS_ LONG ItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, DeleteAllItems)\n    STDMETHOD(DeleteAllItems)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, UpdateItem)\n    STDMETHOD(UpdateItem)(THIS_ LONG ItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetItemRect)\n    STDMETHOD(GetItemRect)(THIS_ LVITEMINDEX ItemIndex, LONG RectangleType, PRECT Rectangle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetSubItemRect)\n    STDMETHOD(GetSubItemRect)(THIS_ LVITEMINDEX ItemIndex, LONG SubItemIndex, LONG RectangleType, PRECT Rectangle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, HitTestSubItem)\n    STDMETHOD(HitTestSubItem)(THIS_ LVHITTESTINFO* HitTestData) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetIncrSearchString)\n    STDMETHOD(GetIncrSearchString)(THIS_ PWSTR Buffer, LONG BufferSize, PLONG CopiedChars) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetItemSpacing)\n    STDMETHOD(GetItemSpacing)(THIS_ BOOL SmallIconView, PLONG HorizontalSpacing, PLONG VerticalSpacing) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetIconSpacing)\n    STDMETHOD(SetIconSpacing)(THIS_ LONG HorizontalSpacing, LONG VerticalSpacing, PLONG OldHorizontalSpacing, PLONG OldVerticalSpacing) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetNextItem)\n    STDMETHOD(GetNextItem)(THIS_ LVITEMINDEX ItemIndex, ULONG Flags, LVITEMINDEX* NextItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, FindItem)\n    STDMETHOD(FindItem)(THIS_ LVITEMINDEX startItemIndex, LVFINDINFOW const* FindInfo, LVITEMINDEX* FoundItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetSelectionMark)\n    STDMETHOD(GetSelectionMark)(THIS_ LVITEMINDEX* SelectionMark) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetSelectionMark)\n    STDMETHOD(SetSelectionMark)(THIS_ LVITEMINDEX NewSelectionMark, LVITEMINDEX* OldSelectionMark) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetItemPosition)\n    STDMETHOD(GetItemPosition)(THIS_ LVITEMINDEX ItemIndex, POINT* Position) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetItemPosition)\n    STDMETHOD(SetItemPosition)(THIS_ LONG ItemIndex, POINT const* Position) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, ScrollView)\n    STDMETHOD(ScrollView)(THIS_ ULONG HorizontalScrollDistance, ULONG VerticalScrollDistance) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, EnsureItemVisible)\n    STDMETHOD(EnsureItemVisible)(THIS_ LVITEMINDEX ItemIndex, BOOL PartialOk) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, EnsureSubItemVisible)\n    STDMETHOD(EnsureSubItemVisible)(THIS_ LVITEMINDEX ItemIndex, LONG SubItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, EditSubItem)\n    STDMETHOD(EditSubItem)(THIS_ LVITEMINDEX ItemIndex, LONG SubItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, RedrawItems)\n    STDMETHOD(RedrawItems)(THIS_ LONG FirstItemIndex, LONG LastItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, ArrangeItems)\n    STDMETHOD(ArrangeItems)(THIS_ LONG Mode) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, RecomputeItems)\n    STDMETHOD(RecomputeItems)(THIS_ LONG Mode) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetEditControl)\n    STDMETHOD(GetEditControl)(THIS_ HWND* EditWindowHandle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, EditLabel)\n    STDMETHOD(EditLabel)(THIS_ LVITEMINDEX ItemIndex, PCWSTR InitialEditText, HWND* EditWindowHandle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, EditGroupLabel)\n    STDMETHOD(EditGroupLabel)(THIS_ LONG GroupIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, CancelEditLabel)\n    STDMETHOD(CancelEditLabel)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetEditItem)\n    STDMETHOD(GetEditItem)(THIS_ LVITEMINDEX* ItemIndex, PLONG SubItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, HitTest)\n    STDMETHOD(HitTest)(THIS_ LVHITTESTINFO* HitTestData) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetStringWidth)\n    STDMETHOD(GetStringWidth)(THIS_ PCWSTR String, PLONG Width) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetColumn)\n    STDMETHOD(GetColumn)(THIS_ LONG ColumnIndex, LVCOLUMNW* Column) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetColumn)\n    STDMETHOD(SetColumn)(THIS_ LONG ColumnIndex, LVCOLUMNW* const Column) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetColumnOrderArray)\n    STDMETHOD(GetColumnOrderArray)(THIS_ LONG NumberOfColumns, _Out_ PVOID* Columns) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetColumnOrderArray)\n    STDMETHOD(SetColumnOrderArray)(THIS_ LONG NumberOfColumns, _In_ PVOID Columns) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetHeaderControl)\n    STDMETHOD(GetHeaderControl)(THIS_ HWND* HeaderWindowHandle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, InsertColumn)\n    STDMETHOD(InsertColumn)(THIS_ LONG InsertAt, LVCOLUMNW* const Column, PLONG ColumnIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, DeleteColumn)\n    STDMETHOD(DeleteColumn)(THIS_ LONG ColumnIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, CreateDragImage)\n    STDMETHOD(CreateDragImage)(THIS_ LONG ItemIndex, POINT const* UpperLeft, HIMAGELIST* ImageList) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetViewRect)\n    STDMETHOD(GetViewRect)(THIS_ RECT* Rectangle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetClientRect)\n    STDMETHOD(GetClientRect)(THIS_ BOOL StyleAndClientRect, RECT* ClientRectangle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetColumnWidth)\n    STDMETHOD(GetColumnWidth)(THIS_ LONG ColumnIndex, PLONG Width) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetColumnWidth)\n    STDMETHOD(SetColumnWidth)(THIS_ LONG ColumnIndex, LONG Width) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetCallbackMask)\n    STDMETHOD(GetCallbackMask)(THIS_ PULONG Mask) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetCallbackMask)\n    STDMETHOD(SetCallbackMask)(THIS_ ULONG Mask) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetTopIndex)\n    STDMETHOD(GetTopIndex)(THIS_ PLONG TopIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetCountPerPage)\n    STDMETHOD(GetCountPerPage)(THIS_ PLONG CountPerPage) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetOrigin)\n    STDMETHOD(GetOrigin)(THIS_ POINT* Origin) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetSelectedCount)\n    STDMETHOD(GetSelectedCount)(THIS_ PLONG SelectedCount) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SortItems)\n    STDMETHOD(SortItems)(THIS_ BOOL SortingByIndex, LPARAM lParam, PFNLVCOMPARE ComparisonFunction) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetExtendedStyle)\n    STDMETHOD(GetExtendedStyle)(THIS_ PULONG Style) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetExtendedStyle)\n    STDMETHOD(SetExtendedStyle)(THIS_ ULONG Mask, ULONG Style, PULONG OldStyle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetHoverTime)\n    STDMETHOD(GetHoverTime)(THIS_ PULONG Time) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetHoverTime)\n    STDMETHOD(SetHoverTime)(THIS_ ULONG Time, PULONG OldSetting) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetToolTip)\n    STDMETHOD(GetToolTip)(THIS_ HWND* ToolTipWindowHandle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetToolTip)\n    STDMETHOD(SetToolTip)(THIS_ HWND ToolTipWindowHandle, HWND* OldToolTipWindowHandle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetHotItem)\n    STDMETHOD(GetHotItem)(THIS_ LVITEMINDEX* HotItem) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetHotItem)\n    STDMETHOD(SetHotItem)(THIS_ LVITEMINDEX NewHotItem, LVITEMINDEX* OldHotItem) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetHotCursor)\n    STDMETHOD(GetHotCursor)(THIS_ HCURSOR* Cursor) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetHotCursor)\n    STDMETHOD(SetHotCursor)(THIS_ HCURSOR Cursor, HCURSOR* OldCursor) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, ApproximateViewRect)\n    STDMETHOD(ApproximateViewRect)(THIS_ LONG ItemCount, PLONG Width, PLONG Height) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetRangeObject)\n    STDMETHOD(SetRangeObject)(THIS_ LONG unknown, void** Object) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetWorkAreas)\n    STDMETHOD(GetWorkAreas)(THIS_ LONG NumberOfWorkAreas, RECT* WorkAreas) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetWorkAreas)\n    STDMETHOD(SetWorkAreas)(THIS_ LONG NumberOfWorkAreas, RECT const* WorkAreas) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetWorkAreaCount)\n    STDMETHOD(GetWorkAreaCount)(THIS_ PLONG NumberOfWorkAreas) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, ResetEmptyText)\n    STDMETHOD(ResetEmptyText)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, EnableGroupView)\n    STDMETHOD(EnableGroupView)(THIS_ BOOL Enable) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, IsGroupViewEnabled)\n    STDMETHOD(IsGroupViewEnabled)(THIS_ PBOOL IsEnabled) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SortGroups)\n    STDMETHOD(SortGroups)(THIS_ PFNLVGROUPCOMPARE pComparisonFunction, PVOID lParam) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetGroupInfo)\n    STDMETHOD(GetGroupInfo)(THIS_ BOOL GetGroupInfoByIndex, LONG GroupIDOrIndex, LVGROUP* Group) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetGroupInfo)\n    STDMETHOD(SetGroupInfo)(THIS_ BOOL SetGroupInfoByIndex, LONG GroupIDOrIndex, LVGROUP* const Group) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetGroupRect)\n    STDMETHOD(GetGroupRect)(THIS_ BOOL GetGroupRectByIndex, LONG GroupIDOrIndex, LONG RectangleType, RECT* pRectangle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetGroupState)\n    STDMETHOD(GetGroupState)(THIS_ LONG GroupID, ULONG Mask, PULONG State) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, HasGroup)\n    STDMETHOD(HasGroup)(THIS_ LONG GroupID, BOOL* HasGroup) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, InsertGroup)\n    STDMETHOD(InsertGroup)(THIS_ LONG InsertAt, LVGROUP* const Group, PLONG GroupID) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, RemoveGroup)\n    STDMETHOD(RemoveGroup)(THIS_ LONG GroupID) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, InsertGroupSorted)\n    STDMETHOD(InsertGroupSorted)(THIS_ LVINSERTGROUPSORTED const* Group, PLONG GroupID) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetGroupMetrics)\n    STDMETHOD(GetGroupMetrics)(THIS_ LVGROUPMETRICS* Metrics) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetGroupMetrics)\n    STDMETHOD(SetGroupMetrics)(THIS_ LVGROUPMETRICS* const Metrics) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, RemoveAllGroups)\n    STDMETHOD(RemoveAllGroups)(THIS) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetFocusedGroup)\n    STDMETHOD(GetFocusedGroup)(THIS_ PLONG pGroupID) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetGroupCount)\n    STDMETHOD(GetGroupCount)(THIS_ PLONG pCount) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetOwnerDataCallback)\n    STDMETHOD(SetOwnerDataCallback)(THIS_ IOwnerDataCallback* pCallback) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetTileViewInfo)\n    STDMETHOD(GetTileViewInfo)(THIS_ LVTILEVIEWINFO* pInfo) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetTileViewInfo)\n    STDMETHOD(SetTileViewInfo)(THIS_ LVTILEVIEWINFO* const pInfo) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetTileInfo)\n    STDMETHOD(GetTileInfo)(THIS_ LVTILEINFO* pTileInfo) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetTileInfo)\n    STDMETHOD(SetTileInfo)(THIS_ LVTILEINFO* const pTileInfo) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetInsertMark)\n    STDMETHOD(GetInsertMark)(THIS_ LVINSERTMARK* pInsertMarkDetails) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetInsertMark)\n    STDMETHOD(SetInsertMark)(THIS_ LVINSERTMARK const* pInsertMarkDetails) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetInsertMarkRect)\n    STDMETHOD(GetInsertMarkRect)(THIS_ LPRECT pInsertMarkRectangle) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetInsertMarkColor)\n    STDMETHOD(GetInsertMarkColor)(THIS_ COLORREF* pColor) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetInsertMarkColor)\n    STDMETHOD(SetInsertMarkColor)(THIS_ COLORREF color, COLORREF* pOldColor) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, HitTestInsertMark)\n    STDMETHOD(HitTestInsertMark)(THIS_ POINT const* Point, LVINSERTMARK* pInsertMarkDetails) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetInfoTip)\n    STDMETHOD(SetInfoTip)(THIS_ LVSETINFOTIP* const InfoTip) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetOutlineColor)\n    STDMETHOD(GetOutlineColor)(THIS_ COLORREF* Color) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetOutlineColor)\n    STDMETHOD(SetOutlineColor)(THIS_ COLORREF Color, COLORREF* OldColor) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetFrozenItem)\n    STDMETHOD(GetFrozenItem)(THIS_ PLONG ItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetFrozenItem)\n    STDMETHOD(SetFrozenItem)(THIS_ LONG ItemIndexStart, LONG ItemIndexEnd) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetFrozenSlot)\n    STDMETHOD(GetFrozenSlot)(THIS_ RECT* Rect) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetFrozenSlot)\n    STDMETHOD(SetFrozenSlot)(THIS_ LONG Slot, POINT const* Rect) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetViewMargin)\n    STDMETHOD(GetViewMargin)(THIS_ RECT* Margin) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetViewMargin)\n    STDMETHOD(SetViewMargin)(THIS_ RECT const* Margin) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetKeyboardSelected)\n    STDMETHOD(SetKeyboardSelected)(THIS_ LVITEMINDEX ItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, MapIndexToId)\n    STDMETHOD(MapIndexToId)(THIS_ LONG ItemIndex, PLONG ItemID) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, MapIdToIndex)\n    STDMETHOD(MapIdToIndex)(THIS_ LONG ItemID, PLONG ItemIndex) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, IsItemVisible)\n    STDMETHOD(IsItemVisible)(THIS_ LVITEMINDEX ItemIndex, BOOL* Visible) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, EnableAlphaShadow)\n    STDMETHOD(EnableAlphaShadow)(THIS_ BOOL Enable) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetGroupSubsetCount)\n    STDMETHOD(GetGroupSubsetCount)(THIS_ PLONG NumberOfRowsDisplayed) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetGroupSubsetCount)\n    STDMETHOD(SetGroupSubsetCount)(THIS_ LONG NumberOfRowsToDisplay) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetVisibleSlotCount)\n    STDMETHOD(GetVisibleSlotCount)(THIS_ PLONG Count) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetColumnMargin)\n    STDMETHOD(GetColumnMargin)(THIS_ RECT* Margin) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetSubItemCallback)\n    STDMETHOD(SetSubItemCallback)(THIS_ LPVOID Callback) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, GetVisibleItemRange)\n    STDMETHOD(GetVisibleItemRange)(THIS_ LVITEMINDEX* FirstItem, LVITEMINDEX* LastItem) PURE;\n\n    DECLSPEC_XFGVIRT(IListView, SetTypeAheadFlags)\n    STDMETHOD(SetTypeAheadFlags)(THIS_ ULONG Mask, ULONG Flags) PURE; // HRESULT SetTypeAheadFlags (TYPEAHEAD_FLAGS, TYPEAHEAD_FLAGS);\n\n    // Windows 10\n\n    /**\n     * \\brief Sets the work areas with DPI awareness for the view.\n     *\n     * \\param [in] LONG The number of work areas to set.\n     * \\param [in] struct tagLVWORKAREAWITHDPI const* Pointer to an array of LVWORKAREAWITHDPI structures that define the work areas and their associated DPI settings.\n     * \\return HRESULT Returns S_OK if successful, or an error code otherwise.\n     */\n    DECLSPEC_XFGVIRT(IListView, SetWorkAreasWithDpi)\n    STDMETHOD(SetWorkAreasWithDpi)(THIS_ LONG index, struct tagLVWORKAREAWITHDPI const*) PURE;\n\n    /**\n     * \\brief Retrieves the work areas along with their associated DPI settings.\n     *\n     * \\param [in] LONG The index or identifier for the work area.\n     * \\param [out] tagLVWORKAREAWITHDPI* Pointer to a structure that receives the work area information and its DPI.\n     *\n     * \\return HRESULT indicating success or failure of the operation.\n     */\n    DECLSPEC_XFGVIRT(IListView, GetWorkAreasWithDpi)\n    STDMETHOD(GetWorkAreasWithDpi)(THIS_ LONG index, struct tagLVWORKAREAWITHDPI*) PURE;\n\n    /**\n     * Sets the image list for the work area.\n     *\n     * \\param [in] param1 The first LONG parameter (purpose depends on implementation).\n     * \\param [in] param2 The second LONG parameter (purpose depends on implementation).\n     * \\param [in] hImageList Handle to the image list to be set.\n     * \\param [out] phOldImageList Pointer to a variable that receives the handle to the previous image list.\n     * \\return HRESULT Returns S_OK on success, or an error code otherwise.\n     */\n    DECLSPEC_XFGVIRT(IListView, SetWorkAreaImageList)\n    STDMETHOD(SetWorkAreaImageList)(THIS_ LONG param1, LONG param2, HIMAGELIST hImageList, HIMAGELIST* phOldImageList) PURE;\n\n    /**\n     * Retrieves the image list associated with a specified work area.\n     *\n     * \\param [in] param1 The first LONG parameter, typically representing the work area index or identifier.\n     * \\param [in] param2 The second LONG parameter, usage depends on implementation context.\n     * \\param [out] phImageList Pointer to a HIMAGELIST that receives the handle to the image list.\n     * \\return HRESULT Returns S_OK on success, or an error code otherwise.\n     */\n    DECLSPEC_XFGVIRT(IListView, GetWorkAreaImageList)\n    STDMETHOD(GetWorkAreaImageList)(THIS_ LONG param1, LONG param2, HIMAGELIST* phImageList) PURE;\n\n    /**\n     * Enables or disables the \"Icon Bullying\" feature.\n     *\n     * This method controls the behavior of icon manipulation within the interface.\n     *\n     * \\param Mode Specifies the mode for icon bullying.\n     * \\return HRESULT indicating success or failure of the operation.\n     */\n    DECLSPEC_XFGVIRT(IListView, EnableIconBullying)\n    STDMETHOD(EnableIconBullying)(THIS_ LONG Mode) PURE;\n\n    /**\n     * \\brief Enables or configures specific quirks or compatibility modes.\n     *\n     * \\param Flags A bitmask of flags specifying which quirks to enable.\n     * \\return HRESULT indicating success or failure of the operation.\n     */\n    DECLSPEC_XFGVIRT(IListView, EnableQuirks)\n    STDMETHOD(EnableQuirks)(THIS_ ULONG Flags) PURE;\n\n    END_INTERFACE\n};\n\n#undef INTERFACE\n\n#define IListViewQueryInterface(This,riid,ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))\n#define IListView_AddRef(This) \\\n    ((This)->lpVtbl->AddRef(This))\n#define IListView_Release(This) \\\n    ((This)->lpVtbl->Release(This))\n#define IListView_GetWindow(This, OleWindow, WindowHandle) \\\n    ((This)->lpVtbl->GetWindow(This, OleWindow, WindowHandle))\n#define IListView_ContextSensitiveHelp(This, fEnterMode) \\\n    ((This)->lpVtbl->ContextSensitiveHelp(This, fEnterMode))\n#define IListView_GetImageList(This, imageList, pHImageList) \\\n    ((This)->lpVtbl->GetImageList(This, imageList, pHImageList))\n#define IListView_SetImageList(This, imageList, hNewImageList, pHOldImageList) \\\n    ((This)->lpVtbl->SetImageList(This, imageList, hNewImageList, pHOldImageList))\n#define IListView_GetBackgroundColor(This, pColor) \\\n    ((This)->lpVtbl->GetBackgroundColor(This, pColor))\n#define IListView_SetBackgroundColor(This, color) \\\n    ((This)->lpVtbl->SetBackgroundColor(This, color))\n#define IListView_GetTextColor(This, pColor) \\\n    ((This)->lpVtbl->GetTextColor(This, pColor))\n#define IListView_SetTextColor(This, color) \\\n    ((This)->lpVtbl->SetTextColor(This, color))\n#define IListView_GetTextBackgroundColor(This, pColor) \\\n    ((This)->lpVtbl->GetTextBackgroundColor(This, pColor))\n#define IListView_SetTextBackgroundColor(This, color) \\\n    ((This)->lpVtbl->SetTextBackgroundColor(This, color))\n#define IListView_GetHotLightColor(This, pColor) \\\n    ((This)->lpVtbl->GetHotLightColor(This, pColor))\n#define IListView_SetHotLightColor(This, color) \\\n    ((This)->lpVtbl->SetHotLightColor(This, color))\n#define IListView_GetItemCount(This, pItemCount) \\\n    ((This)->lpVtbl->GetItemCount(This, pItemCount))\n#define IListView_SetItemCount(This, itemCount, flags) \\\n    ((This)->lpVtbl->SetItemCount(This, itemCount, flags))\n#define IListView_GetItem(This, pItem) \\\n    ((This)->lpVtbl->GetItem(This, pItem))\n#define IListView_SetItem(This, pItem) \\\n    ((This)->lpVtbl->SetItem(This, pItem))\n#define IListView_GetItemState(This, itemIndex, subItemIndex, mask, pState) \\\n    ((This)->lpVtbl->GetItemState(This, itemIndex, subItemIndex, mask, pState))\n#define IListView_SetItemState(This, itemIndex, subItemIndex, mask, state) \\\n    ((This)->lpVtbl->SetItemState(This, itemIndex, subItemIndex, mask, state))\n#define IListView_GetItemText(This, itemIndex, subItemIndex, pBuffer, bufferSize) \\\n    ((This)->lpVtbl->GetItemText(This, itemIndex, subItemIndex, pBuffer, bufferSize))\n#define IListView_SetItemText(This, itemIndex, subItemIndex, pText) \\\n    ((This)->lpVtbl->SetItemText(This, itemIndex, subItemIndex, pText))\n#define IListView_GetBackgroundImage(This, pBkImage) \\\n    ((This)->lpVtbl->GetBackgroundImage(This, pBkImage))\n#define IListView_SetBackgroundImage(This, pBkImage) \\\n    ((This)->lpVtbl->SetBackgroundImage(This, pBkImage))\n#define IListView_GetFocusedColumn(This, pColumnIndex) \\\n    ((This)->lpVtbl->GetFocusedColumn(This, pColumnIndex))\n#define IListView_SetSelectionFlags(This, mask, flags) \\\n    ((This)->lpVtbl->SetSelectionFlags(This, mask, flags))\n#define IListView_GetSelectedColumn(This, pColumnIndex) \\\n    ((This)->lpVtbl->GetSelectedColumn(This, pColumnIndex))\n#define IListView_SetSelectedColumn(This, columnIndex) \\\n    ((This)->lpVtbl->SetSelectedColumn(This, columnIndex))\n#define IListView_GetView(This, pView) \\\n    ((This)->lpVtbl->GetView(This, pView))\n#define IListView_SetView(This, view) \\\n    ((This)->lpVtbl->SetView(This, view))\n#define IListView_InsertItem(This, pItem, pItemIndex) \\\n    ((This)->lpVtbl->InsertItem(This, pItem, pItemIndex))\n#define IListView_DeleteItem(This, itemIndex) \\\n    ((This)->lpVtbl->DeleteItem(This, itemIndex))\n#define IListView_DeleteAllItems(This) \\\n    ((This)->lpVtbl->DeleteAllItems(This))\n#define IListView_UpdateItem(This, itemIndex) \\\n    ((This)->lpVtbl->UpdateItem(This, itemIndex))\n#define IListView_GetItemRect(This, itemIndex, rectangleType, pRectangle) \\\n    ((This)->lpVtbl->GetItemRect(This, itemIndex, rectangleType, pRectangle))\n#define IListView_GetSubItemRect(This, itemIndex, subItemIndex, rectangleType, pRectangle) \\\n    ((This)->lpVtbl->GetSubItemRect(This, itemIndex, subItemIndex, rectangleType, pRectangle))\n#define IListView_HitTestSubItem(This, pHitTestData) \\\n    ((This)->lpVtbl->HitTestSubItem(This, pHitTestData))\n#define IListView_GetIncrSearchString(This, pBuffer, bufferSize, pCopiedChars) \\\n    ((This)->lpVtbl->GetIncrSearchString(This, pBuffer, bufferSize, pCopiedChars))\n#define IListView_GetItemSpacing(This, smallIconView, pHorizontalSpacing, pVerticalSpacing) \\\n    ((This)->lpVtbl->GetItemSpacing(This, smallIconView, pHorizontalSpacing, pVerticalSpacing))\n#define IListView_SetIconSpacing(This, horizontalSpacing, verticalSpacing, pHorizontalSpacing, pVerticalSpacing) \\\n    ((This)->lpVtbl->SetIconSpacing(This, horizontalSpacing, verticalSpacing, pHorizontalSpacing, pVerticalSpacing))\n#define IListView_GetNextItem(This, itemIndex, flags, pNextItemIndex) \\\n    ((This)->lpVtbl->GetNextItem(This, itemIndex, flags, pNextItemIndex))\n#define IListView_FindItem(This, startItemIndex, pFindInfo, pFoundItemIndex) \\\n    ((This)->lpVtbl->FindItem(This, startItemIndex, pFindInfo, pFoundItemIndex))\n#define IListView_GetSelectionMark(This, pSelectionMark) \\\n    ((This)->lpVtbl->GetSelectionMark(This, pSelectionMark))\n#define IListView_SetSelectionMark(This, newSelectionMark, pOldSelectionMark) \\\n    ((This)->lpVtbl->SetSelectionMark(This, newSelectionMark, pOldSelectionMark))\n#define IListView_GetItemPosition(This, itemIndex, pPosition) \\\n    ((This)->lpVtbl->GetItemPosition(This, itemIndex, pPosition))\n#define IListView_SetItemPosition(This, itemIndex, pPosition) \\\n    ((This)->lpVtbl->SetItemPosition(This, itemIndex, pPosition))\n#define IListView_ScrollView(This, horizontalScrollDistance, verticalScrollDistance) \\\n    ((This)->lpVtbl->ScrollView(This, horizontalScrollDistance, verticalScrollDistance))\n#define IListView_EnsureItemVisible(This, itemIndex, partialOk) \\\n    ((This)->lpVtbl->EnsureItemVisible(This, itemIndex, partialOk))\n#define IListView_EnsureSubItemVisible(This, itemIndex, subItemIndex) \\\n    ((This)->lpVtbl->EnsureSubItemVisible(This, itemIndex, subItemIndex))\n#define IListView_EditSubItem(This, itemIndex, subItemIndex) \\\n    ((This)->lpVtbl->EditSubItem(This, itemIndex, subItemIndex))\n#define IListView_RedrawItems(This, firstItemIndex, lastItemIndex) \\\n    ((This)->lpVtbl->RedrawItems(This, firstItemIndex, lastItemIndex))\n#define IListView_ArrangeItems(This, mode) \\\n    ((This)->lpVtbl->ArrangeItems(This, mode))\n#define IListView_RecomputeItems(This, unknown) \\\n    ((This)->lpVtbl->RecomputeItems(This, unknown))\n#define IListView_GetEditControl(This, EditWindowHandle) \\\n    ((This)->lpVtbl->GetEditControl(This, EditWindowHandle))\n#define IListView_EditLabel(This, itemIndex, initialEditText, EditWindowHandle) \\\n    ((This)->lpVtbl->EditLabel(This, itemIndex, initialEditText, EditWindowHandle))\n#define IListView_EditGroupLabel(This, groupIndex) \\\n    ((This)->lpVtbl->EditGroupLabel(This, groupIndex))\n#define IListView_CancelEditLabel(This) \\\n    ((This)->lpVtbl->CancelEditLabel(This))\n#define IListView_GetEditItem(This, itemIndex, subItemIndex) \\\n    ((This)->lpVtbl->GetEditItem(This, itemIndex, subItemIndex))\n#define IListView_HitTest(This, pHitTestData) \\\n    ((This)->lpVtbl->HitTest(This, pHitTestData))\n#define IListView_GetStringWidth(This, pString, pWidth) \\\n    ((This)->lpVtbl->GetStringWidth(This, pString, pWidth))\n#define IListView_GetColumn(This, columnIndex, pColumn) \\\n    ((This)->lpVtbl->GetColumn(This, columnIndex, pColumn))\n#define IListView_SetColumn(This, columnIndex, pColumn) \\\n    ((This)->lpVtbl->SetColumn(This, columnIndex, pColumn))\n#define IListView_GetColumnOrderArray(This, numberOfColumns, pColumns) \\\n    ((This)->lpVtbl->GetColumnOrderArray(This, numberOfColumns, pColumns))\n#define IListView_SetColumnOrderArray(This, numberOfColumns, pColumns) \\\n    ((This)->lpVtbl->SetColumnOrderArray(This, numberOfColumns, pColumns))\n#define IListView_GetHeaderControl(This, HeaderWindowHandle) \\\n    ((This)->lpVtbl->GetHeaderControl(This, HeaderWindowHandle))\n#define IListView_InsertColumn(This, insertAt, pColumn, pColumnIndex) \\\n    ((This)->lpVtbl->InsertColumn(This, insertAt, pColumn, pColumnIndex))\n#define IListView_DeleteColumn(This, columnIndex) \\\n    ((This)->lpVtbl->DeleteColumn(This, columnIndex))\n#define IListView_CreateDragImage(This, itemIndex, pUpperLeft, pHImageList) \\\n    ((This)->lpVtbl->CreateDragImage(This, itemIndex, pUpperLeft, pHImageList))\n#define IListView_GetViewRect(This, pRectangle) \\\n    ((This)->lpVtbl->GetViewRect(This, pRectangle))\n#define IListView_GetClientRect(This, unknown, pClientRectangle) \\\n    ((This)->lpVtbl->GetClientRect(This, unknown, pClientRectangle))\n#define IListView_GetColumnWidth(This, columnIndex, pWidth) \\\n    ((This)->lpVtbl->GetColumnWidth(This, columnIndex, pWidth))\n#define IListView_SetColumnWidth(This, columnIndex, width) \\\n    ((This)->lpVtbl->SetColumnWidth(This, columnIndex, width))\n#define IListView_GetCallbackMask(This, pMask) \\\n    ((This)->lpVtbl->GetCallbackMask(This, pMask))\n#define IListView_SetCallbackMask(This, mask) \\\n    ((This)->lpVtbl->SetCallbackMask(This, mask))\n#define IListView_GetTopIndex(This, pTopIndex) \\\n    ((This)->lpVtbl->GetTopIndex(This, pTopIndex))\n#define IListView_GetCountPerPage(This, pCountPerPage) \\\n    ((This)->lpVtbl->GetCountPerPage(This, pCountPerPage))\n#define IListView_GetOrigin(This, pOrigin) \\\n    ((This)->lpVtbl->GetOrigin(This, pOrigin))\n#define IListView_GetSelectedCount(This, pSelectedCount) \\\n    ((This)->lpVtbl->GetSelectedCount(This, pSelectedCount))\n#define IListView_SortItems(This, SortingByIndex, lParam, pComparisonFunction) \\\n    ((This)->lpVtbl->SortItems(This, SortingByIndex, lParam, pComparisonFunction))\n#define IListView_GetExtendedStyle(This, pStyle) \\\n    ((This)->lpVtbl->GetExtendedStyle(This, pStyle))\n#define IListView_SetExtendedStyle(This, mask, style, pOldStyle) \\\n    ((This)->lpVtbl->SetExtendedStyle(This, mask, style, pOldStyle))\n#define IListView_GetHoverTime(This, pTime) \\\n    ((This)->lpVtbl->GetHoverTime(This, pTime))\n#define IListView_SetHoverTime(This, time, pOldSetting) \\\n    ((This)->lpVtbl->SetHoverTime(This, time, pOldSetting))\n#define IListView_GetToolTip(This, ToolTipWindowHandle) \\\n    ((This)->lpVtbl->GetToolTip(This, ToolTipWindowHandle))\n#define IListView_SetToolTip(This, ToolTipWindowHandle, OldToolTipWindowHandle) \\\n    ((This)->lpVtbl->SetToolTip(This, ToolTipWindowHandle, OldToolTipWindowHandle))\n#define IListView_GetHotItem(This, pHotItem) \\\n    ((This)->lpVtbl->GetHotItem(This, pHotItem))\n#define IListView_SetHotItem(This, newHotItem, pOldHotItem) \\\n    ((This)->lpVtbl->SetHotItem(This, newHotItem, pOldHotItem))\n#define IListView_GetHotCursor(This, pHCursor) \\\n    ((This)->lpVtbl->GetHotCursor(This, pHCursor))\n#define IListView_SetHotCursor(This, hCursor, pHOldCursor) \\\n    ((This)->lpVtbl->SetHotCursor(This, hCursor, pHOldCursor))\n#define IListView_ApproximateViewRect(This, itemCount, pWidth, pHeight) \\\n    ((This)->lpVtbl->ApproximateViewRect(This, itemCount, pWidth, pHeight))\n#define IListView_SetRangeObject(This, unknown, pObject) \\\n    ((This)->lpVtbl->SetRangeObject(This, unknown, pObject))\n#define IListView_GetWorkAreas(This, numberOfWorkAreas, pWorkAreas) \\\n    ((This)->lpVtbl->GetWorkAreas(This, numberOfWorkAreas, pWorkAreas))\n#define IListView_SetWorkAreas(This, numberOfWorkAreas, pWorkAreas) \\\n    ((This)->lpVtbl->SetWorkAreas(This, numberOfWorkAreas, pWorkAreas))\n#define IListView_GetWorkAreaCount(This, pNumberOfWorkAreas) \\\n    ((This)->lpVtbl->GetWorkAreaCount(This, pNumberOfWorkAreas))\n#define IListView_ResetEmptyText(This) \\\n    ((This)->lpVtbl->ResetEmptyText(This))\n#define IListView_EnableGroupView(This, enable) \\\n    ((This)->lpVtbl->EnableGroupView(This, enable))\n#define IListView_IsGroupViewEnabled(This, pIsEnabled) \\\n    ((This)->lpVtbl->IsGroupViewEnabled(This, pIsEnabled))\n#define IListView_SortGroups(This, pComparisonFunction, lParam) \\\n    ((This)->lpVtbl->SortGroups(This, pComparisonFunction, lParam))\n#define IListView_GetGroupInfo(This, GetGroupInfoByIndex, GroupIDOrIndex, pGroup) \\\n    ((This)->lpVtbl->GetGroupInfo(This, GetGroupInfoByIndex, GroupIDOrIndex, pGroup))\n#define IListView_SetGroupInfo(This, SetGroupInfoByIndex, GroupIDOrIndex, pGroup) \\\n    ((This)->lpVtbl->SetGroupInfo(This, SetGroupInfoByIndex, GroupIDOrIndex, pGroup))\n#define IListView_GetGroupRect(This, GetGroupRectByIndex, GroupIDOrIndex, rectangleType, pRectangle) \\\n    ((This)->lpVtbl->GetGroupRect(This, GetGroupRectByIndex, GroupIDOrIndex, rectangleType, pRectangle))\n#define IListView_GetGroupState(This, groupID, mask, pState) \\\n    ((This)->lpVtbl->GetGroupState(This, groupID, mask, pState))\n#define IListView_HasGroup(This, groupID, pHasGroup) \\\n    ((This)->lpVtbl->HasGroup(This, groupID, pHasGroup))\n#define IListView_InsertGroup(This, insertAt, pGroup, pGroupID) \\\n    ((This)->lpVtbl->InsertGroup(This, insertAt, pGroup, pGroupID))\n#define IListView_RemoveGroup(This, groupID) \\\n    ((This)->lpVtbl->RemoveGroup(This, groupID))\n#define IListView_InsertGroupSorted(This, pGroup, pGroupID) \\\n    ((This)->lpVtbl->InsertGroupSorted(This, pGroup, pGroupID))\n#define IListView_GetGroupMetrics(This, pMetrics) \\\n    ((This)->lpVtbl->GetGroupMetrics(This, pMetrics))\n#define IListView_SetGroupMetrics(This, pMetrics) \\\n    ((This)->lpVtbl->SetGroupMetrics(This, pMetrics))\n#define IListView_RemoveAllGroups(This) \\\n    ((This)->lpVtbl->RemoveAllGroups(This))\n#define IListView_GetFocusedGroup(This, pGroupID) \\\n    ((This)->lpVtbl->GetFocusedGroup(This, pGroupID))\n#define IListView_GetGroupCount(This, pCount) \\\n    ((This)->lpVtbl->GetGroupCount(This, pCount))\n#define IListView_SetOwnerDataCallback(This, pCallback) \\\n    ((This)->lpVtbl->SetOwnerDataCallback(This, pCallback))\n#define IListView_GetTileViewInfo(This, pInfo) \\\n    ((This)->lpVtbl->GetTileViewInfo(This, pInfo))\n#define IListView_SetTileViewInfo(This, pInfo) \\\n    ((This)->lpVtbl->SetTileViewInfo(This, pInfo))\n#define IListView_GetTileInfo(This, pTileInfo) \\\n    ((This)->lpVtbl->GetTileInfo(This, pTileInfo))\n#define IListView_SetTileInfo(This, pTileInfo) \\\n    ((This)->lpVtbl->SetTileInfo(This, pTileInfo))\n#define IListView_GetInsertMark(This, pInsertMarkDetails) \\\n    ((This)->lpVtbl->GetInsertMark(This, pInsertMarkDetails))\n#define IListView_SetInsertMark(This, pInsertMarkDetails) \\\n    ((This)->lpVtbl->SetInsertMark(This, pInsertMarkDetails))\n#define IListView_GetInsertMarkRect(This, pInsertMarkRectangle) \\\n    ((This)->lpVtbl->GetInsertMarkRect(This, pInsertMarkRectangle))\n#define IListView_GetInsertMarkColor(This, pColor) \\\n    ((This)->lpVtbl->GetInsertMarkColor(This, pColor))\n#define IListView_SetInsertMarkColor(This, color, pOldColor) \\\n    ((This)->lpVtbl->SetInsertMarkColor(This, color, pOldColor))\n#define IListView_HitTestInsertMark(This, pPoint, pInsertMarkDetails) \\\n    ((This)->lpVtbl->HitTestInsertMark(This, pPoint, pInsertMarkDetails))\n#define IListView_SetInfoTip(This, pInfoTip) \\\n    ((This)->lpVtbl->SetInfoTip(This, pInfoTip))\n#define IListView_GetOutlineColor(This, pColor) \\\n    ((This)->lpVtbl->GetOutlineColor(This, pColor))\n#define IListView_SetOutlineColor(This, color, pOldColor) \\\n    ((This)->lpVtbl->SetOutlineColor(This, color, pOldColor))\n#define IListView_GetFrozenItem(This, pItemIndex) \\\n    ((This)->lpVtbl->GetFrozenItem(This, pItemIndex))\n#define IListView_SetFrozenItem(This, unknown1, unknown2) \\\n    ((This)->lpVtbl->SetFrozenItem(This, unknown1, unknown2))\n#define IListView_GetFrozenSlot(This, pUnknown) \\\n    ((This)->lpVtbl->GetFrozenSlot(This, pUnknown))\n#define IListView_SetFrozenSlot(This, unknown1, pUnknown2) \\\n    ((This)->lpVtbl->SetFrozenSlot(This, unknown1, pUnknown2))\n#define IListView_GetViewMargin(This, pMargin) \\\n    ((This)->lpVtbl->GetViewMargin(This, pMargin))\n#define IListView_SetViewMargin(This, pMargin) \\\n    ((This)->lpVtbl->SetViewMargin(This, pMargin))\n#define IListView_SetKeyboardSelected(This, itemIndex) \\\n    ((This)->lpVtbl->SetKeyboardSelected(This, itemIndex))\n#define IListView_MapIndexToId(This, itemIndex, pItemID) \\\n    ((This)->lpVtbl->MapIndexToId(This, itemIndex, pItemID))\n#define IListView_MapIdToIndex(This, itemID, pItemIndex) \\\n    ((This)->lpVtbl->MapIdToIndex(This, itemID, pItemIndex))\n#define IListView_IsItemVisible(This, itemIndex, pVisible) \\\n    ((This)->lpVtbl->IsItemVisible(This, itemIndex, pVisible))\n#define IListView_EnableAlphaShadow(This, enable) \\\n    ((This)->lpVtbl->EnableAlphaShadow(This, enable))\n#define IListView_GetGroupSubsetCount(This, pNumberOfRowsDisplayed) \\\n    ((This)->lpVtbl->GetGroupSubsetCount(This, pNumberOfRowsDisplayed))\n#define IListView_SetGroupSubsetCount(This, numberOfRowsToDisplay) \\\n    ((This)->lpVtbl->SetGroupSubsetCount(This, numberOfRowsToDisplay))\n#define IListView_GetVisibleSlotCount(This, pCount) \\\n    ((This)->lpVtbl->GetVisibleSlotCount(This, pCount))\n#define IListView_GetColumnMargin(This, pMargin) \\\n    ((This)->lpVtbl->GetColumnMargin(This, pMargin))\n#define IListView_SetSubItemCallback(This, pCallback) \\\n    ((This)->lpVtbl->SetSubItemCallback(This, pCallback))\n#define IListView_GetVisibleItemRange(This, pFirstItem, pLastItem) \\\n    ((This)->lpVtbl->GetVisibleItemRange(This, pFirstItem, pLastItem))\n#define IListView_SetTypeAheadFlags(This, mask, flags) \\\n    ((This)->lpVtbl->SetTypeAheadFlags(This, mask, flags))\n\n#endif\n"
  },
  {
    "path": "phlib/include/handle.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *\n */\n\n#ifndef _PH_HANDLE_H\n#define _PH_HANDLE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct _PH_HANDLE_TABLE;\ntypedef struct _PH_HANDLE_TABLE *PPH_HANDLE_TABLE;\n\ntypedef struct _PH_HANDLE_TABLE_ENTRY\n{\n    union\n    {\n        PVOID Object;\n        ULONG_PTR Value;\n        struct\n        {\n            /** The type of the entry; 1 if the entry is free, otherwise 0 if the entry is in use. */\n            ULONG_PTR Type : 1;\n            /**\n             * Whether the entry is not locked; 1 if the entry is not locked, otherwise 0 if the\n             * entry is locked.\n             */\n            ULONG_PTR Locked : 1;\n            ULONG_PTR Value : sizeof(ULONG_PTR) * 8 - 2;\n        } TypeAndValue;\n    };\n    union\n    {\n        ACCESS_MASK GrantedAccess;\n        ULONG NextFreeValue;\n        ULONG_PTR Value2;\n    };\n} PH_HANDLE_TABLE_ENTRY, *PPH_HANDLE_TABLE_ENTRY;\n\n#define PH_HANDLE_TABLE_SAFE\n#define PH_HANDLE_TABLE_FREE_COUNT 64\n\n#define PH_HANDLE_TABLE_STRICT_FIFO 0x1\n#define PH_HANDLE_TABLE_VALID_FLAGS 0x1\n\nPHLIBAPI\nPPH_HANDLE_TABLE\nNTAPI\nPhCreateHandleTable(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDestroyHandleTable(\n    _In_ _Post_invalid_ PPH_HANDLE_TABLE HandleTable\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLockHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUnlockHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhCreateHandle(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDestroyHandle(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle,\n    _In_opt_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPHLIBAPI\nPPH_HANDLE_TABLE_ENTRY\nNTAPI\nPhLookupHandleTableEntry(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle\n    );\n\ntypedef BOOLEAN (NTAPI *PPH_ENUM_HANDLE_TABLE_CALLBACK)(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhEnumHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSweepHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef enum _PH_HANDLE_TABLE_INFORMATION_CLASS\n{\n    HandleTableBasicInformation,\n    HandleTableFlagsInformation,\n    MaxHandleTableInfoClass\n} PH_HANDLE_TABLE_INFORMATION_CLASS;\n\ntypedef struct _PH_HANDLE_TABLE_BASIC_INFORMATION\n{\n    ULONG Count;\n    ULONG Flags;\n    ULONG TableLevel;\n} PH_HANDLE_TABLE_BASIC_INFORMATION, *PPH_HANDLE_TABLE_BASIC_INFORMATION;\n\ntypedef struct _PH_HANDLE_TABLE_FLAGS_INFORMATION\n{\n    ULONG Flags;\n} PH_HANDLE_TABLE_FLAGS_INFORMATION, *PPH_HANDLE_TABLE_FLAGS_INFORMATION;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryInformationHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,\n    _Out_writes_bytes_opt_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetInformationHandleTable(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,\n    _In_reads_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/handlep.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#ifndef _PH_HANDLEP_H\n#define _PH_HANDLEP_H\n\n#define PH_HANDLE_TABLE_ENTRY_TYPE 0x1\n#define PH_HANDLE_TABLE_ENTRY_IN_USE 0x0\n#define PH_HANDLE_TABLE_ENTRY_FREE 0x1\n\n// Locked actually means Not Locked. This means that an in use, locked handle table entry can be\n// used as-is.\n#define PH_HANDLE_TABLE_ENTRY_LOCKED 0x2\n#define PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT 1\n\n// There is initially one handle table level, with 256 entries. When the handle table is expanded,\n// the table is replaced with a level 1 table, which contains 256 pointers to level 0 tables (the\n// first entry already points to the initial level 0 table). Similarly, when the handle table is\n// expanded a second time, the table is replaced with a level 2 table, which contains 256 pointers\n// to level 1 tables.\n//\n// This provides a maximum of 16,777,216 handles.\n\n#define PH_HANDLE_TABLE_LEVEL_ENTRIES 256\n#define PH_HANDLE_TABLE_LEVEL_MASK 0x3\n\n#define PH_HANDLE_TABLE_LOCKS 8\n#define PH_HANDLE_TABLE_LOCK_INDEX(HandleValue) ((HandleValue) % PH_HANDLE_TABLE_LOCKS)\n\ntypedef struct _PH_HANDLE_TABLE\n{\n    PH_QUEUED_LOCK Lock;\n    PH_WAKE_EVENT HandleWakeEvent;\n\n    ULONG Count;\n    ULONG_PTR TableValue;\n    ULONG FreeValue;\n    ULONG NextValue;\n    ULONG FreeValueAlt;\n\n    ULONG Flags;\n\n    PH_QUEUED_LOCK Locks[PH_HANDLE_TABLE_LOCKS];\n} PH_HANDLE_TABLE, *PPH_HANDLE_TABLE;\n\nFORCEINLINE VOID PhpLockHandleTableShared(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG Index\n    )\n{\n    PhAcquireQueuedLockShared(&HandleTable->Locks[Index]);\n}\n\nFORCEINLINE VOID PhpUnlockHandleTableShared(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG Index\n    )\n{\n    PhReleaseQueuedLockShared(&HandleTable->Locks[Index]);\n}\n\n// Handle values work by specifying indices into each\n// level.\n//\n// Bits 0-7: level 0\n// Bits 8-15: level 1\n// Bits 16-23: level 2\n// Bits 24-31: reserved\n\n#define PH_HANDLE_VALUE_INVALID ((ULONG)-1)\n#define PH_HANDLE_VALUE_SHIFT 2\n#define PH_HANDLE_VALUE_BIAS 4\n\n#define PH_HANDLE_VALUE_LEVEL0(HandleValue) ((HandleValue) & 0xff)\n#define PH_HANDLE_VALUE_LEVEL1_U(HandleValue) ((HandleValue) >> 8)\n#define PH_HANDLE_VALUE_LEVEL1(HandleValue) (PH_HANDLE_VALUE_LEVEL1_U(HandleValue) & 0xff)\n#define PH_HANDLE_VALUE_LEVEL2_U(HandleValue) ((HandleValue) >> 16)\n#define PH_HANDLE_VALUE_LEVEL2(HandleValue) (PH_HANDLE_VALUE_LEVEL2_U(HandleValue) & 0xff)\n#define PH_HANDLE_VALUE_IS_INVALID(HandleValue) (((HandleValue) >> 24) != 0)\n\nFORCEINLINE HANDLE PhpEncodeHandle(\n    _In_ ULONG HandleValue\n    )\n{\n    return UlongToHandle(((HandleValue << PH_HANDLE_VALUE_SHIFT) + PH_HANDLE_VALUE_BIAS));\n}\n\nFORCEINLINE ULONG PhpDecodeHandle(\n    _In_ HANDLE Handle\n    )\n{\n    return (HandleToUlong(Handle) - PH_HANDLE_VALUE_BIAS) >> PH_HANDLE_VALUE_SHIFT;\n}\n\nVOID PhpBlockOnLockedHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Out_ PULONG HandleValue\n    );\n\nVOID PhpFreeHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG HandleValue,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nBOOLEAN PhpAllocateMoreHandleTableEntries(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ BOOLEAN Initialize\n    );\n\nPPH_HANDLE_TABLE_ENTRY PhpLookupHandleTableEntry(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG HandleValue\n    );\n\nULONG PhpMoveFreeHandleTableEntries(\n    _Inout_ PPH_HANDLE_TABLE HandleTable\n    );\n\nPPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ BOOLEAN Initialize\n    );\n\nVOID PhpFreeHandleTableLevel0(\n    _In_ PPH_HANDLE_TABLE_ENTRY Table\n    );\n\nPPH_HANDLE_TABLE_ENTRY *PhpCreateHandleTableLevel1(\n    _In_ PPH_HANDLE_TABLE HandleTable\n    );\n\nVOID PhpFreeHandleTableLevel1(\n    _In_ PPH_HANDLE_TABLE_ENTRY *Table\n    );\n\nPPH_HANDLE_TABLE_ENTRY **PhpCreateHandleTableLevel2(\n    _In_ PPH_HANDLE_TABLE HandleTable\n    );\n\nVOID PhpFreeHandleTableLevel2(\n    _In_ PPH_HANDLE_TABLE_ENTRY **Table\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/hexedit.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#ifndef _PH_HEXEDIT_H\n#define _PH_HEXEDIT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_HEXEDIT_CLASSNAME L\"PhHexEdit\"\n\n#define EDIT_NONE 0\n#define EDIT_ASCII 1\n#define EDIT_HIGH 2\n#define EDIT_LOW 3\n\nPHLIBAPI\nRTL_ATOM\nNTAPI\nPhHexEditInitialization(\n    VOID\n    );\n\n#define HEM_SETBUFFER (WM_USER + 1)\n#define HEM_SETDATA (WM_USER + 2)\n#define HEM_GETBUFFER (WM_USER + 3)\n#define HEM_SETSEL (WM_USER + 4)\n#define HEM_SETEDITMODE (WM_USER + 5)\n#define HEM_SETBYTESPERROW (WM_USER + 6)\n#define HEM_SETEXTENDEDUNICODE (WM_USER + 7)\n\n#define HexEdit_SetBuffer(hWnd, Buffer, Length) \\\n    SendMessage((hWnd), HEM_SETBUFFER, (WPARAM)(Length), (LPARAM)(Buffer))\n\n#define HexEdit_SetData(hWnd, Buffer, Length) \\\n    SendMessage((hWnd), HEM_SETDATA, (WPARAM)(Length), (LPARAM)(Buffer))\n\n#define HexEdit_GetBuffer(hWnd, Length) \\\n    ((PUCHAR)SendMessage((hWnd), HEM_GETBUFFER, (WPARAM)(Length), 0))\n\n#define HexEdit_SetSel(hWnd, Start, End) \\\n    SendMessage((hWnd), HEM_SETSEL, (WPARAM)(Start), (LPARAM)(End))\n\n#define HexEdit_SetEditMode(hWnd, Mode) \\\n    SendMessage((hWnd), HEM_SETEDITMODE, (WPARAM)(Mode), 0)\n\n#define HexEdit_SetBytesPerRow(hWnd, BytesPerRow) \\\n    SendMessage((hWnd), HEM_SETBYTESPERROW, (WPARAM)(BytesPerRow), 0)\n\n#define HexEdit_SetExtendedUnicode(hWnd, ExtendedUnicode) \\\n    SendMessage((hWnd), HEM_SETEXTENDEDUNICODE, (WPARAM)(ExtendedUnicode), 0)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/hexeditp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#ifndef _PH_HEXEDITP_H\n#define _PH_HEXEDITP_H\n\ntypedef struct _PHP_HEXEDIT_CONTEXT\n{\n    PUCHAR Data;\n    LONG Length;\n    BOOLEAN UserBuffer;\n    LONG TopIndex; // index of first visible byte on screen\n\n    LONG CurrentAddress;\n    LONG CurrentMode;\n    LONG SelStart;\n    LONG SelEnd;\n\n    LONG BytesPerRow;\n    LONG LinesPerPage;\n\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN ShowAddress : 1;\n            BOOLEAN ShowAscii : 1;\n            BOOLEAN ShowHex : 1;\n            BOOLEAN AddressIsWide : 1;\n            BOOLEAN AllowLengthChange : 1;\n            BOOLEAN NoAddressChange : 1;\n            BOOLEAN HalfPage : 1;\n            BOOLEAN ExtendedUnicode : 1;\n        };\n    };\n\n    HFONT Font;\n    LONG LineHeight;\n    LONG NullWidth;\n    PWCHAR CharBuffer;\n    ULONG CharBufferLength;\n    LONG WindowDpi;\n    BOOLEAN Update;\n\n    LONG HexOffset;\n    LONG AsciiOffset;\n    LONG AddressOffset;\n\n    BOOLEAN HasCapture;\n    POINT EditPosition;\n} PHP_HEXEDIT_CONTEXT, *PPHP_HEXEDIT_CONTEXT;\n\n#define TO_HEX(Buffer, Byte) \\\n{ \\\n    *(Buffer)++ = PhIntegerToChar[(Byte) >> 4]; \\\n    *(Buffer)++ = PhIntegerToChar[(Byte) & 0xf]; \\\n}\n\n#define REDRAW_WINDOW(hwnd) \\\n    RedrawWindow((hwnd), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE)\n\nPPHP_HEXEDIT_CONTEXT PhpCreateHexEditContext(\n    VOID\n    );\n\nVOID PhpFreeHexEditContext(\n    _In_ _Post_invalid_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nLRESULT CALLBACK PhpHexEditWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhpHexEditUpdateMetrics(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ BOOLEAN UpdateLineHeight,\n    _In_opt_ HDC hdc\n    );\n\nVOID PhpHexEditOnPaint(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PAINTSTRUCT *PaintStruct,\n    _In_ HDC hdc\n    );\n\nVOID PhpHexEditUpdateScrollbars(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nFORCEINLINE BOOLEAN PhpHexEditHasSelected(\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    return Context->SelStart != -1;\n}\n\nVOID PhpHexEditCreateAddressCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditCreateEditCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditRepositionCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG Position\n    );\n\nVOID PhpHexEditCalculatePosition(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _Out_ POINT *Point\n    );\n\nVOID PhpHexEditMove(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y\n    );\n\nVOID PhpHexEditSetSel(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG E\n    );\n\nVOID PhpHexEditScrollTo(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG Position\n    );\n\nVOID PhpHexEditClearEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditCopyEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditCutEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditPasteEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditSelectAll(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditUndoEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditNormalizeSel(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditSelDelete(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG E\n    );\n\nVOID PhpHexEditSelInsert(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG L\n    );\n\nVOID PhpHexEditSetBuffer(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PUCHAR Data,\n    _In_ ULONG Length\n    );\n\nVOID PhpHexEditSetData(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PUCHAR Data,\n    _In_ ULONG Length\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/hndlinfo.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_HNDLINFO_H\n#define _PH_HNDLINFO_H\n\nEXTERN_C_START\n\n#define MAX_OBJECT_TYPE_NUMBER 257\n\nextern BOOLEAN PhEnableProcessHandlePnPDeviceNameSupport;\n\ntypedef PPH_STRING (NTAPI *PPH_GET_CLIENT_ID_NAME)(\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nPPH_GET_CLIENT_ID_NAME\nNTAPI\nPhSetHandleClientIdFunction(\n    _In_ PPH_GET_CLIENT_ID_NAME GetClientIdName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetObjectBasicInformation(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _Out_ POBJECT_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetEtwObjectName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING* ObjectName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetObjectName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ BOOLEAN WithTimeout,\n    _Out_ PPH_STRING* ObjectName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetObjectTypeName(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Out_ PPH_STRING* TypeName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryObjectName(\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING* ObjectName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryObjectBasicInformation(\n    _In_ HANDLE Handle,\n    _Out_ POBJECT_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCompareObjects(\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetEtwPublisherName(\n    _In_ PGUID Guid\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatNativeKeyName(\n    _In_ PPH_STRING Name\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSectionFileName(\n    _In_ HANDLE SectionHandle,\n    _Out_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\n_Callback_ PPH_STRING\nNTAPI\nPhStdGetClientIdName(\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhStdGetClientIdNameEx(\n    _In_ PCLIENT_ID ClientId,\n    _In_opt_ PPH_STRING ProcessName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetHandleInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,\n    _Out_opt_ PPH_STRING *TypeName,\n    _Out_opt_ PPH_STRING *ObjectName,\n    _Out_opt_ PPH_STRING *BestObjectName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetHandleInformationEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Reserved_ ULONG Flags,\n    _Out_opt_ PNTSTATUS SubStatus,\n    _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,\n    _Out_opt_ PPH_STRING *TypeName,\n    _Out_opt_ PPH_STRING *ObjectName,\n    _Out_opt_ PPH_STRING *BestObjectName,\n    _Reserved_ PVOID *ExtraInformation\n    );\n\n#define PH_FIRST_OBJECT_TYPE(ObjectTypes) \\\n    PTR_ADD_OFFSET((ObjectTypes), ALIGN_UP(sizeof(OBJECT_TYPES_INFORMATION), ULONG_PTR))\n\n#define PH_NEXT_OBJECT_TYPE(ObjectType) \\\n    PTR_ADD_OFFSET((ObjectType), sizeof(OBJECT_TYPE_INFORMATION) + \\\n    ALIGN_UP((ObjectType)->TypeName.MaximumLength, ULONG_PTR))\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumObjectTypes(\n    _Out_ POBJECT_TYPES_INFORMATION *ObjectTypes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetObjectTypeMask(\n    _In_ PPH_STRINGREF TypeName,\n    _Out_ PGENERIC_MAPPING GenericMapping\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetObjectTypeNumber(\n    _In_ PPH_STRINGREF TypeName\n    );\n\nFORCEINLINE\nULONG\nNTAPI\nPhGetObjectTypeNumberZ(\n    _In_ PCWSTR TypeName\n    )\n{\n    PH_STRINGREF typeName;\n\n    PhInitializeStringRef(&typeName, TypeName);\n\n    return PhGetObjectTypeNumber(&typeName);\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetObjectTypeIndexName(\n    _In_ ULONG TypeIndex\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallWithTimeout(\n    _In_ PUSER_THREAD_START_ROUTINE Routine,\n    _In_opt_ PVOID Context,\n    _In_opt_ PLARGE_INTEGER AcquireTimeout,\n    _In_ PLARGE_INTEGER CallTimeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallNtQueryObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallNtQuerySecurityObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ULONG Length,\n    _Out_ PULONG LengthNeeded\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallNtSetSecurityObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallNtQueryFileInformationWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_writes_bytes_opt_(FileInformationLength) PVOID FileInformation,\n    _In_ ULONG FileInformationLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallKphQueryFileInformationWithTimeout(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_writes_bytes_opt_(FileInformationLength) PVOID FileInformation,\n    _In_ ULONG FileInformationLength\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetPnPDeviceName(\n    _In_ PPH_STRING ObjectName\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/hvsocketcontrol.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2023\n *\n */\n\n#ifndef _PH_HVSOCKETCONTROL_H\n#define _PH_HVSOCKETCONTROL_H\n\n#include <hvsocket.h>\n\nEXTERN_C_START\n\n#ifdef _WIN64\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHvSocketOpenSystemControl(\n    _Out_ PHANDLE SystemHandle,\n    _In_opt_ const GUID* VmId\n    );\n\n// rev\ntypedef struct _HVSOCKET_LISTENER\n{\n    union // HV_GUID_VSOCK_TEMPLATE\n    {\n        ULONG Port;\n        GUID ServiceId;\n    };\n    GUID VmId;\n    ULONG ProcessId;\n    LARGE_INTEGER TimeStamp;\n    BYTE Unknown; // Type?\n} HVSOCKET_LISTENER, *PHVSOCKET_LISTENER;\nC_ASSERT(FIELD_OFFSET(HVSOCKET_LISTENER, ProcessId) == 32);\nC_ASSERT(sizeof(HVSOCKET_LISTENER) == 56);\n\n// rev\ntypedef struct _HVSOCKET_LISTENERS\n{\n    ULONG Count;\n    HVSOCKET_LISTENER Listener[ANYSIZE_ARRAY];\n} HVSOCKET_LISTENERS, *PHVSOCKET_LISTENERS;\nC_ASSERT(FIELD_OFFSET(HVSOCKET_LISTENERS, Listener) == 8);\nC_ASSERT(sizeof(HVSOCKET_LISTENERS) == 64);\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHvSocketGetListeners(\n    _In_ HANDLE SystemHandle,\n    _In_ const GUID* VmId,\n    _In_opt_ PHVSOCKET_LISTENERS Listeners,\n    _In_ ULONG ListenersLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// rev\ntypedef struct _HVSOCKET_CONNECTION\n{\n    union // HV_GUID_VSOCK_TEMPLATE\n    {\n        ULONG Port;\n        GUID ServiceId;\n    };\n    GUID VmId;\n    ULONG ProcessId;\n    LARGE_INTEGER TimeStamp;\n    ULONG Type; // 1 or 2?\n} HVSOCKET_CONNECTION, *PHVSOCKET_CONNECTION;\nC_ASSERT(FIELD_OFFSET(HVSOCKET_CONNECTION, ProcessId) == 32);\nC_ASSERT(sizeof(HVSOCKET_CONNECTION) == 56);\n\n// rev\ntypedef struct _HVSOCKET_CONNECTIONS\n{\n    ULONG Count;\n    HVSOCKET_CONNECTION Connection[ANYSIZE_ARRAY];\n} HVSOCKET_CONNECTIONS, *PHVSOCKET_CONNECTIONS;\nC_ASSERT(FIELD_OFFSET(HVSOCKET_CONNECTIONS, Connection) == 8);\nC_ASSERT(sizeof(HVSOCKET_CONNECTIONS) == 64);\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHvSocketGetConnections(\n    _In_ HANDLE SystemHandle,\n    _In_ const GUID* VmId,\n    _In_opt_ PHVSOCKET_CONNECTIONS Connections,\n    _In_ ULONG ConnectionsLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// rev\ntypedef struct _HVSOCKET_SERVICE_INFO\n{\n    GUID Unknown1;\n    ULONG Unknown2;\n    ULONG Unknown3;\n} HVSOCKET_SERVICE_INFO, *PHVSOCKET_SERVICE_INFO;\nC_ASSERT(sizeof(HVSOCKET_SERVICE_INFO) == 24);\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHvSocketGetServiceInfo(\n    _In_ HANDLE SystemHandle,\n    _In_ const GUID* ServiceId,\n    _Out_ PHVSOCKET_SERVICE_INFO ServiceInfo\n    );\n\n#endif // _WIN64\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhHvSocketIsVSockTemplate(\n    _In_ PGUID ServiceId\n    );\n\nPHLIBAPI\n_Maybenull_\nPPH_STRING\nNTAPI\nPhHvSocketGetVmName(\n    _In_ PGUID VmId\n    );\n\nPHLIBAPI\n_Maybenull_\nPPH_STRING\nNTAPI\nPhHvSocketGetServiceName(\n    _In_ PGUID ServiceId\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhHvSocketAddressString(\n    _In_ PGUID Address\n    );\n\nEXTERN_C_END\n\n#endif // _PH_HVSOCKETCONTROL_H\n\n"
  },
  {
    "path": "phlib/include/json.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017\n *\n */\n\n#ifndef _PH_PHJSON_H\n#define _PH_PHJSON_H\n\nEXTERN_C_START\n\ntypedef struct _JSON_ARRAY_LIST_OBJECT\n{\n    PCSTR Key;\n    PVOID Entry;\n} JSON_ARRAY_LIST_OBJECT, *PJSON_ARRAY_LIST_OBJECT;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateJsonParser(\n    _Out_ PVOID* JsonObject,\n    _In_ PCSTR JsonString\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateJsonParserEx(\n    _Out_ PVOID* JsonObject,\n    _In_ PVOID JsonString,\n    _In_ BOOLEAN Unicode\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeJsonObject(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetJsonValueAsString(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetJsonObjectString(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nLONGLONG\nNTAPI\nPhGetJsonValueAsInt64(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    );\n\nPHLIBAPI\nULONGLONG\nNTAPI\nPhGetJsonValueAsUInt64(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    );\n\nFORCEINLINE\nULONG\nPhGetJsonValueAsUlong(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    )\n{\n    return (ULONG)PhGetJsonValueAsUInt64(Object, Key);\n}\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetJsonUInt32Object(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nULONGLONG\nNTAPI\nPhGetJsonUInt64Object(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nLONGLONG\nNTAPI\nPhGetJsonInt64Object(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateJsonObject(\n    VOID\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetJsonObject(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    );\n\ntypedef enum _PH_JSON_OBJECT_TYPE\n{\n    PH_JSON_OBJECT_TYPE_NULL,\n    PH_JSON_OBJECT_TYPE_BOOLEAN,\n    PH_JSON_OBJECT_TYPE_DOUBLE,\n    PH_JSON_OBJECT_TYPE_INT,\n    PH_JSON_OBJECT_TYPE_OBJECT,\n    PH_JSON_OBJECT_TYPE_ARRAY,\n    PH_JSON_OBJECT_TYPE_STRING,\n    PH_JSON_OBJECT_TYPE_UNKNOWN\n} PH_JSON_OBJECT_TYPE;\n\nPHLIBAPI\nPH_JSON_OBJECT_TYPE\nNTAPI\nPhGetJsonObjectType(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhGetJsonObjectLength(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetJsonObjectBool(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonObjectValue(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PVOID Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonObject(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PCSTR Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonObject2(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PCSTR Value,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonObjectUtf8(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PPH_BYTES String\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonObjectInt64(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ LONGLONG Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonObjectUInt64(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ ULONGLONG Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonObjectDouble(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ DOUBLE Value\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateJsonArray(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonArrayObject(\n    _In_ PVOID Object,\n    _In_ PVOID Value\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetJsonArrayString(\n    _In_ PVOID Object,\n    _In_ BOOLEAN Unicode\n    );\n\nPHLIBAPI\nINT64\nNTAPI\nPhGetJsonArrayLong64(\n    _In_ PVOID Object,\n    _In_ ULONG Index\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetJsonArrayLength(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetJsonArrayIndexObject(\n    _In_ PVOID Object,\n    _In_ ULONG Index\n    );\n\ntypedef BOOLEAN (NTAPI* PPH_ENUM_JSON_OBJECT_CALLBACK)(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PVOID Value,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhEnumJsonArrayObject(\n    _In_ PVOID Object,\n    _In_ PPH_ENUM_JSON_OBJECT_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetJsonObjectAsArrayList(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadJsonObjectFromFile(\n    _Out_ PVOID* JsonObject,\n    _In_ PCPH_STRINGREF FileName\n    );\n\n#define PH_JSON_TO_STRING_PLAIN 0x0001\n#define PH_JSON_TO_STRING_SPACED 0x0002\n#define PH_JSON_TO_STRING_PRETTY 0x0004\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhJsonObjectToString(\n    _In_ PPH_BYTES_BUILDER StringBuilder,\n    _In_ PVOID Object,\n    _In_ ULONG Level,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhJsonObjectToJsonString(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSaveJsonObjectToFile(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PVOID Object,\n    _In_opt_ ULONG Flags\n    );\n\n// XML\n\nPHLIBAPI\nPVOID\nNTAPI\nPhLoadXmlObjectFromString(\n    _In_ PCSTR String\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhLoadXmlObjectFromString2(\n    _In_ PCSTR String\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadXmlObjectFromFile(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_opt_ PVOID* XmlRootObject\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSaveXmlObjectToFile(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PVOID XmlRootObject,\n    _In_opt_ PVOID XmlSaveCallback\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeXmlObject(\n    _In_ PVOID XmlRootObject\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetXmlObject(\n    _In_ PVOID XmlNodeObject,\n    _In_ PCSTR Path\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhFindXmlObject(\n    _In_ PVOID XmlNodeObject,\n    _In_opt_ PVOID XmlTopObject,\n    _In_opt_ PCSTR Element,\n    _In_opt_ PCSTR Attribute,\n    _In_opt_ PCSTR Value\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetXmlNodeOpaqueText(\n    _In_ PVOID XmlNodeObject\n    );\n\nPHLIBAPI\nPCSTR\nNTAPI\nPhGetXmlNodeElementText(\n    _In_ PVOID XmlNodeObject\n    );\n\nPHLIBAPI\nPCSTR\nNTAPI\nPhGetXmlNodeCDATAText(\n    _In_ PVOID XmlNodeObject\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetXmlNodeAttributeText(\n    _In_ PVOID XmlNodeObject,\n    _In_ PCSTR AttributeName\n    );\n\nPHLIBAPI\nPCSTR\nNTAPI\nPhGetXmlNodeAttributeByIndex(\n    _In_ PVOID XmlNodeObject,\n    _In_ SIZE_T Index,\n    _Out_ PCSTR* AttributeName\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetXmlNodeAttributeText(\n    _In_ PVOID XmlNodeObject,\n    _In_ PCSTR Name,\n    _In_ PCSTR Value\n    );\n\nPHLIBAPI\nSIZE_T\nNTAPI\nPhGetXmlNodeAttributeCount(\n    _In_ PVOID XmlNodeObject\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetXmlNodeFirstChild(\n    _In_ PVOID XmlNodeObject\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetXmlNodeNextChild(\n    _In_ PVOID XmlNodeObject\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateXmlNode(\n    _In_opt_ PVOID ParentNode,\n    _In_ PCSTR Name\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateXmlOpaqueNode(\n    _In_opt_ PVOID ParentNode,\n    _In_ PCSTR Value\n    );\n\ntypedef PVOID (NTAPI* PH_XML_LOAD_OBJECT_FROM_STRING)(\n    _In_ PCSTR String\n    );\n\ntypedef NTSTATUS (NTAPI* PH_XML_LOAD_OBJECT_FROM_FILE)(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_opt_ PVOID* XmlRootNode\n    );\n\ntypedef NTSTATUS (NTAPI* PH_XML_SAVE_OBJECT_TO_FILE)(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PVOID XmlRootObject,\n    _In_opt_ PVOID XmlSaveCallback\n    );\n\ntypedef VOID (NTAPI* PH_XML_FREE_OBJECT)(\n    _In_ PVOID XmlRootObject\n    );\n\ntypedef PVOID (NTAPI* PH_XML_GET_OBJECT)(\n    _In_ PVOID XmlNodeObject,\n    _In_ PCSTR Path\n    );\n\ntypedef PVOID (NTAPI* PH_XML_CREATE_NODE)(\n    _In_opt_ PVOID ParentNode,\n    _In_ PCSTR Name\n    );\n\ntypedef PVOID (NTAPI* PH_XML_CREATE_OPAQUE_NODE)(\n    _In_opt_ PVOID ParentNode,\n    _In_ PCSTR Value\n    );\n\ntypedef PVOID (NTAPI* PH_XML_FIND_OBJECT)(\n    _In_ PVOID XmlNodeObject,\n    _In_ PVOID XmlTopObject,\n    _In_ PCSTR Element,\n    _In_ PCSTR Attribute,\n    _In_ PCSTR Value\n    );\n\ntypedef PVOID (NTAPI* PH_XML_GET_NODE_FIRST_CHILD)(\n    _In_ PVOID XmlNodeObject\n    );\n\ntypedef PVOID (NTAPI* PH_XML_GET_NODE_NEXT_CHILD)(\n    _In_ PVOID XmlNodeObject\n    );\n\ntypedef PPH_STRING (NTAPI* PH_XML_GET_XML_NODE_OPAQUE_TEXT)(\n    _In_ PVOID XmlNodeObject\n    );\n\ntypedef PCSTR (NTAPI* PH_XML_GET_XML_NODE_ELEMENT_TEXT)(\n    _In_ PVOID XmlNodeObject\n    );\n\ntypedef PPH_STRING (NTAPI* PH_XML_GET_XML_NODE_ATTRIBUTE_TEXT)(\n    _In_ PVOID XmlNodeObject,\n    _In_ PCSTR AttributeName\n    );\n\ntypedef PCSTR (NTAPI* PH_XML_GET_XML_NODE_ATTRIBUTE_BY_INDEX)(\n    _In_ PVOID XmlNodeObject,\n    _In_ SIZE_T Index,\n    _Out_ PCSTR* AttributeName\n    );\n\ntypedef VOID (NTAPI* PH_XML_SET_XML_NODE_ATTRIBUTE_TEXT)(\n    _In_ PVOID XmlNodeObject,\n    _In_ PCSTR Name,\n    _In_ PCSTR Value\n    );\n\ntypedef SIZE_T (NTAPI* PH_XML_GET_XML_NODE_ATTRIBUTE_COUNT)(\n    _In_ PVOID XmlNodeObject\n    );\n\ntypedef struct _PH_XML_INTERFACE\n{\n    ULONG Version;\n    PH_XML_LOAD_OBJECT_FROM_STRING LoadXmlObjectFromString;\n    PH_XML_LOAD_OBJECT_FROM_FILE LoadXmlObjectFromFile;\n    PH_XML_SAVE_OBJECT_TO_FILE SaveXmlObjectToFile;\n    PH_XML_FREE_OBJECT FreeXmlObject;\n    PH_XML_GET_OBJECT GetXmlObject;\n    PH_XML_CREATE_NODE CreateXmlNode;\n    PH_XML_CREATE_OPAQUE_NODE CreateXmlOpaqueNode;\n    PH_XML_FIND_OBJECT FindXmlObject;\n    PH_XML_GET_NODE_FIRST_CHILD GetXmlNodeFirstChild;\n    PH_XML_GET_NODE_NEXT_CHILD GetXmlNodeNextChild;\n    PH_XML_GET_XML_NODE_OPAQUE_TEXT GetXmlNodeOpaqueText;\n    PH_XML_GET_XML_NODE_ELEMENT_TEXT GetXmlNodeElementText;\n    PH_XML_GET_XML_NODE_ATTRIBUTE_TEXT GetXmlNodeAttributeText;\n    PH_XML_GET_XML_NODE_ATTRIBUTE_BY_INDEX GetXmlNodeAttributeByIndex;\n    PH_XML_SET_XML_NODE_ATTRIBUTE_TEXT SetXmlNodeAttributeText;\n    PH_XML_GET_XML_NODE_ATTRIBUTE_COUNT GetXmlNodeAttributeCount;\n} PH_XML_INTERFACE, *PPH_XML_INTERFACE;\n\n#define PH_XML_INTERFACE_VERSION 1\n\nPPH_XML_INTERFACE PhGetXmlInterface(\n    _In_ ULONG Version\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/kphcomms.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022\n *\n */\n\n#ifndef _PH_KPHCOMMS_H\n#define _PH_KPHCOMMS_H\n\n#include <kphmsg.h>\n\n/**\n * \\brief Callback for handling messages from the kernel.\n *\n * \\details Synchronous messages expecting a reply must always be handled. The\n * callback may return FALSE even when the kernel is expecting a reply. In this\n * case, the internals of the system will handle the reply on behalf of the\n * callback.\n *\n * \\param[in] ReplyToken The token used to reply to kernel messages. If zero\n * the kernel is not expecting a reply. Use KphCommsReplyMessage to reply.\n * \\param[in] Message The message from the kernel.\n *\n * \\return TRUE if the message was handled by this callback, FALSE otherwise.\n */\ntypedef _Function_class_(KPH_COMMS_CALLBACK)\nBOOLEAN NTAPI KPH_COMMS_CALLBACK(\n    _In_ ULONG_PTR ReplyToken,\n    _In_ PCKPH_MESSAGE Message\n    );\ntypedef KPH_COMMS_CALLBACK* PKPH_COMMS_CALLBACK;\n\n_Must_inspect_result_\nNTSTATUS\nNTAPI\nKphCommsStart(\n    _In_ PCPH_STRINGREF PortName,\n    _In_opt_ PKPH_COMMS_CALLBACK Callback,\n    _In_ ULONG RingBufferLength\n    );\n\nVOID\nNTAPI\nKphCommsStop(\n    VOID\n    );\n\nBOOLEAN\nNTAPI\nKphCommsIsConnected(\n    VOID\n    );\n\nNTSTATUS\nNTAPI\nKphCommsReplyMessage(\n    _In_ ULONG_PTR ReplyToken,\n    _In_ PKPH_MESSAGE Message\n    );\n\n_Must_inspect_result_\nNTSTATUS\nNTAPI\nKphCommsSendMessage(\n    _Inout_ PKPH_MESSAGE Message\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/kphuser.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *     jxy-s   2021-2022\n *\n */\n\n#ifndef _PH_KPHUSER_H\n#define _PH_KPHUSER_H\n\n#include <kphapi.h>\n#include <kphcomms.h>\n\nEXTERN_C_START\n\n#define KPH_SERVICE_NAME TEXT(\"KSystemInformer\")\n#define KPH_OBJECT_NAME  TEXT(\"\\\\Driver\\\\KSystemInformer\")\n#define KPH_PORT_NAME    TEXT(\"\\\\KSystemInformer\")\n\ntypedef struct _KPH_CONFIG_PARAMETERS\n{\n    _In_ PPH_STRINGREF FileName;\n    _In_ PPH_STRINGREF ServiceName;\n    _In_ PPH_STRINGREF ObjectName;\n    _In_opt_ PCPH_STRINGREF PortName;\n    _In_opt_ PCPH_STRINGREF Altitude;\n    _In_opt_ PCPH_STRINGREF SystemProcessName;\n    _In_ ULONG FsSupportedFeatures;\n    _In_ KPH_PARAMETER_FLAGS Flags;\n    _In_ BOOLEAN EnableNativeLoad;\n    _In_ BOOLEAN EnableFilterLoad;\n    _In_ ULONG RingBufferLength;\n    _In_opt_ PKPH_COMMS_CALLBACK Callback;\n} KPH_CONFIG_PARAMETERS, *PKPH_CONFIG_PARAMETERS;\n\nPHLIBAPI\nVOID\nNTAPI\nKphInitialize(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphConnect(\n    _In_ PKPH_CONFIG_PARAMETERS Options\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetParameters(\n    _In_ PKPH_CONFIG_PARAMETERS Options\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nKphSetServiceSecurity(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKsiLoadUnloadService(\n    _In_ PKPH_CONFIG_PARAMETERS Config,\n    _In_ BOOLEAN LoadDriver\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphServiceStop(\n    _In_ PKPH_CONFIG_PARAMETERS Config\n    );\n\n//PHLIBAPI\n//NTSTATUS\n//NTAPI\n//KphInstall(\n//    _In_ PPH_STRINGREF ServiceName,\n//    _In_ PPH_STRINGREF ObjectName,\n//    _In_ PPH_STRINGREF PortName,\n//    _In_ PPH_STRINGREF FileName,\n//    _In_ PPH_STRINGREF Altitude,\n//    _In_ BOOLEAN DisableImageLoadProtection\n//    );\n//\n//PHLIBAPI\n//NTSTATUS\n//NTAPI\n//KphUninstall(\n//    _In_ PPH_STRINGREF ServiceName\n//    );\n\nPHLIBAPI\nPKPH_MESSAGE\nNTAPI\nKphCreateMessage(\n    _In_ SIZE_T Size\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphGetInformerSettings(\n    _Out_ PKPH_INFORMER_SETTINGS Settings\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetInformerSettings(\n    _In_ PKPH_INFORMER_SETTINGS Settings\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenProcessJob(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE JobHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphReadVirtualMemory(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle\n    );\n\n#define KPH_STACK_BACK_TRACE_USER_MODE   0x00000001ul\n#define KPH_STACK_BACK_TRACE_SKIP_KPH    0x00000002ul\n#define KPH_STACK_BACK_TRACE_NO_SENTINEL 0x00000004ul\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphCaptureStackBackTraceThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID* BackTrace,\n    _Out_ PULONG CapturedFrames,\n    _Out_opt_ PULONG BackTraceHash,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphEnumerateProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _In_opt_ ULONG BufferLength,\n    _Inout_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKsiEnumerateProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryObjectThreadName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING* ThreadName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryObjectSectionMappingsInfo(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _Out_ PKPH_SECTION_MAPPINGS_INFORMATION* Info\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenDriver(\n    _Out_ PHANDLE DriverHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryInformationDriver(\n    _In_ HANDLE DriverHandle,\n    _In_ KPH_DRIVER_INFORMATION_CLASS DriverInformationClass,\n    _Out_writes_bytes_opt_(DriverInformationLength) PVOID DriverInformation,\n    _In_ ULONG DriverInformationLength,\n    _Inout_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _Out_writes_bytes_opt_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Inout_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nKPH_PROCESS_STATE\nNTAPI\nKphGetProcessState(\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nKPH_PROCESS_STATE\nNTAPI\nKphGetCurrentProcessState(\n    VOID\n    );\n\ntypedef enum _KPH_LEVEL\n{\n    KphLevelNone,\n    KphLevelMin,\n    KphLevelLow,\n    KphLevelMed,\n    KphLevelHigh,\n    KphLevelMax\n} KPH_LEVEL;\n\nPHLIBAPI\nKPH_LEVEL\nNTAPI\nKphProcessLevel(\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nKPH_LEVEL\nNTAPI\nKphLevelEx(\n    _In_ BOOLEAN Cached\n    );\n\nPHLIBAPI\nKPH_LEVEL\nNTAPI\nKsiLevel(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSystemControl(\n    _In_ KPH_SYSTEM_CONTROL_CLASS SystemControlClass,\n    _In_reads_bytes_(SystemControlInfoLength) PVOID SystemControlInfo,\n    _In_ ULONG SystemControlInfoLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphAlpcQueryInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE PortHandle,\n    _In_ KPH_ALPC_INFORMATION_CLASS AlpcInformationClass,\n    _Out_writes_bytes_opt_(AlpcInformationLength) PVOID AlpcInformation,\n    _In_ ULONG AlpcInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphAlpcQueryCommunicationsNamesInfo(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE PortHandle,\n    _Out_ PKPH_ALPC_COMMUNICATION_NAMES_INFORMATION* Names\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryInformationFile(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_writes_bytes_(FileInformationLength) PVOID FileInformation,\n    _In_ ULONG FileInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryVolumeInformationFile(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FS_INFORMATION_CLASS FsInformationClass,\n    _Out_writes_bytes_(FsInformationLength) PVOID FsInformation,\n    _In_ ULONG FsInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphDuplicateObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE SourceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TargetHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryPerformanceCounter(\n    _Out_ PLARGE_INTEGER PerformanceCounter,\n    _Out_opt_ PLARGE_INTEGER PerformanceFrequency\n    );\n\n#define IO_OPEN_TARGET_DIRECTORY        0x0004\n#define IO_STOP_ON_SYMLINK              0x0008\n#define IO_IGNORE_SHARE_ACCESS_CHECK    0x0800  // Ignores share access checks on opens.\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphCreateFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,\n    _In_ ULONG EaLength,\n    _In_ ULONG Options\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _Out_writes_bytes_opt_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQuerySection(\n    _In_ HANDLE SectionHandle,\n    _In_ KPH_SECTION_INFORMATION_CLASS SectionInformationClass,\n    _Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation,\n    _In_ ULONG SectionInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQuerySectionMappingsInfo(\n    _In_ HANDLE SectionHandle,\n    _Out_ PKPH_SECTION_MAPPINGS_INFORMATION* Info\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphCompareObjects(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphGetInformerClientSettings(\n    _Out_ PKPH_INFORMER_CLIENT_SETTINGS Settings\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetInformerClientSettings(\n    _Out_ PKPH_INFORMER_CLIENT_SETTINGS Settings\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphAcquireDriverUnloadProtection(\n    _Out_opt_ PLONG PreviousCount,\n    _Out_opt_ PLONG ClientPreviousCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphReleaseDriverUnloadProtection(\n    _Out_opt_ PLONG PreviousCount,\n    _Out_opt_ PLONG ClientPreviousCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphGetConnectedClientCount(\n    _Out_ PULONG Count\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphActivateDynData(\n    _In_ PBYTE DynData,\n    _In_ ULONG DynDataLength,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphIsDynDataActive(\n    _Out_ PBOOLEAN IsActive\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphRequestSessionAccessToken(\n    _Out_ PKPH_SESSION_ACCESS_TOKEN AccessToken,\n    _In_ PLARGE_INTEGER Expiry,\n    _In_ ULONG Privileges,\n    _In_ LONG Uses\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphAssignProcessSessionToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphAssignThreadSessionToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphGetInformerProcessSettings(\n    _In_ HANDLE ProcessHandle,\n    _In_ PKPH_INFORMER_SETTINGS Settings\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetInformerProcessSettings(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PKPH_INFORMER_SETTINGS Settings\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphStripProtectedProcessMasks(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK ProcessAllowedMask,\n    _In_ ACCESS_MASK ThreadAllowedMask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ KPH_MEMORY_INFORMATION_CLASS MemoryInformationClass,\n    _Out_writes_bytes_opt_(MemoryInformationLength) PVOID MemoryInformation,\n    _In_ ULONG MemoryInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKsiQueryHashInformationFile(\n    _In_ HANDLE FileHandle,\n    _Inout_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG HashInformationLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenDevice(\n    _Out_ PHANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenDeviceDriver(\n    _In_ HANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE DriverHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenDeviceBaseDevice(\n    _In_ HANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE BaseDeviceHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphGetInformerStats(\n    _In_opt_ HANDLE ProcessHandle,\n    _Out_ PKPH_INFORMER_STATS Stats\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphGetInformerClientStats(\n    _Out_ PKPH_INFORMER_CLIENT_STATS Stats\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/lsamsup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2023\n *\n */\n#ifndef _PH_LSAMSUP_H\n#define _PH_LSAMSUP_H\n\nEXTERN_C_START\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenSamHandle(\n    _Out_ PSAM_HANDLE SamHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PUNICODE_STRING SystemName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSamServerHandle(\n    _Out_ PSAM_HANDLE SamHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenSamDomainHandle(\n    _Out_ PSAM_HANDLE DomainHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PSID DomainSid\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSamDomainHandle(\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE DomainHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupSamName(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PPH_STRINGREF Name,\n    _Out_ PULONG RelativeId,\n    _Out_ PSID_NAME_USE Use\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupSamNames(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ULONG Count,\n    _In_ PPH_STRINGREF Names,\n    _Out_ PULONG* RelativeIds,\n    _Out_ PSID_NAME_USE* Uses\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSamAliasDescription(\n    _In_ PSID Sid,\n    _Out_ PPH_STRING *Description\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSamGroupDescription(\n    _In_ PSID Sid,\n    _Out_ PPH_STRING *Description\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSamUserDescription(\n    _In_ PSID Sid,\n    _Out_ PPH_STRING *Description\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSamAccountDescription(\n    _In_ PSID Sid\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryLogonInformation(\n    _In_ PCPH_STRINGREF DomainName,\n    _In_ PCPH_STRINGREF UserName,\n    _Out_ PUSER_LOGON_INFORMATION* LogonInfo\n    );\n\nEXTERN_C_END\n\n#endif // _PH_LSAMSUP_H\n"
  },
  {
    "path": "phlib/include/lsasup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2018-2022\n *\n */\n\n#ifndef _PH_LSASUP_H\n#define _PH_LSASUP_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenLsaPolicy(\n    _Out_ PLSA_HANDLE PolicyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PUNICODE_STRING SystemName\n    );\n\nPHLIBAPI\nLSA_HANDLE\nNTAPI\nPhGetLookupPolicyHandle(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupPrivilegeName(\n    _In_ PLUID PrivilegeValue,\n    _Out_ PPH_STRING *PrivilegeName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupPrivilegeDisplayName(\n    _In_ PPH_STRINGREF PrivilegeName,\n    _Out_ PPH_STRING *PrivilegeDisplayName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupPrivilegeValue(\n    _In_ PPH_STRINGREF PrivilegeName,\n    _Out_ PLUID PrivilegeValue\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupSid(\n    _In_ PSID Sid,\n    _Out_opt_ PPH_STRING *Name,\n    _Out_opt_ PPH_STRING *DomainName,\n    _Out_opt_ PSID_NAME_USE NameUse\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupSids(\n    _In_ ULONG Count,\n    _In_ PSID *Sids,\n    _Out_ PPH_STRING **FullNames\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupName(\n    _In_ PPH_STRINGREF Name,\n    _Out_opt_ PSID *Sid,\n    _Out_opt_ PPH_STRING *DomainName,\n    _Out_opt_ PSID_NAME_USE NameUse\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSidFullName(\n    _In_ PSID Sid,\n    _In_ BOOLEAN IncludeDomain,\n    _Out_opt_ PSID_NAME_USE NameUse\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhSidToStringSid(\n    _In_ PSID Sid\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSidToBuffer(\n    _In_ PSID Sid,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ USHORT BufferLength,\n    _Out_opt_ PUSHORT ReturnLength\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetTokenUserString(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN IncludeDomain\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetAccountPrivileges(\n    _In_ PSID AccountSid,\n    _Out_ PTOKEN_PRIVILEGES* Privileges\n    );\n\ntypedef NTSTATUS (NTAPI* PPH_ENUM_PRIVILEGES)(\n    _In_ PPOLICY_PRIVILEGE_DEFINITION Privileges,\n    _In_ ULONG NumberOfPrivileges,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumeratePrivileges(\n    _In_ PPH_ENUM_PRIVILEGES Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef enum _LSA_USER_ACCOUNT_TYPE\n{\n    UnknownUserAccountType,\n    LocalUserAccountType,\n    PrimaryDomainUserAccountType,\n    ExternalDomainUserAccountType,\n    LocalConnectedUserAccountType,\n    AADUserAccountType,\n    InternetUserAccountType,\n    MSAUserAccountType\n} LSA_USER_ACCOUNT_TYPE, *PLSA_USER_ACCOUNT_TYPE;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSidAccountType(\n    _In_ PSID Sid,\n    _Out_ PLSA_USER_ACCOUNT_TYPE AccountType\n    );\n\nPHLIBAPI\nPCWSTR\nNTAPI\nPhGetSidAccountTypeString(\n    _In_ PSID Sid\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetCapabilitySidName(\n    _In_ PSID CapabilitySid\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetCapabilityGuidName(\n    _In_ PPH_STRING GuidString\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhBuildTrusteeWithSid(\n    _Out_ PVOID Trustee,\n    _In_opt_ PSID Sid\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhMapGenericMask(\n    _Inout_ PACCESS_MASK AccessMask,\n    _In_ PGENERIC_MAPPING GenericMapping\n    );\n\ntypedef _Function_class_(PH_ENUM_ACCOUNT_CALLBACK)\nNTSTATUS PH_ENUM_ACCOUNT_CALLBACK(\n    _In_ PPH_STRINGREF AccountName,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_ACCOUNT_CALLBACK* PPH_ENUM_ACCOUNT_CALLBACK;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumerateAccounts(\n    _In_ PPH_ENUM_ACCOUNT_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateServiceSidToBuffer(\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid,\n    _Inout_ PULONG ServiceSidLength\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhCreateServiceSidToStringSid(\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetAzureDirectoryObjectSid(\n    _In_ PSID ActiveDirectorySid\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsDomainJoined(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSidAuthorityName(\n    _In_ PSID Sid\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatSidTooltip(\n    _In_ PSID Sid,\n    _In_ BOOLEAN IncludeName,\n    _In_opt_ PLSA_USER_ACCOUNT_TYPE AccountType\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsServiceSid(\n    _In_ PSID Sid\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/mapimg.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2017-2023\n *     jx-s    2023\n *\n */\n\n#ifndef _PH_MAPIMG_H\n#define _PH_MAPIMG_H\n\nEXTERN_C_START\n\n#include <exlf.h>\n#include <exprodid.h>\n\n// Section mapping type flags\n#define PH_MAPPED_IMAGE_FLAG_SEC_COMMIT      0x0  // File mapping (default)\n#define PH_MAPPED_IMAGE_FLAG_SEC_IMAGE       0x1  // Image mapping (SEC_IMAGE*)\n\ntypedef struct _PH_MAPPED_IMAGE\n{\n    USHORT Signature;\n    USHORT Flags;\n    ULONG Spare;\n    PVOID ViewBase;\n    SIZE_T ViewSize;\n\n    union\n    {\n        struct // PE image\n        {\n            union\n            {\n                PIMAGE_NT_HEADERS32 NtHeaders32;\n                PIMAGE_NT_HEADERS64 NtHeaders64;\n                PIMAGE_NT_HEADERS NtHeaders;\n            };\n\n            USHORT Magic;\n            USHORT NumberOfSections;\n            PIMAGE_SECTION_HEADER Sections;\n        };\n\n        struct // ELF image\n        {\n            struct _ELF_IMAGE_HEADER *Header;\n            union\n            {\n                struct _ELF_IMAGE_HEADER32 *Headers32;\n                struct _ELF_IMAGE_HEADER64 *Headers64;\n            };\n        };\n    };\n} PH_MAPPED_IMAGE, *PPH_MAPPED_IMAGE;\n\nFORCEINLINE\nVOID\nNTAPI\nPhMappedImageProbe(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    )\n{\n    PhProbeAddress(Address, Length, MappedImage->ViewBase, MappedImage->ViewSize, __alignof(UCHAR));\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeMappedImage(\n    _Out_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T ViewSize\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadMappedImage(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadMappedImageEx(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadMappedImageHeaderPageSize(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadMappedImage(\n    _Inout_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadMappedImageHeaderFromFile(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadMappedImageHeaderFromFile(\n    _Inout_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMapViewOfEntireFile(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PVOID *ViewBase,\n    _Out_ PSIZE_T ViewSize\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMapViewOfEntireFileEx(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PVOID* ViewBase,\n    _Out_ PSIZE_T ViewSize\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhMappedImagePrefetch(\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nPIMAGE_SECTION_HEADER\nNTAPI\nPhMappedImageSectionByName(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PCWSTR Name,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nPIMAGE_SECTION_HEADER\nNTAPI\nPhMappedImageRvaToSection(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Rva\n    );\n\n_Success_(return != NULL)\nPHLIBAPI\nPVOID\nNTAPI\nPhMappedImageRvaToVa(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Rva,\n    _Out_opt_ PIMAGE_SECTION_HEADER *Section\n    );\n\n_Success_(return != NULL)\nPHLIBAPI\nPVOID\nNTAPI\nPhMappedImageVaToVa(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONGLONG Va,\n    _Out_opt_ PIMAGE_SECTION_HEADER* Section\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageSectionName(\n    _In_ PIMAGE_SECTION_HEADER Section,\n    _Out_writes_opt_z_(Count) PWSTR Buffer,\n    _In_ ULONG Count,\n    _Out_opt_ PULONG ReturnCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageDataDirectory(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Index,\n    _Out_ PIMAGE_DATA_DIRECTORY *Entry\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhRelocateMappedImageDataEntryARM64X(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_DATA_DIRECTORY Entry,\n    _Out_ PIMAGE_DATA_DIRECTORY RelocatedEntry\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetMappedImageDirectoryEntry(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Index\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageLoadConfig32(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY32 *LoadConfig\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageLoadConfig64(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY64 *LoadConfig\n    );\n\n// Remote mapped image\n\ntypedef _Function_class_(PH_READ_VIRTUAL_MEMORY_CALLBACK)\nNTSTATUS NTAPI PH_READ_VIRTUAL_MEMORY_CALLBACK(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_READ_VIRTUAL_MEMORY_CALLBACK* PPH_READ_VIRTUAL_MEMORY_CALLBACK;\n\ntypedef struct _PH_REMOTE_MAPPED_IMAGE\n{\n    HANDLE ProcessHandle;\n    PVOID ViewBase;\n    SIZE_T ViewSize;\n    union\n    {\n        PIMAGE_NT_HEADERS32 NtHeaders32;\n        PIMAGE_NT_HEADERS64 NtHeaders64;\n        PIMAGE_NT_HEADERS NtHeaders;\n    };\n    USHORT Magic;\n    USHORT NumberOfSections;\n    PIMAGE_SECTION_HEADER Sections;\n    PVOID PageCache;\n\n    PPH_READ_VIRTUAL_MEMORY_CALLBACK ReadVirtualMemoryCallback;\n    PVOID Context;\n} PH_REMOTE_MAPPED_IMAGE, *PPH_REMOTE_MAPPED_IMAGE;\n\nFORCEINLINE\nVOID\nNTAPI\nRemoteMappedImageProbe(\n    _In_ PPH_REMOTE_MAPPED_IMAGE MappedImage,\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    )\n{\n    PhProbeAddress(Address, Length, MappedImage->ViewBase, MappedImage->ViewSize, 1);\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeRemoteMappedImage(\n    _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_opt_ PPH_READ_VIRTUAL_MEMORY_CALLBACK ReadVirtualMemoryCallback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadRemoteMappedImage(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T ViewSize\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadRemoteMappedImage(\n    _Inout_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetRemoteMappedImageDataEntry(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_ ULONG Index,\n    _Out_ PIMAGE_DATA_DIRECTORY* Entry\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetRemoteMappedImageDirectoryEntry(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_ ULONG Index,\n    _Out_ PVOID* DataBuffer,\n    _Out_opt_ ULONG* DataLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetRemoteMappedImageDebugEntryByType(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_ ULONG Type,\n    _Out_opt_ PULONG DataLength,\n    _Out_ PPVOID DataBuffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetRemoteMappedImageGuardFlags(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _Out_ PULONG GuardFlags\n    );\n\ntypedef struct _PH_MAPPED_IMAGE_EXPORTS\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    ULONG NumberOfEntries;\n\n    PIMAGE_DATA_DIRECTORY DataDirectory;\n    IMAGE_DATA_DIRECTORY DataDirectoryARM64X;\n    PIMAGE_EXPORT_DIRECTORY ExportDirectory;\n    PULONG AddressTable;\n    PULONG NamePointerTable;\n    PUSHORT OrdinalTable;\n} PH_MAPPED_IMAGE_EXPORTS, *PPH_MAPPED_IMAGE_EXPORTS;\n\ntypedef struct _PH_MAPPED_IMAGE_EXPORT_ENTRY\n{\n    USHORT Ordinal;\n    ULONG Hint;\n    PCSTR Name;\n} PH_MAPPED_IMAGE_EXPORT_ENTRY, *PPH_MAPPED_IMAGE_EXPORT_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_EXPORT_FUNCTION\n{\n    PVOID Function;\n    PCSTR ForwardedName;\n} PH_MAPPED_IMAGE_EXPORT_FUNCTION, *PPH_MAPPED_IMAGE_EXPORT_FUNCTION;\n\n#define PH_GET_IMAGE_EXPORTS_ARM64X 0x00000001ul\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExportsEx(\n    _Out_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExports(\n    _Out_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExportEntry(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_EXPORT_ENTRY Entry\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExportFunction(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_opt_ PCSTR Name,\n    _In_opt_ USHORT Ordinal,\n    _Out_ PPH_MAPPED_IMAGE_EXPORT_FUNCTION Function\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExportFunctionRemote(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_opt_ PCSTR Name,\n    _In_opt_ USHORT Ordinal,\n    _In_ PVOID RemoteBase,\n    _Out_ PVOID *Function\n    );\n\n#define PH_MAPPED_IMAGE_DELAY_IMPORTS 0x1\n\ntypedef struct _PH_MAPPED_IMAGE_IMPORTS\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    ULONG Flags;\n    ULONG NumberOfDlls;\n\n    union\n    {\n        PIMAGE_IMPORT_DESCRIPTOR DescriptorTable;\n        PIMAGE_DELAYLOAD_DESCRIPTOR DelayDescriptorTable;\n    };\n} PH_MAPPED_IMAGE_IMPORTS, *PPH_MAPPED_IMAGE_IMPORTS;\n\ntypedef struct _PH_MAPPED_IMAGE_IMPORT_DLL\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    ULONG Flags;\n    ULONG NumberOfEntries;\n    PCSTR Name;\n\n    union\n    {\n        PIMAGE_IMPORT_DESCRIPTOR Descriptor;\n        PIMAGE_DELAYLOAD_DESCRIPTOR DelayDescriptor;\n    };\n    PVOID LookupTable;\n} PH_MAPPED_IMAGE_IMPORT_DLL, *PPH_MAPPED_IMAGE_IMPORT_DLL;\n\ntypedef struct _PH_MAPPED_IMAGE_IMPORT_ENTRY\n{\n    PCSTR Name;\n    union\n    {\n        USHORT Ordinal;\n        USHORT NameHint;\n    };\n} PH_MAPPED_IMAGE_IMPORT_ENTRY, *PPH_MAPPED_IMAGE_IMPORT_ENTRY;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageImports(\n    _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageImportDll(\n    _In_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageImportEntry(\n    _In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_IMPORT_ENTRY Entry\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetMappedImageImportEntryRva(\n    _In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll,\n    _In_ ULONG Index,\n    _In_ BOOLEAN DelayImport\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageDelayImports(\n    _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nUSHORT\nNTAPI\nPhCheckSum(\n    _In_ ULONG Sum,\n    _In_reads_(Count) PUSHORT Buffer,\n    _In_ ULONG Count\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhCheckSumMappedImage(\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\ntypedef struct _IMAGE_CFG_ENTRY\n{\n    ULONG Rva;\n    struct\n    {\n        BOOLEAN SuppressedCall : 1;\n        BOOLEAN ExportSuppressed : 1;\n        BOOLEAN LangExcptHandler : 1;\n        BOOLEAN Xfg : 1;\n        BOOLEAN Reserved : 4;\n    };\n    ULONG64 XfgHash;\n} IMAGE_CFG_ENTRY, *PIMAGE_CFG_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_CFG\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    ULONG EntrySize;\n\n    union\n    {\n        ULONG GuardFlags;\n        struct\n        {\n            ULONG CfgInstrumented : 1;\n            ULONG WriteIntegrityChecks : 1;\n            ULONG CfgFunctionTablePresent : 1;\n            ULONG SecurityCookieUnused : 1;\n            ULONG ProtectDelayLoadedIat : 1;\n            ULONG DelayLoadInDidatSection : 1;\n            ULONG HasExportSuppressionInfos : 1;\n            ULONG EnableExportSuppression : 1;\n            ULONG CfgLongJumpTablePresent : 1;\n            ULONG Spare : 23;\n        };\n    };\n\n    PULONGLONG GuardFunctionTable;\n    ULONGLONG NumberOfGuardFunctionEntries;\n\n    PULONGLONG GuardAdressIatTable;\n    ULONGLONG NumberOfGuardAdressIatEntries;\n\n    PULONGLONG GuardLongJumpTable;\n    ULONGLONG NumberOfGuardLongJumpEntries;\n} PH_MAPPED_IMAGE_CFG, *PPH_MAPPED_IMAGE_CFG;\n\ntypedef enum _CFG_ENTRY_TYPE\n{\n    ControlFlowGuardFunction,\n    ControlFlowGuardTakenIatEntry,\n    ControlFlowGuardLongJump\n} CFG_ENTRY_TYPE;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageCfg(\n    _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageCfgEntry(\n    _In_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ ULONGLONG Index,\n    _In_ CFG_ENTRY_TYPE Type,\n    _Out_ PIMAGE_CFG_ENTRY Entry\n    );\n\ntypedef struct _PH_IMAGE_RESOURCE_ENTRY\n{\n    ULONG_PTR Type;\n    ULONG_PTR Name;\n    ULONG_PTR Language;\n    ULONG Offset;\n    ULONG Size;\n    ULONG CodePage;\n    //PVOID Data; // PhMappedImageRvaToVa(MappedImage, resourceData->OffsetToData, NULL);\n} PH_IMAGE_RESOURCE_ENTRY, *PPH_IMAGE_RESOURCE_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_RESOURCES\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    PIMAGE_DATA_DIRECTORY DataDirectory;\n    PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;\n\n    ULONG NumberOfEntries;\n    PPH_IMAGE_RESOURCE_ENTRY ResourceEntries;\n} PH_MAPPED_IMAGE_RESOURCES, *PPH_MAPPED_IMAGE_RESOURCES;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageResources(\n    _Out_ PPH_MAPPED_IMAGE_RESOURCES Resources,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageResource(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _In_opt_ USHORT Language,\n    _Out_opt_ PULONG ResourceLength,\n    _Out_opt_ PVOID* ResourceBuffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageResourceIndex(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_RESOURCE_DIRECTORY ResourceDirectory,\n    _In_ LONG ResourceIndex,\n    _In_ PCWSTR ResourceType,\n    _Out_opt_ ULONG* ResourceLength,\n    _Out_opt_ PVOID* ResourceBuffer\n    );\n\ntypedef struct _PH_IMAGE_TLS_CALLBACK_ENTRY\n{\n    ULONGLONG Index;\n    ULONGLONG Address;\n} PH_IMAGE_TLS_CALLBACK_ENTRY, *PPH_IMAGE_TLS_CALLBACK_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_TLS_CALLBACKS\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    PIMAGE_DATA_DIRECTORY DataDirectory;\n\n    union\n    {\n        PIMAGE_TLS_DIRECTORY32 TlsDirectory32;\n        PIMAGE_TLS_DIRECTORY64 TlsDirectory64;\n    };\n\n    //PVOID CallbackIndexes;\n    PVOID CallbackAddress;\n\n    ULONG NumberOfEntries;\n    PPH_IMAGE_TLS_CALLBACK_ENTRY Entries;\n} PH_MAPPED_IMAGE_TLS_CALLBACKS, *PPH_MAPPED_IMAGE_TLS_CALLBACKS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageTlsCallbacks(\n    _Out_ PPH_MAPPED_IMAGE_TLS_CALLBACKS TlsCallbacks,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\ntypedef struct _PH_MAPPED_IMAGE_PRODID_ENTRY\n{\n    USHORT ProductId;\n    USHORT ProductBuild;\n    ULONG ProductCount;\n} PH_MAPPED_IMAGE_PRODID_ENTRY, *PPH_MAPPED_IMAGE_PRODID_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_PRODID\n{\n    //WCHAR Key[PH_PTR_STR_LEN_1];\n    BOOLEAN Valid;\n    PPH_STRING Key;\n    PPH_STRING RawHash;\n    PPH_STRING Hash;\n    ULONG NumberOfEntries;\n    PPH_MAPPED_IMAGE_PRODID_ENTRY ProdIdEntries;\n} PH_MAPPED_IMAGE_PRODID, *PPH_MAPPED_IMAGE_PRODID;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageProdIdHeader(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_PRODID ProdIdHeader\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageProdIdExtents(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PULONG ProdIdHeaderStart,\n    _Out_ PULONG ProdIdHeaderEnd\n    );\n\ntypedef struct _PH_IMAGE_DEBUG_ENTRY\n{\n    ULONG Characteristics;\n    ULONG TimeDateStamp;\n    USHORT MajorVersion;\n    USHORT MinorVersion;\n    ULONG Type;\n    ULONG SizeOfData;\n    ULONG AddressOfRawData;\n    ULONG PointerToRawData;\n} PH_IMAGE_DEBUG_ENTRY, *PPH_IMAGE_DEBUG_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_DEBUG\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    PIMAGE_DATA_DIRECTORY DataDirectory;\n    PIMAGE_DEBUG_DIRECTORY DebugDirectory;\n\n    ULONG NumberOfEntries;\n    PPH_IMAGE_DEBUG_ENTRY DebugEntries;\n} PH_MAPPED_IMAGE_DEBUG, *PPH_MAPPED_IMAGE_DEBUG;\n\n// Note: Remove once they've been added to the Windows SDK. (dmex)\n#ifndef IMAGE_DEBUG_TYPE_EMBEDDEDPORTABLEPDB\n#define IMAGE_DEBUG_TYPE_EMBEDDEDPORTABLEPDB 17\n#endif\n\n#ifndef IMAGE_DEBUG_TYPE_PDBCHECKSUM\n#define IMAGE_DEBUG_TYPE_PDBCHECKSUM 19\n#endif\n\n#ifndef IMAGE_DEBUG_TYPE_PERFMAP\n#define IMAGE_DEBUG_TYPE_PERFMAP 21\n#endif\n\ntypedef struct _IMAGE_DEBUG_TYPE_PERFMAPV1\n{\n    ULONG Magic; // 0x4D523252\n    BYTE Signature[16];\n    ULONG Version;\n    // BYTE Data[1];\n} IMAGE_DEBUG_TYPE_PERFMAPV1, *PIMAGE_DEBUG_TYPE_PERFMAPV1;\n\n#define CODEVIEW_SIGNATURE_NB10 '01BN'\n#define CODEVIEW_SIGNATURE_RSDS 'SDSR'\n\ntypedef struct _CODEVIEW_HEADER\n{\n    ULONG Signature;\n    LONG Offset;\n} CODEVIEW_HEADER, *PCODEVIEW_HEADER;\n\ntypedef struct _CODEVIEW_INFO_PDB20\n{\n    CODEVIEW_HEADER Header;\n    ULONG Timestamp; // seconds since 1970\n    ULONG Age;\n    CHAR PdbFileName[1];\n} CODEVIEW_INFO_PDB20, *PCODEVIEW_INFO_PDB20;\n\ntypedef struct _CODEVIEW_INFO_PDB70\n{\n    ULONG Signature;\n    GUID PdbGuid;\n    ULONG PdbAge;\n    CHAR ImageName[1];\n} CODEVIEW_INFO_PDB70, *PCODEVIEW_INFO_PDB70;\n\n// IMAGE_GUARD_EH_CONTINUATION_TABLE_PRESENT, Windows 20H1 and 21H1 have different values\n#define IMAGE_GUARD_EH_CONTINUATION_TABLE_PRESENT_V1 0x00200000\n#define IMAGE_GUARD_EH_CONTINUATION_TABLE_PRESENT_V2 0x00400000\n\n#ifndef IMAGE_GUARD_XFG_ENABLED\n#define IMAGE_GUARD_XFG_ENABLED 0x00800000 // Module was built with xfg\n#endif\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageDebug(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_DEBUG Debug\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageDebugEntryByType(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Type,\n    _Out_opt_ ULONG* DataLength,\n    _Out_opt_ PVOID* DataBuffer\n    );\n\n// maplib\n\ntypedef struct _PH_MAPPED_ARCHIVE *PPH_MAPPED_ARCHIVE;\n\ntypedef enum _PH_MAPPED_ARCHIVE_MEMBER_TYPE\n{\n    NormalArchiveMemberType,\n    LinkerArchiveMemberType,\n    LongnamesArchiveMemberType\n} PH_MAPPED_ARCHIVE_MEMBER_TYPE;\n\ntypedef struct _PH_MAPPED_ARCHIVE_MEMBER\n{\n    PPH_MAPPED_ARCHIVE MappedArchive;\n    PH_MAPPED_ARCHIVE_MEMBER_TYPE Type;\n    PCSTR Name;\n    ULONG Size;\n    PVOID Data;\n\n    PIMAGE_ARCHIVE_MEMBER_HEADER Header;\n    CHAR NameBuffer[20];\n} PH_MAPPED_ARCHIVE_MEMBER, *PPH_MAPPED_ARCHIVE_MEMBER;\n\ntypedef struct _PH_MAPPED_ARCHIVE\n{\n    PVOID ViewBase;\n    SIZE_T Size;\n\n    PH_MAPPED_ARCHIVE_MEMBER FirstLinkerMember;\n    PH_MAPPED_ARCHIVE_MEMBER SecondLinkerMember;\n    PH_MAPPED_ARCHIVE_MEMBER LongnamesMember;\n    BOOLEAN HasLongnamesMember;\n\n    PPH_MAPPED_ARCHIVE_MEMBER FirstStandardMember;\n    PPH_MAPPED_ARCHIVE_MEMBER LastStandardMember;\n} PH_MAPPED_ARCHIVE, *PPH_MAPPED_ARCHIVE;\n\ntypedef struct _PH_MAPPED_ARCHIVE_IMPORT_ENTRY\n{\n    PCSTR Name;\n    PCSTR DllName;\n    union\n    {\n        USHORT Ordinal;\n        USHORT NameHint;\n    };\n    BYTE Type;\n    BYTE NameType;\n    USHORT Machine;\n} PH_MAPPED_ARCHIVE_IMPORT_ENTRY, *PPH_MAPPED_ARCHIVE_IMPORT_ENTRY;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeMappedArchive(\n    _Out_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadMappedArchive(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_ARCHIVE MappedArchive\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadMappedArchive(\n    _Inout_ PPH_MAPPED_ARCHIVE MappedArchive\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetNextMappedArchiveMember(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member,\n    _Out_ PPH_MAPPED_ARCHIVE_MEMBER NextMember\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsMappedArchiveMemberShortFormat(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedArchiveImportEntry(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member,\n    _Out_ PPH_MAPPED_ARCHIVE_IMPORT_ENTRY Entry\n    );\n\ntypedef struct _PH_MAPPED_IMAGE_EH_CONT\n{\n    PULONGLONG EhContTable;\n    ULONGLONG NumberOfEhContEntries;\n    ULONG EntrySize;\n} PH_MAPPED_IMAGE_EH_CONT, *PPH_MAPPED_IMAGE_EH_CONT;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageEhCont(\n    _Out_ PPH_MAPPED_IMAGE_EH_CONT EhContConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\ntypedef struct _PH_IMAGE_DEBUG_POGO_ENTRY\n{\n    ULONG Rva;\n    ULONG Size;\n    PVOID Data;\n    WCHAR Name[0x100];\n} PH_IMAGE_DEBUG_POGO_ENTRY, *PPH_IMAGE_DEBUG_POGO_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_DEBUG_POGO\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    PIMAGE_DEBUG_POGO_SIGNATURE PogoDirectory;\n\n    ULONG NumberOfEntries;\n    PPH_IMAGE_DEBUG_POGO_ENTRY PogoEntries;\n} PH_MAPPED_IMAGE_DEBUG_POGO, *PPH_MAPPED_IMAGE_DEBUG_POGO;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImagePogo(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_DEBUG_POGO PogoDebug\n    );\n\ntypedef struct _PH_IMAGE_RELOC_ENTRY\n{\n    ULONG BlockIndex;\n    ULONG BlockRva;\n    IMAGE_RELOCATION_RECORD Record;\n    PVOID ImageBaseVa;\n    PVOID MappedImageVa;\n} PH_IMAGE_RELOC_ENTRY, *PPH_IMAGE_RELOC_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_RELOC\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    PIMAGE_DATA_DIRECTORY DataDirectory;\n    PIMAGE_BASE_RELOCATION FirstRelocationDirectory;\n\n    ULONG NumberOfEntries;\n    PPH_IMAGE_RELOC_ENTRY RelocationEntries;\n} PH_MAPPED_IMAGE_RELOC, *PPH_MAPPED_IMAGE_RELOC;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageRelocations(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_RELOC Relocations\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeMappedImageRelocations(\n    _In_opt_ PPH_MAPPED_IMAGE_RELOC Relocations\n    );\n\ntypedef struct _PH_IMAGE_DYNAMIC_RELOC_ENTRY\n{\n    ULONGLONG Symbol;\n\n    union\n    {\n        // IMAGE_DYNAMIC_RELOCATION_GUARD_IMPORT_CONTROL_TRANSFER\n        struct\n        {\n            ULONG BlockIndex;\n            ULONG BlockRva;\n            IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION Record;\n        } ImportControl;\n\n        // IMAGE_DYNAMIC_RELOCATION_GUARD_INDIR_CONTROL_TRANSFER\n        struct\n        {\n            ULONG BlockIndex;\n            ULONG BlockRva;\n            IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION Record;\n        } IndirControl;\n\n        // IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH\n        struct\n        {\n            ULONG BlockIndex;\n            ULONG BlockRva;\n            IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION Record;\n        } SwitchBranch;\n\n        // IMAGE_DYNAMIC_RELOCATION_FUNCTION_OVERRIDE\n        struct\n        {\n            ULONG BlockIndex;\n            ULONG BlockRva;\n            IMAGE_RELOCATION_RECORD Record;\n            PIMAGE_BDD_DYNAMIC_RELOCATION BDDNodes;\n            ULONG BDDNodesCount;\n            ULONG OriginalRva;\n            ULONG BDDOffset;\n            PULONG Rvas;\n            ULONG RvasCount;\n        } FuncOverride;\n\n        // IMAGE_DYNAMIC_RELOCATION_ARM64X\n        struct\n        {\n            ULONG BlockIndex;\n            ULONG BlockRva;\n            union\n            {\n                LONG64 Delta;\n                ULONG64 Value8;\n                ULONG Value4;\n                USHORT Value2;\n            };\n            union\n            {\n                IMAGE_DVRT_ARM64X_FIXUP_RECORD RecordFixup;\n                IMAGE_DVRT_ARM64X_DELTA_FIXUP_RECORD RecordDelta;\n            };\n        } ARM64X;\n\n        // IMAGE_DYNAMIC_RELOCATION_ARM64_KERNEL_IMPORT_CALL_TRANSFER\n        struct\n        {\n            ULONG BlockIndex;\n            ULONG BlockRva;\n            IMAGE_IMPORT_CONTROL_TRANSFER_ARM64_RELOCATION Record;\n        } ARM64ImportControl;\n\n        // IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE\n        struct\n        {\n            ULONG BlockIndex;\n            ULONG BlockRva;\n            UCHAR PrologueByteCount;\n            PVOID PrologueBytes;  // Pointer to prologue byte array\n        } RFPrologue;\n\n        // IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE\n        struct\n        {\n            ULONG BlockIndex;\n            ULONG BlockRva;\n            ULONG EpilogueCount;\n            UCHAR EpilogueByteCount;\n            UCHAR BranchDescriptorElementSize;\n            USHORT BranchDescriptorCount;\n            PVOID BranchDescriptors;      // Pointer to branch descriptors\n            PVOID BranchDescriptorBitMap; // Pointer to branch descriptor bitmap\n        } RFEpilogue;\n\n        // IMAGE_DYNAMIC_RELOCATION_KI_USER_SHARED_DATA64 or similar\n        struct\n        {\n            ULONG BlockIndex;\n            ULONG BlockRva;\n            IMAGE_RELOCATION_RECORD Record;\n        } Other;\n    };\n\n    PVOID ImageBaseVa;\n    PVOID MappedImageVa;\n} PH_IMAGE_DYNAMIC_RELOC_ENTRY, *PPH_IMAGE_DYNAMIC_RELOC_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_DYNAMIC_RELOC\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    PIMAGE_DYNAMIC_RELOCATION_TABLE RelocationTable;\n\n    ULONG NumberOfEntries;\n    PPH_IMAGE_DYNAMIC_RELOC_ENTRY RelocationEntries;\n} PH_MAPPED_IMAGE_DYNAMIC_RELOC, *PPH_MAPPED_IMAGE_DYNAMIC_RELOC;\n\ntypedef _Function_class_(PH_MAPPED_IMAGE_RELOC_CALLBACK)\nNTSTATUS NTAPI PH_MAPPED_IMAGE_RELOC_CALLBACK(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_DATA_DIRECTORY DataDirectory,\n    _In_ PIMAGE_BASE_RELOCATION RelocationDirectory,\n    _In_ PIMAGE_RELOCATION_RECORD Relocations,\n    _In_ ULONG RelocationCount,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_MAPPED_IMAGE_RELOC_CALLBACK *PPH_MAPPED_IMAGE_RELOC_CALLBACK;\n\ntypedef _Function_class_(PH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK)\nNTSTATUS NTAPI PH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PPH_IMAGE_DYNAMIC_RELOC_ENTRY Entry,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK *PPH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMappedImageEnumerateRelocations(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PPH_MAPPED_IMAGE_RELOC_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMappedImageEnumerateDynamicRelocations(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageDynamicRelocationsTable(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_opt_ PIMAGE_DYNAMIC_RELOCATION_TABLE* Table\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageDynamicRelocations(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC Relocations\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeMappedImageDynamicRelocations(\n    _In_opt_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC Relocations\n    );\n\ntypedef struct _PH_MAPPED_IMAGE_EXCEPTIONS\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    PIMAGE_DATA_DIRECTORY DataDirectory;\n    IMAGE_DATA_DIRECTORY DataDirectoryARM64X;\n    PVOID ExceptionDirectory;\n\n    ULONG NumberOfEntries;\n    PVOID ExceptionEntries;\n} PH_MAPPED_IMAGE_EXCEPTIONS, *PPH_MAPPED_IMAGE_EXCEPTIONS;\n\n#define PH_GET_IMAGE_EXCEPTIONS_ARM64X 0x00000001ul\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExceptionsEx(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_EXCEPTIONS Exceptions,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExceptions(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_EXCEPTIONS Exceptions\n    );\n\n// Note: Remove if/when added to the Windows SDK. (dmex)\n#ifndef _IMAGE_VOLATILE_METADATA\ntypedef struct _IMAGE_VOLATILE_METADATA\n{\n    ULONG Size;\n    ULONG Version;\n    ULONG VolatileAccessTable;\n    ULONG VolatileAccessTableSize;\n    ULONG VolatileInfoRangeTable;\n    ULONG VolatileInfoRangeTableSize;\n} IMAGE_VOLATILE_METADATA, *PIMAGE_VOLATILE_METADATA;\n#endif\n\n// Note: Remove if/when added to the Windows SDK. (dmex)\n#ifndef _IMAGE_VOLATILE_RVA_METADATA\ntypedef struct _IMAGE_VOLATILE_RVA_METADATA\n{\n    ULONG Rva;\n} IMAGE_VOLATILE_RVA_METADATA, *PIMAGE_VOLATILE_RVA_METADATA;\n#endif\n\n// Note: Remove if/when added to the Windows SDK. (dmex)\n#ifndef _IMAGE_VOLATILE_RANGE_METADATA\ntypedef struct _IMAGE_VOLATILE_RANGE_METADATA\n{\n    ULONG Rva;\n    ULONG Size;\n} IMAGE_VOLATILE_RANGE_METADATA, *PIMAGE_VOLATILE_RANGE_METADATA;\n#endif\n\ntypedef struct _PH_IMAGE_VOLATILE_ENTRY\n{\n    ULONG Rva;\n    ULONG Size;\n} PH_IMAGE_VOLATILE_ENTRY, *PPH_IMAGE_VOLATILE_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_VOLATILE_METADATA\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    PIMAGE_VOLATILE_METADATA VolatileMetadata;\n\n    ULONG NumberOfAccessEntries;\n    ULONG NumberOfRangeEntries;\n    PPH_IMAGE_VOLATILE_ENTRY AccessEntries;\n    PPH_IMAGE_VOLATILE_ENTRY RangeEntries;\n} PH_MAPPED_IMAGE_VOLATILE_METADATA, *PPH_MAPPED_IMAGE_VOLATILE_METADATA;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageVolatileMetadata(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_VOLATILE_METADATA VolatileMetadata\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageAuthenticodeHash(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PH_HASH_ALGORITHM Algorithm,\n    _Out_ PPH_STRING* AuthenticodeHash\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageWdacHash(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PH_HASH_ALGORITHM Algorithm,\n    _Out_ PPH_STRING* WdacHash\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetMappedImageEntropy(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PFLOAT ImageEntropy,\n    _Out_ PFLOAT ImageMean,\n    _Out_ PFLOAT ImageVariance\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetMappedImageCHPEVersion(\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetRemoteMappedImageCHPEVersion(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _Out_ PULONG CHPEVersion\n    );\n\n// ELF binary support\n\nNTSTATUS PhInitializeMappedWslImage(\n    _Out_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    );\n\nULONG64 PhGetMappedWslImageBaseAddress(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage\n    );\n\ntypedef struct _PH_ELF_IMAGE_SECTION\n{\n    UINT32 Type;\n    ULONGLONG Flags;\n    ULONGLONG Address;\n    ULONGLONG Offset;\n    ULONGLONG Size;\n    WCHAR Name[MAX_PATH];\n} PH_ELF_IMAGE_SECTION, *PPH_ELF_IMAGE_SECTION;\n\nBOOLEAN PhGetMappedWslImageSections(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ USHORT *NumberOfSections,\n    _Out_ PPH_ELF_IMAGE_SECTION *ImageSections\n    );\n\ntypedef struct _PH_ELF_IMAGE_SYMBOL_ENTRY\n{\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN ImportSymbol : 1;\n            BOOLEAN ExportSymbol : 1;\n            BOOLEAN UnknownSymbol : 1;\n            BOOLEAN Spare : 5;\n        };\n    };\n    UCHAR TypeInfo;\n    UCHAR OtherInfo;\n    ULONG SectionIndex;\n    ULONGLONG Address;\n    ULONGLONG Size;\n    WCHAR Name[MAX_PATH * 2];\n    WCHAR Module[MAX_PATH * 2];\n} PH_ELF_IMAGE_SYMBOL_ENTRY, *PPH_ELF_IMAGE_SYMBOL_ENTRY;\n\nBOOLEAN PhGetMappedWslImageSymbols(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ PPH_LIST *ImageSymbols\n    );\n\nVOID PhFreeMappedWslImageSymbols(\n    _In_ PPH_LIST ImageSymbols\n    );\n\ntypedef struct _PH_ELF_IMAGE_DYNAMIC_ENTRY\n{\n    LONGLONG Tag;\n    PWSTR Type;\n    PPH_STRING Value;\n} PH_ELF_IMAGE_DYNAMIC_ENTRY, *PPH_ELF_IMAGE_DYNAMIC_ENTRY;\n\nBOOLEAN PhGetMappedWslImageDynamic(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ PPH_LIST *DynamicSymbols\n    );\n\nVOID PhFreeMappedWslImageDynamic(\n    _In_ PPH_LIST ImageDynamic\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/mapldr.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_MAPLDR_H\n#define _PH_MAPLDR_H\n\nEXTERN_C_START\n\nPHLIBAPI\nPVOID\nNTAPI\nPhLoadLibrary(\n    _In_ PCWSTR FileName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhFreeLibrary(\n    _In_ PVOID BaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadLibraryAsImageResource(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName,\n    _Out_opt_ PVOID *BaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFreeLibraryAsImageResource(\n    _In_ PVOID BaseAddress\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetDllHandle(\n    _In_ PCWSTR DllName\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetModuleProcAddress(\n    _In_ PCWSTR ModuleName,\n    _In_opt_ PCSTR ProcedureName\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetProcedureAddress(\n    _In_ PVOID DllHandle,\n    _In_opt_ PCSTR ProcedureName,\n    _In_opt_ USHORT ProcedureNumber\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcedureAddressRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PCSTR ProcedureName,\n    _Out_ PVOID *ProcedureAddress,\n    _Out_opt_ PVOID *DllBase\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetProcedureAddressRemoteZ(\n    _In_ HANDLE ProcessHandle,\n    _In_ PCWSTR FileName,\n    _In_ PCSTR ProcedureName,\n    _Out_ PVOID *ProcedureAddress,\n    _Out_opt_ PVOID *DllBase\n    )\n{\n    PH_STRINGREF fileName;\n\n    PhInitializeStringRef(&fileName, FileName);\n\n    return PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &fileName,\n        ProcedureName,\n        ProcedureAddress,\n        DllBase\n        );\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadResource(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _Out_opt_ ULONG *ResourceLength,\n    _Out_opt_ PVOID *ResourceBuffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadResourceCopy(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _Out_opt_ ULONG *ResourceLength,\n    _Out_opt_ PVOID *ResourceBuffer\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhLoadString(\n    _In_ PVOID DllBase,\n    _In_ ULONG ResourceId\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhLoadIndirectString(\n    _In_ PCPH_STRINGREF SourceString\n    );\n\n_Success_(return != NULL)\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetDllFileName(\n    _In_ PVOID DllBase,\n    _Out_opt_ PULONG IndexOfFileName\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetLoaderEntryData(\n    _In_ PCPH_STRINGREF BaseDllName,\n    _Out_opt_ PVOID* DllBase,\n    _Out_opt_ ULONG* SizeOfImage,\n    _Out_opt_ PPH_STRING* FullName\n    );\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhGetLoaderEntryDataZ(\n    _In_ PCWSTR BaseDllName,\n    _Out_opt_ PVOID* DllBase,\n    _Out_opt_ ULONG* SizeOfImage,\n    _Out_opt_ PPH_STRING* FullName\n    )\n{\n    PH_STRINGREF baseDllName;\n\n    PhInitializeStringRef(&baseDllName, BaseDllName);\n\n    return PhGetLoaderEntryData(\n        &baseDllName,\n        DllBase,\n        SizeOfImage,\n        FullName\n        );\n}\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetLoaderEntryAddressDllBase(\n    _In_ PVOID PcAddress\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetLoaderEntryDllBase(\n    _In_opt_ PCPH_STRINGREF FullDllName,\n    _In_opt_ PCPH_STRINGREF BaseDllName\n    );\n\nFORCEINLINE\nPVOID\nNTAPI\nPhGetLoaderEntryDllBaseZ(\n    _In_ PCWSTR DllName\n    )\n{\n    PH_STRINGREF baseDllName;\n\n    PhInitializeStringRef(&baseDllName, DllName);\n\n    return PhGetLoaderEntryDllBase(NULL, &baseDllName);\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCaptureSystemDllInitBlock(\n    _In_ PVOID Source,\n    _Out_ PPS_SYSTEM_DLL_INIT_BLOCK Destination\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSystemDllInitBlock(\n    _Out_ PPS_SYSTEM_DLL_INIT_BLOCK SystemDllInitBlock\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetDllBaseProcedureAddress(\n    _In_ PVOID DllBase,\n    _In_opt_ PCSTR ProcedureName,\n    _In_opt_ USHORT ProcedureNumber\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetDllBaseProcedureAddressWithHint(\n    _In_ PVOID BaseAddress,\n    _In_ PCSTR ProcedureName,\n    _In_ USHORT ProcedureHint\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetDllProcedureAddress(\n    _In_ PCPH_STRINGREF DllName,\n    _In_opt_ PCSTR ProcedureName,\n    _In_opt_ USHORT ProcedureNumber\n    );\n\nFORCEINLINE\nPVOID\nNTAPI\nPhGetDllProcedureAddressZ(\n    _In_ PCWSTR DllName,\n    _In_opt_ PCSTR ProcedureName,\n    _In_opt_ USHORT ProcedureNumber\n    )\n{\n    PH_STRINGREF fileName;\n\n    PhInitializeStringRef(&fileName, DllName);\n\n    return PhGetDllProcedureAddress(\n        &fileName,\n        ProcedureName,\n        ProcedureNumber\n        );\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetLoaderEntryImageNtHeaders(\n    _In_ PVOID BaseAddress,\n    _Out_ PIMAGE_NT_HEADERS *ImageNtHeaders\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetLoaderEntryImageDirectory(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ ULONG ImageDirectoryIndex,\n    _Out_ PIMAGE_DATA_DIRECTORY *ImageDataDirectoryEntry,\n    _Out_ PVOID *ImageDirectoryEntry,\n    _Out_opt_ SIZE_T *ImageDirectoryLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetLoaderEntryImageVaToSection(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ PVOID ImageDirectoryAddress,\n    _Out_ PVOID *ImageSectionAddress,\n    _Out_ SIZE_T *ImageSectionLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoaderEntryImageRvaToSection(\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ ULONG Rva,\n    _Out_ PIMAGE_SECTION_HEADER *ImageSection,\n    _Out_ SIZE_T *ImageSectionLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoaderEntryImageRvaToVa(\n    _In_ PVOID BaseAddress,\n    _In_ ULONG Rva,\n    _Out_ PVOID *Va\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLoaderEntryImageExportSupressionPresent(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLoaderEntryGrantSuppressedCall(\n    _In_ PVOID ExportAddress\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetLoaderEntryImageExportFunction(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ PIMAGE_DATA_DIRECTORY DataDirectory,\n    _In_ PIMAGE_EXPORT_DIRECTORY ExportDirectory,\n    _In_opt_ PCSTR ExportName,\n    _In_opt_ USHORT ExportOrdinal\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetExportNameFromOrdinal(\n    _In_ PVOID DllBase,\n    _In_opt_ USHORT ProcedureNumber\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoaderEntryDetourImportProcedure(\n    _In_ PVOID BaseAddress,\n    _In_ PCSTR ImportName,\n    _In_ PCSTR ProcedureName,\n    _In_ PVOID FunctionAddress,\n    _Out_opt_ PVOID* OriginalAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoaderEntryLoadDll(\n    _In_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE RootDirectory,\n    _Out_ PVOID* BaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoaderEntryLoadAllImportsForDll(\n    _In_ PVOID BaseAddress,\n    _In_ PCSTR ImportDllName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadAllImportsForDll(\n    _In_ PCWSTR TargetDllName,\n    _In_ PCSTR ImportDllName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadPluginImage(\n    _In_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE RootDirectory,\n    _Out_opt_ PVOID *BaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileBinaryTypeWin32(\n    _In_ PCWSTR FileName,\n    _Out_ PULONG BinaryType\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/ph.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2018\n *\n */\n\n#ifndef _PH_PH_H\n#define _PH_PH_H\n\n#include <phbase.h>\n#include <phnative.h>\n#include <phnativeinl.h>\n#include <phutil.h>\n\n#endif\n"
  },
  {
    "path": "phlib/include/phafd.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     diversenok   2025\n *\n */\n\n#ifndef _PH_PHAFD_H\n#define _PH_PHAFD_H\n\n#include <ntafd.h>\n\nEXTERN_C_START\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhAfdIsSocketObjectName(\n    _In_opt_ PPH_STRING ObjectName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdIsSocketHandle(\n    _In_ HANDLE Handle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdDeviceIoControl(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG IoControlCode,\n    _In_reads_bytes_(InBufferSize) PVOID InBuffer,\n    _In_ ULONG InBufferSize,\n    _Out_writes_bytes_to_opt_(OutputBufferSize, *BytesReturned) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferSize,\n    _Out_opt_ PULONG BytesReturned,\n    _Inout_opt_ LPOVERLAPPED Overlapped\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdQuerySharedInfo(\n    _In_ HANDLE SocketHandle,\n    _Out_ PSOCK_SHARED_INFO SharedInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdQuerySimpleInfo(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG InformationType,\n    _Out_ PAFD_INFORMATION Information\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdQuerySocketOption(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG Level,\n    _In_ ULONG OptionName,\n    _Out_ PVOID OptionValue,\n    _In_ ULONG OptionLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdQueryOption(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG Level,\n    _In_ ULONG OptionName,\n    _Out_ PULONG OptionValue\n    );\n\ntypedef struct _TCP_INFO_v2 TCP_INFO_v2, *PTCP_INFO_v2;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdQueryTcpInfo(\n    _In_ HANDLE SocketHandle,\n    _Out_ PTCP_INFO_v2 TcpInfo,\n    _Out_ PULONG TcpInfoVersion\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdQueryTdiHandle(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG QueryMode,\n    _Out_ PHANDLE TdiHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdQueryFormatTdiDeviceName(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG QueryMode,\n    _Outptr_ PPH_STRING* TdiDeviceName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdQueryAddress(\n    _In_ HANDLE SocketHandle,\n    _In_ BOOLEAN Remote,\n    _Out_ PSOCKADDR_STORAGE Address\n    );\n\n// Address formatting flags\n#define PH_AFD_ADDRESS_SIMPLIFY 0x01 // Print addresses as human-readable\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAfdQueryFormatAddress(\n    _In_ HANDLE SocketHandle,\n    _In_ BOOLEAN Remote,\n    _Out_ PPH_STRING *AddressString,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatSocketState(\n    _In_ SOCKET_STATE SocketState\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatSocketType(\n    _In_ LONG SocketType\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatAddressFamily(\n    _In_ LONG AddressFamily\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatProtocol(\n    _In_ LONG AddressFamily,\n    _In_ LONG Protocol\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatProviderFlags(\n    _In_ ULONG ProviderFlags\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatServiceFlags(\n    _In_ ULONG ServiceFlags\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatCreationFlags(\n    _In_ ULONG CreationFlags\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatSharedInfoFlags(\n    _In_ PSOCK_SHARED_INFO SharedInfo\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatGroupType(\n    _In_ AFD_GROUP_TYPE GroupType\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatProtectionLevel(\n    _In_ ULONG ProtectionLevel\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatMtuDiscoveryMode(\n    _In_ ULONG MtuDiscover\n    );\n\ntypedef enum _TCPSTATE TCPSTATE;\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatTcpState(\n    _In_ TCPSTATE TcpState\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhAfdFormatInterfaceOption(\n    _In_ ULONG Interface\n    );\n\n_Maybenull_\nPPH_STRING\nNTAPI\nPhAfdFormatSocketBestName(\n    _In_ HANDLE SocketHandle\n    );\n\nEXTERN_C_END\n\n#endif // _PH_PHAFD_H\n"
  },
  {
    "path": "phlib/include/phbase.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2016-2023\n *\n */\n\n#ifndef _PH_PHBASE_H\n#define _PH_PHBASE_H\n\n#ifndef PHLIB_NO_DEFAULT_LIB\n#pragma comment(lib, \"ntdll.lib\")\n#pragma comment(lib, \"bcrypt.lib\")\n#pragma comment(lib, \"comctl32.lib\")\n#pragma comment(lib, \"winsta.lib\")\n#endif\n\n#if !defined(_PHLIB_)\n#define PHLIBAPI __declspec(dllimport)\n#else\n#define PHLIBAPI\n#endif\n\n#ifdef __clang__\n#define PH_CLANG_STRINGIFYX(x)         #x\n#define PH_CLANG_STRINGIFY(x)          PH_CLANG_STRINGIFYX(x)\n#define PH_CLANG_DIAGNOSTIC_PUSH()     _Pragma(\"clang diagnostic push\")\n#define PH_CLANG_DIAGNOSTIC_IGNORED(x) _Pragma(PH_CLANG_STRINGIFY(clang diagnostic ignored x))\n#define PH_CLANG_DIAGNOSTIC_POP()      _Pragma(\"clang diagnostic pop\")\n#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L\n#define typeof __typeof__\n#endif\n#else\n#define PH_CLANG_DIAGNOSTIC_PUSH()\n#define PH_CLANG_DIAGNOSTIC_IGNORED(x)\n#define PH_CLANG_DIAGNOSTIC_POP()\n#endif\n\n#include <phnt_windows.h>\n#include <phnt.h>\n#include <phsup.h>\n#include <ref.h>\n#include <queuedlock.h>\n#include <phconfig.h>\n#include <phbasesup.h>\n#include <phdata.h>\n\n#endif\n"
  },
  {
    "path": "phlib/include/phbasesup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_PHBASESUP_H\n#define _PH_PHBASESUP_H\n\nEXTERN_C_START\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhBaseInitialization(\n    VOID\n    );\n\n//\n// Threads\n//\n\n#ifdef DEBUG\ntypedef struct _PH_AUTO_POOL *PPH_AUTO_POOL;\n\ntypedef struct _PHP_BASE_THREAD_DBG\n{\n    CLIENT_ID ClientId;\n    LIST_ENTRY ListEntry;\n    PVOID StartAddress;\n    PVOID Parameter;\n\n    PPH_AUTO_POOL CurrentAutoPool;\n} PHP_BASE_THREAD_DBG, *PPHP_BASE_THREAD_DBG;\n\nextern ULONG PhDbgThreadDbgTlsIndex;\nextern LIST_ENTRY PhDbgThreadListHead;\nextern PH_QUEUED_LOCK PhDbgThreadListLock;\n#endif\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateUserThread(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG CreateFlags,\n    _In_opt_ SIZE_T ZeroBits,\n    _In_opt_ SIZE_T StackSize,\n    _In_opt_ SIZE_T MaximumStackSize,\n    _In_ PUSER_THREAD_START_ROUTINE StartRoutine,\n    _In_opt_ PVOID Argument,\n    _Out_opt_ PHANDLE ThreadHandle,\n    _Out_opt_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhCreateThread(\n    _In_opt_ SIZE_T StackSize,\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateThreadEx(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateThread2(\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueueUserWorkItem(\n    _In_ PUSER_THREAD_START_ROUTINE StartRoutine,\n    _In_opt_ PVOID Argument\n    );\n\n//\n// Misc. system\n//\n\nPHLIBAPI\nULONG64\nNTAPI\nPhReadTimeStampCounter(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhQueryPerformanceCounter(\n    _Out_ PLARGE_INTEGER PerformanceCounter\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhQueryPerformanceFrequency(\n    _Out_ PLARGE_INTEGER PerformanceFrequency\n    );\n\nFORCEINLINE\nULONGLONG\nNTAPI\nPhReadPerformanceCounter(\n    VOID\n    )\n{\n    LARGE_INTEGER counter;\n    PhQueryPerformanceCounter(&counter);\n    return (ULONGLONG)counter.QuadPart;\n}\n\nFORCEINLINE\nULONGLONG\nNTAPI\nPhReadPerformanceFrequency(\n    VOID\n    )\n{\n    LARGE_INTEGER counter;\n    PhQueryPerformanceFrequency(&counter);\n    return (ULONGLONG)counter.QuadPart;\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhQueryInterruptTime(\n    _Out_ PLARGE_INTEGER InterruptTime\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhQuerySystemTime(\n    _Out_ PLARGE_INTEGER SystemTime\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryTimeZoneBias(\n    _Out_ PLARGE_INTEGER TimeZoneBias\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSystemTimeToLocalTime(\n    _In_ PLARGE_INTEGER SystemTime,\n    _Out_ PLARGE_INTEGER LocalTime\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLocalTimeToSystemTime(\n    _In_ PLARGE_INTEGER LocalTime,\n    _Out_ PLARGE_INTEGER SystemTime\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhTimeToSecondsSince1980(\n    _In_ PLARGE_INTEGER Time,\n    _Out_ PULONG ElapsedSeconds\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhTimeToSecondsSince1970(\n    _In_ PLARGE_INTEGER Time,\n    _Out_ PULONG ElapsedSeconds\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSecondsSince1980ToTime(\n    _In_ ULONG ElapsedSeconds,\n    _Out_ PLARGE_INTEGER Time\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSecondsSince1970ToTime(\n    _In_ ULONG ElapsedSeconds,\n    _Out_ PLARGE_INTEGER Time\n    );\n\n//\n// Heap\n//\n\n_May_raise_\n_Post_writable_byte_size_(Size)\nPHLIBAPI\nDECLSPEC_ALLOCATOR\nDECLSPEC_NOALIAS\nDECLSPEC_RESTRICT\nPVOID\nNTAPI\nPhAllocate(\n    _In_ SIZE_T Size\n    );\n\n_Must_inspect_result_\n_Ret_maybenull_\n_When_(return != NULL, _Post_writable_byte_size_(Size))\n_Success_(return != NULL)\nPHLIBAPI\nDECLSPEC_ALLOCATOR\nDECLSPEC_NOALIAS\nDECLSPEC_RESTRICT\nPVOID\nNTAPI\nPhAllocateSafe(\n    _In_ SIZE_T Size\n    );\n\n_Must_inspect_result_\n_Ret_maybenull_\n_When_(return != NULL, _Post_writable_byte_size_(Size))\n_Success_(return != NULL)\nPHLIBAPI\nDECLSPEC_ALLOCATOR\nDECLSPEC_NOALIAS\nDECLSPEC_RESTRICT\nPVOID\nNTAPI\nPhAllocateExSafe(\n    _In_ SIZE_T Size,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFree(\n    _In_opt_ _Frees_ptr_opt_ _Post_invalid_ PVOID Memory\n    );\n\n_May_raise_\n_Ret_maybenull_\n_When_(Size == 0, _Post_null_)\n_When_(return != NULL, _Post_writable_byte_size_(Size))\n_Success_(return != NULL)\nPHLIBAPI\nDECLSPEC_ALLOCATOR\nDECLSPEC_NOALIAS\nDECLSPEC_RESTRICT\nPVOID\nNTAPI\nPhReAllocate(\n    _In_opt_ _Frees_ptr_opt_ PVOID Memory,\n    _In_ SIZE_T Size\n    );\n\n_Must_inspect_result_\n_Ret_maybenull_\n_When_(return != NULL, _Post_writable_byte_size_(Size))\n_Success_(return != NULL)\nPHLIBAPI\nDECLSPEC_ALLOCATOR\nDECLSPEC_NOALIAS\nDECLSPEC_RESTRICT\nPVOID\nNTAPI\nPhReAllocateSafe(\n    _In_opt_ _Frees_ptr_opt_ PVOID Memory,\n    _In_ SIZE_T Size\n    );\n\nPHLIBAPI\nSIZE_T\nNTAPI\nPhSizeHeap(\n    _In_ PVOID Memory\n    );\n\n_Must_inspect_result_\n_Ret_maybenull_\n_When_(return != NULL, _Post_writable_byte_size_(Size))\n_Success_(return != NULL)\nPHLIBAPI\nDECLSPEC_ALLOCATOR\nDECLSPEC_NOALIAS\nDECLSPEC_RESTRICT\nPVOID\nNTAPI\nPhAllocatePage(\n    _In_ SIZE_T Size,\n    _Out_opt_ PSIZE_T NewSize\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreePage(\n    _In_opt_ _Frees_ptr_opt_ _Post_invalid_ PVOID Memory\n    );\n\nFORCEINLINE\nPVOID\nPhAllocatePageZero(\n    _In_ SIZE_T Size\n    )\n{\n    PVOID buffer;\n\n    if (buffer = PhAllocatePage(Size, NULL))\n    {\n        memset(buffer, 0, Size);\n        return buffer;\n    }\n\n    return NULL;\n}\n\n_Must_inspect_result_\n_Ret_maybenull_\n_When_(return != NULL, _Post_writable_byte_size_(Size))\n_Success_(return != NULL)\nPHLIBAPI\nDECLSPEC_ALLOCATOR\nDECLSPEC_NOALIAS\nDECLSPEC_RESTRICT\nPVOID\nNTAPI\nPhAllocatePageAligned(\n    _In_ SIZE_T Size,\n    _In_ SIZE_T Alignment\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreePageAligned(\n    _In_opt_ _Frees_ptr_opt_ _Post_invalid_ PVOID Memory\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAllocateVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Outptr_result_bytebuffer_(AllocationSize) PVOID* BaseAddress,\n    _In_ SIZE_T AllocationSize,\n    _In_ ULONG AllocationType,\n    _In_ ULONG Protection\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFreeVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG FreeType\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhProtectVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize,\n    _In_ ULONG NewProtection,\n    _Out_opt_ PULONG OldProtection\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhReadVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_reads_bytes_(NumberOfBytesToWrite) PVOID Buffer,\n    _In_ SIZE_T NumberOfBytesToWrite,\n    _Out_opt_ PSIZE_T NumberOfBytesWritten\n    );\n\nFORCEINLINE\nPVOID\nPhAllocateCopy(\n    _In_ PVOID Data,\n    _In_ SIZE_T Size\n    )\n{\n    PVOID copy;\n\n    copy = PhAllocate(Size);\n    memcpy(copy, Data, Size);\n\n    return copy;\n}\n\nFORCEINLINE\nPVOID\nPhAllocateZero(\n    _In_ SIZE_T Size\n    )\n{\n    PVOID buffer;\n\n    buffer = PhAllocate(Size);\n    memset(buffer, 0, Size);\n\n    return buffer;\n}\n\nFORCEINLINE\nPVOID\nPhAllocateZeroSafe(\n    _In_ SIZE_T Size\n    )\n{\n    PVOID buffer;\n\n    if (buffer = PhAllocateSafe(Size))\n    {\n        memset(buffer, 0, Size);\n        return buffer;\n    }\n\n    return NULL;\n}\n\nFORCEINLINE\nPVOID\nPhReAllocateZeroSafe(\n    _In_opt_ PVOID Memory,\n    _In_ SIZE_T Size\n    )\n{\n    PVOID buffer;\n\n    if (buffer = PhReAllocateSafe(Memory, Size))\n    {\n        memset(buffer, 0, Size);\n        return buffer;\n    }\n\n    return NULL;\n}\n\n#define PhAllocateStack(Size) _malloca(Size)\n\n#define PhFreeStack(Memory) _freea(Memory)\n\n//\n// Singly linked list\n//\n\n// rev from RtlInitializeSListHead (dmex)\n/**\n * The PhInitializeSListHead function initializes a sequenced singly linked listhead.\n *\n * \\param ListHead A pointer to a sequenced singly linked listhead.\n */\nFORCEINLINE\nVOID\nNTAPI\nPhInitializeSListHead(\n    _Out_ PSLIST_HEADER ListHead\n    )\n{\n#if defined(PHNT_NATIVE_SLIST)\n    RtlInitializeSListHead(ListHead);\n#else\n    if (IS_ALIGNED(ListHead, MEMORY_ALLOCATION_ALIGNMENT))\n        memset(ListHead, 0, sizeof(SLIST_HEADER));\n    else\n        PhRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);\n#endif\n}\n\n// rev from RtlQueryDepthSList (dmex)\n/**\n * The PhQueryDepthSList function queries the current number of entries contained in a sequenced single linked list.\n *\n * \\param ListHead A pointer to a sequenced singly linked listhead.\n * \\return The current number of entries in the sequenced singly linked list is returned as the function value.\n */\nFORCEINLINE\nUSHORT\nNTAPI\nPhQueryDepthSList(\n    _In_ PSLIST_HEADER ListHead\n    )\n{\n#if defined(PHNT_NATIVE_SLIST)\n    return RtlQueryDepthSList(ListHead);\n#else\n#ifdef _M_X64\n    return (USHORT)ListHead->HeaderX64.Depth;\n#elif _M_ARM64\n    return (USHORT)ListHead->HeaderArm64.Depth;\n#else\n    return ListHead->Depth;\n#endif\n#endif\n}\n\n//\n// Event\n//\n\n#define PH_EVENT_SET 0x1\n#define PH_EVENT_SET_SHIFT 0\n#define PH_EVENT_REFCOUNT_SHIFT 1\n#define PH_EVENT_REFCOUNT_INC 0x2\n#define PH_EVENT_REFCOUNT_MASK (((ULONG_PTR)1 << 15) - 1)\n\n/**\n * A fast event object.\n *\n * \\remarks This event object does not use a kernel event object until necessary, and frees the\n * object automatically when it is no longer needed.\n */\ntypedef struct _PH_EVENT\n{\n    union\n    {\n        ULONG_PTR Value;\n        struct\n        {\n            USHORT Set : 1;\n            USHORT RefCount : 15;\n            UCHAR Reserved;\n            UCHAR AvailableForUse;\n#ifdef _WIN64\n            ULONG Spare;\n#endif\n        };\n    };\n    HANDLE EventHandle;\n} PH_EVENT, *PPH_EVENT;\n\n#define PH_EVENT_INIT { { PH_EVENT_REFCOUNT_INC }, NULL }\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfInitializeEvent(\n    _Out_ PPH_EVENT Event\n    );\n\n#define PhSetEvent PhfSetEvent\nPHLIBAPI\nVOID\nFASTCALL\nPhfSetEvent(\n    _Inout_ PPH_EVENT Event\n    );\n\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfWaitForEvent(\n    _Inout_ PPH_EVENT Event,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nFORCEINLINE\nBOOLEAN\nPhWaitForEvent(\n    _Inout_ PPH_EVENT Event,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    if (Event->Set)\n        return TRUE;\n\n    return PhfWaitForEvent(Event, Timeout);\n}\n\n#define PhResetEvent PhfResetEvent\nPHLIBAPI\nVOID\nFASTCALL\nPhfResetEvent(\n    _Inout_ PPH_EVENT Event\n    );\n\nFORCEINLINE\nVOID\nPhInitializeEvent(\n    _Out_ PPH_EVENT Event\n    )\n{\n    WriteULongPtrRelease(&Event->Value, PH_EVENT_REFCOUNT_INC);\n    WritePointerRelease(&Event->EventHandle, UlongToPtr(0));\n}\n\n/**\n * Determines whether an event object is set.\n *\n * \\param Event A pointer to an event object.\n *\n * \\return TRUE if the event object is set, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhTestEvent(\n    _In_ PPH_EVENT Event\n    )\n{\n    return (BOOLEAN)Event->Set;\n}\n\n//\n// Barrier\n//\n\n#define PH_BARRIER_COUNT_SHIFT 0\n#define PH_BARRIER_COUNT_MASK (((LONG_PTR)1 << (sizeof(ULONG_PTR) * 8 / 2 - 1)) - 1)\n#define PH_BARRIER_COUNT_INC ((LONG_PTR)1 << PH_BARRIER_COUNT_SHIFT)\n#define PH_BARRIER_TARGET_SHIFT (sizeof(ULONG_PTR) * 8 / 2)\n#define PH_BARRIER_TARGET_MASK (((LONG_PTR)1 << (sizeof(ULONG_PTR) * 8 / 2 - 1)) - 1)\n#define PH_BARRIER_TARGET_INC ((LONG_PTR)1 << PH_BARRIER_TARGET_SHIFT)\n#define PH_BARRIER_WAKING ((LONG_PTR)1 << (sizeof(ULONG_PTR) * 8 - 1))\n\n#define PH_BARRIER_MASTER 1\n#define PH_BARRIER_SLAVE 2\n#define PH_BARRIER_OBSERVER 3\n\ntypedef struct _PH_BARRIER\n{\n    ULONG_PTR Value;\n    PH_WAKE_EVENT WakeEvent;\n} PH_BARRIER, *PPH_BARRIER;\n\n#define PH_BARRIER_INIT(Target) { (ULONG_PTR)(Target) << PH_BARRIER_TARGET_SHIFT, PH_WAKE_EVENT_INIT }\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfInitializeBarrier(\n    _Out_ PPH_BARRIER Barrier,\n    _In_ ULONG_PTR Target\n    );\n\n#define PhWaitForBarrier PhfWaitForBarrier\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfWaitForBarrier(\n    _Inout_ PPH_BARRIER Barrier,\n    _In_ BOOLEAN Spin\n    );\n\nFORCEINLINE\nVOID\nPhInitializeBarrier(\n    _Out_ PPH_BARRIER Barrier,\n    _In_ ULONG_PTR Target\n    )\n{\n    Barrier->Value = Target << PH_BARRIER_TARGET_SHIFT;\n    PhInitializeQueuedLock(&Barrier->WakeEvent);\n}\n\n//\n// Rundown protection\n//\n\n#define PH_RUNDOWN_ACTIVE 0x1\n#define PH_RUNDOWN_REF_SHIFT 1\n#define PH_RUNDOWN_REF_INC 0x2\n\ntypedef struct _PH_RUNDOWN_PROTECT\n{\n    ULONG_PTR Value;\n} PH_RUNDOWN_PROTECT, *PPH_RUNDOWN_PROTECT;\n\n#define PH_RUNDOWN_PROTECT_INIT { 0 }\n\ntypedef struct _PH_RUNDOWN_WAIT_BLOCK\n{\n    ULONG_PTR Count;\n    PH_EVENT WakeEvent;\n} PH_RUNDOWN_WAIT_BLOCK, *PPH_RUNDOWN_WAIT_BLOCK;\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfInitializeRundownProtection(\n    _Out_ PPH_RUNDOWN_PROTECT Protection\n    );\n\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfAcquireRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    );\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    );\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfWaitForRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    );\n\nFORCEINLINE\nVOID\nPhInitializeRundownProtection(\n    _Out_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    Protection->Value = 0;\n}\n\nFORCEINLINE\nBOOLEAN\nPhAcquireRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    value = ReadULongPtrAcquire(&Protection->Value) & ~PH_RUNDOWN_ACTIVE; // fail fast path when rundown is active\n\n    if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&Protection->Value,\n        (PVOID)(value + PH_RUNDOWN_REF_INC),\n        (PVOID)value\n        ) == value)\n    {\n        return TRUE;\n    }\n    else\n    {\n        return PhfAcquireRundownProtection(Protection);\n    }\n}\n\nFORCEINLINE\nVOID\nPhReleaseRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    value = ReadULongPtrAcquire(&Protection->Value) & ~PH_RUNDOWN_ACTIVE; // Fail fast path when rundown is active\n\n    if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&Protection->Value,\n        (PVOID)(value - PH_RUNDOWN_REF_INC),\n        (PVOID)value\n        ) != value)\n    {\n        PhfReleaseRundownProtection(Protection);\n    }\n}\n\nFORCEINLINE\nVOID\nPhWaitForRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    value = (ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&Protection->Value,\n        (PVOID)PH_RUNDOWN_ACTIVE,\n        (PVOID)0\n        );\n\n    if (value != 0 && value != PH_RUNDOWN_ACTIVE)\n        PhfWaitForRundownProtection(Protection);\n}\n\n//\n// One-time initialization\n//\n\n#define PH_INITONCE_SHIFT 31\n#define PH_INITONCE_INITIALIZING (0x1 << PH_INITONCE_SHIFT)\n#define PH_INITONCE_INITIALIZING_SHIFT PH_INITONCE_SHIFT\n\ntypedef struct _PH_INITONCE\n{\n    PH_EVENT Event;\n} PH_INITONCE, *PPH_INITONCE;\n\nC_ASSERT(PH_INITONCE_SHIFT >= FIELD_OFFSET(PH_EVENT, AvailableForUse) * 8);\n\n#define PH_INITONCE_INIT { PH_EVENT_INIT }\n\n#define PhInitializeInitOnce PhfInitializeInitOnce\nPHLIBAPI\nVOID\nFASTCALL\nPhfInitializeInitOnce(\n    _Out_ PPH_INITONCE InitOnce\n    );\n\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfBeginInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    );\n\n#define PhEndInitOnce PhfEndInitOnce\nPHLIBAPI\nVOID\nFASTCALL\nPhfEndInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    );\n\nFORCEINLINE\nBOOLEAN\nPhBeginInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    )\n{\n    if (InitOnce->Event.Set)\n        return FALSE;\n    else\n        return PhfBeginInitOnce(InitOnce);\n}\n\nFORCEINLINE\nBOOLEAN\nPhTestInitOnce(\n    _In_ PPH_INITONCE InitOnce\n    )\n{\n    return (BOOLEAN)InitOnce->Event.Set;\n}\n\n//\n// String\n//\n\nPHLIBAPI\nSIZE_T\nNTAPI\nPhCountStringZ(\n    _In_ PCWSTR String\n    );\n\nFORCEINLINE\nSIZE_T\nPhCountBytesZ(\n    _In_ PCSTR String\n    )\n{\n    return (SIZE_T)strlen(String);\n}\n\n_Ret_notnull_\n_Post_z_\nPHLIBAPI\nPSTR\nNTAPI\nPhDuplicateBytesZ(\n    _In_ PCSTR String\n    );\n\n_Ret_maybenull_\n_Post_z_\nPHLIBAPI\nPSTR\nNTAPI\nPhDuplicateBytesZSafe(\n    _In_ PCSTR String\n    );\n\n_Ret_notnull_\n_Post_z_\nPHLIBAPI\nPWSTR\nNTAPI\nPhDuplicateStringZ(\n    _In_ PCWSTR String\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCopyBytesZ(\n    _In_ PCSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCopyStringZ(\n    _In_ PCWSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCopyStringZFromBytes(\n    _In_ PCSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCopyStringZFromMultiByte(\n    _In_ PCSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCopyStringZFromUtf8(\n    _In_ PCSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    );\n\nFORCEINLINE\nBOOLEAN\nPhAreCharactersDifferent(\n    _In_ WCHAR Char1,\n    _In_ WCHAR Char2\n    )\n{\n    WCHAR d;\n\n    d = Char1 ^ Char2;\n\n    // We ignore bits beyond bit 5 because bit 6 is the case bit, and also we\n    // don't support localization here.\n    if (d & 0x1f)\n        return TRUE;\n\n    return FALSE;\n}\n\nFORCEINLINE\nBOOLEAN\nPhIsDigitCharacter(\n    _In_ WCHAR Char\n    )\n{\n    return (USHORT)(Char - '0') < 10;\n}\n\nFORCEINLINE\nWCHAR\nNTAPI_INLINE\nPhUpcaseUnicodeChar(\n    _In_ WCHAR SourceCharacter\n    )\n{\n    WCHAR c;\n\n    //c = towupper(c);\n    //c = __ascii_towupper(c);\n    c = RtlUpcaseUnicodeChar(SourceCharacter);\n\n    return c;\n}\n\nFORCEINLINE\nWCHAR\nNTAPI_INLINE\nPhDowncaseUnicodeChar(\n    _In_ WCHAR SourceCharacter\n    )\n{\n    WCHAR c;\n\n    c = RtlDowncaseUnicodeChar(SourceCharacter);\n\n    return c;\n}\n\n/**\n * Tests if a character is whitespace.\n *\n * \\param c The character to test.\n * \\return TRUE if the character is whitespace (space, tab, CR, LF, etc.); otherwise, FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhIsWhiteSpaceUnicodeChar(\n    _In_ WCHAR SourceCharacter\n    )\n{\n    return (\n        SourceCharacter == L' ' ||\n        SourceCharacter == L'\\t' ||\n        SourceCharacter == L'\\r' ||\n        SourceCharacter == L'\\n' ||\n        SourceCharacter == L'\\v' ||\n        SourceCharacter == L'\\f'\n        );\n}\n\n/**\n * Tests if a character is a unicode control or formatting character.\n *\n * Detects bidirectional overrides (RTLO, etc.), zero-width characters, and\n * control characters (including tab, CR, LF).\n *\n * \\param c The character to test.\n * \\return TRUE if the character is a control/formatting character; otherwise, FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhIsControlOrFormattingUnicodeChar(\n    _In_ WCHAR c\n    )\n{\n    // C0 and C1 control characters\n    if (c < 0x20 || (c >= 0x7F && c <= 0x9F)) // TAB, CR, LF\n        return TRUE;\n    \n    // Bidirectional format characters\n    if (c >= 0x202A && c <= 0x202E)\n        return TRUE;\n    \n    // Direction mark characters\n    if (c == 0x200E || c == 0x200F)\n        return TRUE;\n    \n    // Zero-width and invisible characters\n    if (c >= 0x200B && c <= 0x200D) // ZWSP, ZWNJ, ZWJ\n        return TRUE;\n\n    // Zero-width no-break space (BOM)\n    if (c == 0xFEFF) \n        return TRUE;\n    \n    return FALSE;\n}\n\nFORCEINLINE\nLONG\nPhCompareBytesZ(\n    _In_ PCSTR String1,\n    _In_ PCSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (IgnoreCase)\n        return _stricmp(String1, String2);\n    else\n        return strcmp(String1, String2);\n}\n\nFORCEINLINE\nBOOLEAN\nPhEqualBytesZ(\n    _In_ PCSTR String1,\n    _In_ PCSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (IgnoreCase)\n        return _stricmp(String1, String2) == 0;\n    else\n        return strcmp(String1, String2) == 0;\n}\n\nFORCEINLINE\nBOOLEAN\nPhEqualStringZ(\n    _In_ PCWSTR String1,\n    _In_ PCWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (IgnoreCase)\n    {\n        // wcsicmp is very expensive, so we do a quick check for negatives first.\n        if (PhAreCharactersDifferent(String1[0], String2[0]))\n            return FALSE;\n\n        return _wcsicmp(String1, String2) == 0;\n    }\n    else\n    {\n        return wcscmp(String1, String2) == 0;\n    }\n}\n\ntypedef struct _PH_STRINGREF\n{\n    /** The length, in bytes, of the string. */\n    SIZE_T Length;\n    /** The buffer containing the contents of the string. */\n    PWCH Buffer;\n} PH_STRINGREF, *PPH_STRINGREF;\ntypedef const PH_STRINGREF* PCPH_STRINGREF;\n\ntypedef struct _PH_BYTESREF\n{\n    /** The length, in bytes, of the string. */\n    SIZE_T Length;\n    /** The buffer containing the contents of the string. */\n    PCH Buffer;\n} PH_BYTESREF, *PPH_BYTESREF;\ntypedef const PH_BYTESREF* PCPH_BYTESREF;\n\ntypedef struct _PH_RELATIVE_BYTESREF\n{\n    /** The length, in bytes, of the string. */\n    ULONG Length;\n    /** A user-defined offset. */\n    ULONG Offset;\n} PH_RELATIVE_BYTESREF, *PPH_RELATIVE_BYTESREF, PH_RELATIVE_STRINGREF, *PPH_RELATIVE_STRINGREF;\n\n#define PH_STRINGREF_INIT(String) { sizeof(String) - sizeof(UNICODE_NULL), RTL_CONST_CAST(PWCH)(String) }\n#define PH_BYTESREF_INIT(String) { sizeof(String) - sizeof(ANSI_NULL), RTL_CONST_CAST(PCH)(String) }\n\nFORCEINLINE\nVOID\nPhInitializeStringRef(\n    _Out_ PPH_STRINGREF String,\n    _In_ PCWSTR Buffer\n    )\n{\n    String->Length = wcslen(Buffer) * sizeof(WCHAR);\n    String->Buffer = (PWCH)Buffer;\n}\n\nFORCEINLINE\nVOID\nPhInitializeStringRefLongHint(\n    _Out_ PPH_STRINGREF String,\n    _In_ PCWSTR Buffer\n    )\n{\n    String->Length = PhCountStringZ(Buffer) * sizeof(WCHAR);\n    String->Buffer = (PWCH)Buffer;\n}\n\nFORCEINLINE\nVOID\nPhInitializeBytesRef(\n    _Out_ PPH_BYTESREF Bytes,\n    _In_ PCSTR Buffer\n    )\n{\n    Bytes->Length = strlen(Buffer) * sizeof(CHAR);\n    Bytes->Buffer = (PCH)Buffer;\n}\n\nFORCEINLINE\nVOID\nPhInitializeEmptyStringRef(\n    _Out_ PPH_STRINGREF String\n    )\n{\n    String->Length = 0;\n    String->Buffer = NULL;\n}\n\nFORCEINLINE\nVOID\nPhInitializeEmptyBytesRef(\n    _Out_ PPH_BYTESREF String\n    )\n{\n    String->Length = 0;\n    String->Buffer = NULL;\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhInitializeBufferStringRef(\n    _Out_ PPH_STRINGREF String,\n    _Writable_bytes_(Length) _When_(Length != 0, _Notnull_) PWCH Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    memset(String, 0, sizeof(PH_STRINGREF));\n    String->Length = Length;\n    String->Buffer = Buffer;\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhInitializeBufferBytesRef(\n    _Out_ PPH_BYTESREF String,\n    _Writable_bytes_(Length) _When_(Length != 0, _Notnull_) PCH Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    memset(String, 0, sizeof(PH_BYTESREF));\n    String->Length = Length;\n    String->Buffer = Buffer;\n}\n\nFORCEINLINE\nBOOLEAN\nPhStringRefToUnicodeString(\n    _In_ PCPH_STRINGREF String,\n    _Out_ PUNICODE_STRING UnicodeString\n    )\n{\n    memset(UnicodeString, 0, sizeof(UNICODE_STRING));\n    UnicodeString->Length = (USHORT)String->Length;\n    UnicodeString->MaximumLength = (USHORT)String->Length + sizeof(UNICODE_NULL);\n    UnicodeString->Buffer = String->Buffer;\n\n    return String->Length <= UNICODE_STRING_MAX_BYTES;\n}\n\nFORCEINLINE\nVOID\nPhUnicodeStringToStringRef(\n    _In_ PCUNICODE_STRING UnicodeString,\n    _Out_ PPH_STRINGREF String\n    )\n{\n    memset(String, 0, sizeof(PH_STRINGREF));\n    String->Length = UnicodeString->Length;\n    String->Buffer = UnicodeString->Buffer;\n}\n\nFORCEINLINE\nLONG\nPhCompareStringZ(\n    _In_ PCWSTR String1,\n    _In_ PCWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (IgnoreCase)\n        return _wcsicmp(String1, String2);\n    else\n        return wcscmp(String1, String2);\n}\n\nPHLIBAPI\nLONG\nNTAPI\nPhCompareStringZNatural(\n    _In_ PCWSTR A,\n    _In_ PCWSTR B,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhCompareStringRef(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEqualStringRef(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nULONG_PTR\nNTAPI\nPhFindCharInStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ WCHAR Character,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nULONG_PTR\nNTAPI\nPhFindLastCharInStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ WCHAR Character,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nULONG_PTR\nNTAPI\nPhFindStringInStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ PCPH_STRINGREF SubString,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nFORCEINLINE\nULONG_PTR\nPhFindStringInStringRefZ(\n    _In_ PCPH_STRINGREF String,\n    _In_ PCWSTR SubString,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF sr2;\n\n    PhInitializeStringRef(&sr2, SubString);\n\n    return PhFindStringInStringRef(String, &sr2, IgnoreCase);\n}\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSplitStringRefAtChar(\n    _In_ PCPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSplitStringRefAtLastChar(\n    _In_ PCPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSplitStringRefAtString(\n    _In_ PCPH_STRINGREF Input,\n    _In_ PCPH_STRINGREF Separator,\n    _In_ BOOLEAN IgnoreCase,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    );\n\n#define PH_SPLIT_AT_CHAR_SET 0x0 // default\n#define PH_SPLIT_AT_STRING 0x1\n#define PH_SPLIT_AT_RANGE 0x2\n#define PH_SPLIT_CASE_INSENSITIVE 0x1000\n#define PH_SPLIT_COMPLEMENT_CHAR_SET 0x2000\n#define PH_SPLIT_START_AT_END 0x4000\n#define PH_SPLIT_CHAR_SET_IS_UPPERCASE 0x8000\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSplitStringRefEx(\n    _In_ PCPH_STRINGREF Input,\n    _In_ PCPH_STRINGREF Separator,\n    _In_ ULONG Flags,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart,\n    _Out_opt_ PPH_STRINGREF SeparatorPart\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSplitStringRef(\n    _In_ PCPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PVOID **Strings,\n    _Out_ PULONG NumberOfStrings\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeStringArray(\n    _In_ PVOID *Strings,\n    _In_ ULONG NumberOfStrings\n    );\n\n#define PH_TRIM_START_ONLY 0x1\n#define PH_TRIM_END_ONLY 0x2\n\nPHLIBAPI\nVOID\nNTAPI\nPhTrimStringRef(\n    _Inout_ PPH_STRINGREF String,\n    _In_ PCPH_STRINGREF CharSet,\n    _In_ ULONG Flags\n    );\n\nFORCEINLINE\nLONG\nPhCompareStringRef2(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF sr2;\n\n    PhInitializeStringRef(&sr2, String2);\n\n    return PhCompareStringRef(String1, &sr2, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhEqualStringRef2(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF sr2;\n\n    PhInitializeStringRef(&sr2, String2);\n\n    return PhEqualStringRef(String1, &sr2, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhStartsWithStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ PCPH_STRINGREF Prefix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF sr;\n\n    sr.Buffer = String->Buffer;\n    sr.Length = Prefix->Length;\n\n    if (String->Length < sr.Length)\n        return FALSE;\n\n    return PhEqualStringRef(&sr, Prefix, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhStartsWithStringRef2(\n    _In_ PCPH_STRINGREF String,\n    _In_ PCWSTR Prefix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF prefix;\n\n    PhInitializeStringRef(&prefix, Prefix);\n\n    return PhStartsWithStringRef(String, &prefix, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhEndsWithStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ PCPH_STRINGREF Suffix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF sr;\n\n    if (Suffix->Length > String->Length)\n        return FALSE;\n\n    sr.Buffer = (PWCH)PTR_ADD_OFFSET(String->Buffer, String->Length - Suffix->Length);\n    sr.Length = Suffix->Length;\n\n    return PhEqualStringRef(&sr, Suffix, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhEndsWithStringRef2(\n    _In_ PCPH_STRINGREF String,\n    _In_ PCWSTR Suffix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF suffix;\n\n    PhInitializeStringRef(&suffix, Suffix);\n\n    return PhEndsWithStringRef(String, &suffix, IgnoreCase);\n}\n\nFORCEINLINE\nVOID\nPhSkipStringRef(\n    _Inout_ PPH_STRINGREF String,\n    _In_ SIZE_T Length\n    )\n{\n    String->Buffer = (PWCH)PTR_ADD_OFFSET(String->Buffer, Length);\n    String->Length -= Length;\n}\n\nFORCEINLINE\nVOID\nPhReverseStringRef(\n    _In_ PCPH_STRINGREF String\n    )\n{\n    SIZE_T i;\n    SIZE_T j;\n    WCHAR t;\n\n    for (i = 0, j = String->Length / sizeof(WCHAR) - 1; i <= j; i++, j--)\n    {\n        t = String->Buffer[i];\n        String->Buffer[i] = String->Buffer[j];\n        String->Buffer[j] = t;\n    }\n}\n\nextern PPH_OBJECT_TYPE PhStringType;\n\n/**\n * A 16-bit string object, which supports UTF-16.\n *\n * \\remarks The \\a Length never includes the null terminator. Every string must have a null\n * terminator at the end, for compatibility reasons. The invariant is:\n * \\code Buffer[Length / sizeof(WCHAR)] = 0 \\endcode\n */\ntypedef struct _PH_STRING\n{\n    // Header\n    union\n    {\n        PH_STRINGREF sr;\n        struct\n        {\n            /** The length, in bytes, of the string. */\n            SIZE_T Length;\n            /** The buffer containing the contents of the string. */\n            PWCH Buffer;\n        };\n    };\n\n    // Data\n    union\n    {\n        WCHAR Data[1];\n        struct\n        {\n            /** Reserved. */\n            ULONG AllocationFlags;\n            /** Reserved. */\n            PVOID Allocation;\n        };\n    };\n} PH_STRING, *PPH_STRING;\n\nextern PPH_STRING PhSharedEmptyString;\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhCreateStringEx(\n    _In_reads_bytes_opt_(Length) PCWCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\n/**\n * Creates a string object from an existing null-terminated string.\n *\n * \\param Buffer A null-terminated Unicode string.\n */\nFORCEINLINE\nPPH_STRING\nNTAPI\nPhCreateString(\n    _In_ PCWSTR Buffer\n    )\n{\n    return PhCreateStringEx(Buffer, PhCountStringZ(Buffer) * sizeof(WCHAR));\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhReferenceEmptyString(\n    VOID\n    );\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhCreateString2(\n    _In_ PCPH_STRINGREF String\n    )\n{\n    if (String->Length == 0)\n        return PhReferenceEmptyString();\n\n    return PhCreateStringEx(String->Buffer, String->Length);\n}\n\n/**\n * Creates a string object from a null-terminated string.\n *\n * \\param String A null-terminated Unicode string.\n */\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhCreateStringZ(\n    _In_z_ PCWSTR String\n    )\n{\n    PH_STRINGREF string;\n\n    string.Length = wcslen(String) * sizeof(WCHAR);\n    string.Buffer = (PWSTR)String;\n    //PhInitializeStringRef(&string, (PWSTR)String);\n\n    return PhCreateString2(&string);\n}\n\n/**\n * Creates a string object from a null-terminated string up to a maximum length.\n *\n * \\param String A null-terminated Unicode string.\n * \\param MaximumLength The maximum length, in bytes, of the string.\n */\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhCreateStringZ2(\n    _In_reads_or_z_(MaximumLength / sizeof(WCHAR)) PCWSTR String,\n    _In_ SIZE_T MaximumLength\n    )\n{\n    PH_STRINGREF string;\n\n    string.Length = wcsnlen(String, MaximumLength / sizeof(WCHAR)) * sizeof(WCHAR);\n    string.Buffer = (PWSTR)String;\n\n    return PhCreateString2(&string);\n}\n\n#define PH_STRING_TRIM_START_ONLY PH_TRIM_START_ONLY\n#define PH_STRING_TRIM_END_ONLY   PH_TRIM_END_ONLY\n#define PH_STRING_TRIM_MASK       (PH_STRING_TRIM_START_ONLY | PH_STRING_TRIM_END_ONLY)\n#define PH_STRING_UPPER_CASE      0x4\n#define PH_STRING_LOWER_CASE      0x8\n#define PH_STRING_CASE_MASK       (PH_STRING_UPPER_CASE | PH_STRING_LOWER_CASE)\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhCreateString3(\n    _In_ PCPH_STRINGREF String,\n    _In_ ULONG Flags,\n    _In_opt_ PCPH_STRINGREF TrimCharSet\n    );\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhTrimStringZ(\n    _In_ PCPH_STRINGREF String,\n    _In_ ULONG Flags,\n    _In_ PCWSTR TrimCharSet\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, TrimCharSet);\n\n    return PhCreateString3(String, Flags, &string);\n}\n\nFORCEINLINE\nVOID\nNTAPI_INLINE\nPhUpperStringRefInto(\n    _Inout_ PPH_STRINGREF Destination,\n    _In_ PCPH_STRINGREF Source\n    )\n{\n    assert(Destination->Length >= Source->Length);\n    SIZE_T numberOfChars = Source->Length / sizeof(WCHAR);\n    for (SIZE_T i = 0; i < numberOfChars; i++)\n        Destination->Buffer[i] = PhUpcaseUnicodeChar(Source->Buffer[i]);\n    Destination->Length = Source->Length;\n}\n\nFORCEINLINE\nVOID\nNTAPI_INLINE\nPhUpperStringRef(\n    _Inout_ PPH_STRINGREF String\n    )\n{\n    PhUpperStringRefInto(String, String);\n}\n\nFORCEINLINE\nVOID\nNTAPI_INLINE\nPhLowerStringRefInto(\n    _Inout_ PPH_STRINGREF Destination,\n    _In_ PCPH_STRINGREF Source\n    )\n{\n    assert(Destination->Length >= Source->Length);\n    SIZE_T numberOfChars = Source->Length / sizeof(WCHAR);\n    for (SIZE_T i = 0; i < numberOfChars; i++)\n        Destination->Buffer[i] = PhDowncaseUnicodeChar(Source->Buffer[i]);\n    Destination->Length = Source->Length;\n}\n\nFORCEINLINE\nVOID\nNTAPI_INLINE\nPhLowerStringRef(\n    _Inout_ PPH_STRINGREF String\n    )\n{\n    PhLowerStringRefInto(String, String);\n}\n\nFORCEINLINE\nVOID\nNTAPI_INLINE\nPhLowerStringZ(\n    _Inout_ PCWSTR String\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, String);\n    PhLowerStringRefInto(&string, &string);\n}\n\nFORCEINLINE\nVOID\nNTAPI_INLINE\nPhLowerStringMaxZ(\n    _In_reads_or_z_(MaximumLength / sizeof(WCHAR)) PCWSTR String,\n    _In_ SIZE_T MaximumLength\n    )\n{\n    PH_STRINGREF string;\n\n    string.Length = wcsnlen(String, MaximumLength / sizeof(WCHAR)) * sizeof(WCHAR);\n    string.Buffer = (PWSTR)String;\n\n    PhLowerStringRefInto(&string, &string);\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhCreateStringFromUnicodeString(\n    _In_ PCUNICODE_STRING UnicodeString\n    )\n{\n    if (UnicodeString->Length == 0)\n        return PhReferenceEmptyString();\n\n    return PhCreateStringEx(UnicodeString->Buffer, UnicodeString->Length);\n}\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStrings(\n    _In_ ULONG Count,\n    ...\n    );\n\n#define PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE 16\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStrings_V(\n    _In_ ULONG Count,\n    _In_ va_list ArgPtr\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStrings2(\n    _In_ PCWSTR String1,\n    _In_ PCWSTR String2\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStringRef2(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStringRef3(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2,\n    _In_ PCPH_STRINGREF String3\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStringRef4(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCPH_STRINGREF String2,\n    _In_ PCPH_STRINGREF String3,\n    _In_ PCPH_STRINGREF String4\n    );\n\nFORCEINLINE\nPPH_STRING\nPhConcatStringRefZ(\n    _In_ PCPH_STRINGREF String1,\n    _In_ PCWSTR String2\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, String2);\n\n    return PhConcatStringRef2(String1, &string);\n}\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatString(\n    _In_ _Printf_format_string_ PCWSTR Format,\n    ...\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatString_V(\n    _In_ _Printf_format_string_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    );\n\n/**\n * Retrieves a pointer to a string object's buffer or returns NULL.\n *\n * \\param String A pointer to a string object.\n *\n * \\return A pointer to the string object's buffer if the supplied pointer is non-NULL, otherwise\n * NULL.\n */\nFORCEINLINE\nPWSTR\nPhGetString(\n    _In_opt_ PPH_STRING String\n    )\n{\n    if (String)\n        return String->Buffer;\n    else\n        return NULL;\n}\n\n/**\n * Retrieves a string reference from a given string object.\n *\n * This function returns a `PH_STRINGREF` structure that references the string\n * contained in the provided `PPH_STRING` object. If the input string object is\n * `NULL`, it initializes and returns an empty `PH_STRINGREF`.\n *\n * \\param String A pointer to a `PPH_STRING` object. This parameter is optional and can be `NULL`.\n * \\return A `PH_STRINGREF` structure that references the string in the provided `PPH_STRING` object,\n *         or an empty `PH_STRINGREF` if the input is `NULL`.\n */\nFORCEINLINE\nPH_STRINGREF\nPhGetStringRef(\n    _In_opt_ PPH_STRING String\n    )\n{\n    PH_STRINGREF sr;\n\n    if (String)\n        sr = String->sr;\n    else\n        PhInitializeEmptyStringRef(&sr);\n\n    return sr;\n}\n\n/**\n * Retrieves the buffer from a PPH_STRINGREF structure or returns an empty string if the input is NULL.\n *\n * This function checks if the provided PPH_STRINGREF structure is not NULL. If it is not NULL, it returns the buffer\n * contained within the structure. If the structure is NULL, it returns an empty string.\n *\n * \\param String A pointer to a PPH_STRINGREF structure. This parameter is optional and can be NULL.\n * \\return A pointer to the buffer contained within the PPH_STRINGREF structure if it is not NULL, otherwise an empty string.\n */\nFORCEINLINE\nPCWSTR\nPhGetStringRefZ(\n    _In_opt_ PCPH_STRINGREF String\n    )\n{\n    if (String)\n        return String->Buffer;\n    else\n        return L\"\";\n}\n\n/**\n * Retrieves a pointer to a string object's buffer or returns an empty string.\n *\n * \\param String A pointer to a string object.\n * \\return A pointer to the string object's buffer if the supplied pointer is non-NULL, otherwise an empty string.\n */\nFORCEINLINE\nPCWSTR\nPhGetStringOrEmpty(\n    _In_opt_ PPH_STRING String\n    )\n{\n    if (String)\n        return String->Buffer;\n    else\n        return L\"\";\n}\n\n/**\n * Retrieves a pointer to a string object's buffer or returns the specified alternative string.\n *\n * \\param String A pointer to a string object.\n * \\param DefaultString The alternative string.\n *\n * \\return A pointer to the string object's buffer if the supplied pointer is non-NULL, otherwise\n * the specified alternative string.\n */\nFORCEINLINE\nPCWSTR\nPhGetStringOrDefault(\n    _In_opt_ PPH_STRING String,\n    _In_ PCWSTR DefaultString\n    )\n{\n    if (String)\n        return String->Buffer;\n    else\n        return DefaultString;\n}\n\n/**\n * Determines whether a string is null or empty.\n *\n * \\param String A pointer to a string object.\n */\n_Success_(return == FALSE)\n_At_(String, _When_(return == FALSE, _Notnull_))\nFORCEINLINE\nBOOLEAN\nPhIsNullOrEmptyString(\n    _In_opt_ PPH_STRING String\n    )\n{\n    if (String == NULL)\n        return TRUE;\n\n    return String->Length == 0;\n}\n\n/**\n * Determines whether a STRINGREF is null or empty.\n *\n * \\param String A pointer to a string object.\n */\n_Success_(return == FALSE)\n_At_(String, _When_(return == FALSE, _Notnull_))\nFORCEINLINE\nBOOLEAN\nPhIsNullOrEmptyStringRef(\n    _In_opt_ PCPH_STRINGREF String\n    )\n{\n    return !(String && String->Length);\n}\n\n/**\n * Tests if a string is null, empty, or starts with whitespace.\n *\n * \\param String The string to test.\n * \\return TRUE if the string is null, empty, or starts with whitespace; otherwise, FALSE.\n */\n#undef PhIsNullOrWhitespaceString\n#define PhIsNullOrWhitespaceString(string) \\\n    ((!(string)) || ((string)->Length == 0) || PhIsWhiteSpaceUnicodeChar((string)->Buffer[0]))\n\n// FORCEINLINE\n// BOOLEAN\n// PhIsNullOrWhitespaceString(\n//     _In_opt_ PPH_STRING String\n//     )\n// {\n//     SIZE_T length;\n//     \n//     if (!String || String->Length == 0)\n//         return TRUE;\n//     \n//     length = String->Length / sizeof(WCHAR);\n//     \n//     // Check first and last character (leading/trailing whitespace)\n//     if (PhIsWhiteSpaceUnicodeChar(String->Buffer[0]) ||\n//         PhIsWhiteSpaceUnicodeChar(String->Buffer[length - 1]))\n//     {\n//         return TRUE;\n//     }\n//     \n//     return FALSE;\n// }\n\n// The MSVC static analyzer can misinterpret the _In_opt_ SAL for String on PhIsNullOrEmptyString and raise C6387.\n// Provide a macro override during analysis to avoid the false positive while preserving semantics.\n#if (defined(_PREFAST_) || defined(_MSC_ANALYSIS))\n#undef PhIsNullOrEmptyString\n#define PhIsNullOrEmptyString(string) \\\n    ((!(string)) || ((string)->Length == 0))\n\n#undef PhIsNullOrEmptyStringRef\n#define PhIsNullOrEmptyStringRef(string) \\\n    ((!(string)) || ((string)->Length == 0))\n#endif\n\n/**\n * Duplicates a string.\n *\n * \\param String A string to duplicate.\n */\nFORCEINLINE\nPPH_STRING\nPhDuplicateString(\n    _In_ PPH_STRING String\n    )\n{\n    return PhCreateStringEx(String->Buffer, String->Length);\n}\n\n/**\n * Compares two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nLONG\nPhCompareString(\n    _In_ PPH_STRING String1,\n    _In_ PPH_STRING String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (IgnoreCase)\n        return PhCompareStringRef(&String1->sr, &String2->sr, IgnoreCase); // faster than wcsicmp\n    else\n        return wcscmp(String1->Buffer, String2->Buffer);\n}\n\n/**\n * Compares two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nLONG\nPhCompareString2(\n    _In_ PPH_STRING String1,\n    _In_ PCWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (IgnoreCase)\n        return PhCompareStringRef2(&String1->sr, String2, IgnoreCase);\n    else\n        return wcscmp(String1->Buffer, String2);\n}\n\n/**\n * Compares two strings, handling NULL strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nLONG\nPhCompareStringWithNull(\n    _In_opt_ PPH_STRING String1,\n    _In_opt_ PPH_STRING String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (String1 && String2)\n    {\n        return PhCompareString(String1, String2, IgnoreCase);\n    }\n    else if (!String1)\n    {\n        return !String2 ? 0 : 1;\n    }\n    else\n    {\n        return -1;\n    }\n}\n\n/**\n * Compares two strings with support for null values and customizable sort order.\n *\n * This function compares two strings, taking into account the possibility of null values and allowing for customizable sort order.\n * If both `String1` and `String2` are not null, the function calls `PhCompareString` to perform the comparison.\n * If `String1` is null and `String2` is not null, the function returns 0 if `String2` is also null, or 1 or -1 based on the specified `Order` (AscendingSortOrder or DescendingSortOrder).\n * If `String1` is not null and `String2` is null, the function returns -1 or 1 based on the specified `Order`.\n *\n * \\param String1 The first string to compare.\n * \\param String2 The second string to compare.\n * \\param Order The sort order to use for the comparison (AscendingSortOrder or DescendingSortOrder).\n * \\param IgnoreCase Specifies whether the comparison should be case-insensitive (TRUE) or case-sensitive (FALSE).\n * \\return Returns a negative value if `String1` is less than `String2`, a positive value if `String1` is greater than `String2`, or 0 if they are equal.\n */\nFORCEINLINE\nLONG\nPhCompareStringWithNullSortOrder(\n    _In_opt_ PPH_STRING String1,\n    _In_opt_ PPH_STRING String2,\n    _In_ PH_SORT_ORDER Order,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (String1 && String2)\n    {\n        return PhCompareString(String1, String2, IgnoreCase);\n    }\n    else if (!String1)\n    {\n        return !String2 ? 0 : (Order == AscendingSortOrder ? 1 : -1);\n    }\n    else\n    {\n        return (Order == AscendingSortOrder ? -1 : 1);\n    }\n}\n\n/**\n * Compares two strings with support for null values and customizable sort order.\n *\n * This function compares two strings, taking into account the possibility of null values and allowing for customizable sort order.\n * If both `String1` and `String2` are not null, the function calls `PhCompareString` to perform the comparison.\n * If `String1` is null and `String2` is not null, the function returns 0 if `String2` is also null, or 1 if `String2` is not null, depending on the specified sort order.\n * If `String1` is not null and `String2` is null, the function returns -1 or 1, depending on the specified sort order.\n *\n * \\param String1 The first string to compare. Can be null.\n * \\param String2 The second string to compare. Can be null.\n * \\param Order The sort order to use for the comparison. Must be either `AscendingSortOrder` or `DescendingSortOrder`.\n * \\param IgnoreCase Specifies whether the comparison should be case-insensitive (`true`) or case-sensitive (`false`).\n * \\return The result of the comparison. Returns a negative value if `String1` is less than `String2`, 0 if they are equal, or a positive value if `String1` is greater than `String2`.\n */\nFORCEINLINE\nLONG\nPhCompareStringRefWithNullSortOrder(\n    _In_opt_ PCPH_STRINGREF String1,\n    _In_opt_ PCPH_STRINGREF String2,\n    _In_ PH_SORT_ORDER Order,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (String1 && String2)\n    {\n        return PhCompareStringRef(String1, String2, IgnoreCase);\n    }\n    else if (!String1)\n    {\n        return !String2 ? 0 : (Order == AscendingSortOrder ? 1 : -1);\n    }\n    else\n    {\n        return (Order == AscendingSortOrder ? -1 : 1);\n    }\n}\n\n/**\n * Determines whether two strings are equal.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nBOOLEAN\nPhEqualString(\n    _In_ PPH_STRING String1,\n    _In_ PPH_STRING String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    return PhEqualStringRef(&String1->sr, &String2->sr, IgnoreCase);\n}\n\n/**\n * Determines whether two strings are equal.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nBOOLEAN\nPhEqualString2(\n    _In_ PPH_STRING String1,\n    _In_ PCWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (IgnoreCase)\n        return PhEqualStringRef2(&String1->sr, String2, IgnoreCase);\n    else\n        return wcscmp(String1->Buffer, String2) == 0;\n}\n\n/**\n * Determines whether a string starts with another.\n *\n * \\param String The first string.\n * \\param Prefix The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n *\n * \\return TRUE if \\a String starts with \\a Prefix, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhStartsWithString(\n    _In_ PPH_STRING String,\n    _In_ PPH_STRING Prefix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    return PhStartsWithStringRef(&String->sr, &Prefix->sr, IgnoreCase);\n}\n\n/**\n * Determines whether a string starts with another.\n *\n * \\param String The first string.\n * \\param Prefix The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n *\n * \\return TRUE if \\a String starts with \\a Prefix, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhStartsWithString2(\n    _In_ PPH_STRING String,\n    _In_ PCWSTR Prefix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF prefix;\n\n    PhInitializeStringRef(&prefix, Prefix);\n\n    return PhStartsWithStringRef(&String->sr, &prefix, IgnoreCase);\n}\n\n/**\n * Determines whether a string ends with another.\n *\n * \\param String The first string.\n * \\param Suffix The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n *\n * \\return TRUE if \\a String ends with \\a Suffix, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhEndsWithString(\n    _In_ PPH_STRING String,\n    _In_ PPH_STRING Suffix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    return PhEndsWithStringRef(&String->sr, &Suffix->sr, IgnoreCase);\n}\n\n/**\n * Determines whether a string ends with another.\n *\n * \\param String The first string.\n * \\param Suffix The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n *\n * \\return TRUE if \\a String ends with \\a Suffix, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhEndsWithString2(\n    _In_ PPH_STRING String,\n    _In_ PCWSTR Suffix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF suffix;\n\n    PhInitializeStringRef(&suffix, Suffix);\n\n    return PhEndsWithStringRef(&String->sr, &suffix, IgnoreCase);\n}\n\n/**\n * Locates a character in a string.\n *\n * \\param String The string to search.\n * \\param StartIndex The index, in characters, to start searching at.\n * \\param Char The character to search for.\n *\n * \\return The index, in characters, of the first occurrence of \\a Char in \\a String after\n * \\a StartIndex. If \\a Char was not found, -1 is returned.\n */\nFORCEINLINE\nULONG_PTR\nPhFindCharInString(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ WCHAR Char\n    )\n{\n    if (StartIndex != 0)\n    {\n        ULONG_PTR r;\n        PH_STRINGREF sr;\n\n        sr = String->sr;\n        PhSkipStringRef(&sr, StartIndex * sizeof(WCHAR));\n        r = PhFindCharInStringRef(&sr, Char, FALSE);\n\n        if (r != SIZE_MAX)\n            return r + StartIndex;\n        else\n            return SIZE_MAX;\n    }\n    else\n    {\n        return PhFindCharInStringRef(&String->sr, Char, FALSE);\n    }\n}\n\n/**\n * Locates a character in a string, backwards.\n *\n * \\param String The string to search.\n * \\param StartIndex The index, in characters, to start searching at.\n * \\param Char The character to search for.\n *\n * \\return The index, in characters, of the last occurrence of \\a Char in \\a String after\n * \\a StartIndex. If \\a Char was not found, -1 is returned.\n */\nFORCEINLINE\nULONG_PTR\nPhFindLastCharInString(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ WCHAR Char\n    )\n{\n    if (StartIndex != 0)\n    {\n        ULONG_PTR r;\n        PH_STRINGREF sr;\n\n        sr = String->sr;\n        PhSkipStringRef(&sr, StartIndex * sizeof(WCHAR));\n        r = PhFindLastCharInStringRef(&sr, Char, FALSE);\n\n        if (r != SIZE_MAX)\n            return r + StartIndex;\n        else\n            return SIZE_MAX;\n    }\n    else\n    {\n        return PhFindLastCharInStringRef(&String->sr, Char, FALSE);\n    }\n}\n\n/**\n * Locates a string in a string.\n *\n * \\param String The string to search.\n * \\param StartIndex The index, in characters, to start searching at.\n * \\param SubString The string to search for.\n *\n * \\return The index, in characters, of the first occurrence of \\a SubString in \\a String after\n * \\a StartIndex. If \\a SubString was not found, -1 is returned.\n */\nFORCEINLINE\nULONG_PTR\nPhFindStringInString(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ PCWSTR SubString\n    )\n{\n    PH_STRINGREF sr2;\n\n    PhInitializeStringRef(&sr2, SubString);\n\n    if (StartIndex != 0)\n    {\n        ULONG_PTR r;\n        PH_STRINGREF sr1;\n\n        sr1 = String->sr;\n        PhSkipStringRef(&sr1, StartIndex * sizeof(WCHAR));\n        r = PhFindStringInStringRef(&sr1, &sr2, FALSE);\n\n        if (r != SIZE_MAX)\n            return r + StartIndex;\n        else\n            return SIZE_MAX;\n    }\n    else\n    {\n        return PhFindStringInStringRef(&String->sr, &sr2, FALSE);\n    }\n}\n\n/**\n * Creates a substring of a string.\n *\n * \\param String The original string.\n * \\param StartIndex The start index, in characters.\n * \\param Count The number of characters to use.\n */\nFORCEINLINE\nPPH_STRING\nPhSubstring(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    )\n{\n    return PhCreateStringEx(&String->Buffer[StartIndex], Count * sizeof(WCHAR));\n}\n\n/**\n * Updates a string object's length with its true length as determined by an embedded null\n * terminator.\n *\n * \\param String The string to modify.\n *\n * \\remarks Use this function after modifying a string object's buffer manually.\n */\nFORCEINLINE\nVOID\nPhTrimToNullTerminatorString(\n    _Inout_ PPH_STRING String\n    )\n{\n    String->Length = PhCountStringZ(String->Buffer) * sizeof(WCHAR);\n}\n\n// Byte string\n\nextern PPH_OBJECT_TYPE PhBytesType;\n\n/**\n * An 8-bit string object, which supports ASCII, UTF-8 and Windows multi-byte encodings, as well as\n * binary data.\n */\ntypedef struct _PH_BYTES\n{\n    // Header\n    union\n    {\n        PH_BYTESREF br;\n        struct\n        {\n            /** The length, in bytes, of the string. */\n            SIZE_T Length;\n            /** The buffer containing the contents of the string. */\n            PCH Buffer;\n        };\n    };\n\n    // Data\n    union\n    {\n        CHAR Data[1];\n        struct\n        {\n            /** Reserved. */\n            ULONG AllocationFlags;\n            /** Reserved. */\n            PVOID Allocation;\n        };\n    };\n} PH_BYTES, *PPH_BYTES;\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhCreateBytes(\n    _In_ PCSTR Buffer\n    );\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhCreateBytesEx(\n    _In_opt_ PCCH Buffer,\n    _In_ SIZE_T Length\n    );\n\n/**\n * Creates a bytes object from an existing null-terminated string of bytes.\n *\n * \\param Buffer A null-terminated byte string.\n */\nFORCEINLINE\nPPH_BYTES\nNTAPI\nPhCreateBytes(\n    _In_ PCSTR Buffer\n    )\n{\n    return PhCreateBytesEx(Buffer, strlen(Buffer) * sizeof(CHAR));\n}\n\nFORCEINLINE\nPPH_BYTES\nNTAPI\nPhCreateBytes2(\n    _In_ PPH_BYTESREF Bytes\n    )\n{\n    return PhCreateBytesEx(Bytes->Buffer, Bytes->Length);\n}\n\nPPH_BYTES\nNTAPI\nPhFormatBytes_V(\n    _In_ _Printf_format_string_ PCSTR Format,\n    _In_ va_list ArgPtr\n    );\n\nPPH_BYTES\nNTAPI\nPhFormatBytes(\n    _In_ _Printf_format_string_ PCSTR Format,\n    ...\n    );\n\n//\n// Unicode\n//\n\n#define PH_UNICODE_BYTE_ORDER_MARK 0xfeff\n#define PH_UNICODE_MAX_CODE_POINT 0x10ffff\n#define PH_UNICODE_REPLACEMENT_CHARACTER 0xfffd\n\n#define PH_UNICODE_UTF16_TO_HIGH_SURROGATE(CodePoint) ((USHORT)((CodePoint) >> 10) + 0xd7c0)\n#define PH_UNICODE_UTF16_TO_LOW_SURROGATE(CodePoint) ((USHORT)((CodePoint) & 0x3ff) + 0xdc00)\n#define PH_UNICODE_UTF16_IS_HIGH_SURROGATE(CodeUnit) ((CodeUnit) >= 0xd800 && (CodeUnit) <= 0xdbff)\n#define PH_UNICODE_UTF16_IS_LOW_SURROGATE(CodeUnit) ((CodeUnit) >= 0xdc00 && (CodeUnit) <= 0xdfff)\n#define PH_UNICODE_UTF16_TO_CODE_POINT(HighSurrogate, LowSurrogate) (((ULONG)(HighSurrogate) << 10) + (ULONG)(LowSurrogate) - 0x35fdc00)\n\n#define PH_UNICODE_UTF8 0\n#define PH_UNICODE_UTF16 1\n#define PH_UNICODE_UTF32 2\n\ntypedef struct _PH_UNICODE_DECODER\n{\n    UCHAR Encoding; // PH_UNICODE_*\n    UCHAR State;\n    UCHAR InputCount;\n    UCHAR Reserved;\n    union\n    {\n        UCHAR Utf8[4];\n        USHORT Utf16[2];\n        ULONG Utf32;\n    } Input;\n    union\n    {\n        struct\n        {\n            UCHAR Input[4];\n            UCHAR CodeUnit1;\n            UCHAR CodeUnit2;\n            UCHAR CodeUnit3;\n            UCHAR CodeUnit4;\n        } Utf8;\n        struct\n        {\n            USHORT Input[2];\n            USHORT CodeUnit;\n        } Utf16;\n        struct\n        {\n            ULONG Input;\n        } Utf32;\n    } u;\n} PH_UNICODE_DECODER, *PPH_UNICODE_DECODER;\n\nFORCEINLINE\nVOID\nPhInitializeUnicodeDecoder(\n    _Out_ PPH_UNICODE_DECODER Decoder,\n    _In_ UCHAR Encoding\n    )\n{\n    memset(Decoder, 0, sizeof(PH_UNICODE_DECODER));\n    Decoder->Encoding = Encoding;\n}\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhWriteUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _In_ ULONG CodeUnit\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDecodeUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _Out_ PULONG CodePoint\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEncodeUnicode(\n    _In_ UCHAR Encoding,\n    _In_ ULONG CodePoint,\n    _Out_opt_ PVOID CodeUnits,\n    _Out_ PULONG NumberOfCodeUnits\n    );\n\n//\n// 8-bit to UTF-16\n//\n\nPHLIBAPI\nVOID\nNTAPI\nPhZeroExtendToUtf16Buffer(\n    _In_reads_bytes_(InputLength) PCCH Input,\n    _In_ SIZE_T InputLength,\n    _Out_writes_bytes_(InputLength * sizeof(WCHAR)) PWCH Output\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhZeroExtendToUtf16Ex(\n    _In_reads_bytes_(InputLength) PCCH Input,\n    _In_ SIZE_T InputLength\n    );\n\nFORCEINLINE\nPPH_STRING\nNTAPI\nPhZeroExtendToUtf16(\n    _In_ PCSTR Input\n    )\n{\n    return PhZeroExtendToUtf16Ex(Input, strlen(Input));\n}\n\n//\n// UTF-16 to ASCII\n//\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToAsciiEx(\n    _In_ PCWCH Buffer,\n    _In_ SIZE_T Length,\n    _In_opt_ CHAR Replacement\n    );\n\nFORCEINLINE\nPPH_BYTES\nPhConvertUtf16ToAscii(\n    _In_ PCWSTR Buffer,\n    _In_opt_ CHAR Replacement\n    )\n{\n    return PhConvertUtf16ToAsciiEx(Buffer, PhCountStringZ(Buffer) * sizeof(WCHAR), Replacement);\n}\n\n//\n// Multi-byte to UTF-16\n// In-place: RtlMultiByteToUnicodeN, RtlMultiByteToUnicodeSize\n//\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConvertMultiByteToUtf16(\n    _In_ PCSTR Buffer\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConvertMultiByteToUtf16Ex(\n    _In_ PCSTR Buffer,\n    _In_ SIZE_T Length\n    );\n\n//\n// UTF-16 to multi-byte\n// In-place: RtlUnicodeToMultiByteN, RtlUnicodeToMultiByteSize\n//\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToMultiByte(\n    _In_ PCWSTR Buffer\n    );\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToMultiByteEx(\n    _In_ PCWCH Buffer,\n    _In_ SIZE_T Length\n    );\n\n//\n// UTF-8 to UTF-16\n// In-place: RtlUTF8ToUnicodeN\n//\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConvertUtf8ToUtf16Size(\n    _Out_ PSIZE_T BytesInUtf16String,\n    _In_reads_bytes_(BytesInUtf8String) PCCH Utf8String,\n    _In_ SIZE_T BytesInUtf8String\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConvertUtf8ToUtf16Buffer(\n    _Out_writes_bytes_to_(MaxBytesInUtf16String, *BytesInUtf16String) PWCH Utf16String,\n    _In_ SIZE_T MaxBytesInUtf16String,\n    _Out_opt_ PSIZE_T BytesInUtf16String,\n    _In_reads_bytes_(BytesInUtf8String) PCCH Utf8String,\n    _In_ SIZE_T BytesInUtf8String\n    );\n\n_Ret_maybenull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConvertUtf8ToUtf16(\n    _In_ PCSTR Buffer\n    );\n\n_Ret_maybenull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConvertUtf8ToUtf16Ex(\n    _In_reads_bytes_(Length) PCCH Buffer,\n    _In_ SIZE_T Length\n    );\n\n//\n// UTF-16 to UTF-8\n// In-place: RtlUnicodeToUTF8N\n//\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConvertUtf16ToUtf8Size(\n    _Out_ PSIZE_T BytesInUtf8String,\n    _In_reads_bytes_(BytesInUtf16String) PCWCH Utf16String,\n    _In_ SIZE_T BytesInUtf16String\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConvertUtf16ToUtf8Buffer(\n    _Out_writes_bytes_to_(MaxBytesInUtf8String, *BytesInUtf8String) PCH Utf8String,\n    _In_ SIZE_T MaxBytesInUtf8String,\n    _Out_opt_ PSIZE_T BytesInUtf8String,\n    _In_reads_bytes_(BytesInUtf16String) PCWCH Utf16String,\n    _In_ SIZE_T BytesInUtf16String\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToUtf8(\n    _In_ PCWSTR Buffer\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToUtf8Ex(\n    _In_reads_bytes_(Length) PCWCH Buffer,\n    _In_ SIZE_T Length\n    );\n\nFORCEINLINE\nPPH_BYTES\nNTAPI\nPhConvertStringToUtf8(\n    _In_ PPH_STRING String\n    )\n{\n    return PhConvertUtf16ToUtf8Ex(String->Buffer, String->Length);\n}\n\nFORCEINLINE\nPPH_BYTES\nNTAPI\nPhConvertStringRefToUtf8(\n    _In_ PCPH_STRINGREF String\n    )\n{\n    return PhConvertUtf16ToUtf8Ex(String->Buffer, String->Length);\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI\nPhConvertBytesToUtf16(\n    _In_ PPH_BYTES String\n    )\n{\n    return PhConvertUtf8ToUtf16Ex(String->Buffer, String->Length);\n}\n\n//\n// String builder\n//\n\n/**\n * A string builder structure.\n * The string builder object allows you to easily construct complex strings without allocating\n * a great number of strings in the process.\n */\ntypedef struct _PH_STRING_BUILDER\n{\n    /** Allocated length of the string, not including the null terminator. */\n    SIZE_T AllocatedLength;\n    /**\n     * The constructed string.\n     * \\a String will be allocated for \\a AllocatedLength, we will modify the \\a Length field to be\n     * the correct length.\n     */\n    PPH_STRING String;\n} PH_STRING_BUILDER, *PPH_STRING_BUILDER;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeStringBuilder(\n    _Out_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T InitialCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFinalStringBuilderString(\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendStringBuilderEx(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_opt_ PWCHAR String,\n    _In_ SIZE_T Length\n    );\n\n/**\n * Appends a string to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param String The string to append.\n */\nFORCEINLINE\nVOID\nNTAPI\nPhAppendStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PCPH_STRINGREF String\n    )\n{\n    PhAppendStringBuilderEx(\n        StringBuilder,\n        String->Buffer,\n        String->Length\n        );\n}\n\n/**\n * Appends a string to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param String The string to append.\n */\nFORCEINLINE\nVOID\nNTAPI\nPhAppendStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PCWSTR String\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, String);\n    PhAppendStringBuilder(StringBuilder, &string);\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendCharStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ WCHAR Character\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendCharStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ WCHAR Character,\n    _In_ SIZE_T Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendFormatStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ _Printf_format_string_ PCWSTR Format,\n    ...\n    );\n\nVOID\nNTAPI\nPhAppendFormatStringBuilder_V(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ _Printf_format_string_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_ PCPH_STRINGREF String\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_ PCWSTR String\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertStringBuilderEx(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_opt_ PCWCHAR String,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    );\n\nFORCEINLINE\nVOID\nPhRemoveEndStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Count\n    )\n{\n    PhRemoveStringBuilder(\n        StringBuilder,\n        StringBuilder->String->Length / sizeof(WCHAR) - Count,\n        Count\n        );\n}\n\n//\n// Byte string builder\n//\n\n/**\n * A byte string builder structure.\n * This is similar to string builder, but is based on PH_BYTES and is suitable for general binary\n * data.\n */\ntypedef struct _PH_BYTES_BUILDER\n{\n    /** Allocated length of the byte string, not including the null terminator. */\n    SIZE_T AllocatedLength;\n    /**\n     * The constructed byte string.\n     * \\a Bytes will be allocated for \\a AllocatedLength, we will modify the \\a Length field to be\n     * the correct length.\n     */\n    PPH_BYTES Bytes;\n} PH_BYTES_BUILDER, *PPH_BYTES_BUILDER;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeBytesBuilder(\n    _Out_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ SIZE_T InitialCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder\n    );\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhFinalBytesBuilderBytes(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder\n    );\n\nFORCEINLINE\nPVOID\nPhOffsetBytesBuilder(\n    _In_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ SIZE_T Offset\n    )\n{\n    return BytesBuilder->Bytes->Buffer + Offset;\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ PPH_BYTESREF Bytes\n    );\n\n/**\n * Appends a byte string to the end of a byte string builder string.\n *\n * \\param BytesBuilder A byte string builder object.\n * \\param Bytes The byte string to append.\n */\nFORCEINLINE\nVOID\nNTAPI\nPhAppendBytesBuilder2(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ PCSTR Bytes\n    )\n{\n    PH_BYTESREF string;\n\n    PhInitializeBytesRef(&string, Bytes);\n    PhAppendBytesBuilder(BytesBuilder, &string);\n}\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAppendBytesBuilderEx(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_opt_ PVOID Buffer,\n    _In_ SIZE_T Length,\n    _In_opt_ SIZE_T Alignment,\n    _Out_opt_ PSIZE_T Offset\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendFormatBytesBuilder_V(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ _Printf_format_string_ PCSTR Format,\n    _In_ va_list ArgPtr\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendFormatBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ _Printf_format_string_ PCSTR Format,\n    ...\n    );\n\n//\n// Array\n//\n\n/** An array structure. Storage is automatically allocated for new elements. */\ntypedef struct _PH_ARRAY\n{\n    /** The number of items in the list. */\n    SIZE_T Count;\n    /** The number of items for which storage is allocated. */\n    SIZE_T AllocatedCount;\n    /** The size of each item, in bytes. */\n    SIZE_T ItemSize;\n    /** The base address of the array. */\n    PVOID Items;\n} PH_ARRAY, *PPH_ARRAY;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeArray(\n    _Out_ PPH_ARRAY Array,\n    _In_ SIZE_T ItemSize,\n    _In_ SIZE_T InitialCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteArray(\n    _Inout_ PPH_ARRAY Array\n    );\n\nFORCEINLINE\nPVOID\nPhItemArray(\n    _In_ PPH_ARRAY Array,\n    _In_ SIZE_T Index\n    )\n{\n    return PTR_ADD_OFFSET(Array->Items, Index * Array->ItemSize);\n}\n\nFORCEINLINE\nPVOID\nPhFinalArrayItems(\n    _Inout_ PPH_ARRAY Array\n    )\n{\n    return Array->Items;\n}\n\nFORCEINLINE\nSIZE_T\nPhFinalArrayCount(\n    _In_ PPH_ARRAY Array\n    )\n{\n    return Array->Count;\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhResizeArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T NewCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddItemArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ PVOID Item\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddItemsArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ PVOID Items,\n    _In_ SIZE_T Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhClearArray(\n    _Inout_ PPH_ARRAY Array\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T Index\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemsArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    );\n\n//\n// List\n//\n\nextern PPH_OBJECT_TYPE PhListType;\n\n/** A list structure. Storage is automatically allocated for new elements. */\ntypedef struct _PH_LIST\n{\n    /** The number of items in the list. */\n    ULONG Count;\n    /** The number of items for which storage is allocated. */\n    ULONG AllocatedCount;\n    /** The array of list items. */\n    PVOID *Items;\n} PH_LIST, *PPH_LIST;\n\nFORCEINLINE\nPVOID\nPhItemList(\n    _In_ PPH_LIST List,\n    _In_ ULONG Index\n    )\n{\n    return List->Items[Index];\n}\n\nPHLIBAPI\nPPH_LIST\nNTAPI\nPhCreateList(\n    _In_ ULONG InitialCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhResizeList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG NewCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddItemList(\n    _Inout_ PPH_LIST List,\n    _In_ PVOID Item\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ PVOID *Items,\n    _In_ ULONG Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhClearList(\n    _Inout_ PPH_LIST List\n    );\n\n_Success_(return != -1)\nPHLIBAPI\nULONG\nNTAPI\nPhFindItemList(\n    _In_ PPH_LIST List,\n    _In_ PVOID Item\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertItemList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index,\n    _In_ PVOID Item\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index,\n    _In_ PVOID *Items,\n    _In_ ULONG Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG StartIndex,\n    _In_ ULONG Count\n    );\n\n/**\n * A comparison function.\n *\n * \\param Item1 The first item.\n * \\param Item2 The second item.\n * \\param Context A user-defined value.\n *\n * \\return\n * \\li A positive value if \\a Item1 > \\a Item2,\n * \\li A negative value if \\a Item1 < \\a Item2, and\n * \\li 0 if \\a Item1 = \\a Item2.\n */\ntypedef _Function_class_(PH_COMPARE_FUNCTION)\nLONG NTAPI PH_COMPARE_FUNCTION(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_COMPARE_FUNCTION* PPH_COMPARE_FUNCTION;\n\n//\n// Pointer list\n//\n\nextern PPH_OBJECT_TYPE PhPointerListType;\n\n/**\n * A pointer list structure. The pointer list is similar to the normal list structure, but both\n * insertions and deletions occur in constant time. The list is not ordered.\n */\ntypedef struct _PH_POINTER_LIST\n{\n    /** The number of pointers in the list. */\n    ULONG Count;\n    /** The number of pointers for which storage is allocated. */\n    ULONG AllocatedCount;\n    /** Index into pointer array for free list. */\n    ULONG FreeEntry;\n    /** Index of next usable index into pointer array. */\n    ULONG NextEntry;\n    /** The array of pointers. */\n    PVOID *Items;\n} PH_POINTER_LIST, *PPH_POINTER_LIST;\n\n#define PH_IS_LIST_POINTER_VALID(Pointer) (!((ULONG_PTR)(Pointer) & 0x1))\n\nPHLIBAPI\nPPH_POINTER_LIST\nNTAPI\nPhCreatePointerList(\n    _In_ ULONG InitialCapacity\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhAddItemPointerList(\n    _Inout_ PPH_POINTER_LIST PointerList,\n    _In_ PVOID Pointer\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEnumPointerListEx(\n    _In_ PPH_POINTER_LIST PointerList,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PVOID *Pointer,\n    _Out_ PHANDLE PointerHandle\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhFindItemPointerList(\n    _In_ PPH_POINTER_LIST PointerList,\n    _In_ PVOID Pointer\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemPointerList(\n    _Inout_ PPH_POINTER_LIST PointerList,\n    _In_ HANDLE PointerHandle\n    );\n\n_Success_(return != FALSE)\nFORCEINLINE\nBOOLEAN\nPhEnumPointerList(\n    _In_ PPH_POINTER_LIST PointerList,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PVOID *Pointer\n    )\n{\n    while (*EnumerationKey < PointerList->NextEntry)\n    {\n        PVOID pointer = PointerList->Items[*EnumerationKey];\n\n        (*EnumerationKey)++;\n\n        if (PH_IS_LIST_POINTER_VALID(pointer))\n        {\n            *Pointer = pointer;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n//\n// Hash\n//\n\ntypedef struct _PH_HASH_ENTRY\n{\n    struct _PH_HASH_ENTRY *Next;\n    ULONG Hash;\n} PH_HASH_ENTRY, *PPH_HASH_ENTRY;\n\n#define PH_HASH_SET_INIT { 0 }\n#define PH_HASH_SET_SIZE(Buckets) (sizeof(Buckets) / sizeof(PPH_HASH_ENTRY))\n\n/**\n * Initializes a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n */\nFORCEINLINE\nVOID\nPhInitializeHashSet(\n    _Out_ PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets\n    )\n{\n    memset(Buckets, 0, sizeof(PPH_HASH_ENTRY) * NumberOfBuckets);\n}\n\n/**\n * Allocates and initializes a hash set.\n *\n * \\param NumberOfBuckets The number of buckets.\n *\n * \\return The allocated hash set. You must free it with PhFree() when you no longer need it.\n */\nFORCEINLINE\nPPH_HASH_ENTRY *\nPhCreateHashSet(\n    _In_ ULONG NumberOfBuckets\n    )\n{\n    PPH_HASH_ENTRY *buckets;\n\n    buckets = (PPH_HASH_ENTRY *)PhAllocate(sizeof(PPH_HASH_ENTRY) * NumberOfBuckets);\n    PhInitializeHashSet(buckets, NumberOfBuckets);\n\n    return buckets;\n}\n\n/**\n * Determines the number of entries in a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n *\n * \\return The number of entries in the hash set.\n */\nFORCEINLINE\nULONG\nPhCountHashSet(\n    _In_ PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets\n    )\n{\n    ULONG i;\n    PPH_HASH_ENTRY entry;\n    ULONG count;\n\n    count = 0;\n\n    for (i = 0; i < NumberOfBuckets; i++)\n    {\n        for (entry = Buckets[i]; entry; entry = entry->Next)\n            count++;\n    }\n\n    return count;\n}\n\n/**\n * Moves entries from one hash set to another.\n *\n * \\param NewBuckets The new bucket array.\n * \\param NumberOfNewBuckets The number of buckets in \\a NewBuckets.\n * \\param OldBuckets The old bucket array.\n * \\param NumberOfOldBuckets The number of buckets in \\a OldBuckets.\n *\n * \\remarks \\a NewBuckets and \\a OldBuckets must be different.\n */\nFORCEINLINE\nVOID\nPhDistributeHashSet(\n    _Inout_ PPH_HASH_ENTRY *NewBuckets,\n    _In_ ULONG NumberOfNewBuckets,\n    _In_ CONST PPH_HASH_ENTRY *OldBuckets,\n    _In_ ULONG NumberOfOldBuckets\n    )\n{\n    ULONG i;\n    PPH_HASH_ENTRY entry;\n    PPH_HASH_ENTRY nextEntry;\n    ULONG index;\n\n    for (i = 0; i < NumberOfOldBuckets; i++)\n    {\n        entry = OldBuckets[i];\n\n        while (entry)\n        {\n            nextEntry = entry->Next;\n\n            index = entry->Hash & (NumberOfNewBuckets - 1);\n            entry->Next = NewBuckets[index];\n            NewBuckets[index] = entry;\n\n            entry = nextEntry;\n        }\n    }\n}\n\n/**\n * Adds an entry to a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n * \\param Entry The entry.\n * \\param Hash The hash for the entry.\n *\n * \\remarks This function does not check for duplicates.\n */\nFORCEINLINE\nVOID\nPhAddEntryHashSet(\n    _Inout_ PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets,\n    _Out_ PPH_HASH_ENTRY Entry,\n    _In_ ULONG Hash\n    )\n{\n    ULONG index;\n\n    index = Hash & (NumberOfBuckets - 1);\n\n    Entry->Hash = Hash;\n    Entry->Next = Buckets[index];\n    Buckets[index] = Entry;\n}\n\n/**\n * Begins the process of finding an entry in a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n * \\param Hash The hash for the entry.\n *\n * \\return The first entry in the chain.\n *\n * \\remarks If the function returns NULL, the entry does not exist in the hash set.\n */\nFORCEINLINE\nPPH_HASH_ENTRY\nPhFindEntryHashSet(\n    _In_ CONST PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets,\n    _In_ ULONG Hash\n    )\n{\n    return Buckets[Hash & (NumberOfBuckets - 1)];\n}\n\n/**\n * Removes an entry from a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n * \\param Entry An entry present in the hash set.\n */\nFORCEINLINE\nVOID\nPhRemoveEntryHashSet(\n    _Inout_ PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets,\n    _Inout_ PPH_HASH_ENTRY Entry\n    )\n{\n    ULONG index;\n    PPH_HASH_ENTRY entry;\n    PPH_HASH_ENTRY previousEntry;\n\n    index = Entry->Hash & (NumberOfBuckets - 1);\n    previousEntry = NULL;\n\n    entry = Buckets[index];\n\n    do\n    {\n        if (entry == Entry)\n        {\n            if (!previousEntry)\n                Buckets[index] = entry->Next;\n            else\n                previousEntry->Next = entry->Next;\n\n            return;\n        }\n\n        previousEntry = entry;\n        entry = entry->Next;\n    } while (entry);\n\n    // Entry doesn't actually exist in the set. This is a fatal logic error.\n    PhRaiseStatus(STATUS_INTERNAL_ERROR);\n}\n\n/**\n * Resizes a hash set.\n *\n * \\param Buckets A pointer to the bucket array. On return the new bucket array is stored in this\n * variable.\n * \\param NumberOfBuckets A pointer to the number of buckets. On return the new number of buckets is\n * stored in this variable.\n * \\param NewNumberOfBuckets The new number of buckets.\n */\nFORCEINLINE\nVOID\nPhResizeHashSet(\n    _Inout_ PPH_HASH_ENTRY **Buckets,\n    _Inout_ PULONG NumberOfBuckets,\n    _In_ ULONG NewNumberOfBuckets\n    )\n{\n    PPH_HASH_ENTRY *newBuckets;\n\n    newBuckets = PhCreateHashSet(NewNumberOfBuckets);\n    PhDistributeHashSet(newBuckets, NewNumberOfBuckets, *Buckets, *NumberOfBuckets);\n\n    PhFree(*Buckets);\n    *Buckets = newBuckets;\n    *NumberOfBuckets = NewNumberOfBuckets;\n}\n\n//\n// Hashtable\n//\n\nextern PPH_OBJECT_TYPE PhHashtableType;\n\ntypedef struct _PH_HASHTABLE_ENTRY\n{\n    /** Hash code of the entry. -1 if entry is unused. */\n    ULONG HashCode;\n    /**\n     * Either the index of the next entry in the bucket, the index of the next free entry, or -1 for\n     * invalid.\n     */\n    ULONG Next;\n    /** The beginning of user data. */\n    QUAD_PTR Body;\n} PH_HASHTABLE_ENTRY, *PPH_HASHTABLE_ENTRY;\n\nC_ASSERT((FIELD_OFFSET(PH_HASHTABLE_ENTRY, Body) % MEMORY_ALLOCATION_ALIGNMENT) == 0);\n\n/**\n * A comparison function used by a hashtable.\n *\n * \\param Entry1 The first entry.\n * \\param Entry2 The second entry.\n *\n * \\return TRUE if the entries are equal, otherwise FALSE.\n */\ntypedef _Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PH_HASHTABLE_EQUAL_FUNCTION(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\ntypedef PH_HASHTABLE_EQUAL_FUNCTION* PPH_HASHTABLE_EQUAL_FUNCTION;\n\n/**\n * A hash function used by a hashtable.\n *\n * \\param Entry The entry.\n *\n * \\return A hash code for the entry.\n *\n * \\remarks\n * \\li Two entries which are considered to be equal by the comparison function must be given the\n * same hash code.\n * \\li Two different entries do not have to be given different hash codes.\n */\ntypedef _Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PH_HASHTABLE_HASH_FUNCTION(\n    _In_ PVOID Entry\n    );\ntypedef PH_HASHTABLE_HASH_FUNCTION* PPH_HASHTABLE_HASH_FUNCTION;\n\n// Use power-of-two sizes instead of primes\n#define PH_HASHTABLE_POWER_OF_TWO_SIZE\n\n// Enables 2^32-1 possible hash codes instead of only 2^31\n//#define PH_HASHTABLE_FULL_HASH\n\n/**\n * A hashtable structure.\n */\ntypedef struct _PH_HASHTABLE\n{\n    /** Size of user data in each entry. */\n    ULONG EntrySize;\n    /** The comparison function. */\n    PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction;\n    /** The hash function. */\n    PPH_HASHTABLE_HASH_FUNCTION HashFunction;\n\n    /** The number of allocated buckets. */\n    ULONG AllocatedBuckets;\n    /** The bucket array. */\n    PULONG Buckets;\n    /** The number of allocated entries. */\n    ULONG AllocatedEntries;\n    /** The entry array. */\n    PVOID Entries;\n\n    /** Number of entries in the hashtable. */\n    ULONG Count;\n    /** Index into entry array for free list. */\n    ULONG FreeEntry;\n    /**\n     * Index of next usable index into entry array, a.k.a. the count of entries that were ever\n     * allocated.\n     */\n    ULONG NextEntry;\n} PH_HASHTABLE, *PPH_HASHTABLE;\n\n#define PH_HASHTABLE_ENTRY_SIZE(InnerSize) (UInt32Add32To64(UFIELD_OFFSET(PH_HASHTABLE_ENTRY, Body), (InnerSize)))\n#define PH_HASHTABLE_GET_ENTRY(Hashtable, Index) ((PPH_HASHTABLE_ENTRY)PTR_ADD_OFFSET((Hashtable)->Entries, UInt32x32To64(PH_HASHTABLE_ENTRY_SIZE((Hashtable)->EntrySize), (Index))))\n#define PH_HASHTABLE_GET_ENTRY_INDEX(Hashtable, Entry) ((ULONG)(PTR_ADD_OFFSET(Entry, -(Hashtable)->Entries) / PH_HASHTABLE_ENTRY_SIZE((Hashtable)->EntrySize)))\n\nPHLIBAPI\nPPH_HASHTABLE\nNTAPI\nPhCreateHashtable(\n    _In_ ULONG EntrySize,\n    _In_ PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction,\n    _In_ PPH_HASHTABLE_HASH_FUNCTION HashFunction,\n    _In_ ULONG InitialCapacity\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAddEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAddEntryHashtableEx(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry,\n    _Out_opt_ PBOOLEAN Added\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhClearHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEnumHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _Out_ PVOID *Entry,\n    _Inout_ PULONG EnumerationKey\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhFindEntryHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhRemoveEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    );\n\n// New faster enumeration method\n\ntypedef struct _PH_HASHTABLE_ENUM_CONTEXT\n{\n    ULONG_PTR Current;\n    ULONG_PTR End;\n    ULONG_PTR Step;\n} PH_HASHTABLE_ENUM_CONTEXT, *PPH_HASHTABLE_ENUM_CONTEXT;\n\nFORCEINLINE\nVOID\nNTAPI_INLINE\nPhBeginEnumHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _Out_ PPH_HASHTABLE_ENUM_CONTEXT Context\n    )\n{\n    Context->Current = (ULONG_PTR)Hashtable->Entries;\n    Context->Step = PH_HASHTABLE_ENTRY_SIZE((ULONG_PTR)Hashtable->EntrySize);\n    Context->End = Context->Current + (ULONG_PTR)Hashtable->NextEntry * Context->Step;\n}\n\nFORCEINLINE\nPVOID\nNTAPI_INLINE\nPhNextEnumHashtable(\n    _Inout_ PPH_HASHTABLE_ENUM_CONTEXT Context\n    )\n{\n    PPH_HASHTABLE_ENTRY entry;\n\n    while (Context->Current != Context->End)\n    {\n        entry = (PPH_HASHTABLE_ENTRY)Context->Current;\n        Context->Current += Context->Step;\n\n        if (entry->HashCode != ULONG_MAX)\n            return &entry->Body;\n    }\n\n    return NULL;\n}\n\nPHLIBAPI\nULONG\nNTAPI\nPhHashBytes(\n    _In_reads_(Length) PUCHAR Bytes,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhHashStringRef(\n    _In_ PCPH_STRINGREF String,\n    _In_ BOOLEAN IgnoreCase\n    );\n\ntypedef enum _PH_STRING_HASH\n{\n    PH_STRING_HASH_DEFAULT,\n    PH_STRING_HASH_FNV1A,\n    PH_STRING_HASH_X65599,\n    PH_STRING_HASH_XXH32,\n} PH_STRING_HASH;\n\nPHLIBAPI\nULONG\nNTAPI\nPhHashStringRefEx(\n    _In_ PCPH_STRINGREF String,\n    _In_ BOOLEAN IgnoreCase,\n    _In_ PH_STRING_HASH HashAlgorithm\n    );\n\nFORCEINLINE\nULONG\nPhHashInt32(\n    _In_ ULONG Value\n    )\n{\n    // Java style.\n    Value ^= (Value >> 20) ^ (Value >> 12);\n    return Value ^ (Value >> 7) ^ (Value >> 4);\n}\n\nFORCEINLINE\nULONG\nPhHashInt64(\n    _In_ ULONG64 Value\n    )\n{\n    // http://www.concentric.net/~Ttwang/tech/inthash.htm\n\n    Value = ~Value + (Value << 18);\n    Value ^= Value >> 31;\n    Value *= 21;\n    Value ^= Value >> 11;\n    Value += Value << 6;\n    Value ^= Value >> 22;\n\n    return (ULONG)Value;\n}\n\nFORCEINLINE\nULONG\nPhHashIntPtr(\n    _In_ ULONG_PTR Value\n    )\n{\n#ifdef _WIN64\n    return PhHashInt64(Value);\n#else\n    return PhHashInt32(Value);\n#endif\n}\n\n//\n// Simple hashtable\n//\n\n#define SIP(String, Integer) { (String), (PVOID)(Integer) }\n#define SREF(String) ((PVOID)&(PH_STRINGREF)PH_STRINGREF_INIT((String)))\n\ntypedef struct _PH_KEY_VALUE_PAIR\n{\n    PVOID Key;\n    PVOID Value;\n} PH_KEY_VALUE_PAIR, *PPH_KEY_VALUE_PAIR;\n\ntypedef CONST PH_KEY_VALUE_PAIR *PCPH_KEY_VALUE_PAIR;\n\nPHLIBAPI\nPPH_HASHTABLE\nNTAPI\nPhCreateSimpleHashtable(\n    _In_ ULONG InitialCapacity\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAddItemSimpleHashtable(\n    _Inout_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key,\n    _In_opt_ PVOID Value\n    );\n\nPHLIBAPI\nPVOID *\nNTAPI\nPhFindItemSimpleHashtable(\n    _In_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    );\n\nFORCEINLINE\nPVOID\nNTAPI_INLINE\nPhFindItemSimpleHashtable2(\n    _In_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    )\n{\n    PVOID *item;\n\n    item = PhFindItemSimpleHashtable(SimpleHashtable, Key);\n\n    if (item)\n        return *item;\n    else\n        return NULL;\n}\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhRemoveItemSimpleHashtable(\n    _Inout_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    );\n\n// Free list\n\ntypedef struct _PH_FREE_LIST\n{\n    SLIST_HEADER ListHead;\n\n    ULONG Count;\n    ULONG MaximumCount;\n    SIZE_T Size;\n} PH_FREE_LIST, *PPH_FREE_LIST;\n\ntypedef struct _PH_FREE_LIST_ENTRY\n{\n    SLIST_ENTRY ListEntry;\n    QUAD_PTR Body;\n} PH_FREE_LIST_ENTRY, *PPH_FREE_LIST_ENTRY;\n\nC_ASSERT((FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) % MEMORY_ALLOCATION_ALIGNMENT) == 0);\n\n#ifdef _WIN64\nC_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, ListEntry) == 0x0);\nC_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) == 0x10);\n#else\nC_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, ListEntry) == 0x0);\nC_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) == 0x8);\n#endif\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeFreeList(\n    _Out_ PPH_FREE_LIST FreeList,\n    _In_ SIZE_T Size,\n    _In_ ULONG MaximumCount\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteFreeList(\n    _Inout_ PPH_FREE_LIST FreeList\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAllocateFromFreeList(\n    _Inout_ PPH_FREE_LIST FreeList\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeToFreeList(\n    _Inout_ PPH_FREE_LIST FreeList,\n    _In_ _Post_invalid_ PVOID Memory\n    );\n\n//\n// Callback\n//\n\n/**\n * A callback function.\n *\n * \\param Parameter A value given to all callback functions being notified.\n * \\param Context A user-defined value passed to PhRegisterCallback().\n */\ntypedef _Function_class_(PH_CALLBACK_FUNCTION)\nVOID NTAPI PH_CALLBACK_FUNCTION(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_CALLBACK_FUNCTION *PPH_CALLBACK_FUNCTION;\n\n/** A callback registration structure. */\ntypedef struct _PH_CALLBACK_REGISTRATION\n{\n    /** The list entry in the callbacks list. */\n    LIST_ENTRY ListEntry;\n    /** The callback function. */\n    PPH_CALLBACK_FUNCTION Function;\n    /** A user-defined value to be passed to the callback function. */\n    PVOID Context;\n    /** A value indicating whether the registration structure is being used. */\n    LONG Busy;\n    /** Whether the registration structure is being removed. */\n    BOOLEAN Unregistering;\n    BOOLEAN Reserved;\n    /** Flags controlling the callback. */\n    USHORT Flags;\n} PH_CALLBACK_REGISTRATION, *PPH_CALLBACK_REGISTRATION;\n\n/**\n * A callback structure. The callback object allows multiple callback functions to be registered and\n * notified in a thread-safe way.\n */\ntypedef struct _PH_CALLBACK\n{\n    /** The list of registered callbacks. */\n    LIST_ENTRY ListHead;\n    /** A lock protecting the callbacks list. */\n    PH_QUEUED_LOCK ListLock;\n    /** A condition variable pulsed when the callback becomes free. */\n    PH_CONDITION BusyCondition;\n} PH_CALLBACK, *PPH_CALLBACK;\n\n#define PH_CALLBACK_DECLARE(Name) PH_CALLBACK Name = { &(Name).ListHead, &(Name).ListHead, PH_QUEUED_LOCK_INIT, PH_CONDITION_INIT }\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeCallback(\n    _Out_ PPH_CALLBACK Callback\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteCallback(\n    _Inout_ PPH_CALLBACK Callback\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRegisterCallback(\n    _Inout_ PPH_CALLBACK Callback,\n    _In_ PPH_CALLBACK_FUNCTION Function,\n    _In_opt_ PVOID Context,\n    _Out_ PPH_CALLBACK_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRegisterCallbackEx(\n    _Inout_ PPH_CALLBACK Callback,\n    _In_ PPH_CALLBACK_FUNCTION Function,\n    _In_opt_ PVOID Context,\n    _In_ USHORT Flags,\n    _Out_ PPH_CALLBACK_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUnregisterCallback(\n    _Inout_ PPH_CALLBACK Callback,\n    _Inout_ PPH_CALLBACK_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInvokeCallback(\n    _In_ PPH_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    );\n\n// General\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetPrimeNumber(\n    _In_ ULONG Minimum\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhRoundUpToPowerOfTwo(\n    _In_ ULONG Number\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhExponentiate(\n    _In_ ULONG Base,\n    _In_ ULONG Exponent\n    );\n\nPHLIBAPI\nULONG64\nNTAPI\nPhExponentiate64(\n    _In_ ULONG64 Base,\n    _In_ ULONG Exponent\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhHexStringToBuffer(\n    _In_ PCPH_STRINGREF String,\n    _Out_writes_bytes_(String->Length / sizeof(WCHAR) / 2) PUCHAR Buffer\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhHexStringToBufferEx(\n    _In_ PCPH_STRINGREF String,\n    _In_ SIZE_T BufferLength,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhBufferToHexString(\n    _In_reads_bytes_(Length) PUCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhBufferToHexStringEx(\n    _In_reads_bytes_(Length) PUCHAR Buffer,\n    _In_ SIZE_T Length,\n    _In_ BOOLEAN UpperCase\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhBufferToHexStringBuffer(\n    _In_reads_bytes_(InputLength) PUCHAR InputBuffer,\n    _In_ SIZE_T InputLength,\n    _In_ BOOLEAN UpperCase,\n    _Out_writes_bytes_to_(OutputLength, *ReturnLength) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhStringToInteger64(\n    _In_ PCPH_STRINGREF String,\n    _In_opt_ ULONG Base,\n    _Out_opt_ PLONG64 Integer\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhStringToUInt64(\n    _In_ PCPH_STRINGREF String,\n    _In_opt_ ULONG Base,\n    _Out_opt_ PULONG64 Integer\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhStringToDouble(\n    _In_ PCPH_STRINGREF String,\n    _Reserved_ ULONG Base,\n    _Out_opt_ DOUBLE *Double\n    );\n\n_Ret_notnull_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhIntegerToString64(\n    _In_ LONG64 Integer,\n    _In_opt_ ULONG Base,\n    _In_ BOOLEAN Signed\n    );\n\n#define PH_TIMESPAN_STR_LEN 30\n#define PH_TIMESPAN_STR_LEN_1 (PH_TIMESPAN_STR_LEN + 1)\n\n#define PH_TIMESPAN_HMS 0\n#define PH_TIMESPAN_HMSM 1\n#define PH_TIMESPAN_DHMS 2\n#define PH_TIMESPAN_DHMSM 3\n\nPHLIBAPI\nVOID\nNTAPI\nPhPrintTimeSpan(\n    _Out_writes_(PH_TIMESPAN_STR_LEN_1) PWSTR Destination,\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhPrintTimeSpanToBuffer(\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhCalculateEntropy(\n    _In_ PBYTE Buffer,\n    _In_ ULONG64 BufferLength,\n    _Out_opt_ PFLOAT Entropy,\n    _Out_opt_ PFLOAT Mean,\n    _Out_opt_ PFLOAT Variance\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatEntropy(\n    _In_ FLOAT Entropy,\n    _In_ USHORT EntropyPrecision,\n    _In_opt_ FLOAT Mean,\n    _In_opt_ USHORT MeanPrecision,\n    _In_opt_ FLOAT Variance,\n    _In_opt_ USHORT VariancePrecision\n    );\n\nDECLSPEC_NOALIAS\nPHLIBAPI\nVOID\nNTAPI\nPhFillMemoryUlong(\n    _Inout_updates_(Count) PULONG Memory,\n    _In_ ULONG Value,\n    _In_ SIZE_T Count\n    );\n\nDECLSPEC_NOALIAS\nPHLIBAPI\nVOID\nNTAPI\nPhDivideSinglesBySingle(\n    _Inout_updates_(Count) PFLOAT A,\n    _In_ FLOAT B,\n    _In_ SIZE_T Count\n    );\n\nDECLSPEC_NOALIAS\nPHLIBAPI\nFLOAT\nNTAPI\nPhMaxMemorySingles(\n    _In_ PFLOAT A,\n    _In_ SIZE_T Count\n    );\n\nDECLSPEC_NOALIAS\nPHLIBAPI\nFLOAT\nNTAPI\nPhAddPlusMaxMemorySingles(\n    _Inout_updates_(Count) PFLOAT A,\n    _Inout_updates_(Count) PFLOAT B,\n    _In_ SIZE_T Count\n    );\n\nDECLSPEC_NOALIAS\nPHLIBAPI\nVOID\nNTAPI\nPhConvertCopyMemoryUlong(\n    _Inout_updates_(Count) PULONG From,\n    _Inout_updates_(Count) PFLOAT To,\n    _In_ SIZE_T Count\n    );\n\nDECLSPEC_NOALIAS\nPHLIBAPI\nVOID\nNTAPI\nPhConvertCopyMemoryUlong64(\n    _Inout_updates_(Count) PULONG64 From,\n    _Inout_updates_(Count) PFLOAT To,\n    _In_ SIZE_T Count\n    );\n\nDECLSPEC_NOALIAS\nPHLIBAPI\nVOID\nNTAPI\nPhConvertCopyMemorySingles(\n    _Inout_updates_(Count) PFLOAT From,\n    _Inout_updates_(Count) PULONG To,\n    _In_ SIZE_T Count\n    );\n\ntypedef struct _PH_CIRCULAR_BUFFER_ULONG* PPH_CIRCULAR_BUFFER_ULONG;\ntypedef struct _PH_CIRCULAR_BUFFER_ULONG64* PPH_CIRCULAR_BUFFER_ULONG64;\n\nDECLSPEC_NOALIAS\nPHLIBAPI\nVOID\nNTAPI\nPhCopyConvertCircularBufferULONG(\n    _Inout_ PPH_CIRCULAR_BUFFER_ULONG Buffer,\n    _Out_writes_(Count) FLOAT* Destination,\n    _In_ ULONG Count\n    );\n\nDECLSPEC_NOALIAS\nPHLIBAPI\nVOID\nNTAPI\nPhCopyConvertCircularBufferULONG64(\n    _Inout_ PPH_CIRCULAR_BUFFER_ULONG64 Buffer,\n    _Out_writes_(Count) FLOAT* Destination,\n    _In_ ULONG Count\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhCountBits(\n    _In_ ULONG Value\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhCountBitsUlongPtr(\n    _In_ ULONG_PTR Value\n    );\n\n//\n// Thread Local Storage (TLS)\n//\n\nPHLIBAPI\nULONG\nNTAPI\nPhTlsAlloc(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTlsFree(\n    _In_ ULONG Index\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhTlsGetValue(\n    _In_ ULONG Index\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTlsGetValueEx(\n    _In_ ULONG Index,\n    _Out_ PVOID* Value\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTlsSetValue(\n    _In_ ULONG Index,\n    _In_opt_ PVOID Value\n    );\n\n//\n// Errors\n//\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetLastError(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetLastError(\n    _In_ ULONG ErrorValue\n    );\n\n//\n// Wildcards\n//\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDoesNameContainWildCards(\n    _In_ PCPH_STRINGREF Expression\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsNameInExpression(\n    _In_ PCPH_STRINGREF Expression,\n    _In_ PCPH_STRINGREF Name,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhStringFuzzyMatch(\n    _In_ PCPH_STRINGREF Pattern,\n    _In_ PCPH_STRINGREF Text,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nFORCEINLINE\nBOOLEAN\nPhIsLegacyPrefix(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    static const WCHAR prefix[] = { L'P',L'r',L'o',L'c',L'e',L's',L's',L'H',L'a',L'c',L'k',L'e',L'r',L'.' };\n\n    if (Name->Length < sizeof(prefix))\n        return FALSE;\n\n    for (ULONG i = 0; i < RTL_NUMBER_OF(prefix); i++)\n    {\n        if (PhUpcaseUnicodeChar(Name->Buffer[i]) != PhUpcaseUnicodeChar(prefix[i]))\n            return FALSE;\n    }\n\n    return TRUE;\n}\n\n//\n// Auto-dereference convenience functions\n//\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhaCreateString(\n    _In_ PCWSTR Buffer\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhCreateString(Buffer));\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhaCreateStringEx(\n    _In_opt_ PCWSTR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhCreateStringEx(Buffer, Length));\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhaDuplicateString(\n    _In_ PPH_STRING String\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhDuplicateString(String));\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhaConcatStrings(\n    _In_ ULONG Count,\n    ...\n    )\n{\n    PPH_STRING string;\n    va_list argptr;\n\n    va_start(argptr, Count);\n    string = PH_AUTO_T(PH_STRING, PhConcatStrings_V(Count, argptr));\n    va_end(argptr);\n\n    return string;\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhaConcatStrings2(\n    _In_ PCWSTR String1,\n    _In_ PCWSTR String2\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhConcatStrings2(String1, String2));\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhaFormatString(\n    _In_ _Printf_format_string_ PCWSTR Format,\n    ...\n    )\n{\n    PPH_STRING string;\n    va_list argptr;\n\n    va_start(argptr, Format);\n    string = PH_AUTO_T(PH_STRING, PhFormatString_V(Format, argptr));\n    va_end(argptr);\n\n    return string;\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhLowerString(\n    _In_ PPH_STRING String\n    )\n{\n    return PhCreateString3(&String->sr, PH_STRING_LOWER_CASE, NULL);\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhaLowerString(\n    _In_ PPH_STRING String\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhCreateString3(&String->sr, PH_STRING_LOWER_CASE, NULL));\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhUpperString(\n    _In_ PPH_STRING String\n    )\n{\n    return PhCreateString3(&String->sr, PH_STRING_UPPER_CASE, NULL);\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhaUpperString(\n    _In_ PPH_STRING String\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhCreateString3(&String->sr, PH_STRING_UPPER_CASE, NULL));\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI_INLINE\nPhaSubstring(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhSubstring(String, StartIndex, Count));\n}\n\n//\n// Format\n//\n\ntypedef enum _PH_FORMAT_TYPE\n{\n    CharFormatType,\n    StringFormatType,\n    StringZFormatType,\n    MultiByteStringFormatType,\n    MultiByteStringZFormatType,\n    Int32FormatType,\n    Int64FormatType,\n    IntPtrFormatType,\n    UInt32FormatType,\n    UInt64FormatType,\n    UIntPtrFormatType,\n    SingleFormatType,\n    DoubleFormatType,\n    SizeFormatType,\n    FormatTypeMask = 0x3f,\n\n    /** If not specified, for floating-point 6 is assumed **/\n    FormatUsePrecision = 0x40,\n    /** If not specified, ' ' is assumed */\n    FormatUsePad = 0x80,\n    /** If not specified, 10 is assumed */\n    FormatUseRadix = 0x100,\n    /** If not specified, the default value is assumed */\n    FormatUseParameter = 0x200,\n\n    //\n    // Floating-point flags\n    //\n\n    /** Use standard form instead of normal form */\n    FormatStandardForm = 0x1000,\n    /** Use hexadecimal form instead of normal form */\n    FormatHexadecimalForm = 0x2000,\n    /** Reserved */\n    FormatForceDecimalPoint = 0x4000,\n    /** Trailing zeros and possibly the decimal point are trimmed */\n    FormatCropZeros = 0x8000,\n\n    //\n    // Floating-point and integer flags\n    //\n\n    /** Group digits (with floating-point, only works when in normal form) */\n    FormatGroupDigits = 0x10000,\n    /** Always insert a prefix, '+' for positive and '-' for negative */\n    FormatPrefixSign = 0x20000,\n    /**\n     * Pad left with zeros, taking into consideration the sign. Width must be specified.\n     * Format*Align cannot be used in conjunction with this flag. If FormatGroupDigits is specified,\n     * this flag is ignored.\n     */\n    FormatPadZeros = 0x40000,\n\n    //\n    // General flags\n    //\n\n    /** Make characters uppercase (only available for some types) */\n    FormatUpperCase = 0x20000000,\n    /** Applies right alignment. Width must be specified. */\n    FormatRightAlign = 0x40000000,\n    /** Applies left alignment. Width must be specified. */\n    FormatLeftAlign = 0x80000000,\n} PH_FORMAT_TYPE;\n\n/** Describes an element to be formatted to a string. */\ntypedef struct _PH_FORMAT\n{\n    /** Specifies the type of the element and optional flags. */\n    ULONG Type;\n    /**\n     * The precision of the element. The meaning of this field depends on the element type. For\n     * \\a Double and \\a Size, this field specifies the number of decimal points to include.\n     */\n    USHORT Precision;\n    /**\n     * The width of the element. This field specifies the minimum number of characters to output.\n     * The remaining space is padded with either spaces, zeros, or a custom character.\n     */\n    USHORT Width;\n    /** The pad character. */\n    WCHAR Pad;\n    /**\n     * The meaning of this field depends on the element type. For integer types, this field\n     * specifies the base to convert the number into. For \\a Size, this field specifies the maximum\n     * size unit.\n     */\n    UCHAR Radix;\n    /**\n     * The meaning of this field depends on the element type. For \\a Size, this field specifies the\n     * minimum size unit.\n     */\n    UCHAR Parameter;\n    union\n    {\n        WCHAR Char;\n        PH_STRINGREF String;\n        PWSTR StringZ;\n        PH_BYTESREF MultiByteString;\n        PSTR MultiByteStringZ;\n        LONG Int32;\n        LONG64 Int64;\n        LONG_PTR IntPtr;\n        ULONG UInt32;\n        ULONG64 UInt64;\n        ULONG_PTR UIntPtr;\n        FLOAT Single;\n        DOUBLE Double;\n        ULONG64 Size;\n    } u;\n} PH_FORMAT, *PPH_FORMAT;\n\n// Convenience functions\n\nFORCEINLINE\nVOID\nPhInitFormatC(\n    _Out_ PPH_FORMAT Format,\n    _In_ WCHAR Char\n    )\n{\n    Format->Type = CharFormatType;\n    Format->u.Char = Char;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatS(\n    _Out_ PPH_FORMAT Format,\n    _In_ PCWSTR String\n    )\n{\n    Format->Type = StringFormatType;\n    PhInitializeStringRef(&Format->u.String, String);\n}\n\nFORCEINLINE\nVOID\nPhInitFormatSR(\n    _Out_ PPH_FORMAT Format,\n    _In_ PH_STRINGREF String\n    )\n{\n    Format->Type = StringFormatType;\n    Format->u.String = String;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatUCS(\n    _Out_ PPH_FORMAT Format,\n    _In_ PCUNICODE_STRING String\n    )\n{\n    Format->Type = StringFormatType;\n    PhUnicodeStringToStringRef(String, &Format->u.String);\n}\n\nFORCEINLINE\nVOID\nPhInitFormatMultiByteS(\n    _Out_ PPH_FORMAT Format,\n    _In_ PCSTR String\n    )\n{\n    Format->Type = MultiByteStringFormatType;\n    PhInitializeBytesRef(&Format->u.MultiByteString, String);\n}\n\nFORCEINLINE\nVOID\nPhInitFormatD(\n    _Out_ PPH_FORMAT Format,\n    _In_ LONG Int32\n    )\n{\n    Format->Type = Int32FormatType;\n    Format->u.Int32 = Int32;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatU(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG UInt32\n    )\n{\n    Format->Type = UInt32FormatType;\n    Format->u.UInt32 = UInt32;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatX(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG UInt32\n    )\n{\n    Format->Type = UInt32FormatType | FormatUseRadix;\n    Format->u.UInt32 = UInt32;\n    Format->Radix = 16;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatI64D(\n    _Out_ PPH_FORMAT Format,\n    _In_ LONG64 Int64\n    )\n{\n    Format->Type = Int64FormatType;\n    Format->u.Int64 = Int64;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatI64U(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG64 UInt64\n    )\n{\n    Format->Type = UInt64FormatType;\n    Format->u.UInt64 = UInt64;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatI64UGroupDigits(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG64 UInt64\n    )\n{\n    Format->Type = UInt64FormatType | FormatGroupDigits;\n    Format->u.UInt64 = UInt64;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatI64UWithWidth(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG64 UInt64,\n    _In_ USHORT Width\n    )\n{\n    Format->Type = UInt64FormatType | FormatPadZeros;\n    Format->u.UInt64 = UInt64;\n    Format->Width = Width;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatI64X(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG64 UInt64\n    )\n{\n    Format->Type = UInt64FormatType | FormatUseRadix;\n    Format->u.UInt64 = UInt64;\n    Format->Radix = 16;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatI64XWithWidth(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG64 UInt64,\n    _In_ USHORT Width\n    )\n{\n    Format->Type = UInt64FormatType | FormatUseRadix | FormatPadZeros;\n    Format->u.UInt64 = UInt64;\n    Format->Radix = 16;\n    Format->Width = Width;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatI64XPadZeroes(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG64 UInt64,\n    _In_ USHORT Width\n    )\n{\n    Format->Type = UInt64FormatType | FormatUseRadix | FormatPadZeros;\n    Format->u.UInt64 = UInt64;\n    Format->Radix = 16;\n    Format->Width = Width;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatIU(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG_PTR UIntPtr\n    )\n{\n    Format->Type = UIntPtrFormatType;\n    Format->u.UIntPtr = UIntPtr;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatIX(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG_PTR UIntPtr\n    )\n{\n    Format->Type = UIntPtrFormatType | FormatUseRadix;\n    Format->u.UIntPtr = UIntPtr;\n    Format->Radix = 16;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatIXPadZeros(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG_PTR UIntPtr\n    )\n{\n    Format->Type = UIntPtrFormatType | FormatUseRadix | FormatPadZeros;\n    Format->u.UIntPtr = UIntPtr;\n    Format->Radix = 16;\n    Format->Width = sizeof(ULONG_PTR) * 2;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatF(\n    _Out_ PPH_FORMAT Format,\n    _In_ FLOAT Single,\n    _In_ USHORT Precision\n    )\n{\n    Format->Type = SingleFormatType | FormatUsePrecision;\n    Format->u.Single = Single;\n    Format->Precision = Precision;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatFD(\n    _Out_ PPH_FORMAT Format,\n    _In_ DOUBLE Double,\n    _In_ USHORT Precision\n    )\n{\n    Format->Type = DoubleFormatType | FormatUsePrecision;\n    Format->u.Double = Double;\n    Format->Precision = Precision;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatE(\n    _Out_ PPH_FORMAT Format,\n    _In_ DOUBLE Double,\n    _In_ USHORT Precision\n    )\n{\n    Format->Type = DoubleFormatType | FormatStandardForm | FormatUsePrecision;\n    Format->u.Double = Double;\n    Format->Precision = Precision;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatA(\n    _Out_ PPH_FORMAT Format,\n    _In_ DOUBLE Double,\n    _In_ USHORT Precision\n    )\n{\n    Format->Type = DoubleFormatType | FormatHexadecimalForm | FormatUsePrecision;\n    Format->u.Double = Double;\n    Format->Precision = Precision;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatSize(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG64 Size\n    )\n{\n    Format->Type = SizeFormatType;\n    Format->u.Size = Size;\n}\n\nFORCEINLINE\nVOID\nPhInitFormatSizeWithPrecision(\n    _Out_ PPH_FORMAT Format,\n    _In_ ULONG64 Size,\n    _In_ USHORT Precision\n    )\n{\n    Format->Type = SizeFormatType | FormatUsePrecision;\n    Format->u.Size = Size;\n    Format->Precision = Precision;\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormat(\n    _In_reads_(Count) PPH_FORMAT Format,\n    _In_ ULONG Count,\n    _In_opt_ SIZE_T InitialCapacity\n    );\n\nFORCEINLINE\nPPH_STRING\nPhaFormat(\n    _In_reads_(Count) PPH_FORMAT Format,\n    _In_ ULONG Count,\n    _In_opt_ SIZE_T InitialCapacity\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhFormat(Format, Count, InitialCapacity));\n}\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhFormatToBuffer(\n    _In_reads_(Count) PPH_FORMAT Format,\n    _In_ ULONG Count,\n    _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFormatSingleToUtf8(\n    _In_ FLOAT Value,\n    _In_ ULONG Type,\n    _In_ LONG Precision,\n    _Out_writes_bytes_(BufferLength) PSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFormatDoubleToUtf8(\n    _In_ DOUBLE Value,\n    _In_ ULONG Type,\n    _In_ LONG Precision,\n    _Out_writes_bytes_(BufferLength) PSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhIntegerToUtf8Buffer(\n    _In_ LONG64 Integer,\n    _In_opt_ ULONG Base,\n    _In_ BOOLEAN Signed,\n    _Out_writes_bytes_(BufferLength) PSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\n//\n// Errors\n//\n\n#define HRESULT_CUSTOMER(hr) (((ULONG)(hr) >> 29) & 0x1)\n#define HRESULT_NTSTATUS(hr) (((ULONG)(hr) >> 28) & 0x1)\n\nPHLIBAPI\nULONG\nNTAPI\nPhNtStatusToDosError(\n    _In_ NTSTATUS Status\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhNtStatusToServiceStatus(\n    _In_ NTSTATUS Status\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDosErrorToNtStatus(\n    _In_ ULONG DosError\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhNtStatusFileNotFound(\n    _In_ NTSTATUS Status\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhNtStatusFromHResult(\n    _In_ HRESULT Result\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetLastWin32ErrorAsNtStatus(\n    VOID\n    )\n{\n    return PhDosErrorToNtStatus(PhGetLastError());\n}\n\n//\n// Generic tree definitions\n//\n\ntypedef enum _PH_TREE_ENUMERATION_ORDER\n{\n    TreeEnumerateInOrder,\n    TreeEnumerateInReverseOrder\n} PH_TREE_ENUMERATION_ORDER;\n\n#define PhIsLeftChildElement(Links) ((Links)->Parent->Left == (Links))\n#define PhIsRightChildElement(Links) ((Links)->Parent->Right == (Links))\n\n//\n// avltree\n//\n\ntypedef struct _PH_AVL_LINKS\n{\n    struct _PH_AVL_LINKS *Parent;\n    struct _PH_AVL_LINKS *Left;\n    struct _PH_AVL_LINKS *Right;\n    LONG Balance;\n} PH_AVL_LINKS, *PPH_AVL_LINKS;\n\ntypedef _Function_class_(PH_AVL_TREE_COMPARE_FUNCTION)\nLONG NTAPI PH_AVL_TREE_COMPARE_FUNCTION(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    );\ntypedef PH_AVL_TREE_COMPARE_FUNCTION* PPH_AVL_TREE_COMPARE_FUNCTION;\n\ntypedef struct _PH_AVL_TREE\n{\n    PH_AVL_LINKS Root; // Right contains real root\n    ULONG Count;\n\n    PPH_AVL_TREE_COMPARE_FUNCTION CompareFunction;\n} PH_AVL_TREE, *PPH_AVL_TREE;\n\n#define PH_AVL_TREE_INIT(CompareFunction) { { NULL, NULL, NULL, 0 }, 0, CompareFunction }\n\n#define PhRootElementAvlTree(Tree) ((Tree)->Root.Right)\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeAvlTree(\n    _Out_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_TREE_COMPARE_FUNCTION CompareFunction\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhAddElementAvlTree(\n    _Inout_ PPH_AVL_TREE Tree,\n    _Out_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveElementAvlTree(\n    _Inout_ PPH_AVL_TREE Tree,\n    _Inout_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhFindElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhLowerBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhUpperBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhLowerDualBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhUpperDualBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhMinimumElementAvlTree(\n    _In_ PPH_AVL_TREE Tree\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhMaximumElementAvlTree(\n    _In_ PPH_AVL_TREE Tree\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhSuccessorElementAvlTree(\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhPredecessorElementAvlTree(\n    _In_ PPH_AVL_LINKS Element\n    );\n\ntypedef _Function_class_(PH_ENUM_AVL_TREE_CALLBACK)\nBOOLEAN NTAPI PH_ENUM_AVL_TREE_CALLBACK(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_AVL_TREE_CALLBACK *PPH_ENUM_AVL_TREE_CALLBACK;\n\nPHLIBAPI\nVOID\nNTAPI\nPhEnumAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PH_TREE_ENUMERATION_ORDER Order,\n    _In_ PPH_ENUM_AVL_TREE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/phconfig.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2025\n *\n */\n\n#ifndef _PH_PHCONFIG_H\n#define _PH_PHCONFIG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nEXTERN_C PVOID PhInstanceHandle;\nEXTERN_C PCWSTR PhApplicationName;\nEXTERN_C HANDLE PhHeapHandle;\nEXTERN_C RTL_OSVERSIONINFOEX PhOsVersion;\nEXTERN_C ULONG WindowsVersion;\n\n#define WINDOWS_ANCIENT 0\n#define WINDOWS_XP 51 // August, 2001\n#define WINDOWS_SERVER_2003 52 // April, 2003\n#define WINDOWS_VISTA 60 // November, 2006\n#define WINDOWS_7 61 // July, 2009\n#define WINDOWS_8 62 // August, 2012\n#define WINDOWS_8_1 63 // August, 2013\n#define WINDOWS_10 100 // July, 2015            // Version 1507, Build 10240\n#define WINDOWS_10_TH2 101 // November, 2015    // Version 1511, Build 10586\n#define WINDOWS_10_RS1 102 // August, 2016      // Version 1607, Build 14393\n#define WINDOWS_10_RS2 103 // April, 2017       // Version 1703, Build 15063\n#define WINDOWS_10_RS3 104 // October, 2017     // Version 1709, Build 16299\n#define WINDOWS_10_RS4 105 // April, 2018       // Version 1803, Build 17134\n#define WINDOWS_10_RS5 106 // November, 2018    // Version 1809, Build 17763\n#define WINDOWS_10_19H1 107 // May, 2019        // Version 1903, Build 18362\n#define WINDOWS_10_19H2 108 // November, 2019   // Version 1909, Build 18363\n#define WINDOWS_10_20H1 109 // May, 2020        // Version 2004, Build 19041\n#define WINDOWS_10_20H2 110 // October, 2020    // Build 19042\n#define WINDOWS_10_21H1 111 // May, 2021        // Build 19043\n#define WINDOWS_10_21H2 112 // November, 2021   // Build 19044\n#define WINDOWS_10_22H2 113 // October, 2022    // Build 19045\n#define WINDOWS_11 114 // October, 2021         // Build 22000\n#define WINDOWS_11_22H2 115 // September, 2022  // Build 22621\n#define WINDOWS_11_23H2 116 // October, 2023    // Build 22631\n#define WINDOWS_11_24H2 117 // October, 2024    // Build 26100\n#define WINDOWS_11_25H2 118 // October, 2025    // Build 26200\n#define WINDOWS_11_26H1 119                     // Build 28000\n#define WINDOWS_MAX WINDOWS_11_26H1\n#define WINDOWS_NEW ULONG_MAX\n\n#ifdef DEBUG\n#define dprintf(format, ...) DbgPrint(format __VA_OPT__(,) __VA_ARGS__)\n#else\n#define dprintf(format, ...)\n#endif\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializePhLib(\n    _In_ PCWSTR ApplicationName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsExecutingInWow64(\n    VOID\n    );\n\n_Analysis_noreturn_\nDECLSPEC_NORETURN\nVOID\nNTAPI\nPhExitApplication(\n    _In_ NTSTATUS Status\n    );\n\n// Processor group support (dmex)\n\ntypedef struct _PH_SYSTEM_BASIC_INFORMATION\n{\n    USHORT PageSize;\n    USHORT NumberOfProcessors;\n    ULONG MaximumTimerResolution;\n    ULONG NumberOfPhysicalPages;\n    ULONG AllocationGranularity;\n    ULONG_PTR MaximumUserModeAddress;\n    KAFFINITY ActiveProcessorsAffinityMask;\n} PH_SYSTEM_BASIC_INFORMATION, *PPH_SYSTEM_BASIC_INFORMATION;\n\nPHLIBAPI extern PH_SYSTEM_BASIC_INFORMATION PhSystemBasicInformation;\n\ntypedef struct _PH_SYSTEM_PROCESSOR_INFORMATION\n{\n    BOOLEAN SingleProcessorGroup;\n    USHORT NumberOfProcessors;\n    USHORT NumberOfProcessorGroups;\n    PUSHORT ActiveProcessorCount;\n    PKAFFINITY ActiveProcessorsAffinityMasks;\n} PH_SYSTEM_PROCESSOR_INFORMATION, *PPH_SYSTEM_PROCESSOR_INFORMATION;\n\nextern PH_SYSTEM_PROCESSOR_INFORMATION PhSystemProcessorInformation;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/phconsole.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2024\n *\n */\n\n#ifndef _PH_CONSOLE_H\n#define _PH_CONSOLE_H\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAttachConsole(\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhGetStdHandle(\n    _In_ ULONG StdHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeConsole(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetConsoleProcessList(\n    _In_ HANDLE ProcessId,\n    _In_ ULONG ProcessCount,\n    _Out_writes_(ProcessCount) PULONG ProcessList,\n    _Out_ PULONG ProcessTotal\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConsoleSetForeground(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN Foreground\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConsoleSetWindow(\n    _In_ HANDLE ProcessID,\n    _In_ HANDLE ThreadId,\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConsoleEndTask(\n    _In_ HANDLE ProcessId,\n    _In_ HWND WindowHandle\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/phdata.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *     dmex    2023-2026\n *\n */\n\n#ifndef _PH_PHDATA_H\n#define _PH_PHDATA_H\n\nEXTERN_C_START\n\n//\n// SIDs\n//\n\nextern CONST SID PhSeNobodySid;\n\nextern CONST SID PhSeEveryoneSid;\n\nextern CONST SID PhSeLocalSid;\n\nextern CONST SID PhSeCreatorOwnerSid;\nextern CONST SID PhSeCreatorGroupSid;\n\nextern CONST SID PhSeDialupSid;\nextern CONST SID PhSeNetworkSid;\nextern CONST SID PhSeBatchSid;\nextern CONST SID PhSeInteractiveSid;\nextern CONST SID PhSeServiceSid;\nextern CONST SID PhSeAnonymousLogonSid;\nextern CONST SID PhSeProxySid;\nextern CONST SID PhSeAuthenticatedUserSid;\nextern CONST SID PhSeRestrictedCodeSid;\nextern CONST SID PhSeTerminalServerUserSid;\nextern CONST SID PhSeRemoteInteractiveLogonSid;\nextern CONST SID PhSeLocalSystemSid;\nextern CONST SID PhSeLocalServiceSid;\nextern CONST SID PhSeNetworkServiceSid;\n\nPSID PhSeAdministratorsSid(\n    VOID\n    );\n\nPSID PhSeUsersSid(\n    VOID\n    );\n\nPSID PhSeAnyPackageSid(\n    VOID\n    );\n\nPSID PhSeInternetExplorerSid(\n    VOID\n    );\n\nPSID PhSeCloudActiveDirectorySid(\n    VOID\n    );\n\nPSID PhSeLogonIdSid(\n    _In_ ULONG LogonId\n    );\n\n//\n// Unicode\n//\n\nextern CONST PH_STRINGREF PhUnicodeByteOrderMark;\n\n//\n// Characters\n//\n\nextern CONST BOOLEAN PhCharIsPrintable[256];\nextern CONST BOOLEAN PhCharIsPrintableEx[256];\nextern CONST LONG PhCharToInteger[256];\nextern CONST CHAR PhIntegerToChar[69];\nextern CONST CHAR PhIntegerToCharUpper[69];\n\n//\n// UTF-16\n//\n\nextern CONST BOOLEAN PhIsUTF16HighSurrogateHighByte[256];\nextern CONST BOOLEAN PhIsUTF16LowSurrogateHighByte[256];\nextern CONST BOOLEAN PhIsUTF16StandaloneHighByte[256];\nextern CONST BOOLEAN PhIsUTF16PrintableHighByte[256];\n\n//\n// CRC32\n//\n\nextern CONST ULONG PhCrc32Table[256];\n\n//\n// Enums\n//\n\nextern CONST PH_STRINGREF PhIoPriorityHintNames[];\nextern CONST PH_STRINGREF PhPagePriorityNames[];\nextern CONST PH_STRINGREF PhKThreadStateNames[];\nextern CONST PH_STRINGREF PhKWaitReasonNames[];\n\n//\n// Aliases\n//\n\nextern CONST PH_STRINGREF PhHalFileAliasList[];\nextern CONST PH_STRINGREF PhKernelFileAliasList[];\nextern CONST PH_STRINGREF PhSecureKernelFileAliasList[];\nextern CONST PH_STRINGREF PhHypervisorFileAliasList[];\nextern CONST PH_STRINGREF PhOsLoaderFileAliasList[];\nextern CONST PH_STRINGREF PhOsBootFileAliasList[];\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/phfirmware.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025\n *\n */\n\n#ifndef _PH_PHSMBIOS_H\n#define _PH_PHSMBIOS_H\n\n#include <smbios.h>\n\nEXTERN_C_START\n\ntypedef enum _PH_VIRTUAL_STATUS\n{\n    PhVirtualStatusNotCapable = 0,\n    PhVirtualStatusVirtualMachine = 1,\n    PhVirtualStatusEnabledHyperV = 2,\n    PhVirtualStatusEnabledFirmware = 3,\n    //PhVirtualStatusUnknown = 4,\n    PhVirtualStatusDisabledWithHyperV = 5,\n    PhVirtualStatusDisabled = 6,\n} PH_VIRTUAL_STATUS, *PPH_VIRTUAL_STATUS;\n\nPHLIBAPI\nPH_VIRTUAL_STATUS\nNTAPI\nPhGetVirtualStatus(\n    VOID\n    );\n\n#define PH_SMBIOS_CONTAINS_FIELD(Entry, Item, Field) \\\n    (RTL_CONTAINS_FIELD(&(Entry)->Item, (Entry)->Header.Length, Field))\n#define PH_SMBIOS_CONTAINS_STRING(Entry, Item, Field) \\\n    (PH_SMBIOS_CONTAINS_FIELD(Entry, Item, Field) && \\\n     (Entry)->Item.Field != SMBIOS_INVALID_STRING)\n\ntypedef union _PH_SMBIOS_ENTRY\n{\n    SMBIOS_HEADER Header;\n    SMBIOS_FIRMWARE_INFORMATION Firmware;\n    SMBIOS_SYSTEM_INFORMATION System;\n    SMBIOS_BASEBOARD_INFORMATION Baseboard;\n    SMBIOS_CHASSIS_INFORMATION Chassis;\n    SMBIOS_PROCESSOR_INFORMATION Processor;\n    SMBIOS_MEMORY_CONTROLLER_INFORMATION MemoryController;\n    SMBIOS_MEMORY_MODULE_INFORMATION MemoryModule;\n    SMBIOS_CACHE_INFORMATION Cache;\n    SMBIOS_PORT_CONNECTOR_INFORMATION PortConnector;\n    SMBIOS_SYSTEM_SLOT_INFORMATION SystemSlot;\n    SMBIOS_ON_BOARD_DEVICE_INFORMATION OnBoardDevice;\n    SMBIOS_OEM_STRING_INFORMATION OEMString;\n    SMBIOS_SYSTEM_CONFIGURATION_OPTION_INFORMATION SystemConfigurationOption;\n    SMBIOS_FIRMWARE_LANGUAGE_INFORMATION FirmwareLanguage;\n    SMBIOS_GROUP_ASSOCIATION_INFORMATION GroupAssociation;\n    SMBIOS_SYSTEM_EVENT_LOG_INFORMATION EventLog;\n    SMBIOS_PHYSICAL_MEMORY_ARRAY_INFORMATION PhysicalMemoryArray;\n    SMBIOS_MEMORY_DEVICE_INFORMATION MemoryDevice;\n    SMBIOS_32_BIT_MEMORY_ERROR_INFORMATION MemoryError32;\n    SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS_INFORMATION MemoryArrayMappedAddress;\n    SMBIOS_MEMORY_DEVICE_MAPPED_ADDRESS_INFORMATION MemoryDeviceMappedAddress;\n    SMBIOS_BUILT_IN_POINTING_DEVICE_INFORMATION BuiltInPointingDevice;\n    SMBIOS_PORTABLE_BATTERY_INFORMATION PortableBattery;\n    SMBIOS_SYSTEM_RESET_INFORMATION SystemReset;\n    SMBIOS_HARDWARE_SECURITY_INFORMATION HardwareSecurity;\n    SMBIOS_SYSTEM_POWER_CONTROLS_INFORMATION SystemPowerControls;\n    SMBIOS_VOLTAGE_PROBE_INFORMATION VoltageProbe;\n    SMBIOS_COOLING_DEVICE_INFORMATION CoolingDevice;\n    SMBIOS_TEMPERATURE_PROBE_INFORMATION TemperatureProbe;\n    SMBIOS_ELECTRICAL_CURRENT_PROBE_INFORMATION ElectricalCurrentProbe;\n    SMBIOS_OUT_OF_BAND_REMOTE_ACCESS_INFORMATION OutOfBandRemoteAccess;\n    SMBIOS_SYSTEM_BOOT_INFORMATION SystemBoot;\n    SMBIOS_64_BIT_MEMORY_ERROR_INFORMATION MemoryError64;\n    SMBIOS_MANAGEMENT_DEVICE_INFORMATION ManagementDevice;\n    SMBIOS_MANAGEMENT_DEVICE_COMPONENT_INFORMATION ManagementDeviceComponent;\n    SMBIOS_MANAGEMENT_DEVICE_THRESHOLD_INFORMATION ManagementDeviceThreshold;\n    SMBIOS_MEMORY_CHANNEL_INFORMATION MemoryChannel;\n    SMBIOS_IPMI_DEVICE_INFORMATION IPMIDevice;\n    SMBIOS_SYSTEM_POWER_SUPPLY_INFORMATION SystemPowerSupply;\n    SMBIOS_ADDITIONAL_INFORMATION AdditionalInformation;\n    SMBIOS_ONBOARD_DEVICE_INFORMATION OnboardDevice;\n    SMBIOS_MCHI_INFORMATION MCHInterface;\n    SMBIOS_TPM_DEVICE_INFORMATION TPMDevice;\n    SMBIOS_PROCESSOR_ADDITIONAL_INFORMATION ProcessorAdditional;\n    SMBIOS_FIRMWARE_INVENTORY_INFORMATION FirmwareInventory;\n    SMBIOS_STRING_PROPERTY StringProperty;\n    SMBIOS_INACTIVE Inactive;\n    SMBIOS_END_OF_TABLE EndOfTable;\n} PH_SMBIOS_ENTRY, *PPH_SMBIOS_ENTRY;\n\ntypedef\n_Function_class_(PH_ENUM_SMBIOS_CALLBACK)\nBOOLEAN\nNTAPI\nPH_ENUM_SMBIOS_CALLBACK(\n    _In_ ULONG_PTR EnumHandle,\n    _In_ UCHAR MajorVersion,\n    _In_ UCHAR MinorVersion,\n    _In_ PPH_SMBIOS_ENTRY Entry,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_SMBIOS_CALLBACK* PPH_ENUM_SMBIOS_CALLBACK;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumSMBIOS(\n    _In_ PPH_ENUM_SMBIOS_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSMBIOSString(\n    _In_ ULONG_PTR EnumHandle,\n    _In_ UCHAR Index,\n    _Out_ PPH_STRING* String\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/phintrin.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s    2023\n *     dmex     2023\n *\n */\n\n/**\n * Intrinsics and SIMD wrapper header for cross-platform support.\n *\n * This header provides a unified interface for SIMD (Single Instruction Multiple Data) operations\n * and intrinsic functions across different platforms and architectures. It abstracts platform-specific\n * differences between ARM64 (using NEON) and x86/x64 (using SSE2, SSE4.2, AVX, AVX2) instruction sets.\n *\n * Key Features:\n * - Population count (bit counting) operations for 32-bit and 64-bit integers\n * - 128-bit integer vector operations (load, store, compare, arithmetic, bitwise)\n * - 128-bit floating-point vector operations (arithmetic, conversion, manipulation)\n * - Cross-platform type definitions (PH_INT128, PH_FLOAT128)\n * - ISA (Instruction Set Architecture) feature detection for x86/x64\n *\n * Platform Support:\n * - ARM64: Uses ARM NEON intrinsics via <arm_acle.h>\n * - x86/x64: Uses SSE2, SSE4.2, AVX, AVX2 intrinsics via <intrin.h>\n *\n * Design Patterns:\n * - All functions are marked FORCEINLINE for performance-critical operations\n * - Conditional compilation (#ifdef _ARM64_) selects appropriate intrinsics per platform\n * - Operations support various element sizes: 8-bit, 16-bit, 32-bit, and 64-bit lanes\n * - Memory operations support both aligned and unaligned access variants\n *\n * \\note Runtime ISA feature detection on x86/x64 uses MSCRT-provided __isa_available and __isa_enabled variables.\n * \\warning Some operations require specific CPU features (SSE4.2 for popcnt, AVX2 for advanced operations).\n */\n\n#ifndef _PH_PHINTRIN_H\n#define _PH_PHINTRIN_H\n\n#include <intrin.h>\n\n#if defined(_M_ARM64) && defined(__clang__)\n#include <arm_acle.h>\n#endif\n\n#ifdef _ARM64_\n#define PhHasIntrinsics TRUE\n#define PhHasPopulationCount TRUE\n#define PhHasAVX FALSE\n#else\n/**\n * @var __isa_available\n * \n * External variable indicating the availability of ISA (Instruction Set Architecture) features.\n * \n * \\note This is an external variable initialized by the MSCRT (Microsoft C Runtime).\n */\nextern int __isa_available;\n#define ISA_AVAILABLE_X86 0\n#define ISA_AVAILABLE_SSE2 1\n#define ISA_AVAILABLE_SSE42 2\n#define ISA_AVAILABLE_AVX 3\n#define ISA_AVAILABLE_ENFSTRG 4\n#define ISA_AVAILABLE_AVX2 5\n#define ISA_AVAILABLE_AVX512 6\n\n/**\n * @var __isa_enabled\n *\n * External variable indicating which ISA (Instruction Set Architecture) \n * extensions are enabled and available on the current system (e.g., SSE, AVX, etc.).\n * \n * \\note This is an external variable initialized by the MSCRT (Microsoft C Runtime).\n */\nextern long __isa_enabled;\n#define ISA_ENABLED_X86 0x00000001\n#define ISA_ENABLED_SSE2 0x00000002\n#define ISA_ENABLED_SSE42 0x00000004\n#define ISA_ENABLED_AVX 0x00000008\n//#define ISA_ENABLED_ENFSTRG 0x00000010\n#define ISA_ENABLED_AVX2 0x00000020\n#define ISA_ENABLED_AVX512 0x00000040\n\n#ifdef _M_IX86\n#define PhHasIntrinsics \\\n    FlagOn(__isa_enabled, ISA_ENABLED_SSE2)\n#else\n#define PhHasIntrinsics TRUE\n#endif\n#define PhHasPopulationCount \\\n    FlagOn(__isa_enabled, ISA_ENABLED_SSE42)\n#define PhHasAVX \\\n    FlagOn(__isa_enabled, ISA_ENABLED_AVX2)\n#define PhHasAVX512 \\\n    FlagOn(__isa_enabled, ISA_ENABLED_AVX512)\n#endif\n\n/**\n * Counts the number of set bits in a 32-bit unsigned integer.\n *\n * This function calculates the population count (Hamming weight) of the given\n * 32-bit value, returning the total number of '1' bits present in its binary\n * representation.\n *\n * \\param[in] Value The 32-bit unsigned integer to count bits from.\n * \\return The number of set bits in the input value.\n * \\remarks\n * On ARM64 platforms, this function uses the native _CountOneBits intrinsic.\n * On other platforms (x86/x64), it uses the SSE4.2 _mm_popcnt_u32 intrinsic.\n * Both provide efficient hardware-accelerated bit counting when available.\n */\nFORCEINLINE\nULONG\nPhPopulationCount32(\n    _In_ ULONG Value\n    )\n{\n#ifdef _ARM64_\n    return _CountOneBits(Value);\n#else\n    return (ULONG)_mm_popcnt_u32(Value);\n#endif\n}\n\n#ifdef _WIN64\n/**\n * Counts the number of set bits (population count) in a 64-bit unsigned integer.\n * \n * This function calculates the Hamming weight (number of 1-bits) in the given 64-bit value.\n * It uses platform-specific intrinsics for optimal performance:\n * - On ARM64: uses _CountOneBits64() intrinsic\n * - On other platforms: uses SSE4.2 _mm_popcnt_u64() intrinsic\n * \n * \\param[in] Value The 64-bit unsigned integer to count bits in.\n * \\return The number of set bits (1s) in the Value parameter.\n * \\note This function requires SSE4.2 support on x86/x64 platforms or ARM64 platform.\n * \\see _CountOneBits64, _mm_popcnt_u64\n */\nFORCEINLINE\nULONG64\nPhPopulationCount64(\n    _In_ ULONG64 Value\n    )\n{\n#ifdef _ARM64_\n    return _CountOneBits64(Value);\n#else\n    return (ULONG64)_mm_popcnt_u64(Value);\n#endif\n}\n#endif\n\n#ifdef _ARM64_\ntypedef int64x2_t PH_INT128;\ntypedef float32x4_t PH_FLOAT128;\n#else\ntypedef __m128i PH_INT128;\ntypedef __m128  PH_FLOAT128;\n#endif\n\ntypedef PH_INT128* PPH_INT128;\ntypedef PH_FLOAT128* PPH_FLOAT128;\n\n/**\n * The PhSetZeroINT128 function initializes a 128-bit integer\n * value to zero using platform-specific intrinsic functions.\n * \n * \\return A PH_INT128 value with all bits set to zero.\n */\nFORCEINLINE\nPH_INT128\nPhSetZeroINT128(\n    VOID\n    )\n{\n#ifdef _ARM64_\n    return vdupq_n_s32(0);\n#else\n    return _mm_setzero_si128();\n#endif\n}\n\n/**\n * Loads a 128-bit integer value from an unaligned memory address.\n *\n * This function reads a 128-bit value from memory without requiring the memory\n * address to be aligned.\n *\n * \\param[in] Memory Pointer to the memory location to load from. Does not need to be aligned.\n * \\return A PH_INT128 value loaded from the specified memory address.\n * \\remarks This is useful when the alignment of the source data cannot be guaranteed.\n */\nFORCEINLINE\nPH_INT128\nPhLoadINT128U(\n    _In_reads_bytes_(2 * sizeof(LONG)) PLONG Memory\n    )\n{\n#ifdef _ARM64_\n    return vld1q_s32(Memory);\n#else\n    return _mm_loadu_si128((__m128i const*)Memory);\n#endif\n}\n\n/**\n * Loads a 128-bit integer value from an aligned memory address.\n *\n * \\param[in] Memory Pointer to the memory location to load from. Must be 16-byte aligned.\n * \\return A PH_INT128 value loaded from the specified memory address.\n * \\remarks The memory address must be properly aligned for optimal performance.\n */\nFORCEINLINE\nPH_INT128\nPhLoadINT128(\n    _In_reads_bytes_(2 * sizeof(LONG)) PLONG Memory\n    )\n{\n#ifdef _ARM64_\n    return vld1q_s32(Memory);\n#else\n    return _mm_load_si128((__m128i const*)Memory);\n#endif\n}\n\n/**\n * The PhStoreINT128 function stores a 128-bit integer value to the specified target address.\n *\n * \\param[out] Target A pointer to a memory location where the 128-bit value will be stored.\n * Must be aligned to at least 16 bytes and writable for 16 bytes (2 * sizeof(LONG)).\n * \\param[in] Value The 128-bit integer value to be stored.\n */\nFORCEINLINE\nVOID\nPhStoreINT128(\n    _Out_writes_bytes_(2 * sizeof(LONG)) PLONG Target,\n    _In_ PH_INT128 Value\n    )\n{\n#ifdef _ARM64_\n    vst1q_s32(Target, Value);\n#else\n    _mm_store_si128((__m128i*)Target, Value);\n#endif\n}\n\n/**\n * The PhStoreINT128U function stores a 128-bit integer value to the specified unaligned target address\n * without alignment requirements.\n * \n * \\param[out] Target A pointer to a memory location where the 128-bit value will be stored.\n * The memory does not need to be aligned and must be at least 2 * sizeof(LONG) bytes.\n * \\param[in] Value The 128-bit integer value to store.\n */\nFORCEINLINE\nVOID\nPhStoreINT128U(\n    _Out_writes_bytes_(2 * sizeof(LONG)) PLONG Target,\n    _In_ PH_INT128 Value\n    )\n{\n#ifdef _ARM64_\n    vst1q_s32(Target, Value);\n#else\n    _mm_storeu_si128((__m128i*)Target, Value);\n#endif\n}\n\n/**\n * Compares two 128-bit integers element-wise for equality using 16-bit signed integer elements.\n * \n * \\param Left The left operand as a 128-bit integer.\n * \\param Right The right operand as a 128-bit integer.\n * \\return A 128-bit integer where each 16-bit element is set to all 1s (0xFFFF) if the \n * corresponding elements in Left and Right are equal, or all 0s (0x0000) if they are not equal.\n */\nFORCEINLINE\nPH_INT128\nPhCompareEqINT128by16(\n    _In_ PH_INT128 Left,\n    _In_ PH_INT128 Right\n    )\n{\n#ifdef _ARM64_\n    return vceqq_s16(Left, Right);\n#else\n    return _mm_cmpeq_epi16(Left, Right);\n#endif\n}\n\n/**\n * Compares two 128-bit integer vectors element-wise for equality using 32-bit elements.\n *\n * \\param[in] Left Left operand vector.\n * \\param[in] Right Right operand vector.\n * \\return A PH_INT128 where each 32-bit lane is 0xFFFFFFFF if equal, otherwise 0.\n */\nFORCEINLINE\nPH_INT128\nPhCompareEqINT128by32(\n    _In_ PH_INT128 Left,\n    _In_ PH_INT128 Right\n    )\n{\n#ifdef _ARM64_\n    return vceqq_s32(Left, Right);\n#else\n    return _mm_cmpeq_epi32(Left, Right);\n#endif\n}\n\n/**\n * Creates a movemask from the top bit of each 8-bit lane in a 128-bit vector.\n *\n * \\param[in] Value Input vector.\n * \\return A mask in the low 16 bits where bit i corresponds to the top bit of byte i.\n */\nFORCEINLINE\nULONG\nPhMoveMaskINT128by8(\n    _In_ PH_INT128 Value\n    )\n{\n#ifdef _ARM64_\n    // https://github.com/DLTcollab/sse2neon/blob/master/sse2neon.h\n    uint8x16_t input = Value;\n    uint16x8_t high_bits = vshrq_n_u8(input, 7);\n    uint32x4_t paired16 = vsraq_n_u16(high_bits, high_bits, 7);\n    uint64x2_t paired32 = vsraq_n_u32(paired16, paired16, 14);\n    uint8x16_t paired64 = vsraq_n_u64(paired32, paired32, 28);\n    return vgetq_lane_u8(paired64, 0) | ((int) vgetq_lane_u8(paired64, 8) << 8);\n#else\n    return _mm_movemask_epi8(Value);\n#endif\n}\n\n/**\n * Broadcasts a single float into all lanes of a 128-bit float vector.\n *\n * \\param[in] Value Float value to broadcast.\n * \\return A PH_FLOAT128 containing Value in every lane.\n */\nFORCEINLINE\nPH_FLOAT128\nPhSetFLOAT128bySingle(\n    _In_ FLOAT Value\n    )\n{\n#ifdef _ARM64_\n    return vdupq_n_f32(Value);\n#else\n    return _mm_set1_ps(Value);\n#endif\n}\n\n/**\n * Broadcasts a 16-bit signed integer into all 16-bit lanes of a 128-bit vector.\n *\n * \\param[in] Value 16-bit value to broadcast.\n * \\return A PH_INT128 with Value replicated in each 16-bit lane.\n */\nFORCEINLINE\nPH_INT128\nPhSetINT128by16(\n    _In_ SHORT Value\n    )\n{\n#ifdef _ARM64_\n    return vdupq_n_s16(Value);\n#else\n    return _mm_set1_epi16(Value);\n#endif\n}\n\n/**\n * Broadcasts a 32-bit signed integer into all 32-bit lanes of a 128-bit vector.\n *\n * \\param[in] Value 32-bit value to broadcast.\n * \\return A PH_INT128 with Value replicated in each 32-bit lane.\n */\nFORCEINLINE\nPH_INT128\nPhSetINT128by32(\n    _In_ LONG Value\n    )\n{\n#ifdef _ARM64_\n    return vdupq_n_s32(Value);\n#else\n    return _mm_set1_epi32(Value);\n#endif\n}\n\n/**\n * Broadcasts a 32-bit unsigned integer into all 32-bit lanes of a 128-bit vector.\n *\n * \\param[in] Value 32-bit unsigned value to broadcast.\n * \\return A PH_INT128 with Value replicated in each 32-bit lane.\n */\nFORCEINLINE\nPH_INT128\nPhSetUINT128by32(\n    _In_ ULONG Value\n    )\n{\n#ifdef _ARM64_\n    return vdupq_n_u32(Value);\n#else\n    return _mm_set1_epi32(Value);\n#endif\n}\n\n/**\n * Broadcasts a single float by loading it as a replicated scalar into a 128-bit vector.\n *\n * \\param[in] Value Float value to replicate.\n * \\return A PH_FLOAT128 with Value in every lane.\n */\nFORCEINLINE\nPH_FLOAT128\nPhSetFLOAT128by32(\n    _In_ FLOAT Value\n    )\n{\n#ifdef _ARM64_\n    return vld1q_dup_f32(&Value);\n#else\n    return _mm_load_ps1(&Value);\n#endif\n}\n\n/**\n * Loads four floats from memory into a 128-bit float vector.\n *\n * \\param[in] Memory Pointer to 4 floats (must be readable).\n * \\return A PH_FLOAT128 loaded from Memory.\n */\nFORCEINLINE\nPH_FLOAT128\nPhLoadFLOAT128(\n    _In_reads_bytes_(2 * sizeof(PFLOAT)) PFLOAT Memory\n    )\n{\n#ifdef _ARM64_\n    return vld1q_f32(Memory);\n#else\n    return _mm_load_ps(Memory);\n#endif\n}\n\n/**\n * Adds two 128-bit float vectors lane-wise.\n *\n * \\param[in] A First addend vector.\n * \\param[in] B Second addend vector.\n * \\return The lane-wise sum vector.\n */\nFORCEINLINE\nPH_FLOAT128\nPhAddFLOAT128(\n    _In_ PH_FLOAT128 A,\n    _In_ PH_FLOAT128 B\n    )\n{\n#ifdef _ARM64_\n    return vaddq_f32(A, B);\n#else\n    return _mm_add_ps(A, B);\n#endif\n}\n\n/**\n * Divides one 128-bit floating-point vector by another.\n *\n * \\param Divisor The dividend vector to be divided.\n * \\param Dividend The divisor vector used to divide the Divisor.\n * \\return A PH_FLOAT128 containing the lane-wise results of the division.\n */\nFORCEINLINE\nPH_FLOAT128\nPhDivideFLOAT128(\n    _In_ PH_FLOAT128 Divisor,\n    _In_ PH_FLOAT128 Dividend\n    )\n{\n#ifdef _ARM64_\n    // https://github.com/DLTcollab/sse2neon/blob/master/sse2neon.h\n    float32x4_t recip = vrecpeq_f32(Dividend);\n    recip = vmulq_f32(recip, vrecpsq_f32(recip, Dividend));\n    recip = vmulq_f32(recip, vrecpsq_f32(recip, Dividend));\n    return vmulq_f32(Divisor, recip);\n#else\n    return _mm_div_ps(Divisor, Dividend);\n#endif\n}\n\n/**\n * Returns the lane-wise maximum of two 128-bit float vectors.\n *\n * \\param[in] A First vector.\n * \\param[in] B Second vector.\n * \\return A vector containing the maximum of A and B per lane.\n */\nFORCEINLINE\nPH_FLOAT128\nPhMaxFLOAT128(\n    _In_ PH_FLOAT128 A,\n    _In_ PH_FLOAT128 B\n    )\n{\n#ifdef _ARM64_\n    // https://github.com/DLTcollab/sse2neon/blob/master/sse2neon.h\n#if SSE2NEON_PRECISE_MINMAX\n    float32x4_t _a = A;\n    float32x4_t _b = B;\n    return vbslq_f32(vcgtq_f32(_a, _b), _a, _b);\n#else\n    return vmaxq_f32(A, B);\n#endif\n#else\n    return _mm_max_ps(A, B);\n#endif\n}\n\n/**\n * Multiplies two 128-bit float vectors lane-wise.\n *\n * \\param[in] A First multiplicand vector.\n * \\param[in] B Second multiplicand vector.\n * \\return The lane-wise product vector.\n */\nFORCEINLINE\nPH_FLOAT128\nPhMultiplyFLOAT128(\n    _In_ PH_FLOAT128 A,\n    _In_ PH_FLOAT128 B\n    )\n{\n#ifdef _ARM64_\n    return vmulq_f32(A, B);\n#else\n    return _mm_mul_ps(A, B);\n#endif\n}\n\n/**\n * Stores four floats from a 128-bit vector to memory.\n *\n * \\param[out] Target Destination pointer to 4 floats (writable).\n * \\param[in] Value Vector to store.\n */\nFORCEINLINE\nVOID\nPhStoreFLOAT128(\n    _Out_writes_bytes_(2 * sizeof(FLOAT)) PFLOAT Target,\n    _In_ PH_FLOAT128 Value\n    )\n{\n#ifdef _ARM64_\n    vst1q_f32(Target, Value);\n#else\n    _mm_store_ps(Target, Value);\n#endif\n}\n\n/**\n * Stores the lowest single float lane of a 128-bit vector to memory.\n *\n * \\param[out] Target Destination pointer to a float.\n * \\param[in] Value Vector containing the value to store in lane 0.\n */\nFORCEINLINE\nVOID\nPhStoreFLOAT128LowSingle(\n    _Out_writes_bytes_(2 * sizeof(FLOAT)) PFLOAT Target,\n    _In_ PH_FLOAT128 Value\n    )\n{\n#ifdef _ARM64_\n    vst1q_lane_f32(Target, Value, 0);\n#else\n    _mm_store_ss(Target, Value);\n#endif\n}\n\n/**\n * Returns a 128-bit float vector set to zero.\n *\n * \\return A PH_FLOAT128 with all lanes set to 0.0f.\n */\nFORCEINLINE\nPH_FLOAT128\nPhZeroFLOAT128(\n    VOID\n    )\n{\n#ifdef _ARM64_\n    return vdupq_n_f32(0);\n#else\n    return _mm_setzero_ps();\n#endif\n}\n\n#ifndef _MM_SHUFFLE\n#define _MM_SHUFFLE(fp3,fp2,fp1,fp0) (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | ((fp0)))\n#endif\n\n/**\n * Shuffle/combine lanes from two 128-bit float vectors in the 2,1,0,3 order.\n *\n * \\param[in] A First input vector.\n * \\param[in] B Second input vector.\n * \\return A shuffled PH_FLOAT128 composed of selected lanes from A and B.\n */\nFORCEINLINE\nPH_FLOAT128\nPhShuffleFLOAT128_2103(\n    _In_ PH_FLOAT128 A,\n    _In_ PH_FLOAT128 B\n    )\n{\n#ifdef _ARM64_\n    // https://github.com/DLTcollab/sse2neon/blob/master/sse2neon.h\n    float32x2_t a03 = vget_low_f32(vextq_f32(A, A, 3));\n    float32x2_t b21 = vget_high_f32(vextq_f32(B, B, 3));\n    return vcombine_f32(a03, b21);\n#else\n    return _mm_shuffle_ps(A, B, _MM_SHUFFLE(2, 1, 0, 3));\n#endif\n}\n\n/**\n * Shuffle/combine lanes from two 128-bit float vectors in the 2,3,0,1 order.\n *\n * \\param[in] A First input vector.\n * \\param[in] B Second input vector.\n * \\return A shuffled PH_FLOAT128 composed of selected lanes from A and B.\n */\nFORCEINLINE\nPH_FLOAT128\nPhShuffleFLOAT128_2301(\n    _In_ PH_FLOAT128 A,\n    _In_ PH_FLOAT128 B\n    )\n{\n#ifdef _ARM64_\n    // https://github.com/DLTcollab/sse2neon/blob/master/sse2neon.h\n    float32x2_t a03 = vget_low_f32(vextq_f32(A, A, 3));\n    float32x2_t b21 = vget_high_f32(vextq_f32(B, B, 3));\n    return vcombine_f32(a03, b21);\n#else\n    return _mm_shuffle_ps(A, B, _MM_SHUFFLE(2, 3, 0, 1));\n#endif\n}\n\n/**\n * Shuffle/combine lanes from two 128-bit float vectors in the 1,0,3,2 order.\n *\n * \\param[in] A First input vector.\n * \\param[in] B Second input vector.\n * \\return A shuffled PH_FLOAT128 composed of selected lanes from A and B.\n */\nFORCEINLINE\nPH_FLOAT128\nPhShuffleFLOAT128_1032(\n    _In_ PH_FLOAT128 A,\n    _In_ PH_FLOAT128 B\n    )\n{\n#ifdef _ARM64_\n    // https://github.com/DLTcollab/sse2neon/blob/master/sse2neon.h\n    float32x2_t a03 = vget_low_f32(vextq_f32(A, A, 3));\n    float32x2_t b21 = vget_high_f32(vextq_f32(B, B, 3));\n    return vcombine_f32(a03, b21);\n#else\n    return _mm_shuffle_ps(A, B, _MM_SHUFFLE(1, 0, 3, 2));\n#endif\n}\n/**\n * Shift each 32-bit lane left by a constant count.\n *\n * \\param[in] A Vector to shift.\n * \\param[in] Count Shift count in bits (0-255).\n * \\return The shifted vector.\n */\nFORCEINLINE\nPH_INT128\nPhShiftLeftINT128(\n    _In_ PH_INT128 A,\n    _In_ _In_range_(0, 255) INT32 Count\n    )\n{\n#ifdef _ARM64_\n    return vshlq_s32(A, vdupq_n_s32(Count));\n#else\n    return _mm_slli_epi32(A, Count);\n#endif\n}\n\n/**\n * Shift each 32-bit lane right logically by a constant count.\n *\n * \\param[in] A Vector to shift.\n * \\param[in] Count Shift count in bits (0-255).\n * \\return The shifted vector.\n */\nFORCEINLINE\nPH_INT128\nPhShiftRightINT128(\n    _In_ PH_INT128 A,\n    _In_ _In_range_(0, 255) INT32 Count\n    )\n{\n#ifdef _ARM64_\n    return vshlq_u32(A, vdupq_n_s32(-Count));\n#else\n    return _mm_srli_epi32(A, Count);\n#endif\n}\n\n/**\n * Compares two 128-bit integer vectors lane-wise treating lanes as signed 16-bit values.\n *\n * \\param[in] A Left operand.\n * \\param[in] B Right operand.\n * \\return A mask vector with 0xFFFF in lanes where A > B, otherwise 0.\n */\nFORCEINLINE\nPH_INT128\nPhCompareGtINT128by16(\n    _In_ PH_INT128 A,\n    _In_ PH_INT128 B\n    )\n{\n#ifdef _ARM64_\n    return vcgtq_s16(A, B);\n#else\n    return _mm_cmpgt_epi16(A, B);\n#endif\n}\n\n/**\n * Adds two 128-bit integer vectors lane-wise using 16-bit signed lanes.\n *\n * \\param[in] A First addend.\n * \\param[in] B Second addend.\n * \\return Lane-wise sum vector.\n */\nFORCEINLINE\nPH_INT128\nPhAddINT128by16(\n    _In_ PH_INT128 A,\n    _In_ PH_INT128 B\n    )\n{\n#ifdef _ARM64_\n    return vaddq_s16(A, B);\n#else\n    return _mm_add_epi16(A, B);\n#endif\n}\n\n/**\n * Subtracts two 128-bit integer vectors lane-wise using 16-bit signed lanes.\n *\n * \\param[in] A Minuend.\n * \\param[in] B Subtrahend.\n * \\return Lane-wise difference vector.\n */\nFORCEINLINE\nPH_INT128\nPhSubINT128by16(\n    _In_ PH_INT128 A,\n    _In_ PH_INT128 B\n    )\n{\n#ifdef _ARM64_\n    return vsubq_s16(A, B);\n#else\n    return _mm_sub_epi16(A, B);\n#endif\n}\n\n/**\n * Bitwise AND of two 128-bit integer vectors.\n *\n * \\param[in] A First operand.\n * \\param[in] B Second operand.\n * \\return Result of A & B.\n */\nFORCEINLINE\nPH_INT128\nPhAndINT128(\n    _In_ PH_INT128 A,\n    _In_ PH_INT128 B\n    )\n{\n#ifdef _ARM64_\n    return vandq_s32(A, B);\n#else\n    return _mm_and_si128(A, B);\n#endif\n}\n\n/**\n * Bitwise OR of two 128-bit integer vectors.\n *\n * \\param[in] A First operand.\n * \\param[in] B Second operand.\n * \\return Result of A | B.\n */\nFORCEINLINE\nPH_INT128\nPhOrINT128(\n    _In_ PH_INT128 A,\n    _In_ PH_INT128 B\n    )\n{\n#ifdef _ARM64_\n    return vorrq_s32(A, B);\n#else\n    return _mm_or_si128(A, B);\n#endif\n}\n\n/**\n * Convert 128-bit float vector to unsigned 32-bit integers per lane.\n *\n * \\param[in] A Float vector to convert.\n * \\return A PH_INT128 containing converted unsigned 32-bit integers.\n */\nFORCEINLINE\nPH_INT128\nPhConvertFLOAT128ToUINT128(\n    _In_ PH_FLOAT128 A\n    )\n{\n#ifdef _ARM64_\n    return vcvtq_u32_f32(A);\n#else\n    return _mm_cvtps_epu32(A); // _mm_cvtps_epi32\n#endif\n}\n\n/**\n * Convert 128-bit signed 32-bit integer vector to float per lane.\n *\n * \\param[in] A Integer vector to convert.\n * \\return A PH_FLOAT128 containing converted floats.\n */\nFORCEINLINE\nPH_FLOAT128\nPhConvertINT128ToFLOAT128(\n    _In_ PH_INT128 A\n    )\n{\n#ifdef _ARM64_\n    return vcvtq_f32_s32(A);\n#else\n    return _mm_cvtepi32_ps(A);\n#endif\n}\n\n/**\n * Convert ASCII lower-case letters (a-z) to upper-case (A-Z) for 16-bit lanes.\n *\n * \\param[in] Input Vector containing UTF-16 characters in 16-bit lanes.\n * \\return Vector with ASCII letters converted to upper-case; other values unchanged.\n */\nFORCEINLINE\nPH_INT128\nPhUppercaseLatin1INT128by16(\n    _In_ PH_INT128 Input\n    )\n{\n#ifdef _ARM64_\n    // NEON: convert a-z (0x61-0x7A) and à-þ (0xE0-0xFE) excluding ÷ (0xF7)\n    uint16x8_t ge_a = vcgeq_u16(Input, vdupq_n_u16(0x0061));\n    uint16x8_t le_z = vcleq_u16(Input, vdupq_n_u16(0x007A));\n    uint16x8_t mask1 = vandq_u16(ge_a, le_z);\n    uint16x8_t ge_lat = vcgeq_u16(Input, vdupq_n_u16(0x00E0));\n    uint16x8_t le_lat = vcleq_u16(Input, vdupq_n_u16(0x00FE));\n    uint16x8_t mask2 = vandq_u16(ge_lat, le_lat);\n    uint16x8_t not_div = vceqq_u16(Input, vdupq_n_u16(0x00F7));\n    mask2 = vbicq_u16(mask2, not_div);\n    uint16x8_t final_mask = vorrq_u16(mask1, mask2);\n    return vsubq_u16(Input, vandq_u16(final_mask, vdupq_n_u16(0x0020)));\n#else\n    // SSE2: convert a-z (0x61-0x7A) and à-þ (0xE0-0xFE) excluding ÷ (0xF7)\n    __m128i ge_a = _mm_cmpgt_epi16(Input, _mm_set1_epi16(0x0060));\n    __m128i le_z = _mm_cmpgt_epi16(_mm_set1_epi16(0x007B), Input);\n    __m128i mask1 = _mm_and_si128(ge_a, le_z);\n    __m128i ge_lat = _mm_cmpgt_epi16(Input, _mm_set1_epi16(0x00DF));\n    __m128i le_lat = _mm_cmpgt_epi16(_mm_set1_epi16(0x00FF), Input);\n    __m128i mask2 = _mm_and_si128(ge_lat, le_lat);\n    __m128i is_div = _mm_cmpeq_epi16(Input, _mm_set1_epi16(0x00F7));\n    mask2 = _mm_andnot_si128(is_div, mask2);\n    __m128i final_mask = _mm_or_si128(mask1, mask2);\n    return _mm_sub_epi16(Input, _mm_and_si128(final_mask, _mm_set1_epi16(0x0020)));\n#endif\n}\n\n#ifndef _ARM64_\n/**\n * Convert Latin-1 lowercase letters to upper-case (AVX2).\n *\n * \\param[in] Input 256-bit vector containing UTF-16 characters in 16-bit lanes.\n * \\return Vector with letters converted to upper-case; other values unchanged.\n */\nFORCEINLINE\n__m256i\nPhUppercaseLatin1INT256by16(\n    _In_ __m256i Input\n    )\n{\n    // convert a-z (0x61-0x7A) and à-þ (0xE0-0xFE) excluding ÷ (0xF7)\n    __m256i ge_a = _mm256_cmpgt_epi16(Input, _mm256_set1_epi16(0x0060));\n    __m256i le_z = _mm256_cmpgt_epi16(_mm256_set1_epi16(0x007B), Input);\n    __m256i mask1 = _mm256_and_si256(ge_a, le_z);\n    __m256i ge_lat = _mm256_cmpgt_epi16(Input, _mm256_set1_epi16(0x00DF));\n    __m256i le_lat = _mm256_cmpgt_epi16(_mm256_set1_epi16(0x00FF), Input);\n    __m256i mask2 = _mm256_and_si256(ge_lat, le_lat);\n    __m256i is_div = _mm256_cmpeq_epi16(Input, _mm256_set1_epi16(0x00F7));\n    mask2 = _mm256_andnot_si256(is_div, mask2);\n    __m256i final_mask = _mm256_or_si256(mask1, mask2);\n    return _mm256_sub_epi16(Input, _mm256_and_si256(final_mask, _mm256_set1_epi16(0x0020)));\n}\n#endif\n\nFORCEINLINE\nPH_INT128\nPhUppercaseASCIIINT128by16(\n    _In_ PH_INT128 Input\n    )\n{\n#ifdef _ARM64_\n    // NEON:  convert a-z to A-Z\n    int16x8_t ge_a = vcgeq_s16(Input, vdupq_n_s16(L'a'));\n    int16x8_t le_z = vcleq_s16(Input, vdupq_n_s16(L'z'));\n    int16x8_t mask = vandq_s16(ge_a, le_z);\n    return vsubq_s16(Input, vandq_s16(mask, vdupq_n_s16(0x20)));\n#else\n    // SSE2: convert a-z to A-Z (8 UTF-16 chars)\n    __m128i ge_a = _mm_cmpgt_epi16(Input, _mm_set1_epi16(L'a' - 1));\n    __m128i le_z = _mm_cmpgt_epi16(_mm_set1_epi16(L'z' + 1), Input);\n    __m128i mask = _mm_and_si128(ge_a, le_z);\n    return _mm_sub_epi16(Input, _mm_and_si128(mask, _mm_set1_epi16(0x20)));\n#endif\n}\n\n#ifndef _ARM64_\n/**\n * Convert ASCII lower-case letters (a-z) to upper-case (A-Z) for 16-bit lanes (AVX2).\n *\n * \\param[in] Input 256-bit vector containing UTF-16 characters in 16-bit lanes.\n * \\return Vector with ASCII letters converted to upper-case; other values unchanged.\n */\nFORCEINLINE\n__m256i\nPhUppercaseASCIIINT256by16(\n    _In_ __m256i Input\n    )\n{\n    __m256i ge_a = _mm256_cmpgt_epi16(Input, _mm256_set1_epi16(L'a' - 1));\n    __m256i le_z = _mm256_cmpgt_epi16(_mm256_set1_epi16(L'z' + 1), Input);\n    __m256i mask = _mm256_and_si256(ge_a, le_z);\n    return _mm256_sub_epi16(Input, _mm256_and_si256(mask, _mm256_set1_epi16(0x20)));\n}\n\n/**\n * Convert 8 unsigned 32-bit integers in a 256-bit vector to floats.\n *\n * \\param[in] Value 256-bit integer vector containing 8 uint32 values.\n * \\return A __m256 of floats representing the unsigned conversion of Value.\n */\nFORCEINLINE\n__m256\n_mm256_cvtf_epu32(\n    _In_ __m256i Value\n    )\n{\n    const __m256 mul = _mm256_set1_ps(0x1.0p16f);\n    const __m256i hi = _mm256_srli_epi32(Value, 16);\n    const __m256i lo = _mm256_srli_epi32(_mm256_slli_epi32(Value, 16), 16);\n    const __m256 fHi = _mm256_mul_ps(_mm256_cvtepi32_ps(hi), mul);\n    const __m256 fLo = _mm256_cvtepi32_ps(lo);\n\n    return _mm256_add_ps(fHi, fLo);\n}\n#endif\n\n/**\n * Convert a 128-bit vector of unsigned 32-bit integers to floats accurately.\n *\n * \\param[in] Value Integer vector to convert.\n * \\return Float vector with converted values.\n */\nFORCEINLINE\nPH_FLOAT128\nPhConvertUINT128ToFLOAT128(\n    _In_ PH_INT128 Value\n    )\n{\n    // https://stackoverflow.com/questions/9151711/most-efficient-way-to-convert-vector-of-uint32-to-vector-of-float\n\n    const PH_FLOAT128 mul = PhSetFLOAT128bySingle(0x1.0p16f); // 65536\n\n    // Avoid double rounding by doing two exact conversions of high and low 16-bit segments.\n\n    const PH_INT128 hi = PhShiftRightINT128(Value, 16);\n    const PH_INT128 lo = PhShiftRightINT128(PhShiftLeftINT128(Value, 16), 16); // PhAndINT128(Value, PhSetINT128by32(0x0000FFFF));\n    const PH_FLOAT128 fHi = PhMultiplyFLOAT128(PhConvertINT128ToFLOAT128(hi), mul);\n    const PH_FLOAT128 fLo = PhConvertINT128ToFLOAT128(lo);\n\n    return PhAddFLOAT128(fHi, fLo);\n}\n\n#endif\n"
  },
  {
    "path": "phlib/include/phintrnl.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2023\n *\n */\n\n#ifndef _PH_PHINTRNL_H\n#define _PH_PHINTRNL_H\n\nNTSTATUS PhInitializeRuntimeInformation(\n    VOID\n    );\n\nNTSTATUS PhInitializeSystemInformation(\n    VOID\n    );\n\nNTSTATUS PhInitializeWindowsInformation(\n    VOID\n    );\n\nNTSTATUS PhHeapInitialization(\n    VOID\n    );\n\nNTSTATUS PhInitializeProcessorInformation(\n    VOID\n    );\n\ntypedef struct _PHLIB_STATISTICS_BLOCK\n{\n    // basesup\n    ULONG BaseThreadsCreated;\n    ULONG BaseThreadsCreateFailed;\n    ULONG BaseStringBuildersCreated;\n    ULONG BaseStringBuildersResized;\n\n    // ref\n    ULONG RefObjectsCreated;\n    ULONG RefObjectsDestroyed;\n    ULONG RefObjectsAllocated;\n    ULONG RefObjectsFreed;\n    ULONG RefObjectsAllocatedFromSmallFreeList;\n    ULONG RefObjectsFreedToSmallFreeList;\n    ULONG RefObjectsAllocatedFromTypeFreeList;\n    ULONG RefObjectsFreedToTypeFreeList;\n    ULONG RefObjectsDeleteDeferred;\n    ULONG RefAutoPoolsCreated;\n    ULONG RefAutoPoolsDestroyed;\n    ULONG RefAutoPoolsDynamicAllocated;\n    ULONG RefAutoPoolsDynamicResized;\n\n    // queuedlock\n    ULONG QlBlockSpins;\n    ULONG QlBlockWaits;\n    ULONG QlAcquireExclusiveBlocks;\n    ULONG QlAcquireSharedBlocks;\n\n    // workqueue\n    ULONG WqWorkQueueThreadsCreated;\n    ULONG WqWorkQueueThreadsCreateFailed;\n    ULONG WqWorkItemsQueued;\n} PHLIB_STATISTICS_BLOCK;\n\n#ifdef DEBUG\nextern PHLIB_STATISTICS_BLOCK PhLibStatisticsBlock;\n#endif\n\n#ifdef DEBUG\n#define PHLIB_INC_STATISTIC(Name) (_InterlockedIncrement(&PhLibStatisticsBlock.Name))\n#else\n#define PHLIB_INC_STATISTIC(Name)\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/phnative.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#ifndef _PH_PHNATIVE_H\n#define _PH_PHNATIVE_H\n\nEXTERN_C_START\n\n/** The PID of the interrupt process. */\n#define INTERRUPTS_PROCESS_ID ((HANDLE)(LONG_PTR)-3)\n/** The PID of the dpc process. */\n#define DPCS_PROCESS_ID ((HANDLE)(LONG_PTR)-2)\n/** The PID of the current process. */\n#define CURRENT_PROCESS_ID ((HANDLE)(LONG_PTR)-1)\n/** The PID of the idle process. */\n#define SYSTEM_IDLE_PROCESS_ID ((HANDLE)0)\n/** The PID of the system process. */\n#define SYSTEM_PROCESS_ID ((HANDLE)4)\n\n/** The name of the system idle process. */\n#define SYSTEM_IDLE_PROCESS_NAME ((UNICODE_STRING)RTL_CONSTANT_STRING(L\"System Idle Process\"))\n\n#define PhNtPathSeparatorString ((PH_STRINGREF)PH_STRINGREF_INIT(L\"\\\\\")) // OBJ_NAME_PATH_SEPARATOR // RtlNtPathSeperatorString\n#define PhNtDosDevicesPrefix ((PH_STRINGREF)PH_STRINGREF_INIT(L\"\\\\??\\\\\")) // RtlDosDevicesPrefix\n#define PhNtDevicePathPrefix ((PH_STRINGREF)PH_STRINGREF_INIT(L\"\\\\Device\\\\\"))\n#define PhWin32ExtendedPathPrefix ((PH_STRINGREF)PH_STRINGREF_INIT(L\"\\\\\\\\?\\\\\")) // extended-length paths, disable path normalization\n\nFORCEINLINE\nBOOLEAN\nPhIsNullOrInvalidHandle(\n    _In_ HANDLE Handle\n    )\n{\n    return (((ULONG_PTR)Handle + 1) & 0xFFFFFFFFFFFFFFFEuLL) == 0;\n}\n\n//\n// General object-related function types\n//\n\ntypedef _Function_class_(PH_OPEN_OBJECT)\nNTSTATUS NTAPI PH_OPEN_OBJECT(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_OPEN_OBJECT* PPH_OPEN_OBJECT;\n\ntypedef _Function_class_(PH_CLOSE_OBJECT)\nNTSTATUS NTAPI PH_CLOSE_OBJECT(\n    _In_ HANDLE Handle,\n    _In_ BOOLEAN Release,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_CLOSE_OBJECT* PPH_CLOSE_OBJECT;\n\ntypedef _Function_class_(PH_GET_OBJECT_SECURITY)\nNTSTATUS NTAPI PH_GET_OBJECT_SECURITY(\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_GET_OBJECT_SECURITY* PPH_GET_OBJECT_SECURITY;\n\ntypedef _Function_class_(PH_SET_OBJECT_SECURITY)\nNTSTATUS NTAPI PH_SET_OBJECT_SECURITY(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_SET_OBJECT_SECURITY* PPH_SET_OBJECT_SECURITY;\n\ntypedef struct _PH_TOKEN_ATTRIBUTES\n{\n    HANDLE TokenHandle;\n    struct\n    {\n        ULONG Elevated : 1;\n        ULONG ElevationType : 2;\n        ULONG SpareBits : 29;\n    };\n    ULONG Spare;\n    PSID TokenSid;\n} PH_TOKEN_ATTRIBUTES, *PPH_TOKEN_ATTRIBUTES;\n\ntypedef enum _MANDATORY_LEVEL_RID\n{\n    MandatoryUntrustedRID = SECURITY_MANDATORY_UNTRUSTED_RID,\n    MandatoryLowRID = SECURITY_MANDATORY_LOW_RID,\n    MandatoryMediumRID = SECURITY_MANDATORY_MEDIUM_RID,\n    MandatoryMediumPlusRID = SECURITY_MANDATORY_MEDIUM_PLUS_RID,\n    MandatoryHighRID = SECURITY_MANDATORY_HIGH_RID,\n    MandatorySystemRID = SECURITY_MANDATORY_SYSTEM_RID,\n    MandatorySecureProcessRID = SECURITY_MANDATORY_PROTECTED_PROCESS_RID\n} MANDATORY_LEVEL_RID, *PMANDATORY_LEVEL_RID;\n\nPHLIBAPI\nPH_TOKEN_ATTRIBUTES\nNTAPI\nPhGetOwnTokenAttributes(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    );\n\n/**\n * Opens a process handle with the best available query access.\n *\n * The function tries the following access combinations in order:\n *   1. PROCESS_QUERY_INFORMATION | DesiredAccess\n *   2. PROCESS_QUERY_LIMITED_INFORMATION | DesiredAccess\n *   3. PROCESS_QUERY_LIMITED_INFORMATION\n *\n * The first successful attempt is returned to the caller. If all attempts\n * fail, the final NTSTATUS code is returned.\n *\n * \\param ProcessHandle Receives the resulting process handle on success.\n * \\param DesiredAccess Additional access rights the caller wishes to request.\n * \\param ProcessId The process identifier of the target process.\n * \\return NTSTATUS Successful or errant status.\n */\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhOpenProcessWithQueryAccess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n\n    status = PhOpenProcess(\n        ProcessHandle,\n        PROCESS_QUERY_INFORMATION | DesiredAccess,\n        ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        status = PhOpenProcess(\n            ProcessHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION | DesiredAccess,\n            ProcessId\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            status = PhOpenProcess(\n                ProcessHandle,\n                PROCESS_QUERY_LIMITED_INFORMATION,\n                ProcessId\n                );\n        }\n    }\n\n    return status;\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenProcessClientId(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenProcessPublic(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ThreadId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenThreadClientId(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenThreadPublic(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ThreadId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadBasicInformation(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PTHREAD_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadBasePriority(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PKPRIORITY Increment\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadTeb(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG_PTR TebBaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadTeb32(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG_PTR TebBaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadStartAddress(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG_PTR StartAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadIoPriority(\n    _In_ HANDLE ThreadHandle,\n    _Out_ IO_PRIORITY_HINT* IoPriority\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadPagePriority(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG PagePriority\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadPriorityBoost(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PBOOLEAN PriorityBoostDisabled\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadPerformanceCounter(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PLARGE_INTEGER PerformanceCounter\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadCycleTime(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG64 CycleTime\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadIdealProcessor(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PPROCESSOR_NUMBER ProcessorNumber\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadSuspendCount(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG SuspendCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadWow64Context(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PWOW64_CONTEXT Context\n    );\n\n#if defined(_ARM64_)\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadArm32Context(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PARM_NT_CONTEXT Context\n    );\n#endif\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadBreakOnTermination(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PBOOLEAN BreakOnTermination\n);\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadBreakOnTermination(\n    _In_ HANDLE ThreadHandle,\n    _In_ BOOLEAN BreakOnTermination\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadContainerId(\n    _In_ HANDLE ThreadHandle,\n    _In_ PGUID ContainerId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadIsIoPending(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PBOOLEAN IsIoPending\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadTimes(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PKERNEL_USER_TIMES Times\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadIsTerminated(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PBOOLEAN IsTerminated\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetThreadIsTerminated2(\n    _In_ HANDLE ThreadHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadGroupAffinity(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PGROUP_AFFINITY GroupAffinity\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadIndexInformation(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PTHREAD_INDEX_INFORMATION ThreadIndex\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenProcessTokenPublic(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenThreadToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ BOOLEAN OpenAsSelf,\n    _Out_ PHANDLE TokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n#define AUDIT_ALARM_ACE_TYPE_MASK ( \\\n    (1 << SYSTEM_AUDIT_ACE_TYPE) | \\\n    (1 << SYSTEM_ALARM_ACE_TYPE) | \\\n    (1 << SYSTEM_AUDIT_OBJECT_ACE_TYPE) | \\\n    (1 << SYSTEM_ALARM_OBJECT_ACE_TYPE) | \\\n    (1 << SYSTEM_AUDIT_CALLBACK_ACE_TYPE) | \\\n    (1 << SYSTEM_ALARM_CALLBACK_ACE_TYPE) | \\\n    (1 << SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE) | \\\n    (1 << SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE))\n\n#define MANDATORY_LABEL_ACE_TYPE_MASK (1 << SYSTEM_MANDATORY_LABEL_ACE_TYPE)\n#define RESOURCE_ATTRIBUTE_ACE_TYPE_MASK (1 << SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE)\n#define SCOPED_POLICY_ACE_TYPE_MASK (1 << SYSTEM_SCOPED_POLICY_ID_ACE_TYPE)\n#define PROCESS_TRUST_ACE_TYPE_MASK (1 << SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE)\n#define ACCESS_FILTER_ACE_TYPE_MASK (1 << SYSTEM_ACCESS_FILTER_ACE_TYPE)\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMergeSystemAcls(\n    _In_opt_ PACL LowerSacl,\n    _In_opt_ PACL HigherSacl,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Outptr_result_maybenull_ PACL* MergedSacl\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMergeSecurityDescriptors(\n    _In_ PSECURITY_DESCRIPTOR LowerSecurityDescriptor,\n    _In_ PSECURITY_DESCRIPTOR HigherSecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Outptr_ PSECURITY_DESCRIPTOR* MergedSecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSuspendProcess(\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhResumeProcess(\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTerminateThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessBasicInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessExtendedBasicInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_EXTENDED_BASIC_INFORMATION ExtendedBasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessTimes(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKERNEL_USER_TIMES Times\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessSessionId(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG SessionId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsWow64(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsWow64Process\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessPeb32(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID* Peb32\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessPeb(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID* PebBaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessDebugObject(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE DebugObjectHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessEnergyValues(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_EXTENDED_ENERGY_VALUES EnergyValues\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessErrorMode(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ErrorMode\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessErrorMode(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG ErrorMode\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessExecuteFlags(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ExecuteFlags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIoPriority(\n    _In_ HANDLE ProcessHandle,\n    _Out_ IO_PRIORITY_HINT *IoPriority\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessPagePriority(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG PagePriority\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessPriorityBoost(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN PriorityBoostDisabled\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessCycleTime(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG64 CycleTime\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessUptime(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_UPTIME_INFORMATION Uptime\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessConsoleHostProcessId(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE ConsoleHostProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessConsoleHostProcess(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE ConsoleHostProcessId,\n    _Out_opt_ PBOOLEAN ConsoleApplication\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessProtection(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPS_PROTECTION Protection\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessAffinityMask(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKAFFINITY AffinityMask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessGroupInformation(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PUSHORT GroupCount,\n    _Out_ PUSHORT GroupArray\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessGroupAffinity(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PGROUP_AFFINITY GroupAffinity\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsCFGuardEnabled(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsControlFlowGuardEnabled\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsXFGuardEnabled(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsXFGuardEnabled,\n    _Out_ PBOOLEAN IsXFGuardAuditEnabled\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessHandleCount(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_HANDLE_INFORMATION HandleInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessBreakOnTermination(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN BreakOnTermination\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessBreakOnTermination(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN BreakOnTermination\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessAppMemoryInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_JOB_MEMORY_INFO JobMemoryInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessMitigationPolicy(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESS_MITIGATION_POLICY Policy,\n    _Out_ PPROCESS_MITIGATION_POLICY_INFORMATION MitigationPolicy\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessNetworkIoCounters(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_NETWORK_COUNTERS NetworkIoCounters\n    );\n\ntypedef struct _PH_PROCESS_RUNTIME_LIBRARY\n{\n    PH_STRINGREF NtdllFileName;\n    PH_STRINGREF Kernel32FileName;\n    PH_STRINGREF User32FileName;\n} PH_PROCESS_RUNTIME_LIBRARY, *PPH_PROCESS_RUNTIME_LIBRARY;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessRuntimeLibrary(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_RUNTIME_LIBRARY* RuntimeLibrary,\n    _Out_opt_ PBOOLEAN IsWow64Process\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessImageFileName(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessImageFileNameWin32(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessImageFileNameById(\n    _In_ HANDLE ProcessId,\n    _Out_opt_ PPH_STRING *FullFileName,\n    _Out_opt_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessImageFileNameByProcessId(\n    _In_opt_ HANDLE ProcessId,\n    _Out_ PPH_STRING* FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsBeingDebugged(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsBeingDebugged\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsTerminating(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsTerminated\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsTerminated(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsTerminated\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessDeviceMap(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG DeviceMap\n    );\n\n/** Specifies a PEB string. */\ntypedef enum _PH_PEB_OFFSET\n{\n    PhpoNone,\n    PhpoCurrentDirectory,\n    PhpoDllPath,\n    PhpoImagePathName,\n    PhpoCommandLine,\n    PhpoWindowTitle,\n    PhpoDesktopInfo,\n    PhpoShellInfo,\n    PhpoRuntimeData,\n    PhpoTypeMask = 0xffff,\n\n    PhpoWow64 = 0x10000\n} PH_PEB_OFFSET;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessPebString(\n    _In_ HANDLE ProcessHandle,\n    _In_ PH_PEB_OFFSET Offset,\n    _Out_ PPH_STRING *String\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessCommandLine(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *CommandLine\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessCommandLineStringRef(\n    _Out_ PPH_STRINGREF CommandLine\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessCurrentDirectory(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN IsWow64Process,\n    _Out_ PPH_STRING* CurrentDirectory\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessDesktopInfo(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *DesktopInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessWindowTitle(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG WindowFlags,\n    _Out_ PPH_STRING *WindowTitle\n    );\n\n#define PH_PROCESS_DEP_ENABLED 0x1\n#define PH_PROCESS_DEP_ATL_THUNK_EMULATION_DISABLED 0x2\n#define PH_PROCESS_DEP_PERMANENT 0x4\n#define PH_PROCESS_DEP_EXECUTE_ENABLED 0x8\n#define PH_PROCESS_DEP_IMAGE_ENABLED 0x10\n#define PH_PROCESS_DEP_DISABLE_EXCEPTION_CHAIN 0x20\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessDepStatus(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG DepStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessEnvironment(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN IsWow64Process,\n    _Out_ PVOID *Environment,\n    _Out_ PULONG EnvironmentLength\n    );\n\ntypedef struct _PH_ENVIRONMENT_VARIABLE\n{\n    PH_STRINGREF Name;\n    PH_STRINGREF Value;\n} PH_ENVIRONMENT_VARIABLE, *PPH_ENVIRONMENT_VARIABLE;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessEnvironmentVariables(\n    _In_ PVOID Environment,\n    _In_ ULONG EnvironmentLength,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PPH_ENVIRONMENT_VARIABLE Variable\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryEnvironmentVariableStringRef(\n    _In_opt_ PVOID Environment,\n    _In_ PCPH_STRINGREF Name,\n    _Inout_opt_ PPH_STRINGREF Value\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhQueryEnvironmentVariableToBufferZ(\n    _In_opt_ PVOID Environment,\n    _In_ PCWSTR Name,\n    _Out_writes_opt_(BufferLength) PWSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_ PSIZE_T ReturnLength\n    )\n{\n    NTSTATUS status;\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    status = RtlQueryEnvironmentVariable(\n        Environment,\n        name.Buffer,\n        name.Length / sizeof(WCHAR),\n        Buffer,\n        BufferLength,\n        ReturnLength\n        );\n\n    return status;\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryEnvironmentVariable(\n    _In_opt_ PVOID Environment,\n    _In_ PCPH_STRINGREF Name,\n    _Out_opt_ PPH_STRING* Value\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhQueryEnvironmentVariableZ(\n    _In_opt_ PVOID Environment,\n    _In_ PCWSTR Name,\n    _Out_opt_ PPH_STRING* Value\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    return PhQueryEnvironmentVariable(Environment, &name, Value);\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetEnvironmentVariable(\n    _In_opt_ PVOID Environment,\n    _In_ PCPH_STRINGREF Name,\n    _In_opt_ PCPH_STRINGREF Value\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetEnvironmentVariableZ(\n    _In_opt_ PVOID Environment,\n    _In_ PCWSTR Name,\n    _In_opt_ PCWSTR Value\n    )\n{\n    if (Value)\n    {\n        PH_STRINGREF name;\n        PH_STRINGREF value;\n\n        PhInitializeStringRef(&name, Name);\n        PhInitializeStringRef(&value, Value);\n\n        return PhSetEnvironmentVariable(Environment, &name, &value);\n    }\n    else\n    {\n        PH_STRINGREF name;\n\n        PhInitializeStringRef(&name, Name);\n\n        return PhSetEnvironmentVariable(Environment, &name, NULL);\n    }\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessMappedFileName(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessMappedImageInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_ PMEMORY_IMAGE_INFORMATION ImageInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessMappedImageBaseFromAddress(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID Address,\n    _Out_ PVOID* ImageBase,\n    _Out_opt_ PSIZE_T ImageSize\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessWorkingSetInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PMEMORY_WORKING_SET_INFORMATION *WorkingSetInformation\n    );\n\ntypedef struct _PH_PROCESS_WS_COUNTERS\n{\n    SIZE_T NumberOfPages;\n    SIZE_T NumberOfPrivatePages;\n    SIZE_T NumberOfSharedPages;\n    SIZE_T NumberOfShareablePages;\n} PH_PROCESS_WS_COUNTERS, *PPH_PROCESS_WS_COUNTERS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessWsCounters(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_WS_COUNTERS WsCounters\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadDllProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_STRINGREF FileName,\n    _In_opt_ ULONG Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadDllProcessApcThread(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_STRINGREF FileName,\n    _In_opt_ ULONG Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadDllProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_opt_ ULONG Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessUnloadedDlls(\n    _In_ HANDLE ProcessId,\n    _Out_ PVOID *EventTrace,\n    _Out_ ULONG *EventTraceSize,\n    _Out_ ULONG *EventTraceCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTraceControl(\n    _In_ ETWTRACECONTROLCODE TraceInformationClass,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _Out_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTraceControlVariableSize(\n    _In_ ETWTRACECONTROLCODE TraceInformationClass,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(*OutputBufferLength) PVOID* OutputBuffer,\n    _Out_opt_ PULONG OutputBufferLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetEnvironmentVariableRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_STRINGREF Name,\n    _In_opt_ PPH_STRINGREF Value,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetWindowClientId(\n    _In_ HWND WindowHandle,\n    _Out_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDestroyWindowRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInvokeWindowProcedureRemote(\n    _In_ HWND WindowHandle,\n    _In_ PPS_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetHandleInformationRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE RemoteHandle,\n    _In_ ULONG Mask,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenJobObject(\n    _Out_ PHANDLE JobHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetJobProcessIdList(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_PROCESS_ID_LIST *ProcessIdList\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetJobBasicAndIoAccounting(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION BasicAndIoAccounting\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetJobBasicLimits(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimits\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetJobExtendedLimits(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_EXTENDED_LIMIT_INFORMATION ExtendedLimits\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetJobBasicUiRestrictions(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_UI_RESTRICTIONS BasicUiRestrictions\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryTokenVariableSize(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _Out_ PVOID *Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenType(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_TYPE Type\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenSessionId(\n    _In_ HANDLE TokenHandle,\n    _Out_ PULONG SessionId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenElevationType(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_ELEVATION_TYPE ElevationType\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenElevation(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN TokenIsElevated\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenStatistics(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_STATISTICS Statistics\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenSource(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_SOURCE Source\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenLinkedToken(\n    _In_ HANDLE TokenHandle,\n    _Out_ PHANDLE LinkedTokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIsRestricted(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsRestricted\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIsVirtualizationAllowed(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsVirtualizationAllowed\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIsVirtualizationEnabled(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsVirtualizationEnabled\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenUIAccess(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsUIAccessEnabled\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetTokenUIAccess(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN IsUIAccessEnabled\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIsSandBoxInert(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsSandBoxInert\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenMandatoryPolicy(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_MANDATORY_POLICY MandatoryPolicy\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenOrigin(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_ORIGIN Origin\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIsAppContainer(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsAppContainer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenAppContainerNumber(\n    _In_ HANDLE TokenHandle,\n    _Out_ PULONG AppContainerNumber\n    );\n\n// rev from SE_TOKEN_USER (dmex)\ntypedef struct _PH_TOKEN_USER\n{\n    union\n    {\n        TOKEN_USER TokenUser;\n        SID_AND_ATTRIBUTES User;\n    };\n    union\n    {\n        SID Sid;\n        BYTE Buffer[SECURITY_MAX_SID_SIZE];\n    };\n} PH_TOKEN_USER, *PPH_TOKEN_USER;\n\nC_ASSERT(sizeof(PH_TOKEN_USER) >= TOKEN_USER_MAX_SIZE);\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenUser(\n    _In_ HANDLE TokenHandle,\n    _Out_ PPH_TOKEN_USER User\n    );\n\ntypedef struct _PH_TOKEN_OWNER\n{\n    union\n    {\n        TOKEN_OWNER TokenOwner;\n        SID_AND_ATTRIBUTES Owner;\n    };\n    union\n    {\n        SID Sid;\n        BYTE Buffer[SECURITY_MAX_SID_SIZE];\n    };\n} PH_TOKEN_OWNER, *PPH_TOKEN_OWNER;\n\nC_ASSERT(sizeof(PH_TOKEN_OWNER) >= TOKEN_OWNER_MAX_SIZE);\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenOwner(\n    _In_ HANDLE TokenHandle,\n    _Out_ PPH_TOKEN_OWNER Owner\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenPrimaryGroup(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PRIMARY_GROUP *PrimaryGroup\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenDefaultDacl(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_DEFAULT_DACL* DefaultDacl\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenGroups(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_GROUPS *Groups\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenRestrictedSids(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_GROUPS* RestrictedSids\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenPrivileges(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PRIVILEGES *Privileges\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenTrustLevel(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PROCESS_TRUST_LEVEL *TrustLevel\n    );\n\ntypedef struct _PH_TOKEN_APPCONTAINER\n{\n    union\n    {\n        TOKEN_APPCONTAINER_INFORMATION TokenAppContainer;\n        SID_AND_ATTRIBUTES AppContainer;\n    };\n    union\n    {\n        SID Sid;\n        BYTE Buffer[SECURITY_MAX_SID_SIZE];\n    };\n} PH_TOKEN_APPCONTAINER, *PPH_TOKEN_APPCONTAINER;\n\nC_ASSERT(sizeof(PH_TOKEN_APPCONTAINER) >= TOKEN_APPCONTAINER_SID_MAX_SIZE);\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenAppContainerSid(\n    _In_ HANDLE TokenHandle,\n    _Out_ PPH_TOKEN_APPCONTAINER AppContainerSid\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenSecurityAttributes(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION* SecurityAttributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenSecurityAttribute(\n    _In_ HANDLE TokenHandle,\n    _In_ PCPH_STRINGREF AttributeName,\n    _Out_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION* SecurityAttributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDoesTokenSecurityAttributeExist(\n    _In_ HANDLE TokenHandle,\n    _In_ PCPH_STRINGREF AttributeName,\n    _Out_ PBOOLEAN SecurityAttributeExists\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetTokenIsFullTrustPackage(\n    _In_ HANDLE TokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIsLessPrivilegedAppContainer(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsLessPrivilegedAppContainer\n    );\n\nPHLIBAPI\nULONG64\nNTAPI\nPhGetTokenSecurityAttributeValueUlong64(\n    _In_ HANDLE TokenHandle,\n    _In_ PCPH_STRINGREF Name,\n    _In_ ULONG ValueIndex\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenPackageFullName(\n    _In_ HANDLE TokenHandle,\n    _Out_ PPH_STRING* PackageFullName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsStronglyNamed(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsStronglyNamed\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetProcessIsFullTrustPackage(\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetProcessPackageFullName(\n    _In_ HANDLE ProcessHandle\n    );\n\n// rev from RtlInitializeSid (dmex)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhInitializeSid(\n    _Out_ PSID Sid,\n    _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,\n    _In_ UCHAR SubAuthorityCount\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return NT_SUCCESS(RtlInitializeSid(Sid, IdentifierAuthority, SubAuthorityCount));\n#else\n    ((PISID)Sid)->Revision = SID_REVISION;\n    ((PISID)Sid)->IdentifierAuthority = *IdentifierAuthority;\n    ((PISID)Sid)->SubAuthorityCount = SubAuthorityCount;\n\n    for (UCHAR i = 0; i < SubAuthorityCount; i++)\n    {\n        ((PISID)Sid)->SubAuthority[i] = 0;\n    }\n\n    return TRUE;\n#endif\n}\n\n// rev from RtlLengthSid (dmex)\nFORCEINLINE\nULONG\nNTAPI\nPhLengthSid(\n    _In_ PCSID Sid\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlLengthSid((PSID)Sid);\n#else\n    //return UFIELD_OFFSET(SID, SubAuthority) + (((PISID)Sid)->SubAuthorityCount * sizeof(ULONG));\n    return UFIELD_OFFSET(SID, SubAuthority[((PISID)Sid)->SubAuthorityCount]);\n#endif\n}\n\n// rev from RtlLengthRequiredSid (dmex)\nFORCEINLINE\nULONG\nNTAPI\nPhLengthRequiredSid(\n    _In_ ULONG SubAuthorityCount\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlLengthRequiredSid(SubAuthorityCount);\n#else\n    return UFIELD_OFFSET(SID, SubAuthority[SubAuthorityCount]);\n#endif\n}\n\n// rev from RtlEqualSid (dmex)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhEqualSid(\n    _In_ PCSID Sid1,\n    _In_ PCSID Sid2\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlEqualSid((PSID)Sid1, (PSID)Sid2);\n#else\n    if (!(Sid1 && Sid2))\n        return FALSE;\n\n    if (!(\n        ((PISID)Sid1)->Revision == ((PISID)Sid2)->Revision &&\n        ((PISID)Sid1)->SubAuthorityCount == ((PISID)Sid2)->SubAuthorityCount\n        ))\n    {\n        return FALSE;\n    }\n\n    ULONG length1 = PhLengthSid(Sid1);\n    ULONG length2 = PhLengthSid(Sid2);\n\n    if (length1 != length2)\n        return FALSE;\n\n    return (BOOLEAN)RtlEqualMemory(Sid1, Sid2, length1);\n#endif\n}\n\n// rev from RtlValidSid (dmex)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhValidSid(\n    _In_ PCSID Sid\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlValidSid((PSID)Sid);\n#else\n    if (\n        ((PISID)Sid) &&\n        ((PISID)Sid)->Revision == SID_REVISION &&\n        ((PISID)Sid)->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES\n        )\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n#endif\n}\n\n// rev from RtlSubAuthoritySid (dmex)\nFORCEINLINE\nPULONG\nNTAPI\nPhSubAuthoritySid(\n    _In_ PCSID Sid,\n    _In_ ULONG SubAuthority\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlSubAuthoritySid((PSID)Sid, SubAuthority);\n#else\n    return &((PISID)Sid)->SubAuthority[SubAuthority];\n#endif\n}\n\n// rev from RtlSubAuthorityCountSid (dmex)\nFORCEINLINE\nPUCHAR\nNTAPI\nPhSubAuthorityCountSid(\n    _In_ PCSID Sid\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlSubAuthorityCountSid((PSID)Sid);\n#else\n    return &((PISID)Sid)->SubAuthorityCount;\n#endif\n}\n\n// rev from RtlIdentifierAuthoritySid (dmex)\nFORCEINLINE\nPSID_IDENTIFIER_AUTHORITY\nNTAPI\nPhIdentifierAuthoritySid(\n    _In_ PCSID Sid\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlIdentifierAuthoritySid((PSID)Sid);\n#else\n    return &((PISID)Sid)->IdentifierAuthority;\n#endif\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhEqualIdentifierAuthoritySid(\n    _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthoritySid1,\n    _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthoritySid2\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlEqualMemory(RtlIdentifierAuthoritySid(IdentifierAuthoritySid1), RtlIdentifierAuthoritySid(IdentifierAuthoritySid2), sizeof(SID_IDENTIFIER_AUTHORITY));\n#else\n    return (BOOLEAN)RtlEqualMemory(IdentifierAuthoritySid1, IdentifierAuthoritySid2, sizeof(SID_IDENTIFIER_AUTHORITY));\n#endif\n}\n\n// rev from RtlCreateSecurityDescriptor (dmex)\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhCreateSecurityDescriptor(\n    _Out_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ULONG Revision\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlCreateSecurityDescriptor(SecurityDescriptor, Revision);\n#else\n    memset(SecurityDescriptor, 0, sizeof(SECURITY_DESCRIPTOR));\n    ((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision = (BYTE)Revision;\n    return STATUS_SUCCESS;\n#endif\n}\n\n// rev from RtlValidAcl (dmex)\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhValidAcl(\n    _In_opt_ PACL Acl\n    )\n{\n    if (!Acl || Acl->AclRevision < MIN_ACL_REVISION || Acl->AclRevision > MAX_ACL_REVISION)\n        return FALSE;\n    if (Acl->AclSize < sizeof(ACL) || ((Acl->AclSize & 3U) != 0)) // enforce alignment\n        return FALSE;\n\n    return RtlValidAcl(Acl);\n}\n\nFORCEINLINE\nUCHAR\nNTAPI\nPhRequiredAclRevision(\n    _In_ UCHAR AceType\n    )\n{\n    switch (AceType)\n    {\n    case ACCESS_ALLOWED_OBJECT_ACE_TYPE:\n    case ACCESS_DENIED_OBJECT_ACE_TYPE:\n    case SYSTEM_AUDIT_OBJECT_ACE_TYPE:\n    case SYSTEM_ALARM_OBJECT_ACE_TYPE:\n    case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:\n    case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:\n    case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:\n    case SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE:\n        return ACL_REVISION4;\n\n    case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:\n        return ACL_REVISION3;\n\n    default:\n        return MIN_ACL_REVISION;\n    }\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhEnsureAclRevision(\n    _Inout_ PULONG_PTR AclRevision,\n    _In_ UCHAR AceType\n    )\n{\n    UCHAR requiredRevision = PhRequiredAclRevision(AceType);\n\n    if (requiredRevision > *AclRevision)\n    {\n        *AclRevision = requiredRevision;\n    }\n}\n\nFORCEINLINE\nPVOID\nNTAPI\nPhFirstAce(\n    _In_ PACL Acl\n    )\n{\n    return RTL_PTR_ADD(Acl, sizeof(ACL));\n}\n\nFORCEINLINE\nPVOID\nNTAPI\nPhNextAce(\n    _In_ PACL Ace\n    )\n{\n    PACE_HEADER ace = (PACE_HEADER)Ace;\n\n    if (ace->AceSize < sizeof(ACE_HEADER) || (ace->AceSize & 3U) != 0) // enforce alignment\n        return NULL;\n\n    return RTL_PTR_ADD(Ace, ace->AceSize);\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhFirstFreeAce(\n    _In_ PACL Acl,\n    _Out_ PVOID* FirstFree\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlFirstFreeAce(Acl, FirstFree);\n#else\n    if (!PhValidAcl(Acl))\n    {\n        *FirstFree = NULL;\n        return FALSE;\n    }\n\n    ULONG_PTR current = (ULONG_PTR)PhFirstAce(Acl);\n    const ULONG_PTR last = (ULONG_PTR)RTL_PTR_ADD(Acl, Acl->AclSize);\n\n    for (USHORT i = 0; i < Acl->AceCount; i++)\n    {\n        if (current >= last)\n            goto InvalidAcl;\n\n        //ULONG_PTR headerEnd = (ULONG_PTR)RTL_PTR_ADD(current, sizeof(ACE_HEADER));\n        //if (headerEnd > last)\n        //    goto InvalidAcl;\n\n        ULONG_PTR next = (ULONG_PTR)PhNextAce((PACL)current);\n\n        if (next > last)\n            goto InvalidAcl;\n\n        current = next;\n    }\n\n    *FirstFree = (PVOID)current;\n    return TRUE;\n\nInvalidAcl:\n    *FirstFree = NULL;\n    return FALSE;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetAce(\n    _In_ PACL Acl,\n    _In_ ULONG AceIndex,\n    _Out_ PVOID* Ace\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetAce(Acl, AceIndex, Ace);\n#else\n    PVOID current;\n    PVOID lastace;\n\n    if (Acl->AclRevision < MIN_ACL_REVISION ||\n        Acl->AclRevision > MAX_ACL_REVISION ||\n        AceIndex >= Acl->AceCount)\n    {\n        return STATUS_INVALID_ACL;\n    }\n\n    current = PhFirstAce(Acl);\n    lastace = RTL_PTR_ADD(Acl, Acl->AclSize);\n\n    for (ULONG i = 0; i < AceIndex; i++)\n    {\n        if ((ULONG_PTR)current >= (ULONG_PTR)lastace)\n            return STATUS_INVALID_ACL;\n\n        current = PhNextAce((PACL)current);\n    }\n\n    if (current >= lastace)\n        return STATUS_INVALID_ACL;\n\n    *Ace = current;\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhAddAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ULONG StartingAceIndex,\n    _In_reads_bytes_(AceListLength) PVOID AceList,\n    _In_ ULONG AceListLength\n    )\n{\n    PVOID firstFree = NULL;\n\n    if (!PhValidAcl(Acl))\n        return STATUS_INVALID_PARAMETER;\n    if (AceListLength == 0)\n        return STATUS_SUCCESS;\n\n    if (!PhFirstFreeAce(Acl, &firstFree) || !firstFree)\n        return STATUS_INVALID_ACL;\n\n    // Determine final revision (max of current ACL revision and requested).\n    ULONG_PTR finalRevision = Acl->AclRevision;\n\n    if ((ULONG_PTR)AceRevision > finalRevision)\n    {\n        finalRevision = (ULONG_PTR)AceRevision;\n    }\n\n    // Validate the incoming ACE list and compute newAceCount, while checking\n    // the ACL revision supports the ACE types to be inserted.\n    ULONG_PTR src = (ULONG_PTR)AceList;\n    ULONG_PTR const srcEnd = src + AceListLength;\n    USHORT newAceCount = 0;\n\n    while (src < srcEnd)\n    {\n        if (src + sizeof(ACE_HEADER) > srcEnd)\n            return STATUS_INVALID_PARAMETER;\n\n        PACE_HEADER aceHdr = (PACE_HEADER)src;\n        USHORT inSize = aceHdr->AceSize;\n\n        if (inSize == 0 || src + inSize > srcEnd)\n            return STATUS_INVALID_PARAMETER;\n\n        // Ensure the ACL revision can host this ACE type.\n        PhEnsureAclRevision(&finalRevision, aceHdr->AceType);\n\n        src += inSize;\n        ++newAceCount;\n    }\n\n    if (src != srcEnd)\n        return STATUS_INVALID_PARAMETER;\n\n    // Determine insertion point.\n    PVOID insertAce = firstFree;\n    ULONG existingAceCount = Acl->AceCount;\n\n    if (StartingAceIndex < existingAceCount)\n    {\n        NTSTATUS status;\n\n        status = PhGetAce(\n            Acl,\n            StartingAceIndex,\n            &insertAce\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n    // else insert at end (firstFree)\n\n    // Ensure AceListLength bytes free between end of ACL buffer and current firstFree.\n    ULONG_PTR const aclStart = (ULONG_PTR)Acl;\n    ULONG_PTR const aclEnd = aclStart + Acl->AclSize;\n\n    if ((ULONG_PTR)PTR_ADD_OFFSET(firstFree, AceListLength) > (ULONG_PTR)aclEnd)\n        return STATUS_BUFFER_TOO_SMALL;\n\n    // Shift tail [insertPtr, firstFree) forward to make room.\n    ULONG_PTR tailBytes = (ULONG_PTR)PTR_SUB_OFFSET(firstFree, insertAce);\n\n    if (tailBytes > 0)\n    {\n        RtlMoveMemory(PTR_ADD_OFFSET(insertAce, AceListLength), insertAce, tailBytes);\n    }\n\n    // Copy new ACEs.\n    RtlCopyMemory(insertAce, AceList, AceListLength);\n\n    // Update counts and revision.\n    Acl->AceCount = (USHORT)(Acl->AceCount + newAceCount);\n    Acl->AclRevision = (UCHAR)finalRevision;\n\n    return STATUS_SUCCESS;\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhCreateAcl(\n    _Out_ PACL Acl,\n    _In_ ULONG Length,\n    _In_ ULONG Revision\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlCreateAcl(Acl, Length, Revision);\n#else\n    if (Length < sizeof(ACL))\n        return STATUS_BUFFER_TOO_SMALL;\n    if (Length > USHRT_MAX)\n        return STATUS_INVALID_PARAMETER;\n    if (Revision < MIN_ACL_REVISION || Revision > MAX_ACL_REVISION)\n        return STATUS_REVISION_MISMATCH;\n\n    memset(Acl, 0, sizeof(ACL));\n    Acl->AclRevision = (BYTE)Revision;\n    Acl->AclSize = (USHORT)(Length & ~0x0003);\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetDaclSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PBOOLEAN DaclPresent,\n    _Outptr_result_maybenull_ PACL* Dacl,\n    _Out_ PBOOLEAN DaclDefaulted\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetDaclSecurityDescriptor(SecurityDescriptor, DaclPresent, Dacl, DaclDefaulted);\n#else\n    PISECURITY_DESCRIPTOR securityDescriptor = (PISECURITY_DESCRIPTOR)SecurityDescriptor;\n    BOOLEAN present = FALSE;\n    BOOLEAN defaulted = FALSE;\n    PACL dacl = NULL;\n\n    if (securityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n\n    if (present = BooleanFlagOn(securityDescriptor->Control, SE_DACL_PRESENT))\n    {\n        defaulted = BooleanFlagOn(securityDescriptor->Control, SE_DACL_DEFAULTED);\n\n        if (BooleanFlagOn(securityDescriptor->Control, SE_SELF_RELATIVE))\n        {\n            PISECURITY_DESCRIPTOR_RELATIVE securityDescriptorRelative = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;\n\n            if (securityDescriptorRelative->Dacl)\n            {\n                dacl = (PACL)RTL_PTR_ADD(SecurityDescriptor, securityDescriptorRelative->Dacl);\n            }\n        }\n        else\n        {\n            dacl = securityDescriptor->Dacl;\n        }\n    }\n\n    *DaclPresent = present;\n    *DaclDefaulted = defaulted;\n    *Dacl = dacl;\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetDaclSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ BOOLEAN DaclPresent,\n    _In_opt_ PACL Dacl,\n    _In_opt_ BOOLEAN DaclDefaulted\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlSetDaclSecurityDescriptor(SecurityDescriptor, DaclPresent, Dacl, DaclDefaulted);\n#else\n    if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n    if (FlagOn(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SELF_RELATIVE))\n        return STATUS_INVALID_SECURITY_DESCR;\n\n    if (DaclPresent)\n        SetFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_DACL_PRESENT);\n    else\n        ClearFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_DACL_PRESENT);\n\n    if (DaclDefaulted)\n        SetFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_DACL_DEFAULTED);\n    else\n        ClearFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_DACL_DEFAULTED);\n\n    ((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Dacl = Dacl;\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetDaclSecurityDescriptorNotNull(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PBOOLEAN DaclPresent,\n    _Out_ PBOOLEAN DaclDefaulted,\n    _Outptr_result_maybenull_ PACL* Dacl\n    )\n{\n    NTSTATUS status;\n    BOOLEAN present = FALSE;\n    BOOLEAN defaulted = FALSE;\n    PACL dacl = NULL;\n\n    status = PhGetDaclSecurityDescriptor(\n        SecurityDescriptor,\n        &present,\n        &dacl,\n        &defaulted\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (dacl)\n        {\n            *DaclPresent = present;\n            *DaclDefaulted = defaulted;\n            *Dacl = dacl;\n        }\n        else\n        {\n            status = STATUS_INVALID_SECURITY_DESCR;\n        }\n    }\n\n    return status;\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetSaclSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PBOOLEAN SaclPresent,\n    _Outptr_result_maybenull_ PACL* Sacl,\n    _Out_ PBOOLEAN SaclDefaulted\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetSaclSecurityDescriptor(SecurityDescriptor, SaclPresent, Sacl, SaclDefaulted);\n#else\n    PISECURITY_DESCRIPTOR securityDescriptor = (PISECURITY_DESCRIPTOR)SecurityDescriptor;\n    BOOLEAN present = FALSE;\n    BOOLEAN defaulted = FALSE;\n    PACL sacl = NULL;\n\n    if (securityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n\n    if (present = BooleanFlagOn(securityDescriptor->Control, SE_SACL_PRESENT))\n    {\n        defaulted = BooleanFlagOn(securityDescriptor->Control, SE_SACL_DEFAULTED);\n\n        if (BooleanFlagOn(securityDescriptor->Control, SE_SELF_RELATIVE))\n        {\n            PISECURITY_DESCRIPTOR_RELATIVE securityDescriptorRelative = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;\n\n            if (securityDescriptorRelative->Sacl)\n            {\n                sacl = (PACL)RTL_PTR_ADD(SecurityDescriptor, securityDescriptorRelative->Sacl);\n            }\n        }\n        else\n        {\n            sacl = securityDescriptor->Sacl;\n        }\n    }\n\n    *SaclPresent = present;\n    *SaclDefaulted = defaulted;\n    *Sacl = sacl;\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetSaclSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ BOOLEAN SaclPresent,\n    _In_opt_ PACL Sacl,\n    _In_opt_ BOOLEAN SaclDefaulted\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlSetSaclSecurityDescriptor(SecurityDescriptor, SaclPresent, Sacl, SaclDefaulted);\n#else\n    if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n    if (FlagOn(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SELF_RELATIVE))\n        return STATUS_INVALID_SECURITY_DESCR;\n\n    if (SaclPresent)\n        SetFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SACL_PRESENT);\n    else\n        ClearFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SACL_PRESENT);\n\n    if (SaclDefaulted)\n        SetFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SACL_DEFAULTED);\n    else\n        ClearFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SACL_DEFAULTED);\n\n    ((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Sacl = Sacl;\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetOwnerSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Outptr_result_maybenull_ PSID* Owner,\n    _Out_ PBOOLEAN OwnerDefaulted\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetOwnerSecurityDescriptor(SecurityDescriptor, Owner, OwnerDefaulted);\n#else\n    PISECURITY_DESCRIPTOR securityDescriptor = (PISECURITY_DESCRIPTOR)SecurityDescriptor;\n    BOOLEAN present = FALSE;\n    BOOLEAN defaulted = FALSE;\n    PSID owner = NULL;\n\n    if (securityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n\n    defaulted = BooleanFlagOn(securityDescriptor->Control, SE_OWNER_DEFAULTED);\n\n    if (BooleanFlagOn(securityDescriptor->Control, SE_SELF_RELATIVE))\n    {\n        PISECURITY_DESCRIPTOR_RELATIVE securityDescriptorRelative = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;\n\n        if (securityDescriptorRelative->Owner)\n        {\n            owner = RTL_PTR_ADD(SecurityDescriptor, securityDescriptorRelative->Owner);\n        }\n    }\n    else\n    {\n        owner = securityDescriptor->Sacl;\n    }\n\n    *OwnerDefaulted = defaulted;\n    *Owner = owner;\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetOwnerSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID Owner,\n    _In_opt_ BOOLEAN OwnerDefaulted\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlSetOwnerSecurityDescriptor(SecurityDescriptor, Owner, OwnerDefaulted);\n#else\n    if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n\n    if (FlagOn(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SELF_RELATIVE))\n    {\n        return STATUS_INVALID_SECURITY_DESCR;\n    }\n    else\n    {\n        if (OwnerDefaulted)\n            SetFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_OWNER_DEFAULTED);\n        else\n            ClearFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_OWNER_DEFAULTED);\n\n        ((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Owner = Owner;\n\n        return STATUS_SUCCESS;\n    }\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetGroupSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Outptr_result_maybenull_ PSID* Group,\n    _Out_ PBOOLEAN GroupDefaulted\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetGroupSecurityDescriptor(SecurityDescriptor, Group, GroupDefaulted);\n#else\n    PISECURITY_DESCRIPTOR securityDescriptor = (PISECURITY_DESCRIPTOR)SecurityDescriptor;\n    BOOLEAN present = FALSE;\n    BOOLEAN defaulted = FALSE;\n    PSID group = NULL;\n\n    if (securityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n\n    defaulted = BooleanFlagOn(securityDescriptor->Control, SE_GROUP_DEFAULTED);\n\n    if (BooleanFlagOn(securityDescriptor->Control, SE_SELF_RELATIVE))\n    {\n        PISECURITY_DESCRIPTOR_RELATIVE securityDescriptorRelative = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;\n\n        if (securityDescriptorRelative->Group)\n        {\n            group = RTL_PTR_ADD(SecurityDescriptor, securityDescriptorRelative->Group);\n        }\n    }\n    else\n    {\n        group = securityDescriptor->Group;\n    }\n\n    *GroupDefaulted = defaulted;\n    *Group = group;\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetGroupSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID Group,\n    _In_opt_ BOOLEAN GroupDefaulted\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlSetGroupSecurityDescriptor(SecurityDescriptor, Group, GroupDefaulted);\n#else\n    if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n\n    if (FlagOn(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SELF_RELATIVE))\n    {\n        return STATUS_INVALID_SECURITY_DESCR;\n    }\n    else\n    {\n        if (GroupDefaulted)\n            SetFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_GROUP_DEFAULTED);\n        else\n            ClearFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_GROUP_DEFAULTED);\n\n        ((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Group = Group;\n\n        return STATUS_SUCCESS;\n    }\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetControlSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PSECURITY_DESCRIPTOR_CONTROL Control,\n    _Out_ PULONG Revision\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetControlSecurityDescriptor(SecurityDescriptor, Control, Revision);\n#else\n    if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n\n    if (FlagOn(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SELF_RELATIVE))\n    {\n        return STATUS_INVALID_SECURITY_DESCR;\n    }\n    else\n    {\n        *Control = ((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control;\n        *Revision = ((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision;\n        return STATUS_SUCCESS;\n    }\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetControlSecurityDescriptor(\n    _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,\n    _In_ SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlSetControlSecurityDescriptor(SecurityDescriptor, ControlBitsOfInterest, ControlBitsToSet);\n#else\n    if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION)\n        return STATUS_UNKNOWN_REVISION;\n\n    if (FlagOn(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, SE_SELF_RELATIVE))\n    {\n        return STATUS_INVALID_SECURITY_DESCR;\n    }\n    else\n    {\n        ClearFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, ControlBitsOfInterest);\n        SetFlag(((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Control, ControlBitsToSet);\n        return STATUS_SUCCESS;\n    }\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhAddAccessAllowedAceEx(\n    _In_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ UCHAR AceFlags,\n    _In_ ACCESS_MASK AccessMask,\n    _In_ PCSID Sid\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlAddAccessAllowedAceEx(Acl, AceRevision, AceFlags, AccessMask, (PSID)Sid);\n#else\n    PVOID offset;\n\n    if (!PhValidSid(Sid))\n        return STATUS_INVALID_SID;\n    if (!PhValidAcl(Acl))\n        return STATUS_INVALID_ACL;\n\n    // Allow caller to pass any revision <= current ACL revision (matches RtlAddAce semantics). (dmex)\n    if (AceRevision > Acl->AclRevision)\n        return STATUS_REVISION_MISMATCH;\n    if (!PhFirstFreeAce(Acl, &offset))\n        return STATUS_INVALID_ACL;\n\n    ULONG sidLength = PhLengthSid(Sid);\n    ULONG aceSize = UFIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + sidLength;\n\n    // Ensure fits into USHORT and inside ACL buffer. (dmex)\n    if (aceSize >= USHRT_MAX)\n        return STATUS_INVALID_BUFFER_SIZE;\n    if ((ULONG_PTR)RTL_PTR_ADD(offset, aceSize) > (ULONG_PTR)RTL_PTR_ADD(Acl, Acl->AclSize))\n        return STATUS_ALLOTTED_SPACE_EXCEEDED;\n\n    PACCESS_ALLOWED_ACE ace = (PACCESS_ALLOWED_ACE)offset;\n    PACE_HEADER header = &ace->Header;\n    header->AceType = ACCESS_ALLOWED_ACE_TYPE;\n    header->AceFlags = AceFlags;\n    header->AceSize = (USHORT)aceSize;\n    ace->Mask = AccessMask;\n    RtlCopyMemory(&ace->SidStart, Sid, sidLength);\n    Acl->AceCount++;\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhAddAccessAllowedAce(\n    _In_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ACCESS_MASK AccessMask,\n    _In_ CONST SID* Sid\n    )\n{\n    return PhAddAccessAllowedAceEx(Acl, AceRevision, 0, AccessMask, Sid);\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhAcquirePebLock(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlAcquirePebLock();\n#else\n    return RtlEnterCriticalSection(NtCurrentPeb()->FastPebLock);\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhReleasePebLock(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlReleasePebLock();\n#else\n    return RtlLeaveCriticalSection(NtCurrentPeb()->FastPebLock);\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhAcquireLoaderLock(\n    VOID\n    )\n{\n    return RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhReleaseLoaderLock(\n    VOID\n    )\n{\n    return RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);\n}\n\nFORCEINLINE\nUSHORT\nNTAPI\nPhGetCurrentThreadPrimaryGroup(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetCurrentThreadPrimaryGroup();\n#else\n    return NtCurrentTeb()->PrimaryGroupAffinity.Group;\n#endif\n}\n\nFORCEINLINE\nULONG\nNTAPI\nPhGetCurrentServiceSessionId(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetCurrentServiceSessionId();\n#else\n    if (NtCurrentPeb()->SharedData && NtCurrentPeb()->SharedData->ServiceSessionId)\n        return NtCurrentPeb()->SharedData->ServiceSessionId;\n    else\n        return 0;\n#endif\n}\n\nFORCEINLINE\nULONG\nNTAPI\nPhGetActiveConsoleId(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetActiveConsoleId();\n#else\n    if (NtCurrentPeb()->SharedData && NtCurrentPeb()->SharedData->ServiceSessionId)\n        return NtCurrentPeb()->SharedData->ActiveConsoleId;\n    else\n        return USER_SHARED_DATA->ActiveConsoleId;\n#endif\n}\n\nFORCEINLINE\nLONGLONG\nNTAPI\nPhGetConsoleSessionForegroundProcessId(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetConsoleSessionForegroundProcessId();\n#else\n    if (NtCurrentPeb()->SharedData && NtCurrentPeb()->SharedData->ServiceSessionId)\n        return NtCurrentPeb()->SharedData->ConsoleSessionForegroundProcessId;\n    else\n        return USER_SHARED_DATA->ConsoleSessionForegroundProcessId;\n#endif\n}\n\nFORCEINLINE\nPWSTR\nNTAPI\nPhRtlGetNtSystemRoot(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlGetNtSystemRoot();\n#else\n    if (NtCurrentPeb()->SharedData && NtCurrentPeb()->SharedData->ServiceSessionId) // RtlGetCurrentServiceSessionId\n        return NtCurrentPeb()->SharedData->NtSystemRoot;\n    else\n        return USER_SHARED_DATA->NtSystemRoot;\n#endif\n}\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhAreLongPathsEnabled(\n    VOID\n    )\n{\n//#if defined(PHNT_NATIVE_INLINE)\n//    return RtlAreLongPathsEnabled();\n//#else\n    return NtCurrentPeb()->IsLongPathAwareProcess;\n//#endif\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhFreeUnicodeString(\n    _Inout_ _At_(UnicodeString->Buffer, _Frees_ptr_opt_) PUNICODE_STRING UnicodeString\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    RtlFreeUnicodeString(UnicodeString);\n#else\n    if (UnicodeString->Buffer)\n    {\n        RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString->Buffer);\n        memset(UnicodeString, 0, sizeof(UNICODE_STRING));\n    }\n#endif\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhFreeAnsiString(\n    _Inout_ _At_(AnsiString->Buffer, _Frees_ptr_opt_) PANSI_STRING AnsiString\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    RtlFreeAnsiString(AnsiString);\n#else\n    if (AnsiString->Buffer)\n    {\n        RtlFreeHeap(RtlProcessHeap(), 0, AnsiString->Buffer);\n        memset(AnsiString, 0, sizeof(ANSI_STRING));\n    }\n#endif\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhFreeUTF8String(\n    _Inout_ _At_(Utf8String->Buffer, _Frees_ptr_opt_) PUTF8_STRING Utf8String\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    RtlFreeUTF8String(Utf8String);\n#else\n    if (Utf8String->Buffer)\n    {\n        RtlFreeHeap(RtlProcessHeap(), 0, Utf8String->Buffer);\n        memset(Utf8String, 0, sizeof(UTF8_STRING));\n    }\n#endif\n}\n\nFORCEINLINE\nPVOID\nNTAPI\nPhFreeSid(\n    _In_ _Post_invalid_ PSID Sid\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlFreeSid(Sid);\n#else\n    RtlFreeHeap(RtlProcessHeap(), 0, Sid);\n    return NULL;\n#endif\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhDeleteBoundaryDescriptor(\n    _In_ _Post_invalid_ POBJECT_BOUNDARY_DESCRIPTOR BoundaryDescriptor\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    RtlDeleteBoundaryDescriptor(BoundaryDescriptor);\n#else\n    RtlFreeHeap(RtlProcessHeap(), 0, BoundaryDescriptor);\n#endif\n}\n\n//#define RtlDeleteSecurityObject(ObjectDescriptor) RtlFreeHeap(RtlProcessHeap(), 0, *(ObjectDescriptor))\n//FORCEINLINE\n//NTSTATUS\n//RtlDeleteSecurityObject(\n//    _Inout_ PSECURITY_DESCRIPTOR *ObjectDescriptor\n//    )\n//{\n//    RtlFreeHeap(RtlProcessHeap(), 0, *ObjectDescriptor);\n//    return STATUS_SUCCESS;\n//}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhDestroyEnvironment(\n    _In_ _Post_invalid_ PVOID Environment\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlDestroyEnvironment(Environment);\n#else\n    RtlFreeHeap(RtlProcessHeap(), 0, Environment);\n    return STATUS_SUCCESS;\n#endif\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhDestroyProcessParameters(\n    _In_ _Post_invalid_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters\n    )\n{\n#if defined(PHNT_NATIVE_INLINE)\n    return RtlDestroyProcessParameters(ProcessParameters);\n#else\n    RtlFreeHeap(RtlProcessHeap(), 0, ProcessParameters);\n    return STATUS_SUCCESS;\n#endif\n}\n\n#define RtlAcquirePebLock PhAcquirePebLock\n#define RtlReleasePebLock PhReleasePebLock\n#define RtlGetCurrentThreadPrimaryGroup PhGetCurrentThreadPrimaryGroup\n#define RtlGetCurrentServiceSessionId PhGetCurrentServiceSessionId\n#define RtlGetActiveConsoleId PhGetActiveConsoleId\n#define RtlGetConsoleSessionForegroundProcessId PhGetConsoleSessionForegroundProcessId\n#define RtlGetNtSystemRoot PhRtlGetNtSystemRoot\n#define RtlAreLongPathsEnabled PhAreLongPathsEnabled\n//#define RtlFreeUnicodeString(UnicodeString) { if ((UnicodeString)->Buffer) RtlFreeHeap(RtlProcessHeap(), 0, (UnicodeString)->Buffer); memset(UnicodeString, 0, sizeof(UNICODE_STRING)); }\n#define RtlFreeUnicodeString PhFreeUnicodeString\n//#define RtlFreeAnsiString(UnicodeString) {if ((AnsiString)->Buffer) RtlFreeHeap(RtlProcessHeap(), 0, (AnsiString)->Buffer); memset(AnsiString, 0, sizeof(ANSI_STRING));}\n#define RtlFreeAnsiString PhFreeAnsiString\n//#define RtlFreeUTF8String(Utf8String) {if ((Utf8String)->Buffer) RtlFreeHeap(RtlProcessHeap(), 0, (Utf8String)->Buffer); memset(Utf8String, 0, sizeof(UTF8_STRING));}\n#define RtlFreeUTF8String PhFreeUTF8String\n//#define RtlFreeSid(Sid) RtlFreeHeap(RtlProcessHeap(), 0, (Sid))\n#define RtlFreeSid PhFreeSid\n//#define RtlDeleteBoundaryDescriptor(BoundaryDescriptor) RtlFreeHeap(RtlProcessHeap(), 0, (BoundaryDescriptor))\n#define RtlDeleteBoundaryDescriptor PhDeleteBoundaryDescriptor\n//#define RtlDestroyEnvironment(Environment) RtlFreeHeap(RtlProcessHeap(), 0, (Environment))\n#define RtlDestroyEnvironment PhDestroyEnvironment\n//#define RtlDestroyProcessParameters(ProcessParameters) RtlFreeHeap(RtlProcessHeap(), 0, (ProcessParameters))\n#define RtlDestroyProcessParameters PhDestroyProcessParameters\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenNamedObjectPath(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PSID Sid,\n    _Out_ PPH_STRING* ObjectPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetAppContainerNamedObjectPath(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PSID AppContainerSid,\n    _In_ BOOLEAN RelativePath,\n    _Out_ PPH_STRING* ObjectPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetTokenSessionId(\n    _In_ HANDLE TokenHandle,\n    _In_ ULONG SessionId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetTokenPrivilege(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PCWSTR PrivilegeName,\n    _In_opt_ PLUID PrivilegeLuid,\n    _In_ ULONG Attributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetTokenPrivilege2(\n    _In_ HANDLE TokenHandle,\n    _In_ LONG Privilege,\n    _In_ ULONG Attributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAdjustPrivilege(\n    _In_opt_ PCWSTR PrivilegeName,\n    _In_opt_ LONG Privilege,\n    _In_ BOOLEAN Enable\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetTokenGroups(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PCWSTR GroupName,\n    _In_opt_ PSID GroupSid,\n    _In_ ULONG Attributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetTokenIsVirtualizationEnabled(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN IsVirtualizationEnabled\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIntegrityLevelRID(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PMANDATORY_LEVEL_RID IntegrityLevelRID,\n    _Out_opt_ PWSTR *IntegrityString\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIntegrityLevel(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PMANDATORY_LEVEL IntegrityLevel,\n    _Out_opt_ PWSTR *IntegrityString\n    );\n\ntypedef union _PH_INTEGRITY_LEVEL\n{\n    struct\n    {\n        //\n        // Lower bits describe amendments to the MANDATOR_LEVEL which are a\n        // combination of additional features closely related to integrity on\n        // the system.\n        //\n        USHORT Plus : 1;\n        USHORT AppContainer : 1;\n        USHORT Spare : 10;\n\n        USHORT Mandatory : 4; // MANDATORY_LEVEL\n    };\n\n    USHORT Level;\n} PH_INTEGRITY_LEVEL, *PPH_INTEGRITY_LEVEL;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIntegrityLevelEx(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PPH_INTEGRITY_LEVEL IntegrityLevel,\n    _Out_opt_ PCPH_STRINGREF* IntegrityString\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessMandatoryPolicy(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PACCESS_MASK Mask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessMandatoryPolicy(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK Mask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenProcessTrustLevelRID(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PULONG ProtectionType,\n    _Out_opt_ PULONG ProtectionLevel,\n    _Out_opt_ PPH_STRING* TrustLevelString,\n    _Out_opt_ PPH_STRING* TrustLevelSidString\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileBasicInformation(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_BASIC_INFORMATION BasicInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileBasicInformation(\n    _In_ HANDLE FileHandle,\n    _In_ PFILE_BASIC_INFORMATION BasicInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileFullAttributesInformation(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileStandardInformation(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_STANDARD_INFORMATION StandardInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileCompletionNotificationMode(\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileSize(\n    _In_ HANDLE FileHandle,\n    _Out_ PLARGE_INTEGER Size\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileSize(\n    _In_ HANDLE FileHandle,\n    _In_ PLARGE_INTEGER Size\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFilePosition(\n    _In_ HANDLE FileHandle,\n    _Out_ PLARGE_INTEGER Position\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFilePosition(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PLARGE_INTEGER Position\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileAllocationSize(\n    _In_ HANDLE FileHandle,\n    _Out_ PLARGE_INTEGER AllocationSize\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileAllocationSize(\n    _In_ HANDLE FileHandle,\n    _In_ PLARGE_INTEGER AllocationSize\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileIndexNumber(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_INTERNAL_INFORMATION IndexNumber\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileDelete(\n    _In_ HANDLE FileHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileRename(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ BOOLEAN ReplaceIfExists,\n    _In_ PCPH_STRINGREF NewFileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileIoPriorityHint(\n    _In_ HANDLE FileHandle,\n    _Out_ IO_PRIORITY_HINT* IoPriorityHint\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileIoPriorityHint(\n    _In_ HANDLE FileHandle,\n    _In_ IO_PRIORITY_HINT IoPriorityHint\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFlushBuffersFile(\n    _In_ HANDLE FileHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileHandleName(\n    _In_ HANDLE FileHandle,\n    _Out_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileNetworkPhysicalName(\n    _In_ HANDLE FileHandle,\n    _Out_ PPH_STRING* FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileAllInformation(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_ALL_INFORMATION *FileInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileId(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_ID_INFORMATION FileId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIdsUsingFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *ProcessIdsUsingFile\n    );\n\ntypedef USN *PUSN;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileUsn(\n    _In_ HANDLE FileHandle,\n    _Out_ PUSN Usn\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileBypassIO(\n    _In_ HANDLE FileHandle,\n    _In_ BOOLEAN Enable\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTransactionManagerBasicInformation(\n    _In_ HANDLE TransactionManagerHandle,\n    _Out_ PTRANSACTIONMANAGER_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTransactionManagerLogFileName(\n    _In_ HANDLE TransactionManagerHandle,\n    _Out_ PPH_STRING *LogFileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTransactionBasicInformation(\n    _In_ HANDLE TransactionHandle,\n    _Out_ PTRANSACTION_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTransactionPropertiesInformation(\n    _In_ HANDLE TransactionHandle,\n    _Out_opt_ PLARGE_INTEGER Timeout,\n    _Out_opt_ TRANSACTION_OUTCOME *Outcome,\n    _Out_opt_ PPH_STRING *Description\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetResourceManagerBasicInformation(\n    _In_ HANDLE ResourceManagerHandle,\n    _Out_opt_ PGUID Guid,\n    _Out_opt_ PPH_STRING *Description\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetEnlistmentBasicInformation(\n    _In_ HANDLE EnlistmentHandle,\n    _Out_ PENLISTMENT_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenDriverByBaseAddress(\n    _Out_ PHANDLE DriverHandle,\n    _In_ PVOID BaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenDriver(\n    _Out_ PHANDLE DriverHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetDriverName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *Name\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetDriverImageFileName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *Name\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetDriverServiceKeyName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *ServiceKeyName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadDriver(\n    _In_opt_ PVOID BaseAddress,\n    _In_opt_ PCPH_STRINGREF Name,\n    _In_ PCPH_STRINGREF FileName\n    );\n\ntypedef _Function_class_(PH_ENUM_PROCESS_MODULES_LIMITED_CALLBACK)\nNTSTATUS NTAPI PH_ENUM_PROCESS_MODULES_LIMITED_CALLBACK(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress,\n    _In_ PVOID ImageBase,\n    _In_ SIZE_T ImageSize,\n    _In_ PPH_STRING FileName,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_PROCESS_MODULES_LIMITED_CALLBACK* PPH_ENUM_PROCESS_MODULES_LIMITED_CALLBACK;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModulesLimited(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_LIMITED_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef _Function_class_(PH_ENUM_PROCESS_MODULES_RUNDOWN_CALLBACK)\nNTSTATUS NTAPI PH_ENUM_PROCESS_MODULES_RUNDOWN_CALLBACK(\n    _In_ PVOID ImageBase,\n    _In_ SIZE_T ImageSize,\n    _In_ PPH_STRING FileName,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_PROCESS_MODULES_RUNDOWN_CALLBACK* PPH_ENUM_PROCESS_MODULES_RUNDOWN_CALLBACK;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModulesRundown(\n    _In_opt_ HANDLE ProcessId,\n    _In_ PPH_ENUM_PROCESS_MODULES_RUNDOWN_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\n/**\n * A callback function passed to PhEnumProcessModules() and called for each process module.\n *\n * \\param Module A structure providing information about the module.\n * \\param Context A user-defined value passed to PhEnumProcessModules().\n *\n * \\return TRUE to continue the enumeration, FALSE to stop.\n */\ntypedef _Function_class_(PH_ENUM_PROCESS_MODULES_CALLBACK)\nBOOLEAN NTAPI PH_ENUM_PROCESS_MODULES_CALLBACK(\n    _In_ PLDR_DATA_TABLE_ENTRY Module,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_PROCESS_MODULES_CALLBACK* PPH_ENUM_PROCESS_MODULES_CALLBACK;\n\n#define PH_ENUM_PROCESS_MODULES_DONT_RESOLVE_WOW64_FS 0x1\n#define PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME 0x2\n#define PH_ENUM_PROCESS_MODULES_LIMIT 0x800\n\ntypedef struct _PH_ENUM_PROCESS_MODULES_PARAMETERS\n{\n    PPH_ENUM_PROCESS_MODULES_CALLBACK Callback;\n    PVOID Context;\n    ULONG Flags;\n} PH_ENUM_PROCESS_MODULES_PARAMETERS, *PPH_ENUM_PROCESS_MODULES_PARAMETERS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModulesEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessModuleLoadCount(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG LoadCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModules32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModules32Ex(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessModuleLoadCount32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG LoadCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessQuotaLimits(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PQUOTA_LIMITS QuotaLimits\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessQuotaLimits(\n    _In_ HANDLE ProcessHandle,\n    _In_ QUOTA_LIMITS QuotaLimits\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessEmptyWorkingSet(\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessWorkingSetEmpty(\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessEmptyPageWorkingSet(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T Size\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessPriorityClass(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PUCHAR PriorityClass\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessPriorityClass(\n    _In_ HANDLE ProcessHandle,\n    _In_ UCHAR PriorityClass\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessIoPriority(\n    _In_ HANDLE ProcessHandle,\n    _In_ IO_PRIORITY_HINT IoPriority\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessPagePriority(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG PagePriority\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessPriorityBoost(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN DisablePriorityBoost\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessAffinityMask(\n    _In_ HANDLE ProcessHandle,\n    _In_ KAFFINITY AffinityMask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessActivityModerationState(\n    _In_ PCPH_STRINGREF ModerationIdentifier,\n    _Out_ PSYSTEM_ACTIVITY_MODERATION_APP_SETTINGS ModerationSettings\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessActivityModerationState(\n    _In_ PCPH_STRINGREF ModerationIdentifier,\n    _In_ SYSTEM_ACTIVITY_MODERATION_APP_TYPE ModerationType,\n    _In_ SYSTEM_ACTIVITY_MODERATION_STATE ModerationState\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessGroupAffinity(\n    _In_ HANDLE ProcessHandle,\n    _In_ GROUP_AFFINITY GroupAffinity\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessPowerThrottlingState(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPOWER_THROTTLING_PROCESS_STATE PowerThrottlingState\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessPowerThrottlingState(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG ControlMask,\n    _In_ ULONG StateMask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF SectionName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG SectionPageProtection,\n    _In_ ULONG AllocationAttributes,\n    _In_opt_ HANDLE FileHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMapViewOfSection(\n    _In_ HANDLE SectionHandle,\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress,\n    _In_ SIZE_T CommitSize,\n    _In_opt_ PLARGE_INTEGER SectionOffset,\n    _Inout_ PSIZE_T ViewSize,\n    _In_ SECTION_INHERIT InheritDisposition,\n    _In_ ULONG AllocationType,\n    _In_ ULONG PageProtection\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnmapViewOfSection(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumKernelModules(\n    _Out_ PRTL_PROCESS_MODULES *Modules\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumKernelModulesEx(\n    _Out_ PRTL_PROCESS_MODULE_INFORMATION_EX *Modules\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetKernelFileName(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetKernelFileNameEx(\n    _Out_opt_ PPH_STRING* FileName,\n    _Out_ PVOID* ImageBase,\n    _Out_ ULONG* ImageSize\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSecureKernelFileName(\n    VOID\n    );\n\n/**\n * Gets a pointer to the first process information structure in a buffer returned by\n * PhEnumProcesses().\n *\n * \\param Processes A pointer to a buffer returned by PhEnumProcesses().\n */\n#define PH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes))\n\n/**\n * Gets a pointer to the process information structure after a given structure.\n *\n * \\param Process A pointer to a process information structure.\n *\n * \\return A pointer to the next process information structure, or NULL if there are no more.\n */\n#define PH_NEXT_PROCESS(Process) ( \\\n    ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \\\n    (PSYSTEM_PROCESS_INFORMATION)PTR_ADD_OFFSET((Process), \\\n    ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \\\n    NULL \\\n    )\n\n#define PH_PROCESS_EXTENSION(Process) \\\n    ((PSYSTEM_PROCESS_INFORMATION_EXTENSION)PTR_ADD_OFFSET((Process), \\\n    UFIELD_OFFSET(SYSTEM_PROCESS_INFORMATION, Threads) + \\\n    sizeof(SYSTEM_THREAD_INFORMATION) * \\\n    ((PSYSTEM_PROCESS_INFORMATION)(Process))->NumberOfThreads))\n\n#define PH_EXTENDED_PROCESS_EXTENSION(Process) \\\n    ((PSYSTEM_PROCESS_INFORMATION_EXTENSION)PTR_ADD_OFFSET((Process), \\\n    UFIELD_OFFSET(SYSTEM_PROCESS_INFORMATION, Threads) + \\\n    sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION) * \\\n    ((PSYSTEM_PROCESS_INFORMATION)(Process))->NumberOfThreads))\n\n// rev from PsGetProcessStartKey (dmex)\n#define PH_PROCESS_EXTENSION_STARTKEY(SequenceNumber) \\\n    ((SequenceNumber) | (((ULONGLONG)USER_SHARED_DATA->BootId) << 0x30)) // SYSTEM_PROCESS_INFORMATION_EXTENSION->ProcessSequenceNumber\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcesses(\n    _Out_ PVOID *Processes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessesEx(\n    _Out_ PVOID *Processes,\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass\n    );\n\ntypedef _Function_class_(PH_ENUM_PROCESS_THREADS)\nNTSTATUS NTAPI PH_ENUM_PROCESS_THREADS(\n    _In_ ULONG NumberOfThreads,\n    _In_ PSYSTEM_THREAD_INFORMATION Threads,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_PROCESS_THREADS* PPH_ENUM_PROCESS_THREADS;\n\nNTSTATUS PhEnumProcessThreads(\n    _In_ HANDLE ProcessId,\n    _In_ PPH_ENUM_PROCESS_THREADS Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef _Function_class_(PH_ENUM_NEXT_PROCESS)\nNTSTATUS NTAPI PH_ENUM_NEXT_PROCESS(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_NEXT_PROCESS* PPH_ENUM_NEXT_PROCESS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumNextProcess(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPH_ENUM_NEXT_PROCESS Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef _Function_class_(PH_ENUM_NEXT_THREAD)\nNTSTATUS NTAPI PH_ENUM_NEXT_THREAD(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_NEXT_THREAD* PPH_ENUM_NEXT_THREAD;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumNextThread(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPH_ENUM_NEXT_THREAD Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessesForSession(\n    _Out_ PVOID *Processes,\n    _In_ ULONG SessionId\n    );\n\nPHLIBAPI\nPSYSTEM_PROCESS_INFORMATION\nNTAPI\nPhFindProcessInformation(\n    _In_ PVOID Processes,\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nPSYSTEM_PROCESS_INFORMATION\nNTAPI\nPhFindProcessInformationByImageName(\n    _In_ PVOID Processes,\n    _In_ PCPH_STRINGREF ImageName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumHandles(\n    _Out_ PSYSTEM_HANDLE_INFORMATION *Handles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumHandlesEx(\n    _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_HANDLE_SNAPSHOT_INFORMATION *Handles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumHandlesGeneric(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN EnableHandleSnapshot,\n    _Out_ PSYSTEM_HANDLE_INFORMATION_EX* Handles\n    );\n\n#define PH_FIRST_PAGEFILE(Pagefiles) ( \\\n    /* The size of a pagefile can never be 0. A TotalSize of 0\n     * is used to indicate that there are no pagefiles.\n     */ ((PSYSTEM_PAGEFILE_INFORMATION)(Pagefiles))->TotalSize ? \\\n    (PSYSTEM_PAGEFILE_INFORMATION)(Pagefiles) : \\\n    NULL \\\n    )\n#define PH_NEXT_PAGEFILE(Pagefile) ( \\\n    ((PSYSTEM_PAGEFILE_INFORMATION)(Pagefile))->NextEntryOffset ? \\\n    (PSYSTEM_PAGEFILE_INFORMATION)PTR_ADD_OFFSET((Pagefile), \\\n    ((PSYSTEM_PAGEFILE_INFORMATION)(Pagefile))->NextEntryOffset) : \\\n    NULL \\\n    )\n\n#define PH_FIRST_PAGEFILE_EX(Pagefiles) ( \\\n    ((PSYSTEM_PAGEFILE_INFORMATION_EX)(Pagefiles))->TotalSize ? \\\n    (PSYSTEM_PAGEFILE_INFORMATION_EX)(Pagefiles) : \\\n    NULL \\\n    )\n#define PH_NEXT_PAGEFILE_EX(Pagefile) ( \\\n    ((PSYSTEM_PAGEFILE_INFORMATION_EX)(Pagefile))->NextEntryOffset ? \\\n    (PSYSTEM_PAGEFILE_INFORMATION_EX)PTR_ADD_OFFSET((Pagefile), \\\n    ((PSYSTEM_PAGEFILE_INFORMATION_EX)(Pagefile))->NextEntryOffset) : \\\n    NULL \\\n    )\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumPagefiles(\n    _Out_ PVOID *Pagefiles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumPagefilesEx(\n    _Out_ PVOID *Pagefiles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumPoolTagInformation(\n    _Out_ PVOID* Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumBigPoolInformation(\n    _Out_ PVOID* Buffer\n    );\n\n_Must_inspect_result_\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsContainer(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _Out_opt_ PBOOLEAN IsContainer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsDotNet(\n    _In_ HANDLE ProcessId,\n    _Out_ PBOOLEAN IsDotNet\n    );\n\n#define PH_CLR_USE_SECTION_CHECK 0x1\n#define PH_CLR_NO_WOW64_CHECK 0x2\n#define PH_CLR_KNOWN_IS_WOW64 0x4\n\n#define PH_CLR_VERSION_1_0 0x1\n#define PH_CLR_VERSION_1_1 0x2\n#define PH_CLR_VERSION_2_0 0x4\n#define PH_CLR_VERSION_4_ABOVE 0x8\n#define PH_CLR_CORE_3_0_ABOVE 0x10\n#define PH_CLR_VERSION_MASK 0x1f\n\n#define PH_CLR_MSCORLIB_PRESENT 0x10000\n#define PH_CLR_CORELIB_PRESENT 0x20000\n#define PH_CLR_PROCESS_IS_WOW64 0x100000\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsDotNetEx(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ULONG InFlags,\n    _Out_opt_ PBOOLEAN IsDotNet,\n    _Out_opt_ PULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenDirectoryObject(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName\n    );\n\n/**\n * A callback function passed to PhEnumDirectoryObjects() and called for each directory object.\n *\n * \\param RootDirectory The handle to the current object directory.\n * \\param Name The name of the object.\n * \\param TypeName The name of the object's type.\n * \\param Context A user-defined value passed to PhEnumDirectoryObjects().\n * \\return TRUE to continue the enumeration, FALSE to stop.\n */\ntypedef _Function_class_(PH_ENUM_DIRECTORY_OBJECTS)\nNTSTATUS NTAPI PH_ENUM_DIRECTORY_OBJECTS(\n    _In_ HANDLE RootDirectory,\n    _In_ PPH_STRINGREF Name,\n    _In_ PPH_STRINGREF TypeName,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_DIRECTORY_OBJECTS* PPH_ENUM_DIRECTORY_OBJECTS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumDirectoryObjects(\n    _In_ HANDLE DirectoryHandle,\n    _In_ PPH_ENUM_DIRECTORY_OBJECTS Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef _Function_class_(PH_ENUM_DIRECTORY_FILE)\nBOOLEAN NTAPI PH_ENUM_DIRECTORY_FILE(\n    _In_ HANDLE RootDirectory,\n    _In_ PVOID Information,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_DIRECTORY_FILE* PPH_ENUM_DIRECTORY_FILE;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PCPH_STRINGREF SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhEnumDirectoryFileZ(\n    _In_ HANDLE FileHandle,\n    _In_ PCWSTR SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_STRINGREF searchPattern;\n\n    PhInitializeStringRef(&searchPattern, SearchPattern);\n\n    return PhEnumDirectoryFile(\n        FileHandle,\n        &searchPattern,\n        Callback,\n        Context\n        );\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumDirectoryFileEx(\n    _In_ HANDLE FileHandle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_opt_ PCPH_STRINGREF SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhEnumDirectoryFileExZ(\n    _In_ HANDLE FileHandle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_ PCWSTR SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_STRINGREF searchPattern;\n\n    PhInitializeStringRef(&searchPattern, SearchPattern);\n\n    return PhEnumDirectoryFileEx(\n        FileHandle,\n        FileInformationClass,\n        ReturnSingleEntry,\n        &searchPattern,\n        Callback,\n        Context\n        );\n}\n\ntypedef _Function_class_(PH_ENUM_REPARSE_POINT)\nNTSTATUS NTAPI PH_ENUM_REPARSE_POINT(\n    _In_ HANDLE RootDirectory,\n    _In_ PVOID Information,\n    _In_ SIZE_T InformationLength,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_REPARSE_POINT* PPH_ENUM_REPARSE_POINT;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumReparsePointInformation(\n    _In_ HANDLE FileHandle,\n    _In_ PPH_ENUM_REPARSE_POINT Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef _Function_class_(PH_ENUM_OBJECT_ID)\nNTSTATUS NTAPI PH_ENUM_OBJECT_ID(\n    _In_ HANDLE RootDirectory,\n    _In_ PVOID Information,\n    _In_ SIZE_T InformationLength,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_OBJECT_ID* PPH_ENUM_OBJECT_ID;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumObjectIdInformation(\n    _In_ HANDLE FileHandle,\n    _In_ PPH_ENUM_OBJECT_ID Callback,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_FIRST_FILE_EA(Information) \\\n    ((PFILE_FULL_EA_INFORMATION)(Information))\n#define PH_NEXT_FILE_EA(Information) \\\n    (((PFILE_FULL_EA_INFORMATION)(Information))->NextEntryOffset ? \\\n    (PTR_ADD_OFFSET((Information), ((PFILE_FULL_EA_INFORMATION)(Information))->NextEntryOffset)) : \\\n    NULL \\\n    )\n\ntypedef _Function_class_(PH_ENUM_FILE_EA)\nNTSTATUS NTAPI PH_ENUM_FILE_EA(\n    _In_ HANDLE RootDirectory,\n    _In_ PFILE_FULL_EA_INFORMATION Information,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_FILE_EA* PPH_ENUM_FILE_EA;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumFileExtendedAttributes(\n    _In_ HANDLE FileHandle,\n    _In_ PPH_ENUM_FILE_EA Callback,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_FIRST_STREAM(Streams) ((PFILE_STREAM_INFORMATION)(Streams))\n#define PH_NEXT_STREAM(Stream) ( \\\n    ((PFILE_STREAM_INFORMATION)(Stream))->NextEntryOffset ? \\\n    (PFILE_STREAM_INFORMATION)(PTR_ADD_OFFSET((Stream), \\\n    ((PFILE_STREAM_INFORMATION)(Stream))->NextEntryOffset)) : \\\n    NULL \\\n    )\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileExtendedAttributes(\n    _In_ HANDLE FileHandle,\n    _In_ PPH_BYTESREF Name,\n    _In_opt_ PPH_BYTESREF Value\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumFileStreams(\n    _In_ HANDLE FileHandle,\n    _Out_ PVOID *Streams\n    );\n\n#define PH_FIRST_LINK(Links) ((PFILE_LINK_ENTRY_INFORMATION)(Links))\n#define PH_NEXT_LINK(Links) ( \\\n    ((PFILE_LINK_ENTRY_INFORMATION)(Links))->NextEntryOffset ? \\\n    (PFILE_LINK_ENTRY_INFORMATION)(PTR_ADD_OFFSET((Links), \\\n    ((PFILE_LINK_ENTRY_INFORMATION)(Links))->NextEntryOffset)) : \\\n    NULL \\\n    )\n\ntypedef _Function_class_(PH_ENUM_FILE_HARDLINKS)\nBOOLEAN NTAPI PH_ENUM_FILE_HARDLINKS(\n    _In_ PFILE_LINK_ENTRY_INFORMATION Information,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_FILE_HARDLINKS* PPH_ENUM_FILE_HARDLINKS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumFileHardLinks(\n    _In_ HANDLE FileHandle,\n    _Out_ PVOID *HardLinks\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQuerySymbolicLinkObject(\n    _Out_ PPH_STRING* LinkTarget,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhQuerySymbolicLinkObjectZ(\n    _Out_ PPH_STRING* LinkTarget,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCWSTR ObjectName\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, ObjectName);\n\n    return PhQuerySymbolicLinkObject(LinkTarget, RootDirectory, &name);\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhUpdateMupDevicePrefixes(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUpdateDosDevicePrefixes(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFlushVolumeCache(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhResolveDevicePrefix(\n    _In_ PCPH_STRINGREF Name\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetFileName(\n    _In_ PPH_STRING FileName\n    );\n\n// \"X:\\\"\n#define PATH_IS_WIN32_DRIVE_PREFIX(s) ( \\\n    (s)->Length >= (3 * sizeof(WCHAR)) && \\\n    (((s)->Buffer[0] >= L'A' && \\\n      (s)->Buffer[0] <= L'Z') || \\\n     ((s)->Buffer[0] >= L'a' && \\\n      (s)->Buffer[0] <= L'z')) && \\\n    (s)->Buffer[1] == L':' && \\\n    (s)->Buffer[2] == OBJ_NAME_PATH_SEPARATOR)\n\n// \"\\??\\\" or \"\\\\?\\\" or \"\\\\.\\\"\n#define PATH_IS_WIN32_DOSDEVICES_PREFIX(s) ( \\\n    (s)->Length >= (4 * sizeof(WCHAR)) && \\\n    (s)->Buffer[0] == '\\\\' && \\\n    ((s)->Buffer[1] == '?' || (s)->Buffer[1] == '\\\\') && \\\n    (s)->Buffer[2] == '?' || (s)->Buffer[2] == '.'&& \\\n    (s)->Buffer[3] == '\\\\')\n\n// \".\" or \"..\"\n#define PATH_IS_WIN32_RELATIVE_PREFIX(s) ( \\\n    (s)->Length == (1 * sizeof(WCHAR)) && (s)->Buffer[0] == L'.' || \\\n    (s)->Length == (2 * sizeof(WCHAR)) && (s)->Buffer[0] == L'.' && (s)->Buffer[1] == L'.')\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhDosPathNameToNtPathName(\n    _In_ PCPH_STRINGREF Name\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDosLongPathNameToNtPathNameWithStatus(\n    _In_ PCWSTR DosFileName,\n    _Out_ PUNICODE_STRING NtFileName,\n    _Out_opt_ PWSTR* FilePart,\n    _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetNtPathRootPrefix(\n    _In_ PCPH_STRINGREF Name\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetExistingPathPrefix(\n    _In_ PCPH_STRINGREF Name\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetExistingPathPrefixWin32(\n    _In_ PCPH_STRINGREF Name\n    );\n\ntypedef enum _PH_MODULE_TYPE\n{\n    PH_MODULE_TYPE_UNKNOWN = 0,\n    PH_MODULE_TYPE_MODULE = 1,\n    PH_MODULE_TYPE_MAPPED_FILE = 2,\n    PH_MODULE_TYPE_WOW64_MODULE = 3,\n    PH_MODULE_TYPE_KERNEL_MODULE = 4,\n    PH_MODULE_TYPE_MAPPED_IMAGE = 5,\n    PH_MODULE_TYPE_ELF_MAPPED_IMAGE = 6,\n    PH_MODULE_TYPE_ENCLAVE_MODULE = 7\n} PH_MODULE_TYPE;\n\ntypedef struct _PH_MODULE_INFO\n{\n    ULONG Type;\n    ULONG Flags;\n    ULONG Size;\n    ULONG EnclaveType;\n\n    PVOID BaseAddress;\n    PVOID ParentBaseAddress;\n    PVOID OriginalBaseAddress;\n    PVOID EntryPoint;\n\n    PPH_STRING Name;\n    PPH_STRING FileName;\n\n    USHORT LoadOrderIndex; // -1 if N/A\n    USHORT LoadCount; // -1 if N/A\n    USHORT LoadReason; // -1 if N/A\n    USHORT Reserved;\n    LARGE_INTEGER LoadTime; // 0 if N/A\n\n    PVOID EnclaveBaseAddress;\n    SIZE_T EnclaveSize;\n} PH_MODULE_INFO, *PPH_MODULE_INFO;\n\n/**\n * A callback function passed to PhEnumGenericModules() and called for each process module.\n *\n * \\param Module A structure providing information about the module.\n * \\param Context A user-defined value passed to PhEnumGenericModules().\n * \\return TRUE to continue the enumeration, FALSE to stop.\n */\ntypedef _Function_class_(PH_ENUM_GENERIC_MODULES_CALLBACK)\nBOOLEAN NTAPI PH_ENUM_GENERIC_MODULES_CALLBACK(\n    _In_ PPH_MODULE_INFO Module,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_GENERIC_MODULES_CALLBACK* PPH_ENUM_GENERIC_MODULES_CALLBACK;\n\n#define PH_ENUM_GENERIC_MAPPED_FILES 0x1\n#define PH_ENUM_GENERIC_MAPPED_IMAGES 0x2\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumGenericModules(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_KEY_PREDEFINE(Number) ((HANDLE)(LONG_PTR)(-3 - (Number) * 2))\n#define PH_KEY_IS_PREDEFINED(Predefine) (((LONG_PTR)(Predefine) < 0) && ((LONG_PTR)(Predefine) & 0x1))\n#define PH_KEY_PREDEFINE_TO_NUMBER(Predefine) (ULONG)(((-(LONG_PTR)(Predefine) - 3) >> 1))\n\n#define PH_KEY_LOCAL_MACHINE PH_KEY_PREDEFINE(0) // \\Registry\\Machine\n#define PH_KEY_USERS PH_KEY_PREDEFINE(1) // \\Registry\\User\n#define PH_KEY_CLASSES_ROOT PH_KEY_PREDEFINE(2) // \\Registry\\Machine\\Software\\Classes\n#define PH_KEY_CURRENT_USER PH_KEY_PREDEFINE(3) // \\Registry\\User\\<SID>\n#define PH_KEY_CURRENT_USER_NUMBER 3\n#define PH_KEY_MAXIMUM_PREDEFINE 4\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName,\n    _In_ ULONG Attributes,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG Disposition\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhCreateKeyZ(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCWSTR ObjectName,\n    _In_ ULONG Attributes,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG Disposition\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, ObjectName);\n\n    return PhCreateKey(KeyHandle, DesiredAccess, RootDirectory, &name, Attributes, CreateOptions, Disposition);\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName,\n    _In_ ULONG Attributes\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhOpenKeyZ(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCWSTR ObjectName,\n    _In_ ULONG Attributes\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, ObjectName);\n\n    return PhOpenKey(KeyHandle, DesiredAccess, RootDirectory, &name, Attributes);\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadAppKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_INFORMATION_CLASS KeyInformationClass,\n    _Out_ PVOID *Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryKeyInformation(\n    _In_ HANDLE KeyHandle,\n    _Out_opt_ PKEY_FULL_INFORMATION Information\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryKeyLastWriteTime(\n    _In_ HANDLE KeyHandle,\n    _Out_ PLARGE_INTEGER LastWriteTime\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName,\n    _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\n    _Out_ PVOID *Buffer\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhQueryValueKeyZ(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName,\n    _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\n    _Out_ PVOID* Buffer\n    )\n{\n    PH_STRINGREF valueName;\n\n    PhInitializeStringRef(&valueName, ValueName);\n\n    return PhQueryValueKey(\n        KeyHandle,\n        &valueName,\n        KeyValueInformationClass,\n        Buffer\n        );\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName,\n    _In_ ULONG ValueType,\n    _In_ PVOID Buffer,\n    _In_ ULONG BufferLength\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetValueKeyZ(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName,\n    _In_ ULONG ValueType,\n    _In_ PVOID Buffer,\n    _In_ ULONG BufferLength\n    )\n{\n    PH_STRINGREF valueName;\n\n    PhInitializeStringRef(&valueName, ValueName);\n\n    return PhSetValueKey(\n        KeyHandle,\n        &valueName,\n        ValueType,\n        Buffer,\n        BufferLength\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetValueKeyStringZ(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName,\n    _In_ PCPH_STRINGREF String\n    )\n{\n    PH_STRINGREF valueName;\n\n    if (String->Length > ULONG_MAX)\n    {\n        return STATUS_INTEGER_OVERFLOW;\n    }\n\n    PhInitializeStringRef(&valueName, ValueName);\n\n    return PhSetValueKey(\n        KeyHandle,\n        &valueName,\n        REG_SZ,\n        String->Buffer,\n        (ULONG)String->Length + sizeof(UNICODE_NULL)\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetValueKeyString2Z(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName,\n    _In_ PCWSTR String\n    )\n{\n    PH_STRINGREF valueName;\n    PH_STRINGREF valueString;\n\n    PhInitializeStringRef(&valueName, ValueName);\n    PhInitializeStringRef(&valueString, String);\n\n    return PhSetValueKey(\n        KeyHandle,\n        &valueName,\n        REG_SZ,\n        valueString.Buffer,\n        (ULONG)valueString.Length + sizeof(UNICODE_NULL)\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhSetValueKeyUlong(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName,\n    _In_ ULONG Value\n    )\n{\n    PH_STRINGREF valueName;\n\n    PhInitializeStringRef(&valueName, ValueName);\n\n    return PhSetValueKey(\n        KeyHandle,\n        &valueName,\n        REG_DWORD,\n        &Value,\n        sizeof(ULONG)\n        );\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhDeleteValueKeyZ(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName\n    )\n{\n    PH_STRINGREF valueName;\n\n    PhInitializeStringRef(&valueName, ValueName);\n\n    return PhDeleteValueKey(KeyHandle, &valueName);\n}\n\ntypedef _Function_class_(PH_ENUM_KEY_CALLBACK)\nBOOLEAN NTAPI PH_ENUM_KEY_CALLBACK(\n    _In_ HANDLE RootDirectory,\n    _In_ PVOID Information,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_KEY_CALLBACK* PPH_ENUM_KEY_CALLBACK;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumerateKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_INFORMATION_CLASS InformationClass,\n    _In_ PPH_ENUM_KEY_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumerateValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_VALUE_INFORMATION_CLASS InformationClass,\n    _In_ PPH_ENUM_KEY_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumerateValueKeyEx(\n    _In_ HANDLE KeyHandle,\n    _In_ ULONG Index,\n    _In_ KEY_VALUE_INFORMATION_CLASS InformationClass,\n    _Out_ PVOID* Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileWin32(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileWin32Ex(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG CreateStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileWin32ExAlt(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_ ULONG CreateFlags,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _Out_opt_ PULONG CreateStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileEx(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG CreateStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenFileWin32(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenFileWin32Ex(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions,\n    _Out_opt_ PULONG OpenStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions,\n    _Out_opt_ PULONG OpenStatus\n    );\n\ntypedef struct _PH_FILE_ID_DESCRIPTOR\n{\n    FILE_ID_TYPE Type;\n    union\n    {\n        LARGE_INTEGER FileId;\n        GUID ObjectId;\n        FILE_ID_128 ExtendedFileId;\n    };\n} PH_FILE_ID_DESCRIPTOR, *PPH_FILE_ID_DESCRIPTOR;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenFileById(\n    _Out_ PHANDLE FileHandle,\n    _In_ HANDLE VolumeHandle,\n    _In_ PPH_FILE_ID_DESCRIPTOR FileId,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhReOpenFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ HANDLE OriginalFileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhReadFile(\n    _In_ HANDLE FileHandle,\n    _In_ PVOID Buffer,\n    _In_opt_ ULONG NumberOfBytesToRead,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _Out_opt_ PULONG NumberOfBytesRead\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteFile(\n    _In_ HANDLE FileHandle,\n    _In_ PVOID Buffer,\n    _In_opt_ ULONG NumberOfBytesToWrite,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _Out_opt_ PULONG NumberOfBytesWritten\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryFullAttributesFileWin32(\n    _In_ PCWSTR FileName,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryFullAttributesFile(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryAttributesFileWin32(\n    _In_ PCWSTR FileName,\n    _Out_ PFILE_BASIC_INFORMATION FileInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryAttributesFile(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_ PFILE_BASIC_INFORMATION FileInformation\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDoesFileExistWin32(\n    _In_ PCWSTR FileName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDoesFileExist(\n    _In_ PCPH_STRINGREF FileName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDoesDirectoryExistWin32(\n    _In_ PCWSTR FileName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDoesDirectoryExist(\n    _In_ PCPH_STRINGREF FileName\n    );\n\nPHLIBAPI\nRTL_PATH_TYPE\nNTAPI\nPhDetermineDosPathNameType(\n    _In_ PCPH_STRINGREF FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteFileWin32(\n    _In_ PCWSTR FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteFile(\n    _In_ PCPH_STRINGREF FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCopyFileWin32(\n    _In_ PCWSTR OldFileName,\n    _In_ PCWSTR NewFileName,\n    _In_ BOOLEAN FailIfExists\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCopyFileChunkWin32(\n    _In_ PCWSTR OldFileName,\n    _In_ PCWSTR NewFileName,\n    _In_ BOOLEAN FailIfExists\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMoveFile(\n    _In_ PCPH_STRINGREF OldFileName,\n    _In_ PCPH_STRINGREF NewFileName,\n    _In_ BOOLEAN FailIfExists\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMoveFileWin32(\n    _In_ PCWSTR OldFileName,\n    _In_ PCWSTR NewFileName,\n    _In_ BOOLEAN FailIfExists\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateDirectoryWin32(\n    _In_ PCPH_STRINGREF DirectoryPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateDirectory(\n    _In_ PCPH_STRINGREF DirectoryPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateDirectoryFullPathWin32(\n    _In_ PCPH_STRINGREF FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateDirectoryFullPath(\n    _In_ PCPH_STRINGREF FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteDirectory(\n    _In_ PCPH_STRINGREF DirectoryPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteDirectoryWin32(\n    _In_ PCPH_STRINGREF DirectoryPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteDirectoryFullPath(\n    _In_ PCPH_STRINGREF FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreatePipe(\n    _Out_ PHANDLE PipeReadHandle,\n    _Out_ PHANDLE PipeWriteHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreatePipeEx(\n    _Out_ PHANDLE PipeReadHandle,\n    _Out_ PHANDLE PipeWriteHandle,\n    _In_opt_ PSECURITY_ATTRIBUTES PipeReadAttributes,\n    _In_opt_ PSECURITY_ATTRIBUTES PipeWriteAttributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateNamedPipe(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PCPH_STRINGREF PipeName\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhCreateNamedPipeZ(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PCWSTR PipeName\n    )\n{\n    PH_STRINGREF pipeName;\n\n    PhInitializeStringRef(&pipeName, PipeName);\n\n    return PhCreateNamedPipe(PipeHandle, &pipeName);\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConnectPipe(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PCPH_STRINGREF PipeName\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhConnectPipeZ(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PCWSTR PipeName\n    )\n{\n    PH_STRINGREF pipeName;\n\n    PhInitializeStringRef(&pipeName, PipeName);\n\n    return PhConnectPipe(PipeHandle, &pipeName);\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhListenNamedPipe(\n    _In_ HANDLE PipeHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDisconnectNamedPipe(\n    _In_ HANDLE PipeHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhPeekNamedPipe(\n    _In_ HANDLE PipeHandle,\n    _Out_writes_bytes_opt_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG NumberOfBytesRead,\n    _Out_opt_ PULONG NumberOfBytesAvailable,\n    _Out_opt_ PULONG NumberOfBytesLeftInMessage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTransceiveNamedPipe(\n    _In_ HANDLE PipeHandle,\n    _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWaitForNamedPipe(\n    _In_ PCWSTR PipeName,\n    _In_opt_ ULONG Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhImpersonateClientOfNamedPipe(\n    _In_ HANDLE PipeHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDisableImpersonateNamedPipe(\n    _In_ HANDLE PipeHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetNamedPipeClientComputerName(\n    _In_ HANDLE PipeHandle,\n    _In_ ULONG ClientComputerNameLength,\n    _Out_ PVOID ClientComputerName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetNamedPipeClientProcessId(\n    _In_ HANDLE PipeHandle,\n    _Out_ PHANDLE ClientProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetNamedPipeServerProcessId(\n    _In_ HANDLE PipeHandle,\n    _Out_ PHANDLE ServerProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumDirectoryNamedPipe(\n    _In_opt_ PCPH_STRINGREF SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDefaultNpAcl(\n    _Out_ PACL* DefaultNpAc\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetContextThread(\n    _In_ HANDLE ThreadHandle,\n    _Inout_ PCONTEXT ThreadContext\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadName(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PPH_STRING *ThreadName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadName(\n    _In_ HANDLE ThreadHandle,\n    _In_ PCWSTR ThreadName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadAffinityMask(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PKAFFINITY AffinityMask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadAffinityMask(\n    _In_ HANDLE ThreadHandle,\n    _In_ KAFFINITY AffinityMask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadBasePriorityClientId(\n    _In_ CLIENT_ID ClientId,\n    _In_ KPRIORITY Increment\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadBasePriority(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPRIORITY Increment\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadIoPriority(\n    _In_ HANDLE ThreadHandle,\n    _In_ IO_PRIORITY_HINT IoPriority\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadPagePriority(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG PagePriority\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadPriorityBoost(\n    _In_ HANDLE ThreadHandle,\n    _In_ BOOLEAN DisablePriorityBoost\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadPowerThrottlingState(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PPOWER_THROTTLING_THREAD_STATE PowerThrottlingState\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadIdealProcessor(\n    _In_ HANDLE ThreadHandle,\n    _In_ PPROCESSOR_NUMBER ProcessorNumber,\n    _Out_opt_ PPROCESSOR_NUMBER PreviousIdealProcessor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetThreadGroupAffinity(\n    _In_ HANDLE ThreadHandle,\n    _In_ GROUP_AFFINITY GroupAffinity\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadLastSystemCall(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PTHREAD_LAST_SYSCALL_INFORMATION LastSystemCall\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateImpersonationToken(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PHANDLE TokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhImpersonateToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE TokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhRevertImpersonationToken(\n    _In_ HANDLE ThreadHandle\n    );\n\ntypedef struct _PH_PROCESS_DEBUG_HEAP_ENTRY\n{\n    ULONG Flags;\n    ULONG Signature;\n    UCHAR HeapFrontEndType;\n    ULONG NumberOfEntries;\n    PVOID BaseAddress;\n    SIZE_T BytesAllocated;\n    SIZE_T BytesCommitted;\n} PH_PROCESS_DEBUG_HEAP_ENTRY, *PPH_PROCESS_DEBUG_HEAP_ENTRY;\n\ntypedef struct _PH_PROCESS_DEBUG_HEAP_ENTRY32\n{\n    ULONG Flags;\n    ULONG Signature;\n    UCHAR HeapFrontEndType;\n    ULONG NumberOfEntries;\n    ULONG BaseAddress;\n    ULONG BytesAllocated;\n    ULONG BytesCommitted;\n} PH_PROCESS_DEBUG_HEAP_ENTRY32, *PPH_PROCESS_DEBUG_HEAP_ENTRY32;\n\ntypedef struct _PH_PROCESS_DEBUG_HEAP_INFORMATION\n{\n    ULONG NumberOfHeaps;\n    PVOID DefaultHeap;\n    PH_PROCESS_DEBUG_HEAP_ENTRY Heaps[1];\n} PH_PROCESS_DEBUG_HEAP_INFORMATION, *PPH_PROCESS_DEBUG_HEAP_INFORMATION;\n\ntypedef struct _PH_PROCESS_DEBUG_HEAP_INFORMATION32\n{\n    ULONG NumberOfHeaps;\n    ULONG DefaultHeap;\n    PH_PROCESS_DEBUG_HEAP_ENTRY32 Heaps[1];\n} PH_PROCESS_DEBUG_HEAP_INFORMATION32, *PPH_PROCESS_DEBUG_HEAP_INFORMATION32;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryProcessHeapInformation(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_PROCESS_DEBUG_HEAP_INFORMATION* HeapInformation\n    );\n\ntypedef _Function_class_(PH_ENUM_PROCESS_LOCKS)\nNTSTATUS NTAPI PH_ENUM_PROCESS_LOCKS(\n    _In_ ULONG NumberOfLocks,\n    _In_ PRTL_PROCESS_LOCK_INFORMATION Locks,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_PROCESS_LOCKS* PPH_ENUM_PROCESS_LOCKS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryProcessLockInformation(\n    _In_ HANDLE ProcessId,\n    _In_ PPH_ENUM_PROCESS_LOCKS Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryVolumeInformationFile(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FS_INFORMATION_CLASS FsInformationClass,\n    _Out_writes_bytes_(FsInformationLength) PVOID FsInformation,\n    _In_ ULONG FsInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMachineTypeAttributes(\n    _In_ USHORT Machine,\n    _Out_ MACHINE_ATTRIBUTES* Attributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessArchitecture(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PUSHORT ProcessArchitecture\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessImageBaseAddress(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID* ImageBaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessCodePage(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PUSHORT ProcessCodePage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessConsoleCodePage(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN ConsoleOutputCP,\n    _Out_ PUSHORT ConsoleCodePage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessSecurityDomain(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONGLONG SecurityDomain\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessServerSilo(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ServerSilo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessSequenceNumber(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONGLONG SequenceNumber\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessStartKey(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONGLONG ProcessStartKey\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessSystemDllInitBlock(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPS_SYSTEM_DLL_INIT_BLOCK SystemDllInitBlock\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessTelemetryIdInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_TELEMETRY_ID_INFORMATION* TelemetryInformation,\n    _Out_opt_ PULONG TelemetryInformationLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessTlsBitMapCounters(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG TlsBitMapCount,\n    _Out_ PULONG TlsExpansionBitMapCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadLastStatusValue(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PNTSTATUS LastStatusValue\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessMTAUsage(\n    _In_ HANDLE ProcessHandle,\n    _Out_opt_ PULONG MTAInits,\n    _Out_opt_ PULONG MTAIncInits\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadApartmentFlags(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ApartmentState,\n    _Out_opt_ PULONG ComInits\n    );\n\ntypedef enum _PH_APARTMENT_TYPE\n{\n    PH_APARTMENT_TYPE_INVALID = 0,\n    PH_APARTMENT_TYPE_MAIN_STA,\n    PH_APARTMENT_TYPE_STA,\n    PH_APARTMENT_TYPE_APPLICATION_STA,\n    PH_APARTMENT_TYPE_MTA,\n    PH_APARTMENT_TYPE_IMPLICIT_MTA\n} PH_APARTMENT_TYPE;\n\ntypedef struct _PH_APARTMENT_INFO\n{\n    PH_APARTMENT_TYPE Type;\n    BOOLEAN InNeutral;\n    ULONG ComInits;\n    ULONG Flags;\n} PH_APARTMENT_INFO, *PPH_APARTMENT_INFO;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadApartment(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_APARTMENT_INFO ApartmentInfo\n    );\n\ntypedef struct _PH_COM_CALLSTATE\n{\n    ULONG ClientPID;\n    ULONG ServerPID;\n    ULONG ServerTID;\n    GUID ServerGuid;\n} PH_COM_CALLSTATE, *PPH_COM_CALLSTATE;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadApartmentCallState(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_COM_CALLSTATE ApartmentCallState\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadRpcState(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN HasRpcState\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadCriticalSectionOwnerThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessId,\n    _Out_ PULONG ThreadId\n    );\n\ntypedef enum _PH_THREAD_SOCKET_STATE\n{\n    PH_THREAD_SOCKET_STATE_NONE,\n    PH_THREAD_SOCKET_STATE_SHARED,\n    PH_THREAD_SOCKET_STATE_DISCONNECTED,\n    PH_THREAD_SOCKET_STATE_NOT_TCPIP\n} PH_THREAD_SOCKET_STATE, *PPH_THREAD_SOCKET_STATE;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadSocketState(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_THREAD_SOCKET_STATE ThreadSocketState\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadStackLimits(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG_PTR LowPart,\n    _Out_ PULONG_PTR HighPart\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadStackSize(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG_PTR StackUsage,\n    _Out_ PULONG_PTR StackLimit\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadIsFiber(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN ThreadIsFiber\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSwitchToThread(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsFirmwareSupported(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFirmwareEnvironmentVariable(\n    _In_ PCPH_STRINGREF VariableName,\n    _In_ PCPH_STRINGREF VendorGuid,\n    _Out_writes_bytes_opt_(*ValueLength) PVOID* ValueBuffer,\n    _Out_opt_ PULONG ValueLength,\n    _Out_opt_ PULONG ValueAttributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFirmwareEnvironmentVariable(\n    _In_ PCPH_STRINGREF VariableName,\n    _In_ PCPH_STRINGREF VendorGuid,\n    _In_reads_bytes_opt_(ValueLength) PVOID ValueBuffer,\n    _In_ ULONG ValueLength,\n    _In_ ULONG Attributes\n    );\n\n#define PH_FIRST_FIRMWARE_VALUE(Variables) ((PVARIABLE_NAME_AND_VALUE)(Variables))\n#define PH_NEXT_FIRMWARE_VALUE(Variables) ( \\\n    ((PVARIABLE_NAME_AND_VALUE)(Variables))->NextEntryOffset ? \\\n    (PVARIABLE_NAME_AND_VALUE)(PTR_ADD_OFFSET((Variables), \\\n    ((PVARIABLE_NAME_AND_VALUE)(Variables))->NextEntryOffset)) : \\\n    NULL \\\n    )\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumFirmwareEnvironmentValues(\n    _In_ SYSTEM_ENVIRONMENT_INFORMATION_CLASS InformationClass,\n    _Out_ PVOID* Variables\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetSystemEnvironmentBootToFirmware(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateExecutionRequiredRequest(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE PowerRequestHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDestroyExecutionRequiredRequest(\n    _In_opt_ _Post_ptr_invalid_ HANDLE PowerRequestHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFreezeProcess(\n    _Out_ PHANDLE ProcessStateChangeHandle,\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFreezeProcessById(\n    _Out_ PHANDLE ProcessStateChangeHandle,\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhThawProcess(\n    _In_ HANDLE ProcessStateChangeHandle,\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhThawProcessById(\n    _In_ HANDLE ProcessStateChangeHandle,\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFreezeThread(\n    _Out_ PHANDLE ThreadStateChangeHandle,\n    _In_ HANDLE ThreadHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFreezeThreadById(\n    _Out_ PHANDLE ThreadStateChangeHandle,\n    _In_ HANDLE ThreadId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhThawThread(\n    _In_ HANDLE ThreadStateChangeHandle,\n    _In_ HANDLE ThreadHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhThawThreadById(\n    _In_ HANDLE ThreadStateChangeHandle,\n    _In_ HANDLE ThreadId\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsProcessExecutionRequired(\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhProcessExecutionRequiredEnable(\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhProcessExecutionRequiredDisable(\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsKnownDllFileName(\n    _In_ PPH_STRING FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSystemProcessorPerformanceDistribution(\n    _Out_ PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION* Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSystemProcessorPerformanceDistributionEx(\n    _In_ USHORT ProcessorGroup,\n    _Out_ PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION* Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSystemLogicalProcessorInformation(\n    _In_ LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,\n    _Out_ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* Buffer,\n    _Out_ PULONG BufferLength\n    );\n\ntypedef struct _PH_LOGICAL_PROCESSOR_INFORMATION\n{\n    ULONG ProcessorCoreCount;\n    ULONG ProcessorNumaCount;\n    ULONG ProcessorLogicalCount;\n    ULONG ProcessorPackageCount;\n} PH_LOGICAL_PROCESSOR_INFORMATION, *PPH_LOGICAL_PROCESSOR_INFORMATION;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSystemLogicalProcessorRelationInformation(\n    _Out_ PPH_LOGICAL_PROCESSOR_INFORMATION LogicalProcessorInformation\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsProcessorFeaturePresent(\n    _In_ ULONG ProcessorFeature\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetCurrentProcessorNumber(\n    _Out_ PPROCESSOR_NUMBER ProcessorNumber\n    );\n\nPHLIBAPI\nUSHORT\nNTAPI\nPhGetActiveProcessorCount(\n    _In_ USHORT ProcessorGroup\n    );\n\ntypedef struct _PH_PROCESSOR_NUMBER\n{\n    USHORT Group;\n    USHORT Number;\n} PH_PROCESSOR_NUMBER, *PPH_PROCESSOR_NUMBER;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessorNumberFromIndex(\n    _In_ ULONG ProcessorIndex,\n    _Out_ PPH_PROCESSOR_NUMBER ProcessorNumber\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessorGroupActiveAffinityMask(\n    _In_ USHORT ProcessorGroup,\n    _Out_ PKAFFINITY ActiveProcessorMask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessorSystemAffinityMask(\n    _Out_ PKAFFINITY ActiveProcessorsAffinityMask\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetNumaHighestNodeNumber(\n    _Out_ PUSHORT NodeNumber\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetNumaProcessorNode(\n    _In_ PPH_PROCESSOR_NUMBER ProcessorNumber,\n    _Out_ PUSHORT NodeNumber\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhPrefetchVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ SIZE_T NumberOfEntries,\n    _In_ PMEMORY_RANGE_ENTRY VirtualAddresses\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetVirtualMemoryPagePriority(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG PagePriority,\n    _In_ PVOID VirtualAddress,\n    _In_ SIZE_T NumberOfBytes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGuardGrantSuppressedCallAccess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessorNominalFrequency(\n    _In_ PPH_PROCESSOR_NUMBER ProcessorNumber,\n    _Out_ PULONG NominalFrequency\n    );\n\ntypedef struct _PH_SYSTEM_STORE_COMPRESSION_INFORMATION\n{\n    ULONG CompressionPid;\n    ULONG WorkingSetSize;\n    SIZE_T TotalDataCompressed;\n    SIZE_T TotalCompressedSize;\n    SIZE_T TotalUniqueDataCompressed;\n} PH_SYSTEM_STORE_COMPRESSION_INFORMATION, *PPH_SYSTEM_STORE_COMPRESSION_INFORMATION;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSystemCompressionStoreInformation(\n    _Out_ PPH_SYSTEM_STORE_COMPRESSION_INFORMATION SystemCompressionStoreInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSystemFileCacheSize(\n    _Out_ PSYSTEM_FILECACHE_INFORMATION CacheInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetSystemFileCacheSize(\n    _In_ SIZE_T MinimumFileCacheSize,\n    _In_ SIZE_T MaximumFileCacheSize,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateEvent(\n    _Out_ PHANDLE EventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ EVENT_TYPE EventType,\n    _In_ BOOLEAN InitialState\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeviceIoControlFile(\n    _In_ HANDLE DeviceHandle,\n    _In_ ULONG IoControlCode,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_to_opt_(OutputBufferLength, *ReturnLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\ntypedef _Function_class_(PH_ENUM_MEMORY_CALLBACK)\nNTSTATUS NTAPI PH_ENUM_MEMORY_CALLBACK(\n    _In_ HANDLE ProcessHandle,\n    _In_ PMEMORY_BASIC_INFORMATION BasicInformation,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_MEMORY_CALLBACK *PPH_ENUM_MEMORY_CALLBACK;\n\ntypedef _Function_class_(PH_ENUM_MEMORY_BULK_CALLBACK)\nNTSTATUS NTAPI PH_ENUM_MEMORY_BULK_CALLBACK(\n    _In_ HANDLE ProcessHandle,\n    _In_ PMEMORY_BASIC_INFORMATION BasicInfo,\n    _In_ SIZE_T Count,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_MEMORY_BULK_CALLBACK *PPH_ENUM_MEMORY_BULK_CALLBACK;\n\ntypedef _Function_class_(PH_ENUM_MEMORY_PAGE_CALLBACK)\nNTSTATUS NTAPI PH_ENUM_MEMORY_PAGE_CALLBACK(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG_PTR NumberOfEntries,\n    _In_ PMEMORY_WORKING_SET_BLOCK Blocks,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_MEMORY_PAGE_CALLBACK *PPH_ENUM_MEMORY_PAGE_CALLBACK;\n\ntypedef _Function_class_(PH_ENUM_MEMORY_ATTRIBUTE_CALLBACK)\nNTSTATUS NTAPI PH_ENUM_MEMORY_ATTRIBUTE_CALLBACK(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T SizeOfImage,\n    _In_ ULONG_PTR NumberOfEntries,\n    _In_ PMEMORY_WORKING_SET_EX_INFORMATION Blocks,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_ENUM_MEMORY_ATTRIBUTE_CALLBACK *PPH_ENUM_MEMORY_ATTRIBUTE_CALLBACK;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_MEMORY_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumVirtualMemoryBulk(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ BOOLEAN BulkQuery,\n    _In_ PPH_ENUM_MEMORY_BULK_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumVirtualMemoryPages(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_MEMORY_PAGE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumVirtualMemoryAttributes(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T Size,\n    _In_ PPH_ENUM_MEMORY_ATTRIBUTE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetKernelDebuggerInformation(\n    _Out_opt_ PBOOLEAN KernelDebuggerEnabled,\n    _Out_opt_ PBOOLEAN KernelDebuggerPresent\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsDebuggerPresent(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetDeviceType(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _Out_ DEVICE_TYPE* DeviceType\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsAppExecutionAliasTarget(\n    _In_ PPH_STRING FileName\n    );\n\ntypedef BOOLEAN (NTAPI *PPH_ENUM_PROCESS_ENCLAVES_CALLBACK)(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID EnclaveAddress,\n    _In_ PLDR_SOFTWARE_ENCLAVE Enclave,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessEnclaves(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID LdrEnclaveList,\n    _In_ PPH_ENUM_PROCESS_ENCLAVES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef BOOLEAN (NTAPI *PPH_ENUM_PROCESS_ENCLAVE_MODULES_CALLBACK)(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_SOFTWARE_ENCLAVE Enclave,\n    _In_ PVOID EntryAddress,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessEnclaveModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID EnclaveAddress,\n    _In_ PLDR_SOFTWARE_ENCLAVE Enclave,\n    _In_ PPH_ENUM_PROCESS_ENCLAVE_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessLdrTableEntryNames(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _Out_ PPH_STRING* Name,\n    _Out_ PPH_STRING* FileName\n    );\n\n#ifdef _M_ARM64\nPHLIBAPI\nVOID\nNTAPI\nPhEcContextToNativeContext(\n    _Out_ PCONTEXT Context,\n    _In_ PARM64EC_NT_CONTEXT EcContext\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhNativeContextToEcContext(\n    _When_(InitializeEc, _Out_) _When_(!InitializeEc, _Inout_) PARM64EC_NT_CONTEXT EcContext,\n    _In_ PCONTEXT Context,\n    _In_ BOOLEAN InitializeEc\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhIsEcCode(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID CodePointer,\n    _Out_ PBOOLEAN IsEcCode\n    );\n#endif\n\ntypedef enum _PH_MOTW_ZONE_ID\n{\n    PhMotwZoneIdLocalComputer,\n    PhMotwZoneIdLocalIntranet,\n    PhMotwZoneIdTrustedSites,\n    PhMotwZoneIdInternet,\n    PhMotwZoneIdRestrictedSites,\n    PhMotwZoneIdUnknown,\n} PH_MOTW_ZONE_ID, *PPH_MOTW_ZONE_ID;\n\nPHLIBAPI\nNTSTATUS\nPhGetFileMotw(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_opt_ PPH_MOTW_ZONE_ID ZoneId,\n    _Out_opt_ PPH_STRING* ReferrerUrl,\n    _Out_opt_ PPH_STRING* HostUrl\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFlushProcessHeapsRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFilterLoadUnload(\n    _In_ PCPH_STRINGREF ServiceName,\n    _In_ BOOLEAN LoadDriver\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFilterSendMessage(\n    _In_ HANDLE Port,\n    _In_reads_bytes_(InBufferSize) PVOID InBuffer,\n    _In_ ULONG InBufferSize,\n    _Out_writes_bytes_to_opt_(OutputBufferSize, *BytesReturned) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferSize,\n    _Out_ PULONG BytesReturned\n    );\n\ntypedef struct _FILTER_MESSAGE_HEADER\n{\n    //\n    //  OUT\n    //\n    //  Total buffer length in bytes, including the FILTER_REPLY_HEADER, of\n    //  the expected reply.  If no reply is expected, 0 is returned.\n    //\n\n    ULONG ReplyLength;\n\n    //\n    //  OUT\n    //\n    //  Unique Id for this message.  This will be set when the kernel message\n    //  satisfies this FilterGetMessage or FilterInstanceGetMessage request.\n    //  If replying to this message, this is the MessageId that should be used.\n    //\n\n    ULONGLONG MessageId;\n\n    //\n    //  General filter-specific buffer data follows...\n    //\n\n} FILTER_MESSAGE_HEADER, *PFILTER_MESSAGE_HEADER;\n\ntypedef struct _FILTER_REPLY_HEADER\n{\n    //\n    //  IN.\n    //\n    //  Status of this reply. This status will be returned back to the filter\n    //  driver who is waiting for a reply.\n    //\n\n    NTSTATUS Status;\n\n    //\n    //  IN\n    //\n    //  Unique Id for this message.  This id was returned in the\n    //  FILTER_MESSAGE_HEADER from the kernel message to which we are replying.\n    //\n\n    ULONGLONG MessageId;\n\n    //\n    //  General filter-specific buffer data follows...\n    //\n\n} FILTER_REPLY_HEADER, *PFILTER_REPLY_HEADER;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFilterGetMessage(\n    _In_ HANDLE Port,\n    _Out_writes_bytes_(MessageBufferSize) PFILTER_MESSAGE_HEADER MessageBuffer,\n    _In_ ULONG MessageBufferSize,\n    _Inout_ LPOVERLAPPED Overlapped\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFilterReplyMessage(\n    _In_ HANDLE Port,\n    _In_reads_bytes_(ReplyBufferSize) PFILTER_REPLY_HEADER ReplyBuffer,\n    _In_ ULONG ReplyBufferSize\n    );\n\n// Filter connect options: Windows 8 and above\n#define FLT_PORT_FLAG_SYNC_HANDLE 0x00000001\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFilterConnectCommunicationPort(\n    _In_ PCPH_STRINGREF PortName,\n    _In_ ULONG Options,\n    _In_reads_bytes_opt_(SizeOfContext) PVOID ConnectionContext,\n    _In_ USHORT SizeOfContext,\n    _In_opt_ PSECURITY_ATTRIBUTES SecurityAttributes,\n    _Outptr_ PHANDLE Port\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/phnativeinl.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2018-2024\n *\n */\n\n#ifndef _PH_PHNATINL_H\n#define _PH_PHNATINL_H\n\n// This file contains inlined native API wrapper functions. These functions were previously\n// exported, but are now inlined because they are extremely simple wrappers around equivalent native\n// API functions.\n\n/**\n * Gets basic information for a event.\n *\n * \\param EventHandle A handle to a event. The handle must have EVENT_QUERY_STATE access.\n * \\param BasicInformation A variable which receives the information.\n */\nFORCEINLINE\nNTSTATUS\nPhGetEventBasicInformation(\n    _In_ HANDLE EventHandle,\n    _Out_ PEVENT_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryEvent(\n        EventHandle,\n        EventBasicInformation,\n        BasicInformation,\n        sizeof(EVENT_BASIC_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhOpenMutant(\n    _Out_ PHANDLE MutantHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_opt_ PCPH_STRINGREF ObjectName\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (ObjectName)\n    {\n        if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&objectName, NULL, 0);\n    }\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = NtOpenMutant(\n        MutantHandle,\n        DesiredAccess,\n        &objectAttributes\n        );\n\n    return status;\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetMutantBasicInformation(\n    _In_ HANDLE MutantHandle,\n    _Out_ PMUTANT_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryMutant(\n        MutantHandle,\n        MutantBasicInformation,\n        BasicInformation,\n        sizeof(MUTANT_BASIC_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetMutantOwnerInformation(\n    _In_ HANDLE MutantHandle,\n    _Out_ PMUTANT_OWNER_INFORMATION OwnerInformation\n    )\n{\n    return NtQueryMutant(\n        MutantHandle,\n        MutantOwnerInformation,\n        OwnerInformation,\n        sizeof(MUTANT_OWNER_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetSectionBasicInformation(\n    _In_ HANDLE SectionHandle,\n    _Out_ PSECTION_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQuerySection(\n        SectionHandle,\n        SectionBasicInformation,\n        BasicInformation,\n        sizeof(SECTION_BASIC_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetSemaphoreBasicInformation(\n    _In_ HANDLE SemaphoreHandle,\n    _Out_ PSEMAPHORE_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQuerySemaphore(\n        SemaphoreHandle,\n        SemaphoreBasicInformation,\n        BasicInformation,\n        sizeof(SEMAPHORE_BASIC_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetTimerBasicInformation(\n    _In_ HANDLE TimerHandle,\n    _Out_ PTIMER_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryTimer(\n        TimerHandle,\n        TimerBasicInformation,\n        BasicInformation,\n        sizeof(TIMER_BASIC_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * The action to be performed when the calling thread exits.\n *\n * \\param DebugObjectHandle A handle to a process' debug object.\n * \\param KillProcessOnExit If this parameter is TRUE, the thread terminates all attached processes on exit\n * (note that this is the default). Otherwise, the thread detaches from all processes being debugged on exit.\n * \\return Successful or errant status.\n */\nFORCEINLINE\nNTSTATUS\nPhSetDebugKillProcessOnExit(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ BOOLEAN KillProcessOnExit\n    )\n{\n    ULONG killProcessOnExit;\n\n    killProcessOnExit = KillProcessOnExit ? 1 : 0;\n\n    return NtSetInformationDebugObject(\n        DebugObjectHandle,\n        DebugObjectKillProcessOnExitInformation,\n        &killProcessOnExit,\n        sizeof(ULONG),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetProcessIsCetEnabled(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsCetEnabled,\n    _Out_ PBOOLEAN IsCetStrictModeEnabled\n    )\n{\n    NTSTATUS status;\n    PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;\n\n    policyInfo.Policy = ProcessUserShadowStackPolicy;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessMitigationPolicy,\n        &policyInfo,\n        sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n#if !defined(NTDDI_WIN10_CO) || (NTDDI_VERSION < NTDDI_WIN10_CO)\n        *IsCetEnabled = _bittest((const PLONG)&policyInfo.ControlFlowGuardPolicy.Flags, 0);\n        *IsCetStrictModeEnabled = _bittest((const PLONG)&policyInfo.ControlFlowGuardPolicy.Flags, 4);\n#else\n        *IsCetEnabled = !!policyInfo.UserShadowStackPolicy.EnableUserShadowStack;\n        *IsCetStrictModeEnabled = !!policyInfo.UserShadowStackPolicy.EnableUserShadowStackStrictMode;\n#endif\n    }\n\n    return status;\n}\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetSystemHypervisorSharedPageInformation(\n    _Out_ PSYSTEM_HYPERVISOR_USER_SHARED_DATA* HypervisorSharedUserVa\n    )\n{\n    NTSTATUS status;\n    SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION HypervisorSharedPageInfo;\n\n    status = NtQuerySystemInformation(\n        SystemHypervisorSharedPageInformation,\n        &HypervisorSharedPageInfo,\n        sizeof(SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *HypervisorSharedUserVa = HypervisorSharedPageInfo.HypervisorSharedUserVa;\n    }\n\n    return status;\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetSystemShadowStackInformation(\n    _Out_ PSYSTEM_SHADOW_STACK_INFORMATION ShadowStackInformation\n    )\n{\n    return NtQuerySystemInformation(\n        SystemShadowStackInformation,\n        ShadowStackInformation,\n        sizeof(SYSTEM_SHADOW_STACK_INFORMATION),\n        NULL\n        );\n}\n\n/**\n* The system boot time in Coordinated Universal Time (UTC) format.\n*\n* \\param BootTime A pointer to a LARGE_INTEGER structure to receive the current system boot date and time.\n* \\return Successful or errant status.\n*/\nFORCEINLINE\nNTSTATUS\nPhGetSystemBootTime(\n    _Out_ PLARGE_INTEGER BootTime\n    )\n{\n    NTSTATUS status;\n    SYSTEM_TIMEOFDAY_INFORMATION timeOfDayInfo;\n\n    status = NtQuerySystemInformation(\n        SystemTimeOfDayInformation,\n        &timeOfDayInfo,\n        sizeof(SYSTEM_TIMEOFDAY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *BootTime = timeOfDayInfo.BootTime;\n    }\n\n    return status;\n}\n\n/**\n * The system uptime in Coordinated Universal Time (UTC) format.\n *\n * \\param Uptime A pointer to a LARGE_INTEGER structure to receive the current system uptime.\n * \\return Successful or errant status.\n */\nFORCEINLINE\nNTSTATUS\nPhGetSystemUptime(\n    _Out_ PLARGE_INTEGER Uptime\n    )\n{\n    NTSTATUS status;\n    SYSTEM_TIMEOFDAY_INFORMATION timeOfDayInfo;\n\n    status = NtQuerySystemInformation(\n        SystemTimeOfDayInformation,\n        &timeOfDayInfo,\n        sizeof(SYSTEM_TIMEOFDAY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        Uptime->QuadPart = timeOfDayInfo.CurrentTime.QuadPart - timeOfDayInfo.BootTime.QuadPart;\n    }\n\n    return status;\n}\n\n/**\n * Waits until the specified object is in the signaled state or the time-out interval elapses.\n *\n * \\param Handle A handle to the object.\n * \\param Timeout The time-out interval.\n * If a nonzero value is specified, the function waits until the object is signaled or the interval elapses.\n * If Timeout is zero, the function does not enter a wait state if the object is not signaled; it always returns immediately.\n * If Timeout is INFINITE, the function will return only when the object is signaled.\n * \\return Successful or errant status.\n */\nFORCEINLINE\nNTSTATUS\nPhWaitForSingleObject(\n    _In_ HANDLE Handle,\n    _In_opt_ ULONG Timeout\n    )\n{\n    if (Timeout)\n    {\n        LARGE_INTEGER timeout;\n\n        timeout.QuadPart = -(LONGLONG)UInt32x32To64(Timeout, PH_TIMEOUT_MS);\n\n        return NtWaitForSingleObject(Handle, FALSE, &timeout);\n    }\n    else\n    {\n        return NtWaitForSingleObject(Handle, FALSE, NULL);\n    }\n}\n\n/**\n * Provides a process-wide memory barrier that ensures that reads and writes from any CPU cannot move across the barrier.\n *\n * The process-wide memory barrier method differs from the \"normal\" MemoryBarrier method as follows:\n * The process-wide memory barrier ensures that any read or write from any CPU being used in the process can't move across the barrier.\n * The process-wide memory barrier forces other CPUs to synchronize with process memory (for example, to flush write buffers and synchronize read buffers).\n * The process-wide memory barrier is very expensive. It has to force every CPU in the process do to something, at a probable cost of thousands of cycles.\n * The process-wide memory barrier suffers from all the subtleties of lock-free programming.\n * \\sa https://learn.microsoft.com/en-us/dotnet/api/system.threading.interlocked.memorybarrierprocesswid\n * \\return Successful or errant status.\n */\nFORCEINLINE\nNTSTATUS\nPhMemoryBarrierProcessWide(\n    VOID\n    )\n{\n    return NtFlushProcessWriteBuffers();\n}\n\n#endif\n"
  },
  {
    "path": "phlib/include/phnet.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_PHNET_H\n#define _PH_PHNET_H\n\nEXTERN_C_START\n\n#ifndef __WINDOT11_H__\n#define __WINDOT11_H__ // Workaround windot11.h C2288 - WinSDK 10.0.22621 (dmex)\n#endif\n\n#ifndef PIO_APC_ROUTINE_DEFINED\n#define PIO_APC_ROUTINE_DEFINED 1\n#endif\n\n#ifndef ALIGN_SIZE\n#define ALIGN_SIZE 0x00000008\n#endif\n\n#ifndef UM_NDIS60\n#define UM_NDIS60 1\n#endif\n\n// #include <rtinfo.h>\n#include <winsock2.h>\n#include <ws2tcpip.h>\n#include <ws2def.h>\n#include <windns.h>\n#include <nldef.h>\n#include <netiodef.h>\n#include <iphlpapi.h>\n#include <mstcpip.h>\n#include <icmpapi.h>\n#include <hvsocket.h>\n\nEXTERN_C CONST DECLSPEC_SELECTANY IN_ADDR  inaddr_any             = { 0x00 };\nEXTERN_C CONST DECLSPEC_SELECTANY IN6_ADDR in6addr_any            = { 0x00 };\nEXTERN_C CONST DECLSPEC_SELECTANY IN6_ADDR in6addr_v4mappedprefix = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };\n\n#define PH_NETWORK_TYPE_NONE 0x0\n#define PH_NETWORK_TYPE_IPV4 0x1\n#define PH_NETWORK_TYPE_IPV6 0x2\n#define PH_NETWORK_TYPE_HYPERV 0x4\n#define PH_NETWORK_TYPE_MASK 0x8\n\n#define PH_PROTOCOL_TYPE_NONE 0x0\n#define PH_PROTOCOL_TYPE_TCP  0x10\n#define PH_PROTOCOL_TYPE_UDP  0x20\n#define PH_PROTOCOL_TYPE_MASK 0x30\n\n#define PH_NETWORK_PROTOCOL_NONE 0x0\n#define PH_NETWORK_PROTOCOL_TCP4 (PH_NETWORK_TYPE_IPV4 | PH_PROTOCOL_TYPE_TCP)\n#define PH_NETWORK_PROTOCOL_TCP6 (PH_NETWORK_TYPE_IPV6 | PH_PROTOCOL_TYPE_TCP)\n#define PH_NETWORK_PROTOCOL_UDP4 (PH_NETWORK_TYPE_IPV4 | PH_PROTOCOL_TYPE_UDP)\n#define PH_NETWORK_PROTOCOL_UDP6 (PH_NETWORK_TYPE_IPV6 | PH_PROTOCOL_TYPE_UDP)\n#define PH_NETWORK_PROTOCOL_HYPERV (PH_NETWORK_TYPE_HYPERV)\n\ntypedef struct _PH_IP_ADDRESS\n{\n    ULONG Type;\n    union\n    {\n        UCHAR Ipv4[4];\n        IN_ADDR InAddr;\n        UCHAR Ipv6[16];\n        IN6_ADDR In6Addr;\n        GUID HvAddr;\n    };\n} PH_IP_ADDRESS, *PPH_IP_ADDRESS;\n\ntypedef struct _PH_IP_ENDPOINT\n{\n    PH_IP_ADDRESS Address;\n    ULONG Port;\n} PH_IP_ENDPOINT, *PPH_IP_ENDPOINT;\n\nFORCEINLINE\nBOOLEAN\nPhEqualIpAddress(\n    _In_ PPH_IP_ADDRESS Address1,\n    _In_ PPH_IP_ADDRESS Address2\n    )\n{\n    if ((Address1->Type | Address2->Type) == 0) // don't check addresses if both are invalid\n        return TRUE;\n    if (Address1->Type != Address2->Type)\n        return FALSE;\n\n    switch (Address1->Type)\n    {\n    case PH_NETWORK_TYPE_IPV4:\n        {\n            return IN4_ADDR_EQUAL(&Address1->InAddr, &Address2->InAddr);\n        }\n        break;\n    case PH_NETWORK_TYPE_IPV6:\n        {\n            return IN6_ADDR_EQUAL(&Address1->In6Addr, &Address2->In6Addr);\n//#ifdef _WIN64\n//            return\n//                *(PULONG64)(Address1->Ipv6) == *(PULONG64)(Address2->Ipv6) &&\n//                *(PULONG64)(Address1->Ipv6 + 8) == *(PULONG64)(Address2->Ipv6 + 8);\n//#else\n//            return\n//                *(PULONG)(Address1->Ipv6) == *(PULONG)(Address2->Ipv6) &&\n//                *(PULONG)(Address1->Ipv6 + 4) == *(PULONG)(Address2->Ipv6 + 4) &&\n//                *(PULONG)(Address1->Ipv6 + 8) == *(PULONG)(Address2->Ipv6 + 8) &&\n//                *(PULONG)(Address1->Ipv6 + 12) == *(PULONG)(Address2->Ipv6 + 12);\n//#endif\n        }\n        break;\n    case PH_NETWORK_TYPE_HYPERV:\n        {\n            //return IsEqualGUID(&Address1->HvAddr, &Address2->HvAddr);\n            return !memcmp(&Address1->HvAddr, &Address2->HvAddr, sizeof(GUID));\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nFORCEINLINE\nULONG\nPhHashIpAddress(\n    _In_ PPH_IP_ADDRESS Address\n    )\n{\n    if (Address->Type == PH_NETWORK_TYPE_NONE)\n        return 0;\n\n    switch (Address->Type)\n    {\n    case PH_NETWORK_TYPE_IPV4:\n        {\n            ULONG hash;\n\n            hash = Address->Type | (Address->Type << 16);\n            hash ^= *(PULONG)(Address->Ipv4);\n\n            return hash;\n        }\n        break;\n    case PH_NETWORK_TYPE_IPV6:\n        {\n            ULONG hash;\n\n            hash = Address->Type | (Address->Type << 16);\n            hash += *(PULONG)(Address->Ipv6);\n            hash ^= *(PULONG)(Address->Ipv6 + 4);\n            hash += *(PULONG)(Address->Ipv6 + 8);\n            hash ^= *(PULONG)(Address->Ipv6 + 12);\n\n            return hash;\n        }\n        break;\n    case PH_NETWORK_TYPE_HYPERV:\n        {\n            ULONG hash;\n\n            hash = Address->Type | (Address->Type << 16);\n            hash += Address->HvAddr.Data1;\n            hash ^= *(PULONG)(&Address->HvAddr.Data2);\n            hash ^= *(PULONG)(Address->HvAddr.Data4);\n            hash ^= *(PULONG)(Address->HvAddr.Data4 + 4);\n\n            return hash;\n        }\n        break;\n    }\n\n    return 0;\n}\n\nFORCEINLINE\nBOOLEAN\nPhIsNullIpAddress(\n    _In_ PPH_IP_ADDRESS Address\n    )\n{\n    if (Address->Type == PH_NETWORK_TYPE_NONE)\n        return TRUE;\n\n    switch (Address->Type)\n    {\n    case PH_NETWORK_TYPE_IPV4:\n        {\n            return IN4_IS_ADDR_UNSPECIFIED(&Address->InAddr);\n        }\n        break;\n    case PH_NETWORK_TYPE_IPV6:\n        {\n            return IN6_IS_ADDR_UNSPECIFIED(&Address->In6Addr);\n//#ifdef _WIN64\n//            return (*(PULONG64)(Address->Ipv6) | *(PULONG64)(Address->Ipv6 + 8)) == 0;\n//#else\n//            return (*(PULONG)(Address->Ipv6) | *(PULONG)(Address->Ipv6 + 4) |\n//                *(PULONG)(Address->Ipv6 + 8) | *(PULONG)(Address->Ipv6 + 12)) == 0;\n//#endif\n        }\n        break;\n    case PH_NETWORK_TYPE_HYPERV:\n        {\n            //return IsEqualGUID(&Address->HvAddr, &HV_GUID_ZERO);\n            return !memcmp(&Address->HvAddr, &HV_GUID_ZERO, sizeof(GUID));\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\nFORCEINLINE\nBOOLEAN\nPhEqualIpEndpoint(\n    _In_ PPH_IP_ENDPOINT Endpoint1,\n    _In_ PPH_IP_ENDPOINT Endpoint2\n    )\n{\n    return PhEqualIpAddress(&Endpoint1->Address, &Endpoint2->Address) &&\n        Endpoint1->Port == Endpoint2->Port;\n}\n\nFORCEINLINE\nULONG\nPhHashIpEndpoint(\n    _In_ PPH_IP_ENDPOINT Endpoint\n    )\n{\n    return PhHashIpAddress(&Endpoint->Address) ^ Endpoint->Port;\n}\n\n// DOH/HTTP/HTTP2 support (dmex)\n\ntypedef enum _PHHTTP_EVENT_TYPE\n{\n    PHHTTP_EVENT_DEBUG,\n    PHHTTP_EVENT_INITIALIZING,\n    PHHTTP_EVENT_RESOLVING_NAME,\n    PHHTTP_EVENT_NAME_RESOLVED,\n    PHHTTP_EVENT_CONNECTING,\n    PHHTTP_EVENT_CONNECTED,\n    PHHTTP_EVENT_SENDING_REQUEST,\n    PHHTTP_EVENT_REQUEST_SENT,\n    PHHTTP_EVENT_RECEIVING_RESPONSE,\n    PHHTTP_EVENT_RESPONSE_RECEIVED,\n    PHHTTP_EVENT_CLOSING_CONNECTION,\n    PHHTTP_EVENT_CONNECTION_CLOSED,\n    PHHTTP_EVENT_HANDLE_CREATED,\n    PHHTTP_EVENT_HANDLE_CLOSING,\n    PHHTTP_EVENT_DETECTING_PROXY,\n    PHHTTP_EVENT_REDIRECT\n} PHHTTP_EVENT_TYPE;\n\ntypedef _Function_class_(PH_HTTP_EVENT_CALLBACK)\nVOID NTAPI PH_HTTP_EVENT_CALLBACK(\n    _In_ PHHTTP_EVENT_TYPE Event,\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_HTTP_EVENT_CALLBACK* PPH_HTTP_EVENT_CALLBACK;\n\ntypedef struct _PH_HTTP_CONTEXT\n{\n    PVOID SessionHandle;\n    PVOID ConnectionHandle;\n    PVOID RequestHandle;\n    BOOL EventCallbackRegistered;\n    PPH_HTTP_EVENT_CALLBACK Callback;\n    PVOID Context;\n} PH_HTTP_CONTEXT, *PPH_HTTP_CONTEXT;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpInitialize(\n    _Out_ PPH_HTTP_CONTEXT *HttpContext\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhHttpDestroy(\n    _In_ _Maybenull_ _Frees_ptr_ PPH_HTTP_CONTEXT HttpContext\n    );\n\ntypedef enum _PH_HTTP_SOCKET_CLOSE_TYPE\n{\n    PH_HTTP_SOCKET_CLOSE_SESSION = 0x1,\n    PH_HTTP_SOCKET_CLOSE_CONNECTION = 0x2,\n    PH_HTTP_SOCKET_CLOSE_REQUEST = 0x4,\n} PH_HTTP_SOCKET_CLOSE_TYPE;\n\nPHLIBAPI\nVOID\nNTAPI\nPhHttpClose(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PH_HTTP_SOCKET_CLOSE_TYPE Type\n    );\n\n#define PH_HTTP_DEFAULT_PORT 0 // use the protocol-specific default port\n#define PH_HTTP_DEFAULT_HTTP_PORT 80\n#define PH_HTTP_DEFAULT_HTTPS_PORT 443\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpConnect(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PCWSTR ServerName,\n    _In_ USHORT ServerPort\n    );\n\n#define PH_HTTP_FLAG_SECURE 0x1\n#define PH_HTTP_FLAG_REFRESH 0x2\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpBeginRequest(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_opt_ PCWSTR RequestMethod,\n    _In_ PCWSTR RequestPath,\n    _In_ ULONG Flags\n    );\n\n#define PH_HTTP_IGNORE_REQUEST_TOTAL_LENGTH 0\n#define PH_HTTP_NO_ADDITIONAL_HEADERS NULL\n#define PH_HTTP_NO_REQUEST_DATA NULL\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSendRequest(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_opt_ PCWSTR HeadersBuffer,\n    _In_ ULONG HeadersLength,\n    _In_opt_ PVOID OptionalBuffer,\n    _In_ ULONG OptionalLength,\n    _In_ ULONG TotalLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpReceiveResponse(\n    _In_ PPH_HTTP_CONTEXT HttpContext\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpReadData(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG BytesCopied\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpWriteData(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG BytesCopied\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpAddRequestHeaders(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PCWSTR Headers,\n    _In_opt_ ULONG HeadersLength\n    );\n\nFORCEINLINE\nNTSTATUS\nPhHttpAddRequestHeadersSR(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PCPH_STRINGREF Headers\n    )\n{\n    return PhHttpAddRequestHeaders(\n        HttpContext,\n        Headers->Buffer,\n        (ULONG)Headers->Length / sizeof(WCHAR)\n        );\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhHttpQueryHeaders(\n    _In_ PPH_HTTP_CONTEXT HttpContext\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhHttpQueryHeaderString(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PCWSTR HeaderString\n    );\n\n// status codes\n#define PH_HTTP_STATUS_OK 200 // request completed\n#define PH_HTTP_STATUS_CREATED 201\n#define PH_HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method\n#define PH_HTTP_STATUS_REDIRECT 302 // object temporarily moved\n\n// header query flags\n#define PH_HTTP_QUERY_CONTENT_LENGTH 0x1\n#define PH_HTTP_QUERY_STATUS_CODE 0x2\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpQueryHeaderUlong(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG QueryValue,\n    _Out_ PULONG HeaderValue\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpQueryHeaderUlong64(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG QueryValue,\n    _Out_ PULONG64 HeaderValue\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhHttpQueryResponseStatus(\n    _In_ PPH_HTTP_CONTEXT HttpContext\n    )\n{\n    NTSTATUS status;\n    ULONG httpStatus = PH_HTTP_STATUS_OK;\n\n    status = PhHttpQueryHeaderUlong(HttpContext, PH_HTTP_QUERY_STATUS_CODE, &httpStatus);\n\n    if (NT_SUCCESS(status))\n    {\n        switch (httpStatus)\n        {\n        case 301:\n        case 308:\n            //status = STATUS_MORE_ENTRIES;\n        case PH_HTTP_STATUS_OK:\n            status = STATUS_SUCCESS;\n            break;\n        case 401:\n        case 403:\n            status = STATUS_ACCESS_DENIED;\n            break;\n        case 404:\n            status = STATUS_OBJECT_NAME_NOT_FOUND;\n            break;\n        default:\n            status = STATUS_UNEXPECTED_NETWORK_ERROR;\n            break;\n        }\n    }\n\n    return status;\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhHttpQueryOptionString(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ BOOLEAN SessionOption,\n    _In_ ULONG QueryOption\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpReadDataToBuffer(\n    _In_ PVOID RequestHandle,\n    _Out_ PVOID* Buffer,\n    _Out_ ULONG* BufferLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpDownloadString(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ BOOLEAN Unicode,\n    _Out_ PVOID* StringBuffer\n    );\n\ntypedef struct _PH_HTTPDOWNLOAD_CONTEXT\n{\n    ULONG64 ReadLength;\n    ULONG64 TotalLength;\n    ULONG64 BitsPerSecond;\n    DOUBLE Percent;\n} PH_HTTPDOWNLOAD_CONTEXT, *PPH_HTTPDOWNLOAD_CONTEXT;\n\ntypedef BOOLEAN (NTAPI *PPH_HTTPDOWNLOAD_CALLBACK)(\n    _In_opt_ PPH_HTTPDOWNLOAD_CONTEXT Parameter,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpDownloadToFile(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PPH_STRINGREF FileName,\n    _In_ PPH_HTTPDOWNLOAD_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_HTTP_FEATURE_REDIRECTS 0x1\n#define PH_HTTP_FEATURE_KEEP_ALIVE 0x2\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSetFeature(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG Feature,\n    _In_ BOOLEAN Enable\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSetOption(\n    _In_ PVOID HttpHandle,\n    _In_ ULONG Option,\n    _In_ ULONG Value\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSetOptionString(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG Option,\n    _In_ PPH_STRINGREF Value\n    );\n\ntypedef _Function_class_(PH_HTTP_STATUS_CALLBACK)\nVOID CALLBACK PH_HTTP_STATUS_CALLBACK(\n    _In_ PVOID InternetHandle,\n    _In_ ULONG_PTR Context,\n    _In_ ULONG InternetStatus,\n    _In_opt_ LPVOID StatusInformation,\n    _In_ ULONG StatusInformationLength\n    );\ntypedef PH_HTTP_STATUS_CALLBACK* PPH_HTTP_STATUS_CALLBACK;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSetCallback(\n    _In_ PVOID HttpHandle,\n    _In_ PPH_HTTP_STATUS_CALLBACK Callback,\n    _In_ ULONG NotificationFlags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSetContext(\n    _In_ PVOID HttpHandle,\n    _In_ PVOID Context\n    );\n\nFORCEINLINE\nNTSTATUS\nPhWinHttpSetOptionStringZ(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG Option,\n    _In_ PCWSTR Value\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, Value);\n\n    return PhHttpSetOptionString(HttpContext, Option, &string);\n}\n\n#define PH_HTTP_SECURITY_IGNORE_UNKNOWN_CA 0x1\n#define PH_HTTP_SECURITY_IGNORE_CERT_DATE_INVALID 0x2\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSetSecurity(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ ULONG Feature\n    );\n\n#define PH_HTTP_PROTOCOL_FLAG_HTTP2 0x1\n#define PH_HTTP_PROTOCOL_FLAG_HTTP3 0x2\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSetProtocol(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ BOOLEAN Session,\n    _In_ ULONG Protocol,\n    _In_ ULONG Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpCrackUrl(\n    _In_ PPH_STRING Url,\n    _Out_ PPH_STRING *Host,\n    _Out_ PPH_STRING *Path,\n    _Out_ PUSHORT Port\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhHttpGetErrorMessage(\n    _In_ ULONG ErrorCode\n    );\n\ntypedef struct _PH_HTTP_CERTIFICATE_INFO\n{\n    LARGE_INTEGER Expiry;\n    LARGE_INTEGER Start;\n    PWSTR SubjectInfo;\n    PWSTR IssuerInfo;\n    PWSTR ProtocolName;\n    PWSTR SignatureAlgName;\n    PWSTR EncryptionAlgName;\n    ULONG KeySize;\n} PH_HTTP_CERTIFICATE_INFO, *PPH_HTTP_CERTIFICATE_INFO;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpGetCertificateInfo(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _Out_ PPH_HTTP_CERTIFICATE_INFO Certificate\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpGetStatistics(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSetCredentials(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Value\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpSetEventCallback(\n    _In_ PPH_HTTP_CONTEXT HttpContext,\n    _In_ PPH_HTTP_EVENT_CALLBACK EventCallback,\n    _In_opt_ PVOID Context\n    );\n\n//\n// IPv4 and IPv6\n//\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhIpv4AddressToString(\n    _In_ PCIN_ADDR Address,\n    _In_ USHORT Port,\n    _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString,\n    _Inout_ PULONG AddressStringLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhIpv4StringToAddress(\n    _In_ PCWSTR AddressString,\n    _In_ BOOLEAN Strict,\n    _Out_ PIN_ADDR Address,\n    _Out_ PUSHORT Port\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhIpv6AddressToString(\n    _In_ PCIN6_ADDR Address,\n    _In_ ULONG ScopeId,\n    _In_ USHORT Port,\n    _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString,\n    _Inout_ PULONG AddressStringLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhIpv6StringToAddress(\n    _In_ PCWSTR AddressString,\n    _Out_ PIN6_ADDR Address,\n    _Out_ PULONG ScopeId,\n    _Out_ PUSHORT Port\n    );\n\n//\n// DNS\n//\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhDnsReverseLookupNameFromAddress(\n    _In_ ULONG Type,\n    _In_ PVOID Address\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhHttpDnsQuery(\n    _In_opt_ PCWSTR DnsServerAddress,\n    _In_ PCWSTR DnsQueryMessage,\n    _In_ USHORT DnsQueryMessageType,\n    _Out_ PDNS_RECORD* DnsQueryRecord\n    );\n\nPHLIBAPI\nPDNS_RECORD\nNTAPI\nPhDnsQuery(\n    _In_opt_ PCWSTR DnsServerAddress,\n    _In_ PCWSTR DnsQueryMessage,\n    _In_ USHORT DnsQueryMessageType\n    );\n\nPHLIBAPI\nPDNS_RECORD\nNTAPI\nPhDnsQuery2(\n    _In_opt_ PCWSTR DnsServerAddress,\n    _In_ PCWSTR DnsQueryMessage,\n    _In_ USHORT DnsQueryMessageType,\n    _In_ USHORT DnsQueryMessageOptions\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDnsFree(\n    _In_ PDNS_RECORD DnsRecordList\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/phsup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_PHSUP_H\n#define _PH_PHSUP_H\n\n// This header file provides some useful definitions specific to phlib.\n\n//\n// Workaround for macro redefinition conflicts between Clang and MSVC.\n// Save and restore these definitions.\n//\n// See: https://github.com/llvm/llvm-project/issues/36748\n//\n// C:\\Program Files\\LLVM\\lib\\clang\\20\\include\\xmmintrin.h(2195,9): error: '_MM_HINT_T0' macro redefined [-Werror,-Wmacro-redefined]\n//  2195 | #define _MM_HINT_T0  3\n//       |         ^\n// C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.26100.0\\\\um\\winnt.h(3649,9): note: previous definition is here\n//  3649 | #define _MM_HINT_T0     1\n//       |\n//\n// Workaround for unused function warnings.\n// Narrowly suppress -Wunused-function warnings.\n//\n// C:\\Program Files\\LLVM\\lib\\clang\\20\\include\\amxcomplexintrin.h(139,13): error: unused function '__tile_cmmimfp16ps' [-Werror,-Wunused-function]\n//   139 | static void __tile_cmmimfp16ps(__tile1024i *dst, __tile1024i src0,\n//       |             ^~~~~~~~~~~~~~~~~~\n// C:\\Program Files\\LLVM\\lib\\clang\\20\\include\\amxcomplexintrin.h(162,13): error: unused function '__tile_cmmrlfp16ps' [-Werror,-Wunused-function]\n//   162 | static void __tile_cmmrlfp16ps(__tile1024i *dst, __tile1024i src0,\n//       |             ^~~~~~~~~~~~~~~~~~\n//\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#ifdef _MM_HINT_T0\n#pragma push_macro(\"_MM_HINT_T0\")\n#pragma push_macro(\"_MM_HINT_T1\")\n#pragma push_macro(\"_MM_HINT_T2\")\n#undef _MM_HINT_T0\n#undef _MM_HINT_T1\n#undef _MM_HINT_T2\n#define PH_SAVED_MM_HINT_MACROS\n#endif // _MM_HINT_T0\n#endif // __clang__\n#include <intrin.h>\n#ifdef __clang__\n#pragma clang diagnostic pop\n#ifdef PH_SAVED_MM_HINT_MACROS\n#pragma pop_macro(\"_MM_HINT_T2\")\n#pragma pop_macro(\"_MM_HINT_T1\")\n#pragma pop_macro(\"_MM_HINT_T0\")\n#undef PH_SAVED_MM_HINT_MACROS\n#endif // PH_SAVED_MM_HINT_MACROS\n#endif // __clang__\n\n#include <wchar.h>\n#include <assert.h>\n#include <stdalign.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <limits.h>\n#include <locale.h>\n#include <inttypes.h>\n#include <math.h>\n#include <malloc.h>\n#include <float.h>\n\n//\n// Memory\n//\n\n#if defined(_cplusplus)\ntemplate <class T>\nFORCEINLINE T* PTR_ADD_OFFSET(\n    _In_ const T* Pointer,\n    _In_ const T* Offset\n    )\n{\n    return reinterpret_cast<T*>(\n        static_cast<const unsigned char*>(Pointer) +\n        static_cast<const unsigned long long>(Offset)\n        );\n}\n\ntemplate <class T>\nFORCEINLINE T* PTR_SUB_OFFSET(\n    _In_ const T* Pointer,\n    _In_ const T* Offset\n    )\n{\n    return reinterpret_cast<T*>(\n        static_cast<const unsigned char*>(Pointer) -\n        static_cast<const unsigned long long>(Pointer)\n        );\n}\n#else\n#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset)))\n#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset)))\n#endif\n\n#define PH_LARGE_BUFFER_SIZE (256 * 1024 * 1024)\n\n#define XMM_SIZE sizeof(__m128i)\n#define XMM_OFFSET(p) ((XMM_SIZE - 1) & (ULONG_PTR)(p))\n#define XMM_CHARS (XMM_SIZE / sizeof(wchar_t))\n#define XMM_CHAR_ALIGNED(p) (0 == (((ULONG_PTR)(p) + sizeof(wchar_t) - 1) & (0-sizeof(wchar_t)) & (XMM_SIZE-1)))\n#define XMM_PAGE_SAFE(p) (PAGE_OFFSET(p) <= (PAGE_SIZE - XMM_SIZE))\n\n//\n// Exceptions\n//\n\n#define PhRaiseStatus(Status) RtlRaiseStatus(Status)\n\n#define SIMPLE_EXCEPTION_FILTER(Condition) \\\n    ((Condition) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)\n\n//\n// Compiler\n//\n\n#ifdef DEBUG\n#define ASSUME_ASSERT(Expression) assert(Expression)\n#define ASSUME_NO_DEFAULT assert(FALSE)\n#else\n#define ASSUME_ASSERT(Expression) __assume(Expression)\n#define ASSUME_NO_DEFAULT __assume(FALSE)\n#endif\n\n//\n// Math\n//\n\n#if defined(_M_IX86)\n#define UInt32Add32To64(a, b) ((unsigned __int64)(((unsigned __int64)((unsigned int)(a))) + ((unsigned int)(b)))) // Avoids warning C26451 (dmex)\n#define UInt32Sub32To64(a, b) ((unsigned __int64)(((unsigned __int64)((unsigned int)(a))) - ((unsigned int)(b))))\n#define UInt32Div32To64(a, b) ((unsigned __int64)(((unsigned __int64)((unsigned int)(a))) / ((unsigned int)(b))))\n#define UInt32Mul32To64(a, b) ((unsigned __int64)(((unsigned __int64)((unsigned int)(a))) * ((unsigned int)(b))))\n#else\n#define UInt32Add32To64(a, b) (((unsigned __int64)((unsigned int)(a))) + ((unsigned __int64)((unsigned int)(b)))) // from UInt32x32To64 (dmex)\n#define UInt32Sub32To64(a, b) (((unsigned __int64)((unsigned int)(a))) - ((unsigned __int64)((unsigned int)(b))))\n#define UInt32Div32To64(a, b) (((unsigned __int64)((unsigned int)(a))) / ((unsigned __int64)((unsigned int)(b))))\n#define UInt32Mul32To64(a, b) (((unsigned __int64)((unsigned int)(a))) * ((unsigned __int64)((unsigned int)(b))))\n#endif\n\n//\n// Time\n//\n\n#define PH_TICKS_PER_NS ((LONG64)1 * 10)\n#define PH_TICKS_PER_MS (PH_TICKS_PER_NS * 1000)\n#define PH_TICKS_PER_SEC (PH_TICKS_PER_MS * 1000)\n#define PH_TICKS_PER_MIN (PH_TICKS_PER_SEC * 60)\n#define PH_TICKS_PER_HOUR (PH_TICKS_PER_MIN * 60)\n#define PH_TICKS_PER_DAY (PH_TICKS_PER_HOUR * 24)\n\n#define PH_TICKS_PARTIAL_NS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_NS) % 1000000)\n#define PH_TICKS_PARTIAL_MS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MS) % 1000)\n#define PH_TICKS_PARTIAL_SEC(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_SEC) % 60)\n#define PH_TICKS_PARTIAL_MIN(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MIN) % 60)\n#define PH_TICKS_PARTIAL_HOURS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_HOUR) % 24)\n#define PH_TICKS_PARTIAL_DAYS(Ticks) ((ULONG64)(Ticks) / PH_TICKS_PER_DAY)\n\n#define PH_TIMEOUT_MS PH_TICKS_PER_MS\n#define PH_TIMEOUT_SEC PH_TICKS_PER_SEC\n\n//\n// Annotations\n//\n\n/**\n * Indicates that a function assumes the specified number of references are available for the\n * object.\n *\n * \\remarks Usually functions reference objects if they store them for later usage; this annotation\n * specifies that the caller must supply these extra references itself. In effect these references\n * are \"transferred\" to the function and must not be used. E.g. if you create an object and\n * immediately call a function with _Assume_refs_(1), you may no longer use the object since that\n * one reference you held is no longer yours.\n */\n#define _Assume_refs_(count)\n\n#define _Callback_\n\n/**\n * Indicates that a function may raise a software exception.\n *\n * \\remarks Do not use this annotation for temporary usages of exceptions, e.g. unimplemented\n * functions.\n */\n#define _May_raise_\n\n//\n// Casts\n//\n\n// Zero extension and sign extension macros\n#define C_1uTo2(x) ((unsigned short)(unsigned char)(x))\n#define C_1sTo2(x) ((unsigned short)(signed char)(x))\n#define C_1uTo4(x) ((unsigned int)(unsigned char)(x))\n#define C_1sTo4(x) ((unsigned int)(signed char)(x))\n#define C_2uTo4(x) ((unsigned int)(unsigned short)(x))\n#define C_2sTo4(x) ((unsigned int)(signed short)(x))\n#define C_4uTo8(x) ((unsigned __int64)(unsigned int)(x))\n#define C_4sTo8(x) ((unsigned __int64)(signed int)(x))\n\n//\n// Sorting\n//\n\ntypedef enum _PH_SORT_ORDER\n{\n    NoSortOrder = 0,\n    AscendingSortOrder,\n    DescendingSortOrder\n} PH_SORT_ORDER, *PPH_SORT_ORDER;\n\nFORCEINLINE LONG PhModifySort(\n    _In_ LONG Result,\n    _In_ PH_SORT_ORDER Order\n    )\n{\n    switch (Order)\n    {\n    case AscendingSortOrder:\n        return Result;\n    case DescendingSortOrder:\n        return -Result;\n    default:\n        return Result;\n    }\n}\n\n#define PH_BUILTIN_COMPARE(value1, value2) \\\n    if ((value1) > (value2)) \\\n        return 1; \\\n    else if ((value1) < (value2)) \\\n        return -1; \\\n    \\\n    return 0\n\nFORCEINLINE int charcmp(\n    _In_ signed char value1,\n    _In_ signed char value2\n    )\n{\n    return C_1sTo4(value1 - value2);\n}\n\nFORCEINLINE int ucharcmp(\n    _In_ unsigned char value1,\n    _In_ unsigned char value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int shortcmp(\n    _In_ signed short value1,\n    _In_ signed short value2\n    )\n{\n    return C_2sTo4(value1 - value2);\n}\n\nFORCEINLINE int ushortcmp(\n    _In_ unsigned short value1,\n    _In_ unsigned short value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int intcmp(\n    _In_ int value1,\n    _In_ int value2\n    )\n{\n    return value1 - value2;\n}\n\nFORCEINLINE int uintcmp(\n    _In_ unsigned int value1,\n    _In_ unsigned int value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int int64cmp(\n    _In_ __int64 value1,\n    _In_ __int64 value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int uint64cmp(\n    _In_ unsigned __int64 value1,\n    _In_ unsigned __int64 value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int intptrcmp(\n    _In_ LONG_PTR value1,\n    _In_ LONG_PTR value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int uintptrcmp(\n    _In_ ULONG_PTR value1,\n    _In_ ULONG_PTR value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int singlecmp(\n    _In_ float value1,\n    _In_ float value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int doublecmp(\n    _In_ double value1,\n    _In_ double value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int wcsicmp2(\n    _In_opt_ PCWSTR Value1,\n    _In_opt_ PCWSTR Value2\n    )\n{\n    if (Value1 && Value2)\n        return _wcsicmp(Value1, Value2);\n    else if (!Value1)\n        return !Value2 ? 0 : -1;\n    else\n        return 1;\n}\n\ntypedef int (__cdecl *PC_COMPARE_FUNCTION)(void *, const void *, const void *);\n\n//\n// Synchronization\n//\n\nFORCEINLINE LONG_PTR __InterlockedExchangeAddPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend,\n    _In_ LONG_PTR Value\n    )\n{\n#ifdef _WIN64\n    return (LONG_PTR)_InterlockedExchangeAdd64((volatile LONG64*)Addend, (LONG64)Value);\n#else\n    return (LONG_PTR)_InterlockedExchangeAdd((volatile LONG*)Addend, (LONG)Value);\n#endif\n}\n\n#define _InterlockedExchangeAddPointer __InterlockedExchangeAddPointer\n\nFORCEINLINE LONG_PTR _InterlockedIncrementPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend\n    )\n{\n#ifdef _WIN64\n    return (LONG_PTR)_InterlockedIncrement64((volatile LONG64*)Addend);\n#else\n    return (LONG_PTR)_InterlockedIncrement((volatile LONG*)Addend);\n#endif\n}\n\nFORCEINLINE LONG_PTR __InterlockedDecrementPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend\n    )\n{\n#ifdef _WIN64\n    return (LONG_PTR)_InterlockedDecrement64((volatile LONG64*)Addend);\n#else\n    return (LONG_PTR)_InterlockedDecrement((volatile LONG*)Addend);\n#endif\n}\n\n#define _InterlockedDecrementPointer __InterlockedDecrementPointer\n\nFORCEINLINE BOOLEAN _InterlockedBitTestAndResetPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Base,\n    _In_ LONG_PTR Bit\n    )\n{\n#ifdef _WIN64\n    return _interlockedbittestandreset64((volatile LONG64*)Base, (LONG64)Bit);\n#else\n    return _interlockedbittestandreset((volatile LONG*)Base, (LONG)Bit);\n#endif\n}\n\nFORCEINLINE BOOLEAN _InterlockedBitTestAndSetPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Base,\n    _In_ LONG_PTR Bit\n    )\n{\n#ifdef _WIN64\n    return _interlockedbittestandset64((volatile LONG64*)Base, (LONG64)Bit);\n#else\n    return _interlockedbittestandset((volatile LONG*)Base, (LONG)Bit);\n#endif\n}\n\nFORCEINLINE BOOLEAN _InterlockedIncrementNoZero(\n    _Inout_ _Interlocked_operand_ LONG volatile *Addend\n    )\n{\n    LONG value;\n    LONG newValue;\n\n    value = *Addend;\n\n    while (TRUE)\n    {\n        if (value == 0)\n            return FALSE;\n\n        if ((newValue = _InterlockedCompareExchange(\n            Addend,\n            value + 1,\n            value\n            )) == value)\n        {\n            return TRUE;\n        }\n\n        value = newValue;\n    }\n}\n\nFORCEINLINE BOOLEAN _InterlockedIncrementPositive(\n    _Inout_ _Interlocked_operand_ LONG volatile *Addend\n    )\n{\n    LONG value;\n    LONG newValue;\n\n    value = *Addend;\n\n    while (TRUE)\n    {\n        if (value <= 0)\n            return FALSE;\n\n        if ((newValue = _InterlockedCompareExchange(\n            Addend,\n            value + 1,\n            value\n            )) == value)\n        {\n            return TRUE;\n        }\n\n        value = newValue;\n    }\n}\n\nFORCEINLINE\nPVOID\n_InterlockedReadPointer(\n    _Inout_ _Interlocked_operand_ volatile PVOID *Base\n    )\n{\n    return _InterlockedCompareExchangePointer(Base, NULL, NULL);\n}\n\nFORCEINLINE\nPVOID\n_InterlockedWritePointer(\n    _Inout_ _Interlocked_operand_ volatile PVOID* Base,\n    _In_ PVOID Value\n    )\n{\n    return _InterlockedExchangePointer(Base, Value);\n}\n\n#ifndef InterlockedReadPointer\n#define InterlockedReadPointer _InterlockedReadPointer\n#endif\n#ifndef InterlockedWritePointer\n#define InterlockedWritePointer _InterlockedWritePointer\n#endif\n\n//\n// Strings\n//\n\n#define PH_INT32_STR_LEN 12\n#define PH_INT32_STR_LEN_1 (PH_INT32_STR_LEN + 1)\n\n#define PH_INT64_STR_LEN 50\n#define PH_INT64_STR_LEN_1 (PH_INT64_STR_LEN + 1)\n\n#define PH_PTR_STR_LEN 24\n#define PH_PTR_STR_LEN_1 (PH_PTR_STR_LEN + 1)\n\n#define PH_HEX_CHARS L\"0123456789abcdef\"\n\n#pragma warning(push)\n#pragma warning(disable:4996)\n\nFORCEINLINE\nVOID\nPhPrintInt32(\n    _Out_writes_(PH_INT32_STR_LEN_1) CONST PWSTR Destination,\n    _In_ CONST LONG Int32\n    )\n{\n    _ltow(Int32, Destination, 10);\n}\n\nFORCEINLINE\nVOID\nPhPrintUInt32(\n    _Out_writes_(PH_INT32_STR_LEN_1) CONST PWSTR Destination,\n    _In_ CONST ULONG UInt32\n    )\n{\n    _ultow(UInt32, Destination, 10);\n}\n\nFORCEINLINE\nVOID\nPhPrintUInt32IX(\n    _Out_writes_(PH_PTR_STR_LEN_1) CONST PWSTR Destination,\n    _In_ CONST ULONG UInt32\n    )\n{\n    _ultow(UInt32, Destination, 16);\n}\n\nFORCEINLINE\nVOID\nPhPrintInt64(\n    _Out_writes_(PH_INT64_STR_LEN_1) CONST PWSTR Destination,\n    _In_ CONST LONG64 Int64\n    )\n{\n    _i64tow(Int64, Destination, 10);\n}\n\nFORCEINLINE\nVOID\nPhPrintUInt64(\n    _Out_writes_(PH_INT64_STR_LEN_1) CONST PWSTR Destination,\n    _In_ CONST ULONG64 UInt64\n    )\n{\n    _ui64tow(UInt64, Destination, 10);\n}\n\nFORCEINLINE\nVOID\nPhPrintPointer(\n    _Out_writes_(PH_PTR_STR_LEN_1) PWSTR Destination,\n    _In_opt_ PVOID Pointer\n    )\n{\n    Destination[0] = L'0';\n    Destination[1] = L'x';\n#ifdef _WIN64\n    _ui64tow((ULONG64)Pointer, &Destination[2], 16);\n#else\n    _ultow((ULONG)Pointer, &Destination[2], 16);\n#endif\n}\n\n#pragma warning(pop)\n\nFORCEINLINE\nVOID\nPhPrintPointerPadZeros(\n    _Out_writes_(PH_PTR_STR_LEN_1) PWSTR Destination,\n    _In_ PVOID Pointer\n    )\n{\n    ULONG_PTR ptr = (ULONG_PTR)Pointer;\n    PWSTR dest = Destination;\n\n    *dest++ = L'0';\n    *dest++ = L'x';\n\n#ifdef _WIN64\n    *dest++ = PH_HEX_CHARS[ptr >> 60];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x0f00000000000000) >> 56];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x00f0000000000000) >> 52];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x000f000000000000) >> 48];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x0000f00000000000) >> 44];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x00000f0000000000) >> 40];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x000000f000000000) >> 36];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x0000000f00000000) >> 32];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x00000000f0000000) >> 28];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x000000000f000000) >> 24];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x0000000000f00000) >> 20];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x00000000000f0000) >> 16];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x000000000000f000) >> 12];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x0000000000000f00) >> 8];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x00000000000000f0) >> 4];\n    *dest++ = PH_HEX_CHARS[ptr & 0x000000000000000f];\n#else\n    *dest++ = PH_HEX_CHARS[ptr >> 28];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x0f000000) >> 24];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x00f00000) >> 20];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x000f0000) >> 16];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x0000f000) >> 12];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x00000f00) >> 8];\n    *dest++ = PH_HEX_CHARS[(ptr & 0x000000f0) >> 4];\n    *dest++ = PH_HEX_CHARS[ptr & 0x0000000f];\n#endif\n\n    *dest = UNICODE_NULL;\n}\n\n//\n// Misc.\n//\n\n/**\n * Rounds the given value to the nearest multiple of the specified granularity.\n *\n * \\param Value The value to round.\n * \\param Granularity The granularity to which the value should be rounded.\n * \\return The value rounded to the nearest multiple of granularity.\n */\nFORCEINLINE\nULONG64\nPhRoundNumber(\n    _In_ CONST ULONG64 Value,\n    _In_ CONST ULONG64 Granularity\n    )\n{\n    return (Value + Granularity / 2) / Granularity * Granularity;\n}\n\n/**\n * Multiplies a number by a numerator and divides by a denominator, with rounding.\n *\n * This function performs the operation: ((Number * Numerator) + (Denominator / 2)) / Denominator\n * using 32-bit unsigned integers, avoiding overflow and providing rounding.\n *\n * \\param Number The base number to multiply.\n * \\param Numerator The numerator for multiplication.\n * \\param Denominator The denominator for division.\n * \\return The result of the multiply-divide operation, rounded to the nearest integer.\n */\nFORCEINLINE\nULONG\nPhMultiplyDivide(\n    _In_ CONST ULONG Number,\n    _In_ CONST ULONG Numerator,\n    _In_ CONST ULONG Denominator\n    )\n{\n    //return (((ULONG64)Number * (ULONG64)Numerator + (ULONG64)Denominator / 2) / (ULONG64)Denominator);\n    return UInt32Div32To64(UInt32Add32To64(UInt32Mul32To64(Number, Numerator), UInt32Div32To64(Denominator, 2)), Denominator);\n}\n\n/**\n * Multiplies a signed number by a numerator and divides by a denominator, with rounding.\n *\n * This function performs the operation: ((Number * Numerator) + (Denominator / 2)) / Denominator\n * for signed numbers, preserving the sign and providing rounding.\n *\n * \\param Number The signed base number to multiply.\n * \\param Numerator The numerator for multiplication.\n * \\param Denominator The denominator for division.\n * \\return The result of the signed multiply-divide operation, rounded to the nearest integer.\n */\nFORCEINLINE\nLONG\nPhMultiplyDivideSigned(\n    _In_ CONST LONG Number,\n    _In_ CONST ULONG Numerator,\n    _In_ CONST ULONG Denominator\n    )\n{\n    if (Number >= 0)\n        return (LONG)PhMultiplyDivide(Number, Numerator, Denominator);\n    else\n        return -(LONG)PhMultiplyDivide(-Number, Numerator, Denominator);\n}\n\n/**\n * Probes a user-supplied address for validity and alignment within a specified buffer.\n *\n * This function checks that the given `UserAddress` is properly aligned to the specified `Alignment`,\n * and that the memory region defined by `UserAddress` and `UserLength` is fully contained within\n * the buffer defined by `BufferAddress` and `BufferLength`. If any of these checks fail, a software\n * exception is raised.\n *\n * \\param UserAddress    The starting address of the user-supplied memory region to probe.\n * \\param UserLength     The length, in bytes, of the memory region to probe.\n * \\param BufferAddress  The base address of the buffer within which the user region must reside.\n * \\param BufferLength   The length, in bytes, of the buffer.\n * \\param Alignment      The required alignment, in bytes, for the user address.\n * \\remarks\n * This function does not actually access the memory at `UserAddress`; it only performs pointer arithmetic\n * and alignment checks. Use this function before reading from or writing to user-supplied memory to ensure\n * safety and prevent access violations.\n */\nFORCEINLINE\nVOID\nPhProbeAddress(\n    _In_ CONST PVOID UserAddress,\n    _In_ CONST SIZE_T UserLength,\n    _In_ CONST PVOID BufferAddress,\n    _In_ CONST SIZE_T BufferLength,\n    _In_ CONST ULONG Alignment\n    )\n{\n    if (UserLength != 0)\n    {\n        if (!IS_ALIGNED(UserAddress, Alignment))\n        {\n            PhRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);\n        }\n\n        if (\n            ((ULONG_PTR)UserAddress + UserLength < (ULONG_PTR)UserAddress) ||\n            ((ULONG_PTR)UserAddress < (ULONG_PTR)BufferAddress) ||\n            ((ULONG_PTR)UserAddress + UserLength > (ULONG_PTR)BufferAddress + BufferLength)\n            )\n        {\n            PhRaiseStatus(STATUS_ACCESS_VIOLATION);\n        }\n    }\n}\n\n/**\n * Probes a user address for read access and checks if the specified user address is readable\n * and within the bounds of the buffer.\n *\n * \\param UserAddress The address to probe.\n * \\param UserLength The length of the memory to probe.\n * \\param BufferAddress The base address of the buffer.\n * \\param BufferLength The length of the buffer.\n * \\param Alignment The required alignment of the address.\n */\nFORCEINLINE\nVOID\nPhProbeForRead(\n    _In_ CONST PVOID UserAddress,\n    _In_ CONST SIZE_T UserLength,\n    _In_ CONST PVOID BufferAddress,\n    _In_ CONST SIZE_T BufferLength,\n    _In_ CONST ULONG Alignment\n    )\n{\n    if (UserLength != 0)\n    {\n        PhProbeAddress(UserAddress, UserLength, BufferAddress, BufferLength, Alignment);\n\n        // Align the UserLength to the nearest page boundary.\n        SIZE_T length = (SIZE_T)ALIGN_UP_BY(UserLength, PAGE_SIZE);\n\n        // Iterate over each page and ensure the address is valid and accessible.\n        for (SIZE_T offset = 0; offset < length; offset += PAGE_SIZE)\n        {\n            // Ensure the address does not overflow\n            if ((ULONG_PTR)UserAddress + offset < (ULONG_PTR)UserAddress)\n            {\n                PhRaiseStatus(STATUS_ACCESS_VIOLATION);\n            }\n\n            *((volatile char*)UserAddress + offset);\n        }\n    }\n}\n\nFORCEINLINE\nVOID\nPhProbeForWrite(\n    _In_ CONST PVOID UserAddress,\n    _In_ CONST SIZE_T UserLength,\n    _In_ CONST PVOID BufferAddress,\n    _In_ CONST SIZE_T BufferLength,\n    _In_ CONST ULONG Alignment\n    )\n{\n    if (UserLength != 0)\n    {\n        PhProbeAddress(UserAddress, UserLength, BufferAddress, BufferLength, Alignment);\n\n        // Align the UserLength to the nearest page boundary.\n        SIZE_T length = (SIZE_T)ALIGN_UP_BY(UserLength, PAGE_SIZE);\n\n        // Iterate over each page and ensure the address is valid and accessible.\n        for (SIZE_T offset = 0; offset < length; offset += PAGE_SIZE)\n        {\n            // Ensure the address does not overflow\n            if ((ULONG_PTR)UserAddress + offset < (ULONG_PTR)UserAddress)\n            {\n                PhRaiseStatus(STATUS_ACCESS_VIOLATION);\n            }\n\n            *((volatile char*)UserAddress + offset) = *((volatile char*)UserAddress + offset);\n        }\n    }\n}\n\nFORCEINLINE\nPLARGE_INTEGER\nPhTimeoutFromMilliseconds(\n    _Out_ CONST PLARGE_INTEGER Timeout,\n    _In_ CONST ULONG Milliseconds\n    )\n{\n    if (Milliseconds == INFINITE)\n        Timeout->QuadPart = MINLONGLONG;\n    else\n        Timeout->QuadPart = -(LONGLONG)UInt32x32To64(Milliseconds, PH_TIMEOUT_MS);\n\n    return Timeout;\n}\n\nFORCEINLINE\nFLOAT\nPhClampSingle(\n    _In_ FLOAT Value,\n    _In_ FLOAT Min,\n    _In_ FLOAT Max\n    )\n{\n    return fminf(fmaxf(Value, Min), Max);\n}\n\nFORCEINLINE\nDOUBLE\nPhClampDouble(\n    _In_ DOUBLE Value,\n    _In_ DOUBLE Min,\n    _In_ DOUBLE Max\n    )\n{\n    return fmin(fmax(Value, Min), Max);\n}\n\n#endif\n"
  },
  {
    "path": "phlib/include/phutil.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_PHUTIL_H\n#define _PH_PHUTIL_H\n\nEXTERN_C_START\n\nextern CONST WCHAR *PhSizeUnitNames[7];\nextern ULONG PhMaxSizeUnit;\nextern USHORT PhMaxPrecisionUnit;\nextern FLOAT PhMaxPrecisionLimit;\nextern CONST PH_STRINGREF PhPrefixUnitNamesCounted[7];\nextern CONST PH_STRINGREF PhSiPrefixUnitNamesCounted[7];\n\ntypedef struct _PH_INTEGER_PAIR\n{\n    LONG X;\n    LONG Y;\n} PH_INTEGER_PAIR, *PPH_INTEGER_PAIR;\n\ntypedef struct _PH_SCALABLE_INTEGER_PAIR\n{\n    union\n    {\n        PH_INTEGER_PAIR Pair;\n        struct\n        {\n            LONG X;\n            LONG Y;\n        };\n    };\n    union\n    {\n        PH_INTEGER_PAIR Padding;\n        struct\n        {\n            LONG Scale;\n            LONG Spare;\n        };\n    };\n} PH_SCALABLE_INTEGER_PAIR, *PPH_SCALABLE_INTEGER_PAIR;\n\ntypedef struct _PH_RECTANGLE\n{\n    union\n    {\n        PH_INTEGER_PAIR Position;\n        struct\n        {\n            LONG Left;\n            LONG Top;\n        };\n    };\n    union\n    {\n        PH_INTEGER_PAIR Size;\n        struct\n        {\n            LONG Width;\n            LONG Height;\n        };\n    };\n} PH_RECTANGLE, *PPH_RECTANGLE;\n\n/**\n * Converts a Win32 RECT to a PPH_RECTANGLE.\n *\n * The resulting rectangle uses left/top coordinates and width/height\n * dimensions rather than Win32's left/top/right/bottom edge format.\n */\nFORCEINLINE\nVOID\nPhRectToRectangle(\n    _Out_ PPH_RECTANGLE Rectangle,\n    _In_ PRECT Rect\n    )\n{\n    Rectangle->Left = Rect->left;\n    Rectangle->Top = Rect->top;\n    Rectangle->Width = Rect->right - Rect->left;\n    Rectangle->Height = Rect->bottom - Rect->top;\n}\n\n/**\n * Converts a PPH_RECTANGLE to a Win32 RECT.\n *\n * The output RECT uses absolute edge coordinates computed from the\n * rectangle's left/top origin and width/height dimensions.\n */\nFORCEINLINE\nVOID\nPhRectangleToRect(\n    _Out_ PRECT Rect,\n    _In_ PPH_RECTANGLE Rectangle\n    )\n{\n    Rect->left = Rectangle->Left;\n    Rect->top = Rectangle->Top;\n    Rect->right = Rectangle->Left + Rectangle->Width;\n    Rect->bottom = Rectangle->Top + Rectangle->Height;\n}\n\n/**\n * Converts a RECT from right/bottom offsets to absolute coordinates.\n *\n * The right and bottom fields of the input RECT are interpreted as offsets\n * from the parent rectangle's right and bottom edges. This function converts\n * them into absolute coordinates relative to the parent.\n */\nFORCEINLINE\nVOID\nPhConvertRect(\n    _Inout_ PRECT Rect,\n    _In_ PRECT ParentRect\n    )\n{\n    Rect->right = ParentRect->right - ParentRect->left - Rect->right;\n    Rect->bottom = ParentRect->bottom - ParentRect->top - Rect->bottom;\n}\n\n/**\n * Maps a RECT from an outer coordinate space into an inner one.\n *\n * The resulting RECT is expressed relative to the outer rectangle's origin.\n * This is useful when translating child‑window or sub‑region coordinates\n * into a parent coordinate system.\n */\nFORCEINLINE\nVOID\nPhMapRect(\n    _Out_ PRECT Rect,\n    _In_ PRECT InnerRect,\n    _In_ PRECT OuterRect\n    )\n{\n    Rect->left = InnerRect->left - OuterRect->left;\n    Rect->top = InnerRect->top - OuterRect->top;\n    Rect->right = InnerRect->right - OuterRect->left;\n    Rect->bottom = InnerRect->bottom - OuterRect->top;\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhAdjustRectangleToBounds(\n    _Inout_ PPH_RECTANGLE Rectangle,\n    _In_ PPH_RECTANGLE Bounds\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhCenterRectangle(\n    _Inout_ PPH_RECTANGLE Rectangle,\n    _In_ PPH_RECTANGLE Bounds\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAdjustRectangleToWorkingArea(\n    _In_opt_ HWND WindowHandle,\n    _Inout_ PPH_RECTANGLE Rectangle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhCenterWindow(\n    _In_ HWND WindowHandle,\n    _In_opt_ HWND ParentWindowHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMoveWindowToMonitor(\n    _In_ HWND WindowHandle,\n    _In_ HMONITOR MonitorHandle\n    );\n\n//\n// NLS\n//\n\nPHLIBAPI\nLANGID\nNTAPI\nPhGetUserDefaultLangID(\n    VOID\n    );\n\nPHLIBAPI\nLCID\nNTAPI\nPhGetSystemDefaultLCID(\n    VOID\n    );\n\nPHLIBAPI\nLCID\nNTAPI\nPhGetUserDefaultLCID(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetUserLocaleInfoBool(\n    _In_ LCTYPE LCType\n    );\n\nPHLIBAPI\nLCID\nNTAPI\nPhGetCurrentThreadLCID(\n    VOID\n    );\n\n//\n// Time\n//\n\nPHLIBAPI\nVOID\nNTAPI\nPhLargeIntegerToSystemTime(\n    _Out_ PSYSTEMTIME SystemTime,\n    _In_ PLARGE_INTEGER LargeInteger\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSystemTimeToLargeInteger(\n    _Out_ PLARGE_INTEGER LargeInteger,\n    _In_ PSYSTEMTIME SystemTime\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLargeIntegerToLocalSystemTime(\n    _Out_ PSYSTEMTIME SystemTime,\n    _In_ PLARGE_INTEGER LargeInteger\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLocalSystemTimeToLargeInteger(\n    _Out_ PLARGE_INTEGER LargeInteger,\n    _In_ PSYSTEMTIME SystemTime\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSystemTimeToTzSpecificLocalTime(\n    _In_ CONST SYSTEMTIME* UniversalTime,\n    _Out_ PSYSTEMTIME LocalTime\n    );\n\n//\n// Error messages\n//\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetMessage(\n    _In_ PVOID DllHandle,\n    _In_ ULONG MessageTableId,\n    _In_ ULONG MessageLanguageId,\n    _In_ ULONG MessageId\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetNtMessage(\n    _In_ NTSTATUS Status\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetWin32Message(\n    _In_ ULONG Result\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetWin32FormatMessage(\n    _In_ ULONG Result\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetNtFormatMessage(\n    _In_ NTSTATUS Status\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhShowMessage(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Type,\n    _In_ PCWSTR Format,\n    ...\n    );\n\n#define PhShowError(WindowHandle, Format, ...) PhShowMessage(WindowHandle, MB_OK | MB_ICONERROR, Format, __VA_ARGS__)\n#define PhShowWarning(WindowHandle, Format, ...) PhShowMessage(WindowHandle, MB_OK | MB_ICONWARNING, Format, __VA_ARGS__)\n#define PhShowInformation(WindowHandle, Format, ...) PhShowMessage(WindowHandle, MB_OK | MB_ICONINFORMATION, Format, __VA_ARGS__)\n\nPHLIBAPI\nLONG\nNTAPI\nPhShowMessage2(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    );\n\n#define TD_OK_BUTTON      0x0001\n#define TD_YES_BUTTON     0x0002\n#define TD_NO_BUTTON      0x0004\n#define TD_CANCEL_BUTTON  0x0008\n#define TD_RETRY_BUTTON   0x0010\n#define TD_CLOSE_BUTTON   0x0020\n\n#ifndef TD_WARNING_ICON\n#define TD_WARNING_ICON         MAKEINTRESOURCEW(-1)\n#endif\n#ifndef TD_ERROR_ICON\n#define TD_ERROR_ICON           MAKEINTRESOURCEW(-2)\n#endif\n#ifndef TD_INFORMATION_ICON\n#define TD_INFORMATION_ICON     MAKEINTRESOURCEW(-3)\n#endif\n#ifndef TD_SHIELD_ICON\n#define TD_SHIELD_ICON          MAKEINTRESOURCEW(-4)\n#endif\n\n#define PhShowError2(WindowHandle, Title, Format, ...) PhShowMessage2(WindowHandle, TD_CLOSE_BUTTON, TD_ERROR_ICON, Title, Format, __VA_ARGS__)\n#define PhShowWarning2(WindowHandle, Title, Format, ...) PhShowMessage2(WindowHandle, TD_CLOSE_BUTTON, TD_WARNING_ICON, Title, Format, __VA_ARGS__)\n#define PhShowInformation2(WindowHandle, Title, Format, ...) PhShowMessage2(WindowHandle, TD_CLOSE_BUTTON, TD_INFORMATION_ICON, Title, Format, __VA_ARGS__)\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShowMessageOneTime(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhShowMessageOneTime2(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ PCWSTR Title,\n    _Out_opt_ PBOOLEAN Checked,\n    _In_ PCWSTR Format,\n    ...\n    );\n\ntypedef struct _TASKDIALOGCONFIG TASKDIALOGCONFIG, *PTASKDIALOGCONFIG;\n\n// TDM_NAVIGATE_PAGE is not thread safe and accelerator keys crash the process\n// after navigating to the page and pressing ctrl, alt, home or insert keys. (dmex)\nFORCEINLINE\nVOID\nPhTaskDialogNavigatePage(\n    _In_ HWND WindowHandle,\n    _In_ PTASKDIALOGCONFIG Config\n    )\n{\n    assert(HandleToUlong(NtCurrentThreadId()) == GetWindowThreadProcessId(WindowHandle, NULL));\n\n    #define WM_TDM_NAVIGATE_PAGE (WM_USER + 101)\n\n    SendMessage(WindowHandle, WM_TDM_NAVIGATE_PAGE, 0, (LPARAM)(Config));\n}\n\n#define TD_WARN_ICON             MAKEINTRESOURCEW(-1) // Warning icon\n#define TD_ERROR_ICON            MAKEINTRESOURCEW(-2) // Error icon\n#define TD_INFO_ICON             MAKEINTRESOURCEW(-3) // Information icon\n#define TD_SHIELD_ICON           MAKEINTRESOURCEW(-4) // Shield icon\n#define TD_SHIELD_INFO_ICON      MAKEINTRESOURCEW(-5) // Shield icon + Blue background\n#define TD_SHIELD_WARNING_ICON   MAKEINTRESOURCEW(-6) // Shield icon + Yellow background\n#define TD_SHIELD_ERROR_ICON     MAKEINTRESOURCEW(-7) // Shield icon + Red background\n#define TD_SHIELD_SUCCESS_ICON   MAKEINTRESOURCEW(-8) // Shield icon + Green background\n#define TD_SHIELD_INACTIVE_ICON  MAKEINTRESOURCEW(-9) // Shield icon + Gray background\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShowTaskDialog(\n    _In_ PTASKDIALOGCONFIG Config,\n    _Out_opt_ PULONG Button,\n    _Out_opt_ PULONG RadioButton,\n    _Out_opt_ PBOOLEAN FlagChecked\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetStatusMessage(\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhShowStatus(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR Message,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShowContinueStatus(\n    _In_ HWND WindowHandle,\n    _In_opt_ PCWSTR Message,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShowConfirmMessage(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Verb,\n    _In_ PCWSTR Object,\n    _In_opt_ PCWSTR Message,\n    _In_ BOOLEAN Warning\n    );\n\n/**\n * Finds an integer in an array of string-integer pairs.\n *\n * \\param KeyValuePairs The array.\n * \\param SizeOfKeyValuePairs The size of the array, in bytes.\n * \\param String The string to search for.\n * \\param Integer A variable which receives the found integer.\n * \\return TRUE if the string was found, otherwise FALSE.\n * \\remarks The search is case-sensitive.\n */\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nPhFindIntegerSiKeyValuePairs(\n    _In_ PCPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ PCWSTR String,\n    _Out_ PULONG Integer\n    )\n{\n    for (ULONG i = 0; i < SizeOfKeyValuePairs / sizeof(PH_KEY_VALUE_PAIR); i++)\n    {\n        if (PhEqualStringZ((PCWSTR)KeyValuePairs[i].Key, String, TRUE))\n        {\n            *Integer = PtrToUlong(KeyValuePairs[i].Value);\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Finds an integer in an array of string-integer pairs using a STRINGREF.\n *\n * \\param KeyValuePairs The array.\n * \\param SizeOfKeyValuePairs The size of the array, in bytes.\n * \\param String The string reference to search for.\n * \\param Integer A variable which receives the found integer.\n * \\return TRUE if the string was found, otherwise FALSE.\n * \\remarks The search is case-sensitive.\n */\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nPhFindIntegerSiKeyValuePairsStringRef(\n    _In_ PCPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ PCPH_STRINGREF String,\n    _Out_ PULONG Integer\n    )\n{\n    for (ULONG i = 0; i < SizeOfKeyValuePairs / sizeof(PH_KEY_VALUE_PAIR); i++)\n    {\n        if (PhEqualStringRef((PCPH_STRINGREF)KeyValuePairs[i].Key, String, TRUE))\n        {\n            *Integer = PtrToUlong(KeyValuePairs[i].Value);\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Finds a string in an array of string-integer pairs.\n *\n * \\param KeyValuePairs The array.\n * \\param SizeOfKeyValuePairs The size of the array, in bytes.\n * \\param Integer The integer to search for.\n * \\param String A variable which receives the found string.\n * \\return TRUE if the integer was found, otherwise FALSE.\n */\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nPhFindStringSiKeyValuePairs(\n    _In_ PCPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ ULONG Integer,\n    _Out_ PCWSTR *String\n    )\n{\n    for (ULONG i = 0; i < SizeOfKeyValuePairs / sizeof(PH_KEY_VALUE_PAIR); i++)\n    {\n        if (PtrToUlong(KeyValuePairs[i].Value) == Integer)\n        {\n            *String = (PCWSTR)KeyValuePairs[i].Key;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Finds a string reference in an array of string-integer pairs.\n *\n * \\param KeyValuePairs The array.\n * \\param SizeOfKeyValuePairs The size of the array, in bytes.\n * \\param Integer The integer to search for.\n * \\param String A variable which receives the found string reference.\n * \\return TRUE if the integer was found, otherwise FALSE.\n */\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nPhFindStringRefSiKeyValuePairs(\n    _In_ PCPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ ULONG Integer,\n    _Out_ PCPH_STRINGREF* String\n    )\n{\n    for (ULONG i = 0; i < SizeOfKeyValuePairs / sizeof(PH_KEY_VALUE_PAIR); i++)\n    {\n        if (PtrToUlong(KeyValuePairs[i].Value) == Integer)\n        {\n            *String = (PCPH_STRINGREF)KeyValuePairs[i].Key;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Retrieves a string from an array of string-integer pairs by index.\n *\n * \\param KeyValuePairs The array.\n * \\param SizeOfKeyValuePairs The size of the array, in bytes.\n * \\param Integer The index or integer to search for.\n * \\param String A variable which receives the found string.\n * \\return TRUE if the string was found, otherwise FALSE.\n * \\remarks If the index is out of range, a full search is performed.\n */\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nPhIndexStringSiKeyValuePairs(\n    _In_ PCPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ ULONG Integer,\n    _Out_ PCWSTR *String\n    )\n{\n    assert(KeyValuePairs[0].Value == 0); // Values must be zero based\n\n    if (Integer < SizeOfKeyValuePairs / sizeof(PH_KEY_VALUE_PAIR))\n    {\n        *String = (PCWSTR)KeyValuePairs[Integer].Key;\n        return TRUE;\n    }\n\n    return PhFindStringSiKeyValuePairs(KeyValuePairs, SizeOfKeyValuePairs, Integer, String);\n}\n\n/**\n * Retrieves a string reference from an array of string-integer pairs by index.\n *\n * \\param KeyValuePairs The array.\n * \\param SizeOfKeyValuePairs The size of the array, in bytes.\n * \\param Integer The index or integer to search for.\n * \\param String A variable which receives the found string reference.\n * \\return TRUE if the string reference was found, otherwise FALSE.\n * \\remarks Values must be zero-based.\n */\n_Success_(return)\nFORCEINLINE\nBOOLEAN\nPhIndexStringRefSiKeyValuePairs(\n    _In_ PCPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ ULONG Integer,\n    _Out_ PCPH_STRINGREF* String\n    )\n{\n    assert(KeyValuePairs[0].Value == 0); // Values must be zero based\n\n    if (Integer < SizeOfKeyValuePairs / sizeof(PH_KEY_VALUE_PAIR))\n    {\n        *String = (PCPH_STRINGREF)KeyValuePairs[Integer].Key;\n        return TRUE;\n    }\n\n    return PhFindStringRefSiKeyValuePairs(KeyValuePairs, SizeOfKeyValuePairs, Integer, String);\n}\n\n#define GUID_VERSION_MAC 1\n#define GUID_VERSION_DCE 2\n#define GUID_VERSION_MD5 3\n#define GUID_VERSION_RANDOM 4\n#define GUID_VERSION_SHA1 5\n#define GUID_VERSION_TIME 6\n#define GUID_VERSION_EPOCH 7\n#define GUID_VERSION_VENDOR 8\n\n#define GUID_VARIANT_NCS_MASK 0x80\n#define GUID_VARIANT_NCS 0x00\n#define GUID_VARIANT_STANDARD_MASK 0xc0\n#define GUID_VARIANT_STANDARD 0x80\n#define GUID_VARIANT_MICROSOFT_MASK 0xe0\n#define GUID_VARIANT_MICROSOFT 0xc0\n#define GUID_VARIANT_RESERVED_MASK 0xe0\n#define GUID_VARIANT_RESERVED 0xe0\n\ntypedef union _GUID_EX\n{\n    GUID Guid;\n    UCHAR Data[16];\n    struct\n    {\n        ULONG TimeLowPart;\n        USHORT TimeMidPart;\n        USHORT TimeHighPart;\n        UCHAR ClockSequenceHigh;\n        UCHAR ClockSequenceLow;\n        UCHAR Node[6];\n    } s;\n    struct\n    {\n        ULONG Part0;\n        USHORT Part32;\n        UCHAR Part48;\n        UCHAR Part56 : 4;\n        UCHAR Version : 4;\n        UCHAR Variant;\n        UCHAR Part72;\n        USHORT Part80;\n        ULONG Part96;\n    } s2;\n} GUID_EX, *PGUID_EX;\n\nPHLIBAPI\nVOID\nNTAPI\nPhGenerateGuid(\n    _Out_ PGUID Guid\n    );\n\n/**\n * Reverses the byte order of a GUID.\n *\n * \\param Guid The GUID to reverse.\n * \\remarks This function reverses the endianness of the first three GUID fields\n * (Data1, Data2, and Data3). The remaining fields are left unchanged.\n */\nFORCEINLINE\nVOID\nNTAPI\nPhReverseGuid(\n    _Inout_ PGUID Guid\n    )\n{\n    Guid->Data1 = _byteswap_ulong(Guid->Data1);\n    Guid->Data2 = _byteswap_ushort(Guid->Data2);\n    Guid->Data3 = _byteswap_ushort(Guid->Data3);\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhGenerateGuidFromName(\n    _Out_ PGUID Guid,\n    _In_ PGUID Namespace,\n    _In_ PCHAR Name,\n    _In_ ULONG NameLength,\n    _In_ UCHAR Version\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGenerateClass5Guid(\n    _In_ REFGUID NamespaceGuid,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _Out_ PGUID Guid\n    );\n\nDEFINE_GUID(GUID_NAMESPACE_MICROSOFT, 0x70ffd812, 0x4c7f, 0x4c7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);\n\nPHLIBAPI\nVOID\nNTAPI\nPhGenerateHardwareIDGuid(\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _Out_ PGUID Guid\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGenerateRandomAlphaString(\n    _Out_writes_z_(Count) PWSTR Buffer,\n    _In_ SIZE_T Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGenerateRandomNumericString(\n    _Out_writes_z_(Count) PWSTR Buffer,\n    _In_ SIZE_T Count\n    );\n\n/**\n * Generates a random alphabetic string and initializes a STRINGREF to reference it.\n *\n * \\param Buffer The buffer that receives the generated string.\n * \\param Count The number of characters to generate, including the null terminator.\n * \\param String A variable which receives the resulting string reference.\n */\nFORCEINLINE\nVOID\nPhGenerateRandomAlphaStringRef(\n    _Out_writes_z_(Count) PWSTR Buffer,\n    _In_ SIZE_T Count,\n    _Out_ PPH_STRINGREF String\n    )\n{\n    PhGenerateRandomAlphaString(Buffer, Count);\n    String->Buffer = Buffer;\n    String->Length = (Count * sizeof(WCHAR)) - sizeof(UNICODE_NULL);\n}\n\nPHLIBAPI\nULONG64\nNTAPI\nPhGenerateRandomNumber64(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGenerateRandomNumber(\n    _Out_ PLARGE_INTEGER Number\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGenerateRandomSeed(\n    _Out_ PLARGE_INTEGER Seed\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhEllipsisString(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T DesiredCount\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhEllipsisStringPath(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T DesiredCount\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhMatchWildcards(\n    _In_ PCWSTR Pattern,\n    _In_ PCWSTR String,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhEscapeStringForMenuPrefix(\n    _In_ PCPH_STRINGREF String\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhCompareUnicodeStringZIgnoreMenuPrefix(\n    _In_ PCWSTR A,\n    _In_ PCWSTR B,\n    _In_ BOOLEAN IgnoreCase,\n    _In_ BOOLEAN MatchIfPrefix\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatSystemTimeISO(\n    _In_opt_ PSYSTEMTIME SystemTime\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatLocalSystemTimeISO(\n    _In_opt_ PSYSTEMTIME SystemTime\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatDate(\n    _In_opt_ PSYSTEMTIME Date,\n    _In_opt_ PCWSTR Format\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatTime(\n    _In_opt_ PSYSTEMTIME Time,\n    _In_opt_ PCWSTR Format\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatDateTime(\n    _In_opt_ PSYSTEMTIME DateTime\n    );\n\n#define PhaFormatDateTime(DateTime) PH_AUTO_T(PH_STRING, PhFormatDateTime(DateTime))\n\n#define PH_DATETIME_STR_LEN 256\n#define PH_DATETIME_STR_LEN_1 (PH_DATETIME_STR_LEN + 1)\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhFormatDateTimeToBuffer(\n    _In_opt_ PSYSTEMTIME DateTime,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatTimeSpan(\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatTimeSpanRelative(\n    _In_ ULONG64 TimeSpan\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatUInt64(\n    _In_ ULONG64 Value,\n    _In_ BOOLEAN GroupDigits\n    );\n\n#define PhaFormatUInt64(Value, GroupDigits) \\\n    PH_AUTO_T(PH_STRING, PhFormatUInt64((Value), (GroupDigits)))\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatUInt64BitratePrefix(\n    _In_ ULONG64 Value,\n    _In_ BOOLEAN GroupDigits\n    );\n\n#define PhaFormatUInt64BitratePrefix(Value, GroupDigits) \\\n    PH_AUTO_T(PH_STRING, PhFormatUInt64BitratePrefix((Value), (GroupDigits)))\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatDecimal(\n    _In_ PCWSTR Value,\n    _In_ ULONG FractionalDigits,\n    _In_ BOOLEAN GroupDigits\n    );\n\n#define PhaFormatDecimal(Value, FractionalDigits, GroupDigits) \\\n    PH_AUTO_T(PH_STRING, PhFormatDecimal((Value), (FractionalDigits), (GroupDigits)))\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatSize(\n    _In_ ULONG64 Size,\n    _In_ ULONG MaxSizeUnit\n    );\n\n#define PhaFormatSize(Size, MaxSizeUnit) \\\n    PH_AUTO_T(PH_STRING, PhFormatSize((Size), (MaxSizeUnit)))\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhFormatSizeToBuffer(\n    _In_ ULONG64 Size,\n    _In_ ULONG MaxSizeUnit,\n    _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatGuid(\n    _In_ PGUID Guid\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFormatGuidToBuffer(\n    _In_ PGUID Guid,\n    _Writable_bytes_(BufferLength) _When_(BufferLength != 0, _Notnull_) PWCHAR Buffer,\n    _In_opt_ USHORT BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhStringToGuid(\n    _In_ PCPH_STRINGREF GuidString,\n    _Out_ PGUID Guid\n    );\n\ntypedef struct _VS_VERSION_INFO_STRUCT16\n{\n    USHORT Length;\n    USHORT ValueLength;\n    CHAR Key[1];\n} VS_VERSION_INFO_STRUCT16, *PVS_VERSION_INFO_STRUCT16;\n\ntypedef struct _VS_VERSION_INFO_STRUCT32\n{\n    USHORT Length;\n    USHORT ValueLength;\n    USHORT Type;\n    WCHAR Key[1];\n} VS_VERSION_INFO_STRUCT32, *PVS_VERSION_INFO_STRUCT32;\n\nFORCEINLINE\nBOOLEAN\nPhIsFileVersionInfo32(\n    _In_ PVOID VersionInfo\n    )\n{\n    return ((PVS_VERSION_INFO_STRUCT16)VersionInfo)->Key[0] < 32;\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileVersionInfo(\n    _In_ PCWSTR FileName,\n    _Out_ PVOID* VersionInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileVersionInfoEx(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_ PVOID* VersionInfo\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileVersionInfoKey(\n    _In_ PVS_VERSION_INFO_STRUCT32 VersionInfo,\n    _In_ SIZE_T KeyLength,\n    _In_ PCWSTR Key,\n    _Out_opt_ PVOID* Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileVersionVarFileInfoValue(\n    _In_ PVOID VersionInfo,\n    _In_ PCPH_STRINGREF KeyName,\n    _Out_opt_ PVOID* Buffer,\n    _Out_opt_ PULONG BufferLength\n    );\n\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhGetFileVersionVarFileInfoValueZ(\n    _In_ PVOID VersionInfo,\n    _In_ PCWSTR KeyName,\n    _Out_opt_ PVOID* Buffer,\n    _Out_opt_ PULONG BufferLength\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, KeyName);\n\n    return PhGetFileVersionVarFileInfoValue(VersionInfo, &string, Buffer, BufferLength);\n}\n\nPHLIBAPI\nVS_FIXEDFILEINFO*\nNTAPI\nPhGetFileVersionFixedInfo(\n    _In_ PVOID VersionInfo\n    );\n\ntypedef struct _LANGANDCODEPAGE\n{\n    USHORT Language;\n    USHORT CodePage;\n} LANGANDCODEPAGE, *PLANGANDCODEPAGE;\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetFileVersionInfoLangCodePage(\n    _In_ PVOID VersionInfo\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetFileVersionInfoString(\n    _In_ PVOID VersionInfo,\n    _In_ PCWSTR SubBlock\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetFileVersionInfoString2(\n    _In_ PVOID VersionInfo,\n    _In_ ULONG LangCodePage,\n    _In_ PCPH_STRINGREF KeyName\n    );\n\ntypedef struct _PH_IMAGE_VERSION_INFO\n{\n    PPH_STRING CompanyName;\n    PPH_STRING FileDescription;\n    PPH_STRING FileVersion;\n    PPH_STRING ProductName;\n} PH_IMAGE_VERSION_INFO, *PPH_IMAGE_VERSION_INFO;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeImageVersionInfo(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PCWSTR FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeImageVersionInfoEx(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN ExtendedVersionInfo\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteImageVersionInfo(\n    _Inout_ PPH_IMAGE_VERSION_INFO ImageVersionInfo\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatImageVersionInfo(\n    _In_opt_ PPH_STRING FileName,\n    _In_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_opt_ PCPH_STRINGREF Indent,\n    _In_opt_ ULONG LineLimit\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeImageVersionInfoCached(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PPH_STRING FileName,\n    _In_ BOOLEAN IsSubsystemProcess,\n    _In_ BOOLEAN ExtendedVersion\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFlushImageVersionInfoCache(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFullPath(\n    _In_ PCWSTR FileName,\n    _Out_ PPH_STRING *FullPath,\n    _Out_opt_ PULONG IndexOfFileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhExpandEnvironmentStrings(\n    _In_ PCPH_STRINGREF String\n    );\n\nFORCEINLINE\nPPH_STRING\nPhExpandEnvironmentStringsZ(\n    _In_ PCWSTR String\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, String);\n\n    return PhExpandEnvironmentStrings(&string);\n}\n\n/**\n * Converts NT path separators to alternate DOS path separators in a string.\n *\n * \\param String The string to modify.\n * \\return The modified string.\n * \\remarks Only the NT path separator ('\\\\') is replaced. The function operates\n * in-place and returns the same string pointer.\n */\nFORCEINLINE\nPPH_STRING\nPhConvertNtPathSeperatorToAltSeperator(\n    _In_ PPH_STRING String\n    )\n{\n    if (String)\n    {\n        for (ULONG i = 0; i < String->Length / sizeof(WCHAR); i++)\n        {\n            if (String->Buffer[i] == OBJ_NAME_PATH_SEPARATOR) // RtlNtPathSeperatorString\n                String->Buffer[i] = OBJ_NAME_ALTPATH_SEPARATOR; // RtlAlternateDosPathSeperatorString\n        }\n    }\n\n    return String;\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetBaseName(\n    _In_ PPH_STRING FileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetBaseNameChangeExtension(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PCPH_STRINGREF FileExtension\n    );\n\nFORCEINLINE\nPPH_STRING\nNTAPI\nPhGetBaseNameChangeExtensionZ(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PCWSTR FileExtension\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, FileExtension);\n\n    return PhGetBaseNameChangeExtension(FileName, &string);\n}\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetBasePath(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_opt_ PPH_STRINGREF BasePathName,\n    _Out_opt_ PPH_STRINGREF BaseFileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetBaseDirectory(\n    _In_ PPH_STRING FileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSystemDirectory(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSystemDirectoryWin32(\n    _In_opt_ PCPH_STRINGREF AppendPath\n    );\n\nFORCEINLINE\nPPH_STRING\nPhGetSystemDirectoryWin32Z(\n    _In_ PCWSTR AppendPath\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, AppendPath);\n\n    return PhGetSystemDirectoryWin32(&string);\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetSystemRoot(\n    _Out_ PPH_STRINGREF SystemRoot\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetNtSystemRoot(\n    _Out_ PPH_STRINGREF NtSystemRoot\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetApplicationFileName(\n    VOID\n    );\n\nFORCEINLINE\nPPH_STRING\nPhGetApplicationFileNameZ(\n    _In_ PCWSTR AppendPath\n    )\n{\n    PPH_STRING fileName = NULL;\n    PPH_STRING applicationFileName;\n\n    if (applicationFileName = PhGetApplicationFileName())\n    {\n        PH_STRINGREF string;\n\n        PhInitializeStringRef(&string, AppendPath);\n        fileName = PhConcatStringRef2(&applicationFileName->sr, &string);\n        PhDereferenceObject(applicationFileName);\n    }\n\n    return fileName;\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetApplicationFileNameWin32(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetApplicationDirectory(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetApplicationDirectoryWin32(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetApplicationDirectoryFileName(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    );\n\nFORCEINLINE\nPPH_STRING\nPhGetApplicationDirectoryFileNameZ(\n    _In_ PCWSTR FileName,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, FileName);\n\n    return PhGetApplicationDirectoryFileName(&string, NativeFileName);\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetTemporaryDirectoryRandomAlphaFileName(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetLocalAppDataDirectory(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    );\n\nFORCEINLINE\nPPH_STRING\nPhGetLocalAppDataDirectoryZ(\n    _In_ PCWSTR String,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, String);\n\n    return PhGetLocalAppDataDirectory(&string, NativeFileName);\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetRoamingAppDataDirectory(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    );\n\nFORCEINLINE\nPPH_STRING\nPhGetRoamingAppDataDirectoryZ(\n    _In_ PCWSTR String,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, String);\n\n    return PhGetRoamingAppDataDirectory(&string, NativeFileName);\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetApplicationDataFileName(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    );\n\n#define PH_FOLDERID_LocalAppData 1\n#define PH_FOLDERID_RoamingAppData 2\n#define PH_FOLDERID_ProgramFiles 3\n#define PH_FOLDERID_ProgramData 4\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetKnownLocation(\n    _In_ ULONG Folder,\n    _In_opt_ PCPH_STRINGREF AppendPath,\n    _In_ BOOLEAN NativeFileName\n    );\n\nFORCEINLINE\nPPH_STRING\nPhGetKnownLocationZ(\n    _In_ ULONG Folder,\n    _In_ PCWSTR AppendPath,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, AppendPath);\n\n    return PhGetKnownLocation(Folder, &string, NativeFileName);\n}\n\nDEFINE_GUID(FOLDERID_LocalAppData, 0xF1B32785, 0x6FBA, 0x4FCF, 0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91);\nDEFINE_GUID(FOLDERID_RoamingAppData, 0x3EB685DB, 0x65F9, 0x4CF6, 0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D);\nDEFINE_GUID(FOLDERID_ProgramFiles, 0x905e63b6, 0xc1bf, 0x494e, 0xb2, 0x9c, 0x65, 0xb7, 0x32, 0xd3, 0xd2, 0x1a);\nDEFINE_GUID(FOLDERID_ProgramData, 0x62AB5D82, 0xFDC1, 0x4DC3, 0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97);\n\n#define PH_KF_FLAG_FORCE_PACKAGE_REDIRECTION 0x1\n#define PH_KF_FLAG_FORCE_APPCONTAINER_REDIRECTION 0x2\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetKnownFolderPath(\n    _In_ PCGUID Folder,\n    _In_opt_ PCPH_STRINGREF AppendPath\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetKnownFolderPathEx(\n    _In_ PCGUID Folder,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _In_opt_ PCPH_STRINGREF AppendPath\n    );\n\nFORCEINLINE\nPPH_STRING\nPhGetKnownFolderPathZ(\n    _In_ PCGUID Folder,\n    _In_ PCWSTR AppendPath\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, AppendPath);\n\n    return PhGetKnownFolderPath(Folder, &string);\n}\n\nFORCEINLINE\nPPH_STRING\nPhGetKnownFolderPathExZ(\n    _In_ PCGUID Folder,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _In_ PCWSTR AppendPath\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, AppendPath);\n\n    return PhGetKnownFolderPathEx(Folder, Flags, TokenHandle, &string);\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetTemporaryDirectory(\n    _In_opt_ PCPH_STRINGREF AppendPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWaitForMultipleObjectsAndPump(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG NumberOfHandles,\n    _In_ PHANDLE Handles,\n    _In_ ULONG Timeout,\n    _In_ ULONG WakeMask\n    );\n\ntypedef struct _PH_CREATE_PROCESS_INFO\n{\n    PUNICODE_STRING DllPath;\n    PUNICODE_STRING WindowTitle;\n    PUNICODE_STRING DesktopInfo;\n    PUNICODE_STRING ShellInfo;\n    PUNICODE_STRING RuntimeData;\n} PH_CREATE_PROCESS_INFO, *PPH_CREATE_PROCESS_INFO;\n\n#define PH_CREATE_PROCESS_INHERIT_HANDLES 0x1\n#define PH_CREATE_PROCESS_UNICODE_ENVIRONMENT 0x2\n#define PH_CREATE_PROCESS_SUSPENDED 0x4\n#define PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB 0x8\n#define PH_CREATE_PROCESS_NEW_CONSOLE 0x10\n#define PH_CREATE_PROCESS_DEBUG 0x20\n#define PH_CREATE_PROCESS_DEBUG_ONLY_THIS_PROCESS 0x40\n#define PH_CREATE_PROCESS_EXTENDED_STARTUPINFO 0x80\n#define PH_CREATE_PROCESS_DEFAULT_ERROR_MODE 0x100\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcess(\n    _In_ PCWSTR FileName,\n    _In_opt_ PCPH_STRINGREF CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PCPH_STRINGREF CurrentDirectory,\n    _In_opt_ PPH_CREATE_PROCESS_INFO Information,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE ParentProcessHandle,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessWin32(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ PCWSTR CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PCWSTR CurrentDirectory,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessWin32Ex(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ PCWSTR CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PCWSTR CurrentDirectory,\n    _In_opt_ PVOID StartupInfo,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    );\n\ntypedef struct _PH_CREATE_PROCESS_AS_USER_INFO\n{\n    _In_opt_ PCWSTR ApplicationName;\n    _In_opt_ PCWSTR CommandLine;\n    _In_opt_ PCWSTR CurrentDirectory;\n    _In_opt_ PVOID Environment;\n    _In_opt_ PCWSTR DesktopName;\n    _In_opt_ ULONG SessionId; // use PH_CREATE_PROCESS_SET_SESSION_ID\n    union\n    {\n        struct\n        {\n            _In_ PCWSTR DomainName;\n            _In_ PCWSTR UserName;\n            _In_ PCWSTR Password;\n            _In_opt_ ULONG LogonType;\n            _In_opt_ ULONG LogonFlags;\n        };\n        _In_ HANDLE ProcessIdWithToken; // use PH_CREATE_PROCESS_USE_PROCESS_TOKEN\n        _In_ ULONG SessionIdWithToken; // use PH_CREATE_PROCESS_USE_SESSION_TOKEN\n    };\n} PH_CREATE_PROCESS_AS_USER_INFO, *PPH_CREATE_PROCESS_AS_USER_INFO;\n\n#define PH_CREATE_PROCESS_USE_PROCESS_TOKEN 0x1000\n#define PH_CREATE_PROCESS_USE_SESSION_TOKEN 0x2000\n#define PH_CREATE_PROCESS_USE_LINKED_TOKEN 0x10000\n#define PH_CREATE_PROCESS_SET_SESSION_ID 0x20000\n#define PH_CREATE_PROCESS_WITH_PROFILE 0x40000\n#define PH_CREATE_PROCESS_SET_UIACCESS 0x80000\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessAsUser(\n    _In_ PPH_CREATE_PROCESS_AS_USER_INFO Information,\n    _In_ ULONG Flags,\n    _In_opt_ PVOID StartupInfo,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFilterTokenForLimitedUser(\n    _In_ HANDLE TokenHandle,\n    _Out_ PHANDLE NewTokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSecurityDescriptorAsString(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PPH_STRING* SecurityDescriptorString\n    );\n\nPHLIBAPI\nPSECURITY_DESCRIPTOR\nNTAPI\nPhGetSecurityDescriptorFromString(\n    _In_ PCWSTR SecurityDescriptorString\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetObjectSecurityDescriptorAsString(\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING* SecurityDescriptorString\n    );\n\ntypedef struct _SHELLEXECUTEINFOW SHELLEXECUTEINFOW, *PSHELLEXECUTEINFOW;\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShellExecuteWin32(\n    _Inout_ PSHELLEXECUTEINFOW ExecInfo\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhShellExecute(\n    _In_opt_ HWND WindowHandle,\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR Parameters\n    );\n\n#define PH_SHELL_EXECUTE_DEFAULT 0x0\n#define PH_SHELL_EXECUTE_ADMIN 0x1\n#define PH_SHELL_EXECUTE_PUMP_MESSAGES 0x2\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhShellExecuteEx(\n    _In_opt_ HWND WindowHandle,\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR Parameters,\n    _In_opt_ PCWSTR Directory,\n    _In_ LONG ShowWindowType,\n    _In_ ULONG Flags,\n    _In_opt_ ULONG Timeout,\n    _Out_opt_ PHANDLE ProcessHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhShellExploreFile(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR FileName\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhShellProperties(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR FileName\n    );\n\ntypedef struct _NOTIFYICONDATAW NOTIFYICONDATAW, *PNOTIFYICONDATAW;\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShellNotifyIcon(\n    _In_ ULONG Message,\n    _In_ PNOTIFYICONDATAW NotifyIconData\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhShellGetKnownFolderPath(\n    _In_ PCGUID rfid, // REFKNOWNFOLDERID\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Outptr_ PWSTR* FolderPath\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhShellGetKnownFolderItem(\n    _In_ PCGUID rfid, // REFKNOWNFOLDERID\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _In_ REFIID riid,\n    _Outptr_ PVOID* ppv\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhExpandKeyName(\n    _In_ PPH_STRING KeyName,\n    _In_ BOOLEAN Computer\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhQueryRegistryString(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName\n    );\n\nFORCEINLINE\nPPH_STRING\nNTAPI\nPhQueryRegistryStringZ(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName\n    )\n{\n    PH_STRINGREF valueName;\n\n    PhInitializeStringRef(&valueName, ValueName);\n\n    return PhQueryRegistryString(KeyHandle, &valueName);\n}\n\nPHLIBAPI\nULONG\nNTAPI\nPhQueryRegistryUlong(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName\n    );\n\nFORCEINLINE\nULONG\nNTAPI\nPhQueryRegistryUlongZ(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName\n    )\n{\n    PH_STRINGREF valueName;\n\n    PhInitializeStringRef(&valueName, ValueName);\n\n    return PhQueryRegistryUlong(KeyHandle, &valueName);\n}\n\nPHLIBAPI\nULONG64\nNTAPI\nPhQueryRegistryUlong64(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName\n    );\n\nFORCEINLINE\nULONG64\nNTAPI\nPhQueryRegistryUlong64Z(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName\n    )\n{\n    PH_STRINGREF valueName;\n\n    PhInitializeStringRef(&valueName, ValueName);\n\n    return PhQueryRegistryUlong64(KeyHandle, &valueName);\n}\n\ntypedef struct _PH_FLAG_MAPPING\n{\n    ULONG Flag1;\n    ULONG Flag2;\n} PH_FLAG_MAPPING, *PPH_FLAG_MAPPING;\n\nPHLIBAPI\nVOID\nNTAPI\nPhMapFlags1(\n    _Inout_ PULONG Value2,\n    _In_ ULONG Value1,\n    _In_ const PH_FLAG_MAPPING *Mappings,\n    _In_ ULONG NumberOfMappings\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhMapFlags2(\n    _Inout_ PULONG Value1,\n    _In_ ULONG Value2,\n    _In_ const PH_FLAG_MAPPING *Mappings,\n    _In_ ULONG NumberOfMappings\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateOpenFileDialog(\n    VOID\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateSaveFileDialog(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeFileDialog(\n    _In_ PVOID FileDialog\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShowFileDialog(\n    _In_opt_ HWND WindowHandle,\n    _In_ PVOID FileDialog\n    );\n\n#define PH_FILEDIALOG_CREATEPROMPT 0x1\n#define PH_FILEDIALOG_PATHMUSTEXIST 0x2 // default both\n#define PH_FILEDIALOG_FILEMUSTEXIST 0x4 // default open\n#define PH_FILEDIALOG_SHOWHIDDEN 0x8\n#define PH_FILEDIALOG_NODEREFERENCELINKS 0x10\n#define PH_FILEDIALOG_OVERWRITEPROMPT 0x20 // default save\n#define PH_FILEDIALOG_DEFAULTEXPANDED 0x40\n#define PH_FILEDIALOG_STRICTFILETYPES 0x80\n#define PH_FILEDIALOG_PICKFOLDERS 0x100\n#define PH_FILEDIALOG_NOPATHVALIDATE 0x200\n#define PH_FILEDIALOG_DONTADDTORECENT 0x400\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetFileDialogOptions(\n    _In_ PVOID FileDialog\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetFileDialogOptions(\n    _In_ PVOID FileDialog,\n    _In_ ULONG Options\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetFileDialogFilterIndex(\n    _In_ PVOID FileDialog\n    );\n\ntypedef struct _PH_FILETYPE_FILTER\n{\n    PWSTR Name;\n    PWSTR Filter;\n} PH_FILETYPE_FILTER, *PPH_FILETYPE_FILTER;\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetFileDialogFilter(\n    _In_ PVOID FileDialog,\n    _In_ PPH_FILETYPE_FILTER Filters,\n    _In_ ULONG NumberOfFilters\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetFileDialogFileName(\n    _In_ PVOID FileDialog\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetFileDialogFileName(\n    _In_ PVOID FileDialog,\n    _In_ PCWSTR FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhIsExecutablePacked(\n    _In_ PPH_STRING FileName,\n    _Out_ PBOOLEAN IsPacked,\n    _Out_opt_ PULONG NumberOfModules,\n    _Out_opt_ PULONG NumberOfFunctions\n    );\n\n/**\n * Image Coherency Scan Type\n */\ntypedef enum _PH_IMGCOHERENCY_SCAN_TYPE\n{\n    /**\n    * Quick scan of the image coherency\n    * - Image header information\n    * - A few pages of each executable section\n    * - Scans a few pages at entry point if it exists and was missed due to previous note\n    * - .NET manifests if appropriate\n    */\n    PhImageCoherencyQuick,\n\n    /**\n    * Normal scan of the image coherency\n    * - Image header information\n    * - Up to 40Mib of each executable section\n    * - Scans a few pages at entry point if it exists and was missed due to previous note\n    * - .NET manifests if appropriate\n    */\n    PhImageCoherencyNormal,\n\n    /**\n    * Full scan of the image coherency\n    * - Image header information\n    * - Complete scan of all executable sections, this will include the entry point\n    * - .NET manifests if appropriate\n    * - Scans for code caves in tail of mapped sections (virtual mapping > size on disk)\n    */\n    PhImageCoherencyFull,\n\n    /**\n     * Fast scan of the image coherency\n     * - only checks for shared original pages using NtQueryVirtualMemory\n     */\n    PhImageCoherencySharedOriginal,\n\n} PH_IMAGE_COHERENCY_SCAN_TYPE;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessImageCoherency(\n    _In_ PPH_STRING FileName,\n    _In_ HANDLE ProcessId,\n    _In_ PH_IMAGE_COHERENCY_SCAN_TYPE Type,\n    _Out_ PFLOAT ImageCoherency\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessModuleImageCoherency(\n    _In_ PPH_STRING FileName,\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID ImageBaseAddress,\n    _In_ SIZE_T ImageSize,\n    _In_ BOOLEAN IsKernelModule,\n    _In_ PH_IMAGE_COHERENCY_SCAN_TYPE Type,\n    _Out_ PFLOAT ImageCoherency\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCheckImagePagesForTampering(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T SizeOfImage,\n    _Out_ PSIZE_T NumberOfPages,\n    _Out_ PSIZE_T NumberOfTamperedPages\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhCrc32(\n    _In_ ULONG Crc,\n    _In_reads_(Length) PUCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhCrc32C(\n    _In_ ULONG Crc,\n    _In_reads_(Length) PVOID Buffer,\n    _In_ SIZE_T Length\n    );\n\ntypedef enum _PH_HASH_ALGORITHM\n{\n    Crc32HashAlgorithm,\n    Crc32CHashAlgorithm,\n    Md5HashAlgorithm,\n    Sha1HashAlgorithm,\n    Sha256HashAlgorithm\n} PH_HASH_ALGORITHM;\n\n#define PH_HASH_CRC32_LENGTH 4\n#define PH_HASH_MD5_LENGTH 16\n#define PH_HASH_SHA1_LENGTH 20\n#define PH_HASH_SHA256_LENGTH 32\n\ntypedef struct _PH_HASH_CONTEXT\n{\n    PH_HASH_ALGORITHM Algorithm;\n    ULONG Context[64];\n} PH_HASH_CONTEXT, *PPH_HASH_CONTEXT;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeHash(\n    _Out_ PPH_HASH_CONTEXT Context,\n    _In_ PH_HASH_ALGORITHM Algorithm\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUpdateHash(\n    _In_ PPH_HASH_CONTEXT Context,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFinalHash(\n    _In_ PPH_HASH_CONTEXT Context,\n    _Out_writes_bytes_(HashLength) PVOID Hash,\n    _In_ ULONG HashLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n/**\n * Completes a hash operation and returns the result as a hexadecimal string.\n *\n * \\param Context The hash context.\n * \\param HashString A variable which receives the resulting hexadecimal string.\n * \\return An NTSTATUS value indicating success or failure.\n * \\remarks The returned string contains the SHA-256 hash encoded as hexadecimal\n * characters. The caller is responsible for freeing the string.\n */\nFORCEINLINE\nNTSTATUS\nNTAPI\nPhFinalHashString(\n    _In_ PPH_HASH_CONTEXT Context,\n    _Out_ PPH_STRING* HashString\n    )\n{\n    NTSTATUS status;\n    UCHAR hash[PH_HASH_SHA256_LENGTH];\n\n    status = PhFinalHash(Context, hash, sizeof(hash), NULL);\n\n    if (NT_SUCCESS(status))\n    {\n        *HashString = PhBufferToHexString(hash, sizeof(hash));\n    }\n\n    return status;\n}\n\ntypedef enum _PH_COMMAND_LINE_OPTION_TYPE\n{\n    NoArgumentType,\n    MandatoryArgumentType,\n    OptionalArgumentType\n} PH_COMMAND_LINE_OPTION_TYPE, *PPH_COMMAND_LINE_OPTION_TYPE;\n\ntypedef struct _PH_COMMAND_LINE_OPTION\n{\n    ULONG Id;\n    PCWSTR Name;\n    PH_COMMAND_LINE_OPTION_TYPE Type;\n} PH_COMMAND_LINE_OPTION, *PPH_COMMAND_LINE_OPTION;\ntypedef const PH_COMMAND_LINE_OPTION* PCPH_COMMAND_LINE_OPTION;\n\ntypedef _Function_class_(PH_COMMAND_LINE_CALLBACK)\nBOOLEAN NTAPI PH_COMMAND_LINE_CALLBACK(\n    _In_opt_ PCPH_COMMAND_LINE_OPTION Option,\n    _In_opt_ PPH_STRING Value,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_COMMAND_LINE_CALLBACK *PPH_COMMAND_LINE_CALLBACK;\n\n#define PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS 0x1\n#define PH_COMMAND_LINE_IGNORE_FIRST_PART 0x2\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhParseCommandLinePart(\n    _In_ PCPH_STRINGREF CommandLine,\n    _Inout_ PULONG_PTR Index\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhParseCommandLine(\n    _In_ PCPH_STRINGREF CommandLine,\n    _In_opt_ PCPH_COMMAND_LINE_OPTION Options,\n    _In_ ULONG NumberOfOptions,\n    _In_ ULONG Flags,\n    _In_ PPH_COMMAND_LINE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhEscapeCommandLinePart(\n    _In_ PCPH_STRINGREF String\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhParseCommandLineFuzzy(\n    _In_ PCPH_STRINGREF CommandLine,\n    _Out_ PPH_STRINGREF FileName,\n    _Out_ PPH_STRINGREF Arguments,\n    _Out_opt_ PPH_STRING *FullFileName\n    );\n\nPHLIBAPI\nPPH_LIST\nNTAPI\nPhCommandLineToList(\n    _In_ PCWSTR CommandLine\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhCommandLineQuoteSpaces(\n    _In_ PCPH_STRINGREF CommandLine\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhSearchFilePath(\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR Extension\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhCreateCacheFile(\n    _In_ BOOLEAN PortableDirectory,\n    _In_ PPH_STRING FileName,\n    _In_ BOOLEAN NativeFileName\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteCacheFile(\n    _In_ PPH_STRING FileName,\n    _In_ BOOLEAN NativeFileName\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhClearCacheDirectory(\n    _In_ BOOLEAN PortableDirectory\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhGetNamespaceHandle(\n    VOID\n    );\n\nPHLIBAPI\nHWND\nNTAPI\nPhHungWindowFromGhostWindow(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileData(\n    _In_ HANDLE FileHandle,\n    _Out_ PVOID* Buffer,\n    _Out_ PULONG BufferLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileText(\n    _Out_ PVOID* String,\n    _In_ HANDLE FileHandle,\n    _In_ BOOLEAN Unicode\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFileReadAllText(\n    _Out_ PVOID* String,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN Unicode\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFileReadAllTextWin32(\n    _Out_ PVOID* String,\n    _In_ PCWSTR FileName,\n    _In_ BOOLEAN Unicode\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhGetClassObjectDllBase(\n    _In_ PVOID DllBase,\n    _In_ REFCLSID Rclsid,\n    _In_ REFIID Riid,\n    _Out_ PVOID * Ppv\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhGetClassObject(\n    _In_ PCWSTR DllName,\n    _In_ REFCLSID Rclsid,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Ppv\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhGetActivationFactory(\n    _In_ PCWSTR DllName,\n    _In_ PCWSTR RuntimeClass,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Ppv\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhActivateInstance(\n    _In_ PCWSTR DllName,\n    _In_ PCWSTR RuntimeClass,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Ppv\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDelayExecution(\n    _In_ ULONG Milliseconds\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDelayExecutionEx(\n    _In_ BOOLEAN Alertable,\n    _In_ PLARGE_INTEGER DelayInterval\n    );\n\n//\n// Stopwatch\n//\n\n/**\n * Represents a high‑resolution stopwatch.\n */\ntypedef struct _PH_STOPWATCH\n{\n    LARGE_INTEGER StartCounter;\n    LARGE_INTEGER EndCounter;\n    LARGE_INTEGER Frequency;\n} PH_STOPWATCH, *PPH_STOPWATCH;\n\n/**\n * Initializes a stopwatch structure.\n * \\param Stopwatch The stopwatch to initialize.\n */\nFORCEINLINE\nVOID\nPhInitializeStopwatch(\n    _Out_ PPH_STOPWATCH Stopwatch\n    )\n{\n    Stopwatch->StartCounter.QuadPart = 0;\n    Stopwatch->EndCounter.QuadPart = 0;\n}\n\n/**\n * Starts a stopwatch.\n *\n * \\param Stopwatch The stopwatch to start.\n * \\remarks The performance counter frequency is also queried and stored.\n */\nFORCEINLINE\nVOID\nPhStartStopwatch(\n    _Inout_ PPH_STOPWATCH Stopwatch\n    )\n{\n    PhQueryPerformanceCounter(&Stopwatch->StartCounter);\n    PhQueryPerformanceFrequency(&Stopwatch->Frequency);\n}\n\n/**\n * Stops a stopwatch.\n *\n * \\param Stopwatch The stopwatch to stop.\n */\nFORCEINLINE\nVOID\nPhStopStopwatch(\n    _Inout_ PPH_STOPWATCH Stopwatch\n    )\n{\n    PhQueryPerformanceCounter(&Stopwatch->EndCounter);\n}\n\n/**\n * Retrieves the elapsed time of a stopwatch in milliseconds.\n *\n * \\param Stopwatch The stopwatch.\n * \\return The elapsed time, in milliseconds.\n */\nFORCEINLINE\nULONG\nPhGetMillisecondsStopwatch(\n    _In_ PPH_STOPWATCH Stopwatch\n    )\n{\n    LARGE_INTEGER elapsedMilliseconds;\n\n    elapsedMilliseconds.QuadPart = Stopwatch->EndCounter.QuadPart - Stopwatch->StartCounter.QuadPart;\n    elapsedMilliseconds.QuadPart *= 1000;\n    elapsedMilliseconds.QuadPart /= Stopwatch->Frequency.QuadPart;\n\n    return (ULONG)elapsedMilliseconds.QuadPart;\n}\n\n/**\n * Retrieves the elapsed time of a stopwatch in microseconds.\n *\n * \\param Stopwatch The stopwatch.\n * \\return The elapsed time, in microseconds.\n */\nFORCEINLINE\nDOUBLE\nPhGetMicrosecondsStopwatch(\n    _In_ PPH_STOPWATCH Stopwatch\n    )\n{\n    DOUBLE elapsedMicroseconds;\n\n    // Convert to microseconds before dividing by ticks-per-second.\n    elapsedMicroseconds = (DOUBLE)(Stopwatch->EndCounter.QuadPart - Stopwatch->StartCounter.QuadPart);\n    elapsedMicroseconds *= 1000000.0;\n    elapsedMicroseconds /= (DOUBLE)Stopwatch->Frequency.QuadPart;\n\n    return elapsedMicroseconds;\n}\n\n/**\n * Retrieves the elapsed time of a stopwatch in nanoseconds.\n *\n * \\param Stopwatch The stopwatch.\n * \\return The elapsed time, in nanoseconds.\n */\nFORCEINLINE\nDOUBLE\nPhGetNanosecondsStopwatch(\n    _In_ PPH_STOPWATCH Stopwatch\n    )\n{\n    DOUBLE elapsedNanoseconds;\n\n    // Convert to nanoseconds before dividing by ticks-per-second.\n    elapsedNanoseconds = (DOUBLE)(Stopwatch->EndCounter.QuadPart - Stopwatch->StartCounter.QuadPart);\n    elapsedNanoseconds *= 1000000000.0;\n    elapsedNanoseconds /= (DOUBLE)Stopwatch->Frequency.QuadPart;\n\n    return elapsedNanoseconds;\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhApiSetResolveToHost(\n    _In_ PAPI_SET_NAMESPACE Schema,\n    _In_ PCPH_STRINGREF ApiSetName,\n    _In_opt_ PCPH_STRINGREF ParentName,\n    _Out_ PPH_STRINGREF HostBinary\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhCreateProcessAsInteractiveUser(\n    _In_ PCWSTR CommandLine,\n    _In_ PCWSTR CurrentDirectory\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessClone(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessReflection(\n    _Out_ PPROCESS_REFLECTION_INFORMATION ReflectionInformation,\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeProcessReflection(\n    _In_ PPROCESS_REFLECTION_INFORMATION ReflectionInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessSnapshot(\n    _Out_ PHANDLE SnapshotHandle,\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeProcessSnapshot(\n    _In_ HANDLE SnapshotHandle,\n    _In_ HANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessRedirection(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ PCPH_STRINGREF CommandLine,\n    _In_opt_ PCPH_STRINGREF CommandInput,\n    _Out_opt_ PPH_STRING* CommandOutput\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeProcThreadAttributeList(\n    _Out_ PPROC_THREAD_ATTRIBUTE_LIST* AttributeList,\n    _In_ ULONG AttributeCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteProcThreadAttributeList(\n    _In_ PPROC_THREAD_ATTRIBUTE_LIST AttributeList\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUpdateProcThreadAttribute(\n    _In_ PPROC_THREAD_ATTRIBUTE_LIST AttributeList,\n    _In_ ULONG_PTR Attribute,\n    _In_ PVOID Buffer,\n    _In_ SIZE_T BufferLength\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetActiveComputerName(\n    VOID\n    );\n\n#include <devpropdef.h>\n#include <devquery.h>\n\ntypedef enum _DEV_OBJECT_TYPE DEV_OBJECT_TYPE, *PDEV_OBJECT_TYPE;\ntypedef enum _DEV_QUERY_FLAGS DEV_QUERY_FLAGS, *PDEV_QUERY_FLAGS;\ntypedef struct _DEVPROPCOMPKEY DEVPROPCOMPKEY, *PDEVPROPCOMPKEY;\ntypedef struct _DEVPROP_FILTER_EXPRESSION DEVPROP_FILTER_EXPRESSION, *PDEVPROP_FILTER_EXPRESSION;\ntypedef struct _DEV_OBJECT DEV_OBJECT, *PDEV_OBJECT;\n\nPHLIBAPI\nPDEVPROPERTY\nNTAPI\nPhDevFindProperty(\n    _In_ PDEVPROPKEY Key,\n    _In_ ULONG Store,\n    _In_ ULONG PropertiesCount,\n    _In_reads_(PropertiesCount) PDEVPROPERTY Properties\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhDevGetObjects(\n    _In_ DEV_OBJECT_TYPE ObjectType,\n    _In_ DEV_QUERY_FLAGS QueryFlags,\n    _In_ ULONG RequestedPropertiesCount,\n    _In_reads_opt_(RequestedPropertiesCount) const DEVPROPCOMPKEY* RequestedProperties,\n    _In_ ULONG FilterExpressionCount,\n    _In_reads_opt_(FilterExpressionCount) const DEVPROP_FILTER_EXPRESSION* FilterExpressions,\n    _Out_ PULONG ObjectCount,\n    _Outptr_result_buffer_(*ObjectCount) const DEV_OBJECT** Objects\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDevFreeObjects(\n    _In_ ULONG ObjectCount,\n    _In_reads_(ObjectCount) const DEV_OBJECT* Objects\n    );\n\ntypedef GUID  DEVPROPGUID, *PDEVPROPGUID;\ntypedef ULONG DEVPROPID,   *PDEVPROPID;\ntypedef struct _DEVPROPKEY DEVPROPKEY, *PDEVPROPKEY;\ntypedef enum _DEVPROPSTORE DEVPROPSTORE, *PDEVPROPSTORE;\ntypedef ULONG DEVPROPTYPE, *PDEVPROPTYPE;\ntypedef struct _DEVPROPCOMPKEY DEVPROPCOMPKEY, *PDEVPROPCOMPKEY;\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhDevGetObjectProperties(\n    _In_ DEV_OBJECT_TYPE ObjectType,\n    _In_ PCWSTR ObjectId,\n    _In_ DEV_QUERY_FLAGS QueryFlags,\n    _In_ ULONG RequestedPropertiesCount,\n    _In_reads_(RequestedPropertiesCount) const DEVPROPCOMPKEY* RequestedProperties,\n    _Out_ PULONG PropertiesCount,\n    _Outptr_result_buffer_(*PropertiesCount) const DEVPROPERTY** Properties\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDevFreeObjectProperties(\n    _In_ ULONG PropertiesCount,\n    _In_reads_(PropertiesCount) const DEVPROPERTY* Properties\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhDevCreateObjectQuery(\n    _In_ DEV_OBJECT_TYPE ObjectType,\n    _In_ DEV_QUERY_FLAGS QueryFlags,\n    _In_ ULONG RequestedPropertiesCount,\n    _In_reads_opt_(RequestedPropertiesCount) const DEVPROPCOMPKEY* RequestedProperties,\n    _In_ ULONG FilterExpressionCount,\n    _In_reads_opt_(FilterExpressionCount) const DEVPROP_FILTER_EXPRESSION* Filter,\n    _In_ PDEV_QUERY_RESULT_CALLBACK Callback,\n    _In_opt_ PVOID Context,\n    _Out_ PHDEVQUERY DevQuery\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDevCloseObjectQuery(\n    _In_ HDEVQUERY QueryHandle\n    );\n\n#define PH_DEVKEY_HARDWARE        (0x00000000)\n#define PH_DEVKEY_SOFTWARE        (0x00000001)\n#define PH_DEVKEY_USER            (0x00000100)\n#define PH_DEVKEY_CONFIG          (0x00000200)\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDevOpenObjectKey(\n    _In_ PPH_STRING DeviceInstanceId,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG Flags,\n    _Out_ PHANDLE KeyHandle\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhTaskbarListCreate(\n    _Out_ PHANDLE TaskbarHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhTaskbarListDestroy(\n    _In_ HANDLE TaskbarHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhTaskbarListSetProgressValue(\n    _In_ HANDLE TaskbarHandle,\n    _In_ HWND WindowHandle,\n    _In_ ULONGLONG Completed,\n    _In_ ULONGLONG Total\n    );\n\n#define PH_TBLF_NOPROGRESS 0x1\n#define PH_TBLF_INDETERMINATE 0x2\n#define PH_TBLF_NORMAL 0x4\n#define PH_TBLF_ERROR 0x8\n#define PH_TBLF_PAUSED 0x10\n\nPHLIBAPI\nVOID\nNTAPI\nPhTaskbarListSetProgressState(\n    _In_ HANDLE TaskbarHandle,\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhTaskbarListSetOverlayIcon(\n    _In_ HANDLE TaskbarHandle,\n    _In_ HWND WindowHandle,\n    _In_opt_ HICON IconHandle,\n    _In_opt_ PCWSTR IconDescription\n    );\n\n/**\n * Adds an offset to a pointer with overflow protection.\n *\n * \\param Pointer The pointer to modify.\n * \\param Offset The number of bytes to add.\n * \\return TRUE if the offset was successfully added, otherwise FALSE.\n * \\remarks The function fails if the addition would wrap past the end of the\n * address space.\n */\nFORCEINLINE\nBOOLEAN\nPhPtrAddOffset(\n    _Inout_ PVOID* Pointer,\n    _In_ SIZE_T Offset\n    )\n{\n    PVOID pointer;\n\n    pointer = PTR_ADD_OFFSET(*Pointer, Offset);\n    if (pointer < *Pointer)\n        return FALSE;\n\n    *Pointer = pointer;\n    return TRUE;\n}\n\n/**\n * Advances a pointer by a specified offset while ensuring it does not exceed a limit.\n *\n * \\param Pointer The pointer to modify.\n * \\param EndPointer The end boundary that must not be crossed.\n * \\param Offset The number of bytes to advance.\n * \\return TRUE if the pointer was successfully advanced, otherwise FALSE.\n * \\remarks The function fails if the addition overflows or if the resulting\n * pointer would be greater than or equal to EndPointer.\n */\nFORCEINLINE\nBOOLEAN\nPhPtrAdvance(\n    _Inout_ PVOID* Pointer,\n    _In_ PVOID EndPointer,\n    _In_ SIZE_T Offset\n    )\n{\n    PVOID pointer;\n\n    pointer = *Pointer;\n    if (!PhPtrAddOffset(&pointer, Offset))\n        return FALSE;\n\n    if (pointer >= EndPointer)\n        return FALSE;\n\n    *Pointer = pointer;\n    return TRUE;\n}\n\ntypedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;\ntypedef enum _D3DKMT_VIDPNSOURCEOWNER_TYPE D3DKMT_VIDPNSOURCEOWNER_TYPE;\ntypedef struct _D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP, *PD3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP;\n\nBOOLEAN PhIsDirectXRunningFullScreen(\n    VOID\n    );\n\nNTSTATUS PhRestoreFromDirectXRunningFullScreen(\n    _In_ HANDLE ProcessHandle\n    );\n\nNTSTATUS PhQueryDirectXExclusiveOwnership(\n    _Inout_ PD3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP QueryExclusiveOwnership\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEndWindowSession(\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nPCPH_STRINGREF\nNTAPI\nPhGetLuidKnownTypeToString(\n    _In_ PLUID Luid\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/provider.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2021-2022\n *\n */\n\n#ifndef _PH_PROVIDER_H\n#define _PH_PROVIDER_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(DEBUG)\nextern PPH_LIST PhDbgProviderList;\nextern PH_QUEUED_LOCK PhDbgProviderListLock;\n#endif\n\ntypedef enum _PH_PROVIDER_THREAD_STATE\n{\n    ProviderThreadRunning,\n    ProviderThreadStopped,\n    ProviderThreadStopping\n} PH_PROVIDER_THREAD_STATE;\n\ntypedef _Function_class_(PH_PROVIDER_FUNCTION)\nVOID NTAPI PH_PROVIDER_FUNCTION(\n    _In_opt_ PVOID Object\n    );\ntypedef PH_PROVIDER_FUNCTION *PPH_PROVIDER_FUNCTION;\n\ntypedef struct _PH_PROVIDER_THREAD *PPH_PROVIDER_THREAD;\n\ntypedef struct _PH_PROVIDER_REGISTRATION\n{\n    LIST_ENTRY ListEntry;\n    PPH_PROVIDER_THREAD ProviderThread;\n    PPH_PROVIDER_FUNCTION Function;\n    PVOID Object;\n    ULONG RunId;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Enabled : 1;\n            ULONG Unregistering : 1;\n            ULONG Boosting : 1;\n            ULONG Spare : 29;\n        };\n    };\n    PH_RUNDOWN_PROTECT RundownProtect;\n} PH_PROVIDER_REGISTRATION, *PPH_PROVIDER_REGISTRATION;\n\ntypedef struct _PH_PROVIDER_THREAD\n{\n    HANDLE ThreadHandle;\n    HANDLE TimerHandle;\n    ULONG Interval;\n    PH_PROVIDER_THREAD_STATE State;\n\n    PH_QUEUED_LOCK Lock;\n    LIST_ENTRY ListHead;\n    ULONG BoostCount;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG UseHighResolution : 1;\n            ULONG Spare : 31;\n        };\n    };\n} PH_PROVIDER_THREAD, *PPH_PROVIDER_THREAD;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeProviderThread(\n    _Out_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ ULONG Interval\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhStartProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhStopProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetIntervalProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ LONG Interval\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRegisterProvider(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ PPH_PROVIDER_FUNCTION Function,\n    _In_opt_ PVOID Object,\n    _Out_ PPH_PROVIDER_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUnregisterProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhBoostProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration,\n    _Out_opt_ PULONG FutureRunId\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetRunIdProvider(\n    _In_ PPH_PROVIDER_REGISTRATION Registration\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetEnabledProvider(\n    _In_ PPH_PROVIDER_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetEnabledProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration,\n    _In_ BOOLEAN Enabled\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetHighResolutionProvider(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ BOOLEAN UseHighResolution\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/queuedlock.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n#ifndef _PH_QUEUEDLOCK_H\n#define _PH_QUEUEDLOCK_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_QUEUED_LOCK_OWNED ((ULONG_PTR)0x1)\n#define PH_QUEUED_LOCK_OWNED_SHIFT 0\n#define PH_QUEUED_LOCK_WAITERS ((ULONG_PTR)0x2)\n\n// Valid only if Waiters = 0\n#define PH_QUEUED_LOCK_SHARED_INC ((ULONG_PTR)0x4)\n#define PH_QUEUED_LOCK_SHARED_SHIFT 2\n\n// Valid only if Waiters = 1\n#define PH_QUEUED_LOCK_TRAVERSING ((ULONG_PTR)0x4)\n#define PH_QUEUED_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8)\n\n#define PH_QUEUED_LOCK_FLAGS ((ULONG_PTR)0xf)\n\n#define PhGetQueuedLockSharedOwners(Value) \\\n    ((ULONG_PTR)(Value) >> PH_QUEUED_LOCK_SHARED_SHIFT)\n#define PhGetQueuedLockWaitBlock(Value) \\\n    ((PPH_QUEUED_WAIT_BLOCK)((ULONG_PTR)(Value) & ~PH_QUEUED_LOCK_FLAGS))\n\ntypedef struct _PH_QUEUED_LOCK\n{\n    ULONG_PTR Value;\n} PH_QUEUED_LOCK, *PPH_QUEUED_LOCK;\n\n#define PH_QUEUED_LOCK_INIT { 0 }\n\n#define PH_QUEUED_WAITER_EXCLUSIVE 0x1\n#define PH_QUEUED_WAITER_SPINNING 0x2\n#define PH_QUEUED_WAITER_SPINNING_SHIFT 1\n\ntypedef struct DECLSPEC_ALIGN(16) _PH_QUEUED_WAIT_BLOCK\n{\n    /** A pointer to the next wait block, i.e. the wait block pushed onto the list before this one. */\n    struct _PH_QUEUED_WAIT_BLOCK *Next;\n    /**\n     * A pointer to the previous wait block, i.e. the wait block pushed onto the list after this\n     * one.\n     */\n    struct _PH_QUEUED_WAIT_BLOCK *Previous;\n    /** A pointer to the last wait block, i.e. the first waiter pushed onto the list. */\n    struct _PH_QUEUED_WAIT_BLOCK *Last;\n\n    ULONG SharedOwners;\n    ULONG Flags;\n} PH_QUEUED_WAIT_BLOCK, *PPH_QUEUED_WAIT_BLOCK;\n\nstatic_assert((sizeof(PH_QUEUED_WAIT_BLOCK) % MEMORY_ALLOCATION_ALIGNMENT) == 0, \"PH_QUEUED_WAIT_BLOCK alignment invalid\");\n\nNTSTATUS PhQueuedLockInitialization(\n    VOID\n    );\n\n// Queued lock\n\nFORCEINLINE\nVOID\nPhInitializeQueuedLock(\n    _Out_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    QueuedLock->Value = 0;\n}\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfAcquireQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    );\n\n_Acquires_exclusive_lock_(*QueuedLock)\nFORCEINLINE\nVOID\nPhAcquireQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    if (_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))\n    {\n        // Owned bit was already set. Slow path.\n        PhfAcquireQueuedLockExclusive(QueuedLock);\n    }\n}\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfAcquireQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    );\n\n_Acquires_shared_lock_(*QueuedLock)\nFORCEINLINE\nVOID\nPhAcquireQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    if ((ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&QueuedLock->Value,\n        (PVOID)(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC),\n        (PVOID)NULL\n        ) != 0)\n    {\n        PhfAcquireQueuedLockShared(QueuedLock);\n    }\n}\n\n_When_(return != 0, _Acquires_exclusive_lock_(*QueuedLock))\nFORCEINLINE\nBOOLEAN\nPhTryAcquireQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))\n    {\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    );\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfWakeForReleaseQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    );\n\n_Releases_exclusive_lock_(*QueuedLock)\nFORCEINLINE\nVOID\nPhReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n\n    value = (ULONG_PTR)_InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_OWNED);\n\n    if ((value & (PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_TRAVERSING)) == PH_QUEUED_LOCK_WAITERS)\n    {\n        PhfWakeForReleaseQueuedLock(QueuedLock, value - PH_QUEUED_LOCK_OWNED);\n    }\n}\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    );\n\n_Releases_shared_lock_(*QueuedLock)\nFORCEINLINE\nVOID\nPhReleaseQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n\n    value = PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC;\n\n    if ((ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&QueuedLock->Value,\n        (PVOID)NULL,\n        (PVOID)value\n        ) != value)\n    {\n        PhfReleaseQueuedLockShared(QueuedLock);\n    }\n}\n\nFORCEINLINE\nVOID\nPhAcquireReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    BOOLEAN owned;\n\n    MemoryBarrier();\n    owned = !!(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);\n    MemoryBarrier();\n\n    if (owned)\n    {\n        PhAcquireQueuedLockExclusive(QueuedLock);\n        PhReleaseQueuedLockExclusive(QueuedLock);\n    }\n}\n\nFORCEINLINE\nBOOLEAN\nPhTryAcquireReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    BOOLEAN owned;\n\n    // Need two memory barriers because we don't want the compiler re-ordering the following check\n    // in either direction.\n    MemoryBarrier();\n    owned = !(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);\n    MemoryBarrier();\n\n    return owned;\n}\n\n// Condition variable\n\ntypedef struct _PH_QUEUED_LOCK PH_CONDITION, *PPH_CONDITION;\n\n#define PH_CONDITION_INIT PH_QUEUED_LOCK_INIT\n\nFORCEINLINE\nVOID\nPhInitializeCondition(\n    _Out_ PPH_CONDITION Condition\n    )\n{\n    PhInitializeQueuedLock(Condition);\n}\n\n#define PhPulseCondition PhfPulseCondition\nPHLIBAPI\nVOID\nFASTCALL\nPhfPulseCondition(\n    _Inout_ PPH_CONDITION Condition\n    );\n\n#define PhPulseAllCondition PhfPulseAllCondition\nPHLIBAPI\nVOID\nFASTCALL\nPhfPulseAllCondition(\n    _Inout_ PPH_CONDITION Condition\n    );\n\n#define PhWaitForCondition PhfWaitForCondition\nPHLIBAPI\nVOID\nFASTCALL\nPhfWaitForCondition(\n    _Inout_ PPH_CONDITION Condition,\n    _Inout_ PPH_QUEUED_LOCK Lock,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#define PH_CONDITION_WAIT_QUEUED_LOCK 0x1\n#define PH_CONDITION_WAIT_CRITICAL_SECTION 0x2\n#define PH_CONDITION_WAIT_FAST_LOCK 0x4\n#define PH_CONDITION_WAIT_LOCK_TYPE_MASK 0xfff\n\n#define PH_CONDITION_WAIT_SHARED 0x1000\n#define PH_CONDITION_WAIT_SPIN 0x2000\n\n#define PhWaitForConditionEx PhfWaitForConditionEx\nPHLIBAPI\nVOID\nFASTCALL\nPhfWaitForConditionEx(\n    _Inout_ PPH_CONDITION Condition,\n    _Inout_ PVOID Lock,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n// Wake event\n\ntypedef struct _PH_QUEUED_LOCK PH_WAKE_EVENT, *PPH_WAKE_EVENT;\n\n#define PH_WAKE_EVENT_INIT PH_QUEUED_LOCK_INIT\n\nFORCEINLINE\nVOID\nPhInitializeWakeEvent(\n    _Out_ PPH_WAKE_EVENT WakeEvent\n    )\n{\n    PhInitializeQueuedLock(WakeEvent);\n}\n\n#define PhQueueWakeEvent PhfQueueWakeEvent\nPHLIBAPI\nVOID\nFASTCALL\nPhfQueueWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    );\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfSetWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    );\n\nFORCEINLINE\nVOID\nPhSetWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    )\n{\n    // The wake event is similar to a synchronization event in that it does not have thread-safe\n    // pulsing; we can simply skip the function call if there's nothing to wake. However, if we're\n    // cancelling a wait (WaitBlock != NULL) we need to make the call.\n\n    if (WakeEvent->Value || WaitBlock)\n        PhfSetWakeEvent(WakeEvent, WaitBlock);\n}\n\n#define PhWaitForWakeEvent PhfWaitForWakeEvent\nPHLIBAPI\nNTSTATUS\nFASTCALL\nPhfWaitForWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock,\n    _In_ BOOLEAN Spin,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/ref.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *\n */\n\n#ifndef _PH_REF_H\n#define _PH_REF_H\n\nEXTERN_C_START\n\n//\n// Configuration\n//\n\n#define PH_OBJECT_SMALL_OBJECT_SIZE  48\n#define PH_OBJECT_SMALL_OBJECT_COUNT 512\n\n// Object type flags\n#define PH_OBJECT_TYPE_USE_FREE_LIST     0x00000001\n#define PH_OBJECT_TYPE_TRY_USE_FREE_LIST 0x00000002\n#define PH_OBJECT_TYPE_VALID_FLAGS       0x00000003\n\n//\n// Object type callbacks\n//\n\n/**\n * The delete procedure for an object type, called when an object of the type is being freed.\n *\n * \\param Object A pointer to the object being freed.\n * \\param Flags Reserved.\n */\ntypedef _Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PH_TYPE_DELETE_PROCEDURE(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\ntypedef PH_TYPE_DELETE_PROCEDURE* PPH_TYPE_DELETE_PROCEDURE;\n\ntypedef struct _PH_OBJECT_TYPE PH_OBJECT_TYPE;\ntypedef PH_OBJECT_TYPE* PPH_OBJECT_TYPE;\n\ntypedef struct _PH_QUEUED_LOCK PH_QUEUED_LOCK;\ntypedef PH_QUEUED_LOCK* PPH_QUEUED_LOCK;\n\n#ifdef DEBUG\ntypedef _Function_class_(PH_CREATE_OBJECT_HOOK)\nVOID NTAPI PH_CREATE_OBJECT_HOOK(\n    _In_ PVOID Object,\n    _In_ SIZE_T Size,\n    _In_ ULONG Flags,\n    _In_ PPH_OBJECT_TYPE ObjectType\n    );\ntypedef PH_CREATE_OBJECT_HOOK* PPH_CREATE_OBJECT_HOOK;\n#endif\n\ntypedef struct _PH_OBJECT_TYPE_PARAMETERS\n{\n    SIZE_T FreeListSize;\n    ULONG FreeListCount;\n} PH_OBJECT_TYPE_PARAMETERS, *PPH_OBJECT_TYPE_PARAMETERS;\n\ntypedef struct _PH_OBJECT_TYPE_INFORMATION\n{\n    PCWSTR Name;\n    ULONG NumberOfObjects;\n    USHORT Flags;\n    UCHAR TypeIndex;\n    UCHAR Reserved;\n} PH_OBJECT_TYPE_INFORMATION, *PPH_OBJECT_TYPE_INFORMATION;\n\nextern PPH_OBJECT_TYPE PhObjectTypeObject;\nextern PPH_OBJECT_TYPE PhAllocType;\n\n#ifdef DEBUG\nextern LIST_ENTRY PhDbgObjectListHead;\nextern PH_QUEUED_LOCK PhDbgObjectListLock;\nextern PPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook;\n#endif\n\nNTSTATUS PhRefInitialization(\n    VOID\n    );\n\n_May_raise_\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateObject(\n    _In_ SIZE_T ObjectSize,\n    _In_ PPH_OBJECT_TYPE ObjectType\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhReferenceObject(\n    _In_ PVOID Object\n    );\n\n_May_raise_\nPHLIBAPI\nPVOID\nNTAPI\nPhReferenceObjectEx(\n    _In_ PVOID Object,\n    _In_ LONG RefCount\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhReferenceObjectSafe(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDereferenceObject(\n    _In_ _Post_invalid_ PVOID Object\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDereferenceObjectDeferDelete(\n    _In_ _Post_invalid_ PVOID Object\n    );\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhDereferenceObjectEx(\n    _In_ PVOID Object,\n    _In_ LONG RefCount,\n    _In_ BOOLEAN DeferDelete\n    );\n\n/**\n * References an array of objects.\n *\n * \\param Objects An array of objects.\n * \\param NumberOfObjects The number of elements in \\a Objects.\n */\nFORCEINLINE\nVOID\nNTAPI\nPhReferenceObjects(\n    _In_reads_(NumberOfObjects) const PVOID *Objects,\n    _In_ ULONG NumberOfObjects\n    )\n{\n    for (ULONG i = 0; i < NumberOfObjects; i++)\n        PhReferenceObject(Objects[i]);\n}\n\n/**\n * Dereferences an array of objects.\n *\n * \\param Objects An array of objects.\n * \\param NumberOfObjects The number of elements in \\a Objects.\n */\nFORCEINLINE\nVOID\nNTAPI\nPhDereferenceObjects(\n    _In_reads_(NumberOfObjects) const PVOID *Objects,\n    _In_ ULONG NumberOfObjects\n    )\n{\n    for (ULONG i = 0; i < NumberOfObjects; i++)\n        PhDereferenceObject(Objects[i]);\n}\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetObjectRefCount(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nPPH_OBJECT_TYPE\nNTAPI\nPhGetObjectType(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nPPH_OBJECT_TYPE\nNTAPI\nPhCreateObjectType(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure\n    );\n\nPHLIBAPI\nPPH_OBJECT_TYPE\nNTAPI\nPhCreateObjectTypeEx(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure,\n    _In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetObjectTypeInformation(\n    _In_ PPH_OBJECT_TYPE ObjectType,\n    _Out_ PPH_OBJECT_TYPE_INFORMATION Information\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateAlloc(\n    _In_ SIZE_T Size\n    );\n\n//\n// Object reference functions\n//\n\n#if defined(__cplusplus)\n\nEXTERN_C_END\n\ntemplate<typename T>\nFORCEINLINE\nVOID\nPhSwapReference(\n    _Inout_ T** ObjectReference,\n    _In_opt_ T* NewObject\n    )\n{\n    T* oldObject;\n\n    oldObject = *ObjectReference;\n    *ObjectReference = NewObject;\n\n    if (NewObject) PhReferenceObject((PVOID)NewObject);\n    if (oldObject) PhDereferenceObject((PVOID)oldObject);\n}\n\ntemplate<typename T>\nFORCEINLINE\nVOID\nPhMoveReference(\n    _Inout_ T** ObjectReference,\n    _In_opt_ _Assume_refs_(1) T* NewObject\n    )\n{\n    T* oldObject = *ObjectReference;\n    *ObjectReference = NewObject;\n\n    if (oldObject)\n    {\n        PhDereferenceObject((PVOID)oldObject);\n    }\n}\n\ntemplate<typename T>\nFORCEINLINE\nVOID\nPhSetReference(\n    _Out_ T** ObjectReference,\n    _In_opt_ T* NewObject\n    )\n{\n    *ObjectReference = NewObject;\n\n    if (NewObject) PhReferenceObject(NewObject);\n}\n\ntemplate<typename T>\nFORCEINLINE\nVOID\nPhClearReference(\n    _Inout_ T** ObjectReference\n    )\n{\n    T* oldObject = *ObjectReference;\n    *ObjectReference = NULL;\n\n    if (oldObject)\n    {\n        PhDereferenceObject((PVOID)oldObject);\n    }\n}\n\nEXTERN_C_START\n\n#else\n\nFORCEINLINE\nVOID\nPhSwapReference(\n    _Inout_ PVOID *ObjectReference,\n    _In_opt_ PVOID NewObject\n    )\n{\n    PVOID oldObject;\n\n    oldObject = *ObjectReference;\n    *ObjectReference = NewObject;\n\n    if (NewObject) PhReferenceObject(NewObject);\n    if (oldObject) PhDereferenceObject(oldObject);\n}\n\nFORCEINLINE\nVOID\nPhMoveReference(\n    _Inout_ PVOID *ObjectReference,\n    _In_opt_ _Assume_refs_(1) PVOID NewObject\n    )\n{\n    PVOID oldObject;\n\n    oldObject = *ObjectReference;\n    *ObjectReference = NewObject;\n\n    if (oldObject) PhDereferenceObject(oldObject);\n}\n\nFORCEINLINE\nVOID\nPhSetReference(\n    _Out_ PVOID *ObjectReference,\n    _In_opt_ PVOID NewObject\n    )\n{\n    *ObjectReference = NewObject;\n\n    if (NewObject) PhReferenceObject(NewObject);\n}\n\nFORCEINLINE\nVOID\nPhClearReference(\n    _Inout_ PVOID* ObjectReference\n    )\n{\n    PVOID oldObject;\n\n    oldObject = *ObjectReference;\n    *ObjectReference = NULL;\n\n    if (oldObject) PhDereferenceObject(oldObject);\n}\n\n#endif\n\n//\n// Convenience functions\n//\n\nFORCEINLINE\nPVOID\nPhCreateObjectZero(\n    _In_ SIZE_T ObjectSize,\n    _In_ PPH_OBJECT_TYPE ObjectType\n    )\n{\n    PVOID object;\n\n    object = PhCreateObject(ObjectSize, ObjectType);\n    memset(object, 0, ObjectSize);\n\n    return object;\n}\n\n//\n// Auto-dereference pool\n//\n\n/** The size of the static array in an auto-release pool. */\n#define PH_AUTO_POOL_STATIC_SIZE 64\n/** The maximum size of the dynamic array for it to be kept after the auto-release pool is drained. */\n#define PH_AUTO_POOL_DYNAMIC_BIG_SIZE 256\n\n/**\n * An auto-dereference pool can be used for semi-automatic reference counting. Batches of objects\n * are dereferenced at a certain time.\n *\n * This object is not thread-safe and cannot be used across thread boundaries. Always store them as\n * local variables.\n */\ntypedef struct _PH_AUTO_POOL\n{\n    ULONG StaticCount;\n    PVOID StaticObjects[PH_AUTO_POOL_STATIC_SIZE];\n\n    ULONG DynamicCount;\n    ULONG DynamicAllocated;\n    PVOID *DynamicObjects;\n\n    struct _PH_AUTO_POOL *NextPool;\n} PH_AUTO_POOL, *PPH_AUTO_POOL;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeAutoPool(\n    _Out_ PPH_AUTO_POOL AutoPool\n    );\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteAutoPool(\n    _In_ _Post_invalid_ PPH_AUTO_POOL AutoPool\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDrainAutoPool(\n    _In_ PPH_AUTO_POOL AutoPool\n    );\n\n_May_raise_\nPHLIBAPI\nPVOID\nNTAPI\nPhAutoDereferenceObject(\n    _In_opt_ PVOID Object\n    );\n\n#define PH_AUTO PhAutoDereferenceObject\n#define PH_AUTO_T(Type, Object) ((Type *)PH_AUTO(Object))\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/refp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *\n */\n\n#ifndef _PH_REFP_H\n#define _PH_REFP_H\n\n#define PH_OBJECT_TYPE_TABLE_SIZE 256\n\n/** The object was allocated from the small free list. */\n#define PH_OBJECT_FROM_SMALL_FREE_LIST 0x1\n/** The object was allocated from the type free list. */\n#define PH_OBJECT_FROM_TYPE_FREE_LIST 0x2\n\n/**\n * The object header contains object manager information including the reference count of an object\n * and its type.\n */\ntypedef struct _PH_OBJECT_HEADER\n{\n    union\n    {\n        struct\n        {\n            USHORT TypeIndex;\n            UCHAR Flags;\n            UCHAR Reserved1;\n#ifdef _WIN64\n            ULONG Reserved2;\n#endif\n            union\n            {\n                LONG RefCount;\n                struct\n                {\n                    LONG SavedTypeIndex : 16;\n                    LONG SavedFlags : 8;\n                    LONG Reserved : 7;\n                    LONG DeferDelete : 1; // MUST be the high bit, so that RefCount < 0 when deferring delete\n                };\n            };\n#ifdef _WIN64\n            ULONG Reserved3;\n#endif\n        };\n        SLIST_ENTRY DeferDeleteListEntry;\n    };\n\n#ifdef DEBUG\n    PVOID StackBackTrace[16];\n    LIST_ENTRY ObjectListEntry;\n#endif\n\n    /**\n     * The body of the object. For use by the \\ref PhObjectToObjectHeader and\n     * \\ref PhObjectHeaderToObject macros.\n     */\n    QUAD_PTR Body;\n} PH_OBJECT_HEADER, *PPH_OBJECT_HEADER;\n\nstatic_assert((FIELD_OFFSET(PH_OBJECT_HEADER, Body) % MEMORY_ALLOCATION_ALIGNMENT) == 0, \"PH_OBJECT_HEADER alignment invalid\");\n\n#ifdef _WIN64\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0, \"PH_OBJECT_HEADER.TypeIndex offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2, \"PH_OBJECT_HEADER.Flags offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3, \"PH_OBJECT_HEADER.Reserved1 offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved2) == 0x4, \"PH_OBJECT_HEADER.Reserved2 offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x8, \"PH_OBJECT_HEADER.RefCount offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved3) == 0xc, \"PH_OBJECT_HEADER.Reserved3 offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0, \"PH_OBJECT_HEADER.DeferDeleteListEntry offset mismatch\");\n#if defined(DEBUG)\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0xA0, \"PH_OBJECT_HEADER.Body offset mismatch\");\n#else\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x10, \"PH_OBJECT_HEADER.Body offset mismatch\");\n#endif\n#else\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0, \"PH_OBJECT_HEADER.TypeIndex offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2, \"PH_OBJECT_HEADER.Flags offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3, \"PH_OBJECT_HEADER.Reserved1 offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x4, \"PH_OBJECT_HEADER.RefCount offset mismatch\");\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0, \"PH_OBJECT_HEADER.DeferDeleteListEntry offset mismatch\");\n#if defined(DEBUG)\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x50, \"PH_OBJECT_HEADER.Body offset mismatch\");\n#else\nstatic_assert(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x8, \"PH_OBJECT_HEADER.Body offset mismatch\");\n#endif\n#endif\n\n/**\n * Gets a pointer to the object header for an object.\n *\n * \\param Object A pointer to an object.\n *\n * \\return A pointer to the object header of the object.\n */\n#if defined(_PHLIB_)\n#define PhObjectToObjectHeader(Object) ((PPH_OBJECT_HEADER)CONTAINING_RECORD((Object), PH_OBJECT_HEADER, Body))\n#else\nFORCEINLINE\nPPH_OBJECT_HEADER\nNTAPI\nPhObjectToObjectHeader(\n    _In_ PVOID Object\n    )\n{\n    return CONTAINING_RECORD(Object, PH_OBJECT_HEADER, Body);\n}\n#endif\n\n/**\n * Gets a pointer to an object from an object header.\n *\n * \\param ObjectHeader A pointer to an object header.\n *\n * \\return A pointer to an object.\n */\n#if defined(_PHLIB_)\n#define PhObjectHeaderToObject(ObjectHeader) ((PVOID)&((PPH_OBJECT_HEADER)(ObjectHeader))->Body)\n#else\nFORCEINLINE\nPVOID\nPhObjectHeaderToObject(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    )\n{\n    return &ObjectHeader->Body;\n}\n#endif\n\n/**\n * Calculates the total size to allocate for an object.\n *\n * \\param Size The size of the object to allocate.\n *\n * \\return The new size, including space for the object header.\n */\n#if defined(_PHLIB_)\n#define PhAddObjectHeaderSize(Size) ((Size) + UFIELD_OFFSET(PH_OBJECT_HEADER, Body))\n#else\nFORCEINLINE\nSIZE_T\nPhAddObjectHeaderSize(\n    _In_ SIZE_T Size\n    )\n{\n    return UFIELD_OFFSET(PH_OBJECT_HEADER, Body) + Size;\n}\n#endif\n\n/** An object type specifies a kind of object and its delete procedure. */\ntypedef struct _PH_OBJECT_TYPE\n{\n    /** The flags that were used to create the object type. */\n    USHORT Flags;\n    UCHAR TypeIndex;\n    UCHAR Reserved;\n    /** The total number of objects of this type that are alive. */\n    ULONG NumberOfObjects;\n    /** An optional procedure called when objects of this type are freed. */\n    PPH_TYPE_DELETE_PROCEDURE DeleteProcedure;\n    /** The name of the type. */\n    PCWSTR Name;\n    /** A free list to use when allocating for this type. */\n    PH_FREE_LIST FreeList;\n} PH_OBJECT_TYPE, *PPH_OBJECT_TYPE;\n\n/**\n * Increments a reference count, but will never increment from a nonpositive value to 1.\n *\n * \\param RefCount A pointer to a reference count.\n */\nFORCEINLINE\nBOOLEAN\nPhpInterlockedIncrementSafe(\n    _Inout_ PLONG RefCount\n    )\n{\n    /* Here we will attempt to increment the reference count, making sure that it is positive. */\n    return _InterlockedIncrementPositive(RefCount);\n}\n\nPPH_OBJECT_HEADER PhpAllocateObject(\n    _In_ PPH_OBJECT_TYPE ObjectType,\n    _In_ SIZE_T ObjectSize\n    );\n\nVOID PhpFreeObject(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    );\n\nVOID PhpDeferDeleteObject(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpDeferDeleteObjectRoutine(\n    _In_ PVOID Parameter\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/searchbox.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2012-2023\n *     jxy-s   2023-2024\n *\n */\n\n#ifndef _PH_SEARCHBOX_H\n#define _PH_SEARCHBOX_H\n\nEXTERN_C_START\n\ntypedef _Function_class_(PH_SEARCHCONTROL_CALLBACK)\nVOID NTAPI PH_SEARCHCONTROL_CALLBACK(\n    _In_ ULONG_PTR MatchHandle,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_SEARCHCONTROL_CALLBACK* PPH_SEARCHCONTROL_CALLBACK;\n\nPHLIBAPI\nVOID\nNTAPI\nPhCreateSearchControlEx(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND SearchWindowHandle,\n    _In_opt_ PCWSTR BannerText,\n    _In_ PVOID ImageBaseAddress,\n    _In_ PCWSTR SearchButtonResource,\n    _In_ PCWSTR SearchButtonActiveResource,\n    _In_ PCWSTR CaseButtonResource,\n    _In_ PCWSTR RegexButtonResource,\n    _In_ PCWSTR RegexSetting,\n    _In_ PCWSTR CaseSetting,\n    _In_ PPH_SEARCHCONTROL_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSearchControlClear(\n    _In_ HWND SearchWindowHandle\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSearchControlMatch(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PCPH_STRINGREF Text\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSearchControlMatchZ(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PCWSTR Text\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSearchControlMatchLongHintZ(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PCWSTR Text\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSearchControlMatchPointer(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PVOID Pointer\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSearchControlMatchPointerRange(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PVOID Pointer,\n    _In_ SIZE_T Size\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/secedit.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_SECEDIT_H\n#define _PH_SECEDIT_H\n\nEXTERN_C_START\n\nextern BOOLEAN PhEnableSecurityAdvancedDialog;\n\n//\n// secedit\n//\n\ntypedef struct _PH_ACCESS_ENTRY\n{\n    PCWSTR Name;\n    ACCESS_MASK Access;\n    BOOLEAN General;\n    BOOLEAN Specific;\n    PCWSTR ShortName;\n} PH_ACCESS_ENTRY, *PPH_ACCESS_ENTRY;\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateSecurityPage(\n    _In_opt_ PCWSTR ObjectName,\n    _In_ PCWSTR ObjectType,\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhEditSecurity(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR ObjectName,\n    _In_ PCWSTR ObjectType,\n    _In_opt_ PPH_OPEN_OBJECT OpenObject,\n    _In_opt_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhEditSecurityEx(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR ObjectName,\n    _In_ PCWSTR ObjectType,\n    _In_opt_ PPH_OPEN_OBJECT OpenObject,\n    _In_opt_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_opt_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context\n    );\n\ntypedef struct _PH_STD_OBJECT_SECURITY\n{\n    PVOID ObjectContext;\n    PVOID Context;\n} PH_STD_OBJECT_SECURITY, *PPH_STD_OBJECT_SECURITY;\n\nFORCEINLINE ACCESS_MASK PhGetAccessForGetSecurity(\n    _In_ SECURITY_INFORMATION SecurityInformation\n    )\n{\n    ACCESS_MASK access = 0;\n\n    if (\n        FlagOn(SecurityInformation, OWNER_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, GROUP_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, DACL_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, LABEL_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, ATTRIBUTE_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, SCOPE_SECURITY_INFORMATION)\n        )\n    {\n        SetFlag(access, READ_CONTROL);\n    }\n\n    if (FlagOn(SecurityInformation, SACL_SECURITY_INFORMATION))\n    {\n        SetFlag(access, ACCESS_SYSTEM_SECURITY);\n    }\n\n    if (FlagOn(SecurityInformation, BACKUP_SECURITY_INFORMATION))\n    {\n        SetFlag(access, READ_CONTROL | ACCESS_SYSTEM_SECURITY);\n    }\n\n    return access;\n}\n\nFORCEINLINE ACCESS_MASK PhGetAccessForSetSecurity(\n    _In_ SECURITY_INFORMATION SecurityInformation\n    )\n{\n    ACCESS_MASK access = 0;\n\n    if (\n        FlagOn(SecurityInformation, OWNER_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, GROUP_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, LABEL_SECURITY_INFORMATION)\n        )\n    {\n        SetFlag(access, WRITE_OWNER);\n    }\n\n    if (\n        FlagOn(SecurityInformation, DACL_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, ATTRIBUTE_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, PROTECTED_DACL_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, UNPROTECTED_DACL_SECURITY_INFORMATION)\n        )\n    {\n        SetFlag(access, WRITE_DAC);\n    }\n\n    if (\n        FlagOn(SecurityInformation, SACL_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, SCOPE_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, PROTECTED_SACL_SECURITY_INFORMATION) ||\n        FlagOn(SecurityInformation, UNPROTECTED_SACL_SECURITY_INFORMATION)\n        )\n    {\n        SetFlag(access, ACCESS_SYSTEM_SECURITY);\n    }\n\n    if (FlagOn(SecurityInformation, BACKUP_SECURITY_INFORMATION))\n    {\n        SetFlag(access, WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY);\n    }\n\n    return access;\n}\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhStdGetObjectSecurity(\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhStdSetObjectSecurity(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSeObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectType,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetSeObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectType,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLsaQuerySecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSamQuerySecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSeObjectSecurityTokenDefault(\n    _In_ HANDLE TokenHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetSeObjectSecurityTokenDefault(\n    _In_ HANDLE TokenHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSeObjectSecurityPowerGuid(\n    _In_ HANDLE Object,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetSeObjectSecurityPowerGuid(\n    _In_ HANDLE Object,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n//\n// secdata\n//\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetAccessEntries(\n    _In_ PCWSTR Type,\n    _Out_ PPH_ACCESS_ENTRY *AccessEntries,\n    _Out_ PULONG NumberOfAccessEntries\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetAccessString(\n    _In_ ACCESS_MASK Access,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/seceditp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2016-2023\n *\n */\n\n#ifndef _PH_SECEDITP_H\n#define _PH_SECEDITP_H\n\ntypedef enum _PH_SE_OBJECT_TYPE\n{\n    PH_SE_DEFAULT_OBJECT_TYPE,\n\n    // System objects\n    PH_SE_ALPC_OBJECT_TYPE,\n    PH_SE_FILE_OBJECT_TYPE,\n    PH_SE_RDP_OBJECT_TYPE,\n    PH_SE_SERVICE_OBJECT_TYPE,\n    PH_SE_LSA_OBJECT_TYPE,\n    PH_SE_SAM_OBJECT_TYPE,\n\n    PH_SE_KEY_OBJECT,\n    PH_SE_KERNEL_OBJECT,\n    PH_SE_PROCESS_OBJECT_TYPE,\n    PH_SE_THREAD_OBJECT_TYPE,\n\n    PH_SE_WINDOW_OBJECT,\n    PH_SE_WMIGUID_OBJECT,\n    // ...\n\n    // Virtual objects (always last)\n    PH_SE_TOKENDEF_OBJECT_TYPE,\n    PH_SE_POWERDEF_OBJECT_TYPE,\n    PH_SE_RDPDEF_OBJECT_TYPE,\n    PH_SE_WMIDEF_OBJECT_TYPE,\n    PH_SE_COMACCESSDEF_OBJECT_TYPE,\n    PH_SE_COMLAUNCHDEF_OBJECT_TYPE,\n    // ...\n\n} PH_SE_OBJECT_TYPE;\n\ntypedef struct\n{\n    const ISecurityInformationVtbl *VTable;\n\n    ULONG RefCount;\n\n    HWND WindowHandle;\n    BOOLEAN IsPage;\n    BOOLEAN HaveGenericMapping;\n    PPH_ACCESS_ENTRY AccessEntriesArray;\n    PSI_ACCESS AccessEntries;\n    ULONG NumberOfAccessEntries;\n    GENERIC_MAPPING GenericMapping;\n\n    PH_SE_OBJECT_TYPE ObjectType;\n\n    PPH_STRING ObjectNameString;\n    PPH_STRING ObjectTypeString;\n\n    PPH_OPEN_OBJECT OpenObject;\n    PPH_CLOSE_OBJECT CloseObject;\n\n    PPH_GET_OBJECT_SECURITY GetObjectSecurity;\n    PPH_SET_OBJECT_SECURITY SetObjectSecurity;\n\n    PVOID Context;\n} PhSecurityInformation;\n\ntypedef struct\n{\n    const ISecurityInformation2Vtbl *VTable;\n\n    PhSecurityInformation *Context;\n    ULONG RefCount;\n} PhSecurityInformation2;\n\ntypedef struct\n{\n    const ISecurityInformation3Vtbl *VTable;\n\n    PhSecurityInformation *Context;\n    ULONG RefCount;\n} PhSecurityInformation3;\n\ntypedef struct\n{\n    const IDataObjectVtbl *VTable;\n\n    PhSecurityInformation *Context;\n    ULONG RefCount;\n    ULONG SidCount;\n    PSID *Sids;\n    PPH_LIST NameCache;\n} PhSecurityIDataObject;\n\ntypedef struct\n{\n    const IEffectivePermissionVtbl *VTable;\n\n    PhSecurityInformation *Context;\n    ULONG RefCount;\n} PhEffectivePermission;\n\n#undef INTERFACE\n#define INTERFACE   ISecurityObjectTypeInfoEx\nDECLARE_INTERFACE_IID_(ISecurityObjectTypeInfoEx, IUnknown, \"FC3066EB-79EF-444b-9111-D18A75EBF2FA\")\n{\n    BEGIN_INTERFACE\n\n    // *** IUnknown methods ***\n\n    DECLSPEC_XFGVIRT(ISecurityObjectTypeInfoEx, QueryInterface)\n    STDMETHOD(QueryInterface) (THIS_ _In_ REFIID riid, _Outptr_ void** ppvObj) PURE;\n\n    DECLSPEC_XFGVIRT(ISecurityObjectTypeInfoEx, AddRef)\n    STDMETHOD_(ULONG, AddRef) (THIS)  PURE;\n\n    DECLSPEC_XFGVIRT(ISecurityObjectTypeInfoEx, Release)\n    STDMETHOD_(ULONG, Release) (THIS) PURE;\n\n    // *** ISecurityInformation methods ***\n    DECLSPEC_XFGVIRT(ISecurityObjectTypeInfoEx, GetInheritSource)\n    STDMETHOD(GetInheritSource)(THIS_\n        _In_ SECURITY_INFORMATION si,\n        _In_ PACL pACL,\n        _In_ PINHERITED_FROM* ppInheritArray\n        ) PURE;\n\n    END_INTERFACE\n};\ntypedef ISecurityObjectTypeInfoEx* LPSecurityObjectTypeInfoEx;\n\ntypedef struct\n{\n    const ISecurityObjectTypeInfoExVtbl* VTable;\n\n    PhSecurityInformation* Context;\n    ULONG RefCount;\n} PhSecurityObjectTypeInfo;\n\n// ISecurityInformation\n\nISecurityInformation *PhSecurityInformation_Create(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR ObjectName,\n    _In_ PCWSTR ObjectType,\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_opt_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context,\n    _In_ BOOLEAN IsPage\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface(\n    _In_ ISecurityInformation *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef(\n    _In_ ISecurityInformation *This\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation_Release(\n    _In_ ISecurityInformation *This\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation(\n    _In_ ISecurityInformation *This,\n    _Out_ PSI_OBJECT_INFO ObjectInfo\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity(\n    _In_ ISecurityInformation *This,\n    _In_ SECURITY_INFORMATION RequestedInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ BOOL Default\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity(\n    _In_ ISecurityInformation *This,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights(\n    _In_ ISecurityInformation *This,\n    _In_ PCGUID ObjectType,\n    _In_ ULONG Flags,\n    _Out_ PSI_ACCESS *Access,\n    _Out_ PULONG Accesses,\n    _Out_ PULONG DefaultAccess\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric(\n    _In_ ISecurityInformation *This,\n    _In_ PCGUID ObjectType,\n    _In_ PUCHAR AceFlags,\n    _Inout_ PACCESS_MASK Mask\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes(\n    _In_ ISecurityInformation *This,\n    _Out_ PSI_INHERIT_TYPE *InheritTypes,\n    _Out_ PULONG InheritTypesCount\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback(\n    _In_ ISecurityInformation *This,\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ SI_PAGE_TYPE uPage\n    );\n\n// ISecurityInformation2\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation2_QueryInterface(\n    _In_ ISecurityInformation2 *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation2_AddRef(\n    _In_ ISecurityInformation2 *This\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation2_Release(\n    _In_ ISecurityInformation2 *This\n    );\n\nBOOL STDMETHODCALLTYPE PhSecurityInformation2_IsDaclCanonical(\n    _In_ ISecurityInformation2 *This,\n    _In_ PACL pDacl\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids(\n    _In_ ISecurityInformation2 *This,\n    _In_ ULONG cSids,\n    _In_ PSID *rgpSids,\n    _Out_ LPDATAOBJECT *ppdo\n    );\n\n// ISecurityInformation3\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation3_QueryInterface(\n    _In_ ISecurityInformation3 *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation3_AddRef(\n    _In_ ISecurityInformation3 *This\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation3_Release(\n    _In_ ISecurityInformation3 *This\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation3_GetFullResourceName(\n    _In_ ISecurityInformation3 *This,\n    _Outptr_ PWSTR *ResourceName\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation3_OpenElevatedEditor(\n    _In_ ISecurityInformation3 *This,\n    _In_ HWND hWnd,\n    _In_ SI_PAGE_TYPE uPage\n    );\n\n// IDataObject\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryInterface(\n    _In_ IDataObject *This,\n    _In_ REFIID Riid,\n    _COM_Outptr_ PVOID *Object\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityDataObject_AddRef(\n    _In_ IDataObject *This\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityDataObject_Release(\n    _In_ IDataObject *This\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetcIn,\n    _Out_ STGMEDIUM *pmedium);\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetDataHere(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _Inout_ STGMEDIUM *pmedium\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryGetData(\n    _In_ IDataObject *This,\n    _In_opt_ FORMATETC *pformatetc\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetCanonicalFormatEtc(\n    _In_ IDataObject *This,\n    _In_opt_ FORMATETC *pformatectIn,\n    _Out_ FORMATETC *pformatetcOut\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_SetData(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _In_ STGMEDIUM *pmedium,\n    _In_ BOOL fRelease\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumFormatEtc(\n    _In_ IDataObject *This,\n    _In_ ULONG dwDirection,\n    _Out_opt_ IEnumFORMATETC **ppenumFormatEtc\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_DAdvise(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _In_ ULONG advf,\n    _In_opt_ IAdviseSink *pAdvSink,\n    _Out_ ULONG *pdwConnection\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_DUnadvise(\n    _In_ IDataObject *This,\n    _In_ ULONG dwConnection\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumDAdvise(\n    _In_ IDataObject *This,\n    _Out_opt_ IEnumSTATDATA **ppenumAdvise\n    );\n\n// ISecurityObjectTypeInfo\n\nHRESULT STDMETHODCALLTYPE PhSecurityObjectTypeInfo_QueryInterface(\n    _In_ ISecurityObjectTypeInfoEx* This,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Object\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityObjectTypeInfo_AddRef(\n    _In_ ISecurityObjectTypeInfoEx* This\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityObjectTypeInfo_Release(\n    _In_ ISecurityObjectTypeInfoEx* This\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityObjectTypeInfo_GetInheritSource(\n    _In_ ISecurityObjectTypeInfoEx* This,\n    _In_ SECURITY_INFORMATION SecurityInfo,\n    _In_ PACL Acl,\n    _Out_ PINHERITED_FROM *InheritArray\n    );\n\n// IEffectivePermission\n\nHRESULT STDMETHODCALLTYPE PhEffectivePermission_QueryInterface(\n    _In_ IEffectivePermission* This,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Object\n    );\n\nULONG STDMETHODCALLTYPE PhEffectivePermission_AddRef(\n    _In_ IEffectivePermission* This\n    );\n\nULONG STDMETHODCALLTYPE PhEffectivePermission_Release(\n    _In_ IEffectivePermission* This\n    );\n\nHRESULT STDMETHODCALLTYPE PhEffectivePermission_GetEffectivePermission(\n    _In_ IEffectivePermission* This,\n    _In_ LPCGUID GuidObjectType,\n    _In_ PSID UserSid,\n    _In_ LPCWSTR ServerName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ POBJECT_TYPE_LIST* ObjectTypeList,\n    _Out_ PULONG ObjectTypeListLength,\n    _Out_ PACCESS_MASK* GrantedAccessList,\n    _Out_ PULONG GrantedAccessListLength\n    );\n\nPH_SE_OBJECT_TYPE PhSecurityObjectType(\n    _In_ PPH_STRING ObjectType\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/secwmi.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2016-2023\n *\n */\n\n#ifndef _PH_SECWMI_H\n#define _PH_SECWMI_H\n\nEXTERN_C_START\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhGetWbemLocatorClass(\n    _Out_ struct IWbemLocator** WbemLocatorClass\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhCoSetProxyBlanket(\n    _In_ IUnknown* InterfacePtr\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhGetWbemClassObjectDependency(\n    _Out_ PVOID* WbemClassObjectDependency,\n    _In_ struct IWbemClassObject* WbemClassObject,\n    _In_ struct IWbemServices* WbemServices,\n    _In_ PCWSTR Name\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetWbemClassObjectString(\n    _In_ PVOID WbemClassObject,\n    _In_ PCWSTR Name\n    );\n\nPHLIBAPI\nULONG64\nNTAPI\nPhGetWbemClassObjectUlong64(\n    _In_ PVOID WbemClassObject,\n    _In_ PCWSTR Name\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetWbemClassObjectUlongPtr(\n    _In_ PVOID WbemClassObject,\n    _In_ PCWSTR Name\n    );\n\n#define PhStringRefToBSTR(String) \\\n    SysAllocStringLen((String)->Buffer, (UINT)(String)->Length / sizeof(WCHAR))\n#define PhStringZToBSTR(String) \\\n    SysAllocStringLen((String), (UINT)((sizeof(String) / sizeof(WCHAR)) - 1))\n\n// powrprof.h\ntypedef enum _POWER_DATA_ACCESSOR POWER_DATA_ACCESSOR;\n\n// rev\ntypedef ULONG (WINAPI* _PowerReadSecurityDescriptor)(\n    _In_ POWER_DATA_ACCESSOR AccessFlags,\n    _In_ PGUID PowerGuid,\n    _Out_ PWSTR* StringSecurityDescriptor\n    );\n\n// rev\ntypedef ULONG (WINAPI* _PowerWriteSecurityDescriptor)(\n    _In_ POWER_DATA_ACCESSOR AccessFlags,\n    _In_ PGUID PowerGuid,\n    _In_ PCWSTR StringSecurityDescriptor\n    );\n\n// Power policy\n\nNTSTATUS PhpGetPowerPolicySecurityDescriptor(\n    _Out_ PPH_STRING* StringSecurityDescriptor\n    );\n\nNTSTATUS PhpSetPowerPolicySecurityDescriptor(\n    _In_ PPH_STRING StringSecurityDescriptor\n    );\n\n// Terminal server policy\n\nNTSTATUS PhpGetRemoteDesktopSecurityDescriptor(\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    );\n\nNTSTATUS PhpSetRemoteDesktopSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n// Wbem namespace policy\n\nNTSTATUS PhGetWmiNamespaceSecurityDescriptor(\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    );\n\nNTSTATUS PhSetWmiNamespaceSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n// COM access and launch policy\n\nNTSTATUS PhGetComSecurityDescriptor(\n    _In_ COMSD comSDType,\n    _Outptr_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    );\n\nNTSTATUS PhSetComSecurityDescriptor(\n    _In_ COMSD comSDType,\n    _In_ ULONG SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n// Defender offline scan\n\nHRESULT PhRestartDefenderOfflineScan(\n    VOID\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/settings.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2016-2023\n *\n */\n\n#ifndef PHLIB_SETTINGS_H\n#define PHLIB_SETTINGS_H\n\nEXTERN_C_START\n\ntypedef enum _PH_SETTINGS_FORMAT\n{\n    SettingsFormatJson = 1,\n    SettingsFormatXml = 2,\n    SettingsFormatKey = 3,\n    SettingsFormatReg = 4,\n    SettingsFormatBin = 5,\n    SettingsFormatMax\n} PH_SETTINGS_FORMAT;\n\ntypedef struct _PH_SETTINGS_STORE_DESCRIPTOR\n{\n    PH_SETTINGS_FORMAT Format;\n    PCWSTR Extension;\n    BOOLEAN IsFileBased;\n    BOOLEAN IsPreferred;\n    BOOLEAN IsLegacy;\n    INT Priority;\n} PH_SETTINGS_STORE_DESCRIPTOR, *PPH_SETTINGS_STORE_DESCRIPTOR;\n\n// begin_phapppub\n\n// These macros make sure the C strings can be seamlessly converted into\n// PH_STRINGREFs at compile time, for a small speed boost.\n\n#define ADD_SETTING_WRAPPER(Type, Name, DefaultValue) \\\n{ \\\n    static CONST PH_STRINGREF name = PH_STRINGREF_INIT(Name); \\\n    static CONST PH_STRINGREF defaultValue = PH_STRINGREF_INIT(DefaultValue); \\\n    PhAddSetting(Type, &name, &defaultValue); \\\n}\n\n#define PhpAddStringSetting(A, B) ADD_SETTING_WRAPPER(StringSettingType, A, B)\n#define PhpAddIntegerSetting(A, B) ADD_SETTING_WRAPPER(IntegerSettingType, A, B)\n#define PhpAddIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(IntegerPairSettingType, A, B)\n#define PhpAddScalableIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(ScalableIntegerPairSettingType, A, B)\n\ntypedef enum _PH_SETTING_TYPE\n{\n    StringSettingType,\n    IntegerSettingType,\n    IntegerPairSettingType,\n    ScalableIntegerPairSettingType\n} PH_SETTING_TYPE, PPH_SETTING_TYPE;\n// end_phapppub\n\ntypedef struct _PH_SETTING\n{\n    PH_SETTING_TYPE Type;\n    PH_STRINGREF Name;\n    PH_STRINGREF DefaultValue;\n\n    union\n    {\n        PVOID Pointer;\n        ULONG Integer;\n        PH_INTEGER_PAIR IntegerPair;\n    } u;\n} PH_SETTING, *PPH_SETTING;\n\nPHLIBAPI\nVOID\nNTAPI\nPhSettingsInitialization(\n    VOID\n    );\n\n// private\n\nPPH_STRING PhSettingToString(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_SETTING Setting\n    );\n\nBOOLEAN PhSettingFromString(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PCPH_STRINGREF StringRef,\n    _In_opt_ PPH_STRING String,\n    _Inout_ PPH_SETTING Setting\n    );\n\ntypedef _Function_class_(PH_SETTINGS_ENUM_CALLBACK)\nBOOLEAN NTAPI PH_SETTINGS_ENUM_CALLBACK(\n    _In_ PPH_SETTING Setting,\n    _In_ PVOID Context\n    );\ntypedef PH_SETTINGS_ENUM_CALLBACK* PPH_SETTINGS_ENUM_CALLBACK;\n\nVOID PhEnumSettings(\n    _In_ PPH_SETTINGS_ENUM_CALLBACK Callback,\n    _In_ PVOID Context\n    );\n\n// begin_phapppub\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetIntegerStringRefSetting(\n    _In_ PCPH_STRINGREF Name\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetIntegerPairStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _Out_ PPH_INTEGER_PAIR IntegerPair\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetScalableIntegerPairStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ BOOLEAN ScaleToDpi,\n    _In_ LONG Dpi,\n    _Out_ PPH_SCALABLE_INTEGER_PAIR* ScalableIntegerPair\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetStringRefSetting(\n    _In_ PCPH_STRINGREF Name\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetIntegerStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ ULONG Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetIntegerPairStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PPH_INTEGER_PAIR Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetScalableIntegerPairStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PPH_SCALABLE_INTEGER_PAIR Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetScalableIntegerPairStringRefSetting2(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PPH_INTEGER_PAIR Value,\n    _In_ LONG dpiValue\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PCPH_STRINGREF Value\n    );\n\nFORCEINLINE\nVOID\nPhScalableIntegerPairToScale(\n    _In_ PPH_SCALABLE_INTEGER_PAIR ScalableIntegerPair,\n    _In_ LONG Scale\n    )\n{\n    if (ScalableIntegerPair->Scale != Scale && ScalableIntegerPair->Scale != 0)\n    {\n        ScalableIntegerPair->X = PhMultiplyDivideSigned(ScalableIntegerPair->X, Scale, ScalableIntegerPair->Scale);\n        ScalableIntegerPair->Y = PhMultiplyDivideSigned(ScalableIntegerPair->Y, Scale, ScalableIntegerPair->Scale);\n        ScalableIntegerPair->Scale = Scale;\n    }\n}\n\nFORCEINLINE\nVOID\nPhScalableIntegerPairScaleToDefault(\n    _In_ PPH_SCALABLE_INTEGER_PAIR ScalableIntegerPair\n    )\n{\n    PhScalableIntegerPairToScale(ScalableIntegerPair, USER_DEFAULT_SCREEN_DPI);\n}\n\nFORCEINLINE\nULONG\nNTAPI\nPhGetIntegerSetting(\n    _In_ PCWSTR Name\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    return PhGetIntegerStringRefSetting(&name);\n}\n\nFORCEINLINE\nPH_INTEGER_PAIR\nNTAPI\nPhGetIntegerPairSetting(\n    _In_ PCWSTR Name\n    )\n{\n    PH_INTEGER_PAIR scalableIntegerPair = { 0 };\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhGetIntegerPairStringRefSetting(&name, &scalableIntegerPair);\n\n    return scalableIntegerPair;\n}\n\nFORCEINLINE\nPPH_SCALABLE_INTEGER_PAIR\nNTAPI\nPhGetScalableIntegerPairSetting(\n    _In_ PCWSTR Name,\n    _In_ BOOLEAN ScaleToDpi,\n    _In_ LONG Dpi\n    )\n{\n    PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = NULL;\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhGetScalableIntegerPairStringRefSetting(&name, ScaleToDpi, Dpi, &scalableIntegerPair);\n\n    return scalableIntegerPair;\n}\n\nFORCEINLINE\nPPH_STRING\nNTAPI\nPhGetStringSetting(\n    _In_ PCWSTR Name\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    return PhGetStringRefSetting(&name);\n}\n\n#define PhaGetStringSetting(Name) PH_AUTO_T(PH_STRING, PhGetStringSetting(Name)) // phapppub\n\nFORCEINLINE\nPPH_STRING\nNTAPI\nPhGetExpandStringSetting(\n    _In_ PCWSTR Name\n    )\n{\n    PPH_STRING setting;\n\n    setting = PhGetStringSetting(Name);\n    PhMoveReference(&setting, PhExpandEnvironmentStrings(&setting->sr));\n\n    return setting;\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhSetIntegerSetting(\n    _In_ PCWSTR Name,\n    _In_ ULONG Value\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhSetIntegerStringRefSetting(&name, Value);\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhSetStringSetting(\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Value\n    )\n{\n    PH_STRINGREF name;\n    PH_STRINGREF value;\n\n    PhInitializeStringRef(&name, Name);\n    PhInitializeStringRef(&value, Value);\n\n    PhSetStringRefSetting(&name, &value);\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhSetStringSetting2(\n    _In_ PCWSTR Name,\n    _In_ PCPH_STRINGREF Value\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhSetStringRefSetting(&name, Value);\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhSetIntegerPairSetting(\n    _In_ PCWSTR Name,\n    _In_ PH_INTEGER_PAIR Value\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhSetIntegerPairStringRefSetting(&name, &Value);\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhSetScalableIntegerPairSetting(\n    _In_ PCWSTR Name,\n    _In_ PPH_SCALABLE_INTEGER_PAIR Value\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhSetScalableIntegerPairStringRefSetting(&name, Value);\n}\n\nFORCEINLINE\nVOID\nNTAPI\nPhSetScalableIntegerPairSetting2(\n    _In_ PCWSTR Name,\n    _In_ PH_INTEGER_PAIR Value,\n    _In_ LONG dpiValue\n    )\n{\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhSetScalableIntegerPairStringRefSetting2(&name, &Value, dpiValue);\n}\n\n// end_phapppub\n\nVOID PhClearIgnoredSettings(\n    VOID\n    );\n\nULONG PhCountIgnoredSettings(\n    VOID\n    );\n\nVOID PhConvertIgnoredSettings(\n    VOID\n    );\n\nNTSTATUS PhLoadSettings(\n    _In_ PCPH_STRINGREF FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadSettingsAutoDetect(\n    _In_opt_ PPH_STRING BasePath,\n    _In_opt_ PCWSTR DefaultName,\n    _Out_opt_ PPH_STRING* ActualPath,\n    _Out_opt_ PH_SETTINGS_FORMAT* ActualFormat,\n    _Out_opt_ PBOOLEAN IsPortable\n    );\n\nNTSTATUS PhSaveSettings(\n    _In_opt_ PCPH_STRINGREF FileName\n    );\n\nFORCEINLINE\nNTSTATUS\nPhLoadSettings2(\n    _In_ PPH_STRING FileName\n    )\n{\n    if (PhIsNullOrEmptyString(FileName))\n        return STATUS_UNSUCCESSFUL;\n\n    return PhLoadSettings(&FileName->sr);\n}\n\nFORCEINLINE\nNTSTATUS\nPhSaveSettings2(\n    _In_ PPH_STRING FileName\n    )\n{\n    if (PhIsNullOrEmptyString(FileName))\n        return STATUS_UNSUCCESSFUL;\n\n    return PhSaveSettings(&FileName->sr);\n}\n\nVOID PhResetSettings(\n    _In_ HWND hwnd\n    );\n\nNTSTATUS PhResetSettingsFile(\n    _In_ PCPH_STRINGREF FileName\n    );\n\n// begin_phapppub\n// High-level settings creation\n\nVOID PhAddSetting(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PCPH_STRINGREF Name,\n    _In_ PCPH_STRINGREF DefaultValue\n    );\n\ntypedef struct _PH_SETTING_CREATE\n{\n    PH_SETTING_TYPE Type;\n    PWSTR Name;\n    PWSTR DefaultValue;\n} PH_SETTING_CREATE, *PPH_SETTING_CREATE;\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddSettings(\n    _In_ PPH_SETTING_CREATE Settings,\n    _In_ ULONG NumberOfSettings\n    );\n\nPHLIBAPI\nPPH_SETTING\nNTAPI\nPhGetSetting(\n    _In_ PCPH_STRINGREF Name\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLoadWindowPlacementFromRectangle(\n    _In_ PCWSTR PositionSettingName,\n    _In_ PCWSTR SizeSettingName,\n    _Inout_ PPH_RECTANGLE WindowRectangle\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLoadWindowPlacementFromSetting(\n    _In_opt_ PCWSTR PositionSettingName,\n    _In_opt_ PCWSTR SizeSettingName,\n    _In_ HWND WindowHandle\n    );\n\nFORCEINLINE\nBOOLEAN\nNTAPI\nPhValidWindowPlacementFromSetting(\n    _In_ PCWSTR Name\n    )\n{\n    PH_STRINGREF name;\n    PH_INTEGER_PAIR integerPair;\n\n    PhInitializeStringRef(&name, Name);\n\n    if (PhGetIntegerPairStringRefSetting(&name, &integerPair))\n    {\n        if (integerPair.X != 0)\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhSaveWindowPlacementToSetting(\n    _In_opt_ PCWSTR PositionSettingName,\n    _In_opt_ PCWSTR SizeSettingName,\n    _In_ HWND WindowHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLoadListViewColumnsFromSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSaveListViewColumnsToSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLoadListViewSortColumnsFromSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSaveListViewSortColumnsToSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLoadListViewGroupStatesFromSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSaveListViewGroupStatesToSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLoadCustomColorList(\n    _In_ PCWSTR Name,\n    _In_ PULONG CustomColorList,\n    _In_ ULONG CustomColorCount\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSaveCustomColorList(\n    _In_ PCWSTR Name,\n    _In_ PULONG CustomColorList,\n    _In_ ULONG CustomColorCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConvertSettingsXmlToJson(\n    _In_ PCPH_STRINGREF XmlFileName,\n    _In_ PCPH_STRINGREF JsonFileName\n    );\n\n// end_phapppub\n\n#define PH_GET_INTEGER_CACHED_SETTING(Name) ((PhCs##Name) = PhGetIntegerSetting(TEXT(#Name)))\n#define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(TEXT(#Name), (PhCs##Name) = (Value)))\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/strsrch.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2017-2023\n *     jxy-s   2024\n *\n */\n\n#ifndef _PH_MEMSRCH_H\n#define _PH_MEMSRCH_H\n\nEXTERN_C_START\n\ntypedef struct _PH_STRING_SEARCH_RESULT\n{\n    PVOID Address;\n    SIZE_T Length;\n    PPH_STRING String;\n    BOOLEAN Unicode;\n} PH_STRING_SEARCH_RESULT, *PPH_STRING_SEARCH_RESULT;\n\n_Function_class_(PH_STRING_SEARCH_CALLBACK)\ntypedef\n_Must_inspect_result_\nBOOLEAN\nNTAPI\nPH_STRING_SEARCH_CALLBACK(\n    _In_ PPH_STRING_SEARCH_RESULT Result,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_STRING_SEARCH_CALLBACK* PPH_STRING_SEARCH_CALLBACK;\n\n_Function_class_(PH_STRING_SEARCH_NEXT_BUFFER)\ntypedef\n_Must_inspect_result_\nNTSTATUS\nNTAPI\nPH_STRING_SEARCH_NEXT_BUFFER(\n    _Inout_bytecount_(*Length) PVOID* Buffer,\n    _Out_ PSIZE_T Length,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_STRING_SEARCH_NEXT_BUFFER* PPH_STRING_SEARCH_NEXT_BUFFER;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSearchStrings(\n    _In_ ULONG MinimumLength,\n    _In_ BOOLEAN ExtendedCharSet,\n    _In_ PPH_STRING_SEARCH_NEXT_BUFFER NextBuffer,\n    _In_ PPH_STRING_SEARCH_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/svcsup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2018-2023\n *\n */\n\n#ifndef _PH_SVCSUP_H\n#define _PH_SVCSUP_H\n\ntypedef struct _PH_SVC_HOST_POLICY_INFO\n{\n    ULONG AuthenticationCapabilities;\n    ULONG AuthenticationLevel;\n    ULONG BinarySignaturePolicy;\n    ULONG CoInitializeSecurityAllowComCapability;\n    ULONG CoInitializeSecurityAllowCrossContainer;\n    ULONG CoInitializeSecurityAllowInteractiveUsers;\n    ULONG CoInitializeSecurityAllowLowBox;\n    ULONG CoInitializeSecurityParam;\n    ULONG COM_UnmarshalingPolicy;\n    ULONG DefaultRpcStackSize;\n    ULONG DynamicCodePolicy;\n    ULONG ImpersonationLevel;\n    ULONG RedirectionTrustPolicy;\n    ULONG RpcExceptionFilterMode;\n} PH_SVC_HOST_POLICY_INFO, *PPH_SVC_HOST_POLICY_INFO;\n\nEXTERN_C_START\n\nextern CONST PPH_STRINGREF PhServiceTypeStrings[12];\nextern CONST PPH_STRINGREF PhServiceStartTypeStrings[5];\nextern CONST PPH_STRINGREF PhServiceErrorControlStrings[4];\n\ntypedef SC_HANDLE* PSC_HANDLE;\n\nPHLIBAPI\nSC_HANDLE\nNTAPI\nPhGetServiceManagerHandle(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumServices(\n    _Out_ LPENUM_SERVICE_STATUS_PROCESS* Services,\n    _Out_ PULONG NumberOfServices\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumDependentServices(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ LPENUM_SERVICE_STATUS* DependentServices,\n    _Out_ PULONG NumberOfDependentServices\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenServiceManager(\n    _Out_ PSC_HANDLE ServiceManagerHandle,\n    _In_opt_ PCWSTR DatabaseName,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenService(\n    _Out_ PSC_HANDLE ServiceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCWSTR ServiceName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenServiceKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCloseServiceHandle(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateService(\n    _Out_ PSC_HANDLE ServiceHandle,\n    _In_ PCWSTR ServiceName,\n    _In_opt_ PCWSTR DisplayName,\n    _In_ ULONG DesiredAccess,\n    _In_ ULONG ServiceType,\n    _In_ ULONG StartType,\n    _In_ ULONG ErrorControl,\n    _In_opt_ PCWSTR BinaryPathName,\n    _In_opt_ PCWSTR UserName,\n    _In_opt_ PCWSTR Password\n    );\n\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhChangeServiceConfig(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG ServiceType,\n    _In_ ULONG StartType,\n    _In_ ULONG ErrorControl,\n    _In_opt_ PCWSTR BinaryPathName,\n    _In_opt_ PCWSTR LoadOrderGroup,\n    _Out_opt_ PULONG TagId,\n    _In_opt_ PCWSTR Dependencies,\n    _In_opt_ PCWSTR ServiceStartName,\n    _In_opt_ PCWSTR Password,\n    _In_opt_ PCWSTR DisplayName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhChangeServiceConfig2(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG ServiceConfigLevel,\n    _In_opt_ PVOID Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryServiceConfig(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_writes_bytes_opt_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryServiceConfig2(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG ServiceConfigLevel,\n    _Out_writes_bytes_opt_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetServiceObjectSecurity(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetServiceObjectSecurity(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryServiceStatus(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ LPSERVICE_STATUS_PROCESS ServiceStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhContinueService(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhPauseService(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteService(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhStartService(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG NumberOfServiceArgs,\n    _In_reads_opt_(NumberOfServiceArgs) PCWSTR* ServiceArgVectors\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhStopService(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetServiceConfig(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ LPQUERY_SERVICE_CONFIG* ServiceConfig\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryServiceVariableSize(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG InfoLevel,\n    _Out_ PVOID* ServiceConfig\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceDescription(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceDescriptionKey(\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetServiceDelayedAutoStart(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ PBOOLEAN DelayedAutoStart\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetServiceDelayedAutoStart(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ BOOLEAN DelayedAutoStart\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetServiceTriggerInfo(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_opt_ PSERVICE_TRIGGER_INFO* ServiceTriggerInfo\n    );\n\nPHLIBAPI\nPCPH_STRINGREF\nNTAPI\nPhGetServiceStateString(\n    _In_ ULONG ServiceState\n    );\n\nPHLIBAPI\nPCPH_STRINGREF\nNTAPI\nPhGetServiceTypeString(\n    _In_ ULONG ServiceType\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetServiceTypeInteger(\n    _In_ PPH_STRINGREF ServiceType\n    );\n\nPHLIBAPI\nPCPH_STRINGREF\nNTAPI\nPhGetServiceStartTypeString(\n    _In_ ULONG ServiceStartType\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetServiceStartTypeInteger(\n    _In_ PPH_STRINGREF ServiceStartType\n    );\n\nPHLIBAPI\nPCPH_STRINGREF\nNTAPI\nPhGetServiceErrorControlString(\n    _In_ ULONG ServiceErrorControl\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetServiceErrorControlInteger(\n    _In_ PPH_STRINGREF ServiceErrorControl\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceNameFromTag(\n    _In_ HANDLE ProcessId,\n    _In_ PVOID ServiceTag\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceNameForModuleReference(\n    _In_ HANDLE ProcessId,\n    _In_ PCWSTR ModuleName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadServiceTag(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID *ServiceTag\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceKeyName(\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceParametersKeyName(\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceConfigFileName(\n    _In_ ULONG ServiceType,\n    _In_opt_ PCWSTR ServicePathName,\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetServiceHandleFileName(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PPH_STRING* ServiceFileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetServiceFileName(\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PPH_STRING* ServiceFileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetServiceDllParameter(\n    _In_ ULONG ServiceType,\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PPH_STRING *ServiceDll\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceAppUserModelId(\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetServiceBootFlags(\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetServiceUserFlags(\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServicePackageFullName(\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nPPH_SVC_HOST_POLICY_INFO\nNTAPI\nPhGetSvchostGroupPolicy(\n    _In_ PPH_STRINGREF ServiceName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWaitForServiceStatus(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG WaitForState,\n    _In_ ULONG Timeout\n    );\n\nFORCEINLINE\nVOID\nNTAPI\nPhServiceWorkaroundWindowsServiceTypeBug(\n    _Inout_ LPENUM_SERVICE_STATUS_PROCESS ServiceEntry\n    )\n{\n    // SERVICE_WIN32 is not a valid ServiceType: https://github.com/winsiderss/systeminformer/issues/120 (dmex)\n    if (ServiceEntry->ServiceStatusProcess.dwServiceType == SERVICE_WIN32)\n        ServiceEntry->ServiceStatusProcess.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;\n    if (ServiceEntry->ServiceStatusProcess.dwServiceType == (SERVICE_WIN32 | SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE))\n        ServiceEntry->ServiceStatusProcess.dwServiceType = SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE;\n}\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/symprv.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_SYMPRV_H\n#define _PH_SYMPRV_H\n\nEXTERN_C_START\n\nextern PPH_OBJECT_TYPE PhSymbolProviderType;\nextern PH_CALLBACK PhSymbolEventCallback;\n\n#define PH_MAX_SYMBOL_NAME_LEN MAX_SYM_NAME\n\ntypedef struct _PH_SYMBOL_PROVIDER\n{\n    LIST_ENTRY ModulesListHead;\n    PH_QUEUED_LOCK ModulesListLock;\n    HANDLE ProcessHandle;\n\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN IsRealHandle : 1;\n            BOOLEAN IsRegistered : 1;\n            BOOLEAN Terminating : 1;\n            BOOLEAN Spare : 5;\n        };\n    };\n\n    PH_INITONCE InitOnce;\n    PH_AVL_TREE ModulesSet;\n} PH_SYMBOL_PROVIDER, *PPH_SYMBOL_PROVIDER;\n\ntypedef enum _PH_SYMBOL_RESOLVE_LEVEL\n{\n    PhsrlFunction,\n    PhsrlModule,\n    PhsrlAddress,\n    PhsrlInvalid\n} PH_SYMBOL_RESOLVE_LEVEL, *PPH_SYMBOL_RESOLVE_LEVEL;\n\ntypedef struct _PH_SYMBOL_INFORMATION\n{\n    PVOID Address;\n    PVOID ModuleBase;\n    ULONG Index;\n    ULONG Size;\n} PH_SYMBOL_INFORMATION, *PPH_SYMBOL_INFORMATION;\n\ntypedef struct _PH_SYMBOL_LINE_INFORMATION\n{\n    ULONG LineNumber;\n    ULONG64 Address;\n} PH_SYMBOL_LINE_INFORMATION, *PPH_SYMBOL_LINE_INFORMATION;\n\ntypedef enum _PH_SYMBOL_EVENT_TYPE\n{\n    PH_SYMBOL_EVENT_TYPE_LOAD_START,\n    PH_SYMBOL_EVENT_TYPE_LOAD_END,\n    PH_SYMBOL_EVENT_TYPE_PROGRESS,\n} PH_SYMBOL_EVENT_TYPE;\n\ntypedef struct _PH_SYMBOL_EVENT_DATA\n{\n    PH_SYMBOL_EVENT_TYPE EventType;\n    PVOID EventMessage;\n    ULONG64 EventProgress;\n} PH_SYMBOL_EVENT_DATA, *PPH_SYMBOL_EVENT_DATA;\n\nPHLIBAPI\nPPH_SYMBOL_PROVIDER\nNTAPI\nPhCreateSymbolProvider(\n    _In_opt_ HANDLE ProcessId\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetLineFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address,\n    _Out_ PPH_STRING *FileName,\n    _Out_opt_ PULONG Displacement,\n    _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information\n    );\n\n_Success_(return != 0)\nPHLIBAPI\nPVOID\nNTAPI\nPhGetModuleFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address,\n    _Out_opt_ PPH_STRING *FileName\n    );\n\ntypedef struct _PH_SYMBOL_MODULE *PPH_SYMBOL_MODULE;\n\nPHLIBAPI\nPPH_SYMBOL_MODULE\nNTAPI\nPhGetSymbolModuleFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address\n    );\n\n_Success_(return != NULL)\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSymbolFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address,\n    _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel,\n    _Out_opt_ PPH_STRING *FileName,\n    _Out_opt_ PPH_STRING *SymbolName,\n    _Out_opt_ PULONG64 Displacement\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetSymbolFromName(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PCWSTR Name,\n    _Out_ PPH_SYMBOL_INFORMATION Information\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLoadModuleSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PPH_STRING FileName,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG Size\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLoadFileNameSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PPH_STRING FileName,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG Size\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLoadSymbolProviderModules(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadModulesForVirtualSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_opt_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle\n    );\n\n#define PH_SYMOPT_UNDNAME 0x1\n#define PH_SYMOPT_VERIFY_MICROSOFT_CHAIN 0x2\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetOptionsSymbolProvider(\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetSearchPathSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PCWSTR Path\n    );\n\n#ifdef _WIN64\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAccessOutOfProcessFunctionEntry(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG64 ControlPc,\n    _Out_ PRUNTIME_FUNCTION Function\n    );\n#endif\n\nPHLIBAPI\nULONG64\n__stdcall\nPhGetModuleBase64(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 dwAddr\n    );\n\nPHLIBAPI\nPVOID\n__stdcall\nPhFunctionTableAccess64(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 AddrBase\n    );\n\n#ifndef _DBGHELP_\n\n// Some of the types used below are defined in dbghelp.h.\n\ntypedef struct _tagSTACKFRAME64 *LPSTACKFRAME64;\ntypedef struct _tagSTACKFRAME_EX* LPSTACKFRAME_EX;\ntypedef struct _tagADDRESS64 *LPADDRESS64;\n\ntypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 qwBaseAddress,\n    _Out_writes_bytes_(nSize) PVOID lpBuffer,\n    _In_ ULONG nSize,\n    _Out_ PULONG lpNumberOfBytesRead\n    );\n\ntypedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(\n    _In_ HANDLE ahProcess,\n    _In_ ULONG64 AddrBase\n    );\n\ntypedef ULONG64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 Address\n    );\n\ntypedef ULONG64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(\n    _In_ HANDLE hProcess,\n    _In_ HANDLE hThread,\n    _In_ LPADDRESS64 lpaddr\n    );\n\ntypedef enum _MINIDUMP_TYPE MINIDUMP_TYPE;\ntypedef struct _MINIDUMP_EXCEPTION_INFORMATION *PMINIDUMP_EXCEPTION_INFORMATION;\ntypedef struct _MINIDUMP_USER_STREAM_INFORMATION *PMINIDUMP_USER_STREAM_INFORMATION;\ntypedef struct _MINIDUMP_CALLBACK_INFORMATION *PMINIDUMP_CALLBACK_INFORMATION;\n\n#endif\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhStackWalk(\n    _In_ ULONG MachineType,\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ThreadHandle,\n    _Inout_ LPSTACKFRAME_EX StackFrame,\n    _Inout_ PVOID ContextRecord,\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,\n    _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,\n    _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,\n    _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress\n    );\n\nPHLIBAPI\nHRESULT\nNTAPI\nPhWriteMiniDumpProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE FileHandle,\n    _In_ MINIDUMP_TYPE DumpType,\n    _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,\n    _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,\n    _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam\n    );\n\n// High-level stack walking\n\n#define PH_THREAD_STACK_FRAME_KERNEL           0x0001\n#define PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT 0x0002\n\n/** Contains information about a thread stack frame. */\ntypedef struct _PH_THREAD_STACK_FRAME\n{\n    PVOID PcAddress;\n    PVOID ReturnAddress;\n    PVOID FrameAddress;\n    PVOID StackAddress;\n    PVOID BStoreAddress;\n    PVOID Params[4];\n    USHORT Machine;\n    USHORT Flags;\n    ULONG InlineFrameContext;\n} PH_THREAD_STACK_FRAME, *PPH_THREAD_STACK_FRAME;\n\n#define PH_WALK_USER_STACK 0x1\n#define PH_WALK_USER_WOW64_STACK 0x2\n#define PH_WALK_KERNEL_STACK 0x10\n\n/**\n * A callback function passed to PhWalkThreadStack() and called for each stack frame.\n *\n * \\param StackFrame A structure providing information about the stack frame.\n * \\param Context A user-defined value passed to PhWalkThreadStack().\n * \\return TRUE to continue the stack walk, FALSE to stop.\n */\ntypedef _Function_class_(PH_WALK_THREAD_STACK_CALLBACK)\nBOOLEAN NTAPI PH_WALK_THREAD_STACK_CALLBACK(\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_WALK_THREAD_STACK_CALLBACK* PPH_WALK_THREAD_STACK_CALLBACK;\n\n/**\n * Walks the stack of a thread and invokes a callback for each stack frame.\n *\n * This function performs a stack walk for the specified thread, optionally using symbol information\n * to resolve stack frames. For each frame encountered, the provided callback function is called.\n *\n * \\param ThreadHandle Handle to the thread whose stack is to be walked.\n * \\param ProcessHandle Optional handle to the process containing the thread. May be NULL.\n * \\param ClientId Optional pointer to a CLIENT_ID structure identifying the thread. May be NULL.\n * \\param SymbolProvider Optional pointer to a symbol provider for resolving symbols. May be NULL.\n * \\param Flags Flags controlling the stack walk behavior (e.g., PH_WALK_USER_STACK, PH_WALK_KERNEL_STACK).\n * \\param Callback Pointer to a callback function to be called for each stack frame.\n * \\param Context Optional user-defined context value passed to the callback.\n * \\return Returns STATUS_SUCCESS on success, or an appropriate NTSTATUS error code on failure.\n */\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWalkThreadStack(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_opt_ PCLIENT_ID ClientId,\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG Flags,\n    _In_ PPH_WALK_THREAD_STACK_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhUndecorateSymbolName(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PCWSTR DecoratedName\n    );\n\ntypedef struct _PH_SYMBOL_INFO\n{\n    PH_STRINGREF Name;\n    ULONG TypeIndex;   // Type Index of symbol\n    ULONG Index;\n    ULONG Size;\n    ULONG64 ModBase;   // Base Address of module containing this symbol\n    ULONG Flags;\n    ULONG64 Value;     // Value of symbol, ValuePresent should be 1\n    ULONG64 Address;   // Address of symbol including base address of module\n    ULONG Register;    // register holding value or pointer to value\n    ULONG Scope;       // scope of the symbol\n    ULONG Tag;         // pdb classification\n} PH_SYMBOL_INFO, *PPH_SYMBOL_INFO;\n\ntypedef BOOLEAN (NTAPI* PPH_ENUMERATE_SYMBOLS_CALLBACK)(\n    _In_ PPH_SYMBOL_INFO SymbolInfo,\n    _In_ ULONG SymbolSize,\n    _In_opt_ PVOID UserContext\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEnumerateSymbols(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseOfDll,\n    _In_opt_ PCWSTR Mask,\n    _In_ PPH_ENUMERATE_SYMBOLS_CALLBACK EnumSymbolsCallback,\n    _In_opt_ PVOID UserContext\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetSymbolProviderDiaSource(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID BaseOfDll,\n    _Out_ PVOID* DiaSource\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetSymbolProviderDiaSession(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID BaseOfDll,\n    _Out_ PVOID* DiaSession\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSymbolProviderFreeDiaString(\n    _In_ PCWSTR DiaString\n    );\n\n// Inline stack support\n\ntypedef union _INLINE_FRAME_CONTEXT\n{\n    ULONG ContextValue;\n    struct\n    {\n        UCHAR FrameId;\n        UCHAR FrameType;\n        USHORT FrameSignature;\n    };\n} INLINE_FRAME_CONTEXT, *PINLINE_FRAME_CONTEXT;\n\n#define STACK_FRAME_TYPE_INIT 0x00\n#define STACK_FRAME_TYPE_STACK 0x01\n#define STACK_FRAME_TYPE_INLINE 0x02\n#define STACK_FRAME_TYPE_RA 0x80 // Whether the instruction pointer is the current IP or a RA from callee frame.\n#define STACK_FRAME_TYPE_IGNORE 0xFF\n\n#ifndef INLINE_FRAME_CONTEXT_INIT\n#define INLINE_FRAME_CONTEXT_INIT 0\n#endif\n\n#ifndef INLINE_FRAME_CONTEXT_IGNORE\n#define INLINE_FRAME_CONTEXT_IGNORE 0xFFFFFFFF\n#endif\n\nFORCEINLINE\nBOOLEAN\nPhIsStackFrameTypeInline(\n    _In_ ULONG InlineFrameContext\n    )\n{\n    INLINE_FRAME_CONTEXT frameContext = { InlineFrameContext };\n\n    if (frameContext.ContextValue == INLINE_FRAME_CONTEXT_IGNORE)\n        return FALSE;\n\n    if (frameContext.FrameType & STACK_FRAME_TYPE_INLINE)\n        return TRUE;\n\n    return FALSE;\n}\n\nBOOLEAN PhSymbolProviderInlineContextSupported(\n    VOID\n    );\n\n_Success_(return != NULL)\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSymbolFromInlineContext(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel,\n    _Out_opt_ PPH_STRING* FileName,\n    _Out_opt_ PPH_STRING* SymbolName,\n    _Out_opt_ PULONG64 Displacement,\n    _Out_opt_ PPVOID BaseAddress\n    );\n\n_Success_(return)\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetLineFromInlineContext(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _In_opt_ PVOID BaseAddress,\n    _Out_ PPH_STRING* FileName,\n    _Out_opt_ PULONG Displacement,\n    _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information\n    );\n\n//typedef struct _PH_INLINE_STACK_FRAME\n//{\n//    PH_SYMBOL_RESOLVE_LEVEL ResolveLevel;\n//    PPH_STRING Symbol;\n//    PPH_STRING FileName;\n//\n//    ULONG64 LineAddress;\n//    ULONG LineDisplacement;\n//    ULONG LineNumber;\n//    PPH_STRING LineFileName;\n//} PH_INLINE_STACK_FRAME, *PPH_INLINE_STACK_FRAME;\n//\n//PPH_LIST PhGetInlineStackSymbolsFromAddress(\n//    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n//    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n//    _In_ BOOLEAN IncludeLineInformation\n//    );\n//\n//VOID PhFreeInlineStackSymbols(\n//    _In_ PPH_LIST InlineSymbolList\n//    );\n\ntypedef struct _PH_DIA_SYMBOL_INFORMATION\n{\n    ULONG FunctionLength;\n    PPH_STRING UndecoratedName;\n    PPH_STRING SymbolInformation;\n    PPH_STRING SymbolLangugage;\n} PH_DIA_SYMBOL_INFORMATION, *PPH_DIA_SYMBOL_INFORMATION;\n\n_Success_(return)\nBOOLEAN PhGetDiaSymbolInformation(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address,\n    _Out_ PPH_DIA_SYMBOL_INFORMATION SymbolInformation\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUnregisterSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider\n    );\n\n// symprv_std.cpp (dmex)\n\nEXTERN_C VOID PhPrintCurrentStacktrace(\n    VOID\n    );\n\nEXTERN_C PPH_STRING PhGetStacktraceAsString(\n    VOID\n    );\n\nEXTERN_C PPH_STRING PhGetStacktraceSymbolFromAddress(\n    _In_ PVOID Address\n    );\n\nEXTERN_C PPH_STRING PhGetObjectTypeStacktraceToString(\n    _In_ PVOID Object\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/symprvp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2015\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_SYMPRVP_H\n#define _PH_SYMPRVP_H\n\n// undocumented\ntypedef BOOL (WINAPI *_SymGetDiaSource)(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG64 BaseOfDll,\n    _Out_ PVOID* IDiaDataSource\n    );\n\n// undocumented\ntypedef BOOL (WINAPI *_SymGetDiaSession)(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG64 BaseOfDll,\n    _Out_ PVOID* IDiaSession\n    );\n\n// undocumented\ntypedef BOOL (WINAPI *_SymSetDiaSession)(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG64 BaseOfDll,\n    _In_ PVOID IDiaSession\n    );\n\n// undocumented\ntypedef VOID (WINAPI *_SymFreeDiaString)(\n    _In_ PCWSTR DiaString\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/templ.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *\n */\n\n#ifndef _PH_TEMPL_H\n#define _PH_TEMPL_H\n\n#define TEMPLATE_(f,T) f##_##T\n#define T___(f,T) TEMPLATE_(f,T)\n\n#endif\n"
  },
  {
    "path": "phlib/include/thirdparty.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2024\n *\n */\n\n#pragma once\n\n#define PCRE2_CODE_UNIT_WIDTH 16\n\n#if __has_include(\"../../tools/thirdparty/pcre/pcre2.h\")\n#include \"../../tools/thirdparty/pcre/pcre2.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n\n#if __has_include(\"../../tools/thirdparty/jsonc/json.h\")\n#include \"../../tools/thirdparty/jsonc/json.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n\n#if __has_include(\"../../tools/thirdparty/mxml/mxml.h\")\n#include \"../../tools/thirdparty/mxml/mxml.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n\n#if __has_include(\"../../tools/thirdparty/detours/detours.h\")\n#include \"../../tools/thirdparty/detours/detours.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n\n#if __has_include(\"../../tools/thirdparty/md5/md5.h\")\n#include \"../../tools/thirdparty/md5/md5.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n\n#if __has_include(\"../../tools/thirdparty/sha/sha.h\")\n#include \"../../tools/thirdparty/sha/sha.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n\n#if __has_include(\"../../tools/thirdparty/sha256/sha256.h\")\n#include \"../../tools/thirdparty/sha256/sha256.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n\n#if __has_include(\"../../tools/thirdparty/winsdk/dia2.h\")\n#include \"../../tools/thirdparty/winsdk/dia2.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n\n#if __has_include(\"../../tools/thirdparty/winsdk/dia3.h\")\n#include \"../../tools/thirdparty/winsdk/dia3.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n\n#if __has_include(\"../../tools/thirdparty/xxhash/xxhashwrapper.h\")\n#include \"../../tools/thirdparty/xxhash/xxhashwrapper.h\"\n#else\n#error \"ThirdParty.lib is missing\"\n#endif\n"
  },
  {
    "path": "phlib/include/trace.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2025\n *\n */\n\n#pragma once\n\n#define WPP_CONTROL_GUIDS                                                      \\\n    WPP_DEFINE_CONTROL_GUID(                                                   \\\n        SystemInformer, (0b23b1bf, 45ee, 4219, bf51, 8979219d8acd),            \\\n        WPP_DEFINE_BIT(GENERAL)     /* bit  0 = 0x00000001 */                  \\\n        WPP_DEFINE_BIT(PROFILING)   /* bit  1 = 0x00000002 */                  \\\n        )\n\n#define WPP_LEVEL_EVENT_LOGGER(level,event) WPP_LEVEL_LOGGER(event)\n#define WPP_LEVEL_EVENT_ENABLED(level,event) \\\n    (WPP_LEVEL_ENABLED(event) && \\\n     WPP_CONTROL(WPP_BIT_ ## event).Level >= level)\n\n//\n// begin_wpp config\n//\n// FUNC PhTracePrint(LEVEL,EVENT,MSG, ...);\n// FUNC PhTrace{LEVEL=TRACE_LEVEL_VERBOSE,EVENT=GENERAL}(MSG,...);\n// FUNC PhTraceInfo{LEVEL=TRACE_LEVEL_INFORMATION,EVENT=GENERAL}(MSG,...);\n// FUNC PhTraceWarning{LEVEL=TRACE_LEVEL_WARNING,EVENT=GENERAL}(MSG,...);\n// FUNC PhTraceError{LEVEL=TRACE_LEVEL_ERROR,EVENT=GENERAL}(MSG,...);\n// FUNC PhTraceFatal{LEVEL=TRACE_LEVEL_FATAL,EVENT=GENERAL}(MSG,...);\n//\n// FUNC PhTraceFuncEnter{LEVEL=TRACE_LEVEL_VERBOSE,EVENT=PROFILING,ENTERFUNC=0}(MSG,...);\n// USESUFFIX(PhTraceFuncEnter,\" enter\");\n// FUNC PhTraceFuncExit{LEVEL=TRACE_LEVEL_VERBOSE,EVENT=PROFILING,EXITFUNC=_traceElapsed}(MSG,...);\n// USESUFFIX(PhTraceFuncExit,\" exit (elapsed=%llu)\",_traceElapsed);\n//\n// end_wpp\n//\n\n#ifdef SI_NO_WPP\n#define PhTracePrint(LEVEL,EVENT,MSG,...) ((void)(MSG, ## __VA_ARGS__))\n#define PhTrace(MSG, ...)                 ((void)(MSG, ## __VA_ARGS__))\n#define PhTraceInfo(MSG, ...)             ((void)(MSG, ## __VA_ARGS__))\n#define PhTraceWarning(MSG, ...)          ((void)(MSG, ## __VA_ARGS__))\n#define PhTraceError(MSG, ...)            ((void)(MSG, ## __VA_ARGS__))\n#define PhTraceFatal(MSG, ...)            ((void)(MSG, ## __VA_ARGS__))\n#define PhTraceFuncEnter(MSG,...)         ((void)(MSG, ## __VA_ARGS__))\n#define PhTraceFuncExit(MSG,...)          ((void)(MSG, ## __VA_ARGS__))\n#define WPP_INIT_TRACING(...)             ((void)0)\n#define WPP_CLEANUP()                     ((void)0)\n#else // SI_NO_WPP\n\n//\n// PhTraceFuncEnter\n//\n#define WPP_LEVEL_EVENT_ENTERFUNC_PRE(level,event,zero)                        \\\nLARGE_INTEGER _traceStart;                                                     \\\nLARGE_INTEGER _traceEnd;                                                       \\\nULONG64 _traceElapsed = 0;                                                     \\\nif (WPP_LEVEL_EVENT_ENABLED(level,event))                                      \\\n{                                                                              \\\n    PhQueryPerformanceCounter(&_traceStart);                                   \\\n}                                                                              \\\nelse                                                                           \\\n{                                                                              \\\n    _traceStart.QuadPart = 0;                                                  \\\n}\n//#define WPP_LEVEL_EVENT_ENTERFUNC_POST(level,event,zero)\n#define WPP_LEVEL_EVENT_ENTERFUNC_ENABLED(level,event,elapsed) WPP_LEVEL_EVENT_ENABLED(level,event)\n#define WPP_LEVEL_EVENT_ENTERFUNC_LOGGER(level,event,elapsed) WPP_LEVEL_EVENT_LOGGER(level,event)\n\n//\n// PhTraceFuncExit\n//\n#define WPP_LEVEL_EVENT_EXITFUNC_PRE(level,event,elapsed)                      \\\nif (WPP_LEVEL_EVENT_ENABLED(level,event))                                      \\\n{                                                                              \\\n    PhQueryPerformanceCounter(&_traceEnd);                                     \\\n    elapsed = _traceEnd.QuadPart - _traceStart.QuadPart;                       \\\n}\n//#define WPP_LEVEL_EVENT_EXITFUNC_POST(level,event,elapsed)\n#define WPP_LEVEL_EVENT_EXITFUNC_ENABLED(level,event,elapsed) WPP_LEVEL_EVENT_ENABLED(level,event)\n#define WPP_LEVEL_EVENT_EXITFUNC_LOGGER(level,event,elapsed) WPP_LEVEL_EVENT_LOGGER(level,event)\n\n#endif // SI_NO_WPP\n\n#define TMH_STRINGIFYX(x) #x\n#define TMH_STRINGIFY(x) TMH_STRINGIFYX(x)\n\n#ifdef TMH_FILE\n#include TMH_STRINGIFY(TMH_FILE)\n#endif\n"
  },
  {
    "path": "phlib/include/treenew.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2008-2016\n *     dmex    2017-2024\n *\n */\n\n#ifndef _PH_TREENEW_H\n#define _PH_TREENEW_H\n\nEXTERN_C_START\n\n#define PH_TREENEW_CLASSNAME L\"PhTreeNew\"\n\ntypedef struct _PH_TREENEW_CREATEPARAMS\n{\n    ULONG Size;\n    COLORREF TextColor;\n    COLORREF FocusColor;\n    COLORREF SelectionColor;\n    ULONG RowHeight;\n    // Add new fields here.\n} PH_TREENEW_CREATEPARAMS, *PPH_TREENEW_CREATEPARAMS;\n\ntypedef struct _PH_TREENEW_COLUMN\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Visible : 1;\n            ULONG CustomDraw : 1;\n            ULONG Fixed : 1; // Whether this is the fixed column\n            ULONG SortDescending : 1; // Sort descending on initial click rather than ascending\n            ULONG DpiScaleOnAdd : 1; // Whether to DPI scale the width (only when adding)\n            ULONG SpareFlags : 27;\n        };\n    };\n    ULONG Id;\n    PVOID Context;\n    PCWSTR Text;\n    LONG Width;\n    ULONG Alignment;\n    ULONG DisplayIndex; // -1 for fixed column or invalid\n\n    ULONG TextFlags;\n\n    struct\n    {\n        LONG ViewIndex; // Actual index in header control\n        LONG ViewX; // 0 for the fixed column, and an offset from the divider for normal columns\n    } s;\n} PH_TREENEW_COLUMN, *PPH_TREENEW_COLUMN;\n\ntypedef struct _PH_TREENEW_NODE\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Visible : 1;\n            ULONG Selected : 1;\n            ULONG Expanded : 1;\n            ULONG UseAutoForeColor : 1;\n            ULONG UseTempBackColor : 1;\n            ULONG Unselectable : 1;\n            ULONG SpareFlags : 26;\n        };\n    };\n\n    COLORREF BackColor;\n    COLORREF ForeColor;\n    COLORREF TempBackColor;\n    HFONT Font;\n    HICON Icon;\n\n    PPH_STRINGREF TextCache;\n    ULONG TextCacheSize;\n\n    ULONG Index; // Index within the flat list\n    ULONG Level; // 0 for root, 1, 2, ...\n\n    struct\n    {\n        union\n        {\n            ULONG Flags2;\n            struct\n            {\n                ULONG IsLeaf : 1;\n                ULONG CachedColorValid : 1;\n                ULONG CachedFontValid : 1;\n                ULONG CachedIconValid : 1;\n                ULONG PlusMinusHot : 1;\n                ULONG SpareFlags2 : 27;\n            };\n        };\n\n        // Temp. drawing data\n        COLORREF DrawBackColor;\n        COLORREF DrawForeColor;\n    } s;\n} PH_TREENEW_NODE, *PPH_TREENEW_NODE;\n\n// Styles\n#define TN_STYLE_ICONS 0x1\n#define TN_STYLE_DOUBLE_BUFFERED 0x2\n#define TN_STYLE_NO_DIVIDER 0x4\n#define TN_STYLE_ANIMATE_DIVIDER 0x8\n#define TN_STYLE_NO_COLUMN_SORT 0x10\n#define TN_STYLE_NO_COLUMN_REORDER 0x20\n#define TN_STYLE_THIN_ROWS 0x40\n#define TN_STYLE_NO_COLUMN_HEADER 0x80\n#define TN_STYLE_CUSTOM_COLORS 0x100\n#define TN_STYLE_ALWAYS_SHOW_SELECTION 0x200\n#define TN_STYLE_CUSTOM_HEADERDRAW 0x400\n#define TN_STYLE_DRAG_REORDER_ROWS 0x800\n\n// Extended flags\n#define TN_FLAG_ITEM_DRAG_SELECT 0x1\n#define TN_FLAG_NO_UNFOLDING_TOOLTIPS 0x2\n\n// Callback flags\n#define TN_CACHE 0x1\n#define TN_AUTO_FORECOLOR 0x1000\n\n// Column display flags\n#define TN_COLUMN_FIXED -2\n\n// Column change flags\n#define TN_COLUMN_CONTEXT 0x1\n#define TN_COLUMN_TEXT 0x2\n#define TN_COLUMN_WIDTH 0x4\n#define TN_COLUMN_ALIGNMENT 0x8\n#define TN_COLUMN_DISPLAYINDEX 0x10\n#define TN_COLUMN_TEXTFLAGS 0x20\n#define TN_COLUMN_FLAG_VISIBLE 0x100000\n#define TN_COLUMN_FLAG_CUSTOMDRAW 0x200000\n#define TN_COLUMN_FLAG_FIXED 0x400000\n#define TN_COLUMN_FLAG_SORTDESCENDING 0x800000\n#define TN_COLUMN_FLAG_NODPISCALEONADD 0x1000000\n#define TN_COLUMN_FLAGS 0xfff00000\n\n// Cache flags\n#define TN_CACHE_COLOR 0x1\n#define TN_CACHE_FONT 0x2\n#define TN_CACHE_ICON 0x4\n\n// Cell part input flags\n#define TN_MEASURE_TEXT 0x1\n\n// Cell part flags\n#define TN_PART_CELL 0x1\n#define TN_PART_PLUSMINUS 0x2\n#define TN_PART_ICON 0x4\n#define TN_PART_CONTENT 0x8\n#define TN_PART_TEXT 0x10\n\n// Hit test input flags\n#define TN_TEST_COLUMN 0x1\n#define TN_TEST_SUBITEM 0x2 // requires TN_TEST_COLUMN\n\n// Hit test flags\n#define TN_HIT_LEFT 0x1\n#define TN_HIT_RIGHT 0x2\n#define TN_HIT_ABOVE 0x4\n#define TN_HIT_BELOW 0x8\n#define TN_HIT_ITEM 0x10\n#define TN_HIT_ITEM_PLUSMINUS 0x20 // requires TN_TEST_SUBITEM\n#define TN_HIT_ITEM_ICON 0x40 // requires TN_TEST_SUBITEM\n#define TN_HIT_ITEM_CONTENT 0x80 // requires TN_TEST_SUBITEM\n#define TN_HIT_DIVIDER 0x100\n\n// Selection flags\n#define TN_SELECT_DESELECT 0x1\n#define TN_SELECT_TOGGLE 0x2\n#define TN_SELECT_RESET 0x4\n\n// Auto-size flags\n#define TN_AUTOSIZE_REMAINING_SPACE 0x1\n\ntypedef struct _PH_TREENEW_VIEW_PARTS\n{\n    RECT ClientRect;\n    LONG HeaderHeight;\n    LONG RowHeight;\n    ULONG VScrollWidth;\n    ULONG HScrollHeight;\n    LONG VScrollPosition;\n    LONG HScrollPosition;\n    LONG FixedWidth;\n    LONG NormalLeft;\n    LONG NormalWidth;\n    ULONG64 ScrollTickCount;\n} PH_TREENEW_VIEW_PARTS, *PPH_TREENEW_VIEW_PARTS;\n\ntypedef struct _PH_TREENEW_CELL_PARTS\n{\n    ULONG Flags;\n    RECT RowRect;\n    RECT CellRect; // TN_PART_CELL\n    RECT PlusMinusRect; // TN_PART_PLUSMINUS\n    RECT IconRect; // TN_PART_ICON\n    RECT ContentRect; // TN_PART_CONTENT\n    RECT TextRect; // TN_PART_TEXT\n    PH_STRINGREF Text; // TN_PART_TEXT\n    HFONT Font; // TN_PART_TEXT\n} PH_TREENEW_CELL_PARTS, *PPH_TREENEW_CELL_PARTS;\n\ntypedef struct _PH_TREENEW_HIT_TEST\n{\n    POINT Point;\n    ULONG InFlags;\n\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column; // requires TN_TEST_COLUMN\n} PH_TREENEW_HIT_TEST, *PPH_TREENEW_HIT_TEST;\n\ntypedef enum _PH_TREENEW_MESSAGE\n{\n    TreeNewGetChildren, // PPH_TREENEW_GET_CHILDREN Parameter1\n    TreeNewIsLeaf, // PPH_TREENEW_IS_LEAF Parameter1\n    TreeNewGetCellText, // PPH_TREENEW_GET_CELL_TEXT Parameter1\n    TreeNewGetNodeColor, // PPH_TREENEW_GET_NODE_COLOR Parameter1\n    TreeNewGetNodeFont, // PPH_TREENEW_GET_NODE_FONT Parameter1\n    TreeNewGetNodeIcon, // PPH_TREENEW_GET_NODE_ICON Parameter1\n    TreeNewGetCellTooltip, // PPH_TREENEW_GET_CELL_TOOLTIP Parameter1\n    TreeNewCustomDraw, // PPH_TREENEW_CUSTOM_DRAW Parameter1\n\n    // Notifications\n    TreeNewNodeExpanding, // PPH_TREENEW_NODE Parameter1, PPH_TREENEW_NODE_EVENT Parameter2\n    TreeNewNodeSelecting, // PPH_TREENEW_NODE Parameter1\n\n    TreeNewSortChanged, // PH_TREENEW_SORT_CHANGED_EVENT Parameter1\n    TreeNewSelectionChanged,\n\n    TreeNewKeyDown, // PPH_TREENEW_KEY_EVENT Parameter1\n    TreeNewLeftClick, // PPH_TREENEW_MOUSE_EVENT Parameter1\n    TreeNewRightClick, // PPH_TREENEW_MOUSE_EVENT Parameter1\n    TreeNewMiddleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1\n    TreeNewLeftDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1\n    TreeNewRightDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1\n    TreeNewContextMenu, // PPH_TREENEW_CONTEXT_MENU Parameter1\n\n    TreeNewHeaderRightClick, // PPH_TREENEW_HEADER_MOUSE_EVENT Parameter1\n    TreeNewIncrementalSearch, // PPH_TREENEW_SEARCH_EVENT Parameter1\n\n    TreeNewColumnResized, // PPH_TREENEW_COLUMN Parameter1\n    TreeNewColumnReordered,\n\n    TreeNewDestroying,\n    TreeNewGetDialogCode, // ULONG Parameter1, PULONG Parameter2\n\n    TreeNewGetHeaderText,\n\n    TreeNewDpiChanged, // PH_TREENEW_DPICHANGED_EVENT Parameter1\n\n    TreeNewReorderBegin,   // PH_TREENEW_REORDER_EVENT (in/out) Parameter1\n    TreeNewReorderOver,    // PH_TREENEW_REORDER_EVENT (in/out) Parameter1\n    TreeNewReorderCommit,  // PH_TREENEW_REORDER_EVENT (in) Parameter1\n    TreeNewReorderCancel,  // PH_TREENEW_REORDER_EVENT (best-effort notify) Parameter1\n\n    MaxTreeNewMessage\n} PH_TREENEW_MESSAGE;\n\ntypedef BOOLEAN _Function_class_(PH_TREENEW_CALLBACK)\nNTAPI PH_TREENEW_CALLBACK(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    );\ntypedef PH_TREENEW_CALLBACK* PPH_TREENEW_CALLBACK;\n\ntypedef struct _PH_TREENEW_GET_CHILDREN\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    ULONG NumberOfChildren;\n    PPH_TREENEW_NODE *Children; // can be NULL if no children\n} PH_TREENEW_GET_CHILDREN, *PPH_TREENEW_GET_CHILDREN;\n\ntypedef struct _PH_TREENEW_IS_LEAF\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    BOOLEAN IsLeaf;\n} PH_TREENEW_IS_LEAF, *PPH_TREENEW_IS_LEAF;\n\ntypedef struct _PH_TREENEW_GET_CELL_TEXT\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n    ULONG Id;\n\n    PH_STRINGREF Text;\n} PH_TREENEW_GET_CELL_TEXT, *PPH_TREENEW_GET_CELL_TEXT;\n\ntypedef struct _PH_TREENEW_GET_NODE_COLOR\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    COLORREF BackColor;\n    COLORREF ForeColor;\n} PH_TREENEW_GET_NODE_COLOR, *PPH_TREENEW_GET_NODE_COLOR;\n\ntypedef struct _PH_TREENEW_GET_NODE_FONT\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    HFONT Font;\n} PH_TREENEW_GET_NODE_FONT, *PPH_TREENEW_GET_NODE_FONT;\n\ntypedef struct _PH_TREENEW_GET_NODE_ICON\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    HICON Icon;\n} PH_TREENEW_GET_NODE_ICON, *PPH_TREENEW_GET_NODE_ICON;\n\ntypedef struct _PH_TREENEW_GET_CELL_TOOLTIP\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column;\n\n    BOOLEAN Unfolding;\n    PH_STRINGREF Text;\n    HFONT Font;\n    ULONG MaximumWidth;\n} PH_TREENEW_GET_CELL_TOOLTIP, *PPH_TREENEW_GET_CELL_TOOLTIP;\n\ntypedef struct _PH_TREENEW_CUSTOM_DRAW\n{\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column;\n\n    HDC Dc;\n    RECT CellRect;\n    RECT TextRect;\n    ULONG Flags;\n} PH_TREENEW_CUSTOM_DRAW, *PPH_TREENEW_CUSTOM_DRAW;\n\ntypedef struct _PH_TREENEW_MOUSE_EVENT\n{\n    POINT Location;\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column;\n    ULONG KeyFlags;\n} PH_TREENEW_MOUSE_EVENT, *PPH_TREENEW_MOUSE_EVENT;\n\ntypedef struct _PH_TREENEW_KEY_EVENT\n{\n    BOOLEAN Handled;\n    BOOLEAN Spare[3];\n    ULONG VirtualKey;\n    ULONG Data;\n} PH_TREENEW_KEY_EVENT, *PPH_TREENEW_KEY_EVENT;\n\ntypedef struct _PH_TREENEW_SORT_CHANGED_EVENT\n{\n    ULONG SortColumn;\n    PH_SORT_ORDER SortOrder;\n} PH_TREENEW_SORT_CHANGED_EVENT, *PPH_TREENEW_SORT_CHANGED_EVENT;\n\ntypedef struct _PH_TREENEW_NODE_EVENT\n{\n    BOOLEAN Handled;\n    BOOLEAN Spare[3];\n    ULONG Flags;\n    PVOID Reserved1;\n    PVOID Reserved2;\n} PH_TREENEW_NODE_EVENT, *PPH_TREENEW_NODE_EVENT;\n\ntypedef struct _PH_TREENEW_CONTEXT_MENU\n{\n    POINT Location;\n    POINT ClientLocation;\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column;\n    BOOLEAN KeyboardInvoked;\n} PH_TREENEW_CONTEXT_MENU, *PPH_TREENEW_CONTEXT_MENU;\n\ntypedef struct _PH_TREENEW_HEADER_MOUSE_EVENT\n{\n    POINT ScreenLocation;\n    POINT Location;\n    POINT HeaderLocation;\n    PPH_TREENEW_COLUMN Column;\n} PH_TREENEW_HEADER_MOUSE_EVENT, *PPH_TREENEW_HEADER_MOUSE_EVENT;\n\n#define PH_TREENEW_SEARCH_TIMEOUT 1000\n#define PH_TREENEW_SEARCH_MAXIMUM_LENGTH 1023\n\ntypedef struct _PH_TREENEW_SEARCH_EVENT\n{\n    LONG FoundIndex;\n    LONG StartIndex;\n    PH_STRINGREF String;\n} PH_TREENEW_SEARCH_EVENT, *PPH_TREENEW_SEARCH_EVENT;\n\n#define PH_TREENEW_HEADER_TEXT_SIZE_MAX 0x40\n\ntypedef struct _PH_TREENEW_GET_HEADER_TEXT\n{\n    PPH_TREENEW_COLUMN Column;\n    PH_STRINGREF Text;\n    PWSTR TextCache;\n    ULONG TextCacheSize;\n} PH_TREENEW_GET_HEADER_TEXT, *PPH_TREENEW_GET_HEADER_TEXT;\n\ntypedef struct _PH_TREENEW_SET_HEADER_CACHE\n{\n    ULONG HeaderTreeColumnMax;\n    PVOID HeaderTreeColumnStringCache;\n    PVOID HeaderTreeColumnTextCache;\n} PH_TREENEW_SET_HEADER_CACHE, *PPH_TREENEW_SET_HEADER_CACHE;\n\ntypedef struct _PH_TREENEW_DPICHANGED_EVENT\n{\n    LONG OldWindowDpi;\n    LONG NewWindowDpi;\n} PH_TREENEW_DPICHANGED_EVENT, *PPH_TREENEW_DPICHANGED_EVENT;\n\ntypedef struct _PH_TREENEW_REORDER_EVENT\n{\n    PPH_TREENEW_NODE Source; // node being dragged\n    PPH_TREENEW_NODE Target; // node at drop caret (may be NULL if empty area)\n    BOOLEAN DropAfter; // TRUE = insert after Target; FALSE = before Target\n    BOOLEAN Allow; // in Begin/Over: host sets to TRUE to allow; Commit ignores this field\n} PH_TREENEW_REORDER_EVENT, *PPH_TREENEW_REORDER_EVENT;\n\ntypedef struct _PH_TREENEW_GET_CELL_PARTS\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column;\n    PH_TREENEW_CELL_PARTS Parts;\n} PH_TREENEW_GET_CELL_PARTS, *PPH_TREENEW_GET_CELL_PARTS;\n\n#define TNM_FIRST (WM_USER + 1)\n#define TNM_SETCALLBACK (WM_USER + 1)\n#define TNM_NODESADDED (WM_USER + 2) // unimplemented\n#define TNM_NODESREMOVED (WM_USER + 3) // unimplemented\n#define TNM_NODESSTRUCTURED (WM_USER + 4)\n#define TNM_ADDCOLUMN (WM_USER + 5)\n#define TNM_REMOVECOLUMN (WM_USER + 6)\n#define TNM_GETCOLUMN (WM_USER + 7)\n#define TNM_SETCOLUMN (WM_USER + 8)\n#define TNM_GETCOLUMNORDERARRAY (WM_USER + 9)\n#define TNM_SETCOLUMNORDERARRAY (WM_USER + 10)\n#define TNM_SETCURSOR (WM_USER + 11)\n#define TNM_GETSORT (WM_USER + 12)\n#define TNM_SETSORT (WM_USER + 13)\n#define TNM_SETTRISTATE (WM_USER + 14)\n#define TNM_ENSUREVISIBLE (WM_USER + 15)\n#define TNM_SCROLL (WM_USER + 16)\n#define TNM_GETFLATNODECOUNT (WM_USER + 17)\n#define TNM_GETFLATNODE (WM_USER + 18)\n#define TNM_GETCELLTEXT (WM_USER + 19)\n#define TNM_SETNODEEXPANDED (WM_USER + 20)\n#define TNM_GETMAXID (WM_USER + 21)\n#define TNM_SETMAXID (WM_USER + 22)\n#define TNM_INVALIDATENODE (WM_USER + 23)\n#define TNM_INVALIDATENODES (WM_USER + 24)\n#define TNM_GETFIXEDHEADER (WM_USER + 25)\n#define TNM_GETHEADER (WM_USER + 26)\n#define TNM_GETTOOLTIPS (WM_USER + 27)\n#define TNM_SELECTRANGE (WM_USER + 28)\n#define TNM_DESELECTRANGE (WM_USER + 29)\n#define TNM_GETCOLUMNCOUNT (WM_USER + 30)\n#define TNM_SETREDRAW (WM_USER + 31)\n#define TNM_GETVIEWPARTS (WM_USER + 32)\n#define TNM_GETFIXEDCOLUMN (WM_USER + 33)\n#define TNM_GETFIRSTCOLUMN (WM_USER + 34)\n#define TNM_SETFOCUSNODE (WM_USER + 35)\n#define TNM_SETMARKNODE (WM_USER + 36)\n#define TNM_SETHOTNODE (WM_USER + 37)\n#define TNM_SETEXTENDEDFLAGS (WM_USER + 38)\n#define TNM_GETCALLBACK (WM_USER + 39)\n#define TNM_HITTEST (WM_USER + 40)\n#define TNM_GETVISIBLECOLUMNCOUNT (WM_USER + 41)\n#define TNM_AUTOSIZECOLUMN (WM_USER + 42)\n#define TNM_SETEMPTYTEXT (WM_USER + 43)\n#define TNM_SETROWHEIGHT (WM_USER + 44)\n#define TNM_ISFLATNODEVALID (WM_USER + 45)\n#define TNM_THEMESUPPORT (WM_USER + 46)\n#define TNM_SETIMAGELIST (WM_USER + 47)\n#define TNM_SETCOLUMNTEXTCACHE (WM_USER + 48)\n#define TNM_ENSUREVISIBLEINDEX (WM_USER + 49)\n#define TNM_GETVISIBLECOLUMN (WM_USER + 50)\n#define TNM_GETVISIBLECOLUMNARRAY (WM_USER + 51)\n#define TNM_GETSELECTEDCOUNT (WM_USER + 52)\n#define TNM_GETSELECTEDNODE (WM_USER + 53)\n#define TNM_FOCUSMARKSELECT (WM_USER + 54)\n#define TNM_FOCUSVISIBLENODE (WM_USER + 55)\n#define TNM_GETCELLPARTS (WM_USER + 56)\n#define TNM_LAST (WM_USER + 57)\n\n#if defined(_PHLIB_)\n\nEXTERN_C LRESULT PhTnSendMessage(\n    _In_ HWND WindowHandle,\n    _In_ ULONG WindowMessage,\n    _Pre_maybenull_ _Post_valid_ WPARAM wParam,\n    _Pre_maybenull_ _Post_valid_ LPARAM lParam\n    );\n\n#define TreeNew_SetCallback(hWnd, Callback, Context) \\\n    PhTnSendMessage((hWnd), TNM_SETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback))\n \n#define TreeNew_NodesStructured(hWnd) \\\n    PhTnSendMessage((hWnd), TNM_NODESSTRUCTURED, 0, 0)\n \n#define TreeNew_AddColumn(hWnd, Column) \\\n    PhTnSendMessage((hWnd), TNM_ADDCOLUMN, 0, (LPARAM)(Column))\n \n#define TreeNew_RemoveColumn(hWnd, Id) \\\n    PhTnSendMessage((hWnd), TNM_REMOVECOLUMN, (WPARAM)(Id), 0)\n \n#define TreeNew_GetColumn(hWnd, Id, Column) \\\n    PhTnSendMessage((hWnd), TNM_GETCOLUMN, (WPARAM)(Id), (LPARAM)(Column))\n \n#define TreeNew_SetColumn(hWnd, Mask, Column) \\\n    PhTnSendMessage((hWnd), TNM_SETCOLUMN, (WPARAM)(Mask), (LPARAM)(Column))\n \n#define TreeNew_GetColumnOrderArray(hWnd, Count, Array) \\\n    PhTnSendMessage((hWnd), TNM_GETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array))\n \n#define TreeNew_SetColumnOrderArray(hWnd, Count, Array) \\\n    PhTnSendMessage((hWnd), TNM_SETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array))\n \n#define TreeNew_SetCursor(hWnd, Cursor) \\\n    PhTnSendMessage((hWnd), TNM_SETCURSOR, 0, (LPARAM)(Cursor))\n \n#define TreeNew_GetSort(hWnd, Column, Order) \\\n    PhTnSendMessage((hWnd), TNM_GETSORT, (WPARAM)(Column), (LPARAM)(Order))\n \n#define TreeNew_SetSort(hWnd, Column, Order) \\\n    PhTnSendMessage((hWnd), TNM_SETSORT, (WPARAM)(Column), (LPARAM)(Order))\n \n#define TreeNew_SetTriState(hWnd, TriState) \\\n    PhTnSendMessage((hWnd), TNM_SETTRISTATE, (WPARAM)(TriState), 0)\n \n#define TreeNew_EnsureVisible(hWnd, Node) \\\n    PhTnSendMessage((hWnd), TNM_ENSUREVISIBLE, 0, (LPARAM)(Node))\n \n#define TreeNew_Scroll(hWnd, DeltaRows, DeltaX) \\\n    PhTnSendMessage((hWnd), TNM_SCROLL, (WPARAM)(DeltaRows), (LPARAM)(DeltaX))\n \n#define TreeNew_GetFlatNodeCount(hWnd) \\\n    ((ULONG)PhTnSendMessage((hWnd), TNM_GETFLATNODECOUNT, 0, 0))\n \n#define TreeNew_GetFlatNode(hWnd, Index) \\\n    ((PPH_TREENEW_NODE)PhTnSendMessage((hWnd), TNM_GETFLATNODE, (WPARAM)(Index), 0))\n \n#define TreeNew_GetCellText(hWnd, GetCellText) \\\n    PhTnSendMessage((hWnd), TNM_GETCELLTEXT, 0, (LPARAM)(GetCellText))\n \n#define TreeNew_SetNodeExpanded(hWnd, Node, Expanded) \\\n    PhTnSendMessage((hWnd), TNM_SETNODEEXPANDED, (WPARAM)(Expanded), (LPARAM)(Node))\n \n#define TreeNew_GetMaxId(hWnd) \\\n    ((ULONG)PhTnSendMessage((hWnd), TNM_GETMAXID, 0, 0))\n \n#define TreeNew_SetMaxId(hWnd, MaxId) \\\n    PhTnSendMessage((hWnd), TNM_SETMAXID, (WPARAM)(MaxId), 0)\n \n#define TreeNew_InvalidateNode(hWnd, Node) \\\n    PhTnSendMessage((hWnd), TNM_INVALIDATENODE, 0, (LPARAM)(Node))\n \n#define TreeNew_InvalidateNodes(hWnd, Start, End) \\\n    PhTnSendMessage((hWnd), TNM_INVALIDATENODES, (WPARAM)(Start), (LPARAM)(End))\n \n#define TreeNew_GetFixedHeader(hWnd) \\\n    ((HWND)PhTnSendMessage((hWnd), TNM_GETFIXEDHEADER, 0, 0))\n \n#define TreeNew_GetHeader(hWnd) \\\n    ((HWND)PhTnSendMessage((hWnd), TNM_GETHEADER, 0, 0))\n \n#define TreeNew_GetTooltips(hWnd) \\\n    ((HWND)PhTnSendMessage((hWnd), TNM_GETTOOLTIPS, 0, 0))\n \n#define TreeNew_SelectRange(hWnd, Start, End) \\\n    PhTnSendMessage((hWnd), TNM_SELECTRANGE, (WPARAM)(Start), (LPARAM)(End))\n \n#define TreeNew_DeselectRange(hWnd, Start, End) \\\n    PhTnSendMessage((hWnd), TNM_DESELECTRANGE, (WPARAM)(Start), (LPARAM)(End))\n \n#define TreeNew_GetColumnCount(hWnd) \\\n    ((ULONG)PhTnSendMessage((hWnd), TNM_GETCOLUMNCOUNT, 0, 0))\n \n#define TreeNew_SetRedraw(hWnd, Redraw) \\\n    ((LONG)PhTnSendMessage((hWnd), TNM_SETREDRAW, (WPARAM)(Redraw), 0))\n \n#define TreeNew_GetViewParts(hWnd, Parts) \\\n    PhTnSendMessage((hWnd), TNM_GETVIEWPARTS, 0, (LPARAM)(Parts))\n \n#define TreeNew_GetFixedColumn(hWnd) \\\n    ((PPH_TREENEW_COLUMN)PhTnSendMessage((hWnd), TNM_GETFIXEDCOLUMN, 0, 0))\n \n#define TreeNew_GetFirstColumn(hWnd) \\\n    ((PPH_TREENEW_COLUMN)PhTnSendMessage((hWnd), TNM_GETFIRSTCOLUMN, 0, 0))\n \n#define TreeNew_SetFocusNode(hWnd, Node) \\\n    PhTnSendMessage((hWnd), TNM_SETFOCUSNODE, 0, (LPARAM)(Node))\n \n#define TreeNew_SetMarkNode(hWnd, Node) \\\n    PhTnSendMessage((hWnd), TNM_SETMARKNODE, 0, (LPARAM)(Node))\n \n#define TreeNew_SetHotNode(hWnd, Node) \\\n    PhTnSendMessage((hWnd), TNM_SETHOTNODE, 0, (LPARAM)(Node))\n \n#define TreeNew_SetExtendedFlags(hWnd, Mask, Value) \\\n    PhTnSendMessage((hWnd), TNM_SETEXTENDEDFLAGS, (WPARAM)(Mask), (LPARAM)(Value))\n \n#define TreeNew_GetCallback(hWnd, Callback, Context) \\\n    PhTnSendMessage((hWnd), TNM_GETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback))\n \n#define TreeNew_HitTest(hWnd, HitTest) \\\n    PhTnSendMessage((hWnd), TNM_HITTEST, 0, (LPARAM)(HitTest))\n \n#define TreeNew_GetVisibleColumnCount(hWnd) \\\n    ((ULONG)PhTnSendMessage((hWnd), TNM_GETVISIBLECOLUMNCOUNT, 0, 0))\n \n#define TreeNew_AutoSizeColumn(hWnd, Id, Flags) \\\n    PhTnSendMessage((hWnd), TNM_AUTOSIZECOLUMN, (WPARAM)(Id), (LPARAM)(Flags))\n \n#define TreeNew_SetEmptyText(hWnd, Text, Flags) \\\n    PhTnSendMessage((hWnd), TNM_SETEMPTYTEXT, (WPARAM)(Flags), (LPARAM)(Text))\n \n#define TreeNew_SetRowHeight(hWnd, RowHeight) \\\n    PhTnSendMessage((hWnd), TNM_SETROWHEIGHT, (WPARAM)(RowHeight), 0)\n \n#define TreeNew_IsFlatNodeValid(hWnd) \\\n    ((BOOLEAN)PhTnSendMessage((hWnd), TNM_ISFLATNODEVALID, 0, 0))\n \n#define TreeNew_ThemeSupport(hWnd, Enable) \\\n    PhTnSendMessage((hWnd), TNM_THEMESUPPORT, (WPARAM)(Enable), 0)\n \n#define TreeNew_SetImageList(hWnd, ImageListHandle) \\\n    PhTnSendMessage((hWnd), TNM_SETIMAGELIST, (WPARAM)(ImageListHandle), 0)\n \n#define TreeNew_SetColumnTextCache(hWnd, Cache) \\\n    PhTnSendMessage((hWnd), TNM_SETCOLUMNTEXTCACHE, (WPARAM)(Cache), 0)\n \n#define TreeNew_EnsureVisibleIndex(hWnd, Index) \\\n    PhTnSendMessage((hWnd), TNM_ENSUREVISIBLEINDEX, 0, (LPARAM)(Index))\n \n#define TreeNew_GetVisibleColumn(hWnd, Index, Column) \\\n    PhTnSendMessage((hWnd), TNM_GETVISIBLECOLUMN, (WPARAM)(Index), (LPARAM)(Column))\n \n#define TreeNew_GetVisibleColumnArray(hWnd, Count, ColumnArray) \\\n    ((BOOLEAN)PhTnSendMessage((hWnd), TNM_GETVISIBLECOLUMNARRAY, (WPARAM)(Count), (LPARAM)(ColumnArray)))\n\n#define TreeNew_GetSelectedNodeCount(hWnd) \\\n    ((ULONG)PhTnSendMessage((hWnd), TNM_GETSELECTEDCOUNT, 0, 0))\n\n#define TreeNew_GetSelectedNode(hWnd) \\\n    ((PPH_TREENEW_NODE)PhTnSendMessage((hWnd), TNM_GETSELECTEDNODE, 0, 0))\n\n#define TreeNew_GetVisibleNode(hWnd) \\\n    ((PPH_TREENEW_NODE)PhTnSendMessage((hWnd), TNM_GETSELECTEDNODE, 0, 0))\n\n#define TreeNew_FocusMarkSelectNode(hWnd, Node) \\\n    PhTnSendMessage((hWnd), TNM_FOCUSMARKSELECT, 0, (LPARAM)(Node))\n\n#define TreeNew_SelectFirstVisibleNode(hWnd) \\\n    PhTnSendMessage((hWnd), TNM_FOCUSVISIBLENODE, 0, 0)\n\n#define TreeNew_GetCellParts(hWnd, Parts) \\\n    ((BOOLEAN)PhTnSendMessage((hWnd), TNM_GETCELLPARTS, 0, (LPARAM)(Parts)))\n\n#else\n\n#define TreeNew_SetCallback(hWnd, Callback, Context) \\\n    SendMessage((hWnd), TNM_SETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback))\n\n#define TreeNew_NodesStructured(hWnd) \\\n    SendMessage((hWnd), TNM_NODESSTRUCTURED, 0, 0)\n\n#define TreeNew_AddColumn(hWnd, Column) \\\n    SendMessage((hWnd), TNM_ADDCOLUMN, 0, (LPARAM)(Column))\n\n#define TreeNew_RemoveColumn(hWnd, Id) \\\n    SendMessage((hWnd), TNM_REMOVECOLUMN, (WPARAM)(Id), 0)\n\n#define TreeNew_GetColumn(hWnd, Id, Column) \\\n    SendMessage((hWnd), TNM_GETCOLUMN, (WPARAM)(Id), (LPARAM)(Column))\n\n#define TreeNew_SetColumn(hWnd, Mask, Column) \\\n    SendMessage((hWnd), TNM_SETCOLUMN, (WPARAM)(Mask), (LPARAM)(Column))\n\n#define TreeNew_GetColumnOrderArray(hWnd, Count, Array) \\\n    SendMessage((hWnd), TNM_GETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array))\n\n#define TreeNew_SetColumnOrderArray(hWnd, Count, Array) \\\n    SendMessage((hWnd), TNM_SETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array))\n\n#define TreeNew_SetCursor(hWnd, Cursor) \\\n    SendMessage((hWnd), TNM_SETCURSOR, 0, (LPARAM)(Cursor))\n\n#define TreeNew_GetSort(hWnd, Column, Order) \\\n    SendMessage((hWnd), TNM_GETSORT, (WPARAM)(Column), (LPARAM)(Order))\n\n#define TreeNew_SetSort(hWnd, Column, Order) \\\n    SendMessage((hWnd), TNM_SETSORT, (WPARAM)(Column), (LPARAM)(Order))\n\n#define TreeNew_SetTriState(hWnd, TriState) \\\n    SendMessage((hWnd), TNM_SETTRISTATE, (WPARAM)(TriState), 0)\n\n#define TreeNew_EnsureVisible(hWnd, Node) \\\n    SendMessage((hWnd), TNM_ENSUREVISIBLE, 0, (LPARAM)(Node))\n\n#define TreeNew_Scroll(hWnd, DeltaRows, DeltaX) \\\n    SendMessage((hWnd), TNM_SCROLL, (WPARAM)(DeltaRows), (LPARAM)(DeltaX))\n\n#define TreeNew_GetFlatNodeCount(hWnd) \\\n    ((ULONG)SendMessage((hWnd), TNM_GETFLATNODECOUNT, 0, 0))\n\n#define TreeNew_GetFlatNode(hWnd, Index) \\\n    ((PPH_TREENEW_NODE)SendMessage((hWnd), TNM_GETFLATNODE, (WPARAM)(Index), 0))\n\n#define TreeNew_GetCellText(hWnd, GetCellText) \\\n    SendMessage((hWnd), TNM_GETCELLTEXT, 0, (LPARAM)(GetCellText))\n\n#define TreeNew_SetNodeExpanded(hWnd, Node, Expanded) \\\n    SendMessage((hWnd), TNM_SETNODEEXPANDED, (WPARAM)(Expanded), (LPARAM)(Node))\n\n#define TreeNew_GetMaxId(hWnd) \\\n    ((ULONG)SendMessage((hWnd), TNM_GETMAXID, 0, 0))\n\n#define TreeNew_SetMaxId(hWnd, MaxId) \\\n    SendMessage((hWnd), TNM_SETMAXID, (WPARAM)(MaxId), 0)\n\n#define TreeNew_InvalidateNode(hWnd, Node) \\\n    SendMessage((hWnd), TNM_INVALIDATENODE, 0, (LPARAM)(Node))\n\n#define TreeNew_InvalidateNodes(hWnd, Start, End) \\\n    SendMessage((hWnd), TNM_INVALIDATENODES, (WPARAM)(Start), (LPARAM)(End))\n\n#define TreeNew_GetFixedHeader(hWnd) \\\n    ((HWND)SendMessage((hWnd), TNM_GETFIXEDHEADER, 0, 0))\n\n#define TreeNew_GetHeader(hWnd) \\\n    ((HWND)SendMessage((hWnd), TNM_GETHEADER, 0, 0))\n\n#define TreeNew_GetTooltips(hWnd) \\\n    ((HWND)SendMessage((hWnd), TNM_GETTOOLTIPS, 0, 0))\n\n#define TreeNew_SelectRange(hWnd, Start, End) \\\n    SendMessage((hWnd), TNM_SELECTRANGE, (WPARAM)(Start), (LPARAM)(End))\n\n#define TreeNew_DeselectRange(hWnd, Start, End) \\\n    SendMessage((hWnd), TNM_DESELECTRANGE, (WPARAM)(Start), (LPARAM)(End))\n\n#define TreeNew_GetColumnCount(hWnd) \\\n    ((ULONG)SendMessage((hWnd), TNM_GETCOLUMNCOUNT, 0, 0))\n\n#define TreeNew_SetRedraw(hWnd, Redraw) \\\n    ((LONG)SendMessage((hWnd), TNM_SETREDRAW, (WPARAM)(Redraw), 0))\n\n#define TreeNew_GetViewParts(hWnd, Parts) \\\n    SendMessage((hWnd), TNM_GETVIEWPARTS, 0, (LPARAM)(Parts))\n\n#define TreeNew_GetFixedColumn(hWnd) \\\n    ((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIXEDCOLUMN, 0, 0))\n\n#define TreeNew_GetFirstColumn(hWnd) \\\n    ((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIRSTCOLUMN, 0, 0))\n\n#define TreeNew_SetFocusNode(hWnd, Node) \\\n    SendMessage((hWnd), TNM_SETFOCUSNODE, 0, (LPARAM)(Node))\n\n#define TreeNew_SetMarkNode(hWnd, Node) \\\n    SendMessage((hWnd), TNM_SETMARKNODE, 0, (LPARAM)(Node))\n\n#define TreeNew_SetHotNode(hWnd, Node) \\\n    SendMessage((hWnd), TNM_SETHOTNODE, 0, (LPARAM)(Node))\n\n#define TreeNew_SetExtendedFlags(hWnd, Mask, Value) \\\n    SendMessage((hWnd), TNM_SETEXTENDEDFLAGS, (WPARAM)(Mask), (LPARAM)(Value))\n\n#define TreeNew_GetCallback(hWnd, Callback, Context) \\\n    SendMessage((hWnd), TNM_GETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback))\n\n#define TreeNew_HitTest(hWnd, HitTest) \\\n    SendMessage((hWnd), TNM_HITTEST, 0, (LPARAM)(HitTest))\n\n#define TreeNew_GetVisibleColumnCount(hWnd) \\\n    ((ULONG)SendMessage((hWnd), TNM_GETVISIBLECOLUMNCOUNT, 0, 0))\n\n#define TreeNew_AutoSizeColumn(hWnd, Id, Flags) \\\n    SendMessage((hWnd), TNM_AUTOSIZECOLUMN, (WPARAM)(Id), (LPARAM)(Flags))\n\n#define TreeNew_SetEmptyText(hWnd, Text, Flags) \\\n    SendMessage((hWnd), TNM_SETEMPTYTEXT, (WPARAM)(Flags), (LPARAM)(Text))\n\n#define TreeNew_SetRowHeight(hWnd, RowHeight) \\\n    SendMessage((hWnd), TNM_SETROWHEIGHT, (WPARAM)(RowHeight), 0)\n\n#define TreeNew_IsFlatNodeValid(hWnd) \\\n    ((BOOLEAN)SendMessage((hWnd), TNM_ISFLATNODEVALID, 0, 0))\n\n#define TreeNew_ThemeSupport(hWnd, Enable) \\\n    SendMessage((hWnd), TNM_THEMESUPPORT, (WPARAM)(Enable), 0)\n\n#define TreeNew_SetImageList(hWnd, ImageListHandle) \\\n    SendMessage((hWnd), TNM_SETIMAGELIST, (WPARAM)(ImageListHandle), 0)\n\n#define TreeNew_SetColumnTextCache(hWnd, Cache) \\\n    SendMessage((hWnd), TNM_SETCOLUMNTEXTCACHE, (WPARAM)(Cache), 0)\n\n#define TreeNew_EnsureVisibleIndex(hWnd, Index) \\\n    SendMessage((hWnd), TNM_ENSUREVISIBLEINDEX, 0, (LPARAM)(Index))\n\n#define TreeNew_GetVisibleColumn(hWnd, Index, Column) \\\n    SendMessage((hWnd), TNM_GETVISIBLECOLUMN, (WPARAM)(Index), (LPARAM)(Column))\n\n#define TreeNew_GetVisibleColumnArray(hWnd, Count, ColumnArray) \\\n    ((BOOLEAN)SendMessage((hWnd), TNM_GETVISIBLECOLUMNARRAY, (WPARAM)(Count), (LPARAM)(ColumnArray)))\n\n#define TreeNew_GetSelectedNodeCount(hWnd) \\\n    ((ULONG)SendMessage((hWnd), TNM_GETSELECTEDCOUNT, 0, 0))\n\n#define TreeNew_GetSelectedNode(hWnd) \\\n    ((PPH_TREENEW_NODE)SendMessage((hWnd), TNM_GETSELECTEDNODE, 0, 0))\n\n#define TreeNew_FocusMarkSelectNode(hWnd, Node) \\\n    SendMessage((hWnd), TNM_FOCUSMARKSELECT, 0, (LPARAM)(Node))\n\n#define TreeNew_SelectFirstVisibleNode(hWnd) \\\n    SendMessage((hWnd), TNM_FOCUSVISIBLENODE, 0, 0)\n\n#define TreeNew_GetCellParts(hWnd, Parts) \\\n    SendMessage((hWnd), TNM_GETCELLPARTS, 0, (LPARAM)(Parts))\n#endif\n\nPHLIBAPI\nRTL_ATOM\nNTAPI\nPhTreeNewInitialization(\n    VOID\n    );\n\nFORCEINLINE VOID PhInitializeTreeNewNode(\n    _In_ PPH_TREENEW_NODE Node\n    )\n{\n    memset(Node, 0, sizeof(PH_TREENEW_NODE));\n\n    Node->Visible = TRUE;\n    Node->Expanded = TRUE;\n}\n\nFORCEINLINE VOID PhInvalidateTreeNewNode(\n    _Inout_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Flags\n    )\n{\n    if (Flags & TN_CACHE_COLOR)\n        Node->s.CachedColorValid = FALSE;\n    if (Flags & TN_CACHE_FONT)\n        Node->s.CachedFontValid = FALSE;\n    if (Flags & TN_CACHE_ICON)\n        Node->s.CachedIconValid = FALSE;\n}\n\nFORCEINLINE BOOLEAN PhAddTreeNewColumn(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id,\n    _In_ BOOLEAN Visible,\n    _In_ PCWSTR Text,\n    _In_ ULONG Width,\n    _In_ ULONG Alignment,\n    _In_ ULONG DisplayIndex,\n    _In_ ULONG TextFlags\n    )\n{\n    PH_TREENEW_COLUMN column;\n\n    memset(&column, 0, sizeof(PH_TREENEW_COLUMN));\n    column.Id = Id;\n    column.Visible = Visible;\n    column.Text = Text;\n    column.Width = Width;\n    column.Alignment = Alignment;\n    column.DisplayIndex = DisplayIndex;\n    column.TextFlags = TextFlags;\n    column.DpiScaleOnAdd = TRUE;\n\n    if (DisplayIndex == -2)\n        column.Fixed = TRUE;\n\n    return !!TreeNew_AddColumn(WindowHandle, &column);\n}\n\nFORCEINLINE BOOLEAN PhAddTreeNewColumnEx(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id,\n    _In_ BOOLEAN Visible,\n    _In_ PCWSTR Text,\n    _In_ ULONG Width,\n    _In_ ULONG Alignment,\n    _In_ ULONG DisplayIndex,\n    _In_ ULONG TextFlags,\n    _In_ BOOLEAN SortDescending\n    )\n{\n    PH_TREENEW_COLUMN column;\n\n    memset(&column, 0, sizeof(PH_TREENEW_COLUMN));\n    column.Id = Id;\n    column.Visible = Visible;\n    column.Text = Text;\n    column.Width = Width;\n    column.Alignment = Alignment;\n    column.DisplayIndex = DisplayIndex;\n    column.TextFlags = TextFlags;\n    column.DpiScaleOnAdd = TRUE;\n\n    if (DisplayIndex == -2)\n        column.Fixed = TRUE;\n    if (SortDescending)\n        column.SortDescending = TRUE;\n\n    return !!TreeNew_AddColumn(WindowHandle, &column);\n}\n\nFORCEINLINE BOOLEAN PhAddTreeNewColumnEx2(\n    _In_ HWND WindowHandle,\n    _In_ ULONG Id,\n    _In_ BOOLEAN Visible,\n    _In_ PCWSTR Text,\n    _In_ ULONG Width,\n    _In_ ULONG Alignment,\n    _In_ ULONG DisplayIndex,\n    _In_ ULONG TextFlags,\n    _In_ ULONG ExtraFlags\n    )\n{\n    PH_TREENEW_COLUMN column;\n\n    memset(&column, 0, sizeof(PH_TREENEW_COLUMN));\n    column.Id = Id;\n    column.Visible = Visible;\n    column.Text = Text;\n    column.Width = Width;\n    column.Alignment = Alignment;\n    column.DisplayIndex = DisplayIndex;\n    column.TextFlags = TextFlags;\n\n    if (DisplayIndex == -2)\n        column.Fixed = TRUE;\n    if (ExtraFlags & TN_COLUMN_FLAG_CUSTOMDRAW)\n        column.CustomDraw = TRUE;\n    if (ExtraFlags & TN_COLUMN_FLAG_SORTDESCENDING)\n        column.SortDescending = TRUE;\n    if (!(ExtraFlags & TN_COLUMN_FLAG_NODPISCALEONADD))\n        column.DpiScaleOnAdd = TRUE;\n\n    return !!TreeNew_AddColumn(WindowHandle, &column);\n}\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/treenewp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_TREENEWP_H\n#define _PH_TREENEWP_H\n\n// Important notes about pointers:\n//\n// All memory allocation for nodes and strings is handled by the user. This usually means there is a\n// very limited time during which they can be safely accessed.\n//\n// Node pointers are valid through the duration of message processing, and also up to the next\n// restructure operation, either user- or control- initiated. This means that state such as the\n// focused node, hot node and mark node must be carefully preserved through restructuring. If\n// restructuring is suspended by a set-redraw call, all nodes must be considered invalid and no user\n// input can be handled.\n//\n// Strings are valid only through the duration of message processing.\n\ntypedef struct _PH_TREENEW_CONTEXT\n{\n    HWND Handle;\n    PVOID InstanceHandle;\n    HWND FixedHeaderHandle;\n    HWND HeaderHandle;\n    HWND VScrollHandle;\n    HWND HScrollHandle;\n    HWND FillerBoxHandle;\n    HWND TooltipsHandle;\n\n    union\n    {\n        struct\n        {\n            ULONG FontOwned : 1;\n            ULONG Tracking : 1; // tracking for fixed divider\n            ULONG VScrollVisible : 1;\n            ULONG HScrollVisible : 1;\n            ULONG FixedColumnVisible : 1;\n            ULONG FixedDividerVisible : 1;\n            ULONG AnimateDivider : 1;\n            ULONG AnimateDividerFadingIn : 1;\n            ULONG AnimateDividerFadingOut : 1;\n            ULONG CanAnyExpand : 1;\n            ULONG TriState : 1;\n            ULONG HasFocus : 1;\n            ULONG ThemeInitialized : 1; // delay load theme data\n            ULONG ThemeActive : 1;\n            ULONG ThemeHasItemBackground : 1;\n            ULONG ThemeHasGlyph : 1;\n            ULONG ThemeHasHotGlyph : 1;\n            ULONG FocusNodeFound : 1; // used to preserve the focused node across restructuring\n            ULONG SearchFailed : 1; // used to prevent multiple beeps\n            ULONG SearchSingleCharMode : 1; // LV style single-character search\n            ULONG TooltipUnfolding : 1; // whether the current tooltip is unfolding\n            ULONG DoubleBuffered : 1;\n            ULONG SuspendUpdateStructure : 1;\n            ULONG SuspendUpdateLayout : 1;\n            ULONG SuspendUpdateMoveMouse : 1;\n            ULONG DragSelectionActive : 1;\n            ULONG SelectionRectangleAlpha : 1; // use alpha blending for the selection rectangle\n            ULONG CustomRowHeight : 1;\n            ULONG CustomColors : 1;\n            ULONG ContextMenuActive : 1;\n            ULONG ThemeSupport : 1;\n            ULONG ImageListSupport : 1;\n        };\n        ULONG Flags;\n    };\n    ULONG Style;\n    ULONG ExtendedStyle;\n    ULONG ExtendedFlags;\n\n    HFONT Font;\n    HCURSOR Cursor;\n\n    RECT ClientRect;\n    LONG HeaderHeight;\n    LONG RowHeight;\n    LONG VScrollWidth;\n    LONG HScrollHeight;\n    LONG VScrollPosition;\n    LONG HScrollPosition;\n    LONG FixedWidth; // width of the fixed part of the tree list\n    LONG FixedWidthMinimum;\n    LONG NormalLeft; // FixedWidth + 1 if there is a fixed column, otherwise 0\n\n    LONG WheelScrollLines;\n    LONG TextMarginPadding;\n    LONG CellMarginLeft;\n    LONG CellMarginRight;\n    LONG IconRightPadding;\n    LONG HeaderTextPadding;\n    LONG HeaderTextMargin;\n    LONG HeaderRowMargin;\n\n    PPH_TREENEW_NODE FocusNode;\n    ULONG HotNodeIndex;\n    ULONG MarkNodeIndex; // selection mark\n\n    ULONG MouseDownLast;\n    POINT MouseDownLocation;\n    POINT MouseLocation;\n\n    PPH_TREENEW_CALLBACK Callback;\n    PVOID CallbackContext;\n\n    PPH_TREENEW_COLUMN *Columns; // columns, indexed by ID\n    ULONG NextId;\n    ULONG AllocatedColumns;\n    ULONG NumberOfColumns; // just a statistic; do not use for actual logic\n\n    PPH_TREENEW_COLUMN *ColumnsByDisplay; // columns, indexed by display order (excluding the fixed column)\n    ULONG AllocatedColumnsByDisplay;\n    ULONG NumberOfColumnsByDisplay; // the number of visible columns (excluding the fixed column)\n    LONG TotalViewX; // total width of normal columns\n    PPH_TREENEW_COLUMN FixedColumn;\n    PPH_TREENEW_COLUMN FirstColumn; // first column, by display order (including the fixed column)\n    PPH_TREENEW_COLUMN LastColumn; // last column, by display order (including the fixed column)\n\n    PPH_TREENEW_COLUMN ResizingColumn;\n    LONG OldColumnWidth;\n    LONG TrackStartX;\n    LONG TrackOldFixedWidth;\n    ULONG DividerHot; // 0 for un-hot, 100 for completely hot\n\n    PPH_LIST FlatList;\n\n    ULONG SortColumn; // ID of the column to sort by\n    PH_SORT_ORDER SortOrder;\n\n    FLOAT VScrollRemainder;\n    FLOAT HScrollRemainder;\n\n    LONG SearchMessageTime;\n    PWSTR SearchString;\n    ULONG SearchStringCount;\n    ULONG AllocatedSearchString;\n\n    ULONG TooltipIndex;\n    ULONG TooltipId;\n    PPH_STRING TooltipText;\n    RECT TooltipRect; // text rectangle of an unfolding tooltip\n    HFONT TooltipFont;\n    HFONT NewTooltipFont;\n    ULONG TooltipColumnId;\n\n    TEXTMETRIC TextMetrics;\n    HTHEME ThemeData;\n    COLORREF DefaultBackColor;\n    COLORREF DefaultForeColor;\n\n    // User configurable colors.\n    COLORREF CustomTextColor;\n    COLORREF CustomFocusColor;\n    COLORREF CustomSelectedColor;\n\n    LONG SystemBorderX;\n    LONG SystemBorderY;\n    LONG SystemEdgeX;\n    LONG SystemEdgeY;\n\n    HDC BufferedContext;\n    HBITMAP BufferedOldBitmap;\n    HBITMAP BufferedBitmap;\n    RECT BufferedContextRect;\n\n    LONG SystemDragX;\n    LONG SystemDragY;\n    RECT DragRect;\n\n    LONG WindowDpi;\n    LONG SmallIconWidth;\n    LONG SmallIconHeight;\n\n    LONG EnableRedraw;\n    HRGN SuspendUpdateRegion;\n\n    PH_STRINGREF EmptyText;\n\n    WNDPROC HeaderWindowProc;\n    WNDPROC FixedHeaderWindowProc;\n    HIMAGELIST ImageListHandle;\n\n    union\n    {\n        ULONG HeaderFlags;\n        struct\n        {\n            ULONG HeaderCustomDraw : 1;\n            ULONG HeaderMouseActive : 1;\n            ULONG HeaderDragging : 1;\n            ULONG HeaderUnused : 12;\n\n            ULONG FillerBoxVisible : 1;\n            ULONG ReorderDragActive : 1;\n            ULONG ReorderJustStarted : 1;\n            ULONG TooltipVisible : 1;\n            ULONG TooltipActive : 1;\n            ULONG SpareUnused : 12;\n        };\n    };\n\n    ULONG HeaderHotColumn;\n\n    HTHEME HeaderThemeHandle;\n    HFONT HeaderBoldFontHandle;\n    RECT HeaderLastHotRect;\n\n    HDC HeaderBufferedDc;\n    HBITMAP HeaderBufferedOldBitmap;\n    HBITMAP HeaderBufferedBitmap;\n    RECT HeaderBufferedContextRect;\n\n    ULONG HeaderColumnCacheMax;\n    PPH_STRINGREF HeaderStringCache;\n    PVOID HeaderTextCache;\n\n    HANDLE UniqueThread;\n\n    ULONG64 ScrollTickCount;\n\n    // Drag-reorder support\n    ULONG   ReorderSourceIndex;   // source row index in FlatList\n    ULONG   ReorderTargetIndex;   // target row index under caret\n    BOOLEAN ReorderDropAfter;     // caret drops after the target row\n    RECT    ReorderInsertRect;    // last drawn caret invalidation\n    HCURSOR ReorderCursor;        // optional cursor during reorder\n} PH_TREENEW_CONTEXT, *PPH_TREENEW_CONTEXT;\n\nLRESULT CALLBACK PhTnpWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n_Function_class_(PH_TREENEW_CALLBACK)\nBOOLEAN NTAPI PhTnpNullCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    );\n\nPPH_TREENEW_CONTEXT PhTnpCreateTreeNewContext(\n    VOID\n    );\n\nVOID PhTnpDestroyTreeNewContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\n// Event handlers\n\nBOOLEAN PhTnpOnCreate(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ CONST CREATESTRUCT *CreateStruct\n    );\n\nVOID PhTnpOnSize(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnSetFont(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HFONT Font,\n    _In_ LOGICAL Redraw\n    );\n\nVOID PhTnpOnStyleChanged(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Type,\n    _In_ STYLESTRUCT *StyleStruct\n    );\n\nVOID PhTnpOnSettingChange(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnThemeChanged(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnDpiChanged(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nULONG PhTnpOnGetDlgCode(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey,\n    _In_opt_ PMSG Message\n    );\n\nVOID PhTnpOnPaint(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnPrintClient(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ ULONG Flags\n    );\n\nBOOLEAN PhTnpOnNcPaint(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HRGN UpdateRegion\n    );\n\nBOOLEAN PhTnpOnSetCursor(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HWND CursorWindowHandle,\n    _In_ ULONG HitTest,\n    _In_ ULONG Source\n    );\n\nVOID PhTnpOnTimer(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    );\n\nVOID PhTnpOnMouseMove(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpOnMouseLeave(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnXxxButtonXxx(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Message,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpOnCaptureChanged(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnKeyDown(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey,\n    _In_ ULONG Data\n    );\n\nVOID PhTnpOnChar(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Character,\n    _In_ ULONG Data\n    );\n\nVOID PhTnpOnMouseWheel(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpOnMouseHWheel(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpOnContextMenu(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorScreenX,\n    _In_ LONG CursorScreenY\n    );\n\nVOID PhTnpOnVScroll(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Request,\n    _In_ USHORT Position\n    );\n\nVOID PhTnpOnHScroll(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Request,\n    _In_ USHORT Position\n    );\n\n_Success_(return)\nBOOLEAN PhTnpOnNotify(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    );\n\nLRESULT PhTnpOnUserMessage(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    );\n\n// Misc.\n\nVOID PhTnpSetFont(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HFONT Font,\n    _In_ BOOLEAN Redraw\n    );\n\nVOID PhTnpUpdateSystemMetrics(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpUpdateTextMetrics(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpUpdateThemeData(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpInitializeThemeData(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpCancelTrack(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpLayout(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpLayoutHeader(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpSetFixedWidth(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG FixedWidth\n    );\n\nVOID PhTnpSetRedraw(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Redraw\n    );\n\nVOID PhTnpSendMouseEvent(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY,\n    _In_opt_ PPH_TREENEW_NODE Node,\n    _In_opt_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG VirtualKeys\n    );\n\n// Columns\n\nPPH_TREENEW_COLUMN PhTnpLookupColumnById(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    );\n\nBOOLEAN PhTnpAddColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column\n    );\n\nBOOLEAN PhTnpRemoveColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    );\n\n_Success_(return)\nBOOLEAN PhTnpCopyColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id,\n    _Out_ PPH_TREENEW_COLUMN Column\n    );\n\nBOOLEAN PhTnpChangeColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Mask,\n    _In_ ULONG Id,\n    _In_ PPH_TREENEW_COLUMN Column\n    );\n\nVOID PhTnpExpandAllocatedColumns(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpUpdateColumnMaps(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\n// Columns (header control)\n\nLONG PhTnpInsertColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column\n    );\n\nVOID PhTnpChangeColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Mask,\n    _In_ PPH_TREENEW_COLUMN Column\n    );\n\nVOID PhTnpDeleteColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_COLUMN Column\n    );\n\nVOID PhTnpUpdateColumnHeaders(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpUpdateColumnHeadersDpiChanged(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG OldWindowDpi,\n    _In_ LONG NewWindowDpi\n    );\n\nVOID PhTnpProcessResizeColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ LONG Delta\n    );\n\nVOID PhTnpProcessSortColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN NewColumn\n    );\n\nBOOLEAN PhTnpSetColumnHeaderSortIcon(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_COLUMN SortColumnPointer\n    );\n\nVOID PhTnpAutoSizeColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HWND HeaderHandle,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG Flags\n    );\n\n// Nodes\n\n_Success_(return)\nBOOLEAN PhTnpGetNodeChildren(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_NODE Node,\n    _Out_ PPH_TREENEW_NODE **Children,\n    _Out_ PULONG NumberOfChildren\n    );\n\nBOOLEAN PhTnpIsNodeLeaf(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node\n    );\n\n_Success_(return)\nBOOLEAN PhTnpGetCellText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Id,\n    _Out_ PPH_STRINGREF Text\n    );\n\nVOID PhTnpRestructureNodes(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpInsertNodeChildren(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Level\n    );\n\nVOID PhTnpSetExpandedNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ BOOLEAN Expanded\n    );\n\nBOOLEAN PhTnpGetCellParts(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Index,\n    _In_opt_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG Flags,\n    _Out_ PPH_TREENEW_CELL_PARTS Parts\n    );\n\n_Success_(return)\nBOOLEAN PhTnpGetRowRects(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Start,\n    _In_ ULONG End,\n    _In_ BOOLEAN Clip,\n    _Out_ PRECT Rect\n    );\n\nVOID PhTnpHitTest(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_HIT_TEST HitTest\n    );\n\nVOID PhTnpSelectRange(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Start,\n    _In_ ULONG End,\n    _In_ ULONG Flags,\n    _Out_opt_ PULONG ChangedStart,\n    _Out_opt_ PULONG ChangedEnd\n    );\n\nVOID PhTnpSetHotNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_NODE NewHotNode,\n    _In_ BOOLEAN NewPlusMinusHot\n    );\n\nVOID PhTnpProcessSelectNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ LOGICAL ControlKey,\n    _In_ LOGICAL ShiftKey,\n    _In_ LOGICAL RightButton\n    );\n\nBOOLEAN PhTnpEnsureVisibleNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Index\n    );\n\n// Mouse\n\nVOID PhTnpProcessMoveMouse(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpProcessMouseVWheel(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance\n    );\n\nVOID PhTnpProcessMouseHWheel(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance\n    );\n\n// Keyboard\n\nBOOLEAN PhTnpProcessFocusKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey\n    );\n\nBOOLEAN PhTnpProcessNodeKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey\n    );\n\nVOID PhTnpProcessSearchKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Character\n    );\n\nBOOLEAN PhTnpDefaultIncrementalSearch(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_SEARCH_EVENT SearchEvent,\n    _In_ BOOLEAN Partial,\n    _In_ BOOLEAN Wrap\n    );\n\n// Scrolling\n\nVOID PhTnpUpdateScrollBars(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG DeltaRows,\n    _In_ LONG DeltaX\n    );\n\nVOID PhTnpProcessScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG DeltaRows,\n    _In_ LONG DeltaX\n    );\n\nBOOLEAN PhTnpCanScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Horizontal,\n    _In_ BOOLEAN Positive\n    );\n\n// Drawing\n\nVOID PhTnpPaint(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT PaintRect\n    );\n\nVOID PhTnpPrepareRowForDraw(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _Inout_ PPH_TREENEW_NODE Node\n    );\n\nVOID PhTnpDrawCell(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT CellRect,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ LONG RowIndex,\n    _In_ LONG ColumnIndex\n    );\n\nVOID PhTnpDrawDivider(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc\n    );\n\nVOID PhTnpDrawPlusMinusGlyph(\n    _In_ HDC hdc,\n    _In_ PRECT Rect,\n    _In_ BOOLEAN Plus\n    );\n\nVOID PhTnpDrawSelectionRectangle(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT Rect\n    );\n\nVOID PhTnpDrawThemedBorder(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc\n    );\n\n// Tooltips\n\nVOID PhTnpInitializeTooltips(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\n_Success_(return)\nBOOLEAN PhTnpGetTooltipText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPOINT Point,\n    _Out_ PPH_STRING *Text\n    );\n\nBOOLEAN PhTnpPrepareTooltipShow(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpPrepareTooltipPop(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpPopTooltip(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nPPH_TREENEW_COLUMN PhTnpHitTestHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Fixed,\n    _In_ PPOINT Point,\n    _Out_opt_ PRECT ItemRect\n    );\n\n_Success_(return)\nBOOLEAN PhTnpGetHeaderTooltipText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Fixed,\n    _In_ PPOINT Point,\n    _Out_ PPH_STRING *Text\n    );\n\nLRESULT CALLBACK PhTnpHeaderHookWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n// Drag selection\n\nBOOLEAN PhTnpDetectDrag(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY,\n    _In_ BOOLEAN DispatchMessages,\n    _Out_opt_ PULONG CancelledByMessage\n    );\n\nVOID PhTnpDragSelect(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpProcessDragSelect(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKeys,\n    _In_ PRECT OldRect,\n    _In_ PRECT NewRect,\n    _In_ PRECT TotalRect\n    );\n\n// Drag-reorder\n\nVOID PhTnpDrawInsertionCaret(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC Hdc\n    );\n\nVOID PhTnpReorderInvalidateCaret(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpReorderUpdateCaretRect(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpReorderBegin(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG SourceIndex\n    );\n\nVOID PhTnpReorderCancel(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpReorderCommit(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpReorderUpdate(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\n// Double buffering\n\nVOID PhTnpCreateBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC Hdc\n    );\n\nVOID PhTnpDestroyBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\n// Support functions\n\n_Success_(return)\nBOOLEAN PhTnpGetMessagePos(\n    _In_ HWND WindowHandle,\n    _Out_ PPOINT ClientPoint\n    );\n\n_Success_(return)\nBOOLEAN PhTnpGetColumnHeaderText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _Out_ PPH_STRINGREF Text\n    );\n\nBOOLEAN TnHeaderCustomPaint(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LPNMCUSTOMDRAW CustomDraw\n    );\n\n// Macros\n\n#define TNP_CELL_LEFT_MARGIN 6\n#define TNP_CELL_RIGHT_MARGIN 6\n#define TNP_ICON_RIGHT_PADDING 4\n\n#define TNP_TIMER_NULL 1\n#define TNP_TIMER_ANIMATE_DIVIDER 2\n\n#define TNP_TOOLTIPS_ITEM 0\n#define TNP_TOOLTIPS_FIXED_HEADER 1\n#define TNP_TOOLTIPS_HEADER 2\n#define TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH 550\n\n#define TNP_ANIMATE_DIVIDER_INTERVAL 10\n#define TNP_ANIMATE_DIVIDER_INCREMENT 17\n#define TNP_ANIMATE_DIVIDER_DECREMENT 2\n\n#define TNP_HIT_TEST_FIXED_DIVIDER(X, Context) \\\n    ((Context)->FixedDividerVisible && (X) >= (Context)->FixedWidth - 8 && (X) < (Context)->FixedWidth + 8)\n#define TNP_HIT_TEST_PLUS_MINUS_GLYPH(X, NodeLevel) \\\n    (((X) >= TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth)) && ((X) < TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth) + SmallIconWidth))\n\n#endif\n"
  },
  {
    "path": "phlib/include/verify.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2013-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_VERIFY_H\n#define _PH_VERIFY_H\n\nEXTERN_C_START\n\n#define PH_VERIFY_DEFAULT_SIZE_LIMIT (32 * 1024 * 1024)\n\ntypedef enum _VERIFY_RESULT\n{\n    VrUnknown = 0,\n    VrNoSignature,\n    VrTrusted,\n    VrExpired,\n    VrRevoked,\n    VrDistrust,\n    VrSecuritySettings,\n    VrBadSignature\n} VERIFY_RESULT, *PVERIFY_RESULT;\n\n#define PH_VERIFY_UNTRUSTED(x) ((x) != VrUnknown && (x) != VrTrusted)\n\nPHLIBAPI\nPH_STRINGREF\nNTAPI\nPhVerifyResultToStringRef(\n    _In_ VERIFY_RESULT Result\n    );\n\n#define PH_VERIFY_PREVENT_NETWORK_ACCESS 0x1\n#define PH_VERIFY_VIEW_PROPERTIES 0x2\n\ntypedef struct _PH_VERIFY_FILE_INFO\n{\n    HANDLE FileHandle;\n    ULONG Flags; // PH_VERIFY_*\n\n    ULONG FileSizeLimitForHash; // 0 for PH_VERIFY_DEFAULT_SIZE_LIMIT, -1 for unlimited\n    ULONG NumberOfCatalogFileNames;\n    PWSTR *CatalogFileNames;\n\n    HWND hWnd; // for PH_VERIFY_VIEW_PROPERTIES\n} PH_VERIFY_FILE_INFO, *PPH_VERIFY_FILE_INFO;\n\nPHLIBAPI\nVERIFY_RESULT\nNTAPI\nPhVerifyFile(\n    _In_ PCWSTR FileName,\n    _Out_opt_ PPH_STRING *SignerName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhVerifyFileIsChainedToMicrosoft(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    );\n\ntypedef struct _CERT_CONTEXT CERT_CONTEXT;\ntypedef CERT_CONTEXT *PCERT_CONTEXT;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhVerifyFileEx(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _Out_ VERIFY_RESULT *VerifyResult,\n    _Out_opt_ PCERT_CONTEXT **Signatures,\n    _Out_opt_ PULONG NumberOfSignatures\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeVerifySignatures(\n    _In_opt_ PCERT_CONTEXT *Signatures,\n    _In_ ULONG NumberOfSignatures\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSignerNameFromCertificate(\n    _In_ PCERT_CONTEXT Certificate\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSystemComponentFromCertificate(\n    _In_ PCERT_CONTEXT Certificate\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/include/verifyp.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2023\n *\n */\n\n#ifndef _PH_VERIFYP_H\n#define _PH_VERIFYP_H\n\ntypedef struct _PH_VERIFY_CACHE_ENTRY\n{\n    PPH_STRING FileName;\n    ULONGLONG SequenceNumber;\n    VERIFY_RESULT VerifyResult;\n    PPH_STRING VerifySignerName;\n} PH_VERIFY_CACHE_ENTRY, *PPH_VERIFY_CACHE_ENTRY;\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpVerifyCacheHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpVerifyCacheHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\ntypedef struct _CATALOG_INFO\n{\n    ULONG cbStruct;\n    _Field_z_ WCHAR wszCatalogFile[MAX_PATH];\n} CATALOG_INFO, *PCATALOG_INFO;\n\ntypedef struct tagCRYPTUI_VIEWSIGNERINFO_STRUCT\n{\n    ULONG dwSize;\n    HWND hwndParent;\n    ULONG dwFlags;\n    LPCTSTR szTitle;\n    CMSG_SIGNER_INFO *pSignerInfo;\n    HCRYPTMSG hMsg;\n    LPCSTR pszOID;\n    ULONG_PTR dwReserved;\n    ULONG cStores;\n    HCERTSTORE *rghStores;\n    ULONG cPropSheetPages;\n    PVOID rgPropSheetPages;\n} CRYPTUI_VIEWSIGNERINFO_STRUCT, *PCRYPTUI_VIEWSIGNERINFO_STRUCT;\n\ntypedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle)(\n    _In_ HANDLE hFile,\n    _Inout_ PULONG pcbHash,\n    _Out_writes_bytes_to_opt_(*pcbHash, *pcbHash) PBYTE pbHash,\n    _Reserved_ ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle2)(\n    _In_ HCATADMIN hCatAdmin,\n    _In_ HANDLE hFile,\n    _Inout_ PULONG pcbHash,\n    _Out_writes_bytes_to_opt_(*pcbHash, *pcbHash) PBYTE pbHash,\n    _Reserved_ ULONG dwFlags\n    );\n\n#define CRYPTCATADMIN_CALCHASH_FLAG_NONCONFORMANT_FILES_FALLBACK_FLAT 0x1\n\ntypedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle3)(\n    _In_ HCATADMIN hCatAdmin,\n    _In_ HANDLE hFile,\n    _Inout_ PULONG pcbHash,\n    _Out_writes_bytes_to_opt_(*pcbHash, *pcbHash) PBYTE pbHash,\n    _Reserved_ ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminAcquireContext)(\n    _Out_ HCATADMIN *phCatAdmin,\n    _In_opt_ PCGUID pgSubsystem,\n    _Reserved_ ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminAcquireContext2)(\n    _Out_ HCATADMIN *phCatAdmin,\n    _In_opt_ PCGUID pgSubsystem,\n    _In_opt_ PCWSTR pwszHashAlgorithm,\n    _In_opt_ PCCERT_STRONG_SIGN_PARA pStrongHashPolicy,\n    _Reserved_ ULONG dwFlags\n    );\n\ntypedef HANDLE (WINAPI *_CryptCATAdminEnumCatalogFromHash)(\n    _In_ HCATADMIN hCatAdmin,\n    _In_reads_bytes_(cbHash) PBYTE pbHash,\n    _In_ ULONG cbHash,\n    _Reserved_ ULONG dwFlags,\n    _Inout_opt_ HANDLE phPrevCatInfo // HCATINFO\n    );\n\ntypedef BOOL (WINAPI *_CryptCATCatalogInfoFromContext)(\n    _In_ HANDLE hCatInfo,\n    _Inout_ CATALOG_INFO *psCatInfo,\n    _In_ ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminReleaseCatalogContext)(\n    _In_ HCATADMIN hCatAdmin,\n    _In_ HANDLE hCatInfo,\n    _In_ ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminReleaseContext)(\n    _In_ HCATADMIN hCatAdmin,\n    _In_ ULONG dwFlags\n    );\n\ntypedef PCRYPT_PROVIDER_DATA (WINAPI *_WTHelperProvDataFromStateData)(\n    _In_ HANDLE hStateData\n    );\n\ntypedef PCRYPT_PROVIDER_SGNR (WINAPI *_WTHelperGetProvSignerFromChain)(\n    _In_ CRYPT_PROVIDER_DATA *pProvData,\n    _In_ ULONG idxSigner,\n    _In_ BOOL fCounterSigner,\n    _In_ ULONG idxCounterSigner\n    );\n\ntypedef BOOL (WINAPI *_WTHelperIsChainedToMicrosoftFromStateData)(\n    _In_ CRYPT_PROVIDER_DATA *pProvData\n    );\n\ntypedef BOOL (WINAPI* _WTHelperIsChainedToMicrosoft)(\n    _In_ PCCERT_CONTEXT pCertContext,\n    _In_ HCERTSTORE hSiblingStore,\n    _In_ BOOL IncludeMicrosoftTestRootCerts\n    );\n\ntypedef BOOL (WINAPI* _WTHelperCheckCertUsage)(\n    _In_ PCCERT_CONTEXT pCertContext,\n    _In_ PCSTR pszOID\n    );\n\ntypedef LONG (WINAPI *_WinVerifyTrust)(\n    _In_ HWND hWnd,\n    _In_ PCGUID pgActionID,\n    _In_ PVOID pWVTData\n    );\n\ntypedef VOID (WINAPI* _WintrustSetDefaultIncludePEPageHashes)(\n    _In_ BOOL fIncludePEPageHashes\n    );\n\ntypedef ULONG (WINAPI *_CertNameToStr)(\n    _In_ ULONG dwCertEncodingType,\n    _In_ PCERT_NAME_BLOB pName,\n    _In_ ULONG dwStrType,\n    _Out_writes_to_opt_(csz, return) PWSTR psz,\n    _In_ ULONG csz\n    );\n\ntypedef BOOL (WINAPI *_CertGetEnhancedKeyUsage)(\n    _In_ PCCERT_CONTEXT pCertContext,\n    _In_ ULONG dwFlags,\n    _Out_writes_bytes_to_opt_(*pcbUsage, *pcbUsage) PCERT_ENHKEY_USAGE pUsage,\n    _Inout_ PULONG pcbUsage\n    );\n\ntypedef PCCERT_CONTEXT (WINAPI *_CertDuplicateCertificateContext)(\n    _In_ PCCERT_CONTEXT pCertContext\n    );\n\ntypedef BOOL (WINAPI *_CertFreeCertificateContext)(\n    _In_ PCCERT_CONTEXT pCertContext\n    );\n\ntypedef BOOL (WINAPI *_CryptUIDlgViewSignerInfo)(\n    _In_ CRYPTUI_VIEWSIGNERINFO_STRUCT *pcvsi\n    );\n\n// C689AAB8-8E78-11D0-8C47-00C04FC295EE\nDEFINE_GUID(WINTRUST_KNOWN_SUBJECT_PE_IMAGE, 0xC689AAB8, 0x8E78, 0x11D0, 0x8C, 0x47, 0x0, 0xC0, 0x4F, 0xC2, 0x95, 0xEE);\n\ntypedef enum _SIGNATURE_STATE\n{\n    SIGNATURE_STATE_UNSIGNED_MISSING,\n    SIGNATURE_STATE_UNSIGNED_UNSUPPORTED,\n    SIGNATURE_STATE_UNSIGNED_POLICY,\n    SIGNATURE_STATE_INVALID_CORRUPT,\n    SIGNATURE_STATE_INVALID_POLICY,\n    SIGNATURE_STATE_VALID,\n    SIGNATURE_STATE_TRUSTED,\n    SIGNATURE_STATE_UNTRUSTED\n} SIGNATURE_STATE;\n\ntypedef enum _SIGNATURE_INFO_TYPE\n{\n    SIT_UNKNOWN,\n    SIT_AUTHENTICODE,\n    SIT_CATALOG\n} SIGNATURE_INFO_TYPE;\n\ntypedef enum _SIGNATURE_INFO_FLAGS\n{\n    SIF_NONE = 0,\n    SIF_AUTHENTICODE_SIGNED = 1,\n    SIF_CATALOG_SIGNED = 2,\n    SIF_VERSION_INFO = 4,\n    SIF_CHECK_OS_BINARY = 0x800,\n    SIF_BASE_VERIFICATION = 0x1000,\n    SIF_CATALOG_FIRST = 0x2000,\n    SIF_MOTW = 0x4000\n} SIGNATURE_INFO_FLAGS;\n\ntypedef struct _SIGNATURE_INFO\n{\n    ULONG cbSize;\n    SIGNATURE_STATE nSignatureState;\n    SIGNATURE_INFO_TYPE nSignatureType;\n    ULONG dwSignatureInfoAvailability;\n    ULONG dwInfoAvailability;\n    PWSTR pszDisplayName;\n    ULONG cchDisplayName;\n    PWSTR pszPublisherName;\n    ULONG cchPublisherName;\n    PWSTR pszMoreInfoURL;\n    ULONG cchMoreInfoURL;\n    PBYTE prgbHash;\n    ULONG cbHash;\n    BOOL fOSBinary;\n} SIGNATURE_INFO, *PSIGNATURE_INFO;\n\ntypedef HRESULT (WINAPI* _WTGetSignatureInfo)(\n    _In_opt_ PCWSTR pszFile,\n    _In_opt_ HANDLE hFile,\n    _In_ SIGNATURE_INFO_FLAGS sigInfoFlags,\n    _Inout_ PSIGNATURE_INFO psiginfo,\n    _Out_ PVOID ppCertContext,\n    _Out_ PHANDLE phWVTStateData\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/workqueue.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *\n */\n\n#ifndef _PH_WORKQUEUE_H\n#define _PH_WORKQUEUE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(DEBUG)\nextern PPH_LIST PhDbgWorkQueueList;\nextern PH_QUEUED_LOCK PhDbgWorkQueueListLock;\n#endif\n\ntypedef struct _PH_WORK_QUEUE\n{\n    PH_RUNDOWN_PROTECT RundownProtect;\n    BOOLEAN Terminating;\n\n    LIST_ENTRY QueueListHead;\n    PH_QUEUED_LOCK QueueLock;\n    PH_CONDITION QueueEmptyCondition;\n\n    ULONG MaximumThreads;\n    ULONG MinimumThreads;\n    ULONG NoWorkTimeout;\n\n    PH_QUEUED_LOCK StateLock;\n    HANDLE SemaphoreHandle;\n    ULONG CurrentThreads;\n    ULONG BusyCount;\n} PH_WORK_QUEUE, *PPH_WORK_QUEUE;\n\ntypedef VOID (NTAPI *PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION)(\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_ PVOID Context\n    );\n\ntypedef struct _PH_WORK_QUEUE_ENVIRONMENT\n{\n    LONG BasePriority : 6; // Base priority increment\n    ULONG IoPriority : 3; // I/O priority hint\n    ULONG PagePriority : 3; // Page/memory priority\n    ULONG ForceUpdate : 1; // Always set priorities regardless of cached values\n    ULONG SpareBits : 19;\n} PH_WORK_QUEUE_ENVIRONMENT, *PPH_WORK_QUEUE_ENVIRONMENT;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeWorkQueue(\n    _Out_ PPH_WORK_QUEUE WorkQueue,\n    _In_ ULONG MinimumThreads,\n    _In_ ULONG MaximumThreads,\n    _In_ ULONG NoWorkTimeout\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhWaitForWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhQueueItemWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue,\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhQueueItemWorkQueueEx(\n    _Inout_ PPH_WORK_QUEUE WorkQueue,\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,\n    _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeWorkQueueEnvironment(\n    _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    );\n\nPHLIBAPI\nPPH_WORK_QUEUE\nNTAPI\nPhGetGlobalWorkQueue(\n    VOID\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "phlib/include/workqueuep.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2016\n *\n */\n\n#ifndef _PH_WORKQUEUEP_H\n#define _PH_WORKQUEUEP_H\n\ntypedef struct _PH_WORK_QUEUE_ITEM\n{\n    LIST_ENTRY ListEntry;\n    PUSER_THREAD_START_ROUTINE Function;\n    PVOID Context;\n    PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction;\n    PH_WORK_QUEUE_ENVIRONMENT Environment;\n} PH_WORK_QUEUE_ITEM, *PPH_WORK_QUEUE_ITEM;\n\nVOID PhpGetDefaultWorkQueueEnvironment(\n    _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    );\n\nVOID PhpUpdateWorkQueueEnvironment(\n    _Inout_ PPH_WORK_QUEUE_ENVIRONMENT CurrentEnvironment,\n    _In_ PPH_WORK_QUEUE_ENVIRONMENT NewEnvironment\n    );\n\nPPH_WORK_QUEUE_ITEM PhpCreateWorkQueueItem(\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,\n    _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    );\n\nVOID PhpDestroyWorkQueueItem(\n    _In_ PPH_WORK_QUEUE_ITEM WorkQueueItem\n    );\n\nVOID PhpExecuteWorkQueueItem(\n    _Inout_ PPH_WORK_QUEUE_ITEM WorkQueueItem\n    );\n\nHANDLE PhpGetSemaphoreWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    );\n\nBOOLEAN PhpCreateWorkQueueThread(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    );\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpWorkQueueThreadStart(\n    _In_ PVOID Parameter\n    );\n\n#endif\n"
  },
  {
    "path": "phlib/include/wslsup.h",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2019-2023\n *\n */\n\n#ifndef _PH_WSLSUP_H\n#define _PH_WSLSUP_H\n\nEXTERN_C_START\n\nNTSTATUS PhWslQueryDistroProcessCommandLine(\n    _In_ PPH_STRINGREF FileName,\n    _In_ ULONG LxssProcessId,\n    _Out_ PPH_STRING* Result\n    );\n\nNTSTATUS PhWslQueryDistroProcessEnvironment(\n    _In_ PPH_STRINGREF FileName,\n    _In_ ULONG LxssProcessId,\n    _Out_ PPH_STRING* Result\n    );\n\nNTSTATUS PhInitializeLxssImageVersionInfo(\n    _Inout_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PPH_STRINGREF FileName\n    );\n\nNTSTATUS PhCreateProcessLxss(\n    _In_ PPH_STRING DistributionGuid,\n    _In_ PPH_STRING DistributionName,\n    _In_ PPH_STRING DistributionCommand,\n    _Out_ PPH_STRING* Result\n    );\n\nEXTERN_C_END\n\n#endif\n"
  },
  {
    "path": "phlib/json.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017-2023\n *\n */\n\n#include <ph.h>\n#include <phbasesup.h>\n#include <phutil.h>\n#include <json.h>\n#include <thirdparty.h>\n\nstatic PVOID json_get_object(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    )\n{\n    json_object* returnObj;\n\n    if (json_object_object_get_ex(Object, Key, &returnObj))\n    {\n        return returnObj;\n    }\n\n    return NULL;\n}\n\nstatic NTSTATUS PhJsonErrorToNtStatus(\n    _In_ enum json_tokener_error JsonError\n    )\n{\n    switch (JsonError)\n    {\n    case json_tokener_success:\n        return STATUS_SUCCESS;\n    case json_tokener_continue:\n        return STATUS_MORE_ENTRIES;\n    case json_tokener_error_depth:\n        return STATUS_PARTIAL_COPY;\n    case json_tokener_error_parse_eof:\n    case json_tokener_error_parse_unexpected:\n    case json_tokener_error_parse_null:\n    case json_tokener_error_parse_boolean:\n    case json_tokener_error_parse_number:\n    case json_tokener_error_parse_array:\n    case json_tokener_error_parse_object_key_name:\n    case json_tokener_error_parse_object_key_sep:\n    case json_tokener_error_parse_object_value_sep:\n    case json_tokener_error_parse_string:\n    case json_tokener_error_parse_comment:\n    case json_tokener_error_parse_utf8_string:\n        return STATUS_FAIL_CHECK;\n    case json_tokener_error_memory:\n        return STATUS_NO_MEMORY;\n    case json_tokener_error_size:\n        return STATUS_BUFFER_TOO_SMALL;\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nNTSTATUS PhCreateJsonParser(\n    _Out_ PVOID* JsonObject,\n    _In_ PCSTR JsonString\n    )\n{\n    if (*JsonObject = json_tokener_parse(JsonString))\n        return STATUS_SUCCESS;\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nNTSTATUS PhCreateJsonParserEx(\n    _Out_ PVOID* JsonObject,\n    _In_ PVOID JsonString,\n    _In_ BOOLEAN Unicode\n    )\n{\n    json_tokener* tokenerObject;\n    json_object* jsonObject;\n    enum json_tokener_error jsonStatus;\n\n    if (Unicode)\n    {\n        PPH_STRING jsonStringUtf16 = JsonString;\n        PPH_BYTES jsonStringUtf8;\n\n        if (jsonStringUtf16->Length / sizeof(WCHAR) >= INT32_MAX)\n            return STATUS_INVALID_BUFFER_SIZE;\n        if (!(tokenerObject = json_tokener_new()))\n            return STATUS_NO_MEMORY;\n\n        json_tokener_set_flags(\n            tokenerObject,\n            JSON_TOKENER_STRICT | JSON_TOKENER_VALIDATE_UTF8\n            );\n\n        jsonStringUtf8 = PhConvertUtf16ToUtf8Ex(\n            jsonStringUtf16->Buffer,\n            jsonStringUtf16->Length\n            );\n        jsonObject = json_tokener_parse_ex(\n            tokenerObject,\n            jsonStringUtf8->Buffer,\n            (LONG)jsonStringUtf8->Length\n            );\n        PhDereferenceObject(jsonStringUtf8);\n    }\n    else\n    {\n        PPH_BYTES jsonStringUtf8 = JsonString;\n\n        if (jsonStringUtf8->Length >= INT32_MAX)\n            return STATUS_INVALID_BUFFER_SIZE;\n        if (!(tokenerObject = json_tokener_new()))\n            return STATUS_NO_MEMORY;\n\n        json_tokener_set_flags(\n            tokenerObject,\n            JSON_TOKENER_STRICT | JSON_TOKENER_VALIDATE_UTF8\n            );\n\n        jsonObject = json_tokener_parse_ex(\n            tokenerObject,\n            jsonStringUtf8->Buffer,\n            (LONG)jsonStringUtf8->Length\n            );\n    }\n\n    jsonStatus = json_tokener_get_error(tokenerObject);\n    if (jsonStatus != json_tokener_success)\n    {\n        json_tokener_free(tokenerObject);\n        return PhJsonErrorToNtStatus(jsonStatus);\n    }\n\n    json_tokener_free(tokenerObject);\n    *JsonObject = jsonObject;\n    return STATUS_SUCCESS;\n}\n\nVOID PhFreeJsonObject(\n    _In_ PVOID Object\n    )\n{\n    json_object_put(Object);\n}\n\nPPH_STRING PhGetJsonValueAsString(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    )\n{\n    PVOID object;\n    PCSTR value;\n    size_t length;\n\n    if (object = json_get_object(Object, (PCSTR)Key))\n    {\n        if (\n            (length = json_object_get_string_len(object)) &&\n            (value = json_object_get_string(object))\n            )\n        {\n            return PhConvertUtf8ToUtf16Ex(value, length);\n        }\n    }\n\n    return NULL;\n}\n\nPPH_STRING PhGetJsonObjectString(\n    _In_ PVOID Object\n    )\n{\n    PCSTR value;\n    size_t length;\n\n    if (\n        (length = json_object_get_string_len(Object)) &&\n        (value = json_object_get_string(Object))\n        )\n    {\n        return PhConvertUtf8ToUtf16Ex(value, length);\n    }\n\n    return PhReferenceEmptyString();\n}\n\nLONGLONG PhGetJsonValueAsInt64(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    )\n{\n    return json_object_get_int64(json_get_object(Object, Key));\n}\n\nULONGLONG PhGetJsonValueAsUInt64(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    )\n{\n    return json_object_get_uint64(json_get_object(Object, Key));\n}\n\nULONG PhGetJsonUInt32Object(\n    _In_ PVOID Object\n    )\n{\n    return json_object_get_int(Object);\n}\n\nULONGLONG PhGetJsonUInt64Object(\n    _In_ PVOID Object\n    )\n{\n    return json_object_get_uint64(Object);\n}\n\nLONGLONG PhGetJsonInt64Object(\n    _In_ PVOID Object\n    )\n{\n    return json_object_get_int64(Object);\n}\n\nPVOID PhCreateJsonObject(\n    VOID\n    )\n{\n    return json_object_new_object();\n}\n\nPVOID PhCreateJsonStringObject(\n    _In_ PCSTR Value\n    )\n{\n    return json_object_new_string(Value);\n}\n\nPVOID PhGetJsonObject(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    )\n{\n    return json_get_object(Object, Key);\n}\n\nPH_JSON_OBJECT_TYPE PhGetJsonObjectType(\n    _In_ PVOID Object\n    )\n{\n    switch (json_object_get_type(Object))\n    {\n    case json_type_null:\n        return PH_JSON_OBJECT_TYPE_NULL;\n    case json_type_boolean:\n        return PH_JSON_OBJECT_TYPE_BOOLEAN;\n    case json_type_double:\n        return PH_JSON_OBJECT_TYPE_DOUBLE;\n    case json_type_int:\n        return PH_JSON_OBJECT_TYPE_INT;\n    case json_type_object:\n        return PH_JSON_OBJECT_TYPE_OBJECT;\n    case json_type_array:\n        return PH_JSON_OBJECT_TYPE_ARRAY;\n    case json_type_string:\n        return PH_JSON_OBJECT_TYPE_STRING;\n    }\n\n    return PH_JSON_OBJECT_TYPE_UNKNOWN;\n}\n\nLONG PhGetJsonObjectLength(\n    _In_ PVOID Object\n    )\n{\n    return json_object_object_length(Object);\n}\n\nBOOLEAN PhGetJsonObjectBool(\n    _In_ PVOID Object,\n    _In_ PCSTR Key\n    )\n{\n    return json_object_get_boolean(json_get_object(Object, Key)) == TRUE;\n}\n\nVOID PhAddJsonObjectValue(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PVOID Value\n    )\n{\n    json_object_object_add_ex(Object, Key, Value, JSON_C_OBJECT_ADD_KEY_IS_NEW | JSON_C_OBJECT_ADD_CONSTANT_KEY);\n}\n\nVOID PhAddJsonObject(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PCSTR Value\n    )\n{\n    json_object_object_add_ex(Object, Key, json_object_new_string(Value), JSON_C_OBJECT_ADD_KEY_IS_NEW | JSON_C_OBJECT_ADD_CONSTANT_KEY);\n}\n\nVOID PhAddJsonObject2(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PCSTR Value,\n    _In_ SIZE_T Length\n    )\n{\n    PVOID string = json_object_new_string_len(Value, (UINT32)Length);\n\n    json_object_object_add_ex(Object, Key, string, JSON_C_OBJECT_ADD_KEY_IS_NEW | JSON_C_OBJECT_ADD_CONSTANT_KEY);\n}\n\nVOID PhAddJsonObjectUtf8(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PPH_BYTES String\n    )\n{\n    PVOID string = json_object_new_string_len(String->Buffer, (UINT32)String->Length);\n\n    json_object_object_add_ex(Object, Key, string, JSON_C_OBJECT_ADD_KEY_IS_NEW | JSON_C_OBJECT_ADD_CONSTANT_KEY);\n}\n\nVOID PhAddJsonObjectInt64(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ LONGLONG Value\n    )\n{\n    json_object_object_add_ex(Object, Key, json_object_new_int64(Value), JSON_C_OBJECT_ADD_KEY_IS_NEW | JSON_C_OBJECT_ADD_CONSTANT_KEY);\n}\n\nVOID PhAddJsonObjectUInt64(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ ULONGLONG Value\n    )\n{\n    json_object_object_add_ex(Object, Key, json_object_new_uint64(Value), JSON_C_OBJECT_ADD_KEY_IS_NEW | JSON_C_OBJECT_ADD_CONSTANT_KEY);\n}\n\nVOID PhAddJsonObjectDouble(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ DOUBLE Value\n    )\n{\n    json_object_object_add_ex(Object, Key, json_object_new_double(Value), JSON_C_OBJECT_ADD_KEY_IS_NEW | JSON_C_OBJECT_ADD_CONSTANT_KEY);\n}\n\nPVOID PhCreateJsonArray(\n    VOID\n    )\n{\n    return json_object_new_array();\n}\n\nVOID PhAddJsonArrayObject(\n    _In_ PVOID Object,\n    _In_ PVOID Value\n    )\n{\n    json_object_array_add(Object, Value);\n}\n\nPVOID PhGetJsonArrayString(\n    _In_ PVOID Object,\n    _In_ BOOLEAN Unicode\n    )\n{\n    PCSTR value;\n    size_t length;\n\n    if (value = json_object_to_json_string_length(Object, JSON_C_TO_STRING_PLAIN, &length)) // json_object_get_string(Object))\n    {\n        if (Unicode)\n            return PhConvertUtf8ToUtf16Ex(value, length);\n        else\n            return PhCreateBytesEx(value, length);\n    }\n\n    return NULL;\n}\n\nINT64 PhGetJsonArrayLong64(\n    _In_ PVOID Object,\n    _In_ ULONG Index\n    )\n{\n    return json_object_get_int64(json_object_array_get_idx(Object, Index));\n}\n\nULONG PhGetJsonArrayLength(\n    _In_ PVOID Object\n    )\n{\n    return (ULONG)json_object_array_length(Object);\n}\n\nPVOID PhGetJsonArrayIndexObject(\n    _In_ PVOID Object,\n    _In_ ULONG Index\n    )\n{\n    return json_object_array_get_idx(Object, Index);\n}\n\nVOID PhEnumJsonArrayObject(\n    _In_ PVOID Object,\n    _In_ PPH_ENUM_JSON_OBJECT_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    if (PhGetJsonObjectType(Object) == PH_JSON_OBJECT_TYPE_OBJECT)\n    {\n        json_object_iter iter;\n\n        json_object_object_foreachC(Object, iter)\n        {\n            if (!Callback(Object, iter.key, iter.val, Context))\n                break;\n        }\n    }\n}\n\nPVOID PhGetJsonObjectAsArrayList(\n    _In_ PVOID Object\n    )\n{\n    PPH_LIST listArray = NULL;\n\n    if (PhGetJsonObjectType(Object) == PH_JSON_OBJECT_TYPE_OBJECT)\n    {\n        json_object_iter iter;\n\n        listArray = PhCreateList(1);\n\n        json_object_object_foreachC(Object, iter)\n        {\n            PJSON_ARRAY_LIST_OBJECT object;\n\n            object = PhAllocateZero(sizeof(JSON_ARRAY_LIST_OBJECT));\n            object->Key = iter.key;\n            object->Entry = iter.val;\n\n            PhAddItemList(listArray, object);\n        }\n    }\n\n    return listArray;\n}\n\nNTSTATUS PhLoadJsonObjectFromFile(\n    _Out_ PVOID* JsonObject,\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    PPH_BYTES content;\n\n    if (NT_SUCCESS(status = PhFileReadAllText(&content, FileName, FALSE)))\n    {\n        status = PhCreateJsonParserEx(JsonObject, content, FALSE);\n        PhDereferenceObject(content);\n    }\n\n    return status;\n}\n\nstatic CONST PH_FLAG_MAPPING PhJsonFormatFlagMappings[] =\n{\n    { PH_JSON_TO_STRING_PLAIN, JSON_C_TO_STRING_PLAIN },\n    { PH_JSON_TO_STRING_SPACED, JSON_C_TO_STRING_SPACED },\n    { PH_JSON_TO_STRING_PRETTY, JSON_C_TO_STRING_PRETTY },\n};\n\nstatic VOID PhJsonObjectToJsonStringIndent(\n    _In_ PPH_BYTES_BUILDER StringBuilder,\n    _In_ ULONG level,\n    _In_ ULONG flags\n    )\n{\n    if (FlagOn(flags, JSON_C_TO_STRING_PRETTY))\n    {\n        // Print the indentation 'level' times\n        for (ULONG i = 0; i < level; i++)\n        {\n            if (FlagOn(flags, JSON_C_TO_STRING_PRETTY_TAB))\n            {\n                PhAppendBytesBuilder2(StringBuilder, \"\\t\");\n            }\n            else\n            {\n                // Standard 2-space indentation\n                //PhAppendBytesBuilder2(StringBuilder, \"  \");\n            }\n        }\n    }\n}\n\nstatic void PhJsonObjectToJsonStringEscape(\n    _In_ PPH_BYTES_BUILDER StringBuilder,\n    _In_ PCSTR JsonString,\n    _In_ SIZE_T Length,\n    _In_ ULONG Flags\n    )\n{\n    SIZE_T pos = 0;\n    SIZE_T offset = 0;\n    UCHAR c;\n\n    while (Length)\n    {\n        --Length;\n        c = JsonString[pos];\n\n        switch (c)\n        {\n        case '\\b':\n        case '\\n':\n        case '\\r':\n        case '\\t':\n        case '\\f':\n        case '\"':\n        case '\\\\':\n        case '/':\n            {\n                if ((Flags & JSON_C_TO_STRING_NOSLASHESCAPE) && c == '/')\n                {\n                    pos++;\n                    break;\n                }\n\n                if (pos > offset)\n                {\n                    PH_BYTESREF string;\n                    string.Buffer = (PCH)(JsonString + offset);\n                    string.Length = pos - offset;\n                    PhAppendBytesBuilder(StringBuilder, &string);\n                }\n\n                if (c == '\\b') PhAppendBytesBuilder2(StringBuilder, \"\\\\b\");\n                else if (c == '\\n') PhAppendBytesBuilder2(StringBuilder, \"\\\\n\");\n                else if (c == '\\r') PhAppendBytesBuilder2(StringBuilder, \"\\\\r\");\n                else if (c == '\\t') PhAppendBytesBuilder2(StringBuilder, \"\\\\t\");\n                else if (c == '\\f') PhAppendBytesBuilder2(StringBuilder, \"\\\\f\");\n                else if (c == '\"') PhAppendBytesBuilder2(StringBuilder, \"\\\\\\\"\");\n                else if (c == '\\\\') PhAppendBytesBuilder2(StringBuilder, \"\\\\\\\\\");\n                else if (c == '/') PhAppendBytesBuilder2(StringBuilder, \"\\\\/\");\n\n                offset = ++pos;\n            }\n            break;\n        default:\n            {\n                if (c < ' ')\n                {\n                    if (pos > offset)\n                    {\n                        PH_BYTESREF string;\n                        string.Buffer = (PCH)(JsonString + offset);\n                        string.Length = pos - offset;\n                        PhAppendBytesBuilder(StringBuilder, &string);\n                    }\n\n                    char buffer[7];\n                    const char* json_hex_chars = \"0123456789abcdefABCDEF\";\n                    sprintf_s(buffer, sizeof(buffer), \"\\\\u00%c%c\", json_hex_chars[c >> 4], json_hex_chars[c & 0xf]);\n                    \n                    PH_BYTESREF string;\n                    string.Buffer = buffer;\n                    string.Length = (SIZE_T)strlen(buffer);\n                    PhAppendBytesBuilder(StringBuilder, &string);\n\n                    offset = ++pos;\n                }\n                else\n                {\n                    pos++;\n                }\n            }\n            break;\n        }\n    }\n\n    if (pos > offset)\n    {\n        PH_BYTESREF string;\n        string.Buffer = (PCH)(JsonString + offset);\n        string.Length = pos - offset;\n        PhAppendBytesBuilder(StringBuilder, &string);\n    }\n}\n\nstatic BOOLEAN PhInternalJsonObjectObjectToString(\n    _In_ PPH_BYTES_BUILDER StringBuilder,\n    _In_ PVOID Object,\n    _In_ ULONG Level,\n    _In_ ULONG Flags\n    )\n{\n    struct json_object_iterator it = json_object_iter_begin(Object);\n    struct json_object_iterator itEnd = json_object_iter_end(Object);\n    BOOLEAN had_children = FALSE;\n\n    PhAppendBytesBuilder2(StringBuilder, \"{\");\n\n    while (!json_object_iter_equal(&it, &itEnd)) \n    {\n        const char* key = json_object_iter_peek_name(&it);\n        struct json_object* val = json_object_iter_peek_value(&it);\n\n        if (had_children)\n        {\n            PhAppendBytesBuilder2(StringBuilder, \",\");\n        }\n\n        if (FlagOn(Flags, JSON_C_TO_STRING_PRETTY))\n        {\n            PhAppendBytesBuilder2(StringBuilder, \"\\n\");\n        }\n\n        had_children = TRUE;\n\n        if ((Flags & JSON_C_TO_STRING_SPACED) && !(Flags & JSON_C_TO_STRING_PRETTY))\n        {\n            PhAppendBytesBuilder2(StringBuilder, \" \");\n        }\n\n        PhJsonObjectToJsonStringIndent(StringBuilder, Level + 1, Flags);\n\n        PhAppendBytesBuilder2(StringBuilder, \"\\\"\");\n        PhJsonObjectToJsonStringEscape(StringBuilder, key, strlen(key), Flags);\n        PhAppendBytesBuilder2(StringBuilder, \"\\\"\");\n\n        if (FlagOn(Flags, JSON_C_TO_STRING_SPACED))\n            PhAppendBytesBuilder2(StringBuilder, \": \");\n        else\n            PhAppendBytesBuilder2(StringBuilder, \":\");\n\n        if (val == NULL)\n        {\n            PhAppendBytesBuilder2(StringBuilder, \"null\");\n        }\n        else if (!PhJsonObjectToString(StringBuilder, val, Level + 1, Flags))\n        {\n            return FALSE;\n        }\n\n        json_object_iter_next(&it);\n    }\n\n    if (FlagOn(Flags, JSON_C_TO_STRING_PRETTY) && had_children)\n    {\n        PhAppendBytesBuilder2(StringBuilder, \"\\n\");\n        PhJsonObjectToJsonStringIndent(StringBuilder, Level, Flags);\n    }\n\n    if (FlagOn(Flags, JSON_C_TO_STRING_SPACED) && !(Flags & JSON_C_TO_STRING_PRETTY))\n    {\n        PhAppendBytesBuilder2(StringBuilder, \" }\");\n    }\n    else\n    {\n        PhAppendBytesBuilder2(StringBuilder, \"}\");\n    }\n\n    return TRUE;\n}\n\nstatic BOOLEAN PhInternalJsonObjectArrayToString(\n    _In_ PPH_BYTES_BUILDER StringBuilder,\n    _In_ PVOID Object,\n    _In_ ULONG Level,\n    _In_ ULONG Flags\n    )\n{\n    SIZE_T length = json_object_array_length(Object);\n    SIZE_T i;\n\n    PhAppendBytesBuilder2(StringBuilder, \"[\");\n\n    for (i = 0; i < length; i++)\n    {\n        struct json_object* value = json_object_array_get_idx(Object, i);\n\n        if (i > 0)\n        {\n            PhAppendBytesBuilder2(StringBuilder, \",\");\n        }\n\n        if (FlagOn(Flags, JSON_C_TO_STRING_PRETTY))\n        {\n            PhAppendBytesBuilder2(StringBuilder, \"\\n\");\n        }\n\n        if ((Flags & JSON_C_TO_STRING_SPACED) && !(Flags & JSON_C_TO_STRING_PRETTY))\n        {\n            PhAppendBytesBuilder2(StringBuilder, \" \");\n        }\n\n        PhJsonObjectToJsonStringIndent(StringBuilder, Level + 1, Flags);\n\n        if (value == NULL) // Should not happen in json-c arrays\n        {\n             PhAppendBytesBuilder2(StringBuilder, \"null\");\n        }\n        else\n        {\n            if (!PhJsonObjectToString(StringBuilder, value, Level + 1, Flags))\n                return FALSE;\n        }\n    }\n\n    if (FlagOn(Flags, JSON_C_TO_STRING_PRETTY) && length > 0)\n    {\n        PhAppendBytesBuilder2(StringBuilder, \"\\n\");\n        PhJsonObjectToJsonStringIndent(StringBuilder, Level, Flags);\n    }\n\n    if (FlagOn(Flags, JSON_C_TO_STRING_SPACED) && !(Flags & JSON_C_TO_STRING_PRETTY))\n        PhAppendBytesBuilder2(StringBuilder, \" ]\");\n    else\n        PhAppendBytesBuilder2(StringBuilder, \"]\");\n\n    return TRUE;\n}\n\nBOOLEAN PhJsonObjectToString(\n    _In_ PPH_BYTES_BUILDER StringBuilder,\n    _In_ PVOID Object,\n    _In_ ULONG Level,\n    _In_ ULONG Flags\n    )\n{\n    switch (json_object_get_type(Object))\n    {\n    case json_type_null:\n        {\n            PhAppendBytesBuilder2(StringBuilder, \"null\");\n        }\n        break;\n    case json_type_boolean:\n        {\n            if (json_object_get_boolean(Object))\n                PhAppendBytesBuilder2(StringBuilder, \"true\");\n            else\n                PhAppendBytesBuilder2(StringBuilder, \"false\");\n        }\n        break;\n    case json_type_double:\n        {\n            SIZE_T returnLength;\n            CHAR formatBuffer[_CVTBUFSIZE + 1];\n\n            if (NT_SUCCESS(PhFormatDoubleToUtf8(\n                json_object_get_double(Object),\n                FormatStandardForm,\n                -1,\n                formatBuffer,\n                sizeof(formatBuffer),\n                &returnLength\n                )))\n            {\n                PH_BYTESREF stringFormat;\n\n                stringFormat.Buffer = formatBuffer;\n                stringFormat.Length = returnLength - sizeof(ANSI_NULL);\n\n                PhAppendBytesBuilder(StringBuilder, &stringFormat);\n            }\n            else\n            {\n                CHAR buffer[64];\n\n                // %.17g is standard to preserve double precision in text\n                if (sprintf_s(buffer, sizeof(buffer), \"%.17g\", json_object_get_double(Object)) > 0)\n                {\n                    // Handle specific JSON quirk: if double looks like int (no dot), append .0?\n                    // Standard JSON-C usually handles this, but strictly speaking \"1\" is a valid double in JSON.\n                    // We stick to the string output.\n                    PhAppendBytesBuilder2(StringBuilder, buffer);\n                }\n            }\n        }\n        break;\n    case json_type_int:\n        {\n            SIZE_T returnLength;\n            //PH_FORMAT format[1];\n            //WCHAR formatBuffer[260];\n            //\n            //PhInitFormatI64D(&format[0], json_object_get_int64(Object));\n            //\n            //if (PhFormatToBuffer(\n            //    format,\n            //    RTL_NUMBER_OF(format),\n            //    formatBuffer,\n            //    sizeof(formatBuffer),\n            //    &returnLength\n            //    ))\n            //{\n            //    PH_BYTESREF stringFormat;\n            //\n            //    stringFormat.Buffer = formatBuffer;\n            //    stringFormat.Length = returnLength - sizeof(ANSI_NULL);\n            //\n            //    PhAppendBytesBuilder(StringBuilder, &stringFormat);\n            //}\n            //else\n            {\n                CHAR formatBuffer[65];\n\n                if (NT_SUCCESS(PhIntegerToUtf8Buffer(\n                    json_object_get_int64(Object),\n                    10,\n                    TRUE,\n                    formatBuffer,\n                    sizeof(formatBuffer),\n                    &returnLength\n                    )))\n                {\n                    PH_BYTESREF stringFormat;\n\n                    stringFormat.Buffer = formatBuffer;\n                    stringFormat.Length = returnLength - sizeof(ANSI_NULL);\n\n                    PhAppendBytesBuilder(StringBuilder, &stringFormat);\n                }\n                else\n                {\n                    if (sprintf_s(formatBuffer, sizeof(formatBuffer), \"%lld\", json_object_get_int64(Object)) > 0)\n                    {\n                        PhAppendBytesBuilder2(StringBuilder, formatBuffer);\n                    }\n                }\n            }\n        }\n        break;\n    case json_type_object:\n        {\n            return PhInternalJsonObjectObjectToString(StringBuilder, Object, Level, Flags);\n        }\n        break;\n    case json_type_array:\n        {\n            return PhInternalJsonObjectArrayToString(StringBuilder, Object, Level, Flags);\n        }\n        break;\n    case json_type_string:\n        {\n            PhAppendBytesBuilder2(StringBuilder, \"\\\"\");\n            PhJsonObjectToJsonStringEscape(\n                StringBuilder,\n                json_object_get_string(Object),\n                (size_t)json_object_get_string_len(Object),\n                Flags\n                );\n            PhAppendBytesBuilder2(StringBuilder, \"\\\"\");\n        }\n        break;\n    default:\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nPPH_BYTES PhJsonObjectToJsonString(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PH_BYTES_BUILDER stringBuilder;\n\n    PhInitializeBytesBuilder(&stringBuilder, 25 * 1000);\n\n    if (PhJsonObjectToString(&stringBuilder, Object, 0, Flags))\n    {\n        return PhFinalBytesBuilderBytes(&stringBuilder);\n    }\n\n    PhDeleteBytesBuilder(&stringBuilder);\n    return NULL;\n}\n\nNTSTATUS PhSaveJsonObjectToFile(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PVOID Object,\n    _In_opt_ ULONG Flags\n    )\n{\n    static CONST PH_STRINGREF extension = PH_STRINGREF_INIT(L\".backup\");\n    NTSTATUS status;\n    ULONG json_flags = 0;\n    HANDLE fileHandle = NULL;\n    PPH_STRING fileName;\n    IO_STATUS_BLOCK ioStatusBlock;\n    LARGE_INTEGER allocationSize;\n    PPH_BYTES jsonStringUtf8;\n    //SIZE_T json_length;\n    //PCSTR json_string;\n\n    json_flags = 0;\n    PhMapFlags1(&json_flags, Flags, PhJsonFormatFlagMappings, RTL_NUMBER_OF(PhJsonFormatFlagMappings));\n\n    jsonStringUtf8 = PhJsonObjectToJsonString(Object, json_flags);\n\n    //json_string = json_object_to_json_string_length(\n    //    Object,\n    //    json_flags,\n    //    &json_length\n    //    );\n\n    if (!jsonStringUtf8 || jsonStringUtf8->Length == 0)\n        return STATUS_UNSUCCESSFUL;\n\n    // Preallocate the file size.\n\n    allocationSize.QuadPart = jsonStringUtf8->Length;\n\n    // Create the directory if it does not exist.\n\n    status = PhCreateDirectoryFullPath(FileName);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Create a temporary filename.\n\n    fileName = PhGetBaseNameChangeExtension(FileName, &extension);\n\n    // Create the temporary file.\n\n    status = PhCreateFileEx(\n        &fileHandle,\n        &fileName->sr,\n        FILE_GENERIC_WRITE | DELETE,\n        NULL,\n        &allocationSize,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_NONE,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL\n        );\n\n    // Cleanup the temporary filename.\n\n    PhDereferenceObject(fileName);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Write the buffer to the temporary file.\n\n    status = NtWriteFile(\n        fileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &ioStatusBlock,\n        (PVOID)jsonStringUtf8->Buffer,\n        (ULONG)jsonStringUtf8->Length,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Flush the temporary file.\n\n    PhFlushBuffersFile(fileHandle);\n\n    // Atomically update the target file:\n    // https://learn.microsoft.com/en-us/windows/win32/fileio/deprecation-of-txf#applications-updating-a-single-file-with-document-like-data\n\n    status = PhSetFileRename(\n        fileHandle,\n        NULL,\n        TRUE,\n        FileName\n        );\n\nCleanupExit:\n    if (fileHandle)\n    {\n        NtClose(fileHandle);\n    }\n\n    if (jsonStringUtf8)\n    {\n        PhDereferenceObject(jsonStringUtf8);\n    }\n\n    return status;\n}\n\n// XML support\n\nstatic mxml_node_t* PhXmlLoadString(\n    _In_ PCSTR String\n    )\n{\n    mxml_options_t* options;\n    mxml_node_t* currentNode;\n\n    options = mxmlOptionsNew();\n    mxmlOptionsSetTypeValue(options, MXML_TYPE_OPAQUE);\n\n    currentNode = mxmlLoadString(NULL, options, String);\n\n    mxmlOptionsDelete(options);\n\n    return currentNode;\n}\n\nstatic PPH_BYTES PhXmlSaveString(\n    _In_ PVOID XmlRootObject,\n    _In_opt_ PVOID XmlSaveCallback\n    )\n{\n    mxml_options_t* options;\n    PPH_BYTES string;\n\n    options = mxmlOptionsNew();\n    mxmlOptionsSetTypeValue(options, MXML_TYPE_OPAQUE);\n\n    if (XmlSaveCallback)\n    {\n        mxmlOptionsSetWhitespaceCallback(options, XmlSaveCallback, NULL);\n    }\n\n    string = PhCreateBytes(mxmlSaveAllocString(XmlRootObject, options));\n    mxmlOptionsDelete(options);\n\n    return string;\n}\n\nPVOID PhLoadXmlObjectFromString(\n    _In_ PCSTR String\n    )\n{\n    mxml_node_t* currentNode;\n\n    if (currentNode = PhXmlLoadString(String))\n    {\n        if (mxmlGetType(currentNode) == MXML_TYPE_ELEMENT)\n        {\n            return currentNode;\n        }\n\n        mxmlDelete(currentNode);\n    }\n\n    return NULL;\n}\n\nPVOID PhLoadXmlObjectFromString2(\n    _In_ PCSTR String\n    )\n{\n    mxml_node_t* currentNode;\n\n    if (currentNode = PhXmlLoadString(String))\n    {\n        return currentNode;\n    }\n\n    return NULL;\n}\n\nNTSTATUS PhLoadXmlObjectFromFile(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_opt_ PVOID* XmlRootObject\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    LARGE_INTEGER fileSize;\n    PPH_BYTES fileContent;\n    mxml_node_t* currentNode = NULL;\n\n    status = PhCreateFile(\n        &fileHandle,\n        FileName,\n        FILE_GENERIC_READ,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0)\n    {\n        // A blank file is OK.\n        NtClose(fileHandle);\n        return STATUS_END_OF_FILE;\n    }\n\n    if (NT_SUCCESS(status = PhGetFileText(&fileContent, fileHandle, FALSE)))\n    {\n        currentNode = PhXmlLoadString(fileContent->Buffer);\n        PhDereferenceObject(fileContent);\n    }\n\n    NtClose(fileHandle);\n\n    if (currentNode)\n    {\n        if (mxmlGetType(currentNode) == MXML_TYPE_ELEMENT)\n        {\n            if (XmlRootObject)\n                *XmlRootObject = currentNode;\n\n            return STATUS_SUCCESS;\n        }\n\n        mxmlDelete(currentNode);\n    }\n\n    return STATUS_FILE_CORRUPT_ERROR;\n}\n\nNTSTATUS PhSaveXmlObjectToFile(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PVOID XmlRootObject,\n    _In_opt_ PVOID XmlSaveCallback\n    )\n{\n    static CONST PH_STRINGREF extension = PH_STRINGREF_INIT(L\".tmp\");\n    NTSTATUS status;\n    PPH_STRING fileName;\n    HANDLE fileHandle = NULL;\n    LARGE_INTEGER allocationSize;\n    PPH_BYTES string;\n\n    string = PhXmlSaveString(XmlRootObject, XmlSaveCallback);\n\n    if (!string)\n    {\n        status = STATUS_UNSUCCESSFUL;\n        goto CleanupExit;\n    }\n\n    allocationSize.QuadPart = string->Length;\n\n    // Create the directory if it does not exist.\n\n    status = PhCreateDirectoryFullPath(FileName);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Create a temporary filename.\n\n    fileName = PhGetBaseNameChangeExtension(FileName, &extension);\n\n    // Create the temporary file.\n\n    status = PhCreateFileEx(\n        &fileHandle,\n        &fileName->sr,\n        FILE_GENERIC_WRITE | DELETE,\n        NULL,\n        &allocationSize,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_NONE,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL\n        );\n\n    // Cleanup the temporary filename.\n\n    PhDereferenceObject(fileName);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Write the buffer to the temporary file.\n\n    status = PhWriteFile(\n        fileHandle,\n        (PVOID)string->Buffer,\n        (ULONG)string->Length,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Flush the temporary file.\n\n    PhFlushBuffersFile(fileHandle);\n\n    // Atomically update the target file:\n    // https://learn.microsoft.com/en-us/windows/win32/fileio/deprecation-of-txf#applications-updating-a-single-file-with-document-like-data\n\n    status = PhSetFileRename(\n        fileHandle,\n        NULL,\n        TRUE,\n        FileName\n        );\n\nCleanupExit:\n    if (fileHandle)\n    {\n        NtClose(fileHandle);\n    }\n\n    if (string)\n    {\n        PhDereferenceObject(string);\n    }\n\n    return status;\n}\n\nVOID PhFreeXmlObject(\n    _In_ PVOID XmlRootObject\n    )\n{\n    mxmlDelete(XmlRootObject);\n}\n\nPVOID PhGetXmlObject(\n    _In_ PVOID XmlNodeObject,\n    _In_ PCSTR Path\n    )\n{\n    mxml_node_t* currentNode;\n    mxml_node_t* realNode;\n\n    if (currentNode = mxmlFindPath(XmlNodeObject, Path))\n    {\n        if (realNode = mxmlGetParent(currentNode))\n            return realNode;\n\n        return currentNode;\n    }\n\n    return NULL;\n}\n\nPVOID PhCreateXmlNode(\n    _In_opt_ PVOID ParentNode,\n    _In_ PCSTR Name\n    )\n{\n    return mxmlNewElement(ParentNode, Name);\n}\n\nPVOID PhCreateXmlOpaqueNode(\n    _In_opt_ PVOID ParentNode,\n    _In_ PCSTR Value\n    )\n{\n    return mxmlNewOpaque(ParentNode, Value);\n}\n\nPVOID PhFindXmlObject(\n    _In_ PVOID XmlNodeObject,\n    _In_opt_ PVOID XmlTopObject,\n    _In_opt_ PCSTR Element,\n    _In_opt_ PCSTR Attribute,\n    _In_opt_ PCSTR Value\n    )\n{\n    return mxmlFindElement(XmlNodeObject, XmlTopObject, Element, Attribute, Value, MXML_DESCEND_ALL);\n}\n\nPVOID PhGetXmlNodeFirstChild(\n    _In_ PVOID XmlNodeObject\n    )\n{\n    return mxmlGetFirstChild(XmlNodeObject);\n}\n\nPVOID PhGetXmlNodeNextChild(\n    _In_ PVOID XmlNodeObject\n    )\n{\n    return mxmlGetNextSibling(XmlNodeObject);\n}\n\nPPH_STRING PhGetXmlNodeOpaqueText(\n    _In_ PVOID XmlNodeObject\n    )\n{\n    PCSTR string;\n\n    if (string = mxmlGetOpaque(XmlNodeObject))\n    {\n        return PhConvertUtf8ToUtf16(string);\n    }\n    else\n    {\n        return PhReferenceEmptyString();\n    }\n}\n\nPCSTR PhGetXmlNodeElementText(\n    _In_ PVOID XmlNodeObject\n    )\n{\n    return mxmlGetElement(XmlNodeObject);\n}\n\nPCSTR PhGetXmlNodeCDATAText(\n    _In_ PVOID XmlNodeObject\n    )\n{\n    return mxmlGetCDATA(XmlNodeObject);\n}\n\nPPH_STRING PhGetXmlNodeAttributeText(\n    _In_ PVOID XmlNodeObject,\n    _In_ PCSTR AttributeName\n    )\n{\n    PCSTR string;\n\n    if (string = mxmlElementGetAttr(XmlNodeObject, AttributeName))\n    {\n        return PhConvertUtf8ToUtf16(string);\n    }\n\n    return NULL;\n}\n\nPCSTR PhGetXmlNodeAttributeByIndex(\n    _In_ PVOID XmlNodeObject,\n    _In_ SIZE_T Index,\n    _Out_ PCSTR* AttributeName\n    )\n{\n    return mxmlElementGetAttrByIndex(XmlNodeObject, Index, AttributeName);\n}\n\nVOID PhSetXmlNodeAttributeText(\n    _In_ PVOID XmlNodeObject,\n    _In_ PCSTR Name,\n    _In_ PCSTR Value\n    )\n{\n    mxmlElementSetAttr(XmlNodeObject, Name, Value);\n}\n\nSIZE_T PhGetXmlNodeAttributeCount(\n    _In_ PVOID XmlNodeObject\n    )\n{\n    return mxmlElementGetAttrCount(XmlNodeObject);\n}\n\ntypedef BOOLEAN (NTAPI* PPH_ENUM_XML_NODE_CALLBACK)(\n    _In_ PVOID XmlNodeObject,\n    _In_opt_ PVOID Context\n    );\n\nBOOLEAN PhEnumXmlNode(\n    _In_ PVOID XmlNodeObject,\n    _In_ PPH_ENUM_XML_NODE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PVOID currentNode;\n\n    currentNode = PhGetXmlNodeFirstChild(XmlNodeObject);\n\n    while (currentNode)\n    {\n        if (Callback(currentNode, Context))\n            break;\n\n        currentNode = PhGetXmlNodeNextChild(currentNode);\n    }\n\n    return TRUE;\n}\n\nPPH_XML_INTERFACE PhGetXmlInterface(\n    _In_ ULONG Version\n    )\n{\n    static PH_XML_INTERFACE PhXmlInterface =\n    {\n        PH_XML_INTERFACE_VERSION,\n        PhLoadXmlObjectFromString,\n        PhLoadXmlObjectFromFile,\n        PhSaveXmlObjectToFile,\n        PhFreeXmlObject,\n        PhGetXmlObject,\n        PhCreateXmlNode,\n        PhCreateXmlOpaqueNode,\n        PhFindXmlObject,\n        PhGetXmlNodeFirstChild,\n        PhGetXmlNodeNextChild,\n        PhGetXmlNodeOpaqueText,\n        PhGetXmlNodeElementText,\n        PhGetXmlNodeAttributeText,\n        PhGetXmlNodeAttributeByIndex,\n        PhSetXmlNodeAttributeText,\n        PhGetXmlNodeAttributeCount\n    };\n\n    if (Version < PH_XML_INTERFACE_VERSION)\n        return NULL;\n\n    return &PhXmlInterface;\n}\n"
  },
  {
    "path": "phlib/kph.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2018-2023\n *\n */\n\n#include <ph.h>\n#include <svcsup.h>\n#include <kphuser.h>\n\nstatic CONST PH_STRINGREF KphDefaultPortName = PH_STRINGREF_INIT(KPH_PORT_NAME);\nstatic PPH_OBJECT_TYPE KphMessageObjectType = NULL;\nstatic PPH_OBJECT_TYPE KphUserMessageObjectType = NULL;\n\nVOID KphInitialize(\n    VOID\n    )\n{\n    PH_OBJECT_TYPE_PARAMETERS parameters;\n\n    parameters.FreeListSize = ALIGN_UP_BY(KPH_MESSAGE_MIN_SIZE, 1024);\n    parameters.FreeListCount = 65536;\n\n    KphMessageObjectType = PhCreateObjectTypeEx(\n        L\"KsiMessage\",\n        PH_OBJECT_TYPE_TRY_USE_FREE_LIST,\n        NULL,\n        &parameters\n        );\n\n    parameters.FreeListSize = KPH_MESSAGE_MIN_SIZE;\n    parameters.FreeListCount = 16;\n\n    KphUserMessageObjectType = PhCreateObjectTypeEx(\n        L\"KsiUserMessage\",\n        PH_OBJECT_TYPE_USE_FREE_LIST,\n        NULL,\n        &parameters\n        );\n}\n\nPKPH_MESSAGE KphCreateMessage(\n    _In_ SIZE_T Size\n    )\n{\n    assert(KphMessageObjectType);\n\n    return PhCreateObject(Size, KphMessageObjectType);\n}\n\nPKPH_MESSAGE KphCreateUserMessage(\n    _In_ KPH_MESSAGE_ID MessageId\n    )\n{\n    PKPH_MESSAGE msg;\n\n    assert(KphUserMessageObjectType);\n\n    msg = PhCreateObject(KPH_MESSAGE_MIN_SIZE, KphUserMessageObjectType);\n\n    KphMsgInit(msg, MessageId);\n\n    return msg;\n}\n\nNTSTATUS KphConnect(\n    _In_ PKPH_CONFIG_PARAMETERS Config\n    )\n{\n    NTSTATUS status;\n    SC_HANDLE serviceHandle;\n    BOOLEAN created = FALSE;\n    PCPH_STRINGREF portName;\n\n    portName = (Config->PortName ? Config->PortName : &KphDefaultPortName);\n\n    status = KphCommsStart(portName, Config->Callback, Config->RingBufferLength);\n\n    if (NT_SUCCESS(status) || (status == STATUS_ALREADY_INITIALIZED))\n        return status;\n\n    // Load the driver, and try again.\n\n    if (Config->EnableNativeLoad || Config->EnableFilterLoad)\n    {\n        status = KsiLoadUnloadService(Config, TRUE);\n\n        if (NT_SUCCESS(status))\n        {\n            status = KphCommsStart(portName, Config->Callback, Config->RingBufferLength);\n        }\n\n        return status;\n    }\n\n    // Try to start the service, if it exists.\n\n    status = PhOpenService(&serviceHandle, SERVICE_START | SERVICE_QUERY_STATUS, PhGetStringRefZ(Config->ServiceName));\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhStartService(serviceHandle, 0, NULL);\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhWaitForServiceStatus(serviceHandle, SERVICE_RUNNING, 5000);\n        }\n\n        PhCloseServiceHandle(serviceHandle);\n        serviceHandle = NULL;\n\n        if (!NT_SUCCESS(status))\n            goto CreateAndConnectEnd;\n\n        status = KphCommsStart(portName, Config->Callback, Config->RingBufferLength);\n\n        goto CreateAndConnectEnd;\n    }\n\n    if (!PhDoesFileExistWin32(PhGetStringRefZ(Config->FileName)))\n    {\n        status = STATUS_NO_SUCH_FILE;\n        goto CreateAndConnectEnd;\n    }\n\n    // Try to create the service.\n\n    status = PhCreateService(\n        &serviceHandle,\n        PhGetStringRefZ(Config->ServiceName),\n        PhGetStringRefZ(Config->ServiceName),\n        SERVICE_ALL_ACCESS,\n        SERVICE_KERNEL_DRIVER,\n        SERVICE_DEMAND_START,\n        SERVICE_ERROR_IGNORE,\n        PhGetStringRefZ(Config->FileName),\n        PhGetStringRefZ(Config->ObjectName),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CreateAndConnectEnd;\n\n    created = TRUE;\n\n    KphSetServiceSecurity(serviceHandle);\n\n    status = KphSetParameters(Config);\n\n    if (!NT_SUCCESS(status))\n        goto CreateAndConnectEnd;\n\n    status = PhStartService(serviceHandle, 0, NULL);\n\n    if (!NT_SUCCESS(status))\n        goto CreateAndConnectEnd;\n\n    status = PhWaitForServiceStatus(serviceHandle, SERVICE_RUNNING, 5000);\n\n    if (!NT_SUCCESS(status))\n        goto CreateAndConnectEnd;\n\n    status = KphCommsStart(portName, Config->Callback, Config->RingBufferLength);\n\nCreateAndConnectEnd:\n\n    if (created && serviceHandle)\n    {\n        //\n        // \"Delete\" the service (mark it for deletion), SCM will retain the\n        // service entry as long as the \"ObjectName\" exists. We do not use a\n        // device object, SCM will detect that the driver has gone away by the\n        // driver object (the specified \"ObjectName\").\n        //\n        PhDeleteService(serviceHandle);\n        PhCloseServiceHandle(serviceHandle);\n    }\n\n    return status;\n}\n\nNTSTATUS KphpSetParametersService(\n    _In_ PKPH_CONFIG_PARAMETERS Config\n    )\n{\n#ifdef _WIN64\n    NTSTATUS status;\n    HANDLE servicesKeyHandle = NULL;\n    ULONG disposition;\n    SIZE_T returnLength;\n    PH_STRINGREF servicesKeyName;\n    PH_FORMAT format[3];\n    WCHAR servicesKeyNameBuffer[MAX_PATH];\n\n    PhInitFormatS(&format[0], L\"System\\\\CurrentControlSet\\\\Services\");\n    PhInitFormatSR(&format[1], PhNtPathSeparatorString);\n    PhInitFormatSR(&format[2], *Config->ServiceName);\n\n    if (!PhFormatToBuffer(\n        format,\n        RTL_NUMBER_OF(format),\n        servicesKeyNameBuffer,\n        sizeof(servicesKeyNameBuffer),\n        &returnLength\n        ))\n    {\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    servicesKeyName.Buffer = servicesKeyNameBuffer;\n    servicesKeyName.Length = returnLength - sizeof(UNICODE_NULL);\n\n    status = PhCreateKey(\n        &servicesKeyHandle,\n        KEY_WRITE | DELETE,\n        PH_KEY_LOCAL_MACHINE,\n        &servicesKeyName,\n        0,\n        0,\n        &disposition\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhSetValueKeyZ(\n        servicesKeyHandle,\n        L\"SupportedFeatures\",\n        REG_DWORD,\n        &Config->FsSupportedFeatures,\n        sizeof(ULONG)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\nCleanupExit:\n\n    if (servicesKeyHandle)\n        NtClose(servicesKeyHandle);\n\n    return status;\n#else\n    return STATUS_NOT_SUPPORTED;\n#endif\n}\n\nNTSTATUS KphSetParameters(\n    _In_ PKPH_CONFIG_PARAMETERS Config\n    )\n{\n#ifdef _WIN64\n    NTSTATUS status;\n    HANDLE parametersKeyHandle = NULL;\n    ULONG disposition;\n    SIZE_T returnLength;\n    PH_STRINGREF parametersKeyName;\n    PH_FORMAT format[4];\n    WCHAR parametersKeyNameBuffer[MAX_PATH];\n\n    // Services key parameters.\n    status = KphpSetParametersService(Config);\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!Config->PortName &&\n        !Config->Altitude &&\n        !Config->Flags.Flags &&\n        !Config->SystemProcessName)\n    {\n        // Don't create parameters key unless we must.\n        return STATUS_SUCCESS;\n    }\n\n    PhInitFormatS(&format[0], L\"System\\\\CurrentControlSet\\\\Services\");\n    PhInitFormatSR(&format[1], PhNtPathSeparatorString);\n    PhInitFormatSR(&format[2], *Config->ServiceName);\n    PhInitFormatS(&format[3], L\"\\\\Parameters\");\n\n    if (!PhFormatToBuffer(\n        format,\n        RTL_NUMBER_OF(format),\n        parametersKeyNameBuffer,\n        sizeof(parametersKeyNameBuffer),\n        &returnLength\n        ))\n    {\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    parametersKeyName.Buffer = parametersKeyNameBuffer;\n    parametersKeyName.Length = returnLength - sizeof(UNICODE_NULL);\n\n    status = PhCreateKey(\n        &parametersKeyHandle,\n        KEY_WRITE | DELETE,\n        PH_KEY_LOCAL_MACHINE,\n        &parametersKeyName,\n        0,\n        0,\n        &disposition\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (Config->PortName)\n    {\n        status = PhSetValueKeyStringZ(parametersKeyHandle, L\"PortName\", Config->PortName);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    if (Config->Altitude)\n    {\n        status = PhSetValueKeyStringZ(parametersKeyHandle, L\"Altitude\", Config->Altitude);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    if (Config->Flags.Flags)\n    {\n        C_ASSERT(sizeof(KPH_PARAMETER_FLAGS) == sizeof(ULONG));\n\n        status = PhSetValueKeyUlong(parametersKeyHandle, L\"Flags\", Config->Flags.Flags);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    if (Config->SystemProcessName)\n    {\n        status = PhSetValueKeyZ(\n            parametersKeyHandle,\n            L\"SystemProcessName\",\n            REG_SZ,\n            Config->SystemProcessName->Buffer,\n            (ULONG)Config->SystemProcessName->Length + sizeof(UNICODE_NULL)\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    // Put more parameters here...\n\n    status = STATUS_SUCCESS;\n\nCleanupExit:\n    if (!NT_SUCCESS(status))\n    {\n        // Delete the key if we created it.\n        if (disposition == REG_CREATED_NEW_KEY)\n            NtDeleteKey(parametersKeyHandle);\n    }\n\n    NtClose(parametersKeyHandle);\n\n    return status;\n#else\n    return STATUS_NOT_SUPPORTED;\n#endif\n}\n\nVOID KphSetServiceSecurity(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    PSID administratorsSid = PhSeAdministratorsSid();\n    UCHAR securityDescriptorBuffer[SECURITY_DESCRIPTOR_MIN_LENGTH + 0x80];\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    ULONG sdAllocationLength;\n    PACL dacl;\n\n    sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH +\n        (ULONG)sizeof(ACL) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        PhLengthSid(&PhSeServiceSid) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        PhLengthSid(administratorsSid) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        PhLengthSid(&PhSeInteractiveSid);\n\n    securityDescriptor = (PSECURITY_DESCRIPTOR)securityDescriptorBuffer;\n    dacl = PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH);\n\n    PhCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n    PhCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION);\n    PhAddAccessAllowedAce(dacl, ACL_REVISION, SERVICE_ALL_ACCESS, &PhSeServiceSid);\n    PhAddAccessAllowedAce(dacl, ACL_REVISION, SERVICE_ALL_ACCESS, administratorsSid);\n    PhAddAccessAllowedAce(dacl, ACL_REVISION,\n        SERVICE_QUERY_CONFIG |\n        SERVICE_QUERY_STATUS |\n        SERVICE_START |\n        SERVICE_STOP |\n        SERVICE_INTERROGATE |\n        DELETE,\n        &PhSeInteractiveSid\n        );\n    PhSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE);\n\n    PhSetServiceObjectSecurity(ServiceHandle, DACL_SECURITY_INFORMATION, securityDescriptor);\n\n    NT_ASSERT(RtlValidSecurityDescriptor(securityDescriptor));\n    NT_ASSERT(sdAllocationLength < sizeof(securityDescriptorBuffer));\n    NT_ASSERT(RtlLengthSecurityDescriptor(securityDescriptor) < sizeof(securityDescriptorBuffer));\n}\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nstatic BOOLEAN NTAPI KsiLoadUnloadServiceCleanupKeyCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PKEY_BASIC_INFORMATION Information,\n    _In_ PVOID Context\n    )\n{\n    HANDLE keyHandle;\n    PH_STRINGREF keyName;\n\n    keyName.Buffer = Information->Name;\n    keyName.Length = Information->NameLength;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ | DELETE,\n        RootDirectory,\n        &keyName,\n        0\n        )))\n    {\n        PhEnumerateKey(keyHandle, KeyBasicInformation, KsiLoadUnloadServiceCleanupKeyCallback, NULL);\n        NtDeleteKey(keyHandle);\n        NtClose(keyHandle);\n    }\n\n    return TRUE;\n}\n\nNTSTATUS KsiLoadUnloadService(\n    _In_ PKPH_CONFIG_PARAMETERS Config,\n    _In_ BOOLEAN LoadDriver\n    )\n{\n#ifdef _WIN64\n    static CONST PH_STRINGREF fullServicesKeyName = PH_STRINGREF_INIT(L\"\\\\Registry\\\\Machine\\\\System\\\\CurrentControlSet\\\\Services\\\\\");\n    static CONST PH_STRINGREF parametersKeyName = PH_STRINGREF_INIT(L\"Parameters\");\n    NTSTATUS status;\n    PPH_STRING fullServiceKeyName;\n    PPH_STRING fullServiceFileName;\n    UNICODE_STRING driverServiceKeyName;\n    HANDLE serviceKeyHandle;\n    HANDLE parametersKeyHandle = NULL;\n    ULONG disposition;\n\n    NT_ASSERT(Config->FileName);\n    NT_ASSERT(Config->ServiceName);\n    NT_ASSERT(Config->ObjectName);\n\n    fullServiceKeyName = PhConcatStringRef2(&fullServicesKeyName, Config->ServiceName);\n\n    if (!PhStringRefToUnicodeString(&fullServiceKeyName->sr, &driverServiceKeyName))\n    {\n        PhDereferenceObject(fullServiceKeyName);\n        return STATUS_NAME_TOO_LONG;\n    }\n\n    status = PhCreateKey(\n        &serviceKeyHandle,\n        KEY_WRITE | KEY_CREATE_SUB_KEY,\n        NULL,\n        &fullServiceKeyName->sr,\n        0,\n        0,\n        &disposition\n        );\n\n    if (NT_SUCCESS(status) && disposition == REG_CREATED_NEW_KEY)\n    {\n        fullServiceFileName = PhConcatStringRef2(&PhNtDosDevicesPrefix, Config->FileName);\n        PhSetValueKeyUlong(serviceKeyHandle, L\"ErrorControl\", SERVICE_ERROR_NORMAL);\n        PhSetValueKeyUlong(serviceKeyHandle, L\"Type\", SERVICE_KERNEL_DRIVER);\n        PhSetValueKeyUlong(serviceKeyHandle, L\"Start\", SERVICE_DISABLED);\n        PhSetValueKeyStringZ(serviceKeyHandle, L\"ImagePath\", &fullServiceFileName->sr);\n        PhSetValueKeyStringZ(serviceKeyHandle, L\"ObjectName\", Config->ObjectName);\n        PhDereferenceObject(fullServiceFileName);\n\n        KphSetParameters(Config);\n\n        NtClose(serviceKeyHandle);\n    }\n\n    if (LoadDriver)\n    {\n        if (Config->EnableFilterLoad)\n            status = PhFilterLoadUnload(Config->ServiceName, TRUE);\n        else\n            status = NtLoadDriver(&driverServiceKeyName);\n\n        // Handle rare race condition with natively loading the driver.\n        if (status == STATUS_IMAGE_ALREADY_LOADED)\n            status = STATUS_SUCCESS;\n    }\n    else\n    {\n        if (Config->EnableFilterLoad)\n            status = PhFilterLoadUnload(Config->ServiceName, FALSE);\n        else\n            status = NtUnloadDriver(&driverServiceKeyName);\n    }\n\n    if (!NT_SUCCESS(status) || !LoadDriver)\n    {\n        if (NT_SUCCESS(PhOpenKey(\n            &serviceKeyHandle,\n            KEY_READ | DELETE,\n            NULL,\n            &fullServiceKeyName->sr,\n            0\n            )))\n        {\n            if (NT_SUCCESS(PhOpenKey(\n                &parametersKeyHandle,\n                DELETE,\n                serviceKeyHandle,\n                &parametersKeyName,\n                0\n                )))\n            {\n                NtDeleteKey(parametersKeyHandle);\n                NtClose(parametersKeyHandle);\n            }\n\n            PhEnumerateKey(serviceKeyHandle, KeyBasicInformation, KsiLoadUnloadServiceCleanupKeyCallback, NULL);\n            NtDeleteKey(serviceKeyHandle);\n            NtClose(serviceKeyHandle);\n        }\n    }\n\n    PhDereferenceObject(fullServiceKeyName);\n\n    return status;\n#else\n    return STATUS_NOT_SUPPORTED;\n#endif\n}\n\nNTSTATUS KphServiceStop(\n    _In_ PKPH_CONFIG_PARAMETERS Config\n    )\n{\n    NTSTATUS status;\n\n    //KphCommsStop();\n\n    if (Config->EnableNativeLoad || Config->EnableFilterLoad)\n    {\n        status = KsiLoadUnloadService(Config, FALSE);\n    }\n    else\n    {\n        SC_HANDLE serviceHandle;\n\n        status = PhOpenService(&serviceHandle, SERVICE_STOP, PhGetStringRefZ(Config->ServiceName));\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhStopService(serviceHandle);\n\n            PhCloseServiceHandle(serviceHandle);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS KphGetInformerSettings(\n    _Out_ PKPH_INFORMER_SETTINGS Settings\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgGetInformerSettings);\n    msg->User.GetInformerSettings.Settings = Settings;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.GetInformerSettings.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphSetInformerSettings(\n    _In_ PKPH_INFORMER_SETTINGS Settings\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgSetInformerSettings);\n    msg->User.SetInformerSettings.Settings = Settings;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.SetInformerSettings.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgOpenProcess);\n    msg->User.OpenProcess.ProcessHandle = ProcessHandle;\n    msg->User.OpenProcess.DesiredAccess = DesiredAccess;\n    msg->User.OpenProcess.ClientId = ClientId;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.OpenProcess.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgOpenProcessToken);\n    msg->User.OpenProcessToken.ProcessHandle = ProcessHandle;\n    msg->User.OpenProcessToken.DesiredAccess = DesiredAccess;\n    msg->User.OpenProcessToken.TokenHandle = TokenHandle;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.OpenProcessToken.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphOpenProcessJob(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE JobHandle\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgOpenProcessJob);\n    msg->User.OpenProcessJob.ProcessHandle = ProcessHandle;\n    msg->User.OpenProcessJob.DesiredAccess = DesiredAccess;\n    msg->User.OpenProcessJob.JobHandle = JobHandle;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.OpenProcessJob.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgTerminateProcess);\n    msg->User.TerminateProcess.ProcessHandle = ProcessHandle;\n    msg->User.TerminateProcess.ExitStatus = ExitStatus;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.TerminateProcess.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphReadVirtualMemory(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgReadVirtualMemory);\n    msg->User.ReadVirtualMemory.ProcessHandle = ProcessHandle;\n    msg->User.ReadVirtualMemory.BaseAddress = BaseAddress;\n    msg->User.ReadVirtualMemory.Buffer = Buffer;\n    msg->User.ReadVirtualMemory.BufferSize = BufferSize;\n    msg->User.ReadVirtualMemory.NumberOfBytesRead = NumberOfBytesRead;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.ReadVirtualMemory.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgOpenThread);\n    msg->User.OpenThread.ThreadHandle = ThreadHandle;\n    msg->User.OpenThread.DesiredAccess = DesiredAccess;\n    msg->User.OpenThread.ClientId = ClientId;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.OpenThread.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgOpenThreadProcess);\n    msg->User.OpenThreadProcess.ThreadHandle = ThreadHandle;\n    msg->User.OpenThreadProcess.DesiredAccess = DesiredAccess;\n    msg->User.OpenThreadProcess.ProcessHandle = ProcessHandle;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.OpenThreadProcess.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphCaptureStackBackTraceThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID *BackTrace,\n    _Out_ PULONG CapturedFrames,\n    _Out_opt_ PULONG BackTraceHash,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n    LARGE_INTEGER timeout;\n\n    msg = KphCreateUserMessage(KphMsgCaptureStackBackTraceThread);\n    msg->User.CaptureStackBackTraceThread.ThreadHandle = ThreadHandle;\n    msg->User.CaptureStackBackTraceThread.FramesToSkip = FramesToSkip;\n    msg->User.CaptureStackBackTraceThread.FramesToCapture = FramesToCapture;\n    msg->User.CaptureStackBackTraceThread.BackTrace = BackTrace;\n    msg->User.CaptureStackBackTraceThread.CapturedFrames = CapturedFrames;\n    msg->User.CaptureStackBackTraceThread.BackTraceHash = BackTraceHash;\n    msg->User.CaptureStackBackTraceThread.Timeout = PhTimeoutFromMilliseconds(&timeout, 300);\n    msg->User.CaptureStackBackTraceThread.Flags = Flags;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.CaptureStackBackTraceThread.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphEnumerateProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _In_opt_ ULONG BufferLength,\n    _Inout_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgEnumerateProcessHandles);\n    msg->User.EnumerateProcessHandles.ProcessHandle = ProcessHandle;\n    msg->User.EnumerateProcessHandles.Buffer = Buffer;\n    msg->User.EnumerateProcessHandles.BufferLength = BufferLength;\n    msg->User.EnumerateProcessHandles.ReturnLength = ReturnLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.EnumerateProcessHandles.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KsiEnumerateProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 2048;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = KphEnumerateProcessHandles(\n            ProcessHandle,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *Handles = buffer;\n\n    return status;\n}\n\nNTSTATUS KphQueryInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQueryInformationObject);\n    msg->User.QueryInformationObject.ProcessHandle = ProcessHandle;\n    msg->User.QueryInformationObject.Handle = Handle;\n    msg->User.QueryInformationObject.ObjectInformationClass = ObjectInformationClass;\n    msg->User.QueryInformationObject.ObjectInformation = ObjectInformation;\n    msg->User.QueryInformationObject.ObjectInformationLength = ObjectInformationLength;\n    msg->User.QueryInformationObject.ReturnLength = ReturnLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.QueryInformationObject.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphQueryObjectThreadName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING* ThreadName\n    )\n{\n    NTSTATUS status;\n    ULONG bufferSize;\n    ULONG returnLength;\n    PTHREAD_NAME_INFORMATION buffer;\n\n    returnLength = 0;\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    status = KphQueryInformationObject(\n        ProcessHandle,\n        Handle,\n        KphObjectThreadNameInformation,\n        buffer,\n        bufferSize,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL && returnLength > 0)\n    {\n        PhFree(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocate(returnLength);\n\n        status = KphQueryInformationObject(\n            ProcessHandle,\n            Handle,\n            KphObjectThreadNameInformation,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *ThreadName = PhCreateStringFromUnicodeString(&buffer->ThreadName);\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\nNTSTATUS KphQueryObjectSectionMappingsInfo(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _Out_ PKPH_SECTION_MAPPINGS_INFORMATION* Info\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = MAX_PATH;\n\n    *Info = NULL;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = KphQueryInformationObject(ProcessHandle,\n                                           Handle,\n                                           KphObjectSectionMappingsInformation,\n                                           buffer,\n                                           bufferSize,\n                                           &bufferSize);\n        if (status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *Info = buffer;\n\n    return status;\n}\n\nNTSTATUS KphSetInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgSetInformationObject);\n    msg->User.SetInformationObject.ProcessHandle = ProcessHandle;\n    msg->User.SetInformationObject.Handle = Handle;\n    msg->User.SetInformationObject.ObjectInformationClass = ObjectInformationClass;\n    msg->User.SetInformationObject.ObjectInformation = ObjectInformation;\n    msg->User.SetInformationObject.ObjectInformationLength = ObjectInformationLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.SetInformationObject.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphOpenDriver(\n    _Out_ PHANDLE DriverHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgOpenDriver);\n    msg->User.OpenDriver.DriverHandle = DriverHandle;\n    msg->User.OpenDriver.DesiredAccess = DesiredAccess;\n    msg->User.OpenDriver.ObjectAttributes = (POBJECT_ATTRIBUTES)ObjectAttributes;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.OpenDriver.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphQueryInformationDriver(\n    _In_ HANDLE DriverHandle,\n    _In_ KPH_DRIVER_INFORMATION_CLASS DriverInformationClass,\n    _Out_writes_bytes_opt_(DriverInformationLength) PVOID DriverInformation,\n    _In_ ULONG DriverInformationLength,\n    _Inout_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQueryInformationDriver);\n    msg->User.QueryInformationDriver.DriverHandle = DriverHandle;\n    msg->User.QueryInformationDriver.DriverInformationClass = DriverInformationClass;\n    msg->User.QueryInformationDriver.DriverInformation = DriverInformation;\n    msg->User.QueryInformationDriver.DriverInformationLength = DriverInformationLength;\n    msg->User.QueryInformationDriver.ReturnLength = ReturnLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.QueryInformationDriver.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _Out_writes_bytes_opt_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Inout_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQueryInformationProcess);\n    msg->User.QueryInformationProcess.ProcessHandle = ProcessHandle;\n    msg->User.QueryInformationProcess.ProcessInformationClass = ProcessInformationClass;\n    msg->User.QueryInformationProcess.ProcessInformation = ProcessInformation;\n    msg->User.QueryInformationProcess.ProcessInformationLength = ProcessInformationLength;\n    msg->User.QueryInformationProcess.ReturnLength = ReturnLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.QueryInformationProcess.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nKPH_PROCESS_STATE KphGetProcessState(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    KPH_PROCESS_STATE state;\n\n    if (!KphCommsIsConnected())\n        return 0;\n\n    if (!NT_SUCCESS(KphQueryInformationProcess(\n        ProcessHandle,\n        KphProcessStateInformation,\n        &state,\n        sizeof(state),\n        NULL\n        )))\n        return 0;\n\n    return state;\n}\n\nKPH_PROCESS_STATE KphGetCurrentProcessState(\n    VOID\n    )\n{\n    return KphGetProcessState(NtCurrentProcess());\n}\n\nKPH_LEVEL KphProcessLevel(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    KPH_PROCESS_STATE state;\n\n    //\n    // This corresponds to the API access the client is currently given.\n    // See comms_handlers.c\n    //\n    // Note that process state can change in runtime, so re-checking is\n    // necessary.\n    //\n\n    state = KphGetProcessState(ProcessHandle);\n\n    if ((state & KPH_PROCESS_STATE_MAXIMUM) == KPH_PROCESS_STATE_MAXIMUM)\n        return KphLevelMax;\n\n    if ((state & KPH_PROCESS_STATE_HIGH) == KPH_PROCESS_STATE_HIGH)\n        return KphLevelHigh;\n\n    if ((state & KPH_PROCESS_STATE_MEDIUM) == KPH_PROCESS_STATE_MEDIUM)\n        return KphLevelMed;\n\n    if ((state & KPH_PROCESS_STATE_LOW) == KPH_PROCESS_STATE_LOW)\n        return KphLevelLow;\n\n    if ((state & KPH_PROCESS_STATE_MINIMUM) == KPH_PROCESS_STATE_MINIMUM)\n        return KphLevelMin;\n\n    return KphLevelNone;\n}\n\nKPH_LEVEL KphLevelEx(\n    _In_ BOOLEAN Cached\n    )\n{\n    static KPH_LEVEL level = KphLevelNone;\n\n    if (!Cached)\n        level = KphProcessLevel(NtCurrentProcess());\n\n    return level;\n}\n\nKPH_LEVEL KsiLevel(\n    VOID\n    )\n{\n    return KphLevelEx(TRUE);\n}\n\nNTSTATUS KphSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgSetInformationProcess);\n    msg->User.SetInformationProcess.ProcessHandle = ProcessHandle;\n    msg->User.SetInformationProcess.ProcessInformationClass = ProcessInformationClass;\n    msg->User.SetInformationProcess.ProcessInformation = ProcessInformation;\n    msg->User.SetInformationProcess.ProcessInformationLength = ProcessInformationLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.SetInformationProcess.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgSetInformationThread);\n    msg->User.SetInformationThread.ThreadHandle = ThreadHandle;\n    msg->User.SetInformationThread.ThreadInformationClass = ThreadInformationClass;\n    msg->User.SetInformationThread.ThreadInformation = ThreadInformation;\n    msg->User.SetInformationThread.ThreadInformationLength = ThreadInformationLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.SetInformationThread.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphSystemControl(\n    _In_ KPH_SYSTEM_CONTROL_CLASS SystemControlClass,\n    _In_reads_bytes_(SystemControlInfoLength) PVOID SystemControlInfo,\n    _In_ ULONG SystemControlInfoLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgSystemControl);\n    msg->User.SystemControl.SystemControlClass = SystemControlClass;\n    msg->User.SystemControl.SystemControlInfo = SystemControlInfo;\n    msg->User.SystemControl.SystemControlInfoLength = SystemControlInfoLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.SystemControl.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphAlpcQueryInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE PortHandle,\n    _In_ KPH_ALPC_INFORMATION_CLASS AlpcInformationClass,\n    _Out_writes_bytes_opt_(AlpcInformationLength) PVOID AlpcInformation,\n    _In_ ULONG AlpcInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgAlpcQueryInformation);\n    msg->User.AlpcQueryInformation.ProcessHandle = ProcessHandle;\n    msg->User.AlpcQueryInformation.PortHandle = PortHandle;\n    msg->User.AlpcQueryInformation.AlpcInformationClass = AlpcInformationClass;\n    msg->User.AlpcQueryInformation.AlpcInformation = AlpcInformation;\n    msg->User.AlpcQueryInformation.AlpcInformationLength = AlpcInformationLength;\n    msg->User.AlpcQueryInformation.ReturnLength = ReturnLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.AlpcQueryInformation.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphAlpcQueryCommunicationsNamesInfo(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE PortHandle,\n    _Out_ PKPH_ALPC_COMMUNICATION_NAMES_INFORMATION* Names\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = MAX_PATH;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = KphAlpcQueryInformation(ProcessHandle,\n                                         PortHandle,\n                                         KphAlpcCommunicationNamesInformation,\n                                         buffer,\n                                         bufferSize,\n                                         &bufferSize);\n        if (status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *Names = buffer;\n\n    return status;\n}\n\nNTSTATUS KphQueryInformationFile(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_writes_bytes_(FileInformationLength) PVOID FileInformation,\n    _In_ ULONG FileInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQueryInformationFile);\n    msg->User.QueryInformationFile.ProcessHandle = ProcessHandle;\n    msg->User.QueryInformationFile.FileHandle = FileHandle;\n    msg->User.QueryInformationFile.FileInformationClass = FileInformationClass;\n    msg->User.QueryInformationFile.FileInformation = FileInformation;\n    msg->User.QueryInformationFile.FileInformationLength = FileInformationLength;\n    msg->User.QueryInformationFile.IoStatusBlock = IoStatusBlock;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.QueryInformationFile.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphQueryVolumeInformationFile(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FS_INFORMATION_CLASS FsInformationClass,\n    _Out_writes_bytes_(FsInformationLength) PVOID FsInformation,\n    _In_ ULONG FsInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQueryVolumeInformationFile);\n    msg->User.QueryVolumeInformationFile.ProcessHandle = ProcessHandle;\n    msg->User.QueryVolumeInformationFile.FileHandle = FileHandle;\n    msg->User.QueryVolumeInformationFile.FsInformationClass = FsInformationClass;\n    msg->User.QueryVolumeInformationFile.FsInformation = FsInformation;\n    msg->User.QueryVolumeInformationFile.FsInformationLength = FsInformationLength;\n    msg->User.QueryVolumeInformationFile.IoStatusBlock = IoStatusBlock;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.QueryVolumeInformationFile.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphDuplicateObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE SourceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TargetHandle\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgDuplicateObject);\n    msg->User.DuplicateObject.ProcessHandle = ProcessHandle;\n    msg->User.DuplicateObject.SourceHandle = SourceHandle;\n    msg->User.DuplicateObject.DesiredAccess = DesiredAccess;\n    msg->User.DuplicateObject.TargetHandle = TargetHandle;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.DuplicateObject.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphQueryPerformanceCounter(\n    _Out_ PLARGE_INTEGER PerformanceCounter,\n    _Out_opt_ PLARGE_INTEGER PerformanceFrequency\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQueryPerformanceCounter);\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        *PerformanceCounter = msg->User.QueryPerformanceCounter.PerformanceCounter;\n        if (PerformanceFrequency)\n        {\n            *PerformanceFrequency = msg->User.QueryPerformanceCounter.PerformanceFrequency;\n        }\n    }\n    else\n    {\n        PerformanceCounter->QuadPart = 0;\n        if (PerformanceFrequency)\n        {\n            PerformanceFrequency->QuadPart = 0;\n        }\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphCreateFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,\n    _In_ ULONG EaLength,\n    _In_ ULONG Options\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgCreateFile);\n    msg->User.CreateFile.FileHandle = FileHandle;\n    msg->User.CreateFile.DesiredAccess = DesiredAccess;\n    msg->User.CreateFile.ObjectAttributes = (POBJECT_ATTRIBUTES)ObjectAttributes;\n    msg->User.CreateFile.IoStatusBlock = IoStatusBlock;\n    msg->User.CreateFile.AllocationSize = AllocationSize;\n    msg->User.CreateFile.FileAttributes = FileAttributes;\n    msg->User.CreateFile.ShareAccess = ShareAccess;\n    msg->User.CreateFile.CreateDisposition = CreateDisposition;\n    msg->User.CreateFile.CreateOptions = CreateOptions;\n    msg->User.CreateFile.EaBuffer = EaBuffer;\n    msg->User.CreateFile.EaLength = EaLength;\n    msg->User.CreateFile.Options = Options;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.CreateFile.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _Out_writes_bytes_opt_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQueryInformationThread);\n    msg->User.QueryInformationThread.ThreadHandle = ThreadHandle;\n    msg->User.QueryInformationThread.ThreadInformationClass = ThreadInformationClass;\n    msg->User.QueryInformationThread.ThreadInformation = ThreadInformation;\n    msg->User.QueryInformationThread.ThreadInformationLength = ThreadInformationLength;\n    msg->User.QueryInformationThread.ReturnLength = ReturnLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.QueryInformationThread.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphQuerySection(\n    _In_ HANDLE SectionHandle,\n    _In_ KPH_SECTION_INFORMATION_CLASS SectionInformationClass,\n    _Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation,\n    _In_ ULONG SectionInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQuerySection);\n    msg->User.QuerySection.SectionHandle = SectionHandle;\n    msg->User.QuerySection.SectionInformationClass = SectionInformationClass;\n    msg->User.QuerySection.SectionInformation = SectionInformation;\n    msg->User.QuerySection.SectionInformationLength = SectionInformationLength;\n    msg->User.QuerySection.ReturnLength = ReturnLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.QuerySection.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphQuerySectionMappingsInfo(\n    _In_ HANDLE SectionHandle,\n    _Out_ PKPH_SECTION_MAPPINGS_INFORMATION* Info\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = MAX_PATH;\n\n    *Info = NULL;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = KphQuerySection(SectionHandle,\n                                 KphSectionMappingsInformation,\n                                 buffer,\n                                 bufferSize,\n                                 &bufferSize);\n        if (status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *Info = buffer;\n\n    return status;\n}\n\nNTSTATUS KphCompareObjects(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgCompareObjects);\n    msg->User.CompareObjects.ProcessHandle = ProcessHandle;\n    msg->User.CompareObjects.FirstObjectHandle = FirstObjectHandle;\n    msg->User.CompareObjects.SecondObjectHandle = SecondObjectHandle;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.CompareObjects.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphGetInformerClientSettings(\n    _Out_ PKPH_INFORMER_CLIENT_SETTINGS Settings\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgGetInformerClientSettings);\n    msg->User.GetInformerClientSettings.Settings = Settings;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.GetInformerClientSettings.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphSetInformerClientSettings(\n    _Out_ PKPH_INFORMER_CLIENT_SETTINGS Settings\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgSetInformerClientSettings);\n    msg->User.SetInformerClientSettings.Settings = Settings;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.SetInformerClientSettings.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphAcquireDriverUnloadProtection(\n    _Out_opt_ PLONG PreviousCount,\n    _Out_opt_ PLONG ClientPreviousCount\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    if (PreviousCount)\n        *PreviousCount = 0;\n\n    if (ClientPreviousCount)\n        *ClientPreviousCount = 0;\n\n    msg = KphCreateUserMessage(KphMsgAcquireDriverUnloadProtection);\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.AcquireDriverUnloadProtection.Status;\n\n        if (NT_SUCCESS(status))\n        {\n            if (PreviousCount)\n                *PreviousCount = msg->User.AcquireDriverUnloadProtection.PreviousCount;\n\n            if (ClientPreviousCount)\n                *ClientPreviousCount = msg->User.AcquireDriverUnloadProtection.ClientPreviousCount;\n        }\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphReleaseDriverUnloadProtection(\n    _Out_opt_ PLONG PreviousCount,\n    _Out_opt_ PLONG ClientPreviousCount\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgReleaseDriverUnloadProtection);\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.ReleaseDriverUnloadProtection.Status;\n\n        if (NT_SUCCESS(status))\n        {\n            if (PreviousCount)\n                *PreviousCount = msg->User.ReleaseDriverUnloadProtection.PreviousCount;\n\n            if (ClientPreviousCount)\n                *ClientPreviousCount = msg->User.ReleaseDriverUnloadProtection.ClientPreviousCount;\n        }\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphGetConnectedClientCount(\n    _Out_ PULONG Count\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgGetConnectedClientCount);\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        *Count = msg->User.GetConnectedClientCount.Count;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphActivateDynData(\n    _In_ PBYTE DynData,\n    _In_ ULONG DynDataLength,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgActivateDynData);\n    msg->User.ActivateDynData.DynData = DynData;\n    msg->User.ActivateDynData.DynDataLength = DynDataLength;\n    msg->User.ActivateDynData.Signature = Signature;\n    msg->User.ActivateDynData.SignatureLength = SignatureLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.ActivateDynData.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphIsDynDataActive(\n    _Out_ PBOOLEAN IsActive\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    *IsActive = FALSE;\n\n    if (!KphCommsIsConnected())\n        return STATUS_PORT_DISCONNECTED;\n\n    msg = KphCreateUserMessage(KphMsgIsDynDataActive);\n    msg->User.IsDynDataActive.IsActive = IsActive;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.IsDynDataActive.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphRequestSessionAccessToken(\n    _Out_ PKPH_SESSION_ACCESS_TOKEN AccessToken,\n    _In_ PLARGE_INTEGER Expiry,\n    _In_ ULONG Privileges,\n    _In_ LONG Uses\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgRequestSessionAccessToken);\n    msg->User.RequestSessionAccessToken.Expiry = *Expiry;\n    msg->User.RequestSessionAccessToken.Privileges = Privileges;\n    msg->User.RequestSessionAccessToken.Uses = Uses;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        RtlCopyMemory(AccessToken,\n                      &msg->User.RequestSessionAccessToken.AccessToken,\n                      sizeof(KPH_SESSION_ACCESS_TOKEN));\n\n        status = msg->User.RequestSessionAccessToken.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphAssignProcessSessionToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgAssignProcessSessionToken);\n    msg->User.AssignProcessSessionToken.ProcessHandle = ProcessHandle;\n    msg->User.AssignProcessSessionToken.Signature = Signature;\n    msg->User.AssignProcessSessionToken.SignatureLength = SignatureLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.AssignProcessSessionToken.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphAssignThreadSessionToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ PBYTE Signature,\n    _In_ ULONG SignatureLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgAssignThreadSessionToken);\n    msg->User.AssignThreadSessionToken.ThreadHandle = ThreadHandle;\n    msg->User.AssignThreadSessionToken.Signature = Signature;\n    msg->User.AssignThreadSessionToken.SignatureLength = SignatureLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.AssignThreadSessionToken.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphGetInformerProcessSettings(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKPH_INFORMER_SETTINGS Settings\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgGetInformerProcessSettings);\n    msg->User.GetInformerProcessSettings.ProcessHandle = ProcessHandle;\n    msg->User.GetInformerProcessSettings.Settings = Settings;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.GetInformerProcessSettings.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphSetInformerProcessSettings(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PKPH_INFORMER_SETTINGS Settings\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgSetInformerProcessSettings);\n    msg->User.SetInformerProcessSettings.ProcessHandle = ProcessHandle;\n    msg->User.SetInformerProcessSettings.Settings = Settings;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.SetInformerProcessSettings.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphStripProtectedProcessMasks(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK ProcessAllowedMask,\n    _In_ ACCESS_MASK ThreadAllowedMask\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgStripProtectedProcessMasks);\n    msg->User.StripProtectedProcessMasks.ProcessHandle = ProcessHandle;\n    msg->User.StripProtectedProcessMasks.ProcessAllowedMask = ProcessAllowedMask;\n    msg->User.StripProtectedProcessMasks.ThreadAllowedMask = ThreadAllowedMask;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.StripProtectedProcessMasks.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphQueryVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ KPH_MEMORY_INFORMATION_CLASS MemoryInformationClass,\n    _Out_writes_bytes_opt_(MemoryInformationLength) PVOID MemoryInformation,\n    _In_ ULONG MemoryInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQueryVirtualMemory);\n    msg->User.QueryVirtualMemory.ProcessHandle = ProcessHandle;\n    msg->User.QueryVirtualMemory.BaseAddress = BaseAddress;\n    msg->User.QueryVirtualMemory.MemoryInformationClass = MemoryInformationClass;\n    msg->User.QueryVirtualMemory.MemoryInformation = MemoryInformation;\n    msg->User.QueryVirtualMemory.MemoryInformationLength = MemoryInformationLength;\n    msg->User.QueryVirtualMemory.ReturnLength = ReturnLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.QueryVirtualMemory.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KsiQueryHashInformationFile(\n    _In_ HANDLE FileHandle,\n    _Inout_ PKPH_HASH_INFORMATION HashInformation,\n    _In_ ULONG HashInformationLength\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgQueryHashInformationFile);\n    msg->User.QueryHashInformationFile.FileHandle = FileHandle;\n    msg->User.QueryHashInformationFile.HashingInformation = HashInformation;\n    msg->User.QueryHashInformationFile.HashingInformationLength = HashInformationLength;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.QueryHashInformationFile.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphOpenDevice(\n    _Out_ PHANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgOpenDevice);\n    msg->User.OpenDevice.DeviceHandle = DeviceHandle;\n    msg->User.OpenDevice.DesiredAccess = DesiredAccess;\n    msg->User.OpenDevice.ObjectAttributes = ObjectAttributes;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.OpenDevice.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphOpenDeviceDriver(\n    _In_ HANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE DriverHandle\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgOpenDeviceDriver);\n    msg->User.OpenDeviceDriver.DeviceHandle = DeviceHandle;\n    msg->User.OpenDeviceDriver.DesiredAccess = DesiredAccess;\n    msg->User.OpenDeviceDriver.DriverHandle = DriverHandle;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.OpenDeviceDriver.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphOpenDeviceBaseDevice(\n    _In_ HANDLE DeviceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE BaseDeviceHandle\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgOpenDeviceBaseDevice);\n    msg->User.OpenDeviceBaseDevice.DeviceHandle = DeviceHandle;\n    msg->User.OpenDeviceBaseDevice.DesiredAccess = DesiredAccess;\n    msg->User.OpenDeviceBaseDevice.BaseDeviceHandle = BaseDeviceHandle;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.OpenDeviceBaseDevice.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphGetInformerStats(\n    _In_opt_ HANDLE ProcessHandle,\n    _Out_ PKPH_INFORMER_STATS Stats\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgGetInformerStats);\n    msg->User.GetInformerStats.ProcessHandle = ProcessHandle;\n    msg->User.GetInformerStats.Stats = Stats;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.GetInformerStats.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n\nNTSTATUS KphGetInformerClientStats(\n    _Out_ PKPH_INFORMER_CLIENT_STATS Stats\n    )\n{\n    NTSTATUS status;\n    PKPH_MESSAGE msg;\n\n    msg = KphCreateUserMessage(KphMsgGetInformerClientStats);\n    msg->User.GetInformerClientStats.Stats = Stats;\n    status = KphCommsSendMessage(msg);\n\n    if (NT_SUCCESS(status))\n    {\n        status = msg->User.GetInformerClientStats.Status;\n    }\n\n    PhDereferenceObject(msg);\n    return status;\n}\n"
  },
  {
    "path": "phlib/kphcomms.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2022-2025\n *     dmex    2022-2025\n *\n */\n\n#include <ph.h>\n#include <kphcomms.h>\n#include <kphuser.h>\n#include <kphringbuff.h>\n#include <mapldr.h>\n#include <apiimport.h>\n\ntypedef struct _KPH_UMESSAGE\n{\n    FILTER_MESSAGE_HEADER MessageHeader;\n    KPH_MESSAGE Message;\n    OVERLAPPED Overlapped;\n} KPH_UMESSAGE, *PKPH_UMESSAGE;\n\ntypedef struct _KPH_UREPLY\n{\n    FILTER_REPLY_HEADER ReplyHeader;\n    KPH_MESSAGE Message;\n} KPH_UREPLY, *PKPH_UREPLY;\n\nPKPH_COMMS_CALLBACK KphpCommsRegisteredCallback = NULL;\nHANDLE KphpCommsFltPortHandle = NULL;\nBOOLEAN KphpCommsPortDisconnected = TRUE;\nPTP_POOL KphpCommsThreadPool = NULL;\nTP_CALLBACK_ENVIRON KphpCommsThreadPoolEnv;\nPTP_IO KphpCommsThreadPoolIo = NULL;\nPKPH_UMESSAGE KphpCommsMessages = NULL;\nULONG KphpCommsMessageCount = 0;\nPH_RUNDOWN_PROTECT KphpCommsRundown;\nPH_FREE_LIST KphpCommsReplyFreeList;\nHANDLE KphpCommsRingBufferThread = NULL;\nKPH_RING_BUFFER_CONNECT KphpCommsRingBuffer = { 0 };\nULONG KphpCommsTlsSlot = TLS_OUT_OF_INDEXES;\n\n#define KPH_COMMS_MIN_THREADS           2\n#define KPH_COMMS_MESSAGE_SCALE         2\n#define KPH_COMMS_THREAD_SCALE          2\n#define KPH_COMMS_MAX_MESSAGES          1024\n#define KPH_COMMS_THREAD_PROPERTIES_SET UlongToPtr(1)\n\nVOID KphpCommsSetThreadProperties(\n    _In_z_ PCWSTR ThreadName,\n    _In_ KPRIORITY Priority\n    )\n{\n    if (PhTlsGetValue(KphpCommsTlsSlot) != KPH_COMMS_THREAD_PROPERTIES_SET)\n    {\n        PhSetThreadName(NtCurrentThread(), ThreadName);\n        if (Priority >= THREAD_PRIORITY_TIME_CRITICAL)\n            Priority = LOW_REALTIME_PRIORITY;\n        PhSetThreadBasePriority(NtCurrentThread(), Priority);\n        PhTlsSetValue(KphpCommsTlsSlot, KPH_COMMS_THREAD_PROPERTIES_SET);\n    }\n}\n\n/**\n * \\brief Unhandled communications callback.\n *\n * \\details Synchronous messages expecting a reply must always be handled, this\n * no-operation default callback will handle them as necessary. Used when no\n * callback is provided when connecting. Or when the callback does not handle\n * the message.\n *\n * \\param[in] ReplyToken - Token used to reply, when possible.\n * \\param[in] Message - Message from KPH to handle.\n */\nVOID KphpCommsCallbackUnhandled(\n    _In_ ULONG_PTR ReplyToken,\n    _In_ PCKPH_MESSAGE Message\n    )\n{\n    PKPH_MESSAGE msg;\n\n    if (!ReplyToken)\n        return;\n\n    msg = KphCreateMessage(KPH_MESSAGE_MIN_SIZE);\n    KphMsgInit(msg, KphMsgUnhandled);\n\n    KphCommsReplyMessage(ReplyToken, msg);\n\n    PhDereferenceObject(msg);\n}\n\n/**\n * \\brief I/O thread pool callback for filter port.\n *\n * \\param[in,out] Instance Unused\n * \\param[in,out] Context Unused\n * \\param[in,out] ApcContext Pointer to overlapped I/O that was completed.\n * \\param[in] IoSB Result of the asynchronous I/O operation.\n * \\param[in,out] Io Unused\n */\n_Function_class_(TP_IO_CALLBACK)\nVOID WINAPI KphpCommsIoCallback(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context,\n    _In_ PVOID ApcContext,\n    _In_ PIO_STATUS_BLOCK IoSB,\n    _In_ PTP_IO Io\n    )\n{\n    NTSTATUS status;\n    PKPH_UMESSAGE msg;\n    SIZE_T length;\n\n    if (!PhAcquireRundownProtection(&KphpCommsRundown))\n        return;\n\n    KphpCommsSetThreadProperties(L\"Message Processor\", THREAD_PRIORITY_TIME_CRITICAL);\n\n    msg = CONTAINING_RECORD(ApcContext, KPH_UMESSAGE, Overlapped);\n\n    if (IoSB->Status != STATUS_SUCCESS)\n    {\n        if (IoSB->Status == STATUS_PORT_DISCONNECTED)\n        {\n            KphpCommsPortDisconnected = TRUE;\n            PhReleaseRundownProtection(&KphpCommsRundown);\n            return;\n        }\n\n        goto QueueIoOperation;\n    }\n\n    assert(IoSB->Information >= UFIELD_OFFSET(KPH_UMESSAGE, Message));\n\n    if (IoSB->Information < UFIELD_OFFSET(KPH_UMESSAGE, Message))\n        goto QueueIoOperation;\n\n    length = IoSB->Information - UFIELD_OFFSET(KPH_UMESSAGE, Message);\n\n    assert(length >= KPH_MESSAGE_MIN_SIZE);\n\n    if (length < KPH_MESSAGE_MIN_SIZE)\n        goto QueueIoOperation;\n\n    if (!NT_SUCCESS(status = KphMsgValidate(&msg->Message)))\n    {\n        assert(NT_SUCCESS(status));\n        goto QueueIoOperation;\n    }\n\n    if (msg->MessageHeader.ReplyLength)\n    {\n        BOOLEAN handled;\n        ULONG_PTR replyToken;\n\n        replyToken = (ULONG_PTR)&msg->MessageHeader;\n\n        assert(length == msg->Message.Header.Size);\n\n        if (KphpCommsRegisteredCallback)\n            handled = KphpCommsRegisteredCallback(replyToken, &msg->Message);\n        else\n            handled = FALSE;\n\n        if (!handled)\n            KphpCommsCallbackUnhandled(replyToken, &msg->Message);\n    }\n    else if (KphpCommsRegisteredCallback)\n    {\n        for (ULONG offset = 0; offset < length; NOTHING)\n        {\n            PKPH_MESSAGE message;\n\n            assert(offset < sizeof(KPH_MESSAGE));\n\n            message = PTR_ADD_OFFSET(&msg->Message, offset);\n\n            KphpCommsRegisteredCallback(0, message);\n\n            offset += message->Header.Size;\n        }\n    }\n\nQueueIoOperation:\n\n    RtlZeroMemory(&msg->Overlapped, sizeof(OVERLAPPED));\n\n    assert(Io == KphpCommsThreadPoolIo);\n\n    TpStartAsyncIoOperation(KphpCommsThreadPoolIo);\n\n    status = PhFilterGetMessage(\n        KphpCommsFltPortHandle,\n        &msg->MessageHeader,\n        FIELD_OFFSET(KPH_UMESSAGE, Overlapped),\n        &msg->Overlapped\n        );\n\n    if (status != STATUS_PENDING)\n    {\n        assert(status == STATUS_PORT_DISCONNECTED);\n\n        if (status == STATUS_PORT_DISCONNECTED)\n            KphpCommsPortDisconnected = TRUE;\n\n        TpCancelAsyncIoOperation(KphpCommsThreadPoolIo);\n    }\n\n    PhReleaseRundownProtection(&KphpCommsRundown);\n}\n\n_Function_class_(KPH_RING_CALLBACK)\nBOOLEAN NTAPI KphpRingBufferCallback(\n    _In_opt_ PVOID Context,\n    _In_bytecount_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    )\n{\n    if (!PhAcquireRundownProtection(&KphpCommsRundown))\n        return TRUE;\n\n    if (KphpCommsRegisteredCallback && NT_VERIFY(Length >= KPH_MESSAGE_MIN_SIZE))\n    {\n        if (NT_VERIFY(NT_SUCCESS(KphMsgValidate(Buffer))))\n        {\n            KphpCommsRegisteredCallback(0, Buffer);\n        }\n    }\n\n    PhReleaseRundownProtection(&KphpCommsRundown);\n\n    return FALSE;\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI KphpRingBufferProcessor(\n    _In_ PVOID Context\n    )\n{\n    KphpCommsSetThreadProperties(L\"Message Ring Processor\", THREAD_PRIORITY_HIGHEST);\n\n    while (PhAcquireRundownProtection(&KphpCommsRundown))\n    {\n        PhReleaseRundownProtection(&KphpCommsRundown);\n\n        if (!KphProcessRingBuffer(&KphpCommsRingBuffer.Ring, KphpRingBufferCallback, NULL))\n        {\n            if (KphpCommsRingBuffer.EventHandle)\n                PhWaitForSingleObject(KphpCommsRingBuffer.EventHandle, INFINITE);\n            else\n                PhDelayExecution(300);\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * \\brief Starts the communications infrastructure.\n *\n * \\param[in] PortName Communication port name.\n * \\param[in] Callback Communication callback for receiving (and replying to)\n * messages from the driver.\n * \\param[in] RingBufferLength Size of the ring buffer to use for messages.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphCommsStart(\n    _In_ PCPH_STRINGREF PortName,\n    _In_opt_ PKPH_COMMS_CALLBACK Callback,\n    _In_ ULONG RingBufferLength\n    )\n{\n    NTSTATUS status;\n    ULONG numberOfThreads;\n    PVOID connectionContext;\n    PVOID connectionContextPointer;\n    USHORT connectionContextSize;\n\n    if (KphpCommsFltPortHandle)\n    {\n        status = STATUS_ALREADY_INITIALIZED;\n        goto CleanupExit;\n    }\n\n    if (RingBufferLength)\n    {\n        NtCreateEvent(&KphpCommsRingBuffer.EventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);\n        KphpCommsRingBuffer.Length = RingBufferLength;\n        connectionContext = &KphpCommsRingBuffer;\n        connectionContextPointer = &connectionContext;\n        connectionContextSize = sizeof(PVOID);\n    }\n    else\n    {\n        connectionContextPointer = NULL;\n        connectionContextSize = 0;\n    }\n\n    if (!NT_SUCCESS(status = PhFilterConnectCommunicationPort(\n        PortName,\n        0,\n        connectionContextPointer,\n        connectionContextSize,\n        NULL,\n        &KphpCommsFltPortHandle\n        )))\n        goto CleanupExit;\n\n    KphpCommsPortDisconnected = FALSE;\n    KphpCommsRegisteredCallback = Callback;\n\n    PhInitializeRundownProtection(&KphpCommsRundown);\n    PhInitializeFreeList(&KphpCommsReplyFreeList, sizeof(KPH_UREPLY), 16);\n\n    KphpCommsTlsSlot = PhTlsAlloc();\n    if (KphpCommsTlsSlot == TLS_OUT_OF_INDEXES)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto CleanupExit;\n    }\n\n    if (RingBufferLength)\n    {\n        if (!NT_SUCCESS(status = PhCreateThreadEx(&KphpCommsRingBufferThread, KphpRingBufferProcessor, NULL)))\n            goto CleanupExit;\n    }\n\n    if (PhSystemProcessorInformation.NumberOfProcessors >= KPH_COMMS_MIN_THREADS)\n        numberOfThreads = PhSystemProcessorInformation.NumberOfProcessors * KPH_COMMS_THREAD_SCALE;\n    else\n        numberOfThreads = KPH_COMMS_MIN_THREADS;\n\n    KphpCommsMessageCount = numberOfThreads * KPH_COMMS_MESSAGE_SCALE;\n    if (KphpCommsMessageCount > KPH_COMMS_MAX_MESSAGES)\n        KphpCommsMessageCount = KPH_COMMS_MAX_MESSAGES;\n\n    if (!NT_SUCCESS(status = TpAllocPool(&KphpCommsThreadPool, NULL)))\n        goto CleanupExit;\n\n    TpSetPoolMinThreads(KphpCommsThreadPool, KPH_COMMS_MIN_THREADS);\n    TpSetPoolMaxThreads(KphpCommsThreadPool, numberOfThreads);\n\n    if (TpSetPoolThreadBasePriority_Import())\n        TpSetPoolThreadBasePriority_Import()(KphpCommsThreadPool, THREAD_PRIORITY_HIGHEST);\n\n    TpInitializeCallbackEnviron(&KphpCommsThreadPoolEnv);\n    TpSetCallbackNoActivationContext(&KphpCommsThreadPoolEnv);\n    TpSetCallbackPriority(&KphpCommsThreadPoolEnv, TP_CALLBACK_PRIORITY_HIGH);\n    TpSetCallbackThreadpool(&KphpCommsThreadPoolEnv, KphpCommsThreadPool);\n    //TpSetCallbackLongFunction(&KphpCommsThreadPoolEnv);\n\n    PhSetFileCompletionNotificationMode(KphpCommsFltPortHandle, FILE_SKIP_SET_EVENT_ON_HANDLE);\n\n    if (!NT_SUCCESS(status = TpAllocIoCompletion(\n        &KphpCommsThreadPoolIo,\n        KphpCommsFltPortHandle,\n        KphpCommsIoCallback,\n        NULL,\n        &KphpCommsThreadPoolEnv\n        )))\n        goto CleanupExit;\n\n    KphpCommsMessages = PhAllocateZeroSafe(sizeof(KPH_UMESSAGE) * KphpCommsMessageCount);\n    if (!KphpCommsMessages)\n    {\n        status = STATUS_NO_MEMORY;\n        goto CleanupExit;\n    }\n\n    for (ULONG i = 0; i < KphpCommsMessageCount; i++)\n    {\n        RtlZeroMemory(&KphpCommsMessages[i].Overlapped, sizeof(OVERLAPPED));\n\n        TpStartAsyncIoOperation(KphpCommsThreadPoolIo);\n\n        status = PhFilterGetMessage(\n            KphpCommsFltPortHandle,\n            &KphpCommsMessages[i].MessageHeader,\n            FIELD_OFFSET(KPH_UMESSAGE, Overlapped),\n            &KphpCommsMessages[i].Overlapped\n            );\n        if (status == STATUS_PENDING)\n        {\n            status = STATUS_SUCCESS;\n        }\n        else\n        {\n            status = STATUS_FLT_INTERNAL_ERROR;\n            goto CleanupExit;\n        }\n    }\n\n    status = STATUS_SUCCESS;\n\nCleanupExit:\n\n    if (!NT_SUCCESS(status))\n        KphCommsStop();\n\n    return status;\n}\n\n/**\n * \\brief Stops the communications infrastructure.\n */\nVOID KphCommsStop(\n    VOID\n    )\n{\n    if (!KphpCommsFltPortHandle)\n        return;\n\n    PhWaitForRundownProtection(&KphpCommsRundown);\n\n    if (KphpCommsThreadPoolIo)\n    {\n        TpWaitForIoCompletion(KphpCommsThreadPoolIo, TRUE);\n        TpReleaseIoCompletion(KphpCommsThreadPoolIo);\n        KphpCommsThreadPoolIo = NULL;\n    }\n\n    TpDestroyCallbackEnviron(&KphpCommsThreadPoolEnv);\n\n    if (KphpCommsThreadPool)\n    {\n        TpReleasePool(KphpCommsThreadPool);\n        KphpCommsThreadPool = NULL;\n    }\n\n    if (KphpCommsRingBufferThread)\n    {\n        if (KphpCommsRingBuffer.EventHandle)\n            NtSetEvent(KphpCommsRingBuffer.EventHandle, NULL);\n\n        NtWaitForSingleObject(KphpCommsRingBufferThread, FALSE, NULL);\n        NtClose(KphpCommsRingBufferThread);\n        KphpCommsRingBufferThread = NULL;\n\n        if (KphpCommsRingBuffer.Ring.Producer)\n        {\n            NtUnmapViewOfSection(NtCurrentProcess(), KphpCommsRingBuffer.Ring.Producer);\n            KphpCommsRingBuffer.Ring.Producer = NULL;\n        }\n\n        if (KphpCommsRingBuffer.Ring.Consumer)\n        {\n            NtUnmapViewOfSection(NtCurrentProcess(), KphpCommsRingBuffer.Ring.Consumer);\n            KphpCommsRingBuffer.Ring.Consumer = NULL;\n        }\n\n        if (KphpCommsRingBuffer.EventHandle)\n        {\n            NtClose(KphpCommsRingBuffer.EventHandle);\n            KphpCommsRingBuffer.EventHandle = NULL;\n        }\n    }\n\n    KphpCommsRegisteredCallback = NULL;\n    KphpCommsPortDisconnected = TRUE;\n\n    NtClose(KphpCommsFltPortHandle);\n    KphpCommsFltPortHandle = NULL;\n\n    if (KphpCommsMessages)\n    {\n        KphpCommsMessageCount = 0;\n\n        PhFree(KphpCommsMessages);\n        KphpCommsMessages = NULL;\n    }\n\n    if (KphpCommsTlsSlot != TLS_OUT_OF_INDEXES)\n    {\n        PhTlsFree(KphpCommsTlsSlot);\n        KphpCommsTlsSlot = TLS_OUT_OF_INDEXES;\n    }\n\n    PhDeleteFreeList(&KphpCommsReplyFreeList);\n}\n\n/**\n * \\brief Checks if communications is connected to the driver.\n *\n * \\return TRUE if connected, FALSE otherwise.\n */\nBOOLEAN KphCommsIsConnected(\n    VOID\n    )\n{\n    return (KphpCommsFltPortHandle && !KphpCommsPortDisconnected);\n}\n\n/**\n * \\brief Replies to a message send to the communications callback.\n *\n * \\param[in] ReplyToken Reply token from the communications callback.\n * \\param[in] Message The message to reply with.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS KphCommsReplyMessage(\n    _In_ ULONG_PTR ReplyToken,\n    _In_ PKPH_MESSAGE Message\n    )\n{\n    NTSTATUS status;\n    PKPH_UREPLY reply;\n    PFILTER_MESSAGE_HEADER header;\n\n    reply = NULL;\n    header = (PFILTER_MESSAGE_HEADER)ReplyToken;\n\n    if (!KphpCommsFltPortHandle)\n    {\n        status = STATUS_FLT_NOT_INITIALIZED;\n        goto CleanupExit;\n    }\n\n    if (!header || !header->ReplyLength)\n    {\n        //\n        // Kernel is not expecting a reply.\n        //\n        status = STATUS_INVALID_PARAMETER_1;\n        goto CleanupExit;\n    }\n\n    if (!NT_SUCCESS(status = KphMsgValidate(Message)))\n        goto CleanupExit;\n\n    if (!(reply = PhAllocateFromFreeList(&KphpCommsReplyFreeList)))\n    {\n        status = STATUS_NO_MEMORY;\n        goto CleanupExit;\n    }\n\n    RtlZeroMemory(reply, sizeof(KPH_UREPLY));\n    RtlCopyMemory(&reply->ReplyHeader, header, sizeof(reply->ReplyHeader));\n    RtlCopyMemory(&reply->Message, Message, Message->Header.Size);\n\n    status = PhFilterReplyMessage(\n        KphpCommsFltPortHandle,\n        &reply->ReplyHeader,\n        sizeof(reply->ReplyHeader) + Message->Header.Size\n        );\n\n    if (status == STATUS_PORT_DISCONNECTED)\n        KphpCommsPortDisconnected = TRUE;\n\nCleanupExit:\n\n    if (reply)\n        PhFreeToFreeList(&KphpCommsReplyFreeList, reply);\n\n    return status;\n}\n\n/**\n * \\brief Sends a message to the driver (and may receive output if applicable).\n *\n * \\param[in,out] Message The message to send to driver, on success this message\n * contains the output from the driver.\n *\n * \\return Successful or errant status.\n */\n_Must_inspect_result_\nNTSTATUS KphCommsSendMessage(\n    _Inout_ PKPH_MESSAGE Message\n    )\n{\n    NTSTATUS status;\n    ULONG bytesReturned;\n\n    if (!KphpCommsFltPortHandle)\n        return STATUS_FLT_NOT_INITIALIZED;\n\n    if (!NT_SUCCESS(status = KphMsgValidate(Message)))\n        return status;\n\n    status = PhFilterSendMessage(\n        KphpCommsFltPortHandle,\n        Message,\n        Message->Header.Size,\n        NULL,\n        0,\n        &bytesReturned\n        );\n\n    if (status == STATUS_PORT_DISCONNECTED)\n        KphpCommsPortDisconnected = TRUE;\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/lsamsup.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2023\n *\n */\n\n#include <ph.h>\n#include <ntsam.h>\n#include <lsasup.h>\n#include <lsamsup.h>\n\n/**\n * Opens a handle to the SAM server.\n *\n * \\param SamHandle A variable which receives the handle.\n * \\param DesiredAccess The desired access to the handle.\n * \\param SystemName The name of the system to connect to.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenSamHandle(\n    _Out_ PSAM_HANDLE SamHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PUNICODE_STRING SystemName\n    )\n{\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        NULL,\n        OBJ_EXCLUSIVE,\n        NULL,\n        NULL\n        );\n\n    return SamConnect(\n        SystemName,\n        SamHandle,\n        DesiredAccess,\n        &objectAttributes\n        );\n}\n\n/**\n * Opens a handle to a SAM domain.\n *\n * \\param DomainHandle A variable which receives the handle.\n * \\param DesiredAccess The desired access to the handle.\n * \\param DomainSid The SID of the domain to open.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenSamDomainHandle(\n    _Out_ PSAM_HANDLE DomainHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PSID DomainSid\n    )\n{\n    NTSTATUS status;\n    SAM_HANDLE serverHandle;\n\n    status = PhGetSamServerHandle(&serverHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    return SamOpenDomain(\n        serverHandle,\n        DesiredAccess,\n        DomainSid,\n        DomainHandle\n        );\n}\n\n/**\n * Retrieves a handle to the local SAM server with SAM_SERVER_LOOKUP_DOMAIN access.\n *\n * \\param SamHandle A variable which receives the handle.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Do not close the handle; it is cached.\n */\nNTSTATUS PhGetSamServerHandle(\n    _Out_ PSAM_HANDLE SamHandle\n    )\n{\n    static SAM_HANDLE cachedSamServerHandle = NULL;\n    static NTSTATUS cachedStatus = STATUS_UNSUCCESSFUL;\n    SAM_HANDLE samServerHandle;\n\n    // Fast Path: No locking for the common case.\n    samServerHandle = *(volatile SAM_HANDLE*)&cachedSamServerHandle;\n    if (samServerHandle && samServerHandle != (SAM_HANDLE)-1)\n    {\n        *SamHandle = samServerHandle;\n        return STATUS_SUCCESS;\n    }\n\n    while (TRUE)\n    {\n        // Attempt to acquire the lock (swap NULL with -1)\n        samServerHandle = InterlockedCompareExchangePointer(\n            &cachedSamServerHandle,\n            (SAM_HANDLE)-1,\n            NULL\n            );\n\n        // Handle Contention\n        if (samServerHandle != NULL)\n        {\n            // If the handle is fully initialized by another thread, return it.\n            if (samServerHandle != (SAM_HANDLE)-1)\n            {\n                *SamHandle = samServerHandle;\n                return STATUS_SUCCESS;\n            }\n\n            // The lock is held (-1). The other thread is talking to LSASS.\n            // Try to yield execution to the lock-holder.\n\n            if (!PhSwitchToThread())\n            {\n                // If PhSwitchToThread returns FALSE, it means no yield happened \n                // (we are alone on this core), so we must force a sleep to stop burning CPU.\n                PhDelayExecution(100);\n            }\n\n            // If it returned TRUE, we yielded successfully. \n            // We loop immediately to check if the lock is free now.\n            continue;\n        }\n\n        // We hold the lock. Open the handle.\n        SAM_HANDLE newSamServerHandle;\n        NTSTATUS status;\n\n        status = PhOpenSamHandle(\n            &newSamServerHandle,\n            SAM_SERVER_LOOKUP_DOMAIN | SAM_SERVER_CONNECT,\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // Publish the new handle (releases waiting threads)\n            InterlockedExchangePointer(&cachedSamServerHandle, newSamServerHandle);\n            samServerHandle = newSamServerHandle;\n            cachedStatus = STATUS_SUCCESS;\n        }\n        else\n        {\n            // Failed (e.g., Access Denied). Reset to NULL so we can try again later.\n            InterlockedExchangePointer(&cachedSamServerHandle, NULL);\n            samServerHandle = NULL;\n            cachedStatus = status;\n        }\n        break;\n    }\n\n    if (samServerHandle && samServerHandle != (SAM_HANDLE)-1)\n    {\n        *SamHandle = samServerHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return cachedStatus;\n}\n\n/**\n * Retrieves a handle to the local SAM domain.\n *\n * \\param DesiredAccess The desired access to the handle.\n * \\param DomainHandle A variable which receives the handle.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Do not close the handle; it is cached.\n */\nNTSTATUS PhGetSamDomainHandle(\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE DomainHandle\n    )\n{\n    static SAM_HANDLE cachedSamDomainHandle = NULL;\n    NTSTATUS status = STATUS_SUCCESS;\n    SAM_HANDLE samDomainHandle;\n\n    // Fast Path: No locking for the common case.\n    samDomainHandle = *(volatile SAM_HANDLE*)&cachedSamDomainHandle;\n    if (samDomainHandle && samDomainHandle != (SAM_HANDLE)-1)\n    {\n        *DomainHandle = samDomainHandle;\n        return STATUS_SUCCESS;\n    }\n\n    while (TRUE)\n    {\n        // Attempt to acquire the lock (swap NULL with -1)\n        samDomainHandle = InterlockedCompareExchangePointer(\n            &cachedSamDomainHandle,\n            (SAM_HANDLE)-1,\n            NULL\n            );\n\n        // Handle Contention\n        if (samDomainHandle != NULL)\n        {\n            // If the handle is fully initialized by another thread, return it.\n            if (samDomainHandle != (SAM_HANDLE)-1)\n            {\n                *DomainHandle = samDomainHandle;\n                return STATUS_SUCCESS;\n            }\n\n            // The lock is held (-1). The other thread is talking to LSASS.\n            // Try to yield execution to the lock-holder.\n\n            if (!PhSwitchToThread())\n            {\n                // If PhSwitchToThread returns FALSE, it means no yield happened \n                // (we are alone on this core), so we must force a sleep to stop burning CPU.\n                PhDelayExecution(100);\n            }\n\n            // If it returned TRUE, we yielded successfully. \n            // We loop immediately to check if the lock is free now.\n            continue;\n        }\n\n        // We hold the lock. Open the handle.\n        SAM_HANDLE newSamDomainHandle;\n        PPOLICY_ACCOUNT_DOMAIN_INFO accountDomainInfo;\n\n        status = LsaQueryInformationPolicy(\n            PhGetLookupPolicyHandle(),\n            PolicyAccountDomainInformation,\n            &accountDomainInfo\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhOpenSamDomainHandle(\n                &newSamDomainHandle,\n                DesiredAccess,\n                accountDomainInfo->DomainSid\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                // Publish the new handle (releases waiting threads)\n                InterlockedExchangePointer(&cachedSamDomainHandle, newSamDomainHandle);\n                samDomainHandle = newSamDomainHandle;\n            }\n            else\n            {\n                // Failed. Reset to NULL so we can try again later.\n                InterlockedExchangePointer(&cachedSamDomainHandle, NULL);\n            }\n\n            LsaFreeMemory(accountDomainInfo);\n        }\n        else\n        {\n            InterlockedExchangePointer(&cachedSamDomainHandle, NULL);\n        }\n\n        break;\n    }\n\n    if (samDomainHandle && samDomainHandle != (SAM_HANDLE)-1)\n    {\n        *DomainHandle = samDomainHandle;\n        return STATUS_SUCCESS;\n    }\n\n    return status;\n}\n\n/**\n * Looks up a SAM account name in a domain.\n *\n * \\param DomainHandle A handle to a SAM domain.\n * \\param Name The name of the account to look up.\n * \\param RelativeId A variable which receives the RID of the account.\n * \\param Use A variable which receives the usage of the account.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhLookupSamName(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PPH_STRINGREF Name,\n    _Out_ PULONG RelativeId,\n    _Out_ PSID_NAME_USE Use\n    )\n{\n    NTSTATUS status;\n    PULONG relativeIds;\n    PSID_NAME_USE uses;\n\n    status = PhLookupSamNames(\n        DomainHandle,\n        1,\n        Name,\n        &relativeIds,\n        &uses\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *RelativeId = relativeIds[0];\n        *Use = uses[0];\n\n        PhFree(relativeIds);\n        PhFree(uses);\n    }\n\n    return status;\n}\n\n/**\n * Looks up multiple SAM account names in a domain.\n *\n * \\param DomainHandle A handle to a SAM domain.\n * \\param Count The number of names to look up.\n * \\param Names An array of account names.\n * \\param RelativeIds A variable which receives a pointer to an array of RIDs. You must free the array using PhFree().\n * \\param Uses A variable which receives a pointer to an array of usages. You must free the array using PhFree().\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhLookupSamNames(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ULONG Count,\n    _In_ PPH_STRINGREF Names,\n    _Out_ PULONG* RelativeIds,\n    _Out_ PSID_NAME_USE* Uses\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING names;\n    PULONG relativeIds = NULL;\n    PSID_NAME_USE uses = NULL;\n\n    names = PhAllocateZero(sizeof(UNICODE_STRING) * Count);\n\n    for (ULONG i = 0; i < Count; i++)\n    {\n        if (!PhStringRefToUnicodeString(&Names[i], &names[i]))\n        {\n            PhFree(names);\n            return STATUS_NAME_TOO_LONG;\n        }\n    }\n\n    status = SamLookupNamesInDomain(\n        DomainHandle,\n        Count,\n        names,\n        &relativeIds,\n        &uses\n        );\n\n    if (NT_SUCCESS(status) || status == STATUS_SOME_NOT_MAPPED)\n    {\n        *RelativeIds = PhAllocateCopy(relativeIds, sizeof(ULONG) * Count);\n        *Uses = PhAllocateCopy(uses, sizeof(SID_NAME_USE) * Count);\n\n        SamFreeMemory(relativeIds);\n        SamFreeMemory(uses);\n    }\n\n    PhFree(names);\n\n    return status;\n}\n\n/**\n * Gets the description of a SAM alias (local group).\n *\n * \\param Sid The SID of the alias.\n * \\param Description A variable which receives a pointer to a string containing the alias description.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSamAliasDescription(\n    _In_ PSID Sid,\n    _Out_ PPH_STRING *Description\n    )\n{\n    NTSTATUS status;\n    PPH_STRING description = NULL;\n    SAM_HANDLE domainHandle;\n    SAM_HANDLE aliasHandle;\n    ULONG rid;\n    PVOID infoBuffer;\n\n    *Description = NULL;\n\n    status = PhGetSamDomainHandle(DOMAIN_LOOKUP, &domainHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    rid = *PhSubAuthoritySid(Sid, *PhSubAuthorityCountSid(Sid) - 1);\n\n    status = SamOpenAlias(\n        domainHandle,\n        ALIAS_READ_INFORMATION,\n        rid,\n        &aliasHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = SamQueryInformationAlias(\n            aliasHandle,\n            AliasAdminCommentInformation,\n            &infoBuffer\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            PALIAS_ADM_COMMENT_INFORMATION commentInfo = (PALIAS_ADM_COMMENT_INFORMATION)infoBuffer;\n\n            description = PhCreateStringFromUnicodeString(&commentInfo->AdminComment);\n\n            SamFreeMemory(infoBuffer);\n        }\n\n        SamCloseHandle(aliasHandle);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Description = description;\n    }\n\n    return status;\n}\n\n/**\n * Gets the description of a SAM group.\n *\n * \\param Sid The SID of the group.\n * \\param Description A variable which receives a pointer to a string containing the group description.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSamGroupDescription(\n    _In_ PSID Sid,\n    _Out_ PPH_STRING *Description\n    )\n{\n    NTSTATUS status;\n    PPH_STRING description = NULL;\n    SAM_HANDLE domainHandle;\n    SAM_HANDLE groupHandle;\n    ULONG rid;\n    PVOID infoBuffer;\n\n    status = PhGetSamDomainHandle(DOMAIN_LOOKUP, &domainHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    rid = *PhSubAuthoritySid(Sid, *PhSubAuthorityCountSid(Sid) - 1);\n\n    status = SamOpenGroup(\n        domainHandle,\n        GROUP_READ_INFORMATION,\n        rid,\n        &groupHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = SamQueryInformationGroup(\n            groupHandle,\n            GroupAdminCommentInformation,\n            &infoBuffer\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            PGROUP_ADM_COMMENT_INFORMATION commentInfo = (PGROUP_ADM_COMMENT_INFORMATION)infoBuffer;\n\n            description = PhCreateStringFromUnicodeString(&commentInfo->AdminComment);\n\n            SamFreeMemory(infoBuffer);\n        }\n\n        SamCloseHandle(groupHandle);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Description = description;\n    }\n\n    return status;\n}\n\n/**\n * Gets the description of a SAM user.\n *\n * \\param Sid The SID of the user.\n * \\param Description A variable which receives a pointer to a string containing the user description.\n * You must free the string using PhDereferenceObject() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSamUserDescription(\n    _In_ PSID Sid,\n    _Out_ PPH_STRING *Description\n    )\n{\n    NTSTATUS status;\n    SAM_HANDLE domainHandle;\n    SAM_HANDLE userHandle;\n    ULONG rid;\n    PPH_STRING description = NULL;\n    PVOID infoBuffer;\n\n    *Description = NULL;\n\n    status = PhGetSamDomainHandle(DOMAIN_LOOKUP, &domainHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    rid = *PhSubAuthoritySid(Sid, *PhSubAuthorityCountSid(Sid) - 1);\n\n    status = SamOpenUser(\n        domainHandle,\n        USER_READ_GENERAL,\n        rid,\n        &userHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = SamQueryInformationUser(\n            userHandle,\n            UserAdminCommentInformation,\n            &infoBuffer\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            PUSER_ADMIN_COMMENT_INFORMATION commentInfo = (PUSER_ADMIN_COMMENT_INFORMATION)infoBuffer;\n\n            description = PhCreateStringFromUnicodeString(&commentInfo->AdminComment);\n\n            SamFreeMemory(infoBuffer);\n        }\n\n        SamCloseHandle(userHandle);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Description = description;\n    }\n\n    return status;\n}\n\n/**\n * Gets the description of a SAM account (user, group or alias).\n *\n * \\param Sid The SID of the account.\n * \\return A string containing the account description, or NULL if not found.\n */\nPPH_STRING PhGetSamAccountDescription(\n    _In_ PSID Sid\n    )\n{\n    PPH_STRING description;\n\n    if (NT_SUCCESS(PhGetSamAliasDescription(Sid, &description)))\n    {\n        return description;\n    }\n\n    if (NT_SUCCESS(PhGetSamGroupDescription(Sid, &description)))\n    {\n        return description;\n    }\n\n    if (NT_SUCCESS(PhGetSamUserDescription(Sid, &description)))\n    {\n        return description;\n    }\n\n    return NULL;\n}\n\n/**\n * Queries logon information for a user.\n *\n * \\param DomainName The name of the domain.\n * \\param UserName The name of the user.\n * \\param LogonInfo A variable which receives a pointer to a structure containing the logon\n * information. You must free the structure using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryLogonInformation(\n    _In_ PCPH_STRINGREF DomainName,\n    _In_ PCPH_STRINGREF UserName,\n    _Out_ PUSER_LOGON_INFORMATION* LogonInfo\n    )\n{\n    NTSTATUS status;\n    SAM_HANDLE serverHandle;\n    SAM_HANDLE domainHandle = NULL;\n    SAM_HANDLE userHandle = NULL;\n    PSID domainSid = NULL;\n    UNICODE_STRING domainName;\n    UNICODE_STRING userName;\n    PULONG relativeIds = NULL;\n    PSID_NAME_USE uses = NULL;\n    PUSER_LOGON_INFORMATION samLogonInfo = NULL;\n\n    if (DomainName)\n    {\n        if (!PhStringRefToUnicodeString(DomainName, &domainName))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&domainName, NULL, 0);\n    }\n\n    if (UserName)\n    {\n        if (!PhStringRefToUnicodeString(UserName, &userName))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&userName, NULL, 0);\n    }\n\n    status = PhOpenSamHandle(\n        &serverHandle, \n        SAM_SERVER_LOOKUP_DOMAIN | SAM_SERVER_CONNECT, \n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = SamLookupDomainInSamServer(\n        serverHandle,\n        &domainName,\n        &domainSid\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = SamOpenDomain(\n        serverHandle, \n        DOMAIN_LOOKUP, \n        domainSid, \n        &domainHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = SamLookupNamesInDomain(\n        domainHandle,\n        1,\n        &userName, \n        &relativeIds,\n        &uses\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = SamOpenUser(\n        domainHandle,\n        USER_READ_GENERAL | USER_READ_PREFERENCES |\n        USER_READ_LOGON | USER_READ_ACCOUNT |\n        USER_LIST_GROUPS | USER_READ_GROUP_INFORMATION,\n        relativeIds[0],\n        &userHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = SamQueryInformationUser(\n        userHandle, \n        UserLogonInformation, \n        &samLogonInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    RtlCopyMemory(LogonInfo, samLogonInfo, sizeof(USER_LOGON_INFORMATION));\n\nCleanupExit:\n    if (samLogonInfo)\n        SamFreeMemory(samLogonInfo);\n    if (relativeIds)\n        SamFreeMemory(relativeIds);\n    if (uses)\n        SamFreeMemory(uses);\n    if (userHandle)\n        SamCloseHandle(userHandle);\n    if (domainHandle)\n        SamCloseHandle(domainHandle);\n    if (domainSid)\n        SamFreeMemory(domainSid);\n\n    return status;\n}\n\n"
  },
  {
    "path": "phlib/lsasup.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2011\n *     dmex    2019-2023\n *\n */\n\n/*\n * These are functions which communicate with LSA or are support functions. They replace certain\n * Win32 security-related functions such as LookupAccountName, LookupAccountSid and\n * LookupPrivilege*, which are badly designed. (LSA already allocates the return values for the\n * caller, yet the Win32 functions insist on their callers providing their own buffers.)\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <accctrl.h>\n#include <lsasup.h>\n#include <mapldr.h>\n\n/**\n * Opens a handle to the local LSA policy.\n *\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenLsaPolicy(\n    _Out_ PLSA_HANDLE PolicyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PUNICODE_STRING SystemName\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        NULL,\n        OBJ_EXCLUSIVE,\n        NULL,\n        NULL\n        );\n\n    status = LsaOpenPolicy(\n        SystemName,\n        &objectAttributes,\n        DesiredAccess,\n        PolicyHandle\n        );\n\n    return status;\n}\n\n/**\n * Retrieves a handle to the local LSA policy with POLICY_LOOKUP_NAMES access.\n *\n * \\remarks Do not close the handle; it is cached.\n */\nLSA_HANDLE PhGetLookupPolicyHandle(\n    VOID\n    )\n{\n    static LSA_HANDLE cachedLookupPolicyHandle = NULL;\n    LSA_HANDLE lookupPolicyHandle;\n    LSA_HANDLE newLookupPolicyHandle;\n\n    // Use the cached value if possible.\n\n    lookupPolicyHandle = InterlockedCompareExchangePointer(&cachedLookupPolicyHandle, NULL, NULL);\n\n    // If there is no cached handle, open one.\n\n    if (!lookupPolicyHandle)\n    {\n        if (NT_SUCCESS(PhOpenLsaPolicy(\n            &newLookupPolicyHandle,\n            POLICY_LOOKUP_NAMES,\n            NULL\n            )))\n        {\n            // We succeeded in opening a policy handle, and since we did not have a cached handle\n            // before, we will now store it.\n\n            lookupPolicyHandle = InterlockedCompareExchangePointer(\n                &cachedLookupPolicyHandle,\n                newLookupPolicyHandle,\n                NULL\n                );\n\n            if (!lookupPolicyHandle)\n            {\n                // Success. Use our handle.\n                lookupPolicyHandle = newLookupPolicyHandle;\n            }\n            else\n            {\n                // Someone already placed a handle in the cache. Close our handle and use their\n                // handle.\n                LsaClose(newLookupPolicyHandle);\n            }\n        }\n    }\n\n    return lookupPolicyHandle;\n}\n\n/**\n * Gets the name of a privilege from its LUID.\n *\n * \\param PrivilegeValue The LUID of a privilege.\n * \\param PrivilegeName A variable which receives a pointer to a string containing the privilege\n * name. You must free the string using PhDereferenceObject() when you no longer need it.\n */\nNTSTATUS PhLookupPrivilegeName(\n    _In_ PLUID PrivilegeValue,\n    _Out_ PPH_STRING *PrivilegeName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING name;\n\n    status = LsaLookupPrivilegeName(\n        PhGetLookupPolicyHandle(),\n        PrivilegeValue,\n        &name\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *PrivilegeName = PhCreateStringFromUnicodeString(name);\n    LsaFreeMemory(name);\n\n    return status;\n}\n\n/**\n * Gets the display name of a privilege from its name.\n *\n * \\param PrivilegeName The name of a privilege.\n * \\param PrivilegeDisplayName A variable which receives a pointer to a string containing the\n * privilege's display name. You must free the string using PhDereferenceObject() when you no longer\n * need it.\n */\nNTSTATUS PhLookupPrivilegeDisplayName(\n    _In_ PPH_STRINGREF PrivilegeName,\n    _Out_ PPH_STRING *PrivilegeDisplayName\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING privilegeName;\n    PUNICODE_STRING displayName;\n    SHORT language;\n\n    if (!PhStringRefToUnicodeString(PrivilegeName, &privilegeName))\n        return STATUS_NAME_TOO_LONG;\n\n    status = LsaLookupPrivilegeDisplayName(\n        PhGetLookupPolicyHandle(),\n        &privilegeName,\n        &displayName,\n        &language\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *PrivilegeDisplayName = PhCreateStringFromUnicodeString(displayName);\n    LsaFreeMemory(displayName);\n\n    return status;\n}\n\n/**\n * Gets the LUID of a privilege from its name.\n *\n * \\param PrivilegeName The name of a privilege.\n * \\param PrivilegeValue A variable which receives the LUID of the privilege.\n */\nNTSTATUS PhLookupPrivilegeValue(\n    _In_ PPH_STRINGREF PrivilegeName,\n    _Out_ PLUID PrivilegeValue\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING privilegeName;\n\n    if (!PhStringRefToUnicodeString(PrivilegeName, &privilegeName))\n        return STATUS_NAME_TOO_LONG;\n\n    status = LsaLookupPrivilegeValue(\n        PhGetLookupPolicyHandle(),\n        &privilegeName,\n        PrivilegeValue\n        );\n\n    return status;\n}\n\n/**\n * Gets information about a SID.\n *\n * \\param Sid A SID to query.\n * \\param Name A variable which receives a pointer to a string containing the SID's name. You must\n * free the string using PhDereferenceObject() when you no longer need it.\n * \\param DomainName A variable which receives a pointer to a string containing the SID's domain\n * name. You must free the string using PhDereferenceObject() when you no longer need it.\n * \\param NameUse A variable which receives the SID's usage.\n */\nNTSTATUS PhLookupSid(\n    _In_ PSID Sid,\n    _Out_opt_ PPH_STRING *Name,\n    _Out_opt_ PPH_STRING *DomainName,\n    _Out_opt_ PSID_NAME_USE NameUse\n    )\n{\n    NTSTATUS status;\n    LSA_HANDLE policyHandle;\n    PLSA_REFERENCED_DOMAIN_LIST referencedDomains;\n    PLSA_TRANSLATED_NAME names;\n\n    policyHandle = PhGetLookupPolicyHandle();\n\n    referencedDomains = NULL;\n    names = NULL;\n\n    if (NT_SUCCESS(status = LsaLookupSids(\n        policyHandle,\n        1,\n        &Sid,\n        &referencedDomains,\n        &names\n        )))\n    {\n        if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)\n        {\n            if (Name)\n            {\n                *Name = PhCreateStringFromUnicodeString(&names[0].Name);\n            }\n\n            if (DomainName)\n            {\n                if (names[0].DomainIndex >= 0)\n                {\n                    PLSA_TRUST_INFORMATION trustInfo;\n\n                    trustInfo = &referencedDomains->Domains[names[0].DomainIndex];\n                    *DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);\n                }\n                else\n                {\n                    *DomainName = PhReferenceEmptyString();\n                }\n            }\n\n            if (NameUse)\n            {\n                *NameUse = names[0].Use;\n            }\n        }\n        else\n        {\n            status = STATUS_NONE_MAPPED;\n        }\n    }\n\n    // LsaLookupSids allocates memory even if it returns STATUS_NONE_MAPPED.\n    if (referencedDomains)\n        LsaFreeMemory(referencedDomains);\n    if (names)\n        LsaFreeMemory(names);\n\n    return status;\n}\n\n/**\n * Converts an array of SIDs to a human-readable form.\n *\n * \\param Count The size of the array.\n * \\param Sids An array of SIDs to query.\n * \\param FullNames A variable which receives a pointer to an array of strings in the following format:\n * domain\\\\user. If not applicable to a particular SID, the function returns its SDDL representation.\n * You must free each item using PhDereferenceObject(), and then free the array by calling PhFree().\n */\nNTSTATUS PhLookupSids(\n    _In_ ULONG Count,\n    _In_ PSID *Sids,\n    _Out_ PPH_STRING **FullNames\n    )\n{\n    NTSTATUS status;\n    PLSA_REFERENCED_DOMAIN_LIST referencedDomains = NULL;\n    PLSA_TRANSLATED_NAME names = NULL;\n    PPH_STRING *translatedNames;\n\n    translatedNames = PhAllocateZero(sizeof(PPH_STRING) * Count);\n\n    status = LsaLookupSids(\n        PhGetLookupPolicyHandle(),\n        Count,\n        Sids,\n        &referencedDomains,\n        &names\n        );\n\n    if (status == STATUS_NONE_MAPPED)\n    {\n        // Even without mapping names it converts most of them to SDDL representation\n        status = STATUS_SOME_NOT_MAPPED;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        PPH_STRING userName;\n        PPH_STRING domainName;\n\n        for (ULONG i = 0; i < Count; i++)\n        {\n            userName = NULL;\n            domainName = NULL;\n\n            // Reference user if present\n            if (names[i].Name.Length > 0)\n            {\n                userName = PhCreateStringFromUnicodeString(&names[i].Name);\n            }\n\n            // Reference domain if present\n            if (names[i].DomainIndex >= 0)\n            {\n                PLSA_TRUST_INFORMATION trustInfo;\n\n                trustInfo = &referencedDomains->Domains[names[i].DomainIndex];\n\n                if (trustInfo->Name.Length > 0)\n                {\n                    domainName = PhCreateStringFromUnicodeString(&trustInfo->Name);\n                }\n            }\n\n            // Construct the name\n            if (names[i].Use != SidTypeInvalid && names[i].Use != SidTypeUnknown)\n            {\n                if (domainName && userName)\n                {\n                    translatedNames[i] = PhConcatStringRef3(\n                        &domainName->sr,\n                        &PhNtPathSeparatorString,\n                        &userName->sr\n                        );\n                }\n                else if (domainName)\n                {\n                    translatedNames[i] = PhReferenceObject(domainName);\n                }\n                else if (userName)\n                {\n                    translatedNames[i] = PhReferenceObject(userName);\n                }\n            }\n            else\n            {\n                if (userName && PhStartsWithString2(userName, L\"S-1-\", TRUE))\n                {\n                    translatedNames[i] = PhReferenceObject(userName);\n                }\n            }\n\n            if (userName)\n            {\n                PhDereferenceObject(userName);\n            }\n\n            if (domainName)\n            {\n                PhDereferenceObject(domainName);\n            }\n        }\n\n        LsaFreeMemory(referencedDomains);\n        LsaFreeMemory(names);\n    }\n\n    for (ULONG i = 0; i < Count; i++)\n    {\n        // Make sure everything is converted at least to SDDL\n        if (!translatedNames[i])\n        {\n            translatedNames[i] = PhSidToStringSid(Sids[i]);\n        }\n    }\n\n    *FullNames = translatedNames;\n    return status;\n}\n\n/**\n * Gets information about a name.\n *\n * \\param Name A name to query.\n * \\param Sid A variable which receives a pointer to a SID. You must free the SID using PhFree()\n * when you no longer need it.\n * \\param DomainName A variable which receives a pointer to a string containing the SID's domain\n * name. You must free the string using PhDereferenceObject() when you no longer need it.\n * \\param NameUse A variable which receives the SID's usage.\n */\nNTSTATUS PhLookupName(\n    _In_ PPH_STRINGREF Name,\n    _Out_opt_ PSID *Sid,\n    _Out_opt_ PPH_STRING *DomainName,\n    _Out_opt_ PSID_NAME_USE NameUse\n    )\n{\n    NTSTATUS status;\n    LSA_HANDLE policyHandle;\n    UNICODE_STRING name;\n    PLSA_REFERENCED_DOMAIN_LIST referencedDomains;\n    PLSA_TRANSLATED_SID2 sids;\n\n    if (!PhStringRefToUnicodeString(Name, &name))\n        return STATUS_NAME_TOO_LONG;\n\n    policyHandle = PhGetLookupPolicyHandle();\n    referencedDomains = NULL;\n    sids = NULL;\n\n    if (NT_SUCCESS(status = LsaLookupNames2(\n        policyHandle,\n        0,\n        1,\n        &name,\n        &referencedDomains,\n        &sids\n        )))\n    {\n        if (sids[0].Use != SidTypeInvalid && sids[0].Use != SidTypeUnknown)\n        {\n            if (Sid)\n            {\n                *Sid = PhAllocateCopy(sids[0].Sid, PhLengthSid(sids[0].Sid));\n            }\n\n            if (DomainName)\n            {\n                if (sids[0].DomainIndex >= 0)\n                {\n                    PLSA_TRUST_INFORMATION trustInfo;\n\n                    trustInfo = &referencedDomains->Domains[sids[0].DomainIndex];\n                    *DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);\n                }\n                else\n                {\n                    *DomainName = PhReferenceEmptyString();\n                }\n            }\n\n            if (NameUse)\n            {\n                *NameUse = sids[0].Use;\n            }\n        }\n        else\n        {\n            status = STATUS_NONE_MAPPED;\n        }\n    }\n\n    // LsaLookupNames2 allocates memory even if it returns STATUS_NONE_MAPPED.\n    if (referencedDomains)\n        LsaFreeMemory(referencedDomains);\n    if (sids)\n        LsaFreeMemory(sids);\n\n    return status;\n}\n\n/**\n * Gets the name of a SID.\n *\n * \\param Sid A SID to query.\n * \\param IncludeDomain TRUE to include the domain name, otherwise FALSE.\n * \\param NameUse A variable which receives the SID's usage.\n *\n * \\return A pointer to a string containing the name of the SID in the following format:\n * domain\\\\name. You must free the string using PhDereferenceObject() when you no longer need it. If\n * an error occurs, the function returns NULL.\n */\nPPH_STRING PhGetSidFullName(\n    _In_ PSID Sid,\n    _In_ BOOLEAN IncludeDomain,\n    _Out_opt_ PSID_NAME_USE NameUse\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fullName;\n    LSA_HANDLE policyHandle;\n    PLSA_REFERENCED_DOMAIN_LIST referencedDomains;\n    PLSA_TRANSLATED_NAME names;\n\n    policyHandle = PhGetLookupPolicyHandle();\n\n    referencedDomains = NULL;\n    names = NULL;\n\n    if (NT_SUCCESS(status = LsaLookupSids(\n        policyHandle,\n        1,\n        &Sid,\n        &referencedDomains,\n        &names\n        )))\n    {\n        if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)\n        {\n            PWSTR domainNameBuffer;\n            ULONG domainNameLength;\n\n            if (IncludeDomain && names[0].DomainIndex >= 0)\n            {\n                PLSA_TRUST_INFORMATION trustInfo;\n\n                trustInfo = &referencedDomains->Domains[names[0].DomainIndex];\n                domainNameBuffer = trustInfo->Name.Buffer;\n                domainNameLength = trustInfo->Name.Length;\n            }\n            else\n            {\n                domainNameBuffer = NULL;\n                domainNameLength = 0;\n            }\n\n            if (domainNameBuffer && domainNameLength != 0)\n            {\n                fullName = PhCreateStringEx(NULL, domainNameLength + sizeof(UNICODE_NULL) + names[0].Name.Length);\n                memcpy(&fullName->Buffer[0], domainNameBuffer, domainNameLength);\n                fullName->Buffer[domainNameLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;\n                memcpy(&fullName->Buffer[domainNameLength / sizeof(WCHAR) + 1], names[0].Name.Buffer, names[0].Name.Length);\n            }\n            else\n            {\n                fullName = PhCreateStringFromUnicodeString(&names[0].Name);\n            }\n\n            if (NameUse)\n            {\n                *NameUse = names[0].Use;\n            }\n        }\n        else\n        {\n            fullName = NULL;\n\n            if (NameUse)\n            {\n                *NameUse = SidTypeUnknown;\n            }\n        }\n    }\n    else\n    {\n        fullName = NULL;\n\n        if (NameUse)\n        {\n            *NameUse = SidTypeUnknown;\n        }\n    }\n\n    if (referencedDomains)\n        LsaFreeMemory(referencedDomains);\n    if (names)\n        LsaFreeMemory(names);\n\n    return fullName;\n}\n\n/**\n * Gets a SDDL string representation of a SID.\n *\n * \\param Sid A SID to query.\n *\n * \\return A pointer to a string containing the SDDL representation of the SID. You must free the\n * string using PhDereferenceObject() when you no longer need it. If an error occurs, the function\n * returns NULL.\n */\nPPH_STRING PhSidToStringSid(\n    _In_ PSID Sid\n    )\n{\n    PPH_STRING string;\n    UNICODE_STRING unicodeString;\n\n    string = PhCreateStringEx(NULL, SECURITY_MAX_SID_STRING_CHARACTERS * sizeof(WCHAR));\n\n    if (!PhStringRefToUnicodeString(&string->sr, &unicodeString))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    if (NT_SUCCESS(RtlConvertSidToUnicodeString(\n        &unicodeString,\n        Sid,\n        FALSE\n        )))\n    {\n        string->Length = unicodeString.Length;\n        string->Buffer[unicodeString.Length / sizeof(WCHAR)] = UNICODE_NULL;\n\n        return string;\n    }\n    else\n    {\n        PhDereferenceObject(string);\n\n        return NULL;\n    }\n}\n\n/**\n * Converts a SID to its SDDL string representation and writes it to a buffer.\n *\n * \\param Sid A pointer to the SID to convert.\n * \\param Buffer A pointer to a buffer that receives the SDDL string representation.\n * \\param BufferLength The size of the buffer in bytes.\n * \\param ReturnLength A variable which receives the actual length of the SDDL string in bytes.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The buffer must be large enough to hold the SDDL representation. Use\n * SECURITY_MAX_SID_STRING_CHARACTERS * sizeof(WCHAR) for a safe buffer size.\n */\nNTSTATUS PhSidToBuffer(\n    _In_ PSID Sid,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ USHORT BufferLength,\n    _Out_opt_ PUSHORT ReturnLength\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING unicodeString;\n\n    RtlInitEmptyUnicodeString(&unicodeString, Buffer, BufferLength);\n\n    status = RtlConvertSidToUnicodeString(\n        &unicodeString,\n        Sid,\n        FALSE\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (ReturnLength)\n            *ReturnLength = unicodeString.Length;\n    }\n\n    return status;\n}\n\n/**\n * Gets the name of the user associated with a token.\n *\n * \\param TokenHandle A handle to a token.\n * \\param IncludeDomain TRUE to include the domain name in the result, FALSE to return only the username.\n * \\return A pointer to a string containing the user's name, or NULL on failure. You must free the\n * string using PhDereferenceObject() when you no longer need it. The format is domain\\\\username\n * when IncludeDomain is TRUE, or just username otherwise.\n */\nPPH_STRING PhGetTokenUserString(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN IncludeDomain\n    )\n{\n    PPH_STRING tokenUserString = NULL;\n    PH_TOKEN_USER tokenUser;\n\n    if (NT_SUCCESS(PhGetTokenUser(TokenHandle, &tokenUser)))\n    {\n        tokenUserString = PhGetSidFullName(tokenUser.User.Sid, IncludeDomain, NULL);\n    }\n\n    return tokenUserString;\n}\n\n/**\n * Retrieves the privileges assigned to an account.\n *\n * \\param AccountSid A pointer to the SID of the account.\n * \\param Privileges A variable which receives a pointer to a TOKEN_PRIVILEGES structure\n * containing the account's privileges. You must free the structure using PhFree() when\n * you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetAccountPrivileges(\n    _In_ PSID AccountSid,\n    _Out_ PTOKEN_PRIVILEGES *Privileges\n    )\n{\n    NTSTATUS status;\n    LSA_HANDLE accountHandle;\n    PPRIVILEGE_SET accountPrivileges;\n    PTOKEN_PRIVILEGES privileges;\n\n    status = LsaOpenAccount(PhGetLookupPolicyHandle(), AccountSid, ACCOUNT_VIEW, &accountHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = LsaEnumeratePrivilegesOfAccount(accountHandle, &accountPrivileges);\n    LsaClose(accountHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    privileges = PhAllocate(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * accountPrivileges->PrivilegeCount);\n    privileges->PrivilegeCount = accountPrivileges->PrivilegeCount;\n    memcpy(privileges->Privileges, accountPrivileges->Privilege, sizeof(LUID_AND_ATTRIBUTES) * accountPrivileges->PrivilegeCount);\n\n    LsaFreeMemory(accountPrivileges);\n\n    *Privileges = privileges;\n\n    return status;\n}\n\n/**\n * Enumerates all privileges defined on the local system.\n *\n * \\param Callback A callback function invoked for each batch of privileges. The callback should\n * return STATUS_SUCCESS to continue enumeration or an error status to stop.\n * \\param Context An optional user-defined context value passed to the callback function.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function invokes the callback multiple times with batches of privileges until\n * all privileges are enumerated or the callback returns an error status.\n */\nNTSTATUS PhEnumeratePrivileges(\n    _In_ PPH_ENUM_PRIVILEGES Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    LSA_HANDLE policyHandle;\n    LSA_ENUMERATION_HANDLE enumContext;\n    PPOLICY_PRIVILEGE_DEFINITION buffer;\n    ULONG count;\n\n    status = PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    enumContext = 0;\n\n    while (TRUE)\n    {\n        status = LsaEnumeratePrivileges(\n            policyHandle,\n            &enumContext,\n            &buffer,\n            0x100,\n            &count\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        status = Callback(buffer, count, Context);\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        LsaFreeMemory(buffer);\n    }\n\n    if (status == STATUS_NO_MORE_ENTRIES)\n        status = STATUS_SUCCESS;\n\n    LsaClose(policyHandle);\n\n    return status;\n}\n\n/**\n * Determines the account type of a SID.\n *\n * \\param Sid A pointer to the SID to examine.\n * \\param AccountType A variable which receives the account type (e.g., LocalUserAccountType,\n * PrimaryDomainUserAccountType, AADUserAccountType).\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function requires the LsaLookupUserAccountType function from sechost.dll, which\n * may not be available on older versions of Windows.\n */\nNTSTATUS PhGetSidAccountType(\n    _In_ PSID Sid,\n    _Out_ PLSA_USER_ACCOUNT_TYPE AccountType\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static NTSTATUS (WINAPI* LsaLookupUserAccountType_I)(\n        _In_ PSID Sid,\n        _Out_ PLSA_USER_ACCOUNT_TYPE AccountType\n        );\n    LSA_USER_ACCOUNT_TYPE accountType = UnknownUserAccountType;\n    NTSTATUS status;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        LsaLookupUserAccountType_I = PhGetDllProcedureAddressZ(L\"sechost.dll\", \"LsaLookupUserAccountType\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!LsaLookupUserAccountType_I)\n        return STATUS_UNSUCCESSFUL;\n\n    status = LsaLookupUserAccountType_I(\n        Sid,\n        &accountType\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *AccountType = accountType;\n    }\n\n    return status;\n}\n\n/**\n * Gets a descriptive string representation of the account type for a SID.\n *\n * \\param Sid A pointer to the SID to examine.\n * \\return A pointer to a constant string describing the account type, such as \"Local\", \"ActiveDirectory\",\n * \"Microsoft\", \"AzureAD\", or \"Unknown\". The returned string should not be freed.\n * \\remarks If the account type cannot be determined via LsaLookupUserAccountType, this function\n * falls back to examining the SID authority to provide a descriptive string.\n */\nPCWSTR PhGetSidAccountTypeString(\n    _In_ PSID Sid\n    )\n{\n    LSA_USER_ACCOUNT_TYPE accountType;\n\n    if (NT_SUCCESS(PhGetSidAccountType(Sid, &accountType)))\n    {\n        switch (accountType)\n        {\n        case LocalUserAccountType:\n            return L\"Local\";\n        case PrimaryDomainUserAccountType:\n        case ExternalDomainUserAccountType:\n            return L\"ActiveDirectory\";\n        case LocalConnectedUserAccountType:\n        case MSAUserAccountType:\n            return L\"Microsoft\";\n        case AADUserAccountType:\n            return L\"AzureAD\";\n        case InternetUserAccountType:\n            {\n                SID_IDENTIFIER_AUTHORITY msaAuthority = { 0, 0, 0, 0, 0, 11 };\n\n                if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(Sid), &msaAuthority))\n                {\n                    return L\"Microsoft\";\n                }\n\n                return L\"Internet\";\n            }\n            break;\n        }\n    }\n\n    // If we don't get a result from LsaLookupUserAccountType then return the SID authority (or some other value?)  (dmex)\n\n    if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(Sid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_NULL_SID_AUTHORITY)) // 0\n    {\n        return L\"NULL (Authority)\";\n    }\n\n    if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(Sid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_WORLD_SID_AUTHORITY)) // 1\n    {\n        return L\"World (Authority)\";\n    }\n\n    if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(Sid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_LOCAL_SID_AUTHORITY)) // 2\n    {\n        return L\"Local (Authority)\";\n    }\n\n    if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(Sid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_NT_AUTHORITY)) // 5\n    {\n        return L\"NT (Authority)\";\n    }\n\n    if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(Sid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_APP_PACKAGE_AUTHORITY)) // 15\n    {\n        return L\"APP_PACKAGE (Authority)\";\n    }\n\n    if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(Sid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_MANDATORY_LABEL_AUTHORITY)) // 16\n    {\n        return L\"Mandatory label\";\n    }\n\n    return L\"Unknown\";\n}\n\ntypedef struct _PH_CAPABILITY_ENTRY\n{\n    PPH_STRING Name;\n    PSID CapabilityGroupSid;\n    PSID CapabilitySid;\n} PH_CAPABILITY_ENTRY, *PPH_CAPABILITY_ENTRY;\n\n/**\n * Initializes a cache of capability SIDs by reading the system capabilities list.\n *\n * \\param CapabilitySidArrayList A variable which receives an initialized array containing\n * capability SIDs and their associated names. The caller is responsible for freeing the\n * array and its contents when no longer needed.\n * \\remarks This function reads the capability information from CapsList.txt in the application's\n * Resources directory and populates the array with capability SIDs and names for efficient lookup.\n * This function requires Windows 8 or later and the RtlDeriveCapabilitySidsFromName function.\n */\nVOID PhInitializeCapabilitySidCache(\n    _Inout_ PPH_ARRAY CapabilitySidArrayList\n    )\n{\n    PPH_STRING capabilityListString = NULL;\n    PPH_STRING capabilityListFileName;\n    PH_STRINGREF namePart;\n    PH_STRINGREF remainingPart;\n\n    if (!RtlDeriveCapabilitySidsFromName_Import())\n        return;\n\n    if (capabilityListFileName = PhGetApplicationDirectoryFileNameZ(L\"Resources\\\\CapsList.txt\", TRUE))\n    {\n        PhFileReadAllText(&capabilityListString, &capabilityListFileName->sr, TRUE);\n        PhDereferenceObject(capabilityListFileName);\n    }\n\n    if (!capabilityListString)\n        return;\n\n    PhInitializeArray(CapabilitySidArrayList, sizeof(PH_CAPABILITY_ENTRY), 800);\n    remainingPart = PhGetStringRef(capabilityListString);\n\n    while (remainingPart.Length != 0)\n    {\n        PhSplitStringRefAtChar(&remainingPart, L'\\n', &namePart, &remainingPart);\n\n        if (namePart.Length != 0)\n        {\n            BYTE capabilityGroupSidBuffer[SECURITY_MAX_SID_SIZE] = { 0 };\n            BYTE capabilitySidBuffer[SECURITY_MAX_SID_SIZE] = { 0 };\n            PSID capabilityGroupSid = (PSID)capabilityGroupSidBuffer;\n            PSID capabilitySid = (PSID)capabilitySidBuffer;\n            UNICODE_STRING capabilityName;\n\n            if (PhEndsWithStringRef2(&namePart, L\"\\r\", FALSE))\n                namePart.Length -= sizeof(WCHAR);\n\n            if (!PhStringRefToUnicodeString(&namePart, &capabilityName))\n                continue;\n\n            if (NT_SUCCESS(RtlDeriveCapabilitySidsFromName_Import()(\n                &capabilityName,\n                capabilityGroupSid,\n                capabilitySid\n                )))\n            {\n                PH_CAPABILITY_ENTRY entry;\n\n                entry.Name = PhCreateStringFromUnicodeString(&capabilityName);\n                entry.CapabilityGroupSid = PhAllocateCopy(capabilityGroupSid, PhLengthSid(capabilityGroupSid));\n                entry.CapabilitySid = PhAllocateCopy(capabilitySid, PhLengthSid(capabilitySid));\n\n                PhAddItemArray(CapabilitySidArrayList, &entry);\n            }\n        }\n    }\n\n    PhDereferenceObject(capabilityListString);\n}\n\n/**\n * Gets the display name of a capability SID.\n *\n * \\param CapabilitySid A pointer to a capability SID.\n * \\return A pointer to a string containing the capability's display name, or NULL if the\n * capability cannot be found. You must free the string using PhDereferenceObject() when\n * you no longer need it.\n * \\remarks This function returns the cached capability name, allowing efficient lookup of\n * capability SIDs. This function requires Windows 8 or later.\n */\nPPH_STRING PhGetCapabilitySidName(\n    _In_ PSID CapabilitySid\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PH_ARRAY capabilitySidArrayList;\n    PPH_CAPABILITY_ENTRY entry;\n    SIZE_T i;\n\n    if (WindowsVersion < WINDOWS_8)\n        return NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeCapabilitySidCache(&capabilitySidArrayList);\n        PhEndInitOnce(&initOnce);\n    }\n\n    for (i = 0; i < capabilitySidArrayList.Count; i++)\n    {\n        entry = PhItemArray(&capabilitySidArrayList, i);\n\n        if (PhEqualSid(entry->CapabilitySid, CapabilitySid))\n        {\n            return PhReferenceObject(entry->Name);\n        }\n\n        if (PhEqualSid(entry->CapabilityGroupSid, CapabilitySid))\n        {\n            return PhReferenceObject(entry->Name);\n        }\n    }\n\n    return NULL;\n}\n\ntypedef struct _PH_CAPABILITY_GUID_ENTRY\n{\n    PPH_STRING Name;\n    PPH_STRING CapabilityGuid;\n} PH_CAPABILITY_GUID_ENTRY, *PPH_CAPABILITY_GUID_ENTRY;\n\ntypedef struct _PH_CAPABILITY_KEY_CALLBACK\n{\n    PPH_STRING KeyName;\n    PVOID Context;\n} PH_CAPABILITY_KEY_CALLBACK, *PPH_CAPABILITY_KEY_CALLBACK;\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nBOOLEAN NTAPI PhpAccessManagerEnumerateKeyCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PKEY_BASIC_INFORMATION Information,\n    _In_ PVOID Context\n    )\n{\n    HANDLE keyHandle;\n    PPH_STRING guidString;\n    PH_STRINGREF keyName;\n\n    keyName.Buffer = Information->Name;\n    keyName.Length = Information->NameLength;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        RootDirectory,\n        &keyName,\n        0\n        )))\n    {\n        if (guidString = PhQueryRegistryStringZ(keyHandle, L\"LegacyInterfaceClassGuid\"))\n        {\n            PH_CAPABILITY_GUID_ENTRY entry;\n\n            PhSetReference(&entry.Name, PhCreateString2(&keyName));\n            PhSetReference(&entry.CapabilityGuid, guidString);\n            PhAddItemArray(Context, &entry);\n\n            PhDereferenceObject(guidString);\n        }\n\n        NtClose(keyHandle);\n    }\n\n    return TRUE;\n}\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nBOOLEAN NTAPI PhpDeviceAccessSubKeyEnumerateKeyCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PKEY_BASIC_INFORMATION Information,\n    _In_ PVOID Context\n    )\n{\n    PPH_CAPABILITY_KEY_CALLBACK context = Context;\n    HANDLE keyHandle;\n    PH_STRINGREF keyName;\n\n    keyName.Buffer = Information->Name;\n    keyName.Length = Information->NameLength;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        RootDirectory,\n        &keyName,\n        0\n        )))\n    {\n        PH_CAPABILITY_GUID_ENTRY entry;\n\n        PhSetReference(&entry.Name, context->KeyName);\n        PhSetReference(&entry.CapabilityGuid, PhCreateString2(&keyName));\n        PhAddItemArray(context->Context, &entry);\n\n        NtClose(keyHandle);\n    }\n\n    return TRUE;\n}\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nBOOLEAN NTAPI PhpDeviceAccessEnumerateKeyCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PKEY_BASIC_INFORMATION Information,\n    _In_ PVOID Context\n    )\n{\n    HANDLE keyHandle;\n    PH_STRINGREF keyName;\n\n    keyName.Buffer = Information->Name;\n    keyName.Length = Information->NameLength;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        RootDirectory,\n        &keyName,\n        0\n        )))\n    {\n        PH_CAPABILITY_KEY_CALLBACK entry;\n\n        entry.KeyName = PhCreateString2(&keyName);\n        entry.Context = Context;\n\n        PhEnumerateKey(keyHandle, KeyBasicInformation, PhpDeviceAccessSubKeyEnumerateKeyCallback, &entry);\n\n        PhDereferenceObject(entry.KeyName);\n        NtClose(keyHandle);\n    }\n\n    return TRUE;\n}\n\n/**\n * Initializes a cache of capability GUIDs by reading the system registry.\n *\n * \\param CapabilityGuidArrayList A variable which receives an initialized array containing\n * capability GUIDs and their associated names. The caller is responsible for freeing the\n * array and its contents when no longer needed.\n * \\remarks This function reads capability GUID information from the Windows registry under\n * HKEY_LOCAL_MACHINE\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\CapabilityAccessManager\\\\Capabilities\n * and HKEY_LOCAL_MACHINE\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\DeviceAccess\\\\CapabilityMappings\n * and populates the array for efficient lookup. This function requires Windows 8 or later.\n */\nVOID PhInitializeCapabilityGuidCache(\n    _Inout_ PPH_ARRAY CapabilityGuidArrayList\n    )\n{\n    static CONST PH_STRINGREF accessManagerKeyPath = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\CapabilityAccessManager\\\\Capabilities\");\n    static CONST PH_STRINGREF deviceAccessKeyPath = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\DeviceAccess\\\\CapabilityMappings\");\n    HANDLE keyHandle;\n\n    PhInitializeArray(CapabilityGuidArrayList, sizeof(PH_CAPABILITY_GUID_ENTRY), 100);\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &accessManagerKeyPath,\n        0\n        )))\n    {\n        PhEnumerateKey(keyHandle, KeyBasicInformation, PhpAccessManagerEnumerateKeyCallback, CapabilityGuidArrayList);\n        NtClose(keyHandle);\n    }\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &deviceAccessKeyPath,\n        0\n        )))\n    {\n        PhEnumerateKey(keyHandle, KeyBasicInformation, PhpDeviceAccessEnumerateKeyCallback, CapabilityGuidArrayList);\n        NtClose(keyHandle);\n    }\n}\n\n/**\n * Gets the display name associated with a capability GUID.\n *\n * \\param GuidString A string containing a capability GUID.\n * \\return A pointer to a string containing the capability's display name, or NULL if the\n * GUID cannot be found. You must free the string using PhDereferenceObject() when you no\n * longer need it.\n * \\remarks This function returns the cached capability name associated with the given GUID,\n * allowing efficient lookup of capability GUIDs. This function requires Windows 8 or later.\n */\nPPH_STRING PhGetCapabilityGuidName(\n    _In_ PPH_STRING GuidString\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PH_ARRAY capabilityGuidArrayList;\n    PPH_CAPABILITY_GUID_ENTRY entry;\n    SIZE_T i;\n\n    if (WindowsVersion < WINDOWS_8)\n        return NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PhInitializeCapabilityGuidCache(&capabilityGuidArrayList);\n        PhEndInitOnce(&initOnce);\n    }\n\n    for (i = 0; i < capabilityGuidArrayList.Count; i++)\n    {\n        entry = PhItemArray(&capabilityGuidArrayList, i);\n\n        if (PhEqualString(entry->CapabilityGuid, GuidString, TRUE))\n        {\n            return PhReferenceObject(entry->Name);\n        }\n    }\n\n    return NULL;\n}\n\n// rev from BuildTrusteeWithSidW (dmex)\n/**\n * Initializes a TRUSTEE structure with a SID.\n *\n * \\param Trustee A variable which receives a pointer to an initialized TRUSTEE structure.\n * \\param Sid An optional pointer to a SID. If NULL, the TRUSTEE is initialized with no SID.\n * \\return TRUE if the operation succeeds, FALSE otherwise.\n * \\remarks This function is a replacement for the BuildTrusteeWithSidW API and initializes\n * the TRUSTEE structure with the appropriate fields set for use with access control functions.\n */\nBOOLEAN PhBuildTrusteeWithSid(\n    _Out_ PVOID Trustee,\n    _In_opt_ PSID Sid\n    )\n{\n    memset((PTRUSTEE)Trustee, 0, sizeof(TRUSTEE));\n    ((PTRUSTEE)Trustee)->pMultipleTrustee = NULL;\n    ((PTRUSTEE)Trustee)->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;\n    ((PTRUSTEE)Trustee)->TrusteeForm = TRUSTEE_IS_SID;\n    ((PTRUSTEE)Trustee)->TrusteeType = TRUSTEE_IS_UNKNOWN;\n    ((PTRUSTEE)Trustee)->ptstrName = (LPWCH)Sid;\n    return TRUE;\n}\n\n// rev from RtlMapGenericMask (dmex)\n/**\n * Maps generic access rights to specific access rights.\n *\n * \\param AccessMask A pointer to an access mask containing generic rights (GENERIC_READ,\n * GENERIC_WRITE, GENERIC_EXECUTE, GENERIC_ALL) to be converted to specific rights.\n * \\param GenericMapping A pointer to a GENERIC_MAPPING structure containing the mapping\n * information for the object type.\n * \\remarks This function modifies the access mask in-place, replacing generic access rights\n * with their corresponding specific rights. This is a replacement for the RtlMapGenericMask\n * function and is useful when working with access control lists and security descriptors.\n */\nVOID PhMapGenericMask(\n    _Inout_ PACCESS_MASK AccessMask,\n    _In_ PGENERIC_MAPPING GenericMapping\n    )\n{\n    ACCESS_MASK accessMask = *AccessMask;\n\n    if (BooleanFlagOn(accessMask, GENERIC_READ))\n        SetFlag(accessMask, GenericMapping->GenericRead);\n    if (BooleanFlagOn(accessMask, GENERIC_WRITE))\n        SetFlag(accessMask, GenericMapping->GenericWrite);\n    if (BooleanFlagOn(accessMask, GENERIC_EXECUTE))\n        SetFlag(accessMask, GenericMapping->GenericExecute);\n    if (BooleanFlagOn(accessMask, GENERIC_ALL))\n        SetFlag(accessMask, GenericMapping->GenericAll);\n\n    *AccessMask = ClearFlag(accessMask, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);\n}\n\n/**\n * Enumerates all local user accounts on the system.\n *\n * \\param Callback A callback function invoked for each user account. The callback should\n * return STATUS_SUCCESS to continue enumeration or an error status to stop.\n * \\param Context An optional user-defined context value passed to the callback function.\n * \\return STATUS_UNSUCCESSFUL if enumeration could not be performed or if the callback\n * returned an error, otherwise STATUS_SUCCESS.\n * \\remarks This function enumerates accounts via the LSA policy and filters results to\n * include only user-type accounts (SidTypeUser). The callback function is invoked with\n * the account name as a string reference and the user-provided context.\n */\nNTSTATUS PhEnumerateAccounts(\n    _In_ PPH_ENUM_ACCOUNT_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    //static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    //static ULONG (WINAPI* NetUserEnum_I)( // NET_API_STATUS\n    //    _In_ PCWSTR servername,\n    //    _In_ ULONG level,\n    //    _In_ ULONG filter,\n    //    _Out_ PVOID* bufptr,\n    //    _In_ ULONG prefmaxlen,\n    //    _Out_ PULONG entriesread,\n    //    _Out_ PULONG totalentries,\n    //    _Inout_ PULONG resume_handle\n    //    );\n    //static ULONG (WINAPI* NetApiBufferFree_I)(\n    //    _Frees_ptr_opt_ PVOID Buffer\n    //    );\n    //typedef struct _USER_INFO_0\n    //{\n    //    LPWSTR usri0_name;\n    //} USER_INFO_0, *PUSER_INFO_0;\n    //#define FILTER_NORMAL_ACCOUNT (0x0002)\n    //ULONG status;\n    //PUSER_INFO_0 userinfoArray = NULL;\n    //ULONG userinfoEntriesRead = 0;\n    //ULONG userinfoTotalEntries = 0;\n    //\n    //if (PhBeginInitOnce(&initOnce))\n    //{\n    //    PVOID baseAddress;\n    //\n    //    if (baseAddress = PhLoadLibrary(L\"netapi32.dll\"))\n    //    {\n    //        NetUserEnum_I = PhGetDllBaseProcedureAddress(baseAddress, \"NetUserEnum\", 0);\n    //        NetApiBufferFree_I = PhGetDllBaseProcedureAddress(baseAddress, \"NetApiBufferFree\", 0);\n    //    }\n    //\n    //    PhEndInitOnce(&initOnce);\n    //}\n    //\n    //if (!(NetUserEnum_I && NetApiBufferFree_I))\n    //    return STATUS_UNSUCCESSFUL;\n    //\n    //NetUserEnum_I(\n    //    NULL,\n    //    0,\n    //    FILTER_NORMAL_ACCOUNT,\n    //    &userinfoArray,\n    //    ULONG_MAX,\n    //    &userinfoEntriesRead,\n    //    &userinfoTotalEntries,\n    //    NULL\n    //    );\n    //\n    //if (userinfoArray)\n    //{\n    //    NetApiBufferFree_I(userinfoArray);\n    //    userinfoArray = NULL;\n    //}\n    //\n    //status = NetUserEnum_I(\n    //    NULL,\n    //    0,\n    //    FILTER_NORMAL_ACCOUNT,\n    //    &userinfoArray,\n    //    ULONG_MAX,\n    //    &userinfoEntriesRead,\n    //    &userinfoTotalEntries,\n    //    NULL\n    //    );\n    //\n    //if (status == ERROR_SUCCESS)\n    //{\n    //    for (ULONG i = 0; i < userinfoEntriesRead; i++)\n    //    {\n    //        PUSER_INFO_0 entry = PTR_ADD_OFFSET(userinfoArray, sizeof(USER_INFO_0) * i);\n    //\n    //        if (entry->usri0_name)\n    //        {\n    //            PH_STRINGREF string;\n    //\n    //            PhInitializeStringRefLongHint(&string, entry->usri0_name);\n    //\n    //            if (!NT_SUCCESS(Callback(&string, Context)))\n    //            {\n    //                break;\n    //            }\n    //        }\n    //    }\n    //}\n    //\n    //if (userinfoArray)\n    //    NetApiBufferFree_I(userinfoArray);\n\n    LSA_HANDLE policyHandle;\n    LSA_ENUMERATION_HANDLE enumerationContext = 0;\n    PLSA_ENUMERATION_INFORMATION buffer;\n    ULONG count;\n    ULONG i;\n    PPH_STRING name;\n    SID_NAME_USE nameUse;\n\n    if (NT_SUCCESS(PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL)))\n    {\n        while (NT_SUCCESS(LsaEnumerateAccounts(\n            policyHandle,\n            &enumerationContext,\n            &buffer,\n            0x100,\n            &count\n            )))\n        {\n            for (i = 0; i < count; i++)\n            {\n                name = PhGetSidFullName(buffer[i].Sid, TRUE, &nameUse);\n                if (name)\n                {\n                    if (nameUse == SidTypeUser)\n                    {\n                        if (!NT_SUCCESS(Callback(&name->sr, Context)))\n                        {\n                            break;\n                        }\n                    }\n                    PhDereferenceObject(name);\n                }\n            }\n            LsaFreeMemory(buffer);\n        }\n\n        LsaClose(policyHandle);\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n/**\n * Creates a service SID from a service name and writes it to a buffer.\n *\n * \\param ServiceName The name of the service for which to create a SID.\n * \\param ServiceSid A pointer to a buffer that receives the service SID. If NULL, the function\n * returns the required buffer size in ServiceSidLength.\n * \\param ServiceSidLength On input, contains the size of the ServiceSid buffer in bytes.\n * On output, receives the actual size of the SID in bytes.\n * \\return STATUS_SUCCESS on success, or an error status indicating failure.\n * \\remarks If ServiceSid is NULL, the function returns STATUS_BUFFER_TOO_SMALL with the\n * required buffer size. Service SIDs are created using RtlCreateServiceSid.\n */\nNTSTATUS PhCreateServiceSidToBuffer(\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid,\n    _Inout_ PULONG ServiceSidLength\n    )\n{\n    UNICODE_STRING serviceName;\n    NTSTATUS status;\n\n    if (!PhStringRefToUnicodeString(ServiceName, &serviceName))\n        return STATUS_NAME_TOO_LONG;\n\n    status = RtlCreateServiceSid(\n        &serviceName,\n        ServiceSid,\n        ServiceSidLength\n        );\n\n    return status;\n}\n\n/**\n * Converts a service name to its SDDL string representation of the service SID.\n *\n * \\param ServiceName The name of the service for which to create a SID.\n * \\return A pointer to a string containing the SDDL representation of the service SID, or NULL\n * on failure. You must free the string using PhDereferenceObject() when you no longer need it.\n * \\remarks This function creates a service SID and then converts it to its SDDL representation\n * for display or storage purposes.\n */\nPPH_STRING PhCreateServiceSidToStringSid(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    BYTE serviceSidBuffer[SECURITY_MAX_SID_SIZE] = { 0 };\n    ULONG serviceSidLength = sizeof(serviceSidBuffer);\n    PSID serviceSid = (PSID)serviceSidBuffer;\n\n    if (NT_SUCCESS(PhCreateServiceSidToBuffer(ServiceName, serviceSid, &serviceSidLength)))\n    {\n        return PhSidToStringSid(serviceSid);\n    }\n\n    return NULL;\n}\n\n/**\n * Extracts the Azure AD object GUID from an Azure AD directory SID.\n *\n * \\param ActiveDirectorySid A pointer to a SID from Azure AD (cloud-based directory authority).\n * \\return A pointer to a string containing the GUID of the Azure AD object, or NULL if the\n * SID is not an Azure AD SID or the GUID cannot be extracted. The returned string does not\n * include the surrounding braces. You must free the string using PhDereferenceObject() when\n * you no longer need it.\n * \\remarks This function is specifically designed to work with Azure AD (cloud) SIDs and\n * extracts the object identifier from sub-authorities. The SID must have the Azure AD\n * authority identifier and follow the specific sub-authority format used by Azure AD.\n */\nPPH_STRING PhGetAzureDirectoryObjectSid(\n    _In_ PSID ActiveDirectorySid\n    )\n{\n    if (PhEqualIdentifierAuthoritySid(\n        PhIdentifierAuthoritySid(ActiveDirectorySid),\n        PhIdentifierAuthoritySid(PhSeCloudActiveDirectorySid())\n        ))\n    {\n        ULONG subAuthority = *PhSubAuthoritySid(ActiveDirectorySid, 0);\n\n        if (subAuthority == 1)\n        {\n            PPH_STRING string;\n            union\n            {\n                GUID Guid;\n                struct\n                {\n                    ULONG Data1;\n                    ULONG Data2;\n                    ULONG Data3;\n                    ULONG Data4;\n                };\n            } objectGuid;\n\n            objectGuid.Data1 = *PhSubAuthoritySid(ActiveDirectorySid, 1);\n            objectGuid.Data2 = *PhSubAuthoritySid(ActiveDirectorySid, 2);\n            objectGuid.Data3 = *PhSubAuthoritySid(ActiveDirectorySid, 3);\n            objectGuid.Data4 = *PhSubAuthoritySid(ActiveDirectorySid, 4);\n\n            if (string = PhFormatGuid(&objectGuid.Guid))\n            {\n                PhMoveReference(&string, PhSubstring(string, 1, string->Length / sizeof(WCHAR) - 2)); // Strip {}\n                return string;\n            }\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Returns the user and the domain of the security principal that is invoking the method.\n * \\param UserName A variable which receives a pointer to a string containing the username.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhLsaGetUserName(\n    _Out_ PPH_STRING* UserName\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fullName = NULL;\n    PLSA_UNICODE_STRING userName = NULL;\n    PLSA_UNICODE_STRING domainName = NULL;\n\n    status = LsaGetUserName(\n        &userName,\n        &domainName\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (domainName && domainName->Length != 0)\n        {\n            fullName = PhCreateStringEx(NULL, domainName->MaximumLength + userName->MaximumLength);\n            memcpy(&fullName->Buffer[0], domainName->Buffer, domainName->Length);\n            fullName->Buffer[domainName->Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;\n            memcpy(&fullName->Buffer[domainName->Length / sizeof(WCHAR) + 1], userName->Buffer, userName->Length);\n        }\n        else\n        {\n            fullName = PhCreateStringFromUnicodeString(userName);\n        }\n\n        LsaFreeMemory(userName);\n\n        if (domainName)\n            LsaFreeMemory(domainName);\n    }\n\n    if (UserName)\n        *UserName = fullName;\n\n    return status;\n}\n/**\n * Determines whether the local machine is joined to a domain.\n *\n * \\return TRUE if the machine is domain-joined, FALSE otherwise.\n */\nBOOLEAN PhIsDomainJoined(\n    VOID\n    )\n{\n    NTSTATUS status;\n    PPOLICY_DNS_DOMAIN_INFO domainInfo = NULL;\n    BOOLEAN joined = FALSE;\n\n    status = LsaQueryInformationPolicy(\n        PhGetLookupPolicyHandle(),\n        PolicyDnsDomainInformation,\n        &domainInfo\n        );\n\n    if (NT_SUCCESS(status) && domainInfo)\n    {\n        joined = (domainInfo->DnsDomainName.Length != 0) || (domainInfo->Sid != NULL);\n        LsaFreeMemory(domainInfo);\n    }\n\n    return joined;\n}\n\n/**\n * Determines whether a SID is a service SID.\n *\n * \\param Sid A pointer to the SID to check.\n * \\return TRUE if the SID is a service SID (NT AUTHORITY with SECURITY_SERVICE_ID_BASE_RID), FALSE otherwise.\n */\nBOOLEAN PhIsServiceSid(\n    _In_ PSID Sid\n    )\n{\n    if (!Sid || !RtlValidSid(Sid)) return FALSE;\n\n    if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(Sid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_NT_AUTHORITY))\n    {\n        ULONG subAuthority = *PhSubAuthoritySid(Sid, 0);\n\n        if (subAuthority == SECURITY_SERVICE_ID_BASE_RID)\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Gets a descriptive name for a SID authority.\n *\n * \\param Sid The SID to examine.\n * \\return A string describing the authority, or NULL if unknown. You must free the string using PhDereferenceObject().\n */\nPPH_STRING PhGetSidAuthorityName(\n    _In_ PSID Sid\n    )\n{\n    PSID_IDENTIFIER_AUTHORITY authority;\n    UCHAR authorityValue;\n\n    if (!Sid || !RtlValidSid(Sid))\n        return NULL;\n\n    authority = PhIdentifierAuthoritySid(Sid);\n\n    // Get the last byte of the authority (most significant for standard authorities)\n    authorityValue = authority->Value[5];\n\n    switch (authorityValue)\n    {\n    case 0: // SECURITY_NULL_SID_AUTHORITY\n        return PhCreateString(L\"NULL Authority\");\n    case 1: // SECURITY_WORLD_SID_AUTHORITY\n        return PhCreateString(L\"World Authority\");\n    case 2: // SECURITY_LOCAL_SID_AUTHORITY\n        return PhCreateString(L\"Local Authority\");\n    case 3: // SECURITY_CREATOR_SID_AUTHORITY\n        return PhCreateString(L\"Creator Authority\");\n    case 5: // SECURITY_NT_AUTHORITY\n        return PhCreateString(L\"NT Authority\");\n    case 9: // SECURITY_RESOURCE_MANAGER_AUTHORITY\n        return PhCreateString(L\"Resource Manager Authority\");\n    case 12: // Azure Active Directory\n        return PhCreateString(L\"Azure Active Directory\");\n    case 15: // SECURITY_APP_PACKAGE_AUTHORITY\n        return PhCreateString(L\"App Package Authority\");\n    case 16: // SECURITY_MANDATORY_LABEL_AUTHORITY\n        return PhCreateString(L\"Mandatory Label Authority\");\n    case 18: // SECURITY_AUTHENTICATION_AUTHORITY\n        return PhCreateString(L\"Authentication Authority\");\n    case 19: // SECURITY_PROCESS_TRUST_AUTHORITY\n        return PhCreateString(L\"Process Trust Authority\");\n    default:\n        return PhFormatString(L\"Authority %u\", authorityValue);\n    }\n}\n"
  },
  {
    "path": "phlib/mapexlf.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2017\n *\n */\n\n#include <ph.h>\n#include <mapimg.h>\n\nNTSTATUS PhInitializeMappedWslImage(\n    _Out_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    )\n{\n    MappedWslImage->ViewBase = ViewBase;\n    MappedWslImage->ViewSize = Size;\n    MappedWslImage->Header = (PELF_IMAGE_HEADER)ViewBase;\n\n    __try\n    {\n        PhProbeAddress(\n            MappedWslImage->Header,\n            sizeof(ELF_IMAGE_HEADER),\n            MappedWslImage->ViewBase,\n            MappedWslImage->ViewSize,\n            1\n            );\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // Check the magic number.\n\n    if (!RtlEqualMemory(MappedWslImage->Header->e_ident, ELFMAG, sizeof(ELFMAG)))\n        return STATUS_FAIL_CHECK;\n\n    // Check the class type.\n\n    if (MappedWslImage->Header->e_ident[EI_CLASS] == ELFCLASS64)\n    {\n        MappedWslImage->Headers64 = PTR_ADD_OFFSET(MappedWslImage->Header, sizeof(ELF_IMAGE_HEADER));\n\n        __try\n        {\n            PhProbeAddress(\n                MappedWslImage->Headers64,\n                sizeof(ELF64_IMAGE_SECTION_HEADER),\n                MappedWslImage->ViewBase,\n                MappedWslImage->ViewSize,\n                1\n                );\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n    else\n    {\n        // TODO: Add 32bit ELF support.\n        return STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT;\n    }\n\n    //if (MappedWslImage->Headers64->e_phentsize != sizeof(ELF64_IMAGE_SEGMENT_HEADER))\n    //    return STATUS_FAIL_CHECK;\n    if (MappedWslImage->Headers64->e_shentsize != sizeof(ELF64_IMAGE_SECTION_HEADER))\n        return STATUS_FAIL_CHECK;\n\n    return STATUS_SUCCESS;\n}\n\nPELF64_IMAGE_SEGMENT_HEADER PhGetMappedWslImageSegment(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ USHORT Index\n    )\n{\n    return IMAGE_ELF64_SEGMENT_BY_INDEX(IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage), Index);\n}\n\nPELF64_IMAGE_SEGMENT_HEADER PhGetWslImageSegmentByType(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_opt_ USHORT Type\n    )\n{\n    PELF64_IMAGE_SEGMENT_HEADER segmentHeader;\n    USHORT i;\n\n    segmentHeader = IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_phnum; i++)\n    {\n        if (segmentHeader[i].p_type == Type)\n            return segmentHeader;\n    }\n\n    return NULL;\n}\n\nPVOID PhGetMappedWslImageSectionData(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_opt_ PCSTR Name,\n    _In_opt_ USHORT Index\n    )\n{\n    if (Name)\n    {\n        PELF64_IMAGE_SECTION_HEADER sectionHeader;\n        PELF64_IMAGE_SECTION_HEADER stringSection;\n        PELF64_IMAGE_SECTION_HEADER section;\n        PVOID stringTable;\n        USHORT i;\n\n        sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n        stringSection = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, MappedWslImage->Headers64->e_shstrndx);\n        stringTable = PTR_ADD_OFFSET(MappedWslImage->Header, stringSection->sh_offset);\n\n        for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++)\n        {\n            section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i);\n\n            if (PhEqualBytesZ(Name, PTR_ADD_OFFSET(stringTable, section->sh_name), FALSE))\n            {\n                return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset);\n            }\n        }\n\n        return NULL;\n    }\n    else\n    {\n        PELF64_IMAGE_SECTION_HEADER sectionHeader;\n        PELF64_IMAGE_SECTION_HEADER section;\n\n        sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n        section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, Index);\n\n        return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset);\n    }\n}\n\nPVOID PhGetMappedWslImageSectionDataByType(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ UINT32 Type\n    )\n{\n    PELF64_IMAGE_SECTION_HEADER sectionHeader;\n    PELF64_IMAGE_SECTION_HEADER section;\n    USHORT i;\n\n    sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++)\n    {\n        section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i);\n\n        if (section->sh_type == Type)\n        {\n            return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset);\n        }\n    }\n\n    return NULL;\n}\n\nPELF64_IMAGE_SECTION_HEADER PhGetMappedWslImageSectionByIndex(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ USHORT Index\n    )\n{\n    return IMAGE_ELF64_SECTION_BY_INDEX(IMAGE_FIRST_ELF64_SECTION(MappedWslImage), Index);\n}\n\nPELF64_IMAGE_SECTION_HEADER PhGetMappedWslImageSectionByType(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ UINT32 Type\n    )\n{\n    PELF64_IMAGE_SECTION_HEADER sectionHeader;\n    PELF64_IMAGE_SECTION_HEADER section;\n    USHORT i;\n\n    sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++)\n    {\n        section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i);\n\n        if (section->sh_type == Type)\n            return section;\n    }\n\n    return NULL;\n}\n\nPELF64_IMAGE_SECTION_HEADER PhGetMappedWslImageSectionByName(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ PCSTR Name\n    )\n{\n    if (Name)\n    {\n        PELF64_IMAGE_SECTION_HEADER sectionHeader;\n        PELF64_IMAGE_SECTION_HEADER stringSection;\n        PELF64_IMAGE_SECTION_HEADER section;\n        PVOID stringTable;\n        USHORT i;\n\n        sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n        stringSection = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, MappedWslImage->Headers64->e_shstrndx);\n        stringTable = PTR_ADD_OFFSET(MappedWslImage->Header, stringSection->sh_offset);\n\n        for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++)\n        {\n            section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i);\n\n            if (PhEqualBytesZ(Name, PTR_ADD_OFFSET(stringTable, section->sh_name), FALSE))\n            {\n                return section;\n            }\n        }\n    }\n\n    return NULL;\n}\n\nULONG64 PhGetMappedWslImageBaseAddress(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage\n    )\n{\n    ULONG64 baseAddress = MAXULONG64;\n    PELF64_IMAGE_SEGMENT_HEADER segment;\n    ULONG loadBias = 0;\n    USHORT i;\n\n    segment = IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_phnum; i++)\n    {\n        if (segment[i].p_type == PT_LOAD)\n        {\n            loadBias = (ULONG)ALIGN_DOWN_BY(segment[i].p_vaddr, PAGE_SIZE);\n            break;\n        }\n    }\n\n    for (i = 0; i < MappedWslImage->Headers64->e_phnum; i++)\n    {\n        if (segment[i].p_type == PT_LOAD)\n        {\n            if (segment[i].p_paddr < baseAddress)\n                baseAddress = segment[i].p_paddr;\n        }\n    }\n\n    if (baseAddress == MAXULONG64)\n        baseAddress = 0;\n\n    return baseAddress;\n}\n\nBOOLEAN PhGetMappedWslImageSections(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ USHORT *NumberOfSections,\n    _Out_ PPH_ELF_IMAGE_SECTION *ImageSections\n    )\n{\n    USHORT count;\n    USHORT i;\n    PPH_ELF_IMAGE_SECTION sections;\n    PELF64_IMAGE_SECTION_HEADER sectionHeader;\n    PELF64_IMAGE_SECTION_HEADER stringSection;\n    PVOID stringTableAddress;\n\n    count = MappedWslImage->Headers64->e_shnum;\n    sections = PhAllocate(sizeof(PH_ELF_IMAGE_SECTION) * count);\n    memset(sections, 0, sizeof(PH_ELF_IMAGE_SECTION) * count);\n\n    // Get the first section.\n    sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n\n    // Get the string section.\n    stringSection = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, MappedWslImage->Headers64->e_shstrndx);\n\n    // Get the string table (The string table is an array of null terminated strings).\n    stringTableAddress = PTR_ADD_OFFSET(MappedWslImage->Header, stringSection->sh_offset);\n\n    // Enumerate the sections.\n    for (i = 0; i < count; i++)\n    {\n        sections[i].Type = sectionHeader[i].sh_type;\n        sections[i].Flags = sectionHeader[i].sh_flags;\n        sections[i].Address = sectionHeader[i].sh_addr;\n        sections[i].Offset = sectionHeader[i].sh_offset;\n        sections[i].Size = sectionHeader[i].sh_size;\n\n        if (sectionHeader[i].sh_name)\n        {\n            // Get the section name from the ELF string table and convert to unicode.\n            PhCopyStringZFromUtf8(\n                PTR_ADD_OFFSET(stringTableAddress, sectionHeader[i].sh_name),\n                SIZE_MAX,\n                sections[i].Name,\n                sizeof(sections[i].Name),\n                NULL\n                );\n        }\n    }\n\n    *NumberOfSections = count;\n    *ImageSections = sections;\n\n    return TRUE;\n}\n\ntypedef struct _PH_ELF_VERSION_RECORD\n{\n    USHORT Version;\n    PCSTR Name;\n    PCSTR FileName;\n} PH_ELF_VERSION_RECORD, *PPH_ELF_VERSION_RECORD;\n\nstatic PPH_LIST PhpParseMappedWslImageVersionRecords(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ PVOID SymbolStringTable\n    )\n{\n    PPH_LIST recordsList;\n    PELF_VERSION_NEED version;\n\n    if (!(version = PhGetMappedWslImageSectionDataByType(MappedWslImage, SHT_SUNW_verneed)))\n        return NULL;\n\n    recordsList = PhCreateList(10);\n\n    while (TRUE)\n    {\n        PELF_VERSION_AUX versionAux = PTR_ADD_OFFSET(version, version->vn_aux);\n\n        while (TRUE)\n        {\n            PPH_ELF_VERSION_RECORD versionInfo;\n\n            versionInfo = PhAllocateZero(sizeof(PH_ELF_VERSION_RECORD));\n            versionInfo->Version = versionAux->vna_other;\n            versionInfo->Name = PTR_ADD_OFFSET(SymbolStringTable, versionAux->vna_name);\n            versionInfo->FileName = PTR_ADD_OFFSET(SymbolStringTable, version->vn_file);\n\n            PhAddItemList(recordsList, versionInfo);\n\n            if (versionAux->vna_next == 0)\n                break;\n\n            versionAux = PTR_ADD_OFFSET(versionAux, versionAux->vna_next);\n        }\n\n        if (version->vn_next == 0)\n            break;\n\n        version = PTR_ADD_OFFSET(version, version->vn_next);\n    }\n\n    return recordsList;\n}\n\nstatic VOID PhpFreeMappedWslImageVersionRecords(\n    _In_ PPH_LIST RecordsList\n    )\n{\n    for (ULONG i = 0; i < RecordsList->Count; i++)\n        PhFree(RecordsList->Items[i]);\n\n    PhDereferenceObject(RecordsList);\n}\n\nstatic PCSTR PhpFindWslImageVersionRecordName(\n    _In_ PPH_LIST VersionRecordList,\n    _In_ USHORT VersionIndex\n    )\n{\n    // Note: 'ldconfig -v' and 'ldconfig -p' can be used to locate the path from the FileName.\n    for (ULONG i = 0; i < VersionRecordList->Count; i++)\n    {\n        PPH_ELF_VERSION_RECORD versionInfo = VersionRecordList->Items[i];\n\n        if (versionInfo->Version == VersionIndex)\n            return versionInfo->FileName;\n    }\n\n    return NULL;\n}\n\nBOOLEAN PhGetMappedWslImageSymbols(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ PPH_LIST *ImageSymbols\n    )\n{\n    PELF64_IMAGE_SECTION_HEADER sectionHeader;\n    PELF64_IMAGE_SECTION_HEADER section;\n    PPH_LIST sectionSymbols;\n    USHORT i;\n\n    sectionSymbols = PhCreateList(0x800);\n    sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++)\n    {\n        ULONGLONG count;\n        ULONGLONG ii;\n        PELF_IMAGE_SYMBOL_ENTRY entry;\n        PVOID stringTable;\n        PELF_VERSION_TABLE versionTable;\n        PPH_LIST versionRecords;\n\n        section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i);\n\n        // NOTE: The below code needs some improvements for SHT_SYMTAB -dmex\n        if (section->sh_type != SHT_SYMTAB && section->sh_type != SHT_DYNSYM)\n            continue;\n\n        if (section->sh_entsize != sizeof(ELF_IMAGE_SYMBOL_ENTRY))\n            return FALSE;\n\n        count = section->sh_size / sizeof(ELF_IMAGE_SYMBOL_ENTRY);\n        entry = PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset);\n        stringTable = PhGetMappedWslImageSectionData(MappedWslImage, NULL, section->sh_link);\n\n        // NOTE: SHT_DYNSYM entries include the version in the symbol name (e.g. printf@GLIBC_2.2.5)\n        // instead of using a version record entry from the SHT_SUNW_versym section -dmex\n        versionTable = PhGetMappedWslImageSectionDataByType(MappedWslImage, SHT_SUNW_versym);\n        versionRecords = PhpParseMappedWslImageVersionRecords(MappedWslImage, stringTable);\n\n        for (ii = 1; ii < count; ii++)\n        {\n            if (entry[ii].st_shndx == SHN_UNDEF)\n            {\n                PPH_ELF_IMAGE_SYMBOL_ENTRY import;\n\n                import = PhAllocateZero(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY));\n                import->ImportSymbol = TRUE;\n                import->Address = entry[ii].st_value;\n                import->Size = entry[ii].st_size;\n                import->TypeInfo = entry[ii].st_info;\n                import->OtherInfo = entry[ii].st_other;\n                import->SectionIndex = entry[ii].st_shndx;\n\n                // function name\n                PhCopyStringZFromBytes(\n                    PTR_ADD_OFFSET(stringTable, entry[ii].st_name),\n                    SIZE_MAX,\n                    import->Name,\n                    sizeof(import->Name),\n                    NULL\n                    );\n\n                // import library name\n                if (versionTable && versionRecords)\n                {\n                    PCSTR moduleName;\n\n                    if (moduleName = PhpFindWslImageVersionRecordName(versionRecords, versionTable[ii].vs_vers))\n                    {\n                        PhCopyStringZFromUtf8(\n                            moduleName,\n                            SIZE_MAX,\n                            import->Module,\n                            sizeof(import->Module),\n                            NULL\n                            );\n                    }\n                }\n\n                PhAddItemList(sectionSymbols, import);\n            }\n            else if (entry[ii].st_shndx != SHN_UNDEF && entry[ii].st_value != 0)\n            {\n                PPH_ELF_IMAGE_SYMBOL_ENTRY export;\n\n                if (ELF_ST_TYPE(entry[ii].st_info) == STT_SECTION) // Ignore section symbol types.\n                    continue;\n\n                export = PhAllocateZero(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY));\n                export->ExportSymbol = TRUE;\n                export->Address = entry[ii].st_value;\n                export->Size = entry[ii].st_size;\n                export->TypeInfo = entry[ii].st_info;\n                export->OtherInfo = entry[ii].st_other;\n                export->SectionIndex = entry[ii].st_shndx;\n\n                // function name\n                PhCopyStringZFromUtf8(\n                    PTR_ADD_OFFSET(stringTable, entry[ii].st_name),\n                    SIZE_MAX,\n                    export->Name,\n                    sizeof(export->Name),\n                    NULL\n                    );\n\n                PhAddItemList(sectionSymbols, export);\n            }\n            else\n            {\n                PPH_ELF_IMAGE_SYMBOL_ENTRY export;\n\n                export = PhAllocateZero(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY));\n                export->UnknownSymbol = TRUE;\n                export->Address = entry[ii].st_value;\n                export->Size = entry[ii].st_size;\n                export->TypeInfo = entry[ii].st_info;\n                export->OtherInfo = entry[ii].st_other;\n                export->SectionIndex = entry[ii].st_shndx;\n\n                // function name\n                PhCopyStringZFromUtf8(\n                    PTR_ADD_OFFSET(stringTable, entry[ii].st_name),\n                    SIZE_MAX,\n                    export->Name,\n                    sizeof(export->Name),\n                    NULL\n                    );\n\n                PhAddItemList(sectionSymbols, export);\n            }\n        }\n\n        if (versionRecords)\n            PhpFreeMappedWslImageVersionRecords(versionRecords);\n    }\n\n    *ImageSymbols = sectionSymbols;\n\n    return TRUE;\n}\n\nVOID PhFreeMappedWslImageSymbols(\n    _In_ PPH_LIST ImageSymbols\n    )\n{\n    for (ULONG i = 0; i < ImageSymbols->Count; i++)\n        PhFree(ImageSymbols->Items[i]);\n\n    PhDereferenceObject(ImageSymbols);\n}\n\nBOOLEAN PhGetMappedWslImageDynamic(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ PPH_LIST *ImageDynamic\n    )\n{\n    PELF64_IMAGE_SECTION_HEADER sectionHeader;\n    PELF64_IMAGE_SECTION_HEADER section;\n    PPH_LIST dynamicSymbols;\n    USHORT i;\n\n    dynamicSymbols = PhCreateList(0x40);\n    sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++)\n    {\n        ULONGLONG count;\n        ULONGLONG ii;\n        PELF64_IMAGE_DYNAMIC_ENTRY entry;\n        PVOID stringTable;\n\n        section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i);\n\n        if (section->sh_type != SHT_DYNAMIC)\n            continue;\n\n        if (section->sh_entsize != sizeof(ELF64_IMAGE_DYNAMIC_ENTRY))\n            return FALSE;\n\n        count = section->sh_size / sizeof(ELF64_IMAGE_DYNAMIC_ENTRY);\n        entry = PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset);\n        stringTable = PhGetMappedWslImageSectionData(MappedWslImage, NULL, section->sh_link);\n\n        for (ii = 0; ii < count; ii++)\n        {\n            PPH_ELF_IMAGE_DYNAMIC_ENTRY dynamic;\n\n            dynamic = PhAllocateZero(sizeof(PH_ELF_IMAGE_DYNAMIC_ENTRY));\n            dynamic->Tag = entry[ii].d_tag;\n\n            switch (dynamic->Tag)\n            {\n            case DT_NEEDED:\n            case DT_SONAME:\n            case DT_RPATH:\n            case DT_RUNPATH:\n                dynamic->Value = PhConvertUtf8ToUtf16(PTR_ADD_OFFSET(stringTable, entry[ii].d_val));\n                break;\n            case DT_PLTRELSZ:\n            case DT_RELASZ:\n            case DT_RELAENT:\n            case DT_STRSZ:\n            case DT_SYMENT:\n            case DT_RELSZ:\n            case DT_RELENT:\n            case DT_INIT_ARRAYSZ:\n            case DT_FINI_ARRAYSZ:\n            case DT_PREINIT_ARRAYSZ:\n                dynamic->Value = PhFormatSize(entry[ii].d_val, ULONG_MAX);\n                break;\n            case DT_RELACOUNT:\n            case DT_RELCOUNT:\n            case DT_VERDEFNUM:\n            case DT_VERNEEDNUM:\n                dynamic->Value = PhFormatUInt64(entry[ii].d_val, TRUE);\n                break;\n            default:\n                dynamic->Value = PhFormatString(L\"0x%llx\", entry[ii].d_val);\n                break;\n            }\n\n            PhAddItemList(dynamicSymbols, dynamic);\n\n            if (entry[ii].d_tag == DT_NULL)\n                break;\n        }\n    }\n\n    *ImageDynamic = dynamicSymbols;\n\n    return TRUE;\n}\n\nVOID PhFreeMappedWslImageDynamic(\n    _In_ PPH_LIST ImageDynamic\n    )\n{\n    for (ULONG i = 0; i < ImageDynamic->Count; i++)\n    {\n        PPH_ELF_IMAGE_DYNAMIC_ENTRY dynamic = ImageDynamic->Items[i];\n\n        PhDereferenceObject(dynamic->Value);\n        PhFree(dynamic);\n    }\n\n    PhDereferenceObject(ImageDynamic);\n}\n"
  },
  {
    "path": "phlib/mapimg.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2017-2023\n *     jxy-s   2023\n *\n */\n\n#include <ph.h>\n#include <mapimg.h>\n\n/**\n * Initializes a mapped PE image structure from a memory view.\n *\n * \\param MappedImage A pointer to a structure that receives the mapped image information.\n * \\param ViewBase The base address of the mapped view containing the PE image.\n * \\param ViewSize The size of the mapped view in bytes.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function validates the DOS and NT headers, verifies signatures, and initializes\n * the MappedImage structure with pointers to key PE structures. All memory accesses are\n * protected with structured exception handling.\n */\nNTSTATUS PhInitializeMappedImage(\n    _Out_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T ViewSize\n    )\n{\n    PIMAGE_DOS_HEADER dosHeader;\n    PIMAGE_NT_HEADERS ntHeaders;\n    ULONG_PTR dosHeaderOffset;\n    ULONG_PTR ntHeadersOffset;\n\n    memset(MappedImage, 0, sizeof(PH_MAPPED_IMAGE));\n    MappedImage->ViewBase = ViewBase;\n    MappedImage->ViewSize = ViewSize;\n\n    if (ViewSize < sizeof(IMAGE_DOS_HEADER))\n        return STATUS_INVALID_VIEW_SIZE;\n\n    // Get a pointer to the base address and probe it.\n\n    dosHeaderOffset = (ULONG_PTR)ViewBase;\n\n    if (dosHeaderOffset == 0 || dosHeaderOffset == SIZE_MAX)\n        return STATUS_INVALID_PARAMETER;\n\n    // Get a pointer to the dos headers and probe it.\n\n    dosHeader = (PIMAGE_DOS_HEADER)dosHeaderOffset;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, dosHeader, sizeof(IMAGE_DOS_HEADER));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    MappedImage->Signature = dosHeader->e_magic;\n\n    // Check the initial MZ.\n\n    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)\n        return STATUS_INVALID_IMAGE_NOT_MZ;\n\n    // Get a pointer to the nt headers and probe it.\n\n    ntHeadersOffset = (ULONG_PTR)dosHeader->e_lfanew;\n\n    if (ntHeadersOffset >= ViewSize || ntHeadersOffset >= RTL_IMAGE_MAX_DOS_HEADER)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    // Get a pointer to the optional headers and probe it.\n\n    ntHeaders = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(dosHeader, ntHeadersOffset);\n\n    __try\n    {\n        PhMappedImageProbe(\n            MappedImage,\n            ntHeaders,\n            UFIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader)\n            );\n        PhMappedImageProbe(\n            MappedImage,\n            ntHeaders,\n            UFIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +\n            ntHeaders->FileHeader.SizeOfOptionalHeader +\n            ntHeaders->FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER\n            );\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // Check the signature and verify the magic.\n\n    if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    if (\n        ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC &&\n        ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC\n        )\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    // Get a pointer to the first section.\n\n    MappedImage->NtHeaders = ntHeaders;\n    MappedImage->Magic = ntHeaders->OptionalHeader.Magic;\n    MappedImage->NumberOfSections = ntHeaders->FileHeader.NumberOfSections;\n    MappedImage->Sections = IMAGE_FIRST_SECTION(ntHeaders);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Loads a PE image file into memory and initializes a mapped image structure.\n *\n * \\param FileName The path to the PE image file. Specify NULL to use FileHandle.\n * \\param FileHandle A handle to an open file. Specify NULL to use FileName.\n * \\param MappedImage A pointer to a structure that receives the mapped image information.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The entire file is mapped into memory using a section object. The caller must\n * call PhUnloadMappedImage() to release resources when finished.\n */\nNTSTATUS PhLoadMappedImage(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PVOID viewBase;\n    SIZE_T viewSize;\n\n    status = PhMapViewOfEntireFile(\n        FileName,\n        FileHandle,\n        &viewBase,\n        &viewSize\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhInitializeMappedImage(\n            MappedImage,\n            viewBase,\n            viewSize\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            PhUnloadMappedImage(MappedImage);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Loads an image file into memory and initializes a mapped image structure, with support for\n * multiple image formats (PE and ELF).\n *\n * \\param FileName The path to the image file as a string reference. Specify NULL to use FileHandle.\n * \\param FileHandle A handle to an open file. Specify NULL to use FileName.\n * \\param MappedImage A pointer to a structure that receives the mapped image information.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT The image format is not recognized.\n * \\remarks This function detects the image type based on the signature and initializes it\n * appropriately. Supported formats include PE (IMAGE_DOS_SIGNATURE) and ELF (IMAGE_ELF_SIGNATURE).\n */\nNTSTATUS PhLoadMappedImageEx(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PVOID viewBase;\n    SIZE_T viewSize;\n\n    status = PhMapViewOfEntireFileEx(\n        FileName,\n        FileHandle,\n        &viewBase,\n        &viewSize\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        MappedImage->Signature = *(PUSHORT)viewBase;\n        MappedImage->ViewBase = viewBase;\n        MappedImage->ViewSize = viewSize;\n        MappedImage->Flags = 0;\n        MappedImage->Spare = 0;\n\n        switch (MappedImage->Signature)\n        {\n        case IMAGE_DOS_SIGNATURE:\n            {\n                status = PhInitializeMappedImage(\n                    MappedImage,\n                    viewBase,\n                    viewSize\n                    );\n            }\n            break;\n        case IMAGE_ELF_SIGNATURE:\n            {\n                status = PhInitializeMappedWslImage(\n                    MappedImage,\n                    viewBase,\n                    viewSize\n                    );\n            }\n            break;\n        default:\n            status = STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhUnloadMappedImage(MappedImage);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhLoadMappedImageNoExecute(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    BOOLEAN openedFile = FALSE;\n    HANDLE sectionHandle;\n    PVOID viewBase;\n    SIZE_T viewSize;\n\n    if (!FileName && !FileHandle)\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    if (!FileHandle)\n    {\n        status = PhCreateFile(\n            &FileHandle,\n            FileName,\n            FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_EXECUTE | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        openedFile = TRUE;\n    }\n\n    status = PhCreateSection(\n        &sectionHandle,\n        SECTION_QUERY | SECTION_MAP_READ,\n        NULL,\n        PAGE_READONLY,\n        SEC_IMAGE_NO_EXECUTE,\n        FileHandle\n        );\n\n    if (openedFile)\n        NtClose(FileHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    viewBase = NULL;\n    viewSize = 0;\n\n    status = PhMapViewOfSection(\n        sectionHandle,\n        NtCurrentProcess(),\n        &viewBase,\n        0,\n        NULL,\n        &viewSize,\n        ViewUnmap,\n        WindowsVersion < WINDOWS_10_RS2 ? 0 : MEM_MAPPED,\n        PAGE_READONLY\n        );\n\n    NtClose(sectionHandle);\n\n    if (status == STATUS_IMAGE_NOT_AT_BASE)\n        status = STATUS_SUCCESS;\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhInitializeMappedImage(\n        MappedImage,\n        viewBase,\n        viewSize\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        MappedImage->Flags |= PH_MAPPED_IMAGE_FLAG_SEC_IMAGE;\n    }\n    else\n    {\n        PhUnloadMappedImage(MappedImage);\n    }\n\n    return status;\n}\n\nNTSTATUS PhLoadMappedImageHeaderPageSize(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    BOOLEAN openedFile = FALSE;\n    LARGE_INTEGER sectionSize;\n    HANDLE sectionHandle;\n    SIZE_T viewSize;\n    PVOID viewBase;\n\n    if (!FileName && !FileHandle)\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    if (!FileHandle)\n    {\n        status = PhCreateFile(\n            &FileHandle,\n            FileName,\n            FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        openedFile = TRUE;\n    }\n\n    sectionSize.QuadPart = PAGE_SIZE;\n\n    status = PhCreateSection(\n        &sectionHandle,\n        SECTION_QUERY | SECTION_MAP_READ,\n        &sectionSize,\n        PAGE_READONLY,\n        SEC_COMMIT,\n        FileHandle\n        );\n\n    if (openedFile)\n        NtClose(FileHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    viewSize = PAGE_SIZE;\n    viewBase = NULL;\n\n    status = PhMapViewOfSection(\n        sectionHandle,\n        NtCurrentProcess(),\n        &viewBase,\n        0,\n        NULL,\n        &viewSize,\n        ViewUnmap,\n        0,\n        PAGE_READONLY\n        );\n\n    NtClose(sectionHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhInitializeMappedImage(\n        MappedImage,\n        viewBase,\n        viewSize\n        );\n\n    return status;\n}\n\n/**\n * Releases resources associated with a mapped image.\n *\n * \\param MappedImage A pointer to the mapped image structure to unload.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function unmaps the view and releases associated memory. The MappedImage\n * structure should not be used after this function is called.\n */\nNTSTATUS PhUnloadMappedImage(\n    _Inout_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    if (MappedImage->ViewBase)\n    {\n        PhUnmapViewOfSection(NtCurrentProcess(), MappedImage->ViewBase);\n        MappedImage->ViewBase = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Loads only the header portion of a PE image file into memory.\n *\n * \\param FileName The path to the PE image file as a string reference. Specify NULL to use FileHandle.\n * \\param FileHandle A handle to an open file. Specify NULL to use FileName.\n * \\param MappedImage A pointer to a structure that receives the mapped image header information.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function reads only the first page (4KB) of the file, which contains the DOS\n * and NT headers. This is more efficient than mapping the entire file when only header\n * information is needed. Call PhUnloadMappedImageHeaderFromFile() to release resources.\n */\nNTSTATUS PhLoadMappedImageHeaderFromFile(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    BOOLEAN openedFile = FALSE;\n    PVOID viewBase;\n    LARGE_INTEGER byteOffset;\n    ULONG bytesRead;\n\n    if (!FileName && !FileHandle)\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    if (!FileHandle)\n    {\n        status = PhCreateFile(\n            &FileHandle,\n            FileName,\n            FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        openedFile = TRUE;\n    }\n\n    viewBase = PhAllocatePageZero(PAGE_SIZE);\n\n    if (!viewBase)\n    {\n        if (openedFile)\n            NtClose(FileHandle);\n\n        return STATUS_NO_MEMORY;\n    }\n\n    byteOffset.QuadPart = 0;\n    bytesRead = 0;\n\n    status = PhReadFile(\n        FileHandle,\n        viewBase,\n        PAGE_SIZE,\n        &byteOffset,\n        &bytesRead\n        );\n\n    if (status == STATUS_END_OF_FILE && bytesRead > 0)\n        status = STATUS_SUCCESS;\n\n    if (openedFile)\n        NtClose(FileHandle);\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFreePage(viewBase);\n        return status;\n    }\n\n    status = PhInitializeMappedImage(\n        MappedImage,\n        viewBase,\n        PAGE_SIZE\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhUnloadMappedImageHeaderFromFile(MappedImage);\n    }\n\n    return status;\n}\n\n/**\n * Releases resources associated with a mapped image header loaded from a file.\n *\n * \\param MappedImage A pointer to the mapped image header structure to unload.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhUnloadMappedImageHeaderFromFile(\n    _Inout_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    if (MappedImage->ViewBase)\n    {\n        PhFreePage(MappedImage->ViewBase);\n        MappedImage->ViewBase = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Maps an entire file into memory using a section object.\n *\n * \\param FileName The path to the file. Specify NULL to use FileHandle.\n * \\param FileHandle A handle to an open file. Specify NULL to use FileName.\n * \\param ViewBase A pointer that receives the base address of the mapped view.\n * \\param ViewSize A pointer that receives the size of the mapped view.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The file is mapped read-only. The caller must unmap the view using\n * PhUnmapViewOfSection() when finished.\n */\nNTSTATUS PhMapViewOfEntireFile(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PVOID *ViewBase,\n    _Out_ PSIZE_T ViewSize\n    )\n{\n    NTSTATUS status;\n    BOOLEAN openedFile = FALSE;\n    LARGE_INTEGER sectionSize;\n    HANDLE sectionHandle;\n    SIZE_T viewSize;\n    PVOID viewBase;\n\n    if (!FileName && !FileHandle)\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    // Open the file if we weren't supplied a file handle.\n    if (!FileHandle)\n    {\n        status = PhCreateFileWin32(\n            &FileHandle,\n            FileName,\n            FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        openedFile = TRUE;\n    }\n\n    // Get the file size and create the section.\n\n    status = PhGetFileSize(FileHandle, &sectionSize);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreateSection(\n        &sectionHandle,\n        SECTION_QUERY | SECTION_MAP_READ,\n        &sectionSize,\n        PAGE_READONLY,\n        SEC_COMMIT,\n        FileHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Map the section.\n\n    viewSize = (SIZE_T)sectionSize.QuadPart;\n    viewBase = NULL;\n\n    status = PhMapViewOfSection(\n        sectionHandle,\n        NtCurrentProcess(),\n        &viewBase,\n        0,\n        NULL,\n        &viewSize,\n        ViewUnmap,\n        0,\n        PAGE_READONLY\n        );\n\n    NtClose(sectionHandle);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    *ViewBase = viewBase;\n    *ViewSize = (SIZE_T)sectionSize.QuadPart;\n\nCleanupExit:\n    if (openedFile)\n        NtClose(FileHandle);\n\n    return status;\n}\n\nNTSTATUS PhMapViewOfEntireFileEx(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PVOID *ViewBase,\n    _Out_ PSIZE_T ViewSize\n    )\n{\n    NTSTATUS status;\n    BOOLEAN openedFile = FALSE;\n    LARGE_INTEGER sectionSize;\n    HANDLE sectionHandle;\n    SIZE_T viewSize;\n    PVOID viewBase;\n\n    if (!FileName && !FileHandle)\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    // Open the file if we weren't supplied a file handle.\n    if (!FileHandle)\n    {\n        status = PhCreateFile(\n            &FileHandle,\n            FileName,\n            FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        openedFile = TRUE;\n    }\n\n    // Get the file size and create the section.\n\n    status = PhGetFileSize(FileHandle, &sectionSize);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreateSection(\n        &sectionHandle,\n        SECTION_QUERY | SECTION_MAP_READ,\n        &sectionSize,\n        PAGE_READONLY,\n        SEC_COMMIT,\n        FileHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    viewSize = (SIZE_T)sectionSize.QuadPart;\n    viewBase = NULL;\n\n    // Map the section.\n\n    status = PhMapViewOfSection(\n        sectionHandle,\n        NtCurrentProcess(),\n        &viewBase,\n        0,\n        NULL,\n        &viewSize,\n        ViewUnmap,\n        0,\n        PAGE_READONLY\n        );\n\n    NtClose(sectionHandle);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    *ViewBase = viewBase;\n    *ViewSize = (SIZE_T)sectionSize.QuadPart;\n\nCleanupExit:\n    if (openedFile)\n        NtClose(FileHandle);\n\n    return status;\n}\n\nVOID PhMappedImagePrefetch(\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    MEMORY_RANGE_ENTRY prefetchMemoryRange[1];\n\n    memset(prefetchMemoryRange, 0, sizeof(prefetchMemoryRange));\n    prefetchMemoryRange[0].NumberOfBytes = MappedImage->ViewSize;\n    prefetchMemoryRange[0].VirtualAddress = MappedImage->ViewBase;\n\n    PhPrefetchVirtualMemory(NtCurrentProcess(), RTL_NUMBER_OF(prefetchMemoryRange), prefetchMemoryRange);\n}\n\n/**\n * Retrieves a section header by name from a mapped image.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Name The name of the section to find (e.g., \".text\", \".data\").\n * \\param IgnoreCase TRUE to perform a case-insensitive comparison, FALSE for case-sensitive.\n * \\return A pointer to the section header if found, otherwise NULL.\n */\nPIMAGE_SECTION_HEADER PhMappedImageSectionByName(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PCWSTR Name,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    for (USHORT i = 0; i < MappedImage->NumberOfSections; i++)\n    {\n        WCHAR sectionName[IMAGE_SIZEOF_SHORT_NAME + 1];\n\n        if (NT_SUCCESS(PhGetMappedImageSectionName(\n            &MappedImage->Sections[i],\n            sectionName,\n            RTL_NUMBER_OF(sectionName),\n            NULL\n            )) && PhEqualStringZ(sectionName, Name, IgnoreCase))\n        {\n            return &MappedImage->Sections[i];\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Locates the section that contains a given relative virtual address (RVA).\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Rva The relative virtual address to locate.\n * \\return A pointer to the section header containing the RVA, otherwise NULL.\n */\nPIMAGE_SECTION_HEADER PhMappedImageRvaToSection(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Rva\n    )\n{\n    for (USHORT i = 0; i < MappedImage->NumberOfSections; i++)\n    {\n        ULONG sectionSize;\n\n        if (FlagOn(MappedImage->Flags, PH_MAPPED_IMAGE_FLAG_SEC_IMAGE))\n            sectionSize = MappedImage->Sections[i].Misc.VirtualSize;\n        else\n            sectionSize = MappedImage->Sections[i].SizeOfRawData;\n\n        if (\n            (Rva >= MappedImage->Sections[i].VirtualAddress) &&\n            (Rva < MappedImage->Sections[i].VirtualAddress + sectionSize)\n            )\n        {\n            return &MappedImage->Sections[i];\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Converts a relative virtual address (RVA) to a virtual address within the mapped image.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Rva The relative virtual address to convert.\n * \\param Section An optional pointer that receives the section header containing the RVA.\n * \\return A pointer to the virtual address in the mapped view, otherwise NULL.\n * \\remarks This function handles both memory-mapped images (SEC_IMAGE) and file-mapped images (SEC_COMMIT),\n * adjusting for section alignment differences.\n */\n_Success_(return != NULL)\nPVOID PhMappedImageRvaToVa(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Rva,\n    _Out_opt_ PIMAGE_SECTION_HEADER *Section\n    )\n{\n    PIMAGE_SECTION_HEADER section;\n\n    if (Rva == 0)\n        return NULL;\n\n    section = PhMappedImageRvaToSection(MappedImage, Rva);\n\n    if (!section)\n        return NULL;\n\n    if (Section)\n        *Section = section;\n\n    if (FlagOn(MappedImage->Flags, PH_MAPPED_IMAGE_FLAG_SEC_IMAGE))\n        return PTR_ADD_OFFSET(MappedImage->ViewBase, Rva);\n\n    return PTR_ADD_OFFSET(MappedImage->ViewBase, PTR_ADD_OFFSET(\n        PTR_SUB_OFFSET(Rva, section->VirtualAddress),\n        section->PointerToRawData\n        ));\n}\n\n/**\n * Converts a virtual address (VA) to a pointer within the mapped image.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Va The virtual address to convert.\n * \\param Section An optional pointer that receives the section header containing the address.\n * \\return A pointer to the address in the mapped view, otherwise NULL.\n */\n_Success_(return != NULL)\nPVOID PhMappedImageVaToVa(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONGLONG Va,\n    _Out_opt_ PIMAGE_SECTION_HEADER *Section\n    )\n{\n    ULONG rva;\n    PIMAGE_SECTION_HEADER section;\n\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        rva = PtrToUlong(PTR_SUB_OFFSET(Va, MappedImage->NtHeaders32->OptionalHeader.ImageBase));\n    }\n    else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        rva = PtrToUlong(PTR_SUB_OFFSET(Va, MappedImage->NtHeaders->OptionalHeader.ImageBase));\n    }\n    else\n    {\n        return NULL;\n    }\n\n    section = PhMappedImageRvaToSection(MappedImage, rva);\n\n    if (!section)\n        return NULL;\n\n    if (Section)\n        *Section = section;\n\n    if (FlagOn(MappedImage->Flags, PH_MAPPED_IMAGE_FLAG_SEC_IMAGE))\n        return PTR_ADD_OFFSET(MappedImage->ViewBase, rva);\n\n    return PTR_ADD_OFFSET(MappedImage->ViewBase, PTR_ADD_OFFSET(\n        PTR_SUB_OFFSET(rva, section->VirtualAddress),\n        section->PointerToRawData\n        ));\n}\n\n_Success_(return != NULL)\nPVOID PhMappedImageRvaToFileOffset(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Rva,\n    _Out_opt_ PIMAGE_SECTION_HEADER *Section\n    )\n{\n    PIMAGE_SECTION_HEADER section;\n\n    if (Rva == 0)\n        return NULL;\n\n    section = PhMappedImageRvaToSection(MappedImage, Rva);\n\n    if (!section)\n        return NULL;\n\n    if (Section)\n        *Section = section;\n\n    if (FlagOn(MappedImage->Flags, PH_MAPPED_IMAGE_FLAG_SEC_IMAGE))\n        return PTR_ADD_OFFSET(MappedImage->ViewBase, Rva);\n\n    return PTR_ADD_OFFSET(\n        PTR_SUB_OFFSET(Rva, section->VirtualAddress),\n        section->PointerToRawData\n        );\n}\n\n/**\n * Retrieves the name of a PE section as a Unicode string.\n *\n * \\param Section A pointer to the section header.\n * \\param Buffer An optional buffer that receives the section name.\n * \\param Count The size of the buffer in characters.\n * \\param ReturnCount An optional pointer that receives the number of characters written.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetMappedImageSectionName(\n    _In_ PIMAGE_SECTION_HEADER Section,\n    _Out_writes_opt_z_(Count) PWSTR Buffer,\n    _In_ ULONG Count,\n    _Out_opt_ PULONG ReturnCount\n    )\n{\n    NTSTATUS status;\n    SIZE_T returnCount = 0;\n\n    status = PhCopyStringZFromUtf8(\n        (PCSTR)Section->Name,\n        IMAGE_SIZEOF_SHORT_NAME,\n        Buffer,\n        Count,\n        &returnCount\n        );\n\n    if (ReturnCount)\n        *ReturnCount = (ULONG)returnCount;\n\n    return status;\n}\n\n/**\n * Retrieves a data directory from the PE optional header.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Index The data directory index (e.g., IMAGE_DIRECTORY_ENTRY_EXPORT).\n * \\param Entry A pointer that receives the data directory structure.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Data directories contain RVAs and sizes for various PE structures such as\n * exports, imports, resources, base relocations, and debug information.\n */\nNTSTATUS PhGetMappedImageDataDirectory(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Index,\n    _Out_ PIMAGE_DATA_DIRECTORY *Entry\n    )\n{\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_OPTIONAL_HEADER32 optionalHeader;\n        PIMAGE_DATA_DIRECTORY dataDirectory;\n\n        optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&MappedImage->NtHeaders32->OptionalHeader;\n\n        if (Index >= optionalHeader->NumberOfRvaAndSizes)\n            return STATUS_INVALID_PARAMETER_2;\n\n        dataDirectory = &optionalHeader->DataDirectory[Index];\n\n        if (dataDirectory->VirtualAddress && dataDirectory->Size)\n        {\n            *Entry = dataDirectory;\n            return STATUS_SUCCESS;\n        }\n    }\n    else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        PIMAGE_OPTIONAL_HEADER64 optionalHeader;\n        PIMAGE_DATA_DIRECTORY dataDirectory;\n\n        optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&MappedImage->NtHeaders->OptionalHeader;\n\n        if (Index >= optionalHeader->NumberOfRvaAndSizes)\n            return STATUS_INVALID_PARAMETER_2;\n\n        dataDirectory = &optionalHeader->DataDirectory[Index];\n\n        if (dataDirectory->VirtualAddress && dataDirectory->Size)\n        {\n            *Entry = dataDirectory;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return STATUS_NOT_FOUND;\n}\n\nPVOID PhGetMappedImageDirectoryEntry(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Index\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        Index,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    return PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n}\n\nFORCEINLINE NTSTATUS PhpGetMappedImageLoadConfig(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ USHORT Magic,\n    _In_ ULONG ProbeLength,\n    _Out_ PVOID *LoadConfig\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY entry;\n    PVOID loadConfig;\n\n    if (MappedImage->Magic != Magic)\n        return STATUS_INVALID_PARAMETER;\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,\n        &entry\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    loadConfig = PhMappedImageRvaToVa(\n        MappedImage,\n        entry->VirtualAddress,\n        NULL\n        );\n\n    if (!loadConfig)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, loadConfig, ProbeLength);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    *LoadConfig = loadConfig;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageLoadConfig32(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY32 *LoadConfig\n    )\n{\n    return PhpGetMappedImageLoadConfig(\n        MappedImage,\n        IMAGE_NT_OPTIONAL_HDR32_MAGIC,\n        sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32),\n        LoadConfig\n        );\n}\n\nNTSTATUS PhGetMappedImageLoadConfig64(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY64 *LoadConfig\n    )\n{\n    return PhpGetMappedImageLoadConfig(\n        MappedImage,\n        IMAGE_NT_OPTIONAL_HDR64_MAGIC,\n        sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64),\n        LoadConfig\n        );\n}\n\n// Remote mapped image routines\n\nNTSTATUS PhInitializeRemoteMappedImage(\n    _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_opt_ PPH_READ_VIRTUAL_MEMORY_CALLBACK ReadVirtualMemoryCallback,\n    _In_opt_ PVOID Context\n    )\n{\n    memset(RemoteMappedImage, 0, sizeof(PH_REMOTE_MAPPED_IMAGE));\n    RemoteMappedImage->ReadVirtualMemoryCallback = ReadVirtualMemoryCallback;\n    RemoteMappedImage->Context = Context;\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhLoadRemoteMappedImagePageSize(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T ViewSize\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DOS_HEADER dosHeader;\n    PIMAGE_NT_HEADERS ntHeaders;\n    ULONG_PTR dosHeaderOffset;\n    ULONG_PTR ntHeadersOffset;\n    SIZE_T ntHeadersSize;\n\n    RemoteMappedImage->ViewBase = ViewBase;\n    RemoteMappedImage->ViewSize = ViewSize;\n\n    if (ViewSize < PAGE_SIZE)\n        return STATUS_INSUFFICIENT_RESOURCES;\n\n    // Get a pointer to the base address and probe it.\n\n    dosHeaderOffset = (ULONG_PTR)ViewBase;\n\n    if (dosHeaderOffset == 0 || dosHeaderOffset == SIZE_MAX)\n        return STATUS_INVALID_PARAMETER;\n\n    // Read one page and validate both headers.\n\n    dosHeader = PhAllocatePageZero(PAGE_SIZE);\n\n    if (!dosHeader)\n    {\n        return STATUS_NO_MEMORY;\n    }\n\n    if (RemoteMappedImage->ReadVirtualMemoryCallback)\n    {\n        status = RemoteMappedImage->ReadVirtualMemoryCallback(\n            ProcessHandle,\n            ViewBase,\n            dosHeader,\n            PAGE_SIZE,\n            NULL,\n            RemoteMappedImage->Context\n            );\n    }\n    else\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            ViewBase,\n            dosHeader,\n            PAGE_SIZE,\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Check the initial MZ.\n\n    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)\n    {\n        status = STATUS_INVALID_IMAGE_NOT_MZ;\n        goto CleanupExit;\n    }\n\n    // Get a pointer to the IMAGE_NT_HEADERS and probe it.\n\n    ntHeadersOffset = (ULONG_PTR)dosHeader->e_lfanew;\n\n    if (ntHeadersOffset == 0 || ntHeadersOffset >= ViewSize || ntHeadersOffset >= RTL_IMAGE_MAX_DOS_HEADER)\n    {\n        status = STATUS_INVALID_IMAGE_NOT_MZ;\n        goto CleanupExit;\n    }\n\n    if (ntHeadersOffset + sizeof(IMAGE_NT_HEADERS) >= PAGE_SIZE)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto CleanupExit;\n    }\n\n    ntHeaders = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(dosHeader, ntHeadersOffset);\n\n    // Check the signature and verify the magic.\n\n    if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)\n    {\n        status = STATUS_INVALID_IMAGE_FORMAT;\n        goto CleanupExit;\n    }\n\n    if (\n        ntHeaders->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER32) &&\n        ntHeaders->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64)\n        )\n    {\n        status = STATUS_BAD_FILE_TYPE;\n        goto CleanupExit;\n    }\n\n    RemoteMappedImage->Magic = ntHeaders->OptionalHeader.Magic;\n\n    if (\n        RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC &&\n        RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC\n        )\n    {\n        status = STATUS_INVALID_IMAGE_FORMAT;\n        goto CleanupExit;\n    }\n\n    RemoteMappedImage->NumberOfSections = ntHeaders->FileHeader.NumberOfSections;\n\n    if (RemoteMappedImage->NumberOfSections >= SCHAR_MAX)\n    {\n        status = STATUS_INVALID_IMAGE_FORMAT;\n        goto CleanupExit;\n    }\n\n    // Get the total size and verify in the whole thing.\n\n    ntHeadersSize = UFIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +\n        ntHeaders->FileHeader.SizeOfOptionalHeader +\n        RemoteMappedImage->NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER;\n\n    if (ntHeadersSize + ntHeadersOffset + sizeof(IMAGE_NT_HEADERS) >= PAGE_SIZE)\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto CleanupExit;\n    }\n\n    RemoteMappedImage->ProcessHandle = ProcessHandle;\n    RemoteMappedImage->NtHeaders = ntHeaders;\n    RemoteMappedImage->Sections = IMAGE_FIRST_SECTION(RemoteMappedImage->NtHeaders);\n    RemoteMappedImage->PageCache = dosHeader;\n\nCleanupExit:\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFreePage(dosHeader);\n    }\n\n    return status;\n}\n\nNTSTATUS PhLoadRemoteMappedImage(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T ViewSize\n    )\n{\n    NTSTATUS status;\n    IMAGE_DOS_HEADER dosHeader;\n    IMAGE_NT_HEADERS ntHeaders;\n    ULONG_PTR dosHeaderOffset;\n    ULONG_PTR ntHeadersOffset;\n    SIZE_T ntHeadersSize;\n\n    status = PhLoadRemoteMappedImagePageSize(\n        RemoteMappedImage,\n        ProcessHandle,\n        ViewBase,\n        ViewSize\n        );\n\n    if (NT_SUCCESS(status) || status != STATUS_INSUFFICIENT_RESOURCES)\n        return status;\n\n    RemoteMappedImage->ViewBase = ViewBase;\n    RemoteMappedImage->ViewSize = ViewSize;\n\n    if (ViewSize < sizeof(IMAGE_DOS_HEADER))\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    // Get a pointer to the base address and probe it.\n\n    dosHeaderOffset = (ULONG_PTR)ViewBase;\n\n    if (dosHeaderOffset == 0 || dosHeaderOffset == SIZE_MAX)\n        return STATUS_INVALID_PARAMETER;\n\n    if (RemoteMappedImage->ReadVirtualMemoryCallback)\n    {\n        status = RemoteMappedImage->ReadVirtualMemoryCallback(\n            ProcessHandle,\n            ViewBase,\n            &dosHeader,\n            sizeof(IMAGE_DOS_HEADER),\n            NULL,\n            RemoteMappedImage->Context\n            );\n    }\n    else\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            ViewBase,\n            &dosHeader,\n            sizeof(IMAGE_DOS_HEADER),\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Check the initial MZ.\n\n    if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE)\n        return STATUS_INVALID_IMAGE_NOT_MZ;\n\n    // Get a pointer to the IMAGE_NT_HEADERS and probe it.\n\n    ntHeadersOffset = (ULONG_PTR)dosHeader.e_lfanew;\n\n    if (ntHeadersOffset == 0 || ntHeadersOffset >= ViewSize || ntHeadersOffset >= RTL_IMAGE_MAX_DOS_HEADER)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    if (RemoteMappedImage->ReadVirtualMemoryCallback)\n    {\n        status = RemoteMappedImage->ReadVirtualMemoryCallback(\n            ProcessHandle,\n            PTR_ADD_OFFSET(ViewBase, ntHeadersOffset),\n            &ntHeaders,\n            sizeof(IMAGE_NT_HEADERS),\n            NULL,\n            RemoteMappedImage->Context\n            );\n    }\n    else\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(ViewBase, ntHeadersOffset),\n            &ntHeaders,\n            sizeof(IMAGE_NT_HEADERS),\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Check the signature and verify the magic.\n\n    if (ntHeaders.Signature != IMAGE_NT_SIGNATURE)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    if (\n        ntHeaders.FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER32) &&\n        ntHeaders.FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64)\n        )\n    {\n        return STATUS_BAD_FILE_TYPE;\n    }\n\n    RemoteMappedImage->Magic = ntHeaders.OptionalHeader.Magic;\n\n    if (\n        RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC &&\n        RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC\n        )\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    RemoteMappedImage->NumberOfSections = ntHeaders.FileHeader.NumberOfSections;\n\n    if (RemoteMappedImage->NumberOfSections >= SCHAR_MAX)\n    {\n        return STATUS_INVALID_IMAGE_FORMAT;\n    }\n\n    // Get the real size and read in the whole thing.\n\n    ntHeadersSize = UFIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +\n        ntHeaders.FileHeader.SizeOfOptionalHeader +\n        RemoteMappedImage->NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER;\n\n    if (ntHeadersSize > UInt32x32To64(1024, 1024)) // 1 MB\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    RemoteMappedImage->NtHeaders = PhAllocatePageZero(ntHeadersSize);\n\n    if (!RemoteMappedImage->NtHeaders)\n    {\n        return STATUS_NO_MEMORY;\n    }\n\n    if (RemoteMappedImage->ReadVirtualMemoryCallback)\n    {\n        status = RemoteMappedImage->ReadVirtualMemoryCallback(\n            ProcessHandle,\n            PTR_ADD_OFFSET(ViewBase, ntHeadersOffset),\n            RemoteMappedImage->NtHeaders,\n            ntHeadersSize,\n            NULL,\n            RemoteMappedImage->Context\n            );\n    }\n    else\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(ViewBase, ntHeadersOffset),\n            RemoteMappedImage->NtHeaders,\n            ntHeadersSize,\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFreePage(RemoteMappedImage->NtHeaders);\n        RemoteMappedImage->NtHeaders = NULL;\n        return status;\n    }\n\n    RemoteMappedImage->ProcessHandle = ProcessHandle;\n    RemoteMappedImage->Sections = IMAGE_FIRST_SECTION(RemoteMappedImage->NtHeaders);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhUnloadRemoteMappedImage(\n    _Inout_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage\n    )\n{\n    if (RemoteMappedImage->PageCache)\n    {\n        PhFreePage(RemoteMappedImage->PageCache);\n        RemoteMappedImage->PageCache = NULL;\n    }\n    else if (RemoteMappedImage->NtHeaders)\n    {\n        PhFreePage(RemoteMappedImage->NtHeaders);\n        RemoteMappedImage->NtHeaders = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetRemoteMappedImageDataEntry(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_ ULONG Index,\n    _Out_ PIMAGE_DATA_DIRECTORY* Entry\n    )\n{\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n\n    if (RemoteMappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_OPTIONAL_HEADER32 optionalHeader;\n\n        optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&RemoteMappedImage->NtHeaders32->OptionalHeader;\n\n        if (Index >= optionalHeader->NumberOfRvaAndSizes)\n            return STATUS_INVALID_PARAMETER_2;\n\n        dataDirectory = &optionalHeader->DataDirectory[Index];\n    }\n    else if (RemoteMappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        PIMAGE_OPTIONAL_HEADER64 optionalHeader;\n\n        optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&RemoteMappedImage->NtHeaders->OptionalHeader;\n\n        if (Index >= optionalHeader->NumberOfRvaAndSizes)\n            return STATUS_INVALID_PARAMETER_2;\n\n        dataDirectory = &optionalHeader->DataDirectory[Index];\n    }\n    else\n    {\n        return STATUS_INVALID_IMAGE_FORMAT;\n    }\n\n    if (!(dataDirectory->VirtualAddress && dataDirectory->Size))\n        return STATUS_UNSUCCESSFUL;\n\n    *Entry = dataDirectory;\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetRemoteMappedImageDirectoryEntry(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_ ULONG Index,\n    _Out_ PVOID* DataBuffer,\n    _Out_opt_ ULONG* DataLength\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PVOID dataBuffer;\n    ULONG dataLength;\n\n    status = PhGetRemoteMappedImageDataEntry(\n        RemoteMappedImage,\n        Index,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (dataDirectory->Size > 16 * 1024 * 1024) // 16 MB\n        return STATUS_FAIL_CHECK;\n\n    dataLength = dataDirectory->Size;\n    dataBuffer = PhAllocatePageZero(dataLength);\n\n    if (!dataBuffer)\n        return STATUS_NO_MEMORY;\n\n    if (RemoteMappedImage->ReadVirtualMemoryCallback)\n    {\n        status = RemoteMappedImage->ReadVirtualMemoryCallback(\n            RemoteMappedImage->ProcessHandle,\n            PTR_ADD_OFFSET(RemoteMappedImage->ViewBase, dataDirectory->VirtualAddress),\n            dataBuffer,\n            dataLength,\n            NULL,\n            RemoteMappedImage->Context\n            );\n    }\n    else\n    {\n        status = PhReadVirtualMemory(\n            RemoteMappedImage->ProcessHandle,\n            PTR_ADD_OFFSET(RemoteMappedImage->ViewBase, dataDirectory->VirtualAddress),\n            dataBuffer,\n            dataLength,\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFreePage(dataBuffer);\n        return status;\n    }\n\n    if (DataBuffer)\n        *DataBuffer = dataBuffer;\n    if (DataLength)\n        *DataLength = dataLength;\n\n    return status;\n}\n\nNTSTATUS PhGetRemoteMappedImageDebugEntryByType(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _In_ ULONG Type,\n    _Out_opt_ PULONG DataLength,\n    _Out_ PPVOID DataBuffer\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DEBUG_DIRECTORY debugDirectory;\n    ULONG debugDirectoryLength;\n\n    status = PhGetRemoteMappedImageDirectoryEntry(\n        RemoteMappedImage,\n        IMAGE_DIRECTORY_ENTRY_DEBUG,\n        &debugDirectory,\n        &debugDirectoryLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = STATUS_NOT_FOUND;\n\n    for (ULONG i = 0; i < debugDirectoryLength / sizeof(IMAGE_DEBUG_DIRECTORY); i++)\n    {\n        PIMAGE_DEBUG_DIRECTORY entry = PTR_ADD_OFFSET(debugDirectory, UInt32x32To64(i, sizeof(IMAGE_DEBUG_DIRECTORY)));\n\n        if (entry->Type == Type)\n        {\n            PVOID dataBuffer;\n            ULONG dataLength;\n\n            if (entry->SizeOfData > 16 * 1024 * 1024) // 16 MB\n            {\n                status = STATUS_FAIL_CHECK;\n                break;\n            }\n\n            dataLength = entry->SizeOfData;\n            dataBuffer = PhAllocatePageZero(dataLength);\n\n            if (!dataBuffer)\n            {\n                status = STATUS_INSUFFICIENT_RESOURCES;\n                break;\n            }\n\n            if (RemoteMappedImage->ReadVirtualMemoryCallback)\n            {\n                status = RemoteMappedImage->ReadVirtualMemoryCallback(\n                    RemoteMappedImage->ProcessHandle,\n                    PTR_ADD_OFFSET(RemoteMappedImage->ViewBase, entry->AddressOfRawData),\n                    dataBuffer,\n                    dataLength,\n                    NULL,\n                    RemoteMappedImage->Context\n                    );\n            }\n            else\n            {\n                status = PhReadVirtualMemory(\n                    RemoteMappedImage->ProcessHandle,\n                    PTR_ADD_OFFSET(RemoteMappedImage->ViewBase, entry->AddressOfRawData),\n                    dataBuffer,\n                    dataLength,\n                    NULL\n                    );\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                if (DataLength)\n                    *DataLength = dataLength;\n\n                *DataBuffer = dataBuffer;\n\n                status = STATUS_SUCCESS;\n            }\n            else\n            {\n                PhFreePage(dataBuffer);\n            }\n\n            break;\n        }\n    }\n\n    PhFreePage(debugDirectory);\n\n    return status;\n}\n\nNTSTATUS PhGetRemoteMappedImageGuardFlags(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _Out_ PULONG GuardFlags\n    )\n{\n    NTSTATUS status;\n    ULONG guardFlags = ULONG_MAX;\n\n    if (RemoteMappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY32 config32 = NULL;\n        ULONG config32Length = 0;\n\n        status = PhGetRemoteMappedImageDirectoryEntry(\n            RemoteMappedImage,\n            IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,\n            &config32,\n            &config32Length\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (RTL_CONTAINS_FIELD(config32, min(config32->Size, config32Length), GuardFlags))\n            {\n                guardFlags = config32->GuardFlags;\n            }\n            else\n            {\n                status = STATUS_NOT_FOUND;\n            }\n\n            PhFreePage(config32);\n        }\n    }\n    else\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY64 config64 = NULL;\n        ULONG config64Length = 0;\n\n        status = PhGetRemoteMappedImageDirectoryEntry(\n            RemoteMappedImage,\n            IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,\n            &config64,\n            &config64Length\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (RTL_CONTAINS_FIELD(config64, min(config64->Size, config64Length), GuardFlags))\n            {\n                guardFlags = config64->GuardFlags;\n            }\n            else\n            {\n                status = STATUS_NOT_FOUND;\n            }\n\n            PhFreePage(config64);\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (guardFlags != ULONG_MAX)\n        {\n            *GuardFlags = guardFlags;\n        }\n        else\n        {\n            status = STATUS_NOT_FOUND;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetRemoteMappedImageCHPEVersion(\n    _In_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage,\n    _Out_ PULONG CHPEVersion\n    )\n{\n    NTSTATUS status;\n    PVOID entry;\n    ULONG entryLength;\n\n    *CHPEVersion = 0;\n\n    if (!NT_SUCCESS(status = PhGetRemoteMappedImageDirectoryEntry(\n        RemoteMappedImage,\n        IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,\n        &entry,\n        &entryLength\n        )))\n        return status;\n\n    if (RemoteMappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY32 config32;\n        IMAGE_CHPE_METADATA_X86 chpe32;\n\n        if (entryLength < sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32))\n        {\n            status = STATUS_BUFFER_TOO_SMALL;\n            goto CleanupExit;\n        }\n\n        config32 = entry;\n\n        if (!RTL_CONTAINS_FIELD(config32, config32->Size, CHPEMetadataPointer) ||\n            !config32->CHPEMetadataPointer)\n        {\n            status = STATUS_SUCCESS;\n            goto CleanupExit;\n        }\n\n        if (RemoteMappedImage->ReadVirtualMemoryCallback)\n        {\n            status = RemoteMappedImage->ReadVirtualMemoryCallback(\n                RemoteMappedImage->ProcessHandle,\n                ULongToPtr(config32->CHPEMetadataPointer),\n                &chpe32,\n                sizeof(chpe32),\n                NULL,\n                RemoteMappedImage->Context\n                );\n        }\n        else\n        {\n            status = PhReadVirtualMemory(\n                RemoteMappedImage->ProcessHandle,\n                ULongToPtr(config32->CHPEMetadataPointer),\n                &chpe32,\n                sizeof(chpe32),\n                NULL\n                );\n        }\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        *CHPEVersion = chpe32.Version;\n    }\n    else if (RemoteMappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY64 config64;\n        IMAGE_ARM64EC_METADATA chpe64;\n\n        if (entryLength < sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64))\n        {\n            status = STATUS_BUFFER_TOO_SMALL;\n            goto CleanupExit;\n        }\n\n        config64 = entry;\n\n        if (!RTL_CONTAINS_FIELD(config64, config64->Size, CHPEMetadataPointer) ||\n            !config64->CHPEMetadataPointer)\n        {\n            status = STATUS_SUCCESS;\n            goto CleanupExit;\n        }\n\n        if (RemoteMappedImage->ReadVirtualMemoryCallback)\n        {\n            status = RemoteMappedImage->ReadVirtualMemoryCallback(\n                RemoteMappedImage->ProcessHandle,\n                (PVOID)config64->CHPEMetadataPointer,\n                &chpe64,\n                sizeof(chpe64),\n                NULL,\n                RemoteMappedImage->Context\n                );\n        }\n        else\n        {\n            status = PhReadVirtualMemory(\n                RemoteMappedImage->ProcessHandle,\n                (PVOID)config64->CHPEMetadataPointer,\n                &chpe64,\n                sizeof(chpe64),\n                NULL\n                );\n        }\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        *CHPEVersion = chpe64.Version;\n    }\n\nCleanupExit:\n\n    PhFreePage(entry);\n\n    return status;\n}\n\n// Mapped image\n\nNTSTATUS PhRelocateMappedImageDataEntryARM64X(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_DATA_DIRECTORY Entry,\n    _Out_ PIMAGE_DATA_DIRECTORY RelocatedEntry\n    )\n{\n    NTSTATUS status;\n    ULONG vaRva;\n    ULONG sizeRva;\n    PIMAGE_DYNAMIC_RELOCATION_TABLE table;\n    PIMAGE_DYNAMIC_RELOCATION64 reloc;\n    PVOID end;\n\n    RtlZeroMemory(RelocatedEntry, sizeof(IMAGE_DATA_DIRECTORY));\n\n    if (MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n        return STATUS_INVALID_PARAMETER;\n\n    status = PhGetMappedImageDynamicRelocationsTable(MappedImage, &table);\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (table->Version != 1)\n        return STATUS_NOT_SUPPORTED;\n\n    vaRva = PtrToUlong(PTR_SUB_OFFSET(Entry, MappedImage->ViewBase));\n    sizeRva = PtrToUlong(PTR_SUB_OFFSET(PTR_ADD_OFFSET(Entry, sizeof(ULONG)), MappedImage->ViewBase));\n\n#define PH_ARM64X_DIR_FIX_DONE() (vaRva == 0 && sizeRva == 0)\n\n    reloc = PTR_ADD_OFFSET(table, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION_TABLE, Size));\n    end = PTR_ADD_OFFSET(table, table->Size);\n\n    while ((ULONG_PTR)reloc < (ULONG_PTR)end)\n    {\n        if (reloc->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X)\n        {\n            PIMAGE_BASE_RELOCATION base;\n            PVOID baseEnd;\n\n            base = PTR_ADD_OFFSET(reloc, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION64, BaseRelocSize));\n            baseEnd = PTR_ADD_OFFSET(base, reloc->BaseRelocSize);\n\n            for (;;)\n            {\n                PIMAGE_DVRT_ARM64X_FIXUP_RECORD record;\n                PVOID recordsEnd;\n\n                record = (PIMAGE_DVRT_ARM64X_FIXUP_RECORD)base;\n                recordsEnd = PTR_ADD_OFFSET(base, base->SizeOfBlock);\n\n                if (!PhPtrAdvance(&record, recordsEnd, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock)))\n                    break;\n\n                for (;;)\n                {\n                    SIZE_T consumed;\n\n                    if (record->Offset == 0 && record->Type == 0 && record->Size == 0)\n                    {\n                        // padding block(s), we're done\n                        break;\n                    }\n\n                    if (record->Type == IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL)\n                    {\n                        consumed = sizeof(IMAGE_DVRT_ARM64X_FIXUP_RECORD);\n                    }\n                    else if (record->Type == IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE)\n                    {\n                        consumed = sizeof(IMAGE_DVRT_ARM64X_FIXUP_RECORD);\n                        if (record->Size == IMAGE_DVRT_ARM64X_FIXUP_SIZE_2BYTES)\n                        {\n                            consumed += sizeof(USHORT);\n                        }\n                        else if (record->Size == IMAGE_DVRT_ARM64X_FIXUP_SIZE_4BYTES)\n                        {\n                            ULONG rva = base->VirtualAddress + record->Offset;\n                            ULONG value = *(PULONG)PTR_ADD_OFFSET(record, consumed);\n                            if (vaRva != 0 && vaRva == rva)\n                            {\n                                RelocatedEntry->VirtualAddress = value;\n                                vaRva = 0;\n                            }\n                            else if (sizeRva != 0 && sizeRva == rva)\n                            {\n                                RelocatedEntry->Size = value;\n                                sizeRva = 0;\n                            }\n\n                            consumed += sizeof(ULONG);\n                        }\n                        else if (record->Size == IMAGE_DVRT_ARM64X_FIXUP_SIZE_8BYTES)\n                        {\n                            consumed += sizeof(ULONG64);\n                        }\n                        else\n                        {\n                            break;\n                        }\n                    }\n                    else if (record->Type == IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA)\n                    {\n                        consumed = sizeof(IMAGE_DVRT_ARM64X_DELTA_FIXUP_RECORD);\n                        consumed += sizeof(USHORT);\n                    }\n                    else\n                    {\n                        break;\n                    }\n\n                    if (PH_ARM64X_DIR_FIX_DONE())\n                        break;\n\n                    if (!PhPtrAdvance(&record, recordsEnd, consumed))\n                        break;\n                }\n\n                if (PH_ARM64X_DIR_FIX_DONE())\n                    break;\n\n                if (!PhPtrAdvance(&base, baseEnd, base->SizeOfBlock))\n                    break;\n            }\n        }\n\n        if (PH_ARM64X_DIR_FIX_DONE())\n            break;\n\n        if (!PhPtrAdvance(&reloc, end, reloc->BaseRelocSize))\n            break;\n\n        if (!PhPtrAdvance(&reloc, end, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION64, BaseRelocSize)))\n            break;\n    }\n\n    return PH_ARM64X_DIR_FIX_DONE() ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;\n}\n\n/**\n * Retrieves export information from a mapped PE image with advanced options.\n *\n * \\param Exports A pointer to a structure that receives the export information.\n * \\param MappedImage A pointer to the mapped image.\n * \\param Flags Flags that control the retrieval (e.g., PH_GET_IMAGE_EXPORTS_ARM64X).\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INVALID_PARAMETER The export directory is invalid or not found.\n * \\remarks This function retrieves pointers to the export directory and associated tables\n * (address table, name pointer table, ordinal table). For ARM64X images, it can relocate\n * the export directory using dynamic relocations. All memory accesses are validated with\n * structured exception handling.\n */\nNTSTATUS PhGetMappedImageExportsEx(\n    _Out_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_EXPORT_DIRECTORY exportDirectory;\n\n    Exports->DataDirectoryARM64X.VirtualAddress = 0;\n    Exports->DataDirectoryARM64X.Size = 0;\n\n    // Get a pointer to the export directory.\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_EXPORT,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (Flags & PH_GET_IMAGE_EXPORTS_ARM64X)\n    {\n        status = PhRelocateMappedImageDataEntryARM64X(\n            MappedImage,\n            dataDirectory,\n            &Exports->DataDirectoryARM64X\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        exportDirectory = PhMappedImageRvaToVa(\n            MappedImage,\n            Exports->DataDirectoryARM64X.VirtualAddress,\n            NULL\n            );\n    }\n    else\n    {\n        exportDirectory = PhMappedImageRvaToVa(\n            MappedImage,\n            dataDirectory->VirtualAddress,\n            NULL\n            );\n    }\n\n    if (!exportDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, exportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Exports->MappedImage = MappedImage;\n    Exports->DataDirectory = dataDirectory;\n    Exports->ExportDirectory = exportDirectory;\n    Exports->NumberOfEntries = exportDirectory->NumberOfFunctions;\n\n    // Get pointers to the various tables and probe them.\n\n    Exports->AddressTable = (PULONG)PhMappedImageRvaToVa(\n        MappedImage,\n        exportDirectory->AddressOfFunctions,\n        NULL\n        );\n    Exports->NamePointerTable = (PULONG)PhMappedImageRvaToVa(\n        MappedImage,\n        exportDirectory->AddressOfNames,\n        NULL\n        );\n    Exports->OrdinalTable = (PUSHORT)PhMappedImageRvaToVa(\n        MappedImage,\n        exportDirectory->AddressOfNameOrdinals,\n        NULL\n        );\n\n    // Note: NamePointerTable and OrdinalTable are null for binaries\n    // such as mfc140u.dll yet contain valid exports (dmex)\n\n    if (!Exports->AddressTable)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(\n            MappedImage,\n            Exports->AddressTable,\n            exportDirectory->NumberOfFunctions * sizeof(ULONG)\n            );\n\n        if (Exports->NamePointerTable)\n        {\n            PhMappedImageProbe(\n                MappedImage,\n                Exports->NamePointerTable,\n                exportDirectory->NumberOfNames * sizeof(ULONG)\n                );\n        }\n\n        if (Exports->OrdinalTable)\n        {\n            PhMappedImageProbe(\n                MappedImage,\n                Exports->OrdinalTable,  // ordinal list for named exports\n                exportDirectory->NumberOfNames * sizeof(USHORT)\n                );\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // The ordinal and name tables are parallel.\n    // Getting an index into the name table (e.g. by doing a binary\n    // search) and indexing into the ordinal table will produce the\n    // ordinal for that name, *unbiased* (unlike in the specification).\n    // The unbiased ordinal is an index into the address table.\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves export information from a mapped PE image.\n *\n * \\param Exports A pointer to a structure that receives the export information.\n * \\param MappedImage A pointer to the mapped image.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetMappedImageExports(\n    _Out_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    return PhGetMappedImageExportsEx(Exports, MappedImage, 0);\n}\n\n/**\n * Retrieves information about a specific export entry by index.\n *\n * \\param Exports A pointer to the export information structure.\n * \\param Index The zero-based index into the export address table.\n * \\param Entry A pointer to a structure that receives the export entry information.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_PROCEDURE_NOT_FOUND The index is out of range.\n * \\retval STATUS_INVALID_PARAMETER The export name pointer is invalid.\n * \\remarks The function populates the entry with the ordinal, name (if exported by name),\n * and hint. The ordinal is biased (index + base ordinal).\n */\nNTSTATUS PhGetMappedImageExportEntry(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_EXPORT_ENTRY Entry\n    )\n{\n    ULONG nameIndex = 0;\n    BOOLEAN exportByName = FALSE;\n    PCSTR name;\n\n    if (Index >= Exports->ExportDirectory->NumberOfFunctions)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    Entry->Ordinal = (USHORT)Index + (USHORT)Exports->ExportDirectory->Base;\n\n    if (Exports->OrdinalTable)\n    {\n        // look into named exports ordinal list.\n        for (nameIndex = 0; nameIndex < Exports->ExportDirectory->NumberOfNames; nameIndex++)\n        {\n            if (Index == Exports->OrdinalTable[nameIndex])\n            {\n                exportByName = TRUE;\n                break;\n            }\n        }\n    }\n\n    if (Exports->NamePointerTable && exportByName)\n    {\n        name = PhMappedImageRvaToVa(\n            Exports->MappedImage,\n            Exports->NamePointerTable[nameIndex],\n            NULL\n            );\n\n        if (!name)\n            return STATUS_INVALID_PARAMETER;\n\n        // TODO: Probe the name.\n\n        Entry->Name = name;\n        Entry->Hint = nameIndex;\n    }\n    else\n    {\n        Entry->Name = NULL;\n        Entry->Hint = 0;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Locates an export by name using binary search.\n *\n * \\param Exports A pointer to the export information structure.\n * \\param Name The name of the export to find.\n * \\return The index of the export in the name table, or ULONG_MAX if not found.\n * \\remarks The export name table is sorted alphabetically, allowing for efficient binary search.\n * The returned index can be used with the ordinal table to obtain the unbiased ordinal.\n */\nULONG PhLookupMappedImageExportName(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ PCSTR Name\n    )\n{\n    LONG low;\n    LONG high;\n    LONG i;\n\n    if (Exports->ExportDirectory->NumberOfNames == 0)\n        return ULONG_MAX;\n\n    low = 0;\n    high = Exports->ExportDirectory->NumberOfNames - 1;\n\n    do\n    {\n        PCSTR name;\n        INT comparison;\n\n        i = (low + high) / 2;\n\n        name = PhMappedImageRvaToVa(\n            Exports->MappedImage,\n            Exports->NamePointerTable[i],\n            NULL\n            );\n\n        if (!name)\n            return ULONG_MAX;\n\n        // TODO: Probe the name.\n\n        comparison = strcmp(Name, name);\n\n        if (comparison == 0)\n            return i;\n        else if (comparison < 0)\n            high = i - 1;\n        else\n            low = i + 1;\n    } while (low <= high);\n\n    return ULONG_MAX;\n}\n\n/**\n * Retrieves the address of an exported function by name or ordinal.\n *\n * \\param Exports A pointer to the export information structure.\n * \\param Name The name of the exported function. Specify NULL to use Ordinal.\n * \\param Ordinal The ordinal of the exported function. Specify 0 to use Name.\n * \\param Function A pointer to a structure that receives the function information.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_PROCEDURE_NOT_FOUND The function was not found.\n * \\retval STATUS_INVALID_PARAMETER The forwarder name is invalid.\n * \\remarks This function returns the RVA of the export. If the export is a forwarder,\n * the ForwardedName field will point to the forwarding string (e.g., \"NTDLL.RtlAllocateHeap\").\n */\nNTSTATUS PhGetMappedImageExportFunction(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_opt_ PCSTR Name,\n    _In_opt_ USHORT Ordinal,\n    _Out_ PPH_MAPPED_IMAGE_EXPORT_FUNCTION Function\n    )\n{\n    ULONG rva;\n\n    if (Name)\n    {\n        ULONG index;\n\n        index = PhLookupMappedImageExportName(Exports, Name);\n\n        if (index == ULONG_MAX)\n            return STATUS_PROCEDURE_NOT_FOUND;\n\n        Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base;\n    }\n\n    Ordinal -= (USHORT)Exports->ExportDirectory->Base;\n\n    if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    rva = Exports->AddressTable[Ordinal];\n\n    if (\n        (rva >= Exports->DataDirectory->VirtualAddress) &&\n        (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size)\n        )\n    {\n        // This is a forwarder RVA.\n\n        Function->ForwardedName = PhMappedImageRvaToVa(\n            Exports->MappedImage,\n            rva,\n            NULL\n            );\n\n        if (!Function->ForwardedName)\n            return STATUS_INVALID_PARAMETER;\n\n        // TODO: Probe the name.\n\n        Function->Function = UlongToPtr(rva);\n    }\n    else\n    {\n        Function->Function = UlongToPtr(rva);\n        Function->ForwardedName = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageExportFunctionRemote(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_opt_ PCSTR Name,\n    _In_opt_ USHORT Ordinal,\n    _In_ PVOID RemoteBase,\n    _Out_ PVOID *Function\n    )\n{\n    ULONG rva;\n\n    if (Name)\n    {\n        ULONG index;\n\n        index = PhLookupMappedImageExportName(Exports, Name);\n\n        if (index == ULONG_MAX)\n            return STATUS_PROCEDURE_NOT_FOUND;\n\n        Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base;\n    }\n\n    Ordinal -= (USHORT)Exports->ExportDirectory->Base;\n\n    if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    rva = Exports->AddressTable[Ordinal];\n\n    if (\n        (rva >= Exports->DataDirectory->VirtualAddress) &&\n        (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size)\n        )\n    {\n        // This is a forwarder RVA. Not supported for remote lookup.\n        return STATUS_NOT_SUPPORTED;\n    }\n    else\n    {\n        *Function = PTR_ADD_OFFSET(RemoteBase, rva);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves import information from a mapped PE image.\n *\n * \\param Imports A pointer to a structure that receives the import information.\n * \\param MappedImage A pointer to the mapped image.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetMappedImageImports(\n    _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_IMPORT_DESCRIPTOR descriptor;\n    ULONG i;\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_IMPORT,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    descriptor = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!descriptor)\n        return STATUS_INVALID_PARAMETER;\n\n    Imports->MappedImage = MappedImage;\n    Imports->Flags = 0;\n    Imports->DescriptorTable = descriptor;\n\n    // Do a scan to determine how many import descriptors there are.\n\n    i = 0;\n\n    __try\n    {\n        while (TRUE)\n        {\n            PhMappedImageProbe(MappedImage, descriptor, sizeof(IMAGE_IMPORT_DESCRIPTOR));\n\n            if (descriptor->OriginalFirstThunk == 0 && descriptor->FirstThunk == 0)\n                break;\n\n            descriptor++;\n            i++;\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Imports->NumberOfDlls = i;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves information about a specific imported DLL by index.\n *\n * \\param Imports A pointer to the import information structure.\n * \\param Index The zero-based index of the imported DLL.\n * \\param ImportDll A pointer to a structure that receives the import DLL information.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INVALID_PARAMETER_2 The index is out of range.\n * \\retval STATUS_INVALID_PARAMETER The DLL name or thunk data is invalid.\n *\n * \\remarks This function retrieves the import descriptor, DLL name, and import/name tables\n * for a specific DLL. The lookup table (OriginalFirstThunk) contains import information,\n * while the address table (FirstThunk) is patched by the loader with actual addresses.\n */\nNTSTATUS PhGetMappedImageImportDll(\n    _In_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll\n    )\n{\n    ULONG i;\n\n    if (Index >= Imports->NumberOfDlls)\n        return STATUS_INVALID_PARAMETER_2;\n\n    ImportDll->MappedImage = Imports->MappedImage;\n    ImportDll->Flags = Imports->Flags;\n\n    if (!FlagOn(ImportDll->Flags, PH_MAPPED_IMAGE_DELAY_IMPORTS))\n    {\n        ImportDll->Descriptor = &Imports->DescriptorTable[Index];\n\n        ImportDll->Name = PhMappedImageRvaToVa(\n            ImportDll->MappedImage,\n            ImportDll->Descriptor->Name,\n            NULL\n            );\n\n        if (!ImportDll->Name)\n            return STATUS_INVALID_PARAMETER;\n\n        // TODO: Probe the name.\n\n        if (ImportDll->Descriptor->OriginalFirstThunk)\n        {\n            ImportDll->LookupTable = PhMappedImageRvaToVa(\n                ImportDll->MappedImage,\n                ImportDll->Descriptor->OriginalFirstThunk,\n                NULL\n                );\n        }\n        else\n        {\n            ImportDll->LookupTable = PhMappedImageRvaToVa(\n                ImportDll->MappedImage,\n                ImportDll->Descriptor->FirstThunk,\n                NULL\n                );\n        }\n    }\n    else\n    {\n        ImportDll->DelayDescriptor = &Imports->DelayDescriptorTable[Index];\n\n        if (ImportDll->DelayDescriptor->Attributes.RvaBased)\n        {\n            ImportDll->Name = PhMappedImageRvaToVa(\n                ImportDll->MappedImage,\n                ImportDll->DelayDescriptor->DllNameRVA,\n                NULL\n                );\n\n            if (!ImportDll->Name)\n                return STATUS_INVALID_PARAMETER;\n\n            // TODO: Probe the name.\n\n            ImportDll->LookupTable = PhMappedImageRvaToVa(\n                ImportDll->MappedImage,\n                ImportDll->DelayDescriptor->ImportNameTableRVA,\n                NULL\n                );\n        }\n        else\n        {\n            ImportDll->Name = PhMappedImageVaToVa(\n                ImportDll->MappedImage,\n                ImportDll->DelayDescriptor->DllNameRVA,\n                NULL\n                );\n\n            if (!ImportDll->Name)\n                return STATUS_INVALID_PARAMETER;\n\n            // TODO: Probe the name.\n\n            ImportDll->LookupTable = PhMappedImageVaToVa(\n                ImportDll->MappedImage,\n                ImportDll->DelayDescriptor->ImportNameTableRVA,\n                NULL\n                );\n        }\n    }\n\n    if (!ImportDll->LookupTable)\n        return STATUS_INVALID_PARAMETER;\n\n    // Do a scan to determine how many entries there are.\n\n    i = 0;\n\n    if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        UNALIGNED_PIMAGE_THUNK_DATA32 entry;\n\n        entry = (UNALIGNED_PIMAGE_THUNK_DATA32)ImportDll->LookupTable;\n\n        __try\n        {\n            while (TRUE)\n            {\n                PhMappedImageProbe(ImportDll->MappedImage, entry, sizeof(IMAGE_THUNK_DATA32));\n\n                if (entry->u1.AddressOfData == 0)\n                    break;\n\n                entry++;\n                i++;\n            }\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n    else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        UNALIGNED_PIMAGE_THUNK_DATA64 entry;\n\n        entry = (UNALIGNED_PIMAGE_THUNK_DATA64)ImportDll->LookupTable;\n\n        __try\n        {\n            while (TRUE)\n            {\n                PhMappedImageProbe(ImportDll->MappedImage, entry, sizeof(IMAGE_THUNK_DATA64));\n\n                if (entry->u1.AddressOfData == 0)\n                    break;\n\n                entry++;\n                i++;\n            }\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n    else\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    ImportDll->NumberOfEntries = i;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageImportEntry(\n    _In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_IMPORT_ENTRY Entry\n    )\n{\n    PIMAGE_IMPORT_BY_NAME importByName;\n\n    if (Index >= ImportDll->NumberOfEntries)\n        return STATUS_INVALID_PARAMETER_2;\n\n    if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        IMAGE_THUNK_DATA32 entry = ((PIMAGE_THUNK_DATA32)ImportDll->LookupTable)[Index];\n\n        if (IMAGE_SNAP_BY_ORDINAL32(entry.u1.Ordinal))\n        {\n            Entry->Name = NULL;\n            Entry->Ordinal = IMAGE_ORDINAL32(entry.u1.Ordinal);\n\n            return STATUS_SUCCESS;\n        }\n        else\n        {\n            if (FlagOn(ImportDll->Flags, PH_MAPPED_IMAGE_DELAY_IMPORTS) && !ImportDll->DelayDescriptor->Attributes.RvaBased)\n            {\n                importByName = PhMappedImageVaToVa(ImportDll->MappedImage, entry.u1.AddressOfData, NULL);\n            }\n            else\n            {\n                importByName = PhMappedImageRvaToVa(ImportDll->MappedImage, entry.u1.AddressOfData, NULL);\n            }\n        }\n    }\n    else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        IMAGE_THUNK_DATA64 entry = ((PIMAGE_THUNK_DATA64)ImportDll->LookupTable)[Index];\n\n        if (IMAGE_SNAP_BY_ORDINAL64(entry.u1.Ordinal))\n        {\n            Entry->Name = NULL;\n            Entry->Ordinal = IMAGE_ORDINAL64(entry.u1.Ordinal);\n\n            return STATUS_SUCCESS;\n        }\n        else\n        {\n            if (FlagOn(ImportDll->Flags, PH_MAPPED_IMAGE_DELAY_IMPORTS) && !ImportDll->DelayDescriptor->Attributes.RvaBased)\n            {\n                importByName = PhMappedImageVaToVa(ImportDll->MappedImage, entry.u1.AddressOfData, NULL);\n            }\n            else\n            {\n                importByName = PhMappedImageRvaToVa(ImportDll->MappedImage, (ULONG)entry.u1.AddressOfData, NULL);\n            }\n        }\n    }\n    else\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    if (!importByName)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(ImportDll->MappedImage, importByName, sizeof(IMAGE_IMPORT_BY_NAME));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Entry->Name = (PSTR)importByName->Name;\n    Entry->NameHint = importByName->Hint;\n\n    // TODO: Probe the name.\n\n    return STATUS_SUCCESS;\n}\n\nULONG PhGetMappedImageImportEntryRva(\n    _In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll,\n    _In_ ULONG Index,\n    _In_ BOOLEAN DelayImport\n    )\n{\n    ULONG rva = 0;\n    //PVOID va;\n\n    if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        if (DelayImport)\n        {\n            rva = ImportDll->DelayDescriptor->ImportAddressTableRVA + Index * sizeof(IMAGE_THUNK_DATA32);\n            //va = PTR_ADD_OFFSET(ImportDll->MappedImage->NtHeaders32->OptionalHeader.ImageBase, rva);\n        }\n        else\n        {\n            rva = ImportDll->Descriptor->FirstThunk + Index * sizeof(IMAGE_THUNK_DATA32);\n            //va = PTR_ADD_OFFSET(ImportDll->MappedImage->NtHeaders32->OptionalHeader.ImageBase, rva);\n        }\n    }\n    else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        if (DelayImport)\n        {\n            rva = ImportDll->DelayDescriptor->ImportAddressTableRVA + Index * sizeof(IMAGE_THUNK_DATA64);\n            //va = PTR_ADD_OFFSET(ImportDll->MappedImage->NtHeaders->OptionalHeader.ImageBase, rva);\n        }\n        else\n        {\n            rva = ImportDll->Descriptor->FirstThunk + Index * sizeof(IMAGE_THUNK_DATA64);\n            //va = PTR_ADD_OFFSET(ImportDll->MappedImage->NtHeaders->OptionalHeader.ImageBase, rva);\n        }\n    }\n\n    return rva;\n}\n\n/**\n * Retrieves delay-load import information from a mapped PE image.\n *\n * \\param Imports A pointer to a structure that receives the delay-load import information.\n * \\param MappedImage A pointer to the mapped image.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetMappedImageDelayImports(\n    _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_DELAYLOAD_DESCRIPTOR descriptor;\n    ULONG i;\n\n    Imports->MappedImage = MappedImage;\n    Imports->Flags = PH_MAPPED_IMAGE_DELAY_IMPORTS;\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    descriptor = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!descriptor)\n        return STATUS_INVALID_PARAMETER;\n\n    Imports->DelayDescriptorTable = descriptor;\n\n    // Do a scan to determine how many import descriptors there are.\n\n    i = 0;\n\n    __try\n    {\n        while (TRUE)\n        {\n            PhMappedImageProbe(MappedImage, descriptor, sizeof(PIMAGE_DELAYLOAD_DESCRIPTOR));\n\n            if (descriptor->ImportAddressTableRVA == 0 && descriptor->ImportNameTableRVA == 0)\n                break;\n\n            descriptor++;\n            i++;\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Imports->NumberOfDlls = i;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Computes a partial checksum for PE image validation.\n *\n * \\param Sum The initial sum value.\n * \\param Buffer A pointer to the buffer to checksum.\n * \\param Count The number of 16-bit words to process.\n * \\return The computed checksum value.\n * \\remarks This implements the standard PE checksum algorithm used by Windows loaders\n * to verify image integrity. The algorithm processes 16-bit words with carry folding.\n */\nUSHORT PhCheckSum(\n    _In_ ULONG Sum,\n    _In_reads_(Count) PUSHORT Buffer,\n    _In_ ULONG Count\n    )\n{\n    while (Count--)\n    {\n        Sum += *Buffer++;\n        Sum = (Sum >> 16) + (Sum & 0xffff);\n    }\n\n    Sum = (Sum >> 16) + Sum;\n\n    return (USHORT)Sum;\n}\n\n/**\n * Computes the checksum of a mapped PE image.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\return The computed checksum value.\n * \\remarks This function calculates the PE image checksum using the standard algorithm.\n * The checksum field in the optional header is excluded from the calculation. The result\n * can be compared with OptionalHeader.CheckSum to verify image integrity.\n */\nULONG PhCheckSumMappedImage(\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    ULONG checkSum;\n    USHORT partialSum;\n    PUSHORT adjust;\n\n    partialSum = PhCheckSum(0, (PUSHORT)MappedImage->ViewBase, (ULONG)(MappedImage->ViewSize + 1) / 2);\n\n    // This is actually the same for 32-bit and 64-bit executables.\n    adjust = (PUSHORT)&MappedImage->NtHeaders->OptionalHeader.CheckSum;\n\n    // Subtract the existing check sum (with carry).\n    partialSum -= partialSum < adjust[0];\n    partialSum -= adjust[0];\n    partialSum -= partialSum < adjust[1];\n    partialSum -= adjust[1];\n\n    checkSum = partialSum + (ULONG)MappedImage->ViewSize;\n\n    return checkSum;\n}\n\nNTSTATUS PhGetMappedImageCfg64(\n    _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_LOAD_CONFIG_DIRECTORY64 config64;\n\n    if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig64(MappedImage, &config64)))\n        return status;\n\n    // Not every load configuration defines CFG characteristics\n    if (!RTL_CONTAINS_FIELD(config64, config64->Size, GuardFlags))\n        return STATUS_INVALID_VIEW_SIZE;\n\n    CfgConfig->MappedImage = MappedImage;\n    CfgConfig->EntrySize = RTL_FIELD_SIZE(IMAGE_CFG_ENTRY, Rva) +\n        (ULONG)((config64->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT);\n    CfgConfig->CfgInstrumented = !!(config64->GuardFlags & IMAGE_GUARD_CF_INSTRUMENTED);\n    CfgConfig->WriteIntegrityChecks = !!(config64->GuardFlags & IMAGE_GUARD_CFW_INSTRUMENTED);\n    CfgConfig->CfgFunctionTablePresent = !!(config64->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT);\n    CfgConfig->SecurityCookieUnused = !!(config64->GuardFlags & IMAGE_GUARD_SECURITY_COOKIE_UNUSED);\n    CfgConfig->ProtectDelayLoadedIat = !!(config64->GuardFlags & IMAGE_GUARD_PROTECT_DELAYLOAD_IAT);\n    CfgConfig->DelayLoadInDidatSection = !!(config64->GuardFlags & IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION);\n    CfgConfig->EnableExportSuppression = !!(config64->GuardFlags & IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION);\n    CfgConfig->HasExportSuppressionInfos = !!(config64->GuardFlags & IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT);\n    CfgConfig->CfgLongJumpTablePresent = !!(config64->GuardFlags & IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT);\n\n    CfgConfig->NumberOfGuardFunctionEntries = config64->GuardCFFunctionCount;\n    CfgConfig->GuardFunctionTable = PhMappedImageVaToVa(\n        MappedImage,\n        config64->GuardCFFunctionTable,\n        NULL\n        );\n\n    if (CfgConfig->GuardFunctionTable && CfgConfig->NumberOfGuardFunctionEntries)\n    {\n        __try\n        {\n            PhMappedImageProbe(\n                MappedImage,\n                CfgConfig->GuardFunctionTable,\n                (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardFunctionEntries)\n                );\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n\n    CfgConfig->NumberOfGuardAdressIatEntries = 0;\n    CfgConfig->GuardAdressIatTable = 0;\n\n    if (RTL_CONTAINS_FIELD(config64, config64->Size, GuardAddressTakenIatEntryTable))\n    {\n        CfgConfig->NumberOfGuardAdressIatEntries = config64->GuardAddressTakenIatEntryCount;\n        CfgConfig->GuardAdressIatTable = PhMappedImageVaToVa(\n            MappedImage,\n            config64->GuardAddressTakenIatEntryTable,\n            NULL\n            );\n\n        if (CfgConfig->GuardAdressIatTable && CfgConfig->NumberOfGuardAdressIatEntries)\n        {\n            __try\n            {\n                PhMappedImageProbe(\n                    MappedImage,\n                    CfgConfig->GuardAdressIatTable,\n                    (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardAdressIatEntries)\n                    );\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    CfgConfig->NumberOfGuardLongJumpEntries = 0;\n    CfgConfig->GuardLongJumpTable = 0;\n\n    if (RTL_CONTAINS_FIELD(config64, config64->Size, GuardLongJumpTargetTable))\n    {\n        CfgConfig->NumberOfGuardLongJumpEntries = config64->GuardLongJumpTargetCount;\n        CfgConfig->GuardLongJumpTable = PhMappedImageVaToVa(\n            MappedImage,\n            config64->GuardLongJumpTargetTable,\n            NULL\n            );\n\n        if (CfgConfig->GuardLongJumpTable && CfgConfig->NumberOfGuardLongJumpEntries)\n        {\n            __try\n            {\n                PhMappedImageProbe(\n                    MappedImage,\n                    CfgConfig->GuardLongJumpTable,\n                    (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardLongJumpEntries)\n                    );\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageCfg32(\n    _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_LOAD_CONFIG_DIRECTORY32 config32;\n\n    if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig32(MappedImage, &config32)))\n        return status;\n\n    // Not every load configuration defines CFG characteristics\n    if (!RTL_CONTAINS_FIELD(config32, config32->Size, GuardFlags))\n        return STATUS_INVALID_VIEW_SIZE;\n\n    CfgConfig->MappedImage = MappedImage;\n    CfgConfig->EntrySize = RTL_FIELD_SIZE(IMAGE_CFG_ENTRY, Rva) +\n        (ULONG)((config32->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT);\n    CfgConfig->CfgInstrumented = !!(config32->GuardFlags & IMAGE_GUARD_CF_INSTRUMENTED);\n    CfgConfig->WriteIntegrityChecks = !!(config32->GuardFlags & IMAGE_GUARD_CFW_INSTRUMENTED);\n    CfgConfig->CfgFunctionTablePresent = !!(config32->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT);\n    CfgConfig->SecurityCookieUnused = !!(config32->GuardFlags & IMAGE_GUARD_SECURITY_COOKIE_UNUSED);\n    CfgConfig->ProtectDelayLoadedIat = !!(config32->GuardFlags & IMAGE_GUARD_PROTECT_DELAYLOAD_IAT);\n    CfgConfig->DelayLoadInDidatSection = !!(config32->GuardFlags & IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION);\n    CfgConfig->EnableExportSuppression = !!(config32->GuardFlags & IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION);\n    CfgConfig->HasExportSuppressionInfos = !!(config32->GuardFlags & IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT);\n    CfgConfig->CfgLongJumpTablePresent = !!(config32->GuardFlags & IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT);\n\n    CfgConfig->NumberOfGuardFunctionEntries = config32->GuardCFFunctionCount;\n    CfgConfig->GuardFunctionTable = PhMappedImageVaToVa(\n        MappedImage,\n        config32->GuardCFFunctionTable,\n        NULL\n        );\n\n    if (CfgConfig->GuardFunctionTable && CfgConfig->NumberOfGuardFunctionEntries)\n    {\n        __try\n        {\n            PhMappedImageProbe(\n                MappedImage,\n                CfgConfig->GuardFunctionTable,\n                (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardFunctionEntries)\n                );\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n\n    CfgConfig->NumberOfGuardAdressIatEntries = 0;\n    CfgConfig->GuardAdressIatTable = 0;\n\n    if (RTL_CONTAINS_FIELD(config32, config32->Size, GuardAddressTakenIatEntryTable))\n    {\n        CfgConfig->NumberOfGuardAdressIatEntries = config32->GuardAddressTakenIatEntryCount;\n        CfgConfig->GuardAdressIatTable = PhMappedImageVaToVa(\n            MappedImage,\n            config32->GuardAddressTakenIatEntryTable,\n            NULL\n            );\n\n        if (CfgConfig->GuardAdressIatTable && CfgConfig->NumberOfGuardAdressIatEntries)\n        {\n            __try\n            {\n                PhMappedImageProbe(\n                    MappedImage,\n                    CfgConfig->GuardAdressIatTable,\n                    (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardAdressIatEntries)\n                    );\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    CfgConfig->NumberOfGuardLongJumpEntries = 0;\n    CfgConfig->GuardLongJumpTable = 0;\n\n    if (RTL_CONTAINS_FIELD(config32, config32->Size, GuardLongJumpTargetTable))\n    {\n        CfgConfig->NumberOfGuardLongJumpEntries = config32->GuardLongJumpTargetCount;\n        CfgConfig->GuardLongJumpTable = PhMappedImageVaToVa(\n            MappedImage,\n            config32->GuardLongJumpTargetTable,\n            NULL\n            );\n\n        if (CfgConfig->GuardLongJumpTable && CfgConfig->NumberOfGuardLongJumpEntries)\n        {\n            __try\n            {\n                PhMappedImageProbe(\n                    MappedImage,\n                    CfgConfig->GuardLongJumpTable,\n                    (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardLongJumpEntries)\n                    );\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageCfg(\n    _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        return PhGetMappedImageCfg32(CfgConfig, MappedImage);\n    }\n    else\n    {\n        return PhGetMappedImageCfg64(CfgConfig, MappedImage);\n    }\n}\n\nNTSTATUS PhGetMappedImageCfgEntry(\n    _In_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ ULONGLONG Index,\n    _In_ CFG_ENTRY_TYPE Type,\n    _Out_ PIMAGE_CFG_ENTRY Entry\n    )\n{\n    PULONGLONG guardTable;\n    ULONGLONG numberofGuardEntries;\n    PIMAGE_CFG_ENTRY cfgMappedEntry;\n\n    switch (Type)\n    {\n    case ControlFlowGuardFunction:\n        {\n            guardTable = CfgConfig->GuardFunctionTable;\n            numberofGuardEntries = CfgConfig->NumberOfGuardFunctionEntries;\n        }\n        break;\n    case ControlFlowGuardTakenIatEntry:\n        {\n            guardTable = CfgConfig->GuardAdressIatTable;\n            numberofGuardEntries = CfgConfig->NumberOfGuardAdressIatEntries;\n        }\n        break;\n    case ControlFlowGuardLongJump:\n        {\n            guardTable = CfgConfig->GuardLongJumpTable;\n            numberofGuardEntries = CfgConfig->NumberOfGuardLongJumpEntries;\n        }\n        break;\n    default:\n        return STATUS_INVALID_PARAMETER_3;\n    }\n\n    if (!guardTable || Index >= numberofGuardEntries)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    cfgMappedEntry = (PIMAGE_CFG_ENTRY)PTR_ADD_OFFSET(guardTable, Index * CfgConfig->EntrySize);\n\n    Entry->Rva = cfgMappedEntry->Rva;\n\n    // Optional header after the rva entry\n\n    if (CfgConfig->EntrySize > RTL_FIELD_SIZE(IMAGE_CFG_ENTRY, Rva))\n    {\n        Entry->SuppressedCall = cfgMappedEntry->SuppressedCall;\n        Entry->ExportSuppressed = cfgMappedEntry->ExportSuppressed;\n        Entry->LangExcptHandler = cfgMappedEntry->LangExcptHandler;\n        Entry->Xfg = cfgMappedEntry->Xfg;\n        Entry->Reserved = cfgMappedEntry->Reserved;\n\n        if (cfgMappedEntry->Xfg)\n        {\n            // XFG hashes are offset from the rva (dmex)\n            PVOID cfgFunctionOffset = PTR_ADD_OFFSET(CfgConfig->MappedImage->ViewBase, Entry->Rva);\n            Entry->XfgHash = *(PULONG64)PTR_SUB_OFFSET(cfgFunctionOffset, sizeof(ULONG64));\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageResources(\n    _Out_ PPH_MAPPED_IMAGE_RESOURCES Resources,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_RESOURCE_DIRECTORY resourceDirectory;\n    PIMAGE_RESOURCE_DIRECTORY nameDirectory;\n    PIMAGE_RESOURCE_DIRECTORY languageDirectory;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceType;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceName;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceLanguage;\n    ULONG resourceCount = 0;\n    ULONG resourceTypeCount;\n    ULONG resourceNameCount;\n    ULONG resourceLanguageCount;\n    PH_ARRAY resourceArray;\n\n    // Get a pointer to the resource directory.\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_RESOURCE,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    resourceDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!resourceDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // NOTE: We can't use LdrEnumResources here because we're using an image mapped with SEC_COMMIT.\n\n    // Do a scan to determine how many resources there are.\n\n    resourceType = PTR_ADD_OFFSET(resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n    resourceTypeCount = resourceDirectory->NumberOfNamedEntries + resourceDirectory->NumberOfIdEntries;\n\n    for (ULONG i = 0; i < resourceTypeCount; ++i, ++resourceType)\n    {\n        if (!resourceType->DataIsDirectory)\n            continue; // return STATUS_RESOURCE_TYPE_NOT_FOUND;\n\n        nameDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceType->OffsetToDirectory);\n        resourceName = PTR_ADD_OFFSET(nameDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n        resourceNameCount = nameDirectory->NumberOfNamedEntries + nameDirectory->NumberOfIdEntries;\n\n        for (ULONG j = 0; j < resourceNameCount; ++j, ++resourceName)\n        {\n            if (!resourceName->DataIsDirectory)\n                continue; // return STATUS_RESOURCE_NAME_NOT_FOUND;\n\n            languageDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceName->OffsetToDirectory);\n            resourceLanguage = PTR_ADD_OFFSET(languageDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n            resourceLanguageCount = languageDirectory->NumberOfNamedEntries + languageDirectory->NumberOfIdEntries;\n\n            for (ULONG k = 0; k < resourceLanguageCount; ++k, ++resourceLanguage)\n            {\n                if (resourceLanguage->DataIsDirectory)\n                    continue; // return STATUS_RESOURCE_DATA_NOT_FOUND;\n\n                resourceCount++;\n            }\n        }\n    }\n\n    if (resourceCount == 0)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    // Allocate the number of resources.\n\n    PhInitializeArray(&resourceArray, sizeof(PH_IMAGE_RESOURCE_ENTRY), resourceCount);\n\n    // Enumerate the resources adding them into our buffer.\n\n    resourceType = PTR_ADD_OFFSET(resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n    resourceTypeCount = resourceDirectory->NumberOfNamedEntries + resourceDirectory->NumberOfIdEntries;\n\n    for (ULONG i = 0; i < resourceTypeCount; ++i, ++resourceType)\n    {\n        if (!resourceType->DataIsDirectory)\n            continue;\n\n        nameDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceType->OffsetToDirectory);\n        resourceName = PTR_ADD_OFFSET(nameDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n        resourceNameCount = nameDirectory->NumberOfNamedEntries + nameDirectory->NumberOfIdEntries;\n\n        for (ULONG j = 0; j < resourceNameCount; ++j, ++resourceName)\n        {\n            if (!resourceName->DataIsDirectory)\n                continue;\n\n            languageDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceName->OffsetToDirectory);\n            resourceLanguage = PTR_ADD_OFFSET(languageDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n            resourceLanguageCount = languageDirectory->NumberOfNamedEntries + languageDirectory->NumberOfIdEntries;\n\n            for (ULONG k = 0; k < resourceLanguageCount; ++k, ++resourceLanguage)\n            {\n                PIMAGE_RESOURCE_DATA_ENTRY resourceData;\n\n                if (resourceLanguage->DataIsDirectory)\n                    continue;\n\n                resourceData = PTR_ADD_OFFSET(resourceDirectory, resourceLanguage->OffsetToData);\n\n                {\n                    PH_IMAGE_RESOURCE_ENTRY entry;\n\n                    entry.Type = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceType);\n                    entry.Name = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceName);\n                    entry.Language = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceLanguage);\n                    entry.Offset = resourceData->OffsetToData;\n                    entry.Size = resourceData->Size;\n                    entry.CodePage = resourceData->CodePage;\n                    //entry.Data = PhMappedImageRvaToVa(MappedImage, resourceData->OffsetToData, NULL);\n\n                    PhAddItemArray(&resourceArray, &entry);\n                }\n            }\n        }\n    }\n\n    Resources->MappedImage = MappedImage;\n    Resources->DataDirectory = dataDirectory;\n    Resources->ResourceDirectory = resourceDirectory;\n    Resources->NumberOfEntries = (ULONG)PhFinalArrayCount(&resourceArray); // resourceCount;\n    Resources->ResourceEntries = PhFinalArrayItems(&resourceArray);\n\n    return status;\n}\n\nNTSTATUS PhGetMappedImageResource(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _In_opt_ USHORT Language,\n    _Out_opt_ PULONG ResourceLength,\n    _Out_opt_ PVOID* ResourceBuffer\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_RESOURCE_DIRECTORY resourceDirectory;\n    PIMAGE_RESOURCE_DIRECTORY nameDirectory;\n    PIMAGE_RESOURCE_DIRECTORY languageDirectory;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceType;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceName;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceLanguage;\n    ULONG resourceTypeCount;\n    ULONG resourceNameCount;\n    ULONG resourceLanguageCount;\n\n    // Get a pointer to the resource directory.\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_RESOURCE,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    resourceDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!resourceDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    resourceType = PTR_ADD_OFFSET(resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n    resourceTypeCount = resourceDirectory->NumberOfNamedEntries + resourceDirectory->NumberOfIdEntries;\n\n    for (ULONG i = 0; i < resourceTypeCount; ++i, ++resourceType)\n    {\n        if (!resourceType->DataIsDirectory)\n            continue;\n\n        nameDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceType->OffsetToDirectory);\n        resourceName = PTR_ADD_OFFSET(nameDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n        resourceNameCount = nameDirectory->NumberOfNamedEntries + nameDirectory->NumberOfIdEntries;\n\n        for (ULONG j = 0; j < resourceNameCount; ++j, ++resourceName)\n        {\n            if (!resourceName->DataIsDirectory)\n                continue;\n\n            languageDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceName->OffsetToDirectory);\n            resourceLanguage = PTR_ADD_OFFSET(languageDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n            resourceLanguageCount = languageDirectory->NumberOfNamedEntries + languageDirectory->NumberOfIdEntries;\n\n            for (ULONG k = 0; k < resourceLanguageCount; ++k, ++resourceLanguage)\n            {\n                PIMAGE_RESOURCE_DATA_ENTRY resourceData;\n\n                if (resourceLanguage->DataIsDirectory)\n                    continue;\n\n                if (IS_INTRESOURCE(Type))\n                {\n                    if (resourceType->NameIsString)\n                        continue;\n                    if (resourceType->Id != PtrToUshort(Type))\n                        continue;\n                }\n                else\n                {\n                    PIMAGE_RESOURCE_DIR_STRING_U resourceString;\n                    PH_STRINGREF string1;\n                    PH_STRINGREF string2;\n\n                    if (!resourceType->NameIsString)\n                        continue;\n\n                    resourceString = PTR_ADD_OFFSET(resourceDirectory, resourceType->NameOffset);\n                    string1.Buffer = resourceString->NameString;\n                    string1.Length = resourceString->Length * sizeof(WCHAR);\n                    PhInitializeStringRefLongHint(&string2, Type);\n\n                    if (!PhEqualStringRef(&string1, &string2, TRUE))\n                        continue;\n                }\n\n                if (IS_INTRESOURCE(Name))\n                {\n                    if (resourceName->NameIsString)\n                        continue;\n                    if (resourceName->Id != PtrToUshort(Name))\n                        continue;\n                }\n                else\n                {\n                    PIMAGE_RESOURCE_DIR_STRING_U resourceString;\n                    PH_STRINGREF string1;\n                    PH_STRINGREF string2;\n\n                    if (!resourceName->NameIsString)\n                        continue;\n\n                    resourceString = PTR_ADD_OFFSET(resourceDirectory, resourceName->NameOffset);\n                    string1.Buffer = resourceString->NameString;\n                    string1.Length = resourceString->Length * sizeof(WCHAR);\n                    PhInitializeStringRefLongHint(&string2, Name);\n\n                    if (!PhEqualStringRef(&string1, &string2, TRUE))\n                        continue;\n                }\n\n                if (Language)\n                {\n                    if (resourceLanguage->NameIsString)\n                        continue;\n                    if (resourceLanguage->Id != Language)\n                        continue;\n                }\n\n                resourceData = PTR_ADD_OFFSET(resourceDirectory, resourceLanguage->OffsetToData);\n\n                if (ResourceLength)\n                {\n                    *ResourceLength = resourceData->Size;\n                }\n\n                if (ResourceBuffer)\n                {\n                    *ResourceBuffer = PhMappedImageRvaToVa(MappedImage, resourceData->OffsetToData, NULL);\n                }\n\n                return STATUS_SUCCESS;\n            }\n        }\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nNTSTATUS PhGetMappedImageResourceIndex(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_RESOURCE_DIRECTORY ResourceDirectory,\n    _In_ LONG ResourceIndex,\n    _In_ PCWSTR ResourceType,\n    _Out_opt_ ULONG* ResourceLength,\n    _Out_opt_ PVOID* ResourceBuffer\n    )\n{\n    ULONG resourceIndex;\n    ULONG resourceCount;\n    PVOID resourceBuffer;\n    PIMAGE_RESOURCE_DIRECTORY nameDirectory;\n    PIMAGE_RESOURCE_DIRECTORY languageDirectory;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceType;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceName;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceLanguage;\n    PIMAGE_RESOURCE_DATA_ENTRY resourceData;\n\n    // Find the type\n    resourceCount = ResourceDirectory->NumberOfIdEntries + ResourceDirectory->NumberOfNamedEntries;\n    resourceType = PTR_ADD_OFFSET(ResourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n\n    for (resourceIndex = 0; resourceIndex < resourceCount; resourceIndex++)\n    {\n        if (resourceType[resourceIndex].NameIsString)\n            continue;\n        if (resourceType[resourceIndex].Name == PtrToUlong(ResourceType))\n            break;\n    }\n\n    if (resourceIndex == resourceCount)\n        return STATUS_RESOURCE_TYPE_NOT_FOUND;\n    if (!resourceType[resourceIndex].DataIsDirectory)\n        return STATUS_RESOURCE_TYPE_NOT_FOUND;\n\n    // Find the name\n    nameDirectory = PTR_ADD_OFFSET(ResourceDirectory, resourceType[resourceIndex].OffsetToDirectory);\n    resourceCount = nameDirectory->NumberOfIdEntries + nameDirectory->NumberOfNamedEntries;\n    resourceName = PTR_ADD_OFFSET(nameDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n\n    if (ResourceIndex < 0) // RT_ICON and DEVPKEY_DeviceClass_IconPath\n    {\n        for (resourceIndex = 0; resourceIndex < resourceCount; resourceIndex++)\n        {\n            if (resourceName[resourceIndex].NameIsString)\n                continue;\n            if (resourceName[resourceIndex].Name == (ULONG)-ResourceIndex)\n                break;\n        }\n    }\n    else // RT_GROUP_ICON\n    {\n        resourceIndex = ResourceIndex;\n    }\n\n    if (resourceIndex >= resourceCount)\n        return STATUS_RESOURCE_NAME_NOT_FOUND;\n    if (!resourceName[resourceIndex].DataIsDirectory)\n        return STATUS_RESOURCE_NAME_NOT_FOUND;\n\n    // Find the language\n    languageDirectory = PTR_ADD_OFFSET(ResourceDirectory, resourceName[resourceIndex].OffsetToDirectory);\n    //resourceCount = languageDirectory->NumberOfIdEntries + languageDirectory->NumberOfNamedEntries;\n    resourceLanguage = PTR_ADD_OFFSET(languageDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n    resourceIndex = 0; // use the first entry\n\n    if (resourceLanguage[resourceIndex].DataIsDirectory)\n        return STATUS_RESOURCE_LANG_NOT_FOUND;\n\n    resourceData = PTR_ADD_OFFSET(ResourceDirectory, resourceLanguage[resourceIndex].OffsetToData);\n\n    if (!resourceData)\n        return STATUS_RESOURCE_DATA_NOT_FOUND;\n\n    resourceBuffer = PhMappedImageRvaToVa(MappedImage, resourceData->OffsetToData, NULL);\n\n    if (!resourceBuffer)\n        return STATUS_RESOURCE_DATA_NOT_FOUND;\n\n    if (ResourceLength)\n        *ResourceLength = resourceData->Size;\n    if (ResourceBuffer)\n        *ResourceBuffer = resourceBuffer;\n\n    // if (LDR_IS_IMAGEMAPPING(ImageBaseAddress))\n    // PhLoaderEntryImageRvaToVa(ImageBaseAddress, resourceData->OffsetToData, resourceBuffer);\n    // PhLoadResource(ImageBaseAddress, MAKEINTRESOURCE(ResourceIndex), ResourceType, &resourceLength, &resourceBuffer);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageTlsCallbackDirectory32(\n    _Out_ PPH_MAPPED_IMAGE_TLS_CALLBACKS TlsCallbacks,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_TLS_DIRECTORY32 tlsDirectory;\n    ULONG tlsCallbacksOffset;\n\n    // Get a pointer to the TLS directory.\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_TLS,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    tlsDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!tlsDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, tlsDirectory, sizeof(IMAGE_TLS_DIRECTORY32));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    TlsCallbacks->DataDirectory = dataDirectory;\n    TlsCallbacks->TlsDirectory32 = tlsDirectory;\n\n    if (tlsDirectory->StartAddressOfRawData > MappedImage->NtHeaders32->OptionalHeader.ImageBase)\n        tlsCallbacksOffset = MappedImage->NtHeaders32->OptionalHeader.ImageBase;\n    else\n        tlsCallbacksOffset = 0;\n\n    //TlsCallbacks->CallbackIndexes = PhMappedImageRvaToVa(MappedImage, PtrToUlong(PTR_SUB_OFFSET(tlsDirectory->AddressOfIndex, tlsCallbacksOffset)), NULL);\n    TlsCallbacks->CallbackAddress = PhMappedImageRvaToVa(MappedImage, (tlsDirectory->AddressOfCallBacks - tlsCallbacksOffset), NULL);\n\n    if (TlsCallbacks->CallbackAddress)\n        return STATUS_SUCCESS;\n\n    return STATUS_INVALID_PARAMETER;\n}\n\nNTSTATUS PhGetMappedImageTlsCallbackDirectory64(\n    _Out_ PPH_MAPPED_IMAGE_TLS_CALLBACKS TlsCallbacks,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_TLS_DIRECTORY64 tlsDirectory;\n    ULONG_PTR tlsCallbacksOffset;\n\n    // Get a pointer to the TLS directory.\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_TLS,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    tlsDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!tlsDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, tlsDirectory, sizeof(IMAGE_TLS_DIRECTORY64));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    TlsCallbacks->DataDirectory = dataDirectory;\n    TlsCallbacks->TlsDirectory64 = tlsDirectory;\n\n    if (tlsDirectory->StartAddressOfRawData > MappedImage->NtHeaders->OptionalHeader.ImageBase)\n        tlsCallbacksOffset = MappedImage->NtHeaders->OptionalHeader.ImageBase;\n    else\n        tlsCallbacksOffset = 0;\n\n    //TlsCallbacks->CallbackIndexes = PhMappedImageRvaToVa(MappedImage, PtrToUlong(PTR_SUB_OFFSET(tlsDirectory->AddressOfIndex, tlsCallbacksOffset)), NULL);\n    TlsCallbacks->CallbackAddress = PhMappedImageRvaToVa(MappedImage, PtrToUlong(PTR_SUB_OFFSET(tlsDirectory->AddressOfCallBacks, tlsCallbacksOffset)), NULL);\n\n    if (TlsCallbacks->CallbackAddress)\n        return STATUS_SUCCESS;\n\n    return STATUS_INVALID_PARAMETER;\n}\n\nNTSTATUS PhGetMappedImageTlsCallbacks(\n    _Out_ PPH_MAPPED_IMAGE_TLS_CALLBACKS TlsCallbacks,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    ULONG count = 0;\n    PH_ARRAY entryArray;\n\n    // Get a pointer to the TLS directory.\n\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n        status = PhGetMappedImageTlsCallbackDirectory32(TlsCallbacks, MappedImage);\n    else\n        status = PhGetMappedImageTlsCallbackDirectory64(TlsCallbacks, MappedImage);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Do a scan to determine how many callbacks there are.\n\n    if (TlsCallbacks->CallbackAddress)\n    {\n        if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n        {\n            PULONG array = (PULONG)(PULONG_PTR)TlsCallbacks->CallbackAddress;\n\n            for (ULONG i = 0; array[i]; i++)\n                count++;\n        }\n        else\n        {\n            PULONGLONG array = (PULONGLONG)(PULONG_PTR)TlsCallbacks->CallbackAddress;\n\n            for (ULONG i = 0; array[i]; i++)\n                count++;\n        }\n    }\n\n    if (count == 0)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    // Allocate the number of TLS callbacks.\n\n    PhInitializeArray(&entryArray, sizeof(PH_IMAGE_TLS_CALLBACK_ENTRY), count);\n\n    // Add the TLS callbacks into our buffer.\n\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PULONG array = (PULONG)(PULONG_PTR)TlsCallbacks->CallbackAddress;\n\n        for (ULONG i = 0; i < count; i++)\n        {\n            PH_IMAGE_TLS_CALLBACK_ENTRY entry;\n\n            entry.Address = array[i];\n            entry.Index = 0; // CallbackIndexes\n\n            PhAddItemArray(&entryArray, &entry);\n        }\n    }\n    else\n    {\n        PULONGLONG array = (PULONGLONG)(PULONG_PTR)TlsCallbacks->CallbackAddress;\n\n        for (ULONG i = 0; i < count; i++)\n        {\n            PH_IMAGE_TLS_CALLBACK_ENTRY entry;\n\n            entry.Address = array[i];\n            entry.Index = 0; // CallbackIndexes\n\n            PhAddItemArray(&entryArray, &entry);\n        }\n    }\n\n    TlsCallbacks->NumberOfEntries = count;\n    TlsCallbacks->Entries = PhFinalArrayItems(&entryArray);\n\n    return status;\n}\n\nNTSTATUS PhGetMappedImageProdIdHeader(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_PRODID ProdIdHeader\n    )\n{\n    PIMAGE_DOS_HEADER imageDosHeader = NULL;\n    PIMAGE_NT_HEADERS imageNtHeader = NULL;\n    PPRODITEM richHeaderStart = NULL; // PTR_ADD_OFFSET(imageDosHeader, 0x80)\n    PPRODITEM richHeaderEnd = NULL; // PTR_SUB_OFFSET(imageNtHeader, 0x0);\n    PPRODITEM richHeaderChecksum = NULL; // PTR_SUB_OFFSET(imageNtHeader, 0x10);\n    ULONG ntHeadersOffset = ULONG_MAX;\n    ULONG richHeaderKey = ULONG_MAX;\n    ULONG richHeaderValue = ULONG_MAX;\n    ULONG richStartSignature = ULONG_MAX;\n    ULONG richEndSignature = ULONG_MAX;\n    ULONG richHeaderStartOffset = ULONG_MAX;\n    ULONG richHeaderEndOffset = ULONG_MAX;\n    ULONG richHeaderLength = ULONG_MAX;\n    PH_ARRAY richHeaderEntryArray;\n\n    imageDosHeader = (PIMAGE_DOS_HEADER)MappedImage->ViewBase;\n\n    if (imageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)\n        return STATUS_INVALID_IMAGE_NOT_MZ;\n\n    ntHeadersOffset = (ULONG)imageDosHeader->e_lfanew;\n\n    if (ntHeadersOffset == 0 || ntHeadersOffset >= RTL_IMAGE_MAX_DOS_HEADER)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    imageNtHeader = PTR_ADD_OFFSET(MappedImage->ViewBase, ntHeadersOffset);\n\n    if (imageNtHeader->Signature == IMAGE_NT_SIGNATURE)\n    {\n        PBYTE startHeaderAddress = PTR_ADD_OFFSET(MappedImage->ViewBase, ntHeadersOffset);\n        PBYTE endHeaderAddress = PTR_ADD_OFFSET(MappedImage->ViewBase, sizeof(IMAGE_DOS_HEADER));\n\n        for (PBYTE i = startHeaderAddress; i >= endHeaderAddress; i -= sizeof(ULONG))\n        {\n            __try\n            {\n                if (*(PULONG)i == ProdIdTagStart)\n                {\n                    richHeaderEndOffset = PtrToUlong(PTR_SUB_OFFSET(i, MappedImage->ViewBase));\n                    break;\n                }\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    if (richHeaderEndOffset == ULONG_MAX)\n        return STATUS_FAIL_CHECK;\n\n    richHeaderChecksum = PTR_ADD_OFFSET(MappedImage->ViewBase, richHeaderEndOffset);\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, richHeaderChecksum, sizeof(PRODITEM));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    richHeaderKey = richHeaderChecksum->dwCount;\n    richStartSignature = richHeaderChecksum->dwProdid;\n\n    if (richHeaderKey && richStartSignature)\n    {\n        PBYTE startHeaderAddress = PTR_ADD_OFFSET(MappedImage->ViewBase, ntHeadersOffset);\n        PBYTE endHeaderAddress = PTR_ADD_OFFSET(MappedImage->ViewBase, sizeof(IMAGE_DOS_HEADER));\n\n        for (PBYTE i = startHeaderAddress; i >= endHeaderAddress; i -= sizeof(ULONG))\n        {\n            __try\n            {\n                if ((*(PULONG)i ^ richHeaderKey) == ProdIdTagEnd)\n                {\n                    richHeaderStartOffset = PtrToUlong(PTR_SUB_OFFSET(i, MappedImage->ViewBase));\n                    break;\n                }\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    if (richHeaderStartOffset == ULONG_MAX)\n        return STATUS_FAIL_CHECK;\n\n    richHeaderValue = richHeaderStartOffset;\n    richHeaderStart = PTR_ADD_OFFSET(MappedImage->ViewBase, richHeaderStartOffset);\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, richHeaderStart, sizeof(PRODITEM));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    richHeaderEnd = PTR_ADD_OFFSET(MappedImage->ViewBase, richHeaderEndOffset + sizeof(PRODITEM));\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, richHeaderEnd, sizeof(PRODITEM));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    richHeaderLength = PtrToUlong(PTR_SUB_OFFSET(richHeaderEnd, richHeaderStart));\n    richEndSignature = richHeaderStart->dwProdid ^ richHeaderKey;\n\n    if (richStartSignature == ProdIdTagStart && richEndSignature == ProdIdTagEnd)\n    {\n        PPH_STRING hashRawContentString = NULL;\n        PPH_STRING hashContentString = NULL;\n        ULONG currentCount = 0;\n        PBYTE currentAddress;\n        PBYTE currentEnd;\n        PBYTE offset;\n\n        currentAddress = PTR_ADD_OFFSET(richHeaderStart, 0);\n        currentEnd = PTR_SUB_OFFSET(richHeaderEnd, 0);\n\n        __try\n        {\n            PH_HASH_CONTEXT hashContext;\n            PPH_STRING hashString = NULL;\n\n            if (NT_SUCCESS(PhInitializeHash(&hashContext, Md5HashAlgorithm)))\n            {\n                if (NT_SUCCESS(PhUpdateHash(&hashContext, richHeaderStart, richHeaderLength)))\n                {\n                    if (NT_SUCCESS(PhFinalHashString(&hashContext, &hashString)))\n                    {\n                        hashRawContentString = hashString;\n                    }\n                }\n            }\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n\n        if (PhIsNullOrEmptyString(hashRawContentString))\n            return STATUS_FAIL_CHECK;\n\n        // VT creates a different hash based on the decrypted header while other tools\n        // (including this one) create the hash based on the raw header. So create a second hash\n        // from the decrypted header so we can show and search both hashes (dmex)\n        {\n            PVOID richHeaderContentEnd;\n            ULONG richHeaderContentLength;\n            PULONG richHeaderContentBuffer;\n            PULONG richHeaderContentOffset;\n            PH_HASH_CONTEXT hashContext;\n            UCHAR hash[PH_HASH_MD5_LENGTH];\n\n            // Recalculate the length needed for the hash since VT doesn't include the remaining entry.\n            richHeaderContentEnd = PTR_ADD_OFFSET(MappedImage->ViewBase, richHeaderEndOffset);\n            richHeaderContentLength = PtrToUlong(PTR_SUB_OFFSET(richHeaderContentEnd, richHeaderStart));\n\n            // We already probed above so this isn't really needed but probe again just to be sure.\n            __try\n            {\n                PhMappedImageProbe(MappedImage, richHeaderStart, richHeaderContentLength);\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n\n            richHeaderContentBuffer = PhAllocateZero(richHeaderContentLength);\n            memcpy(richHeaderContentBuffer, richHeaderStart, richHeaderContentLength);\n\n            // Walk the buffer and decrypt the entire thing. Based on the same loop used by yara:\n            // https://github.com/VirusTotal/yara/blob/master/libyara/modules/pe/pe.c#L251-L259\n            for (\n                richHeaderContentOffset = richHeaderContentBuffer;\n                richHeaderContentOffset < (PULONG)PTR_ADD_OFFSET(richHeaderContentBuffer, richHeaderContentLength);\n                richHeaderContentOffset++\n                )\n            {\n                *richHeaderContentOffset ^= richHeaderKey;\n            }\n\n            if (NT_SUCCESS(PhInitializeHash(&hashContext, Md5HashAlgorithm)))\n            {\n                if (NT_SUCCESS(PhUpdateHash(&hashContext, richHeaderContentBuffer, richHeaderContentLength)))\n                {\n                    if (NT_SUCCESS(PhFinalHash(&hashContext, hash, sizeof(hash), NULL)))\n                    {\n                        hashContentString = PhBufferToHexString(hash, sizeof(hash));\n                    }\n                }\n            }\n\n            PhFree(richHeaderContentBuffer);\n        }\n\n        if (PhIsNullOrEmptyString(hashContentString))\n            return STATUS_FAIL_CHECK;\n\n        // Do a scan to determine how many entries there are.\n        for (offset = currentAddress; offset < currentEnd; offset += sizeof(PRODITEM))\n        {\n            currentCount++;\n        }\n\n        // Compute the DOS header and DOS stub checksums.\n        for (ULONG i = 0; i < richHeaderStartOffset; i++)\n        {\n            BYTE value;\n\n            // Skip the e_lfanew field.\n            if (i >= UFIELD_OFFSET(IMAGE_DOS_HEADER, e_lfanew) &&\n                i <= UFIELD_OFFSET(IMAGE_DOS_HEADER, e_lfanew) + RTL_FIELD_SIZE(IMAGE_DOS_HEADER, e_lfanew) - sizeof(BYTE))\n            {\n                continue;\n            }\n\n            __try\n            {\n                value = *(PBYTE)PTR_ADD_OFFSET(imageDosHeader, UInt32x32To64(i, sizeof(BYTE)));\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n\n            richHeaderValue += _rotl(value, i);\n        }\n\n        // Compute each of the RICH entry value checksums.\n        for (ULONG i = 0; i < currentCount; i++)\n        {\n            PPRODITEM entry;\n            ULONG prodid;\n            ULONG count;\n\n            entry = PTR_ADD_OFFSET(currentAddress, UInt32x32To64(i, sizeof(PRODITEM)));\n\n            __try\n            {\n                PhMappedImageProbe(MappedImage, entry, sizeof(PRODITEM));\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n\n            prodid = entry->dwProdid ^ richHeaderKey;\n            count = entry->dwCount ^ richHeaderKey;\n\n            if (count > 0 && count != richHeaderKey)\n            {\n                richHeaderValue += _rotl((ProdidFromDwProdid(prodid) << 16 | WBuildFromDwProdid(prodid)), count & 0x1F);\n            }\n        }\n\n        // Allocate the number of product entries.\n\n        PhInitializeArray(&richHeaderEntryArray, sizeof(PH_MAPPED_IMAGE_PRODID_ENTRY), currentCount);\n\n        // Add the product entries into our buffer.\n\n        for (ULONG i = 0; i < currentCount; i++)\n        {\n            PPRODITEM item = PTR_ADD_OFFSET(currentAddress, UInt32x32To64(i, sizeof(PRODITEM)));\n\n            __try\n            {\n                PhMappedImageProbe(MappedImage, item, sizeof(PRODITEM));\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n\n            // The prodid header can include 3 extra checksum values. Ignore these for now (dmex)\n            if ((item->dwCount ^ richHeaderKey) != richHeaderKey)\n            {\n                PH_MAPPED_IMAGE_PRODID_ENTRY entry;\n\n                entry.ProductId = ProdidFromDwProdid(item->dwProdid ^ richHeaderKey);\n                entry.ProductBuild = WBuildFromDwProdid(item->dwProdid ^ richHeaderKey);\n                entry.ProductCount = item->dwCount ^ richHeaderKey;\n\n                PhAddItemArray(&richHeaderEntryArray, &entry);\n            }\n        }\n\n        //PhPrintPointer(ProdIdHeader->Key, UlongToPtr(richHeaderKey));\n        ProdIdHeader->Valid = richHeaderKey == richHeaderValue;\n        ProdIdHeader->Key = PhFormatString(L\"%lx\", richHeaderKey);\n        ProdIdHeader->RawHash = hashRawContentString;\n        ProdIdHeader->Hash = hashContentString;\n        ProdIdHeader->NumberOfEntries = currentCount;\n        ProdIdHeader->ProdIdEntries = PhFinalArrayItems(&richHeaderEntryArray);\n\n        //for (offset = currentAddress; offset < currentEnd; offset += sizeof(PRODITEM))\n        //{\n        //    PPRODITEM entry = (PPRODITEM)offset;\n        //    ULONG prodid = ProdidFromDwProdid(entry->dwProdid ^ richHeaderKey);\n        //    ULONG build = WBuildFromDwProdid(entry->dwProdid ^ richHeaderKey);\n        //    ULONG count = entry->dwCount ^ richHeaderKey;\n        //    dprintf(\"%x %x %x\\n\", prodid, build, count);\n        //}\n\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_FAIL_CHECK;\n}\n\nNTSTATUS PhGetMappedImageProdIdExtents(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PULONG ProdIdHeaderStart,\n    _Out_ PULONG ProdIdHeaderEnd\n    )\n{\n    PIMAGE_DOS_HEADER imageDosHeader = NULL;\n    PIMAGE_NT_HEADERS imageNtHeader = NULL;\n    PPRODITEM richHeaderStart = NULL;\n    PPRODITEM richHeaderEnd = NULL;\n    PPRODITEM richHeaderChecksum = NULL;\n    ULONG ntHeadersOffset = ULONG_MAX;\n    ULONG richHeaderKey = ULONG_MAX;\n    ULONG richStartSignature = ULONG_MAX;\n    ULONG richEndSignature = ULONG_MAX;\n    ULONG richHeaderStartOffset = ULONG_MAX;\n    ULONG richHeaderEndOffset = ULONG_MAX;\n\n    imageDosHeader = (PIMAGE_DOS_HEADER)MappedImage->ViewBase;\n\n    if (imageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)\n        return STATUS_INVALID_IMAGE_NOT_MZ;\n\n    ntHeadersOffset = (ULONG)imageDosHeader->e_lfanew;\n\n    if (ntHeadersOffset == 0 || ntHeadersOffset >= RTL_IMAGE_MAX_DOS_HEADER)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    imageNtHeader = PTR_ADD_OFFSET(MappedImage->ViewBase, ntHeadersOffset);\n\n    if (imageNtHeader->Signature == IMAGE_NT_SIGNATURE)\n    {\n        PBYTE startHeaderAddress = PTR_ADD_OFFSET(MappedImage->ViewBase, ntHeadersOffset);\n        PBYTE endHeaderAddress = PTR_ADD_OFFSET(MappedImage->ViewBase, sizeof(IMAGE_DOS_HEADER));\n\n        for (PBYTE i = startHeaderAddress; i >= endHeaderAddress; i -= sizeof(ULONG))\n        {\n            __try\n            {\n                if (*(PULONG)i == ProdIdTagStart)\n                {\n                    richHeaderEndOffset = PtrToUlong(PTR_SUB_OFFSET(i, MappedImage->ViewBase));\n                    break;\n                }\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    if (richHeaderEndOffset == ULONG_MAX)\n        return STATUS_FAIL_CHECK;\n\n    richHeaderChecksum = PTR_ADD_OFFSET(MappedImage->ViewBase, richHeaderEndOffset);\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, richHeaderChecksum, sizeof(PRODITEM));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    richHeaderKey = richHeaderChecksum->dwCount;\n    richStartSignature = richHeaderChecksum->dwProdid;\n\n    if (richHeaderKey && richStartSignature)\n    {\n        PBYTE startHeaderAddress = PTR_ADD_OFFSET(MappedImage->ViewBase, ntHeadersOffset);\n        PBYTE endHeaderAddress = PTR_ADD_OFFSET(MappedImage->ViewBase, sizeof(IMAGE_DOS_HEADER));\n\n        for (PBYTE i = startHeaderAddress; i >= endHeaderAddress; i -= sizeof(ULONG))\n        {\n            __try\n            {\n                if ((*(PULONG)i ^ richHeaderKey) == ProdIdTagEnd)\n                {\n                    richHeaderStartOffset = PtrToUlong(PTR_SUB_OFFSET(i, MappedImage->ViewBase));\n                    break;\n                }\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    if (richHeaderStartOffset == ULONG_MAX)\n        return STATUS_FAIL_CHECK;\n\n    richHeaderStart = PTR_ADD_OFFSET(MappedImage->ViewBase, richHeaderStartOffset);\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, richHeaderStart, sizeof(PRODITEM));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    richHeaderEnd = PTR_ADD_OFFSET(MappedImage->ViewBase, richHeaderEndOffset + sizeof(PRODITEM));\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, richHeaderEnd, sizeof(PRODITEM));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    richEndSignature = richHeaderStart->dwProdid ^ richHeaderKey;\n\n    if (richStartSignature == ProdIdTagStart && richEndSignature == ProdIdTagEnd)\n    {\n        ULONG richHeaderTotalLength;\n        ULONG currentCount = 0;\n        PBYTE currentAddress;\n        PBYTE currentEnd;\n        PBYTE offset;\n\n        currentAddress = PTR_ADD_OFFSET(richHeaderStart, 0);\n        currentEnd = PTR_SUB_OFFSET(richHeaderEnd, 0);\n\n        // Do a scan to determine how many entries there are.\n        for (offset = currentAddress; offset < currentEnd; offset += sizeof(PRODITEM))\n        {\n            currentCount++;\n        }\n\n        // Calculate rich header and rich header padding. (Todo: Generate richHeaderKey and validate).\n        richHeaderTotalLength = (richHeaderKey >> 5) % 3;\n        richHeaderTotalLength += currentCount - 3; // remove 3 fixed checksum entries.\n        richHeaderTotalLength *= sizeof(PRODITEM);\n        richHeaderTotalLength += sizeof(PRODITEM) * 4; // add 3 fixed checksums and 1 null entry (0x20).\n        richHeaderTotalLength += richHeaderStartOffset;\n\n        // If we assert then the image has hidden data or the rich format changed.\n        assert(richHeaderTotalLength == ntHeadersOffset);\n\n        *ProdIdHeaderStart = richHeaderStartOffset;\n        *ProdIdHeaderEnd = richHeaderTotalLength;\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nNTSTATUS PhGetMappedImageDebug(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_DEBUG Debug\n    )\n{\n    NTSTATUS status;\n    ULONG currentCount;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_DEBUG_DIRECTORY debugDirectory;\n    PH_ARRAY debugEntryArray;\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_DEBUG,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    debugDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!debugDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, debugDirectory, sizeof(IMAGE_DEBUG_DIRECTORY));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    currentCount = dataDirectory->Size / sizeof(IMAGE_DEBUG_DIRECTORY);\n\n    // Allocate the number of debug entries.\n\n    PhInitializeArray(&debugEntryArray, sizeof(PH_IMAGE_DEBUG_ENTRY), currentCount);\n\n    // Add the debug entries into our buffer.\n\n    for (ULONG i = 0; i < currentCount; i++)\n    {\n        PIMAGE_DEBUG_DIRECTORY item = PTR_ADD_OFFSET(debugDirectory, UInt32x32To64(i, sizeof(IMAGE_DEBUG_DIRECTORY)));\n\n        __try\n        {\n            PhMappedImageProbe(MappedImage, item, sizeof(IMAGE_DEBUG_DIRECTORY));\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            break;\n        }\n\n        PH_IMAGE_DEBUG_ENTRY entry;\n\n        entry.Characteristics = item->Characteristics;\n        entry.TimeDateStamp = item->TimeDateStamp;\n        entry.MajorVersion = item->MajorVersion;\n        entry.MinorVersion = item->MinorVersion;\n        entry.Type = item->Type;\n        entry.SizeOfData = item->SizeOfData;\n        entry.AddressOfRawData = item->AddressOfRawData;\n        entry.PointerToRawData = item->PointerToRawData;\n\n        PhAddItemArray(&debugEntryArray, &entry);\n    }\n\n    Debug->MappedImage = MappedImage;\n    Debug->DataDirectory = dataDirectory;\n    Debug->DebugDirectory = debugDirectory;\n    Debug->NumberOfEntries = currentCount;\n    Debug->DebugEntries = PhFinalArrayItems(&debugEntryArray);\n\n    return status;\n}\n\nNTSTATUS PhGetMappedImageDebugEntryByType(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Type,\n    _Out_opt_ ULONG* DataLength,\n    _Out_opt_ PVOID* DataBuffer\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_DEBUG_DIRECTORY debugDirectory;\n    PIMAGE_DEBUG_DIRECTORY debugEntry;\n    ULONG currentCount;\n    ULONG i;\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_DEBUG,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    debugDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!debugDirectory)\n        return STATUS_UNSUCCESSFUL;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, debugDirectory, sizeof(IMAGE_DEBUG_DIRECTORY));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    currentCount = dataDirectory->Size / sizeof(IMAGE_DEBUG_DIRECTORY);\n\n    for (i = 0; i < currentCount; i++)\n    {\n        debugEntry = PTR_ADD_OFFSET(debugDirectory, UInt32x32To64(i, sizeof(IMAGE_DEBUG_DIRECTORY)));\n\n        __try\n        {\n            PhMappedImageProbe(MappedImage, debugEntry, sizeof(IMAGE_DEBUG_DIRECTORY));\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            break;\n        }\n\n        if (debugEntry->Type == Type)\n        {\n            if (DataLength)\n                *DataLength = debugEntry->SizeOfData;\n            if (DataBuffer)\n                *DataBuffer = PTR_ADD_OFFSET(MappedImage->ViewBase, debugEntry->PointerToRawData);\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nNTSTATUS PhGetMappedImageEhCont32(\n    _Out_ PPH_MAPPED_IMAGE_EH_CONT EhContConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_LOAD_CONFIG_DIRECTORY32 config32;\n\n    if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig32(MappedImage, &config32)))\n        return status;\n\n    // Not every load configuration contains eh continuation\n    if (!RTL_CONTAINS_FIELD(config32, config32->Size, GuardEHContinuationCount))\n        return STATUS_INVALID_VIEW_SIZE;\n\n    EhContConfig->EhContTable = PhMappedImageVaToVa(MappedImage, config32->GuardEHContinuationTable, NULL);\n    EhContConfig->NumberOfEhContEntries = config32->GuardEHContinuationCount;\n\n    // taken from nt!RtlGuardRestoreContext\n    EhContConfig->EntrySize = ((config32->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT) + sizeof(ULONG);\n\n    if (EhContConfig->EhContTable && EhContConfig->NumberOfEhContEntries)\n    {\n        __try\n        {\n            PhMappedImageProbe(\n                MappedImage,\n                EhContConfig->EhContTable,\n                (SIZE_T)(EhContConfig->NumberOfEhContEntries * EhContConfig->EntrySize)\n                );\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageEhCont64(\n    _Out_ PPH_MAPPED_IMAGE_EH_CONT EhContConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_LOAD_CONFIG_DIRECTORY64 config64;\n\n    if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig64(MappedImage, &config64)))\n        return status;\n\n    // Not every load configuration contains eh continuation\n    if (!RTL_CONTAINS_FIELD(config64, config64->Size, GuardEHContinuationCount))\n        return STATUS_INVALID_VIEW_SIZE;\n\n    EhContConfig->EhContTable = PhMappedImageVaToVa(MappedImage, config64->GuardEHContinuationTable, NULL);\n    EhContConfig->NumberOfEhContEntries = config64->GuardEHContinuationCount;\n\n    // taken from nt!RtlGuardRestoreContext\n    EhContConfig->EntrySize = ((config64->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT) + sizeof(ULONG);\n\n    if (EhContConfig->EhContTable && EhContConfig->NumberOfEhContEntries)\n    {\n        __try\n        {\n            PhMappedImageProbe(\n                MappedImage,\n                EhContConfig->EhContTable,\n                (SIZE_T)(EhContConfig->NumberOfEhContEntries * EhContConfig->EntrySize)\n                );\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageEhCont(\n    _Out_ PPH_MAPPED_IMAGE_EH_CONT EhContConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        return PhGetMappedImageEhCont32(EhContConfig, MappedImage);\n    }\n    else\n    {\n        return PhGetMappedImageEhCont64(EhContConfig, MappedImage);\n    }\n}\n\n_Success_(return)\nBOOLEAN PhGetMappedImagePogoEntryByName(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PCSTR Name,\n    _Out_opt_ ULONG* DataLength,\n    _Out_opt_ PVOID* DataBuffer\n    )\n{\n    ULONG debugEntryLength;\n    PIMAGE_DEBUG_POGO_SIGNATURE debugEntry;\n    PIMAGE_DEBUG_POGO_ENTRY debugPogoEntry;\n\n    if (!NT_SUCCESS(PhGetMappedImageDebugEntryByType(\n        MappedImage,\n        IMAGE_DEBUG_TYPE_POGO,\n        &debugEntryLength,\n        &debugEntry\n        )))\n    {\n        return FALSE;\n    }\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, debugEntry, sizeof(IMAGE_DEBUG_POGO_SIGNATURE));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return FALSE;\n    }\n\n    if (debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_LTCG && debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_PGI && debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_PGO && debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_PGU && debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_SPGO)\n    {\n        // The signature can be zero but still contain valid entries.\n        if (!(debugEntry->Signature == 0 && debugEntryLength > sizeof(IMAGE_DEBUG_POGO_SIGNATURE)))\n            return FALSE;\n    }\n\n    debugPogoEntry = PTR_ADD_OFFSET(debugEntry, sizeof(IMAGE_DEBUG_POGO_SIGNATURE));\n\n    while ((ULONG_PTR)debugPogoEntry < (ULONG_PTR)PTR_ADD_OFFSET(debugEntry, debugEntryLength))\n    {\n        __try\n        {\n            PhMappedImageProbe(MappedImage, debugPogoEntry, sizeof(IMAGE_DEBUG_POGO_ENTRY));\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return FALSE;\n        }\n\n        if (!(debugPogoEntry->Rva && debugPogoEntry->Size))\n            break;\n\n        if (PhEqualBytesZ(debugPogoEntry->Name, Name, TRUE))\n        {\n            if (DataLength)\n            {\n                *DataLength = debugPogoEntry->Size;\n            }\n\n            if (DataBuffer)\n            {\n                *DataBuffer = PTR_ADD_OFFSET(MappedImage->ViewBase, debugPogoEntry->Rva);\n            }\n\n            return TRUE;\n        }\n\n        debugPogoEntry = PTR_ADD_OFFSET(debugPogoEntry, ALIGN_UP(UFIELD_OFFSET(IMAGE_DEBUG_POGO_ENTRY, Name) + strlen(debugPogoEntry->Name) + sizeof(ANSI_NULL), ULONG));\n    }\n\n    return FALSE;\n}\n\nNTSTATUS PhGetMappedImagePogo(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_DEBUG_POGO PogoDebug\n    )\n{\n    ULONG debugEntryCount = 0;\n    ULONG debugEntryLength = 0;\n    PIMAGE_DEBUG_POGO_SIGNATURE debugEntry;\n    PIMAGE_DEBUG_POGO_ENTRY debugPogoEntry;\n    PH_ARRAY pogoArray;\n\n    if (!NT_SUCCESS(PhGetMappedImageDebugEntryByType(\n        MappedImage,\n        IMAGE_DEBUG_TYPE_POGO,\n        &debugEntryLength,\n        &debugEntry\n        )))\n    {\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, debugEntry, sizeof(IMAGE_DEBUG_POGO_SIGNATURE));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    if (debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_LTCG && debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_PGI && debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_PGO && debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_PGU && debugEntry->Signature != IMAGE_DEBUG_POGO_SIGNATURE_SPGO)\n    {\n        // The signature can be zero but still contain valid entries.\n        if (!(debugEntry->Signature == 0 && debugEntryLength > sizeof(IMAGE_DEBUG_POGO_SIGNATURE)))\n            return STATUS_UNSUCCESSFUL;\n    }\n\n    // Skip the signature.\n\n    debugPogoEntry = PTR_ADD_OFFSET(debugEntry, sizeof(IMAGE_DEBUG_POGO_SIGNATURE));\n\n    // Do a scan to determine how many entries there are.\n\n    while ((ULONG_PTR)debugPogoEntry < (ULONG_PTR)PTR_ADD_OFFSET(debugEntry, debugEntryLength))\n    {\n        __try\n        {\n            PhMappedImageProbe(MappedImage, debugPogoEntry, sizeof(IMAGE_DEBUG_POGO_ENTRY));\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n\n        debugEntryCount++;\n\n        debugPogoEntry = PTR_ADD_OFFSET(debugPogoEntry, ALIGN_UP(UFIELD_OFFSET(IMAGE_DEBUG_POGO_ENTRY, Name) + strlen(debugPogoEntry->Name) + sizeof(ANSI_NULL), ULONG));\n    }\n\n    // Allocate the number of pogo entries.\n\n    PhInitializeArray(&pogoArray, sizeof(PH_IMAGE_DEBUG_POGO_ENTRY), debugEntryCount);\n\n    // Add the debug entries into our buffer.\n\n    debugPogoEntry = PTR_ADD_OFFSET(debugEntry, sizeof(IMAGE_DEBUG_POGO_SIGNATURE));\n\n    while ((ULONG_PTR)debugPogoEntry < (ULONG_PTR)PTR_ADD_OFFSET(debugEntry, debugEntryLength))\n    {\n        if (!(debugPogoEntry->Rva && debugPogoEntry->Size))\n            break;\n\n        {\n            PH_IMAGE_DEBUG_POGO_ENTRY entry;\n\n            memset(entry.Name, ANSI_NULL, sizeof(entry.Name));\n            entry.Rva = debugPogoEntry->Rva;\n            entry.Size = debugPogoEntry->Size;\n            entry.Data = PhMappedImageRvaToVa(MappedImage, debugPogoEntry->Rva, NULL);\n\n            PhCopyStringZFromUtf8(\n                debugPogoEntry->Name,\n                SIZE_MAX,\n                entry.Name,\n                RTL_NUMBER_OF(entry.Name),\n                NULL\n                );\n\n            PhAddItemArray(&pogoArray, &entry);\n        }\n\n        debugPogoEntry = PTR_ADD_OFFSET(debugPogoEntry, ALIGN_UP(UFIELD_OFFSET(IMAGE_DEBUG_POGO_ENTRY, Name) + strlen(debugPogoEntry->Name) + sizeof(ANSI_NULL), ULONG));\n    }\n\n    PogoDebug->PogoDirectory = debugEntry;\n    PogoDebug->NumberOfEntries = debugEntryCount;\n    PogoDebug->PogoEntries = PhFinalArrayItems(&pogoArray);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves base relocation information from a mapped PE image.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Relocations A pointer to a structure that receives the relocation information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetMappedImageRelocations(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_RELOC Relocations\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_BASE_RELOCATION relocationDirectory;\n    PVOID relocationDirectoryEnd;\n    PH_ARRAY relocationArray;\n    ULONG relocationTotal = 0;\n    ULONG relocationIndex = 0;\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_BASERELOC,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    relocationDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!relocationDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    Relocations->MappedImage = MappedImage;\n    Relocations->DataDirectory = dataDirectory;\n    Relocations->FirstRelocationDirectory = relocationDirectory;\n\n    //\n    // Do a scan to determine how many entries there are. And validate the\n    // blocks are within the mapping.\n    //\n\n    relocationDirectory = Relocations->FirstRelocationDirectory;\n    relocationDirectoryEnd = PTR_ADD_OFFSET(relocationDirectory, dataDirectory->Size);\n\n    while ((ULONG_PTR)relocationDirectory < (ULONG_PTR)relocationDirectoryEnd)\n    {\n        __try\n        {\n            PhMappedImageProbe(MappedImage, relocationDirectory, sizeof(IMAGE_BASE_RELOCATION));\n            PhMappedImageProbe(MappedImage, relocationDirectory, relocationDirectory->SizeOfBlock);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n\n        if (relocationDirectory->SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION))\n        {\n            //\n            // Prevent runaway.\n            //\n            return STATUS_INVALID_IMAGE_FORMAT;\n        }\n\n        relocationTotal += (relocationDirectory->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOCATION_RECORD);\n        relocationDirectory = PTR_ADD_OFFSET(relocationDirectory, relocationDirectory->SizeOfBlock);\n    }\n\n    // Allocate the number of relocation entries.\n\n    PhInitializeArray(&relocationArray, sizeof(PH_IMAGE_RELOC_ENTRY), relocationTotal);\n\n    // Add the relocation entries into our buffer.\n\n    relocationDirectory = Relocations->FirstRelocationDirectory;\n\n    while ((ULONG_PTR)relocationDirectory < (ULONG_PTR)relocationDirectoryEnd)\n    {\n        ULONG relocationCount;\n        PIMAGE_RELOCATION_RECORD relocations;\n\n        relocationCount = (relocationDirectory->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOCATION_RECORD);\n        relocations = PTR_ADD_OFFSET(relocationDirectory, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock));\n\n        for (ULONG i = 0; i < relocationCount; i++)\n        {\n            PH_IMAGE_RELOC_ENTRY entry;\n\n            entry.BlockIndex = relocationIndex;\n            entry.Record.Type = relocations[i].Type;\n            entry.Record.Offset = relocations[i].Offset;\n            entry.BlockRva = relocationDirectory->VirtualAddress;\n\n            if (entry.Record.Type == IMAGE_REL_BASED_ABSOLUTE)\n            {\n                entry.ImageBaseVa = NULL;\n                entry.MappedImageVa = NULL;\n            }\n            else\n            {\n                if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n                    entry.ImageBaseVa = PTR_ADD_OFFSET(MappedImage->NtHeaders->OptionalHeader.ImageBase, UInt32Add32To64(entry.BlockRva, entry.Record.Offset));\n                else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n                    entry.ImageBaseVa = PTR_ADD_OFFSET(MappedImage->NtHeaders32->OptionalHeader.ImageBase, UInt32Add32To64(entry.BlockRva, entry.Record.Offset));\n\n                entry.MappedImageVa = PhMappedImageRvaToVa(MappedImage, UInt32Add32To64(entry.BlockRva, entry.Record.Offset), NULL);\n            }\n\n            PhAddItemArray(&relocationArray, &entry);\n        }\n\n        relocationDirectory = PTR_ADD_OFFSET(relocationDirectory, relocationDirectory->SizeOfBlock);\n        relocationIndex++;\n    }\n\n    Relocations->NumberOfEntries = (ULONG)PhFinalArrayCount(&relocationArray);\n    Relocations->RelocationEntries = PhFinalArrayItems(&relocationArray);\n\n    return status;\n}\n\n/**\n * Releases resources associated with mapped image relocations.\n *\n * \\param Relocations A pointer to the relocation information structure.\n *\n * \\remarks This function frees the relocation entries array allocated by\n * PhGetMappedImageRelocations().\n */\nVOID PhFreeMappedImageRelocations(\n    _In_opt_ PPH_MAPPED_IMAGE_RELOC Relocations\n    )\n{\n    if (Relocations && Relocations->RelocationEntries)\n    {\n        PhFree(Relocations->RelocationEntries);\n        Relocations->RelocationEntries = NULL;\n        Relocations->NumberOfEntries = 0;\n    }\n}\n\n/**\n * Enumerates base relocations in a mapped PE image using a callback function.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Callback A callback function invoked for each relocation entry.\n * \\param Context An optional context pointer passed to the callback.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhMappedImageEnumerateRelocations(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PPH_MAPPED_IMAGE_RELOC_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_BASE_RELOCATION relocationDirectory;\n    PVOID relocationDirectoryEnd;\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_BASERELOC,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    relocationDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!relocationDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    relocationDirectoryEnd = PTR_ADD_OFFSET(relocationDirectory, dataDirectory->Size);\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, relocationDirectory, dataDirectory->Size);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    while ((ULONG_PTR)relocationDirectory < (ULONG_PTR)relocationDirectoryEnd)\n    {\n        ULONG relocationCount;\n        PIMAGE_RELOCATION_RECORD relocations;\n\n        __try\n        {\n            PhMappedImageProbe(MappedImage, relocationDirectory, sizeof(IMAGE_BASE_RELOCATION));\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n\n        if (relocationDirectory->SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION))\n        {\n            //\n            // Prevent runaway.\n            //\n            return STATUS_INVALID_IMAGE_FORMAT;\n        }\n\n        relocationCount = (relocationDirectory->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOCATION_RECORD);\n        relocations = PTR_ADD_OFFSET(relocationDirectory, sizeof(IMAGE_BASE_RELOCATION));\n\n        __try\n        {\n            PhMappedImageProbe(MappedImage, relocations, relocationCount * sizeof(IMAGE_RELOCATION_RECORD));\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n\n        status = Callback(\n            MappedImage,\n            dataDirectory,\n            relocationDirectory,\n            relocations,\n            relocationCount,\n            Context\n            );\n\n        if (status == STATUS_NO_MORE_ENTRIES)\n            break;\n\n        relocationDirectory = PTR_ADD_OFFSET(relocationDirectory, relocationDirectory->SizeOfBlock);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the dynamic relocation table from a mapped PE image.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Table An optional pointer that receives the dynamic relocation table.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetMappedImageDynamicRelocationsTable(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_opt_ PIMAGE_DYNAMIC_RELOCATION_TABLE* Table\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DYNAMIC_RELOCATION_TABLE table = NULL;\n    PVOID reloc;\n\n    if (Table)\n        *Table = NULL;\n\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY32 config32;\n\n        status = PhGetMappedImageLoadConfig32(MappedImage, &config32);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (RTL_CONTAINS_FIELD(config32, config32->Size, DynamicValueRelocTable) && config32->DynamicValueRelocTable)\n        {\n            table = PhMappedImageRvaToVa(MappedImage, config32->DynamicValueRelocTable, NULL);\n        }\n        else if (\n            RTL_CONTAINS_FIELD(config32, config32->Size, DynamicValueRelocTableOffset) && config32->DynamicValueRelocTableOffset &&\n            RTL_CONTAINS_FIELD(config32, config32->Size, DynamicValueRelocTableSection) && config32->DynamicValueRelocTableSection\n            )\n        {\n            if (config32->DynamicValueRelocTableSection <= MappedImage->NumberOfSections)\n            {\n                PIMAGE_SECTION_HEADER section = &MappedImage->Sections[config32->DynamicValueRelocTableSection - 1];\n                PVOID offset = PTR_ADD_OFFSET(section->PointerToRawData, config32->DynamicValueRelocTableOffset);\n\n                if (offset < PTR_ADD_OFFSET(section->PointerToRawData, section->SizeOfRawData))\n                {\n                    table = PTR_ADD_OFFSET(MappedImage->ViewBase, offset);\n                }\n            }\n        }\n    }\n    else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY64 config64;\n\n        status = PhGetMappedImageLoadConfig64(MappedImage, &config64);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (RTL_CONTAINS_FIELD(config64, config64->Size, DynamicValueRelocTable) && config64->DynamicValueRelocTable)\n        {\n            table = PhMappedImageRvaToVa(MappedImage, (ULONG)config64->DynamicValueRelocTable, NULL);\n        }\n        else if (\n            RTL_CONTAINS_FIELD(config64, config64->Size, DynamicValueRelocTableOffset) && config64->DynamicValueRelocTableOffset &&\n            RTL_CONTAINS_FIELD(config64, config64->Size, DynamicValueRelocTableSection) && config64->DynamicValueRelocTableSection\n            )\n        {\n            if (config64->DynamicValueRelocTableSection <= MappedImage->NumberOfSections)\n            {\n                PIMAGE_SECTION_HEADER section = &MappedImage->Sections[config64->DynamicValueRelocTableSection - 1];\n                PVOID offset = PTR_ADD_OFFSET(section->PointerToRawData, config64->DynamicValueRelocTableOffset);\n\n                if (offset < PTR_ADD_OFFSET(section->PointerToRawData, section->SizeOfRawData))\n                {\n                    table = PTR_ADD_OFFSET(MappedImage->ViewBase, offset);\n                }\n            }\n        }\n    }\n    else\n    {\n        return STATUS_INVALID_IMAGE_FORMAT;\n    }\n\n    if (!table)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, table, sizeof(IMAGE_DYNAMIC_RELOCATION_TABLE));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    reloc = PTR_ADD_OFFSET(table, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION_TABLE, Size));\n    __try\n    {\n        PhMappedImageProbe(MappedImage, reloc, table->Size);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    if (Table)\n        *Table = table;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhpFillDynamicRelocations(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONGLONG Symbol,\n    _In_ PIMAGE_BASE_RELOCATION BaseRelocs,\n    _In_ PVOID BaseRelocsEnd,\n    _In_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    if (Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X)\n    {\n        PIMAGE_BASE_RELOCATION base = BaseRelocs;\n\n        for (ULONG blockIndex = 0; ; blockIndex++)\n        {\n            PIMAGE_DVRT_ARM64X_FIXUP_RECORD record;\n            PVOID blockEnd;\n\n            record = (PIMAGE_DVRT_ARM64X_FIXUP_RECORD)base;\n            blockEnd = PTR_ADD_OFFSET(base, base->SizeOfBlock);\n            if (!PhPtrAdvance(&record, blockEnd, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock)))\n                break;\n\n            for (;;)\n            {\n                PH_IMAGE_DYNAMIC_RELOC_ENTRY entry;\n                SIZE_T consumed;\n\n                if (record->Offset == 0 && record->Type == 0 && record->Size == 0)\n                {\n                    // padding block(s), we're done\n                    break;\n                }\n\n                RtlZeroMemory(&entry, sizeof(entry));\n                entry.Symbol = IMAGE_DYNAMIC_RELOCATION_ARM64X;\n                entry.ARM64X.BlockIndex = blockIndex;\n                entry.ARM64X.BlockRva = base->VirtualAddress;\n                entry.ARM64X.RecordFixup = *record;\n\n                entry.ImageBaseVa = PTR_ADD_OFFSET(\n                    MappedImage->NtHeaders->OptionalHeader.ImageBase,\n                    UInt32Add32To64(entry.ARM64X.BlockRva, entry.ARM64X.RecordFixup.Offset)\n                    );\n                entry.MappedImageVa = PhMappedImageRvaToVa(\n                    MappedImage,\n                    UInt32Add32To64(entry.ARM64X.BlockRva, entry.ARM64X.RecordFixup.Offset),\n                    NULL\n                    );\n\n                if (record->Type == IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL)\n                {\n                    entry.ARM64X.Value8 = 0;\n                    consumed = sizeof(IMAGE_DVRT_ARM64X_FIXUP_RECORD);\n                }\n                else if (record->Type == IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE)\n                {\n                    consumed = sizeof(IMAGE_DVRT_ARM64X_FIXUP_RECORD);\n                    if (entry.ARM64X.RecordFixup.Size == IMAGE_DVRT_ARM64X_FIXUP_SIZE_2BYTES)\n                    {\n                        entry.ARM64X.Value2 = *(PUSHORT)PTR_ADD_OFFSET(record, consumed);\n                        consumed += sizeof(USHORT);\n                    }\n                    else if (entry.ARM64X.RecordFixup.Size == IMAGE_DVRT_ARM64X_FIXUP_SIZE_4BYTES)\n                    {\n                        entry.ARM64X.Value4 = *(PULONG)PTR_ADD_OFFSET(record, consumed);\n                        consumed += sizeof(ULONG);\n                    }\n                    else if (entry.ARM64X.RecordFixup.Size == IMAGE_DVRT_ARM64X_FIXUP_SIZE_8BYTES)\n                    {\n                        entry.ARM64X.Value8 = *(PULONG64)PTR_ADD_OFFSET(record, consumed);\n                        consumed += sizeof(ULONG64);\n                    }\n                    else\n                    {\n                        break;\n                    }\n                }\n                else if (record->Type == IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA)\n                {\n                    consumed = sizeof(IMAGE_DVRT_ARM64X_DELTA_FIXUP_RECORD);\n                    entry.ARM64X.Delta = *(PUSHORT)PTR_ADD_OFFSET(record, consumed);\n                    entry.ARM64X.Delta *= entry.ARM64X.RecordDelta.Scale ? 8 : 4;\n                    entry.ARM64X.Delta *= entry.ARM64X.RecordDelta.Sign ? -1 : 1;\n                    consumed += sizeof(USHORT);\n                }\n                else\n                {\n                    break;\n                }\n\n                status = Callback(MappedImage, &entry, Context);\n\n                if (!NT_SUCCESS(status))\n                    return status;\n\n                if (!PhPtrAdvance(&record, blockEnd, consumed))\n                    break;\n            }\n\n            if (!PhPtrAdvance(&base, BaseRelocsEnd, base->SizeOfBlock))\n                break;\n        }\n    }\n    else if (Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE)\n    {\n        PIMAGE_BASE_RELOCATION base = BaseRelocs;\n\n        for (ULONG blockIndex = 0; ; blockIndex++)\n        {\n            PIMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER header;\n            PVOID prologueBytes;\n            PH_IMAGE_DYNAMIC_RELOC_ENTRY entry;\n\n            if (base->SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION) + sizeof(IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER))\n            {\n                break;\n            }\n\n            header = PTR_ADD_OFFSET(base, sizeof(IMAGE_BASE_RELOCATION));\n            prologueBytes = PTR_ADD_OFFSET(header, sizeof(IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER));\n\n            // Validate prologue bytes are within block bounds\n            if ((ULONG_PTR)PTR_ADD_OFFSET(prologueBytes, header->PrologueByteCount) > \n                (ULONG_PTR)PTR_ADD_OFFSET(base, base->SizeOfBlock))\n            {\n                break;\n            }\n\n            RtlZeroMemory(&entry, sizeof(entry));\n            entry.Symbol = IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE;\n            entry.RFPrologue.BlockIndex = blockIndex;\n            entry.RFPrologue.BlockRva = base->VirtualAddress;\n            entry.RFPrologue.PrologueByteCount = header->PrologueByteCount;\n            entry.RFPrologue.PrologueBytes = prologueBytes;\n\n            entry.ImageBaseVa = PTR_ADD_OFFSET(\n                MappedImage->NtHeaders->OptionalHeader.ImageBase,\n                base->VirtualAddress\n                );\n            entry.MappedImageVa = PhMappedImageRvaToVa(\n                MappedImage,\n                base->VirtualAddress,\n                NULL\n                );\n\n            status = Callback(MappedImage, &entry, Context);\n\n            if (!NT_SUCCESS(status))\n                return status;\n\n            if (!PhPtrAdvance(&base, BaseRelocsEnd, base->SizeOfBlock))\n                break;\n        }\n    }\n    else if (Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE)\n    {\n        PIMAGE_BASE_RELOCATION base = BaseRelocs;\n\n        for (ULONG blockIndex = 0; ; blockIndex++)\n        {\n            PIMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER header;\n            PVOID branchDescriptors;\n            PVOID branchDescriptorBitMap;\n            PH_IMAGE_DYNAMIC_RELOC_ENTRY entry;\n            SIZE_T descriptorsSize;\n            SIZE_T bitMapSize;\n\n            if (base->SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION) + sizeof(IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER))\n            {\n                break;\n            }\n\n            header = PTR_ADD_OFFSET(base, sizeof(IMAGE_BASE_RELOCATION));\n            branchDescriptors = PTR_ADD_OFFSET(header, sizeof(IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER));\n\n            // Calculate sizes and validate bounds\n            descriptorsSize = (SIZE_T)header->BranchDescriptorElementSize * header->BranchDescriptorCount;\n            branchDescriptorBitMap = PTR_ADD_OFFSET(branchDescriptors, descriptorsSize);\n            \n            // Bitmap size: (BranchDescriptorCount + 7) / 8 bytes\n            bitMapSize = (header->BranchDescriptorCount + 7) / 8;\n\n            if ((ULONG_PTR)PTR_ADD_OFFSET(branchDescriptorBitMap, bitMapSize) > \n                (ULONG_PTR)PTR_ADD_OFFSET(base, base->SizeOfBlock))\n            {\n                break;\n            }\n\n            RtlZeroMemory(&entry, sizeof(entry));\n            entry.Symbol = IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE;\n            entry.RFEpilogue.BlockIndex = blockIndex;\n            entry.RFEpilogue.BlockRva = base->VirtualAddress;\n            entry.RFEpilogue.EpilogueCount = header->EpilogueCount;\n            entry.RFEpilogue.EpilogueByteCount = header->EpilogueByteCount;\n            entry.RFEpilogue.BranchDescriptorElementSize = header->BranchDescriptorElementSize;\n            entry.RFEpilogue.BranchDescriptorCount = header->BranchDescriptorCount;\n            entry.RFEpilogue.BranchDescriptors = branchDescriptors;\n            entry.RFEpilogue.BranchDescriptorBitMap = branchDescriptorBitMap;\n\n            entry.ImageBaseVa = PTR_ADD_OFFSET(\n                MappedImage->NtHeaders->OptionalHeader.ImageBase,\n                base->VirtualAddress\n                );\n            entry.MappedImageVa = PhMappedImageRvaToVa(\n                MappedImage,\n                base->VirtualAddress,\n                NULL\n                );\n\n            status = Callback(MappedImage, &entry, Context);\n\n            if (!NT_SUCCESS(status))\n                return status;\n\n            if (!PhPtrAdvance(&base, BaseRelocsEnd, base->SizeOfBlock))\n                break;\n        }\n    }\n    else if (Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_IMPORT_CONTROL_TRANSFER)\n    {\n        PIMAGE_BASE_RELOCATION base = BaseRelocs;\n\n        for (ULONG blockIndex = 0; ; blockIndex++)\n        {\n            ULONG relocationCount;\n            PIMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION relocations;\n\n            if (base->SizeOfBlock < sizeof(IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION))\n            {\n                break;\n            }\n\n            relocationCount = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION);\n            relocations = PTR_ADD_OFFSET(base, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock));\n\n            for (ULONG i = 0; i < relocationCount; i++)\n            {\n                PH_IMAGE_DYNAMIC_RELOC_ENTRY entry;\n\n                RtlZeroMemory(&entry, sizeof(entry));\n                entry.Symbol = IMAGE_DYNAMIC_RELOCATION_GUARD_IMPORT_CONTROL_TRANSFER;\n                entry.ImportControl.Record = relocations[i];\n                entry.ImportControl.BlockIndex = blockIndex;\n                entry.ImportControl.BlockRva = base->VirtualAddress;\n\n                entry.ImageBaseVa = PTR_ADD_OFFSET(\n                    MappedImage->NtHeaders->OptionalHeader.ImageBase,\n                    UInt32Add32To64(entry.ImportControl.BlockRva, entry.ImportControl.Record.PageRelativeOffset)\n                    );\n                entry.MappedImageVa = PhMappedImageRvaToVa(\n                    MappedImage,\n                    UInt32Add32To64(entry.ImportControl.BlockRva, entry.ImportControl.Record.PageRelativeOffset),\n                    NULL\n                    );\n\n                status = Callback(MappedImage, &entry, Context);\n\n                if (!NT_SUCCESS(status))\n                    return status;\n            }\n\n            if (!PhPtrAdvance(&base, BaseRelocsEnd, base->SizeOfBlock))\n                break;\n        }\n    }\n    else if (Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_INDIR_CONTROL_TRANSFER)\n    {\n        PIMAGE_BASE_RELOCATION base = BaseRelocs;\n\n        for (ULONG blockIndex = 0; ; blockIndex++)\n        {\n            ULONG relocationCount;\n            PIMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION relocations;\n\n            if (base->SizeOfBlock < sizeof(IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION))\n            {\n                break;\n            }\n\n            relocationCount = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION);\n            relocations = PTR_ADD_OFFSET(base, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock));\n\n            for (ULONG i = 0; i < relocationCount; i++)\n            {\n                PH_IMAGE_DYNAMIC_RELOC_ENTRY entry;\n\n                if (relocations[i].PageRelativeOffset == 0)\n                {\n                    break;\n                }\n\n                RtlZeroMemory(&entry, sizeof(PH_IMAGE_DYNAMIC_RELOC_ENTRY));\n                entry.Symbol = IMAGE_DYNAMIC_RELOCATION_GUARD_INDIR_CONTROL_TRANSFER;\n                entry.IndirControl.Record = relocations[i];\n                entry.IndirControl.BlockIndex = blockIndex;\n                entry.IndirControl.BlockRva = base->VirtualAddress;\n\n                entry.ImageBaseVa = PTR_ADD_OFFSET(\n                    MappedImage->NtHeaders->OptionalHeader.ImageBase,\n                    UInt32Add32To64(entry.IndirControl.BlockRva, entry.IndirControl.Record.PageRelativeOffset)\n                    );\n                entry.MappedImageVa = PhMappedImageRvaToVa(\n                    MappedImage,\n                    UInt32Add32To64(entry.IndirControl.BlockRva, entry.IndirControl.Record.PageRelativeOffset),\n                    NULL\n                    );\n\n                status = Callback(MappedImage, &entry, Context);\n\n                if (!NT_SUCCESS(status))\n                    return status;\n            }\n\n            if (!PhPtrAdvance(&base, BaseRelocsEnd, base->SizeOfBlock))\n                break;\n        }\n    }\n    else if (Symbol == IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH)\n    {\n        PIMAGE_BASE_RELOCATION base = BaseRelocs;\n\n        for (ULONG blockIndex = 0; ; blockIndex++)\n        {\n            ULONG relocationCount;\n            PIMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION relocations;\n\n            if (base->SizeOfBlock < sizeof(IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION))\n            {\n                break;\n            }\n\n            relocationCount = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION);\n            relocations = PTR_ADD_OFFSET(base, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock));\n\n            for (ULONG i = 0; i < relocationCount; i++)\n            {\n                PH_IMAGE_DYNAMIC_RELOC_ENTRY entry;\n\n                if (relocations[i].PageRelativeOffset == 0)\n                {\n                    break;\n                }\n\n                RtlZeroMemory(&entry, sizeof(PH_IMAGE_DYNAMIC_RELOC_ENTRY));\n                entry.Symbol = IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH;\n                entry.SwitchBranch.Record.PageRelativeOffset = relocations[i].PageRelativeOffset;\n                entry.SwitchBranch.Record.RegisterNumber = relocations[i].RegisterNumber;\n                entry.SwitchBranch.BlockIndex = blockIndex;\n                entry.SwitchBranch.BlockRva = base->VirtualAddress;\n\n                entry.ImageBaseVa = PTR_ADD_OFFSET(\n                    MappedImage->NtHeaders->OptionalHeader.ImageBase,\n                    UInt32Add32To64(entry.SwitchBranch.BlockRva, entry.SwitchBranch.Record.PageRelativeOffset)\n                    );\n                entry.MappedImageVa = PhMappedImageRvaToVa(\n                    MappedImage,\n                    UInt32Add32To64(entry.SwitchBranch.BlockRva, entry.SwitchBranch.Record.PageRelativeOffset),\n                    NULL\n                    );\n\n                status = Callback(MappedImage, &entry, Context);\n\n                if (!NT_SUCCESS(status))\n                    return status;\n            }\n\n            if (!PhPtrAdvance(&base, BaseRelocsEnd, base->SizeOfBlock))\n                break;\n        }\n    }\n    else if (Symbol == IMAGE_DYNAMIC_RELOCATION_FUNCTION_OVERRIDE)\n    {\n        PIMAGE_FUNCTION_OVERRIDE_HEADER header;\n        PVOID end;\n        PIMAGE_BDD_INFO bddInfo;\n        ULONG bddInfoSize;\n        PIMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION funcOverride;\n        PIMAGE_BDD_DYNAMIC_RELOCATION bddNodes = NULL;\n        ULONG bddNodesCount = 0;\n\n        header = (PIMAGE_FUNCTION_OVERRIDE_HEADER)BaseRelocs;\n        end = header;\n        if (!PhPtrAdvance(&end, BaseRelocsEnd, header->FuncOverrideSize))\n            return STATUS_INVALID_PARAMETER;\n\n        funcOverride = PTR_ADD_OFFSET(header, RTL_SIZEOF_THROUGH_FIELD(IMAGE_FUNCTION_OVERRIDE_HEADER, FuncOverrideSize));\n        bddInfo = PTR_ADD_OFFSET(funcOverride, header->FuncOverrideSize);\n        bddInfoSize = PtrToUlong(PTR_SUB_OFFSET(BaseRelocsEnd, BaseRelocs));\n        bddInfoSize -= (bddInfoSize > sizeof(IMAGE_FUNCTION_OVERRIDE_HEADER) ? sizeof(IMAGE_FUNCTION_OVERRIDE_HEADER) : bddInfoSize);\n        bddInfoSize -= (bddInfoSize > header->FuncOverrideSize ? header->FuncOverrideSize : bddInfoSize);\n        if (bddInfoSize && bddInfo->Version == 1 && bddInfo->BDDSize >= sizeof(IMAGE_BDD_DYNAMIC_RELOCATION))\n        {\n            bddNodes = PTR_ADD_OFFSET(bddInfo, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BDD_INFO, BDDSize));\n            bddNodesCount = bddInfo->BDDSize / sizeof(IMAGE_BDD_DYNAMIC_RELOCATION);\n        }\n\n        for (ULONG blockIndex = 0;;)\n        {\n            PVOID next;\n            PULONG rvas = NULL;\n            ULONG rvasCount = 0;\n\n            if (funcOverride->RvaSize >= sizeof(ULONG))\n            {\n                rvas = PTR_ADD_OFFSET(funcOverride, RTL_SIZEOF_THROUGH_FIELD(IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION, BaseRelocSize));\n                rvasCount = funcOverride->RvaSize / sizeof(ULONG);\n            }\n\n            if (funcOverride->BaseRelocSize)\n            {\n                PIMAGE_BASE_RELOCATION base;\n                PVOID baseEnd;\n\n                base = PTR_ADD_OFFSET(funcOverride, RTL_SIZEOF_THROUGH_FIELD(IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION, BaseRelocSize));\n                base = PTR_ADD_OFFSET(base, funcOverride->RvaSize);\n                baseEnd = PTR_ADD_OFFSET(base, funcOverride->BaseRelocSize);\n\n                for (;; blockIndex++)\n                {\n                    ULONG relocationCount;\n                    PIMAGE_RELOCATION_RECORD relocations;\n\n                    if (base->SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION))\n                    {\n                        break;\n                    }\n\n                    relocationCount = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOCATION_RECORD);\n                    relocations = PTR_ADD_OFFSET(base, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock));\n\n                    for (ULONG i = 0; i < relocationCount; i++)\n                    {\n                        PH_IMAGE_DYNAMIC_RELOC_ENTRY entry;\n\n                        if (relocations[i].Type == IMAGE_FUNCTION_OVERRIDE_INVALID)\n                        {\n                            break;\n                        }\n\n                        RtlZeroMemory(&entry, sizeof(PH_IMAGE_DYNAMIC_RELOC_ENTRY));\n                        entry.Symbol = Symbol;\n                        entry.FuncOverride.BlockIndex = blockIndex;\n                        entry.FuncOverride.BlockRva = base->VirtualAddress;\n                        entry.FuncOverride.Record.Offset = relocations[i].Offset;\n                        entry.FuncOverride.Record.Type = relocations[i].Type;\n                        entry.FuncOverride.BDDNodes = bddNodes;\n                        entry.FuncOverride.BDDNodesCount = bddNodesCount;\n                        entry.FuncOverride.OriginalRva = funcOverride->OriginalRva;\n                        entry.FuncOverride.BDDOffset = funcOverride->BDDOffset;\n                        entry.FuncOverride.Rvas = rvas;\n                        entry.FuncOverride.RvasCount = rvasCount;\n\n                        entry.ImageBaseVa = PTR_ADD_OFFSET(\n                            MappedImage->NtHeaders->OptionalHeader.ImageBase,\n                            UInt32Add32To64(entry.FuncOverride.BlockRva, entry.FuncOverride.Record.Offset)\n                            );\n                        entry.MappedImageVa = PhMappedImageRvaToVa(\n                            MappedImage,\n                            UInt32Add32To64(entry.FuncOverride.BlockRva, entry.FuncOverride.Record.Offset),\n                            NULL\n                            );\n\n                        status = Callback(MappedImage, &entry, Context);\n\n                        if (!NT_SUCCESS(status))\n                            return status;\n                    }\n\n                    if (!PhPtrAdvance(&base, baseEnd, base->SizeOfBlock))\n                        break;\n                }\n            }\n\n            next = funcOverride;\n            if (!PhPtrAdvance(&next, bddInfo, RTL_SIZEOF_THROUGH_FIELD(IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION, BaseRelocSize)))\n                break;\n            if (!PhPtrAdvance(&next, bddInfo, funcOverride->RvaSize))\n                break;\n            if (!PhPtrAdvance(&next, bddInfo, funcOverride->BaseRelocSize))\n                break;\n            funcOverride = next;\n        }\n    }\n    else if (Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64_KERNEL_IMPORT_CALL_TRANSFER)\n    {\n        PIMAGE_BASE_RELOCATION base = BaseRelocs;\n\n        for (ULONG blockIndex = 0; ; blockIndex++)\n        {\n            ULONG relocationCount;\n            PIMAGE_IMPORT_CONTROL_TRANSFER_ARM64_RELOCATION relocations;\n\n            if (base->SizeOfBlock < sizeof(IMAGE_IMPORT_CONTROL_TRANSFER_ARM64_RELOCATION))\n                break;\n\n            relocationCount = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_IMPORT_CONTROL_TRANSFER_ARM64_RELOCATION);\n            relocations = PTR_ADD_OFFSET(base, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock));\n\n            for (ULONG i = 0; i < relocationCount; i++)\n            {\n                PH_IMAGE_DYNAMIC_RELOC_ENTRY entry;\n\n                if (relocations[i].PageRelativeOffset == 0)\n                    break;\n\n                RtlZeroMemory(&entry, sizeof(entry));\n                entry.Symbol = IMAGE_DYNAMIC_RELOCATION_ARM64_KERNEL_IMPORT_CALL_TRANSFER;\n                entry.ARM64ImportControl.Record = relocations[i];\n                entry.ARM64ImportControl.BlockIndex = blockIndex;\n                entry.ARM64ImportControl.BlockRva = base->VirtualAddress;\n\n                // ARM64 instructions are 4-byte aligned, so PageRelativeOffset is shifted left by 2\n                entry.ImageBaseVa = PTR_ADD_OFFSET(\n                    MappedImage->NtHeaders->OptionalHeader.ImageBase,\n                    UInt32Add32To64(entry.ARM64ImportControl.BlockRva, entry.ARM64ImportControl.Record.PageRelativeOffset << 2)\n                    );\n                entry.MappedImageVa = PhMappedImageRvaToVa(\n                    MappedImage,\n                    UInt32Add32To64(entry.ARM64ImportControl.BlockRva, entry.ARM64ImportControl.Record.PageRelativeOffset << 2),\n                    NULL\n                    );\n\n                status = Callback(MappedImage, &entry, Context);\n\n                if (!NT_SUCCESS(status))\n                    return status;\n            }\n\n            if (!PhPtrAdvance(&base, BaseRelocsEnd, base->SizeOfBlock))\n                break;\n        }\n    }\n    else if (Symbol > 0xff) // assumes IMAGE_DYNAMIC_RELOCATION_KI_USER_SHARED_DATA64 or similar\n    {\n        PIMAGE_BASE_RELOCATION base = BaseRelocs;\n\n        for (ULONG blockIndex = 0; ; blockIndex++)\n        {\n            ULONG relocationCount;\n            PIMAGE_RELOCATION_RECORD relocations;\n\n            if (base->SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION))\n            {\n                break;\n            }\n\n            relocationCount = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOCATION_RECORD);\n            relocations = PTR_ADD_OFFSET(base, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock));\n\n            for (ULONG i = 0; i < relocationCount; i++)\n            {\n                PH_IMAGE_DYNAMIC_RELOC_ENTRY entry;\n\n                RtlZeroMemory(&entry, sizeof(PH_IMAGE_DYNAMIC_RELOC_ENTRY));\n                entry.Symbol = Symbol;\n                entry.Other.Record.Offset = relocations[i].Offset;\n                entry.Other.Record.Type = relocations[i].Type;\n                entry.Other.BlockIndex = blockIndex;\n                entry.Other.BlockRva = base->VirtualAddress;\n\n                entry.ImageBaseVa = PTR_ADD_OFFSET(\n                    MappedImage->NtHeaders->OptionalHeader.ImageBase,\n                    UInt32Add32To64(entry.Other.BlockRva, entry.Other.Record.Offset)\n                    );\n                entry.MappedImageVa = PhMappedImageRvaToVa(\n                    MappedImage,\n                    UInt32Add32To64(entry.Other.BlockRva, entry.Other.Record.Offset),\n                    NULL\n                    );\n\n                status = Callback(MappedImage, &entry, Context);\n\n                if (!NT_SUCCESS(status))\n                    return status;\n            }\n\n            if (!PhPtrAdvance(&base, BaseRelocsEnd, base->SizeOfBlock))\n                break;\n        }\n    }\n\n    return status;\n}\n\nPVOID PhpFillDynamicRelocationsArray32(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_DYNAMIC_RELOCATION32 Relocs,\n    _In_ PVOID RelocsEnd,\n    _In_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PVOID next;\n    PIMAGE_BASE_RELOCATION base;\n    PVOID end;\n\n    base = PTR_ADD_OFFSET(Relocs, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION32, BaseRelocSize));\n    end = PTR_ADD_OFFSET(Relocs, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION32, BaseRelocSize));\n    end = PTR_ADD_OFFSET(end, Relocs->BaseRelocSize);\n\n    PhpFillDynamicRelocations(MappedImage, (ULONGLONG)Relocs->Symbol, base, end, Callback, Context);\n\n    next = Relocs;\n    if (!PhPtrAdvance(&next, RelocsEnd, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION32, BaseRelocSize)))\n        return RelocsEnd;\n\n    if (!PhPtrAdvance(&next, RelocsEnd, Relocs->BaseRelocSize))\n        return RelocsEnd;\n\n    return next;\n}\n\nPVOID PhpFillDynamicRelocationsArray64(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_DYNAMIC_RELOCATION64 Relocs,\n    _In_ PVOID RelocsEnd,\n    _In_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PVOID next;\n    PIMAGE_BASE_RELOCATION base;\n    PVOID end;\n\n    base = PTR_ADD_OFFSET(Relocs, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION64, BaseRelocSize));\n    end = PTR_ADD_OFFSET(Relocs, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION64, BaseRelocSize));\n    end = PTR_ADD_OFFSET(end, Relocs->BaseRelocSize);\n\n    PhpFillDynamicRelocations(MappedImage, Relocs->Symbol, base, end, Callback, Context);\n\n    next = Relocs;\n    if (!PhPtrAdvance(&next, RelocsEnd, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION64, BaseRelocSize)))\n        return RelocsEnd;\n\n    if (!PhPtrAdvance(&next, RelocsEnd, Relocs->BaseRelocSize))\n        return RelocsEnd;\n\n    return next;\n}\n\nPVOID PhpFillDynamicRelocationsArray32v2(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_DYNAMIC_RELOCATION32_V2 Relocs,\n    _In_ PVOID RelocsEnd,\n    _In_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PVOID next;\n    PIMAGE_BASE_RELOCATION base;\n    PVOID end;\n\n    base = PTR_ADD_OFFSET(Relocs, Relocs->HeaderSize);\n    end = PTR_ADD_OFFSET(base, Relocs->FixupInfoSize);\n\n    PhpFillDynamicRelocations(MappedImage, (ULONGLONG)Relocs->Symbol, base, end, Callback, Context);\n\n    next = Relocs;\n    if (!PhPtrAdvance(&next, RelocsEnd, Relocs->HeaderSize))\n        return RelocsEnd;\n\n    if (!PhPtrAdvance(&next, RelocsEnd, Relocs->FixupInfoSize))\n        return RelocsEnd;\n\n    return next;\n}\n\nPVOID PhpFillDynamicRelocationsArray64v2(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PIMAGE_DYNAMIC_RELOCATION64_V2 Relocs,\n    _In_ PVOID RelocsEnd,\n    _In_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PVOID next;\n    PIMAGE_BASE_RELOCATION base;\n    PVOID end;\n\n    base = PTR_ADD_OFFSET(Relocs, Relocs->HeaderSize);\n    end = PTR_ADD_OFFSET(base, Relocs->FixupInfoSize);\n\n    PhpFillDynamicRelocations(MappedImage, Relocs->Symbol, base, end, Callback, Context);\n\n    next = Relocs;\n    if (!PhPtrAdvance(&next, RelocsEnd, Relocs->HeaderSize))\n        return RelocsEnd;\n\n    if (!PhPtrAdvance(&next, RelocsEnd, Relocs->FixupInfoSize))\n        return RelocsEnd;\n\n    return next;\n}\n\n/**\n * Enumerates dynamic relocations in a mapped PE image using a callback function.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Callback A callback function invoked for each dynamic relocation entry.\n * \\param Context An optional context pointer passed to the callback.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhMappedImageEnumerateDynamicRelocations(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DYNAMIC_RELOCATION_TABLE table;\n    PVOID reloc;\n    PVOID end;\n\n    status = PhGetMappedImageDynamicRelocationsTable(MappedImage, &table);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (table->Version != 1 && table->Version != 2)\n    {\n        return STATUS_UNKNOWN_REVISION;\n    }\n\n    reloc = PTR_ADD_OFFSET(table, RTL_SIZEOF_THROUGH_FIELD(IMAGE_DYNAMIC_RELOCATION_TABLE, Size));\n    end = PTR_ADD_OFFSET(table, table->Size);\n\n    while (reloc < end)\n    {\n        if (table->Version == 1)\n        {\n            if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n            {\n                reloc = PhpFillDynamicRelocationsArray32(MappedImage, reloc, end, Callback, Context);\n            }\n            else\n            {\n                assert(MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC);\n                reloc = PhpFillDynamicRelocationsArray64(MappedImage, reloc, end, Callback, Context);\n            }\n        }\n        else\n        {\n            assert(table->Version == 2);\n            if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n            {\n                reloc = PhpFillDynamicRelocationsArray32v2(MappedImage, reloc, end, Callback, Context);\n            }\n            else\n            {\n                assert(MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC);\n                reloc = PhpFillDynamicRelocationsArray64v2(MappedImage, reloc, end, Callback, Context);\n            }\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\ntypedef struct _PHP_DYNAMIC_RELOC_CONTEXT\n{\n    PPH_ARRAY Array;\n} PHP_DYNAMIC_RELOC_CONTEXT, *PPHP_DYNAMIC_RELOC_CONTEXT;\n\nNTSTATUS NTAPI PhpGetMappedImageDynamicRelocationsCallback(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PPH_IMAGE_DYNAMIC_RELOC_ENTRY Entry,\n    _In_opt_ PVOID Context\n    )\n{\n    PPHP_DYNAMIC_RELOC_CONTEXT context = Context;\n\n    PhAddItemArray(context->Array, Entry);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves all dynamic relocations from a mapped PE image into an array.\n *\n * \\param MappedImage A pointer to the mapped image.\n * \\param Relocations A pointer to a structure that receives the dynamic relocation information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetMappedImageDynamicRelocations(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC Relocations\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DYNAMIC_RELOCATION_TABLE table;\n    PH_ARRAY relocationArray;\n    PHP_DYNAMIC_RELOC_CONTEXT context;\n\n    status = PhGetMappedImageDynamicRelocationsTable(MappedImage, &table);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhInitializeArray(&relocationArray, sizeof(PH_IMAGE_DYNAMIC_RELOC_ENTRY), 1);\n    context.Array = &relocationArray;\n\n    status = PhMappedImageEnumerateDynamicRelocations(\n        MappedImage,\n        PhpGetMappedImageDynamicRelocationsCallback,\n        &context\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDeleteArray(&relocationArray);\n        return status;\n    }\n\n    Relocations->MappedImage = MappedImage;\n    Relocations->RelocationTable = table;\n    Relocations->NumberOfEntries = (ULONG)relocationArray.Count;\n    Relocations->RelocationEntries = PhFinalArrayItems(&relocationArray);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Releases resources associated with dynamic relocations.\n *\n * \\param Relocations A pointer to the dynamic relocation information structure.\n */\nVOID PhFreeMappedImageDynamicRelocations(\n    _In_opt_ PPH_MAPPED_IMAGE_DYNAMIC_RELOC Relocations\n    )\n{\n    if (Relocations && Relocations->RelocationEntries)\n    {\n        PhFree(Relocations->RelocationEntries);\n        Relocations->RelocationEntries = NULL;\n        Relocations->NumberOfEntries = 0;\n    }\n}\n\nNTSTATUS PhGetMappedImageExceptions(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_EXCEPTIONS Exceptions\n    )\n{\n    return PhGetMappedImageExceptionsEx(MappedImage, Exceptions, 0);\n}\n\nNTSTATUS PhGetMappedImageExceptionsEx(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_EXCEPTIONS Exceptions,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PVOID exceptionDirectory;\n    PH_ARRAY exceptionArray;\n    ULONG imageMachine;\n    ULONG exceptionTotal = 0;\n    ULONG exceptionEntrySize = 0;\n\n    Exceptions->DataDirectoryARM64X.VirtualAddress = 0;\n    Exceptions->DataDirectoryARM64X.Size = 0;\n\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n        imageMachine = MappedImage->NtHeaders32->FileHeader.Machine;\n    else\n        imageMachine = MappedImage->NtHeaders->FileHeader.Machine;\n\n    // 32bit images require special handling for the SEH table.\n    switch (imageMachine)\n    {\n    case IMAGE_FILE_MACHINE_I386:\n        {\n            PIMAGE_LOAD_CONFIG_DIRECTORY32 config32;\n            PULONG exceptionHandlerTable = NULL;\n\n            status = PhGetMappedImageLoadConfig32(MappedImage, &config32);\n\n            if (!NT_SUCCESS(status))\n                return status;\n\n            if (config32->SEHandlerTable)\n            {\n                exceptionTotal = config32->SEHandlerCount;\n                exceptionHandlerTable = PhMappedImageVaToVa(MappedImage, config32->SEHandlerTable, NULL);\n            }\n\n            if (!exceptionHandlerTable)\n                return STATUS_UNSUCCESSFUL;\n\n            __try\n            {\n                PhMappedImageProbe(MappedImage, exceptionHandlerTable, UInt32x32To64(exceptionTotal, sizeof(ULONG)));\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n\n            // Allocate the number of exception entries.\n\n            PhInitializeArray(&exceptionArray, sizeof(ULONG), exceptionTotal);\n\n            // Add the exception entries into our buffer.\n\n            for (ULONG i = 0; i < exceptionTotal; i++)\n            {\n                ULONG rva = *(PULONG)PTR_ADD_OFFSET(exceptionHandlerTable, UInt32x32To64(i, sizeof(ULONG)));\n\n                PhAddItemArray(&exceptionArray, &rva);\n            }\n\n            Exceptions->MappedImage = MappedImage;\n            Exceptions->DataDirectory = NULL;\n            Exceptions->ExceptionDirectory = NULL;\n            Exceptions->NumberOfEntries = (ULONG)exceptionArray.Count;\n            Exceptions->ExceptionEntries = PhFinalArrayItems(&exceptionArray);\n\n            return STATUS_SUCCESS;\n        }\n        break;\n    }\n\n    status = PhGetMappedImageDataDirectory(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_EXCEPTION,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (Flags & PH_GET_IMAGE_EXCEPTIONS_ARM64X)\n    {\n        status = PhRelocateMappedImageDataEntryARM64X(\n            MappedImage,\n            dataDirectory,\n            &Exceptions->DataDirectoryARM64X\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        exceptionDirectory = PhMappedImageRvaToVa(\n            MappedImage,\n            Exceptions->DataDirectoryARM64X.VirtualAddress,\n            NULL\n            );\n\n        if (!exceptionDirectory)\n            return STATUS_INVALID_PARAMETER;\n\n        __try\n        {\n            PhMappedImageProbe(MappedImage, exceptionDirectory, Exceptions->DataDirectoryARM64X.Size);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n\n        // N.B. intentionally inverted\n        switch (imageMachine)\n        {\n        //case IMAGE_FILE_MACHINE_AMD64:\n        //    {\n        //        exceptionEntrySize = sizeof(IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY);\n        //        exceptionTotal = Exceptions->DataDirectoryARM64X.Size / exceptionEntrySize;\n        //    }\n        //    break;\n        case IMAGE_FILE_MACHINE_ARM64:\n            {\n                exceptionEntrySize = sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);\n                exceptionTotal = Exceptions->DataDirectoryARM64X.Size / exceptionEntrySize;\n            }\n            break;\n        default:\n            return STATUS_NOT_SUPPORTED;\n        }\n    }\n    else\n    {\n        exceptionDirectory = PhMappedImageRvaToVa(\n            MappedImage,\n            dataDirectory->VirtualAddress,\n            NULL\n            );\n\n        if (!exceptionDirectory)\n            return STATUS_INVALID_PARAMETER;\n\n        __try\n        {\n            PhMappedImageProbe(MappedImage, exceptionDirectory, dataDirectory->Size);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n\n        switch (imageMachine)\n        {\n        case IMAGE_FILE_MACHINE_AMD64:\n        case IMAGE_FILE_MACHINE_IA64:\n            {\n                exceptionEntrySize = sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);\n                exceptionTotal = dataDirectory->Size / exceptionEntrySize;\n            }\n            break;\n        case IMAGE_FILE_MACHINE_ARMNT:\n            {\n                exceptionEntrySize = sizeof(IMAGE_ARM_RUNTIME_FUNCTION_ENTRY);\n                exceptionTotal = dataDirectory->Size / exceptionEntrySize;\n            }\n            break;\n        case IMAGE_FILE_MACHINE_ARM64:\n            {\n                exceptionEntrySize = sizeof(IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY);\n                exceptionTotal = dataDirectory->Size / exceptionEntrySize;\n            }\n            break;\n        }\n    }\n\n    Exceptions->MappedImage = MappedImage;\n    Exceptions->DataDirectory = dataDirectory;\n    Exceptions->ExceptionDirectory = exceptionDirectory;\n\n    // Allocate the number of exception entries.\n\n    PhInitializeArray(&exceptionArray, exceptionEntrySize, exceptionTotal);\n\n    // Add the exception entries into our buffer.\n\n    for (ULONG i = 0; i < exceptionTotal; i++)\n    {\n        PVOID entry = PTR_ADD_OFFSET(exceptionDirectory, UInt32x32To64(i, exceptionEntrySize));\n\n        PhAddItemArray(&exceptionArray, entry);\n    }\n\n    Exceptions->NumberOfEntries = (ULONG)exceptionArray.Count;\n    Exceptions->ExceptionEntries = PhFinalArrayItems(&exceptionArray);\n\n    return status;\n}\n\nNTSTATUS PhGetMappedImageVolatileMetadata(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PPH_MAPPED_IMAGE_VOLATILE_METADATA VolatileMetadata\n    )\n{\n    NTSTATUS status;\n    PIMAGE_VOLATILE_METADATA metadata;\n    ULONG metadataAccessTotal = 0;\n    ULONG metadataRangeTotal = 0;\n    PH_ARRAY metadataAccessArray = { 0 };\n    PH_ARRAY metadataRangeArray = { 0 };\n\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY32 config32;\n\n        status = PhGetMappedImageLoadConfig32(MappedImage, &config32);\n\n        if (!NT_SUCCESS(status))\n            return status;\n        if (!RTL_CONTAINS_FIELD(config32, config32->Size, VolatileMetadataPointer))\n            return STATUS_INVALID_VIEW_SIZE;\n        if (config32->VolatileMetadataPointer == 0)\n            return STATUS_INVALID_FILE_FOR_SECTION;\n\n        metadata = PhMappedImageVaToVa(\n            MappedImage,\n            config32->VolatileMetadataPointer,\n            NULL\n            );\n    }\n    else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY64 config64;\n\n        status = PhGetMappedImageLoadConfig64(MappedImage, &config64);\n\n        if (!NT_SUCCESS(status))\n            return status;\n        if (!RTL_CONTAINS_FIELD(config64, config64->Size, VolatileMetadataPointer))\n            return STATUS_INVALID_VIEW_SIZE;\n        if (config64->VolatileMetadataPointer == 0)\n            return STATUS_INVALID_FILE_FOR_SECTION;\n\n        metadata = PhMappedImageVaToVa(\n            MappedImage,\n            config64->VolatileMetadataPointer,\n            NULL\n            );\n    }\n    else\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    if (!metadata)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhMappedImageProbe(MappedImage, metadata, sizeof(IMAGE_VOLATILE_METADATA));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    if (metadata->Size != sizeof(IMAGE_VOLATILE_METADATA))\n        return STATUS_NOT_IMPLEMENTED;\n\n    //USHORT metadataVersionMin = HIWORD(metadata->Version) & 0xff;\n    //USHORT metadataVersionMax = LOWORD(metadata->Version) & 0xff;\n    //if (metadataVersionMin != 2 && metadataVersionMax != 2)\n    //    return STATUS_NOT_IMPLEMENTED;\n\n    if (metadata->VolatileAccessTable && metadata->VolatileAccessTableSize)\n    {\n        PVOID volatileAccessTable;\n        PIMAGE_VOLATILE_RVA_METADATA entry;\n\n        volatileAccessTable = PhMappedImageRvaToVa(\n            MappedImage,\n            metadata->VolatileAccessTable,\n            NULL\n            );\n\n        if (volatileAccessTable)\n        {\n            ULONG count;\n            ULONG i;\n\n            count = metadata->VolatileAccessTableSize / sizeof(IMAGE_VOLATILE_RVA_METADATA);\n\n            PhInitializeArray(&metadataAccessArray, sizeof(PH_IMAGE_VOLATILE_ENTRY), count);\n\n            for (i = 0; i < count; i++)\n            {\n                entry = PTR_ADD_OFFSET(volatileAccessTable, UInt32x32To64(i, sizeof(IMAGE_VOLATILE_RVA_METADATA)));\n\n                __try\n                {\n                    PhMappedImageProbe(MappedImage, entry, sizeof(IMAGE_VOLATILE_RVA_METADATA));\n                }\n                __except (EXCEPTION_EXECUTE_HANDLER)\n                {\n                    continue;\n                }\n\n                {\n                    PH_IMAGE_VOLATILE_ENTRY volatileRvaEntry;\n\n                    volatileRvaEntry.Rva = entry->Rva;\n                    volatileRvaEntry.Size = 0;\n\n                    PhAddItemArray(&metadataAccessArray, &volatileRvaEntry);\n                }\n            }\n\n            metadataAccessTotal = (ULONG)metadataAccessArray.Count;\n        }\n    }\n\n    if (metadata->VolatileInfoRangeTable && metadata->VolatileInfoRangeTableSize)\n    {\n        PVOID volatileRangeTable;\n        PIMAGE_VOLATILE_RANGE_METADATA entry;\n\n        volatileRangeTable = PhMappedImageRvaToVa(\n            MappedImage,\n            metadata->VolatileInfoRangeTable,\n            NULL\n            );\n\n        if (volatileRangeTable)\n        {\n            ULONG count;\n            ULONG i;\n\n            count = metadata->VolatileInfoRangeTableSize / sizeof(IMAGE_VOLATILE_RANGE_METADATA);\n\n            PhInitializeArray(&metadataRangeArray, sizeof(PH_IMAGE_VOLATILE_ENTRY), count);\n\n            for (i = 0; i < count; i++)\n            {\n                entry = PTR_ADD_OFFSET(volatileRangeTable, UInt32x32To64(i, sizeof(IMAGE_VOLATILE_RANGE_METADATA)));\n\n                __try\n                {\n                    PhMappedImageProbe(MappedImage, entry, sizeof(IMAGE_VOLATILE_RANGE_METADATA));\n                }\n                __except (EXCEPTION_EXECUTE_HANDLER)\n                {\n                    continue;\n                }\n\n                {\n                    PH_IMAGE_VOLATILE_ENTRY volatileRangeEntry;\n\n                    volatileRangeEntry.Rva = entry->Rva;\n                    volatileRangeEntry.Size = entry->Size;\n\n                    PhAddItemArray(&metadataRangeArray, &volatileRangeEntry);\n                }\n            }\n\n            metadataRangeTotal = (ULONG)metadataRangeArray.Count;\n        }\n    }\n\n    VolatileMetadata->MappedImage = MappedImage;\n    VolatileMetadata->VolatileMetadata = metadata;\n    VolatileMetadata->NumberOfAccessEntries = metadataAccessTotal;\n    VolatileMetadata->NumberOfRangeEntries = metadataRangeTotal;\n    VolatileMetadata->AccessEntries = PhFinalArrayItems(&metadataAccessArray);\n    VolatileMetadata->RangeEntries = PhFinalArrayItems(&metadataRangeArray);\n\n    return status;\n}\n\nNTSTATUS PhMappedImageUpdateHashData(\n    _In_ PPH_HASH_CONTEXT HashContext,\n    _In_ PVOID Buffer,\n    _In_ ULONG64 BufferLength\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n\n    __try\n    {\n        if (BufferLength >= ULONG_MAX)\n        {\n            PBYTE address;\n            ULONG64 numberOfBytes;\n            ULONG blockSize;\n\n            // Chunk the data into smaller blocks when the buffer length\n            // overflows the maximum length of the BCryptHashData function.\n\n            address = (PBYTE)Buffer;\n            numberOfBytes = BufferLength;\n            blockSize = PAGE_SIZE * 64;\n\n            while (numberOfBytes != 0)\n            {\n                if (blockSize > numberOfBytes)\n                    blockSize = (ULONG)numberOfBytes;\n\n                status = PhUpdateHash(HashContext, address, blockSize);\n\n                if (!NT_SUCCESS(status))\n                    break;\n\n                address += blockSize;\n                numberOfBytes -= blockSize;\n            }\n        }\n        else\n        {\n            status = PhUpdateHash(HashContext, Buffer, (ULONG)BufferLength);\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n    }\n\n    return status;\n}\n\ntypedef struct _PH_MAPPED_IMAGE_HASH_REGION\n{\n    ULONG64 Offset;\n    ULONG64 Length;\n} PH_MAPPED_IMAGE_HASH_REGION;\n\nNTSTATUS PhGetMappedImageAuthenticodeHash(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PH_HASH_ALGORITHM Algorithm,\n    _Out_ PPH_STRING* AuthenticodeHash\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DOS_HEADER imageDosHeader;\n    PPH_STRING hashString = NULL;\n    ULONG imageChecksumOffset;\n    ULONG imageSecurityOffset;\n    ULONG imageSecurityAddress = 0;\n    ULONG imageSecuritySize = 0;\n    PH_MAPPED_IMAGE_HASH_REGION imageHashBlock[4] = { 0 };\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PH_HASH_CONTEXT hashContext;\n\n    __try\n    {\n        imageDosHeader = (PIMAGE_DOS_HEADER)MappedImage->ViewBase;\n\n        if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n        {\n            imageChecksumOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);\n            imageSecurityOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);\n        }\n        else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n        {\n            imageChecksumOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum);\n            imageSecurityOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);\n        }\n        else\n        {\n            return STATUS_INVALID_IMAGE_FORMAT;\n        }\n\n        PhMappedImagePrefetch(MappedImage);\n\n        if (NT_SUCCESS(PhGetMappedImageDataDirectory(MappedImage, IMAGE_DIRECTORY_ENTRY_SECURITY, &dataDirectory)))\n        {\n            imageSecurityAddress = dataDirectory->VirtualAddress;\n            imageSecuritySize = dataDirectory->Size;\n        }\n\n        // BaseAddress -> Checksum\n        imageHashBlock[0].Offset = 0;\n        imageHashBlock[0].Length = imageChecksumOffset;\n\n        // Checksum -> Security directory\n        imageHashBlock[1].Offset = imageChecksumOffset + RTL_FIELD_SIZE(IMAGE_OPTIONAL_HEADER, CheckSum);\n        imageHashBlock[1].Length = imageSecurityOffset - imageHashBlock[1].Offset;\n\n        if (imageSecurityAddress && imageSecuritySize)\n        {\n            // Security directory -> Certificate data\n            imageHashBlock[2].Offset = UInt32Add32To64(imageSecurityOffset, sizeof(IMAGE_DATA_DIRECTORY));\n            imageHashBlock[2].Length = imageSecurityAddress - imageHashBlock[2].Offset;\n\n            // Certificate data -> End of file\n            imageHashBlock[3].Offset = UInt32Add32To64(imageSecurityAddress, imageSecuritySize);\n            imageHashBlock[3].Length = MappedImage->ViewSize - imageHashBlock[3].Offset;\n        }\n        else\n        {\n            // Security directory -> End of file\n            imageHashBlock[2].Offset = UInt32Add32To64(imageSecurityOffset, sizeof(IMAGE_DATA_DIRECTORY));\n            imageHashBlock[2].Length = MappedImage->ViewSize - imageHashBlock[2].Offset;\n        }\n\n        status = PhInitializeHash(&hashContext, Algorithm);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        for (ULONG i = 0; i < RTL_NUMBER_OF(imageHashBlock); i++)\n        {\n            if (imageHashBlock[i].Length)\n            {\n                status = PhMappedImageUpdateHashData(\n                    &hashContext,\n                    PTR_ADD_OFFSET(MappedImage->ViewBase, imageHashBlock[i].Offset),\n                    imageHashBlock[i].Length\n                    );\n\n                if (!NT_SUCCESS(status))\n                    break;\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            ULONG hashLength = PH_HASH_SHA256_LENGTH;\n            UCHAR hash[PH_HASH_SHA256_LENGTH];\n\n            status = PhFinalHash(&hashContext, hash, hashLength, &hashLength);\n\n            if (NT_SUCCESS(status))\n            {\n                hashString = PhBufferToHexString(hash, sizeof(hash));\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            *AuthenticodeHash = hashString;\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetMappedImageAuthenticodeLegacy(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PH_HASH_ALGORITHM Algorithm,\n    _Out_ PPH_STRING* AuthenticodeHash\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DOS_HEADER imageDosHeader;\n    PPH_STRING hashString = NULL;\n    ULONG64 offset = 0;\n    ULONG imageChecksumOffset;\n    ULONG imageSecurityOffset;\n    ULONG directoryAddress = 0;\n    ULONG directorySize = 0;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PH_HASH_CONTEXT hashContext;\n\n    __try\n    {\n        imageDosHeader = (PIMAGE_DOS_HEADER)MappedImage->ViewBase;\n\n        if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n        {\n            imageChecksumOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);\n            imageSecurityOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);\n        }\n        else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n        {\n            imageChecksumOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum);\n            imageSecurityOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);\n        }\n        else\n        {\n            return STATUS_INVALID_IMAGE_FORMAT;\n        }\n\n        PhMappedImagePrefetch(MappedImage);\n\n        if (NT_SUCCESS(PhGetMappedImageDataDirectory(MappedImage, IMAGE_DIRECTORY_ENTRY_SECURITY, &dataDirectory)))\n        {\n            directoryAddress = dataDirectory->VirtualAddress;\n            directorySize = dataDirectory->Size;\n        }\n\n        status = PhInitializeHash(&hashContext, Algorithm);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        while (offset < imageChecksumOffset)\n        {\n            if (!NT_SUCCESS(status = PhUpdateHash(&hashContext, PTR_ADD_OFFSET(MappedImage->ViewBase, offset), sizeof(BYTE))))\n                break;\n\n            offset++;\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            offset += RTL_FIELD_SIZE(IMAGE_OPTIONAL_HEADER, CheckSum);\n\n            while (offset < imageSecurityOffset)\n            {\n                if (!NT_SUCCESS(status = PhUpdateHash(&hashContext, PTR_ADD_OFFSET(MappedImage->ViewBase, offset), sizeof(BYTE))))\n                    break;\n\n                offset++;\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            offset += sizeof(IMAGE_DATA_DIRECTORY);\n\n            while (offset < directoryAddress)\n            {\n                if (!NT_SUCCESS(status = PhUpdateHash(&hashContext, PTR_ADD_OFFSET(MappedImage->ViewBase, offset), sizeof(BYTE))))\n                    break;\n\n                offset++;\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            offset += directorySize;\n\n            while (offset < MappedImage->ViewSize)\n            {\n                if (!NT_SUCCESS(status = PhUpdateHash(&hashContext, PTR_ADD_OFFSET(MappedImage->ViewBase, offset), sizeof(BYTE))))\n                    break;\n\n                offset++;\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            ULONG hashLength = PH_HASH_SHA256_LENGTH;\n            UCHAR hash[PH_HASH_SHA256_LENGTH];\n\n            status = PhFinalHash(&hashContext, hash, hashLength, &hashLength);\n\n            if (NT_SUCCESS(status))\n            {\n                hashString = PhBufferToHexString(hash, sizeof(hash));\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            *AuthenticodeHash = hashString;\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetMappedImageWdacHash(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PH_HASH_ALGORITHM Algorithm,\n    _Out_ PPH_STRING* WdacHash\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DOS_HEADER imageDosHeader;\n    PPH_STRING hashString = NULL;\n    ULONG offset = 0;\n    ULONG imageChecksumOffset;\n    ULONG imageSecurityOffset;\n    ULONG imageSizeOfHeaders;\n    PH_HASH_CONTEXT hashContext;\n\n    __try\n    {\n        imageDosHeader = (PIMAGE_DOS_HEADER)MappedImage->ViewBase;\n\n        if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n        {\n            imageChecksumOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);\n            imageSecurityOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);\n            imageSizeOfHeaders = ((PIMAGE_OPTIONAL_HEADER32)&MappedImage->NtHeaders32->OptionalHeader)->SizeOfHeaders;\n        }\n        else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n        {\n            imageChecksumOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum);\n            imageSecurityOffset = imageDosHeader->e_lfanew + UFIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);\n            imageSizeOfHeaders = ((PIMAGE_OPTIONAL_HEADER64)&MappedImage->NtHeaders->OptionalHeader)->SizeOfHeaders;\n        }\n        else\n        {\n            return STATUS_INVALID_IMAGE_FORMAT;\n        }\n\n        status = PhInitializeHash(&hashContext, Algorithm);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        while (offset < PAGE_SIZE)\n        {\n            if (offset == imageChecksumOffset)\n                offset += RTL_FIELD_SIZE(IMAGE_OPTIONAL_HEADER, CheckSum);\n            if (offset == imageSecurityOffset)\n                offset += sizeof(IMAGE_DATA_DIRECTORY);\n            if (offset >= imageSizeOfHeaders)\n                break;\n\n            status = PhUpdateHash(&hashContext, PTR_ADD_OFFSET(MappedImage->ViewBase, offset), sizeof(BYTE));\n\n            if (!NT_SUCCESS(status))\n                break;\n\n            offset++;\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            if (offset < PAGE_SIZE)\n            {\n                ULONG paddingLength;\n                PVOID paddingBuffer;\n\n                paddingLength = PAGE_SIZE - offset;\n                paddingBuffer = PhAllocateZero(paddingLength);\n\n                status = PhUpdateHash(&hashContext, paddingBuffer, paddingLength);\n                PhFree(paddingBuffer);\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            ULONG hashLength = PH_HASH_SHA256_LENGTH;\n            UCHAR hash[PH_HASH_SHA256_LENGTH];\n\n            status = PhFinalHash(&hashContext, hash, hashLength, &hashLength);\n\n            if (NT_SUCCESS(status))\n            {\n                hashString = PhBufferToHexString(hash, hashLength);\n            }\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            *WdacHash = hashString;\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n    }\n\n    return status;\n}\n\nBOOLEAN PhGetMappedImageEntropy(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PFLOAT ImageEntropy,\n    _Out_ PFLOAT ImageMean,\n    _Out_ PFLOAT ImageVariance\n    )\n{\n    BOOLEAN status = FALSE;\n\n    __try\n    {\n        status = PhCalculateEntropy(\n            MappedImage->ViewBase,\n            MappedImage->ViewSize,\n            ImageEntropy,\n            ImageMean,\n            ImageVariance\n            );\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = FALSE;\n    }\n\n    return status;\n}\n\nULONG PhGetMappedImageCHPEVersion(\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY32 config32;\n\n        if (NT_SUCCESS(PhGetMappedImageLoadConfig32(MappedImage, &config32)) &&\n            RTL_CONTAINS_FIELD(config32, config32->Size, CHPEMetadataPointer) &&\n            config32->CHPEMetadataPointer)\n        {\n            PIMAGE_CHPE_METADATA_X86 chpe32;\n\n            chpe32 = PhMappedImageVaToVa(MappedImage, config32->CHPEMetadataPointer, NULL);\n            if (chpe32)\n                return chpe32->Version;\n        }\n    }\n    else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        PIMAGE_LOAD_CONFIG_DIRECTORY64 config64;\n\n        if (NT_SUCCESS(PhGetMappedImageLoadConfig64(MappedImage, &config64)) &&\n            RTL_CONTAINS_FIELD(config64, config64->Size, CHPEMetadataPointer) &&\n            config64->CHPEMetadataPointer)\n        {\n            PIMAGE_ARM64EC_METADATA chpe64;\n\n            chpe64 = PhMappedImageVaToVa(MappedImage, config64->CHPEMetadataPointer, NULL);\n            if (chpe64)\n                return chpe64->Version;\n        }\n    }\n\n    return 0;\n}\n\n"
  },
  {
    "path": "phlib/mapldr.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <mapimg.h>\n#include <mapldr.h>\n\n/**\n * Locates a loader entry in the current process.\n *\n * \\param[in,opt] DllBase The base address of the DLL. Specify NULL if this is not a search criteria.\n * \\param[in,opt] FullDllName The full name of the DLL. Specify NULL if this is not a search criteria.\n * \\param[in,opt] BaseDllName The base name of the DLL. Specify NULL if this is not a search criteria.\n * \\remarks This function must be called with the loader lock acquired. The first entry matching all\n * of the specified values is returned.\n */\nPLDR_DATA_TABLE_ENTRY PhFindLoaderEntry(\n    _In_opt_ PVOID DllBase,\n    _In_opt_ PCPH_STRINGREF FullDllName,\n    _In_opt_ PCPH_STRINGREF BaseDllName\n    )\n{\n    PLDR_DATA_TABLE_ENTRY result = NULL;\n    PLDR_DATA_TABLE_ENTRY entry;\n    PH_STRINGREF fullDllName;\n    PH_STRINGREF baseDllName;\n    PLIST_ENTRY listHead;\n    PLIST_ENTRY listEntry;\n\n    listHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;\n    listEntry = listHead->Flink;\n\n    while (listEntry != listHead)\n    {\n        entry = CONTAINING_RECORD(listEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n        PhUnicodeStringToStringRef(&entry->FullDllName, &fullDllName);\n        PhUnicodeStringToStringRef(&entry->BaseDllName, &baseDllName);\n\n        if (\n            (!DllBase || entry->DllBase == DllBase) &&\n            (!FullDllName || PhStartsWithStringRef(&fullDllName, FullDllName, TRUE)) &&\n            (!BaseDllName || PhStartsWithStringRef(&baseDllName, BaseDllName, TRUE))\n            )\n        {\n            result = entry;\n            break;\n        }\n\n        listEntry = listEntry->Flink;\n    }\n\n    return result;\n}\n\n/**\n * Locates a loader entry by address in the current process.\n *\n * \\param[in] Address An address within the module's address range.\n * \\return A pointer to the loader entry, or NULL if not found.\n */\nPLDR_DATA_TABLE_ENTRY PhFindLoaderEntryAddress(\n    _In_ PVOID Address\n    )\n{\n    PLDR_DATA_TABLE_ENTRY result = NULL;\n    PLDR_DATA_TABLE_ENTRY entry;\n    PLIST_ENTRY listHead;\n    PLIST_ENTRY listEntry;\n\n    listHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;\n    listEntry = listHead->Flink;\n\n    while (listEntry != listHead)\n    {\n        entry = CONTAINING_RECORD(listEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n\n        if (\n            (ULONG_PTR)Address >= (ULONG_PTR)entry->DllBase &&\n            (ULONG_PTR)Address < (ULONG_PTR)PTR_ADD_OFFSET(entry->DllBase, entry->SizeOfImage)\n            )\n        {\n            result = entry;\n            break;\n        }\n\n        listEntry = listEntry->Flink;\n    }\n\n    return result;\n}\n\n/**\n * Locates a loader entry by base name hash in the current process.\n *\n * \\param[in] BaseNameHash The hash value of the DLL base name.\n * \\return A pointer to the loader entry, or NULL if not found.\n */\nPLDR_DATA_TABLE_ENTRY PhFindLoaderEntryNameHash(\n    _In_ ULONG BaseNameHash\n    )\n{\n    PLDR_DATA_TABLE_ENTRY entry;\n    PLIST_ENTRY listHead;\n    PLIST_ENTRY listEntry;\n\n    listHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;\n    listEntry = listHead->Flink;\n\n    while (listEntry != listHead)\n    {\n        entry = CONTAINING_RECORD(listEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n\n        if (entry->BaseNameHashValue == BaseNameHash)\n            return entry;\n\n        listEntry = listEntry->Flink;\n    }\n\n    return NULL;\n}\n\n/**\n * Loads a DLL into the current process with safe search path behavior.\n *\n * \\param[in] FileName The file name of the DLL to load.\n * \\return The base address of the loaded DLL, or NULL if loading failed.\n * \\remarks This function attempts to load the DLL with safe search paths, prioritizing\n * System32 and the application directory. On Windows 7 without KB2533623, it falls back\n * to the default LoadLibraryEx behavior for compatibility.\n */\nPVOID PhLoadLibrary(\n    _In_ PCWSTR FileName\n    )\n{\n    PVOID baseAddress;\n\n    // Force System32 as the default search path.\n    // - If the file name is not qualified this will fail.\n    // - If the file name qualified this will succeed.\n    // Note: Directories in the standard search path are not searched.\n\n    if (baseAddress = LoadLibraryEx(FileName, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32))\n        return baseAddress;\n\n    // Force the current executable directory as the default search path.\n    // - If the file name is not qualified this will fail.\n    // - If the file name qualified this will succeed.\n    // Note: Directories in the standard search path are not searched.\n\n    if (baseAddress = LoadLibraryEx(FileName, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR))\n        return baseAddress;\n\n    // Windows 7, Windows 8, Windows Server 2008 R2, and Windows Server 2008\n    // don't support the above flags prior to installing KB2533623. (dmex)\n\n    if (WindowsVersion < WINDOWS_8)\n    {\n        // Note: This case is required for Windows 7 without KB2533623 (dmex)\n\n        if (baseAddress = LoadLibraryEx(FileName, NULL, 0))\n        {\n            return baseAddress;\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Loads a library with specific flags.\n *\n * \\param[out] BaseAddress Receives the base address of the loaded library.\n * \\param[in] FileName The file name of the library to load.\n * \\param[in] Flags Flags to control the loading behavior.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhLoadLibraryEx(\n    _Out_ PVOID* BaseAddress,\n    _In_ PCWSTR FileName,\n    _In_ ULONG Flags\n    )\n{\n    PVOID baseAddress;\n\n    if (baseAddress = LoadLibraryEx(FileName, NULL, Flags))\n    {\n        *BaseAddress = baseAddress;\n        return STATUS_SUCCESS;\n    }\n\n    *BaseAddress = NULL;\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Frees a loaded library.\n *\n * \\param[in] BaseAddress The base address of the library to free.\n * \\return TRUE if successful, FALSE otherwise.\n */\nBOOLEAN PhFreeLibrary(\n    _In_ PVOID BaseAddress\n    )\n{\n    return !!FreeLibrary(BaseAddress);\n}\n\n#ifdef DEBUG\n// rev from BasepLoadLibraryAsDataFileInternal (dmex)\n/**\n * Temporarily suppresses debugger symbol loading notifications for resource loading.\n *\n * \\param [in] SuppressDebugMessage TRUE to suppress debug messages, FALSE to restore them.\n *\n * \\remarks This function is based on BasepLoadLibraryAsDataFileInternal from kernelbase.dll.\n * On Windows 7/8, the Visual Studio debugger attempts to load symbols for non-executable resources,\n * causing unnecessary overhead. This function temporarily sets the TEB's SuppressDebugMsg flag to\n * prevent symbol loading during resource-only image mapping. On Windows 10+, SEC_IMAGE_NO_EXECUTE\n * prevents symbol loading, making this suppression unnecessary. Only enabled in DEBUG builds.\n */\nFORCEINLINE\nVOID\nNtSuppressDebugMessage(\n    _In_ BOOLEAN SuppressDebugMessage\n    )\n{\n    // Note: The Visual Studio debugger on Windows 7/8 attempts to load symbols\n    // for non-executable resources. The kernelbase BasepLoadLibraryAsDataFileInternal\n    // function temporarily suppresses symbols while loading resources (both release and debug)\n    // as a QOL optimization but we only suppress debug messages for debug builds. This issue was fixed\n    // by Microsoft on Windows 10 and above with SEC_IMAGE_NO_EXECUTE and suppression is not required (dmex)\n\n    if (WindowsVersion < WINDOWS_10)\n    {\n        NtCurrentTeb()->SuppressDebugMsg = SuppressDebugMessage;\n    }\n}\n#else\n#define NtSuppressDebugMessage(SuppressDebugMessage)\n#endif\n\n/**\n * Loads a DLL as a read-only resource from a file handle.\n *\n * \\param[in] FileHandle A handle to the file containing the DLL image.\n * \\param[out,opt] BaseAddress An optional pointer that receives the base address with the image mapping flag.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function creates a read-only SEC_IMAGE section and maps it into the current\n * process. On Windows 8+, SEC_IMAGE_NO_EXECUTE is used. The returned address has the\n * LDR_IS_IMAGEMAPPING flag set (bitwise OR 2). Debug messages are suppressed during mapping\n * on Windows versions prior to Windows 10.\n */\nNTSTATUS PhLoadLibraryAsResource(\n    _In_ HANDLE FileHandle,\n    _Out_opt_ PVOID *BaseAddress\n    )\n{\n    NTSTATUS status;\n    HANDLE sectionHandle;\n    PVOID imageBaseAddress;\n    SIZE_T imageBaseSize;\n\n    status = PhCreateSection(\n        &sectionHandle,\n        SECTION_QUERY | SECTION_MAP_READ,\n        NULL,\n        PAGE_READONLY,\n        WindowsVersion < WINDOWS_8 ? SEC_IMAGE : SEC_IMAGE_NO_EXECUTE,\n        FileHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    imageBaseAddress = NULL;\n    imageBaseSize = 0;\n\n    NtSuppressDebugMessage(TRUE);\n\n    status = PhMapViewOfSection(\n        sectionHandle,\n        NtCurrentProcess(),\n        &imageBaseAddress,\n        0,\n        NULL,\n        &imageBaseSize,\n        ViewUnmap,\n        WindowsVersion < WINDOWS_10_RS2 ? 0 : MEM_MAPPED,\n        PAGE_READONLY\n        );\n\n    NtSuppressDebugMessage(FALSE);\n\n    if (status == STATUS_IMAGE_NOT_AT_BASE)\n    {\n        status = STATUS_SUCCESS;\n    }\n\n    NtClose(sectionHandle);\n\n    if (NT_SUCCESS(status))\n    {\n        // Windows returns the address with bitwise OR|2 for use with LDR_IS_IMAGEMAPPING (dmex)\n        if (BaseAddress)\n        {\n            *BaseAddress = LDR_MAPPEDVIEW_TO_IMAGEMAPPING(imageBaseAddress);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Loads a DLL as a read-only image resource from a file path.\n *\n * \\param[in] FileName The file name of the DLL as a string reference.\n * \\param[in] NativeFileName TRUE if FileName is in NT native format, FALSE for Win32 format.\n * \\param[out,opt] BaseAddress An optional pointer that receives the base address with the image mapping flag.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function opens the file and calls PhLoadLibraryAsResource(). The file is\n * opened with read-only access and share permissions.\n */\nNTSTATUS PhLoadLibraryAsImageResource(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName,\n    _Out_opt_ PVOID *BaseAddress\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n\n    if (NativeFileName)\n    {\n        status = PhCreateFile(\n            &fileHandle,\n            FileName,\n            FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n    }\n    else\n    {\n        status = PhCreateFileWin32(\n            &fileHandle,\n            FileName->Buffer,\n            FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhLoadLibraryAsResource(fileHandle, BaseAddress);\n    NtClose(fileHandle);\n\n    return status;\n}\n\n/**\n * Releases a DLL loaded as an image resource.\n *\n * \\param[in] BaseAddress The base address returned by PhLoadLibraryAsImageResource(), with the image mapping flag.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function unmaps the view created by PhLoadLibraryAsResource(). The\n * LDR_IS_IMAGEMAPPING flag is removed before unmapping. Debug messages are suppressed\n * during unmapping on Windows versions prior to Windows 10.\n */\nNTSTATUS PhFreeLibraryAsImageResource(\n    _In_ PVOID BaseAddress\n    )\n{\n    NTSTATUS status;\n\n    NtSuppressDebugMessage(TRUE);\n\n    status = PhUnmapViewOfSection(\n        NtCurrentProcess(),\n        LDR_IMAGEMAPPING_TO_MAPPEDVIEW(BaseAddress)\n        );\n\n    NtSuppressDebugMessage(FALSE);\n\n    return status;\n}\n\n/**\n * Retrieves the base address of a loaded DLL by name.\n *\n * \\param[in] DllName The base name of the DLL (e.g., \"kernel32.dll\").\n * \\return The base address of the DLL, or NULL if not found.\n * \\remarks On builds with PHNT_NATIVE_LDR, this uses LdrGetDllHandle(). Otherwise, it\n * searches the loader data table manually.\n */\nPVOID PhGetDllHandle(\n    _In_ PCWSTR DllName\n    )\n{\n#if defined(PHNT_NATIVE_LDR)\n    UNICODE_STRING dllName;\n    PVOID dllHandle;\n\n    RtlInitUnicodeString(&dllName, DllName);\n\n    if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &dllName, &dllHandle)))\n        return dllHandle;\n    else\n        return NULL;\n#else\n    PH_STRINGREF baseDllName;\n\n    PhInitializeStringRefLongHint(&baseDllName, DllName);\n\n    return PhGetLoaderEntryDllBase(NULL, &baseDllName);\n#endif\n}\n\n/**\n * Retrieves the address of an exported function from a loaded module by name.\n *\n * \\param[in] ModuleName The name of the module (e.g., \"ntdll.dll\").\n * \\param[in,opt] ProcedureName The name of the exported procedure, or an ordinal value cast to PCSTR.\n * \\return The address of the procedure, or NULL if not found.\n * \\remarks This function first locates the module, then retrieves the procedure address.\n * Ordinal values should be passed using the IS_INTRESOURCE macro.\n */\nPVOID PhGetModuleProcAddress(\n    _In_ PCWSTR ModuleName,\n    _In_opt_ PCSTR ProcedureName\n    )\n{\n#if defined(PHNT_NATIVE_LDR)\n    PVOID module;\n\n    module = PhGetDllHandle(ModuleName);\n\n    if (module)\n        return PhGetProcedureAddress(module, ProcedureName, 0);\n    else\n        return NULL;\n#else\n    PH_STRINGREF baseDllName;\n\n    PhInitializeStringRefLongHint(&baseDllName, ModuleName);\n\n    if (IS_INTRESOURCE(ProcedureName))\n        return PhGetDllProcedureAddress(&baseDllName, NULL, PtrToUshort(ProcedureName));\n\n    return PhGetDllProcedureAddress(&baseDllName, ProcedureName, 0);\n#endif\n}\n\n/**\n * Retrieves the address of an exported function from a loaded DLL.\n *\n * \\param[in] DllHandle The base address of the DLL.\n * \\param[in,opt] ProcedureName The name of the exported procedure. Specify NULL to use ProcedureNumber.\n * \\param[in,opt] ProcedureNumber The ordinal of the exported procedure. Specify 0 to use ProcedureName.\n * \\return The address of the procedure, or NULL if not found.\n * \\remarks On builds with PHNT_NATIVE_LDR, this uses LdrGetProcedureAddress(). Otherwise,\n * it calls PhGetDllBaseProcedureAddress() which handles export suppression and forwarding.\n */\nPVOID PhGetProcedureAddress(\n    _In_ PVOID DllHandle,\n    _In_opt_ PCSTR ProcedureName,\n    _In_opt_ USHORT ProcedureNumber\n    )\n{\n#if defined(PHNT_NATIVE_LDR)\n    NTSTATUS status;\n    ANSI_STRING procedureName;\n    PVOID procedureAddress;\n\n    if (ProcedureName)\n    {\n        RtlInitAnsiString(&procedureName, ProcedureName);\n        status = LdrGetProcedureAddress(\n            DllHandle,\n            &procedureName,\n            0,\n            &procedureAddress\n            );\n    }\n    else\n    {\n        status = LdrGetProcedureAddress(\n            DllHandle,\n            NULL,\n            ProcedureNumber,\n            &procedureAddress\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    return procedureAddress;\n#else\n    return PhGetDllBaseProcedureAddress(DllHandle, ProcedureName, ProcedureNumber);\n#endif\n}\n\ntypedef struct _PH_PROCEDURE_ADDRESS_REMOTE_CONTEXT\n{\n    PVOID DllBase;\n    PPH_STRING FileName;\n} PH_PROCEDURE_ADDRESS_REMOTE_CONTEXT, *PPH_PROCEDURE_ADDRESS_REMOTE_CONTEXT;\n\n/**\n * Callback function for limited module enumeration during remote procedure address lookup.\n *\n * \\param [in] ProcessHandle A handle to the target process.\n * \\param [in] VirtualAddress The virtual address of the module.\n * \\param [in] ImageBase The base address of the module.\n * \\param [in] ImageSize The size of the module image in bytes.\n * \\param [in] FileName The file name of the module.\n * \\param [in] Context A pointer to PH_PROCEDURE_ADDRESS_REMOTE_CONTEXT containing search criteria.\n * \\return STATUS_SUCCESS to continue enumeration, or STATUS_NO_MORE_ENTRIES to stop when a match is found.\n * \\remarks This callback is used with limited process module enumeration (PROCESS_QUERY_LIMITED_INFORMATION)\n * to locate a DLL by name in a remote process. When the file name matches the search criteria, it stores\n * the base address in the context and returns STATUS_NO_MORE_ENTRIES to terminate enumeration.\n */\n_Function_class_(PH_ENUM_PROCESS_MODULES_LIMITED_CALLBACK)\nstatic NTSTATUS NTAPI PhpGetProcedureAddressRemoteLimitedCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress,\n    _In_ PVOID ImageBase,\n    _In_ SIZE_T ImageSize,\n    _In_ PPH_STRING FileName,\n    _In_ PPH_PROCEDURE_ADDRESS_REMOTE_CONTEXT Context\n    )\n{\n    if (PhEqualString(FileName, Context->FileName, TRUE))\n    {\n        Context->DllBase = ImageBase;\n        return STATUS_NO_MORE_ENTRIES;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Callback function for full module enumeration during remote procedure address lookup.\n *\n * \\param [in] Module A pointer to the loader data table entry for the module.\n * \\param [in] Context A pointer to PH_PROCEDURE_ADDRESS_REMOTE_CONTEXT containing search criteria.\n * \\return TRUE to continue enumeration, FALSE to stop when a match is found.\n * \\remarks This callback is used with full process module enumeration (requiring PROCESS_VM_READ)\n * to locate a DLL by its full path in a remote process. When the full DLL name matches the search\n * criteria, it stores the base address in the context and returns FALSE to terminate enumeration.\n */\n_Function_class_(PH_ENUM_PROCESS_MODULES_CALLBACK)\nstatic BOOLEAN PhpGetProcedureAddressRemoteCallback(\n    _In_ PLDR_DATA_TABLE_ENTRY Module,\n    _In_ PPH_PROCEDURE_ADDRESS_REMOTE_CONTEXT Context\n    )\n{\n    PH_STRINGREF fullDllName;\n\n    PhUnicodeStringToStringRef(&Module->FullDllName, &fullDllName);\n\n    if (PhEqualStringRef(&fullDllName, &Context->FileName->sr, TRUE))\n    {\n        Context->DllBase = Module->DllBase;\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Gets the address of a procedure in a process.\n *\n * \\param[in] ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param[in] FileName The file name of the DLL containing the procedure.\n * \\param[in] ProcedureName The name or ordinal of the procedure.\n * \\param[out] ProcedureAddress A variable which receives the address of the procedure in the address\n * space of the process.\n * \\param[out,opt] DllBase A variable which receives the base address of the DLL containing the procedure.\n */\nNTSTATUS PhGetProcedureAddressRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PCSTR ProcedureName,\n    _Out_ PVOID *ProcedureAddress,\n    _Out_opt_ PVOID *DllBase\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName = NULL;\n    PH_MAPPED_IMAGE mappedImage;\n    PH_MAPPED_IMAGE_EXPORTS exports;\n    PH_PROCEDURE_ADDRESS_REMOTE_CONTEXT context;\n    PH_ENUM_PROCESS_MODULES_PARAMETERS parameters;\n#ifdef _M_ARM64\n    USHORT processArchitecture;\n    ULONG exportsFlags;\n#endif\n\n    status = PhLoadMappedImageEx(\n        FileName,\n        NULL,\n        &mappedImage\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    fileName = PhDosPathNameToNtPathName(FileName);\n\n    if (PhIsNullOrEmptyString(fileName))\n    {\n        status = PhGetProcessMappedFileName(\n            NtCurrentProcess(),\n            mappedImage.ViewBase,\n            &fileName\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    memset(&context, 0, sizeof(PH_PROCEDURE_ADDRESS_REMOTE_CONTEXT));\n    context.FileName = fileName;\n\n    status = PhEnumProcessModulesLimited(\n        ProcessHandle,\n        PhpGetProcedureAddressRemoteLimitedCallback,\n        &context\n        );\n\n    if (!context.DllBase)\n    {\n        memset(&parameters, 0, sizeof(PH_ENUM_PROCESS_MODULES_PARAMETERS));\n        parameters.Callback = PhpGetProcedureAddressRemoteCallback;\n        parameters.Context = &context;\n        parameters.Flags = PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME;\n\n        switch (mappedImage.Magic)\n        {\n        case IMAGE_NT_OPTIONAL_HDR32_MAGIC:\n            status = PhEnumProcessModules32Ex(ProcessHandle, &parameters);\n            break;\n        case IMAGE_NT_OPTIONAL_HDR64_MAGIC:\n            status = PhEnumProcessModulesEx(ProcessHandle, &parameters);\n            break;\n        default:\n            status = STATUS_NOT_SUPPORTED;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    if (!context.DllBase)\n    {\n        status = STATUS_DLL_NOT_FOUND;\n        goto CleanupExit;\n    }\n\n#ifdef _M_ARM64\n    exportsFlags = 0;\n    if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC &&\n        mappedImage.NtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64)\n    {\n        status = PhGetProcessArchitecture(ProcessHandle, &processArchitecture);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        if (processArchitecture == IMAGE_FILE_MACHINE_AMD64)\n            exportsFlags |= PH_GET_IMAGE_EXPORTS_ARM64X;\n    }\n\n    status = PhGetMappedImageExportsEx(&exports, &mappedImage, exportsFlags);\n#else\n    status = PhGetMappedImageExports(&exports, &mappedImage);\n#endif\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (IS_INTRESOURCE(ProcedureName))\n    {\n        status = PhGetMappedImageExportFunctionRemote(\n            &exports,\n            NULL,\n            PtrToUshort(ProcedureName),\n            context.DllBase,\n            ProcedureAddress\n            );\n    }\n    else\n    {\n        status = PhGetMappedImageExportFunctionRemote(\n            &exports,\n            ProcedureName,\n            0,\n            context.DllBase,\n            ProcedureAddress\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (DllBase)\n            *DllBase = context.DllBase;\n    }\n\nCleanupExit:\n    PhUnloadMappedImage(&mappedImage);\n    PhClearReference(&fileName);\n\n    return status;\n}\n\n// rev from LdrAccessResource (dmex)\n//NTSTATUS PhAccessResource(\n//    _In_ PVOID DllBase,\n//    _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,\n//    _Out_opt_ PVOID *ResourceBuffer,\n//    _Out_opt_ ULONG *ResourceLength\n//    )\n//{\n//    PVOID baseAddress;\n//\n//    if (LDR_IS_DATAFILE(DllBase))\n//        baseAddress = LDR_DATAFILE_TO_MAPPEDVIEW(DllBase);\n//    else if (LDR_IS_IMAGEMAPPING(DllBase))\n//        baseAddress = LDR_IMAGEMAPPING_TO_MAPPEDVIEW(DllBase);\n//    else\n//        baseAddress = DllBase;\n//\n//    if (ResourceLength)\n//    {\n//        *ResourceLength = ResourceDataEntry->Size;\n//    }\n//\n//    if (ResourceBuffer)\n//    {\n//        if (LDR_IS_DATAFILE(DllBase))\n//        {\n//            NTSTATUS status;\n//\n//            status = PhLoaderEntryImageRvaToVa(\n//                baseAddress,\n//                ResourceDataEntry->OffsetToData,\n//                ResourceBuffer\n//                );\n//\n//            return status;\n//        }\n//        else\n//        {\n//            *ResourceBuffer = PTR_ADD_OFFSET(\n//                baseAddress,\n//                ResourceDataEntry->OffsetToData\n//                );\n//\n//            return STATUS_SUCCESS;\n//        }\n//    }\n//\n//    return STATUS_SUCCESS;\n//}\n\n/**\n * Finds and returns the address of a resource.\n *\n * \\param[in] DllBase The base address of the image containing the resource.\n * \\param[in] Name The name of the resource or the integer identifier.\n * \\param[in] Type The type of resource or the integer identifier.\n * \\param[out,opt] ResourceLength A variable which will receive the length of the resource block.\n * \\param[out,opt] ResourceBuffer A variable which receives the address of the resource data.\n * \\return TRUE if the resource was found, FALSE if an error occurred.\n * \\remarks Use this function instead of LoadResource() because no memory allocation is required.\n * This function returns the address of the resource from the read-only section of the image\n * and does not need to be allocated or deallocated. This function cannot be used when the\n * image will be unloaded since the validity of the address is tied to the lifetime of the image.\n */\nNTSTATUS PhLoadResource(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _Out_opt_ ULONG *ResourceLength,\n    _Out_opt_ PVOID *ResourceBuffer\n    )\n{\n    NTSTATUS status;\n    PIMAGE_RESOURCE_DATA_ENTRY resourceData = NULL;\n    PVOID resourceBuffer = NULL;\n    ULONG resourceLength;\n    ULONG_PTR resourcePath[] = {\n        (ULONG_PTR)Type,\n        (ULONG_PTR)Name,\n        MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)\n    };\n\n    __try\n    {\n        status = LdrFindResource_U(DllBase, resourcePath, RTL_NUMBER_OF(resourcePath), &resourceData);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    __try\n    {\n        status = LdrAccessResource(DllBase, resourceData, &resourceBuffer, &resourceLength);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        status = GetExceptionCode();\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (ResourceLength)\n        *ResourceLength = resourceLength;\n    if (ResourceBuffer)\n        *ResourceBuffer = resourceBuffer;\n\n    return status;\n}\n\n /**\n  * Finds and returns a copy of the resource.\n  *\n  * \\param[in] DllBase The base address of the image containing the resource.\n  * \\param[in] Name The name of the resource or the integer identifier.\n  * \\param[in] Type The type of resource or the integer identifier.\n  * \\param[out,opt] ResourceLength A variable which will receive the length of the resource block.\n  * \\param[out,opt] ResourceBuffer A variable which receives the address of the resource data.\n  * \\return TRUE if the resource was found, FALSE if an error occurred.\n  * \\remarks This function returns a copy of a resource from heap memory\n  * and must be deallocated. Use this function when the image will be unloaded.\n  */\nNTSTATUS PhLoadResourceCopy(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _Out_opt_ ULONG *ResourceLength,\n    _Out_opt_ PVOID *ResourceBuffer\n    )\n{\n    NTSTATUS status;\n    ULONG resourceLength;\n    PVOID resourceBuffer;\n\n    status = PhLoadResource(\n        DllBase,\n        Name,\n        Type,\n        &resourceLength,\n        &resourceBuffer\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (ResourceLength)\n            *ResourceLength = resourceLength;\n        if (ResourceBuffer)\n            *ResourceBuffer = PhAllocateCopy(resourceBuffer, resourceLength);\n    }\n\n    return status;\n}\n\n// rev from LoadString (dmex)\n/**\n * Loads a string resource from the image into a buffer.\n *\n * \\param[in] DllBase The base address of the image containing the resource.\n * \\param[in] ResourceId The identifier of the string to be loaded.\n * \\return A string containing a copy of the string resource.\n */\nPPH_STRING PhLoadString(\n    _In_ PVOID DllBase,\n    _In_ ULONG ResourceId\n    )\n{\n    ULONG resourceId = (LOWORD(ResourceId) >> 4) + 1;\n    PIMAGE_RESOURCE_DIR_STRING_U stringBuffer;\n    PPH_STRING string = NULL;\n    ULONG resourceLength;\n    PVOID resourceBuffer;\n    ULONG stringIndex;\n\n    if (!NT_SUCCESS(PhLoadResource(\n        DllBase,\n        MAKEINTRESOURCE(resourceId),\n        RT_STRING,\n        &resourceLength,\n        &resourceBuffer\n        )))\n    {\n        return NULL;\n    }\n\n    if (!resourceBuffer)\n        return NULL;\n\n    stringBuffer = resourceBuffer;\n    stringIndex = ResourceId & 0x000F;\n\n    for (ULONG i = 0; i < stringIndex; i++)\n    {\n        stringBuffer = PTR_ADD_OFFSET(stringBuffer, (stringBuffer->Length + sizeof(ANSI_NULL)) * sizeof(WCHAR)); // ANSI_NULL required (dmex)\n    }\n\n    if (\n        stringBuffer->Length > 0 && // sizeof(UNICODE_NULL) || resourceLength\n        stringBuffer->Length < UNICODE_STRING_MAX_BYTES\n        )\n    {\n        string = PhCreateStringEx(\n            stringBuffer->NameString,\n            stringBuffer->Length * sizeof(WCHAR) - sizeof(UNICODE_NULL)\n            );\n    }\n\n    return string;\n}\n\n// rev from SHLoadIndirectString (dmex)\n/**\n * Extracts a specified text resource when given that resource in the form of an indirect string (a string that begins with the '@' symbol).\n * \\param[in] SourceString The indirect string from which the resource will be retrieved.\n */\nPPH_STRING PhLoadIndirectString(\n    _In_ PCPH_STRINGREF SourceString\n    )\n{\n    PPH_STRING indirectString = NULL;\n\n    if (!SourceString || !SourceString->Buffer)\n        return NULL;\n\n    if (SourceString->Buffer[0] == L'@')\n    {\n        PPH_STRING libraryString;\n        PVOID libraryModule;\n        PH_STRINGREF sourceRef;\n        PH_STRINGREF dllNameRef;\n        PH_STRINGREF dllIndexRef;\n        LONG64 index64;\n        LONG index;\n\n        sourceRef.Length = SourceString->Length;\n        sourceRef.Buffer = SourceString->Buffer;\n        PhSkipStringRef(&sourceRef, sizeof(WCHAR)); // Skip the @ character.\n\n        if (!PhSplitStringRefAtChar(&sourceRef, L',', &dllNameRef, &dllIndexRef))\n            return NULL;\n\n        if (!PhStringToInteger64(&dllIndexRef, 10, &index64))\n        {\n            // HACK: Services.exe includes custom logic for indirect Service description strings by reading descriptions from inf files,\n            // these strings use the following format: \"@FileName.inf,%SectionKeyName%;DefaultString\".\n            // Return the last token of the service string instead of locating and parsing the inf file with GetPrivateProfileString.\n            if (PhSplitStringRefAtChar(&sourceRef, L';', &dllNameRef, &dllIndexRef)) // dllIndexRef.Buffer[0] == L'%'\n            {\n                return PhCreateString2(&dllIndexRef);\n            }\n\n            return NULL;\n        }\n\n        libraryString = PhCreateString2(&dllNameRef);\n        index = (LONG)index64;\n\n        if (libraryString->Buffer[0] == L'%')\n        {\n            PPH_STRING expandedString;\n\n            if (expandedString = PhExpandEnvironmentStrings(&libraryString->sr))\n                PhMoveReference(&libraryString, expandedString);\n        }\n\n        if (PhDetermineDosPathNameType(&libraryString->sr) == RtlPathTypeRelative)\n        {\n            PPH_STRING librarySearchPathString;\n\n            if (librarySearchPathString = PhSearchFilePath(libraryString->Buffer, L\".dll\"))\n            {\n                PhMoveReference(&libraryString, librarySearchPathString);\n            }\n        }\n\n        if (NT_SUCCESS(PhLoadLibraryAsImageResource(&libraryString->sr, FALSE, &libraryModule)))\n        {\n            indirectString = PhLoadString(libraryModule, -index);\n            PhFreeLibraryAsImageResource(libraryModule);\n        }\n\n        PhDereferenceObject(libraryString);\n    }\n\n    return indirectString;\n}\n\n/**\n * Retrieves the file name of a DLL loaded by the current process.\n *\n * \\param[in] DllBase The base address of the DLL.\n * \\param[out,opt] IndexOfFileName A variable which receives the index of the base name of the DLL in the\n * returned string.\n * \\return The file name of the DLL, or NULL if the DLL could not be found.\n */\n_Success_(return != NULL)\nPPH_STRING PhGetDllFileName(\n    _In_ PVOID DllBase,\n    _Out_opt_ PULONG IndexOfFileName\n    )\n{\n    PLDR_DATA_TABLE_ENTRY entry;\n    PPH_STRING fileName;\n    ULONG_PTR indexOfFileName;\n\n    PhAcquireLoaderLock();\n\n    entry = PhFindLoaderEntry(DllBase, NULL, NULL);\n\n    if (entry)\n        fileName = PhCreateStringFromUnicodeString(&entry->FullDllName);\n    else\n        fileName = NULL;\n\n    PhReleaseLoaderLock();\n\n    if (!fileName)\n        return NULL;\n\n    PhMoveReference(&fileName, PhGetFileName(fileName));\n\n    if (IndexOfFileName)\n    {\n        indexOfFileName = PhFindLastCharInString(fileName, 0, OBJ_NAME_PATH_SEPARATOR);\n\n        if (indexOfFileName != SIZE_MAX)\n            indexOfFileName++;\n        else\n            indexOfFileName = 0;\n\n        *IndexOfFileName = (ULONG)indexOfFileName;\n    }\n\n    return fileName;\n}\n\n/**\n * Retrieves information about a loaded DLL by its base name.\n *\n * \\param[in] BaseDllName The base name of the DLL as a string reference (e.g., \"kernel32.dll\").\n * \\param[out,opt] DllBase An optional pointer that receives the base address of the DLL.\n * \\param[out,opt] SizeOfImage An optional pointer that receives the size of the image in bytes.\n * \\param[out,opt] FullName An optional pointer that receives the full path to the DLL.\n * \\return TRUE if the DLL was found, FALSE otherwise.\n * \\remarks This function searches the loader data table with the loader lock held.\n */\n_Success_(return)\nBOOLEAN PhGetLoaderEntryData(\n    _In_ PCPH_STRINGREF BaseDllName,\n    _Out_opt_ PVOID* DllBase,\n    _Out_opt_ ULONG* SizeOfImage,\n    _Out_opt_ PPH_STRING* FullName\n    )\n{\n    BOOLEAN result = FALSE;\n    PLDR_DATA_TABLE_ENTRY entry;\n\n    PhAcquireLoaderLock();\n\n    entry = PhFindLoaderEntry(NULL, NULL, BaseDllName);\n\n    if (entry)\n    {\n        if (DllBase)\n        {\n            *DllBase = entry->DllBase;\n            result = TRUE;\n        }\n\n        if (SizeOfImage)\n        {\n            *SizeOfImage = entry->SizeOfImage;\n            result = TRUE;\n        }\n\n        if (FullName)\n        {\n            PH_STRINGREF fullName;\n            PPH_STRING fileName;\n\n            PhUnicodeStringToStringRef(&entry->FullDllName, &fullName);\n\n            if (fileName = PhDosPathNameToNtPathName(&fullName))\n            {\n                *FullName = fileName;\n                result = TRUE;\n            }\n            else\n            {\n                result = FALSE;\n            }\n        }\n    }\n\n    PhReleaseLoaderLock();\n\n    return result;\n}\n\n/**\n * Retrieves the base address of a DLL containing the specified address.\n *\n * \\param[in] Address An address within the DLL's address space.\n * \\return The base address of the DLL, or NULL if not found.\n * \\remarks This function searches the loader data table with the loader lock held.\n */\nPVOID PhGetLoaderEntryAddressDllBase(\n    _In_ PVOID Address\n    )\n{\n    PLDR_DATA_TABLE_ENTRY entry;\n    PVOID baseAddress;\n\n    PhAcquireLoaderLock();\n\n    entry = PhFindLoaderEntryAddress(Address);\n\n    if (entry)\n        baseAddress = entry->DllBase;\n    else\n        baseAddress = NULL;\n\n    PhReleaseLoaderLock();\n\n    return baseAddress;\n}\n\n/**\n * Retrieves the base address of a DLL by name.\n *\n * \\param[in,opt] FullDllName The full path to the DLL. Specify NULL if not used.\n * \\param[in,opt] BaseDllName The base name of the DLL (e.g., \"kernel32.dll\"). Specify NULL if not used.\n * \\return The base address of the DLL, or NULL if not found.\n * \\remarks On Windows 8 and later, when only BaseDllName is specified, this function uses\n * hash-based lookup for improved performance. Otherwise it performs a linear search.\n */\nPVOID PhGetLoaderEntryDllBase(\n    _In_opt_ PCPH_STRINGREF FullDllName,\n    _In_opt_ PCPH_STRINGREF BaseDllName\n    )\n{\n    PLDR_DATA_TABLE_ENTRY entry;\n    PVOID baseAddress;\n\n    PhAcquireLoaderLock();\n\n    if (WindowsVersion >= WINDOWS_8 && !FullDllName && BaseDllName)\n    {\n        ULONG baseNameHash = PhHashStringRefEx(BaseDllName, TRUE, PH_STRING_HASH_X65599);\n\n        entry = PhFindLoaderEntryNameHash(baseNameHash);\n    }\n    else\n    {\n        entry = PhFindLoaderEntry(NULL, FullDllName, BaseDllName);\n    }\n\n    if (entry)\n        baseAddress = entry->DllBase;\n    else\n        baseAddress = NULL;\n\n    PhReleaseLoaderLock();\n\n    return baseAddress;\n}\n\n/**\n * Retrieves the address of an exported function from a loaded DLL.\n *\n * \\param[in] DllBase The base address of the DLL.\n * \\param[in,opt] ProcedureName The name of the exported procedure. Specify NULL to use ProcedureNumber.\n * \\param[in,opt] ProcedureNumber The ordinal number of the exported procedure. Specify 0 to use ProcedureName.\n * \\return The address of the exported function, or NULL if the function could not be found.\n * \\remarks This function supports Control Flow Guard (CFG) export suppression on Windows 10 RS2 and later.\n * It also handles forwarded exports by recursively resolving them through the forwarding chain.\n */\nPVOID PhGetDllBaseProcedureAddress(\n    _In_ PVOID DllBase,\n    _In_opt_ PCSTR ProcedureName,\n    _In_opt_ USHORT ProcedureNumber\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOLEAN exportSuppressionEnabled = FALSE;\n    PVOID exportAddress;\n    PIMAGE_NT_HEADERS imageNtHeader;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_EXPORT_DIRECTORY exportDirectory;\n    PROCESS_MITIGATION_POLICY_INFORMATION mitigation;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if ((WindowsVersion >= WINDOWS_10_RS2) &&\n            NT_SUCCESS(PhGetProcessMitigationPolicy(NtCurrentProcess(), ProcessControlFlowGuardPolicy, &mitigation)) &&\n            mitigation.ControlFlowGuardPolicy.EnableExportSuppression)\n        {\n            exportSuppressionEnabled = TRUE;\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!NT_SUCCESS(PhGetLoaderEntryImageNtHeaders(DllBase, &imageNtHeader)))\n        return NULL;\n\n    if (!NT_SUCCESS(PhGetLoaderEntryImageDirectory(\n        DllBase,\n        imageNtHeader,\n        IMAGE_DIRECTORY_ENTRY_EXPORT,\n        &dataDirectory,\n        &exportDirectory,\n        NULL\n        )))\n        return NULL;\n\n    exportAddress = PhGetLoaderEntryImageExportFunction(\n        DllBase,\n        imageNtHeader,\n        dataDirectory,\n        exportDirectory,\n        ProcedureName,\n        ProcedureNumber\n        );\n\n    if (exportAddress && exportSuppressionEnabled)\n    {\n        if (PhLoaderEntryImageExportSupressionPresent(DllBase, imageNtHeader))\n        {\n            PhLoaderEntryGrantSuppressedCall(exportAddress);\n        }\n    }\n\n    return exportAddress;\n}\n\n/**\n * Retrieves the address of an exported function from a loaded DLL.\n *\n * \\param[in] BaseAddress The base address of the DLL.\n * \\param[in,opt] ProcedureName The name of the exported procedure, or an ordinal value cast to a pointer.\n * \\return The address of the exported function, or NULL if the function could not be found.\n * \\remarks This is a convenience wrapper around PhGetDllBaseProcedureAddress that automatically\n * determines whether ProcedureName is a name or an ordinal based on IS_INTRESOURCE.\n */\nPVOID PhGetDllBaseProcAddress(\n    _In_ PVOID BaseAddress,\n    _In_opt_ PCSTR ProcedureName\n    )\n{\n    if (IS_INTRESOURCE(ProcedureName))\n        return PhGetDllBaseProcedureAddress(BaseAddress, NULL, PtrToUshort(ProcedureName));\n\n    return PhGetDllBaseProcedureAddress(BaseAddress, ProcedureName, 0);\n}\n\n/**\n * Retrieves the address of an exported function from a DLL by name.\n *\n * \\param[in] DllName The name of the DLL.\n * \\param[in,opt] ProcedureName The name of the exported procedure. Specify NULL to use ProcedureNumber.\n * \\param[in,opt] ProcedureNumber The ordinal number of the exported procedure. Specify 0 to use ProcedureName.\n * \\return The address of the exported function, or NULL if the DLL or function could not be found.\n * \\remarks This function first locates the DLL in the loader data, then resolves the export address.\n */\nPVOID PhGetDllProcedureAddress(\n    _In_ PCPH_STRINGREF DllName,\n    _In_opt_ PCSTR ProcedureName,\n    _In_opt_ USHORT ProcedureNumber\n    )\n{\n    PVOID baseAddress;\n\n    if (!(baseAddress = PhGetLoaderEntryDllBase(NULL, DllName)))\n        return NULL;\n\n    return PhGetDllBaseProcedureAddress(\n        baseAddress,\n        ProcedureName,\n        ProcedureNumber\n        );\n}\n\n/**\n * Retrieves the NT headers of a loaded image.\n *\n * \\param[in] BaseAddress The base address of the image.\n * \\param[out] ImageNtHeaders A variable which receives a pointer to the NT headers.\n * \\return An NTSTATUS code indicating success or failure.\n * \\retval STATUS_INVALID_IMAGE_NOT_MZ The DOS signature is invalid.\n * \\retval STATUS_INVALID_IMAGE_FORMAT The NT headers offset or signature is invalid.\n * \\remarks This function validates the DOS and NT signatures before returning the NT headers pointer.\n */\nNTSTATUS PhGetLoaderEntryImageNtHeaders(\n    _In_ PVOID BaseAddress,\n    _Out_ PIMAGE_NT_HEADERS *ImageNtHeaders\n    )\n{\n    PIMAGE_DOS_HEADER imageDosHeader;\n    PIMAGE_NT_HEADERS imageNtHeaders;\n    ULONG imageNtHeadersOffset;\n\n    imageDosHeader = PTR_ADD_OFFSET(BaseAddress, 0);\n\n    if (imageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)\n        return STATUS_INVALID_IMAGE_NOT_MZ;\n\n    imageNtHeadersOffset = (ULONG)imageDosHeader->e_lfanew;\n\n    if (imageNtHeadersOffset == 0 || imageNtHeadersOffset >= RTL_IMAGE_MAX_DOS_HEADER)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    imageNtHeaders = PTR_ADD_OFFSET(BaseAddress, imageNtHeadersOffset);\n\n    if (imageNtHeaders->Signature != IMAGE_NT_SIGNATURE)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    *ImageNtHeaders = imageNtHeaders;\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves the entry point address of an image.\n *\n * \\param[in] BaseAddress The base address of the image.\n * \\param[in] ImageNtHeader The NT headers of the image.\n * \\param[out] ImageEntryPoint A variable which receives the entry point address.\n * \\return An NTSTATUS code indicating success or failure.\n * \\retval STATUS_ENTRYPOINT_NOT_FOUND The image has no entry point.\n * \\remarks Some images, such as resource-only DLLs, may not have an entry point.\n */\nNTSTATUS PhGetLoaderEntryImageEntryPoint(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _Out_ PDLL_INIT_ROUTINE *ImageEntryPoint\n    )\n{\n    if (ImageNtHeader->OptionalHeader.AddressOfEntryPoint == 0)\n        return STATUS_ENTRYPOINT_NOT_FOUND;\n\n    *ImageEntryPoint = PTR_ADD_OFFSET(BaseAddress, ImageNtHeader->OptionalHeader.AddressOfEntryPoint);\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves a data directory entry from an image.\n *\n * \\param[in] BaseAddress The base address of the image.\n * \\param[in] ImageNtHeader The NT headers of the image.\n * \\param[in] ImageDirectoryIndex The index of the data directory (e.g., IMAGE_DIRECTORY_ENTRY_EXPORT).\n * \\param[out] ImageDataDirectoryEntry A variable which receives a pointer to the data directory entry.\n * \\param[out] ImageDirectoryEntry A variable which receives the virtual address of the directory data.\n * \\param[out,opt] ImageDirectoryLength A variable which optionally receives the size of the directory.\n * \\return An NTSTATUS code indicating success or failure.\n * \\retval STATUS_INVALID_FILE_FOR_SECTION The directory index is invalid or the directory is empty.\n */\nNTSTATUS PhGetLoaderEntryImageDirectory(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ ULONG ImageDirectoryIndex,\n    _Out_ PIMAGE_DATA_DIRECTORY *ImageDataDirectoryEntry,\n    _Out_ PVOID *ImageDirectoryEntry,\n    _Out_opt_ SIZE_T *ImageDirectoryLength\n    )\n{\n    PIMAGE_DATA_DIRECTORY directory;\n\n    directory = &ImageNtHeader->OptionalHeader.DataDirectory[ImageDirectoryIndex];\n\n    //if (ImageNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)\n    //{\n    //    PIMAGE_OPTIONAL_HEADER32 optionalHeader;\n    //\n    //    optionalHeader = &((PIMAGE_NT_HEADERS32)ImageNtHeader)->OptionalHeader;\n    //\n    //    if (ImageDirectoryIndex >= optionalHeader->NumberOfRvaAndSizes)\n    //        return STATUS_INVALID_FILE_FOR_SECTION;\n    //\n    //    directory = &optionalHeader->DataDirectory[ImageDirectoryIndex];\n    //}\n    //else if (ImageNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)\n    //{\n    //    PIMAGE_OPTIONAL_HEADER64 optionalHeader;\n    //\n    //    optionalHeader = &((PIMAGE_NT_HEADERS64)ImageNtHeader)->OptionalHeader;\n    //\n    //    if (ImageDirectoryIndex >= optionalHeader->NumberOfRvaAndSizes)\n    //        return STATUS_INVALID_FILE_FOR_SECTION;\n    //\n    //    directory = &optionalHeader->DataDirectory[ImageDirectoryIndex];\n    //}\n    //else\n    //{\n    //    return STATUS_INVALID_FILE_FOR_SECTION;\n    //}\n\n    if (directory->VirtualAddress == 0 || directory->Size == 0)\n        return STATUS_INVALID_FILE_FOR_SECTION;\n\n    *ImageDataDirectoryEntry = directory;\n    *ImageDirectoryEntry = PTR_ADD_OFFSET(BaseAddress, directory->VirtualAddress);\n    if (ImageDirectoryLength) *ImageDirectoryLength = directory->Size;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Locates the section containing a given virtual address.\n *\n * \\param[in] BaseAddress The base address of the image.\n * \\param[in] ImageNtHeader The NT headers of the image.\n * \\param[in] ImageDirectoryAddress The virtual address to locate.\n * \\param[out] ImageSectionAddress A pointer that receives the base address of the section.\n * \\param[out] ImageSectionLength A pointer that receives the size of the section.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_SECTION_NOT_IMAGE The address is not within any section.\n * \\remarks This function iterates through all sections to find which one contains the\n * specified address. Section size is calculated as the maximum of VirtualSize and SizeOfRawData.\n */\nNTSTATUS PhGetLoaderEntryImageVaToSection(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ PVOID ImageDirectoryAddress,\n    _Out_ PVOID *ImageSectionAddress,\n    _Out_ SIZE_T *ImageSectionLength\n    )\n{\n    SIZE_T directorySectionLength = 0;\n    PIMAGE_SECTION_HEADER section;\n    PIMAGE_SECTION_HEADER sectionHeader;\n    PVOID directorySectionAddress = NULL;\n    PVOID imageSectionStart;\n    ULONG imageSectionSize;\n    PVOID imageSectionEnd;\n\n    section = IMAGE_FIRST_SECTION(ImageNtHeader);\n\n    for (USHORT i = 0; i < ImageNtHeader->FileHeader.NumberOfSections; i++)\n    {\n        sectionHeader = PTR_ADD_OFFSET(section, UInt32x32To64(IMAGE_SIZEOF_SECTION_HEADER, i));\n\n        // Note: VirtualSize is used by the loader, SizeOfRawData is used for file on disk.\n        // A .bss section in a PE file might have SizeOfRawData = 0 (since it is not stored in the file) \n        // and VirtualSize = 4096 (the amount of memory to allocate and zero-fill).\n        // The section length must be the maximum of the two values.\n\n        imageSectionStart = PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress);\n        imageSectionSize = max(sectionHeader->Misc.VirtualSize, sectionHeader->SizeOfRawData);\n        imageSectionEnd = PTR_ADD_OFFSET(imageSectionStart, imageSectionSize);\n\n        if (\n            ((ULONG_PTR)ImageDirectoryAddress >= (ULONG_PTR)imageSectionStart) &&\n            ((ULONG_PTR)ImageDirectoryAddress < (ULONG_PTR)imageSectionEnd)\n            )\n        {\n            directorySectionLength = imageSectionSize;\n            directorySectionAddress = imageSectionStart;\n            break;\n        }\n    }\n\n    if (directorySectionAddress && directorySectionLength)\n    {\n        *ImageSectionAddress = directorySectionAddress;\n        *ImageSectionLength = directorySectionLength;\n        return STATUS_SUCCESS;\n    }\n\n    *ImageSectionAddress = NULL;\n    *ImageSectionLength = 0;\n    return STATUS_SECTION_NOT_IMAGE;\n}\n\n/**\n * Converts an RVA to a file offset within an image.\n *\n * \\param[in] ImageNtHeader The NT headers of the image.\n * \\param[in] Rva The relative virtual address to convert.\n * \\param[out] Offset A pointer that receives the file offset.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_NOT_FOUND The RVA is not within any section's raw data range.\n * \\remarks This function calculates the file offset by finding the section containing\n * the RVA and adjusting for the section's PointerToRawData.\n */\nNTSTATUS PhLoaderEntryImageRvaToFileOffset(\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ ULONG Rva,\n    _Out_ PULONG Offset\n    )\n{\n    PIMAGE_SECTION_HEADER section;\n    PIMAGE_SECTION_HEADER sectionHeader;\n\n    section = IMAGE_FIRST_SECTION(ImageNtHeader);\n\n    for (USHORT i = 0; i < ImageNtHeader->FileHeader.NumberOfSections; i++)\n    {\n        sectionHeader = PTR_ADD_OFFSET(section, UInt32x32To64(IMAGE_SIZEOF_SECTION_HEADER, i));\n\n        if (\n            Rva >= sectionHeader->VirtualAddress &&\n            Rva < sectionHeader->VirtualAddress + sectionHeader->SizeOfRawData\n            )\n        {\n            *Offset = sectionHeader->PointerToRawData + (Rva - sectionHeader->VirtualAddress);\n            return STATUS_SUCCESS;\n        }\n    }\n\n    *Offset = 0;\n    return STATUS_NOT_FOUND;\n}\n\n/**\n * Locates the section header containing a given RVA.\n *\n * \\param[in] ImageNtHeader The NT headers of the image.\n * \\param[in] Rva The relative virtual address to locate.\n * \\param[out] ImageSection A pointer that receives the section header.\n * \\param[out] ImageSectionLength A pointer that receives the section size.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_SECTION_NOT_IMAGE The RVA is not within any section.\n * \\remarks Section size is calculated as the maximum of VirtualSize and SizeOfRawData\n * to handle both memory-mapped and file-mapped scenarios correctly.\n */\nNTSTATUS PhLoaderEntryImageRvaToSection(\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ ULONG Rva,\n    _Out_ PIMAGE_SECTION_HEADER *ImageSection,\n    _Out_ SIZE_T *ImageSectionLength\n    )\n{\n    SIZE_T directorySectionLength = 0;\n    PIMAGE_SECTION_HEADER section;\n    PIMAGE_SECTION_HEADER sectionHeader;\n    PIMAGE_SECTION_HEADER directorySectionHeader = NULL;\n    ULONG imageSectionAddress;\n    SIZE_T imageSectionLength;\n    PVOID imageSectionMaximum;\n\n    section = IMAGE_FIRST_SECTION(ImageNtHeader);\n\n    for (USHORT i = 0; i < ImageNtHeader->FileHeader.NumberOfSections; i++)\n    {\n        sectionHeader = PTR_ADD_OFFSET(section, UInt32x32To64(IMAGE_SIZEOF_SECTION_HEADER, i));\n\n        imageSectionAddress = sectionHeader->VirtualAddress;\n        imageSectionLength = __max(sectionHeader->Misc.VirtualSize, sectionHeader->SizeOfRawData);\n        imageSectionMaximum = PTR_ADD_OFFSET(imageSectionAddress, imageSectionLength);\n\n        if (\n            ((ULONG_PTR)Rva >= (ULONG_PTR)imageSectionAddress) &&\n            ((ULONG_PTR)Rva < (ULONG_PTR)imageSectionMaximum)\n            )\n        {\n            directorySectionLength = imageSectionLength;\n            directorySectionHeader = sectionHeader;\n            break;\n        }\n    }\n\n    if (directorySectionHeader && directorySectionLength)\n    {\n        *ImageSection = directorySectionHeader;\n        *ImageSectionLength = directorySectionLength;\n        return STATUS_SUCCESS;\n    }\n\n    *ImageSection = NULL;\n    *ImageSectionLength = 0;\n    return STATUS_SECTION_NOT_IMAGE;\n}\n\n/**\n * Converts an RVA to a virtual address within a loaded image.\n *\n * \\param[in] BaseAddress The base address of the image.\n * \\param[in] Rva The relative virtual address to convert.\n * \\param[out] Va A pointer that receives the virtual address.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_SECTION_NOT_IMAGE The RVA is not within any section.\n * \\remarks This function finds the section containing the RVA and calculates the\n * virtual address by adding the base address and adjusting for section alignment.\n */\nNTSTATUS PhLoaderEntryImageRvaToVa(\n    _In_ PVOID BaseAddress,\n    _In_ ULONG Rva,\n    _Out_ PVOID *Va\n    )\n{\n    NTSTATUS status;\n    SIZE_T imageSectionSize;\n    PIMAGE_SECTION_HEADER imageSection;\n    PIMAGE_NT_HEADERS imageNtHeader;\n\n    status = PhGetLoaderEntryImageNtHeaders(\n        BaseAddress,\n        &imageNtHeader\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhLoaderEntryImageRvaToSection(\n        imageNtHeader,\n        Rva,\n        &imageSection,\n        &imageSectionSize\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *Va = PTR_ADD_OFFSET(BaseAddress, PTR_ADD_OFFSET(\n        PTR_SUB_OFFSET(Rva, imageSection->VirtualAddress),\n        imageSection->PointerToRawData\n        ));\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Determines whether an image has Control Flow Guard export suppression information.\n *\n * \\param[in] BaseAddress The base address of the image.\n * \\param[in] ImageNtHeader The NT headers of the image.\n * \\return TRUE if export suppression information is present; otherwise, FALSE.\n * \\remarks This function checks the IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT flag\n * in the load configuration directory. Export suppression is a CFG feature on Windows 10 RS2\n * and later that restricts which exported functions can be called.\n */\nBOOLEAN PhLoaderEntryImageExportSupressionPresent(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader\n    )\n{\n    PIMAGE_LOAD_CONFIG_DIRECTORY configDirectory;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n\n    if (NT_SUCCESS(PhGetLoaderEntryImageDirectory(\n        BaseAddress,\n        ImageNtHeader,\n        IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,\n        &dataDirectory,\n        &configDirectory,\n        NULL\n        )))\n    {\n        if (RTL_CONTAINS_FIELD(configDirectory, configDirectory->Size, GuardFlags))\n        {\n            if (BooleanFlagOn(configDirectory->GuardFlags, IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT))\n            {\n                return TRUE;\n            }\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Grants CFG-suppressed call access to an export address.\n *\n * \\param[in] ExportAddress The address of the suppressed export to grant access to.\n * \\remarks This function maintains a cache of export addresses that have been granted access\n * to avoid making redundant system calls. On Windows 10 RS2 and later with CFG export\n * suppression enabled, attempting to call a suppressed export will fail unless access is\n * explicitly granted via PhGuardGrantSuppressedCallAccess.\n */\nVOID PhLoaderEntryGrantSuppressedCall(\n    _In_ PVOID ExportAddress\n    )\n{\n    static PPH_HASHTABLE PhLoaderEntryCacheHashtable = NULL;\n\n    if (!PhLoaderEntryCacheHashtable)\n    {\n        PhLoaderEntryCacheHashtable = PhCreateSimpleHashtable(10);\n    }\n\n    if (PhLoaderEntryCacheHashtable && !PhFindItemSimpleHashtable(PhLoaderEntryCacheHashtable, ExportAddress))\n    {\n        if (NT_SUCCESS(PhGuardGrantSuppressedCallAccess(NtCurrentProcess(), ExportAddress)))\n        {\n            PhAddItemSimpleHashtable(PhLoaderEntryCacheHashtable, ExportAddress, UlongToPtr(TRUE));\n        }\n    }\n}\n\n/**\n * Performs a binary search to find the index of an exported function by name.\n *\n * \\param [in] BaseAddress The base address of the image.\n * \\param [in] ExportDirectory The export directory structure.\n * \\param [in] ExportNameTable The export name table (array of RVAs to name strings).\n * \\param [in] ExportName The name of the exported function to search for.\n *\n * \\return The index into the export name table, or ULONG_MAX if not found.\n *\n * \\remarks This function performs a binary search on the export name table, which is sorted\n * alphabetically by the Windows linker. This provides O(log n) lookup performance compared to\n * linear search. The returned index can be used with the export ordinal table to locate the\n * function address in the export address table.\n */\nstatic ULONG PhpLookupLoaderEntryImageExportFunctionIndex(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_EXPORT_DIRECTORY ExportDirectory,\n    _In_ PULONG ExportNameTable,\n    _In_ PCSTR ExportName\n    )\n{\n    LONG low;\n    LONG high;\n    LONG i;\n\n    if (ExportDirectory->NumberOfNames == 0)\n        return ULONG_MAX;\n\n    low = 0;\n    high = ExportDirectory->NumberOfNames - 1;\n\n    do\n    {\n        PSTR name;\n        INT comparison;\n\n        i = (low + high) / 2;\n        name = PTR_ADD_OFFSET(BaseAddress, ExportNameTable[i]);\n\n        if (!name)\n            return ULONG_MAX;\n\n        comparison = strcmp(ExportName, name);\n\n        if (comparison == 0)\n            return i;\n        else if (comparison < 0)\n            high = i - 1;\n        else\n            low = i + 1;\n    } while (low <= high);\n\n    return ULONG_MAX;\n}\n\n/**\n * Validates export table RVAs to prevent out-of-bounds memory access.\n *\n * \\param [in] ImageNtHeader The NT headers of the image.\n * \\param [in] ExportDirectory The export directory structure to validate.\n * \\return TRUE if all export table RVAs are valid and within image bounds, FALSE otherwise.\n */\nstatic BOOLEAN PhpValidateExportTableRvas(\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ PIMAGE_EXPORT_DIRECTORY ExportDirectory\n    )\n{\n    ULONG imageSize;\n    ULONG addressTableSize;\n    ULONG nameTableSize;\n    ULONG ordinalTableSize;\n    ULONG addressTableEnd;\n    ULONG nameTableEnd;\n    ULONG ordinalTableEnd;\n\n    imageSize = ImageNtHeader->OptionalHeader.SizeOfImage;\n\n    if (ExportDirectory->NumberOfFunctions > 0)\n    {\n        if (ExportDirectory->AddressOfFunctions == 0)\n            return FALSE;\n        if (!NT_SUCCESS(RtlULongMult(ExportDirectory->NumberOfFunctions, sizeof(ULONG), &addressTableSize)))\n            return FALSE;\n        if (!NT_SUCCESS(RtlULongAdd(ExportDirectory->AddressOfFunctions, addressTableSize, &addressTableEnd)))\n            return FALSE;\n        if (addressTableEnd > imageSize)\n            return FALSE;\n    }\n\n    if (ExportDirectory->NumberOfNames > 0)\n    {\n        if (ExportDirectory->AddressOfNames == 0)\n            return FALSE;\n        if (!NT_SUCCESS(RtlULongMult(ExportDirectory->NumberOfNames, sizeof(ULONG), &nameTableSize)))\n            return FALSE;\n        if (!NT_SUCCESS(RtlULongAdd(ExportDirectory->AddressOfNames, nameTableSize, &nameTableEnd)))\n            return FALSE;\n        if (nameTableEnd > imageSize)\n            return FALSE;\n    }\n\n    if (ExportDirectory->NumberOfNames > 0)\n    {\n        if (ExportDirectory->AddressOfNameOrdinals == 0)\n            return FALSE;\n        if (!NT_SUCCESS(RtlULongMult(ExportDirectory->NumberOfNames, sizeof(USHORT), &ordinalTableSize)))\n            return FALSE;\n        if (!NT_SUCCESS(RtlULongAdd(ExportDirectory->AddressOfNameOrdinals, ordinalTableSize, &ordinalTableEnd)))\n            return FALSE;\n        if (ordinalTableEnd > imageSize)\n            return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Retrieves the address of an exported function from an image's export directory.\n *\n * \\param [in] BaseAddress The base address of the image.\n * \\param [in] ImageNtHeader The NT headers of the image.\n * \\param [in] DataDirectory The data directory entry for the export table.\n * \\param [in] ExportDirectory The export directory.\n * \\param [in,opt] ExportName The name of the exported function. Specify NULL to use ExportOrdinal.\n * \\param [in,opt] ExportOrdinal The ordinal number of the exported function. Specify 0 to use ExportName.\n * \\return The address of the exported function, or NULL if the function could not be found or validation failed.\n * \\remarks This function validates export table bounds before accessing export data to prevent\n * malformed DLLs from causing out-of-bounds reads. It uses safe integer arithmetic to prevent\n * overflow attacks. The function also handles forwarded exports by recursively calling\n * PhGetDllBaseProcedureAddress to resolve the forwarding chain.\n */\nPVOID PhGetLoaderEntryImageExportFunction(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ PIMAGE_DATA_DIRECTORY DataDirectory,\n    _In_ PIMAGE_EXPORT_DIRECTORY ExportDirectory,\n    _In_opt_ PCSTR ExportName,\n    _In_opt_ USHORT ExportOrdinal\n    )\n{\n    PVOID exportAddress = NULL;\n    PULONG exportAddressTable;\n    PULONG exportNameTable;\n    PUSHORT exportOrdinalTable;\n\n    if (!PhpValidateExportTableRvas(ImageNtHeader, ExportDirectory))\n        return NULL;\n\n    exportAddressTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfFunctions);\n    exportNameTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNames);\n    exportOrdinalTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNameOrdinals);\n\n    if (ExportOrdinal)\n    {\n        ULONG maxOrdinal;\n\n        if (!NT_SUCCESS(RtlULongAdd(ExportDirectory->Base, ExportDirectory->NumberOfFunctions, &maxOrdinal)))\n            return NULL;\n\n        if (ExportOrdinal > maxOrdinal)\n            return NULL;\n\n        exportAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[ExportOrdinal - ExportDirectory->Base]);\n    }\n    else if (ExportName)\n    {\n        ULONG exportIndex;\n\n        exportIndex = PhpLookupLoaderEntryImageExportFunctionIndex(\n            BaseAddress,\n            ExportDirectory,\n            exportNameTable,\n            ExportName\n            );\n\n        if (exportIndex == ULONG_MAX)\n            return NULL;\n\n        exportAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[exportOrdinalTable[exportIndex]]);\n\n        //for (exportIndex = 0; exportIndex < ExportDirectory->NumberOfNames; exportIndex++)\n        //{\n        //    if (PhEqualBytesZ(ExportName, PTR_ADD_OFFSET(BaseAddress, exportNameTable[exportIndex]), FALSE))\n        //    {\n        //        exportAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[exportOrdinalTable[exportIndex]]);\n        //        break;\n        //    }\n        //}\n    }\n\n    if (!exportAddress)\n        return NULL;\n\n    if (\n        ((ULONG_PTR)exportAddress >= (ULONG_PTR)ExportDirectory) &&\n        ((ULONG_PTR)exportAddress < (ULONG_PTR)PTR_ADD_OFFSET(ExportDirectory, DataDirectory->Size))\n        )\n    {\n        SIZE_T dllForwarderLength;\n        PH_STRINGREF dllNameRef;\n        PH_STRINGREF dllForwarderRef;\n        PH_STRINGREF dllProcedureRef;\n        WCHAR dllForwarderName[DOS_MAX_PATH_LENGTH] = L\"\";\n\n        // This is a forwarder RVA.\n\n        dllForwarderLength = PhCountBytesZ((PCSTR)exportAddress);\n        PhZeroExtendToUtf16Buffer((PCSTR)exportAddress, dllForwarderLength, dllForwarderName);\n        dllForwarderRef.Length = dllForwarderLength * sizeof(WCHAR);\n        dllForwarderRef.Buffer = dllForwarderName;\n\n        if (PhSplitStringRefAtChar(&dllForwarderRef, L'.', &dllNameRef, &dllProcedureRef))\n        {\n            PVOID libraryDllBase;\n            WCHAR libraryName[DOS_MAX_PATH_LENGTH] = L\"\";\n\n            if (memcpy_s(libraryName, sizeof(libraryName), dllNameRef.Buffer, dllNameRef.Length))\n            {\n                return NULL;\n            }\n\n            libraryDllBase = PhLoadLibrary(libraryName);\n\n            if (libraryDllBase)\n            {\n                CHAR libraryFunctionName[DOS_MAX_PATH_LENGTH] = \"\";\n\n                if (!NT_SUCCESS(PhConvertUtf16ToUtf8Buffer(\n                    libraryFunctionName,\n                    sizeof(libraryFunctionName),\n                    NULL,\n                    dllProcedureRef.Buffer,\n                    dllProcedureRef.Length\n                    )))\n                {\n                    return NULL;\n                }\n\n                if (libraryFunctionName[0] == '#') // This is a forwarder RVA with an ordinal import.\n                {\n                    LONG64 importOrdinal;\n\n                    PhSkipStringRef(&dllProcedureRef, sizeof(L'#'));\n\n                    if (PhStringToInteger64(&dllProcedureRef, 10, &importOrdinal))\n                        exportAddress = PhGetDllBaseProcedureAddress(libraryDllBase, NULL, (USHORT)importOrdinal);\n                    else\n                        exportAddress = PhGetDllBaseProcedureAddress(libraryDllBase, libraryFunctionName, 0);\n                }\n                else\n                {\n                    exportAddress = PhGetDllBaseProcedureAddress(libraryDllBase, libraryFunctionName, 0);\n                }\n            }\n        }\n    }\n\n    return exportAddress;\n}\n\n/**\n * Retrieves the address of an exported function using a hint for optimization.\n *\n * \\param[in] BaseAddress The base address of the image.\n * \\param[in] ProcedureName The name of the exported procedure.\n * \\param[in] ProcedureHint A hint index into the export name table (typically from import descriptor).\n * \\return The address of the exported function, or NULL if not found.\n * \\remarks The hint is an optimization that allows the loader to check if the export at\n * the hint index matches the desired name before performing a binary search. If the hint\n * matches, the lookup is O(1). If not, the function falls back to PhGetDllBaseProcedureAddress().\n * This function also handles forwarded exports.\n */\nPVOID PhGetDllBaseProcedureAddressWithHint(\n    _In_ PVOID BaseAddress,\n    _In_ PCSTR ProcedureName,\n    _In_ USHORT ProcedureHint\n    )\n{\n    PIMAGE_NT_HEADERS imageNtHeader;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_EXPORT_DIRECTORY exportDirectory;\n\n    if (!NT_SUCCESS(PhGetLoaderEntryImageNtHeaders(BaseAddress, &imageNtHeader)))\n        return NULL;\n\n    if (!NT_SUCCESS(PhGetLoaderEntryImageDirectory(\n        BaseAddress,\n        imageNtHeader,\n        IMAGE_DIRECTORY_ENTRY_EXPORT,\n        &dataDirectory,\n        &exportDirectory,\n        NULL\n        )))\n    {\n        return NULL;\n    }\n\n    if (ProcedureHint < exportDirectory->NumberOfNames)\n    {\n        PULONG exportAddressTable = PTR_ADD_OFFSET(BaseAddress, exportDirectory->AddressOfFunctions);\n        PULONG exportNameTable = PTR_ADD_OFFSET(BaseAddress, exportDirectory->AddressOfNames);\n        PUSHORT exportOrdinalTable = PTR_ADD_OFFSET(BaseAddress, exportDirectory->AddressOfNameOrdinals);\n\n        // If the import hint matches the export name then return the address.\n        if (PhEqualBytesZ(ProcedureName, PTR_ADD_OFFSET(BaseAddress, exportNameTable[ProcedureHint]), FALSE))\n        {\n            PVOID exportAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[exportOrdinalTable[ProcedureHint]]);\n\n            if (\n                ((ULONG_PTR)exportAddress >= (ULONG_PTR)exportDirectory) &&\n                ((ULONG_PTR)exportAddress < (ULONG_PTR)PTR_ADD_OFFSET(exportDirectory, dataDirectory->Size))\n                )\n            {\n                SIZE_T dllForwarderLength;\n                PH_STRINGREF dllNameRef;\n                PH_STRINGREF dllForwarderRef;\n                PH_STRINGREF dllProcedureRef;\n                WCHAR dllForwarderName[DOS_MAX_PATH_LENGTH] = L\"\";\n\n                // This is a forwarder RVA.\n\n                dllForwarderLength = PhCountBytesZ((PCSTR)exportAddress);\n                PhZeroExtendToUtf16Buffer((PCSTR)exportAddress, dllForwarderLength, dllForwarderName);\n                dllForwarderRef.Length = dllForwarderLength * sizeof(WCHAR);\n                dllForwarderRef.Buffer = dllForwarderName;\n\n                if (PhSplitStringRefAtChar(&dllForwarderRef, L'.', &dllNameRef, &dllProcedureRef))\n                {\n                    PVOID libraryDllBase;\n                    WCHAR libraryName[DOS_MAX_PATH_LENGTH] = L\"\";\n\n                    if (memcpy_s(libraryName, sizeof(libraryName), dllNameRef.Buffer, dllNameRef.Length))\n                    {\n                        return NULL;\n                    }\n\n                    libraryDllBase = PhLoadLibrary(libraryName);\n\n                    if (libraryDllBase)\n                    {\n                        CHAR libraryFunctionName[DOS_MAX_PATH_LENGTH] = \"\";\n\n                        if (!NT_SUCCESS(PhConvertUtf16ToUtf8Buffer(\n                            libraryFunctionName,\n                            sizeof(libraryFunctionName),\n                            NULL,\n                            dllProcedureRef.Buffer,\n                            dllProcedureRef.Length\n                            )))\n                        {\n                            return NULL;\n                        }\n\n                        if (libraryFunctionName[0] == '#') // This is a forwarder RVA with an ordinal import.\n                        {\n                            LONG64 importOrdinal;\n\n                            PhSkipStringRef(&dllProcedureRef, sizeof(L'#'));\n\n                            if (PhStringToInteger64(&dllProcedureRef, 10, &importOrdinal))\n                                exportAddress = PhGetDllBaseProcedureAddress(libraryDllBase, NULL, (USHORT)importOrdinal);\n                            else\n                                exportAddress = PhGetDllBaseProcedureAddress(libraryDllBase, libraryFunctionName, 0);\n                        }\n                        else\n                        {\n                            exportAddress = PhGetDllBaseProcedureAddress(libraryDllBase, libraryFunctionName, 0);\n                        }\n                    }\n                }\n            }\n\n            return exportAddress;\n        }\n    }\n\n    return PhGetDllBaseProcedureAddress(BaseAddress, ProcedureName, 0);\n}\n\n/**\n * Detours (replaces) an imported function in a loaded module's Import Address Table (IAT).\n *\n * \\param[in] BaseAddress The base address of the module whose import to detour.\n * \\param[in] ImportName The name of the DLL that exports the function (e.g., \"ntdll.dll\").\n * \\param[in] ProcedureName The name of the imported function to detour (e.g., \"NtCreateFile\").\n * \\param[in] FunctionAddress The address of the replacement function.\n * \\param[out,opt] OriginalAddress An optional pointer that receives the original function address.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INVALID_PARAMETER BaseAddress, ImportName, or ProcedureName is NULL.\n * \\retval STATUS_UNSUCCESSFUL The import or procedure was not found.\n * \\remarks This function modifies the Import Address Table (IAT) to redirect calls to the\n * specified import to a new function address. The memory is temporarily made writable, the\n * thunk is updated, and protection is restored. On ARM64, the instruction cache is flushed.\n * This is commonly used for API hooking and function interception. The caller should save\n * the original address if they need to call the original function.\n */\nNTSTATUS PhLoaderEntryDetourImportProcedure(\n    _In_ PVOID BaseAddress,\n    _In_ PCSTR ImportName,\n    _In_ PCSTR ProcedureName,\n    _In_ PVOID FunctionAddress,\n    _Out_opt_ PVOID* OriginalAddress\n    )\n{\n    NTSTATUS status;\n    PIMAGE_NT_HEADERS imageNtHeaders;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_IMPORT_DESCRIPTOR importDirectory;\n\n    if (!BaseAddress || !ImportName || !ProcedureName)\n        return STATUS_INVALID_PARAMETER;\n\n    status = PhGetLoaderEntryImageNtHeaders(\n        BaseAddress,\n        &imageNtHeaders\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetLoaderEntryImageDirectory(\n        BaseAddress,\n        imageNtHeaders,\n        IMAGE_DIRECTORY_ENTRY_IMPORT,\n        &dataDirectory,\n        &importDirectory,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = STATUS_UNSUCCESSFUL;\n\n    while (importDirectory->Name && importDirectory->OriginalFirstThunk)\n    {\n        PCSTR importName;\n        PIMAGE_THUNK_DATA importThunk;\n        PIMAGE_THUNK_DATA originalThunk;\n        PIMAGE_IMPORT_BY_NAME importByName;\n\n        importName = PTR_ADD_OFFSET(BaseAddress, importDirectory->Name);\n        importThunk = PTR_ADD_OFFSET(BaseAddress, importDirectory->FirstThunk);\n        originalThunk = PTR_ADD_OFFSET(BaseAddress, importDirectory->OriginalFirstThunk);\n\n        if (PhEqualBytesZ(importName, ImportName, TRUE))\n        {\n            for (; originalThunk->u1.AddressOfData; originalThunk++, importThunk++) // while (originalThunk->u1.AddressOfData)\n            {\n                SIZE_T importThunkSize = sizeof(IMAGE_THUNK_DATA);\n                PVOID importThunkAddress = importThunk;\n                ULONG importThunkProtect = 0;\n\n                if (IMAGE_SNAP_BY_ORDINAL(originalThunk->u1.Ordinal))\n                    continue;\n\n                importByName = PTR_ADD_OFFSET(BaseAddress, originalThunk->u1.AddressOfData);\n\n                if (!PhEqualBytesZ(importByName->Name, ProcedureName, FALSE))\n                    continue;\n\n                if (OriginalAddress)\n                    *OriginalAddress = (PVOID)importThunk->u1.Function;\n\n                if (NT_SUCCESS(status = PhProtectVirtualMemory(\n                    NtCurrentProcess(),\n                    importThunkAddress,\n                    importThunkSize,\n                    PAGE_READWRITE,\n                    &importThunkProtect\n                    )))\n                {\n                    importThunk->u1.Function = (ULONG_PTR)FunctionAddress;\n\n                    PhProtectVirtualMemory(\n                        NtCurrentProcess(),\n                        importThunkAddress,\n                        importThunkSize,\n                        importThunkProtect,\n                        &importThunkProtect\n                        );\n#ifdef _M_ARM64\n                    NtFlushInstructionCache(\n                        NtCurrentProcess(),\n                        importThunkAddress,\n                        importThunkSize\n                        );\n#endif\n                }\n                break;\n            }\n        }\n\n        importDirectory++;\n    }\n\n    return status;\n}\n\n/**\n * Displays an error message when an import cannot be resolved during plugin loading.\n *\n * \\param [in] BaseAddress The base address of the image that failed to load.\n * \\param [in] ImportName The name of the DLL containing the unresolved import.\n * \\param [in] OriginalThunk The thunk data for the unresolved import.\n * \\remarks This function shows a user-friendly error dialog indicating which function\n * or ordinal could not be resolved from which module. This is typically called when\n * plugin loading fails due to missing dependencies.\n */\nVOID PhLoaderEntrySnapShowErrorMessage(\n    _In_ PVOID BaseAddress,\n    _In_ PCSTR ImportName,\n    _In_ PIMAGE_THUNK_DATA OriginalThunk\n    )\n{\n    PPH_STRING fileName;\n\n    if (!BaseAddress || !ImportName || !OriginalThunk)\n        return;\n\n    if (NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), BaseAddress, &fileName)))\n    {\n        PhMoveReference(&fileName, PhGetFileName(fileName));\n        PhMoveReference(&fileName, PhGetBaseName(fileName));\n\n        if (IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal))\n        {\n            PhShowError2(\n                NULL,\n                L\"Unable to load plugin.\",\n                L\"Name: %s\\r\\nOrdinal: %u\\r\\nModule: %hs\",\n                PhGetStringOrEmpty(fileName),\n                IMAGE_ORDINAL(OriginalThunk->u1.Ordinal),\n                ImportName\n                );\n        }\n        else\n        {\n            PIMAGE_IMPORT_BY_NAME importByName;\n\n            importByName = PTR_ADD_OFFSET(BaseAddress, OriginalThunk->u1.AddressOfData);\n\n            PhShowError2(\n                NULL,\n                L\"Unable to load plugin.\",\n                L\"Name: %s\\r\\nFunction: %hs\\r\\nModule: %hs\",\n                PhGetStringOrEmpty(fileName),\n                importByName->Name,\n                ImportName\n                );\n        }\n\n        PhDereferenceObject(fileName);\n    }\n}\n\n/**\n * Resolves a single import thunk by filling it with the actual function address.\n *\n * \\param [in] BaseAddress The base address of the importing image.\n * \\param [in] ImportBaseAddress The base address of the DLL containing the export.\n * \\param [in] OriginalThunk The original thunk data containing the import information.\n * \\param [in] ImportThunk The import thunk to be filled with the resolved address.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INVALID_PARAMETER One of the required parameters is NULL.\n * \\retval STATUS_ORDINAL_NOT_FOUND The import could not be resolved.\n *\n * \\remarks This function handles both ordinal and name-based imports. For ordinal imports,\n * it uses the ordinal number directly. For name-based imports, it uses the hint value\n * for optimization before falling back to a full lookup. This is the core function for\n * binding imports during dynamic loading.\n */\nNTSTATUS PhLoaderEntrySnapImportThunk(\n    _In_ PVOID BaseAddress,\n    _In_ PVOID ImportBaseAddress,\n    _In_ PIMAGE_THUNK_DATA OriginalThunk,\n    _In_ PIMAGE_THUNK_DATA ImportThunk\n    )\n{\n    if (!BaseAddress || !ImportBaseAddress || !OriginalThunk || !ImportThunk)\n        return STATUS_INVALID_PARAMETER;\n\n    if (IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal))\n    {\n        USHORT procedureOrdinal;\n        PVOID procedureAddress;\n\n        procedureOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);\n        procedureAddress = PhGetDllBaseProcedureAddress(ImportBaseAddress, NULL, procedureOrdinal);\n\n        if (procedureAddress)\n        {\n            ImportThunk->u1.Function = (ULONG_PTR)procedureAddress;\n            return STATUS_SUCCESS;\n        }\n    }\n    else\n    {\n        PIMAGE_IMPORT_BY_NAME importByName;\n        PVOID procedureAddress;\n\n        importByName = PTR_ADD_OFFSET(BaseAddress, OriginalThunk->u1.AddressOfData);\n        procedureAddress = PhGetDllBaseProcedureAddressWithHint(ImportBaseAddress, importByName->Name, importByName->Hint);\n\n        if (procedureAddress)\n        {\n            ImportThunk->u1.Function = (ULONG_PTR)procedureAddress;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return STATUS_ORDINAL_NOT_FOUND;\n}\n\n#if defined(PH_NATIVE_LOADER_WORKQUEUE)\ntypedef struct _PH_LOADER_IMPORT_THUNK_WORKQUEUE_CONTEXT\n{\n    PVOID BaseAddress;\n    PVOID ImportBaseAddress;\n    PIMAGE_THUNK_DATA OriginalThunkData;\n    PIMAGE_THUNK_DATA ImportThunkData;\n} PH_LOADER_IMPORT_THUNK_WORKQUEUE_CONTEXT, *PPH_LOADER_IMPORT_THUNK_WORKQUEUE_CONTEXT;\n\n/**\n * Thread pool callback function that resolves import thunks asynchronously.\n *\n * \\param Instance The callback instance.\n * \\param Context A pointer to the PH_LOADER_IMPORT_THUNK_WORKQUEUE_CONTEXT structure.\n * \\param Work The work item.\n * \\remarks This function is called by the thread pool to resolve imports in parallel when\n * PH_NATIVE_LOADER_WORKQUEUE is defined. It calls PhLoaderEntrySnapImportThunk() and raises\n * an exception on failure. The context is freed after processing.\n */\nVOID CALLBACK LoaderEntryImageImportThunkWorkQueueCallback(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context,\n    _Inout_ PTP_WORK Work\n    )\n{\n    PPH_LOADER_IMPORT_THUNK_WORKQUEUE_CONTEXT context = (PPH_LOADER_IMPORT_THUNK_WORKQUEUE_CONTEXT)Context;\n    NTSTATUS status;\n\n    status = PhLoaderEntrySnapImportThunk(\n        context->BaseAddress,\n        context->ImportBaseAddress,\n        context->OriginalThunkData,\n        context->ImportThunkData\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n#ifdef DEBUG\n        PhLoaderEntrySnapShowErrorMessage(context->BaseAddress, \"ThunkWorkQueue\", context->OriginalThunkData);\n#endif\n        PhRaiseStatus(status);\n    }\n\n    PhFree(context);\n}\n#endif\n\n/**\n * Resolves all imports from a specific DLL for a single import descriptor.\n *\n * \\param [in] BaseAddress The base address of the importing image.\n * \\param [in] ImportDirectory The import descriptor for the DLL.\n * \\param [in] ImportDllName The name of the DLL to resolve imports from.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INVALID_PARAMETER One of the required parameters is NULL.\n * \\remarks This function loads the specified DLL (if not already loaded), then iterates\n * through all import thunks for that DLL and resolves them to actual function addresses.\n * Special handling exists for self-imports (SystemInformer.exe importing from itself).\n * When PH_NATIVE_LOADER_WORKQUEUE is enabled, imports are resolved in parallel using a\n * thread pool for better performance.\n */\nNTSTATUS PhLoaderEntrySnapImportDirectory(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_IMPORT_DESCRIPTOR ImportDirectory,\n    _In_ PCSTR ImportDllName\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    PCSTR importName;\n    PIMAGE_THUNK_DATA importThunk;\n    PIMAGE_THUNK_DATA originalThunk;\n    PVOID importBaseAddress;\n\n    if (!BaseAddress || !ImportDirectory || !ImportDllName)\n        return STATUS_INVALID_PARAMETER;\n\n    importName = PTR_ADD_OFFSET(BaseAddress, ImportDirectory->Name);\n    importThunk = PTR_ADD_OFFSET(BaseAddress, ImportDirectory->FirstThunk);\n    originalThunk = PTR_ADD_OFFSET(BaseAddress, ImportDirectory->OriginalFirstThunk);\n\n    if (PhEqualBytesZ(importName, ImportDllName, FALSE))\n    {\n        importBaseAddress = NtCurrentImageBase();\n    }\n    else\n    {\n        WCHAR dllImportName[DOS_MAX_PATH_LENGTH] = L\"\";\n\n        PhZeroExtendToUtf16Buffer(importName, PhCountBytesZ(importName), dllImportName);\n\n        importBaseAddress = PhLoadLibrary(dllImportName);\n    }\n\n    if (!importBaseAddress)\n    {\n        return STATUS_DLL_NOT_FOUND;\n    }\n\n#if defined(PH_NATIVE_LOADER_WORKQUEUE)\n    PTP_POOL loaderThreadpool;\n    TP_CALLBACK_ENVIRON loaderThreadpoolEnvironment;\n    PTP_CLEANUP_GROUP loaderThreadpoolCleanupGroup;\n\n    status = TpAllocPool(&loaderThreadpool, NULL);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = TpAllocCleanupGroup(&loaderThreadpoolCleanupGroup);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = TpSetPoolMinThreads(loaderThreadpool, 1); // NtCurrentPeb()->ProcessParameters->LoaderThreads\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    TpSetPoolMaxThreads(loaderThreadpool, PhGetActiveProcessorCount(ALL_PROCESSOR_GROUPS));\n\n    TpInitializeCallbackEnviron(&loaderThreadpoolEnvironment);\n    TpSetCallbackThreadpool(&loaderThreadpoolEnvironment, loaderThreadpool);\n    TpSetCallbackCleanupGroup(&loaderThreadpoolEnvironment, loaderThreadpoolCleanupGroup, NULL);\n#endif\n\n    while (originalThunk->u1.AddressOfData)\n    {\n#if (PH_NATIVE_LOADER_WORKQUEUE)\n        PPH_LOADER_IMPORT_THUNK_WORKQUEUE_CONTEXT context;\n        PTP_WORK loaderThreadpoolWork;\n\n        context = PhAllocateZero(sizeof(PH_LOADER_IMPORT_THUNK_WORKQUEUE_CONTEXT));\n        context->BaseAddress = BaseAddress;\n        context->ImportBaseAddress = importBaseAddress;\n        context->OriginalThunkData = originalThunk;\n        context->ImportThunkData = importThunk;\n\n        status = TpAllocWork(\n            &loaderThreadpoolWork,\n            LoaderEntryImageImportThunkWorkQueueCallback,\n            context,\n            &loaderThreadpoolEnvironment\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        TpPostWork(loaderThreadpoolWork);\n#else\n        status = PhLoaderEntrySnapImportThunk(\n            BaseAddress,\n            importBaseAddress,\n            originalThunk,\n            importThunk\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n#ifdef DEBUG\n            PhLoaderEntrySnapShowErrorMessage(BaseAddress, importName, originalThunk);\n#endif\n            break;\n        }\n#endif\n        originalThunk++;\n        importThunk++;\n    }\n\n#if (PH_NATIVE_LOADER_WORKQUEUE)\nCleanupExit:\n    TpReleaseCleanupGroupMembers(loaderThreadpoolCleanupGroup, FALSE, NULL);\n    TpReleaseCleanupGroup(loaderThreadpoolCleanupGroup);\n    TpReleasePool(loaderThreadpool);\n#endif\n\n    return status;\n}\n\n#if (PH_NATIVE_LOADER_WORKQUEUE)\ntypedef struct _PH_LOADER_IMPORTS_WORKQUEUE_CONTEXT\n{\n    PVOID BaseAddress;\n    PIMAGE_IMPORT_DESCRIPTOR ImportDirectory;\n    PCSTR ImportName;\n} PH_LOADER_IMPORTS_WORKQUEUE_CONTEXT, *PPH_LOADER_IMPORTS_WORKQUEUE_CONTEXT;\n\n/**\n * Thread pool callback function that resolves import directories asynchronously.\n *\n * \\param [in,out] Instance The callback instance.\n * \\param [in,out,opt] Context A pointer to the PH_LOADER_IMPORTS_WORKQUEUE_CONTEXT structure.\n * \\param [in,out] Work The work item.\n * \\remarks This function is called by the thread pool to resolve import directories in parallel\n * when PH_NATIVE_LOADER_WORKQUEUE is defined. It calls PhLoaderEntrySnapImportDirectory() and\n * raises an exception on failure. The context is freed after processing.\n */\nVOID CALLBACK LoaderEntryImageImportsWorkQueueCallback(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context,\n    _Inout_ PTP_WORK Work\n    )\n{\n    PPH_LOADER_IMPORTS_WORKQUEUE_CONTEXT context = (PPH_LOADER_IMPORTS_WORKQUEUE_CONTEXT)Context;\n    NTSTATUS status;\n\n    status = PhLoaderEntrySnapImportDirectory(\n        context->BaseAddress,\n        context->ImportDirectory,\n        context->ImportName\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhRaiseStatus(status);\n    }\n\n    PhFree(context);\n}\n#endif\n\n/**\n * Resolves all standard imports for a loaded image from a specific DLL.\n *\n * \\param [in] BaseAddress The base address of the image.\n * \\param [in] ImageNtHeader The NT headers of the image.\n * \\param [in] ImportDllName The name of the DLL to resolve imports from.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function processes the import directory table, locating all import descriptors\n * and resolving their thunks. Memory protection is temporarily changed to PAGE_READWRITE to\n * allow updating the IAT, then restored. On ARM64, the instruction cache is flushed after\n * updates. When PH_NATIVE_LOADER_WORKQUEUE is enabled, import directories are processed\n * in parallel using a thread pool.\n */\nstatic NTSTATUS PhpFixupLoaderEntryImageImports(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeader,\n    _In_ PCSTR ImportDllName\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_IMPORT_DESCRIPTOR importDirectory;\n    PVOID importDirectorySectionAddress;\n    SIZE_T importDirectorySectionSize;\n    ULONG importDirectoryProtect;\n\n    status = PhGetLoaderEntryImageDirectory(\n        BaseAddress,\n        ImageNtHeader,\n        IMAGE_DIRECTORY_ENTRY_IMPORT,\n        &dataDirectory,\n        &importDirectory,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetLoaderEntryImageVaToSection(\n        BaseAddress,\n        ImageNtHeader,\n        importDirectory,\n        &importDirectorySectionAddress,\n        &importDirectorySectionSize\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhProtectVirtualMemory(\n        NtCurrentProcess(),\n        importDirectorySectionAddress,\n        importDirectorySectionSize,\n        PAGE_READWRITE,\n        &importDirectoryProtect\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n#if (PH_NATIVE_LOADER_WORKQUEUE)\n    PTP_POOL loaderThreadpool;\n    TP_CALLBACK_ENVIRON loaderThreadpoolEnvironment;\n    PTP_CLEANUP_GROUP loaderThreadpoolCleanupGroup;\n\n    status = TpAllocPool(&loaderThreadpool, NULL);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = TpAllocCleanupGroup(&loaderThreadpoolCleanupGroup);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = TpSetPoolMinThreads(loaderThreadpool, 8);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    TpSetPoolMaxThreads(loaderThreadpool, 8);\n\n    TpInitializeCallbackEnviron(&loaderThreadpoolEnvironment);\n    TpSetCallbackThreadpool(&loaderThreadpoolEnvironment, loaderThreadpool);\n    TpSetCallbackCleanupGroup(&loaderThreadpoolEnvironment, loaderThreadpoolCleanupGroup, NULL);\n#endif\n\n    while (importDirectory->Name && importDirectory->OriginalFirstThunk)\n    {\n#if (PH_NATIVE_LOADER_WORKQUEUE)\n        PPH_LOADER_IMPORTS_WORKQUEUE_CONTEXT context;\n        PTP_WORK loaderThreadpoolWork;\n\n        context = PhAllocateZero(sizeof(PH_LOADER_IMPORTS_WORKQUEUE_CONTEXT));\n        context->BaseAddress = BaseAddress;\n        context->ImportDirectory = importDirectory;\n        context->ImportName = ImportDllName;\n\n        status = TpAllocWork(\n            &loaderThreadpoolWork,\n            LoaderEntryImageImportsWorkQueueCallback,\n            context,\n            &loaderThreadpoolEnvironment\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        TpPostWork(loaderThreadpoolWork);\n#else\n        status = PhLoaderEntrySnapImportDirectory(\n            BaseAddress,\n            importDirectory,\n            ImportDllName\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n#endif\n        importDirectory++;\n    }\n\n#if (PH_NATIVE_LOADER_WORKQUEUE)\n    // Wait for all callbacks to finish.\n    TpReleaseCleanupGroupMembers(loaderThreadpoolCleanupGroup, FALSE, NULL);\n    // Clean up the pool.\n    TpReleaseCleanupGroup(loaderThreadpoolCleanupGroup);\n    TpReleasePool(loaderThreadpool);\n#endif\n\n    status = PhProtectVirtualMemory(\n        NtCurrentProcess(),\n        importDirectorySectionAddress,\n        importDirectorySectionSize,\n        importDirectoryProtect,\n        &importDirectoryProtect\n        );\n\nCleanupExit:\n\n#ifdef _M_ARM64\n    NtFlushInstructionCache(\n        NtCurrentProcess(),\n        importDirectorySectionAddress,\n        importDirectorySectionSize\n        );\n#endif\n\n    return status;\n}\n\n/**\n * Resolves all delay-load imports for a loaded image from a specific DLL.\n *\n * \\param [in] BaseAddress The base address of the image.\n * \\param [in] ImageNtHeaders The NT headers of the image.\n * \\param [in] ImportDllName The name of the DLL to resolve delay-load imports from.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_SUCCESS All delay-load imports were resolved or no delay-load imports exist.\n * \\remarks Delay-load imports are resolved on-demand rather than at load time. This function\n * processes the delay-load import directory, loading required DLLs and binding their imports.\n * Special handling exists for self-imports and cached module handles. If the import DLL is already\n * cached in the module handle, it is reused to avoid redundant loading.\n */\nstatic NTSTATUS PhpFixupLoaderEntryImageDelayImports(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_NT_HEADERS ImageNtHeaders,\n    _In_ PCSTR ImportDllName\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_DELAYLOAD_DESCRIPTOR delayImportDirectory;\n    PVOID importDirectorySectionAddress;\n    SIZE_T importDirectorySectionSize;\n    ULONG importDirectoryProtect;\n\n    status = PhGetLoaderEntryImageDirectory(\n        BaseAddress,\n        ImageNtHeaders,\n        IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,\n        &dataDirectory,\n        &delayImportDirectory,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        if (status == STATUS_INVALID_FILE_FOR_SECTION)\n            status = STATUS_SUCCESS;\n\n        return status;\n    }\n\n    status = PhGetLoaderEntryImageVaToSection(\n        BaseAddress,\n        ImageNtHeaders,\n        PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ImportAddressTableRVA),\n        &importDirectorySectionAddress,\n        &importDirectorySectionSize\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhProtectVirtualMemory(\n        NtCurrentProcess(),\n        importDirectorySectionAddress,\n        importDirectorySectionSize,\n        PAGE_READWRITE,\n        &importDirectoryProtect\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    while (delayImportDirectory->ImportAddressTableRVA && delayImportDirectory->ImportNameTableRVA)\n    {\n        PCSTR importName;\n        PVOID* importHandle;\n        PIMAGE_THUNK_DATA importAddressTable;\n        PIMAGE_THUNK_DATA importNameTable;\n        PVOID importBaseAddress;\n        BOOLEAN importNeedsFree = FALSE;\n\n        importName = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->DllNameRVA);\n        importHandle = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ModuleHandleRVA);\n        importAddressTable = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ImportAddressTableRVA);\n        importNameTable = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ImportNameTableRVA);\n\n        if (PhEqualBytesZ(importName, ImportDllName, TRUE))\n        {\n            if (PhEqualBytesZ(importName, \"SystemInformer.exe\", FALSE))\n            {\n                importBaseAddress = NtCurrentImageBase();\n                status = STATUS_SUCCESS;\n            }\n            else if (ReadPointerAcquire(importHandle))\n            {\n                importBaseAddress = ReadPointerAcquire(importHandle);\n                status = STATUS_SUCCESS;\n            }\n            else\n            {\n                WCHAR dllImportName[DOS_MAX_PATH_LENGTH] = L\"\";\n\n                PhZeroExtendToUtf16Buffer(importName, PhCountBytesZ(importName), dllImportName);\n\n                if (importBaseAddress = PhLoadLibrary(dllImportName))\n                {\n                    importNeedsFree = TRUE;\n                    status = STATUS_SUCCESS;\n                }\n                else\n                {\n                    status = PhGetLastWin32ErrorAsNtStatus();\n                }\n            }\n\n            if (!NT_SUCCESS(status))\n                break;\n\n            if (!importBaseAddress)\n            {\n                status = STATUS_UNSUCCESSFUL;\n                break;\n            }\n\n            while (importNameTable->u1.AddressOfData)\n            {\n                status = PhLoaderEntrySnapImportThunk(\n                    BaseAddress,\n                    importBaseAddress,\n                    importNameTable,\n                    importAddressTable\n                    );\n\n                if (!NT_SUCCESS(status))\n                    break;\n\n                importAddressTable++;\n                importNameTable++;\n            }\n\n            if ((InterlockedExchangePointer(importHandle, importBaseAddress) == importBaseAddress) && importNeedsFree)\n            {\n                PhFreeLibrary(importBaseAddress); // A different thread has already updated the cache.\n            }\n        }\n\n        delayImportDirectory++;\n    }\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhProtectVirtualMemory(\n        NtCurrentProcess(),\n        importDirectorySectionAddress,\n        importDirectorySectionSize,\n        importDirectoryProtect,\n        &importDirectoryProtect\n        );\n\nCleanupExit:\n\n#ifdef _M_ARM64\n    NtFlushInstructionCache(\n        NtCurrentProcess(),\n        importDirectorySectionAddress,\n        importDirectorySectionSize\n        );\n#endif\n\n    return status;\n}\n\n/**\n * Validates that a section handle represents a valid executable DLL image.\n *\n * \\param [in] SectionHandle A handle to the section to validate.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INVALID_IMPORT_OF_NON_DLL The section is not a valid DLL or executable.\n * \\retval STATUS_IMAGE_MACHINE_TYPE_MISMATCH The image architecture doesn't match the process.\n * \\remarks This function queries section information to verify it's a Windows GUI subsystem\n * image with DLL and executable characteristics. It also validates the machine type matches\n * the current process architecture (x64 for 64-bit processes, x86 for 32-bit processes).\n * ARM64 images are also accepted on 64-bit processes.\n */\nNTSTATUS PhLoaderEntryIsSectionImageExecutable(\n    _In_ HANDLE SectionHandle\n    )\n{\n    NTSTATUS status;\n    SECTION_IMAGE_INFORMATION sectionInfo;\n\n    status = NtQuerySection(\n        SectionHandle,\n        SectionImageInformation,\n        &sectionInfo,\n        sizeof(SECTION_IMAGE_INFORMATION),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (sectionInfo.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI)\n        return STATUS_INVALID_IMPORT_OF_NON_DLL;\n    if (!FlagOn(sectionInfo.ImageCharacteristics, IMAGE_FILE_DLL | IMAGE_FILE_EXECUTABLE_IMAGE))\n        return STATUS_INVALID_IMPORT_OF_NON_DLL;\n\n#ifdef _WIN64\n    if (sectionInfo.Machine != IMAGE_FILE_MACHINE_AMD64 && sectionInfo.Machine != IMAGE_FILE_MACHINE_ARM64)\n        return STATUS_IMAGE_MACHINE_TYPE_MISMATCH;\n#else\n    if (sectionInfo.Machine != IMAGE_FILE_MACHINE_I386)\n        return STATUS_IMAGE_MACHINE_TYPE_MISMATCH;\n#endif\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Applies base relocations to an image loaded at a different address than its preferred base.\n *\n * \\param [in] BaseAddress The base address where the image is loaded.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function is essential when loading DLLs at non-preferred base addresses due to\n * ASLR or address conflicts. It calculates the relocation delta (actual base - preferred base),\n * then iterates through all relocation blocks applying fixups to adjust pointers.\n */\nNTSTATUS PhLoaderEntryRelocateImage(\n    _In_ PVOID BaseAddress)\n{\n    NTSTATUS status;\n    PIMAGE_NT_HEADERS imageNtHeader;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_BASE_RELOCATION relocationDirectory;\n    PVOID relocationDirectoryEnd;\n    ULONG_PTR relocationDelta;\n\n    status = PhGetLoaderEntryImageNtHeaders(\n        BaseAddress,\n        &imageNtHeader\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetLoaderEntryImageDirectory(\n        BaseAddress,\n        imageNtHeader,\n        IMAGE_DIRECTORY_ENTRY_BASERELOC,\n        &dataDirectory,\n        &relocationDirectory,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (FlagOn(imageNtHeader->FileHeader.Characteristics, IMAGE_FILE_RELOCS_STRIPPED))\n        return STATUS_SUCCESS;\n\n    for (USHORT i = 0; i < imageNtHeader->FileHeader.NumberOfSections; i++)\n    {\n        PIMAGE_SECTION_HEADER sectionHeader;\n        PVOID sectionHeaderAddress;\n        SIZE_T sectionHeaderSize;\n        ULONG sectionProtectionJunk = 0;\n\n        sectionHeader = PTR_ADD_OFFSET(IMAGE_FIRST_SECTION(imageNtHeader), UInt32x32To64(IMAGE_SIZEOF_SECTION_HEADER, i));\n        sectionHeaderAddress = PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress);\n        sectionHeaderSize = sectionHeader->SizeOfRawData;\n\n        status = PhProtectVirtualMemory(\n            NtCurrentProcess(),\n            sectionHeaderAddress,\n            sectionHeaderSize,\n            PAGE_READWRITE,\n            &sectionProtectionJunk\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    relocationDirectoryEnd = PTR_ADD_OFFSET(relocationDirectory, dataDirectory->Size);\n    relocationDelta = (ULONG_PTR)PTR_SUB_OFFSET(BaseAddress, imageNtHeader->OptionalHeader.ImageBase);\n\n    while ((ULONG_PTR)relocationDirectory < (ULONG_PTR)relocationDirectoryEnd)\n    {\n        ULONG relocationCount;\n        PVOID relocationAddress;\n        PIMAGE_RELOCATION_RECORD relocations;\n\n        relocationCount = (relocationDirectory->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOCATION_RECORD);\n        relocationAddress = PTR_ADD_OFFSET(BaseAddress, relocationDirectory->VirtualAddress);\n        relocations = PTR_ADD_OFFSET(relocationDirectory, RTL_SIZEOF_THROUGH_FIELD(IMAGE_BASE_RELOCATION, SizeOfBlock));\n\n        for (ULONG i = 0; i < relocationCount; i++)\n        {\n            switch (relocations[i].Type)\n            {\n            case IMAGE_REL_BASED_LOW:\n                *(PUSHORT)PTR_ADD_OFFSET(relocationAddress, relocations[i].Offset) += (USHORT)relocationDelta;\n                break;\n            case IMAGE_REL_BASED_HIGHLOW:\n                *(PULONG)PTR_ADD_OFFSET(relocationAddress, relocations[i].Offset) += (ULONG)relocationDelta;\n                break;\n            case IMAGE_REL_BASED_DIR64:\n                *(PULONGLONG)PTR_ADD_OFFSET(relocationAddress, relocations[i].Offset) += (ULONGLONG)relocationDelta;\n                break;\n            }\n        }\n\n        relocationDirectory = PTR_ADD_OFFSET(relocationDirectory, relocationDirectory->SizeOfBlock);\n    }\n\n    for (USHORT i = 0; i < imageNtHeader->FileHeader.NumberOfSections; i++)\n    {\n        PIMAGE_SECTION_HEADER sectionHeader;\n        PVOID sectionHeaderAddress;\n        SIZE_T sectionHeaderSize;\n        ULONG sectionProtection = 0;\n        ULONG sectionProtectionJunk = 0;\n\n        sectionHeader = PTR_ADD_OFFSET(IMAGE_FIRST_SECTION(imageNtHeader), UInt32x32To64(IMAGE_SIZEOF_SECTION_HEADER, i));\n        sectionHeaderAddress = PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress);\n        sectionHeaderSize = sectionHeader->SizeOfRawData;\n\n        if (FlagOn(sectionHeader->Characteristics, IMAGE_SCN_MEM_READ))\n            sectionProtection = PAGE_READONLY;\n        if (FlagOn(sectionHeader->Characteristics, IMAGE_SCN_MEM_WRITE))\n            sectionProtection = PAGE_WRITECOPY;\n        if (FlagOn(sectionHeader->Characteristics, IMAGE_SCN_MEM_EXECUTE))\n            sectionProtection = PAGE_EXECUTE;\n        if (FlagOn(sectionHeader->Characteristics, IMAGE_SCN_MEM_READ) && FlagOn(sectionHeader->Characteristics, IMAGE_SCN_MEM_EXECUTE))\n            sectionProtection = PAGE_EXECUTE_READ;\n        if (FlagOn(sectionHeader->Characteristics, IMAGE_SCN_MEM_WRITE) && FlagOn(sectionHeader->Characteristics, IMAGE_SCN_MEM_EXECUTE))\n            sectionProtection = PAGE_EXECUTE_READWRITE;\n\n        status = PhProtectVirtualMemory(\n            NtCurrentProcess(),\n            sectionHeaderAddress,\n            sectionHeaderSize,\n            sectionProtection,\n            &sectionProtectionJunk\n            );\n\n#ifdef _M_ARM64\n        NtFlushInstructionCache(\n            NtCurrentProcess(),\n            sectionHeaderAddress,\n            sectionHeaderSize\n            );\n#endif\n        if (!NT_SUCCESS(status))\n            break;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the export name for a given ordinal from a DLL.\n *\n * \\param [in] DllBase The base address of the DLL.\n * \\param [in,opt] ProcedureNumber The ordinal number of the exported function.\n * \\return A string containing the export name, or NULL if not found.\n * \\remarks This function searches the export name table for an entry matching the specified\n * ordinal. If found and not a forwarder, it returns the function name. If the export is a\n * forwarder (RVA within the export directory), it returns the forwarder string. The returned\n * string must be freed by the caller using PhDereferenceObject().\n */\nPPH_STRING PhGetExportNameFromOrdinal(\n    _In_ PVOID DllBase,\n    _In_opt_ USHORT ProcedureNumber\n    )\n{\n    PIMAGE_NT_HEADERS imageNtHeader;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_EXPORT_DIRECTORY exportDirectory;\n    PULONG exportAddressTable;\n    PULONG exportNameTable;\n    PUSHORT exportOrdinalTable;\n    ULONG i;\n\n    if (!NT_SUCCESS(PhGetLoaderEntryImageNtHeaders(DllBase, &imageNtHeader)))\n        return NULL;\n\n    if (!NT_SUCCESS(PhGetLoaderEntryImageDirectory(\n        DllBase,\n        imageNtHeader,\n        IMAGE_DIRECTORY_ENTRY_EXPORT,\n        &dataDirectory,\n        &exportDirectory,\n        NULL\n        )))\n        return NULL;\n\n    exportAddressTable = PTR_ADD_OFFSET(DllBase, exportDirectory->AddressOfFunctions);\n    exportNameTable = PTR_ADD_OFFSET(DllBase, exportDirectory->AddressOfNames);\n    exportOrdinalTable = PTR_ADD_OFFSET(DllBase, exportDirectory->AddressOfNameOrdinals);\n\n    for (i = 0; i < exportDirectory->NumberOfNames; i++)\n    {\n        if ((exportOrdinalTable[i] + exportDirectory->Base) == ProcedureNumber)\n        {\n            PVOID baseAddress = PTR_ADD_OFFSET(DllBase, exportAddressTable[exportOrdinalTable[i]]);\n\n            if (\n                ((ULONG_PTR)baseAddress >= (ULONG_PTR)exportDirectory) &&\n                ((ULONG_PTR)baseAddress < (ULONG_PTR)PTR_ADD_OFFSET(exportDirectory, dataDirectory->Size))\n                )\n            {\n                // This is a forwarder RVA.\n                return PhZeroExtendToUtf16((PCSTR)baseAddress);\n            }\n            else\n            {\n                return PhZeroExtendToUtf16(PTR_ADD_OFFSET(DllBase, exportNameTable[i]));\n            }\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Loads a DLL from a file into the current process using native loader functionality.\n *\n * \\param [in] FileName The path to the DLL file as a string reference.\n * \\param [in,opt] RootDirectory An optional handle to a root directory for relative paths.\n * \\param [out] BaseAddress A pointer that receives the base address of the loaded DLL.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This is only built to support plugins.\n */\nNTSTATUS PhLoaderEntryLoadDll(\n    _In_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE RootDirectory,\n    _Out_ PVOID* BaseAddress\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    HANDLE sectionHandle;\n    PVOID imageBaseAddress;\n    SIZE_T imageBaseSize;\n\n    status = PhCreateFileEx(\n        &fileHandle,\n        FileName,\n        FILE_READ_DATA | FILE_EXECUTE | SYNCHRONIZE,\n        RootDirectory,\n        NULL,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhCreateSection(\n        &sectionHandle,\n        SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_EXECUTE,\n        NULL,\n        PAGE_EXECUTE,\n        SEC_IMAGE,\n        fileHandle\n        );\n\n    NtClose(fileHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhLoaderEntryIsSectionImageExecutable(\n        sectionHandle\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        NtClose(sectionHandle);\n        return status;\n    }\n\n    imageBaseAddress = NULL;\n    imageBaseSize = 0;\n\n    status = PhMapViewOfSection(\n        sectionHandle,\n        NtCurrentProcess(),\n        &imageBaseAddress,\n        0,\n        NULL,\n        &imageBaseSize,\n        ViewUnmap,\n        0,\n        PAGE_EXECUTE\n        );\n\n    NtClose(sectionHandle);\n\n    if (status == STATUS_IMAGE_NOT_AT_BASE)\n    {\n        status = PhLoaderEntryRelocateImage(imageBaseAddress);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (BaseAddress)\n        {\n            *BaseAddress = imageBaseAddress;\n        }\n    }\n    else\n    {\n        PhUnmapViewOfSection(NtCurrentProcess(), imageBaseAddress);\n    }\n\n    return status;\n}\n\n/**\n * Unloads a manually-loaded DLL from the current process.\n *\n * \\param [in] BaseAddress The base address of the DLL to unload.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function calls the DLL's entry point with DLL_PROCESS_DETACH to allow it to\n * perform cleanup operations, then unmaps the image from the process address space. If the\n * DLL entry point returns FALSE during detachment, STATUS_DLL_INIT_FAILED is returned.\n * This is the cleanup counterpart to PhLoaderEntryLoadDll().\n */\nNTSTATUS PhLoaderEntryUnloadDll(\n    _In_ PVOID BaseAddress\n    )\n{\n    NTSTATUS status;\n    PIMAGE_NT_HEADERS imageNtHeaders;\n    PDLL_INIT_ROUTINE imageEntryRoutine;\n\n    status = PhGetLoaderEntryImageNtHeaders(\n        BaseAddress,\n        &imageNtHeaders\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetLoaderEntryImageEntryPoint(\n        BaseAddress,\n        imageNtHeaders,\n        &imageEntryRoutine\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!imageEntryRoutine(BaseAddress, DLL_PROCESS_DETACH, NULL))\n        status = STATUS_DLL_INIT_FAILED;\n\n    PhUnmapViewOfSection(NtCurrentProcess(), BaseAddress);\n\n    return status;\n}\n\n/**\n * Resolves all delay-load imports for a specific DLL within a loaded image.\n *\n * \\param [in] BaseAddress The base address of the image to process.\n * \\param [in] ImportDllName The name of the DLL whose imports should be resolved (e.g., \"SystemInformer.exe\").\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function resolves delay-load imports from the specified DLL by calling\n * PhpFixupLoaderEntryImageDelayImports(). Delay-load imports are not resolved at load time\n * but are instead resolved on first use. This function allows preemptive resolution, which\n * is useful for plugins that need to ensure all imports from the host application are\n * available before proceeding.\n */\nNTSTATUS PhLoaderEntryLoadAllImportsForDll(\n    _In_ PVOID BaseAddress,\n    _In_ PCSTR ImportDllName\n    )\n{\n    NTSTATUS status;\n    PIMAGE_NT_HEADERS imageNtHeaders;\n\n    status = PhGetLoaderEntryImageNtHeaders(\n        BaseAddress,\n        &imageNtHeaders\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhpFixupLoaderEntryImageDelayImports(\n        BaseAddress,\n        imageNtHeaders,\n        ImportDllName\n        );\n\n    return status;\n}\n\n/**\n * Resolves all delay-load imports for a specific DLL within a loaded image identified by name.\n *\n * \\param [in] TargetDllName The name of the target DLL whose imports should be resolved.\n * \\param [in] ImportDllName The name of the DLL to import from (e.g., \"SystemInformer.exe\").\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INVALID_PARAMETER The target DLL was not found in the process.\n * \\remarks This is a convenience wrapper around PhLoaderEntryLoadAllImportsForDll() that\n * looks up the DLL by name in the loader data structures. It's useful when you know the\n * DLL name but not its base address.\n */\nNTSTATUS PhLoadAllImportsForDll(\n    _In_ PCWSTR TargetDllName,\n    _In_ PCSTR ImportDllName\n    )\n{\n    PVOID imageBaseAddress;\n\n    if (!(imageBaseAddress = PhGetLoaderEntryDllBaseZ(TargetDllName)))\n        return STATUS_INVALID_PARAMETER;\n\n    return PhLoaderEntryLoadAllImportsForDll(\n        imageBaseAddress,\n        ImportDllName\n        );\n}\n\n/**\n * Loads a System Informer plugin image with full initialization.\n *\n * \\param FileName The path to the plugin DLL as a string reference.\n * \\param RootDirectory An optional handle to a root directory for relative paths.\n * \\param BaseAddress An optional pointer that receives the base address of the loaded plugin.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_DLL_INIT_FAILED The plugin's DllMain returned FALSE during initialization.\n * \\remarks This function performs a complete plugin load sequence:\n * 1. Loads the plugin using PhLoaderEntryLoadDll() or LdrLoadDll() (if PH_NATIVE_PLUGIN_IMAGE_LOAD is defined)\n * 2. Resolves standard imports from SystemInformer.exe (this is required since the executable might be renamed)\n * 3. Resolves delay-load imports from SystemInformer.exe (this is required since the executable might be renamed)\n * 4. Calls the plugin's DllMain with DLL_PROCESS_ATTACH (optionally including an extra internal context)\n * The loader lock is held during the operation unless PH_NATIVE_PLUGIN_IMAGE_LOAD is defined.\n * On failure, the plugin is unloaded before returning.\n */\nNTSTATUS PhLoadPluginImage(\n    _In_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE RootDirectory,\n    _Out_opt_ PVOID *BaseAddress\n    )\n{\n    NTSTATUS status;\n    PVOID imageBaseAddress;\n    PIMAGE_NT_HEADERS imageNtHeaders;\n    PDLL_INIT_ROUTINE imageEntryRoutine;\n\n#if defined(PH_NATIVE_PLUGIN_IMAGE_LOAD)\n    UNICODE_STRING imageFileName;\n    ULONG imageType;\n\n    if (!PhStringRefToUnicodeString(FileName, &imageFileName))\n        return STATUS_NAME_TOO_LONG;\n\n    imageType = IMAGE_FILE_EXECUTABLE_IMAGE;\n\n    status = LdrLoadDll(\n        NULL,\n        &imageType,\n        &imageFileName,\n        &imageBaseAddress\n        );\n#else\n    PhAcquireLoaderLock();\n\n    status = PhLoaderEntryLoadDll(\n        FileName,\n        RootDirectory,\n        &imageBaseAddress\n        );\n#endif\n\n    if (!NT_SUCCESS(status))\n    {\n#if !defined(PH_NATIVE_PLUGIN_IMAGE_LOAD)\n        PhReleaseLoaderLock();\n#endif\n        return status;\n    }\n\n    status = PhGetLoaderEntryImageNtHeaders(\n        imageBaseAddress,\n        &imageNtHeaders\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhpFixupLoaderEntryImageImports(\n        imageBaseAddress,\n        imageNtHeaders,\n        \"SystemInformer.exe\"\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    //status = PhLoaderEntryLoadAllImportsForDll(imageBaseAddress, \"SystemInformer.exe\");\n    status = PhpFixupLoaderEntryImageDelayImports(\n        imageBaseAddress,\n        imageNtHeaders,\n        \"SystemInformer.exe\"\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetLoaderEntryImageEntryPoint(\n        imageBaseAddress,\n        imageNtHeaders,\n        &imageEntryRoutine\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (!imageEntryRoutine(imageBaseAddress, DLL_PROCESS_ATTACH, NULL))\n        status = STATUS_DLL_INIT_FAILED;\n\nCleanupExit:\n\n    if (NT_SUCCESS(status))\n    {\n        if (BaseAddress)\n        {\n            *BaseAddress = imageBaseAddress;\n        }\n    }\n    else\n    {\n#if defined(PH_NATIVE_PLUGIN_IMAGE_LOAD)\n        LdrUnloadDll(imageBaseAddress);\n#else\n        PhLoaderEntryUnloadDll(imageBaseAddress);\n#endif\n    }\n\n#if !defined(PH_NATIVE_PLUGIN_IMAGE_LOAD)\n    PhReleaseLoaderLock();\n#endif\n\n    return status;\n}\n\n/**\n * Determines the binary type of an executable file (32-bit, 64-bit, or DOS).\n *\n * \\param FileName The path to the executable file.\n * \\param BinaryType A pointer that receives the binary type constant (SCS_32BIT_BINARY, SCS_64BIT_BINARY, or SCS_DOS_BINARY).\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function mimics the behavior of GetBinaryTypeW by creating a SEC_IMAGE section\n * and querying its machine type. It returns:\n * - SCS_32BIT_BINARY for x86 images or STATUS_INVALID_IMAGE_WIN_32\n * - SCS_64BIT_BINARY for x64/IA64 images or STATUS_INVALID_IMAGE_WIN_64\n * - SCS_DOS_BINARY for DOS executables (STATUS_INVALID_IMAGE_PROTECT) or .COM/.PIF/.EXE files without valid PE headers\n * This is useful for determining compatibility before attempting to load an image.\n */\n// based on GetBinaryTypeW (dmex)\nNTSTATUS PhGetFileBinaryTypeWin32(\n    _In_ PCWSTR FileName,\n    _Out_ PULONG BinaryType\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    HANDLE sectionHandle;\n    UNICODE_STRING fileName;\n    IO_STATUS_BLOCK ioStatusBlock;\n    OBJECT_ATTRIBUTES objectAttributes;\n    SECTION_IMAGE_INFORMATION section;\n\n    RtlZeroMemory(&section, sizeof(SECTION_IMAGE_INFORMATION));\n\n    status = PhDosLongPathNameToNtPathNameWithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &fileHandle,\n        FILE_READ_DATA | FILE_EXECUTE | SYNCHRONIZE,\n        &objectAttributes,\n        &ioStatusBlock,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreateSection(\n        &sectionHandle,\n        SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_EXECUTE,\n        NULL,\n        PAGE_EXECUTE,\n        SEC_IMAGE,\n        fileHandle\n        );\n\n    NtClose(fileHandle);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtQuerySection(\n        sectionHandle,\n        SectionImageInformation,\n        &section,\n        sizeof(SECTION_IMAGE_INFORMATION),\n        NULL\n        );\n\n    NtClose(sectionHandle);\n\nCleanupExit:\n    RtlFreeUnicodeString(&fileName);\n\n    if (NT_SUCCESS(status))\n    {\n        switch (section.Machine)\n        {\n        case IMAGE_FILE_MACHINE_I386:\n            {\n                *BinaryType = SCS_32BIT_BINARY;\n            }\n            return STATUS_SUCCESS;\n        case IMAGE_FILE_MACHINE_IA64:\n        case IMAGE_FILE_MACHINE_AMD64:\n            {\n                *BinaryType = SCS_64BIT_BINARY;\n            }\n            return STATUS_SUCCESS;\n        }\n\n        return STATUS_UNSUCCESSFUL;\n    }\n    else\n    {\n        switch (status)\n        {\n        case STATUS_INVALID_IMAGE_PROTECT:\n            {\n                *BinaryType = SCS_DOS_BINARY;\n            }\n            return STATUS_SUCCESS;\n        case STATUS_INVALID_IMAGE_NOT_MZ:\n            {\n                static PH_STRINGREF extensionCOM = PH_STRINGREF_INIT(L\".COM\");\n                static PH_STRINGREF extensionPIF = PH_STRINGREF_INIT(L\".PIF\");\n                static PH_STRINGREF extensionEXE = PH_STRINGREF_INIT(L\".EXE\");\n                PH_STRINGREF fileNameSr;\n\n                PhInitializeStringRefLongHint(&fileNameSr, FileName);\n\n                if (\n                    PhEndsWithStringRef(&fileNameSr, &extensionCOM, TRUE) ||\n                    PhEndsWithStringRef(&fileNameSr, &extensionPIF, TRUE) ||\n                    PhEndsWithStringRef(&fileNameSr, &extensionEXE, TRUE)\n                    )\n                {\n                    *BinaryType = SCS_DOS_BINARY;\n                    return STATUS_SUCCESS;\n                }\n            }\n            break;\n        case STATUS_INVALID_IMAGE_WIN_32:\n            {\n                *BinaryType = SCS_32BIT_BINARY;\n            }\n            return STATUS_SUCCESS;\n        case STATUS_INVALID_IMAGE_WIN_64:\n            {\n                *BinaryType = SCS_64BIT_BINARY;\n            }\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Converts a system DLL init block from the current OS version layout to the latest layout.\n *\n * \\param[in] Source A buffer returned or copied from LdrSystemDllInitBlock.\n * \\param[out] Destination A buffer for storing a version-independent copy of the structure.\n */\nNTSTATUS PhCaptureSystemDllInitBlock(\n    _In_ PVOID Source,\n    _Out_ PPS_SYSTEM_DLL_INIT_BLOCK Destination\n    )\n{\n    ULONG sourceSize;\n\n    RtlZeroMemory(Destination, sizeof(PS_SYSTEM_DLL_INIT_BLOCK));\n\n    if (WindowsVersion >= WINDOWS_10_20H1)\n    {\n        PPS_SYSTEM_DLL_INIT_BLOCK_V3 source = (PPS_SYSTEM_DLL_INIT_BLOCK_V3)Source;\n\n        sourceSize = source->Size;\n\n        if (sourceSize > sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V3))\n            sourceSize = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V3);\n\n        // No adjustments necessary for the latest layout\n        RtlCopyMemory(Destination, source, sourceSize);\n        Destination->Size = sourceSize;\n\n        return STATUS_SUCCESS;\n    }\n    else if (WindowsVersion >= WINDOWS_10_RS2)\n    {\n        PPS_SYSTEM_DLL_INIT_BLOCK_V2 source = (PPS_SYSTEM_DLL_INIT_BLOCK_V2)Source;\n\n        sourceSize = source->Size;\n\n        if (sourceSize > sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V2))\n            sourceSize = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V2);\n\n        // Everything up to and including Flags uses the same layout\n        if (RTL_CONTAINS_FIELD(source, sourceSize, Flags))\n        {\n            RtlCopyMemory(\n                Destination,\n                source,\n                RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK_V2, Flags)\n                );\n\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, Flags);\n        }\n\n        // Mitigation options include 2 out of 3 values\n        if (RTL_CONTAINS_FIELD(source, sourceSize, MitigationOptionsMap))\n        {\n            Destination->MitigationOptionsMap.Map[0] = source->MitigationOptionsMap.Map[0];\n            Destination->MitigationOptionsMap.Map[1] = source->MitigationOptionsMap.Map[1];\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, MitigationOptionsMap.Map[1]);\n        }\n\n        // The subsequent fields are shifted\n        if (RTL_CONTAINS_FIELD(source, sourceSize, CfgBitMap))\n        {\n            Destination->CfgBitMap = source->CfgBitMap;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, CfgBitMap);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, CfgBitMapSize))\n        {\n            Destination->CfgBitMapSize = source->CfgBitMapSize;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, CfgBitMapSize);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, Wow64CfgBitMap))\n        {\n            Destination->Wow64CfgBitMap = source->Wow64CfgBitMap;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, Wow64CfgBitMap);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, Wow64CfgBitMapSize))\n        {\n            Destination->Wow64CfgBitMapSize = source->Wow64CfgBitMapSize;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, Wow64CfgBitMapSize);\n        }\n\n        // Mitigation audit options include 2 out of 3 values\n        if (RTL_CONTAINS_FIELD(source, sourceSize, MitigationAuditOptionsMap))\n        {\n            Destination->MitigationAuditOptionsMap.Map[0] = source->MitigationAuditOptionsMap.Map[0];\n            Destination->MitigationAuditOptionsMap.Map[1] = source->MitigationAuditOptionsMap.Map[1];\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, MitigationAuditOptionsMap.Map[1]);\n        }\n\n        return STATUS_SUCCESS;\n    }\n    else if (WindowsVersion >= PHNT_WINDOWS_8)\n    {\n        PPS_SYSTEM_DLL_INIT_BLOCK_V1 source = (PPS_SYSTEM_DLL_INIT_BLOCK_V1)Source;\n\n        sourceSize = source->Size;\n\n        if (sourceSize > sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V1))\n            sourceSize = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V1);\n\n        // All fields are shifted\n        if (RTL_CONTAINS_FIELD(source, sourceSize, SystemDllWowRelocation))\n        {\n            Destination->SystemDllWowRelocation = source->SystemDllWowRelocation;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, SystemDllWowRelocation);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, SystemDllNativeRelocation))\n        {\n            Destination->SystemDllNativeRelocation = source->SystemDllNativeRelocation;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, SystemDllNativeRelocation);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, Wow64SharedInformation))\n        {\n            RtlCopyMemory(\n                &Destination->Wow64SharedInformation,\n                &source->Wow64SharedInformation,\n                RTL_FIELD_SIZE(PS_SYSTEM_DLL_INIT_BLOCK_V1, Wow64SharedInformation)\n                );\n\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, Wow64SharedInformation);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, RngData))\n        {\n            Destination->RngData = source->RngData;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, RngData);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, Flags))\n        {\n            Destination->Flags = source->Flags;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, Flags);\n        }\n\n        // Mitigation options include 1 out of 3 values\n        if (RTL_CONTAINS_FIELD(source, sourceSize, MitigationOptions))\n        {\n            Destination->MitigationOptionsMap.Map[0] = source->MitigationOptions;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, MitigationOptionsMap.Map[0]);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, CfgBitMap))\n        {\n            Destination->CfgBitMap = source->CfgBitMap;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, CfgBitMap);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, CfgBitMapSize))\n        {\n            Destination->CfgBitMapSize = source->CfgBitMapSize;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, CfgBitMapSize);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, Wow64CfgBitMap))\n        {\n            Destination->Wow64CfgBitMap = source->Wow64CfgBitMap;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, Wow64CfgBitMap);\n        }\n\n        if (RTL_CONTAINS_FIELD(source, sourceSize, Wow64CfgBitMapSize))\n        {\n            Destination->Wow64CfgBitMapSize = source->Wow64CfgBitMapSize;\n            Destination->Size = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK, Wow64CfgBitMapSize);\n        }\n\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_NOT_SUPPORTED;\n}\n\n/**\n * Retrieves a copy of the system DLL init block of the current process.\n *\n * \\param[out] SystemDllInitBlock A buffer for storing a version-independent copy of LdrSystemDllInitBlock.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSystemDllInitBlock(\n    _Out_ PPS_SYSTEM_DLL_INIT_BLOCK SystemDllInitBlock\n    )\n{\n    PVOID systemDllInitBlock;\n\n    if (!LdrSystemDllInitBlock_Import())\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    systemDllInitBlock = LdrSystemDllInitBlock_Import();\n\n    if (!systemDllInitBlock)\n        return STATUS_NOT_SUPPORTED;\n\n    return PhCaptureSystemDllInitBlock(systemDllInitBlock, SystemDllInitBlock);\n}\n"
  },
  {
    "path": "phlib/maplib.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2019\n *\n */\n\n/*\n * This file contains functions to load and retrieve information for library/archive files (lib).\n * The file format for archive files is explained in the PE/COFF specification located at:\n *\n * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx\n */\n\n#include <ph.h>\n#include <mapimg.h>\n\nVOID PhpMappedArchiveProbe(\n    _In_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    );\n\nNTSTATUS PhpGetMappedArchiveMemberFromHeader(\n    _In_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header,\n    _Out_ PPH_MAPPED_ARCHIVE_MEMBER Member\n    );\n\nNTSTATUS PhInitializeMappedArchive(\n    _Out_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    )\n{\n    NTSTATUS status;\n    PVOID start;\n\n    start = ViewBase;\n\n    memset(MappedArchive, 0, sizeof(PH_MAPPED_ARCHIVE));\n    MappedArchive->ViewBase = ViewBase;\n    MappedArchive->Size = Size;\n\n    __try\n    {\n        // Verify the file signature.\n\n        PhpMappedArchiveProbe(MappedArchive, start, IMAGE_ARCHIVE_START_SIZE);\n\n        if (memcmp(start, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE) != 0)\n            PhRaiseStatus(STATUS_INVALID_IMAGE_FORMAT);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // Get the members.\n    // Note: the names are checked.\n\n    // First linker member\n\n    status = PhpGetMappedArchiveMemberFromHeader(\n        MappedArchive,\n        PTR_ADD_OFFSET(start, IMAGE_ARCHIVE_START_SIZE),\n        &MappedArchive->FirstLinkerMember\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (MappedArchive->FirstLinkerMember.Type != LinkerArchiveMemberType)\n        return STATUS_INVALID_PARAMETER;\n\n    MappedArchive->FirstStandardMember = &MappedArchive->FirstLinkerMember;\n\n    // Second linker member\n\n    status = PhGetNextMappedArchiveMember(\n        &MappedArchive->FirstLinkerMember,\n        &MappedArchive->SecondLinkerMember\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (\n        MappedArchive->SecondLinkerMember.Type != LinkerArchiveMemberType &&\n        MappedArchive->SecondLinkerMember.Type != NormalArchiveMemberType // NormalArchiveMemberType might not be correct here but set by LLVM compiled libs (dmex)\n        )\n        return STATUS_INVALID_PARAMETER;\n\n    // Longnames member\n    // This member doesn't seem to be mandatory, contrary to the specification.\n    // So we'll check if it's actually a longnames member, and if not, ignore it.\n\n    status = PhGetNextMappedArchiveMember(\n        &MappedArchive->SecondLinkerMember,\n        &MappedArchive->LongnamesMember\n        );\n\n    if (\n        NT_SUCCESS(status) &&\n        MappedArchive->LongnamesMember.Type == LongnamesArchiveMemberType\n        )\n    {\n        MappedArchive->HasLongnamesMember = TRUE;\n        MappedArchive->LastStandardMember = &MappedArchive->LongnamesMember;\n    }\n    else\n    {\n        MappedArchive->LastStandardMember = &MappedArchive->SecondLinkerMember;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhLoadMappedArchive(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PPH_MAPPED_ARCHIVE MappedArchive\n    )\n{\n    NTSTATUS status;\n\n    status = PhMapViewOfEntireFile(\n        FileName,\n        FileHandle,\n        &MappedArchive->ViewBase,\n        &MappedArchive->Size\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhInitializeMappedArchive(\n            MappedArchive,\n            MappedArchive->ViewBase,\n            MappedArchive->Size\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            PhUnloadMappedArchive(MappedArchive);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhUnloadMappedArchive(\n    _Inout_ PPH_MAPPED_ARCHIVE MappedArchive\n    )\n{\n    if (MappedArchive->ViewBase)\n    {\n        PhUnmapViewOfSection(NtCurrentProcess(), MappedArchive->ViewBase);\n        MappedArchive->ViewBase = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhpMappedArchiveProbe(\n    _In_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    )\n{\n    PhProbeAddress(Address, Length, MappedArchive->ViewBase, MappedArchive->Size, 1);\n}\n\n/**\n * Gets the next archive member.\n *\n * \\param Member An archive member structure.\n * \\param NextMember A variable which receives a structure describing the next archive member. This\n * pointer may be the same as the pointer specified in \\a Member.\n */\nNTSTATUS PhGetNextMappedArchiveMember(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member,\n    _Out_ PPH_MAPPED_ARCHIVE_MEMBER NextMember\n    )\n{\n    PIMAGE_ARCHIVE_MEMBER_HEADER nextHeader;\n\n    nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET(\n        Member->Data,\n        Member->Size\n        );\n\n    // 2 byte alignment.\n    if ((ULONG_PTR)nextHeader & 0x1)\n        nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET(nextHeader, 1);\n\n    return PhpGetMappedArchiveMemberFromHeader(\n        Member->MappedArchive,\n        nextHeader,\n        NextMember\n        );\n}\n\nNTSTATUS PhpGetMappedArchiveMemberFromHeader(\n    _In_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header,\n    _Out_ PPH_MAPPED_ARCHIVE_MEMBER Member\n    )\n{\n    WCHAR integerString[11];\n    ULONG64 size;\n    PH_STRINGREF string;\n    PWSTR digit;\n    PSTR slash;\n\n    if ((ULONG_PTR)Header >= (ULONG_PTR)MappedArchive->ViewBase + MappedArchive->Size)\n        return STATUS_NO_MORE_ENTRIES;\n\n    __try\n    {\n        PhpMappedArchiveProbe(MappedArchive, Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Member->MappedArchive = MappedArchive;\n    Member->Header = Header;\n    Member->Data = PTR_ADD_OFFSET(Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));\n    Member->Type = NormalArchiveMemberType;\n\n    // Read the size string, terminate it after the last digit and parse it.\n\n    if (!NT_SUCCESS(PhCopyStringZFromBytes(Header->Size, 10, integerString, 11, NULL)))\n        return STATUS_INVALID_PARAMETER;\n\n    string.Buffer = integerString;\n    string.Length = 0;\n    digit = string.Buffer;\n\n    while (iswdigit(*digit++))\n        string.Length += sizeof(WCHAR);\n\n    if (!PhStringToInteger64(&string, 10, &size))\n        return STATUS_INVALID_PARAMETER;\n\n    Member->Size = (ULONG)size;\n\n    __try\n    {\n        PhpMappedArchiveProbe(MappedArchive, Member->Data, Member->Size);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // Parse the name.\n\n    if (!NT_SUCCESS(PhCopyBytesZ(Header->Name, 16, Member->NameBuffer, 20, NULL)))\n        return STATUS_INVALID_PARAMETER;\n\n    Member->Name = Member->NameBuffer;\n\n    slash = strchr(Member->NameBuffer, '/');\n\n    if (!slash)\n        return STATUS_INVALID_PARAMETER;\n\n    // Special names:\n    // * If the slash is the first character, then this is a linker member.\n    // * If there is a slash after the slash which is a first character, then this is the longnames\n    //   member.\n    // * If there are digits after the slash, then the real name is stored in the longnames member.\n\n    if (slash == Member->NameBuffer)\n    {\n        if (Member->NameBuffer[1] == '/')\n        {\n            // Longnames member. Set the name to \"/\".\n            Member->NameBuffer[0] = '/';\n            Member->NameBuffer[1] = ANSI_NULL;\n\n            Member->Type = LongnamesArchiveMemberType;\n        }\n        else\n        {\n            // Linker member. Set the name to \"\".\n            Member->NameBuffer[0] = ANSI_NULL;\n\n            Member->Type = LinkerArchiveMemberType;\n        }\n    }\n    else\n    {\n        if (isdigit(slash[1]))\n        {\n            PSTR digita;\n            ULONG64 offset64;\n            ULONG offset;\n\n            // The name is stored in the longnames member.\n            // Note: we make sure we have the longnames member first.\n\n            if (!MappedArchive->LongnamesMember.Header)\n                return STATUS_INVALID_PARAMETER;\n\n            // Find the last digit and null terminate the string there.\n\n            digita = slash + 2;\n\n            while (isdigit(*digita))\n                digita++;\n\n            *digita = 0;\n\n            // Parse the offset and make sure it lies within the longnames member.\n\n            if (!NT_SUCCESS(PhCopyStringZFromBytes(slash + 1, -1, integerString, 11, NULL)))\n                return STATUS_INVALID_PARAMETER;\n\n            PhInitializeStringRefLongHint(&string, integerString);\n\n            if (!PhStringToUInt64(&string, 10, &offset64))\n                return STATUS_INVALID_PARAMETER;\n\n            offset = (ULONG)offset64;\n\n            if (offset >= MappedArchive->LongnamesMember.Size)\n                return STATUS_INVALID_PARAMETER;\n\n            // TODO: Probe the name.\n            Member->Name = PTR_ADD_OFFSET(MappedArchive->LongnamesMember.Data, offset);\n        }\n        else\n        {\n            // Null terminate the string.\n            slash[0] = 0;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nBOOLEAN PhIsMappedArchiveMemberShortFormat(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member\n    )\n{\n    PIMAGE_FILE_HEADER header;\n\n    header = (PIMAGE_FILE_HEADER)Member->Data;\n\n    return header->Machine != IMAGE_FILE_MACHINE_UNKNOWN;\n}\n\nNTSTATUS PhGetMappedArchiveImportEntry(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member,\n    _Out_ PPH_MAPPED_ARCHIVE_IMPORT_ENTRY Entry\n    )\n{\n    IMPORT_OBJECT_HEADER *importHeader;\n\n    importHeader = (IMPORT_OBJECT_HEADER *)Member->Data;\n\n    if (\n        importHeader->Sig1 != IMAGE_FILE_MACHINE_UNKNOWN ||\n        importHeader->Sig2 != IMPORT_OBJECT_HDR_SIG2\n        )\n        return STATUS_INVALID_PARAMETER;\n\n    Entry->Type = (BYTE)importHeader->Type;\n    Entry->NameType = (BYTE)importHeader->NameType;\n    Entry->Machine = importHeader->Machine;\n\n    // TODO: Probe the name.\n    Entry->Name = PTR_ADD_OFFSET(importHeader, sizeof(IMPORT_OBJECT_HEADER));\n    Entry->DllName = PTR_ADD_OFFSET(Entry->Name, strlen(Entry->Name) + 1);\n\n    // Ordinal/NameHint are union'ed, so these statements are exactly the same.\n    // It's there in case this changes in the future.\n    if (Entry->NameType == IMPORT_OBJECT_ORDINAL)\n    {\n        Entry->Ordinal = importHeader->Ordinal;\n    }\n    else\n    {\n        Entry->NameHint = importHeader->Hint;\n    }\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "phlib/native.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <kphuser.h>\n#include <lsasup.h>\n#include <mapldr.h>\n\n#define PH_DEVICE_PREFIX_LENGTH 64\n#define PH_DEVICE_MUP_PREFIX_MAX_COUNT 16\n\nstatic PH_INITONCE PhDevicePrefixesInitOnce = PH_INITONCE_INIT;\n\nstatic UNICODE_STRING PhDevicePrefixes[26];\nstatic PH_QUEUED_LOCK PhDevicePrefixesLock = PH_QUEUED_LOCK_INIT;\n\nstatic PPH_STRING PhDeviceMupPrefixes[PH_DEVICE_MUP_PREFIX_MAX_COUNT] = { 0 };\nstatic ULONG PhDeviceMupPrefixesCount = 0;\nstatic PH_QUEUED_LOCK PhDeviceMupPrefixesLock = PH_QUEUED_LOCK_INIT;\n\n/**\n * Retrieves a copy of an object's security descriptor.\n *\n * \\param Handle A handle to the object whose security descriptor is to be queried.\n * \\param SecurityInformation The type of security information to be queried.\n * \\param SecurityDescriptor A copy of the specified security descriptor in self-relative format.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    ULONG bufferSize;\n    PVOID buffer;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n    // This is required (especially for File objects) because some drivers don't seem to handle\n    // QuerySecurity properly. (wj32)\n    memset(buffer, 0, bufferSize);\n\n    status = NtQuerySecurityObject(\n        Handle,\n        SecurityInformation,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n        memset(buffer, 0, bufferSize);\n\n        status = NtQuerySecurityObject(\n            Handle,\n            SecurityInformation,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer;\n\n    return status;\n}\n\n/**\n * Sets an object's security descriptor.\n *\n * \\param Handle A handle to the object whose security descriptor is to be set.\n * \\param SecurityInformation The type of security information to be set.\n * \\param SecurityDescriptor The security descriptor in self-relative format.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    return NtSetSecurityObject(\n        Handle,\n        SecurityInformation,\n        SecurityDescriptor\n        );\n}\n\n/**\n * Merges two SACLs according to the provided security information.\n * The function preserves ACEs not covered by the change from the lower SACL and replaces other\n * ACEs with the ones from the higher SACL.\n *\n * Example:\n *  - A lower SACL containing two ACEs: a trust label and a mandatory label.\n *  - A higher SACL containing one ACE: a trust label.\n *  - Security information specifies PROCESS_TRUST_LABEL_SECURITY_INFORMATION.\n * Result: a SACL with the trust label from the higher SACL and the mandatory label from the lower SACL.\n *\n * \\param LowerSacl An existing SACL with potentially mixed ACE types.\n * \\param HigherSacl An overlaying SACL for the specified security information.\n * \\param SecurityInformation The type of security information to be set.\n * \\param MergedSacl The new merged SACL.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhMergeSystemAcls(\n    _In_opt_ PACL LowerSacl,\n    _In_opt_ PACL HigherSacl,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Outptr_result_maybenull_ PACL* MergedSacl\n    )\n{\n    NTSTATUS status;\n    ULONG aceTypesToReplace = 0;\n    ULONG requiredSize = 0;\n    PACL mergedSacl;\n    PACE_HEADER mergedAce;\n\n    if (!LowerSacl && !HigherSacl)\n    {\n        // Nothing to merge\n        *MergedSacl = NULL;\n        return STATUS_SUCCESS;\n    }\n\n    if (LowerSacl && (LowerSacl->AclRevision < MIN_ACL_REVISION || LowerSacl->AclRevision > MAX_ACL_REVISION))\n        return STATUS_UNKNOWN_REVISION;\n\n    if (HigherSacl && (HigherSacl->AclRevision < MIN_ACL_REVISION || HigherSacl->AclRevision > MAX_ACL_REVISION))\n        return STATUS_UNKNOWN_REVISION;\n\n    // Identify which types of ACEs we want to keep from the lower SACL and\n    // which to replace with the ones from the higher SACL\n\n    if (FlagOn(SecurityInformation, SACL_SECURITY_INFORMATION))\n        aceTypesToReplace |= AUDIT_ALARM_ACE_TYPE_MASK;\n    if (FlagOn(SecurityInformation, LABEL_SECURITY_INFORMATION))\n        aceTypesToReplace |= MANDATORY_LABEL_ACE_TYPE_MASK;\n    if (FlagOn(SecurityInformation, ATTRIBUTE_SECURITY_INFORMATION))\n        aceTypesToReplace |= RESOURCE_ATTRIBUTE_ACE_TYPE_MASK;\n    if (FlagOn(SecurityInformation, SCOPE_SECURITY_INFORMATION))\n        aceTypesToReplace |= SCOPED_POLICY_ACE_TYPE_MASK;\n    if (FlagOn(SecurityInformation, PROCESS_TRUST_LABEL_SECURITY_INFORMATION))\n        aceTypesToReplace |= PROCESS_TRUST_ACE_TYPE_MASK;\n    if (FlagOn(SecurityInformation, ACCESS_FILTER_SECURITY_INFORMATION))\n        aceTypesToReplace |= ACCESS_FILTER_ACE_TYPE_MASK;\n\n    // Calculate the size of ACEs to keep from the lower SACL\n\n    if (LowerSacl && !HigherSacl && aceTypesToReplace == 0)\n    {\n        if (LowerSacl->AclSize > USHORT_MAX)\n            return STATUS_INVALID_PARAMETER;\n\n        mergedSacl = (PACL)PhAllocate(LowerSacl->AclSize);\n        RtlCopyMemory(mergedSacl, LowerSacl, LowerSacl->AclSize);\n        *MergedSacl = mergedSacl;\n        return STATUS_SUCCESS;\n    }\n\n    // Helper macro to walk the ACL. (dmex)\n#define START_FOR_EACH_ACE(_ACL_, _ACE_) \\\n    if (_ACL_) \\\n    { \\\n        PVOID _end = PTR_ADD_OFFSET((_ACL_), (_ACL_)->AclSize); \\\n        PACE_HEADER _ACE_ = (PACE_HEADER)PTR_ADD_OFFSET((_ACL_), sizeof(ACL)); \\\n        for (USHORT _i = 0; _i < (_ACL_)->AceCount; _i++, _ACE_ = (PACE_HEADER)PTR_ADD_OFFSET(_ACE_, _ACE_->AceSize)) \\\n        { \\\n            if ((ULONG_PTR)_ACE_ >= (ULONG_PTR)_end) \\\n                return STATUS_UNSUCCESSFUL; /* malformed */ \\\n            if (_ACE_->AceSize < sizeof(ACE_HEADER) || PTR_ADD_OFFSET(_ACE_, _ACE_->AceSize) > _end) \\\n                return STATUS_UNSUCCESSFUL; /* malformed */\n#define END_FOR_EACH_ACE } }\n\n    // Calculate required payload size (sum of selected ACE sizes).\n\n    if (LowerSacl)\n    {\n        START_FOR_EACH_ACE(LowerSacl, ace)\n        {\n            ULONG bit = ace->AceType < 32 ? (1u << ace->AceType) : 0;\n\n            if (!FlagOn(bit, aceTypesToReplace))\n            {\n                requiredSize += ace->AceSize;\n            }\n        }\n        END_FOR_EACH_ACE\n    }\n\n    // Calculate the size of ACEs to use from the higher SACL\n\n    if (HigherSacl)\n    {\n        START_FOR_EACH_ACE(HigherSacl, ace)\n        {\n            ULONG bit = ace->AceType < 32 ? (1u << ace->AceType) : 0;\n\n            if (FlagOn(bit, aceTypesToReplace))\n            {\n                requiredSize += ace->AceSize;\n            }\n        }\n        END_FOR_EACH_ACE\n    }\n\n    // Allocate new ACL (header + aligned payload).\n\n    requiredSize = sizeof(ACL) + ALIGN_UP_BY(requiredSize, sizeof(ULONG));\n\n    if (requiredSize > USHORT_MAX)\n        return STATUS_INVALID_PARAMETER;\n\n    mergedSacl = (PACL)PhAllocate(requiredSize);\n    mergedAce = (PACE_HEADER)PTR_ADD_OFFSET(mergedSacl, sizeof(ACL));\n\n    status = PhCreateAcl(mergedSacl, requiredSize, ACL_REVISION);\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(mergedSacl);\n        return status;\n    }\n\n    // Add the lower SACL ACEs we keep\n\n    if (LowerSacl)\n    {\n        START_FOR_EACH_ACE(LowerSacl, ace)\n        {\n            ULONG bit = ace->AceType < 32 ? (1u << ace->AceType) : 0;\n            if (!(bit & aceTypesToReplace))\n            {\n                RtlCopyMemory(mergedAce, ace, ace->AceSize);\n                mergedSacl->AceCount++;\n                PhEnsureAclRevision((PULONG_PTR)&mergedSacl->AclRevision, mergedAce->AceType);\n                mergedAce = (PACE_HEADER)PTR_ADD_OFFSET(mergedAce, mergedAce->AceSize);\n            }\n        }\n        END_FOR_EACH_ACE\n    }\n\n    // Add the higher SACL ACEs\n\n    if (HigherSacl)\n    {\n        START_FOR_EACH_ACE(HigherSacl, ace)\n        {\n            ULONG bit = ace->AceType < 32 ? (1u << ace->AceType) : 0;\n            if (bit & aceTypesToReplace)\n            {\n                RtlCopyMemory(mergedAce, ace, ace->AceSize);\n                mergedSacl->AceCount++;\n                PhEnsureAclRevision((PULONG_PTR)&mergedSacl->AclRevision, mergedAce->AceType);\n                mergedAce = (PACE_HEADER)PTR_ADD_OFFSET(mergedAce, mergedAce->AceSize);\n            }\n        }\n        END_FOR_EACH_ACE\n    }\n\n#undef START_FOR_EACH_ACE\n#undef END_FOR_EACH_ACE\n\n    *MergedSacl = mergedSacl;\n    return STATUS_SUCCESS;\n}\n\n/**\n * Merges two security descriptors according to the provided security information.\n * The function preserves parts not covered by the change from the lower security descriptor and\n * replaces other parts with the ones from the higher security descriptor.\n *\n * Example:\n *  - A lower security descriptor containing a DACL, an owner, and a SACL with a trust label.\n *  - A higher security descriptor containing a DACL, and a SACL with a mandatory label.\n *  - Security information specifies DACL_SECURITY_INFORMATION and LABEL_SECURITY_INFORMATION.\n * Result: a security descriptor with the higher DACL, the lower owner, and a merged SACL with\n * the lower trust label and the higher mandatory label.\n *\n * \\param LowerSecurityDescriptor An existing security descriptor.\n * \\param HigherSecurityDescriptor An overlaying security descriptor for the specified security information.\n * \\param SecurityInformation The type of security information to be set.\n * \\param MergedSecurityDescriptor The new merged security descriptor.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhMergeSecurityDescriptors(\n    _In_ PSECURITY_DESCRIPTOR LowerSecurityDescriptor,\n    _In_ PSECURITY_DESCRIPTOR HigherSecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Outptr_ PSECURITY_DESCRIPTOR* MergedSecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    SECURITY_DESCRIPTOR mergedSecurityDescriptor;\n    PACL acl;\n    PSID sid;\n    BOOLEAN present;\n    BOOLEAN defaulted;\n    PACL higherSacl;\n    PACL lowerSacl;\n    PACL mergedSacl = NULL;\n    PSECURITY_DESCRIPTOR relativeSecurityDescriptor = NULL;\n    ULONG requiredLength = 0;\n\n    status = PhCreateSecurityDescriptor(&mergedSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Choose the DACL\n\n    status = PhGetDaclSecurityDescriptor(\n        (SecurityInformation & DACL_SECURITY_INFORMATION) ? HigherSecurityDescriptor : LowerSecurityDescriptor,\n        &present,\n        &acl,\n        &defaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhSetDaclSecurityDescriptor(\n        &mergedSecurityDescriptor,\n        present,\n        acl,\n        defaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Choose the owner\n\n    status = PhGetOwnerSecurityDescriptor(\n        (SecurityInformation & OWNER_SECURITY_INFORMATION) ? HigherSecurityDescriptor : LowerSecurityDescriptor,\n        &sid,\n        &defaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!sid)\n        return STATUS_INVALID_OWNER;\n\n    status = PhSetOwnerSecurityDescriptor(\n        &mergedSecurityDescriptor,\n        sid,\n        defaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Choose the primary group\n\n    status = PhGetGroupSecurityDescriptor(\n        (SecurityInformation & GROUP_SECURITY_INFORMATION) ? HigherSecurityDescriptor : LowerSecurityDescriptor,\n        &sid,\n        &defaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!sid)\n        return STATUS_INVALID_PRIMARY_GROUP;\n\n    status = PhSetGroupSecurityDescriptor(\n        &mergedSecurityDescriptor,\n        sid,\n        defaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Collect both SACLs\n\n    status = PhGetSaclSecurityDescriptor(\n        LowerSecurityDescriptor,\n        &present,\n        &lowerSacl,\n        &defaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!present)\n        lowerSacl = NULL;\n\n    status = PhGetSaclSecurityDescriptor(\n        HigherSecurityDescriptor,\n        &present,\n        &higherSacl,\n        &defaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!present)\n        higherSacl = NULL;\n\n    // Merge SACLs and apply\n\n    status = PhMergeSystemAcls(\n        lowerSacl,\n        higherSacl,\n        SecurityInformation,\n        &mergedSacl\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhSetSaclSecurityDescriptor(\n        &mergedSecurityDescriptor,\n        !!mergedSacl,\n        mergedSacl,\n        FALSE\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Make the buffer self-relative\n\n    status = RtlAbsoluteToSelfRelativeSD(\n        &mergedSecurityDescriptor,\n        NULL,\n        &requiredLength\n        );\n\n    if (status != STATUS_BUFFER_TOO_SMALL)\n    {\n        status = STATUS_INVALID_SECURITY_DESCR;\n        goto CleanupExit;\n    }\n\n    relativeSecurityDescriptor = PhAllocate(requiredLength);\n\n    status = RtlAbsoluteToSelfRelativeSD(\n        &mergedSecurityDescriptor,\n        relativeSecurityDescriptor,\n        &requiredLength\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    *MergedSecurityDescriptor = relativeSecurityDescriptor;\n    relativeSecurityDescriptor = NULL;\n\nCleanupExit:\n    if (mergedSacl)\n        PhFree(mergedSacl);\n\n    if (relativeSecurityDescriptor)\n        PhFree(relativeSecurityDescriptor);\n\n    return status;\n}\n\n/**\n * Retrieves the next environment variable from a process environment block.\n *\n * \\param Environment The environment block.\n * \\param EnvironmentLength The length of the environment block, in bytes.\n * \\param EnumerationKey A pointer to an index variable used for enumeration.\n * \\param Variable A pointer to a structure that receives the variable.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumProcessEnvironmentVariables(\n    _In_ PVOID Environment,\n    _In_ ULONG EnvironmentLength,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PPH_ENVIRONMENT_VARIABLE Variable\n    )\n{\n    ULONG length;\n    ULONG startIndex;\n    PWCHAR name;\n    ULONG nameLength;\n    PWCHAR value;\n    ULONG valueLength;\n    PWCHAR currentChar;\n    ULONG currentIndex;\n\n    length = EnvironmentLength / sizeof(WCHAR);\n\n    currentIndex = *EnumerationKey;\n    currentChar = PTR_ADD_OFFSET(Environment, currentIndex * sizeof(WCHAR));\n    startIndex = currentIndex;\n    name = currentChar;\n\n    // Find the end of the name.\n    while (TRUE)\n    {\n        if (currentIndex >= length)\n            return STATUS_UNSUCCESSFUL;\n        if (*currentChar == L'=' && startIndex != currentIndex)\n            break; // equality sign is considered as a delimiter unless it is the first character (diversenok)\n        if (*currentChar == UNICODE_NULL)\n            return STATUS_UNSUCCESSFUL; // no more variables\n\n        currentIndex++;\n        currentChar++;\n    }\n\n    nameLength = currentIndex - startIndex;\n\n    currentIndex++;\n    currentChar++;\n    startIndex = currentIndex;\n    value = currentChar;\n\n    // Find the end of the value.\n    while (TRUE)\n    {\n        if (currentIndex >= length)\n            return STATUS_UNSUCCESSFUL;\n        if (*currentChar == UNICODE_NULL)\n            break;\n\n        currentIndex++;\n        currentChar++;\n    }\n\n    valueLength = currentIndex - startIndex;\n\n    currentIndex++;\n    *EnumerationKey = currentIndex;\n\n    Variable->Name.Buffer = name;\n    Variable->Name.Length = nameLength * sizeof(WCHAR);\n    Variable->Value.Buffer = value;\n    Variable->Value.Length = valueLength * sizeof(WCHAR);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Queries an environment variable as a string reference.\n *\n * \\param Environment The environment block.\n * \\param Name The name of the variable.\n * \\param Value A pointer to a string reference that receives the value.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryEnvironmentVariableStringRef(\n    _In_opt_ PVOID Environment,\n    _In_ PCPH_STRINGREF Name,\n    _Inout_opt_ PPH_STRINGREF Value\n    )\n{\n    NTSTATUS status;\n    SIZE_T returnLength;\n\n    status = RtlQueryEnvironmentVariable(\n        Environment,\n        Name->Buffer,\n        Name->Length / sizeof(WCHAR),\n        Value ? Value->Buffer : NULL,\n        Value ? Value->Length / sizeof(WCHAR) : 0,\n        &returnLength\n        );\n\n    if (Value && NT_SUCCESS(status))\n    {\n        Value->Length = returnLength * sizeof(WCHAR);\n    }\n\n    return status;\n}\n\n/**\n * Queries an environment variable.\n *\n * \\param Environment The environment block.\n * \\param Name The name of the variable.\n * \\param Value A pointer to a string that receives the value.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryEnvironmentVariable(\n    _In_opt_ PVOID Environment,\n    _In_ PCPH_STRINGREF Name,\n    _Out_opt_ PPH_STRING* Value\n    )\n{\n#ifdef PHNT_UNICODESTRING_ENVIRONMENTVARIABLE\n    NTSTATUS status;\n    UNICODE_STRING variableName;\n    UNICODE_STRING variableValue;\n\n    if (!PhStringRefToUnicodeString(Name, &variableName))\n        return STATUS_NAME_TOO_LONG;\n\n    if (Value)\n    {\n        variableValue.Length = 0x100 * sizeof(WCHAR);\n        variableValue.MaximumLength = variableValue.Length + sizeof(UNICODE_NULL);\n        variableValue.Buffer = PhAllocate(variableValue.MaximumLength);\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&variableValue, NULL, 0);\n    }\n\n    status = RtlQueryEnvironmentVariable_U(\n        Environment,\n        &variableName,\n        &variableValue\n        );\n\n    if (Value && status == STATUS_BUFFER_TOO_SMALL)\n    {\n        if (variableValue.Length + sizeof(UNICODE_NULL) > UNICODE_STRING_MAX_BYTES)\n            variableValue.MaximumLength = variableValue.Length;\n        else\n            variableValue.MaximumLength = variableValue.Length + sizeof(UNICODE_NULL);\n\n        PhFree(variableValue.Buffer);\n        variableValue.Buffer = PhAllocate(variableValue.MaximumLength);\n\n        status = RtlQueryEnvironmentVariable_U(\n            Environment,\n            &variableName,\n            &variableValue\n            );\n    }\n\n    if (Value && NT_SUCCESS(status))\n    {\n        *Value = PhCreateStringFromUnicodeString(&variableValue);\n    }\n\n    if (Value && variableValue.Buffer)\n    {\n        PhFree(variableValue.Buffer);\n    }\n\n    return status;\n#else\n    NTSTATUS status;\n    PPH_STRING buffer;\n    SIZE_T returnLength;\n\n    status = RtlQueryEnvironmentVariable(\n        Environment,\n        Name->Buffer,\n        Name->Length / sizeof(WCHAR),\n        NULL,\n        0,\n        &returnLength\n        );\n\n    if (Value && status == STATUS_BUFFER_TOO_SMALL)\n    {\n        buffer = PhCreateStringEx(NULL, returnLength * sizeof(WCHAR));\n\n        status = RtlQueryEnvironmentVariable(\n            Environment,\n            Name->Buffer,\n            Name->Length / sizeof(WCHAR),\n            buffer->Buffer,\n            buffer->Length / sizeof(WCHAR),\n            &returnLength\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            buffer->Length = returnLength * sizeof(WCHAR);\n            *Value = buffer;\n        }\n        else\n        {\n            PhDereferenceObject(buffer);\n        }\n    }\n    else\n    {\n        if (Value)\n            *Value = NULL;\n    }\n\n    return status;\n#endif\n}\n\n/**\n * Sets an environment variable.\n *\n * \\param Environment The environment block.\n * \\param Name The name of the variable.\n * \\param Value The value to set, or NULL to delete the variable.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetEnvironmentVariable(\n    _In_opt_ PVOID Environment,\n    _In_ PCPH_STRINGREF Name,\n    _In_opt_ PCPH_STRINGREF Value\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING variableName;\n    UNICODE_STRING variableValue;\n\n    if (!PhStringRefToUnicodeString(Name, &variableName))\n        return STATUS_NAME_TOO_LONG;\n\n    if (Value)\n    {\n        if (!PhStringRefToUnicodeString(Value, &variableValue))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&variableValue, NULL, 0);\n    }\n\n    status = RtlSetEnvironmentVariable(\n        Environment,\n        &variableName,\n        &variableValue\n        );\n\n    return status;\n}\n\n/**\n * Retrieves the file name for a mapped section in a process.\n *\n * \\param SectionHandle The section handle.\n * \\param ProcessHandle The process handle.\n * \\param FileName A pointer to a string that receives the file name.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessSectionFileName(\n    _In_ HANDLE SectionHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    PVOID baseAddress;\n    SIZE_T viewSize;\n\n    baseAddress = NULL;\n    viewSize = PAGE_SIZE;\n\n    status = PhMapViewOfSection(\n        SectionHandle,\n        ProcessHandle,\n        &baseAddress,\n        0,\n        NULL,\n        &viewSize,\n        ViewUnmap,\n        0,\n        PAGE_READONLY\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetProcessMappedFileName(\n        ProcessHandle,\n        baseAddress,\n        FileName\n        );\n\n    PhUnmapViewOfSection(ProcessHandle, baseAddress);\n\n    return status;\n}\n\n/**\n * Retrieves the list of unloaded DLLs for a process.\n *\n * \\param ProcessId The process ID.\n * \\param EventTrace A pointer to the event trace buffer.\n * \\param EventTraceSize The size of each event trace element.\n * \\param EventTraceCount The number of event trace elements.\n */\nNTSTATUS PhGetProcessUnloadedDlls(\n    _In_ HANDLE ProcessId,\n    _Out_ PVOID *EventTrace,\n    _Out_ ULONG *EventTraceSize,\n    _Out_ ULONG *EventTraceCount\n    )\n{\n    NTSTATUS status;\n    PULONG elementSize;\n    PULONG elementCount;\n    PVOID eventTrace;\n    HANDLE processHandle = NULL;\n    SIZE_T eventTraceSize;\n    ULONG capturedElementSize = 0;\n    ULONG capturedElementCount = 0;\n    PVOID capturedEventTracePointer;\n    PVOID capturedEventTrace = NULL;\n\n    RtlGetUnloadEventTraceEx(&elementSize, &elementCount, &eventTrace);\n\n    if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_VM_READ, ProcessId)))\n        goto CleanupExit;\n\n    // We have the pointers for the unload event trace information.\n    // Since ntdll is loaded at the same base address across all processes,\n    // we can read the information in.\n\n    if (!NT_SUCCESS(status = PhReadVirtualMemory(\n        processHandle,\n        elementSize,\n        &capturedElementSize,\n        sizeof(ULONG),\n        NULL\n        )))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhReadVirtualMemory(\n        processHandle,\n        elementCount,\n        &capturedElementCount,\n        sizeof(ULONG),\n        NULL\n        )))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhReadVirtualMemory(\n        processHandle,\n        eventTrace,\n        &capturedEventTracePointer,\n        sizeof(PVOID),\n        NULL\n        )))\n        goto CleanupExit;\n\n    if (!capturedEventTracePointer)\n    {\n        status = STATUS_NOT_FOUND; // no events\n        goto CleanupExit;\n    }\n\n    if (capturedElementCount > 0x4000)\n        capturedElementCount = 0x4000;\n\n    eventTraceSize = capturedElementSize * capturedElementCount;\n    capturedEventTrace = PhAllocateSafe(eventTraceSize);\n\n    if (!capturedEventTrace)\n    {\n        status = STATUS_NO_MEMORY;\n        goto CleanupExit;\n    }\n\n    if (!NT_SUCCESS(status = PhReadVirtualMemory(\n        processHandle,\n        capturedEventTracePointer,\n        capturedEventTrace,\n        eventTraceSize,\n        NULL\n        )))\n        goto CleanupExit;\n\nCleanupExit:\n\n    if (processHandle)\n        NtClose(processHandle);\n\n    if (NT_SUCCESS(status))\n    {\n        *EventTrace = capturedEventTrace;\n        *EventTraceSize = capturedElementSize;\n        *EventTraceCount = capturedElementCount;\n    }\n    else\n    {\n        if (capturedEventTrace)\n            PhFree(capturedEventTrace);\n    }\n\n    return status;\n}\n\n/**\n * Sends a trace control request.\n *\n * \\param TraceInformationClass The trace information class.\n * \\param InputBuffer The input buffer.\n * \\param InputBufferLength The length of the input buffer.\n * \\param OutputBuffer The output buffer.\n * \\param OutputBufferLength The length of the output buffer.\n * \\param ReturnLength A pointer to a variable that receives the return length.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhTraceControl(\n    _In_ ETWTRACECONTROLCODE TraceInformationClass,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _Out_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n\n    status = NtTraceControl(\n        TraceInformationClass,\n        InputBuffer,\n        InputBufferLength,\n        OutputBuffer,\n        OutputBufferLength,\n        ReturnLength\n        );\n\n    return status;\n}\n\n/**\n * Sends a trace control request with variable output size.\n *\n * \\param TraceInformationClass The trace information class.\n * \\param InputBuffer The input buffer.\n * \\param InputBufferLength The length of the input buffer.\n * \\param OutputBuffer A pointer to a buffer that receives the output.\n * \\param OutputBufferLength A pointer to a variable that receives the output buffer length.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhTraceControlVariableSize(\n    _In_ ETWTRACECONTROLCODE TraceInformationClass,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(*OutputBufferLength) PVOID* OutputBuffer,\n    _Out_opt_ PULONG OutputBufferLength\n    )\n{\n    NTSTATUS status;\n    PVOID buffer = NULL;\n    ULONG bufferLength = 0;\n    ULONG returnLength = 0;\n\n    status = NtTraceControl(\n        TraceInformationClass,\n        InputBuffer,\n        InputBufferLength,\n        NULL,\n        0,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        bufferLength = returnLength;\n        buffer = PhAllocate(bufferLength);\n\n        status = NtTraceControl(\n            TraceInformationClass,\n            InputBuffer,\n            InputBufferLength,\n            buffer,\n            bufferLength,\n            &bufferLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (OutputBuffer)\n            *OutputBuffer = buffer;\n        if (OutputBufferLength)\n            *OutputBufferLength = bufferLength;\n    }\n    else\n    {\n        if (buffer)\n            PhFree(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the client ID associated with the specified window handle.\n *\n * \\param WindowHandle The handle to the window whose client ID is to be retrieved.\n * \\param ClientId A pointer to a CLIENT_ID structure that receives the process and thread IDs.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetWindowClientId(\n    _In_ HWND WindowHandle,\n    _Out_ PCLIENT_ID ClientId\n    )\n{\n    ULONG windowProcessId;\n    ULONG windowThreadId;\n\n    if (windowThreadId = GetWindowThreadProcessId(WindowHandle, &windowProcessId))\n    {\n        ClientId->UniqueProcess = UlongToHandle(windowProcessId);\n        ClientId->UniqueThread = UlongToHandle(windowThreadId);\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_NOT_FOUND;\n}\n\ntypedef struct _OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT\n{\n    NTSTATUS Status;\n    PVOID BaseAddress;\n    HANDLE DriverHandle;\n} OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT, *POPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT;\n\n_Function_class_(PH_ENUM_DIRECTORY_OBJECTS)\nNTSTATUS NTAPI PhpOpenDriverByBaseAddressCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PPH_STRINGREF Name,\n    _In_ PPH_STRINGREF TypeName,\n    _In_ POPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    HANDLE driverHandle;\n    UNICODE_STRING driverName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    KPH_DRIVER_BASIC_INFORMATION basicInfo;\n\n    if (!PhStringRefToUnicodeString(Name, &driverName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &driverName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = KphOpenDriver(\n        &driverHandle,\n        SYNCHRONIZE,\n        &objectAttributes\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = KphQueryInformationDriver(\n        driverHandle,\n        KphDriverBasicInformation,\n        &basicInfo,\n        sizeof(KPH_DRIVER_BASIC_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (basicInfo.DriverStart == Context->BaseAddress)\n        {\n            Context->Status = STATUS_SUCCESS;\n            Context->DriverHandle = driverHandle;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    NtClose(driverHandle);\n\n    return status;\n}\n\n/**\n * Opens a driver object using a base address.\n *\n * \\param DriverHandle A variable which receives a handle to the driver object.\n * \\param BaseAddress The base address of the driver to open.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks STATUS_OBJECT_NAME_NOT_FOUND is returned if the driver could not be found.\n */\nNTSTATUS PhOpenDriverByBaseAddress(\n    _Out_ PHANDLE DriverHandle,\n    _In_ PVOID BaseAddress\n    )\n{\n    NTSTATUS status;\n    HANDLE directoryHandle;\n    UNICODE_STRING objectDirectory;\n    OBJECT_ATTRIBUTES objectAttributes;\n    OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT context;\n\n    RtlInitUnicodeString(&objectDirectory, L\"\\\\Driver\");\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectDirectory,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtOpenDirectoryObject(\n        &directoryHandle,\n        DIRECTORY_QUERY,\n        &objectAttributes\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    context.Status = STATUS_OBJECT_NAME_NOT_FOUND;\n    context.BaseAddress = BaseAddress;\n\n    status = PhEnumDirectoryObjects(\n        directoryHandle,\n        PhpOpenDriverByBaseAddressCallback,\n        &context\n        );\n\n    NtClose(directoryHandle);\n\n    if (NT_SUCCESS(status))\n    {\n        if (NT_SUCCESS(context.Status))\n        {\n            *DriverHandle = context.DriverHandle;\n            return STATUS_SUCCESS;\n        }\n\n        return context.Status;\n    }\n\n    return status;\n}\n\n/**\n * Opens a handle to a driver object.\n *\n * \\param DriverHandle Pointer to a variable that receives the handle to the driver object.\n * \\param DesiredAccess Specifies the desired access rights to the driver object.\n * \\param RootDirectory Optional handle to the root directory for the object name (can be NULL).\n * \\param ObjectName Pointer to a string reference that specifies the name of the driver object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenDriver(\n    _Out_ PHANDLE DriverHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName\n    )\n{\n    if (KsiLevel() == KphLevelMax)\n    {\n        UNICODE_STRING objectName;\n        OBJECT_ATTRIBUTES objectAttributes;\n\n        if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n            return STATUS_NAME_TOO_LONG;\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            &objectName,\n            OBJ_CASE_INSENSITIVE,\n            RootDirectory,\n            NULL\n            );\n\n        return KphOpenDriver(\n            DriverHandle,\n            DesiredAccess,\n            &objectAttributes\n            );\n    }\n    else\n    {\n        return STATUS_NOT_IMPLEMENTED;\n    }\n}\n\n/**\n * Queries variable-sized information for a driver. The function allocates a buffer to contain the\n * information.\n *\n * \\param DriverHandle A handle to a driver. The access required depends on the information class specified.\n * \\param DriverInformationClass The information class to retrieve.\n * \\param Buffer A variable which receives a pointer to a buffer containing the information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpQueryDriverVariableSize(\n    _In_ HANDLE DriverHandle,\n    _In_ KPH_DRIVER_INFORMATION_CLASS DriverInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer = NULL;\n    ULONG bufferSize;\n    ULONG returnLength = 0;\n\n    status = KphQueryInformationDriver(\n        DriverHandle,\n        DriverInformationClass,\n        NULL,\n        0,\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status) && returnLength == 0)\n    {\n        return STATUS_NOT_FOUND;\n    }\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        bufferSize = returnLength;\n        buffer = PhAllocate(bufferSize);\n\n        status = KphQueryInformationDriver(\n            DriverHandle,\n            DriverInformationClass,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (returnLength == 0)\n        {\n            status = STATUS_NOT_FOUND;\n            PhFree(buffer);\n        }\n        else\n        {\n            *Buffer = buffer;\n        }\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Gets the object name of a driver.\n *\n * \\param DriverHandle A handle to a driver.\n * \\param Name A variable which receives a pointer to a string containing the object name.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetDriverName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *Name\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING unicodeString;\n\n    if (!NT_SUCCESS(status = PhpQueryDriverVariableSize(\n        DriverHandle,\n        KphDriverNameInformation,\n        &unicodeString\n        )))\n        return status;\n\n    *Name = PhCreateStringFromUnicodeString(unicodeString);\n    PhFree(unicodeString);\n\n    return status;\n}\n\n/**\n * Gets the object name of a driver.\n *\n * \\param DriverHandle A handle to a driver.\n * \\param Name A variable which receives a pointer to a string containing the driver image file name.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetDriverImageFileName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *Name\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING unicodeString;\n\n    if (!NT_SUCCESS(status = PhpQueryDriverVariableSize(\n        DriverHandle,\n        KphDriverImageFileNameInformation,\n        &unicodeString\n        )))\n        return status;\n\n    *Name = PhCreateStringFromUnicodeString(unicodeString);\n    PhFree(unicodeString);\n\n    return status;\n}\n\n/**\n * Gets the service key name of a driver.\n *\n * \\param DriverHandle A handle to a driver.\n * \\param ServiceKeyName A string containing the service key name.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetDriverServiceKeyName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *ServiceKeyName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING unicodeString;\n\n    if (!NT_SUCCESS(status = PhpQueryDriverVariableSize(\n        DriverHandle,\n        KphDriverServiceKeyNameInformation,\n        &unicodeString\n        )))\n        return status;\n\n    *ServiceKeyName = PhCreateStringFromUnicodeString(unicodeString);\n    PhFree(unicodeString);\n\n    return status;\n}\n\nstatic NTSTATUS PhpUnloadDriver(\n    _In_ PCPH_STRINGREF ServiceKeyName,\n    _In_ PCPH_STRINGREF DriverFileName\n    )\n{\n    static CONST PH_STRINGREF fullServicesKeyName = PH_STRINGREF_INIT(L\"\\\\Registry\\\\Machine\\\\System\\\\CurrentControlSet\\\\Services\\\\\");\n    NTSTATUS status;\n    PPH_STRING fullServiceKeyName;\n    UNICODE_STRING fullServiceKeyNameUs;\n    HANDLE serviceKeyHandle;\n    ULONG disposition;\n\n    fullServiceKeyName = PhConcatStringRef2(&fullServicesKeyName, ServiceKeyName);\n\n    if (!PhStringRefToUnicodeString(&fullServiceKeyName->sr, &fullServiceKeyNameUs))\n    {\n        PhDereferenceObject(fullServiceKeyName);\n        return STATUS_NAME_TOO_LONG;\n    }\n\n    if (NT_SUCCESS(status = PhCreateKey(\n        &serviceKeyHandle,\n        KEY_WRITE | DELETE,\n        NULL,\n        &fullServiceKeyName->sr,\n        0,\n        0,\n        &disposition\n        )))\n    {\n        if (disposition == REG_CREATED_NEW_KEY)\n        {\n            ULONG regValue = 0;\n\n            // Set up the required values.\n            PhSetValueKeyZ(serviceKeyHandle, L\"ErrorControl\", REG_DWORD, &regValue, sizeof(ULONG));\n            PhSetValueKeyZ(serviceKeyHandle, L\"Start\", REG_DWORD, &regValue, sizeof(ULONG));\n            PhSetValueKeyZ(serviceKeyHandle, L\"Type\", REG_DWORD, &regValue, sizeof(ULONG));\n            PhSetValueKeyZ(serviceKeyHandle, L\"ImagePath\", REG_SZ, DriverFileName->Buffer, (ULONG)DriverFileName->Length + sizeof(UNICODE_NULL));\n        }\n\n        status = NtUnloadDriver(&fullServiceKeyNameUs);\n\n        if (disposition == REG_CREATED_NEW_KEY)\n        {\n            // We added values, not subkeys, so this function will work correctly.\n            NtDeleteKey(serviceKeyHandle);\n        }\n\n        NtClose(serviceKeyHandle);\n    }\n\n    PhDereferenceObject(fullServiceKeyName);\n\n    return status;\n}\n\n/**\n * Unloads a driver.\n *\n * \\param BaseAddress The base address of the driver. This parameter can be NULL if a value is\n * specified in \\c Name.\n * \\param Name The base name of the driver. This parameter can be NULL if a value is specified in\n * \\c BaseAddress and KSystemInformer is loaded.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INVALID_PARAMETER_MIX Both \\c BaseAddress and \\c Name were null, or \\c Name was\n * not specified and KSystemInformer is not loaded.\n * \\retval STATUS_OBJECT_NAME_NOT_FOUND The driver could not be found.\n */\nNTSTATUS PhUnloadDriver(\n    _In_opt_ PVOID BaseAddress,\n    _In_opt_ PCPH_STRINGREF Name,\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    HANDLE driverHandle;\n    PPH_STRING serviceKeyName = NULL;\n    KPH_LEVEL level;\n\n    level = KsiLevel();\n\n    if (!BaseAddress && !Name)\n        return STATUS_INVALID_PARAMETER_MIX;\n    if (!Name && (level != KphLevelMax))\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    // Try to get the service key name by scanning the Driver directory.\n\n    if ((level == KphLevelMax) && BaseAddress)\n    {\n        if (PhGetOwnTokenAttributes().Elevated)\n        {\n            if (NT_SUCCESS(PhOpenDriverByBaseAddress(\n                &driverHandle,\n                BaseAddress\n                )))\n            {\n                PhGetDriverServiceKeyName(driverHandle, &serviceKeyName);\n                NtClose(driverHandle);\n            }\n        }\n    }\n\n    // Use the base name if we didn't get the service key name.\n\n    if (!serviceKeyName && Name)\n    {\n        PPH_STRING name;\n\n        name = PhCreateString2(Name);\n\n        // Remove the extension if it is present.\n        if (PhEndsWithString2(name, L\".sys\", TRUE))\n        {\n            serviceKeyName = PhSubstring(name, 0, name->Length / sizeof(WCHAR) - 4);\n            PhDereferenceObject(name);\n        }\n        else\n        {\n            serviceKeyName = name;\n        }\n    }\n\n    if (!serviceKeyName)\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n\n    status = PhpUnloadDriver(&serviceKeyName->sr, FileName);\n    PhDereferenceObject(serviceKeyName);\n\n    return status;\n}\n\n/**\n * Enumerates the running processes.\n *\n * \\param Processes A variable which receives a pointer to a buffer containing process information.\n * You must free the buffer using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks You can use the \\ref PH_FIRST_PROCESS and \\ref PH_NEXT_PROCESS macros to process the\n * information contained in the buffer.\n */\nNTSTATUS PhEnumProcesses(\n    _Out_ PVOID *Processes\n    )\n{\n    return PhEnumProcessesEx(Processes, SystemProcessInformation);\n}\n\n/**\n * Enumerates the running processes.\n *\n * \\param Processes A variable which receives a pointer to a buffer containing process information.\n * You must free the buffer using PhFree() when you no longer need it.\n * \\param SystemInformationClass A variable which indicates the kind of system information to be retrieved.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks You can use the \\ref PH_FIRST_PROCESS and \\ref PH_NEXT_PROCESS macros to process the\n * information contained in the buffer.\n */\nNTSTATUS PhEnumProcessesEx(\n    _Out_ PVOID *Processes,\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass\n    )\n{\n    static ULONG initialBufferSize[3] = { 0x4000, 0x4000, 0x4000 };\n    NTSTATUS status;\n    ULONG classIndex;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    switch (SystemInformationClass)\n    {\n    case SystemProcessInformation:\n        classIndex = 0;\n        break;\n    case SystemExtendedProcessInformation:\n        classIndex = 1;\n        break;\n    case SystemFullProcessInformation:\n        classIndex = 2;\n        break;\n    default:\n        return STATUS_INVALID_INFO_CLASS;\n    }\n\n    bufferSize = initialBufferSize[classIndex];\n    buffer = PhAllocateSafe(bufferSize);\n    if (!buffer) return STATUS_NO_MEMORY;\n\n    while (TRUE)\n    {\n        status = NtQuerySystemInformation(\n            SystemInformationClass,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            buffer = PhAllocateSafe(bufferSize);\n            if (!buffer) return STATUS_NO_MEMORY;\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x100000) initialBufferSize[classIndex] = bufferSize;\n    *Processes = buffer;\n\n    return status;\n}\n\n/**\n * Enumerates the threads of a running process.\n *\n * \\param ProcessId The ID of the process.\n * \\param Callback The callback function to be called for each enumerated thread.\n * \\param Context An optional context parameter to be passed to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumProcessThreads(\n    _In_ HANDLE ProcessId,\n    _In_ PPH_ENUM_PROCESS_THREADS Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PVOID processes;\n    PSYSTEM_PROCESS_INFORMATION process;\n\n    status = PhEnumProcesses(&processes);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (process = PhFindProcessInformation(processes, ProcessId))\n    {\n        status = Callback(\n            process->NumberOfThreads,\n            process->Threads,\n            Context\n            );\n    }\n    else\n    {\n        status = STATUS_INVALID_CID;\n    }\n\n    PhFree(processes);\n\n    return status;\n}\n\n/**\n * Enumerates the next process.\n *\n * \\param ProcessHandle The handle to the current process. Pass NULL to start enumeration from the beginning.\n * \\param DesiredAccess The desired access rights for the process handle.\n * \\param Callback The callback function to be called for each enumerated process.\n * \\param Context An optional context parameter to be passed to the callback function.\n * \\return Returns the status of the enumeration operation.\n *         If the enumeration is successful, it returns STATUS_SUCCESS.\n *         If there are no more processes to enumerate, it returns STATUS_NO_MORE_ENTRIES.\n *         Otherwise, it returns an appropriate NTSTATUS error code.\n */\nNTSTATUS PhEnumNextProcess(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPH_ENUM_NEXT_PROCESS Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    HANDLE newProcessHandle;\n\n    status = NtGetNextProcess(\n        ProcessHandle,\n        DesiredAccess,\n        0,\n        0,\n        &processHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    while (TRUE)\n    {\n        status = Callback(processHandle, Context);\n\n        if (status == STATUS_NO_MORE_ENTRIES)\n            break;\n\n        if (!NT_SUCCESS(status))\n        {\n            NtClose(processHandle);\n            break;\n        }\n\n        status = NtGetNextProcess(\n            processHandle,\n            DesiredAccess,\n            0,\n            0,\n            &newProcessHandle\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            NtClose(processHandle);\n            processHandle = newProcessHandle;\n        }\n        else\n        {\n            NtClose(processHandle);\n            break;\n        }\n    }\n\n    if (status == STATUS_NO_MORE_ENTRIES)\n        status = STATUS_SUCCESS;\n\n    return status;\n}\n\n/**\n * Enumerates the next thread.\n *\n * \\param ProcessHandle The handle to the process.\n * \\param ThreadHandle The handle to the current thread. Pass NULL to start enumeration from the beginning.\n * \\param DesiredAccess The desired access rights for the thread handle.\n * \\param Callback The callback function to be called for each enumerated thread.\n * \\param Context An optional context parameter to be passed to the callback function.\n * \\return Returns the status of the enumeration operation.\n *         If the enumeration is successful, it returns STATUS_SUCCESS.\n *         If there are no more threads to enumerate, it returns STATUS_NO_MORE_ENTRIES.\n *         Otherwise, it returns an appropriate NTSTATUS error code.\n */\nNTSTATUS PhEnumNextThread(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPH_ENUM_NEXT_THREAD Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n    HANDLE newThreadHandle;\n\n    status = NtGetNextThread(\n        ProcessHandle,\n        ThreadHandle,\n        DesiredAccess,\n        0,\n        0,\n        &threadHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    while (TRUE)\n    {\n        status = Callback(threadHandle, Context);\n\n        if (status == STATUS_NO_MORE_ENTRIES)\n            break;\n\n        if (!NT_SUCCESS(status))\n        {\n            NtClose(threadHandle);\n            break;\n        }\n\n        status = NtGetNextThread(\n            ProcessHandle,\n            threadHandle,\n            DesiredAccess,\n            0,\n            0,\n            &newThreadHandle\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            NtClose(threadHandle);\n            threadHandle = newThreadHandle;\n        }\n        else\n        {\n            NtClose(threadHandle);\n            break;\n        }\n    }\n\n    if (status == STATUS_NO_MORE_ENTRIES)\n        status = STATUS_SUCCESS;\n\n    return status;\n}\n\n/**\n * Enumerates the running processes for a session.\n *\n * \\param Processes A variable which receives a pointer to a buffer containing process information.\n * You must free the buffer using PhFree() when you no longer need it.\n * \\param SessionId A session ID.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks You can use the \\ref PH_FIRST_PROCESS and \\ref PH_NEXT_PROCESS macros to process the\n * information contained in the buffer.\n */\nNTSTATUS PhEnumProcessesForSession(\n    _Out_ PVOID *Processes,\n    _In_ ULONG SessionId\n    )\n{\n    static ULONG initialBufferSize = 0x4000;\n    NTSTATUS status;\n    SYSTEM_SESSION_PROCESS_INFORMATION sessionProcessInfo;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocate(bufferSize);\n\n    sessionProcessInfo.SessionId = SessionId;\n\n    while (TRUE)\n    {\n        sessionProcessInfo.BufferSize = bufferSize;\n        sessionProcessInfo.Buffer = buffer;\n\n        status = NtQuerySystemInformation(\n            SystemSessionProcessInformation,\n            &sessionProcessInfo,\n            sizeof(SYSTEM_SESSION_PROCESS_INFORMATION),\n            &bufferSize // size of the inner buffer gets returned\n            );\n\n        if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x100000) initialBufferSize = bufferSize;\n    *Processes = buffer;\n\n    return status;\n}\n\n/**\n * Finds the process information structure for a specific process.\n *\n * \\param Processes A pointer to a buffer returned by PhEnumProcesses().\n * \\param ProcessId The ID of the process.\n * \\return A pointer to the process information structure for the specified process, or NULL if the\n * structure could not be found.\n */\nPSYSTEM_PROCESS_INFORMATION PhFindProcessInformation(\n    _In_ PVOID Processes,\n    _In_ HANDLE ProcessId\n    )\n{\n    PSYSTEM_PROCESS_INFORMATION process;\n\n    process = PH_FIRST_PROCESS(Processes);\n\n    do\n    {\n        if (process->UniqueProcessId == ProcessId)\n            return process;\n    } while (process = PH_NEXT_PROCESS(process));\n\n    return NULL;\n}\n\n/**\n * Finds the process information structure for a specific process.\n *\n * \\param Processes A pointer to a buffer returned by PhEnumProcesses().\n * \\param ImageName The image name to search for.\n * \\return A pointer to the process information structure for the specified process, or NULL if the\n * structure could not be found.\n */\nPSYSTEM_PROCESS_INFORMATION PhFindProcessInformationByImageName(\n    _In_ PVOID Processes,\n    _In_ PCPH_STRINGREF ImageName\n    )\n{\n    PSYSTEM_PROCESS_INFORMATION process;\n    PH_STRINGREF processImageName;\n\n    process = PH_FIRST_PROCESS(Processes);\n\n    do\n    {\n        PhUnicodeStringToStringRef(&process->ImageName, &processImageName);\n\n        if (PhEqualStringRef(&processImageName, ImageName, TRUE))\n            return process;\n    } while (process = PH_NEXT_PROCESS(process));\n\n    return NULL;\n}\n\n/**\n * Enumerates all open handles.\n *\n * \\param Handles A variable which receives a pointer to a structure containing information about\n * all opened handles. You must free the structure using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large.\n */\n__declspec(deprecated(\"The SystemHandleInformation class is deprecated on 64-bit Windows. Use PhEnumHandlesEx instead.\"))\nNTSTATUS PhEnumHandles(\n    _Out_ PSYSTEM_HANDLE_INFORMATION *Handles\n    )\n{\n    static ULONG initialBufferSize = 0x10000;\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQuerySystemInformation(\n        SystemHandleInformation,\n        buffer,\n        bufferSize,\n        NULL\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x200000) initialBufferSize = bufferSize;\n    *Handles = (PSYSTEM_HANDLE_INFORMATION)buffer;\n\n    return status;\n}\n\n/**\n * Enumerates all open handles.\n *\n * \\param Handles A variable which receives a pointer to a structure containing information about\n * all opened handles. You must free the structure using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large.\n * \\remarks This function is only available starting with Windows XP.\n */\nNTSTATUS PhEnumHandlesEx(\n    _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles\n    )\n{\n    static ULONG initialBufferSize = 0x10000;\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG returnLength = 0;\n    ULONG attempts = 0;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQuerySystemInformation(\n        SystemExtendedHandleInformation,\n        buffer,\n        bufferSize,\n        &returnLength\n        );\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 10)\n    {\n        PhFree(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQuerySystemInformation(\n            SystemExtendedHandleInformation,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n\n        attempts++;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        // Fall back to using the previous code that we've used since Windows XP (dmex)\n        bufferSize = initialBufferSize;\n        buffer = PhAllocate(bufferSize);\n\n        while ((status = NtQuerySystemInformation(\n            SystemExtendedHandleInformation,\n            buffer,\n            bufferSize,\n            NULL\n            )) == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n\n            // Fail if we're resizing the buffer to something very large.\n            if (bufferSize > PH_LARGE_BUFFER_SIZE)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            buffer = PhAllocate(bufferSize);\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x200000) initialBufferSize = bufferSize;\n    *Handles = (PSYSTEM_HANDLE_INFORMATION_EX)buffer;\n\n    return status;\n}\n\n/**\n * Enumerates all open handles.\n *\n * \\param ProcessHandle A handle to the process. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param Handles A variable which receives a pointer to a structure containing information about\n * handles opened by the process. You must free the structure using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large.\n * \\remarks This function is only available starting with Windows 8.\n */\nNTSTATUS PhEnumProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_HANDLE_SNAPSHOT_INFORMATION *Handles\n    )\n{\n    NTSTATUS status;\n    PPROCESS_HANDLE_SNAPSHOT_INFORMATION buffer;\n    ULONG bufferSize;\n    ULONG returnLength = 0;\n    ULONG attempts = 0;\n\n    bufferSize = 0x8000;\n    buffer = PhAllocatePage(bufferSize, NULL);\n    if (!buffer) return STATUS_NO_MEMORY;\n    buffer->NumberOfHandles = 0;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessHandleInformation,\n        buffer,\n        bufferSize,\n        &returnLength\n        );\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)\n    {\n        PhFreePage(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocatePage(bufferSize, NULL);\n        if (!buffer) return STATUS_NO_MEMORY;\n        buffer->NumberOfHandles = 0;\n\n        status = NtQueryInformationProcess(\n            ProcessHandle,\n            ProcessHandleInformation,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n\n        attempts++;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        // NOTE: This is needed to workaround minimal processes on Windows 10\n        // returning STATUS_SUCCESS with invalid handle data. (dmex)\n        // NOTE: 21H1 and above no longer set NumberOfHandles to zero before returning\n        // STATUS_SUCCESS so we first zero the entire buffer using PhAllocateZero. (dmex)\n        if (buffer->NumberOfHandles == 0)\n        {\n            status = STATUS_UNSUCCESSFUL;\n            PhFreePage(buffer);\n        }\n        else\n        {\n            *Handles = buffer;\n        }\n    }\n    else\n    {\n        PhFreePage(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Enumerates all handles in a process.\n *\n * \\param ProcessId The ID of the process.\n * \\param ProcessHandle A handle to the process.\n * \\param EnableHandleSnapshot TRUE to return a snapshot of the process handles.\n * \\param Handles A variable which receives a pointer to a buffer containing\n * information about the handles.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumHandlesGeneric(\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN EnableHandleSnapshot,\n    _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n\n    // There are three ways of enumerating handles:\n    // * On Windows 8 and later, NtQueryInformationProcess with ProcessHandleInformation is the most efficient method.\n    // * On Windows XP and later, NtQuerySystemInformation with SystemExtendedHandleInformation.\n    // * Otherwise, NtQuerySystemInformation with SystemHandleInformation can be used.\n\n    if ((KsiLevel() >= KphLevelMed) && ProcessHandle)\n    {\n        PKPH_PROCESS_HANDLE_INFORMATION handles;\n        PSYSTEM_HANDLE_INFORMATION_EX convertedHandles;\n        ULONG i;\n\n        // Enumerate handles using KSystemInformer. Unlike with NtQuerySystemInformation,\n        // this only enumerates handles for a single process and saves a lot of processing.\n\n        if (NT_SUCCESS(status = KsiEnumerateProcessHandles(ProcessHandle, &handles)))\n        {\n            convertedHandles = PhAllocate(UFIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles[handles->HandleCount]));\n            convertedHandles->NumberOfHandles = handles->HandleCount;\n\n            for (i = 0; i < handles->HandleCount; i++)\n            {\n                PKPH_PROCESS_HANDLE handle = &handles->Handles[i];\n\n                convertedHandles->Handles[i].Object = handle->Object;\n                convertedHandles->Handles[i].UniqueProcessId = ProcessId;\n                convertedHandles->Handles[i].HandleValue = handle->Handle;\n                convertedHandles->Handles[i].GrantedAccess = handle->GrantedAccess;\n                convertedHandles->Handles[i].CreatorBackTraceIndex = 0;\n                convertedHandles->Handles[i].ObjectTypeIndex = handle->ObjectTypeIndex;\n                convertedHandles->Handles[i].HandleAttributes = handle->HandleAttributes;\n            }\n\n            PhFree(handles);\n\n            *Handles = convertedHandles;\n        }\n    }\n\n    if (!NT_SUCCESS(status) && WindowsVersion >= WINDOWS_8 && ProcessHandle && EnableHandleSnapshot)\n    {\n        PPROCESS_HANDLE_SNAPSHOT_INFORMATION handles;\n        PSYSTEM_HANDLE_INFORMATION_EX convertedHandles;\n        ULONG i;\n\n        if (NT_SUCCESS(status = PhEnumProcessHandles(ProcessHandle, &handles)))\n        {\n            convertedHandles = PhAllocate(UFIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles[handles->NumberOfHandles]));\n            convertedHandles->NumberOfHandles = handles->NumberOfHandles;\n\n            for (i = 0; i < handles->NumberOfHandles; i++)\n            {\n                PPROCESS_HANDLE_TABLE_ENTRY_INFO handle = &handles->Handles[i];\n\n                convertedHandles->Handles[i].Object = NULL;\n                convertedHandles->Handles[i].UniqueProcessId = ProcessId;\n                convertedHandles->Handles[i].HandleValue = handle->HandleValue;\n                convertedHandles->Handles[i].GrantedAccess = handle->GrantedAccess;\n                convertedHandles->Handles[i].CreatorBackTraceIndex = 0;\n                convertedHandles->Handles[i].ObjectTypeIndex = (USHORT)handle->ObjectTypeIndex;\n                convertedHandles->Handles[i].HandleAttributes = handle->HandleAttributes;\n            }\n\n            PhFreePage(handles);\n\n            *Handles = convertedHandles;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PSYSTEM_HANDLE_INFORMATION_EX handles;\n        PSYSTEM_HANDLE_INFORMATION_EX convertedHandles;\n        ULONG i, numberOfHandles = 0;\n        ULONG firstIndex = 0, lastIndex = 0;\n\n        if (NT_SUCCESS(status = PhEnumHandlesEx(&handles)))\n        {\n            for (i = 0; i < handles->NumberOfHandles; i++)\n            {\n                PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handles->Handles[i];\n\n                if (handle->UniqueProcessId == ProcessId)\n                {\n                    if (numberOfHandles == 0)\n                        firstIndex = i;\n                    lastIndex = i;\n                    numberOfHandles++;\n                }\n            }\n\n            if (numberOfHandles)\n            {\n                convertedHandles = PhAllocate(UFIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles[numberOfHandles]));\n                convertedHandles->NumberOfHandles = numberOfHandles;\n\n                if (lastIndex == firstIndex + numberOfHandles - 1) // consecutive\n                {\n                    memcpy(\n                        &convertedHandles->Handles[0],\n                        &handles->Handles[firstIndex],\n                        numberOfHandles * sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)\n                        );\n\n                    *Handles = convertedHandles;\n                }\n                else\n                {\n                    ULONG j = 0;\n\n                    for (i = firstIndex; i <= lastIndex; i++)\n                    {\n                        PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handles->Handles[i];\n\n                        if (handle->UniqueProcessId == ProcessId)\n                        {\n                            memcpy(&convertedHandles->Handles[j++], handle, sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX));\n                        }\n                    }\n\n                    *Handles = convertedHandles;\n                }\n            }\n            else\n            {\n                status = STATUS_NOT_FOUND;\n            }\n\n            PhFree(handles);\n        }\n\n        return status;\n    }\n\n    return status;\n}\n\n/**\n * Enumerates all pagefiles.\n *\n * \\param Pagefiles A variable which receives a pointer to a buffer containing information about all\n * active pagefiles. You must free the structure using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumPagefiles(\n    _Out_ PVOID *Pagefiles\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x200;\n\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQuerySystemInformation(\n        SystemPageFileInformation,\n        buffer,\n        bufferSize,\n        NULL\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *Pagefiles = buffer;\n\n    return status;\n}\n\n/**\n * Enumerates all pagefiles.\n *\n * \\param Pagefiles A variable which receives a pointer to a buffer containing information about all\n * active pagefiles. You must free the structure using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumPagefilesEx(\n    _Out_ PVOID *Pagefiles\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x200;\n\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQuerySystemInformation(\n        SystemPageFileInformationEx,\n        buffer,\n        bufferSize,\n        NULL\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *Pagefiles = buffer;\n\n    return status;\n}\n\n/**\n * Enumerates pool tag information.\n *\n * \\param Buffer A pointer to a buffer that will receive the pool tag information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumPoolTagInformation(\n    _Out_ PVOID* Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG attempts;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQuerySystemInformation(\n        SystemPoolTagInformation,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n    attempts = 0;\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQuerySystemInformation(\n            SystemPoolTagInformation,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n        attempts++;\n    }\n\n    if (NT_SUCCESS(status))\n        *Buffer = buffer;\n    else\n        PhFree(buffer);\n\n    return status;\n}\n\n/**\n * Enumerates information about the big pool allocations in the system.\n *\n * \\param Buffer A pointer to a variable that receives the buffer containing the big pool information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumBigPoolInformation(\n    _Out_ PVOID* Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG attempts;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQuerySystemInformation(\n        SystemBigPoolInformation,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n    attempts = 0;\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)\n    {\n        buffer = PhReAllocate(buffer, bufferSize);\n\n        status = NtQuerySystemInformation(\n            SystemBigPoolInformation,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n        attempts++;\n    }\n\n    if (NT_SUCCESS(status))\n        *Buffer = buffer;\n    else\n        PhFree(buffer);\n\n    return status;\n}\n\ntypedef struct _PH_IS_CONTAINER_CONTEXT\n{\n    HANDLE ProcessObject;\n    BOOLEAN Found;\n} PH_IS_CONTAINER_CONTEXT, *PPH_IS_CONTAINER_CONTEXT;\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nstatic BOOLEAN NTAPI PhEnumHostComputeServiceKeyCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PVOID Information,\n    _In_ PVOID Context\n    )\n{\n    static CONST PH_STRINGREF objectNamePrefix = PH_STRINGREF_INIT(L\"Container_\");\n    PKEY_BASIC_INFORMATION basicInfo = (PKEY_BASIC_INFORMATION)Information;\n    PPH_IS_CONTAINER_CONTEXT context = (PPH_IS_CONTAINER_CONTEXT)Context;\n    PH_STRINGREF keyName;\n    PPH_STRING string;\n\n    keyName.Buffer = basicInfo->Name;\n    keyName.Length = basicInfo->NameLength;\n\n    if (string = PhConcatStringRef2(&objectNamePrefix, &keyName))\n    {\n        HANDLE objectHandle;\n\n        if (NT_SUCCESS(PhOpenJobObject(\n            &objectHandle,\n            JOB_OBJECT_QUERY,\n            NULL,\n            &string->sr\n            )))\n        {\n            PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList;\n\n            if (NT_SUCCESS(PhGetJobProcessIdList(objectHandle, &processIdList)))\n            {\n                for (ULONG i = 0; i < processIdList->NumberOfProcessIdsInList; i++)\n                {\n                    if (context->ProcessObject == (HANDLE)processIdList->ProcessIdList[i])\n                    {\n                        context->Found = TRUE;\n                        break;\n                    }\n                }\n\n                PhFree(processIdList);\n            }\n\n            // JobObjectAssociateCompletionPortInformation for process start/stop notifications (dmex)\n\n            NtClose(objectHandle);\n        }\n    }\n\n    if (context->Found)\n        return FALSE;\n\n    return TRUE;\n}\n\nNTSTATUS PhEnumHostComputeService(\n    _In_ HANDLE ProcessId\n    )\n{\n    static CONST PH_STRINGREF keyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\HostComputeService\\\\VolatileStore\\\\ComputeSystem\");\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &keyName,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PH_IS_CONTAINER_CONTEXT context;\n\n        context.ProcessObject = ProcessId;\n        context.Found = FALSE;\n\n        status = PhEnumerateKey(\n            keyHandle,\n            KeyBasicInformation,\n            PhEnumHostComputeServiceKeyCallback,\n            &context\n            );\n\n        NtClose(keyHandle);\n    }\n\n    return status;\n}\n\n_Function_class_(PH_ENUM_DIRECTORY_OBJECTS)\nstatic NTSTATUS NTAPI PhIsContainerEnumCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PPH_STRINGREF Name,\n    _In_ PPH_STRINGREF TypeName,\n    _In_ PVOID Context\n    )\n{\n    PPH_IS_CONTAINER_CONTEXT context = (PPH_IS_CONTAINER_CONTEXT)Context;\n    HANDLE objectHandle;\n\n    if (!PhEqualStringRef2(TypeName, L\"Job\", FALSE))\n        return STATUS_NAME_TOO_LONG;\n\n    if (NT_SUCCESS(PhOpenJobObject(\n        &objectHandle,\n        JOB_OBJECT_QUERY,\n        RootDirectory,\n        Name\n        )))\n    {\n        if (NT_SUCCESS(NtIsProcessInJob(\n            context->ProcessObject,\n            objectHandle\n            )))\n        {\n            context->Found = TRUE;\n            NtClose(objectHandle);\n            return STATUS_NO_MORE_ENTRIES;\n        }\n\n        NtClose(objectHandle);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Determines if a process is managed.\n *\n * \\param ProcessId The ID of the process.\n * \\param ProcessHandle A handle to the process.\n * \\param IsContainer A variable which receives a boolean indicating whether the process is managed.\n * \\return NTSTATUS Successful or errant status.\n */\n_Use_decl_annotations_\nNTSTATUS PhGetProcessIsContainer(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _Out_opt_ PBOOLEAN IsContainer\n    )\n{\n    {\n        static CONST PH_STRINGREF keyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\HostComputeService\\\\VolatileStore\\\\ComputeSystem\");\n        HANDLE keyHandle;\n        PH_IS_CONTAINER_CONTEXT context;\n\n        context.ProcessObject = NULL;\n        context.Found = FALSE;\n\n        if (NT_SUCCESS(PhOpenKey(\n            &keyHandle,\n            KEY_READ,\n            PH_KEY_LOCAL_MACHINE,\n            &keyName,\n            0\n            )))\n        {\n            PhEnumerateKey(\n                keyHandle,\n                KeyBasicInformation,\n                PhEnumHostComputeServiceKeyCallback,\n                &context\n                );\n\n            NtClose(keyHandle);\n        }\n\n        if (context.Found)\n        {\n            if (IsContainer)\n                *IsContainer = TRUE;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    {\n        static CONST PH_STRINGREF directoryName = PH_STRINGREF_INIT(L\"\\\\\");\n        NTSTATUS status;\n        HANDLE directoryHandle;\n        HANDLE processHandle;\n        PH_IS_CONTAINER_CONTEXT context;\n\n        context.ProcessObject = NULL;\n        context.Found = FALSE;\n\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            ProcessId\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhOpenDirectoryObject(\n                &directoryHandle,\n                DIRECTORY_QUERY,\n                NULL,\n                &directoryName\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                context.ProcessObject = processHandle;\n\n                status = PhEnumDirectoryObjects(\n                    directoryHandle,\n                    PhIsContainerEnumCallback,\n                    NULL\n                    );\n\n                NtClose(directoryHandle);\n            }\n\n            NtClose(processHandle);\n        }\n\n        if (context.Found)\n        {\n            if (IsContainer)\n                *IsContainer = TRUE;\n            return STATUS_SUCCESS;\n        }\n\n        if (IsContainer)\n            *IsContainer = FALSE;\n        return status;\n    }\n}\n\n/**\n * Determines if a process is managed.\n *\n * \\param ProcessId The ID of the process.\n * \\param IsDotNet A variable which receives a boolean indicating whether the process is managed.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessIsDotNet(\n    _In_ HANDLE ProcessId,\n    _Out_ PBOOLEAN IsDotNet\n    )\n{\n    return PhGetProcessIsDotNetEx(ProcessId, NULL, 0, IsDotNet, NULL);\n}\n\n_Function_class_(PH_ENUM_PROCESS_MODULES_CALLBACK)\nstatic BOOLEAN NTAPI PhpIsDotNetEnumProcessModulesCallback(\n    _In_ PLDR_DATA_TABLE_ENTRY Module,\n    _In_ PVOID Context\n    )\n{\n    static CONST PH_STRINGREF clrString = PH_STRINGREF_INIT(L\"clr.dll\");\n    static CONST PH_STRINGREF clrcoreString = PH_STRINGREF_INIT(L\"coreclr.dll\");\n    static CONST PH_STRINGREF mscorwksString = PH_STRINGREF_INIT(L\"mscorwks.dll\");\n    static CONST PH_STRINGREF mscorsvrString = PH_STRINGREF_INIT(L\"mscorsvr.dll\");\n    static CONST PH_STRINGREF mscorlibString = PH_STRINGREF_INIT(L\"mscorlib.dll\");\n    static CONST PH_STRINGREF mscorlibNiString = PH_STRINGREF_INIT(L\"mscorlib.ni.dll\");\n    static CONST PH_STRINGREF frameworkString = PH_STRINGREF_INIT(L\"\\\\Microsoft.NET\\\\Framework\\\\\");\n    static CONST PH_STRINGREF framework64String = PH_STRINGREF_INIT(L\"\\\\Microsoft.NET\\\\Framework64\\\\\");\n    PH_STRINGREF baseDllName;\n\n    PhUnicodeStringToStringRef(&Module->BaseDllName, &baseDllName);\n\n    if (\n        PhEqualStringRef(&baseDllName, &clrString, TRUE) ||\n        PhEqualStringRef(&baseDllName, &mscorwksString, TRUE) ||\n        PhEqualStringRef(&baseDllName, &mscorsvrString, TRUE)\n        )\n    {\n        PH_STRINGREF fileName;\n        PH_STRINGREF systemRoot;\n        PCPH_STRINGREF frameworkPart;\n\n#ifdef _WIN64\n        if (*(PULONG)Context & PH_CLR_PROCESS_IS_WOW64)\n        {\n#endif\n            frameworkPart = &frameworkString;\n#ifdef _WIN64\n        }\n        else\n        {\n            frameworkPart = &framework64String;\n        }\n#endif\n\n        PhUnicodeStringToStringRef(&Module->FullDllName, &fileName);\n        PhGetSystemRoot(&systemRoot);\n\n        if (PhStartsWithStringRef(&fileName, &systemRoot, TRUE))\n        {\n            fileName.Buffer = PTR_ADD_OFFSET(fileName.Buffer, systemRoot.Length);\n            fileName.Length -= systemRoot.Length;\n\n            if (PhStartsWithStringRef(&fileName, frameworkPart, TRUE))\n            {\n                fileName.Buffer = PTR_ADD_OFFSET(fileName.Buffer, frameworkPart->Length);\n                fileName.Length -= frameworkPart->Length;\n\n                if (fileName.Length >= 4 * sizeof(WCHAR)) // vx.x\n                {\n                    if (fileName.Buffer[1] == L'1')\n                    {\n                        if (fileName.Buffer[3] == L'0')\n                            *(PULONG)Context |= PH_CLR_VERSION_1_0;\n                        else if (fileName.Buffer[3] == L'1')\n                            *(PULONG)Context |= PH_CLR_VERSION_1_1;\n                    }\n                    else if (fileName.Buffer[1] == L'2')\n                    {\n                        *(PULONG)Context |= PH_CLR_VERSION_2_0;\n                    }\n                    else if (fileName.Buffer[1] >= L'4' && fileName.Buffer[1] <= L'9')\n                    {\n                        *(PULONG)Context |= PH_CLR_VERSION_4_ABOVE;\n                    }\n                }\n            }\n        }\n    }\n    else if (\n        PhEqualStringRef(&baseDllName, &mscorlibString, TRUE) ||\n        PhEqualStringRef(&baseDllName, &mscorlibNiString, TRUE)\n        )\n    {\n        *(PULONG)Context |= PH_CLR_MSCORLIB_PRESENT;\n    }\n    else if (PhEqualStringRef(&baseDllName, &clrcoreString, TRUE))\n    {\n        *(PULONG)Context |= PH_CLR_CORELIB_PRESENT;\n    }\n\n    return TRUE;\n}\n\ntypedef struct _PHP_PIPE_NAME_HASH\n{\n    ULONG NameHash;\n    ULONG Found;\n} PHP_PIPE_NAME_HASH, *PPHP_PIPE_NAME_HASH;\n\n_Function_class_(PH_ENUM_DIRECTORY_FILE)\nstatic BOOLEAN NTAPI PhpDotNetCorePipeHashCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PFILE_DIRECTORY_INFORMATION Information,\n    _In_ PVOID Context\n    )\n{\n    PPHP_PIPE_NAME_HASH context = Context;\n    PH_STRINGREF objectName;\n\n    objectName.Length = Information->FileNameLength;\n    objectName.Buffer = Information->FileName;\n\n    if (PhHashStringRefEx(&objectName, FALSE, PH_STRING_HASH_X65599) == context->NameHash)\n    {\n        context->Found = TRUE;\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Determines if a process is managed.\n *\n * \\param ProcessId The ID of the process.\n * \\param ProcessHandle An optional handle to the process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param InFlags A combination of flags.\n * \\li \\c PH_CLR_USE_SECTION_CHECK Checks for the existence of related section objects to determine\n * whether the process is managed.\n * \\li \\c PH_CLR_NO_WOW64_CHECK Instead of a separate query, uses the presence of the\n * \\c PH_CLR_KNOWN_IS_WOW64 flag to determine whether the process is running under WOW64.\n * \\li \\c PH_CLR_KNOWN_IS_WOW64 When \\c PH_CLR_NO_WOW64_CHECK is specified, indicates that the\n * process is managed.\n * \\param IsDotNet A variable which receives a boolean indicating whether the process is managed.\n * \\param Flags A variable which receives additional flags.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessIsDotNetEx(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ULONG InFlags,\n    _Out_opt_ PBOOLEAN IsDotNet,\n    _Out_opt_ PULONG Flags\n    )\n{\n    if (InFlags & PH_CLR_USE_SECTION_CHECK)\n    {\n        NTSTATUS status;\n        HANDLE sectionHandle;\n        SIZE_T returnLength;\n        PH_STRINGREF objectName;\n        PH_FORMAT format[2];\n        WCHAR formatBuffer[0x80];\n\n        // Most .NET processes have a handle open to a section named\n        // \\BaseNamedObjects\\Cor_Private_IPCBlock(_v4)_<ProcessId>. This is the same object used by\n        // the ICorPublish::GetProcess function. Instead of calling that function, we simply check\n        // for the existence of that section object. This means:\n        // * Better performance.\n        // * No need for admin rights to get .NET status of processes owned by other users.\n\n        // Version 4 section object\n\n        PhInitFormatS(&format[0], L\"\\\\BaseNamedObjects\\\\Cor_Private_IPCBlock_v4_\");\n        PhInitFormatU(&format[1], HandleToUlong(ProcessId));\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), &returnLength))\n        {\n            objectName.Length = returnLength - sizeof(UNICODE_NULL);\n            objectName.Buffer = formatBuffer;\n        }\n        else\n        {\n            return STATUS_NO_MEMORY;\n        }\n\n        status = PhOpenSection(\n            &sectionHandle,\n            SECTION_QUERY,\n            NULL,\n            &objectName\n            );\n\n        if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED)\n        {\n            if (NT_SUCCESS(status))\n                NtClose(sectionHandle);\n\n            if (IsDotNet)\n                *IsDotNet = TRUE;\n\n            if (Flags)\n                *Flags = PH_CLR_VERSION_4_ABOVE;\n\n            return STATUS_SUCCESS;\n        }\n\n        // Version 2 section object\n\n        PhInitFormatS(&format[0], L\"\\\\BaseNamedObjects\\\\Cor_Private_IPCBlock_\");\n        PhInitFormatU(&format[1], HandleToUlong(ProcessId));\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), &returnLength))\n        {\n            objectName.Length = returnLength - sizeof(UNICODE_NULL);\n            objectName.Buffer = formatBuffer;\n        }\n        else\n        {\n            return STATUS_NO_MEMORY;\n        }\n\n        status = PhOpenSection(\n            &sectionHandle,\n            SECTION_QUERY,\n            NULL,\n            &objectName\n            );\n\n        if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED)\n        {\n            if (NT_SUCCESS(status))\n                NtClose(sectionHandle);\n\n            if (IsDotNet)\n                *IsDotNet = TRUE;\n\n            if (Flags)\n                *Flags = PH_CLR_VERSION_2_0;\n\n            return STATUS_SUCCESS;\n        }\n\n        // .NET Core 3.0 and above objects\n\n        PhInitFormatS(&format[0], L\"dotnet-diagnostic-\");\n        PhInitFormatU(&format[1], HandleToUlong(ProcessId));\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), &returnLength))\n        {\n            PHP_PIPE_NAME_HASH context;\n\n            objectName.Length = returnLength - sizeof(UNICODE_NULL);\n            objectName.Buffer = formatBuffer;\n            context.NameHash = PhHashStringRefEx(&objectName, FALSE, PH_STRING_HASH_X65599);\n            context.Found = FALSE;\n\n            status = PhEnumDirectoryNamedPipe(\n                &objectName,\n                PhpDotNetCorePipeHashCallback,\n                &context\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                if (!context.Found)\n                {\n                    status = STATUS_OBJECT_NAME_NOT_FOUND;\n                }\n            }\n\n            // NOTE: NtQueryAttributesFile and other query functions connect to the pipe and should be avoided. (dmex)\n            //\n            //FILE_BASIC_INFORMATION fileInfo;\n            //\n            //objectNameSr.Length = returnLength - sizeof(UNICODE_NULL);\n            //objectNameSr.Buffer = formatBuffer;\n            //\n            //PhStringRefToUnicodeString(&objectNameSr, &objectName);\n            //InitializeObjectAttributes(\n            //    &objectAttributes,\n            //    &objectName,\n            //    OBJ_CASE_INSENSITIVE,\n            //    NULL,\n            //    NULL\n            //    );\n            //\n            //status = NtQueryAttributesFile(&objectAttributes, &fileInfo)\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            if (IsDotNet)\n                *IsDotNet = TRUE;\n            if (Flags)\n                *Flags = PH_CLR_VERSION_4_ABOVE | PH_CLR_CORE_3_0_ABOVE;\n\n            return STATUS_SUCCESS;\n        }\n\n        return status;\n    }\n    else\n    {\n        NTSTATUS status;\n        HANDLE processHandle = NULL;\n        ULONG flags = 0;\n#ifdef _WIN64\n        BOOLEAN isWow64;\n#endif\n\n        if (!ProcessHandle)\n        {\n            if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessId)))\n                return status;\n\n            ProcessHandle = processHandle;\n        }\n\n#ifdef _WIN64\n        if (InFlags & PH_CLR_NO_WOW64_CHECK)\n        {\n            isWow64 = !!(InFlags & PH_CLR_KNOWN_IS_WOW64);\n        }\n        else\n        {\n            isWow64 = FALSE;\n            PhGetProcessIsWow64(ProcessHandle, &isWow64);\n        }\n\n        if (isWow64)\n        {\n            flags |= PH_CLR_PROCESS_IS_WOW64;\n            status = PhEnumProcessModules32(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags);\n        }\n        else\n        {\n#endif\n            status = PhEnumProcessModules(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags);\n#ifdef _WIN64\n        }\n#endif\n\n        if (processHandle)\n            NtClose(processHandle);\n\n        if (IsDotNet)\n            *IsDotNet = (flags & PH_CLR_VERSION_MASK) && (flags & (PH_CLR_MSCORLIB_PRESENT | PH_CLR_CORELIB_PRESENT));\n\n        if (Flags)\n            *Flags = flags;\n\n        return status;\n    }\n}\n\n/*\n * Opens a directory object.\n *\n * \\param DirectoryHandle A variable which receives a handle to the directory object.\n * \\param DesiredAccess The desired access to the directory object.\n * \\param RootDirectory A handle to the root directory of the object.\n * \\param ObjectName The name of the directory object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenDirectoryObject(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = NtOpenDirectoryObject(\n        DirectoryHandle,\n        DesiredAccess,\n        &objectAttributes\n        );\n\n    return status;\n}\n\n/**\n * Enumerates the objects in a directory object.\n *\n * \\param DirectoryHandle A handle to a directory. The handle must have DIRECTORY_QUERY access.\n * \\param Callback A callback function which is executed for each object.\n * \\param Context A user-defined value to pass to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumDirectoryObjects(\n    _In_ HANDLE DirectoryHandle,\n    _In_ PPH_ENUM_DIRECTORY_OBJECTS Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    ULONG context = 0;\n    BOOLEAN firstTime = TRUE;\n    ULONG bufferSize;\n    POBJECT_DIRECTORY_INFORMATION buffer;\n    ULONG i;\n\n    bufferSize = 0x200;\n    buffer = PhAllocateStack(bufferSize);\n    if (!buffer) return STATUS_NO_MEMORY;\n\n    while (TRUE)\n    {\n        // Get a batch of entries.\n\n        while ((status = NtQueryDirectoryObject(\n            DirectoryHandle,\n            buffer,\n            bufferSize,\n            FALSE,\n            firstTime,\n            &context,\n            NULL\n            )) == STATUS_MORE_ENTRIES)\n        {\n            // Check if we have at least one entry. If not, we'll double the buffer size and try\n            // again.\n            if (buffer[0].Name.Buffer)\n                break;\n\n            // Make sure we don't use too much memory.\n            if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            {\n                PhFreeStack(buffer);\n                return STATUS_INSUFFICIENT_RESOURCES;\n            }\n\n            PhFreeStack(buffer);\n            bufferSize *= 2;\n            buffer = PhAllocateStack(bufferSize);\n            if (!buffer) return STATUS_NO_MEMORY;\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            if (status == STATUS_NO_MORE_ENTRIES)\n                status = STATUS_SUCCESS;\n\n            PhFreeStack(buffer);\n            return status;\n        }\n\n        // Read the batch and execute the callback function for each object.\n\n        i = 0;\n\n        while (TRUE)\n        {\n            POBJECT_DIRECTORY_INFORMATION info;\n            PH_STRINGREF name;\n            PH_STRINGREF typeName;\n\n            info = &buffer[i];\n\n            if (!info->Name.Buffer)\n                break;\n\n            PhUnicodeStringToStringRef(&info->Name, &name);\n            PhUnicodeStringToStringRef(&info->TypeName, &typeName);\n\n            status = Callback(\n                DirectoryHandle,\n                &name,\n                &typeName,\n                Context\n                );\n\n            if (status == STATUS_NO_MORE_ENTRIES)\n                break;\n\n            i++;\n        }\n\n        if (status == STATUS_NO_MORE_ENTRIES)\n            break;\n\n        firstTime = FALSE;\n    }\n\n    if (status == STATUS_NO_MORE_ENTRIES)\n        status = STATUS_SUCCESS;\n\n    PhFreeStack(buffer);\n\n    return status;\n}\n\n/**\n * Creates a symbolic link object.\n *\n * \\param LinkHandle Pointer to a variable that receives the handle to the symbolic link object.\n * \\param DesiredAccess Specifies the desired access rights for the symbolic link object.\n * \\param RootDirectory Optional handle to the root directory for the symbolic link object name.\n * \\param FileName Pointer to a string that specifies the target file or object to which the symbolic link points.\n * \\param LinkName Pointer to a string that specifies the name of the symbolic link object to be created.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateSymbolicLinkObject(\n    _Out_ PHANDLE LinkHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PCPH_STRINGREF LinkName\n    )\n{\n    NTSTATUS status;\n    HANDLE linkHandle;\n    OBJECT_ATTRIBUTES objectAttributes;\n    UNICODE_STRING objectName;\n    UNICODE_STRING objectTarget;\n\n    if (!PhStringRefToUnicodeString(FileName, &objectName))\n        return STATUS_NAME_TOO_LONG;\n    if (!PhStringRefToUnicodeString(LinkName, &objectTarget))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = NtCreateSymbolicLinkObject(\n        &linkHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &objectTarget\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *LinkHandle = linkHandle;\n    }\n\n    return status;\n}\n\n/**\n * Queries the target of a symbolic link object.\n *\n * \\param LinkTarget Pointer to a variable that receives the target of the symbolic link as a PPH_STRING.\n * \\param RootDirectory Optional handle to the root directory for the object name. Can be NULL.\n * \\param ObjectName Pointer to a string reference that specifies the name of the symbolic link object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQuerySymbolicLinkObject(\n    _Out_ PPH_STRING* LinkTarget,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName\n    )\n{\n    NTSTATUS status;\n    HANDLE linkHandle;\n    OBJECT_ATTRIBUTES objectAttributes;\n    UNICODE_STRING objectName;\n    UNICODE_STRING targetName;\n    ULONG returnLength = 0;\n    WCHAR stackBuffer[DOS_MAX_PATH_LENGTH];\n    ULONG bufferLength = sizeof(stackBuffer);\n    PWCHAR buffer = stackBuffer;\n\n    if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = NtOpenSymbolicLinkObject(\n        &linkHandle,\n        SYMBOLIC_LINK_QUERY,\n        &objectAttributes\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    RtlInitEmptyUnicodeString(&targetName, buffer, (USHORT)bufferLength);\n\n    status = NtQuerySymbolicLinkObject(\n        linkHandle,\n        &targetName,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        bufferLength = returnLength;\n        buffer = PhAllocate(bufferLength);\n\n        RtlInitEmptyUnicodeString(&targetName, buffer, (USHORT)bufferLength);\n\n        status = NtQuerySymbolicLinkObject(\n            linkHandle,\n            &targetName,\n            &returnLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *LinkTarget = PhCreateStringFromUnicodeString(&targetName);\n    }\n\n    if (buffer != stackBuffer)\n    {\n        PhFree(buffer);\n    }\n\n    NtClose(linkHandle);\n\n    return status;\n}\n\n/**\n * Initializes the device prefixes module.\n */\nVOID PhpInitializeDevicePrefixes(\n    VOID\n    )\n{\n    ULONG i;\n    PWCHAR buffer;\n\n    // Allocate one buffer for all 26 prefixes to reduce overhead.\n    buffer = PhAllocate(PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR) * 26);\n\n    for (i = 0; i < 26; i++)\n    {\n        PhDevicePrefixes[i].Length = 0;\n        PhDevicePrefixes[i].MaximumLength = PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR);\n        PhDevicePrefixes[i].Buffer = buffer;\n        buffer = PTR_ADD_OFFSET(buffer, PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR));\n    }\n}\n\nVOID PhUpdateMupDevicePrefixes(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF orderKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Control\\\\NetworkProvider\\\\Order\");\n    static CONST PH_STRINGREF servicesStringPart = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Services\");\n    static CONST PH_STRINGREF networkProviderStringPart = PH_STRINGREF_INIT(L\"\\\\NetworkProvider\");\n\n    HANDLE orderKeyHandle;\n    PPH_STRING providerOrder = NULL;\n    ULONG i;\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF part;\n\n    // The provider names are stored in the ProviderOrder value in this key:\n    // HKLM\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order\n    // Each name can then be looked up, its device name in the DeviceName value in:\n    // HKLM\\System\\CurrentControlSet\\Services\\<ProviderName>\\NetworkProvider\n\n    // Note that we assume the providers only claim their device name. Some providers such as DFS\n    // claim an extra part, and are not resolved correctly here.\n\n    if (NT_SUCCESS(PhOpenKey(\n        &orderKeyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &orderKeyName,\n        0\n        )))\n    {\n        providerOrder = PhQueryRegistryStringZ(orderKeyHandle, L\"ProviderOrder\");\n        NtClose(orderKeyHandle);\n    }\n\n    if (!providerOrder)\n        return;\n\n    PhAcquireQueuedLockExclusive(&PhDeviceMupPrefixesLock);\n\n    for (i = 0; i < PhDeviceMupPrefixesCount; i++)\n    {\n        PhDereferenceObject(PhDeviceMupPrefixes[i]);\n        PhDeviceMupPrefixes[i] = NULL;\n    }\n\n    PhDeviceMupPrefixesCount = 0;\n\n    PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L\"\\\\Device\\\\Mup\");\n\n    // DFS claims an extra part of file names, which we don't handle.\n    // PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L\"\\\\Device\\\\DfsClient\");\n\n    remainingPart = providerOrder->sr;\n\n    while (remainingPart.Length != 0)\n    {\n        PPH_STRING serviceKeyName;\n        HANDLE networkProviderKeyHandle;\n        PPH_STRING deviceName;\n\n        if (PhDeviceMupPrefixesCount == PH_DEVICE_MUP_PREFIX_MAX_COUNT)\n            break;\n\n        PhSplitStringRefAtChar(&remainingPart, L',', &part, &remainingPart);\n\n        if (part.Length != 0)\n        {\n            serviceKeyName = PhConcatStringRef4(\n                &servicesStringPart,\n                &PhNtPathSeparatorString,\n                &part,\n                &networkProviderStringPart\n                );\n\n            if (NT_SUCCESS(PhOpenKey(\n                &networkProviderKeyHandle,\n                KEY_READ,\n                PH_KEY_LOCAL_MACHINE,\n                &serviceKeyName->sr,\n                0\n                )))\n            {\n                if (deviceName = PhQueryRegistryStringZ(networkProviderKeyHandle, L\"DeviceName\"))\n                {\n                    PhDeviceMupPrefixes[PhDeviceMupPrefixesCount] = deviceName;\n                    PhDeviceMupPrefixesCount++;\n                }\n\n                NtClose(networkProviderKeyHandle);\n            }\n\n            PhDereferenceObject(serviceKeyName);\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&PhDeviceMupPrefixesLock);\n\n    PhDereferenceObject(providerOrder);\n}\n\n/**\n * Updates the DOS device names array.\n */\nVOID PhUpdateDosDevicePrefixes(\n    VOID\n    )\n{\n    WCHAR deviceNameBuffer[7] = L\"\\\\??\\\\ :\";\n    ULONG deviceMap = 0;\n\n    PhGetProcessDeviceMap(NtCurrentProcess(), &deviceMap);\n\n    PhAcquireQueuedLockExclusive(&PhDevicePrefixesLock);\n\n    for (ULONG i = 0; i < 0x1A; i++)\n    {\n        HANDLE linkHandle;\n        OBJECT_ATTRIBUTES objectAttributes;\n        UNICODE_STRING deviceName;\n\n        if (deviceMap)\n        {\n            if (!(deviceMap & (0x1 << i)))\n            {\n                PhDevicePrefixes[i].Length = 0;\n                continue;\n            }\n        }\n\n        deviceNameBuffer[4] = (WCHAR)('A' + i);\n        deviceName.Buffer = deviceNameBuffer;\n        deviceName.Length = sizeof(deviceNameBuffer) - sizeof(UNICODE_NULL);\n        deviceName.MaximumLength = deviceName.Length + sizeof(UNICODE_NULL);\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            &deviceName,\n            OBJ_CASE_INSENSITIVE,\n            NULL,\n            NULL\n            );\n\n        if (NT_SUCCESS(NtOpenSymbolicLinkObject(\n            &linkHandle,\n            SYMBOLIC_LINK_QUERY,\n            &objectAttributes\n            )))\n        {\n            if (!NT_SUCCESS(NtQuerySymbolicLinkObject(\n                linkHandle,\n                &PhDevicePrefixes[i],\n                NULL\n                )))\n            {\n                PhDevicePrefixes[i].Length = 0;\n            }\n\n            NtClose(linkHandle);\n        }\n        else\n        {\n            PhDevicePrefixes[i].Length = 0;\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&PhDevicePrefixesLock);\n}\n\n// rev from FindFirstVolumeW (dmex)\n/**\n * Retrieves the mount points of volumes.\n *\n * \\param DeviceHandle A handle to the MountPointManager.\n * \\param MountPoints An array of mounts.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetVolumeMountPoints(\n    _In_ HANDLE DeviceHandle,\n    _Out_ PMOUNTMGR_MOUNT_POINTS* MountPoints\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    MOUNTMGR_MOUNT_POINT inputBuffer = { 0 };\n    PMOUNTMGR_MOUNT_POINTS outputBuffer;\n    ULONG inputBufferLength = sizeof(inputBuffer);\n    ULONG outputBufferLength;\n    ULONG attempts = 16;\n\n    outputBufferLength = 0x800;\n    outputBuffer = PhAllocate(outputBufferLength);\n\n    do\n    {\n        status = NtDeviceIoControlFile(\n            DeviceHandle,\n            NULL,\n            NULL,\n            NULL,\n            &isb,\n            IOCTL_MOUNTMGR_QUERY_POINTS,\n            &inputBuffer,\n            inputBufferLength,\n            outputBuffer,\n            outputBufferLength\n            );\n\n        if (NT_SUCCESS(status))\n            break;\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            outputBufferLength = outputBuffer->Size;\n            PhFree(outputBuffer);\n\n            if (outputBufferLength > PH_LARGE_BUFFER_SIZE)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            outputBuffer = PhAllocate(outputBufferLength);\n        }\n        else\n        {\n            PhFree(outputBuffer);\n            return status;\n        }\n    } while (--attempts);\n\n    if (NT_SUCCESS(status))\n    {\n        *MountPoints = outputBuffer;\n    }\n    else\n    {\n        PhFree(outputBuffer);\n    }\n\n    return status;\n}\n\n// rev from GetVolumePathNamesForVolumeNameW (dmex)\n/**\n * \\brief Retrieves a list of drive letters and mounted folder paths for the specified volume.\n *\n * \\param DeviceHandle A handle to the MountPointManager.\n * \\param VolumeName A volume GUID path for the volume.\n * \\param VolumePathNames A pointer to a buffer that receives the list of drive letters and mounted folder paths.\n * \\a The list is an array of null-terminated strings terminated by an additional NULL character.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetVolumePathNamesForVolumeName(\n    _In_ HANDLE DeviceHandle,\n    _In_ PCPH_STRINGREF VolumeName,\n    _Out_ PMOUNTMGR_VOLUME_PATHS* VolumePathNames\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PMOUNTMGR_TARGET_NAME inputBuffer;\n    PMOUNTMGR_VOLUME_PATHS outputBuffer;\n    ULONG inputBufferLength;\n    ULONG outputBufferLength;\n    ULONG attempts = 16;\n\n    inputBufferLength = UFIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName[VolumeName->Length]) + sizeof(UNICODE_NULL);\n    inputBuffer = PhAllocateStack(inputBufferLength); // Volume{guid}, CM_Get_Device_Interface_List, SymbolicLinks, [??]\n    if (!inputBuffer) return STATUS_NO_MEMORY;\n    inputBuffer->DeviceNameLength = (USHORT)VolumeName->Length;\n    RtlCopyMemory(inputBuffer->DeviceName, VolumeName->Buffer, VolumeName->Length);\n\n    outputBufferLength = UFIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz[DOS_MAX_PATH_LENGTH]) + sizeof(UNICODE_NULL);\n    outputBuffer = PhAllocate(outputBufferLength);\n\n    do\n    {\n        status = NtDeviceIoControlFile(\n            DeviceHandle,\n            NULL,\n            NULL,\n            NULL,\n            &isb,\n            IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS,\n            inputBuffer,\n            inputBufferLength,\n            outputBuffer,\n            outputBufferLength\n            );\n\n        if (NT_SUCCESS(status))\n            break;\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            outputBufferLength = (outputBuffer->MultiSzLength * sizeof(WCHAR)) + sizeof(UNICODE_NULL);\n            PhFree(outputBuffer);\n            outputBuffer = PhAllocate(outputBufferLength);\n        }\n        else\n        {\n            PhFreeStack(inputBuffer);\n            PhFree(outputBuffer);\n            return status;\n        }\n    } while (--attempts);\n\n    if (NT_SUCCESS(status))\n    {\n        *VolumePathNames = outputBuffer;\n    }\n    else\n    {\n        PhFree(outputBuffer);\n    }\n\n    PhFreeStack(inputBuffer);\n\n    return status;\n}\n\n/**\n * Flush file caches on all volumes.\n *\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhFlushVolumeCache(\n    VOID\n    )\n{\n    NTSTATUS status;\n    HANDLE deviceHandle;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n    PMOUNTMGR_MOUNT_POINTS objectMountPoints;\n\n    RtlInitUnicodeString(&objectName, MOUNTMGR_DEVICE_NAME);\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &deviceHandle,\n        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        &objectAttributes,\n        &ioStatusBlock,\n        NULL,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetVolumeMountPoints(\n        deviceHandle,\n        &objectMountPoints\n        );\n\n    NtClose(deviceHandle);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    for (ULONG i = 0; i < objectMountPoints->NumberOfMountPoints; i++)\n    {\n        PMOUNTMGR_MOUNT_POINT mountPoint = &objectMountPoints->MountPoints[i];\n        objectName.Length = mountPoint->SymbolicLinkNameLength;\n        objectName.MaximumLength = mountPoint->SymbolicLinkNameLength + sizeof(UNICODE_NULL);\n        objectName.Buffer = PTR_ADD_OFFSET(objectMountPoints, mountPoint->SymbolicLinkNameOffset);\n\n        if (MOUNTMGR_IS_VOLUME_NAME(&objectName)) // \\\\??\\\\Volume{1111-2222}\n        {\n            HANDLE volumeHandle;\n\n            InitializeObjectAttributes(\n                &objectAttributes,\n                &objectName,\n                OBJ_CASE_INSENSITIVE,\n                NULL,\n                NULL\n                );\n\n            status = NtCreateFile(\n                &volumeHandle,\n                FILE_WRITE_DATA | SYNCHRONIZE,\n                &objectAttributes,\n                &ioStatusBlock,\n                NULL,\n                FILE_ATTRIBUTE_NORMAL,\n                FILE_SHARE_READ | FILE_SHARE_WRITE,\n                FILE_OPEN,\n                FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n                NULL,\n                0\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                //if (WindowsVersion >= WINDOWS_8)\n                //{\n                //    status = NtFlushBuffersFileEx(volumeHandle, 0, 0, 0, &ioStatusBlock);\n                //}\n                //else\n                {\n                    status = NtFlushBuffersFile(volumeHandle, &ioStatusBlock);\n                }\n\n                NtClose(volumeHandle);\n            }\n        }\n    }\n\n    PhFree(objectMountPoints);\n\nCleanupExit:\n\n    return status;\n}\n\n//NTSTATUS PhUpdateDosDeviceMountPrefixes(\n//    VOID\n//    )\n//{\n//    NTSTATUS status;\n//    HANDLE deviceHandle;\n//    UNICODE_STRING objectName;\n//    OBJECT_ATTRIBUTES objectAttributes;\n//    IO_STATUS_BLOCK ioStatusBlock;\n//    PMOUNTMGR_MOUNT_POINTS deviceMountPoints;\n//\n//    RtlInitUnicodeString(&objectName, MOUNTMGR_DEVICE_NAME);\n//    InitializeObjectAttributes(\n//        &objectAttributes,\n//        &objectName,\n//        OBJ_CASE_INSENSITIVE,\n//        NULL,\n//        NULL\n//        );\n//\n//    status = NtCreateFile(\n//        &deviceHandle,\n//        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n//        &objectAttributes,\n//        &ioStatusBlock,\n//        NULL,\n//        FILE_ATTRIBUTE_NORMAL,\n//        FILE_SHARE_READ | FILE_SHARE_WRITE,\n//        FILE_OPEN,\n//        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n//        NULL,\n//        0\n//        );\n//\n//    if (!NT_SUCCESS(status))\n//        return status;\n//\n//    status = PhGetVolumeMountPoints(\n//        deviceHandle,\n//        &deviceMountPoints\n//        );\n//\n//    if (!NT_SUCCESS(status))\n//        goto CleanupExit;\n//\n//    for (ULONG i = 0; i < RTL_NUMBER_OF(PhDevicePrefixes); i++)\n//    {\n//        PhDevicePrefixes[i].Length = 0;\n//    }\n//\n//    for (ULONG i = 0; i < deviceMountPoints->NumberOfMountPoints; i++)\n//    {\n//        PMOUNTMGR_MOUNT_POINT entry = &deviceMountPoints->MountPoints[i];\n//        UNICODE_STRING linkName =\n//        {\n//            entry->SymbolicLinkNameLength,\n//            entry->SymbolicLinkNameLength + sizeof(UNICODE_NULL),\n//            PTR_ADD_OFFSET(deviceMountPoints, entry->SymbolicLinkNameOffset)\n//        };\n//        UNICODE_STRING deviceName =\n//        {\n//            entry->DeviceNameLength,\n//            entry->DeviceNameLength + sizeof(UNICODE_NULL),\n//            PTR_ADD_OFFSET(deviceMountPoints, entry->DeviceNameOffset)\n//        };\n//\n//        if (MOUNTMGR_IS_DRIVE_LETTER(&linkName)) // \\\\DosDevices\\\\C:\n//        {\n//            USHORT index = (USHORT)(linkName.Buffer[12] - L'A');\n//\n//            if (index >= RTL_NUMBER_OF(PhDevicePrefixes))\n//                continue;\n//            if (deviceName.Length >= PhDevicePrefixes[index].MaximumLength - sizeof(UNICODE_NULL))\n//                continue;\n//\n//            PhDevicePrefixes[index].Length = deviceName.Length;\n//            memcpy_s(\n//                PhDevicePrefixes[index].Buffer,\n//                PhDevicePrefixes[index].MaximumLength,\n//                deviceName.Buffer,\n//                deviceName.Length\n//                );\n//        }\n//\n//        //if (MOUNTMGR_IS_VOLUME_NAME(&linkName)) // \\\\??\\\\Volume{1111-2222}\n//        //{\n//        //    PH_STRINGREF volumeLinkName;\n//        //    PMOUNTMGR_VOLUME_PATHS volumePaths;\n//        //\n//        //    PhUnicodeStringToStringRef(&linkName, &volumeLinkName);\n//        //\n//        //    if (NT_SUCCESS(PhGetVolumePathNamesForVolumeName(deviceHandle, &volumeLinkName, &volumePaths)))\n//        //    {\n//        //        for (PWSTR path = volumePaths->MultiSz; *path; path += PhCountStringZ(path) + 1)\n//        //        {\n//        //            dprintf(\"%S\\n\", path); // C:\\\\Mounted\\\\Folders\n//        //        }\n//        //    }\n//        //}\n//    }\n//\n//    PhFree(deviceMountPoints);\n//\n//CleanupExit:\n//    NtClose(deviceHandle);\n//\n//    return status;\n//}\n\n/**\n * Resolves the mount prefix for a given file name.\n *\n * \\param Name A pointer to a constant PPH_STRINGREF structure that specifies the file name to resolve.\n * \\param NativeFileName A BOOLEAN value indicating whether the file name is in native NT format (TRUE) or DOS/Win32 format (FALSE).\n * \\return A pointer to a PPH_STRING structure containing the resolved mount prefix, or NULL if the resolution fails.\n */\nPPH_STRING PhResolveMountPrefix(\n    _In_ PCPH_STRINGREF Name,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    NTSTATUS status;\n    HANDLE deviceHandle;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n    PMOUNTMGR_MOUNT_POINTS mountPoints;\n    PPH_STRING newName = NULL;\n\n    RtlInitUnicodeString(&objectName, MOUNTMGR_DEVICE_NAME);\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &deviceHandle,\n        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        &objectAttributes,\n        &ioStatusBlock,\n        NULL,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    status = PhGetVolumeMountPoints(\n        deviceHandle,\n        &mountPoints\n        );\n\n    NtClose(deviceHandle);\n\n    if (!NT_SUCCESS(status))\n    {\n        return NULL;\n    }\n\n    for (ULONG i = 0; i < mountPoints->NumberOfMountPoints; i++)\n    {\n        PMOUNTMGR_MOUNT_POINT entry = &mountPoints->MountPoints[i];\n        const PH_STRINGREF linkPrefix = {\n            entry->SymbolicLinkNameLength,\n            RTL_PTR_ADD(mountPoints, entry->SymbolicLinkNameOffset)\n        };\n        const PH_STRINGREF devicePrefix = {\n            entry->DeviceNameLength,\n            RTL_PTR_ADD(mountPoints, entry->DeviceNameOffset)\n        };\n\n        if (NativeFileName)\n        {\n            if (PhStartsWithStringRef(Name, &devicePrefix, TRUE))\n            {\n                if (PATH_IS_WIN32_DOSDEVICES_PREFIX(&linkPrefix) && linkPrefix.Buffer[1] == L'?')\n                {\n                    // \\??\\Volume -> \\\\?\\Volume\n                    linkPrefix.Buffer[1] = OBJ_NAME_PATH_SEPARATOR;\n                }\n\n                // \\\\Device\\\\VhdHardDisk{12345678-abcd-1234-abcd-123456789abc} -> \\\\\\\\?\\\\Volume{12345678-abcd-1234-abcd-123456789abc}\n\n                newName = PhCreateStringEx(NULL, linkPrefix.Length + (Name->Length - devicePrefix.Length));\n                memcpy(newName->Buffer, linkPrefix.Buffer, linkPrefix.Length);\n                memcpy(\n                    PTR_ADD_OFFSET(newName->Buffer, linkPrefix.Length),\n                    &Name->Buffer[devicePrefix.Length / sizeof(WCHAR)],\n                    Name->Length - devicePrefix.Length\n                    );\n                PhTrimToNullTerminatorString(newName);\n                break;\n            }\n        }\n        else\n        {\n            if (PhStartsWithStringRef(Name, &linkPrefix, TRUE))\n            {\n                // \\\\?\\Volume{12345678-abcd-1234-abcd-123456789abc} -> \\Device\\VhdHardDisk{12345678-abcd-1234-abcd-123456789abc}\n\n                newName = PhCreateStringEx(NULL, devicePrefix.Length + (Name->Length - linkPrefix.Length));\n                memcpy(newName->Buffer, devicePrefix.Buffer, devicePrefix.Length);\n                memcpy(\n                    PTR_ADD_OFFSET(newName->Buffer, devicePrefix.Length),\n                    &Name->Buffer[linkPrefix.Length / sizeof(WCHAR)],\n                    Name->Length - linkPrefix.Length\n                    );\n                PhTrimToNullTerminatorString(newName);\n                break;\n            }\n        }\n    }\n\n    PhFree(mountPoints);\n\n    return newName;\n}\n\n/**\n * Resolves a NT path into a Win32 path.\n *\n * \\param Name A string containing the path to resolve.\n * \\return A pointer to a string containing the Win32 path. You must free the string using\n * PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhResolveDevicePrefix(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    ULONG i;\n    PPH_STRING newName = NULL;\n\n    if (PhBeginInitOnce(&PhDevicePrefixesInitOnce))\n    {\n        PhpInitializeDevicePrefixes();\n        PhUpdateDosDevicePrefixes();\n        PhUpdateMupDevicePrefixes();\n\n        //PhUpdateDosDeviceMountPrefixes();\n\n        PhEndInitOnce(&PhDevicePrefixesInitOnce);\n    }\n\n    PhAcquireQueuedLockShared(&PhDevicePrefixesLock);\n\n    // Go through the DOS devices and try to find a matching prefix.\n    for (i = 0; i < 26; i++)\n    {\n        BOOLEAN isPrefix = FALSE;\n        PH_STRINGREF prefix;\n\n        PhUnicodeStringToStringRef(&PhDevicePrefixes[i], &prefix);\n\n        if (prefix.Length != 0)\n        {\n            if (PhStartsWithStringRef(Name, &prefix, TRUE))\n            {\n                // To ensure we match the longest prefix, make sure the next character is a\n                // backslash or the path is equal to the prefix.\n                if (Name->Length == prefix.Length || Name->Buffer[prefix.Length / sizeof(WCHAR)] == OBJ_NAME_PATH_SEPARATOR)\n                {\n                    isPrefix = TRUE;\n                }\n            }\n        }\n\n        if (isPrefix)\n        {\n            // <letter>:path\n            newName = PhCreateStringEx(NULL, 2 * sizeof(WCHAR) + Name->Length - prefix.Length);\n            newName->Buffer[0] = (WCHAR)('A' + i);\n            newName->Buffer[1] = L':';\n            memcpy(\n                &newName->Buffer[2],\n                &Name->Buffer[prefix.Length / sizeof(WCHAR)],\n                Name->Length - prefix.Length\n                );\n\n            break;\n        }\n    }\n\n    PhReleaseQueuedLockShared(&PhDevicePrefixesLock);\n\n    if (i == 26)\n    {\n        // Resolve network providers.\n\n        PhAcquireQueuedLockShared(&PhDeviceMupPrefixesLock);\n\n        for (i = 0; i < PhDeviceMupPrefixesCount; i++)\n        {\n            BOOLEAN isPrefix = FALSE;\n            SIZE_T prefixLength;\n\n            prefixLength = PhDeviceMupPrefixes[i]->Length;\n\n            if (prefixLength != 0)\n            {\n                if (PhStartsWithStringRef(Name, &PhDeviceMupPrefixes[i]->sr, TRUE))\n                {\n                    // To ensure we match the longest prefix, make sure the next character is a\n                    // backslash. Don't resolve if the name *is* the prefix. Otherwise, we will end\n                    // up with a useless string like \"\\\".\n                    if (Name->Length != prefixLength && Name->Buffer[prefixLength / sizeof(WCHAR)] == OBJ_NAME_PATH_SEPARATOR)\n                    {\n                        isPrefix = TRUE;\n                    }\n                }\n            }\n\n            if (isPrefix)\n            {\n                // \\path\n                newName = PhCreateStringEx(NULL, 1 * sizeof(WCHAR) + Name->Length - prefixLength);\n                newName->Buffer[0] = OBJ_NAME_PATH_SEPARATOR;\n                memcpy(\n                    &newName->Buffer[1],\n                    &Name->Buffer[prefixLength / sizeof(WCHAR)],\n                    Name->Length - prefixLength\n                    );\n\n                break;\n            }\n        }\n\n        PhReleaseQueuedLockShared(&PhDeviceMupPrefixesLock);\n    }\n\n    if (PhIsNullOrEmptyString(newName) && (Name->Length != 0 && Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))\n    {\n        // We didn't find a match. Try the mount point prefixes.\n        newName = PhResolveMountPrefix(Name, TRUE);\n    }\n\n    if (newName)\n        PhTrimToNullTerminatorString(newName);\n\n    return newName;\n}\n\n/**\n * Converts a file name into Win32 format.\n *\n * \\param FileName A string containing a file name.\n * \\return A pointer to a string containing the Win32 file name. You must free the string using\n * PhDereferenceObject() when you no longer need it.\n * \\remarks This function may convert NT object name paths to invalid ones. If the path to be\n * converted is not necessarily a file name, use PhResolveDevicePrefix().\n */\nPPH_STRING PhGetFileName(\n    _In_ PPH_STRING FileName\n    )\n{\n    PPH_STRING newFileName;\n\n    newFileName = FileName;\n\n    // \"\\??\\\" refers to \\GLOBAL??\\. Just remove it.\n    if (PhStartsWithString2(FileName, L\"\\\\??\\\\\", FALSE))\n    {\n        newFileName = PhCreateStringEx(NULL, FileName->Length - 4 * sizeof(WCHAR));\n        memcpy(newFileName->Buffer, &FileName->Buffer[4], FileName->Length - 4 * sizeof(WCHAR));\n    }\n    // \"\\SystemRoot\" means \"C:\\Windows\".\n    else if (PhStartsWithString2(FileName, L\"\\\\SystemRoot\", TRUE))\n    {\n        PH_STRINGREF systemRoot;\n\n        PhGetSystemRoot(&systemRoot);\n        newFileName = PhCreateStringEx(NULL, systemRoot.Length + FileName->Length - 11 * sizeof(WCHAR));\n        memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length);\n        memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length), &FileName->Buffer[11], FileName->Length - 11 * sizeof(WCHAR));\n    }\n    // System32, SysWOW64, SysArm32, and SyChpe32 are all identical length, fixup is the same\n    else if (\n        // \"System32\\\" means \"C:\\Windows\\System32\\\".\n        PhStartsWithString2(FileName, L\"System32\\\\\", TRUE)\n#if _WIN64\n        // \"SysWOW64\\\" means \"C:\\Windows\\SysWOW64\\\".\n        || PhStartsWithString2(FileName, L\"SysWOW64\\\\\", TRUE)\n#if _M_ARM64\n        // \"SysArm32\\\" means \"C:\\Windows\\SysArm32\\\".\n        || PhStartsWithString2(FileName, L\"SysArm32\\\\\", TRUE)\n        // \"SyChpe32\\\" means \"C:\\Windows\\SyChpe32\\\".\n        || PhStartsWithString2(FileName, L\"SyChpe32\\\\\", TRUE)\n#endif\n#endif\n        )\n    {\n        PH_STRINGREF systemRoot;\n\n        PhGetSystemRoot(&systemRoot);\n        newFileName = PhCreateStringEx(NULL, systemRoot.Length + sizeof(UNICODE_NULL) + FileName->Length);\n        memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length);\n        newFileName->Buffer[systemRoot.Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;\n        memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length + sizeof(UNICODE_NULL)), FileName->Buffer, FileName->Length);\n    }\n    else if (FileName->Length != 0 && FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)\n    {\n        PPH_STRING resolvedName;\n\n        resolvedName = PhResolveDevicePrefix(&FileName->sr);\n\n        if (resolvedName)\n        {\n            newFileName = resolvedName;\n        }\n        else\n        {\n            // We didn't find a match.\n            // If the file name starts with \"\\Windows\", prepend the system drive.\n            if (PhStartsWithString2(newFileName, L\"\\\\Windows\", TRUE))\n            {\n                PH_STRINGREF systemRoot;\n\n                PhGetSystemRoot(&systemRoot);\n                newFileName = PhCreateStringEx(NULL, FileName->Length + 2 * sizeof(WCHAR));\n                newFileName->Buffer[0] = systemRoot.Buffer[0];\n                newFileName->Buffer[1] = L':';\n                memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length);\n            }\n            else\n            {\n                PhReferenceObject(newFileName);\n            }\n        }\n    }\n    else\n    {\n        // Just return the supplied file name. Note that we need to add a reference.\n        PhReferenceObject(newFileName);\n    }\n\n    return newFileName;\n}\n\n/**\n * Converts a DOS-style path name to an NT-style path name.\n *\n * \\param Name A pointer to a PPH_STRINGREF structure that contains the DOS path to convert.\n * \\return A PPH_STRING containing the converted NT path, or NULL if the conversion fails.\n */\nPPH_STRING PhDosPathNameToNtPathName(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    PPH_STRING newName = NULL;\n    PH_STRINGREF prefix;\n    ULONG index;\n    PH_STRINGREF name;\n\n    if (PhBeginInitOnce(&PhDevicePrefixesInitOnce))\n    {\n        PhpInitializeDevicePrefixes();\n        PhUpdateDosDevicePrefixes();\n        PhUpdateMupDevicePrefixes();\n\n        PhEndInitOnce(&PhDevicePrefixesInitOnce);\n    }\n\n    if (PhIsNullOrEmptyStringRef(Name))\n        return NULL;\n\n    name = *Name;\n\n    if (PhStartsWithStringRef(&name, &PhWin32ExtendedPathPrefix, TRUE))\n    {\n        PhSkipStringRef(&name, PhWin32ExtendedPathPrefix.Length);\n    }\n\n    if (PATH_IS_WIN32_DRIVE_PREFIX(&name))\n    {\n        index = (ULONG)(PhUpcaseUnicodeChar(name.Buffer[0]) - L'A');\n\n        if (index >= RTL_NUMBER_OF(PhDevicePrefixes))\n            return NULL;\n\n        PhAcquireQueuedLockShared(&PhDevicePrefixesLock);\n        PhUnicodeStringToStringRef(&PhDevicePrefixes[index], &prefix);\n\n        if (prefix.Length != 0)\n        {\n            // C:\\\\Name -> \\\\Device\\\\HardDiskVolumeX\\\\Name\n            newName = PhCreateStringEx(NULL, prefix.Length + name.Length - sizeof(WCHAR[2]));\n            memcpy(\n                newName->Buffer,\n                prefix.Buffer,\n                prefix.Length\n                );\n            memcpy(\n                PTR_ADD_OFFSET(newName->Buffer, prefix.Length),\n                PTR_ADD_OFFSET(name.Buffer, sizeof(WCHAR[2])),\n                name.Length - sizeof(WCHAR[2])\n                );\n        }\n\n        PhReleaseQueuedLockShared(&PhDevicePrefixesLock);\n    }\n    else if (PhStartsWithStringRef2(&name, L\"\\\\SystemRoot\", TRUE))\n    {\n        PhAcquireQueuedLockShared(&PhDevicePrefixesLock);\n        PhUnicodeStringToStringRef(&PhDevicePrefixes[(ULONG)'C'-'A'], &prefix);\n\n        if (prefix.Length != 0)\n        {\n            static CONST PH_STRINGREF systemRoot = PH_STRINGREF_INIT(L\"\\\\Windows\");\n\n            // \\\\SystemRoot\\\\Name -> \\\\Device\\\\HardDiskVolumeX\\\\Windows\\\\Name\n            newName = PhCreateStringEx(NULL, prefix.Length + name.Length + systemRoot.Length - sizeof(L\"SystemRoot\"));\n            memcpy(\n                newName->Buffer,\n                prefix.Buffer,\n                prefix.Length\n                );\n            memcpy(\n                PTR_ADD_OFFSET(newName->Buffer, prefix.Length),\n                systemRoot.Buffer,\n                systemRoot.Length\n                );\n            memcpy(\n                PTR_ADD_OFFSET(newName->Buffer, prefix.Length + systemRoot.Length),\n                PTR_ADD_OFFSET(name.Buffer, sizeof(L\"SystemRoot\")),\n                name.Length - sizeof(L\"SystemRoot\")\n                );\n        }\n\n        PhReleaseQueuedLockShared(&PhDevicePrefixesLock);\n    }\n    else if (PATH_IS_WIN32_DOSDEVICES_PREFIX(&name))\n    {\n        newName = PhResolveMountPrefix(&name, FALSE);\n    }\n\n    return newName;\n}\n\n/**\n * Converts a DOS-style file path to an NT-style file path.\n *\n * \\param DosFileName The DOS-style file path to convert (e.g., \"C:\\\\Windows\\\\System32\").\n * \\param NtFileName A pointer to a UNICODE_STRING structure that receives the resulting NT-style file path.\n * \\param FilePart If specified, receives a pointer to the file part of the path (the final component).\n * \\param RelativeName If specified, receives a pointer to a RTL_RELATIVE_NAME_U structure that describes the relative name.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhDosLongPathNameToNtPathNameWithStatus(\n    _In_ PCWSTR DosFileName,\n    _Out_ PUNICODE_STRING NtFileName,\n    _Out_opt_ PWSTR* FilePart,\n    _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName\n    )\n{\n    NTSTATUS status;\n\n    if (\n        WindowsVersion >= WINDOWS_10_RS1 && PhAreLongPathsEnabled() &&\n        RtlDosLongPathNameToNtPathName_U_WithStatus_Import()\n        )\n    {\n        status = RtlDosLongPathNameToNtPathName_U_WithStatus_Import()(\n            DosFileName,\n            NtFileName,\n            FilePart,\n            RelativeName\n            );\n    }\n    else\n    {\n        status = RtlDosPathNameToNtPathName_U_WithStatus(\n            DosFileName,\n            NtFileName,\n            FilePart,\n            RelativeName\n            );\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the root prefix of an NT path from the specified string reference.\n *\n * \\param Name A pointer to a PPH_STRINGREF structure that contains the NT path string.\n * \\return A PPH_STRING representing the root prefix of the NT path, or NULL if the prefix cannot be determined.\n */\nPPH_STRING PhGetNtPathRootPrefix(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    PPH_STRING pathDevicePrefix = NULL;\n    PH_STRINGREF prefix;\n\n    PhAcquireQueuedLockShared(&PhDevicePrefixesLock);\n\n    for (ULONG i = 0; i < RTL_NUMBER_OF(PhDevicePrefixes); i++)\n    {\n        PhUnicodeStringToStringRef(&PhDevicePrefixes[i], &prefix);\n\n        if (prefix.Length && PhStartsWithStringRef(Name, &prefix, FALSE))\n        {\n            pathDevicePrefix = PhCreateString2(&prefix);\n            break;\n        }\n    }\n\n    PhReleaseQueuedLockShared(&PhDevicePrefixesLock);\n\n    return pathDevicePrefix;\n}\n\n/**\n * Retrieves the existing path prefix from the specified string reference.\n *\n * This function examines the provided string reference, which is expected to represent a file or directory path,\n * and returns a PPH_STRING containing the longest existing prefix of that path. If no part of the path exists,\n * the function may return NULL or an empty string, depending on implementation.\n *\n * \\param Name A pointer to a PPH_STRINGREF structure that contains the path to be examined.\n * \\return A PPH_STRING containing the longest existing prefix of the specified path, or NULL if no prefix exists.\n */\nPPH_STRING PhGetExistingPathPrefix(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    PPH_STRING existingPathPrefix = NULL;\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF directoryPart;\n    PH_STRINGREF baseNamePart;\n\n    if (PATH_IS_WIN32_DRIVE_PREFIX(Name))\n    {\n        assert(FALSE);\n        return NULL;\n    }\n\n    if (PhDoesDirectoryExist(Name))\n    {\n        return PhCreateString2(Name);\n    }\n\n    remainingPart = *Name;\n\n    while (remainingPart.Length != 0)\n    {\n        PhSplitStringRefAtLastChar(&remainingPart, OBJ_NAME_PATH_SEPARATOR, &directoryPart, &baseNamePart);\n\n        if (directoryPart.Length != 0)\n        {\n            if (PhDoesDirectoryExist(&directoryPart))\n            {\n                existingPathPrefix = PhCreateString2(&directoryPart);\n                break;\n            }\n        }\n\n        remainingPart = directoryPart;\n    }\n\n    //if (PhEqualStringRef(&existingPathPrefix, PhGetNtPathRootPrefix(Name), FALSE))\n    //    return NULL;\n\n    return existingPathPrefix;\n}\n\n/**\n * Retrieves the existing path prefix from a given string reference representing a path.\n *\n * This function examines the provided path and returns the longest existing prefix\n * (i.e., the deepest directory that actually exists on the filesystem).\n *\n * \\param Name A pointer to a PPH_STRINGREF structure that contains the path to be checked.\n * \\return A PPH_STRING containing the longest existing path prefix, or NULL if no part of the path exists.\n */\nPPH_STRING PhGetExistingPathPrefixWin32(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    PPH_STRING existingPathPrefix = NULL;\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF directoryPart;\n    PH_STRINGREF baseNamePart;\n\n    if (!PATH_IS_WIN32_DRIVE_PREFIX(Name))\n    {\n        assert(FALSE);\n        return NULL;\n    }\n\n    if (PhDoesDirectoryExistWin32(PhGetStringRefZ(Name)))\n    {\n        return PhCreateString2(Name);\n    }\n\n    remainingPart = *Name;\n\n    while (remainingPart.Length != 0)\n    {\n        PhSplitStringRefAtLastChar(&remainingPart, OBJ_NAME_PATH_SEPARATOR, &directoryPart, &baseNamePart);\n\n        if (directoryPart.Length != 0)\n        {\n            existingPathPrefix = PhCreateString2(&directoryPart);\n\n            if (PhDoesDirectoryExistWin32(PhGetString(existingPathPrefix)))\n                break;\n\n            PhClearReference(&existingPathPrefix);\n        }\n\n        remainingPart = directoryPart;\n    }\n\n    return existingPathPrefix;\n}\n\n// rev from GetLongPathNameW (dmex)\n/**\n * Retrieves the long (non-8.3) path form of the specified file or directory name.\n *\n * \\param FileName A pointer to a PPH_STRINGREF structure that contains the file or directory name for which to retrieve the long path name.\n * \\return A PPH_STRING containing the long path name if successful, or NULL if the operation fails.\n */\nPPH_STRING PhGetLongPathName(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    PPH_STRING longPathName = NULL;\n    NTSTATUS status;\n    HANDLE fileHandle;\n    IO_STATUS_BLOCK ioStatusBlock;\n    PFILE_BOTH_DIR_INFORMATION directoryInfoBuffer;\n    ULONG directoryInfoLength;\n    PH_STRINGREF baseNamePart;\n    UNICODE_STRING baseNameUs;\n\n    status = PhOpenFile(\n        &fileHandle,\n        FileName,\n        FILE_READ_DATA | FILE_LIST_DIRECTORY | SYNCHRONIZE,\n        NULL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    if (!PhGetBasePath(FileName, NULL, &baseNamePart))\n        goto CleanupExit;\n    if (!PhStringRefToUnicodeString(&baseNamePart, &baseNameUs))\n        goto CleanupExit;\n\n    directoryInfoLength = PAGE_SIZE;\n    directoryInfoBuffer = PhAllocate(directoryInfoLength);\n\n    status = NtQueryDirectoryFile(\n        fileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &ioStatusBlock,\n        directoryInfoBuffer,\n        directoryInfoLength,\n        FileBothDirectoryInformation,\n        TRUE,\n        &baseNameUs,\n        FALSE\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        longPathName = PhCreateStringEx(directoryInfoBuffer->FileName, directoryInfoBuffer->FileNameLength);\n    }\n\n    PhFree(directoryInfoBuffer);\n\nCleanupExit:\n    NtClose(fileHandle);\n\n    return longPathName;\n}\n\n/**\n * Retrieves the heap signature from a process heap structure.\n *\n * \\param ProcessHandle A handle to the process. The handle must have PROCESS_VM_READ access.\n * \\param HeapAddress The base address of the heap in the target process.\n * \\param IsWow64 Specifies whether the target process is running under WOW64 (TRUE) or is native (FALSE).\n * \\param HeapSignature A pointer to a variable that receives the heap signature value.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The heap signature is a validation field in the _HEAP structure used to verify heap integrity.\n * This function reads the SegmentSignature field at different offsets depending on the process architecture:\n * - For WOW64 processes: offset 0x8\n * - For native 64-bit processes: offset 0x10\n * The signature value is only available on Windows 7 and later versions.\n */\nNTSTATUS PhGetProcessHeapSignature(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID HeapAddress,\n    _In_ ULONG IsWow64,\n    _Out_ ULONG *HeapSignature\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    ULONG heapSignature = ULONG_MAX;\n\n    if (WindowsVersion >= WINDOWS_7)\n    {\n        // dt _HEAP SegmentSignature\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(HeapAddress, IsWow64 ? 0x8 : 0x10),\n            &heapSignature,\n            sizeof(ULONG),\n            NULL\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (HeapSignature)\n            *HeapSignature = heapSignature;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the front-end type of a specified heap in a process.\n *\n * \\param ProcessHandle A handle to the process containing the heap.\n * \\param HeapAddress The base address of the heap to query.\n * \\param IsWow64 A flag indicating whether the process is running under WOW64.\n * \\param HeapFrontEndType A pointer to a UCHAR that receives the front-end type of the heap.\n * Possible values include 0x0 (no front-end), 0x1 (LFH), etc., depending on the heap configuration.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessHeapFrontEndType(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID HeapAddress,\n    _In_ ULONG IsWow64,\n    _Out_ UCHAR *HeapFrontEndType\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    UCHAR heapFrontEndType = UCHAR_MAX;\n\n    if (WindowsVersion >= WINDOWS_10)\n    {\n        // dt _HEAP FrontEndHeapType\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(HeapAddress, IsWow64 ? 0x0ea : 0x1a2),\n            &heapFrontEndType,\n            sizeof(UCHAR),\n            NULL\n            );\n    }\n    else if (WindowsVersion >= WINDOWS_8_1)\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(HeapAddress, IsWow64 ? 0x0d6 : 0x17a),\n            &heapFrontEndType,\n            sizeof(UCHAR),\n            NULL\n            );\n    }\n    else if (WindowsVersion >= WINDOWS_7)\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(HeapAddress, IsWow64 ? 0x0da : 0x182),\n            &heapFrontEndType,\n            sizeof(UCHAR),\n            NULL\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (HeapFrontEndType)\n            *HeapFrontEndType = heapFrontEndType;\n    }\n\n    return status;\n}\n\n/**\n * Queries heap information for a specified process.\n *\n * \\param ProcessId Handle to the process whose heap information is to be queried.\n * \\param HeapInformation Pointer to a variable that receives a pointer to a structure containing heap information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryProcessHeapInformation(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_PROCESS_DEBUG_HEAP_INFORMATION* HeapInformation\n    )\n{\n    NTSTATUS status;\n    PRTL_DEBUG_INFORMATION debugBuffer = NULL;\n    PPH_PROCESS_DEBUG_HEAP_INFORMATION heapDebugInfo = NULL;\n\n    for (ULONG i = 0x400000; ; i *= 2) // rev from Heap32First/Heap32Next (dmex)\n    {\n        if (!(debugBuffer = RtlCreateQueryDebugBuffer(i, FALSE)))\n            return STATUS_UNSUCCESSFUL;\n\n        status = RtlQueryProcessDebugInformation(\n            ProcessId,\n            RTL_QUERY_PROCESS_HEAP_SUMMARY | RTL_QUERY_PROCESS_HEAP_ENTRIES | RTL_QUERY_PROCESS_NONINVASIVE,\n            debugBuffer\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            RtlDestroyQueryDebugBuffer(debugBuffer);\n            debugBuffer = NULL;\n        }\n\n        if (NT_SUCCESS(status) || status != STATUS_NO_MEMORY)\n            break;\n\n        if (2 * i <= i)\n        {\n            status = STATUS_UNSUCCESSFUL;\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!debugBuffer->Heaps)\n    {\n        // The RtlQueryProcessDebugInformation function has two bugs on some versions\n        // when querying the ProcessId for a frozen (suspended) immersive process. (dmex)\n        //\n        // 1) It'll deadlock the current thread for 30 seconds.\n        // 2) It'll return STATUS_SUCCESS but with a NULL Heaps buffer.\n        //\n        // A workaround was implemented using PhCreateExecutionRequiredRequest() (dmex)\n\n        RtlDestroyQueryDebugBuffer(debugBuffer);\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    if (WindowsVersion > WINDOWS_11)\n    {\n        heapDebugInfo = PhAllocateZero(sizeof(PH_PROCESS_DEBUG_HEAP_INFORMATION) + ((PRTL_PROCESS_HEAPS_V2)debugBuffer->Heaps)->NumberOfHeaps * sizeof(PH_PROCESS_DEBUG_HEAP_ENTRY));\n        heapDebugInfo->NumberOfHeaps = ((PRTL_PROCESS_HEAPS_V2)debugBuffer->Heaps)->NumberOfHeaps;\n    }\n    else\n    {\n        heapDebugInfo = PhAllocateZero(sizeof(PH_PROCESS_DEBUG_HEAP_INFORMATION) + ((PRTL_PROCESS_HEAPS_V1)debugBuffer->Heaps)->NumberOfHeaps * sizeof(PH_PROCESS_DEBUG_HEAP_ENTRY));\n        heapDebugInfo->NumberOfHeaps = ((PRTL_PROCESS_HEAPS_V1)debugBuffer->Heaps)->NumberOfHeaps;\n    }\n\n    heapDebugInfo->DefaultHeap = debugBuffer->ProcessHeap;\n\n    for (ULONG i = 0; i < heapDebugInfo->NumberOfHeaps; i++)\n    {\n        RTL_HEAP_INFORMATION_V2 heapInfo = { 0 };\n        HANDLE processHandle;\n        SIZE_T allocated = 0;\n        SIZE_T committed = 0;\n\n        if (WindowsVersion > WINDOWS_11)\n        {\n            heapInfo = ((PRTL_PROCESS_HEAPS_V2)debugBuffer->Heaps)->Heaps[i];\n        }\n        else\n        {\n            RTL_HEAP_INFORMATION_V1 heapInfoV1 = ((PRTL_PROCESS_HEAPS_V1)debugBuffer->Heaps)->Heaps[i];\n            heapInfo.NumberOfEntries = heapInfoV1.NumberOfEntries;\n            heapInfo.Entries = heapInfoV1.Entries;\n            heapInfo.BytesCommitted = heapInfoV1.BytesCommitted;\n            heapInfo.Flags = heapInfoV1.Flags;\n            heapInfo.BaseAddress = heapInfoV1.BaseAddress;\n        }\n\n        // go through all heap entries and compute amount of allocated and committed bytes (ge0rdi)\n        for (ULONG e = 0; e < heapInfo.NumberOfEntries; e++)\n        {\n            PRTL_HEAP_ENTRY entry = &heapInfo.Entries[e];\n\n            if (entry->Flags & RTL_HEAP_BUSY)\n                allocated += entry->Size;\n            if (entry->Flags & RTL_HEAP_SEGMENT)\n                committed += entry->u.s2.CommittedSize;\n        }\n\n        // sometimes computed number if committed bytes is few pages smaller than the one reported by API, lets use the higher value (ge0rdi)\n        if (committed < heapInfo.BytesCommitted)\n            committed = heapInfo.BytesCommitted;\n\n        // make sure number of allocated bytes is not higher than number of committed bytes (as that would make no sense) (ge0rdi)\n        if (allocated > committed)\n            allocated = committed;\n\n        heapDebugInfo->Heaps[i].Flags = heapInfo.Flags;\n        heapDebugInfo->Heaps[i].Signature = ULONG_MAX;\n        heapDebugInfo->Heaps[i].HeapFrontEndType = UCHAR_MAX;\n        heapDebugInfo->Heaps[i].NumberOfEntries = heapInfo.NumberOfEntries;\n        heapDebugInfo->Heaps[i].BaseAddress = heapInfo.BaseAddress;\n        heapDebugInfo->Heaps[i].BytesAllocated = allocated;\n        heapDebugInfo->Heaps[i].BytesCommitted = committed;\n\n        if (NT_SUCCESS(PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n            ProcessId\n            )))\n        {\n            ULONG signature = ULONG_MAX;\n            UCHAR frontEndType = UCHAR_MAX;\n#ifndef _WIN64\n            BOOLEAN isWow64 = TRUE;\n#else\n            BOOLEAN isWow64 = FALSE;\n\n            PhGetProcessIsWow64(processHandle, &isWow64);\n#endif\n            if (NT_SUCCESS(PhGetProcessHeapSignature(\n                processHandle,\n                heapInfo.BaseAddress,\n                isWow64,\n                &signature\n                )))\n            {\n                heapDebugInfo->Heaps[i].Signature = signature;\n            }\n\n            if (NT_SUCCESS(PhGetProcessHeapFrontEndType(\n                processHandle,\n                heapInfo.BaseAddress,\n                isWow64,\n                &frontEndType\n                )))\n            {\n                heapDebugInfo->Heaps[i].HeapFrontEndType = frontEndType;\n            }\n\n            NtClose(processHandle);\n        }\n    }\n\n    if (HeapInformation)\n        *HeapInformation = heapDebugInfo;\n    else\n        PhFree(heapDebugInfo);\n\n    if (debugBuffer)\n        RtlDestroyQueryDebugBuffer(debugBuffer);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Queries lock information for a specified process and invokes the provided callback\n * for each lock associated with the process.\n *\n * \\param ProcessId The handle to the process for which to query lock information.\n * \\param Callback A pointer to a callback function of type PPH_ENUM_PROCESS_LOCKS\n * that will be called for each lock.\n * \\param Context An optional pointer to user-defined context data that will be\n * passed to the callback function.\n * \\return NTSTATUS indicating success or failure.\n */\nNTSTATUS PhQueryProcessLockInformation(\n    _In_ HANDLE ProcessId,\n    _In_ PPH_ENUM_PROCESS_LOCKS Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PRTL_DEBUG_INFORMATION debugBuffer = NULL;\n\n    for (ULONG i = 0x400000; ; i *= 2) // rev from Heap32First/Heap32Next (dmex)\n    {\n        if (!(debugBuffer = RtlCreateQueryDebugBuffer(i, FALSE)))\n            return STATUS_UNSUCCESSFUL;\n\n        status = RtlQueryProcessDebugInformation(\n            ProcessId,\n            RTL_QUERY_PROCESS_LOCKS,\n            debugBuffer\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            RtlDestroyQueryDebugBuffer(debugBuffer);\n            debugBuffer = NULL;\n        }\n\n        if (NT_SUCCESS(status) || status != STATUS_NO_MEMORY)\n            break;\n\n        if (2 * i <= i)\n        {\n            status = STATUS_UNSUCCESSFUL;\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!debugBuffer->Locks)\n    {\n        // The RtlQueryProcessDebugInformation function has two bugs on some versions\n        // when querying the ProcessId for a frozen (suspended) immersive process. (dmex)\n        //\n        // 1) It'll deadlock the current thread for 30 seconds.\n        // 2) It'll return STATUS_SUCCESS but with a NULL Heaps buffer.\n        //\n        // A workaround was implemented using PhCreateExecutionRequiredRequest() (dmex)\n\n        RtlDestroyQueryDebugBuffer(debugBuffer);\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    status = Callback(\n        debugBuffer->Locks->NumberOfLocks,\n        debugBuffer->Locks->Locks,\n        Context\n        );\n\n    if (debugBuffer)\n    {\n        RtlDestroyQueryDebugBuffer(debugBuffer);\n    }\n\n    return status;\n}\n\n// rev from kernelbase!GetMachineTypeAttributes (dmex)\n/**\n * Retrieves the attributes associated with a specified machine type.\n *\n * \\param Machine The machine type identifier (e.g., IMAGE_FILE_MACHINE_I386).\n * \\param Attributes A pointer to a MACHINE_ATTRIBUTES structure that receives the attributes.\n * \\return NTSTATUS indicating success or failure.\n * \\remarks Queries if the specified architecture is supported on the current system,\n * either natively or by any form of compatibility or emulation layer.\n */\nNTSTATUS PhGetMachineTypeAttributes(\n    _In_ USHORT Machine,\n    _Out_ MACHINE_ATTRIBUTES* Attributes\n    )\n{\n    NTSTATUS status;\n    HANDLE input[1] = { 0 };\n    SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION output[6] = { 0 };\n    ULONG returnLength;\n\n    status = NtQuerySystemInformationEx(\n        SystemSupportedProcessorArchitectures2,\n        input,\n        sizeof(input),\n        output,\n        sizeof(output),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        MACHINE_ATTRIBUTES attributes;\n\n        memset(&attributes, 0, sizeof(MACHINE_ATTRIBUTES));\n\n        for (ULONG i = 0; i < returnLength / sizeof(SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION); i++)\n        {\n            if (output[i].Machine == Machine)\n            {\n                if (output[i].KernelMode)\n                    SetFlag(attributes, KernelEnabled);\n                if (output[i].UserMode)\n                    SetFlag(attributes, UserEnabled);\n                if (output[i].WoW64Container)\n                    SetFlag(attributes, Wow64Container);\n                break;\n            }\n        }\n\n        *Attributes = attributes;\n    }\n\n    return status;\n}\n\n/**\n * Checks if firmware-related features are supported on the current system.\n *\n * \\return TRUE if firmware features are supported, FALSE otherwise.\n */\nBOOLEAN PhIsFirmwareSupported(\n    VOID\n    )\n{\n    static CONST UNICODE_STRING variableName = RTL_CONSTANT_STRING(L\" \");\n    static CONST GUID vendorGuid = { 0 };\n    ULONG variableValueLength = 0;\n\n    if (NtQuerySystemEnvironmentValueEx(\n        &variableName,\n        &vendorGuid,\n        NULL,\n        &variableValueLength,\n        NULL\n        ) == STATUS_VARIABLE_NOT_FOUND)\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n// rev from GetFirmwareEnvironmentVariableW (dmex)\n/**\n * Retrieves the value of a specified firmware environment variable.\n *\n * \\param VariableName A pointer to a PH_STRINGREF structure that specifies the name of the variable to retrieve.\n * \\param VendorGuid A pointer to a PH_STRINGREF structure that specifies the GUID of the firmware vendor.\n * \\param ValueBuffer A pointer to a buffer that receives the value of the environment variable.\n * \\param ValueLength An optional pointer to a ULONG that receives the length of the value returned in ValueBuffer.\n * \\param ValueAttributes An optional pointer to a ULONG that receives the attributes of the environment variable.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetFirmwareEnvironmentVariable(\n    _In_ PCPH_STRINGREF VariableName,\n    _In_ PCPH_STRINGREF VendorGuid,\n    _Out_writes_bytes_opt_(*ValueLength) PVOID* ValueBuffer,\n    _Out_opt_ PULONG ValueLength,\n    _Out_opt_ PULONG ValueAttributes\n    )\n{\n    NTSTATUS status;\n    GUID vendorGuid;\n    UNICODE_STRING variableName;\n    PVOID valueBuffer;\n    ULONG valueLength = 0;\n    ULONG valueAttributes = 0;\n\n    if (!PhStringRefToUnicodeString(VariableName, &variableName))\n        return STATUS_NAME_TOO_LONG;\n\n    status = PhStringToGuid(\n        VendorGuid,\n        &vendorGuid\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = NtQuerySystemEnvironmentValueEx(\n        &variableName,\n        &vendorGuid,\n        NULL,\n        &valueLength,\n        &valueAttributes\n        );\n\n    if (status != STATUS_BUFFER_TOO_SMALL)\n        return STATUS_UNSUCCESSFUL;\n\n    valueBuffer = PhAllocate(valueLength);\n    memset(valueBuffer, 0, valueLength);\n\n    status = NtQuerySystemEnvironmentValueEx(\n        &variableName,\n        &vendorGuid,\n        valueBuffer,\n        &valueLength,\n        &valueAttributes\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (ValueBuffer)\n            *ValueBuffer = valueBuffer;\n        else\n            PhFree(valueBuffer);\n\n        if (ValueLength)\n            *ValueLength = valueLength;\n\n        if (ValueAttributes)\n            *ValueAttributes = valueAttributes;\n    }\n    else\n    {\n        PhFree(valueBuffer);\n    }\n\n    return status;\n}\n\n/**\n * Sets a firmware environment variable.\n *\n * \\param VariableName A pointer to a PH_STRINGREF structure that specifies the name of the variable to set.\n * \\param VendorGuid A pointer to a PH_STRINGREF structure that specifies the vendor GUID associated with the variable.\n * \\param ValueBuffer An optional pointer to the buffer containing the value to set for the variable.\n * \\param ValueLength The length, in bytes, of the value buffer.\n * \\param Attributes Attributes to apply to the variable.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetFirmwareEnvironmentVariable(\n    _In_ PCPH_STRINGREF VariableName,\n    _In_ PCPH_STRINGREF VendorGuid,\n    _In_reads_bytes_opt_(ValueLength) PVOID ValueBuffer,\n    _In_ ULONG ValueLength,\n    _In_ ULONG Attributes\n    )\n{\n    NTSTATUS status;\n    GUID vendorGuid;\n    UNICODE_STRING variableName;\n\n    if (!PhStringRefToUnicodeString(VariableName, &variableName))\n        return STATUS_NAME_TOO_LONG;\n\n    status = PhStringToGuid(\n        VendorGuid,\n        &vendorGuid\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = NtSetSystemEnvironmentValueEx(\n        &variableName,\n        &vendorGuid,\n        ValueBuffer,\n        ValueLength,\n        Attributes\n        );\n\n    return status;\n}\n\n/**\n * Enumerates firmware environment values based on the specified information class.\n *\n * \\param InformationClass The type of system environment information to enumerate.\n * \\param Variables A pointer to a variable that receives the enumerated firmware environment values.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumFirmwareEnvironmentValues(\n    _In_ SYSTEM_ENVIRONMENT_INFORMATION_CLASS InformationClass,\n    _Out_ PVOID* Variables\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferLength;\n\n    bufferLength = PAGE_SIZE;\n    buffer = PhAllocate(bufferLength);\n\n    while (TRUE)\n    {\n        status = NtEnumerateSystemEnvironmentValuesEx(\n            InformationClass,\n            buffer,\n            &bufferLength\n            );\n\n        if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferLength);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Variables = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Sets the system environment to boot into firmware on next restart.\n *\n * This function modifies the system environment variables to ensure that\n * the system boots directly into the firmware interface (such as UEFI or BIOS)\n * on the next system startup.\n *\n * \\return NTSTATUS code indicating success or failure of the operation.\n */\nNTSTATUS PhSetSystemEnvironmentBootToFirmware(\n    VOID\n    )\n{\n    static CONST GUID EFI_GLOBAL_VARIABLE_GUID = { 0x8be4df61, 0x93ca, 0x11d2, { 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c } };\n    static CONST UNICODE_STRING OsIndicationsSupportedName = RTL_CONSTANT_STRING(L\"OsIndicationsSupported\");\n    static CONST UNICODE_STRING OsIndicationsName = RTL_CONSTANT_STRING(L\"OsIndications\");\n    const ULONG64 EFI_OS_INDICATIONS_BOOT_TO_FW_UI = 0x0000000000000001ULL;\n    ULONG osIndicationsLength = sizeof(ULONG64);\n    ULONG osIndicationsAttributes = 0;\n    ULONG64 osIndicationsSupported = 0;\n    ULONG64 osIndicationsValue = 0;\n    NTSTATUS status;\n\n    status = NtQuerySystemEnvironmentValueEx(\n        &OsIndicationsSupportedName,\n        &EFI_GLOBAL_VARIABLE_GUID,\n        &osIndicationsSupported,\n        &osIndicationsLength,\n        NULL\n        );\n\n    if (status == STATUS_VARIABLE_NOT_FOUND || !(osIndicationsSupported & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))\n    {\n        status = STATUS_NOT_SUPPORTED;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        status = NtQuerySystemEnvironmentValueEx(\n            &OsIndicationsName,\n            &EFI_GLOBAL_VARIABLE_GUID,\n            &osIndicationsValue,\n            &osIndicationsLength,\n            &osIndicationsAttributes\n            );\n\n        if (NT_SUCCESS(status) || status == STATUS_VARIABLE_NOT_FOUND)\n        {\n            osIndicationsValue |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;\n\n            if (status == STATUS_VARIABLE_NOT_FOUND)\n            {\n                osIndicationsAttributes = EFI_VARIABLE_NON_VOLATILE;\n            }\n\n            status = NtSetSystemEnvironmentValueEx(\n                &OsIndicationsName,\n                &EFI_GLOBAL_VARIABLE_GUID,\n                &osIndicationsValue,\n                osIndicationsLength,\n                osIndicationsAttributes\n                );\n        }\n    }\n\n    return status;\n}\n\n// rev from RtlpCreateExecutionRequiredRequest (dmex)\n/**\n * Create a new power request object. The process will continue to run instead of being suspended or terminated by PLM (Process Lifetime Management).\n * This is mandatory on Windows 8 and above to prevent threads created by DebugActiveProcess, QueueUserAPC and RtlQueryProcessDebug* functions from deadlocking the current application.\n *\n * \\param ProcessHandle A handle to the process for which the power request is to be created.\n * \\param PowerRequestHandle A pointer to a variable that receives a handle to the new power request.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateExecutionRequiredRequest(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE PowerRequestHandle\n    )\n{\n    NTSTATUS status;\n    HANDLE powerRequestHandle = NULL;\n    COUNTED_REASON_CONTEXT powerRequestReason;\n    POWER_REQUEST_ACTION powerRequestAction;\n\n    memset(&powerRequestReason, 0, sizeof(COUNTED_REASON_CONTEXT));\n    powerRequestReason.Version = POWER_REQUEST_CONTEXT_VERSION;\n    powerRequestReason.Flags = POWER_REQUEST_CONTEXT_NOT_SPECIFIED;\n\n    status = NtPowerInformation(\n        PlmPowerRequestCreate,\n        &powerRequestReason,\n        sizeof(COUNTED_REASON_CONTEXT),\n        &powerRequestHandle,\n        sizeof(HANDLE)\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    memset(&powerRequestAction, 0, sizeof(POWER_REQUEST_ACTION));\n    powerRequestAction.PowerRequestHandle = powerRequestHandle;\n    powerRequestAction.RequestType = PowerRequestExecutionRequiredInternal;\n    powerRequestAction.SetAction = TRUE;\n    powerRequestAction.ProcessHandle = ProcessHandle;\n\n    status = NtPowerInformation(\n        PowerRequestAction,\n        &powerRequestAction,\n        sizeof(POWER_REQUEST_ACTION),\n        NULL,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PowerRequestHandle = powerRequestHandle;\n    }\n    else\n    {\n        NtClose(powerRequestHandle);\n    }\n\n    return status;\n}\n\n// rev from RtlpDestroyExecutionRequiredRequest (dmex)\n/**\n * Destroys an execution required power request handle.\n *\n * \\param PowerRequestHandle An optional handle to the power request to destroy.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhDestroyExecutionRequiredRequest(\n    _In_opt_ _Post_ptr_invalid_ HANDLE PowerRequestHandle\n    )\n{\n    POWER_REQUEST_ACTION requestPowerAction;\n\n    if (!PowerRequestHandle)\n        return STATUS_INVALID_PARAMETER;\n\n    memset(&requestPowerAction, 0, sizeof(POWER_REQUEST_ACTION));\n    requestPowerAction.PowerRequestHandle = PowerRequestHandle;\n    requestPowerAction.RequestType = PowerRequestExecutionRequiredInternal;\n    requestPowerAction.SetAction = FALSE;\n    requestPowerAction.ProcessHandle = NULL;\n\n    NtPowerInformation(\n        PowerRequestAction,\n        &requestPowerAction,\n        sizeof(POWER_REQUEST_ACTION),\n        NULL,\n        0\n        );\n\n    return NtClose(PowerRequestHandle);\n}\n\n/**\n * Retrieves the nominal frequency (in MHz) of the specified processor.\n *\n * \\param ProcessorNumber The processor number structure identifying the target processor.\n * \\param NominalFrequency Pointer to a variable that receives the nominal frequency of the processor.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessorNominalFrequency(\n    _In_ PPH_PROCESSOR_NUMBER ProcessorNumber,\n    _Out_ PULONG NominalFrequency\n    )\n{\n    NTSTATUS status;\n    POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_INPUT frequencyInput;\n    POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_OUTPUT frequencyOutput;\n\n    memset(&frequencyInput, 0, sizeof(frequencyInput));\n    frequencyInput.InternalType = PowerInternalProcessorBrandedFrequency;\n    frequencyInput.ProcessorNumber.Group = ProcessorNumber->Group; // USHRT_MAX for max\n    frequencyInput.ProcessorNumber.Number = (BYTE)ProcessorNumber->Number; // UCHAR_MAX for max\n    frequencyInput.ProcessorNumber.Reserved = 0; // UCHAR_MAX\n\n    memset(&frequencyOutput, 0, sizeof(frequencyOutput));\n    frequencyOutput.Version = POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_VERSION;\n\n    status = NtPowerInformation(\n        PowerInformationInternal,\n        &frequencyInput,\n        sizeof(POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_INPUT),\n        &frequencyOutput,\n        sizeof(POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_OUTPUT)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (frequencyOutput.Version == POWER_INTERNAL_PROCESSOR_BRANDED_FREQUENCY_VERSION)\n        {\n            *NominalFrequency = frequencyOutput.NominalFrequency;\n        }\n        else\n        {\n            status = STATUS_INVALID_KERNEL_INFO_VERSION;\n        }\n    }\n\n    return status;\n}\n\n//\n// Process freeze/thaw support\n//\n\n/**\n * Freezes the execution of a specified process.\n *\n * \\param[out] ProcessStateChangeHandle A pointer to a handle that will receive the state change handle for the frozen process.\n * \\param[in] ProcessHandle The handle to the process to be frozen.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhFreezeProcess(\n    _Out_ PHANDLE ProcessStateChangeHandle,\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE processStateChangeHandle = NULL;\n\n    if (!(NtCreateProcessStateChange_Import() && NtChangeProcessState_Import()))\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        NULL,\n        OBJ_EXCLUSIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateProcessStateChange_Import()(\n        &processStateChangeHandle,\n        STATECHANGE_SET_ATTRIBUTES,\n        &objectAttributes,\n        ProcessHandle,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = NtChangeProcessState_Import()(\n        processStateChangeHandle,\n        ProcessHandle,\n        ProcessStateChangeSuspend,\n        NULL,\n        0,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ProcessStateChangeHandle = processStateChangeHandle;\n    }\n\n    return status;\n}\n\n/**\n * Freezes a process specified by its process ID.\n *\n * \\param[out] ProcessStateChangeHandle A pointer to a handle that will receive the state change handle for the frozen process.\n * \\param[in] ProcessId The handle to the process to be frozen.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhFreezeProcessById(\n    _Out_ PHANDLE ProcessStateChangeHandle,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    HANDLE processStateChangeHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME,\n        ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhFreezeProcess(\n        &processStateChangeHandle,\n        processHandle\n        );\n\n    NtClose(processHandle);\n\n    if (NT_SUCCESS(status))\n    {\n        *ProcessStateChangeHandle = processStateChangeHandle;\n    }\n\n    return status;\n}\n\n/**\n * Thaws (resumes) a previously frozen process.\n *\n * \\param ProcessStateChangeHandle Handle to the process state change object.\n * \\param ProcessHandle Handle to the target process to be thawed.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhThawProcess(\n    _In_ HANDLE ProcessStateChangeHandle,\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n\n    if (!NtChangeProcessState_Import())\n    {\n        return STATUS_PROCEDURE_NOT_FOUND;\n    }\n\n    status = NtChangeProcessState_Import()(\n        ProcessStateChangeHandle,\n        ProcessHandle,\n        ProcessStateChangeResume,\n        NULL,\n        0,\n        0\n        );\n\n    return status;\n}\n\n/**\n * Thaws (resumes) a process specified by its process ID.\n *\n * \\param ProcessStateChangeHandle Handle used to manage process state changes.\n * \\param ProcessId Handle to the process to be thawed (resumed).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhThawProcessById(\n    _In_ HANDLE ProcessStateChangeHandle,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME,\n        ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhThawProcess(\n        ProcessStateChangeHandle,\n        processHandle\n        );\n\n    NtClose(processHandle);\n\n    return status;\n}\n\n/**\n * Freezes (suspends) the specified thread.\n *\n * \\param[out] ThreadStateChangeHandle A pointer to a handle that receives the thread state change handle.\n * \\param[in] ThreadHandle A handle to the thread to be frozen.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhFreezeThread(\n    _Out_ PHANDLE ThreadStateChangeHandle,\n    _In_ HANDLE ThreadHandle\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE threadStateChangeHandle = NULL;\n\n    if (!(NtCreateThreadStateChange_Import() && NtChangeThreadState_Import()))\n    {\n        return STATUS_PROCEDURE_NOT_FOUND;\n    }\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        NULL,\n        OBJ_EXCLUSIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateThreadStateChange_Import()(\n        &threadStateChangeHandle,\n        STATECHANGE_SET_ATTRIBUTES,\n        &objectAttributes,\n        ThreadHandle,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = NtChangeThreadState_Import()(\n        threadStateChangeHandle,\n        ThreadHandle,\n        ThreadStateChangeSuspend,\n        NULL,\n        0,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ThreadStateChangeHandle = threadStateChangeHandle;\n    }\n\n    return status;\n}\n\n/**\n * Freezes the specified thread by its ID.\n *\n * \\param ThreadStateChangeHandle A pointer to a handle that will receive the thread state change handle.\n * \\param ThreadId The ID of the thread to freeze.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhFreezeThreadById(\n    _Out_ PHANDLE ThreadStateChangeHandle,\n    _In_ HANDLE ThreadId\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n    HANDLE threadStateChangeHandle;\n\n    status = PhOpenThread(\n        &threadHandle,\n        THREAD_SET_INFORMATION | THREAD_SUSPEND_RESUME,\n        ThreadId\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhFreezeThread(\n        &threadStateChangeHandle,\n        threadHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ThreadStateChangeHandle = threadStateChangeHandle;\n    }\n\n    NtClose(threadHandle);\n\n    return status;\n}\n\n/**\n * Resumes a suspended thread using the thread state change mechanism.\n *\n * \\param ThreadStateChangeHandle A handle to the thread state change object, obtained from a prior suspend operation.\n * \\param ThreadHandle A handle to the thread to be resumed.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhThawThread(\n    _In_ HANDLE ThreadStateChangeHandle,\n    _In_ HANDLE ThreadHandle\n    )\n{\n    NTSTATUS status;\n\n    if (!NtChangeThreadState_Import())\n    {\n        return STATUS_PROCEDURE_NOT_FOUND;\n    }\n\n    status = NtChangeThreadState_Import()(\n        ThreadStateChangeHandle,\n        ThreadHandle,\n        ThreadStateChangeResume,\n        NULL,\n        0,\n        0\n        );\n\n    return status;\n}\n\n/**\n * Resumes (thaws) a suspended thread by its ID using a thread state change handle.\n *\n * \\param ThreadStateChangeHandle A handle to the thread state change object, obtained from a previous suspend operation.\n * \\param ThreadId The ID of the thread to resume.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhThawThreadById(\n    _In_ HANDLE ThreadStateChangeHandle,\n    _In_ HANDLE ThreadId\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n\n    status = PhOpenThread(\n        &threadHandle,\n        THREAD_SET_INFORMATION | THREAD_SUSPEND_RESUME,\n        ThreadId\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhThawThread(\n        ThreadStateChangeHandle,\n        threadHandle\n        );\n\n    NtClose(threadHandle);\n\n    return status;\n}\n\n//\n// Process execution request support\n//\n\nstatic PH_INITONCE PhExecutionRequestInitOnce = PH_INITONCE_INIT;\nstatic PPH_HASHTABLE PhExecutionRequestHashtable = NULL;\n\ntypedef struct _PH_EXECUTIONREQUEST_CACHE_ENTRY\n{\n    HANDLE ProcessId;\n    HANDLE ExecutionRequestHandle;\n} PH_EXECUTIONREQUEST_CACHE_ENTRY, *PPH_EXECUTIONREQUEST_CACHE_ENTRY;\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nstatic BOOLEAN NTAPI PhExecutionRequestHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    return\n        ((PPH_EXECUTIONREQUEST_CACHE_ENTRY)Entry1)->ProcessId ==\n        ((PPH_EXECUTIONREQUEST_CACHE_ENTRY)Entry2)->ProcessId;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nstatic ULONG NTAPI PhExecutionRequestHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return HandleToUlong(((PPH_EXECUTIONREQUEST_CACHE_ENTRY)Entry)->ProcessId) / 4;\n}\n\n/**\n * Initializes the execution request table.\n *\n * This function sets up the execution request table, which is used to manage\n * and handle execution requests within the system.\n * \\return TRUE if the initialization succeeds, FALSE otherwise.\n */\nBOOLEAN PhInitializeExecutionRequestTable(\n    VOID\n    )\n{\n    if (PhBeginInitOnce(&PhExecutionRequestInitOnce))\n    {\n        PhExecutionRequestHashtable = PhCreateHashtable(\n            sizeof(PH_EXECUTIONREQUEST_CACHE_ENTRY),\n            PhExecutionRequestHashtableEqualFunction,\n            PhExecutionRequestHashtableHashFunction,\n            1\n            );\n\n        PhEndInitOnce(&PhExecutionRequestInitOnce);\n    }\n\n    return TRUE;\n}\n\n/**\n * Determines whether execution is required for the specified process.\n *\n * This function checks if the process identified by the given process ID requires\n * execution, typically in the context of process management or debugging.\n *\n * \\param ProcessId A handle to the process ID to check.\n * \\return TRUE if execution is required for the process, FALSE otherwise.\n */\nBOOLEAN PhIsProcessExecutionRequired(\n    _In_ HANDLE ProcessId\n    )\n{\n    if (PhInitializeExecutionRequestTable())\n    {\n        PH_EXECUTIONREQUEST_CACHE_ENTRY entry;\n\n        entry.ProcessId = ProcessId;\n\n        if (PhFindEntryHashtable(PhExecutionRequestHashtable, &entry))\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Enables the execution required state for the specified process.\n * This prevents the process from being terminated or suspended by the system\n * under certain conditions, ensuring it remains running.\n *\n * \\param ProcessId The handle to the process for which to enable execution required.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhProcessExecutionRequiredEnable(\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    HANDLE requestHandle;\n\n    if (PhInitializeExecutionRequestTable())\n    {\n        PH_EXECUTIONREQUEST_CACHE_ENTRY entry;\n\n        entry.ProcessId = ProcessId;\n\n        if (PhFindEntryHashtable(PhExecutionRequestHashtable, &entry))\n        {\n            return STATUS_SUCCESS;\n        }\n    }\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_SET_LIMITED_INFORMATION,\n        ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhCreateExecutionRequiredRequest(\n        processHandle,\n        &requestHandle\n        );\n\n    NtClose(processHandle);\n\n    if (NT_SUCCESS(status))\n    {\n        PH_EXECUTIONREQUEST_CACHE_ENTRY entry;\n\n        entry.ProcessId = ProcessId;\n        entry.ExecutionRequestHandle = requestHandle;\n\n        PhAddEntryHashtable(PhExecutionRequestHashtable, &entry);\n    }\n\n    return status;\n}\n\n/**\n * Disables the execution required state for the specified process.\n *\n * \\param ProcessId A handle to the process for which the execution required state should be disabled.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhProcessExecutionRequiredDisable(\n    _In_ HANDLE ProcessId\n    )\n{\n    if (PhInitializeExecutionRequestTable())\n    {\n        PH_EXECUTIONREQUEST_CACHE_ENTRY lookupEntry;\n        PPH_EXECUTIONREQUEST_CACHE_ENTRY entry;\n\n        lookupEntry.ProcessId = ProcessId;\n\n        if (entry = PhFindEntryHashtable(PhExecutionRequestHashtable, &lookupEntry))\n        {\n            HANDLE requestHandle = entry->ExecutionRequestHandle;\n\n            PhRemoveEntryHashtable(PhExecutionRequestHashtable, &lookupEntry);\n\n            if (requestHandle)\n            {\n                return PhDestroyExecutionRequiredRequest(requestHandle);\n            }\n        }\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n// KnownDLLs cache support\n\nstatic PH_INITONCE PhKnownDllsInitOnce = PH_INITONCE_INIT;\nstatic PPH_HASHTABLE PhKnownDllsHashtable = NULL;\n\ntypedef struct _PH_KNOWNDLL_CACHE_ENTRY\n{\n    PPH_STRING FileName;\n} PH_KNOWNDLL_CACHE_ENTRY, *PPH_KNOWNDLL_CACHE_ENTRY;\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nstatic BOOLEAN NTAPI PhKnownDllsHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_KNOWNDLL_CACHE_ENTRY entry1 = (PPH_KNOWNDLL_CACHE_ENTRY)Entry1;\n    PPH_KNOWNDLL_CACHE_ENTRY entry2 = (PPH_KNOWNDLL_CACHE_ENTRY)Entry2;\n\n    return PhEqualStringRef(&entry1->FileName->sr, &entry2->FileName->sr, FALSE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nstatic ULONG NTAPI PhKnownDllsHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_KNOWNDLL_CACHE_ENTRY entry = (PPH_KNOWNDLL_CACHE_ENTRY)Entry;\n\n    return PhHashStringRefEx(&entry->FileName->sr, FALSE, PH_STRING_HASH_XXH32);\n}\n\n_Function_class_(PH_ENUM_DIRECTORY_OBJECTS)\nstatic NTSTATUS NTAPI PhpKnownDllObjectsCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PPH_STRINGREF Name,\n    _In_ PPH_STRINGREF TypeName,\n    _In_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    HANDLE sectionHandle;\n    PVOID baseAddress;\n    SIZE_T viewSize;\n    PPH_STRING fileName;\n\n    status = PhOpenSection(\n        &sectionHandle,\n        SECTION_MAP_READ,\n        RootDirectory,\n        Name\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    baseAddress = NULL;\n    viewSize = PAGE_SIZE;\n\n    status = PhMapViewOfSection(\n        sectionHandle,\n        NtCurrentProcess(),\n        &baseAddress,\n        0,\n        NULL,\n        &viewSize,\n        ViewUnmap,\n        WindowsVersion < WINDOWS_10_RS2 ? 0 : MEM_MAPPED,\n        PAGE_READONLY\n        );\n\n    NtClose(sectionHandle);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcessMappedFileName(\n        NtCurrentProcess(),\n        baseAddress,\n        &fileName\n        );\n\n    PhUnmapViewOfSection(NtCurrentProcess(), baseAddress);\n\n    if (NT_SUCCESS(status))\n    {\n        PH_KNOWNDLL_CACHE_ENTRY entry;\n\n        entry.FileName = fileName;\n\n        PhAddEntryHashtable(PhKnownDllsHashtable, &entry);\n    }\n\nCleanupExit:\n    return STATUS_SUCCESS; // continue enumeration (dmex)\n}\n\n/**\n * Initializes the known DLLs for the system based on the provided object name.\n * \\param ObjectName A pointer to a constant string reference specifying the object name.\n */\nVOID PhInitializeKnownDlls(\n    _In_ PCPH_STRINGREF ObjectName\n    )\n{\n    HANDLE directoryHandle;\n\n    if (NT_SUCCESS(PhOpenDirectoryObject(\n        &directoryHandle,\n        DIRECTORY_QUERY,\n        NULL,\n        ObjectName\n        )))\n    {\n        PhEnumDirectoryObjects(\n            directoryHandle,\n            PhpKnownDllObjectsCallback,\n            NULL\n            );\n        NtClose(directoryHandle);\n    }\n}\n\n/**\n * Initializes the Known DLLs table used by the system.\n * \\return TRUE if the Known DLLs table was successfully initialized, FALSE otherwise.\n */\nBOOLEAN PhInitializeKnownDllsTable(\n    VOID\n    )\n{\n    if (PhBeginInitOnce(&PhKnownDllsInitOnce))\n    {\n        static const PH_STRINGREF KnownDllsObjectName = PH_STRINGREF_INIT(L\"\\\\KnownDlls\");\n        static const PH_STRINGREF KnownDlls32ObjectName = PH_STRINGREF_INIT(L\"\\\\KnownDlls32\");\n#ifdef _ARM64_\n        static const PH_STRINGREF KnownDllsArm32ObjectName = PH_STRINGREF_INIT(L\"\\\\KnownDllsArm32\");\n        static const PH_STRINGREF KnownDllsChpe32ObjectName = PH_STRINGREF_INIT(L\"\\\\KnownDllsChpe32\");\n#endif\n\n        PhKnownDllsHashtable = PhCreateHashtable(\n            sizeof(PH_KNOWNDLL_CACHE_ENTRY),\n            PhKnownDllsHashtableEqualFunction,\n            PhKnownDllsHashtableHashFunction,\n            10\n            );\n\n        PhInitializeKnownDlls(&KnownDllsObjectName);\n        PhInitializeKnownDlls(&KnownDlls32ObjectName);\n#ifdef _ARM64_\n        PhInitializeKnownDlls(&KnownDllsArm32ObjectName);\n        PhInitializeKnownDlls(&KnownDllsChpe32ObjectName);\n#endif\n        PhEndInitOnce(&PhKnownDllsInitOnce);\n    }\n\n    return TRUE;\n}\n\n/**\n * Checks if the specified file name corresponds to a known DLL.\n *\n * \\param FileName A pointer to a PPH_STRING containing the file name to check.\n * \\return TRUE if the file name is a known DLL, FALSE otherwise.\n */\nBOOLEAN PhIsKnownDllFileName(\n    _In_ PPH_STRING FileName\n    )\n{\n    if (PhInitializeKnownDllsTable())\n    {\n        PH_KNOWNDLL_CACHE_ENTRY entry;\n\n        entry.FileName = FileName;\n\n        if (PhFindEntryHashtable(PhKnownDllsHashtable, &entry))\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Retrieves the system processor performance distribution information.\n *\n * \\param Buffer A pointer to the performance distribution data for all processors in the system.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSystemProcessorPerformanceDistribution(\n    _Out_ PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG attempts;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQuerySystemInformation(\n        SystemProcessorPerformanceDistribution,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n    attempts = 0;\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQuerySystemInformation(\n            SystemProcessorPerformanceDistribution,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n        attempts++;\n    }\n\n    if (NT_SUCCESS(status))\n        *Buffer = buffer;\n    else\n        PhFree(buffer);\n\n    return status;\n}\n\n/**\n * Retrieves the processor performance distribution information for a specified processor group.\n *\n * \\param ProcessorGroup The processor group number for which to retrieve performance distribution information.\n * \\param Buffer A pointer to a variable that receives a pointer to a SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION \n * structure containing the performance distribution data.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSystemProcessorPerformanceDistributionEx(\n    _In_ USHORT ProcessorGroup,\n    _Out_ PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG attempts;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQuerySystemInformationEx(\n        SystemProcessorPerformanceDistribution,\n        &ProcessorGroup,\n        sizeof(USHORT),\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n    attempts = 0;\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQuerySystemInformationEx(\n            SystemProcessorPerformanceDistribution,\n            &ProcessorGroup,\n            sizeof(USHORT),\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n        attempts++;\n    }\n\n    if (NT_SUCCESS(status))\n        *Buffer = buffer;\n    else\n        PhFree(buffer);\n\n    return status;\n}\n\n/**\n * Retrieves information about the logical processors in the system.\n *\n * \\param RelationshipType The relationship type to filter the logical processor information (e.g., processor core, NUMA node).\n * \\param Buffer A pointer to a variable that receives a pointer to a buffer containing an array of SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX structures.\n * \\param BufferLength A pointer to a variable that on input specifies the size of the buffer pointed to by Buffer,\n * and on output receives the number of bytes returned or required.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSystemLogicalProcessorInformation(\n    _In_ LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,\n    _Out_ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Buffer,\n    _Out_ PULONG BufferLength\n    )\n{\n    static ULONG initialBufferSize[] = { 0x200, 0x80, 0x100, 0x1000 };\n    NTSTATUS status;\n    ULONG classIndex;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG attempts;\n\n    switch (RelationshipType)\n    {\n    case RelationProcessorCore:\n        classIndex = 0;\n        break;\n    case RelationProcessorPackage:\n        classIndex = 1;\n        break;\n    case RelationGroup:\n        classIndex = 2;\n        break;\n    case RelationAll:\n        classIndex = 3;\n        break;\n    default:\n        return STATUS_INVALID_INFO_CLASS;\n    }\n\n    bufferSize = initialBufferSize[classIndex];\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQuerySystemInformationEx(\n        SystemLogicalProcessorAndGroupInformation,\n        &RelationshipType,\n        sizeof(LOGICAL_PROCESSOR_RELATIONSHIP),\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n    attempts = 0;\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQuerySystemInformationEx(\n            SystemLogicalProcessorAndGroupInformation,\n            &RelationshipType,\n            sizeof(LOGICAL_PROCESSOR_RELATIONSHIP),\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n        attempts++;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x100000) initialBufferSize[classIndex] = bufferSize;\n    *Buffer = buffer;\n    *BufferLength = bufferSize;\n\n    return status;\n}\n\n/**\n * Retrieves information about the logical processor relationships in the system.\n *\n * \\param LogicalProcessorInformation A pointer to a PH_LOGICAL_PROCESSOR_INFORMATION structure \n * that receives the logical processor relationship information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSystemLogicalProcessorRelationInformation(\n    _Out_ PPH_LOGICAL_PROCESSOR_INFORMATION LogicalProcessorInformation\n    )\n{\n    NTSTATUS status;\n    ULONG logicalInformationLength = 0;\n    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX logicalInformation;\n\n    status = PhGetSystemLogicalProcessorInformation(\n        RelationAll,\n        &logicalInformation,\n        &logicalInformationLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        ULONG processorCoreCount = 0;\n        ULONG processorNumaCount = 0;\n        ULONG processorLogicalCount = 0;\n        ULONG processorPackageCount = 0;\n\n        for (\n            PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX processorInfo = logicalInformation;\n            (ULONG_PTR)processorInfo < (ULONG_PTR)PTR_ADD_OFFSET(logicalInformation, logicalInformationLength);\n            processorInfo = PTR_ADD_OFFSET(processorInfo, processorInfo->Size)\n            )\n        {\n            switch (processorInfo->Relationship)\n            {\n            case RelationProcessorCore:\n                {\n                    processorCoreCount++;\n\n                    for (USHORT j = 0; j < processorInfo->Processor.GroupCount; j++)\n                    {\n                        processorLogicalCount += PhCountBitsUlongPtr(processorInfo->Processor.GroupMask[j].Mask); // RtlNumberOfSetBitsUlongPtr\n                    }\n                }\n                break;\n            case RelationNumaNode:\n                processorNumaCount++;\n                break;\n            case RelationProcessorPackage:\n                processorPackageCount++;\n                break;\n            }\n        }\n\n        memset(LogicalProcessorInformation, 0, sizeof(PH_LOGICAL_PROCESSOR_INFORMATION));\n        LogicalProcessorInformation->ProcessorCoreCount = processorCoreCount;\n        LogicalProcessorInformation->ProcessorNumaCount = processorNumaCount;\n        LogicalProcessorInformation->ProcessorLogicalCount = processorLogicalCount;\n        LogicalProcessorInformation->ProcessorPackageCount = processorPackageCount;\n\n        PhFree(logicalInformation);\n    }\n\n    return status;\n}\n\n// based on RtlIsProcessorFeaturePresent (dmex)\n/**\n * Checks if a specific processor feature is present on the system.\n *\n * This function first checks if the current Windows version is older than a specified version\n * and if the requested processor feature index is within the valid range. If so, it queries\n * the processor feature from the user shared data. Otherwise, it calls the system API\n * `IsProcessorFeaturePresent` to determine the presence of the feature.\n *\n * \\param ProcessorFeature The index of the processor feature to check.\n * \\return TRUE if the processor feature is present, FALSE otherwise.\n */\nBOOLEAN PhIsProcessorFeaturePresent(\n    _In_ ULONG ProcessorFeature\n    )\n{\n    if (WindowsVersion < WINDOWS_NEW && ProcessorFeature < PROCESSOR_FEATURE_MAX)\n    {\n        return USER_SHARED_DATA->ProcessorFeatures[ProcessorFeature];\n    }\n\n    return !!IsProcessorFeaturePresent(ProcessorFeature); // RtlIsProcessorFeaturePresent\n}\n\n/**\n * Retrieves the processor number information for the current processor.\n *\n * \\param ProcessorNumber A pointer to a PROCESSOR_NUMBER structure that receives the processor number details.\n */\nVOID PhGetCurrentProcessorNumber(\n    _Out_ PPROCESSOR_NUMBER ProcessorNumber\n    )\n{\n    //if (PhIsProcessorFeaturePresent(PF_RDPID_INSTRUCTION_AVAILABLE))\n//    _rdpid_u32();\n//if (PhIsProcessorFeaturePresent(PF_RDTSCP_INSTRUCTION_AVAILABLE))\n//    __rdtscp();\n\n    memset(ProcessorNumber, 0, sizeof(PROCESSOR_NUMBER));\n\n    RtlGetCurrentProcessorNumberEx(ProcessorNumber);\n}\n\n// based on GetActiveProcessorCount (dmex)\n/**\n * Retrieves the number of active processors in the specified processor group.\n *\n * \\param ProcessorGroup The processor group for which to retrieve the active processor count.\n * \\return The number of active processors in the specified group.\n */\nUSHORT PhGetActiveProcessorCount(\n    _In_ USHORT ProcessorGroup\n    )\n{\n    if (PhSystemProcessorInformation.ActiveProcessorCount)\n    {\n        USHORT numberOfProcessors = 0;\n\n        if (ProcessorGroup == ALL_PROCESSOR_GROUPS)\n        {\n            for (USHORT i = 0; i < PhSystemProcessorInformation.NumberOfProcessorGroups; i++)\n            {\n                numberOfProcessors += PhSystemProcessorInformation.ActiveProcessorCount[i];\n            }\n        }\n        else\n        {\n            if (ProcessorGroup < PhSystemProcessorInformation.NumberOfProcessorGroups)\n            {\n                numberOfProcessors = PhSystemProcessorInformation.ActiveProcessorCount[ProcessorGroup];\n            }\n        }\n\n        return numberOfProcessors;\n    }\n    else\n    {\n        return PhSystemProcessorInformation.NumberOfProcessors;\n    }\n}\n\n/**\n * Retrieves the processor number structure corresponding to a given processor index.\n *\n * \\param ProcessorIndex The zero-based index of the processor.\n * \\param ProcessorNumber A pointer to a PPH_PROCESSOR_NUMBER structure that receives the processor number information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessorNumberFromIndex(\n    _In_ ULONG ProcessorIndex,\n    _Out_ PPH_PROCESSOR_NUMBER ProcessorNumber\n    )\n{\n    USHORT processorIndex = 0;\n\n    for (USHORT processorGroup = 0; processorGroup < PhSystemProcessorInformation.NumberOfProcessorGroups; processorGroup++)\n    {\n        USHORT processorCount = PhGetActiveProcessorCount(processorGroup);\n\n        for (USHORT processorNumber = 0; processorNumber < processorCount; processorNumber++)\n        {\n            if (processorIndex++ == ProcessorIndex)\n            {\n                memset(ProcessorNumber, 0, sizeof(PH_PROCESSOR_NUMBER));\n                ProcessorNumber->Group = processorGroup;\n                ProcessorNumber->Number = processorNumber;\n                return STATUS_SUCCESS;\n            }\n        }\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n/**\n * Retrieves the active processor affinity mask for a specified processor group.\n *\n * \\param ProcessorGroup The processor group number for which to retrieve the active affinity mask.\n * \\param ActiveProcessorMask A pointer to a variable that receives the active processor affinity mask for the specified group.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessorGroupActiveAffinityMask(\n    _In_ USHORT ProcessorGroup,\n    _Out_ PKAFFINITY ActiveProcessorMask\n    )\n{\n    NTSTATUS status;\n    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX processorInformation;\n    ULONG processorInformationLength;\n\n    status = PhGetSystemLogicalProcessorInformation(\n        RelationGroup,\n        &processorInformation,\n        &processorInformationLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (ProcessorGroup < processorInformation->Group.ActiveGroupCount)\n        {\n            *ActiveProcessorMask = processorInformation->Group.GroupInfo[ProcessorGroup].ActiveProcessorMask;\n        }\n        else\n        {\n            status = STATUS_UNSUCCESSFUL;\n        }\n\n        PhFree(processorInformation);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the system affinity mask for active processors.\n *\n * \\param[out] ActiveProcessorsAffinityMask Pointer to a variable that receives the affinity mask representing active processors in the system.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessorSystemAffinityMask(\n    _Out_ PKAFFINITY ActiveProcessorsAffinityMask\n    )\n{\n    if (PhSystemProcessorInformation.SingleProcessorGroup)\n    {\n        *ActiveProcessorsAffinityMask = PhSystemBasicInformation.ActiveProcessorsAffinityMask;\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        PROCESSOR_NUMBER processorNumber;\n\n        PhGetCurrentProcessorNumber(&processorNumber);\n\n        return PhGetProcessorGroupActiveAffinityMask(processorNumber.Group, ActiveProcessorsAffinityMask);\n    }\n}\n\n// rev from GetNumaHighestNodeNumber (dmex)\n/**\n * Retrieves the highest NUMA (Non-Uniform Memory Access) node number available on the system.\n *\n * \\param[out] NodeNumber A pointer to a variable that receives the highest NUMA node number.\n * \\return Returns an NTSTATUS code indicating success or failure of the operation.\n * \\remarks The function queries the system for NUMA topology information and stores the highest node number\n * in the variable pointed to by NodeNumber. The value is zero-based; for example, if the system has\n * two NUMA nodes, the highest node number will be 1.\n */\nNTSTATUS PhGetNumaHighestNodeNumber(\n    _Out_ PUSHORT NodeNumber\n    )\n{\n    NTSTATUS status;\n    SYSTEM_NUMA_INFORMATION numaProcessorMap;\n\n    status = NtQuerySystemInformation(\n        SystemNumaProcessorMap,\n        &numaProcessorMap,\n        sizeof(SYSTEM_NUMA_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *NodeNumber = (USHORT)numaProcessorMap.HighestNodeNumber;\n    }\n\n    return status;\n}\n\n// rev from GetNumaProcessorNodeEx (dmex)\n/**\n * Retrieves the NUMA node number for a specified processor.\n *\n * \\param ProcessorNumber A pointer to a PPH_PROCESSOR_NUMBER structure that specifies the processor for which to retrieve the NUMA node.\n * \\param NodeNumber A pointer to a variable that receives the NUMA node number associated with the specified processor.\n * \\return Returns TRUE if the NUMA node number was successfully retrieved; otherwise, returns FALSE.\n */\nBOOLEAN PhGetNumaProcessorNode(\n    _In_ PPH_PROCESSOR_NUMBER ProcessorNumber,\n    _Out_ PUSHORT NodeNumber\n    )\n{\n    NTSTATUS status;\n    SYSTEM_NUMA_INFORMATION numaProcessorMap;\n    USHORT processorNode = 0;\n\n    if (ProcessorNumber->Group >= 20 || ProcessorNumber->Number >= MAXIMUM_PROC_PER_GROUP)\n    {\n        *NodeNumber = USHRT_MAX;\n        return FALSE;\n    }\n\n    status = NtQuerySystemInformation(\n        SystemNumaProcessorMap,\n        &numaProcessorMap,\n        sizeof(SYSTEM_NUMA_INFORMATION),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        *NodeNumber = USHRT_MAX;\n        return FALSE;\n    }\n\n    while (\n        numaProcessorMap.ActiveProcessorsGroupAffinity[processorNode].Group != ProcessorNumber->Group ||\n        (numaProcessorMap.ActiveProcessorsGroupAffinity[processorNode].Mask & AFFINITY_MASK(ProcessorNumber->Number)) == 0\n        )\n    {\n        if (++processorNode > numaProcessorMap.HighestNodeNumber)\n        {\n            *NodeNumber = USHRT_MAX;\n            return FALSE;\n        }\n    }\n\n    *NodeNumber = processorNode;\n    return TRUE;\n}\n\n// rev from GetNumaProximityNodeEx (dmex)\n/**\n * Retrieves the NUMA (Non-Uniform Memory Access) node number associated with a given proximity ID.\n *\n * \\param ProximityId The proximity ID for which to retrieve the corresponding NUMA node number.\n * \\param NodeNumber A pointer to a variable that receives the NUMA node number associated with the specified proximity ID.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetNumaProximityNode(\n    _In_ ULONG ProximityId,\n    _Out_ PUSHORT NodeNumber\n    )\n{\n    NTSTATUS status;\n    SYSTEM_NUMA_PROXIMITY_MAP numaProximityMap;\n\n    memset(&numaProximityMap, 0, sizeof(SYSTEM_NUMA_PROXIMITY_MAP));\n    numaProximityMap.NodeProximityId = ProximityId;\n\n    status = NtQuerySystemInformation(\n        SystemNumaProximityNodeInformation,\n        &numaProximityMap,\n        sizeof(SYSTEM_NUMA_PROXIMITY_MAP),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *NodeNumber = numaProximityMap.NodeNumber;\n    }\n\n    return status;\n}\n\nDECLSPEC_GUARDNOCF\nstatic NTSTATUS PhpSetInformationVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ VIRTUAL_MEMORY_INFORMATION_CLASS VmInformationClass,\n    _In_ ULONG_PTR NumberOfEntries,\n    _In_reads_(NumberOfEntries) PMEMORY_RANGE_ENTRY VirtualAddresses,\n    _In_reads_bytes_(VmInformationLength) PVOID VmInformation,\n    _In_ ULONG VmInformationLength\n    )\n{\n    assert(NtSetInformationVirtualMemory_Import());\n\n    //\n    // Our custom loader logic creates chicken and egg problem. To register\n    // valid CFG call targets, we need access to NtSetInformationVirtualMemory,\n    // but that function itself cannot be marked as a valid target until it has\n    // been imported. Here we wrap the call in a routine that disables CFG.\n    //\n    return NtSetInformationVirtualMemory_Import()(\n        ProcessHandle,\n        VmInformationClass,\n        NumberOfEntries,\n        VirtualAddresses,\n        VmInformation,\n        VmInformationLength\n        );\n}\n\n// rev from PrefetchVirtualMemory (dmex)\n/**\n * Provides an efficient mechanism to bring into memory potentially discontiguous virtual address ranges in a process address space.\n *\n * \\param ProcessHandle A handle to the process whose virtual address ranges are to be prefetched.\n * \\param NumberOfEntries Number of entries in the array pointed to by the VirtualAddresses parameter.\n * \\param VirtualAddresses A pointer to an array of MEMORY_RANGE_ENTRY structures which each specify a virtual address range\n * to be prefetched. The virtual address ranges may cover any part of the process address space accessible by the target process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhPrefetchVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ SIZE_T NumberOfEntries,\n    _In_ PMEMORY_RANGE_ENTRY VirtualAddresses\n    )\n{\n    NTSTATUS status;\n    ULONG prefetchInformationFlags;\n\n    if (!NtSetInformationVirtualMemory_Import())\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    memset(&prefetchInformationFlags, 0, sizeof(prefetchInformationFlags));\n\n    status = PhpSetInformationVirtualMemory(\n        ProcessHandle,\n        VmPrefetchInformation,\n        NumberOfEntries,\n        VirtualAddresses,\n        &prefetchInformationFlags,\n        sizeof(prefetchInformationFlags)\n        );\n\n    return status;\n}\n\n// rev from OfferVirtualMemory (dmex)\n//NTSTATUS PhOfferVirtualMemory(\n//    _In_ HANDLE ProcessHandle,\n//    _In_ PVOID VirtualAddress,\n//    _In_ SIZE_T NumberOfBytes,\n//    _In_ MEMORY_PAGE_PRIORITY_INFORMATION Priority\n//    )\n//{\n//    NTSTATUS status;\n//    MEMORY_RANGE_ENTRY virtualMemoryRange;\n//    ULONG virtualMemoryFlags;\n//\n//    if (!NtSetInformationVirtualMemory_Import())\n//        return STATUS_PROCEDURE_NOT_FOUND;\n//\n//    // TODO: NtQueryVirtualMemory (dmex)\n//\n//    memset(&virtualMemoryRange, 0, sizeof(MEMORY_RANGE_ENTRY));\n//    virtualMemoryRange.VirtualAddress = VirtualAddress;\n//    virtualMemoryRange.NumberOfBytes = NumberOfBytes;\n//\n//    memset(&virtualMemoryFlags, 0, sizeof(virtualMemoryFlags));\n//    virtualMemoryFlags = Priority;\n//\n//    status = PhpSetInformationVirtualMemory(\n//        ProcessHandle,\n//        VmPagePriorityInformation,\n//        1,\n//        &virtualMemoryRange,\n//        &virtualMemoryFlags,\n//        sizeof(virtualMemoryFlags)\n//        );\n//\n//    return status;\n//}\n//\n// rev from DiscardVirtualMemory (dmex)\n//NTSTATUS PhDiscardVirtualMemory(\n//    _In_ HANDLE ProcessHandle,\n//    _In_ PVOID VirtualAddress,\n//    _In_ SIZE_T NumberOfBytes\n//    )\n//{\n//    NTSTATUS status;\n//    MEMORY_RANGE_ENTRY virtualMemoryRange;\n//    ULONG virtualMemoryFlags;\n//\n//    if (!NtSetInformationVirtualMemory_Import())\n//        return STATUS_PROCEDURE_NOT_FOUND;\n//\n//    memset(&virtualMemoryRange, 0, sizeof(MEMORY_RANGE_ENTRY));\n//    virtualMemoryRange.VirtualAddress = VirtualAddress;\n//    virtualMemoryRange.NumberOfBytes = NumberOfBytes;\n//\n//    memset(&virtualMemoryFlags, 0, sizeof(virtualMemoryFlags));\n//\n//    status = PhpSetInformationVirtualMemory(\n//        ProcessHandle,\n//        VmPagePriorityInformation,\n//        1,\n//        &virtualMemoryRange,\n//        &virtualMemoryFlags,\n//        sizeof(virtualMemoryFlags)\n//        );\n//\n//    return status;\n//}\n\n/**\n * Sets the priority of a range of virtual memory pages in a specified process.\n *\n * \\param ProcessHandle Handle to the process whose memory pages will be modified.\n * \\param PagePriority The priority value to assign to the memory pages.\n * \\param VirtualAddress Pointer to the starting address of the memory region.\n * \\param NumberOfBytes Size, in bytes, of the memory region to modify.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetVirtualMemoryPagePriority(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG PagePriority,\n    _In_ PVOID VirtualAddress,\n    _In_ SIZE_T NumberOfBytes\n    )\n{\n    NTSTATUS status;\n    MEMORY_RANGE_ENTRY virtualMemoryRange;\n\n    memset(&virtualMemoryRange, 0, sizeof(MEMORY_RANGE_ENTRY));\n    virtualMemoryRange.VirtualAddress = VirtualAddress;\n    virtualMemoryRange.NumberOfBytes = NumberOfBytes;\n\n    status = PhpSetInformationVirtualMemory(\n        ProcessHandle,\n        VmPagePriorityInformation,\n        1,\n        &virtualMemoryRange,\n        &PagePriority,\n        sizeof(PagePriority)\n        );\n\n    return status;\n}\n\n// rev from SetProcessValidCallTargets (dmex)\n//NTSTATUS PhSetProcessValidCallTarget(\n//    _In_ HANDLE ProcessHandle,\n//    _In_ PVOID VirtualAddress\n//    )\n//{\n//    NTSTATUS status;\n//    MEMORY_BASIC_INFORMATION basicInfo;\n//    MEMORY_RANGE_ENTRY cfgCallTargetRangeInfo;\n//    CFG_CALL_TARGET_INFO cfgCallTargetInfo;\n//    CFG_CALL_TARGET_LIST_INFORMATION cfgCallTargetListInfo;\n//    ULONG numberOfEntriesProcessed = 0;\n//\n//    if (!NtSetInformationVirtualMemory_Import())\n//        return STATUS_PROCEDURE_NOT_FOUND;\n//\n//    status = NtQueryVirtualMemory(\n//        ProcessHandle,\n//        VirtualAddress,\n//        MemoryBasicInformation,\n//        &basicInfo,\n//        sizeof(MEMORY_BASIC_INFORMATION),\n//        NULL\n//        );\n//\n//    if (!NT_SUCCESS(status))\n//        return status;\n//\n//    memset(&cfgCallTargetInfo, 0, sizeof(CFG_CALL_TARGET_INFO));\n//    cfgCallTargetInfo.Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)basicInfo.AllocationBase;\n//    cfgCallTargetInfo.Flags = CFG_CALL_TARGET_VALID;\n//\n//    memset(&cfgCallTargetRangeInfo, 0, sizeof(MEMORY_RANGE_ENTRY));\n//    cfgCallTargetRangeInfo.VirtualAddress = basicInfo.AllocationBase;\n//    cfgCallTargetRangeInfo.NumberOfBytes = basicInfo.RegionSize;\n//\n//    memset(&cfgCallTargetListInfo, 0, sizeof(CFG_CALL_TARGET_LIST_INFORMATION));\n//    cfgCallTargetListInfo.NumberOfEntries = 1;\n//    cfgCallTargetListInfo.Reserved = 0;\n//    cfgCallTargetListInfo.NumberOfEntriesProcessed = &numberOfEntriesProcessed;\n//    cfgCallTargetListInfo.CallTargetInfo = &cfgCallTargetInfo;\n//\n//    status = PhpSetInformationVirtualMemory(\n//        ProcessHandle,\n//        VmCfgCallTargetInformation,\n//        1,\n//        &cfgCallTargetRangeInfo,\n//        &cfgCallTargetListInfo,\n//        sizeof(CFG_CALL_TARGET_LIST_INFORMATION)\n//        );\n//\n//    if (status == STATUS_INVALID_PAGE_PROTECTION)\n//        status = STATUS_SUCCESS;\n//\n//    return status;\n//}\n\n// rev from RtlGuardGrantSuppressedCallAccess (dmex)\n/**\n * Grants suppressed call access to a specific virtual address in the target process.\n *\n * \\param ProcessHandle Handle to the process in which access is to be granted.\n * \\param VirtualAddress Pointer to the virtual address for which suppressed call access is requested.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGuardGrantSuppressedCallAccess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress\n    )\n{\n    NTSTATUS status;\n    MEMORY_RANGE_ENTRY cfgCallTargetRangeInfo;\n    CFG_CALL_TARGET_INFO cfgCallTargetInfo;\n    CFG_CALL_TARGET_LIST_INFORMATION cfgCallTargetListInfo;\n    ULONG numberOfEntriesProcessed = 0;\n\n    if (!NtSetInformationVirtualMemory_Import())\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    memset(&cfgCallTargetRangeInfo, 0, sizeof(MEMORY_RANGE_ENTRY));\n    cfgCallTargetRangeInfo.VirtualAddress = PAGE_ALIGN(VirtualAddress);\n    cfgCallTargetRangeInfo.NumberOfBytes = PAGE_SIZE;\n\n    memset(&cfgCallTargetInfo, 0, sizeof(CFG_CALL_TARGET_INFO));\n    cfgCallTargetInfo.Offset = BYTE_OFFSET(VirtualAddress);\n    cfgCallTargetInfo.Flags = CFG_CALL_TARGET_VALID;\n\n    memset(&cfgCallTargetListInfo, 0, sizeof(CFG_CALL_TARGET_LIST_INFORMATION));\n    cfgCallTargetListInfo.NumberOfEntries = 1;\n    cfgCallTargetListInfo.Reserved = 0;\n    cfgCallTargetListInfo.NumberOfEntriesProcessed = &numberOfEntriesProcessed;\n    cfgCallTargetListInfo.CallTargetInfo = &cfgCallTargetInfo;\n\n    status = PhpSetInformationVirtualMemory(\n        ProcessHandle,\n        VmCfgCallTargetInformation,\n        1,\n        &cfgCallTargetRangeInfo,\n        &cfgCallTargetListInfo,\n        sizeof(CFG_CALL_TARGET_LIST_INFORMATION)\n        );\n\n    if (status == STATUS_INVALID_PAGE_PROTECTION)\n        status = STATUS_SUCCESS;\n\n    return status;\n}\n\n// rev from RtlDisableXfgOnTarget (dmex)\n/**\n * Disables Control Flow Guard (CFG/XFG) protection on a specified memory region in a target process.\n *\n * \\param ProcessHandle Handle to the target process.\n * \\param VirtualAddress Pointer to the base address of the memory region to modify.\n * \\return NTSTATUS code indicating success or failure of the operation.\n */\nNTSTATUS PhDisableXfgOnTarget(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID VirtualAddress\n    )\n{\n    NTSTATUS status;\n    PS_SYSTEM_DLL_INIT_BLOCK systemDllInitBlock;\n    MEMORY_RANGE_ENTRY cfgCallTargetRangeInfo;\n    CFG_CALL_TARGET_INFO cfgCallTargetInfo;\n    CFG_CALL_TARGET_LIST_INFORMATION cfgCallTargetListInfo;\n    ULONG numberOfEntriesProcessed = 0;\n\n    if (!NtSetInformationVirtualMemory_Import())\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    if (!NT_SUCCESS(status = PhGetSystemDllInitBlock(&systemDllInitBlock)))\n        return status;\n\n    // Check if CFG is disabled. PhGetProcessIsCFGuardEnabled(NtCurrentProcess());\n    if (!(systemDllInitBlock.CfgBitMap && systemDllInitBlock.CfgBitMapSize))\n        return STATUS_SUCCESS;\n\n    memset(&cfgCallTargetRangeInfo, 0, sizeof(MEMORY_RANGE_ENTRY));\n    cfgCallTargetRangeInfo.VirtualAddress = PAGE_ALIGN(VirtualAddress);\n    cfgCallTargetRangeInfo.NumberOfBytes = PAGE_SIZE;\n\n    memset(&cfgCallTargetInfo, 0, sizeof(CFG_CALL_TARGET_INFO));\n    cfgCallTargetInfo.Offset = BYTE_OFFSET(VirtualAddress);\n    cfgCallTargetInfo.Flags = CFG_CALL_TARGET_CONVERT_XFG_TO_CFG;\n\n    memset(&cfgCallTargetListInfo, 0, sizeof(CFG_CALL_TARGET_LIST_INFORMATION));\n    cfgCallTargetListInfo.NumberOfEntries = 1;\n    cfgCallTargetListInfo.Reserved = 0;\n    cfgCallTargetListInfo.NumberOfEntriesProcessed = &numberOfEntriesProcessed;\n    cfgCallTargetListInfo.CallTargetInfo = &cfgCallTargetInfo;\n\n    status = PhpSetInformationVirtualMemory(\n        ProcessHandle,\n        VmCfgCallTargetInformation,\n        1,\n        &cfgCallTargetRangeInfo,\n        &cfgCallTargetListInfo,\n        sizeof(CFG_CALL_TARGET_LIST_INFORMATION)\n        );\n\n    if (status == STATUS_INVALID_PAGE_PROTECTION)\n        status = STATUS_SUCCESS;\n\n    return status;\n}\n\n/**\n * Retrieves information about the system compression store.\n *\n * \\param[out] SystemCompressionStoreInformation A pointer to the compression store information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSystemCompressionStoreInformation(\n    _Out_ PPH_SYSTEM_STORE_COMPRESSION_INFORMATION SystemCompressionStoreInformation\n    )\n{\n    NTSTATUS status;\n    SYSTEM_STORE_INFORMATION storeInfo;\n    SM_STORE_COMPRESSION_INFORMATION_REQUEST compressionInfo;\n\n    memset(&compressionInfo, 0, sizeof(SM_STORE_COMPRESSION_INFORMATION_REQUEST));\n    compressionInfo.Version = SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION_V1;\n\n    memset(&storeInfo, 0, sizeof(SYSTEM_STORE_INFORMATION));\n    storeInfo.Version = SYSTEM_STORE_INFORMATION_VERSION;\n    storeInfo.StoreInformationClass = MemCompressionInfoRequest;\n    storeInfo.Data = &compressionInfo;\n    storeInfo.Length = SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V1;\n\n    status = NtQuerySystemInformation(\n        SystemStoreInformation,\n        &storeInfo,\n        sizeof(SYSTEM_STORE_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        memset(SystemCompressionStoreInformation, 0, sizeof(PH_SYSTEM_STORE_COMPRESSION_INFORMATION));\n        SystemCompressionStoreInformation->CompressionPid = compressionInfo.CompressionPid;\n        SystemCompressionStoreInformation->WorkingSetSize = compressionInfo.WorkingSetSize;\n        SystemCompressionStoreInformation->TotalDataCompressed = compressionInfo.TotalDataCompressed;\n        SystemCompressionStoreInformation->TotalCompressedSize = compressionInfo.TotalCompressedSize;\n        SystemCompressionStoreInformation->TotalUniqueDataCompressed = compressionInfo.TotalUniqueDataCompressed;\n    }\n\n    return status;\n}\n\n// rev from PsmServiceExtHost!RmpMemoryMonitorEmptySystemStore (dmex)\n/**\n * Requests a trim operation on the system compression store.\n * This function initiates a trim request for the system's compression store,\n * potentially freeing up unused or unnecessary compressed memory.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSystemCompressionStoreTrimRequest(\n    VOID\n    )\n{\n    NTSTATUS status;\n    SYSTEM_STORE_INFORMATION storeInfo;\n    SM_SYSTEM_STORE_TRIM_REQUEST trimRequestInfo;\n    PH_SYSTEM_STORE_COMPRESSION_INFORMATION compressionInfo;\n\n    status = PhGetSystemCompressionStoreInformation(&compressionInfo);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    memset(&trimRequestInfo, 0, sizeof(SM_SYSTEM_STORE_TRIM_REQUEST));\n    trimRequestInfo.Version = SYSTEM_STORE_TRIM_INFORMATION_VERSION_V1;\n    trimRequestInfo.PagesToTrim = BYTES_TO_PAGES(compressionInfo.WorkingSetSize);\n\n    memset(&storeInfo, 0, sizeof(SYSTEM_STORE_INFORMATION));\n    storeInfo.Version = SYSTEM_STORE_INFORMATION_VERSION;\n    storeInfo.StoreInformationClass = SystemStoreTrimRequest;\n    storeInfo.Data = &trimRequestInfo;\n    storeInfo.Length = SYSTEM_STORE_TRIM_INFORMATION_SIZE_V1;\n\n    status = NtQuerySystemInformation(\n        SystemStoreInformation,\n        &storeInfo,\n        sizeof(SYSTEM_STORE_INFORMATION),\n        NULL\n        );\n\n    return status;\n}\n\n/**\n * Requests to set or clear high memory priority for the system compression store of a process.\n *\n * \\param ProcessHandle Handle to the target process.\n * \\param SetHighMemoryPriority TRUE to set high memory priority, FALSE to clear it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSystemCompressionStoreHighMemoryPriorityRequest(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN SetHighMemoryPriority\n    )\n{\n    NTSTATUS status;\n    SYSTEM_STORE_INFORMATION storeInfo;\n    SM_STORE_MEMORY_PRIORITY_REQUEST memoryPriorityInfo;\n\n    memset(&memoryPriorityInfo, 0, sizeof(SM_STORE_MEMORY_PRIORITY_REQUEST));\n    memoryPriorityInfo.Version = SYSTEM_STORE_PRIORITY_REQUEST_VERSION;\n    memoryPriorityInfo.Flags = SYSTEM_STORE_PRIORITY_FLAG_REQUIRE_HANDLE;\n    memoryPriorityInfo.ProcessHandle = ProcessHandle;\n\n    if (SetHighMemoryPriority)\n    {\n        SetFlag(memoryPriorityInfo.Flags, SYSTEM_STORE_PRIORITY_FLAG_SET_PRIORITY);\n    }\n\n    memset(&storeInfo, 0, sizeof(SYSTEM_STORE_INFORMATION));\n    storeInfo.Version = SYSTEM_STORE_INFORMATION_VERSION;\n    storeInfo.StoreInformationClass = StoreHighMemoryPriorityRequest;\n    storeInfo.Data = &memoryPriorityInfo;\n    storeInfo.Length = SYSTEM_STORE_TRIM_INFORMATION_SIZE_V1;\n\n    status = NtQuerySystemInformation(\n        SystemStoreInformation,\n        &storeInfo,\n        sizeof(SYSTEM_STORE_INFORMATION),\n        NULL\n        );\n\n    return status;\n}\n\n/**\n * Retrieves the current size limits for the working set of the virtual memory manager system cache.\n *\n * \\param CacheInfo A pointer to a variable that receives the file cache information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetSystemFileCacheSize(\n    _Out_ PSYSTEM_FILECACHE_INFORMATION CacheInfo\n    )\n{\n    return NtQuerySystemInformation(\n        SystemFileCacheInformationEx,\n        CacheInfo,\n        sizeof(SYSTEM_FILECACHE_INFORMATION),\n        0\n        );\n}\n\n// rev from SetSystemFileCacheSize (MSDN) (dmex)\n/**\n * Limits the size of the working set of the virtual memory manager system cache.\n *\n * \\param CacheInfo The minimum size of the file cache, in bytes. The virtual memory manager\n * attempts to keep at least this much memory resident in the system file cache.\n * \\param CacheInfo The maximum size of the file cache, in bytes. The virtual memory manager\n * enforces this limit only if this call or a previous call to SetSystemFileCacheSize\n * specifies FILE_CACHE_MAX_HARD_ENABLE.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetSystemFileCacheSize(\n    _In_ SIZE_T MinimumFileCacheSize,\n    _In_ SIZE_T MaximumFileCacheSize,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    SYSTEM_FILECACHE_INFORMATION cacheInfo;\n\n    memset(&cacheInfo, 0, sizeof(SYSTEM_FILECACHE_INFORMATION));\n    cacheInfo.MinimumWorkingSet = MinimumFileCacheSize;\n    cacheInfo.MaximumWorkingSet = MaximumFileCacheSize;\n    cacheInfo.Flags = Flags;\n\n    status = NtSetSystemInformation(\n        SystemFileCacheInformationEx,\n        &cacheInfo,\n        sizeof(SYSTEM_FILECACHE_INFORMATION)\n        );\n\n    return status;\n}\n\n/**\n * Creates an event object, sets the initial state of the event to the specified value,\n * and opens a handle to the object with the specified desired access.\n *\n * \\param EventHandle A pointer to a variable that receives the event object handle.\n * \\param DesiredAccess The access mask that specifies the requested access to the event object.\n * \\param EventType The type of the event, which can be SynchronizationEvent or a NotificationEvent.\n * \\param InitialState The initial state of the event object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateEvent(\n    _Out_ PHANDLE EventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ EVENT_TYPE EventType,\n    _In_ BOOLEAN InitialState\n    )\n{\n    NTSTATUS status;\n    HANDLE eventHandle;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        NULL,\n        OBJ_EXCLUSIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateEvent(\n        &eventHandle,\n        DesiredAccess,\n        &objectAttributes,\n        EventType,\n        InitialState\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *EventHandle = eventHandle;\n    }\n\n    return status;\n}\n\n/**\n * Sends a control code directly to a specified device driver, causing the corresponding device to perform the corresponding operation.\n *\n * \\param DeviceHandle A handle to the device on which the operation is to be performed.\n * \\param IoControlCode The control code for the operation. This value identifies the specific operation to be performed and the type of device on which to perform it.\n * \\param InputBuffer A pointer to the input buffer that contains the data required to perform the operation.\n * \\param InputBufferLength The size of the input buffer, in bytes.\n * \\param OutputBuffer A pointer to the output buffer that is to receive the data returned by the operation.\n * \\param OutputBufferLength The size of the output buffer, in bytes.\n * \\param ReturnLength A pointer to a variable that receives the size of the data stored in the output buffer, in bytes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhDeviceIoControlFile(\n    _In_ HANDLE DeviceHandle,\n    _In_ ULONG IoControlCode,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_to_opt_(OutputBufferLength, *ReturnLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    if (DEVICE_TYPE_FROM_CTL_CODE(IoControlCode) == FILE_DEVICE_FILE_SYSTEM)\n    {\n        status = NtFsControlFile(\n            DeviceHandle,\n            NULL,\n            NULL,\n            NULL,\n            &ioStatusBlock,\n            IoControlCode,\n            InputBuffer,\n            InputBufferLength,\n            OutputBuffer,\n            OutputBufferLength\n            );\n    }\n    else\n    {\n        status = NtDeviceIoControlFile(\n            DeviceHandle,\n            NULL,\n            NULL,\n            NULL,\n            &ioStatusBlock,\n            IoControlCode,\n            InputBuffer,\n            InputBufferLength,\n            OutputBuffer,\n            OutputBufferLength\n            );\n    }\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(DeviceHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n        {\n            status = ioStatusBlock.Status;\n        }\n    }\n\n    if (ReturnLength)\n    {\n        *ReturnLength = (ULONG)ioStatusBlock.Information;\n    }\n\n    return status;\n}\n\n// rev from RtlpWow64SelectSystem32PathInternal (dmex)\n/**\n * Selects the appropriate System32 path for the specified machine architecture.\n *\n * \\param Machine The machine architecture identifier (e.g., IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386).\n * \\param IncludePathSeperator If TRUE, appends a path separator to the returned path.\n * \\param SystemPath A pointer to a PPH_STRINGREF that receives the selected System32 path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhWow64SelectSystem32Path(\n    _In_ USHORT Machine,\n    _In_ BOOLEAN IncludePathSeperator,\n    _Out_ PPH_STRINGREF SystemPath\n    )\n{\n    PWSTR WithSeperators;\n    PWSTR WithoutSeperators;\n\n    if (Machine != IMAGE_FILE_MACHINE_TARGET_HOST)\n    {\n        switch (Machine)\n        {\n        case IMAGE_FILE_MACHINE_I386:\n            WithoutSeperators = L\"SysWOW64\";\n            WithSeperators = L\"\\\\SysWOW64\\\\\";\n            goto CreateResult;\n        case IMAGE_FILE_MACHINE_ARMNT:\n            WithoutSeperators = L\"SysArm32\";\n            WithSeperators = L\"\\\\SysArm32\\\\\";\n            goto CreateResult;\n        case IMAGE_FILE_MACHINE_CHPE_X86:\n            WithoutSeperators = L\"SyChpe32\";\n            WithSeperators = L\"\\\\SyChpe32\\\\\";\n            goto CreateResult;\n        }\n\n        if (Machine != IMAGE_FILE_MACHINE_AMD64 && Machine != IMAGE_FILE_MACHINE_ARM64)\n            return STATUS_INVALID_PARAMETER;\n    }\n\n    WithSeperators = L\"\\\\System32\\\\\";\n    WithoutSeperators = L\"System32\";\n\nCreateResult:\n    if (!IncludePathSeperator)\n        WithSeperators = WithoutSeperators;\n\n    PhInitializeStringRefLongHint(SystemPath, WithSeperators); // RtlInitUnicodeString\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves information about a range of pages within the virtual address space of a specified process.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param Callback A callback function which is executed for each memory region.\n * \\param Context A user-defined value to pass to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_MEMORY_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    PVOID baseAddress;\n    MEMORY_BASIC_INFORMATION basicInfo;\n\n    baseAddress = (PVOID)0;\n\n    while (TRUE)\n    {\n        status = NtQueryVirtualMemory(\n            ProcessHandle,\n            baseAddress,\n            MemoryBasicInformation,\n            &basicInfo,\n            sizeof(MEMORY_BASIC_INFORMATION),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        if (basicInfo.State & MEM_FREE)\n        {\n            basicInfo.AllocationBase = basicInfo.BaseAddress;\n            basicInfo.AllocationProtect = basicInfo.Protect;\n        }\n\n        status = Callback(ProcessHandle, &basicInfo, Context);\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize);\n\n        if ((ULONG_PTR)baseAddress >= PhSystemBasicInformation.MaximumUserModeAddress)\n            break;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves information about a range of pages within the virtual address space of a specified process in batches for improved performance.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param BaseAddress The base address at which to begin retrieving information.\n * \\param BulkQuery A boolean indicating the mode of bulk query (accuracy vs reliability).\n * \\param Callback A callback function which is executed for each memory region.\n * \\param Context A user-defined value to pass to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumVirtualMemoryBulk(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ BOOLEAN BulkQuery,\n    _In_ PPH_ENUM_MEMORY_BULK_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n\n    if (PhIsExecutingInWow64())\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n\n    if (!NtPssCaptureVaSpaceBulk_Import())\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n\n    // BulkQuery... TRUE:\n    // * Faster.\n    // * More accurate snapshots.\n    // * Copies the entire VA space into local memory.\n    // * Wastes large amounts of heap memory due to buffer doubling.\n    // * Unsuitable for low-memory situations and fails with insufficient system resources.\n    // * ...\n    //\n    // BulkQuery... FALSE:\n    // * Slightly slower.\n    // * Slightly less accurate snapshots.\n    // * Does not copy the VA space.\n    // * Does not waste heap memory.\n    // * Suitable for low-memory situations and doesn't fail with insufficient system resources.\n    // * ...\n\n    if (BulkQuery)\n    {\n        SIZE_T bufferLength;\n        PNTPSS_MEMORY_BULK_INFORMATION buffer;\n        PMEMORY_BASIC_INFORMATION information;\n\n        bufferLength = sizeof(NTPSS_MEMORY_BULK_INFORMATION) + sizeof(MEMORY_BASIC_INFORMATION[20]);\n        buffer = PhAllocate(bufferLength);\n        buffer->QueryFlags = MEMORY_BULK_INFORMATION_FLAG_BASIC;\n\n        // Allocate a large buffer and copy all entries.\n\n        while ((status = NtPssCaptureVaSpaceBulk_Import()(\n            ProcessHandle,\n            BaseAddress,\n            buffer,\n            bufferLength,\n            NULL\n            )) == STATUS_MORE_ENTRIES)\n        {\n            PhFree(buffer);\n            bufferLength *= 2;\n\n            if (bufferLength > PH_LARGE_BUFFER_SIZE)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            buffer = PhAllocate(bufferLength);\n            buffer->QueryFlags = MEMORY_BULK_INFORMATION_FLAG_BASIC;\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            // Skip the enumeration header.\n\n            information = PTR_ADD_OFFSET(buffer, RTL_SIZEOF_THROUGH_FIELD(NTPSS_MEMORY_BULK_INFORMATION, NextValidAddress));\n\n            // Execute the callback.\n\n            Callback(ProcessHandle, information, buffer->NumberOfEntries, Context);\n        }\n\n        PhFree(buffer);\n    }\n    else\n    {\n        UCHAR stackBuffer[sizeof(NTPSS_MEMORY_BULK_INFORMATION) + sizeof(MEMORY_BASIC_INFORMATION[20])];\n        SIZE_T bufferLength;\n        PNTPSS_MEMORY_BULK_INFORMATION buffer;\n        PMEMORY_BASIC_INFORMATION information;\n\n        bufferLength = sizeof(stackBuffer);\n        buffer = (PNTPSS_MEMORY_BULK_INFORMATION)stackBuffer;\n        buffer->QueryFlags = MEMORY_BULK_INFORMATION_FLAG_BASIC;\n        buffer->NextValidAddress = BaseAddress;\n\n        while (TRUE)\n        {\n            // Get a batch of entries.\n\n            status = NtPssCaptureVaSpaceBulk_Import()(\n                ProcessHandle,\n                buffer->NextValidAddress,\n                buffer,\n                bufferLength,\n                NULL\n                );\n\n            if (!NT_SUCCESS(status))\n                break;\n\n            // Skip the enumeration header.\n\n            information = PTR_ADD_OFFSET(buffer, RTL_SIZEOF_THROUGH_FIELD(NTPSS_MEMORY_BULK_INFORMATION, NextValidAddress));\n\n            // Execute the callback.\n\n            if (!NT_SUCCESS(Callback(ProcessHandle, information, buffer->NumberOfEntries, Context)))\n                break;\n\n            // Get the next batch.\n\n            if (status != STATUS_MORE_ENTRIES)\n                break;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Retrieves information about the pages currently added to the working set of the specified process.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param Callback A callback function which is executed for each memory page.\n * \\param Context A user-defined value to pass to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumVirtualMemoryPages(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_MEMORY_PAGE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PMEMORY_WORKING_SET_INFORMATION pageInfo;\n\n    status = PhGetProcessWorkingSetInformation(\n        ProcessHandle,\n        &pageInfo\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = Callback(\n            ProcessHandle,\n            pageInfo->NumberOfEntries,\n            pageInfo->WorkingSetInfo,\n            Context\n            );\n\n        //for (ULONG_PTR i = 0; i < pageInfo->NumberOfEntries; i++)\n        //{\n        //    PMEMORY_WORKING_SET_BLOCK workingSetBlock = &pageInfo->WorkingSetInfo[i];\n        //    PVOID virtualAddress = (PVOID)(workingSetBlock->VirtualPage << PAGE_SHIFT);\n        //}\n\n        PhFree(pageInfo);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves extended information about memory pages in the working set\n * of the specified process, beginning at a given virtual address.\n *\n * \\param[in] ProcessHandle A handle to the target process.\n * \\param[in] BaseAddress The starting virtual address from which page information should be queried.\n * \\param[in] Size The total size, in bytes, of the address range to examine.\n * \\param[in] Callback A user-supplied callback invoked once for each page in the range.\n * \\param[in] Context A user-defined value passed to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumVirtualMemoryAttributes(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T Size,\n    _In_ PPH_ENUM_MEMORY_ATTRIBUTE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    SIZE_T numberOfPages;\n    ULONG_PTR virtualAddress;\n    PMEMORY_WORKING_SET_EX_INFORMATION info;\n    SIZE_T i;\n\n    numberOfPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, Size);\n    virtualAddress = (ULONG_PTR)PAGE_ALIGN(BaseAddress);\n\n    if (!numberOfPages)\n    {\n        status = STATUS_UNSUCCESSFUL;\n        goto CleanupExit;\n    }\n\n    info = PhAllocatePage(numberOfPages * sizeof(MEMORY_WORKING_SET_EX_INFORMATION), NULL);\n\n    if (!info)\n    {\n        status = STATUS_UNSUCCESSFUL;\n        goto CleanupExit;\n    }\n\n    for (i = 0; i < numberOfPages; i++)\n    {\n        info[i].VirtualAddress = (PVOID)virtualAddress;\n        virtualAddress += PAGE_SIZE;\n    }\n\n    status = NtQueryVirtualMemory(\n        ProcessHandle,\n        NULL,\n        MemoryWorkingSetExInformation,\n        info,\n        numberOfPages * sizeof(MEMORY_WORKING_SET_EX_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = Callback(\n            ProcessHandle,\n            BaseAddress,\n            Size,\n            numberOfPages,\n            info,\n            Context\n            );\n    }\n\n    PhFreePage(info);\n\nCleanupExit:\n    return status;\n}\n\n/**\n * Retrieves information about the state of the kernel debugger.\n *\n * \\param[out] KernelDebuggerEnabled Optional. Receives a BOOLEAN value that indicates whether the kernel debugger is enabled.\n * \\param[out] KernelDebuggerPresent Optional. Receives a BOOLEAN value that indicates whether the kernel debugger is present.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetKernelDebuggerInformation(\n    _Out_opt_ PBOOLEAN KernelDebuggerEnabled,\n    _Out_opt_ PBOOLEAN KernelDebuggerPresent\n    )\n{\n    NTSTATUS status;\n    SYSTEM_KERNEL_DEBUGGER_INFORMATION debugInfo;\n\n    status = NtQuerySystemInformation(\n        SystemKernelDebuggerInformation,\n        &debugInfo,\n        sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (KernelDebuggerEnabled)\n            *KernelDebuggerEnabled = debugInfo.KernelDebuggerEnabled;\n        if (KernelDebuggerPresent)\n            *KernelDebuggerPresent = !debugInfo.KernelDebuggerNotPresent;\n    }\n\n    return status;\n}\n\n// rev from BasepIsDebugPortPresent (dmex)\n/**\n * Checks if a debug port is present for the current process.\n * \\return TRUE if a debug port is detected, otherwise FALSE.\n */\nBOOLEAN PhIsDebugPortPresent(\n    VOID\n    )\n{\n    BOOLEAN isBeingDebugged;\n\n    if (NT_SUCCESS(PhGetProcessIsBeingDebugged(NtCurrentProcess(), &isBeingDebugged)))\n    {\n        if (isBeingDebugged)\n        {\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n// rev from IsDebuggerPresent (dmex)\n/**\n * Determines whether the calling process is being debugged by a user-mode debugger.\n *\n * \\return TRUE if the current process is running in the context of a debugger, otherwise the return value is FALSE.\n */\nBOOLEAN PhIsDebuggerPresent(\n    VOID\n    )\n{\n#ifdef PHNT_NATIVE_DEBUGGER\n    return !!IsDebuggerPresent();\n#else\n    return NtCurrentPeb()->BeingDebugged;\n#endif\n}\n\n// rev from GetFileType (dmex)\n/**\n * Retrieves the type of the specified file handle.\n *\n * \\param ProcessHandle A handle to the process.\n * \\param FileHandle A handle to the file.\n * \\param DeviceType The type of the specified file\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetDeviceType(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _Out_ DEVICE_TYPE* DeviceType\n    )\n{\n    NTSTATUS status;\n    FILE_FS_DEVICE_INFORMATION debugInfo;\n    IO_STATUS_BLOCK isb;\n\n    status = PhQueryVolumeInformationFile(\n        ProcessHandle,\n        FileHandle,\n        FileFsDeviceInformation,\n        &debugInfo,\n        sizeof(FILE_FS_DEVICE_INFORMATION),\n        &isb\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *DeviceType = debugInfo.DeviceType;\n    }\n\n    return status;\n}\n\n/**\n * Checks if the specified file name is an App Execution Alias target.\n *\n * \\param FileName A pointer to a PPH_STRING structure containing the file name to check.\n * \\return TRUE if the file name is an App Execution Alias target, FALSE otherwise.\n */\nBOOLEAN PhIsAppExecutionAliasTarget(\n    _In_ PPH_STRING FileName\n    )\n{\n    PPH_STRING targetFileName = NULL;\n    PREPARSE_DATA_BUFFER reparseBuffer;\n    ULONG reparseLength;\n    HANDLE fileHandle;\n    IO_STATUS_BLOCK isb;\n\n    if (PhIsNullOrEmptyString(FileName))\n        return FALSE;\n\n    if (!NT_SUCCESS(PhCreateFileWin32(\n        &fileHandle,\n        PhGetString(FileName),\n        FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT\n        )))\n    {\n        return FALSE;\n    }\n\n    reparseLength = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;\n    reparseBuffer = PhAllocateZero(reparseLength);\n\n    if (NT_SUCCESS(NtFsControlFile(\n        fileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_GET_REPARSE_POINT,\n        NULL,\n        0,\n        reparseBuffer,\n        reparseLength\n        )))\n    {\n        if (\n            IsReparseTagMicrosoft(reparseBuffer->ReparseTag) &&\n            reparseBuffer->ReparseTag == IO_REPARSE_TAG_APPEXECLINK\n            )\n        {\n            PCWSTR string;\n\n            string = (PCWSTR)reparseBuffer->AppExecLinkReparseBuffer.StringList;\n\n            for (ULONG i = 0; i < reparseBuffer->AppExecLinkReparseBuffer.StringCount; i++)\n            {\n                if (i == 2 && PhDoesFileExistWin32(string))\n                {\n                    targetFileName = PhCreateString(string);\n                    break;\n                }\n\n                string += PhCountStringZ(string) + 1;\n            }\n        }\n    }\n\n    PhFree(reparseBuffer);\n    NtClose(fileHandle);\n\n    if (targetFileName)\n    {\n        if (PhDoesFileExistWin32(targetFileName->Buffer))\n        {\n            PhDereferenceObject(targetFileName);\n            return TRUE;\n        }\n\n        PhDereferenceObject(targetFileName);\n    }\n\n    return FALSE;\n}\n\n/**\n * Enumerates the enclaves of a process.\n *\n * \\param ProcessHandle Handle to the process whose enclaves are to be enumerated.\n * \\param LdrEnclaveList Pointer to the process's loader enclave list.\n * \\param Callback Callback function to be called for each enclave found.\n * \\param Context Optional context to be passed to the callback function.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumProcessEnclaves(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID LdrEnclaveList,\n    _In_ PPH_ENUM_PROCESS_ENCLAVES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    LIST_ENTRY enclaveList;\n    LDR_SOFTWARE_ENCLAVE enclave;\n\n    status = PhReadVirtualMemory(\n        ProcessHandle,\n        LdrEnclaveList,\n        &enclaveList,\n        sizeof(LIST_ENTRY),\n        NULL\n        );\n    if (!NT_SUCCESS(status))\n        return status;\n\n    for (PLIST_ENTRY link = enclaveList.Flink;\n         link != LdrEnclaveList;\n         link = enclave.Links.Flink)\n    {\n        PVOID enclaveAddress;\n\n        enclaveAddress = CONTAINING_RECORD(link, LDR_SOFTWARE_ENCLAVE, Links);\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            link,\n            &enclave,\n            sizeof(enclave),\n            NULL\n            );\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (!Callback(ProcessHandle, enclaveAddress, &enclave, Context))\n            break;\n    }\n\n    return status;\n}\n\n#ifdef _M_ARM64\n// rev from ntdll!RtlEcContextToNativeContext (jxy-s)\nVOID PhEcContextToNativeContext(\n    _Out_ PCONTEXT Context,\n    _In_ PARM64EC_NT_CONTEXT EcContext\n    )\n{\n    Context->ContextFlags = 0;\n\n    //#define CONTEXT_AMD64   0x00100000L\n\n    //#define CONTEXT_CONTROL         (CONTEXT_AMD64 | 0x00000001L)\n    if (BooleanFlagOn(EcContext->ContextFlags, 0x00100000L | 0x00000001L))\n        SetFlag(Context->ContextFlags, CONTEXT_CONTROL);\n\n    //#define CONTEXT_INTEGER         (CONTEXT_AMD64 | 0x00000002L)\n    if (BooleanFlagOn(EcContext->ContextFlags, 0x00100000L | 0x00000002L))\n        SetFlag(Context->ContextFlags, CONTEXT_INTEGER);\n\n    //#define CONTEXT_FLOATING_POINT  (CONTEXT_AMD64 | 0x00000008L)\n    if (BooleanFlagOn(EcContext->ContextFlags, 0x00100000L | 0x00000008L))\n        SetFlag(Context->ContextFlags, CONTEXT_FLOATING_POINT);\n\n    SetFlag(Context->ContextFlags,\n            EcContext->ContextFlags & (\n                CONTEXT_EXCEPTION_ACTIVE |\n                CONTEXT_SERVICE_ACTIVE |\n                CONTEXT_EXCEPTION_REQUEST |\n                CONTEXT_EXCEPTION_REPORTING\n                ));\n\n    Context->Cpsr = (EcContext->AMD64_EFlags & 0x00000100);         // Overflow Flag\n    Context->Cpsr |= ((EcContext->AMD64_EFlags & 0x00000800) << 4); // Direction Flag\n    Context->Cpsr |= ((EcContext->AMD64_EFlags & 0xFFFFFFC0) << 7); // Other Flags\n    Context->Cpsr |= ((EcContext->AMD64_EFlags & 0x00000001) << 5); // Carry Flag\n    Context->Cpsr <<= 13;\n\n    Context->X0 = EcContext->X0;\n    Context->X2 = EcContext->X2;\n    Context->X4 = EcContext->X4;\n    Context->X6 = EcContext->X6;\n    Context->X7 = EcContext->X7;\n    Context->X8 = EcContext->X8;\n    Context->X9 = EcContext->X9;\n    Context->X10 = EcContext->X10;\n    Context->X11 = EcContext->X11;\n    Context->X12 = EcContext->X12;\n    Context->X14 = 0;\n    Context->X15 = EcContext->X15;\n\n    Context->X16 = EcContext->X16_0;\n    Context->X16 |= ((ULONG64)EcContext->X16_1 << 16);\n    Context->X16 |= ((ULONG64)EcContext->X16_2 << 32);\n    Context->X16 |= ((ULONG64)EcContext->X16_3 << 48);\n\n    Context->X17 = EcContext->X17_0;\n    Context->X17 |= ((ULONG64)EcContext->X17_1 << 16);\n    Context->X17 |= ((ULONG64)EcContext->X17_2 << 32);\n    Context->X17 |= ((ULONG64)EcContext->X17_3 << 48);\n\n    Context->X19 = EcContext->X19;\n    Context->X21 = EcContext->X21;\n    Context->X23 = 0;\n    Context->X25 = EcContext->X25;\n    Context->X27 = EcContext->X27;\n\n    Context->Fp = EcContext->Fp;\n    Context->Lr = EcContext->Lr;\n    Context->Sp = EcContext->Sp;\n    Context->Pc = EcContext->Pc;\n\n    Context->V[0] = EcContext->V[0];\n    Context->V[1] = EcContext->V[1];\n    Context->V[2] = EcContext->V[2];\n    Context->V[3] = EcContext->V[3];\n    Context->V[4] = EcContext->V[4];\n    Context->V[5] = EcContext->V[5];\n    Context->V[6] = EcContext->V[6];\n    Context->V[7] = EcContext->V[7];\n    Context->V[8] = EcContext->V[8];\n    Context->V[9] = EcContext->V[9];\n    Context->V[10] = EcContext->V[10];\n    Context->V[11] = EcContext->V[11];\n    Context->V[12] = EcContext->V[12];\n    Context->V[13] = EcContext->V[13];\n    Context->V[14] = EcContext->V[14];\n    Context->V[15] = EcContext->V[15];\n    RtlZeroMemory(&Context->V[16], sizeof(ARM64_NT_NEON128));\n\n    Context->Fpcr = (EcContext->AMD64_MxCsr & 0x00000080) == 0;         // IM: Invalid Operation Mask\n    Context->Fpcr |= ((EcContext->AMD64_MxCsr & 0x00000200) == 0) << 1; // ZM: Divide-by-Zero Mask\n    Context->Fpcr |= ((EcContext->AMD64_MxCsr & 0x00000400) == 0) << 2; // OM: Overflow Mask\n    Context->Fpcr |= ((EcContext->AMD64_MxCsr & 0x00000800) == 0) << 3; // UM: Underflow Mask\n    Context->Fpcr |= ((EcContext->AMD64_MxCsr & 0x00001000) == 0) << 4; // PM: Precision Mask\n    Context->Fpcr |= (EcContext->AMD64_MxCsr & 0x00000040) << 5;        // DAZ: Denormals Are Zero Mask\n    Context->Fpcr |= ((EcContext->AMD64_MxCsr & 0x00000100) == 0) << 7; // DM: Denormal Operation Mask\n    Context->Fpcr |= (EcContext->AMD64_MxCsr & 0x00002000);             // FZ: Flush to Zero Mask\n    Context->Fpcr |= (EcContext->AMD64_MxCsr & 0x0000C000);             // RC: Rounding Control\n    Context->Fpcr <<= 8;\n\n    Context->Fpsr = EcContext->AMD64_MxCsr & 1;            // IE: Invalid Operation Flag\n    Context->Fpsr |= (EcContext->AMD64_MxCsr & 2) << 6;    // DE: Denormal Flag\n    Context->Fpsr |= (EcContext->AMD64_MxCsr >> 1) & 0x1E; // ZE | OE | UE | PE: Zero, Overflow, Underflow, Precision Flags\n\n    RtlZeroMemory(Context->Bcr, sizeof(Context->Bcr));\n    RtlZeroMemory(Context->Bvr, sizeof(Context->Bvr));\n    RtlZeroMemory(Context->Wcr, sizeof(Context->Wcr));\n    RtlZeroMemory(Context->Wvr, sizeof(Context->Wvr));\n}\n\n// rev from ntdll!RtlNativeContextToEcContext (jxy-s)\nVOID PhNativeContextToEcContext(\n    _When_(InitializeEc, _Out_) _When_(!InitializeEc, _Inout_) PARM64EC_NT_CONTEXT EcContext,\n    _In_ PCONTEXT Context,\n    _In_ BOOLEAN InitializeEc\n    )\n{\n    if (InitializeEc)\n    {\n        EcContext->ContextFlags = 0;\n\n        //#define CONTEXT_AMD64   0x00100000L\n\n        //#define CONTEXT_CONTROL         (CONTEXT_AMD64 | 0x00000001L)\n        if (BooleanFlagOn(Context->ContextFlags, CONTEXT_CONTROL))\n            SetFlag(EcContext->ContextFlags, (0x00100000L | 0x00000001L));\n\n        //#define CONTEXT_INTEGER         (CONTEXT_AMD64 | 0x00000002L)\n        if (BooleanFlagOn(Context->ContextFlags, CONTEXT_INTEGER))\n            SetFlag(EcContext->ContextFlags, (0x00100000L | 0x00000002L));\n\n        //#define CONTEXT_FLOATING_POINT  (CONTEXT_AMD64 | 0x00000008L)\n        if (BooleanFlagOn(Context->ContextFlags, CONTEXT_FLOATING_POINT))\n            SetFlag(EcContext->ContextFlags, (0x00100000L | 0x00000008L));\n\n        EcContext->AMD64_P1Home = 0;\n        EcContext->AMD64_P2Home = 0;\n        EcContext->AMD64_P3Home = 0;\n        EcContext->AMD64_P4Home = 0;\n        EcContext->AMD64_P5Home = 0;\n        EcContext->AMD64_P6Home = 0;\n\n        EcContext->AMD64_Dr0 = 0;\n        EcContext->AMD64_Dr1 = 0;\n        EcContext->AMD64_Dr3 = 0;\n        EcContext->AMD64_Dr6 = 0;\n        EcContext->AMD64_Dr7 = 0;\n\n        EcContext->AMD64_MxCsr_copy = 0;\n\n        EcContext->AMD64_SegCs = 0x0033;\n        EcContext->AMD64_SegDs = 0x002B;\n        EcContext->AMD64_SegEs = 0x002B;\n        EcContext->AMD64_SegFs = 0x0053;\n        EcContext->AMD64_SegGs = 0x002B;\n        EcContext->AMD64_SegSs = 0x002B;\n\n        EcContext->AMD64_ControlWord = 0;\n        EcContext->AMD64_StatusWord = 0;\n        EcContext->AMD64_TagWord = 0;\n        EcContext->AMD64_Reserved1 = 0;\n        EcContext->AMD64_ErrorOpcode = 0;\n        EcContext->AMD64_ErrorOffset = 0;\n        EcContext->AMD64_ErrorSelector = 0;\n        EcContext->AMD64_Reserved2= 0;\n        EcContext->AMD64_DataOffset = 0;\n        EcContext->AMD64_DataSelector = 0;\n        EcContext->AMD64_Reserved3 = 0;\n\n        EcContext->AMD64_MxCsr = 0;\n        EcContext->AMD64_MxCsr_Mask = 0;\n\n        EcContext->AMD64_St0_Reserved1 = 0;\n        EcContext->AMD64_St0_Reserved2 = 0;\n        EcContext->AMD64_St1_Reserved1 = 0;\n        EcContext->AMD64_St1_Reserved2 = 0;\n        EcContext->AMD64_St2_Reserved1 = 0;\n        EcContext->AMD64_St2_Reserved2 = 0;\n        EcContext->AMD64_St3_Reserved1 = 0;\n        EcContext->AMD64_St3_Reserved2 = 0;\n        EcContext->AMD64_St4_Reserved1 = 0;\n        EcContext->AMD64_St4_Reserved2 = 0;\n        EcContext->AMD64_St5_Reserved1 = 0;\n        EcContext->AMD64_St5_Reserved2 = 0;\n        EcContext->AMD64_St6_Reserved1 = 0;\n        EcContext->AMD64_St6_Reserved2 = 0;\n        EcContext->AMD64_St7_Reserved1 = 0;\n        EcContext->AMD64_St7_Reserved2 = 0;\n\n        EcContext->AMD64_EFlags = 0x202; // IF(EI) | RESERVED_1(always set)\n    }\n\n    EcContext->ContextFlags &= 0x7ffffffff;\n    SetFlag(EcContext->ContextFlags,\n            Context->ContextFlags & (\n                CONTEXT_EXCEPTION_ACTIVE |\n                CONTEXT_SERVICE_ACTIVE |\n                CONTEXT_EXCEPTION_REQUEST |\n                CONTEXT_EXCEPTION_REPORTING\n                ));\n\n    EcContext->AMD64_MxCsr_copy &= 0xFFFF0000;\n    EcContext->AMD64_MxCsr_copy |= (Context->Fpsr & 0x00000080) >> 6;         // IM: Invalid Operation Mask\n    EcContext->AMD64_MxCsr_copy |= (Context->Fpcr & 0x00400000) >> 8;         // ZM: Divide-by-Zero Mask\n    EcContext->AMD64_MxCsr_copy |= (Context->Fpcr & 0x01000000) >> 9;         // OM: Overflow Mask\n    EcContext->AMD64_MxCsr_copy |= (Context->Fpcr & 0x00080000) >> 7;         // UM: Underflow Mask\n    EcContext->AMD64_MxCsr_copy |= (Context->Fpcr & 0x00800000) >> 7;         // PM: Precision Mask\n    EcContext->AMD64_MxCsr_copy |= (Context->Fpsr & 0x0000001E) << 1;         // Other Flags\n    EcContext->AMD64_MxCsr_copy |= ((Context->Fpcr & 0x00000100) == 0) << 7;  // DAZ: Denormals Are Zeros\n    EcContext->AMD64_MxCsr_copy |= ((Context->Fpcr & 0x00008000) == 0) << 8;  // DM: Denormal Operation Mask\n    EcContext->AMD64_MxCsr_copy |= ((Context->Fpcr & 0x00000200) == 0) << 9;  // FZ: Flush to Zero\n    EcContext->AMD64_MxCsr_copy |= ((Context->Fpcr & 0x00000400) == 0) << 10; // RC: Rounding Control\n    EcContext->AMD64_MxCsr_copy |= ((Context->Fpcr & 0x00000800) == 0) << 11; // RC: Rounding Control\n    EcContext->AMD64_MxCsr_copy |= ((Context->Fpcr & 0x00001000) == 0) << 12; // RC: Rounding Control\n    EcContext->AMD64_MxCsr_copy |= Context->Fpsr & 0x00000001;\n\n    EcContext->AMD64_EFlags &= 0xFFFFF63E;\n    EcContext->AMD64_EFlags |= ((Context->Cpsr & 0x200000) >> 13);         // Overflow Flag\n    EcContext->AMD64_EFlags |= ((Context->Cpsr & 0x10000000) >> 17);       // Direction Flag\n    EcContext->AMD64_EFlags |= (((Context->Cpsr >> 5) & 0x1000000) >> 20); // Carry Flag\n    EcContext->AMD64_EFlags |= ((Context->Cpsr & 0xC0FFFFFF) >> 20);       // Other Flags\n\n    EcContext->Pc = Context->Pc;\n\n    EcContext->X8 = Context->X8;\n    EcContext->X0 = Context->X0;\n    EcContext->X1 = Context->X1;\n    EcContext->X27 = Context->X27;\n    EcContext->Sp = Context->Sp;\n    EcContext->Fp = Context->Fp;\n    EcContext->X25 = Context->X25;\n    EcContext->X26 = Context->X26;\n    EcContext->X2 = Context->X2;\n    EcContext->X3 = Context->X3;\n    EcContext->X4 = Context->X4;\n    EcContext->X5 = Context->X5;\n    EcContext->X19 = Context->X19;\n    EcContext->X20 = Context->X20;\n    EcContext->X21 = Context->X21;\n    EcContext->X22 = Context->X22;\n\n    EcContext->Lr = Context->Lr;\n    EcContext->X16_0 = LOWORD(Context->X16);\n    EcContext->X6 = Context->X6;\n    EcContext->X16_1 = HIWORD(Context->X16);\n    EcContext->X7 = Context->X7;\n    EcContext->X16_2 = LOWORD(Context->X16 >> 32);\n    EcContext->X9 = Context->X9;\n    EcContext->X16_3 = HIWORD(Context->X16 >> 32);\n    EcContext->X10 = Context->X10;\n    EcContext->X17_0 = LOWORD(Context->X17);\n    EcContext->X11 = Context->X11;\n    EcContext->X17_1 = HIWORD(Context->X17);\n    EcContext->X12 = Context->X12;\n    EcContext->X17_2 = LOWORD(Context->X17 >> 32);\n    EcContext->X15 = Context->X15;\n    EcContext->X17_3 = HIWORD(Context->X17 >> 32);\n\n    EcContext->V[0] = Context->V[0];\n    EcContext->V[1] = Context->V[1];\n    EcContext->V[2] = Context->V[2];\n    EcContext->V[3] = Context->V[3];\n    EcContext->V[4] = Context->V[4];\n    EcContext->V[5] = Context->V[5];\n    EcContext->V[6] = Context->V[6];\n    EcContext->V[7] = Context->V[7];\n    EcContext->V[8] = Context->V[8];\n    EcContext->V[9] = Context->V[9];\n    EcContext->V[10] = Context->V[10];\n    EcContext->V[11] = Context->V[11];\n    EcContext->V[12] = Context->V[12];\n    EcContext->V[13] = Context->V[13];\n    EcContext->V[14] = Context->V[14];\n    EcContext->V[15] = Context->V[15];\n}\n\n// rev from ntdll!RtlIsEcCode (jxy-s)\nNTSTATUS PhIsEcCode(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID CodePointer,\n    _Out_ PBOOLEAN IsEcCode\n    )\n{\n    NTSTATUS status;\n    PVOID pebBaseAddress;\n    PVOID ecCodeBitMap;\n    ULONG64 bitmap;\n\n    *IsEcCode = FALSE;\n\n    // hack (jxy-s)\n    // 0x00007ffffffeffff = LdrpEcBitmapData.HighestAddress (MmHighestUserAddress)\n    // 0x0000000000010000 = MM_LOWEST_USER_ADDRESS\n    if ((ULONG_PTR)CodePointer > 0x00007ffffffeffff || (ULONG_PTR)CodePointer < 0x0000000000010000)\n        return STATUS_INVALID_PARAMETER_2;\n\n    if (!NT_SUCCESS(status = PhGetProcessPeb(ProcessHandle, &pebBaseAddress)))\n        return status;\n\n    if (!NT_SUCCESS(status = PhReadVirtualMemory(\n        ProcessHandle,\n        PTR_ADD_OFFSET(pebBaseAddress, FIELD_OFFSET(PEB, EcCodeBitMap)),\n        &ecCodeBitMap,\n        sizeof(PVOID),\n        NULL\n        )))\n        return status;\n\n    if (!ecCodeBitMap)\n        return STATUS_INVALID_PARAMETER_1;\n\n    // each byte of bitmap indexes 8*4K = 2^15 byte span\n    ecCodeBitMap = PTR_ADD_OFFSET(ecCodeBitMap, (ULONG_PTR)CodePointer >> 15);\n\n    if (!NT_SUCCESS(status = PhReadVirtualMemory(\n        ProcessHandle,\n        ecCodeBitMap,\n        &bitmap,\n        sizeof(ULONG64),\n        NULL\n        )))\n        return status;\n\n    // index to the 4k page within the 8*4K span\n    bitmap >>= (((ULONG_PTR)CodePointer >> PAGE_SHIFT) & 7);\n\n    // test the specific page\n    if (bitmap & 1)\n        *IsEcCode = TRUE;\n\n    return STATUS_SUCCESS;\n}\n#endif\n\n/**\n * Retrieves the Mark of the Web (MOTW) information from a file.\n *\n * The MOTW information resides in the Zone.Identifier alternate data\n * stream on a file. This routine attempts to open and read this alternate data\n * stream and optionally returns the MOTW information.\n *\n * \\param[in] FileName - File name to retrieve the MOTS information from.\n * \\param[out] ZoneId - Optionally receives the zone identifier for the file.\n * \\param[out] ReferrerUrl - Optionally receives the referrer URL for the file.\n * Can be an empty string if no referrer URL is present.\n * \\param[out] HostUrl - Optionally receives the host URL for the file. Can be\n * an empty string if no referrer URL is present.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetFileMotw(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_opt_ PPH_MOTW_ZONE_ID ZoneId,\n    _Out_opt_ PPH_STRING* ReferrerUrl,\n    _Out_opt_ PPH_STRING* HostUrl\n    )\n{\n    static const PH_STRINGREF zoneIdentifierStream = PH_STRINGREF_INIT(L\":Zone.Identifier\");\n    static const PH_STRINGREF newLine = PH_STRINGREF_INIT(L\"\\r\\n\");\n    static const PH_STRINGREF zoneIdKey = PH_STRINGREF_INIT(L\"ZoneId\");\n    static const PH_STRINGREF referrerUrlKey = PH_STRINGREF_INIT(L\"ReferrerUrl\");\n    static const PH_STRINGREF hostUrlKey = PH_STRINGREF_INIT(L\"HostUrl\");\n\n    NTSTATUS status;\n    PPH_STRING fileName;\n    HANDLE fileHandle;\n    ULONG zoneId = ULONG_MAX;\n    PPH_STRING referrerUrl = NULL;\n    PPH_STRING hostUrl = NULL;\n\n    if (ZoneId)\n        *ZoneId = PhMotwZoneIdUnknown;\n    if (ReferrerUrl)\n        *ReferrerUrl = NULL;\n    if (HostUrl)\n        *HostUrl = NULL;\n\n    fileName = PhConcatStringRef2(FileName, &zoneIdentifierStream);\n\n    if (NT_SUCCESS(status = PhCreateFile(\n        &fileHandle,\n        &fileName->sr,\n        FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        )))\n    {\n        PPH_STRING fileText;\n\n        if (NT_SUCCESS(status = PhGetFileText(&fileText, fileHandle, TRUE)))\n        {\n            PH_STRINGREF line;\n            PH_STRINGREF remaining;\n            PH_STRINGREF key;\n            PH_STRINGREF value;\n\n            status = STATUS_NOT_FOUND;\n\n            remaining = fileText->sr;\n\n            while (remaining.Length)\n            {\n                PhSplitStringRefAtString(&remaining, &newLine, FALSE, &line, &remaining);\n                PhSplitStringRefAtChar(&line, L'=', &key, &value);\n\n                if (!value.Length)\n                    continue;\n\n                if (zoneId == ULONG_MAX && PhEqualStringRef(&key, &zoneIdKey, TRUE))\n                {\n                    zoneId = value.Buffer[0] - L'0';\n                    if (zoneId > PhMotwZoneIdRestrictedSites)\n                        zoneId = PhMotwZoneIdUnknown;\n                }\n                else if (!referrerUrl && PhEqualStringRef(&key, &referrerUrlKey, TRUE))\n                {\n                    referrerUrl = PhCreateString2(&value);\n                }\n                else if (!hostUrl && PhEqualStringRef(&key, &hostUrlKey, TRUE))\n                {\n                    hostUrl = PhCreateString2(&value);\n                }\n\n                if (zoneId != ULONG_MAX && referrerUrl && hostUrl)\n                    break;\n            }\n\n            if (zoneId == ULONG_MAX)\n            {\n                status = STATUS_NOT_FOUND;\n                PhClearReference(&referrerUrl);\n                PhClearReference(&hostUrl);\n            }\n            else\n            {\n                status = STATUS_SUCCESS;\n\n                if (!referrerUrl)\n                    referrerUrl = PhReferenceEmptyString();\n                if (!hostUrl)\n                    hostUrl = PhReferenceEmptyString();\n\n                if (ZoneId)\n                    *ZoneId = zoneId;\n\n                if (ReferrerUrl)\n                    PhMoveReference(ReferrerUrl, referrerUrl);\n                else\n                    PhClearReference(&referrerUrl);\n\n                if (HostUrl)\n                    PhMoveReference(HostUrl, hostUrl);\n                else\n                    PhClearReference(&hostUrl);\n            }\n        }\n\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/nativefile.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <kphuser.h>\n\n/**\n * Creates or opens a file.\n *\n * \\param FileHandle A variable that receives the file handle.\n * \\param FileName The Win32 file name.\n * \\param DesiredAccess The desired access to the file.\n * \\param FileAttributes File attributes applied if the file is created or overwritten.\n * \\param ShareAccess The file access granted to other threads.\n * \\li \\c FILE_SHARE_READ Allows other threads to read from the file.\n * \\li \\c FILE_SHARE_WRITE Allows other threads to write to the file.\n * \\li \\c FILE_SHARE_DELETE Allows other threads to delete the file.\n * \\param CreateDisposition The action to perform if the file does or does not exist.\n * \\li \\c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file.\n * \\li \\c FILE_CREATE If the file exists, fail. Otherwise, create the file.\n * \\li \\c FILE_OPEN If the file exists, open it. Otherwise, fail.\n * \\li \\c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file.\n * \\li \\c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail.\n * \\li \\c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file.\n * \\param CreateOptions The options to apply when the file is opened or created.\n */\nNTSTATUS PhCreateFileWin32(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions\n    )\n{\n    return PhCreateFileWin32Ex(\n        FileHandle,\n        FileName,\n        DesiredAccess,\n        NULL,\n        FileAttributes,\n        ShareAccess,\n        CreateDisposition,\n        CreateOptions,\n        NULL\n        );\n}\n\n/**\n * Creates or opens a file.\n *\n * \\param FileHandle A variable that receives the file handle.\n * \\param FileName The Win32 file name.\n * \\param DesiredAccess The desired access to the file.\n * \\param AllocationSize The initial allocation size if the file is being created, overwritten, or superseded.\n * \\param FileAttributes File attributes applied if the file is created or overwritten.\n * \\param ShareAccess The file access granted to other threads.\n * \\li \\c FILE_SHARE_READ Allows other threads to read from the file.\n * \\li \\c FILE_SHARE_WRITE Allows other threads to write to the file.\n * \\li \\c FILE_SHARE_DELETE Allows other threads to delete the file.\n * \\param CreateDisposition The action to perform if the file does or does not exist.\n * \\li \\c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file.\n * \\li \\c FILE_CREATE If the file exists, fail. Otherwise, create the file.\n * \\li \\c FILE_OPEN If the file exists, open it. Otherwise, fail.\n * \\li \\c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file.\n * \\li \\c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail.\n * \\li \\c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file.\n * \\param CreateOptions The options to apply when the file is opened or created.\n * \\param CreateStatus A variable that receives creation information.\n * \\li \\c FILE_SUPERSEDED The file was replaced because \\c FILE_SUPERSEDE was specified in\n * \\a CreateDisposition.\n * \\li \\c FILE_OPENED The file was opened because \\c FILE_OPEN or \\c FILE_OPEN_IF was specified in\n * \\a CreateDisposition.\n * \\li \\c FILE_CREATED The file was created because \\c FILE_CREATE or \\c FILE_OPEN_IF was specified\n * in \\a CreateDisposition.\n * \\li \\c FILE_OVERWRITTEN The file was overwritten because \\c FILE_OVERWRITE or\n * \\c FILE_OVERWRITE_IF was specified in \\a CreateDisposition.\n * \\li \\c FILE_EXISTS The file was not opened because it already existed and \\c FILE_CREATE was\n * specified in \\a CreateDisposition.\n * \\li \\c FILE_DOES_NOT_EXIST The file was not opened because it did not exist and \\c FILE_OPEN or\n * \\c FILE_OVERWRITE was specified in \\a CreateDisposition.\n */\nNTSTATUS PhCreateFileWin32Ex(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG CreateStatus\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    status = PhDosLongPathNameToNtPathNameWithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &fileHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &ioStatusBlock,\n        AllocationSize,\n        FileAttributes,\n        ShareAccess,\n        CreateDisposition,\n        CreateOptions,\n        NULL,\n        0\n        );\n\n    if (status == STATUS_SHARING_VIOLATION &&\n        KsiLevel() >= KphLevelMed &&\n        (DesiredAccess & KPH_FILE_READ_ACCESS) == DesiredAccess &&\n        CreateDisposition == KPH_FILE_READ_DISPOSITION)\n    {\n        status = KphCreateFile(\n            &fileHandle,\n            DesiredAccess,\n            &objectAttributes,\n            &ioStatusBlock,\n            AllocationSize,\n            FileAttributes,\n            ShareAccess,\n            CreateDisposition,\n            CreateOptions,\n            NULL,\n            0,\n            IO_IGNORE_SHARE_ACCESS_CHECK\n            );\n    }\n\n    RtlFreeUnicodeString(&fileName);\n\n    if (NT_SUCCESS(status))\n    {\n        *FileHandle = fileHandle;\n    }\n\n    if (CreateStatus)\n        *CreateStatus = (ULONG)ioStatusBlock.Information;\n\n    return status;\n}\n\nNTSTATUS PhCreateFileWin32ExAlt(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_ ULONG CreateFlags,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _Out_opt_ PULONG CreateStatus\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n    EXTENDED_CREATE_INFORMATION extendedInfo;\n\n    status = PhDosLongPathNameToNtPathNameWithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    memset(&extendedInfo, 0, sizeof(EXTENDED_CREATE_INFORMATION));\n    extendedInfo.ExtendedCreateFlags = CreateFlags;\n\n    status = NtCreateFile(\n        &fileHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &ioStatusBlock,\n        AllocationSize,\n        FileAttributes,\n        ShareAccess,\n        CreateDisposition,\n        CreateOptions | FILE_CONTAINS_EXTENDED_CREATE_INFORMATION,\n        &extendedInfo,\n        sizeof(EXTENDED_CREATE_INFORMATION)\n        );\n\n    if (status == STATUS_SHARING_VIOLATION &&\n        KsiLevel() >= KphLevelMed &&\n        (DesiredAccess & KPH_FILE_READ_ACCESS) == DesiredAccess &&\n        CreateDisposition == KPH_FILE_READ_DISPOSITION)\n    {\n        status = KphCreateFile(\n            &fileHandle,\n            DesiredAccess,\n            &objectAttributes,\n            &ioStatusBlock,\n            AllocationSize,\n            FileAttributes,\n            ShareAccess,\n            CreateDisposition,\n            CreateOptions | FILE_CONTAINS_EXTENDED_CREATE_INFORMATION,\n            &extendedInfo,\n            sizeof(EXTENDED_CREATE_INFORMATION),\n            IO_IGNORE_SHARE_ACCESS_CHECK\n            );\n    }\n\n    RtlFreeUnicodeString(&fileName);\n\n    if (NT_SUCCESS(status))\n    {\n        *FileHandle = fileHandle;\n    }\n\n    if (CreateStatus)\n        *CreateStatus = (ULONG)ioStatusBlock.Information;\n\n    return status;\n}\n\n/**\n * Creates or opens a file.\n *\n * \\param FileHandle A variable that receives the file handle.\n * \\param FileName The Win32 file name.\n * \\param DesiredAccess The desired access to the file.\n * \\param FileAttributes File attributes applied if the file is created or overwritten.\n * \\param ShareAccess The file access granted to other threads.\n * \\li \\c FILE_SHARE_READ Allows other threads to read from the file.\n * \\li \\c FILE_SHARE_WRITE Allows other threads to write to the file.\n * \\li \\c FILE_SHARE_DELETE Allows other threads to delete the file.\n * \\param CreateDisposition The action to perform if the file does or does not exist.\n * \\li \\c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file.\n * \\li \\c FILE_CREATE If the file exists, fail. Otherwise, create the file.\n * \\li \\c FILE_OPEN If the file exists, open it. Otherwise, fail.\n * \\li \\c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file.\n * \\li \\c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail.\n * \\li \\c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file.\n * \\param CreateOptions The options to apply when the file is opened or created.\n * \\return Successful or errant status.\n */\nNTSTATUS PhCreateFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    if (!PhStringRefToUnicodeString(FileName, &fileName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &fileHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &ioStatusBlock,\n        NULL,\n        FileAttributes,\n        ShareAccess,\n        CreateDisposition,\n        CreateOptions,\n        NULL,\n        0\n        );\n\n    if (status == STATUS_SHARING_VIOLATION &&\n        KsiLevel() >= KphLevelMed &&\n        (DesiredAccess & KPH_FILE_READ_ACCESS) == DesiredAccess &&\n        CreateDisposition == KPH_FILE_READ_DISPOSITION)\n    {\n        status = KphCreateFile(\n            &fileHandle,\n            DesiredAccess,\n            &objectAttributes,\n            &ioStatusBlock,\n            NULL,\n            FileAttributes,\n            ShareAccess,\n            CreateDisposition,\n            CreateOptions,\n            NULL,\n            0,\n            IO_IGNORE_SHARE_ACCESS_CHECK\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *FileHandle = fileHandle;\n    }\n\n    return status;\n}\n\n/**\n * Creates or opens a file.\n *\n * \\param FileHandle A variable that receives the file handle.\n * \\param FileName The Win32 file name.\n * \\param DesiredAccess The desired access to the file.\n * \\param RootDirectory The root object directory for the file.\n * \\param AllocationSize The initial allocation size if the file is being created, overwritten, or superseded.\n * \\param FileAttributes File attributes applied if the file is created or overwritten.\n * \\param ShareAccess The file access granted to other threads.\n * \\li \\c FILE_SHARE_READ Allows other threads to read from the file.\n * \\li \\c FILE_SHARE_WRITE Allows other threads to write to the file.\n * \\li \\c FILE_SHARE_DELETE Allows other threads to delete the file.\n * \\param CreateDisposition The action to perform if the file does or does not exist.\n * \\li \\c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file.\n * \\li \\c FILE_CREATE If the file exists, fail. Otherwise, create the file.\n * \\li \\c FILE_OPEN If the file exists, open it. Otherwise, fail.\n * \\li \\c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file.\n * \\li \\c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail.\n * \\li \\c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file.\n * \\param CreateOptions The options to apply when the file is opened or created.\n * \\param CreateStatus A variable that receives creation information.\n * \\li \\c FILE_SUPERSEDED The file was replaced because \\c FILE_SUPERSEDE was specified in\n * \\a CreateDisposition.\n * \\li \\c FILE_OPENED The file was opened because \\c FILE_OPEN or \\c FILE_OPEN_IF was specified in\n * \\a CreateDisposition.\n * \\li \\c FILE_CREATED The file was created because \\c FILE_CREATE or \\c FILE_OPEN_IF was specified\n * in \\a CreateDisposition.\n * \\li \\c FILE_OVERWRITTEN The file was overwritten because \\c FILE_OVERWRITE or\n * \\c FILE_OVERWRITE_IF was specified in \\a CreateDisposition.\n * \\li \\c FILE_EXISTS The file was not opened because it already existed and \\c FILE_CREATE was\n * specified in \\a CreateDisposition.\n * \\li \\c FILE_DOES_NOT_EXIST The file was not opened because it did not exist and \\c FILE_OPEN or\n * \\c FILE_OVERWRITE was specified in \\a CreateDisposition.\n * \\return Successful or errant status.\n */\nNTSTATUS PhCreateFileEx(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG CreateStatus\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    if (!PhStringRefToUnicodeString(FileName, &fileName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &fileHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &ioStatusBlock,\n        AllocationSize,\n        FileAttributes,\n        ShareAccess,\n        CreateDisposition,\n        CreateOptions,\n        NULL,\n        0\n        );\n\n    if (status == STATUS_SHARING_VIOLATION &&\n        KsiLevel() >= KphLevelMed &&\n        (DesiredAccess & KPH_FILE_READ_ACCESS) == DesiredAccess &&\n        CreateDisposition == KPH_FILE_READ_DISPOSITION)\n    {\n        status = KphCreateFile(\n            &fileHandle,\n            DesiredAccess,\n            &objectAttributes,\n            &ioStatusBlock,\n            AllocationSize,\n            FileAttributes,\n            ShareAccess,\n            CreateDisposition,\n            CreateOptions,\n            NULL,\n            0,\n            IO_IGNORE_SHARE_ACCESS_CHECK\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *FileHandle = fileHandle;\n    }\n\n    if (CreateStatus)\n        *CreateStatus = (ULONG)ioStatusBlock.Information;\n\n    return status;\n}\n\nNTSTATUS PhOpenFileWin32(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions\n    )\n{\n    return PhOpenFileWin32Ex(\n        FileHandle,\n        FileName,\n        DesiredAccess,\n        ShareAccess,\n        OpenOptions,\n        NULL\n        );\n}\n\nNTSTATUS PhOpenFileWin32Ex(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions,\n    _Out_opt_ PULONG OpenStatus\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    status = PhDosLongPathNameToNtPathNameWithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &fileHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &ioStatusBlock,\n        ShareAccess,\n        OpenOptions\n        );\n\n    RtlFreeUnicodeString(&fileName);\n\n    if (NT_SUCCESS(status))\n    {\n        *FileHandle = fileHandle;\n    }\n\n    if (OpenStatus)\n        *OpenStatus = (ULONG)ioStatusBlock.Information;\n\n    return status;\n}\n\nNTSTATUS PhOpenFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions,\n    _Out_opt_ PULONG OpenStatus\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    if (!PhStringRefToUnicodeString(FileName, &fileName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &fileHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &ioStatusBlock,\n        ShareAccess,\n        OpenOptions\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *FileHandle = fileHandle;\n    }\n\n    if (OpenStatus)\n    {\n        *OpenStatus = (ULONG)ioStatusBlock.Information;\n    }\n\n    return status;\n}\n\n// rev from OpenFileById\nNTSTATUS PhOpenFileById(\n    _Out_ PHANDLE FileHandle,\n    _In_ HANDLE VolumeHandle,\n    _In_ PPH_FILE_ID_DESCRIPTOR FileId,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    switch (FileId->Type)\n    {\n    case FileIdType:\n        {\n            fileName.Length = sizeof(LONGLONG);\n            fileName.MaximumLength = sizeof(LONGLONG);\n            fileName.Buffer = (PWSTR)&FileId->FileId.QuadPart;\n        }\n        break;\n    case ObjectIdType:\n        {\n            fileName.Length = sizeof(GUID);\n            fileName.MaximumLength = sizeof(GUID);\n            fileName.Buffer = (PWSTR)&FileId->ObjectId;\n        }\n        break;\n    case ExtendedFileIdType:\n        {\n            fileName.Length = sizeof(FILE_ID_128);\n            fileName.MaximumLength = sizeof(FILE_ID_128);\n            fileName.Buffer = (PWSTR)&FileId->ExtendedFileId.Identifier;\n        }\n        break;\n    default:\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        VolumeHandle,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &fileHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &ioStatusBlock,\n        ShareAccess,\n        OpenOptions | FILE_OPEN_BY_FILE_ID\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *FileHandle = fileHandle;\n    }\n\n    return status;\n}\n\n// rev from ReOpenFile (dmex)\n/**\n * Reopens the specified file handle with different access rights, sharing mode, and flags.\n * Note: This function creates new FILE_OBJECTs compared to other functions simply referencing the existing object.\n *\n * \\param FileHandle A variable that receives the file handle.\n * \\param OriginalFileHandle A handle to the object to be reopened.\n * \\param DesiredAccess The desired access to the file.\n * \\param ShareAccess The file access granted to other threads.\n * \\param OpenOptions The options to apply when the file is opened.\n * \\return Successful or errant status.\n */\nNTSTATUS PhReOpenFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ HANDLE OriginalFileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    RtlInitEmptyUnicodeString(&fileName, NULL, 0);\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        OriginalFileHandle,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &fileHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &ioStatusBlock,\n        NULL,\n        0,\n        ShareAccess,\n        FILE_OPEN,\n        OpenOptions,\n        NULL,\n        0\n        );\n\n    if (status == STATUS_SHARING_VIOLATION &&\n        KsiLevel() >= KphLevelMed &&\n        (DesiredAccess & KPH_FILE_READ_ACCESS) == DesiredAccess)\n    {\n        assert(KPH_FILE_READ_DISPOSITION == FILE_OPEN);\n\n        status = KphCreateFile(\n            &fileHandle,\n            DesiredAccess,\n            &objectAttributes,\n            &ioStatusBlock,\n            NULL,\n            0,\n            ShareAccess,\n            FILE_OPEN,\n            OpenOptions,\n            NULL,\n            0,\n            IO_IGNORE_SHARE_ACCESS_CHECK\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *FileHandle = fileHandle;\n    }\n\n    return status;\n}\n\nNTSTATUS PhReadFile(\n    _In_ HANDLE FileHandle,\n    _In_ PVOID Buffer,\n    _In_opt_ ULONG NumberOfBytesToRead,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _Out_opt_ PULONG NumberOfBytesRead\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtReadFile(\n        FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        Buffer,\n        NumberOfBytesToRead,\n        ByteOffset,\n        NULL\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(FileHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n        {\n            status = isb.Status;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (NumberOfBytesRead)\n        {\n            *NumberOfBytesRead = (ULONG)isb.Information;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhWriteFile(\n    _In_ HANDLE FileHandle,\n    _In_ PVOID Buffer,\n    _In_opt_ ULONG NumberOfBytesToWrite,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _Out_opt_ PULONG NumberOfBytesWritten\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtWriteFile(\n        FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        Buffer,\n        NumberOfBytesToWrite,\n        ByteOffset,\n        NULL\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(FileHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n        {\n            status = isb.Status;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (NumberOfBytesWritten)\n        {\n            *NumberOfBytesWritten = (ULONG)isb.Information;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhEnumDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PCPH_STRINGREF SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    return PhEnumDirectoryFileEx(\n        FileHandle,\n        FileDirectoryInformation,\n        FALSE,\n        SearchPattern,\n        Callback,\n        Context\n        );\n}\n\nNTSTATUS PhEnumDirectoryFileEx(\n    _In_ HANDLE FileHandle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_opt_ PCPH_STRINGREF SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    BOOLEAN firstTime = TRUE;\n    UNICODE_STRING searchPattern;\n    PVOID buffer;\n    ULONG bufferSize = 0x400;\n    ULONG i;\n    BOOLEAN cont;\n\n    if (SearchPattern)\n    {\n        if (!PhStringRefToUnicodeString(SearchPattern, &searchPattern))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&searchPattern, NULL, 0);\n    }\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        // Query the directory, doubling the buffer each time NtQueryDirectoryFile fails. (wj32)\n        while (TRUE)\n        {\n            status = NtQueryDirectoryFile(\n                FileHandle,\n                NULL,\n                NULL,\n                NULL,\n                &isb,\n                buffer,\n                bufferSize,\n                FileInformationClass,\n                ReturnSingleEntry,\n                &searchPattern,\n                firstTime\n                );\n\n            // Our ISB is on the stack, so we have to wait for the operation to complete before continuing. (wj32)\n            if (status == STATUS_PENDING)\n            {\n                status = NtWaitForSingleObject(FileHandle, FALSE, NULL);\n\n                if (NT_SUCCESS(status))\n                    status = isb.Status;\n            }\n\n            if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH)\n            {\n                PhFree(buffer);\n                bufferSize *= 2;\n                buffer = PhAllocate(bufferSize);\n            }\n            else\n            {\n                break;\n            }\n        }\n\n        // If we don't have any entries to read, exit. (wj32)\n        if (status == STATUS_NO_MORE_FILES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        // Read the batch and execute the callback function for each file. (wj32)\n\n        i = 0;\n        cont = TRUE;\n\n        while (TRUE)\n        {\n            CONST PFILE_DIRECTORY_NEXT_INFORMATION information = PTR_ADD_OFFSET(buffer, i);\n\n            if (!Callback(FileHandle, information, Context))\n            {\n                cont = FALSE;\n                break;\n            }\n\n            if (information->NextEntryOffset != 0)\n                i += information->NextEntryOffset;\n            else\n                break;\n        }\n\n        if (!cont)\n            break;\n\n        firstTime = FALSE;\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\n/**\n * Queries file attributes.\n *\n * \\param FileName The Win32 file name.\n * \\param FileInformation A variable that receives the file information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryFullAttributesFileWin32(\n    _In_ PCWSTR FileName,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    status = PhDosLongPathNameToNtPathNameWithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtQueryFullAttributesFile(&objectAttributes, FileInformation);\n\n    RtlFreeUnicodeString(&fileName);\n\n    return status;\n}\n\n/**\n * Queries file attributes.\n *\n * \\param FileName The file name.\n * \\param FileInformation A variable that receives the file information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryFullAttributesFile(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (!PhStringRefToUnicodeString(FileName, &fileName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtQueryFullAttributesFile(&objectAttributes, FileInformation);\n\n    return status;\n}\n\n/**\n * Queries file attributes.\n *\n * \\param FileName The Win32 file name.\n * \\param FileInformation A variable that receives the file information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryAttributesFileWin32(\n    _In_ PCWSTR FileName,\n    _Out_ PFILE_BASIC_INFORMATION FileInformation\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    status = PhDosLongPathNameToNtPathNameWithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtQueryAttributesFile(&objectAttributes, FileInformation);\n\n    RtlFreeUnicodeString(&fileName);\n\n    return status;\n}\n\n/**\n * Queries file attributes.\n *\n * \\param FileName The file name.\n * \\param FileInformation A variable that receives the file information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryAttributesFile(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_ PFILE_BASIC_INFORMATION FileInformation\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (!PhStringRefToUnicodeString(FileName, &fileName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtQueryAttributesFile(&objectAttributes, FileInformation);\n\n    return status;\n}\n\n// rev from RtlDoesFileExists_U (dmex)\n/**\n * Checks whether a file exists at the specified path using Win32 APIs.\n *\n * \\param FileName A pointer to a null-terminated string that specifies the path to the file.\n * \\return Returns TRUE if the file exists, otherwise FALSE.\n */\nBOOLEAN PhDoesFileExistWin32(\n    _In_ PCWSTR FileName\n    )\n{\n    NTSTATUS status;\n    FILE_BASIC_INFORMATION basicInfo;\n\n    status = PhQueryAttributesFileWin32(FileName, &basicInfo);\n\n    if (\n        NT_SUCCESS(status) ||\n        status == STATUS_SHARING_VIOLATION ||\n        status == STATUS_ACCESS_DENIED\n        )\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Checks whether a file exists at the specified path.\n *\n * \\param FileName A pointer to a PH_STRINGREF structure that specifies the path of the file to check.\n * \\return TRUE if the file exists, FALSE otherwise.\n */\nBOOLEAN PhDoesFileExist(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    FILE_BASIC_INFORMATION basicInfo;\n\n    status = PhQueryAttributesFile(FileName, &basicInfo);\n\n    if (\n        NT_SUCCESS(status) ||\n        status == STATUS_SHARING_VIOLATION ||\n        status == STATUS_ACCESS_DENIED\n        )\n    {\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Checks whether a directory exists at the specified path.\n *\n * \\param FileName The path of the directory to check.\n * \\return TRUE if the directory exists, FALSE otherwise.\n */\nBOOLEAN PhDoesDirectoryExistWin32(\n    _In_ PCWSTR FileName\n    )\n{\n    NTSTATUS status;\n    FILE_BASIC_INFORMATION basicInfo;\n\n    status = PhQueryAttributesFileWin32(FileName, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        if (basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Checks whether a directory exists at the specified path.\n *\n * \\param FileName The path of the directory to check.\n * \\return TRUE if the directory exists, FALSE otherwise.\n */\nBOOLEAN PhDoesDirectoryExist(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    FILE_BASIC_INFORMATION basicInfo;\n\n    status = PhQueryAttributesFile(FileName, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        if (basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n// rev from RtlDetermineDosPathNameType_U (dmex)\n/**\n * Determines the type of DOS path name.\n *\n * \\param FileName A reference to the file name string.\n * \\return The type of the DOS path name.\n */\nRTL_PATH_TYPE PhDetermineDosPathNameType(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n#if defined(PHNT_USE_NATIVE_PATHTYPE)\n    return RtlDetermineDosPathNameType_U(FileName);\n#else\n    if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR || FileName->Buffer[0] == OBJ_NAME_ALTPATH_SEPARATOR)\n    {\n        if (FileName->Buffer[1] == OBJ_NAME_PATH_SEPARATOR || FileName->Buffer[1] == OBJ_NAME_ALTPATH_SEPARATOR)\n        {\n            if (FileName->Buffer[2] == L'?' || FileName->Buffer[2] == L'.')\n            {\n                if (FileName->Buffer[3] == OBJ_NAME_PATH_SEPARATOR || FileName->Buffer[3] == OBJ_NAME_ALTPATH_SEPARATOR)\n                    return RtlPathTypeLocalDevice;\n\n                if (FileName->Buffer[3] != UNICODE_NULL)\n                    return RtlPathTypeUncAbsolute;\n\n                return RtlPathTypeRootLocalDevice;\n            }\n\n            return RtlPathTypeUncAbsolute;\n        }\n\n        return RtlPathTypeRooted;\n    }\n    else if (FileName->Buffer[0] != UNICODE_NULL && FileName->Buffer[1] == L':')\n    {\n        if (FileName->Buffer[2] == OBJ_NAME_PATH_SEPARATOR || FileName->Buffer[2] == OBJ_NAME_ALTPATH_SEPARATOR)\n            return RtlPathTypeDriveAbsolute;\n\n        return RtlPathTypeDriveRelative;\n    }\n\n    return RtlPathTypeRelative;\n#endif\n}\n\n/**\n * Deletes a file.\n *\n * \\param FileName The Win32 file name.\n */\nNTSTATUS PhDeleteFileWin32(\n    _In_ PCWSTR FileName\n    )\n{\n    NTSTATUS status;\n#if defined(PHNT_USE_NATIVE_DELETE)\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    status = PhDosLongPathNameToNtPathNameWithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtDeleteFile(&objectAttributes);\n\n    RtlFreeUnicodeString(&fileName);\n\n    if (!NT_SUCCESS(status))\n#endif\n    {\n        HANDLE fileHandle;\n\n        status = PhCreateFileWin32(\n            &fileHandle,\n            FileName,\n            DELETE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DELETE_ON_CLOSE\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            if (status == STATUS_OBJECT_NAME_NOT_FOUND)\n                status = STATUS_SUCCESS;\n            return status;\n        }\n\n        //PhSetFileDelete(fileHandle);\n\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\n/**\n * Deletes a file.\n *\n * \\param FileName The file name.\n */\nNTSTATUS PhDeleteFile(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n#if defined(PHNT_USE_NATIVE_DELETE)\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtDeleteFile(&objectAttributes);\n\n    RtlFreeUnicodeString(&fileName);\n\n    if (!NT_SUCCESS(status))\n#endif\n    {\n        HANDLE fileHandle;\n\n        status = PhCreateFile(\n            &fileHandle,\n            FileName,\n            DELETE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DELETE_ON_CLOSE\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            if (status == STATUS_OBJECT_NAME_NOT_FOUND)\n                status = STATUS_SUCCESS;\n            return status;\n        }\n\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\n/**\n * Creates a directory path recursively.\n *\n * \\param DirectoryPath The directory path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateDirectory(\n    _In_ PCPH_STRINGREF DirectoryPath\n    )\n{\n    PPH_STRING directoryPath;\n    PPH_STRING directoryName;\n    PH_STRINGREF directoryPart;\n    PH_STRINGREF remainingPart;\n\n    if (PhDoesDirectoryExist(DirectoryPath))\n        return STATUS_SUCCESS;\n\n    directoryPath = PhGetExistingPathPrefix(DirectoryPath);\n\n    if (PhIsNullOrEmptyString(directoryPath))\n        return STATUS_UNSUCCESSFUL;\n\n    remainingPart.Length = DirectoryPath->Length - directoryPath->Length - sizeof(OBJ_NAME_PATH_SEPARATOR);\n    remainingPart.Buffer = PTR_ADD_OFFSET(DirectoryPath->Buffer, directoryPath->Length + sizeof(OBJ_NAME_PATH_SEPARATOR));\n\n    while (remainingPart.Length != 0)\n    {\n        PhSplitStringRefAtChar(&remainingPart, OBJ_NAME_PATH_SEPARATOR, &directoryPart, &remainingPart);\n\n        if (directoryPart.Length != 0)\n        {\n            directoryName = PhConcatStringRef3(\n                &directoryPath->sr,\n                &PhNtPathSeparatorString,\n                &directoryPart\n                );\n\n            if (!PhDoesDirectoryExist(&directoryName->sr))\n            {\n                HANDLE directoryHandle;\n\n                if (NT_SUCCESS(PhCreateFile(\n                    &directoryHandle,\n                    &directoryName->sr,\n                    FILE_LIST_DIRECTORY | SYNCHRONIZE,\n                    FILE_ATTRIBUTE_NORMAL,\n                    FILE_SHARE_READ | FILE_SHARE_WRITE,\n                    FILE_CREATE,\n                    FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT //| FILE_OPEN_REPARSE_POINT\n                    )))\n                {\n                    NtClose(directoryHandle);\n                }\n            }\n\n            PhMoveReference(&directoryPath, directoryName);\n        }\n    }\n\n    PhClearReference(&directoryPath);\n\n    if (!PhDoesDirectoryExist(DirectoryPath))\n        return STATUS_NOT_FOUND;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Creates a directory path recursively.\n *\n * \\param DirectoryPath The Win32 directory path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateDirectoryWin32(\n    _In_ PCPH_STRINGREF DirectoryPath\n    )\n{\n    PPH_STRING directoryPath;\n    PPH_STRING directoryName;\n    PH_STRINGREF directoryPart;\n    PH_STRINGREF remainingPart;\n\n    if (PhDoesDirectoryExistWin32(PhGetStringRefZ(DirectoryPath)))\n        return STATUS_SUCCESS;\n\n    directoryPath = PhGetExistingPathPrefixWin32(DirectoryPath);\n\n    if (PhIsNullOrEmptyString(directoryPath))\n        return STATUS_UNSUCCESSFUL;\n\n    remainingPart.Length = DirectoryPath->Length - directoryPath->Length - sizeof(OBJ_NAME_PATH_SEPARATOR);\n    remainingPart.Buffer = PTR_ADD_OFFSET(DirectoryPath->Buffer, directoryPath->Length + sizeof(OBJ_NAME_PATH_SEPARATOR));\n\n    while (remainingPart.Length != 0)\n    {\n        PhSplitStringRefAtChar(&remainingPart, OBJ_NAME_PATH_SEPARATOR, &directoryPart, &remainingPart);\n\n        if (directoryPart.Length != 0)\n        {\n            if (PhIsNullOrEmptyString(directoryPath))\n            {\n                PhMoveReference(&directoryPath, PhCreateString2(&directoryPart));\n            }\n            else\n            {\n                directoryName = PhConcatStringRef3(&directoryPath->sr, &PhNtPathSeparatorString, &directoryPart);\n\n                // Check if the directory already exists. (dmex)\n\n                if (!PhDoesDirectoryExistWin32(PhGetString(directoryName)))\n                {\n                    HANDLE directoryHandle;\n\n                    // Create the directory. (dmex)\n\n                    if (NT_SUCCESS(PhCreateFileWin32(\n                        &directoryHandle,\n                        PhGetString(directoryName),\n                        FILE_LIST_DIRECTORY | SYNCHRONIZE,\n                        FILE_ATTRIBUTE_NORMAL,\n                        FILE_SHARE_READ | FILE_SHARE_WRITE,\n                        FILE_CREATE,\n                        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT //| FILE_OPEN_REPARSE_POINT\n                        )))\n                    {\n                        NtClose(directoryHandle);\n                    }\n                }\n\n                PhMoveReference(&directoryPath, directoryName);\n            }\n        }\n    }\n\n    PhClearReference(&directoryPath);\n\n    if (!PhDoesDirectoryExistWin32(PhGetStringRefZ(DirectoryPath)))\n        return STATUS_NOT_FOUND;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Creates a directory path recursively.\n *\n * \\param DirectoryPath The Win32 directory path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateDirectoryFullPathWin32(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    PH_STRINGREF directoryPart;\n    PPH_STRING directoryPath;\n    PPH_STRING directory;\n\n    if (PhGetBasePath(FileName, &directoryPart, NULL))\n    {\n        if (directory = PhCreateString2(&directoryPart))\n        {\n            if (NT_SUCCESS(PhGetFullPath(PhGetString(directory), &directoryPath, NULL)))\n            {\n                status = PhCreateDirectoryWin32(&directoryPath->sr);\n                PhDereferenceObject(directoryPath);\n            }\n\n            PhDereferenceObject(directory);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Creates a directory path recursively.\n *\n * \\param DirectoryPath The directory path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateDirectoryFullPath(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    PH_STRINGREF directoryPart;\n\n    if (PhGetBasePath(FileName, &directoryPart, NULL))\n    {\n        return PhCreateDirectory(&directoryPart);\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n// NOTE: This callback handles both Native and Win32 filenames\n// since they're both relative to the parent RootDirectory. (dmex)\n_Function_class_(PH_ENUM_DIRECTORY_FILE)\nstatic BOOLEAN PhDeleteDirectoryCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PFILE_DIRECTORY_INFORMATION Information,\n    _In_ PVOID Context\n    )\n{\n    PH_STRINGREF fileName;\n    HANDLE fileHandle;\n\n    fileName.Buffer = Information->FileName;\n    fileName.Length = Information->FileNameLength;\n\n    if (FlagOn(Information->FileAttributes, FILE_ATTRIBUTE_DIRECTORY))\n    {\n        if (PATH_IS_WIN32_RELATIVE_PREFIX(&fileName))\n            return TRUE;\n\n        if (NT_SUCCESS(PhCreateFileEx(\n            &fileHandle,\n            &fileName,\n            FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE,\n            RootDirectory,\n            NULL,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT, // | FILE_OPEN_REPARSE_POINT\n            NULL\n            )))\n        {\n            PhEnumDirectoryFile(fileHandle, NULL, PhDeleteDirectoryCallback, Context);\n\n            PhSetFileDelete(fileHandle);\n\n            NtClose(fileHandle);\n        }\n    }\n    else\n    {\n        if (NT_SUCCESS(PhCreateFileEx(\n            &fileHandle,\n            &fileName,\n            FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE,\n            RootDirectory,\n            NULL,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, // | FILE_OPEN_REPARSE_POINT\n            NULL\n            )))\n        {\n            if (FlagOn(Information->FileAttributes, FILE_ATTRIBUTE_READONLY) && WindowsVersion < WINDOWS_10_RS5)\n            {\n                FILE_BASIC_INFORMATION fileBasicInfo;\n\n                memset(&fileBasicInfo, 0, sizeof(FILE_BASIC_INFORMATION));\n                fileBasicInfo.FileAttributes = ClearFlag(Information->FileAttributes, FILE_ATTRIBUTE_READONLY);\n\n                PhSetFileBasicInformation(fileHandle, &fileBasicInfo);\n            }\n\n            PhSetFileDelete(fileHandle);\n\n            NtClose(fileHandle);\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Deletes a directory path recursively.\n *\n * \\param DirectoryPath The directory path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhDeleteDirectory(\n    _In_ PCPH_STRINGREF DirectoryPath\n    )\n{\n    NTSTATUS status;\n    HANDLE directoryHandle;\n\n    status = PhCreateFile(\n        &directoryHandle,\n        DirectoryPath,\n        FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        // Remove any files or folders inside the directory. (dmex)\n        status = PhEnumDirectoryFile(\n            directoryHandle,\n            NULL,\n            PhDeleteDirectoryCallback,\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // Remove the directory. (dmex)\n            status = PhSetFileDelete(directoryHandle);\n        }\n\n        NtClose(directoryHandle);\n    }\n\n    if (!PhDoesDirectoryExist(DirectoryPath))\n        return STATUS_SUCCESS;\n\n    return status;\n}\n\n/**\n * Deletes a directory path recursively.\n *\n * \\param DirectoryPath The Win32 directory path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhDeleteDirectoryWin32(\n    _In_ PCPH_STRINGREF DirectoryPath\n    )\n{\n    NTSTATUS status;\n    HANDLE directoryHandle;\n\n    status = PhCreateFileWin32(\n        &directoryHandle,\n        PhGetStringRefZ(DirectoryPath),\n        FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        // Remove any files or folders inside the directory. (dmex)\n        status = PhEnumDirectoryFile(\n            directoryHandle,\n            NULL,\n            PhDeleteDirectoryCallback,\n            (PVOID)DirectoryPath\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // Remove the directory. (dmex)\n            status = PhSetFileDelete(directoryHandle);\n        }\n\n        NtClose(directoryHandle);\n    }\n\n    if (!PhDoesDirectoryExistWin32(PhGetStringRefZ(DirectoryPath)))\n        return STATUS_SUCCESS;\n\n    return status;\n}\n\n/**\n * Deletes a directory path recursively.\n *\n * \\param DirectoryPath The directory path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhDeleteDirectoryFullPath(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    PH_STRINGREF directoryPart;\n\n    if (PhGetBasePath(FileName, &directoryPart, NULL))\n    {\n        return PhDeleteDirectory(&directoryPart);\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\n/**\n * Copies a file from OldFileName to NewFileName using Win32 APIs.\n *\n * \\param OldFileName The path to the source file to copy.\n * \\param NewFileName The path to the destination file.\n * \\param FailIfExists If TRUE, the function fails if the destination file already exists.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCopyFileWin32(\n    _In_ PCWSTR OldFileName,\n    _In_ PCWSTR NewFileName,\n    _In_ BOOLEAN FailIfExists\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    HANDLE newFileHandle;\n    FILE_BASIC_INFORMATION basicInfo;\n    LARGE_INTEGER newFileSize;\n    IO_STATUS_BLOCK isb;\n    ULONG bufferLength;\n    PBYTE buffer;\n\n    status = PhCreateFileWin32(\n        &fileHandle,\n        OldFileName,\n        FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetFileBasicInformation(fileHandle, &basicInfo);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetFileSize(fileHandle, &newFileSize);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreateFileWin32Ex(\n        &newFileHandle,\n        NewFileName,\n        FILE_GENERIC_WRITE,\n        &newFileSize,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FailIfExists ? FILE_CREATE : FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    bufferLength = PAGE_SIZE * 2;\n    buffer = PhAllocatePage(bufferLength, NULL);\n\n    if (!buffer)\n    {\n        status = STATUS_NO_MEMORY;\n        goto CleanupExit;\n    }\n\n    while (TRUE)\n    {\n        status = NtReadFile(\n            fileHandle,\n            NULL,\n            NULL,\n            NULL,\n            &isb,\n            buffer,\n            bufferLength,\n            NULL,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n        if (isb.Information == 0)\n            break;\n\n        status = NtWriteFile(\n            newFileHandle,\n            NULL,\n            NULL,\n            NULL,\n            &isb,\n            buffer,\n            (ULONG)isb.Information,\n            NULL,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n        if (isb.Information == 0)\n            break;\n    }\n\n    PhFreePage(buffer);\n\n    if (status == STATUS_END_OF_FILE)\n    {\n        status = STATUS_SUCCESS;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        PhSetFileBasicInformation(\n            newFileHandle,\n            &basicInfo\n            );\n    }\n    else\n    {\n        PhSetFileDelete(newFileHandle);\n    }\n\n    NtClose(newFileHandle);\n\nCleanupExit:\n    NtClose(fileHandle);\n\n    return status;\n}\n\n/**\n * Copies a file from OldFileName to NewFileName using file chunk APIs.\n *\n * \\param OldFileName The path to the source file to copy.\n * \\param NewFileName The path to the destination file.\n * \\param FailIfExists If TRUE, the function fails if the destination file already exists.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCopyFileChunkDirectIoWin32(\n    _In_ PCWSTR OldFileName,\n    _In_ PCWSTR NewFileName,\n    _In_ BOOLEAN FailIfExists\n    )\n{\n    NTSTATUS status;\n    HANDLE sourceHandle;\n    HANDLE destinationHandle;\n    FILE_BASIC_INFORMATION basicInfo;\n    FILE_FS_SECTOR_SIZE_INFORMATION sourceSectorInfo = { 0 };\n    FILE_FS_SECTOR_SIZE_INFORMATION destinationSectorInfo = { 0 };\n    IO_STATUS_BLOCK ioStatusBlock;\n    LARGE_INTEGER sourceOffset = { 0 };\n    LARGE_INTEGER destinationOffset = { 0 };\n    LARGE_INTEGER fileSize;\n    SIZE_T numberOfBytes;\n    ULONG alignSize;\n    ULONG blockSize;\n\n    if (!NtCopyFileChunk_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    status = PhCreateFileWin32ExAlt(\n        &sourceHandle,\n        OldFileName,\n        FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NO_INTERMEDIATE_BUFFERING,\n        EX_CREATE_FLAG_FILE_SOURCE_OPEN_FOR_COPY,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetFileBasicInformation(sourceHandle, &basicInfo);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetFileSize(sourceHandle, &fileSize);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreateFileWin32ExAlt(\n        &destinationHandle,\n        NewFileName,\n        FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        0,\n        FailIfExists ? FILE_CREATE : FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NO_INTERMEDIATE_BUFFERING,\n        EX_CREATE_FLAG_FILE_DEST_OPEN_FOR_COPY,\n        &fileSize,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // https://learn.microsoft.com/en-us/windows/win32/w8cookbook/advanced-format--4k--disk-compatibility-update\n    NtQueryVolumeInformationFile(\n        sourceHandle,\n        &ioStatusBlock,\n        &sourceSectorInfo,\n        sizeof(FILE_FS_SECTOR_SIZE_INFORMATION),\n        FileFsSectorSizeInformation\n        );\n\n    NtQueryVolumeInformationFile(\n        destinationHandle,\n        &ioStatusBlock,\n        &destinationSectorInfo,\n        sizeof(FILE_FS_SECTOR_SIZE_INFORMATION),\n        FileFsSectorSizeInformation\n        );\n\n    // Non-cached I/O requires 'blockSize' be sector-aligned with whichever file is opened as non-cached.\n    // If both, the length should be aligned with the larger sector size of the two. (dmex)\n    alignSize = __max(max(sourceSectorInfo.PhysicalBytesPerSectorForPerformance, destinationSectorInfo.PhysicalBytesPerSectorForPerformance),\n        max(sourceSectorInfo.PhysicalBytesPerSectorForAtomicity, destinationSectorInfo.PhysicalBytesPerSectorForAtomicity));\n\n    // Enable BypassIO (skip error checking since might be disabled) (dmex)\n    PhSetFileBypassIO(sourceHandle, TRUE);\n    PhSetFileBypassIO(destinationHandle, TRUE);\n\n    blockSize = PAGE_SIZE;\n    numberOfBytes = (SIZE_T)fileSize.QuadPart;\n\n    while (numberOfBytes != 0)\n    {\n        if (blockSize > numberOfBytes)\n            blockSize = (ULONG)numberOfBytes;\n        blockSize = ALIGN_UP_BY(blockSize, alignSize);\n\n        status = NtCopyFileChunk_Import()(\n            sourceHandle,\n            destinationHandle,\n            NULL,\n            &ioStatusBlock,\n            blockSize,\n            &sourceOffset,\n            &destinationOffset,\n            NULL,\n            NULL,\n            0\n            );\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        destinationOffset.QuadPart += blockSize;\n        sourceOffset.QuadPart += blockSize;\n        numberOfBytes -= blockSize;\n    }\n\n    if (status == STATUS_END_OF_FILE)\n        status = STATUS_SUCCESS;\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhSetFileSize(destinationHandle, &fileSize); // Required (dmex)\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhSetFileBasicInformation(destinationHandle, &basicInfo);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhSetFileDelete(destinationHandle);\n    }\n\n    NtClose(destinationHandle);\n\nCleanupExit:\n    NtClose(sourceHandle);\n\n    return status;\n}\n\n/**\n * Copies a file from OldFileName to NewFileName using Win32 APIs, potentially in chunks.\n *\n * \\param OldFileName The path to the source file to copy.\n * \\param NewFileName The path to the destination file.\n * \\param FailIfExists If TRUE, the function fails if the destination file already exists.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCopyFileChunkWin32(\n    _In_ PCWSTR OldFileName,\n    _In_ PCWSTR NewFileName,\n    _In_ BOOLEAN FailIfExists\n    )\n{\n    NTSTATUS status;\n    HANDLE sourceHandle;\n    HANDLE destinationHandle;\n    FILE_BASIC_INFORMATION basicInfo;\n    IO_STATUS_BLOCK ioStatusBlock;\n    LARGE_INTEGER sourceOffset = { 0 };\n    LARGE_INTEGER destinationOffset = { 0 };\n    LARGE_INTEGER fileSize;\n\n    if (!NtCopyFileChunk_Import())\n    {\n        return PhCopyFileWin32(OldFileName, NewFileName, FailIfExists);\n    }\n\n    status = PhCreateFileWin32ExAlt(\n        &sourceHandle,\n        OldFileName,\n        FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        EX_CREATE_FLAG_FILE_SOURCE_OPEN_FOR_COPY,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetFileBasicInformation(sourceHandle, &basicInfo);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetFileSize(sourceHandle, &fileSize);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreateFileWin32ExAlt(\n        &destinationHandle,\n        NewFileName,\n        FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FailIfExists ? FILE_CREATE : FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        EX_CREATE_FLAG_FILE_DEST_OPEN_FOR_COPY,\n        &fileSize,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (fileSize.QuadPart >= ULONG_MAX)\n    {\n        SIZE_T numberOfBytes = (SIZE_T)fileSize.QuadPart;\n        ULONG blockSize = ULONG_MAX;\n\n        // Split into smaller blocks when the length\n        // overflows the maximum chunk size. (dmex)\n\n        while (numberOfBytes != 0)\n        {\n            if (blockSize > numberOfBytes)\n                blockSize = (ULONG)numberOfBytes;\n\n            status = NtCopyFileChunk_Import()(\n                sourceHandle,\n                destinationHandle,\n                NULL,\n                &ioStatusBlock,\n                blockSize,\n                &sourceOffset,\n                &destinationOffset,\n                NULL,\n                NULL,\n                0\n                );\n\n            if (!NT_SUCCESS(status))\n                break;\n\n            destinationOffset.QuadPart += blockSize;\n            sourceOffset.QuadPart += blockSize;\n            numberOfBytes -= blockSize;\n        }\n    }\n    else\n    {\n        status = NtCopyFileChunk_Import()(\n            sourceHandle,\n            destinationHandle,\n            NULL,\n            &ioStatusBlock,\n            (ULONG)fileSize.QuadPart,\n            &sourceOffset,\n            &destinationOffset,\n            NULL,\n            NULL,\n            0\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        PhSetFileBasicInformation(\n            destinationHandle,\n            &basicInfo\n            );\n    }\n    else\n    {\n        PhSetFileDelete(destinationHandle);\n    }\n\n    NtClose(destinationHandle);\n\nCleanupExit:\n    NtClose(sourceHandle);\n\n    return status;\n}\n\n/**\n * Moves a file from OldFileName to NewFileName.\n *\n * \\param OldFileName Pointer to a PH_STRINGREF structure containing the source file name.\n * \\param NewFileName Pointer to a PH_STRINGREF structure containing the destination file name.\n * \\param FailIfExists If TRUE, the operation fails if the destination file already exists.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhMoveFile(\n    _In_ PCPH_STRINGREF OldFileName,\n    _In_ PCPH_STRINGREF NewFileName,\n    _In_ BOOLEAN FailIfExists\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    IO_STATUS_BLOCK isb;\n    ULONG fileNameLength;\n    ULONG renameInfoLength;\n    PFILE_RENAME_INFORMATION renameInfo = NULL;\n\n    status = PhCreateFile(\n        &fileHandle,\n        OldFileName,\n        FILE_READ_ATTRIBUTES | FILE_READ_DATA | DELETE | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = RtlSIZETToULong(NewFileName->Length, &fileNameLength);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    renameInfoLength = sizeof(FILE_RENAME_INFORMATION) + fileNameLength + sizeof(UNICODE_NULL);\n    renameInfo = PhAllocateStack(renameInfoLength);\n    if (!renameInfo) return STATUS_NO_MEMORY;\n    memset(renameInfo, 0, renameInfoLength);\n    renameInfo->ReplaceIfExists = FailIfExists ? FALSE : TRUE;\n    renameInfo->RootDirectory = NULL;\n    renameInfo->FileNameLength = fileNameLength;\n    memcpy(renameInfo->FileName, NewFileName->Buffer, fileNameLength);\n\n    status = NtSetInformationFile(\n        fileHandle,\n        &isb,\n        renameInfo,\n        renameInfoLength,\n        FileRenameInformation\n        );\n\n    if (status == STATUS_NOT_SAME_DEVICE)\n    {\n        HANDLE newFileHandle;\n        LARGE_INTEGER newFileSize;\n        ULONG bufferLength;\n        PBYTE buffer;\n\n        status = PhGetFileSize(fileHandle, &newFileSize);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhCreateFileEx(\n            &newFileHandle,\n            NewFileName,\n            FILE_GENERIC_WRITE,\n            NULL,\n            &newFileSize,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FailIfExists ? FILE_CREATE : FILE_OVERWRITE_IF,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            bufferLength = PAGE_SIZE * 2;\n            buffer = PhAllocatePage(bufferLength, NULL);\n\n            if (!buffer)\n            {\n                status = STATUS_NO_MEMORY;\n                goto CleanupExit;\n            }\n\n            while (TRUE)\n            {\n                status = NtReadFile(\n                    fileHandle,\n                    NULL,\n                    NULL,\n                    NULL,\n                    &isb,\n                    buffer,\n                    bufferLength,\n                    NULL,\n                    NULL\n                    );\n\n                if (!NT_SUCCESS(status))\n                    break;\n                if (isb.Information == 0)\n                    break;\n\n                status = NtWriteFile(\n                    newFileHandle,\n                    NULL,\n                    NULL,\n                    NULL,\n                    &isb,\n                    buffer,\n                    (ULONG)isb.Information,\n                    NULL,\n                    NULL\n                    );\n\n                if (!NT_SUCCESS(status))\n                    break;\n                if (isb.Information == 0)\n                    break;\n            }\n\n            PhFreePage(buffer);\n\n            if (status == STATUS_END_OF_FILE)\n            {\n                status = STATUS_SUCCESS;\n            }\n\n            if (status != STATUS_SUCCESS)\n            {\n                PhSetFileDelete(newFileHandle);\n            }\n\n            NtClose(newFileHandle);\n        }\n    }\n\nCleanupExit:\n    NtClose(fileHandle);\n    PhFreeStack(renameInfo);\n\n    return status;\n}\n\n/**\n * Moves a file from OldFileName to NewFileName using Win32 semantics.\n *\n * \\param OldFileName The path to the existing file to be moved.\n * \\param NewFileName The destination path for the moved file.\n * \\param FailIfExists If TRUE, the operation fails if NewFileName already exists.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhMoveFileWin32(\n    _In_ PCWSTR OldFileName,\n    _In_ PCWSTR NewFileName,\n    _In_ BOOLEAN FailIfExists\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    IO_STATUS_BLOCK isb;\n    ULONG renameInfoLength;\n    UNICODE_STRING newFileName;\n    PFILE_RENAME_INFORMATION renameInfo;\n\n    status = PhDosLongPathNameToNtPathNameWithStatus(\n        NewFileName,\n        &newFileName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhCreateFileWin32(\n        &fileHandle,\n        OldFileName,\n        FILE_READ_ATTRIBUTES | FILE_READ_DATA | DELETE | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        RtlFreeUnicodeString(&newFileName);\n        return status;\n    }\n\n    renameInfoLength = sizeof(FILE_RENAME_INFORMATION) + newFileName.Length + sizeof(UNICODE_NULL);\n    renameInfo = PhAllocateStack(renameInfoLength);\n    if (!renameInfo) return STATUS_NO_MEMORY;\n    memset(renameInfo, 0, renameInfoLength);\n    renameInfo->ReplaceIfExists = FailIfExists ? FALSE : TRUE;\n    renameInfo->RootDirectory = NULL;\n    renameInfo->FileNameLength = newFileName.Length;\n    memcpy(renameInfo->FileName, newFileName.Buffer, newFileName.Length);\n    RtlFreeUnicodeString(&newFileName);\n\n    status = NtSetInformationFile(\n        fileHandle,\n        &isb,\n        renameInfo,\n        renameInfoLength,\n        FileRenameInformation\n        );\n\n    if (status == STATUS_NOT_SAME_DEVICE)\n    {\n        HANDLE newFileHandle;\n        LARGE_INTEGER newFileSize;\n        PBYTE buffer;\n\n        status = PhGetFileSize(fileHandle, &newFileSize);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhCreateFileWin32Ex(\n            &newFileHandle,\n            NewFileName,\n            FILE_GENERIC_WRITE,\n            &newFileSize,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FailIfExists ? FILE_CREATE : FILE_OVERWRITE_IF,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            buffer = PhAllocatePage(PAGE_SIZE * 2, NULL);\n\n            if (!buffer)\n            {\n                status = STATUS_NO_MEMORY;\n                goto CleanupExit;\n            }\n\n            while (TRUE)\n            {\n                status = NtReadFile(\n                    fileHandle,\n                    NULL,\n                    NULL,\n                    NULL,\n                    &isb,\n                    buffer,\n                    PAGE_SIZE * 2,\n                    NULL,\n                    NULL\n                    );\n\n                if (!NT_SUCCESS(status))\n                    break;\n                if (isb.Information == 0)\n                    break;\n\n                status = NtWriteFile(\n                    newFileHandle,\n                    NULL,\n                    NULL,\n                    NULL,\n                    &isb,\n                    buffer,\n                    (ULONG)isb.Information,\n                    NULL,\n                    NULL\n                    );\n\n                if (!NT_SUCCESS(status))\n                    break;\n                if (isb.Information == 0)\n                    break;\n            }\n\n            PhFreePage(buffer);\n\n            if (status == STATUS_END_OF_FILE)\n            {\n                status = STATUS_SUCCESS;\n            }\n\n            if (status != STATUS_SUCCESS)\n            {\n                PhSetFileDelete(newFileHandle);\n            }\n\n            NtClose(newFileHandle);\n        }\n    }\n\nCleanupExit:\n    NtClose(fileHandle);\n    PhFreeStack(renameInfo);\n\n    return status;\n}\n\n/**\n * \\brief Enumerates the volume Reparse Points using the \\\\$Extend\\\\$Reparse:$R:$INDEX_ALLOCATION directory.\n *\n * \\param FileHandle A handle to the volume.\n * \\param Callback A pointer to a callback function.\n * \\param Context A user-defined value to pass to the callback function.\n * \\return Successful or errant status\n */\nNTSTATUS PhEnumReparsePointInformation(\n    _In_ HANDLE FileHandle,\n    _In_ PPH_ENUM_REPARSE_POINT Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    BOOLEAN firstTime = TRUE;\n    ULONG bufferSize;\n    PVOID buffer;\n\n    bufferSize = sizeof(FILE_REPARSE_POINT_INFORMATION[512]);\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryDirectoryFile(\n            FileHandle,\n            NULL,\n            NULL,\n            NULL,\n            &isb,\n            buffer,\n            bufferSize,\n            FileReparsePointInformation,\n            FALSE,\n            NULL,\n            firstTime\n            );\n\n        if (status == STATUS_PENDING)\n        {\n            status = NtWaitForSingleObject(FileHandle, FALSE, NULL);\n\n            if (NT_SUCCESS(status))\n                status = isb.Status;\n        }\n\n        if (status == STATUS_NO_MORE_FILES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        status = Callback(FileHandle, buffer, isb.Information, Context);\n\n        if (status == STATUS_NO_MORE_FILES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        firstTime = FALSE;\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\n/**\n * \\brief Enumerates the volume ObjectIDs using the \\\\$Extend\\\\$ObjId:$O:$INDEX_ALLOCATION directory.\n *\n * \\param FileHandle A handle to the volume.\n * \\param Callback A pointer to a callback function.\n * \\param Context A user-defined value to pass to the callback function.\n * \\return Successful or errant status\n */\nNTSTATUS PhEnumObjectIdInformation(\n    _In_ HANDLE FileHandle,\n    _In_ PPH_ENUM_OBJECT_ID Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    BOOLEAN firstTime = TRUE;\n    ULONG bufferSize;\n    PVOID buffer;\n\n    bufferSize = sizeof(FILE_OBJECTID_INFORMATION[128]);\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryDirectoryFile(\n            FileHandle,\n            NULL,\n            NULL,\n            NULL,\n            &isb,\n            buffer,\n            bufferSize,\n            FileObjectIdInformation,\n            FALSE,\n            NULL,\n            firstTime\n            );\n\n        if (status == STATUS_PENDING)\n        {\n            status = NtWaitForSingleObject(FileHandle, FALSE, NULL);\n\n            if (NT_SUCCESS(status))\n                status = isb.Status;\n        }\n\n        if (status == STATUS_NO_MORE_FILES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        status = Callback(FileHandle, buffer, isb.Information, Context);\n\n        if (status == STATUS_NO_MORE_FILES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        firstTime = FALSE;\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\nNTSTATUS PhEnumFileExtendedAttributes(\n    _In_ HANDLE FileHandle,\n    _In_ PPH_ENUM_FILE_EA Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    BOOLEAN firstTime = TRUE;\n    IO_STATUS_BLOCK isb;\n    ULONG bufferSize;\n    PVOID buffer;\n\n    bufferSize = 0x400;\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        while (TRUE)\n        {\n            status = NtQueryEaFile(\n                FileHandle,\n                &isb,\n                buffer,\n                bufferSize,\n                FALSE,\n                NULL,\n                0,\n                NULL,\n                firstTime\n                );\n\n            if (status == STATUS_PENDING)\n            {\n                status = NtWaitForSingleObject(FileHandle, FALSE, NULL);\n\n                if (NT_SUCCESS(status))\n                    status = isb.Status;\n            }\n\n            if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH)\n            {\n                PhFree(buffer);\n                bufferSize *= 2;\n                buffer = PhAllocate(bufferSize);\n            }\n            else\n            {\n                break;\n            }\n        }\n\n        if (status == STATUS_NO_MORE_FILES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        status = Callback(FileHandle, buffer, Context);\n\n        if (status == STATUS_NO_MORE_FILES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        firstTime = FALSE;\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\nNTSTATUS PhSetFileExtendedAttributes(\n    _In_ HANDLE FileHandle,\n    _In_ PPH_BYTESREF Name,\n    _In_opt_ PPH_BYTESREF Value\n    )\n{\n    NTSTATUS status;\n    ULONG infoLength;\n    PFILE_FULL_EA_INFORMATION info;\n    IO_STATUS_BLOCK isb;\n\n    infoLength = sizeof(FILE_FULL_EA_INFORMATION) + (ULONG)Name->Length + sizeof(ANSI_NULL);\n    if (Value) infoLength += (ULONG)Value->Length + sizeof(ANSI_NULL);\n\n    info = PhAllocateZero(infoLength);\n    info->EaNameLength = (UCHAR)Name->Length;\n    memcpy(\n        info->EaName,\n        Name->Buffer,\n        Name->Length\n        );\n\n    if (Value)\n    {\n        info->EaValueLength = (USHORT)Value->Length;\n        memcpy(\n            PTR_ADD_OFFSET(info->EaName, info->EaNameLength + sizeof(ANSI_NULL)),\n            Value->Buffer,\n            Value->Length\n            );\n    }\n\n    status = NtSetEaFile(\n        FileHandle,\n        &isb,\n        info,\n        infoLength\n        );\n\n    PhFree(info);\n\n    return status;\n}\n\nNTSTATUS PhpQueryFileVariableSize(\n    _In_ HANDLE FileHandle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PVOID buffer;\n    ULONG bufferSize = 0x200;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryInformationFile(\n            FileHandle,\n            &isb,\n            buffer,\n            bufferSize,\n            FileInformationClass\n            );\n\n        if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\nNTSTATUS PhEnumFileStreams(\n    _In_ HANDLE FileHandle,\n    _Out_ PVOID *Streams\n    )\n{\n    return PhpQueryFileVariableSize(\n        FileHandle,\n        FileStreamInformation,\n        Streams\n        );\n}\n\nNTSTATUS PhEnumFileHardLinks(\n    _In_ HANDLE FileHandle,\n    _Out_ PVOID *HardLinks\n    )\n{\n    return PhpQueryFileVariableSize(\n        FileHandle,\n        FileHardLinkInformation,\n        HardLinks\n        );\n}\n\n/**\n * Queries information about the volume associated with a given file, directory, storage device, or volume.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param FileHandle A handle to the volume.\n * \\param FsInformationClass Type of information to be returned about the volume.\n * \\param FsInformation A pointer to a caller-allocated buffer.\n * \\param FsInformationLength Size in bytes of the buffer pointed to by FsInformation.\n * \\param IoStatusBlock A pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the query operation.\n */\nNTSTATUS PhQueryVolumeInformationFile(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ HANDLE FileHandle,\n    _In_ FS_INFORMATION_CLASS FsInformationClass,\n    _Out_writes_bytes_(FsInformationLength) PVOID FsInformation,\n    _In_ ULONG FsInformationLength,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    )\n{\n    NTSTATUS status;\n\n    if (ProcessHandle)\n    {\n        if (KsiLevel() >= KphLevelMed)\n        {\n            status = KphQueryVolumeInformationFile(\n                ProcessHandle,\n                FileHandle,\n                FsInformationClass,\n                FsInformation,\n                FsInformationLength,\n                IoStatusBlock\n                );\n        }\n        else if (ProcessHandle == NtCurrentProcess())\n        {\n            status = NtQueryVolumeInformationFile(\n                FileHandle,\n                IoStatusBlock,\n                FsInformation,\n                FsInformationLength,\n                FsInformationClass\n                );\n        }\n        else\n        {\n            status = STATUS_UNSUCCESSFUL;\n        }\n    }\n    else\n    {\n        status = NtQueryVolumeInformationFile(\n            FileHandle,\n            IoStatusBlock,\n            FsInformation,\n            FsInformationLength,\n            FsInformationClass\n            );\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetFileBasicInformation(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_BASIC_INFORMATION BasicInfo\n    )\n{\n    IO_STATUS_BLOCK isb;\n\n    return NtQueryInformationFile(\n        FileHandle,\n        &isb,\n        BasicInfo,\n        sizeof(FILE_BASIC_INFORMATION),\n        FileBasicInformation\n        );\n}\n\nNTSTATUS PhSetFileBasicInformation(\n    _In_ HANDLE FileHandle,\n    _In_ PFILE_BASIC_INFORMATION BasicInfo\n    )\n{\n    IO_STATUS_BLOCK isb;\n\n    return NtSetInformationFile(\n        FileHandle,\n        &isb,\n        BasicInfo,\n        sizeof(FILE_BASIC_INFORMATION),\n        FileBasicInformation\n        );\n}\n\nNTSTATUS PhGetFileFullAttributesInformation(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    FILE_NETWORK_OPEN_INFORMATION fullAttributesInfo;\n\n    status = NtQueryInformationFile(\n        FileHandle,\n        &isb,\n        &fullAttributesInfo,\n        sizeof(FILE_NETWORK_OPEN_INFORMATION),\n        FileNetworkOpenInformation\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *FileInformation = fullAttributesInfo;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetFileStandardInformation(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_STANDARD_INFORMATION StandardInfo\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    FILE_STANDARD_INFORMATION standardInfo;\n\n    status = NtQueryInformationFile(\n        FileHandle,\n        &isb,\n        &standardInfo,\n        sizeof(FILE_STANDARD_INFORMATION),\n        FileStandardInformation\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *StandardInfo = standardInfo;\n    }\n\n    return status;\n}\n\n// rev from SetFileCompletionNotificationModes (dmex)\nNTSTATUS PhSetFileCompletionNotificationMode(\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags\n    )\n{\n    FILE_IO_COMPLETION_NOTIFICATION_INFORMATION completionMode;\n    IO_STATUS_BLOCK isb;\n\n    completionMode.Flags = Flags;\n\n    return NtSetInformationFile(\n        FileHandle,\n        &isb,\n        &completionMode,\n        sizeof(FILE_IO_COMPLETION_NOTIFICATION_INFORMATION),\n        FileIoCompletionNotificationInformation\n        );\n}\n\nNTSTATUS PhGetFileSize(\n    _In_ HANDLE FileHandle,\n    _Out_ PLARGE_INTEGER Size\n    )\n{\n    NTSTATUS status;\n    FILE_STANDARD_INFORMATION standardInfo;\n\n    status = PhGetFileStandardInformation(\n        FileHandle,\n        &standardInfo\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Size = standardInfo.EndOfFile;\n    }\n\n    return status;\n}\n\nNTSTATUS PhSetFileSize(\n    _In_ HANDLE FileHandle,\n    _In_ PLARGE_INTEGER Size\n    )\n{\n    FILE_END_OF_FILE_INFORMATION endOfFileInfo;\n    IO_STATUS_BLOCK isb;\n\n    endOfFileInfo.EndOfFile = *Size;\n\n    return NtSetInformationFile(\n        FileHandle,\n        &isb,\n        &endOfFileInfo,\n        sizeof(FILE_END_OF_FILE_INFORMATION),\n        FileEndOfFileInformation\n        );\n}\n\nNTSTATUS PhGetFilePosition(\n    _In_ HANDLE FileHandle,\n    _Out_ PLARGE_INTEGER Position\n    )\n{\n    NTSTATUS status;\n    FILE_POSITION_INFORMATION positionInfo;\n    IO_STATUS_BLOCK isb;\n\n    status = NtQueryInformationFile(\n        FileHandle,\n        &isb,\n        &positionInfo,\n        sizeof(FILE_POSITION_INFORMATION),\n        FilePositionInformation\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *Position = positionInfo.CurrentByteOffset;\n\n    return status;\n}\n\nNTSTATUS PhSetFilePosition(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PLARGE_INTEGER Position\n    )\n{\n    FILE_POSITION_INFORMATION positionInfo;\n    IO_STATUS_BLOCK isb;\n\n    if (Position)\n        positionInfo.CurrentByteOffset.QuadPart = Position->QuadPart;\n    else\n        positionInfo.CurrentByteOffset.QuadPart = 0;\n\n    return NtSetInformationFile(\n        FileHandle,\n        &isb,\n        &positionInfo,\n        sizeof(FILE_POSITION_INFORMATION),\n        FilePositionInformation\n        );\n}\n\nNTSTATUS PhGetFileAllocationSize(\n    _In_ HANDLE FileHandle,\n    _Out_ PLARGE_INTEGER AllocationSize\n    )\n{\n    NTSTATUS status;\n    FILE_ALLOCATION_INFORMATION allocationInfo;\n    IO_STATUS_BLOCK isb;\n\n    status = NtQueryInformationFile(\n        FileHandle,\n        &isb,\n        &allocationInfo,\n        sizeof(FILE_ALLOCATION_INFORMATION),\n        FileAllocationInformation\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *AllocationSize = allocationInfo.AllocationSize;\n\n    return status;\n}\n\nNTSTATUS PhSetFileAllocationSize(\n    _In_ HANDLE FileHandle,\n    _In_ PLARGE_INTEGER AllocationSize\n    )\n{\n    FILE_ALLOCATION_INFORMATION allocationInfo;\n    IO_STATUS_BLOCK isb;\n\n    allocationInfo.AllocationSize = *AllocationSize;\n\n    return NtSetInformationFile(\n        FileHandle,\n        &isb,\n        &allocationInfo,\n        sizeof(FILE_ALLOCATION_INFORMATION),\n        FileAllocationInformation\n        );\n}\n\nNTSTATUS PhGetFileIndexNumber(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_INTERNAL_INFORMATION IndexNumber\n    )\n{\n    IO_STATUS_BLOCK isb;\n\n    return NtQueryInformationFile(\n        FileHandle,\n        &isb,\n        IndexNumber,\n        sizeof(FILE_INTERNAL_INFORMATION),\n        FileInternalInformation\n        );\n}\n\nNTSTATUS PhGetFileIsRemoteDevice(\n    _In_ HANDLE FileHandle,\n    _Out_ PBOOLEAN FileIsRemoteDevice\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK ioStatusBlock;\n    FILE_IS_REMOTE_DEVICE_INFORMATION fileRemoteInfo;\n\n    status = NtQueryInformationFile(\n        FileHandle,\n        &ioStatusBlock,\n        &fileRemoteInfo,\n        sizeof(FILE_IS_REMOTE_DEVICE_INFORMATION),\n        FileIsRemoteDeviceInformation\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *FileIsRemoteDevice = !!fileRemoteInfo.IsRemote;\n    }\n\n    return status;\n}\n\nNTSTATUS PhSetFileDelete(\n    _In_ HANDLE FileHandle\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n\n    if (WindowsVersion >= WINDOWS_10_RS5)\n    {\n        FILE_DISPOSITION_INFO_EX dispositionInfo;\n        IO_STATUS_BLOCK ioStatusBlock;\n\n        dispositionInfo.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE;\n        status = NtSetInformationFile(\n            FileHandle,\n            &ioStatusBlock,\n            &dispositionInfo,\n            sizeof(FILE_DISPOSITION_INFO_EX),\n            FileDispositionInformationEx\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        FILE_DISPOSITION_INFORMATION dispositionInfo;\n        IO_STATUS_BLOCK ioStatusBlock;\n\n        dispositionInfo.DeleteFile = TRUE;\n        status = NtSetInformationFile(\n            FileHandle,\n            &ioStatusBlock,\n            &dispositionInfo,\n            sizeof(FILE_DISPOSITION_INFORMATION),\n            FileDispositionInformation\n            );\n    }\n\n    //if (!NT_SUCCESS(status))\n    //{\n    //    HANDLE deleteHandle;\n    //\n    //    if (NT_SUCCESS(PhReOpenFile(\n    //        &deleteHandle,\n    //        FileHandle,\n    //        DELETE,\n    //        FILE_SHARE_DELETE,\n    //        FILE_DELETE_ON_CLOSE\n    //        )))\n    //    {\n    //        NtClose(deleteHandle);\n    //        status = STATUS_SUCCESS;\n    //    }\n    //}\n\n    return status;\n}\n\nNTSTATUS PhSetFileRename(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ BOOLEAN ReplaceIfExists,\n    _In_ PCPH_STRINGREF NewFileName\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n\n    if (WindowsVersion >= WINDOWS_10_RS2)\n    {\n        PFILE_RENAME_INFORMATION_EX renameInfo;\n        IO_STATUS_BLOCK ioStatusBlock;\n        ULONG renameInfoLength;\n\n        renameInfoLength = sizeof(FILE_RENAME_INFORMATION_EX) + (ULONG)NewFileName->Length + sizeof(UNICODE_NULL);\n        renameInfo = PhAllocateStack(renameInfoLength);\n\n        if (renameInfo)\n        {\n            RtlZeroMemory(renameInfo, renameInfoLength);\n            renameInfo->Flags = (ReplaceIfExists ? FILE_RENAME_REPLACE_IF_EXISTS : 0) | FILE_RENAME_POSIX_SEMANTICS;\n            renameInfo->RootDirectory = RootDirectory;\n            renameInfo->FileNameLength = (ULONG)NewFileName->Length;\n            RtlCopyMemory(renameInfo->FileName, NewFileName->Buffer, NewFileName->Length);\n\n            if (WindowsVersion >= WINDOWS_10_RS5)\n            {\n                SetFlag(renameInfo->Flags, FILE_RENAME_IGNORE_READONLY_ATTRIBUTE);\n            }\n            else\n            {\n                FILE_BASIC_INFORMATION basicInfo;\n\n                RtlZeroMemory(&basicInfo, sizeof(FILE_BASIC_INFORMATION));\n                basicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;\n\n                PhSetFileBasicInformation(FileHandle, &basicInfo);\n            }\n\n            status = NtSetInformationFile(\n                FileHandle,\n                &ioStatusBlock,\n                renameInfo,\n                renameInfoLength,\n                FileRenameInformationEx\n                );\n\n            PhFreeStack(renameInfo);\n        }\n        else\n        {\n            status = STATUS_NO_MEMORY;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PFILE_RENAME_INFORMATION renameInfo;\n        IO_STATUS_BLOCK ioStatusBlock;\n        ULONG renameInfoLength;\n\n        renameInfoLength = sizeof(FILE_RENAME_INFORMATION) + (ULONG)NewFileName->Length + sizeof(UNICODE_NULL);\n        renameInfo = PhAllocateStack(renameInfoLength);\n\n        if (renameInfo)\n        {\n            RtlZeroMemory(renameInfo, renameInfoLength);\n            renameInfo->ReplaceIfExists = ReplaceIfExists;\n            renameInfo->RootDirectory = RootDirectory;\n            renameInfo->FileNameLength = (ULONG)NewFileName->Length;\n            RtlCopyMemory(renameInfo->FileName, NewFileName->Buffer, NewFileName->Length);\n\n            {\n                FILE_BASIC_INFORMATION basicInfo;\n\n                RtlZeroMemory(&basicInfo, sizeof(FILE_BASIC_INFORMATION));\n                basicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;\n\n                PhSetFileBasicInformation(FileHandle, &basicInfo);\n            }\n\n            status = NtSetInformationFile(\n                FileHandle,\n                &ioStatusBlock,\n                renameInfo,\n                renameInfoLength,\n                FileRenameInformation\n                );\n\n            PhFreeStack(renameInfo);\n        }\n        else\n        {\n            status = STATUS_NO_MEMORY;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetFileIoPriorityHint(\n    _In_ HANDLE FileHandle,\n    _Out_ IO_PRIORITY_HINT* IoPriorityHint\n    )\n{\n    NTSTATUS status;\n    FILE_IO_PRIORITY_HINT_INFORMATION ioPriorityHint;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    status = NtQueryInformationFile(\n        FileHandle,\n        &ioStatusBlock,\n        &ioPriorityHint,\n        sizeof(FILE_IO_PRIORITY_HINT_INFORMATION),\n        FileIoPriorityHintInformation\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *IoPriorityHint = ioPriorityHint.PriorityHint;\n\n    return status;\n}\n\nNTSTATUS PhSetFileIoPriorityHint(\n    _In_ HANDLE FileHandle,\n    _In_ IO_PRIORITY_HINT IoPriorityHint\n    )\n{\n    IO_STATUS_BLOCK ioStatusBlock;\n#ifndef _WIN64\n    FILE_IO_PRIORITY_HINT_INFORMATION ioPriorityHint;\n#else\n    FILE_IO_PRIORITY_HINT_INFORMATION_EX ioPriorityHint;\n#endif\n    memset(&ioPriorityHint, 0, sizeof(ioPriorityHint));\n\n    ioPriorityHint.PriorityHint = IoPriorityHint;\n\n    return NtSetInformationFile(\n        FileHandle,\n        &ioStatusBlock,\n        &ioPriorityHint,\n        sizeof(ioPriorityHint),\n        FileIoPriorityHintInformation\n        );\n}\n\n/**\n * Flushes the buffers of a file.\n * - Write any modified data for the given file from the Windows in-memory cache.\n * - Commit all pending metadata changes for the given file from the Windows in-memory cache.\n * - Send a SYNC command to the storage device to commit in-memory cache to persistent storage.\n * \\param FileHandle Handle to the file.\n * \\return NTSTATUS Status code.\n */\nNTSTATUS PhFlushBuffersFile(\n    _In_ HANDLE FileHandle\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    //if (WindowsVersion >= WINDOWS_8)\n    //{\n    //    status = NtFlushBuffersFileEx(volumeHandle, 0, 0, 0, &ioStatusBlock);\n    //}\n    //else\n    {\n        status = NtFlushBuffersFile(FileHandle, &ioStatusBlock);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetFileHandleName(\n    _In_ HANDLE FileHandle,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    ULONG bufferSize;\n    PFILE_NAME_INFORMATION buffer;\n    IO_STATUS_BLOCK isb;\n\n    bufferSize = sizeof(FILE_NAME_INFORMATION) + MAX_PATH;\n    buffer = PhAllocateZero(bufferSize);\n\n    status = NtQueryInformationFile(\n        FileHandle,\n        &isb,\n        buffer,\n        bufferSize,\n        FileNameInformation\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW)\n    {\n        bufferSize = sizeof(FILE_NAME_INFORMATION) + buffer->FileNameLength + sizeof(UNICODE_NULL);\n        PhFree(buffer);\n        buffer = PhAllocateZero(bufferSize);\n\n        status = NtQueryInformationFile(\n            FileHandle,\n            &isb,\n            buffer,\n            bufferSize,\n            FileNameInformation\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *FileName = PhCreateStringEx(buffer->FileName, buffer->FileNameLength);\n    PhFree(buffer);\n\n    return status;\n}\n\nNTSTATUS PhGetFileNetworkPhysicalName(\n    _In_ HANDLE FileHandle,\n    _Out_ PPH_STRING* FileName\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK ioStatusBlock;\n    ULONG bufferLength;\n    PFILE_NETWORK_PHYSICAL_NAME_INFORMATION buffer;\n\n    bufferLength = UFIELD_OFFSET(FILE_NETWORK_PHYSICAL_NAME_INFORMATION, FileName[DOS_MAX_PATH_LENGTH]) + sizeof(UNICODE_NULL);\n    buffer = PhAllocate(bufferLength);\n\n    status = NtQueryInformationFile(\n        FileHandle,\n        &ioStatusBlock,\n        buffer,\n        bufferLength,\n        FileNetworkPhysicalNameInformation\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW)\n    {\n        bufferLength = sizeof(FILE_NETWORK_PHYSICAL_NAME_INFORMATION) + buffer->FileNameLength;\n        PhFree(buffer);\n        buffer = PhAllocate(bufferLength);\n\n        status = NtQueryInformationFile(\n            FileHandle,\n            &ioStatusBlock,\n            buffer,\n            bufferLength,\n            FileNetworkPhysicalNameInformation\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *FileName = PhCreateStringEx(buffer->FileName, buffer->FileNameLength);\n    PhFree(buffer);\n\n    return status;\n}\n\nNTSTATUS PhGetFileAllInformation(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_ALL_INFORMATION *FileInformation\n    )\n{\n    return PhpQueryFileVariableSize(\n        FileHandle,\n        FileAllInformation,\n        FileInformation\n        );\n}\n\nNTSTATUS PhGetFileId(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_ID_INFORMATION FileId\n    )\n{\n    IO_STATUS_BLOCK isb;\n\n    return NtQueryInformationFile(\n        FileHandle,\n        &isb,\n        FileId,\n        sizeof(FILE_ID_INFORMATION),\n        FileIdInformation\n        );\n}\n\nNTSTATUS PhGetProcessIdsUsingFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *ProcessIdsUsingFile\n    )\n{\n    return PhpQueryFileVariableSize(\n        FileHandle,\n        FileProcessIdsUsingFileInformation,\n        ProcessIdsUsingFile\n        );\n}\n\nNTSTATUS PhGetProcessIdsUsingFileByName(\n    _In_ PCPH_STRINGREF FileName,\n    _In_opt_ HANDLE RootDirectory,\n    _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *ProcessIdsUsingFile\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n\n    status = PhOpenFile(\n        &fileHandle,\n        FileName,\n        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        RootDirectory,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhpQueryFileVariableSize(\n            fileHandle,\n            FileProcessIdsUsingFileInformation,\n            ProcessIdsUsingFile\n            );\n\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessesUsingVolumeOrFile(\n    _In_ HANDLE VolumeOrFileHandle,\n    _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *Information\n    )\n{\n    static ULONG initialBufferSize = 0x4000;\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    IO_STATUS_BLOCK isb;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQueryInformationFile(\n        VolumeOrFileHandle,\n        &isb,\n        buffer,\n        bufferSize,\n        FileProcessIdsUsingFileInformation\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > (1 << 30)) // 1GiB\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x100000) initialBufferSize = bufferSize;\n    *Information = (PFILE_PROCESS_IDS_USING_FILE_INFORMATION)buffer;\n\n    return status;\n}\n\nNTSTATUS PhGetFileUsn(\n    _In_ HANDLE FileHandle,\n    _Out_ PUSN Usn\n    )\n{\n    NTSTATUS status;\n    ULONG recordLength;\n    PUSN_RECORD_V2 recordBuffer; // USN_RECORD_UNION\n    UCHAR buffer[sizeof(USN_RECORD_V2) + MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR)];\n    IO_STATUS_BLOCK isb;\n\n    recordLength = sizeof(buffer);\n    recordBuffer = (PUSN_RECORD_V2)buffer;\n\n    status = NtFsControlFile(\n        FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_READ_FILE_USN_DATA, // FSCTL_WRITE_USN_CLOSE_RECORD\n        NULL, // READ_FILE_USN_DATA\n        0,\n        recordBuffer,\n        recordLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Usn = recordBuffer->Usn;\n\n        //switch (recordBuffer->Header.MajorVersion)\n        //{\n        //case 2:\n        //    *Usn = recordBuffer->V2.Usn;\n        //    break;\n        //case 3:\n        //    *Usn = recordBuffer->V3.Usn;\n        //    break;\n        //case 4:\n        //    *Usn = recordBuffer->V4.Usn;\n        //    break;\n        //}\n    }\n\n    return status;\n}\n\nNTSTATUS PhSetFileBypassIO(\n    _In_ HANDLE FileHandle,\n    _In_ BOOLEAN Enable\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK ioStatusBlock;\n    FS_BPIO_INPUT bypassIoInput;\n    FS_BPIO_OUTPUT bypassIoOutput;\n\n    // https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/bypassio\n    memset(&bypassIoInput, 0, sizeof(FS_BPIO_INPUT));\n    bypassIoInput.Operation = Enable ? FS_BPIO_OP_ENABLE : FS_BPIO_OP_DISABLE;\n    memset(&bypassIoOutput, 0, sizeof(FS_BPIO_OUTPUT));\n\n    status = NtFsControlFile(\n        FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &ioStatusBlock,\n        FSCTL_MANAGE_BYPASS_IO,\n        &bypassIoInput,\n        sizeof(bypassIoInput),\n        &bypassIoOutput,\n        sizeof(bypassIoOutput)\n        );\n\n#ifdef DEBUG\n    if (bypassIoOutput.OutFlags != FSBPIO_OUTFL_COMPATIBLE_STORAGE_DRIVER) // NT_SUCCESS(bypassIoOutput.Enable.OpStatus)\n    {\n        dprintf(\"BypassIO failed: (%S) %S\\n\", bypassIoOutput.Enable.FailingDriverName, bypassIoOutput.Enable.FailureReason);\n    }\n#endif\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/nativeflt.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     jxy-s   2024-2025\n *\n */\n\n#include <ph.h>\n\n/**\n * \\brief Wrapper which is essentially FilterpDeviceIoControl.\n *\n * \\param[in] Handle Filter port handle.\n * \\param[in] IoControlCode Filter I/O control code\n * \\param[in] InBuffer Input buffer.\n * \\param[in] InBufferSize Input buffer size.\n * \\param[out] OutputBuffer Output Buffer.\n * \\param[in] OutputBufferSize Output buffer size.\n * \\param[out] BytesReturned Optionally set to the number of bytes returned.\n * \\param[in,out] Overlapped Optional overlapped structure.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS PhpFilterDeviceIoControl(\n    _In_ HANDLE Handle,\n    _In_ ULONG IoControlCode,\n    _In_reads_bytes_(InBufferSize) PVOID InBuffer,\n    _In_ ULONG InBufferSize,\n    _Out_writes_bytes_to_opt_(OutputBufferSize, *BytesReturned) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferSize,\n    _Out_opt_ PULONG BytesReturned,\n    _Inout_opt_ LPOVERLAPPED Overlapped\n    )\n{\n    NTSTATUS status;\n\n    if (BytesReturned)\n        *BytesReturned = 0;\n\n    if (Overlapped)\n    {\n        Overlapped->Internal = STATUS_PENDING;\n\n        if (DEVICE_TYPE_FROM_CTL_CODE(IoControlCode) == FILE_DEVICE_FILE_SYSTEM)\n        {\n            status = NtFsControlFile(\n                Handle,\n                Overlapped->hEvent,\n                NULL,\n                Overlapped,\n                (PIO_STATUS_BLOCK)Overlapped,\n                IoControlCode,\n                InBuffer,\n                InBufferSize,\n                OutputBuffer,\n                OutputBufferSize\n                );\n        }\n        else\n        {\n            status = NtDeviceIoControlFile(\n                Handle,\n                Overlapped->hEvent,\n                NULL,\n                Overlapped,\n                (PIO_STATUS_BLOCK)Overlapped,\n                IoControlCode,\n                InBuffer,\n                InBufferSize,\n                OutputBuffer,\n                OutputBufferSize\n                );\n        }\n\n        if (NT_INFORMATION(status) && BytesReturned)\n            *BytesReturned = (ULONG)Overlapped->InternalHigh;\n    }\n    else\n    {\n        IO_STATUS_BLOCK ioStatusBlock;\n\n        if (DEVICE_TYPE_FROM_CTL_CODE(IoControlCode) == FILE_DEVICE_FILE_SYSTEM)\n        {\n            status = NtFsControlFile(\n                Handle,\n                NULL,\n                NULL,\n                NULL,\n                &ioStatusBlock,\n                IoControlCode,\n                InBuffer,\n                InBufferSize,\n                OutputBuffer,\n                OutputBufferSize\n                );\n        }\n        else\n        {\n            status = NtDeviceIoControlFile(\n                Handle,\n                NULL,\n                NULL,\n                NULL,\n                &ioStatusBlock,\n                IoControlCode,\n                InBuffer,\n                InBufferSize,\n                OutputBuffer,\n                OutputBufferSize\n                );\n        }\n\n        if (status == STATUS_PENDING)\n        {\n            if (NT_SUCCESS(status = NtWaitForSingleObject(Handle, FALSE, NULL)))\n                status = ioStatusBlock.Status;\n        }\n\n        if (BytesReturned)\n            *BytesReturned = (ULONG)ioStatusBlock.Information;\n    }\n\n    return status;\n}\n\n// rev from FilterLoad/FilterUnload (fltlib) (dmex)\n/**\n * \\brief An application with mini-filter support can dynamically load and\n * unload the mini-filter.\n *\n * \\param[in] ServiceName The service name from the registry.\n * \\param[in] LoadDriver TRUE to load the kernel driver, FALSE to unload the\n * kernel driver.\n *\n * \\remarks The caller must have SE_LOAD_DRIVER_PRIVILEGE.\n * \\remarks This IOCTL is a kernel wrapper around NtLoad/UnloadDriver.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS PhFilterLoadUnload(\n    _In_ PCPH_STRINGREF ServiceName,\n    _In_ BOOLEAN LoadDriver\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK ioStatusBlock;\n    ULONG filterLoadParametersLength;\n    PFLT_LOAD_PARAMETERS filterLoadParameters;\n    SECURITY_QUALITY_OF_SERVICE filterSecurityQos =\n    {\n        sizeof(SECURITY_QUALITY_OF_SERVICE),\n        SecurityImpersonation,\n        SECURITY_DYNAMIC_TRACKING,\n        TRUE\n    };\n\n    RtlInitUnicodeString(&objectName, FLT_MSG_DEVICE_NAME);\n    InitializeObjectAttributesEx(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE | (WindowsVersion < WINDOWS_10 ? 0 : OBJ_DONT_REPARSE),\n        NULL,\n        NULL,\n        &filterSecurityQos\n        );\n\n    if (!NT_SUCCESS(status = NtCreateFile(\n        &fileHandle,\n        FILE_READ_ATTRIBUTES | GENERIC_WRITE | SYNCHRONIZE,\n        &objectAttributes,\n        &ioStatusBlock,\n        NULL,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_WRITE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL,\n        0\n        )))\n        return status;\n\n    filterLoadParametersLength = UFIELD_OFFSET(FLT_LOAD_PARAMETERS, FilterName[ServiceName->Length]) + sizeof(UNICODE_NULL);\n    filterLoadParameters = PhAllocateStack(filterLoadParametersLength);\n\n    if (filterLoadParameters)\n    {\n        RtlZeroMemory(filterLoadParameters, filterLoadParametersLength);\n        filterLoadParameters->FilterNameSize = (USHORT)ServiceName->Length;\n        RtlCopyMemory(filterLoadParameters->FilterName, ServiceName->Buffer, ServiceName->Length);\n\n        status = NtDeviceIoControlFile(\n            fileHandle,\n            NULL,\n            NULL,\n            NULL,\n            &ioStatusBlock,\n            LoadDriver ? FLT_CTL_LOAD : FLT_CTL_UNLOAD,\n            filterLoadParameters,\n            filterLoadParametersLength,\n            NULL,\n            0\n            );\n\n        PhFreeStack(filterLoadParameters);\n    }\n    else\n    {\n        status = STATUS_NO_MEMORY;\n    }\n\n    NtClose(fileHandle);\n\n    return status;\n}\n\n/**\n * \\brief Wrapper which is essentially FilterSendMessage.\n *\n * \\param[in] Port Filter port handle.\n * \\param[in] InBuffer Input buffer.\n * \\param[in] InBufferSize Input buffer size.\n * \\param[out] OutputBuffer Output Buffer.\n * \\param[in] OutputBufferSize Output buffer size.\n * \\param[out] BytesReturned Set to the number of bytes returned.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS PhFilterSendMessage(\n    _In_ HANDLE Port,\n    _In_reads_bytes_(InBufferSize) PVOID InBuffer,\n    _In_ ULONG InBufferSize,\n    _Out_writes_bytes_to_opt_(OutputBufferSize, *BytesReturned) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferSize,\n    _Out_ PULONG BytesReturned\n    )\n{\n    return PhpFilterDeviceIoControl(\n        Port,\n        FLT_CTL_SEND_MESSAGE,\n        InBuffer,\n        InBufferSize,\n        OutputBuffer,\n        OutputBufferSize,\n        BytesReturned,\n        NULL\n        );\n}\n\n/**\n * \\brief Wrapper which is essentially FilterGetMessage.\n *\n * \\param[in] Port Filter port handle.\n * \\param[out] MessageBuffer Message buffer.\n * \\param[in] MessageBufferSize Message buffer size.\n * \\param[in] Overlapped Th overlapped structure.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS PhFilterGetMessage(\n    _In_ HANDLE Port,\n    _Out_writes_bytes_(MessageBufferSize) PFILTER_MESSAGE_HEADER MessageBuffer,\n    _In_ ULONG MessageBufferSize,\n    _Inout_ LPOVERLAPPED Overlapped\n    )\n{\n    return PhpFilterDeviceIoControl(\n        Port,\n        FLT_CTL_GET_MESSAGE,\n        NULL,\n        0,\n        MessageBuffer,\n        MessageBufferSize,\n        NULL,\n        Overlapped\n        );\n}\n\n/**\n * \\brief Wrapper which is essentially FilterReplyMessage.\n *\n * \\param[in] Port Filter port handle.\n * \\param[in] ReplyBuffer Reply buffer.\n * \\param[in] ReplyBufferSize Reply buffer size.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS PhFilterReplyMessage(\n    _In_ HANDLE Port,\n    _In_reads_bytes_(ReplyBufferSize) PFILTER_REPLY_HEADER ReplyBuffer,\n    _In_ ULONG ReplyBufferSize\n    )\n{\n    return PhpFilterDeviceIoControl(\n        Port,\n        FLT_CTL_REPLY_MESSAGE,\n        ReplyBuffer,\n        ReplyBufferSize,\n        NULL,\n        0,\n        NULL,\n        NULL\n        );\n}\n\n/**\n * \\brief Wrapper which is essentially FilterConnectCommunicationPort.\n *\n * \\param[in] PortName Name of filter port to connect to.\n * \\param[in] Options Filter port options.\n * \\param[in] ConnectionContext Connection context.\n * \\param[in] SizeOfContext Size of connection context.\n * \\param[in] SecurityAttributes Security attributes for handle.\n * \\param[out] Port Set to filter port handle on success, null on failure.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS PhFilterConnectCommunicationPort(\n    _In_ PCPH_STRINGREF PortName,\n    _In_ ULONG Options,\n    _In_reads_bytes_opt_(SizeOfContext) PVOID ConnectionContext,\n    _In_ USHORT SizeOfContext,\n    _In_opt_ PSECURITY_ATTRIBUTES SecurityAttributes,\n    _Outptr_ PHANDLE Port\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    UNICODE_STRING objectName;\n    UNICODE_STRING portName;\n    UNICODE_STRING64 portName64;\n    ULONG eaLength;\n    PFILE_FULL_EA_INFORMATION ea;\n    PFLT_CONNECT_CONTEXT eaValue;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    *Port = NULL;\n\n    if ((SizeOfContext > 0 && !ConnectionContext) || (SizeOfContext == 0 && ConnectionContext))\n        return STATUS_INVALID_PARAMETER;\n\n    if (SizeOfContext >= FLT_PORT_CONTEXT_MAX)\n        return STATUS_INTEGER_OVERFLOW;\n\n    if (!PhStringRefToUnicodeString(PortName, &portName))\n        return STATUS_NAME_TOO_LONG;\n\n    portName64.Buffer = (ULONGLONG)portName.Buffer;\n    portName64.Length = portName.Length;\n    portName64.MaximumLength = portName.MaximumLength;\n\n    //\n    // Build the filter EA, this contains the port name and the context.\n    //\n\n    eaLength = FLT_PORT_FULL_EA_SIZE + FLT_PORT_FULL_EA_VALUE_SIZE + SizeOfContext;\n    ea = _malloca(eaLength);\n\n    if (!ea)\n        return STATUS_NO_MEMORY;\n\n    RtlZeroMemory(ea, eaLength);\n    ea->Flags = 0;\n    ea->EaNameLength = sizeof(FLT_PORT_EA_NAME) - sizeof(ANSI_NULL);\n    ea->EaValueLength = FLT_PORT_FULL_EA_VALUE_SIZE + SizeOfContext;\n    RtlCopyMemory(ea->EaName, FLT_PORT_EA_NAME, sizeof(FLT_PORT_EA_NAME));\n    eaValue = PTR_ADD_OFFSET(ea->EaName, sizeof(FLT_PORT_EA_NAME));\n    eaValue->PortName = &portName;\n    eaValue->PortName64 = &portName64;\n    eaValue->SizeOfContext = SizeOfContext;\n\n    if (SizeOfContext > 0)\n        RtlCopyMemory(eaValue->Context, ConnectionContext, SizeOfContext);\n\n    RtlInitUnicodeString(&objectName, FLT_MSG_DEVICE_NAME);\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE | (WindowsVersion < WINDOWS_10 ? 0 : OBJ_DONT_REPARSE),\n        NULL,\n        NULL\n        );\n    if (SecurityAttributes)\n    {\n        if (SecurityAttributes->bInheritHandle)\n            objectAttributes.Attributes |= OBJ_INHERIT;\n        objectAttributes.SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;\n    }\n\n    status = NtCreateFile(\n        Port,\n        FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,\n        &objectAttributes,\n        &ioStatusBlock,\n        NULL,\n        0,\n        0,\n        FILE_OPEN_IF,\n        FlagOn(Options, FLT_PORT_FLAG_SYNC_HANDLE) ? FILE_SYNCHRONOUS_IO_NONALERT : 0,\n        ea,\n        eaLength\n        );\n\n    _freea(ea);\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/nativejob.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n\n /**\n  * Create a new job object in the object namespace.\n  *\n  * \\param JobObject Receives the handle to the created job object on success.\n  * \\param DesiredAccess Desired access mask for the returned handle (e.g., JOB_OBJECT_ALL_ACCESS).\n  * \\param RootDirectory Optional handle to an object directory; if non-NULL the object is created relative to this directory.\n  * \\param ObjectName Pointer to a constant string reference that names the object. If NULL or empty, an unnamed job is created.\n  * \\return NTSTATUS Successful or errant status.\n  */\nNTSTATUS PhCreateJobObject(\n    _Out_ PHANDLE JobObject,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_opt_ PCPH_STRINGREF ObjectName\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (ObjectName)\n    {\n        if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&objectName, NULL, 0);\n    }\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = NtCreateJobObject(\n        JobObject,\n        DesiredAccess,\n        &objectAttributes\n        );\n\n    return status;\n}\n\n/*\n * Opens a job object.\n *\n * \\param JobHandle A variable which receives a handle to the job object.\n * \\param DesiredAccess The desired access to the job object.\n * \\param RootDirectory A handle to the object directory of the job.\n * \\param ObjectName The name of the job object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenJobObject(\n    _Out_ PHANDLE JobHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = NtOpenJobObject(\n        JobHandle,\n        DesiredAccess,\n        &objectAttributes\n        );\n\n    return status;\n}\n\n/**\n * Retrieves the list of process IDs associated with a specified job object.\n *\n * \\param JobHandle A handle to the job object whose process ID list is to be retrieved.\n * \\param ProcessIdList A pointer to a JOBOBJECT_BASIC_PROCESS_ID_LIST structure containing the list of process IDs.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetJobProcessIdList(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_PROCESS_ID_LIST *ProcessIdList\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x100;\n\n    do\n    {\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQueryInformationJobObject(\n            JobHandle,\n            JobObjectBasicProcessIdList,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            *ProcessIdList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)buffer;\n        }\n        else\n        {\n            PhFree(buffer);\n        }\n\n    } while (status == STATUS_BUFFER_OVERFLOW);\n\n    return status;\n}\n\n/**\n * Query basic and I/O accounting information for a job object.\n *\n * \\param JobHandle Handle to the job object to query.\n * \\param BasicAndIoAccounting Pointer to a JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION structure that receives the data.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetJobBasicAndIoAccounting(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION BasicAndIoAccounting\n    )\n{\n    return NtQueryInformationJobObject(\n        JobHandle,\n        JobObjectBasicAndIoAccountingInformation,\n        BasicAndIoAccounting,\n        sizeof(JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * Query the basic limit information for a job object.\n *\n * \\param JobHandle Handle to the job object to query.\n * \\param BasicLimits Pointer to a JOBOBJECT_BASIC_LIMIT_INFORMATION structure that receives the data.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetJobBasicLimits(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimits\n    )\n{\n    return NtQueryInformationJobObject(\n        JobHandle,\n        JobObjectBasicLimitInformation,\n        BasicLimits,\n        sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * Query extended limit information for a job object.\n *\n * \\param JobHandle Handle to the job object to query.\n * \\param ExtendedLimits Pointer to a JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure that receives the data.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetJobExtendedLimits(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_EXTENDED_LIMIT_INFORMATION ExtendedLimits\n    )\n{\n    return NtQueryInformationJobObject(\n        JobHandle,\n        JobObjectExtendedLimitInformation,\n        ExtendedLimits,\n        sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * Query UI restrictions imposed by a job object.\n *\n * \\param JobHandle Handle to the job object to query.\n * \\param BasicUiRestrictions Pointer to a JOBOBJECT_BASIC_UI_RESTRICTIONS structure that receives the data.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetJobBasicUiRestrictions(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_UI_RESTRICTIONS BasicUiRestrictions\n    )\n{\n    return NtQueryInformationJobObject(\n        JobHandle,\n        JobObjectBasicUIRestrictions,\n        BasicUiRestrictions,\n        sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS),\n        NULL\n        );\n}\n"
  },
  {
    "path": "phlib/nativekey.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n\nstatic PH_INITONCE PhPredefineKeyInitOnce = PH_INITONCE_INIT;\nstatic UNICODE_STRING PhPredefineKeyNames[PH_KEY_MAXIMUM_PREDEFINE] =\n{\n    RTL_CONSTANT_STRING(L\"\\\\Registry\\\\Machine\"),\n    RTL_CONSTANT_STRING(L\"\\\\Registry\\\\User\"),\n    RTL_CONSTANT_STRING(L\"\\\\Registry\\\\Machine\\\\Software\\\\Classes\"),\n    { 0, 0, NULL }\n};\nstatic HANDLE PhPredefineKeyHandles[PH_KEY_MAXIMUM_PREDEFINE] = { 0 };\n\n/**\n * Initializes usage of predefined keys.\n */\nVOID PhpInitializePredefineKeys(\n    VOID\n    )\n{\n    static CONST UNICODE_STRING currentUserPrefix = RTL_CONSTANT_STRING(L\"\\\\Registry\\\\User\\\\\");\n    NTSTATUS status;\n    PH_TOKEN_USER tokenUser;\n    UNICODE_STRING stringSid;\n    WCHAR stringSidBuffer[SECURITY_MAX_SID_STRING_CHARACTERS];\n    PUNICODE_STRING currentUserKeyName;\n\n    // Get the string SID of the current user.\n\n    if (NT_SUCCESS(status = PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &tokenUser)))\n    {\n        RtlInitEmptyUnicodeString(&stringSid, stringSidBuffer, sizeof(stringSidBuffer));\n\n        if (PhEqualSid(tokenUser.User.Sid, &PhSeLocalSystemSid))\n        {\n            status = RtlInitUnicodeStringEx(&stringSid, L\".DEFAULT\");\n        }\n        else\n        {\n            status = RtlConvertSidToUnicodeString(&stringSid, tokenUser.User.Sid, FALSE);\n        }\n    }\n\n    // Construct the current user key name.\n\n    if (NT_SUCCESS(status))\n    {\n        currentUserKeyName = &PhPredefineKeyNames[PH_KEY_CURRENT_USER_NUMBER];\n        currentUserKeyName->Length = currentUserPrefix.Length + stringSid.Length;\n        currentUserKeyName->MaximumLength = currentUserKeyName->Length + sizeof(UNICODE_NULL);\n        currentUserKeyName->Buffer = PhAllocate(currentUserKeyName->MaximumLength);\n        memcpy(currentUserKeyName->Buffer, currentUserPrefix.Buffer, currentUserPrefix.Length);\n        memcpy(&currentUserKeyName->Buffer[currentUserPrefix.Length / sizeof(WCHAR)], stringSid.Buffer, stringSid.Length);\n    }\n}\n\n/**\n * Initializes the attributes of a key object for creating/opening.\n *\n * \\param RootDirectory A handle to a root key, or one of the predefined keys. See PhCreateKey() for details.\n * \\param ObjectName The path to the key.\n * \\param Attributes Additional object flags.\n * \\param ObjectAttributes The OBJECT_ATTRIBUTES structure to initialize.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpInitializeKeyObjectAttributes(\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ ULONG Attributes,\n    _Out_ POBJECT_ATTRIBUTES ObjectAttributes\n    )\n{\n    NTSTATUS status;\n    ULONG predefineIndex;\n    HANDLE predefineHandle;\n    OBJECT_ATTRIBUTES predefineObjectAttributes;\n\n    InitializeObjectAttributes(\n        ObjectAttributes,\n        ObjectName,\n        Attributes | OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    if (RootDirectory && PH_KEY_IS_PREDEFINED(RootDirectory))\n    {\n        predefineIndex = PH_KEY_PREDEFINE_TO_NUMBER(RootDirectory);\n\n        if (predefineIndex < PH_KEY_MAXIMUM_PREDEFINE)\n        {\n            if (PhBeginInitOnce(&PhPredefineKeyInitOnce))\n            {\n                PhpInitializePredefineKeys();\n                PhEndInitOnce(&PhPredefineKeyInitOnce);\n            }\n\n            predefineHandle = InterlockedReadPointer(&PhPredefineKeyHandles[predefineIndex]);\n\n            if (!predefineHandle)\n            {\n                // The predefined key has not been opened yet. Do so now.\n                if (!PhPredefineKeyNames[predefineIndex].Buffer) // we may have failed in getting the current user key name\n                    return STATUS_UNSUCCESSFUL;\n\n                InitializeObjectAttributes(\n                    &predefineObjectAttributes,\n                    &PhPredefineKeyNames[predefineIndex],\n                    OBJ_CASE_INSENSITIVE,\n                    NULL,\n                    NULL\n                    );\n\n                status = NtOpenKey(\n                    &predefineHandle,\n                    KEY_READ,\n                    &predefineObjectAttributes\n                    );\n\n                if (!NT_SUCCESS(status))\n                    return status;\n\n                HANDLE keyHandle = InterlockedCompareExchangePointer(\n                    &PhPredefineKeyHandles[predefineIndex],\n                    predefineHandle,\n                    NULL\n                    );\n\n                if (keyHandle)\n                {\n                    // Someone else already opened the key and cached it.\n                    NtClose(predefineHandle);\n                    predefineHandle = keyHandle;\n                }\n            }\n\n            ObjectAttributes->RootDirectory = predefineHandle;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Creates or opens a registry key.\n *\n * \\param KeyHandle A variable which receives a handle to the key.\n * \\param DesiredAccess The desired access to the key.\n * \\param RootDirectory A handle to a root key, or one of the following predefined keys:\n * \\li \\c PH_KEY_LOCAL_MACHINE Represents \\\\Registry\\\\Machine.\n * \\li \\c PH_KEY_USERS Represents \\\\Registry\\\\User.\n * \\li \\c PH_KEY_CLASSES_ROOT Represents \\\\Registry\\\\Machine\\\\Software\\\\Classes.\n * \\li \\c PH_KEY_CURRENT_USER Represents \\\\Registry\\\\User\\\\[SID of current user].\n * \\param ObjectName The path to the key.\n * \\param Attributes Additional object flags.\n * \\param CreateOptions The options to apply when creating or opening the key.\n * \\param Disposition A variable which receives a value indicating whether a new key was created or\n * an existing key was opened:\n * \\li \\c REG_CREATED_NEW_KEY A new key was created.\n * \\li \\c REG_OPENED_EXISTING_KEY An existing key was opened.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName,\n    _In_ ULONG Attributes,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG Disposition\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n        return STATUS_NAME_TOO_LONG;\n\n    if (!NT_SUCCESS(status = PhpInitializeKeyObjectAttributes(\n        RootDirectory,\n        &objectName,\n        Attributes,\n        &objectAttributes\n        )))\n    {\n        return status;\n    }\n\n    status = NtCreateKey(\n        KeyHandle,\n        DesiredAccess,\n        &objectAttributes,\n        0,\n        NULL,\n        CreateOptions,\n        Disposition\n        );\n\n    return status;\n}\n\n/**\n * Opens a registry key.\n *\n * \\param KeyHandle A variable which receives a handle to the key.\n * \\param DesiredAccess The desired access to the key.\n * \\param RootDirectory A handle to a root key, or one of the predefined keys. See PhCreateKey() for details.\n * \\param ObjectName The path to the key.\n * \\param Attributes Additional object flags.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF ObjectName,\n    _In_ ULONG Attributes\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n        return STATUS_NAME_TOO_LONG;\n\n    if (!NT_SUCCESS(status = PhpInitializeKeyObjectAttributes(\n        RootDirectory,\n        &objectName,\n        Attributes,\n        &objectAttributes\n        )))\n    {\n        return status;\n    }\n\n    status = NtOpenKey(\n        KeyHandle,\n        DesiredAccess,\n        &objectAttributes\n        );\n\n    return status;\n}\n\n// rev from RegLoadAppKey (dmex)\n/**\n * Loads the specified registry hive file into a private application hive.\n *\n * \\param KeyHandle A variable which receives a handle to the key.\n * \\param FileName A string containing a file name.\n * \\param DesiredAccess The desired access to the key.\n * \\param Flags Optional flags for loading the hive.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhLoadAppKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    GUID guid;\n    UNICODE_STRING fileName;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES targetAttributes;\n    OBJECT_ATTRIBUTES sourceAttributes;\n\n    if (!PhStringRefToUnicodeString(FileName, &fileName))\n        return STATUS_NAME_TOO_LONG;\n\n    PhGenerateGuid(&guid);\n\n#if defined(PHNT_USE_NATIVE_APPEND)\n    UNICODE_STRING guidStringUs;\n    WCHAR objectNameBuffer[MAXIMUM_FILENAME_LENGTH];\n\n    RtlInitEmptyUnicodeString(&objectName, objectNameBuffer, sizeof(objectNameBuffer));\n\n    if (!NT_SUCCESS(status = RtlStringFromGUID(&guid, &guidStringUs)))\n        return status;\n\n    if (!NT_SUCCESS(status = RtlAppendUnicodeToString(&objectName, L\"\\\\REGISTRY\\\\A\\\\\")))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = RtlAppendUnicodeStringToString(&objectName, &guidStringUs)))\n        goto CleanupExit;\n#else\n    static CONST PH_STRINGREF namespaceString = PH_STRINGREF_INIT(L\"\\\\REGISTRY\\\\A\\\\\");\n    PPH_STRING guidString;\n\n    if (!(guidString = PhFormatGuid(&guid)))\n        return STATUS_UNSUCCESSFUL;\n\n    PhMoveReference(&guidString, PhConcatStringRef2(&namespaceString, &guidString->sr));\n\n    if (!PhStringRefToUnicodeString(&guidString->sr, &objectName))\n    {\n        PhDereferenceObject(guidString);\n        return STATUS_NAME_TOO_LONG;\n    }\n#endif\n\n    InitializeObjectAttributes(\n        &targetAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    InitializeObjectAttributes(\n        &sourceAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtLoadKeyEx(\n        &targetAttributes,\n        &sourceAttributes,\n        REG_APP_HIVE | Flags,\n        NULL,\n        NULL,\n        DesiredAccess,\n        KeyHandle,\n        NULL\n        );\n\n#if defined(PHNT_USE_NATIVE_APPEND)\n    RtlFreeUnicodeString(&guidStringUs);\n#else\n    PhDereferenceObject(guidString);\n#endif\n\n    return status;\n}\n\n/**\n * Gets information about a registry key.\n *\n * \\param KeyHandle A handle to the key.\n * \\param KeyInformationClass The information class to query.\n * \\param Buffer A variable which receives a pointer to a buffer containing information about the\n * registry key. You must free the buffer with PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_INFORMATION_CLASS KeyInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG attempts = 16;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    do\n    {\n        status = NtQueryKey(\n            KeyHandle,\n            KeyInformationClass,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (NT_SUCCESS(status))\n            break;\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            PhFree(buffer);\n            return status;\n        }\n    } while (--attempts);\n\n    *Buffer = buffer;\n\n    return status;\n}\n\n/**\n * Gets the information for a registry key.\n *\n * \\param KeyHandle A handle to the key.\n * \\param Information The registry key information, including information\n * about its subkeys and the maximum length for their names and value entries.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryKeyInformation(\n    _In_ HANDLE KeyHandle,\n    _Out_opt_ PKEY_FULL_INFORMATION Information\n    )\n{\n    NTSTATUS status;\n    ULONG bufferLength = 0;\n\n    status = NtQueryKey(\n        KeyHandle,\n        KeyFullInformation,\n        Information,\n        sizeof(KEY_FULL_INFORMATION),\n        &bufferLength\n        );\n\n    return status;\n}\n\n/**\n * Gets the last write time for a registry key without allocating memory. (dmex)\n *\n * \\param KeyHandle A handle to the key.\n * \\param LastWriteTime The last write time of the key.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryKeyLastWriteTime(\n    _In_ HANDLE KeyHandle,\n    _Out_ PLARGE_INTEGER LastWriteTime\n    )\n{\n    NTSTATUS status;\n    KEY_BASIC_INFORMATION basicInfo = { 0 };\n    ULONG bufferLength = 0;\n\n    status = NtQueryKey(\n        KeyHandle,\n        KeyBasicInformation,\n        &basicInfo,\n        UFIELD_OFFSET(KEY_BASIC_INFORMATION, Name),\n        &bufferLength\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW && basicInfo.LastWriteTime.QuadPart != 0)\n    {\n        *LastWriteTime = basicInfo.LastWriteTime;\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        PKEY_BASIC_INFORMATION buffer;\n\n        status = PhQueryKey(\n            KeyHandle,\n            KeyBasicInformation,\n            &buffer\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            memcpy(LastWriteTime, &buffer->LastWriteTime, sizeof(LARGE_INTEGER));\n            PhFree(buffer);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Gets a registry value of any type.\n *\n * \\param KeyHandle A handle to the key.\n * \\param ValueName The name of the value.\n * \\param KeyValueInformationClass The information class to query.\n * \\param Buffer A variable which receives a pointer to a buffer containing information about the\n * registry value. You must free the buffer with PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName,\n    _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING valueName;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG attempts = 16;\n\n    if (ValueName && ValueName->Length)\n    {\n        if (!PhStringRefToUnicodeString(ValueName, &valueName))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&valueName, NULL, 0);\n    }\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    do\n    {\n        status = NtQueryValueKey(\n            KeyHandle,\n            &valueName,\n            KeyValueInformationClass,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (NT_SUCCESS(status))\n            break;\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            PhFree(buffer);\n            return status;\n        }\n    } while (--attempts);\n\n    *Buffer = buffer;\n\n    return status;\n}\n\n/**\n * Sets the value of a registry key.\n *\n * \\param KeyHandle Handle to an open registry key.\n * \\param ValueName Optional pointer to a PH_STRINGREF structure that specifies the name of the value to set.\n * \\param ValueType Type of data to be stored (e.g., REG_SZ, REG_DWORD).\n * \\param Buffer Pointer to the data to be stored.\n * \\param BufferLength Length, in bytes, of the data pointed to by Buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName,\n    _In_ ULONG ValueType,\n    _In_ PVOID Buffer,\n    _In_ ULONG BufferLength\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING valueName;\n\n    if (ValueName)\n    {\n        if (!PhStringRefToUnicodeString(ValueName, &valueName))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&valueName, NULL, 0);\n    }\n\n    status = NtSetValueKey(\n        KeyHandle,\n        &valueName,\n        0,\n        ValueType,\n        Buffer,\n        BufferLength\n        );\n\n    return status;\n}\n\n/**\n * Deletes a value from the specified registry key.\n *\n * \\param KeyHandle Handle to an open registry key.\n * \\param ValueName Optional. Pointer to a PH_STRINGREF structure that specifies the name of the value to delete.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhDeleteValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName\n    )\n{\n    UNICODE_STRING valueName;\n\n    if (ValueName)\n    {\n        if (!PhStringRefToUnicodeString(ValueName, &valueName))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitEmptyUnicodeString(&valueName, NULL, 0);\n    }\n\n    return NtDeleteValueKey(KeyHandle, &valueName);\n}\n\n/**\n * Enumerates subkeys of a registry key and invokes a callback for each enumerated entry.\n *\n * \\param KeyHandle Handle to an open registry key to enumerate.\n * \\param InformationClass KEY_INFORMATION_CLASS value specifying the format of the returned records.\n * \\param Callback A function pointer invoked for each successfully retrieved key entry.\n * \\param Context Optional context pointer forwarded to the callback.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumerateKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_INFORMATION_CLASS InformationClass,\n    _In_ PPH_ENUM_KEY_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG index = 0;\n\n    bufferSize = 0x100;\n    buffer = PhAllocateStack(bufferSize);\n    if (!buffer) return STATUS_NO_MEMORY;\n\n    while (TRUE)\n    {\n        status = NtEnumerateKey(\n            KeyHandle,\n            index,\n            InformationClass,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (status == STATUS_NO_MORE_ENTRIES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFreeStack(buffer);\n            buffer = PhAllocateStack(bufferSize);\n            if (!buffer) return STATUS_NO_MEMORY;\n\n            status = NtEnumerateKey(\n                KeyHandle,\n                index,\n                InformationClass,\n                buffer,\n                bufferSize,\n                &bufferSize\n                );\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        if (!Callback(KeyHandle, buffer, Context))\n            break;\n\n        index++;\n    }\n\n    PhFreeStack(buffer);\n\n    return status;\n}\n\n/**\n * Enumerates the values of a registry key and invokes a callback for each enumerated value entry.\n *\n * \\param KeyHandle Handle to an open registry key to enumerate values from.\n * \\param InformationClass KEY_VALUE_INFORMATION_CLASS value specifying the format of the returned records.\n * \\param Callback A function pointer invoked for each successfully retrieved value entry.\n * \\param Context Optional context pointer forwarded to the callback.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumerateValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_VALUE_INFORMATION_CLASS InformationClass,\n    _In_ PPH_ENUM_KEY_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG index = 0;\n\n    bufferSize = 0x100;\n    buffer = PhAllocateStack(bufferSize);\n    if (!buffer) return STATUS_NO_MEMORY;\n\n    while (TRUE)\n    {\n        status = NtEnumerateValueKey(\n            KeyHandle,\n            index,\n            InformationClass,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (status == STATUS_NO_MORE_ENTRIES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFreeStack(buffer);\n            buffer = PhAllocateStack(bufferSize);\n            if (!buffer) return STATUS_NO_MEMORY;\n\n            status = NtEnumerateValueKey(\n                KeyHandle,\n                index,\n                InformationClass,\n                buffer,\n                bufferSize,\n                &bufferSize\n                );\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        if (!Callback(KeyHandle, buffer, Context))\n            break;\n\n        index++;\n    }\n\n    PhFreeStack(buffer);\n\n    return status;\n}\n\n/**\n * Enumerates the values of a registry key and returns a buffer for each enumerated value entry.\n *\n * \\param[in] KeyHandle Handle to an open registry key to enumerate values from.\n * \\param[in] Index Zero-based index of the value entry to retrieve.\n * \\param[in] InformationClass KEY_VALUE_INFORMATION_CLASS value specifying the format of the returned record.\n * \\param[out] Buffer Receives a pointer to a buffer containing the value entry information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEnumerateValueKeyEx(\n    _In_ HANDLE KeyHandle,\n    _In_ ULONG Index,\n    _In_ KEY_VALUE_INFORMATION_CLASS InformationClass,\n    _Out_ PVOID* Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG returnLength;\n\n    bufferSize = 256;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtEnumerateValueKey(\n        KeyHandle,\n        Index,\n        InformationClass,\n        buffer,\n        bufferSize,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhFree(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocate(bufferSize);\n\n        status = NtEnumerateValueKey(\n            KeyHandle,\n            Index,\n            InformationClass,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n        *Buffer = NULL;\n    }\n\n    return status;\n}\n\n"
  },
  {
    "path": "phlib/nativemodule.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <secwmi.h>\n#include <apiimport.h>\n\ntypedef _Function_class_(PH_ENUM_MODULES_CALLBACK)\nBOOLEAN NTAPI PH_ENUM_MODULES_CALLBACK(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID Entry,\n    _In_ PVOID AddressOfEntry,\n    _In_ ULONG SizeOfEntry,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    );\ntypedef PH_ENUM_MODULES_CALLBACK* PPH_ENUM_MODULES_CALLBACK;\n\n/**\n * Opens a named section object and a handle to the section object.\n *\n * \\param[out] SectionHandle Receives the opened section handle on success; NULL on failure.\n * \\param[in] DesiredAccess Access mask specifying desired rights.\n * \\param[in] RootDirectory Optional root directory handle for relative section name resolution; NULL for absolute names.\n * \\param[in] SectionName Pointer to the section name. If the name is too long, STATUS_NAME_TOO_LONG is returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PCPH_STRINGREF SectionName\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE sectionHandle;\n\n    if (!PhStringRefToUnicodeString(SectionName, &objectName))\n        return STATUS_NAME_TOO_LONG;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    status = NtOpenSection(\n        &sectionHandle,\n        DesiredAccess,\n        &objectAttributes\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *SectionHandle = sectionHandle;\n    }\n    else\n    {\n        *SectionHandle = NULL;\n    }\n\n    return status;\n}\n\n/**\n * Creates a section object.\n *\n * \\param[out] SectionHandle Pointer to a variable that receives a handle to the section object.\n * \\param[in] DesiredAccess The access mask that specifies the requested access to the section object.\n * \\param[in] MaximumSize The maximum size, in bytes, of the section. The actual size when backed by the paging file, or the maximum the file can be extended or mapped when backed by an ordinary file.\n * \\param[in] SectionPageProtection Specifies the protection to place on each page in the section.\n * \\param[in] AllocationAttributes A bitmask of SEC_XXX flags that determines the allocation attributes of the section.\n * \\param[in] FileHandle Optionally specifies a handle for an open file object. If the value of FileHandle is NULL, the section is backed by the paging file. Otherwise, the section is backed by the specified file.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG SectionPageProtection,\n    _In_ ULONG AllocationAttributes,\n    _In_opt_ HANDLE FileHandle\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE sectionHandle;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        NULL,\n        OBJ_EXCLUSIVE,\n        NULL,\n        NULL\n        );\n\n    //if (WindowsVersion >= WINDOWS_10_RS5)\n    //{\n    //    MEM_ADDRESS_REQUIREMENTS addressRequirement;\n    //    MEM_EXTENDED_PARAMETER extendedParameters[3];\n    //\n    //    addressRequirement.LowestStartingAddress = NULL;\n    //    addressRequirement.HighestEndingAddress = UlongToPtr(MAXLONG); // 0x7fffffff // below 4GB\n    //    addressRequirement.Alignment = PAGE_SIZE;\n    //\n    //    extendedParameters[0].Type = MemExtendedParameterAddressRequirements;\n    //    extendedParameters[0].Pointer = &addressRequirement;\n    //    extendedParameters[1].Type = MemExtendedParameterAttributeFlags;\n    //    extendedParameters[1].ULong64 = MEM_EXTENDED_PARAMETER_EC_CODE;\n    //    extendedParameters[2].Type = MemExtendedParameterImageMachine;\n    //    extendedParameters[2].ULong64 = IMAGE_FILE_MACHINE_ARM64EC;\n    //\n    //    status = NtCreateSectionEx(\n    //        &sectionHandle,\n    //        DesiredAccess,\n    //        &objectAttributes,\n    //        MaximumSize,\n    //        SectionPageProtection,\n    //        AllocationAttributes,\n    //        FileHandle,\n    //        extendedParameters,\n    //        RTL_NUMBER_OF(extendedParameters)\n    //        );\n    //}\n\n    status = NtCreateSection(\n        &sectionHandle,\n        DesiredAccess,\n        &objectAttributes,\n        MaximumSize,\n        SectionPageProtection,\n        AllocationAttributes,\n        FileHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *SectionHandle = sectionHandle;\n    }\n    else\n    {\n        *SectionHandle = NULL;\n    }\n\n    return status;\n}\n\n/**\n * Maps a view of a section into the address space of a process.\n *\n * \\param[in] SectionHandle Handle to the section object.\n * \\param[in] ProcessHandle Handle to the process to map into.\n * \\param[in,out] BaseAddress On input, preferred base address; on output, actual base address.\n * \\param[in] CommitSize Size of the initially committed pages in the view.\n * \\param[in] SectionOffset Optional offset in the section to begin mapping.\n * \\param[in,out] ViewSize On input, requested view size; on output, actual mapped size.\n * \\param[in] InheritDisposition Specifies whether the view is shared or unshared.\n * \\param[in] AllocationType Type of allocation (usually 0).\n * \\param[in] PageProtection Protection for the mapped pages.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhMapViewOfSection(\n    _In_ HANDLE SectionHandle,\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress,\n    _In_ SIZE_T CommitSize,\n    _In_opt_ PLARGE_INTEGER SectionOffset,\n    _Inout_ PSIZE_T ViewSize,\n    _In_ SECTION_INHERIT InheritDisposition,\n    _In_ ULONG AllocationType,\n    _In_ ULONG PageProtection\n    )\n{\n    NTSTATUS status;\n    PVOID baseAddress = *BaseAddress;\n    SIZE_T viewSize = *ViewSize;\n\n    //if (WindowsVersion >= WINDOWS_10_RS5)\n    //{\n    //    MEM_ADDRESS_REQUIREMENTS addressRequirement;\n    //    MEM_EXTENDED_PARAMETER extendedParameters[3];\n    //\n    //    addressRequirement.LowestStartingAddress = NULL;\n    //    addressRequirement.HighestEndingAddress = UlongToPtr(MAXLONG); // 0x7fffffff // below 4GB\n    //    addressRequirement.Alignment = PAGE_SIZE;\n    //\n    //    extendedParameters[0].Type = MemExtendedParameterAddressRequirements;\n    //    extendedParameters[0].Pointer = &addressRequirement;\n    //    extendedParameters[1].Type = MemExtendedParameterAttributeFlags;\n    //    extendedParameters[1].ULong64 = MEM_EXTENDED_PARAMETER_EC_CODE;\n    //    extendedParameters[2].Type = MemExtendedParameterImageMachine;\n    //    extendedParameters[2].ULong64 = IMAGE_FILE_MACHINE_ARM64EC;\n    //\n    //    status = NtMapViewOfSectionEx(\n    //        SectionHandle,\n    //        ProcessHandle,\n    //        &baseAddress,\n    //        SectionOffset,\n    //        &viewSize,\n    //        AllocationType,\n    //        PageProtection,\n    //        extendedParameters,\n    //        RTL_NUMBER_OF(extendedParameters)\n    //        );\n    //}\n\n    status = NtMapViewOfSection(\n        SectionHandle,\n        ProcessHandle,\n        &baseAddress,\n        0,\n        CommitSize,\n        SectionOffset,\n        &viewSize,\n        InheritDisposition,\n        AllocationType,\n        PageProtection\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *BaseAddress = baseAddress;\n        *ViewSize = viewSize;\n    }\n    else\n    {\n        *BaseAddress = NULL;\n        *ViewSize = 0;\n    }\n\n    return status;\n}\n\n/**\n * Unmaps a view of a section from the address space of a process.\n *\n * \\param ProcessHandle Handle to the process from which the section view will be unmapped.\n * \\param BaseAddress Optional base address of the mapped view to unmap. If NULL, the system determines the base address.\n * \\return NTSTATUS code indicating success or failure of the operation.\n *\n * This function calls NtUnmapViewOfSection to remove a mapped section from the specified process's address space.\n */\nNTSTATUS PhUnmapViewOfSection(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress\n    )\n{\n    NTSTATUS status;\n\n    status = NtUnmapViewOfSection(\n        ProcessHandle,\n        BaseAddress\n        );\n\n    return status;\n}\n\n/**\n * Enumerates the modules loaded by the kernel.\n *\n * \\param Modules A variable which receives a pointer to a structure containing information about\n * the kernel modules. You must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhEnumKernelModules(\n    _Out_ PRTL_PROCESS_MODULES *Modules\n    )\n{\n    static ULONG initialBufferSize = 0x1000;\n    NTSTATUS status;\n    PRTL_PROCESS_MODULES buffer;\n    ULONG bufferSize;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocateZero(bufferSize);\n\n    status = NtQuerySystemInformation(\n        SystemModuleInformation,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        buffer = PhAllocateZero(bufferSize);\n\n        status = NtQuerySystemInformation(\n            SystemModuleInformation,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    // Note: Windows 11 24H2 introduced breaking changes where, without SeDebugPrivilege, every module's reported base address is zero.\n    // System Informer previously keyed modules by base address in a hash table; this causes enumeration collisions and prevents modules\n    // from being displayed correctly. It also breaks displaying symbol information and interoperability with APIs that require distinct\n    // base addresses for symbol resolution (for example, dbghelp). System Informer only presents module metadata and does not require the\n    // base addresses to be valid. To preserve unique identifiers and restore correct enumeration and symbol-related behavior, generate a\n    // synthetic base address for each module above MaximumUserModeAddress. (dmex)\n\n    if (WindowsVersion >= WINDOWS_11_24H2 && !PhGetOwnTokenAttributes().Elevated)\n    {\n        PBYTE pseudoBase = IntToPtr(INT32_MIN);\n        PRTL_PROCESS_MODULE_INFORMATION module;\n\n        for (ULONG i = 0; i < buffer->NumberOfModules; i++)\n        {\n            module = &buffer->Modules[i];\n\n            if (module->ImageBase == 0)\n                module->ImageBase = pseudoBase;\n            pseudoBase += module->ImageSize;\n        }\n    }\n\n    if (bufferSize <= 0x100000) initialBufferSize = bufferSize;\n    *Modules = buffer;\n\n    return status;\n}\n\n/**\n * Enumerates the modules loaded by the kernel.\n *\n * \\param Modules A variable which receives a pointer to a structure containing information about\n * the kernel modules. You must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhEnumKernelModulesEx(\n    _Out_ PRTL_PROCESS_MODULE_INFORMATION_EX *Modules\n    )\n{\n    static ULONG initialBufferSize = 0x1000;\n    NTSTATUS status;\n    PRTL_PROCESS_MODULE_INFORMATION_EX buffer;\n    ULONG bufferSize;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocateZero(bufferSize);\n\n    status = NtQuerySystemInformation(\n        SystemModuleInformationEx,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        buffer = PhAllocateZero(bufferSize);\n\n        status = NtQuerySystemInformation(\n            SystemModuleInformationEx,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    // Note: Windows 11 24H2 introduced breaking changes where, without SeDebugPrivilege, every module's reported base address is zero.\n    // System Informer previously keyed modules by base address in a hash table; this causes enumeration collisions and prevents modules\n    // from being displayed correctly. It also breaks displaying symbol information and interoperability with APIs that require distinct\n    // base addresses for symbol resolution (for example, dbghelp). System Informer only presents module metadata and does not require the\n    // base addresses to be valid. To preserve unique identifiers and restore correct enumeration and symbol-related behavior, generate a\n    // synthetic base address for each module above MaximumUserModeAddress. (dmex)\n\n    if (WindowsVersion >= WINDOWS_11_24H2 && !PhGetOwnTokenAttributes().Elevated)\n    {\n        PBYTE pseudoBase = IntToPtr(INT32_MIN);\n        PRTL_PROCESS_MODULE_INFORMATION_EX module;\n\n        for (module = buffer; module->NextOffset; module = RTL_PTR_ADD(module, module->NextOffset))\n        {\n            if (module->ImageBase == 0)\n                module->ImageBase = pseudoBase;\n            pseudoBase += module->ImageSize;\n        }\n    }\n\n    if (bufferSize <= 0x100000) initialBufferSize = bufferSize;\n    *Modules = buffer;\n\n    return status;\n}\n\n/**\n * Gets the file name of the kernel image.\n *\n * \\return A pointer to a string containing the kernel image file name. You must free the string\n * using PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhGetKernelFileName(\n    VOID\n    )\n{\n    NTSTATUS status;\n    UCHAR buffer[FIELD_OFFSET(RTL_PROCESS_MODULES, Modules) + sizeof(RTL_PROCESS_MODULE_INFORMATION)] = { 0 };\n    PRTL_PROCESS_MODULES modules;\n    ULONG modulesLength;\n\n    modules = (PRTL_PROCESS_MODULES)buffer;\n    modulesLength = sizeof(buffer);\n\n    status = NtQuerySystemInformation(\n        SystemModuleInformation,\n        modules,\n        modulesLength,\n        &modulesLength\n        );\n\n    if (status != STATUS_SUCCESS && status != STATUS_INFO_LENGTH_MISMATCH)\n        return NULL;\n    if (status == STATUS_SUCCESS || modules->NumberOfModules < 1)\n        return NULL;\n\n    return PhZeroExtendToUtf16((PCSTR)modules->Modules[0].FullPathName);\n}\n\n/**\n * Gets the file name, base address and size of the kernel image.\n *\n * \\return A pointer to a string containing the kernel image file name. You must free the string\n * using PhDereferenceObject() when you no longer need it.\n */\nNTSTATUS PhGetKernelFileNameEx(\n    _Out_opt_ PPH_STRING* FileName,\n    _Out_ PVOID* ImageBase,\n    _Out_ ULONG* ImageSize\n    )\n{\n    NTSTATUS status;\n    UCHAR buffer[FIELD_OFFSET(RTL_PROCESS_MODULES, Modules) + sizeof(RTL_PROCESS_MODULE_INFORMATION)] = { 0 };\n    PRTL_PROCESS_MODULES modules;\n    ULONG modulesLength;\n\n    modules = (PRTL_PROCESS_MODULES)buffer;\n    modulesLength = sizeof(buffer);\n\n    status = NtQuerySystemInformation(\n        SystemModuleInformation,\n        modules,\n        modulesLength,\n        &modulesLength\n        );\n\n    if (status != STATUS_SUCCESS && status != STATUS_INFO_LENGTH_MISMATCH)\n        return STATUS_UNSUCCESSFUL;\n    if (status == STATUS_SUCCESS || modules->NumberOfModules < 1)\n        return STATUS_UNSUCCESSFUL;\n\n    if (FileName)\n    {\n        *FileName = PhZeroExtendToUtf16((PCSTR)modules->Modules[0].FullPathName);\n    }\n\n    if (WindowsVersion >= WINDOWS_11_24H2 && !PhGetOwnTokenAttributes().Elevated)\n    {\n        // Note: Windows 11 24H2 introduced breaking changes where, without SeDebugPrivilege, every module's reported base address is zero.\n        // System Informer previously keyed modules by base address in a hash table; this causes enumeration collisions and prevents modules\n        // from being displayed correctly. It also breaks displaying symbol information and interoperability with APIs that require distinct\n        // base addresses for symbol resolution (for example, dbghelp). System Informer only presents module metadata and does not require the\n        // base addresses to be valid. To preserve unique identifiers and restore correct enumeration and symbol-related behavior, generate a\n        // synthetic base address for each module above MaximumUserModeAddress. (dmex)\n\n        if (modules->Modules[0].ImageBase == 0)\n            modules->Modules[0].ImageBase = IntToPtr(INT32_MIN);\n    }\n\n    *ImageBase = modules->Modules[0].ImageBase;\n    *ImageSize = modules->Modules[0].ImageSize;\n\n    return STATUS_SUCCESS;\n}\n\nPPH_STRING PhGetSecureKernelFileName(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF system32String = PH_STRINGREF_INIT(L\"\\\\System32\\\\\");\n    static CONST PH_STRINGREF secureKernelPathPart = PH_STRINGREF_INIT(L\"\\\\securekernel.exe\");\n    static CONST PH_STRINGREF secureKernella57PathPart = PH_STRINGREF_INIT(L\"\\\\securekernella57.exe\");\n    PPH_STRING fileName = NULL;\n    PPH_STRING kernelFileName;\n    BOOLEAN isLa57 = FALSE;\n\n    if (kernelFileName = PhGetKernelFileName())\n    {\n        PH_STRINGREF baseName;\n\n        if (PhEndsWithStringRef2(&kernelFileName->sr, L\"la57.exe\", TRUE))\n        {\n            isLa57 = TRUE;\n        }\n\n        if (PhGetBasePath(&kernelFileName->sr, &baseName, NULL))\n        {\n            fileName = PhConcatStringRef2(&baseName, isLa57 ? &PhSecureKernelFileAliasList[1] : &secureKernelPathPart);\n        }\n\n        PhDereferenceObject(kernelFileName);\n    }\n\n    if (PhIsNullOrEmptyString(fileName))\n    {\n        PH_STRINGREF systemRootString;\n\n        PhGetNtSystemRoot(&systemRootString);\n\n        fileName = PhConcatStringRef3(\n            &systemRootString,\n            &system32String,\n            isLa57 ? &secureKernella57PathPart : &secureKernelPathPart\n            );\n    }\n\n    return fileName;\n}\n\nNTSTATUS PhpEnumProcessModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    NTSTATUS status;\n    PPEB peb;\n    PVOID ldr;\n    PEB_LDR_DATA pebLdrData;\n    PLIST_ENTRY startLink;\n    PLIST_ENTRY currentLink;\n    ULONG entrySize;\n    LDR_DATA_TABLE_ENTRY currentEntry;\n    ULONG i;\n\n    // Get the PEB address.\n    status = PhGetProcessPeb(ProcessHandle, &peb);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Read the address of the loader data.\n    status = PhReadVirtualMemory(\n        ProcessHandle,\n        PTR_ADD_OFFSET(peb, FIELD_OFFSET(PEB, Ldr)),\n        &ldr,\n        sizeof(PVOID),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!ldr)\n        return STATUS_UNSUCCESSFUL;\n\n    // Read the loader data.\n    status = PhReadVirtualMemory(\n        ProcessHandle,\n        ldr,\n        &pebLdrData,\n        sizeof(PEB_LDR_DATA),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Check the loader was initialized (dmex)\n    if (!pebLdrData.Initialized)\n        return STATUS_UNSUCCESSFUL;\n\n    if (WindowsVersion >= WINDOWS_11)\n        entrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN11;\n    else if (WindowsVersion >= WINDOWS_8)\n        entrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8;\n    else\n        entrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7;\n\n    // Traverse the linked list (in load order).\n\n    i = 0;\n    startLink = PTR_ADD_OFFSET(ldr, UFIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModuleList));\n    currentLink = pebLdrData.InLoadOrderModuleList.Flink;\n\n    while (\n        currentLink != startLink &&\n        i <= PH_ENUM_PROCESS_MODULES_LIMIT\n        )\n    {\n        PVOID addressOfEntry;\n\n        addressOfEntry = CONTAINING_RECORD(currentLink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            addressOfEntry,\n            &currentEntry,\n            entrySize,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        // Make sure the entry is valid.\n        if (currentEntry.DllBase)\n        {\n            // Execute the callback.\n            if (!Callback(\n                ProcessHandle,\n                &currentEntry,\n                addressOfEntry,\n                entrySize,\n                Context1,\n                Context2\n                ))\n                break;\n        }\n\n        currentLink = currentEntry.InLoadOrderLinks.Flink;\n        i++;\n    }\n\n    return status;\n}\n\n_Function_class_(PH_ENUM_MODULES_CALLBACK)\nstatic BOOLEAN NTAPI PhpEnumProcessModulesCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _In_ PVOID AddressOfEntry,\n    _In_ ULONG SizeOfEntry,\n    _In_ PVOID Context1,\n    _In_ PVOID Context2\n    )\n{\n    PPH_ENUM_PROCESS_MODULES_PARAMETERS parameters = Context1;\n    NTSTATUS status;\n    BOOLEAN result;\n    PPH_STRING mappedFileName = NULL;\n    PWSTR fullDllNameOriginal;\n    PWSTR fullDllNameBuffer = NULL;\n    PWSTR baseDllNameOriginal;\n    PWSTR baseDllNameBuffer = NULL;\n\n    if (parameters->Flags & PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME)\n    {\n        PhGetProcessMappedFileName(ProcessHandle, Entry->DllBase, &mappedFileName);\n    }\n\n    if (mappedFileName)\n    {\n        ULONG_PTR indexOfLastBackslash;\n\n        PhStringRefToUnicodeString(&mappedFileName->sr, &Entry->FullDllName);\n        indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, OBJ_NAME_PATH_SEPARATOR);\n\n        if (indexOfLastBackslash != SIZE_MAX)\n        {\n            Entry->BaseDllName.Buffer = Entry->FullDllName.Buffer + indexOfLastBackslash + 1;\n            Entry->BaseDllName.Length = Entry->FullDllName.Length - (USHORT)indexOfLastBackslash * sizeof(WCHAR) - sizeof(UNICODE_NULL);\n            Entry->BaseDllName.MaximumLength = Entry->BaseDllName.Length + sizeof(UNICODE_NULL);\n        }\n        else\n        {\n            Entry->BaseDllName = Entry->FullDllName;\n        }\n    }\n    else\n    {\n        // Read the full DLL name string and add a null terminator.\n\n        fullDllNameOriginal = Entry->FullDllName.Buffer;\n        fullDllNameBuffer = PhAllocate(Entry->FullDllName.Length + sizeof(UNICODE_NULL));\n        Entry->FullDllName.Buffer = fullDllNameBuffer;\n\n        if (NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            fullDllNameOriginal,\n            fullDllNameBuffer,\n            Entry->FullDllName.Length,\n            NULL\n            )))\n        {\n            fullDllNameBuffer[Entry->FullDllName.Length / sizeof(WCHAR)] = UNICODE_NULL;\n        }\n        else\n        {\n            fullDllNameBuffer[0] = UNICODE_NULL;\n            Entry->FullDllName.Length = 0;\n        }\n\n        baseDllNameOriginal = Entry->BaseDllName.Buffer;\n\n        // Try to use the buffer we just read in.\n        if (\n            NT_SUCCESS(status) &&\n            (ULONG_PTR)baseDllNameOriginal >= (ULONG_PTR)fullDllNameOriginal &&\n            (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length >= (ULONG_PTR)baseDllNameOriginal &&\n            (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length <= (ULONG_PTR)fullDllNameOriginal + Entry->FullDllName.Length\n            )\n        {\n            baseDllNameBuffer = NULL;\n\n            Entry->BaseDllName.Buffer = (PWCHAR)((ULONG_PTR)Entry->FullDllName.Buffer + ((ULONG_PTR)baseDllNameOriginal - (ULONG_PTR)fullDllNameOriginal));\n        }\n        else\n        {\n            // Read the base DLL name string and add a null terminator.\n\n            baseDllNameBuffer = PhAllocate(Entry->BaseDllName.Length + sizeof(UNICODE_NULL));\n            Entry->BaseDllName.Buffer = baseDllNameBuffer;\n\n            if (NT_SUCCESS(PhReadVirtualMemory(\n                ProcessHandle,\n                baseDllNameOriginal,\n                baseDllNameBuffer,\n                Entry->BaseDllName.Length,\n                NULL\n                )))\n            {\n                baseDllNameBuffer[Entry->BaseDllName.Length / sizeof(WCHAR)] = UNICODE_NULL;\n            }\n            else\n            {\n                baseDllNameBuffer[0] = UNICODE_NULL;\n                Entry->BaseDllName.Length = 0;\n            }\n        }\n    }\n\n    if (WindowsVersion >= WINDOWS_8 && Entry->DdagNode && RTL_CONTAINS_FIELD(Entry, SizeOfEntry, DdagNode))\n    {\n        LDR_DDAG_NODE ldrDagNode;\n\n        memset(&ldrDagNode, 0, sizeof(LDR_DDAG_NODE));\n\n        if (NT_SUCCESS(PhReadVirtualMemory(\n            ProcessHandle,\n            Entry->DdagNode,\n            &ldrDagNode,\n            sizeof(LDR_DDAG_NODE),\n            NULL\n            )))\n        {\n            // Fixup the module load count. (dmex)\n            Entry->ObsoleteLoadCount = (USHORT)ldrDagNode.LoadCount;\n        }\n    }\n\n    // Execute the callback.\n    result = parameters->Callback(Entry, parameters->Context);\n\n    if (mappedFileName)\n    {\n        PhDereferenceObject(mappedFileName);\n    }\n    else\n    {\n        if (fullDllNameBuffer)\n            PhFree(fullDllNameBuffer);\n        if (baseDllNameBuffer)\n            PhFree(baseDllNameBuffer);\n    }\n\n    return result;\n}\n\n/**\n * Enumerates the modules loaded by a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param Callback A callback function which is executed for each process module.\n * \\param Context A user-defined value to pass to the callback function.\n */\nNTSTATUS PhEnumProcessModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_ENUM_PROCESS_MODULES_PARAMETERS parameters;\n\n    parameters.Callback = Callback;\n    parameters.Context = Context;\n    parameters.Flags = 0;\n\n    return PhEnumProcessModulesEx(ProcessHandle, &parameters);\n}\n\n/**\n * Enumerates the modules loaded by a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. If\n * \\c PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME is specified in \\a Parameters, the handle should\n * have PROCESS_QUERY_INFORMATION access.\n * \\param Parameters The enumeration parameters.\n */\nNTSTATUS PhEnumProcessModulesEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters\n    )\n{\n    return PhpEnumProcessModules(\n        ProcessHandle,\n        PhpEnumProcessModulesCallback,\n        Parameters,\n        NULL\n        );\n}\n\ntypedef struct _SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT\n{\n    NTSTATUS Status;\n    PVOID BaseAddress;\n    ULONG LoadCount;\n} SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT, *PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT;\n\n_Function_class_(PH_ENUM_MODULES_CALLBACK)\nBOOLEAN NTAPI PhpSetProcessModuleLoadCountCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _In_ PVOID AddressOfEntry,\n    _In_ ULONG SizeOfEntry,\n    _In_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1;\n\n    if (Entry->DllBase == context->BaseAddress)\n    {\n        context->Status = PhWriteVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(AddressOfEntry, FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ObsoleteLoadCount)),\n            &context->LoadCount,\n            sizeof(USHORT),\n            NULL\n            );\n\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Sets the load count of a process module.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ and PROCESS_VM_WRITE access.\n * \\param BaseAddress The base address of a module.\n * \\param LoadCount The new load count of the module.\n *\n * \\retval STATUS_DLL_NOT_FOUND The module was not found.\n */\nNTSTATUS PhSetProcessModuleLoadCount(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG LoadCount\n    )\n{\n    NTSTATUS status;\n    SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context;\n\n    context.Status = STATUS_DLL_NOT_FOUND;\n    context.BaseAddress = BaseAddress;\n    context.LoadCount = LoadCount;\n\n    status = PhpEnumProcessModules(\n        ProcessHandle,\n        PhpSetProcessModuleLoadCountCallback,\n        &context,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    return context.Status;\n}\n\nNTSTATUS PhpEnumProcessModules32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    NTSTATUS status;\n    PPEB32 peb;\n    ULONG ldr; // PEB_LDR_DATA32 *32\n    PEB_LDR_DATA32 pebLdrData;\n    ULONG startLink; // LIST_ENTRY32 *32\n    ULONG currentLink; // LIST_ENTRY32 *32\n    ULONG entrySize;\n    LDR_DATA_TABLE_ENTRY32 currentEntry;\n    ULONG i;\n\n    // Get the 32-bit PEB address.\n    status = PhGetProcessPeb32(ProcessHandle, &peb);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Read the address of the loader data.\n    status = PhReadVirtualMemory(\n        ProcessHandle,\n        PTR_ADD_OFFSET(peb, FIELD_OFFSET(PEB32, Ldr)),\n        &ldr,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!ldr)\n        return STATUS_UNSUCCESSFUL;\n\n    // Read the loader data.\n    status = PhReadVirtualMemory(\n        ProcessHandle,\n        UlongToPtr(ldr),\n        &pebLdrData,\n        sizeof(PEB_LDR_DATA32),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Check the loader was initialized (dmex)\n    if (!pebLdrData.Initialized)\n        return STATUS_UNSUCCESSFUL;\n\n    if (WindowsVersion >= WINDOWS_11)\n        entrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN11_32;\n    else if (WindowsVersion >= WINDOWS_8)\n        entrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8_32;\n    else\n        entrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7_32;\n\n    // Traverse the linked list (in load order).\n\n    i = 0;\n    startLink = ldr + UFIELD_OFFSET(PEB_LDR_DATA32, InLoadOrderModuleList);\n    currentLink = pebLdrData.InLoadOrderModuleList.Flink;\n\n    while (\n        currentLink != startLink &&\n        i <= PH_ENUM_PROCESS_MODULES_LIMIT\n        )\n    {\n        PVOID addressOfEntry;\n\n        addressOfEntry = CONTAINING_RECORD(UlongToPtr(currentLink), LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks);\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            addressOfEntry,\n            &currentEntry,\n            entrySize,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        // Make sure the entry is valid.\n        if (currentEntry.DllBase)\n        {\n            // Execute the callback.\n            if (!Callback(\n                ProcessHandle,\n                &currentEntry,\n                addressOfEntry,\n                entrySize,\n                Context1,\n                Context2\n                ))\n                break;\n        }\n\n        currentLink = currentEntry.InLoadOrderLinks.Flink;\n        i++;\n    }\n\n    return status;\n}\n\n_Function_class_(PH_ENUM_MODULES_CALLBACK)\nBOOLEAN NTAPI PhpEnumProcessModules32Callback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY32 Entry,\n    _In_ PVOID AddressOfEntry,\n    _In_ ULONG SizeOfEntry,\n    _In_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    static CONST PH_STRINGREF system32String = PH_STRINGREF_INIT(L\"\\\\System32\\\\\");\n    PPH_ENUM_PROCESS_MODULES_PARAMETERS parameters = Context1;\n    BOOLEAN cont;\n    LDR_DATA_TABLE_ENTRY nativeEntry;\n    PPH_STRING mappedFileName;\n    PWSTR baseDllNameBuffer = NULL;\n    PWSTR fullDllNameBuffer = NULL;\n    PH_STRINGREF fullDllName;\n    PH_STRINGREF systemRootString;\n\n    // Convert the 32-bit entry to a native-sized entry.\n\n    memset(&nativeEntry, 0, sizeof(LDR_DATA_TABLE_ENTRY));\n    nativeEntry.DllBase = UlongToPtr(Entry->DllBase);\n    nativeEntry.EntryPoint = UlongToPtr(Entry->EntryPoint);\n    nativeEntry.SizeOfImage = Entry->SizeOfImage;\n    UStr32ToUStr(&nativeEntry.FullDllName, &Entry->FullDllName);\n    UStr32ToUStr(&nativeEntry.BaseDllName, &Entry->BaseDllName);\n    nativeEntry.Flags = Entry->Flags;\n    nativeEntry.ObsoleteLoadCount = Entry->ObsoleteLoadCount;\n    nativeEntry.TlsIndex = Entry->TlsIndex;\n    nativeEntry.TimeDateStamp = Entry->TimeDateStamp;\n    nativeEntry.OriginalBase = UlongToPtr(Entry->OriginalBase);\n    nativeEntry.LoadTime = Entry->LoadTime;\n    nativeEntry.BaseNameHashValue = Entry->BaseNameHashValue;\n    nativeEntry.LoadReason = Entry->LoadReason;\n    nativeEntry.ParentDllBase = UlongToPtr(Entry->ParentDllBase);\n\n    mappedFileName = NULL;\n\n    if (parameters->Flags & PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME)\n    {\n        PhGetProcessMappedFileName(ProcessHandle, nativeEntry.DllBase, &mappedFileName);\n    }\n\n    if (mappedFileName)\n    {\n        ULONG_PTR indexOfLastBackslash;\n\n        PhStringRefToUnicodeString(&mappedFileName->sr, &nativeEntry.FullDllName);\n        indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, OBJ_NAME_PATH_SEPARATOR);\n\n        if (indexOfLastBackslash != SIZE_MAX)\n        {\n            nativeEntry.BaseDllName.Buffer = nativeEntry.FullDllName.Buffer + indexOfLastBackslash + 1;\n            nativeEntry.BaseDllName.Length = nativeEntry.FullDllName.Length - (USHORT)indexOfLastBackslash * sizeof(WCHAR) - sizeof(UNICODE_NULL);\n            nativeEntry.BaseDllName.MaximumLength = nativeEntry.BaseDllName.Length + sizeof(UNICODE_NULL);\n        }\n        else\n        {\n            nativeEntry.BaseDllName = nativeEntry.FullDllName;\n        }\n    }\n    else\n    {\n        // Read the base DLL name string and add a null terminator.\n\n        baseDllNameBuffer = PhAllocate(nativeEntry.BaseDllName.Length + sizeof(UNICODE_NULL));\n\n        if (NT_SUCCESS(PhReadVirtualMemory(\n            ProcessHandle,\n            nativeEntry.BaseDllName.Buffer,\n            baseDllNameBuffer,\n            nativeEntry.BaseDllName.Length,\n            NULL\n            )))\n        {\n            baseDllNameBuffer[nativeEntry.BaseDllName.Length / sizeof(WCHAR)] = UNICODE_NULL;\n        }\n        else\n        {\n            baseDllNameBuffer[0] = UNICODE_NULL;\n            nativeEntry.BaseDllName.Length = 0;\n        }\n\n        nativeEntry.BaseDllName.Buffer = baseDllNameBuffer;\n\n        // Read the full DLL name string and add a null terminator.\n\n        fullDllNameBuffer = PhAllocate(nativeEntry.FullDllName.Length + sizeof(UNICODE_NULL));\n\n        if (NT_SUCCESS(PhReadVirtualMemory(\n            ProcessHandle,\n            nativeEntry.FullDllName.Buffer,\n            fullDllNameBuffer,\n            nativeEntry.FullDllName.Length,\n            NULL\n            )))\n        {\n            fullDllNameBuffer[nativeEntry.FullDllName.Length / sizeof(WCHAR)] = UNICODE_NULL;\n\n            if (!(parameters->Flags & PH_ENUM_PROCESS_MODULES_DONT_RESOLVE_WOW64_FS))\n            {\n                // WOW64 file system redirection - convert \"system32\" to \"SysWOW64\" or \"SysArm32\".\n                if (!(nativeEntry.FullDllName.Length & 1)) // validate the string length\n                {\n#ifdef _M_ARM64\n                    USHORT arch;\n                    if (NT_SUCCESS(PhGetProcessArchitecture(ProcessHandle, &arch)))\n                    {\n#endif\n                        fullDllName.Buffer = fullDllNameBuffer;\n                        fullDllName.Length = nativeEntry.FullDllName.Length;\n\n                        PhGetSystemRoot(&systemRootString);\n\n                        if (PhStartsWithStringRef(&fullDllName, &systemRootString, TRUE))\n                        {\n                            PhSkipStringRef(&fullDllName, systemRootString.Length);\n\n                            if (PhStartsWithStringRef(&fullDllName, &system32String, TRUE))\n                            {\n#ifdef _M_ARM64\n                                if (arch == IMAGE_FILE_MACHINE_ARMNT)\n                                {\n                                    fullDllName.Buffer[1] = L'S';\n                                    fullDllName.Buffer[2] = L'y';\n                                    fullDllName.Buffer[3] = L's';\n                                    fullDllName.Buffer[4] = L'A';\n                                    fullDllName.Buffer[5] = L'r';\n                                    fullDllName.Buffer[6] = L'm';\n                                    fullDllName.Buffer[7] = L'3';\n                                    fullDllName.Buffer[8] = L'2';\n                                }\n                                else\n#endif\n                                {\n                                    fullDllName.Buffer[1] = L'S';\n                                    fullDllName.Buffer[4] = L'W';\n                                    fullDllName.Buffer[5] = L'O';\n                                    fullDllName.Buffer[6] = L'W';\n                                    fullDllName.Buffer[7] = L'6';\n                                    fullDllName.Buffer[8] = L'4';\n                                }\n                            }\n                        }\n#ifdef _M_ARM64\n                    }\n                    else\n                    {\n                        fullDllNameBuffer[0] = UNICODE_NULL;\n                        nativeEntry.FullDllName.Length = 0;\n                    }\n#endif\n                }\n            }\n        }\n        else\n        {\n            fullDllNameBuffer[0] = UNICODE_NULL;\n            nativeEntry.FullDllName.Length = 0;\n        }\n\n        nativeEntry.FullDllName.Buffer = fullDllNameBuffer;\n    }\n\n    if (WindowsVersion >= WINDOWS_8 && Entry->DdagNode && RTL_CONTAINS_FIELD(Entry, SizeOfEntry, DdagNode))\n    {\n        LDR_DDAG_NODE32 ldrDagNode32 = { 0 };\n\n        if (NT_SUCCESS(PhReadVirtualMemory(\n            ProcessHandle,\n            UlongToPtr(Entry->DdagNode),\n            &ldrDagNode32,\n            sizeof(LDR_DDAG_NODE32),\n            NULL\n            )))\n        {\n            // Fixup the module load count. (dmex)\n            nativeEntry.ObsoleteLoadCount = (USHORT)ldrDagNode32.LoadCount;\n        }\n    }\n\n    // Execute the callback.\n    cont = parameters->Callback(&nativeEntry, parameters->Context);\n\n    if (mappedFileName)\n    {\n        PhDereferenceObject(mappedFileName);\n    }\n    else\n    {\n        if (baseDllNameBuffer)\n            PhFree(baseDllNameBuffer);\n        if (fullDllNameBuffer)\n            PhFree(fullDllNameBuffer);\n    }\n\n    return cont;\n}\n\n/**\n * Enumerates the 32-bit modules loaded by a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param Callback A callback function which is executed for each process module.\n * \\param Context A user-defined value to pass to the callback function.\n *\n * \\retval STATUS_NOT_SUPPORTED The process is not running under WOW64.\n *\n * \\remarks Do not use this function under a 32-bit environment.\n */\nNTSTATUS PhEnumProcessModules32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_ENUM_PROCESS_MODULES_PARAMETERS parameters;\n\n    parameters.Callback = Callback;\n    parameters.Context = Context;\n    parameters.Flags = 0;\n\n    return PhEnumProcessModules32Ex(ProcessHandle, &parameters);\n}\n\n/**\n * Enumerates the 32-bit modules loaded by a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. If\n * \\c PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME is specified in \\a Parameters, the handle should\n * have PROCESS_QUERY_INFORMATION access.\n * \\param Parameters The enumeration parameters.\n *\n * \\retval STATUS_NOT_SUPPORTED The process is not running under WOW64.\n *\n * \\remarks Do not use this function under a 32-bit environment.\n */\nNTSTATUS PhEnumProcessModules32Ex(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters\n    )\n{\n    return PhpEnumProcessModules32(\n        ProcessHandle,\n        PhpEnumProcessModules32Callback,\n        Parameters,\n        NULL\n        );\n}\n\n_Function_class_(PH_ENUM_MODULES_CALLBACK)\nstatic BOOLEAN NTAPI PhSetProcessModuleLoadCount32Callback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY32 Entry,\n    _In_ PVOID AddressOfEntry,\n    _In_ ULONG SizeOfEntry,\n    _In_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1;\n\n    if (UlongToPtr(Entry->DllBase) == context->BaseAddress)\n    {\n        context->Status = PhWriteVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(AddressOfEntry, FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, ObsoleteLoadCount)),\n            &context->LoadCount,\n            sizeof(USHORT),\n            NULL\n            );\n\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Sets the load count of a 32-bit process module.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ and PROCESS_VM_WRITE access.\n * \\param BaseAddress The base address of a module.\n * \\param LoadCount The new load count of the module.\n *\n * \\retval STATUS_DLL_NOT_FOUND The module was not found.\n * \\retval STATUS_NOT_SUPPORTED The process is not running under WOW64.\n *\n * \\remarks Do not use this function under a 32-bit environment.\n */\nNTSTATUS PhSetProcessModuleLoadCount32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG LoadCount\n    )\n{\n    NTSTATUS status;\n    SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context;\n\n    context.Status = STATUS_DLL_NOT_FOUND;\n    context.BaseAddress = BaseAddress;\n    context.LoadCount = LoadCount;\n\n    status = PhpEnumProcessModules32(\n        ProcessHandle,\n        PhSetProcessModuleLoadCount32Callback,\n        &context,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    return context.Status;\n}\n\ntypedef struct _ENUM_GENERIC_PROCESS_MODULES_CONTEXT\n{\n    PPH_HASHTABLE BaseAddressHashtable;\n    PPH_ENUM_GENERIC_MODULES_CALLBACK Callback;\n    PVOID Context;\n    ULONG Type;\n    ULONG LoadOrderIndex;\n} ENUM_GENERIC_PROCESS_MODULES_CONTEXT, *PENUM_GENERIC_PROCESS_MODULES_CONTEXT;\n\nULONG PhGetRtlModuleType(\n    _In_ PVOID ImageBase\n    )\n{\n    if ((ULONG_PTR)ImageBase > (ULONG_PTR)PhSystemBasicInformation.MaximumUserModeAddress)\n        return PH_MODULE_TYPE_KERNEL_MODULE;\n\n    return PH_MODULE_TYPE_MODULE;\n}\n\n_Function_class_(PH_ENUM_PROCESS_MODULES_CALLBACK)\nstatic BOOLEAN EnumGenericProcessModulesCallback(\n    _In_ PLDR_DATA_TABLE_ENTRY Module,\n    _In_ PENUM_GENERIC_PROCESS_MODULES_CONTEXT Context\n    )\n{\n    PH_MODULE_INFO moduleInfo;\n    BOOLEAN result;\n\n    // Check if we have a duplicate base address.\n    if (PhFindEntryHashtable(Context->BaseAddressHashtable, &Module->DllBase))\n        return TRUE;\n\n    PhAddEntryHashtable(Context->BaseAddressHashtable, &Module->DllBase);\n\n    RtlZeroMemory(&moduleInfo, sizeof(PH_MODULE_INFO));\n    moduleInfo.Type = Context->Type;\n    moduleInfo.BaseAddress = Module->DllBase;\n    moduleInfo.Size = Module->SizeOfImage;\n    moduleInfo.EntryPoint = Module->EntryPoint;\n    moduleInfo.Flags = Module->Flags;\n    moduleInfo.LoadOrderIndex = (USHORT)(Context->LoadOrderIndex++);\n    moduleInfo.LoadCount = Module->ObsoleteLoadCount;\n    moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName);\n    moduleInfo.FileName = PhCreateStringFromUnicodeString(&Module->FullDllName);\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        moduleInfo.ParentBaseAddress = Module->ParentDllBase;\n        moduleInfo.OriginalBaseAddress = Module->OriginalBase;\n        moduleInfo.LoadReason = (USHORT)Module->LoadReason;\n        moduleInfo.LoadTime = Module->LoadTime;\n    }\n    else\n    {\n        moduleInfo.ParentBaseAddress = NULL;\n        moduleInfo.OriginalBaseAddress = NULL;\n        moduleInfo.LoadReason = USHRT_MAX;\n        moduleInfo.LoadTime.QuadPart = 0;\n    }\n\n    result = Context->Callback(&moduleInfo, Context->Context);\n\n    PhDereferenceObject(moduleInfo.Name);\n    PhDereferenceObject(moduleInfo.FileName);\n\n    return result;\n}\n\nVOID PhpRtlModulesToGenericModules(\n    _In_ PRTL_PROCESS_MODULES Modules,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_ PPH_HASHTABLE BaseAddressHashtable,\n    _In_opt_ PVOID Context\n    )\n{\n    PRTL_PROCESS_MODULE_INFORMATION module;\n    PH_MODULE_INFO moduleInfo;\n    BOOLEAN result;\n\n    for (ULONG i = 0; i < Modules->NumberOfModules; i++)\n    {\n        module = &Modules->Modules[i];\n\n        // Check if we have a duplicate base address.\n        if (PhFindEntryHashtable(BaseAddressHashtable, &module->ImageBase))\n            continue;\n\n        PhAddEntryHashtable(BaseAddressHashtable, &module->ImageBase);\n\n        RtlZeroMemory(&moduleInfo, sizeof(PH_MODULE_INFO));\n        moduleInfo.Type = PhGetRtlModuleType(module->ImageBase);\n        moduleInfo.BaseAddress = module->ImageBase;\n        moduleInfo.Size = module->ImageSize;\n        moduleInfo.EntryPoint = NULL;\n        moduleInfo.Flags = module->Flags;\n        moduleInfo.LoadOrderIndex = module->LoadOrderIndex;\n        moduleInfo.LoadCount = module->LoadCount;\n        moduleInfo.LoadReason = USHRT_MAX;\n        moduleInfo.LoadTime.QuadPart = 0;\n        moduleInfo.ParentBaseAddress = NULL;\n        moduleInfo.OriginalBaseAddress = NULL;\n\n        if (module->OffsetToFileName == 0)\n        {\n            static CONST PH_STRINGREF driversString = PH_STRINGREF_INIT(L\"\\\\System32\\\\Drivers\\\\\");\n            PH_STRINGREF systemRoot;\n\n            // We only have the file name, without a path. The driver must be in the default drivers\n            // directory.\n            PhGetNtSystemRoot(&systemRoot);\n            moduleInfo.Name = PhConvertUtf8ToUtf16((PSTR)module->FullPathName);\n            moduleInfo.FileName = PhConcatStringRef3(&systemRoot, &driversString, &moduleInfo.Name->sr);\n        }\n        else\n        {\n            moduleInfo.Name = PhConvertUtf8ToUtf16((PSTR)&module->FullPathName[module->OffsetToFileName]);\n            moduleInfo.FileName = PhConvertUtf8ToUtf16((PSTR)module->FullPathName);\n        }\n\n        result = Callback(&moduleInfo, Context);\n\n        PhDereferenceObject(moduleInfo.Name);\n        PhDereferenceObject(moduleInfo.FileName);\n\n        if (!result)\n            break;\n    }\n}\n\nstatic VOID PhpRtlModulesExToGenericModules(\n    _In_ PRTL_PROCESS_MODULE_INFORMATION_EX Modules,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_ PPH_HASHTABLE BaseAddressHashtable,\n    _In_opt_ PVOID Context\n    )\n{\n    PRTL_PROCESS_MODULE_INFORMATION_EX module;\n    PH_MODULE_INFO moduleInfo;\n    BOOLEAN result;\n\n    for (module = Modules; module->NextOffset; module = RTL_PTR_ADD(module, module->NextOffset))\n    {\n        // Check if we have a duplicate base address.\n        if (PhFindEntryHashtable(BaseAddressHashtable, &module->ImageBase))\n            continue;\n\n        PhAddEntryHashtable(BaseAddressHashtable, &module->ImageBase);\n\n        RtlZeroMemory(&moduleInfo, sizeof(PH_MODULE_INFO));\n        moduleInfo.Type = PhGetRtlModuleType(module->ImageBase);\n        moduleInfo.BaseAddress = module->ImageBase;\n        moduleInfo.Size = module->ImageSize;\n        moduleInfo.EntryPoint = NULL;\n        moduleInfo.Flags = module->Flags;\n        moduleInfo.LoadOrderIndex = module->LoadOrderIndex;\n        moduleInfo.LoadCount = module->LoadCount;\n        moduleInfo.LoadReason = USHRT_MAX;\n        moduleInfo.LoadTime.QuadPart = 0;\n        moduleInfo.ParentBaseAddress = NULL;\n        moduleInfo.OriginalBaseAddress = NULL;\n\n        if (module->OffsetToFileName == 0)\n        {\n            static CONST PH_STRINGREF driversString = PH_STRINGREF_INIT(L\"\\\\System32\\\\Drivers\\\\\");\n            PH_STRINGREF systemRoot;\n\n            // We only have the file name, without a path. The driver must be in the default drivers\n            // directory.\n            PhGetNtSystemRoot(&systemRoot);\n            moduleInfo.Name = PhConvertUtf8ToUtf16((PSTR)module->FullPathName);\n            moduleInfo.FileName = PhConcatStringRef3(&systemRoot, &driversString, &moduleInfo.Name->sr);\n        }\n        else\n        {\n            moduleInfo.Name = PhConvertUtf8ToUtf16((PSTR)&module->FullPathName[module->OffsetToFileName]);\n            moduleInfo.FileName = PhConvertUtf8ToUtf16((PSTR)module->FullPathName);\n        }\n\n        result = Callback(&moduleInfo, Context);\n\n        PhDereferenceObject(moduleInfo.Name);\n        PhDereferenceObject(moduleInfo.FileName);\n\n        if (!result)\n            break;\n    }\n}\n\nstatic BOOLEAN PhpCallbackMappedFileOrImage(\n    _In_ PVOID AllocationBase,\n    _In_ SIZE_T AllocationSize,\n    _In_ ULONG Type,\n    _In_ PPH_STRING FileName,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_MODULE_INFO moduleInfo;\n    BOOLEAN result;\n\n    RtlZeroMemory(&moduleInfo, sizeof(PH_MODULE_INFO));\n    moduleInfo.Type = Type;\n    moduleInfo.BaseAddress = AllocationBase;\n    moduleInfo.Size = (ULONG)AllocationSize;\n    moduleInfo.EntryPoint = NULL;\n    moduleInfo.Flags = 0;\n    moduleInfo.FileName = FileName;\n    moduleInfo.Name = PhGetBaseName(moduleInfo.FileName);\n    moduleInfo.LoadOrderIndex = USHRT_MAX;\n    moduleInfo.LoadCount = USHRT_MAX;\n    moduleInfo.LoadReason = USHRT_MAX;\n    moduleInfo.LoadTime.QuadPart = 0;\n    moduleInfo.ParentBaseAddress = NULL;\n    moduleInfo.OriginalBaseAddress = NULL;\n\n    result = Callback(&moduleInfo, Context);\n\n    PhDereferenceObject(moduleInfo.FileName);\n    PhDereferenceObject(moduleInfo.Name);\n\n    return result;\n}\n\n//typedef struct _PH_ENUM_MAPPED_MODULES_PARAMETERS\n//{\n//    PPH_ENUM_GENERIC_MODULES_CALLBACK Callback;\n//    PVOID Context;\n//    PPH_HASHTABLE BaseAddressHashtable;\n//} PH_ENUM_MAPPED_MODULES_PARAMETERS, *PPH_ENUM_MAPPED_MODULES_PARAMETERS;\n//\n//NTSTATUS NTAPI PhpEnumGenericMappedFilesAndImagesBulk(\n//    _In_ HANDLE ProcessHandle,\n//    _In_ PMEMORY_BASIC_INFORMATION MemoryBasicInfo,\n//    _In_ SIZE_T Count,\n//    _In_ PPH_ENUM_MAPPED_MODULES_PARAMETERS Parameters\n//    )\n//{\n//    ULONG type;\n//    PPH_STRING fileName;\n//\n//    for (SIZE_T i = 0; i < Count; i++)\n//    {\n//        PMEMORY_BASIC_INFORMATION basicInfo = &MemoryBasicInfo[i];\n//\n//        if (basicInfo->Type == MEM_MAPPED || basicInfo->Type == MEM_IMAGE)\n//        {\n//            if (basicInfo->Type == MEM_MAPPED)\n//                type = PH_MODULE_TYPE_MAPPED_FILE;\n//            else\n//                type = PH_MODULE_TYPE_MAPPED_IMAGE;\n//\n//            if (!PhFindEntryHashtable(Parameters->BaseAddressHashtable, &basicInfo->AllocationBase))\n//            {\n//                if (NT_SUCCESS(PhGetProcessMappedFileName(ProcessHandle, basicInfo->AllocationBase, &fileName)))\n//                {\n//                    PhAddEntryHashtable(Parameters->BaseAddressHashtable, &basicInfo->AllocationBase);\n//\n//                    if (!PhpCallbackMappedFileOrImage(\n//                        basicInfo->AllocationBase,\n//                        basicInfo->RegionSize,\n//                        type,\n//                        fileName,\n//                        Parameters->Callback,\n//                        Parameters->Context\n//                        ))\n//                    {\n//                        break;\n//                    }\n//                }\n//            }\n//        }\n//    }\n//\n//    return STATUS_SUCCESS;\n//}\n//\n//VOID PhpEnumGenericBulkMappedFilesAndImages(\n//    _In_ HANDLE ProcessHandle,\n//    _In_ ULONG Flags,\n//    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n//    _In_ PPH_HASHTABLE BaseAddressHashtable,\n//    _In_opt_ PVOID Context\n//    )\n//{\n//    PH_ENUM_MAPPED_MODULES_PARAMETERS enumParameters;\n//\n//    memset(&enumParameters, 0, sizeof(PH_ENUM_MAPPED_MODULES_PARAMETERS));\n//    enumParameters.BaseAddressHashtable = BaseAddressHashtable;\n//    enumParameters.Callback = Callback;\n//    enumParameters.Context = Context;\n//\n//    if (NT_SUCCESS(PhEnumVirtualMemoryBulk(\n//        ProcessHandle,\n//        NULL,\n//        FALSE,\n//        PhpEnumGenericMappedFilesAndImagesBulk,\n//        &enumParameters\n//        )))\n//    {\n//        return;\n//    }\n//}\n\nstatic VOID PhpEnumGenericMappedFilesAndImages(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_ PPH_HASHTABLE BaseAddressHashtable,\n    _In_opt_ PVOID Context\n    )\n{\n    BOOLEAN querySucceeded;\n    PVOID baseAddress;\n    MEMORY_BASIC_INFORMATION basicInfo;\n\n    baseAddress = (PVOID)0;\n\n    if (!NT_SUCCESS(NtQueryVirtualMemory(\n        ProcessHandle,\n        baseAddress,\n        MemoryBasicInformation,\n        &basicInfo,\n        sizeof(MEMORY_BASIC_INFORMATION),\n        NULL\n        )))\n    {\n        return;\n    }\n\n    querySucceeded = TRUE;\n\n    while (querySucceeded)\n    {\n        PVOID allocationBase;\n        SIZE_T allocationSize;\n        ULONG type;\n        PPH_STRING fileName;\n        BOOLEAN result;\n\n        if (basicInfo.Type == MEM_MAPPED || basicInfo.Type == MEM_IMAGE)\n        {\n            if (basicInfo.Type == MEM_MAPPED)\n                type = PH_MODULE_TYPE_MAPPED_FILE;\n            else\n                type = PH_MODULE_TYPE_MAPPED_IMAGE;\n\n            // Find the total allocation size.\n\n            allocationBase = basicInfo.AllocationBase;\n            allocationSize = 0;\n\n            do\n            {\n                baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize);\n                allocationSize += basicInfo.RegionSize;\n\n                if (!NT_SUCCESS(NtQueryVirtualMemory(\n                    ProcessHandle,\n                    baseAddress,\n                    MemoryBasicInformation,\n                    &basicInfo,\n                    sizeof(MEMORY_BASIC_INFORMATION),\n                    NULL\n                    )))\n                {\n                    querySucceeded = FALSE;\n                    break;\n                }\n            } while (basicInfo.AllocationBase == allocationBase);\n\n            if ((type == PH_MODULE_TYPE_MAPPED_FILE && !(Flags & PH_ENUM_GENERIC_MAPPED_FILES)) ||\n                (type == PH_MODULE_TYPE_MAPPED_IMAGE && !(Flags & PH_ENUM_GENERIC_MAPPED_IMAGES)))\n            {\n                // The user doesn't want this type of entry.\n                continue;\n            }\n\n            // Check if we have a duplicate base address.\n            if (PhFindEntryHashtable(BaseAddressHashtable, &allocationBase))\n            {\n                continue;\n            }\n\n            if (!NT_SUCCESS(PhGetProcessMappedFileName(\n                ProcessHandle,\n                allocationBase,\n                &fileName\n                )))\n            {\n                continue;\n            }\n\n            PhAddEntryHashtable(BaseAddressHashtable, &allocationBase);\n\n            result = PhpCallbackMappedFileOrImage(\n                allocationBase,\n                allocationSize,\n                type,\n                fileName,\n                Callback,\n                Context\n                );\n\n            if (!result)\n                break;\n        }\n        else\n        {\n            baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize);\n\n            if (!NT_SUCCESS(NtQueryVirtualMemory(\n                ProcessHandle,\n                baseAddress,\n                MemoryBasicInformation,\n                &basicInfo,\n                sizeof(MEMORY_BASIC_INFORMATION),\n                NULL\n                )))\n            {\n                querySucceeded = FALSE;\n            }\n        }\n    }\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nstatic BOOLEAN NTAPI PhpBaseAddressHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    return *(PVOID *)Entry1 == *(PVOID *)Entry2;\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nstatic ULONG NTAPI PhpBaseAddressHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashIntPtr((ULONG_PTR)*(PVOID *)Entry);\n}\n\n/**\n * Enumerates the modules loaded by a process.\n *\n * \\param ProcessId The ID of a process. If \\ref SYSTEM_PROCESS_ID is specified the function\n * enumerates the kernel modules.\n * \\param ProcessHandle A handle to the process.\n * \\param Flags Flags controlling the information to retrieve.\n * \\li \\c PH_ENUM_GENERIC_MAPPED_FILES Enumerate mapped files.\n * \\li \\c PH_ENUM_GENERIC_MAPPED_IMAGES Enumerate mapped images (those which are not mapped by the\n * loader).\n * \\param Callback A callback function which is executed for each module.\n * \\param Context A user-defined value to pass to the callback function.\n */\nNTSTATUS PhEnumGenericModules(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PPH_HASHTABLE baseAddressHashtable;\n\n    baseAddressHashtable = PhCreateHashtable(\n        sizeof(PVOID),\n        PhpBaseAddressHashtableEqualFunction,\n        PhpBaseAddressHashtableHashFunction,\n        100\n        );\n\n    if (ProcessId == SYSTEM_PROCESS_ID)\n    {\n        // Kernel modules\n\n        PVOID modules;\n\n        status = PhEnumKernelModulesEx((PRTL_PROCESS_MODULE_INFORMATION_EX*)&modules);\n\n        if (NT_SUCCESS(status))\n        {\n            PhpRtlModulesExToGenericModules(\n                modules,\n                Callback,\n                baseAddressHashtable,\n                Context\n                );\n            PhFree(modules);\n        }\n        else\n        {\n            status = PhEnumKernelModules((PRTL_PROCESS_MODULES*)&modules);\n\n            if (NT_SUCCESS(status))\n            {\n                PhpRtlModulesToGenericModules(\n                    modules,\n                    Callback,\n                    baseAddressHashtable,\n                    Context\n                    );\n                PhFree(modules);\n            }\n        }\n    }\n    else\n    {\n        // Process modules\n\n        BOOLEAN opened = FALSE;\n#ifdef _WIN64\n        BOOLEAN isWow64 = FALSE;\n#endif\n        ENUM_GENERIC_PROCESS_MODULES_CONTEXT context;\n        PH_ENUM_PROCESS_MODULES_PARAMETERS parameters;\n\n        if (!ProcessHandle)\n        {\n            if (!NT_SUCCESS(status = PhOpenProcess(\n                &ProcessHandle,\n                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, // needed for enumerating mapped files\n                ProcessId\n                )))\n            {\n                if (!NT_SUCCESS(status = PhOpenProcess(\n                    &ProcessHandle,\n                    PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,\n                    ProcessId\n                    )))\n                {\n                    goto CleanupExit;\n                }\n            }\n\n            opened = TRUE;\n        }\n\n        context.Callback = Callback;\n        context.Context = Context;\n        context.Type = PH_MODULE_TYPE_MODULE;\n        context.BaseAddressHashtable = baseAddressHashtable;\n        context.LoadOrderIndex = 0;\n\n        parameters.Callback = EnumGenericProcessModulesCallback;\n        parameters.Context = &context;\n        parameters.Flags = PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME;\n\n        status = PhEnumProcessModulesEx(\n            ProcessHandle,\n            &parameters\n            );\n\n#ifdef _WIN64\n        PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n        // 32-bit process modules\n        if (isWow64)\n        {\n            context.Callback = Callback;\n            context.Context = Context;\n            context.Type = PH_MODULE_TYPE_WOW64_MODULE;\n            context.BaseAddressHashtable = baseAddressHashtable;\n            context.LoadOrderIndex = 0;\n\n            status = PhEnumProcessModules32Ex(\n                ProcessHandle,\n                &parameters\n                );\n        }\n#endif\n\n        // Mapped files and mapped images\n        // This is done last because it provides the least amount of information.\n\n        if (Flags & (PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES))\n        {\n            PhpEnumGenericMappedFilesAndImages(\n                ProcessHandle,\n                Flags,\n                Callback,\n                baseAddressHashtable,\n                Context\n                );\n        }\n\n        if (opened)\n            NtClose(ProcessHandle);\n    }\n\nCleanupExit:\n    PhDereferenceObject(baseAddressHashtable);\n\n    return status;\n}\n\ntypedef struct _PH_ENUM_PROCESS_MODULES_LIMITED_PARAMETERS\n{\n    PPH_ENUM_PROCESS_MODULES_LIMITED_CALLBACK Callback;\n    PPH_HASHTABLE BaseAddressHashtable;\n    PVOID Context;\n} PH_ENUM_PROCESS_MODULES_LIMITED_PARAMETERS, *PPH_ENUM_PROCESS_MODULES_LIMITED_PARAMETERS;\n\n_Function_class_(PH_ENUM_MEMORY_PAGE_CALLBACK)\nstatic NTSTATUS NTAPI PhEnumProcessModulesLimitedCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG_PTR NumberOfEntries,\n    _In_ PMEMORY_WORKING_SET_BLOCK WorkingSetBlock,\n    _In_ PVOID Context\n    )\n{\n    PPH_ENUM_PROCESS_MODULES_LIMITED_PARAMETERS parameters = Context;\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    MEMORY_IMAGE_INFORMATION imageInformation;\n    PVOID baseAddress = NULL;\n    PPH_STRING fileName;\n\n    for (ULONG_PTR i = 0; i < NumberOfEntries; i++)\n    {\n        PMEMORY_WORKING_SET_BLOCK workingSetBlock = &WorkingSetBlock[i];\n        PVOID virtualAddress = (PVOID)(workingSetBlock->VirtualPage << PAGE_SHIFT);\n\n        if (virtualAddress < baseAddress)\n            continue;\n\n        status = PhGetProcessMappedImageInformation(\n            ProcessHandle,\n            virtualAddress,\n            &imageInformation\n            );\n\n        if (\n            !NT_SUCCESS(status) ||\n            !imageInformation.ImageBase ||\n            imageInformation.ImageNotExecutable ||\n            imageInformation.ImagePartialMap\n            )\n        {\n            continue;\n        }\n\n        if (PhFindEntryHashtable(parameters->BaseAddressHashtable, &imageInformation.ImageBase))\n            continue;\n\n        PhAddEntryHashtable(parameters->BaseAddressHashtable, &imageInformation.ImageBase);\n\n        status = PhGetProcessMappedFileName(\n            ProcessHandle,\n            imageInformation.ImageBase,\n            &fileName\n            );\n\n        if (!NT_SUCCESS(status))\n            continue;\n\n        status = parameters->Callback(\n            ProcessHandle,\n            virtualAddress,\n            imageInformation.ImageBase,\n            imageInformation.SizeOfImage,\n            fileName,\n            parameters->Context\n            );\n\n        PhDereferenceObject(fileName);\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        baseAddress = PTR_ADD_OFFSET(imageInformation.ImageBase, imageInformation.SizeOfImage);\n    }\n\n    if (status == STATUS_NO_MORE_ENTRIES)\n    {\n        status = STATUS_SUCCESS;\n    }\n\n    return status;\n}\n\nNTSTATUS PhEnumProcessModulesLimited(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_LIMITED_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PH_ENUM_PROCESS_MODULES_LIMITED_PARAMETERS limitedParameters;\n    PPH_HASHTABLE baseAddressHashtable;\n\n    baseAddressHashtable = PhCreateHashtable(\n        sizeof(PVOID),\n        PhpBaseAddressHashtableEqualFunction,\n        PhpBaseAddressHashtableHashFunction,\n        100\n        );\n\n    memset(&limitedParameters, 0, sizeof(PH_ENUM_PROCESS_MODULES_LIMITED_PARAMETERS));\n    limitedParameters.BaseAddressHashtable = baseAddressHashtable;\n    limitedParameters.Callback = Callback;\n    limitedParameters.Context = Context;\n\n    status = PhEnumVirtualMemoryPages(\n        ProcessHandle,\n        PhEnumProcessModulesLimitedCallback,\n        &limitedParameters\n        );\n\n    PhDereferenceObject(baseAddressHashtable);\n\n    return status;\n}\n\nNTSTATUS PhEnumProcessEnclaveModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID EnclaveAddress,\n    _In_ PLDR_SOFTWARE_ENCLAVE Enclave,\n    _In_ PPH_ENUM_PROCESS_ENCLAVE_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PVOID listHead;\n    LDR_DATA_TABLE_ENTRY entry;\n\n    status = STATUS_SUCCESS;\n\n    listHead = PTR_ADD_OFFSET(EnclaveAddress, FIELD_OFFSET(LDR_SOFTWARE_ENCLAVE, Modules));\n\n    for (PLIST_ENTRY link = Enclave->Modules.Flink;\n         link != listHead;\n         link = entry.InLoadOrderLinks.Flink)\n    {\n        PVOID entryAddress;\n\n        entryAddress = CONTAINING_RECORD(link, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            entryAddress,\n            &entry,\n            sizeof(entry),\n            NULL\n            );\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (!Callback(ProcessHandle, Enclave, entryAddress, &entry, Context))\n            break;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessLdrTableEntryNames(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _Out_ PPH_STRING* Name,\n    _Out_ PPH_STRING* FileName\n    )\n{\n    NTSTATUS status;\n    PPH_STRING name;\n    PPH_STRING fileName;\n    PWSTR fullDllName;\n    ULONG_PTR index;\n\n    *Name = NULL;\n    *FileName = NULL;\n\n    name = NULL;\n    fileName = NULL;\n    fullDllName = NULL;\n\n    if (Entry->DllBase)\n    {\n        PhGetProcessMappedFileName(ProcessHandle, Entry->DllBase, &fileName);\n    }\n\n    if (PhIsNullOrEmptyString(fileName))\n    {\n        fullDllName = PhAllocate(Entry->FullDllName.Length);\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            Entry->FullDllName.Buffer,\n            fullDllName,\n            Entry->FullDllName.Length,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        if (!(Entry->FullDllName.Length & 1)) // validate the string length\n        {\n            fileName = PhCreateStringEx(fullDllName, Entry->FullDllName.Length);\n        }\n        else\n        {\n            goto CleanupExit;\n        }\n    }\n\n    index = PhFindLastCharInStringRef(\n        &fileName->sr,\n        OBJ_NAME_PATH_SEPARATOR,\n        FALSE\n        );\n\n    if (index != SIZE_MAX)\n    {\n        name = PhCreateStringEx(\n            &fileName->Buffer[index + 1],\n            fileName->Length - (index * sizeof(WCHAR))\n            );\n    }\n    else\n    {\n        name = PhReferenceObject(fileName);\n    }\n\n    *Name = name;\n    *FileName = fileName;\n\n    name = NULL;\n    fileName = NULL;\n\nCleanupExit:\n\n    if (fullDllName)\n        PhFree(fullDllName);\n\n    PhClearReference(&name);\n    PhClearReference(&fileName);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "phlib/nativepipe.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n\n/**\n* Creates an anonymous pipe.\n*\n* \\param PipeReadHandle The pipe read handle.\n* \\param PipeWriteHandle The pipe write handle.\n*/\nNTSTATUS PhCreatePipe(\n    _Out_ PHANDLE PipeReadHandle,\n    _Out_ PHANDLE PipeWriteHandle\n    )\n{\n    return PhCreatePipeEx(PipeReadHandle, PipeWriteHandle, NULL, NULL);\n}\n\n/**\n* Creates an anonymous pipe.\n*\n* \\param[out] PipeReadHandle The pipe read handle.\n* \\param[out] PipeWriteHandle The pipe write handle.\n* \\param[in] PipeReadAttributes Optional pipe read attributes.\n* \\param[in] PipeWriteAttributes Optional pipe write attributes.\n*/\nNTSTATUS PhCreatePipeEx(\n    _Out_ PHANDLE PipeReadHandle,\n    _Out_ PHANDLE PipeWriteHandle,\n    _In_opt_ PSECURITY_ATTRIBUTES PipeReadAttributes,\n    _In_opt_ PSECURITY_ATTRIBUTES PipeWriteAttributes\n    )\n{\n    NTSTATUS status;\n    PACL pipeAcl = NULL;\n    HANDLE pipeDirectoryHandle;\n    HANDLE pipeReadHandle;\n    HANDLE pipeWriteHandle;\n    UNICODE_STRING pipeName;\n    SECURITY_DESCRIPTOR securityDescriptor;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK isb;\n    LARGE_INTEGER timeout;\n    SECURITY_QUALITY_OF_SERVICE pipeSecurityQos =\n    {\n        sizeof(SECURITY_QUALITY_OF_SERVICE),\n        SecurityAnonymous,\n        SECURITY_STATIC_TRACKING,\n        FALSE\n    };\n\n    RtlInitUnicodeString(&pipeName, DEVICE_NAMED_PIPE);\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &pipeName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &pipeDirectoryHandle,\n        GENERIC_READ | SYNCHRONIZE,\n        &objectAttributes,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    RtlInitEmptyUnicodeString(&pipeName, NULL, 0);\n    InitializeObjectAttributesEx(\n        &objectAttributes,\n        &pipeName,\n        OBJ_CASE_INSENSITIVE,\n        pipeDirectoryHandle,\n        NULL,\n        &pipeSecurityQos\n        );\n\n    if (PipeReadAttributes)\n    {\n        if (PipeReadAttributes->bInheritHandle)\n        {\n            SetFlag(objectAttributes.Attributes, OBJ_INHERIT);\n        }\n\n        if (PipeReadAttributes->lpSecurityDescriptor)\n        {\n            objectAttributes.SecurityDescriptor = PipeReadAttributes->lpSecurityDescriptor;\n        }\n    }\n\n    if (!objectAttributes.SecurityDescriptor)\n    {\n        status = PhDefaultNpAcl(&pipeAcl);\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE);\n\n                if (NT_SUCCESS(status))\n                {\n                    objectAttributes.SecurityDescriptor = &securityDescriptor;\n                }\n\n                assert(RtlValidSecurityDescriptor(&securityDescriptor));\n            }\n        }\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    status = NtCreateNamedPipeFile(\n        &pipeReadHandle,\n        FILE_WRITE_ATTRIBUTES | GENERIC_READ | SYNCHRONIZE,\n        &objectAttributes,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_CREATE,\n        FILE_PIPE_INBOUND | FILE_SYNCHRONOUS_IO_NONALERT,\n        FILE_PIPE_BYTE_STREAM_TYPE | FILE_PIPE_REJECT_REMOTE_CLIENTS,\n        FILE_PIPE_BYTE_STREAM_MODE,\n        FILE_PIPE_QUEUE_OPERATION,\n        1,\n        PAGE_SIZE,\n        PAGE_SIZE,\n        PhTimeoutFromMilliseconds(&timeout, 120000)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    RtlInitEmptyUnicodeString(&pipeName, NULL, 0);\n    InitializeObjectAttributesEx(\n        &objectAttributes,\n        &pipeName,\n        OBJ_CASE_INSENSITIVE,\n        pipeReadHandle,\n        NULL,\n        &pipeSecurityQos\n        );\n\n    if (PipeWriteAttributes)\n    {\n        if (PipeWriteAttributes->bInheritHandle)\n        {\n            SetFlag(objectAttributes.Attributes, OBJ_INHERIT);\n        }\n\n        if (PipeWriteAttributes->lpSecurityDescriptor)\n        {\n            objectAttributes.SecurityDescriptor = PipeWriteAttributes->lpSecurityDescriptor;\n        }\n    }\n\n    status = NtOpenFile(\n        &pipeWriteHandle,\n        FILE_READ_ATTRIBUTES | GENERIC_WRITE | SYNCHRONIZE,\n        &objectAttributes,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PipeReadHandle = pipeReadHandle;\n        *PipeWriteHandle = pipeWriteHandle;\n    }\n\nCleanupExit:\n    if (pipeAcl)\n    {\n        PhFree(pipeAcl);\n    }\n\n    NtClose(pipeDirectoryHandle);\n    return status;\n}\n\n/**\n* Creates an named pipe.\n*\n* \\param PipeHandle The pipe read/write handle.\n* \\param PipeName The pipe name.\n*/\nNTSTATUS PhCreateNamedPipe(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PCPH_STRINGREF PipeName\n    )\n{\n    static CONST PH_STRINGREF deviceName = PH_STRINGREF_INIT(DEVICE_NAMED_PIPE);\n    NTSTATUS status;\n    PACL pipeAcl = NULL;\n    HANDLE pipeHandle;\n    PPH_STRING pipeName;\n    UNICODE_STRING pipeNameUs;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK isb;\n    LARGE_INTEGER timeout;\n    SECURITY_DESCRIPTOR securityDescriptor;\n    SECURITY_QUALITY_OF_SERVICE pipeSecurityQos =\n    {\n        sizeof(SECURITY_QUALITY_OF_SERVICE),\n        SecurityAnonymous,\n        SECURITY_STATIC_TRACKING,\n        FALSE\n    };\n\n    pipeName = PhConcatStringRef2(&deviceName, PipeName);\n\n    if (!PhStringRefToUnicodeString(&pipeName->sr, &pipeNameUs))\n    {\n        PhDereferenceObject(pipeName);\n        return STATUS_NAME_TOO_LONG;\n    }\n\n    InitializeObjectAttributesEx(\n        &objectAttributes,\n        &pipeNameUs,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL,\n        &pipeSecurityQos\n        );\n\n    if (NT_SUCCESS(PhDefaultNpAcl(&pipeAcl)))\n    {\n        PhCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n        PhSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE);\n\n        objectAttributes.SecurityDescriptor = &securityDescriptor;\n    }\n\n    status = NtCreateNamedPipeFile(\n        &pipeHandle,\n        FILE_GENERIC_READ | FILE_GENERIC_WRITE | SYNCHRONIZE,\n        &objectAttributes,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_OPEN_IF,\n        FILE_PIPE_FULL_DUPLEX | FILE_SYNCHRONOUS_IO_NONALERT,\n        FILE_PIPE_MESSAGE_TYPE | FILE_PIPE_REJECT_REMOTE_CLIENTS,\n        FILE_PIPE_MESSAGE_MODE,\n        FILE_PIPE_QUEUE_OPERATION,\n        FILE_PIPE_UNLIMITED_INSTANCES,\n        PAGE_SIZE,\n        PAGE_SIZE,\n        PhTimeoutFromMilliseconds(&timeout, 1000)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PipeHandle = pipeHandle;\n    }\n\n    if (pipeAcl)\n    {\n        PhFree(pipeAcl);\n    }\n\n    PhDereferenceObject(pipeName);\n    return status;\n}\n\nNTSTATUS PhConnectPipe(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PCPH_STRINGREF PipeName\n    )\n{\n    static CONST PH_STRINGREF deviceName = PH_STRINGREF_INIT(DEVICE_NAMED_PIPE);\n    NTSTATUS status;\n    HANDLE pipeHandle;\n    PPH_STRING pipeName;\n    UNICODE_STRING pipeNameUs;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK isb;\n    SECURITY_QUALITY_OF_SERVICE pipeSecurityQos =\n    {\n        sizeof(SECURITY_QUALITY_OF_SERVICE),\n        SecurityAnonymous,\n        SECURITY_STATIC_TRACKING,\n        FALSE\n    };\n\n    pipeName = PhConcatStringRef2(&deviceName, PipeName);\n\n    if (!PhStringRefToUnicodeString(&pipeName->sr, &pipeNameUs))\n    {\n        PhDereferenceObject(pipeName);\n        return STATUS_NAME_TOO_LONG;\n    }\n\n    InitializeObjectAttributesEx(\n        &objectAttributes,\n        &pipeNameUs,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL,\n        &pipeSecurityQos\n        );\n\n    status = NtCreateFile(\n        &pipeHandle,\n        FILE_GENERIC_READ | FILE_GENERIC_WRITE | SYNCHRONIZE,\n        &objectAttributes,\n        &isb,\n        NULL,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_OPEN_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PipeHandle = pipeHandle;\n    }\n\n    PhDereferenceObject(pipeName);\n    return status;\n}\n\nNTSTATUS PhListenNamedPipe(\n    _In_ HANDLE PipeHandle\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_LISTEN,\n        NULL,\n        0,\n        NULL,\n        0\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    return status;\n}\n\nNTSTATUS PhDisconnectNamedPipe(\n    _In_ HANDLE PipeHandle\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_DISCONNECT,\n        NULL,\n        0,\n        NULL,\n        0\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    return status;\n}\n\nNTSTATUS PhPeekNamedPipe(\n    _In_ HANDLE PipeHandle,\n    _Out_writes_bytes_opt_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG NumberOfBytesRead,\n    _Out_opt_ PULONG NumberOfBytesAvailable,\n    _Out_opt_ PULONG NumberOfBytesLeftInMessage\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PFILE_PIPE_PEEK_BUFFER peekBuffer;\n    ULONG peekBufferLength;\n\n    peekBufferLength = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data) + Length;\n    peekBuffer = PhAllocate(peekBufferLength);\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_PEEK,\n        NULL,\n        0,\n        peekBuffer,\n        peekBufferLength\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    // STATUS_BUFFER_OVERFLOW means that there is data remaining; this is normal.\n    if (status == STATUS_BUFFER_OVERFLOW)\n        status = STATUS_SUCCESS;\n\n    if (NT_SUCCESS(status))\n    {\n        ULONG numberOfBytesRead = 0;\n\n        if (Buffer || NumberOfBytesRead || NumberOfBytesLeftInMessage)\n            numberOfBytesRead = (ULONG)(isb.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data));\n\n        if (Buffer)\n            memcpy(Buffer, peekBuffer->Data, numberOfBytesRead);\n\n        if (NumberOfBytesRead)\n            *NumberOfBytesRead = numberOfBytesRead;\n\n        if (NumberOfBytesAvailable)\n            *NumberOfBytesAvailable = peekBuffer->ReadDataAvailable;\n\n        if (NumberOfBytesLeftInMessage)\n            *NumberOfBytesLeftInMessage = peekBuffer->MessageLength - numberOfBytesRead;\n    }\n\n    PhFree(peekBuffer);\n\n    return status;\n}\n\nNTSTATUS PhCallNamedPipe(\n    _In_ PCWSTR PipeName,\n    _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    )\n{\n    NTSTATUS status;\n    HANDLE pipeHandle = NULL;\n\n    status = PhConnectPipeZ(&pipeHandle, PipeName);\n\n    if (!NT_SUCCESS(status))\n    {\n        PhWaitForNamedPipe(PipeName, 1000);\n\n        status = PhConnectPipeZ(&pipeHandle, PipeName);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        FILE_PIPE_INFORMATION pipeInfo;\n        IO_STATUS_BLOCK isb;\n\n        memset(&pipeInfo, 0, sizeof(FILE_PIPE_INFORMATION));\n        pipeInfo.CompletionMode = FILE_PIPE_QUEUE_OPERATION;\n        pipeInfo.ReadMode = FILE_PIPE_MESSAGE_MODE;\n\n        status = NtSetInformationFile(\n            pipeHandle,\n            &isb,\n            &pipeInfo,\n            sizeof(FILE_PIPE_INFORMATION),\n            FilePipeInformation\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhTransceiveNamedPipe(\n            pipeHandle,\n            InputBuffer,\n            InputBufferLength,\n            OutputBuffer,\n            OutputBufferLength\n            );\n    }\n\n    if (pipeHandle)\n    {\n        IO_STATUS_BLOCK ioStatusBlock;\n\n        NtFlushBuffersFile(pipeHandle, &ioStatusBlock);\n\n        PhDisconnectNamedPipe(pipeHandle);\n\n        NtClose(pipeHandle);\n    }\n\n    return status;\n}\n\nNTSTATUS PhTransceiveNamedPipe(\n    _In_ HANDLE PipeHandle,\n    _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_TRANSCEIVE,\n        InputBuffer,\n        InputBufferLength,\n        OutputBuffer,\n        OutputBufferLength\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    return status;\n}\n\nNTSTATUS PhWaitForNamedPipe(\n    _In_ PCWSTR PipeName,\n    _In_opt_ ULONG Timeout\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PH_STRINGREF pipeName;\n    UNICODE_STRING objectName;\n    HANDLE fileSystemHandle;\n    OBJECT_ATTRIBUTES objectAttributes;\n    PFILE_PIPE_WAIT_FOR_BUFFER waitForBuffer;\n    ULONG waitForBufferLength;\n\n    RtlInitUnicodeString(&objectName, DEVICE_NAMED_PIPE);\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &fileSystemHandle,\n        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        &objectAttributes,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhInitializeStringRefLongHint(&pipeName, PipeName);\n    waitForBufferLength = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name) + (ULONG)pipeName.Length;\n    waitForBuffer = PhAllocate(waitForBufferLength);\n\n    if (Timeout)\n    {\n        PhTimeoutFromMilliseconds(&waitForBuffer->Timeout, Timeout);\n        waitForBuffer->TimeoutSpecified = TRUE;\n    }\n    else\n    {\n        waitForBuffer->Timeout.LowPart = 0;\n        waitForBuffer->Timeout.HighPart = MINLONG; // a very long time\n        waitForBuffer->TimeoutSpecified = TRUE;\n    }\n\n    waitForBuffer->NameLength = (ULONG)pipeName.Length;\n    memcpy(waitForBuffer->Name, pipeName.Buffer, pipeName.Length);\n\n    status = NtFsControlFile(\n        fileSystemHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_WAIT,\n        waitForBuffer,\n        waitForBufferLength,\n        NULL,\n        0\n        );\n\n    PhFree(waitForBuffer);\n    NtClose(fileSystemHandle);\n\n    return status;\n}\n\nNTSTATUS PhImpersonateClientOfNamedPipe(\n    _In_ HANDLE PipeHandle\n    )\n{\n    IO_STATUS_BLOCK isb;\n\n    return NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_IMPERSONATE,\n        NULL,\n        0,\n        NULL,\n        0\n        );\n}\n\nNTSTATUS PhDisableImpersonateNamedPipe(\n    _In_ HANDLE PipeHandle\n    )\n{\n    IO_STATUS_BLOCK isb;\n\n    return NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_DISABLE_IMPERSONATE,\n        NULL,\n        0,\n        NULL,\n        0\n        );\n}\n\nNTSTATUS PhGetNamedPipeClientComputerName(\n    _In_ HANDLE PipeHandle,\n    _In_ ULONG ClientComputerNameLength,\n    _Out_ PVOID ClientComputerName\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,\n        \"ClientComputerName\",\n        sizeof(\"ClientComputerName\"),\n        ClientComputerName,\n        ClientComputerNameLength\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetNamedPipeClientProcessId(\n    _In_ HANDLE PipeHandle,\n    _Out_ PHANDLE ClientProcessId\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    ULONG processId = 0;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,\n        \"ClientProcessId\",\n        sizeof(\"ClientProcessId\"),\n        &processId,\n        sizeof(ULONG)\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (ClientProcessId)\n        {\n            *ClientProcessId = UlongToHandle(processId);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetNamedPipeClientSessionId(\n    _In_ HANDLE PipeHandle,\n    _Out_ PHANDLE ClientSessionId\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    ULONG processId = 0;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,\n        \"ClientSessionId\",\n        sizeof(\"ClientSessionId\"),\n        &processId,\n        sizeof(ULONG)\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (ClientSessionId)\n        {\n            *ClientSessionId = UlongToHandle(processId);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetNamedPipeServerProcessId(\n    _In_ HANDLE PipeHandle,\n    _Out_ PHANDLE ServerProcessId\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    ULONG processId = 0;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_GET_PIPE_ATTRIBUTE,\n        \"ServerProcessId\",\n        sizeof(\"ServerProcessId\"),\n        &processId,\n        sizeof(ULONG)\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (ServerProcessId)\n        {\n            *ServerProcessId = UlongToHandle(processId);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetNamedPipeServerSessionId(\n    _In_ HANDLE PipeHandle,\n    _Out_ PHANDLE ServerSessionId\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    ULONG processId = 0;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_GET_PIPE_ATTRIBUTE,\n        \"ServerSessionId\",\n        sizeof(\"ServerSessionId\"),\n        &processId,\n        sizeof(ULONG)\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (ServerSessionId)\n        {\n            *ServerSessionId = UlongToHandle(processId);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhEnumDirectoryNamedPipe(\n    _In_opt_ PCPH_STRINGREF SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    static CONST PH_STRINGREF objectName = PH_STRINGREF_INIT(DEVICE_NAMED_PIPE);\n    HANDLE objectHandle;\n    NTSTATUS status;\n\n    status = PhOpenFile(\n        &objectHandle,\n        &objectName,\n        FILE_LIST_DIRECTORY | SYNCHRONIZE,\n        NULL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhEnumDirectoryFile(\n            objectHandle,\n            SearchPattern,\n            Callback,\n            Context\n            );\n\n        NtClose(objectHandle);\n    }\n\n    return status;\n}\n\n// rev from RtlDefaultNpAcl\nNTSTATUS PhDefaultNpAcl(\n    _Out_ PACL* DefaultNpAc\n    )\n{\n    NTSTATUS status;\n    PACL pipeAcl;\n    PH_TOKEN_OWNER tokenQuery;\n\n    status = PhGetTokenOwner(\n        NtCurrentThreadEffectiveToken(),\n        &tokenQuery\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        APPCONTAINER_SID_TYPE appContainerSidType = InvalidAppContainerSidType;\n        PH_TOKEN_APPCONTAINER tokenAppContainer = { 0 };\n        PSID appContainerSidParent = NULL;\n\n        ULONG defaultAclSize =\n            (ULONG)sizeof(ACL) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            PhLengthSid((PSID)&PhSeLocalSystemSid) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            PhLengthSid(PhSeAdministratorsSid()) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            PhLengthSid(tokenQuery.TokenOwner.Owner) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            PhLengthSid((PSID)&PhSeEveryoneSid) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            PhLengthSid((PSID)&PhSeAnonymousLogonSid);\n\n        if (NT_SUCCESS(PhGetTokenAppContainerSid(NtCurrentThreadEffectiveToken(), &tokenAppContainer)))\n        {\n            if (RtlGetAppContainerSidType_Import())\n                RtlGetAppContainerSidType_Import()(tokenAppContainer.AppContainer.Sid, &appContainerSidType);\n\n            if (appContainerSidType == ChildAppContainerSidType)\n            {\n                if (RtlGetAppContainerParent_Import())\n                    RtlGetAppContainerParent_Import()(tokenAppContainer.AppContainer.Sid, &appContainerSidParent);\n            }\n        }\n\n        if (tokenAppContainer.AppContainer.Sid)\n            defaultAclSize += (ULONG)sizeof(ACCESS_ALLOWED_ACE) + PhLengthSid(tokenAppContainer.AppContainer.Sid);\n        if (appContainerSidParent)\n            defaultAclSize += (ULONG)sizeof(ACCESS_ALLOWED_ACE) + PhLengthSid(appContainerSidParent);\n\n        pipeAcl = PhAllocateZero(defaultAclSize);\n        PhCreateAcl(pipeAcl, defaultAclSize, ACL_REVISION);\n        PhAddAccessAllowedAce(pipeAcl, ACL_REVISION, GENERIC_ALL, &PhSeLocalSystemSid);\n        PhAddAccessAllowedAce(pipeAcl, ACL_REVISION, GENERIC_ALL, PhSeAdministratorsSid());\n\n        if (tokenAppContainer.AppContainer.Sid)\n            PhAddAccessAllowedAce(pipeAcl, ACL_REVISION, GENERIC_ALL, tokenAppContainer.AppContainer.Sid);\n        if (appContainerSidParent)\n            PhAddAccessAllowedAce(pipeAcl, ACL_REVISION, GENERIC_ALL, appContainerSidParent);\n\n        PhAddAccessAllowedAce(pipeAcl, ACL_REVISION, GENERIC_ALL, tokenQuery.TokenOwner.Owner);\n        PhAddAccessAllowedAce(pipeAcl, ACL_REVISION, GENERIC_READ, &PhSeEveryoneSid);\n        PhAddAccessAllowedAce(pipeAcl, ACL_REVISION, GENERIC_READ, &PhSeAnonymousLogonSid);\n\n        *DefaultNpAc = pipeAcl;\n\n        if (appContainerSidParent)\n        {\n            RtlFreeSid(appContainerSidParent);\n        }\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/nativeprocess.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <kphuser.h>\n\n/**\n * Opens a process.\n *\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param DesiredAccess The desired access to the process.\n * \\param ProcessId The ID of the process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    CLIENT_ID clientId;\n    KPH_LEVEL level;\n\n    clientId.UniqueProcess = ProcessId;\n    clientId.UniqueThread = NULL;\n\n    level = KsiLevel();\n\n    if ((level >= KphLevelMed) && (DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess)\n    {\n        status = KphOpenProcess(\n            ProcessHandle,\n            DesiredAccess,\n            &clientId\n            );\n    }\n    else\n    {\n        InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n        status = NtOpenProcess(\n            ProcessHandle,\n            DesiredAccess,\n            &objectAttributes,\n            &clientId\n            );\n\n        if (status == STATUS_ACCESS_DENIED && (level == KphLevelMax))\n        {\n            status = KphOpenProcess(\n                ProcessHandle,\n                DesiredAccess,\n                &clientId\n                );\n        }\n    }\n\n    return status;\n}\n\n/**\n * Opens a process handle using a CLIENT_ID structure.\n *\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param DesiredAccess The desired access rights for the process handle.\n * \\param ClientId A pointer to a CLIENT_ID structure that specifies the process and (optionally) thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenProcessClientId(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    KPH_LEVEL level;\n\n    level = KsiLevel();\n\n    if ((level >= KphLevelMed) && (DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess)\n    {\n        status = KphOpenProcess(\n            ProcessHandle,\n            DesiredAccess,\n            ClientId\n            );\n    }\n    else\n    {\n        InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n        status = NtOpenProcess(\n            ProcessHandle,\n            DesiredAccess,\n            &objectAttributes,\n            ClientId\n            );\n\n        if (status == STATUS_ACCESS_DENIED && (level == KphLevelMax))\n        {\n            status = KphOpenProcess(\n                ProcessHandle,\n                DesiredAccess,\n                ClientId\n                );\n        }\n    }\n\n    return status;\n}\n\n/** Limited API for untrusted/external code. */\n/**\n * Opens a process with limited access for untrusted or external code.\n *\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param DesiredAccess The desired access rights for the process handle.\n * \\param ProcessId The unique identifier (PID) of the process to open.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenProcessPublic(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    )\n{\n    OBJECT_ATTRIBUTES objectAttributes;\n    CLIENT_ID clientId;\n\n    InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n    clientId.UniqueProcess = ProcessId;\n    clientId.UniqueThread = NULL;\n\n    return NtOpenProcess(\n        ProcessHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &clientId\n        );\n}\n\n/**\n * Terminates a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_TERMINATE access.\n * \\param ExitStatus A status value that indicates why the process is being terminated.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    )\n{\n    NTSTATUS status;\n\n    if (KsiLevel() == KphLevelMax)\n    {\n        status = KphTerminateProcess(\n            ProcessHandle,\n            ExitStatus\n            );\n\n        if (NT_SUCCESS(status))\n            return status;\n    }\n\n    status = NtTerminateProcess(\n        ProcessHandle,\n        ExitStatus\n        );\n\n    return status;\n}\n\n/**\n * Suspends the specified process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_SUSPEND_RESUME access.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSuspendProcess(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n\n    status = NtSuspendProcess(\n        ProcessHandle\n        );\n\n    return status;\n}\n\n/**\n * Resumes the specified process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_SUSPEND_RESUME access.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhResumeProcess(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n\n    status = NtResumeProcess(\n        ProcessHandle\n        );\n\n    return status;\n}\n\n/**\n * Gets basic information for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param BasicInformation A variable which receives the information.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessBasicInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessBasicInformation,\n        BasicInformation,\n        sizeof(PROCESS_BASIC_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * Gets extended basic information for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param ExtendedBasicInformation A variable which receives the information.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessExtendedBasicInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_EXTENDED_BASIC_INFORMATION ExtendedBasicInformation\n    )\n{\n    ExtendedBasicInformation->Size = sizeof(PROCESS_EXTENDED_BASIC_INFORMATION);\n\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessBasicInformation,\n        ExtendedBasicInformation,\n        sizeof(PROCESS_EXTENDED_BASIC_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * Gets time information for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param Times A variable which receives the information.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessTimes(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKERNEL_USER_TIMES Times\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessTimes,\n        Times,\n        sizeof(KERNEL_USER_TIMES),\n        NULL\n        );\n}\n\n/**\n * Gets a process' session ID.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param SessionId A variable which receives the process' session ID.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessSessionId(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG SessionId\n    )\n{\n    NTSTATUS status;\n    PROCESS_SESSION_INFORMATION sessionInfo;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessSessionInformation,\n        &sessionInfo,\n        sizeof(PROCESS_SESSION_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *SessionId = sessionInfo.SessionId;\n    }\n\n    return status;\n}\n\n/**\n * Gets whether a process is running under 32-bit emulation.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param IsWow64Process A variable which receives a boolean indicating whether the process is 32-bit.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessIsWow64(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsWow64Process\n    )\n{\n    NTSTATUS status;\n    ULONG_PTR wow64;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessWow64Information,\n        &wow64,\n        sizeof(ULONG_PTR),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *IsWow64Process = !!wow64;\n    }\n\n    return status;\n}\n\n/**\n * Gets a process' WOW64 PEB address.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param Peb32 A variable which receives the base address of the process' WOW64 PEB. If the process\n * is 64-bit, the variable receives NULL.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessPeb32(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID* Peb32\n    )\n{\n    NTSTATUS status;\n    ULONG_PTR wow64;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessWow64Information,\n        &wow64,\n        sizeof(ULONG_PTR),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        // No PEB for System, Minimal or Pico processes. (dmex)\n        if (!wow64)\n            return STATUS_UNSUCCESSFUL;\n\n        *Peb32 = (PVOID)wow64;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessPeb(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID* PebBaseAddress\n    )\n{\n    NTSTATUS status;\n    PROCESS_BASIC_INFORMATION basicInfo;\n\n    status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        // No PEB for System, Minimal or Pico processes. (dmex)\n        if (!basicInfo.PebBaseAddress)\n            return STATUS_UNSUCCESSFUL;\n\n        *PebBaseAddress = (PVOID)basicInfo.PebBaseAddress;\n    }\n\n    return status;\n}\n\n/**\n * Gets a handle to a process' debug object.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param DebugObjectHandle A variable which receives a handle to the debug object associated with\n * the process. You must close the handle when you no longer need it.\n * \\return Successful or errant status.\n * \\retval STATUS_PORT_NOT_SET The process is not being debugged and has no associated debug object.\n */\nNTSTATUS PhGetProcessDebugObject(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE DebugObjectHandle\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessDebugObjectHandle,\n        DebugObjectHandle,\n        sizeof(HANDLE),\n        NULL\n        );\n}\n\nNTSTATUS PhGetProcessEnergyValues(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_EXTENDED_ENERGY_VALUES EnergyValues\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessEnergyValues,\n        EnergyValues,\n        sizeof(PROCESS_EXTENDED_ENERGY_VALUES),\n        NULL\n        );\n}\n\nNTSTATUS PhGetProcessErrorMode(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ErrorMode\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessDefaultHardErrorMode,\n        ErrorMode,\n        sizeof(ULONG),\n        NULL\n        );\n}\n\n/**\n * Sets the error mode for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_SET_INFORMATION access.\n * \\param ErrorMode The error mode to set for the process.\n * \\return STATUS_SUCCESS if the error mode was successfully set, otherwise an appropriate NTSTATUS error code.\n */\nNTSTATUS PhSetProcessErrorMode(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG ErrorMode\n    )\n{\n    return NtSetInformationProcess(\n        ProcessHandle,\n        ProcessDefaultHardErrorMode,\n        &ErrorMode,\n        sizeof(ULONG)\n        );\n}\n\n/**\n * Gets a process' no-execute status.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param ExecuteFlags A variable which receives the no-execute flags.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessExecuteFlags(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ExecuteFlags\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessExecuteFlags,\n        ExecuteFlags,\n        sizeof(ULONG),\n        NULL\n        );\n}\n\n/**\n * Gets a process' I/O priority.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param IoPriority A variable which receives the I/O priority of the process.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessIoPriority(\n    _In_ HANDLE ProcessHandle,\n    _Out_ IO_PRIORITY_HINT *IoPriority\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessIoPriority,\n        IoPriority,\n        sizeof(IO_PRIORITY_HINT),\n        NULL\n        );\n}\n\n/**\n * Gets a process' page priority.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param PagePriority A variable which receives the page priority of the process.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessPagePriority(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG PagePriority\n    )\n{\n    NTSTATUS status;\n    PAGE_PRIORITY_INFORMATION pagePriorityInfo;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessPagePriority,\n        &pagePriorityInfo,\n        sizeof(PAGE_PRIORITY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PagePriority = pagePriorityInfo.PagePriority;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessPriorityBoost(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN PriorityBoostDisabled\n    )\n{\n    NTSTATUS status;\n    ULONG priorityBoostDisabled;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessPriorityBoost,\n        &priorityBoostDisabled,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PriorityBoostDisabled = !!priorityBoostDisabled;\n    }\n\n    return status;\n}\n\n/**\n * Gets a process' cycle count.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param CycleTime A variable which receives the 64-bit cycle time.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetProcessCycleTime(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG64 CycleTime\n    )\n{\n    NTSTATUS status;\n    PROCESS_CYCLE_TIME_INFORMATION cycleTimeInfo;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessCycleTime,\n        &cycleTimeInfo,\n        sizeof(PROCESS_CYCLE_TIME_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *CycleTime = cycleTimeInfo.AccumulatedCycles;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessUptime(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_UPTIME_INFORMATION Uptime\n    )\n{\n    NTSTATUS status;\n    PROCESS_UPTIME_INFORMATION uptimeInfo;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessUptimeInformation,\n        &uptimeInfo,\n        sizeof(PROCESS_UPTIME_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Uptime = uptimeInfo;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessConsoleHostProcessId(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE ConsoleHostProcessId\n    )\n{\n    NTSTATUS status;\n    ULONG_PTR consoleHostProcess;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessConsoleHostProcess,\n        &consoleHostProcess,\n        sizeof(ULONG_PTR),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ConsoleHostProcessId = (HANDLE)consoleHostProcess;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessConsoleHostProcess(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE ConsoleHostProcessId,\n    _Out_opt_ PBOOLEAN ConsoleApplication\n    )\n{\n    NTSTATUS status;\n    ULONG_PTR consoleHostProcess;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessConsoleHostProcess,\n        &consoleHostProcess,\n        sizeof(ULONG_PTR),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ConsoleHostProcessId = (HANDLE)(consoleHostProcess & ~3);\n    }\n\n    if (ConsoleApplication)\n    {\n        *ConsoleApplication = !!(ULONG_PTR)(consoleHostProcess & 2);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessProtection(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPS_PROTECTION Protection\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessProtectionInformation,\n        Protection,\n        sizeof(PS_PROTECTION),\n        NULL\n        );\n}\n\nNTSTATUS PhGetProcessAffinityMask(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKAFFINITY AffinityMask\n    )\n{\n    NTSTATUS status;\n    KAFFINITY affinityMask;\n\n    memset(&affinityMask, 0, sizeof(KAFFINITY));\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessAffinityMask,\n        &affinityMask,\n        sizeof(KAFFINITY),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *AffinityMask = affinityMask;\n    }\n    else // Windows 7 (dmex)\n    {\n        PROCESS_BASIC_INFORMATION basicInfo;\n\n        if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessHandle, &basicInfo)))\n        {\n            *AffinityMask = basicInfo.AffinityMask;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessGroupInformation(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PUSHORT GroupCount,\n    _Out_ PUSHORT GroupArray\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n\n    // rev from GetProcessGroupAffinity (dmex)\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessGroupInformation,\n        GroupArray,\n        sizeof(USHORT) * *GroupCount,\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status) || status == STATUS_BUFFER_TOO_SMALL)\n    {\n        *GroupCount = (USHORT)returnLength / sizeof(USHORT); // (USHORT)returnLength >> 1\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessGroupAffinity(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PGROUP_AFFINITY GroupAffinity\n    )\n{\n    NTSTATUS status;\n    GROUP_AFFINITY groupAffinity;\n\n    memset(&groupAffinity, 0, sizeof(GROUP_AFFINITY));\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessAffinityMask,\n        &groupAffinity,\n        sizeof(GROUP_AFFINITY),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        memcpy(GroupAffinity, &groupAffinity, sizeof(GROUP_AFFINITY));\n    }\n    else // Windows 7 (dmex)\n    {\n        KAFFINITY affinityMask;\n\n        if (NT_SUCCESS(PhGetProcessAffinityMask(ProcessHandle, &affinityMask)))\n        {\n            groupAffinity.Mask = affinityMask;\n            memcpy(GroupAffinity, &groupAffinity, sizeof(GROUP_AFFINITY));\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessIsCFGuardEnabled(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsControlFlowGuardEnabled\n    )\n{\n    NTSTATUS status;\n    PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;\n\n    policyInfo.Policy = ProcessControlFlowGuardPolicy;\n    policyInfo.ControlFlowGuardPolicy.Flags = 0;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessMitigationPolicy,\n        &policyInfo,\n        sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *IsControlFlowGuardEnabled = !!policyInfo.ControlFlowGuardPolicy.EnableControlFlowGuard;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessIsXFGuardEnabled(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsXFGuardEnabled,\n    _Out_ PBOOLEAN IsXFGuardAuditEnabled\n    )\n{\n    NTSTATUS status;\n    PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;\n\n    policyInfo.Policy = ProcessControlFlowGuardPolicy;\n    policyInfo.ControlFlowGuardPolicy.Flags = 0;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessMitigationPolicy,\n        &policyInfo,\n        sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n#if !defined(NTDDI_WIN10_CO) || (NTDDI_VERSION < NTDDI_WIN10_CO)\n        *IsXFGuardEnabled = _bittest((const PLONG)&policyInfo.ControlFlowGuardPolicy.Flags, 3);\n        *IsXFGuardAuditEnabled = _bittest((const PLONG)&policyInfo.ControlFlowGuardPolicy.Flags, 4);\n#else\n        *IsXFGuardEnabled = !!policyInfo.ControlFlowGuardPolicy.EnableXfg;\n        *IsXFGuardAuditEnabled = !!policyInfo.ControlFlowGuardPolicy.EnableXfgAuditMode;\n#endif\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessHandleCount(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_HANDLE_INFORMATION HandleInfo\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessHandleCount,\n        HandleInfo,\n        sizeof(PROCESS_HANDLE_INFORMATION),\n        NULL\n        );\n}\n\nNTSTATUS PhGetProcessBreakOnTermination(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN BreakOnTermination\n    )\n{\n    NTSTATUS status;\n    ULONG breakOnTermination;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessBreakOnTermination,\n        &breakOnTermination,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *BreakOnTermination = !!breakOnTermination;\n    }\n\n    return status;\n}\n\nNTSTATUS PhSetProcessBreakOnTermination(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN BreakOnTermination\n    )\n{\n    ULONG breakOnTermination;\n\n    breakOnTermination = BreakOnTermination ? 1 : 0;\n\n    return NtSetInformationProcess(\n        ProcessHandle,\n        ProcessBreakOnTermination,\n        &breakOnTermination,\n        sizeof(ULONG)\n        );\n}\n\nNTSTATUS PhGetProcessAppMemoryInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_JOB_MEMORY_INFO JobMemoryInfo\n    )\n{\n    NTSTATUS status;\n    PROCESS_JOB_MEMORY_INFO jobMemoryInfo;\n\n    // Win32 called this ProcessAppMemoryInfo with APP_MEMORY_INFORMATION struct (dmex)\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessJobMemoryInformation,\n        &jobMemoryInfo,\n        sizeof(PROCESS_JOB_MEMORY_INFO),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *JobMemoryInfo = jobMemoryInfo;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetProcessMitigationPolicy(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESS_MITIGATION_POLICY Policy,\n    _Out_ PPROCESS_MITIGATION_POLICY_INFORMATION MitigationPolicy\n    )\n{\n    memset(MitigationPolicy, 0, sizeof(PROCESS_MITIGATION_POLICY_INFORMATION));\n    MitigationPolicy->Policy = Policy;\n\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessMitigationPolicy,\n        MitigationPolicy,\n        sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),\n        NULL\n        );\n}\n\nNTSTATUS PhGetProcessNetworkIoCounters(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_NETWORK_COUNTERS NetworkIoCounters\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessNetworkIoCounters,\n        NetworkIoCounters,\n        sizeof(PROCESS_NETWORK_COUNTERS),\n        NULL\n        );\n}\n\n/**\n * Queries variable-sized information for a process. The function allocates a buffer to contain the\n * information.\n *\n * \\param ProcessHandle A handle to a process. The access required depends on the information class\n * specified.\n * \\param ProcessInformationClass The information class to retrieve.\n * \\param Buffer A variable which receives a pointer to a buffer containing the information. You\n * must free the buffer using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpQueryProcessVariableSize(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG returnLength = 0;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessInformationClass,\n        NULL,\n        0,\n        &returnLength\n        );\n\n    if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL && status != STATUS_INFO_LENGTH_MISMATCH)\n    {\n        *Buffer = NULL;\n        return status;\n    }\n\n    buffer = PhAllocate(returnLength);\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessInformationClass,\n        buffer,\n        returnLength,\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n        *Buffer = NULL;\n    }\n\n    return status;\n}\n\n/**\n * Gets the cookie of the process.\n * A ProcessCookie is a per-process random value generated by the Windows kernel.\n * Its main purpose is to help protect against certain types of security attacks,\n * such as handle prediction and spoofing. By associating a unique, unpredictable\n * cookie with each process, the system can use it as part of internal validation\n * checks-making it harder for malicious code to guess or forge process information.\n * \\param ProcessHandle Handle to the process for which the cookie is retrieved.\n * \\param ProcessModifiedCookie Pointer to a ULONG that receives the modified process cookie.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessModifiedCookie(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ProcessModifiedCookie\n    )\n{\n    NTSTATUS status;\n    ULONG processCookie;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessCookie,\n        &processCookie,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ProcessModifiedCookie = (0x7FFFFFED * processCookie + 0x7FFFFFC3) % 0x7FFFFFFF;\n    }\n\n    return status;\n}\n\n/**\n * Gets the file name of the process' image.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param FileName A variable which receives a pointer to a string containing the file name. You\n * must free the string using PhDereferenceObject() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessImageFileName(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING fileName;\n    ULONG bufferLength;\n    ULONG returnLength = 0;\n\n    bufferLength = sizeof(UNICODE_STRING) + DOS_MAX_PATH_LENGTH * sizeof(WCHAR);\n    fileName = PhAllocateStack(bufferLength);\n    if (!fileName) return STATUS_NO_MEMORY;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessImageFileName,\n        fileName,\n        bufferLength,\n        &returnLength\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFreeStack(fileName);\n        bufferLength = returnLength;\n        fileName = PhAllocateStack(bufferLength);\n        if (!fileName) return STATUS_NO_MEMORY;\n\n        status = NtQueryInformationProcess(\n            ProcessHandle,\n            ProcessImageFileName,\n            fileName,\n            bufferLength,\n            &returnLength\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFreeStack(fileName);\n        return status;\n    }\n\n    // Note: Some minimal/pico processes have UNICODE_NULL as their filename. (dmex)\n    if (RtlIsNullOrEmptyUnicodeString(fileName))\n    {\n        PhFreeStack(fileName);\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    *FileName = PhCreateStringFromUnicodeString(fileName);\n    PhFreeStack(fileName);\n\n    return status;\n}\n\n/**\n * Gets the Win32 file name of the process' image.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param FileName A variable which receives a pointer to a string containing the file name. You\n * must free the string using PhDereferenceObject() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function is only available on Windows Vista and above.\n */\nNTSTATUS PhGetProcessImageFileNameWin32(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING fileName;\n    ULONG bufferLength;\n    ULONG returnLength = 0;\n\n    bufferLength = sizeof(UNICODE_STRING) + DOS_MAX_PATH_LENGTH * sizeof(WCHAR);\n    fileName = PhAllocateStack(bufferLength);\n    if (!fileName) return STATUS_NO_MEMORY;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessImageFileNameWin32,\n        fileName,\n        bufferLength,\n        &returnLength\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFreeStack(fileName);\n        bufferLength = returnLength;\n        fileName = PhAllocateStack(bufferLength);\n        if (!fileName) return STATUS_NO_MEMORY;\n\n        status = NtQueryInformationProcess(\n            ProcessHandle,\n            ProcessImageFileNameWin32,\n            fileName,\n            bufferLength,\n            &returnLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        PPH_STRING fileNameWin32;\n\n        // Note: Some minimal/pico processes have UNICODE_NULL as their filename. (dmex)\n        if (RtlIsNullOrEmptyUnicodeString(fileName))\n        {\n            PhFreeStack(fileName);\n            return STATUS_UNSUCCESSFUL;\n        }\n\n        fileNameWin32 = PhCreateStringFromUnicodeString(fileName);\n\n        // Note: ProcessImageFileNameWin32 returns the NT device path\n        // instead of the Win32 path in some cases were drivers haven't\n        // registered with the volume manager or have ignored the mount\n        // manager (e.g. ImDisk). We workaround these issues by calling\n        // PhGetFileName and resolving the NT device prefix. (dmex)\n\n        if (fileNameWin32->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)\n        {\n            PhMoveReference(&fileNameWin32, PhGetFileName(fileNameWin32));\n        }\n\n        *FileName = fileNameWin32;\n    }\n\n    PhFreeStack(fileName);\n\n    return status;\n}\n\n/**\n * Gets the file name of the process' image by a PID.\n *\n * \\param ProcessId A unique identifier of the process.\n * \\param FullFileName A variable which receives a pointer to a string containing the full name\n * of the file. You must free the string using PhDereferenceObject() when you no longer need it.\n * \\param FileName A variable which receives a pointer to a string containing the file name without\n * the path. You must free the string using PhDereferenceObject() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessImageFileNameById(\n    _In_ HANDLE ProcessId,\n    _Out_opt_ PPH_STRING *FullFileName,\n    _Out_opt_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    USHORT bufferSize;\n    SYSTEM_PROCESS_ID_INFORMATION processIdInfo;\n\n    if (!FullFileName && !FileName)\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    bufferSize = 0x200;\n    buffer = PhAllocateStack(bufferSize);\n    if (!buffer) return STATUS_NO_MEMORY;\n\n    processIdInfo.ProcessId = ProcessId;\n    processIdInfo.ImageName.Length = 0;\n    processIdInfo.ImageName.MaximumLength = bufferSize;\n    processIdInfo.ImageName.Buffer = buffer;\n\n    status = NtQuerySystemInformation(\n        SystemProcessIdInformation,\n        &processIdInfo,\n        sizeof(SYSTEM_PROCESS_ID_INFORMATION),\n        NULL\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        // Required length is stored in MaximumLength.\n\n        PhFreeStack(buffer);\n        buffer = PhAllocateStack(processIdInfo.ImageName.MaximumLength);\n        if (!buffer) return STATUS_NO_MEMORY;\n        processIdInfo.ImageName.Buffer = buffer;\n\n        status = NtQuerySystemInformation(\n            SystemProcessIdInformation,\n            &processIdInfo,\n            sizeof(SYSTEM_PROCESS_ID_INFORMATION),\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFreeStack(buffer);\n        return status;\n    }\n\n    if (FullFileName)\n    {\n        *FullFileName = PhCreateStringFromUnicodeString(&processIdInfo.ImageName);\n    }\n\n    if (FileName)\n    {\n        PH_STRINGREF stringRef;\n        ULONG_PTR index;\n\n        stringRef.Length = processIdInfo.ImageName.Length;\n        stringRef.Buffer = processIdInfo.ImageName.Buffer;\n\n        // Find where the name starts\n        index = PhFindLastCharInStringRef(&stringRef, L'\\\\', FALSE);\n\n        if (index == SIZE_MAX)\n            *FileName = PhCreateStringFromUnicodeString(&processIdInfo.ImageName);\n        else\n        {\n            // Reference the tail only\n            stringRef.Buffer = PTR_ADD_OFFSET(stringRef.Buffer, index * sizeof(WCHAR) + sizeof(UNICODE_NULL));\n            stringRef.Length = stringRef.Length - index * sizeof(WCHAR) - sizeof(UNICODE_NULL);\n\n            *FileName = PhCreateString2(&stringRef);\n        }\n    }\n\n    PhFreeStack(buffer);\n\n    return status;\n}\n\n/**\n * Gets the file name of a process' image.\n *\n * \\param ProcessId The ID of the process.\n * \\param FileName A variable which receives a pointer to a string containing the file name. You\n * must free the string using PhDereferenceObject() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function only works on Windows Vista and above. There does not appear to be any\n * access checking performed by the kernel for this.\n */\nNTSTATUS PhGetProcessImageFileNameByProcessId(\n    _In_opt_ HANDLE ProcessId,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    USHORT bufferSize;\n    SYSTEM_PROCESS_ID_INFORMATION processIdInfo;\n\n    bufferSize = 0x200;\n    buffer = PhAllocateStack(bufferSize);\n    if (!buffer) return STATUS_NO_MEMORY;\n\n    processIdInfo.ProcessId = ProcessId;\n    processIdInfo.ImageName.Length = 0;\n    processIdInfo.ImageName.MaximumLength = bufferSize;\n    processIdInfo.ImageName.Buffer = buffer;\n\n    status = NtQuerySystemInformation(\n        SystemProcessIdInformation,\n        &processIdInfo,\n        sizeof(SYSTEM_PROCESS_ID_INFORMATION),\n        NULL\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        // Required length is stored in MaximumLength.\n\n        PhFreeStack(buffer);\n        buffer = PhAllocateStack(processIdInfo.ImageName.MaximumLength);\n        if (!buffer) return STATUS_NO_MEMORY;\n        processIdInfo.ImageName.Buffer = buffer;\n\n        status = NtQuerySystemInformation(\n            SystemProcessIdInformation,\n            &processIdInfo,\n            sizeof(SYSTEM_PROCESS_ID_INFORMATION),\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFreeStack(buffer);\n        return status;\n    }\n\n    // Note: Some minimal/pico processes have UNICODE_NULL as their filename. (dmex)\n    if (RtlIsNullOrEmptyUnicodeString(&processIdInfo.ImageName))\n    {\n        PhFreeStack(buffer);\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    *FileName = PhCreateStringFromUnicodeString(&processIdInfo.ImageName);\n    PhFreeStack(buffer);\n\n    return status;\n}\n\n/**\n * Gets whether a process is being debugged.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param IsBeingDebugged A variable which receives a boolean indicating whether the process is being debugged.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessIsBeingDebugged(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsBeingDebugged\n    )\n{\n    NTSTATUS status;\n    PVOID debugHandle;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessDebugPort,\n        &debugHandle,\n        sizeof(PVOID),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *IsBeingDebugged = !!debugHandle;\n        return status;\n    }\n\n    if (KsiLevel() >= KphLevelLow)\n    {\n        KPH_PROCESS_STATE processState;\n\n        status = KphQueryInformationProcess(\n            ProcessHandle,\n            KphProcessStateInformation,\n            &processState,\n            sizeof(processState),\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            *IsBeingDebugged = !BooleanFlagOn(processState, KPH_PROCESS_NOT_BEING_DEBUGGED);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Determines if a process has started termination.\n *\n * \\param[in] ProcessHandle A handle to the process whose termination state is to be retrieved.\n * \\param[out] IsTerminated A pointer to a variable that receives the termination state (TRUE if terminated).\n * \\return Successful or errant status.\n * \\remarks The handle must have PROCESS_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetProcessIsTerminating(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsTerminated\n    )\n{\n    NTSTATUS status;\n    PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n\n    status = PhGetProcessExtendedBasicInformation(ProcessHandle, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        *IsTerminated = !!basicInfo.IsProcessDeleting;\n    }\n\n    return status;\n}\n\n/**\n * Determines if a process has terminated by waiting with zero timeout.\n *\n * \\param[in] ProcessHandle A handle to the process.\n * \\return TRUE if the process is terminated, FALSE otherwise.\n * \\remarks The handle must have SYNCRONIZE access.\n */\nNTSTATUS PhGetProcessIsTerminated(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsTerminated\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER timeout;\n\n    memset(&timeout, 0, sizeof(LARGE_INTEGER));\n\n    status = NtWaitForSingleObject(\n        ProcessHandle,\n        FALSE,\n        &timeout\n        );\n\n    *IsTerminated = status == STATUS_WAIT_0;\n\n    return status;\n}\n\n/**\n * Retrieves the device map for a specified process.\n *\n * \\param ProcessHandle Handle to the process whose device map is to be queried.\n * \\param DeviceMap Pointer to a ULONG that receives the device map value.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessDeviceMap(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG DeviceMap\n    )\n{\n    NTSTATUS status;\n#ifndef _WIN64\n    PROCESS_DEVICEMAP_INFORMATION deviceMapInfo;\n#else\n    PROCESS_DEVICEMAP_INFORMATION_EX deviceMapInfo;\n#endif\n    memset(&deviceMapInfo, 0, sizeof(deviceMapInfo));\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessDeviceMap,\n        &deviceMapInfo,\n        sizeof(deviceMapInfo),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (DeviceMap)\n        {\n            *DeviceMap = deviceMapInfo.Query.DriveMap;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Gets a string stored in a process' parameters structure.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param Offset The string to retrieve.\n * \\param String A variable which receives a pointer to the requested string. You must free the\n * string using PhDereferenceObject() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n * \\retval STATUS_INVALID_PARAMETER_2 An invalid value was specified in the Offset parameter.\n */\nNTSTATUS PhGetProcessPebString(\n    _In_ HANDLE ProcessHandle,\n    _In_ PH_PEB_OFFSET Offset,\n    _Out_ PPH_STRING *String\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n    ULONG offset;\n\n#define PEB_OFFSET_CASE(Enum, Field) \\\n    case Enum: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Field); break; \\\n    case Enum | PhpoWow64: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Field); break\n\n    switch (Offset)\n    {\n        PEB_OFFSET_CASE(PhpoCurrentDirectory, CurrentDirectory);\n        PEB_OFFSET_CASE(PhpoDllPath, DllPath);\n        PEB_OFFSET_CASE(PhpoImagePathName, ImagePathName);\n        PEB_OFFSET_CASE(PhpoCommandLine, CommandLine);\n        PEB_OFFSET_CASE(PhpoWindowTitle, WindowTitle);\n        PEB_OFFSET_CASE(PhpoDesktopInfo, DesktopInfo);\n        PEB_OFFSET_CASE(PhpoShellInfo, ShellInfo);\n        PEB_OFFSET_CASE(PhpoRuntimeData, RuntimeData);\n    default:\n        return STATUS_INVALID_PARAMETER_2;\n    }\n\n    if (!(Offset & PhpoWow64))\n    {\n        PVOID pebBaseAddress;\n        PVOID processParameters;\n        UNICODE_STRING unicodeString;\n\n        // Get the PEB address.\n        if (!NT_SUCCESS(status = PhGetProcessPeb(ProcessHandle, &pebBaseAddress)))\n            return status;\n\n        // Read the address of the process parameters.\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)),\n            &processParameters,\n            sizeof(PVOID),\n            NULL\n            )))\n            return status;\n\n        // Read the string structure.\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters, offset),\n            &unicodeString,\n            sizeof(UNICODE_STRING),\n            NULL\n            )))\n            return status;\n\n        if (RtlIsNullOrEmptyUnicodeString(&unicodeString))\n        {\n            *String = PhReferenceEmptyString();\n            return status;\n        }\n\n        string = PhCreateStringEx(NULL, unicodeString.Length);\n\n        // Read the string contents.\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            unicodeString.Buffer,\n            string->Buffer,\n            string->Length,\n            NULL\n            )))\n        {\n            PhDereferenceObject(string);\n            return status;\n        }\n    }\n    else\n    {\n        PVOID pebBaseAddress32;\n        ULONG processParameters32;\n        UNICODE_STRING32 unicodeString32;\n\n        if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &pebBaseAddress32)))\n            return status;\n\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress32, FIELD_OFFSET(PEB32, ProcessParameters)),\n            &processParameters32,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters32, offset),\n            &unicodeString32,\n            sizeof(UNICODE_STRING32),\n            NULL\n            )))\n            return status;\n\n        if (unicodeString32.Length == 0)\n        {\n            *String = PhReferenceEmptyString();\n            return status;\n        }\n\n        string = PhCreateStringEx(NULL, unicodeString32.Length);\n\n        // Read the string contents.\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            UlongToPtr(unicodeString32.Buffer),\n            string->Buffer,\n            string->Length,\n            NULL\n            )))\n        {\n            PhDereferenceObject(string);\n            return status;\n        }\n    }\n\n    *String = string;\n\n    return status;\n}\n\n/**\n * Gets a process' command line.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION. Before Windows 8.1, the handle must also have PROCESS_VM_READ\n * access.\n * \\param CommandLine A variable which receives a pointer to a string containing the command line. You\n * must free the string using PhDereferenceObject() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessCommandLine(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *CommandLine\n    )\n{\n    if (WindowsVersion >= WINDOWS_8_1)\n    {\n        NTSTATUS status;\n        PUNICODE_STRING buffer;\n        ULONG bufferLength;\n        ULONG returnLength = 0;\n\n        bufferLength = sizeof(UNICODE_STRING) + DOS_MAX_PATH_LENGTH * sizeof(WCHAR);\n        buffer = PhAllocateStack(bufferLength);\n        if (!buffer) return STATUS_NO_MEMORY;\n\n        status = NtQueryInformationProcess(\n            ProcessHandle,\n            ProcessCommandLineInformation,\n            buffer,\n            bufferLength,\n            &returnLength\n            );\n\n        if (status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFreeStack(buffer);\n            bufferLength = returnLength;\n            buffer = PhAllocateStack(bufferLength);\n            if (!buffer) return STATUS_NO_MEMORY;\n\n            status = NtQueryInformationProcess(\n                ProcessHandle,\n                ProcessCommandLineInformation,\n                buffer,\n                bufferLength,\n                &returnLength\n                );\n        }\n\n        if (NT_SUCCESS(status))\n        {\n            *CommandLine = PhCreateStringFromUnicodeString(buffer);\n        }\n\n        PhFreeStack(buffer);\n\n        return status;\n    }\n\n    return PhGetProcessPebString(ProcessHandle, PhpoCommandLine, CommandLine);\n}\n\n/**\n * Retrieves the command line string reference for the current process.\n *\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessCommandLineStringRef(\n    _Out_ PPH_STRINGREF CommandLine\n    )\n{\n    PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, CommandLine);\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves the current directory of a specified process.\n *\n * \\param ProcessHandle A handle to the process. The handle must have PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param IsWow64 Specifies whether to retrieve the current directory from the WOW64 PEB (TRUE) or the native PEB (FALSE).\n * \\param CurrentDirectory A variable which receives a pointer to a string containing the current directory.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessCurrentDirectory(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN IsWow64,\n    _Out_ PPH_STRING* CurrentDirectory\n    )\n{\n    return PhGetProcessPebString(ProcessHandle, PhpoCurrentDirectory | (IsWow64 ? PhpoWow64 : PhpoNone), CurrentDirectory);\n}\n\n/**\n * Retrieves the desktop information string for a specified process.\n *\n * \\param ProcessHandle A handle to the process. The handle must have PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param DesktopInfo A variable which receives a pointer to a string containing the desktop information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessDesktopInfo(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING* DesktopInfo\n    )\n{\n    return PhGetProcessPebString(ProcessHandle, PhpoDesktopInfo, DesktopInfo);\n}\n\n/**\n * Gets the window flags and window title of a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION. Before Windows 7 SP1, the handle must also have\n * PROCESS_VM_READ access.\n * \\param WindowFlags A variable which receives the window flags.\n * \\param WindowTitle A variable which receives a pointer to the window title. You must free the\n * string using PhDereferenceObject() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessWindowTitle(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG WindowFlags,\n    _Out_ PPH_STRING *WindowTitle\n    )\n{\n    NTSTATUS status;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n    ULONG windowFlags;\n    PPROCESS_WINDOW_INFORMATION windowInfo;\n    ULONG bufferLength;\n    ULONG returnLength = 0;\n\n    bufferLength = UFIELD_OFFSET(PROCESS_WINDOW_INFORMATION, WindowTitle[DOS_MAX_PATH_LENGTH]) + sizeof(UNICODE_NULL);\n    windowInfo = PhAllocate(bufferLength);\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessWindowInformation,\n        windowInfo,\n        bufferLength,\n        &returnLength\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(windowInfo);\n        bufferLength = returnLength;\n        windowInfo = PhAllocate(bufferLength);\n\n        status = NtQueryInformationProcess(\n            ProcessHandle,\n            ProcessWindowInformation,\n            windowInfo,\n            bufferLength,\n            &returnLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *WindowFlags = windowInfo->WindowFlags;\n        *WindowTitle = PhCreateStringEx(windowInfo->WindowTitle, windowInfo->WindowTitleLength);\n        PhFree(windowInfo);\n\n        return status;\n    }\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (!isWow64)\n#endif\n    {\n        PVOID pebBaseAddress;\n        PVOID processParameters;\n\n        // Get the PEB address.\n        if (!NT_SUCCESS(status = PhGetProcessPeb(ProcessHandle, &pebBaseAddress)))\n            return status;\n\n        // Read the address of the process parameters.\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)),\n            &processParameters,\n            sizeof(PVOID),\n            NULL\n            )))\n            return status;\n\n        // Read the window flags.\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, WindowFlags)),\n            &windowFlags,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n    }\n#ifdef _WIN64\n    else\n    {\n        PVOID pebBaseAddress32;\n        ULONG processParameters32;\n\n        if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &pebBaseAddress32)))\n            return status;\n\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress32, FIELD_OFFSET(PEB32, ProcessParameters)),\n            &processParameters32,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters32, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, WindowFlags)),\n            &windowFlags,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n    }\n#endif\n\n#ifdef _WIN64\n    status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle | (isWow64 ? PhpoWow64 : PhpoNone), WindowTitle);\n#else\n    status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle, WindowTitle);\n#endif\n\n    if (NT_SUCCESS(status))\n        *WindowFlags = windowFlags;\n\n    return status;\n}\n\n/**\n * Retrieves the Data Execution Prevention (DEP) status for a specified process.\n *\n * \\param ProcessHandle Handle to the process whose DEP status is to be queried.\n * \\param DepStatus Pointer to a variable that receives the DEP status flags.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessDepStatus(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG DepStatus\n    )\n{\n    NTSTATUS status;\n    ULONG executeFlags;\n    ULONG depStatus;\n\n    if (!NT_SUCCESS(status = PhGetProcessExecuteFlags(\n        ProcessHandle,\n        &executeFlags\n        )))\n        return status;\n\n    // Check if execution of data pages is enabled.\n    // TODO: if we want real, effective DEP status here as computed by nt!MiCanGrantExecute (x64 oskernels):\n    // canGrantExecEvenForNxPages = (EPROCESS.WoW64Process && EPROCESS.Machine == IMAGE_FILE_MACHINE_I386)\n    //     && (KF_GLOBAL_32BIT_EXECUTE || MEM_EXECUTE_OPTION_ENABLE\n    //         || (!KF_GLOBAL_32BIT_NOEXECUTE && !MEM_EXECUTE_OPTION_DISABLE));\n    if (executeFlags & MEM_EXECUTE_OPTION_DISABLE)\n        depStatus = PH_PROCESS_DEP_ENABLED;\n    else\n        depStatus = 0;\n\n    if (executeFlags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)\n        depStatus |= PH_PROCESS_DEP_ATL_THUNK_EMULATION_DISABLED;\n    if (executeFlags & MEM_EXECUTE_OPTION_PERMANENT)\n        depStatus |= PH_PROCESS_DEP_PERMANENT;\n\n    *DepStatus = depStatus;\n\n    return status;\n}\n\n/**\n * Gets a process' environment block.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION and\n * PROCESS_VM_READ access.\n * \\param IsWow64Process A variable which receives a boolean indicating whether the process is 32-bit.\n * \\li \\c PH_GET_PROCESS_ENVIRONMENT_WOW64 Retrieve the environment block from the WOW64 PEB.\n * \\param Environment A variable which will receive a pointer to the environment block copied from\n * the process. You must free the block using PhFreePage() when you no longer need it.\n * \\param EnvironmentLength A variable which will receive the length of the environment block, in bytes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessEnvironment(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN IsWow64Process,\n    _Out_ PVOID *Environment,\n    _Out_ PULONG EnvironmentLength\n    )\n{\n    NTSTATUS status;\n    PVOID environmentRemote;\n    MEMORY_BASIC_INFORMATION basicInfo;\n    PVOID environment;\n    SIZE_T environmentLength;\n    ULONG_PTR environmenOffset;\n\n    if (IsWow64Process)\n    {\n        PVOID pebBaseAddress32;\n        ULONG processParameters32;\n        ULONG environmentRemote32;\n\n        status = PhGetProcessPeb32(ProcessHandle, &pebBaseAddress32);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress32, UFIELD_OFFSET(PEB32, ProcessParameters)),\n            &processParameters32,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters32, UFIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Environment)),\n            &environmentRemote32,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n\n        environmentRemote = UlongToPtr(environmentRemote32);\n    }\n    else\n    {\n        PVOID pebBaseAddress;\n        PVOID processParameters;\n\n        status = PhGetProcessPeb(ProcessHandle, &pebBaseAddress);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB, ProcessParameters)),\n            &processParameters,\n            sizeof(PVOID),\n            NULL\n            )))\n            return status;\n\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters, UFIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment)),\n            &environmentRemote,\n            sizeof(PVOID),\n            NULL\n            )))\n            return status;\n    }\n\n    if (!NT_SUCCESS(status = NtQueryVirtualMemory(\n        ProcessHandle,\n        environmentRemote,\n        MemoryBasicInformation,\n        &basicInfo,\n        sizeof(MEMORY_BASIC_INFORMATION),\n        NULL\n        )))\n        return status;\n\n    // Read in the entire region of memory.\n\n#if defined(PH_NATIVE_ENVCHECK)\n\n    environmentLength = (SIZE_T)PTR_SUB_OFFSET(mbi.RegionSize,\n        PTR_SUB_OFFSET(environmentRemote, mbi.BaseAddress));\n\n#else\n\n    // Check environment address is valid for the region. (dmex)\n\n    status = RtlULongPtrSub(\n        (ULONG_PTR)environmentRemote,\n        (ULONG_PTR)basicInfo.BaseAddress,\n        &environmenOffset\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (environmenOffset > (ULONG_PTR)basicInfo.RegionSize)\n        return STATUS_FAIL_CHECK;\n\n    status = RtlSizeTSub(\n        (SIZE_T)basicInfo.RegionSize,\n        (SIZE_T)environmenOffset,\n        &environmentLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n#endif\n\n    environment = PhAllocatePage(environmentLength, NULL);\n\n    if (!environment)\n        return STATUS_NO_MEMORY;\n\n    if (!NT_SUCCESS(status = PhReadVirtualMemory(\n        ProcessHandle,\n        environmentRemote,\n        environment,\n        environmentLength,\n        NULL\n        )))\n    {\n        PhFreePage(environment);\n        return status;\n    }\n\n    *Environment = environment;\n\n    if (EnvironmentLength)\n        *EnvironmentLength = (ULONG)environmentLength;\n\n    return status;\n}\n\n/**\n * Gets the file name of a mapped section.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param BaseAddress The base address of the section view.\n * \\param FileName A variable which receives a pointer to a string containing the file name of the\n * section. You must free the string using PhDereferenceObject() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessMappedFileName(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    SIZE_T bufferSize;\n    SIZE_T returnLength;\n    PUNICODE_STRING buffer;\n\n    returnLength = 0;\n    bufferSize = 0x200;\n    buffer = PhAllocateStack(bufferSize);\n    if (!buffer) return STATUS_NO_MEMORY;\n\n    status = NtQueryVirtualMemory(\n        ProcessHandle,\n        BaseAddress,\n        MemoryMappedFilenameInformation,\n        buffer,\n        bufferSize,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW && returnLength > 0) // returnLength > 0 required for MemoryMappedFilename on Windows 7 SP1 (dmex)\n    {\n        PhFreeStack(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocateStack(bufferSize);\n        if (!buffer) return STATUS_NO_MEMORY;\n\n        status = NtQueryVirtualMemory(\n            ProcessHandle,\n            BaseAddress,\n            MemoryMappedFilenameInformation,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFreeStack(buffer);\n        return status;\n    }\n\n    *FileName = PhCreateStringFromUnicodeString(buffer);\n    PhFreeStack(buffer);\n\n    return status;\n}\n\n/**\n * Retrieves information about a mapped image in the virtual memory of a process.\n *\n * \\param ProcessHandle Handle to the process whose memory is being queried.\n * \\param BaseAddress Base address of the mapped image in the process's virtual memory.\n * \\param ImageInformation Pointer to a MEMORY_IMAGE_INFORMATION structure that receives the image information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessMappedImageInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_ PMEMORY_IMAGE_INFORMATION ImageInformation\n    )\n{\n    NTSTATUS status;\n    MEMORY_IMAGE_INFORMATION imageInformation;\n\n    status = NtQueryVirtualMemory(\n        ProcessHandle,\n        BaseAddress,\n        MemoryImageInformation,\n        &imageInformation,\n        sizeof(MEMORY_IMAGE_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ImageInformation = imageInformation;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the base address and optional size of a mapped image in a process, given an address within the image.\n *\n * This function queries the process for image mapping information at the specified address.\n * If the address is valid and corresponds to an executable image, the base address and size\n * (if requested) are returned. Otherwise, an unsuccessful status is returned.\n *\n * \\param ProcessHandle Handle to the target process.\n * \\param Address Address within the mapped image in the target process.\n * \\param ImageBaseAddress Receives the base address of the mapped image.\n * \\param SizeOfImage Optional pointer to receive the size of the mapped image.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessMappedImageBaseFromAddress(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID Address,\n    _Out_ PVOID* ImageBaseAddress,\n    _Out_opt_ PSIZE_T SizeOfImage\n    )\n{\n    NTSTATUS status;\n    MEMORY_IMAGE_INFORMATION imageInfo;\n\n    status = PhGetProcessMappedImageInformation(\n        ProcessHandle,\n        Address,\n        &imageInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!imageInfo.ImageBase || imageInfo.ImageNotExecutable || imageInfo.ImagePartialMap)\n        return STATUS_UNSUCCESSFUL;\n    if (Address < imageInfo.ImageBase || (imageInfo.SizeOfImage && ((ULONG_PTR)Address >= (ULONG_PTR)imageInfo.ImageBase + imageInfo.SizeOfImage)))\n        return STATUS_UNSUCCESSFUL;\n\n    *ImageBaseAddress = imageInfo.ImageBase;\n\n    if (SizeOfImage)\n    {\n        *SizeOfImage = imageInfo.SizeOfImage;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Gets working set information for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param WorkingSetInformation A variable which receives a pointer to the information. You must\n * free the buffer using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessWorkingSetInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PMEMORY_WORKING_SET_INFORMATION *WorkingSetInformation\n    )\n{\n    NTSTATUS status;\n    PMEMORY_WORKING_SET_INFORMATION buffer;\n    SIZE_T bufferSize;\n    ULONG attempts = 0;\n\n    bufferSize = 0x8000;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQueryVirtualMemory(\n        ProcessHandle,\n        NULL,\n        MemoryWorkingSetInformation,\n        buffer,\n        bufferSize,\n        NULL\n        );\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)\n    {\n        bufferSize = UFIELD_OFFSET(MEMORY_WORKING_SET_INFORMATION, WorkingSetInfo[buffer->NumberOfEntries]);\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQueryVirtualMemory(\n            ProcessHandle,\n            NULL,\n            MemoryWorkingSetInformation,\n            buffer,\n            bufferSize,\n            NULL\n            );\n\n        attempts++;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        // Fall back to using the previous code that we've used since Windows 7 (dmex)\n        bufferSize = 0x8000;\n        buffer = PhAllocate(bufferSize);\n\n        while ((status = NtQueryVirtualMemory(\n            ProcessHandle,\n            NULL,\n            MemoryWorkingSetInformation,\n            buffer,\n            bufferSize,\n            NULL\n            )) == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n\n            // Fail if we're resizing the buffer to something very large.\n            if (bufferSize > PH_LARGE_BUFFER_SIZE)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            buffer = PhAllocate(bufferSize);\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *WorkingSetInformation = (PMEMORY_WORKING_SET_INFORMATION)buffer;\n\n    return status;\n}\n\n/**\n * Gets working set counters for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param WsCounters A variable which receives the counters.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessWsCounters(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_WS_COUNTERS WsCounters\n    )\n{\n    NTSTATUS status;\n    PMEMORY_WORKING_SET_INFORMATION wsInfo;\n    PH_PROCESS_WS_COUNTERS wsCounters;\n    ULONG_PTR i;\n\n    if (!NT_SUCCESS(status = PhGetProcessWorkingSetInformation(\n        ProcessHandle,\n        &wsInfo\n        )))\n        return status;\n\n    memset(&wsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS));\n\n    for (i = 0; i < wsInfo->NumberOfEntries; i++)\n    {\n        wsCounters.NumberOfPages++;\n\n        if (wsInfo->WorkingSetInfo[i].ShareCount > 1)\n            wsCounters.NumberOfSharedPages++;\n        if (wsInfo->WorkingSetInfo[i].ShareCount == 0)\n            wsCounters.NumberOfPrivatePages++;\n        if (wsInfo->WorkingSetInfo[i].Shared)\n            wsCounters.NumberOfShareablePages++;\n    }\n\n    PhFree(wsInfo);\n\n    *WsCounters = wsCounters;\n\n    return status;\n}\n\n/**\n * Retrieves the mandatory integrity policy for a specified process.\n *\n * \\param ProcessHandle A handle to the process whose mandatory policy is to be queried.\n * \\param Mask A pointer to an ACCESS_MASK variable that receives the mandatory policy mask.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessMandatoryPolicy(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PACCESS_MASK Mask\n    )\n{\n    NTSTATUS status;\n    BOOLEAN found = FALSE;\n    ACCESS_MASK currentMask = 0;\n    PSYSTEM_MANDATORY_LABEL_ACE currentAce;\n    PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n    BOOLEAN currentSaclPresent;\n    BOOLEAN currentSaclDefaulted;\n    PACL currentSacl;\n\n    status = PhGetObjectSecurity(\n        ProcessHandle,\n        LABEL_SECURITY_INFORMATION,\n        &currentSecurityDescriptor\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetSaclSecurityDescriptor(\n        currentSecurityDescriptor,\n        &currentSaclPresent,\n        &currentSacl,\n        &currentSaclDefaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (!(currentSaclPresent && currentSacl))\n        goto CleanupExit;\n\n    for (USHORT i = 0; i < currentSacl->AceCount; i++)\n    {\n        status = PhGetAce(currentSacl, i, &currentAce);\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        if (currentAce->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE)\n        {\n            currentMask = currentAce->Mask;\n            found = TRUE;\n            break;\n        }\n    }\n\nCleanupExit:\n    PhFree(currentSecurityDescriptor);\n\n    if (NT_SUCCESS(status))\n    {\n        if (found)\n        {\n            *Mask = currentMask;\n            status = STATUS_SUCCESS;\n        }\n        else\n        {\n            status = STATUS_NOT_FOUND;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Sets the mandatory label policy for a specified process.\n *\n * \\param ProcessHandle Handle to the target process.\n * \\param Mask Mandatory label policy mask to apply.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessMandatoryPolicy(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK Mask\n    )\n{\n    NTSTATUS status;\n    PSYSTEM_MANDATORY_LABEL_ACE currentAce;\n    PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n    BOOLEAN currentSaclPresent;\n    BOOLEAN currentSaclDefaulted;\n    PACL currentSacl;\n\n    status = PhGetObjectSecurity(\n        ProcessHandle,\n        LABEL_SECURITY_INFORMATION,\n        &currentSecurityDescriptor\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetSaclSecurityDescriptor(\n        currentSecurityDescriptor,\n        &currentSaclPresent,\n        &currentSacl,\n        &currentSaclDefaulted\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = STATUS_UNSUCCESSFUL;\n\n    if (!(currentSaclPresent && currentSacl))\n        goto CleanupExit;\n\n    for (USHORT i = 0; i < currentSacl->AceCount; i++)\n    {\n        status = PhGetAce(currentSacl, i, &currentAce);\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        if (currentAce->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE)\n        {\n            currentAce->Mask = Mask;\n\n            status = PhSetObjectSecurity(\n                ProcessHandle,\n                LABEL_SECURITY_INFORMATION,\n                currentSecurityDescriptor\n                );\n            break;\n        }\n    }\n\nCleanupExit:\n    PhFree(currentSecurityDescriptor);\n\n    return status;\n}\n\n/**\n * Retrieves the quota limits for a specified process.\n *\n * \\param ProcessHandle Handle to the process whose quota limits are to be queried.\n * \\param QuotaLimits Pointer to a QUOTA_LIMITS structure that receives the quota limits.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessQuotaLimits(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PQUOTA_LIMITS QuotaLimits\n    )\n{\n    NTSTATUS status;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessQuotaLimits,\n        QuotaLimits,\n        sizeof(QUOTA_LIMITS),\n        NULL\n        );\n\n    // Not implemented (dmex)\n    //if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    //{\n    //    status = KphQueryInformationProcess(\n    //        ProcessHandle,\n    //        KphProcessQuotaLimits,\n    //        QuotaLimits,\n    //        sizeof(QUOTA_LIMITS),\n    //        NULL\n    //        );\n    //}\n\n    return status;\n}\n\n/**\n * Sets the quota limits for a specified process.\n *\n * \\param ProcessHandle A handle to the process whose quota limits are to be set.\n * \\param QuotaLimits The quota limits to apply to the process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessQuotaLimits(\n    _In_ HANDLE ProcessHandle,\n    _In_ QUOTA_LIMITS QuotaLimits\n    )\n{\n    NTSTATUS status;\n\n    status = NtSetInformationProcess(\n        ProcessHandle,\n        ProcessQuotaLimits,\n        &QuotaLimits,\n        sizeof(QUOTA_LIMITS)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationProcess(\n            ProcessHandle,\n            KphProcessQuotaLimits,\n            &QuotaLimits,\n            sizeof(QUOTA_LIMITS)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Attempts to empty the working set of the specified process.\n *\n * \\param ProcessHandle A handle to the process whose working set should be emptied.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessEmptyWorkingSet(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    QUOTA_LIMITS_EX quotaLimits;\n\n    memset(&quotaLimits, 0, sizeof(QUOTA_LIMITS_EX));\n    quotaLimits.MinimumWorkingSetSize = SIZE_MAX;\n    quotaLimits.MaximumWorkingSetSize = SIZE_MAX;\n\n    status = NtSetInformationProcess(\n        ProcessHandle,\n        ProcessQuotaLimits,\n        &quotaLimits,\n        sizeof(QUOTA_LIMITS_EX)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationProcess(\n            ProcessHandle,\n            KphProcessEmptyWorkingSet,\n            &quotaLimits,\n            sizeof(QUOTA_LIMITS_EX)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Empties the working set of the specified process.\n *\n * \\param ProcessHandle A handle to the process whose working set should be emptied.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessWorkingSetEmpty(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    PROCESS_WORKING_SET_CONTROL controlInfo;\n\n    memset(&controlInfo, 0, sizeof(PROCESS_WORKING_SET_CONTROL));\n    controlInfo.Version = PROCESS_WORKING_SET_CONTROL_VERSION;\n    controlInfo.Operation = ProcessWorkingSetEmpty;\n    controlInfo.Flags = PROCESS_WORKING_SET_FLAG_EMPTY_PAGES;\n\n    status = NtSetInformationProcess(\n        ProcessHandle,\n        ProcessWorkingSetControl,\n        &controlInfo,\n        sizeof(PROCESS_WORKING_SET_CONTROL)\n        );\n\n    return status;\n}\n\n/**\n * Sets the specified region of a process's working set to empty pages.\n *\n * \\param ProcessHandle Handle to the target process.\n * \\param BaseAddress Pointer to the base address of the region to modify.\n * \\param Size Size, in bytes, of the region to modify.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessEmptyPageWorkingSet(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T Size\n    )\n{\n    NTSTATUS status;\n    PVOID baseAddress;\n    SIZE_T regionSize;\n\n    baseAddress = BaseAddress;\n    regionSize = Size;\n\n    // Calling VirtualUnlock on a range of memory that is not locked\n    // releases the pages from the process's working set. (MSDN)\n\n    status = NtUnlockVirtualMemory(\n        ProcessHandle,\n        &baseAddress,\n        &regionSize,\n        MAP_PROCESS\n        );\n\n    // Note: STATUS_SUCCESS is a bad status in this case. (dmex)\n    assert(status == STATUS_NOT_LOCKED);\n\n    if (status == STATUS_NOT_LOCKED)\n        status = STATUS_SUCCESS;\n\n    return status;\n}\n\n/**\n * Retrieves the priority class of a specified process.\n *\n * \\param ProcessHandle Handle to the process whose priority class is to be retrieved.\n * \\param PriorityClass Pointer to a variable that receives the priority class value.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessPriorityClass(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PUCHAR PriorityClass\n    )\n{\n    NTSTATUS status;\n    PROCESS_PRIORITY_CLASS processPriorityClass;\n\n    memset(&processPriorityClass, 0, sizeof(PROCESS_PRIORITY_CLASS));\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessPriorityClass,\n        &processPriorityClass,\n        sizeof(PROCESS_PRIORITY_CLASS),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PriorityClass = processPriorityClass.PriorityClass;\n    }\n\n    return status;\n}\n\n/**\n * Sets the priority class of a process.\n *\n * \\param ProcessHandle A handle to the process whose priority class is to be set.\n * \\param PriorityClass The priority class value to assign to the process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessPriorityClass(\n    _In_ HANDLE ProcessHandle,\n    _In_ UCHAR PriorityClass\n    )\n{\n    NTSTATUS status;\n\n    if (WindowsVersion >= WINDOWS_11_22H2)\n    {\n        PROCESS_PRIORITY_CLASS_EX processPriorityClassEx;\n\n        memset(&processPriorityClassEx, 0, sizeof(PROCESS_PRIORITY_CLASS_EX));\n        processPriorityClassEx.PriorityClassValid = TRUE;\n        processPriorityClassEx.PriorityClass = PriorityClass;\n\n        status = NtSetInformationProcess(\n            ProcessHandle,\n            ProcessPriorityClassEx,\n            &processPriorityClassEx,\n            sizeof(PROCESS_PRIORITY_CLASS_EX)\n            );\n\n        if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n        {\n            status = KphSetInformationProcess(\n                ProcessHandle,\n                KphProcessPriorityClassEx,\n                &processPriorityClassEx,\n                sizeof(PROCESS_PRIORITY_CLASS_EX)\n                );\n        }\n    }\n    else\n    {\n        PROCESS_PRIORITY_CLASS processPriorityClass;\n\n        memset(&processPriorityClass, 0, sizeof(PROCESS_PRIORITY_CLASS));\n        processPriorityClass.Foreground = FALSE;\n        processPriorityClass.PriorityClass = PriorityClass;\n\n        status = NtSetInformationProcess(\n            ProcessHandle,\n            ProcessPriorityClass,\n            &processPriorityClass,\n            sizeof(PROCESS_PRIORITY_CLASS)\n            );\n\n        if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n        {\n            status = KphSetInformationProcess(\n                ProcessHandle,\n                KphProcessPriorityClass,\n                &processPriorityClass,\n                sizeof(PROCESS_PRIORITY_CLASS)\n                );\n        }\n    }\n\n    return status;\n}\n\n/**\n * Sets a process' I/O priority.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_SET_INFORMATION access.\n * \\param IoPriority The new I/O priority.\n */\nNTSTATUS PhSetProcessIoPriority(\n    _In_ HANDLE ProcessHandle,\n    _In_ IO_PRIORITY_HINT IoPriority\n    )\n{\n    NTSTATUS status;\n\n    status = NtSetInformationProcess(\n        ProcessHandle,\n        ProcessIoPriority,\n        &IoPriority,\n        sizeof(IO_PRIORITY_HINT)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationProcess(\n            ProcessHandle,\n            KphProcessIoPriority,\n            &IoPriority,\n            sizeof(IO_PRIORITY_HINT)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Sets the page priority for the specified process.\n *\n * \\param ProcessHandle Handle to the process whose page priority is to be set.\n * \\param PagePriority The desired page priority value.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessPagePriority(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG PagePriority\n    )\n{\n    // See also PhSetVirtualMemoryPagePriority (dmex)\n    NTSTATUS status;\n    PAGE_PRIORITY_INFORMATION pagePriorityInfo;\n\n    pagePriorityInfo.PagePriority = PagePriority;\n\n    status = NtSetInformationProcess(\n        ProcessHandle,\n        ProcessPagePriority,\n        &pagePriorityInfo,\n        sizeof(PAGE_PRIORITY_INFORMATION)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationProcess(\n            ProcessHandle,\n            KphProcessPagePriority,\n            &pagePriorityInfo,\n            sizeof(PAGE_PRIORITY_INFORMATION)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Sets the priority boost for a specified process.\n *\n * \\param ProcessHandle Handle to the process whose priority boost setting is to be changed.\n * \\param DisablePriorityBoost If TRUE, disables priority boost for the process; if FALSE, enables it.\n * \\return NTSTATUS code indicating success or failure of the operation.\n */\nNTSTATUS PhSetProcessPriorityBoost(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN DisablePriorityBoost\n    )\n{\n    NTSTATUS status;\n    ULONG priorityBoost;\n\n    priorityBoost = DisablePriorityBoost ? 1 : 0;\n\n    status = NtSetInformationProcess(\n        ProcessHandle,\n        ProcessPriorityBoost,\n        &priorityBoost,\n        sizeof(ULONG)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationProcess(\n            ProcessHandle,\n            KphProcessPriorityBoost,\n            &priorityBoost,\n            sizeof(ULONG)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the activity moderation state for a process based on the specified moderation identifier.\n *\n * \\param processId The identifier of the process to query.\n * \\param moderationId The moderation identifier to check.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessActivityModerationState(\n    _In_ PCPH_STRINGREF ModerationIdentifier,\n    _Out_ PSYSTEM_ACTIVITY_MODERATION_APP_SETTINGS ModerationSettings\n    )\n{\n    NTSTATUS status;\n    SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS activityModeration;\n    PKEY_VALUE_PARTIAL_INFORMATION keyValueInfo = NULL;\n\n    RtlZeroMemory(&activityModeration, sizeof(SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS));\n\n    status = NtQuerySystemInformation(\n        SystemActivityModerationUserSettings,\n        &activityModeration,\n        sizeof(SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhQueryValueKey(\n        activityModeration.UserKeyHandle,\n        ModerationIdentifier,\n        KeyValuePartialInformation,\n        &keyValueInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (\n        keyValueInfo->Type != REG_BINARY ||\n        keyValueInfo->DataLength != sizeof(SYSTEM_ACTIVITY_MODERATION_APP_SETTINGS)\n        )\n    {\n        status = STATUS_INVALID_KERNEL_INFO_VERSION;\n    }\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    RtlCopyMemory(\n        ModerationSettings,\n        keyValueInfo->Data,\n        sizeof(SYSTEM_ACTIVITY_MODERATION_APP_SETTINGS)\n        );\n\nCleanupExit:\n    if (activityModeration.UserKeyHandle)\n    {\n        NtClose(activityModeration.UserKeyHandle);\n    }\n    if (keyValueInfo)\n    {\n        PhFree(keyValueInfo);\n    }\n\n    return status;\n}\n\n/**\n * Sets the activity moderation state for a process.\n *\n * \\param ModerationIdentifier A pointer to a PH_STRINGREF structure that identifies the moderation context.\n * \\param ModerationType The type of activity moderation to apply (SYSTEM_ACTIVITY_MODERATION_APP_TYPE).\n * \\param ModerationState The desired moderation state (SYSTEM_ACTIVITY_MODERATION_STATE).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessActivityModerationState(\n    _In_ PCPH_STRINGREF ModerationIdentifier,\n    _In_ SYSTEM_ACTIVITY_MODERATION_APP_TYPE ModerationType,\n    _In_ SYSTEM_ACTIVITY_MODERATION_STATE ModerationState\n    )\n{\n    NTSTATUS status;\n    SYSTEM_ACTIVITY_MODERATION_INFO moderationInfo;\n\n    RtlZeroMemory(&moderationInfo, sizeof(SYSTEM_ACTIVITY_MODERATION_INFO));\n    moderationInfo.AppType = ModerationType;\n    moderationInfo.ModerationState = ModerationState;\n\n    if (!PhStringRefToUnicodeString(ModerationIdentifier, &moderationInfo.Identifier))\n        return STATUS_NAME_TOO_LONG;\n\n    status = NtSetSystemInformation(\n        SystemActivityModerationExeState,\n        &moderationInfo,\n        sizeof(SYSTEM_ACTIVITY_MODERATION_INFO)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS activityModeration;\n\n        RtlZeroMemory(&activityModeration, sizeof(SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS));\n\n        status = NtQuerySystemInformation(\n            SystemActivityModerationUserSettings,\n            &activityModeration,\n            sizeof(SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS),\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            SYSTEM_ACTIVITY_MODERATION_APP_SETTINGS moderationSettings;\n\n            RtlZeroMemory(&moderationSettings, sizeof(SYSTEM_ACTIVITY_MODERATION_APP_SETTINGS));\n            PhQuerySystemTime(&moderationSettings.LastUpdatedTime);\n            moderationSettings.AppType = ModerationType;\n            moderationSettings.ModerationState = ModerationState;\n\n            status = PhSetValueKey(\n                activityModeration.UserKeyHandle,\n                ModerationIdentifier,\n                REG_BINARY,\n                &moderationSettings,\n                sizeof(SYSTEM_ACTIVITY_MODERATION_APP_SETTINGS)\n                );\n\n            NtClose(activityModeration.UserKeyHandle);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Sets a process' affinity mask.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_SET_INFORMATION access.\n * \\param AffinityMask The new affinity mask.\n */\nNTSTATUS PhSetProcessAffinityMask(\n    _In_ HANDLE ProcessHandle,\n    _In_ KAFFINITY AffinityMask\n    )\n{\n    NTSTATUS status;\n\n    status = NtSetInformationProcess(\n        ProcessHandle,\n        ProcessAffinityMask,\n        &AffinityMask,\n        sizeof(KAFFINITY)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationProcess(\n            ProcessHandle,\n            KphProcessAffinityMask,\n            &AffinityMask,\n            sizeof(KAFFINITY)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Sets the processor group affinity for a specified process.\n *\n * \\param ProcessHandle Handle to the process whose group affinity is to be set.\n * \\param GroupAffinity The GROUP_AFFINITY structure specifying the desired processor group and affinity mask.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessGroupAffinity(\n    _In_ HANDLE ProcessHandle,\n    _In_ GROUP_AFFINITY GroupAffinity\n    )\n{\n    NTSTATUS status;\n\n    status = NtSetInformationProcess(\n        ProcessHandle,\n        ProcessAffinityMask,\n        &GroupAffinity,\n        sizeof(GROUP_AFFINITY)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationProcess(\n            ProcessHandle,\n            KphProcessAffinityMask,\n            &GroupAffinity,\n            sizeof(GROUP_AFFINITY)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Query the power throttling state for a specified process.\n *\n * \\param ProcessHandle The handle to the target process.\n * \\param PowerThrottlingState The control and state masks indicating the current power throttling of the process.\n * \\return The NTSTATUS code indicating the success or failure of the operation.\n */\nNTSTATUS PhGetProcessPowerThrottlingState(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPOWER_THROTTLING_PROCESS_STATE PowerThrottlingState\n    )\n{\n    NTSTATUS status;\n\n    memset(PowerThrottlingState, 0, sizeof(POWER_THROTTLING_PROCESS_STATE));\n    PowerThrottlingState->Version = POWER_THROTTLING_PROCESS_CURRENT_VERSION;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessPowerThrottlingState,\n        PowerThrottlingState,\n        sizeof(POWER_THROTTLING_PROCESS_STATE),\n        NULL\n        );\n\n    return status;\n}\n\n/**\n * Sets the power throttling state for a specified process.\n *\n * \\param ProcessHandle The handle to the target process.\n * \\param ControlMask The control mask specifying the power throttling control actions to perform.\n * \\param StateMask The state mask specifying the power throttling states to set.\n * \\return The NTSTATUS code indicating the success or failure of the operation.\n */\nNTSTATUS PhSetProcessPowerThrottlingState(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG ControlMask,\n    _In_ ULONG StateMask\n    )\n{\n    NTSTATUS status;\n    POWER_THROTTLING_PROCESS_STATE powerThrottlingState;\n\n    memset(&powerThrottlingState, 0, sizeof(POWER_THROTTLING_PROCESS_STATE));\n    powerThrottlingState.Version = POWER_THROTTLING_PROCESS_CURRENT_VERSION;\n    powerThrottlingState.ControlMask = ControlMask;\n    powerThrottlingState.StateMask = StateMask;\n\n    status = NtSetInformationProcess(\n        ProcessHandle,\n        ProcessPowerThrottlingState,\n        &powerThrottlingState,\n        sizeof(POWER_THROTTLING_PROCESS_STATE)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationProcess(\n            ProcessHandle,\n            KphProcessPowerThrottlingState,\n            &powerThrottlingState,\n            sizeof(POWER_THROTTLING_PROCESS_STATE)\n            );\n    }\n\n    return status;\n}\n\n// rev from KernelBase!QueryProcessMachine (jxy-s)\n/**\n * Retrieves the architecture of the specified process.\n *\n * \\param ProcessHandle A handle to the process whose architecture is to be determined.\n * \\param ProcessArchitecture A pointer to a variable that receives the process architecture.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessArchitecture(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PUSHORT ProcessArchitecture\n    )\n{\n    NTSTATUS status;\n    HANDLE input[1] = { ProcessHandle };\n    SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION output[6];\n    ULONG returnLength;\n\n    status = NtQuerySystemInformationEx(\n        SystemSupportedProcessorArchitectures2,\n        input,\n        sizeof(input),\n        output,\n        sizeof(output),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        for (ULONG i = 0; i < returnLength / sizeof(SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION); i++)\n        {\n            if (output[i].Process)\n            {\n                *ProcessArchitecture = (USHORT)output[i].Machine;\n                return STATUS_SUCCESS;\n            }\n        }\n\n        status = STATUS_NOT_FOUND;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the base address of the image for a specified process.\n *\n * \\param ProcessHandle A handle to the process whose image base address is to be retrieved.\n * \\param ImageBaseAddress A pointer that receives the image base address of the process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessImageBaseAddress(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID* ImageBaseAddress\n    )\n{\n    NTSTATUS status;\n    PVOID pebAddress;\n    PVOID baseAddress;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        ULONG imageBaseAddress32;\n\n        status = PhGetProcessPeb32(ProcessHandle, &pebAddress);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebAddress, UFIELD_OFFSET(PEB32, ImageBaseAddress)),\n            &imageBaseAddress32,\n            sizeof(ULONG),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        baseAddress = UlongToPtr(imageBaseAddress32);\n    }\n    else\n#endif\n    {\n        PVOID imageBaseAddress;\n\n        status = PhGetProcessPeb(ProcessHandle, &pebAddress);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebAddress, UFIELD_OFFSET(PEB, ImageBaseAddress)),\n            &imageBaseAddress,\n            sizeof(PVOID),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        baseAddress = imageBaseAddress;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *ImageBaseAddress = baseAddress;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the security domain identifier for a specified process.\n *\n * \\param ProcessHandle A handle to the process whose security domain is to be retrieved.\n * \\param SecurityDomain A pointer to a variable that receives the security domain identifier.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessSecurityDomain(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONGLONG SecurityDomain\n    )\n{\n    NTSTATUS status;\n    PROCESS_SECURITY_DOMAIN_INFORMATION processSecurityDomainInfo;\n\n    memset(&processSecurityDomainInfo, 0, sizeof(PROCESS_SECURITY_DOMAIN_INFORMATION));\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessSecurityDomainInformation,\n        &processSecurityDomainInfo,\n        sizeof(PROCESS_SECURITY_DOMAIN_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *SecurityDomain = processSecurityDomainInfo.SecurityDomain;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the Server Silo identifier for a specified process.\n *\n * \\param ProcessHandle A handle to the process for which the Server Silo information is to be retrieved.\n * \\param ServerSilo A pointer to a variable that receives the Server Silo identifier.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessServerSilo(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ServerSilo\n    )\n{\n    NTSTATUS status;\n    PROCESS_MEMBERSHIP_INFORMATION processMembershipInfo;\n\n    memset(&processMembershipInfo, 0, sizeof(PROCESS_MEMBERSHIP_INFORMATION));\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessMembershipInformation,\n        &processMembershipInfo,\n        sizeof(PROCESS_MEMBERSHIP_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ServerSilo = processMembershipInfo.ServerSiloId;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the sequence number of a process.\n *\n * \\param ProcessHandle A handle to the process whose sequence number is to be retrieved.\n * \\param SequenceNumber A pointer to a variable that receives the process sequence number.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessSequenceNumber(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONGLONG SequenceNumber\n    )\n{\n    NTSTATUS status;\n\n    if (KsiLevel() >= KphLevelLow)\n    {\n        // The driver exposes this information earlier than ProcessSequenceNumber was introduced.\n        // Where not available it synthesizes it for informer messages, for consistency use it if\n        // it's enabled.\n        status = KphQueryInformationProcess(\n            ProcessHandle,\n            KphProcessSequenceNumber,\n            SequenceNumber,\n            sizeof(ULONGLONG),\n            NULL\n            );\n    }\n    else\n    {\n        ULONGLONG sequenceNumber = 0;\n\n        status = NtQueryInformationProcess(\n            ProcessHandle,\n            ProcessSequenceNumber,\n            &sequenceNumber,\n            sizeof(ULONGLONG),\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            *SequenceNumber = sequenceNumber;\n        }\n        else if (status == STATUS_INVALID_INFO_CLASS && WindowsVersion >= WINDOWS_10)\n        {\n            PROCESS_TELEMETRY_ID_INFORMATION telemetryInfo;\n\n            memset(&telemetryInfo, 0, sizeof(PROCESS_TELEMETRY_ID_INFORMATION));\n\n            // ProcessTelemetryIdInformation exposes the process sequence number (and process start\n            // key) earlier than ProcessSequenceNumber was introduced.\n            status = NtQueryInformationProcess(\n                ProcessHandle,\n                ProcessTelemetryIdInformation,\n                &telemetryInfo,\n                sizeof(PROCESS_TELEMETRY_ID_INFORMATION),\n                NULL\n                );\n\n            if (\n                status == STATUS_BUFFER_OVERFLOW &&\n                RTL_CONTAINS_FIELD(&telemetryInfo, telemetryInfo.HeaderSize, ProcessSequenceNumber)\n                )\n            {\n                status = STATUS_SUCCESS;\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                *SequenceNumber = telemetryInfo.ProcessSequenceNumber;\n            }\n        }\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the unique start key for a specified process.\n *\n * \\param ProcessHandle Handle to the process whose start key is to be retrieved.\n * \\param ProcessStartKey Pointer to a variable that receives the process start key.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessStartKey(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONGLONG ProcessStartKey\n    )\n{\n    NTSTATUS status;\n\n    if (KsiLevel() >= KphLevelLow)\n    {\n        // The driver exposes this information earlier than ProcessSequenceNumber was introduced.\n        // Where not available it synthesizes it for informer messages, for consistency use it if\n        // it's enabled.\n        status = KphQueryInformationProcess(\n            ProcessHandle,\n            KphProcessStartKey,\n            ProcessStartKey,\n            sizeof(ULONGLONG),\n            NULL\n            );\n    }\n    else\n    {\n        ULONGLONG processSequenceNumber;\n\n        status = PhGetProcessSequenceNumber(\n            ProcessHandle,\n            &processSequenceNumber\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            *ProcessStartKey = PH_PROCESS_EXTENSION_STARTKEY(processSequenceNumber);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the telemetry application session GUID for a specified process.\n *\n * \\param ProcessHandle Handle to the process whose telemetry session GUID is to be retrieved.\n * \\param TelemetrySessionGuid Pointer to a GUID structure that receives the telemetry session GUID.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessTelemetryAppSessionGuid(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PGUID TelemetrySessionGuid\n    )\n{\n    NTSTATUS status;\n    PROCESS_TELEMETRY_ID_INFORMATION telemetryInfo;\n    ULONG returnLength;\n\n    memset(&telemetryInfo, 0, sizeof(PROCESS_TELEMETRY_ID_INFORMATION));\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessTelemetryIdInformation,\n        &telemetryInfo,\n        sizeof(PROCESS_TELEMETRY_ID_INFORMATION),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW &&\n        RTL_CONTAINS_FIELD(&telemetryInfo, returnLength, BootId) &&\n        RTL_CONTAINS_FIELD(&telemetryInfo, telemetryInfo.HeaderSize, BootId)))\n    {\n        GUID telemetryAppGuid;\n\n        memset(&telemetryAppGuid, 0, sizeof(GUID));\n        telemetryAppGuid.Data1 = telemetryInfo.ProcessId;\n        telemetryAppGuid.Data2 = (USHORT)telemetryInfo.SessionId;\n        telemetryAppGuid.Data3 = (USHORT)telemetryInfo.BootId;\n\n        if (memcpy_s(telemetryAppGuid.Data4, sizeof(telemetryAppGuid.Data4), &telemetryInfo.CreateTime, sizeof(telemetryInfo.CreateTime)))\n            return STATUS_FAIL_CHECK;\n        if (memcpy_s(TelemetrySessionGuid, sizeof(*TelemetrySessionGuid), &telemetryAppGuid, sizeof(telemetryAppGuid)))\n            return STATUS_FAIL_CHECK;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves telemetry ID information for a specified process.\n *\n * \\param ProcessHandle Handle to the process for which telemetry information is to be retrieved.\n * \\param TelemetryInformation Pointer to a variable that receives a pointer to the telemetry ID information structure.\n * \\param TelemetryInformationLength Optional pointer to a variable that receives the length, in bytes, of the telemetry information structure.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessTelemetryIdInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_TELEMETRY_ID_INFORMATION* TelemetryInformation,\n    _Out_opt_ PULONG TelemetryInformationLength\n    )\n{\n    NTSTATUS status;\n    PPROCESS_TELEMETRY_ID_INFORMATION telemetryBuffer;\n    ULONG telemetryLength;\n    ULONG returnLength;\n    ULONG attempts;\n\n    telemetryLength = sizeof(PROCESS_TELEMETRY_ID_INFORMATION) + SECURITY_MAX_SID_SIZE + (DOS_MAX_PATH_LENGTH * sizeof(WCHAR)) + (DOS_MAX_PATH_LENGTH * sizeof(WCHAR));\n    telemetryBuffer = PhAllocateZero(telemetryLength);\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessTelemetryIdInformation,\n        telemetryBuffer,\n        telemetryLength,\n        &returnLength\n        );\n    attempts = 0;\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)\n    {\n        telemetryLength = returnLength;\n        telemetryBuffer = PhReAllocate(telemetryBuffer, telemetryLength);\n\n        status = NtQueryInformationProcess(\n            ProcessHandle,\n            ProcessTelemetryIdInformation,\n            telemetryBuffer,\n            telemetryLength,\n            &returnLength\n            );\n        attempts++;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *TelemetryInformation = telemetryBuffer;\n\n        if (TelemetryInformationLength)\n        {\n            *TelemetryInformationLength = telemetryLength;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the count of TLS (Thread Local Storage) bitmap entries and TLS expansion bitmap entries for a specified process.\n *\n * \\param ProcessHandle A handle to the process whose TLS bitmap counters are to be retrieved.\n * \\param TlsBitMapCount Pointer to a variable that receives the count of TLS bitmap entries.\n * \\param TlsExpansionBitMapCount Pointer to a variable that receives the count of TLS expansion bitmap entries.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessTlsBitMapCounters(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG TlsBitMapCount,\n    _Out_ PULONG TlsExpansionBitMapCount\n    )\n{\n    NTSTATUS status;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n    PVOID pebBaseAddress;\n    RTL_BITMAP tlsBitMap;\n    RTL_BITMAP tlsExpansionBitMap;\n    ULONG bitmapBits[2] = { 0 };\n    ULONG bitmapExpansionBits[32] = { 0 };\n\n    static_assert(sizeof(bitmapBits) == RTL_FIELD_SIZE(PEB, TlsBitmapBits), \"Buffer must equal TlsBitmapBits\");\n    static_assert(sizeof(bitmapExpansionBits) == RTL_FIELD_SIZE(PEB, TlsExpansionBitmapBits), \"Buffer must equal TlsExpansionBitmapBits\");\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        status = PhGetProcessPeb32(ProcessHandle, &pebBaseAddress);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB32, TlsBitmapBits)),\n            bitmapBits,\n            sizeof(bitmapBits),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB32, TlsExpansionBitmapBits)),\n            bitmapExpansionBits,\n            sizeof(bitmapExpansionBits),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n    else\n#endif\n    {\n        status = PhGetProcessPeb(ProcessHandle, &pebBaseAddress);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB, TlsBitmapBits)),\n            bitmapBits,\n            sizeof(bitmapBits),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB, TlsExpansionBitmapBits)),\n            bitmapExpansionBits,\n            sizeof(bitmapExpansionBits),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    RtlInitializeBitMap(&tlsBitMap, bitmapBits, TLS_MINIMUM_AVAILABLE);\n    RtlInitializeBitMap(&tlsExpansionBitMap, bitmapExpansionBits, TLS_EXPANSION_SLOTS);\n\n    *TlsBitMapCount = RtlNumberOfSetBits(&tlsBitMap);\n    *TlsExpansionBitMapCount = RtlNumberOfSetBits(&tlsExpansionBitMap);\n\nCleanupExit:\n    return status;\n}\n\n/**\n * Gets whether the process is running under the POSIX subsystem.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param IsPosix A variable which receives a boolean\n * indicating whether the process is running under the POSIX subsystem.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessIsPosix(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsPosix\n    )\n{\n    NTSTATUS status;\n    PVOID pebBaseAddress;\n    ULONG imageSubsystem;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n\n    if (WindowsVersion >= WINDOWS_10)\n    {\n        *IsPosix = FALSE; // Not supported (dmex)\n        return STATUS_SUCCESS;\n    }\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        status = PhGetProcessPeb32(ProcessHandle, &pebBaseAddress);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB32, ImageSubsystem)),\n            &imageSubsystem,\n            sizeof(ULONG),\n            NULL\n            );\n    }\n    else\n#endif\n    {\n        status = PhGetProcessPeb(ProcessHandle, &pebBaseAddress);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB, ImageSubsystem)),\n            &imageSubsystem,\n            sizeof(ULONG),\n            NULL\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *IsPosix = imageSubsystem == IMAGE_SUBSYSTEM_POSIX_CUI;\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/nativesocket.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     diversenok   2025\n *\n */\n\n#include <ph.h>\n#include <phafd.h>\n#include <phnet.h>\n#include <hndlinfo.h>\n#include <ws2ipdef.h>\n#include <ws2bth.h>\n#include <afunix.h>\n#include <hvsocketcontrol.h>\n#include <secedit.h>\n\n#include <mstcpip.h>\n\n/**\n * Determines if an object name represents an AFD socket handle.\n *\n * \\param[in] ObjectName A native object name.\n * \\return Whether the name matches an AFD socket name format.\n */\nBOOLEAN PhAfdIsSocketObjectName(\n    _In_opt_ PPH_STRING ObjectName\n    )\n{\n    static CONST PH_STRINGREF deviceName = PH_STRINGREF_INIT(AFD_DEVICE_NAME);\n\n    if (ObjectName && PhStartsWithStringRef(&ObjectName->sr, &deviceName, TRUE))\n    {\n        // N.B. Check explicitly for \"\\\\Device\\\\Afd\" or \"\\\\Device\\\\Afd\\\\\" to avoid \"\\\\Device\\\\AfdABC\"\n\n        if (ObjectName->Length == deviceName.Length)\n            return TRUE;\n\n        assert(ObjectName->Length > deviceName.Length);\n\n        if (ObjectName->Buffer[deviceName.Length / sizeof(WCHAR)] == OBJ_NAME_PATH_SEPARATOR)\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Determines if a file handle is an AFD socket handle.\n *\n * \\param[in] Handle A file handle.\n * \\return A successful status if the handle is an AFD socket or an errant status otherwise.\n */\nNTSTATUS PhAfdIsSocketHandle(\n    _In_ HANDLE Handle\n    )\n{\n    static CONST PH_STRINGREF deviceName = PH_STRINGREF_INIT(AFD_DEVICE_NAME);\n    NTSTATUS status;\n    PH_STRINGREF volumeName;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    union {\n        FILE_VOLUME_NAME_INFORMATION VolumeName;\n        UCHAR Raw[sizeof(FILE_VOLUME_NAME_INFORMATION) + sizeof(AFD_DEVICE_NAME) - sizeof(UNICODE_NULL)];\n    } Buffer;\n\n    // Query the backing device name\n    status = NtQueryInformationFile(\n        Handle,\n        &ioStatusBlock,\n        &Buffer,\n        sizeof(Buffer),\n        FileVolumeNameInformation\n        );\n\n    // If the name does not fit into the buffer, it's not AFD\n    if (status == STATUS_BUFFER_OVERFLOW)\n        return STATUS_NOT_SAME_DEVICE;\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    volumeName.Buffer = Buffer.VolumeName.DeviceName;\n    volumeName.Length = Buffer.VolumeName.DeviceNameLength;\n\n    // Compare the file's device name to AFD\n    return PhEqualStringRef(&volumeName, &deviceName, TRUE) ? STATUS_SUCCESS : STATUS_NOT_SAME_DEVICE;\n}\n\n/**\n * Issues an IOCTL on an AFD handle and waits for its completion.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[in] IoControlCode I/O control code\n * \\param[in] InBuffer Input buffer.\n * \\param[in] InBufferSize Input buffer size.\n * \\param[out] OutputBuffer Output Buffer.\n * \\param[in] OutputBufferSize Output buffer size.\n * \\param[out] BytesReturned Optionally set to the number of bytes returned.\n * \\param[in,out] Overlapped Optional overlapped structure.\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdDeviceIoControl(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG IoControlCode,\n    _In_reads_bytes_(InBufferSize) PVOID InBuffer,\n    _In_ ULONG InBufferSize,\n    _Out_writes_bytes_to_opt_(OutputBufferSize, *BytesReturned) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferSize,\n    _Out_opt_ PULONG BytesReturned,\n    _Inout_opt_ LPOVERLAPPED Overlapped\n    )\n{\n    NTSTATUS status;\n    HANDLE eventHandle;\n    IO_STATUS_BLOCK ioStatusBlock;\n\n    if (BytesReturned)\n    {\n        *BytesReturned = 0;\n    }\n\n    if (Overlapped)\n    {\n        eventHandle = Overlapped->hEvent;\n        Overlapped->Internal = STATUS_PENDING;\n    }\n    else\n    {\n        // We cannot wait on the file handle because it might not grant SYNCHRONIZE access.\n        // Always use an event instead.\n\n        status = PhCreateEvent(\n            &eventHandle,\n            EVENT_ALL_ACCESS,\n            SynchronizationEvent,\n            FALSE\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n\n    status = NtDeviceIoControlFile(\n        SocketHandle,\n        eventHandle,\n        NULL,\n        Overlapped,\n        Overlapped ? (PIO_STATUS_BLOCK)Overlapped : &ioStatusBlock,\n        IoControlCode,\n        InBuffer,\n        InBufferSize,\n        OutputBuffer,\n        OutputBufferSize\n        );\n\n    if (Overlapped)\n    {\n        if (NT_INFORMATION(status) && BytesReturned)\n        {\n            *BytesReturned = (ULONG)Overlapped->InternalHigh;\n        }\n    }\n    else\n    {\n        if (status == STATUS_PENDING)\n        {\n            NtWaitForSingleObject(eventHandle, FALSE, NULL);\n            status = ioStatusBlock.Status;\n        }\n\n        NtClose(eventHandle);\n\n        if (BytesReturned)\n        {\n            *BytesReturned = (ULONG)ioStatusBlock.Information;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Retrieves shared information for an AFD socket.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[out] SharedInfo A buffer with the shared socket information.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdQuerySharedInfo(\n    _In_ HANDLE SocketHandle,\n    _Out_ PSOCK_SHARED_INFO SharedInfo\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n\n    status = PhAfdDeviceIoControl(\n        SocketHandle,\n        IOCTL_AFD_GET_CONTEXT,\n        NULL,\n        0,\n        SharedInfo,\n        sizeof(SOCK_SHARED_INFO),\n        &returnLength,\n        NULL\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW)\n        return STATUS_SUCCESS;\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Shared information is provided by the Win32 level; do a sanity check on the returned size\n    return returnLength < sizeof(SOCK_SHARED_INFO) ? STATUS_NOT_FOUND : status;\n}\n\n/**\n * Retrieves simple information for an AFD socket.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[in] InformationType The type of information to query, such as AFD_CONNECT_TIME or AFD_GROUP_ID_AND_TYPE.\n * \\param[out] Information Output buffer.\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdQuerySimpleInfo(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG InformationType,\n    _Out_ PAFD_INFORMATION Information\n    )\n{\n    Information->InformationType = InformationType;\n\n    return PhAfdDeviceIoControl(\n        SocketHandle,\n        IOCTL_AFD_GET_INFORMATION,\n        Information,\n        sizeof(AFD_INFORMATION),\n        Information,\n        sizeof(AFD_INFORMATION),\n        NULL,\n        NULL\n        );\n}\n\n/**\n * Retrieves socket option for an AFD socket.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[in] Level A level for the option, such as SOL_SOCKET or IPPROTO_IP.\n * \\param[in] OptionName An option identifier within the level, such as SO_REUSEADDR or IP_TTL.\n * \\param[out] OptionValue A buffer that receives the option value.\n * \\param[in] OptionLength The size of the OptionValue buffer.\n * \\param[in] ReturnLength The size of the returned option value, if available.\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdQuerySocketOption(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG Level,\n    _In_ ULONG OptionName,\n    _Out_ PVOID OptionValue,\n    _In_ ULONG OptionLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    AFD_TL_IO_CONTROL_INFO controlInfo;\n\n    memset(&controlInfo, 0, sizeof(AFD_TL_IO_CONTROL_INFO));\n    controlInfo.Type = TlGetSockOptIoControlType;\n    controlInfo.EndpointIoctl = TRUE;\n    controlInfo.Level = Level;\n    controlInfo.IoControlCode = OptionName;\n\n    return PhAfdDeviceIoControl(\n        SocketHandle,\n        IOCTL_AFD_TRANSPORT_IOCTL,\n        &controlInfo,\n        sizeof(AFD_TL_IO_CONTROL_INFO),\n        OptionValue,\n        OptionLength,\n        ReturnLength,\n        NULL\n        );\n}\n\n/**\n * Retrieves socket option for an AFD socket.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[in] Level A level for the option, such as SOL_SOCKET or IPPROTO_IP.\n * \\param[in] OptionName An option identifier within the level, such as SO_REUSEADDR or IP_TTL.\n * \\param[out] OptionValue A buffer that receives the option value.\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdQueryOption(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG Level,\n    _In_ ULONG OptionName,\n    _Out_ PULONG OptionValue\n    )\n{\n    AFD_TL_IO_CONTROL_INFO controlInfo = { 0 };\n    controlInfo.Type = TlGetSockOptIoControlType;\n    controlInfo.EndpointIoctl = TRUE;\n    controlInfo.Level = Level;\n    controlInfo.IoControlCode = OptionName;\n    *OptionValue = 0;\n\n    return PhAfdDeviceIoControl(\n        SocketHandle,\n        IOCTL_AFD_TRANSPORT_IOCTL,\n        &controlInfo,\n        sizeof(AFD_TL_IO_CONTROL_INFO),\n        OptionValue,\n        sizeof(ULONG),\n        NULL,\n        NULL\n        );\n}\n\n/**\n * Retrieves the latest supported TCP_INFO for an AFD socket.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[out] TcpInfo A buffer that receives the TCP information.\n * \\param[out] TcpInfoVersion The version of the returned structure.\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdQueryTcpInfo(\n    _In_ HANDLE SocketHandle,\n    _Out_ PTCP_INFO_v2 TcpInfo,\n    _Out_ PULONG TcpInfoVersion\n    )\n{\n    static CONST ULONG tcpInfoSize[] =\n    {\n        sizeof(TCP_INFO_v0),\n        sizeof(TCP_INFO_v1),\n        sizeof(TCP_INFO_v2)\n    };\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    AFD_TL_IO_CONTROL_INFO controlInfo = { 0 };\n    LONG version;\n\n    controlInfo.Type = TlSocketIoControlType;\n    controlInfo.EndpointIoctl = TRUE;\n    controlInfo.IoControlCode = SIO_TCP_INFO;\n    controlInfo.InputBuffer = &version;\n    controlInfo.InputBufferLength = sizeof(LONG);\n\n    RtlZeroMemory(TcpInfo, sizeof(TCP_INFO_v2));\n\n    for (version = 2; version >= 0; version--)\n    {\n        status = PhAfdDeviceIoControl(\n            SocketHandle,\n            IOCTL_AFD_TRANSPORT_IOCTL,\n            &controlInfo,\n            sizeof(AFD_TL_IO_CONTROL_INFO),\n            TcpInfo,\n            tcpInfoSize[version],\n            NULL,\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            *TcpInfoVersion = version;\n            break;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Opens an address or a connection handle to the underlying device for a TDI socket.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[in] QueryMode A type of the query, either AFD_QUERY_ADDRESS_HANDLE or AFD_QUERY_CONNECTION_HANDLE.\n * \\param[out] TdiHandle A pointer to a variable that receives a TDI device handle, NULL (when no handle is available), or INVALID_HANDLE_VALUE (for non-TDI sockets).\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdQueryTdiHandle(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG QueryMode,\n    _Out_ PHANDLE TdiHandle\n    )\n{\n    NTSTATUS status;\n    AFD_HANDLE_INFO handles;\n\n    if (QueryMode != AFD_QUERY_ADDRESS_HANDLE && QueryMode != AFD_QUERY_CONNECTION_HANDLE)\n        return STATUS_INVALID_INFO_CLASS;\n\n    status = PhAfdDeviceIoControl(\n        SocketHandle,\n        IOCTL_AFD_QUERY_HANDLES,\n        &QueryMode,\n        sizeof(QueryMode),\n        &handles,\n        sizeof(handles),\n        NULL,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (QueryMode == AFD_QUERY_ADDRESS_HANDLE)\n            *TdiHandle = handles.TdiAddressHandle;\n        else\n            *TdiHandle = handles.TdiConnectionHandle;\n    }\n\n    return status;\n}\n\n/**\n * Formats a TDI device name for a socket.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[in] QueryMode A type of the query, either AFD_QUERY_ADDRESS_HANDLE or AFD_QUERY_CONNECTION_HANDLE.\n * \\param[out] TdiDeviceName A pointer to a variable that receives a device name string.\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdQueryFormatTdiDeviceName(\n    _In_ HANDLE SocketHandle,\n    _In_ ULONG QueryMode,\n    _Outptr_ PPH_STRING *TdiDeviceName\n    )\n{\n    NTSTATUS status;\n    HANDLE hTdiDevice;\n\n    status = PhAfdQueryTdiHandle(\n        SocketHandle,\n        QueryMode,\n        &hTdiDevice\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (hTdiDevice == INVALID_HANDLE_VALUE)\n    {\n        *TdiDeviceName = PhCreateString(L\"N/A (transport is not TDI)\");\n    }\n    else if (hTdiDevice == NULL)\n    {\n        *TdiDeviceName = PhCreateString(L\"None\");\n    }\n    else\n    {\n        status = PhGetObjectName(NtCurrentProcess(), hTdiDevice, TRUE, TdiDeviceName);\n        NtClose(hTdiDevice);\n    }\n\n    return status;\n}\n\n/**\n * Determines if we know how to handle a specific address family.\n *\n * \\param[in] AddressFamily A socket address family value.\n * \\return Whether the address family is supported.\n */\nBOOLEAN PhpAfdIsSupportedAddressFamily(\n    _In_ LONG AddressFamily\n    )\n{\n    switch (AddressFamily)\n    {\n    case AF_UNIX:\n    case AF_INET:\n    case AF_INET6:\n    case AF_BTH:\n    case AF_HYPERV:\n        return TRUE;\n    default:\n        return FALSE;\n    }\n}\n\n/**\n * Retrieves an address associated with an AFD socket.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[in] Remote Whether the function should return a remote or a local address.\n * \\param[out] Address Output buffer.\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdQueryAddress(\n    _In_ HANDLE SocketHandle,\n    _In_ BOOLEAN Remote,\n    _Out_ PSOCKADDR_STORAGE Address\n    )\n{\n    NTSTATUS status;\n    AFD_ADDRESS buffer = { 0 };\n\n    if (Remote)\n    {\n        // HACK: If the socket has a suitable state but no remote address, the IOCTL can succeed without\n        // writing anything to the buffer, yet setting IO_STATUS_BLOCK's Information to a non-zero value.\n        // We issue a zero-size query to recognize this scenario. (diversenok)\n\n        if (NT_SUCCESS(PhAfdDeviceIoControl(SocketHandle, IOCTL_AFD_GET_REMOTE_ADDRESS, NULL, 0, NULL, 0, NULL, NULL)))\n            return STATUS_NOT_FOUND;\n    }\n\n    // Retrieve the address\n    status = PhAfdDeviceIoControl(\n        SocketHandle,\n        Remote ? IOCTL_AFD_GET_REMOTE_ADDRESS : IOCTL_AFD_GET_ADDRESS,\n        NULL,\n        0,\n        &buffer,\n        sizeof(buffer),\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Most sockets are TLI; their addresses don't need conversion.\n    if (PhpAfdIsSupportedAddressFamily(buffer.TliAddress.ss_family))\n    {\n        *Address = buffer.TliAddress;\n        return status;\n    }\n\n    // Some sockets (like Bluetooth) use TDI. Verify the header and extarct the socket address.\n    if (buffer.TdiAddress.ActivityCount > 0 &&\n        buffer.TdiAddress.Address.TAAddressCount >= 1 &&\n        buffer.TdiAddress.Address.Address[0].AddressLength <= sizeof(buffer) - RTL_SIZEOF_THROUGH_FIELD(TDI_ADDRESS_INFO, Address.Address[0].AddressType) &&\n        PhpAfdIsSupportedAddressFamily(buffer.TdiAddress.Address.Address[0].AddressType))\n    {\n        RtlZeroMemory(Address, sizeof(SOCKADDR_STORAGE));\n\n        // AddressLength covers the length after the AddressType field, while the socket address starts at the AddressType field.\n        // See comments in AFD_ADDRESS for details about the layout.\n        RtlCopyMemory(\n            Address,\n            &buffer.TdiAddressUnpacked.EmbeddedAddress,\n            buffer.TdiAddress.Address.Address[0].AddressLength + RTL_FIELD_SIZE(TDI_ADDRESS_INFO, Address.Address[0].AddressType)\n            );\n\n        return status;\n    }\n\n    return STATUS_UNKNOWN_REVISION;\n}\n\n/**\n * Formats a socket address as a strings.\n *\n * \\param[in] Address The address buffer.\n * \\param[out] AddressString The string representation of the address.\n * \\param[in] Flags A bit mask of PH_AFD_ADDRESS_* flags that control address formatting.\n * \\return Successful or errant status.\n */\nNTSTATUS PhAfdFormatAddress(\n    _In_ PSOCKADDR_STORAGE Address,\n    _Out_ PPH_STRING *AddressString,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status = STATUS_NOT_SUPPORTED;\n    WCHAR buffer[70];\n    ULONG characters = RTL_NUMBER_OF(buffer);\n\n    if (Address->ss_family == AF_UNIX)\n    {\n        PSOCKADDR_UN address = (PSOCKADDR_UN)Address;\n\n        *AddressString = PhConvertUtf8ToUtf16Ex(address->sun_path, strnlen(address->sun_path, UNIX_PATH_MAX));\n\n        if (!(*AddressString))\n            return STATUS_SOME_NOT_MAPPED;\n\n        status = STATUS_SUCCESS;\n    }\n    else if (Address->ss_family == AF_INET)\n    {\n        PSOCKADDR_IN address = (PSOCKADDR_IN)Address;\n\n        // Format an IPv4 address\n        status = RtlIpv4AddressToStringExW(\n            &address->sin_addr,\n            address->sin_port,\n            buffer,\n            &characters\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        *AddressString = PhCreateStringEx(buffer, characters * sizeof(WCHAR) - sizeof(UNICODE_NULL));\n    }\n    else if (Address->ss_family == AF_INET6)\n    {\n        PSOCKADDR_IN6 address = (PSOCKADDR_IN6)Address;\n\n        // Format an IPv6 address\n        status = RtlIpv6AddressToStringExW(\n            &address->sin6_addr,\n            address->sin6_scope_id,\n            address->sin6_port,\n            buffer,\n            &characters\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        *AddressString = PhCreateStringEx(buffer, characters * sizeof(WCHAR) - sizeof(UNICODE_NULL));\n    }\n    else if (Address->ss_family == AF_BTH)\n    {\n        PSOCKADDR_BTH address = (PSOCKADDR_BTH)Address;\n\n        // Format a Bluetooth address\n        *AddressString = PhFormatString(\n            L\"(%02X:%02X:%02X:%02X:%02X:%02X):%d\",\n            (UCHAR)(address->btAddr >> 40),\n            (UCHAR)(address->btAddr >> 32),\n            (UCHAR)(address->btAddr >> 24),\n            (UCHAR)(address->btAddr >> 16),\n            (UCHAR)(address->btAddr >> 8),\n            (UCHAR)(address->btAddr),\n            address->port\n            );\n\n        status = STATUS_SUCCESS;\n    }\n    else if (Address->ss_family == AF_HYPERV)\n    {\n        PSOCKADDR_HV address = (PSOCKADDR_HV)Address;\n\n        if (Flags & PH_AFD_ADDRESS_SIMPLIFY)\n        {\n            PH_FORMAT format[5];\n            ULONG count = 0;\n            PPH_STRING serviceString = NULL;\n            PPH_STRING vmName = NULL;\n\n            if (PhHvSocketIsVSockTemplate(&address->ServiceId))\n            {\n                PhInitFormatS(&format[count++], L\"VSOCK:\");\n                PhInitFormatU(&format[count++], address->ServiceId.Data1);\n            }\n            else if (serviceString = PhHvSocketGetServiceName(&address->ServiceId))\n            {\n                PhInitFormatSR(&format[count++], serviceString->sr);\n            }\n            else\n            {\n                serviceString = PhFormatGuid(&address->ServiceId);\n                PhInitFormatSR(&format[count++], serviceString->sr);\n            }\n\n            if (!IsEqualGUID(&address->VmId, &HV_GUID_WILDCARD))\n            {\n                PhInitFormatS(&format[count++], L\" (VM: \");\n\n                if (vmName = PhHvSocketGetVmName(&address->VmId))\n                {\n                    PhInitFormatSR(&format[count++], vmName->sr);\n                }\n                else\n                {\n                    vmName = PhHvSocketAddressString(&address->VmId);\n                    PhInitFormatSR(&format[count++], vmName->sr);\n                }\n\n                PhInitFormatS(&format[count++], L\")\");\n            }\n\n            *AddressString = PhFormat(format, count, 80);\n\n            PhClearReference(&serviceString);\n            PhClearReference(&vmName);\n        }\n        else\n        {\n            PPH_STRING vmIdPart;\n            PPH_STRING serviceIdPart;\n            PH_FORMAT format[3];\n\n            vmIdPart = PhFormatGuid(&address->VmId);\n            serviceIdPart = PhFormatGuid(&address->ServiceId);\n\n            PhInitFormatSR(&format[0], vmIdPart->sr);\n            PhInitFormatC(&format[1], L':');\n            PhInitFormatSR(&format[2], serviceIdPart->sr);\n\n            *AddressString = PhFormat(format, 3, 80);\n\n            PhDereferenceObject(vmIdPart);\n            PhDereferenceObject(serviceIdPart);\n        }\n\n        status = STATUS_SUCCESS;\n    }\n\n    return status;\n}\n\n/**\n * Queries an address associated with an AFD socket and prints it into a string.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\param[in] Remote Whether the function should return a remote or a local address.\n * \\param[out] AddressString The string representation of the address.\n * \\param[in] Flags A bit mask of PH_AFD_ADDRESS_* flags that control address formatting.\n * Successful or errant status.\n */\nNTSTATUS PhAfdQueryFormatAddress(\n    _In_ HANDLE SocketHandle,\n    _In_ BOOLEAN Remote,\n    _Out_ PPH_STRING *AddressString,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    SOCKADDR_STORAGE address;\n\n    status = PhAfdQueryAddress(SocketHandle, Remote, &address);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    return PhAfdFormatAddress(&address, AddressString, Flags);\n}\n\n/**\n * Looks up a human-readable name of a known socket state.\n *\n * \\param[in] SocketState The socket state value.\n * \\return A string with the state name or NULL when the state value is not recognized.\n */\n_Maybenull_\nPCWSTR PhpAfdGetSocketStateString(\n    _In_ SOCKET_STATE SocketState\n    )\n{\n    switch (SocketState)\n    {\n    case SocketStateInitializing:\n        return L\"Initializing\";\n    case SocketStateOpen:\n        return L\"Open\";\n    case SocketStateBound:\n        return L\"Bound\";\n    case SocketStateBoundSpecific:\n        return L\"Bound (specific)\";\n    case SocketStateConnected:\n        return L\"Connected\";\n    case SocketStateClosing:\n        return L\"Closing\";\n    default:\n        return NULL;\n    }\n}\n\n/**\n * Formats a socket state as a string.\n *\n * \\param[in] SocketState The socket state value.\n * \\return A human-readable name of the socket state.\n */\nPPH_STRING PhAfdFormatSocketState(\n    _In_ SOCKET_STATE SocketState\n    )\n{\n    PCWSTR knownName = PhpAfdGetSocketStateString(SocketState);\n\n    if (knownName)\n        return PhCreateString(knownName);\n    else\n        return PhFormatString(L\"Invalid state (%d)\", SocketState);\n}\n\n/**\n * Looks up a human-readable name of a known socket type.\n *\n * \\param[in] SocketType The socket type value.\n * \\return A string with the socket type name or NULL when the value is not recognized.\n */\n_Maybenull_\nPCWSTR PhpAfdGetSocketTypeString(\n    _In_ LONG SocketType\n    )\n{\n    switch (SocketType)\n    {\n    case SOCK_STREAM:\n        return L\"Stream\";\n    case SOCK_DGRAM:\n        return L\"Datagram\";\n    case SOCK_RAW:\n        return L\"Raw\";\n    case SOCK_RDM:\n        return L\"Reliably-delivered message\";\n    case SOCK_SEQPACKET:\n        return L\"Pseudo-stream\";\n    default:\n        return NULL;\n    }\n}\n\n/**\n * Formats a socket type as a string.\n *\n * \\param[in] SocketType The socket type value.\n * \\return A human-readable name for the socket type.\n */\nPPH_STRING PhAfdFormatSocketType(\n    _In_ LONG SocketType\n    )\n{\n    PCWSTR knownName = PhpAfdGetSocketTypeString(SocketType);\n\n    if (knownName)\n        return PhCreateString(knownName);\n    else\n        return PhFormatString(L\"Unknown (%d)\", SocketType);\n}\n\n/**\n * Formats a human-readable name for a set of protocol provider flags.\n *\n * \\param[in] ProviderFlags The provider flags value.\n * \\return A string with the flag names.\n */\nPPH_STRING PhAfdFormatProviderFlags(\n    _In_ ULONG ProviderFlags\n    )\n{\n#define PH_AFD_PROVIDER_FLAG(x, n) { TEXT(#x), x, FALSE, FALSE, n }\n\n    static const PH_ACCESS_ENTRY providerFlags[] =\n    {\n        PH_AFD_PROVIDER_FLAG(PFL_MULTIPLE_PROTO_ENTRIES, L\"Multiple entries\"),\n        PH_AFD_PROVIDER_FLAG(PFL_RECOMMENDED_PROTO_ENTRY, L\"Recommended entry\"),\n        PH_AFD_PROVIDER_FLAG(PFL_HIDDEN, L\"Hidden\"),\n        PH_AFD_PROVIDER_FLAG(PFL_MATCHES_PROTOCOL_ZERO, L\"Matches protocol zero\"),\n        PH_AFD_PROVIDER_FLAG(PFL_NETWORKDIRECT_PROVIDER, L\"Network direct\"),\n    };\n\n    PPH_STRING string;\n    PH_FORMAT format[5];\n\n    if (ProviderFlags)\n    {\n        string = PhGetAccessString(ProviderFlags, (PPH_ACCESS_ENTRY)providerFlags, RTL_NUMBER_OF(providerFlags));\n\n        PhInitFormatS(&format[0], L\"0x\");\n        PhInitFormatX(&format[1], ProviderFlags);\n        PhInitFormatS(&format[2], L\" (\");\n        PhInitFormatSR(&format[3], string->sr);\n        PhInitFormatC(&format[4], L')');\n\n        PhMoveReference(&string, PhFormat(format, 5, 10));\n    }\n    else\n    {\n        string = PhCreateString(L\"None\");\n    }\n\n    return string;\n}\n\n/**\n * Formats a human-readable name for a set of service flags.\n *\n * \\param[in] ServiceFlags The service flags value.\n * \\return A string with the flag names.\n */\nPPH_STRING PhAfdFormatServiceFlags(\n    _In_ ULONG ServiceFlags\n    )\n{\n#define PH_AFD_SERVICE_FLAG(x, n) { TEXT(#x), x, FALSE, FALSE, n }\n\n    static const PH_ACCESS_ENTRY serviceFlags[] =\n    {\n        PH_AFD_SERVICE_FLAG(XP1_CONNECTIONLESS, L\"Connectionless\"),\n        PH_AFD_SERVICE_FLAG(XP1_GUARANTEED_DELIVERY, L\"Guaranteed delivery\"),\n        PH_AFD_SERVICE_FLAG(XP1_GUARANTEED_ORDER, L\"Guaranteed order\"),\n        PH_AFD_SERVICE_FLAG(XP1_MESSAGE_ORIENTED, L\"Message-oriented\"),\n        PH_AFD_SERVICE_FLAG(XP1_PSEUDO_STREAM, L\"Pseudo-stream\"),\n        PH_AFD_SERVICE_FLAG(XP1_GRACEFUL_CLOSE, L\"Graceful close\"),\n        PH_AFD_SERVICE_FLAG(XP1_EXPEDITED_DATA, L\"Expedited data\"),\n        PH_AFD_SERVICE_FLAG(XP1_CONNECT_DATA, L\"Connect data\"),\n        PH_AFD_SERVICE_FLAG(XP1_DISCONNECT_DATA, L\"Disconnect data\"),\n        PH_AFD_SERVICE_FLAG(XP1_SUPPORT_BROADCAST, L\"Broadcast\"),\n        PH_AFD_SERVICE_FLAG(XP1_SUPPORT_MULTIPOINT, L\"Support multipoint\"),\n        PH_AFD_SERVICE_FLAG(XP1_MULTIPOINT_CONTROL_PLANE, L\"Multipoint control plane\"),\n        PH_AFD_SERVICE_FLAG(XP1_MULTIPOINT_DATA_PLANE, L\"Multipoint data plane\"),\n        PH_AFD_SERVICE_FLAG(XP1_QOS_SUPPORTED, L\"QoS supported\"),\n        PH_AFD_SERVICE_FLAG(XP1_INTERRUPT, L\"Interrupt\"),\n        PH_AFD_SERVICE_FLAG(XP1_UNI_SEND, L\"Unidirectional send\"),\n        PH_AFD_SERVICE_FLAG(XP1_UNI_RECV, L\"Unidirectional receive\"),\n        PH_AFD_SERVICE_FLAG(XP1_IFS_HANDLES, L\"IFS handles\"),\n        PH_AFD_SERVICE_FLAG(XP1_PARTIAL_MESSAGE, L\"Partial message\"),\n        PH_AFD_SERVICE_FLAG(XP1_SAN_SUPPORT_SDP, L\"SAN\"),\n    };\n\n    PPH_STRING string;\n    PH_FORMAT format[5];\n\n    if (ServiceFlags)\n    {\n        string = PhGetAccessString(ServiceFlags, (PPH_ACCESS_ENTRY)serviceFlags, RTL_NUMBER_OF(serviceFlags));\n\n        PhInitFormatS(&format[0], L\"0x\");\n        PhInitFormatX(&format[1], ServiceFlags);\n        PhInitFormatS(&format[2], L\" (\");\n        PhInitFormatSR(&format[3], string->sr);\n        PhInitFormatC(&format[4], L')');\n\n        PhMoveReference(&string, PhFormat(format, 5, 10));\n    }\n    else\n    {\n        string = PhCreateString(L\"None\");\n    }\n\n    return string;\n}\n\n/**\n * Formats a human-readable name for a set of socket creation flags.\n *\n * \\param[in] CreationFlags The creation flags value.\n * \\return A string with the flag names.\n */\nPPH_STRING PhAfdFormatCreationFlags(\n    _In_ ULONG CreationFlags\n    )\n{\n#define PH_AFD_CREATION_FLAG(x, n) { TEXT(#x), x, FALSE, FALSE, n }\n\n    static const PH_ACCESS_ENTRY creationFlags[] =\n    {\n        PH_AFD_CREATION_FLAG(WSA_FLAG_OVERLAPPED, L\"Overlapped\"),\n        PH_AFD_CREATION_FLAG(WSA_FLAG_MULTIPOINT_C_ROOT, L\"Multipoint control root\"),\n        PH_AFD_CREATION_FLAG(WSA_FLAG_MULTIPOINT_C_LEAF, L\"Multipoint control leaf\"),\n        PH_AFD_CREATION_FLAG(WSA_FLAG_MULTIPOINT_D_ROOT, L\"Multipoint data root\"),\n        PH_AFD_CREATION_FLAG(WSA_FLAG_MULTIPOINT_D_LEAF, L\"Multipoint data leaf\"),\n        PH_AFD_CREATION_FLAG(WSA_FLAG_ACCESS_SYSTEM_SECURITY, L\"Access SACL\"),\n        PH_AFD_CREATION_FLAG(WSA_FLAG_NO_HANDLE_INHERIT, L\"No handle inherit\"),\n        PH_AFD_CREATION_FLAG(WSA_FLAG_REGISTERED_IO, L\"Registered I/O\"),\n    };\n\n    PPH_STRING string;\n    PH_FORMAT format[5];\n\n    if (CreationFlags)\n    {\n        string = PhGetAccessString(CreationFlags, (PPH_ACCESS_ENTRY)creationFlags, RTL_NUMBER_OF(creationFlags));\n\n        PhInitFormatS(&format[0], L\"0x\");\n        PhInitFormatX(&format[1], CreationFlags);\n        PhInitFormatS(&format[2], L\" (\");\n        PhInitFormatSR(&format[3], string->sr);\n        PhInitFormatC(&format[4], L')');\n\n        PhMoveReference(&string, PhFormat(format, 5, 10));\n    }\n    else\n    {\n        string = PhCreateString(L\"None\");\n    }\n\n    return string;\n}\n\n/**\n * Formats a human-readable name for a set of AFD socket flags.\n *\n * \\param[in] SharedInfo The shared socket information buffer.\n * \\return A string with the flag names.\n */\nPPH_STRING PhAfdFormatSharedInfoFlags(\n    _In_ PSOCK_SHARED_INFO SharedInfo\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n\n    if (!SharedInfo->Flags)\n        return PhCreateString(L\"None\");\n\n    PhInitializeStringBuilder(&stringBuilder, 80);\n\n    PhAppendFormatStringBuilder(&stringBuilder, L\"0x%x (\", SharedInfo->Flags);\n\n    if (SharedInfo->Listening)\n        PhAppendStringBuilder2(&stringBuilder, L\"Listening, \");\n    if (SharedInfo->Broadcast)\n        PhAppendStringBuilder2(&stringBuilder, L\"Broadcast, \");\n    if (SharedInfo->Debug)\n        PhAppendStringBuilder2(&stringBuilder, L\"Debug, \");\n    if (SharedInfo->OobInline)\n        PhAppendStringBuilder2(&stringBuilder, L\"OOB in line, \");\n    if (SharedInfo->ReuseAddresses)\n        PhAppendStringBuilder2(&stringBuilder, L\"Reuse addresses, \");\n    if (SharedInfo->ExclusiveAddressUse)\n        PhAppendStringBuilder2(&stringBuilder, L\"Exclusive address use, \");\n    if (SharedInfo->NonBlocking)\n        PhAppendStringBuilder2(&stringBuilder, L\"Non-blocking, \");\n    if (SharedInfo->DontUseWildcard)\n        PhAppendStringBuilder2(&stringBuilder, L\"Don't use wildcard, \");\n    if (SharedInfo->ReceiveShutdown)\n        PhAppendStringBuilder2(&stringBuilder, L\"Receive shutdown, \");\n    if (SharedInfo->SendShutdown)\n        PhAppendStringBuilder2(&stringBuilder, L\"Send shutdown, \");\n    if (SharedInfo->ConditionalAccept)\n        PhAppendStringBuilder2(&stringBuilder, L\"Conditional accept, \");\n    if (SharedInfo->IsSANSocket)\n        PhAppendStringBuilder2(&stringBuilder, L\"SAN, \");\n    if (SharedInfo->fIsTLI)\n        PhAppendStringBuilder2(&stringBuilder, L\"TLI, \");\n    if (SharedInfo->Rio)\n        PhAppendStringBuilder2(&stringBuilder, L\"RIO, \");\n    if (SharedInfo->ReceiveBufferSizeSet)\n        PhAppendStringBuilder2(&stringBuilder, L\"Receive buffer size set, \");\n    if (SharedInfo->SendBufferSizeSet)\n        PhAppendStringBuilder2(&stringBuilder, L\"Send buffer size set, \");\n\n    // Remove the trailing comma\n    PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhAppendStringBuilder2(&stringBuilder, L\")\");\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n/**\n * Looks up a name of a known address family.\n *\n * \\param[in] AddressFamily The address family value.\n * \\return A string with the address family name or NULL when it is not recognized.\n */\n_Maybenull_\nPCWSTR PhpAfdGetAddressFamilyString(\n    _In_ LONG AddressFamily\n    )\n{\n    switch (AddressFamily)\n    {\n    case AF_UNSPEC:\n        return L\"Unspecified\";\n    case AF_UNIX:\n        return L\"Unix\";\n    case AF_INET:\n        return L\"Internet\";\n    case AF_INET6:\n        return L\"Internet v6\";\n    case AF_BTH:\n        return L\"Bluetooth\";\n    case AF_HYPERV:\n        return L\"Hyper-V\";\n    default:\n        return NULL;\n    }\n}\n\n/**\n * Formats an address family as a string.\n *\n * \\param[in] AddressFamily The address family value.\n * \\return A string with the address family name.\n */\nPPH_STRING PhAfdFormatAddressFamily(\n    _In_ LONG AddressFamily\n    )\n{\n    PCWSTR knownName = PhpAfdGetAddressFamilyString(AddressFamily);\n\n    if (knownName)\n        return PhCreateString(knownName);\n    else\n        return PhFormatString(L\"Unrecognized address family %d\", AddressFamily);\n}\n\n/**\n * Looks up a name for a known protocol.\n *\n * \\param[in] AddressFamily The address family of the protocol.\n * \\param[in] Protocol The protocol value.\n * \\return A string with the protocol name or NULL when it is not recognized.\n */\n_Maybenull_\nPCWSTR PhpAfdGetProtocolString(\n    _In_ LONG AddressFamily,\n    _In_ LONG Protocol\n    )\n{\n    switch (AddressFamily)\n    {\n    case AF_UNIX:\n        return L\"UNIX\";\n    case AF_INET:\n    case AF_INET6:\n        {\n            switch (Protocol)\n            {\n            case IPPROTO_ICMP:\n                return L\"ICMP\";\n            case IPPROTO_IGMP:\n                return L\"IGMP\";\n            case IPPROTO_TCP:\n                return L\"TCP\";\n            case IPPROTO_UDP:\n                return L\"UDP\";\n            case IPPROTO_RDP:\n                return L\"RDP\";\n            case IPPROTO_ICMPV6:\n                return L\"ICMPv6\";\n            case IPPROTO_PGM:\n                return L\"PGM\";\n            case IPPROTO_L2TP:\n                return L\"L2TP\";\n            case IPPROTO_SCTP:\n                return L\"SCTP\";\n            case IPPROTO_RAW:\n                return L\"RAW\";\n            case IPPROTO_RESERVED_IPSEC:\n                return L\"IPSec\";\n            }\n        }\n        break;\n    case AF_BTH:\n        {\n            switch (Protocol)\n            {\n            case BTHPROTO_RFCOMM:\n                return L\"RFCOMM\";\n            case BTHPROTO_L2CAP:\n                return L\"L2CAP\";\n            }\n        }\n        break;\n    case AF_HYPERV:\n        {\n            switch (Protocol)\n            {\n            case HV_PROTOCOL_RAW:\n                return L\"RAW\";\n            }\n        }\n        break;\n    }\n\n    return NULL;\n}\n\n/**\n * Formats a protocol name as a string.\n *\n * \\param[in] AddressFamily The address family of the protocol.\n * \\param[in] Protocol The protocol value.\n * \\return A string with a human-readable protocol name.\n */\nPPH_STRING PhAfdFormatProtocol(\n    _In_ LONG AddressFamily,\n    _In_ LONG Protocol\n    )\n{\n    PCWSTR knownName = PhpAfdGetProtocolString(AddressFamily, Protocol);\n\n    if (knownName)\n        return PhCreateString(knownName);\n    else\n        return PhFormatString(L\"Unrecognized protocol %d\", Protocol);\n}\n\n/**\n * Looks up a short human-readable identifier for a known protocol.\n *\n * \\param[in] AddressFamily The address family of the protocol.\n * \\param[in] Protocol The protocol value.\n * \\return A string with the protocol name or NULL when it is not recognized.\n */\n_Maybenull_\nPCWSTR PhpAfdGetProtocolSummary(\n    _In_ LONG AddressFamily,\n    _In_ LONG Protocol\n    )\n{\n    switch (AddressFamily)\n    {\n    case AF_UNIX:\n        return L\"UNIX\";\n    case AF_INET:\n        switch (Protocol)\n        {\n        case IPPROTO_ICMP:\n            return L\"ICMP\";\n        case IPPROTO_TCP:\n            return L\"TCP\";\n        case IPPROTO_UDP:\n            return L\"UDP\";\n        case IPPROTO_RAW:\n            return L\"RAW/IPv4\";\n        }\n    case AF_INET6:\n        switch (Protocol)\n        {\n        case IPPROTO_ICMPV6:\n            return L\"ICMP6\";\n        case IPPROTO_TCP:\n            return L\"TCP6\";\n        case IPPROTO_UDP:\n            return L\"UDP6\";\n        case IPPROTO_RAW:\n            return L\"RAW/IPv6\";\n        }\n    case AF_BTH:\n        switch (Protocol)\n        {\n        case BTHPROTO_RFCOMM:\n            return L\"RFCOMM [Bluetooth]\";\n        case BTHPROTO_L2CAP:\n            return L\"L2CAP [Bluetooth]\";\n        }\n    case AF_HYPERV:\n        switch (Protocol)\n        {\n        case HV_PROTOCOL_RAW:\n            return L\"Hyper-V RAW\";\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Looks up a human-readable name of a group type.\n *\n * \\param[in] GroupType The socket group type value.\n * \\return A string with the group type name or NULL when the value is not recognized.\n */\n_Maybenull_\nPCWSTR PhpAfdGetGroupTypeString(\n    _In_ AFD_GROUP_TYPE GroupType\n    )\n{\n    switch (GroupType)\n    {\n    case GroupTypeNeither:\n        return L\"Neither\";\n    case GroupTypeUnconstrained:\n        return L\"Unconstrained\";\n    case GroupTypeConstrained:\n        return L\"Constrained\";\n    default:\n        return NULL;\n    }\n}\n\n/**\n * Formats a group type name as a string.\n *\n * \\param[in] GroupType The socket group type value.\n * \\return A string with a human-readable group type name.\n */\nPPH_STRING PhAfdFormatGroupType(\n    _In_ AFD_GROUP_TYPE GroupType\n    )\n{\n    PCWSTR knownName = PhpAfdGetGroupTypeString(GroupType);\n\n    if (knownName)\n        return PhCreateString(knownName);\n    else\n        return PhFormatString(L\"Unrecognized type (%d)\", GroupType);\n}\n\n/**\n * Looks up a human-readable name for an IPv6 protection level.\n *\n * \\param[in] ProtectionLevel The protection level value.\n * \\return A string with the protection level name or NULL when the value is not recognized.\n */\n_Maybenull_\nPCWSTR PhpAfdGetProtectionLevelString(\n    _In_ ULONG ProtectionLevel\n    )\n{\n    switch (ProtectionLevel)\n    {\n    case PROTECTION_LEVEL_UNRESTRICTED:\n        return L\"Unrestricted\";\n    case PROTECTION_LEVEL_EDGERESTRICTED:\n        return L\"Edge-restricted\";\n    case PROTECTION_LEVEL_RESTRICTED:\n        return L\"Restricted\";\n    case PROTECTION_LEVEL_DEFAULT:\n        return L\"Default\";\n    default:\n        return NULL;\n    }\n}\n\n/**\n * Formats an IPv6 protection level name as a string.\n *\n * \\param[in] ProtectionLevel The protection level value.\n * \\return A string with a human-readable protection level name.\n */\nPPH_STRING PhAfdFormatProtectionLevel(\n    _In_ ULONG ProtectionLevel\n    )\n{\n    PCWSTR knownName;\n\n    if (knownName = PhpAfdGetProtectionLevelString(ProtectionLevel))\n    {\n        return PhCreateString(knownName);\n    }\n\n    return PhFormatString(L\"Unrecognized value (%d)\", ProtectionLevel);\n}\n\n/**\n * Looks up a human-readable name for MTU discovery mode.\n *\n * \\param[in] MtuDiscover The MTU discovery value.\n * \\return A string with the MTU discovery mode name or NULL when the value is not recognized.\n */\n_Maybenull_\nPCWSTR PhpAfdGetMtuDiscoveryString(\n    _In_ ULONG MtuDiscover\n    )\n{\n    switch (MtuDiscover)\n    {\n    case IP_PMTUDISC_NOT_SET:\n        return L\"Not set\";\n    case IP_PMTUDISC_DO:\n        return L\"Perform\";\n    case IP_PMTUDISC_DONT:\n        return L\"Don't perform\";\n    case IP_PMTUDISC_PROBE:\n        return L\"Probe\";\n    default:\n        return NULL;\n    }\n}\n\n/**\n * Formats an MTU discovery mode as a string.\n *\n * \\param[in] MtuDiscover The MTU discovery value.\n * \\return A string with a human-readable MTU discovery mode name.\n */\nPPH_STRING PhAfdFormatMtuDiscoveryMode(\n    _In_ ULONG MtuDiscover\n    )\n{\n    PCWSTR knownName;\n\n    if (knownName = PhpAfdGetMtuDiscoveryString(MtuDiscover))\n    {\n        return PhCreateString(knownName);\n    }\n\n    return PhFormatString(L\"Unrecognized value (%d)\", MtuDiscover);\n}\n\n/**\n * Looks up a human-readable name for a TCP state.\n *\n * \\param[in] TcpState The TCP state value.\n * \\return A string with the TCP state name or NULL when the value is not recognized.\n */\n_Maybenull_\nPCWSTR PhpAfdGetTcpStateString(\n    _In_ TCPSTATE TcpState\n    )\n{\n    switch (TcpState)\n    {\n    case TCPSTATE_CLOSED:\n        return L\"Closed\";\n    case TCPSTATE_LISTEN:\n        return L\"Listen\";\n    case TCPSTATE_SYN_SENT:\n        return L\"SYN sent\";\n    case TCPSTATE_SYN_RCVD:\n        return L\"SYN received\";\n    case TCPSTATE_ESTABLISHED:\n        return L\"Established\";\n    case TCPSTATE_FIN_WAIT_1:\n        return L\"FIN wait 1\";\n    case TCPSTATE_FIN_WAIT_2:\n        return L\"FIN wait 2\";\n    case TCPSTATE_CLOSE_WAIT:\n        return L\"Close wait\";\n    case TCPSTATE_CLOSING:\n        return L\"Closing\";\n    case TCPSTATE_LAST_ACK:\n        return L\"Last ACK\";\n    case TCPSTATE_TIME_WAIT:\n        return L\"Time wait\";\n    default:\n        return NULL;\n    }\n}\n\n/**\n * Formats a TCP state as a string.\n *\n * \\param[in] TcpState The TCP state value.\n * \\return A string with a human-readable TCP state name.\n */\nPPH_STRING PhAfdFormatTcpState(\n    _In_ TCPSTATE TcpState\n    )\n{\n    PCWSTR knownName;\n\n    if (knownName = PhpAfdGetTcpStateString(TcpState))\n    {\n        return PhCreateString(knownName);\n    }\n\n    return PhFormatString(L\"Unrecognized state (%d)\", TcpState);\n}\n\n/**\n * Formats an interface identifier as a string.\n *\n * \\param[in] Interface The interface identifier.\n * \\return A human-readable string with the interface IP address or scope ID.\n */\nPPH_STRING PhAfdFormatInterfaceOption(\n    _In_ ULONG Interface\n    )\n{\n    if (Interface & 0x000000FF)\n    {\n        NTSTATUS status;\n        IN_ADDR interfaceIp;\n        ULONG addressStringLength = INET6_ADDRSTRLEN;\n        WCHAR addressString[INET6_ADDRSTRLEN];\n\n        // Values with a non-zero first octet identify an interface by IP address\n        interfaceIp.S_un.S_addr = Interface;\n\n        status = PhIpv4AddressToString(\n            &interfaceIp,\n            0,\n            addressString,\n            &addressStringLength\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            PH_STRINGREF string;\n\n            string.Buffer = addressString;\n            string.Length = (addressStringLength - 1) * sizeof(WCHAR);\n\n            return PhCreateString2(&string);\n        }\n\n        return PhFormatString(L\"Error: %lu\", status);\n    }\n    else if (Interface)\n    {\n        PH_FORMAT format[2];\n\n        // Other values (0.0.0.0/24 addresses) store a big-endian interface index/scope ID\n        PhInitFormatC(&format[0], L'%');\n        PhInitFormatU(&format[1], _byteswap_ulong(Interface));\n        return PhFormat(format, RTL_NUMBER_OF(format), 8);\n    }\n    else\n    {\n        // The zero interface is special\n        return PhCreateString(L\"Default\");\n    }\n}\n\n/**\n * Formats a human-readable name for an AFD socket.\n *\n * \\param[in] SocketHandle An AFD socket handle.\n * \\return The best handle name representation available on success, or NULL on error.\n */\n_Maybenull_\nPPH_STRING PhAfdFormatSocketBestName(\n    _In_ HANDLE SocketHandle\n    )\n{\n    PPH_STRING string = NULL;\n    PH_FORMAT format[9];\n    ULONG count = 0;\n    SOCK_SHARED_INFO sharedInfo;\n    PPH_STRING addressString = NULL;\n    PPH_STRING remoteAddressString = NULL;\n\n    PhInitFormatS(&format[count++], L\"AFD socket:\");\n\n    if (NT_SUCCESS(PhAfdQuerySharedInfo(SocketHandle, &sharedInfo)))\n    {\n        PCWSTR detail;\n\n        // State\n        if (detail = PhpAfdGetSocketStateString(sharedInfo.State))\n        {\n            PhInitFormatC(&format[count++], L' ');\n            PhInitFormatS(&format[count++], detail);\n        }\n\n        // Protocol\n        if (detail = PhpAfdGetProtocolSummary(sharedInfo.AddressFamily, sharedInfo.Protocol))\n        {\n            PhInitFormatC(&format[count++], L' ');\n            PhInitFormatS(&format[count++], detail);\n        }\n    }\n\n    // Local address\n    if (NT_SUCCESS(PhAfdQueryFormatAddress(SocketHandle, FALSE, &addressString, PH_AFD_ADDRESS_SIMPLIFY)) &&\n        !PhIsNullOrEmptyString(addressString))\n    {\n        PhInitFormatS(&format[count++], L\" on \");\n        PhInitFormatSR(&format[count++], addressString->sr);\n    }\n\n    // Remote address\n    if (NT_SUCCESS(PhAfdQueryFormatAddress(SocketHandle, TRUE, &remoteAddressString, PH_AFD_ADDRESS_SIMPLIFY)) &&\n        !PhIsNullOrEmptyString(remoteAddressString))\n    {\n        PhInitFormatS(&format[count++], L\" to \");\n        PhInitFormatSR(&format[count++], remoteAddressString->sr);\n    }\n\n    if (count > 1)\n        string = PhFormat(format, count, 10);\n\n    PhClearReference(&addressString);\n    PhClearReference(&remoteAddressString);\n\n    return string;\n}\n"
  },
  {
    "path": "phlib/nativethread.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <hndlinfo.h>\n#include <kphuser.h>\n#include <lsasup.h>\n#include <mapldr.h>\n#include <phafd.h>\n\n/**\n * Opens a thread.\n *\n * \\param[out] ThreadHandle A variable which receives a handle to the thread.\n * \\param[in] DesiredAccess The desired access to the thread.\n * \\param[in] ThreadId The ID of the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ThreadId\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    CLIENT_ID clientId;\n    KPH_LEVEL level;\n\n    clientId.UniqueProcess = NULL;\n    clientId.UniqueThread = ThreadId;\n\n    level = KsiLevel();\n\n    if ((level >= KphLevelMed) && (DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess)\n    {\n        status = KphOpenThread(\n            ThreadHandle,\n            DesiredAccess,\n            &clientId\n            );\n    }\n    else\n    {\n        InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n        status = NtOpenThread(\n            ThreadHandle,\n            DesiredAccess,\n            &objectAttributes,\n            &clientId\n            );\n\n        if (status == STATUS_ACCESS_DENIED && (level == KphLevelMax))\n        {\n            status = KphOpenThread(\n                ThreadHandle,\n                DesiredAccess,\n                &clientId\n                );\n        }\n    }\n\n    return status;\n}\n\n/**\n * Opens a thread using a CLIENT_ID structure.\n *\n * \\param[out] ThreadHandle Receives a handle to the opened thread.\n * \\param[in] DesiredAccess The access rights requested for the thread.\n * \\param[in] ClientId Pointer to a CLIENT_ID structure identifying the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenThreadClientId(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    KPH_LEVEL level;\n\n    level = KsiLevel();\n\n    if ((level >= KphLevelMed) && (DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess)\n    {\n        status = KphOpenThread(\n            ThreadHandle,\n            DesiredAccess,\n            ClientId\n            );\n    }\n    else\n    {\n        InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n        status = NtOpenThread(\n            ThreadHandle,\n            DesiredAccess,\n            &objectAttributes,\n            ClientId\n            );\n\n        if (status == STATUS_ACCESS_DENIED && (level == KphLevelMax))\n        {\n            status = KphOpenThread(\n                ThreadHandle,\n                DesiredAccess,\n                ClientId\n                );\n        }\n    }\n\n    return status;\n}\n\n/**\n * Limited API for untrusted/external code.\n *\n * \\param[out] ThreadHandle A variable which receives a handle to the thread.\n * \\param[in] DesiredAccess The desired access to the thread.\n * \\param[in] ThreadId The ID of the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenThreadPublic(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ThreadId\n    )\n{\n    OBJECT_ATTRIBUTES objectAttributes;\n    CLIENT_ID clientId;\n\n    clientId.UniqueProcess = NULL;\n    clientId.UniqueThread = ThreadId;\n\n    InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n\n    return NtOpenThread(\n        ThreadHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &clientId\n        );\n}\n\n/**\n * Opens the process that owns the specified thread.\n *\n * \\param[in] ThreadHandle Handle to the thread whose owning process is to be opened.\n * \\param[in] DesiredAccess Access rights requested for the process handle.\n * \\param[out] ProcessHandle Receives a handle to the opened process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n    KPH_LEVEL level;\n\n    level = KsiLevel();\n\n    if (level == KphLevelMax || (level >= KphLevelMed && FlagOn(DesiredAccess, KPH_PROCESS_READ_ACCESS) == DesiredAccess))\n    {\n        status = KphOpenThreadProcess(\n            ThreadHandle,\n            DesiredAccess,\n            ProcessHandle\n            );\n\n        if (NT_SUCCESS(status))\n            return status;\n    }\n\n    status = PhGetThreadBasicInformation(\n        ThreadHandle,\n        &basicInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhOpenProcessClientId(\n        ProcessHandle,\n        DesiredAccess,\n        &basicInfo.ClientId\n        );\n\n    return status;\n}\n\n/**\n * Gets basic information for a thread.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param BasicInformation A variable which receives the information.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetThreadBasicInformation(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PTHREAD_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadBasicInformation,\n        BasicInformation,\n        sizeof(THREAD_BASIC_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * Retrieves the base priority of a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose base priority is to be retrieved.\n * \\param[out] Increment A pointer to a variable that receives the base priority value (KPRIORITY).\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadBasePriority(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PKPRIORITY Increment\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n\n    status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        *Increment = basicInfo.BasePriority;\n    }\n\n    return status;\n\n    //return NtQueryInformationThread(\n    //    ThreadHandle,\n    //    ThreadBasePriority,\n    //    Increment,\n    //    sizeof(LONG),\n    //    NULL\n    //    );\n}\n\n/**\n * Retrieves the Thread Environment Block (TEB) base address for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose TEB base address is to be retrieved.\n * \\param[out] TebBaseAddress A pointer to a variable that receives the TEB base address as an ULONG_PTR.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadTeb(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG_PTR TebBaseAddress\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n\n    status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        if (!basicInfo.TebBaseAddress)\n            return STATUS_UNSUCCESSFUL;\n\n        *TebBaseAddress = (ULONG_PTR)basicInfo.TebBaseAddress;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the Thread Environment Block (TEB32) base address for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose TEB32 base address is to be retrieved.\n * \\param[out] TebBaseAddress A pointer to a variable that receives the TEB base address as an ULONG_PTR.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadTeb32(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG_PTR TebBaseAddress\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n\n    status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        if (!basicInfo.TebBaseAddress)\n            return STATUS_UNSUCCESSFUL;\n\n        *TebBaseAddress = (ULONG_PTR)WOW64_GET_TEB32(basicInfo.TebBaseAddress);\n    }\n\n    return status;\n}\n\n/**\n * Gets a thread's Win32 start address.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param StartAddress A variable which receives the start address of the thread.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetThreadStartAddress(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG_PTR StartAddress\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadQuerySetWin32StartAddress,\n        StartAddress,\n        sizeof(ULONG_PTR),\n        NULL\n        );\n}\n\n/**\n * Gets a thread's I/O priority.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param IoPriority A variable which receives the I/O priority of the thread.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetThreadIoPriority(\n    _In_ HANDLE ThreadHandle,\n    _Out_ IO_PRIORITY_HINT *IoPriority\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadIoPriority,\n        IoPriority,\n        sizeof(IO_PRIORITY_HINT),\n        NULL\n        );\n}\n\n/**\n * Gets a thread's page priority.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param PagePriority A variable which receives the page priority of the thread.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetThreadPagePriority(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG PagePriority\n    )\n{\n    NTSTATUS status;\n    PAGE_PRIORITY_INFORMATION pagePriorityInfo;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadPagePriority,\n        &pagePriorityInfo,\n        sizeof(PAGE_PRIORITY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PagePriority = pagePriorityInfo.PagePriority;\n    }\n\n    return status;\n}\n\n/**\n * Gets a thread's dynamic boosting.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param PriorityBoostDisabled A variable which receives the dynamic boosting state.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetThreadPriorityBoost(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PBOOLEAN PriorityBoostDisabled\n    )\n{\n    NTSTATUS status;\n    ULONG priorityBoost;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadPriorityBoost,\n        &priorityBoost,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PriorityBoostDisabled = !!priorityBoost;\n    }\n\n    return status;\n}\n\n/**\n * Gets a thread's performance counter.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param PerformanceCounter A variable which receives the 64-bit performance counter.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetThreadPerformanceCounter(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PLARGE_INTEGER PerformanceCounter\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER performanceCounter;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadPerformanceCount,\n        &performanceCounter,\n        sizeof(LARGE_INTEGER),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PerformanceCounter = performanceCounter;\n    }\n\n    return status;\n}\n\n/**\n * Gets a thread's cycle count.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param CycleTime A variable which receives the 64-bit cycle time.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetThreadCycleTime(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG64 CycleTime\n    )\n{\n    NTSTATUS status;\n    THREAD_CYCLE_TIME_INFORMATION cycleTimeInfo;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadCycleTime,\n        &cycleTimeInfo,\n        sizeof(THREAD_CYCLE_TIME_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *CycleTime = cycleTimeInfo.AccumulatedCycles;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the ideal processor for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose ideal processor is to be retrieved.\n * \\param[out] ProcessorNumber A pointer to a PROCESSOR_NUMBER structure that receives the ideal processor information.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadIdealProcessor(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PPROCESSOR_NUMBER ProcessorNumber\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadIdealProcessorEx,\n        ProcessorNumber,\n        sizeof(PROCESSOR_NUMBER),\n        NULL\n        );\n}\n\n/**\n * Retrieves the suspend count for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose suspend count is to be retrieved.\n * \\param[out] SuspendCount A pointer to a variable that receives the suspend count.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadSuspendCount(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG SuspendCount\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadSuspendCount,\n        SuspendCount,\n        sizeof(ULONG),\n        NULL\n        );\n}\n\n/**\n * Retrieves the WOW64 context for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose WOW64 context is to be retrieved.\n * \\param[out] Context A pointer to a WOW64_CONTEXT structure that receives the context.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadWow64Context(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PWOW64_CONTEXT Context\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadWow64Context,\n        Context,\n        sizeof(WOW64_CONTEXT),\n        NULL\n        );\n}\n\n#if defined(_ARM64_)\n/**\n * Retrieves the ARM32 context for a thread on ARM64 systems.\n *\n * \\param[in] ThreadHandle A handle to the thread whose ARM32 context is to be retrieved.\n * \\param[out] Context A pointer to an ARM_NT_CONTEXT structure that receives the context.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadArm32Context(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PARM_NT_CONTEXT Context\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadWow64Context,\n        Context,\n        sizeof(ARM_NT_CONTEXT),\n        NULL\n        );\n}\n#endif\n\n/**\n * Retrieves the break on termination state for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[out] BreakOnTermination A pointer to a variable that receives the break on termination state.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadBreakOnTermination(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PBOOLEAN BreakOnTermination\n    )\n{\n    NTSTATUS status;\n    ULONG breakOnTermination;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadBreakOnTermination,\n        &breakOnTermination,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *BreakOnTermination = !!breakOnTermination;\n    }\n\n    return status;\n}\n\n/**\n * Sets the break on termination state for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[in] BreakOnTermination TRUE to enable break on termination, FALSE to disable.\n * \\return Successful or errant status.\n */\nNTSTATUS PhSetThreadBreakOnTermination(\n    _In_ HANDLE ThreadHandle,\n    _In_ BOOLEAN BreakOnTermination\n    )\n{\n    ULONG breakOnTermination;\n\n    breakOnTermination = BreakOnTermination ? 1 : 0;\n\n    return NtSetInformationThread(\n        ThreadHandle,\n        ThreadBreakOnTermination,\n        &breakOnTermination,\n        sizeof(ULONG)\n        );\n}\n\n/**\n * Retrieves the container ID for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[out] ContainerId A pointer to a GUID structure that receives the container ID.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadContainerId(\n    _In_ HANDLE ThreadHandle,\n    _In_ PGUID ContainerId\n    )\n{\n    NTSTATUS status;\n    GUID threadContainerId;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadContainerId,\n        &threadContainerId,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        memcpy(ContainerId, &threadContainerId, sizeof(GUID));\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the I/O pending state for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose I/O pending state is to be retrieved.\n * \\param[out] IsIoPending A pointer to a variable that receives the I/O pending state.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadIsIoPending(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PBOOLEAN IsIoPending\n    )\n{\n    NTSTATUS status;\n    ULONG isIoPending;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadIsIoPending,\n        &isIoPending,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *IsIoPending = !!isIoPending;\n    }\n\n    return status;\n}\n\n/**\n * Gets time information for a thread.\n *\n * \\param ThreadHandle A handle to a thread.\n * \\param Times A variable which receives the information.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadTimes(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PKERNEL_USER_TIMES Times\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadTimes,\n        Times,\n        sizeof(KERNEL_USER_TIMES),\n        NULL\n        );\n}\n\n/**\n * Retrieves the termination state for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose termination state is to be retrieved.\n * \\param[out] IsTerminated A pointer to a variable that receives the termination state (TRUE if terminated).\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadIsTerminated(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PBOOLEAN IsTerminated\n    )\n{\n    NTSTATUS status;\n    ULONG threadIsTerminated;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadIsTerminated,\n        &threadIsTerminated,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *IsTerminated = !!threadIsTerminated;\n    }\n\n    return status;\n}\n\n/**\n * Determines if a thread is terminated by waiting with zero timeout.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\return TRUE if the thread is terminated, FALSE otherwise.\n */\nBOOLEAN PhGetThreadIsTerminated2(\n    _In_ HANDLE ThreadHandle\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER timeout;\n\n    memset(&timeout, 0, sizeof(LARGE_INTEGER));\n\n    status = NtWaitForSingleObject(\n        ThreadHandle,\n        FALSE,\n        &timeout\n        );\n\n    return status == STATUS_WAIT_0;\n}\n\n/**\n * Retrieves the group affinity for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose group affinity is to be retrieved.\n * \\param[out] GroupAffinity A pointer to a GROUP_AFFINITY structure that receives the group affinity.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadGroupAffinity(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PGROUP_AFFINITY GroupAffinity\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadGroupInformation,\n        GroupAffinity,\n        sizeof(GROUP_AFFINITY),\n        &returnLength\n        );\n}\n\n/**\n * Retrieves the index information for a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread whose index information is to be retrieved.\n * \\param[out] ThreadIndex A pointer to a THREAD_INDEX_INFORMATION structure that receives the index information.\n * \\return Successful or errant status.\n * \\remarks The handle must have THREAD_QUERY_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadIndexInformation(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PTHREAD_INDEX_INFORMATION ThreadIndex\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadIndexInformation,\n        ThreadIndex,\n        sizeof(THREAD_INDEX_INFORMATION),\n        &returnLength\n        );\n}\n\n/**\n * Terminates a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread to be terminated.\n * \\param[in] ExitStatus The exit status for the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhTerminateThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ NTSTATUS ExitStatus\n    )\n{\n    NTSTATUS status;\n\n    status = NtTerminateThread(\n        ThreadHandle,\n        ExitStatus\n        );\n\n    return status;\n}\n\n/**\n * Retrieves the context of a thread.\n *\n * \\param[in] ThreadHandle The handle to the thread.\n * \\param[in,out] ThreadContext A pointer to the CONTEXT structure that receives the thread context.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetContextThread(\n    _In_ HANDLE ThreadHandle,\n    _Inout_ PCONTEXT ThreadContext\n    )\n{\n    NTSTATUS status;\n\n    status = NtGetContextThread(\n        ThreadHandle,\n        ThreadContext\n        );\n\n    return status;\n}\n\n/**\n * Atomically queries raw bytes from a thread's TEB at a specified offset.\n *\n * \\param[in] ThreadHandle Handle to target thread.\n * \\param[in,out] TebInformation Buffer to receive the bytes.\n * \\param[in] TebOffset Offset (in bytes) from TEB base.\n * \\param[in] BytesToRead Number of bytes to read.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadTebInformationAtomic(\n    _In_ HANDLE ThreadHandle,\n    _Inout_bytecount_(BytesToRead) PVOID TebInformation,\n    _In_ ULONG TebOffset,\n    _In_ ULONG BytesToRead\n    )\n{\n    NTSTATUS status;\n    THREAD_TEB_INFORMATION threadInfo;\n    ULONG returnLength;\n\n    if (WindowsVersion < WINDOWS_11_24H2)\n        return STATUS_NOT_SUPPORTED;\n\n    threadInfo.TebInformation = TebInformation;\n    threadInfo.TebOffset = TebOffset; // FIELD_OFFSET(TEB, Value);\n    threadInfo.BytesToRead = BytesToRead; // RTL_FIELD_SIZE(TEB, Value);\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadTebInformationAtomic,\n        &threadInfo,\n        sizeof(THREAD_TEB_INFORMATION),\n        &returnLength\n        );\n\n    return status;\n}\n\n/**\n * Retrieves a thread's name (Set by SetThreadDescription API).\n *\n * \\param[in] ThreadHandle Handle to thread (THREAD_QUERY_LIMITED_INFORMATION).\n * \\param[out] ThreadName Receives allocated PPH_STRING containing the name.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadName(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PPH_STRING *ThreadName\n    )\n{\n    NTSTATUS status;\n    PTHREAD_NAME_INFORMATION buffer;\n    ULONG bufferSize;\n    ULONG returnLength;\n\n    if (WindowsVersion < WINDOWS_10)\n        return STATUS_NOT_SUPPORTED;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadNameInformation,\n        buffer,\n        bufferSize,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhFree(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQueryInformationThread(\n            ThreadHandle,\n            ThreadNameInformation,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        // Note: Some threads have UNICODE_NULL as their name. (dmex)\n        if (RtlIsNullOrEmptyUnicodeString(&buffer->ThreadName))\n        {\n            PhFree(buffer);\n            return STATUS_UNSUCCESSFUL;\n        }\n\n        *ThreadName = PhCreateStringFromUnicodeString(&buffer->ThreadName);\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\n/**\n * Sets the description (thread name) for a thread.\n *\n * \\param[in] ThreadHandle Handle to thread (THREAD_SET_LIMITED_INFORMATION).\n * \\param[in] ThreadName Wide string for new name.\n * \\returns NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetThreadName(\n    _In_ HANDLE ThreadHandle,\n    _In_ PCWSTR ThreadName\n    )\n{\n    NTSTATUS status;\n    THREAD_NAME_INFORMATION threadNameInfo;\n\n    if (WindowsVersion < WINDOWS_10)\n        return STATUS_NOT_SUPPORTED;\n\n    memset(&threadNameInfo, 0, sizeof(THREAD_NAME_INFORMATION));\n\n    status = RtlInitUnicodeStringEx(\n        &threadNameInfo.ThreadName,\n        ThreadName\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = NtSetInformationThread(\n        ThreadHandle,\n        ThreadNameInformation,\n        &threadNameInfo,\n        sizeof(THREAD_NAME_INFORMATION)\n        );\n\n    return status;\n}\n\n/**\n * Gets a thread's affinity mask.\n *\n * \\param[in] ThreadHandle A handle to a thread.\n * \\param[out] AffinityMask The affinity mask.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The handle must have THREAD_SET_LIMITED_INFORMATION access.\n */\nNTSTATUS PhGetThreadAffinityMask(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PKAFFINITY AffinityMask\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n\n    status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        *AffinityMask = basicInfo.AffinityMask;\n    }\n\n    return status;\n\n    //return NtQueryInformationThread(\n    //    ThreadHandle,\n    //    ThreadAffinityMask,\n    //    &AffinityMask,\n    //    sizeof(KAFFINITY),\n    //    NULL\n    //    );\n}\n\n/**\n * Sets a thread's affinity mask.\n *\n * \\param[in] ThreadHandle A handle to a thread.\n * \\param[in] AffinityMask The new affinity mask.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The handle must have THREAD_SET_LIMITED_INFORMATION access.\n */\nNTSTATUS PhSetThreadAffinityMask(\n    _In_ HANDLE ThreadHandle,\n    _In_ KAFFINITY AffinityMask\n    )\n{\n    NTSTATUS status;\n\n    status = NtSetInformationThread(\n        ThreadHandle,\n        ThreadAffinityMask,\n        &AffinityMask,\n        sizeof(KAFFINITY)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationThread(\n            ThreadHandle,\n            KphThreadAffinityMask,\n            &AffinityMask,\n            sizeof(KAFFINITY)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Sets thread base priority using a CLIENT_ID (system-wide).\n *\n * \\param[in] ClientId Target thread identifier.\n * \\param[in] Increment New base priority value.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetThreadBasePriorityClientId(\n    _In_ CLIENT_ID ClientId,\n    _In_ KPRIORITY Increment\n    )\n{\n    NTSTATUS status;\n    SYSTEM_THREAD_CID_PRIORITY_INFORMATION threadInfo;\n\n    threadInfo.ClientId = ClientId;\n    threadInfo.Priority = Increment;\n\n    status = NtSetSystemInformation(\n        SystemThreadPriorityClientIdInformation,\n        &threadInfo,\n        sizeof(SYSTEM_THREAD_CID_PRIORITY_INFORMATION)\n        );\n\n    if (status == STATUS_PENDING)\n        status = STATUS_SUCCESS;\n\n    return status;\n}\n\n/**\n * Sets a thread's base priority.\n *\n * \\param[in] ThreadHandle Handle to thread.\n * \\param[in] Increment New priority value (KPRIORITY).\n * \\returns NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetThreadBasePriority(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPRIORITY Increment\n    )\n{\n    NTSTATUS status;\n\n    status = NtSetInformationThread(\n        ThreadHandle,\n        ThreadBasePriority,\n        &Increment,\n        sizeof(KPRIORITY)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationThread(\n            ThreadHandle,\n            KphThreadBasePriority,\n            &Increment,\n            sizeof(KPRIORITY)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Sets a thread's I/O priority.\n *\n * \\param[in] ThreadHandle A handle to a thread.\n * \\param[in] IoPriority The new I/O priority.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The handle must have THREAD_SET_LIMITED_INFORMATION access.\n */\nNTSTATUS PhSetThreadIoPriority(\n    _In_ HANDLE ThreadHandle,\n    _In_ IO_PRIORITY_HINT IoPriority\n    )\n{\n    NTSTATUS status;\n\n    status = NtSetInformationThread(\n        ThreadHandle,\n        ThreadIoPriority,\n        &IoPriority,\n        sizeof(IO_PRIORITY_HINT)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationThread(\n            ThreadHandle,\n            KphThreadIoPriority,\n            &IoPriority,\n            sizeof(IO_PRIORITY_HINT)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Sets a thread's page priority.\n *\n * \\param[in] ThreadHandle Thread handle.\n * \\param[in] PagePriority New page priority value (1..5 typical).\n * \\returns NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetThreadPagePriority(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG PagePriority\n    )\n{\n    NTSTATUS status;\n    PAGE_PRIORITY_INFORMATION pagePriorityInfo;\n\n    pagePriorityInfo.PagePriority = PagePriority;\n\n    status = NtSetInformationThread(\n        ThreadHandle,\n        ThreadPagePriority,\n        &pagePriorityInfo,\n        sizeof(PAGE_PRIORITY_INFORMATION)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationThread(\n            ThreadHandle,\n            KphThreadPagePriority,\n            &pagePriorityInfo,\n            sizeof(PAGE_PRIORITY_INFORMATION)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Enables or disables priority boost for a thread.\n *\n * \\param[in] ThreadHandle Thread handle.\n * \\param[in] DisablePriorityBoost TRUE to disable boost, FALSE to enable.\n * \\returns NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetThreadPriorityBoost(\n    _In_ HANDLE ThreadHandle,\n    _In_ BOOLEAN DisablePriorityBoost\n    )\n{\n    NTSTATUS status;\n    ULONG priorityBoost;\n\n    priorityBoost = DisablePriorityBoost ? 1 : 0;\n\n    status = NtSetInformationThread(\n        ThreadHandle,\n        ThreadPriorityBoost,\n        &priorityBoost,\n        sizeof(ULONG)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationThread(\n            ThreadHandle,\n            KphThreadPriorityBoost,\n            &priorityBoost,\n            sizeof(ULONG)\n            );\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the current power throttling state applied to the specified thread.\n *\n * \\param[in] ThreadHandle Handle to the thread whose power throttling state is to be queried.\n * \\param[out] PowerThrottlingState Pointer to a POWER_THROTTLING_THREAD_STATE structure that receives the throttling state.\n * \\returns NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadPowerThrottlingState(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PPOWER_THROTTLING_THREAD_STATE PowerThrottlingState\n    )\n{\n    NTSTATUS status;\n    POWER_THROTTLING_THREAD_STATE threadPowerThrottlingState;\n\n    memset(&threadPowerThrottlingState, 0, sizeof(POWER_THROTTLING_THREAD_STATE));\n    threadPowerThrottlingState.Version = POWER_THROTTLING_THREAD_CURRENT_VERSION;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadPowerThrottlingState,\n        &threadPowerThrottlingState,\n        sizeof(POWER_THROTTLING_THREAD_STATE),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PowerThrottlingState = threadPowerThrottlingState;\n    }\n\n    return status;\n}\n\n/**\n * Sets a thread's ideal processor (ThreadIdealProcessorEx).\n *\n * \\param[in] ULONG Thread handle.\n * \\param[in] ProcessorNumber Desired processor number/group.\n * \\param[out] PreviousIdealProcessor Receives previous value if provided.\n * \\returns NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetThreadIdealProcessor(\n    _In_ HANDLE ThreadHandle,\n    _In_ PPROCESSOR_NUMBER ProcessorNumber,\n    _Out_opt_ PPROCESSOR_NUMBER PreviousIdealProcessor\n    )\n{\n    NTSTATUS status;\n    PROCESSOR_NUMBER processorNumber;\n\n    processorNumber = *ProcessorNumber;\n    status = NtSetInformationThread(\n        ThreadHandle,\n        ThreadIdealProcessorEx,\n        &processorNumber,\n        sizeof(PROCESSOR_NUMBER)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationThread(\n            ThreadHandle,\n            KphThreadIdealProcessorEx,\n            &processorNumber,\n            sizeof(PROCESSOR_NUMBER)\n            );\n    }\n\n    if (PreviousIdealProcessor)\n        *PreviousIdealProcessor = processorNumber;\n\n    return status;\n}\n\n/**\n * Sets a thread's group affinity.\n *\n * \\param[in] ThreadHandle Thread handle.\n * \\param[in] GroupAffinity New affinity data.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetThreadGroupAffinity(\n    _In_ HANDLE ThreadHandle,\n    _In_ GROUP_AFFINITY GroupAffinity\n    )\n{\n    NTSTATUS status;\n\n    status = NtSetInformationThread(\n        ThreadHandle,\n        ThreadGroupInformation,\n        &GroupAffinity,\n        sizeof(GROUP_AFFINITY)\n        );\n\n    if ((status == STATUS_ACCESS_DENIED) && (KsiLevel() == KphLevelMax))\n    {\n        status = KphSetInformationThread(\n            ThreadHandle,\n            KphThreadGroupInformation,\n            &GroupAffinity,\n            sizeof(GROUP_AFFINITY)\n            );\n    }\n\n    return status;\n}\n\n/**\n * The PhGetThreadLastSystemCall function returns the last system call of a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[out] LastSystemCall The last system call of the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadLastSystemCall(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PTHREAD_LAST_SYSCALL_INFORMATION LastSystemCall\n    )\n{\n    if (WindowsVersion < WINDOWS_8)\n    {\n        return NtQueryInformationThread(\n            ThreadHandle,\n            ThreadLastSystemCall,\n            LastSystemCall,\n            FIELD_OFFSET(THREAD_LAST_SYSCALL_INFORMATION, WaitTime),\n            NULL\n            );\n    }\n\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadLastSystemCall,\n        LastSystemCall,\n        sizeof(THREAD_LAST_SYSCALL_INFORMATION),\n        NULL\n        );\n}\n\n// rev from Advapi32!ImpersonateAnonymousToken (dmex)\n/**\n * The PhCreateImpersonationToken function creates an anonymous logon token.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[out] TokenHandle A handle to the token.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateImpersonationToken(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PHANDLE TokenHandle\n    )\n{\n    NTSTATUS status;\n    HANDLE tokenHandle;\n    SECURITY_QUALITY_OF_SERVICE securityService;\n\n    status = PhRevertImpersonationToken(ThreadHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    securityService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);\n    securityService.ImpersonationLevel = SecurityImpersonation;\n    securityService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;\n    securityService.EffectiveOnly = FALSE;\n\n    status = NtImpersonateThread(\n        ThreadHandle,\n        ThreadHandle,\n        &securityService\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhOpenThreadToken(\n        ThreadHandle,\n        TOKEN_DUPLICATE | TOKEN_IMPERSONATE,\n        FALSE,\n        &tokenHandle\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *TokenHandle = tokenHandle;\n    }\n\n    return status;\n}\n\n// rev from Advapi32!ImpersonateLoggedOnUser (dmex)\n/**\n * The PhImpersonateToken function enables the specified thread to impersonate the security context of a token.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[in] TokenHandle A handle to the token.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhImpersonateToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE TokenHandle\n    )\n{\n    NTSTATUS status;\n    TOKEN_TYPE tokenType;\n    ULONG returnLength;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenType,\n        &tokenType,\n        sizeof(TOKEN_TYPE),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (tokenType == TokenPrimary)\n    {\n        SECURITY_QUALITY_OF_SERVICE securityService;\n        OBJECT_ATTRIBUTES objectAttributes;\n        HANDLE tokenHandle;\n\n        memset(&securityService, 0, sizeof(SECURITY_QUALITY_OF_SERVICE));\n        securityService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);\n        securityService.ImpersonationLevel = SecurityImpersonation;\n        securityService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;\n        securityService.EffectiveOnly = FALSE;\n\n        InitializeObjectAttributesEx(\n            &objectAttributes,\n            NULL,\n            OBJ_EXCLUSIVE,\n            NULL,\n            NULL,\n            &securityService\n            );\n\n        status = NtDuplicateToken(\n            TokenHandle,\n            TOKEN_IMPERSONATE | TOKEN_QUERY,\n            &objectAttributes,\n            FALSE,\n            TokenImpersonation,\n            &tokenHandle\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        status = NtSetInformationThread(\n            ThreadHandle,\n            ThreadImpersonationToken,\n            &tokenHandle,\n            sizeof(HANDLE)\n            );\n\n        NtClose(tokenHandle);\n    }\n    else\n    {\n        status = NtSetInformationThread(\n            ThreadHandle,\n            ThreadImpersonationToken,\n            &TokenHandle,\n            sizeof(HANDLE)\n            );\n    }\n\n    return status;\n}\n\n// rev from Advapi32!RevertToSelf (dmex)\n/**\n * The PhRevertImpersonationToken function terminates the impersonation of a security context.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhRevertImpersonationToken(\n    _In_ HANDLE ThreadHandle\n    )\n{\n    HANDLE tokenHandle = NULL;\n\n    return NtSetInformationThread(\n        ThreadHandle,\n        ThreadImpersonationToken,\n        &tokenHandle,\n        sizeof(HANDLE)\n        );\n}\n\n/**\n * Retrieves the last error status of a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[in] ProcessHandle A handle to the process.\n * \\param[out] LastStatusValue The last status of the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadLastStatusValue(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PNTSTATUS LastStatusValue\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n\n    if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return status;\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(WOW64_GET_TEB32(basicInfo.TebBaseAddress), UFIELD_OFFSET(TEB32, LastStatusValue)),\n            LastStatusValue,\n            sizeof(NTSTATUS),\n            NULL\n            );\n    }\n    else\n#endif\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.TebBaseAddress, UFIELD_OFFSET(TEB, LastStatusValue)), // LastErrorValue/ExceptionCode\n            LastStatusValue,\n            sizeof(NTSTATUS),\n            NULL\n            );\n    }\n\n    return status;\n}\n\n/**\n * Retrieves statistics about COM multi-threaded apartment (MTA) usage in a process.\n *\n * \\param[in] ProcessHandle A handle to the process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param[out] MTAInits The total number of MTA references in the process.\n * \\param[out] MTAIncInits The number of MTA references from CoIncrementMTAUsage.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessMTAUsage(\n    _In_ HANDLE ProcessHandle,\n    _Out_opt_ PULONG MTAInits,\n    _Out_opt_ PULONG MTAIncInits\n    )\n{\n    NTSTATUS status;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PMTA_USAGE_GLOBALS mtaUsageGlobals = NULL;\n\n    if (!MTAInits && !MTAIncInits)\n        return STATUS_INVALID_PARAMETER;\n\n#ifdef _WIN64\n    if (!NT_SUCCESS(status = PhGetProcessIsWow64(ProcessHandle, &isWow64)))\n        return status;\n\n    if (isWow64)\n        return STATUS_NOT_SUPPORTED;\n#endif\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion >= WINDOWS_8)\n        {\n            PVOID combase;\n            PMTA_USAGE_GLOBALS (WINAPI* CoGetMTAUsageInfo_I)(VOID);\n\n            if (combase = PhGetLoaderEntryDllBaseZ(L\"combase.dll\"))\n            {\n                // combase exports CoGetMTAUsageInfo as ordinal 70\n                CoGetMTAUsageInfo_I = PhGetDllBaseProcedureAddress(combase, NULL, 70);\n\n                if (CoGetMTAUsageInfo_I)\n                {\n                    // CoGetMTAUsageInfo returns addresses of several global variables we can read\n                    mtaUsageGlobals = CoGetMTAUsageInfo_I();\n                }\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!mtaUsageGlobals)\n        return STATUS_UNSUCCESSFUL;\n\n    if (MTAInits)\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            mtaUsageGlobals->MTAInits,\n            MTAInits,\n            sizeof(ULONG),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n\n    if (MTAIncInits)\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            mtaUsageGlobals->MTAIncInits,\n            MTAIncInits,\n            sizeof(ULONG),\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves COM apartment flags and init count of a thread.\n *\n * \\param[in] ThreadHandle A handle to the thread. The handle must have\n * THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param[in] ProcessHandle A handle to the process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param[out] ApartmentFlags The COM apartment flags of the thread.\n * \\param[out] ComInits The number of times the thread initialized COM.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadApartmentFlags(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ApartmentFlags,\n    _Out_opt_ PULONG ComInits\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n    PVOID apartmentStateOffset;\n    PVOID oletlsBaseAddress;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n\n    if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return status;\n\n#ifdef _WIN64\n    if (!NT_SUCCESS(status = PhGetProcessIsWow64(ProcessHandle, &isWow64)))\n        return status;\n\n    if (isWow64)\n    {\n        ULONG oletlsDataAddress32 = 0;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(WOW64_GET_TEB32(basicInfo.TebBaseAddress), UFIELD_OFFSET(TEB32, ReservedForOle)),\n            &oletlsDataAddress32,\n            sizeof(ULONG),\n            NULL\n            );\n\n        oletlsBaseAddress = UlongToPtr(oletlsDataAddress32);\n    }\n    else\n#endif\n    {\n        ULONG_PTR oletlsDataAddress = 0;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.TebBaseAddress, UFIELD_OFFSET(TEB, ReservedForOle)),\n            &oletlsDataAddress,\n            sizeof(ULONG_PTR),\n            NULL\n            );\n\n        oletlsBaseAddress = (PVOID)oletlsDataAddress;\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!oletlsBaseAddress)\n    {\n        // Return a special error to indicate that we successfully determined\n        // that the thread has no associated COM state. (diversenok)\n        return NTSTATUS_FROM_WIN32(CO_E_NOTINITIALIZED);\n    }\n\n#ifdef _WIN64\n    if (isWow64)\n        apartmentStateOffset = PTR_ADD_OFFSET(oletlsBaseAddress, UFIELD_OFFSET(SOleTlsData32, Flags));\n    else\n        apartmentStateOffset = PTR_ADD_OFFSET(oletlsBaseAddress, UFIELD_OFFSET(SOleTlsData, Flags));\n#else\n    apartmentStateOffset = PTR_ADD_OFFSET(oletlsBaseAddress, UFIELD_OFFSET(SOleTlsData, Flags));\n#endif\n\n    status = PhReadVirtualMemory(\n        ProcessHandle,\n        apartmentStateOffset,\n        ApartmentFlags,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (ComInits)\n    {\n        PVOID comInitsOffset;\n\n#ifdef _WIN64\n        if (isWow64)\n            comInitsOffset = PTR_ADD_OFFSET(oletlsBaseAddress, UFIELD_OFFSET(SOleTlsData32, ComInits));\n        else\n            comInitsOffset = PTR_ADD_OFFSET(oletlsBaseAddress, UFIELD_OFFSET(SOleTlsData, ComInits));\n#else\n        comInitsOffset = PTR_ADD_OFFSET(oletlsBaseAddress, UFIELD_OFFSET(SOleTlsData, ComInits));\n#endif\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            comInitsOffset,\n            ComInits,\n            sizeof(ULONG),\n            NULL\n            );\n    }\n\n    return status;\n}\n\n/**\n * Determines COM apartment type of a thread, similar to CoGetApartmentType.\n *\n * \\param[in] ThreadHandle A handle to the thread. The handle must have\n * THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param[in] ProcessHandle A handle to the process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param[out] ApartmentInfo The COM apartment information of the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadApartment(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_APARTMENT_INFO ApartmentInfo\n    )\n{\n    NTSTATUS status;\n    PH_APARTMENT_INFO info = { 0 };\n\n    //\n    // N.B. Most information about the thread's apartment comes from OLE TLS data in TEB.\n    // Without it, threads can still implicitly belong to the multi-threaded apartment (MTA)\n    // as long as one exists in the process. (diversenok)\n    //\n\n    // Read OLE TLS flags\n    status = PhGetThreadApartmentFlags(ThreadHandle, ProcessHandle, &info.Flags, &info.ComInits);\n\n    if (status == NTSTATUS_FROM_WIN32(CO_E_NOTINITIALIZED))\n    {\n        // For our purposes, no OLE TLS data is equivalent to empty flags\n        info.Flags = 0;\n        info.ComInits = 0;\n        status = STATUS_SUCCESS;\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (info.Flags & OLETLS_APARTMENTTHREADED)\n    {\n        //\n        // N.B. Single-threaded apartments (STAs) belong to one of the three sub-types:\n        //  - Main STA: the first (classic) STA created in the process. It has the responsibility of hosting\n        //    all components with no ThreadingModel and ThreadingModel=Single (which are equivalent).\n        //  - Classic STA: a reentrant single-threaded apartment, usually referred to as just STA.\n        //  - Application STA (ASTA): a non-reentrant single-threaded apartment used primarily by WinRT.\n        //\n\n        if (info.Flags & OLETLS_APPLICATION_STA)\n        {\n            // The non-reentrancy requirement of ASTA means it cannot serve as the main STA\n            info.Type = PH_APARTMENT_TYPE_APPLICATION_STA;\n        }\n        else\n        {\n            THREAD_BASIC_INFORMATION basicInfo;\n            BOOLEAN isMainSta = FALSE;\n\n            //\n            // N.B. There is no flag to distinguish between main and non-main classic STAs.\n            // Internally, CoGetApartmentType compares the caller's thread ID to the thread ID\n            // stored in a private global variable (which we cannot access). Instead, we can\n            // check if the specified thread owns the main STA window - a message-only window\n            // with a known class and name. (diversenok)\n            //\n\n            if (NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n            {\n\n                CLIENT_ID clientId;\n                HWND hwnd = NULL;\n\n                do\n                {\n                    // Find the next main STA window\n                    hwnd = FindWindowExW(\n                        HWND_MESSAGE,\n                        hwnd,\n                        L\"OleMainThreadWndClass\",\n                        L\"OleMainThreadWndName\"\n                        );\n\n                    // Check if it belongs to the specified thread ID\n                } while (hwnd && NT_SUCCESS(PhGetWindowClientId(hwnd, &clientId)) &&\n                    (clientId.UniqueProcess != basicInfo.ClientId.UniqueProcess ||\n                    clientId.UniqueThread != basicInfo.ClientId.UniqueThread));\n\n                isMainSta = !!hwnd;\n            }\n\n            info.Type = isMainSta ? PH_APARTMENT_TYPE_MAIN_STA : PH_APARTMENT_TYPE_STA;\n        }\n    }\n    else if (info.Flags & (OLETLS_MULTITHREADED | OLETLS_DISPATCHTHREAD))\n    {\n        // CoGetApartmentType treats explicit MTA threads and dispatch threads equally\n        info.Type = PH_APARTMENT_TYPE_MTA;\n    }\n    else\n    {\n        //\n        // N.B. The thread lacks an explicit apartment. A single MTA init, however, is\n        // enough to put all apartmentless threads into implicit MTA. The existence of MTA\n        // can be checked by reading the process-wide MTA usage counter. (diversenok)\n        //\n\n        if (!NT_SUCCESS(status = PhGetProcessMTAUsage(ProcessHandle, &info.ComInits, NULL)))\n            return status;\n\n        if (info.ComInits > 0)\n            info.Type = PH_APARTMENT_TYPE_IMPLICIT_MTA;\n        else\n            return NTSTATUS_FROM_WIN32(CO_E_NOTINITIALIZED);\n    }\n\n    //\n    // N.B. Threads can temporarily enter the neutral apartment on top of their existing apartment.\n    // Neutral apartment is often abbreviated to NA, NTA, or TNA. (diversenok)\n    //\n\n    info.InNeutral = !!(info.Flags & OLETLS_INNEUTRALAPT);\n\n    *ApartmentInfo = info;\n    return STATUS_SUCCESS;\n}\n\n// rev from advapi32!WctGetCOMInfo (dmex)\n/**\n * If a thread is blocked on a COM call, we can retrieve COM ownership information using these functions.\n * Retrieves COM information when a thread is blocked on a COM call.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[out] ApartmentCallState The COM call information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadApartmentCallState(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_COM_CALLSTATE ApartmentCallState\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n    PVOID oletlsBaseAddress = NULL;\n\n    if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return status;\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        ULONG oletlsDataAddress32 = 0;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(WOW64_GET_TEB32(basicInfo.TebBaseAddress), UFIELD_OFFSET(TEB32, ReservedForOle)),\n            &oletlsDataAddress32,\n            sizeof(ULONG),\n            NULL\n            );\n\n        oletlsBaseAddress = UlongToPtr(oletlsDataAddress32);\n    }\n    else\n#endif\n    {\n        ULONG_PTR oletlsDataAddress = 0;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.TebBaseAddress, UFIELD_OFFSET(TEB, ReservedForOle)),\n            &oletlsDataAddress,\n            sizeof(ULONG_PTR),\n            NULL\n            );\n\n        oletlsBaseAddress = (PVOID)oletlsDataAddress;\n    }\n\n    if (NT_SUCCESS(status) && oletlsBaseAddress)\n    {\n        typedef enum _CALL_STATE_TYPE\n        {\n            CALL_STATE_TYPE_OUTGOING, // tagOutgoingCallData\n            CALL_STATE_TYPE_INCOMING, // tagIncomingCallData\n            CALL_STATE_TYPE_ACTIVATION // tagOutgoingActivationData\n        } CALL_STATE_TYPE;\n        typedef struct tagOutgoingCallData // private\n        {\n            ULONG dwServerPID;\n            ULONG dwServerTID;\n        } tagOutgoingCallData, *PtagOutgoingCallData;\n        typedef struct tagIncomingCallData // private\n        {\n            ULONG dwClientPID;\n        } tagIncomingCallData, *PtagIncomingCallData;\n        typedef struct tagOutgoingActivationData // private\n        {\n            GUID guidServer;\n        } tagOutgoingActivationData, *PtagOutgoingActivationData;\n        static HRESULT (WINAPI* CoGetCallState_I)( // rev\n            _In_ CALL_STATE_TYPE Type,\n            _Out_ PULONG OffSet\n            ) = NULL;\n        //static HRESULT (WINAPI* CoGetActivationState_I)( // rev\n        //    _In_ LPCLSID Clsid,\n        //    _In_ ULONG ClientTid,\n        //    _Out_ PULONG ServerPid\n        //    ) = NULL;\n        static PH_INITONCE initOnce = PH_INITONCE_INIT;\n        ULONG outgoingCallDataOffset = 0;\n        ULONG incomingCallDataOffset = 0;\n        ULONG outgoingActivationDataOffset = 0;\n        tagOutgoingCallData outgoingCallData = { 0 };\n        tagIncomingCallData incomingCallData = { 0 };\n        tagOutgoingActivationData outgoingActivationData = { 0 };\n\n        if (PhBeginInitOnce(&initOnce))\n        {\n            PVOID baseAddress;\n\n            if (baseAddress = PhGetLoaderEntryDllBaseZ(L\"combase.dll\"))\n            {\n                CoGetCallState_I = PhGetDllBaseProcedureAddress(baseAddress, \"CoGetCallState\", 0);\n                //CoGetActivationState_I = PhGetDllBaseProcedureAddress(baseAddress, \"CoGetActivationState\", 0);\n            }\n\n            PhEndInitOnce(&initOnce);\n        }\n\n        if (HR_SUCCESS(CoGetCallState_I(CALL_STATE_TYPE_OUTGOING, &outgoingCallDataOffset)) && outgoingCallDataOffset)\n        {\n            PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(oletlsBaseAddress, outgoingCallDataOffset),\n                &outgoingCallData,\n                sizeof(tagOutgoingCallData),\n                NULL\n                );\n        }\n\n        if (HR_SUCCESS(CoGetCallState_I(CALL_STATE_TYPE_INCOMING, &incomingCallDataOffset)) && incomingCallDataOffset)\n        {\n            PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(oletlsBaseAddress, incomingCallDataOffset),\n                &incomingCallData,\n                sizeof(tagIncomingCallData),\n                NULL\n                );\n        }\n\n        if (HR_SUCCESS(CoGetCallState_I(CALL_STATE_TYPE_ACTIVATION, &outgoingActivationDataOffset)) && outgoingActivationDataOffset)\n        {\n            PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(oletlsBaseAddress, outgoingActivationDataOffset),\n                &outgoingActivationData,\n                sizeof(tagOutgoingActivationData),\n                NULL\n                );\n        }\n\n        memset(ApartmentCallState, 0, sizeof(PH_COM_CALLSTATE));\n        ApartmentCallState->ServerPID = outgoingCallData.dwServerPID != 0 ? outgoingCallData.dwServerPID : ULONG_MAX;\n        ApartmentCallState->ServerTID = outgoingCallData.dwServerTID != 0 ? outgoingCallData.dwServerTID : ULONG_MAX;\n        ApartmentCallState->ClientPID = incomingCallData.dwClientPID != 0 ? incomingCallData.dwClientPID : ULONG_MAX;\n        memcpy(&ApartmentCallState->ServerGuid, &outgoingActivationData.guidServer, sizeof(GUID));\n    }\n    else\n    {\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    return status;\n}\n\n/**\n * Determines if a thread has an associated RPC state.\n *\n * \\param[in] ThreadHandle A handle to the thread. The handle must have\n * THREAD_QUERY_LIMITED_INFORMATION access.\n * \\param[in] ProcessHandle A handle to the process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param[out] HasRpcState Whether the thread has allocated RPC state.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadRpcState(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN HasRpcState\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n\n    if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return status;\n\n#ifdef _WIN64\n    if (!NT_SUCCESS(status = PhGetProcessIsWow64(ProcessHandle, &isWow64)))\n        return status;\n\n    if (isWow64)\n    {\n        typeof(RTL_FIELD_TYPE(TEB32, ReservedForNtRpc)) reservedForNtRpc32 = 0;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(WOW64_GET_TEB32(basicInfo.TebBaseAddress), UFIELD_OFFSET(TEB32, ReservedForNtRpc)),\n            &reservedForNtRpc32,\n            sizeof(RTL_FIELD_TYPE(TEB32, ReservedForNtRpc)),\n            NULL\n            );\n\n        *HasRpcState = !!reservedForNtRpc32;\n    }\n    else\n#endif\n    {\n        typeof(RTL_FIELD_TYPE(TEB, ReservedForNtRpc)) reservedForNtRpc = NULL;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.TebBaseAddress, UFIELD_OFFSET(TEB, ReservedForNtRpc)),\n            &reservedForNtRpc,\n            sizeof(RTL_FIELD_TYPE(TEB, ReservedForNtRpc)),\n            NULL\n            );\n\n        *HasRpcState = !!reservedForNtRpc;\n    }\n\n    return status;\n}\n\n// rev from advapi32!WctGetCritSecInfo (dmex)\n/**\n * Retrieves the thread identifier when a thread is blocked on a critical section.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[in] ProcessId The ID of a process.\n * \\param[out] ThreadId The ID of the thread owning the critical section.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadCriticalSectionOwnerThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessId,\n    _Out_ PULONG ThreadId\n    )\n{\n    NTSTATUS status;\n    PRTL_DEBUG_INFORMATION debugBuffer;\n\n    if (WindowsVersion < WINDOWS_11)\n        return STATUS_UNSUCCESSFUL;\n\n    if (!(debugBuffer = RtlCreateQueryDebugBuffer(0, FALSE)))\n        return STATUS_UNSUCCESSFUL;\n\n    debugBuffer->CriticalSectionOwnerThread = ThreadHandle;\n\n    status = RtlQueryProcessDebugInformation(\n        ProcessId,\n        RTL_QUERY_PROCESS_NONINVASIVE_CS_OWNER, // TODO: RTL_QUERY_PROCESS_CS_OWNER (dmex)\n        debugBuffer\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        RtlDestroyQueryDebugBuffer(debugBuffer);\n        return status;\n    }\n\n    if (!debugBuffer->Reserved[0])\n    {\n        RtlDestroyQueryDebugBuffer(debugBuffer);\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    *ThreadId = PtrToUlong(debugBuffer->Reserved[0]);\n\n    RtlDestroyQueryDebugBuffer(debugBuffer);\n\n    return STATUS_SUCCESS;\n}\n\n// rev from advapi32!WctGetSocketInfo (dmex)\n/**\n * Retrieves the connection state when a thread is blocked on a socket.\n *\n * \\param[in] ThreadHandle A handle to the thread.\n * \\param[in] ProcessHandle A handle to a process.\n * \\param[out] ThreadSocketState The state of the socket.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadSocketState(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_THREAD_SOCKET_STATE ThreadSocketState\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n    typeof(RTL_FIELD_TYPE(TEB, WinSockData)) winsockHandleAddress = NULL;\n\n    if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return status;\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        typeof(RTL_FIELD_TYPE(TEB32, WinSockData)) winsockDataAddress = 0;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(WOW64_GET_TEB32(basicInfo.TebBaseAddress), UFIELD_OFFSET(TEB32, WinSockData)),\n            &winsockDataAddress,\n            sizeof(RTL_FIELD_TYPE(TEB32, WinSockData)),\n            NULL\n            );\n\n        winsockHandleAddress = UlongToHandle(winsockDataAddress);\n    }\n    else\n#endif\n    {\n        typeof(RTL_FIELD_TYPE(TEB, WinSockData)) winsockDataAddress = NULL;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.TebBaseAddress, UFIELD_OFFSET(TEB, WinSockData)),\n            &winsockDataAddress,\n            sizeof(RTL_FIELD_TYPE(TEB, WinSockData)),\n            NULL\n            );\n\n        winsockHandleAddress = winsockDataAddress;\n    }\n\n    if (NT_SUCCESS(status) && winsockHandleAddress)\n    {\n#if defined(PHLIB_SOCKET_STATE_WINSOCK)\n        static LONG (WINAPI* LPFN_WSASTARTUP)(\n            _In_ WORD wVersionRequested,\n            _Out_ PVOID* lpWSAData\n            );\n        static LONG (WINAPI* LPFN_GETSOCKOPT)(\n            _In_ UINT_PTR s,\n            _In_ LONG level,\n            _In_ LONG optname,\n            _Out_writes_bytes_(*optlen) char FAR* optval,\n            _Inout_ LONG FAR* optlen\n            );\n        static LONG (WINAPI* LPFN_CLOSESOCKET)(\n            _In_ ULONG_PTR s\n            );\n        static LONG (WINAPI* LPFN_WSACLEANUP)(\n            void\n            );\n        static PH_INITONCE initOnce = PH_INITONCE_INIT;\n        #ifndef WINSOCK_VERSION\n        #define WINSOCK_VERSION MAKEWORD(2,2)\n        #endif\n        #ifndef SOCKET_ERROR\n        #define SOCKET_ERROR (-1)\n        #endif\n        #ifndef SOL_SOCKET\n        #define SOL_SOCKET 0xffff\n        #endif\n        #ifndef SO_BSP_STATE\n        #define SO_BSP_STATE 0x1009\n        #endif\n        typedef struct _SOCKET_ADDRESS\n        {\n            _Field_size_bytes_(iSockaddrLength) PVOID lpSockaddr;\n            // _When_(lpSockaddr->sa_family == AF_INET, _Field_range_(>=, sizeof(SOCKADDR_IN)))\n            // _When_(lpSockaddr->sa_family == AF_INET6, _Field_range_(>=, sizeof(SOCKADDR_IN6)))\n            LONG iSockaddrLength;\n        } SOCKET_ADDRESS, *PSOCKET_ADDRESS, *LPSOCKET_ADDRESS;\n        typedef struct _CSADDR_INFO\n        {\n            SOCKET_ADDRESS LocalAddr;\n            SOCKET_ADDRESS RemoteAddr;\n            LONG iSocketType;\n            LONG iProtocol;\n        } CSADDR_INFO, *PCSADDR_INFO, FAR* LPCSADDR_INFO;\n        PVOID wsaStartupData;\n#endif\n        HANDLE winsockTargetHandle;\n\n#if defined(PHLIB_SOCKET_STATE_WINSOCK)\n        if (PhBeginInitOnce(&initOnce))\n        {\n            PVOID baseAddress;\n\n            if (baseAddress = PhLoadLibrary(L\"ws2_32.dll\"))\n            {\n                LPFN_WSASTARTUP = PhGetDllBaseProcedureAddress(baseAddress, \"WSAStartup\", 0);\n                LPFN_GETSOCKOPT = PhGetDllBaseProcedureAddress(baseAddress, \"getsockopt\", 0);\n                //LPFN_GETSOCKNAME = PhGetDllBaseProcedureAddress(baseAddress, \"getsockname\", 0);\n                //LPFN_GETPEERNAME = PhGetDllBaseProcedureAddress(baseAddress, \"getpeername\", 0);\n                LPFN_CLOSESOCKET = PhGetDllBaseProcedureAddress(baseAddress, \"closesocket\", 0);\n                LPFN_WSACLEANUP = PhGetDllBaseProcedureAddress(baseAddress, \"WSACleanup\", 0);\n            }\n\n            PhEndInitOnce(&initOnce);\n        }\n\n        if (LPFN_WSASTARTUP(WINSOCK_VERSION, &wsaStartupData) != 0)\n        {\n            status = STATUS_UNSUCCESSFUL;\n            goto CleanupExit;\n        }\n#endif\n        status = NtDuplicateObject(\n            ProcessHandle,\n            winsockHandleAddress,\n            NtCurrentProcess(),\n            &winsockTargetHandle,\n            0,\n            0,\n            DUPLICATE_SAME_ACCESS\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            OBJECT_BASIC_INFORMATION winsockTargetBasicInfo;\n\n            status = PhGetObjectBasicInformation(\n                ProcessHandle,\n                winsockTargetHandle,\n                &winsockTargetBasicInfo\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                ULONG winsockAddressInfoLength = sizeof(CSADDR_INFO);\n                CSADDR_INFO winsockAddressInfo;\n\n                status = PhAfdQuerySocketOption(\n                    winsockTargetHandle,\n                    SOL_SOCKET,\n                    SO_BSP_STATE,\n                    &winsockAddressInfo,\n                    winsockAddressInfoLength,\n                    &winsockAddressInfoLength\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    if (winsockAddressInfo.iProtocol == 6)\n                    {\n                        if (winsockAddressInfo.LocalAddr.lpSockaddr && winsockAddressInfo.RemoteAddr.lpSockaddr)\n                            *ThreadSocketState = PH_THREAD_SOCKET_STATE_SHARED;\n                        else\n                            *ThreadSocketState = PH_THREAD_SOCKET_STATE_DISCONNECTED;\n                    }\n                    else\n                    {\n                        *ThreadSocketState = PH_THREAD_SOCKET_STATE_NOT_TCPIP;\n                    }\n                }\n\n#if defined(PHLIB_SOCKET_STATE_WINSOCK)\n                if (LPFN_GETSOCKOPT((UINT_PTR)winsockTargetHandle, SOL_SOCKET, SO_BSP_STATE, (PCHAR)&winsockAddressInfo, &winsockAddressInfoLength) != SOCKET_ERROR)\n                {\n                    if (winsockAddressInfo.iProtocol == 6)\n                    {\n                        if (winsockAddressInfo.LocalAddr.lpSockaddr && winsockAddressInfo.RemoteAddr.lpSockaddr)\n                            *ThreadSocketState = PH_THREAD_SOCKET_STATE_SHARED;\n                        else\n                            *ThreadSocketState = PH_THREAD_SOCKET_STATE_DISCONNECTED;\n                    }\n                    else\n                        *ThreadSocketState = PH_THREAD_SOCKET_STATE_NOT_TCPIP;\n                }\n                else\n                {\n                    status = STATUS_UNSUCCESSFUL; // WSAGetLastError();\n                }\n#endif\n            }\n#if defined(PHLIB_SOCKET_STATE_WINSOCK)\n            LPFN_CLOSESOCKET((UINT_PTR)winsockTargetHandle);\n#endif\n            NtClose(winsockTargetHandle);\n        }\n#if defined(PHLIB_SOCKET_STATE_WINSOCK)\n        LPFN_WSACLEANUP();\n#endif\n    }\n    else\n    {\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves stack base/limit pointers for a thread.\n *\n * \\param[in] ThreadHandle Thread handle.\n * \\param[in] ProcessHandle Process handle.\n * \\param[out] LowPart Receives stack base address.\n * \\param[out] HighPart Receives stack limit address.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadStackLimits(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG_PTR LowPart,\n    _Out_ PULONG_PTR HighPart\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n    PVOID stackBaseAddress;\n    PVOID stackLimitAddress;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n\n    if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return status;\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        typeof(RTL_FIELD_TYPE(TEB32, NtTib)) ntTib32 = { 0 };\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(WOW64_GET_TEB32(basicInfo.TebBaseAddress), UFIELD_OFFSET(TEB32, NtTib)),\n            &ntTib32,\n            sizeof(RTL_FIELD_TYPE(TEB32, NtTib)),\n            NULL\n            );\n\n        stackBaseAddress = UlongToPtr(ntTib32.StackBase);\n        stackLimitAddress = UlongToPtr(ntTib32.StackLimit);\n    }\n    else\n#endif\n    {\n        typeof(RTL_FIELD_TYPE(TEB, NtTib)) ntTib = { 0 };\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.TebBaseAddress, UFIELD_OFFSET(TEB, NtTib)),\n            &ntTib,\n            sizeof(RTL_FIELD_TYPE(TEB, NtTib)),\n            NULL\n            );\n\n        stackBaseAddress = ntTib.StackBase;\n        stackLimitAddress = ntTib.StackLimit;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *LowPart = (ULONG_PTR)stackBaseAddress;\n        *HighPart = (ULONG_PTR)stackLimitAddress;\n    }\n\n    return status;\n}\n\n/**\n * Computes stack usage and total reserved size for a thread.\n *\n * \\param[in] ThreadHandle Thread handle.\n * \\param[in] ProcessHandle Process handle.\n * \\param[out] StackUsage Bytes currently committed (base - limit).\n * \\param[out] StackLimit Total reserved size (base - allocation base).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadStackSize(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG_PTR StackUsage,\n    _Out_ PULONG_PTR StackLimit\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n    PVOID stackBaseAddress;\n    PVOID stackLimitAddress;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n\n    if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return status;\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        typeof(RTL_FIELD_TYPE(TEB32, NtTib)) ntTib32 = { 0 };\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(WOW64_GET_TEB32(basicInfo.TebBaseAddress), UFIELD_OFFSET(TEB32, NtTib)),\n            &ntTib32,\n            sizeof(RTL_FIELD_TYPE(TEB32, NtTib)),\n            NULL\n            );\n\n        stackBaseAddress = UlongToPtr(ntTib32.StackBase);\n        stackLimitAddress = UlongToPtr(ntTib32.StackLimit);\n    }\n    else\n#endif\n    {\n        typeof(RTL_FIELD_TYPE(TEB, NtTib)) ntTib = { 0 };\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.TebBaseAddress, UFIELD_OFFSET(TEB, NtTib)),\n            &ntTib,\n            sizeof(RTL_FIELD_TYPE(TEB, NtTib)),\n            NULL\n            );\n\n        stackBaseAddress = ntTib.StackBase;\n        stackLimitAddress = ntTib.StackLimit;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        MEMORY_BASIC_INFORMATION memoryBasicInformation;\n\n        memset(&memoryBasicInformation, 0, sizeof(MEMORY_BASIC_INFORMATION));\n\n        status = NtQueryVirtualMemory(\n            ProcessHandle,\n            stackLimitAddress,\n            MemoryBasicInformation,\n            &memoryBasicInformation,\n            sizeof(MEMORY_BASIC_INFORMATION),\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // TEB->DeallocationStack == memoryBasicInfo.AllocationBase\n            *StackUsage = (ULONG_PTR)PTR_SUB_OFFSET(stackBaseAddress, stackLimitAddress);\n            *StackLimit = (ULONG_PTR)PTR_SUB_OFFSET(stackBaseAddress, memoryBasicInformation.AllocationBase);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Determines whether a thread has fiber data.\n *\n * \\param[in] ThreadHandle Thread handle.\n * \\param[in] ProcessHandle Process handle.\n * \\param[out] ThreadIsFiber TRUE if fiber data present.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadIsFiber(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN ThreadIsFiber\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n    BOOLEAN threadIsFiber;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n\n    if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return status;\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        typeof(RTL_FIELD_TYPE(TEB32, SameTebFlags)) flags = 0;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(WOW64_GET_TEB32(basicInfo.TebBaseAddress), UFIELD_OFFSET(TEB32, SameTebFlags)),\n            &flags,\n            sizeof(RTL_FIELD_TYPE(TEB32, SameTebFlags)),\n            NULL\n            );\n\n        threadIsFiber = _bittest((LONG CONST*)&flags, 2); // HasFiberData offset (dmex)\n    }\n    else\n#endif\n    {\n        typeof(RTL_FIELD_TYPE(TEB, SameTebFlags)) flags = 0;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.TebBaseAddress, UFIELD_OFFSET(TEB, SameTebFlags)),\n            &flags,\n            sizeof(RTL_FIELD_TYPE(TEB, SameTebFlags)),\n            NULL\n            );\n\n        threadIsFiber = _bittest((LONG CONST*)&flags, 2); // HasFiberData offset (dmex)\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *ThreadIsFiber = threadIsFiber;\n    }\n\n    return status;\n}\n\n// rev from SwitchToThread (dmex)\n/**\n * Causes the calling thread to yield execution to another thread that is ready to run on the\n * current processor. The operating system selects the next thread to be executed.\n *\n * \\remarks The operating system will not switch execution to another processor, even if that processor is idle or is running a thread of lower priority.\n * \\return If calling the SwitchToThread function caused the operating system to switch execution to another thread, the return value is nonzero.\n * \\rthere are no other threads ready to execute, the operating system does not switch execution to another thread, and the return value is zero.\n */\nBOOLEAN PhSwitchToThread(\n    VOID\n    )\n{\n    LARGE_INTEGER interval = { 0 };\n\n    return PhDelayExecutionEx(FALSE, &interval) != STATUS_NO_YIELD_PERFORMED;\n}\n\n/**\n * Determines runtime library path set (ntdll/kernel32/user32) for a process,\n * including WOW64/ARM32 variants.\n *\n * \\param[in] ProcessHandle Process handle.\n * \\param[out] RuntimeLibrary Receives pointer to predefined library set.\n * \\param[out] IsWow64Process TRUE if target is WOW64/alternate architecture.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessRuntimeLibrary(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_RUNTIME_LIBRARY* RuntimeLibrary,\n    _Out_opt_ PBOOLEAN IsWow64Process\n    )\n{\n    static PH_PROCESS_RUNTIME_LIBRARY NativeRuntime =\n    {\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\ntdll.dll\"),\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\kernel32.dll\"),\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\System32\\\\user32.dll\"),\n    };\n#ifdef _WIN64\n    static PH_PROCESS_RUNTIME_LIBRARY Wow64Runtime =\n    {\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\SysWOW64\\\\ntdll.dll\"),\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\SysWOW64\\\\kernel32.dll\"),\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\SysWOW64\\\\user32.dll\"),\n    };\n#ifdef _M_ARM64\n    static PH_PROCESS_RUNTIME_LIBRARY Arm32Runtime =\n    {\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\SysArm32\\\\ntdll.dll\"),\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\SysArm32\\\\kernel32.dll\"),\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\SysArm32\\\\user32.dll\"),\n    };\n    static PH_PROCESS_RUNTIME_LIBRARY Chpe32Runtime =\n    {\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\SyChpe32\\\\ntdll.dll\"),\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\SyChpe32\\\\kernel32.dll\"),\n        PH_STRINGREF_INIT(L\"\\\\SystemRoot\\\\SyChpe32\\\\user32.dll\"),\n    };\n#endif\n#endif\n\n    *RuntimeLibrary = &NativeRuntime;\n\n    if (IsWow64Process)\n        *IsWow64Process = FALSE;\n\n#ifdef _WIN64\n    NTSTATUS status;\n#ifdef _M_ARM64\n    USHORT machine;\n\n    status = PhGetProcessArchitecture(ProcessHandle, &machine);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (machine != IMAGE_FILE_MACHINE_TARGET_HOST)\n    {\n        switch (machine)\n        {\n        case IMAGE_FILE_MACHINE_I386:\n        case IMAGE_FILE_MACHINE_CHPE_X86:\n            {\n                *RuntimeLibrary = &Chpe32Runtime;\n\n                if (IsWow64Process)\n                    *IsWow64Process = TRUE;\n            }\n            break;\n        case IMAGE_FILE_MACHINE_ARMNT:\n            {\n                *RuntimeLibrary = &Arm32Runtime;\n\n                if (IsWow64Process)\n                    *IsWow64Process = TRUE;\n            }\n            break;\n        case IMAGE_FILE_MACHINE_AMD64:\n        case IMAGE_FILE_MACHINE_ARM64:\n            break;\n        default:\n            return STATUS_INVALID_PARAMETER;\n        }\n    }\n#else\n    BOOLEAN isWow64 = FALSE;\n\n    status = PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (isWow64)\n    {\n        *RuntimeLibrary = &Wow64Runtime;\n\n        if (IsWow64Process)\n            *IsWow64Process = TRUE;\n    }\n#endif\n#endif\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Loads the specified module into the process's address space using standard LoadLibraryW provided\n * by the operating system.\n *\n * \\param[in] ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ\n * and PROCESS_VM_WRITE access.\n * \\param[in] FileName The file name of the DLL to inject.\n * \\param[in] Timeout The timeout, in milliseconds, for the process to load the DLL.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks If the process does not load the DLL before the timeout expires it may crash. Choose the\n * timeout value carefully.\n */\nNTSTATUS PhLoadDllProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_STRINGREF FileName,\n    _In_opt_ ULONG Timeout\n    )\n{\n    NTSTATUS status;\n    PVOID fileNameBaseAddress = NULL;\n    PVOID loadLibraryW = NULL;\n    HANDLE threadHandle = NULL;\n    HANDLE powerRequestHandle = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n\n    if (KphProcessLevel(ProcessHandle) > KphLevelMed)\n    {\n        return STATUS_ACCESS_DENIED;\n    }\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->Kernel32FileName,\n        \"LoadLibraryW\",\n        &loadLibraryW,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhAllocateVirtualMemory(\n        ProcessHandle,\n        &fileNameBaseAddress,\n        FileName->Length + sizeof(UNICODE_NULL),\n        MEM_COMMIT,\n        PAGE_READWRITE\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhWriteVirtualMemory(\n        ProcessHandle,\n        fileNameBaseAddress,\n        FileName->Buffer,\n        FileName->Length + sizeof(UNICODE_NULL),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        0,\n        0,\n        0,\n        0,\n        loadLibraryW,\n        fileNameBaseAddress,\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhWaitForSingleObject(threadHandle, Timeout);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\nCleanupExit:\n    if (threadHandle)\n        NtClose(threadHandle);\n\n    if (powerRequestHandle)\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n\n    if (fileNameBaseAddress)\n        PhFreeVirtualMemory(ProcessHandle, fileNameBaseAddress, MEM_RELEASE);\n\n    return status;\n}\n\n/**\n * Loads the specified module into the process's address space using standard Asynchronous Procedure Call (APC)\n * routines provided by the operating system.\n *\n * \\param[in] ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ\n * and PROCESS_VM_WRITE access.\n * \\param[in] FileName The file name of the DLL to inject.\n * \\param[in]Timeout The timeout, in milliseconds, for the process to load the DLL.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks If the process does not load the DLL before the timeout expires it may crash. Choose the\n * timeout value carefully.\n */\nNTSTATUS PhLoadDllProcessApcThread(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_STRINGREF FileName,\n    _In_opt_ ULONG Timeout\n    )\n{\n    NTSTATUS status;\n    PVOID fileNameBaseAddress = NULL;\n    PVOID loadLibraryW = NULL;\n    PVOID rtlExitUserThread = NULL;\n    HANDLE threadHandle = NULL;\n    HANDLE powerRequestHandle = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n\n    if (KphProcessLevel(ProcessHandle) > KphLevelMed)\n    {\n        return STATUS_ACCESS_DENIED;\n    }\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->Kernel32FileName,\n        \"LoadLibraryW\",\n        &loadLibraryW,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->NtdllFileName,\n        \"RtlExitUserThread\",\n        &rtlExitUserThread,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhAllocateVirtualMemory(\n        ProcessHandle,\n        &fileNameBaseAddress,\n        FileName->Length + sizeof(UNICODE_NULL),\n        MEM_COMMIT,\n        PAGE_READWRITE\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhWriteVirtualMemory(\n        ProcessHandle,\n        fileNameBaseAddress,\n        FileName->Buffer,\n        FileName->Length + sizeof(UNICODE_NULL),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        THREAD_CREATE_FLAGS_CREATE_SUSPENDED,\n        0,\n        0,\n        0,\n        rtlExitUserThread,\n        LongToPtr(STATUS_SUCCESS),\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtQueueApcThread(\n        threadHandle,\n        loadLibraryW,\n        fileNameBaseAddress,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhWaitForSingleObject(threadHandle, Timeout);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\nCleanupExit:\n    if (threadHandle)\n        NtClose(threadHandle);\n\n    if (powerRequestHandle)\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n\n    if (fileNameBaseAddress)\n        PhFreeVirtualMemory(ProcessHandle, fileNameBaseAddress, MEM_RELEASE);\n\n    return status;\n}\n\n/**\n * Causes a process to unload a DLL.\n *\n * \\param[in] ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ\n * and PROCESS_VM_WRITE access.\n * \\param[in]BaseAddress The base address of the DLL to unload.\n * \\param[in] Timeout The timeout, in milliseconds, for the process to unload the DLL.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhUnloadDllProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_opt_ ULONG Timeout\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n    HANDLE powerRequestHandle = NULL;\n    THREAD_BASIC_INFORMATION basicInfo;\n    PVOID freeLibrary = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // No point trying to set the load count on Windows 8 and higher, because NT now uses a DAG of\n    // loader nodes. (wj32)\n    if (WindowsVersion < WINDOWS_8)\n    {\n#ifdef _WIN64\n        BOOLEAN isWow64 = FALSE;\n#endif\n        status = PhSetProcessModuleLoadCount(\n            ProcessHandle,\n            BaseAddress,\n            1\n            );\n\n#ifdef _WIN64\n        PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n        if (isWow64 && status == STATUS_DLL_NOT_FOUND)\n        {\n            // The DLL might be 32-bit.\n            status = PhSetProcessModuleLoadCount32(\n                ProcessHandle,\n                BaseAddress,\n                1\n                );\n        }\n#endif\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->Kernel32FileName,\n        \"FreeLibrary\",\n        &freeLibrary,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        0,\n        0,\n        0,\n        0,\n        freeLibrary,\n        BaseAddress,\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhWaitForSingleObject(threadHandle, Timeout);\n\n    if (status == STATUS_WAIT_0)\n    {\n        status = PhGetThreadBasicInformation(threadHandle, &basicInfo);\n\n        if (NT_SUCCESS(status))\n            status = basicInfo.ExitStatus;\n    }\n\n    NtClose(threadHandle);\n\n    if (powerRequestHandle)\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n\n    return status;\n}\n\n/**\n * Sets an environment variable in a process.\n *\n * \\param[in] ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ\n * and PROCESS_VM_WRITE access.\n * \\param[in] Name The name of the environment variable to set.\n * \\param[in] Value The new value of the environment variable. If this parameter is NULL, the\n * environment variable is deleted.\n * \\param[in] Timeout The timeout, in milliseconds, for the process to set the environment variable.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetEnvironmentVariableRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_STRINGREF Name,\n    _In_opt_ PPH_STRINGREF Value,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInformation;\n    PVOID nameBaseAddress = NULL;\n    PVOID valueBaseAddress = NULL;\n    SIZE_T nameAllocationSize = 0;\n    SIZE_T valueAllocationSize = 0;\n    PVOID rtlExitUserThread = NULL;\n    PVOID setEnvironmentVariableW = NULL;\n    HANDLE threadHandle = NULL;\n    HANDLE powerRequestHandle = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n\n    nameAllocationSize = Name->Length + sizeof(UNICODE_NULL);\n\n    if (Value)\n        valueAllocationSize = Value->Length + sizeof(UNICODE_NULL);\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n#ifdef _WIN64\n        &isWow64\n#else\n        NULL\n#endif\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->NtdllFileName,\n        \"RtlExitUserThread\",\n        &rtlExitUserThread,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->Kernel32FileName,\n        \"SetEnvironmentVariableW\",\n        &setEnvironmentVariableW,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhAllocateVirtualMemory(\n        ProcessHandle,\n        &nameBaseAddress,\n        nameAllocationSize,\n        MEM_COMMIT,\n        PAGE_READWRITE\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhWriteVirtualMemory(\n        ProcessHandle,\n        nameBaseAddress,\n        Name->Buffer,\n        Name->Length,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (Value)\n    {\n        status = PhAllocateVirtualMemory(\n            ProcessHandle,\n            &valueBaseAddress,\n            valueAllocationSize,\n            MEM_COMMIT,\n            PAGE_READWRITE\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhWriteVirtualMemory(\n            ProcessHandle,\n            valueBaseAddress,\n            Value->Buffer,\n            Value->Length,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        THREAD_CREATE_FLAGS_CREATE_SUSPENDED,\n        0,\n        0,\n        0,\n        rtlExitUserThread,\n        LongToPtr(STATUS_SUCCESS),\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n#ifdef _WIN64\n    if (isWow64)\n    {\n        status = RtlQueueApcWow64Thread(\n            threadHandle,\n            setEnvironmentVariableW,\n            nameBaseAddress,\n            valueBaseAddress,\n            NULL\n            );\n    }\n    else\n    {\n#endif\n        status = NtQueueApcThread(\n            threadHandle,\n            setEnvironmentVariableW,\n            nameBaseAddress,\n            valueBaseAddress,\n            NULL\n            );\n#ifdef _WIN64\n    }\n#endif\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtResumeThread(threadHandle, NULL); // Execute the pending APC (dmex)\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtWaitForSingleObject(threadHandle, FALSE, Timeout);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetThreadBasicInformation(threadHandle, &basicInformation);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = basicInformation.ExitStatus;\n\nCleanupExit:\n\n    if (threadHandle)\n    {\n        NtClose(threadHandle);\n    }\n\n    if (powerRequestHandle)\n    {\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n    }\n\n    if (nameBaseAddress)\n    {\n        nameAllocationSize = 0;\n        NtFreeVirtualMemory(\n            ProcessHandle,\n            &nameBaseAddress,\n            &nameAllocationSize,\n            MEM_RELEASE\n            );\n    }\n\n    if (valueBaseAddress)\n    {\n        valueAllocationSize = 0;\n        NtFreeVirtualMemory(\n            ProcessHandle,\n            &valueBaseAddress,\n            &valueAllocationSize,\n            MEM_RELEASE\n            );\n    }\n\n    return status;\n}\n\n// based on https://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547 (dmex)\n/**\n * Safe process termination via remote RtlExitUserProcess in the context of the remote process.\n *\n * \\param[in] ProcessHandle A handle to the process to be terminated.\n * \\param[in] ExitStatus The exit status code to be used when terminating the process.\n * \\param[in] Timeout Optional. The timeout, in milliseconds, to wait for the termination thread to complete.\n * If NULL, the function will wait indefinitely.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function attempts to terminate the specified process by creating a remote thread\n * that calls RtlExitUserProcess. On Windows 8 and later, it creates an execution required power request\n * to prevent deadlocks during the termination operation. The function cleans up any handles it creates before returning.\n */\nNTSTATUS PhTerminateProcessAlternative(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus,\n    _In_opt_ ULONG Timeout\n    )\n{\n    NTSTATUS status;\n    PVOID rtlExitUserProcess = NULL;\n    HANDLE powerRequestHandle = NULL;\n    HANDLE threadHandle = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->NtdllFileName,\n        \"RtlExitUserProcess\",\n        &rtlExitUserProcess,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        0,\n        0,\n        0,\n        0,\n        rtlExitUserProcess,\n        LongToPtr(ExitStatus),\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhWaitForSingleObject(threadHandle, Timeout);\n\nCleanupExit:\n\n    if (threadHandle)\n    {\n        NtClose(threadHandle);\n    }\n\n    if (powerRequestHandle)\n    {\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves a copy of the system DLL init block for the process.\n *\n * \\param[in] ProcessHandle A handle to the process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param[out] SystemDllInitBlock A buffer for a version-independent copy of LdrSystemDllInitBlock.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessSystemDllInitBlock(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPS_SYSTEM_DLL_INIT_BLOCK SystemDllInitBlock\n    )\n{\n    NTSTATUS status;\n    PS_SYSTEM_DLL_INIT_BLOCK systemDllInitBlock = { 0 };\n    PVOID ldrSystemDllInitBlockAddress;\n    ULONG expectedSize;\n\n    // N.B. Aside from having three revisions, PS_SYSTEM_DLL_INIT_BLOCK\n    // has different fields available on different OS versions. Determine\n    // the maximum number of bytes we can read. (diversenok)\n\n    if (WindowsVersion >= WINDOWS_11_24H2)\n        expectedSize = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V3);\n    else if (WindowsVersion >= PHNT_WINDOWS_10_20H1)\n        expectedSize = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK_V3, MitigationAuditOptionsMap);\n    else if (WindowsVersion >= PHNT_WINDOWS_10_RS3)\n        expectedSize = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V2);\n    else if (WindowsVersion >= PHNT_WINDOWS_10_RS2)\n        expectedSize = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK_V2, Wow64CfgBitMapSize);\n    else if (WindowsVersion >= PHNT_WINDOWS_10)\n        expectedSize = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V1);\n    else if (WindowsVersion >= PHNT_WINDOWS_8_1)\n        expectedSize = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK_V1, CfgBitMapSize);\n    else if (WindowsVersion >= PHNT_WINDOWS_8)\n        expectedSize = RTL_SIZEOF_THROUGH_FIELD(PS_SYSTEM_DLL_INIT_BLOCK_V1, MitigationOptions);\n    else\n        return STATUS_NOT_SUPPORTED;\n\n    status = PhGetProcedureAddressRemoteZ(\n        ProcessHandle,\n        L\"\\\\SystemRoot\\\\System32\\\\ntdll.dll\",\n        \"LdrSystemDllInitBlock\",\n        &ldrSystemDllInitBlockAddress,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhReadVirtualMemory(\n        ProcessHandle,\n        ldrSystemDllInitBlockAddress,\n        &systemDllInitBlock,\n        expectedSize,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (systemDllInitBlock.Size > expectedSize)\n        systemDllInitBlock.Size = expectedSize;\n\n    status = PhCaptureSystemDllInitBlock(\n        &systemDllInitBlock,\n        SystemDllInitBlock\n        );\n\n    return status;\n}\n\n/**\n * Retrieves the CrossProcessFlags from the target process's PEB (Process Environment Block).\n *\n * \\param[in] ProcessHandle Handle to the process whose cross-process flags are to be retrieved.\n * \\param[in] ProcessFlags Pointer to a ULONG variable that receives the cross-process flags.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessCrossProcessFlags(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ProcessFlags\n    )\n{\n    NTSTATUS status;\n    ULONG crossProcessFlags = 0;\n    PVOID pebBaseAddress;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (isWow64)\n    {\n        status = PhGetProcessPeb32(ProcessHandle, &pebBaseAddress);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB32, CrossProcessFlags)),\n            &crossProcessFlags,\n            sizeof(ULONG),\n            NULL\n            );\n    }\n    else\n#endif\n    {\n        status = PhGetProcessPeb(ProcessHandle, &pebBaseAddress);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB, CrossProcessFlags)),\n            &crossProcessFlags,\n            sizeof(ULONG),\n            NULL\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *ProcessFlags = crossProcessFlags;\n    }\n\nCleanupExit:\n    return status;\n}\n\n/**\n * Retrieves the active ANSI code page of a process (PEB ActiveCodePage or ntdll variable).\n *\n * \\param[in] ProcessHandle Process handle.\n * \\param[out] ProcessCodePage Receives code page ID.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessCodePage(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PUSHORT ProcessCodePage\n    )\n{\n    NTSTATUS status;\n    USHORT codePage = 0;\n\n    if (WindowsVersion >= WINDOWS_11)\n    {\n        PVOID pebBaseAddress;\n#ifdef _WIN64\n        BOOLEAN isWow64 = FALSE;\n\n        PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n        if (isWow64)\n        {\n            status = PhGetProcessPeb32(ProcessHandle, &pebBaseAddress);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB32, ActiveCodePage)),\n                &codePage,\n                sizeof(USHORT),\n                NULL\n                );\n        }\n        else\n#endif\n        {\n            status = PhGetProcessPeb(ProcessHandle, &pebBaseAddress);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhReadVirtualMemory(\n                ProcessHandle,\n                PTR_ADD_OFFSET(pebBaseAddress, UFIELD_OFFSET(PEB, ActiveCodePage)),\n                &codePage,\n                sizeof(USHORT),\n                NULL\n                );\n        }\n    }\n    else\n    {\n        PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n        PVOID nlsAnsiCodePage;\n\n        status = PhGetProcessRuntimeLibrary(\n            ProcessHandle,\n            &runtimeLibrary,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetProcedureAddressRemote(\n            ProcessHandle,\n            &runtimeLibrary->NtdllFileName,\n            \"NlsAnsiCodePage\",\n            &nlsAnsiCodePage,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            nlsAnsiCodePage,\n            &codePage,\n            sizeof(USHORT),\n            NULL\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *ProcessCodePage = codePage;\n    }\n\nCleanupExit:\n    return status;\n}\n\n/**\n * Executes GetConsoleCP or GetConsoleOutputCP inside remote process and returns its code page.\n *\n * \\param[in] ProcessHandle Target process.\n * \\param[in] ConsoleOutputCP TRUE for output, FALSE for input code page.\n * \\param[out] ConsoleCodePage Receives code page.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessConsoleCodePage(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN ConsoleOutputCP,\n    _Out_ PUSHORT ConsoleCodePage\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInformation;\n    HANDLE threadHandle = NULL;\n    HANDLE powerRequestHandle = NULL;\n    PVOID getConsoleCP = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->Kernel32FileName,\n        ConsoleOutputCP ? \"GetConsoleOutputCP\" : \"GetConsoleCP\",\n        &getConsoleCP,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        0,\n        0,\n        0,\n        0,\n        getConsoleCP,\n        NULL,\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhWaitForSingleObject(threadHandle, 5000);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetThreadBasicInformation(threadHandle, &basicInformation);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    *ConsoleCodePage = (USHORT)basicInformation.ExitStatus;\n\nCleanupExit:\n    if (threadHandle)\n    {\n        NtClose(threadHandle);\n    }\n\n    if (powerRequestHandle)\n    {\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n    }\n\n    return status;\n}\n\n/**\n * Flushes remote process heaps by invoking RtlFlushHeaps through a queued APC.\n *\n * \\param[in] ProcessHandle Target process.\n * \\param[in] Timeout Optional timeout.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Uses suspended thread with queued APC; waits for completion (5s).\n */\nNTSTATUS PhFlushProcessHeapsRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInformation;\n    PVOID rtlExitUserThread = NULL;\n    PVOID rtlFlushHeaps = NULL;\n    HANDLE threadHandle = NULL;\n    HANDLE powerRequestHandle = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n#ifdef _WIN64\n        &isWow64\n#else\n        NULL\n#endif\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->NtdllFileName,\n        \"RtlExitUserThread\",\n        &rtlExitUserThread,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->NtdllFileName,\n        \"RtlFlushHeaps\",\n        &rtlFlushHeaps,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        THREAD_CREATE_FLAGS_CREATE_SUSPENDED,\n        0,\n        0,\n        0,\n        rtlExitUserThread,\n        LongToPtr(STATUS_SUCCESS),\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n#ifdef _WIN64\n    if (isWow64)\n    {\n        status = RtlQueueApcWow64Thread(\n            threadHandle,\n            rtlFlushHeaps,\n            NULL,\n            NULL,\n            NULL\n            );\n    }\n    else\n    {\n#endif\n        status = NtQueueApcThreadEx(\n            threadHandle,\n            QUEUE_USER_APC_SPECIAL_USER_APC,\n            rtlFlushHeaps,\n            NULL,\n            NULL,\n            NULL\n            );\n#ifdef _WIN64\n    }\n#endif\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtResumeThread(threadHandle, NULL); // Execute the pending APC (dmex)\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtWaitForSingleObject(threadHandle, FALSE, Timeout);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetThreadBasicInformation(threadHandle, &basicInformation);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = basicInformation.ExitStatus;\n\nCleanupExit:\n\n    if (threadHandle)\n    {\n        NtClose(threadHandle);\n    }\n\n    if (powerRequestHandle)\n    {\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n    }\n\n    return status;\n}\n\n/**\n * Invokes a procedure in the context of the owning thread for the window.\n *\n * \\param[in] WindowHandle The handle of the window.\n * \\param[in] ApcRoutine The procedure to be invoked.\n * \\param[in] ApcArgument1 The first argument to be passed to the procedure.\n * \\param[in] ApcArgument2 The second argument to be passed to the procedure.\n * \\param[in] ApcArgument3 The third argument to be passed to the procedure.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhInvokeWindowProcedureRemote(\n    _In_ HWND WindowHandle,\n    _In_ PPS_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    )\n{\n    NTSTATUS status;\n    HANDLE processHande = NULL;\n    HANDLE threadHande = NULL;\n    HANDLE powerHandle = NULL;\n    CLIENT_ID clientId;\n\n    // Get the client ID of the window.\n\n    status = PhGetWindowClientId(WindowHandle, &clientId);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Open the process associated with the window.\n\n    status = PhOpenProcessClientId(\n        &processHande,\n        PROCESS_ALL_ACCESS,\n        &clientId\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Open the thread associated with the window.\n\n    status = PhOpenThreadClientId(\n        &threadHande,\n        THREAD_ALL_ACCESS, // THREAD_ALERT\n        &clientId\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Create an execution required request for the process (Windows 8 and above)\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(processHande, &powerHandle);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    // Queue a Special user-mode APC to execute within the context of the message loop.\n\n    status = NtQueueApcThreadEx(\n        threadHande,\n        QUEUE_USER_APC_SPECIAL_USER_APC,\n        ApcRoutine,\n        ApcArgument1,\n        ApcArgument2,\n        ApcArgument3\n        );\n\nCleanupExit:\n    if (threadHande)\n        NtClose(threadHande);\n    if (processHande)\n        NtClose(processHande);\n    if (powerHandle)\n        PhDestroyExecutionRequiredRequest(powerHandle);\n\n    return status;\n}\n\n/**\n * Destroys the specified window in a process.\n *\n * \\param[in] ProcessHandle A handle to a process. The handle must have PROCESS_SET_LIMITED_INFORMATION access.\n * \\param[in] WindowHandle A handle to the window to be destroyed.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks A thread cannot call DestroyWindow for a window created by a different thread,\n * unless we queue a special APC to the owner thread.\n */\nNTSTATUS PhDestroyWindowRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n    PVOID destroyWindow = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->User32FileName,\n        \"DestroyWindow\",\n        &destroyWindow,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhInvokeWindowProcedureRemote(\n        WindowHandle,\n        destroyWindow,\n        (PVOID)WindowHandle,\n        NULL,\n        NULL\n        );\n\nCleanupExit:\n    return status;\n}\n\n/**\n * Posts WM_QUIT (exit code) to a window's message loop via PostQuitMessage in remote context.\n *\n * \\param[in] ProcessHandle Process handle.\n * \\param[in] WindowHandle Window handle.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhPostWindowQuitMessageRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n    PVOID postQuitMessage = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->User32FileName,\n        \"PostQuitMessage\",\n        &postQuitMessage,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhInvokeWindowProcedureRemote(\n        WindowHandle,\n        postQuitMessage,\n        UlongToPtr(EXIT_SUCCESS),\n        NULL,\n        NULL\n        );\n\nCleanupExit:\n    return status;\n}\n\n// https://learn.microsoft.com/en-us/windows/win32/multimedia/obtaining-and-setting-timer-resolution\n/**\n * Sets process timer resolution (TimeBeginPeriod) via remote APC invocation.\n *\n * \\param[in] ProcessHandle Process handle.\n * \\param[in] Period Requested timer resolution in ms.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessTimerResolutionRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Period\n    )\n{\n    NTSTATUS status;\n    PVOID rtlExitUserThread = NULL;\n    PVOID timeBeginPeriod = NULL;\n    HANDLE threadHandle = NULL;\n    HANDLE powerRequestHandle = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n    LARGE_INTEGER timeout;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n#ifdef _WIN64\n        & isWow64\n#else\n        NULL\n#endif\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->NtdllFileName,\n        \"RtlExitUserThread\",\n        &rtlExitUserThread,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->Kernel32FileName,\n        \"TimeBeginPeriod\",\n        &timeBeginPeriod,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        THREAD_CREATE_FLAGS_CREATE_SUSPENDED,\n        0,\n        0,\n        0,\n        rtlExitUserThread,\n        LongToPtr(STATUS_SUCCESS),\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n#ifdef _WIN64\n    if (isWow64)\n    {\n        status = RtlQueueApcWow64Thread(\n            threadHandle,\n            timeBeginPeriod,\n            UlongToPtr(Period),\n            NULL,\n            NULL\n            );\n    }\n    else\n    {\n#endif\n        status = NtQueueApcThread(\n            threadHandle,\n            timeBeginPeriod,\n            UlongToPtr(Period),\n            NULL,\n            NULL\n            );\n#ifdef _WIN64\n    }\n#endif\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtResumeThread(threadHandle, NULL);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtWaitForSingleObject(threadHandle, FALSE, PhTimeoutFromMilliseconds(&timeout, 5000));\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\nCleanupExit:\n\n    if (threadHandle)\n    {\n        NtClose(threadHandle);\n    }\n\n    if (powerRequestHandle)\n    {\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n    }\n\n    return status;\n}\n\n/**\n * Alternate variant for setting timer resolution (same semantics as PhSetProcessTimerResolutionRemote).\n *\n * \\param[in] ProcessHandle Process handle.\n * \\param[in] Period Requested period.\n * \\returns NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetProcessTimerResolutionRemote2(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Period\n    )\n{\n    NTSTATUS status;\n    PVOID rtlExitUserThread = NULL;\n    PVOID timeBeginPeriod = NULL;\n    HANDLE threadHandle = NULL;\n    HANDLE powerRequestHandle = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n#ifdef _WIN64\n        & isWow64\n#else\n        NULL\n#endif\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->NtdllFileName,\n        \"RtlExitUserThread\",\n        &rtlExitUserThread,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->Kernel32FileName,\n        \"TimeBeginPeriod\",\n        &timeBeginPeriod,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        THREAD_CREATE_FLAGS_CREATE_SUSPENDED,\n        0,\n        0,\n        0,\n        rtlExitUserThread,\n        LongToPtr(STATUS_SUCCESS),\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n#ifdef _WIN64\n    if (isWow64)\n    {\n        status = RtlQueueApcWow64Thread(\n            threadHandle,\n            timeBeginPeriod,\n            UlongToPtr(Period),\n            NULL,\n            NULL\n            );\n    }\n    else\n    {\n#endif\n        status = NtQueueApcThread(\n            threadHandle,\n            timeBeginPeriod,\n            UlongToPtr(Period),\n            NULL,\n            NULL\n            );\n#ifdef _WIN64\n    }\n#endif\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtResumeThread(threadHandle, NULL);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhWaitForSingleObject(threadHandle, 5000);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\nCleanupExit:\n\n    if (threadHandle)\n    {\n        NtClose(threadHandle);\n    }\n\n    if (powerRequestHandle)\n    {\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n    }\n\n    return status;\n}\n\n/**\n * Sets handle flags (e.g. HANDLE_FLAG_INHERIT, HANDLE_FLAG_PROTECT_FROM_CLOSE) in a remote process.\n *\n * \\param[in] ProcessHandle Target process.\n * \\param[in] RemoteHandle Handle value in remote process.\n * \\param[in] Mask Bitmask of flags to modify.\n * \\param[in] Flags New flag values.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Invokes SetHandleInformation via APC onto suspended thread.\n */\nNTSTATUS PhSetHandleInformationRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE RemoteHandle,\n    _In_ ULONG Mask,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    PVOID rtlExitUserThread = NULL;\n    PVOID setHandleInformation = NULL;\n    HANDLE threadHandle = NULL;\n    HANDLE powerRequestHandle = NULL;\n    PPH_PROCESS_RUNTIME_LIBRARY runtimeLibrary;\n    THREAD_BASIC_INFORMATION basicInformation;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n\n    status = PhGetProcessRuntimeLibrary(\n        ProcessHandle,\n        &runtimeLibrary,\n#ifdef _WIN64\n        & isWow64\n#else\n        NULL\n#endif\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->NtdllFileName,\n        \"RtlExitUserThread\",\n        &rtlExitUserThread,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        &runtimeLibrary->Kernel32FileName,\n        \"SetHandleInformation\",\n        &setHandleInformation,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        status = PhCreateExecutionRequiredRequest(ProcessHandle, &powerRequestHandle);\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    status = PhCreateUserThread(\n        ProcessHandle,\n        NULL,\n        THREAD_ALL_ACCESS,\n        THREAD_CREATE_FLAGS_CREATE_SUSPENDED,\n        0,\n        0,\n        0,\n        rtlExitUserThread,\n        LongToPtr(STATUS_SUCCESS),\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n#ifdef _WIN64\n    if (isWow64)\n    {\n        status = RtlQueueApcWow64Thread(\n            threadHandle,\n            setHandleInformation,\n            RemoteHandle,\n            UlongToPtr(Mask),\n            UlongToPtr(Flags)\n            );\n    }\n    else\n    {\n#endif\n        status = NtQueueApcThread(\n            threadHandle,\n            setHandleInformation,\n            RemoteHandle,\n            UlongToPtr(Mask),\n            UlongToPtr(Flags)\n            );\n#ifdef _WIN64\n    }\n#endif\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtResumeThread(threadHandle, NULL);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhWaitForSingleObject(threadHandle, 5000);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetThreadBasicInformation(threadHandle, &basicInformation);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = basicInformation.ExitStatus;\n\nCleanupExit:\n\n    if (threadHandle)\n    {\n        NtClose(threadHandle);\n    }\n\n    if (powerRequestHandle)\n    {\n        PhDestroyExecutionRequiredRequest(powerRequestHandle);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/nativetoken.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <kphuser.h>\n#include <lsasup.h>\n\n/**\n * Queries information about the token of the current process.\n */\nPH_TOKEN_ATTRIBUTES PhGetOwnTokenAttributes(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PH_TOKEN_ATTRIBUTES attributes = { NULL, {0}, 0, NULL };\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        BOOLEAN elevated = TRUE;\n        TOKEN_ELEVATION_TYPE elevationType = TokenElevationTypeFull;\n\n        if (WindowsVersion >= WINDOWS_8_1)\n        {\n            attributes.TokenHandle = NtCurrentProcessToken();\n        }\n        else\n        {\n            HANDLE tokenHandle;\n\n            if (NT_SUCCESS(PhOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &tokenHandle)))\n            {\n                attributes.TokenHandle = tokenHandle;\n            }\n        }\n\n        if (attributes.TokenHandle)\n        {\n            PH_TOKEN_USER tokenUser;\n\n            PhGetTokenElevation(attributes.TokenHandle, &elevated);\n            PhGetTokenElevationType(attributes.TokenHandle, &elevationType);\n\n            if (NT_SUCCESS(PhGetTokenUser(attributes.TokenHandle, &tokenUser)))\n            {\n                attributes.TokenSid = PhAllocateCopy(tokenUser.User.Sid, PhLengthSid(tokenUser.User.Sid));\n            }\n        }\n\n        attributes.Elevated = elevated;\n        attributes.ElevationType = elevationType;\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return attributes;\n}\n\n/**\n * Opens a process token.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param DesiredAccess The desired access to the token.\n * \\param TokenHandle A variable which receives a handle to the token.\n */\nNTSTATUS PhOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    )\n{\n    NTSTATUS status;\n    KPH_LEVEL level;\n\n    level = KsiLevel();\n\n    if ((level >= KphLevelMed) && (DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess)\n    {\n        status = KphOpenProcessToken(\n            ProcessHandle,\n            DesiredAccess,\n            TokenHandle\n            );\n    }\n    else\n    {\n        status = NtOpenProcessToken(\n            ProcessHandle,\n            DesiredAccess,\n            TokenHandle\n            );\n\n        if (status == STATUS_ACCESS_DENIED && (level == KphLevelMax))\n        {\n            status = KphOpenProcessToken(\n                ProcessHandle,\n                DesiredAccess,\n                TokenHandle\n                );\n        }\n    }\n\n    return status;\n}\n\n/**\n * Public API to open a process token using only NtOpenProcessToken.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param DesiredAccess The desired access to the token.\n * \\param TokenHandle Receives a handle to the token on success.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenProcessTokenPublic(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    )\n{\n    return NtOpenProcessToken(\n        ProcessHandle,\n        DesiredAccess,\n        TokenHandle\n        );\n}\n\n/**\n * Opens a thread token by calling NtOpenThreadToken.\n *\n * \\param ThreadHandle A handle to a thread.\n * \\param DesiredAccess The desired access to the token.\n * \\param OpenAsSelf Whether to open the token using the process security context.\n * \\param TokenHandle Receives a handle to the token on success.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenThreadToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ BOOLEAN OpenAsSelf,\n    _Out_ PHANDLE TokenHandle\n    )\n{\n    NTSTATUS status;\n\n    status = NtOpenThreadToken(\n        ThreadHandle,\n        DesiredAccess,\n        OpenAsSelf,\n        TokenHandle\n        );\n\n    return status;\n}\n\n/**\n * Queries variable-sized information for a token. Allocates a buffer of the\n * appropriate size and returns it via \\a Buffer.\n *\n * \\param TokenHandle A handle to a token.\n * \\param TokenInformationClass The information class to retrieve.\n * \\param Buffer Receives a pointer to an allocated buffer containing the information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpQueryTokenVariableSize(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG returnLength;\n\n    returnLength = 0;\n    bufferSize = 0x80;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenInformationClass,\n        buffer,\n        bufferSize,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhFree(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQueryInformationToken(\n            TokenHandle,\n            TokenInformationClass,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Alias for PhpQueryTokenVariableSize.\n *\n * \\param TokenHandle A handle to a token.\n * \\param TokenInformationClass The information class to retrieve.\n * \\param Buffer Receives a pointer to an allocated buffer containing the information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhQueryTokenVariableSize(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenInformationClass,\n        Buffer\n        );\n}\n\n/**\n * Retrieves the type of a token (primary or impersonation).\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param Type A variable which receives the token type (primary or impersonation).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenType(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_TYPE Type\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenType,\n        Type,\n        sizeof(TOKEN_TYPE),\n        &returnLength\n        );\n}\n\n/**\n * Gets a token's session ID.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param SessionId A variable which receives the session ID.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenSessionId(\n    _In_ HANDLE TokenHandle,\n    _Out_ PULONG SessionId\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenSessionId,\n        SessionId,\n        sizeof(ULONG),\n        &returnLength\n        );\n}\n\n/**\n * Gets a token's elevation type.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param ElevationType A variable which receives the elevation type.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenElevationType(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_ELEVATION_TYPE ElevationType\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenElevationType,\n        ElevationType,\n        sizeof(TOKEN_ELEVATION_TYPE),\n        &returnLength\n        );\n}\n\n/**\n * Gets whether a token is elevated.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param TokenIsElevated A variable which receives a boolean indicating whether the token is elevated.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenElevation(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN TokenIsElevated\n    )\n{\n    NTSTATUS status;\n    TOKEN_ELEVATION elevation;\n    ULONG returnLength;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenElevation,\n        &elevation,\n        sizeof(TOKEN_ELEVATION),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *TokenIsElevated = !!elevation.TokenIsElevated;\n    }\n\n    return status;\n}\n\n/**\n * Gets a token's statistics.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param Statistics A variable which receives the token's statistics.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenStatistics(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_STATISTICS Statistics\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenStatistics,\n        Statistics,\n        sizeof(TOKEN_STATISTICS),\n        &returnLength\n        );\n}\n\n/**\n * Gets a token's source.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY_SOURCE access.\n * \\param Source A variable which receives the token's source.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenSource(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_SOURCE Source\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenSource,\n        Source,\n        sizeof(TOKEN_SOURCE),\n        &returnLength\n        );\n}\n\n/**\n * Gets a handle to a token's linked token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param LinkedTokenHandle A variable which receives a handle to the linked token. You must close\n * the handle using NtClose() when you no longer need it.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenLinkedToken(\n    _In_ HANDLE TokenHandle,\n    _Out_ PHANDLE LinkedTokenHandle\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    TOKEN_LINKED_TOKEN linkedToken;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenLinkedToken,\n        &linkedToken,\n        sizeof(TOKEN_LINKED_TOKEN),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *LinkedTokenHandle = linkedToken.LinkedToken;\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetTokenIsRestricted(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsRestricted\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    ULONG restricted;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenIsRestricted,\n        &restricted,\n        sizeof(ULONG),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *IsRestricted = !!restricted;\n    }\n\n    return status;\n}\n\n/**\n * Gets whether virtualization is allowed for a token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param IsVirtualizationAllowed A variable which receives a boolean indicating whether\n * virtualization is allowed for the token.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenIsVirtualizationAllowed(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsVirtualizationAllowed\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    ULONG virtualizationAllowed;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenVirtualizationAllowed,\n        &virtualizationAllowed,\n        sizeof(ULONG),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *IsVirtualizationAllowed = !!virtualizationAllowed;\n    }\n\n    return status;\n}\n\n/**\n * Gets whether virtualization is enabled for a token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param IsVirtualizationEnabled A variable which receives a boolean indicating whether\n * virtualization is enabled for the token.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenIsVirtualizationEnabled(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsVirtualizationEnabled\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    ULONG virtualizationEnabled;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenVirtualizationEnabled,\n        &virtualizationEnabled,\n        sizeof(ULONG),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *IsVirtualizationEnabled = !!virtualizationEnabled;\n\n    return status;\n}\n\n/**\n * Gets UIAccess flag for a token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param IsUIAccessEnabled A variable which receives a boolean indicating whether\n * UIAccess is enabled for the token.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenUIAccess(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsUIAccessEnabled\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    ULONG uiAccess;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenUIAccess,\n        &uiAccess,\n        sizeof(ULONG),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *IsUIAccessEnabled = !!uiAccess;\n\n    return status;\n}\n\n/**\n * Sets UIAccess flag for a token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_ADJUST_DEFAULT access.\n * \\param IsUIAccessEnabled The new flag state.\n * \\remarks Enabling UIAccess requires SeTcbPrivilege.\n * \\return Successful or errant status.\n */\nNTSTATUS PhSetTokenUIAccess(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN IsUIAccessEnabled\n    )\n{\n    ULONG uiAccess;\n\n    uiAccess = IsUIAccessEnabled ? 1 : 0;\n\n    return NtSetInformationToken(\n        TokenHandle,\n        TokenUIAccess,\n        &uiAccess,\n        sizeof(ULONG)\n        );\n}\n\n/**\n * Gets SandBoxInert flag for a token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param IsSandBoxInert A variable which receives a boolean indicating whether\n * AppLocker rules or Software Restriction Policies are enabled for the token.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenIsSandBoxInert(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsSandBoxInert\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    ULONG sandBoxInert;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenSandBoxInert,\n        &sandBoxInert,\n        sizeof(ULONG),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *IsSandBoxInert = !!sandBoxInert;\n\n    return status;\n}\n\n/**\n * Gets Mandatory Policy for a token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param MandatoryPolicy A variable which receives a set of mandatory integrity\n * policies enforced for the token.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenMandatoryPolicy(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_MANDATORY_POLICY MandatoryPolicy\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenMandatoryPolicy,\n        MandatoryPolicy,\n        sizeof(TOKEN_MANDATORY_POLICY),\n        &returnLength\n        );\n}\n\n/**\n * The TOKEN_ORIGIN structure contains information about the origin of the logon session.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param Origin A variable which receives the Locally unique identifier (LUID) for the logon session.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenOrigin(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_ORIGIN Origin\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenOrigin,\n        Origin,\n        sizeof(TOKEN_ORIGIN),\n        &returnLength\n        );\n}\n\n/**\n * Gets a value that is nonzero if the token is an app container token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param IsAppContainer Any callers who check the TokenIsAppContainer and have it return 0 should\n * also verify that the caller token is not an identify level impersonation token.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenIsAppContainer(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsAppContainer\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    ULONG isAppContainer;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenIsAppContainer,\n        &isAppContainer,\n        sizeof(ULONG),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *IsAppContainer = !!isAppContainer;\n\n    return status;\n}\n\n/**\n * Gets a value that includes the app container number for the token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param AppContainerNumber The app container number for the token.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetTokenAppContainerNumber(\n    _In_ HANDLE TokenHandle,\n    _Out_ PULONG AppContainerNumber\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenAppContainerNumber,\n        AppContainerNumber,\n        sizeof(ULONG),\n        &returnLength\n        );\n}\n\n/**\n * Gets a token's user SID and returns a copy of the SID.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param User Receives a pointer to a newly allocated SID copy.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenUserCopy(\n    _In_ HANDLE TokenHandle,\n    _Out_ PSID* User\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    UCHAR tokenUserBuffer[TOKEN_USER_MAX_SIZE];\n    PTOKEN_USER tokenUser = (PTOKEN_USER)tokenUserBuffer;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenUser,\n        tokenUser,\n        sizeof(tokenUserBuffer),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *User = PhAllocateCopy(tokenUser->User.Sid, PhLengthSid(tokenUser->User.Sid));\n    }\n\n    return status;\n}\n\n/**\n * Gets a token's user information into a caller-provided PH_TOKEN_USER buffer.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param User Receives the token user information (PH_TOKEN_USER sized buffer).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenUser(\n    _In_ HANDLE TokenHandle,\n    _Out_ PPH_TOKEN_USER User\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenUser,\n        User,\n        sizeof(PH_TOKEN_USER), // SE_TOKEN_USER\n        &returnLength\n        );\n}\n\n/**\n * Gets a token's owner SID and returns a copy of the SID.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param Owner Receives a pointer to a newly allocated SID copy.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenOwnerCopy(\n    _In_ HANDLE TokenHandle,\n    _Out_ PSID* Owner\n    )\n{\n    NTSTATUS status;\n    UCHAR tokenOwnerBuffer[TOKEN_OWNER_MAX_SIZE];\n    PTOKEN_OWNER tokenOwner = (PTOKEN_OWNER)tokenOwnerBuffer;\n    ULONG returnLength;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenOwner,\n        tokenOwner,\n        sizeof(tokenOwnerBuffer),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Owner = PhAllocateCopy(tokenOwner->Owner, PhLengthSid(tokenOwner->Owner));\n    }\n\n    return status;\n}\n\n/**\n * Gets a token's owner information into a caller-provided PH_TOKEN_OWNER buffer.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param Owner Receives the token owner information (PH_TOKEN_OWNER sized buffer).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenOwner(\n    _In_ HANDLE TokenHandle,\n    _Out_ PPH_TOKEN_OWNER Owner\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenOwner,\n        Owner,\n        sizeof(PH_TOKEN_OWNER),\n        &returnLength\n        );\n}\n\n/**\n * Gets a token's primary group information.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param PrimaryGroup Receives a pointer to the allocated TOKEN_PRIMARY_GROUP structure.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenPrimaryGroup(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PRIMARY_GROUP *PrimaryGroup\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenPrimaryGroup,\n        PrimaryGroup\n        );\n}\n\n/**\n * Gets a token's default DACL.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param DefaultDacl Receives a pointer to the allocated TOKEN_DEFAULT_DACL structure.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenDefaultDacl(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_DEFAULT_DACL* DefaultDacl\n    )\n{\n    NTSTATUS status;\n    PTOKEN_DEFAULT_DACL defaultDacl;\n\n    status = PhQueryTokenVariableSize(\n        TokenHandle,\n        TokenDefaultDacl,\n        &defaultDacl\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (defaultDacl->DefaultDacl)\n        {\n            *DefaultDacl = defaultDacl;\n        }\n        else\n        {\n            status = STATUS_INVALID_SECURITY_DESCR;\n            PhFree(defaultDacl);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Gets a token's groups.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param Groups Receives a pointer to the allocated TOKEN_GROUPS structure.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenGroups(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_GROUPS *Groups\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenGroups,\n        Groups\n        );\n}\n\n/**\n * Gets a token's restricted SIDs.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param RestrictedSids Receives a pointer to the allocated TOKEN_GROUPS structure describing restricted SIDs.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenRestrictedSids(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_GROUPS* RestrictedSids\n)\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenRestrictedSids,\n        RestrictedSids\n        );\n}\n\n/**\n * Gets a token's privileges.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param Privileges Receives a pointer to the allocated TOKEN_PRIVILEGES structure.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenPrivileges(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PRIVILEGES *Privileges\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenPrivileges,\n        Privileges\n        );\n}\n\n/**\n * Gets a token's process trust level information.\n *\n * \\param TokenHandle A handle to a token. Must have appropriate access for TokenProcessTrustLevel.\n * \\param TrustLevel Receives a pointer to the allocated TOKEN_PROCESS_TRUST_LEVEL structure.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenTrustLevel(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PROCESS_TRUST_LEVEL *TrustLevel\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenProcessTrustLevel,\n        TrustLevel\n        );\n}\n\n/**\n * Gets a token's AppContainer SID.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param AppContainerSid Receives the PH_TOKEN_APPCONTAINER structure.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenAppContainerSid(\n    _In_ HANDLE TokenHandle,\n    _Out_ PPH_TOKEN_APPCONTAINER AppContainerSid\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenAppContainerSid,\n        AppContainerSid,\n        sizeof(PH_TOKEN_APPCONTAINER),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status) && !AppContainerSid->AppContainer.Sid)\n    {\n        status = STATUS_NOT_FOUND;\n    }\n\n    return status;\n}\n\n/**\n * Gets a copy of a token's AppContainer SID.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param AppContainerSid Receives a pointer to a newly allocated SID copy.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenAppContainerSidCopy(\n    _In_ HANDLE TokenHandle,\n    _Out_ PSID* AppContainerSid\n    )\n{\n    NTSTATUS status;\n    UCHAR tokenAppContainerSidBuffer[TOKEN_APPCONTAINER_SID_MAX_SIZE];\n    PTOKEN_APPCONTAINER_INFORMATION tokenAppContainerSid = (PTOKEN_APPCONTAINER_INFORMATION)tokenAppContainerSidBuffer;\n    ULONG returnLength;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenAppContainerSid,\n        tokenAppContainerSid,\n        sizeof(tokenAppContainerSidBuffer),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (tokenAppContainerSid->TokenAppContainer)\n        {\n            *AppContainerSid = PhAllocateCopy(tokenAppContainerSid->TokenAppContainer, PhLengthSid(tokenAppContainerSid->TokenAppContainer));\n        }\n        else\n        {\n            status = STATUS_NOT_FOUND;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Retrieves token security attributes.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param SecurityAttributes Receives pointer to the allocated TOKEN_SECURITY_ATTRIBUTES_INFORMATION.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenSecurityAttributes(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION* SecurityAttributes\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenSecurityAttributes,\n        SecurityAttributes\n        );\n}\n\n/**\n * Retrieves specific security attribute values for a token by attribute name.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param AttributeName The attribute name to query (stringref).\n * \\param SecurityAttributes Receives pointer to the allocated TOKEN_SECURITY_ATTRIBUTES_INFORMATION.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenSecurityAttribute(\n    _In_ HANDLE TokenHandle,\n    _In_ PCPH_STRINGREF AttributeName,\n    _Out_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION* SecurityAttributes\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING attributeName[1];\n    PTOKEN_SECURITY_ATTRIBUTES_INFORMATION buffer;\n    ULONG bufferLength;\n    ULONG returnLength;\n\n    if (!PhStringRefToUnicodeString(AttributeName, &attributeName[0]))\n        return STATUS_NAME_TOO_LONG;\n\n    returnLength = 0;\n    bufferLength = 0x200;\n    buffer = PhAllocate(bufferLength);\n\n    status = NtQuerySecurityAttributesToken(\n        TokenHandle,\n        attributeName,\n        RTL_NUMBER_OF(attributeName),\n        buffer,\n        bufferLength,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhFree(buffer);\n        bufferLength = returnLength;\n        buffer = PhAllocate(bufferLength);\n\n        status = NtQuerySecurityAttributesToken(\n            TokenHandle,\n            attributeName,\n            RTL_NUMBER_OF(attributeName),\n            buffer,\n            bufferLength,\n            &returnLength\n            );\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (returnLength == sizeof(TOKEN_SECURITY_ATTRIBUTES_INFORMATION))\n        {\n            PhFree(buffer);\n            return STATUS_NOT_FOUND;\n        }\n\n        *SecurityAttributes = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Determines whether a named security attribute exists on a token.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param AttributeName The attribute name to query (stringref).\n * \\param SecurityAttributeExists Receives TRUE if attribute exists.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhDoesTokenSecurityAttributeExist(\n    _In_ HANDLE TokenHandle,\n    _In_ PCPH_STRINGREF AttributeName,\n    _Out_ PBOOLEAN SecurityAttributeExists\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING attributeName;\n    ULONG returnLength;\n\n    if (!PhStringRefToUnicodeString(AttributeName, &attributeName))\n        return STATUS_NAME_TOO_LONG;\n\n    status = NtQuerySecurityAttributesToken(\n        TokenHandle,\n        &attributeName,\n        1,\n        NULL,\n        0,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        *SecurityAttributeExists = TRUE;\n        return STATUS_SUCCESS;\n    }\n\n    return status;\n}\n\n/**\n * Finds a security attribute entry by name within a TOKEN_SECURITY_ATTRIBUTES_INFORMATION block.\n *\n * \\param Attributes Pointer to TOKEN_SECURITY_ATTRIBUTES_INFORMATION to search.\n * \\param AttributeName The attribute name to find (stringref).\n * \\return PTOKEN_SECURITY_ATTRIBUTE_V1 Pointer to the attribute entry if found, NULL otherwise.\n */\nPTOKEN_SECURITY_ATTRIBUTE_V1 PhFindTokenSecurityAttributeName(\n    _In_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION Attributes,\n    _In_ PCPH_STRINGREF AttributeName\n    )\n{\n    for (ULONG i = 0; i < Attributes->AttributeCount; i++)\n    {\n        PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &Attributes->AttributeV1[i];\n        PH_STRINGREF attributeName;\n\n        PhUnicodeStringToStringRef(&attribute->Name, &attributeName);\n\n        if (PhEqualStringRef(&attributeName, AttributeName, FALSE))\n        {\n            return attribute;\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Determines whether a token represents a full-trust (system) package.\n * This checks for the presence of the WIN://SYSAPPID attribute and ensures the\n * token is not an AppContainer.\n *\n * \\param TokenHandle A handle to a token.\n * \\return BOOLEAN TRUE if token is a full-trust package, FALSE otherwise.\n */\nBOOLEAN PhGetTokenIsFullTrustPackage(\n    _In_ HANDLE TokenHandle\n    )\n{\n    static CONST PH_STRINGREF attributeName = PH_STRINGREF_INIT(L\"WIN://SYSAPPID\");\n    BOOLEAN tokenIsStronglyNamedAttribute = FALSE;\n    BOOLEAN tokenIsAppContainer = FALSE;\n\n    if (NT_SUCCESS(PhDoesTokenSecurityAttributeExist(TokenHandle, &attributeName, &tokenIsStronglyNamedAttribute)) && tokenIsStronglyNamedAttribute)\n    {\n        if (NT_SUCCESS(PhGetTokenIsAppContainer(TokenHandle, &tokenIsAppContainer)))\n        {\n            if (tokenIsAppContainer)\n                return FALSE;\n        }\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Determines whether a token is a process user service (SCM user service) by checking the WIN://SCMUserService attribute.\n * \n * \\param TokenHandle A handle to a token.\n * \\param IsStronglyNamed Receives TRUE if the attribute exists.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenIsProcessUserService(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsStronglyNamed\n    )\n{\n    static CONST PH_STRINGREF attributeName = PH_STRINGREF_INIT(L\"WIN://SCMUserService\");\n    BOOLEAN attributeExists = FALSE;\n    NTSTATUS status;\n\n    status = PhDoesTokenSecurityAttributeExist(TokenHandle, &attributeName, &attributeExists);\n\n    if (NT_SUCCESS(status))\n    {\n        *IsStronglyNamed = attributeExists;\n    }\n\n    return status;\n}\n\n/**\n * Determines whether a process is strongly named by querying extended basic info.\n *\n * \\param ProcessHandle A handle to the process.\n * \\param IsStronglyNamed Receives TRUE if the process is strongly named.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetProcessIsStronglyNamed(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsStronglyNamed\n    )\n{\n    NTSTATUS status;\n    PROCESS_EXTENDED_BASIC_INFORMATION basicInfo;\n\n    status = PhGetProcessExtendedBasicInformation(ProcessHandle, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        *IsStronglyNamed = !!basicInfo.IsStronglyNamed;\n    }\n\n    return status;\n}\n\n/**\n * Determines whether a token is strongly named by checking the WIN://SYSAPPID attribute.\n *\n * \\param TokenHandle A handle to a token.\n * \\param IsStronglyNamed Receives TRUE if token is strongly named.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenIsStronglyNamed(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsStronglyNamed\n    )\n{\n    static CONST PH_STRINGREF attributeName = PH_STRINGREF_INIT(L\"WIN://SYSAPPID\");\n    BOOLEAN attributeExists = FALSE;\n    NTSTATUS status;\n\n    status = PhDoesTokenSecurityAttributeExist(TokenHandle, &attributeName, &attributeExists);\n\n    if (NT_SUCCESS(status))\n    {\n        *IsStronglyNamed = attributeExists;\n    }\n\n    return status;\n}\n\n/**\n * Determines whether a process is a full-trust package and not an AppContainer.\n *\n * \\param ProcessHandle A handle to the process.\n * \\return BOOLEAN TRUE if process is a full-trust package, FALSE otherwise.\n */\nBOOLEAN PhGetProcessIsFullTrustPackage(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    BOOLEAN processIsStronglyNamed = FALSE;\n    BOOLEAN tokenIsAppContainer = FALSE;\n\n    if (NT_SUCCESS(PhGetProcessIsStronglyNamed(ProcessHandle, &processIsStronglyNamed)))\n    {\n        if (processIsStronglyNamed)\n        {\n            HANDLE tokenHandle;\n\n            if (NT_SUCCESS(PhOpenProcessToken(ProcessHandle, TOKEN_QUERY, &tokenHandle)))\n            {\n                PhGetTokenIsAppContainer(tokenHandle, &tokenIsAppContainer);\n                NtClose(tokenHandle);\n            }\n\n            if (tokenIsAppContainer)\n                return FALSE;\n\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Retrieves the package full name for a process by opening its token and querying.\n *\n * \\param ProcessHandle A handle to the process.\n * \\return PPH_STRING The package full name string object, or NULL if not available.\n */\nPPH_STRING PhGetProcessPackageFullName(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    HANDLE tokenHandle;\n    PPH_STRING packageName = NULL;\n\n    if (NT_SUCCESS(PhOpenProcessToken(ProcessHandle, TOKEN_QUERY, &tokenHandle)))\n    {\n        PhGetTokenPackageFullName(tokenHandle, &packageName);\n        NtClose(tokenHandle);\n    }\n\n    return packageName;\n}\n\n/**\n * Determines whether a token is a less-privileged AppContainer by checking for the WIN://NOALLAPPPKG attribute.\n *\n * \\param TokenHandle A handle to a token.\n * \\param IsLessPrivilegedAppContainer Receives TRUE if the attribute indicates less-privileged AppContainer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenIsLessPrivilegedAppContainer(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsLessPrivilegedAppContainer\n    )\n{\n    static CONST PH_STRINGREF attributeName = PH_STRINGREF_INIT(L\"WIN://NOALLAPPPKG\");\n    NTSTATUS status;\n    BOOLEAN attributeExists = FALSE;\n\n    status = PhDoesTokenSecurityAttributeExist(\n        TokenHandle,\n        &attributeName,\n        &attributeExists\n        );\n\n    if (NT_SUCCESS(status) && attributeExists)\n        *IsLessPrivilegedAppContainer = TRUE;\n    else\n        *IsLessPrivilegedAppContainer = FALSE;\n\n    // TODO: NtQueryInformationToken(TokenIsLessPrivilegedAppContainer);\n\n    return status;\n}\n\n/**\n * Helper to retrieve a 64-bit value from a token security attribute.\n *\n * \\param TokenHandle A handle to a token.\n * \\param Name The attribute name (stringref).\n * \\param ValueIndex Index of the value to retrieve.\n * \\return ULONG64 The retrieved value, or MAXULONG64 if not present.\n */\nULONG64 PhGetTokenSecurityAttributeValueUlong64(\n    _In_ HANDLE TokenHandle,\n    _In_ PCPH_STRINGREF Name,\n    _In_ ULONG ValueIndex\n    )\n{\n    ULONG64 value = MAXULONG64;\n    PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info;\n\n    if (NT_SUCCESS(PhGetTokenSecurityAttribute(TokenHandle, Name, &info)))\n    {\n        PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = PhFindTokenSecurityAttributeName(info, Name);\n\n        if (attribute && attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64 && ValueIndex < attribute->ValueCount)\n        {\n            value = attribute->Values.Uint64[ValueIndex];\n        }\n\n        PhFree(info);\n    }\n\n    return value;\n}\n\n/**\n * Helper to retrieve a string value from a token security attribute.\n *\n * \\param TokenHandle A handle to a token.\n * \\param Name The attribute name (stringref).\n * \\param ValueIndex Index of the value to retrieve.\n * \\return PPH_STRING The retrieved string object or NULL if not present.\n */\nPPH_STRING PhGetTokenSecurityAttributeValueString(\n    _In_ HANDLE TokenHandle,\n    _In_ PCPH_STRINGREF Name,\n    _In_ ULONG ValueIndex\n    )\n{\n    PPH_STRING value = NULL;\n    PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info;\n\n    if (NT_SUCCESS(PhGetTokenSecurityAttribute(TokenHandle, Name, &info)))\n    {\n        PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = PhFindTokenSecurityAttributeName(info, Name);\n\n        if (attribute && attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING && ValueIndex < attribute->ValueCount)\n        {\n            value = PhCreateStringFromUnicodeString(&attribute->Values.String[ValueIndex]);\n        }\n\n        PhFree(info);\n    }\n\n    return value;\n}\n\n// rev from GetApplicationUserModelId/GetApplicationUserModelIdFromToken (dmex)\n/**\n * Retrieves the Application User Model ID (AUMID) for a token's package.\n *\n * \\param TokenHandle A handle to a token.\n * \\return PPH_STRING The AUMID string or NULL if not available.\n * \\remarks Constructs the AUMID from the SYSAPPID attribute values (family and relative id)\n * as \"<packageFamilyName>!<relativeIdName>\".\n */\nPPH_STRING PhGetTokenPackageApplicationUserModelId(\n    _In_ HANDLE TokenHandle\n    )\n{\n    static CONST PH_STRINGREF attributeName = PH_STRINGREF_INIT(L\"WIN://SYSAPPID\");\n    static CONST PH_STRINGREF separator = PH_STRINGREF_INIT(L\"!\");\n    PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info;\n    PPH_STRING applicationUserModelId = NULL;\n\n    if (NT_SUCCESS(PhGetTokenSecurityAttribute(TokenHandle, &attributeName, &info)))\n    {\n        PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = PhFindTokenSecurityAttributeName(info, &attributeName);\n\n        if (attribute && attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING && attribute->ValueCount >= 3)\n        {\n            PPH_STRING relativeIdName;\n            PPH_STRING packageFamilyName;\n\n            relativeIdName = PhCreateStringFromUnicodeString(&attribute->Values.String[1]);\n            packageFamilyName = PhCreateStringFromUnicodeString(&attribute->Values.String[2]);\n\n            applicationUserModelId = PhConcatStringRef3(\n                &packageFamilyName->sr,\n                &separator,\n                &relativeIdName->sr\n                );\n\n            PhDereferenceObject(packageFamilyName);\n            PhDereferenceObject(relativeIdName);\n        }\n\n        PhFree(info);\n    }\n\n    return applicationUserModelId;\n}\n\n/**\n * Retrieves the package full name for a token from the SYSAPPID attribute.\n *\n * \\param TokenHandle A handle to a token.\n * \\return PPH_STRING The package full name string object, or NULL if not available.\n */\nNTSTATUS PhGetTokenPackageFullName(\n    _In_ HANDLE TokenHandle,\n    _Out_ PPH_STRING* PackageFullName\n    )\n{\n    static CONST PH_STRINGREF attributeName = PH_STRINGREF_INIT(L\"WIN://SYSAPPID\");\n    PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info;\n    PPH_STRING packageFullName = NULL;\n    NTSTATUS status;\n\n    status = PhGetTokenSecurityAttribute(\n        TokenHandle,\n        &attributeName,\n        &info\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = PhFindTokenSecurityAttributeName(info, &attributeName);\n\n        if (attribute && attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING)\n        {\n            packageFullName = PhCreateStringFromUnicodeString(&attribute->Values.String[0]);\n        }\n        else\n        {\n            status = STATUS_OBJECT_TYPE_MISMATCH;\n        }\n\n        PhFree(info);\n    }\n\n    *PackageFullName = packageFullName;\n\n    return status;\n}\n\n/**\n * Retrieves the named object path of a token.\n *\n * \\param TokenHandle A handle to a token.\n * \\param Sid Optional SID to query a named path for (may be NULL).\n * \\param ObjectPath Receives the created string object for the object path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenNamedObjectPath(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PSID Sid,\n    _Out_ PPH_STRING* ObjectPath\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectPath;\n\n    if (!RtlGetTokenNamedObjectPath_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    RtlInitEmptyUnicodeString(&objectPath, NULL, 0);\n\n    status = RtlGetTokenNamedObjectPath_Import()(\n        TokenHandle,\n        Sid,\n        &objectPath\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ObjectPath = PhCreateStringFromUnicodeString(&objectPath);\n        RtlFreeUnicodeString(&objectPath);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves an AppContainer named object path if available.\n *\n * \\param TokenHandle A handle to a token.\n * \\param AppContainerSid Optional AppContainer SID to query for (may be NULL to use token's AppContainer).\n * \\param RelativePath If TRUE, request a relative path.\n * \\param ObjectPath Receives the created string object for the object path.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetAppContainerNamedObjectPath(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PSID AppContainerSid,\n    _In_ BOOLEAN RelativePath,\n    _Out_ PPH_STRING* ObjectPath\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectPath;\n\n    if (!RtlGetAppContainerNamedObjectPath_Import())\n        return STATUS_UNSUCCESSFUL;\n\n    RtlInitEmptyUnicodeString(&objectPath, NULL, 0);\n\n    status = RtlGetAppContainerNamedObjectPath_Import()(\n        TokenHandle,\n        AppContainerSid,\n        RelativePath,\n        &objectPath\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ObjectPath = PhCreateStringFromUnicodeString(&objectPath);\n        RtlFreeUnicodeString(&objectPath);\n    }\n\n    return status;\n}\n\n/**\n * Checks whether the specified privilege is enabled for the token.\n *\n * \\param TokenHandle A handle to a token.\n * \\param Privilege The privilege constant (as ULONG) to check.\n * \\return BOOLEAN TRUE if the privilege is enabled and used for access, FALSE otherwise.\n */\nBOOLEAN PhPrivilegeCheck(\n    _In_ HANDLE TokenHandle,\n    _In_ ULONG Privilege\n    )\n{\n    CHAR privilegesBuffer[FIELD_OFFSET(PRIVILEGE_SET, Privilege) + sizeof(LUID_AND_ATTRIBUTES) * 1];\n    PPRIVILEGE_SET requiredPrivileges;\n    BOOLEAN result = FALSE;\n\n    requiredPrivileges = (PPRIVILEGE_SET)privilegesBuffer;\n    requiredPrivileges->PrivilegeCount = 1;\n    requiredPrivileges->Control = PRIVILEGE_SET_ALL_NECESSARY;\n    requiredPrivileges->Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;\n    requiredPrivileges->Privilege[0].Luid = RtlConvertUlongToLuid(Privilege);\n\n    NtPrivilegeCheck(TokenHandle, requiredPrivileges, &result);\n\n    return result;\n}\n\n/**\n * Checks whether a privilege is present in the token and was used for access.\n * This function returns TRUE either when the privileged was used for access\n * (SE_PRIVILEGE_USED_FOR_ACCESS) or when NtPrivilegeCheck indicates success\n * and the attributes were set accordingly.\n *\n * \\param TokenHandle A handle to a token.\n * \\param Privilege The privilege constant (as ULONG) to check.\n * \\return BOOLEAN TRUE if privilege was used for access, FALSE otherwise.\n */\nBOOLEAN PhPrivilegeCheckAny(\n    _In_ HANDLE TokenHandle,\n    _In_ ULONG Privilege\n    )\n{\n    CHAR privilegesBuffer[FIELD_OFFSET(PRIVILEGE_SET, Privilege) + sizeof(LUID_AND_ATTRIBUTES) * 1];\n    PPRIVILEGE_SET requiredPrivileges;\n    BOOLEAN result = FALSE;\n\n    requiredPrivileges = (PPRIVILEGE_SET)privilegesBuffer;\n    requiredPrivileges->PrivilegeCount = 1;\n    requiredPrivileges->Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;\n    requiredPrivileges->Privilege[0].Luid = RtlConvertUlongToLuid(Privilege);\n\n    NtPrivilegeCheck(TokenHandle, requiredPrivileges, &result);\n\n    if (requiredPrivileges->Privilege[0].Attributes == SE_PRIVILEGE_USED_FOR_ACCESS)\n        return TRUE;\n\n    return FALSE;\n}\n\n/**\n * Modifies a token privilege. Can specify privilege by name or by LUID.\n *\n * \\param TokenHandle A handle to a token with TOKEN_ADJUST_PRIVILEGES access.\n * \\param PrivilegeName Optional privilege name (NULL if PrivilegeLuid supplied).\n * \\param PrivilegeLuid Optional pointer to LUID (NULL if PrivilegeName supplied).\n * \\param Attributes New attributes for the privilege (e.g. SE_PRIVILEGE_ENABLED or 0).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetTokenPrivilege(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PCWSTR PrivilegeName,\n    _In_opt_ PLUID PrivilegeLuid,\n    _In_ ULONG Attributes\n    )\n{\n    NTSTATUS status;\n    TOKEN_PRIVILEGES privileges;\n\n    privileges.PrivilegeCount = 1;\n    privileges.Privileges[0].Attributes = Attributes;\n\n    if (PrivilegeLuid)\n    {\n        privileges.Privileges[0].Luid = *PrivilegeLuid;\n    }\n    else if (PrivilegeName)\n    {\n        PH_STRINGREF privilegeName;\n\n        PhInitializeStringRefLongHint(&privilegeName, PrivilegeName);\n\n        status = PhLookupPrivilegeValue(\n            &privilegeName,\n            &privileges.Privileges[0].Luid\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n    else\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    status = NtAdjustPrivilegesToken(\n        TokenHandle,\n        FALSE,\n        &privileges,\n        0,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (status == STATUS_NOT_ALL_ASSIGNED)\n    {\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    return status;\n}\n\n/**\n * Convenience wrapper to set a privilege by numeric constant.\n *\n * \\param TokenHandle A handle to a token with TOKEN_ADJUST_PRIVILEGES access.\n * \\param Privilege The privilege constant to change (LONG).\n * \\param Attributes New attribute flags.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetTokenPrivilege2(\n    _In_ HANDLE TokenHandle,\n    _In_ LONG Privilege,\n    _In_ ULONG Attributes\n    )\n{\n    LUID privilegeLuid;\n\n    privilegeLuid = RtlConvertLongToLuid(Privilege);\n\n    return PhSetTokenPrivilege(TokenHandle, NULL, &privilegeLuid, Attributes);\n}\n\n/**\n * Adjusts a privilege for the current process token.\n *\n * \\param PrivilegeName Optional name of privilege to change (NULL if Privilege provided).\n * \\param Privilege Optional numeric privilege constant (0 if PrivilegeName provided).\n * \\param Enable TRUE to enable, FALSE to disable.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhAdjustPrivilege(\n    _In_opt_ PCWSTR PrivilegeName,\n    _In_opt_ LONG Privilege,\n    _In_ BOOLEAN Enable\n    )\n{\n    NTSTATUS status;\n    HANDLE tokenHandle;\n    TOKEN_PRIVILEGES privileges;\n\n    status = NtOpenProcessToken(\n        NtCurrentProcess(),\n        TOKEN_ADJUST_PRIVILEGES,\n        &tokenHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    privileges.PrivilegeCount = 1;\n    privileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;\n\n    if (Privilege)\n    {\n        LUID privilegeLuid;\n\n        privilegeLuid = RtlConvertLongToLuid(Privilege);\n\n        privileges.Privileges[0].Luid = privilegeLuid;\n    }\n    else if (PrivilegeName)\n    {\n        PH_STRINGREF privilegeName;\n\n        PhInitializeStringRefLongHint(&privilegeName, PrivilegeName);\n\n        status = PhLookupPrivilegeValue(\n            &privilegeName,\n            &privileges.Privileges[0].Luid\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            NtClose(tokenHandle);\n            return status;\n        }\n    }\n    else\n    {\n        NtClose(tokenHandle);\n        return STATUS_INVALID_PARAMETER_1;\n    }\n\n    status = NtAdjustPrivilegesToken(\n        tokenHandle,\n        FALSE,\n        &privileges,\n        0,\n        NULL,\n        NULL\n        );\n\n    NtClose(tokenHandle);\n\n    if (status == STATUS_NOT_ALL_ASSIGNED)\n        return STATUS_PRIVILEGE_NOT_HELD;\n\n    return status;\n}\n\n/**\n * Modifies a token group by name or SID.\n *\n * \\param TokenHandle A handle to a token with TOKEN_ADJUST_GROUPS access.\n * \\param GroupName Optional group name to lookup (NULL if GroupSid supplied).\n * \\param GroupSid Optional group SID to set (NULL if GroupName supplied).\n * \\param Attributes New attributes for the group.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetTokenGroups(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PCWSTR GroupName,\n    _In_opt_ PSID GroupSid,\n    _In_ ULONG Attributes\n    )\n{\n    NTSTATUS status;\n    TOKEN_GROUPS groups;\n\n    groups.GroupCount = 1;\n    groups.Groups[0].Attributes = Attributes;\n\n    if (GroupSid)\n    {\n        groups.Groups[0].Sid = GroupSid;\n    }\n    else if (GroupName)\n    {\n        PH_STRINGREF groupName;\n\n        PhInitializeStringRefLongHint(&groupName, GroupName);\n\n        if (!NT_SUCCESS(status = PhLookupName(&groupName, &groups.Groups[0].Sid, NULL, NULL)))\n            return status;\n    }\n    else\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    status = NtAdjustGroupsToken(\n        TokenHandle,\n        FALSE,\n        &groups,\n        0,\n        NULL,\n        NULL\n        );\n\n    if (GroupName && groups.Groups[0].Sid)\n        PhFree(groups.Groups[0].Sid);\n\n    return status;\n}\n\n/**\n * Sets the session ID for a token.\n *\n * \\param TokenHandle A handle to a token with appropriate access.\n * \\param SessionId The session id to set.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetTokenSessionId(\n    _In_ HANDLE TokenHandle,\n    _In_ ULONG SessionId\n    )\n{\n    return NtSetInformationToken(\n        TokenHandle,\n        TokenSessionId,\n        &SessionId,\n        sizeof(ULONG)\n        );\n}\n\n/**\n * Enables or disables virtualization for a token.\n *\n * \\param TokenHandle A handle to a token with TOKEN_WRITE access.\n * \\param IsVirtualizationEnabled TRUE to enable, FALSE to disable.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhSetTokenIsVirtualizationEnabled(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN IsVirtualizationEnabled\n    )\n{\n    ULONG virtualizationEnabled;\n\n    virtualizationEnabled = IsVirtualizationEnabled;\n\n    return NtSetInformationToken(\n        TokenHandle,\n        TokenVirtualizationEnabled,\n        &virtualizationEnabled,\n        sizeof(ULONG)\n        );\n}\n\n/**\n * Gets a token's integrity level RID and an optional human-readable string.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param IntegrityLevelRID Receives the integrity-level RID (last subauthority).\n * \\param IntegrityString Receives a pointer to a static descriptive string (optional).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenIntegrityLevelRID(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PMANDATORY_LEVEL_RID IntegrityLevelRID,\n    _Out_opt_ PWSTR *IntegrityString\n    )\n{\n    NTSTATUS status;\n    UCHAR mandatoryLabelBuffer[TOKEN_INTEGRITY_LEVEL_MAX_SIZE];\n    PTOKEN_MANDATORY_LABEL mandatoryLabel = (PTOKEN_MANDATORY_LABEL)mandatoryLabelBuffer;\n    ULONG returnLength;\n    ULONG subAuthoritiesCount;\n    ULONG subAuthority;\n    PWSTR integrityString;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenIntegrityLevel,\n        mandatoryLabel,\n        sizeof(mandatoryLabelBuffer),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    subAuthoritiesCount = *PhSubAuthorityCountSid(mandatoryLabel->Label.Sid);\n\n    if (subAuthoritiesCount > 0)\n    {\n        subAuthority = *PhSubAuthoritySid(mandatoryLabel->Label.Sid, subAuthoritiesCount - 1);\n    }\n    else\n    {\n        subAuthority = SECURITY_MANDATORY_UNTRUSTED_RID;\n    }\n\n    if (IntegrityString)\n    {\n        switch (subAuthority)\n        {\n        case SECURITY_MANDATORY_UNTRUSTED_RID:\n            integrityString = L\"Untrusted\";\n            break;\n        case SECURITY_MANDATORY_LOW_RID:\n            integrityString = L\"Low\";\n            break;\n        case SECURITY_MANDATORY_MEDIUM_RID:\n            integrityString = L\"Medium\";\n            break;\n        case SECURITY_MANDATORY_MEDIUM_PLUS_RID:\n            integrityString = L\"Medium+\";\n            break;\n        case SECURITY_MANDATORY_HIGH_RID:\n            integrityString = L\"High\";\n            break;\n        case SECURITY_MANDATORY_SYSTEM_RID:\n            integrityString = L\"System\";\n            break;\n        case SECURITY_MANDATORY_PROTECTED_PROCESS_RID:\n            integrityString = L\"Protected\";\n            break;\n        default:\n            integrityString = L\"Other\";\n            break;\n        }\n\n        *IntegrityString = integrityString;\n    }\n\n    if (IntegrityLevelRID)\n        *IntegrityLevelRID = subAuthority;\n\n    return status;\n}\n\n/**\n * Gets a token's integrity level as a well-known enumerated value.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param IntegrityLevel Receives the mapped MANDATORY_LEVEL enumeration (optional).\n * \\param IntegrityString Receives a static descriptive string (optional).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenIntegrityLevel(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PMANDATORY_LEVEL IntegrityLevel,\n    _Out_opt_ PWSTR *IntegrityString\n    )\n{\n    NTSTATUS status;\n    MANDATORY_LEVEL_RID integrityLevelRID;\n    MANDATORY_LEVEL integrityLevel;\n\n    status = PhGetTokenIntegrityLevelRID(TokenHandle, &integrityLevelRID, IntegrityString);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (IntegrityLevel)\n    {\n        switch (integrityLevelRID)\n        {\n        case SECURITY_MANDATORY_UNTRUSTED_RID:\n            integrityLevel = MandatoryLevelUntrusted;\n            break;\n        case SECURITY_MANDATORY_LOW_RID:\n            integrityLevel = MandatoryLevelLow;\n            break;\n        case SECURITY_MANDATORY_MEDIUM_RID:\n            integrityLevel = MandatoryLevelMedium;\n            break;\n        case SECURITY_MANDATORY_MEDIUM_PLUS_RID:\n            integrityLevel = MandatoryLevelMedium;\n            break;\n        case SECURITY_MANDATORY_HIGH_RID:\n            integrityLevel = MandatoryLevelHigh;\n            break;\n        case SECURITY_MANDATORY_SYSTEM_RID:\n            integrityLevel = MandatoryLevelSystem;\n            break;\n        case SECURITY_MANDATORY_PROTECTED_PROCESS_RID:\n            integrityLevel = MandatoryLevelSecureProcess;\n            break;\n        default:\n            return STATUS_UNSUCCESSFUL;\n        }\n\n        *IntegrityLevel = integrityLevel;\n    }\n\n    return status;\n}\n\ntypedef struct _PH_INTEGRITY_LEVEL_STRING_ENTRY\n{\n    PH_STRINGREF String;\n    PH_INTEGRITY_LEVEL IntegrityLevel;\n} PH_INTEGRITY_LEVEL_STRING_ENTRY, *PPH_INTEGRITY_LEVEL_STRING_ENTRY;\n\n/**\n * Gets a token's integrity level with extended information and a mapped stringref.\n *\n * \\param TokenHandle A handle to a token. Must have TOKEN_QUERY access.\n * \\param IntegrityLevel Receives the PH_INTEGRITY_LEVEL (as a Level value) if provided.\n * \\param IntegrityString Receives a pointer to a static PH_STRINGREF describing the level.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenIntegrityLevelEx(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PPH_INTEGRITY_LEVEL IntegrityLevel,\n    _Out_opt_ PCPH_STRINGREF* IntegrityString\n    )\n{\n    static CONST PH_STRINGREF integrityLevelDefaultString = PH_STRINGREF_INIT(L\"Other\");\n    static CONST PH_INTEGRITY_LEVEL_STRING_ENTRY integrityLevelStringTable[] =\n    {\n        { PH_STRINGREF_INIT(L\"Untrusted\"), { .Mandatory = MandatoryLevelUntrusted } },\n        { PH_STRINGREF_INIT(L\"Low\"), {.Mandatory = MandatoryLevelLow }},\n        { PH_STRINGREF_INIT(L\"Medium\"), { .Mandatory = MandatoryLevelMedium } },\n        { PH_STRINGREF_INIT(L\"Medium+\"), { .Mandatory = MandatoryLevelMedium, .Plus = TRUE } },\n        { PH_STRINGREF_INIT(L\"High\"), { .Mandatory = MandatoryLevelHigh, } },\n        { PH_STRINGREF_INIT(L\"System\"), { .Mandatory = MandatoryLevelSystem, } },\n        { PH_STRINGREF_INIT(L\"Secure\"), { .Mandatory = MandatoryLevelSecureProcess, } },\n        { PH_STRINGREF_INIT(L\"Untrusted (AppContainer)\"), { .Mandatory = MandatoryLevelUntrusted, .AppContainer = TRUE, } },\n        { PH_STRINGREF_INIT(L\"Low (AppContainer)\"), {.Mandatory = MandatoryLevelLow, .AppContainer = TRUE, } },\n        { PH_STRINGREF_INIT(L\"Medium (AppContainer)\"), { .Mandatory = MandatoryLevelMedium, .AppContainer = TRUE, } },\n        { PH_STRINGREF_INIT(L\"Medium+ (AppContainer)\"), { .Mandatory = MandatoryLevelMedium, .AppContainer = TRUE, .Plus = TRUE, } },\n        { PH_STRINGREF_INIT(L\"High (AppContainer)\"), { .Mandatory = MandatoryLevelHigh, .AppContainer = TRUE, } },\n        { PH_STRINGREF_INIT(L\"System (AppContainer)\"), { .Mandatory = MandatoryLevelSystem, .AppContainer = TRUE, } },\n        { PH_STRINGREF_INIT(L\"Secure (AppContainer)\"), { .Mandatory = MandatoryLevelSecureProcess, .AppContainer = TRUE, } },\n    };\n\n    NTSTATUS status;\n    PH_INTEGRITY_LEVEL integrityLevel;\n    MANDATORY_LEVEL_RID integrityLevelRID;\n    BOOLEAN tokenIsAppContainer;\n\n    integrityLevel.Level = 0;\n\n    if (!NT_SUCCESS(status = PhGetTokenIntegrityLevelRID(TokenHandle, &integrityLevelRID, NULL)))\n        return status;\n\n    if (IntegrityLevel)\n    {\n        switch (integrityLevelRID)\n        {\n        case SECURITY_MANDATORY_UNTRUSTED_RID:\n            integrityLevel.Mandatory = MandatoryLevelUntrusted;\n            break;\n        case SECURITY_MANDATORY_LOW_RID:\n            integrityLevel.Mandatory = MandatoryLevelLow;\n            break;\n        case SECURITY_MANDATORY_MEDIUM_RID:\n            integrityLevel.Mandatory = MandatoryLevelMedium;\n            break;\n        case SECURITY_MANDATORY_MEDIUM_PLUS_RID:\n            integrityLevel.Mandatory = MandatoryLevelMedium;\n            integrityLevel.Plus = TRUE;\n            break;\n        case SECURITY_MANDATORY_HIGH_RID:\n            integrityLevel.Mandatory = MandatoryLevelHigh;\n            break;\n        case SECURITY_MANDATORY_SYSTEM_RID:\n            integrityLevel.Mandatory = MandatoryLevelSystem;\n            break;\n        case SECURITY_MANDATORY_PROTECTED_PROCESS_RID:\n            integrityLevel.Mandatory = MandatoryLevelSecureProcess;\n            break;\n        default:\n            return STATUS_UNSUCCESSFUL;\n        }\n    }\n\n    if (NT_SUCCESS(PhGetTokenIsAppContainer(TokenHandle, &tokenIsAppContainer)) && tokenIsAppContainer)\n        integrityLevel.AppContainer = TRUE;\n\n    if (IntegrityLevel)\n        IntegrityLevel->Level = integrityLevel.Level;\n\n    if (!IntegrityString)\n        return STATUS_SUCCESS;\n\n    *IntegrityString = &integrityLevelDefaultString;\n\n    for (ULONG i = 0; i < RTL_NUMBER_OF(integrityLevelStringTable); i++)\n    {\n        if (integrityLevelStringTable[i].IntegrityLevel.Level == integrityLevel.Level)\n        {\n            *IntegrityString = &integrityLevelStringTable[i].String;\n            break;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Parses the token process trust level SID into protection type and level and\n * optionally returns readable strings and the SID string.\n *\n * \\param TokenHandle A handle to a token.\n * \\param ProtectionType Receives the protection type RID (optional).\n * \\param ProtectionLevel Receives the protection level RID (optional).\n * \\param TrustLevelString Receives a newly created or concatenated string describing the protection (optional).\n * \\param TrustLevelSidString Receives a string SID representation of the trust-level SID (optional).\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetTokenProcessTrustLevelRID(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PULONG ProtectionType,\n    _Out_opt_ PULONG ProtectionLevel,\n    _Out_opt_ PPH_STRING* TrustLevelString,\n    _Out_opt_ PPH_STRING* TrustLevelSidString\n    )\n{\n    NTSTATUS status;\n    PTOKEN_PROCESS_TRUST_LEVEL trustLevel;\n    ULONG subAuthoritiesCount;\n    ULONG protectionType;\n    ULONG protectionLevel;\n\n    status = PhGetTokenTrustLevel(TokenHandle, &trustLevel);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!trustLevel->TrustLevelSid)\n        return STATUS_UNSUCCESSFUL;\n\n    if (!PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(trustLevel->TrustLevelSid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_PROCESS_TRUST_AUTHORITY))\n        return STATUS_INVALID_SUB_AUTHORITY;\n\n    subAuthoritiesCount = *PhSubAuthorityCountSid(trustLevel->TrustLevelSid);\n\n    if (subAuthoritiesCount == SECURITY_PROCESS_TRUST_AUTHORITY_RID_COUNT)\n    {\n        protectionType = *PhSubAuthoritySid(trustLevel->TrustLevelSid, 0);\n        protectionLevel = *PhSubAuthoritySid(trustLevel->TrustLevelSid, 1);\n    }\n    else\n    {\n        protectionType = SECURITY_PROCESS_PROTECTION_TYPE_NONE_RID;\n        protectionLevel = SECURITY_PROCESS_PROTECTION_LEVEL_NONE_RID;\n    }\n\n    if (ProtectionType)\n        *ProtectionType = protectionType;\n    if (ProtectionLevel)\n        *ProtectionLevel = protectionLevel;\n\n    if (TrustLevelString)\n    {\n        static CONST PH_STRINGREF UnknownProtectionString = PH_STRINGREF_INIT(L\"Unknown\");\n        static CONST PH_STRINGREF ProtectionTypeString[] =\n        {\n            PH_STRINGREF_INIT(L\"None\"),\n            PH_STRINGREF_INIT(L\"Full\"),\n            PH_STRINGREF_INIT(L\"Lite\"),\n        };\n        static CONST PH_STRINGREF ProtectionLevelString[] =\n        {\n            PH_STRINGREF_INIT(L\" (None)\"),\n            PH_STRINGREF_INIT(L\" (WinTcb)\"),\n            PH_STRINGREF_INIT(L\" (Windows)\"),\n            PH_STRINGREF_INIT(L\" (StoreApp)\"),\n            PH_STRINGREF_INIT(L\" (Antimalware)\"),\n            PH_STRINGREF_INIT(L\" (Authenticode)\"),\n        };\n        PCPH_STRINGREF protectionTypeString = NULL;\n        PCPH_STRINGREF protectionLevelString = NULL;\n\n        switch (protectionType)\n        {\n        case SECURITY_PROCESS_PROTECTION_TYPE_NONE_RID:\n            protectionTypeString = &ProtectionTypeString[0];\n            break;\n        case SECURITY_PROCESS_PROTECTION_TYPE_FULL_RID:\n            protectionTypeString = &ProtectionTypeString[1];\n            break;\n        case SECURITY_PROCESS_PROTECTION_TYPE_LITE_RID:\n            protectionTypeString = &ProtectionTypeString[2];\n            break;\n        }\n\n        switch (protectionLevel)\n        {\n        case SECURITY_PROCESS_PROTECTION_LEVEL_NONE_RID:\n            protectionLevelString = &ProtectionLevelString[0];\n            break;\n        case SECURITY_PROCESS_PROTECTION_LEVEL_WINTCB_RID:\n            protectionLevelString = &ProtectionLevelString[1];\n            break;\n        case SECURITY_PROCESS_PROTECTION_LEVEL_WINDOWS_RID:\n            protectionLevelString = &ProtectionLevelString[2];\n            break;\n        case SECURITY_PROCESS_PROTECTION_LEVEL_APP_RID:\n            protectionLevelString = &ProtectionLevelString[3];\n            break;\n        case SECURITY_PROCESS_PROTECTION_LEVEL_ANTIMALWARE_RID:\n            protectionLevelString = &ProtectionLevelString[4];\n            break;\n        case SECURITY_PROCESS_PROTECTION_LEVEL_AUTHENTICODE_RID:\n            protectionLevelString = &ProtectionLevelString[5];\n            break;\n        }\n\n        if (protectionTypeString && protectionLevelString)\n            *TrustLevelString = PhConcatStringRef2(protectionTypeString, protectionLevelString);\n        else\n            *TrustLevelString = PhCreateString2(&UnknownProtectionString);\n    }\n\n    if (TrustLevelSidString)\n    {\n        *TrustLevelSidString = PhSidToStringSid(trustLevel->TrustLevelSid);\n    }\n\n    PhFree(trustLevel);\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/nativetxn.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n\nNTSTATUS PhpQueryTransactionManagerVariableSize(\n    _In_ HANDLE TransactionManagerHandle,\n    _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x100;\n\n    if (!NtQueryInformationTransactionManager_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryInformationTransactionManager_Import()(\n            TransactionManagerHandle,\n            TransactionManagerInformationClass,\n            buffer,\n            bufferSize,\n            NULL\n            );\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n\n            if (bufferSize > 1 * 1024 * 1024)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetTransactionManagerBasicInformation(\n    _In_ HANDLE TransactionManagerHandle,\n    _Out_ PTRANSACTIONMANAGER_BASIC_INFORMATION BasicInformation\n    )\n{\n    memset(BasicInformation, 0, sizeof(TRANSACTIONMANAGER_BASIC_INFORMATION));\n\n    if (NtQueryInformationTransactionManager_Import())\n    {\n        return NtQueryInformationTransactionManager_Import()(\n            TransactionManagerHandle,\n            TransactionManagerBasicInformation,\n            BasicInformation,\n            sizeof(TRANSACTIONMANAGER_BASIC_INFORMATION),\n            NULL\n            );\n    }\n    else\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n}\n\nNTSTATUS PhGetTransactionManagerLogFileName(\n    _In_ HANDLE TransactionManagerHandle,\n    _Out_ PPH_STRING *LogFileName\n    )\n{\n    NTSTATUS status;\n    PTRANSACTIONMANAGER_LOGPATH_INFORMATION logPathInfo;\n\n    status = PhpQueryTransactionManagerVariableSize(\n        TransactionManagerHandle,\n        TransactionManagerLogPathInformation,\n        &logPathInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (logPathInfo->LogPathLength == 0)\n    {\n        *LogFileName = PhReferenceEmptyString();\n    }\n    else\n    {\n        *LogFileName = PhCreateStringEx(\n            logPathInfo->LogPath,\n            logPathInfo->LogPathLength\n            );\n    }\n\n    PhFree(logPathInfo);\n\n    return status;\n}\n\nNTSTATUS PhpQueryTransactionVariableSize(\n    _In_ HANDLE TransactionHandle,\n    _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x100;\n\n    if (!NtQueryInformationTransaction_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryInformationTransaction_Import()(\n            TransactionHandle,\n            TransactionInformationClass,\n            buffer,\n            bufferSize,\n            NULL\n            );\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n\n            if (bufferSize > 1 * 1024 * 1024)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetTransactionBasicInformation(\n    _In_ HANDLE TransactionHandle,\n    _Out_ PTRANSACTION_BASIC_INFORMATION BasicInformation\n    )\n{\n    memset(BasicInformation, 0, sizeof(TRANSACTION_BASIC_INFORMATION));\n\n    if (NtQueryInformationTransaction_Import())\n    {\n        return NtQueryInformationTransaction_Import()(\n            TransactionHandle,\n            TransactionBasicInformation,\n            BasicInformation,\n            sizeof(TRANSACTION_BASIC_INFORMATION),\n            NULL\n            );\n    }\n    else\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n}\n\nNTSTATUS PhGetTransactionPropertiesInformation(\n    _In_ HANDLE TransactionHandle,\n    _Out_opt_ PLARGE_INTEGER Timeout,\n    _Out_opt_ TRANSACTION_OUTCOME *Outcome,\n    _Out_opt_ PPH_STRING *Description\n    )\n{\n    NTSTATUS status;\n    PTRANSACTION_PROPERTIES_INFORMATION propertiesInfo;\n\n    status = PhpQueryTransactionVariableSize(\n        TransactionHandle,\n        TransactionPropertiesInformation,\n        &propertiesInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (Timeout)\n    {\n        *Timeout = propertiesInfo->Timeout;\n    }\n\n    if (Outcome)\n    {\n        *Outcome = propertiesInfo->Outcome;\n    }\n\n    if (Description)\n    {\n        *Description = PhCreateStringEx(\n            propertiesInfo->Description,\n            propertiesInfo->DescriptionLength\n            );\n    }\n\n    PhFree(propertiesInfo);\n\n    return status;\n}\n\nNTSTATUS PhpQueryResourceManagerVariableSize(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x100;\n\n    if (!NtQueryInformationResourceManager_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryInformationResourceManager_Import()(\n            ResourceManagerHandle,\n            ResourceManagerInformationClass,\n            buffer,\n            bufferSize,\n            NULL\n            );\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n\n            if (bufferSize > 1 * 1024 * 1024)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetResourceManagerBasicInformation(\n    _In_ HANDLE ResourceManagerHandle,\n    _Out_opt_ PGUID Guid,\n    _Out_opt_ PPH_STRING *Description\n    )\n{\n    NTSTATUS status;\n    PRESOURCEMANAGER_BASIC_INFORMATION basicInfo;\n\n    status = PhpQueryResourceManagerVariableSize(\n        ResourceManagerHandle,\n        ResourceManagerBasicInformation,\n        &basicInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (Guid)\n    {\n        *Guid = basicInfo->ResourceManagerId;\n    }\n\n    if (Description)\n    {\n        if (basicInfo->DescriptionLength == 0)\n        {\n            *Description = PhReferenceEmptyString();\n        }\n        else\n        {\n            *Description = PhCreateStringEx(\n                basicInfo->Description,\n                basicInfo->DescriptionLength\n                );\n        }\n    }\n\n    PhFree(basicInfo);\n\n    return status;\n}\n\nNTSTATUS PhGetEnlistmentBasicInformation(\n    _In_ HANDLE EnlistmentHandle,\n    _Out_ PENLISTMENT_BASIC_INFORMATION BasicInformation\n    )\n{\n    memset(BasicInformation, 0, sizeof(ENLISTMENT_BASIC_INFORMATION));\n\n    if (NtQueryInformationEnlistment_Import())\n    {\n        return NtQueryInformationEnlistment_Import()(\n            EnlistmentHandle,\n            EnlistmentBasicInformation,\n            BasicInformation,\n            sizeof(ENLISTMENT_BASIC_INFORMATION),\n            NULL\n            );\n    }\n    else\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n}\n"
  },
  {
    "path": "phlib/nativeuser.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2024\n *\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <ntuser.h>\n#include <phconsole.h>\n\n/**\n * Attach this process to the console of another process.\n *\n * This function first frees any existing console association for this process by calling\n * `PhFreeConsole` to avoid leaking console handles stored in the process environment block (PEB).\n * It then calls the Win32 `AttachConsole` API using the numeric process identifier derived from\n * `ProcessId`. If `AttachConsole` succeeds, the function returns `STATUS_SUCCESS`. Otherwise\n * it converts the last Win32 error into an NTSTATUS via `PhGetLastWin32ErrorAsNtStatus`.\n * \\param[in] ProcessId Handle representing the target process whose console we want to attach to.\n * The handle value is converted to an unsigned long before calling `AttachConsole`.\n * \\return NTSTATUS STATUS_SUCCESS on success; translated Win32 error as NTSTATUS on failure.\n */\nNTSTATUS PhAttachConsole(\n    _In_ HANDLE ProcessId\n    )\n{\n    PhFreeConsole();\n\n    if (AttachConsole(HandleToUlong(ProcessId)))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Free the current console and clear PEB console-related fields.\n *\n * \\remarks The FreeConsole API doesn't zero handles it created and cached in the current\n * process environment block (PEB). It'll close the handle but does not zero the fields.\n * When these values are later recycled by the kernel with a new handle, the values in the PEB\n * are now pointing to valid objects and start getting passed to console functions despite\n * these handles are some other object. This causes all sorts of issues including crashes\n * and data corruption. To avoid these issues, we manually zero the PEB fields.\n */\nVOID PhFreeConsole(\n    VOID\n    )\n{\n    PRTL_USER_PROCESS_PARAMETERS processParameters;\n\n    FreeConsole();\n\n    // Note: FreeConsole leaks the StandardInput, StandardOutput, StandardError and ConsoleHandle.\n    // The console API is not thread-safe and these values must be set to null or we run into issues\n    // with all the other console functions since they continue using these values, we also run into\n    // issues with strict handle checking. (dmex)\n\n    processParameters = NtCurrentPeb()->ProcessParameters;\n    processParameters->StandardInput = NULL;\n    processParameters->StandardOutput = NULL;\n    processParameters->StandardError = NULL;\n    processParameters->ConsoleHandle = NULL;\n}\n\n/**\n * Retrieve a standard I/O handle for the current process.\n *\n * \\param[in] StdHandle One of `STD_INPUT_HANDLE`, `STD_OUTPUT_HANDLE` or `STD_ERROR_HANDLE`.\n * \\return HANDLE The appropriate standard handle. On older Windows versions, returns the value\n * from the PEB's `ProcessParameters`. If `StdHandle` is invalid on those versions,\n * returns `INVALID_HANDLE_VALUE`. On newer versions, returns the value returned by `GetStdHandle`.\n */\nHANDLE PhGetStdHandle(\n    _In_ ULONG StdHandle\n    )\n{\n    if (WindowsVersion < WINDOWS_NEW)\n    {\n        switch (StdHandle)\n        {\n        case STD_INPUT_HANDLE:\n            return NtCurrentPeb()->ProcessParameters->StandardInput;\n        case STD_OUTPUT_HANDLE:\n            return NtCurrentPeb()->ProcessParameters->StandardOutput;\n        case STD_ERROR_HANDLE:\n            return NtCurrentPeb()->ProcessParameters->StandardError;\n        }\n\n        return INVALID_HANDLE_VALUE;\n    }\n    else\n    {\n        return GetStdHandle(StdHandle);\n    }\n}\n\n/**\n * Query the list of process identifiers attached to a console.\n *\n * \\param[in] ProcessId Handle to the process whose console should be queried.\n * \\param[in] ProcessCount Number of entries the `ProcessList` buffer can hold.\n * \\param[out] ProcessList Buffer that receives the list of process identifiers (ULONG values).\n * \\param[out] ProcessTotal Receives the total number of processes attached to the console.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetConsoleProcessList(\n    _In_ HANDLE ProcessId,\n    _In_ ULONG ProcessCount,\n    _Out_writes_(ProcessCount) PULONG ProcessList,\n    _Out_ PULONG ProcessTotal\n    )\n{\n    NTSTATUS status;\n\n    status = PhAttachConsole(ProcessId);\n\n    if (NT_SUCCESS(status))\n    {\n        if (*ProcessTotal = GetConsoleProcessList(ProcessList, ProcessCount))\n            status = STATUS_SUCCESS;\n        else\n            status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    PhFreeConsole();\n\n    return status;\n}\n\n/**\n * Update the console foreground window for a console process.\n *\n * \\param[in] ProcessHandle Handle to the target console process.\n * \\param[in] Foreground Non-zero to set the foreground flag; zero to clear it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhConsoleSetForeground(\n    _In_ HANDLE ProcessHandle,\n    _In_ BOOLEAN Foreground\n    )\n{\n    NTSTATUS status;\n    CONSOLESETFOREGROUND consoleInfo;\n\n    if (!ConsoleControl_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    consoleInfo.ProcessHandle = ProcessHandle;\n    consoleInfo.Foreground = !!Foreground;\n\n    status = ConsoleControl_Import()(\n        ConsoleSetForeground,\n        &consoleInfo,\n        sizeof(CONSOLESETFOREGROUND)\n        );\n\n    return status;\n}\n\n/**\n * Notify the console subsystem that a console application created a new window.\n *\n * \\param[in] ProcessID Handle representing the process that created the new window.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhConsoleNotifyWindow(\n    _In_ HANDLE ProcessID\n    )\n{\n    NTSTATUS status;\n    CONSOLE_PROCESS_INFO consoleProcessInfo;\n\n    if (!ConsoleControl_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    consoleProcessInfo.Flags = CPI_NEWPROCESSWINDOW;\n    consoleProcessInfo.ProcessID = HandleToUlong(ProcessID);\n\n    status = ConsoleControl_Import()(\n        ConsoleNotifyConsoleApplication,\n        &consoleProcessInfo,\n        sizeof(CONSOLE_PROCESS_INFO)\n        );\n\n    return status;\n}\n\n/**\n * Updates the psuedo owner of the console window.\n *\n * \\param[in] ProcessID Handle representing the process whose console window owner is being set.\n * \\param[in] ThreadId Handle representing the thread associated with the window owner.\n * \\param[in] WindowHandle Window handle (HWND) to associate with the console process/thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhConsoleSetWindow(\n    _In_ HANDLE ProcessID,\n    _In_ HANDLE ThreadId,\n    _In_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n    CONSOLEWINDOWOWNER consoleInfo;\n\n    if (!ConsoleControl_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    consoleInfo.ProcessId = HandleToUlong(ProcessID);\n    consoleInfo.ThreadId = HandleToUlong(ThreadId);\n    consoleInfo.WindowHandle = WindowHandle;\n\n    status = ConsoleControl_Import()(\n        ConsoleSetWindowOwner,\n        &consoleInfo,\n        sizeof(CONSOLEWINDOWOWNER)\n        );\n\n    return status;\n}\n\n/**\n * \\brief Request the console subsystem to end a console task (send console event).\n *\n * Builds a `CONSOLEENDTASK` structure and invokes the `ConsoleEndTask` `ConsoleControl` operation.\n * The `ConsoleEventCode` is set to `CTRL_C_EVENT` and `ConsoleFlags` is zeroed.\n *\n * \\param[in] ProcessId Handle of the process whose console task should be ended.\n * \\param[in] WindowHandle Window handle (HWND) associated with the console to be signaled.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The semantics of ending a console task are determined by the console subsystem; callers\n * should ensure they understand the impact of sending `CTRL_C_EVENT` to the target console.\n */\nNTSTATUS PhConsoleEndTask(\n    _In_ HANDLE ProcessId,\n    _In_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n    CONSOLEENDTASK consoleInfo;\n\n    if (!ConsoleControl_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    consoleInfo.ProcessId = ProcessId;\n    consoleInfo.WindowHandle = WindowHandle;\n    consoleInfo.ConsoleEventCode = CTRL_C_EVENT;\n    consoleInfo.ConsoleFlags = 0;\n\n    status = ConsoleControl_Import()(\n        ConsoleEndTask,\n        &consoleInfo,\n        sizeof(CONSOLEENDTASK)\n        );\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/phlib.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>17.0</VCProjectVersion>\n    <ProjectGuid>{477D0215-F252-41A1-874B-F27E3EA1ED17}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectName>phlib</ProjectName>\n    <RootNamespace>phlib</RootNamespace>\n    <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Lib>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);..\\tools\\thirdparty\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>kphlib_um.lib;thirdparty.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Lib>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);..\\tools\\thirdparty\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>kphlib_um.lib;thirdparty.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Lib>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);..\\tools\\thirdparty\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>kphlib_um.lib;thirdparty.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Lib>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);..\\tools\\thirdparty\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>kphlib_um.lib;thirdparty.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Lib>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);..\\tools\\thirdparty\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>kphlib_um.lib;thirdparty.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;$(SolutionDir)phlib\\include;$(SolutionDir)kphlib\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Lib>\n      <AdditionalLibraryDirectories>$(SolutionDir)kphlib\\bin\\$(Configuration)$(PlatformArchitecture);..\\tools\\thirdparty\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>kphlib_um.lib;thirdparty.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"apiimport.c\" />\n    <ClCompile Include=\"appresolver.c\" />\n    <ClCompile Include=\"appruntime.c\" />\n    <ClCompile Include=\"avltree.c\" />\n    <ClCompile Include=\"basestring.c\" />\n    <ClCompile Include=\"basesup.c\" />\n    <ClCompile Include=\"bcd.cpp\" />\n    <ClCompile Include=\"circbuf.c\" />\n    <ClCompile Include=\"colorbox.c\" />\n    <ClCompile Include=\"cpysave.c\" />\n    <ClCompile Include=\"data.c\" />\n    <ClCompile Include=\"directdraw.cpp\" />\n    <ClCompile Include=\"dspick.c\" />\n    <ClCompile Include=\"emenu.c\" />\n    <ClCompile Include=\"error.c\" />\n    <ClCompile Include=\"extlv.c\" />\n    <ClCompile Include=\"fastlock.c\" />\n    <ClCompile Include=\"filepool.c\" />\n    <ClCompile Include=\"firmware.c\" />\n    <ClCompile Include=\"format.c\" />\n    <ClCompile Include=\"format_std.cpp\" />\n    <ClCompile Include=\"global.c\" />\n    <ClCompile Include=\"graph.c\" />\n    <ClCompile Include=\"guisup.c\" />\n    <ClCompile Include=\"guisuplistview.cpp\" />\n    <ClCompile Include=\"handle.c\" />\n    <ClCompile Include=\"hexedit.c\" />\n    <ClCompile Include=\"hndlinfo.c\" />\n    <ClCompile Include=\"http.c\" />\n    <ClCompile Include=\"hvsocketcontrol.c\" />\n    <ClCompile Include=\"icotobmp.c\" />\n    <ClCompile Include=\"filestream.c\" />\n    <ClCompile Include=\"imgcoherency.c\" />\n    <ClCompile Include=\"apistubs.cpp\" />\n    <ClCompile Include=\"mapldr.c\" />\n    <ClCompile Include=\"json.c\" />\n    <ClCompile Include=\"kph.c\" />\n    <ClCompile Include=\"kphcomms.c\" />\n    <ClCompile Include=\"lsamsup.c\" />\n    <ClCompile Include=\"lsasup.c\" />\n    <ClCompile Include=\"mapexlf.c\" />\n    <ClCompile Include=\"mapimg.c\" />\n    <ClCompile Include=\"maplib.c\" />\n    <ClCompile Include=\"native.c\" />\n    <ClCompile Include=\"nativefile.c\" />\n    <ClCompile Include=\"nativejob.c\" />\n    <ClCompile Include=\"nativekey.c\" />\n    <ClCompile Include=\"nativeprocess.c\" />\n    <ClCompile Include=\"nativesocket.c\" />\n    <ClCompile Include=\"nativeflt.c\" />\n    <ClCompile Include=\"nativepipe.c\" />\n    <ClCompile Include=\"nativemodule.c\" />\n    <ClCompile Include=\"nativethread.c\" />\n    <ClCompile Include=\"nativetoken.c\" />\n    <ClCompile Include=\"nativetxn.c\" />\n    <ClCompile Include=\"nativeuser.c\" />\n    <ClCompile Include=\"provider.c\" />\n    <ClCompile Include=\"queuedlock.c\" />\n    <ClCompile Include=\"ref.c\" />\n    <ClCompile Include=\"searchbox.c\" />\n    <ClCompile Include=\"secdata.c\" />\n    <ClCompile Include=\"secedit.c\" />\n    <ClCompile Include=\"secwmi.c\" />\n    <ClCompile Include=\"settings.c\" />\n    <ClCompile Include=\"strsrch.c\" />\n    <ClCompile Include=\"symprv_std.cpp\" />\n    <ClCompile Include=\"theme.c\" />\n    <ClCompile Include=\"util.c\" />\n    <ClCompile Include=\"svcsup.c\" />\n    <ClCompile Include=\"symprv.c\" />\n    <ClCompile Include=\"sync.c\" />\n    <ClCompile Include=\"treenew.c\" />\n    <ClCompile Include=\"verify.c\" />\n    <ClCompile Include=\"workqueue.c\" />\n    <ClCompile Include=\"wslsup.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\apiimport.h\" />\n    <ClInclude Include=\"include\\appresolver.h\" />\n    <ClInclude Include=\"include\\appresolverp.h\" />\n    <ClInclude Include=\"include\\bcd.h\" />\n    <ClInclude Include=\"include\\phafd.h\" />\n    <ClInclude Include=\"include\\phconsole.h\" />\n    <ClInclude Include=\"include\\phfirmware.h\" />\n    <ClInclude Include=\"include\\searchbox.h\" />\n    <ClInclude Include=\"include\\cpysave.h\" />\n    <ClInclude Include=\"include\\exlf.h\" />\n    <ClInclude Include=\"include\\exprodid.h\" />\n    <ClInclude Include=\"include\\filepool.h\" />\n    <ClInclude Include=\"include\\filepoolp.h\" />\n    <ClInclude Include=\"include\\filestream.h\" />\n    <ClInclude Include=\"include\\handle.h\" />\n    <ClInclude Include=\"include\\hndlinfo.h\" />\n    <ClInclude Include=\"include\\hvsocketcontrol.h\" />\n    <ClInclude Include=\"include\\json.h\" />\n    <ClInclude Include=\"include\\kphcomms.h\" />\n    <ClInclude Include=\"include\\guisupview.h\" />\n    <ClInclude Include=\"include\\lsamsup.h\" />\n    <ClInclude Include=\"include\\lsasup.h\" />\n    <ClInclude Include=\"include\\mapimg.h\" />\n    <ClInclude Include=\"include\\mapldr.h\" />\n    <ClInclude Include=\"include\\phbasesup.h\" />\n    <ClInclude Include=\"include\\phconfig.h\" />\n    <ClInclude Include=\"include\\phdata.h\" />\n    <ClInclude Include=\"include\\phintrin.h\" />\n    <ClInclude Include=\"include\\phintrnl.h\" />\n    <ClInclude Include=\"include\\phnative.h\" />\n    <ClInclude Include=\"include\\phnativeinl.h\" />\n    <ClInclude Include=\"include\\circbuf.h\" />\n    <ClInclude Include=\"include\\circbuf_h.h\" />\n    <ClInclude Include=\"circbuf_i.h\" />\n    <ClInclude Include=\"include\\colorbox.h\" />\n    <ClInclude Include=\"include\\phutil.h\" />\n    <ClInclude Include=\"include\\provider.h\" />\n    <ClInclude Include=\"include\\secedit.h\" />\n    <ClInclude Include=\"include\\secwmi.h\" />\n    <ClInclude Include=\"include\\settings.h\" />\n    <ClInclude Include=\"include\\strsrch.h\" />\n    <ClInclude Include=\"include\\svcsup.h\" />\n    <ClInclude Include=\"include\\symprvp.h\" />\n    <ClInclude Include=\"include\\thirdparty.h\" />\n    <ClInclude Include=\"include\\trace.h\" />\n    <ClInclude Include=\"include\\treenew.h\" />\n    <ClInclude Include=\"include\\treenewp.h\" />\n    <ClInclude Include=\"include\\verify.h\" />\n    <ClInclude Include=\"include\\dltmgr.h\" />\n    <ClInclude Include=\"include\\dspick.h\" />\n    <ClInclude Include=\"include\\emenu.h\" />\n    <ClInclude Include=\"include\\fastlock.h\" />\n    <ClInclude Include=\"format_i.h\" />\n    <ClInclude Include=\"include\\graph.h\" />\n    <ClInclude Include=\"include\\guisupp.h\" />\n    <ClInclude Include=\"include\\handlep.h\" />\n    <ClInclude Include=\"include\\hexedit.h\" />\n    <ClInclude Include=\"include\\hexeditp.h\" />\n    <ClInclude Include=\"include\\filestreamp.h\" />\n    <ClInclude Include=\"include\\kphuser.h\" />\n    <ClInclude Include=\"include\\wslsup.h\" />\n    <ClInclude Include=\"include\\ph.h\" />\n    <ClInclude Include=\"include\\phbase.h\" />\n    <ClInclude Include=\"include\\guisup.h\" />\n    <ClInclude Include=\"include\\phnet.h\" />\n    <ClInclude Include=\"include\\phsup.h\" />\n    <ClInclude Include=\"include\\queuedlock.h\" />\n    <ClInclude Include=\"include\\ref.h\" />\n    <ClInclude Include=\"include\\refp.h\" />\n    <ClInclude Include=\"include\\seceditp.h\" />\n    <ClInclude Include=\"include\\symprv.h\" />\n    <ClInclude Include=\"include\\templ.h\" />\n    <ClInclude Include=\"include\\verifyp.h\" />\n    <ClInclude Include=\"include\\workqueue.h\" />\n    <ClInclude Include=\"include\\workqueuep.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>"
  },
  {
    "path": "phlib/phlib.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"basesup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"circbuf.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"colorbox.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"data.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"dspick.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"emenu.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"error.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"extlv.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"fastlock.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"format.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"global.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"graph.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"guisup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"handle.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hexedit.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hndlinfo.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"icotobmp.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kph.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mapimg.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"maplib.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"native.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"provider.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"queuedlock.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ref.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"secdata.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"secedit.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"svcsup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"symprv.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sync.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"verify.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"workqueue.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"cpysave.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"filepool.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"treenew.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"apiimport.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"avltree.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"filestream.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lsamsup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lsasup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"util.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"settings.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mapexlf.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"appresolver.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"theme.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wslsup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"http.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"format_std.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"json.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"imgcoherency.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"bcd.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphcomms.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"directdraw.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"secwmi.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mapldr.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"appruntime.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"symprv_std.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"strsrch.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativeuser.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativemodule.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativepipe.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hvsocketcontrol.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativethread.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativeflt.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"searchbox.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"guisuplistview.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"firmware.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativetoken.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativesocket.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativeprocess.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativefile.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"apistubs.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativejob.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativetxn.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"nativekey.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"basestring.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\circbuf.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\circbuf_h.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"circbuf_i.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\colorbox.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\dltmgr.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\dspick.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\emenu.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\fastlock.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"format_i.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\graph.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\guisupp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\handlep.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hexedit.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hexeditp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\ph.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phbase.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phnet.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phsup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\queuedlock.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\ref.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\refp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\seceditp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\symprv.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\templ.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\verifyp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phintrnl.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphuser.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\cpysave.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\filepool.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\filepoolp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\treenew.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\treenewp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\verify.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\secedit.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\symprvp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\apiimport.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\handle.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\workqueue.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\mapimg.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\workqueuep.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\filestreamp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\filestream.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hndlinfo.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\provider.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phdata.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phconfig.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phbasesup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\lsasup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\lsamsup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phnativeinl.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phnative.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\svcsup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phutil.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\guisup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\settings.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\json.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\exlf.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\appresolver.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\appresolverp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\wslsup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\exprodid.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\bcd.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphcomms.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\secwmi.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\mapldr.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phintrin.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hvsocketcontrol.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\strsrch.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\guisupview.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\thirdparty.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\searchbox.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phconsole.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phfirmware.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phafd.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\trace.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "phlib/provider.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *\n */\n\n/*\n * Provider objects allow a function to be executed periodically. This is managed by a\n * synchronization timer object which is signaled periodically. The use of a timer object as opposed\n * to a simple sleep call means that the length of time a provider function takes to execute has no\n * effect on the interval between runs.\n *\n * In contrast to callback objects, the context passed to provider functions must be\n * reference-counted objects. This means that it is not guaranteed that the function will not be in\n * execution after the unregister operation is complete. However, the since the context object is\n * reference-counted, there are no safety issues.\n *\n * Providers can be boosted, which causes them to be run immediately ignoring the interval. This is\n * separate to the periodic runs, and does not cause the next periodic run to be missed. Providers,\n * even when boosted, always run on the same provider thread. The other option would be to have the\n * boosting thread run the provider function directly, which would involve unnecessary blocking and\n * synchronization.\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <provider.h>\n\n#ifdef DEBUG\nPPH_LIST PhDbgProviderList;\nPH_QUEUED_LOCK PhDbgProviderListLock = PH_QUEUED_LOCK_INIT;\n#endif\n\n/**\n * Initializes a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n * \\param Interval The interval between each run, in milliseconds.\n */\nVOID PhInitializeProviderThread(\n    _Out_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ ULONG Interval\n    )\n{\n    ProviderThread->ThreadHandle = NULL;\n    ProviderThread->TimerHandle = NULL;\n    ProviderThread->Interval = Interval;\n    ProviderThread->State = ProviderThreadStopped;\n\n    PhInitializeQueuedLock(&ProviderThread->Lock);\n    InitializeListHead(&ProviderThread->ListHead);\n    ProviderThread->BoostCount = 0;\n    ProviderThread->Flags = 0;\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgProviderListLock);\n    if (!PhDbgProviderList)\n        PhDbgProviderList = PhCreateList(4);\n    PhAddItemList(PhDbgProviderList, ProviderThread);\n    PhReleaseQueuedLockExclusive(&PhDbgProviderListLock);\n#endif\n}\n\n/**\n * Frees resources used by a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n */\nVOID PhDeleteProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    )\n{\n#ifdef DEBUG\n    ULONG index;\n#endif\n    // Nothing\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgProviderListLock);\n    if ((index = PhFindItemList(PhDbgProviderList, ProviderThread)) != ULONG_MAX)\n        PhRemoveItemList(PhDbgProviderList, index);\n    PhReleaseQueuedLockExclusive(&PhDbgProviderListLock);\n#endif\n}\n\n/**\n * The start routine for the provider thread.\n *\n * \\param Parameter A pointer to user-defined data passed to the thread.\n * \\return NTSTATUS status code indicating success or failure of the thread routine.\n */\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI PhpProviderThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_PROVIDER_THREAD providerThread = (PPH_PROVIDER_THREAD)Parameter;\n    NTSTATUS status = STATUS_SUCCESS;\n    PLIST_ENTRY listEntry;\n    PPH_PROVIDER_REGISTRATION registration;\n    PPH_PROVIDER_FUNCTION providerFunction;\n    PVOID object;\n    LIST_ENTRY tempListHead;\n\n    PhSetThreadName(NtCurrentThread(), L\"ProviderThread\");\n\n    PhInitializeAutoPool(&autoPool);\n\n    while (providerThread->State != ProviderThreadStopping)\n    {\n        // Keep removing and executing providers from the list until there are no more. Each removed\n        // provider will be placed on the temporary list. After this is done, all providers on the\n        // temporary list will be re-added to the list again.\n        //\n        // The key to this working safely with the other functions (boost, register, unregister) is\n        // that at all times when the mutex is not acquired every single provider must be in a list\n        // (main list or the temp list).\n\n        InitializeListHead(&tempListHead);\n\n        PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n        // Main loop.\n\n        // We check the status variable for STATUS_ALERTED, which means that someone is requesting\n        // that a provider be boosted. Note that if they alert this thread while we are not waiting\n        // on the timer, when we do perform the wait it will return immediately with STATUS_ALERTED.\n\n        while (TRUE)\n        {\n            if (status == STATUS_ALERTED)\n            {\n                // Check if we have any more providers to boost. Note that this always works because\n                // boosted providers are always in front of normal providers. Therefore we will\n                // never mistakenly boost normal providers.\n\n                if (providerThread->BoostCount == 0)\n                    break;\n            }\n\n            listEntry = RemoveHeadList(&providerThread->ListHead);\n\n            if (listEntry == &providerThread->ListHead)\n                break;\n\n            registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry);\n\n            // Add the provider to the temp list.\n            InsertTailList(&tempListHead, listEntry);\n\n            if (status != STATUS_ALERTED)\n            {\n                if (!registration->Enabled || registration->Unregistering)\n                    continue;\n            }\n            else\n            {\n                // If we're boosting providers, we don't care if they are enabled or not. However,\n                // we have to make sure any providers which are being unregistered get a chance to\n                // fix the boost count.\n\n                if (registration->Unregistering)\n                {\n                    PhReleaseQueuedLockExclusive(&providerThread->Lock);\n                    PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n                    continue;\n                }\n            }\n\n            if (status == STATUS_ALERTED)\n            {\n                assert(registration->Boosting);\n                registration->Boosting = FALSE;\n                providerThread->BoostCount--;\n            }\n\n            providerFunction = registration->Function;\n            object = registration->Object;\n\n            if (object)\n                PhReferenceObject(object);\n\n            registration->RunId++;\n\n            PhReleaseQueuedLockExclusive(&providerThread->Lock);\n\n            if (PhAcquireRundownProtection(&registration->RundownProtect))\n            {\n                providerFunction(object);\n\n                PhReleaseRundownProtection(&registration->RundownProtect);\n            }\n\n            PhDrainAutoPool(&autoPool);\n\n            PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n            if (object)\n                PhDereferenceObject(object);\n        }\n\n        // Re-add the items in the temp list to the main list.\n\n        while ((listEntry = RemoveHeadList(&tempListHead)) != &tempListHead)\n        {\n            registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry);\n\n            // We must insert boosted providers at the front of the list in order to maintain the\n            // condition that boosted providers are always in front of normal providers. This occurs\n            // when the timer is signaled just before a boosting provider alerts our thread.\n            if (!registration->Boosting)\n                InsertTailList(&providerThread->ListHead, listEntry);\n            else\n                InsertHeadList(&providerThread->ListHead, listEntry);\n        }\n\n        PhReleaseQueuedLockExclusive(&providerThread->Lock);\n\n        // Perform an alertable wait so we can be woken up by someone telling us to boost providers,\n        // or to terminate.\n        status = NtWaitForSingleObject(\n            providerThread->TimerHandle,\n            TRUE,\n            NULL\n            );\n    }\n\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Starts a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n */\nNTSTATUS PhStartProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    )\n{\n    NTSTATUS status;\n\n    if (ProviderThread->State != ProviderThreadStopped)\n        return STATUS_PENDING;\n\n    //\n    // Create the synchronization timer.\n    //\n\n    if (WindowsVersion >= WINDOWS_11 && ProviderThread->UseHighResolution && NtCreateTimer2_Import())\n    {\n        status = NtCreateTimer2_Import()(\n            &ProviderThread->TimerHandle,\n            NULL,\n            NULL,\n            TIMER2_BUILD_ATTRIBUTES(SynchronizationTimer, TRUE),\n            TIMER_ALL_ACCESS\n            );\n    }\n    else\n    {\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        OBJECT_ATTRIBUTES objectAttributes;\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            NULL,\n            OBJ_EXCLUSIVE,\n            NULL,\n            NULL\n            );\n\n        status = NtCreateTimer(\n            &ProviderThread->TimerHandle,\n            TIMER_ALL_ACCESS,\n            &objectAttributes,\n            SynchronizationTimer\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Set the run interval for the timer.\n\n    status = PhSetIntervalProviderThread(\n        ProviderThread,\n        ProviderThread->Interval\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        NtClose(ProviderThread->TimerHandle);\n        ProviderThread->TimerHandle = NULL;\n        return status;\n    }\n\n    // Create and start the thread.\n\n    status = PhCreateUserThread(\n        NtCurrentProcess(),\n        NULL,\n        THREAD_ALL_ACCESS, // THREAD_ALERT | SYNCHRONIZE,\n        0,\n        0,\n        0,\n        0,\n        PhpProviderThreadStart,\n        ProviderThread,\n        &ProviderThread->ThreadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        NtClose(ProviderThread->TimerHandle);\n        ProviderThread->TimerHandle = NULL;\n        return status;\n    }\n\n    ProviderThread->State = ProviderThreadRunning;\n    return STATUS_SUCCESS;\n}\n\n/**\n * Stops a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n */\nVOID PhStopProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    )\n{\n    if (ProviderThread->State != ProviderThreadRunning)\n        return;\n\n    // Verify all providers are unregistered\n    PhAcquireQueuedLockExclusive(&ProviderThread->Lock);\n    if (!IsListEmpty(&ProviderThread->ListHead))\n    {\n        PhReleaseQueuedLockExclusive(&ProviderThread->Lock);\n        assert(FALSE && \"Stopping provider thread with active registrations\");\n    }\n    else\n    {\n        PhReleaseQueuedLockExclusive(&ProviderThread->Lock);\n    }\n\n    // Signal to the thread that we are shutting down, and wait for it to exit.\n    ProviderThread->State = ProviderThreadStopping;\n    NtAlertThread(ProviderThread->ThreadHandle); // wake it up\n    NtWaitForSingleObject(ProviderThread->ThreadHandle, FALSE, NULL);\n\n    // Free resources.\n    NtClose(ProviderThread->ThreadHandle);\n    ProviderThread->ThreadHandle = NULL;\n\n    NtClose(ProviderThread->TimerHandle);\n    ProviderThread->TimerHandle = NULL;\n\n    ProviderThread->State = ProviderThreadStopped;\n}\n\n/**\n * Sets the run interval for a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n * \\param Interval The interval between each run, in milliseconds.\n */\nNTSTATUS PhSetIntervalProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ LONG Interval\n    )\n{\n    LARGE_INTEGER interval;\n\n    if (Interval < 0)\n        return STATUS_INVALID_PARAMETER;\n\n    // Prevent intervals > 24 hours (86400000 ms)\n    if (Interval > (24 * 60 * 60 * 1000))\n        return STATUS_INVALID_PARAMETER;\n\n    if (!ProviderThread->TimerHandle)\n        return STATUS_INVALID_HANDLE;\n\n    ProviderThread->Interval = Interval;\n\n    interval.QuadPart = -(LONGLONG)UInt32x32To64(Interval, PH_TIMEOUT_MS);\n\n    if (WindowsVersion >= WINDOWS_11 && ProviderThread->UseHighResolution && NtSetTimer2_Import())\n    {\n        LARGE_INTEGER period;\n        T2_SET_PARAMETERS timerParameters;\n\n        period.QuadPart = UInt32x32To64(Interval, PH_TIMEOUT_MS);\n\n        memset(&timerParameters, 0, sizeof(T2_SET_PARAMETERS));\n        timerParameters.Version = TIMER2_SET_PARAMETERS_CURRENT_VERSION;\n        timerParameters.NoWakeTolerance = 0;\n\n        return NtSetTimer2_Import()(\n            ProviderThread->TimerHandle,\n            &interval,\n            &period,\n            &timerParameters\n            );\n    }\n\n    return NtSetTimer(\n        ProviderThread->TimerHandle,\n        &interval,\n        NULL,\n        NULL,\n        FALSE,\n        Interval,\n        NULL\n        );\n}\n\n/**\n * Registers a provider with a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n * \\param Function The provider function.\n * \\param Object A pointer to an object to pass to the provider function. The object must be managed\n * by the reference-counting system.\n * \\param Registration A variable which receives registration information for the provider.\n * \\remarks The provider is initially disabled. Call PhSetEnabledProvider() to enable it.\n */\nVOID PhRegisterProvider(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ PPH_PROVIDER_FUNCTION Function,\n    _In_opt_ PVOID Object,\n    _Out_ PPH_PROVIDER_REGISTRATION Registration\n    )\n{\n    PhInitializeRundownProtection(&Registration->RundownProtect);\n    Registration->ProviderThread = ProviderThread;\n    Registration->Function = Function;\n    Registration->Object = Object;\n    Registration->RunId = 0;\n    Registration->Enabled = FALSE;\n    Registration->Unregistering = FALSE;\n    Registration->Boosting = FALSE;\n\n    if (Object)\n        PhReferenceObject(Object);\n\n    PhAcquireQueuedLockExclusive(&ProviderThread->Lock);\n    InsertTailList(&ProviderThread->ListHead, &Registration->ListEntry);\n    PhReleaseQueuedLockExclusive(&ProviderThread->Lock);\n}\n\n/**\n * Unregisters a provider.\n *\n * \\param Registration A pointer to the registration object for a provider.\n * \\remarks The provider function may still be in execution once this function returns.\n */\nVOID PhUnregisterProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration\n    )\n{\n    PPH_PROVIDER_THREAD providerThread;\n\n    providerThread = Registration->ProviderThread;\n\n    Registration->Unregistering = TRUE;\n\n    // There are two possibilities for removal:\n    // 1. The provider is removed while the thread is not in the main loop. This is the normal case.\n    // 2. The provider is removed while the thread is in the main loop. In that case the provider\n    //    will be removed from the temp list and so it won't be re-added to the main list.\n\n    PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n    RemoveEntryList(&Registration->ListEntry);\n\n    // Fix the boost count.\n    if (Registration->Boosting)\n        providerThread->BoostCount--;\n\n    PhReleaseQueuedLockExclusive(&providerThread->Lock);\n\n    PhWaitForRundownProtection(&Registration->RundownProtect);\n\n    // Reacquire the lock to safely dereference the object\n    PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n    // The user-supplied object must be dereferenced\n    // while the mutex is held.\n    if (Registration->Object)\n        PhDereferenceObject(Registration->Object);\n\n    PhReleaseQueuedLockExclusive(&providerThread->Lock);\n}\n\n/**\n * Causes a provider to be queued for immediate execution.\n *\n * \\param Registration A pointer to the registration object for a provider.\n * \\param FutureRunId A variable which receives the run ID of the future run.\n * \\return TRUE if the operation was successful; FALSE if the provider is being unregistered, the\n * provider is already being boosted, or the provider thread is not running.\n * \\remarks Boosted providers will be run immediately, ignoring the run interval. Boosting will not\n * however affect the normal runs.\n */\n_Use_decl_annotations_\nBOOLEAN PhBoostProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration,\n    _Out_opt_ PULONG FutureRunId\n    )\n{\n    PPH_PROVIDER_THREAD providerThread;\n    ULONG futureRunId;\n\n    providerThread = Registration->ProviderThread;\n\n    // Simply move to the provider to the front of the list. This works even if the provider is\n    // currently in the temp list.\n\n    PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n    // Abort if the provider is already being boosted, unregistering, or the provider thread is stopping/stopped.\n    if (Registration->Unregistering || Registration->Boosting || providerThread->State != ProviderThreadRunning)\n    {\n        PhReleaseQueuedLockExclusive(&providerThread->Lock);\n        return FALSE;\n    }\n\n    RemoveEntryList(&Registration->ListEntry);\n    InsertHeadList(&providerThread->ListHead, &Registration->ListEntry);\n\n    Registration->Boosting = TRUE;\n    providerThread->BoostCount++;\n\n    futureRunId = Registration->RunId + 1;\n\n    PhReleaseQueuedLockExclusive(&providerThread->Lock);\n\n    // Wake up the thread.\n    NtAlertThread(providerThread->ThreadHandle);\n\n    if (FutureRunId)\n        *FutureRunId = futureRunId;\n\n    return TRUE;\n}\n\n/**\n * Gets the current run ID of a provider.\n *\n * \\param Registration A pointer to the registration object for a provider.\n */\nULONG PhGetRunIdProvider(\n    _In_ PPH_PROVIDER_REGISTRATION Registration\n    )\n{\n    return Registration->RunId;\n}\n\n/**\n * Gets whether a provider is enabled.\n *\n * \\param Registration A pointer to the registration object for a provider.\n */\nBOOLEAN PhGetEnabledProvider(\n    _In_ PPH_PROVIDER_REGISTRATION Registration\n    )\n{\n    PPH_PROVIDER_THREAD providerThread;\n    BOOLEAN enabled;\n\n    providerThread = Registration->ProviderThread;\n\n    PhAcquireQueuedLockShared(&providerThread->Lock);\n    enabled = !!Registration->Enabled;\n    PhReleaseQueuedLockShared(&providerThread->Lock);\n\n    return enabled;\n}\n\n/**\n * Sets whether a provider is enabled.\n *\n * \\param Registration A pointer to the registration object for a provider.\n * \\param Enabled TRUE if the provider is enabled, otherwise FALSE.\n */\nVOID PhSetEnabledProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration,\n    _In_ BOOLEAN Enabled\n    )\n{\n    PPH_PROVIDER_THREAD providerThread;\n\n    providerThread = Registration->ProviderThread;\n\n    PhAcquireQueuedLockExclusive(&providerThread->Lock);\n    Registration->Enabled = Enabled;\n    PhReleaseQueuedLockExclusive(&providerThread->Lock);\n}\n\n/**\n * Sets whether a provider thread uses a high-resolution timer.\n *\n * \\param ProviderThread A pointer to the provider thread object.\n * \\param UseHighResolutionTimer TRUE to use a high-resolution timer, otherwise FALSE.\n */\nVOID PhSetHighResolutionProvider(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ BOOLEAN UseHighResolution\n    )\n{\n    ProviderThread->UseHighResolution = !!UseHighResolution;\n}\n"
  },
  {
    "path": "phlib/queuedlock.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *\n */\n\n/*\n * Queued lock, a.k.a. push lock (kernel-mode) or slim reader-writer lock (user-mode).\n *\n * The queued lock is:\n * * Around 10% faster than the fast lock.\n * * Only the size of a pointer.\n * * Low on resource usage (no additional kernel objects are created for blocking).\n *\n * The usual flags are used for contention-free acquire/release. When there is contention,\n * stack-based wait blocks are chained. The first wait block contains the shared owners count which\n * is decremented by shared releasers.\n *\n * Naturally these wait blocks would be chained in FILO order, but list optimization is done for two\n * purposes:\n * * Finding the last wait block (where the shared owners count is stored). This is implemented by\n *   the Last pointer.\n * * Unblocking the wait blocks in FIFO order. This is implemented by the Previous pointer.\n *\n * The optimization is incremental - each optimization run will stop at the first optimized wait\n * block. Any needed optimization is completed just before waking waiters.\n *\n * The waiters list/chain has the following restrictions:\n * * At any time wait blocks may be pushed onto the list.\n * * While waking waiters, the list may not be traversed nor optimized.\n * * When there are multiple shared owners, shared releasers may traverse the list (to find the last\n *   wait block). This is not an issue because waiters wouldn't be woken until there are no more\n *   shared owners.\n * * List optimization may be done at any time except for when someone else is waking waiters. This\n *   is controlled by the traversing bit.\n *\n * The traversing bit has the following rules:\n * * The list may be optimized only after the traversing bit is set, checking that it wasn't set\n *   already. If it was set, it would indicate that someone else is optimizing the list or waking\n *   waiters.\n * * Before waking waiters the traversing bit must be set. If it was set already, just clear the\n *   owned bit.\n * * If during list optimization the owned bit is detected to be cleared, the function begins waking\n *   waiters. This is because the owned bit is cleared when a releaser fails to set the traversing\n *   bit.\n *\n * Blocking is implemented through a process-wide keyed event. A spin count is also used before\n * blocking on the keyed event.\n *\n * Queued locks can act as condition variables, with wait, pulse and pulse all support. Waiters are\n * released in FIFO order.\n *\n * Queued locks can act as wake events. These are designed for tiny one-bit locks which share a\n * single event to block on. Spurious wake-ups are a part of normal operation.\n */\n\n#include <phbase.h>\n\n#include <fastlock.h>\n#include <phintrnl.h>\n#include <queuedlock.h>\n\nVOID FASTCALL PhpfOptimizeQueuedLockList(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    );\n\nVOID FASTCALL PhpfWakeQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    );\n\nVOID FASTCALL PhpfWakeQueuedLockEx(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN IgnoreOwned,\n    _In_ BOOLEAN WakeAll\n    );\n\nstatic HANDLE PhQueuedLockKeyedEventHandle;\nstatic ULONG PhQueuedLockSpinCount = 2000;\n\nNTSTATUS PhQueuedLockInitialization(\n    VOID\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        NULL,\n        OBJ_EXCLUSIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateKeyedEvent(\n        &PhQueuedLockKeyedEventHandle,\n        KEYEDEVENT_ALL_ACCESS,\n        &objectAttributes,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n        return status;\n\n    if (PhSystemBasicInformation.NumberOfProcessors > 1)\n        PhQueuedLockSpinCount = 4000;\n    else\n        PhQueuedLockSpinCount = 0;\n\n    return status;\n}\n\n/**\n * Pushes a wait block onto a queued lock's waiters list.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n * \\param Exclusive Whether the wait block is in exclusive mode.\n * \\param WaitBlock A variable which receives the resulting wait block structure.\n * \\param Optimize A variable which receives a boolean indicating whether to optimize the waiters\n * list.\n * \\param NewValue The old value of the queued lock. This value is useful only if the function\n * returns FALSE.\n * \\param CurrentValue The new value of the queued lock. This value is useful only if the function\n * returns TRUE.\n *\n * \\return TRUE if the wait block was pushed onto the waiters list, otherwise FALSE.\n *\n * \\remarks\n * \\li The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_OWNED.\n * \\li Do not move the wait block location after this function is called.\n * \\li The \\a Optimize boolean is a hint to call PhpfOptimizeQueuedLockList() if the function\n * succeeds. It is recommended, but not essential that this occurs.\n * \\li Call PhpBlockOnQueuedWaitBlock() to wait for the wait block to be unblocked.\n */\nFORCEINLINE BOOLEAN PhpPushQueuedWaitBlock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN Exclusive,\n    _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock,\n    _Out_ PBOOLEAN Optimize,\n    _Out_ PULONG_PTR NewValue,\n    _Out_ PULONG_PTR CurrentValue\n    )\n{\n    ULONG_PTR newValue;\n    BOOLEAN optimize;\n\n    WaitBlock->Previous = NULL; // set later by optimization\n    optimize = FALSE;\n\n    if (Exclusive)\n        WaitBlock->Flags = PH_QUEUED_WAITER_EXCLUSIVE | PH_QUEUED_WAITER_SPINNING;\n    else\n        WaitBlock->Flags = PH_QUEUED_WAITER_SPINNING;\n\n    if (Value & PH_QUEUED_LOCK_WAITERS)\n    {\n        // We're not the first waiter.\n\n        WaitBlock->Last = NULL; // set later by optimization\n        WaitBlock->Next = PhGetQueuedLockWaitBlock(Value);\n        WaitBlock->SharedOwners = 0;\n\n        // Push our wait block onto the list.\n        // Set the traversing bit because we'll be optimizing the list.\n        newValue = ((ULONG_PTR)WaitBlock) | (Value & PH_QUEUED_LOCK_FLAGS) |\n            PH_QUEUED_LOCK_TRAVERSING;\n\n        if (!(Value & PH_QUEUED_LOCK_TRAVERSING))\n            optimize = TRUE;\n    }\n    else\n    {\n        // We're the first waiter.\n\n        WaitBlock->Last = WaitBlock; // indicate that this is the last wait block\n\n        if (Exclusive)\n        {\n            // We're the first waiter. Save the shared owners count.\n            WaitBlock->SharedOwners = (ULONG)PhGetQueuedLockSharedOwners(Value);\n\n            if (WaitBlock->SharedOwners > 1)\n            {\n                newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED |\n                    PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_MULTIPLE_SHARED;\n            }\n            else\n            {\n                newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED |\n                    PH_QUEUED_LOCK_WAITERS;\n            }\n        }\n        else\n        {\n            // We're waiting in shared mode, which means there can't be any shared owners (otherwise\n            // we would've acquired the lock already).\n\n            WaitBlock->SharedOwners = 0;\n\n            newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED |\n                PH_QUEUED_LOCK_WAITERS;\n        }\n    }\n\n    *Optimize = optimize;\n    *CurrentValue = newValue;\n\n    newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n        (volatile PVOID *)&QueuedLock->Value,\n        (PVOID)newValue,\n        (PVOID)Value\n        );\n\n    *NewValue = newValue;\n\n    return newValue == Value;\n}\n\n/**\n * Finds the last wait block in the waiters list.\n *\n * \\param Value The current value of the queued lock.\n *\n * \\return A pointer to the last wait block.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS,\n * \\ref PH_QUEUED_LOCK_MULTIPLE_SHARED or\n * \\ref PH_QUEUED_LOCK_TRAVERSING.\n */\nFORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpFindLastQueuedWaitBlock(\n    _In_ ULONG_PTR Value\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK lastWaitBlock;\n\n    waitBlock = PhGetQueuedLockWaitBlock(Value);\n\n    // Traverse the list until we find the last wait block.\n    // The Last pointer should be set by list optimization, allowing us to skip all, if not most of\n    // the wait blocks.\n\n    while (TRUE)\n    {\n        lastWaitBlock = waitBlock->Last;\n\n        if (lastWaitBlock)\n        {\n            // Follow the Last pointer. This can mean two things: the pointer was set by list\n            // optimization, or this wait block is actually the last wait block (set when it was\n            // pushed onto the list).\n            waitBlock = lastWaitBlock;\n            break;\n        }\n\n        waitBlock = waitBlock->Next;\n    }\n\n    return waitBlock;\n}\n\n/**\n * Waits for a wait block to be unblocked.\n *\n * \\param WaitBlock A wait block.\n * \\param Spin TRUE to spin, FALSE to block immediately.\n * \\param Timeout A timeout value.\n */\n_May_raise_ FORCEINLINE NTSTATUS PhpBlockOnQueuedWaitBlock(\n    _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock,\n    _In_ BOOLEAN Spin,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n    ULONG i;\n\n    if (Spin)\n    {\n        PHLIB_INC_STATISTIC(QlBlockSpins);\n\n        for (i = PhQueuedLockSpinCount; i != 0; i--)\n        {\n            if (!(ReadULongAcquire(&WaitBlock->Flags) & PH_QUEUED_WAITER_SPINNING))\n                return STATUS_SUCCESS;\n\n            YieldProcessor();\n        }\n    }\n\n    if (_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT))\n    {\n        PHLIB_INC_STATISTIC(QlBlockWaits);\n\n        status = NtWaitForKeyedEvent(\n            PhQueuedLockKeyedEventHandle,\n            WaitBlock,\n            FALSE,\n            Timeout\n            );\n\n        // If an error occurred (timeout is not an error), raise an exception as it is nearly\n        // impossible to recover from this situation.\n        if (!NT_SUCCESS(status))\n            PhRaiseStatus(status);\n    }\n    else\n    {\n        status = STATUS_SUCCESS;\n    }\n\n    return status;\n}\n\n/**\n * Unblocks a wait block.\n *\n * \\param WaitBlock A wait block.\n *\n * \\remarks The wait block is in an undefined state after it is unblocked. Do not attempt to read\n * any values from it. All relevant information should be saved before unblocking the wait block.\n */\n_May_raise_ FORCEINLINE VOID PhpUnblockQueuedWaitBlock(\n    _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    )\n{\n    NTSTATUS status;\n\n    if (!_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT))\n    {\n        if (!NT_SUCCESS(status = NtReleaseKeyedEvent(\n            PhQueuedLockKeyedEventHandle,\n            WaitBlock,\n            FALSE,\n            NULL\n            )))\n            PhRaiseStatus(status);\n    }\n}\n\n/**\n * Optimizes a queued lock waiters list.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n * \\param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS, \\ref PH_QUEUED_LOCK_TRAVERSING.\n */\nFORCEINLINE VOID PhpOptimizeQueuedLockListEx(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN IgnoreOwned\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK firstWaitBlock;\n    PPH_QUEUED_WAIT_BLOCK lastWaitBlock;\n    PPH_QUEUED_WAIT_BLOCK previousWaitBlock;\n\n    value = ReadULongPtrAcquire(&Value);\n\n    while (TRUE)\n    {\n        assert(value & PH_QUEUED_LOCK_TRAVERSING);\n\n        if (!IgnoreOwned && !(value & PH_QUEUED_LOCK_OWNED))\n        {\n            // Someone has requested that we wake waiters.\n            PhpfWakeQueuedLock(QueuedLock, value);\n            break;\n        }\n\n        // Perform the optimization.\n\n        waitBlock = PhGetQueuedLockWaitBlock(value);\n        firstWaitBlock = waitBlock;\n\n        while (TRUE)\n        {\n            lastWaitBlock = waitBlock->Last;\n\n            if (lastWaitBlock)\n            {\n                // Save a pointer to the last wait block in the first wait block and stop\n                // optimizing.\n                //\n                // We don't need to continue setting Previous pointers because the last optimization\n                // run would have set them already.\n\n                firstWaitBlock->Last = lastWaitBlock;\n                break;\n            }\n\n            previousWaitBlock = waitBlock;\n            waitBlock = waitBlock->Next;\n            waitBlock->Previous = previousWaitBlock;\n        }\n\n        // Try to clear the traversing bit.\n\n        newValue = value - PH_QUEUED_LOCK_TRAVERSING;\n\n        if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n            (volatile PVOID *)&QueuedLock->Value,\n            (PVOID)newValue,\n            (PVOID)value\n            )) == value)\n            break;\n\n        // Either someone pushed a wait block onto the list or someone released ownership. In either\n        // case we need to go back.\n\n        value = newValue;\n    }\n}\n\n/**\n * Optimizes a queued lock waiters list.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS, \\ref PH_QUEUED_LOCK_TRAVERSING.\n */\nVOID FASTCALL PhpfOptimizeQueuedLockList(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    )\n{\n    PhpOptimizeQueuedLockListEx(QueuedLock, Value, FALSE);\n}\n\n/**\n * Dequeues the appropriate number of wait blocks in a queued lock.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n * \\param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks.\n * \\param WakeAll TRUE to remove all wait blocks, FALSE to decide based on the wait block type.\n */\nFORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpPrepareToWakeQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN IgnoreOwned,\n    _In_ BOOLEAN WakeAll\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK firstWaitBlock;\n    PPH_QUEUED_WAIT_BLOCK lastWaitBlock;\n    PPH_QUEUED_WAIT_BLOCK previousWaitBlock;\n\n    value = ReadULongPtrAcquire(&Value);\n\n    while (TRUE)\n    {\n        // If there are multiple shared owners, no one is going to wake waiters since the lock would\n        // still be owned. Also if there are multiple shared owners they may be traversing the list.\n        // While that is safe when done concurrently with list optimization, we may be removing and\n        // waking waiters.\n        assert(!(value & PH_QUEUED_LOCK_MULTIPLE_SHARED));\n        assert(IgnoreOwned || (value & PH_QUEUED_LOCK_TRAVERSING));\n\n        // There's no point in waking a waiter if the lock is owned. Clear the traversing bit.\n        while (!IgnoreOwned && (value & PH_QUEUED_LOCK_OWNED))\n        {\n            newValue = value - PH_QUEUED_LOCK_TRAVERSING;\n\n            if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n                (volatile PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                return NULL;\n\n            value = newValue;\n        }\n\n        // Finish up any needed optimization (setting the Previous pointers) while finding the last\n        // wait block.\n\n        waitBlock = PhGetQueuedLockWaitBlock(value);\n        firstWaitBlock = waitBlock;\n\n        while (TRUE)\n        {\n            lastWaitBlock = waitBlock->Last;\n\n            if (lastWaitBlock)\n            {\n                waitBlock = lastWaitBlock;\n                break;\n            }\n\n            previousWaitBlock = waitBlock;\n            waitBlock = waitBlock->Next;\n            waitBlock->Previous = previousWaitBlock;\n        }\n\n        // Unlink the relevant wait blocks and clear the traversing bit before we wake waiters.\n\n        if (\n            !WakeAll &&\n            (waitBlock->Flags & PH_QUEUED_WAITER_EXCLUSIVE) &&\n            (previousWaitBlock = waitBlock->Previous)\n            )\n        {\n            // We have an exclusive waiter and there are multiple waiters. We'll only be waking this\n            // waiter.\n\n            // Unlink the wait block from the list. Although other wait blocks may have their Last\n            // pointers set to this wait block, the algorithm to find the last wait block will stop\n            // here. Likewise the Next pointers are never followed beyond this point, so we don't\n            // need to clear those.\n            firstWaitBlock->Last = previousWaitBlock;\n\n            // Make sure we only wake this waiter.\n            waitBlock->Previous = NULL;\n\n            if (!IgnoreOwned)\n            {\n                // Clear the traversing bit.\n                _InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_TRAVERSING);\n            }\n\n            break;\n        }\n        else\n        {\n            // We're waking an exclusive waiter and there is only one waiter, or we are waking a\n            // shared waiter and possibly others.\n\n            newValue = 0;\n\n            if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n                (volatile PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                break;\n\n            // Someone changed the lock (acquired it or pushed a wait block).\n\n            value = newValue;\n        }\n    }\n\n    return waitBlock;\n}\n\n/**\n * Wakes waiters in a queued lock.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS, \\ref PH_QUEUED_LOCK_TRAVERSING. The function assumes the following\n * flags are not set:\n * \\ref PH_QUEUED_LOCK_MULTIPLE_SHARED.\n */\nVOID FASTCALL PhpfWakeQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK previousWaitBlock;\n\n    waitBlock = PhpPrepareToWakeQueuedLock(QueuedLock, Value, FALSE, FALSE);\n\n    // Wake waiters.\n\n    while (waitBlock)\n    {\n        previousWaitBlock = waitBlock->Previous;\n        PhpUnblockQueuedWaitBlock(waitBlock);\n        waitBlock = previousWaitBlock;\n    }\n}\n\n/**\n * Wakes waiters in a queued lock.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n * \\param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks.\n * \\param WakeAll TRUE to wake all waiters, FALSE to decide based on the wait block type.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS, \\ref PH_QUEUED_LOCK_TRAVERSING. The function assumes the following\n * flags are not set:\n * \\ref PH_QUEUED_LOCK_MULTIPLE_SHARED.\n */\nVOID FASTCALL PhpfWakeQueuedLockEx(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN IgnoreOwned,\n    _In_ BOOLEAN WakeAll\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK previousWaitBlock;\n\n    waitBlock = PhpPrepareToWakeQueuedLock(QueuedLock, Value, IgnoreOwned, WakeAll);\n\n    // Wake waiters.\n\n    while (waitBlock)\n    {\n        previousWaitBlock = waitBlock->Previous;\n        PhpUnblockQueuedWaitBlock(waitBlock);\n        waitBlock = previousWaitBlock;\n    }\n}\n\n/**\n * Acquires a queued lock in exclusive mode.\n *\n * \\param QueuedLock A queued lock.\n */\nVOID FASTCALL PhfAcquireQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR currentValue;\n    BOOLEAN optimize;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n\n    value = ReadULongPtrAcquire(&QueuedLock->Value);\n\n    while (TRUE)\n    {\n        if (!(value & PH_QUEUED_LOCK_OWNED))\n        {\n            if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n                (volatile PVOID *)&QueuedLock->Value,\n                (PVOID)(value + PH_QUEUED_LOCK_OWNED),\n                (PVOID)value\n                )) == value)\n                break;\n        }\n        else\n        {\n            if (PhpPushQueuedWaitBlock(\n                QueuedLock,\n                value,\n                TRUE,\n                &waitBlock,\n                &optimize,\n                &newValue,\n                &currentValue\n                ))\n            {\n                if (optimize)\n                    PhpfOptimizeQueuedLockList(QueuedLock, currentValue);\n\n                PHLIB_INC_STATISTIC(QlAcquireExclusiveBlocks);\n                PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL);\n            }\n        }\n\n        value = newValue;\n    }\n}\n\n/**\n * Acquires a queued lock in shared mode.\n *\n * \\param QueuedLock A queued lock.\n */\nVOID FASTCALL PhfAcquireQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR currentValue;\n    BOOLEAN optimize;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n\n    value = ReadULongPtrAcquire(&QueuedLock->Value);\n\n    while (TRUE)\n    {\n        // We can't acquire if there are waiters for two reasons:\n        //\n        // We want to prioritize exclusive acquires over shared acquires. There's currently no fast,\n        // safe way of finding the last wait block and incrementing the shared owners count here.\n        if (\n            !(value & PH_QUEUED_LOCK_WAITERS) &&\n            (!(value & PH_QUEUED_LOCK_OWNED) || (PhGetQueuedLockSharedOwners(value) > 0))\n            )\n        {\n            newValue = (value + PH_QUEUED_LOCK_SHARED_INC) | PH_QUEUED_LOCK_OWNED;\n\n            if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n                (volatile PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                break;\n        }\n        else\n        {\n            if (PhpPushQueuedWaitBlock(\n                QueuedLock,\n                value,\n                FALSE,\n                &waitBlock,\n                &optimize,\n                &newValue,\n                &currentValue\n                ))\n            {\n                if (optimize)\n                    PhpfOptimizeQueuedLockList(QueuedLock, currentValue);\n\n                PHLIB_INC_STATISTIC(QlAcquireSharedBlocks);\n                PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL);\n            }\n        }\n\n        value = newValue;\n    }\n}\n\n/**\n * Releases a queued lock in exclusive mode.\n *\n * \\param QueuedLock A queued lock.\n */\nVOID FASTCALL PhfReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR currentValue;\n\n    value = ReadULongPtrAcquire(&QueuedLock->Value);\n\n    while (TRUE)\n    {\n        assert(value & PH_QUEUED_LOCK_OWNED);\n        assert((value & PH_QUEUED_LOCK_WAITERS) || (PhGetQueuedLockSharedOwners(value) == 0));\n\n        if ((value & (PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_TRAVERSING)) != PH_QUEUED_LOCK_WAITERS)\n        {\n            // There are no waiters or someone is traversing the list.\n            //\n            // If there are no waiters, we're simply releasing ownership. If someone is traversing\n            // the list, clearing the owned bit is a signal for them to wake waiters.\n\n            newValue = value - PH_QUEUED_LOCK_OWNED;\n\n            if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n                (volatile PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                break;\n        }\n        else\n        {\n            // We need to wake waiters and no one is traversing the list.\n            // Try to set the traversing bit and wake waiters.\n\n            newValue = value - PH_QUEUED_LOCK_OWNED + PH_QUEUED_LOCK_TRAVERSING;\n            currentValue = newValue;\n\n            if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n                (volatile PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n            {\n                PhpfWakeQueuedLock(QueuedLock, currentValue);\n                break;\n            }\n        }\n\n        value = newValue;\n    }\n}\n\n/**\n * Wakes waiters in a queued lock for releasing it in exclusive mode.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS. The function assumes the following flags are not set:\n * \\ref PH_QUEUED_LOCK_MULTIPLE_SHARED, \\ref PH_QUEUED_LOCK_TRAVERSING.\n */\nVOID FASTCALL PhfWakeForReleaseQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    )\n{\n    ULONG_PTR newValue;\n\n    newValue = Value + PH_QUEUED_LOCK_TRAVERSING;\n\n    if ((ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n        (volatile PVOID *)&QueuedLock->Value,\n        (PVOID)newValue,\n        (PVOID)Value\n        ) == Value)\n    {\n        PhpfWakeQueuedLock(QueuedLock, newValue);\n    }\n}\n\n/**\n * Releases a queued lock in shared mode.\n *\n * \\param QueuedLock A queued lock.\n */\nVOID FASTCALL PhfReleaseQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR currentValue;\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n\n    value = ReadULongPtrAcquire(&QueuedLock->Value);\n\n    while (!(value & PH_QUEUED_LOCK_WAITERS))\n    {\n        assert(value & PH_QUEUED_LOCK_OWNED);\n        assert((value & PH_QUEUED_LOCK_WAITERS) || (PhGetQueuedLockSharedOwners(value) > 0));\n\n        if (PhGetQueuedLockSharedOwners(value) > 1)\n            newValue = value - PH_QUEUED_LOCK_SHARED_INC;\n        else\n            newValue = 0;\n\n        if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n            (volatile PVOID *)&QueuedLock->Value,\n            (PVOID)newValue,\n            (PVOID)value\n            )) == value)\n            return;\n\n        value = newValue;\n    }\n\n    if (value & PH_QUEUED_LOCK_MULTIPLE_SHARED)\n    {\n        // Unfortunately we have to find the last wait block and decrement the shared owners count.\n        waitBlock = PhpFindLastQueuedWaitBlock(value);\n\n        if ((ULONG)_InterlockedDecrement((PLONG)&waitBlock->SharedOwners) > 0)\n            return;\n    }\n\n    while (TRUE)\n    {\n        if (value & PH_QUEUED_LOCK_TRAVERSING)\n        {\n            newValue = value & ~(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_MULTIPLE_SHARED);\n\n            if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n                (volatile PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                break;\n        }\n        else\n        {\n            newValue = (value & ~(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_MULTIPLE_SHARED)) |\n                PH_QUEUED_LOCK_TRAVERSING;\n            currentValue = newValue;\n\n            if ((newValue = (ULONG_PTR)(PULONG_PTR)_InterlockedCompareExchangePointer(\n                (volatile PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n            {\n                PhpfWakeQueuedLock(QueuedLock, currentValue);\n                break;\n            }\n        }\n\n        value = newValue;\n    }\n}\n\n/**\n * Wakes one thread sleeping on a condition variable.\n *\n * \\param Condition A condition variable.\n *\n * \\remarks The associated lock must be acquired before calling the function.\n */\nVOID FASTCALL PhfPulseCondition(\n    _Inout_ PPH_CONDITION Condition\n    )\n{\n    if (Condition->Value & PH_QUEUED_LOCK_WAITERS)\n        PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, FALSE);\n}\n\n/**\n * Wakes all threads sleeping on a condition variable.\n *\n * \\param Condition A condition variable.\n *\n * \\remarks The associated lock must be acquired before calling the function.\n */\nVOID FASTCALL PhfPulseAllCondition(\n    _Inout_ PPH_CONDITION Condition\n    )\n{\n    if (Condition->Value & PH_QUEUED_LOCK_WAITERS)\n        PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, TRUE);\n}\n\n/**\n * Sleeps on a condition variable.\n *\n * \\param Condition A condition variable.\n * \\param Lock A queued lock to release/acquire in exclusive mode.\n * \\param Timeout Not implemented.\n *\n * \\remarks The associated lock must be acquired before calling the function.\n */\n_Use_decl_annotations_\nVOID FASTCALL PhfWaitForCondition(\n    _Inout_ PPH_CONDITION Condition,\n    _Inout_ PPH_QUEUED_LOCK Lock,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR currentValue;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n    BOOLEAN optimize;\n\n    value = ReadULongPtrAcquire(&Condition->Value);\n\n    while (TRUE)\n    {\n        if (PhpPushQueuedWaitBlock(\n            Condition,\n            value,\n            TRUE,\n            &waitBlock,\n            &optimize,\n            &value,\n            &currentValue\n            ))\n        {\n            if (optimize)\n            {\n                PhpOptimizeQueuedLockListEx(Condition, currentValue, TRUE);\n            }\n\n            PhReleaseQueuedLockExclusive(Lock);\n\n            PhpBlockOnQueuedWaitBlock(&waitBlock, FALSE, NULL);\n\n            // Don't use the inline variant; it is extremely likely that the lock is still owned.\n            PhfAcquireQueuedLockExclusive(Lock);\n\n            break;\n        }\n    }\n}\n\n/**\n * Sleeps on a condition variable.\n *\n * \\param Condition A condition variable.\n * \\param Lock A pointer to a lock.\n * \\param Flags A combination of flags controlling the operation.\n * \\param Timeout Not implemented.\n */\nVOID FASTCALL PhfWaitForConditionEx(\n    _Inout_ PPH_CONDITION Condition,\n    _Inout_ PVOID Lock,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR currentValue;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n    BOOLEAN optimize;\n\n    value = ReadULongPtrAcquire(&Condition->Value);\n\n    while (TRUE)\n    {\n        if (PhpPushQueuedWaitBlock(\n            Condition,\n            value,\n            TRUE,\n            &waitBlock,\n            &optimize,\n            &value,\n            &currentValue\n            ))\n        {\n            if (optimize)\n            {\n                PhpOptimizeQueuedLockListEx(Condition, currentValue, TRUE);\n            }\n\n            switch (Flags & PH_CONDITION_WAIT_LOCK_TYPE_MASK)\n            {\n            case PH_CONDITION_WAIT_QUEUED_LOCK:\n                __analysis_assume_lock_acquired(*(PPH_QUEUED_LOCK)Lock);\n                if (!(Flags & PH_CONDITION_WAIT_SHARED))\n                    PhReleaseQueuedLockExclusive((PPH_QUEUED_LOCK)Lock);\n                else\n                    PhReleaseQueuedLockShared((PPH_QUEUED_LOCK)Lock);\n                break;\n            case PH_CONDITION_WAIT_CRITICAL_SECTION:\n                __analysis_assume_lock_acquired(*(PRTL_CRITICAL_SECTION)Lock);\n                RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)Lock);\n                break;\n            case PH_CONDITION_WAIT_FAST_LOCK:\n                __analysis_assume_lock_acquired(*(PPH_FAST_LOCK)Lock);\n                if (!(Flags & PH_CONDITION_WAIT_SHARED))\n                    PhReleaseFastLockExclusive((PPH_FAST_LOCK)Lock);\n                else\n                    PhReleaseFastLockShared((PPH_FAST_LOCK)Lock);\n                break;\n            }\n\n            if (!(Flags & PH_CONDITION_WAIT_SPIN))\n            {\n                PhpBlockOnQueuedWaitBlock(&waitBlock, FALSE, NULL);\n            }\n            else\n            {\n                PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL);\n            }\n\n            switch (Flags & PH_CONDITION_WAIT_LOCK_TYPE_MASK)\n            {\n            case PH_CONDITION_WAIT_QUEUED_LOCK:\n                if (!(Flags & PH_CONDITION_WAIT_SHARED))\n                    PhfAcquireQueuedLockExclusive((PPH_QUEUED_LOCK)Lock);\n                else\n                    PhfAcquireQueuedLockShared((PPH_QUEUED_LOCK)Lock);\n                break;\n            case PH_CONDITION_WAIT_CRITICAL_SECTION:\n                RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)Lock);\n                break;\n            case PH_CONDITION_WAIT_FAST_LOCK:\n                if (!(Flags & PH_CONDITION_WAIT_SHARED))\n                    PhAcquireFastLockExclusive((PPH_FAST_LOCK)Lock);\n                else\n                    PhAcquireFastLockShared((PPH_FAST_LOCK)Lock);\n                break;\n            }\n\n            break;\n        }\n    }\n}\n\n/**\n * Queues a wait block to a wake event.\n *\n * \\param WakeEvent A wake event.\n * \\param WaitBlock A wait block.\n *\n * \\remarks If you later determine that the wait should not occur, you must call PhfSetWakeEvent()\n * to dequeue the wait block.\n */\nVOID FASTCALL PhfQueueWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK value;\n    PPH_QUEUED_WAIT_BLOCK newValue;\n\n    WaitBlock->Flags = PH_QUEUED_WAITER_SPINNING;\n\n    value = _InterlockedCompareExchangePointer((volatile PVOID *)&WakeEvent->Value, NULL, NULL);\n\n    while (TRUE)\n    {\n        WaitBlock->Next = value;\n\n        if ((newValue = _InterlockedCompareExchangePointer(\n            (volatile PVOID *)&WakeEvent->Value,\n            WaitBlock,\n            value\n            )) == value)\n            break;\n\n        value = newValue;\n    }\n}\n\n/**\n * Sets a wake event, unblocking all queued wait blocks.\n *\n * \\param WakeEvent A wake event.\n * \\param WaitBlock A wait block for a cancelled wait, otherwise NULL.\n */\nVOID FASTCALL PhfSetWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK nextWaitBlock;\n\n    // Pop all waiters and unblock them.\n\n    waitBlock = _InterlockedExchangePointer((volatile PVOID *)&WakeEvent->Value, NULL);\n\n    while (waitBlock)\n    {\n        nextWaitBlock = waitBlock->Next;\n        PhpUnblockQueuedWaitBlock(waitBlock);\n        waitBlock = nextWaitBlock;\n    }\n\n    if (WaitBlock)\n    {\n        // We're cancelling a wait; the thread called this function instead of PhfWaitForWakeEvent.\n        // This will remove all waiters from the list. However, we may not have popped and unblocked\n        // the cancelled wait block ourselves. Another thread may have popped all waiters but not\n        // unblocked them yet at this point:\n        //\n        // 1. This thread: calls PhfQueueWakeEvent.\n        // 2. This thread: code determines that the wait should be cancelled.\n        // 3. Other thread: calls PhfSetWakeEvent and pops our wait block off. It hasn't unblocked\n        //    any wait blocks yet.\n        // 4. This thread: calls PhfSetWakeEvent. Since all wait blocks have been popped, we don't\n        //    do anything. The caller function exits, making our wait block invalid.\n        // 5. Other thread: tries to unblock our wait block. Anything could happen, since our caller\n        //    already returned.\n        //\n        // The solution is to (always) wait for an unblock. Note that the check below for the\n        // spinning flag is not required, but it is a small optimization. If the wait block has been\n        // unblocked (i.e. the spinning flag is cleared), then there's no danger.\n\n        if (WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING)\n            PhpBlockOnQueuedWaitBlock(WaitBlock, FALSE, NULL);\n    }\n}\n\n/**\n * Waits for a wake event to be set.\n *\n * \\param WakeEvent A wake event.\n * \\param WaitBlock A wait block previously queued to the wake event using PhfQueueWakeEvent().\n * \\param Spin TRUE to spin on the wake event before blocking, FALSE to block immediately.\n * \\param Timeout A timeout value.\n *\n * \\remarks Wake events are subject to spurious wakeups. You should call this function in a loop\n * which checks a predicate.\n */\nNTSTATUS FASTCALL PhfWaitForWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock,\n    _In_ BOOLEAN Spin,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n\n    status = PhpBlockOnQueuedWaitBlock(WaitBlock, Spin, Timeout);\n\n    if (status != STATUS_SUCCESS)\n    {\n        // Probably a timeout. There's no way of unlinking the wait block safely, so just wake\n        // everyone.\n        PhSetWakeEvent(WakeEvent, WaitBlock);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/ref.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *\n */\n\n#include <phbase.h>\n#include <refp.h>\n\n#include <phintrnl.h>\n#include <workqueue.h>\n\nPPH_OBJECT_TYPE PhObjectTypeObject = NULL;\nSLIST_HEADER PhObjectDeferDeleteListHead;\nPH_FREE_LIST PhObjectSmallFreeList;\nPPH_OBJECT_TYPE PhAllocType = NULL;\n\nULONG PhObjectTypeCount = 0;\nPPH_OBJECT_TYPE PhObjectTypeTable[PH_OBJECT_TYPE_TABLE_SIZE];\n\nstatic ULONG PhpAutoPoolTlsIndex;\n\n#ifdef DEBUG\nLIST_ENTRY PhDbgObjectListHead;\nPH_QUEUED_LOCK PhDbgObjectListLock = PH_QUEUED_LOCK_INIT;\nPPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook = NULL;\n#endif\n\n#define REF_STAT_UP(Name) PHLIB_INC_STATISTIC(Name)\n\n/**\n * Initializes the object manager module.\n */\nNTSTATUS PhRefInitialization(\n    VOID\n    )\n{\n    PH_OBJECT_TYPE dummyObjectType;\n\n#ifdef DEBUG\n    InitializeListHead(&PhDbgObjectListHead);\n#endif\n\n    PhInitializeSListHead(&PhObjectDeferDeleteListHead);\n    PhInitializeFreeList(\n        &PhObjectSmallFreeList,\n        PhAddObjectHeaderSize(PH_OBJECT_SMALL_OBJECT_SIZE),\n        PH_OBJECT_SMALL_OBJECT_COUNT\n        );\n\n    // Create the fundamental object type.\n\n    memset(&dummyObjectType, 0, sizeof(PH_OBJECT_TYPE));\n    PhObjectTypeObject = &dummyObjectType; // PhCreateObject expects an object type.\n    PhObjectTypeTable[0] = &dummyObjectType; // PhCreateObject also expects PhObjectTypeTable[0] to be filled in.\n    PhObjectTypeObject = PhCreateObjectType(L\"Type\", 0, NULL);\n\n    // Now that the fundamental object type exists, fix it up.\n    PhObjectToObjectHeader(PhObjectTypeObject)->TypeIndex = PhObjectTypeObject->TypeIndex;\n    PhObjectTypeObject->NumberOfObjects = 1;\n\n    // Create the allocated memory object type.\n    PhAllocType = PhCreateObjectType(L\"Alloc\", 0, NULL);\n\n    // Reserve a slot for the auto pool.\n    PhpAutoPoolTlsIndex = PhTlsAlloc();\n\n    if (PhpAutoPoolTlsIndex == TLS_OUT_OF_INDEXES)\n        return STATUS_NO_MEMORY;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Allocates a object.\n *\n * \\param ObjectSize The size of the object.\n * \\param ObjectType The type of the object.\n *\n * \\return A pointer to the newly allocated object.\n */\n_May_raise_ PVOID PhCreateObject(\n    _In_ SIZE_T ObjectSize,\n    _In_ PPH_OBJECT_TYPE ObjectType\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n\n    // Allocate storage for the object. Note that this includes the object header followed by the\n    // object body.\n    objectHeader = PhpAllocateObject(ObjectType, ObjectSize);\n\n    // Object type statistics.\n    _InterlockedIncrement((PLONG)&ObjectType->NumberOfObjects);\n\n    // Initialize the object header.\n    objectHeader->RefCount = 1;\n    objectHeader->TypeIndex = ObjectType->TypeIndex;\n    // objectHeader->Flags is set by PhpAllocateObject.\n\n    REF_STAT_UP(RefObjectsCreated);\n\n#ifdef DEBUG\n    {\n        USHORT capturedFrames;\n\n        capturedFrames = RtlCaptureStackBackTrace(1, 16, objectHeader->StackBackTrace, NULL);\n        memset(\n            &objectHeader->StackBackTrace[capturedFrames],\n            0,\n            sizeof(objectHeader->StackBackTrace) - capturedFrames * sizeof(PVOID)\n            );\n    }\n\n    PhAcquireQueuedLockExclusive(&PhDbgObjectListLock);\n    InsertTailList(&PhDbgObjectListHead, &objectHeader->ObjectListEntry);\n    PhReleaseQueuedLockExclusive(&PhDbgObjectListLock);\n\n    {\n        PPH_CREATE_OBJECT_HOOK dbgCreateObjectHook;\n\n        dbgCreateObjectHook = PhDbgCreateObjectHook;\n\n        if (dbgCreateObjectHook)\n        {\n            dbgCreateObjectHook(\n                PhObjectHeaderToObject(objectHeader),\n                ObjectSize,\n                0,\n                ObjectType\n                );\n        }\n    }\n#endif\n\n    return PhObjectHeaderToObject(objectHeader);\n}\n\n/**\n * References the specified object.\n *\n * \\param Object A pointer to the object to reference.\n *\n * \\return The object.\n */\nPVOID PhReferenceObject(\n    _In_ PVOID Object\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n\n    objectHeader = PhObjectToObjectHeader(Object);\n    // Increment the reference count.\n    _InterlockedIncrement(&objectHeader->RefCount);\n\n    return Object;\n}\n\n/**\n * References the specified object.\n *\n * \\param Object A pointer to the object to reference.\n * \\param RefCount The number of references to add.\n *\n * \\return The object.\n */\n_May_raise_ PVOID PhReferenceObjectEx(\n    _In_ PVOID Object,\n    _In_ LONG RefCount\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n    LONG oldRefCount;\n\n    assert(RefCount >= 0);\n\n    objectHeader = PhObjectToObjectHeader(Object);\n    // Increase the reference count.\n    oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, RefCount);\n\n    return Object;\n}\n\n/**\n * Attempts to reference an object and fails if it is being destroyed.\n *\n * \\param Object The object to reference if it is not being deleted.\n *\n * \\return The object itself if the object was referenced, NULL if it was being deleted and was not\n * referenced.\n *\n * \\remarks This function is useful if a reference to an object is held, protected by a mutex, and\n * the delete procedure of the object's type attempts to acquire the mutex. If this function is\n * called while the mutex is owned, you can avoid referencing an object that is being destroyed.\n */\nPVOID PhReferenceObjectSafe(\n    _In_ PVOID Object\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n\n    objectHeader = PhObjectToObjectHeader(Object);\n\n    // Increase the reference count only if it positive already (atomically).\n    if (PhpInterlockedIncrementSafe(&objectHeader->RefCount))\n        return Object;\n    else\n        return NULL;\n}\n\n/**\n * Dereferences the specified object.\n * The object will be freed if its reference count reaches 0.\n *\n * \\param Object A pointer to the object to dereference.\n */\nVOID PhDereferenceObject(\n    _In_ _Post_invalid_ PVOID Object\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n    LONG newRefCount;\n\n    objectHeader = PhObjectToObjectHeader(Object);\n    // Decrement the reference count.\n    newRefCount = _InterlockedDecrement(&objectHeader->RefCount);\n    ASSUME_ASSERT(newRefCount >= 0);\n\n    // Free the object if it has 0 references.\n    if (newRefCount == 0)\n    {\n        PhpFreeObject(objectHeader);\n    }\n}\n\n/**\n * Dereferences the specified object.\n * The object will be freed in a worker thread if its reference count reaches 0.\n *\n * \\param Object A pointer to the object to dereference.\n */\nVOID PhDereferenceObjectDeferDelete(\n    _In_ _Post_invalid_ PVOID Object\n    )\n{\n    PhDereferenceObjectEx(Object, 1, TRUE);\n}\n\n/**\n * Dereferences the specified object.\n * The object will be freed if its reference count reaches 0.\n *\n * \\param Object A pointer to the object to dereference.\n * \\param RefCount The number of references to remove.\n * \\param DeferDelete Whether to defer deletion of the object.\n */\n_May_raise_ VOID PhDereferenceObjectEx(\n    _In_ PVOID Object,\n    _In_ LONG RefCount,\n    _In_ BOOLEAN DeferDelete\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n    LONG oldRefCount;\n    LONG newRefCount;\n\n    assert(!(RefCount < 0));\n\n    objectHeader = PhObjectToObjectHeader(Object);\n\n    // Decrease the reference count.\n    oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, -RefCount);\n    newRefCount = oldRefCount - RefCount;\n\n    // Free the object if it has 0 references.\n    if (newRefCount == 0)\n    {\n        if (DeferDelete)\n        {\n            PhpDeferDeleteObject(objectHeader);\n        }\n        else\n        {\n            // Free the object.\n            PhpFreeObject(objectHeader);\n        }\n    }\n    else if (newRefCount < 0)\n    {\n        PhRaiseStatus(STATUS_INVALID_PARAMETER);\n    }\n}\n\n/**\n * Gets an object's reference count.\n *\n * \\param Object A pointer to an object.\n *\n * \\return The object's reference count.\n */\nULONG PhGetObjectRefCount(\n    _In_ PVOID Object\n    )\n{\n    return PhObjectToObjectHeader(Object)->RefCount;\n}\n\n/**\n * Gets an object's type.\n *\n * \\param Object A pointer to an object.\n *\n * \\return A pointer to a type object.\n */\nPPH_OBJECT_TYPE PhGetObjectType(\n    _In_ PVOID Object\n    )\n{\n    return PhObjectTypeTable[PhObjectToObjectHeader(Object)->TypeIndex];\n}\n\n/**\n * Creates an object type.\n *\n * \\param Name The name of the type.\n * \\param Flags A combination of flags affecting the behaviour of the object type.\n * \\param DeleteProcedure A callback function that is executed when an object of this type is about\n * to be freed (i.e. when its reference count is 0).\n *\n * \\return A pointer to the newly created object type.\n *\n * \\remarks Do not reference or dereference the object type once it is created.\n */\nPPH_OBJECT_TYPE PhCreateObjectType(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure\n    )\n{\n    return PhCreateObjectTypeEx(\n        Name,\n        Flags,\n        DeleteProcedure,\n        NULL\n        );\n}\n\n/**\n * Creates an object type.\n *\n * \\param Name The name of the type.\n * \\param Flags A combination of flags affecting the behavior of the object type.\n * \\param DeleteProcedure A callback function that is executed when an object of this type is about\n * to be freed (i.e. when its reference count is 0).\n * \\param Parameters A structure containing additional parameters for the object type.\n *\n * \\return A pointer to the newly created object type.\n *\n * \\remarks Do not reference or dereference the object type once it is created.\n */\nPPH_OBJECT_TYPE PhCreateObjectTypeEx(\n    _In_ PCWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure,\n    _In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters\n    )\n{\n    PPH_OBJECT_TYPE objectType;\n\n    // Check the flags.\n    if ((Flags & PH_OBJECT_TYPE_VALID_FLAGS) != Flags) /* Valid flag mask */\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_3);\n    if ((Flags & (PH_OBJECT_TYPE_USE_FREE_LIST | PH_OBJECT_TYPE_TRY_USE_FREE_LIST)) == (PH_OBJECT_TYPE_USE_FREE_LIST | PH_OBJECT_TYPE_TRY_USE_FREE_LIST))\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_3);\n    if ((Flags & (PH_OBJECT_TYPE_USE_FREE_LIST | PH_OBJECT_TYPE_TRY_USE_FREE_LIST)) && !Parameters)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_MIX);\n\n    // Create the type object.\n    objectType = PhCreateObject(sizeof(PH_OBJECT_TYPE), PhObjectTypeObject);\n\n    // Initialize the type object.\n    objectType->Flags = (USHORT)Flags;\n    objectType->TypeIndex = (USHORT)_InterlockedIncrement(&PhObjectTypeCount) - 1;\n    objectType->NumberOfObjects = 0;\n    objectType->DeleteProcedure = DeleteProcedure;\n    objectType->Name = Name;\n\n    assert(InterlockedCompareExchange(&PhObjectTypeCount, 0, 0) < PH_OBJECT_TYPE_TABLE_SIZE);\n\n    PhObjectTypeTable[objectType->TypeIndex] = objectType;\n\n    if (Parameters)\n    {\n        if (Flags & (PH_OBJECT_TYPE_USE_FREE_LIST | PH_OBJECT_TYPE_TRY_USE_FREE_LIST))\n        {\n            PhInitializeFreeList(\n                &objectType->FreeList,\n                PhAddObjectHeaderSize(Parameters->FreeListSize),\n                Parameters->FreeListCount\n                );\n        }\n    }\n\n    return objectType;\n}\n\n/**\n * Gets information about an object type.\n *\n * \\param ObjectType A pointer to an object type.\n * \\param Information A variable which receives information about the object type.\n */\nVOID PhGetObjectTypeInformation(\n    _In_ PPH_OBJECT_TYPE ObjectType,\n    _Out_ PPH_OBJECT_TYPE_INFORMATION Information\n    )\n{\n    Information->Name = ObjectType->Name;\n    Information->NumberOfObjects = ObjectType->NumberOfObjects;\n    Information->Flags = ObjectType->Flags;\n    Information->TypeIndex = ObjectType->TypeIndex;\n}\n\n/**\n * Allocates storage for an object.\n *\n * \\param ObjectType The type of the object.\n * \\param ObjectSize The size of the object, excluding the header.\n */\nPPH_OBJECT_HEADER PhpAllocateObject(\n    _In_ PPH_OBJECT_TYPE ObjectType,\n    _In_ SIZE_T ObjectSize\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n\n    if (ObjectType->Flags & PH_OBJECT_TYPE_USE_FREE_LIST)\n    {\n        assert(ObjectType->FreeList.Size == PhAddObjectHeaderSize(ObjectSize));\n\n        objectHeader = PhAllocateFromFreeList(&ObjectType->FreeList);\n        objectHeader->Flags = PH_OBJECT_FROM_TYPE_FREE_LIST;\n        REF_STAT_UP(RefObjectsAllocatedFromTypeFreeList);\n    }\n    else if (ObjectSize <= PH_OBJECT_SMALL_OBJECT_SIZE)\n    {\n        objectHeader = PhAllocateFromFreeList(&PhObjectSmallFreeList);\n        objectHeader->Flags = PH_OBJECT_FROM_SMALL_FREE_LIST;\n        REF_STAT_UP(RefObjectsAllocatedFromSmallFreeList);\n    }\n    else if (ObjectType->Flags & PH_OBJECT_TYPE_TRY_USE_FREE_LIST &&\n             PhAddObjectHeaderSize(ObjectSize) <= ObjectType->FreeList.Size)\n    {\n        objectHeader = PhAllocateFromFreeList(&ObjectType->FreeList);\n        objectHeader->Flags = PH_OBJECT_FROM_TYPE_FREE_LIST;\n        REF_STAT_UP(RefObjectsAllocatedFromTypeFreeList);\n    }\n    else\n    {\n        objectHeader = PhAllocate(PhAddObjectHeaderSize(ObjectSize));\n        objectHeader->Flags = 0;\n        REF_STAT_UP(RefObjectsAllocated);\n    }\n\n    return objectHeader;\n}\n\n/**\n * Calls the delete procedure for an object and frees its allocated storage.\n *\n * \\param ObjectHeader A pointer to the object header of an allocated object.\n */\nVOID PhpFreeObject(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    )\n{\n    PPH_OBJECT_TYPE objectType;\n\n    objectType = PhObjectTypeTable[ObjectHeader->TypeIndex];\n\n    // Object type statistics.\n    _InterlockedDecrement(&objectType->NumberOfObjects);\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgObjectListLock);\n    RemoveEntryList(&ObjectHeader->ObjectListEntry);\n    PhReleaseQueuedLockExclusive(&PhDbgObjectListLock);\n#endif\n\n    REF_STAT_UP(RefObjectsDestroyed);\n\n    // Call the delete procedure if we have one.\n    if (objectType->DeleteProcedure)\n    {\n        objectType->DeleteProcedure(PhObjectHeaderToObject(ObjectHeader), 0);\n    }\n\n    if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST)\n    {\n        PhFreeToFreeList(&objectType->FreeList, ObjectHeader);\n        REF_STAT_UP(RefObjectsFreedToTypeFreeList);\n    }\n    else if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST)\n    {\n        PhFreeToFreeList(&PhObjectSmallFreeList, ObjectHeader);\n        REF_STAT_UP(RefObjectsFreedToSmallFreeList);\n    }\n    else\n    {\n        PhFree(ObjectHeader);\n        REF_STAT_UP(RefObjectsFreed);\n    }\n}\n\n/**\n * Queues an object for deletion.\n *\n * \\param ObjectHeader A pointer to the object header of the object to delete.\n */\nVOID PhpDeferDeleteObject(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    )\n{\n    PSLIST_ENTRY oldFirstEntry;\n\n    // Save TypeIndex and Flags since they get overwritten when we push the object onto the defer\n    // delete list.\n\nPH_CLANG_DIAGNOSTIC_PUSH();\nPH_CLANG_DIAGNOSTIC_IGNORED(\"-Wsingle-bit-bitfield-constant-conversion\");\n    ObjectHeader->DeferDelete = 1;\nPH_CLANG_DIAGNOSTIC_POP();\n\n    MemoryBarrier();\n    ObjectHeader->SavedTypeIndex = ObjectHeader->TypeIndex;\n    ObjectHeader->SavedFlags = ObjectHeader->Flags;\n\n    oldFirstEntry = RtlFirstEntrySList(&PhObjectDeferDeleteListHead);\n    RtlInterlockedPushEntrySList(&PhObjectDeferDeleteListHead, &ObjectHeader->DeferDeleteListEntry);\n    REF_STAT_UP(RefObjectsDeleteDeferred);\n\n    // Was the to-free list empty before? If so, we need to queue a work item.\n    if (!oldFirstEntry)\n    {\n        PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpDeferDeleteObjectRoutine, NULL);\n    }\n}\n\n/**\n * Removes and frees objects from the to-free list.\n */\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpDeferDeleteObjectRoutine(\n    _In_ PVOID Parameter\n    )\n{\n    PSLIST_ENTRY listEntry;\n    PPH_OBJECT_HEADER objectHeader;\n\n    // Clear the list and obtain the first object to free.\n    listEntry = RtlInterlockedFlushSList(&PhObjectDeferDeleteListHead);\n\n    while (listEntry)\n    {\n        objectHeader = CONTAINING_RECORD(listEntry, PH_OBJECT_HEADER, DeferDeleteListEntry);\n        listEntry = listEntry->Next;\n\n        // Restore TypeIndex and Flags.\n        objectHeader->TypeIndex = (USHORT)objectHeader->SavedTypeIndex;\n        objectHeader->Flags = (UCHAR)objectHeader->SavedFlags;\n\n        PhpFreeObject(objectHeader);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Creates a reference-counted memory block.\n *\n * \\param Size The number of bytes to allocate.\n *\n * \\return A pointer to the memory block.\n */\nPVOID PhCreateAlloc(\n    _In_ SIZE_T Size\n    )\n{\n    return PhCreateObject(Size, PhAllocType);\n}\n\n/**\n * Gets the current auto-dereference pool for the current thread.\n */\nFORCEINLINE PPH_AUTO_POOL PhpGetCurrentAutoPool(\n    VOID\n    )\n{\n    return (PPH_AUTO_POOL)PhTlsGetValue(PhpAutoPoolTlsIndex);\n}\n\n/**\n * Sets the current auto-dereference pool for the current thread.\n */\n_May_raise_ FORCEINLINE VOID PhpSetCurrentAutoPool(\n    _In_ PPH_AUTO_POOL AutoPool\n    )\n{\n    if (!NT_SUCCESS(PhTlsSetValue(PhpAutoPoolTlsIndex, AutoPool)))\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n\n#ifdef DEBUG\n    {\n        PPHP_BASE_THREAD_DBG dbg;\n\n        dbg = (PPHP_BASE_THREAD_DBG)PhTlsGetValue(PhDbgThreadDbgTlsIndex);\n\n        if (dbg)\n        {\n            dbg->CurrentAutoPool = AutoPool;\n        }\n    }\n#endif\n}\n\n/**\n * Initializes an auto-dereference pool and sets it as the current pool for the current thread. You\n * must call PhDeleteAutoPool() before storage for the auto-dereference pool is freed.\n *\n * \\remarks Always store auto-dereference pools in local variables, and do not share the pool with\n * any other functions.\n */\nVOID PhInitializeAutoPool(\n    _Out_ PPH_AUTO_POOL AutoPool\n    )\n{\n    AutoPool->StaticCount = 0;\n    AutoPool->DynamicCount = 0;\n    AutoPool->DynamicAllocated = 0;\n    AutoPool->DynamicObjects = NULL;\n\n    // Add the pool to the stack.\n    AutoPool->NextPool = PhpGetCurrentAutoPool();\n    PhpSetCurrentAutoPool(AutoPool);\n\n    REF_STAT_UP(RefAutoPoolsCreated);\n}\n\n/**\n * Deletes an auto-dereference pool. The function will dereference any objects currently in the\n * pool. If a pool other than the current pool is passed to the function, an exception is raised.\n *\n * \\param AutoPool The auto-dereference pool to delete.\n */\n_May_raise_ VOID PhDeleteAutoPool(\n    _In_ _Post_invalid_ PPH_AUTO_POOL AutoPool\n    )\n{\n    PhDrainAutoPool(AutoPool);\n\n    if (PhpGetCurrentAutoPool() != AutoPool)\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n\n    // Remove the pool from the stack.\n    PhpSetCurrentAutoPool(AutoPool->NextPool);\n\n    // Free the dynamic array if it hasn't been freed yet.\n    if (AutoPool->DynamicObjects)\n        PhFree(AutoPool->DynamicObjects);\n\n    REF_STAT_UP(RefAutoPoolsDestroyed);\n}\n\n/**\n * Dereferences and removes all objects in an auto-release pool.\n *\n * \\param AutoPool The auto-release pool to drain.\n */\nVOID PhDrainAutoPool(\n    _In_ PPH_AUTO_POOL AutoPool\n    )\n{\n    PhDereferenceObjects(AutoPool->StaticObjects, AutoPool->StaticCount);\n    AutoPool->StaticCount = 0;\n\n    if (AutoPool->DynamicObjects)\n    {\n        PhDereferenceObjects(AutoPool->DynamicObjects, AutoPool->DynamicCount);\n        AutoPool->DynamicCount = 0;\n\n        if (AutoPool->DynamicAllocated > PH_AUTO_POOL_DYNAMIC_BIG_SIZE)\n        {\n            AutoPool->DynamicAllocated = 0;\n            PhFree(AutoPool->DynamicObjects);\n            AutoPool->DynamicObjects = NULL;\n        }\n    }\n}\n\n/**\n * Adds an object to the current auto-dereference pool for the current thread. If the current thread\n * does not have an auto-dereference pool, the function raises an exception.\n *\n * \\param Object A pointer to an object. The object will be dereferenced when the current\n * auto-dereference pool is drained or freed.\n */\n_May_raise_ PVOID PhAutoDereferenceObject(\n    _In_opt_ PVOID Object\n    )\n{\n    PPH_AUTO_POOL autoPool = PhpGetCurrentAutoPool();\n\n#ifdef DEBUG\n    // If we don't have an auto-dereference pool, we don't want to leak the object (unlike what\n    // Apple does with NSAutoreleasePool).\n    if (!autoPool)\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n#endif\n\n    if (!Object)\n        return NULL;\n\n    // See if we can use the static array.\n    if (autoPool->StaticCount < PH_AUTO_POOL_STATIC_SIZE)\n    {\n        autoPool->StaticObjects[autoPool->StaticCount++] = Object;\n        return Object;\n    }\n\n    // Use the dynamic array.\n\n    // Allocate the array if we haven't already.\n    if (!autoPool->DynamicObjects)\n    {\n        autoPool->DynamicAllocated = 64;\n        autoPool->DynamicObjects = PhAllocate(\n            sizeof(PVOID) * autoPool->DynamicAllocated\n            );\n        REF_STAT_UP(RefAutoPoolsDynamicAllocated);\n    }\n\n    // See if we need to resize the array.\n    if (autoPool->DynamicCount == autoPool->DynamicAllocated)\n    {\n        autoPool->DynamicAllocated *= 2;\n        autoPool->DynamicObjects = PhReAllocate(\n            autoPool->DynamicObjects,\n            sizeof(PVOID) * autoPool->DynamicAllocated\n            );\n        REF_STAT_UP(RefAutoPoolsDynamicResized);\n    }\n\n    autoPool->DynamicObjects[autoPool->DynamicCount++] = Object;\n\n    return Object;\n}\n"
  },
  {
    "path": "phlib/searchbox.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2012-2023\n *     jxy-s   2023-2024\n *\n */\n\n#include <ph.h>\n#include <searchbox.h>\n#include <guisup.h>\n#include <settings.h>\n#include <vssym32.h>\n#include <emenu.h>\n#include <thirdparty.h>\n\ntypedef struct _PH_SEARCHCONTROL_BUTTON\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Hot : 1;\n            ULONG Pushed : 1;\n            ULONG Active : 1;\n            ULONG Error : 1;\n            ULONG Spare : 28;\n        };\n    };\n\n    ULONG Index;\n    ULONG ImageIndex;\n    ULONG ActiveImageIndex;\n    HWND TooltipHandle;\n} PH_SEARCHCONTROL_BUTTON, *PPH_SEARCHCONTROL_BUTTON;\n\n#define PH_SC_BUTTON_COUNT 3\n\ntypedef struct _PH_SEARCHCONTROL_CONTEXT\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Hot : 1;\n            ULONG HotTrack : 1;\n            ULONG WindowFocus : 1;\n            ULONG UseSearchPointer : 1;\n            ULONG Spare : 28;\n        };\n    };\n\n    HWND ParentWindowHandle;\n    HWND PreviousFocusWindowHandle;\n    LONG WindowDpi;\n\n    PCWSTR RegexSetting;\n    PCWSTR CaseSetting;\n\n    PVOID ImageBaseAddress;\n    PCWSTR SearchButtonResource;\n    PCWSTR SearchButtonActiveResource;\n    PCWSTR RegexButtonResource;\n    PCWSTR CaseButtonResource;\n\n    PH_SEARCHCONTROL_BUTTON SearchButton;\n    PH_SEARCHCONTROL_BUTTON RegexButton;\n    PH_SEARCHCONTROL_BUTTON CaseButton;\n\n    LONG ButtonWidth;\n    LONG BorderSize;\n    LONG ImageWidth;\n    LONG ImageHeight;\n    WNDPROC DefaultWindowProc;\n    HFONT WindowFont;\n    HIMAGELIST ImageListHandle;\n    PPH_STRING CueBannerText;\n\n    HDC BufferedDc;\n    HBITMAP BufferedOldBitmap;\n    HBITMAP BufferedBitmap;\n    RECT BufferedContextRect;\n\n    HBRUSH FrameBrush;\n    HBRUSH WindowBrush;\n\n    ULONG SearchDelayMs;\n\n    PPH_SEARCHCONTROL_CALLBACK Callback;\n    PVOID CallbackContext;\n\n    PH_STRINGREF SearchboxText;\n    WCHAR SearchboxTextBuffer[0x100];\n\n    ULONG64 SearchPointer;\n    LONG SearchboxRegexError;\n    PCRE2_SIZE SearchboxRegexErrorOffset;\n    pcre2_code* SearchboxRegexCode;\n    pcre2_match_data* SearchboxRegexMatchData;\n} PH_SEARCHCONTROL_CONTEXT, *PPH_SEARCHCONTROL_CONTEXT;\n\nVOID PhpSearchControlCreateBufferedContext(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ HDC Hdc,\n    _In_ PRECT BufferRect\n    )\n{\n    Context->BufferedDc = CreateCompatibleDC(Hdc);\n\n    if (!Context->BufferedDc)\n        return;\n\n    Context->BufferedContextRect = *BufferRect;\n    Context->BufferedBitmap = CreateCompatibleBitmap(\n        Hdc,\n        Context->BufferedContextRect.right,\n        Context->BufferedContextRect.bottom\n        );\n\n    Context->BufferedOldBitmap = SelectBitmap(Context->BufferedDc, Context->BufferedBitmap);\n}\n\nVOID PhpSearchControlDestroyBufferedContext(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context\n    )\n{\n    if (Context->BufferedDc && Context->BufferedOldBitmap)\n    {\n        SelectBitmap(Context->BufferedDc, Context->BufferedOldBitmap);\n    }\n\n    if (Context->BufferedBitmap)\n    {\n        DeleteBitmap(Context->BufferedBitmap);\n        Context->BufferedBitmap = NULL;\n    }\n\n    if (Context->BufferedDc)\n    {\n        DeleteDC(Context->BufferedDc);\n        Context->BufferedDc = NULL;\n    }\n}\n\nVOID PhpSearchControlInitializeFont(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ HWND WindowHandle\n    )\n{\n    if (Context->WindowFont)\n    {\n        DeleteFont(Context->WindowFont);\n        Context->WindowFont = NULL;\n    }\n\n    Context->WindowFont = PhCreateCommonFont(10, FW_MEDIUM, WindowHandle, Context->WindowDpi);\n}\n\nVOID PhpSearchControlInitializeTheme(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ HWND WindowHandle\n    )\n{\n    LONG borderSize;\n\n    borderSize = PhGetSystemMetrics(SM_CXBORDER, Context->WindowDpi);\n\n    Context->CaseButton.Index = 0;\n    Context->RegexButton.Index = 1;\n    Context->SearchButton.Index = 2;\n\n    Context->ButtonWidth = PhGetDpi(20, Context->WindowDpi);\n    Context->BorderSize = borderSize;\n    Context->FrameBrush = GetSysColorBrush(COLOR_WINDOWFRAME);\n    Context->WindowBrush = GetSysColorBrush(COLOR_WINDOW);\n\n    if (PhIsThemeActive())\n    {\n        HTHEME themeHandle;\n\n        if (themeHandle = PhOpenThemeData(WindowHandle, VSCLASS_EDIT, Context->WindowDpi))\n        {\n            if (PhGetThemeInt(themeHandle, 0, 0, TMT_BORDERSIZE, &borderSize))\n            {\n                Context->BorderSize = borderSize;\n            }\n\n            PhCloseThemeData(themeHandle);\n        }\n    }\n}\n\nVOID PhpSearchControlInitializeImages(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ HWND WindowHandle\n    )\n{\n    HBITMAP bitmap;\n\n    Context->ImageWidth = PhGetSystemMetrics(SM_CXSMICON, Context->WindowDpi) + PhGetDpi(4, Context->WindowDpi);\n    Context->ImageHeight = PhGetSystemMetrics(SM_CYSMICON, Context->WindowDpi) + PhGetDpi(4, Context->WindowDpi);\n\n    if (Context->ImageListHandle)\n    {\n        PhImageListSetIconSize(\n            Context->ImageListHandle,\n            Context->ImageWidth,\n            Context->ImageHeight\n            );\n    }\n    else\n    {\n        Context->ImageListHandle = PhImageListCreate(\n            Context->ImageWidth,\n            Context->ImageHeight,\n            ILC_MASK | ILC_COLOR32,\n            2, 0\n            );\n    }\n\n    PhImageListSetImageCount(Context->ImageListHandle, 4);\n\n    // Search Button\n    Context->SearchButton.ImageIndex = ULONG_MAX;\n    Context->SearchButton.ActiveImageIndex = ULONG_MAX;\n\n    bitmap = PhLoadImageFormatFromResource(Context->ImageBaseAddress, Context->SearchButtonResource, L\"PNG\", PH_IMAGE_FORMAT_TYPE_PNG, Context->ImageWidth, Context->ImageHeight);\n    if (bitmap)\n    {\n        Context->SearchButton.ImageIndex = 0;\n        PhImageListReplace(Context->ImageListHandle, 0, bitmap, NULL);\n        DeleteBitmap(bitmap);\n    }\n\n    bitmap = PhLoadImageFormatFromResource(Context->ImageBaseAddress, Context->SearchButtonActiveResource, L\"PNG\", PH_IMAGE_FORMAT_TYPE_PNG, Context->ImageWidth, Context->ImageHeight);\n    if (bitmap)\n    {\n        Context->SearchButton.ActiveImageIndex = 1;\n        PhImageListReplace(Context->ImageListHandle, 1, bitmap, NULL);\n        DeleteBitmap(bitmap);\n    }\n\n    // Regex Button\n    Context->RegexButton.ImageIndex = ULONG_MAX;\n    Context->RegexButton.ActiveImageIndex = ULONG_MAX;\n\n    bitmap = PhLoadImageFormatFromResource(Context->ImageBaseAddress, Context->RegexButtonResource, L\"PNG\", PH_IMAGE_FORMAT_TYPE_PNG, Context->ImageWidth, Context->ImageHeight);\n    if (bitmap)\n    {\n        Context->RegexButton.ImageIndex = 2;\n        PhImageListReplace(Context->ImageListHandle, 2, bitmap, NULL);\n        DeleteBitmap(bitmap);\n    }\n\n    // Case-Sensitivity Button\n    Context->CaseButton.ImageIndex = ULONG_MAX;\n    Context->CaseButton.ActiveImageIndex = ULONG_MAX;\n\n    bitmap = PhLoadImageFormatFromResource(Context->ImageBaseAddress, Context->CaseButtonResource, L\"PNG\", PH_IMAGE_FORMAT_TYPE_PNG, Context->ImageWidth, Context->ImageHeight);\n    if (bitmap)\n    {\n        Context->CaseButton.ImageIndex = 3;\n        PhImageListReplace(Context->ImageListHandle, 3, bitmap, NULL);\n        DeleteBitmap(bitmap);\n    }\n}\n\nVOID PhpSearchControlButtonRect(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ PPH_SEARCHCONTROL_BUTTON Button,\n    _In_ PRECT WindowRect,\n    _Out_ PRECT ButtonRect\n    )\n{\n    memcpy(ButtonRect, WindowRect, sizeof(RECT));\n\n    ButtonRect->left = ((ButtonRect->right - Context->ButtonWidth) - Context->BorderSize - 1);\n    ButtonRect->top += Context->BorderSize;\n    ButtonRect->right -= Context->BorderSize;\n    ButtonRect->bottom -= Context->BorderSize;\n\n    // Shift the button rect to the left based on the button index.\n    ButtonRect->left -= ((Context->ButtonWidth + Context->BorderSize - 1) * (PH_SC_BUTTON_COUNT - 1 - Button->Index));\n    ButtonRect->right -= ((Context->ButtonWidth + Context->BorderSize - 1) * (PH_SC_BUTTON_COUNT - 1 - Button->Index));\n}\n\nVOID PhpSearchControlCreateTooltip(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ PPH_SEARCHCONTROL_BUTTON Button,\n    _In_ HWND ParentWindow,\n    _In_ PRECT TooltipRect,\n    _In_ PWSTR TooltipText\n    )\n{\n    TOOLINFO toolInfo;\n\n    if (Button->TooltipHandle)\n        return;\n\n    Button->TooltipHandle = PhCreateWindowEx(\n        TOOLTIPS_CLASS,\n        NULL,\n        WS_POPUP | TTS_ALWAYSTIP | TTS_NOPREFIX | TTS_NOANIMATE | TTS_NOFADE,\n        WS_EX_TOPMOST | WS_EX_TRANSPARENT,\n        CW_USEDEFAULT,\n        CW_USEDEFAULT,\n        CW_USEDEFAULT,\n        CW_USEDEFAULT,\n        ParentWindow,\n        NULL,\n        NULL,\n        NULL\n        );\n\n    SetWindowPos(\n        Button->TooltipHandle,\n        HWND_TOPMOST,\n        0, 0, 0, 0,\n        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE\n        );\n\n    MapWindowRect(HWND_DESKTOP, ParentWindow, TooltipRect);\n    PhInflateRect(TooltipRect, -1, -1);\n\n    memset(&toolInfo, 0, sizeof(TOOLINFO));\n    toolInfo.cbSize = sizeof(TOOLINFO);\n    toolInfo.uFlags = TTF_TRANSPARENT | TTF_SUBCLASS;\n    toolInfo.hwnd = ParentWindow;\n    toolInfo.lpszText = TooltipText;\n    toolInfo.rect = *TooltipRect;\n    SendMessage(Button->TooltipHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);\n    SendMessage(Button->TooltipHandle, TTM_SETDELAYTIME, TTDT_INITIAL, 0);\n    SendMessage(Button->TooltipHandle, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);\n    SendMessage(Button->TooltipHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT);\n    SendMessage(Button->TooltipHandle, TTM_POPUP, 0, 0);\n}\n\nVOID PhpSearchControlThemeChanged(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ HWND WindowHandle\n    )\n{\n    PhpSearchControlInitializeFont(Context, WindowHandle);\n    PhpSearchControlInitializeTheme(Context, WindowHandle);\n    PhpSearchControlInitializeImages(Context, WindowHandle);\n\n    // Reset the client area margins.\n    CallWindowProc(Context->DefaultWindowProc, WindowHandle, EM_SETMARGINS, EC_LEFTMARGIN, MAKELPARAM(0, 0));\n\n    // Refresh the non-client area.\n    SetWindowPos(WindowHandle, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);\n\n    // Force the edit control to update its non-client area.\n    RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n}\n\nVOID PhpSearchDrawWindow(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HDC Hdc,\n    _In_ PRECT WindowRect\n    )\n{\n    if (PhEnableThemeSupport)\n    {\n        SetDCBrushColor(Hdc, PhThemeWindowBackground2Color);\n        SelectBrush(Hdc, PhGetStockBrush(DC_BRUSH));\n        PatBlt(Hdc, WindowRect->left, WindowRect->top, 1, WindowRect->bottom - WindowRect->top, PATCOPY);\n        PatBlt(Hdc, WindowRect->right - 1, WindowRect->top, 1, WindowRect->bottom - WindowRect->top, PATCOPY);\n        PatBlt(Hdc, WindowRect->left, WindowRect->top, WindowRect->right - WindowRect->left, 1, PATCOPY);\n        PatBlt(Hdc, WindowRect->left, WindowRect->bottom - 1, WindowRect->right - WindowRect->left, 1, PATCOPY);\n\n        SetDCBrushColor(Hdc, RGB(60, 60, 60));\n        SelectBrush(Hdc, PhGetStockBrush(DC_BRUSH));\n        PatBlt(Hdc, WindowRect->left + 1, WindowRect->top + 1, 1, WindowRect->bottom - WindowRect->top - 2, PATCOPY);\n        PatBlt(Hdc, WindowRect->right - 2, WindowRect->top + 1, 1, WindowRect->bottom - WindowRect->top - 2, PATCOPY);\n        PatBlt(Hdc, WindowRect->left + 1, WindowRect->top + 1, WindowRect->right - WindowRect->left - 2, 1, PATCOPY);\n        PatBlt(Hdc, WindowRect->left + 1, WindowRect->bottom - 2, WindowRect->right - WindowRect->left - 2, 1, PATCOPY);\n    }\n}\n\nVOID PhpSearchDrawButton(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ PPH_SEARCHCONTROL_BUTTON Button,\n    _In_ HWND WindowHandle,\n    _In_ HDC Hdc,\n    _In_ PRECT WindowRect\n    )\n{\n    RECT buttonRect;\n\n    PhpSearchControlButtonRect(Context, Button, WindowRect, &buttonRect);\n\n    if (Button->Pushed)\n    {\n        if (PhEnableThemeSupport)\n        {\n            SetDCBrushColor(Hdc, RGB(99, 99, 99));\n            FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n        }\n        else\n        {\n            SetDCBrushColor(Hdc, RGB(153, 209, 255));\n            FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n        }\n    }\n    else if (Button->Hot)\n    {\n        if (Button->Active && Button->ActiveImageIndex == ULONG_MAX)\n        {\n            if (PhEnableThemeSupport)\n            {\n                SetDCBrushColor(Hdc, RGB(54, 54, 54));\n                FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n            }\n            else\n            {\n                SetDCBrushColor(Hdc, RGB(133, 199, 255));\n                FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n            }\n        }\n        else\n        {\n            if (PhEnableThemeSupport)\n            {\n                SetDCBrushColor(Hdc, RGB(78, 78, 78));\n                FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n            }\n            else\n            {\n                SetDCBrushColor(Hdc, RGB(205, 232, 255));\n                FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n            }\n        }\n    }\n    else if (Button->Error)\n    {\n        if (PhEnableThemeSupport)\n        {\n            SetDCBrushColor(Hdc, RGB(100, 28, 30));\n            FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n        }\n        else\n        {\n            SetDCBrushColor(Hdc, RGB(255, 155, 155));\n            FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n        }\n    }\n    else if (Button->Active && Button->ActiveImageIndex == ULONG_MAX)\n    {\n        if (PhEnableThemeSupport)\n        {\n            SetDCBrushColor(Hdc, RGB(44, 44, 44));\n            FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n        }\n        else\n        {\n            SetDCBrushColor(Hdc, RGB(123, 189, 255));\n            FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n        }\n    }\n    else\n    {\n        if (PhEnableThemeSupport)\n        {\n            SetDCBrushColor(Hdc, RGB(60, 60, 60));\n            FillRect(Hdc, &buttonRect, PhGetStockBrush(DC_BRUSH));\n        }\n        else\n        {\n            FillRect(Hdc, &buttonRect, Context->WindowBrush);\n        }\n    }\n\n    if (Button->Active && Button->ActiveImageIndex != ULONG_MAX)\n    {\n        PhImageListDrawIcon(\n            Context->ImageListHandle,\n            Button->ActiveImageIndex,\n            Hdc,\n            buttonRect.left + 1 /*offset*/ + ((buttonRect.right - buttonRect.left) - Context->ImageWidth) / 2,\n            buttonRect.top + ((buttonRect.bottom - buttonRect.top) - Context->ImageHeight) / 2,\n            ILD_TRANSPARENT,\n            FALSE\n            );\n    }\n    else\n    {\n        PhImageListDrawIcon(\n            Context->ImageListHandle,\n            Button->ImageIndex,\n            Hdc,\n            buttonRect.left + 1 /*offset*/ + ((buttonRect.right - buttonRect.left) - Context->ImageWidth) / 2,\n            buttonRect.top +  ((buttonRect.bottom - buttonRect.top) - Context->ImageHeight) / 2,\n            ILD_TRANSPARENT,\n            FALSE\n            );\n    }\n}\n\nVOID PhpSearchUpdateRegex(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context\n    )\n{\n    ULONG flags;\n\n    Context->RegexButton.Error = FALSE;\n    Context->SearchboxRegexError = 0;\n    Context->SearchboxRegexErrorOffset = 0;\n\n    if (Context->SearchboxRegexCode)\n    {\n        pcre2_code_free(Context->SearchboxRegexCode);\n        Context->SearchboxRegexCode = NULL;\n    }\n\n    if (Context->SearchboxRegexMatchData)\n    {\n        pcre2_match_data_free(Context->SearchboxRegexMatchData);\n        Context->SearchboxRegexMatchData = NULL;\n    }\n\n    if (!Context->RegexButton.Active || Context->SearchboxText.Length == 0)\n        return;\n\n    if (Context->CaseButton.Active)\n        flags = PCRE2_DOTALL;\n    else\n        flags = PCRE2_CASELESS | PCRE2_DOTALL;\n\n    Context->SearchboxRegexCode = pcre2_compile(\n        Context->SearchboxText.Buffer,\n        Context->SearchboxText.Length / sizeof(WCHAR),\n        flags,\n        &Context->SearchboxRegexError,\n        &Context->SearchboxRegexErrorOffset,\n        NULL\n        );\n    if (!Context->SearchboxRegexCode)\n    {\n        Context->RegexButton.Error = TRUE;\n        return;\n    }\n\n    Context->SearchboxRegexMatchData = pcre2_match_data_create_from_pattern(\n        Context->SearchboxRegexCode,\n        NULL\n        );\n}\n\nBOOLEAN PhGetSearchTextToBuffer(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_ PSIZE_T ReturnLength\n    )\n{\n    SIZE_T returnLength;\n\n    returnLength = CallWindowProc(\n        Context->DefaultWindowProc,\n        WindowHandle,\n        WM_GETTEXT,\n        BufferLength,\n        (LPARAM)Buffer\n        );\n\n    if (returnLength != 0)\n    {\n        *ReturnLength = returnLength;\n        return TRUE;\n    }\n\n    memset(Buffer, UNICODE_NULL, sizeof(UNICODE_NULL));\n    *ReturnLength = 0;\n    return TRUE;\n}\n\nBOOLEAN PhpSearchUpdateText(\n    _In_ HWND WindowHandle,\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context,\n    _In_ BOOLEAN Force\n    )\n{\n    ULONG_PTR matchHandle;\n    PH_STRINGREF newSearchboxText;\n    SIZE_T searchboxTextBufferLength;\n    WCHAR searchboxTextBuffer[0x100];\n\n    //if (PhGetWindowTextLength(WindowHandle) == 0)\n    //{\n    //    return FALSE;\n    //}\n\n    if (!PhGetSearchTextToBuffer(\n        WindowHandle,\n        Context,\n        searchboxTextBuffer,\n        RTL_NUMBER_OF(searchboxTextBuffer),\n        &searchboxTextBufferLength\n        ))\n    {\n        return FALSE;\n    }\n\n    newSearchboxText.Buffer = searchboxTextBuffer;\n    newSearchboxText.Length = searchboxTextBufferLength * sizeof(WCHAR);\n\n    Context->SearchButton.Active = (newSearchboxText.Length > 0);\n\n    if (!Force && PhEqualStringRef(&newSearchboxText, &Context->SearchboxText, FALSE))\n        return FALSE;\n\n    if (memcpy_s(Context->SearchboxTextBuffer, sizeof(Context->SearchboxTextBuffer), newSearchboxText.Buffer, newSearchboxText.Length))\n        return FALSE;\n    Context->SearchboxText.Buffer = Context->SearchboxTextBuffer;\n    Context->SearchboxText.Length = searchboxTextBufferLength * sizeof(WCHAR);\n\n    Context->UseSearchPointer = PhStringToUInt64(&newSearchboxText, 0, &Context->SearchPointer);\n\n    PhpSearchUpdateRegex(WindowHandle, Context);\n\n    if (!Context->Callback)\n        return TRUE;\n\n    matchHandle = (Context->SearchboxText.Length == 0 || (Context->RegexButton.Active && !Context->SearchboxRegexCode)) ? 0 : (ULONG_PTR)Context;\n\n    Context->Callback(matchHandle, Context->CallbackContext);\n\n    return TRUE;\n}\n\nvoid PhpSearchRestoreFocus(\n    _In_ PPH_SEARCHCONTROL_CONTEXT Context\n    )\n{\n    if (Context->PreviousFocusWindowHandle)\n    {\n        SetFocus(Context->PreviousFocusWindowHandle);\n        Context->PreviousFocusWindowHandle = NULL;\n    }\n}\n\nLRESULT CALLBACK PhpSearchWndSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_SEARCHCONTROL_CONTEXT context;\n    WNDPROC oldWndProc;\n\n    if (!(context = PhGetWindowContext(WindowHandle, SHRT_MAX)))\n        return 0;\n\n    oldWndProc = context->DefaultWindowProc;\n\n    switch (WindowMessage)\n    {\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, SHRT_MAX);\n            PhSetWindowProcedure(WindowHandle, oldWndProc);\n\n            if (context->WindowFont)\n            {\n                DeleteFont(context->WindowFont);\n                context->WindowFont = NULL;\n            }\n\n            if (context->ImageListHandle)\n            {\n                PhImageListDestroy(context->ImageListHandle);\n                context->ImageListHandle = NULL;\n            }\n\n            if (context->CueBannerText)\n            {\n                PhDereferenceObject(context->CueBannerText);\n                context->CueBannerText = NULL;\n            }\n\n            if (context->SearchboxRegexCode)\n            {\n                pcre2_code_free(context->SearchboxRegexCode);\n            }\n\n            if (context->SearchboxRegexMatchData)\n            {\n                pcre2_match_data_free(context->SearchboxRegexMatchData);\n            }\n\n            if (context->CaseButton.TooltipHandle)\n            {\n                DestroyWindow(context->CaseButton.TooltipHandle);\n                context->CaseButton.TooltipHandle = NULL;\n            }\n\n            if (context->RegexButton.TooltipHandle)\n            {\n                DestroyWindow(context->RegexButton.TooltipHandle);\n                context->RegexButton.TooltipHandle = NULL;\n            }\n\n            if (context->SearchButton.TooltipHandle)\n            {\n                DestroyWindow(context->SearchButton.TooltipHandle);\n                context->SearchButton.TooltipHandle = NULL;\n            }\n\n            PhpSearchControlDestroyBufferedContext(context);\n\n            PhFree(context);\n        }\n        break;\n    case WM_ERASEBKGND:\n        return TRUE;\n    case WM_NCCALCSIZE:\n        {\n            LPNCCALCSIZE_PARAMS ncCalcSize = (NCCALCSIZE_PARAMS*)lParam;\n\n            // Let Windows handle the non-client defaults.\n            CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n\n            // Deflate the client area to accommodate the custom button.\n            ncCalcSize->rgrc[0].right -= (context->ButtonWidth * PH_SC_BUTTON_COUNT);\n        }\n        return 0;\n    case WM_NCPAINT:\n        {\n            RECT windowRect;\n            HDC hdc;\n            ULONG flags;\n            HRGN updateRegion;\n\n            if (!PhGetWindowRect(WindowHandle, &windowRect))\n                break;\n\n            updateRegion = (HRGN)wParam;\n\n            if (updateRegion == HRGN_FULL)\n                updateRegion = NULL;\n\n            flags = DCX_WINDOW | DCX_CACHE | DCX_USESTYLE;\n\n            if (updateRegion)\n                flags |= DCX_INTERSECTRGN | DCX_NODELETERGN;\n\n            if (hdc = GetDCEx(WindowHandle, updateRegion, flags))\n            {\n                RECT windowRectStart;\n                RECT bufferRect;\n\n                // Adjust the coordinates (start from 0,0).\n                PhOffsetRect(&windowRect, -windowRect.left, -windowRect.top);\n                windowRectStart = windowRect;\n\n                // Exclude client area.\n                ExcludeClipRect(\n                    hdc,\n                    windowRect.left + (context->BorderSize + 1),\n                    windowRect.top + (context->BorderSize + 1),\n                    windowRect.right - (context->ButtonWidth * PH_SC_BUTTON_COUNT) - (context->BorderSize + 1),\n                    windowRect.bottom - (context->BorderSize + 1)\n                    );\n\n                bufferRect.left = 0;\n                bufferRect.top = 0;\n                bufferRect.right = windowRect.right - windowRect.left;\n                bufferRect.bottom = windowRect.bottom - windowRect.top;\n\n                if (context->BufferedDc && (\n                    context->BufferedContextRect.right < bufferRect.right ||\n                    context->BufferedContextRect.bottom < bufferRect.bottom))\n                {\n                    PhpSearchControlDestroyBufferedContext(context);\n                }\n\n                if (!context->BufferedDc)\n                {\n                    PhpSearchControlCreateBufferedContext(context, hdc, &bufferRect);\n                }\n\n                if (!context->BufferedDc)\n                {\n                    ReleaseDC(WindowHandle, hdc);\n                    break;\n                }\n\n                if (GetFocus() == WindowHandle)\n                {\n                    FrameRect(context->BufferedDc, &windowRect, GetSysColorBrush(COLOR_HOTLIGHT));\n                    PhInflateRect(&windowRect, -1, -1);\n                    FrameRect(context->BufferedDc, &windowRect, context->WindowBrush);\n                }\n                else if (context->Hot)\n                {\n                    if (PhEnableThemeSupport)\n                    {\n                        SetDCBrushColor(context->BufferedDc, PhThemeWindowHighlight2Color);\n                        FrameRect(context->BufferedDc, &windowRect, PhGetStockBrush(DC_BRUSH));\n                    }\n                    else\n                    {\n                        SetDCBrushColor(context->BufferedDc, RGB(43, 43, 43));\n                        FrameRect(context->BufferedDc, &windowRect, PhGetStockBrush(DC_BRUSH));\n                    }\n\n                    PhInflateRect(&windowRect, -1, -1);\n                    FrameRect(context->BufferedDc, &windowRect, context->WindowBrush);\n                }\n                else\n                {\n                    FrameRect(context->BufferedDc, &windowRect, context->FrameBrush);\n                    PhInflateRect(&windowRect, -1, -1);\n                    FrameRect(context->BufferedDc, &windowRect, context->WindowBrush);\n                }\n\n                PhpSearchDrawWindow(context, WindowHandle, context->BufferedDc, &windowRectStart);\n                PhpSearchDrawButton(context, &context->SearchButton, WindowHandle, context->BufferedDc, &windowRectStart);\n                PhpSearchDrawButton(context, &context->RegexButton, WindowHandle, context->BufferedDc, &windowRectStart);\n                PhpSearchDrawButton(context, &context->CaseButton, WindowHandle, context->BufferedDc, &windowRectStart);\n\n                BitBlt(\n                    hdc,\n                    bufferRect.left,\n                    bufferRect.top,\n                    bufferRect.right,\n                    bufferRect.bottom,\n                    context->BufferedDc,\n                    0,\n                    0,\n                    SRCCOPY\n                    );\n\n                ReleaseDC(WindowHandle, hdc);\n            }\n        }\n        return 0;\n    case WM_NCHITTEST:\n        {\n            POINT windowPoint;\n            RECT windowRect;\n            RECT buttonRect;\n\n            // Get the screen coordinates of the mouse.\n            //if (!PhGetCursorPos(&windowPoint))\n            //    break;\n            windowPoint.x = GET_X_LPARAM(lParam);\n            windowPoint.y = GET_Y_LPARAM(lParam);\n\n            // Get the screen coordinates of the window.\n            if (!PhGetWindowRect(WindowHandle, &windowRect))\n                break;\n\n            // Get the position of the inserted buttons.\n            PhpSearchControlButtonRect(context, &context->SearchButton, &windowRect, &buttonRect);\n            if (PhPtInRect(&buttonRect, &windowPoint))\n                return HTBORDER;\n\n            PhpSearchControlButtonRect(context, &context->RegexButton, &windowRect, &buttonRect);\n            if (PhPtInRect(&buttonRect, &windowPoint))\n                return HTBORDER;\n\n            PhpSearchControlButtonRect(context, &context->CaseButton, &windowRect, &buttonRect);\n            if (PhPtInRect(&buttonRect, &windowPoint))\n                return HTBORDER;\n        }\n        break;\n    case WM_NCLBUTTONDOWN:\n        {\n            UINT codeHitTest = (UINT)wParam;\n            POINT windowPoint;\n            RECT windowRect;\n            RECT buttonRect;\n\n            // Get the screen coordinates of the mouse.\n            //if (!PhGetMessagePos(&windowPoint))\n            //    break;\n            windowPoint.x = GET_X_LPARAM(lParam);\n            windowPoint.y = GET_Y_LPARAM(lParam);\n\n            // Get the screen coordinates of the window.\n            if (!PhGetWindowRect(WindowHandle, &windowRect))\n                break;\n\n            PhpSearchControlButtonRect(context, &context->SearchButton, &windowRect, &buttonRect);\n            context->SearchButton.Pushed = PhPtInRect(&buttonRect, &windowPoint);\n\n            PhpSearchControlButtonRect(context, &context->RegexButton, &windowRect, &buttonRect);\n            context->RegexButton.Pushed = PhPtInRect(&buttonRect, &windowPoint);\n\n            PhpSearchControlButtonRect(context, &context->CaseButton, &windowRect, &buttonRect);\n            context->CaseButton.Pushed = PhPtInRect(&buttonRect, &windowPoint);\n\n            SetCapture(WindowHandle);\n            RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n        }\n        break;\n    case WM_LBUTTONUP:\n        {\n            POINT windowPoint;\n            RECT windowRect;\n            RECT buttonRect;\n\n            // Get the screen coordinates of the mouse.\n            if (!PhGetMessagePos(&windowPoint))\n                break;\n\n            // Get the screen coordinates of the window.\n            if (!PhGetWindowRect(WindowHandle, &windowRect))\n                break;\n\n            PhpSearchControlButtonRect(context, &context->SearchButton, &windowRect, &buttonRect);\n            if (PhPtInRect(&buttonRect, &windowPoint))\n            {\n                SetFocus(WindowHandle);\n                PhSetWindowText(WindowHandle, L\"\");\n                PhpSearchUpdateText(WindowHandle, context, FALSE);\n            }\n\n            PhpSearchControlButtonRect(context, &context->RegexButton, &windowRect, &buttonRect);\n            if (PhPtInRect(&buttonRect, &windowPoint))\n            {\n                context->RegexButton.Active = !context->RegexButton.Active;\n                PhSetIntegerSetting(context->RegexSetting, context->RegexButton.Active);\n                PhpSearchUpdateText(WindowHandle, context, TRUE);\n            }\n\n            PhpSearchControlButtonRect(context, &context->CaseButton, &windowRect, &buttonRect);\n            if (PhPtInRect(&buttonRect, &windowPoint))\n            {\n                context->CaseButton.Active = !context->CaseButton.Active;\n                PhSetIntegerSetting(context->CaseSetting, context->CaseButton.Active);\n                PhpSearchUpdateText(WindowHandle, context, FALSE);\n            }\n\n            if (GetCapture() == WindowHandle)\n            {\n                context->SearchButton.Pushed = FALSE;\n                context->RegexButton.Pushed = FALSE;\n                context->CaseButton.Pushed = FALSE;\n                ReleaseCapture();\n            }\n\n            RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            POINT windowPoint;\n            PPH_EMENU menu;\n            PPH_EMENU item;\n            ULONG selStart;\n            ULONG selEnd;\n\n            windowPoint.x = GET_X_LPARAM(lParam);\n            windowPoint.y = GET_Y_LPARAM(lParam);\n\n            CallWindowProc(oldWndProc, WindowHandle, EM_GETSEL, (WPARAM)&selStart, (LPARAM)&selEnd);\n\n            menu = PhCreateEMenu();\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L\"Undo\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 2, L\"Cut\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 3, L\"Copy\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 4, L\"Paste\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 5, L\"Delete\", NULL, NULL), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX);\n            PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 6, L\"Select All\", NULL, NULL), ULONG_MAX);\n\n            if (selStart == selEnd)\n            {\n                PhEnableEMenuItem(menu, 2, FALSE);\n                PhEnableEMenuItem(menu, 3, FALSE);\n                PhEnableEMenuItem(menu, 6, FALSE);\n            }\n\n            item = PhShowEMenu(\n                menu,\n                WindowHandle,\n                PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,\n                PH_ALIGN_LEFT | PH_ALIGN_TOP,\n                windowPoint.x,\n                windowPoint.y\n                );\n\n            if (item)\n            {\n                PPH_STRING text = PhGetWindowText(WindowHandle);\n\n                switch (item->Id)\n                {\n                    case 1:\n                        {\n                            CallWindowProc(oldWndProc, WindowHandle, EM_UNDO, 0, 0);\n                            PhpSearchUpdateText(WindowHandle, context, FALSE);\n                        }\n                        break;\n                    case 2:\n                        {\n                            PPH_STRING selectedText = PH_AUTO(PhSubstring(text, selStart, selEnd - selStart));\n                            PPH_STRING startText = PH_AUTO(PhSubstring(text, 0, selStart));\n                            PPH_STRING endText = PH_AUTO(PhSubstring(text, selEnd, text->Length / sizeof(WCHAR)));\n                            PPH_STRING newText = PH_AUTO(PhConcatStringRef2(&startText->sr, &endText->sr));\n                            PhSetClipboardString(WindowHandle, &selectedText->sr);\n                            PhSetWindowText(WindowHandle, newText->Buffer);\n                            PhpSearchUpdateText(WindowHandle, context, FALSE);\n                        }\n                        break;\n                    case 3:\n                        {\n                            PPH_STRING selectedText = PH_AUTO(PhSubstring(text, selStart, selEnd - selStart));\n                            PhSetClipboardString(WindowHandle, &selectedText->sr);\n                        }\n                        break;\n                    case 4:\n                        {\n                            PPH_STRING clipText = PH_AUTO(PhGetClipboardString(WindowHandle));\n                            PPH_STRING startText = PH_AUTO(PhSubstring(text, 0, selStart));\n                            PPH_STRING endText = PH_AUTO(PhSubstring(text, selEnd, text->Length / sizeof(WCHAR)));\n                            PPH_STRING newText = PH_AUTO(PhConcatStringRef3(&startText->sr, &clipText->sr, &endText->sr));\n                            PhSetWindowText(WindowHandle, newText->Buffer);\n                            PhpSearchUpdateText(WindowHandle, context, FALSE);\n                        }\n                        break;\n                    case 5:\n                        {\n                            PPH_STRING startText = PH_AUTO(PhSubstring(text, 0, selStart));\n                            PPH_STRING endText = PH_AUTO(PhSubstring(text, selEnd, text->Length / sizeof(WCHAR)));\n                            PPH_STRING newText = PH_AUTO(PhConcatStringRef2(&startText->sr, &endText->sr));\n                            PhSetWindowText(WindowHandle, newText->Buffer);\n                            PhpSearchUpdateText(WindowHandle, context, FALSE);\n                        }\n                        break;\n                    case 6:\n                        {\n                            CallWindowProc(oldWndProc, WindowHandle, EM_SETSEL, 0, -1);\n                        }\n                        break;\n                }\n\n                PhDereferenceObject(text);\n            }\n\n            PhDestroyEMenu(menu);\n        }\n        return FALSE;\n    case WM_CUT:\n    case WM_CLEAR:\n    case WM_PASTE:\n    case WM_UNDO:\n    case WM_KEYUP:\n    case WM_SETTEXT:\n        {\n            LRESULT result = CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n\n            PhpSearchUpdateText(WindowHandle, context, FALSE);\n\n            RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n\n            return result;\n        }\n        break;\n    case WM_SETFOCUS:\n        {\n            context->WindowFocus = TRUE;\n            context->PreviousFocusWindowHandle = (HWND)wParam;\n        }\n        break;\n    case WM_KILLFOCUS:\n        {\n            context->WindowFocus = FALSE;\n\n            RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n        }\n        break;\n    case WM_SETTINGCHANGE:\n    case WM_SYSCOLORCHANGE:\n    case WM_THEMECHANGED:\n        {\n            PhpSearchControlThemeChanged(context, WindowHandle);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            context->WindowDpi = PhGetWindowDpi(context->ParentWindowHandle);\n\n            PhpSearchControlThemeChanged(context, WindowHandle);\n        }\n        break;\n    case WM_MOUSEMOVE:\n    case WM_NCMOUSEMOVE:\n        {\n            POINT windowPoint;\n            RECT windowRect;\n            RECT buttonRect;\n\n            // Get the screen coordinates of the mouse.\n            if (!PhGetMessagePos(&windowPoint))\n                break;\n            // Get the screen coordinates of the window.\n            if (!PhGetWindowRect(WindowHandle, &windowRect))\n                break;\n\n            context->Hot = PhPtInRect(&windowRect, &windowPoint);\n\n            PhpSearchControlButtonRect(context, &context->RegexButton, &windowRect, &buttonRect);\n            context->RegexButton.Hot = PhPtInRect(&buttonRect, &windowPoint);\n\n            if (context->RegexButton.Hot)\n            {\n                PhpSearchControlCreateTooltip(context, &context->RegexButton, WindowHandle, &buttonRect, L\"Regular Expression\");\n            }\n\n            PhpSearchControlButtonRect(context, &context->CaseButton, &windowRect, &buttonRect);\n            context->CaseButton.Hot = PhPtInRect(&buttonRect, &windowPoint);\n\n            if (context->CaseButton.Hot)\n            {\n                PhpSearchControlCreateTooltip(context, &context->CaseButton, WindowHandle, &buttonRect, L\"Match Case\");\n            }\n\n            PhpSearchControlButtonRect(context, &context->SearchButton, &windowRect, &buttonRect);\n            context->SearchButton.Hot = PhPtInRect(&buttonRect, &windowPoint);\n\n            if (context->SearchButton.Hot)\n            {\n                PhpSearchControlCreateTooltip(context, &context->SearchButton, WindowHandle, &buttonRect, L\"Clear Search\");\n            }\n\n            // Check that the mouse is within the inserted button.\n            if (!context->HotTrack)\n            {\n                TRACKMOUSEEVENT trackMouseEvent;\n                trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);\n                trackMouseEvent.dwFlags = TME_LEAVE | TME_NONCLIENT;\n                trackMouseEvent.hwndTrack = WindowHandle;\n                trackMouseEvent.dwHoverTime = 0;\n\n                context->HotTrack = TRUE;\n\n                TrackMouseEvent(&trackMouseEvent);\n            }\n\n            RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n        }\n        break;\n    case WM_MOUSELEAVE:\n    case WM_NCMOUSELEAVE:\n        {\n            POINT windowPoint;\n            RECT windowRect;\n            RECT buttonRect;\n\n            context->HotTrack = FALSE;\n\n            if (!PhGetMessagePos(&windowPoint))\n                break;\n            if (!PhGetWindowRect(WindowHandle, &windowRect))\n                break;\n\n            context->Hot = PhPtInRect(&windowRect, &windowPoint);\n\n            PhpSearchControlButtonRect(context, &context->SearchButton, &windowRect, &buttonRect);\n            context->SearchButton.Hot = PhPtInRect(&buttonRect, &windowPoint);\n\n            PhpSearchControlButtonRect(context, &context->RegexButton, &windowRect, &buttonRect);\n            context->RegexButton.Hot = PhPtInRect(&buttonRect, &windowPoint);\n\n            PhpSearchControlButtonRect(context, &context->CaseButton, &windowRect, &buttonRect);\n            context->CaseButton.Hot = PhPtInRect(&buttonRect, &windowPoint);\n\n            RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n        }\n        break;\n    case WM_PAINT:\n        {\n            if (\n                PhIsNullOrEmptyString(context->CueBannerText) ||\n                context->WindowFocus || // GetFocus() == WindowHandle ||\n                CallWindowProc(oldWndProc, WindowHandle, WM_GETTEXTLENGTH, 0, 0) > 0 // Edit_GetTextLength\n                )\n            {\n                goto SubclassWndProc;\n            }\n\n            PAINTSTRUCT paintStruct;\n            RECT clientRect;\n            HDC hdc;\n\n            if (hdc = BeginPaint(WindowHandle, &paintStruct))\n            {\n                HDC bufferDc;\n                HFONT oldFont;\n                HBITMAP bufferBitmap;\n                HBITMAP oldBufferBitmap;\n\n                clientRect = paintStruct.rcPaint;\n                bufferDc = CreateCompatibleDC(hdc);\n                bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom);\n                oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap);\n\n                SetBkMode(bufferDc, TRANSPARENT);\n\n                if (PhEnableThemeSupport)\n                {\n                    SetTextColor(bufferDc, RGB(170, 170, 170));\n                    SetDCBrushColor(bufferDc, RGB(60, 60, 60));\n                    FillRect(bufferDc, &clientRect, PhGetStockBrush(DC_BRUSH));\n                }\n                else\n                {\n                    SetTextColor(bufferDc, GetSysColor(COLOR_GRAYTEXT));\n                    FillRect(bufferDc, &clientRect, context->WindowBrush);\n                }\n\n                oldFont = SelectFont(bufferDc, context->WindowFont);\n                clientRect.left += 2;\n                DrawText(\n                    bufferDc,\n                    context->CueBannerText->Buffer,\n                    (UINT)context->CueBannerText->Length / sizeof(WCHAR),\n                    &clientRect,\n                    DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP\n                    );\n                clientRect.left -= 2;\n                SelectFont(bufferDc, oldFont);\n\n                BitBlt(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, bufferDc, 0, 0, SRCCOPY);\n                SelectBitmap(bufferDc, oldBufferBitmap);\n                DeleteBitmap(bufferBitmap);\n                DeleteDC(bufferDc);\n\n                EndPaint(WindowHandle, &paintStruct);\n            }\n        }\n        return 0;\n    case WM_KEYDOWN:\n        {\n            // Delete previous word for ctrl+backspace (thanks to Katayama Hirofumi MZ) (modified) (dmex)\n            if (wParam == VK_BACK && GetAsyncKeyState(VK_CONTROL) < 0)\n            {\n                LONG textStart = 0;\n                LONG textEnd = 0;\n                LONG textLength;\n\n                textLength = (LONG)CallWindowProc(oldWndProc, WindowHandle, WM_GETTEXTLENGTH, 0, 0);\n                CallWindowProc(oldWndProc, WindowHandle, EM_GETSEL, (WPARAM)&textStart, (LPARAM)&textEnd);\n\n                if (textLength > 0 && textStart == textEnd)\n                {\n                    ULONG textBufferLength;\n                    WCHAR textBuffer[0x100];\n\n                    if (!NT_SUCCESS(PhGetWindowTextToBuffer(WindowHandle, 0, textBuffer, RTL_NUMBER_OF(textBuffer), &textBufferLength)))\n                    {\n                        break;\n                    }\n\n                    for (; 0 < textStart; --textStart)\n                    {\n                        if (textBuffer[textStart - 1] == L' ' && iswalnum(textBuffer[textStart]))\n                        {\n                            CallWindowProc(oldWndProc, WindowHandle, EM_SETSEL, textStart, textEnd);\n                            CallWindowProc(oldWndProc, WindowHandle, EM_REPLACESEL, TRUE, (LPARAM)L\"\");\n                            return 1;\n                        }\n                    }\n\n                    if (textStart == 0)\n                    {\n                        PhSetWindowText(WindowHandle, L\"\");\n                        PhpSearchUpdateText(WindowHandle, context, FALSE);\n                        return 1;\n                    }\n                }\n            }\n            // Clear search and restore focus for esc key\n            else if (wParam == VK_ESCAPE)\n            {\n                PhSetWindowText(WindowHandle, L\"\");\n                PhpSearchUpdateText(WindowHandle, context, FALSE);\n                PhpSearchRestoreFocus(context);\n                return 1;\n            }\n            // Up/down arrows will just restore previous focus without clearing search\n            else if (wParam == VK_DOWN || wParam == VK_UP)\n            {\n                PhpSearchRestoreFocus(context);\n                return 1;\n            }\n        }\n        break;\n    case WM_CHAR:\n        {\n            // Delete previous word for ctrl+backspace (dmex)\n            if (wParam == VK_F16 && GetAsyncKeyState(VK_CONTROL) < 0)\n                return 1;\n        }\n        break;\n    case WM_GETDLGCODE:\n        {\n            // Intercept esc key (otherwise it would get sent to parent window)\n            if (wParam == VK_ESCAPE && ((MSG*)lParam)->message == WM_KEYDOWN)\n                return DLGC_WANTMESSAGE;\n        }\n        break;\n    case EM_SETCUEBANNER:\n        {\n            PWSTR text = (PWSTR)lParam;\n\n            PhMoveReference(&context->CueBannerText, PhCreateString(text));\n\n            RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n        }\n        return TRUE;\n    }\n\nSubclassWndProc:\n    return CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n//DefaultWndProc:\n//    return DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n}\n\nVOID PhCreateSearchControlEx(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND SearchWindowHandle,\n    _In_opt_ PCWSTR BannerText,\n    _In_ PVOID ImageBaseAddress,\n    _In_ PCWSTR SearchButtonResource,\n    _In_ PCWSTR SearchButtonActiveResource,\n    _In_ PCWSTR RegexButtonResource,\n    _In_ PCWSTR CaseButtonResource,\n    _In_ PCWSTR RegexSetting,\n    _In_ PCWSTR CaseSetting,\n    _In_ PPH_SEARCHCONTROL_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_SEARCHCONTROL_CONTEXT context;\n\n    context = PhAllocateZero(sizeof(PH_SEARCHCONTROL_CONTEXT));\n    context->ParentWindowHandle = ParentWindowHandle;\n    context->CueBannerText = BannerText ? PhCreateString(BannerText) : NULL;\n    context->WindowDpi = PhGetWindowDpi(ParentWindowHandle);\n\n    context->RegexSetting = RegexSetting;\n    context->CaseSetting = CaseSetting;\n\n    context->ImageBaseAddress = ImageBaseAddress;\n    context->SearchButtonResource = SearchButtonResource;\n    context->SearchButtonActiveResource = SearchButtonActiveResource;\n    context->RegexButtonResource = RegexButtonResource;\n    context->CaseButtonResource = CaseButtonResource;\n\n    context->Callback = Callback;\n    context->CallbackContext = Context;\n\n    context->RegexButton.Active = !!PhGetIntegerSetting(context->RegexSetting);\n    context->CaseButton.Active = !!PhGetIntegerSetting(context->CaseSetting);\n\n    // Subclass the Edit control window procedure.\n    context->DefaultWindowProc = PhGetWindowProcedure(SearchWindowHandle);\n    PhSetWindowContext(SearchWindowHandle, SHRT_MAX, context);\n    PhSetWindowProcedure(SearchWindowHandle, PhpSearchWndSubclassProc);\n\n    // Initialize the theme parameters.\n    PhpSearchControlThemeChanged(context, SearchWindowHandle);\n}\n\nVOID PhSearchControlClear(\n    _In_ HWND SearchWindowHandle\n    )\n{\n    SetFocus(SearchWindowHandle);\n    PhSetWindowText(SearchWindowHandle, L\"\");\n}\n\nBOOLEAN PhSearchControlMatch(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PCPH_STRINGREF Text\n    )\n{\n    PPH_SEARCHCONTROL_CONTEXT context;\n\n    context = (PPH_SEARCHCONTROL_CONTEXT)MatchHandle;\n\n    if (!context)\n        return FALSE;\n\n    if (context->RegexButton.Active)\n    {\n        if (pcre2_match(\n            context->SearchboxRegexCode,\n            Text->Buffer,\n            Text->Length / sizeof(WCHAR),\n            0,\n            0,\n            context->SearchboxRegexMatchData,\n            NULL\n            ) >= 0)\n        {\n            return TRUE;\n        }\n    }\n    else if (context->CaseButton.Active)\n    {\n        if (PhFindStringInStringRef(Text, &context->SearchboxText, FALSE) != MAXULONG_PTR)\n            return TRUE;\n    }\n    else\n    {\n        if (PhFindStringInStringRef(Text, &context->SearchboxText, TRUE) != MAXULONG_PTR)\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhSearchControlMatchZ(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PCWSTR Text\n    )\n{\n    PH_STRINGREF text;\n\n    PhInitializeStringRef(&text, Text);\n\n    return PhSearchControlMatch(MatchHandle, &text);\n}\n\nBOOLEAN PhSearchControlMatchLongHintZ(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PCWSTR Text\n    )\n{\n    PH_STRINGREF text;\n\n    PhInitializeStringRefLongHint(&text, Text);\n\n    return PhSearchControlMatch(MatchHandle, &text);\n}\n\nBOOLEAN PhSearchControlMatchPointer(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PVOID Pointer\n    )\n{\n    PPH_SEARCHCONTROL_CONTEXT context;\n\n    context = (PPH_SEARCHCONTROL_CONTEXT)MatchHandle;\n\n    if (!Pointer || !context || !context->UseSearchPointer)\n        return FALSE;\n\n    return ((ULONG64)Pointer == context->SearchPointer);\n}\n\nBOOLEAN PhSearchControlMatchPointerRange(\n    _In_ ULONG_PTR MatchHandle,\n    _In_ PVOID Pointer,\n    _In_ SIZE_T Size\n    )\n{\n    PPH_SEARCHCONTROL_CONTEXT context;\n    PVOID pointerEnd;\n\n    context = (PPH_SEARCHCONTROL_CONTEXT)MatchHandle;\n\n    if (!context || !context->UseSearchPointer)\n        return FALSE;\n\n    pointerEnd = PTR_ADD_OFFSET(Pointer, Size);\n\n    return ((context->SearchPointer >= (ULONG64)Pointer) &&\n            (context->SearchPointer < (ULONG64)pointerEnd));\n}\n\n"
  },
  {
    "path": "phlib/secdata.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <ph.h>\n#include <secedit.h>\n#include <wbemcli.h>\n#include <wtsapi32.h>\n\n#define ACCESS_ENTRIES(Type) static const PH_ACCESS_ENTRY Ph##Type##AccessEntries[] =\n#define ACCESS_ENTRY(Type, HasSynchronize) \\\n   { TEXT(#Type), (PPH_ACCESS_ENTRY)Ph##Type##AccessEntries, sizeof(Ph##Type##AccessEntries), HasSynchronize }\n\ntypedef struct _PH_SPECIFIC_TYPE\n{\n    PCWSTR Type;\n    PPH_ACCESS_ENTRY AccessEntries;\n    ULONG SizeOfAccessEntries;\n    BOOLEAN HasSynchronize;\n} PH_SPECIFIC_TYPE, *PPH_SPECIFIC_TYPE;\n\nACCESS_ENTRIES(Standard)\n{\n    { L\"Synchronize\", SYNCHRONIZE, FALSE, TRUE, NULL },\n    { L\"Delete\", DELETE, FALSE, TRUE, NULL },\n    { L\"Read permissions\", READ_CONTROL, FALSE, TRUE, L\"Read control\" },\n    { L\"Change permissions\", WRITE_DAC, FALSE, TRUE, L\"Write DAC\" },\n    { L\"Take ownership\", WRITE_OWNER, FALSE, TRUE, L\"Write owner\" }\n};\n\nACCESS_ENTRIES(AlpcPort)\n{\n    { L\"Full control\", PORT_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Connect\", PORT_CONNECT, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(DebugObject)\n{\n    { L\"Full control\", DEBUG_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read events\", DEBUG_READ_EVENT, TRUE, TRUE, NULL },\n    { L\"Assign processes\", DEBUG_PROCESS_ASSIGN, TRUE, TRUE, NULL },\n    { L\"Query information\", DEBUG_QUERY_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set information\", DEBUG_SET_INFORMATION, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Desktop)\n{\n    { L\"Full control\", DESKTOP_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", DESKTOP_GENERIC_READ, TRUE, FALSE, NULL },\n    { L\"Write\", DESKTOP_GENERIC_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", DESKTOP_GENERIC_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Enumerate\", DESKTOP_ENUMERATE, FALSE, TRUE, NULL },\n    { L\"Read objects\", DESKTOP_READOBJECTS, FALSE, TRUE, NULL },\n    { L\"Playback journals\", DESKTOP_JOURNALPLAYBACK, FALSE, TRUE, NULL },\n    { L\"Write objects\", DESKTOP_WRITEOBJECTS, FALSE, TRUE, NULL },\n    { L\"Create windows\", DESKTOP_CREATEWINDOW, FALSE, TRUE, NULL },\n    { L\"Create menus\", DESKTOP_CREATEMENU, FALSE, TRUE, NULL },\n    { L\"Create window hooks\", DESKTOP_HOOKCONTROL, FALSE, TRUE, NULL },\n    { L\"Record journals\", DESKTOP_JOURNALRECORD, FALSE, TRUE, NULL },\n    { L\"Switch desktop\", DESKTOP_SWITCHDESKTOP, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Directory)\n{\n    { L\"Full control\", DIRECTORY_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", DIRECTORY_QUERY, TRUE, TRUE, NULL },\n    { L\"Traverse\", DIRECTORY_TRAVERSE, TRUE, TRUE, NULL },\n    { L\"Create objects\", DIRECTORY_CREATE_OBJECT, TRUE, TRUE, NULL },\n    { L\"Create subdirectories\", DIRECTORY_CREATE_SUBDIRECTORY, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(EtwConsumer)\n{\n    { L\"Full control\", WMIGUID_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", WMIGUID_QUERY, TRUE, TRUE, NULL },\n    { L\"Read\", WMIGUID_SET, TRUE, TRUE, NULL },\n    { L\"Notification\", WMIGUID_NOTIFICATION, TRUE, TRUE, NULL },\n    { L\"Read description\", WMIGUID_READ_DESCRIPTION, TRUE, TRUE, NULL },\n    { L\"Execute\", WMIGUID_EXECUTE, TRUE, TRUE, NULL },\n    { L\"Create realtime\", TRACELOG_CREATE_REALTIME, TRUE, TRUE, NULL },\n    { L\"Create logfile\", TRACELOG_CREATE_ONDISK, TRUE, TRUE, NULL },\n    { L\"GUID enable\", TRACELOG_GUID_ENABLE, TRUE, TRUE, NULL },\n    { L\"Access kernel logger\", TRACELOG_ACCESS_KERNEL_LOGGER, TRUE, TRUE, NULL },\n    { L\"Log events\", TRACELOG_LOG_EVENT, TRUE, TRUE, NULL },\n    { L\"Access realtime\", TRACELOG_ACCESS_REALTIME, TRUE, TRUE, NULL },\n    { L\"Register guids\", TRACELOG_REGISTER_GUIDS, TRUE, TRUE, NULL },\n    { L\"Join group\", TRACELOG_JOIN_GROUP, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(EtwRegistration)\n{\n    { L\"Full control\", WMIGUID_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", WMIGUID_QUERY, TRUE, TRUE, NULL },\n    { L\"Read\", WMIGUID_SET, TRUE, TRUE, NULL },\n    { L\"Notification\", WMIGUID_NOTIFICATION, TRUE, TRUE, NULL },\n    { L\"Read description\", WMIGUID_READ_DESCRIPTION, TRUE, TRUE, NULL },\n    { L\"Execute\", WMIGUID_EXECUTE, TRUE, TRUE, NULL },\n    { L\"Create realtime\", TRACELOG_CREATE_REALTIME, TRUE, TRUE, NULL },\n    { L\"Create logfile\", TRACELOG_CREATE_ONDISK, TRUE, TRUE, NULL },\n    { L\"GUID enable\", TRACELOG_GUID_ENABLE, TRUE, TRUE, NULL },\n    { L\"Access kernel logger\", TRACELOG_ACCESS_KERNEL_LOGGER, TRUE, TRUE, NULL },\n    { L\"Log events\", TRACELOG_LOG_EVENT, TRUE, TRUE, NULL },\n    { L\"Access realtime\", TRACELOG_ACCESS_REALTIME, TRUE, TRUE, NULL },\n    { L\"Register guids\", TRACELOG_REGISTER_GUIDS, TRUE, TRUE, NULL },\n    { L\"Join group\", TRACELOG_JOIN_GROUP, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Event)\n{\n    { L\"Full control\", EVENT_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", EVENT_QUERY_STATE, TRUE, TRUE, NULL },\n    { L\"Modify\", EVENT_MODIFY_STATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(EventPair)\n{\n    { L\"Full control\", EVENT_PAIR_ALL_ACCESS, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(File)\n{\n    { L\"Full control\", FILE_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read & execute\", FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Read\", FILE_GENERIC_READ, TRUE, FALSE, NULL },\n    { L\"Write\", FILE_GENERIC_WRITE, TRUE, FALSE, NULL },\n    { L\"Traverse folder / execute file\", FILE_EXECUTE, FALSE, TRUE, L\"Execute\" },\n    { L\"List folder / read data\", FILE_READ_DATA, FALSE, TRUE, L\"Read data\" },\n    { L\"Read attributes\", FILE_READ_ATTRIBUTES, FALSE, TRUE, NULL },\n    { L\"Read extended attributes\", FILE_READ_EA, FALSE, TRUE, L\"Read EA\" },\n    { L\"Create files / write data\", FILE_WRITE_DATA, FALSE, TRUE, L\"Write data\" },\n    { L\"Create folders / append data\", FILE_APPEND_DATA, FALSE, TRUE, L\"Append data\" },\n    { L\"Write attributes\", FILE_WRITE_ATTRIBUTES, FALSE, TRUE, NULL },\n    { L\"Write extended attributes\", FILE_WRITE_EA, FALSE, TRUE, L\"Write EA\" },\n    { L\"Delete subfolders and files\", FILE_DELETE_CHILD, FALSE, TRUE, L\"Delete child\" }\n};\n\nACCESS_ENTRIES(FilterConnectionPort)\n{\n    { L\"Full control\", FLT_PORT_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Connect\", FLT_PORT_CONNECT, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(IoCompletion)\n{\n    { L\"Full control\", IO_COMPLETION_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", IO_COMPLETION_QUERY_STATE, TRUE, TRUE, NULL },\n    { L\"Modify\", IO_COMPLETION_MODIFY_STATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Job)\n{\n    { L\"Full control\", JOB_OBJECT_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", JOB_OBJECT_QUERY, TRUE, TRUE, NULL },\n    { L\"Assign processes\", JOB_OBJECT_ASSIGN_PROCESS, TRUE, TRUE, NULL },\n    { L\"Set attributes\", JOB_OBJECT_SET_ATTRIBUTES, TRUE, TRUE, NULL },\n    { L\"Set security attributes\", JOB_OBJECT_SET_SECURITY_ATTRIBUTES, TRUE, TRUE, NULL },\n    { L\"Terminate\", JOB_OBJECT_TERMINATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Key)\n{\n    { L\"Full control\", KEY_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", KEY_READ, TRUE, FALSE, NULL },\n    { L\"Write\", KEY_WRITE, TRUE, FALSE, NULL },\n    //{ L\"Execute\", KEY_EXECUTE, TRUE, FALSE }, // KEY_EXECUTE has the same value as KEY_READ (dmex)\n    { L\"Enumerate subkeys\", KEY_ENUMERATE_SUB_KEYS, FALSE, TRUE, NULL },\n    { L\"Query values\", KEY_QUERY_VALUE, FALSE, TRUE, NULL },\n    { L\"Notify\", KEY_NOTIFY, FALSE, TRUE, NULL },\n    { L\"Set values\", KEY_SET_VALUE, FALSE, TRUE, NULL },\n    { L\"Create subkeys\", KEY_CREATE_SUB_KEY, FALSE, TRUE, NULL },\n    { L\"Create links\", KEY_CREATE_LINK, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(KeyedEvent)\n{\n    { L\"Full control\", KEYEDEVENT_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Wait\", KEYEDEVENT_WAIT, TRUE, TRUE, NULL },\n    { L\"Wake\", KEYEDEVENT_WAKE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(LsaAccount)\n{\n    { L\"Full control\", ACCOUNT_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", ACCOUNT_READ, TRUE, FALSE, NULL },\n    { L\"Write\", ACCOUNT_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", ACCOUNT_EXECUTE, TRUE, FALSE, NULL },\n    { L\"View\", ACCOUNT_VIEW, FALSE, TRUE, NULL },\n    { L\"Adjust privileges\", ACCOUNT_ADJUST_PRIVILEGES, FALSE, TRUE, NULL },\n    { L\"Adjust quotas\", ACCOUNT_ADJUST_QUOTAS, FALSE, TRUE, NULL },\n    { L\"Adjust system access\", ACCOUNT_ADJUST_SYSTEM_ACCESS, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(LsaPolicy)\n{\n    { L\"Full control\", POLICY_ALL_ACCESS | POLICY_NOTIFICATION, TRUE, TRUE, NULL },\n    { L\"Read\", POLICY_READ, TRUE, FALSE, NULL },\n    { L\"Write\", POLICY_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", POLICY_EXECUTE | POLICY_NOTIFICATION, TRUE, FALSE, NULL },\n    { L\"View local information\", POLICY_VIEW_LOCAL_INFORMATION, FALSE, TRUE, NULL },\n    { L\"View audit information\", POLICY_VIEW_AUDIT_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Get private information\", POLICY_GET_PRIVATE_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Administer trust\", POLICY_TRUST_ADMIN, FALSE, TRUE, NULL },\n    { L\"Create account\", POLICY_CREATE_ACCOUNT, FALSE, TRUE, NULL },\n    { L\"Create secret\", POLICY_CREATE_SECRET, FALSE, TRUE, NULL },\n    { L\"Create privilege\", POLICY_CREATE_PRIVILEGE, FALSE, TRUE, NULL },\n    { L\"Set default quota limits\", POLICY_SET_DEFAULT_QUOTA_LIMITS, FALSE, TRUE, NULL },\n    { L\"Set audit requirements\", POLICY_SET_AUDIT_REQUIREMENTS, FALSE, TRUE, NULL },\n    { L\"Administer audit log\", POLICY_AUDIT_LOG_ADMIN, FALSE, TRUE, NULL },\n    { L\"Administer server\", POLICY_SERVER_ADMIN, FALSE, TRUE, NULL },\n    { L\"Lookup names\", POLICY_LOOKUP_NAMES, FALSE, TRUE, NULL },\n    { L\"Get notifications\", POLICY_NOTIFICATION, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(LsaSecret)\n{\n    { L\"Full control\", SECRET_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", SECRET_READ, TRUE, FALSE, NULL },\n    { L\"Write\", SECRET_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", SECRET_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Set value\", SECRET_SET_VALUE, FALSE, TRUE, NULL },\n    { L\"Query value\", SECRET_QUERY_VALUE, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(LsaTrusted)\n{\n    { L\"Full control\", TRUSTED_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", TRUSTED_READ, TRUE, FALSE, NULL },\n    { L\"Write\", TRUSTED_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", TRUSTED_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Query domain name\", TRUSTED_QUERY_DOMAIN_NAME, FALSE, TRUE, NULL },\n    { L\"Query controllers\", TRUSTED_QUERY_CONTROLLERS, FALSE, TRUE, NULL },\n    { L\"Set controllers\", TRUSTED_SET_CONTROLLERS, FALSE, TRUE, NULL },\n    { L\"Query POSIX\", TRUSTED_QUERY_POSIX, FALSE, TRUE, NULL },\n    { L\"Set POSIX\", TRUSTED_SET_POSIX, FALSE, TRUE, NULL },\n    { L\"Query authentication\", TRUSTED_QUERY_AUTH, FALSE, TRUE, NULL },\n    { L\"Set authentication\", TRUSTED_SET_AUTH, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Mutant)\n{\n    { L\"Full control\", MUTANT_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", MUTANT_QUERY_STATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Partition)\n{\n    { L\"Full control\", MEMORY_PARTITION_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", MEMORY_PARTITION_QUERY_ACCESS, TRUE, TRUE, NULL },\n    { L\"Modify\", MEMORY_PARTITION_MODIFY_ACCESS, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Process)\n{\n    { L\"Full control\", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, TRUE, TRUE, NULL },\n    { L\"Query information\", PROCESS_QUERY_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set information\", PROCESS_SET_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set quotas\", PROCESS_SET_QUOTA, TRUE, TRUE, NULL },\n    { L\"Set session ID\", PROCESS_SET_SESSIONID, TRUE, TRUE, NULL },\n    { L\"Create threads\", PROCESS_CREATE_THREAD, TRUE, TRUE, NULL },\n    { L\"Create processes\", PROCESS_CREATE_PROCESS, TRUE, TRUE, NULL },\n    { L\"Modify memory\", PROCESS_VM_OPERATION, TRUE, TRUE, L\"VM operation\" },\n    { L\"Read memory\", PROCESS_VM_READ, TRUE, TRUE, L\"VM read\" },\n    { L\"Write memory\", PROCESS_VM_WRITE, TRUE, TRUE, L\"VM write\" },\n    { L\"Duplicate handles\", PROCESS_DUP_HANDLE, TRUE, TRUE, NULL },\n    { L\"Suspend / resume / set port\", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L\"Suspend/resume\" },\n    { L\"Terminate\", PROCESS_TERMINATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Process60)\n{\n    { L\"Full control\", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | SPECIFIC_RIGHTS_ALL, TRUE, TRUE, NULL }, // PROCESS_ALL_ACCESS\n    { L\"Query limited information\", PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Query information\", PROCESS_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set information\", PROCESS_SET_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set limited information\", PROCESS_SET_LIMITED_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set quotas\", PROCESS_SET_QUOTA, TRUE, TRUE, NULL },\n    { L\"Set session ID\", PROCESS_SET_SESSIONID, TRUE, TRUE, NULL },\n    { L\"Create threads\", PROCESS_CREATE_THREAD, TRUE, TRUE, NULL },\n    { L\"Create processes\", PROCESS_CREATE_PROCESS, TRUE, TRUE, NULL },\n    { L\"Modify memory\", PROCESS_VM_OPERATION, TRUE, TRUE, L\"VM operation\" },\n    { L\"Read memory\", PROCESS_VM_READ, TRUE, TRUE, L\"VM read\" },\n    { L\"Write memory\", PROCESS_VM_WRITE, TRUE, TRUE, L\"VM write\" },\n    { L\"Duplicate handles\", PROCESS_DUP_HANDLE, TRUE, TRUE, NULL },\n    { L\"Suspend / resume / set port\", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L\"Suspend/resume\" },\n    { L\"Terminate\", PROCESS_TERMINATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Profile)\n{\n    { L\"Full control\", PROFILE_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Control\", PROFILE_CONTROL, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(SamAlias)\n{\n    { L\"Full control\", ALIAS_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", ALIAS_READ, TRUE, FALSE, NULL },\n    { L\"Write\", ALIAS_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", ALIAS_EXECUTE, TRUE, FALSE },\n    { L\"Read information\", ALIAS_READ_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Write account\", ALIAS_WRITE_ACCOUNT, FALSE, TRUE, NULL },\n    { L\"Add member\", ALIAS_ADD_MEMBER, FALSE, TRUE, NULL },\n    { L\"Remove member\", ALIAS_REMOVE_MEMBER, FALSE, TRUE, NULL },\n    { L\"List members\", ALIAS_LIST_MEMBERS, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(SamDomain)\n{\n    { L\"Full control\", DOMAIN_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", DOMAIN_READ, TRUE, FALSE, NULL },\n    { L\"Write\", DOMAIN_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", DOMAIN_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Read password parameters\", DOMAIN_READ_PASSWORD_PARAMETERS, FALSE, TRUE, NULL },\n    { L\"Write password parameters\", DOMAIN_WRITE_PASSWORD_PARAMS, FALSE, TRUE, NULL },\n    { L\"Read other parameters\", DOMAIN_READ_OTHER_PARAMETERS, FALSE, TRUE, NULL },\n    { L\"Write other parameters\", DOMAIN_WRITE_OTHER_PARAMETERS, FALSE, TRUE, NULL },\n    { L\"Create user\", DOMAIN_CREATE_USER, FALSE, TRUE, NULL },\n    { L\"Create group\", DOMAIN_CREATE_GROUP, FALSE, TRUE, NULL },\n    { L\"Create alias\", DOMAIN_CREATE_ALIAS, FALSE, TRUE, NULL },\n    { L\"Get alias membership\", DOMAIN_GET_ALIAS_MEMBERSHIP, FALSE, TRUE, NULL },\n    { L\"List accounts\", DOMAIN_LIST_ACCOUNTS, FALSE, TRUE, NULL },\n    { L\"Lookup\", DOMAIN_LOOKUP, FALSE, TRUE, NULL },\n    { L\"Administer server\", DOMAIN_ADMINISTER_SERVER, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(SamGroup)\n{\n    { L\"Full control\", GROUP_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", GROUP_READ, TRUE, FALSE, NULL },\n    { L\"Write\", GROUP_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", GROUP_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Read information\", GROUP_READ_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Write account\", GROUP_WRITE_ACCOUNT, FALSE, TRUE, NULL },\n    { L\"Add member\", GROUP_ADD_MEMBER, FALSE, TRUE, NULL },\n    { L\"Remove member\", GROUP_REMOVE_MEMBER, FALSE, TRUE, NULL },\n    { L\"List members\", GROUP_LIST_MEMBERS, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(SamServer)\n{\n    { L\"Full control\", SAM_SERVER_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", SAM_SERVER_READ, TRUE, FALSE, NULL },\n    { L\"Write\", SAM_SERVER_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", SAM_SERVER_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Connect\", SAM_SERVER_CONNECT, FALSE, TRUE, NULL },\n    { L\"Shutdown\", SAM_SERVER_SHUTDOWN, FALSE, TRUE, NULL },\n    { L\"Initialize\", SAM_SERVER_INITIALIZE, FALSE, TRUE, NULL },\n    { L\"Create domain\", SAM_SERVER_CREATE_DOMAIN, FALSE, TRUE, NULL },\n    { L\"Enumerate domains\", SAM_SERVER_ENUMERATE_DOMAINS, FALSE, TRUE, NULL },\n    { L\"Lookup domain\", SAM_SERVER_LOOKUP_DOMAIN, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(SamUser)\n{\n    { L\"Full control\", USER_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", USER_READ, TRUE, FALSE, NULL },\n    { L\"Write\", USER_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", USER_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Read general\", USER_READ_GENERAL, FALSE, TRUE, NULL },\n    { L\"Read preferences\", USER_READ_PREFERENCES, FALSE, TRUE, NULL },\n    { L\"Write preferences\", USER_WRITE_PREFERENCES, FALSE, TRUE, NULL },\n    { L\"Read logon\", USER_READ_LOGON, FALSE, TRUE, NULL },\n    { L\"Read account\", USER_READ_ACCOUNT, FALSE, TRUE, NULL },\n    { L\"Write account\", USER_WRITE_ACCOUNT, FALSE, TRUE, NULL },\n    { L\"Change password\", USER_CHANGE_PASSWORD, FALSE, TRUE, NULL },\n    { L\"Force password change\", USER_FORCE_PASSWORD_CHANGE, FALSE, TRUE, NULL },\n    { L\"List groups\", USER_LIST_GROUPS, FALSE, TRUE, NULL },\n    { L\"Read group information\", USER_READ_GROUP_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Write group information\", USER_WRITE_GROUP_INFORMATION, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Section)\n{\n    { L\"Full control\", SECTION_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", SECTION_QUERY, TRUE, TRUE, NULL },\n    { L\"Map for read\", SECTION_MAP_READ, TRUE, TRUE, L\"Map read\" },\n    { L\"Map for write\", SECTION_MAP_WRITE, TRUE, TRUE, L\"Map write\" },\n    { L\"Map for execute\", SECTION_MAP_EXECUTE, TRUE, TRUE, L\"Map execute\" },\n    { L\"Map for execute (explicit)\", SECTION_MAP_EXECUTE_EXPLICIT, TRUE, TRUE, L\"Map execute explicit\" },\n    { L\"Extend size\", SECTION_EXTEND_SIZE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Semaphore)\n{\n    { L\"Full control\", SEMAPHORE_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", SEMAPHORE_QUERY_STATE, TRUE, TRUE, NULL },\n    { L\"Modify\", SEMAPHORE_MODIFY_STATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Service)\n{\n    { L\"Full control\", SERVICE_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query status\", SERVICE_QUERY_STATUS, TRUE, TRUE, NULL },\n    { L\"Query configuration\", SERVICE_QUERY_CONFIG, TRUE, TRUE, NULL },\n    { L\"Modify configuration\", SERVICE_CHANGE_CONFIG, TRUE, TRUE, NULL },\n    { L\"Enumerate dependents\", SERVICE_ENUMERATE_DEPENDENTS, TRUE, TRUE, NULL },\n    { L\"Start\", SERVICE_START, TRUE, TRUE, NULL },\n    { L\"Stop\", SERVICE_STOP, TRUE, TRUE, NULL },\n    { L\"Pause / continue\", SERVICE_PAUSE_CONTINUE, TRUE, TRUE, L\"Pause/continue\" },\n    { L\"Interrogate\", SERVICE_INTERROGATE, TRUE, TRUE, NULL },\n    { L\"User-defined control\", SERVICE_USER_DEFINED_CONTROL, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(SCManager)\n{\n    { L\"Full control\", SC_MANAGER_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Create service\", SC_MANAGER_CREATE_SERVICE, TRUE, TRUE, NULL },\n    { L\"Connect\", SC_MANAGER_CONNECT, TRUE, TRUE, NULL },\n    { L\"Enumerate services\", SC_MANAGER_ENUMERATE_SERVICE, TRUE, TRUE, NULL },\n    { L\"Lock\", SC_MANAGER_LOCK, TRUE, TRUE, NULL },\n    { L\"Modify boot config\", SC_MANAGER_MODIFY_BOOT_CONFIG, TRUE, TRUE, NULL },\n    { L\"Query lock status\", SC_MANAGER_QUERY_LOCK_STATUS, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Session)\n{\n    { L\"Full control\", SESSION_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", SESSION_QUERY_ACCESS, TRUE, TRUE, NULL },\n    { L\"Modify\", SESSION_MODIFY_ACCESS, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(SymbolicLink)\n{\n    { L\"Full control\", SYMBOLIC_LINK_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Full control (extended)\", SYMBOLIC_LINK_ALL_ACCESS_EX, TRUE, TRUE, NULL },\n    { L\"Query\", SYMBOLIC_LINK_QUERY, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Thread)\n{\n    { L\"Full control\", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff, TRUE, TRUE, NULL },\n    { L\"Query information\", THREAD_QUERY_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set information\", THREAD_SET_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Get context\", THREAD_GET_CONTEXT, TRUE, TRUE, NULL },\n    { L\"Set context\", THREAD_SET_CONTEXT, TRUE, TRUE, NULL },\n    { L\"Set token\", THREAD_SET_THREAD_TOKEN, TRUE, TRUE, NULL },\n    { L\"Alert\", THREAD_ALERT, TRUE, TRUE, NULL },\n    { L\"Impersonate\", THREAD_IMPERSONATE, TRUE, TRUE, NULL },\n    { L\"Direct impersonate\", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE, NULL },\n    { L\"Suspend / resume\", THREAD_SUSPEND_RESUME, TRUE, TRUE, L\"Suspend/resume\" },\n    { L\"Terminate\", THREAD_TERMINATE, TRUE, TRUE, NULL },\n};\n\nACCESS_ENTRIES(Thread60)\n{\n    { L\"Full control\", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | SPECIFIC_RIGHTS_ALL, TRUE, TRUE, NULL }, // THREAD_ALL_ACCESS\n    { L\"Query limited information\", THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Query information\", THREAD_QUERY_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set limited information\", THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set information\", THREAD_SET_INFORMATION | THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Get context\", THREAD_GET_CONTEXT, TRUE, TRUE, NULL },\n    { L\"Set context\", THREAD_SET_CONTEXT, TRUE, TRUE, NULL },\n    { L\"Set token\", THREAD_SET_THREAD_TOKEN, TRUE, TRUE, NULL },\n    { L\"Alert\", THREAD_ALERT, TRUE, TRUE, NULL },\n    { L\"Impersonate\", THREAD_IMPERSONATE, TRUE, TRUE, NULL },\n    { L\"Direct impersonate\", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE, NULL },\n    { L\"Suspend / resume\", THREAD_SUSPEND_RESUME, TRUE, TRUE, L\"Suspend/resume\" },\n    { L\"Terminate\", THREAD_TERMINATE, TRUE, TRUE, NULL },\n};\n\nACCESS_ENTRIES(Timer)\n{\n    { L\"Full control\", TIMER_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query\", TIMER_QUERY_STATE, TRUE, TRUE, NULL },\n    { L\"Modify\", TIMER_MODIFY_STATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(TmEn)\n{\n    { L\"Full control\", ENLISTMENT_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", ENLISTMENT_GENERIC_READ, TRUE, FALSE, NULL },\n    { L\"Write\", ENLISTMENT_GENERIC_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", ENLISTMENT_GENERIC_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Query information\", ENLISTMENT_QUERY_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Set information\", ENLISTMENT_SET_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Recover\", ENLISTMENT_RECOVER, FALSE, TRUE, NULL },\n    { L\"Subordinate rights\", ENLISTMENT_SUBORDINATE_RIGHTS, FALSE, TRUE, NULL },\n    { L\"Superior rights\", ENLISTMENT_SUPERIOR_RIGHTS, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(TmRm)\n{\n    { L\"Full control\", RESOURCEMANAGER_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", RESOURCEMANAGER_GENERIC_READ, TRUE, FALSE, NULL },\n    { L\"Write\", RESOURCEMANAGER_GENERIC_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", RESOURCEMANAGER_GENERIC_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Query information\", RESOURCEMANAGER_QUERY_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Set information\", RESOURCEMANAGER_SET_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Get notifications\", RESOURCEMANAGER_GET_NOTIFICATION, FALSE, TRUE, NULL },\n    { L\"Enlist\", RESOURCEMANAGER_ENLIST, FALSE, TRUE, NULL },\n    { L\"Recover\", RESOURCEMANAGER_RECOVER, FALSE, TRUE, NULL },\n    { L\"Register protocols\", RESOURCEMANAGER_REGISTER_PROTOCOL, FALSE, TRUE, NULL },\n    { L\"Complete propagation\", RESOURCEMANAGER_COMPLETE_PROPAGATION, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(TmTm)\n{\n    { L\"Full control\", TRANSACTIONMANAGER_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", TRANSACTIONMANAGER_GENERIC_READ, TRUE, FALSE, NULL },\n    { L\"Write\", TRANSACTIONMANAGER_GENERIC_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", TRANSACTIONMANAGER_GENERIC_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Query information\", TRANSACTIONMANAGER_QUERY_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Set information\", TRANSACTIONMANAGER_SET_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Recover\", TRANSACTIONMANAGER_RECOVER, FALSE, TRUE, NULL },\n    { L\"Rename\", TRANSACTIONMANAGER_RENAME, FALSE, TRUE, NULL },\n    { L\"Create resource manager\", TRANSACTIONMANAGER_CREATE_RM, FALSE, TRUE, NULL },\n    { L\"Bind transactions\", TRANSACTIONMANAGER_BIND_TRANSACTION, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(TmTx)\n{\n    { L\"Full control\", TRANSACTION_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", TRANSACTION_GENERIC_READ, TRUE, FALSE, NULL },\n    { L\"Write\", TRANSACTION_GENERIC_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", TRANSACTION_GENERIC_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Query information\", TRANSACTION_QUERY_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Set information\", TRANSACTION_SET_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Enlist\", TRANSACTION_ENLIST, FALSE, TRUE, NULL },\n    { L\"Commit\", TRANSACTION_COMMIT, FALSE, TRUE, NULL },\n    { L\"Rollback\", TRANSACTION_ROLLBACK, FALSE, TRUE, NULL },\n    { L\"Propagate\", TRANSACTION_PROPAGATE, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Token)\n{\n    { L\"Full control\", TOKEN_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", TOKEN_READ, FALSE, FALSE, NULL },\n    { L\"Write\", TOKEN_WRITE, FALSE, FALSE, NULL },\n    { L\"Execute\", TOKEN_EXECUTE, FALSE, FALSE, NULL },\n    { L\"Adjust privileges\", TOKEN_ADJUST_PRIVILEGES, TRUE, TRUE, NULL },\n    { L\"Adjust groups\", TOKEN_ADJUST_GROUPS, TRUE, TRUE, NULL },\n    { L\"Adjust defaults\", TOKEN_ADJUST_DEFAULT, TRUE, TRUE, NULL },\n    { L\"Adjust session ID\", TOKEN_ADJUST_SESSIONID, TRUE, TRUE, NULL },\n    { L\"Assign as primary token\", TOKEN_ASSIGN_PRIMARY, TRUE, TRUE, L\"Assign primary\" },\n    { L\"Duplicate\", TOKEN_DUPLICATE, TRUE, TRUE, NULL },\n    { L\"Impersonate\", TOKEN_IMPERSONATE, TRUE, TRUE, NULL },\n    { L\"Query\", TOKEN_QUERY, TRUE, TRUE, NULL },\n    { L\"Query source\", TOKEN_QUERY_SOURCE, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(TokenDefault)\n{\n    { L\"Full control\", GENERIC_ALL, TRUE, TRUE, NULL },\n    { L\"Read\", GENERIC_READ, TRUE, TRUE, NULL },\n    { L\"Write\", GENERIC_WRITE, TRUE, TRUE, NULL },\n    { L\"Execute\", GENERIC_EXECUTE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(TpWorkerFactory)\n{\n    { L\"Full control\", WORKER_FACTORY_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Release worker\", WORKER_FACTORY_RELEASE_WORKER, FALSE, TRUE, NULL },\n    { L\"Ready worker\", WORKER_FACTORY_READY_WORKER, FALSE, TRUE, NULL },\n    { L\"Wait\", WORKER_FACTORY_WAIT, FALSE, TRUE, NULL },\n    { L\"Set information\", WORKER_FACTORY_SET_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Query information\", WORKER_FACTORY_QUERY_INFORMATION, FALSE, TRUE, NULL },\n    { L\"Shutdown\", WORKER_FACTORY_SHUTDOWN, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Type)\n{\n    { L\"Full control\", OBJECT_TYPE_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Create\", OBJECT_TYPE_CREATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(WaitCompletionPacket)\n{\n    { L\"Full control\", OBJECT_TYPE_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Modify state\", OBJECT_TYPE_CREATE, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(Wbem)\n{\n    { L\"Enable account\", WBEM_ENABLE, TRUE, TRUE, NULL },\n    { L\"Execute methods\", WBEM_METHOD_EXECUTE, TRUE, TRUE, NULL },\n    { L\"Full write\", WBEM_FULL_WRITE_REP, TRUE, TRUE, NULL },\n    { L\"Partial write\", WBEM_PARTIAL_WRITE_REP, TRUE, TRUE, NULL },\n    { L\"Provider write\", WBEM_WRITE_PROVIDER, TRUE, TRUE, NULL },\n    { L\"Remote enable\", WBEM_REMOTE_ACCESS, TRUE, TRUE, NULL },\n    { L\"Get notifications\", WBEM_RIGHT_SUBSCRIBE, TRUE, TRUE, NULL },\n    { L\"Read description\", WBEM_RIGHT_PUBLISH, TRUE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(WindowStation)\n{\n    { L\"Full control\", WINSTA_ALL_ACCESS | STANDARD_RIGHTS_REQUIRED, TRUE, TRUE, NULL },\n    { L\"Read\", WINSTA_GENERIC_READ, TRUE, FALSE, NULL },\n    { L\"Write\", WINSTA_GENERIC_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", WINSTA_GENERIC_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Enumerate\", WINSTA_ENUMERATE, FALSE, TRUE, NULL },\n    { L\"Enumerate desktops\", WINSTA_ENUMDESKTOPS, FALSE, TRUE, NULL },\n    { L\"Read attributes\", WINSTA_READATTRIBUTES, FALSE, TRUE, NULL },\n    { L\"Read screen\", WINSTA_READSCREEN, FALSE, TRUE, NULL },\n    { L\"Access clipboard\", WINSTA_ACCESSCLIPBOARD, FALSE, TRUE, NULL },\n    { L\"Access global atoms\", WINSTA_ACCESSGLOBALATOMS, FALSE, TRUE, NULL },\n    { L\"Create desktop\", WINSTA_CREATEDESKTOP, FALSE, TRUE, NULL },\n    { L\"Write attributes\", WINSTA_WRITEATTRIBUTES, FALSE, TRUE, NULL },\n    { L\"Exit windows\", WINSTA_EXITWINDOWS, FALSE, TRUE, NULL }\n};\n\nACCESS_ENTRIES(WmiGuid)\n{\n    { L\"Full control\", WMIGUID_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Read\", WMIGUID_GENERIC_READ, TRUE, FALSE, NULL },\n    { L\"Write\", WMIGUID_GENERIC_WRITE, TRUE, FALSE, NULL },\n    { L\"Execute\", WMIGUID_GENERIC_EXECUTE, TRUE, FALSE, NULL },\n    { L\"Query information\", WMIGUID_QUERY, FALSE, TRUE, NULL },\n    { L\"Set information\", WMIGUID_SET, FALSE, TRUE, NULL },\n    { L\"Get notifications\", WMIGUID_NOTIFICATION, FALSE, TRUE, NULL },\n    { L\"Read description\", WMIGUID_READ_DESCRIPTION, FALSE, TRUE, NULL },\n    { L\"Execute\", WMIGUID_EXECUTE, FALSE, TRUE, NULL },\n    { L\"Create real-time logs\", TRACELOG_CREATE_REALTIME, FALSE, TRUE, L\"Create real-time\" },\n    { L\"Create on disk logs\", TRACELOG_CREATE_ONDISK, FALSE, TRUE, L\"Create on disk\" },\n    { L\"Enable provider GUIDs\", TRACELOG_GUID_ENABLE, FALSE, TRUE, L\"Enable GUIDs\" },\n    { L\"Access kernel logger\", TRACELOG_ACCESS_KERNEL_LOGGER, FALSE, TRUE, NULL },\n    { L\"Log events\", TRACELOG_LOG_EVENT, FALSE, TRUE, NULL },\n    { L\"Access real-time events\", TRACELOG_ACCESS_REALTIME, FALSE, TRUE, L\"Access real-time\" },\n    { L\"Register provider GUIDs\", TRACELOG_REGISTER_GUIDS, FALSE, TRUE, L\"Register GUIDs\" }\n};\n\nACCESS_ENTRIES(Rdp)\n{\n    { L\"Full control\", WTS_SECURITY_ALL_ACCESS, TRUE, TRUE, NULL },\n    { L\"Query information\", WTS_SECURITY_QUERY_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Set information\", WTS_SECURITY_SET_INFORMATION, TRUE, TRUE, NULL },\n    { L\"Reset\", WTS_SECURITY_RESET, FALSE, TRUE, NULL },\n    { L\"Virtual channels\", WTS_SECURITY_VIRTUAL_CHANNELS, FALSE, TRUE, NULL },\n    { L\"Remote control\", WTS_SECURITY_REMOTE_CONTROL, FALSE, TRUE, NULL },\n    { L\"Logon\", WTS_SECURITY_LOGON, FALSE, TRUE, NULL },\n    { L\"Logoff\", WTS_SECURITY_LOGOFF, FALSE, TRUE, NULL },\n    { L\"Message\", WTS_SECURITY_MESSAGE, FALSE, TRUE, NULL },\n    { L\"Connect\", WTS_SECURITY_CONNECT, FALSE, TRUE, NULL },\n    { L\"Disconnect\", WTS_SECURITY_DISCONNECT, FALSE, TRUE, NULL },\n    { L\"Guest access\", WTS_SECURITY_GUEST_ACCESS, FALSE, TRUE, NULL },\n    { L\"Guest access (current)\", WTS_SECURITY_CURRENT_GUEST_ACCESS, FALSE, TRUE, NULL },\n    { L\"User access\", WTS_SECURITY_USER_ACCESS, FALSE, TRUE, NULL },\n    { L\"User access (current)\", WTS_SECURITY_SET_INFORMATION | WTS_SECURITY_RESET | WTS_SECURITY_VIRTUAL_CHANNELS | WTS_SECURITY_LOGOFF | WTS_SECURITY_DISCONNECT, FALSE, TRUE, NULL }, // WTS_SECURITY_CURRENT_USER_ACCESS\n};\n\nACCESS_ENTRIES(ComAccess)\n{\n    { L\"Full control\", COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL | COM_RIGHTS_EXECUTE_REMOTE, TRUE, TRUE, NULL },\n    { L\"Execute\", COM_RIGHTS_EXECUTE, TRUE, TRUE, NULL },\n    { L\"Execute local\", COM_RIGHTS_EXECUTE_LOCAL, TRUE, TRUE, NULL },\n    { L\"Execute remote\", COM_RIGHTS_EXECUTE_REMOTE, TRUE, TRUE, NULL },\n};\n\nACCESS_ENTRIES(ComLaunch)\n{\n    { L\"Full control\", COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL | COM_RIGHTS_EXECUTE_REMOTE | COM_RIGHTS_ACTIVATE_LOCAL | COM_RIGHTS_ACTIVATE_REMOTE, TRUE, TRUE, NULL },\n    { L\"Execute\", COM_RIGHTS_EXECUTE, TRUE, TRUE, NULL },\n    { L\"Execute local\", COM_RIGHTS_EXECUTE_LOCAL, TRUE, TRUE, NULL },\n    { L\"Execute remote\", COM_RIGHTS_EXECUTE_REMOTE, TRUE, TRUE, NULL },\n    { L\"Activate local\", COM_RIGHTS_ACTIVATE_LOCAL, TRUE, TRUE, NULL },\n    { L\"Activate remote\", COM_RIGHTS_ACTIVATE_REMOTE, TRUE, TRUE, NULL },\n};\n\nstatic const PH_SPECIFIC_TYPE PhSpecificTypes[] =\n{\n    ACCESS_ENTRY(AlpcPort, TRUE),\n    ACCESS_ENTRY(DebugObject, TRUE),\n    ACCESS_ENTRY(Desktop, FALSE),\n    ACCESS_ENTRY(Directory, FALSE),\n    ACCESS_ENTRY(EtwConsumer, FALSE),\n    ACCESS_ENTRY(EtwRegistration, FALSE),\n    ACCESS_ENTRY(Event, TRUE),\n    ACCESS_ENTRY(EventPair, TRUE),\n    ACCESS_ENTRY(File, TRUE),\n    ACCESS_ENTRY(FilterConnectionPort, FALSE),\n    ACCESS_ENTRY(IoCompletion, TRUE),\n    ACCESS_ENTRY(Job, TRUE),\n    ACCESS_ENTRY(Key, FALSE),\n    ACCESS_ENTRY(KeyedEvent, FALSE),\n    ACCESS_ENTRY(LsaAccount, FALSE),\n    ACCESS_ENTRY(LsaPolicy, FALSE),\n    ACCESS_ENTRY(LsaSecret, FALSE),\n    ACCESS_ENTRY(LsaTrusted, FALSE),\n    ACCESS_ENTRY(Mutant, TRUE),\n    ACCESS_ENTRY(Partition, TRUE),\n    ACCESS_ENTRY(Process, TRUE),\n    ACCESS_ENTRY(Process60, TRUE),\n    ACCESS_ENTRY(Profile, FALSE),\n    ACCESS_ENTRY(SamAlias, FALSE),\n    ACCESS_ENTRY(SamDomain, FALSE),\n    ACCESS_ENTRY(SamGroup, FALSE),\n    ACCESS_ENTRY(SamServer, FALSE),\n    ACCESS_ENTRY(SamUser, FALSE),\n    ACCESS_ENTRY(Section, FALSE),\n    ACCESS_ENTRY(Semaphore, TRUE),\n    ACCESS_ENTRY(Service, FALSE),\n    ACCESS_ENTRY(SCManager, FALSE),\n    ACCESS_ENTRY(Session, FALSE),\n    ACCESS_ENTRY(SymbolicLink, FALSE),\n    ACCESS_ENTRY(Thread, TRUE),\n    ACCESS_ENTRY(Thread60, TRUE),\n    ACCESS_ENTRY(Timer, TRUE),\n    ACCESS_ENTRY(TmEn, FALSE),\n    ACCESS_ENTRY(TmRm, FALSE),\n    ACCESS_ENTRY(TmTm, FALSE),\n    ACCESS_ENTRY(TmTx, FALSE),\n    ACCESS_ENTRY(Token, FALSE),\n    ACCESS_ENTRY(TokenDefault, FALSE),\n    ACCESS_ENTRY(TpWorkerFactory, FALSE),\n    ACCESS_ENTRY(Type, FALSE),\n    ACCESS_ENTRY(WaitCompletionPacket, FALSE),\n    ACCESS_ENTRY(Wbem, FALSE),\n    ACCESS_ENTRY(WindowStation, FALSE),\n    ACCESS_ENTRY(WmiGuid, TRUE),\n    ACCESS_ENTRY(Rdp, FALSE),\n    ACCESS_ENTRY(ComAccess, FALSE),\n    ACCESS_ENTRY(ComLaunch, FALSE),\n};\n\n/**\n * Gets access entries for an object type.\n *\n * \\param Type The name of the object type.\n * \\param AccessEntries A variable which receives an array of access entry structures. You must free\n * the buffer with PhFree() when you no longer need it.\n * \\param NumberOfAccessEntries A variable which receives the number of access entry structures\n * returned in\n * \\a AccessEntries.\n */\nBOOLEAN PhGetAccessEntries(\n    _In_ PCWSTR Type,\n    _Out_ PPH_ACCESS_ENTRY *AccessEntries,\n    _Out_ PULONG NumberOfAccessEntries\n    )\n{\n    ULONG i;\n    PPH_SPECIFIC_TYPE specificType = NULL;\n    PPH_ACCESS_ENTRY accessEntries;\n\n    if (PhEqualStringZ(Type, L\"ALPC Port\", TRUE))\n    {\n        Type = L\"AlpcPort\";\n    }\n    else if (PhEqualStringZ(Type, L\"Port\", TRUE))\n    {\n        Type = L\"AlpcPort\";\n    }\n    else if (PhEqualStringZ(Type, L\"WaitablePort\", TRUE))\n    {\n        Type = L\"AlpcPort\";\n    }\n    else if (PhEqualStringZ(Type, L\"Process\", TRUE))\n    {\n        Type = L\"Process60\";\n    }\n    else if (PhEqualStringZ(Type, L\"Thread\", TRUE))\n    {\n        Type = L\"Thread60\";\n    }\n    else if (PhEqualStringZ(Type, L\"FileObject\", TRUE))\n    {\n        Type = L\"File\";\n    }\n    else if (PhEqualStringZ(Type, L\"Device\", TRUE))\n    {\n        Type = L\"File\";\n    }\n    else if (PhEqualStringZ(Type, L\"Driver\", TRUE))\n    {\n        Type = L\"File\";\n    }\n    else if (PhEqualStringZ(Type, L\"PowerDefault\", TRUE))\n    {\n        Type = L\"Key\";\n    }\n    else if (PhEqualStringZ(Type, L\"RdpDefault\", TRUE))\n    {\n        Type = L\"Rdp\";\n    }\n    else if (PhEqualStringZ(Type, L\"WmiDefault\", TRUE))\n    {\n        // WBEM doesn't allow StandardAccessEntries (dmex)\n        for (i = 0; i < RTL_NUMBER_OF(PhSpecificTypes); i++)\n        {\n            if (PhEqualStringZ(PhSpecificTypes[i].Type, L\"Wbem\", TRUE))\n            {\n                specificType = (PPH_SPECIFIC_TYPE)&PhSpecificTypes[i];\n                break;\n            }\n        }\n\n        if (specificType)\n        {\n            accessEntries = PhAllocate(specificType->SizeOfAccessEntries);\n            memcpy(accessEntries, specificType->AccessEntries, specificType->SizeOfAccessEntries);\n\n            *AccessEntries = accessEntries;\n            *NumberOfAccessEntries = specificType->SizeOfAccessEntries / sizeof(PH_ACCESS_ENTRY);\n            return TRUE;\n        }\n    }\n\n    // Find the specific type.\n    for (i = 0; i < sizeof(PhSpecificTypes) / sizeof(PH_SPECIFIC_TYPE); i++)\n    {\n        if (PhEqualStringZ(PhSpecificTypes[i].Type, Type, TRUE))\n        {\n            specificType = (PPH_SPECIFIC_TYPE)&PhSpecificTypes[i];\n            break;\n        }\n    }\n\n    if (specificType)\n    {\n        ULONG sizeOfEntries;\n\n        // Copy the specific access entries and append the standard access entries.\n\n        if (specificType->HasSynchronize)\n            sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries);\n        else\n            sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY);\n\n        accessEntries = PhAllocate(sizeOfEntries);\n        memcpy(accessEntries, specificType->AccessEntries, specificType->SizeOfAccessEntries);\n\n        if (specificType->HasSynchronize)\n        {\n            memcpy(\n                PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries),\n                PhStandardAccessEntries,\n                sizeof(PhStandardAccessEntries)\n                );\n        }\n        else\n        {\n            memcpy(\n                PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries),\n                &PhStandardAccessEntries[1],\n                sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY)\n                );\n        }\n\n        *AccessEntries = accessEntries;\n        *NumberOfAccessEntries = sizeOfEntries / sizeof(PH_ACCESS_ENTRY);\n    }\n    else\n    {\n        *AccessEntries = PhAllocateCopy((PVOID)PhStandardAccessEntries, sizeof(PhStandardAccessEntries));\n        *NumberOfAccessEntries = sizeof(PhStandardAccessEntries) / sizeof(PH_ACCESS_ENTRY);\n    }\n\n    return TRUE;\n}\n\nstatic int __cdecl PhpAccessEntryCompare(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    const PH_ACCESS_ENTRY* entry1 = (const PH_ACCESS_ENTRY*)elem1;\n    const PH_ACCESS_ENTRY* entry2 = (const PH_ACCESS_ENTRY*)elem2;\n\n    return uintcmp(PhCountBits(entry2->Access), PhCountBits(entry1->Access));\n}\n\n/**\n * Creates a string representation of an access mask.\n *\n * \\param Access The access mask.\n * \\param AccessEntries An array of access entry structures. You can call PhGetAccessEntries() to\n * retrieve the access entry structures for a standard object type.\n * \\param NumberOfAccessEntries The number of elements in \\a AccessEntries.\n *\n * \\return The string representation of \\a Access.\n */\nPPH_STRING PhGetAccessString(\n    _In_ ACCESS_MASK Access,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    PPH_ACCESS_ENTRY accessEntries;\n    PBOOLEAN matched;\n    ULONG i;\n    ULONG j;\n\n    PhInitializeStringBuilder(&stringBuilder, 32);\n\n    // Sort the access entries according to how many access rights they include.\n    accessEntries = PhAllocateCopy(AccessEntries, NumberOfAccessEntries * sizeof(PH_ACCESS_ENTRY));\n    qsort(accessEntries, NumberOfAccessEntries, sizeof(PH_ACCESS_ENTRY), PhpAccessEntryCompare);\n\n    matched = PhAllocate(NumberOfAccessEntries * sizeof(BOOLEAN));\n    memset(matched, 0, NumberOfAccessEntries * sizeof(BOOLEAN));\n\n    for (i = 0; i < NumberOfAccessEntries; i++)\n    {\n        // We make sure we haven't matched this access entry yet. This ensures that we won't get\n        // duplicates, e.g. FILE_GENERIC_READ includes FILE_READ_DATA, and we don't want to display\n        // both to the user.\n        if (\n            !matched[i] &&\n            ((Access & accessEntries[i].Access) == accessEntries[i].Access)\n            )\n        {\n            if (accessEntries[i].ShortName)\n                PhAppendStringBuilder2(&stringBuilder, accessEntries[i].ShortName);\n            else\n                PhAppendStringBuilder2(&stringBuilder, accessEntries[i].Name);\n\n            PhAppendStringBuilder2(&stringBuilder, L\", \");\n\n            // Disable equal or more specific entries.\n            for (j = i; j < NumberOfAccessEntries; j++)\n            {\n                if ((accessEntries[i].Access | accessEntries[j].Access) == accessEntries[i].Access)\n                    matched[j] = TRUE;\n            }\n        }\n    }\n\n    // Remove the trailing \", \".\n    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhFree(matched);\n    PhFree(accessEntries);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n"
  },
  {
    "path": "phlib/secedit.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2023\n *\n */\n\n#include <ph.h>\n#include <appresolver.h>\n#include <secedit.h>\n#include <svcsup.h>\n#include <lsasup.h>\n\n#include <aclui.h>\n#include <aclapi.h>\n\n#include <guisup.h>\n#include <hndlinfo.h>\n#include <seceditp.h>\n#include <secwmi.h>\n\nBOOLEAN PhEnableSecurityAdvancedDialog = FALSE;\nBOOLEAN PhEnableSecurityDialogThread = TRUE;\n\nstatic const ISecurityInformationVtbl PhSecurityInformation_VTable =\n{\n    PhSecurityInformation_QueryInterface,\n    PhSecurityInformation_AddRef,\n    PhSecurityInformation_Release,\n    PhSecurityInformation_GetObjectInformation,\n    PhSecurityInformation_GetSecurity,\n    PhSecurityInformation_SetSecurity,\n    PhSecurityInformation_GetAccessRights,\n    PhSecurityInformation_MapGeneric,\n    PhSecurityInformation_GetInheritTypes,\n    PhSecurityInformation_PropertySheetPageCallback\n};\n\nstatic const ISecurityInformation2Vtbl PhSecurityInformation_VTable2 =\n{\n    PhSecurityInformation2_QueryInterface,\n    PhSecurityInformation2_AddRef,\n    PhSecurityInformation2_Release,\n    PhSecurityInformation2_IsDaclCanonical,\n    PhSecurityInformation2_LookupSids\n};\n\nstatic const ISecurityInformation3Vtbl PhSecurityInformation_VTable3 =\n{\n    PhSecurityInformation3_QueryInterface,\n    PhSecurityInformation3_AddRef,\n    PhSecurityInformation3_Release,\n    PhSecurityInformation3_GetFullResourceName,\n    PhSecurityInformation3_OpenElevatedEditor\n};\n\nstatic const IDataObjectVtbl PhDataObject_VTable =\n{\n    PhSecurityDataObject_QueryInterface,\n    PhSecurityDataObject_AddRef,\n    PhSecurityDataObject_Release,\n    PhSecurityDataObject_GetData,\n    PhSecurityDataObject_GetDataHere,\n    PhSecurityDataObject_QueryGetData,\n    PhSecurityDataObject_GetCanonicalFormatEtc,\n    PhSecurityDataObject_SetData,\n    PhSecurityDataObject_EnumFormatEtc,\n    PhSecurityDataObject_DAdvise,\n    PhSecurityDataObject_DUnadvise,\n    PhSecurityDataObject_EnumDAdvise\n};\n\nstatic const ISecurityObjectTypeInfoExVtbl PhSecurityObjectTypeInfo_VTable3 =\n{\n    PhSecurityObjectTypeInfo_QueryInterface,\n    PhSecurityObjectTypeInfo_AddRef,\n    PhSecurityObjectTypeInfo_Release,\n    PhSecurityObjectTypeInfo_GetInheritSource\n};\n\nstatic const IEffectivePermissionVtbl PhEffectivePermission_VTable =\n{\n    PhEffectivePermission_QueryInterface,\n    PhEffectivePermission_AddRef,\n    PhEffectivePermission_Release,\n    PhEffectivePermission_GetEffectivePermission\n};\n\nstatic VOID PhEditSecurityAdvanced(\n    _In_ PVOID Context\n    )\n{\n    PhSecurityInformation* this = (PhSecurityInformation*)Context;\n\n    if (WindowsVersion > WINDOWS_7 && PhEnableSecurityAdvancedDialog)\n        EditSecurityAdvanced(this->WindowHandle, Context, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED));\n    else\n        EditSecurity(this->WindowHandle, Context);\n\n    PhSecurityInformation_Release(Context);\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nstatic NTSTATUS PhEditSecurityAdvancedThread(\n    _In_ PVOID Context\n    )\n{\n    PhEditSecurityAdvanced(Context);\n    return STATUS_SUCCESS;\n}\n\n/**\n * Creates a security editor page.\n *\n * \\param ObjectName The name of the object.\n * \\param ObjectType The type name of the object.\n * \\param OpenObject An optional procedure for opening the object.\n * \\param CloseObject An optional procedure for closing the object.\n * \\param Context A user-defined value to pass to the callback functions.\n */\nPVOID PhCreateSecurityPage(\n    _In_opt_ PCWSTR ObjectName,\n    _In_ PCWSTR ObjectType,\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    )\n{\n    ISecurityInformation *info;\n    PVOID page;\n\n    info = PhSecurityInformation_Create(\n        NULL,\n        ObjectName,\n        ObjectType,\n        OpenObject,\n        CloseObject,\n        NULL,\n        NULL,\n        Context,\n        TRUE\n        );\n\n    page = CreateSecurityPage(info);\n\n    PhSecurityInformation_Release(info);\n\n    return page;\n}\n\n/**\n * Displays a security editor dialog.\n *\n * \\param WindowHandle The parent window of the dialog.\n * \\param ObjectName The name of the object.\n * \\param ObjectType The type of object.\n * \\param OpenObject An optional procedure for opening the object.\n * \\param CloseObject An optional procedure for closing the object.\n * \\param Context A user-defined value to pass to the callback functions.\n */\nVOID PhEditSecurity(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR ObjectName,\n    _In_ PCWSTR ObjectType,\n    _In_opt_ PPH_OPEN_OBJECT OpenObject,\n    _In_opt_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PVOID Context\n    )\n{\n    ISecurityInformation *info;\n\n    info = PhSecurityInformation_Create(\n        WindowHandle,\n        ObjectName,\n        ObjectType,\n        OpenObject,\n        CloseObject,\n        NULL,\n        NULL,\n        Context,\n        FALSE\n        );\n\n    if (PhEnableSecurityDialogThread)\n        PhCreateThread2(PhEditSecurityAdvancedThread, info);\n    else\n        PhEditSecurityAdvanced(info);\n}\n\n/**\n * Displays a security editor dialog.\n *\n * \\param WindowHandle The parent window of the dialog.\n * \\param ObjectName The name of the object.\n * \\param ObjectType The type of object.\n * \\param OpenObject An optional procedure for opening the object.\n * \\param CloseObject An optional procedure for closing the object.\n * \\param GetObjectSecurity A callback function executed to retrieve the security descriptor of the object.\n * \\param SetObjectSecurity A callback function executed to modify the security descriptor of the object.\n * \\param Context A user-defined value to pass to the callback functions.\n */\nVOID PhEditSecurityEx(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR ObjectName,\n    _In_ PCWSTR ObjectType,\n    _In_opt_ PPH_OPEN_OBJECT OpenObject,\n    _In_opt_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_opt_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context\n    )\n{\n    ISecurityInformation *info;\n\n    info = PhSecurityInformation_Create(\n        WindowHandle,\n        ObjectName,\n        ObjectType,\n        OpenObject,\n        CloseObject,\n        GetObjectSecurity,\n        SetObjectSecurity,\n        Context,\n        FALSE\n        );\n\n    if (PhEnableSecurityDialogThread)\n        PhCreateThread2(PhEditSecurityAdvancedThread, info);\n    else\n        PhEditSecurityAdvanced(info);\n}\n\nISecurityInformation *PhSecurityInformation_Create(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR ObjectName,\n    _In_ PCWSTR ObjectType,\n    _In_ PPH_OPEN_OBJECT OpenObject,\n    _In_ PPH_CLOSE_OBJECT CloseObject,\n    _In_opt_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_opt_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context,\n    _In_ BOOLEAN IsPage\n    )\n{\n    PhSecurityInformation *info;\n    ULONG i;\n\n    info = PhAllocateZero(sizeof(PhSecurityInformation));\n    info->VTable = &PhSecurityInformation_VTable;\n    info->RefCount = 1;\n\n    info->WindowHandle = WindowHandle;\n    info->ObjectNameString = ObjectName ? PhCreateString(ObjectName) : NULL;\n    info->ObjectTypeString = PhCreateString(ObjectType);\n    info->ObjectType = PhSecurityObjectType(info->ObjectTypeString);\n    info->OpenObject = OpenObject;\n    info->CloseObject = CloseObject;\n    info->GetObjectSecurity = GetObjectSecurity;\n    info->SetObjectSecurity = SetObjectSecurity;\n    info->Context = Context;\n    info->IsPage = IsPage;\n\n    if (PhGetAccessEntries(ObjectType, &info->AccessEntriesArray, &info->NumberOfAccessEntries))\n    {\n        info->AccessEntries = PhAllocateZero(sizeof(SI_ACCESS) * info->NumberOfAccessEntries);\n\n        for (i = 0; i < info->NumberOfAccessEntries; i++)\n        {\n            info->AccessEntries[i].pszName = info->AccessEntriesArray[i].Name;\n            info->AccessEntries[i].mask = info->AccessEntriesArray[i].Access;\n\n            if (info->AccessEntriesArray[i].General)\n                SetFlag(info->AccessEntries[i].dwFlags, SI_ACCESS_GENERAL);\n            if (info->AccessEntriesArray[i].Specific)\n                SetFlag(info->AccessEntries[i].dwFlags, SI_ACCESS_SPECIFIC);\n\n            if (info->ObjectType == PH_SE_FILE_OBJECT_TYPE)\n                SetFlag(info->AccessEntries[i].dwFlags, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);\n        }\n    }\n\n    if (info->ObjectTypeString)\n    {\n        GENERIC_MAPPING genericMapping;\n\n        if (NT_SUCCESS(PhGetObjectTypeMask(&info->ObjectTypeString->sr, &genericMapping)))\n        {\n            memcpy(&info->GenericMapping, &genericMapping, sizeof(genericMapping));\n            info->HaveGenericMapping = TRUE;\n        }\n    }\n\n    if (PhIsNullOrEmptyString(info->ObjectNameString))\n    {\n        // Note: The ACUI dialog doesn't allow empty strings for the object name. (dmex)  \n        PhMoveReference(&info->ObjectNameString, PhCreateString(L\"Unknown\"));\n    }\n\n    return (ISecurityInformation *)info;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface(\n    _In_ ISecurityInformation *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    if (\n        IsEqualIID(Riid, &IID_IUnknown) ||\n        IsEqualIID(Riid, &IID_ISecurityInformation)\n        )\n    {\n        PhSecurityInformation_AddRef(This);\n        *Object = This;\n        return S_OK;\n    }\n    else if (IsEqualGUID(Riid, &IID_ISecurityInformation2))\n    {\n        if (WindowsVersion >= WINDOWS_8)\n        {\n            PhSecurityInformation2 *info;\n\n            info = PhAllocateZero(sizeof(PhSecurityInformation2));\n            info->VTable = &PhSecurityInformation_VTable2;\n            info->Context = this;\n            info->RefCount = 1;\n\n            *Object = info;\n            return S_OK;\n        }\n    }\n    else if (IsEqualGUID(Riid, &IID_ISecurityInformation3))\n    {\n        if (WindowsVersion >= WINDOWS_8)\n        {\n            PhSecurityInformation3 *info;\n\n            info = PhAllocateZero(sizeof(PhSecurityInformation3));\n            info->VTable = &PhSecurityInformation_VTable3;\n            info->Context = this;\n            info->RefCount = 1;\n\n            *Object = info;\n            return S_OK;\n        }\n    }\n    else if (IsEqualGUID(Riid, &IID_ISecurityObjectTypeInfo))\n    {\n        if (WindowsVersion >= WINDOWS_8)\n        {\n            PhSecurityObjectTypeInfo* info;\n\n            info = PhAllocateZero(sizeof(PhSecurityObjectTypeInfo));\n            info->VTable = &PhSecurityObjectTypeInfo_VTable3;\n            info->Context = this;\n            info->RefCount = 1;\n\n            *Object = info;\n            return S_OK;\n        }\n    }\n    else if (IsEqualGUID(Riid, &IID_IEffectivePermission))\n    {\n        PhEffectivePermission* info;\n\n        info = PhAllocateZero(sizeof(PhEffectivePermission));\n        info->VTable = &PhEffectivePermission_VTable;\n        info->Context = this;\n        info->RefCount = 1;\n\n        *Object = info;\n        return S_OK;\n    }\n\n    *Object = NULL;\n    return E_NOINTERFACE;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef(\n    _In_ ISecurityInformation *This\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    this->RefCount++;\n\n    return this->RefCount;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation_Release(\n    _In_ ISecurityInformation *This\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    this->RefCount--;\n\n    if (this->RefCount == 0)\n    {\n        if (this->CloseObject)\n            this->CloseObject(NULL, TRUE, this->Context);\n\n        if (this->ObjectNameString)\n            PhDereferenceObject(this->ObjectNameString);\n        if (this->ObjectTypeString)\n            PhDereferenceObject(this->ObjectTypeString);\n        if (this->AccessEntries)\n            PhFree(this->AccessEntries);\n        if (this->AccessEntriesArray)\n            PhFree(this->AccessEntriesArray);\n\n        PhFree(this);\n\n        return 0;\n    }\n\n    return this->RefCount;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation(\n    _In_ ISecurityInformation *This,\n    _Out_ PSI_OBJECT_INFO ObjectInfo\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    memset(ObjectInfo, 0, sizeof(SI_OBJECT_INFO));\n    ObjectInfo->dwFlags = SI_EDIT_ALL | SI_ADVANCED | SI_EDIT_EFFECTIVE;\n    ObjectInfo->pszObjectName = PhGetString(this->ObjectNameString);\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        SetFlag(ObjectInfo->dwFlags, SI_VIEW_ONLY | SI_EDIT_EFFECTIVE);\n    }\n\n    switch (this->ObjectType)\n    {\n    case PH_SE_FILE_OBJECT_TYPE:\n        {\n            SetFlag(ObjectInfo->dwFlags, SI_ENABLE_EDIT_ATTRIBUTE_CONDITION | SI_MAY_WRITE); // SI_RESET | SI_READONLY\n\n            // Check if the string is a filename or directory.\n            if (this->ObjectNameString && PhFindLastCharInString(this->ObjectNameString, 0, OBJ_NAME_PATH_SEPARATOR) == SIZE_MAX)\n            {\n                SetFlag(ObjectInfo->dwFlags, SI_CONTAINER); // directory\n            }\n        }\n        break;\n    case PH_SE_TOKENDEF_OBJECT_TYPE:\n        {\n            ClearFlag(ObjectInfo->dwFlags, SI_EDIT_OWNER | SI_EDIT_AUDITS);\n        }\n        break;\n    case PH_SE_POWERDEF_OBJECT_TYPE:\n        {\n            ClearFlag(ObjectInfo->dwFlags, SI_EDIT_AUDITS);\n            SetFlag(ObjectInfo->dwFlags, SI_NO_ACL_PROTECT | SI_NO_TREE_APPLY | SI_CONTAINER | SI_OWNER_READONLY);\n        }\n        break;\n    case PH_SE_RDPDEF_OBJECT_TYPE:\n        {\n            ClearFlag(ObjectInfo->dwFlags, SI_EDIT_OWNER);\n            SetFlag(ObjectInfo->dwFlags, SI_NO_ACL_PROTECT | SI_NO_TREE_APPLY);\n        }\n        break;\n    case PH_SE_WMIDEF_OBJECT_TYPE:\n        {\n            SetFlag(ObjectInfo->dwFlags, SI_CONTAINER | SI_OWNER_READONLY);\n        }\n        break;\n    }\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity(\n    _In_ ISecurityInformation *This,\n    _In_ SECURITY_INFORMATION RequestedInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ BOOL Default\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    ULONG sdLength;\n    PSECURITY_DESCRIPTOR newSd;\n\n    //if (Default)\n    //{\n    //    securityDescriptor = PhAllocateZero(SECURITY_DESCRIPTOR_MIN_LENGTH);\n    //\n    //    status = RtlCreateSecurityDescriptor(\n    //        securityDescriptor,\n    //        SECURITY_DESCRIPTOR_REVISION\n    //        );\n    //\n    //    if (!NT_SUCCESS(status))\n    //        return HRESULT_FROM_WIN32(PhNtStatusToDosError(status));\n    //\n    //    status = RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, NULL, FALSE);\n    //\n    //    if (!NT_SUCCESS(status))\n    //        return HRESULT_FROM_WIN32(PhNtStatusToDosError(status));\n    //}\n    //else\n    {\n        if (this->GetObjectSecurity)\n        {\n            PH_STD_OBJECT_SECURITY objectSecurity;\n\n            objectSecurity.ObjectContext = this;\n            objectSecurity.Context = this->Context;\n\n            status = this->GetObjectSecurity(\n                &securityDescriptor,\n                RequestedInformation,\n                &objectSecurity\n                );\n        }\n        else\n        {\n            status = PhStdGetObjectSecurity(\n                &securityDescriptor,\n                RequestedInformation,\n                this\n                );\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            // Note: The ACUI doesn't support HRESULT_FROM_NT (dmex)\n            return HRESULT_FROM_WIN32(PhNtStatusToDosError(status));\n        }\n    }\n\n    sdLength = RtlLengthSecurityDescriptor(securityDescriptor);\n    newSd = LocalAlloc(LPTR, sdLength);\n    memcpy(newSd, securityDescriptor, sdLength);\n    PhFree(securityDescriptor);\n\n    *SecurityDescriptor = newSd;\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity(\n    _In_ ISecurityInformation *This,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n    NTSTATUS status;\n\n    if (this->SetObjectSecurity)\n    {\n        PH_STD_OBJECT_SECURITY objectSecurity;\n\n        objectSecurity.ObjectContext = this;\n        objectSecurity.Context = this->Context;\n\n        status = this->SetObjectSecurity(\n            SecurityDescriptor,\n            SecurityInformation,\n            &objectSecurity\n            );\n    }\n    else\n    {\n        status = PhStdSetObjectSecurity(\n            SecurityDescriptor,\n            SecurityInformation,\n            this\n            );\n    }\n\n    // Note: The ACUI doesn't support HRESULT_FROM_NT (dmex)\n    return HRESULT_FROM_WIN32(PhNtStatusToDosError(status));\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights(\n    _In_ ISecurityInformation *This,\n    _In_ PCGUID ObjectType,\n    _In_ ULONG Flags,\n    _Out_ PSI_ACCESS *Access,\n    _Out_ PULONG Accesses,\n    _Out_ PULONG DefaultAccess\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    *Access = this->AccessEntries;\n    *Accesses = this->NumberOfAccessEntries;\n    *DefaultAccess = 0;\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric(\n    _In_ ISecurityInformation *This,\n    _In_ PCGUID ObjectType,\n    _In_ PUCHAR AceFlags,\n    _Inout_ PACCESS_MASK Mask\n    )\n{\n    PhSecurityInformation* this = (PhSecurityInformation*)This;\n\n    if (this->ObjectType == PH_SE_FILE_OBJECT_TYPE)\n    {\n        static GENERIC_MAPPING genericMappings =\n        {\n            FILE_GENERIC_READ,\n            FILE_GENERIC_WRITE,\n            FILE_GENERIC_EXECUTE,\n            FILE_ALL_ACCESS\n        };\n\n        PhMapGenericMask(Mask, &genericMappings);\n    }\n    else\n    {\n        if (this->HaveGenericMapping)\n        {\n            PhMapGenericMask(Mask, &this->GenericMapping);\n        }\n    }\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes(\n    _In_ ISecurityInformation *This,\n    _Out_ PSI_INHERIT_TYPE *InheritTypes,\n    _Out_ PULONG InheritTypesCount\n    )\n{\n\n    PhSecurityInformation* this = (PhSecurityInformation*)This;\n\n    if (this->ObjectType == PH_SE_WMIDEF_OBJECT_TYPE)\n    {\n        static const SI_INHERIT_TYPE inheritTypes[] =\n        {\n            { NULL, 0, L\"This namespace only\" },\n            { NULL, CONTAINER_INHERIT_ACE, L\"This namespace and subnamespaces\" },\n            { NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, L\"Subnamespaces only\" },\n        };\n\n        *InheritTypes = (PSI_INHERIT_TYPE)inheritTypes;\n        *InheritTypesCount = RTL_NUMBER_OF(inheritTypes);\n        return S_OK;\n    }\n    else\n    {\n        static const SI_INHERIT_TYPE inheritTypes[] =\n        {\n            { NULL, 0, L\"This folder only\" },\n            { NULL, CONTAINER_INHERIT_ACE, L\"This folder, subfolders and files\" },\n            { NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, L\"Subfolders and files only\" },\n        };\n\n        *InheritTypes = (PSI_INHERIT_TYPE)inheritTypes;\n        *InheritTypesCount = RTL_NUMBER_OF(inheritTypes);\n        return S_OK;\n    }\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback(\n    _In_ ISecurityInformation *This,\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ SI_PAGE_TYPE uPage\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    if (uMsg == PSPCB_SI_INITDIALOG)\n    {\n        // Center the security editor window.\n        if (!this->IsPage)\n            PhCenterWindow(GetParent(hwnd), GetParent(GetParent(hwnd)));\n\n        if (this->IsPage)\n            PhInitializeWindowTheme(hwnd, PhEnableThemeSupport);\n        else\n            PhInitializeWindowTheme(GetParent(hwnd), PhEnableThemeSupport);\n    }\n\n    return E_NOTIMPL;\n}\n\n// ISecurityInformation2\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation2_QueryInterface(\n    _In_ ISecurityInformation2 *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    )\n{\n    if (\n        IsEqualIID(Riid, &IID_IUnknown) ||\n        IsEqualIID(Riid, &IID_ISecurityInformation2)\n        )\n    {\n        PhSecurityInformation2_AddRef(This);\n        *Object = This;\n        return S_OK;\n    }\n\n    *Object = NULL;\n    return E_NOINTERFACE;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation2_AddRef(\n    _In_ ISecurityInformation2 *This\n    )\n{\n    PhSecurityInformation2 *this = (PhSecurityInformation2 *)This;\n\n    this->RefCount++;\n\n    return this->RefCount;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation2_Release(\n    _In_ ISecurityInformation2 *This\n    )\n{\n    PhSecurityInformation2 *this = (PhSecurityInformation2 *)This;\n\n    this->RefCount--;\n\n    if (this->RefCount == 0)\n    {\n        PhFree(this);\n        return 0;\n    }\n\n    return this->RefCount;\n}\n\nBOOL STDMETHODCALLTYPE PhSecurityInformation2_IsDaclCanonical(\n    _In_ ISecurityInformation2 *This,\n    _In_ PACL pDacl\n    )\n{\n    return TRUE;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids(\n    _In_ ISecurityInformation2 *This,\n    _In_ ULONG cSids,\n    _In_ PSID *rgpSids,\n    _Out_ LPDATAOBJECT *ppdo\n    )\n{\n    PhSecurityInformation2 *this = (PhSecurityInformation2 *)This;\n    PhSecurityIDataObject *dataObject;\n\n    dataObject = PhAllocateZero(sizeof(PhSecurityInformation));\n    dataObject->VTable = &PhDataObject_VTable;\n    dataObject->Context = this->Context;\n    dataObject->RefCount = 1;\n\n    dataObject->SidCount = cSids;\n    dataObject->Sids = rgpSids;\n    dataObject->NameCache = PhCreateList(1);\n\n    *ppdo = (LPDATAOBJECT)dataObject;\n\n    return S_OK;\n}\n\n// ISecurityInformation3\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation3_QueryInterface(\n    _In_ ISecurityInformation3 *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    )\n{\n    if (\n        IsEqualIID(Riid, &IID_IUnknown) ||\n        IsEqualIID(Riid, &IID_ISecurityInformation3)\n        )\n    {\n        PhSecurityInformation3_AddRef(This);\n        *Object = This;\n        return S_OK;\n    }\n\n    *Object = NULL;\n    return E_NOINTERFACE;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation3_AddRef(\n    _In_ ISecurityInformation3 *This\n    )\n{\n    PhSecurityInformation3 *this = (PhSecurityInformation3 *)This;\n\n    this->RefCount++;\n\n    return this->RefCount;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation3_Release(\n    _In_ ISecurityInformation3 *This\n    )\n{\n    PhSecurityInformation3 *this = (PhSecurityInformation3 *)This;\n\n    this->RefCount--;\n\n    if (this->RefCount == 0)\n    {\n        PhFree(this);\n        return 0;\n    }\n\n    return this->RefCount;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation3_GetFullResourceName(\n    _In_ ISecurityInformation3 *This,\n    _Outptr_ PWSTR *ResourceName\n    )\n{\n    PhSecurityInformation3 *this = (PhSecurityInformation3 *)This;\n\n    *ResourceName = PhGetString(this->Context->ObjectNameString);\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation3_OpenElevatedEditor(\n    _In_ ISecurityInformation3 *This,\n    _In_ HWND hWnd,\n    _In_ SI_PAGE_TYPE uPage\n    )\n{\n    PhSecurityInformation3 *this = (PhSecurityInformation3 *)This;\n\n    return E_NOTIMPL;\n}\n\n// IDataObject\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryInterface(\n    _In_ IDataObject *This,\n    _In_ REFIID Riid,\n    _COM_Outptr_ PVOID *Object\n    )\n{\n    if (\n        IsEqualIID(Riid, &IID_IUnknown) ||\n        IsEqualIID(Riid, &IID_IDataObject)\n        )\n    {\n        PhSecurityDataObject_AddRef(This);\n        *Object = This;\n        return S_OK;\n    }\n\n    *Object = NULL;\n    return E_NOINTERFACE;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityDataObject_AddRef(\n    _In_ IDataObject *This\n    )\n{\n    PhSecurityIDataObject *this = (PhSecurityIDataObject *)This;\n\n    this->RefCount++;\n\n    return this->RefCount;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityDataObject_Release(\n    _In_ IDataObject *This\n    )\n{\n    PhSecurityIDataObject *this = (PhSecurityIDataObject *)This;\n\n    this->RefCount--;\n\n    if (this->RefCount == 0)\n    {\n        PhDereferenceObjects(this->NameCache->Items, this->NameCache->Count);\n        PhDereferenceObject(this->NameCache);\n\n        PhFree(this);\n        return 0;\n    }\n\n    return this->RefCount;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *Format,\n    _Out_ STGMEDIUM *Medium\n    )\n{\n    PhSecurityIDataObject *this = (PhSecurityIDataObject *)This;\n    PSID_INFO_LIST sidInfoList;\n\n    sidInfoList = (PSID_INFO_LIST)GlobalAlloc(GMEM_ZEROINIT, sizeof(SID_INFO_LIST) + (sizeof(SID_INFO) * this->SidCount));\n\n    if (!sidInfoList)\n    {\n        Medium = NULL;\n        return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);\n    }\n\n    sidInfoList->cItems = this->SidCount;\n\n    for (ULONG i = 0; i < this->SidCount; i++)\n    {\n        SID_INFO sidInfo;\n        PPH_STRING sidString;\n        SID_NAME_USE sidNameUse;\n\n        memset(&sidInfo, 0, sizeof(SID_INFO));\n        sidInfo.pSid = this->Sids[i];\n\n        if (sidString = PhGetSidFullName(sidInfo.pSid, FALSE, &sidNameUse))\n        {\n            switch (sidNameUse)\n            {\n            case SidTypeUser:\n            case SidTypeLogonSession:\n            case SidTypeDeletedAccount:\n                sidInfo.pwzClass = L\"User\";\n                break;\n            case SidTypeAlias:\n            case SidTypeGroup:\n            case SidTypeWellKnownGroup:\n                sidInfo.pwzClass = L\"Group\";\n                break;\n            case SidTypeDomain:\n            case SidTypeComputer:\n                sidInfo.pwzClass = L\"Computer\";\n                break;\n            }\n\n            sidInfo.pwzCommonName = PhGetString(sidString);\n            PhAddItemList(this->NameCache, sidString);\n        }\n        else if (sidString = PhGetAppContainerPackageName(sidInfo.pSid))\n        {\n            PhMoveReference(&sidString, PhConcatStringRefZ(&sidString->sr, L\" (APP_PACKAGE)\"));\n            sidInfo.pwzCommonName = PhGetString(sidString);\n            PhAddItemList(this->NameCache, sidString);\n        }\n        else if (sidString = PhGetAppContainerName(sidInfo.pSid))\n        {\n            PhMoveReference(&sidString, PhConcatStringRefZ(&sidString->sr, L\" (APP_CONTAINER)\"));\n            sidInfo.pwzCommonName = PhGetString(sidString);\n            PhAddItemList(this->NameCache, sidString);\n        }\n        else if (sidString = PhGetCapabilitySidName(sidInfo.pSid))\n        {\n            PhMoveReference(&sidString, PhConcatStringRefZ(&sidString->sr, L\" (APP_CAPABILITY)\"));\n            sidInfo.pwzCommonName = PhGetString(sidString);\n            PhAddItemList(this->NameCache, sidString);\n        }\n        else\n        {\n            if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(sidInfo.pSid), &(SID_IDENTIFIER_AUTHORITY)SECURITY_NT_AUTHORITY))\n            {\n                ULONG subAuthority = *PhSubAuthoritySid(sidInfo.pSid, 0);\n\n                switch (subAuthority)\n                {\n                case SECURITY_UMFD_BASE_RID:\n                    {\n                        PhMoveReference(&sidString, PhCreateString(L\"Font Driver Host\\\\UMFD\"));\n                        sidInfo.pwzCommonName = PhGetString(sidString);\n                        PhAddItemList(this->NameCache, sidString);\n                    }\n                    break;\n                }\n            }\n            else if (PhEqualIdentifierAuthoritySid(PhIdentifierAuthoritySid(sidInfo.pSid), PhIdentifierAuthoritySid(PhSeCloudActiveDirectorySid())))\n            {\n                ULONG subAuthority = *PhSubAuthoritySid(sidInfo.pSid, 0);\n\n                if (subAuthority == 1)\n                {\n                    PhMoveReference(&sidString, PhGetAzureDirectoryObjectSid(sidInfo.pSid));\n                    sidInfo.pwzCommonName = PhGetString(sidString);\n                    PhAddItemList(this->NameCache, sidString);\n                }\n            }\n        }\n\n        sidInfoList->aSidInfo[i] = sidInfo;\n    }\n\n    Medium->tymed = TYMED_HGLOBAL;\n    Medium->hGlobal = (HGLOBAL)sidInfoList;\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetDataHere(\n    _In_ IDataObject *This,\n    _In_  FORMATETC *pformatetc,\n    _Inout_ STGMEDIUM *pmedium\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryGetData(\n    _In_ IDataObject *This,\n    _In_opt_ FORMATETC *pformatetc\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetCanonicalFormatEtc(\n    _In_ IDataObject * This,\n    _In_opt_ FORMATETC *pformatectIn,\n    _Out_ FORMATETC *pformatetcOut\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_SetData(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _In_ STGMEDIUM *pmedium,\n    _In_ BOOL fRelease\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumFormatEtc(\n    _In_ IDataObject *This,\n    _In_ ULONG dwDirection,\n    _Out_opt_ IEnumFORMATETC **ppenumFormatEtc\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_DAdvise(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _In_ ULONG advf,\n    _In_opt_ IAdviseSink *pAdvSink,\n    _Out_ ULONG *pdwConnection\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_DUnadvise(\n    _In_ IDataObject *This,\n    _In_ ULONG dwConnection\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumDAdvise(\n    _In_ IDataObject *This,\n    _Out_opt_ IEnumSTATDATA **ppenumAdvise\n    )\n{\n    return E_NOTIMPL;\n}\n\n// ISecurityObjectTypeInfo\n\nHRESULT STDMETHODCALLTYPE PhSecurityObjectTypeInfo_QueryInterface(\n    _In_ ISecurityObjectTypeInfoEx* This,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Object\n    )\n{\n    if (\n        IsEqualIID(Riid, &IID_IUnknown) ||\n        IsEqualIID(Riid, &IID_ISecurityObjectTypeInfo)\n        )\n    {\n        PhSecurityObjectTypeInfo_AddRef(This);\n        *Object = This;\n        return S_OK;\n    }\n\n    *Object = NULL;\n    return E_NOINTERFACE;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityObjectTypeInfo_AddRef(\n    _In_ ISecurityObjectTypeInfoEx* This\n    )\n{\n    PhSecurityObjectTypeInfo* this = (PhSecurityObjectTypeInfo*)This;\n\n    this->RefCount++;\n\n    return this->RefCount;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityObjectTypeInfo_Release(\n    _In_ ISecurityObjectTypeInfoEx* This\n    )\n{\n    PhSecurityObjectTypeInfo* this = (PhSecurityObjectTypeInfo*)This;\n\n    this->RefCount--;\n\n    if (this->RefCount == 0)\n    {\n        PhFree(this);\n        return 0;\n    }\n\n    return this->RefCount;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityObjectTypeInfo_GetInheritSource(\n    _In_ ISecurityObjectTypeInfoEx* This,\n    _In_ SECURITY_INFORMATION SecurityInfo,\n    _In_ PACL Acl,\n    _Out_ PINHERITED_FROM* InheritArray\n    )\n{\n    static GENERIC_MAPPING genericMappings =\n    {\n        FILE_GENERIC_READ,\n        FILE_GENERIC_WRITE,\n        FILE_GENERIC_EXECUTE,\n        FILE_ALL_ACCESS\n    };\n    PhSecurityObjectTypeInfo* this = (PhSecurityObjectTypeInfo*)This;\n    PINHERITED_FROM result;\n    ULONG status;\n\n    if (PhIsNullOrEmptyString(this->Context->ObjectNameString))\n        return HRESULT_FROM_WIN32(ERROR_INVALID_STATE);\n\n    if (this->Context->ObjectType != PH_SE_FILE_OBJECT_TYPE)\n        return HRESULT_FROM_WIN32(ERROR_INVALID_STATE);\n\n    if (!(result = (PINHERITED_FROM)LocalAlloc(LPTR, ((ULONGLONG)Acl->AceCount + 1) * sizeof(INHERITED_FROM))))\n        return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);\n\n    if ((status = GetInheritanceSource(\n        PhGetString(this->Context->ObjectNameString),\n        SE_FILE_OBJECT,\n        SecurityInfo,\n        TRUE, // Container\n        NULL,\n        0,\n        Acl,\n        NULL,\n        &genericMappings,\n        result\n        )) == ERROR_SUCCESS)\n    {\n        *InheritArray = result;\n    }\n    else\n    {\n        LocalFree(result);\n    }\n\n    return HRESULT_FROM_WIN32(status);\n}\n\n// IEffectivePermission\n\nHRESULT STDMETHODCALLTYPE PhEffectivePermission_QueryInterface(\n    _In_ IEffectivePermission* This,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Object\n    )\n{\n    if (\n        IsEqualIID(Riid, &IID_IUnknown) ||\n        IsEqualIID(Riid, &IID_IEffectivePermission)\n        )\n    {\n        PhEffectivePermission_AddRef(This);\n        *Object = This;\n        return S_OK;\n    }\n\n    *Object = NULL;\n    return E_NOINTERFACE;\n}\n\nULONG STDMETHODCALLTYPE PhEffectivePermission_AddRef(\n    _In_ IEffectivePermission* This\n    )\n{\n    PhEffectivePermission* this = (PhEffectivePermission*)This;\n\n    this->RefCount++;\n\n    return this->RefCount;\n}\n\nULONG STDMETHODCALLTYPE PhEffectivePermission_Release(\n    _In_ IEffectivePermission* This\n    )\n{\n    PhEffectivePermission* this = (PhEffectivePermission*)This;\n\n    this->RefCount--;\n\n    if (this->RefCount == 0)\n    {\n        PhFree(this);\n        return 0;\n    }\n\n    return this->RefCount;\n}\n\nHRESULT STDMETHODCALLTYPE PhEffectivePermission_GetEffectivePermission(\n    _In_ IEffectivePermission* This,\n    _In_ LPCGUID GuidObjectType,\n    _In_ PSID UserSid,\n    _In_ LPCWSTR ServerName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ POBJECT_TYPE_LIST* ObjectTypeList,\n    _Out_ PULONG ObjectTypeListLength,\n    _Out_ PACCESS_MASK* GrantedAccessList,\n    _Out_ PULONG GrantedAccessListLength\n    )\n{\n    static OBJECT_TYPE_LIST defaultObjectTypeList[1] = { 0 };\n    NTSTATUS status;\n    BOOLEAN present = FALSE;\n    BOOLEAN defaulted = FALSE;\n    PACL dacl = NULL;\n    PACCESS_MASK accessRights;\n    TRUSTEE trustee;\n\n    status = PhGetDaclSecurityDescriptorNotNull(\n        SecurityDescriptor,\n        &present,\n        &defaulted,\n        &dacl\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (dacl && (accessRights = (PACCESS_MASK)LocalAlloc(LPTR, sizeof(PACCESS_MASK) + sizeof(ACCESS_MASK))))\n        {\n            PhBuildTrusteeWithSid(&trustee, UserSid);\n\n            status = GetEffectiveRightsFromAcl(dacl, &trustee, accessRights);\n\n            if (status == ERROR_SUCCESS)\n            {\n                *ObjectTypeList = defaultObjectTypeList;\n                *ObjectTypeListLength = 1;\n                *GrantedAccessList = accessRights;\n                *GrantedAccessListLength = 1;\n                return S_OK;\n            }\n            else\n            {\n                LocalFree(accessRights);\n                return HRESULT_FROM_WIN32(status);\n            }\n        }\n\n        return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);\n    }\n\n    return HRESULT_FROM_WIN32(PhNtStatusToDosError(status));\n}\n\nNTSTATUS PhpGetObjectSecurityWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    ULONG bufferSize;\n    PVOID buffer;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n    // This is required (especially for File objects) because some drivers don't seem to handle\n    // QuerySecurity properly. (wj32)\n    memset(buffer, 0, bufferSize);\n\n    status = PhCallNtQuerySecurityObjectWithTimeout(\n        Handle,\n        SecurityInformation,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n        memset(buffer, 0, bufferSize);\n\n        status = PhCallNtQuerySecurityObjectWithTimeout(\n            Handle,\n            SecurityInformation,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer;\n\n    return status;\n}\n\n/**\n * Retrieves the security descriptor of an object.\n *\n * \\param SecurityDescriptor A variable which receives a pointer to the security descriptor of the\n * object. The security descriptor must be freed using PhFree() when no longer needed.\n * \\param SecurityInformation The security information to retrieve.\n * \\param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object.\n *\n * \\remarks This function may be used for the \\a GetObjectSecurity callback in\n * PhCreateSecurityPage() or PhEditSecurity().\n */\nNTSTATUS PhStdGetObjectSecurity(\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PVOID Context\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)Context;\n    NTSTATUS status;\n    HANDLE handle;\n\n    status = this->OpenObject(\n        &handle,\n        PhGetAccessForGetSecurity(SecurityInformation),\n        this->Context\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    switch (this->ObjectType)\n    {\n    case PH_SE_FILE_OBJECT_TYPE:\n        status = PhpGetObjectSecurityWithTimeout(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_SERVICE_OBJECT_TYPE:\n        status = PhGetServiceObjectSecurity(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_LSA_OBJECT_TYPE:\n        status = PhLsaQuerySecurityObject(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_SAM_OBJECT_TYPE:\n        status = PhSamQuerySecurityObject(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_TOKENDEF_OBJECT_TYPE:\n        status = PhGetSeObjectSecurityTokenDefault(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_POWERDEF_OBJECT_TYPE:\n        status = PhGetSeObjectSecurityPowerGuid(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_RDPDEF_OBJECT_TYPE:\n        status = PhpGetRemoteDesktopSecurityDescriptor(SecurityDescriptor);\n        break;\n    case PH_SE_WMIDEF_OBJECT_TYPE:\n        status = PhGetWmiNamespaceSecurityDescriptor(SecurityDescriptor);\n        break;\n    case PH_SE_COMACCESSDEF_OBJECT_TYPE:\n    case PH_SE_COMLAUNCHDEF_OBJECT_TYPE:\n        status = PhGetComSecurityDescriptor((COMSD)handle, SecurityDescriptor);\n        break;\n    case PH_SE_DEFAULT_OBJECT_TYPE:\n    default:\n        status = PhGetObjectSecurity(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    }\n\n    if (this->CloseObject)\n    {\n        this->CloseObject(\n            handle,\n            FALSE,\n            this->Context\n            );\n    }\n\n    return status;\n}\n\n/**\n * Modifies the security descriptor of an object.\n *\n * \\param SecurityDescriptor A security descriptor containing security information to set.\n * \\param SecurityInformation The security information to retrieve.\n * \\param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object.\n *\n * \\remarks This function may be used for the \\a SetObjectSecurity callback in\n * PhCreateSecurityPage() or PhEditSecurity().\n */\nNTSTATUS PhStdSetObjectSecurity(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PVOID Context\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)Context;\n    NTSTATUS status;\n    HANDLE handle;\n\n    status = this->OpenObject(\n        &handle,\n        PhGetAccessForSetSecurity(SecurityInformation),\n        this->Context\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    switch (this->ObjectType)\n    {\n    case PH_SE_FILE_OBJECT_TYPE:\n        status = PhSetObjectSecurity(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_SERVICE_OBJECT_TYPE:\n        status = PhSetServiceObjectSecurity(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_LSA_OBJECT_TYPE:\n        status = LsaSetSecurityObject(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_SAM_OBJECT_TYPE:\n        status = STATUS_NOT_SUPPORTED; // SamSetSecurityObject(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_TOKENDEF_OBJECT_TYPE:\n        status = PhSetSeObjectSecurityTokenDefault(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_POWERDEF_OBJECT_TYPE:\n        status = PhSetSeObjectSecurityPowerGuid(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_RDPDEF_OBJECT_TYPE:\n        status = PhpSetRemoteDesktopSecurityDescriptor(SecurityDescriptor);\n        break;\n    case PH_SE_WMIDEF_OBJECT_TYPE:\n        status = PhSetWmiNamespaceSecurityDescriptor(SecurityDescriptor);\n        break;\n    case PH_SE_COMACCESSDEF_OBJECT_TYPE:\n    case PH_SE_COMLAUNCHDEF_OBJECT_TYPE:\n        status = PhSetComSecurityDescriptor((COMSD)handle, SecurityInformation, SecurityDescriptor);\n        break;\n    case PH_SE_DEFAULT_OBJECT_TYPE:\n    default:\n        status = PhSetObjectSecurity(handle, SecurityInformation, SecurityDescriptor);\n        break;\n    }\n\n    if (this->CloseObject)\n    {\n        this->CloseObject(\n            handle,\n            FALSE,\n            this->Context\n            );\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetSeObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectType,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    )\n{\n    ULONG win32Result;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n\n    win32Result = GetSecurityInfo(\n        Handle,\n        ObjectType,\n        SecurityInformation,\n        NULL,\n        NULL,\n        NULL,\n        NULL,\n        &securityDescriptor\n        );\n\n    if (win32Result != ERROR_SUCCESS)\n    {\n        *SecurityDescriptor = NULL;\n        return PhDosErrorToNtStatus(win32Result);\n    }\n\n    *SecurityDescriptor = PhAllocateCopy(securityDescriptor, RtlLengthSecurityDescriptor(securityDescriptor));\n    LocalFree(securityDescriptor);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSetSeObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectType,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    ULONG win32Result;\n    SECURITY_INFORMATION securityInformation = 0;\n    BOOLEAN present = FALSE;\n    BOOLEAN defaulted = FALSE;\n    PSID owner = NULL;\n    PSID group = NULL;\n    PACL dacl = NULL;\n    PACL sacl = NULL;\n\n    if (FlagOn(SecurityInformation, OWNER_SECURITY_INFORMATION))\n    {\n        if (NT_SUCCESS(PhGetOwnerSecurityDescriptor(SecurityDescriptor, &owner, &defaulted)))\n            SetFlag(securityInformation, OWNER_SECURITY_INFORMATION);\n    }\n\n    if (FlagOn(SecurityInformation, GROUP_SECURITY_INFORMATION))\n    {\n        if (NT_SUCCESS(PhGetGroupSecurityDescriptor(SecurityDescriptor, &group, &defaulted)))\n            SetFlag(securityInformation, GROUP_SECURITY_INFORMATION);\n    }\n\n    if (FlagOn(SecurityInformation, DACL_SECURITY_INFORMATION))\n    {\n        if (NT_SUCCESS(PhGetDaclSecurityDescriptor(SecurityDescriptor, &present, &dacl, &defaulted)) && present)\n            SetFlag(securityInformation, DACL_SECURITY_INFORMATION);\n    }\n\n    if (FlagOn(SecurityInformation, SACL_SECURITY_INFORMATION))\n    {\n        if (NT_SUCCESS(PhGetSaclSecurityDescriptor(SecurityDescriptor, &present, &sacl, &defaulted)) && present)\n            SetFlag(securityInformation, SACL_SECURITY_INFORMATION);\n    }\n\n    if (ObjectType == SE_FILE_OBJECT) // probably works with other types but haven't checked (dmex)\n    {\n        SECURITY_DESCRIPTOR_CONTROL control;\n        ULONG revision;\n\n        if (NT_SUCCESS(PhGetControlSecurityDescriptor(SecurityDescriptor, &control, &revision)))\n        {\n            if (FlagOn(SecurityInformation, DACL_SECURITY_INFORMATION))\n            {\n                if (FlagOn(control, SE_DACL_PROTECTED))\n                    SetFlag(securityInformation, PROTECTED_DACL_SECURITY_INFORMATION);\n                else\n                    SetFlag(securityInformation, UNPROTECTED_DACL_SECURITY_INFORMATION);\n            }\n\n            if (FlagOn(SecurityInformation, SACL_SECURITY_INFORMATION))\n            {\n                if (FlagOn(control, SE_SACL_PROTECTED))\n                    SetFlag(securityInformation, PROTECTED_SACL_SECURITY_INFORMATION);\n                else\n                    SetFlag(securityInformation, UNPROTECTED_SACL_SECURITY_INFORMATION);\n            }\n        }\n    }\n\n    win32Result = SetSecurityInfo(\n        Handle,\n        ObjectType,\n        securityInformation, // SecurityInformation\n        owner,\n        group,\n        dacl,\n        sacl\n        );\n\n    if (win32Result != ERROR_SUCCESS)\n        return PhDosErrorToNtStatus(win32Result);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhLsaQuerySecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n\n    status = LsaQuerySecurityObject(\n        Handle,\n        SecurityInformation,\n        &securityDescriptor\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *SecurityDescriptor = PhAllocateCopy(\n            securityDescriptor,\n            RtlLengthSecurityDescriptor(securityDescriptor)\n            );\n        LsaFreeMemory(securityDescriptor);\n    }\n\n    return status;\n}\n\nNTSTATUS PhSamQuerySecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    //NTSTATUS status;\n    //PSECURITY_DESCRIPTOR securityDescriptor;\n    //\n    //status = SamQuerySecurityObject(\n    //    Handle,\n    //    SecurityInformation,\n    //    &securityDescriptor\n    //    );\n    //\n    //if (NT_SUCCESS(status))\n    //{\n    //    *SecurityDescriptor = PhAllocateCopy(\n    //        securityDescriptor,\n    //        RtlLengthSecurityDescriptor(securityDescriptor)\n    //        );\n    //    SamFreeMemory(securityDescriptor);\n    //}\n    //\n    //return status;\n    return STATUS_NOT_SUPPORTED;\n}\n\nNTSTATUS PhGetSeObjectSecurityTokenDefault(\n    _In_ HANDLE TokenHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    PTOKEN_DEFAULT_DACL defaultDacl;\n\n    status = PhGetTokenDefaultDacl(\n        TokenHandle,\n        &defaultDacl\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        ULONG allocationLength;\n        ULONG allocationLengthRelative = 0;\n        PSECURITY_DESCRIPTOR securityDescriptor;\n        PSECURITY_DESCRIPTOR securityRelative = NULL;\n\n        allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + defaultDacl->DefaultDacl->AclSize;\n\n        securityDescriptor = PhAllocateZero(allocationLength);\n        status = PhCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhSetDaclSecurityDescriptor(securityDescriptor, TRUE, defaultDacl->DefaultDacl, FALSE);\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        assert(allocationLength == RtlLengthSecurityDescriptor(securityDescriptor));\n\n        status = RtlAbsoluteToSelfRelativeSD(securityDescriptor, NULL, &allocationLengthRelative);\n        if (status != STATUS_BUFFER_TOO_SMALL)\n            goto CleanupExit;\n\n        securityRelative = PhAllocateZero(allocationLengthRelative);\n        status = RtlAbsoluteToSelfRelativeSD(securityDescriptor, securityRelative, &allocationLengthRelative);\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        assert(allocationLengthRelative == RtlLengthSecurityDescriptor(securityRelative));\n\nCleanupExit:\n        *SecurityDescriptor = securityRelative;\n        assert(RtlValidSecurityDescriptor(securityDescriptor));\n        PhFree(securityDescriptor);\n        PhFree(defaultDacl);\n    }\n\n    return status;\n}\n\nNTSTATUS PhSetSeObjectSecurityTokenDefault(\n    _In_ HANDLE TokenHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    BOOLEAN present = FALSE;\n    BOOLEAN defaulted = FALSE;\n    PACL dacl = NULL;\n\n    status = PhGetDaclSecurityDescriptorNotNull(\n        SecurityDescriptor,\n        &present,\n        &defaulted,\n        &dacl\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        TOKEN_DEFAULT_DACL defaultDacl;\n\n        defaultDacl.DefaultDacl = dacl;\n\n        status = NtSetInformationToken(\n            TokenHandle,\n            TokenDefaultDacl,\n            &defaultDacl,\n            sizeof(TOKEN_DEFAULT_DACL)\n            );\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetSeObjectSecurityPowerGuid(\n    _In_ HANDLE Object,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    PPH_STRING powerPolicySddl;\n\n    status = PhpGetPowerPolicySecurityDescriptor(&powerPolicySddl);\n\n    if (NT_SUCCESS(status))\n    {\n        if (securityDescriptor = PhGetSecurityDescriptorFromString(PhGetString(powerPolicySddl)))\n        {\n            if (FlagOn(SecurityInformation, OWNER_SECURITY_INFORMATION))\n            {\n                PhSetOwnerSecurityDescriptor(securityDescriptor, PhSeAdministratorsSid(), TRUE);\n            }\n\n            if (FlagOn(SecurityInformation, GROUP_SECURITY_INFORMATION))\n            {\n                PhSetGroupSecurityDescriptor(securityDescriptor, PhSeAdministratorsSid(), TRUE);\n            }\n\n            *SecurityDescriptor = PhAllocateCopy(\n                securityDescriptor,\n                RtlLengthSecurityDescriptor(securityDescriptor)\n                );\n            PhFree(securityDescriptor);\n        }\n        else\n        {\n            status = STATUS_INVALID_SECURITY_DESCR;\n        }\n\n        PhDereferenceObject(powerPolicySddl);\n    }\n\n    return status;\n}\n\nNTSTATUS PhSetSeObjectSecurityPowerGuid(\n    _In_ HANDLE Object,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    PPH_STRING powerPolicySddl;\n\n    // kludge the descriptor into the correct SDDL format required by powercfg (dmex)\n    // 1) The owner must always be the built-in domain administrator.\n    // 2) The group must always be NT AUTHORITY\\SYSTEM.\n    // 3) Remove the INHERIT_REQ flag (not required but makes the sddl consistent with powercfg).\n\n    PhSetOwnerSecurityDescriptor(SecurityDescriptor, PhSeAdministratorsSid(), TRUE);\n    PhSetGroupSecurityDescriptor(SecurityDescriptor, (PSID)&PhSeLocalSystemSid, TRUE);\n    PhSetControlSecurityDescriptor(SecurityDescriptor, SE_DACL_PROTECTED | SE_DACL_AUTO_INHERIT_REQ, SE_DACL_PROTECTED);\n\n    if (NT_SUCCESS(status = PhGetSecurityDescriptorAsString(\n        SecurityDescriptor,\n        OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |\n        DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,\n        &powerPolicySddl\n        )))\n    {\n        status = PhpSetPowerPolicySecurityDescriptor(powerPolicySddl);\n        PhDereferenceObject(powerPolicySddl);\n    }\n\n    return status;\n}\n\nPH_SE_OBJECT_TYPE PhSecurityObjectType(\n    _In_ PPH_STRING ObjectType\n    )\n{\n    if (PhEqualString2(ObjectType, L\"File\", TRUE))\n        return PH_SE_FILE_OBJECT_TYPE;\n    if (PhEqualString2(ObjectType, L\"FileObject\", TRUE))\n        return PH_SE_FILE_OBJECT_TYPE;\n\n    if (PhEqualString2(ObjectType, L\"Service\", TRUE))\n        return PH_SE_SERVICE_OBJECT_TYPE;\n    if (PhEqualString2(ObjectType, L\"SCManager\", TRUE))\n        return PH_SE_SERVICE_OBJECT_TYPE;\n\n    if (PhEqualString2(ObjectType, L\"TokenDefault\", TRUE))\n        return PH_SE_TOKENDEF_OBJECT_TYPE;\n    if (PhEqualString2(ObjectType, L\"PowerDefault\", TRUE))\n        return PH_SE_POWERDEF_OBJECT_TYPE;\n    if (PhEqualString2(ObjectType, L\"RdpDefault\", TRUE))\n        return PH_SE_RDPDEF_OBJECT_TYPE;\n    if (PhEqualString2(ObjectType, L\"WmiDefault\", TRUE))\n        return PH_SE_WMIDEF_OBJECT_TYPE;\n    if (PhEqualString2(ObjectType, L\"ComAccess\", TRUE))\n        return PH_SE_COMACCESSDEF_OBJECT_TYPE;\n    if (PhEqualString2(ObjectType, L\"ComLaunch\", TRUE))\n        return PH_SE_COMLAUNCHDEF_OBJECT_TYPE;\n\n    if (\n        PhEqualString2(ObjectType, L\"LsaAccount\", TRUE) ||\n        PhEqualString2(ObjectType, L\"LsaPolicy\", TRUE) ||\n        PhEqualString2(ObjectType, L\"LsaSecret\", TRUE) ||\n        PhEqualString2(ObjectType, L\"LsaTrusted\", TRUE)\n        )\n    {\n        return PH_SE_LSA_OBJECT_TYPE;\n    }\n\n    if (\n        PhEqualString2(ObjectType, L\"SamAlias\", TRUE) ||\n        PhEqualString2(ObjectType, L\"SamDomain\", TRUE) ||\n        PhEqualString2(ObjectType, L\"SamGroup\", TRUE) ||\n        PhEqualString2(ObjectType, L\"SamServer\", TRUE) ||\n        PhEqualString2(ObjectType, L\"SamUser\", TRUE)\n        )\n    {\n        return PH_SE_SAM_OBJECT_TYPE;\n    }\n\n    return PH_SE_DEFAULT_OBJECT_TYPE;\n}\n"
  },
  {
    "path": "phlib/secwmi.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2016-2024\n *\n */\n\n#include <ph.h>\n#include <guisup.h>\n#include <mapldr.h>\n#include <wbemidl.h>\n#include <wtsapi32.h>\n#include <powrprof.h>\n#include <powersetting.h>\n#include <secwmi.h>\n\nDEFINE_GUID(CLSID_WbemLocator, 0x4590f811, 0x1d3a, 0x11d0, 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24);\nDEFINE_GUID(IID_IWbemLocator, 0xdc12a687, 0x737f, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24);\n\ntypeof(&PowerGetActiveScheme) PowerGetActiveScheme_I = NULL;\ntypeof(&PowerSetActiveScheme) PowerSetActiveScheme_I = NULL;\ntypeof(&PowerRestoreDefaultPowerSchemes) PowerRestoreDefaultPowerSchemes_I = NULL;\n_PowerReadSecurityDescriptor PowerReadSecurityDescriptor_I = NULL;\n_PowerWriteSecurityDescriptor PowerWriteSecurityDescriptor_I = NULL;\ntypeof(&WTSGetListenerSecurityW) WTSGetListenerSecurity_I = NULL;\ntypeof(&WTSSetListenerSecurityW) WTSSetListenerSecurity_I = NULL;\n\nHRESULT PhGetWbemLocatorClass(\n    _Out_ struct IWbemLocator** WbemLocatorClass\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID imageBaseAddress = NULL;\n    HRESULT status;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PPH_STRING systemFileName;\n\n        if (systemFileName = PhGetSystemDirectoryWin32Z(L\"\\\\wbem\\\\wbemprox.dll\"))\n        {\n            imageBaseAddress = PhLoadLibrary(PhGetString(systemFileName));\n            PhDereferenceObject(systemFileName);\n        }\n\n        {\n            typedef void (WINAPI* _SetOaNoCache)(void);\n            _SetOaNoCache SetOaNoCache_I;\n\n            if (SetOaNoCache_I = PhGetModuleProcAddress(L\"oleaut32.dll\", \"SetOaNoCache\"))\n            {\n                SetOaNoCache_I();\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    status = PhGetClassObjectDllBase(\n        imageBaseAddress,\n        &CLSID_WbemLocator,\n        &IID_IWbemLocator,\n        WbemLocatorClass\n        );\n\n    return status;\n}\n\nPVOID PhpInitializePowerPolicyApi(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID imageBaseAddress = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        imageBaseAddress = PhLoadLibrary(L\"powrprof.dll\");\n        PhEndInitOnce(&initOnce);\n    }\n\n    return imageBaseAddress;\n}\n\nPVOID PhpInitializeRemoteDesktopServiceApi(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID imageBaseAddress = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        imageBaseAddress = PhLoadLibrary(L\"wtsapi32.dll\");\n        PhEndInitOnce(&initOnce);\n    }\n\n    return imageBaseAddress;\n}\n\nHRESULT PhCoSetProxyBlanket(\n    _In_ IUnknown* InterfacePtr\n    )\n{\n    HRESULT status;\n    IClientSecurity* clientSecurity;\n\n    status = IUnknown_QueryInterface(\n        InterfacePtr,\n        &IID_IClientSecurity,\n        &clientSecurity\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IClientSecurity_SetBlanket(\n            clientSecurity,\n            InterfacePtr,\n            RPC_C_AUTHN_WINNT,\n            RPC_C_AUTHZ_NONE,\n            NULL,\n            RPC_C_AUTHN_LEVEL_PKT_PRIVACY,\n            RPC_C_IMP_LEVEL_IMPERSONATE,\n            NULL,\n            EOAC_NONE\n            );\n        IClientSecurity_Release(InterfacePtr);\n    }\n\n    return status;\n}\n\nHRESULT PhGetWbemClassObjectDependency(\n    _Out_ PVOID* WbemClassObjectDependency,\n    _In_ IWbemClassObject* WbemClassObject,\n    _In_ IWbemServices* WbemServices,\n    _In_ PCWSTR Name\n    )\n{\n    HRESULT status;\n    IWbemClassObject* dependency;\n    VARIANT variant = { 0 };\n\n    status = IWbemClassObject_Get(\n        WbemClassObject,\n        Name,\n        0,\n        &variant,\n        NULL,\n        NULL\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IWbemServices_GetObject(\n            WbemServices,\n            V_BSTR(&variant),\n            WBEM_FLAG_RETURN_WBEM_COMPLETE,\n            NULL,\n            &dependency,\n            NULL\n            );\n\n        if (SUCCEEDED(status))\n        {\n            *WbemClassObjectDependency = dependency;\n        }\n\n        SysFreeString(V_BSTR(&variant));\n    }\n\n    return status;\n}\n\nPPH_STRING PhGetWbemClassObjectString(\n    _In_ PVOID WbemClassObject,\n    _In_ PCWSTR Name\n    )\n{\n    PPH_STRING string = NULL;\n    VARIANT variant = { 0 };\n\n    if (SUCCEEDED(IWbemClassObject_Get((IWbemClassObject*)WbemClassObject, Name, 0, &variant, NULL, 0)))\n    {\n        if (V_BSTR(&variant)) // Can be null (dmex)\n        {\n            string = PhCreateString(V_BSTR(&variant));\n        }\n\n        VariantClear(&variant);\n    }\n\n    return string;\n}\n\nULONG64 PhGetWbemClassObjectUlong64(\n    _In_ PVOID WbemClassObject,\n    _In_ PCWSTR Name\n    )\n{\n    VARIANT variant;\n\n    RtlZeroMemory(&variant, sizeof(VARIANT));\n\n    if (SUCCEEDED(IWbemClassObject_Get((IWbemClassObject*)WbemClassObject, Name, 0, &variant, NULL, 0)))\n    {\n        return V_UI8(&variant);\n    }\n\n    return ULONG64_MAX;\n}\n\nPVOID PhGetWbemClassObjectUlongPtr(\n    _In_ PVOID WbemClassObject,\n    _In_ PCWSTR Name\n    )\n{\n    VARIANT variant;\n\n    RtlZeroMemory(&variant, sizeof(VARIANT));\n\n    if (SUCCEEDED(IWbemClassObject_Get((IWbemClassObject*)WbemClassObject, Name, 0, &variant, NULL, 0)))\n    {\n        return (PVOID)V_UINT_PTR(&variant);\n    }\n\n    return NULL;\n}\n\n// Power policy security descriptors\n\nNTSTATUS PhpGetPowerPolicySecurityDescriptor(\n    _Out_ PPH_STRING* StringSecurityDescriptor\n    )\n{\n    ULONG status;\n    PWSTR stringSecurityDescriptor;\n    PGUID policyGuid;\n\n    if (!(PowerGetActiveScheme_I && PowerReadSecurityDescriptor_I))\n    {\n        PVOID imageBaseAddress;\n\n        if (imageBaseAddress = PhpInitializePowerPolicyApi())\n        {\n            PowerGetActiveScheme_I = PhGetDllBaseProcedureAddress(imageBaseAddress, \"PowerGetActiveScheme\", 0);\n            PowerReadSecurityDescriptor_I = PhGetDllBaseProcedureAddress(imageBaseAddress, \"PowerReadSecurityDescriptor\", 0);\n        }\n        else\n        {\n            return STATUS_DLL_NOT_FOUND;\n        }\n    }\n\n    if (!(PowerGetActiveScheme_I && PowerReadSecurityDescriptor_I))\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    // We can use GUIDs for schemes, policies or other values but we only query the default scheme. (dmex)\n    status = PowerGetActiveScheme_I(\n        NULL,\n        &policyGuid\n        );\n\n    if (status != ERROR_SUCCESS)\n        return PhDosErrorToNtStatus(status);\n\n    // PowerReadSecurityDescriptor/PowerWriteSecurityDescriptor both use the same SDDL\n    // format as registry keys and are RPC wrappers for this registry key:\n    // HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Power\\SecurityDescriptors\n\n    status = PowerReadSecurityDescriptor_I(\n        ACCESS_DEFAULT_SECURITY_DESCRIPTOR, // ACCESS_ACTIVE_SCHEME?\n        policyGuid,\n        &stringSecurityDescriptor\n        );\n\n    if (status == ERROR_SUCCESS)\n    {\n        if (StringSecurityDescriptor)\n        {\n            *StringSecurityDescriptor = PhCreateString(stringSecurityDescriptor);\n        }\n\n        LocalFree(stringSecurityDescriptor);\n    }\n\n    LocalFree(policyGuid);\n\n    return PhDosErrorToNtStatus(status);\n}\n\nNTSTATUS PhpSetPowerPolicySecurityDescriptor(\n    _In_ PPH_STRING StringSecurityDescriptor\n    )\n{\n    ULONG status;\n    PGUID policyGuid;\n\n    if (!(PowerGetActiveScheme_I && PowerWriteSecurityDescriptor_I))\n    {\n        PVOID imageBaseAddress;\n\n        if (imageBaseAddress = PhpInitializePowerPolicyApi())\n        {\n            PowerGetActiveScheme_I = PhGetDllBaseProcedureAddress(imageBaseAddress, \"PowerGetActiveScheme\", 0);\n            PowerWriteSecurityDescriptor_I = PhGetDllBaseProcedureAddress(imageBaseAddress, \"PowerWriteSecurityDescriptor\", 0);\n        }\n        else\n        {\n            return STATUS_DLL_NOT_FOUND;\n        }\n    }\n\n    if (!(PowerGetActiveScheme_I && PowerWriteSecurityDescriptor_I))\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    status = PowerGetActiveScheme_I(\n        NULL,\n        &policyGuid\n        );\n\n    if (status != ERROR_SUCCESS)\n        return PhDosErrorToNtStatus(status);\n\n    status = PowerWriteSecurityDescriptor_I(\n        ACCESS_DEFAULT_SECURITY_DESCRIPTOR,\n        policyGuid, // Todo: Pass the GUID from the original query.\n        PhGetString(StringSecurityDescriptor)\n        );\n\n    //if (status == ERROR_SUCCESS)\n    //{\n    //    // refresh/reapply the current scheme.\n    //    status = PowerSetActiveScheme_I(NULL, policyGuid);\n    //}\n\n    LocalFree(policyGuid);\n\n    return PhDosErrorToNtStatus(status);\n}\n\n// Terminal server security descriptors\n\nNTSTATUS PhpGetRemoteDesktopSecurityDescriptor(\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    BOOL status;\n    ULONG securityDescriptorLength = 0;\n    PSECURITY_DESCRIPTOR securityDescriptor = NULL;\n\n    if (!WTSGetListenerSecurity_I)\n    {\n        PVOID imageBaseAddress;\n\n        if (imageBaseAddress = PhpInitializeRemoteDesktopServiceApi())\n            WTSGetListenerSecurity_I = PhGetDllBaseProcedureAddress(imageBaseAddress, \"WTSGetListenerSecurityW\", 0);\n        else\n            return STATUS_DLL_NOT_FOUND;\n    }\n\n    if (!WTSGetListenerSecurity_I)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    // Todo: Add support for SI_RESET using the default security descriptor:\n    // HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\DefaultSecurity\n\n    status = WTSGetListenerSecurity_I(\n        WTS_CURRENT_SERVER_HANDLE,\n        NULL,\n        0,\n        L\"Rdp-Tcp\", // or \"Console\"\n        DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,\n        securityDescriptor,\n        0,\n        &securityDescriptorLength\n        );\n\n    if (!(!status && securityDescriptorLength))\n        return STATUS_INVALID_SECURITY_DESCR;\n\n    securityDescriptor = PhAllocateZero(securityDescriptorLength);\n\n    status = WTSGetListenerSecurity_I(\n        WTS_CURRENT_SERVER_HANDLE,\n        NULL,\n        0,\n        L\"Rdp-Tcp\", // or \"Console\"\n        DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,\n        securityDescriptor,\n        securityDescriptorLength,\n        &securityDescriptorLength\n        );\n\n    if (status)\n    {\n        if (SecurityDescriptor)\n        {\n            *SecurityDescriptor = securityDescriptor;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return STATUS_INVALID_SECURITY_DESCR;\n}\n\nNTSTATUS PhpSetRemoteDesktopSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    if (!WTSSetListenerSecurity_I)\n    {\n        PVOID imageBaseAddress;\n\n        if (imageBaseAddress = PhpInitializeRemoteDesktopServiceApi())\n            WTSSetListenerSecurity_I = PhGetDllBaseProcedureAddress(imageBaseAddress, \"WTSSetListenerSecurityW\", 0);\n        else\n            return STATUS_DLL_NOT_FOUND;\n    }\n\n    if (!WTSSetListenerSecurity_I)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    if (WTSSetListenerSecurity_I(\n        WTS_CURRENT_SERVER_HANDLE,\n        NULL,\n        0,\n        L\"RDP-Tcp\",\n        DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,\n        SecurityDescriptor\n        ))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_INVALID_SECURITY_DESCR;\n}\n\n// WBEM security descriptors\n\nNTSTATUS PhGetWmiNamespaceSecurityDescriptor(\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    HRESULT status;\n    PVOID securityDescriptor = NULL;\n    PVOID securityDescriptorData = NULL;\n    BSTR wbemResourceString = NULL;\n    BSTR wbemObjectString = NULL;\n    BSTR wbemMethodString = NULL;\n    IWbemLocator* wbemLocator = NULL;\n    IWbemServices* wbemServices = NULL;\n    IWbemClassObject* wbemClassObject = NULL;\n    IWbemClassObject* wbemGetSDClassObject = 0;\n    VARIANT variantArrayValue = { 0 };\n    VARIANT variantReturnValue = { 0 };\n\n    status = PhGetWbemLocatorClass(\n        &wbemLocator\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    wbemResourceString = PhStringZToBSTR(L\"Root\");\n    status = IWbemLocator_ConnectServer(\n        wbemLocator,\n        wbemResourceString,\n        NULL,\n        NULL,\n        NULL,\n        WBEM_FLAG_CONNECT_USE_MAX_WAIT,\n        NULL,\n        NULL,\n        &wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = PhCoSetProxyBlanket(\n        (IUnknown*)wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    wbemObjectString = PhStringZToBSTR(L\"__SystemSecurity\");\n    status = IWbemServices_GetObject(\n        wbemServices,\n        wbemObjectString,\n        0,\n        NULL,\n        &wbemClassObject,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    wbemMethodString = PhStringZToBSTR(L\"GetSD\");\n    status = IWbemServices_ExecMethod(\n        wbemServices,\n        wbemObjectString,\n        wbemMethodString,\n        0,\n        NULL,\n        wbemClassObject,\n        &wbemGetSDClassObject,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = IWbemClassObject_Get(\n        wbemGetSDClassObject,\n        L\"ReturnValue\",\n        0,\n        &variantReturnValue,\n        NULL,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    if (V_UI4(&variantReturnValue) != ERROR_SUCCESS)\n    {\n        status = HRESULT_FROM_WIN32(V_UI4(&variantReturnValue));\n        goto CleanupExit;\n    }\n\n    status = IWbemClassObject_Get(\n        wbemGetSDClassObject,\n        L\"SD\",\n        0,\n        &variantArrayValue,\n        NULL,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = SafeArrayAccessData(V_ARRAY(&variantArrayValue), &securityDescriptorData);\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    // The Wbem security descriptor is relative but the ACUI\n    // dialog automatically converts the descriptor for us\n    // so we don't have to convert just validate. (dmex)\n\n    if (RtlValidSecurityDescriptor(securityDescriptorData))\n    {\n        securityDescriptor = PhAllocateCopy(\n            securityDescriptorData,\n            RtlLengthSecurityDescriptor(securityDescriptorData)\n            );\n    }\n\n    SafeArrayUnaccessData(V_ARRAY(&variantArrayValue));\n\nCleanupExit:\n    if (wbemGetSDClassObject)\n        IWbemClassObject_Release(wbemGetSDClassObject);\n    if (wbemServices)\n        IWbemServices_Release(wbemServices);\n    if (wbemClassObject)\n        IWbemClassObject_Release(wbemClassObject);\n    if (wbemLocator)\n        IWbemLocator_Release(wbemLocator);\n\n    VariantClear(&variantArrayValue);\n\n    if (wbemMethodString)\n        SysFreeString(wbemMethodString);\n    if (wbemObjectString)\n        SysFreeString(wbemObjectString);\n    if (wbemResourceString)\n        SysFreeString(wbemResourceString);\n\n    if (HR_SUCCESS(status) && securityDescriptor)\n    {\n        *SecurityDescriptor = securityDescriptor;\n        return STATUS_SUCCESS;\n    }\n\n    if (securityDescriptor)\n    {\n        PhFree(securityDescriptor);\n    }\n\n    if (status == WBEM_E_ACCESS_DENIED)\n        return STATUS_ACCESS_DENIED;\n    if (status == WBEM_E_INVALID_PARAMETER)\n        return STATUS_INVALID_PARAMETER;\n\n    return STATUS_INVALID_SECURITY_DESCR;\n}\n\nNTSTATUS PhSetWmiNamespaceSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    HRESULT status;\n    BSTR wbemResourceString = NULL;\n    BSTR wbemObjectString = NULL;\n    BSTR wbemMethodString = NULL;\n    IWbemLocator* wbemLocator = NULL;\n    IWbemServices* wbemServices = NULL;\n    IWbemClassObject* wbemClassObject = NULL;\n    IWbemClassObject* wbemSetSDClassObject = NULL;\n    PVOID safeArrayData = NULL;\n    LPSAFEARRAY safeArray = NULL;\n    SAFEARRAYBOUND safeArrayBounds;\n    PSECURITY_DESCRIPTOR relativeSecurityDescriptor = NULL;\n    ULONG relativeSecurityDescriptorLength = 0;\n    BOOLEAN freeSecurityDescriptor = FALSE;\n    VARIANT variantArrayValue = { 0 };\n    VARIANT variantReturnValue = { 0 };\n    PSID administratorsSid;\n\n    // kludge the descriptor into the correct format required by wmimgmt (dmex)\n    // 1) The owner must always be the built-in domain administrator.\n    // 2) The group must always be the built-in domain administrator.\n\n    administratorsSid = PhSeAdministratorsSid();\n    PhSetOwnerSecurityDescriptor(SecurityDescriptor, administratorsSid, TRUE);\n    PhSetGroupSecurityDescriptor(SecurityDescriptor, administratorsSid, TRUE);\n\n    status = PhGetWbemLocatorClass(\n        &wbemLocator\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    wbemResourceString = PhStringZToBSTR(L\"Root\");\n    status = IWbemLocator_ConnectServer(\n        wbemLocator,\n        wbemResourceString,\n        NULL,\n        NULL,\n        NULL,\n        WBEM_FLAG_CONNECT_USE_MAX_WAIT,\n        NULL,\n        NULL,\n        &wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = PhCoSetProxyBlanket(\n        (IUnknown*)wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    wbemObjectString = PhStringZToBSTR(L\"__SystemSecurity\");\n    status = IWbemServices_GetObject(\n        wbemServices,\n        wbemObjectString,\n        0,\n        NULL,\n        &wbemClassObject,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    if (RtlValidRelativeSecurityDescriptor(\n        SecurityDescriptor,\n        RtlLengthSecurityDescriptor(SecurityDescriptor),\n        OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |\n        DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION\n        ))\n    {\n        relativeSecurityDescriptor = SecurityDescriptor;\n        relativeSecurityDescriptorLength = RtlLengthSecurityDescriptor(SecurityDescriptor);\n    }\n    else\n    {\n        NTSTATUS ntstatus;\n\n        ntstatus = RtlAbsoluteToSelfRelativeSD(\n            SecurityDescriptor,\n            NULL,\n            &relativeSecurityDescriptorLength\n            );\n\n        if (ntstatus != STATUS_BUFFER_TOO_SMALL)\n        {\n            // Note: HR>WIN32>NT required for correct WMI error messages (dmex)\n            status = HRESULT_FROM_WIN32(PhNtStatusToDosError(ntstatus));\n            goto CleanupExit;\n        }\n\n        relativeSecurityDescriptor = PhAllocate(relativeSecurityDescriptorLength);\n        ntstatus = RtlAbsoluteToSelfRelativeSD(\n            SecurityDescriptor,\n            relativeSecurityDescriptor,\n            &relativeSecurityDescriptorLength\n            );\n\n        if (!NT_SUCCESS(ntstatus))\n        {\n            PhFree(relativeSecurityDescriptor);\n            // Note: HR>WIN32>NT required for correct WMI error messages (dmex)\n            status = HRESULT_FROM_WIN32(PhNtStatusToDosError(ntstatus));\n            goto CleanupExit;\n        }\n\n        freeSecurityDescriptor = TRUE;\n    }\n\n    safeArrayBounds.lLbound = 0;\n    safeArrayBounds.cElements = relativeSecurityDescriptorLength;\n\n    if (!(safeArray = SafeArrayCreate(VT_UI1, 1, &safeArrayBounds)))\n    {\n        status = STATUS_NO_MEMORY;\n        goto CleanupExit;\n    }\n\n    status = SafeArrayAccessData(safeArray, &safeArrayData);\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    memcpy(\n        safeArrayData,\n        relativeSecurityDescriptor,\n        relativeSecurityDescriptorLength\n        );\n\n    status = SafeArrayUnaccessData(safeArray);\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    V_VT(&variantArrayValue) = VT_ARRAY | VT_UI1;\n    V_ARRAY(&variantArrayValue) = safeArray;\n\n    status = IWbemClassObject_Put(\n        wbemClassObject,\n        L\"SD\",\n        0,\n        &variantArrayValue,\n        CIM_EMPTY\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    wbemMethodString = PhStringZToBSTR(L\"SetSD\");\n    status = IWbemServices_ExecMethod(\n        wbemServices,\n        wbemObjectString,\n        wbemMethodString,\n        0,\n        NULL,\n        wbemClassObject,\n        &wbemSetSDClassObject,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = IWbemClassObject_Get(\n        wbemSetSDClassObject,\n        L\"ReturnValue\",\n        0,\n        &variantReturnValue,\n        NULL,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    if (V_UI4(&variantReturnValue) != ERROR_SUCCESS)\n    {\n        status = HRESULT_FROM_WIN32(V_UI4(&variantReturnValue));\n    }\n\nCleanupExit:\n    if (wbemSetSDClassObject)\n        IWbemClassObject_Release(wbemSetSDClassObject);\n    if (wbemClassObject)\n        IWbemClassObject_Release(wbemClassObject);\n    if (wbemServices)\n        IWbemServices_Release(wbemServices);\n    if (wbemLocator)\n        IWbemLocator_Release(wbemLocator);\n\n    if (freeSecurityDescriptor && relativeSecurityDescriptor)\n        PhFree(relativeSecurityDescriptor);\n\n    VariantClear(&variantArrayValue);\n    //if (safeArray) SafeArrayDestroy(safeArray);\n\n    if (wbemMethodString)\n        SysFreeString(wbemMethodString);\n    if (wbemObjectString)\n        SysFreeString(wbemObjectString);\n    if (wbemResourceString)\n        SysFreeString(wbemResourceString);\n\n    if (HR_SUCCESS(status))\n    {\n        return STATUS_SUCCESS;\n    }\n\n    if (status == WBEM_E_ACCESS_DENIED)\n        return STATUS_ACCESS_DENIED;\n    if (status == WBEM_E_INVALID_PARAMETER)\n        return STATUS_INVALID_PARAMETER;\n\n    return STATUS_INVALID_SECURITY_DESCR;\n}\n\nstatic PH_STRINGREF OleKeyName = PH_STRINGREF_INIT(L\"\\\\REGISTRY\\\\MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Ole\");\nstatic PH_STRINGREF OlePermissionValueName[] =\n{\n    PH_STRINGREF_INIT(L\"DefaultLaunchPermission\"),\n    PH_STRINGREF_INIT(L\"DefaultAccessPermission\"),\n    PH_STRINGREF_INIT(L\"MachineLaunchRestriction\"),\n    PH_STRINGREF_INIT(L\"MachineAccessRestriction\"),\n};\n\n/**\n * Read a COM access/launch policy security descriptor override from the registry.\n *\n * \\param ComSDType The type of a security descriptor to read.\n * \\param SecurityDescriptor A security descriptor buffer.\n */\nNTSTATUS PhGetComSecurityDescriptorOverride(\n    _In_ COMSD ComSDType,\n    _Outptr_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    HANDLE keyHandle = NULL;\n    PKEY_VALUE_PARTIAL_INFORMATION value = NULL;\n\n    if (ComSDType >= RTL_NUMBER_OF(OlePermissionValueName))\n        return STATUS_INVALID_PARAMETER;\n\n    status = PhOpenKey(&keyHandle, KEY_QUERY_VALUE, NULL, &OleKeyName, OBJ_CASE_INSENSITIVE);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhQueryValueKey(\n        keyHandle,\n        &OlePermissionValueName[ComSDType],\n        KeyValuePartialInformation,\n        &value\n    );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (!RtlValidRelativeSecurityDescriptor(\n        (PSECURITY_DESCRIPTOR)value->Data,\n        value->DataLength,\n        OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION\n        ))\n    {\n        status = STATUS_INVALID_SECURITY_DESCR;\n        goto CleanupExit;\n    }\n\n    *SecurityDescriptor = PhAllocateCopy(value->Data, value->DataLength);\n\nCleanupExit:\n\n    if (keyHandle)\n        NtClose(keyHandle);\n\n    if (value)\n        PhFree(value);\n\n    return status;\n}\n\n/**\n * Query a COM access/launch policy security descriptor.\n *\n * \\param ComSDType The type of a security descriptor to query.\n * \\param SecurityDescriptor A security descriptor buffer.\n */\nNTSTATUS PhGetComSecurityDescriptor(\n    _In_ COMSD ComSDType,\n    _Outptr_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    HRESULT hresult;\n    PSECURITY_DESCRIPTOR securityDescriptor = NULL;\n\n    status = PhGetComSecurityDescriptorOverride(ComSDType, SecurityDescriptor);\n\n    if (NT_SUCCESS(status) || (status != STATUS_OBJECT_NAME_NOT_FOUND))\n        return status;\n\n    hresult = CoGetSystemSecurityPermissions(ComSDType, &securityDescriptor);\n\n    if (HR_FAILED(hresult))\n    {\n        switch (hresult)\n        {\n        case E_ACCESSDENIED:\n            return STATUS_ACCESS_DENIED;\n        case E_OUTOFMEMORY:\n            return STATUS_NO_MEMORY;\n        case E_INVALIDARG:\n            return STATUS_INVALID_PARAMETER;\n        }\n\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    if (!RtlValidSecurityDescriptor(securityDescriptor))\n    {\n        status = STATUS_INVALID_SECURITY_DESCR;\n        goto CleanupExit;\n    }\n\n    *SecurityDescriptor = PhAllocateCopy(\n        securityDescriptor,\n        RtlLengthSecurityDescriptor(securityDescriptor)\n        );\n\nCleanupExit:\n    if (securityDescriptor)\n        LocalFree(securityDescriptor);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Adjust a COM access/launch policy security descriptor.\n *\n * \\param ComSDType The type of a security descriptor to read.\n * \\param SecurityInformation The security information to change.\n * \\param SecurityDescriptor A security descriptor buffer.\n */\nNTSTATUS PhSetComSecurityDescriptor(\n    _In_ COMSD ComSDType,\n    _In_ ULONG SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    HANDLE keyHandle = NULL;\n    PSECURITY_DESCRIPTOR originalSecurityDescriptor = NULL;\n    PSECURITY_DESCRIPTOR mergedSecurityDescriptor = NULL;\n\n    if (ComSDType >= RTL_NUMBER_OF(OlePermissionValueName))\n        return STATUS_INVALID_PARAMETER;\n\n    status = PhOpenKey(&keyHandle, KEY_SET_VALUE, NULL, &OleKeyName, OBJ_CASE_INSENSITIVE);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetComSecurityDescriptor(ComSDType, &originalSecurityDescriptor);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhMergeSecurityDescriptors(\n        originalSecurityDescriptor,\n        SecurityDescriptor,\n        SecurityInformation,\n        &mergedSecurityDescriptor\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhSetValueKey(\n        keyHandle,\n        &OlePermissionValueName[ComSDType],\n        REG_BINARY,\n        mergedSecurityDescriptor,\n        RtlLengthSecurityDescriptor(mergedSecurityDescriptor)\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        // Notify RPCSS about the change\n        UpdateDCOMSettings();        \n    }\n\nCleanupExit:\n    if (keyHandle)\n        NtClose(keyHandle);\n\n    if (originalSecurityDescriptor)\n        PhFree(originalSecurityDescriptor);\n\n    if (mergedSecurityDescriptor)\n        PhFree(mergedSecurityDescriptor);\n\n    return status;\n}\n\nHRESULT PhRestartDefenderOfflineScan(\n    VOID\n    )\n{\n    HRESULT status;\n    BSTR wbemResourceString = NULL;\n    BSTR wbemObjectString = NULL;\n    BSTR wbemMethodString = NULL;\n    IWbemLocator* wbemLocator = NULL;\n    IWbemServices* wbemServices = NULL;\n    IWbemClassObject* wbemClassObject = NULL;\n    IWbemClassObject* wbemStartClassObject = NULL;\n    VARIANT variantReturnValue = { 0 };\n\n    status = PhGetWbemLocatorClass(\n        &wbemLocator\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    wbemResourceString = PhStringZToBSTR(L\"Root\\\\Microsoft\\\\Windows\\\\Defender\");\n    status = IWbemLocator_ConnectServer(\n        wbemLocator,\n        wbemResourceString,\n        NULL,\n        NULL,\n        NULL,\n        WBEM_FLAG_CONNECT_USE_MAX_WAIT,\n        NULL,\n        NULL,\n        &wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = PhCoSetProxyBlanket(\n        (IUnknown*)wbemServices\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    wbemObjectString = PhStringZToBSTR(L\"MSFT_MpWDOScan\");\n    status = IWbemServices_GetObject(\n        wbemServices,\n        wbemObjectString,\n        0,\n        NULL,\n        &wbemClassObject,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    wbemMethodString = PhStringZToBSTR(L\"Start\");\n    status = IWbemServices_ExecMethod(\n        wbemServices,\n        wbemObjectString,\n        wbemMethodString,\n        0,\n        NULL,\n        wbemClassObject,\n        &wbemStartClassObject,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    status = IWbemClassObject_Get(\n        wbemStartClassObject,\n        L\"ReturnValue\",\n        0,\n        &variantReturnValue,\n        NULL,\n        NULL\n        );\n\n    if (HR_FAILED(status))\n        goto CleanupExit;\n\n    if (V_UI4(&variantReturnValue) != ERROR_SUCCESS)\n    {\n        status = HRESULT_FROM_WIN32(V_UI4(&variantReturnValue));\n        goto CleanupExit;\n    }\n\nCleanupExit:\n    if (wbemStartClassObject)\n        IWbemClassObject_Release(wbemStartClassObject);\n    if (wbemServices)\n        IWbemServices_Release(wbemServices);\n    if (wbemClassObject)\n        IWbemClassObject_Release(wbemClassObject);\n    if (wbemLocator)\n        IWbemLocator_Release(wbemLocator);\n\n    if (wbemMethodString)\n        SysFreeString(wbemMethodString);\n    if (wbemObjectString)\n        SysFreeString(wbemObjectString);\n    if (wbemResourceString)\n        SysFreeString(wbemResourceString);\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/settings.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2016\n *     dmex    2017-2022\n *\n */\n\n/*\n * This file contains a program-specific settings system. All possible\n * settings are defined at program startup and added to a hashtable.\n * The values of these settings can then be read in from a XML file or\n * saved to a XML file at any time. Settings which are not recognized\n * are added to a list of \"ignored settings\"; this is necessary to\n * support plugin settings, as we don't want their settings to get\n * deleted whenever the plugins are disabled.\n *\n * The get/set functions are very strict. If the wrong function is used\n * (the get-integer-setting function is used on a string setting) or\n * the setting does not exist, an exception will be raised.\n */\n\n#include <ph.h>\n#include <apiimport.h>\n#include <guisup.h>\n#include <guisupview.h>\n#include <mapimg.h>\n#include <mapldr.h>\n#include <thirdparty.h>\n#include <settings.h>\n#include <json.h>\n#include <filestream.h>\n\nPPH_HASHTABLE PhSettingsHashtable;\nPH_QUEUED_LOCK PhSettingsLock = PH_QUEUED_LOCK_INIT;\nPPH_LIST PhIgnoredSettings;\n\n// Settings store descriptors (priority order: lower = higher priority)\nstatic const PH_SETTINGS_STORE_DESCRIPTOR PhSettingsStores[] =\n{\n    { SettingsFormatJson, L\".json\", TRUE,   TRUE,   FALSE, 1 },\n    { SettingsFormatXml, L\".xml\",   TRUE,   FALSE,  TRUE,  2 },\n    { SettingsFormatKey, L\".dat\",   TRUE,   FALSE,  FALSE, 3 },\n    { SettingsFormatReg, NULL,      FALSE,  FALSE,  FALSE, 4 },\n    { SettingsFormatBin, L\".bin\",   TRUE,   FALSE,  FALSE, 5 },\n};\n\n#define PH_SETTINGS_STORE_COUNT RTL_NUMBER_OF(PhSettingsStores)\n\n// Track which format was loaded\nPH_SETTINGS_FORMAT PhSettingsLoadedFormat = SettingsFormatJson;\n\n#define PH_SETTINGS_BIN_SIGNATURE 0x4E485042 // 'BPHN'\n#define PH_SETTINGS_BIN_VERSION 1\n\n#include <pshpack1.h>\ntypedef struct _PH_SETTINGS_BIN_HEADER\n{\n    ULONG Signature;\n    ULONG Version;\n    ULONG NumberOfSettings;\n} PH_SETTINGS_BIN_HEADER, *PPH_SETTINGS_BIN_HEADER;\n\ntypedef struct _PH_SETTINGS_BIN_SETTING\n{\n    ULONG NameLength; // in bytes\n    ULONG Type;\n    ULONG ValueLength; // in bytes\n} PH_SETTINGS_BIN_SETTING, *PPH_SETTINGS_BIN_SETTING;\n#include <poppack.h>\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN NTAPI PhSettingsHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_SETTING setting1 = (PPH_SETTING)Entry1;\n    PPH_SETTING setting2 = (PPH_SETTING)Entry2;\n\n    return PhEqualStringRef(&setting1->Name, &setting2->Name, TRUE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG NTAPI PhSettingsHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_SETTING setting = (PPH_SETTING)Entry;\n\n    return PhHashStringRefEx(&setting->Name, TRUE, PH_STRING_HASH_XXH32);\n}\n\nVOID PhSettingsInitialization(\n    VOID\n    )\n{\n    PhSettingsHashtable = PhCreateHashtable(\n        sizeof(PH_SETTING),\n        PhSettingsHashtableEqualFunction,\n        PhSettingsHashtableHashFunction,\n        512\n        );\n    PhIgnoredSettings = PhCreateList(1);\n}\n\nPPH_STRING PhSettingToString(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_SETTING Setting\n    )\n{\n    switch (Type)\n    {\n    case StringSettingType:\n        {\n            if (!Setting->u.Pointer)\n                return PhReferenceEmptyString();\n\n            PhReferenceObject(Setting->u.Pointer);\n\n            return (PPH_STRING)Setting->u.Pointer;\n        }\n        break;\n    case IntegerSettingType:\n        {\n            PH_FORMAT format[1];\n\n            // %x\n            PhInitFormatX(&format[0], Setting->u.Integer);\n\n            return PhFormat(format, RTL_NUMBER_OF(format), 0);\n        }\n        break;\n    case IntegerPairSettingType:\n        {\n            PPH_INTEGER_PAIR integerPair = &Setting->u.IntegerPair;\n            PH_FORMAT format[3];\n\n            // %ld,%ld\n            PhInitFormatD(&format[0], integerPair->X);\n            PhInitFormatC(&format[1], L',');\n            PhInitFormatD(&format[2], integerPair->Y);\n\n            return PhFormat(format, RTL_NUMBER_OF(format), 0);\n        }\n        break;\n    case ScalableIntegerPairSettingType:\n        {\n            PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = Setting->u.Pointer;\n            PH_FORMAT format[6];\n\n            if (!scalableIntegerPair)\n                return PhReferenceEmptyString();\n\n            // @%lu|%ld,%ld\n            PhInitFormatC(&format[0], L'@');\n            PhInitFormatU(&format[1], scalableIntegerPair->Scale);\n            PhInitFormatC(&format[2], L'|');\n            PhInitFormatD(&format[3], scalableIntegerPair->X);\n            PhInitFormatC(&format[4], L',');\n            PhInitFormatD(&format[5], scalableIntegerPair->Y);\n\n            return PhFormat(format, RTL_NUMBER_OF(format), 0);\n        }\n        break;\n    }\n\n    return PhReferenceEmptyString();\n}\n\nBOOLEAN PhSettingFromString(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PCPH_STRINGREF StringRef,\n    _In_opt_ PPH_STRING String,\n    _Inout_ PPH_SETTING Setting\n    )\n{\n    switch (Type)\n    {\n    case StringSettingType:\n        {\n            if (String)\n            {\n                PhSetReference(&Setting->u.Pointer, String);\n            }\n            else\n            {\n                Setting->u.Pointer = PhCreateString2(StringRef);\n            }\n\n            return TRUE;\n        }\n        break;\n    case IntegerSettingType:\n        {\n            ULONG64 integer;\n\n            if (PhStringToInteger64(StringRef, 16, &integer))\n            {\n                Setting->u.Integer = (ULONG)integer;\n                return TRUE;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        break;\n    case IntegerPairSettingType:\n        {\n            LONG64 x;\n            LONG64 y;\n            PH_STRINGREF xString;\n            PH_STRINGREF yString;\n\n            if (!PhSplitStringRefAtChar(StringRef, L',', &xString, &yString))\n                return FALSE;\n\n            if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y))\n            {\n                Setting->u.IntegerPair.X = (LONG)x;\n                Setting->u.IntegerPair.Y = (LONG)y;\n                return TRUE;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        break;\n    case ScalableIntegerPairSettingType:\n        {\n            LONG64 scale;\n            LONG64 x;\n            LONG64 y;\n            PH_STRINGREF stringRef;\n            PH_STRINGREF firstPart;\n            PH_STRINGREF secondPart;\n            PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair;\n\n            stringRef = *StringRef;\n\n            if (stringRef.Length != 0 && stringRef.Buffer[0] == L'@')\n            {\n                PhSkipStringRef(&stringRef, sizeof(WCHAR));\n\n                if (!PhSplitStringRefAtChar(&stringRef, L'|', &firstPart, &stringRef))\n                    return FALSE;\n                if (!PhStringToInteger64(&firstPart, 10, &scale))\n                    return FALSE;\n            }\n            else\n            {\n                scale = USER_DEFAULT_SCREEN_DPI;\n            }\n\n            if (!PhSplitStringRefAtChar(&stringRef, L',', &firstPart, &secondPart))\n                return FALSE;\n\n            if (PhStringToInteger64(&firstPart, 10, &x) && PhStringToInteger64(&secondPart, 10, &y))\n            {\n                scalableIntegerPair = PhAllocateZero(sizeof(PH_SCALABLE_INTEGER_PAIR));\n                scalableIntegerPair->X = (LONG)x;\n                scalableIntegerPair->Y = (LONG)y;\n                scalableIntegerPair->Scale = (ULONG)scale;\n                Setting->u.Pointer = scalableIntegerPair;\n                return TRUE;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nstatic VOID PhpFreeSettingValue(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_SETTING Setting\n    )\n{\n    switch (Type)\n    {\n    case StringSettingType:\n        PhClearReference(&Setting->u.Pointer);\n        break;\n    case ScalableIntegerPairSettingType:\n        PhFree(Setting->u.Pointer);\n        Setting->u.Pointer = NULL;\n        break;\n    }\n}\n\nstatic PVOID PhpLookupSetting(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    PH_SETTING lookupSetting;\n    PPH_SETTING setting;\n\n    lookupSetting.Name = *Name;\n    setting = (PPH_SETTING)PhFindEntryHashtable(\n        PhSettingsHashtable,\n        &lookupSetting\n        );\n\n    return setting;\n}\n\nVOID PhEnumSettings(\n    _In_ PPH_SETTINGS_ENUM_CALLBACK Callback,\n    _In_ PVOID Context\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SETTING setting;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        if (!Callback(setting, Context))\n            break;\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nULONG PhGetIntegerStringRefSetting(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    PPH_SETTING setting;\n    ULONG value;\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    setting = PhpLookupSetting(Name);\n    assert(setting && setting->Type == IntegerSettingType);\n\n    if (setting && setting->Type == IntegerSettingType)\n    {\n        value = setting->u.Integer;\n    }\n    else\n    {\n        value = 0;\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    return value;\n}\n\nBOOLEAN PhGetIntegerPairStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _Out_ PPH_INTEGER_PAIR IntegerPair\n    )\n{\n    BOOLEAN result;\n    PPH_SETTING setting;\n    PH_INTEGER_PAIR value;\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    setting = PhpLookupSetting(Name);\n    assert(setting && setting->Type == IntegerPairSettingType);\n\n    if (setting && setting->Type == IntegerPairSettingType)\n    {\n        value = setting->u.IntegerPair;\n        result = TRUE;\n    }\n    else\n    {\n        RtlZeroMemory(&value, sizeof(PH_INTEGER_PAIR));\n        result = FALSE;\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    RtlZeroMemory(IntegerPair, sizeof(PH_INTEGER_PAIR));\n    RtlCopyMemory(IntegerPair, &value, sizeof(PH_INTEGER_PAIR));\n\n    return result;\n}\n\nBOOLEAN PhGetScalableIntegerPairStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ BOOLEAN ScaleToDpi,\n    _In_ LONG Dpi,\n    _Out_ PPH_SCALABLE_INTEGER_PAIR* ScalableIntegerPair\n    )\n{\n    BOOLEAN result;\n    PPH_SETTING setting;\n    PPH_SCALABLE_INTEGER_PAIR value;\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    setting = PhpLookupSetting(Name);\n    assert(setting && setting->Type == ScalableIntegerPairSettingType);\n\n    if (setting && setting->Type == ScalableIntegerPairSettingType)\n    {\n        value = setting->u.Pointer;\n        result = TRUE;\n    }\n    else\n    {\n        value = NULL;\n        result = FALSE;\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    if (ScaleToDpi)\n    {\n        if (value->Scale != Dpi && value->Scale != 0)\n        {\n            value->X = PhMultiplyDivideSigned(value->X, Dpi, value->Scale);\n            value->Y = PhMultiplyDivideSigned(value->Y, Dpi, value->Scale);\n            value->Scale = Dpi;\n        }\n    }\n\n    *ScalableIntegerPair = value;\n\n    return result;\n}\n\nPPH_STRING PhGetStringRefSetting(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    PPH_SETTING setting;\n    PPH_STRING value = NULL;\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    setting = PhpLookupSetting(Name);\n    assert(setting && setting->Type == StringSettingType);\n\n    if (setting && setting->Type == StringSettingType)\n    {\n        if (setting->u.Pointer)\n        {\n            PhSetReference(&value, setting->u.Pointer);\n        }\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    if (PhIsNullOrEmptyString(value))\n    {\n        value = PhReferenceEmptyString();\n    }\n\n    return value;\n}\n\nBOOLEAN PhGetBinarySetting(\n    _In_ PCPH_STRINGREF Name,\n    _Out_ PVOID Buffer\n    )\n{\n    PPH_STRING setting;\n    BOOLEAN result;\n\n    setting = PhGetStringRefSetting(Name);\n    result = PhHexStringToBuffer(&setting->sr, (PUCHAR)Buffer);\n    PhDereferenceObject(setting);\n\n    return result;\n}\n\nVOID PhSetIntegerStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ ULONG Value\n    )\n{\n    PPH_SETTING setting;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    setting = PhpLookupSetting(Name);\n    assert(setting);\n\n    if (setting && setting->Type == IntegerSettingType)\n    {\n        setting->u.Integer = Value;\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nVOID PhSetIntegerPairStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PPH_INTEGER_PAIR Value\n    )\n{\n    PPH_SETTING setting;\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    setting = PhpLookupSetting(Name);\n    assert(setting);\n\n    if (setting && setting->Type == IntegerPairSettingType)\n    {\n        memcpy(&setting->u.IntegerPair, Value, sizeof(PH_INTEGER_PAIR));\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nVOID PhSetScalableIntegerPairStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PPH_SCALABLE_INTEGER_PAIR Value\n    )\n{\n    PPH_SETTING setting;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    setting = PhpLookupSetting(Name);\n    assert(setting);\n\n    if (setting && setting->Type == ScalableIntegerPairSettingType)\n    {\n        PhpFreeSettingValue(ScalableIntegerPairSettingType, setting);\n        setting->u.Pointer = PhAllocateCopy(Value, sizeof(PH_SCALABLE_INTEGER_PAIR));\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nVOID PhSetScalableIntegerPairStringRefSetting2(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PPH_INTEGER_PAIR Value,\n    _In_ LONG dpiValue\n    )\n{\n    PH_SCALABLE_INTEGER_PAIR scalableIntegerPair;\n\n    ZeroMemory(&scalableIntegerPair, sizeof(PH_SCALABLE_INTEGER_PAIR));\n    memcpy(&scalableIntegerPair.Pair, Value, sizeof(PH_INTEGER_PAIR));\n    scalableIntegerPair.Scale = dpiValue;\n\n    PhSetScalableIntegerPairStringRefSetting(Name, &scalableIntegerPair);\n}\n\nVOID PhSetStringRefSetting(\n    _In_ PCPH_STRINGREF Name,\n    _In_ PCPH_STRINGREF Value\n    )\n{\n    PPH_SETTING setting;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    setting = PhpLookupSetting(Name);\n    assert(setting);\n\n    if (setting && setting->Type == StringSettingType)\n    {\n        PhpFreeSettingValue(StringSettingType, setting);\n        setting->u.Pointer = PhCreateString2(Value);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nVOID PhpFreeIgnoredSetting(\n    _In_ PPH_SETTING Setting\n    )\n{\n    PhFree(Setting->Name.Buffer);\n    PhDereferenceObject(Setting->u.Pointer);\n\n    PhFree(Setting);\n}\n\nVOID PhpClearIgnoredSettings(\n    VOID\n    )\n{\n    ULONG i;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    for (i = 0; i < PhIgnoredSettings->Count; i++)\n    {\n        PhpFreeIgnoredSetting(PhIgnoredSettings->Items[i]);\n    }\n\n    PhClearList(PhIgnoredSettings);\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nVOID PhClearIgnoredSettings(\n    VOID\n    )\n{\n    PhpClearIgnoredSettings();\n}\n\nULONG PhCountIgnoredSettings(\n    VOID\n    )\n{\n    ULONG count;\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n    count = PhIgnoredSettings->Count;\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    return count;\n}\n\nVOID PhConvertIgnoredSettings(\n    VOID\n    )\n{\n    PPH_SETTING ignoredSetting;\n    PPH_SETTING setting;\n    ULONG i;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    for (i = 0; i < PhIgnoredSettings->Count; i++)\n    {\n        ignoredSetting = PhIgnoredSettings->Items[i];\n\n        setting = PhpLookupSetting(&ignoredSetting->Name);\n\n        if (setting)\n        {\n            PhpFreeSettingValue(setting->Type, setting);\n\n            if (!PhSettingFromString(\n                setting->Type,\n                &((PPH_STRING)ignoredSetting->u.Pointer)->sr,\n                ignoredSetting->u.Pointer,\n                setting\n                ))\n            {\n                PhSettingFromString(\n                    setting->Type,\n                    &setting->DefaultValue,\n                    NULL,\n                    setting\n                    );\n            }\n\n            PhpFreeIgnoredSetting(ignoredSetting);\n\n            PhRemoveItemList(PhIgnoredSettings, i);\n            i--;\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nNTSTATUS PhLoadSettingsBin(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    PVOID viewBase;\n    SIZE_T viewSize;\n    PPH_SETTINGS_BIN_HEADER header;\n    PBYTE pointer;\n    PBYTE limit;\n\n    status = PhMapViewOfEntireFileEx(FileName, NULL, &viewBase, &viewSize);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (viewSize < sizeof(PH_SETTINGS_BIN_HEADER))\n    {\n        PhUnmapViewOfSection(NtCurrentProcess(), viewBase);\n        return STATUS_FILE_CORRUPT_ERROR;\n    }\n\n    header = (PPH_SETTINGS_BIN_HEADER)viewBase;\n\n    if (header->Signature != PH_SETTINGS_BIN_SIGNATURE || header->Version != PH_SETTINGS_BIN_VERSION)\n    {\n        PhUnmapViewOfSection(NtCurrentProcess(), viewBase);\n        return STATUS_FILE_CORRUPT_ERROR;\n    }\n\n    PhpClearIgnoredSettings();\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    pointer = (PBYTE)viewBase + sizeof(PH_SETTINGS_BIN_HEADER);\n    limit = (PBYTE)viewBase + viewSize;\n\n    for (ULONG i = 0; i < header->NumberOfSettings; i++)\n    {\n        PPH_SETTINGS_BIN_SETTING entry;\n        PPH_SETTING setting;\n        PH_STRINGREF settingName;\n        PH_STRINGREF settingValue;\n\n        if (pointer + sizeof(PH_SETTINGS_BIN_SETTING) > limit)\n            break;\n\n        entry = (PPH_SETTINGS_BIN_SETTING)pointer;\n        pointer += sizeof(PH_SETTINGS_BIN_SETTING);\n\n        if (pointer + entry->NameLength + entry->ValueLength > limit)\n            break;\n\n        settingName.Buffer = (PWCH)pointer;\n        settingName.Length = entry->NameLength;\n        pointer += entry->NameLength;\n\n        settingValue.Buffer = (PWCH)pointer;\n        settingValue.Length = entry->ValueLength;\n        pointer += entry->ValueLength;\n\n        if (setting = PhpLookupSetting(&settingName))\n        {\n            PhpFreeSettingValue(setting->Type, setting);\n\n            if (!PhSettingFromString(\n                setting->Type,\n                &settingValue,\n                NULL,\n                setting\n                ))\n            {\n                PhSettingFromString(\n                    setting->Type,\n                    &setting->DefaultValue,\n                    NULL,\n                    setting\n                    );\n            }\n        }\n        else\n        {\n            setting = PhAllocateZero(sizeof(PH_SETTING));\n            setting->Type = StringSettingType;\n            setting->Name.Buffer = PhAllocateCopy(settingName.Buffer, settingName.Length + sizeof(WCHAR));\n            setting->Name.Length = settingName.Length;\n            setting->Name.Buffer[settingName.Length / sizeof(WCHAR)] = 0;\n            setting->u.Pointer = PhCreateString2(&settingValue);\n\n            PhAddItemList(PhIgnoredSettings, setting);\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n    PhUnmapViewOfSection(NtCurrentProcess(), viewBase);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSaveSettingsBin(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SETTING setting;\n    PH_SETTINGS_BIN_HEADER header;\n    SIZE_T totalSize = 0;\n    PBYTE buffer;\n    PBYTE pointer;\n    HANDLE fileHandle;\n    IO_STATUS_BLOCK isb;\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    // Calculate total size required\n    totalSize = sizeof(PH_SETTINGS_BIN_HEADER);\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        PPH_STRING settingValue = PhSettingToString(setting->Type, setting);\n        totalSize += sizeof(PH_SETTINGS_BIN_SETTING) + setting->Name.Length + settingValue->Length;\n        PhDereferenceObject(settingValue);\n    }\n\n    for (ULONG i = 0; i < PhIgnoredSettings->Count; i++)\n    {\n        setting = PhIgnoredSettings->Items[i];\n        PPH_STRING settingValue = setting->u.Pointer;\n        totalSize += sizeof(PH_SETTINGS_BIN_SETTING) + setting->Name.Length + settingValue->Length;\n    }\n\n    buffer = PhAllocate(totalSize);\n    pointer = buffer;\n\n    __analysis_assume(pointer <= (PBYTE)buffer + totalSize);\n    header.Signature = PH_SETTINGS_BIN_SIGNATURE;\n    header.Version = PH_SETTINGS_BIN_VERSION;\n    header.NumberOfSettings = PhSettingsHashtable->Count + PhIgnoredSettings->Count;\n\n    __analysis_assume(pointer + sizeof(PH_SETTINGS_BIN_HEADER) <= (PBYTE)buffer + totalSize);\n    memcpy(pointer, &header, sizeof(PH_SETTINGS_BIN_HEADER));\n    pointer += sizeof(PH_SETTINGS_BIN_HEADER);\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        PPH_STRING settingValue = PhSettingToString(setting->Type, setting);\n        PH_SETTINGS_BIN_SETTING entry;\n\n        entry.NameLength = (ULONG)setting->Name.Length;\n        entry.Type = (ULONG)setting->Type;\n        entry.ValueLength = (ULONG)settingValue->Length;\n\n        memcpy(pointer, &entry, sizeof(PH_SETTINGS_BIN_SETTING));\n        pointer += sizeof(PH_SETTINGS_BIN_SETTING);\n        memcpy(pointer, setting->Name.Buffer, setting->Name.Length);\n        pointer += setting->Name.Length;\n        memcpy(pointer, settingValue->Buffer, settingValue->Length);\n        pointer += settingValue->Length;\n\n        PhDereferenceObject(settingValue);\n    }\n\n    for (ULONG i = 0; i < PhIgnoredSettings->Count; i++)\n    {\n        setting = PhIgnoredSettings->Items[i];\n        PPH_STRING settingValue = setting->u.Pointer;\n        PH_SETTINGS_BIN_SETTING entry;\n\n        entry.NameLength = (ULONG)setting->Name.Length;\n        entry.Type = (ULONG)setting->Type;\n        entry.ValueLength = (ULONG)settingValue->Length;\n\n        memcpy(pointer, &entry, sizeof(PH_SETTINGS_BIN_SETTING));\n        pointer += sizeof(PH_SETTINGS_BIN_SETTING);\n        memcpy(pointer, setting->Name.Buffer, setting->Name.Length);\n        pointer += setting->Name.Length;\n        memcpy(pointer, settingValue->Buffer, settingValue->Length);\n        pointer += settingValue->Length;\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    status = PhCreateFile(\n        &fileHandle,\n        FileName,\n        FILE_GENERIC_WRITE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = NtWriteFile(fileHandle, NULL, NULL, NULL, &isb, buffer, (ULONG)totalSize, NULL, NULL);\n        NtClose(fileHandle);\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nstatic BOOLEAN NTAPI PhSettingsKeyCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PKEY_VALUE_FULL_INFORMATION Information,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_STRINGREF settingName;\n    PH_STRINGREF settingValue;\n    PPH_SETTING setting;\n\n    settingName.Buffer = Information->Name;\n    settingName.Length = Information->NameLength;\n    settingValue.Buffer = PTR_ADD_OFFSET(Information, Information->DataOffset);\n    settingValue.Length = Information->DataLength - (Information->Type == REG_SZ ? sizeof(UNICODE_NULL) : 0);\n\n    if (setting = PhpLookupSetting(&settingName))\n    {\n        PhpFreeSettingValue(setting->Type, setting);\n\n        switch (setting->Type)\n        {\n        case StringSettingType:\n            {\n                if (PhSettingFromString(\n                    setting->Type,\n                    &settingValue,\n                    NULL,\n                    setting\n                    ))\n                {\n                    return TRUE;\n                }\n\n                if (PhSettingFromString(\n                    setting->Type,\n                    &setting->DefaultValue,\n                    NULL,\n                    setting\n                    ))\n                {\n                    return TRUE;\n                }\n            }\n            break;\n        case IntegerSettingType:\n            {\n                if (Information->Type == REG_DWORD)\n                {\n                    PLARGE_INTEGER value = PTR_ADD_OFFSET(Information, Information->DataOffset);\n\n                    setting->u.Integer = value->LowPart;\n                    return TRUE;\n                }\n                else if (Information->Type == REG_SZ)\n                {\n                    if (PhSettingFromString(setting->Type, &settingValue, NULL, setting))\n                        return TRUE;\n                }\n            }\n            break;\n        case IntegerPairSettingType:\n            {\n                if (Information->Type == REG_QWORD)\n                {\n                    PLARGE_INTEGER value = PTR_ADD_OFFSET(Information, Information->DataOffset);\n\n                    setting->u.IntegerPair.X = (LONG)value->LowPart;\n                    setting->u.IntegerPair.Y = (LONG)value->HighPart;\n                    return TRUE;\n                }\n                else if (Information->Type == REG_SZ)\n                {\n                    if (PhSettingFromString(setting->Type, &settingValue, NULL, setting))\n                        return TRUE;\n                }\n            }\n            break;\n        case ScalableIntegerPairSettingType:\n            {\n                if (Information->Type == REG_BINARY)\n                {\n                    PPH_SCALABLE_INTEGER_PAIR value = PTR_ADD_OFFSET(Information, Information->DataOffset);\n\n                    setting->u.Pointer = PhAllocateCopy(value, sizeof(PH_SCALABLE_INTEGER_PAIR));\n                    return TRUE;\n                }\n                else if (Information->Type == REG_SZ)\n                {\n                    if (PhSettingFromString(setting->Type, &settingValue, NULL, setting))\n                        return TRUE;\n                }\n            }\n            break;\n        }\n\n        assert(FALSE);\n    }\n    else\n    {\n        setting = PhAllocateZero(sizeof(PH_SETTING));\n        setting->Type = StringSettingType;\n        setting->Name.Buffer = PhAllocateCopy(settingName.Buffer, settingName.Length + sizeof(WCHAR));\n        setting->Name.Length = settingName.Length;\n        setting->u.Pointer = PhCreateString2(&settingValue);\n\n        PhAddItemList(PhIgnoredSettings, setting);\n    }\n\n    return TRUE;\n}\n\nstatic VOID PhpSaveSettingsToKey(\n    _In_ HANDLE KeyHandle\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SETTING setting;\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        switch (setting->Type)\n        {\n        case StringSettingType:\n            {\n                PPH_STRING value = (PPH_STRING)setting->u.Pointer;\n\n                if (PhIsNullOrEmptyString(value))\n                {\n                    PhDeleteValueKey(KeyHandle, &setting->Name);\n                }\n                else\n                {\n                    PhSetValueKey(\n                        KeyHandle,\n                        &setting->Name,\n                        REG_SZ,\n                        value->Buffer,\n                        (ULONG)value->Length + sizeof(UNICODE_NULL)\n                        );\n                }\n            }\n            break;\n        case IntegerSettingType:\n            {\n                if (setting->u.Integer)\n                {\n                    PhSetValueKey(\n                        KeyHandle,\n                        &setting->Name,\n                        REG_DWORD,\n                        &setting->u.Integer,\n                        sizeof(setting->u.Integer)\n                        );\n                }\n                else\n                {\n                    PhDeleteValueKey(KeyHandle, &setting->Name);\n                }\n            }\n            break;\n        case IntegerPairSettingType:\n            {\n                PPH_INTEGER_PAIR integerPair = &setting->u.IntegerPair;\n                LARGE_INTEGER value;\n\n                value.LowPart = integerPair->X;\n                value.HighPart = integerPair->Y;\n\n                if (value.QuadPart)\n                {\n                    PhSetValueKey(\n                        KeyHandle,\n                        &setting->Name,\n                        REG_QWORD,\n                        &value.QuadPart,\n                        sizeof(value.QuadPart)\n                        );\n                }\n                else\n                {\n                    PhDeleteValueKey(KeyHandle, &setting->Name);\n                }\n            }\n            break;\n        case ScalableIntegerPairSettingType:\n            {\n                PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = setting->u.Pointer;\n\n                if (scalableIntegerPair && scalableIntegerPair->X && scalableIntegerPair->Y && scalableIntegerPair->Scale)\n                {\n                    PhSetValueKey(\n                        KeyHandle,\n                        &setting->Name,\n                        REG_BINARY,\n                        scalableIntegerPair,\n                        sizeof(PH_SCALABLE_INTEGER_PAIR)\n                        );\n                }\n                else\n                {\n                    PhDeleteValueKey(KeyHandle, &setting->Name);\n                }\n            }\n            break;\n        default:\n            {\n                PPH_STRING settingValue = PhSettingToString(setting->Type, setting);\n\n                PhSetValueKey(\n                    KeyHandle,\n                    &setting->Name,\n                    REG_SZ,\n                    settingValue->Buffer,\n                    (ULONG)settingValue->Length + sizeof(UNICODE_NULL)\n                    );\n\n                PhDereferenceObject(settingValue);\n            }\n            break;\n        }\n    }\n\n    for (ULONG i = 0; i < PhIgnoredSettings->Count; i++)\n    {\n        setting = PhIgnoredSettings->Items[i];\n\n        switch (setting->Type)\n        {\n        case StringSettingType:\n            {\n                PPH_STRING value = (PPH_STRING)setting->u.Pointer;\n\n                if (PhIsNullOrEmptyString(value))\n                {\n                    PhDeleteValueKey(KeyHandle, &setting->Name);\n                }\n                else\n                {\n                    PhSetValueKey(\n                        KeyHandle,\n                        &setting->Name,\n                        REG_SZ,\n                        value->Buffer,\n                        (ULONG)value->Length + sizeof(UNICODE_NULL)\n                        );\n                }\n            }\n            break;\n        case IntegerSettingType:\n            {\n                if (setting->u.Integer)\n                {\n                    PhSetValueKey(\n                        KeyHandle,\n                        &setting->Name,\n                        REG_DWORD,\n                        &setting->u.Integer,\n                        sizeof(setting->u.Integer)\n                        );\n                }\n                else\n                {\n                    PhDeleteValueKey(KeyHandle, &setting->Name);\n                }\n            }\n            break;\n        case IntegerPairSettingType:\n            {\n                PPH_INTEGER_PAIR integerPair = &setting->u.IntegerPair;\n                LARGE_INTEGER value;\n\n                value.LowPart = integerPair->X;\n                value.HighPart = integerPair->Y;\n\n                if (value.QuadPart)\n                {\n                    PhSetValueKey(\n                        KeyHandle,\n                        &setting->Name,\n                        REG_QWORD,\n                        &value.QuadPart,\n                        sizeof(value.QuadPart)\n                        );\n                }\n                else\n                {\n                    PhDeleteValueKey(KeyHandle, &setting->Name);\n                }\n            }\n            break;\n        case ScalableIntegerPairSettingType:\n            {\n                PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = setting->u.Pointer;\n\n                if (scalableIntegerPair && scalableIntegerPair->X && scalableIntegerPair->Y && scalableIntegerPair->Scale)\n                {\n                    PhSetValueKey(\n                        KeyHandle,\n                        &setting->Name,\n                        REG_BINARY,\n                        scalableIntegerPair,\n                        sizeof(PH_SCALABLE_INTEGER_PAIR)\n                        );\n                }\n                else\n                {\n                    PhDeleteValueKey(KeyHandle, &setting->Name);\n                }\n            }\n            break;\n        default:\n            {\n                PPH_STRING settingValue = PhSettingToString(setting->Type, setting);\n\n                PhSetValueKey(\n                    KeyHandle,\n                    &setting->Name,\n                    REG_SZ,\n                    settingValue->Buffer,\n                    (ULONG)settingValue->Length + sizeof(UNICODE_NULL)\n                    );\n\n                PhDereferenceObject(settingValue);\n            }\n            break;\n        }\n    }\n}\n\nNTSTATUS PhLoadSettingsAppKey(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = PhLoadAppKey(\n        &keyHandle,\n        FileName,\n        KEY_ALL_ACCESS,\n        REG_APP_HIVE | REG_PROCESS_PRIVATE | REG_HIVE_NO_RM\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    status = PhEnumerateValueKey(\n        keyHandle,\n        KeyValueFullInformation,\n        PhSettingsKeyCallback,\n        NULL\n        );\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n    NtClose(keyHandle);\n\n    return status;\n}\n\nNTSTATUS PhSaveSettingsAppKey(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = PhLoadAppKey(\n        &keyHandle,\n        FileName,\n        KEY_ALL_ACCESS,\n        REG_APP_HIVE | REG_PROCESS_PRIVATE | REG_HIVE_NO_RM\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    PhpSaveSettingsToKey(keyHandle);\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    NtClose(keyHandle);\n\n    return status;\n}\n\nNTSTATUS PhLoadSettingsKey(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF keyName = PH_STRINGREF_INIT(L\"Software\\\\SystemInformer\");\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_CURRENT_USER,\n        &keyName,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    status = PhEnumerateValueKey(\n        keyHandle,\n        KeyValueFullInformation,\n        PhSettingsKeyCallback,\n        NULL\n        );\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n    NtClose(keyHandle);\n\n    return status;\n}\n\nNTSTATUS PhSaveSettingsKey(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF keyName = PH_STRINGREF_INIT(L\"Software\\\\SystemInformer\");\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = PhCreateKey(\n        &keyHandle,\n        KEY_WRITE,\n        PH_KEY_CURRENT_USER,\n        &keyName,\n        0,\n        0,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    PhpSaveSettingsToKey(keyHandle);\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    NtClose(keyHandle);\n\n    return status;\n}\n\nstatic BOOLEAN PhLoadSettingsEnumJsonCallback(\n    _In_ PVOID Object,\n    _In_ PCSTR Key,\n    _In_ PVOID Value,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_SETTING setting;\n    PPH_STRING settingName;\n\n    settingName = PhZeroExtendToUtf16(Key);\n\n    if (setting = PhpLookupSetting(&settingName->sr))\n    {\n        PhpFreeSettingValue(setting->Type, setting);\n\n        switch (setting->Type)\n        {\n        case IntegerSettingType:\n            {\n                if (PhGetJsonObjectType(Value) == PH_JSON_OBJECT_TYPE_INT)\n                {\n                    setting->u.Integer = PhGetJsonUInt32Object(Value);\n                    break;\n                }\n            }\n            goto DefaultCase;\n        case IntegerPairSettingType:\n            {\n                if (PhGetJsonObjectType(Value) == PH_JSON_OBJECT_TYPE_INT)\n                {\n                    ULARGE_INTEGER value;\n                    value.QuadPart = PhGetJsonUInt64Object(Value);\n                    setting->u.IntegerPair.X = (LONG)value.LowPart;\n                    setting->u.IntegerPair.Y = (LONG)value.HighPart;\n                    break;\n                }\n            }\n            goto DefaultCase;\n        case StringSettingType:\n        case ScalableIntegerPairSettingType:\nDefaultCase:\n            {\n                PPH_STRING settingValue;\n\n                settingValue = PhGetJsonObjectString(Value);\n\n                if (settingValue)\n                {\n                    PhSetReference(&setting->u.Pointer, settingValue);\n                }\n                else\n                {\n                    setting->u.Pointer = PhReferenceEmptyString();\n                }\n\n                if (!PhSettingFromString(\n                    setting->Type,\n                    &settingValue->sr,\n                    settingValue,\n                    setting\n                    ))\n                {\n                    PhSettingFromString(\n                        setting->Type,\n                        &setting->DefaultValue,\n                        NULL,\n                        setting\n                        );\n                }\n            }\n            break;\n        }\n    }\n    else\n    {\n        PPH_STRING settingValue;\n\n        settingValue = PhGetJsonObjectString(Value);\n\n        setting = PhAllocateZero(sizeof(PH_SETTING));\n        setting->Type = StringSettingType;\n        setting->Name.Buffer = PhAllocateCopy(settingName->Buffer, settingName->Length + sizeof(WCHAR));\n        setting->Name.Length = settingName->Length;\n        PhReferenceObject(settingValue);\n        setting->u.Pointer = settingValue;\n\n        PhAddItemList(PhIgnoredSettings, setting);\n    }\n\n    PhDereferenceObject(settingName);\n    return TRUE;\n}\n\nNTSTATUS PhLoadSettingsJson(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    PVOID object;\n\n    status = PhLoadJsonObjectFromFile(&object, FileName);\n\n    if (NT_SUCCESS(status))\n    {\n        if (PhGetJsonObjectType(object) == PH_JSON_OBJECT_TYPE_OBJECT)\n        {\n            PhAcquireQueuedLockExclusive(&PhSettingsLock);\n            PhEnumJsonArrayObject(object, PhLoadSettingsEnumJsonCallback, NULL);\n            PhReleaseQueuedLockExclusive(&PhSettingsLock);\n        }\n\n        PhFreeJsonObject(object);\n    }\n\n    return status;\n}\n\nNTSTATUS PhSaveSettingsJson(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    PVOID object;\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SETTING setting;\n    PPH_LIST strings = NULL;\n\n    object = PhCreateJsonObject();\n\n    if (!object)\n        return STATUS_FILE_CORRUPT_ERROR;\n\n    strings = PhCreateList(1);\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        switch (setting->Type)\n        {\n        //case IntegerSettingType:\n        //    {\n        //        PPH_BYTES stringName = PhConvertStringRefToUtf8(&setting->Name);\n        //        PhAddJsonObjectInt64(object, stringName->Buffer, setting->u.Integer);\n        //        PhAddItemList(strings, stringName);\n        //    }\n        //    break;\n        //case IntegerPairSettingType:\n        //    {\n        //        PPH_BYTES stringName = PhConvertStringRefToUtf8(&setting->Name);\n        //        ULARGE_INTEGER value;\n        //\n        //        value.LowPart = setting->u.IntegerPair.X;\n        //        value.HighPart = setting->u.IntegerPair.Y;\n        //        PhAddJsonObjectUInt64(object, stringName->Buffer, value.QuadPart);\n        //        PhAddItemList(strings, stringName);\n        //    }\n        //    break;\n        case IntegerSettingType:\n        case IntegerPairSettingType:\n        case StringSettingType:\n        case ScalableIntegerPairSettingType:\n            {\n                PPH_STRING stringSetting;\n                PPH_BYTES stringName;\n                PPH_BYTES stringValue;\n\n                stringName = PhConvertStringRefToUtf8(&setting->Name);\n                stringSetting = PhSettingToString(setting->Type, setting);\n                stringValue = PhConvertStringToUtf8(stringSetting);\n\n                PhAddJsonObject2(object, stringName->Buffer, stringValue->Buffer, stringValue->Length);\n\n                PhAddItemList(strings, stringValue);\n                PhAddItemList(strings, stringSetting);\n                PhAddItemList(strings, stringName);\n            }\n            break;\n        }\n    }\n\n    for (ULONG i = 0; i < PhIgnoredSettings->Count; i++)\n    {\n        PPH_STRING stringSetting;\n        PPH_BYTES stringName;\n        PPH_BYTES stringValue;\n\n        setting = PhIgnoredSettings->Items[i];\n\n        stringSetting = setting->u.Pointer;\n        stringName = PhConvertStringRefToUtf8(&setting->Name);\n        stringValue = PhConvertStringToUtf8(stringSetting);\n\n        PhAddJsonObject2(object, stringName->Buffer, stringValue->Buffer, stringValue->Length);\n\n        PhAddItemList(strings, stringValue);\n        PhAddItemList(strings, stringName);\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    status = PhSaveJsonObjectToFile(\n        FileName,\n        object,\n        PH_JSON_TO_STRING_PRETTY\n        );\n\n    PhFreeJsonObject(object);\n\n    PhDereferenceObjects(strings->Items, strings->Count);\n    PhDereferenceObject(strings);\n\n    return status;\n}\n\nNTSTATUS PhLoadSettingsXml(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    PVOID topNode;\n    PVOID currentNode;\n    PPH_SETTING setting;\n    PPH_STRING settingName;\n    PPH_STRING settingValue;\n\n    PhpClearIgnoredSettings();\n\n    if (!NT_SUCCESS(status = PhLoadXmlObjectFromFile(FileName, &topNode)))\n        return status;\n    if (!topNode) // Return corrupt status and reset the settings.\n        return STATUS_FILE_CORRUPT_ERROR;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    currentNode = PhGetXmlNodeFirstChild(topNode);\n\n    while (currentNode)\n    {\n        if (settingName = PhGetXmlNodeAttributeText(currentNode, \"name\"))\n        {\n            PH_STRINGREF name = settingName->sr;\n\n            if (PhIsLegacyPrefix(&name))\n            {\n                PhSkipStringRef(&name, 14 * sizeof(WCHAR));\n            }\n\n            settingValue = PhGetXmlNodeOpaqueText(currentNode);\n\n            {\n                if (setting = PhpLookupSetting(&name))\n                {\n                    PhpFreeSettingValue(setting->Type, setting);\n\n                    if (!PhSettingFromString(\n                        setting->Type,\n                        &settingValue->sr,\n                        settingValue,\n                        setting\n                        ))\n                    {\n                        PhSettingFromString(\n                            setting->Type,\n                            &setting->DefaultValue,\n                            NULL,\n                            setting\n                            );\n                    }\n                }\n                else\n                {\n                    setting = PhAllocateZero(sizeof(PH_SETTING));\n                    setting->Type = StringSettingType;\n                    setting->Name.Buffer = PhAllocateCopy(settingName->Buffer, settingName->Length + sizeof(WCHAR));\n                    setting->Name.Length = settingName->Length;\n                    PhReferenceObject(settingValue);\n                    setting->u.Pointer = settingValue;\n\n                    PhAddItemList(PhIgnoredSettings, setting);\n                }\n            }\n\n            PhDereferenceObject(settingValue);\n            PhDereferenceObject(settingName);\n        }\n\n        currentNode = PhGetXmlNodeNextChild(currentNode);\n    }\n\n    PhFreeXmlObject(topNode);\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n    return STATUS_SUCCESS;\n}\n\n//static BOOLEAN PhXmlLiteInitialized(\n//    VOID\n//    )\n//{\n//    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n//    static BOOLEAN XmlLiteInitialized = FALSE;\n//\n//    if (PhBeginInitOnce(&initOnce))\n//    {\n//        if (CreateXmlReader_Import() && CreateXmlWriter_Import() && SHCreateStreamOnFileEx_Import())\n//        {\n//            XmlLiteInitialized = TRUE;\n//        }\n//\n//        PhEndInitOnce(&initOnce);\n//    }\n//\n//    return XmlLiteInitialized;\n//}\n//\n//HRESULT PhLoadSettingsXmlRead(\n//    _In_ PCWSTR FileName\n//    )\n//{\n//    HRESULT status;\n//    IXmlReader* xmlReader = NULL;\n//    IStream* fileStream = NULL;\n//    PPH_SETTING setting;\n//    SIZE_T settingBufferLength;\n//    WCHAR settingBuffer[0x1000];\n//    PH_STRINGREF settingName;\n//    PH_STRINGREF settingValue;\n//    XmlNodeType nodeType;\n//    PCWSTR nodeName;\n//    PCWSTR attrName;\n//\n//    status = SHCreateStreamOnFileEx_Import()(\n//        FileName,\n//        STGM_READ | STGM_SIMPLE,\n//        FILE_ATTRIBUTE_NORMAL,\n//        FALSE,\n//        NULL,\n//        &fileStream\n//        );\n//\n//    if (HR_FAILED(status))\n//        goto CleanupExit;\n//\n//    status = CreateXmlReader_Import()(&IID_IXmlReader, &xmlReader, NULL);\n//\n//    if (HR_FAILED(status))\n//        goto CleanupExit;\n//\n//    IXmlReader_SetProperty(xmlReader, XmlReaderProperty_DtdProcessing, DtdProcessing_Prohibit);\n//\n//    status = IXmlReader_SetInput(xmlReader, (IUnknown*)fileStream);\n//\n//    if (HR_FAILED(status))\n//        goto CleanupExit;\n//\n//    while (HR_SUCCESS(IXmlReader_Read(xmlReader, &nodeType)))\n//    {\n//        if (nodeType == XmlNodeType_Element)\n//        {\n//            if (HR_SUCCESS(IXmlReader_GetLocalName(xmlReader, &nodeName, NULL)))\n//            {\n//                if (PhEqualStringZ(nodeName, L\"setting\", TRUE))\n//                {\n//                    if (HR_SUCCESS(IXmlReader_MoveToFirstAttribute(xmlReader)))\n//                    {\n//                        if (HR_SUCCESS(IXmlReader_GetLocalName(xmlReader, &attrName, NULL)))\n//                        {\n//                            if (PhEqualStringZ(attrName, L\"name\", TRUE))\n//                            {\n//                                ULONG nameStringLength = 0;\n//                                PCWSTR nameStringBuffer;\n//\n//                                if (HR_SUCCESS(IXmlReader_GetValue(xmlReader, &nameStringBuffer, &nameStringLength)))\n//                                {\n//                                    settingBufferLength = nameStringLength * sizeof(WCHAR);\n//\n//                                    if (settingBufferLength % 2 != 0)\n//                                        continue;\n//                                    if (settingBufferLength > sizeof(settingBuffer))\n//                                        continue;\n//\n//                                    // Note: IXmlReader_GetValue returns a pointer to the string offset in the IStream buffer.\n//                                    // Copy the string since since the offset might be invalid after the next buffer read. (dmex)\n//                                    memcpy(settingBuffer, nameStringBuffer, settingBufferLength);\n//                                    settingName.Buffer = settingBuffer;\n//                                    settingName.Length = settingBufferLength;\n//\n//                                    if (HR_SUCCESS(IXmlReader_Read(xmlReader, &nodeType)) && nodeType == XmlNodeType_Text)\n//                                    {\n//                                        ULONG valueStringLength = 0;\n//                                        PCWSTR valueStringBuffer;\n//\n//                                        if (HR_SUCCESS(IXmlReader_GetValue(xmlReader, &valueStringBuffer, &valueStringLength)))\n//                                        {\n//                                            settingBufferLength = valueStringLength * sizeof(WCHAR);\n//\n//                                            if (settingBufferLength % 2 != 0)\n//                                                continue;\n//\n//                                            settingValue.Buffer = (PWCH)valueStringBuffer;\n//                                            settingValue.Length = settingBufferLength;\n//\n//                                            {\n//                                                setting = PhpLookupSetting(&settingName);\n//\n//                                                if (setting)\n//                                                {\n//                                                    PhpFreeSettingValue(setting->Type, setting);\n//\n//                                                    if (!PhSettingFromString(\n//                                                        setting->Type,\n//                                                        &settingValue,\n//                                                        NULL,\n//                                                        setting\n//                                                        ))\n//                                                    {\n//                                                        PhSettingFromString(\n//                                                            setting->Type,\n//                                                            &setting->DefaultValue,\n//                                                            NULL,\n//                                                            setting\n//                                                            );\n//                                                    }\n//                                                }\n//                                                else\n//                                                {\n//                                                    setting = PhAllocate(sizeof(PH_SETTING));\n//                                                    setting->Name.Buffer = PhAllocateCopy(settingName.Buffer, settingName.Length + sizeof(UNICODE_NULL));\n//                                                    setting->Name.Length = settingName.Length;\n//                                                    setting->u.Pointer = PhCreateString2(&settingValue);\n//\n//                                                    PhAddItemList(PhIgnoredSettings, setting);\n//                                                }\n//                                            }\n//                                        }\n//                                    }\n//                                }\n//                            }\n//                        }\n//                    }\n//                }\n//            }\n//        }\n//    }\n//\n//CleanupExit:\n//    if (xmlReader) IXmlReader_Release(xmlReader);\n//    if (fileStream) IStream_Release(fileStream);\n//\n//    return status;\n//}\n//\n//NTSTATUS PhLoadSettingsXmlLite(\n//    _In_ PCPH_STRINGREF FileName\n//    )\n//{\n//    HRESULT status;\n//    PPH_STRING fileNameWin32;\n//\n//    fileNameWin32 = PhResolveDevicePrefix(FileName);\n//\n//    if (PhIsNullOrEmptyString(fileNameWin32))\n//        return STATUS_UNSUCCESSFUL;\n//\n//    PhMoveReference(&fileNameWin32, PhConcatStringRef2(&PhWin32ExtendedPathPrefix, &fileNameWin32->sr));\n//\n//    PhpClearIgnoredSettings();\n//\n//    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n//    status = PhLoadSettingsXmlRead(PhGetString(fileNameWin32));\n//    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n//\n//    PhDereferenceObject(fileNameWin32);\n//\n//    if (HR_FAILED(status))\n//        return STATUS_UNSUCCESSFUL; // HRESULT_CODE(status);\n//    return STATUS_SUCCESS;\n//}\n//\n//DEFINE_GUID(IID_IXmlWriterLite, 0x862494C6, 0x1310, 0x4AAD, 0xB3, 0xCD, 0x2D, 0xBE, 0xEB, 0xF6, 0x70, 0xD3);\n//\n//HRESULT PhSaveSettingsXmlWrite(\n//    _In_ PCWSTR FileName\n//    )\n//{\n//    HRESULT status;\n//    PH_AUTO_POOL autoPool;\n//    IStream* fileStream = NULL;\n//    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n//    PPH_SETTING setting;\n//\n//    status = SHCreateStreamOnFileEx_Import()(\n//        FileName,\n//        STGM_WRITE | STGM_CREATE,\n//        FILE_ATTRIBUTE_NORMAL,\n//        TRUE,\n//        NULL,\n//        &fileStream\n//        );\n//\n//    if (HR_FAILED(status))\n//        return status;\n//\n//    PhInitializeAutoPool(&autoPool);\n//\n//    {\n//        IXmlWriter* xmlWriter = NULL;\n//\n//        status = CreateXmlWriter_Import()(&IID_IXmlWriter, &xmlWriter, NULL);\n//\n//        if (HR_FAILED(status))\n//            goto CleanupExit;\n//\n//        IXmlWriter_SetProperty(xmlWriter, XmlWriterProperty_Indent, TRUE);\n//        IXmlWriter_SetProperty(xmlWriter, XmlWriterProperty_OmitXmlDeclaration, TRUE);\n//\n//        status = IXmlWriter_SetOutput(xmlWriter, (IUnknown*)fileStream);\n//\n//        if (HR_FAILED(status))\n//            goto CleanupExit;\n//\n//        IXmlWriter_WriteStartElement(xmlWriter, NULL, L\"settings\", NULL);\n//\n//        PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n//\n//        while (setting = PhNextEnumHashtable(&enumContext))\n//        {\n//            PPH_STRING settingValue;\n//\n//            settingValue = PH_AUTO_T(PH_STRING, PhSettingToString(setting->Type, setting));\n//            IXmlWriter_WriteStartElement(xmlWriter, NULL, L\"setting\", NULL);\n//            IXmlWriter_WriteAttributeString(xmlWriter, NULL, L\"name\", NULL, PhGetStringRefZ(&setting->Name));\n//            IXmlWriter_WriteString(xmlWriter, PhGetStringRefZ(&settingValue->sr));\n//            IXmlWriter_WriteEndElement(xmlWriter);\n//        }\n//\n//        for (ULONG i = 0; i < PhIgnoredSettings->Count; i++)\n//        {\n//            PPH_STRING settingValue;\n//\n//            setting = PhIgnoredSettings->Items[i];\n//            settingValue = setting->u.Pointer;\n//\n//            IXmlWriter_WriteStartElement(xmlWriter, NULL, L\"setting\", NULL);\n//            IXmlWriter_WriteAttributeString(xmlWriter, NULL, L\"name\", NULL, PhGetStringRefZ(&setting->Name));\n//            IXmlWriter_WriteString(xmlWriter, PhGetStringRefZ(&settingValue->sr));\n//            IXmlWriter_WriteEndElement(xmlWriter);\n//        }\n//\n//        IXmlWriter_WriteEndElement(xmlWriter);\n//\n//        status = IXmlWriter_Flush(xmlWriter);\n//\n//        IXmlWriter_Release(xmlWriter);\n//    }\n//\n//    //{\n//    //    IXmlWriterLite* xmlWriterLite = NULL;\n//    //\n//    //    status = CreateXmlWriter_Import()(&IID_IXmlWriterLite, &xmlWriterLite, NULL);\n//    //\n//    //    if (HR_FAILED(status))\n//    //        goto CleanupExit;\n//    //\n//    //    status = IXmlWriterLite_SetOutput(xmlWriterLite, (IUnknown*)fileStream);\n//    //\n//    //    if (HR_FAILED(status))\n//    //        goto CleanupExit;\n//\n//    //    IXmlWriterLite_WriteStartElement(xmlWriterLite, L\"settings\", 8);\n//    //    IXmlWriterLite_WriteWhitespace(xmlWriterLite, L\"\\n\");\n//    //\n//    //    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n//    //\n//    //    while (setting = PhNextEnumHashtable(&enumContext))\n//    //    {\n//    //        PPH_STRING settingValue;\n//    //\n//    //        settingValue = PhSettingToString(setting->Type, setting);\n//    //        IXmlWriterLite_WriteStartElement(xmlWriterLite, L\"setting\", 7);\n//    //        IXmlWriterLite_WriteAttributeString(xmlWriterLite, L\"name\", 4, setting->Name.Buffer, (ULONG)setting->Name.Length / sizeof(WCHAR));\n//    //        IXmlWriterLite_WriteString(xmlWriterLite, PhGetStringRefZ(&settingValue->sr));\n//    //        //IXmlWriterLite_WriteChars(xmlWriterLite, settingValue->Buffer, (ULONG)settingValue->Length / sizeof(WCHAR));\n//    //        IXmlWriterLite_WriteEndElement(xmlWriterLite, L\"setting\", 7);\n//    //        IXmlWriterLite_WriteWhitespace(xmlWriterLite, L\"\\n\");\n//    //        PhDereferenceObject(settingValue);\n//    //    }\n//    //\n//    //    // Write the ignored settings.\n//    //\n//    //    for (ULONG i = 0; i < PhIgnoredSettings->Count; i++)\n//    //    {\n//    //        PPH_STRING settingValue;\n//    //\n//    //        setting = PhIgnoredSettings->Items[i];\n//    //        settingValue = setting->u.Pointer;\n//    //        IXmlWriterLite_WriteStartElement(xmlWriterLite, L\"setting\", 7);\n//    //        IXmlWriterLite_WriteAttributeString(xmlWriterLite, L\"name\", 4, setting->Name.Buffer, (ULONG)setting->Name.Length / sizeof(WCHAR));\n//    //        IXmlWriterLite_WriteString(xmlWriterLite, PhGetStringRefZ(&settingValue->sr));\n//    //        IXmlWriterLite_WriteEndElement(xmlWriterLite, L\"setting\", 7);\n//    //        IXmlWriterLite_WriteWhitespace(xmlWriterLite, L\"\\n\");\n//    //    }\n//    //\n//    //    IXmlWriterLite_WriteEndElement(xmlWriterLite, L\"settings\", 8);\n//\n//    //    status = IXmlWriterLite_Flush(xmlWriterLite);\n//    //\n//    //    IXmlWriterLite_Release(xmlWriterLite);\n//    //}\n//\n//CleanupExit:\n//    //IStream_Commit(fileStream, STGC_DEFAULT);\n//    IStream_Release(fileStream);\n//\n//    PhDeleteAutoPool(&autoPool);\n//\n//    return status;\n//}\n//\n//NTSTATUS PhSaveSettingsXmlLite(\n//    _In_ PCPH_STRINGREF FileName\n//    )\n//{\n//    static CONST PH_STRINGREF extension = PH_STRINGREF_INIT(L\".tmp\");\n//    HRESULT status;\n//    PPH_STRING fileNameWin32;\n//    PPH_STRING fileNameTempWin32;\n//\n//    fileNameWin32 = PhResolveDevicePrefix(FileName);\n//\n//    if (PhIsNullOrEmptyString(fileNameWin32))\n//        return STATUS_UNSUCCESSFUL;\n//\n//    // TODO: Write XmlLite to buffer and atomic rename (same as PhSaveXmlObjectToFile) (dmex)\n//    PhMoveReference(&fileNameWin32, PhConcatStringRef2(&PhWin32ExtendedPathPrefix, &fileNameWin32->sr));\n//    fileNameTempWin32 = PhConcatStringRef2(&fileNameWin32->sr, &extension);\n//\n//    PhpClearIgnoredSettings();\n//\n//    PhAcquireQueuedLockShared(&PhSettingsLock);\n//    status = PhSaveSettingsXmlWrite(PhGetString(fileNameTempWin32));\n//    PhReleaseQueuedLockShared(&PhSettingsLock);\n//\n//    if (HR_FAILED(status))\n//    {\n//        PhDereferenceObject(fileNameTempWin32);\n//        PhDereferenceObject(fileNameWin32);\n//        return STATUS_UNSUCCESSFUL; // HRESULT_CODE(status);\n//    }\n//\n//    status = PhMoveFileWin32(\n//        PhGetString(fileNameTempWin32),\n//        PhGetString(fileNameWin32),\n//        FALSE\n//        );\n//\n//    PhDereferenceObject(fileNameTempWin32);\n//    PhDereferenceObject(fileNameWin32);\n//    return status;\n//}\n\nPCSTR PhpSettingsSaveCallback(\n    _In_ PVOID cbdata,\n    _In_ PVOID node,\n    _In_ LONG when\n    )\n{\n    PCSTR elementName;\n\n    if (!(elementName = PhGetXmlNodeElementText(node)))\n        return NULL;\n\n    if (PhEqualBytesZ(elementName, \"setting\", TRUE))\n    {\n        if (when == MXML_WS_BEFORE_OPEN)\n            return \"  \";\n        else if (when == MXML_WS_AFTER_CLOSE)\n            return \"\\r\\n\";\n    }\n    else if (PhEqualBytesZ(elementName, \"settings\", TRUE))\n    {\n        if (when == MXML_WS_AFTER_OPEN)\n            return \"\\r\\n\";\n    }\n\n    return NULL;\n}\n\nPVOID PhpCreateSettingElement(\n    _Inout_ PVOID ParentNode,\n    _In_ PCPH_STRINGREF SettingName,\n    _In_ PCPH_STRINGREF SettingValue\n    )\n{\n    PVOID settingNode;\n    PPH_BYTES settingNameUtf8;\n    PPH_BYTES settingValueUtf8;\n\n    // Create the setting element.\n\n    settingNode = PhCreateXmlNode(ParentNode, \"setting\");\n\n    settingNameUtf8 = PhConvertUtf16ToUtf8Ex(SettingName->Buffer, SettingName->Length);\n    PhSetXmlNodeAttributeText(settingNode, \"name\", settingNameUtf8->Buffer);\n    PhDereferenceObject(settingNameUtf8);\n\n    // Set the value.\n\n    settingValueUtf8 = PhConvertUtf16ToUtf8Ex(SettingValue->Buffer, SettingValue->Length);\n    PhCreateXmlOpaqueNode(settingNode, settingValueUtf8->Buffer);\n    PhDereferenceObject(settingValueUtf8);\n\n    return settingNode;\n}\n\nNTSTATUS PhSaveSettingsXml(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    PVOID topNode;\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SETTING setting;\n\n    topNode = PhCreateXmlNode(NULL, \"settings\");\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        PPH_STRING settingValue;\n\n        settingValue = PhSettingToString(setting->Type, setting);\n        PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr);\n        PhDereferenceObject(settingValue);\n    }\n\n    // Write the ignored settings.\n\n    for (ULONG i = 0; i < PhIgnoredSettings->Count; i++)\n    {\n        PPH_STRING settingValue;\n\n        setting = PhIgnoredSettings->Items[i];\n        settingValue = setting->u.Pointer;\n        PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr);\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    status = PhSaveXmlObjectToFile(\n        FileName,\n        topNode,\n        PhpSettingsSaveCallback\n        );\n    PhFreeXmlObject(topNode);\n\n    if (status == STATUS_SHARING_VIOLATION) // Skip multiple instances (dmex)\n        status = STATUS_SUCCESS;\n\n    return status;\n}\n\ntypedef struct _PH_SETTINGS_DISCOVERY_RESULT\n{\n    PH_SETTINGS_FORMAT Format;\n    PPH_STRING FilePath;\n    LARGE_INTEGER LastWriteTime;\n    BOOLEAN Found;\n} PH_SETTINGS_DISCOVERY_RESULT, *PPH_SETTINGS_DISCOVERY_RESULT;\n\nstatic ULONG PhpDiscoverSettingsStores(\n    _In_opt_ PPH_STRING BasePath,\n    _In_opt_ PCWSTR DefaultName,\n    _Out_writes_(PH_SETTINGS_STORE_COUNT) PPH_SETTINGS_DISCOVERY_RESULT Results,\n    _In_ ULONG ResultCount,\n    _Out_opt_ PBOOLEAN IsPortable\n    )\n{\n    ULONG foundCount = 0;\n\n    RtlZeroMemory(Results, sizeof(PH_SETTINGS_DISCOVERY_RESULT) * ResultCount);\n\n    if (IsPortable) *IsPortable = FALSE;\n\n    if (!BasePath)\n    {\n        PPH_STRING searchPath;\n\n        // 1. Portable\n        if (searchPath = PhGetApplicationFileNameZ(L\".settings\"))\n        {\n            foundCount = PhpDiscoverSettingsStores(searchPath, DefaultName, Results, ResultCount, NULL);\n            PhDereferenceObject(searchPath);\n            if (foundCount > 0)\n            {\n                if (IsPortable) *IsPortable = TRUE;\n                return foundCount;\n            }\n        }\n\n        // 2. AppData\n        if (DefaultName && (searchPath = PhGetRoamingAppDataDirectoryZ(DefaultName, TRUE)))\n        {\n            foundCount = PhpDiscoverSettingsStores(searchPath, DefaultName, Results, ResultCount, NULL);\n            PhDereferenceObject(searchPath);\n            if (foundCount > 0) return foundCount;\n        }\n    }\n\n    for (ULONG i = 0; i < PH_SETTINGS_STORE_COUNT; i++)\n// ... (omitting lines for brevity, but I will include them in the real tool call)\n    {\n        const PH_SETTINGS_STORE_DESCRIPTOR* store = &PhSettingsStores[i];\n\n        Results[i].Format = store->Format;\n        Results[i].Found = FALSE;\n\n        if (store->IsFileBased)\n        {\n            if (!BasePath)\n                continue;\n\n            PPH_STRING filePath = PhConcatStringRefZ(&BasePath->sr, store->Extension);\n\n            if (PhDoesFileExist(&filePath->sr))\n            {\n                FILE_NETWORK_OPEN_INFORMATION networkOpenInfo;\n\n                if (NT_SUCCESS(PhQueryFullAttributesFile(&filePath->sr, &networkOpenInfo)))\n                {\n                    Results[i].Found = TRUE;\n                    Results[i].FilePath = filePath;\n                    Results[i].LastWriteTime = networkOpenInfo.LastWriteTime;\n                    foundCount++;\n                }\n                else\n                {\n                    PhDereferenceObject(filePath);\n                }\n            }\n            else\n            {\n                PhDereferenceObject(filePath);\n            }\n        }\n        else if (store->Format == SettingsFormatReg)\n        {\n            if (BasePath)\n                continue;\n\n            static CONST PH_STRINGREF keyName = PH_STRINGREF_INIT(L\"Software\\\\SystemInformer\");\n            HANDLE keyHandle;\n\n            if (NT_SUCCESS(PhOpenKey(\n                &keyHandle,\n                KEY_READ,\n                PH_KEY_CURRENT_USER,\n                &keyName,\n                0\n                )))\n            {\n                //LARGE_INTEGER lastwriteTime = { 0 };\n                //PhQueryKeyLastWriteTime(keyHandle, &lastwriteTime);\n\n                Results[i].Found = TRUE;\n                Results[i].FilePath = NULL;\n                //Results[i].LastWriteTime = lastwriteTime;\n                foundCount++;\n                NtClose(keyHandle);\n            }\n        }\n    }\n\n    return foundCount;\n}\n\nstatic LONG PhpSelectBestSettingsStore(\n    _In_reads_(PH_SETTINGS_STORE_COUNT) PPH_SETTINGS_DISCOVERY_RESULT Results\n    )\n{\n    LONG preferredIndex = -1;\n    LONG newestIndex = -1;\n    LONG highestPriorityIndex = -1;\n    LARGE_INTEGER newestTime = { 0 };\n    LONG highestPriority = INT_MAX;\n\n    for (ULONG i = 0; i < PH_SETTINGS_STORE_COUNT; i++)\n    {\n        if (!Results[i].Found)\n            continue;\n\n        if (PhSettingsStores[i].IsPreferred)\n        {\n            preferredIndex = i;\n        }\n\n        if (PhSettingsStores[i].IsFileBased)\n        {\n            if (Results[i].LastWriteTime.QuadPart > newestTime.QuadPart)\n            {\n                newestTime = Results[i].LastWriteTime;\n                newestIndex = i;\n            }\n        }\n\n        if (PhSettingsStores[i].Priority < highestPriority)\n        {\n            highestPriority = PhSettingsStores[i].Priority;\n            highestPriorityIndex = i;\n        }\n    }\n\n    if (preferredIndex >= 0)\n        return preferredIndex;\n\n    if (newestIndex >= 0)\n        return newestIndex;\n\n    return highestPriorityIndex;\n}\n\nstatic VOID PhpFreeDiscoveryResults(\n    _In_reads_(PH_SETTINGS_STORE_COUNT) PPH_SETTINGS_DISCOVERY_RESULT Results\n    )\n{\n    for (ULONG i = 0; i < PH_SETTINGS_STORE_COUNT; i++)\n    {\n        if (Results[i].FilePath)\n        {\n            PhDereferenceObject(Results[i].FilePath);\n            Results[i].FilePath = NULL;\n        }\n    }\n}\n\nNTSTATUS PhLoadSettingsAutoDetect(\n    _In_opt_ PPH_STRING BasePath,\n    _In_opt_ PCWSTR DefaultName,\n    _Out_opt_ PPH_STRING* ActualPath,\n    _Out_opt_ PH_SETTINGS_FORMAT* ActualFormat,\n    _Out_opt_ PBOOLEAN IsPortable\n    )\n{\n    PH_SETTINGS_DISCOVERY_RESULT results[PH_SETTINGS_STORE_COUNT];\n    NTSTATUS status = STATUS_NOT_FOUND;\n    LONG selectedIndex;\n    ULONG foundCount;\n\n    foundCount = PhpDiscoverSettingsStores(BasePath, DefaultName, results, PH_SETTINGS_STORE_COUNT, IsPortable);\n\n    if (foundCount == 0)\n    {\n        if (ActualPath)\n        {\n            PPH_STRING searchPath = NULL;\n\n            if (BasePath)\n            {\n                searchPath = PhReferenceObject(BasePath);\n            }\n            else if (DefaultName)\n            {\n                searchPath = PhGetRoamingAppDataDirectoryZ(DefaultName, TRUE);\n            }\n\n            if (searchPath)\n            {\n                for (ULONG i = 0; i < PH_SETTINGS_STORE_COUNT; i++)\n                {\n                    if (PhSettingsStores[i].IsPreferred && PhSettingsStores[i].IsFileBased)\n                    {\n                        *ActualPath = PhConcatStringRefZ(&searchPath->sr, PhSettingsStores[i].Extension);\n                        if (ActualFormat)\n                            *ActualFormat = PhSettingsStores[i].Format;\n                        break;\n                    }\n                }\n                PhDereferenceObject(searchPath);\n            }\n        }\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n    }\n\n    selectedIndex = PhpSelectBestSettingsStore(results);\n\n    if (selectedIndex < 0)\n    {\n        status = STATUS_NOT_FOUND;\n        goto Cleanup;\n    }\n\n    const PH_SETTINGS_STORE_DESCRIPTOR* selectedStore = &PhSettingsStores[selectedIndex];\n\n    switch (selectedStore->Format)\n    {\n        case SettingsFormatJson:\n            status = PhLoadSettingsJson(&results[selectedIndex].FilePath->sr);\n            break;\n        case SettingsFormatXml:\n            status = PhLoadSettingsXml(&results[selectedIndex].FilePath->sr);\n            break;\n        case SettingsFormatKey:\n            status = PhLoadSettingsAppKey(&results[selectedIndex].FilePath->sr);\n            break;\n        case SettingsFormatReg:\n            status = PhLoadSettingsKey();\n            break;\n        case SettingsFormatBin:\n            status = PhLoadSettingsBin(&results[selectedIndex].FilePath->sr);\n            break;\n        default:\n            status = STATUS_NOT_SUPPORTED;\n            break;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (ActualPath)\n        {\n            if (results[selectedIndex].FilePath)\n                *ActualPath = PhReferenceObject(results[selectedIndex].FilePath);\n            else\n                *ActualPath = NULL;\n        }\n\n        if (ActualFormat)\n            *ActualFormat = selectedStore->Format;\n\n        PhSettingsLoadedFormat = selectedStore->Format;\n    }\n\nCleanup:\n    PhpFreeDiscoveryResults(results);\n    return status;\n}\n\nNTSTATUS PhLoadSettings(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status = STATUS_INVALID_PARAMETER;\n\n    // Detect format from extension\n    for (ULONG i = 0; i < PH_SETTINGS_STORE_COUNT; i++)\n    {\n        if (PhSettingsStores[i].IsFileBased &&\n            PhEndsWithStringRef2(FileName, PhSettingsStores[i].Extension, TRUE))\n        {\n            PhSettingsLoadedFormat = PhSettingsStores[i].Format;\n\n            switch (PhSettingsStores[i].Format)\n            {\n                case SettingsFormatBin:\n                    status = PhLoadSettingsBin(FileName);\n                    break;\n                case SettingsFormatJson:\n                    status = PhLoadSettingsJson(FileName);\n                    break;\n                case SettingsFormatXml:\n                    status = PhLoadSettingsXml(FileName);\n                    break;\n                case SettingsFormatKey:\n                    status = PhLoadSettingsAppKey(FileName);\n                    break;\n            }\n            break;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhSaveSettings(\n    _In_opt_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status = STATUS_INVALID_PARAMETER;\n\n    switch (PhSettingsLoadedFormat)\n    {\n    case SettingsFormatJson:\n        {\n            if (FileName)\n            {\n                status = PhSaveSettingsJson(FileName);\n            }\n        }\n        break;\n    case SettingsFormatXml:\n        {\n            if (FileName)\n            {\n                status = PhSaveSettingsXml(FileName);\n            }\n        }\n        break;\n    case SettingsFormatKey:\n        {\n            if (FileName)\n            {\n                status = PhSaveSettingsAppKey(FileName);\n            }\n        }\n        break;\n    case SettingsFormatReg:\n        {\n            status = PhSaveSettingsKey();\n        }\n        break;\n    case SettingsFormatBin:\n        {\n            if (FileName)\n            {\n                status = PhSaveSettingsBin(FileName);\n            }\n        }\n        break;\n    }\n\n    return status;\n}\n\nVOID PhResetSettings(\n    _In_ HWND hwnd\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SETTING setting;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        PhpFreeSettingValue(setting->Type, setting);\n        PhSettingFromString(setting->Type, &setting->DefaultValue, NULL, setting);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nNTSTATUS PhResetSettingsFile(\n    _In_ PCPH_STRINGREF FileName\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    PVOID data = NULL;\n    SIZE_T dataLength = 0;\n    CHAR jsonData[] = \"{}\";\n    CHAR xmlData[] = \"<settings></settings>\";\n    PH_SETTINGS_FORMAT detectedFormat = SettingsFormatJson;\n    PH_SETTINGS_BIN_HEADER binData = { PH_SETTINGS_BIN_SIGNATURE, PH_SETTINGS_BIN_VERSION, 0 };\n\n    // Detect format from file extension\n    for (ULONG i = 0; i < PH_SETTINGS_STORE_COUNT; i++)\n    {\n        if (PhSettingsStores[i].IsFileBased &&\n            PhEndsWithStringRef2(FileName, PhSettingsStores[i].Extension, TRUE))\n        {\n            detectedFormat = PhSettingsStores[i].Format;\n            break;\n        }\n    }\n\n    // Select appropriate reset data based on format\n    switch (detectedFormat)\n    {\n        case SettingsFormatJson:\n            data = jsonData;\n            dataLength = sizeof(jsonData) - 1;\n            break;\n        case SettingsFormatXml:\n            data = xmlData;\n            dataLength = sizeof(xmlData) - 1;\n            break;\n        case SettingsFormatKey:\n            // For AppKey/DAT files, delete and recreate is better\n            PhDeleteFile(FileName);\n            return STATUS_SUCCESS;\n        case SettingsFormatReg:\n            // Registry format doesn't use file - should not be called\n            return STATUS_NOT_SUPPORTED;\n        case SettingsFormatBin:\n            data = &binData;\n            dataLength = sizeof(PH_SETTINGS_BIN_HEADER);\n            break;\n        default:\n            // Unknown format - default to JSON\n            data = jsonData;\n            dataLength = sizeof(jsonData) - 1;\n            break;\n    }\n\n    // Overwrite the file with empty valid content\n    status = PhCreateFile(\n        &fileHandle,\n        FileName,\n        FILE_GENERIC_WRITE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PhWriteFile(fileHandle, data, (ULONG)dataLength, NULL, NULL);\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\nVOID PhAddSetting(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PCPH_STRINGREF Name,\n    _In_ PCPH_STRINGREF DefaultValue\n    )\n{\n    PH_SETTING setting;\n\n    memset(&setting, 0, sizeof(PH_SETTING));\n    setting.Type = Type;\n    setting.Name = *Name;\n    setting.DefaultValue = *DefaultValue;\n    memset(&setting.u, 0, sizeof(setting.u));\n\n    PhSettingFromString(Type, &setting.DefaultValue, NULL, &setting);\n\n    PhAddEntryHashtable(PhSettingsHashtable, &setting);\n}\n\nVOID PhAddSettings(\n    _In_ PPH_SETTING_CREATE Settings,\n    _In_ ULONG NumberOfSettings\n    )\n{\n    ULONG i;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    for (i = 0; i < NumberOfSettings; i++)\n    {\n        PH_STRINGREF name;\n        PH_STRINGREF defaultValue;\n\n        PhInitializeStringRefLongHint(&name, Settings[i].Name);\n        PhInitializeStringRefLongHint(&defaultValue, Settings[i].DefaultValue);\n        PhAddSetting(Settings[i].Type, &name, &defaultValue);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nPPH_SETTING PhGetSetting(\n    _In_ PCPH_STRINGREF Name\n    )\n{\n    PPH_SETTING setting;\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n    setting = PhpLookupSetting(Name);\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    return setting;\n}\n\nVOID PhLoadWindowPlacementFromRectangle(\n    _In_ PCWSTR PositionSettingName,\n    _In_ PCWSTR SizeSettingName,\n    _Inout_ PPH_RECTANGLE WindowRectangle\n    )\n{\n    PH_INTEGER_PAIR windowIntegerPair = { 0 };\n    PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = NULL;\n    LONG windowDpi;\n    RECT windowRect;\n\n    windowIntegerPair = PhGetIntegerPairSetting(PositionSettingName);\n    scalableIntegerPair = PhGetScalableIntegerPairSetting(SizeSettingName, FALSE, 0);\n\n    memset(WindowRectangle, 0, sizeof(PH_RECTANGLE));\n    WindowRectangle->Position = windowIntegerPair;\n    WindowRectangle->Size = scalableIntegerPair->Pair;\n\n    PhRectangleToRect(&windowRect, WindowRectangle);\n    windowDpi = PhGetMonitorDpi(NULL, &windowRect);\n\n    PhScalableIntegerPairToScale(scalableIntegerPair, windowDpi);\n    PhAdjustRectangleToWorkingArea(NULL, WindowRectangle);\n}\n\nBOOLEAN PhLoadWindowPlacementFromSetting(\n    _In_opt_ PCWSTR PositionSettingName,\n    _In_opt_ PCWSTR SizeSettingName,\n    _In_ HWND WindowHandle\n    )\n{\n    if (PositionSettingName && SizeSettingName)\n    {\n        PH_INTEGER_PAIR windowIntegerPair = { 0 };\n        PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = NULL;\n        PH_RECTANGLE windowRectangle = { 0 };\n        LONG dpi;\n        RECT rectForAdjust;\n\n        windowIntegerPair = PhGetIntegerPairSetting(PositionSettingName);\n        scalableIntegerPair = PhGetScalableIntegerPairSetting(SizeSettingName, FALSE, 0);\n        windowRectangle.Position = windowIntegerPair;\n        windowRectangle.Size = scalableIntegerPair->Pair;\n\n        if (windowRectangle.Position.X == 0)\n            return FALSE;\n\n        PhAdjustRectangleToWorkingArea(NULL, &windowRectangle);\n\n        // Update the window position before querying the DPI or changing the size. (dmex)\n        SetWindowPos(\n            WindowHandle,\n            NULL,\n            windowRectangle.Left,\n            windowRectangle.Top,\n            0,\n            0,\n            SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER\n            );\n\n        //dpi = PhGetMonitorDpiFromRect(&windowRectangle);\n        dpi = PhGetWindowDpi(WindowHandle);\n        PhScalableIntegerPairToScale(scalableIntegerPair, dpi);\n\n        RtlZeroMemory(&windowRectangle, sizeof(PH_RECTANGLE));\n        windowRectangle.Position = windowIntegerPair;\n        windowRectangle.Size = scalableIntegerPair->Pair;\n\n        // Let the window adjust for the minimum size if needed.\n        PhRectangleToRect(&rectForAdjust, &windowRectangle);\n        SendMessage(WindowHandle, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&rectForAdjust);\n        PhRectToRectangle(&windowRectangle, &rectForAdjust);\n\n        MoveWindow(WindowHandle, windowRectangle.Left, windowRectangle.Top,\n            windowRectangle.Width, windowRectangle.Height, FALSE);\n    }\n    else\n    {\n        PH_RECTANGLE windowRectangle = { 0 };\n        PH_INTEGER_PAIR position = { 0 };\n        PH_INTEGER_PAIR size;\n        ULONG flags;\n        LONG dpi;\n\n        flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER;\n\n        if (PositionSettingName)\n        {\n            position = PhGetIntegerPairSetting(PositionSettingName);\n            ClearFlag(flags, SWP_NOMOVE);\n        }\n        else\n        {\n            position.X = 0;\n            position.Y = 0;\n        }\n\n        if (SizeSettingName)\n        {\n            //RECT rect;\n            //\n            //windowRectangle.Position = position;\n            //rect = PhRectangleToRect(windowRectangle);\n            //dpi = PhGetMonitorDpi(&rect);\n            dpi = PhGetWindowDpi(WindowHandle);\n            size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE, dpi)->Pair;\n            ClearFlag(flags, SWP_NOSIZE);\n        }\n        else\n        {\n            RECT windowRect;\n\n            //size.X = 16;\n            //size.Y = 16;\n\n            if (!PhGetWindowRect(WindowHandle, &windowRect))\n                return FALSE;\n\n            size.X = windowRect.right - windowRect.left;\n            size.Y = windowRect.bottom - windowRect.top;\n        }\n\n        // Make sure the window doesn't get positioned on disconnected monitors. (dmex)\n        windowRectangle.Position = position;\n        windowRectangle.Size = size;\n        PhAdjustRectangleToWorkingArea(NULL, &windowRectangle);\n\n        SetWindowPos(WindowHandle, NULL, windowRectangle.Left, windowRectangle.Top, size.X, size.Y, flags);\n    }\n\n    return TRUE;\n}\n\nVOID PhSaveWindowPlacementToSetting(\n    _In_opt_ PCWSTR PositionSettingName,\n    _In_opt_ PCWSTR SizeSettingName,\n    _In_ HWND WindowHandle\n    )\n{\n    WINDOWPLACEMENT placement = { sizeof(placement) };\n    PH_RECTANGLE windowRectangle;\n    MONITORINFO monitorInfo = { sizeof(MONITORINFO) };\n    //RECT rect;\n    LONG dpi;\n\n    GetWindowPlacement(WindowHandle, &placement);\n    PhRectToRectangle(&windowRectangle, &placement.rcNormalPosition);\n\n    // The rectangle is in workspace coordinates. Convert the values back to screen coordinates.\n    if (GetMonitorInfo(MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo))\n    {\n        windowRectangle.Left += monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;\n        windowRectangle.Top += monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;\n    }\n\n    //PhRectangleToRect(&rect, &windowRectangle);\n    //dpi = PhGetMonitorDpi(&rect);\n    dpi = PhGetWindowDpi(WindowHandle);\n\n    if (PositionSettingName)\n        PhSetIntegerPairSetting(PositionSettingName, windowRectangle.Position);\n    if (SizeSettingName)\n        PhSetScalableIntegerPairSetting2(SizeSettingName, windowRectangle.Size, dpi);\n}\n\nBOOLEAN PhLoadListViewColumnSettings(\n    _In_ HWND ListViewHandle,\n    _In_ PPH_STRING Settings\n    )\n{\n#define ORDER_LIMIT 50\n    PH_STRINGREF remainingPart;\n    ULONG columnIndex;\n    ULONG orderArray[ORDER_LIMIT]; // HACK, but reasonable limit\n    ULONG maxOrder;\n    LONG dpi = 0;\n\n#ifdef DEBUG\n    HWND headerHandle = ListView_GetHeader(ListViewHandle);\n    assert(Header_GetItemCount(headerHandle) < ORDER_LIMIT);\n#endif\n\n    if (PhIsNullOrEmptyString(Settings))\n        return FALSE;\n\n    remainingPart = Settings->sr;\n    columnIndex = 0;\n    memset(orderArray, 0, sizeof(orderArray));\n    maxOrder = 0;\n\n    if (WindowsVersion >= WINDOWS_10)\n    {\n        dpi = PhGetWindowDpi(ListViewHandle);\n    }\n\n    while (remainingPart.Length != 0)\n    {\n        PH_STRINGREF columnPart;\n        PH_STRINGREF orderPart;\n        PH_STRINGREF widthPart;\n        ULONG64 integer;\n        ULONG order;\n        LONG width;\n        LVCOLUMN lvColumn;\n\n        PhSplitStringRefAtChar(&remainingPart, L'|', &columnPart, &remainingPart);\n\n        if (columnPart.Length == 0)\n            return FALSE;\n\n        PhSplitStringRefAtChar(&columnPart, L',', &orderPart, &widthPart);\n\n        if (orderPart.Length == 0 || widthPart.Length == 0)\n            return FALSE;\n\n        // Order\n\n        if (!PhStringToInteger64(&orderPart, 10, &integer))\n            return FALSE;\n\n        order = (ULONG)integer;\n\n        if (order < ORDER_LIMIT)\n        {\n            orderArray[order] = columnIndex;\n\n            if (maxOrder < order + 1)\n                maxOrder = order + 1;\n        }\n\n        // Width\n\n        if (!PhStringToInteger64(&widthPart, 10, &integer))\n            return FALSE;\n\n        width = (LONG)integer;\n\n        lvColumn.mask = LVCF_WIDTH;\n        lvColumn.cx = WindowsVersion >= WINDOWS_10 ? PhScaleToDisplay(width, dpi) : width;\n        ListView_SetColumn(ListViewHandle, columnIndex, &lvColumn);\n\n        columnIndex++;\n    }\n\n    ListView_SetColumnOrderArray(ListViewHandle, maxOrder, orderArray);\n\n    return TRUE;\n}\n\nPPH_STRING PhSaveListViewColumnSettings(\n    _In_ HWND ListViewHandle\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    ULONG i = 0;\n    LVCOLUMN lvColumn;\n    LONG dpiValue;\n\n    PhInitializeStringBuilder(&stringBuilder, 20);\n\n    dpiValue = PhGetWindowDpi(ListViewHandle);\n\n    //{\n    //    PH_FORMAT format[3];\n    //    SIZE_T returnLength;\n    //    WCHAR buffer[PH_INT64_STR_LEN_1];\n    //\n    //    // @%lu|\n    //    PhInitFormatC(&format[0], L'@');\n    //    PhInitFormatU(&format[1], dpiValue);\n    //    PhInitFormatC(&format[2], L'|');\n    //\n    //    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n    //    {\n    //        PhAppendStringBuilderEx(&stringBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n    //    }\n    //    else\n    //    {\n    //        PhAppendFormatStringBuilder(&stringBuilder, L\"@%lu|\", dpiValue);\n    //    }\n    //}\n\n    lvColumn.mask = LVCF_WIDTH | LVCF_ORDER;\n\n    while (ListView_GetColumn(ListViewHandle, i, &lvColumn))\n    {\n        PH_FORMAT format[4];\n        SIZE_T returnLength;\n        WCHAR buffer[PH_INT64_STR_LEN_1];\n\n        // %u,%u|\n        PhInitFormatU(&format[0], lvColumn.iOrder);\n        PhInitFormatC(&format[1], L',');\n        PhInitFormatU(&format[2], WindowsVersion >= WINDOWS_10 ? PhScaleToDefault(lvColumn.cx, dpiValue) : lvColumn.cx);\n        PhInitFormatC(&format[3], L'|');\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n        {\n            PhAppendStringBuilderEx(&stringBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n        }\n        else\n        {\n            PhAppendFormatStringBuilder(\n                &stringBuilder,\n                L\"%u,%u|\",\n                lvColumn.iOrder,\n                WindowsVersion >= WINDOWS_10 ? PhScaleToDefault(lvColumn.cx, dpiValue) : lvColumn.cx\n                );\n        }\n        i++;\n    }\n\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nBOOLEAN PhLoadIListViewColumnSettings(\n    _In_ IListView* ListView,\n    _In_ PPH_STRING Settings\n    )\n{\n#define ORDER_LIMIT 50\n    HWND headerHandle = NULL;\n    PH_STRINGREF remainingPart;\n    ULONG columnIndex;\n    ULONG orderArray[ORDER_LIMIT]; // HACK, but reasonable limit\n    ULONG maxOrder;\n    LONG dpi = 0;\n\n    if (!SUCCEEDED(IListView_GetHeaderControl(ListView, &headerHandle)))\n        return FALSE;\n#ifdef DEBUG\n    assert(Header_GetItemCount(headerHandle) < ORDER_LIMIT);\n#endif\n    if (PhIsNullOrEmptyString(Settings))\n        return FALSE;\n\n    remainingPart = Settings->sr;\n    columnIndex = 0;\n    memset(orderArray, 0, sizeof(orderArray));\n    maxOrder = 0;\n\n    //if (remainingPart.Length != 0 && remainingPart.Buffer[0] == L'@')\n    //{\n    //    PH_STRINGREF scalePart;\n    //    LONG64 integer;\n    //\n    //    PhSkipStringRef(&remainingPart, sizeof(WCHAR));\n    //    PhSplitStringRefAtChar(&remainingPart, L'|', &scalePart, &remainingPart);\n    //\n    //    if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer))\n    //        return FALSE;\n    //\n    //    scale = (LONG)integer;\n    //}\n\n    if (WindowsVersion >= WINDOWS_10)\n    {\n        dpi = PhGetWindowDpi(headerHandle);\n    }\n\n    while (remainingPart.Length != 0)\n    {\n        PH_STRINGREF columnPart;\n        PH_STRINGREF orderPart;\n        PH_STRINGREF widthPart;\n        ULONG64 integer;\n        ULONG order;\n        LONG width;\n        LVCOLUMN lvColumn;\n\n        PhSplitStringRefAtChar(&remainingPart, L'|', &columnPart, &remainingPart);\n\n        if (columnPart.Length == 0)\n            return FALSE;\n\n        PhSplitStringRefAtChar(&columnPart, L',', &orderPart, &widthPart);\n\n        if (orderPart.Length == 0 || widthPart.Length == 0)\n            return FALSE;\n\n        // Order\n\n        if (!PhStringToInteger64(&orderPart, 10, &integer))\n            return FALSE;\n\n        order = (ULONG)integer;\n\n        if (order < ORDER_LIMIT)\n        {\n            orderArray[order] = columnIndex;\n\n            if (maxOrder < order + 1)\n                maxOrder = order + 1;\n        }\n\n        // Width\n\n        if (!PhStringToInteger64(&widthPart, 10, &integer))\n            return FALSE;\n\n        width = (LONG)integer;\n\n        lvColumn.mask = LVCF_WIDTH;\n        lvColumn.cx = WindowsVersion >= WINDOWS_10 ? PhScaleToDisplay(width, dpi) : width;\n        IListView_SetColumn(ListView, columnIndex, &lvColumn);\n\n        columnIndex++;\n    }\n\n    IListView_SetColumnOrderArray(ListView, maxOrder, orderArray);\n\n    return TRUE;\n}\n\nPPH_STRING PhSaveIListViewColumnSettings(\n    _In_ IListView* ListView\n    )\n{\n    HWND headerHandle = NULL;\n    PH_STRING_BUILDER stringBuilder;\n    ULONG i = 0;\n    LVCOLUMN lvColumn;\n    LONG dpiValue = 0;\n\n    if (!SUCCEEDED(IListView_GetHeaderControl(ListView, &headerHandle)))\n        return NULL;\n\n    PhInitializeStringBuilder(&stringBuilder, 20);\n\n    if (WindowsVersion >= WINDOWS_10)\n    {\n        dpiValue = PhGetWindowDpi(headerHandle);\n    }\n\n    //{\n    //    PH_FORMAT format[3];\n    //    SIZE_T returnLength;\n    //    WCHAR buffer[PH_INT64_STR_LEN_1];\n    //\n    //    // @%lu|\n    //    PhInitFormatC(&format[0], L'@');\n    //    PhInitFormatU(&format[1], dpiValue);\n    //    PhInitFormatC(&format[2], L'|');\n    //\n    //    if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n    //    {\n    //        PhAppendStringBuilderEx(&stringBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n    //    }\n    //    else\n    //    {\n    //        PhAppendFormatStringBuilder(&stringBuilder, L\"@%lu|\", dpiValue);\n    //    }\n    //}\n\n    memset(&lvColumn, 0, sizeof(LVCOLUMN));\n    lvColumn.mask = LVCF_WIDTH | LVCF_ORDER;\n\n    while (SUCCEEDED(IListView_GetColumn(ListView, i, &lvColumn)))\n    {\n        PH_FORMAT format[4];\n        SIZE_T returnLength;\n        WCHAR buffer[PH_INT64_STR_LEN_1];\n\n        // %u,%u|\n        PhInitFormatU(&format[0], lvColumn.iOrder);\n        PhInitFormatC(&format[1], L',');\n        PhInitFormatU(&format[2], WindowsVersion >= WINDOWS_10 ? PhScaleToDefault(lvColumn.cx, dpiValue) : lvColumn.cx);\n        PhInitFormatC(&format[3], L'|');\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n        {\n            PhAppendStringBuilderEx(&stringBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n        }\n        else\n        {\n            PhAppendFormatStringBuilder(\n                &stringBuilder,\n                L\"%u,%u|\",\n                lvColumn.iOrder,\n                WindowsVersion >= WINDOWS_10 ? PhScaleToDefault(lvColumn.cx, dpiValue) : lvColumn.cx\n                );\n        }\n        i++;\n    }\n\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nVOID PhLoadListViewColumnsFromSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    )\n{\n    PPH_STRING string;\n\n    string = PhGetStringSetting(Name);\n    PhLoadListViewColumnSettings(ListViewHandle, string);\n    PhDereferenceObject(string);\n}\n\nVOID PhSaveListViewColumnsToSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    )\n{\n    PPH_STRING string;\n\n    string = PhSaveListViewColumnSettings(ListViewHandle);\n    PhSetStringSetting2(Name, &string->sr);\n    PhDereferenceObject(string);\n}\n\nVOID PhLoadIListViewColumnsFromSetting(\n    _In_ PCWSTR Name,\n    _In_ IListView* ListViewClass\n    )\n{\n    PPH_STRING string;\n\n    string = PhGetStringSetting(Name);\n    PhLoadIListViewColumnSettings(ListViewClass, string);\n    PhDereferenceObject(string);\n}\n\nVOID PhSaveIListViewColumnsToSetting(\n    _In_ PCWSTR Name,\n    _In_ IListView* ListViewClass\n    )\n{\n    PPH_STRING string;\n\n    string = PhSaveIListViewColumnSettings(ListViewClass);\n    PhSetStringSetting2(Name, &string->sr);\n    PhDereferenceObject(string);\n}\n\nVOID PhLoadListViewSortColumnsFromSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    )\n{\n    PPH_STRING string;\n    ULONG sortColumn = 0;\n    PH_SORT_ORDER sortOrder = AscendingSortOrder;\n    PH_STRINGREF remainingPart;\n\n    string = PhGetStringSetting(Name);\n\n    if (PhIsNullOrEmptyString(string))\n        return;\n\n    remainingPart = string->sr;\n\n    if (remainingPart.Length != 0)\n    {\n        PH_STRINGREF columnPart;\n        PH_STRINGREF orderPart;\n        ULONG64 integer;\n\n        if (!PhSplitStringRefAtChar(&remainingPart, L',', &columnPart, &orderPart))\n            return;\n\n        if (!PhStringToInteger64(&columnPart, 10, &integer))\n            return;\n\n        sortColumn = (ULONG)integer;\n\n        if (!PhStringToInteger64(&orderPart, 10, &integer))\n            return;\n\n        sortOrder = (ULONG)integer;\n    }\n\n    ExtendedListView_SetSort(ListViewHandle, sortColumn, sortOrder);\n\n    PhDereferenceObject(string);\n}\n\nVOID PhSaveListViewSortColumnsToSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    )\n{\n    PPH_STRING string;\n    ULONG sortColumn = 0;\n    PH_SORT_ORDER sortOrder = AscendingSortOrder;\n\n    if (ExtendedListView_GetSort(ListViewHandle, &sortColumn, &sortOrder))\n    {\n        PH_FORMAT format[3];\n\n        // %lu,%lu\n        PhInitFormatU(&format[0], sortColumn);\n        PhInitFormatC(&format[1], L',');\n        PhInitFormatU(&format[2], sortOrder);\n\n        string = PhFormat(format, RTL_NUMBER_OF(format), 0);\n    }\n    else\n    {\n        string = PhCreateString(L\"0,0\");\n    }\n\n    PhSetStringSetting2(Name, &string->sr);\n    PhDereferenceObject(string);\n}\n\nVOID PhLoadListViewGroupStatesFromSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    )\n{\n    ULONG64 countInteger;\n    PPH_STRING settingsString;\n    PH_STRINGREF remaining;\n    PH_STRINGREF part;\n\n    settingsString = PhaGetStringSetting(Name);\n    remaining = settingsString->sr;\n\n    if (remaining.Length == 0)\n        return;\n\n    if (!PhSplitStringRefAtChar(&remaining, L'|', &part, &remaining))\n        return;\n\n    if (!PhStringToInteger64(&part, 10, &countInteger))\n        return;\n\n    for (LONG index = 0; index < (LONG)countInteger; index++)\n    {\n        ULONG64 groupId;\n        ULONG64 stateMask;\n        PH_STRINGREF groupIdPart;\n        PH_STRINGREF stateMaskPart;\n\n        if (remaining.Length == 0)\n            break;\n\n        PhSplitStringRefAtChar(&remaining, L'|', &groupIdPart, &remaining);\n\n        if (groupIdPart.Length == 0)\n            break;\n\n        PhSplitStringRefAtChar(&remaining, L'|', &stateMaskPart, &remaining);\n\n        if (stateMaskPart.Length == 0)\n            break;\n\n        if (!PhStringToInteger64(&groupIdPart, 10, &groupId))\n            break;\n        if (!PhStringToInteger64(&stateMaskPart, 10, &stateMask))\n            break;\n\n        ListView_SetGroupState(\n            ListViewHandle,\n            (LONG)groupId,\n            LVGS_NORMAL | LVGS_COLLAPSED,\n            (UINT)stateMask\n            );\n    }\n}\n\nVOID PhSaveListViewGroupStatesToSetting(\n    _In_ PCWSTR Name,\n    _In_ HWND ListViewHandle\n    )\n{\n    LONG index;\n    LONG count;\n    PPH_STRING settingsString;\n    PH_STRING_BUILDER stringBuilder;\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n\n    count = (LONG)ListView_GetGroupCount(ListViewHandle);\n\n    PhAppendFormatStringBuilder(\n        &stringBuilder,\n        L\"%d|\",\n        count\n        );\n\n    for (index = 0; index < count; index++)\n    {\n        LVGROUP group;\n        PH_FORMAT format[4];\n        SIZE_T returnLength;\n        WCHAR buffer[PH_INT64_STR_LEN_1];\n\n        memset(&group, 0, sizeof(LVGROUP));\n        group.cbSize = sizeof(LVGROUP);\n        group.mask = LVGF_GROUPID | LVGF_STATE;\n        group.stateMask = LVGS_NORMAL | LVGS_COLLAPSED;\n\n        if (ListView_GetGroupInfoByIndex(ListViewHandle, index, &group) == -1)\n            continue;\n\n        PhInitFormatD(&format[0], group.iGroupId);\n        PhInitFormatC(&format[1], L'|');\n        PhInitFormatU(&format[2], group.state);\n        PhInitFormatC(&format[3], L'|');\n\n        if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), buffer, sizeof(buffer), &returnLength))\n        {\n            PhAppendStringBuilderEx(&stringBuilder, buffer, returnLength - sizeof(UNICODE_NULL));\n        }\n        else\n        {\n            PhAppendFormatStringBuilder(\n                &stringBuilder,\n                L\"%d|%u|\",\n                group.iGroupId,\n                group.state\n                );\n        }\n    }\n\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    settingsString = PhFinalStringBuilderString(&stringBuilder);\n    PhSetStringSetting2(Name, &settingsString->sr);\n    PhDereferenceObject(settingsString);\n}\n\nVOID PhLoadCustomColorList(\n    _In_ PCWSTR Name,\n    _In_ PULONG CustomColorList,\n    _In_ ULONG CustomColorCount\n    )\n{\n    PPH_STRING settingsString;\n    PH_STRINGREF remaining;\n    PH_STRINGREF part;\n\n    if (CustomColorCount != 16)\n        return;\n\n    settingsString = PhGetStringSetting(Name);\n\n    if (PhIsNullOrEmptyString(settingsString))\n        goto CleanupExit;\n\n    remaining = PhGetStringRef(settingsString);\n\n    for (ULONG i = 0; i < CustomColorCount; i++)\n    {\n        ULONG64 integer = 0;\n\n        if (remaining.Length == 0)\n            break;\n\n        PhSplitStringRefAtChar(&remaining, L',', &part, &remaining);\n\n        if (PhStringToInteger64(&part, 10, &integer))\n        {\n            CustomColorList[i] = (COLORREF)integer;\n        }\n    }\n\nCleanupExit:\n    PhClearReference(&settingsString);\n}\n\nVOID PhSaveCustomColorList(\n    _In_ PCWSTR Name,\n    _In_ PULONG CustomColorList,\n    _In_ ULONG CustomColorCount\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n\n    if (CustomColorCount != 16)\n        return;\n\n    PhInitializeStringBuilder(&stringBuilder, 100);\n\n    for (ULONG i = 0; i < CustomColorCount; i++)\n    {\n        PH_FORMAT format[2];\n        SIZE_T returnLength;\n        WCHAR formatBuffer[0x100];\n\n        PhInitFormatU(&format[0], CustomColorList[i]);\n        PhInitFormatC(&format[1], L',');\n\n        if (PhFormatToBuffer(\n            format,\n            RTL_NUMBER_OF(format),\n            formatBuffer,\n            sizeof(formatBuffer),\n            &returnLength\n            ))\n        {\n            PhAppendStringBuilderEx(&stringBuilder, formatBuffer, returnLength - sizeof(UNICODE_NULL));\n        }\n        else\n        {\n            PhAppendFormatStringBuilder(&stringBuilder, L\"%lu,\", CustomColorList[i]);\n        }\n    }\n\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    PhSetStringSetting2(Name, &stringBuilder.String->sr);\n\n    PhDeleteStringBuilder(&stringBuilder);\n}\n\nstatic VOID PhBytesStripSubstringZ(\n    _In_ PSTR String,\n    _In_ PCSTR SubString\n    )\n{\n    SIZE_T length = PhCountBytesZ(SubString);\n\n    if (length == 0)\n        return;\n\n    PSTR offset = strstr(String, SubString);\n\n    while (offset)\n    {\n        // Calculate the size of the remaining string (including null terminator) in bytes\n        // and shift it over the substring to be removed.\n        memmove(offset, offset + length, (PhCountBytesZ(offset + length) + 1) * sizeof(CHAR));\n\n        // Rescan from the beginning of the string to handle nested occurrences\n        offset = strstr(String, SubString);\n    }\n}\n\nstatic VOID PhStringStripSubstringZ(\n    _In_ PWSTR String,\n    _In_ PCWSTR SubString\n    )\n{\n    SIZE_T length = PhCountStringZ(SubString);\n    \n    if (length == 0)\n        return;\n\n    PWSTR offset = wcsstr(String, SubString);\n\n    while (offset)\n    {\n        // Calculate the size of the remaining string (including null terminator) in bytes\n        // and shift it over the substring to be removed.\n        memmove(offset, offset + length, (PhCountStringZ(offset + length) + 1) * sizeof(WCHAR));\n\n        // Rescan from the beginning of the string to handle nested occurrences\n        offset = wcsstr(String, SubString);\n    }\n}\n\nstatic PPH_STRING PhRemoveSubstringFromStringSafe(\n    _In_ PPH_STRING String,\n    _In_ PCPH_STRINGREF Separator,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF firstPart;\n    PH_STRINGREF secondPart;\n    PH_STRINGREF remainingPart;\n    PH_STRING_BUILDER stringBuilder;\n\n    if (!String || !String->Buffer || !Separator || Separator->Length == 0)\n        return NULL;\n\n    remainingPart = PhGetStringRef(String);\n\n    PhInitializeStringBuilder(&stringBuilder, 0x1000);\n\n    while (remainingPart.Length != 0)\n    {\n        if (!PhSplitStringRefAtString(&remainingPart, Separator, IgnoreCase, &firstPart, &secondPart))\n            break;\n\n        PhAppendStringBuilder(&stringBuilder, &firstPart);\n    }\n\n    if (remainingPart.Length)\n    {\n        PhAppendStringBuilder(&stringBuilder, &remainingPart);\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nstatic PPH_STRING PhRemoveSubstringFromString(\n    _In_ PPH_STRING String,\n    _In_ PCPH_STRINGREF Substring,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF stringPart;\n\n    remainingPart = PhGetStringRef(String);\n\n    PhInitializeStringBuilder(&stringBuilder, String->Length);\n\n    while (PhSplitStringRefAtString(&remainingPart, Substring, IgnoreCase, &stringPart, &remainingPart))\n    {\n        PhAppendStringBuilder(&stringBuilder, &stringPart);\n    }\n\n    // If 'remainingPart' still has the same length as the original string,\n    // it means the Substring was never found. Return the original to save memory.\n    //if (remainingPart.Length == String->Length)\n    //{\n    //    PhDeleteStringBuilder(&stringBuilder);\n    //    return PhReferenceObject(String);\n    //}\n\n    // Append the final chunk (or the whole string if no Substring was found)\n    if (remainingPart.Length)\n    {\n        PhAppendStringBuilder(&stringBuilder, &remainingPart);\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nstatic VOID PhRemoveSubstringFromStringUnsafe(\n    _In_ PPH_STRING String,\n    _In_ PCPH_STRINGREF Separator,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF firstPart;\n    PH_STRINGREF secondPart;\n    PH_STRINGREF remainingPart;\n    PH_STRING_BUILDER stringBuilder;\n\n    remainingPart = PhGetStringRef(String);\n\n    PhInitializeStringBuilder(&stringBuilder, 0x1000);\n\n    while (remainingPart.Length != 0)\n    {\n        if (!PhSplitStringRefAtString(&remainingPart, Separator, TRUE, &firstPart, &secondPart))\n            break;\n\n        // Calculate the destination pointer (end of the first part)\n        PWSTR destination = (PWSTR)PTR_ADD_OFFSET(firstPart.Buffer, firstPart.Length);\n        // Calculate the source pointer (start of the second part)\n        PWSTR source = secondPart.Buffer;\n\n        // Move the remaining part of the string (including the null terminator)\n        // over the substring we want to remove.\n        memmove(destination, source, secondPart.Length + sizeof(UNICODE_NULL));\n\n        // Update the Length field.\n        String->Length -= Separator->Length;\n\n        // Re-initialize the stringRef to the modified string to continue searching.\n        // This is necessary because the string length has changed.\n        // Since we modified the buffer in-place, the 'STRINGREF' view is now stale.\n        // Re-initialize it to the new string state to find subsequent occurrences.\n        remainingPart.Buffer = String->Buffer;\n        remainingPart.Length = String->Length;\n    }\n}\n\nNTSTATUS PhConvertSettingsXmlToJson(\n    _In_ PCPH_STRINGREF XmlFileName,\n    _In_ PCPH_STRINGREF JsonFileName\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    PPH_BYTES fileContent;\n    PVOID topNode = NULL;\n    PVOID currentNode;\n    PVOID object = NULL;\n    PPH_STRING settingName;\n    PPH_STRING settingValue;\n    PPH_LIST strings = NULL;\n\n    status = PhCreateFile(\n        &fileHandle,\n        XmlFileName,\n        FILE_GENERIC_READ,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhGetFileText(\n        &fileContent,\n        fileHandle,\n        FALSE\n        );\n\n    NtClose(fileHandle);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    topNode = PhLoadXmlObjectFromString(fileContent->Buffer);\n    PhDereferenceObject(fileContent);\n\n    if (!topNode)\n    {\n        status = STATUS_FILE_CORRUPT_ERROR;\n        goto CleanupExit;\n    }\n\n    if (!(object = PhCreateJsonObject()))\n    {\n        status = STATUS_INSUFFICIENT_RESOURCES;\n        goto CleanupExit;\n    }\n\n    if (!(currentNode = PhGetXmlNodeFirstChild(topNode)))\n    {\n        status = STATUS_FILE_CORRUPT_ERROR;\n        goto CleanupExit;\n    }\n\n    strings = PhCreateList(1);\n\n    while (currentNode)\n    {\n        if (settingName = PhGetXmlNodeAttributeText(currentNode, \"name\"))\n        {\n            PH_STRINGREF name = settingName->sr;\n\n            if (PhIsLegacyPrefix(&name))\n            {\n                PhSkipStringRef(&name, 14 * sizeof(WCHAR));\n            }\n\n            if (settingValue = PhGetXmlNodeOpaqueText(currentNode))\n            {\n                PPH_BYTES stringName;\n                PPH_BYTES stringValue;\n\n                stringName = PhConvertStringRefToUtf8(&name);\n                stringValue = PhConvertStringRefToUtf8(&settingValue->sr);\n\n                PhAddJsonObject2(\n                    object,\n                    stringName->Buffer,\n                    stringValue->Buffer,\n                    stringValue->Length\n                    );\n\n                PhAddItemList(strings, stringName);\n                PhAddItemList(strings, stringValue);\n\n                PhDereferenceObject(settingValue);\n            }\n            PhDereferenceObject(settingName);\n        }\n        currentNode = PhGetXmlNodeNextChild(currentNode);\n    }\n\n    status = PhSaveJsonObjectToFile(\n        JsonFileName,\n        object,\n        PH_JSON_TO_STRING_PLAIN | PH_JSON_TO_STRING_PRETTY\n        );\n\n    //if (!NT_SUCCESS(status))\n    //    goto CleanupExit;\n    //\n    //status = PhMoveFile(\n    //    XmlFileName,\n    //    &convertFilePath->sr,\n    //    NULL\n    //    );\n\nCleanupExit:\n    if (object)\n    {\n        PhFreeJsonObject(object);\n    }\n\n    if (topNode)\n    {\n        PhFreeXmlObject(topNode);\n    }\n\n    if (strings)\n    {\n        PhDereferenceObjects(strings->Items, strings->Count);\n        PhDereferenceObject(strings);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/strsrch.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010\n *     dmex    2017-2023\n *     jxy-s   2024\n *\n */\n\n#include <ph.h>\n#include <strsrch.h>\n\ntypedef struct _PH_STRING_SEARCH_CONEXT\n{\n    ULONG MinimumLength;\n    BOOLEAN ExtendedCharSet;\n    PPH_STRING_SEARCH_CALLBACK Callback;\n    PVOID CallbackContext;\n    WCHAR Buffer[PAGE_SIZE * 2];\n} PH_STRING_SEARCH_CONEXT, *PPH_STRING_SEARCH_CONEXT;\n\ntypedef enum _PH_CHAR_TYPE\n{\n    PhCharTypeNone,\n    PhCharTypePrintable,\n    PhCharTypeNULL,\n    PhCharTypeUTF16High,\n} PH_CHAR_TYPE, *PPH_CHAR_TYPE;\n\ntypedef enum _PH_CHAR_PATTERN\n{\n    PhCharPatternNone = 0,\n    PhCharPatternASCII,\n    PhCharPatternUnicode,\n} PH_CHAR_PATTERN, *PPH_CHAR_PATTERN;\n\nFORCEINLINE\nPH_CHAR_TYPE PhpClassifyByte(\n    _In_ BYTE Byte,\n    _In_ BOOLEAN ExtendedCharSet,\n    _In_ BOOLEAN CheckUTF16High\n    )\n{\n    if (Byte == 0)\n    {\n        return PhCharTypeNULL;\n    }\n    else if (ExtendedCharSet ? PhCharIsPrintableEx[Byte] : PhCharIsPrintable[Byte])\n    {\n        return PhCharTypePrintable;\n    }\n    else if (CheckUTF16High &&\n             !PhIsUTF16HighSurrogateHighByte[Byte] &&\n             !PhIsUTF16LowSurrogateHighByte[Byte] &&\n             PhIsUTF16StandaloneHighByte[Byte] &&\n             (ExtendedCharSet ? TRUE : PhIsUTF16PrintableHighByte[Byte]))\n    {\n        return PhCharTypeUTF16High;\n    }\n    else\n    {\n        return PhCharTypeNone;\n    }\n}\n\nBOOLEAN PhpSearchStrings(\n    _In_ PPH_STRING_SEARCH_CONEXT Context,\n    _In_reads_bytes_(Length) PBYTE Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    BYTE byte = 0; // current byte\n    BYTE byte1 = 0; // byte at position i-1\n    BYTE byte2 = 0; // byte at position i-2\n    BYTE byte3 = 0; // byte at position i-3\n    PH_CHAR_TYPE charType = PhCharTypeNone;  // classification of byte\n    PH_CHAR_TYPE charType1 = PhCharTypeNone; // classification of byte1\n    PH_CHAR_TYPE charType2 = PhCharTypeNone; // classification of byte2\n    PH_CHAR_TYPE charType3 = PhCharTypeNone; // classification of byte3\n    PH_CHAR_PATTERN pattern = PhCharPatternNone;\n    ULONG length = 0;\n\n    for (SIZE_T i = 0; i < Length; i++)\n    {\n        BOOLEAN checkUTF8High = FALSE;\n\n        byte = Buffer[i];\n\n        // Classify the current byte.\n        // Only check for UTF-16 high bytes when extended character sets is\n        // enabled and NOT preceded by UTF-16 high or NULL. This prevents\n        // misclassifying low bytes in UTF-16 sequences as high bytes.\n\n        if (Context->ExtendedCharSet &&\n            charType1 != PhCharTypeUTF16High &&\n            charType1 != PhCharTypeNULL)\n        {\n            checkUTF8High = TRUE;\n        }\n\n        charType = PhpClassifyByte(byte, Context->ExtendedCharSet, checkUTF8High);\n\n        // Pattern: [Printable][Printable][Printable] - ANSI string detection\n        if (charType2 == PhCharTypePrintable &&\n            charType1 == PhCharTypePrintable &&\n            charType == PhCharTypePrintable)\n        {\n            if (pattern == PhCharPatternNone)\n            {\n                assert(length == 0);\n                pattern = PhCharPatternASCII;\n                Context->Buffer[length++] = byte2;\n                Context->Buffer[length++] = byte1;\n                Context->Buffer[length++] = byte;\n            }\n            else if (pattern == PhCharPatternASCII)\n            {\n                if (length < RTL_NUMBER_OF(Context->Buffer))\n                    Context->Buffer[length++] = byte;\n            }\n            else if (length >= Context->MinimumLength)\n            {\n                goto CreateResult;\n            }\n            else\n            {\n                length = 0;\n                pattern = PhCharPatternNone;\n            }\n        }\n        // Pattern: [Printable][NULL][Printable] - ASCII-Unicode string detection\n        else if (charType2 == PhCharTypePrintable &&\n                 charType1 == PhCharTypeNULL &&\n                 charType == PhCharTypePrintable)\n        {\n            if (pattern == PhCharPatternNone)\n            {\n                assert(length == 0);\n                pattern = PhCharPatternUnicode;\n                Context->Buffer[length++] = byte2;\n                Context->Buffer[length++] = byte;\n            }\n            else if (pattern == PhCharPatternUnicode)\n            {\n                if (length < RTL_NUMBER_OF(Context->Buffer))\n                    Context->Buffer[length++] = byte;\n            }\n            else if (length >= Context->MinimumLength)\n            {\n                goto CreateResult;\n            }\n            else\n            {\n                length = 0;\n                pattern = PhCharPatternNone;\n            }\n        }\n        // Pattern: [NULL][Printable][NULL] - ASCII-Unicode continuation\n        // Handles the NULL between printable characters in ASCII-Unicode strings\n        else if (pattern == PhCharPatternUnicode &&\n                 charType2 == PhCharTypeNULL &&\n                 charType1 == PhCharTypePrintable &&\n                 charType == PhCharTypeNULL)\n        {\n            NOTHING; // Keep tracking, waiting for next printable or UTF-16 high byte\n        }\n        // Pattern: [NULL][Printable][NULL][None] - ASCII-Unicode to UTF-16 BMP transition\n        // Handles transition point where ASCII-Unicode meets UTF-16 BMP\n        else if (pattern == PhCharPatternUnicode &&\n                 charType3 == PhCharTypeNULL &&\n                 charType2 == PhCharTypePrintable &&\n                 charType1 == PhCharTypeNULL &&\n                 charType == PhCharTypeNone)\n        {\n            NOTHING; // Keep tracking, next byte should be UTF-16 high byte\n        }\n        // Pattern: [UTF16High|NULL][!UTF16High][UTF16High] - UTF-16 BMP character detection\n        // Detects UTF-16 characters: [low_byte][high_byte]\n        else if ((charType2 == PhCharTypeUTF16High || charType2 == PhCharTypeNULL) &&\n                 charType1 != PhCharTypeUTF16High &&\n                 charType == PhCharTypeUTF16High)\n        {\n            if (pattern == PhCharPatternNone)\n            {\n                assert(length == 0);\n                pattern = PhCharPatternUnicode;\n                Context->Buffer[length++] = MAKEWORD(byte1, byte);\n            }\n            else if (pattern == PhCharPatternUnicode)\n            {\n                if (length < RTL_NUMBER_OF(Context->Buffer))\n                    Context->Buffer[length++] = MAKEWORD(byte1, byte);\n            }\n            else if (length >= Context->MinimumLength)\n            {\n                goto CreateResult;\n            }\n            else\n            {\n                length = 0;\n                pattern = PhCharPatternNone;\n            }\n        }\n        // Pattern: [UTF16High|NULL][!UTF16High][UTF16High][!UTF16High] - UTF-16 BMP continuation\n        // Handles the low byte of the next character in a UTF-16 sequence\n        else if (pattern == PhCharPatternUnicode &&\n                 (charType3 == PhCharTypeUTF16High || charType3 == PhCharTypeNULL) &&\n                 charType2 != PhCharTypeUTF16High &&\n                 charType1 == PhCharTypeUTF16High &&\n                 charType != PhCharTypeUTF16High)\n        {\n            NOTHING; // Keep tracking, waiting for next UTF-16 high byte\n        }\n        // Pattern: [!UTF16High][UTF16High][Printable][NULL] - UTF-16 BMP to ASCII-Unicode transition\n        // Handles transition from UTF-16 BMP back to ASCII-Unicode\n        else if (pattern == PhCharPatternUnicode &&\n                 charType3 != PhCharTypeUTF16High &&\n                 charType2 == PhCharTypeUTF16High &&\n                 charType1 == PhCharTypePrintable &&\n                 charType == PhCharTypeNULL)\n        {\n            if (length < RTL_NUMBER_OF(Context->Buffer))\n                Context->Buffer[length++] = byte1;\n        }\n        else if (pattern != PhCharPatternNone &&\n                 length >= Context->MinimumLength)\n        {\n            goto CreateResult;\n        }\n        else\n        {\n            length = 0;\n            pattern = PhCharPatternNone;\n        }\n\n        goto AfterCreateResult;\n\nCreateResult:\n        {\n            PH_STRING_SEARCH_RESULT result;\n            ULONG lengthInBytes;\n            ULONG bias;\n            BOOLEAN isWide;\n            BOOLEAN isFinished;\n\n            lengthInBytes = length;\n            bias = (charType == PhCharTypePrintable);\n            isWide = (pattern != PhCharPatternASCII);\n\n            if (isWide)\n            {\n                lengthInBytes *= 2;\n            }\n\n            result.Unicode = isWide;\n            result.Address = PTR_ADD_OFFSET(Buffer, i - bias - lengthInBytes);\n            result.Length = lengthInBytes;\n            result.String = PhCreateStringEx(\n                Context->Buffer,\n                2 * min(length, RTL_NUMBER_OF(Context->Buffer))\n                );\n\n            isFinished = Context->Callback(&result, Context->CallbackContext);\n\n            PhClearReference(&result.String);\n            pattern = PhCharPatternNone;\n            length = 0;\n\n            if (isFinished)\n                return TRUE;\n        }\nAfterCreateResult:\n\n        byte3 = byte2;\n        byte2 = byte1;\n        byte1 = byte;\n        charType3 = charType2;\n        charType2 = charType1;\n        charType1 = charType;\n    }\n\n    return FALSE;\n}\n\nNTSTATUS PhSearchStrings(\n    _In_ ULONG MinimumLength,\n    _In_ BOOLEAN ExtendedCharSet,\n    _In_ PPH_STRING_SEARCH_NEXT_BUFFER NextBuffer,\n    _In_ PPH_STRING_SEARCH_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PPH_STRING_SEARCH_CONEXT context;\n    PVOID buffer;\n    SIZE_T length;\n\n    if (!MinimumLength)\n        return STATUS_INVALID_PARAMETER;\n\n    context = PhAllocateZero(sizeof(PH_STRING_SEARCH_CONEXT));\n    context->MinimumLength = MinimumLength;\n    context->ExtendedCharSet = ExtendedCharSet;\n    context->Callback = Callback;\n    context->CallbackContext = Context;\n\n    buffer = NULL;\n    length = 0;\n\n    while (NT_SUCCESS(status = NextBuffer(&buffer, &length, Context)))\n    {\n        if (!length)\n            break;\n\n        if (PhpSearchStrings(context, buffer, length))\n            break;\n    }\n\n    PhFree(context);\n\n    return status;\n}\n"
  },
  {
    "path": "phlib/svcsup.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2012\n *     dmex    2019-2024\n *\n */\n\n#include <ph.h>\n#include <subprocesstag.h>\n#include <svcsup.h>\n#include <mapldr.h>\n\nstatic CONST PH_STRINGREF PhpServiceUnknownString = PH_STRINGREF_INIT(L\"Unknown\");\n\nstatic CONST PH_KEY_VALUE_PAIR PhpServiceStatePairs[] =\n{\n    SIP(SREF(L\"Unknown\"), 0),\n    SIP(SREF(L\"Stopped\"), SERVICE_STOPPED),\n    SIP(SREF(L\"Start pending\"), SERVICE_START_PENDING),\n    SIP(SREF(L\"Stop pending\"), SERVICE_STOP_PENDING),\n    SIP(SREF(L\"Running\"), SERVICE_RUNNING),\n    SIP(SREF(L\"Continue pending\"), SERVICE_CONTINUE_PENDING),\n    SIP(SREF(L\"Pause pending\"), SERVICE_PAUSE_PENDING),\n    SIP(SREF(L\"Paused\"), SERVICE_PAUSED)\n};\n\nstatic CONST PH_KEY_VALUE_PAIR PhpServiceTypePairs[] =\n{\n    SIP(SREF(L\"Unknown\"), 0),\n    SIP(SREF(L\"Driver\"), SERVICE_KERNEL_DRIVER),\n    SIP(SREF(L\"FS driver\"), SERVICE_FILE_SYSTEM_DRIVER),\n    SIP(SREF(L\"Own process\"), SERVICE_WIN32_OWN_PROCESS),\n    SIP(SREF(L\"Share process\"), SERVICE_WIN32_SHARE_PROCESS),\n    SIP(SREF(L\"Own interactive process\"), SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS),\n    SIP(SREF(L\"Share interactive process\"), SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS),\n    SIP(SREF(L\"User own process\"), SERVICE_USER_OWN_PROCESS),\n    SIP(SREF(L\"User own process (instance)\"), SERVICE_USER_OWN_PROCESS | SERVICE_USERSERVICE_INSTANCE),\n    SIP(SREF(L\"User share process\"), SERVICE_USER_SHARE_PROCESS),\n    SIP(SREF(L\"User share process (instance)\"), SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE),\n    SIP(SREF(L\"Package own process\"), SERVICE_PKG_SERVICE | SERVICE_WIN32_OWN_PROCESS),\n    SIP(SREF(L\"Package share process\"), SERVICE_PKG_SERVICE | SERVICE_WIN32_SHARE_PROCESS),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR PhpServiceStartTypePairs[] =\n{\n    SIP(SREF(L\"Boot start\"), SERVICE_BOOT_START),\n    SIP(SREF(L\"System start\"), SERVICE_SYSTEM_START),\n    SIP(SREF(L\"Auto start\"), SERVICE_AUTO_START),\n    SIP(SREF(L\"Demand start\"), SERVICE_DEMAND_START),\n    SIP(SREF(L\"Disabled\"), SERVICE_DISABLED),\n};\n\nstatic CONST PH_KEY_VALUE_PAIR PhpServiceErrorControlPairs[] =\n{\n    SIP(SREF(L\"Ignore\"), SERVICE_ERROR_IGNORE),\n    SIP(SREF(L\"Normal\"), SERVICE_ERROR_NORMAL),\n    SIP(SREF(L\"Severe\"), SERVICE_ERROR_SEVERE),\n    SIP(SREF(L\"Critical\"), SERVICE_ERROR_CRITICAL)\n};\n\nCONST PPH_STRINGREF PhServiceTypeStrings[] =\n{\n    SREF(L\"Driver\"),\n    SREF(L\"FS driver\"),\n    SREF(L\"Own process\"),\n    SREF(L\"Share process\"),\n    SREF(L\"Own interactive process\"),\n    SREF(L\"Share interactive process\"),\n    SREF(L\"User own process\"),\n    SREF(L\"User own process (instance)\"),\n    SREF(L\"User share process\"),\n    SREF(L\"User share process (instance)\"),\n    SREF(L\"Package own process\"),\n    SREF(L\"Package share process\"),\n};\n\nCONST PPH_STRINGREF PhServiceStartTypeStrings[5] =\n{\n    SREF(L\"Disabled\"),\n    SREF(L\"Boot start\"),\n    SREF(L\"System start\"),\n    SREF(L\"Auto start\"),\n    SREF(L\"Demand start\"),\n};\n\nCONST PPH_STRINGREF PhServiceErrorControlStrings[4] =\n{\n    SREF(L\"Ignore\"),\n    SREF(L\"Normal\"),\n    SREF(L\"Severe\"),\n    SREF(L\"Critical\"),\n};\n\n/**\n * Gets a cached service manager handle.\n *\n * \\return Service manager handle, or NULL if failed.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-openscmanagerw\n */\nSC_HANDLE PhGetServiceManagerHandle(\n    VOID\n    )\n{\n    static SC_HANDLE cachedServiceManagerHandle = NULL;\n    SC_HANDLE serviceManagerHandle;\n    SC_HANDLE newServiceManagerHandle;\n\n    // Use the cached value if possible.\n\n    serviceManagerHandle = ReadPointerAcquire(&cachedServiceManagerHandle);\n\n    // If there is no cached handle, open one.\n\n    if (!serviceManagerHandle)\n    {\n        if (newServiceManagerHandle = OpenSCManager(\n            NULL,\n            NULL,\n            SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE\n            ))\n        {\n            // We succeeded in opening a policy handle, and since we did not have a cached handle\n            // before, we will now store it.\n            serviceManagerHandle = InterlockedCompareExchangePointer(\n                &cachedServiceManagerHandle,\n                newServiceManagerHandle,\n                NULL\n                );\n\n            if (!serviceManagerHandle)\n            {\n                // Success. Use our handle.\n                serviceManagerHandle = newServiceManagerHandle;\n            }\n            else\n            {\n                // Someone already placed a handle in the cache. Close our handle and use their handle.\n                PhCloseServiceHandle(newServiceManagerHandle);\n            }\n        }\n    }\n\n    return serviceManagerHandle;\n}\n\n/**\n * Enumerates all services.\n *\n * \\param Services Receives a pointer to service status array. Caller must free with PhFree.\n * \\param NumberOfServices Receives the number of services enumerated.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-enumservicesstatusexw\n */\nNTSTATUS PhEnumServices(\n    _Out_ LPENUM_SERVICE_STATUS_PROCESS* Services,\n    _Out_ PULONG NumberOfServices\n    )\n{\n    static ULONG initialBufferSize = 0x8000;\n    NTSTATUS status;\n    SC_HANDLE scManagerHandle;\n    ULONG type;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG returnLength;\n    ULONG servicesReturned;\n\n    if (WindowsVersion >= WINDOWS_10_RS1)\n    {\n        type = SERVICE_TYPE_ALL;\n    }\n    else if (WindowsVersion >= WINDOWS_10)\n    {\n        type = SERVICE_WIN32 |\n            SERVICE_ADAPTER |\n            SERVICE_DRIVER |\n            SERVICE_INTERACTIVE_PROCESS |\n            SERVICE_USER_SERVICE |\n            SERVICE_USERSERVICE_INSTANCE;\n    }\n    else\n    {\n        type = SERVICE_DRIVER | SERVICE_WIN32;\n    }\n\n    scManagerHandle = PhGetServiceManagerHandle();\n    bufferSize = initialBufferSize;\n    buffer = PhAllocate(bufferSize);\n\n    if (EnumServicesStatusEx(\n        scManagerHandle,\n        SC_ENUM_PROCESS_INFO,\n        type,\n        SERVICE_STATE_ALL,\n        (PBYTE)buffer,\n        bufferSize,\n        &returnLength,\n        &servicesReturned,\n        NULL,\n        NULL\n        ))\n    {\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    if (status == STATUS_MORE_ENTRIES)\n    {\n        PhFree(buffer);\n        bufferSize += returnLength;\n        buffer = PhAllocate(bufferSize);\n\n        if (EnumServicesStatusEx(\n            scManagerHandle,\n            SC_ENUM_PROCESS_INFO,\n            type,\n            SERVICE_STATE_ALL,\n            (PBYTE)buffer,\n            bufferSize,\n            &returnLength,\n            &servicesReturned,\n            NULL,\n            NULL\n            ))\n        {\n            status = STATUS_SUCCESS;\n        }\n        else\n        {\n            status = PhGetLastWin32ErrorAsNtStatus();\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x20000) initialBufferSize = bufferSize;\n    *Services = buffer;\n    *NumberOfServices = servicesReturned;\n\n    return status;\n}\n\n/**\n * Enumerates services that depend on the specified service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param DependentServices Receives a pointer to dependent services array. Caller must free with PhFree.\n * \\param NumberOfDependentServices Receives the number of dependent services.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-enumdependentservicesw\n */\nNTSTATUS PhEnumDependentServices(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ LPENUM_SERVICE_STATUS* DependentServices,\n    _Out_ PULONG NumberOfDependentServices\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG returnLength;\n    ULONG servicesReturned;\n\n    bufferSize = 0x800;\n    buffer = PhAllocate(bufferSize);\n\n    if (EnumDependentServices(\n        ServiceHandle,\n        SERVICE_STATE_ALL,\n        buffer,\n        bufferSize,\n        &returnLength,\n        &servicesReturned\n        ))\n    {\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    if (status == STATUS_MORE_ENTRIES)\n    {\n        PhFree(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocate(bufferSize);\n\n        if (EnumDependentServices(\n            ServiceHandle,\n            SERVICE_STATE_ALL,\n            buffer,\n            bufferSize,\n            &returnLength,\n            &servicesReturned\n            ))\n        {\n            status = STATUS_SUCCESS;\n        }\n        else\n        {\n            status = PhGetLastWin32ErrorAsNtStatus();\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *DependentServices = buffer;\n    *NumberOfDependentServices = servicesReturned;\n\n    return status;\n}\n\n/**\n * Opens a handle to the service control manager.\n *\n * \\param ServiceManagerHandle Receives the service manager handle.\n * \\param DatabaseName Name of the service control manager database, or NULL for the default.\n * \\param DesiredAccess Access rights for the handle.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-openscmanagerw\n */\nNTSTATUS PhOpenServiceManager(\n    _Out_ PSC_HANDLE ServiceManagerHandle,\n    _In_opt_ PCWSTR DatabaseName,\n    _In_ ACCESS_MASK DesiredAccess\n    )\n{\n    SC_HANDLE serviceManagerHandle;\n\n    if (serviceManagerHandle = OpenSCManager(NULL, DatabaseName, DesiredAccess))\n    {\n        *ServiceManagerHandle = serviceManagerHandle;\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        *ServiceManagerHandle = NULL;\n        return PhGetLastWin32ErrorAsNtStatus();\n    }\n}\n\n/**\n * Opens a handle to a service.\n *\n * \\param ServiceHandle Receives the service handle.\n * \\param DesiredAccess Access rights for the handle.\n * \\param ServiceName Name of the service.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-openservicew\n */\nNTSTATUS PhOpenService(\n    _Out_ PSC_HANDLE ServiceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCWSTR ServiceName\n    )\n{\n    SC_HANDLE serviceHandle;\n\n    if (serviceHandle = OpenService(PhGetServiceManagerHandle(), ServiceName, DesiredAccess))\n    {\n        *ServiceHandle = serviceHandle;\n        return STATUS_SUCCESS;\n    }\n\n    *ServiceHandle = NULL;\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Opens a registry key for a service.\n *\n * \\param KeyHandle Receives the key handle.\n * \\param DesiredAccess Access rights for the handle.\n * \\param ServiceName Name of the service.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhOpenServiceKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    static CONST PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Services\");\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static HANDLE servicesKeyHandle = NULL;\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    PPH_STRING serviceName;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        status = PhOpenKey(&servicesKeyHandle, KEY_READ, PH_KEY_LOCAL_MACHINE, &servicesKeyName, 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (servicesKeyHandle)\n    {\n        status = PhOpenKey(KeyHandle, DesiredAccess, servicesKeyHandle, ServiceName, 0);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (serviceName = PhGetServiceKeyName(ServiceName))\n        {\n            status = PhOpenKey(\n                KeyHandle,\n                DesiredAccess,\n                PH_KEY_LOCAL_MACHINE,\n                &serviceName->sr,\n                0\n                );\n\n            PhDereferenceObject(serviceName);\n        }\n        else\n        {\n            status = STATUS_NO_MEMORY;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Closes a service handle.\n *\n * \\param ServiceHandle Handle to close.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-closeservicehandle\n */\nNTSTATUS PhCloseServiceHandle(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    if (CloseServiceHandle(ServiceHandle))\n        return STATUS_SUCCESS;\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Creates a service.\n *\n * \\param ServiceHandle Receives the service handle.\n * \\param ServiceName Name of the service to create.\n * \\param DisplayName Display name of the service, or NULL.\n * \\param DesiredAccess Access rights for the handle.\n * \\param ServiceType Service type.\n * \\param StartType Service start type.\n * \\param ErrorControl Error control level.\n * \\param BinaryPathName Path to the service binary, or NULL.\n * \\param UserName User account for the service, or NULL.\n * \\param Password Password for the user account, or NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-createservicew\n */\nNTSTATUS PhCreateService(\n    _Out_ PSC_HANDLE ServiceHandle,\n    _In_ PCWSTR ServiceName,\n    _In_opt_ PCWSTR DisplayName,\n    _In_ ULONG DesiredAccess,\n    _In_ ULONG ServiceType,\n    _In_ ULONG StartType,\n    _In_ ULONG ErrorControl,\n    _In_opt_ PCWSTR BinaryPathName,\n    _In_opt_ PCWSTR UserName,\n    _In_opt_ PCWSTR Password\n    )\n{\n    NTSTATUS status;\n    SC_HANDLE scManagerHandle;\n    SC_HANDLE serviceHandle;\n\n    status = PhOpenServiceManager(&scManagerHandle, NULL, SC_MANAGER_CREATE_SERVICE);\n\n    if (NT_SUCCESS(status))\n    {\n        if (serviceHandle = CreateService(\n            scManagerHandle,\n            ServiceName,\n            DisplayName,\n            DesiredAccess,\n            ServiceType,\n            StartType,\n            ErrorControl,\n            BinaryPathName,\n            NULL,\n            NULL,\n            NULL,\n            UserName,\n            Password\n            ))\n        {\n            *ServiceHandle = serviceHandle;\n            status = STATUS_SUCCESS;\n        }\n        else\n        {\n            *ServiceHandle = NULL;\n            status = PhGetLastWin32ErrorAsNtStatus();\n        }\n\n        PhCloseServiceHandle(scManagerHandle);\n    }\n\n    return status;\n}\n\n/**\n * Changes the configuration of a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param ServiceType Service type, or SERVICE_NO_CHANGE.\n * \\param StartType Service start type, or SERVICE_NO_CHANGE.\n * \\param ErrorControl Error control level, or SERVICE_NO_CHANGE.\n * \\param BinaryPathName Path to the service binary, or NULL.\n * \\param LoadOrderGroup Load order group, or NULL.\n * \\param TagId Receives the tag identifier, or NULL.\n * \\param Dependencies List of dependencies, or NULL.\n * \\param ServiceStartName User account for the service, or NULL.\n * \\param Password Password for the user account, or NULL.\n * \\param DisplayName Display name of the service, or NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-changeserviceconfigw\n */\nNTSTATUS PhChangeServiceConfig(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG ServiceType,\n    _In_ ULONG StartType,\n    _In_ ULONG ErrorControl,\n    _In_opt_ PCWSTR BinaryPathName,\n    _In_opt_ PCWSTR LoadOrderGroup,\n    _Out_opt_ PULONG TagId,\n    _In_opt_ PCWSTR Dependencies,\n    _In_opt_ PCWSTR ServiceStartName,\n    _In_opt_ PCWSTR Password,\n    _In_opt_ PCWSTR DisplayName\n    )\n{\n    NTSTATUS status;\n\n    if (ChangeServiceConfig(\n        ServiceHandle,\n        ServiceType,\n        StartType,\n        ErrorControl,\n        BinaryPathName,\n        LoadOrderGroup,\n        TagId,\n        Dependencies,\n        ServiceStartName,\n        Password,\n        DisplayName\n        ))\n    {\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    return status;\n}\n\n/**\n * Changes optional configuration parameters of a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param ServiceConfigLevel Configuration information level.\n * \\param Buffer Configuration data, or NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-changeserviceconfig2w\n */\nNTSTATUS PhChangeServiceConfig2(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG ServiceConfigLevel,\n    _In_opt_ PVOID Buffer\n    )\n{\n    NTSTATUS status;\n\n    if (ChangeServiceConfig2(ServiceHandle, ServiceConfigLevel, Buffer))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    return status;\n}\n\n/**\n * Enumerates services that depend on the specified service (variant).\n *\n * \\param ServiceHandle Handle to the service.\n * \\param Buffer Buffer to receive dependent services, or NULL.\n * \\param BufferLength Size of the buffer in bytes.\n * \\param ReturnLength Receives the required buffer size.\n * \\param NumberOfServices Receives the number of dependent services.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-enumdependentservicesw\n */\nNTSTATUS PhEnumDependentServices2(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_writes_bytes_opt_(BufferLength) LPENUM_SERVICE_STATUSW Buffer,\n    _In_ ULONG BufferLength,\n    _Out_ PULONG ReturnLength,\n    _Out_ PULONG NumberOfServices\n    )\n{\n    NTSTATUS status;\n\n    if (EnumDependentServices(ServiceHandle, SERVICE_STATE_ALL, Buffer, BufferLength, ReturnLength, NumberOfServices))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    return status;\n}\n\n/**\n * Queries service configuration.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param Buffer Buffer to receive configuration, or NULL.\n * \\param BufferLength Size of the buffer in bytes.\n * \\param ReturnLength Receives the required buffer size, or NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryserviceconfigw\n */\nNTSTATUS PhQueryServiceConfig(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_writes_bytes_opt_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength = 0;\n\n    if (QueryServiceConfig(ServiceHandle, Buffer, BufferLength, &returnLength))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    if (ReturnLength)\n        *ReturnLength = returnLength;\n\n    return status;\n}\n\n/**\n * Queries optional service configuration parameters.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param ServiceConfigLevel Configuration information level.\n * \\param Buffer Buffer to receive configuration, or NULL.\n * \\param BufferLength Size of the buffer in bytes.\n * \\param ReturnLength Receives the required buffer size, or NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryserviceconfig2w\n */\nNTSTATUS PhQueryServiceConfig2(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG ServiceConfigLevel,\n    _Out_writes_bytes_opt_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength = 0;\n\n    if (QueryServiceConfig2(ServiceHandle, ServiceConfigLevel, (PBYTE)Buffer, BufferLength, &returnLength))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    if (ReturnLength)\n        *ReturnLength = returnLength;\n\n    return status;\n}\n\n/**\n * Retrieves security descriptor for a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param SecurityInformation Security information to retrieve.\n * \\param SecurityDescriptor Receives a pointer to the security descriptor. Caller must free with PhFree.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryserviceobjectsecurity\n */\nNTSTATUS PhGetServiceObjectSecurity(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    if (QueryServiceObjectSecurity(ServiceHandle, SecurityInformation, NULL, 0, &bufferSize))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    if (status == STATUS_BUFFER_TOO_SMALL && bufferSize)\n    {\n        buffer = PhAllocate(bufferSize);\n        memset(buffer, 0, bufferSize);\n\n        if (QueryServiceObjectSecurity(ServiceHandle, SecurityInformation, buffer, bufferSize, &bufferSize))\n            status = STATUS_SUCCESS;\n        else\n            status = PhGetLastWin32ErrorAsNtStatus();\n\n        if (NT_SUCCESS(status))\n        {\n            *SecurityDescriptor = buffer;\n            return STATUS_SUCCESS;\n        }\n        else\n        {\n            PhFree(buffer);\n        }\n    }\n\n    if (NT_SUCCESS(status) && !bufferSize)\n    {\n        status = STATUS_INVALID_SECURITY_DESCR;\n    }\n\n    *SecurityDescriptor = NULL;\n\n    return status;\n}\n\n/**\n * Sets the security descriptor for a service object.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param SecurityInformation Specifies the type of security information to set.\n * \\param SecurityDescriptor Pointer to a SECURITY_DESCRIPTOR structure containing the new security descriptor.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-setserviceobjectsecurity\n */\nNTSTATUS PhSetServiceObjectSecurity(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n\n    if (SetServiceObjectSecurity(ServiceHandle, SecurityInformation, SecurityDescriptor))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    return status;\n}\n\n/**\n * Queries the current status of a specified service.\n *\n * \\param ServiceHandle A handle to the service. This handle must have the SERVICE_QUERY_STATUS access right.\n * \\param ServiceStatus A pointer to a SERVICE_STATUS_PROCESS structure that receives the status information for the service.\n * \\return Returns an NTSTATUS code indicating success or failure of the operation.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryservicestatusex\n */\nNTSTATUS PhQueryServiceStatus(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ LPSERVICE_STATUS_PROCESS ServiceStatus\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength = 0;\n\n    memset(ServiceStatus, 0, sizeof(SERVICE_STATUS_PROCESS));\n\n    if (QueryServiceStatusEx(\n        ServiceHandle,\n        SC_STATUS_PROCESS_INFO,\n        (PBYTE)ServiceStatus,\n        sizeof(SERVICE_STATUS_PROCESS),\n        &returnLength\n        ))\n    {\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    return status;\n}\n\n/**\n * Queries variable-sized information about a service.\n *\n * \\param ServiceHandle Handle to the service to query.\n * \\param InfoLevel The information level specifying the type of service information to retrieve.\n * \\param ServiceConfig Pointer to a variable containing the requested service information.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryserviceconfig2w\n */\nNTSTATUS PhQueryServiceVariableSize(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG InfoLevel,\n    _Out_ PVOID* ServiceConfig\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    status = PhQueryServiceConfig2(\n        ServiceHandle,\n        InfoLevel,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = PhQueryServiceConfig2(\n            ServiceHandle,\n            InfoLevel,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            PhFree(buffer);\n            return status;\n        }\n    }\n\n    *ServiceConfig = buffer;\n\n    return status;\n}\n\n/**\n * Sends a continue control code to a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhContinueService(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    NTSTATUS status;\n    SERVICE_STATUS serviceStatus;\n\n    if (ControlService(ServiceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    return status;\n}\n\n/**\n * Sends a pause control code to a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhPauseService(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    NTSTATUS status;\n    SERVICE_STATUS serviceStatus;\n\n    if (ControlService(ServiceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    return status;\n}\n\n/**\n * Deletes a service from the service control manager database.\n *\n * \\param ServiceHandle Handle to the service.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-deleteservice\n */\nNTSTATUS PhDeleteService(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    NTSTATUS status;\n\n    if (DeleteService(ServiceHandle))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    return status;\n}\n\n/**\n * Starts a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param NumberOfServiceArgs Number of arguments in the ServiceArgVectors array.\n * \\param ServiceArgVectors Array of arguments to pass to the service, or NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-startservicew\n */\nNTSTATUS PhStartService(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG NumberOfServiceArgs,\n    _In_reads_opt_(NumberOfServiceArgs) PCWSTR* ServiceArgVectors\n    )\n{\n    NTSTATUS status;\n\n    if (StartService(ServiceHandle, NumberOfServiceArgs, ServiceArgVectors))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    return status;\n}\n\n/**\n * Sends a stop control code to a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhStopService(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    NTSTATUS status;\n    SERVICE_STATUS serviceStatus;\n\n    if (ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &serviceStatus))\n        status = STATUS_SUCCESS;\n    else\n        status = PhGetLastWin32ErrorAsNtStatus();\n\n    return status;\n}\n\n/**\n * Retrieves the configuration of a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param ServiceConfig Receives a pointer to the service configuration. Caller must free with PhFree.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetServiceConfig(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ LPQUERY_SERVICE_CONFIG* ServiceConfig\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    bufferSize = 0x200;\n    buffer = PhAllocate(bufferSize);\n\n    status = PhQueryServiceConfig(\n        ServiceHandle,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = PhQueryServiceConfig(\n            ServiceHandle,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            PhFree(buffer);\n            return status;\n        }\n    }\n\n    *ServiceConfig = buffer;\n\n    return status;\n}\n\n/**\n * Retrieves the description string for a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\return A PPH_STRING containing the service description, or NULL if not found.\n */\nPPH_STRING PhGetServiceDescription(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    PPH_STRING description = NULL;\n    LPSERVICE_DESCRIPTION serviceDescription;\n\n    if (NT_SUCCESS(PhQueryServiceVariableSize(ServiceHandle, SERVICE_CONFIG_DESCRIPTION, &serviceDescription)))\n    {\n        if (serviceDescription->lpDescription)\n            description = PhCreateString(serviceDescription->lpDescription);\n\n        PhFree(serviceDescription);\n\n        return description;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\nPPH_STRING PhGetServiceDescriptionKey(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    NTSTATUS status;\n    HANDLE keyHandle;\n    PPH_STRING description = NULL;\n\n    status = PhOpenServiceKey(\n        &keyHandle,\n        KEY_QUERY_VALUE,\n        ServiceName\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PPH_STRING descriptionString;\n        PPH_STRING serviceDescriptionString;\n\n        if (descriptionString = PhQueryRegistryStringZ(keyHandle, L\"Description\"))\n        {\n            if (serviceDescriptionString = PhLoadIndirectString(&descriptionString->sr))\n                PhMoveReference(&description, serviceDescriptionString);\n            else\n                PhSwapReference(&description, descriptionString);\n\n            PhDereferenceObject(descriptionString);\n        }\n\n        NtClose(keyHandle);\n    }\n    else\n    {\n        PhMoveReference(&description, PhGetStatusMessage(status, 0));\n    }\n\n    return description;\n}\n\n/**\n * Retrieves the delayed auto-start setting for a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param DelayedAutoStart Receives TRUE if delayed auto-start is enabled.\n * \\return TRUE if successful, FALSE otherwise.\n */\nNTSTATUS PhGetServiceDelayedAutoStart(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ PBOOLEAN DelayedAutoStart\n    )\n{\n    NTSTATUS status;\n    SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;\n\n    status = PhQueryServiceConfig2(\n        ServiceHandle,\n        SERVICE_CONFIG_DELAYED_AUTO_START_INFO,\n        &delayedAutoStartInfo,\n        sizeof(SERVICE_DELAYED_AUTO_START_INFO),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *DelayedAutoStart = !!delayedAutoStartInfo.fDelayedAutostart;\n    }\n\n    return status;\n}\n\n/**\n * Sets the delayed auto-start setting for a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param DelayedAutoStart TRUE to enable delayed auto-start, FALSE to disable.\n * \\return TRUE if successful, FALSE otherwise.\n */\nNTSTATUS PhSetServiceDelayedAutoStart(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ BOOLEAN DelayedAutoStart\n    )\n{\n    SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;\n\n    delayedAutoStartInfo.fDelayedAutostart = DelayedAutoStart;\n\n    return PhChangeServiceConfig2(\n        ServiceHandle,\n        SERVICE_CONFIG_DELAYED_AUTO_START_INFO,\n        &delayedAutoStartInfo\n        );\n}\n\n/**\n * Retrieves the trigger information for a service.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param ServiceTriggerInfo Receives a pointer to the trigger information. Caller must free with PhFree.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetServiceTriggerInfo(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_opt_ PSERVICE_TRIGGER_INFO* ServiceTriggerInfo\n    )\n{\n    NTSTATUS status;\n    PVOID buffer = NULL;\n    ULONG bufferSize = 0;\n    SERVICE_TRIGGER_INFO triggerInfo;\n\n    if (ServiceTriggerInfo)\n        *ServiceTriggerInfo = NULL;\n\n    status = PhQueryServiceConfig2(\n        ServiceHandle,\n        SERVICE_CONFIG_TRIGGER_INFO,\n        &triggerInfo,\n        sizeof(SERVICE_TRIGGER_INFO),\n        &bufferSize\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        // The fixed-size struct was sufficient (e.g., no triggers or no variable list).\n        if (ServiceTriggerInfo)\n        {\n            buffer = PhAllocate(sizeof(SERVICE_TRIGGER_INFO));\n            if (!buffer)\n                return STATUS_NO_MEMORY;\n\n            memcpy(buffer, &triggerInfo, sizeof(SERVICE_TRIGGER_INFO));\n            *ServiceTriggerInfo = buffer;\n        }\n\n        return STATUS_SUCCESS;\n    }\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        if (bufferSize == 0)\n            return STATUS_INVALID_BUFFER_SIZE;\n\n        // If the caller does not want it, just report success.\n        if (!ServiceTriggerInfo)\n            return STATUS_SUCCESS;\n\n        buffer = PhAllocate(bufferSize);\n        if (!buffer)\n            return STATUS_NO_MEMORY;\n\n        status = PhQueryServiceConfig2(\n            ServiceHandle,\n            SERVICE_CONFIG_TRIGGER_INFO,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            *ServiceTriggerInfo = buffer;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    if (buffer)\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the service state.\n *\n * \\param ServiceState The service state value (e.g., SERVICE_RUNNING, SERVICE_STOPPED).\n * \\return A pointer to a string reference describing the service state, or \"Unknown\" if not found.\n */\nPCPH_STRINGREF PhGetServiceStateString(\n    _In_ ULONG ServiceState\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        PhpServiceStatePairs,\n        sizeof(PhpServiceStatePairs),\n        ServiceState,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return &PhpServiceUnknownString;\n}\n\n/**\n * Retrieves the display type.\n *\n * \\param ServiceType The service type value (e.g., SERVICE_WIN32_OWN_PROCESS).\n * \\return A pointer to a string reference describing the service type, or \"Unknown\" if not found.\n */\nPCPH_STRINGREF PhGetServiceTypeString(\n    _In_ ULONG ServiceType\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhFindStringRefSiKeyValuePairs(\n        PhpServiceTypePairs,\n        sizeof(PhpServiceTypePairs),\n        ServiceType,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return &PhpServiceUnknownString;\n}\n\n/**\n * Converts a service type string to its corresponding integer value.\n *\n * \\param ServiceType A pointer to a string reference containing the service type name.\n * \\return The integer value of the service type, or ULONG_MAX if not found.\n */\nULONG PhGetServiceTypeInteger(\n    _In_ PPH_STRINGREF ServiceType\n    )\n{\n    ULONG integer;\n\n    if (PhFindIntegerSiKeyValuePairsStringRef(\n        PhpServiceTypePairs,\n        sizeof(PhpServiceTypePairs),\n        ServiceType,\n        &integer\n        ))\n        return integer;\n    else\n        return ULONG_MAX;\n}\n\n/**\n * Retrieves the display string for a service start type value.\n *\n * \\param ServiceStartType The service start type value (e.g., SERVICE_AUTO_START).\n * \\return A pointer to a string reference describing the start type, or \"Unknown\" if not found.\n */\nPCPH_STRINGREF PhGetServiceStartTypeString(\n    _In_ ULONG ServiceStartType\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        PhpServiceStartTypePairs,\n        sizeof(PhpServiceStartTypePairs),\n        ServiceStartType,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return &PhpServiceUnknownString;\n}\n\n/**\n * Converts a service start type string to its corresponding integer value.\n *\n * \\param ServiceStartType A pointer to a string reference containing the start type name.\n * \\return The integer value of the start type, or ULONG_MAX if not found.\n */\nULONG PhGetServiceStartTypeInteger(\n    _In_ PPH_STRINGREF ServiceStartType\n    )\n{\n    ULONG integer;\n\n    if (PhFindIntegerSiKeyValuePairsStringRef(\n        PhpServiceStartTypePairs,\n        sizeof(PhpServiceStartTypePairs),\n        ServiceStartType,\n        &integer\n        ))\n        return integer;\n    else\n        return ULONG_MAX;\n}\n\n/**\n * Retrieves the display string for a service error control value.\n *\n * \\param ServiceErrorControl The service error control value (e.g., SERVICE_ERROR_NORMAL).\n * \\return A pointer to a string reference describing the error control, or \"Unknown\" if not found.\n */\nPCPH_STRINGREF PhGetServiceErrorControlString(\n    _In_ ULONG ServiceErrorControl\n    )\n{\n    PCPH_STRINGREF string;\n\n    if (PhIndexStringRefSiKeyValuePairs(\n        PhpServiceErrorControlPairs,\n        sizeof(PhpServiceErrorControlPairs),\n        ServiceErrorControl,\n        &string\n        ))\n    {\n        return string;\n    }\n\n    return &PhpServiceUnknownString;\n}\n\n/**\n * Converts a service error control string to its corresponding integer value.\n *\n * \\param ServiceErrorControl A pointer to a string reference containing the error control name.\n * \\return The integer value of the error control, or ULONG_MAX if not found.\n */\nULONG PhGetServiceErrorControlInteger(\n    _In_ PPH_STRINGREF ServiceErrorControl\n    )\n{\n    ULONG integer;\n\n    if (PhFindIntegerSiKeyValuePairsStringRef(\n        PhpServiceErrorControlPairs,\n        sizeof(PhpServiceErrorControlPairs),\n        ServiceErrorControl,\n        &integer\n        ))\n        return integer;\n    else\n        return ULONG_MAX;\n}\n\n/**\n * Retrieves the service name associated with a service tag in a process.\n *\n * \\param ProcessId The process ID to query.\n * \\param ServiceTag The service tag value.\n * \\return A newly allocated PPH_STRING containing the service name, or NULL if not found.\n */\nPPH_STRING PhGetServiceNameFromTag(\n    _In_ HANDLE ProcessId,\n    _In_ PVOID ServiceTag\n    )\n{\n    static typeof(&I_QueryTagInformation) QueryTagInformation_I = NULL;\n    PPH_STRING serviceName = NULL;\n    TAG_INFO_NAME_FROM_TAG nameFromTag;\n\n    if (!QueryTagInformation_I)\n    {\n        QueryTagInformation_I = PhGetDllProcedureAddressZ(L\"sechost.dll\", \"I_QueryTagInformation\", 0);\n    }\n\n    if (!QueryTagInformation_I)\n        return NULL;\n\n    memset(&nameFromTag, 0, sizeof(TAG_INFO_NAME_FROM_TAG));\n    nameFromTag.InParams.ProcessId = HandleToUlong(ProcessId);\n    nameFromTag.InParams.ServiceTag = PtrToUlong(ServiceTag);\n\n    QueryTagInformation_I(NULL, eTagInfoLevelNameFromTag, &nameFromTag);\n\n    if (nameFromTag.OutParams.Name)\n    {\n        serviceName = PhCreateString(nameFromTag.OutParams.Name);\n        LocalFree((HLOCAL)nameFromTag.OutParams.Name);\n    }\n\n    return serviceName;\n}\n\n/**\n * Retrieves a comma-separated list of service names referencing a module in a process.\n *\n * \\param ProcessId The process ID to query.\n * \\param ModuleName The name of the module to check for service references.\n * \\return A newly allocated PPH_STRING containing the service names, or NULL if not found.\n */\nPPH_STRING PhGetServiceNameForModuleReference(\n    _In_ HANDLE ProcessId,\n    _In_ PCWSTR ModuleName\n    )\n{\n    static typeof(&I_QueryTagInformation) QueryTagInformation_I = NULL;\n    PPH_STRING serviceNames = NULL;\n    TAG_INFO_NAMES_REFERENCING_MODULE moduleNameRef;\n\n    if (!QueryTagInformation_I)\n    {\n        if (WindowsVersion >= WINDOWS_8_1)\n        {\n            QueryTagInformation_I = PhGetDllProcedureAddressZ(L\"sechost.dll\", \"I_QueryTagInformation\", 0);\n        }\n\n        if (!QueryTagInformation_I)\n            QueryTagInformation_I = PhGetDllProcedureAddressZ(L\"advapi32.dll\", \"I_QueryTagInformation\", 0);\n    }\n\n    if (!QueryTagInformation_I)\n        return NULL;\n\n    memset(&moduleNameRef, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE));\n    moduleNameRef.InParams.ProcessId = HandleToUlong(ProcessId);\n    moduleNameRef.InParams.ModuleName = ModuleName;\n\n    QueryTagInformation_I(NULL, eTagInfoLevelNamesReferencingModule, &moduleNameRef);\n\n    if (moduleNameRef.OutParams.Names)\n    {\n        PH_STRING_BUILDER sb;\n        PCWSTR serviceName;\n\n        PhInitializeStringBuilder(&sb, 0x40);\n\n        for (serviceName = moduleNameRef.OutParams.Names; *serviceName; serviceName += PhCountStringZ(serviceName) + 1)\n            PhAppendFormatStringBuilder(&sb, L\"%s, \", serviceName);\n\n        if (sb.String->Length != 0)\n            PhRemoveEndStringBuilder(&sb, 2);\n\n        serviceNames = PhFinalStringBuilderString(&sb);\n        LocalFree((HLOCAL)moduleNameRef.OutParams.Names);\n    }\n\n    return serviceNames;\n}\n\n/**\n * Retrieves the service tag value for a thread in a process.\n *\n * \\param ThreadHandle Handle to the thread.\n * \\param ProcessHandle Handle to the process containing the thread.\n * \\param ServiceTag Receives the service tag value.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetThreadServiceTag(\n    _In_ HANDLE ThreadHandle,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID *ServiceTag\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n\n    status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo);\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.TebBaseAddress, FIELD_OFFSET(TEB, SubProcessTag)),\n            ServiceTag,\n            sizeof(PVOID),\n            NULL\n            );\n    }\n\n    return status;\n}\n\n/**\n * Builds the full registry key name for a service.\n *\n * \\param ServiceName The service name as a string reference.\n * \\return A newly allocated PPH_STRING containing the full registry key name.\n */\nPPH_STRING PhGetServiceKeyName(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    static CONST PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Services\");\n\n    return PhConcatStringRef3(&servicesKeyName, &PhNtPathSeparatorString, ServiceName);\n}\n\n/**\n * Builds the full registry key name for a service's Parameters subkey.\n *\n * \\param ServiceName The service name as a string reference.\n * \\return A newly allocated PPH_STRING containing the full Parameters subkey name.\n */\nPPH_STRING PhGetServiceParametersKeyName(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    static CONST PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Services\");\n    static CONST PH_STRINGREF parametersKeyName = PH_STRINGREF_INIT(L\"\\\\Parameters\");\n\n    return PhConcatStringRef4(&servicesKeyName, &PhNtPathSeparatorString, ServiceName, &parametersKeyName);\n}\n\n/**\n * Attempts to determine the file name of a service's binary or DLL.\n *\n * \\param ServiceType The service type flags.\n * \\param ServicePathName The service's binary path name.\n * \\param ServiceName The service name as a string reference.\n * \\return A newly allocated PPH_STRING containing the file name, or NULL if not found.\n */\nPPH_STRING PhGetServiceConfigFileName(\n    _In_ ULONG ServiceType,\n    _In_opt_ PCWSTR ServicePathName,\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName = NULL;\n\n    status = PhGetServiceDllParameter(ServiceType, ServiceName, &fileName);\n\n    if (!NT_SUCCESS(status))\n    {\n        if (ServicePathName && ServicePathName[0])\n        {\n            PPH_STRING commandLine = PhCreateString(ServicePathName);\n\n            if (FlagOn(ServiceType, SERVICE_WIN32))\n            {\n                PPH_STRING fileFullName = NULL;\n                PH_STRINGREF dummyFileName = { 0 };\n                PH_STRINGREF dummyArguments = { 0 };\n\n                if (PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileFullName))\n                {\n                    PhSwapReference(&fileName, fileFullName);\n                }\n                else\n                {\n                    PhSwapReference(&fileName, PhGetFileName(commandLine));\n                }\n\n                PhClearReference(&fileFullName);\n            }\n            else\n            {\n                PhMoveReference(&fileName, PhGetFileName(commandLine));\n            }\n\n            PhDereferenceObject(commandLine);\n        }\n    }\n\n    return fileName;\n}\n\n/**\n * Attempts to determine the file name of a service's binary or DLL (variant).\n *\n * \\param ServiceType The service type flags.\n * \\param ServicePathName The service's binary path name.\n * \\param ServiceName The service name as a string reference.\n * \\param ServiceFileName Receives a pointer to the file name string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetServiceConfigFileName2(\n    _In_ ULONG ServiceType,\n    _In_opt_ PCWSTR ServicePathName,\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PPH_STRING* ServiceFileName\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName = NULL;\n\n    status = PhGetServiceDllParameter(ServiceType, ServiceName, &fileName);\n\n    if (!NT_SUCCESS(status))\n    {\n        if (ServicePathName && ServicePathName[0])\n        {\n            PPH_STRING commandLine = PhCreateString(ServicePathName);\n\n            if (FlagOn(ServiceType, SERVICE_WIN32))\n            {\n                PPH_STRING fileFullName = NULL;\n                PH_STRINGREF dummyFileName = { 0 };\n                PH_STRINGREF dummyArguments = { 0 };\n\n                if (PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileFullName))\n                {\n                    PhSwapReference(&fileName, fileFullName);\n                }\n                else\n                {\n                    PhSwapReference(&fileName, PhGetFileName(commandLine));\n                }\n\n                PhClearReference(&fileFullName);\n            }\n            else\n            {\n                PhMoveReference(&fileName, PhGetFileName(commandLine));\n            }\n\n            if (!PhIsNullOrEmptyString(fileName))\n            {\n                *ServiceFileName = fileName;\n                status = STATUS_SUCCESS;\n            }\n\n            PhDereferenceObject(commandLine);\n        }\n    }\n    else\n    {\n        *ServiceFileName = fileName;\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the file name of a service's binary or DLL using a service handle.\n *\n * \\param ServiceHandle Handle to the service.\n * \\param ServiceName The service name as a string reference.\n * \\param ServiceFileName Receives a pointer to the file name string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetServiceHandleFileName(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PPH_STRING* ServiceFileName\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName;\n    LPQUERY_SERVICE_CONFIG config;\n\n    status = PhGetServiceConfig(ServiceHandle, &config);\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetServiceConfigFileName2(\n            config->dwServiceType,\n            config->lpBinaryPathName,\n            ServiceName,\n            &fileName\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            *ServiceFileName = fileName;\n        }\n\n        PhFree(config);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the file name of a service's binary or DLL from the registry.\n *\n * \\param ServiceName The service name as a string reference.\n * \\param ServiceFileName Receives a pointer to the file name string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetServiceFileName(\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PPH_STRING* ServiceFileName\n    )\n{\n    PPH_STRING serviceDllString = NULL;\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = PhOpenServiceKey(\n        &keyHandle,\n        KEY_READ,\n        ServiceName\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (serviceDllString = PhQueryRegistryStringZ(keyHandle, L\"ImagePath\"))\n        {\n            PPH_STRING expandedString;\n\n            if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr))\n            {\n                PH_STRINGREF fileName;\n                PH_STRINGREF arguments;\n\n                if (PhParseCommandLineFuzzy(&expandedString->sr, &fileName, &arguments, NULL))\n                {\n                    PhMoveReference(&serviceDllString, PhCreateString2(&fileName));\n                }\n                else\n                {\n                    PhSwapReference(&serviceDllString, expandedString);\n                }\n\n                PhDereferenceObject(expandedString);\n            }\n        }\n        else\n        {\n            status = STATUS_NOT_FOUND;\n        }\n\n        NtClose(keyHandle);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *ServiceFileName = serviceDllString;\n    }\n    else\n    {\n        PhClearReference(&serviceDllString);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the ServiceDll value for a service from the registry.\n *\n * \\param ServiceKeyName The full registry key name for the service.\n * \\param ServiceDll Receives a pointer to the ServiceDll string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhpGetServiceDllName(\n    _In_ PPH_STRING ServiceKeyName,\n    _Out_ PPH_STRING* ServiceDll\n    )\n{\n    PPH_STRING serviceDllString = NULL;\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &ServiceKeyName->sr,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (serviceDllString = PhQueryRegistryStringZ(keyHandle, L\"ServiceDll\"))\n        {\n            PPH_STRING expandedString;\n\n            if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr))\n            {\n                PhMoveReference(&serviceDllString, expandedString);\n            }\n        }\n        else\n        {\n            status = STATUS_NOT_FOUND;\n        }\n\n        NtClose(keyHandle);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *ServiceDll = serviceDllString;\n    }\n    else\n    {\n        PhClearReference(&serviceDllString);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the ServiceDll parameter for a service, handling user service instances.\n *\n * \\param ServiceType The service type flags.\n * \\param ServiceName The service name as a string reference.\n * \\param ServiceDll Receives a pointer to the ServiceDll string.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetServiceDllParameter(\n    _In_ ULONG ServiceType,\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PPH_STRING *ServiceDll\n    )\n{\n    NTSTATUS status;\n    PPH_STRING serviceDllString;\n    PPH_STRING keyName;\n\n    if (FlagOn(ServiceType, SERVICE_USERSERVICE_INSTANCE))\n    {\n        PH_STRINGREF hostServiceName;\n        PH_STRINGREF userSessionLuid;\n\n        // The SCM creates multiple \"user service instance\" processes for each user session with the following template:\n        // [Host Service Instance Name]_[LUID for Session]\n        // The SCM internally uses the ServiceDll of the \"host service instance\" for all \"user service instance\" processes/services\n        // and we need to parse the user service template and query the \"host service instance\" configuration. (hsebs)\n\n        if (PhSplitStringRefAtLastChar(ServiceName, L'_', &hostServiceName, &userSessionLuid))\n        {\n            keyName = PhGetServiceParametersKeyName(&hostServiceName);\n        }\n        else\n        {\n            keyName = PhGetServiceParametersKeyName(ServiceName);\n        }\n    }\n    else\n    {\n        keyName = PhGetServiceParametersKeyName(ServiceName);\n    }\n\n    status = PhpGetServiceDllName(\n        keyName,\n        &serviceDllString\n        );\n\n    PhDereferenceObject(keyName);\n\n    if (NT_SUCCESS(status))\n    {\n        *ServiceDll = serviceDllString;\n        return STATUS_SUCCESS;\n    }\n\n    if (\n        (WindowsVersion == WINDOWS_8 || WindowsVersion == WINDOWS_8_1) &&\n        (status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NOT_FOUND)\n        )\n    {\n        keyName = PhGetServiceKeyName(ServiceName);\n\n        // Windows 8 places the ServiceDll for some services in the root key. (dmex)\n        status = PhpGetServiceDllName(\n            keyName,\n            &serviceDllString\n            );\n\n        PhDereferenceObject(keyName);\n\n        if (NT_SUCCESS(status))\n        {\n            *ServiceDll = serviceDllString;\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Retrieves the AppUserModelId value for a service from the registry.\n *\n * \\param ServiceName The service name as a string reference.\n * \\return A PPH_STRING containing the AppUserModelId, or NULL if not found.\n */\nPPH_STRING PhGetServiceAppUserModelId(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    PPH_STRING serviceAppUserModelId = NULL;\n    HANDLE keyHandle;\n\n    if (NT_SUCCESS(PhOpenServiceKey(\n        &keyHandle,\n        KEY_READ,\n        ServiceName\n        )))\n    {\n        serviceAppUserModelId = PhQueryRegistryStringZ(keyHandle, L\"AppUserModelId\");\n\n        NtClose(keyHandle);\n    }\n\n    return serviceAppUserModelId;\n}\n\n/**\n * Retrieves the BootFlags value for a service from the registry.\n *\n * \\param ServiceName The service name as a string reference.\n * \\return The BootFlags value, or 0 if not found.\n */\nULONG PhGetServiceBootFlags(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    ULONG serviceBootFlags = 0;\n    HANDLE keyHandle;\n\n    if (NT_SUCCESS(PhOpenServiceKey(\n        &keyHandle,\n        KEY_READ,\n        ServiceName\n        )))\n    {\n        serviceBootFlags = PhQueryRegistryUlongZ(keyHandle, L\"BootFlags\");\n\n        NtClose(keyHandle);\n    }\n\n    if (serviceBootFlags == ULONG_MAX)\n    {\n        PPH_STRING serviceKeyName;\n\n        serviceKeyName = PhGetServiceParametersKeyName(ServiceName);\n\n        if (NT_SUCCESS(PhOpenKey(\n            &keyHandle,\n            KEY_READ,\n            PH_KEY_LOCAL_MACHINE,\n            &serviceKeyName->sr,\n            0\n            )))\n        {\n            serviceBootFlags = PhQueryRegistryUlongZ(keyHandle, L\"BootFlags\");\n\n            NtClose(keyHandle);\n        }\n\n        PhDereferenceObject(serviceKeyName);\n    }\n\n    return serviceBootFlags;\n}\n\n/**\n * Retrieves the UserServiceFlags value for a service from the registry.\n *\n * \\param ServiceName The service name as a string reference.\n * \\return The UserServiceFlags value, or 0 if not found.\n */\nULONG PhGetServiceUserFlags(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    ULONG userServiceFlags = 0;\n    HANDLE keyHandle;\n\n    if (NT_SUCCESS(PhOpenServiceKey(\n        &keyHandle,\n        KEY_READ,\n        ServiceName\n        )))\n    {\n        userServiceFlags = PhQueryRegistryUlongZ(keyHandle, L\"UserServiceFlags\");\n\n        NtClose(keyHandle);\n    }\n\n    if (userServiceFlags == ULONG_MAX)\n        userServiceFlags = 0;\n\n    return userServiceFlags;\n}\n\n/**\n * Retrieves the PackageFullName value for a service.\n *\n * \\param ServiceName Name of the service.\n * \\return A PPH_STRING containing the PackageFullName, or NULL if not found.\n */\nPPH_STRING PhGetServicePackageFullName(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    PPH_STRING servicePackageName = NULL;\n    HANDLE keyHandle;\n\n    if (NT_SUCCESS(PhOpenServiceKey(\n        &keyHandle,\n        KEY_READ,\n        ServiceName\n        )))\n    {\n        servicePackageName = PhQueryRegistryStringZ(keyHandle, L\"PackageFullName\");\n\n        NtClose(keyHandle);\n    }\n\n    return servicePackageName;\n}\n\n/**\n * Queries the Group value for a service.\n *\n * \\param ServiceName Name of the service.\n * \\return A PPH_STRING containing the GroupName, or NULL if not found.\n */\nPPH_STRING PhGetServiceGroupName(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    PPH_STRING groupName = NULL;\n    HANDLE keyHandle;\n\n    if (NT_SUCCESS(PhOpenServiceKey(\n        &keyHandle,\n        KEY_READ,\n        ServiceName\n        )))\n    {\n        groupName = PhQueryRegistryStringZ(keyHandle, L\"Group\");\n        NtClose(keyHandle);\n    }\n\n    return groupName;\n}\n\nPPH_STRING PhGetEarlyStartServices(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Control\");\n    PPH_STRING earlyStartServices = NULL;\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &servicesKeyName,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        earlyStartServices = PhQueryRegistryStringZ(keyHandle, L\"EarlyStartServices\");\n\n        NtClose(keyHandle);\n    }\n\n    return earlyStartServices;\n}\n\nPPH_STRING PhGetSvchostGroup(\n    _In_ PPH_STRINGREF GroupName\n    )\n{\n    static CONST PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Svchost\");\n    PPH_STRING string = NULL;\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &servicesKeyName,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        string = PhQueryRegistryString(keyHandle, GroupName);\n\n        NtClose(keyHandle);\n    }\n\n    return string;\n}\n\nPPH_STRING PhGetSvchostGroupKeyName(\n    _In_ PPH_STRINGREF GroupName\n    )\n{\n    static CONST PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Svchost\");\n    static CONST PH_STRINGREF servicesKeySeperatorName = PH_STRINGREF_INIT(L\"\\\\\");\n\n    return PhConcatStringRef3(&servicesKeyName, &servicesKeySeperatorName, GroupName);\n}\n\nPPH_SVC_HOST_POLICY_INFO PhGetSvchostGroupPolicy(\n    _In_ PPH_STRINGREF ServiceName\n    )\n{\n    PPH_SVC_HOST_POLICY_INFO policyInfo = NULL;\n    PPH_STRING keyName;\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    keyName = PhGetServiceKeyName(ServiceName);\n\n    status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &keyName->sr,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        policyInfo = PhAllocateZero(sizeof(PH_SVC_HOST_POLICY_INFO));\n\n        policyInfo->AuthenticationCapabilities = PhQueryRegistryUlongZ(keyHandle, L\"AuthenticationCapabilities\");\n        policyInfo->AuthenticationLevel = PhQueryRegistryUlongZ(keyHandle, L\"AuthenticationLevel\");\n        policyInfo->BinarySignaturePolicy = PhQueryRegistryUlongZ(keyHandle, L\"BinarySignaturePolicy\");\n        policyInfo->CoInitializeSecurityAllowComCapability = PhQueryRegistryUlongZ(keyHandle, L\"CoInitializeSecurityAllowComCapability\");\n        policyInfo->CoInitializeSecurityAllowCrossContainer = PhQueryRegistryUlongZ(keyHandle, L\"CoInitializeSecurityAllowInteractiveUsers\");\n        policyInfo->CoInitializeSecurityAllowLowBox = PhQueryRegistryUlongZ(keyHandle, L\"CoInitializeSecurityAllowLowBox\");\n        policyInfo->CoInitializeSecurityParam = PhQueryRegistryUlongZ(keyHandle, L\"CoInitializeSecurityParam\");\n        policyInfo->COM_UnmarshalingPolicy = PhQueryRegistryUlongZ(keyHandle, L\"COM_UnmarshalingPolicy\");\n        policyInfo->DefaultRpcStackSize = PhQueryRegistryUlongZ(keyHandle, L\"DefaultRpcStackSize\");\n        policyInfo->DynamicCodePolicy = PhQueryRegistryUlongZ(keyHandle, L\"DynamicCodePolicy\");\n        policyInfo->ImpersonationLevel = PhQueryRegistryUlongZ(keyHandle, L\"ImpersonationLevel\");\n        policyInfo->RedirectionTrustPolicy = PhQueryRegistryUlongZ(keyHandle, L\"RedirectionTrustPolicy\");\n        policyInfo->RpcExceptionFilterMode = PhQueryRegistryUlongZ(keyHandle, L\"RpcExceptionFilterMode\");\n\n        //KEY_VALUE_PARTIAL_INFORMATION keyValueInfo;\n        //status = PhQueryValueKeyZ(\n        //    keyHandle,\n        //    L\"COMAccessPermissionsSD\",\n        //    KeyValuePartialInformation,\n        //    &keyValueInfo\n        //    );\n\n        NtClose(keyHandle);\n    }\n\n    PhDereferenceObject(keyName);\n\n    return policyInfo;\n}\n\nNTSTATUS PhWaitForServiceStatus(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG WaitForState,\n    _In_ ULONG Timeout\n    )\n{\n    NTSTATUS status;\n    SERVICE_STATUS_PROCESS serviceStatus;\n    ULONG64 startTick;\n    ULONG64 lastProgressTick;\n    ULONG serviceCheck;\n\n    status = PhQueryServiceStatus(ServiceHandle, &serviceStatus);\n    if (!NT_SUCCESS(status))\n        return status;\n    if (serviceStatus.dwCurrentState == WaitForState)\n        return STATUS_SUCCESS;\n\n    startTick = NtGetTickCount64();\n    lastProgressTick = startTick;\n    serviceCheck = serviceStatus.dwCheckPoint;\n\n    while (\n        serviceStatus.dwCurrentState == SERVICE_START_PENDING ||\n        serviceStatus.dwCurrentState == SERVICE_STOP_PENDING ||\n        serviceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING ||\n        serviceStatus.dwCurrentState == SERVICE_PAUSE_PENDING\n        )\n    {\n        ULONG statusWaitHint = serviceStatus.dwWaitHint / 10;\n        ULONG64 nowTick;\n\n        if (statusWaitHint < 1000)\n            statusWaitHint = 1000;\n        if (statusWaitHint > 10000)\n            statusWaitHint = 10000;\n\n        PhDelayExecution(statusWaitHint);\n\n        status = PhQueryServiceStatus(ServiceHandle, &serviceStatus);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (serviceStatus.dwCurrentState == WaitForState)\n            return STATUS_SUCCESS;\n\n        if (!(\n            serviceStatus.dwCurrentState == SERVICE_START_PENDING ||\n            serviceStatus.dwCurrentState == SERVICE_STOP_PENDING ||\n            serviceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING ||\n            serviceStatus.dwCurrentState == SERVICE_PAUSE_PENDING\n            ))\n        {\n            return STATUS_SUCCESS;\n        }\n\n        nowTick = NtGetTickCount64();\n\n        if (serviceStatus.dwCheckPoint > serviceCheck)\n        {\n            serviceCheck = serviceStatus.dwCheckPoint;\n            lastProgressTick = nowTick;\n        }\n        else if ((nowTick - lastProgressTick) > serviceStatus.dwWaitHint)\n        {\n            // Service doesn't report progress.\n        }\n\n        if (Timeout && (nowTick - startTick) > Timeout)\n        {\n            return STATUS_TIMEOUT; // STATUS_IO_TIMEOUT\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Queries whether a service is configured for SafeBoot (Safe Mode or Safe Mode with Networking).\n *\n * \\param ServiceName Name of the service.\n * \\param DriverName Name of the service.\n * \\param SafeModeNormal Receives TRUE if the service is configured to start in Safe Mode.\n * \\param SafeModeNetwork Receives TRUE if the service is configured to start in Safe Mode with Network.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetServiceSafeBootStart(\n    _In_opt_ PPH_STRINGREF ServiceName,\n    _In_opt_ PPH_STRINGREF DriverName,\n    _Out_ PBOOLEAN SafeModeNormal,\n    _Out_ PBOOLEAN SafeModeNetwork\n    )\n{\n    static CONST PH_STRINGREF keyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Control\\\\SafeBoot\");\n    static CONST PH_STRINGREF keyNameSafeBoot[] = { PH_STRINGREF_INIT(L\"Minimal\"), PH_STRINGREF_INIT(L\"Network\") };\n    NTSTATUS status;\n    HANDLE safeBootKeyHandle = NULL;\n    HANDLE groupKeyHandle = NULL;\n    HANDLE serviceKeyHandle = NULL;\n    BOOLEAN safeModeNormalFound = FALSE;\n    BOOLEAN safeModeNetworkFound = FALSE;\n\n    *SafeModeNormal = FALSE;\n    *SafeModeNetwork = FALSE;\n\n    status = PhOpenKey(\n        &safeBootKeyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &keyName,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    for (ULONG i = 0; i < RTL_NUMBER_OF(keyNameSafeBoot); i++)\n    {\n        if (NT_SUCCESS(PhOpenKey(\n            &groupKeyHandle,\n            KEY_READ,\n            safeBootKeyHandle,\n            &keyNameSafeBoot[i],\n            0\n            )))\n        {\n            if (ServiceName && PhOpenKey(\n                &serviceKeyHandle,\n                KEY_READ,\n                groupKeyHandle,\n                ServiceName,\n                0\n                ))\n            {\n                if (i == 0)\n                    safeModeNormalFound = TRUE;\n                else if (i == 1)\n                    safeModeNetworkFound = TRUE;\n\n                NtClose(serviceKeyHandle);\n            }\n\n            if (DriverName && PhOpenKey(\n                &serviceKeyHandle,\n                KEY_READ,\n                groupKeyHandle,\n                DriverName,\n                0\n                ))\n            {\n                if (i == 0)\n                    safeModeNormalFound = TRUE;\n                else if (i == 1)\n                    safeModeNetworkFound = TRUE;\n\n                NtClose(serviceKeyHandle);\n            }\n\n            NtClose(groupKeyHandle);\n        }\n    }\n\n    NtClose(safeBootKeyHandle);\n\n    *SafeModeNormal = safeModeNormalFound;\n    *SafeModeNetwork = safeModeNetworkFound;\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves the security descriptor for a service directly from the registry.\n *\n * \\param ServiceName Name of the service.\n * \\param SecurityDescriptor Receives a pointer to the security descriptor. Caller must free with PhFree.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetServiceRegistrySecurityDescriptor(\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PSECURITY_DESCRIPTOR* SecurityDescriptor\n    )\n{\n    static const PH_STRINGREF securityKeyName = PH_STRINGREF_INIT(L\"Security\");\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    HANDLE keyHandle = NULL;\n    PKEY_VALUE_PARTIAL_INFORMATION keyValueInfo;\n    PPH_STRING serviceKeyName = NULL;\n    PVOID buffer = NULL;\n    ULONG bufferSize = 0;\n    ULONG resultLength = 0;\n\n    *SecurityDescriptor = NULL;\n\n    // Build the full registry path: System\\CurrentControlSet\\Services\\<ServiceName>\\Security\n    serviceKeyName = PhGetServiceKeyName(ServiceName);\n\n    if (!serviceKeyName)\n    {\n        return STATUS_NO_MEMORY;\n    }\n\n    // Append \"\\Security\" to the service key name\n    PhSwapReference(&serviceKeyName, PhConcatStringRef3(\n        &serviceKeyName->sr, \n        &PhNtPathSeparatorString,\n        &securityKeyName\n        ));\n\n    status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &serviceKeyName->sr,\n        0\n        );\n\n    PhDereferenceObject(serviceKeyName);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhQueryValueKey(\n        keyHandle,\n        &securityKeyName,\n        KeyValuePartialInformation,\n        &keyValueInfo\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (keyValueInfo->Type == REG_BINARY)\n        {\n            RtlMoveMemory(SecurityDescriptor, keyValueInfo->Data, keyValueInfo->DataLength);\n            return STATUS_SUCCESS;\n        }\n        else\n        {\n            status = STATUS_INVALID_SECURITY_DESCR;\n        }\n\n        NtClose(keyHandle);\n    }\n    else if (NT_SUCCESS(status) && bufferSize == 0)\n    {\n        status = STATUS_INVALID_SECURITY_DESCR;\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\n/**\n * Builds the full registry key name for a service into a caller-supplied buffer.\n *\n * \\param ServiceName Name of the service.\n * \\param Buffer Buffer to receive the key name.\n * \\param BufferLength Length of the buffer in characters.\n * \\param RequiredLength Receives the required length in characters (including null terminator).\n * \\return TRUE if successful, FALSE if the buffer is too small.\n */\n_Success_(return)\nBOOLEAN PhGetServiceKeyNameToBuffer(\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_writes_to_opt_(BufferLength, *RequiredLength) PWSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T RequiredLength\n    )\n{\n    static CONST PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Services\");\n    SIZE_T totalLength = servicesKeyName.Length / sizeof(WCHAR) + ServiceName->Length / sizeof(WCHAR);\n    SIZE_T requiredLength = totalLength + 1;\n\n    if (RequiredLength)\n    {\n        *RequiredLength = requiredLength;\n    }\n\n    if (BufferLength < requiredLength)\n        return FALSE;\n\n    memcpy(Buffer, servicesKeyName.Buffer, servicesKeyName.Length);\n    memcpy(Buffer + (servicesKeyName.Length / sizeof(WCHAR)), ServiceName->Buffer, ServiceName->Length);\n    Buffer[totalLength] = 0;\n\n    return TRUE;\n}\n\n/**\n * Builds the full registry key name for a service's Parameters subkey into a caller-supplied buffer.\n *\n * \\param ServiceName Name of the service.\n * \\param Buffer Buffer to receive the key name.\n * \\param BufferLength Length of the buffer in characters.\n * \\param RequiredLength Receives the required length in characters (including null terminator).\n * \\return TRUE if successful, FALSE if the buffer is too small.\n */\n_Success_(return)\nBOOLEAN PhGetServiceParametersKeyNameToBuffer(\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_writes_to_opt_(BufferLength, *RequiredLength) PWSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T RequiredLength\n    )\n{\n    static CONST PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Services\");\n    static CONST PH_STRINGREF parametersKeyName = PH_STRINGREF_INIT(L\"\\\\Parameters\");\n    SIZE_T totalLength;\n    SIZE_T requiredLength;\n\n    totalLength =\n        servicesKeyName.Length / sizeof(WCHAR) +\n        ServiceName->Length / sizeof(WCHAR) +\n        parametersKeyName.Length / sizeof(WCHAR);\n\n    requiredLength = totalLength + 1;\n\n    if (RequiredLength)\n    {\n        *RequiredLength = requiredLength;\n    }\n\n    if (BufferLength < requiredLength)\n    {\n        return FALSE;\n    }\n\n    memcpy(Buffer, servicesKeyName.Buffer, servicesKeyName.Length);\n    memcpy(Buffer + (servicesKeyName.Length / sizeof(WCHAR)), ServiceName->Buffer, ServiceName->Length);\n    memcpy(Buffer + (servicesKeyName.Length / sizeof(WCHAR)) + (ServiceName->Length / sizeof(WCHAR)), parametersKeyName.Buffer, parametersKeyName.Length);\n    Buffer[totalLength] = 0;\n\n    return TRUE;\n}\n\n"
  },
  {
    "path": "phlib/symprv.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *     dmex    2017-2023\n *\n */\n\n#include <ph.h>\n\n#include <combaseapi.h>\n#include <dbghelp.h>\n\n#include <symprv.h>\n#include <symprvp.h>\n#include <fastlock.h>\n#include <kphuser.h>\n#include <verify.h>\n#include <mapimg.h>\n#include <mapldr.h>\n#include <thirdparty.h>\n\n#if defined(_ARM64_)\n#define PH_THREAD_STACK_NATIVE_MACHINE IMAGE_FILE_MACHINE_ARM64\n#elif defined(_AMD64_)\n#define PH_THREAD_STACK_NATIVE_MACHINE IMAGE_FILE_MACHINE_AMD64\n#else\n#define PH_THREAD_STACK_NATIVE_MACHINE IMAGE_FILE_MACHINE_I386\n#endif\n\n#if defined(_ARM64_)\n#define PAC_DECODE_ADDRESS(Address) ((Address) & ~(USER_SHARED_DATA->UserPointerAuthMask))\n#endif\n\ntypedef struct _PH_SYMBOL_MODULE\n{\n    LIST_ENTRY ListEntry;\n    PH_AVL_LINKS Links;\n    PVOID BaseAddress;\n    ULONG Size;\n    PPH_STRING FileName;\n    USHORT Machine;\n    USHORT MappedMachine;\n} PH_SYMBOL_MODULE, *PPH_SYMBOL_MODULE;\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpSymbolProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nBOOLEAN PhpRegisterSymbolProvider(\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider\n    );\n\nVOID PhpUnregisterSymbolProvider(\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider\n    );\n\nVOID PhpFreeSymbolModule(\n    _In_ PPH_SYMBOL_MODULE SymbolModule\n    );\n\n_Function_class_(PH_AVL_TREE_COMPARE_FUNCTION)\nLONG NTAPI PhpSymbolModuleCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    );\n\nPPH_OBJECT_TYPE PhSymbolProviderType = NULL;\nPH_CALLBACK_DECLARE(PhSymbolEventCallback);\nstatic PH_INITONCE PhSymInitOnce = PH_INITONCE_INIT;\nstatic HANDLE PhNextFakeHandle = (HANDLE)0;\nstatic PH_FAST_LOCK PhSymMutex = PH_FAST_LOCK_INIT;\n#if defined(PH_SYMEVNT_WORKQUEUE)\nstatic PH_FREE_LIST PhSymEventFreeList;\n#endif\n#define PH_LOCK_SYMBOLS() PhAcquireFastLockExclusive(&PhSymMutex)\n#define PH_UNLOCK_SYMBOLS() PhReleaseFastLockExclusive(&PhSymMutex)\n\ntypeof(&SymInitializeW) SymInitializeW_I = NULL;\ntypeof(&SymCleanup) SymCleanup_I = NULL;\ntypeof(&SymEnumSymbolsW) SymEnumSymbolsW_I = NULL;\ntypeof(&SymFromAddrW) SymFromAddrW_I = NULL;\ntypeof(&SymFromNameW) SymFromNameW_I = NULL;\ntypeof(&SymGetLineFromAddrW64) SymGetLineFromAddrW64_I = NULL;\ntypeof(&SymLoadModuleExW) SymLoadModuleExW_I = NULL;\ntypeof(&SymGetOptions) SymGetOptions_I = NULL;\ntypeof(&SymSetOptions) SymSetOptions_I = NULL;\ntypeof(&SymSetSearchPathW) SymSetSearchPathW_I = NULL;\ntypeof(&SymFunctionTableAccess64) SymFunctionTableAccess64_I = NULL;\ntypeof(&SymGetModuleBase64) SymGetModuleBase64_I = NULL;\ntypeof(&SymRegisterCallbackW64) SymRegisterCallbackW64_I = NULL;\ntypeof(&StackWalk64) StackWalk64_I = NULL;\ntypeof(&StackWalkEx) StackWalkEx_I = NULL;\ntypeof(&SymFromInlineContextW) SymFromInlineContextW_I = NULL;\ntypeof(&SymGetLineFromInlineContextW) SymGetLineFromInlineContextW_I = NULL;\ntypeof(&MiniDumpWriteDump) MiniDumpWriteDump_I = NULL;\ntypeof(&UnDecorateSymbolNameW) UnDecorateSymbolNameW_I = NULL;\n_SymGetDiaSource SymGetDiaSource_I = NULL;\n_SymGetDiaSession SymGetDiaSession_I = NULL;\n_SymFreeDiaString SymFreeDiaString_I = NULL;\nstatic ULONG PhSymbolProviderInternalOptions = PH_SYMOPT_VERIFY_MICROSOFT_CHAIN;\n\nPPH_SYMBOL_PROVIDER PhCreateSymbolProvider(\n    _In_opt_ HANDLE ProcessId\n    )\n{\n    static PH_INITONCE symbolProviderInitOnce = PH_INITONCE_INIT;\n    PPH_SYMBOL_PROVIDER symbolProvider;\n\n    if (PhBeginInitOnce(&symbolProviderInitOnce))\n    {\n        PhSymbolProviderType = PhCreateObjectType(L\"SymbolProvider\", 0, PhpSymbolProviderDeleteProcedure);\n        PhEndInitOnce(&symbolProviderInitOnce);\n    }\n\n    symbolProvider = PhCreateObject(sizeof(PH_SYMBOL_PROVIDER), PhSymbolProviderType);\n    memset(symbolProvider, 0, sizeof(PH_SYMBOL_PROVIDER));\n    InitializeListHead(&symbolProvider->ModulesListHead);\n    PhInitializeQueuedLock(&symbolProvider->ModulesListLock);\n    PhInitializeAvlTree(&symbolProvider->ModulesSet, PhpSymbolModuleCompareFunction);\n    PhInitializeInitOnce(&symbolProvider->InitOnce);\n\n    if (ProcessId)\n    {\n        static const ACCESS_MASK accesses[] =\n        {\n            //STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access\n            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE,\n            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n            MAXIMUM_ALLOWED\n        };\n\n        // Try to open the process with many different accesses.\n        // This handle will be re-used when walking stacks, and doing various other things.\n        for (ULONG i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++)\n        {\n            if (NT_SUCCESS(PhOpenProcess(&symbolProvider->ProcessHandle, accesses[i], ProcessId)))\n            {\n                symbolProvider->IsRealHandle = TRUE;\n                break;\n            }\n        }\n    }\n\n    if (!symbolProvider->IsRealHandle)\n    {\n        HANDLE fakeHandle;\n\n        // Just generate a fake handle.\n        fakeHandle = (HANDLE)_InterlockedExchangeAddPointer((PLONG_PTR)&PhNextFakeHandle, 4);\n        // Add one to make sure it isn't divisible by 4 (so it can't be mistaken for a real handle).\n        symbolProvider->ProcessHandle = (HANDLE)((ULONG_PTR)fakeHandle + 1);\n    }\n\n    return symbolProvider;\n}\n\n_Function_class_(PH_TYPE_DELETE_PROCEDURE)\nVOID NTAPI PhpSymbolProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)Object;\n    PLIST_ENTRY listEntry;\n\n    PhpUnregisterSymbolProvider(symbolProvider);\n\n    listEntry = symbolProvider->ModulesListHead.Flink;\n\n    while (listEntry != &symbolProvider->ModulesListHead)\n    {\n        PPH_SYMBOL_MODULE module;\n\n        module = CONTAINING_RECORD(listEntry, PH_SYMBOL_MODULE, ListEntry);\n        listEntry = listEntry->Flink;\n\n        PhpFreeSymbolModule(module);\n    }\n\n    if (symbolProvider->IsRealHandle) NtClose(symbolProvider->ProcessHandle);\n}\n\n#if defined(PH_SYMEVNT_WORKQUEUE)\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpSymbolProviderCallbackWorkItem(\n    _In_ PVOID Context\n    )\n{\n    PPH_SYMBOL_EVENT_DATA data = Context;\n\n    PhInvokeCallback(&PhSymbolEventCallback, data);\n\n    PhClearReference(&data->EventMessage);\n    PhFreeToFreeList(&PhSymEventFreeList, data);\n\n    return STATUS_SUCCESS;\n}\n#endif\n\nstatic VOID PhpSymbolProviderInvokeCallback(\n    _In_ ULONG EventType,\n    _In_opt_ PPH_STRING EventMessage,\n    _In_opt_ ULONG64 EventProgress\n    )\n{\n#if defined(PH_SYMEVNT_WORKQUEUE)\n    PPH_SYMBOL_EVENT_DATA data;\n\n    data = PhAllocateFromFreeList(&PhSymEventFreeList);\n    memset(data, 0, sizeof(PH_SYMBOL_EVENT_DATA));\n    data->EventType = EventType;\n    data->EventProgress = EventProgress;\n    PhSetReference(&data->EventMessage, EventMessage);\n\n    if (!NT_SUCCESS(PhQueueUserWorkItem(PhpSymbolProviderCallbackWorkItem, data)))\n    {\n        PhClearReference(&data->EventMessage);\n        PhFreeToFreeList(&PhSymEventFreeList, data);\n    }\n#else\n    PH_SYMBOL_EVENT_DATA data;\n\n    memset(&data, 0, sizeof(PH_SYMBOL_EVENT_DATA));\n    data.EventType = EventType;\n    data.EventMessage = EventMessage;\n    data.EventProgress = EventProgress;\n\n    PhInvokeCallback(&PhSymbolEventCallback, &data);\n#endif\n}\n\nstatic VOID PhpSymbolProviderEventCallback(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG ActionCode,\n    _In_ ULONG64 CallbackData\n    )\n{\n    static PPH_STRING PhSymbolProviderEventMessageText = NULL;\n\n    switch (ActionCode)\n    {\n    case CBA_DEFERRED_SYMBOL_LOAD_START:\n        {\n            PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData;\n            PPH_STRING fileName;\n\n            if (PhGetModuleFromAddress(SymbolProvider, (PVOID)callbackData->BaseOfImage, &fileName))\n            {\n                PPH_STRING baseName = PhGetBaseName(fileName);\n                PH_FORMAT format[3];\n\n                // Loading symbols for %s...\n                PhInitFormatS(&format[0], L\"Loading symbols for \");\n                PhInitFormatS(&format[1], PhGetStringOrDefault(baseName, L\"image\"));\n                PhInitFormatS(&format[2], L\"...\");\n                PhMoveReference(&PhSymbolProviderEventMessageText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n\n                PhpSymbolProviderInvokeCallback(PH_SYMBOL_EVENT_TYPE_LOAD_START, PhSymbolProviderEventMessageText, 0);\n\n                PhClearReference(&baseName);\n                PhDereferenceObject(fileName);\n            }\n            else\n            {\n                PH_FORMAT format[3];\n\n                // Loading symbols for %s...\n                PhInitFormatS(&format[0], L\"Loading symbols for \");\n                PhInitFormatS(&format[1], L\"image\");\n                PhInitFormatS(&format[2], L\"...\");\n\n                PhMoveReference(&PhSymbolProviderEventMessageText, PhFormat(format, RTL_NUMBER_OF(format), 0));\n                PhpSymbolProviderInvokeCallback(PH_SYMBOL_EVENT_TYPE_LOAD_START, PhSymbolProviderEventMessageText, 0);\n            }\n        }\n        break;\n    case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:\n        {\n            PhClearReference(&PhSymbolProviderEventMessageText);\n            PhpSymbolProviderInvokeCallback(PH_SYMBOL_EVENT_TYPE_LOAD_END, NULL, 0);\n        }\n        break;\n    case CBA_XML_LOG:\n        {\n            PH_STRINGREF xmlStringRef;\n\n            PhInitializeStringRefLongHint(&xmlStringRef, (PCWSTR)CallbackData);\n\n            if (PhStartsWithStringRef2(&xmlStringRef, L\"<Progress percent\", TRUE))\n            {\n                ULONG_PTR progressStartIndex = SIZE_MAX;\n                ULONG_PTR progressEndIndex = SIZE_MAX;\n                ULONG_PTR progressValueLength = 0;\n                PPH_STRING string;\n\n                string = PhCreateString2(&xmlStringRef);\n\n                progressStartIndex = PhFindStringInString(string, 0, L\"percent=\\\"\");\n                if (progressStartIndex != SIZE_MAX)\n                    progressEndIndex = PhFindStringInString(string, progressStartIndex, L\"\\\"/>\");\n                if (progressEndIndex != SIZE_MAX)\n                    progressValueLength = progressEndIndex - progressStartIndex;\n\n                if (progressValueLength != 0)\n                {\n                    PPH_STRING valueString;\n                    ULONG64 integer = 0;\n\n                    valueString = PhSubstring(\n                        string,\n                        progressStartIndex + (RTL_NUMBER_OF(L\"percent=\\\"\") - 1),\n                        progressValueLength - (RTL_NUMBER_OF(L\"percent=\\\"\") - 1)\n                        );\n\n                    if (PhStringToUInt64(&valueString->sr, 10, &integer))\n                    {\n                        PPH_STRING status;\n                        PH_FORMAT format[4];\n\n                        // %s %I64u%%\n                        PhInitFormatS(&format[0], PhGetStringOrEmpty(PhSymbolProviderEventMessageText));\n                        PhInitFormatS(&format[1], L\" \");\n                        PhInitFormatSR(&format[2], valueString->sr);\n                        PhInitFormatC(&format[3], L'%');\n\n                        status = PhFormat(format, RTL_NUMBER_OF(format), 0);\n                        PhpSymbolProviderInvokeCallback(PH_SYMBOL_EVENT_TYPE_PROGRESS, status, integer);\n                        PhDereferenceObject(status);\n                    }\n\n                    PhDereferenceObject(valueString);\n                }\n\n                PhDereferenceObject(string);\n            }\n        }\n        break;\n    }\n}\n\nBOOL CALLBACK PhpSymbolCallbackFunction(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG ActionCode,\n    _In_opt_ ULONG64 CallbackData,\n    _In_opt_ ULONG64 UserContext\n    )\n{\n    PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)UserContext;\n\n    if (!IsListEmpty(&PhSymbolEventCallback.ListHead))\n    {\n        PhpSymbolProviderEventCallback(symbolProvider, ActionCode, CallbackData);\n    }\n\n    switch (ActionCode)\n    {\n    case CBA_DEFERRED_SYMBOL_LOAD_START:\n        {\n            PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData;\n            PPH_STRING fileName;\n            HANDLE fileHandle;\n\n            if (PhGetModuleFromAddress(symbolProvider, (PVOID)callbackData->BaseOfImage, &fileName))\n            {\n                if (NT_SUCCESS(PhCreateFile(\n                    &fileHandle,\n                    &fileName->sr,\n                    FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n                    FILE_ATTRIBUTE_NORMAL,\n                    FILE_SHARE_READ | FILE_SHARE_DELETE,\n                    FILE_OPEN,\n                    FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n                    )))\n                {\n                    callbackData->FileName[0] = UNICODE_NULL;\n                    callbackData->hFile = fileHandle;\n\n                    PhDereferenceObject(fileName);\n                    return TRUE;\n                }\n\n                PhDereferenceObject(fileName);\n            }\n        }\n        return FALSE;\n    case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:\n        {\n            PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData;\n\n            if (callbackData->hFile)\n            {\n                NtClose(callbackData->hFile);\n                callbackData->hFile = NULL;\n            }\n        }\n        return TRUE;\n//    case CBA_READ_MEMORY:\n//#ifndef _ARM64_\n//        {\n//            PIMAGEHLP_CBA_READ_MEMORY callbackData = (PIMAGEHLP_CBA_READ_MEMORY)CallbackData;\n//\n//            if (symbolProvider->IsRealHandle)\n//            {\n//                if (NT_SUCCESS(PhReadVirtualMemory(\n//                    ProcessHandle,\n//                    (PVOID)callbackData->addr,\n//                    callbackData->buf,\n//                    (SIZE_T)callbackData->bytes,\n//                    (PSIZE_T)callbackData->bytesread\n//                    )))\n//                {\n//                    return TRUE;\n//                }\n//            }\n//        }\n//#endif\n//        return FALSE;\n    case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:\n        {\n            if (symbolProvider->Terminating)\n                return TRUE;\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nVOID PhpSymbolProviderCompleteInitialization(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF windowsKitsRootKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows Kits\\\\Installed Roots\");\n    static CONST PH_STRINGREF dbgcoreFileName = PH_STRINGREF_INIT(L\"dbgcore.dll\"); // dbghelp.dll dependency required for MiniDumpWriteDump (dmex)\n    static CONST PH_STRINGREF dbghelpFileName = PH_STRINGREF_INIT(L\"dbghelp.dll\");\n    static CONST PH_STRINGREF symsrvFileName = PH_STRINGREF_INIT(L\"symsrv.dll\");\n    PPH_STRING winsdkPath;\n    PVOID dbgcoreHandle;\n    PVOID dbghelpHandle;\n    PVOID symsrvHandle;\n    HANDLE keyHandle;\n\n    if (\n        PhGetLoaderEntryDllBase(NULL, &dbgcoreFileName) &&\n        PhGetLoaderEntryDllBase(NULL, &dbghelpFileName) &&\n        PhGetLoaderEntryDllBase(NULL, &symsrvFileName)\n        )\n    {\n        return;\n    }\n\n#if defined(PH_SYMEVNT_WORKQUEUE)\n    PhInitializeFreeList(&PhSymEventFreeList, sizeof(PH_SYMBOL_EVENT_DATA), 5);\n#endif\n\n    winsdkPath = NULL;\n    dbgcoreHandle = NULL;\n    dbghelpHandle = NULL;\n    symsrvHandle = NULL;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &windowsKitsRootKeyName,\n        0\n        )))\n    {\n        PhMoveReference(&winsdkPath, PhQueryRegistryStringZ(keyHandle, L\"KitsRoot10\")); // Windows 10 SDK\n        if (PhIsNullOrEmptyString(winsdkPath))\n            PhMoveReference(&winsdkPath, PhQueryRegistryStringZ(keyHandle, L\"KitsRoot81\")); // Windows 8.1 SDK\n        if (PhIsNullOrEmptyString(winsdkPath))\n            PhMoveReference(&winsdkPath, PhQueryRegistryStringZ(keyHandle, L\"KitsRoot\")); // Windows 8 SDK\n\n        NtClose(keyHandle);\n    }\n\n    if (winsdkPath)\n    {\n        PPH_STRING dbgcoreName;\n        PPH_STRING dbghelpName;\n        PPH_STRING symsrvName;\n\n#if defined(_AMD64_)\n        PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L\"\\\\Debuggers\\\\x64\\\\\"));\n#elif defined(_ARM64_)\n        PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L\"\\\\Debuggers\\\\arm64\\\\\"));\n#else\n        PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L\"\\\\Debuggers\\\\x86\\\\\"));\n#endif\n        if (dbgcoreName = PhConcatStringRef3(&PhWin32ExtendedPathPrefix, &winsdkPath->sr, &dbgcoreFileName))\n        {\n            dbgcoreHandle = PhLoadLibrary(PhGetString(dbgcoreName));\n            PhDereferenceObject(dbgcoreName);\n        }\n\n        if (dbghelpName = PhConcatStringRef3(&PhWin32ExtendedPathPrefix, &winsdkPath->sr, &dbghelpFileName))\n        {\n            dbghelpHandle = PhLoadLibrary(PhGetString(dbghelpName));\n            PhDereferenceObject(dbghelpName);\n        }\n\n        if (symsrvName = PhConcatStringRef3(&PhWin32ExtendedPathPrefix, &winsdkPath->sr, &symsrvFileName))\n        {\n            symsrvHandle = PhLoadLibrary(PhGetString(symsrvName));\n            PhDereferenceObject(symsrvName);\n        }\n\n        PhDereferenceObject(winsdkPath);\n    }\n\n    if (!dbghelpHandle)\n    {\n        PPH_STRING applicationDirectory;\n        PPH_STRING dbgcoreName;\n        PPH_STRING dbghelpName;\n        PPH_STRING symsrvName;\n\n        if (applicationDirectory = PhGetApplicationDirectoryWin32())\n        {\n            if (dbgcoreName = PhConcatStringRef3(&PhWin32ExtendedPathPrefix, &applicationDirectory->sr, &dbgcoreFileName))\n            {\n                dbgcoreHandle = PhLoadLibrary(dbgcoreName->Buffer);\n                PhDereferenceObject(dbgcoreName);\n            }\n\n            if (dbghelpName = PhConcatStringRef3(&PhWin32ExtendedPathPrefix, &applicationDirectory->sr, &dbghelpFileName))\n            {\n                dbghelpHandle = PhLoadLibrary(dbghelpName->Buffer);\n                PhDereferenceObject(dbghelpName);\n            }\n\n            if (symsrvName = PhConcatStringRef3(&PhWin32ExtendedPathPrefix, &applicationDirectory->sr, &symsrvFileName))\n            {\n                symsrvHandle = PhLoadLibrary(symsrvName->Buffer);\n                PhDereferenceObject(symsrvName);\n            }\n\n            PhDereferenceObject(applicationDirectory);\n        }\n    }\n\n    if (!dbgcoreHandle)\n        dbgcoreHandle = PhLoadLibrary(L\"dbgcore.dll\");\n    if (!dbghelpHandle)\n        dbghelpHandle = PhLoadLibrary(L\"dbghelp.dll\");\n    if (!symsrvHandle)\n        symsrvHandle = PhLoadLibrary(L\"symsrv.dll\");\n\n    if (dbgcoreHandle)\n    {\n        MiniDumpWriteDump_I = PhGetDllBaseProcedureAddress(dbgcoreHandle, \"MiniDumpWriteDump\", 0);\n    }\n\n    if (dbghelpHandle)\n    {\n        SymInitializeW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymInitializeW\", 0);\n        SymCleanup_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymCleanup\", 0);\n        SymFromAddrW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymFromAddrW\", 0);\n        SymFromNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymFromNameW\", 0);\n        SymGetLineFromAddrW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymGetLineFromAddrW64\", 0);\n        SymLoadModuleExW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymLoadModuleExW\", 0);\n        SymGetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymGetOptions\", 0);\n        SymSetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymSetOptions\", 0);\n        SymSetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymSetSearchPathW\", 0);\n        SymFunctionTableAccess64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymFunctionTableAccess64\", 0);\n        SymGetModuleBase64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymGetModuleBase64\", 0);\n        SymRegisterCallbackW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymRegisterCallbackW64\", 0);\n        StackWalk64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"StackWalk64\", 0);\n        StackWalkEx_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"StackWalkEx\", 0);\n        SymFromInlineContextW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymFromInlineContextW\", 0);\n        SymGetLineFromInlineContextW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"SymGetLineFromInlineContextW\", 0);\n        UnDecorateSymbolNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"UnDecorateSymbolNameW\", 0);\n\n        if (!MiniDumpWriteDump_I)\n        {\n            MiniDumpWriteDump_I = PhGetDllBaseProcedureAddress(dbghelpHandle, \"MiniDumpWriteDump\", 0);\n        }\n    }\n}\n\nBOOLEAN PhpRegisterSymbolProvider(\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider\n    )\n{\n    if (PhBeginInitOnce(&PhSymInitOnce))\n    {\n        PhpSymbolProviderCompleteInitialization();\n\n        if (SymGetOptions_I && SymSetOptions_I)\n        {\n            PH_LOCK_SYMBOLS();\n\n            SymSetOptions_I(\n                SymGetOptions_I() |\n                SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS |\n                SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES |\n                SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME // | SYMOPT_DEBUG\n                );\n\n            PH_UNLOCK_SYMBOLS();\n        }\n\n        PhEndInitOnce(&PhSymInitOnce);\n    }\n\n    if (!SymbolProvider)\n        return FALSE;\n\n    if (PhBeginInitOnce(&SymbolProvider->InitOnce))\n    {\n        if (SymInitializeW_I)\n        {\n            PH_LOCK_SYMBOLS();\n\n            SymInitializeW_I(SymbolProvider->ProcessHandle, NULL, FALSE);\n\n            if (SymRegisterCallbackW64_I)\n                SymRegisterCallbackW64_I(SymbolProvider->ProcessHandle, PhpSymbolCallbackFunction, (ULONG64)SymbolProvider);\n\n            PH_UNLOCK_SYMBOLS();\n\n            SymbolProvider->IsRegistered = TRUE;\n        }\n\n\n        PhEndInitOnce(&SymbolProvider->InitOnce);\n    }\n\n    return SymbolProvider->IsRegistered;\n}\n\nVOID PhpUnregisterSymbolProvider(\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider\n    )\n{\n    if (!SymbolProvider)\n        return;\n\n    if (SymbolProvider->Terminating)\n        return;\n    SymbolProvider->Terminating = TRUE;\n\n    if (SymCleanup_I)\n    {\n        if (SymbolProvider->IsRegistered)\n        {\n            PH_LOCK_SYMBOLS();\n\n            SymCleanup_I(SymbolProvider->ProcessHandle);\n\n            PH_UNLOCK_SYMBOLS();\n        }\n\n        SymbolProvider->IsRegistered = FALSE;\n    }\n}\n\nVOID PhpFreeSymbolModule(\n    _In_ PPH_SYMBOL_MODULE SymbolModule\n    )\n{\n    if (SymbolModule->FileName) PhDereferenceObject(SymbolModule->FileName);\n\n    PhFree(SymbolModule);\n}\n\n_Function_class_(PH_AVL_TREE_COMPARE_FUNCTION)\nLONG NTAPI PhpSymbolModuleCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    )\n{\n    PPH_SYMBOL_MODULE symbolModule1 = CONTAINING_RECORD(Links1, PH_SYMBOL_MODULE, Links);\n    PPH_SYMBOL_MODULE symbolModule2 = CONTAINING_RECORD(Links2, PH_SYMBOL_MODULE, Links);\n\n    return uintptrcmp((ULONG_PTR)symbolModule1->BaseAddress, (ULONG_PTR)symbolModule2->BaseAddress);\n}\n\n_Success_(return)\nBOOLEAN PhGetLineFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address,\n    _Out_ PPH_STRING *FileName,\n    _Out_opt_ PULONG Displacement,\n    _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information\n    )\n{\n    IMAGEHLP_LINEW64 line;\n    BOOL result;\n    ULONG displacement;\n    PPH_STRING fileName;\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return FALSE;\n\n    if (!SymGetLineFromAddrW64_I)\n        return FALSE;\n\n    line.SizeOfStruct = sizeof(IMAGEHLP_LINEW64);\n\n    PH_LOCK_SYMBOLS();\n\n    result = SymGetLineFromAddrW64_I(\n        SymbolProvider->ProcessHandle,\n        (ULONG64)Address,\n        &displacement,\n        &line\n        );\n\n    PH_UNLOCK_SYMBOLS();\n\n    if (result)\n        fileName = PhCreateString(line.FileName);\n    else\n        return FALSE;\n\n    *FileName = fileName;\n\n    if (Displacement)\n        *Displacement = displacement;\n\n    if (Information)\n    {\n        Information->LineNumber = line.LineNumber;\n        Information->Address = line.Address;\n    }\n\n    return TRUE;\n}\n\n_Success_(return != 0)\nPVOID PhGetModuleFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address,\n    _Out_opt_ PPH_STRING *FileName\n    )\n{\n    PH_SYMBOL_MODULE lookupModule;\n    PPH_AVL_LINKS links;\n    PPH_SYMBOL_MODULE module;\n    PPH_STRING foundFileName;\n    PVOID foundBaseAddress;\n\n    foundFileName = NULL;\n    foundBaseAddress = NULL;\n\n    PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock);\n\n    // Do an approximate search on the modules set to locate the module with the largest\n    // base address that is still smaller than the given address.\n    lookupModule.BaseAddress = Address;\n    links = PhUpperDualBoundElementAvlTree(&SymbolProvider->ModulesSet, &lookupModule.Links);\n\n    if (links)\n    {\n        module = CONTAINING_RECORD(links, PH_SYMBOL_MODULE, Links);\n\n        if ((ULONG_PTR)Address < (ULONG_PTR)PTR_ADD_OFFSET(module->BaseAddress, module->Size))\n        {\n            PhSetReference(&foundFileName, module->FileName);\n            foundBaseAddress = module->BaseAddress;\n        }\n    }\n\n    PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock);\n\n    if (foundFileName)\n    {\n        if (FileName)\n        {\n            *FileName = foundFileName;\n        }\n        else\n        {\n            PhDereferenceObject(foundFileName);\n        }\n    }\n\n    return foundBaseAddress;\n}\n\nPPH_SYMBOL_MODULE PhGetSymbolModuleFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address\n    )\n{\n    PPH_SYMBOL_MODULE module = NULL;\n    PH_SYMBOL_MODULE lookupModule;\n    PPH_AVL_LINKS links;\n\n    PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock);\n\n    // Do an approximate search on the modules set to locate the module with the largest\n    // base address that is still smaller than the given address.\n    lookupModule.BaseAddress = Address;\n    links = PhUpperDualBoundElementAvlTree(&SymbolProvider->ModulesSet, &lookupModule.Links);\n\n    if (links)\n    {\n        PPH_SYMBOL_MODULE entry = CONTAINING_RECORD(links, PH_SYMBOL_MODULE, Links);\n\n        if ((ULONG_PTR)Address < (ULONG_PTR)PTR_ADD_OFFSET(entry->BaseAddress, entry->Size))\n        {\n            module = entry;\n        }\n    }\n\n    PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock);\n\n    return module;\n}\n\nUSHORT PhpGetMachineForAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PVOID Address\n    )\n{\n    PH_SYMBOL_MODULE lookupModule;\n    PPH_AVL_LINKS links;\n    PPH_SYMBOL_MODULE module;\n    USHORT machine;\n#ifdef _ARM64_\n    BOOLEAN isEcCode;\n#endif\n\n    machine = IMAGE_FILE_MACHINE_UNKNOWN;\n\n    PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock);\n\n    // Do an approximate search on the modules set to locate the module with the largest\n    // base address that is still smaller than the given address.\n    lookupModule.BaseAddress = Address;\n    links = PhUpperDualBoundElementAvlTree(&SymbolProvider->ModulesSet, &lookupModule.Links);\n\n    if (links)\n    {\n        module = CONTAINING_RECORD(links, PH_SYMBOL_MODULE, Links);\n\n        if (module->Machine && ((ULONG_PTR)Address < (ULONG_PTR)PTR_ADD_OFFSET(module->BaseAddress, module->Size)))\n            machine = module->Machine;\n    }\n\n    PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock);\n\n    if (!ProcessHandle)\n        return machine;\n\n#ifdef _ARM64_\n    if (machine == IMAGE_FILE_MACHINE_UNKNOWN)\n    {\n        if (NT_SUCCESS(PhIsEcCode(ProcessHandle, Address, &isEcCode)))\n        {\n            if (isEcCode)\n                machine = IMAGE_FILE_MACHINE_ARM64EC;\n            else\n                machine = IMAGE_FILE_MACHINE_AMD64;\n        }\n    }\n    else if (machine == IMAGE_FILE_MACHINE_ARM64 || machine == IMAGE_FILE_MACHINE_AMD64)\n    {\n        if (NT_SUCCESS(PhIsEcCode(ProcessHandle, Address, &isEcCode)) && isEcCode)\n            machine = IMAGE_FILE_MACHINE_ARM64EC;\n    }\n#endif\n\n    return machine;\n}\n\nVOID PhpSymbolInfoAnsiToUnicode(\n    _Out_ PSYMBOL_INFOW SymbolInfoW,\n    _In_ PSYMBOL_INFO SymbolInfoA\n    )\n{\n    SymbolInfoW->TypeIndex = SymbolInfoA->TypeIndex;\n    SymbolInfoW->Index = SymbolInfoA->Index;\n    SymbolInfoW->Size = SymbolInfoA->Size;\n    SymbolInfoW->ModBase = SymbolInfoA->ModBase;\n    SymbolInfoW->Flags = SymbolInfoA->Flags;\n    SymbolInfoW->Value = SymbolInfoA->Value;\n    SymbolInfoW->Address = SymbolInfoA->Address;\n    SymbolInfoW->Register = SymbolInfoA->Register;\n    SymbolInfoW->Scope = SymbolInfoA->Scope;\n    SymbolInfoW->Tag = SymbolInfoA->Tag;\n    SymbolInfoW->NameLen = 0;\n\n    if (SymbolInfoA->NameLen != 0 && SymbolInfoW->MaxNameLen != 0)\n    {\n        ULONG copyCount;\n\n        copyCount = min(SymbolInfoA->NameLen, SymbolInfoW->MaxNameLen - 1);\n\n        if (NT_SUCCESS(PhCopyStringZFromMultiByte(\n            SymbolInfoA->Name,\n            copyCount,\n            SymbolInfoW->Name,\n            SymbolInfoW->MaxNameLen,\n            NULL\n            )))\n        {\n            SymbolInfoW->NameLen = copyCount;\n        }\n    }\n}\n\n_Success_(return != NULL)\nPPH_STRING PhGetSymbolFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address,\n    _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel,\n    _Out_opt_ PPH_STRING *FileName,\n    _Out_opt_ PPH_STRING *SymbolName,\n    _Out_opt_ PULONG64 Displacement\n    )\n{\n    PSYMBOL_INFOW symbolInfo;\n    ULONG nameLength;\n    PPH_STRING symbol = NULL;\n    PH_SYMBOL_RESOLVE_LEVEL resolveLevel;\n    ULONG64 displacement;\n    PPH_STRING modFileName = NULL;\n    PPH_STRING modBaseName = NULL;\n    PVOID modBase = NULL;\n    PPH_STRING symbolName = NULL;\n\n    if (Address == NULL)\n    {\n        if (ResolveLevel) *ResolveLevel = PhsrlInvalid;\n        if (FileName) *FileName = NULL;\n        if (SymbolName) *SymbolName = NULL;\n        if (Displacement) *Displacement = 0;\n\n        return NULL;\n    }\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return NULL;\n\n    if (!SymFromAddrW_I)\n        return NULL;\n\n    symbolInfo = PhAllocateZero(FIELD_OFFSET(SYMBOL_INFOW, Name[PH_MAX_SYMBOL_NAME_LEN]));\n    symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n    symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN;\n\n    // Get the symbol name.\n\n    PH_LOCK_SYMBOLS();\n\n    // Note that we don't care whether this call succeeds or not, based on the assumption that it\n    // will not write to the symbolInfo structure if it fails. We've already zeroed the structure,\n    // so we can deal with it.\n\n    SymFromAddrW_I(\n        SymbolProvider->ProcessHandle,\n        (ULONG64)Address,\n        &displacement,\n        symbolInfo\n        );\n    nameLength = symbolInfo->NameLen;\n\n    if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN)\n    {\n        PhFree(symbolInfo);\n        symbolInfo = PhAllocateZero(FIELD_OFFSET(SYMBOL_INFOW, Name[nameLength + sizeof(UNICODE_NULL)]));\n        symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n        symbolInfo->MaxNameLen = nameLength + sizeof(UNICODE_NULL);\n\n        SymFromAddrW_I(\n            SymbolProvider->ProcessHandle,\n            (ULONG64)Address,\n            &displacement,\n            symbolInfo\n            );\n    }\n\n    PH_UNLOCK_SYMBOLS();\n\n    // Find the module name.\n\n    if (symbolInfo->ModBase == 0)\n    {\n        modBase = PhGetModuleFromAddress(\n            SymbolProvider,\n            Address,\n            &modFileName\n            );\n    }\n    else\n    {\n        modBase = PhGetModuleFromAddress(\n            SymbolProvider,\n            (PVOID)symbolInfo->ModBase,\n            &modFileName\n            );\n    }\n\n    // If we don't have a module name, return an address.\n    if (!modFileName)\n    {\n        resolveLevel = PhsrlAddress;\n        symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR));\n        PhPrintPointer(symbol->Buffer, (PVOID)Address);\n        PhTrimToNullTerminatorString(symbol);\n\n        goto CleanupExit;\n    }\n\n    modBaseName = PhGetBaseName(modFileName);\n\n    // If we have a module name but not a symbol name, return the module plus an offset:\n    // module+offset.\n\n    if (symbolInfo->NameLen == 0)\n    {\n        PH_FORMAT format[3];\n\n        resolveLevel = PhsrlModule;\n\n        PhInitFormatSR(&format[0], modBaseName->sr);\n        PhInitFormatS(&format[1], L\"+0x\");\n        PhInitFormatIX(&format[2], (ULONG_PTR)Address - (ULONG_PTR)modBase);\n        symbol = PhFormat(format, 3, modBaseName->Length + 6 + 32);\n\n        goto CleanupExit;\n    }\n\n    // If we have everything, return the full symbol name: module!symbol+offset.\n\n    symbolName = PhCreateStringEx(symbolInfo->Name, symbolInfo->NameLen * sizeof(WCHAR));\n    PhTrimToNullTerminatorString(symbolName); // SymFromAddr doesn't give us the correct name length for vm protected binaries (dmex)\n    resolveLevel = PhsrlFunction;\n\n    if (displacement == 0)\n    {\n        PH_FORMAT format[3];\n\n        PhInitFormatSR(&format[0], modBaseName->sr);\n        PhInitFormatC(&format[1], L'!');\n        PhInitFormatSR(&format[2], symbolName->sr);\n\n        symbol = PhFormat(format, 3, modBaseName->Length + 2 + symbolName->Length);\n    }\n    else\n    {\n        PH_FORMAT format[5];\n\n        PhInitFormatSR(&format[0], modBaseName->sr);\n        PhInitFormatC(&format[1], L'!');\n        PhInitFormatSR(&format[2], symbolName->sr);\n        PhInitFormatS(&format[3], L\"+0x\");\n        PhInitFormatIX(&format[4], (ULONG_PTR)displacement);\n\n        symbol = PhFormat(format, 5, modBaseName->Length + 2 + symbolName->Length + 6 + 32);\n    }\n\nCleanupExit:\n\n    if (ResolveLevel)\n        *ResolveLevel = resolveLevel;\n    if (FileName)\n        PhSetReference(FileName, modFileName);\n    if (SymbolName)\n        PhSetReference(SymbolName, symbolName);\n    if (Displacement)\n        *Displacement = displacement;\n\n    PhClearReference(&modFileName);\n    PhClearReference(&modBaseName);\n    PhClearReference(&symbolName);\n    PhFree(symbolInfo);\n\n    return symbol;\n}\n\n_Success_(return)\nBOOLEAN PhGetSymbolFromName(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PCWSTR Name,\n    _Out_ PPH_SYMBOL_INFORMATION Information\n    )\n{\n    PSYMBOL_INFOW symbolInfo;\n    UCHAR symbolInfoBuffer[FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * sizeof(WCHAR)];\n    BOOL result;\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return FALSE;\n\n    if (!SymFromNameW_I)\n        return FALSE;\n\n    symbolInfo = (PSYMBOL_INFOW)symbolInfoBuffer;\n    memset(symbolInfo, 0, sizeof(SYMBOL_INFOW));\n    symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n    symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN;\n\n    // Get the symbol information.\n\n    PH_LOCK_SYMBOLS();\n\n    result = SymFromNameW_I(\n        SymbolProvider->ProcessHandle,\n        Name,\n        symbolInfo\n        );\n\n    PH_UNLOCK_SYMBOLS();\n\n    if (!result)\n        return FALSE;\n\n    Information->Address = (PVOID)symbolInfo->Address;\n    Information->ModuleBase = (PVOID)symbolInfo->ModBase;\n    Information->Index = symbolInfo->Index;\n    Information->Size = symbolInfo->Size;\n\n    return TRUE;\n}\n\nPPH_SYMBOL_MODULE PhpCreateSymbolModule(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_STRING FileName,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG Size\n    )\n{\n    PPH_SYMBOL_MODULE symbolModule;\n\n    symbolModule = PhAllocateZero(sizeof(PH_SYMBOL_MODULE));\n    symbolModule->BaseAddress = BaseAddress;\n    symbolModule->Size = Size;\n    PhSetReference(&symbolModule->FileName, FileName);\n\n#if defined(_ARM64_)\n    PH_MAPPED_IMAGE mappedImage;\n\n    if (NT_SUCCESS(PhLoadMappedImageHeaderPageSize(&FileName->sr, NULL, &mappedImage)))\n    {\n        if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n            symbolModule->Machine = mappedImage.NtHeaders->FileHeader.Machine;\n        else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n            symbolModule->Machine = mappedImage.NtHeaders32->FileHeader.Machine;\n\n        PhUnloadMappedImage(&mappedImage);\n    }\n#endif\n\n    return symbolModule;\n}\n\nBOOLEAN PhLoadModuleSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PPH_STRING FileName,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG Size\n    )\n{\n    ULONG64 baseAddress;\n    PPH_SYMBOL_MODULE symbolModule = NULL;\n    PPH_AVL_LINKS existingLinks;\n    PH_SYMBOL_MODULE lookupSymbolModule;\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return FALSE;\n\n    if (!SymLoadModuleExW_I)\n        return FALSE;\n\n    // Check for duplicates. It is better to do this before calling SymLoadModuleExW, because it\n    // seems to force symbol loading when it is called twice on the same module even if deferred\n    // loading is enabled.\n    PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n    lookupSymbolModule.BaseAddress = BaseAddress;\n    existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links);\n    PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n\n    if (existingLinks)\n        return TRUE;\n\n    PH_LOCK_SYMBOLS();\n\n    baseAddress = SymLoadModuleExW_I(\n        SymbolProvider->ProcessHandle,\n        NULL,\n        NULL,\n        NULL,\n        (ULONG64)BaseAddress,\n        Size,\n        NULL,\n        0\n        );\n\n    PH_UNLOCK_SYMBOLS();\n\n    // Add the module to the list, even if we couldn't load symbols for the module.\n\n    PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n\n    // Check for duplicates again.\n    lookupSymbolModule.BaseAddress = BaseAddress;\n    existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links);\n\n    if (!existingLinks)\n    {\n        symbolModule = PhpCreateSymbolModule(SymbolProvider->ProcessHandle, FileName, BaseAddress, Size);\n        existingLinks = PhAddElementAvlTree(&SymbolProvider->ModulesSet, &symbolModule->Links);\n        assert(!existingLinks);\n        InsertTailList(&SymbolProvider->ModulesListHead, &symbolModule->ListEntry);\n    }\n\n    PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n\n    if (baseAddress)\n        return TRUE;\n    else\n        return FALSE;\n}\n\nBOOLEAN PhLoadFileNameSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PPH_STRING FileName,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG Size\n    )\n{\n    ULONG64 baseAddress;\n    PPH_SYMBOL_MODULE symbolModule = NULL;\n    PPH_AVL_LINKS existingLinks;\n    PH_SYMBOL_MODULE lookupSymbolModule;\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return FALSE;\n\n    if (!SymLoadModuleExW_I)\n        return FALSE;\n\n    PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n    lookupSymbolModule.BaseAddress = BaseAddress;\n    existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links);\n    PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n\n    if (existingLinks)\n        return TRUE;\n\n    PH_LOCK_SYMBOLS();\n\n    baseAddress = SymLoadModuleExW_I(\n        SymbolProvider->ProcessHandle,\n        NULL,\n        FileName->Buffer,\n        NULL,\n        (ULONG64)BaseAddress,\n        Size,\n        NULL,\n        0\n        );\n\n    PH_UNLOCK_SYMBOLS();\n\n    PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n    lookupSymbolModule.BaseAddress = BaseAddress;\n    existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links);\n\n    if (!existingLinks)\n    {\n        symbolModule = PhpCreateSymbolModule(SymbolProvider->ProcessHandle, FileName, BaseAddress, Size);\n        PhSetReference(&symbolModule->FileName, FileName);\n\n        existingLinks = PhAddElementAvlTree(&SymbolProvider->ModulesSet, &symbolModule->Links);\n        assert(!existingLinks);\n        InsertTailList(&SymbolProvider->ModulesListHead, &symbolModule->ListEntry);\n    }\n\n    PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n\n    if (baseAddress)\n        return TRUE;\n    else\n        return FALSE;\n}\n\ntypedef struct _PH_LOAD_SYMBOLS_CONTEXT\n{\n    PPH_SYMBOL_PROVIDER SymbolProvider;\n    HANDLE ProcessId;\n} PH_LOAD_SYMBOLS_CONTEXT, *PPH_LOAD_SYMBOLS_CONTEXT;\n\n_Function_class_(PH_ENUM_GENERIC_MODULES_CALLBACK)\nstatic BOOLEAN NTAPI PhpSymbolProviderEnumModulesCallback(\n    _In_ PPH_MODULE_INFO Module,\n    _In_ PVOID Context\n    )\n{\n    PPH_LOAD_SYMBOLS_CONTEXT context = Context;\n\n    // If we're loading kernel module symbols for a process other than System, ignore modules which\n    // are in user space. This may happen in Windows 7.\n    if (\n        WindowsVersion < WINDOWS_8 &&\n        context->ProcessId != SYSTEM_PROCESS_ID\n        )\n    {\n        if ((ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress)\n        {\n            return TRUE;\n        }\n    }\n\n    PhLoadModuleSymbolProvider(\n        context->SymbolProvider,\n        Module->FileName,\n        Module->BaseAddress,\n        Module->Size\n        );\n\n    return TRUE;\n}\n\nVOID PhLoadSymbolProviderModules(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ HANDLE ProcessId\n    )\n{\n    PH_LOAD_SYMBOLS_CONTEXT context;\n\n    memset(&context, 0, sizeof(PH_LOAD_SYMBOLS_CONTEXT));\n    context.SymbolProvider = SymbolProvider;\n\n    // Load symbols for process modules.\n    if (ProcessId != SYSTEM_IDLE_PROCESS_ID && SymbolProvider->IsRealHandle)\n    {\n        PhEnumGenericModules(\n            ProcessId,\n            SymbolProvider->ProcessHandle,\n            PH_ENUM_GENERIC_MAPPED_IMAGES,\n            PhpSymbolProviderEnumModulesCallback,\n            &context\n            );\n    }\n\n    // Load symbols for kernel modules.\n    {\n        PhEnumGenericModules(\n            SYSTEM_PROCESS_ID,\n            NULL,\n            0,\n            PhpSymbolProviderEnumModulesCallback,\n            &context\n            );\n    }\n\n    // Load symbols for ntdll.dll and kernel32.dll.\n    {\n        static CONST PH_STRINGREF fileNames[] =\n        {\n            PH_STRINGREF_INIT(L\"ntdll.dll\"),\n            PH_STRINGREF_INIT(L\"kernel32.dll\"),\n        };\n\n        for (ULONG i = 0; i < RTL_NUMBER_OF(fileNames); i++)\n        {\n            PVOID baseAddress;\n            ULONG sizeOfImage;\n            PPH_STRING fileName;\n\n            if (PhGetLoaderEntryData(&fileNames[i], &baseAddress, &sizeOfImage, &fileName))\n            {\n                PhLoadModuleSymbolProvider(SymbolProvider, fileName, baseAddress, sizeOfImage);\n                PhDereferenceObject(fileName);\n            }\n        }\n    }\n}\n\nNTSTATUS PhLoadModulesForVirtualSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_opt_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    PH_LOAD_SYMBOLS_CONTEXT context;\n    HANDLE processHandle = NULL;\n    BOOLEAN closeHandle = FALSE;\n\n    memset(&context, 0, sizeof(PH_LOAD_SYMBOLS_CONTEXT));\n    context.SymbolProvider = SymbolProvider;\n\n    if (SymbolProvider->IsRealHandle)\n    {\n        processHandle = SymbolProvider->ProcessHandle;\n        status = STATUS_SUCCESS;\n    }\n    else if (ProcessHandle)\n    {\n        processHandle = ProcessHandle;\n        status = STATUS_SUCCESS;\n    }\n    else if (ProcessId)\n    {\n        status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            ProcessId\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            closeHandle = TRUE;\n        }\n    }\n    else\n    {\n        status = STATUS_INVALID_PARAMETER_1;\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Load symbols for process modules.\n    if (ProcessId != SYSTEM_IDLE_PROCESS_ID && processHandle)\n    {\n        PhEnumGenericModules(\n            ProcessId,\n            processHandle,\n            PH_ENUM_GENERIC_MAPPED_IMAGES,\n            PhpSymbolProviderEnumModulesCallback,\n            &context\n            );\n    }\n\n    // Load symbols for kernel modules.\n    {\n        PhEnumGenericModules(\n            SYSTEM_PROCESS_ID,\n            NULL,\n            0,\n            PhpSymbolProviderEnumModulesCallback,\n            &context\n            );\n    }\n\n    // Load symbols for ntdll.dll and kernel32.dll (dmex)\n    {\n        static CONST PH_STRINGREF fileNames[] =\n        {\n            PH_STRINGREF_INIT(L\"ntdll.dll\"),\n            PH_STRINGREF_INIT(L\"kernel32.dll\"),\n        };\n\n        for (ULONG i = 0; i < RTL_NUMBER_OF(fileNames); i++)\n        {\n            PVOID baseAddress;\n            ULONG sizeOfImage;\n            PPH_STRING fileName;\n\n            if (PhGetLoaderEntryData(&fileNames[i], &baseAddress, &sizeOfImage, &fileName))\n            {\n                PhLoadModuleSymbolProvider(SymbolProvider, fileName, baseAddress, sizeOfImage);\n                PhDereferenceObject(fileName);\n            }\n        }\n    }\n\n    if (closeHandle && processHandle)\n    {\n        NtClose(processHandle);\n    }\n\n    return status;\n}\n\nstatic const PH_FLAG_MAPPING PhSymbolProviderOptions[] =\n{\n    { PH_SYMOPT_UNDNAME, SYMOPT_UNDNAME },\n};\n\nVOID PhSetOptionsSymbolProvider(\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    )\n{\n    ULONG options;\n    ULONG mask = 0;\n    ULONG value = 0;\n    ULONG internalMask;\n\n    internalMask = Mask & PH_SYMOPT_VERIFY_MICROSOFT_CHAIN;\n\n    if (internalMask)\n    {\n        PhSymbolProviderInternalOptions =\n            (PhSymbolProviderInternalOptions & ~internalMask) | (Value & internalMask);\n    }\n\n    PhpRegisterSymbolProvider(NULL);\n\n    if (!SymGetOptions_I || !SymSetOptions_I)\n        return;\n\n    PhMapFlags1(\n        &mask,\n        Mask,\n        PhSymbolProviderOptions,\n        ARRAYSIZE(PhSymbolProviderOptions)\n        );\n\n    PhMapFlags1(\n        &value,\n        Value,\n        PhSymbolProviderOptions,\n        ARRAYSIZE(PhSymbolProviderOptions)\n        );\n\n    PH_LOCK_SYMBOLS();\n\n    options = SymGetOptions_I();\n    options &= ~mask;\n    options |= value;\n    SymSetOptions_I(options);\n\n    PH_UNLOCK_SYMBOLS();\n}\n\nVOID PhSetSearchPathSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PCWSTR Path\n    )\n{\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!SymSetSearchPathW_I)\n        return;\n\n    PH_LOCK_SYMBOLS();\n\n    SymSetSearchPathW_I(SymbolProvider->ProcessHandle, Path);\n\n    PH_UNLOCK_SYMBOLS();\n}\n\n#ifdef _WIN64\n\nNTSTATUS PhpLookupDynamicFunctionTable(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG64 Address,\n    _Out_opt_ PDYNAMIC_FUNCTION_TABLE *FunctionTableAddress,\n    _Out_opt_ PDYNAMIC_FUNCTION_TABLE FunctionTable,\n    _Out_writes_bytes_opt_(OutOfProcessCallbackDllBufferSize) PWCHAR OutOfProcessCallbackDllBuffer,\n    _In_ ULONG OutOfProcessCallbackDllBufferSize,\n    _Out_opt_ PUNICODE_STRING OutOfProcessCallbackDllString\n    )\n{\n    NTSTATUS status;\n    PLIST_ENTRY (NTAPI *rtlGetFunctionTableListHead)(VOID);\n    PLIST_ENTRY tableListHead;\n    LIST_ENTRY tableListHeadEntry;\n    PLIST_ENTRY tableListEntry;\n    PDYNAMIC_FUNCTION_TABLE functionTableAddress;\n    DYNAMIC_FUNCTION_TABLE functionTable;\n    ULONG count;\n    SIZE_T numberOfBytesRead;\n    ULONG i;\n    BOOLEAN foundNull;\n\n    rtlGetFunctionTableListHead = PhGetDllProcedureAddressZ(L\"ntdll.dll\", \"RtlGetFunctionTableListHead\", 0);\n\n    if (!rtlGetFunctionTableListHead)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    tableListHead = rtlGetFunctionTableListHead();\n\n    // Find the function table entry for this address.\n\n    if (!NT_SUCCESS(status = PhReadVirtualMemory(\n        ProcessHandle,\n        tableListHead,\n        &tableListHeadEntry,\n        sizeof(LIST_ENTRY),\n        NULL\n        )))\n        return status;\n\n    tableListEntry = tableListHeadEntry.Flink;\n    count = 0; // make sure we can't be forced into an infinite loop by crafted data\n\n    while (tableListEntry != tableListHead && count < PH_ENUM_PROCESS_MODULES_LIMIT)\n    {\n        functionTableAddress = CONTAINING_RECORD(tableListEntry, DYNAMIC_FUNCTION_TABLE, ListEntry);\n\n        if (!NT_SUCCESS(status = PhReadVirtualMemory(\n            ProcessHandle,\n            functionTableAddress,\n            &functionTable,\n            sizeof(DYNAMIC_FUNCTION_TABLE),\n            NULL\n            )))\n            return status;\n\n        if (Address >= functionTable.MinimumAddress && Address < functionTable.MaximumAddress)\n        {\n            if (OutOfProcessCallbackDllBuffer)\n            {\n                if (functionTable.OutOfProcessCallbackDll)\n                {\n                    // Read the out-of-process callback DLL path. We don't have a length, so we'll\n                    // just have to read as much as possible.\n\n                    memset(OutOfProcessCallbackDllBuffer, 0xff, OutOfProcessCallbackDllBufferSize);\n                    status = PhReadVirtualMemory(\n                        ProcessHandle,\n                        functionTable.OutOfProcessCallbackDll,\n                        OutOfProcessCallbackDllBuffer,\n                        OutOfProcessCallbackDllBufferSize,\n                        &numberOfBytesRead\n                        );\n\n                    if (status != STATUS_PARTIAL_COPY && !NT_SUCCESS(status))\n                        return status;\n\n                    foundNull = FALSE;\n\n                    for (i = 0; i < OutOfProcessCallbackDllBufferSize / sizeof(WCHAR); i++)\n                    {\n                        if (OutOfProcessCallbackDllBuffer[i] == 0)\n                        {\n                            foundNull = TRUE;\n\n                            if (OutOfProcessCallbackDllString)\n                            {\n                                OutOfProcessCallbackDllString->Buffer = OutOfProcessCallbackDllBuffer;\n                                OutOfProcessCallbackDllString->Length = (USHORT)(i * sizeof(WCHAR));\n                                OutOfProcessCallbackDllString->MaximumLength = OutOfProcessCallbackDllString->Length;\n                            }\n\n                            break;\n                        }\n                    }\n\n                    // If there was no null terminator, then we didn't read the whole string in.\n                    // Fail the operation.\n                    if (!foundNull)\n                        return STATUS_BUFFER_OVERFLOW;\n                }\n                else\n                {\n                    OutOfProcessCallbackDllBuffer[0] = UNICODE_NULL;\n\n                    if (OutOfProcessCallbackDllString)\n                    {\n                        OutOfProcessCallbackDllString->Buffer = NULL;\n                        OutOfProcessCallbackDllString->Length = 0;\n                        OutOfProcessCallbackDllString->MaximumLength = 0;\n                    }\n                }\n            }\n\n            if (FunctionTableAddress)\n                *FunctionTableAddress = functionTableAddress;\n\n            if (FunctionTable)\n                *FunctionTable = functionTable;\n\n            return STATUS_SUCCESS;\n        }\n\n        tableListEntry = functionTable.ListEntry.Flink;\n        count++;\n    }\n\n    return STATUS_NOT_FOUND;\n}\n\nPRUNTIME_FUNCTION PhpLookupFunctionEntry(\n    _In_ PRUNTIME_FUNCTION Functions,\n    _In_ ULONG NumberOfFunctions,\n    _In_ BOOLEAN Sorted,\n    _In_ ULONG64 RelativeControlPc\n    )\n{\n    LONG low;\n    LONG high;\n    ULONG i;\n\n    if (Sorted)\n    {\n        if (NumberOfFunctions == 0)\n            return NULL;\n\n        low = 0;\n        high = NumberOfFunctions - 1;\n\n        do\n        {\n            i = (low + high) / 2;\n\n            if (RelativeControlPc < Functions[i].BeginAddress)\n                high = i - 1;\n#ifdef _ARM64_\n            else if (RelativeControlPc >= (Functions[i].BeginAddress + Functions[i].FunctionLength))\n#else\n            else if (RelativeControlPc >= Functions[i].EndAddress)\n#endif\n                low = i + 1;\n            else\n                return &Functions[i];\n        } while (low <= high);\n    }\n    else\n    {\n        for (i = 0; i < NumberOfFunctions; i++)\n        {\n#ifdef _ARM64_\n            if (RelativeControlPc >= Functions[i].BeginAddress &&\n                RelativeControlPc < (Functions[i].BeginAddress + Functions[i].FunctionLength))\n#else\n            if (RelativeControlPc >= Functions[i].BeginAddress &&\n                RelativeControlPc < Functions[i].EndAddress)\n#endif\n                return &Functions[i];\n        }\n    }\n\n    return NULL;\n}\n\nNTSTATUS PhpAccessCallbackFunctionTable(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID FunctionTableAddress,\n    _In_ PUNICODE_STRING OutOfProcessCallbackDllString,\n    _Out_ PRUNTIME_FUNCTION *Functions,\n    _Out_ PULONG NumberOfFunctions\n    )\n{\n    static CONST PH_STRINGREF knownFunctionTableDllsKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\KnownFunctionTableDlls\");\n    NTSTATUS status;\n    HANDLE keyHandle;\n    ULONG returnLength;\n    PVOID dllHandle;\n    ANSI_STRING outOfProcessFunctionTableCallbackName;\n    POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK outOfProcessFunctionTableCallback;\n\n    if (!OutOfProcessCallbackDllString->Buffer)\n        return STATUS_INVALID_PARAMETER;\n\n    // Don't load DLLs from arbitrary locations. Check if this is a known function table DLL.\n\n    if (!NT_SUCCESS(status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &knownFunctionTableDllsKeyName,\n        0\n        )))\n        return status;\n\n    status = NtQueryValueKey(keyHandle, OutOfProcessCallbackDllString, KeyValuePartialInformation, NULL, 0, &returnLength);\n    NtClose(keyHandle);\n\n    if (status == STATUS_OBJECT_NAME_NOT_FOUND)\n    {\n        PH_STRINGREF fileName;\n\n        PhUnicodeStringToStringRef(OutOfProcessCallbackDllString, &fileName);\n\n        // Verify the signature is valid and the certificate chained to Microsoft (dmex)\n\n        if (FlagOn(PhSymbolProviderInternalOptions, PH_SYMOPT_VERIFY_MICROSOFT_CHAIN) &&\n            !PhVerifyFileIsChainedToMicrosoft(&fileName, FALSE))\n        {\n            return STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT;\n        }\n    }\n\n    status = LdrLoadDll(NULL, NULL, OutOfProcessCallbackDllString, &dllHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    RtlInitAnsiString(&outOfProcessFunctionTableCallbackName, OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME);\n    status = LdrGetProcedureAddress(dllHandle, &outOfProcessFunctionTableCallbackName, 0, (PVOID *)&outOfProcessFunctionTableCallback);\n\n    if (NT_SUCCESS(status))\n    {\n        status = outOfProcessFunctionTableCallback(\n            ProcessHandle,\n            FunctionTableAddress,\n            NumberOfFunctions,\n            Functions\n            );\n    }\n\n    LdrUnloadDll(dllHandle);\n\n    return status;\n}\n\nNTSTATUS PhpAccessNormalFunctionTable(\n    _In_ HANDLE ProcessHandle,\n    _In_ PDYNAMIC_FUNCTION_TABLE FunctionTable,\n    _Out_ PRUNTIME_FUNCTION *Functions,\n    _Out_ PULONG NumberOfFunctions\n    )\n{\n    NTSTATUS status;\n    SIZE_T bufferSize;\n    PRUNTIME_FUNCTION functions;\n\n    // Put a reasonable limit on the number of entries we read.\n    if (FunctionTable->EntryCount > 0x100000)\n        return STATUS_BUFFER_OVERFLOW;\n\n    bufferSize = FunctionTable->EntryCount * sizeof(RUNTIME_FUNCTION);\n    functions = PhAllocatePage(bufferSize, NULL);\n\n    if (!functions)\n        return STATUS_NO_MEMORY;\n\n    status = PhReadVirtualMemory(ProcessHandle, FunctionTable->FunctionTable, functions, bufferSize, NULL);\n\n    if (NT_SUCCESS(status))\n    {\n        *Functions = functions;\n        *NumberOfFunctions = FunctionTable->EntryCount;\n    }\n    else\n    {\n        PhFreePage(functions);\n    }\n\n    return status;\n}\n\nNTSTATUS PhAccessOutOfProcessFunctionEntry(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG64 ControlPc,\n    _Out_ PRUNTIME_FUNCTION Function\n    )\n{\n    NTSTATUS status;\n    PDYNAMIC_FUNCTION_TABLE functionTableAddress;\n    DYNAMIC_FUNCTION_TABLE functionTable;\n    WCHAR outOfProcessCallbackDll[512];\n    UNICODE_STRING outOfProcessCallbackDllString;\n    PRUNTIME_FUNCTION functions;\n    ULONG numberOfFunctions;\n    PRUNTIME_FUNCTION function;\n\n    if (!NT_SUCCESS(status = PhpLookupDynamicFunctionTable(\n        ProcessHandle,\n        ControlPc,\n        &functionTableAddress,\n        &functionTable,\n        outOfProcessCallbackDll,\n        sizeof(outOfProcessCallbackDll),\n        &outOfProcessCallbackDllString\n        )))\n    {\n        return status;\n    }\n\n    if (functionTable.Type == RF_CALLBACK)\n    {\n        if (!NT_SUCCESS(status = PhpAccessCallbackFunctionTable(\n            ProcessHandle,\n            functionTableAddress,\n            &outOfProcessCallbackDllString,\n            &functions,\n            &numberOfFunctions\n            )))\n        {\n            return status;\n        }\n\n        function = PhpLookupFunctionEntry(functions, numberOfFunctions, FALSE, ControlPc - functionTable.BaseAddress);\n\n        if (function)\n            *Function = *function;\n        else\n            status = STATUS_NOT_FOUND;\n\n        RtlFreeHeap(RtlProcessHeap(), 0, functions);\n    }\n    else\n    {\n        if (!NT_SUCCESS(status = PhpAccessNormalFunctionTable(\n            ProcessHandle,\n            &functionTable,\n            &functions,\n            &numberOfFunctions\n            )))\n        {\n            return status;\n        }\n\n        function = PhpLookupFunctionEntry(functions, numberOfFunctions, functionTable.Type == RF_SORTED, ControlPc - functionTable.BaseAddress);\n\n        if (function)\n            *Function = *function;\n        else\n            status = STATUS_NOT_FOUND;\n\n        PhFreePage(functions);\n    }\n\n    return status;\n}\n\n#endif\n\nULONG64 __stdcall PhGetModuleBase64(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 dwAddr\n    )\n{\n    ULONG64 base;\n#ifdef _WIN64\n    DYNAMIC_FUNCTION_TABLE functionTable;\n#endif\n\n#ifdef _WIN64\n    if (NT_SUCCESS(PhpLookupDynamicFunctionTable(\n        hProcess,\n        dwAddr,\n        NULL,\n        &functionTable,\n        NULL,\n        0,\n        NULL\n        )))\n    {\n        base = functionTable.BaseAddress;\n    }\n    else\n    {\n        base = 0;\n    }\n#else\n    base = 0;\n#endif\n\n    if (base == 0 && SymGetModuleBase64_I)\n        base = SymGetModuleBase64_I(hProcess, dwAddr);\n\n    return base;\n}\n\nPVOID __stdcall PhFunctionTableAccess64(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 AddrBase\n    )\n{\n#ifdef _WIN64\n    static RUNTIME_FUNCTION lastRuntimeFunction;\n#endif\n\n    PVOID entry;\n\n#ifdef _WIN64\n    if (NT_SUCCESS(PhAccessOutOfProcessFunctionEntry(hProcess, AddrBase, &lastRuntimeFunction)))\n        entry = &lastRuntimeFunction;\n    else\n        entry = NULL;\n#else\n    entry = NULL;\n#endif\n\n    if (!entry && SymFunctionTableAccess64_I)\n        entry = SymFunctionTableAccess64_I(hProcess, AddrBase);\n\n    return entry;\n}\n\n/**\n * Walks a thread's stack.\n *\n * \\param MachineType The architecture type of the computer for which the stack trace is generated.\n * \\param ProcessHandle A handle to the thread's parent process. The handle must have\n * PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access. If a symbol provider is being used, pass\n * its process handle and specify the symbol provider in \\a SymbolProvider.\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION,\n * THREAD_GET_CONTEXT and THREAD_SUSPEND_RESUME access. The handle can have any access for kernel\n * stack walking.\n * \\param StackFrame A pointer to a STACKFRAME_EX structure. This structure receives information for the next frame, if the function call succeeds.\n * \\param ContextRecord A pointer to a CONTEXT structure.\n * \\param SymbolProvider The associated symbol provider.\n * \\param ReadMemoryRoutine A callback routine that provides memory read services.\n * \\param FunctionTableAccessRoutine A callback routine that provides access to the run-time function table for the process.\n * \\param GetModuleBaseRoutine A callback routine that provides a module base for any given virtual address.\n * \\param TranslateAddress A callback routine that provides address translation for 16-bit addresses.\n *\n * \\return Successful or errant status.\n */\nBOOLEAN PhStackWalk(\n    _In_ ULONG MachineType,\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ThreadHandle,\n    _Inout_ LPSTACKFRAME_EX StackFrame,\n    _Inout_ PVOID ContextRecord,\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,\n    _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,\n    _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,\n    _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress\n    )\n{\n    BOOL result = FALSE;\n\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!FunctionTableAccessRoutine)\n    {\n        if (MachineType == IMAGE_FILE_MACHINE_AMD64)\n            FunctionTableAccessRoutine = PhFunctionTableAccess64;\n        else\n            FunctionTableAccessRoutine = SymFunctionTableAccess64_I;\n    }\n\n    if (!GetModuleBaseRoutine)\n    {\n        if (MachineType == IMAGE_FILE_MACHINE_AMD64)\n            GetModuleBaseRoutine = PhGetModuleBase64;\n        else\n            GetModuleBaseRoutine = SymGetModuleBase64_I;\n    }\n\n    PH_LOCK_SYMBOLS();\n\n    if (PhSymbolProviderInlineContextSupported())\n    {\n        result = StackWalkEx_I(\n            MachineType,\n            ProcessHandle,\n            ThreadHandle,\n            StackFrame,\n            ContextRecord,\n            ReadMemoryRoutine,\n            FunctionTableAccessRoutine,\n            GetModuleBaseRoutine,\n            TranslateAddress,\n            SYM_STKWALK_DEFAULT\n            );\n    }\n    else if (StackWalk64_I)\n    {\n        result = StackWalk64_I(\n            MachineType,\n            ProcessHandle,\n            ThreadHandle,\n            (LPSTACKFRAME64)StackFrame,\n            ContextRecord,\n            ReadMemoryRoutine,\n            FunctionTableAccessRoutine,\n            GetModuleBaseRoutine,\n            TranslateAddress\n            );\n    }\n\n    PH_UNLOCK_SYMBOLS();\n\n    if (result)\n        return TRUE;\n    return FALSE;\n}\n\nHRESULT PhWriteMiniDumpProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE FileHandle,\n    _In_ MINIDUMP_TYPE DumpType,\n    _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,\n    _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,\n    _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam\n    )\n{\n    PhpRegisterSymbolProvider(NULL);\n\n    if (!MiniDumpWriteDump_I)\n    {\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n    }\n\n    if (!MiniDumpWriteDump_I(\n        ProcessHandle,\n        HandleToUlong(ProcessId),\n        FileHandle,\n        DumpType,\n        ExceptionParam,\n        UserStreamParam,\n        CallbackParam\n        ))\n    {\n        return (HRESULT)PhGetLastError();\n    }\n\n    return S_OK;\n}\n\n/**\n * Converts a STACKFRAME64 structure to a PH_THREAD_STACK_FRAME structure.\n *\n * \\param StackFrame A pointer to the STACKFRAME64 structure to convert.\n * \\param Machine Machine to set in the resulting structure.\n * \\param Flags Flags to set in the resulting structure.\n * \\param ThreadStackFrame A pointer to the resulting PH_THREAD_STACK_FRAME structure.\n */\nVOID PhConvertStackFrame(\n    _In_ CONST STACKFRAME_EX *StackFrame,\n    _In_ USHORT Machine,\n    _In_ USHORT Flags,\n    _Out_ PPH_THREAD_STACK_FRAME ThreadStackFrame\n    )\n{\n    memset(ThreadStackFrame, 0, sizeof(ThreadStackFrame->Params));\n    ThreadStackFrame->PcAddress = (PVOID)StackFrame->AddrPC.Offset;\n    ThreadStackFrame->ReturnAddress = (PVOID)StackFrame->AddrReturn.Offset;\n    ThreadStackFrame->FrameAddress = (PVOID)StackFrame->AddrFrame.Offset;\n    ThreadStackFrame->StackAddress = (PVOID)StackFrame->AddrStack.Offset;\n    ThreadStackFrame->BStoreAddress = (PVOID)StackFrame->AddrBStore.Offset;\n\n    for (ULONG i = 0; i < 4; i++)\n        ThreadStackFrame->Params[i] = (PVOID)StackFrame->Params[i];\n\n    ThreadStackFrame->Machine = Machine;\n    ThreadStackFrame->Flags = Flags;\n\n    if (StackFrame->FuncTableEntry)\n        ThreadStackFrame->Flags |= PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT;\n\n    ThreadStackFrame->InlineFrameContext = StackFrame->InlineFrameContext;\n}\n\n/**\n * Walks a thread's stack.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION,\n * THREAD_GET_CONTEXT and THREAD_SUSPEND_RESUME access. The handle can have any access for kernel\n * stack walking.\n * \\param ProcessHandle A handle to the thread's parent process. The handle must have\n * PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access. If a symbol provider is being used, pass\n * its process handle and specify the symbol provider in \\a SymbolProvider.\n * \\param ClientId The client ID identifying the thread.\n * \\param SymbolProvider The associated symbol provider.\n * \\param Flags A combination of flags.\n * \\li \\c PH_WALK_USER_STACK Walks the native user thread context stack.\n * \\li \\c PH_WALK_USER_WOW64_STACK Walks the Wow64 user thread context stack. On x86 systems this\n * flag is ignored. On ARM64 systems this includes ARM stack (ThreadWow64Context ARM_NT_CONTEXT).\n * \\li \\c PH_WALK_KERNEL_STACK Walks the kernel stack. This flag is ignored if there is no active\n * KSystemInformer connection.\n * \\param Callback A callback function which is executed for each stack frame.\n * \\param Context A user-defined value to pass to the callback function.\n */\nNTSTATUS PhWalkThreadStack(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_opt_ PCLIENT_ID ClientId,\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG Flags,\n    _In_ PPH_WALK_THREAD_STACK_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    BOOLEAN suspended = FALSE;\n    BOOLEAN deepfreeze = FALSE;\n    BOOLEAN processOpened = FALSE;\n    BOOLEAN isCurrentThread = FALSE;\n    BOOLEAN isSystemThread = FALSE;\n    THREAD_BASIC_INFORMATION basicInfo;\n    HANDLE stateChangeHandle = NULL;\n\n    // Open a handle to the process if we weren't given one.\n    if (!ProcessHandle)\n    {\n        if ((KsiLevel() >= KphLevelMed) || !ClientId)\n        {\n            if (!NT_SUCCESS(status = PhOpenThreadProcess(\n                ThreadHandle,\n                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n                &ProcessHandle\n                )))\n                return status;\n        }\n        else\n        {\n            if (!NT_SUCCESS(status = PhOpenProcess(\n                &ProcessHandle,\n                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n                ClientId->UniqueProcess\n                )))\n                return status;\n        }\n\n        processOpened = TRUE;\n    }\n\n    // Determine if the caller specified the current thread.\n    if (ClientId)\n    {\n        if (ClientId->UniqueThread == NtCurrentThreadId())\n            isCurrentThread = TRUE;\n        if (ClientId->UniqueProcess == SYSTEM_IDLE_PROCESS_ID || ClientId->UniqueProcess == SYSTEM_PROCESS_ID)\n            isSystemThread = TRUE;\n    }\n    else\n    {\n        if (ThreadHandle == NtCurrentThread())\n        {\n            isCurrentThread = TRUE;\n        }\n        else if (NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        {\n            if (basicInfo.ClientId.UniqueThread == NtCurrentThreadId())\n                isCurrentThread = TRUE;\n            if (basicInfo.ClientId.UniqueProcess == SYSTEM_IDLE_PROCESS_ID || basicInfo.ClientId.UniqueProcess == SYSTEM_PROCESS_ID)\n                isSystemThread = TRUE;\n        }\n    }\n\n    // Make sure this isn't a kernel-mode thread.\n    if (!isSystemThread)\n    {\n        ULONG_PTR startAddress;\n\n        if (NT_SUCCESS(PhGetThreadStartAddress(ThreadHandle, &startAddress)))\n        {\n            if (startAddress > PhSystemBasicInformation.MaximumUserModeAddress)\n            {\n                isSystemThread = TRUE;\n            }\n        }\n    }\n\n    // Suspend the thread to avoid inaccurate results. Don't suspend if we're walking the stack of\n    // the current thread or a kernel-mode thread.\n    if (!isCurrentThread && !isSystemThread)\n    {\n        if (WindowsVersion >= WINDOWS_11)\n        {\n            // Note: NtSuspendThread does not always suspend the thread due to race conditions in the kernel and third party processes.\n            // Windows 11 added state change support and fixed these and other bugs. We need to freeze the thread for an accurate result. (dmex)\n            // https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/controlling-processes-and-threads#freezing-and-suspending-threads\n\n            if (NT_SUCCESS(PhFreezeThread(&stateChangeHandle, ThreadHandle)))\n            {\n                deepfreeze = TRUE;\n            }\n        }\n\n        if (NT_SUCCESS(NtSuspendThread(ThreadHandle, NULL)))\n        {\n            suspended = TRUE;\n        }\n    }\n\n    // Kernel stack walk.\n    if ((Flags & PH_WALK_KERNEL_STACK) && (KsiLevel() >= KphLevelMed))\n    {\n        PVOID stack[256 - 2]; // See MAX_STACK_DEPTH\n        ULONG capturedFrames = 0;\n        ULONG i;\n\n        if (NT_SUCCESS(KphCaptureStackBackTraceThread(\n            ThreadHandle,\n            0,\n            sizeof(stack) / sizeof(PVOID),\n            stack,\n            &capturedFrames,\n            NULL,\n            KPH_STACK_BACK_TRACE_SKIP_KPH\n            )))\n        {\n            PH_THREAD_STACK_FRAME threadStackFrame;\n\n            memset(&threadStackFrame, 0, sizeof(PH_THREAD_STACK_FRAME));\n\n            for (i = 0; i < capturedFrames; i++)\n            {\n                threadStackFrame.PcAddress = stack[i];\n                threadStackFrame.Machine = PH_THREAD_STACK_NATIVE_MACHINE;\n                threadStackFrame.Flags = PH_THREAD_STACK_FRAME_KERNEL;\n\n                if ((ULONG_PTR)stack[i] <= PhSystemBasicInformation.MaximumUserModeAddress)\n                    break;\n\n                if (!Callback(&threadStackFrame, Context))\n                {\n                    goto ResumeExit;\n                }\n            }\n        }\n    }\n\n    if (Flags & PH_WALK_USER_STACK)\n    {\n        STACKFRAME_EX stackFrame;\n        PH_THREAD_STACK_FRAME threadStackFrame;\n        ULONG machine;\n        PVOID contextRecord;\n        CONTEXT context;\n#if defined(_ARM64_)\n        ARM64EC_NT_CONTEXT ecContext;\n        STACKFRAME_EX virtualFrame;\n        ULONG virtualMachine;\n#endif\n\n        contextRecord = &context;\n        machine = PH_THREAD_STACK_NATIVE_MACHINE;\n\n        memset(&context, 0, sizeof(context));\n        context.ContextFlags = CONTEXT_ALL;\n        context.ContextFlags |= CONTEXT_EXCEPTION_REQUEST;\n\n        if (!NT_SUCCESS(status = PhGetContextThread(ThreadHandle, &context)))\n            goto SkipUserStack;\n\n        memset(&stackFrame, 0, sizeof(STACKFRAME_EX));\n        stackFrame.StackFrameSize = sizeof(STACKFRAME_EX);\n\n#if defined(_ARM64_)\n        memset(&virtualFrame, 0, sizeof(STACKFRAME_EX));\n        virtualFrame.AddrReturn.Offset = MAXULONG64;\n#endif\n\n        // Program counter, Stack pointer, Frame pointer\n#if defined(_ARM64_)\n        stackFrame.AddrPC.Mode = AddrModeFlat;\n        stackFrame.AddrPC.Offset = context.Pc;\n        stackFrame.AddrStack.Mode = AddrModeFlat;\n        stackFrame.AddrStack.Offset = context.Sp;\n        stackFrame.AddrFrame.Mode = AddrModeFlat;\n        stackFrame.AddrFrame.Offset = context.Fp;\n#elif defined(_AMD64_)\n        stackFrame.AddrPC.Mode = AddrModeFlat;\n        stackFrame.AddrPC.Offset = context.Rip;\n        stackFrame.AddrStack.Mode = AddrModeFlat;\n        stackFrame.AddrStack.Offset = context.Rsp;\n        stackFrame.AddrFrame.Mode = AddrModeFlat;\n        stackFrame.AddrFrame.Offset = context.Rbp;\n#else\n        stackFrame.AddrPC.Mode = AddrModeFlat;\n        stackFrame.AddrPC.Offset = context.Eip;\n        stackFrame.AddrStack.Mode = AddrModeFlat;\n        stackFrame.AddrStack.Offset = context.Esp;\n        stackFrame.AddrFrame.Mode = AddrModeFlat;\n        stackFrame.AddrFrame.Offset = context.Ebp;\n#endif\n\n        while (TRUE)\n        {\n            if (!PhStackWalk(\n                machine,\n                ProcessHandle,\n                ThreadHandle,\n                &stackFrame,\n                contextRecord,\n                SymbolProvider,\n                NULL,\n                NULL,\n                NULL,\n                NULL\n                ))\n            {\n#if defined(_ARM64_)\n                goto CheckFinalARM64VirtualFrame;\n#else\n                break;\n#endif\n            }\n\n#if defined(_ARM64_)\n            // Strip any PAC bits from the addresses.\n            stackFrame.AddrPC.Offset = PAC_DECODE_ADDRESS(stackFrame.AddrPC.Offset);\n            stackFrame.AddrReturn.Offset = PAC_DECODE_ADDRESS(stackFrame.AddrReturn.Offset);\n            if (contextRecord == &ecContext)\n            {\n                ecContext.Pc = PAC_DECODE_ADDRESS(ecContext.Pc);\n                ecContext.Lr = PAC_DECODE_ADDRESS(ecContext.Lr);\n            }\n            else\n            {\n                context.Pc = PAC_DECODE_ADDRESS(context.Pc);\n                context.Lr = PAC_DECODE_ADDRESS(context.Lr);\n            }\n#endif\n\n            // If we have an invalid instruction pointer, break.\n            if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == ULONG64_MAX)\n            {\n#if defined(_ARM64_)\nCheckFinalARM64VirtualFrame:\n                // If we're in the middle of processing a virtual frame and reach here we still\n                // need to process the virtual frame (it is the final frame). Do not do this for\n                // ARM64EC since it will point to narnia (the final fame is already processed).\n                if (!virtualFrame.AddrReturn.Offset && virtualMachine != IMAGE_FILE_MACHINE_ARM64EC)\n                {\n                    // Convert the stack frame and execute the callback.\n\n                    PhConvertStackFrame(&virtualFrame, (USHORT)virtualMachine, 0, &threadStackFrame);\n\n                    if (!Callback(&threadStackFrame, Context))\n                        goto ResumeExit;\n                }\n#endif\n                break;\n            }\n\n#if defined(_ARM64_)\n            USHORT frameMachine;\n\n            // TODO(jxy-s)\n            //\n            // Much of the stack walk handling for EC code is in dbgeng and not dbghelp. Since we\n            // only rely on dbghelp we need some special handling too. The following are known\n            // issues with possible solutions. These need more time to investigate:\n            //\n            // - ARM64EC (Inline frame) seem to be missing. Probably needs special handling or the\n            //   \"virtual frames\" are messing up the existing inline frame resolution. For context\n            //   dbgeng.dll appears to have \"virtual frames\" as we do here, but we likely need some\n            //   additional handling for inline frames.\n            // - .NET under ARM64 emulation seems to eventually walk into strange frames, x64 is\n            //   known to be affected, other arches on ARM64 need tested too. Seems to be a bug in\n            //   dbghelp.dll because dbgeng.dll (e.g. windbg.exe) seems to be broken here too.\n\n            frameMachine = PhpGetMachineForAddress(SymbolProvider, ProcessHandle, (PVOID)stackFrame.AddrPC.Offset);\n\n            if (machine != frameMachine)\n            {\n                // switch the effective machine\n                machine = frameMachine;\n\n                if (frameMachine == IMAGE_FILE_MACHINE_AMD64 && contextRecord != &ecContext)\n                {\n                    PhNativeContextToEcContext(&ecContext, &context, TRUE);\n                    contextRecord = &ecContext;\n                }\n                else if (contextRecord != &context)\n                {\n                    PhEcContextToNativeContext(&context, &ecContext);\n                    contextRecord = &context;\n                }\n            }\n\n            if (!virtualFrame.AddrReturn.Offset)\n            {\n                // We stored a frame without a return address to process later, do it now.\n                virtualFrame.AddrReturn = stackFrame.AddrPC;\n\n                // Convert the stack frame and execute the callback.\n\n                PhConvertStackFrame(&virtualFrame, (USHORT)virtualMachine, 0, &threadStackFrame);\n\n                if (!Callback(&threadStackFrame, Context))\n                    goto ResumeExit;\n\n                virtualFrame.AddrReturn.Offset = MAXULONG64;\n            }\n\n            if (!stackFrame.AddrReturn.Offset)\n            {\n                // Track this as a temporary virtual frame and continue to try to resolve the next\n                // frame. If we do, during the next loop we will use use the the program counter as\n                // the return address and invoke the callback.\n                virtualFrame = stackFrame;\n                virtualMachine = machine;\n                continue;\n            }\n#endif\n\n            // Convert the stack frame and execute the callback.\n\n            PhConvertStackFrame(&stackFrame, (USHORT)machine, 0, &threadStackFrame);\n\n            if (!Callback(&threadStackFrame, Context))\n                goto ResumeExit;\n\n#if defined(_X86_)\n            // (x86 only) Allow the user to change Eip, Esp and Ebp.\n            context.Eip = PtrToUlong(threadStackFrame.PcAddress);\n            stackFrame.AddrPC.Offset = PtrToUlong(threadStackFrame.PcAddress);\n            context.Ebp = PtrToUlong(threadStackFrame.FrameAddress);\n            stackFrame.AddrFrame.Offset = PtrToUlong(threadStackFrame.FrameAddress);\n            context.Esp = PtrToUlong(threadStackFrame.StackAddress);\n            stackFrame.AddrStack.Offset = PtrToUlong(threadStackFrame.StackAddress);\n#endif\n        }\n    }\n\nSkipUserStack:\n\n#if defined(_WIN64)\n    // WOW64 stack walk.\n    if (Flags & PH_WALK_USER_WOW64_STACK)\n    {\n        STACKFRAME_EX stackFrame;\n        PH_THREAD_STACK_FRAME threadStackFrame;\n        WOW64_CONTEXT context;\n\n        memset(&context, 0, sizeof(WOW64_CONTEXT));\n        context.ContextFlags = WOW64_CONTEXT_ALL;\n        context.ContextFlags |= CONTEXT_EXCEPTION_REQUEST;\n\n        if (!NT_SUCCESS(status = PhGetThreadWow64Context(ThreadHandle, &context)))\n            goto SkipI386Stack;\n\n        memset(&stackFrame, 0, sizeof(STACKFRAME_EX));\n        stackFrame.StackFrameSize = sizeof(STACKFRAME_EX);\n        stackFrame.AddrPC.Mode = AddrModeFlat;\n        stackFrame.AddrPC.Offset = context.Eip;\n        stackFrame.AddrStack.Mode = AddrModeFlat;\n        stackFrame.AddrStack.Offset = context.Esp;\n        stackFrame.AddrFrame.Mode = AddrModeFlat;\n        stackFrame.AddrFrame.Offset = context.Ebp;\n\n        while (TRUE)\n        {\n            if (!PhStackWalk(\n                IMAGE_FILE_MACHINE_I386,\n                ProcessHandle,\n                ThreadHandle,\n                &stackFrame,\n                &context,\n                SymbolProvider,\n                NULL,\n                NULL,\n                NULL,\n                NULL\n                ))\n            {\n                break;\n            }\n\n            // TODO(jxy-s)\n            //\n            // Restore CHPE frame detection and fix x86 stack walking on ARM64. Even dbgeng.dll\n            // seems to struggle here but it will at least show CHPE frames. We use to have support\n            // for this I removed it in the last chunk of ARM64 fixes since I wasn't happy with it.\n\n            // If we have an invalid instruction pointer, break.\n            if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == ULONG64_MAX)\n                break;\n\n            // Convert the stack frame and execute the callback.\n\n            PhConvertStackFrame(&stackFrame, IMAGE_FILE_MACHINE_I386, 0, &threadStackFrame);\n\n            if (!Callback(&threadStackFrame, Context))\n                goto ResumeExit;\n\n#if !defined(_ARM64_)\n            // (x86 only) Allow extensions to fixup the Eip, Esp and Ebp addresses.\n            // Note: Managed environments like .NET manage their own stack frames,\n            // and don't align with native expectations. Extensions like DotNetTools\n            // query the CLR runtime debug interface and provide the correct addresses\n            // as required to show correct thread call stacks and execution context. (dnex)\n            context.Eip = PtrToUlong(threadStackFrame.PcAddress);\n            stackFrame.AddrPC.Offset = PtrToUlong(threadStackFrame.PcAddress);\n            context.Ebp = PtrToUlong(threadStackFrame.FrameAddress);\n            stackFrame.AddrFrame.Offset = PtrToUlong(threadStackFrame.FrameAddress);\n            context.Esp = PtrToUlong(threadStackFrame.StackAddress);\n            stackFrame.AddrStack.Offset = PtrToUlong(threadStackFrame.StackAddress);\n#endif\n        }\n    }\n\nSkipI386Stack:\n\n#endif\n\n#if defined(_ARM64_)\n    // Arm32 stack walk.\n    if (Flags & PH_WALK_USER_WOW64_STACK)\n    {\n        STACKFRAME_EX stackFrame;\n        PH_THREAD_STACK_FRAME threadStackFrame;\n        ARM_NT_CONTEXT context;\n\n        memset(&context, 0, sizeof(ARM_NT_CONTEXT));\n        context.ContextFlags = CONTEXT_ARM_ALL;\n        context.ContextFlags |= CONTEXT_EXCEPTION_REQUEST;\n\n        // ThreadWow64Context ARM_NT_CONTEXT\n        if (!NT_SUCCESS(status = PhGetThreadArm32Context(ThreadHandle, &context)))\n            goto SkipARMStack;\n\n        memset(&stackFrame, 0, sizeof(STACKFRAME_EX));\n        stackFrame.StackFrameSize = sizeof(STACKFRAME_EX);\n        stackFrame.AddrPC.Mode = AddrModeFlat;\n        stackFrame.AddrPC.Offset = context.Pc;\n        stackFrame.AddrStack.Mode = AddrModeFlat;\n        stackFrame.AddrStack.Offset = context.Sp;\n        stackFrame.AddrFrame.Mode = AddrModeFlat;\n        stackFrame.AddrFrame.Offset = 0;\n\n        while (TRUE)\n        {\n            if (!PhStackWalk(\n                IMAGE_FILE_MACHINE_ARMNT,\n                ProcessHandle,\n                ThreadHandle,\n                &stackFrame,\n                &context,\n                SymbolProvider,\n                NULL,\n                NULL,\n                NULL,\n                NULL\n                ))\n            {\n                break;\n            }\n\n            // If we have an invalid instruction pointer, break.\n            if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == ULONG64_MAX)\n                break;\n\n            // Convert the stack frame and execute the callback.\n\n            PhConvertStackFrame(&stackFrame, IMAGE_FILE_MACHINE_ARMNT, 0, &threadStackFrame);\n\n            if (!Callback(&threadStackFrame, Context))\n                goto ResumeExit;\n        }\n    }\n\nSkipARMStack:\n\n#endif\n\nResumeExit:\n    if (suspended)\n    {\n        NtResumeThread(ThreadHandle, NULL);\n    }\n\n    if (stateChangeHandle)\n    {\n        PhThawThread(stateChangeHandle, ThreadHandle);\n        NtClose(stateChangeHandle);\n    }\n\n    if (processOpened)\n    {\n        NtClose(ProcessHandle);\n    }\n\n    return status;\n}\n\nPPH_STRING PhUndecorateSymbolName(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PCWSTR DecoratedName\n    )\n{\n    PPH_STRING undecoratedSymbolName = NULL;\n    PWSTR undecoratedBuffer;\n    ULONG result;\n\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!UnDecorateSymbolNameW_I)\n        return NULL;\n\n    // lucasg: there is no way to know the resulting length of an undecorated name.\n    // If there is not enough space, the function does not fail and instead returns a truncated name.\n\n    undecoratedBuffer = PhAllocate(PAGE_SIZE * sizeof(WCHAR));\n    //memset(undecoratedBuffer, 0, PAGE_SIZE * sizeof(WCHAR));\n\n    PH_LOCK_SYMBOLS();\n\n    result = UnDecorateSymbolNameW_I(\n        DecoratedName,\n        undecoratedBuffer,\n        PAGE_SIZE,\n        UNDNAME_COMPLETE\n        );\n\n    PH_UNLOCK_SYMBOLS();\n\n    if (result != 0)\n        undecoratedSymbolName = PhCreateStringEx(undecoratedBuffer, result * sizeof(WCHAR));\n    PhFree(undecoratedBuffer);\n\n    return undecoratedSymbolName;\n}\n\ntypedef struct _PH_ENUMERATE_SYMBOLS_CONTEXT\n{\n    PVOID UserContext;\n    PPH_ENUMERATE_SYMBOLS_CALLBACK UserCallback;\n} PH_ENUMERATE_SYMBOLS_CONTEXT, *PPH_ENUMERATE_SYMBOLS_CONTEXT;\n\nBOOL CALLBACK PhEnumerateSymbolsCallback(\n    _In_ PSYMBOL_INFOW SymbolInfo,\n    _In_ ULONG SymbolSize,\n    _In_ PVOID Context\n    )\n{\n    PPH_ENUMERATE_SYMBOLS_CONTEXT context = (PPH_ENUMERATE_SYMBOLS_CONTEXT)Context;\n    BOOLEAN result;\n    PH_SYMBOL_INFO symbolInfo = { 0 };\n\n    if (SymbolInfo->MaxNameLen)\n    {\n        SIZE_T SuggestedLength;\n\n        symbolInfo.Name.Buffer = SymbolInfo->Name;\n        symbolInfo.Name.Length = min(SymbolInfo->NameLen, SymbolInfo->MaxNameLen - 1) * sizeof(WCHAR);\n\n        // NameLen is unreliable, might be greater that expected\n\n        SuggestedLength = PhCountStringZ(symbolInfo.Name.Buffer) * sizeof(WCHAR);\n        symbolInfo.Name.Length = min(symbolInfo.Name.Length, SuggestedLength);\n    }\n    else\n    {\n        PhInitializeEmptyStringRef(&symbolInfo.Name);\n    }\n\n    symbolInfo.TypeIndex = SymbolInfo->TypeIndex;\n    symbolInfo.Index = SymbolInfo->Index;\n    symbolInfo.Size = SymbolInfo->Size;\n    symbolInfo.ModBase = SymbolInfo->ModBase;\n    symbolInfo.Flags = SymbolInfo->Flags;\n    symbolInfo.Value = SymbolInfo->Value;\n    symbolInfo.Address = SymbolInfo->Address;\n    symbolInfo.Register = SymbolInfo->Register;\n    symbolInfo.Scope = SymbolInfo->Scope;\n    symbolInfo.Tag = SymbolInfo->Tag;\n\n    result = context->UserCallback(&symbolInfo, SymbolSize, context->UserContext);\n\n    if (result)\n        return TRUE;\n    return FALSE;\n}\n\nBOOLEAN PhEnumerateSymbols(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseOfDll,\n    _In_opt_ PCWSTR Mask,\n    _In_ PPH_ENUMERATE_SYMBOLS_CALLBACK EnumSymbolsCallback,\n    _In_opt_ PVOID UserContext\n    )\n{\n    BOOL result;\n    PH_ENUMERATE_SYMBOLS_CONTEXT enumContext;\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return FALSE;\n\n    if (!SymEnumSymbolsW_I)\n        SymEnumSymbolsW_I = PhGetDllProcedureAddressZ(L\"dbghelp.dll\", \"SymEnumSymbolsW\", 0);\n\n    if (!SymEnumSymbolsW_I)\n    {\n        SetLastError(ERROR_PROC_NOT_FOUND);\n        return FALSE;\n    }\n\n    memset(&enumContext, 0, sizeof(PH_ENUMERATE_SYMBOLS_CONTEXT));\n    enumContext.UserContext = UserContext;\n    enumContext.UserCallback = EnumSymbolsCallback;\n\n    PH_LOCK_SYMBOLS();\n\n    result = SymEnumSymbolsW_I(\n        ProcessHandle,\n        (ULONG64)BaseOfDll,\n        Mask,\n        PhEnumerateSymbolsCallback,\n        &enumContext\n        );\n\n    PH_UNLOCK_SYMBOLS();\n\n    if (result)\n        return TRUE;\n    return FALSE;\n}\n\n_Success_(return)\nBOOLEAN PhGetSymbolProviderDiaSource(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID BaseOfDll,\n    _Out_ PVOID* DiaSource\n    )\n{\n    BOOLEAN result;\n    PVOID source; // IDiaDataSource COM interface\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return FALSE;\n\n    if (!SymGetDiaSource_I)\n        SymGetDiaSource_I = PhGetDllProcedureAddressZ(L\"dbghelp.dll\", \"SymGetDiaSource\", 0);\n    if (!SymGetDiaSource_I)\n        return FALSE;\n\n    //PH_LOCK_SYMBOLS();\n\n    result = !!SymGetDiaSource_I(\n        SymbolProvider->ProcessHandle,\n        (ULONGLONG)BaseOfDll,\n        &source\n        );\n    //GetLastError(); // returns HRESULT\n\n    //PH_UNLOCK_SYMBOLS();\n\n    if (result)\n    {\n        *DiaSource = source;\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n_Success_(return)\nBOOLEAN PhGetSymbolProviderDiaSession(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID BaseOfDll,\n    _Out_ PVOID* DiaSession\n    )\n{\n    BOOLEAN result;\n    PVOID session; // IDiaSession COM interface\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return FALSE;\n\n    if (!SymGetDiaSession_I)\n        SymGetDiaSession_I = PhGetDllProcedureAddressZ(L\"dbghelp.dll\", \"SymGetDiaSession\", 0);\n    if (!SymGetDiaSession_I)\n        return FALSE;\n\n    //PH_LOCK_SYMBOLS();\n\n    result = !!SymGetDiaSession_I(\n        SymbolProvider->ProcessHandle,\n        (ULONGLONG)BaseOfDll,\n        &session\n        );\n    //GetLastError(); // returns HRESULT\n\n    //PH_UNLOCK_SYMBOLS();\n\n    if (result)\n    {\n        *DiaSession = session;\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhSymbolProviderFreeDiaString(\n    _In_ PCWSTR DiaString\n    )\n{\n    if ((SymGetDiaSession_I || SymGetDiaSource_I) && !SymFreeDiaString_I)\n        SymFreeDiaString_I = PhGetDllProcedureAddressZ(L\"dbghelp.dll\", \"SymFreeDiaString\", 0);\n    if (!SymFreeDiaString_I)\n        return;\n\n    SymFreeDiaString_I(DiaString);\n}\n\nBOOLEAN PhSymbolProviderInlineContextSupported(\n    VOID\n    )\n{\n    return StackWalkEx_I && SymFromInlineContextW_I;\n}\n\n_Success_(return != NULL)\nPPH_STRING PhGetSymbolFromInlineContext(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel,\n    _Out_opt_ PPH_STRING *FileName,\n    _Out_opt_ PPH_STRING *SymbolName,\n    _Out_opt_ PULONG64 Displacement,\n    _Out_opt_ PPVOID BaseAddress\n    )\n{\n    PSYMBOL_INFOW symbolInfo;\n    ULONG nameLength;\n    PPH_STRING symbol = NULL;\n    PH_SYMBOL_RESOLVE_LEVEL resolveLevel;\n    ULONG64 displacement;\n    PPH_STRING modFileName = NULL;\n    PPH_STRING modBaseName = NULL;\n    PVOID modBase = NULL;\n    PPH_STRING symbolName = NULL;\n\n    if (StackFrame->PcAddress == 0)\n    {\n        if (ResolveLevel) *ResolveLevel = PhsrlInvalid;\n        if (FileName) *FileName = NULL;\n        if (SymbolName) *SymbolName = NULL;\n        if (Displacement) *Displacement = 0;\n        if (BaseAddress) *BaseAddress = NULL;\n\n        return NULL;\n    }\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return FALSE;\n\n    if (!SymFromInlineContextW_I)\n        return NULL;\n\n    symbolInfo = PhAllocateZero(FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * sizeof(WCHAR));\n    symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n    symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN;\n\n    PH_LOCK_SYMBOLS();\n\n    SymFromInlineContextW_I(\n        SymbolProvider->ProcessHandle,\n        (ULONG64)StackFrame->PcAddress,\n        StackFrame->InlineFrameContext,\n        &displacement,\n        symbolInfo\n        );\n    nameLength = symbolInfo->NameLen;\n\n    if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN)\n    {\n        PhFree(symbolInfo);\n        symbolInfo = PhAllocateZero(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));\n        symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n        symbolInfo->MaxNameLen = nameLength + 1;\n\n        SymFromInlineContextW_I(\n            SymbolProvider->ProcessHandle,\n            (ULONG64)StackFrame->PcAddress,\n            StackFrame->InlineFrameContext,\n            &displacement,\n            symbolInfo\n            );\n    }\n\n    PH_UNLOCK_SYMBOLS();\n\n    if (symbolInfo->ModBase == 0)\n    {\n        modBase = PhGetModuleFromAddress(\n            SymbolProvider,\n            StackFrame->PcAddress,\n            &modFileName\n            );\n    }\n    else\n    {\n        modBase = PhGetModuleFromAddress(\n            SymbolProvider,\n            (PVOID)symbolInfo->ModBase,\n            &modFileName\n            );\n    }\n\n    if (!modFileName)\n    {\n        resolveLevel = PhsrlAddress;\n        symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR));\n        PhPrintPointer(symbol->Buffer, (PVOID)(ULONG64)StackFrame->PcAddress);\n        PhTrimToNullTerminatorString(symbol);\n\n        goto CleanupExit;\n    }\n\n    modBaseName = PhGetBaseName(modFileName);\n\n    if (symbolInfo->NameLen == 0)\n    {\n        PH_FORMAT format[3];\n\n        resolveLevel = PhsrlModule;\n\n        PhInitFormatSR(&format[0], modBaseName->sr);\n        PhInitFormatS(&format[1], L\"+0x\");\n        PhInitFormatIX(&format[2], (ULONG_PTR)((ULONG_PTR)StackFrame->PcAddress - (ULONG_PTR)modBase));\n        symbol = PhFormat(format, 3, modBaseName->Length + 6 + 32);\n\n        goto CleanupExit;\n    }\n\n    symbolName = PhCreateStringEx(symbolInfo->Name, symbolInfo->NameLen * sizeof(WCHAR));\n    PhTrimToNullTerminatorString(symbolName);\n    resolveLevel = PhsrlFunction;\n\n    if (displacement == 0)\n    {\n        PH_FORMAT format[3];\n\n        PhInitFormatSR(&format[0], modBaseName->sr);\n        PhInitFormatC(&format[1], L'!');\n        PhInitFormatSR(&format[2], symbolName->sr);\n\n        symbol = PhFormat(format, 3, modBaseName->Length + 2 + symbolName->Length);\n    }\n    else\n    {\n        PH_FORMAT format[5];\n\n        PhInitFormatSR(&format[0], modBaseName->sr);\n        PhInitFormatC(&format[1], L'!');\n        PhInitFormatSR(&format[2], symbolName->sr);\n        PhInitFormatS(&format[3], L\"+0x\");\n        PhInitFormatIX(&format[4], (ULONG_PTR)displacement);\n\n        symbol = PhFormat(format, 5, modBaseName->Length + 2 + symbolName->Length + 6 + 32);\n    }\n\nCleanupExit:\n\n    if (ResolveLevel)\n        *ResolveLevel = resolveLevel;\n    if (FileName)\n        PhSetReference(FileName, modFileName);\n    if (SymbolName)\n        PhSetReference(SymbolName, symbolName);\n    if (Displacement)\n        *Displacement = displacement;\n    if (BaseAddress)\n        *BaseAddress = symbolInfo->ModBase ? (PVOID)symbolInfo->ModBase : modBase;\n\n    PhClearReference(&modFileName);\n    PhClearReference(&modBaseName);\n    PhClearReference(&symbolName);\n    PhFree(symbolInfo);\n\n    return symbol;\n}\n\n_Success_(return)\nBOOLEAN PhGetLineFromInlineContext(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _In_opt_ PVOID BaseAddress,\n    _Out_ PPH_STRING *FileName,\n    _Out_opt_ PULONG Displacement,\n    _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information\n    )\n{\n    IMAGEHLP_LINEW64 line;\n    BOOL result;\n    ULONG displacement;\n    PPH_STRING fileName;\n\n    if (!PhpRegisterSymbolProvider(SymbolProvider))\n        return FALSE;\n\n    if (!SymGetLineFromInlineContextW_I)\n        return FALSE;\n\n    line.SizeOfStruct = sizeof(IMAGEHLP_LINEW64);\n\n    PH_LOCK_SYMBOLS();\n\n    result = SymGetLineFromInlineContextW_I(\n        SymbolProvider->ProcessHandle,\n        (ULONG64)StackFrame->PcAddress,\n        StackFrame->InlineFrameContext,\n        (ULONG64)BaseAddress,\n        &displacement,\n        &line\n        );\n\n    PH_UNLOCK_SYMBOLS();\n\n    if (result)\n        fileName = PhCreateString(line.FileName);\n    else\n        return FALSE;\n\n    *FileName = fileName;\n\n    if (Displacement)\n        *Displacement = displacement;\n\n    if (Information)\n    {\n        Information->LineNumber = line.LineNumber;\n        Information->Address = line.Address;\n    }\n\n    return TRUE;\n}\n\n// Note: StackWalk64 doesn't support inline frames, so right before calling PhGetSymbolFromAddress\n// we can call this function to get the inline frames and manually insert them without much effort.\n// StackWalkEx provides inline frames by default and does not require this function. This function\n// is basically obsolete an unused because we're using StackWalkEx by default. (dmex)\n//PPH_LIST PhGetInlineStackSymbolsFromAddress(\n//    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n//    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n//    _In_ BOOLEAN IncludeLineInformation\n//    )\n//{\n//    static _SymAddrIncludeInlineTrace SymAddrIncludeInlineTrace_I = NULL;\n//    static _SymQueryInlineTrace SymQueryInlineTrace_I = NULL;\n//    PPH_LIST inlineSymbolList = NULL;\n//    ULONG64 inlineFrameAddress = 0;\n//    ULONG inlineFrameCount = 0;\n//    ULONG inlineFrameContext = 0;\n//    ULONG inlineFrameIndex = 0;\n//\n//    if (StackFrame->PcAddress == 0)\n//        return NULL;\n//\n//    if (!PhpRegisterSymbolProvider(SymbolProvider))\n//        return NULL;\n//\n//    if (!SymAddrIncludeInlineTrace_I)\n//        SymAddrIncludeInlineTrace_I = PhGetDllProcedureAddressZ(L\"dbghelp.dll\", \"SymAddrIncludeInlineTrace\", 0);\n//    if (!SymQueryInlineTrace_I)\n//        SymQueryInlineTrace_I = PhGetDllProcedureAddressZ(L\"dbghelp.dll\", \"SymQueryInlineTrace\", 0);\n//\n//    if (!(\n//        SymAddrIncludeInlineTrace_I &&\n//        SymQueryInlineTrace_I &&\n//        SymFromInlineContextW_I &&\n//        SymGetLineFromInlineContextW_I\n//        ))\n//    {\n//        return NULL;\n//    }\n//\n//    PH_LOCK_SYMBOLS();\n//\n//    inlineFrameAddress = (ULONG64)StackFrame->PcAddress - sizeof(BYTE);\n//    inlineFrameCount = SymAddrIncludeInlineTrace_I(\n//        SymbolProvider->ProcessHandle,\n//        inlineFrameAddress\n//        );\n//\n//    if (inlineFrameCount == 0)\n//    {\n//        PH_UNLOCK_SYMBOLS();\n//        return NULL;\n//    }\n//\n//    if (!SymQueryInlineTrace_I(\n//        SymbolProvider->ProcessHandle,\n//        inlineFrameAddress,\n//        INLINE_FRAME_CONTEXT_INIT,\n//        inlineFrameAddress,\n//        inlineFrameAddress,\n//        &inlineFrameContext,\n//        &inlineFrameIndex\n//        ))\n//    {\n//        PH_UNLOCK_SYMBOLS();\n//        return NULL;\n//    }\n//\n//    inlineSymbolList = PhCreateList(1);\n//\n//    for (ULONG i = 0; i < inlineFrameCount; i++)\n//    {\n//        BOOL result = FALSE;\n//        ULONG64 inlineFrameDisplacement = 0;\n//        ULONG64 modBaseAddress = 0;\n//        PPH_STRING modFileName = NULL;\n//        PPH_STRING modBaseName = NULL;\n//        PSYMBOL_INFOW symbolInfo;\n//        ULONG nameLength = 0;\n//\n//        symbolInfo = PhAllocateZero(FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * sizeof(WCHAR));\n//        symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n//        symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN;\n//\n//        result = SymFromInlineContextW_I(\n//            SymbolProvider->ProcessHandle,\n//            inlineFrameAddress,\n//            inlineFrameContext,\n//            &inlineFrameDisplacement,\n//            symbolInfo\n//            );\n//        nameLength = symbolInfo->NameLen;\n//\n//        if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN)\n//        {\n//            PhFree(symbolInfo);\n//            symbolInfo = PhAllocateZero(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));\n//            symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n//            symbolInfo->MaxNameLen = nameLength + 1;\n//\n//            result = SymFromInlineContextW_I(\n//                SymbolProvider->ProcessHandle,\n//                inlineFrameAddress,\n//                inlineFrameContext,\n//                &inlineFrameDisplacement,\n//                symbolInfo\n//                );\n//        }\n//\n//        if (!result)\n//        {\n//            inlineFrameContext++;\n//            PhFree(symbolInfo);\n//            continue;\n//        }\n//\n//        if (symbolInfo->ModBase == 0)\n//        {\n//            modBaseAddress = PhGetModuleFromAddress(\n//                SymbolProvider,\n//                inlineFrameAddress,\n//                &modFileName\n//                );\n//        }\n//        else\n//        {\n//            PH_SYMBOL_MODULE lookupSymbolModule;\n//            PPH_AVL_LINKS existingLinks;\n//            PPH_SYMBOL_MODULE symbolModule;\n//\n//            lookupSymbolModule.BaseAddress = symbolInfo->ModBase;\n//\n//            PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock);\n//\n//            existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links);\n//\n//            if (existingLinks)\n//            {\n//                symbolModule = CONTAINING_RECORD(existingLinks, PH_SYMBOL_MODULE, Links);\n//                PhSetReference(&modFileName, symbolModule->FileName);\n//            }\n//\n//            PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock);\n//        }\n//\n//        if (modFileName)\n//        {\n//            modBaseName = PhGetBaseName(modFileName);\n//        }\n//\n//        if (result)\n//        {\n//            PPH_INLINE_STACK_FRAME inlineStackFrame;\n//\n//            inlineStackFrame = PhAllocate(sizeof(PH_INLINE_STACK_FRAME));\n//            memset(inlineStackFrame, 0, sizeof(PH_INLINE_STACK_FRAME));\n//\n//            if (modFileName)\n//            {\n//                PhSetReference(&inlineStackFrame->FileName, modFileName);\n//\n//                if (symbolInfo->NameLen == 0)\n//                {\n//                    PH_FORMAT format[3];\n//\n//                    inlineStackFrame->ResolveLevel = PhsrlModule;\n//\n//                    PhInitFormatSR(&format[0], modBaseName->sr);\n//                    PhInitFormatS(&format[1], L\"+0x\");\n//                    PhInitFormatIX(&format[2], (ULONG_PTR)(inlineFrameAddress - modBaseAddress + inlineFrameDisplacement + sizeof(BYTE)));\n//                    // address + inlineFrameDisplacement + sizeof(BYTE) ??\n//\n//                    inlineStackFrame->Symbol = PhFormat(format, 3, modBaseName->Length + 6 + 32);\n//                }\n//                else\n//                {\n//                    PPH_STRING symbolName;\n//\n//                    inlineStackFrame->ResolveLevel = PhsrlFunction;\n//\n//                    symbolName = PhCreateStringEx(symbolInfo->Name, symbolInfo->NameLen * sizeof(WCHAR));\n//                    PhTrimToNullTerminatorString(symbolName);\n//\n//                    if (inlineFrameDisplacement == 0)\n//                    {\n//                        PH_FORMAT format[3];\n//\n//                        PhInitFormatSR(&format[0], modBaseName->sr);\n//                        PhInitFormatC(&format[1], L'!');\n//                        PhInitFormatSR(&format[2], symbolName->sr);\n//\n//                        inlineStackFrame->Symbol = PhFormat(format, 3, modBaseName->Length + 2 + symbolName->Length);\n//                    }\n//                    else\n//                    {\n//                        PH_FORMAT format[5];\n//\n//                        PhInitFormatSR(&format[0], modBaseName->sr);\n//                        PhInitFormatC(&format[1], L'!');\n//                        PhInitFormatSR(&format[2], symbolName->sr);\n//                        PhInitFormatS(&format[3], L\"+0x\");\n//                        PhInitFormatIX(&format[4], (ULONG_PTR)inlineFrameDisplacement + sizeof(BYTE)); // add byte to match the windbg displacement (dmex)\n//\n//                        inlineStackFrame->Symbol = PhFormat(format, 5, modBaseName->Length + 2 + symbolName->Length + 6 + 32);\n//                    }\n//\n//                    PhDereferenceObject(symbolName);\n//                }\n//            }\n//            else\n//            {\n//                PPH_STRING symbolName;\n//\n//                inlineStackFrame->ResolveLevel = PhsrlAddress;\n//\n//                symbolName = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR));\n//                PhPrintPointer(symbolName->Buffer, (PVOID)inlineFrameAddress);\n//                PhTrimToNullTerminatorString(symbolName);\n//\n//                inlineStackFrame->Symbol = symbolName;\n//            }\n//\n//            if (inlineStackFrame->Symbol)\n//            {\n//                PhMoveReference(\n//                    &inlineStackFrame->Symbol,\n//                    PhConcatStringRefZ(&inlineStackFrame->Symbol->sr, L\" (Inline function)\")\n//                    );\n//            }\n//\n//            if (IncludeLineInformation)\n//            {\n//                IMAGEHLP_LINEW64 line;\n//                ULONG lineInlineDisplacement = 0;\n//\n//                memset(&line, 0, sizeof(IMAGEHLP_LINEW64));\n//                line.SizeOfStruct = sizeof(IMAGEHLP_LINEW64);\n//\n//                if (SymGetLineFromInlineContextW_I(\n//                    SymbolProvider->ProcessHandle,\n//                    inlineFrameAddress,\n//                    inlineFrameContext,\n//                    symbolInfo->ModBase, // optional\n//                    &lineInlineDisplacement,\n//                    &line\n//                    ))\n//                {\n//                    inlineStackFrame->LineAddress = line.Address;\n//                    inlineStackFrame->LineNumber = line.LineNumber;\n//                    inlineStackFrame->LineDisplacement = lineInlineDisplacement;\n//                    inlineStackFrame->LineFileName = PhCreateString(line.FileName);\n//                }\n//            }\n//\n//            PhAddItemList(inlineSymbolList, inlineStackFrame);\n//        }\n//\n//        inlineFrameContext++;\n//        PhClearReference(&modFileName);\n//        PhClearReference(&modBaseName);\n//        PhFree(symbolInfo);\n//    }\n//\n//    PH_UNLOCK_SYMBOLS();\n//\n//    return inlineSymbolList;\n//}\n//\n//VOID PhFreeInlineStackSymbols(\n//    _In_ PPH_LIST InlineSymbolList\n//    )\n//{\n//    for (ULONG i = 0; i < InlineSymbolList->Count; i++)\n//    {\n//        PPH_INLINE_STACK_FRAME inlineStackFrame = InlineSymbolList->Items[i];\n//\n//        PhClearReference(&inlineStackFrame->Symbol);\n//        PhClearReference(&inlineStackFrame->FileName);\n//        PhClearReference(&inlineStackFrame->LineFileName);\n//        PhFree(inlineStackFrame);\n//    }\n//\n//    PhDereferenceObject(InlineSymbolList);\n//}\n\nCV_CFL_LANG PhGetDiaSymbolCompilandInformation(\n    _In_ IDiaLineNumber* LineNumber\n    )\n{\n    CV_CFL_LANG compilandLanguage = ULONG_MAX;\n    ULONG count;\n    IDiaSymbol* compiland;\n    IDiaSymbol* symbol;\n    IDiaEnumSymbols* enumSymbols;\n\n    if (IDiaLineNumber_get_compiland(LineNumber, &compiland) == S_OK)\n    {\n        if (IDiaSymbol_findChildren(compiland, SymTagCompilandDetails, NULL, nsNone, &enumSymbols) == S_OK)\n        {\n            while (IDiaEnumSymbols_Next(enumSymbols, 1, &symbol, &count) == S_OK)\n            {\n                ULONG language;\n\n                if (IDiaSymbol_get_language(symbol, &language) == S_OK)\n                {\n                    compilandLanguage = language;\n                    break;\n                }\n\n                IDiaSymbol_Release(symbol);\n            }\n\n            IDiaEnumSymbols_Release(enumSymbols);\n        }\n\n        IDiaSymbol_Release(compiland);\n    }\n\n    return compilandLanguage;\n}\n\nPPH_STRING PhGetDiaSymbolLineInformation(\n    _In_ IDiaSession* Session,\n    _In_ IDiaSymbol* Symbol,\n    _In_ PVOID Address,\n    _In_ ULONG Length\n    )\n{\n    IDiaLineNumber* symbolLineNumber;\n    CV_CFL_LANG language = ULONG_MAX;\n\n    if (IDiaSymbol_getSrcLineOnTypeDefn(Symbol, &symbolLineNumber) == S_OK)\n    {\n        language = PhGetDiaSymbolCompilandInformation(symbolLineNumber);\n        IDiaLineNumber_Release(symbolLineNumber);\n    }\n    else\n    {\n        ULONG count;\n        IDiaEnumLineNumbers* enumLineNumbers;\n\n        if (IDiaSession_findLinesByVA(Session, (ULONGLONG)Address, Length, &enumLineNumbers) == S_OK)\n        {\n            if (IDiaEnumLineNumbers_Next(enumLineNumbers, 1, &symbolLineNumber, &count) == S_OK)\n            {\n                language = PhGetDiaSymbolCompilandInformation(symbolLineNumber);\n                IDiaLineNumber_Release(symbolLineNumber);\n            }\n\n            IDiaEnumLineNumbers_Release(enumLineNumbers);\n        }\n    }\n\n    switch (language)\n    {\n    case CV_CFL_C:\n        return PhCreateString(L\"C\");\n    case CV_CFL_CXX:\n        return PhCreateString(L\"C++\");\n    case CV_CFL_FORTRAN:\n        return PhCreateString(L\"FORTRAN\");\n    case CV_CFL_MASM:\n        return PhCreateString(L\"MASM\");\n    case CV_CFL_PASCAL:\n        return PhCreateString(L\"PASCAL\");\n    case CV_CFL_BASIC:\n        return PhCreateString(L\"BASIC\");\n    case CV_CFL_COBOL:\n        return PhCreateString(L\"COBOL\");\n    case CV_CFL_LINK:\n        return PhCreateString(L\"LINK\");\n    case CV_CFL_CVTRES:\n        return PhCreateString(L\"CVTRES\");\n    case CV_CFL_CVTPGD:\n        return PhCreateString(L\"CVTPGD\");\n    case CV_CFL_CSHARP:\n        return PhCreateString(L\"C#\");\n    case CV_CFL_VB:\n        return PhCreateString(L\"Visual Basic\");\n    case CV_CFL_ILASM:\n        return PhCreateString(L\"ILASM (CLR)\");\n    case CV_CFL_JAVA:\n        return PhCreateString(L\"JAVA\");\n    case CV_CFL_JSCRIPT:\n        return PhCreateString(L\"JSCRIPT\");\n    case CV_CFL_MSIL:\n        return PhCreateString(L\"MSIL\");\n    case CV_CFL_HLSL:\n        return PhCreateString(L\"HLSL (High Level Shader Language)\");\n    case CV_CFL_OBJC:\n        return PhCreateString(L\"Objective-C\");\n    case CV_CFL_OBJCXX:\n        return PhCreateString(L\"Objective-C++\");\n    case CV_CFL_SWIFT:\n        return PhCreateString(L\"SWIFT\");\n    case CV_CFL_ALIASOBJ:\n        return PhCreateString(L\"ALIASOBJ\");\n    case CV_CFL_RUST:\n        return PhCreateString(L\"RUST\");\n    }\n\n    return NULL;\n}\n\n// SymTagCompilandDetails : https://learn.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/compilanddetails\n// SymTagFunction: https://learn.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/function-debug-interface-access-sdk\nPPH_STRING PhGetDiaSymbolExtraInformation(\n    _In_ IDiaSymbol* Symbol\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    BOOL symbolBoolean = FALSE;\n    ULONG64 symbolValue = 0;\n\n    PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n    if (IDiaSymbol_get_isStripped(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Stripped, \");\n    }\n\n    if (IDiaSymbol_get_isStatic(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Static, \");\n    }\n\n    if (IDiaSymbol_get_inlSpec(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Inline, \");\n    }\n\n    if (IDiaSymbol_get_isHotpatchable(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Hotpatchable, \");\n    }\n\n    if (IDiaSymbol_get_hasAlloca(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Has Alloca, \");\n    }\n\n    if (IDiaSymbol_get_hasInlAsm(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Has Inline ASM, \");\n    }\n\n    if (IDiaSymbol_get_hasSetJump(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Has SetJump, \");\n    }\n\n    if (IDiaSymbol_get_hasLongJump(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Has LongJump, \");\n    }\n\n    if (IDiaSymbol_get_hasSEH(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Has SEH, \");\n    }\n\n    if (IDiaSymbol_get_hasSecurityChecks(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Has SecurityChecks, \");\n    }\n\n    if (IDiaSymbol_get_hasControlFlowCheck(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"Has CFG, \");\n    }\n\n    if (IDiaSymbol_get_isOptimizedForSpeed(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"OptimizedForSpeed, \");\n    }\n\n    if (IDiaSymbol_get_isPGO(Symbol, &symbolBoolean) == S_OK && symbolBoolean)\n    {\n        PhAppendStringBuilder2(&stringBuilder, L\"PGO, \");\n    }\n\n    if (IDiaSymbol_get_exceptionHandlerVirtualAddress(Symbol, &symbolValue) == S_OK && symbolValue)\n    {\n        PhAppendFormatStringBuilder(&stringBuilder, L\"Has exception handler (0x%p), \", (PVOID)symbolValue);\n    }\n\n    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n_Success_(return)\nBOOLEAN PhGetDiaSymbolInformation(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PVOID Address,\n    _Out_ PPH_DIA_SYMBOL_INFORMATION SymbolInformation\n    )\n{\n    PH_DIA_SYMBOL_INFORMATION symbolInfo = { 0 };\n    PVOID baseAddress;\n    IDiaSession* datasession;\n    IDiaSymbol* symbol;\n\n    baseAddress = PhGetModuleFromAddress(SymbolProvider, Address, NULL);\n\n    if (baseAddress == 0)\n        return FALSE;\n\n    if (!PhGetSymbolProviderDiaSession(SymbolProvider, baseAddress, &datasession))\n        return FALSE;\n\n    if (IDiaSession_findSymbolByVA(datasession, (ULONGLONG)Address, SymTagFunction, &symbol) == S_OK)\n    {\n        BSTR symbolUndecoratedName = NULL;\n        ULONG64 symbolLength = 0;\n\n        if (IDiaSymbol_get_length(symbol, &symbolLength) == S_OK)\n        {\n            symbolInfo.FunctionLength = (ULONG)symbolLength;\n            symbolInfo.SymbolLangugage = PhGetDiaSymbolLineInformation(\n                datasession,\n                symbol,\n                Address,\n                (ULONG)symbolLength\n                );\n        }\n\n        if (IDiaSymbol_get_undecoratedName(symbol, &symbolUndecoratedName) == S_OK)\n        {\n            symbolInfo.UndecoratedName = PhCreateString(symbolUndecoratedName);\n            PhSymbolProviderFreeDiaString(symbolUndecoratedName);\n        }\n\n        symbolInfo.SymbolInformation = PhGetDiaSymbolExtraInformation(symbol);\n    }\n\n    IDiaSession_Release(datasession);\n\n    memcpy(SymbolInformation, &symbolInfo, sizeof(PH_DIA_SYMBOL_INFORMATION));\n\n    return TRUE;\n}\n\nVOID PhUnregisterSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider\n    )\n{\n    PhpUnregisterSymbolProvider(SymbolProvider);\n}\n"
  },
  {
    "path": "phlib/symprv_std.cpp",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2023\n *\n */\n\n#include <ph.h>\n#include <ref.h>\n#include <refp.h>\n\n#include <stacktrace>\n\nusing namespace std;\n\nEXTERN_C VOID PhPrintCurrentStacktrace(\n    VOID\n    )\n{\n#ifdef DEBUG\n    stacktrace trace = stacktrace::current(1);\n    string result = to_string(trace);\n\n    OutputDebugStringA(result.c_str());\n#endif\n}\n\nEXTERN_C PPH_STRING PhGetStacktraceAsString(\n    VOID\n    )\n{\n#ifdef DEBUG\n    stacktrace trace = stacktrace::current(1);\n    string result = to_string(trace);\n\n    return PhConvertUtf8ToUtf16(result.c_str());\n#else\n    return NULL;\n#endif\n}\n\nEXTERN_C PPH_STRING PhGetStacktraceSymbolFromAddress(\n    _In_ PVOID Address\n    )\n{\n#ifdef DEBUG\n    string result;\n\n    __std_stacktrace_address_to_string(\n        Address,\n        &result,\n        _Stacktrace_string_fill_impl\n        );\n\n    return PhConvertUtf8ToUtf16(result.c_str());\n#else\n    return NULL;\n#endif\n}\n\nEXTERN_C PPH_STRING PhGetObjectTypeStacktraceToString(\n    _In_ PVOID Object\n    )\n{\n#ifdef DEBUG\n    PPH_OBJECT_HEADER objectHeader = PhObjectToObjectHeader(Object);\n    string result;\n\n    __std_stacktrace_to_string(\n        objectHeader->StackBackTrace,\n        ARRAYSIZE(objectHeader->StackBackTrace),\n        &result,\n        _Stacktrace_string_fill_impl\n        );\n\n    return PhConvertUtf8ToUtf16(result.c_str());\n#else\n    return NULL;\n#endif\n}\n"
  },
  {
    "path": "phlib/sync.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2010-2015\n *\n */\n\n/*\n * This file contains code for several synchronization objects.\n *\n * Event. This is a lightweight notification event object that does not create a kernel event object\n * until needed. Additionally, the kernel event object is automatically freed when no longer needed.\n * Note that PhfResetEvent is NOT thread-safe.\n *\n * Barrier. This is a non-traditional implementation of a barrier, built on the wake event object. I\n * have identified three types of participants in this process:\n * 1. The slaves, who wait for the master to release them. This is the main mechanism through which\n *    the threads are synchronized.\n * 2. The master, who is the last thread to wait on the barrier. This thread triggers the waking\n *    process, and waits until all slaves have woken.\n * 3. The observers, who are simply threads which were slaves before, were woken, and have tried to\n *    wait on the barrier again before all other slaves have woken.\n *\n * Rundown protection. This object allows a thread to wait until all other threads have finished\n * using a particular resource before freeing the resource.\n *\n * Init-once. This is a lightweight one-time initialization mechanism which uses the event object\n * for any required blocking. The overhead is very small - only a single inlined comparison.\n */\n\n#include <phbase.h>\n\n/**\n * Initializes an event object.\n *\n * \\param Event A pointer to an event object.\n */\nVOID FASTCALL PhfInitializeEvent(\n    _Out_ PPH_EVENT Event\n    )\n{\n    Event->Value = PH_EVENT_REFCOUNT_INC;\n    WritePointerRelease(&Event->EventHandle, NULL);\n}\n\n/**\n * Dereferences the event object used by an event.\n *\n * \\param Event A pointer to an event object.\n * \\param EventHandle The current value of the event object.\n */\nFORCEINLINE VOID PhpDereferenceEvent(\n    _Inout_ PPH_EVENT Event,\n    _In_opt_ HANDLE EventHandle\n    )\n{\n    ULONG_PTR value;\n\n    value = _InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, -PH_EVENT_REFCOUNT_INC);\n\n    // See if the reference count has become 0.\n    if (((value >> PH_EVENT_REFCOUNT_SHIFT) & PH_EVENT_REFCOUNT_MASK) - 1 == 0)\n    {\n        if (EventHandle)\n        {\n            NtClose(EventHandle);\n            Event->EventHandle = NULL;\n        }\n    }\n}\n\n/**\n * References the event object used by an event.\n *\n * \\param Event A pointer to an event object.\n */\nFORCEINLINE VOID PhpReferenceEvent(\n    _Inout_ PPH_EVENT Event\n    )\n{\n    _InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, PH_EVENT_REFCOUNT_INC);\n}\n\n/**\n * Sets an event object. Any threads waiting on the event will be released.\n *\n * \\param Event A pointer to an event object.\n */\nVOID FASTCALL PhfSetEvent(\n    _Inout_ PPH_EVENT Event\n    )\n{\n    // Only proceed if the event isn't set already.\n    if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&Event->Value, PH_EVENT_SET_SHIFT))\n    {\n        HANDLE eventHandle;\n\n        eventHandle = ReadPointerAcquire(&Event->EventHandle);\n\n        if (eventHandle)\n        {\n            NtSetEvent(eventHandle, NULL);\n        }\n\n        PhpDereferenceEvent(Event, eventHandle);\n    }\n}\n\n/**\n * Waits for an event object to be set.\n *\n * \\param Event A pointer to an event object.\n * \\param Timeout The timeout value.\n *\n * \\return TRUE if the event object was set before the timeout period expired, otherwise FALSE.\n *\n * \\remarks To test the event, use PhTestEvent() instead of using a timeout of zero.\n */\nBOOLEAN FASTCALL PhfWaitForEvent(\n    _Inout_ PPH_EVENT Event,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    BOOLEAN result;\n    ULONG_PTR value;\n    HANDLE eventHandle;\n\n    value = ReadULongPtrAcquire(&Event->Value);\n\n    // Shortcut: if the event is set, return immediately.\n    if (value & PH_EVENT_SET)\n        return TRUE;\n\n    // Shortcut: if the timeout is 0, return immediately if the event isn't set.\n    if (Timeout && Timeout->QuadPart == 0)\n        return FALSE;\n\n    // Prevent the event from being invalidated.\n    PhpReferenceEvent(Event);\n\n    eventHandle = ReadPointerAcquire(&Event->EventHandle);\n\n    if (!eventHandle)\n    {\n        OBJECT_ATTRIBUTES objectAttributes;\n        InitializeObjectAttributes(&objectAttributes, NULL, OBJ_EXCLUSIVE, NULL, NULL);\n        NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, &objectAttributes, NotificationEvent, FALSE);\n        assert(eventHandle);\n\n        // Try to set the event handle to our event.\n        if (_InterlockedCompareExchangePointer(\n            &Event->EventHandle,\n            eventHandle,\n            NULL\n            ) != NULL)\n        {\n            // Someone else set the event before we did.\n            NtClose(eventHandle);\n            eventHandle = ReadPointerAcquire(&Event->EventHandle);\n        }\n    }\n\n    // Essential: check the event one last time to see if it is set.\n    if (!(ReadULongPtrAcquire(&Event->Value) & PH_EVENT_SET))\n    {\n        result = NtWaitForSingleObject(eventHandle, FALSE, Timeout) == STATUS_WAIT_0;\n    }\n    else\n    {\n        result = TRUE;\n    }\n\n    PhpDereferenceEvent(Event, eventHandle);\n\n    return result;\n}\n\n/**\n * Resets an event's state.\n *\n * \\param Event A pointer to an event object.\n *\n * \\remarks This function is not thread-safe. Make sure no other threads are using the event when\n * you call this function.\n */\nVOID FASTCALL PhfResetEvent(\n    _Inout_ PPH_EVENT Event\n    )\n{\n    //assert(!Event->EventHandle);\n\n    if (PhTestEvent(Event))\n    {\n        WriteULongPtrRelease(&Event->Value, PH_EVENT_REFCOUNT_INC);\n    }\n}\n\nVOID FASTCALL PhfInitializeBarrier(\n    _Out_ PPH_BARRIER Barrier,\n    _In_ ULONG_PTR Target\n    )\n{\n    Barrier->Value = Target << PH_BARRIER_TARGET_SHIFT;\n    PhInitializeWakeEvent(&Barrier->WakeEvent);\n}\n\nFORCEINLINE VOID PhpBlockOnBarrier(\n    _Inout_ PPH_BARRIER Barrier,\n    _In_ ULONG Role,\n    _In_ BOOLEAN Spin\n    )\n{\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n    ULONG_PTR cancel;\n\n    PhQueueWakeEvent(&Barrier->WakeEvent, &waitBlock);\n\n    cancel = 0;\n\n    switch (Role)\n    {\n    case PH_BARRIER_MASTER:\n        cancel = ((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) == 1;\n        break;\n    case PH_BARRIER_SLAVE:\n        cancel = Barrier->Value & PH_BARRIER_WAKING;\n        break;\n    case PH_BARRIER_OBSERVER:\n        cancel = !(Barrier->Value & PH_BARRIER_WAKING);\n        break;\n    default:\n        ASSUME_NO_DEFAULT;\n    }\n\n    if (cancel)\n    {\n        PhSetWakeEvent(&Barrier->WakeEvent, &waitBlock);\n        return;\n    }\n\n    PhWaitForWakeEvent(&Barrier->WakeEvent, &waitBlock, Spin, NULL);\n}\n\n/**\n * Waits until all threads are blocking on the barrier, and resets the state of the barrier.\n *\n * \\param Barrier A barrier.\n * \\param Spin TRUE to spin on the barrier before blocking, FALSE to block immediately.\n *\n * \\return TRUE for an unspecified thread after each phase, and FALSE for all other threads.\n *\n * \\remarks By checking the return value of the function, in each phase an action can be performed\n * exactly once. This could, for example, involve merging the results of calculations.\n */\nBOOLEAN FASTCALL PhfWaitForBarrier(\n    _Inout_ PPH_BARRIER Barrier,\n    _In_ BOOLEAN Spin\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR count;\n    ULONG_PTR target;\n\n    value = ReadULongPtrAcquire(&Barrier->Value);\n\n    while (TRUE)\n    {\n        if (!(value & PH_BARRIER_WAKING))\n        {\n            count = (value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK;\n            target = (value >> PH_BARRIER_TARGET_SHIFT) & PH_BARRIER_TARGET_MASK;\n            assert(count != target);\n\n            count++;\n\n            if (count != target)\n                newValue = value + PH_BARRIER_COUNT_INC;\n            else\n                newValue = value + PH_BARRIER_COUNT_INC + PH_BARRIER_WAKING;\n\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&Barrier->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n            {\n                if (count != target)\n                {\n                    // Wait for the master signal (the last thread to reach the barrier).\n                    // Once we get it, decrement the count to allow the master to continue.\n\n                    do\n                    {\n                        PhpBlockOnBarrier(Barrier, PH_BARRIER_SLAVE, Spin);\n                    } while (!(Barrier->Value & PH_BARRIER_WAKING));\n\n                    value = _InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -PH_BARRIER_COUNT_INC);\n\n                    if (((value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) - 1 == 1)\n                    {\n                        PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for the master\n                    }\n\n                    return FALSE;\n                }\n                else\n                {\n                    // We're the last one to reach the barrier, so we become the master.\n                    // Wake the slaves and wait for them to decrease the count to 1. This is so that\n                    // we know the slaves have woken and we don't clear the waking bit before they\n                    // wake.\n\n                    PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for slaves\n\n                    do\n                    {\n                        PhpBlockOnBarrier(Barrier, PH_BARRIER_MASTER, Spin);\n                    } while (((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) != 1);\n\n                    _InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -(PH_BARRIER_WAKING + PH_BARRIER_COUNT_INC));\n                    PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for observers\n\n                    return TRUE;\n                }\n            }\n        }\n        else\n        {\n            // We're too early; other threads are still waking. Wait for them to finish.\n\n            PhpBlockOnBarrier(Barrier, PH_BARRIER_OBSERVER, Spin);\n            newValue = Barrier->Value;\n        }\n\n        value = newValue;\n    }\n}\n\nVOID FASTCALL PhfInitializeRundownProtection(\n    _Out_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    Protection->Value = 0;\n}\n\nBOOLEAN FASTCALL PhfAcquireRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    // Increment the reference count only if rundown has not started.\n\n    while (TRUE)\n    {\n        value = ReadULongPtrAcquire(&Protection->Value);\n\n        if (value & PH_RUNDOWN_ACTIVE)\n            return FALSE;\n\n        if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n            (PVOID *)&Protection->Value,\n            (PVOID)(value + PH_RUNDOWN_REF_INC),\n            (PVOID)value\n            ) == value)\n            return TRUE;\n    }\n}\n\nVOID FASTCALL PhfReleaseRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    while (TRUE)\n    {\n        value = ReadULongPtrAcquire(&Protection->Value);\n\n        if (value & PH_RUNDOWN_ACTIVE)\n        {\n            PPH_RUNDOWN_WAIT_BLOCK waitBlock;\n\n            // Since rundown is active, the reference count has been moved to the waiter's wait\n            // block. If we are the last user, we must wake up the waiter.\n\n            waitBlock = (PPH_RUNDOWN_WAIT_BLOCK)(value & ~PH_RUNDOWN_ACTIVE);\n\n            if (_InterlockedDecrementPointer(&waitBlock->Count) == 0)\n            {\n                PhSetEvent(&waitBlock->WakeEvent);\n            }\n\n            break;\n        }\n        else\n        {\n            // Decrement the reference count normally.\n\n            if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&Protection->Value,\n                (PVOID)(value - PH_RUNDOWN_REF_INC),\n                (PVOID)value\n                ) == value)\n                break;\n        }\n    }\n}\n\nVOID FASTCALL PhfWaitForRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR count;\n    PH_RUNDOWN_WAIT_BLOCK waitBlock;\n    BOOLEAN waitBlockInitialized;\n\n    // Fast path. If the reference count is 0 or rundown has already been completed, return.\n    value = (ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&Protection->Value,\n        (PVOID)PH_RUNDOWN_ACTIVE,\n        (PVOID)0\n        );\n\n    if (value == 0 || value == PH_RUNDOWN_ACTIVE)\n        return;\n\n    waitBlockInitialized = FALSE;\n\n    while (TRUE)\n    {\n        value = ReadULongPtrAcquire(&Protection->Value);\n        count = value >> PH_RUNDOWN_REF_SHIFT;\n\n        // Initialize the wait block if necessary.\n        if (count != 0 && !waitBlockInitialized)\n        {\n            PhInitializeEvent(&waitBlock.WakeEvent);\n            waitBlockInitialized = TRUE;\n        }\n\n        // Save the existing reference count.\n        waitBlock.Count = count;\n\n        if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n            (PVOID *)&Protection->Value,\n            (PVOID)((ULONG_PTR)&waitBlock | PH_RUNDOWN_ACTIVE),\n            (PVOID)value\n            ) == value)\n        {\n            if (count != 0)\n                PhWaitForEvent(&waitBlock.WakeEvent, NULL);\n\n            break;\n        }\n    }\n}\n\nVOID FASTCALL PhfInitializeInitOnce(\n    _Out_ PPH_INITONCE InitOnce\n    )\n{\n    PhInitializeEvent(&InitOnce->Event);\n}\n\nBOOLEAN FASTCALL PhfBeginInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    )\n{\n    if (!_InterlockedBitTestAndSetPointer(&InitOnce->Event.Value, PH_INITONCE_INITIALIZING_SHIFT))\n        return TRUE;\n\n    PhWaitForEvent(&InitOnce->Event, NULL);\n\n    return FALSE;\n}\n\nVOID FASTCALL PhfEndInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    )\n{\n    PhSetEvent(&InitOnce->Event);\n}\n"
  },
  {
    "path": "phlib/theme.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2018-2023\n *\n */\n\n#include <ph.h>\n#include <guisup.h>\n#include <emenu.h>\n#include <treenew.h>\n#include <mapldr.h>\n\n#include <dwmapi.h>\n#include <vsstyle.h>\n#include <vssym32.h>\n\ntypedef struct _PHP_THEME_WINDOW_TAB_CONTEXT\n{\n    WNDPROC DefaultWindowProc;\n    BOOLEAN MouseActive;\n    POINT CursorPos;\n} PHP_THEME_WINDOW_TAB_CONTEXT, *PPHP_THEME_WINDOW_TAB_CONTEXT;\n\ntypedef struct _PHP_THEME_WINDOW_STATUSBAR_CONTEXT\n{\n    WNDPROC DefaultWindowProc;\n\n    struct\n    {\n       BOOLEAN Flags;\n       union\n       {\n            BOOLEAN NonMouseActive : 1;\n            BOOLEAN MouseActive : 1;\n            BOOLEAN HotTrack : 1;\n            BOOLEAN Hot : 1;\n            BOOLEAN Spare : 4;\n       };\n    };\n\n    HTHEME ThemeHandle;\n    POINT CursorPos;\n\n    HDC BufferedDc;\n    HBITMAP BufferedOldBitmap;\n    HBITMAP BufferedBitmap;\n    RECT BufferedContextRect;\n} PHP_THEME_WINDOW_STATUSBAR_CONTEXT, *PPHP_THEME_WINDOW_STATUSBAR_CONTEXT;\n\ntypedef struct _PHP_THEME_WINDOW_COMBO_CONTEXT\n{\n    WNDPROC DefaultWindowProc;\n    HTHEME ThemeHandle;\n    POINT CursorPos;\n} PHP_THEME_WINDOW_COMBO_CONTEXT, *PPHP_THEME_WINDOW_COMBO_CONTEXT;\n\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nBOOLEAN CALLBACK PhpThemeWindowEnumChildWindows(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID Context\n    );\n\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nBOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID Context\n    );\n\nLRESULT CALLBACK PhpThemeWindowSubclassProc(\n    _In_ HWND hWnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\nLRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\nLRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nLRESULT CALLBACK PhpThemeWindowListBoxControlSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nLRESULT CALLBACK PhpThemeWindowComboBoxControlSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nLRESULT CALLBACK PhpThemeWindowACLUISubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\n// Win10-RS5 (uxtheme.dll ordinal 132)\nBOOL (WINAPI *ShouldAppsUseDarkMode_I)(\n    VOID\n    ) = NULL;\n// Win10-RS5 (uxtheme.dll ordinal 138)\nBOOL (WINAPI *ShouldSystemUseDarkMode_I)(\n    VOID\n    ) = NULL;\n// Win10-RS5 (uxtheme.dll ordinal 136)\nBOOL (WINAPI* FlushMenuThemes_I)(\n    VOID\n    ) = NULL;\n\ntypedef enum _PreferredAppMode\n{\n    PreferredAppModeDisabled,\n    PreferredAppModeDarkOnDark,\n    PreferredAppModeDarkAlways\n} PreferredAppMode;\n\n// Win10-RS5 (uxtheme.dll ordinal 135)\n// Win10 build 17763: AllowDarkModeForApp(BOOL)\n// Win10 build 18334: SetPreferredAppMode(enum PreferredAppMode)\nBOOL (WINAPI* SetPreferredAppMode_I)(\n    _In_ PreferredAppMode AppMode\n    ) = NULL;\n\n// Win10-RS5 (uxtheme.dll ordinal 139)\nBOOL (WINAPI *IsDarkModeAllowedForApp_I)(\n    _In_ HWND WindowHandle\n    ) = NULL;\n\n//HRESULT (WINAPI* DwmGetColorizationColor_I)(\n//    _Out_ PULONG Colorization,\n//    _Out_ PBOOL OpaqueBlend\n//    );\n\n#ifdef DEBUG\n#define DEBUG_BEGINPAINT_RECT(WindowHandle, RcPaint) \\\n{\\\n    RECT rect;\\\n    GetClientRect((WindowHandle), &rect);\\\n    assert(EqualRect(&rect, &(RcPaint)));\\\n}\n#else\n#define DEBUG_BEGINPAINT_RECT(RcPaint)\n#endif\n\nBOOLEAN PhEnableThemeSupport = FALSE;\nBOOLEAN PhEnableThemeAcrylicSupport = FALSE;\nBOOLEAN PhEnableThemeAcrylicWindowSupport = FALSE;\nBOOLEAN PhEnableThemeNativeButtons = FALSE;\nBOOLEAN PhEnableThemeListviewBorder = FALSE;\nHBRUSH PhThemeWindowBackgroundBrush = NULL;\nCOLORREF PhThemeWindowForegroundColor = RGB(28, 28, 28);\nCOLORREF PhThemeWindowBackgroundColor = RGB(43, 43, 43);\nCOLORREF PhThemeWindowBackground2Color = RGB(65, 65, 65);\nCOLORREF PhThemeWindowHighlightColor = RGB(128, 128, 128);\nCOLORREF PhThemeWindowHighlight2Color = RGB(143, 143, 143);\nCOLORREF PhThemeWindowTextColor = RGB(255, 255, 255);\n\nVOID PhInitializeWindowTheme(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN EnableThemeSupport\n    )\n{\n    if (EnableThemeSupport && WindowsVersion >= WINDOWS_10_RS5)\n    {\n        static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n        if (PhBeginInitOnce(&initOnce))\n        {\n            if (WindowsVersion >= WINDOWS_10_19H2)\n            {\n                PVOID baseAddress;\n\n                if (!(baseAddress = PhGetLoaderEntryDllBaseZ(L\"uxtheme.dll\")))\n                    baseAddress = PhLoadLibrary(L\"uxtheme.dll\");\n\n                if (baseAddress)\n                {\n                    SetPreferredAppMode_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 135);\n                    //FlushMenuThemes_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 136);\n                }\n\n                if (SetPreferredAppMode_I)\n                {\n                    //switch (PhpThemeColorMode)\n                    //{\n                    //case 0: // New colors\n                    //    SetPreferredAppMode_I(PreferredAppModeDisabled);\n                    //    break;\n                    //case 1: // Old colors\n                    SetPreferredAppMode_I(PreferredAppModeDarkAlways);\n                }\n\n                //if (FlushMenuThemes_I)\n                //    FlushMenuThemes_I();\n            }\n\n            PhEndInitOnce(&initOnce);\n        }\n    }\n\n    PhInitializeThemeWindowFrame(WindowHandle);\n\n    if (!PhThemeWindowBackgroundBrush)\n    {\n        //HBRUSH brush = PhThemeWindowBackgroundBrush;\n        PhThemeWindowBackgroundBrush = CreateSolidBrush(PhThemeWindowBackgroundColor);\n        //if (brush) DeleteBrush(brush);\n    }\n\n    if (EnableThemeSupport)\n    {\n        WNDPROC defaultWindowProc;\n\n        defaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC);\n\n        if (defaultWindowProc != PhpThemeWindowSubclassProc)\n        {\n            PhSetWindowContext(WindowHandle, LONG_MAX, defaultWindowProc);\n            SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowSubclassProc);\n\n            if (WindowsVersion >= WINDOWS_10_RS5)\n            {\n                WCHAR windowClassName[MAX_PATH];\n                if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName)))\n                    windowClassName[0] = UNICODE_NULL;\n                if (PhEqualStringZ(windowClassName, L\"PhTreeNew\", FALSE) || PhEqualStringZ(windowClassName, WC_LISTVIEW, FALSE))\n                    PhAllowDarkModeForWindow(WindowHandle, TRUE);   // HACK for dynamically generated plugin tabs\n            }\n        }\n\n        PhEnumChildWindows(\n            WindowHandle,\n            PhpThemeWindowEnumChildWindows,\n            NULL\n            );\n\n        InvalidateRect(WindowHandle, NULL, FALSE); // HACK\n    }\n    else\n    {\n        //EnableThemeDialogTexture(WindowHandle, ETDT_ENABLETAB);\n    }\n}\n\nVOID PhInitializeWindowThemeEx(\n    _In_ HWND WindowHandle\n    )\n{\n    static CONST PH_STRINGREF keyPath = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Themes\\\\Personalize\");\n    HANDLE keyHandle;\n    BOOLEAN enableThemeSupport = FALSE;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_CURRENT_USER,\n        &keyPath,\n        0\n        )))\n    {\n        enableThemeSupport = !PhQueryRegistryUlongZ(keyHandle, L\"AppsUseLightTheme\");\n        NtClose(keyHandle);\n    }\n\n    PhInitializeWindowTheme(WindowHandle, enableThemeSupport);\n}\n\nVOID PhReInitializeWindowTheme(\n    _In_ HWND WindowHandle\n    )\n{\n    HWND currentWindow = NULL;\n\n    PhInitializeThemeWindowFrame(WindowHandle);\n\n    if (!PhEnableThemeSupport)\n        return;\n\n    if (!PhThemeWindowBackgroundBrush)\n    {\n        //HBRUSH brush = PhThemeWindowBackgroundBrush;\n        PhThemeWindowBackgroundBrush = CreateSolidBrush(PhThemeWindowBackgroundColor);\n        //if (brush) DeleteBrush(brush);\n    }\n\n    PhEnumChildWindows(\n        WindowHandle,\n        PhpReInitializeThemeWindowEnumChildWindows,\n        NULL\n        );\n\n    do\n    {\n        if (currentWindow = FindWindowEx(NULL, currentWindow, NULL, NULL))\n        {\n            ULONG processID = 0;\n\n            GetWindowThreadProcessId(currentWindow, &processID);\n\n            if (UlongToHandle(processID) == NtCurrentProcessId())\n            {\n                WCHAR windowClassName[MAX_PATH];\n\n                if (!GetClassName(currentWindow, windowClassName, RTL_NUMBER_OF(windowClassName)))\n                    windowClassName[0] = UNICODE_NULL;\n\n                //dprintf(\"PhReInitializeWindowTheme: %S\\r\\n\", windowClassName);\n\n                if (currentWindow != WindowHandle)\n                {\n                    if (PhEqualStringZ(windowClassName, L\"#32770\", FALSE))\n                    {\n                        PhEnumChildWindows(\n                            currentWindow,\n                            PhpReInitializeThemeWindowEnumChildWindows,\n                            NULL\n                            );\n                        //PhReInitializeWindowTheme(currentWindow);\n                    }\n\n                    InvalidateRect(currentWindow, NULL, TRUE);\n                }\n            }\n        }\n    } while (currentWindow);\n\n    InvalidateRect(WindowHandle, NULL, FALSE);\n}\n\n#define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19\n#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE\n#define DWMWA_USE_IMMERSIVE_DARK_MODE 20\n#endif\n#ifndef DWMWA_CAPTION_COLOR\n#define DWMWA_CAPTION_COLOR 35\n#endif\n#ifndef DWMWA_SYSTEMBACKDROP_TYPE\n#define DWMWA_SYSTEMBACKDROP_TYPE 38\n#endif\n\nHRESULT PhGetWindowThemeAttribute(\n    _In_ HWND WindowHandle,\n    _In_ ULONG AttributeId,\n    _Out_writes_bytes_(AttributeLength) PVOID Attribute,\n    _In_ ULONG AttributeLength\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static HRESULT (WINAPI* DwmGetWindowAttribute_I)(\n        _In_ HWND WindowHandle,\n        _In_ ULONG AttributeId,\n        _Out_writes_bytes_(AttributeLength) PVOID Attribute,\n        _In_ ULONG AttributeLength\n        );\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"dwmapi.dll\"))\n        {\n            DwmGetWindowAttribute_I = PhGetDllBaseProcedureAddress(baseAddress, \"DwmGetWindowAttribute\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!DwmGetWindowAttribute_I)\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    return DwmGetWindowAttribute_I(WindowHandle, AttributeId, Attribute, AttributeLength);\n}\n\nHRESULT PhSetWindowThemeAttribute(\n    _In_ HWND WindowHandle,\n    _In_ ULONG AttributeId,\n    _In_reads_bytes_(AttributeLength) PVOID Attribute,\n    _In_ ULONG AttributeLength\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static HRESULT (WINAPI* DwmSetWindowAttribute_I)(\n        _In_ HWND WindowHandle,\n        _In_ ULONG AttributeId,\n        _In_reads_bytes_(AttributeLength) PVOID Attribute,\n        _In_ ULONG AttributeLength\n        );\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"dwmapi.dll\"))\n        {\n            DwmSetWindowAttribute_I = PhGetDllBaseProcedureAddress(baseAddress, \"DwmSetWindowAttribute\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!DwmSetWindowAttribute_I)\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    return DwmSetWindowAttribute_I(WindowHandle, AttributeId, Attribute, AttributeLength);\n}\n\nVOID PhInitializeThemeWindowFrame(\n    _In_ HWND WindowHandle\n    )\n{\n    if (WindowsVersion >= WINDOWS_10_RS5)\n    {\n        BOOL boolAttribute;\n        ULONG ulongAttribute;\n\n        if (PhEnableThemeSupport)\n        {\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    {\n            //        boolAttribute = FALSE;\n            //\n            //        if (FAILED(PhSetWindowThemeAttribute(WindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE, &boolAttribute, sizeof(BOOL))))\n            //        {\n            //            PhSetWindowThemeAttribute(WindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, &boolAttribute, sizeof(BOOL));\n            //        }\n            //\n            //        //if (WindowsVersion > WINDOWS_11)\n            //        //{\n            //        //    PhSetWindowThemeAttribute(WindowHandle, DWMWA_CAPTION_COLOR, NULL, 0);\n            //        //}\n            //    }\n            //    break;\n            //case 1: // Old colors\n\n            boolAttribute = TRUE;\n\n            if (FAILED(PhSetWindowThemeAttribute(WindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE, &boolAttribute, sizeof(BOOL))))\n            {\n                PhSetWindowThemeAttribute(WindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, &boolAttribute, sizeof(BOOL));\n            }\n\n            if (WindowsVersion >= WINDOWS_11)\n            {\n                PhSetWindowThemeAttribute(WindowHandle, DWMWA_CAPTION_COLOR, &PhThemeWindowBackgroundColor, sizeof(COLORREF));\n            }\n        }\n\n        if (WindowsVersion >= WINDOWS_11_22H2)\n        {\n            ulongAttribute = 1;\n            PhSetWindowThemeAttribute(WindowHandle, DWMWA_SYSTEMBACKDROP_TYPE, &ulongAttribute, sizeof(ULONG));\n        }\n    }\n}\n\nVOID PhWindowThemeSetDarkMode(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN EnableDarkMode\n    )\n{\n    //BOOL boolAttribute;\n\n    if (EnableDarkMode && PhEnableThemeSupport) // ShouldAppsUseDarkMode_I()\n    {\n        PhSetControlTheme(WindowHandle, L\"DarkMode_Explorer\");\n        //PhSetControlTheme(WindowHandle, L\"DarkMode_ItemsView\");\n\n        //if (WindowsVersion >= WINDOWS_11)\n        //{\n        //    boolAttribute = TRUE;\n        //\n        //    if (FAILED(PhSetWindowThemeAttribute(WindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE, &boolAttribute, sizeof(BOOL))))\n        //    {\n        //        PhSetWindowThemeAttribute(WindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, &boolAttribute, sizeof(BOOL));\n        //    }\n        //}\n    }\n    else\n    {\n        PhSetControlTheme(WindowHandle, L\"Explorer\");\n        //PhSetControlTheme(WindowHandle, L\"ItemsView\");\n\n        //if (WindowsVersion >= WINDOWS_11)\n        //{\n        //    boolAttribute = FALSE;\n        //\n        //    if (FAILED(PhSetWindowThemeAttribute(WindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE, &boolAttribute, sizeof(BOOL))))\n        //    {\n        //        PhSetWindowThemeAttribute(WindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, &boolAttribute, sizeof(BOOL));\n        //    }\n        //}\n    }\n}\n\nHBRUSH PhWindowThemeControlColor(\n    _In_ HWND WindowHandle,\n    _In_ HDC Hdc,\n    _In_ HWND ChildWindowHandle,\n    _In_ LONG Type\n    )\n{\n    SetBkMode(Hdc, TRANSPARENT);\n\n    switch (Type)\n    {\n    case CTLCOLOR_EDIT:\n        {\n            if (PhEnableThemeSupport)\n            {\n                SetTextColor(Hdc, PhThemeWindowTextColor);\n                SetDCBrushColor(Hdc, RGB(60, 60, 60));\n                return PhGetStockBrush(DC_BRUSH);\n            }\n            else\n            {\n                SetTextColor(Hdc, GetSysColor(COLOR_WINDOWTEXT));\n                return GetSysColorBrush(COLOR_WINDOW);\n            }\n        }\n        break;\n    case CTLCOLOR_SCROLLBAR:\n        {\n            if (PhEnableThemeSupport)\n            {\n                SetDCBrushColor(Hdc, RGB(23, 23, 23));\n                return PhGetStockBrush(DC_BRUSH);\n            }\n            else\n            {\n                return GetSysColorBrush(COLOR_SCROLLBAR);\n            }\n        }\n        break;\n    case CTLCOLOR_MSGBOX:\n    case CTLCOLOR_LISTBOX:\n    case CTLCOLOR_BTN:\n    case CTLCOLOR_DLG:\n    case CTLCOLOR_STATIC:\n        {\n            if (PhEnableThemeSupport)\n            {\n                SetTextColor(Hdc, PhThemeWindowTextColor);\n                return PhThemeWindowBackgroundBrush;\n            }\n            else\n            {\n                SetTextColor(Hdc, GetSysColor(COLOR_WINDOWTEXT));\n                return GetSysColorBrush(COLOR_WINDOW);\n            }\n        }\n        break;\n    }\n\n    return (HBRUSH)DefWindowProc(WindowHandle, Type, (WPARAM)Hdc, (LPARAM)ChildWindowHandle);\n}\n\nVOID PhWindowThemeMainMenuBorder(\n    _In_ HWND WindowHandle\n    )\n{\n    if (GetMenu(WindowHandle))\n    {\n        RECT clientRect;\n        RECT windowRect;\n        HDC hdc;\n\n        if (!PhGetClientRect(WindowHandle, &clientRect))\n            return;\n        if (!PhGetWindowRect(WindowHandle, &windowRect))\n            return;\n\n        MapWindowPoints(WindowHandle, NULL, (PPOINT)&clientRect, 2);\n        PhOffsetRect(&clientRect, -windowRect.left, -windowRect.top);\n\n        // the rcBar is offset by the window rect (thanks to adzm) (dmex)\n        RECT rcAnnoyingLine = clientRect;\n        rcAnnoyingLine.bottom = rcAnnoyingLine.top;\n        rcAnnoyingLine.top--;\n\n        if (hdc = GetWindowDC(WindowHandle))\n        {\n            if (PhEnableThemeSupport)\n            {\n                FillRect(hdc, &rcAnnoyingLine, PhThemeWindowBackgroundBrush);\n            }\n            else\n            {\n                FillRect(hdc, &rcAnnoyingLine, (HBRUSH)(COLOR_WINDOW + 1));\n            }\n\n            ReleaseDC(WindowHandle, hdc);\n        }\n    }\n}\n\nVOID PhInitializeThemeWindowTabControl(\n    _In_ HWND TabControlWindow\n    )\n{\n    PPHP_THEME_WINDOW_TAB_CONTEXT context;\n\n    context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_TAB_CONTEXT));\n    context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(TabControlWindow, GWLP_WNDPROC);\n    context->CursorPos.x = LONG_MIN;\n    context->CursorPos.y = LONG_MIN;\n\n    PhSetWindowContext(TabControlWindow, LONG_MAX, context);\n    SetWindowLongPtr(TabControlWindow, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowTabControlWndSubclassProc);\n\n    InvalidateRect(TabControlWindow, NULL, FALSE);\n}\n\nVOID PhInitializeThemeWindowGroupBox(\n    _In_ HWND GroupBoxHandle\n    )\n{\n    WNDPROC groupboxWindowProc;\n\n    groupboxWindowProc = (WNDPROC)GetWindowLongPtr(GroupBoxHandle, GWLP_WNDPROC);\n    PhSetWindowContext(GroupBoxHandle, LONG_MAX, groupboxWindowProc);\n    SetWindowLongPtr(GroupBoxHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowGroupBoxSubclassProc);\n\n    InvalidateRect(GroupBoxHandle, NULL, FALSE);\n}\n\nVOID PhInitializeWindowThemeMainMenu(\n    _In_ HMENU MenuHandle\n    )\n{\n    MENUINFO menuInfo;\n\n    if (!PhEnableThemeSupport)\n        return;\n\n    memset(&menuInfo, 0, sizeof(MENUINFO));\n    menuInfo.cbSize = sizeof(MENUINFO);\n    menuInfo.fMask = MIM_BACKGROUND | MIM_APPLYTOSUBMENUS;\n    menuInfo.hbrBack = PhThemeWindowBackgroundBrush;\n\n    SetMenuInfo(MenuHandle, &menuInfo);\n}\n\nVOID PhInitializeWindowThemeListboxControl(\n    _In_ HWND ListBoxControl\n    )\n{\n    PPHP_THEME_WINDOW_STATUSBAR_CONTEXT context;\n\n    context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_STATUSBAR_CONTEXT));\n    context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(ListBoxControl, GWLP_WNDPROC);\n    context->CursorPos.x = LONG_MIN;\n    context->CursorPos.y = LONG_MIN;\n\n    PhSetWindowContext(ListBoxControl, LONG_MAX, context);\n    SetWindowLongPtr(ListBoxControl, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowListBoxControlSubclassProc);\n\n    InvalidateRect(ListBoxControl, NULL, FALSE);\n    SetWindowPos(ListBoxControl, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);\n}\n\nVOID PhInitializeWindowThemeComboboxControl(\n    _In_ HWND ComboBoxControl\n    )\n{\n    PPHP_THEME_WINDOW_COMBO_CONTEXT context;\n\n    context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_COMBO_CONTEXT));\n    context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(ComboBoxControl, GWLP_WNDPROC);\n    context->ThemeHandle = PhOpenThemeData(ComboBoxControl, VSCLASS_COMBOBOX, PhGetWindowDpi(ComboBoxControl));\n    context->CursorPos.x = LONG_MIN;\n    context->CursorPos.y = LONG_MIN;\n\n    PhSetWindowContext(ComboBoxControl, LONG_MAX, context);\n    SetWindowLongPtr(ComboBoxControl, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowComboBoxControlSubclassProc);\n\n    InvalidateRect(ComboBoxControl, NULL, FALSE);\n}\n\nVOID PhInitializeWindowThemeACLUI(\n    _In_ HWND ACLUIControl\n)\n{\n    PhSetWindowContext(ACLUIControl, LONG_MAX, (PVOID)GetWindowLongPtr(ACLUIControl, GWLP_WNDPROC));\n    SetWindowLongPtr(ACLUIControl, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowACLUISubclassProc);\n\n    InvalidateRect(ACLUIControl, NULL, FALSE);\n}\n\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nBOOLEAN CALLBACK PhpThemeWindowEnumChildWindows(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    WCHAR windowClassName[MAX_PATH];\n\n    PhEnumChildWindows(\n        WindowHandle,\n        PhpThemeWindowEnumChildWindows,\n        NULL\n        );\n\n    if (PhGetWindowContext(WindowHandle, LONG_MAX)) // HACK\n        return TRUE;\n\n    if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName)))\n        windowClassName[0] = UNICODE_NULL;\n\n    //dprintf(\"PhpThemeWindowEnumChildWindows: %S\\r\\n\", windowClassName);\n\n    if (PhEqualStringZ(windowClassName, L\"#32770\", TRUE))\n    {\n        PhInitializeWindowTheme(WindowHandle, TRUE);\n    }\n    else if (PhEqualStringZ(windowClassName, WC_BUTTON, FALSE))\n    {\n        LONG_PTR style = PhGetWindowStyle(WindowHandle);\n        if ((style & BS_GROUPBOX) == BS_GROUPBOX)\n        {\n            PhInitializeThemeWindowGroupBox(WindowHandle);\n        }\n        else    // apply theme for CheckBox, Radio (Dart Vanya)\n        {\n            PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n        }\n    }\n    else if (PhEqualStringZ(windowClassName, WC_TABCONTROL, FALSE))\n    {\n        PhInitializeThemeWindowTabControl(WindowHandle);\n    }\n    else if (PhEqualStringZ(windowClassName, WC_SCROLLBAR, FALSE))\n    {\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    PhWindowThemeSetDarkMode(WindowHandle, FALSE);\n            //    break;\n            //case 1: // Old colors\n            PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n        }\n    }\n    else if (PhEqualStringZ(windowClassName, WC_LISTVIEW, FALSE))\n    {\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            HWND tooltipWindow = ListView_GetToolTips(WindowHandle);\n\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    PhSetControlTheme(WindowHandle, L\"explorer\");\n            //    PhSetControlTheme(tooltipWindow, L\"\");\n            //    break;\n            //case 1: // Old colors\n            //PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n            PhAllowDarkModeForWindow(WindowHandle, TRUE);\n            PhSetControlTheme(WindowHandle, L\"DarkMode_ItemsView\");\n            PhWindowThemeSetDarkMode(tooltipWindow, TRUE);\n        }\n\n        if (PhEnableThemeListviewBorder)\n        {\n            PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER);\n            PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE);\n        }\n        else\n        {\n            PhSetWindowStyle(WindowHandle, WS_BORDER, 0);\n            PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0);\n        }\n\n        SetWindowPos(WindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);\n\n        //switch (PhpThemeColorMode)\n        //{\n        //case 0: // New colors\n        //    ListView_SetBkColor(WindowHandle, RGB(0xff, 0xff, 0xff));\n        //    ListView_SetTextBkColor(WindowHandle, RGB(0xff, 0xff, 0xff));\n        //    ListView_SetTextColor(WindowHandle, RGB(0x0, 0x0, 0x0));\n        //    break;\n        //case 1: // Old colors\n        ListView_SetBkColor(WindowHandle, PhThemeWindowBackgroundColor); // RGB(30, 30, 30)\n        ListView_SetTextBkColor(WindowHandle, PhThemeWindowBackgroundColor); // RGB(30, 30, 30)\n        ListView_SetTextColor(WindowHandle, PhThemeWindowTextColor);\n    }\n    else if (PhEqualStringZ(windowClassName, WC_TREEVIEW, FALSE))\n    {\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            HWND tooltipWindow = TreeView_GetToolTips(WindowHandle);\n\n            PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n            PhWindowThemeSetDarkMode(tooltipWindow, TRUE);\n        }\n\n        TreeView_SetBkColor(WindowHandle, PhThemeWindowBackgroundColor);// RGB(30, 30, 30));\n        //TreeView_SetTextBkColor(WindowHandle, RGB(30, 30, 30));\n        TreeView_SetTextColor(WindowHandle, PhThemeWindowTextColor);\n        //InvalidateRect(WindowHandle, NULL, FALSE);\n    }\n    else if (PhEqualStringZ(windowClassName, L\"RICHEDIT50W\", FALSE))\n    {\n        if (PhEnableThemeListviewBorder)\n            PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER);\n        else\n            PhSetWindowStyle(WindowHandle, WS_BORDER, 0);\n\n        SetWindowPos(WindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);\n\n        #define EM_SETBKGNDCOLOR (WM_USER + 67)\n        //switch (PhpThemeColorMode)\n        //{\n        //case 0: // New colors\n        //    SendMessage(WindowHandle, EM_SETBKGNDCOLOR, 0, RGB(0xff, 0xff, 0xff));\n        //    break;\n        //case 1: // Old colors\n        SendMessage(WindowHandle, EM_SETBKGNDCOLOR, 0, RGB(30, 30, 30));\n        PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n        //InvalidateRect(WindowHandle, NULL, FALSE);\n    }\n    else if (PhEqualStringZ(windowClassName, L\"PhTreeNew\", FALSE))\n    {\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            HWND tooltipWindow = TreeNew_GetTooltips(WindowHandle);\n\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    PhSetControlTheme(tooltipWindow, L\"\");\n            //    PhSetControlTheme(WindowHandle, L\"\");\n            //    break;\n            //case 1: // Old colors\n            PhWindowThemeSetDarkMode(tooltipWindow, TRUE);\n            PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n            PhAllowDarkModeForWindow(WindowHandle, TRUE);\n        }\n\n        if (PhEnableThemeListviewBorder)\n            PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE);\n        else\n            PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0);\n\n        SetWindowPos(WindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);\n\n        //switch (PhpThemeColorMode)\n        //{\n        //case 0: // New colors\n        //    TreeNew_ThemeSupport(WindowHandle, FALSE);\n        //    break;\n        //case 1: // Old colors\n        TreeNew_ThemeSupport(WindowHandle, TRUE);\n\n        //InvalidateRect(WindowHandle, NULL, TRUE);\n    }\n    else if (\n        PhEqualStringZ(windowClassName, WC_LISTBOX, FALSE) ||\n        PhEqualStringZ(windowClassName, L\"ComboLBox\", FALSE)\n        )\n    {\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    PhSetControlTheme(WindowHandle, L\"explorer\");\n            //    break;\n            //case 1: // Old colors\n            PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n        }\n\n        PhInitializeWindowThemeListboxControl(WindowHandle);\n    }\n    else if (PhEqualStringZ(windowClassName, WC_COMBOBOX, FALSE))\n    {\n        COMBOBOXINFO info = { sizeof(COMBOBOXINFO) };\n\n        if (SendMessage(WindowHandle, CB_GETCOMBOBOXINFO, 0, (LPARAM)&info))\n        {\n            //if (info.hwndItem)\n            //{\n            //    SendMessage(info.hwndItem, EM_SETMARGINS, EC_LEFTMARGIN, MAKELPARAM(0, 0));\n            //}\n\n            if (info.hwndList)\n            {\n                PhWindowThemeSetDarkMode(info.hwndList, TRUE);\n            }\n        }\n\n        //if ((PhGetWindowStyle(WindowHandle) & CBS_DROPDOWNLIST) != CBS_DROPDOWNLIST)\n        {\n            PhInitializeWindowThemeComboboxControl(WindowHandle);\n        }\n    }\n    else if (PhEqualStringZ(windowClassName, L\"CHECKLIST_ACLUI\", FALSE))\n    {\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    PhSetControlTheme(WindowHandle, L\"explorer\");\n            //    break;\n            //case 1: // Old colors\n            PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n        }\n\n        PhInitializeWindowThemeACLUI(WindowHandle);\n    }\n    else if (PhEqualStringZ(windowClassName, WC_EDIT, FALSE))\n    {\n        // Fix scrollbar on multiline edit (Dart Vanya)\n        if (PhGetWindowStyle(WindowHandle) & ES_MULTILINE)\n        {\n            PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n        }\n    }\n    else if (PhEqualStringZ(windowClassName, WC_LINK, FALSE))\n    {\n        // SysLink theme support (Dart Vanya)\n        PhAllowDarkModeForWindow(WindowHandle, TRUE);\n    }\n\n    return TRUE;\n}\n\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nBOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    WCHAR windowClassName[MAX_PATH];\n\n    PhEnumChildWindows(\n        WindowHandle,\n        PhpReInitializeThemeWindowEnumChildWindows,\n        NULL\n        );\n\n    if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName)))\n        windowClassName[0] = UNICODE_NULL;\n\n    if (PhEqualStringZ(windowClassName, WC_LISTVIEW, FALSE))\n    {\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    PhSetControlTheme(WindowHandle, L\"explorer\");\n            //    break;\n            //case 1: // Old colors\n            PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n        }\n\n        //switch (PhpThemeColorMode)\n        //{\n        //case 0: // New colors\n        //    ListView_SetBkColor(WindowHandle, RGB(0xff, 0xff, 0xff));\n        //    ListView_SetTextBkColor(WindowHandle, RGB(0xff, 0xff, 0xff));\n        //    ListView_SetTextColor(WindowHandle, RGB(0x0, 0x0, 0x0));\n        //    break;\n        //case 1: // Old colors\n        ListView_SetBkColor(WindowHandle, PhThemeWindowBackgroundColor); // RGB(30, 30, 30)\n        ListView_SetTextBkColor(WindowHandle, PhThemeWindowBackgroundColor); // RGB(30, 30, 30)\n        ListView_SetTextColor(WindowHandle, PhThemeWindowTextColor);\n    }\n    else if (PhEqualStringZ(windowClassName, WC_SCROLLBAR, FALSE))\n    {\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    PhSetControlTheme(WindowHandle, L\"\");\n            //    break;\n            //case 1: // Old colors\n            PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n        }\n    }\n    else if (PhEqualStringZ(windowClassName, L\"PhTreeNew\", FALSE))\n    {\n        //switch (PhpThemeColorMode)\n        //{\n        //case 0: // New colors\n        //    TreeNew_ThemeSupport(WindowHandle, FALSE);\n        //    PhSetControlTheme(WindowHandle, L\"\");\n        //    break;\n        //case 1: // Old colors\n        TreeNew_ThemeSupport(WindowHandle, TRUE);\n        PhWindowThemeSetDarkMode(WindowHandle, TRUE);\n    }\n    else if (PhEqualStringZ(windowClassName, WC_EDIT, FALSE))\n    {\n        SendMessage(WindowHandle, WM_THEMECHANGED, 0, 0); // searchbox.c\n    }\n\n    InvalidateRect(WindowHandle, NULL, TRUE);\n\n    return TRUE;\n}\n\nBOOLEAN PhThemeWindowDrawItem(\n    _In_ HWND WindowHandle,\n    _In_ PDRAWITEMSTRUCT DrawInfo\n    )\n{\n    BOOLEAN isGrayed = (DrawInfo->itemState & CDIS_GRAYED) == CDIS_GRAYED;\n    BOOLEAN isChecked = (DrawInfo->itemState & CDIS_CHECKED) == CDIS_CHECKED;\n    BOOLEAN isDisabled = (DrawInfo->itemState & CDIS_DISABLED) == CDIS_DISABLED;\n    BOOLEAN isSelected = (DrawInfo->itemState & CDIS_SELECTED) == CDIS_SELECTED;\n    //BOOLEAN isHighlighted = (DrawInfo->itemState & CDIS_HOT) == CDIS_HOT;\n    BOOLEAN isFocused = (DrawInfo->itemState & CDIS_FOCUS) == CDIS_FOCUS;\n    //BOOLEAN isGrayed = (DrawInfo->itemState & ODS_GRAYED) == ODS_GRAYED;\n    //BOOLEAN isChecked = (DrawInfo->itemState & ODS_CHECKED) == ODS_CHECKED;\n    //BOOLEAN isDisabled = (DrawInfo->itemState & ODS_DISABLED) == ODS_DISABLED;\n    //BOOLEAN isSelected = (DrawInfo->itemState & ODS_SELECTED) == ODS_SELECTED;\n    BOOLEAN isHighlighted = (DrawInfo->itemState & ODS_HOTLIGHT) == ODS_HOTLIGHT;\n\n    SetBkMode(DrawInfo->hDC, TRANSPARENT);\n\n    switch (DrawInfo->CtlType)\n    {\n    case ODT_MENU:\n        {\n            PPH_EMENU_ITEM menuItemInfo = (PPH_EMENU_ITEM)DrawInfo->itemData;\n            RECT rect = DrawInfo->rcItem;\n            LONG dpiValue = PhGetWindowDpi(WindowHandle);\n            ULONG drawTextFlags = DT_SINGLELINE | DT_NOCLIP;\n            //HFONT fontHandle;\n            //HFONT oldFont = NULL;\n\n            if (DrawInfo->itemState & ODS_NOACCEL)\n            {\n                drawTextFlags |= DT_HIDEPREFIX;\n            }\n\n            //if (fontHandle = PhCreateMessageFont(dpiValue))\n            //{\n            //    oldFont = SelectFont(DrawInfo->hDC, fontHandle);\n            //}\n            //\n            //FillRect(\n            //    DrawInfo->hDC,\n            //    &DrawInfo->rcItem,\n            //    CreateSolidBrush(RGB(0, 0, 0))\n            //    );\n            //SetTextColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff));\n\n            if (DrawInfo->itemState & ODS_HOTLIGHT)\n            {\n                SetTextColor(DrawInfo->hDC, PhThemeWindowTextColor);\n                SetDCBrushColor(DrawInfo->hDC, PhThemeWindowHighlightColor);\n                FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhGetStockBrush(DC_BRUSH));\n            }\n            else if (isDisabled)\n            {\n                SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_GRAYTEXT));\n                FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhThemeWindowBackgroundBrush);\n            }\n            else if (isSelected)\n            {\n                //switch (PhpThemeColorMode)\n                //{\n                //case 0: // New colors\n                //    SetTextColor(DrawInfo->hDC, PhThemeWindowTextColor);\n                //    SetDCBrushColor(DrawInfo->hDC, PhThemeWindowBackgroundColor);\n                //    break;\n\n                SetTextColor(DrawInfo->hDC, PhThemeWindowTextColor);\n                SetDCBrushColor(DrawInfo->hDC, PhThemeWindowHighlightColor);\n                FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhGetStockBrush(DC_BRUSH));\n            }\n            else\n            {\n                //switch (PhpThemeColorMode)\n                //{\n                //case 0: // New colors\n                //    SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_WINDOWTEXT));\n                //    SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff));\n                //    FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhGetStockBrush(DC_BRUSH));\n                //    break;\n\n                SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhThemeWindowBackgroundBrush);\n            }\n\n            if (isChecked)\n            {\n                static CONST PH_STRINGREF menuCheckText = PH_STRINGREF_INIT(L\"\\u2713\");\n                COLORREF oldTextColor;\n\n                //HFONT marlettFontHandle = CreateFont(\n                //    0, 0, 0, 0,\n                //    FW_DONTCARE,\n                //    FALSE,\n                //    FALSE,\n                //    FALSE,\n                //    DEFAULT_CHARSET,\n                //    OUT_OUTLINE_PRECIS,\n                //    CLIP_DEFAULT_PRECIS,\n                //    CLEARTYPE_QUALITY,\n                //    VARIABLE_PITCH,\n                //    L\"Arial Unicode MS\"\n                //    );\n\n                oldTextColor = SetTextColor(DrawInfo->hDC, PhThemeWindowTextColor);\n\n                DrawInfo->rcItem.left += PhGetDpi(8, dpiValue);\n                DrawInfo->rcItem.top += PhGetDpi(3, dpiValue);\n                DrawText(\n                    DrawInfo->hDC,\n                    menuCheckText.Buffer,\n                    (UINT)menuCheckText.Length / sizeof(WCHAR),\n                    &DrawInfo->rcItem,\n                    DT_VCENTER | DT_NOCLIP\n                    );\n                DrawInfo->rcItem.left -= PhGetDpi(8, dpiValue);\n                DrawInfo->rcItem.top -= PhGetDpi(3, dpiValue);\n\n                SetTextColor(DrawInfo->hDC, oldTextColor);\n            }\n\n            if (menuItemInfo->Flags & PH_EMENU_SEPARATOR)\n            {\n                //switch (PhpThemeColorMode)\n                //{\n                //case 0: // New colors\n                //    SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff));\n                //    FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhGetStockBrush(DC_BRUSH));\n                //    break;\n                //case 1: // Old colors\n                //SetDCBrushColor(DrawInfo->hDC, PhThemeWindowBackgroundColor); // PhThemeWindowForegroundColor\n                FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhThemeWindowBackgroundBrush);\n\n                //DrawInfo->rcItem.top += PhGetDpi(1, dpiValue);\n                //DrawInfo->rcItem.bottom -= PhGetDpi(2, dpiValue);\n                //DrawFocusRect(drawInfo->hDC, &drawInfo->rcItem);\n\n                // +5 font margin, +1 extra padding\n                //INT cxMenuCheck = GetSystemMetrics(SM_CXMENUCHECK) + (GetSystemMetrics(SM_CXEDGE) * 2) + 5 + 1;\n                INT cyEdge = PhGetSystemMetrics(SM_CYEDGE, dpiValue);\n                //\n                //SetRect(\n                //    &DrawInfo->rcItem,\n                //    DrawInfo->rcItem.left + cxMenuCheck, // 25\n                //    DrawInfo->rcItem.top + cyEdge,\n                //    DrawInfo->rcItem.right,\n                //    DrawInfo->rcItem.bottom - cyEdge\n                //    );\n\n                SetDCBrushColor(DrawInfo->hDC, RGB(0x5f, 0x5f, 0x5f));\n                SelectBrush(DrawInfo->hDC, PhGetStockBrush(DC_BRUSH));\n                PatBlt(DrawInfo->hDC, DrawInfo->rcItem.left, DrawInfo->rcItem.top + cyEdge, DrawInfo->rcItem.right - DrawInfo->rcItem.left, 1, PATCOPY);\n\n                //switch (PhpThemeColorMode)\n                //{\n                //case 0: // New colors\n                //    SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff));\n                //    FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhGetStockBrush(DC_BRUSH));\n                //    break;\n                //case 1: // Old colors\n                //    SetDCBrushColor(DrawInfo->hDC, RGB(78, 78, 78));\n                //    FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhGetStockBrush(DC_BRUSH));\n                //    break;\n                //}\n\n                //DrawEdge(drawInfo->hDC, &drawInfo->rcItem, BDR_RAISEDINNER, BF_TOP);\n            }\n            else\n            {\n                PH_STRINGREF part = { 0 };\n                PH_STRINGREF firstPart = { 0 };\n                PH_STRINGREF secondPart = { 0 };\n\n                PhInitializeStringRefLongHint(&part, menuItemInfo->Text);\n                PhSplitStringRefAtLastChar(&part, L'\\b', &firstPart, &secondPart);\n\n                //SetDCBrushColor(DrawInfo->hDC, PhThemeWindowForegroundColor);\n                //FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhGetStockBrush(DC_BRUSH));\n\n                if (menuItemInfo->Bitmap)\n                {\n                    HDC bufferDc;\n                    BLENDFUNCTION blendFunction;\n\n                    blendFunction.BlendOp = AC_SRC_OVER;\n                    blendFunction.BlendFlags = 0;\n                    blendFunction.SourceConstantAlpha = 255;\n                    blendFunction.AlphaFormat = AC_SRC_ALPHA;\n\n                    bufferDc = CreateCompatibleDC(DrawInfo->hDC);\n                    SelectBitmap(bufferDc, menuItemInfo->Bitmap);\n\n                    GdiAlphaBlend(\n                        DrawInfo->hDC,\n                        DrawInfo->rcItem.left + 4,\n                        DrawInfo->rcItem.top + 4,\n                        PhGetSystemMetrics(SM_CXSMICON, dpiValue),\n                        PhGetSystemMetrics(SM_CYSMICON, dpiValue),\n                        bufferDc,\n                        0,\n                        0,\n                        PhGetSystemMetrics(SM_CXSMICON, dpiValue),\n                        PhGetSystemMetrics(SM_CYSMICON, dpiValue),\n                        blendFunction\n                        );\n\n                    DeleteDC(bufferDc);\n                }\n\n                DrawInfo->rcItem.left += PhGetDpi(25, dpiValue);\n                DrawInfo->rcItem.right -= PhGetDpi(25, dpiValue);\n\n                if ((menuItemInfo->Flags & PH_EMENU_MAINMENU) == PH_EMENU_MAINMENU)\n                {\n                    if (firstPart.Length)\n                    {\n                        DrawText(\n                            DrawInfo->hDC,\n                            firstPart.Buffer,\n                            (UINT)firstPart.Length / sizeof(WCHAR),\n                            &DrawInfo->rcItem,\n                            DT_LEFT | DT_SINGLELINE | DT_CENTER | DT_VCENTER | drawTextFlags\n                            );\n                    }\n                }\n                else\n                {\n                    if (firstPart.Length)\n                    {\n                        DrawText(\n                            DrawInfo->hDC,\n                            firstPart.Buffer,\n                            (UINT)firstPart.Length / sizeof(WCHAR),\n                            &DrawInfo->rcItem,\n                            DT_LEFT | DT_VCENTER | drawTextFlags\n                            );\n                    }\n                }\n\n                if (secondPart.Length)\n                {\n                    DrawText(\n                        DrawInfo->hDC,\n                        secondPart.Buffer,\n                        (UINT)secondPart.Length / sizeof(WCHAR),\n                        &DrawInfo->rcItem,\n                        DT_RIGHT | DT_VCENTER | drawTextFlags\n                        );\n                }\n            }\n\n            //if (oldFont)\n            //{\n            //    SelectFont(DrawInfo->hDC, oldFont);\n            //}\n\n            if (menuItemInfo->Items && menuItemInfo->Items->Count && (menuItemInfo->Flags & PH_EMENU_MAINMENU) != PH_EMENU_MAINMENU)\n            {\n                HTHEME themeHandle;\n\n                if (themeHandle = PhOpenThemeData(DrawInfo->hwndItem, VSCLASS_MENU, dpiValue))\n                {\n                    //if (IsThemeBackgroundPartiallyTransparent(themeHandle, MENU_POPUPSUBMENU, isDisabled ? MSM_DISABLED : MSM_NORMAL))\n                    //    DrawThemeParentBackground(DrawInfo->hwndItem, DrawInfo->hDC, NULL);\n\n                    rect.left = rect.right - PhGetDpi(25, dpiValue);\n\n                    PhDrawThemeBackground(\n                        themeHandle,\n                        DrawInfo->hDC,\n                        MENU_POPUPSUBMENU,\n                        isDisabled ? MSM_DISABLED : MSM_NORMAL,\n                        &rect,\n                        NULL\n                        );\n\n                    PhCloseThemeData(themeHandle);\n                }\n            }\n\n            ExcludeClipRect(DrawInfo->hDC, rect.left, rect.top, rect.right, rect.bottom); // exclude last\n\n            //if (fontHandle)\n            //{\n            //    DeleteFont(fontHandle);\n            //}\n\n            return TRUE;\n        }\n    case ODT_COMBOBOX:\n        {\n            SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));\n            SetDCBrushColor(DrawInfo->hDC, PhThemeWindowForegroundColor);\n            FillRect(DrawInfo->hDC, &DrawInfo->rcItem, PhGetStockBrush(DC_BRUSH));\n\n            INT length = ComboBox_GetLBTextLen(DrawInfo->hwndItem, DrawInfo->itemID);\n\n            if (length == CB_ERR)\n                break;\n\n            if (length < MAX_PATH)\n            {\n                WCHAR comboText[MAX_PATH] = L\"\";\n\n                if (ComboBox_GetLBText(DrawInfo->hwndItem, DrawInfo->itemID, comboText) == CB_ERR)\n                    break;\n\n                DrawText(\n                    DrawInfo->hDC,\n                    comboText,\n                    (UINT)PhCountStringZ(comboText),\n                    &DrawInfo->rcItem,\n                    DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE\n                    );\n            }\n\n            return TRUE;\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhThemeWindowMeasureItem(\n    _In_ HWND WindowHandle,\n    _In_ PMEASUREITEMSTRUCT DrawInfo\n    )\n{\n    if (DrawInfo->CtlType == ODT_MENU)\n    {\n        PPH_EMENU_ITEM menuItemInfo = (PPH_EMENU_ITEM)DrawInfo->itemData;\n        LONG dpiValue = PhGetWindowDpi(WindowHandle);\n\n        DrawInfo->itemWidth = PhGetDpi(100, dpiValue);\n        DrawInfo->itemHeight = PhGetDpi(100, dpiValue);\n\n        if ((menuItemInfo->Flags & PH_EMENU_SEPARATOR) == PH_EMENU_SEPARATOR)\n        {\n            DrawInfo->itemHeight = PhGetSystemMetrics(SM_CYMENU, dpiValue) >> 2;\n        }\n        else if (menuItemInfo->Text)\n        {\n            //HFONT fontHandle;\n            HDC hdc;\n\n            //fontHandle = PhCreateMessageFont(dpiValue);\n\n            if (hdc = GetDC(WindowHandle))\n            {\n                PCWSTR text;\n                SIZE_T textCount;\n                SIZE textSize;\n                //HFONT oldFont = NULL;\n                INT cyborder = PhGetSystemMetrics(SM_CYBORDER, dpiValue);\n                INT cymenu = PhGetSystemMetrics(SM_CYMENU, dpiValue);\n\n                text = menuItemInfo->Text;\n                textCount = PhCountStringZ(text);\n\n                //if (fontHandle)\n                //{\n                //    oldFont = SelectFont(hdc, fontHandle);\n                //}\n\n                if ((menuItemInfo->Flags & PH_EMENU_MAINMENU) == PH_EMENU_MAINMENU)\n                {\n                    if (GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize))\n                    {\n                        DrawInfo->itemWidth = textSize.cx + (cyborder * 2);\n                        DrawInfo->itemHeight = cymenu + (cyborder * 2) + 1;\n                    }\n                }\n                else\n                {\n                    if (GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize))\n                    {\n                        DrawInfo->itemWidth = textSize.cx + (cyborder * 2) + PhGetDpi(90, dpiValue); // HACK\n                        DrawInfo->itemHeight = cymenu + (cyborder * 2) + PhGetDpi(1, dpiValue);\n                    }\n                }\n\n                //if (oldFont)\n                //{\n                //    SelectFont(hdc, oldFont);\n                //}\n\n                ReleaseDC(WindowHandle, hdc);\n            }\n\n            //if (fontHandle)\n            //{\n            //    DeleteFont(fontHandle);\n            //}\n        }\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n// TODO: Use imagelist instead of loading images from uxtheme.\n//HIMAGELIST CreateTreeViewCheckBoxes(HWND hwnd, int cx, int cy)\n//{\n//    const int frames = 6;\n//\n//    // Get a DC for our window.\n//    HDC hdcScreen = GetDC(hwnd);\n//\n//    // Get a button theme for the window, if available.\n//    HTHEME htheme = OpenThemeData(hwnd, L\"button\");\n//\n//    // If there is a theme, then ask it for the size\n//    // of a checkbox and use that size.\n//    if (htheme)\n//    {\n//        SIZE size;\n//        PhGetThemePartSize(htheme, hdcScreen, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, NULL, TS_DRAW, &size);\n//        cx = size.cx;\n//        cy = size.cy;\n//    }\n//\n//    // Create a 32bpp bitmap that holds the desired number of frames.\n//    BITMAPINFO bi = { sizeof(BITMAPINFOHEADER), cx * frames, cy, 1, 32 };\n//    void* p;\n//    HBITMAP hbmCheckboxes = CreateDIBSection(hdcScreen, &bi, DIB_RGB_COLORS, &p, NULL, 0);\n//\n//    // Create a compatible memory DC.\n//    HDC hdcMem = CreateCompatibleDC(hdcScreen);\n//\n//    // Select our bitmap into it so we can draw to it.\n//    HBITMAP hbmOld = SelectBitmap(hdcMem, hbmCheckboxes);\n//\n//    // Set up the rectangle into which we do our drawing.\n//    RECT rc = { 0, 0, cx, cy };\n//\n//    // Frame 0 is not used. Draw nothing.\n//    PhOffsetRect(&rc, cx, 0);\n//\n//    if (htheme)\n//    {\n//        // Frame 1: Unchecked.\n//        PhDrawThemeBackground(htheme, hdcMem, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, &rc, NULL);\n//        PhOffsetRect(&rc, cx, 0);\n//\n//        // Frame 2: Checked.\n//        PhDrawThemeBackground(htheme, hdcMem, BP_CHECKBOX, CBS_CHECKEDNORMAL, &rc, NULL);\n//        PhOffsetRect(&rc, cx, 0);\n//\n//        // Frame 3: Indeterminate.\n//        PhDrawThemeBackground(htheme, hdcMem, BP_CHECKBOX, CBS_MIXEDNORMAL, &rc, NULL);\n//        PhOffsetRect(&rc, cx, 0);\n//\n//        // Frame 4: Disabled, unchecked.\n//        PhDrawThemeBackground(htheme, hdcMem, BP_CHECKBOX, CBS_UNCHECKEDDISABLED, &rc, NULL);\n//        PhOffsetRect(&rc, cx, 0);\n//\n//        // Frame 5: Disabled, checked.\n//        PhDrawThemeBackground(htheme, hdcMem, BP_CHECKBOX, CBS_CHECKEDDISABLED, &rc, NULL);\n//\n//        // Done with the theme.\n//        PhCloseThemeData(htheme);\n//    }\n//    else\n//    {\n//        // Flags common to all of our DrawFrameControl calls:\n//        // Draw a flat checkbox.\n//        UINT baseFlags = DFCS_FLAT | DFCS_BUTTONCHECK;\n//\n//        // Frame 1: Unchecked.\n//        DrawFrameControl(hdcMem, &rc, DFC_BUTTON, baseFlags);\n//        PhOffsetRect(&rc, cx, 0);\n//\n//        // Frame 2: Checked.\n//        DrawFrameControl(hdcMem, &rc, DFC_BUTTON, baseFlags | DFCS_CHECKED);\n//        PhOffsetRect(&rc, cx, 0);\n//\n//        // Frame 3: Indeterminate.\n//        DrawFrameControl(hdcMem, &rc, DFC_BUTTON, baseFlags | DFCS_CHECKED | DFCS_BUTTON3STATE);\n//        PhOffsetRect(&rc, cx, 0);\n//\n//        // Frame 4: Disabled, unchecked.\n//        DrawFrameControl(hdcMem, &rc, DFC_BUTTON, baseFlags | DFCS_INACTIVE);\n//        PhOffsetRect(&rc, cx, 0);\n//\n//        // Frame 5: Disabled, checked.\n//        DrawFrameControl(hdcMem, &rc, DFC_BUTTON, baseFlags | DFCS_INACTIVE | DFCS_CHECKED);\n//    }\n//\n//    // The bitmap is ready. Clean up.\n//    SelectBitmap(hdcMem, hbmOld);\n//    DeleteDC(hdcMem);\n//    ReleaseDC(hwnd, hdcScreen);\n//\n//    // Create an imagelist from this bitmap.\n//    HIMAGELIST himl = PhImageListCreate(cx, cy, ILC_COLOR, frames, frames);\n//    PhImageListAddBitmap(himl, hbmCheckboxes, NULL);\n//\n//    // Don't need the bitmap any more.\n//    DeleteObject(hbmCheckboxes);\n//\n//    return himl;\n//}\n//\n//VOID OnThemeChange(HWND hwnd) // WM_THEMECHANGE\n//{\n//    // Rebuild the state images to match the new theme.\n//    HIMAGELIST himl = CreateTreeViewCheckBoxes(g_hwndChild, 16, 16);\n//    ImageList_Destroy(TreeView_SetImageList(g_hwndChild, himl, TVSIL_STATE));\n//}\n\nVOID PhThemeDrawButtonIcon(\n    _In_ LPNMCUSTOMDRAW DrawInfo,\n    _In_ HICON ButtonIcon,\n    _In_ PRECT ButtonRect,\n    _In_ LONG WindowDpi\n    )\n{\n    BOOL result;\n    ICONINFO iconInfo;\n    BITMAP bmp;\n    LONG width = PhGetSystemMetrics(SM_CXSMICON, WindowDpi);\n    LONG height = PhGetSystemMetrics(SM_CYSMICON, WindowDpi);\n\n    memset(&iconInfo, 0, sizeof(ICONINFO));\n    memset(&bmp, 0, sizeof(BITMAP));\n\n    result = GetIconInfo(ButtonIcon, &iconInfo);\n\n    if (iconInfo.hbmColor)\n    {\n        if (GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmp))\n        {\n            width = bmp.bmWidth;\n            height = bmp.bmHeight;\n        }\n\n        DeleteBitmap(iconInfo.hbmColor);\n    }\n    else if (iconInfo.hbmMask)\n    {\n        if (GetObject(iconInfo.hbmMask, sizeof(BITMAP), &bmp))\n        {\n            width = bmp.bmWidth;\n            height = bmp.bmHeight / 2;\n        }\n\n        DeleteBitmap(iconInfo.hbmMask);\n    }\n\n    DrawIconEx(\n        DrawInfo->hdc,\n        ButtonRect->left + ((ButtonRect->right - ButtonRect->left) - width) / 2,\n        ButtonRect->top + ((ButtonRect->bottom - ButtonRect->top) - height) / 2,\n        ButtonIcon,\n        width,\n        height,\n        0,\n        NULL,\n        DI_NORMAL\n        );\n\n    if (!result) // HACK\n    {\n        BUTTON_IMAGELIST imageList = { 0 };\n\n        if (Button_GetImageList(DrawInfo->hdr.hwndFrom, &imageList) && imageList.himl)\n        {\n            ButtonRect->left += PhGetDpi(1, WindowDpi);\n\n            PhImageListDrawIcon(\n                imageList.himl,\n                0,\n                DrawInfo->hdc,\n                ButtonRect->left, // + ((ButtonRect->right - ButtonRect->left) - width) / 2,\n                ButtonRect->top + ((ButtonRect->bottom - ButtonRect->top) - height) / 2,\n                ILD_NORMAL,\n                FALSE\n                );\n\n            ButtonRect->left += PhGetDpi(5, WindowDpi);\n        }\n    }\n}\n\nLRESULT CALLBACK PhThemeWindowDrawButton(\n    _In_ LPNMCUSTOMDRAW DrawInfo\n    )\n{\n    ULONG buttonStyle;\n\n    buttonStyle = PhGetWindowStyle(DrawInfo->hdr.hwndFrom);\n    // COMMANDLINK unsupported\n    if ((buttonStyle & BS_COMMANDLINK) == BS_COMMANDLINK || (buttonStyle & BS_DEFCOMMANDLINK) == BS_DEFCOMMANDLINK)\n        return CDRF_DODEFAULT;\n\n    BOOLEAN isGrayed = (DrawInfo->uItemState & CDIS_GRAYED) == CDIS_GRAYED;\n    BOOLEAN isChecked = (DrawInfo->uItemState & CDIS_CHECKED) == CDIS_CHECKED;\n    BOOLEAN isMixed = (DrawInfo->uItemState & CDIS_INDETERMINATE) == CDIS_INDETERMINATE;\n    BOOLEAN isDisabled = (DrawInfo->uItemState & CDIS_DISABLED) == CDIS_DISABLED;\n    BOOLEAN isSelected = (DrawInfo->uItemState & CDIS_SELECTED) == CDIS_SELECTED;\n    BOOLEAN isHighlighted = (DrawInfo->uItemState & CDIS_HOT) == CDIS_HOT;\n    BOOLEAN isFocused = (DrawInfo->uItemState & CDIS_FOCUS) == CDIS_FOCUS;\n    BOOLEAN isKeyboardFocused = isFocused && (DrawInfo->uItemState & CDIS_SHOWKEYBOARDCUES) == CDIS_SHOWKEYBOARDCUES;\n    RECT bufferRect =\n    {\n        0, 0,\n        DrawInfo->rc.right - DrawInfo->rc.left,\n        DrawInfo->rc.bottom - DrawInfo->rc.top\n    };\n\n    switch (DrawInfo->dwDrawStage)\n    {\n    case CDDS_PREPAINT:\n        {\n            PPH_STRING buttonText;\n            HICON buttonIcon;\n            LONG dpiValue;\n\n            BOOLEAN isCheckbox = (buttonStyle & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX || (buttonStyle & BS_AUTO3STATE) == BS_AUTO3STATE;\n            BOOLEAN isRadio = (buttonStyle & BS_AUTORADIOBUTTON) == BS_AUTORADIOBUTTON;\n\n            if (!isCheckbox && !isRadio && PhEnableThemeNativeButtons && !PhEnableThemeAcrylicWindowSupport)\n                return CDRF_DODEFAULT;\n\n            dpiValue = PhGetWindowDpi(DrawInfo->hdr.hwndFrom);\n            buttonText = PhGetWindowText(DrawInfo->hdr.hwndFrom);\n\n            if (!(buttonIcon = Static_GetIcon(DrawInfo->hdr.hwndFrom, 0)))\n                buttonIcon = (HICON)SendMessage(DrawInfo->hdr.hwndFrom, BM_GETIMAGE, IMAGE_ICON, 0);\n\n            // Add support for disabled and tristate checkboxes, support for radio with multiline (ex. TaskDialog) (Dart Vanya)\n            if (isCheckbox || isRadio)\n            {\n                INT state = isCheckbox ? CBS_UNCHECKEDNORMAL : RBS_UNCHECKEDNORMAL;\n                HTHEME themeHandle;\n\n                isChecked = Button_GetCheck(DrawInfo->hdr.hwndFrom) & BST_CHECKED;\n                isMixed =  Button_GetCheck(DrawInfo->hdr.hwndFrom) & BST_INDETERMINATE;\n\n                if (isCheckbox)\n                {\n                    if (isDisabled)\n                        state = isChecked ? CBS_CHECKEDDISABLED : isMixed ? CBS_MIXEDDISABLED : CBS_UNCHECKEDDISABLED;\n                    else if (isSelected)\n                        state = isChecked ? CBS_CHECKEDPRESSED : isMixed ? CBS_MIXEDPRESSED : CBS_UNCHECKEDPRESSED;\n                    else if (isHighlighted)\n                        state = isChecked ? CBS_CHECKEDHOT : isMixed ? CBS_MIXEDHOT : CBS_UNCHECKEDHOT;\n                    else\n                        state = isChecked ? CBS_CHECKEDNORMAL : isMixed ? CBS_MIXEDNORMAL : CBS_UNCHECKEDNORMAL;\n                }\n                else\n                {\n                    if (isDisabled)\n                        state = isChecked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED;\n                    else if (isSelected)\n                        state = isChecked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED;\n                    else if (isHighlighted)\n                        state = isChecked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT;\n                    else\n                        state = isChecked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL;\n                }\n\n                if (buttonIcon)\n                {\n                    if (isSelected || isChecked)\n                    {\n                        //switch (PhpThemeColorMode)\n                        //{\n                        //case 0: // New colors\n                        //    //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff));\n                        //    SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT));\n                        //    break;\n                        //case 1: // Old colors\n                        SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                        SetDCBrushColor(DrawInfo->hdc, RGB(78, 78, 78));\n                        FillRect(DrawInfo->hdc, &DrawInfo->rc, PhGetStockBrush(DC_BRUSH));\n                    }\n                    else if (isHighlighted)\n                    {\n                        //switch (PhpThemeColorMode)\n                        //{\n                        //case 0: // New colors\n                        //    //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff));\n                        //    SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT));\n                        //    break;\n                        //case 1: // Old colors\n                        SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                        SetDCBrushColor(DrawInfo->hdc, PhThemeWindowBackground2Color);\n                        FillRect(DrawInfo->hdc, &DrawInfo->rc, PhGetStockBrush(DC_BRUSH));\n                    }\n                    else\n                    {\n                        SetTextColor(DrawInfo->hdc, !isDisabled ? PhThemeWindowTextColor : RGB(0x9B, 0x9B, 0x9B));\n                        //SetDCBrushColor(DrawInfo->hdc, PhThemeWindowBackgroundColor); // WindowForegroundColor\n                        FillRect(DrawInfo->hdc, &DrawInfo->rc, PhThemeWindowBackgroundBrush);\n                    }\n\n                    SetDCBrushColor(DrawInfo->hdc, PhThemeWindowBackground2Color);\n                    FrameRect(DrawInfo->hdc, &DrawInfo->rc, PhGetStockBrush(DC_BRUSH));\n\n                    PhThemeDrawButtonIcon(DrawInfo, buttonIcon, &bufferRect, dpiValue);\n                }\n                else\n                {\n                    SetBkMode(DrawInfo->hdc, TRANSPARENT);\n                    SetTextColor(DrawInfo->hdc, !isDisabled ? PhThemeWindowTextColor : RGB(0x9B, 0x9B, 0x9B));\n\n                    if (themeHandle = PhOpenThemeData(DrawInfo->hdr.hwndFrom, VSCLASS_BUTTON, dpiValue))\n                    {\n                        SIZE checkBoxSize = { 0 };\n                        SIZE textSize = { 0 };\n                        INT linesCount;\n\n                        PhGetThemePartSize(\n                            themeHandle,\n                            DrawInfo->hdc,\n                            isCheckbox ? BP_CHECKBOX : BP_RADIOBUTTON,\n                            state,\n                            &bufferRect,\n                            THEMEPARTSIZE_TRUE,\n                            &checkBoxSize\n                            );\n                        GetTextExtentPoint32W(DrawInfo->hdc, L\"T\", 1, &textSize);\n\n                        bufferRect.left = 0;\n                        bufferRect.right = checkBoxSize.cx;\n                        linesCount = (bufferRect.bottom - bufferRect.top) / textSize.cy;\n                        if (linesCount > 1)\n                            bufferRect.bottom -= textSize.cy * (linesCount - 1);    // HACK (very sensitive value)\n\n                        //if (IsThemeBackgroundPartiallyTransparent(themeHandle, isCheckbox ? BP_CHECKBOX : BP_RADIOBUTTON, state))\n                        //    DrawThemeParentBackground(DrawInfo->hdr.hwndFrom, DrawInfo->hdc, NULL);\n\n                        PhDrawThemeBackground(\n                            themeHandle,\n                            DrawInfo->hdc,\n                            isCheckbox ? BP_CHECKBOX : BP_RADIOBUTTON,\n                            state,\n                            &bufferRect,\n                            NULL\n                            );\n\n                        bufferRect = DrawInfo->rc;\n                        bufferRect.left = checkBoxSize.cx + 4; // TNP_ICON_RIGHT_PADDING\n\n                        if (linesCount == 1)\n                        {\n                            DrawText(\n                                DrawInfo->hdc,\n                                buttonText->Buffer,\n                                (UINT)buttonText->Length / sizeof(WCHAR),\n                                &bufferRect,\n                                DT_LEFT | DT_SINGLELINE | DT_VCENTER | (!isKeyboardFocused ? DT_HIDEPREFIX : 0)\n                                );\n                        }\n                        else\n                        {\n                            DrawText(\n                                DrawInfo->hdc,\n                                buttonText->Buffer,\n                                (UINT)buttonText->Length / sizeof(WCHAR),\n                                &bufferRect,\n                                DT_LEFT | DT_TOP | DT_CALCRECT | (!isKeyboardFocused ? DT_HIDEPREFIX : 0)\n                                );\n\n                            bufferRect.top = (DrawInfo->rc.bottom - DrawInfo->rc.top) / 2 - (bufferRect.bottom - bufferRect.top) / 2 - 1;\n                            bufferRect.bottom = DrawInfo->rc.bottom, bufferRect.right = DrawInfo->rc.right;\n\n                            DrawText(\n                                DrawInfo->hdc,\n                                buttonText->Buffer,\n                                (UINT)buttonText->Length / sizeof(WCHAR),\n                                &bufferRect,\n                                DT_LEFT | DT_TOP | (!isKeyboardFocused ? DT_HIDEPREFIX : 0)\n                                );\n                        }\n\n                        if (isKeyboardFocused)\n                        {\n                            DrawText(\n                                DrawInfo->hdc,\n                                buttonText->Buffer,\n                                (UINT)buttonText->Length / sizeof(WCHAR),\n                                &bufferRect,\n                                DT_LEFT | DT_TOP | DT_CALCRECT\n                                );\n                            PhInflateRect(&bufferRect, 1, 0);\n                            bufferRect.top += 1, bufferRect.bottom += 2;\n                            if (bufferRect.bottom > DrawInfo->rc.bottom - 1) bufferRect.bottom = DrawInfo->rc.bottom - 1;\n\n                            for (INT i = 0; i < bufferRect.right - bufferRect.left - 1; i += 2)\n                                SetPixel(DrawInfo->hdc, bufferRect.left + i + 1, bufferRect.bottom, PhThemeWindowHighlight2Color);\n                            for (INT i = 0; i < bufferRect.bottom - bufferRect.top - 1; i += 2)\n                                SetPixel(DrawInfo->hdc, bufferRect.right, bufferRect.bottom - i - 1, PhThemeWindowHighlight2Color);\n                            for (INT i = 0; i < bufferRect.right - bufferRect.left - 1; i += 2)\n                                SetPixel(DrawInfo->hdc, bufferRect.right - i - 1, bufferRect.top, PhThemeWindowHighlight2Color);\n                            for (INT i = 0; i < bufferRect.bottom - bufferRect.top - 1; i += 2)\n                                SetPixel(DrawInfo->hdc, bufferRect.left, bufferRect.top + i + 1, PhThemeWindowHighlight2Color);\n                        }\n\n                        PhCloseThemeData(themeHandle);\n                    }\n                    else\n                    {\n                        if (isChecked)\n                        {\n                            HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 16, dpiValue);\n                            HFONT oldFont;\n\n                            oldFont = SelectFont(DrawInfo->hdc, newFont);\n                            DrawText(\n                                DrawInfo->hdc,\n                                L\"\\u2611\",\n                                1,\n                                &DrawInfo->rc,\n                                DT_LEFT | DT_SINGLELINE | DT_VCENTER\n                                );\n                            SelectFont(DrawInfo->hdc, oldFont);\n                            DeleteFont(newFont);\n                        }\n                        else\n                        {\n                            HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 22, dpiValue);\n                            HFONT oldFont;\n\n                            oldFont = SelectFont(DrawInfo->hdc, newFont);\n                            DrawText(\n                                DrawInfo->hdc,\n                                L\"\\u2610\",\n                                1,\n                                &DrawInfo->rc,\n                                DT_LEFT | DT_SINGLELINE | DT_VCENTER\n                                );\n                            SelectFont(DrawInfo->hdc, oldFont);\n                            DeleteFont(newFont);\n                        }\n\n                        bufferRect.left = 17;\n                        bufferRect.right = DrawInfo->rc.right;\n\n                        DrawText(\n                            DrawInfo->hdc,\n                            buttonText->Buffer,\n                            (UINT)buttonText->Length / sizeof(WCHAR),\n                            &bufferRect,\n                            DT_LEFT | DT_VCENTER | DT_SINGLELINE | (!isKeyboardFocused ? DT_HIDEPREFIX : 0)\n                            );\n                    }\n                }\n            }\n            else\n            {\n                if (isSelected)\n                {\n                    //switch (PhpThemeColorMode)\n                    //{\n                    //case 0: // New colors\n                    //    //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff));\n                    //    SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT));\n                    //    break;\n                    //case 1: // Old colors\n                    SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                    SetDCBrushColor(DrawInfo->hdc, RGB(78, 78, 78));\n                    FillRect(DrawInfo->hdc, &DrawInfo->rc, PhGetStockBrush(DC_BRUSH));\n                }\n                else if (isHighlighted)\n                {\n                    //switch (PhpThemeColorMode)\n                    //{\n                    //case 0: // New colors\n                    //    //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff));\n                    //    SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT));\n                    //    break;\n                    //case 1: // Old colors\n                    SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                    SetDCBrushColor(DrawInfo->hdc, PhThemeWindowBackground2Color);\n                    FillRect(DrawInfo->hdc, &DrawInfo->rc, PhGetStockBrush(DC_BRUSH));\n                }\n                else\n                {\n                    SetTextColor(DrawInfo->hdc, !isDisabled ? PhThemeWindowTextColor : RGB(0x9B, 0x9B, 0x9B));\n                    //SetDCBrushColor(DrawInfo->hdc, PhThemeWindowBackgroundColor); // WindowForegroundColor\n                    FillRect(DrawInfo->hdc, &DrawInfo->rc, PhThemeWindowBackgroundBrush);\n                }\n\n                SetBkMode(DrawInfo->hdc, TRANSPARENT);\n                SetDCBrushColor(DrawInfo->hdc, !isFocused ? PhThemeWindowBackground2Color : PhThemeWindowHighlightColor);\n                FrameRect(DrawInfo->hdc, &DrawInfo->rc, PhGetStockBrush(DC_BRUSH));\n\n                PhThemeDrawButtonIcon(DrawInfo, buttonIcon, &bufferRect, dpiValue);\n\n                if ((buttonStyle & BS_ICON) != BS_ICON)\n                {\n                    DrawText(\n                        DrawInfo->hdc,\n                        buttonText->Buffer,\n                        (UINT)buttonText->Length / sizeof(WCHAR),\n                        &bufferRect,\n                        DT_CENTER | DT_SINGLELINE | DT_VCENTER | (!isKeyboardFocused ? DT_HIDEPREFIX : 0)\n                        );\n                }\n            }\n            PhDereferenceObject(buttonText);\n        }\n\n        return CDRF_SKIPDEFAULT;\n    }\n\n    return CDRF_DODEFAULT;\n}\n\nLRESULT CALLBACK PhThemeWindowDrawRebar(\n    _In_ LPNMCUSTOMDRAW DrawInfo\n    )\n{\n    // temp chevron workaround until location/state supported.\n    if (DrawInfo->dwDrawStage != CDDS_PREPAINT)\n        return CDRF_DODEFAULT;\n\n    switch (DrawInfo->dwDrawStage)\n    {\n    case CDDS_PREPAINT:\n        {\n            //REBARBANDINFO bandinfo = { sizeof(REBARBANDINFO), RBBIM_CHILD | RBBIM_STYLE | RBBIM_CHEVRONLOCATION | RBBIM_CHEVRONSTATE };\n            //BOOL havebandinfo = (BOOL)SendMessage(DrawInfo->hdr.hwndFrom, RB_GETBANDINFO, DrawInfo->dwItemSpec, (LPARAM)&bandinfo);\n\n            SetTextColor(DrawInfo->hdc, PhThemeWindowTextColor);\n            FillRect(DrawInfo->hdc, &DrawInfo->rc, PhThemeWindowBackgroundBrush);\n        }\n        return CDRF_NOTIFYITEMDRAW;\n    case CDDS_ITEMPREPAINT:\n        {\n\n        }\n        return CDRF_SKIPDEFAULT;\n    }\n\n    return CDRF_DODEFAULT;\n}\n\nLRESULT CALLBACK PhThemeWindowDrawToolbar(\n    _In_ LPNMTBCUSTOMDRAW DrawInfo\n    )\n{\n    switch (DrawInfo->nmcd.dwDrawStage)\n    {\n    case CDDS_PREPAINT:\n        return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT;\n    case CDDS_ITEMPREPAINT:\n        {\n            TBBUTTONINFO buttonInfo =\n            {\n                sizeof(TBBUTTONINFO),\n                TBIF_STYLE | TBIF_COMMAND | TBIF_STATE | TBIF_IMAGE\n            };\n\n            SetBkMode(DrawInfo->nmcd.hdc, TRANSPARENT);\n\n            LONG dpiValue;\n            INT bitmapWidth = 0;\n            INT bitmapHeight = 0;\n\n            ULONG currentIndex = (ULONG)SendMessage(\n                DrawInfo->nmcd.hdr.hwndFrom,\n                TB_COMMANDTOINDEX,\n                DrawInfo->nmcd.dwItemSpec,\n                0\n                );\n            BOOLEAN isHighlighted = SendMessage(\n                DrawInfo->nmcd.hdr.hwndFrom,\n                TB_GETHOTITEM,\n                0,\n                0\n                ) == currentIndex;\n            BOOLEAN isMouseDown = SendMessage(\n                DrawInfo->nmcd.hdr.hwndFrom,\n                TB_ISBUTTONPRESSED,\n                DrawInfo->nmcd.dwItemSpec,\n                0\n                ) == 0;\n            BOOLEAN isEnabled = SendMessage(\n                DrawInfo->nmcd.hdr.hwndFrom,\n                TB_ISBUTTONENABLED,\n                DrawInfo->nmcd.dwItemSpec,\n                0\n                ) != 0;\n\n            if (SendMessage(\n                DrawInfo->nmcd.hdr.hwndFrom,\n                TB_GETBUTTONINFO,\n                (ULONG)DrawInfo->nmcd.dwItemSpec,\n                (LPARAM)&buttonInfo\n                ) == INT_ERROR)\n            {\n                break;\n            }\n\n            BOOLEAN isDropDown = !!(buttonInfo.fsStyle & BTNS_WHOLEDROPDOWN);\n\n            //if (isMouseDown)\n            //{\n            //    SetTextColor(DrawInfo->nmcd.hdc, PhThemeWindowTextColor);\n            //    SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff));\n            //    FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, PhGetStockBrush(DC_BRUSH));\n            //}\n\n            if (isHighlighted)\n            {\n                //INT stateId;\n                //// Themed background\n                //if (node->Selected)\n                //{\n                //    if (i == Context->HotNodeIndex)\n                //        stateId = TREIS_HOTSELECTED;\n                //    else if (!Context->HasFocus)\n                //        stateId = TREIS_SELECTEDNOTFOCUS;\n                //    else\n                //        stateId = TREIS_SELECTED;\n                //}\n                //else\n                //{\n                //    if (i == Context->HotNodeIndex)\n                //        stateId = TREIS_HOT;\n                //    else\n                //        stateId = INT_MAX;\n                //}\n                //// Themed background\n                //if (stateId != INT_MAX)\n                //if (!Context->FixedColumnVisible)\n                //{\n                //    rowRect.left = Context->NormalLeft - hScrollPosition;\n                //}\n                //switch (PhpThemeColorMode)\n                //{\n                //case 0: // New colors\n                //    SetTextColor(DrawInfo->nmcd.hdc, PhThemeWindowTextColor);\n                //    SetDCBrushColor(DrawInfo->nmcd.hdc, PhThemeWindowBackgroundColor);\n                //    FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, PhGetStockBrush(DC_BRUSH));\n                //    break;\n                //case 1: // Old colors\n                //    SetTextColor(DrawInfo->nmcd.hdc, PhThemeWindowTextColor);\n                //    SetDCBrushColor(DrawInfo->nmcd.hdc, PhThemeWindowHighlightColor);\n                //    FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, PhGetStockBrush(DC_BRUSH));\n                //    break;\n                //}\n\n                SetTextColor(DrawInfo->nmcd.hdc, PhThemeWindowTextColor);\n                SetDCBrushColor(DrawInfo->nmcd.hdc, PhThemeWindowHighlightColor);\n                FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, PhGetStockBrush(DC_BRUSH));\n            }\n            else\n            {\n                //switch (PhpThemeColorMode)\n                //{\n                //case 0: // New colors\n                //    SetTextColor(DrawInfo->nmcd.hdc, PhThemeWindowTextColor); // RGB(0x0, 0x0, 0x0));\n                //    SetDCBrushColor(DrawInfo->nmcd.hdc, PhThemeWindowBackgroundColor); // GetSysColor(COLOR_3DFACE));// RGB(0xff, 0xff, 0xff));\n                //    FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, PhGetStockBrush(DC_BRUSH));\n                //    break;\n                //case 1: // Old colors\n                //    SetTextColor(DrawInfo->nmcd.hdc, PhThemeWindowTextColor);\n                //    SetDCBrushColor(DrawInfo->nmcd.hdc, PhThemeWindowBackgroundColor); //PhThemeWindowForegroundColor);\n                //    FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, PhGetStockBrush(DC_BRUSH));\n                //    break;\n                //}\n\n                BOOLEAN isPressed = buttonInfo.fsState & TBSTATE_PRESSED;\n                SetTextColor(DrawInfo->nmcd.hdc, PhThemeWindowTextColor); // RGB(0x0, 0x0, 0x0));\n                //SetDCBrushColor(DrawInfo->nmcd.hdc, PhThemeWindowBackgroundColor); // GetSysColor(COLOR_3DFACE));// RGB(0xff, 0xff, 0xff));\n                if (!isPressed)\n                    FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, PhThemeWindowBackgroundBrush);\n                else {\n                    SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0x60, 0x60, 0x60));\n                    FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, PhGetStockBrush(DC_BRUSH));\n                }\n            }\n\n            dpiValue = PhGetWindowDpi(DrawInfo->nmcd.hdr.hwndFrom);\n\n            SelectFont(DrawInfo->nmcd.hdc, GetWindowFont(DrawInfo->nmcd.hdr.hwndFrom));\n\n            if (buttonInfo.iImage != I_IMAGECALLBACK)\n            {\n                HIMAGELIST toolbarImageList;\n\n                if (toolbarImageList = (HIMAGELIST)SendMessage(\n                    DrawInfo->nmcd.hdr.hwndFrom,\n                    TB_GETIMAGELIST,\n                    0,\n                    0\n                    ))\n                {\n                    LONG x;\n                    LONG y;\n\n                    PhImageListGetIconSize(toolbarImageList, &bitmapWidth, &bitmapHeight);\n\n                    if (buttonInfo.fsStyle & BTNS_SHOWTEXT)\n                    {\n                        DrawInfo->nmcd.rc.left += PhGetSystemMetrics(SM_CXEDGE, dpiValue); // PhGetDpi(5, dpiValue);\n                        x = DrawInfo->nmcd.rc.left;// + ((DrawInfo->nmcd.rc.right - DrawInfo->nmcd.rc.left) - PhSmallIconSize.X) / 2;\n                        y = DrawInfo->nmcd.rc.top + ((DrawInfo->nmcd.rc.bottom - DrawInfo->nmcd.rc.top) - bitmapHeight) / 2;\n                    }\n                    else\n                    {\n                        x = DrawInfo->nmcd.rc.left + ((DrawInfo->nmcd.rc.right - DrawInfo->nmcd.rc.left) - bitmapWidth) / 2 - (isDropDown * 4);\n                        y = DrawInfo->nmcd.rc.top + ((DrawInfo->nmcd.rc.bottom - DrawInfo->nmcd.rc.top) - bitmapHeight) / 2;\n                    }\n\n                    PhImageListDrawIcon(\n                        toolbarImageList,\n                        buttonInfo.iImage,\n                        DrawInfo->nmcd.hdc,\n                        x,\n                        y,\n                        ILD_NORMAL,\n                        !isEnabled\n                        );\n\n                    if (isDropDown)\n                    {\n                        HDC hdc = DrawInfo->nmcd.hdc;\n                        LPRECT rc = &DrawInfo->nmcd.rc;\n                        int triangleLeft = rc->right - 11, triangleTop = (rc->bottom - rc->top) / 2 - 2;\n                        POINT vertices[] = { {triangleLeft, triangleTop}, {triangleLeft + 6, triangleTop}, {triangleLeft + 3, triangleTop + 3} };\n                        SetDCPenColor(hdc, RGB(0xDE, 0xDE, 0xDE));\n                        SetDCBrushColor(hdc, RGB(0xDE, 0xDE, 0xDE));\n                        SelectPen(hdc, PhGetStockPen(DC_PEN));\n                        SelectBrush(hdc, PhGetStockBrush(DC_BRUSH));\n                        Polygon(hdc, vertices, _countof(vertices));\n                    }\n\n                    //return CDRF_SKIPDEFAULT | CDRF_NOTIFYPOSTPAINT;\n                }\n            }\n            else\n            {\n                return CDRF_DODEFAULT; // Required for I_IMAGECALLBACK (dmex)\n            }\n\n            if (buttonInfo.fsStyle & BTNS_SHOWTEXT)\n            {\n                RECT textRect = DrawInfo->nmcd.rc;\n                WCHAR buttonText[MAX_PATH] = L\"\";\n\n                SendMessage(\n                    DrawInfo->nmcd.hdr.hwndFrom,\n                    TB_GETBUTTONTEXT,\n                    (ULONG)DrawInfo->nmcd.dwItemSpec,\n                    (LPARAM)buttonText\n                    );\n\n                textRect.left += bitmapWidth - (isDropDown * 12); // PhGetDpi(10, dpiValue);\n                DrawText(\n                    DrawInfo->nmcd.hdc,\n                    buttonText,\n                    (UINT)PhCountStringZ(buttonText),\n                    &textRect,\n                    DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX\n                    );\n            }\n\n            //DrawInfo->clrText = RGB(0x0, 0xff, 0);\n            //return TBCDRF_USECDCOLORS | CDRF_NEWFONT;\n        }\n        return CDRF_SKIPDEFAULT;\n    }\n\n    return CDRF_DODEFAULT;\n}\n\nLRESULT CALLBACK PhpThemeWindowDrawListViewGroup(\n    _In_ LPNMLVCUSTOMDRAW DrawInfo\n    )\n{\n    switch (DrawInfo->nmcd.dwDrawStage)\n    {\n    case CDDS_PREPAINT:\n        {\n            LONG dpiValue = PhGetWindowDpi(DrawInfo->nmcd.hdr.hwndFrom);\n            HFONT fontHandle = NULL;\n            HFONT oldFontHandle = NULL;\n            LVGROUP groupInfo;\n\n            {\n                NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) };\n\n                if (PhGetSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, dpiValue))\n                {\n                    metrics.lfMessageFont.lfHeight = PhGetDpi(-11, dpiValue);\n                    metrics.lfMessageFont.lfWeight = FW_BOLD;\n\n                    fontHandle = CreateFontIndirect(&metrics.lfMessageFont);\n                }\n            }\n\n            SetBkMode(DrawInfo->nmcd.hdc, TRANSPARENT);\n            //SelectFont(DrawInfo->nmcd.hdc, GetWindowFont(DrawInfo->nmcd.hdr.hwndFrom));\n            if (fontHandle)\n            {\n                oldFontHandle = SelectFont(DrawInfo->nmcd.hdc, fontHandle);\n            }\n\n            memset(&groupInfo, 0, sizeof(LVGROUP));\n            groupInfo.cbSize = sizeof(LVGROUP);\n            groupInfo.mask = LVGF_HEADER;\n\n            if (ListView_GetGroupInfo(DrawInfo->nmcd.hdr.hwndFrom, (ULONG)DrawInfo->nmcd.dwItemSpec, &groupInfo) != INT_ERROR)\n            {\n                SetTextColor(DrawInfo->nmcd.hdc, PhThemeWindowTextColor);\n                SetDCBrushColor(DrawInfo->nmcd.hdc, PhThemeWindowBackground2Color);\n\n                DrawInfo->rcText.top += PhGetDpi(2, dpiValue);\n                DrawInfo->rcText.bottom -= PhGetDpi(2, dpiValue);\n                FillRect(DrawInfo->nmcd.hdc, &DrawInfo->rcText, PhGetStockBrush(DC_BRUSH));\n                DrawInfo->rcText.top -= PhGetDpi(2, dpiValue);\n                DrawInfo->rcText.bottom += PhGetDpi(2, dpiValue);\n\n                if (groupInfo.pszHeader)\n                {\n                    DrawInfo->rcText.left += PhGetDpi(10, dpiValue);\n                    DrawText(\n                        DrawInfo->nmcd.hdc,\n                        groupInfo.pszHeader,\n                        (UINT)PhCountStringZ(groupInfo.pszHeader),\n                        &DrawInfo->rcText,\n                        DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX\n                        );\n                    DrawInfo->rcText.left -= PhGetDpi(10, dpiValue);\n                }\n            }\n\n            if (oldFontHandle)\n            {\n                SelectFont(DrawInfo->nmcd.hdc, oldFontHandle);\n            }\n\n            if (fontHandle)\n            {\n                DeleteFont(fontHandle);\n            }\n        }\n        return CDRF_SKIPDEFAULT;\n    }\n\n    return CDRF_DODEFAULT;\n}\n\nLRESULT CALLBACK PhpThemeWindowSubclassProc(\n    _In_ HWND hWnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    WNDPROC oldWndProc;\n\n    if (!(oldWndProc = PhGetWindowContext(hWnd, LONG_MAX)))\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContext(hWnd, LONG_MAX);\n            SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR data = (LPNMHDR)lParam;\n\n            switch (data->code)\n            {\n            case NM_CUSTOMDRAW:\n                {\n                    LPNMCUSTOMDRAW customDraw = (LPNMCUSTOMDRAW)lParam;\n                    WCHAR className[MAX_PATH];\n\n                    if (!GetClassName(customDraw->hdr.hwndFrom, className, RTL_NUMBER_OF(className)))\n                        className[0] = UNICODE_NULL;\n\n                    if (PhEqualStringZ(className, WC_BUTTON, FALSE))\n                    {\n                        return PhThemeWindowDrawButton(customDraw);\n                    }\n                    else if (PhEqualStringZ(className, REBARCLASSNAME, FALSE))\n                    {\n                        return PhThemeWindowDrawRebar(customDraw);\n                    }\n                    else if (PhEqualStringZ(className, TOOLBARCLASSNAME, FALSE))\n                    {\n                        return PhThemeWindowDrawToolbar((LPNMTBCUSTOMDRAW)customDraw);\n                    }\n                    else if (PhEqualStringZ(className, WC_LISTVIEW, FALSE))\n                    {\n                        LPNMLVCUSTOMDRAW listViewCustomDraw = (LPNMLVCUSTOMDRAW)customDraw;\n\n                        if (listViewCustomDraw->dwItemType == LVCDI_GROUP)\n                        {\n                            return PhpThemeWindowDrawListViewGroup(listViewCustomDraw);\n                        }\n                    }\n                    else\n                    {\n                        //dprintf(\"NM_CUSTOMDRAW: %S\\r\\n\", className);\n                    }\n                }\n            }\n        }\n        break;\n    case WM_CTLCOLOREDIT:\n        {\n            HDC hdc = (HDC)wParam;\n\n             //Fix typing in multiline edit (Dart Vanya)\n            if (PhGetWindowStyle((HWND)lParam) & ES_MULTILINE)\n                SetBkColor(hdc, PhThemeWindowBackground2Color);\n            else\n                SetBkMode(hdc, TRANSPARENT);\n            SetTextColor(hdc, PhThemeWindowTextColor);\n            SetDCBrushColor(hdc, PhThemeWindowBackground2Color);\n            return (INT_PTR)PhGetStockBrush(DC_BRUSH);\n        }\n        break;\n    case WM_CTLCOLORBTN:\n    case WM_CTLCOLORDLG:\n    case WM_CTLCOLORSTATIC:\n    case WM_CTLCOLORLISTBOX:\n        {\n            HDC hdc = (HDC)wParam;\n\n            if (uMsg == WM_CTLCOLORBTN)     // for correct drawing of system KEYBOARDCUES\n                SetBkColor(hdc, PhThemeWindowBackground2Color);\n            else\n                SetBkMode(hdc, TRANSPARENT);\n            SetTextColor(hdc, PhThemeWindowTextColor);\n            return (INT_PTR)PhThemeWindowBackgroundBrush;\n        }\n        break;\n\n    case WM_MEASUREITEM:\n        if (PhThemeWindowMeasureItem(hWnd, (LPMEASUREITEMSTRUCT)lParam))\n            return TRUE;\n        break;\n    case WM_DRAWITEM:\n        if (PhThemeWindowDrawItem(hWnd, (LPDRAWITEMSTRUCT)lParam))\n            return TRUE;\n        break;\n    case WM_NCPAINT:\n    case WM_NCACTIVATE:\n        {\n            LRESULT result = CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam);\n\n            PhWindowThemeMainMenuBorder(hWnd);\n\n            return result;\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam);\n}\n\nVOID ThemeWindowRenderGroupBoxControl(\n    _In_ HWND WindowHandle,\n    _In_ HDC bufferDc,\n    _In_ PRECT clientRect,\n    _In_ WNDPROC WindowProcedure\n    )\n{\n    ULONG returnLength;\n    WCHAR text[0x80];\n    LONG dpiValue;\n\n    SetBkMode(bufferDc, TRANSPARENT);\n    SelectFont(bufferDc, GetWindowFont(WindowHandle));\n    SetDCBrushColor(bufferDc, PhThemeWindowBackground2Color);\n    FrameRect(bufferDc, clientRect, PhGetStockBrush(DC_BRUSH));\n\n    dpiValue = PhGetWindowDpi(WindowHandle);\n\n    if (NT_SUCCESS(PhGetWindowTextToBuffer(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL, text, RTL_NUMBER_OF(text), &returnLength)))\n    {\n        SIZE nameSize = { 0 };\n        RECT bufferRect;\n\n        GetTextExtentPoint32(\n            bufferDc,\n            text,\n            returnLength,\n            &nameSize\n            );\n\n        bufferRect.left = 0;\n        bufferRect.top = 0;\n        bufferRect.right = clientRect->right;\n        bufferRect.bottom = nameSize.cy;\n\n        SetTextColor(bufferDc, PhThemeWindowTextColor);\n        SetDCBrushColor(bufferDc, PhThemeWindowBackground2Color);\n        FillRect(bufferDc, &bufferRect, PhGetStockBrush(DC_BRUSH));\n\n        bufferRect.left += PhGetDpi(10, dpiValue);\n        DrawText(\n            bufferDc,\n            text,\n            returnLength,\n            &bufferRect,\n            DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE\n            );\n        bufferRect.left -= PhGetDpi(10, dpiValue);\n    }\n}\n\nLRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    WNDPROC oldWndProc;\n\n    if (!(oldWndProc = PhGetWindowContext(WindowHandle, LONG_MAX)))\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_NCDESTROY:\n        {\n            SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc);\n            PhRemoveWindowContext(WindowHandle, LONG_MAX);\n        }\n        break;\n    case WM_ERASEBKGND:\n        {\n            HDC hdc = (HDC)wParam;\n            RECT clientRect;\n\n            if (!PhGetClientRect(WindowHandle, &clientRect))\n                break;\n\n            ThemeWindowRenderGroupBoxControl(WindowHandle, hdc, &clientRect, oldWndProc);\n        }\n        return TRUE;\n    case WM_ENABLE:\n        if (!wParam)    // fix drawing when window visible and switches to disabled\n            return 0;\n        break;\n    case WM_PAINT:\n        {\n            PAINTSTRUCT ps;\n            BeginPaint(WindowHandle, &ps);\n            EndPaint(WindowHandle, &ps);\n        }\n        return 0;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n}\n\nVOID ThemeWindowRenderTabControl(\n    _In_ PPHP_THEME_WINDOW_TAB_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HDC bufferDc,\n    _In_ PRECT clientRect,\n    _In_ WNDPROC WindowProcedure\n    )\n{\n    //RECT windowRect;\n\n    //GetWindowRect(WindowHandle, &windowRect);\n\n    //CallWindowProc(WindowProcedure, WindowHandle, WM_PRINTCLIENT, (WPARAM)bufferDc, PRF_CLIENT);\n\n    //TabCtrl_AdjustRect(WindowHandle, FALSE, clientRect); // Make sure we don't paint in the client area.\n    //ExcludeClipRect(bufferDc, clientRect->left, clientRect->top, clientRect->right, clientRect->bottom);\n\n    //windowRect.right -= windowRect.left;\n    //windowRect.bottom -= windowRect.top;\n    //windowRect.left = 0;\n    //windowRect.top = 0;\n\n    //clientRect->left = windowRect.left;\n    //clientRect->top = windowRect.top;\n    //clientRect->right = windowRect.right;\n    //clientRect->bottom = windowRect.bottom;\n\n    SetBkMode(bufferDc, TRANSPARENT);\n    SelectFont(bufferDc, GetWindowFont(WindowHandle));\n\n    SetTextColor(bufferDc, PhThemeWindowTextColor);\n    FillRect(bufferDc, clientRect, PhThemeWindowBackgroundBrush);\n\n    //switch (PhpThemeColorMode)\n    //{\n    //case 0: // New colors\n    //    {\n    //        //SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0));\n    //        //SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_3DFACE)); // RGB(0xff, 0xff, 0xff));\n    //    }\n    //    break;\n    //case 1: // Old colors\n    //    {\n    //        //SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff));\n    //        //SetDCBrushColor(DrawInfo->hdc, PhThemeWindowBackground2Color);\n    //    }\n    //    break;\n    //}\n\n    //switch (PhpThemeColorMode)\n    //{\n    //case 0: // New colors\n    //    //SetTextColor(hdc, RGB(0x0, 0xff, 0x0));\n    //    SetDCBrushColor(hdc, GetSysColor(COLOR_3DFACE));// PhThemeWindowTextColor);\n    //    FillRect(hdc, &clientRect, PhGetStockBrush(DC_BRUSH));\n    //    break;\n    //case 1: // Old colors\n    //    //SetTextColor(hdc, PhThemeWindowTextColor);\n    //    SetDCBrushColor(hdc, RPhThemeWindowBackground2Color);\n    //    FillRect(hdc, &clientRect, PhGetStockBrush(DC_BRUSH));\n    //    break;\n    //}\n\n    INT currentSelection = TabCtrl_GetCurSel(WindowHandle);\n    INT count = TabCtrl_GetItemCount(WindowHandle);\n    RECT itemRect = { 0 };\n    //RECT itemRectHighlighted;\n    //INT itemHighlighted = INT_ERROR;\n    INT headerBottom;\n    INT oldTop;\n\n    oldTop = clientRect->top;\n    TabCtrl_GetItemRect(WindowHandle, 0, &itemRect);\n    clientRect->top += (itemRect.bottom - itemRect.top) * TabCtrl_GetRowCount(WindowHandle) + 2;\n\n    //SetDCBrushColor(bufferDc, PhThemeWindowBackground2Color);\n    //FrameRect(bufferDc, clientRect, PhGetStockBrush(DC_BRUSH));\n    headerBottom = clientRect->top;\n    clientRect->top = oldTop;\n\n    TCITEM tabItem;\n    WCHAR tabHeaderText[MAX_PATH] = L\"\";\n\n    memset(&tabItem, 0, sizeof(TCITEM));\n\n    tabItem.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_STATE;\n    tabItem.dwStateMask = TCIS_BUTTONPRESSED | TCIS_HIGHLIGHTED;\n    tabItem.cchTextMax = RTL_NUMBER_OF(tabHeaderText);\n    tabItem.pszText = tabHeaderText;\n\n    for (INT i = 0; i < count; i++)\n    {\n        if (i == currentSelection)\n            continue;\n\n        TabCtrl_GetItemRect(WindowHandle, i, &itemRect);\n\n        PhOffsetRect(&itemRect, 2, 2);\n        itemRect.bottom += itemRect.bottom + 1 < headerBottom ? 1 : -1;\n        itemRect.right += itemRect.right + 1 < clientRect->right;\n\n        if (PhPtInRect(&itemRect, &Context->CursorPos))\n        {\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    {\n            //        if (currentSelection == i)\n            //        {\n            //            SetTextColor(bufferDc, RGB(0xff, 0xff, 0xff));\n            //            SetDCBrushColor(bufferDc, PhThemeWindowHighlightColor);\n            //            FillRect(bufferDc, &itemRect, PhGetStockBrush(DC_BRUSH));\n            //        }\n            //        else\n            //        {\n            //            SetTextColor(bufferDc, PhThemeWindowTextColor);\n            //            SetDCBrushColor(bufferDc, PhThemeWindowBackgroundColor);\n            //            FillRect(bufferDc, &itemRect, PhGetStockBrush(DC_BRUSH));\n            //        }\n            //    }\n            //    break;\n            //case 1: // Old colors\n            //SetTextColor(bufferDc, PhThemeWindowTextColor);\n            SetDCBrushColor(bufferDc, PhThemeWindowHighlightColor);\n            FillRect(bufferDc, &itemRect, PhGetStockBrush(DC_BRUSH));\n\n            //itemRectHighlighted = itemRect;\n            //itemHighlighted = i;\n            //continue;\n        }\n        else\n        {\n            //switch (PhpThemeColorMode)\n            //{\n            //case 0: // New colors\n            //    {\n            //        if (currentSelection == i)\n            //        {\n            //            SetTextColor(bufferDc, RGB(0x0, 0x0, 0x0));\n            //            SetDCBrushColor(bufferDc, RGB(0xff, 0xff, 0xff));\n            //            FillRect(bufferDc, &itemRect, PhGetStockBrush(DC_BRUSH));\n            //        }\n            //        else\n            //        {\n            //            SetTextColor(bufferDc, RGB(0, 0, 0));\n            //            SetDCBrushColor(bufferDc, GetSysColor(COLOR_3DFACE));// PhThemeWindowTextColor);\n            //            FillRect(bufferDc, &itemRect, PhGetStockBrush(DC_BRUSH));\n            //        }\n            //    }\n            //    break;\n            //case 1: // Old colors\n            {\n                // SetTextColor(bufferDc, PhThemeWindowTextColor);\n                SetDCBrushColor(bufferDc, PhThemeWindowBackgroundColor);\n                FillRect(bufferDc, &itemRect, PhGetStockBrush(DC_BRUSH));\n                //SetDCBrushColor(bufferDc, PhThemeWindowBackground2Color);\n                //FrameRect(bufferDc, &itemRect, PhGetStockBrush(DC_BRUSH));\n            }\n        }\n\n        {\n            if (TabCtrl_GetItem(WindowHandle, i, &tabItem))\n            {\n                DrawText(\n                    bufferDc,\n                    tabItem.pszText,\n                    (UINT)PhCountStringZ(tabItem.pszText),\n                    &itemRect,\n                    DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX\n                    );\n            }\n        }\n    }\n\n    {\n        TabCtrl_GetItemRect(WindowHandle, currentSelection, &itemRect);\n\n        PhOffsetRect(&itemRect, 2, 2);\n        itemRect.bottom += itemRect.bottom + 1 < headerBottom ? 1 : -1;\n        itemRect.right += itemRect.right + 1 < clientRect->right;\n        PhInflateRect(&itemRect, 1, 1);     // draw selected tab slightly bigger\n        itemRect.bottom -= 1;\n        SetDCBrushColor(bufferDc, PhPtInRect(&itemRect, &Context->CursorPos) ? PhThemeWindowHighlightColor : RGB(0x50, 0x50, 0x50));\n        FillRect(bufferDc, &itemRect, PhGetStockBrush(DC_BRUSH));\n\n        if (TabCtrl_GetItem(WindowHandle, currentSelection, &tabItem))\n        {\n            DrawText(\n                bufferDc,\n                tabItem.pszText,\n                (UINT)PhCountStringZ(tabItem.pszText),\n                &itemRect,\n                DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX\n                );\n        }\n\n        //if (itemHighlighted != INT_ERROR)\n        //{\n        //    SetDCBrushColor(bufferDc, PhThemeWindowHighlightColor);\n        //    FillRect(bufferDc, &itemRectHighlighted, PhGetStockBrush(DC_BRUSH));\n\n        //    if (TabCtrl_GetItem(WindowHandle, itemHighlighted, &tabItem))\n        //    {\n        //        DrawText(\n        //            bufferDc,\n        //            tabItem.pszText,\n        //            (UINT)PhCountStringZ(tabItem.pszText),\n        //            &itemRectHighlighted,\n        //            DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX\n        //            );\n        //    }\n        //}\n    }\n}\n\nLRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_THEME_WINDOW_TAB_CONTEXT context;\n    WNDPROC oldWndProc;\n\n    if (!(context = PhGetWindowContext(WindowHandle, LONG_MAX)))\n        return FALSE;\n\n    oldWndProc = context->DefaultWindowProc;\n\n    switch (uMsg)\n    {\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, LONG_MAX);\n            SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc);\n\n            PhFree(context);\n        }\n        break;\n    case WM_ERASEBKGND:\n        return TRUE;\n    case WM_MOUSEMOVE:\n        {\n            //INT count;\n            //INT i;\n            //\n            //count = TabCtrl_GetItemCount(WindowHandle);\n            //\n            //for (i = 0; i < count; i++)\n            //{\n            //    RECT rect = { 0, 0, 0, 0 };\n            //    TCITEM entry =\n            //    {\n            //        TCIF_STATE,\n            //        0,\n            //        TCIS_HIGHLIGHTED\n            //    };\n            //\n            //    TabCtrl_GetItemRect(WindowHandle, i, &rect);\n            //    entry.dwState = PhPtInRect(&rect, context->CursorPos) ? TCIS_HIGHLIGHTED : 0;\n            //    TabCtrl_SetItem(WindowHandle, i, &entry);\n            //}\n\n            if (!context->MouseActive)\n            {\n                TRACKMOUSEEVENT trackEvent =\n                {\n                    sizeof(TRACKMOUSEEVENT),\n                    TME_LEAVE,\n                    WindowHandle,\n                    0\n                };\n\n                TrackMouseEvent(&trackEvent);\n                context->MouseActive = TRUE;\n            }\n\n            context->CursorPos.x = GET_X_LPARAM(lParam);\n            context->CursorPos.y = GET_Y_LPARAM(lParam);\n\n            InvalidateRect(WindowHandle, NULL, FALSE);\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            //INT count;\n            //INT i;\n            //\n            //count = TabCtrl_GetItemCount(WindowHandle);\n            //\n            //for (i = 0; i < count; i++)\n            //{\n            //    TCITEM entry =\n            //    {\n            //        TCIF_STATE,\n            //        0,\n            //        TCIS_HIGHLIGHTED\n            //    };\n            //\n            //    TabCtrl_SetItem(WindowHandle, i, &entry);\n            //}\n\n            context->CursorPos.x = LONG_MIN;\n            context->CursorPos.y = LONG_MIN;\n\n            context->MouseActive = FALSE;\n            InvalidateRect(WindowHandle, NULL, FALSE);\n        }\n        break;\n    case WM_PAINT:\n        {\n            //PAINTSTRUCT ps;\n            //HDC BufferedHDC;\n            //HPAINTBUFFER BufferedPaint;\n            //\n            //if (!BeginPaint(WindowHandle, &ps))\n            //    break;\n            //\n            //DEBUG_BEGINPAINT_RECT(WindowHandle, ps.rcPaint);\n            //\n            //{\n            //    RECT clientRect;\n            //    GetClientRect(WindowHandle, &clientRect);\n            //    //CallWindowProc(oldWndProc, WindowHandle, WM_PAINT, wParam, lParam);\n            //    TabCtrl_AdjustRect(WindowHandle, FALSE, &clientRect);\n            //    ExcludeClipRect(ps.hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom);\n            //}\n            //\n            //if (BufferedPaint = BeginBufferedPaint(ps.hdc, &ps.rcPaint, BPBF_COMPATIBLEBITMAP, NULL, &BufferedHDC))\n            //{\n            //    ThemeWindowRenderTabControl(context, WindowHandle, BufferedHDC, &ps.rcPaint, oldWndProc);\n            //    EndBufferedPaint(BufferedPaint, TRUE);\n            //}\n            //else\n            {\n                RECT clientRect;\n                HDC hdc;\n                HDC bufferDc;\n                HBITMAP bufferBitmap;\n                HBITMAP oldBufferBitmap;\n\n                if (!PhGetClientRect(WindowHandle, &clientRect))\n                    break;\n\n                hdc = GetDC(WindowHandle);\n                bufferDc = CreateCompatibleDC(hdc);\n                bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom);\n                oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap);\n\n                {\n                    RECT clientRect2 = clientRect;\n                    TabCtrl_AdjustRect(WindowHandle, FALSE, &clientRect2);\n                    ExcludeClipRect(hdc, clientRect2.left, clientRect2.top, clientRect2.right, clientRect2.bottom);\n                }\n\n                ThemeWindowRenderTabControl(context, WindowHandle, bufferDc, &clientRect, oldWndProc);\n\n                BitBlt(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, bufferDc, 0, 0, SRCCOPY);\n                SelectBitmap(bufferDc, oldBufferBitmap);\n                DeleteBitmap(bufferBitmap);\n                DeleteDC(bufferDc);\n                ReleaseDC(WindowHandle, hdc);\n            }\n\n            //EndPaint(WindowHandle, &ps);\n        }\n        goto DefaultWndProc;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n\nDefaultWndProc:\n    return DefWindowProc(WindowHandle, uMsg, wParam, lParam);\n}\n\nLRESULT CALLBACK PhpThemeWindowListBoxControlSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_THEME_WINDOW_STATUSBAR_CONTEXT context;\n    WNDPROC oldWndProc;\n\n    if (!(context = PhGetWindowContext(WindowHandle, LONG_MAX)))\n        return FALSE;\n\n    oldWndProc = context->DefaultWindowProc;\n\n    switch (uMsg)\n    {\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, LONG_MAX);\n            SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc);\n        }\n        break;\n    //case WM_MOUSEMOVE:\n    //case WM_NCMOUSEMOVE:\n    //    {\n    //        POINT windowPoint;\n    //        RECT windowRect;\n    //\n    //        GetCursorPos(&windowPoint);\n    //        GetWindowRect(WindowHandle, &windowRect);\n    //        context->Hot = PhPtInRect(&windowRect, windowPoint);\n    //\n    //        if (!context->HotTrack)\n    //        {\n    //            TRACKMOUSEEVENT trackMouseEvent;\n    //            trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);\n    //            trackMouseEvent.dwFlags = TME_LEAVE;\n    //            trackMouseEvent.hwndTrack = WindowHandle;\n    //            trackMouseEvent.dwHoverTime = 0;\n    //\n    //            context->HotTrack = TRUE;\n    //\n    //            TrackMouseEvent(&trackMouseEvent);\n    //        }\n    //\n    //        RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n    //    }\n    //    break;\n    //case WM_MOUSELEAVE:\n    //case WM_NCMOUSELEAVE:\n    //    {\n    //        POINT windowPoint;\n    //        RECT windowRect;\n    //\n    //        context->HotTrack = FALSE;\n    //\n    //        GetCursorPos(&windowPoint);\n    //        GetWindowRect(WindowHandle, &windowRect);\n    //        context->Hot = PhPtInRect(&windowRect, windowPoint);\n    //\n    //        RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n    //    }\n    //    break;\n    //case WM_CAPTURECHANGED:\n    //    {\n    //        POINT windowPoint;\n    //        RECT windowRect;\n    //\n    //        GetCursorPos(&windowPoint);\n    //        GetWindowRect(WindowHandle, &windowRect);\n    //        context->Hot = PhPtInRect(&windowRect, windowPoint);\n    //\n    //        RedrawWindow(WindowHandle, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);\n    //    }\n    //    break;\n    case WM_NCCALCSIZE:\n        {\n            LPNCCALCSIZE_PARAMS ncCalcSize = (NCCALCSIZE_PARAMS*)lParam;\n\n            CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n\n            PhInflateRect(&ncCalcSize->rgrc[0], 1, 1);\n        }\n        return 0;\n    case WM_NCPAINT:\n        {\n            HDC hdc;\n            ULONG flags;\n            RECT clientRect;\n            RECT windowRect;\n            HRGN updateRegion;\n            LONG dpiValue = PhGetWindowDpi(WindowHandle);\n            INT cxEdge = PhGetSystemMetrics(SM_CXEDGE, dpiValue);\n            INT cyEdge = PhGetSystemMetrics(SM_CYEDGE, dpiValue);\n\n            updateRegion = (HRGN)wParam;\n\n            if (!PhGetWindowRect(WindowHandle, &windowRect))\n                break;\n\n            // draw the scrollbar without the border.\n            {\n                HRGN rectregion = CreateRectRgn(\n                    windowRect.left + cxEdge,\n                    windowRect.top + cyEdge,\n                    windowRect.right - cxEdge,\n                    windowRect.bottom - cyEdge\n                    );\n\n                if (updateRegion != HRGN_FULL)\n                    CombineRgn(rectregion, rectregion, updateRegion, RGN_AND);\n                DefWindowProc(WindowHandle, WM_NCPAINT, (WPARAM)rectregion, 0);\n                DeleteRgn(rectregion);\n            }\n\n            if (updateRegion == HRGN_FULL)\n                updateRegion = NULL;\n\n            flags = DCX_WINDOW | DCX_CACHE | DCX_USESTYLE;\n\n            if (updateRegion)\n                flags |= DCX_INTERSECTRGN | DCX_NODELETERGN;\n\n            if (hdc = GetDCEx(WindowHandle, updateRegion, flags))\n            {\n                PhOffsetRect(&windowRect, -windowRect.left, -windowRect.top);\n                clientRect = windowRect;\n                clientRect.left += cxEdge;\n                clientRect.top += cyEdge;\n                clientRect.right -= cxEdge;\n                clientRect.bottom -= cyEdge;\n\n                {\n                    SCROLLBARINFO scrollInfo = { sizeof(SCROLLBARINFO) };\n\n                    if (GetScrollBarInfo(WindowHandle, OBJID_VSCROLL, &scrollInfo))\n                    {\n                        if ((scrollInfo.rgstate[0] & STATE_SYSTEM_INVISIBLE) == 0)\n                        {\n                            clientRect.right -= PhGetSystemMetrics(SM_CXVSCROLL, dpiValue);\n                        }\n                    }\n                }\n\n                ExcludeClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom);\n\n                if (context->Hot)\n                {\n                    SetDCBrushColor(hdc, PhThemeWindowHighlightColor);\n                    FrameRect(hdc, &windowRect, PhGetStockBrush(DC_BRUSH));\n                }\n                else\n                {\n                    SetDCBrushColor(hdc, PhThemeWindowBackground2Color);\n                    FrameRect(hdc, &windowRect, GetSysColorBrush(COLOR_WINDOWFRAME));\n                }\n\n                ReleaseDC(WindowHandle, hdc);\n                return TRUE;\n            }\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n}\n\nVOID ThemeWindowRenderComboBox(\n    _In_ PPHP_THEME_WINDOW_COMBO_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HDC bufferDc,\n    _In_ PRECT clientRect,\n    _In_ WNDPROC WindowProcedure\n    )\n{\n    RECT bufferRect =\n    {\n        0, 0,\n       clientRect->right - clientRect->left,\n       clientRect->bottom - clientRect->top\n    };\n    ULONG windowStyle = PhGetWindowStyle(WindowHandle);\n    //BOOLEAN isFocused = GetFocus() == WindowHandle;\n\n    SetBkMode(bufferDc, TRANSPARENT);\n    SelectFont(bufferDc, CallWindowProc(WindowProcedure, WindowHandle, WM_GETFONT, 0, 0));\n    SetDCBrushColor(bufferDc, PhThemeWindowBackground2Color);\n    FillRect(bufferDc, clientRect, PhGetStockBrush(DC_BRUSH));\n\n    if (PhPtInRect(clientRect, &Context->CursorPos))\n    {\n        SetDCBrushColor(bufferDc, PhThemeWindowHighlight2Color); // RGB(0, 120, 212) : RGB(68, 68, 68));\n    }\n    else\n    {\n        SetDCBrushColor(bufferDc, GetSysColor(COLOR_WINDOWFRAME));// RGB(0, 120, 212) : RGB(68, 68, 68));\n    }\n\n    SetTextColor(bufferDc, PhThemeWindowTextColor);\n    FrameRect(bufferDc, clientRect, PhGetStockBrush(DC_BRUSH));\n\n    if (Context->ThemeHandle)\n    {\n        SIZE dropdownSize = { 0 };\n\n        PhGetThemePartSize(\n            Context->ThemeHandle,\n            bufferDc,\n            CP_DROPDOWNBUTTONRIGHT,\n            CBXSR_NORMAL,\n            NULL,\n            THEMEPARTSIZE_TRUE,\n            &dropdownSize\n            );\n\n        bufferRect.left = clientRect->right - dropdownSize.cy;\n\n        PhDrawThemeBackground(\n            Context->ThemeHandle,\n            bufferDc,\n            CP_DROPDOWNBUTTONRIGHT,\n            CBXSR_DISABLED,\n            &bufferRect,\n            NULL\n            );\n\n        bufferRect.left = 0;\n    }\n    else\n    {\n        DrawFrameControl(bufferDc, &bufferRect, DFC_SCROLL, DFCS_SCROLLDOWN);\n    }\n\n    if ((windowStyle & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)\n    {\n        INT index = ComboBox_GetCurSel(WindowHandle);\n\n        if (index == CB_ERR)\n            return;\n\n        INT length = ComboBox_GetLBTextLen(WindowHandle, index);\n\n        if (length == CB_ERR)\n            return;\n\n        if (length < MAX_PATH)\n        {\n            WCHAR comboText[MAX_PATH] = L\"\";\n\n            if (ComboBox_GetLBText(WindowHandle, index, comboText) == CB_ERR)\n                return;\n\n            bufferRect.left += 5;\n            bufferRect.right -= 15; // info.rcItem.right\n            DrawText(\n                bufferDc,\n                comboText,\n                (UINT)PhCountStringZ(comboText),\n                &bufferRect,\n                DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS\n                );\n        }\n    }\n}\n\nVOID ThemeWindowComboBoxExcludeRect(\n    _In_ PPHP_THEME_WINDOW_COMBO_CONTEXT Context,\n    _In_ HWND WindowHandle,\n    _In_ HDC Hdc,\n    _In_ PRECT clientRect,\n    _In_ WNDPROC WindowProcedure\n    )\n{\n    ULONG windowStyle = PhGetWindowStyle(WindowHandle);\n\n    if ((windowStyle & CBS_DROPDOWNLIST) != CBS_DROPDOWNLIST || (windowStyle & CBS_DROPDOWN) != CBS_DROPDOWN)\n    {\n        COMBOBOXINFO info = { sizeof(COMBOBOXINFO) };\n\n        if (CallWindowProc(WindowProcedure, WindowHandle, CB_GETCOMBOBOXINFO, 0, (LPARAM)&info))\n        {\n            //INT borderSize = 0;\n            //if (Context->ThemeHandle)\n            //{\n            //    if (PhGetThemeInt(Context->ThemeHandle, 0, 0, TMT_BORDERSIZE, &borderSize))\n            //    {\n            //        borderSize = borderSize * 2;\n            //    }\n            //}\n\n            ExcludeClipRect(\n                Hdc,\n                info.rcItem.left,\n                info.rcItem.top,\n                info.rcItem.right,\n                info.rcItem.bottom\n                );\n        }\n    }\n}\n\nLRESULT CALLBACK PhpThemeWindowComboBoxControlSubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_THEME_WINDOW_COMBO_CONTEXT context;\n    WNDPROC oldWndProc;\n\n    if (!(context = PhGetWindowContext(WindowHandle, LONG_MAX)))\n        return FALSE;\n\n    oldWndProc = context->DefaultWindowProc;\n\n    switch (uMsg)\n    {\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, LONG_MAX);\n            SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc);\n\n            if (context->ThemeHandle)\n            {\n                PhCloseThemeData(context->ThemeHandle);\n            }\n\n            PhFree(context);\n        }\n        break;\n    case WM_THEMECHANGED:\n        {\n            if (context->ThemeHandle)\n            {\n                PhCloseThemeData(context->ThemeHandle);\n                context->ThemeHandle = NULL;\n            }\n\n            context->ThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_COMBOBOX, PhGetWindowDpi(WindowHandle));\n        }\n        break;\n    case WM_ERASEBKGND:\n        return TRUE;\n    case WM_MOUSEMOVE:\n        {\n            context->CursorPos.x = GET_X_LPARAM(lParam);\n            context->CursorPos.y = GET_Y_LPARAM(lParam);\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            context->CursorPos.x = LONG_MIN;\n            context->CursorPos.y = LONG_MIN;\n        }\n        break;\n    case WM_PAINT:\n        {\n            //PAINTSTRUCT ps;\n            //HDC BufferedHDC;\n            //HPAINTBUFFER BufferedPaint;\n            //\n            //if (!BeginPaint(WindowHandle, &ps))\n            //    break;\n            //\n            //DEBUG_BEGINPAINT_RECT(WindowHandle, ps.rcPaint);\n            //\n            //if (BufferedPaint = BeginBufferedPaint(ps.hdc, &ps.rcPaint, BPBF_COMPATIBLEBITMAP, NULL, &BufferedHDC))\n            //{\n            //    ThemeWindowComboBoxExcludeRect(WindowHandle, ps.hdc, &ps.rcPaint, oldWndProc, context);\n            //    ThemeWindowRenderComboBox(WindowHandle, BufferedHDC, &ps.rcPaint, oldWndProc, context);\n            //    EndBufferedPaint(BufferedPaint, TRUE);\n            //}\n            //else\n            {\n                RECT clientRect;\n                HDC hdc;\n                HDC bufferDc;\n                HBITMAP bufferBitmap;\n                HBITMAP oldBufferBitmap;\n\n                if (!PhGetClientRect(WindowHandle, &clientRect))\n                    break;\n\n                hdc = GetDC(WindowHandle);\n                bufferDc = CreateCompatibleDC(hdc);\n                bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom);\n                oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap);\n\n                ThemeWindowComboBoxExcludeRect(context, WindowHandle, hdc, &clientRect, oldWndProc);\n                ThemeWindowRenderComboBox(context, WindowHandle, bufferDc, &clientRect, oldWndProc);\n\n                BitBlt(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, bufferDc, 0, 0, SRCCOPY);\n                SelectBitmap(bufferDc, oldBufferBitmap);\n                DeleteBitmap(bufferBitmap);\n                DeleteDC(bufferDc);\n                ReleaseDC(WindowHandle, hdc);\n            }\n\n            //EndPaint(WindowHandle, &ps);\n        }\n        goto DefaultWndProc;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n\nDefaultWndProc:\n    return DefWindowProc(WindowHandle, uMsg, wParam, lParam);\n}\n\nLRESULT CALLBACK PhpThemeWindowACLUISubclassProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n)\n{\n    WNDPROC oldWndProc;\n\n    if (!(oldWndProc = PhGetWindowContext(WindowHandle, LONG_MAX)))\n        return FALSE;\n\n    switch (uMsg)\n    {\n    case WM_VSCROLL:\n    case WM_MOUSEWHEEL:\n        InvalidateRect(WindowHandle, NULL, FALSE);\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR data = (LPNMHDR)lParam;\n\n            if (data->code == NM_CUSTOMDRAW)\n            {\n                LPNMCUSTOMDRAW customDraw = (LPNMCUSTOMDRAW)lParam;\n                WCHAR className[MAX_PATH];\n\n                if (customDraw->dwDrawStage == CDDS_PREPAINT && !(customDraw->uItemState & CDIS_FOCUS))\n                {\n                    if (!GetClassName(customDraw->hdr.hwndFrom, className, RTL_NUMBER_OF(className)))\n                        className[0] = UNICODE_NULL;\n                    if (PhEqualStringZ(className, WC_BUTTON, FALSE))\n                    {\n                        HDC hdc = GetDC(WindowHandle);\n                        RECT rectControl = customDraw->rc;\n                        PhInflateRect(&rectControl, 2, 2);\n                        MapWindowRect(customDraw->hdr.hwndFrom, WindowHandle, &rectControl);\n                        FillRect(hdc, &rectControl, PhThemeWindowBackgroundBrush);   // fix the annoying white border left by the previous active control\n                        ReleaseDC(WindowHandle, hdc);\n                    }\n                }\n            }\n        }\n        break;\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContext(WindowHandle, LONG_MAX);\n            SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc);\n        }\n        break;\n    case WM_ERASEBKGND:\n        {\n            HDC hdc = (HDC)wParam;\n            RECT clientRect;\n\n            GetClipBox(hdc, &clientRect);\n            FillRect(hdc, &clientRect, PhThemeWindowBackgroundBrush);\n        }\n        return TRUE;\n    case WM_CTLCOLORSTATIC:\n        {\n            HDC hdc = (HDC)wParam;\n\n            SetBkMode(hdc, TRANSPARENT);\n            SetTextColor(hdc, PhThemeWindowTextColor);\n            return (INT_PTR)PhThemeWindowBackgroundBrush;\n        }\n    }\n    return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);\n}\n"
  },
  {
    "path": "phlib/treenew.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2011-2016\n *     dmex    2017-2023\n *\n */\n\n/*\n * The tree new is a tree view with columns. Unlike the old tree list control, which was a wrapper\n * around the list view control, this control was written from scratch.\n *\n * Current issues not included in any comments:\n * * Adding, removing or changing columns does not cause invalidation.\n * * It is not possible to change a column to make it fixed. The current fixed column must be\n *   removed and the new fixed column must then be added.\n * * When there are no visible normal columns, the space usually occupied by the normal column\n *   headers is filled with a solid background color. We should catch this and paint the usual\n *   themed background there instead.\n * * It is not possible to update any TN_STYLE_* flags after the control is created.\n *\n * Possible additions:\n * * More flexible mouse input callbacks to allow custom controls inside columns.\n * * Allow custom drawn columns to customize their behaviour when TN_FLAG_ITEM_DRAG_SELECT is set\n *   (e.g. disable drag selection over certain areas).\n * * Virtual mode\n */\n\n#include <ph.h>\n#include <guisup.h>\n#include <treenew.h>\n#include <treenewp.h>\n#include <vssym32.h>\n\n/**\n * Initializes the treenew window class.\n * \\return RTL_ATOM Returns an atom representing the initialized window class.\n */\nRTL_ATOM PhTreeNewInitialization(\n    VOID\n    )\n{\n    WNDCLASSEX wcex;\n\n    memset(&wcex, 0, sizeof(WNDCLASSEX));\n    wcex.cbSize = sizeof(WNDCLASSEX);\n    wcex.style = CS_DBLCLKS | CS_GLOBALCLASS;\n    wcex.lpfnWndProc = PhTnpWndProc;\n    wcex.cbClsExtra = 0;\n    wcex.cbWndExtra = sizeof(PVOID);\n    wcex.hInstance = NtCurrentImageBase();\n    wcex.hCursor = PhLoadCursor(NULL, IDC_ARROW);\n    wcex.lpszClassName = PH_TREENEW_CLASSNAME;\n\n    return RegisterClassEx(&wcex);\n}\n\n/**\n * Window procedure for the treenew control.\n *\n * \\param WindowHandle Handle to the window receiving the message.\n * \\param WindowMessage The message identifier.\n * \\param wParam Additional message-specific information (depends on the message).\n * \\param lParam Additional message-specific information (depends on the message).\n * \\return The result of the message processing (depends on the message).\n */\nLRESULT CALLBACK PhTnpWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_TREENEW_CONTEXT context;\n\n    if (WindowMessage == WM_NCCREATE)\n    {\n        context = PhTnpCreateTreeNewContext();\n        PhSetWindowContextEx(WindowHandle, context);\n    }\n    else\n    {\n        context = PhGetWindowContextEx(WindowHandle);\n    }\n\n    if (!context)\n        return DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n\n    if (context->Tracking && (GetAsyncKeyState(VK_ESCAPE) & 0x1))\n    {\n        PhTnpCancelTrack(context);\n    }\n\n    // Note: if we have suspended restructuring, we *cannot* access any nodes, because all node\n    // pointers are now invalid. Below, we disable all input.\n\n    switch (WindowMessage)\n    {\n    case WM_CREATE:\n        {\n            if (!PhTnpOnCreate(WindowHandle, context, (CREATESTRUCT *)lParam))\n                return -1;\n        }\n        return 0;\n    case WM_DESTROY:\n        {\n            context->Callback(WindowHandle, TreeNewDestroying, NULL, NULL, context->CallbackContext);\n        }\n        return 0;\n    case WM_NCDESTROY:\n        {\n            PhRemoveWindowContextEx(WindowHandle);\n\n            PhTnpDestroyTreeNewContext(context);\n        }\n        return 0;\n    case WM_SIZE:\n        {\n            PhTnpOnSize(WindowHandle, context);\n        }\n        break;\n    case WM_ERASEBKGND:\n        return TRUE;\n    case WM_PAINT:\n        {\n            PhTnpOnPaint(WindowHandle, context);\n        }\n        return 0;\n    case WM_PRINTCLIENT:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnPrintClient(WindowHandle, context, (HDC)wParam, (ULONG)lParam);\n        }\n        return 0;\n    case WM_NCPAINT:\n        {\n            if (PhTnpOnNcPaint(WindowHandle, context, (HRGN)wParam))\n                return 0;\n        }\n        break;\n    case WM_GETFONT:\n        return (LRESULT)context->Font;\n    case WM_SETFONT:\n        {\n            PhTnpOnSetFont(WindowHandle, context, (HFONT)wParam, LOWORD(lParam));\n        }\n        break;\n    case WM_STYLECHANGED:\n        {\n            PhTnpOnStyleChanged(WindowHandle, context, (LONG)wParam, (STYLESTRUCT *)lParam);\n        }\n        break;\n    case WM_SETTINGCHANGE:\n        {\n            PhTnpOnSettingChange(WindowHandle, context);\n        }\n        break;\n    case WM_THEMECHANGED:\n        {\n            PhTnpOnThemeChanged(WindowHandle, context);\n        }\n        break;\n    case WM_DPICHANGED_AFTERPARENT:\n        {\n            PhTnpOnDpiChanged(WindowHandle, context);\n        }\n        break;\n    case WM_GETDLGCODE:\n        {\n            return PhTnpOnGetDlgCode(WindowHandle, context, (ULONG)wParam, (PMSG)lParam);\n        }\n        break;\n    case WM_ACTIVATE:\n        {\n            if (LOWORD(wParam) == WA_INACTIVE)\n            {\n                // Hide tooltip when window is deactivated\n                PhTnpPopTooltip(context);\n            }\n        }\n        break;\n    case WM_SETFOCUS:\n        {\n            context->HasFocus = TRUE;\n            InvalidateRect(context->Handle, NULL, FALSE);\n        }\n        return 0;\n    case WM_KILLFOCUS:\n        {\n            //if (!context->ContextMenuActive && !(context->Style & TN_STYLE_ALWAYS_SHOW_SELECTION))\n            //    PhTnpSelectRange(context, -1, -1, TN_SELECT_RESET, NULL, NULL);\n\n            context->HasFocus = FALSE;\n\n            // Immediately hide tooltip on focus loss.\n            PhTnpPopTooltip(context);\n\n            InvalidateRect(context->Handle, NULL, FALSE);\n        }\n        return 0;\n    case WM_SETCURSOR:\n        {\n            if (PhTnpOnSetCursor(WindowHandle, context, (HWND)wParam, LOWORD(lParam), HIWORD(lParam)))\n                return TRUE;\n        }\n        break;\n    case WM_TIMER:\n        {\n            PhTnpOnTimer(WindowHandle, context, (ULONG)wParam);\n        }\n        return 0;\n    case WM_MOUSEMOVE:\n        {\n            context->MouseLocation.x = GET_X_LPARAM(lParam);\n            context->MouseLocation.y = GET_Y_LPARAM(lParam);\n\n            if (context->SuspendUpdateStructure)\n                context->SuspendUpdateMoveMouse = TRUE;\n            else\n            {\n                PhTnpOnMouseMove(WindowHandle, context, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n            }\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            //if (!context->ContextMenuActive && !(context->Style & TN_STYLE_ALWAYS_SHOW_SELECTION))\n            //{\n            //    ULONG changedStart;\n            //    ULONG changedEnd;\n            //    RECT rect;\n            //\n            //    PhTnpSelectRange(context, -1, -1, TN_SELECT_RESET, &changedStart, &changedEnd);\n            //\n            //    if (PhTnpGetRowRects(context, changedStart, changedEnd, TRUE, &rect))\n            //    {\n            //        InvalidateRect(context->Handle, &rect, FALSE);\n            //    }\n            //}\n\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnMouseLeave(WindowHandle, context);\n        }\n        break;\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_LBUTTONDBLCLK:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_RBUTTONDBLCLK:\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n    case WM_MBUTTONDBLCLK:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnXxxButtonXxx(WindowHandle, context, WindowMessage, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        break;\n    case WM_CAPTURECHANGED:\n        {\n            PhTnpOnCaptureChanged(WindowHandle, context);\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnKeyDown(WindowHandle, context, (ULONG)wParam, (ULONG)lParam);\n        }\n        break;\n    case WM_CHAR:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnChar(WindowHandle, context, (ULONG)wParam, (ULONG)lParam);\n        }\n        return 0;\n    case WM_MOUSEWHEEL:\n        {\n            PhTnpOnMouseWheel(WindowHandle, context, (SHORT)HIWORD(wParam), LOWORD(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        break;\n    case WM_MOUSEHWHEEL:\n        {\n            PhTnpOnMouseHWheel(WindowHandle, context, (SHORT)HIWORD(wParam), LOWORD(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnContextMenu(WindowHandle, context, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        return 0;\n    case WM_VSCROLL:\n        {\n            PhTnpOnVScroll(WindowHandle, context, LOWORD(wParam), HIWORD(wParam));\n        }\n        return 0;\n    case WM_HSCROLL:\n        {\n            PhTnpOnHScroll(WindowHandle, context, LOWORD(wParam), HIWORD(wParam));\n        }\n        return 0;\n    case WM_NOTIFY:\n        {\n            LRESULT result;\n\n            if (PhTnpOnNotify(WindowHandle, context, (NMHDR *)lParam, &result))\n                return result;\n        }\n        break;\n    case WM_MEASUREITEM:\n        if (context->ThemeSupport && PhThemeWindowMeasureItem(WindowHandle, (LPMEASUREITEMSTRUCT)lParam))\n            return TRUE;\n        break;\n    case WM_DRAWITEM:\n        if (PhThemeWindowDrawItem(WindowHandle, (LPDRAWITEMSTRUCT)lParam))\n            return TRUE;\n        break;\n    case WM_CTLCOLORSCROLLBAR:\n        if (context->ThemeSupport)\n            return HANDLE_WM_CTLCOLORSCROLLBAR(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n        break;\n    case WM_CTLCOLORSTATIC:\n        if (context->ThemeSupport)\n            return HANDLE_WM_CTLCOLORSTATIC(WindowHandle, wParam, lParam, PhWindowThemeControlColor);\n        break;\n    }\n\n    if (WindowMessage >= TNM_FIRST && WindowMessage <= TNM_LAST)\n    {\n        return PhTnpOnUserMessage(WindowHandle, context, WindowMessage, wParam, lParam);\n    }\n\n    switch (WindowMessage)\n    {\n    case WM_MOUSEMOVE:\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n        {\n            if (context->TooltipsHandle)\n            {\n                MSG message;\n\n                message.hwnd = WindowHandle;\n                message.message = WindowMessage;\n                message.wParam = wParam;\n                message.lParam = lParam;\n                SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n        }\n        break;\n    }\n\n    return DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n}\n\n/**\n * Default null callback function for the treenew control.\n *\n * \\param WindowHandle Handle to the treenew window.\n * \\param Message The treenew message identifier.\n * \\param Parameter1 First message-specific parameter.\n * \\param Parameter2 Second message-specific parameter.\n * \\param Context User-defined context pointer.\n * \\return Always returns FALSE.\n */\n_Function_class_(PH_TREENEW_CALLBACK)\nBOOLEAN NTAPI PhTnpNullCallback(\n    _In_ HWND WindowHandle,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    )\n{\n    return FALSE;\n}\n\n/**\n * Creates a new PPH_TREENEW_CONTEXT structure for use with the treenew control.\n * \\return A pointer to the newly created PPH_TREENEW_CONTEXT structure.\n */\nPPH_TREENEW_CONTEXT PhTnpCreateTreeNewContext(\n    VOID\n    )\n{\n    PPH_TREENEW_CONTEXT context;\n\n    context = PhAllocateZero(sizeof(PH_TREENEW_CONTEXT));\n    context->FixedWidthMinimum = 20;\n    context->RowHeight = 1; // must never be 0\n    context->HotNodeIndex = ULONG_MAX;\n    context->Callback = PhTnpNullCallback;\n    context->FlatList = PhCreateList(32);\n    context->TooltipIndex = ULONG_MAX;\n    context->TooltipId = ULONG_MAX;\n    context->TooltipColumnId = ULONG_MAX;\n    context->EnableRedraw = 1;\n    context->DefaultBackColor = GetSysColor(COLOR_WINDOW); // RGB(0xff, 0xff, 0xff)\n    context->DefaultForeColor = GetSysColor(COLOR_WINDOWTEXT); // RGB(0x00, 0x00, 0x00)\n\n   return context;\n}\n\n/**\n * Destroys a treenew context.\n * \\param Context A pointer to the PPH_TREENEW_CONTEXT structure to be destroyed.\n */\nVOID PhTnpDestroyTreeNewContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (Context->Columns)\n    {\n        for (ULONG i = 0; i < Context->NextId; i++)\n        {\n            if (Context->Columns[i])\n                PhFree(Context->Columns[i]);\n        }\n\n        PhFree(Context->Columns);\n    }\n\n    if (Context->ColumnsByDisplay)\n        PhFree(Context->ColumnsByDisplay);\n\n    PhDereferenceObject(Context->FlatList);\n\n    if (Context->FontOwned)\n        DeleteFont(Context->Font);\n\n    if (Context->ThemeData)\n        PhCloseThemeData(Context->ThemeData);\n\n    if (Context->SearchString)\n        PhFree(Context->SearchString);\n\n    if (Context->TooltipText)\n        PhDereferenceObject(Context->TooltipText);\n\n    if (Context->BufferedContext)\n        PhTnpDestroyBufferedContext(Context);\n\n    if (Context->SuspendUpdateRegion)\n        DeleteRgn(Context->SuspendUpdateRegion);\n\n    if (Context->HeaderThemeHandle)\n        PhCloseThemeData(Context->HeaderThemeHandle);\n\n    if (Context->HeaderBoldFontHandle)\n        DeleteFont(Context->HeaderBoldFontHandle);\n\n    PhFree(Context);\n}\n\n/**\n * Handles the creation message of a treenew control.\n *\n * \\param WindowHandle The handle to the window being created for the tree new control.\n * \\param Context A pointer to the PPH_TREENEW_CONTEXT structure that holds the context for the tree new control.\n * \\param CreateStruct A pointer to a constant CREATESTRUCT structure containing the creation parameters.\n * \\return TRUE if the creation and initialization were successful; otherwise, FALSE.\n */\nBOOLEAN PhTnpOnCreate(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ CONST CREATESTRUCT *CreateStruct\n    )\n{\n    ULONG headerStyle;\n    PPH_TREENEW_CREATEPARAMS createParamaters;\n\n    Context->Handle = WindowHandle;\n    Context->InstanceHandle = CreateStruct->hInstance;\n    Context->Style = CreateStruct->style;\n    Context->ExtendedStyle = CreateStruct->dwExStyle;\n    createParamaters = CreateStruct->lpCreateParams;\n\n    if (Context->Style & TN_STYLE_DOUBLE_BUFFERED)\n        Context->DoubleBuffered = TRUE;\n    if ((Context->Style & TN_STYLE_ANIMATE_DIVIDER) && Context->DoubleBuffered)\n        Context->AnimateDivider = TRUE;\n\n    headerStyle = HDS_HORZ | HDS_FULLDRAG;\n\n    if (!(Context->Style & TN_STYLE_NO_COLUMN_SORT))\n        headerStyle |= HDS_BUTTONS;\n    if (!(Context->Style & TN_STYLE_NO_COLUMN_HEADER))\n        headerStyle |= WS_VISIBLE;\n\n    if (createParamaters)\n    {\n        if (Context->Style & TN_STYLE_CUSTOM_COLORS && RTL_CONTAINS_FIELD(createParamaters, createParamaters->Size, SelectionColor))\n        {\n            Context->CustomTextColor = createParamaters->TextColor ? createParamaters->TextColor : RGB(0xff, 0xff, 0xff);\n            Context->CustomFocusColor = createParamaters->FocusColor ? createParamaters->FocusColor : RGB(0x0, 0x0, 0xff);\n            Context->CustomSelectedColor = createParamaters->SelectionColor ? createParamaters->SelectionColor : RGB(0x0, 0x0, 0x80);\n            Context->CustomColors = TRUE;\n        }\n        else\n        {\n            Context->CustomTextColor = GetSysColor(COLOR_WINDOWTEXT);\n            Context->CustomFocusColor = GetSysColor(COLOR_HOTLIGHT);\n            Context->CustomSelectedColor = GetSysColor(COLOR_HIGHLIGHT);\n        }\n\n        if (RTL_CONTAINS_FIELD(createParamaters, createParamaters->Size, RowHeight) && createParamaters->RowHeight)\n        {\n            Context->CustomRowHeight = TRUE;\n            Context->RowHeight = max(createParamaters->RowHeight, 1);\n        }\n    }\n    else\n    {\n        Context->CustomTextColor = GetSysColor(COLOR_WINDOWTEXT);\n        Context->CustomFocusColor = GetSysColor(COLOR_HOTLIGHT);\n        Context->CustomSelectedColor = GetSysColor(COLOR_HIGHLIGHT);\n    }\n\n    if (Context->Style & TN_STYLE_CUSTOM_HEADERDRAW)\n        Context->HeaderCustomDraw = TRUE;\n\n    if (!(Context->FixedHeaderHandle = PhCreateWindow(\n        WC_HEADER,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | headerStyle,\n        0,\n        0,\n        0,\n        0,\n        WindowHandle,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n    if (!(Context->Style & TN_STYLE_NO_COLUMN_REORDER))\n        headerStyle |= HDS_DRAGDROP;\n\n    if (!(Context->HeaderHandle = PhCreateWindow(\n        WC_HEADER,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | headerStyle,\n        0,\n        0,\n        0,\n        0,\n        WindowHandle,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n    if (!(Context->VScrollHandle = PhCreateWindow(\n        WC_SCROLLBAR,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_VERT,\n        0,\n        0,\n        0,\n        0,\n        WindowHandle,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n    if (!(Context->HScrollHandle = PhCreateWindow(\n        WC_SCROLLBAR,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_HORZ,\n        0,\n        0,\n        0,\n        0,\n        WindowHandle,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n    if (!(Context->FillerBoxHandle = PhCreateWindow(\n        WC_STATIC,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,\n        0,\n        0,\n        0,\n        0,\n        WindowHandle,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n#if defined(DEBUG)\n    CLIENT_ID clientId;\n    assert(NT_SUCCESS(PhGetWindowClientId(WindowHandle, &clientId)));\n    Context->UniqueThread = clientId.UniqueThread;\n#endif\n\n    PhTnpUpdateSystemMetrics(Context);\n    PhTnpSetFont(Context, NULL, FALSE); // use default font\n    PhTnpInitializeTooltips(Context);\n\n    return TRUE;\n}\n\n/**\n * Handles the WM_SIZE message for the treenew control.\n *\n * \\param WindowHandle Handle to the window being resized.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpOnSize(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (!PhGetClientRect(WindowHandle, &Context->ClientRect))\n        return;\n\n    if (Context->BufferedContext && (\n        Context->BufferedContextRect.right < Context->ClientRect.right ||\n        Context->BufferedContextRect.bottom < Context->ClientRect.bottom))\n    {\n        // Invalidate the buffered context because the client size has increased.\n        PhTnpDestroyBufferedContext(Context);\n    }\n\n    PhTnpLayout(Context);\n\n    if (Context->TooltipsHandle)\n    {\n        TOOLINFO toolInfo;\n\n        memset(&toolInfo, 0, sizeof(TOOLINFO));\n        toolInfo.cbSize = sizeof(TOOLINFO);\n        toolInfo.hwnd = WindowHandle;\n        toolInfo.uId = TNP_TOOLTIPS_ITEM;\n        toolInfo.rect = Context->ClientRect;\n        SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo);\n    }\n}\n\n/**\n * Handles the WM_SETFONT message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Font Handle to the font to set, or NULL for default.\n * \\param Redraw Whether to redraw the control after setting the font.\n */\nVOID PhTnpOnSetFont(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HFONT Font,\n    _In_ LOGICAL Redraw\n    )\n{\n    PhTnpSetFont(Context, Font, !!Redraw);\n    PhTnpLayout(Context);\n}\n\n/**\n * Handles the WM_STYLECHANGED message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Type Specifies whether the style or extended style changed.\n * \\param StyleStruct Pointer to a STYLESTRUCT structure with style information.\n */\nVOID PhTnpOnStyleChanged(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Type,\n    _In_ STYLESTRUCT *StyleStruct\n    )\n{\n    if (Type == GWL_EXSTYLE)\n        Context->ExtendedStyle = StyleStruct->styleNew;\n}\n\n/**\n * Handles the WM_SETTINGCHANGE message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpOnSettingChange(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    PhTnpUpdateSystemMetrics(Context);\n    PhTnpUpdateTextMetrics(Context);\n    PhTnpLayout(Context);\n}\n\n/**\n * Handles the WM_THEMECHANGED message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpOnThemeChanged(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    PhTnpUpdateThemeData(Context);\n}\n\n/**\n * Handles the WM_DPICHANGED_AFTERPARENT message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpOnDpiChanged(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    LONG oldWindowDpi = Context->WindowDpi;\n\n    PhTnpSetRedraw(Context, FALSE);\n\n    PhTnpUpdateSystemMetrics(Context);\n    PhTnpUpdateTextMetrics(Context);\n    PhTnpUpdateThemeData(Context);\n    PhTnpUpdateColumnHeadersDpiChanged(Context, oldWindowDpi, Context->WindowDpi);\n\n    {\n        PH_TREENEW_DPICHANGED_EVENT dpiChangedEvent;\n\n        memset(&dpiChangedEvent, 0, sizeof(PH_TREENEW_DPICHANGED_EVENT));\n        dpiChangedEvent.OldWindowDpi = oldWindowDpi;\n        dpiChangedEvent.NewWindowDpi = Context->WindowDpi;\n\n        Context->Callback(Context->Handle, TreeNewDpiChanged, &dpiChangedEvent, NULL, Context->CallbackContext);\n    }\n\n    PhTnpSetRedraw(Context, TRUE);\n\n    PhTnpLayout(Context);\n}\n\n/**\n * Handles the WM_GETDLGCODE message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param VirtualKey The virtual key code.\n * \\param Message Optional pointer to a MSG structure.\n * \\return The dialog code flags.\n */\nULONG PhTnpOnGetDlgCode(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey,\n    _In_opt_ PMSG Message\n    )\n{\n    ULONG code = 0;\n\n    if (Context->Callback(WindowHandle, TreeNewGetDialogCode, UlongToPtr(VirtualKey), &code, Context->CallbackContext))\n    {\n        return code;\n    }\n\n    return DLGC_WANTARROWS | DLGC_WANTCHARS;\n}\n\n/**\n * Handles the WM_PAINT message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpOnPaint(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT updateRect;\n    HDC hdc;\n    PAINTSTRUCT paintStruct;\n\n    if (GetUpdateRect(WindowHandle, &updateRect, FALSE) && (updateRect.left | updateRect.right | updateRect.top | updateRect.bottom))\n    {\n        if (Context->EnableRedraw <= 0)\n        {\n            HRGN updateRegion;\n\n            updateRegion = CreateRectRgn(0, 0, 0, 0);\n            GetUpdateRgn(WindowHandle, updateRegion, FALSE);\n\n            if (!Context->SuspendUpdateRegion)\n            {\n                Context->SuspendUpdateRegion = updateRegion;\n            }\n            else\n            {\n                CombineRgn(Context->SuspendUpdateRegion, Context->SuspendUpdateRegion, updateRegion, RGN_OR);\n                DeleteRgn(updateRegion);\n            }\n\n            // Pretend we painted something; this ensures the update region is validated properly.\n            if (BeginPaint(WindowHandle, &paintStruct))\n                EndPaint(WindowHandle, &paintStruct);\n\n            return;\n        }\n\n        if (hdc = BeginPaint(WindowHandle, &paintStruct))\n        {\n            updateRect = paintStruct.rcPaint;\n\n            if (Context->DoubleBuffered)\n            {\n                if (!Context->BufferedContext)\n                {\n                    PhTnpCreateBufferedContext(Context, hdc);\n                }\n            }\n\n            if (Context->BufferedContext)\n            {\n                PhTnpPaint(WindowHandle, Context, Context->BufferedContext, &updateRect);\n                BitBlt(\n                    hdc,\n                    updateRect.left,\n                    updateRect.top,\n                    updateRect.right - updateRect.left,\n                    updateRect.bottom - updateRect.top,\n                    Context->BufferedContext,\n                    updateRect.left,\n                    updateRect.top,\n                    SRCCOPY\n                    );\n            }\n            else\n            {\n                PhTnpPaint(WindowHandle, Context, hdc, &updateRect);\n            }\n\n            EndPaint(WindowHandle, &paintStruct);\n        }\n    }\n}\n\n/**\n * Handles the WM_PRINTCLIENT message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param hdc Device context to print to.\n * \\param Flags Print flags.\n */\nVOID PhTnpOnPrintClient(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ ULONG Flags\n    )\n{\n    PhTnpPaint(WindowHandle, Context, hdc, &Context->ClientRect);\n}\n\n/**\n * Handles the WM_NCPAINT message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param UpdateRegion Optional region to update.\n * \\return TRUE if the non-client area was painted, FALSE otherwise.\n */\nBOOLEAN PhTnpOnNcPaint(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HRGN UpdateRegion\n    )\n{\n    PhTnpInitializeThemeData(Context);\n\n    // Themed border\n    if ((Context->ExtendedStyle & WS_EX_CLIENTEDGE) && Context->ThemeData)\n    {\n        HDC hdc;\n        ULONG flags;\n\n        if (UpdateRegion == HRGN_FULL)\n            UpdateRegion = NULL;\n\n        // Note the use of undocumented flags below. GetDCEx doesn't work without these.\n\n        flags = DCX_WINDOW | DCX_CACHE | DCX_USESTYLE;\n\n        if (UpdateRegion)\n            flags |= DCX_INTERSECTRGN | DCX_NODELETERGN;\n\n        if (hdc = GetDCEx(WindowHandle, UpdateRegion, flags))\n        {\n            PhTnpDrawThemedBorder(Context, hdc);\n            ReleaseDC(WindowHandle, hdc);\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Handles the WM_SETCURSOR message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param CursorWindowHandle Handle to the window receiving the cursor.\n * \\param HitTest Hit test value.\n * \\param Source Source of the cursor event.\n * \\return TRUE if the cursor was set, FALSE otherwise.\n */\nBOOLEAN PhTnpOnSetCursor(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HWND CursorWindowHandle,\n    _In_ ULONG HitTest,\n    _In_ ULONG Source\n    )\n{\n    POINT point;\n\n    if (\n        PhGetClientPos(WindowHandle, &point) && \n        TNP_HIT_TEST_FIXED_DIVIDER(point.x, Context)\n        )\n    {\n        PhSetCursor(PhLoadDividerCursor());\n        return TRUE;\n    }\n\n    if (Context->Cursor)\n    {\n        PhSetCursor(Context->Cursor);\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Handles the WM_TIMER message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Id Timer identifier.\n */\nVOID PhTnpOnTimer(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    )\n{\n    if (Id == TNP_TIMER_ANIMATE_DIVIDER)\n    {\n        RECT dividerRect;\n\n        dividerRect.left = Context->FixedWidth;\n        dividerRect.top = Context->HeaderHeight;\n        dividerRect.right = Context->FixedWidth + 1;\n        dividerRect.bottom = Context->ClientRect.bottom;\n\n        if (Context->AnimateDividerFadingIn)\n        {\n            Context->DividerHot += TNP_ANIMATE_DIVIDER_INCREMENT;\n\n            if (Context->DividerHot >= 100)\n            {\n                Context->DividerHot = 100;\n                Context->AnimateDividerFadingIn = FALSE;\n                PhKillTimer(WindowHandle, TNP_TIMER_ANIMATE_DIVIDER);\n            }\n\n            InvalidateRect(WindowHandle, &dividerRect, FALSE);\n        }\n        else if (Context->AnimateDividerFadingOut)\n        {\n            if (Context->DividerHot <= TNP_ANIMATE_DIVIDER_DECREMENT)\n            {\n                Context->DividerHot = 0;\n                Context->AnimateDividerFadingOut = FALSE;\n                PhKillTimer(WindowHandle, TNP_TIMER_ANIMATE_DIVIDER);\n            }\n            else\n            {\n                Context->DividerHot -= TNP_ANIMATE_DIVIDER_DECREMENT;\n            }\n\n            InvalidateRect(WindowHandle, &dividerRect, FALSE);\n        }\n    }\n}\n\n/**\n * Handles the WM_MOUSEMOVE message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param VirtualKeys Virtual key flags.\n * \\param CursorX X coordinate of the cursor.\n * \\param CursorY Y coordinate of the cursor.\n */\nVOID PhTnpOnMouseMove(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    if (FlagOn(Context->Style, TN_STYLE_DRAG_REORDER_ROWS))\n    {\n        // Reorder drag in progress: update target and caret, swallow normal processing (dmex)\n\n        if (Context->ReorderDragActive)\n        {\n            if (Context->ReorderJustStarted)\n            {\n                Context->ReorderJustStarted = FALSE;\n            }\n\n            if (Context->ReorderCursor)\n            {\n                PhSetCursor(Context->ReorderCursor);\n            }\n\n            PhTnpReorderUpdate(Context, CursorX, CursorY);\n            return;\n        }\n    }\n\n    TRACKMOUSEEVENT trackMouseEvent;\n\n    trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);\n    trackMouseEvent.dwFlags = TME_LEAVE;\n    trackMouseEvent.hwndTrack = WindowHandle;\n    trackMouseEvent.dwHoverTime = 0;\n    TrackMouseEvent(&trackMouseEvent);\n\n    if (Context->Tracking)\n    {\n        ULONG newFixedWidth;\n\n        newFixedWidth = Context->TrackOldFixedWidth + (CursorX - Context->TrackStartX);\n        PhTnpSetFixedWidth(Context, newFixedWidth);\n    }\n\n    PhTnpProcessMoveMouse(Context, CursorX, CursorY);\n}\n\n/**\n * Handles the WM_MOUSELEAVE message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpOnMouseLeave(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT rect;\n\n    if (Context->HotNodeIndex != ULONG_MAX && Context->ThemeData)\n    {\n        // Update the old hot node because it may have a different non-hot background and plus minus part.\n        if (PhTnpGetRowRects(Context, Context->HotNodeIndex, Context->HotNodeIndex, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n\n    Context->HotNodeIndex = ULONG_MAX;\n\n    if (Context->AnimateDivider && Context->FixedDividerVisible)\n    {\n        if ((Context->DividerHot != 0 || Context->AnimateDividerFadingIn) && !Context->AnimateDividerFadingOut)\n        {\n            // Fade out the divider.\n            Context->AnimateDividerFadingOut = TRUE;\n            Context->AnimateDividerFadingIn = FALSE;\n            PhSetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL);\n        }\n    }\n\n    if (Context->TooltipIndex != ULONG_MAX || Context->TooltipId != ULONG_MAX)\n    {\n        // Hide the tooltip when the mouse leaves the window or we lose focus. This fixes a certain tooltip bug\n        // when hovering over an item to show the tooltip while alt-tabbing causes the tooltip to remain stuck\n        // on screen. There's also a similar issue when a window steals focus just as the tooltip becomes visible\n        // and also causes the tooltip to remain stuck on screen. Popping here fixes both issues. (dmex)\n        PhTnpPopTooltip(Context);\n    }\n}\n\n/**\n * Handles mouse button messages (down, up, double-click) for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Message Mouse message identifier.\n * \\param VirtualKeys Virtual key flags.\n * \\param CursorX X coordinate of the cursor.\n * \\param CursorY Y coordinate of the cursor.\n */\nVOID PhTnpOnXxxButtonXxx(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Message,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    BOOLEAN startingTracking;\n    PH_TREENEW_HIT_TEST hitTest;\n    LOGICAL controlKey;\n    LOGICAL shiftKey;\n    RECT rect;\n    ULONG changedStart;\n    ULONG changedEnd;\n    ULONG clickMessage;\n\n    // Focus\n\n    if (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN)\n        SetFocus(WindowHandle);\n\n    // Divider tracking\n\n    startingTracking = FALSE;\n\n    switch (Message)\n    {\n    case WM_LBUTTONDOWN:\n        {\n            if (TNP_HIT_TEST_FIXED_DIVIDER(CursorX, Context))\n            {\n                startingTracking = TRUE;\n                Context->Tracking = TRUE;\n                Context->TrackStartX = CursorX;\n                Context->TrackOldFixedWidth = Context->FixedWidth;\n                SetCapture(WindowHandle);\n\n                PhSetTimer(WindowHandle, TNP_TIMER_NULL, 100, NULL); // make sure we get messages once in a while so we can detect the escape key\n                GetAsyncKeyState(VK_ESCAPE);\n            }\n        }\n        break;\n    case WM_LBUTTONUP:\n        {\n            if (Context->Tracking)\n            {\n                ReleaseCapture();\n            }\n        }\n        break;\n    case WM_RBUTTONDOWN:\n        {\n            if (Context->Tracking)\n            {\n                PhTnpCancelTrack(Context);\n            }\n        }\n        break;\n    }\n\n    if (!startingTracking && Context->Tracking) // still OK to process further if the user is only starting to drag the divider\n        return;\n\n    hitTest.Point.x = CursorX;\n    hitTest.Point.y = CursorY;\n    hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM;\n    PhTnpHitTest(Context, &hitTest);\n\n    if (FlagOn(Context->Style, TN_STYLE_DRAG_REORDER_ROWS))\n    {\n        // Begin reorder drag if:\n        // - TN_STYLE_DRAG_REORDER_ROWS flag enabled\n        // - Left button down on item content (not plus/minus, not divider)\n        // - Ctrl is held (to avoid conflict with drag selection)\n        if (Message == WM_LBUTTONDOWN &&\n            (VirtualKeys & MK_CONTROL) &&\n            (hitTest.Flags & TN_HIT_ITEM) &&\n            !(hitTest.Flags & (TN_HIT_ITEM_PLUSMINUS | TN_HIT_DIVIDER)))\n        {\n            PH_TREENEW_REORDER_EVENT reorderEvent = { 0 };\n\n            memset(&reorderEvent, 0, sizeof(PH_TREENEW_REORDER_EVENT));\n            reorderEvent.Source = hitTest.Node;\n            reorderEvent.Target = hitTest.Node;\n            reorderEvent.DropAfter = FALSE;\n            reorderEvent.Allow = TRUE;\n\n            Context->Callback(Context->Handle, TreeNewReorderBegin, &reorderEvent, NULL, Context->CallbackContext);\n\n            if (reorderEvent.Allow)\n            {\n                ULONG saveIndex = hitTest.Node ? hitTest.Node->Index : ULONG_MAX;\n                ULONG cancelledByMessage = 0;\n\n                if (PhTnpDetectDrag(Context, CursorX, CursorY, TRUE, &cancelledByMessage))\n                {\n                    // Begin drag-reorder\n                    if (saveIndex != ULONG_MAX && saveIndex < Context->FlatList->Count)\n                    {\n                        PhTnpReorderBegin(Context, saveIndex);\n                        PhTnpReorderUpdateCaretRect(Context);\n                        InvalidateRect(Context->Handle, &Context->ReorderInsertRect, FALSE);\n                        return; // swallow normal selection behavior\n                    }\n                }\n                else\n                {\n                    // If detection consumed up-event, don't duplicate\n                    if (cancelledByMessage == WM_LBUTTONUP)\n                        return;\n                }\n            }\n        }\n\n        // Commit/cancel on mouse up if in reorder mode\n        if (Message == WM_LBUTTONUP && Context->ReorderDragActive)\n        {\n            PhTnpReorderCommit(Context);\n            return;\n        }\n        if (Message == WM_RBUTTONDOWN && Context->ReorderDragActive)\n        {\n            PhTnpReorderCancel(Context);\n            return;\n        }\n    }\n\n    controlKey = VirtualKeys & MK_CONTROL;\n    shiftKey = VirtualKeys & MK_SHIFT;\n\n    // Plus minus glyph\n\n    if ((hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && Message == WM_LBUTTONDOWN)\n    {\n        PhTnpSetExpandedNode(Context, hitTest.Node, !hitTest.Node->Expanded);\n    }\n\n    // Selection\n\n    if (!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN))\n    {\n        LOGICAL allowDragSelect;\n        PH_TREENEW_CELL_PARTS parts;\n\n        PhTnpPopTooltip(Context);\n        allowDragSelect = TRUE;\n\n        if (hitTest.Flags & TN_HIT_ITEM)\n        {\n            allowDragSelect = FALSE;\n            Context->FocusNode = hitTest.Node;\n\n            if (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT)\n            {\n                // To allow drag selection to begin even if the cursor is on an item, we check if\n                // the cursor is on the item icon or text. Exceptions are:\n                // * When the item is already selected\n                // * When user is beginning to drag the divider\n\n                if (!hitTest.Node->Selected && !startingTracking)\n                {\n                    if (PhTnpGetCellParts(Context, hitTest.Node->Index, hitTest.Column, TN_MEASURE_TEXT, &parts))\n                    {\n                        allowDragSelect = TRUE;\n\n                        if ((parts.Flags & TN_PART_ICON) && CursorX >= parts.IconRect.left && CursorX < parts.IconRect.right)\n                            allowDragSelect = FALSE;\n\n                        if ((parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT))\n                        {\n                            if (CursorX >= parts.TextRect.left && CursorX < parts.TextRect.right)\n                                allowDragSelect = FALSE;\n                        }\n                    }\n                }\n            }\n\n            PhTnpProcessSelectNode(Context, hitTest.Node, controlKey, shiftKey, Message == WM_RBUTTONDOWN);\n        }\n\n        if (allowDragSelect)\n        {\n            BOOLEAN dragSelect;\n            ULONG indexToSelect;\n            BOOLEAN selectionProcessed;\n            BOOLEAN showContextMenu;\n\n            dragSelect = FALSE;\n            indexToSelect = ULONG_MAX;\n            selectionProcessed = FALSE;\n            showContextMenu = FALSE;\n\n            if (!(hitTest.Flags & (TN_HIT_LEFT | TN_HIT_RIGHT | TN_HIT_ABOVE | TN_HIT_BELOW)) && !startingTracking) // don't interfere with divider\n            {\n                BOOLEAN result;\n                ULONG saveIndex;\n                ULONG saveId;\n                ULONG cancelledByMessage;\n\n                // Check for drag selection. PhTnpDetectDrag has its own message loop, so we need to\n                // clear our pointers before we continue or we will have some access violations when\n                // items get deleted.\n\n                if (hitTest.Node)\n                    saveIndex = hitTest.Node->Index;\n                else\n                    saveIndex = ULONG_MAX;\n\n                if (hitTest.Column)\n                    saveId = hitTest.Column->Id;\n                else\n                    saveId = ULONG_MAX;\n\n                result = PhTnpDetectDrag(Context, CursorX, CursorY, TRUE, &cancelledByMessage);\n\n                // Restore the pointers.\n\n                if (saveIndex == ULONG_MAX)\n                    hitTest.Node = NULL;\n                else if (saveIndex < Context->FlatList->Count)\n                    hitTest.Node = Context->FlatList->Items[saveIndex];\n                else\n                    return;\n\n                if (saveId != ULONG_MAX && !(hitTest.Column = PhTnpLookupColumnById(Context, saveId)))\n                    return;\n\n                if (result)\n                {\n                    dragSelect = TRUE;\n\n                    if ((hitTest.Flags & TN_HIT_ITEM) && (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT))\n                    {\n                        // Include the current node before starting the drag selection, otherwise\n                        // the user will never be able to select the current node.\n                        if (hitTest.Node)\n                        {\n                            indexToSelect = hitTest.Node->Index;\n                        }\n                    }\n                }\n                else\n                {\n                    if ((Message == WM_LBUTTONDOWN && cancelledByMessage == WM_LBUTTONUP) ||\n                        (Message == WM_RBUTTONDOWN && cancelledByMessage == WM_RBUTTONUP))\n                    {\n                        POINT point;\n\n                        if ((hitTest.Flags & TN_HIT_ITEM) && (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT))\n                        {\n                            // The user isn't performing a drag selection, so prevent deselection.\n                            selectionProcessed = TRUE;\n                        }\n\n                        // The button up message gets consumed by PhTnpDetectDrag, so send the mouse\n                        // event here.\n                        // Check if the cursor stayed in the same place.\n\n                        if (\n                            PhGetClientPos(Context->Handle, &point) && \n                            point.x == CursorX && point.y == CursorY\n                            )\n                        {\n                            PhTnpSendMouseEvent(\n                                Context,\n                                Message == WM_LBUTTONDOWN ? TreeNewLeftClick : TreeNewRightClick,\n                                CursorX,\n                                CursorY,\n                                hitTest.Node,\n                                hitTest.Column,\n                                VirtualKeys\n                                );\n                        }\n\n                        if (Message == WM_RBUTTONDOWN)\n                            showContextMenu = TRUE;\n                    }\n                }\n            }\n\n            if (!selectionProcessed && !controlKey && !shiftKey)\n            {\n                // Nothing: deselect everything.\n\n                PhTnpSelectRange(Context, indexToSelect, indexToSelect, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                {\n                    InvalidateRect(WindowHandle, &rect, FALSE);\n                }\n            }\n\n            if (dragSelect)\n            {\n                PhTnpDragSelect(Context, CursorX, CursorY);\n            }\n\n            if (showContextMenu)\n            {\n                SendMessage(Context->Handle, WM_CONTEXTMENU, (WPARAM)Context->Handle, GetMessagePos());\n            }\n\n            return;\n        }\n    }\n\n    // Click, double-click\n    // Note: If TN_FLAG_ITEM_DRAG_SELECT is enabled, the code below that processes WM_xBUTTONDOWN\n    // and WM_xBUTTONUP messages only takes effect when the user clicks directly on an item's icon\n    // or text.\n\n    clickMessage = ULONG_MAX;\n\n    if (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN || Message == WM_MBUTTONDOWN)\n    {\n        if (Context->MouseDownLast != 0 && Context->MouseDownLast != Message)\n        {\n            // User pressed one button and pressed the other without letting go of the first one.\n            // This counts as a click.\n\n            if (Context->MouseDownLast == WM_LBUTTONDOWN)\n                clickMessage = TreeNewLeftClick;\n            else if (Context->MouseDownLast == WM_RBUTTONDOWN)\n                clickMessage = TreeNewRightClick;\n            else\n                clickMessage = TreeNewMiddleClick;\n        }\n\n        Context->MouseDownLast = Message;\n        Context->MouseDownLocation.x = CursorX;\n        Context->MouseDownLocation.y = CursorY;\n    }\n    else if (Message == WM_LBUTTONUP || Message == WM_RBUTTONUP || Message == WM_MBUTTONUP)\n    {\n        if (Context->MouseDownLast != 0 &&\n            Context->MouseDownLocation.x == CursorX && Context->MouseDownLocation.y == CursorY)\n        {\n            if (Context->MouseDownLast == WM_LBUTTONDOWN)\n                clickMessage = TreeNewLeftClick;\n            else if (Context->MouseDownLast == WM_RBUTTONDOWN)\n                clickMessage = TreeNewRightClick;\n            else\n                clickMessage = TreeNewMiddleClick;\n        }\n\n        Context->MouseDownLast = 0;\n    }\n    else if (Message == WM_LBUTTONDBLCLK)\n    {\n        clickMessage = TreeNewLeftDoubleClick;\n    }\n    else if (Message == WM_RBUTTONDBLCLK)\n    {\n        clickMessage = TreeNewRightDoubleClick;\n    }\n\n    if (!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && clickMessage != ULONG_MAX)\n    {\n        PhTnpSendMouseEvent(Context, clickMessage, CursorX, CursorY, hitTest.Node, hitTest.Column, VirtualKeys);\n    }\n}\n\n/**\n * Handles the WM_CAPTURECHANGED message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpOnCaptureChanged(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    Context->Tracking = FALSE;\n    PhKillTimer(WindowHandle, TNP_TIMER_NULL);\n\n    if (FlagOn(Context->Style, TN_STYLE_DRAG_REORDER_ROWS))\n    {\n        if (Context->ReorderDragActive && !Context->ReorderJustStarted)\n            PhTnpReorderCancel(Context);\n    }\n}\n\n/**\n * Handles the WM_KEYDOWN message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param VirtualKey Virtual key code.\n * \\param Data Additional key data.\n */\nVOID PhTnpOnKeyDown(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey,\n    _In_ ULONG Data\n    )\n{\n    PH_TREENEW_KEY_EVENT keyEvent;\n\n    if (FlagOn(Context->Style, TN_STYLE_DRAG_REORDER_ROWS))\n    {\n        // Cancel reorder drag with ESC\n        if (Context->ReorderDragActive && VirtualKey == VK_ESCAPE)\n        {\n            PhTnpReorderCancel(Context);\n            return;\n        }\n    }\n\n    keyEvent.Handled = FALSE;\n    keyEvent.VirtualKey = VirtualKey;\n    keyEvent.Data = Data;\n    Context->Callback(Context->Handle, TreeNewKeyDown, &keyEvent, NULL, Context->CallbackContext);\n\n    if (keyEvent.Handled)\n        return;\n\n    if (PhTnpProcessFocusKey(Context, VirtualKey))\n        return;\n    if (PhTnpProcessNodeKey(Context, VirtualKey))\n        return;\n\n    // handle standard key presses\n    switch (VirtualKey)\n    {\n    case 'A':\n        if (GetKeyState(VK_CONTROL) < 0)\n            TreeNew_SelectRange(WindowHandle, 0, -1);\n        return;\n    }\n\n    // pass unhandled key presses to parent\n    SendMessage(GetParent(WindowHandle), WM_KEYDOWN, VirtualKey, Data);\n}\n\n/**\n * Handles the WM_CHAR message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Character The character code.\n * \\param Data Additional data.\n */\nVOID PhTnpOnChar(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Character,\n    _In_ ULONG Data\n    )\n{\n    // Make sure the character is printable.\n    if (Character >= ' ' && Character <= '~')\n    {\n        PhTnpProcessSearchKey(Context, Character);\n    }\n}\n\n/**\n * Handles the WM_MOUSEWHEEL message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Distance Wheel delta.\n * \\param VirtualKeys Virtual key flags.\n * \\param CursorX X coordinate of the cursor.\n * \\param CursorY Y coordinate of the cursor.\n */\nVOID PhTnpOnMouseWheel(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    // The normal mouse wheel can affect both the vertical scrollbar and the horizontal scrollbar,\n    // but the vertical scrollbar takes precedence.\n    if (Context->VScrollVisible)\n    {\n        PhTnpProcessMouseVWheel(Context, -Distance);\n    }\n    else if (Context->HScrollVisible)\n    {\n        PhTnpProcessMouseHWheel(Context, -Distance);\n    }\n}\n\n/**\n * Handles the WM_MOUSEHWHEEL message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Distance Wheel delta.\n * \\param VirtualKeys Virtual key flags.\n * \\param CursorX X coordinate of the cursor.\n * \\param CursorY Y coordinate of the cursor.\n */\nVOID PhTnpOnMouseHWheel(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    PhTnpProcessMouseHWheel(Context, Distance);\n}\n\n/**\n * Handles the WM_CONTEXTMENU message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param CursorScreenX X coordinate of the context menu (screen coordinates).\n * \\param CursorScreenY Y coordinate of the context menu (screen coordinates).\n */\nVOID PhTnpOnContextMenu(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorScreenX,\n    _In_ LONG CursorScreenY\n    )\n{\n    POINT clientPoint;\n    BOOLEAN keyboardInvoked;\n    PH_TREENEW_HIT_TEST hitTest;\n    PH_TREENEW_CONTEXT_MENU contextMenu;\n\n    if (CursorScreenX == INT_ERROR && CursorScreenY == INT_ERROR)\n    {\n        ULONG i;\n        BOOLEAN found;\n        RECT windowRect;\n        RECT rect;\n\n        keyboardInvoked = TRUE;\n\n        // Context menu was invoked via keyboard. Display the context menu at the selected item.\n\n        found = FALSE;\n\n        for (i = 0; i < Context->FlatList->Count; i++)\n        {\n            if (((PPH_TREENEW_NODE)Context->FlatList->Items[i])->Selected)\n            {\n                found = TRUE;\n                break;\n            }\n        }\n\n        if (found && PhTnpGetRowRects(Context, i, i, FALSE, &rect) &&\n            rect.top >= Context->ClientRect.top && rect.top < Context->ClientRect.bottom)\n        {\n            clientPoint.x = rect.left + Context->SmallIconWidth / 2;\n            clientPoint.y = rect.top + Context->RowHeight / 2;\n        }\n        else\n        {\n            clientPoint.x = 0;\n            clientPoint.y = 0;\n        }\n\n        PhGetWindowRect(WindowHandle, &windowRect);\n        CursorScreenX = windowRect.left + clientPoint.x;\n        CursorScreenY = windowRect.top + clientPoint.y;\n    }\n    else\n    {\n        keyboardInvoked = FALSE;\n\n        clientPoint.x = CursorScreenX;\n        clientPoint.y = CursorScreenY;\n        ScreenToClient(WindowHandle, &clientPoint);\n\n        if (clientPoint.y < Context->HeaderHeight)\n        {\n            // Already handled by TreeNewHeaderRightClick.\n            return;\n        }\n    }\n\n    hitTest.Point = clientPoint;\n    hitTest.InFlags = TN_TEST_COLUMN;\n    PhTnpHitTest(Context, &hitTest);\n\n    contextMenu.Location.x = CursorScreenX;\n    contextMenu.Location.y = CursorScreenY;\n    contextMenu.ClientLocation = clientPoint;\n    contextMenu.Node = hitTest.Node;\n    contextMenu.Column = hitTest.Column;\n    contextMenu.KeyboardInvoked = keyboardInvoked;\n    Context->ContextMenuActive = TRUE;\n    Context->Callback(WindowHandle, TreeNewContextMenu, &contextMenu, NULL, Context->CallbackContext);\n    Context->ContextMenuActive = FALSE;\n}\n\n/**\n * Handles the WM_VSCROLL message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Request Scroll request type.\n * \\param Position Scroll position.\n */\nVOID PhTnpOnVScroll(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Request,\n    _In_ USHORT Position\n    )\n{\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_ALL;\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    switch (Request)\n    {\n    case SB_LINEUP:\n        scrollInfo.nPos--;\n        break;\n    case SB_LINEDOWN:\n        scrollInfo.nPos++;\n        break;\n    case SB_PAGEUP:\n        scrollInfo.nPos -= scrollInfo.nPage;\n        break;\n    case SB_PAGEDOWN:\n        scrollInfo.nPos += scrollInfo.nPage;\n        break;\n    case SB_THUMBPOSITION:\n        // Touch scrolling seems to give us Position but not nTrackPos. The problem is that Position\n        // is a 16-bit value, so don't use it if we have too many rows.\n        if (Context->FlatList->Count <= 0xffff)\n            scrollInfo.nPos = Position;\n        break;\n    case SB_THUMBTRACK:\n        scrollInfo.nPos = scrollInfo.nTrackPos;\n        break;\n    case SB_TOP:\n        scrollInfo.nPos = 0;\n        break;\n    case SB_BOTTOM:\n        scrollInfo.nPos = MAXINT;\n        break;\n    }\n\n    scrollInfo.fMask = SIF_POS;\n    SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE);\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n\n    if (scrollInfo.nPos != oldPosition)\n    {\n        Context->VScrollPosition = scrollInfo.nPos;\n        PhTnpProcessScroll(Context, scrollInfo.nPos - oldPosition, 0);\n    }\n}\n\n/**\n * Handles the WM_HSCROLL message for the treenew control.\n *\n * \\param WindowHandle Handle to the window.\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Request Scroll request type.\n * \\param Position Scroll position.\n */\nVOID PhTnpOnHScroll(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Request,\n    _In_ USHORT Position\n    )\n{\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_ALL;\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    switch (Request)\n    {\n    case SB_LINELEFT:\n        scrollInfo.nPos -= Context->TextMetrics.tmAveCharWidth;\n        break;\n    case SB_LINERIGHT:\n        scrollInfo.nPos += Context->TextMetrics.tmAveCharWidth;\n        break;\n    case SB_PAGELEFT:\n        scrollInfo.nPos -= scrollInfo.nPage;\n        break;\n    case SB_PAGERIGHT:\n        scrollInfo.nPos += scrollInfo.nPage;\n        break;\n    case SB_THUMBPOSITION:\n        // Touch scrolling seems to give us Position but not nTrackPos. The problem is that Position\n        // is a 16-bit value, so don't use it if we have too many rows.\n        if (Context->FlatList->Count <= 0xffff)\n            scrollInfo.nPos = Position;\n        break;\n    case SB_THUMBTRACK:\n        scrollInfo.nPos = scrollInfo.nTrackPos;\n        break;\n    case SB_LEFT:\n        scrollInfo.nPos = 0;\n        break;\n    case SB_RIGHT:\n        scrollInfo.nPos = MAXINT;\n        break;\n    }\n\n    scrollInfo.fMask = SIF_POS;\n    SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE);\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n\n    if (scrollInfo.nPos != oldPosition)\n    {\n        Context->HScrollPosition = scrollInfo.nPos;\n        PhTnpProcessScroll(Context, 0, scrollInfo.nPos - oldPosition);\n    }\n}\n\n/**\n * Handles WM_NOTIFY messages from child controls.\n *\n * \\param WindowHandle Handle to the treenew window.\n * \\param Context Pointer to the treenew context structure.\n * \\param Header Pointer to the NMHDR notification structure.\n * \\param Result Pointer to receive the message result.\n * \\return TRUE if the message was handled, FALSE otherwise.\n */\n_Success_(return)\nBOOLEAN PhTnpOnNotify(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    )\n{\n    switch (Header->code)\n    {\n    case HDN_ITEMCHANGING:\n    case HDN_ITEMCHANGED:\n        {\n            NMHEADER *nmHeader = (NMHEADER *)Header;\n\n            if (Header->code == HDN_ITEMCHANGING && Header->hwndFrom == Context->FixedHeaderHandle)\n            {\n                if (nmHeader->pitem->mask & HDI_WIDTH)\n                {\n                    if (Context->FixedColumnVisible)\n                    {\n                        Context->FixedWidth = nmHeader->pitem->cxy - 1;\n\n                        if (Context->FixedWidth < Context->FixedWidthMinimum)\n                            Context->FixedWidth = Context->FixedWidthMinimum;\n\n                        Context->NormalLeft = Context->FixedWidth + 1;\n                        nmHeader->pitem->cxy = Context->FixedWidth + 1;\n                    }\n                    else\n                    {\n                        Context->FixedWidth = 0;\n                        Context->NormalLeft = 0;\n                    }\n                }\n            }\n\n            if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle)\n            {\n                if (nmHeader->pitem->mask & HDI_WIDTH)\n                {\n                    // A column has been resized. Update our stored information.\n                    PhTnpUpdateColumnHeaders(Context);\n                    PhTnpUpdateColumnMaps(Context);\n\n                    if (Header->code == HDN_ITEMCHANGING)\n                    {\n                        HDITEM item;\n\n                        item.mask = HDI_WIDTH | HDI_LPARAM;\n\n                        if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item))\n                        {\n                            Context->ResizingColumn = (PPH_TREENEW_COLUMN)item.lParam;\n                            Context->OldColumnWidth = item.cxy;\n                        }\n                        else\n                        {\n                            Context->ResizingColumn = NULL;\n                            Context->OldColumnWidth = -1;\n                        }\n                    }\n                    else if (Header->code == HDN_ITEMCHANGED)\n                    {\n                        if (Context->ResizingColumn)\n                        {\n                            LONG delta;\n\n                            delta = nmHeader->pitem->cxy - Context->OldColumnWidth;\n\n                            if (delta != 0)\n                            {\n                                PhTnpProcessResizeColumn(Context, Context->ResizingColumn, delta);\n                                Context->Callback(Context->Handle, TreeNewColumnResized, Context->ResizingColumn, NULL, Context->CallbackContext);\n                            }\n\n                            Context->ResizingColumn = NULL;\n\n                            // Redraw the entire window if we are displaying empty text.\n                            if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0)\n                                InvalidateRect(Context->Handle, NULL, FALSE);\n                        }\n                        else\n                        {\n                            // An error occurred during HDN_ITEMCHANGED, so redraw the entire window.\n                            InvalidateRect(Context->Handle, NULL, FALSE);\n                        }\n                    }\n                }\n            }\n        }\n        break;\n    case HDN_ITEMCLICK:\n        {\n            if ((Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) &&\n                !(Context->Style & TN_STYLE_NO_COLUMN_SORT))\n            {\n                NMHEADER *nmHeader = (NMHEADER *)Header;\n                HDITEM item;\n                PPH_TREENEW_COLUMN column;\n\n                // A column has been clicked, so update the sort state.\n\n                item.mask = HDI_LPARAM;\n\n                if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item))\n                {\n                    column = (PPH_TREENEW_COLUMN)item.lParam;\n                    PhTnpProcessSortColumn(Context, column);\n                }\n            }\n        }\n        break;\n    case HDN_ENDDRAG:\n    case NM_RELEASEDCAPTURE:\n        {\n            if (Header->hwndFrom == Context->HeaderHandle)\n            {\n                // Columns have been re-ordered, so refresh our information.\n                // Note: The fixed column cannot be re-ordered.\n                PhTnpUpdateColumnHeaders(Context);\n                PhTnpUpdateColumnMaps(Context);\n                Context->Callback(Context->Handle, TreeNewColumnReordered, NULL, NULL, Context->CallbackContext);\n                InvalidateRect(Context->Handle, NULL, FALSE);\n            }\n\n            // We need to invalidate the header but hwndFrom doesn't match HeaderHandle,\n            // instead we'll always invalidate? (dmex)\n            if (Context->ThemeSupport)\n            {\n                InvalidateRect(Context->HeaderHandle, NULL, FALSE);\n            }\n        }\n        break;\n    case HDN_DIVIDERDBLCLICK:\n        {\n            if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle)\n            {\n                NMHEADER *nmHeader = (NMHEADER *)Header;\n                HDITEM item;\n\n                if (Context->SuspendUpdateStructure)\n                    break;\n\n                item.mask = HDI_LPARAM;\n\n                if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item))\n                {\n                    PhTnpAutoSizeColumnHeader(\n                        Context,\n                        Header->hwndFrom,\n                        (PPH_TREENEW_COLUMN)item.lParam,\n                        0\n                        );\n                }\n            }\n        }\n        break;\n    case NM_RCLICK:\n        {\n            if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle)\n            {\n                PH_TREENEW_HEADER_MOUSE_EVENT mouseEvent;\n                ULONG position;\n\n                position = GetMessagePos();\n                mouseEvent.ScreenLocation.x = GET_X_LPARAM(position);\n                mouseEvent.ScreenLocation.y = GET_Y_LPARAM(position);\n\n                mouseEvent.Location = mouseEvent.ScreenLocation;\n                ScreenToClient(WindowHandle, &mouseEvent.Location);\n                mouseEvent.HeaderLocation = mouseEvent.ScreenLocation;\n                ScreenToClient(Header->hwndFrom, &mouseEvent.HeaderLocation);\n                mouseEvent.Column = PhTnpHitTestHeader(Context, Header->hwndFrom == Context->FixedHeaderHandle, &mouseEvent.HeaderLocation, NULL);\n                Context->Callback(WindowHandle, TreeNewHeaderRightClick, &mouseEvent, NULL, Context->CallbackContext);\n            }\n        }\n        break;\n    case TTN_GETDISPINFO:\n        {\n            if (Header->hwndFrom == Context->TooltipsHandle)\n            {\n                NMTTDISPINFO *info = (NMTTDISPINFO *)Header;\n                POINT point;\n                PPH_STRING string;\n\n                if (PhGetClientPos(WindowHandle, &point))\n                {\n                    if (PhTnpGetTooltipText(Context, &point, &string))\n                    {\n                        info->lpszText = string->Buffer;\n                        break;\n                    }\n                }\n            }\n        }\n        break;\n    case TTN_SHOW:\n        {\n            if (Header->hwndFrom == Context->TooltipsHandle)\n            {\n                *Result = PhTnpPrepareTooltipShow(Context);\n                return TRUE;\n            }\n        }\n        break;\n    case TTN_POP:\n        {\n            if (Header->hwndFrom == Context->TooltipsHandle)\n            {\n                PhTnpPrepareTooltipPop(Context);\n            }\n        }\n        break;\n    case NM_CUSTOMDRAW:\n        {\n            if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle)\n            {\n                LPNMCUSTOMDRAW customDraw = (LPNMCUSTOMDRAW)Header;\n\n                switch (customDraw->dwDrawStage)\n                {\n                case CDDS_PREPAINT:\n                    {\n                        *Result = CDRF_NOTIFYITEMDRAW;\n                    }\n                    return TRUE;\n                case CDDS_ITEMPREPAINT:\n                    {\n                        if (TnHeaderCustomPaint(Context, customDraw))\n                        {\n                            *Result = CDRF_SKIPDEFAULT;\n                        }\n                        else\n                        {\n                            *Result = CDRF_DODEFAULT;\n                        }\n                    }\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n * Processes treenew-specific user messages (TNM_* messages).\n *\n * \\param WindowHandle Handle to the treenew window.\n * \\param Context Pointer to the treenew context structure.\n * \\param Message The treenew message identifier.\n * \\param WParam First message-specific parameter.\n * \\param LParam Second message-specific parameter.\n * \\return The result of the message processing.\n */\nLRESULT PhTnpOnUserMessage(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    )\n{\n    switch (Message)\n    {\n    case TNM_SETCALLBACK:\n        {\n            Context->Callback = (PPH_TREENEW_CALLBACK)LParam;\n            Context->CallbackContext = (PVOID)WParam;\n\n            if (!Context->Callback)\n                Context->Callback = PhTnpNullCallback;\n        }\n        return TRUE;\n    case TNM_NODESSTRUCTURED:\n        {\n            if (Context->EnableRedraw <= 0)\n            {\n                Context->SuspendUpdateStructure = TRUE;\n                Context->SuspendUpdateLayout = TRUE;\n                InvalidateRect(Context->Handle, NULL, FALSE);\n                return TRUE;\n            }\n\n            PhTnpRestructureNodes(Context);\n            PhTnpLayout(Context);\n            InvalidateRect(Context->Handle, NULL, FALSE);\n        }\n        return TRUE;\n    case TNM_ADDCOLUMN:\n        return PhTnpAddColumn(Context, (PPH_TREENEW_COLUMN)LParam);\n    case TNM_REMOVECOLUMN:\n        return PhTnpRemoveColumn(Context, (ULONG)WParam);\n    case TNM_GETCOLUMN:\n        return PhTnpCopyColumn(Context, (ULONG)WParam, (PPH_TREENEW_COLUMN)LParam);\n    case TNM_SETCOLUMN:\n        {\n            PPH_TREENEW_COLUMN column = (PPH_TREENEW_COLUMN)LParam;\n\n            return PhTnpChangeColumn(Context, (ULONG)WParam, column->Id, column);\n        }\n        break;\n    case TNM_GETCOLUMNORDERARRAY:\n        {\n            ULONG count = (ULONG)WParam;\n            PULONG order = (PULONG)LParam;\n            ULONG i;\n\n            if (count != Context->NumberOfColumnsByDisplay)\n                return FALSE;\n\n            for (i = 0; i < count; i++)\n            {\n                order[i] = Context->ColumnsByDisplay[i]->Id;\n            }\n        }\n        return TRUE;\n    case TNM_SETCOLUMNORDERARRAY:\n        {\n            ULONG count = (ULONG)WParam;\n            PULONG order = (PULONG)LParam;\n            ULONG i;\n            PULONG newOrder;\n            PPH_TREENEW_COLUMN column;\n\n            if (count)\n            {\n                newOrder = PhAllocate(count * sizeof(ULONG));\n\n                for (i = 0; i < count; i++)\n                {\n                    if (!(column = PhTnpLookupColumnById(Context, order[i])))\n                    {\n                        PhFree(newOrder);\n                        return FALSE;\n                    }\n\n                    newOrder[i] = column->s.ViewIndex;\n                }\n\n                if (!Header_SetOrderArray(Context->HeaderHandle, count, newOrder))\n                {\n                    PhFree(newOrder);\n                    return FALSE;\n                }\n\n                PhFree(newOrder);\n            }\n\n            PhTnpUpdateColumnHeaders(Context);\n            PhTnpUpdateColumnMaps(Context);\n        }\n        return TRUE;\n    case TNM_SETCURSOR:\n        {\n            Context->Cursor = (HCURSOR)LParam;\n        }\n        return TRUE;\n    case TNM_GETSORT:\n        {\n            PULONG sortColumn = (PULONG)WParam;\n            PPH_SORT_ORDER sortOrder = (PPH_SORT_ORDER)LParam;\n\n            if (sortColumn)\n                *sortColumn = Context->SortColumn;\n            if (sortOrder)\n                *sortOrder = Context->SortOrder;\n        }\n        return TRUE;\n    case TNM_SETSORT:\n        {\n            ULONG sortColumn = (ULONG)WParam;\n            PH_SORT_ORDER sortOrder = (PH_SORT_ORDER)LParam;\n            PH_TREENEW_SORT_CHANGED_EVENT sortOrderEvent;\n            PPH_TREENEW_COLUMN column;\n\n            if (sortColumn == Context->SortColumn &&\n                sortOrder == Context->SortOrder)\n            {\n                return TRUE; // Nothing to change (dmex)\n            }\n\n            if (sortOrder != NoSortOrder)\n            {\n                if (!(column = PhTnpLookupColumnById(Context, sortColumn)))\n                    return FALSE;\n            }\n            else\n            {\n                sortColumn = 0;\n                column = NULL;\n            }\n\n            Context->SortColumn = sortColumn;\n            Context->SortOrder = sortOrder;\n\n            PhTnpSetColumnHeaderSortIcon(Context, column);\n\n            memset(&sortOrderEvent, 0, sizeof(PH_TREENEW_SORT_CHANGED_EVENT));\n            sortOrderEvent.SortColumn = sortColumn;\n            sortOrderEvent.SortOrder = sortOrder;\n\n            Context->Callback(Context->Handle, TreeNewSortChanged, &sortOrderEvent, NULL, Context->CallbackContext);\n        }\n        return TRUE;\n    case TNM_SETTRISTATE:\n        Context->TriState = !!WParam;\n        return TRUE;\n    case TNM_ENSUREVISIBLE:\n        return PhTnpEnsureVisibleNode(Context, ((PPH_TREENEW_NODE)LParam)->Index);\n    case TNM_SCROLL:\n        PhTnpScroll(Context, (LONG)WParam, (LONG)LParam);\n        return TRUE;\n    case TNM_GETFLATNODECOUNT:\n        if (!Context->SuspendUpdateStructure)\n            return (LRESULT)Context->FlatList->Count;\n        else\n            return 0;\n    case TNM_GETFLATNODE:\n        {\n            ULONG index = (ULONG)WParam;\n\n            if (index >= Context->FlatList->Count)\n                return (LRESULT)NULL;\n\n            return (LRESULT)Context->FlatList->Items[index];\n        }\n        break;\n    case TNM_GETCELLTEXT:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)LParam;\n\n            return PhTnpGetCellText(\n                Context,\n                getCellText->Node,\n                getCellText->Id,\n                &getCellText->Text\n                );\n        }\n        break;\n    case TNM_SETNODEEXPANDED:\n        PhTnpSetExpandedNode(Context, (PPH_TREENEW_NODE)LParam, !!WParam);\n        return TRUE;\n    case TNM_GETMAXID:\n        return (LRESULT)(Context->NextId - 1);\n    case TNM_SETMAXID:\n        {\n            ULONG maxId = (ULONG)WParam;\n\n            if (Context->NextId < maxId + 1)\n            {\n                Context->NextId = maxId + 1;\n\n                if (Context->AllocatedColumns < Context->NextId)\n                {\n                    PhTnpExpandAllocatedColumns(Context);\n                }\n            }\n        }\n        return TRUE;\n    case TNM_INVALIDATENODE:\n        {\n            PPH_TREENEW_NODE node = (PPH_TREENEW_NODE)LParam;\n            RECT rect;\n\n            if (!node->Visible)\n                return FALSE;\n\n            if (!PhTnpGetRowRects(Context, node->Index, node->Index, TRUE, &rect))\n                return FALSE;\n\n            InvalidateRect(WindowHandle, &rect, FALSE);\n        }\n        return TRUE;\n    case TNM_INVALIDATENODES:\n        {\n            RECT rect;\n\n            if (!PhTnpGetRowRects(Context, (ULONG)WParam, (ULONG)LParam, TRUE, &rect))\n                return FALSE;\n\n            InvalidateRect(WindowHandle, &rect, FALSE);\n        }\n        return TRUE;\n    case TNM_GETFIXEDHEADER:\n        return (LRESULT)Context->FixedHeaderHandle;\n    case TNM_GETHEADER:\n        return (LRESULT)Context->HeaderHandle;\n    case TNM_GETTOOLTIPS:\n        return (LRESULT)Context->TooltipsHandle;\n    case TNM_SELECTRANGE:\n    case TNM_DESELECTRANGE:\n        {\n            ULONG flags;\n            ULONG changedStart;\n            ULONG changedEnd;\n            RECT rect;\n\n            flags = 0;\n\n            if (Message == TNM_DESELECTRANGE)\n                flags |= TN_SELECT_DESELECT;\n\n            PhTnpSelectRange(Context, (ULONG)WParam, (ULONG)LParam, flags, &changedStart, &changedEnd);\n\n            if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n            {\n                InvalidateRect(WindowHandle, &rect, FALSE);\n            }\n        }\n        return TRUE;\n    case TNM_GETCOLUMNCOUNT:\n        return (LRESULT)Context->NumberOfColumns;\n    case TNM_SETREDRAW:\n        PhTnpSetRedraw(Context, !!WParam);\n        return (LRESULT)Context->EnableRedraw;\n    case TNM_GETVIEWPARTS:\n        {\n            PPH_TREENEW_VIEW_PARTS parts = (PPH_TREENEW_VIEW_PARTS)LParam;\n\n            parts->ClientRect = Context->ClientRect;\n            parts->HeaderHeight = Context->HeaderHeight;\n            parts->RowHeight = Context->RowHeight;\n            parts->VScrollWidth = Context->VScrollVisible ? Context->VScrollWidth : 0;\n            parts->HScrollHeight = Context->HScrollHeight ? Context->HScrollHeight : 0;\n            parts->VScrollPosition = Context->VScrollPosition;\n            parts->HScrollPosition = Context->HScrollPosition;\n            parts->FixedWidth = Context->FixedWidth;\n            parts->NormalLeft = Context->NormalLeft;\n            parts->NormalWidth = Context->TotalViewX;\n            parts->ScrollTickCount = (NtGetTickCount64() - Context->ScrollTickCount);\n        }\n        return TRUE;\n    case TNM_GETFIXEDCOLUMN:\n        return (LRESULT)Context->FixedColumn;\n    case TNM_GETFIRSTCOLUMN:\n        return (LRESULT)Context->FirstColumn;\n    case TNM_SETFOCUSNODE:\n        Context->FocusNode = (PPH_TREENEW_NODE)LParam;\n        return TRUE;\n    case TNM_SETMARKNODE:\n        Context->MarkNodeIndex = ((PPH_TREENEW_NODE)LParam)->Index;\n        return TRUE;\n    case TNM_SETHOTNODE:\n        PhTnpSetHotNode(Context, (PPH_TREENEW_NODE)LParam, FALSE);\n        return TRUE;\n    case TNM_SETEXTENDEDFLAGS:\n        Context->ExtendedFlags = (Context->ExtendedFlags & ~(ULONG)WParam) | ((ULONG)LParam & (ULONG)WParam);\n        return TRUE;\n    case TNM_GETCALLBACK:\n        {\n            PPH_TREENEW_CALLBACK *callback = (PPH_TREENEW_CALLBACK *)LParam;\n            PVOID *callbackContext = (PVOID *)WParam;\n\n            if (callback)\n            {\n                if (Context->Callback != PhTnpNullCallback)\n                    *callback = Context->Callback;\n                else\n                    *callback = NULL;\n            }\n\n            if (callbackContext)\n            {\n                *callbackContext = Context->CallbackContext;\n            }\n        }\n        return TRUE;\n    case TNM_HITTEST:\n        PhTnpHitTest(Context, (PPH_TREENEW_HIT_TEST)LParam);\n        return TRUE;\n    case TNM_GETVISIBLECOLUMNCOUNT:\n        return Context->NumberOfColumnsByDisplay + (Context->FixedColumnVisible ? 1 : 0);\n    case TNM_AUTOSIZECOLUMN:\n        {\n            ULONG id = (ULONG)WParam;\n            ULONG flags = (ULONG)LParam;\n            PPH_TREENEW_COLUMN column;\n\n            if (!(column = PhTnpLookupColumnById(Context, id)))\n                return FALSE;\n\n            if (!column->Visible)\n                return FALSE;\n\n            PhTnpAutoSizeColumnHeader(\n                Context,\n                column->Fixed ? Context->FixedHeaderHandle : Context->HeaderHandle,\n                column,\n                flags\n                );\n        }\n        return TRUE;\n    case TNM_SETEMPTYTEXT:\n        {\n            PPH_STRINGREF text = (PPH_STRINGREF)LParam;\n            ULONG flags = (ULONG)WParam;\n\n            Context->EmptyText = *text;\n        }\n        return TRUE;\n    case TNM_SETROWHEIGHT:\n        {\n            LONG rowHeight = (LONG)WParam;\n\n            if (rowHeight != 0)\n            {\n                Context->CustomRowHeight = TRUE;\n                Context->RowHeight = rowHeight;\n            }\n            else\n            {\n                Context->CustomRowHeight = FALSE;\n                PhTnpUpdateTextMetrics(Context);\n            }\n        }\n        return TRUE;\n    case TNM_ISFLATNODEVALID:\n        return !Context->SuspendUpdateStructure;\n    case TNM_THEMESUPPORT:\n        Context->ThemeSupport = !!WParam;\n        return TRUE;\n    case TNM_SETIMAGELIST:\n        {\n            Context->ImageListSupport = !!WParam;\n            Context->ImageListHandle = (HIMAGELIST)WParam;\n        }\n        return TRUE;\n    case TNM_SETCOLUMNTEXTCACHE:\n        {\n            PPH_TREENEW_SET_HEADER_CACHE headerCache = (PPH_TREENEW_SET_HEADER_CACHE)WParam;\n\n            Context->HeaderColumnCacheMax = headerCache->HeaderTreeColumnMax;\n            Context->HeaderStringCache = headerCache->HeaderTreeColumnStringCache;\n            Context->HeaderTextCache = headerCache->HeaderTreeColumnTextCache;\n        }\n        return TRUE;\n    case TNM_ENSUREVISIBLEINDEX:\n        return PhTnpEnsureVisibleNode(Context, (ULONG)LParam);\n    case TNM_GETVISIBLECOLUMN:\n        {\n            ULONG index = (ULONG)WParam;\n\n            if (index >= Context->NumberOfColumnsByDisplay + (Context->FixedColumnVisible ? 1 : 0))\n                return FALSE;\n\n            index = Context->ColumnsByDisplay[index - (Context->FixedColumnVisible ? 1 : 0)]->Id;\n\n            return PhTnpCopyColumn(Context, index, (PPH_TREENEW_COLUMN)LParam);\n        }\n        break;\n    case TNM_GETVISIBLECOLUMNARRAY:\n        {\n            ULONG count = (ULONG)WParam;\n            PULONG visible = (PULONG)LParam;\n\n            for (ULONG i = 0; i < count; i++)\n            {\n                if (visible[i] >= Context->AllocatedColumns)\n                    return FALSE;\n\n                visible[i] = Context->Columns[visible[i]]->Visible;\n            }\n        }\n        return TRUE;\n    case TNM_GETSELECTEDCOUNT:\n       {\n            ULONG i;\n            ULONG visibleCount;\n            ULONG selectedCount;\n            PPH_TREENEW_NODE node;\n\n            if (Context->SuspendUpdateStructure)\n                visibleCount = 0;\n            else\n                visibleCount = Context->FlatList->Count;\n            selectedCount = 0;\n\n            for (i = 0; i < visibleCount; i++)\n            {\n                node = Context->FlatList->Items[i];\n\n                if (node->Selected)\n                {\n                    selectedCount++;\n                }\n            }\n\n            return (LRESULT)selectedCount;\n       }\n       break;\n    case TNM_GETSELECTEDNODE:\n        {\n            ULONG i;\n            ULONG visibleCount;\n            PPH_TREENEW_NODE node;\n\n            if (Context->SuspendUpdateStructure)\n                visibleCount = 0;\n            else\n                visibleCount = Context->FlatList->Count;\n\n            for (i = 0; i < visibleCount; i++)\n            {\n                node = Context->FlatList->Items[i];\n\n                if (node->Selected)\n                {\n                    return (LRESULT)node;\n                }\n            }\n        }\n        break;\n    case TNM_FOCUSMARKSELECT:\n       {\n            PPH_TREENEW_NODE node = (PPH_TREENEW_NODE)LParam;\n\n            SetFocus(WindowHandle);\n\n            Context->FocusNode = node; // TNM_SETFOCUSNODE\n            Context->MarkNodeIndex = node->Index; // TNM_SETMARKNODE\n            PhTnpOnUserMessage(WindowHandle, Context, TNM_DESELECTRANGE, 0, -1);\n            PhTnpOnUserMessage(WindowHandle, Context, TNM_SELECTRANGE, node->Index, node->Index);\n            PhTnpEnsureVisibleNode(Context, node->Index); // TNM_ENSUREVISIBLE\n            PhTnpOnUserMessage(WindowHandle, Context, TNM_INVALIDATENODES, node->Index, node->Index);\n       }\n       return TRUE;\n    case TNM_FOCUSVISIBLENODE:\n        {\n            ULONG i;\n            ULONG visibleCount;\n            PPH_TREENEW_NODE node;\n\n            if (Context->SuspendUpdateStructure)\n                visibleCount = 0;\n            else\n                visibleCount = Context->FlatList->Count;\n\n            for (i = 0; i < visibleCount; i++)\n            {\n                node = Context->FlatList->Items[i];\n\n                // Select the first visible node.\n                if (node->Visible)\n                {\n                    SetFocus(WindowHandle);\n\n                    Context->FocusNode = node; // TNM_SETFOCUSNODE\n                    Context->MarkNodeIndex = node->Index; // TNM_SETMARKNODE\n                    PhTnpOnUserMessage(WindowHandle, Context, TNM_DESELECTRANGE, 0, -1);\n                    PhTnpOnUserMessage(WindowHandle, Context, TNM_SELECTRANGE, node->Index, node->Index);\n                    PhTnpEnsureVisibleNode(Context, node->Index); // TNM_ENSUREVISIBLE\n                    PhTnpOnUserMessage(WindowHandle, Context, TNM_INVALIDATENODES, node->Index, node->Index);\n\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    case TNM_GETCELLPARTS:\n        {\n            PPH_TREENEW_GET_CELL_PARTS getCellParts = (PPH_TREENEW_GET_CELL_PARTS)LParam;\n\n            if (getCellParts->Node && getCellParts->Column)\n            {\n                ULONG measureFlags = 0;\n                PH_TREENEW_CELL_PARTS cellparts;\n\n                if (FlagOn(getCellParts->Flags, TN_MEASURE_TEXT))\n                {\n                    measureFlags |= TN_MEASURE_TEXT;\n                }\n\n                RtlZeroMemory(&cellparts, sizeof(PH_TREENEW_CELL_PARTS));\n\n                if (PhTnpGetCellParts(\n                    Context,\n                    getCellParts->Node->Index,\n                    getCellParts->Column,\n                    measureFlags,\n                    &cellparts\n                    ))\n                {\n                    RtlCopyMemory(&getCellParts->Parts, &cellparts, sizeof(PH_TREENEW_CELL_PARTS));\n                    return TRUE;\n                }\n            }\n        }\n        break;\n    }\n\n    return 0;\n}\n\n/**\n * Sets the font for the treenew control and updates related metrics.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Font Handle to the font to set, or NULL to use the default font.\n * \\param Redraw TRUE to redraw the control after setting the font, FALSE otherwise.\n */\nVOID PhTnpSetFont(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HFONT Font,\n    _In_ BOOLEAN Redraw\n    )\n{\n    LOGFONT logFont;\n\n    if (Context->FontOwned)\n    {\n        DeleteFont(Context->Font);\n        Context->FontOwned = FALSE;\n    }\n\n    Context->Font = Font;\n\n    if (!Context->Font)\n    {\n        if (PhGetSystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, Context->WindowDpi))\n        {\n            Context->Font = CreateFontIndirect(&logFont);\n            Context->FontOwned = TRUE;\n        }\n    }\n\n    SetWindowFont(Context->FixedHeaderHandle, Context->Font, Redraw);\n    SetWindowFont(Context->HeaderHandle, Context->Font, Redraw);\n\n    if (Context->TooltipsHandle)\n    {\n        SetWindowFont(Context->TooltipsHandle, Context->Font, FALSE);\n        Context->TooltipFont = Context->Font;\n    }\n\n    PhTnpUpdateTextMetrics(Context);\n}\n\n/**\n * Updates the cached system metrics used by the treenew control.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpUpdateSystemMetrics(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    Context->WindowDpi = PhGetWindowDpi(Context->Handle);\n\n    Context->VScrollWidth = PhGetSystemMetrics(SM_CXVSCROLL, Context->WindowDpi);\n    Context->HScrollHeight = PhGetSystemMetrics(SM_CYHSCROLL, Context->WindowDpi);\n    Context->SystemBorderX = PhGetSystemMetrics(SM_CXBORDER, Context->WindowDpi);\n    Context->SystemBorderY = PhGetSystemMetrics(SM_CYBORDER, Context->WindowDpi);\n    Context->SystemEdgeX = PhGetSystemMetrics(SM_CXEDGE, Context->WindowDpi);\n    Context->SystemEdgeY = PhGetSystemMetrics(SM_CYEDGE, Context->WindowDpi);\n    Context->SystemDragX = PhGetSystemMetrics(SM_CXDRAG, Context->WindowDpi);\n    Context->SystemDragY = PhGetSystemMetrics(SM_CYDRAG, Context->WindowDpi);\n    Context->SmallIconWidth = PhGetSystemMetrics(SM_CXSMICON, Context->WindowDpi);\n    Context->SmallIconHeight = PhGetSystemMetrics(SM_CYSMICON, Context->WindowDpi);\n\n    Context->CellMarginLeft = PhGetDpi(TNP_CELL_LEFT_MARGIN, Context->WindowDpi);\n    Context->CellMarginRight = PhGetDpi(TNP_CELL_RIGHT_MARGIN, Context->WindowDpi);\n    Context->IconRightPadding = PhGetDpi(TNP_ICON_RIGHT_PADDING, Context->WindowDpi);\n    Context->TextMarginPadding = PhGetDpi(6 + 6, Context->WindowDpi);\n    Context->HeaderTextPadding = PhGetDpi(5, Context->WindowDpi);\n    Context->HeaderTextMargin = PhGetDpi(2, Context->WindowDpi);\n    Context->HeaderRowMargin = PhGetDpi(1, Context->WindowDpi);\n\n    if (Context->SystemDragX < 2)\n        Context->SystemDragX = 2;\n    if (Context->SystemDragY < 2)\n        Context->SystemDragY = 2;\n}\n\n/**\n * Updates the text metrics and row height for the treenew control.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpUpdateTextMetrics(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    HDC hdc;\n\n    if (hdc = GetDC(Context->Handle))\n    {\n        SelectFont(hdc, Context->Font);\n        GetTextMetrics(hdc, &Context->TextMetrics);\n\n        if (!Context->CustomRowHeight)\n        {\n            // Below we try to match the row height as calculated by the list view, even if it\n            // involves magic numbers. On Vista and above there seems to be extra padding.\n\n            Context->RowHeight = Context->TextMetrics.tmHeight;\n\n            if (Context->Style & TN_STYLE_ICONS)\n            {\n                if (Context->RowHeight < Context->SmallIconWidth)\n                    Context->RowHeight = Context->SmallIconWidth;\n            }\n            else\n            {\n                if (!(Context->Style & TN_STYLE_THIN_ROWS))\n                    Context->RowHeight += 1; // HACK\n            }\n\n            Context->RowHeight += Context->HeaderRowMargin; // HACK\n\n            if (!(Context->Style & TN_STYLE_THIN_ROWS))\n                Context->RowHeight += Context->HeaderTextMargin; // HACK\n        }\n\n        ReleaseDC(Context->Handle, hdc);\n    }\n}\n\n/**\n * Updates the theme data and colors for the treenew control.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpUpdateThemeData(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    Context->DefaultBackColor = GetSysColor(COLOR_WINDOW);\n    Context->DefaultForeColor = GetSysColor(COLOR_WINDOWTEXT);\n    Context->ThemeActive = !!PhIsThemeActive();\n\n    if (Context->ThemeData)\n    {\n        PhCloseThemeData(Context->ThemeData);\n        Context->ThemeData = NULL;\n    }\n\n    Context->ThemeData = PhOpenThemeData(Context->Handle, VSCLASS_TREEVIEW, Context->WindowDpi);\n\n    if (Context->ThemeData)\n    {\n        Context->ThemeHasItemBackground = !!PhIsThemePartDefined(Context->ThemeData, TVP_TREEITEM, 0);\n        Context->ThemeHasGlyph = !!PhIsThemePartDefined(Context->ThemeData, TVP_GLYPH, 0);\n        Context->ThemeHasHotGlyph = !!PhIsThemePartDefined(Context->ThemeData, TVP_HOTGLYPH, 0);\n    }\n    else\n    {\n        Context->ThemeHasItemBackground = FALSE;\n        Context->ThemeHasGlyph = FALSE;\n        Context->ThemeHasHotGlyph = FALSE;\n    }\n}\n\n/**\n * Initializes the theme data for the treenew control on first use.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpInitializeThemeData(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (!Context->ThemeInitialized)\n    {\n        PhTnpUpdateThemeData(Context);\n        Context->ThemeInitialized = TRUE;\n    }\n}\n\n/**\n * Cancels any active tracking operation in the treenew control.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpCancelTrack(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    PhTnpSetFixedWidth(Context, Context->TrackOldFixedWidth);\n    ReleaseCapture();\n}\n\n/**\n * Recalculates the layout of all treenew control elements.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpLayout(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT clientRect;\n\n    if (Context->EnableRedraw <= 0)\n    {\n        Context->SuspendUpdateLayout = TRUE;\n        return;\n    }\n\n    clientRect = Context->ClientRect;\n\n    PhTnpUpdateScrollBars(Context);\n\n    // Vertical scroll bar\n    if (Context->VScrollVisible)\n    {\n        MoveWindow(\n            Context->VScrollHandle,\n            clientRect.right - Context->VScrollWidth,\n            0,\n            Context->VScrollWidth,\n            clientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0),\n            TRUE\n            );\n    }\n\n    // Horizontal scroll bar\n    if (Context->HScrollVisible)\n    {\n        MoveWindow(\n            Context->HScrollHandle,\n            Context->NormalLeft,\n            clientRect.bottom - Context->HScrollHeight,\n            clientRect.right - Context->NormalLeft - (Context->VScrollVisible ? Context->VScrollWidth : 0),\n            Context->HScrollHeight,\n            TRUE\n            );\n    }\n\n    // Filler box\n    if (Context->VScrollVisible && Context->HScrollVisible)\n    {\n        MoveWindow(\n            Context->FillerBoxHandle,\n            clientRect.right - Context->VScrollWidth,\n            clientRect.bottom - Context->HScrollHeight,\n            Context->VScrollWidth,\n            Context->HScrollHeight,\n            TRUE\n            );\n    }\n\n    PhTnpLayoutHeader(Context);\n\n    // Redraw the entire window if we are displaying empty text.\n    if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0)\n        InvalidateRect(Context->Handle, NULL, FALSE);\n}\n\n/**\n * Recalculates the layout of the header controls.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpLayoutHeader(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT rect;\n    HDLAYOUT hdl;\n    WINDOWPOS windowPos;\n\n    hdl.prc = &rect;\n    hdl.pwpos = &windowPos;\n\n    if (!(Context->Style & TN_STYLE_NO_COLUMN_HEADER))\n    {\n        LONG headerHeight = 0;\n\n        if (Context->HeaderCustomDraw)\n        {\n            // HACK: Use the row height instead of querying the font. (dmex)\n            if (Context->RowHeight)\n            {\n                headerHeight = Context->RowHeight + 1;\n            }\n            else\n            {\n                TEXTMETRIC textMetrics;\n                HDC hdc;\n\n                if (hdc = GetDC(Context->FixedHeaderHandle))\n                {\n                    SelectFont(hdc, GetWindowFont(Context->FixedHeaderHandle));\n                    GetTextMetrics(hdc, &textMetrics);\n\n                    // Below we try to match the height as calculated by the header, even if it\n                    // involves magic numbers. On Vista and above there seems to be extra padding.\n\n                    headerHeight = textMetrics.tmHeight;\n                    ReleaseDC(Context->FixedHeaderHandle, hdc);\n                }\n\n                headerHeight += 5; // Add magic padding\n            }\n        }\n\n        // Fixed portion header control\n        rect.left = 0;\n        rect.top = 0;\n        rect.right = Context->NormalLeft;\n        rect.bottom = Context->ClientRect.bottom;\n        Header_Layout(Context->FixedHeaderHandle, &hdl);\n        SetWindowPos(Context->FixedHeaderHandle, NULL, windowPos.x, windowPos.y, windowPos.cx, windowPos.cy + headerHeight, windowPos.flags);\n        Context->HeaderHeight = windowPos.cy + headerHeight;\n\n        // Normal portion header control\n        rect.left = Context->NormalLeft - Context->HScrollPosition;\n        rect.top = 0;\n        rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n        rect.bottom = Context->ClientRect.bottom;\n        Header_Layout(Context->HeaderHandle, &hdl);\n        SetWindowPos(Context->HeaderHandle, NULL, windowPos.x, windowPos.y, windowPos.cx, windowPos.cy + headerHeight, windowPos.flags);\n    }\n    else\n    {\n        Context->HeaderHeight = 0;\n    }\n\n    if (Context->TooltipsHandle)\n    {\n        TOOLINFO toolInfo;\n\n        memset(&toolInfo, 0, sizeof(TOOLINFO));\n        toolInfo.cbSize = sizeof(TOOLINFO);\n        toolInfo.hwnd = Context->FixedHeaderHandle;\n        toolInfo.uId = TNP_TOOLTIPS_FIXED_HEADER;\n\n        if (PhGetClientRect(Context->FixedHeaderHandle, &toolInfo.rect))\n        {\n            SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo);\n        }\n\n        memset(&toolInfo, 0, sizeof(TOOLINFO));\n        toolInfo.cbSize = sizeof(TOOLINFO);\n        toolInfo.hwnd = Context->HeaderHandle;\n        toolInfo.uId = TNP_TOOLTIPS_HEADER;\n\n        if (PhGetClientRect(Context->HeaderHandle, &toolInfo.rect))\n        {\n            SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo);\n        }\n    }\n}\n\n/**\n * Sets the width of the fixed column.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param FixedWidth The new width for the fixed column.\n */\nVOID PhTnpSetFixedWidth(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG FixedWidth\n    )\n{\n    HDITEM item;\n\n    if (Context->FixedColumnVisible)\n    {\n        Context->FixedWidth = FixedWidth;\n\n        if (Context->FixedWidth < Context->FixedWidthMinimum)\n            Context->FixedWidth = Context->FixedWidthMinimum;\n\n        Context->NormalLeft = Context->FixedWidth + 1;\n\n        item.mask = HDI_WIDTH;\n        item.cxy = Context->FixedWidth + 1;\n        Header_SetItem(Context->FixedHeaderHandle, 0, &item);\n    }\n    else\n    {\n        Context->FixedWidth = 0;\n        Context->NormalLeft = 0;\n    }\n}\n\n/**\n * Enables or disables redrawing of the treenew control.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Redraw TRUE to enable redrawing, FALSE to disable.\n */\nVOID PhTnpSetRedraw(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Redraw\n    )\n{\n    if (Redraw)\n        Context->EnableRedraw++;\n    else\n        Context->EnableRedraw--;\n\n    if (Context->EnableRedraw == 1)\n    {\n        if (Context->SuspendUpdateStructure)\n        {\n            PhTnpRestructureNodes(Context);\n        }\n\n        if (Context->SuspendUpdateLayout)\n        {\n            PhTnpLayout(Context);\n        }\n\n        if (Context->SuspendUpdateMoveMouse)\n        {\n            POINT point;\n\n            if (PhGetClientPos(Context->Handle, &point))\n            {\n                PhTnpProcessMoveMouse(Context, point.x, point.y);\n            }\n        }\n\n        Context->SuspendUpdateStructure = FALSE;\n        Context->SuspendUpdateLayout = FALSE;\n        Context->SuspendUpdateMoveMouse = FALSE;\n\n        if (Context->SuspendUpdateRegion)\n        {\n            InvalidateRgn(Context->Handle, Context->SuspendUpdateRegion, FALSE);\n            DeleteRgn(Context->SuspendUpdateRegion);\n            Context->SuspendUpdateRegion = NULL;\n        }\n    }\n}\n\n/**\n * Sends a mouse event notification to the callback function.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Message The mouse event message type.\n * \\param CursorX The X coordinate of the cursor.\n * \\param CursorY The Y coordinate of the cursor.\n * \\param Node Pointer to the node under the cursor, if any.\n * \\param Column Pointer to the column under the cursor, if any.\n * \\param VirtualKeys The state of virtual keys.\n */\nVOID PhTnpSendMouseEvent(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY,\n    _In_opt_ PPH_TREENEW_NODE Node,\n    _In_opt_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG VirtualKeys\n    )\n{\n    PH_TREENEW_MOUSE_EVENT mouseEvent;\n\n    mouseEvent.Location.x = CursorX;\n    mouseEvent.Location.y = CursorY;\n    mouseEvent.Node = Node;\n    mouseEvent.Column = Column;\n    mouseEvent.KeyFlags = VirtualKeys;\n    Context->Callback(Context->Handle, Message, &mouseEvent, NULL, Context->CallbackContext);\n}\n\n/**\n * Looks up a column by its unique identifier.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Id The column identifier to search for.\n * \\return Pointer to the column structure if found, NULL otherwise.\n */\nPPH_TREENEW_COLUMN PhTnpLookupColumnById(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    )\n{\n    if (Id >= Context->AllocatedColumns)\n        return NULL;\n\n    return Context->Columns[Id];\n}\n\n/**\n * Adds a new column to the treenew control.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Column Pointer to the column structure to add.\n * \\return TRUE if the column was added successfully, FALSE otherwise.\n */\nBOOLEAN PhTnpAddColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column\n    )\n{\n    PPH_TREENEW_COLUMN realColumn;\n\n    // Check if a column with the same ID already exists.\n    if (Column->Id < Context->AllocatedColumns && Context->Columns[Column->Id])\n        return FALSE;\n\n    if (Context->NextId < Column->Id + 1)\n        Context->NextId = Column->Id + 1;\n\n    realColumn = PhAllocateCopy(Column, sizeof(PH_TREENEW_COLUMN));\n\n    if (realColumn->DpiScaleOnAdd)\n    {\n        if (WindowsVersion >= WINDOWS_10)\n        {\n            realColumn->Width = PhGetDpi(realColumn->Width, Context->WindowDpi);\n        }\n        realColumn->DpiScaleOnAdd = FALSE;\n    }\n\n    if (Context->AllocatedColumns < Context->NextId)\n    {\n        PhTnpExpandAllocatedColumns(Context);\n    }\n\n    Context->Columns[Column->Id] = realColumn;\n    Context->NumberOfColumns++;\n\n    if (realColumn->Fixed)\n    {\n        if (Context->FixedColumn)\n        {\n            // We already have a fixed column, and we can't have two. Make this new column un-fixed.\n            realColumn->Fixed = FALSE;\n        }\n        else\n        {\n            Context->FixedColumn = realColumn;\n        }\n\n        realColumn->DisplayIndex = 0;\n        realColumn->s.ViewX = 0;\n    }\n\n    if (realColumn->Visible)\n    {\n        BOOLEAN updateHeaders;\n\n        updateHeaders = FALSE;\n\n        assert(Context->NumberOfColumnsByDisplay == (ULONG)Header_GetItemCount(Context->HeaderHandle));\n        //if (!realColumn->Fixed && realColumn->DisplayIndex != Header_GetItemCount(Context->HeaderHandle))\n        if (!realColumn->Fixed && realColumn->DisplayIndex != Context->NumberOfColumnsByDisplay)\n            updateHeaders = TRUE;\n\n        realColumn->s.ViewIndex = PhTnpInsertColumnHeader(Context, realColumn);\n\n        if (updateHeaders)\n            PhTnpUpdateColumnHeaders(Context);\n    }\n    else\n    {\n        realColumn->s.ViewIndex = -1;\n    }\n\n    PhTnpUpdateColumnMaps(Context);\n\n    if (realColumn->Visible)\n        PhTnpLayout(Context);\n\n    return TRUE;\n}\n\n/**\n * Removes a column from the tree view control by its ID.\n *\n * This function deletes the specified column, updates the layout if necessary,\n * and frees associated resources. The column is removed from the internal columns array,\n * and the column maps are updated accordingly.\n *\n * \\param Context Pointer to the tree-new context.\n * \\param Id The ID of the column to remove.\n * \\return TRUE if the column was removed; FALSE if the column was not found.\n */\nBOOLEAN PhTnpRemoveColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    )\n{\n    PPH_TREENEW_COLUMN realColumn;\n    BOOLEAN updateLayout;\n\n    if (!(realColumn = PhTnpLookupColumnById(Context, Id)))\n        return FALSE;\n\n    updateLayout = FALSE;\n\n    if (realColumn->Visible)\n        updateLayout = TRUE;\n\n    PhTnpDeleteColumnHeader(Context, realColumn);\n    Context->Columns[realColumn->Id] = NULL;\n    PhFree(realColumn);\n    PhTnpUpdateColumnMaps(Context);\n\n    if (updateLayout)\n        PhTnpLayout(Context);\n\n    Context->NumberOfColumns--;\n\n    return TRUE;\n}\n\n/**\n * Copies the data of a column by its ID into a provided column structure.\n *\n * This function looks up the column by ID and copies its data into the output structure.\n *\n * \\param Context Pointer to the tree-new context.\n * \\param Id The ID of the column to copy.\n * \\param Column Pointer to a PH_TREENEW_COLUMN structure to receive the data.\n * \\return TRUE if the column was found and copied; FALSE otherwise.\n */\n_Success_(return)\nBOOLEAN PhTnpCopyColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id,\n    _Out_ PPH_TREENEW_COLUMN Column\n    )\n{\n    PPH_TREENEW_COLUMN realColumn;\n\n    if (!(realColumn = PhTnpLookupColumnById(Context, Id)))\n        return FALSE;\n\n    memcpy(Column, realColumn, sizeof(PH_TREENEW_COLUMN));\n\n    return TRUE;\n}\n\n/**\n * Changes the properties of a column by its ID and a mask.\n *\n * This function updates the specified properties of a column, such as visibility, width,\n * alignment, display index, and other attributes, according to the provided mask and column data.\n * It handles layout and header updates as needed.\n *\n * \\param Context Pointer to the tree-new context.\n * \\param Mask Bitmask specifying which properties to update.\n * \\param Id The ID of the column to change.\n * \\param Column Pointer to a PH_TREENEW_COLUMN structure containing new values.\n * \\return TRUE if the column was found and updated; FALSE otherwise.\n */\nBOOLEAN PhTnpChangeColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Mask,\n    _In_ ULONG Id,\n    _In_ PPH_TREENEW_COLUMN Column\n    )\n{\n    PPH_TREENEW_COLUMN realColumn;\n    BOOLEAN addingOrRemoving;\n\n    if (!(realColumn = PhTnpLookupColumnById(Context, Id)))\n        return FALSE;\n\n    addingOrRemoving = FALSE;\n\n    if (Mask & TN_COLUMN_FLAG_VISIBLE)\n    {\n        if (realColumn->Visible != Column->Visible)\n        {\n            addingOrRemoving = TRUE;\n        }\n    }\n\n    if (Mask & TN_COLUMN_FLAG_CUSTOMDRAW)\n    {\n        realColumn->CustomDraw = Column->CustomDraw;\n    }\n\n    if (Mask & TN_COLUMN_FLAG_SORTDESCENDING)\n    {\n        realColumn->SortDescending = Column->SortDescending;\n    }\n\n    if (Mask & (TN_COLUMN_TEXT | TN_COLUMN_WIDTH | TN_COLUMN_ALIGNMENT | TN_COLUMN_DISPLAYINDEX))\n    {\n        BOOLEAN updateHeaders;\n        BOOLEAN updateMaps;\n        BOOLEAN updateLayout;\n\n        updateHeaders = FALSE;\n        updateMaps = FALSE;\n        updateLayout = FALSE;\n\n        if (Mask & TN_COLUMN_TEXT)\n        {\n            realColumn->Text = Column->Text;\n        }\n\n        if (Mask & TN_COLUMN_WIDTH)\n        {\n            realColumn->Width = Column->Width;\n            updateMaps = TRUE;\n        }\n\n        if (Mask & TN_COLUMN_ALIGNMENT)\n        {\n            realColumn->Alignment = Column->Alignment;\n        }\n\n        if (Mask & TN_COLUMN_DISPLAYINDEX)\n        {\n            realColumn->DisplayIndex = Column->DisplayIndex;\n            updateHeaders = TRUE;\n            updateMaps = TRUE;\n            updateLayout = TRUE;\n        }\n\n        if (!addingOrRemoving && realColumn->Visible)\n        {\n            PhTnpChangeColumnHeader(Context, Mask, realColumn);\n\n            if (updateHeaders)\n                PhTnpUpdateColumnHeaders(Context);\n            if (updateMaps)\n                PhTnpUpdateColumnMaps(Context);\n            if (updateLayout)\n                PhTnpLayout(Context);\n        }\n    }\n\n    if (Mask & TN_COLUMN_CONTEXT)\n    {\n        realColumn->Context = Column->Context;\n    }\n\n    if (Mask & TN_COLUMN_TEXTFLAGS)\n    {\n        realColumn->TextFlags = Column->TextFlags;\n    }\n\n    if (addingOrRemoving)\n    {\n        if (Column->Visible)\n        {\n            BOOLEAN updateHeaders;\n\n            updateHeaders = FALSE;\n\n            if (realColumn->Fixed)\n            {\n                realColumn->DisplayIndex = 0;\n            }\n            else\n            {\n                if (Mask & TN_COLUMN_DISPLAYINDEX)\n                    updateHeaders = TRUE;\n                else\n                    realColumn->DisplayIndex = Header_GetItemCount(Context->HeaderHandle);\n            }\n\n            realColumn->s.ViewIndex = PhTnpInsertColumnHeader(Context, realColumn);\n\n            if (updateHeaders)\n                PhTnpUpdateColumnHeaders(Context);\n        }\n        else\n        {\n            PhTnpDeleteColumnHeader(Context, realColumn);\n        }\n\n        PhTnpUpdateColumnMaps(Context);\n        PhTnpLayout(Context);\n    }\n\n    return TRUE;\n}\n\n/**\n * Expands the allocated columns array for the tree view control.\n *\n * This function doubles the size of the columns array when more space is needed,\n * or initializes it if not already allocated. It ensures that the array is large enough\n * to accommodate all columns, and zeroes the newly allocated memory.\n *\n * \\param Context Pointer to the tree-new context.\n */\nVOID PhTnpExpandAllocatedColumns(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (Context->Columns)\n    {\n        ULONG oldAllocatedColumns;\n\n        oldAllocatedColumns = Context->AllocatedColumns;\n        Context->AllocatedColumns *= 2;\n\n        if (Context->AllocatedColumns < Context->NextId)\n            Context->AllocatedColumns = Context->NextId;\n\n        Context->Columns = PhReAllocate(\n            Context->Columns,\n            Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN)\n            );\n\n        // Zero the newly allocated portion.\n        memset(\n            &Context->Columns[oldAllocatedColumns],\n            0,\n            (Context->AllocatedColumns - oldAllocatedColumns) * sizeof(PPH_TREENEW_COLUMN)\n            );\n    }\n    else\n    {\n        Context->AllocatedColumns = 16;\n\n        if (Context->AllocatedColumns < Context->NextId)\n            Context->AllocatedColumns = Context->NextId;\n\n        Context->Columns = PhAllocate(\n            Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN)\n            );\n        memset(Context->Columns, 0, Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN));\n    }\n}\n\n/**\n * Updates the internal column mapping arrays.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpUpdateColumnMaps(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    ULONG i;\n    LONG x;\n\n    if (Context->AllocatedColumnsByDisplay < Context->NumberOfColumns)\n    {\n        if (Context->ColumnsByDisplay)\n            PhFree(Context->ColumnsByDisplay);\n\n        Context->ColumnsByDisplay = PhAllocate(sizeof(PPH_TREENEW_COLUMN) * Context->NumberOfColumns);\n        Context->AllocatedColumnsByDisplay = Context->NumberOfColumns;\n    }\n\n    memset(Context->ColumnsByDisplay, 0, sizeof(PPH_TREENEW_COLUMN) * Context->AllocatedColumnsByDisplay);\n\n    for (i = 0; i < Context->NextId; i++)\n    {\n        if (!Context->Columns[i])\n            continue;\n\n        if (Context->Columns[i]->Visible && !Context->Columns[i]->Fixed && Context->Columns[i]->DisplayIndex != ULONG_MAX)\n        {\n            if (Context->Columns[i]->DisplayIndex >= Context->NumberOfColumns)\n            {\n                PhRaiseStatus(STATUS_INTERNAL_ERROR);\n                return;\n            }\n\n            Context->ColumnsByDisplay[Context->Columns[i]->DisplayIndex] = Context->Columns[i];\n        }\n    }\n\n    x = 0;\n\n    for (i = 0; i < Context->AllocatedColumnsByDisplay; i++)\n    {\n        if (!Context->ColumnsByDisplay[i])\n            break;\n\n        Context->ColumnsByDisplay[i]->s.ViewX = x;\n        x += Context->ColumnsByDisplay[i]->Width;\n    }\n\n    Context->NumberOfColumnsByDisplay = i;\n    Context->TotalViewX = x;\n\n    if (Context->FixedColumnVisible)\n        Context->FirstColumn = Context->FixedColumn;\n    else if (Context->NumberOfColumnsByDisplay != 0)\n        Context->FirstColumn = Context->ColumnsByDisplay[0];\n    else\n        Context->FirstColumn = NULL;\n\n    if (Context->NumberOfColumnsByDisplay != 0)\n        Context->LastColumn = Context->ColumnsByDisplay[Context->NumberOfColumnsByDisplay - 1];\n    else if (Context->FixedColumnVisible)\n        Context->LastColumn = Context->FixedColumn;\n    else\n        Context->LastColumn = NULL;\n}\n\n/**\n * Inserts a column header into the appropriate header control.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Column Pointer to the column structure.\n * \\return The index of the inserted header item, or -1 on failure.\n */\nLONG PhTnpInsertColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column\n    )\n{\n    HDITEM item;\n\n    if (Column->Fixed)\n    {\n        if (Column->Width < Context->FixedWidthMinimum)\n            Column->Width = Context->FixedWidthMinimum;\n\n        Context->FixedWidth = Column->Width;\n        Context->NormalLeft = Context->FixedWidth + 1;\n        Context->FixedColumnVisible = TRUE;\n\n        if (!(Context->Style & TN_STYLE_NO_DIVIDER))\n            Context->FixedDividerVisible = TRUE;\n    }\n\n    memset(&item, 0, sizeof(HDITEM));\n    item.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT | HDI_LPARAM | HDI_ORDER;\n    item.cxy = Column->Width;\n    item.pszText = (PWSTR)Column->Text;\n    item.fmt = 0;\n    item.lParam = (LPARAM)Column;\n\n    if (Column->Fixed)\n        item.cxy++;\n\n    if (Column->Fixed)\n        item.iOrder = 0;\n    else\n        item.iOrder = Column->DisplayIndex;\n\n    if (Column->Alignment & PH_ALIGN_LEFT)\n        item.fmt |= HDF_LEFT;\n    else if (Column->Alignment & PH_ALIGN_RIGHT)\n        item.fmt |= HDF_RIGHT;\n    else\n        item.fmt |= HDF_CENTER;\n\n    if (Column->Id == Context->SortColumn)\n    {\n        if (Context->SortOrder == AscendingSortOrder)\n            item.fmt |= HDF_SORTUP;\n        else if (Context->SortOrder == DescendingSortOrder)\n            item.fmt |= HDF_SORTDOWN;\n    }\n\n    Column->Visible = TRUE;\n\n    if (Column->Fixed)\n        return Header_InsertItem(Context->FixedHeaderHandle, 0, &item);\n    else\n        return Header_InsertItem(Context->HeaderHandle, MAXINT, &item);\n}\n\n/**\n * Changes the properties of a column header.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Mask Bitmask specifying which properties to update.\n * \\param Column Pointer to the column structure.\n */\nVOID PhTnpChangeColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Mask,\n    _In_ PPH_TREENEW_COLUMN Column\n    )\n{\n    HDITEM item;\n\n    memset(&item, 0, sizeof(HDITEM));\n    item.mask = 0;\n\n    if (Mask & TN_COLUMN_TEXT)\n    {\n        item.mask |= HDI_TEXT;\n        item.pszText = (PWSTR)Column->Text;\n    }\n\n    if (Mask & TN_COLUMN_WIDTH)\n    {\n        item.mask |= HDI_WIDTH;\n        item.cxy = Column->Width;\n\n        if (Column->Fixed)\n            item.cxy++;\n    }\n\n    if (Mask & TN_COLUMN_ALIGNMENT)\n    {\n        item.mask |= HDI_FORMAT;\n        item.fmt = 0;\n\n        if (Column->Alignment & PH_ALIGN_LEFT)\n            item.fmt |= HDF_LEFT;\n        else if (Column->Alignment & PH_ALIGN_RIGHT)\n            item.fmt |= HDF_RIGHT;\n        else\n            item.fmt |= HDF_CENTER;\n\n        if (Column->Id == Context->SortColumn)\n        {\n            if (Context->SortOrder == AscendingSortOrder)\n                item.fmt |= HDF_SORTUP;\n            else if (Context->SortOrder == DescendingSortOrder)\n                item.fmt |= HDF_SORTDOWN;\n        }\n    }\n\n    if (Mask & TN_COLUMN_DISPLAYINDEX)\n    {\n        item.mask |= HDI_ORDER;\n\n        if (Column->Fixed)\n            item.iOrder = 0;\n        else\n            item.iOrder = Column->DisplayIndex;\n    }\n\n    if (Column->Fixed)\n        Header_SetItem(Context->FixedHeaderHandle, 0, &item);\n    else\n        Header_SetItem(Context->HeaderHandle, Column->s.ViewIndex, &item);\n}\n\n/**\n * Deletes a column header from the header control.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Column Pointer to the column structure.\n */\nVOID PhTnpDeleteColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_COLUMN Column\n    )\n{\n    if (Column->Fixed)\n    {\n        Context->FixedColumn = NULL;\n        Context->FixedWidth = 0;\n        Context->NormalLeft = 0;\n        Context->FixedColumnVisible = FALSE;\n        Context->FixedDividerVisible = FALSE;\n    }\n\n    if (Column->Fixed)\n        Header_DeleteItem(Context->FixedHeaderHandle, Column->s.ViewIndex);\n    else\n        Header_DeleteItem(Context->HeaderHandle, Column->s.ViewIndex);\n\n    Column->Visible = FALSE;\n    Column->s.ViewIndex = -1;\n    PhTnpUpdateColumnHeaders(Context);\n}\n\n/**\n * Updates all column headers to reflect current column states.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpUpdateColumnHeaders(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    LONG count;\n    LONG i;\n    HDITEM item;\n    PPH_TREENEW_COLUMN column;\n\n    item.mask = HDI_WIDTH | HDI_LPARAM | HDI_ORDER;\n\n    // Fixed column\n\n    if (Context->FixedColumnVisible && Header_GetItem(Context->FixedHeaderHandle, 0, &item))\n    {\n        column = Context->FixedColumn;\n        column->Width = item.cxy - 1;\n    }\n\n    // Normal columns\n\n    count = Header_GetItemCount(Context->HeaderHandle);\n\n    if (count != INT_ERROR)\n    {\n        for (i = 0; i < count; i++)\n        {\n            if (Header_GetItem(Context->HeaderHandle, i, &item))\n            {\n                column = (PPH_TREENEW_COLUMN)item.lParam;\n                column->s.ViewIndex = i;\n                column->Width = item.cxy;\n                column->DisplayIndex = item.iOrder;\n            }\n        }\n    }\n}\n\n/**\n * Updates column headers after a DPI change.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param OldWindowDpi The previous DPI value.\n * \\param NewWindowDpi The new DPI value.\n */\nVOID PhTnpUpdateColumnHeadersDpiChanged(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG OldWindowDpi,\n    _In_ LONG NewWindowDpi\n    )\n{\n    LONG count;\n    LONG i;\n    HDITEM item;\n    PPH_TREENEW_COLUMN column;\n\n    item.mask = HDI_WIDTH | HDI_LPARAM;\n\n    // Fixed column\n\n    if (Context->FixedColumnVisible && Header_GetItem(Context->FixedHeaderHandle, 0, &item))\n    {\n        column = Context->FixedColumn;\n        column->Width = PhMultiplyDivideSigned(item.cxy, NewWindowDpi, OldWindowDpi);\n\n        PhTnpChangeColumn(Context, TN_COLUMN_WIDTH, column->Id, column);\n    }\n\n    // Normal columns\n\n    count = Header_GetItemCount(Context->HeaderHandle);\n\n    if (count != INT_ERROR)\n    {\n        for (i = 0; i < count; i++)\n        {\n            if (Header_GetItem(Context->HeaderHandle, i, &item))\n            {\n                column = (PPH_TREENEW_COLUMN)item.lParam;\n                column->Width = PhMultiplyDivideSigned(item.cxy, NewWindowDpi, OldWindowDpi);\n\n                PhTnpChangeColumn(Context, TN_COLUMN_WIDTH, column->Id, column);\n            }\n        }\n    }\n}\n\n/**\n * Processes a column resize operation.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Column Pointer to the column being resized.\n * \\param Delta The change in width.\n */\nVOID PhTnpProcessResizeColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ LONG Delta\n    )\n{\n    RECT rect;\n    LONG columnLeft;\n\n    if (Column->Fixed)\n    {\n        columnLeft = 0;\n    }\n    else\n    {\n        columnLeft = Context->NormalLeft + Column->s.ViewX - Context->HScrollPosition;\n    }\n\n    // Scroll the content to the right of the column.\n    //\n    // Clip the scroll area to the new width, or the old width if that is further to the left. We\n    // may have the WS_CLIPCHILDREN style set, so we need to remove the horizontal scrollbar from\n    // the rectangle, otherwise ScrollWindowEx will want to invalidate the entire region! (The\n    // horizontal scrollbar is an overlapping child control.)\n    rect.left = columnLeft + Column->Width;\n    rect.top = Context->HeaderHeight;\n    rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n    rect.bottom = Context->ClientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0);\n\n    if (Delta > 0)\n        rect.left -= Delta; // old width\n\n    // Scroll the window.\n    ScrollWindowEx(\n        Context->Handle,\n        Delta,\n        0,\n        &rect,\n        &rect,\n        NULL,\n        NULL,\n        SW_INVALIDATE\n        );\n\n    UpdateWindow(Context->Handle); // required\n\n    if (Context->HScrollVisible)\n    {\n        // We excluded the bottom region - invalidate it now.\n        rect.top = rect.bottom;\n        rect.bottom = Context->ClientRect.bottom;\n        InvalidateRect(Context->Handle, &rect, FALSE);\n    }\n\n    PhTnpLayout(Context);\n\n    // Redraw the whole column because the content may depend on the width (e.g. text ellipsis).\n    rect.left = columnLeft;\n    rect.top = Context->HeaderHeight;\n    rect.right = columnLeft + Column->Width;\n    RedrawWindow(Context->Handle, &rect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); // must be RedrawWindow\n}\n\n/**\n * Processes a column sort operation.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param NewColumn Pointer to the column being sorted.\n */\nVOID PhTnpProcessSortColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN NewColumn\n    )\n{\n    PH_TREENEW_SORT_CHANGED_EVENT sortOrderEvent;\n\n    if (NewColumn->Id == Context->SortColumn)\n    {\n        if (Context->TriState)\n        {\n            if (!NewColumn->SortDescending)\n            {\n                // Ascending -> Descending -> None\n\n                if (Context->SortOrder == AscendingSortOrder)\n                    Context->SortOrder = DescendingSortOrder;\n                else if (Context->SortOrder == DescendingSortOrder)\n                    Context->SortOrder = NoSortOrder;\n                else\n                    Context->SortOrder = AscendingSortOrder;\n            }\n            else\n            {\n                // Descending -> Ascending -> None\n\n                if (Context->SortOrder == DescendingSortOrder)\n                    Context->SortOrder = AscendingSortOrder;\n                else if (Context->SortOrder == AscendingSortOrder)\n                    Context->SortOrder = NoSortOrder;\n                else\n                    Context->SortOrder = DescendingSortOrder;\n            }\n        }\n        else\n        {\n            if (Context->SortOrder == AscendingSortOrder)\n                Context->SortOrder = DescendingSortOrder;\n            else\n                Context->SortOrder = AscendingSortOrder;\n        }\n    }\n    else\n    {\n        Context->SortColumn = NewColumn->Id;\n\n        if (!NewColumn->SortDescending)\n            Context->SortOrder = AscendingSortOrder;\n        else\n            Context->SortOrder = DescendingSortOrder;\n    }\n\n    PhTnpSetColumnHeaderSortIcon(Context, NewColumn);\n\n    memset(&sortOrderEvent, 0, sizeof(PH_TREENEW_SORT_CHANGED_EVENT));\n    sortOrderEvent.SortColumn = Context->SortColumn;\n    sortOrderEvent.SortOrder = Context->SortOrder;\n\n    Context->Callback(Context->Handle, TreeNewSortChanged, &sortOrderEvent, NULL, Context->CallbackContext);\n}\n\n/**\n * Sets the sort icon on a column header.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param SortColumnPointer Pointer to the column being sorted, or NULL to look it up.\n * \\return TRUE if the icon was set successfully, FALSE otherwise.\n */\nBOOLEAN PhTnpSetColumnHeaderSortIcon(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_COLUMN SortColumnPointer\n    )\n{\n    if (Context->SortOrder == NoSortOrder)\n    {\n        PhSetHeaderSortIcon(\n            Context->FixedHeaderHandle,\n            -1,\n            NoSortOrder\n            );\n        PhSetHeaderSortIcon(\n            Context->HeaderHandle,\n            -1,\n            NoSortOrder\n            );\n\n        return TRUE;\n    }\n\n    if (!SortColumnPointer)\n    {\n        if (!(SortColumnPointer = PhTnpLookupColumnById(Context, Context->SortColumn)))\n            return FALSE;\n    }\n\n    if (SortColumnPointer->Fixed)\n    {\n        PhSetHeaderSortIcon(\n            Context->FixedHeaderHandle,\n            0,\n            Context->SortOrder\n            );\n        PhSetHeaderSortIcon(\n            Context->HeaderHandle,\n            -1,\n            NoSortOrder\n            );\n    }\n    else\n    {\n        PhSetHeaderSortIcon(\n            Context->FixedHeaderHandle,\n            -1,\n            NoSortOrder\n            );\n        PhSetHeaderSortIcon(\n            Context->HeaderHandle,\n            SortColumnPointer->s.ViewIndex,\n            Context->SortOrder\n            );\n    }\n\n    return TRUE;\n}\n\n/**\n * Automatically sizes a column header to fit its content.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param HeaderHandle Handle to the header control.\n * \\param Column Pointer to the column to auto-size.\n * \\param Flags Flags controlling the auto-size behavior.\n */\nVOID PhTnpAutoSizeColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HWND HeaderHandle,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG Flags\n    )\n{\n    LONG newWidth;\n    HDITEM item;\n\n    if (Flags & TN_AUTOSIZE_REMAINING_SPACE)\n    {\n        newWidth = Context->ClientRect.right - (Context->TotalViewX - Column->Width);\n\n        if (Context->FixedColumn)\n            newWidth -= Context->FixedColumn->Width;\n        if (Context->VScrollVisible)\n            newWidth -= Context->VScrollWidth;\n\n        if (newWidth <= 0)\n            return;\n    }\n    else\n    {\n        ULONG i;\n        LONG maximumWidth;\n        PH_TREENEW_CELL_PARTS parts;\n        LONG width;\n\n        if (Context->FlatList->Count == 0)\n            return;\n        if (Column->CustomDraw)\n            return;\n\n        maximumWidth = 0;\n\n        for (i = 0; i < Context->FlatList->Count; i++)\n        {\n            if (PhTnpGetCellParts(Context, i, Column, TN_MEASURE_TEXT, &parts) &&\n                (parts.Flags & TN_PART_CELL) && (parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT))\n            {\n                width = parts.TextRect.right - parts.TextRect.left; // text width\n                width += parts.ContentRect.left - parts.CellRect.left; // left padding\n\n                if (maximumWidth < width)\n                    maximumWidth = width;\n            }\n        }\n\n        newWidth = maximumWidth + Context->CellMarginRight; // right padding\n\n        if (Column->Fixed)\n            newWidth++;\n\n        // Check the column header text width.\n        if (Column->Text)\n        {\n            PCWSTR text;\n            SIZE_T textCount;\n            HDC hdc;\n            SIZE textSize;\n\n            text = Column->Text;\n            textCount = PhCountStringZ(text);\n\n            if (hdc = GetDC(Context->Handle))\n            {\n                SelectFont(hdc, Context->Font);\n\n                if (GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize))\n                {\n                    if (newWidth < textSize.cx + Context->TextMarginPadding) // HACK: Magic values (same as our cell margins?)\n                        newWidth = textSize.cx + Context->TextMarginPadding;\n                }\n\n                ReleaseDC(Context->Handle, hdc);\n            }\n        }\n\n        // Check the custom header text width. (dmex)\n        if (Context->HeaderCustomDraw)\n        {\n            PH_STRINGREF headerString;\n\n            if (PhTnpGetColumnHeaderText(\n                Context,\n                Column,\n                &headerString\n                ))\n            {\n                HDC hdc;\n                SIZE textSize;\n\n                if (hdc = GetDC(Context->Handle))\n                {\n                    SelectFont(hdc, Context->HeaderBoldFontHandle);\n\n                    if (GetTextExtentPoint32(hdc, headerString.Buffer, (ULONG)headerString.Length / sizeof(WCHAR), &textSize))\n                    {\n                        if (newWidth < textSize.cx + Context->TextMarginPadding) // HACK: Magic values (same as our cell margins?)\n                            newWidth = textSize.cx + Context->TextMarginPadding;\n                    }\n\n                    ReleaseDC(Context->Handle, hdc);\n                }\n            }\n        }\n    }\n\n    item.mask = HDI_WIDTH;\n    item.cxy = newWidth;\n\n    Header_SetItem(HeaderHandle, Column->s.ViewIndex, &item);\n}\n\n/**\n * Gets the list of child nodes for a given node.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Node Pointer to the parent node, or NULL for root nodes.\n * \\param Children Pointer to receive the array of child nodes.\n * \\param NumberOfChildren Pointer to receive the number of children.\n * \\return TRUE if the operation succeeded, FALSE otherwise.\n */\n_Success_(return)\nBOOLEAN PhTnpGetNodeChildren(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_NODE Node,\n    _Out_ PPH_TREENEW_NODE **Children,\n    _Out_ PULONG NumberOfChildren\n    )\n{\n    PH_TREENEW_GET_CHILDREN getChildren;\n\n    getChildren.Flags = 0;\n    getChildren.Node = Node;\n    getChildren.Children = NULL;\n    getChildren.NumberOfChildren = 0;\n\n    if (Context->Callback(\n        Context->Handle,\n        TreeNewGetChildren,\n        &getChildren,\n        NULL,\n        Context->CallbackContext\n        ))\n    {\n        *Children = getChildren.Children;\n        *NumberOfChildren = getChildren.NumberOfChildren;\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Determines whether a node is a leaf node (has no children).\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Node Pointer to the node to check.\n * \\return TRUE if the node is a leaf, FALSE otherwise.\n */\nBOOLEAN PhTnpIsNodeLeaf(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node\n    )\n{\n    PH_TREENEW_IS_LEAF isLeaf;\n\n    isLeaf.Flags = 0;\n    isLeaf.Node = Node;\n    isLeaf.IsLeaf = TRUE;\n\n    if (Context->Callback(\n        Context->Handle,\n        TreeNewIsLeaf,\n        &isLeaf,\n        NULL,\n        Context->CallbackContext\n        ))\n    {\n        return isLeaf.IsLeaf;\n    }\n\n    // Doesn't matter, decide when we do the get-children callback.\n    return FALSE;\n}\n\n/**\n * Retrieves the text for a specific cell.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Node Pointer to the node.\n * \\param Id The column ID.\n * \\param Text Pointer to receive the cell text as a string reference.\n * \\return TRUE if text was retrieved, FALSE otherwise.\n */\n_Success_(return)\nBOOLEAN PhTnpGetCellText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Id,\n    _Out_ PPH_STRINGREF Text\n    )\n{\n    PH_TREENEW_GET_CELL_TEXT getCellText;\n\n    if (Id < Node->TextCacheSize && Node->TextCache[Id].Buffer)\n    {\n        *Text = Node->TextCache[Id];\n        return TRUE;\n    }\n\n    getCellText.Flags = 0;\n    getCellText.Node = Node;\n    getCellText.Id = Id;\n    PhInitializeEmptyStringRef(&getCellText.Text);\n\n    if (Context->Callback(\n        Context->Handle,\n        TreeNewGetCellText,\n        &getCellText,\n        NULL,\n        Context->CallbackContext\n        ) && getCellText.Text.Buffer)\n    {\n        *Text = getCellText.Text;\n\n        if ((getCellText.Flags & TN_CACHE) && Id < Node->TextCacheSize)\n            Node->TextCache[Id] = getCellText.Text;\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Restructures the flat list of visible nodes based on the tree hierarchy.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpRestructureNodes(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    PPH_TREENEW_NODE *children;\n    ULONG numberOfChildren;\n    ULONG i;\n\n    if (!PhTnpGetNodeChildren(Context, NULL, &children, &numberOfChildren))\n        return;\n\n    // We try to preserve the hot node, the focused node and the selection mark node. At this point\n    // all node pointers must be regarded as invalid, so we must not follow any pointers.\n\n    Context->FocusNodeFound = FALSE;\n\n    PhClearList(Context->FlatList);\n    Context->CanAnyExpand = FALSE;\n\n    for (i = 0; i < numberOfChildren; i++)\n    {\n        PhTnpInsertNodeChildren(Context, children[i], 0);\n    }\n\n    if (!Context->FocusNodeFound)\n        Context->FocusNode = NULL; // focused node is no longer present\n\n    if (Context->HotNodeIndex >= Context->FlatList->Count) // covers -1 case as well\n        Context->HotNodeIndex = ULONG_MAX;\n\n    if (Context->MarkNodeIndex >= Context->FlatList->Count)\n        Context->MarkNodeIndex = ULONG_MAX;\n}\n\n/**\n * Inserts child nodes into the flat list recursively.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Node Pointer to the parent node.\n * \\param Level The nesting level of the children.\n */\nVOID PhTnpInsertNodeChildren(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Level\n    )\n{\n    PPH_TREENEW_NODE *children;\n    ULONG numberOfChildren;\n    ULONG i;\n    ULONG nextLevel;\n\n    if (Node->Visible)\n    {\n        Node->Level = Level;\n\n        Node->Index = Context->FlatList->Count;\n        PhAddItemList(Context->FlatList, Node);\n\n        if (Context->FocusNode == Node)\n            Context->FocusNodeFound = TRUE;\n\n        nextLevel = Level + 1;\n    }\n    else\n    {\n        nextLevel = 0; // children of this node should be level 0\n    }\n\n    if (!(Node->s.IsLeaf = PhTnpIsNodeLeaf(Context, Node)))\n    {\n        Context->CanAnyExpand = TRUE;\n\n        if (Node->Expanded)\n        {\n            if (PhTnpGetNodeChildren(Context, Node, &children, &numberOfChildren))\n            {\n                for (i = 0; i < numberOfChildren; i++)\n                {\n                    PhTnpInsertNodeChildren(Context, children[i], nextLevel);\n                }\n\n                if (numberOfChildren == 0)\n                    Node->s.IsLeaf = TRUE;\n            }\n        }\n    }\n}\n\n/**\n * Sets the expanded state of a node.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Node Pointer to the node.\n * \\param Expanded TRUE to expand the node, FALSE to collapse it.\n */\nVOID PhTnpSetExpandedNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ BOOLEAN Expanded\n    )\n{\n    if (Node->Expanded != Expanded)\n    {\n        PH_TREENEW_NODE_EVENT nodeEvent;\n\n        memset(&nodeEvent, 0, sizeof(PH_TREENEW_NODE_EVENT));\n        Context->Callback(Context->Handle, TreeNewNodeExpanding, Node, &nodeEvent, Context->CallbackContext);\n\n        if (!nodeEvent.Handled)\n        {\n            if (!Expanded)\n            {\n                ULONG i;\n                PPH_TREENEW_NODE node;\n                BOOLEAN changed;\n\n                // Make sure no children are selected - we don't want invisible selected nodes. Note\n                // that this does not cause any UI changes by itself, since we are hiding the nodes.\n\n                changed = FALSE;\n\n                for (i = Node->Index + 1; i < Context->FlatList->Count; i++)\n                {\n                    node = Context->FlatList->Items[i];\n\n                    if (node->Level <= Node->Level)\n                        break; // no more children\n\n                    if (node->Selected)\n                    {\n                        node->Selected = FALSE;\n                        changed = TRUE;\n                    }\n                }\n\n                if (changed)\n                {\n                    Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext);\n                }\n            }\n\n            Node->Expanded = Expanded;\n            PhTnpRestructureNodes(Context);\n            // We need to update the window before the scrollbars get updated in order for the\n            // scroll processing to work properly.\n            InvalidateRect(Context->Handle, NULL, FALSE);\n            UpdateWindow(Context->Handle);\n            PhTnpLayout(Context);\n        }\n    }\n}\n\n/**\n * Calculates the positions and sizes of all parts of a cell.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Index The index of the row.\n * \\param Column Pointer to the column, or NULL for the fixed column.\n * \\param Flags Flags controlling which parts to calculate.\n * \\param Parts Pointer to receive the cell parts information.\n * \\return TRUE if successful, FALSE otherwise.\n */\nBOOLEAN PhTnpGetCellParts(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Index,\n    _In_opt_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG Flags,\n    _Out_ PPH_TREENEW_CELL_PARTS Parts\n    )\n{\n    PPH_TREENEW_NODE node;\n    LONG viewWidth;\n    LONG nodeY;\n    LONG iconVerticalMargin;\n    LONG currentX;\n\n    if (Index >= Context->FlatList->Count)\n        return FALSE;\n\n    node = Context->FlatList->Items[Index];\n    nodeY = Context->HeaderHeight + ((LONG)Index - Context->VScrollPosition) * Context->RowHeight;\n\n    Parts->Flags = 0;\n    Parts->RowRect.left = 0;\n    Parts->RowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n    Parts->RowRect.top = nodeY;\n    Parts->RowRect.bottom = nodeY + Context->RowHeight;\n\n    viewWidth = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n\n    if (Parts->RowRect.right > viewWidth)\n        Parts->RowRect.right = viewWidth;\n\n    if (!Column)\n        return TRUE;\n    if (!Column->Visible)\n        return FALSE;\n\n    iconVerticalMargin = (Context->RowHeight - Context->SmallIconHeight) / 2;\n\n    if (Column->Fixed)\n    {\n        currentX = 0;\n    }\n    else\n    {\n        currentX = Context->NormalLeft + Column->s.ViewX - Context->HScrollPosition;\n    }\n\n    Parts->Flags |= TN_PART_CELL;\n    Parts->CellRect.left = currentX;\n    Parts->CellRect.right = currentX + Column->Width;\n    Parts->CellRect.top = Parts->RowRect.top;\n    Parts->CellRect.bottom = Parts->RowRect.bottom;\n\n    currentX += Context->CellMarginLeft;\n\n    if (Column == Context->FirstColumn)\n    {\n        currentX += (LONG)node->Level * Context->SmallIconWidth;\n\n        if (Context->CanAnyExpand)\n        {\n            if (!node->s.IsLeaf)\n            {\n                Parts->Flags |= TN_PART_PLUSMINUS;\n                Parts->PlusMinusRect.left = currentX;\n                Parts->PlusMinusRect.right = currentX + Context->SmallIconWidth;\n                Parts->PlusMinusRect.top = Parts->RowRect.top + iconVerticalMargin;\n                Parts->PlusMinusRect.bottom = Parts->RowRect.bottom - iconVerticalMargin;\n            }\n\n            currentX += Context->SmallIconWidth;\n        }\n\n        if (node->Icon)\n        {\n            Parts->Flags |= TN_PART_ICON;\n            Parts->IconRect.left = currentX;\n            Parts->IconRect.right = currentX + Context->SmallIconWidth;\n            Parts->IconRect.top = Parts->RowRect.top + iconVerticalMargin;\n            Parts->IconRect.bottom = Parts->RowRect.bottom - iconVerticalMargin;\n\n            currentX += Context->SmallIconWidth + Context->IconRightPadding;\n        }\n    }\n\n    Parts->Flags |= TN_PART_CONTENT;\n    Parts->ContentRect.left = currentX;\n    Parts->ContentRect.right = Parts->CellRect.right - Context->CellMarginRight;\n    Parts->ContentRect.top = Parts->RowRect.top;\n    Parts->ContentRect.bottom = Parts->RowRect.bottom;\n\n    if (Flags & TN_MEASURE_TEXT)\n    {\n        HDC hdc;\n        PH_STRINGREF text;\n        HFONT font;\n        SIZE textSize;\n\n        if (hdc = GetDC(Context->Handle))\n        {\n            PhTnpPrepareRowForDraw(Context, hdc, node);\n\n            if (PhTnpGetCellText(Context, node, Column->Id, &text))\n            {\n                if (node->Font)\n                    font = node->Font;\n                else\n                    font = Context->Font;\n\n                SelectFont(hdc, font);\n\n                if (GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize))\n                {\n                    Parts->Flags |= TN_PART_TEXT;\n                    Parts->TextRect.left = currentX;\n                    Parts->TextRect.right = currentX + textSize.cx;\n                    Parts->TextRect.top = Parts->RowRect.top + (Context->RowHeight - textSize.cy) / 2;\n                    Parts->TextRect.bottom = Parts->RowRect.bottom - (Context->RowHeight - textSize.cy) / 2;\n\n                    if (Column->TextFlags & DT_CENTER)\n                    {\n                        Parts->TextRect.left = Parts->ContentRect.left / 2 + (Parts->ContentRect.right - textSize.cx) / 2;\n                        Parts->TextRect.right = Parts->ContentRect.left + textSize.cx;\n                    }\n                    else if (Column->TextFlags & DT_RIGHT)\n                    {\n                        Parts->TextRect.right = Parts->ContentRect.right;\n                        Parts->TextRect.left = Parts->TextRect.right - textSize.cx;\n                    }\n\n                    Parts->Text = text;\n                    Parts->Font = font;\n                }\n            }\n\n            ReleaseDC(Context->Handle, hdc);\n        }\n    }\n\n    return TRUE;\n}\n\n_Success_(return)\nBOOLEAN PhTnpGetRowRects(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Start,\n    _In_ ULONG End,\n    _In_ BOOLEAN Clip,\n    _Out_ PRECT Rect\n    )\n{\n    LONG startY;\n    LONG endY;\n    LONG viewWidth;\n\n    if (End >= Context->FlatList->Count)\n        return FALSE;\n    if (Start > End)\n        return FALSE;\n\n    startY = Context->HeaderHeight + ((LONG)Start - Context->VScrollPosition) * Context->RowHeight;\n    endY = Context->HeaderHeight + ((LONG)End - Context->VScrollPosition) * Context->RowHeight;\n\n    Rect->left = 0;\n    Rect->right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n    Rect->top = startY;\n    Rect->bottom = endY + Context->RowHeight;\n\n    viewWidth = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n\n    if (Rect->right > viewWidth)\n        Rect->right = viewWidth;\n\n    if (Clip)\n    {\n        if (Rect->top < Context->HeaderHeight)\n            Rect->top = Context->HeaderHeight;\n        if (Rect->bottom > Context->ClientRect.bottom)\n            Rect->bottom = Context->ClientRect.bottom;\n    }\n\n    return TRUE;\n}\n\n/**\n * Performs hit testing to determine what element is at a given point.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param HitTest Pointer to the hit test structure (Point input, other fields output).\n */\nVOID PhTnpHitTest(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_HIT_TEST HitTest\n    )\n{\n    RECT clientRect;\n    LONG x;\n    LONG y;\n    ULONG index;\n    PPH_TREENEW_NODE node;\n\n    HitTest->Flags = 0;\n    HitTest->Node = NULL;\n    HitTest->Column = NULL;\n\n    clientRect = Context->ClientRect;\n    x = HitTest->Point.x;\n    y = HitTest->Point.y;\n\n    if (x < 0)\n        HitTest->Flags |= TN_HIT_LEFT;\n    if (x >= clientRect.right)\n        HitTest->Flags |= TN_HIT_RIGHT;\n    if (y < 0)\n        HitTest->Flags |= TN_HIT_ABOVE;\n    if (y >= clientRect.bottom)\n        HitTest->Flags |= TN_HIT_BELOW;\n\n    if (HitTest->Flags == 0)\n    {\n        if (TNP_HIT_TEST_FIXED_DIVIDER(x, Context))\n        {\n            HitTest->Flags |= TN_HIT_DIVIDER;\n        }\n\n        if (y >= Context->HeaderHeight && x < Context->FixedWidth + Context->TotalViewX)\n        {\n            index = (y - Context->HeaderHeight) / Context->RowHeight + Context->VScrollPosition;\n\n            if (index < Context->FlatList->Count)\n            {\n                HitTest->Flags |= TN_HIT_ITEM;\n                node = Context->FlatList->Items[index];\n                HitTest->Node = node;\n\n                if (HitTest->InFlags & TN_TEST_COLUMN)\n                {\n                    PPH_TREENEW_COLUMN column;\n                    LONG columnX;\n\n                    column = NULL;\n\n                    if (x < Context->FixedWidth && Context->FixedColumnVisible)\n                    {\n                        column = Context->FixedColumn;\n                        columnX = 0;\n                    }\n                    else\n                    {\n                        LONG currentX;\n                        ULONG i;\n                        PPH_TREENEW_COLUMN currentColumn;\n\n                        currentX = Context->NormalLeft - Context->HScrollPosition;\n\n                        for (i = 0; i < Context->NumberOfColumnsByDisplay; i++)\n                        {\n                            currentColumn = Context->ColumnsByDisplay[i];\n\n                            if (x >= currentX && x < currentX + currentColumn->Width)\n                            {\n                                column = currentColumn;\n                                columnX = currentX;\n                                break;\n                            }\n\n                            currentX += currentColumn->Width;\n                        }\n                    }\n\n                    HitTest->Column = column;\n\n                    if (column && (HitTest->InFlags & TN_TEST_SUBITEM))\n                    {\n                        BOOLEAN isFirstColumn;\n                        LONG currentX;\n                        LONG width;\n\n                        isFirstColumn = HitTest->Column == Context->FirstColumn;\n\n                        currentX = columnX;\n                        currentX += Context->CellMarginLeft;\n\n                        if (isFirstColumn)\n                        {\n                            width = Context->SmallIconWidth;\n\n                            currentX += (LONG)node->Level * width;\n\n                            if (!node->s.IsLeaf)\n                            {\n                                if (x >= currentX && x < currentX + width)\n                                    HitTest->Flags |= TN_HIT_ITEM_PLUSMINUS;\n\n                                currentX += width;\n                            }\n\n                            if (node->Icon)\n                            {\n                                if (x >= currentX && x < currentX + width)\n                                    HitTest->Flags |= TN_HIT_ITEM_ICON;\n\n                                currentX += width + Context->IconRightPadding;\n                            }\n                        }\n\n                        if (x >= currentX)\n                        {\n                            HitTest->Flags |= TN_HIT_ITEM_CONTENT;\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\n/**\n * Selects a range of nodes.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Start The starting node index.\n * \\param End The ending node index.\n * \\param Flags Flags controlling the selection behavior.\n * \\param ChangedStart Pointer to receive the start of the changed range, or NULL.\n * \\param ChangedEnd Pointer to receive the end of the changed range, or NULL.\n */\nVOID PhTnpSelectRange(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Start,\n    _In_ ULONG End,\n    _In_ ULONG Flags,\n    _Out_opt_ PULONG ChangedStart,\n    _Out_opt_ PULONG ChangedEnd\n    )\n{\n    ULONG maximum;\n    ULONG i;\n    PPH_TREENEW_NODE node;\n    BOOLEAN targetValue;\n    ULONG changedStart;\n    ULONG changedEnd;\n\n    if (Context->FlatList->Count == 0)\n        return;\n\n    maximum = Context->FlatList->Count - 1;\n\n    if (End > maximum)\n    {\n        End = maximum;\n    }\n\n    if (Start > End)\n    {\n        // Start is too big, so the selection range becomes empty.\n        // Set it to max + 1 so that Reset still works.\n        Start = maximum + 1;\n        End = 0;\n    }\n\n    targetValue = !(Flags & TN_SELECT_DESELECT);\n    changedStart = maximum;\n    changedEnd = 0;\n\n    if (Flags & TN_SELECT_RESET)\n    {\n        for (i = 0; i < Start; i++)\n        {\n            node = Context->FlatList->Items[i];\n\n            if (node->Selected)\n            {\n                node->Selected = FALSE;\n\n                if (changedStart > i)\n                    changedStart = i;\n                if (changedEnd < i)\n                    changedEnd = i;\n            }\n        }\n    }\n\n    for (i = Start; i <= End; i++)\n    {\n        node = Context->FlatList->Items[i];\n\n        if (!node->Unselectable && ((Flags & TN_SELECT_TOGGLE) || node->Selected != targetValue))\n        {\n            node->Selected = !node->Selected;\n\n            if (changedStart > i)\n                changedStart = i;\n            if (changedEnd < i)\n                changedEnd = i;\n        }\n    }\n\n    if (Flags & TN_SELECT_RESET)\n    {\n        for (i = End + 1; i <= maximum; i++)\n        {\n            node = Context->FlatList->Items[i];\n\n            if (node->Selected)\n            {\n                node->Selected = FALSE;\n\n                if (changedStart > i)\n                    changedStart = i;\n                if (changedEnd < i)\n                    changedEnd = i;\n            }\n        }\n    }\n\n    if (changedStart <= changedEnd)\n    {\n        Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext);\n    }\n\n    if (ChangedStart)\n        *ChangedStart = changedStart;\n    if (ChangedEnd)\n        *ChangedEnd = changedEnd;\n}\n\n/**\n * Sets the hot node (the node under the mouse cursor).\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param NewHotNode Pointer to the new hot node, or NULL to clear.\n * \\param NewPlusMinusHot TRUE if the plus/minus glyph is hot, FALSE otherwise.\n */\nVOID PhTnpSetHotNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_NODE NewHotNode,\n    _In_ BOOLEAN NewPlusMinusHot\n    )\n{\n    ULONG newHotNodeIndex;\n    RECT rowRect;\n    BOOLEAN needsInvalidate;\n\n    if (NewHotNode)\n        newHotNodeIndex = NewHotNode->Index;\n    else\n        newHotNodeIndex = ULONG_MAX;\n\n    needsInvalidate = FALSE;\n\n    if (Context->HotNodeIndex != newHotNodeIndex)\n    {\n        if (Context->HotNodeIndex != ULONG_MAX)\n        {\n            if (Context->ThemeData && PhTnpGetRowRects(Context, Context->HotNodeIndex, Context->HotNodeIndex, TRUE, &rowRect))\n            {\n                // Update the old hot node because it may have a different non-hot background and\n                // plus minus part.\n                InvalidateRect(Context->Handle, &rowRect, FALSE);\n            }\n        }\n\n        Context->HotNodeIndex = newHotNodeIndex;\n\n        if (NewHotNode)\n        {\n            needsInvalidate = TRUE;\n        }\n    }\n\n    if (NewHotNode)\n    {\n        if (NewHotNode->s.PlusMinusHot != NewPlusMinusHot)\n        {\n            NewHotNode->s.PlusMinusHot = NewPlusMinusHot;\n            needsInvalidate = TRUE;\n        }\n\n        if (needsInvalidate && Context->ThemeData && PhTnpGetRowRects(Context, newHotNodeIndex, newHotNodeIndex, TRUE, &rowRect))\n        {\n            InvalidateRect(Context->Handle, &rowRect, FALSE);\n        }\n    }\n}\n\n/**\n * Processes node selection in response to mouse or keyboard input.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Node Pointer to the node to select.\n * \\param ControlKey TRUE if the Control key is pressed, FALSE otherwise.\n * \\param ShiftKey TRUE if the Shift key is pressed, FALSE otherwise.\n * \\param RightButton TRUE if the right mouse button was used, FALSE otherwise.\n */\nVOID PhTnpProcessSelectNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ LOGICAL ControlKey,\n    _In_ LOGICAL ShiftKey,\n    _In_ LOGICAL RightButton\n    )\n{\n    ULONG changedStart;\n    ULONG changedEnd;\n    RECT rect;\n\n    if (RightButton)\n    {\n        // Right button:\n        // If the current node is selected, then do nothing. This is to allow context menus to\n        // operate on multiple items.\n        // If the current node is not selected, select only that node.\n\n        if (!ControlKey && !ShiftKey && !Node->Selected)\n        {\n            PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_RESET, &changedStart, &changedEnd);\n            Context->MarkNodeIndex = Node->Index;\n\n            if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n            {\n                InvalidateRect(Context->Handle, &rect, FALSE);\n            }\n        }\n    }\n    else if (ShiftKey && Context->MarkNodeIndex != ULONG_MAX)\n    {\n        ULONG start;\n        ULONG end;\n\n        // Shift key: select a range from the selection mark node to the current node.\n\n        if (Node->Index > Context->MarkNodeIndex)\n        {\n            start = Context->MarkNodeIndex;\n            end = Node->Index;\n        }\n        else\n        {\n            start = Node->Index;\n            end = Context->MarkNodeIndex;\n        }\n\n        PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n    else if (ControlKey)\n    {\n        // Control key: toggle the selection on the current node, and also make it the selection\n        // mark.\n\n        PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_TOGGLE, NULL, NULL);\n        Context->MarkNodeIndex = Node->Index;\n\n        if (PhTnpGetRowRects(Context, Node->Index, Node->Index, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n    else\n    {\n        // Normal: select the current node, and also make it the selection mark.\n\n        PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_RESET, &changedStart, &changedEnd);\n        Context->MarkNodeIndex = Node->Index;\n\n        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n}\n\n/**\n * Ensures that the specified node is visible within the tree new control.\n *\n * This function scrolls the view if necessary to bring the node at the given index\n * into the visible area of the control. If the node is already fully visible, no action is taken.\n *\n * \\param Context Pointer to the tree new context structure.\n * \\param Index The index of the node to make visible.\n * \\return TRUE if the node is (or was made) visible; FALSE if the index is out of range.\n */\nBOOLEAN PhTnpEnsureVisibleNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Index\n    )\n{\n    LONG viewTop;\n    LONG viewBottom;\n    LONG rowTop;\n    LONG rowBottom;\n    LONG deltaY;\n    LONG deltaRows;\n\n    if (Index >= Context->FlatList->Count)\n        return FALSE;\n\n    viewTop = Context->HeaderHeight;\n    viewBottom = Context->ClientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0);\n    rowTop = Context->HeaderHeight + ((LONG)Index - Context->VScrollPosition) * Context->RowHeight;\n    rowBottom = rowTop + Context->RowHeight;\n\n    // Check if the row is fully visible.\n    if (rowTop >= viewTop && rowBottom <= viewBottom)\n        return TRUE;\n\n    deltaY = rowTop - viewTop;\n\n    if (deltaY > 0)\n    {\n        // The row is below the view area. We want to scroll the row into view at the bottom of the\n        // screen. We need to round up when dividing to make sure the node becomes fully visible.\n        deltaY = rowBottom - viewBottom;\n        deltaRows = (deltaY + Context->RowHeight - 1) / Context->RowHeight; // divide, round up\n    }\n    else\n    {\n        deltaRows = deltaY / Context->RowHeight;\n    }\n\n    PhTnpScroll(Context, deltaRows, 0);\n\n    return TRUE;\n}\n\n/**\n * Processes mouse movement within the tree new control.\n *\n * This function handles mouse movement events by performing hit testing to determine\n * the node and column under the cursor, updating the hot node state, managing divider\n * animation, and handling tooltip display logic.\n *\n * \\param Context Pointer to the tree new context structure.\n * \\param CursorX The X coordinate of the mouse cursor.\n * \\param CursorY The Y coordinate of the mouse cursor.\n */\nVOID PhTnpProcessMoveMouse(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    PH_TREENEW_HIT_TEST hitTest;\n    PPH_TREENEW_NODE hotNode;\n\n    hitTest.Point.x = CursorX;\n    hitTest.Point.y = CursorY;\n    hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM;\n    PhTnpHitTest(Context, &hitTest);\n\n    if (hitTest.Flags & TN_HIT_ITEM)\n        hotNode = hitTest.Node;\n    else\n        hotNode = NULL;\n\n    PhTnpSetHotNode(Context, hotNode, !!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS));\n\n    if (Context->AnimateDivider && Context->FixedDividerVisible)\n    {\n        if (hitTest.Flags & TN_HIT_DIVIDER)\n        {\n            if ((Context->DividerHot < 100 || Context->AnimateDividerFadingOut) && !Context->AnimateDividerFadingIn)\n            {\n                // Begin fading in the divider.\n                Context->AnimateDividerFadingIn = TRUE;\n                Context->AnimateDividerFadingOut = FALSE;\n                PhSetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL);\n            }\n        }\n        else\n        {\n            if ((Context->DividerHot != 0 || Context->AnimateDividerFadingIn) && !Context->AnimateDividerFadingOut)\n            {\n                Context->AnimateDividerFadingOut = TRUE;\n                Context->AnimateDividerFadingIn = FALSE;\n                PhSetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL);\n            }\n        }\n    }\n\n    if (Context->TooltipsHandle)\n    {\n        ULONG index;\n        ULONG id;\n\n        if (!(hitTest.Flags & TN_HIT_DIVIDER))\n        {\n            index = hitTest.Node ? hitTest.Node->Index : ULONG_MAX;\n            id = hitTest.Column ? hitTest.Column->Id : ULONG_MAX;\n        }\n        else\n        {\n            index = ULONG_MAX;\n            id = ULONG_MAX;\n        }\n\n        // This pops unnecessarily - when the cell has no tooltip text, and the user is moving the\n        // mouse over it. However these unnecessary calls seem to fix a certain tooltip bug (move\n        // the mouse around very quickly over the last column and the blank space to the right, and\n        // no more tooltips will appear).\n        if (Context->TooltipIndex != index || Context->TooltipId != id)\n        {\n            PhTnpPopTooltip(Context);\n        }\n    }\n}\n\n/**\n * Processes vertical mouse wheel events for the tree new control.\n *\n * This function handles vertical scrolling when the user rotates the mouse wheel.\n * It calculates the number of lines to scroll based on system settings and updates the vertical\n * scroll position accordingly, including handling partial scrolls and direction changes.\n * It also manages tooltip updates after scrolling.\n *\n * \\param Context Pointer to the tree new context structure.\n * \\param Distance The wheel delta value indicating the amount and direction of scrolling.\n */\nVOID PhTnpProcessMouseVWheel(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance\n    )\n{\n    ULONG wheelScrollLines;\n    FLOAT linesToScroll;\n    LONG wholeLinesToScroll;\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n\n    if (!PhGetSystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScrollLines, 0))\n    {\n        wheelScrollLines = PhGetDpi(3, Context->WindowDpi);\n    }\n\n    // If page scrolling is enabled, use the number of visible rows.\n    if (wheelScrollLines == ULONG_MAX)\n        wheelScrollLines = (Context->ClientRect.bottom - Context->HeaderHeight - (Context->HScrollVisible ? Context->HScrollHeight : 0)) / Context->RowHeight;\n\n    // Zero the remainder if the direction changed.\n    if ((Context->VScrollRemainder > 0) != (Distance > 0))\n        Context->VScrollRemainder = 0;\n\n    linesToScroll = (FLOAT)wheelScrollLines * Distance / WHEEL_DELTA + Context->VScrollRemainder;\n    wholeLinesToScroll = (LONG)linesToScroll;\n    Context->VScrollRemainder = linesToScroll - wholeLinesToScroll;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_ALL;\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    scrollInfo.nPos += wholeLinesToScroll;\n\n    scrollInfo.fMask = SIF_POS;\n    SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE);\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n\n    if (scrollInfo.nPos != oldPosition)\n    {\n        Context->VScrollPosition = scrollInfo.nPos;\n        PhTnpProcessScroll(Context, scrollInfo.nPos - oldPosition, 0);\n\n        if (Context->TooltipsHandle)\n        {\n            MSG message;\n            POINT point;\n\n            PhTnpPopTooltip(Context);\n\n            if (\n                PhGetClientPos(Context->Handle, &point) && \n                point.x >= 0 && point.y >= 0 && \n                point.x < Context->ClientRect.right && \n                point.y < Context->ClientRect.bottom\n                )\n            {\n                // Send a fake mouse move message for the new node that the mouse may be hovering over.\n                message.hwnd = Context->Handle;\n                message.message = WM_MOUSEMOVE;\n                message.wParam = 0;\n                message.lParam = MAKELPARAM(point.x, point.y);\n                SendMessage(Context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n        }\n    }\n}\n\n/**\n * Processes horizontal mouse wheel events for the tree new control.\n *\n * This function handles horizontal scrolling when the user rotates the mouse wheel horizontally.\n * It calculates the number of characters to scroll based on system settings and updates the horizontal\n * scroll position accordingly, including handling partial scrolls and direction changes.\n *\n * \\param Context Pointer to the tree new context structure.\n * \\param Distance The wheel delta value indicating the amount and direction of scrolling.\n */\nVOID PhTnpProcessMouseHWheel(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance\n    )\n{\n    ULONG wheelScrollChars;\n    FLOAT pixelsToScroll;\n    LONG wholePixelsToScroll;\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n\n    if (!PhGetSystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &wheelScrollChars, 0))\n    {\n        wheelScrollChars = PhGetDpi(3, Context->WindowDpi);\n    }\n\n    // Zero the remainder if the direction changed.\n    if ((Context->HScrollRemainder > 0) != (Distance > 0))\n        Context->HScrollRemainder = 0;\n\n    pixelsToScroll = (FLOAT)wheelScrollChars * Context->TextMetrics.tmAveCharWidth * Distance / WHEEL_DELTA + Context->HScrollRemainder;\n    wholePixelsToScroll = (LONG)pixelsToScroll;\n    Context->HScrollRemainder = pixelsToScroll - wholePixelsToScroll;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_ALL;\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    scrollInfo.nPos += wholePixelsToScroll;\n\n    scrollInfo.fMask = SIF_POS;\n    SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE);\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n\n    if (scrollInfo.nPos != oldPosition)\n    {\n        Context->HScrollPosition = scrollInfo.nPos;\n        PhTnpProcessScroll(Context, 0, scrollInfo.nPos - oldPosition);\n    }\n}\n\n/**\n * Processes focus navigation keys for the tree new control.\n *\n * This function handles keyboard navigation for moving the focus between nodes in the tree new control,\n * such as Up, Down, Home, End, Page Up, and Page Down keys. It updates the focused node, selection mark,\n * and selection range as appropriate, and ensures the focused node is visible.\n *\n * \\param Context Pointer to the tree new context structure.\n * \\param VirtualKey The virtual key code to process (e.g., VK_UP, VK_DOWN, VK_HOME, VK_END, VK_PRIOR, VK_NEXT).\n * \\return TRUE if the key was handled; otherwise, FALSE.\n */\nBOOLEAN PhTnpProcessFocusKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey\n    )\n{\n    ULONG count;\n    ULONG index;\n    BOOLEAN controlKey;\n    BOOLEAN shiftKey;\n    ULONG start;\n    ULONG end;\n    ULONG changedStart;\n    ULONG changedEnd;\n    RECT rect;\n\n    if (VirtualKey != VK_UP && VirtualKey != VK_DOWN &&\n        VirtualKey != VK_HOME && VirtualKey != VK_END &&\n        VirtualKey != VK_PRIOR && VirtualKey != VK_NEXT)\n    {\n        return FALSE;\n    }\n\n    count = Context->FlatList->Count;\n\n    if (count == 0)\n        return TRUE;\n\n    // Find the new node to focus.\n\n    switch (VirtualKey)\n    {\n    case VK_UP:\n        {\n            if (Context->FocusNode && Context->FocusNode->Index > 0)\n            {\n                index = Context->FocusNode->Index - 1;\n            }\n            else\n            {\n                index = 0;\n            }\n        }\n        break;\n    case VK_DOWN:\n        {\n            if (Context->FocusNode)\n            {\n                index = Context->FocusNode->Index + 1;\n\n                if (index >= count)\n                    index = count - 1;\n            }\n            else\n            {\n                index = 0;\n            }\n        }\n        break;\n    case VK_HOME:\n        index = 0;\n        break;\n    case VK_END:\n        index = count - 1;\n        break;\n    case VK_PRIOR:\n    case VK_NEXT:\n        {\n            LONG rowsPerPage;\n\n            if (Context->FocusNode)\n                index = Context->FocusNode->Index;\n            else\n                index = 0;\n\n            rowsPerPage = Context->ClientRect.bottom - Context->HeaderHeight - (Context->HScrollVisible ? Context->HScrollHeight : 0);\n\n            if (rowsPerPage < 0)\n                return TRUE;\n\n            rowsPerPage = rowsPerPage / Context->RowHeight - 1;\n\n            if (rowsPerPage < 0)\n                return TRUE;\n\n            if (VirtualKey == VK_PRIOR)\n            {\n                ULONG startOfPageIndex;\n\n                startOfPageIndex = Context->VScrollPosition;\n\n                if (index > startOfPageIndex)\n                {\n                    index = startOfPageIndex;\n                }\n                else\n                {\n                    // Already at or before the start of the page. Go back a page.\n                    if (index >= (ULONG)rowsPerPage)\n                        index -= rowsPerPage;\n                    else\n                        index = 0;\n                }\n            }\n            else\n            {\n                ULONG endOfPageIndex;\n\n                endOfPageIndex = Context->VScrollPosition + rowsPerPage;\n\n                if (endOfPageIndex >= count)\n                    endOfPageIndex = count - 1;\n\n                if (index < endOfPageIndex)\n                {\n                    index = endOfPageIndex;\n                }\n                else\n                {\n                    // Already at or after the end of the page. Go forward a page.\n                    index += rowsPerPage;\n\n                    if (index >= count)\n                        index = count - 1;\n                }\n            }\n        }\n        break;\n    default:\n        {\n            index = 0;\n        }\n        break;\n    }\n\n    // Select the relevant nodes.\n\n    controlKey = GetKeyState(VK_CONTROL) < 0;\n    shiftKey = GetKeyState(VK_SHIFT) < 0;\n\n    Context->FocusNode = Context->FlatList->Items[index];\n    PhTnpSetHotNode(Context, Context->FocusNode, FALSE);\n\n    if (shiftKey && Context->MarkNodeIndex != ULONG_MAX)\n    {\n        if (index > Context->MarkNodeIndex)\n        {\n            start = Context->MarkNodeIndex;\n            end = index;\n        }\n        else\n        {\n            start = index;\n            end = Context->MarkNodeIndex;\n        }\n\n        PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n    else if (!controlKey)\n    {\n        Context->MarkNodeIndex = Context->FocusNode->Index;\n        PhTnpSelectRange(Context, index, index, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n\n    PhTnpEnsureVisibleNode(Context, index);\n    PhTnpPopTooltip(Context);\n\n    return TRUE;\n}\n\n/**\n * Processes a key event for the focused node in the tree new control.\n *\n * This function handles keyboard input such as space, left, right, and plus keys when a node is focused.\n * It manages node selection, expansion/collapse, and navigation based on the key pressed and modifier keys.\n *\n * \\param Context Pointer to the tree new context structure.\n * \\param VirtualKey The virtual key code of the key event to process.\n * \\return TRUE if the key was handled; otherwise, FALSE.\n */\nBOOLEAN PhTnpProcessNodeKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey\n    )\n{\n    BOOLEAN controlKey;\n    BOOLEAN shiftKey;\n    ULONG changedStart;\n    ULONG changedEnd;\n    RECT rect;\n\n    if (VirtualKey != VK_SPACE && VirtualKey != VK_LEFT && VirtualKey != VK_RIGHT && VirtualKey != VK_ADD && VirtualKey != VK_OEM_PLUS)\n    {\n        return FALSE;\n    }\n\n    if (!Context->FocusNode)\n        return TRUE;\n\n    controlKey = GetKeyState(VK_CONTROL) < 0;\n    shiftKey = GetKeyState(VK_SHIFT) < 0;\n\n    switch (VirtualKey)\n    {\n    case VK_SPACE:\n        {\n            if (controlKey)\n            {\n                // Control key: toggle the selection on the focused node.\n\n                Context->MarkNodeIndex = Context->FocusNode->Index;\n                PhTnpSelectRange(Context, Context->FocusNode->Index, Context->FocusNode->Index, TN_SELECT_TOGGLE, &changedStart, &changedEnd);\n\n                if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                {\n                    InvalidateRect(Context->Handle, &rect, FALSE);\n                }\n            }\n            else if (shiftKey)\n            {\n                ULONG start;\n                ULONG end;\n\n                // Shift key: select a range from the selection mark node to the focused node.\n\n                if (Context->FocusNode->Index > Context->MarkNodeIndex)\n                {\n                    start = Context->MarkNodeIndex;\n                    end = Context->FocusNode->Index;\n                }\n                else\n                {\n                    start = Context->FocusNode->Index;\n                    end = Context->MarkNodeIndex;\n                }\n\n                PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                {\n                    InvalidateRect(Context->Handle, &rect, FALSE);\n                }\n            }\n        }\n        break;\n    case VK_LEFT:\n        {\n            ULONG i;\n            ULONG targetLevel;\n            PPH_TREENEW_NODE newNode;\n\n            // If the node is expanded, collapse it. Otherwise, select the node's parent.\n            if (!Context->FocusNode->s.IsLeaf && Context->FocusNode->Expanded)\n            {\n                PhTnpSetExpandedNode(Context, Context->FocusNode, FALSE);\n            }\n            else if (Context->FocusNode->Level != 0)\n            {\n                i = Context->FocusNode->Index;\n                targetLevel = Context->FocusNode->Level - 1;\n\n                while (i != 0)\n                {\n                    i--;\n                    newNode = Context->FlatList->Items[i];\n\n                    if (newNode->Level == targetLevel)\n                    {\n                        Context->FocusNode = newNode;\n                        Context->MarkNodeIndex = newNode->Index;\n                        PhTnpEnsureVisibleNode(Context, i);\n                        PhTnpSetHotNode(Context, newNode, FALSE);\n                        PhTnpSelectRange(Context, i, i, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                        {\n                            InvalidateRect(Context->Handle, &rect, FALSE);\n                        }\n\n                        PhTnpPopTooltip(Context);\n\n                        break;\n                    }\n                }\n            }\n        }\n        break;\n    case VK_RIGHT:\n        {\n            PPH_TREENEW_NODE newNode;\n\n            if (!Context->FocusNode->s.IsLeaf)\n            {\n                // If the node is collapsed, expand it. Otherwise, select the node's first child.\n                if (!Context->FocusNode->Expanded)\n                {\n                    PhTnpSetExpandedNode(Context, Context->FocusNode, TRUE);\n                }\n                else\n                {\n                    if (Context->FocusNode->Index + 1 < Context->FlatList->Count)\n                    {\n                        newNode = Context->FlatList->Items[Context->FocusNode->Index + 1];\n\n                        if (newNode->Level == Context->FocusNode->Level + 1)\n                        {\n                            Context->FocusNode = newNode;\n                            Context->MarkNodeIndex = newNode->Index;\n                            PhTnpEnsureVisibleNode(Context, Context->FocusNode->Index + 1);\n                            PhTnpSetHotNode(Context, newNode, FALSE);\n                            PhTnpSelectRange(Context, Context->FocusNode->Index, Context->FocusNode->Index, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                            if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                            {\n                                InvalidateRect(Context->Handle, &rect, FALSE);\n                            }\n\n                            PhTnpPopTooltip(Context);\n                        }\n                    }\n                }\n            }\n        }\n        break;\n    case VK_ADD:\n    case VK_OEM_PLUS:\n        {\n            if ((VirtualKey == VK_ADD && controlKey) ||\n                (VirtualKey == VK_OEM_PLUS && controlKey && shiftKey))\n            {\n                ULONG i;\n\n                if (Context->FixedColumnVisible)\n                    PhTnpAutoSizeColumnHeader(Context, Context->FixedHeaderHandle, Context->FixedColumn, 0);\n\n                for (i = 0; i < Context->NumberOfColumnsByDisplay; i++)\n                    PhTnpAutoSizeColumnHeader(Context, Context->HeaderHandle, Context->ColumnsByDisplay[i], 0);\n            }\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\n/**\n * Processes a character input for incremental search in the tree view control.\n *\n * This function handles character input (typically from WM_CHAR) to perform incremental\n * search within the tree view. It manages the search buffer, handles timeouts, and\n * updates the focused node and selection based on the search result.\n *\n * \\param Context Pointer to the tree view context.\n * \\param Character The character code to process for search.\n */\nVOID PhTnpProcessSearchKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Character\n    )\n{\n    LONG messageTime;\n    BOOLEAN newSearch;\n    PH_TREENEW_SEARCH_EVENT searchEvent;\n    PPH_TREENEW_NODE foundNode;\n    ULONG changedStart;\n    ULONG changedEnd;\n    RECT rect;\n\n    if (Context->FlatList->Count == 0)\n        return;\n\n    messageTime = GetMessageTime();\n    newSearch = FALSE;\n\n    // Check if the search timed out.\n    if (messageTime - Context->SearchMessageTime > PH_TREENEW_SEARCH_TIMEOUT)\n    {\n        Context->SearchStringCount = 0;\n        Context->SearchFailed = FALSE;\n        newSearch = TRUE;\n        Context->SearchSingleCharMode = TRUE;\n    }\n\n    Context->SearchMessageTime = messageTime;\n\n    // Append the character to the search buffer.\n\n    if (!Context->SearchString)\n    {\n        Context->AllocatedSearchString = 32;\n        Context->SearchString = PhAllocateSafe(Context->AllocatedSearchString * sizeof(WCHAR));\n        newSearch = TRUE;\n        Context->SearchSingleCharMode = TRUE;\n    }\n\n    if (!Context->SearchString)\n    {\n        Context->SearchFailed = TRUE;\n        return;\n    }\n\n    if (Context->SearchStringCount > PH_TREENEW_SEARCH_MAXIMUM_LENGTH)\n    {\n        // The search string has become too long. Fail the search.\n        if (!Context->SearchFailed)\n        {\n            MessageBeep(MB_OK);\n\n            Context->SearchFailed = TRUE;\n            return;\n        }\n    }\n    else if (Context->SearchStringCount == Context->AllocatedSearchString)\n    {\n        Context->AllocatedSearchString *= 2;\n        Context->SearchString = PhReAllocateSafe(Context->SearchString, Context->AllocatedSearchString * sizeof(WCHAR));\n\n        if (!Context->SearchString)\n        {\n            Context->SearchFailed = TRUE;\n            return;\n        }\n    }\n\n    Context->SearchString[Context->SearchStringCount++] = (WCHAR)Character;\n\n    if (Context->SearchString[Context->SearchStringCount - 1] != Context->SearchString[0])\n    {\n        // The user has stopped typing the same character (or never started). Turn single-character\n        // search off.\n        Context->SearchSingleCharMode = FALSE;\n    }\n\n    searchEvent.FoundIndex = INT_ERROR;\n\n    if (Context->FocusNode)\n    {\n        searchEvent.StartIndex = Context->FocusNode->Index;\n\n        if (newSearch || Context->SearchSingleCharMode)\n        {\n            // If it's a new search, start at the next item so the user doesn't find the same item\n            // again.\n            searchEvent.StartIndex++;\n\n            if (searchEvent.StartIndex == Context->FlatList->Count)\n                searchEvent.StartIndex = 0;\n        }\n    }\n    else\n    {\n        searchEvent.StartIndex = 0;\n    }\n\n    searchEvent.String.Buffer = Context->SearchString;\n\n    if (!Context->SearchSingleCharMode)\n        searchEvent.String.Length = Context->SearchStringCount * sizeof(WCHAR);\n    else\n        searchEvent.String.Length = sizeof(WCHAR);\n\n    // Give the user a chance to modify how the search is performed.\n    if (!Context->Callback(Context->Handle, TreeNewIncrementalSearch, &searchEvent, NULL, Context->CallbackContext))\n    {\n        // Use the default search function.\n        if (!PhTnpDefaultIncrementalSearch(Context, &searchEvent, TRUE, TRUE))\n        {\n            return;\n        }\n    }\n\n    if (searchEvent.FoundIndex == INT_ERROR && !Context->SearchFailed)\n    {\n        // No search result. Beep to indicate an error, and set the flag so we don't beep again. But\n        // don't beep if the first character was a space, because that's used for other purposes\n        // elsewhere (see PhTnpProcessNodeKey).\n        if (searchEvent.String.Buffer[0] != L' ')\n        {\n            MessageBeep(MB_OK);\n        }\n\n        Context->SearchFailed = TRUE;\n        return;\n    }\n\n    if (searchEvent.FoundIndex < 0 || searchEvent.FoundIndex >= (LONG)Context->FlatList->Count)\n        return;\n\n    foundNode = Context->FlatList->Items[searchEvent.FoundIndex];\n    Context->FocusNode = foundNode;\n    PhTnpEnsureVisibleNode(Context, searchEvent.FoundIndex);\n    PhTnpSetHotNode(Context, foundNode, FALSE);\n    PhTnpSelectRange(Context, searchEvent.FoundIndex, searchEvent.FoundIndex, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n    if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n    {\n        InvalidateRect(Context->Handle, &rect, FALSE);\n    }\n\n    PhTnpPopTooltip(Context);\n}\n\n/**\n * Performs the default incremental search in the tree view.\n *\n * This function searches for a node whose text matches the search string, starting from a given index.\n * It supports partial and wrapped searches.\n *\n * \\param Context Pointer to the tree view context.\n * \\param SearchEvent Pointer to the search event structure, updated with the found index.\n * \\param Partial TRUE to allow partial matches; FALSE for exact matches.\n * \\param Wrap TRUE to wrap around the list; FALSE to stop at the end.\n * \\return TRUE if the search was performed; FALSE otherwise.\n */\nBOOLEAN PhTnpDefaultIncrementalSearch(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_SEARCH_EVENT SearchEvent,\n    _In_ BOOLEAN Partial,\n    _In_ BOOLEAN Wrap\n    )\n{\n    LONG startIndex;\n    LONG currentIndex;\n    LONG foundIndex;\n    BOOLEAN firstTime;\n\n    if (Context->FlatList->Count == 0)\n        return FALSE;\n    if (!Context->FirstColumn)\n        return FALSE;\n\n    startIndex = SearchEvent->StartIndex;\n    currentIndex = startIndex;\n    foundIndex = INT_ERROR;\n    firstTime = TRUE;\n\n    while (TRUE)\n    {\n        PH_STRINGREF text;\n\n        if (currentIndex >= (LONG)Context->FlatList->Count)\n        {\n            if (Wrap)\n                currentIndex = 0;\n            else\n                break;\n        }\n\n        // We use the firstTime variable instead of a simpler check because we want to include the\n        // current item in the search. E.g. the current item is the only item beginning with \"Z\". If\n        // the user searches for \"Z\", we want to return the current item as being found.\n        if (!firstTime && currentIndex == startIndex)\n            break;\n\n        if (PhTnpGetCellText(Context, Context->FlatList->Items[currentIndex], Context->FirstColumn->Id, &text))\n        {\n            if (Partial)\n            {\n                if (PhStartsWithStringRef(&text, &SearchEvent->String, TRUE))\n                {\n                    foundIndex = currentIndex;\n                    break;\n                }\n            }\n            else\n            {\n                if (PhEqualStringRef(&text, &SearchEvent->String, TRUE))\n                {\n                    foundIndex = currentIndex;\n                    break;\n                }\n            }\n        }\n\n        currentIndex++;\n        firstTime = FALSE;\n    }\n\n    SearchEvent->FoundIndex = foundIndex;\n\n    return TRUE;\n}\n\n/**\n * Updates the scroll bars for the tree view control.\n *\n * This function recalculates and updates the visibility, range, and position of the vertical and horizontal scroll bars\n * based on the current content and client area size. It also manages the filler box visibility and triggers scrolling if needed.\n *\n * \\param Context Pointer to the tree view context.\n */\nVOID PhTnpUpdateScrollBars(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT clientRect;\n    LONG width;\n    LONG height;\n    LONG contentWidth;\n    LONG contentHeight;\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n    LONG deltaRows;\n    LONG deltaX;\n    LOGICAL oldHScrollVisible;\n    RECT rect;\n\n    clientRect = Context->ClientRect;\n    width = clientRect.right - Context->FixedWidth;\n    height = clientRect.bottom - Context->HeaderHeight;\n\n    contentWidth = Context->TotalViewX;\n    contentHeight = (LONG)Context->FlatList->Count * Context->RowHeight;\n\n    if (contentHeight > height)\n    {\n        // We need a vertical scrollbar, so we can't use that area of the screen for content.\n        width -= Context->VScrollWidth;\n    }\n\n    if (contentWidth > width)\n    {\n        height -= Context->HScrollHeight;\n    }\n\n    // Vertical scroll bar\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_POS;\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    scrollInfo.fMask = SIF_RANGE | SIF_PAGE;\n    scrollInfo.nMin = 0;\n    scrollInfo.nMax = Context->FlatList->Count != 0 ? Context->FlatList->Count - 1 : 0;\n    scrollInfo.nPage = height / Context->RowHeight;\n    SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE);\n\n    // The scroll position may have changed due to the modified scroll range.\n    scrollInfo.fMask = SIF_POS;\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    deltaRows = scrollInfo.nPos - oldPosition;\n    Context->VScrollPosition = scrollInfo.nPos;\n\n    if (contentHeight > height && contentHeight != 0)\n    {\n        if (!Context->VScrollVisible)\n        {\n            ShowWindow(Context->VScrollHandle, SW_SHOW);\n            Context->VScrollVisible = TRUE;\n        }\n    }\n    else\n    {\n        if (Context->VScrollVisible)\n        {\n            ShowWindow(Context->VScrollHandle, SW_HIDE);\n            Context->VScrollVisible = FALSE;\n        }\n    }\n\n    // Horizontal scroll bar\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_POS;\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    scrollInfo.fMask = SIF_RANGE | SIF_PAGE;\n    scrollInfo.nMin = 0;\n    scrollInfo.nMax = contentWidth != 0 ? contentWidth - 1 : 0;\n    scrollInfo.nPage = width;\n    SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE);\n\n    scrollInfo.fMask = SIF_POS;\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n    deltaX = scrollInfo.nPos - oldPosition;\n    Context->HScrollPosition = scrollInfo.nPos;\n\n    oldHScrollVisible = Context->HScrollVisible;\n\n    if (contentWidth > width && contentWidth != 0)\n    {\n        if (!Context->HScrollVisible)\n        {\n            ShowWindow(Context->HScrollHandle, SW_SHOW);\n            Context->HScrollVisible = TRUE;\n        }\n    }\n    else\n    {\n        if (Context->HScrollVisible)\n        {\n            ShowWindow(Context->HScrollHandle, SW_HIDE);\n            Context->HScrollVisible = FALSE;\n        }\n    }\n\n    if ((Context->HScrollVisible != oldHScrollVisible) && Context->FixedDividerVisible && Context->AnimateDivider)\n    {\n        rect.left = Context->FixedWidth;\n        rect.top = Context->HeaderHeight;\n        rect.right = Context->FixedWidth + 1;\n        rect.bottom = Context->ClientRect.bottom;\n        InvalidateRect(Context->Handle, &rect, FALSE);\n    }\n\n    if (deltaRows != 0 || deltaX != 0)\n        PhTnpProcessScroll(Context, deltaRows, deltaX);\n\n    if (Context->VScrollVisible && Context->HScrollVisible)\n    {\n        if (!Context->FillerBoxVisible)\n        {\n            ShowWindow(Context->FillerBoxHandle, SW_SHOW);\n            Context->FillerBoxVisible = TRUE;\n        }\n    }\n    else\n    {\n        if (Context->FillerBoxVisible)\n        {\n            ShowWindow(Context->FillerBoxHandle, SW_HIDE);\n            Context->FillerBoxVisible = FALSE;\n        }\n    }\n}\n\n/**\n * Scrolls the tree view by the specified number of rows and columns.\n *\n * This function adjusts the scroll bar positions and triggers a redraw if the scroll position changes.\n *\n * \\param Context Pointer to the tree view context.\n * \\param DeltaRows Number of rows to scroll vertically (can be MINLONG or MAXLONG for extremes).\n * \\param DeltaX Number of pixels to scroll horizontally (can be MINLONG or MAXLONG for extremes).\n */\nVOID PhTnpScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG DeltaRows,\n    _In_ LONG DeltaX\n    )\n{\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n    LONG deltaRows;\n    LONG deltaX;\n\n    deltaRows = 0;\n    deltaX = 0;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_POS;\n\n    if (DeltaRows != 0 && Context->VScrollVisible)\n    {\n        GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n        oldPosition = scrollInfo.nPos;\n\n        if (DeltaRows == MINLONG)\n            scrollInfo.nPos = 0;\n        else if (DeltaRows == MAXLONG)\n            scrollInfo.nPos = Context->FlatList->Count - 1;\n        else\n            scrollInfo.nPos += DeltaRows;\n\n        SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE);\n        GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n        Context->VScrollPosition = scrollInfo.nPos;\n        deltaRows = scrollInfo.nPos - oldPosition;\n    }\n\n    if (DeltaX != 0 && Context->HScrollVisible)\n    {\n        GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n        oldPosition = scrollInfo.nPos;\n\n        if (DeltaX == MINLONG)\n            scrollInfo.nPos = 0;\n        else if (DeltaX == MAXLONG)\n            scrollInfo.nPos = Context->TotalViewX;\n        else\n            scrollInfo.nPos += DeltaX;\n\n        SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE);\n        GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n        Context->HScrollPosition = scrollInfo.nPos;\n        deltaX = scrollInfo.nPos - oldPosition;\n    }\n\n    if (deltaRows != 0 || deltaX != 0)\n        PhTnpProcessScroll(Context, deltaRows, deltaX);\n}\n\n/**\n * Processes the actual scrolling of the tree view window.\n *\n * This function performs the window scrolling operation for both vertical and horizontal directions,\n * updates the header layout, and records the scroll tick count.\n *\n * \\param Context Pointer to the tree view context.\n * \\param DeltaRows Number of rows to scroll vertically.\n * \\param DeltaX Number of pixels to scroll horizontally.\n */\nVOID PhTnpProcessScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG DeltaRows,\n    _In_ LONG DeltaX\n    )\n{\n    RECT rect;\n    LONG deltaY;\n\n    rect.top = Context->HeaderHeight;\n    rect.bottom = Context->ClientRect.bottom;\n\n    if (DeltaX == 0)\n    {\n        rect.left = 0;\n        rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n        ScrollWindowEx(\n            Context->Handle,\n            0,\n            -DeltaRows * Context->RowHeight,\n            &rect,\n            NULL,\n            NULL,\n            NULL,\n            SW_INVALIDATE\n            );\n    }\n    else\n    {\n        // Don't scroll if there are no rows. This is especially important if the user wants us to\n        // display empty text.\n        if (Context->FlatList->Count != 0)\n        {\n            deltaY = DeltaRows * Context->RowHeight;\n\n            // If we're scrolling vertically as well, we need to scroll the fixed part and the\n            // normal part separately.\n\n            if (DeltaRows != 0)\n            {\n                rect.left = 0;\n                rect.right = Context->NormalLeft;\n                ScrollWindowEx(\n                    Context->Handle,\n                    0,\n                    -deltaY,\n                    &rect,\n                    &rect,\n                    NULL,\n                    NULL,\n                    SW_INVALIDATE\n                    );\n            }\n\n            rect.left = Context->NormalLeft;\n            rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n            ScrollWindowEx(\n                Context->Handle,\n                -DeltaX,\n                -deltaY,\n                &rect,\n                &rect,\n                NULL,\n                NULL,\n                SW_INVALIDATE\n                );\n        }\n\n        PhTnpLayoutHeader(Context);\n    }\n\n    Context->ScrollTickCount = NtGetTickCount64();\n}\n\n/**\n * Determines if the tree view can scroll in the specified direction.\n *\n * This function checks the scroll bar positions and ranges to determine if scrolling is possible\n * in the given direction (horizontal/vertical, positive/negative).\n *\n * \\param Context Pointer to the tree view context.\n * \\param Horizontal TRUE to check horizontal scrolling; FALSE for vertical.\n * \\param Positive TRUE to check forward (right/down); FALSE for backward (left/up).\n * \\return TRUE if scrolling is possible; FALSE otherwise.\n */\nBOOLEAN PhTnpCanScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Horizontal,\n    _In_ BOOLEAN Positive\n    )\n{\n    SCROLLINFO scrollInfo;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;\n\n    if (!Horizontal)\n        GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    else\n        GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n\n    if (Positive)\n    {\n        if (scrollInfo.nPage != 0)\n            scrollInfo.nMax -= scrollInfo.nPage - 1;\n\n        return scrollInfo.nPos < scrollInfo.nMax;\n    }\n    else\n    {\n        return scrollInfo.nPos > scrollInfo.nMin;\n    }\n}\n\n/**\n * Paints the tree view control.\n *\n * This function handles the drawing of all visible rows, columns, and cells in the tree view,\n * including themed and non-themed backgrounds, selection, and custom colors. It also manages\n * the drawing of fixed and normal columns and handles the painting of empty space.\n *\n * \\param WindowHandle Handle to the tree view window.\n * \\param Context Pointer to the tree view context.\n * \\param hdc Handle to the device context for painting.\n * \\param PaintRect Pointer to the rectangle to be painted.\n */\nVOID PhTnpPaint(\n    _In_ HWND WindowHandle,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT PaintRect\n    )\n{\n    RECT viewRect;\n    LONG vScrollPosition;\n    LONG hScrollPosition;\n    LONG firstRowToUpdate;\n    LONG lastRowToUpdate;\n    LONG i;\n    LONG j;\n    PPH_TREENEW_NODE node;\n    PPH_TREENEW_COLUMN column;\n    RECT rowRect;\n    LONG x;\n    BOOLEAN fixedUpdate;\n    LONG normalUpdateLeftX;\n    LONG normalUpdateRightX;\n    LONG normalUpdateLeftIndex;\n    LONG normalUpdateRightIndex;\n    LONG normalTotalX;\n    RECT cellRect;\n    HRGN oldClipRegion;\n\n    PhTnpInitializeThemeData(Context);\n\n    viewRect = Context->ClientRect;\n\n    if (Context->VScrollVisible)\n        viewRect.right -= Context->VScrollWidth;\n\n    vScrollPosition = Context->VScrollPosition;\n    hScrollPosition = Context->HScrollPosition;\n\n    // Calculate the indices of the first and last rows that need painting. These indices are\n    // relative to the top of the view area.\n\n    firstRowToUpdate = (PaintRect->top - Context->HeaderHeight) / Context->RowHeight;\n    lastRowToUpdate = (PaintRect->bottom - 1 - Context->HeaderHeight) / Context->RowHeight; // minus one since bottom is exclusive\n\n    if (firstRowToUpdate < 0)\n        firstRowToUpdate = 0;\n\n    rowRect.left = 0;\n    rowRect.top = Context->HeaderHeight + firstRowToUpdate * Context->RowHeight;\n    rowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n    rowRect.bottom = rowRect.top + Context->RowHeight;\n\n    // Change the indices to absolute row indices.\n\n    firstRowToUpdate += vScrollPosition;\n    lastRowToUpdate += vScrollPosition;\n\n    if (lastRowToUpdate >= (LONG)Context->FlatList->Count)\n        lastRowToUpdate = Context->FlatList->Count - 1; // becomes -1 when there are no items, handled correctly by loop below\n\n    // Determine whether the fixed column needs painting, and which normal columns need painting.\n\n    fixedUpdate = FALSE;\n\n    if (Context->FixedColumnVisible && PaintRect->left < Context->FixedWidth)\n        fixedUpdate = TRUE;\n\n    x = Context->NormalLeft - hScrollPosition;\n    normalUpdateLeftX = viewRect.right;\n    normalUpdateLeftIndex = 0;\n    normalUpdateRightX = 0;\n    normalUpdateRightIndex = -1;\n\n    for (j = 0; j < (LONG)Context->NumberOfColumnsByDisplay; j++)\n    {\n        column = Context->ColumnsByDisplay[j];\n\n        if (x + column->Width >= Context->NormalLeft && x + column->Width > PaintRect->left && x < PaintRect->right)\n        {\n            if (normalUpdateLeftX > x)\n            {\n                normalUpdateLeftX = x;\n                normalUpdateLeftIndex = j;\n            }\n\n            if (normalUpdateRightX < x + column->Width)\n            {\n                normalUpdateRightX = x + column->Width;\n                normalUpdateRightIndex = j;\n            }\n        }\n\n        x += column->Width;\n    }\n\n    normalTotalX = x;\n\n    if (normalUpdateRightIndex >= (LONG)Context->NumberOfColumnsByDisplay)\n        normalUpdateRightIndex = Context->NumberOfColumnsByDisplay - 1;\n\n    // Paint the rows.\n\n    SelectFont(hdc, Context->Font);\n    SetBkMode(hdc, TRANSPARENT);\n\n    for (i = firstRowToUpdate; i <= lastRowToUpdate; i++)\n    {\n        node = Context->FlatList->Items[i];\n\n        // Prepare the row for drawing.\n\n        PhTnpPrepareRowForDraw(Context, hdc, node);\n\n        if (Context->ThemeSupport)\n        {\n            HDC tempDc;\n            HBITMAP bitmap;\n            HBITMAP oldBitmap;\n            RECT tempRect;\n            BLENDFUNCTION blendFunction;\n\n            SetTextColor(hdc, PhThemeWindowTextColor);\n            SetDCBrushColor(hdc, PhThemeWindowBackgroundColor);\n            FillRect(hdc, &rowRect, PhGetStockBrush(DC_BRUSH));\n\n            if (tempDc = CreateCompatibleDC(hdc))\n            {\n                if (bitmap = CreateCompatibleBitmap(hdc, 1, 1))\n                {\n                    // Fill in the selection rectangle.\n                    oldBitmap = SelectBitmap(tempDc, bitmap);\n                    tempRect.left = 0;\n                    tempRect.top = 0;\n                    tempRect.right = 1;\n                    tempRect.bottom = 1;\n\n                    SetTextColor(tempDc, node->s.DrawForeColor);\n\n                    if (node->s.DrawBackColor != 16777215)\n                    {\n                        SetDCBrushColor(tempDc, node->s.DrawBackColor);\n                        FillRect(tempDc, &tempRect, PhGetStockBrush(DC_BRUSH));\n                    }\n                    else\n                    {\n                        SetDCBrushColor(tempDc, PhThemeWindowBackgroundColor);\n                        FillRect(tempDc, &tempRect, PhGetStockBrush(DC_BRUSH));\n                    }\n\n                    blendFunction.BlendOp = AC_SRC_OVER;\n                    blendFunction.BlendFlags = 0;\n                    blendFunction.SourceConstantAlpha = 96;\n                    blendFunction.AlphaFormat = 0;\n\n                    GdiAlphaBlend(\n                        hdc,\n                        rowRect.left,\n                        rowRect.top,\n                        rowRect.right - rowRect.left,\n                        rowRect.bottom - rowRect.top,\n                        tempDc,\n                        0,\n                        0,\n                        1,\n                        1,\n                        blendFunction\n                        );\n\n                    // Draw the outline of the selection rectangle (Dart Vanya)\n                    if (Context->HasFocus && node->Selected)\n                    {\n                        //SetDCBrushColor(hdc, RGB(0xF0, 0xF0, 0xF0));\n                        FrameRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW));\n                    }\n\n                    SelectBitmap(tempDc, oldBitmap);\n                    DeleteBitmap(bitmap);\n                }\n\n                DeleteDC(tempDc);\n            }\n        }\n        else\n        {\n            if (node->Selected && (Context->CustomColors || !Context->ThemeHasItemBackground))\n            {\n                // Non-themed background\n\n                if (Context->HasFocus)\n                {\n                    if (Context->CustomColors)\n                    {\n                        SetTextColor(hdc, Context->CustomTextColor);\n                        SetDCBrushColor(hdc, Context->CustomFocusColor);\n                        FillRect(hdc, &rowRect, PhGetStockBrush(DC_BRUSH));\n                    }\n                    else\n                    {\n                        SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                        FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_HIGHLIGHT));\n                    }\n                }\n                else\n                {\n                    if (Context->CustomColors)\n                    {\n                        SetTextColor(hdc, Context->CustomTextColor);\n                        SetDCBrushColor(hdc, Context->CustomSelectedColor);\n                        FillRect(hdc, &rowRect, PhGetStockBrush(DC_BRUSH));\n                    }\n                    else\n                    {\n                        SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));\n                        FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_BTNFACE));\n                    }\n                }\n            }\n            else\n            {\n                SetTextColor(hdc, node->s.DrawForeColor);\n                SetDCBrushColor(hdc, node->s.DrawBackColor);\n                FillRect(hdc, &rowRect, PhGetStockBrush(DC_BRUSH));\n            }\n        }\n\n        if (!Context->CustomColors && Context->ThemeHasItemBackground)\n        {\n            INT stateId;\n\n            // Themed background\n\n            if (node->Selected)\n            {\n                if (i == Context->HotNodeIndex)\n                    stateId = TREIS_HOTSELECTED;\n                else if (!Context->HasFocus)\n                    stateId = TREIS_SELECTEDNOTFOCUS;\n                else\n                    stateId = TREIS_SELECTED;\n            }\n            else\n            {\n                if (i == Context->HotNodeIndex)\n                    stateId = TREIS_HOT;\n                else\n                    stateId = INT_MAX;\n            }\n\n            // Themed background\n\n            if (stateId != INT_MAX)\n            {\n                if (!Context->FixedColumnVisible)\n                {\n                    rowRect.left = Context->NormalLeft - hScrollPosition;\n                }\n\n                PhDrawThemeBackground(\n                    Context->ThemeData,\n                    hdc,\n                    TVP_TREEITEM,\n                    stateId,\n                    &rowRect,\n                    PaintRect\n                    );\n            }\n        }\n\n        // Paint the fixed column.\n\n        cellRect.top = rowRect.top;\n        cellRect.bottom = rowRect.bottom;\n\n        if (fixedUpdate)\n        {\n            cellRect.left = 0;\n            cellRect.right = Context->FixedWidth;\n            PhTnpDrawCell(Context, hdc, &cellRect, node, Context->FixedColumn, i, -1);\n        }\n\n        // Paint the normal columns.\n\n        if (normalUpdateLeftX < normalUpdateRightX)\n        {\n            cellRect.left = normalUpdateLeftX;\n            cellRect.right = cellRect.left;\n\n            oldClipRegion = CreateRectRgn(0, 0, 0, 0);\n\n            if (GetClipRgn(hdc, oldClipRegion) != 1)\n            {\n                DeleteRgn(oldClipRegion);\n                oldClipRegion = NULL;\n            }\n\n            IntersectClipRect(hdc, Context->NormalLeft, cellRect.top, viewRect.right, cellRect.bottom);\n\n            for (j = normalUpdateLeftIndex; j <= normalUpdateRightIndex; j++)\n            {\n                column = Context->ColumnsByDisplay[j];\n\n                cellRect.left = cellRect.right;\n                cellRect.right = cellRect.left + column->Width;\n                PhTnpDrawCell(Context, hdc, &cellRect, node, column, i, j);\n            }\n\n            SelectClipRgn(hdc, oldClipRegion);\n\n            if (oldClipRegion)\n            {\n                DeleteRgn(oldClipRegion);\n            }\n        }\n\n        rowRect.top += Context->RowHeight;\n        rowRect.bottom += Context->RowHeight;\n    }\n\n    if (lastRowToUpdate == Context->FlatList->Count - 1) // works even if there are no items\n    {\n        // Fill the rest of the space on the bottom with the window color.\n        rowRect.bottom = viewRect.bottom;\n\n        if (Context->ThemeSupport)\n        {\n            SetTextColor(hdc, PhThemeWindowTextColor);\n            SetDCBrushColor(hdc, PhThemeWindowBackgroundColor);\n            FillRect(hdc, &rowRect, PhGetStockBrush(DC_BRUSH));\n        }\n        else\n        {\n            FillRect(hdc, &rowRect, (HBRUSH)(COLOR_WINDOW + 1));\n        }\n    }\n\n    if (normalTotalX < viewRect.right && viewRect.right > PaintRect->left && normalTotalX < PaintRect->right)\n    {\n        // Fill the rest of the space on the right with the window color.\n        rowRect.left = normalTotalX;\n        rowRect.top = Context->HeaderHeight;\n        rowRect.right = viewRect.right;\n        rowRect.bottom = viewRect.bottom;\n\n        if (Context->ThemeSupport)\n        {\n            SetTextColor(hdc, PhThemeWindowTextColor);\n            SetDCBrushColor(hdc, PhThemeWindowBackgroundColor);\n            FillRect(hdc, &rowRect, PhGetStockBrush(DC_BRUSH));\n        }\n        else\n        {\n            FillRect(hdc, &rowRect, (HBRUSH)(COLOR_WINDOW + 1));\n        }\n    }\n\n    if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0)\n    {\n        RECT textRect;\n\n        textRect.left = 20;\n        textRect.top = Context->HeaderHeight + PhGetDpi(10, Context->WindowDpi);\n        textRect.right = viewRect.right - PhGetDpi(20, Context->WindowDpi);\n        textRect.bottom = viewRect.bottom - Context->HeaderTextPadding;\n\n        if (Context->ThemeSupport)\n            SetTextColor(hdc, PhThemeWindowTextColor);\n        else\n            SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));\n\n        DrawText(\n            hdc,\n            Context->EmptyText.Buffer,\n            (ULONG)Context->EmptyText.Length / 2,\n            &textRect,\n            DT_NOPREFIX | DT_CENTER | DT_END_ELLIPSIS\n            );\n    }\n\n    if (Context->FixedDividerVisible && Context->FixedWidth >= PaintRect->left && Context->FixedWidth < PaintRect->right)\n    {\n        PhTnpDrawDivider(Context, hdc);\n    }\n\n    if (Context->DragSelectionActive)\n    {\n        PhTnpDrawSelectionRectangle(Context, hdc, &Context->DragRect);\n    }\n\n    if (FlagOn(Context->Style, TN_STYLE_DRAG_REORDER_ROWS))\n    {\n        if (Context->ReorderDragActive)\n        {\n            PhTnpDrawInsertionCaret(Context, hdc);\n        }\n    }\n\n    if (Context->HeaderCustomDraw)\n    {\n        //if (Context->FixedColumnVisible && Context->FixedHeaderHandle)\n        //{\n        //    InvalidateRect(Context->FixedHeaderHandle, NULL, FALSE);\n        //}\n\n        // TODO:\n        // 1) PhTickProcessNodes excludes the header when invalidating the treelist.\n        // 2) This invalidates the whole header even when nothing changes.\n        // We can add a callback similar to TreeNewGetHeaderText that returns TRUE\n        // for headers that have custom text and need invalidating? (dmex)\n\n        if (Context->HeaderHandle && !Context->Tracking) // GetCapture() != Context->HeaderHandle)\n        {\n            InvalidateRect(Context->HeaderHandle, NULL, FALSE);\n        }\n    }\n}\n\n/**\n * Prepares a tree new node for drawing.\n *\n * This function prepares the specified tree new node for drawing by performing\n * necessary calculations or setups using the provided device context and context.\n *\n * \\param Context A pointer to the tree new context.\n * \\param hdc The handle to the device context used for drawing.\n * \\param Node A pointer to the tree new node to prepare for drawing.\n */\nVOID PhTnpPrepareRowForDraw(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _Inout_ PPH_TREENEW_NODE Node\n    )\n{\n    if (!Node->s.CachedColorValid)\n    {\n        PH_TREENEW_GET_NODE_COLOR getNodeColor;\n\n        getNodeColor.Flags = 0;\n        getNodeColor.Node = Node;\n        getNodeColor.BackColor = Context->DefaultBackColor;\n        getNodeColor.ForeColor = Context->DefaultForeColor;\n\n        if (Context->Callback(\n            Context->Handle,\n            TreeNewGetNodeColor,\n            &getNodeColor,\n            NULL,\n            Context->CallbackContext\n            ))\n        {\n            Node->BackColor = getNodeColor.BackColor;\n            Node->ForeColor = getNodeColor.ForeColor;\n            Node->UseAutoForeColor = !!(getNodeColor.Flags & TN_AUTO_FORECOLOR);\n\n            if (getNodeColor.Flags & TN_CACHE)\n                Node->s.CachedColorValid = TRUE;\n        }\n        else\n        {\n            Node->BackColor = getNodeColor.BackColor;\n            Node->ForeColor = getNodeColor.ForeColor;\n        }\n    }\n\n    Node->s.DrawForeColor = Node->ForeColor;\n\n    if (Node->UseTempBackColor)\n        Node->s.DrawBackColor = Node->TempBackColor;\n    else\n        Node->s.DrawBackColor = Node->BackColor;\n\n    if (!Node->s.CachedFontValid)\n    {\n        PH_TREENEW_GET_NODE_FONT getNodeFont;\n\n        getNodeFont.Flags = 0;\n        getNodeFont.Node = Node;\n        getNodeFont.Font = NULL;\n\n        if (Context->Callback(\n            Context->Handle,\n            TreeNewGetNodeFont,\n            &getNodeFont,\n            NULL,\n            Context->CallbackContext\n            ))\n        {\n            Node->Font = getNodeFont.Font;\n\n            if (getNodeFont.Flags & TN_CACHE)\n                Node->s.CachedFontValid = TRUE;\n        }\n        else\n        {\n            Node->Font = NULL;\n        }\n    }\n\n    if (!Node->s.CachedIconValid)\n    {\n        PH_TREENEW_GET_NODE_ICON getNodeIcon;\n\n        getNodeIcon.Flags = 0;\n        getNodeIcon.Node = Node;\n        getNodeIcon.Icon = NULL;\n\n        if (Context->Callback(\n            Context->Handle,\n            TreeNewGetNodeIcon,\n            &getNodeIcon,\n            NULL,\n            Context->CallbackContext\n            ))\n        {\n            Node->Icon = getNodeIcon.Icon;\n\n            if (getNodeIcon.Flags & TN_CACHE)\n                Node->s.CachedIconValid = TRUE;\n        }\n        else\n        {\n            Node->Icon = NULL;\n        }\n    }\n\n    if (Node->UseAutoForeColor || Node->UseTempBackColor)\n    {\n        if (PhGetColorBrightness(Node->s.DrawBackColor) > 100) // slightly less than half\n            Node->s.DrawForeColor = RGB(0x00, 0x00, 0x00);\n        else\n            Node->s.DrawForeColor = RGB(0xff, 0xff, 0xff);\n    }\n}\n\n/**\n * Draws a cell in the tree new control.\n *\n * This function renders the content of a specific cell within the tree new control,\n * including text, icons, and other visual elements based on the provided node and column.\n *\n * \\param Context A pointer to the PPH_TREENEW_CONTEXT structure containing the tree new context.\n * \\param hdc A handle to the device context used for drawing operations.\n * \\param CellRect A pointer to a RECT structure defining the boundaries of the cell to draw.\n * \\param Node A pointer to the PPH_TREENEW_NODE structure representing the node associated with the cell.\n * \\param Column A pointer to the PPH_TREENEW_COLUMN structure representing the column.\n * \\param RowIndex The index of the row containing the cell.\n * \\param ColumnIndex The index of the column containing the cell.\n */\nVOID PhTnpDrawCell(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT CellRect,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ LONG RowIndex,\n    _In_ LONG ColumnIndex\n    )\n{\n    HFONT font; // font to use\n    HFONT oldFont = NULL;\n    PH_STRINGREF text; // text to draw\n    RECT textRect; // working rectangle, modified as needed\n    ULONG textFlags; // DT_* flags\n    LONG iconVerticalMargin; // top/bottom margin for icons (determined using height of small icon)\n    LONG width;\n    LONG height;\n\n    font = Node->Font;\n    textFlags = Column->TextFlags;\n\n    if (Column->Alignment & PH_ALIGN_MONOSPACE_FONT)\n    {\n        font = PhMonospaceFont;\n    }\n\n    textRect = *CellRect;\n\n    width = Context->SmallIconWidth;\n    height = Context->SmallIconHeight;\n\n    // Initial margins used by default list view\n    textRect.left += Context->CellMarginLeft;\n    textRect.right -= Context->CellMarginRight;\n\n    // icon margin = (height of row - height of small icon) / 2\n    iconVerticalMargin = ((textRect.bottom - textRect.top) - height) / 2;\n\n    textRect.top += iconVerticalMargin;\n    textRect.bottom -= iconVerticalMargin;\n\n    if (Column == Context->FirstColumn)\n    {\n        BOOLEAN needsClip = FALSE;\n        HRGN oldClipRegion = NULL;\n\n        textRect.left += Node->Level * width;\n\n        // The icon may need to be clipped if the column is too small.\n        needsClip = Column->Width < textRect.left + (Context->CanAnyExpand ? width : 0) + (Node->Icon ? width : 0);\n\n        if (needsClip)\n        {\n            oldClipRegion = CreateRectRgn(0, 0, 0, 0);\n\n            if (GetClipRgn(hdc, oldClipRegion) != 1)\n            {\n                DeleteRgn(oldClipRegion);\n                oldClipRegion = NULL;\n            }\n\n            // Clip contents to the column.\n            IntersectClipRect(hdc, CellRect->left, textRect.top, CellRect->right, textRect.bottom);\n        }\n\n        if (Context->CanAnyExpand) // flag is used so we can avoid indenting when it's a flat list\n        {\n            BOOLEAN drewUsingTheme = FALSE;\n            RECT themeRect;\n\n            if (!Node->s.IsLeaf)\n            {\n                // Draw the plus/minus glyph.\n\n                themeRect.left = textRect.left;\n                themeRect.right = themeRect.left + width;\n                //themeRect.left = textRect.right;\n                //themeRect.right = textRect.right - SmallIconWidth;\n                themeRect.top = textRect.top;\n                themeRect.bottom = themeRect.top + height;\n\n                if (Context->ThemeHasGlyph)\n                {\n                    INT partId;\n                    INT stateId;\n\n                    partId = (RowIndex == Context->HotNodeIndex && Node->s.PlusMinusHot && Context->ThemeHasHotGlyph) ? TVP_HOTGLYPH : TVP_GLYPH;\n                    stateId = Node->Expanded ? GLPS_OPENED : GLPS_CLOSED;\n\n                    if (PhDrawThemeBackground(\n                        Context->ThemeData,\n                        hdc,\n                        partId,\n                        stateId,\n                        &themeRect,\n                        NULL\n                        ))\n                    {\n                        drewUsingTheme = TRUE;\n                    }\n                }\n\n                if (!drewUsingTheme)\n                {\n                    ULONG glyphWidth;\n                    ULONG glyphHeight;\n                    RECT glyphRect;\n\n                    glyphWidth = width / 2;\n                    glyphHeight = height / 2;\n\n                    glyphRect.left = textRect.left + (width - glyphWidth) / 2;\n                    glyphRect.right = glyphRect.left + glyphWidth;\n                    //glyphRect.left = textRect.right + (SmallIconWidth - glyphWidth) / 2;\n                    //glyphRect.right = glyphRect.left - glyphWidth;\n                    glyphRect.top = textRect.top + (height - glyphHeight) / 2;\n                    glyphRect.bottom = glyphRect.top + glyphHeight;\n\n                    PhTnpDrawPlusMinusGlyph(hdc, &glyphRect, !Node->Expanded);\n                }\n            }\n\n            textRect.left += width;\n        }\n\n        // Draw the icon.\n\n        if (Context->ImageListSupport)\n        {\n            //LONG right = textRect.right;\n            //textRect.right = textRect.left + SmallIconWidth;\n            //FillRect(hdc, &textRect, GetSysColorBrush(COLOR_HOTLIGHT));\n            //textRect.right = right;\n\n            PhImageListDrawEx(\n                Context->ImageListHandle,\n                (ULONG)(ULONG_PTR)Node->Icon, // HACK (dmex)\n                hdc,\n                textRect.left,\n                textRect.top,\n                width,\n                height,\n                CLR_DEFAULT,\n                CLR_NONE,\n                ILD_NORMAL | ILD_TRANSPARENT,\n                ILS_NORMAL\n                );\n\n            textRect.left += width + Context->IconRightPadding;\n        }\n        else if (Node->Icon)\n        {\n            DrawIconEx(\n                hdc,\n                textRect.left,\n                textRect.top,\n                Node->Icon,\n                width,\n                height,\n                0,\n                NULL,\n                DI_NORMAL\n                );\n\n            textRect.left += width + Context->IconRightPadding;\n        }\n\n        if (needsClip)\n        {\n            SelectClipRgn(hdc, oldClipRegion);\n\n            if (oldClipRegion)\n                DeleteRgn(oldClipRegion);\n        }\n\n        if (textRect.left > textRect.right)\n            textRect.left = textRect.right;\n    }\n\n    if (Column->CustomDraw)\n    {\n        BOOLEAN result;\n        PH_TREENEW_CUSTOM_DRAW customDraw;\n        INT savedDc;\n\n        customDraw.Node = Node;\n        customDraw.Column = Column;\n        customDraw.Dc = hdc;\n        customDraw.CellRect = *CellRect;\n        customDraw.TextRect = textRect;\n\n        // Fix up the rectangles before giving them to the user.\n        if (customDraw.CellRect.left > customDraw.CellRect.right)\n            customDraw.CellRect.left = customDraw.CellRect.right;\n        if (customDraw.TextRect.left > customDraw.TextRect.right)\n            customDraw.TextRect.left = customDraw.TextRect.right;\n\n        savedDc = SaveDC(hdc);\n        result = Context->Callback(Context->Handle, TreeNewCustomDraw, &customDraw, NULL, Context->CallbackContext);\n        RestoreDC(hdc, savedDc);\n\n        if (result)\n            return;\n    }\n\n    if (PhTnpGetCellText(Context, Node, Column->Id, &text))\n    {\n        if (!(textFlags & (DT_PATH_ELLIPSIS | DT_WORD_ELLIPSIS)))\n            textFlags |= DT_END_ELLIPSIS;\n\n        textFlags |= DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE;\n\n        textRect.top = CellRect->top;\n        textRect.bottom = CellRect->bottom;\n\n        if (font)\n            oldFont = SelectFont(hdc, font);\n\n        DrawText(\n            hdc,\n            text.Buffer,\n            (ULONG)text.Length / 2,\n            &textRect,\n            textFlags\n            );\n\n        if (oldFont)\n            SelectFont(hdc, oldFont);\n    }\n}\n\n/**\n * Draws the divider line between the fixed and normal columns.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param hdc Device context handle.\n */\nVOID PhTnpDrawDivider(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc\n    )\n{\n    POINT points[2];\n\n    if (Context->AnimateDivider)\n    {\n        if (Context->DividerHot == 0 && !Context->HScrollVisible)\n            return; // divider is invisible\n\n        if (Context->DividerHot < 100)\n        {\n            BLENDFUNCTION blendFunction;\n\n            // We need to draw and alpha blend the divider.\n            // We can use the extra column allocated in the buffered context to initially draw the\n            // divider.\n\n            points[0].x = Context->ClientRect.right;\n            points[0].y = Context->HeaderHeight;\n            points[1].x = Context->ClientRect.right;\n            points[1].y = Context->ClientRect.bottom;\n            SetDCPenColor(Context->BufferedContext, RGB(0x77, 0x77, 0x77));\n            SelectPen(Context->BufferedContext, PhGetStockPen(DC_PEN));\n            Polyline(Context->BufferedContext, points, 2);\n\n            blendFunction.BlendOp = AC_SRC_OVER;\n            blendFunction.BlendFlags = 0;\n            blendFunction.AlphaFormat = 0;\n\n            // If the horizontal scroll bar is visible, we need to display a line even if the\n            // divider is not hot. In this case we increase the base alpha value.\n            if (!Context->HScrollVisible)\n                blendFunction.SourceConstantAlpha = (UCHAR)(Context->DividerHot * 255 / 100);\n            else\n                blendFunction.SourceConstantAlpha = 55 + (UCHAR)(Context->DividerHot * 2);\n\n            GdiAlphaBlend(\n                hdc,\n                Context->FixedWidth,\n                Context->HeaderHeight,\n                1,\n                Context->ClientRect.bottom - Context->HeaderHeight,\n                Context->BufferedContext,\n                Context->ClientRect.right,\n                Context->HeaderHeight,\n                1,\n                Context->ClientRect.bottom - Context->HeaderHeight,\n                blendFunction\n                );\n\n            return;\n        }\n    }\n\n    points[0].x = Context->FixedWidth;\n    points[0].y = Context->HeaderHeight;\n    points[1].x = Context->FixedWidth;\n    points[1].y = Context->ClientRect.bottom;\n    SetDCPenColor(hdc, RGB(0x77, 0x77, 0x77));\n    SelectPen(hdc, PhGetStockPen(DC_PEN));\n    Polyline(hdc, points, 2);\n}\n\n/**\n * Draws the plus/minus glyph for expanding/collapsing tree nodes.\n *\n * \\param hdc Device context handle.\n * \\param Rect Pointer to the bounding rectangle for the glyph.\n * \\param Plus TRUE to draw a plus sign, FALSE to draw a minus sign.\n */\nVOID PhTnpDrawPlusMinusGlyph(\n    _In_ HDC hdc,\n    _In_ PRECT Rect,\n    _In_ BOOLEAN Plus\n    )\n{\n    INT savedDc;\n    ULONG width;\n    ULONG height;\n    POINT points[2];\n\n    savedDc = SaveDC(hdc);\n\n    SelectPen(hdc, PhGetStockPen(DC_PEN));\n    SetDCPenColor(hdc, RGB(0x55, 0x55, 0x55));\n    SelectBrush(hdc, PhGetStockBrush(DC_BRUSH));\n    SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff));\n\n    width = Rect->right - Rect->left;\n    height = Rect->bottom - Rect->top;\n\n    // Draw the rectangle.\n    Rectangle(hdc, Rect->left, Rect->top, Rect->right + 1, Rect->bottom + 1);\n\n    SetDCPenColor(hdc, RGB(0x00, 0x00, 0x00));\n\n    // Draw the horizontal line.\n    points[0].x = Rect->left + 2;\n    points[0].y = Rect->top + height / 2;\n    points[1].x = Rect->right - 2 + 1;\n    points[1].y = points[0].y;\n    Polyline(hdc, points, 2);\n\n    if (Plus)\n    {\n        // Draw the vertical line.\n        points[0].x = Rect->left + width / 2;\n        points[0].y = Rect->top + 2;\n        points[1].x = points[0].x;\n        points[1].y = Rect->bottom - 2 + 1;\n        Polyline(hdc, points, 2);\n    }\n\n    RestoreDC(hdc, savedDc);\n}\n\n/**\n * Draws the selection rectangle around selected items.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param hdc Device context handle.\n * \\param Rect Pointer to the rectangle to draw.\n */\nVOID PhTnpDrawSelectionRectangle(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT Rect\n    )\n{\n    RECT rect;\n    BOOLEAN drewWithAlpha;\n\n    rect = *Rect;\n\n    // MSDN says FrameRect/DrawFocusRect doesn't draw anything if bottom <= top or right <= left.\n    // That's complete rubbish.\n    if (rect.right - rect.left == 0 || rect.bottom - rect.top == 0)\n        return;\n\n    drewWithAlpha = FALSE;\n\n    if (Context->SelectionRectangleAlpha)\n    {\n        HDC tempDc;\n        HBITMAP bitmap;\n        HBITMAP oldBitmap;\n        RECT tempRect;\n        BLENDFUNCTION blendFunction;\n\n        if (tempDc = CreateCompatibleDC(hdc))\n        {\n            if (bitmap = CreateCompatibleBitmap(hdc, 1, 1))\n            {\n                // Draw the outline of the selection rectangle.\n                FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));\n\n                // Fill in the selection rectangle.\n                oldBitmap = SelectBitmap(tempDc, bitmap);\n                tempRect.left = 0;\n                tempRect.top = 0;\n                tempRect.right = 1;\n                tempRect.bottom = 1;\n                FillRect(tempDc, &tempRect, (HBRUSH)(COLOR_HOTLIGHT + 1));\n\n                blendFunction.BlendOp = AC_SRC_OVER;\n                blendFunction.BlendFlags = 0;\n                blendFunction.SourceConstantAlpha = 70;\n                blendFunction.AlphaFormat = 0;\n\n                GdiAlphaBlend(\n                    hdc,\n                    rect.left,\n                    rect.top,\n                    rect.right - rect.left,\n                    rect.bottom - rect.top,\n                    tempDc,\n                    0,\n                    0,\n                    1,\n                    1,\n                    blendFunction\n                    );\n\n                drewWithAlpha = TRUE;\n\n                SelectBitmap(tempDc, oldBitmap);\n                DeleteBitmap(bitmap);\n            }\n\n            DeleteDC(tempDc);\n        }\n    }\n\n    if (!drewWithAlpha)\n    {\n        DrawFocusRect(hdc, &rect);\n    }\n}\n\n/**\n * Draws the themed border around the control.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param hdc Device context handle.\n */\nVOID PhTnpDrawThemedBorder(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc\n    )\n{\n    RECT windowRect;\n    RECT clientRect;\n    LONG sizingBorderWidth;\n    LONG borderX;\n    LONG borderY;\n\n    if (!PhGetWindowRect(Context->Handle, &windowRect))\n        return;\n\n    windowRect.right -= windowRect.left;\n    windowRect.bottom -= windowRect.top;\n    windowRect.left = 0;\n    windowRect.top = 0;\n\n    clientRect.left = windowRect.left + Context->SystemEdgeX;\n    clientRect.top = windowRect.top + Context->SystemEdgeY;\n    clientRect.right = windowRect.right - Context->SystemEdgeX;\n    clientRect.bottom = windowRect.bottom - Context->SystemEdgeY;\n\n    // Make sure we don't paint in the client area.\n    ExcludeClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom);\n\n    // Draw the themed border.\n    PhDrawThemeBackground(Context->ThemeData, hdc, 0, 0, &windowRect, NULL);\n\n    // Calculate the size of the border we just drew, and fill in the rest of the space if we didn't\n    // fully paint the region.\n\n    if (PhGetThemeInt(Context->ThemeData, 0, 0, TMT_SIZINGBORDERWIDTH, &sizingBorderWidth))\n    {\n        borderX = sizingBorderWidth;\n        borderY = sizingBorderWidth;\n    }\n    else\n    {\n        borderX = Context->SystemBorderX;\n        borderY = Context->SystemBorderY;\n    }\n\n    if (borderX < Context->SystemEdgeX || borderY < Context->SystemEdgeY)\n    {\n        windowRect.left += Context->SystemEdgeX - borderX;\n        windowRect.top += Context->SystemEdgeY - borderY;\n        windowRect.right -= Context->SystemEdgeX - borderX;\n        windowRect.bottom -= Context->SystemEdgeY - borderY;\n        FillRect(hdc, &windowRect, (HBRUSH)(COLOR_WINDOW + 1));\n    }\n}\n\n/**\n * Initializes the tooltip control for the treenew control.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpInitializeTooltips(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    TOOLINFO toolInfo;\n\n    Context->TooltipsHandle = PhCreateWindowEx(\n        TOOLTIPS_CLASS,\n        NULL,\n        WS_POPUP | TTS_NOANIMATE | TTS_NOFADE | TTS_NOPREFIX | TTS_ALWAYSTIP,\n        WS_EX_TOPMOST | WS_EX_TRANSPARENT, // solves double-click problem (wj32)\n        CW_USEDEFAULT,\n        CW_USEDEFAULT,\n        CW_USEDEFAULT,\n        CW_USEDEFAULT,\n        NULL,\n        NULL,\n        NULL,\n        NULL\n        );\n\n    if (!Context->TooltipsHandle)\n        return;\n\n    // Item tooltips\n    memset(&toolInfo, 0, sizeof(TOOLINFO));\n    toolInfo.cbSize = sizeof(TOOLINFO);\n    toolInfo.uFlags = TTF_TRANSPARENT;\n    toolInfo.hwnd = Context->Handle;\n    toolInfo.uId = TNP_TOOLTIPS_ITEM;\n    toolInfo.lpszText = LPSTR_TEXTCALLBACK;\n    toolInfo.lParam = TNP_TOOLTIPS_ITEM;\n    SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);\n\n    // Fixed column tooltips\n    toolInfo.uFlags = 0;\n    toolInfo.hwnd = Context->FixedHeaderHandle;\n    toolInfo.uId = TNP_TOOLTIPS_FIXED_HEADER;\n    toolInfo.lpszText = LPSTR_TEXTCALLBACK;\n    toolInfo.lParam = TNP_TOOLTIPS_FIXED_HEADER;\n    SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);\n\n    // Normal column tooltips\n    toolInfo.uFlags = 0;\n    toolInfo.hwnd = Context->HeaderHandle;\n    toolInfo.uId = TNP_TOOLTIPS_HEADER;\n    toolInfo.lpszText = LPSTR_TEXTCALLBACK;\n    toolInfo.lParam = TNP_TOOLTIPS_HEADER;\n    SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);\n\n    SetWindowPos(\n        Context->TooltipsHandle,\n        HWND_TOPMOST,\n        0, 0, 0, 0,\n        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE\n        );\n\n    if (Context->HeaderCustomDraw)\n    {\n        Context->HeaderHotColumn = ULONG_MAX;\n        Context->HeaderThemeHandle = PhOpenThemeData(Context->HeaderHandle, VSCLASS_HEADER, Context->WindowDpi);\n    }\n\n    // Hook the header control window procedures so we can forward mouse messages to the tooltip control.\n    Context->HeaderWindowProc = PhGetWindowProcedure(Context->HeaderHandle);\n    PhSetWindowContext(Context->HeaderHandle, MAXCHAR, Context);\n    PhSetWindowProcedure(Context->HeaderHandle, PhTnpHeaderHookWndProc);\n\n    Context->FixedHeaderWindowProc = PhGetWindowProcedure(Context->FixedHeaderHandle);\n    PhSetWindowContext(Context->FixedHeaderHandle, MAXCHAR, Context);\n    PhSetWindowProcedure(Context->FixedHeaderHandle, PhTnpHeaderHookWndProc);\n\n    SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); // no limit\n    SetWindowFont(Context->TooltipsHandle, Context->Font, FALSE);\n    Context->TooltipFont = Context->Font;\n}\n\n/**\n * Retrieves the tooltip text for a cell at a given point.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Point Pointer to the point to test.\n * \\param Text Pointer to receive the tooltip text.\n * \\return TRUE if tooltip text was retrieved, FALSE otherwise.\n */\n_Success_(return)\nBOOLEAN PhTnpGetTooltipText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPOINT Point,\n    _Out_ PPH_STRING *Text\n    )\n{\n    PH_TREENEW_HIT_TEST hitTest;\n    BOOLEAN unfoldingTooltip;\n    BOOLEAN unfoldingTooltipFromViewCancelled;\n    PH_TREENEW_CELL_PARTS parts;\n    LONG viewRight;\n    PH_TREENEW_GET_CELL_TOOLTIP getCellTooltip;\n\n    hitTest.Point = *Point;\n    hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM;\n    PhTnpHitTest(Context, &hitTest);\n\n    if (Context->DragSelectionActive)\n        return FALSE;\n    if (!(hitTest.Flags & TN_HIT_ITEM))\n        return FALSE;\n    if (hitTest.Flags & (TN_HIT_ITEM_PLUSMINUS | TN_HIT_DIVIDER))\n        return FALSE;\n    if (!hitTest.Column)\n        return FALSE;\n\n    if (Context->TooltipIndex != hitTest.Node->Index || Context->TooltipId != hitTest.Column->Id)\n    {\n        Context->TooltipIndex = hitTest.Node->Index;\n        Context->TooltipId = hitTest.Column->Id;\n\n        getCellTooltip.Flags = 0;\n        getCellTooltip.Node = hitTest.Node;\n        getCellTooltip.Column = hitTest.Column;\n        getCellTooltip.Unfolding = FALSE;\n        PhInitializeEmptyStringRef(&getCellTooltip.Text);\n        getCellTooltip.Font = Context->Font;\n        getCellTooltip.MaximumWidth = ULONG_MAX;\n\n        unfoldingTooltip = FALSE;\n        unfoldingTooltipFromViewCancelled = FALSE;\n\n        if (!(Context->ExtendedFlags & TN_FLAG_NO_UNFOLDING_TOOLTIPS) &&\n            PhTnpGetCellParts(Context, hitTest.Node->Index, hitTest.Column, TN_MEASURE_TEXT, &parts) &&\n            (parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT))\n        {\n            viewRight = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n\n            // Use an unfolding tooltip if the text was truncated within the column, or the text\n            // extends beyond the view area in either direction.\n\n            if (parts.TextRect.left < parts.ContentRect.left || parts.TextRect.right > parts.ContentRect.right)\n            {\n                unfoldingTooltip = TRUE;\n            }\n            else if ((!hitTest.Column->Fixed && parts.TextRect.left < Context->NormalLeft) || parts.TextRect.right > viewRight)\n            {\n                // Only show view-based unfolding tooltips if the mouse is over the text itself.\n                if (Point->x >= parts.TextRect.left && Point->x < parts.TextRect.right)\n                    unfoldingTooltip = TRUE;\n                else\n                    unfoldingTooltipFromViewCancelled = TRUE;\n            }\n\n            if (unfoldingTooltip)\n            {\n                getCellTooltip.Unfolding = TRUE;\n                getCellTooltip.Text = parts.Text;\n                getCellTooltip.Font = parts.Font; // try to use the same font as the cell\n\n                Context->TooltipRect = parts.TextRect;\n            }\n        }\n\n        Context->Callback(Context->Handle, TreeNewGetCellTooltip, &getCellTooltip, NULL, Context->CallbackContext);\n\n        Context->TooltipUnfolding = getCellTooltip.Unfolding;\n\n        if (getCellTooltip.Text.Buffer && getCellTooltip.Text.Length != 0)\n        {\n            PhMoveReference(&Context->TooltipText, PhCreateString2(&getCellTooltip.Text));\n        }\n        else\n        {\n            PhClearReference(&Context->TooltipText);\n\n            if (unfoldingTooltipFromViewCancelled)\n            {\n                // We may need to show the view-based unfolding tooltip if the mouse moves over the\n                // text in the future. Reset the index and ID to make sure we keep checking.\n                Context->TooltipIndex = ULONG_MAX;\n                Context->TooltipId = ULONG_MAX;\n            }\n        }\n\n        Context->NewTooltipFont = getCellTooltip.Font;\n\n        if (!Context->NewTooltipFont)\n            Context->NewTooltipFont = Context->Font;\n\n        if (getCellTooltip.MaximumWidth <= MAXSHORT) // seems to be the maximum value that the tooltip control supports\n            SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, getCellTooltip.MaximumWidth);\n        else\n            SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT);\n    }\n\n    if (Context->TooltipText)\n    {\n        *Text = Context->TooltipText;\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Prepares to show the tooltip.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\return TRUE if the tooltip should be shown, FALSE otherwise.\n */\nBOOLEAN PhTnpPrepareTooltipShow(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT rect;\n\n    if (Context->TooltipFont != Context->NewTooltipFont)\n    {\n        Context->TooltipFont = Context->NewTooltipFont;\n        SetWindowFont(Context->TooltipsHandle, Context->TooltipFont, FALSE);\n    }\n\n    if (!Context->TooltipUnfolding)\n    {\n        SetWindowPos(\n            Context->TooltipsHandle,\n            HWND_TOPMOST,\n            0,\n            0,\n            0,\n            0,\n            SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_HIDEWINDOW\n            );\n\n        return FALSE;\n    }\n\n    rect = Context->TooltipRect;\n    SendMessage(Context->TooltipsHandle, TTM_ADJUSTRECT, TRUE, (LPARAM)&rect);\n    MapWindowRect(Context->Handle, NULL, &rect);\n    SetWindowPos(\n        Context->TooltipsHandle,\n        HWND_TOPMOST,\n        rect.left,\n        rect.top,\n        0,\n        0,\n        SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW\n        );\n\n    return TRUE;\n}\n\nVOID PhTnpPrepareTooltipPop(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    Context->TooltipIndex = ULONG_MAX;\n    Context->TooltipId = ULONG_MAX;\n    Context->TooltipColumnId = ULONG_MAX;\n}\n\n/**\n * Hides the tooltip.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpPopTooltip(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (Context->TooltipsHandle)\n    {\n        SendMessage(Context->TooltipsHandle, TTM_POP, 0, 0);\n        PhTnpPrepareTooltipPop(Context);\n    }\n}\n\n/**\n * Performs hit testing on the header control.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Fixed TRUE to test the fixed header, FALSE for the normal header.\n * \\param Point Pointer to the point to test.\n * \\param ItemRect Pointer to receive the item rectangle, or NULL.\n * \\return Pointer to the column under the point, or NULL.\n */\nPPH_TREENEW_COLUMN PhTnpHitTestHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Fixed,\n    _In_ PPOINT Point,\n    _Out_opt_ PRECT ItemRect\n    )\n{\n    PPH_TREENEW_COLUMN column;\n    RECT itemRect;\n\n    if (ItemRect)\n    {\n        memset(ItemRect, 0, sizeof(RECT));\n    }\n\n    if (Fixed)\n    {\n        if (!Context->FixedColumnVisible)\n            return NULL;\n\n        column = Context->FixedColumn;\n\n        if (!Header_GetItemRect(Context->FixedHeaderHandle, 0, &itemRect))\n            return NULL;\n    }\n    else\n    {\n        HDHITTESTINFO hitTestInfo;\n\n        hitTestInfo.pt = *Point;\n        hitTestInfo.flags = 0;\n        hitTestInfo.iItem = INT_ERROR;\n\n        if (SendMessage(Context->HeaderHandle, HDM_HITTEST, 0, (LPARAM)&hitTestInfo) != INT_ERROR && hitTestInfo.iItem != INT_ERROR)\n        {\n            HDITEM item;\n\n            item.mask = HDI_LPARAM;\n\n            if (!Header_GetItem(Context->HeaderHandle, hitTestInfo.iItem, &item))\n                return NULL;\n\n            column = (PPH_TREENEW_COLUMN)item.lParam;\n\n            if (!Header_GetItemRect(Context->HeaderHandle, hitTestInfo.iItem, &itemRect))\n                return NULL;\n        }\n        else\n        {\n            return NULL;\n        }\n    }\n\n    if (ItemRect)\n        *ItemRect = itemRect;\n\n    return column;\n}\n\n/**\n * Retrieves the tooltip text for a header column.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Fixed TRUE if this is the fixed header, FALSE for normal header.\n * \\param Point Pointer to the point under the cursor.\n * \\param Text Pointer to receive the tooltip text.\n * \\return TRUE if tooltip text was retrieved, FALSE otherwise.\n */\n_Success_(return)\nBOOLEAN PhTnpGetHeaderTooltipText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Fixed,\n    _In_ PPOINT Point,\n    _Out_ PPH_STRING *Text\n    )\n{\n    LOGICAL result;\n    PPH_TREENEW_COLUMN column;\n    RECT itemRect;\n    PCWSTR text;\n    SIZE_T textCount;\n    HFONT oldFont;\n    HDC hdc;\n    SIZE textSize;\n\n    column = PhTnpHitTestHeader(Context, Fixed, Point, &itemRect);\n\n    if (!column)\n        return FALSE;\n\n    if (Context->TooltipColumnId != column->Id)\n    {\n        // Determine if the tooltip needs to be shown.\n\n        text = column->Text;\n        textCount = PhCountStringZ(text);\n\n        if (!(hdc = GetDC(Context->Handle)))\n            return FALSE;\n\n        oldFont = SelectFont(hdc, Context->Font);\n        result = GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize);\n        if (oldFont) SelectFont(hdc, oldFont);\n        ReleaseDC(Context->Handle, hdc);\n\n        if (!result)\n            return FALSE;\n\n        if (textSize.cx + Context->TextMarginPadding <= itemRect.right - itemRect.left) // HACK: Magic values (same as our cell margins?)\n            return FALSE;\n\n        Context->TooltipColumnId = column->Id;\n        PhMoveReference(&Context->TooltipText, PhCreateStringEx(text, textCount * sizeof(WCHAR)));\n    }\n\n    *Text = Context->TooltipText;\n\n    // Always use the default parameters for column header tooltips.\n    Context->NewTooltipFont = Context->Font;\n    Context->TooltipUnfolding = FALSE;\n    SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH);\n\n    return TRUE;\n}\n\n/**\n * Retrieves the text for a column header.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Column Pointer to the column.\n * \\param Text Pointer to receive the header text as a string reference.\n * \\return TRUE if text was retrieved, FALSE otherwise.\n */\n_Success_(return)\nBOOLEAN PhTnpGetColumnHeaderText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _Out_ PPH_STRINGREF Text\n    )\n{\n    if (Column->Id > Context->HeaderColumnCacheMax)\n        return FALSE;\n\n    if (Context->HeaderStringCache && Context->HeaderStringCache[Column->Id].Length)\n    {\n        *Text = Context->HeaderStringCache[Column->Id];\n        return TRUE;\n    }\n\n    if (Context->HeaderTextCache)\n    {\n        PH_TREENEW_GET_HEADER_TEXT getHeaderText;\n\n        PhInitializeEmptyStringRef(&getHeaderText.Text);\n        getHeaderText.Column = Column;\n        getHeaderText.TextCache = (PWSTR)&((WCHAR(*)[PH_TREENEW_HEADER_TEXT_SIZE_MAX])Context->HeaderTextCache)[Column->Id]; // HACK (dmex)\n        getHeaderText.TextCacheSize = PH_TREENEW_HEADER_TEXT_SIZE_MAX * sizeof(WCHAR);\n\n        if (Context->Callback(\n            Context->Handle,\n            TreeNewGetHeaderText,\n            &getHeaderText,\n            NULL,\n            Context->CallbackContext\n            ) && getHeaderText.Text.Buffer)\n        {\n            *Text = getHeaderText.Text;\n\n            if (Context->HeaderStringCache) // (getHeaderText.Flags & TN_CACHE)\n            {\n                Context->HeaderStringCache[Column->Id] = getHeaderText.Text;\n            }\n\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN TnHeaderCustomPaint(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LPNMCUSTOMDRAW CustomDraw\n    )\n{\n    PPH_TREENEW_COLUMN column;\n\n    if (!Context->HeaderCustomDraw)\n        return FALSE;\n\n    if (!(column = (PPH_TREENEW_COLUMN)CustomDraw->lItemlParam))\n        return FALSE;\n\n    SetBkMode(CustomDraw->hdc, TRANSPARENT);\n\n    if (Context->HeaderHotColumn != ULONG_MAX && Context->HeaderHotColumn == column->Id)\n    {\n        if (Context->ThemeSupport)\n        {\n            SetDCBrushColor(CustomDraw->hdc, PhThemeWindowBackground2Color); // PhThemeWindowHighlightColor\n            FillRect(CustomDraw->hdc, &CustomDraw->rc, PhGetStockBrush(DC_BRUSH));\n\n            if (Context->HeaderDragging && Context->HeaderHotColumn != ULONG_MAX && Context->HeaderHotColumn == column->Id)\n            {\n                SetDCBrushColor(CustomDraw->hdc, RGB(0, 0, 229));\n                SelectBrush(CustomDraw->hdc, PhGetStockBrush(DC_BRUSH));\n                PatBlt(CustomDraw->hdc, CustomDraw->rc.right - 2, CustomDraw->rc.top, 2, CustomDraw->rc.bottom - CustomDraw->rc.top, PATCOPY);\n            }\n            else\n            {\n                SetDCBrushColor(CustomDraw->hdc, Context->ThemeSupport ? RGB(0x5f, 0x5f, 0x5f) : RGB(229, 229, 229));\n                SelectBrush(CustomDraw->hdc, PhGetStockBrush(DC_BRUSH));\n                PatBlt(CustomDraw->hdc, CustomDraw->rc.right - 1, CustomDraw->rc.top, 1, CustomDraw->rc.bottom - CustomDraw->rc.top, PATCOPY);\n                //PatBlt(CustomDraw->hdc, CustomDraw->rc.left, CustomDraw->rc.bottom - 1, CustomDraw->rc.right - CustomDraw->rc.left, 1, PATCOPY);\n            }\n        }\n        else\n        {\n            if (Context->HeaderThemeHandle)\n            {\n                INT state;\n\n                if (CustomDraw->uItemState == (CDIS_SHOWKEYBOARDCUES | CDIS_SELECTED))\n                    state = HIS_PRESSED;\n                else\n                    state = HIS_HOT;\n\n                PhDrawThemeBackground(\n                    Context->HeaderThemeHandle,\n                    CustomDraw->hdc,\n                    HP_HEADERITEM,\n                    state,\n                    &CustomDraw->rc,\n                    NULL\n                    );\n            }\n            else\n            {\n                FillRect(CustomDraw->hdc, &CustomDraw->rc, (HBRUSH)(COLOR_HIGHLIGHT + 1));\n            }\n        }\n    }\n    else\n    {\n        if (Context->ThemeSupport)\n        {\n            SetDCBrushColor(CustomDraw->hdc, PhThemeWindowBackgroundColor);\n            FillRect(CustomDraw->hdc, &CustomDraw->rc, PhGetStockBrush(DC_BRUSH));\n\n            if (Context->HeaderDragging && Context->HeaderHotColumn != ULONG_MAX && Context->HeaderHotColumn == column->Id)\n            {\n                SetDCBrushColor(CustomDraw->hdc, RGB(0, 0, 229));\n                SelectBrush(CustomDraw->hdc, PhGetStockBrush(DC_BRUSH));\n                PatBlt(CustomDraw->hdc, CustomDraw->rc.right - 2, CustomDraw->rc.top, 2, CustomDraw->rc.bottom - CustomDraw->rc.top, PATCOPY);\n            }\n            else\n            {\n                SetDCBrushColor(CustomDraw->hdc, Context->ThemeSupport ? RGB(0x5f, 0x5f, 0x5f) : RGB(229, 229, 229));\n                SelectBrush(CustomDraw->hdc, PhGetStockBrush(DC_BRUSH));\n                PatBlt(CustomDraw->hdc, CustomDraw->rc.right - 1, CustomDraw->rc.top, 1, CustomDraw->rc.bottom - CustomDraw->rc.top, PATCOPY);\n                //PatBlt(Hdc, CustomDraw->rc.left, CustomDraw->rc.bottom - 1, CustomDraw->rc.right - CustomDraw->rc.left, 1, PATCOPY);\n            }\n        }\n        else if (Context->HeaderThemeHandle)\n        {\n            PhDrawThemeBackground(\n                Context->HeaderThemeHandle,\n                CustomDraw->hdc,\n                HP_HEADERITEM,\n                HIS_NORMAL,\n                &CustomDraw->rc,\n                NULL\n                );\n        }\n        else\n        {\n            FillRect(CustomDraw->hdc, &CustomDraw->rc, (HBRUSH)(COLOR_WINDOW + 1));\n        }\n    }\n\n    if (column->Text)\n    {\n        PCWSTR textBuffer;\n        LONG textLength;\n        RECT textRect;\n        HFONT oldFont;\n        PH_STRINGREF headerString;\n        ULONG fmt = 0;\n        LONG sdf = 0;\n\n        if (FlagOn(column->Alignment, PH_ALIGN_LEFT))\n            SetFlag(fmt, HDF_LEFT);\n        else if (FlagOn(column->Alignment, PH_ALIGN_RIGHT))\n            SetFlag(fmt, HDF_RIGHT);\n        else\n            SetFlag(fmt, HDF_CENTER);\n\n        if (column->Id == Context->SortColumn)\n        {\n            if (Context->SortOrder == AscendingSortOrder)\n                SetFlag(fmt, HDF_SORTUP);\n            else if (Context->SortOrder == DescendingSortOrder)\n                SetFlag(fmt, HDF_SORTDOWN);\n\n            if (FlagOn(fmt, HDF_SORTDOWN))\n                sdf = HSAS_SORTEDDOWN;\n            else if (FlagOn(fmt, HDF_SORTUP))\n                sdf = HSAS_SORTEDUP;\n        }\n\n        textBuffer = column->Text;\n        textLength = (LONG)PhCountStringZ(column->Text);\n\n        textRect = CustomDraw->rc;\n        textRect.left += Context->HeaderTextPadding;\n        textRect.right -= Context->HeaderTextPadding;\n        textRect.bottom -= Context->HeaderTextPadding;\n        textRect.top += Context->HeaderTextMargin;\n\n        SetTextColor(CustomDraw->hdc, Context->ThemeSupport ? RGB(0x8f, 0x8f, 0x8f) : RGB(97, 116, 139)); // RGB(178, 178, 178)\n\n        oldFont = SelectFont(CustomDraw->hdc, Context->Font);\n        if (FlagOn(fmt, HDF_RIGHT))\n        {\n            DrawText(\n                CustomDraw->hdc, textBuffer, textLength, &textRect,\n                DT_SINGLELINE | DT_HIDEPREFIX | DT_WORD_ELLIPSIS | DT_BOTTOM | DT_RIGHT);\n        }\n        else\n        {\n            DrawText(CustomDraw->hdc, textBuffer, textLength, &textRect,\n                DT_SINGLELINE | DT_HIDEPREFIX | DT_WORD_ELLIPSIS | DT_BOTTOM | DT_LEFT);\n        }\n        SelectFont(CustomDraw->hdc, oldFont);\n\n        if (PhTnpGetColumnHeaderText(Context, column, &headerString))\n        {\n            SetTextColor(CustomDraw->hdc, Context->ThemeSupport ? RGB(0xff, 0xff, 0xff) : RGB(0, 0, 0));\n            oldFont = SelectFont(CustomDraw->hdc, Context->HeaderBoldFontHandle);\n            DrawText(\n                CustomDraw->hdc,\n                headerString.Buffer,\n                (LONG)headerString.Length / (LONG)sizeof(WCHAR),\n                &textRect,\n                DT_SINGLELINE | DT_HIDEPREFIX | DT_WORD_ELLIPSIS | DT_TOP | DT_RIGHT);\n            if (oldFont) SelectFont(CustomDraw->hdc, oldFont);\n        }\n\n        //DrawEdge(CustomDraw->hdc, &CustomDraw->rc, EDGE_SUNKEN, BF_SOFT | BF_RIGHT);\n        SetDCBrushColor(CustomDraw->hdc, Context->ThemeSupport ? RGB(0x5f, 0x5f, 0x5f) : RGB(229, 229, 229));\n        HBRUSH oldBrush = SelectBrush(CustomDraw->hdc, PhGetStockBrush(DC_BRUSH));\n        PatBlt(CustomDraw->hdc, CustomDraw->rc.right - 1, CustomDraw->rc.top, 1, CustomDraw->rc.bottom - CustomDraw->rc.top, PATCOPY);\n        SelectBrush(CustomDraw->hdc, oldBrush);\n\n        if (FlagOn(fmt, HDF_SORTDOWN | HDF_SORTUP))\n        {\n            if (Context->HeaderThemeHandle)\n            {\n                SIZE sortArrowSize = { 0 };\n\n                PhGetThemePartSize(\n                    Context->HeaderThemeHandle,\n                    CustomDraw->hdc,\n                    HP_HEADERSORTARROW,\n                    sdf,\n                    NULL,\n                    THEMEPARTSIZE_TRUE,\n                    &sortArrowSize\n                    );\n\n                CustomDraw->rc.bottom = sortArrowSize.cy;\n\n                PhDrawThemeBackground(\n                    Context->HeaderThemeHandle,\n                    CustomDraw->hdc,\n                    HP_HEADERSORTARROW,\n                    sdf,\n                    &CustomDraw->rc,\n                    NULL\n                    );\n            }\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Creates a buffered paint context for the header.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param Hdc The device context handle.\n * \\param BufferRect Pointer to the buffer rectangle.\n */\nVOID PhTnpHeaderCreateBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC Hdc,\n    _In_ PRECT BufferRect\n    )\n{\n    Context->HeaderBufferedDc = CreateCompatibleDC(Hdc);\n\n    if (!Context->HeaderBufferedDc)\n        return;\n\n    Context->HeaderBufferedContextRect = *BufferRect;\n    Context->HeaderBufferedBitmap = CreateCompatibleBitmap(\n        Hdc,\n        Context->HeaderBufferedContextRect.right,\n        Context->HeaderBufferedContextRect.bottom\n        );\n\n    Context->HeaderBufferedOldBitmap = SelectBitmap(Context->HeaderBufferedDc, Context->HeaderBufferedBitmap);\n}\n\n/**\n * Destroys the buffered paint context for the header.\n *\n * \\param Context Pointer to the treenew context structure.\n */\nVOID PhTnpHeaderDestroyBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (Context->HeaderBufferedDc && Context->HeaderBufferedOldBitmap)\n    {\n        SelectBitmap(Context->HeaderBufferedDc, Context->HeaderBufferedOldBitmap);\n        Context->HeaderBufferedOldBitmap = NULL;\n    }\n\n    if (Context->HeaderBufferedBitmap)\n    {\n        DeleteBitmap(Context->HeaderBufferedBitmap);\n        Context->HeaderBufferedBitmap = NULL;\n    }\n\n    if (Context->HeaderBufferedDc)\n    {\n        DeleteDC(Context->HeaderBufferedDc);\n        Context->HeaderBufferedDc = NULL;\n    }\n}\n\n/**\n * Window procedure hook for the header control.\n *\n * \\param WindowHandle Handle to the header window.\n * \\param WindowMessage The message identifier.\n * \\param wParam Additional message-specific information.\n * \\param lParam Additional message-specific information.\n * \\return The result of the message processing.\n */\nLRESULT CALLBACK PhTnpHeaderHookWndProc(\n    _In_ HWND WindowHandle,\n    _In_ UINT WindowMessage,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_TREENEW_CONTEXT context;\n    WNDPROC oldWndProc;\n\n    if (context = PhGetWindowContext(WindowHandle, MAXCHAR))\n    {\n        if (WindowHandle == context->FixedHeaderHandle)\n            oldWndProc = context->FixedHeaderWindowProc;\n        else\n            oldWndProc = context->HeaderWindowProc;\n    }\n    else\n    {\n        return DefWindowProc(WindowHandle, WindowMessage, wParam, lParam);\n    }\n\n    switch (WindowMessage)\n    {\n    case WM_DESTROY:\n        {\n            PhSetWindowProcedure(WindowHandle, oldWndProc);\n\n            PhRemoveWindowContext(WindowHandle, MAXCHAR);\n\n            PhTnpHeaderDestroyBufferedContext(context);\n        }\n        break;\n    case WM_MOUSEMOVE:\n        {\n            POINT point;\n            PPH_TREENEW_COLUMN column;\n            ULONG id;\n\n            point.x = GET_X_LPARAM(lParam);\n            point.y = GET_Y_LPARAM(lParam);\n            column = PhTnpHitTestHeader(context, WindowHandle == context->FixedHeaderHandle, &point, NULL);\n\n            if (column)\n                id = column->Id;\n            else\n                id = -1;\n\n            if (context->TooltipColumnId != id)\n            {\n                PhTnpPopTooltip(context);\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            NMHDR *header = (NMHDR *)lParam;\n\n            switch (header->code)\n            {\n            case TTN_GETDISPINFO:\n                {\n                    if (header->hwndFrom == context->TooltipsHandle)\n                    {\n                        NMTTDISPINFO *info = (NMTTDISPINFO *)header;\n                        POINT point;\n                        PPH_STRING string;\n\n                        if (PhGetClientPos(WindowHandle, &point))\n                        {\n                            if (PhTnpGetHeaderTooltipText(context, info->lParam == TNP_TOOLTIPS_FIXED_HEADER, &point, &string))\n                            {\n                                info->lpszText = string->Buffer;\n                                break;\n                            }\n                        }\n                    }\n                }\n                break;\n            case TTN_SHOW:\n                {\n                    if (header->hwndFrom == context->TooltipsHandle)\n                    {\n                        return PhTnpPrepareTooltipShow(context);\n                    }\n                }\n                break;\n            case TTN_POP:\n                {\n                    if (header->hwndFrom == context->TooltipsHandle)\n                    {\n                        PhTnpPrepareTooltipPop(context);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    switch (WindowMessage)\n    {\n    //case WM_MOUSEMOVE:\n    //case WM_LBUTTONDOWN:\n    //case WM_LBUTTONUP:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n        {\n            if (context->TooltipsHandle)\n            {\n                MSG message;\n\n                message.hwnd = WindowHandle;\n                message.message = WindowMessage;\n                message.wParam = wParam;\n                message.lParam = lParam;\n                SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n        }\n        break;\n    case WM_SETFONT:\n        {\n            HFONT fontHandle = (HFONT)wParam;\n            LOGFONT logFont;\n\n            if (!context->HeaderCustomDraw)\n                break;\n\n            if (context->HeaderBoldFontHandle)\n            {\n                DeleteFont(context->HeaderBoldFontHandle);\n                context->HeaderBoldFontHandle = NULL;\n            }\n\n            if (GetObject(fontHandle, sizeof(LOGFONT), &logFont))\n            {\n                logFont.lfHeight -= context->HeaderTextMargin;\n                context->HeaderBoldFontHandle = CreateFontIndirect(&logFont);\n                //context->HeaderBoldFontHandle = PhDuplicateFontWithNewHeight(fontHandle, -14);\n            }\n        }\n        break;\n    case WM_MOUSEMOVE:\n        {\n            BOOLEAN redraw = FALSE;\n\n            if (context->TooltipsHandle)\n            {\n                MSG message;\n\n                message.hwnd = WindowHandle;\n                message.message = WindowMessage;\n                message.wParam = wParam;\n                message.lParam = lParam;\n                SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n\n            if (!context->HeaderCustomDraw)\n                break;\n            //if (GetCapture() == WindowHandle)\n            //    break;\n\n            if (!context->HeaderDragging)\n            {\n                ULONG hitcolumn;\n                POINT point;\n                PPH_TREENEW_COLUMN column;\n\n                point.x = GET_X_LPARAM(lParam);\n                point.y = GET_Y_LPARAM(lParam);\n                column = PhTnpHitTestHeader(context, WindowHandle == context->FixedHeaderHandle, &point, NULL);\n\n                hitcolumn = column ? column->Id : ULONG_MAX;\n\n                if (context->HeaderHotColumn != hitcolumn)\n                {\n                    context->HeaderHotColumn = hitcolumn;\n                    //redraw = TRUE;\n                }\n\n                redraw = TRUE;\n            }\n\n            if (!context->HeaderMouseActive)\n            {\n                TRACKMOUSEEVENT trackEvent =\n                {\n                    sizeof(TRACKMOUSEEVENT),\n                    TME_LEAVE,\n                    WindowHandle,\n                    0\n                };\n\n                TrackMouseEvent(&trackEvent);\n                context->HeaderMouseActive = TRUE;\n\n                redraw = TRUE;\n            }\n\n            if (redraw)\n            {\n                InvalidateRect(WindowHandle, NULL, FALSE);\n            }\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            LRESULT result;\n\n            if (!context->HeaderCustomDraw)\n                break;\n\n            result = CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n            InvalidateRect(WindowHandle, NULL, FALSE);\n            return result;\n        }\n        break;\n    case WM_LBUTTONDOWN:\n        {\n            LRESULT result;\n            ULONG hitcolumn;\n            POINT point;\n            PPH_TREENEW_COLUMN column;\n\n            if (context->TooltipsHandle)\n            {\n                MSG message;\n\n                message.hwnd = WindowHandle;\n                message.message = WindowMessage;\n                message.wParam = wParam;\n                message.lParam = lParam;\n                SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n\n            if (!context->HeaderCustomDraw)\n                break;\n\n            point.x = GET_X_LPARAM(lParam);\n            point.y = GET_Y_LPARAM(lParam);\n            column = PhTnpHitTestHeader(context, WindowHandle == context->FixedHeaderHandle, &point, NULL);\n\n            hitcolumn = column ? column->Id : ULONG_MAX;\n\n            if (context->HeaderHotColumn != hitcolumn)\n            {\n                context->HeaderHotColumn = hitcolumn;\n                //redraw = TRUE;\n            }\n\n            InvalidateRect(WindowHandle, NULL, FALSE);\n\n            result = CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n            context->HeaderDragging = TRUE;\n            return result;\n        }\n        break;\n    case WM_LBUTTONUP:\n        {\n            LRESULT result;\n\n            if (context->TooltipsHandle)\n            {\n                MSG message;\n\n                message.hwnd = WindowHandle;\n                message.message = WindowMessage;\n                message.wParam = wParam;\n                message.lParam = lParam;\n                SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n\n            if (!context->HeaderCustomDraw)\n                break;\n\n            result = CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n            context->HeaderDragging = FALSE;\n            return result;\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            LRESULT result;\n\n            if (context->TooltipsHandle)\n            {\n                MSG message;\n\n                message.hwnd = WindowHandle;\n                message.message = WindowMessage;\n                message.wParam = wParam;\n                message.lParam = lParam;\n                SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n\n            if (!context->HeaderCustomDraw)\n                break;\n\n            result = CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n            context->HeaderMouseActive = FALSE;\n            context->HeaderHotColumn = ULONG_MAX;\n\n            //if (GetCapture() != WindowHandle)\n            //{\n            //    InvalidateRect(WindowHandle, NULL, FALSE);\n            //}\n\n            InvalidateRect(WindowHandle, NULL, FALSE);\n\n            return result;\n        }\n        break;\n    case WM_THEMECHANGED:\n        {\n            if (context->HeaderThemeHandle)\n            {\n                PhCloseThemeData(context->HeaderThemeHandle);\n                context->HeaderThemeHandle = NULL;\n            }\n\n            context->HeaderThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_HEADER, context->WindowDpi);\n        }\n        break;\n    }\n\n    return CallWindowProc(oldWndProc, WindowHandle, WindowMessage, wParam, lParam);\n}\n\n/**\n * Detects the start of a drag operation.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param CursorX The X coordinate of the cursor.\n * \\param CursorY The Y coordinate of the cursor.\n * \\param DispatchMessages TRUE to dispatch messages during drag detection, FALSE otherwise.\n * \\param CancelledByMessage Pointer to receive the message that cancelled the drag, or NULL.\n * \\return TRUE if a drag was detected, FALSE otherwise.\n */\nBOOLEAN PhTnpDetectDrag(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY,\n    _In_ BOOLEAN DispatchMessages,\n    _Out_opt_ PULONG CancelledByMessage\n    )\n{\n    RECT dragRect;\n    MSG msg;\n\n    // Capture mouse input and see if the user moves the mouse beyond the drag rectangle.\n\n    dragRect.left = CursorX - Context->SystemDragX;\n    dragRect.top = CursorY - Context->SystemDragY;\n    dragRect.right = CursorX + Context->SystemDragX;\n    dragRect.bottom = CursorY + Context->SystemDragY;\n    MapWindowRect(Context->Handle, NULL, &dragRect);\n\n    SetCapture(Context->Handle);\n\n    if (CancelledByMessage)\n        *CancelledByMessage = 0;\n\n    do\n    {\n        // It seems that GetMessage dispatches nonqueued messages directly from kernel-mode, so we\n        // have to use PeekMessage and WaitMessage in order to process WM_CAPTURECHANGED messages.\n        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))\n        {\n            switch (msg.message)\n            {\n            case WM_LBUTTONDOWN:\n            case WM_LBUTTONUP:\n            case WM_RBUTTONDOWN:\n            case WM_RBUTTONUP:\n                ReleaseCapture();\n\n                if (CancelledByMessage)\n                    *CancelledByMessage = msg.message;\n\n                break;\n            case WM_MOUSEMOVE:\n                if (msg.pt.x < dragRect.left || msg.pt.x >= dragRect.right ||\n                    msg.pt.y < dragRect.top || msg.pt.y >= dragRect.bottom)\n                {\n                    if (IsWindow(Context->Handle))\n                        return TRUE;\n                    else\n                        return FALSE;\n                }\n                break;\n            default:\n                if (DispatchMessages)\n                {\n                    TranslateMessage(&msg);\n                    DispatchMessage(&msg);\n                }\n                break;\n            }\n        }\n        else\n        {\n            WaitMessage();\n        }\n    } while (IsWindow(Context->Handle) && GetCapture() == Context->Handle);\n\n    return FALSE;\n}\n\n/**\n * Performs drag selection of nodes.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param CursorX The starting X coordinate of the cursor.\n * \\param CursorY The starting Y coordinate of the cursor.\n */\nVOID PhTnpDragSelect(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    MSG msg;\n    LONG cursorX;\n    LONG cursorY;\n    BOOLEAN originFixed;\n    RECT dragRect;\n    RECT oldDragRect;\n    RECT windowRect;\n    POINT cursorPoint;\n    BOOLEAN showContextMenu;\n\n    cursorX = CursorX;\n    cursorY = CursorY;\n    originFixed = cursorX < Context->FixedWidth;\n\n    dragRect.left = cursorX;\n    dragRect.top = cursorY;\n    dragRect.right = cursorX;\n    dragRect.bottom = cursorY;\n    oldDragRect = dragRect;\n    Context->DragRect = dragRect;\n    Context->DragSelectionActive = TRUE;\n\n    if (Context->DoubleBuffered)\n        Context->SelectionRectangleAlpha = TRUE;\n    // TODO: Make sure the monitor's color depth is sufficient for alpha-blended selection\n    // rectangles.\n\n    if (!PhGetWindowRect(Context->Handle, &windowRect))\n        return;\n\n    cursorPoint.x = windowRect.left + cursorX;\n    cursorPoint.y = windowRect.top + cursorY;\n\n    showContextMenu = FALSE;\n\n    SetCapture(Context->Handle);\n\n    while (TRUE)\n    {\n        if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))\n        {\n            BOOLEAN leftOrRight;\n            BOOLEAN aboveOrBelow;\n\n            // If the cursor is outside of the window, generate some messages so the window keeps\n            // scrolling.\n\n            leftOrRight = cursorPoint.x < windowRect.left || cursorPoint.x > windowRect.right;\n            aboveOrBelow = cursorPoint.y < windowRect.top || cursorPoint.y > windowRect.bottom;\n\n            if ((Context->VScrollVisible && aboveOrBelow && PhTnpCanScroll(Context, FALSE, cursorPoint.y > windowRect.bottom)) ||\n                (Context->HScrollVisible && leftOrRight && PhTnpCanScroll(Context, TRUE, cursorPoint.x > windowRect.right)))\n            {\n                SetCursorPos(cursorPoint.x, cursorPoint.y);\n            }\n            else\n            {\n                WaitMessage();\n            }\n\n            goto EndOfLoop;\n        }\n\n        cursorPoint = msg.pt;\n\n        switch (msg.message)\n        {\n        case WM_LBUTTONDOWN:\n        case WM_LBUTTONUP:\n        case WM_RBUTTONDOWN:\n        case WM_MBUTTONDOWN:\n        case WM_MBUTTONUP:\n            ReleaseCapture();\n            goto EndOfLoop;\n        case WM_RBUTTONUP:\n            ReleaseCapture();\n            showContextMenu = TRUE;\n            goto EndOfLoop;\n        case WM_MOUSEMOVE:\n            {\n                LONG newCursorX;\n                LONG newCursorY;\n                LONG deltaRows;\n                LONG deltaX;\n                LONG oldVScrollPosition;\n                LONG oldHScrollPosition;\n                LONG newDeltaX;\n                LONG newDeltaY;\n                LONG viewLeft;\n                LONG viewTop;\n                LONG viewRight;\n                LONG viewBottom;\n                LONG temp;\n                RECT totalRect;\n\n                newCursorX = GET_X_LPARAM(msg.lParam);\n                newCursorY = GET_Y_LPARAM(msg.lParam);\n\n                // Scroll the window if the cursor is outside of it.\n\n                deltaRows = 0;\n                deltaX = 0;\n\n                if (Context->VScrollVisible)\n                {\n                    if (cursorPoint.y < windowRect.top)\n                        deltaRows = -(windowRect.top - cursorPoint.y + Context->RowHeight - 1) / Context->RowHeight; // scroll up\n                    else if (cursorPoint.y >= windowRect.bottom)\n                        deltaRows = (cursorPoint.y - windowRect.bottom + Context->RowHeight - 1) / Context->RowHeight; // scroll down\n                }\n\n                if (Context->HScrollVisible)\n                {\n                    if (cursorPoint.x < windowRect.left)\n                        deltaX = -(windowRect.left - cursorPoint.x); // scroll left\n                    else if (cursorPoint.x >= windowRect.right)\n                        deltaX = cursorPoint.x - windowRect.right; // scroll right\n                }\n\n                oldVScrollPosition = Context->VScrollPosition;\n                oldHScrollPosition = Context->HScrollPosition;\n\n                if (deltaRows != 0 || deltaX != 0)\n                    PhTnpScroll(Context, deltaRows, deltaX);\n\n                newDeltaX = oldHScrollPosition - Context->HScrollPosition;\n                newDeltaY = (oldVScrollPosition - Context->VScrollPosition) * Context->RowHeight;\n\n                // Adjust our original drag point for the scrolling.\n                if (!originFixed)\n                    cursorX += newDeltaX;\n                cursorY += newDeltaY;\n\n                // Adjust the old drag rectangle for the scrolling.\n                if (!originFixed)\n                    oldDragRect.left += newDeltaX;\n                oldDragRect.top += newDeltaY;\n                if (!originFixed)\n                    oldDragRect.right += newDeltaX;\n                oldDragRect.bottom += newDeltaY;\n\n                // Ensure that the new cursor position is within the content area.\n\n                viewLeft = Context->FixedColumnVisible ? 0 : -Context->HScrollPosition;\n                viewTop = Context->HeaderHeight - Context->VScrollPosition;\n                viewRight = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n                viewBottom = Context->HeaderHeight + ((LONG)Context->FlatList->Count - Context->VScrollPosition) * Context->RowHeight;\n\n                temp = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n                viewRight = max(viewRight, temp);\n                temp = Context->ClientRect.bottom - ((!Context->FixedColumnVisible && Context->HScrollVisible) ? Context->HScrollHeight : 0);\n                viewBottom = max(viewBottom, temp);\n\n                if (newCursorX < viewLeft)\n                    newCursorX = viewLeft;\n                if (newCursorX > viewRight)\n                    newCursorX = viewRight;\n                if (newCursorY < viewTop)\n                    newCursorY = viewTop;\n                if (newCursorY > viewBottom)\n                    newCursorY = viewBottom;\n\n                // Create the new drag rectangle.\n\n                if (cursorX < newCursorX)\n                {\n                    dragRect.left = cursorX;\n                    dragRect.right = newCursorX;\n                }\n                else\n                {\n                    dragRect.left = newCursorX;\n                    dragRect.right = cursorX;\n                }\n\n                if (cursorY < newCursorY)\n                {\n                    dragRect.top = cursorY;\n                    dragRect.bottom = newCursorY;\n                }\n                else\n                {\n                    dragRect.top = newCursorY;\n                    dragRect.bottom = cursorY;\n                }\n\n                // Has anything changed from before?\n                if (dragRect.left == oldDragRect.left && dragRect.top == oldDragRect.top &&\n                    dragRect.right == oldDragRect.right && dragRect.bottom == oldDragRect.bottom)\n                {\n                    break;\n                }\n\n                Context->DragRect = dragRect;\n\n                // Process the selection.\n                totalRect.left = min(dragRect.left, oldDragRect.left);\n                totalRect.top = min(dragRect.top, oldDragRect.top);\n                totalRect.right = max(dragRect.right, oldDragRect.right);\n                totalRect.bottom = max(dragRect.bottom, oldDragRect.bottom);\n                PhTnpProcessDragSelect(Context, (ULONG)msg.wParam, &oldDragRect, &dragRect, &totalRect);\n\n                // Redraw the drag rectangle.\n                RedrawWindow(Context->Handle, &totalRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW);\n\n                oldDragRect = dragRect;\n            }\n            break;\n        case WM_MOUSELEAVE:\n            break; // don't process\n        case WM_MOUSEWHEEL:\n            break; // don't process\n        case WM_KEYDOWN:\n            if (msg.wParam == VK_ESCAPE)\n            {\n                ULONG changedStart;\n                ULONG changedEnd;\n                RECT rect;\n\n                PhTnpSelectRange(Context, ULONG_MAX, ULONG_MAX, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                {\n                    InvalidateRect(Context->Handle, &rect, FALSE);\n                }\n\n                ReleaseCapture();\n            }\n            break; // don't process\n        case WM_CHAR:\n            break; // don't process\n        default:\n            TranslateMessage(&msg);\n            DispatchMessage(&msg);\n            break;\n        }\n\nEndOfLoop:\n        if (GetCapture() != Context->Handle)\n            break;\n    }\n\n    Context->DragSelectionActive = FALSE;\n    RedrawWindow(Context->Handle, &dragRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW);\n\n    if (showContextMenu)\n    {\n        // Display a context menu at the original drag point.\n        SendMessage(Context->Handle, WM_CONTEXTMENU, (WPARAM)Context->Handle, MAKELPARAM(windowRect.left + CursorX, windowRect.top + CursorY));\n    }\n}\n\n/**\n * Processes drag selection based on mouse movement.\n *\n * \\param Context Pointer to the treenew context structure.\n * \\param VirtualKeys The state of virtual keys.\n * \\param OldRect Pointer to the previous drag rectangle.\n * \\param NewRect Pointer to the new drag rectangle.\n * \\param TotalRect Pointer to the total drag rectangle.\n */\nVOID PhTnpProcessDragSelect(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKeys,\n    _In_ PRECT OldRect,\n    _In_ PRECT NewRect,\n    _In_ PRECT TotalRect\n    )\n{\n    LONG firstRow;\n    LONG lastRow;\n    RECT rowRect;\n    LONG i;\n    PPH_TREENEW_NODE node;\n    LONG changedStart;\n    LONG changedEnd;\n    RECT rect;\n\n    // Determine which rows we need to test. The divisions below must be done on positive integers\n    // to ensure correct rounding.\n\n    firstRow = (TotalRect->top - Context->HeaderHeight + Context->VScrollPosition * Context->RowHeight) / Context->RowHeight;\n    lastRow = (TotalRect->bottom - 1 - Context->HeaderHeight + Context->VScrollPosition * Context->RowHeight) / Context->RowHeight;\n\n    if (firstRow < 0)\n        firstRow = 0;\n    if (lastRow >= (LONG)Context->FlatList->Count)\n        lastRow = Context->FlatList->Count - 1;\n\n    rowRect.left = 0;\n    rowRect.top = Context->HeaderHeight + (firstRow - Context->VScrollPosition) * Context->RowHeight;\n    rowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n    rowRect.bottom = rowRect.top + Context->RowHeight;\n\n    changedStart = lastRow;\n    changedEnd = firstRow;\n\n    // Process the rows.\n    for (i = firstRow; i <= lastRow; i++)\n    {\n        BOOLEAN inOldRect;\n        BOOLEAN inNewRect;\n\n        node = Context->FlatList->Items[i];\n\n        inOldRect = rowRect.top < OldRect->bottom && rowRect.bottom > OldRect->top &&\n            rowRect.left < OldRect->right && rowRect.right > OldRect->left;\n        inNewRect = rowRect.top < NewRect->bottom && rowRect.bottom > NewRect->top &&\n            rowRect.left < NewRect->right && rowRect.right > NewRect->left;\n\n        if (VirtualKeys & MK_CONTROL)\n        {\n            if (!node->Unselectable && inOldRect != inNewRect)\n            {\n                node->Selected = !node->Selected;\n\n                if (changedStart > i)\n                    changedStart = i;\n                if (changedEnd < i)\n                    changedEnd = i;\n            }\n        }\n        else\n        {\n            if (!node->Unselectable && inOldRect != inNewRect)\n            {\n                node->Selected = inNewRect;\n\n                if (changedStart > i)\n                    changedStart = i;\n                if (changedEnd < i)\n                    changedEnd = i;\n            }\n        }\n\n        rowRect.top = rowRect.bottom;\n        rowRect.bottom += Context->RowHeight;\n    }\n\n    if (changedStart <= changedEnd)\n    {\n        Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext);\n    }\n\n    if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n    {\n        InvalidateRect(Context->Handle, &rect, FALSE);\n    }\n}\n\n/**\n * Creates a buffered device context and bitmap for double-buffered drawing.\n *\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Hdc Handle to the device context to be buffered.\n */\nVOID PhTnpCreateBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC Hdc\n    )\n{\n    Context->BufferedContext = CreateCompatibleDC(Hdc);\n\n    if (!Context->BufferedContext)\n        return;\n\n    Context->BufferedContextRect = Context->ClientRect;\n    Context->BufferedBitmap = CreateCompatibleBitmap(\n        Hdc,\n        Context->BufferedContextRect.right + 1, // leave one extra pixel for divider animation\n        Context->BufferedContextRect.bottom\n        );\n\n    if (!Context->BufferedBitmap)\n    {\n        DeleteDC(Context->BufferedContext);\n        Context->BufferedContext = NULL;\n        return;\n    }\n\n    Context->BufferedOldBitmap = SelectBitmap(Context->BufferedContext, Context->BufferedBitmap);\n}\n\n/**\n * Destroys the buffered device context and bitmap, cleaning up resources.\n *\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpDestroyBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n)\n{\n    // The original bitmap must be selected back into the context, otherwise the bitmap can't be\n    // deleted.\n\n    if (Context->BufferedOldBitmap)\n    {\n        SelectBitmap(Context->BufferedContext, Context->BufferedOldBitmap);\n        Context->BufferedOldBitmap = NULL;\n    }\n\n    if (Context->BufferedBitmap)\n    {\n        DeleteBitmap(Context->BufferedBitmap);\n        Context->BufferedBitmap = NULL;\n    }\n\n    if (Context->BufferedContext)\n    {\n        DeleteDC(Context->BufferedContext);\n        Context->BufferedContext = NULL;\n    }\n}\n\n/**\n * Sends a message to a TreeNew window, handling custom messages if needed.\n *\n * \\param WindowHandle Handle to the window.\n * \\param WindowMessage Message to send.\n * \\param wParam WPARAM for the message.\n * \\param lParam LPARAM for the message.\n * \\return The result of the message processing.\n */\nLRESULT PhTnSendMessage(\n    _In_ HWND WindowHandle,\n    _In_ ULONG WindowMessage,\n    _Pre_maybenull_ _Post_valid_ WPARAM wParam,\n    _Pre_maybenull_ _Post_valid_ LPARAM lParam\n    )\n{\n    if (WindowMessage >= TNM_FIRST && WindowMessage <= TNM_LAST)\n    {\n#if defined(DEBUG)\n        PPH_TREENEW_CONTEXT context;\n#else\n        PVOID context;\n#endif\n        if (context = PhGetWindowContextEx(WindowHandle))\n        {\n#if defined(DEBUG)\n            assert(context->UniqueThread == NtCurrentThreadId());\n#endif\n            return PhTnpOnUserMessage(WindowHandle, context, WindowMessage, wParam, lParam);\n        }\n    }\n#if defined(DEBUG)\n    assert(FALSE);\n#endif\n    return SendMessage(WindowHandle, WindowMessage, wParam, lParam);\n}\n\n//\n// Drag-reorder\n//\n\n/**\n * Draws the insertion caret for drag-reorder operations.\n *\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param Hdc Handle to the device context to draw on.\n */\nVOID PhTnpDrawInsertionCaret(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC Hdc\n    )\n{\n    RECT r;\n    HPEN old;\n    COLORREF prev;\n\n    r = Context->ReorderInsertRect;\n\n    if (r.right <= r.left || r.bottom <= r.top)\n        return;\n\n    old = SelectPen(Hdc, PhGetStockPen(DC_PEN));\n    prev = SetDCPenColor(Hdc, RGB(0, 120, 215)); // Windows accent blue-ish\n\n    POINT pts[2];\n    pts[0].x = r.left;\n    pts[0].y = (r.top + r.bottom) / 2;\n    pts[1].x = r.right;\n    pts[1].y = pts[0].y;\n    Polyline(Hdc, pts, 2);\n\n    SetDCPenColor(Hdc, prev);\n    if (old) SelectPen(Hdc, old);\n}\n\n/**\n * Invalidates the region occupied by the drag-reorder insertion caret.\n *\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpReorderInvalidateCaret(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (Context->ReorderInsertRect.right > Context->ReorderInsertRect.left &&\n        Context->ReorderInsertRect.bottom > Context->ReorderInsertRect.top)\n    {\n        InvalidateRect(Context->Handle, &Context->ReorderInsertRect, FALSE);\n    }\n}\n\n/**\n * Updates the rectangle for the drag-reorder insertion caret based on the current target index.\n *\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpReorderUpdateCaretRect(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    // Compute y position for insertion caret\n    LONG viewLeft = 0;\n    LONG viewRight = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n    LONG rowYTop = Context->HeaderHeight + ((LONG)Context->ReorderTargetIndex - Context->VScrollPosition) * Context->RowHeight;\n\n    if (Context->ReorderDropAfter)\n    {\n        rowYTop += Context->RowHeight;\n    }\n\n    RECT rect;\n    rect.left   = viewLeft;\n    rect.right  = viewRight;\n    rect.top    = rowYTop - 1;\n    rect.bottom = rowYTop + 1;\n\n    memcpy(&Context->ReorderInsertRect, &rect, sizeof(RECT));\n}\n\n/**\n * Begins a drag-reorder operation.\n *\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param SourceIndex Index of the node being dragged.\n */\nVOID PhTnpReorderBegin(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG SourceIndex\n    )\n{\n    Context->ReorderDragActive  = TRUE;\n    Context->ReorderSourceIndex = SourceIndex;\n    Context->ReorderTargetIndex = SourceIndex;\n    Context->ReorderDropAfter   = FALSE;\n    Context->ReorderJustStarted = TRUE;\n\n    SetCapture(Context->Handle);\n\n    if (!Context->ReorderCursor)\n        Context->ReorderCursor = PhLoadCursor(NULL, IDC_SIZENS);\n}\n\n/**\n * Cancels an active drag-reorder operation and notifies the callback.\n *\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpReorderCancel(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (!Context->ReorderDragActive)\n        return;\n\n    {\n        PH_TREENEW_REORDER_EVENT reorderEvent;\n\n        memset(&reorderEvent, 0, sizeof(PH_TREENEW_REORDER_EVENT));\n        reorderEvent.Source = (Context->ReorderSourceIndex < Context->FlatList->Count) ? (PPH_TREENEW_NODE)Context->FlatList->Items[Context->ReorderSourceIndex] : NULL;\n        reorderEvent.Target = (Context->ReorderTargetIndex < Context->FlatList->Count) ? (PPH_TREENEW_NODE)Context->FlatList->Items[Context->ReorderTargetIndex] : NULL;\n        reorderEvent.DropAfter = Context->ReorderDropAfter;\n\n        Context->Callback(Context->Handle, TreeNewReorderCancel, &reorderEvent, NULL, Context->CallbackContext);\n    }\n\n    PhTnpReorderInvalidateCaret(Context);\n\n    memset(&Context->ReorderInsertRect, 0, sizeof(Context->ReorderInsertRect));\n\n    Context->ReorderDragActive = FALSE;\n\n    ReleaseCapture();\n\n    InvalidateRect(Context->Handle, NULL, FALSE);\n}\n\n/**\n * Commits a drag-reorder operation, notifies the callback, and updates the UI.\n *\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n */\nVOID PhTnpReorderCommit(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    PH_TREENEW_REORDER_EVENT reorderEvent;\n\n    if (!Context->ReorderDragActive)\n        return;\n\n    // No-op if same place\n    //if (Context->ReorderSourceIndex == Context->ReorderTargetIndex &&\n    //    !Context->ReorderDropAfter)\n    //{\n    //    PhTnpReorderCancel(Context);\n    //    return;\n    //}\n\n    memset(&reorderEvent, 0, sizeof(PH_TREENEW_REORDER_EVENT));\n    reorderEvent.Source = (Context->ReorderSourceIndex < Context->FlatList->Count) ? (PPH_TREENEW_NODE)Context->FlatList->Items[Context->ReorderSourceIndex] : NULL;\n    reorderEvent.Target = (Context->ReorderTargetIndex < Context->FlatList->Count) ? (PPH_TREENEW_NODE)Context->FlatList->Items[Context->ReorderTargetIndex] : NULL;\n    reorderEvent.DropAfter = Context->ReorderDropAfter;\n    reorderEvent.Allow = TRUE;\n\n    Context->Callback(Context->Handle, TreeNewReorderCommit, &reorderEvent, NULL, Context->CallbackContext);\n\n    PhTnpReorderInvalidateCaret(Context);\n\n    Context->ReorderInsertRect = (RECT){ 0 };\n    Context->ReorderDragActive = FALSE;\n\n    ReleaseCapture();\n\n    // Parent should reorder underlying data and then trigger TNM_NODESSTRUCTURED\n    InvalidateRect(Context->Handle, NULL, FALSE);\n}\n\n/**\n * Updates the drag-reorder target index and caret based on the current cursor position.\n *\n * \\param Context Pointer to the PPH_TREENEW_CONTEXT structure.\n * \\param CursorX X coordinate of the cursor.\n * \\param CursorY Y coordinate of the cursor.\n */\nVOID PhTnpReorderUpdate(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    LONG y;\n    ULONG idx;\n\n    if (Context->FlatList->Count == 0)\n        return;\n\n    // Update target index and caret based on cursor position\n\n    y = CursorY;\n    if (y < Context->HeaderHeight)\n        y = Context->HeaderHeight;\n\n    idx = (y - Context->HeaderHeight) / Context->RowHeight + Context->VScrollPosition;\n    if (idx >= Context->FlatList->Count)\n        idx = Context->FlatList->Count - 1;\n\n    BOOLEAN dropAfter = FALSE;\n    LONG localYTop = Context->HeaderHeight + ((LONG)idx - Context->VScrollPosition) * Context->RowHeight;\n    LONG mid = localYTop + (Context->RowHeight / 2);\n    if (CursorY >= mid)\n    {\n        dropAfter = TRUE;\n    }\n\n    if (idx != Context->ReorderTargetIndex || dropAfter != Context->ReorderDropAfter)\n    {\n        PH_TREENEW_REORDER_EVENT reorderEvent;\n\n        memset(&reorderEvent, 0, sizeof(PH_TREENEW_REORDER_EVENT));\n        reorderEvent.Source = (Context->ReorderSourceIndex < Context->FlatList->Count) ? (PPH_TREENEW_NODE)Context->FlatList->Items[Context->ReorderSourceIndex] : NULL;\n        reorderEvent.Target = (idx < Context->FlatList->Count) ? (PPH_TREENEW_NODE)Context->FlatList->Items[idx] : NULL;\n        reorderEvent.DropAfter = dropAfter;\n        reorderEvent.Allow = TRUE;\n\n        Context->Callback(Context->Handle, TreeNewReorderOver, &reorderEvent, NULL, Context->CallbackContext);\n\n        if (reorderEvent.Allow)\n        {\n            PhTnpReorderInvalidateCaret(Context);\n            Context->ReorderTargetIndex = idx;\n            Context->ReorderDropAfter   = dropAfter;\n            PhTnpReorderUpdateCaretRect(Context);\n            InvalidateRect(Context->Handle, &Context->ReorderInsertRect, FALSE);\n        }\n    }\n}\n"
  },
  {
    "path": "phlib/util.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *     dmex    2017-2024\n *\n */\n\n#include <ph.h>\n\n#include <commdlg.h>\n#include <d3dkmthk.h>\n#include <ntintsafe.h>\n#include <processsnapshot.h>\n#include <sddl.h>\n#include <shellapi.h>\n#include <shlobj.h>\n#include <winsta.h>\n\n#include <apiimport.h>\n#include <appresolver.h>\n#include <devpkey.h>\n#include <guisup.h>\n#include <mapimg.h>\n#include <mapldr.h>\n#include <lsasup.h>\n#include <phintrin.h>\n#include <wslsup.h>\n#include <thirdparty.h>\n\n#if defined(PH_BUILD_MSIX)\n#include <roapi.h>\n#include <winstring.h>\n#endif\n\nDECLSPEC_SELECTANY CONST WCHAR *PhSizeUnitNames[7] = { L\"B\", L\"kB\", L\"MB\", L\"GB\", L\"TB\", L\"PB\", L\"EB\" };\nDECLSPEC_SELECTANY ULONG PhMaxSizeUnit = ULONG_MAX;\nDECLSPEC_SELECTANY USHORT PhMaxPrecisionUnit = 2;\nDECLSPEC_SELECTANY FLOAT PhMaxPrecisionLimit = 0.01f;\n\n/**\n * Ensures a rectangle is positioned within the specified bounds.\n *\n * \\param Rectangle The rectangle to be adjusted.\n * \\param Bounds The bounds.\n *\n * \\remarks If the rectangle is too large to fit inside the bounds, it is positioned at the top-left\n * of the bounds.\n */\nVOID PhAdjustRectangleToBounds(\n    _Inout_ PPH_RECTANGLE Rectangle,\n    _In_ PPH_RECTANGLE Bounds\n    )\n{\n    if (Rectangle->Left + Rectangle->Width > Bounds->Left + Bounds->Width)\n        Rectangle->Left = Bounds->Left + Bounds->Width - Rectangle->Width;\n    if (Rectangle->Top + Rectangle->Height > Bounds->Top + Bounds->Height)\n        Rectangle->Top = Bounds->Top + Bounds->Height - Rectangle->Height;\n\n    if (Rectangle->Left < Bounds->Left)\n        Rectangle->Left = Bounds->Left;\n    if (Rectangle->Top < Bounds->Top)\n        Rectangle->Top = Bounds->Top;\n\n    if (Rectangle->Width > Bounds->Width)\n        Rectangle->Width = Bounds->Width;\n    if (Rectangle->Height > Bounds->Height)\n        Rectangle->Height = Bounds->Height;\n}\n\n/**\n * Positions a rectangle in the center of the specified bounds.\n *\n * \\param Rectangle The rectangle to be adjusted.\n * \\param Bounds The bounds.\n */\nVOID PhCenterRectangle(\n    _Inout_ PPH_RECTANGLE Rectangle,\n    _In_ PPH_RECTANGLE Bounds\n    )\n{\n    Rectangle->Left = Bounds->Left + (Bounds->Width - Rectangle->Width) / 2;\n    Rectangle->Top = Bounds->Top + (Bounds->Height - Rectangle->Height) / 2;\n}\n\n/**\n * Ensures a rectangle is positioned within the working area of the specified window's monitor.\n *\n * \\param WindowHandle A handle to a window. If NULL, the monitor closest to \\a Rectangle is used.\n * \\param Rectangle The rectangle to be adjusted.\n */\nVOID PhAdjustRectangleToWorkingArea(\n    _In_opt_ HWND WindowHandle,\n    _Inout_ PPH_RECTANGLE Rectangle\n    )\n{\n    HMONITOR monitor;\n    MONITORINFO monitorInfo;\n\n    if (WindowHandle)\n    {\n        monitor = MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTONEAREST);\n    }\n    else\n    {\n        RECT rect = { 0 };\n\n        PhRectangleToRect(&rect, Rectangle);\n        monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);\n    }\n\n    RtlZeroMemory(&monitorInfo, sizeof(MONITORINFO));\n    monitorInfo.cbSize = sizeof(MONITORINFO);\n\n    if (GetMonitorInfo(monitor, &monitorInfo))\n    {\n        PH_RECTANGLE bounds = { 0 };\n\n        PhRectToRectangle(&bounds, &monitorInfo.rcWork);\n        PhAdjustRectangleToBounds(Rectangle, &bounds);\n    }\n}\n\n/**\n * Centers a window.\n *\n * \\param WindowHandle The window to center.\n * \\param ParentWindowHandle If specified, the window will be positioned at the center of this\n * window. Otherwise, the window will be positioned at the center of the monitor.\n */\nVOID PhCenterWindow(\n    _In_ HWND WindowHandle,\n    _In_opt_ HWND ParentWindowHandle\n    )\n{\n    if (ParentWindowHandle)\n    {\n        RECT rect, parentRect;\n        PH_RECTANGLE rectangle = { 0 };\n        PH_RECTANGLE parentRectangle = { 0 };\n\n        if (!IsWindowVisible(ParentWindowHandle) || IsMinimized(ParentWindowHandle))\n            return;\n        if (!PhGetWindowRect(WindowHandle, &rect))\n            return;\n        if (!PhGetWindowRect(ParentWindowHandle, &parentRect))\n            return;\n\n        PhRectToRectangle(&rectangle, &rect);\n        PhRectToRectangle(&parentRectangle, &parentRect);\n        PhCenterRectangle(&rectangle, &parentRectangle);\n        PhAdjustRectangleToWorkingArea(WindowHandle, &rectangle);\n\n        MoveWindow(WindowHandle, rectangle.Left, rectangle.Top,\n            rectangle.Width, rectangle.Height, FALSE);\n    }\n    else\n    {\n        MONITORINFO monitorInfo;\n\n        RtlZeroMemory(&monitorInfo, sizeof(MONITORINFO));\n        monitorInfo.cbSize = sizeof(MONITORINFO);\n\n        if (GetMonitorInfo(\n            MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTONEAREST),\n            &monitorInfo\n            ))\n        {\n            RECT rect;\n            PH_RECTANGLE rectangle = { 0 };;\n            PH_RECTANGLE bounds = { 0 };;\n\n            if (!PhGetWindowRect(WindowHandle, &rect))\n                return;\n\n            PhRectToRectangle(&rectangle, &rect);\n            PhRectToRectangle(&bounds, &monitorInfo.rcWork);\n            PhCenterRectangle(&rectangle, &bounds);\n\n            MoveWindow(WindowHandle, rectangle.Left, rectangle.Top,\n                rectangle.Width, rectangle.Height, FALSE);\n        }\n    }\n}\n\n/**\n * Moves a window to the specified monitor.\n *\n * \\param WindowHandle The window to move.\n * \\param MonitorHandle The monitor to move the window to.\n * \\return Successful or errant status.\n */\nNTSTATUS PhMoveWindowToMonitor(\n    _In_ HWND WindowHandle,\n    _In_ HMONITOR MonitorHandle\n    )\n{\n    MONITORINFO currentMonitorInfo;\n    MONITORINFO targetMonitorInfo;\n    PH_RECTANGLE rectangle = { 0 };\n    PH_RECTANGLE bounds = { 0 };\n    HMONITOR monitor;\n    RECT windowRect;\n    RECT targetRect;\n\n    // Get window position\n\n    if (!PhGetWindowRect(WindowHandle, &windowRect))\n        return PhGetLastWin32ErrorAsNtStatus();\n\n    // Get current monitor\n\n    memset(&currentMonitorInfo, 0, sizeof(MONITORINFO));\n    currentMonitorInfo.cbSize = sizeof(currentMonitorInfo);\n\n    monitor = MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTONEAREST);\n\n    if (!GetMonitorInfo(monitor, &currentMonitorInfo))\n        return PhGetLastWin32ErrorAsNtStatus();\n\n    // Get target monitor\n\n    memset(&targetMonitorInfo, 0, sizeof(MONITORINFO));\n    targetMonitorInfo.cbSize = sizeof(targetMonitorInfo);\n\n    if (!GetMonitorInfo(MonitorHandle, &targetMonitorInfo))\n        return PhGetLastWin32ErrorAsNtStatus();\n\n    // Calculate relative position\n\n    RECT currentMonitorRect = currentMonitorInfo.rcMonitor;\n    LONG left = windowRect.left - currentMonitorRect.left;\n    LONG top = windowRect.top - currentMonitorRect.top;\n    LONG width = windowRect.right - windowRect.left;\n    LONG height = windowRect.bottom - windowRect.top;\n\n    targetRect.left = targetMonitorInfo.rcMonitor.left + left;\n    targetRect.top = targetMonitorInfo.rcMonitor.top + top;\n    targetRect.right = targetRect.left + width;\n    targetRect.bottom = targetRect.top + height;\n\n    // Adjust relative position\n\n    PhRectToRectangle(&rectangle, &targetRect);\n    PhRectToRectangle(&bounds, &targetMonitorInfo.rcWork);\n    PhAdjustRectangleToBounds(&rectangle, &bounds);\n\n    MoveWindow(WindowHandle, rectangle.Left, rectangle.Top,\n        rectangle.Width, rectangle.Height, TRUE);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Retrieves the system default locale identifier.\n * \\return The system default locale identifier.\n */\nLCID PhGetSystemDefaultLCID(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_LOCALE)\n    return GetSystemDefaultLCID();\n#else\n    LCID localeId = LOCALE_SYSTEM_DEFAULT;\n\n    // rev from GetSystemDefaultLCID (dmex)\n\n    if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &localeId)))\n        return localeId;\n\n    return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);\n#endif\n}\n\n/**\n * Retrieves the user default locale identifier.\n * \\return The user default locale identifier.\n */\nLCID PhGetUserDefaultLCID(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_LOCALE)\n    return GetUserDefaultLCID();\n#else\n    LCID localeId = LOCALE_USER_DEFAULT;\n\n    // rev from GetUserDefaultLCID (dmex)\n\n    if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &localeId)))\n        return localeId;\n\n    return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);\n#endif\n}\n\n/**\n * Retrieves a boolean value from the user locale information.\n *\n * \\param LCType The type of locale information to retrieve.\n * \\return TRUE if the value is '1', otherwise FALSE.\n */\nBOOLEAN PhGetUserLocaleInfoBool(\n    _In_ LCTYPE LCType\n    )\n{\n    WCHAR value[4];\n\n    if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LCType, value, 4))\n    {\n        if (value[0] == L'1')\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Retrieves the locale identifier for the current thread.\n * \\return The locale identifier for the current thread.\n */\nLCID PhGetCurrentThreadLCID(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_LOCALE)\n    return GetThreadLocale();\n#else\n    PTEB currentTeb;\n\n    // rev from GetThreadLocale (dmex)\n\n    currentTeb = NtCurrentTeb();\n\n    if (!currentTeb->CurrentLocale)\n        currentTeb->CurrentLocale = PhGetUserDefaultLCID();\n    if (currentTeb->CurrentLocale == LOCALE_CUSTOM_DEFAULT)\n        currentTeb->CurrentLocale = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);\n    if (currentTeb->CurrentLocale == LOCALE_CUSTOM_UNSPECIFIED)\n        currentTeb->CurrentLocale = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);\n\n    return currentTeb->CurrentLocale;\n#endif\n}\n\n/**\n * Retrieves the system default language identifier.\n * \\return The system default language identifier.\n */\nLANGID PhGetSystemDefaultLangID(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_LOCALE)\n    return GetSystemDefaultLangID();\n#else\n    // rev from GetSystemDefaultLangID (dmex)\n\n    return LANGIDFROMLCID(PhGetSystemDefaultLCID());\n#endif\n}\n\n/**\n * Retrieves the user default language identifier.\n * \\return The user default language identifier.\n */\nLANGID PhGetUserDefaultLangID(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_LOCALE)\n    return GetUserDefaultLangID();\n#else\n    // rev from GetUserDefaultLangID (dmex)\n\n    return LANGIDFROMLCID(PhGetUserDefaultLCID());\n#endif\n}\n\n/**\n * Retrieves the user default UI language identifier.\n * \\return The user default UI language identifier.\n */\nLANGID PhGetUserDefaultUILanguage(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_LOCALE)\n    return GetUserDefaultUILanguage();\n#else\n    LANGID languageId;\n\n    // rev from GetUserDefaultUILanguage (dmex)\n\n    if (NT_SUCCESS(NtQueryDefaultUILanguage(&languageId)))\n        return languageId;\n    if (NT_SUCCESS(NtQueryInstallUILanguage(&languageId)))\n        return languageId;\n\n    return MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);\n#endif\n}\n\n/**\n * Retrieves the user default locale name.\n * \\return A string containing the user default locale name.\n */\nPPH_STRING PhGetUserDefaultLocaleName(\n    VOID\n    )\n{\n#if defined(PHNT_NATIVE_LOCALE)\n    ULONG localNameLength;\n    WCHAR localeName[LOCALE_NAME_MAX_LENGTH] = { UNICODE_NULL };\n\n    localNameLength = GetUserDefaultLocaleName(localeName, RTL_NUMBER_OF(localeName));\n\n    if (localNameLength > sizeof(UNICODE_NULL))\n    {\n        return PhCreateStringEx(localeName, localNameLength - sizeof(UNICODE_NULL));\n    }\n#else\n    UNICODE_STRING localeNameUs;\n    WCHAR localeName[LOCALE_NAME_MAX_LENGTH] = { UNICODE_NULL };\n\n    // rev from GetUserDefaultLocaleName (dmex)\n\n    RtlInitEmptyUnicodeString(&localeNameUs, localeName, sizeof(localeName));\n\n    if (NT_SUCCESS(RtlLcidToLocaleName(PhGetUserDefaultLCID(), &localeNameUs, 0, FALSE)))\n    {\n        return PhCreateStringFromUnicodeString(&localeNameUs);\n    }\n#endif\n\n    return NULL;\n}\n\n/**\n * Converts a locale identifier to a locale name.\n *\n * \\param lcid The locale identifier.\n * \\return A string containing the locale name.\n */\nPPH_STRING PhLCIDToLocaleName(\n    _In_ LCID lcid\n    )\n{\n#if defined(PHNT_NATIVE_LOCALE)\n    ULONG localNameLength;\n    WCHAR localeName[LOCALE_NAME_MAX_LENGTH] = { UNICODE_NULL };\n\n    localNameLength = LCIDToLocaleName(lcid, localeName, RTL_NUMBER_OF(localeName), 0);\n\n    if (localNameLength > sizeof(UNICODE_NULL))\n    {\n        return PhCreateStringEx(localeName, localNameLength - sizeof(UNICODE_NULL));\n    }\n#else\n    UNICODE_STRING localeNameUs;\n    WCHAR localeName[LOCALE_NAME_MAX_LENGTH] = { UNICODE_NULL };\n\n    // rev from LCIDToLocaleName (dmex)\n\n    RtlInitEmptyUnicodeString(&localeNameUs, localeName, sizeof(localeName));\n\n    if (lcid)\n    {\n        if (NT_SUCCESS(RtlLcidToLocaleName(lcid, &localeNameUs, 0, FALSE)))\n        {\n            return PhCreateStringFromUnicodeString(&localeNameUs);\n        }\n    }\n    else // Return the current user locale when zero is specified.\n    {\n        if (NT_SUCCESS(RtlLcidToLocaleName(PhGetUserDefaultLCID(), &localeNameUs, 0, FALSE)))\n        {\n            return PhCreateStringFromUnicodeString(&localeNameUs);\n        }\n    }\n#endif\n\n    return NULL;\n}\n\n/**\n * Converts a LARGE_INTEGER time value to a SYSTEMTIME structure.\n *\n * \\param SystemTime The destination SYSTEMTIME structure.\n * \\param LargeInteger The source LARGE_INTEGER time value.\n */\nVOID PhLargeIntegerToSystemTime(\n    _Out_ PSYSTEMTIME SystemTime,\n    _In_ PLARGE_INTEGER LargeInteger\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n    FILETIME fileTime;\n\n    fileTime.dwLowDateTime = LargeInteger->LowPart;\n    fileTime.dwHighDateTime = LargeInteger->HighPart;\n    FileTimeToSystemTime(&fileTime, SystemTime);\n#else\n    TIME_FIELDS timeFields;\n\n    RtlZeroMemory(&timeFields, sizeof(TIME_FIELDS));\n\n    RtlTimeToTimeFields(LargeInteger, &timeFields);\n    SystemTime->wYear = timeFields.Year;\n    SystemTime->wMonth = timeFields.Month;\n    SystemTime->wDay = timeFields.Day;\n    SystemTime->wHour = timeFields.Hour;\n    SystemTime->wMinute = timeFields.Minute;\n    SystemTime->wSecond = timeFields.Second;\n    SystemTime->wMilliseconds = timeFields.Milliseconds;\n    SystemTime->wDayOfWeek = timeFields.Weekday;\n#endif\n}\n\nBOOLEAN PhSystemTimeToLargeInteger(\n    _Out_ PLARGE_INTEGER LargeInteger,\n    _In_ PSYSTEMTIME SystemTime\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n    FILETIME fileTime;\n\n    if (!SystemTimeToFileTime(SystemTime, &fileTime))\n        return FALSE;\n\n    LargeInteger->LowPart = fileTime.dwLowDateTime;\n    LargeInteger->HighPart = fileTime.dwHighDateTime;\n    return TRUE;\n#else\n    TIME_FIELDS timeFields;\n\n    RtlZeroMemory(&timeFields, sizeof(TIME_FIELDS));\n\n    timeFields.Year = SystemTime->wYear;\n    timeFields.Month = SystemTime->wMonth;\n    timeFields.Day = SystemTime->wDay;\n    timeFields.Hour = SystemTime->wHour;\n    timeFields.Minute = SystemTime->wMinute;\n    timeFields.Second = SystemTime->wSecond;\n    timeFields.Milliseconds = SystemTime->wMilliseconds;\n    timeFields.Weekday = SystemTime->wDayOfWeek;\n\n    return RtlTimeFieldsToTime(&timeFields, LargeInteger);\n#endif\n}\n\nVOID PhLargeIntegerToLocalSystemTime(\n    _Out_ PSYSTEMTIME SystemTime,\n    _In_ PLARGE_INTEGER LargeInteger\n    )\n{\n#if defined(PHNT_NATIVE_TIME)\n    FILETIME fileTime;\n    FILETIME newFileTime;\n\n    fileTime.dwLowDateTime = LargeInteger->LowPart;\n    fileTime.dwHighDateTime = LargeInteger->HighPart;\n\n    FileTimeToLocalFileTime(&fileTime, &newFileTime);\n    FileTimeToSystemTime(&newFileTime, SystemTime);\n#else\n    LARGE_INTEGER timeZoneBias;\n    LARGE_INTEGER fileTime;\n\n    PhQueryTimeZoneBias(&timeZoneBias);\n\n    fileTime.LowPart = LargeInteger->LowPart;\n    fileTime.HighPart = LargeInteger->HighPart;\n    fileTime.QuadPart -= timeZoneBias.QuadPart;\n    PhLargeIntegerToSystemTime(SystemTime, &fileTime);\n#endif\n}\n\nBOOLEAN PhLocalSystemTimeToLargeInteger(\n    _Out_ PLARGE_INTEGER LargeInteger,\n    _In_ PSYSTEMTIME SystemTime\n    )\n{\n    LARGE_INTEGER timeZoneBias;\n\n    if (!PhSystemTimeToLargeInteger(LargeInteger, SystemTime))\n        return FALSE;\n\n    PhQueryTimeZoneBias(&timeZoneBias);\n    LargeInteger->QuadPart += timeZoneBias.QuadPart;\n\n    return TRUE;\n}\n\nBOOLEAN PhSystemTimeToTzSpecificLocalTime(\n    _In_ CONST SYSTEMTIME* UniversalTime,\n    _Out_ PSYSTEMTIME LocalTime\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&SystemTimeToTzSpecificLocalTimeEx) SystemTimeToTzSpecificLocalTimeEx_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        SystemTimeToTzSpecificLocalTimeEx_I = PhGetDllProcedureAddressZ(L\"kernel32.dll\", \"SystemTimeToTzSpecificLocalTimeEx\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    memset(LocalTime, 0, sizeof(SYSTEMTIME));\n\n    if (SystemTimeToTzSpecificLocalTimeEx_I)\n    {\n        return !!SystemTimeToTzSpecificLocalTimeEx_I(NULL, UniversalTime, LocalTime);\n    }\n\n    return !!SystemTimeToTzSpecificLocalTime(NULL, UniversalTime, LocalTime);\n}\n\n/**\n * Gets a string stored in a DLL's message table.\n *\n * \\param DllHandle The base address of the DLL.\n * \\param MessageTableId The identifier of the message table.\n * \\param MessageLanguageId The language ID of the message.\n * \\param MessageId The identifier of the message.\n *\n * \\return A pointer to a string containing the message. You must free the string using\n * PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhGetMessage(\n    _In_ PVOID DllHandle,\n    _In_ ULONG MessageTableId,\n    _In_ ULONG MessageLanguageId,\n    _In_ ULONG MessageId\n    )\n{\n    NTSTATUS status;\n    PMESSAGE_RESOURCE_ENTRY messageEntry;\n\n    status = RtlFindMessage(\n        DllHandle,\n        MessageTableId,\n        MessageLanguageId,\n        MessageId,\n        &messageEntry\n        );\n\n    // Try using the system LANGID.\n    if (!NT_SUCCESS(status))\n    {\n        status = RtlFindMessage(\n            DllHandle,\n            MessageTableId,\n            PhGetSystemDefaultLangID(),\n            MessageId,\n            &messageEntry\n            );\n    }\n\n    // Try using U.S. English.\n    if (!NT_SUCCESS(status))\n    {\n        status = RtlFindMessage(\n            DllHandle,\n            MessageTableId,\n            MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),\n            MessageId,\n            &messageEntry\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    // dmex: We don't support parsing insert sequences.\n    if (messageEntry->Text[0] == L'%')\n        return NULL;\n\n    if (messageEntry->Flags & MESSAGE_RESOURCE_UNICODE)\n        return PhCreateStringEx((PWCHAR)messageEntry->Text, messageEntry->Length);\n    else if (messageEntry->Flags & MESSAGE_RESOURCE_UTF8)\n        return PhConvertUtf8ToUtf16Ex((PCHAR)messageEntry->Text, messageEntry->Length);\n    else\n        return PhConvertMultiByteToUtf16Ex((PCHAR)messageEntry->Text, messageEntry->Length);\n}\n\n/**\n * Gets a message describing a NT status value.\n *\n * \\param Status The NT status value.\n */\nPPH_STRING PhGetNtMessage(\n    _In_ NTSTATUS Status\n    )\n{\n    PPH_STRING message;\n\n    if (NT_CUSTOMER(Status))\n        message = PhGetMessage(PhGetLoaderEntryDllBase(NULL, NULL), 0xb, PhGetUserDefaultLangID(), (ULONG)Status);\n    else if (!NT_NTWIN32(Status))\n        message = PhGetMessage(PhGetLoaderEntryDllBaseZ(L\"ntdll.dll\"), 0xb, PhGetUserDefaultLangID(), (ULONG)Status);\n    else\n        message = PhGetWin32Message(PhNtStatusToDosError(Status));\n\n    if (PhIsNullOrEmptyString(message))\n        return message;\n\n    PhTrimToNullTerminatorString(message);\n\n    // Remove any trailing newline.\n    if (message->Length >= 2 * sizeof(WCHAR) &&\n        message->Buffer[message->Length / sizeof(WCHAR) - 2] == L'\\r' &&\n        message->Buffer[message->Length / sizeof(WCHAR) - 1] == L'\\n')\n    {\n        PhMoveReference(&message, PhCreateStringEx(message->Buffer, message->Length - 2 * sizeof(WCHAR)));\n    }\n\n    // Fix those messages which are formatted like:\n    // {Asdf}\\r\\nAsdf asdf asdf...\n    if (message->Buffer[0] == L'{')\n    {\n        PH_STRINGREF titlePart;\n        PH_STRINGREF remainingPart;\n\n        if (PhSplitStringRefAtChar(&message->sr, L'\\n', &titlePart, &remainingPart))\n            PhMoveReference(&message, PhCreateString2(&remainingPart));\n    }\n\n    return message;\n}\n\n/**\n * Gets a message describing a Win32 error code.\n *\n * \\param Result The Win32 error code.\n */\nPPH_STRING PhGetWin32Message(\n    _In_ ULONG Result\n    )\n{\n    PPH_STRING message;\n\n    message = PhGetMessage(PhGetLoaderEntryDllBaseZ(L\"kernel32.dll\"), 0xb, PhGetUserDefaultLangID(), Result);\n\n    if (message)\n    {\n        PhTrimToNullTerminatorString(message);\n\n        // Remove any trailing newline.\n        if (message && message->Length >= 2 * sizeof(WCHAR) &&\n            message->Buffer[message->Length / sizeof(WCHAR) - 2] == L'\\r' &&\n            message->Buffer[message->Length / sizeof(WCHAR) - 1] == L'\\n')\n        {\n            PhMoveReference(&message, PhCreateStringEx(message->Buffer, message->Length - 2 * sizeof(WCHAR)));\n        }\n    }\n    else\n    {\n        message = PhGetWin32FormatMessage(Result);\n    }\n\n    return message;\n}\n\nPPH_STRING PhGetWin32FormatMessage(\n    _In_ ULONG Result\n    )\n{\n    PPH_STRING messageString = NULL;\n    ULONG messageLength = 0;\n    PWSTR messageBuffer = NULL;\n\n    messageLength = FormatMessage(\n        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,\n        NULL,\n        Result,\n        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\n        (PWSTR)&messageBuffer,\n        0,\n        NULL\n        );\n\n    if (messageBuffer)\n    {\n        if (messageLength)\n        {\n            ULONG_PTR index;\n            PH_STRINGREF string;\n\n            string.Buffer = messageBuffer;\n            string.Length = messageLength * sizeof(WCHAR);\n\n            if ((index = PhFindStringInStringRefZ(&string, L\"\\r\\n\", FALSE)) != SIZE_MAX)\n                messageString = PhCreateStringEx(messageBuffer, index * sizeof(WCHAR));\n            else\n                messageString = PhCreateStringEx(messageBuffer, messageLength * sizeof(WCHAR));\n        }\n\n        LocalFree(messageBuffer);\n    }\n\n    return messageString;\n}\n\nPPH_STRING PhGetNtFormatMessage(\n    _In_ NTSTATUS Status\n    )\n{\n    PPH_STRING messageString = NULL;\n    ULONG messageLength = 0;\n    PWSTR messageBuffer = NULL;\n\n    messageLength = FormatMessage(\n        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM,\n        PhGetLoaderEntryDllBaseZ(RtlNtdllName),\n        Status,\n        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\n        (PWSTR)&messageBuffer,\n        0,\n        NULL\n        );\n\n    if (messageBuffer)\n    {\n        if (messageLength)\n        {\n            ULONG_PTR index;\n            PH_STRINGREF string;\n\n            string.Buffer = messageBuffer;\n            string.Length = messageLength * sizeof(WCHAR);\n\n            if ((index = PhFindStringInStringRefZ(&string, L\"\\r\\n\", FALSE)) != SIZE_MAX)\n                messageString = PhCreateStringEx(messageBuffer, index * sizeof(WCHAR));\n            else\n                messageString = PhCreateStringEx(messageBuffer, messageLength * sizeof(WCHAR));\n        }\n\n        LocalFree(messageBuffer);\n    }\n\n    return messageString;\n}\n\n/**\n * Displays a message box.\n *\n * \\param WindowHandle The owner window of the message box.\n * \\param Type The type of message box to display.\n * \\param Format A format string.\n * \\return The user's response.\n */\nLONG PhShowMessage(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Type,\n    _In_ PCWSTR Format,\n    ...\n    )\n{\n    LONG result;\n    va_list argptr;\n    PPH_STRING message;\n\n    va_start(argptr, Format);\n    message = PhFormatString_V(Format, argptr);\n    va_end(argptr);\n\n    if (!message)\n        return INT_ERROR;\n\n    result = MessageBox(WindowHandle, message->Buffer, PhApplicationName, Type);\n    PhDereferenceObject(message);\n\n    return result;\n}\n\nstatic const PH_FLAG_MAPPING PhShowMessageTaskDialogButtonFlagMappings[] =\n{\n    { TD_OK_BUTTON, TDCBF_OK_BUTTON },\n    { TD_YES_BUTTON, TDCBF_YES_BUTTON },\n    { TD_NO_BUTTON, TDCBF_NO_BUTTON },\n    { TD_CANCEL_BUTTON, TDCBF_CANCEL_BUTTON },\n    { TD_RETRY_BUTTON, TDCBF_RETRY_BUTTON },\n    { TD_CLOSE_BUTTON, TDCBF_CLOSE_BUTTON },\n};\n\nLONG PhShowMessage2(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    )\n{\n    ULONG result;\n    va_list argptr;\n    PPH_STRING message;\n    TASKDIALOGCONFIG config;\n    ULONG buttonsFlags;\n\n    va_start(argptr, Format);\n    message = PhFormatString_V(Format, argptr);\n    va_end(argptr);\n\n    if (!message)\n        return INT_ERROR;\n\n    buttonsFlags = 0;\n    PhMapFlags1(\n        &buttonsFlags,\n        Buttons,\n        PhShowMessageTaskDialogButtonFlagMappings,\n        ARRAYSIZE(PhShowMessageTaskDialogButtonFlagMappings)\n        );\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | ((WindowHandle && IsWindowVisible(WindowHandle) && !IsMinimized(WindowHandle)) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0);\n    config.dwCommonButtons = buttonsFlags;\n    config.hwndParent = WindowHandle;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainIcon = Icon;\n    config.pszMainInstruction = Title;\n    config.pszContent = message->Buffer;\n\n    if (PhShowTaskDialog(\n        &config,\n        &result,\n        NULL,\n        NULL\n        ))\n    {\n        PhDereferenceObject(message);\n        return result;\n    }\n    else\n    {\n        PhDereferenceObject(message);\n        return INT_ERROR;\n    }\n}\n\n/**\n * Internal worker for displaying a message with a \"Don't show this message again\" checkbox.\n *\n * \\param WindowHandle The owner window.\n * \\param Buttons The buttons to display.\n * \\param Icon The icon to display.\n * \\param Title The title of the message.\n * \\param Result Receives the selected button.\n * \\param Checked Receives the state of the checkbox.\n * \\param Format The format string.\n * \\param ArgPtr The argument list.\n * \\return TRUE if the dialog was shown, otherwise FALSE.\n */\nBOOLEAN PhpShowMessageOneTime(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ PCWSTR Title,\n    _Out_opt_ PLONG Result,\n    _Out_opt_ PBOOLEAN Checked,\n    _In_ PCWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    ULONG result;\n    PPH_STRING message;\n    TASKDIALOGCONFIG config;\n    BOOLEAN checked = FALSE;\n    ULONG buttonsFlags;\n\n    if (Result)\n        *Result = INT_ERROR;\n\n    if (Checked)\n        *Checked = FALSE;\n\n    message = PhFormatString_V(Format, ArgPtr);\n\n    if (!message)\n        return FALSE;\n\n    buttonsFlags = 0;\n    PhMapFlags1(\n        &buttonsFlags,\n        Buttons,\n        PhShowMessageTaskDialogButtonFlagMappings,\n        ARRAYSIZE(PhShowMessageTaskDialogButtonFlagMappings)\n        );\n\n    memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n    config.cbSize = sizeof(TASKDIALOGCONFIG);\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | ((WindowHandle && IsWindowVisible(WindowHandle) && !IsMinimized(WindowHandle)) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0);\n    config.dwCommonButtons = buttonsFlags;\n    config.hwndParent = WindowHandle;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainIcon = Icon;\n    config.pszMainInstruction = Title;\n    config.pszContent = PhGetString(message);\n    config.pszVerificationText = L\"Don't show this message again\";\n    config.cxWidth = 200;\n\n    if (PhShowTaskDialog(\n        &config,\n        &result,\n        NULL,\n        &checked\n        ))\n    {\n        PhDereferenceObject(message);\n\n        if (Result)\n            *Result = result;\n\n        if (Checked)\n            *Checked = !!checked;\n\n        return TRUE;\n    }\n    else\n    {\n        PhDereferenceObject(message);\n        return FALSE;\n    }\n}\n\n/**\n * Displays a message with a \"Don't show this message again\" checkbox.\n *\n * \\param WindowHandle The owner window.\n * \\param Buttons The buttons to display.\n * \\param Icon The icon to display.\n * \\param Title The title of the message.\n * \\param Format The format string.\n * \\return TRUE if the checkbox was checked, otherwise FALSE.\n */\nBOOLEAN PhShowMessageOneTime(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ PCWSTR Title,\n    _In_ PCWSTR Format,\n    ...\n    )\n{\n    BOOLEAN checked;\n    va_list argptr;\n\n    va_start(argptr, Format);\n    PhpShowMessageOneTime(WindowHandle, Buttons, Icon, Title, NULL, &checked, Format, argptr);\n    va_end(argptr);\n\n    return checked;\n}\n\n/**\n * Displays a message with a \"Don't show this message again\" checkbox.\n *\n * \\param WindowHandle The owner window.\n * \\param Buttons The buttons to display.\n * \\param Icon The icon to display.\n * \\param Title The title of the message.\n * \\param Checked Receives the state of the checkbox.\n * \\param Format The format string.\n * \\return The selected button.\n */\nLONG PhShowMessageOneTime2(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG Buttons,\n    _In_opt_ PCWSTR Icon,\n    _In_opt_ PCWSTR Title,\n    _Out_opt_ PBOOLEAN Checked,\n    _In_ PCWSTR Format,\n    ...\n    )\n{\n    LONG result;\n    va_list argptr;\n\n    va_start(argptr, Format);\n    PhpShowMessageOneTime(WindowHandle, Buttons, Icon, Title, &result, Checked, Format, argptr);\n    va_end(argptr);\n\n    return result;\n}\n\n/**\n * Displays a task dialog.\n *\n * \\param Config The task dialog configuration.\n * \\param Button Receives the selected button.\n * \\param RadioButton Receives the selected radio button.\n * \\param FlagChecked Receives the state of the verification checkbox.\n * \\return TRUE if the task dialog was shown, otherwise FALSE.\n */\n_Success_(return)\nBOOLEAN PhShowTaskDialog(\n    _In_ PTASKDIALOGCONFIG Config,\n    _Out_opt_ PULONG Button,\n    _Out_opt_ PULONG RadioButton,\n    _Out_opt_ PBOOLEAN FlagChecked\n    )\n{\n    HRESULT status;\n    LONG button;\n    LONG radio;\n    BOOL selected;\n\n    status = TaskDialogIndirect(\n        Config,\n        &button,\n        &radio,\n        &selected\n        );\n\n    if (HR_SUCCESS(status))\n    {\n        if (Button) *Button = button;\n        if (RadioButton) *RadioButton = radio;\n        if (FlagChecked) *FlagChecked = !!selected;\n        return TRUE;\n    }\n\n    return FALSE; // PhDosErrorToNtStatus(HRESULT_CODE(status));\n}\n\n/**\n * Retrieves a status message for a NTSTATUS value or Win32 error code.\n *\n * \\param Status A NTSTATUS value.\n * \\param Win32Result A Win32 error code, or 0 to derive it from the status.\n * \\return A string containing the status message.\n */\nPPH_STRING PhGetStatusMessage(\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    if (!Win32Result)\n    {\n        // In some cases we want the simple Win32 messages.\n        if (\n            Status == STATUS_ACCESS_DENIED ||\n            Status == STATUS_ACCESS_VIOLATION ||\n            Status == STATUS_NO_SUCH_FILE\n            )\n        {\n            Win32Result = RtlNtStatusToDosErrorNoTeb(Status);\n        }\n        // Process NTSTATUS values with the NT-Win32 facility.\n        else if (NT_NTWIN32(Status))\n        {\n            Win32Result = WIN32_FROM_NTSTATUS(Status);\n        }\n        else if (NT_FACILITY(Status) == FACILTIY_MUI_ERROR_CODE)\n        {\n            Win32Result = Status; // needed by PhGetLastWin32ErrorAsNtStatus(CERT_E_REVOKED) (dmex)\n        }\n    }\n\n    if (Win32Result)\n        return PhGetWin32Message(Win32Result);\n    else\n        return PhGetNtMessage(Status);\n}\n\n/**\n * Displays an error message for a NTSTATUS value or Win32 error code.\n *\n * \\param WindowHandle The owner window of the message box.\n * \\param Message A message describing the operation that failed.\n * \\param Status A NTSTATUS value, or 0 if there is none.\n * \\param Win32Result A Win32 error code, or 0 if there is none.\n */\nVOID PhShowStatus(\n    _In_opt_ HWND WindowHandle,\n    _In_opt_ PCWSTR Message,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    PPH_STRING statusMessage;\n\n    if (statusMessage = PhGetStatusMessage(Status, Win32Result))\n    {\n        if (Message)\n            PhShowError2(WindowHandle, Message, L\"%s\", PhGetString(statusMessage));\n        else\n            PhShowError2(WindowHandle, L\"Unable to perform the operation.\", L\"%s\", PhGetString(statusMessage));\n\n        PhDereferenceObject(statusMessage);\n    }\n    else\n    {\n        if (Message)\n            PhShowError2(WindowHandle, L\"Unable to perform the operation.\", L\"%s\", Message);\n        else\n            PhShowStatus(WindowHandle, L\"Unable to perform the operation.\", STATUS_UNSUCCESSFUL, 0);\n    }\n}\n\n/**\n * Displays an error message for a NTSTATUS value or Win32 error code, and allows the user to cancel\n * the current operation.\n *\n * \\param WindowHandle The owner window of the message box.\n * \\param Message A message describing the operation that failed.\n * \\param Status A NTSTATUS value, or 0 if there is none.\n * \\param Win32Result A Win32 error code, or 0 if there is none.\n * \\return TRUE if the user wishes to continue with the current operation, otherwise FALSE.\n */\nBOOLEAN PhShowContinueStatus(\n    _In_ HWND WindowHandle,\n    _In_opt_ PCWSTR Message,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    PPH_STRING statusMessage;\n    LONG result;\n\n    statusMessage = PhGetStatusMessage(Status, Win32Result);\n\n    if (Message && statusMessage)\n        result = PhShowMessage2(WindowHandle, TD_OK_BUTTON | TD_CLOSE_BUTTON, TD_ERROR_ICON, Message, L\"%s\", PhGetString(statusMessage));\n    else if (Message)\n        result = PhShowMessage2(WindowHandle, TD_OK_BUTTON | TD_CANCEL_BUTTON, TD_ERROR_ICON, L\"Unable to perform the operation.\", L\"%s\", Message);\n    else if (statusMessage)\n        result = PhShowMessage2(WindowHandle, TD_OK_BUTTON | TD_CANCEL_BUTTON, TD_ERROR_ICON, L\"Unable to perform the operation.\", L\"%s\", PhGetString(statusMessage));\n    else\n        result = PhShowMessage2(WindowHandle, TD_OK_BUTTON | TD_CANCEL_BUTTON, TD_ERROR_ICON, L\"Unable to perform the operation.\", L\"\");\n\n    if (statusMessage) PhDereferenceObject(statusMessage);\n\n    return result == IDOK;\n}\n\n/**\n * Displays a confirmation message.\n *\n * \\param WindowHandle The owner window of the message box.\n * \\param Verb A verb describing the operation, e.g. \"terminate\".\n * \\param Object The object of the operation, e.g. \"the process\".\n * \\param Message A message describing the operation.\n * \\param Warning TRUE to display the confirmation message as a warning, otherwise FALSE.\n * \\return TRUE if the user wishes to continue, otherwise FALSE.\n */\nBOOLEAN PhShowConfirmMessage(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR Verb,\n    _In_ PCWSTR Object,\n    _In_opt_ PCWSTR Message,\n    _In_ BOOLEAN Warning\n    )\n{\n    PPH_STRING verb;\n    PPH_STRING verbCaps;\n    PPH_STRING action;\n\n    // Make sure the verb is all lowercase.\n    verb = PhaLowerString(PhaCreateString(Verb));\n\n    // \"terminate\" -> \"Terminate\"\n    verbCaps = PhaDuplicateString(verb);\n    if (verbCaps->Length > 0) verbCaps->Buffer[0] = PhUpcaseUnicodeChar(verbCaps->Buffer[0]);\n\n    // \"terminate\", \"the process\" -> \"terminate the process\"\n    action = PhaConcatStrings(3, verb->Buffer, L\" \", Object);\n\n    {\n        ULONG button;\n        TASKDIALOGCONFIG config;\n        TASKDIALOG_BUTTON buttons[2];\n\n        memset(&config, 0, sizeof(TASKDIALOGCONFIG));\n        config.cbSize = sizeof(TASKDIALOGCONFIG);\n        config.hwndParent = WindowHandle;\n        config.hInstance = NtCurrentImageBase();\n        config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | ((WindowHandle && IsWindowVisible(WindowHandle) && !IsMinimized(WindowHandle)) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0);\n        config.pszWindowTitle = PhApplicationName;\n        config.pszMainIcon = Warning ? TD_WARNING_ICON : TD_INFORMATION_ICON;\n        config.pszMainInstruction = PhaConcatStrings(3, L\"Do you want to \", action->Buffer, L\"?\")->Buffer;\n        if (Message) config.pszContent = PhaConcatStrings2(Message, L\" Are you sure you want to continue?\")->Buffer;\n\n        buttons[0].nButtonID = IDYES;\n        buttons[0].pszButtonText = verbCaps->Buffer;\n        buttons[1].nButtonID = IDNO;\n        buttons[1].pszButtonText = L\"Cancel\";\n\n        config.cButtons = 2;\n        config.pButtons = buttons;\n        config.nDefaultButton = IDYES;\n        config.cxWidth = 200;\n\n        if (PhShowTaskDialog(\n            &config,\n            &button,\n            NULL,\n            NULL\n            ))\n        {\n            return button == IDYES;\n        }\n\n        if (PhShowMessage(\n            WindowHandle,\n            MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2,\n            L\"Are you sure you want to %s?\",\n            action->Buffer\n            ) == IDYES)\n        {\n            return TRUE;\n        }\n\n        return FALSE;\n    }\n}\n\n/**\n * Creates a random (type 4) UUID.\n *\n * \\param Guid The destination UUID.\n */\nVOID PhGenerateGuid(\n    _Out_ PGUID Guid\n    )\n{\n    ULARGE_INTEGER seed;\n    // The top/sign bit is always unusable for RtlRandomEx (the result is always unsigned), so we'll\n    // take the bottom 24 bits. We need 128 bits in total, so we'll call the function 6 times.\n    ULONG random[6];\n    ULONG i;\n\n    seed.QuadPart = PhReadPerformanceCounter();\n\n    for (i = 0; i < 6; i++)\n        random[i] = RtlRandomEx(&seed.LowPart);\n\n    // random[0] is usable\n    *(PUSHORT)&Guid->Data1 = (USHORT)random[0];\n    // top byte from random[0] is usable\n    *((PUSHORT)&Guid->Data1 + 1) = (USHORT)((random[0] >> 16) | (random[1] & 0xff));\n    // top 2 bytes from random[1] are usable\n    Guid->Data2 = (SHORT)(random[1] >> 8);\n    // random[2] is usable\n    Guid->Data3 = (SHORT)random[2];\n    // top byte from random[2] is usable\n    *(PUSHORT)&Guid->Data4[0] = (USHORT)((random[2] >> 16) | (random[3] & 0xff));\n    // top 2 bytes from random[3] are usable\n    *(PUSHORT)&Guid->Data4[2] = (USHORT)(random[3] >> 8);\n    // random[4] is usable\n    *(PUSHORT)&Guid->Data4[4] = (USHORT)random[4];\n    // top byte from random[4] is usable\n    *(PUSHORT)&Guid->Data4[6] = (USHORT)((random[4] >> 16) | (random[5] & 0xff));\n\n    ((PGUID_EX)Guid)->s2.Version = GUID_VERSION_RANDOM;\n    ((PGUID_EX)Guid)->s2.Variant &= ~GUID_VARIANT_STANDARD_MASK;\n    ((PGUID_EX)Guid)->s2.Variant |= GUID_VARIANT_STANDARD;\n}\n\n// rev from kernelbase (dmex)\n//VOID PhGenerateGuid2(\n//    _Out_ PGUID Guid\n//    )\n//{\n//    LARGE_INTEGER seed;\n//    PUSHORT buffer;\n//    ULONG count;\n//\n//    PhQuerySystemTime(&seed);\n//    buffer = (PUSHORT)Guid;\n//    count = 8;\n//\n//    do\n//    {\n//        *buffer = (USHORT)RtlRandomEx(&seed.LowPart);\n//        buffer = PTR_ADD_OFFSET(buffer, sizeof(USHORT));\n//    } while (--count);\n//}\n\n/**\n * Creates a name-based (type 3 or 5) UUID.\n *\n * \\param Guid The destination UUID.\n * \\param Namespace The UUID of the namespace.\n * \\param Name The input name.\n * \\param NameLength The length of the input name, not including the null terminator if present.\n * \\param Version The type of UUID.\n * \\li \\c GUID_VERSION_MD5 Creates a type 3, MD5-based UUID.\n * \\li \\c GUID_VERSION_SHA1 Creates a type 5, SHA1-based UUID.\n */\nVOID PhGenerateGuidFromName(\n    _Out_ PGUID Guid,\n    _In_ PGUID Namespace,\n    _In_ PCHAR Name,\n    _In_ ULONG NameLength,\n    _In_ UCHAR Version\n    )\n{\n    PGUID_EX guid;\n    PUCHAR data;\n    ULONG dataLength;\n    GUID ns;\n    UCHAR hash[20];\n\n    // Convert the namespace to big endian.\n\n    ns = *Namespace;\n    PhReverseGuid(&ns);\n\n    // Compute the hash of the namespace concatenated with the name.\n\n    dataLength = 16 + NameLength;\n    data = PhAllocate(dataLength);\n    memcpy(data, &ns, 16);\n    memcpy(&data[16], Name, NameLength);\n\n    if (Version == GUID_VERSION_MD5)\n    {\n        MD5_CTX context;\n\n        MD5Init(&context);\n        MD5Update(&context, data, dataLength);\n        MD5Final(&context);\n\n        memcpy(hash, context.digest, 16);\n    }\n    else\n    {\n        A_SHA_CTX context;\n\n        A_SHAInit(&context);\n        A_SHAUpdate(&context, data, dataLength);\n        A_SHAFinal(&context, hash);\n\n        Version = GUID_VERSION_SHA1;\n    }\n\n    PhFree(data);\n\n    guid = (PGUID_EX)Guid;\n    memcpy(guid->Data, hash, 16);\n    PhReverseGuid(&guid->Guid);\n    guid->s2.Version = Version;\n    guid->s2.Variant &= ~GUID_VARIANT_STANDARD_MASK;\n    guid->s2.Variant |= GUID_VARIANT_STANDARD;\n}\n\n// rev from ntoskrnl.exe!RtlGenerateClass5Guid (dmex)\n/**\n * Creates a type 5 (SHA1-based) UUID.\n *\n * \\param NamespaceGuid The UUID of the namespace.\n * \\param Buffer The input buffer.\n * \\param BufferSize The size of the input buffer.\n * \\param Guid The destination UUID.\n */\nVOID PhGenerateClass5Guid(\n    _In_ REFGUID NamespaceGuid,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _Out_ PGUID Guid\n    )\n{\n    A_SHA_CTX context;\n    GUID data;\n    PGUID_EX guid;\n    UCHAR hash[20];\n\n    data = *NamespaceGuid;\n    data.Data1 = _byteswap_ulong(NamespaceGuid->Data1);\n    data.Data2 = _rotr16(NamespaceGuid->Data2, 8);\n    data.Data3 = _rotr16(NamespaceGuid->Data3, 8);\n\n    A_SHAInit(&context);\n    A_SHAUpdate(&context, (PUCHAR)&data, sizeof(GUID));\n    A_SHAUpdate(&context, Buffer, BufferSize);\n    A_SHAFinal(&context, hash);\n\n    guid = (PGUID_EX)Guid;\n    memcpy(guid->Data, hash, sizeof(GUID));\n    guid->Guid.Data1 = _byteswap_ulong(guid->Guid.Data1);\n    guid->Guid.Data2 = _rotr16(guid->Guid.Data2, 8);\n    guid->Guid.Data3 = _rotr16(guid->Guid.Data3, 8);\n    guid->s2.Version = GUID_VERSION_SHA1;\n    guid->s2.Variant &= ~GUID_VARIANT_STANDARD_MASK;\n    guid->s2.Variant |= GUID_VARIANT_STANDARD;\n}\n\n/**\n * Creates a Hardware ID UUID.\n *\n * \\param Buffer The input buffer.\n * \\param BufferSize The size of the input buffer.\n * \\param Guid The destination UUID.\n * \\remarks rev from Windows SDK\\\\ComputerHardwareIds.exe (dmex)\n * \\remarks https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/computerhardwareids\n * \\remarks https://learn.microsoft.com/en-us/windows-hardware/drivers/install/specifying-hardware-ids-for-a-computer\n */\nVOID PhGenerateHardwareIDGuid(\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _Out_ PGUID Guid\n    )\n{\n    PhGenerateClass5Guid(&GUID_NAMESPACE_MICROSOFT, Buffer, BufferSize, Guid);\n}\n\n/**\n * Fills a buffer with random uppercase alphabetical characters.\n *\n * \\param Buffer The buffer to fill with random characters, plus a null terminator.\n * \\param Count The number of characters available in the buffer, including space for the null\n * terminator.\n */\nVOID PhGenerateRandomAlphaString(\n    _Out_writes_z_(Count) PWSTR Buffer,\n    _In_ SIZE_T Count\n    )\n{\n    ULARGE_INTEGER seed;\n    ULONG i;\n\n    if (Count == 0)\n        return;\n\n    seed.QuadPart = PhReadPerformanceCounter();\n\n    for (i = 0; i < Count - 1; i++)\n    {\n        Buffer[i] = L'A' + (RtlRandomEx(&seed.LowPart) % 26);\n    }\n\n    Buffer[Count - 1] = UNICODE_NULL;\n}\n\n/**\n * Fills a buffer with random numeric characters.\n *\n * \\param Buffer The buffer to fill with random characters, plus a null terminator.\n * \\param Count The number of characters available in the buffer, including space for the null\n * terminator.\n */\nVOID PhGenerateRandomNumericString(\n    _Out_writes_z_(Count) PWSTR Buffer,\n    _In_ SIZE_T Count\n    )\n{\n    ULARGE_INTEGER seed;\n    ULONG i;\n\n    if (Count == 0)\n        return;\n\n    seed.QuadPart = PhReadPerformanceCounter();\n\n    for (i = 0; i < Count - 1; i++)\n    {\n        Buffer[i] = L'0' + (RtlRandomEx(&seed.LowPart) % 10);\n    }\n\n    Buffer[Count - 1] = UNICODE_NULL;\n}\n\n/**\n * Generates a random 64-bit number.\n *\n * \\return A random 64-bit number.\n */\nULONG64 PhGenerateRandomNumber64(\n    VOID\n    )\n{\n    ULARGE_INTEGER seed;\n    ULARGE_INTEGER value;\n\n    seed.QuadPart = PhReadPerformanceCounter();\n    value.LowPart = RtlRandomEx(&seed.LowPart);\n    value.HighPart = RtlRandomEx(&seed.LowPart);\n\n    return value.QuadPart;\n}\n\n/**\n * Generates a random number.\n *\n * \\param Number Receives the random number.\n * \\return TRUE if the random number was generated, otherwise FALSE.\n */\nBOOLEAN PhGenerateRandomNumber(\n    _Out_ PLARGE_INTEGER Number\n    )\n{\n    memset(Number, 0, sizeof(LARGE_INTEGER));\n\n#ifndef _M_ARM64\n    if (PhIsProcessorFeaturePresent(PF_RDRAND_INSTRUCTION_AVAILABLE))\n    {\n        ULONG count = 0;\n\n#ifdef _M_X64\n        while (TRUE)\n        {\n            if (_rdrand64_step(&Number->QuadPart))\n                break;\n            if (++count >= 10)\n                return FALSE;\n        }\n#else\n        ULONG low = 0;\n        ULONG high = 0;\n\n        while (TRUE)\n        {\n            if (_rdrand32_step(&low) && _rdrand32_step(&high))\n            {\n                Number->LowPart = low;\n                Number->HighPart = high;\n                break;\n            }\n\n            if (++count >= 10)\n                return FALSE;\n        }\n#endif\n        return TRUE;\n    }\n#endif\n\n    Number->QuadPart = PhGenerateRandomNumber64();\n    return TRUE;\n}\n\n/**\n * Generates a random seed.\n *\n * \\param Seed Receives the random seed.\n * \\return TRUE if the random seed was generated, otherwise FALSE.\n */\nBOOLEAN PhGenerateRandomSeed(\n    _Out_ PLARGE_INTEGER Seed\n    )\n{\n    memset(Seed, 0, sizeof(LARGE_INTEGER));\n\n//#ifndef _M_ARM64\n//    if (PhIsProcessorFeaturePresent(PF_RDRAND_INSTRUCTION_AVAILABLE))\n//    {\n//#ifdef _M_X64\n//        if (_rdseed64_step(&Seed->QuadPart))\n//            return TRUE;\n//#else\n//        if (_rdseed32_step(&Seed->LowPart))\n//            return TRUE;\n//#endif\n//    }\n//#endif\n\n    return PhQueryPerformanceCounter(Seed);\n}\n\n/**\n * Modifies a string to ensure it is within the specified length.\n *\n * \\param String The input string.\n * \\param DesiredCount The desired number of characters in the new string. If necessary, parts of\n * the string are replaced with an ellipsis to indicate characters have been omitted.\n * \\return The new string.\n */\nPPH_STRING PhEllipsisString(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T DesiredCount\n    )\n{\n    if (\n        String->Length / sizeof(WCHAR) <= DesiredCount ||\n        DesiredCount < 3\n        )\n    {\n        return PhReferenceObject(String);\n    }\n    else\n    {\n        PPH_STRING string;\n\n        string = PhCreateStringEx(NULL, DesiredCount * sizeof(WCHAR));\n        memcpy(string->Buffer, String->Buffer, (DesiredCount - 3) * sizeof(WCHAR));\n        memcpy(&string->Buffer[DesiredCount - 3], L\"...\", 6);\n\n        return string;\n    }\n}\n\n/**\n * Modifies a string to ensure it is within the specified length, parsing the string as a path.\n *\n * \\param String The input string.\n * \\param DesiredCount The desired number of characters in the new string. If necessary, parts of\n * the string are replaced with an ellipsis to indicate characters have been omitted.\n * \\return The new string.\n */\nPPH_STRING PhEllipsisStringPath(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T DesiredCount\n    )\n{\n    ULONG_PTR secondPartIndex;\n\n    secondPartIndex = PhFindLastCharInString(String, 0, OBJ_NAME_PATH_SEPARATOR);\n\n    if (secondPartIndex == SIZE_MAX)\n        secondPartIndex = PhFindLastCharInString(String, 0, OBJ_NAME_ALTPATH_SEPARATOR);\n    if (secondPartIndex == SIZE_MAX)\n        return PhEllipsisString(String, DesiredCount);\n\n    if (\n        String->Length / sizeof(WCHAR) <= DesiredCount ||\n        DesiredCount < 3\n        )\n    {\n        return PhReferenceObject(String);\n    }\n    else\n    {\n        PPH_STRING string;\n        ULONG_PTR firstPartCopyLength;\n        ULONG_PTR secondPartCopyLength;\n\n        string = PhCreateStringEx(NULL, DesiredCount * sizeof(WCHAR));\n        secondPartCopyLength = String->Length / sizeof(WCHAR) - secondPartIndex;\n\n        // Check if we have enough space for the entire second part of the string.\n        if (secondPartCopyLength + 3 <= DesiredCount)\n        {\n            // Yes, copy part of the first part and the entire second part.\n            firstPartCopyLength = DesiredCount - secondPartCopyLength - 3;\n        }\n        else\n        {\n            // No, copy part of both, from the beginning of the first part and the end of the second\n            // part.\n            firstPartCopyLength = (DesiredCount - 3) / sizeof(WCHAR);\n            secondPartCopyLength = DesiredCount - 3 - firstPartCopyLength;\n            secondPartIndex = String->Length / sizeof(WCHAR) - secondPartCopyLength;\n        }\n\n        memcpy(\n            string->Buffer,\n            String->Buffer,\n            firstPartCopyLength * sizeof(WCHAR)\n            );\n        memcpy(\n            &string->Buffer[firstPartCopyLength],\n            L\"...\",\n            6\n            );\n        memcpy(\n            &string->Buffer[firstPartCopyLength + 3],\n            &String->Buffer[secondPartIndex],\n            secondPartCopyLength * sizeof(WCHAR)\n            );\n\n        return string;\n    }\n}\n\n/**\n * Internal worker for matching a pattern against a string.\n *\n * \\param Pattern The pattern.\n * \\param String The string.\n * \\param IgnoreCase Whether to ignore case.\n * \\return TRUE if the pattern matches the string, otherwise FALSE.\n */\nFORCEINLINE BOOLEAN PhpMatchWildcards(\n    _In_ PCWSTR Pattern,\n    _In_ PCWSTR String,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PCWCHAR s, p;\n    BOOLEAN star = FALSE;\n\n    // Code is from http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html\n\nLoopStart:\n    for (s = String, p = Pattern; *s; s++, p++)\n    {\n        switch (*p)\n        {\n        case L'?':\n            break;\n        case L'*':\n            star = TRUE;\n            String = s;\n            Pattern = p;\n\n            do\n            {\n                Pattern++;\n            } while (*Pattern == L'*');\n\n            if (!*Pattern) return TRUE;\n\n            goto LoopStart;\n        default:\n            if (!IgnoreCase)\n            {\n                if (*s != *p)\n                    goto StarCheck;\n            }\n            else\n            {\n                if (PhUpcaseUnicodeChar(*s) != PhUpcaseUnicodeChar(*p))\n                    goto StarCheck;\n            }\n\n            break;\n        }\n    }\n\n    while (*p == L'*')\n        p++;\n\n    return (!*p);\n\nStarCheck:\n    if (!star)\n        return FALSE;\n\n    String++;\n    goto LoopStart;\n}\n\n/**\n * Matches a pattern against a string.\n *\n * \\param Pattern The pattern, which can contain asterisks and question marks.\n * \\param String The string which the pattern is matched against.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nBOOLEAN PhMatchWildcards(\n    _In_ PCWSTR Pattern,\n    _In_ PCWSTR String,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (IgnoreCase)\n        return PhpMatchWildcards(Pattern, String, TRUE);\n    else\n        return PhpMatchWildcards(Pattern, String, FALSE);\n}\n\n/**\n * Escapes a string for prefix characters (ampersands).\n *\n * \\param String The string to process.\n *\n * \\return The escaped string, with each ampersand replaced by 2 ampersands.\n */\nPPH_STRING PhEscapeStringForMenuPrefix(\n    _In_ PCPH_STRINGREF String\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    SIZE_T i;\n    SIZE_T length;\n    PWCHAR runStart;\n    SIZE_T runCount = 0;\n\n    length = String->Length / sizeof(WCHAR);\n    runStart = NULL;\n\n    PhInitializeStringBuilder(&stringBuilder, String->Length);\n\n    for (i = 0; i < length; i++)\n    {\n        switch (String->Buffer[i])\n        {\n        case L'&':\n            if (runStart)\n            {\n                PhAppendStringBuilderEx(&stringBuilder, runStart, runCount * sizeof(WCHAR));\n                runStart = NULL;\n            }\n\n            PhAppendStringBuilder2(&stringBuilder, L\"&&\");\n\n            break;\n        default:\n            if (runStart)\n            {\n                runCount++;\n            }\n            else\n            {\n                runStart = &String->Buffer[i];\n                runCount = 1;\n            }\n\n            break;\n        }\n    }\n\n    if (runStart)\n        PhAppendStringBuilderEx(&stringBuilder, runStart, runCount * sizeof(WCHAR));\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n/**\n * Compares two strings, ignoring prefix characters (ampersands).\n *\n * \\param A The first string.\n * \\param B The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n * \\param MatchIfPrefix Specify TRUE to return 0 when \\a A is a prefix of \\a B.\n */\nLONG PhCompareUnicodeStringZIgnoreMenuPrefix(\n    _In_ PCWSTR A,\n    _In_ PCWSTR B,\n    _In_ BOOLEAN IgnoreCase,\n    _In_ BOOLEAN MatchIfPrefix\n    )\n{\n    WCHAR t;\n\n    if (!A || !B)\n        return -1;\n\n    if (!IgnoreCase)\n    {\n        while (TRUE)\n        {\n            // This takes care of double ampersands as well (they are treated as one literal\n            // ampersand).\n            if (*A == L'&')\n                A++;\n            if (*B == L'&')\n                B++;\n\n            t = *A;\n\n            if (t == UNICODE_NULL)\n            {\n                if (MatchIfPrefix)\n                    return 0;\n\n                break;\n            }\n\n            if (t != *B)\n                break;\n\n            A++;\n            B++;\n        }\n\n        return C_2uTo4(t) - C_2uTo4(*B);\n    }\n    else\n    {\n        while (TRUE)\n        {\n            if (*A == L'&')\n                A++;\n            if (*B == L'&')\n                B++;\n\n            t = *A;\n\n            if (t == UNICODE_NULL)\n            {\n                if (MatchIfPrefix)\n                    return 0;\n\n                break;\n            }\n\n            if (PhUpcaseUnicodeChar(t) != PhUpcaseUnicodeChar(*B))\n                break;\n\n            A++;\n            B++;\n        }\n\n        return C_2uTo4(t) - C_2uTo4(*B);\n    }\n}\n\n/**\n * Formats UTC system time in ISO 8601 format.\n *\n * \\param SystemTime The UTC time structure. If NULL, the current UTC time is used.\n *\n * \\return A string in the ISO 8601 format.\n */\nPPH_STRING PhFormatSystemTimeISO(\n    _In_opt_ PSYSTEMTIME SystemTime\n    )\n{\n    SYSTEMTIME systemTime;\n\n    if (SystemTime)\n    {\n        systemTime = *SystemTime;\n    }\n    else\n    {\n        LARGE_INTEGER timeStamp;\n        PhQuerySystemTime(&timeStamp);\n        PhLargeIntegerToSystemTime(&systemTime, &timeStamp);\n    }\n\n    return PhFormatString(\n        L\"%04u-%02u-%02uT%02u:%02u:%02u.%03uZ\",\n        systemTime.wYear,\n        systemTime.wMonth,\n        systemTime.wDay,\n        systemTime.wHour,\n        systemTime.wMinute,\n        systemTime.wSecond,\n        systemTime.wMilliseconds\n        );\n}\n\n/**\n * Formats local system time in ISO 8601 format, including the time zone offset.\n *\n * \\param SystemTime The local time structure. If NULL, the current local time is used.\n *\n * \\return A string in the ISO 8601 format.\n */\nPPH_STRING PhFormatLocalSystemTimeISO(\n    _In_opt_ PSYSTEMTIME SystemTime\n    )\n{\n    SYSTEMTIME systemTime;\n    LARGE_INTEGER timeZoneBias;\n    CHAR sign;\n    USHORT timeZoneHours;\n    USHORT timeZoneMinutes;\n\n    if (SystemTime)\n    {\n        systemTime = *SystemTime;\n    }\n    else\n    {\n        LARGE_INTEGER timeStamp;\n        PhQuerySystemTime(&timeStamp);\n        PhLargeIntegerToLocalSystemTime(&systemTime, &timeStamp);\n    }\n\n    PhQueryTimeZoneBias(&timeZoneBias);\n    if (timeZoneBias.QuadPart == 0)\n    {\n        return PhFormatSystemTimeISO(&systemTime);\n    }\n\n    //\n    // N.B. Bias is subtracted from system time therefore positive is west of\n    // UTC and negative is east of UTC.\n    //\n    if (timeZoneBias.QuadPart > 0)\n    {\n        sign = '-';\n        timeZoneHours = (USHORT)((timeZoneBias.QuadPart / 600000000LL) / 60);\n        timeZoneMinutes = (USHORT)((timeZoneBias.QuadPart / 600000000LL) % 60);\n    }\n    else\n    {\n        sign = '+';\n        timeZoneHours = (USHORT)((-timeZoneBias.QuadPart / 600000000LL) / 60);\n        timeZoneMinutes = (USHORT)((-timeZoneBias.QuadPart / 600000000LL) % 60);\n    }\n\n    return PhFormatString(\n        L\"%04u-%02u-%02uT%02u:%02u:%02u.%03u%c%02u:%02u\",\n        systemTime.wYear,\n        systemTime.wMonth,\n        systemTime.wDay,\n        systemTime.wHour,\n        systemTime.wMinute,\n        systemTime.wSecond,\n        systemTime.wMilliseconds,\n        sign,\n        timeZoneHours,\n        timeZoneMinutes\n        );\n}\n\n/**\n * Formats a date using the user's default locale.\n *\n * \\param Date The time structure. If NULL, the current time is used.\n * \\param Format The format of the date. If NULL, the format appropriate to the user's locale is\n * used.\n */\nPPH_STRING PhFormatDate(\n    _In_opt_ PSYSTEMTIME Date,\n    _In_opt_ PCWSTR Format\n    )\n{\n    PPH_STRING string;\n    LONG bufferSize;\n\n    bufferSize = GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, 0, Date, Format, NULL, 0, NULL);\n    string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR));\n\n    if (!GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, 0, Date, Format, string->Buffer, bufferSize, NULL))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\n/**\n * Formats a time using the user's default locale.\n *\n * \\param Time The time structure. If NULL, the current time is used.\n * \\param Format The format of the time. If NULL, the format appropriate to the user's locale is\n * used.\n */\nPPH_STRING PhFormatTime(\n    _In_opt_ PSYSTEMTIME Time,\n    _In_opt_ PCWSTR Format\n    )\n{\n    PPH_STRING string;\n    LONG bufferSize;\n\n    bufferSize = GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, Time, Format, NULL, 0);\n    string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR));\n\n    if (!GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, Time, Format, string->Buffer, bufferSize))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\n/**\n * Formats a date and time using the user's default locale.\n *\n * \\param DateTime The time structure. If NULL, the current time is used.\n *\n * \\return A string containing the time, a space character, then the date.\n */\nPPH_STRING PhFormatDateTime(\n    _In_opt_ PSYSTEMTIME DateTime\n    )\n{\n    PPH_STRING string;\n    LONG timeBufferSize;\n    LONG dateBufferSize;\n    ULONG count;\n\n    timeBufferSize = GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, DateTime, NULL, NULL, 0);\n    dateBufferSize = GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, 0, DateTime, NULL, NULL, 0, NULL);\n\n    string = PhCreateStringEx(NULL, ((SIZE_T)timeBufferSize + 1 + dateBufferSize) * sizeof(WCHAR));\n\n    if (!GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, DateTime, NULL, &string->Buffer[0], timeBufferSize))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    count = (ULONG)PhCountStringZ(string->Buffer);\n    string->Buffer[count] = L' ';\n\n    if (!GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, 0, DateTime, NULL, &string->Buffer[count + 1], dateBufferSize, NULL))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\n/**\n * Formats a date and time using the user's default locale to a buffer.\n *\n * \\param DateTime The time structure. If NULL, the current time is used.\n * \\param Buffer The destination buffer.\n * \\param BufferLength The size of the destination buffer, in bytes.\n * \\param ReturnLength Receives the number of bytes written to the buffer.\n * \\return TRUE if the date and time were formatted, otherwise FALSE.\n */\n_Success_(return)\nBOOLEAN PhFormatDateTimeToBuffer(\n    _In_opt_ PSYSTEMTIME DateTime,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _In_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    SIZE_T returnLength;\n    LONG timeBufferSize;\n    LONG dateBufferSize;\n\n    timeBufferSize = GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, DateTime, NULL, NULL, 0);\n    dateBufferSize = GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, 0, DateTime, NULL, NULL, 0, NULL);\n\n    returnLength = ((SIZE_T)timeBufferSize + 1 + (SIZE_T)dateBufferSize) * sizeof(WCHAR);\n\n    if (returnLength >= BufferLength)\n        goto CleanupExit;\n\n    if (!GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, DateTime, NULL, &Buffer[0], timeBufferSize))\n        goto CleanupExit;\n\n    Buffer[timeBufferSize - 1] = L' ';\n\n    if (!GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, 0, DateTime, NULL, &Buffer[timeBufferSize], dateBufferSize, NULL))\n        goto CleanupExit;\n\n    if (ReturnLength)\n        *ReturnLength = returnLength - sizeof(UNICODE_NULL); // HACK\n    Buffer[returnLength] = UNICODE_NULL;\n    return TRUE;\n\nCleanupExit:\n    if (ReturnLength)\n        *ReturnLength = returnLength;\n    return FALSE;\n}\n\n/**\n * Formats a time span.\n *\n * \\param Ticks The number of ticks.\n * \\param Mode The format mode.\n * \\return A string containing the formatted time span.\n */\nPPH_STRING PhFormatTimeSpan(\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode\n    )\n{\n    PPH_STRING string;\n\n    string = PhCreateStringEx(NULL, PH_TIMESPAN_STR_LEN * sizeof(WCHAR));\n    PhPrintTimeSpan(string->Buffer, Ticks, Mode);\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\n/**\n * Formats a time span with extended options.\n *\n * \\param Ticks The number of ticks.\n * \\param Mode The format mode.\n * \\return A string containing the formatted time span.\n */\nPPH_STRING PhFormatTimeSpanEx(\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode\n    )\n{\n    SIZE_T returnLength;\n    WCHAR buffer[PH_TIMESPAN_STR_LEN_1];\n\n    if (PhPrintTimeSpanToBuffer(\n        Ticks,\n        Mode,\n        buffer,\n        PH_TIMESPAN_STR_LEN,\n        &returnLength\n        ))\n    {\n        PH_STRINGREF string;\n\n        string.Length = returnLength - sizeof(UNICODE_NULL);\n        string.Buffer = buffer;\n\n        return PhCreateString2(&string);\n    }\n\n    return PhReferenceEmptyString();\n}\n\n/**\n * Formats a relative time span.\n *\n * \\param TimeSpan The time span, in ticks.\n */\nPPH_STRING PhFormatTimeSpanRelative(\n    _In_ ULONG64 TimeSpan\n    )\n{\n    PPH_STRING string;\n    FLOAT days;\n    FLOAT weeks;\n    FLOAT fortnights;\n    FLOAT months;\n    FLOAT years;\n    FLOAT centuries;\n\n    days = (FLOAT)TimeSpan / (FLOAT)PH_TICKS_PER_DAY;\n    weeks = days / 7;\n    fortnights = weeks / 2;\n    years = days / 365.2425f;\n    months = years * 12;\n    centuries = years / 100;\n\n    if (centuries >= 1)\n    {\n        string = PhFormatString(L\"%u %s\", (ULONG)centuries, (ULONG)centuries == 1 ? L\"century\" : L\"centuries\");\n    }\n    else if (years >= 1)\n    {\n        string = PhFormatString(L\"%u %s\", (ULONG)years, (ULONG)years == 1 ? L\"year\" : L\"years\");\n    }\n    else if (months >= 1)\n    {\n        string = PhFormatString(L\"%u %s\", (ULONG)months, (ULONG)months == 1 ? L\"month\" : L\"months\");\n    }\n    else if (fortnights >= 1)\n    {\n        string = PhFormatString(L\"%u %s\", (ULONG)fortnights, (ULONG)fortnights == 1 ? L\"fortnight\" : L\"fortnights\");\n    }\n    else if (weeks >= 1)\n    {\n        string = PhFormatString(L\"%u %s\", (ULONG)weeks, (ULONG)weeks == 1 ? L\"week\" : L\"weeks\");\n    }\n    else\n    {\n        FLOAT milliseconds;\n        FLOAT seconds;\n        FLOAT minutes;\n        FLOAT hours;\n        ULONG secondsPartial;\n        ULONG minutesPartial;\n        ULONG hoursPartial;\n\n        milliseconds = (FLOAT)TimeSpan / (FLOAT)PH_TICKS_PER_MS;\n        seconds = (FLOAT)TimeSpan / (FLOAT)PH_TICKS_PER_SEC;\n        minutes = (FLOAT)TimeSpan / (FLOAT)PH_TICKS_PER_MIN;\n        hours = (FLOAT)TimeSpan / (FLOAT)PH_TICKS_PER_HOUR;\n\n        if (days >= 1)\n        {\n            hoursPartial = (ULONG)PH_TICKS_PARTIAL_HOURS(TimeSpan);\n\n            if (hoursPartial >= 1)\n            {\n                string = PhFormatString(\n                    L\"%u %s and %u %s\",\n                    (ULONG)days,\n                    (ULONG)days == 1 ? L\"day\" : L\"days\",\n                    hoursPartial,\n                    hoursPartial == 1 ? L\"hour\" : L\"hours\"\n                    );\n            }\n            else\n            {\n                string = PhFormatString(L\"%u %s\", (ULONG)days, (ULONG)days == 1 ? L\"day\" : L\"days\");\n            }\n        }\n        else if (hours >= 1)\n        {\n            minutesPartial = (ULONG)PH_TICKS_PARTIAL_MIN(TimeSpan);\n\n            if (minutesPartial >= 1)\n            {\n                string = PhFormatString(\n                    L\"%u %s and %u %s\",\n                    (ULONG)hours,\n                    (ULONG)hours == 1 ? L\"hour\" : L\"hours\",\n                    (ULONG)minutesPartial,\n                    (ULONG)minutesPartial == 1 ? L\"minute\" : L\"minutes\"\n                    );\n            }\n            else\n            {\n                string = PhFormatString(L\"%u %s\", (ULONG)hours, (ULONG)hours == 1 ? L\"hour\" : L\"hours\");\n            }\n        }\n        else if (minutes >= 1)\n        {\n            secondsPartial = (ULONG)PH_TICKS_PARTIAL_SEC(TimeSpan);\n\n            if (secondsPartial >= 1)\n            {\n                string = PhFormatString(\n                    L\"%u %s and %u %s\",\n                    (ULONG)minutes,\n                    (ULONG)minutes == 1 ? L\"minute\" : L\"minutes\",\n                    (ULONG)secondsPartial,\n                    (ULONG)secondsPartial == 1 ? L\"second\" : L\"seconds\"\n                    );\n            }\n            else\n            {\n                string = PhFormatString(L\"%u %s\", (ULONG)minutes, (ULONG)minutes == 1 ? L\"minute\" : L\"minutes\");\n            }\n        }\n        else if (seconds >= 1)\n        {\n            string = PhFormatString(L\"%u %s\", (ULONG)seconds, (ULONG)seconds == 1 ? L\"second\" : L\"seconds\");\n        }\n        else if (milliseconds >= 1)\n        {\n            string = PhFormatString(L\"%u %s\", (ULONG)milliseconds, (ULONG)milliseconds == 1 ? L\"millisecond\" : L\"milliseconds\");\n        }\n        else\n        {\n            string = PhCreateString(L\"a very short time\");\n        }\n    }\n\n    // Turn 1 into \"a\", e.g. 1 minute -> a minute\n    if (PhStartsWithString2(string, L\"1 \", FALSE))\n    {\n        // Special vowel case: a hour -> an hour\n        if (string->Buffer[2] != L'h')\n            PhMoveReference(&string, PhConcatStrings2(L\"a \", &string->Buffer[2]));\n        else\n            PhMoveReference(&string, PhConcatStrings2(L\"an \", &string->Buffer[2]));\n    }\n\n    return string;\n}\n\n/**\n * Formats a 64-bit unsigned integer.\n *\n * \\param Value The integer.\n * \\param GroupDigits TRUE to group digits, otherwise FALSE.\n */\nPPH_STRING PhFormatUInt64(\n    _In_ ULONG64 Value,\n    _In_ BOOLEAN GroupDigits\n    )\n{\n    PH_FORMAT format;\n\n    format.Type = UInt64FormatType | (GroupDigits ? FormatGroupDigits : 0);\n    format.u.UInt64 = Value;\n\n    return PhFormat(&format, 1, 0);\n}\n\n/**\n * Formats a 64-bit unsigned integer using Metric (SI) Prefixes (1000=1k, 1000000=1M, 1000000000000=1B)\n * https://en.wikipedia.org/wiki/Metric_prefix\n *\n * \\param Value The integer.\n * \\param GroupDigits TRUE to group digits, otherwise FALSE.\n */\nPPH_STRING PhFormatUInt64Prefix(\n    _In_ ULONG64 Value,\n    _In_ BOOLEAN GroupDigits\n    )\n{\n    DOUBLE number = (DOUBLE)Value;\n    ULONG i = 0;\n    PH_FORMAT format[2];\n\n    while (\n        number >= 1000 &&\n        i + 1 < (ULONG)RTL_NUMBER_OF(PhPrefixUnitNamesCounted) &&\n        i < PhMaxSizeUnit\n        )\n    {\n        number /= 1000;\n        i++;\n    }\n\n    format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros | (GroupDigits ? FormatGroupDigits : 0);\n    format[0].Precision = 2;\n    format[0].u.Double = number;\n    PhInitFormatSR(&format[1], PhPrefixUnitNamesCounted[i]);\n\n    return PhFormat(format, 2, 0);\n}\n\n/**\n * Formats a 64-bit unsigned integer using Data-rate (SI) Prefixes (1000=1Bps, 1000000=1Kbps, 1000000000000=1Mbps)\n * https://en.wikipedia.org/wiki/Data-rate_units\n *\n * \\param Value The integer.\n * \\param GroupDigits TRUE to group digits, otherwise FALSE.\n */\nPPH_STRING PhFormatUInt64BitratePrefix(\n    _In_ ULONG64 Value,\n    _In_ BOOLEAN GroupDigits\n    )\n{\n    DOUBLE number = (DOUBLE)Value;\n    ULONG i = 0;\n    PH_FORMAT format[2];\n\n    while (\n        number >= 1000 &&\n        i + 1 < (ULONG)RTL_NUMBER_OF(PhSiPrefixUnitNamesCounted) &&\n        i < PhMaxSizeUnit\n        )\n    {\n        number /= 1000;\n        i++;\n    }\n\n    format[0].Type = DoubleFormatType | FormatUsePrecision | (GroupDigits ? FormatGroupDigits : 0);\n    format[0].Precision = 1;\n    format[0].u.Double = number;\n    PhInitFormatSR(&format[1], PhSiPrefixUnitNamesCounted[i]);\n\n    return PhFormat(format, 2, 0);\n}\n\n/**\n * Formats a decimal string.\n *\n * \\param Value The decimal string.\n * \\param FractionalDigits The number of fractional digits.\n * \\param GroupDigits TRUE to group digits, otherwise FALSE.\n * \\return A string containing the formatted decimal.\n */\nPPH_STRING PhFormatDecimal(\n    _In_ PCWSTR Value,\n    _In_ ULONG FractionalDigits,\n    _In_ BOOLEAN GroupDigits\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static WCHAR decimalSeparator[4];\n    static WCHAR thousandSeparator[4];\n\n    PPH_STRING string;\n    NUMBERFMT format;\n    ULONG bufferSize;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (!GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SDECIMAL, decimalSeparator, 4))\n        {\n            decimalSeparator[0] = L'.';\n            decimalSeparator[1] = UNICODE_NULL;\n        }\n\n        if (!GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_STHOUSAND, thousandSeparator, 4))\n        {\n            thousandSeparator[0] = L',';\n            thousandSeparator[1] = UNICODE_NULL;\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    format.NumDigits = FractionalDigits;\n    format.LeadingZero = 0;\n    format.Grouping = GroupDigits ? 3 : 0;\n    format.lpDecimalSep = decimalSeparator;\n    format.lpThousandSep = thousandSeparator;\n    format.NegativeOrder = 1;\n\n    bufferSize = GetNumberFormatEx(LOCALE_NAME_USER_DEFAULT, 0, Value, &format, NULL, 0);\n    string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR));\n\n    if (!GetNumberFormatEx(LOCALE_NAME_USER_DEFAULT, 0, Value, &format, string->Buffer, bufferSize))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\n/**\n * Gets a string representing a size.\n *\n * \\param Size The size value.\n * \\param MaxSizeUnit The largest unit of size to use, -1 to use PhMaxSizeUnit, or -2 for no limit.\n * \\li \\c 0 Bytes.\n * \\li \\c 1 Kilobytes.\n * \\li \\c 2 Megabytes.\n * \\li \\c 3 Gigabytes.\n * \\li \\c 4 Terabytes.\n * \\li \\c 5 Petabytes.\n * \\li \\c 6 Exabytes.\n */\nPPH_STRING PhFormatSize(\n    _In_ ULONG64 Size,\n    _In_ ULONG MaxSizeUnit\n    )\n{\n    PH_FORMAT format;\n\n    // PhFormat handles this better than the old method.\n\n    format.Type = SizeFormatType | FormatUseRadix;\n    format.Radix = (UCHAR)(MaxSizeUnit != ULONG_MAX ? MaxSizeUnit : PhMaxSizeUnit);\n    format.u.Size = Size;\n\n    return PhFormat(&format, 1, 0);\n}\n\n/**\n * Gets a string representing a size.\n *\n * \\param Size The size value.\n * \\param MaxSizeUnit The largest unit of size to use, -1 to use PhMaxSizeUnit, or -2 for no limit.\n * \\param Buffer A buffer. If NULL, no data is written.\n * \\param BufferLength The number of bytes available in \\a Buffer, including space for the null terminator.\n * \\param ReturnLength The number of bytes required to hold the string, including the null terminator.\n */\nBOOLEAN PhFormatSizeToBuffer(\n    _In_ ULONG64 Size,\n    _In_ ULONG MaxSizeUnit,\n    _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    PH_FORMAT format;\n\n    // PhFormat handles this better than the old method.\n\n    format.Type = SizeFormatType | FormatUseRadix;\n    format.Radix = (UCHAR)(MaxSizeUnit != ULONG_MAX ? MaxSizeUnit : PhMaxSizeUnit);\n    format.u.Size = Size;\n\n    return PhFormatToBuffer(&format, 1, Buffer, BufferLength, ReturnLength);\n}\n\n/**\n * Converts a UUID to its string representation.\n *\n * \\param Guid A UUID.\n */\nPPH_STRING PhFormatGuid(\n    _In_ PGUID Guid\n    )\n{\n    PPH_STRING string;\n    UNICODE_STRING unicodeString;\n\n    if (!NT_SUCCESS(RtlStringFromGUID(Guid, &unicodeString)))\n        return NULL;\n\n    string = PhCreateStringFromUnicodeString(&unicodeString);\n    RtlFreeUnicodeString(&unicodeString);\n\n    return string;\n}\n\n/**\n * Converts a UUID to its string representation.\n *\n * \\param Guid A UUID.\n * \\param Buffer A buffer. If NULL, no data is written.\n * \\param BufferLength The number of bytes available in Buffer, including space for the null terminator.\n * \\param ReturnLength The number of bytes required to hold the string, including the null terminator.\n */\nNTSTATUS PhFormatGuidToBuffer(\n    _In_ PGUID Guid,\n    _Writable_bytes_(BufferLength) _When_(BufferLength != 0, _Notnull_) PWCHAR Buffer,\n    _In_opt_ USHORT BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&RtlStringFromGUIDEx) RtlStringFromGUIDEx_I = NULL;\n    NTSTATUS status;\n    UNICODE_STRING unicodeString;\n\n    if (WindowsVersion < WINDOWS_10)\n    {\n        PPH_STRING guid = PhFormatGuid(Guid);\n\n        if (BufferLength < guid->Length)\n        {\n            if (ReturnLength)\n                *ReturnLength = guid->Length + sizeof(UNICODE_NULL);\n            PhDereferenceObject(guid);\n            return STATUS_BUFFER_TOO_SMALL;\n        }\n\n        memcpy(Buffer, guid->Buffer, BufferLength);\n\n        if (ReturnLength)\n            *ReturnLength = guid->Length + sizeof(UNICODE_NULL);\n        PhDereferenceObject(guid);\n        return STATUS_SUCCESS;\n    }\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion >= WINDOWS_10)\n        {\n            RtlStringFromGUIDEx_I = PhGetDllProcedureAddressZ(RtlNtdllName, \"RtlStringFromGUIDEx\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!RtlStringFromGUIDEx_I)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    RtlInitEmptyUnicodeString(&unicodeString, Buffer, BufferLength);\n\n    status = RtlStringFromGUIDEx_I(\n        Guid,\n        &unicodeString,\n        FALSE\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (ReturnLength)\n        {\n            *ReturnLength = unicodeString.Length + sizeof(UNICODE_NULL);\n        }\n    }\n\n    return status;\n}\n\n/**\n * Converts a string to its UUID representation.\n *\n * \\param GuidString The string representation of the UUID.\n * \\param Guid Receives the UUID.\n * \\return Successful or errant status.\n */\nNTSTATUS PhStringToGuid(\n    _In_ PCPH_STRINGREF GuidString,\n    _Out_ PGUID Guid\n    )\n{\n    UNICODE_STRING unicodeString;\n\n    if (!PhStringRefToUnicodeString(GuidString, &unicodeString))\n        return STATUS_BUFFER_OVERFLOW;\n\n    return RtlGUIDFromString(&unicodeString, Guid);\n}\n\n/**\n * Retrieves image version information for a file.\n *\n * \\param FileName The file name.\n * \\param VersionInfo A version information block. You must free this using PhFree() when you no longer need it.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhGetFileVersionInfo(\n    _In_ PCWSTR FileName,\n    _Out_ PVOID* VersionInfo\n    )\n{\n    NTSTATUS status;\n    PVOID libraryModule;\n    PVOID versionInfo;\n\n    libraryModule = LoadLibraryEx(\n        FileName,\n        NULL,\n        LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE\n        );\n\n    if (!libraryModule)\n    {\n        return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    status = PhLoadResourceCopy(\n        libraryModule,\n        MAKEINTRESOURCE(VS_VERSION_INFO),\n        VS_FILE_INFO,\n        NULL,\n        &versionInfo\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (PhIsFileVersionInfo32(versionInfo))\n        {\n            PhFreeLibrary(libraryModule);\n            *VersionInfo = versionInfo;\n            return STATUS_SUCCESS;\n        }\n        else\n        {\n            status = STATUS_NOT_FOUND;\n        }\n\n        PhFree(versionInfo);\n    }\n\n    PhFreeLibrary(libraryModule);\n\n    return status;\n}\n\nNTSTATUS PhGetFileVersionInfoEx(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_ PVOID* VersionInfo\n    )\n{\n    NTSTATUS status;\n    PVOID imageBaseAddress;\n    PVOID versionInfo;\n\n    status = PhLoadLibraryAsImageResource(FileName, TRUE, &imageBaseAddress);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    //if (LdrResFindResource_Import())\n    //{\n    //    PVOID resourceBuffer = NULL;\n    //    SIZE_T resourceLength = 0;\n    //\n    //    if (NT_SUCCESS(LdrResFindResource_Import()(\n    //        imageBaseAddress,\n    //        VS_FILE_INFO,\n    //        MAKEINTRESOURCE(VS_VERSION_INFO),\n    //        MAKEINTRESOURCE(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)),\n    //        &resourceBuffer,\n    //        &resourceLength,\n    //        NULL,\n    //        NULL,\n    //        0\n    //        )))\n    //    {\n    //        *VersionInfo = PhAllocateCopy(resourceBuffer, resourceLength);\n    //        PhFreeLibraryAsImageResource(imageBaseAddress);\n    //        return STATUS_SUCCESS;\n    //    }\n    //}\n\n    // MUI version information\n    if (PRIMARYLANGID(LANGIDFROMLCID(PhGetCurrentThreadLCID())) != LANG_ENGLISH)\n    {\n        PVOID resourceDllBase;\n        SIZE_T resourceDllSize;\n\n        if (NT_SUCCESS(LdrLoadAlternateResourceModule(imageBaseAddress, &resourceDllBase, &resourceDllSize, 0)))\n        {\n            if (NT_SUCCESS(PhLoadResourceCopy(\n                resourceDllBase,\n                MAKEINTRESOURCE(VS_VERSION_INFO),\n                VS_FILE_INFO,\n                NULL,\n                &versionInfo\n                )))\n            {\n                if (PhIsFileVersionInfo32(versionInfo))\n                {\n                    LdrUnloadAlternateResourceModule(resourceDllBase);\n                    PhFreeLibraryAsImageResource(imageBaseAddress);\n                    *VersionInfo = versionInfo;\n                    return STATUS_SUCCESS;\n                }\n\n                PhFree(versionInfo);\n            }\n\n            LdrUnloadAlternateResourceModule(resourceDllBase);\n        }\n    }\n\n    // EXE version information\n    {\n        status = PhLoadResourceCopy(\n            imageBaseAddress,\n            MAKEINTRESOURCE(VS_VERSION_INFO),\n            VS_FILE_INFO,\n            NULL,\n            &versionInfo\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (PhIsFileVersionInfo32(versionInfo))\n            {\n                PhFreeLibraryAsImageResource(imageBaseAddress);\n                *VersionInfo = versionInfo;\n                return STATUS_SUCCESS;\n            }\n            else\n            {\n                status = STATUS_NOT_FOUND;\n            }\n\n            PhFree(versionInfo);\n        }\n    }\n\n    PhFreeLibraryAsImageResource(imageBaseAddress);\n    return status;\n}\n\nPVOID PhGetFileVersionInfoValue(\n    _In_ PVS_VERSION_INFO_STRUCT32 VersionInfo\n    )\n{\n    const PCWSTR keyOffset = VersionInfo->Key + PhCountStringZ(VersionInfo->Key) + 1;\n\n    return PTR_ADD_OFFSET(VersionInfo, ALIGN_UP(PTR_SUB_OFFSET(keyOffset, VersionInfo), ULONG));\n}\n\nNTSTATUS PhGetFileVersionInfoKey(\n    _In_ PVS_VERSION_INFO_STRUCT32 VersionInfo,\n    _In_ SIZE_T KeyLength,\n    _In_ PCWSTR Key,\n    _Out_opt_ PVOID* Buffer\n    )\n{\n    PVOID value;\n    ULONG valueOffset;\n    PVS_VERSION_INFO_STRUCT32 child;\n\n    if (!(value = PhGetFileVersionInfoValue(VersionInfo)))\n        return STATUS_NOT_FOUND;\n\n    valueOffset = VersionInfo->ValueLength * (VersionInfo->Type ? sizeof(WCHAR) : sizeof(CHAR));\n    child = PTR_ADD_OFFSET(value, ALIGN_UP(valueOffset, ULONG));\n\n    while ((ULONG_PTR)child < (ULONG_PTR)PTR_ADD_OFFSET(VersionInfo, VersionInfo->Length))\n    {\n        if (_wcsnicmp(child->Key, Key, KeyLength) == 0 && child->Key[KeyLength] == UNICODE_NULL)\n        {\n            if (Buffer)\n                *Buffer = child;\n\n            return STATUS_SUCCESS;\n        }\n\n        if (child->Length == 0)\n            break;\n\n        child = PTR_ADD_OFFSET(child, ALIGN_UP(child->Length, ULONG));\n    }\n\n    return STATUS_NOT_FOUND;\n}\n\nNTSTATUS PhGetFileVersionVarFileInfoValue(\n    _In_ PVOID VersionInfo,\n    _In_ PCPH_STRINGREF KeyName,\n    _Out_opt_ PVOID* Buffer,\n    _Out_opt_ PULONG BufferLength\n    )\n{\n    static CONST PH_STRINGREF varfileBlockName = PH_STRINGREF_INIT(L\"VarFileInfo\");\n    PVS_VERSION_INFO_STRUCT32 varfileBlockInfo;\n    PVS_VERSION_INFO_STRUCT32 varfileBlockValue;\n    NTSTATUS status;\n\n    status = PhGetFileVersionInfoKey(\n        VersionInfo,\n        varfileBlockName.Length / sizeof(WCHAR),\n        varfileBlockName.Buffer,\n        &varfileBlockInfo\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetFileVersionInfoKey(\n            varfileBlockInfo,\n            KeyName->Length / sizeof(WCHAR),\n            KeyName->Buffer,\n            &varfileBlockValue\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            if (BufferLength)\n                *BufferLength = varfileBlockValue->ValueLength;\n            if (Buffer)\n                *Buffer = PhGetFileVersionInfoValue(varfileBlockValue);\n        }\n    }\n\n    return status;\n}\n\nVS_FIXEDFILEINFO* PhGetFileVersionFixedInfo(\n    _In_ PVOID VersionInfo\n    )\n{\n    VS_FIXEDFILEINFO* fileInfo;\n\n    fileInfo = PhGetFileVersionInfoValue(VersionInfo);\n\n    if (fileInfo && fileInfo->dwSignature == VS_FFI_SIGNATURE)\n    {\n        return fileInfo;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\n/**\n * Retrieves the language ID and code page used by a version information block.\n *\n * \\param VersionInfo The version information block.\n */\nULONG PhGetFileVersionInfoLangCodePage(\n    _In_ PVOID VersionInfo\n    )\n{\n    PLANGANDCODEPAGE codePage;\n    ULONG codePageLength;\n\n    if (NT_SUCCESS(PhGetFileVersionVarFileInfoValueZ(VersionInfo, L\"Translation\", &codePage, &codePageLength)))\n    {\n        //for (ULONG i = 0; i < (codePageLength / sizeof(LANGANDCODEPAGE)); i++)\n        return ((ULONG)codePage[0].Language << 16) + codePage[0].CodePage; // Combine the language ID and code page.\n    }\n\n    return (MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) << 16) + 1252;\n}\n\n/**\n * Retrieves a string in a version information block.\n *\n * \\param VersionInfo The version information block.\n * \\param SubBlock The path to the sub-block.\n */\nPPH_STRING PhGetFileVersionInfoString(\n    _In_ PVOID VersionInfo,\n    _In_ PCWSTR SubBlock\n    )\n{\n    NTSTATUS status;\n    PH_STRINGREF name;\n    PWSTR buffer;\n    ULONG length;\n\n    PhInitializeStringRefLongHint(&name, SubBlock);\n\n    status = PhGetFileVersionVarFileInfoValue(\n        VersionInfo,\n        &name,\n        &buffer,\n        &length\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    return PhCreateStringZ2(buffer, length * sizeof(WCHAR));\n}\n\n/**\n * Retrieves a string in a version information block.\n *\n * \\param VersionInfo The version information block.\n * \\param LangCodePage The language ID and code page of the string.\n * \\param KeyName The name of the string.\n */\nPPH_STRING PhGetFileVersionInfoString2(\n    _In_ PVOID VersionInfo,\n    _In_ ULONG LangCodePage,\n    _In_ PCPH_STRINGREF KeyName\n    )\n{\n    static CONST PH_STRINGREF blockInfoName = PH_STRINGREF_INIT(L\"StringFileInfo\");\n    PVS_VERSION_INFO_STRUCT32 blockStringInfo;\n    PVS_VERSION_INFO_STRUCT32 blockLangInfo;\n    PVS_VERSION_INFO_STRUCT32 stringNameBlockInfo;\n    NTSTATUS status;\n    PVOID stringNameBlockValue;\n    SIZE_T returnLength;\n    PH_FORMAT format[3];\n    WCHAR langNameString[65];\n\n    status = PhGetFileVersionInfoKey(\n        VersionInfo,\n        blockInfoName.Length / sizeof(WCHAR),\n        blockInfoName.Buffer,\n        &blockStringInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    PhInitFormatX(&format[0], LangCodePage);\n    format[0].Type |= FormatPadZeros | FormatUpperCase;\n    format[0].Width = 8;\n\n    if (!PhFormatToBuffer(format, 1, langNameString, sizeof(langNameString), &returnLength))\n        return NULL;\n\n    status = PhGetFileVersionInfoKey(\n        blockStringInfo,\n        returnLength / sizeof(WCHAR) - sizeof(ANSI_NULL),\n        langNameString,\n        &blockLangInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    status = PhGetFileVersionInfoKey(\n        blockLangInfo,\n        KeyName->Length / sizeof(WCHAR),\n        KeyName->Buffer,\n        &stringNameBlockInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    if (!(stringNameBlockValue = PhGetFileVersionInfoValue(stringNameBlockInfo)))\n        return NULL;\n\n    return PhCreateStringZ2(\n        stringNameBlockValue,\n        stringNameBlockInfo->ValueLength * sizeof(WCHAR)\n        );\n}\n\nPPH_STRING PhGetFileVersionInfoStringEx(\n    _In_ PVOID VersionInfo,\n    _In_ ULONG LangCodePage,\n    _In_ PCPH_STRINGREF KeyName\n    )\n{\n    PPH_STRING string;\n\n    // Use the default language code page.\n    if (string = PhGetFileVersionInfoString2(VersionInfo, LangCodePage, KeyName))\n        return string;\n\n    // Use the windows-1252 code page.\n    if (string = PhGetFileVersionInfoString2(VersionInfo, (LangCodePage & 0xffff0000) + 1252, KeyName))\n        return string;\n\n    // Use the UTF-16 code page.\n    if (string = PhGetFileVersionInfoString2(VersionInfo, (LangCodePage & 0xffff0000) + 1200, KeyName))\n        return string;\n\n    // Use the default language (US English).\n    if (string = PhGetFileVersionInfoString2(VersionInfo, (MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) << 16) + 1252, KeyName))\n        return string;\n\n    // Use the default language (US English).\n    if (string = PhGetFileVersionInfoString2(VersionInfo, (MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) << 16) + 1200, KeyName))\n        return string;\n\n    // Use the default language (US English).\n    if (string = PhGetFileVersionInfoString2(VersionInfo, (MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) << 16) + 0, KeyName))\n        return string;\n\n    return NULL;\n}\n\nVOID PhpGetImageVersionInfoFields(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PVOID VersionInfo,\n    _In_ ULONG LangCodePage\n    )\n{\n    static CONST PH_STRINGREF companyName = PH_STRINGREF_INIT(L\"CompanyName\");\n    static CONST PH_STRINGREF fileDescription = PH_STRINGREF_INIT(L\"FileDescription\");\n    static CONST PH_STRINGREF productName = PH_STRINGREF_INIT(L\"ProductName\");\n\n    ImageVersionInfo->CompanyName = PhGetFileVersionInfoStringEx(VersionInfo, LangCodePage, &companyName);\n    ImageVersionInfo->FileDescription = PhGetFileVersionInfoStringEx(VersionInfo, LangCodePage, &fileDescription);\n    ImageVersionInfo->ProductName = PhGetFileVersionInfoStringEx(VersionInfo, LangCodePage, &productName);\n}\n\nVOID PhpGetImageVersionVersionString(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PVOID VersionInfo\n    )\n{\n    VS_FIXEDFILEINFO* rootBlock;\n\n    // The version information is language-independent and must be read from the root block.\n    if (rootBlock = PhGetFileVersionFixedInfo(VersionInfo))\n    {\n        PH_FORMAT fileVersionFormat[7];\n\n        PhInitFormatU(&fileVersionFormat[0], HIWORD(rootBlock->dwFileVersionMS));\n        PhInitFormatC(&fileVersionFormat[1], L'.');\n        PhInitFormatU(&fileVersionFormat[2], LOWORD(rootBlock->dwFileVersionMS));\n        PhInitFormatC(&fileVersionFormat[3], L'.');\n        PhInitFormatU(&fileVersionFormat[4], HIWORD(rootBlock->dwFileVersionLS));\n        PhInitFormatC(&fileVersionFormat[5], L'.');\n        PhInitFormatU(&fileVersionFormat[6], LOWORD(rootBlock->dwFileVersionLS));\n\n        ImageVersionInfo->FileVersion = PhFormat(fileVersionFormat, RTL_NUMBER_OF(fileVersionFormat), 64);\n    }\n    else\n    {\n        ImageVersionInfo->FileVersion = NULL;\n    }\n}\n\nVOID PhpGetImageVersionVersionStringEx(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PVOID VersionInfo,\n    _In_ ULONG LangCodePage\n    )\n{\n    static CONST PH_STRINGREF fileVersion = PH_STRINGREF_INIT(L\"FileVersion\");\n    VS_FIXEDFILEINFO* rootBlock;\n    PPH_STRING versionString;\n\n    if (versionString = PhGetFileVersionInfoStringEx(VersionInfo, LangCodePage, &fileVersion))\n    {\n        ImageVersionInfo->FileVersion = versionString;\n        return;\n    }\n\n    if (rootBlock = PhGetFileVersionFixedInfo(VersionInfo))\n    {\n        PH_FORMAT fileVersionFormat[7];\n\n        PhInitFormatU(&fileVersionFormat[0], HIWORD(rootBlock->dwFileVersionMS));\n        PhInitFormatC(&fileVersionFormat[1], L'.');\n        PhInitFormatU(&fileVersionFormat[2], LOWORD(rootBlock->dwFileVersionMS));\n        PhInitFormatC(&fileVersionFormat[3], L'.');\n        PhInitFormatU(&fileVersionFormat[4], HIWORD(rootBlock->dwFileVersionLS));\n        PhInitFormatC(&fileVersionFormat[5], L'.');\n        PhInitFormatU(&fileVersionFormat[6], LOWORD(rootBlock->dwFileVersionLS));\n\n        ImageVersionInfo->FileVersion = PhFormat(fileVersionFormat, RTL_NUMBER_OF(fileVersionFormat), 64);\n    }\n    else\n    {\n        ImageVersionInfo->FileVersion = NULL;\n    }\n}\n\n/**\n * Initializes a structure with version information.\n *\n * \\param ImageVersionInfo The version information structure.\n * \\param FileName The file name of an image.\n */\nNTSTATUS PhInitializeImageVersionInfo(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PCWSTR FileName\n    )\n{\n    NTSTATUS status;\n    PVOID versionInfo;\n    ULONG langCodePage;\n\n    status = PhGetFileVersionInfo(FileName, &versionInfo);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    langCodePage = PhGetFileVersionInfoLangCodePage(versionInfo);\n    PhpGetImageVersionVersionString(ImageVersionInfo, versionInfo);\n    PhpGetImageVersionInfoFields(ImageVersionInfo, versionInfo, langCodePage);\n    PhFree(versionInfo);\n\n    return status;\n}\n\nNTSTATUS PhInitializeImageVersionInfoEx(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN ExtendedVersionInfo\n    )\n{\n    NTSTATUS status;\n    PVOID versionInfo;\n    ULONG langCodePage;\n\n    status = PhGetFileVersionInfoEx(FileName, &versionInfo);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    langCodePage = PhGetFileVersionInfoLangCodePage(versionInfo);\n    if (ExtendedVersionInfo)\n        PhpGetImageVersionVersionStringEx(ImageVersionInfo, versionInfo, langCodePage);\n    else\n        PhpGetImageVersionVersionString(ImageVersionInfo, versionInfo);\n    PhpGetImageVersionInfoFields(ImageVersionInfo, versionInfo, langCodePage);\n    PhFree(versionInfo);\n\n    return status;\n}\n\n/**\n * Frees a version information structure initialized by PhInitializeImageVersionInfo().\n *\n * \\param ImageVersionInfo The version information structure.\n */\nVOID PhDeleteImageVersionInfo(\n    _Inout_ PPH_IMAGE_VERSION_INFO ImageVersionInfo\n    )\n{\n    if (ImageVersionInfo->CompanyName) PhDereferenceObject(ImageVersionInfo->CompanyName);\n    if (ImageVersionInfo->FileDescription) PhDereferenceObject(ImageVersionInfo->FileDescription);\n    if (ImageVersionInfo->FileVersion) PhDereferenceObject(ImageVersionInfo->FileVersion);\n    if (ImageVersionInfo->ProductName) PhDereferenceObject(ImageVersionInfo->ProductName);\n}\n\nPPH_STRING PhFormatImageVersionInfo(\n    _In_opt_ PPH_STRING FileName,\n    _In_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_opt_ PCPH_STRINGREF Indent,\n    _In_opt_ ULONG LineLimit\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n\n    if (LineLimit == 0)\n        LineLimit = ULONG_MAX;\n\n    PhInitializeStringBuilder(&stringBuilder, 40);\n\n    // File name\n\n    if (!PhIsNullOrEmptyString(FileName))\n    {\n        PPH_STRING temp;\n\n        if (Indent) PhAppendStringBuilder(&stringBuilder, Indent);\n\n        temp = PhEllipsisStringPath(FileName, LineLimit);\n        PhAppendStringBuilder(&stringBuilder, &temp->sr);\n        PhDereferenceObject(temp);\n        PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n    }\n\n    // File description & version\n\n    if (!(\n        PhIsNullOrEmptyString(ImageVersionInfo->FileDescription) &&\n        PhIsNullOrEmptyString(ImageVersionInfo->FileVersion)\n        ))\n    {\n        PPH_STRING tempDescription = NULL;\n        PPH_STRING tempVersion = NULL;\n        ULONG limitForDescription;\n        ULONG limitForVersion;\n\n        if (LineLimit != ULONG_MAX)\n        {\n            limitForVersion = (LineLimit - 1) / 4; // 1/4 space for version (and space character)\n            limitForDescription = LineLimit - limitForVersion;\n        }\n        else\n        {\n            limitForDescription = ULONG_MAX;\n            limitForVersion = ULONG_MAX;\n        }\n\n        if (!PhIsNullOrEmptyString(ImageVersionInfo->FileDescription))\n        {\n            tempDescription = PhEllipsisString(\n                ImageVersionInfo->FileDescription,\n                limitForDescription\n                );\n        }\n\n        if (!PhIsNullOrEmptyString(ImageVersionInfo->FileVersion))\n        {\n            tempVersion = PhEllipsisString(\n                ImageVersionInfo->FileVersion,\n                limitForVersion\n                );\n        }\n\n        if (Indent) PhAppendStringBuilder(&stringBuilder, Indent);\n\n        if (tempDescription)\n        {\n            PhAppendStringBuilder(&stringBuilder, &tempDescription->sr);\n\n            if (tempVersion)\n                PhAppendCharStringBuilder(&stringBuilder, L' ');\n        }\n\n        if (tempVersion)\n            PhAppendStringBuilder(&stringBuilder, &tempVersion->sr);\n\n        if (tempDescription)\n            PhDereferenceObject(tempDescription);\n        if (tempVersion)\n            PhDereferenceObject(tempVersion);\n\n        PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n    }\n\n    // File company\n\n    if (!PhIsNullOrEmptyString(ImageVersionInfo->CompanyName))\n    {\n        PPH_STRING temp;\n\n        if (Indent) PhAppendStringBuilder(&stringBuilder, Indent);\n\n        temp = PhEllipsisString(ImageVersionInfo->CompanyName, LineLimit);\n        PhAppendStringBuilder(&stringBuilder, &temp->sr);\n        PhDereferenceObject(temp);\n        PhAppendCharStringBuilder(&stringBuilder, L'\\n');\n    }\n\n    // Remove the extra newline.\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\ntypedef struct _PH_FILE_VERSIONINFO_CACHE_ENTRY\n{\n    PPH_STRING FileName;\n    PPH_STRING CompanyName;\n    PPH_STRING FileDescription;\n    PPH_STRING FileVersion;\n    PPH_STRING ProductName;\n} PH_FILE_VERSIONINFO_CACHE_ENTRY, *PPH_FILE_VERSIONINFO_CACHE_ENTRY;\n\nstatic PPH_HASHTABLE PhpImageVersionInfoCacheHashtable = NULL;\nstatic PH_QUEUED_LOCK PhpImageVersionInfoCacheLock = PH_QUEUED_LOCK_INIT;\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nstatic BOOLEAN PhpImageVersionInfoCacheHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_FILE_VERSIONINFO_CACHE_ENTRY entry1 = Entry1;\n    PPH_FILE_VERSIONINFO_CACHE_ENTRY entry2 = Entry2;\n\n    return PhEqualString(entry1->FileName, entry2->FileName, FALSE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nstatic ULONG PhpImageVersionInfoCacheHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_FILE_VERSIONINFO_CACHE_ENTRY entry = Entry;\n\n    return PhHashStringRefEx(&entry->FileName->sr, FALSE, PH_STRING_HASH_XXH32);\n}\n\nNTSTATUS PhInitializeImageVersionInfoCached(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PPH_STRING FileName,\n    _In_ BOOLEAN IsSubsystemProcess,\n    _In_ BOOLEAN ExtendedVersion\n    )\n{\n    PH_IMAGE_VERSION_INFO versionInfo = { 0 };\n    PH_FILE_VERSIONINFO_CACHE_ENTRY newEntry;\n\n    if (PhpImageVersionInfoCacheHashtable)\n    {\n        PPH_FILE_VERSIONINFO_CACHE_ENTRY entry;\n        PH_FILE_VERSIONINFO_CACHE_ENTRY lookupEntry;\n\n        lookupEntry.FileName = FileName;\n\n        PhAcquireQueuedLockShared(&PhpImageVersionInfoCacheLock);\n        entry = PhFindEntryHashtable(PhpImageVersionInfoCacheHashtable, &lookupEntry);\n        PhReleaseQueuedLockShared(&PhpImageVersionInfoCacheLock);\n\n        if (entry)\n        {\n            PhSetReference(&ImageVersionInfo->CompanyName, entry->CompanyName);\n            PhSetReference(&ImageVersionInfo->FileDescription, entry->FileDescription);\n            PhSetReference(&ImageVersionInfo->FileVersion, entry->FileVersion);\n            PhSetReference(&ImageVersionInfo->ProductName, entry->ProductName);\n            return STATUS_SUCCESS;\n        }\n    }\n\n    if (IsSubsystemProcess)\n    {\n        if (!NT_SUCCESS(PhInitializeLxssImageVersionInfo(&versionInfo, &FileName->sr)))\n        {\n            // Note: If the function fails the version info is empty. For extra performance\n            // we still update the cache with a reference to the filename (without version info)\n            // and just return the empty result from the cache instead of loading the same file again.\n            // We flush every few hours so the cache doesn't waste memory or become state. (dmex)\n        }\n    }\n    else\n    {\n        if (!NT_SUCCESS(PhInitializeImageVersionInfoEx(&versionInfo, &FileName->sr, ExtendedVersion)))\n        {\n            // Note: If the function fails the version info is empty. For extra performance\n            // we still update the cache with a reference to the filename (without version info)\n            // and just return the empty result from the cache instead of loading the same file again.\n            // We flush every few hours so the cache doesn't waste memory or become state. (dmex)\n        }\n    }\n\n    if (!PhpImageVersionInfoCacheHashtable)\n    {\n        PhpImageVersionInfoCacheHashtable = PhCreateHashtable(\n            sizeof(PH_FILE_VERSIONINFO_CACHE_ENTRY),\n            PhpImageVersionInfoCacheHashtableEqualFunction,\n            PhpImageVersionInfoCacheHashtableHashFunction,\n            100\n            );\n    }\n\n    PhSetReference(&newEntry.FileName, FileName);\n    PhSetReference(&newEntry.CompanyName, versionInfo.CompanyName);\n    PhSetReference(&newEntry.FileDescription, versionInfo.FileDescription);\n    PhSetReference(&newEntry.FileVersion, versionInfo.FileVersion);\n    PhSetReference(&newEntry.ProductName, versionInfo.ProductName);\n\n    PhAcquireQueuedLockExclusive(&PhpImageVersionInfoCacheLock);\n    PhAddEntryHashtable(PhpImageVersionInfoCacheHashtable, &newEntry);\n    PhReleaseQueuedLockExclusive(&PhpImageVersionInfoCacheLock);\n\n    ImageVersionInfo->CompanyName = versionInfo.CompanyName;\n    ImageVersionInfo->FileDescription = versionInfo.FileDescription;\n    ImageVersionInfo->FileVersion = versionInfo.FileVersion;\n    ImageVersionInfo->ProductName = versionInfo.ProductName;\n    return STATUS_SUCCESS;\n}\n\nVOID PhFlushImageVersionInfoCache(\n    VOID\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_FILE_VERSIONINFO_CACHE_ENTRY entry;\n\n    if (!PhpImageVersionInfoCacheHashtable)\n        return;\n\n    PhAcquireQueuedLockExclusive(&PhpImageVersionInfoCacheLock);\n\n    PhBeginEnumHashtable(PhpImageVersionInfoCacheHashtable, &enumContext);\n\n    while (entry = PhNextEnumHashtable(&enumContext))\n    {\n        if (entry->FileName) PhDereferenceObject(entry->FileName);\n        if (entry->CompanyName) PhDereferenceObject(entry->CompanyName);\n        if (entry->FileDescription) PhDereferenceObject(entry->FileDescription);\n        if (entry->FileVersion) PhDereferenceObject(entry->FileVersion);\n        if (entry->ProductName) PhDereferenceObject(entry->ProductName);\n    }\n\n    PhClearReference(&PhpImageVersionInfoCacheHashtable);\n\n    PhpImageVersionInfoCacheHashtable = PhCreateHashtable(\n        sizeof(PH_FILE_VERSIONINFO_CACHE_ENTRY),\n        PhpImageVersionInfoCacheHashtableEqualFunction,\n        PhpImageVersionInfoCacheHashtableHashFunction,\n        100\n        );\n\n    PhReleaseQueuedLockExclusive(&PhpImageVersionInfoCacheLock);\n}\n\n/**\n * Retrieves the full path and file name of the specified file.\n *\n * \\param FileName The name of the file.\n * \\param BufferLength The size of the buffer to receive the null-terminated string for the drive and path.\n * \\param Buffer A pointer to a buffer that receives the null-terminated string for the drive and path.\n * \\param FilePart A variable which receives the index of the base name.\n * \\param BytesRequired The length of the string including the terminating null character.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetFullPathName(\n    _In_ PCWSTR FileName,\n    _In_ SIZE_T BufferLength,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _Out_opt_ PWSTR* FilePart,\n    _Out_opt_ PULONG BytesRequired\n    )\n{\n    NTSTATUS status;\n    ULONG bufferLength;\n    ULONG bytesRequired;\n\n    status = RtlSizeTToULong(\n        BufferLength,\n        &bufferLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    bytesRequired = 0;\n    status = RtlGetFullPathName_UEx(\n        FileName,\n        bufferLength, // * sizeof(WCHAR)\n        Buffer,\n        FilePart,\n        &bytesRequired\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (BytesRequired)\n    {\n        *BytesRequired = bytesRequired; /* / sizeof(WCHAR) */\n    }\n\n    if (BufferLength < bytesRequired)\n        return STATUS_BUFFER_TOO_SMALL;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Gets an absolute file name.\n *\n * \\param FileName A file name.\n * \\param FullPath An absolute file name, or NULL if the function failed.\n * \\param IndexOfFileName A variable which receives the index of the base name.\n *\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetFullPath(\n    _In_ PCWSTR FileName,\n    _Out_ PPH_STRING *FullPath,\n    _Out_opt_ PULONG IndexOfFileName\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fullPath;\n    ULONG fullPathLength;\n    ULONG returnLength = 0;\n    PWSTR filePart = NULL;\n\n    fullPathLength = DOS_MAX_PATH_LENGTH;\n    fullPath = PhCreateStringEx(NULL, fullPathLength);\n\n    status = PhGetFullPathName(\n        FileName,\n        fullPath->Length + sizeof(UNICODE_NULL),\n        fullPath->Buffer,\n        &filePart,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL && returnLength > sizeof(UNICODE_NULL))\n    {\n        PhDereferenceObject(fullPath);\n        fullPathLength = returnLength - sizeof(UNICODE_NULL);\n        fullPath = PhCreateStringEx(NULL, fullPathLength);\n\n        status = PhGetFullPathName(\n            FileName,\n            fullPath->Length + sizeof(UNICODE_NULL),\n            fullPath->Buffer,\n            &filePart,\n            &returnLength\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(fullPath);\n        return status;\n    }\n\n    PhTrimToNullTerminatorString(fullPath);\n    *FullPath = fullPath;\n\n    if (IndexOfFileName)\n    {\n        if (filePart)\n        {\n            // The path points to a file.\n            *IndexOfFileName = (ULONG)(filePart - fullPath->Buffer);\n        }\n        else\n        {\n            // The path points to a directory.\n            *IndexOfFileName = ULONG_MAX;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Expands environment variables in a string.\n *\n * \\param String The string.\n */\nPPH_STRING PhExpandEnvironmentStrings(\n    _In_ PCPH_STRINGREF String\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING inputString;\n    UNICODE_STRING outputString;\n    PPH_STRING string;\n    ULONG bufferLength;\n\n    if (!PhStringRefToUnicodeString(String, &inputString))\n        return NULL;\n\n    bufferLength = 0x100;\n    string = PhCreateStringEx(NULL, bufferLength);\n    outputString.MaximumLength = (USHORT)bufferLength;\n    outputString.Length = 0;\n    outputString.Buffer = string->Buffer;\n\n    status = RtlExpandEnvironmentStrings_U(\n        NULL,\n        &inputString,\n        &outputString,\n        &bufferLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhDereferenceObject(string);\n        string = PhCreateStringEx(NULL, bufferLength);\n        outputString.MaximumLength = (USHORT)bufferLength;\n        outputString.Length = 0;\n        outputString.Buffer = string->Buffer;\n\n        status = RtlExpandEnvironmentStrings_U(\n            NULL,\n            &inputString,\n            &outputString,\n            &bufferLength\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    string->Length = outputString.Length;\n    string->Buffer[string->Length / sizeof(WCHAR)] = UNICODE_NULL; // make sure there is a null terminator\n\n    return string;\n}\n\n/**\n * Gets the base name from a file name.\n *\n * \\param FileName The file name.\n */\nPPH_STRING PhGetBaseName(\n    _In_ PPH_STRING FileName\n    )\n{\n    PH_STRINGREF pathPart;\n    PH_STRINGREF baseNamePart;\n\n    if (!PhSplitStringRefAtLastChar(&FileName->sr, OBJ_NAME_PATH_SEPARATOR, &pathPart, &baseNamePart))\n    {\n        return PhReferenceObject(FileName);\n    }\n\n    return PhCreateString2(&baseNamePart);\n}\n\n/**\n * Changes the extension of the base name in a file path.\n *\n * This function locates the last path separator and the last dot in the file name.\n * If both are found and the dot is after the last path separator, it replaces the extension\n * with the specified new extension. Otherwise, it appends the new extension to the file name.\n *\n * \\param FileName The input file name as a string reference.\n * \\param FileExtension The new file extension as a string reference.\n * \\return A new string with the base name's extension changed, or the original file name with the extension appended if no dot is found.\n */\nPPH_STRING PhGetBaseNameChangeExtension(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PCPH_STRINGREF FileExtension\n    )\n{\n    ULONG_PTR indexOfBackslash;\n    ULONG_PTR indexOfLastDot;\n    PH_STRINGREF baseFileName;\n    PH_STRINGREF baseFilePath;\n\n    if ((indexOfBackslash = PhFindLastCharInStringRef(FileName, OBJ_NAME_PATH_SEPARATOR, FALSE)) == SIZE_MAX)\n        return PhConcatStringRef2(FileName, FileExtension);\n    if ((indexOfLastDot = PhFindLastCharInStringRef(FileName, L'.', FALSE)) == SIZE_MAX)\n        return PhConcatStringRef2(FileName, FileExtension);\n    if (indexOfLastDot < indexOfBackslash)\n        return PhConcatStringRef2(FileName, FileExtension);\n\n    baseFileName.Buffer = FileName->Buffer + indexOfBackslash + 1;\n    baseFileName.Length = (indexOfLastDot - indexOfBackslash - 1) * sizeof(WCHAR);\n    baseFilePath.Buffer = FileName->Buffer;\n    baseFilePath.Length = (indexOfBackslash + 1) * sizeof(WCHAR);\n\n    return PhConcatStringRef3(&baseFilePath, &baseFileName, FileExtension);\n}\n\n/**\n * Splits a file path into its base path and base file name components.\n *\n * This function separates the input file name into the directory path and the file name.\n * If both output pointers are provided, both components are set if available.\n * If only one output pointer is provided, only that component is set.\n *\n * \\param FileName The input file name as a string reference.\n * \\param BasePathName Optional pointer to receive the base path component.\n * \\param BaseFileName Optional pointer to receive the base file name component.\n * \\return TRUE if the split was successful and the requested components are available, otherwise FALSE.\n */\n_Success_(return)\nBOOLEAN PhGetBasePath(\n    _In_ PCPH_STRINGREF FileName,\n    _Out_opt_ PPH_STRINGREF BasePathName,\n    _Out_opt_ PPH_STRINGREF BaseFileName\n    )\n{\n    PH_STRINGREF basePathPart;\n    PH_STRINGREF baseNamePart;\n\n    if (!PhSplitStringRefAtLastChar(FileName, OBJ_NAME_PATH_SEPARATOR, &basePathPart, &baseNamePart))\n        return FALSE;\n\n    if (BasePathName && BaseFileName)\n    {\n        if (basePathPart.Length && baseNamePart.Length)\n        {\n            BasePathName->Length = basePathPart.Length;\n            BasePathName->Buffer = basePathPart.Buffer;\n\n            BaseFileName->Length = baseNamePart.Length;\n            BaseFileName->Buffer = baseNamePart.Buffer;\n            return TRUE;\n        }\n\n        return FALSE;\n    }\n\n    if (BasePathName && basePathPart.Length)\n    {\n        BasePathName->Length = basePathPart.Length;\n        BasePathName->Buffer = basePathPart.Buffer;\n        return TRUE;\n    }\n\n    if (BaseFileName && baseNamePart.Length)\n    {\n        BaseFileName->Length = baseNamePart.Length;\n        BaseFileName->Buffer = baseNamePart.Buffer;\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\n/**\n * Gets the parent directory from a file name.\n *\n * \\param FileName The file name.\n */\nPPH_STRING PhGetBaseDirectory(\n    _In_ PPH_STRING FileName\n    )\n{\n    PH_STRINGREF pathPart;\n    PH_STRINGREF baseNamePart;\n\n    if (!PhSplitStringRefAtLastChar(&FileName->sr, OBJ_NAME_PATH_SEPARATOR, &pathPart, &baseNamePart))\n        return NULL;\n\n    return PhCreateString2(&pathPart);\n}\n\n/**\n * Retrieves the system directory path.\n */\nPPH_STRING PhGetSystemDirectory(\n    VOID\n    )\n{\n    static CONST PH_STRINGREF system32String = PH_STRINGREF_INIT(L\"\\\\System32\");\n    static PPH_STRING cachedSystemDirectory = NULL;\n    PH_STRINGREF systemRootString;\n    PPH_STRING systemDirectory;\n    PPH_STRING previousSystemDirectory;\n\n    // Use the cached value if possible.\n\n    if (systemDirectory = ReadPointerAcquire(&cachedSystemDirectory))\n        return PhReferenceObject(systemDirectory);\n\n    PhGetSystemRoot(&systemRootString);\n    systemDirectory = PhConcatStringRef2(&systemRootString, &system32String);\n\n    PhReferenceObject(systemDirectory);\n\n    if (previousSystemDirectory = InterlockedExchangePointer(&cachedSystemDirectory, systemDirectory))\n    {\n        PhDereferenceObject(previousSystemDirectory);\n    }\n\n    return systemDirectory;\n}\n\n/**\n * Retrieves the path to the Windows System32 directory in Win32 format, optionally appending a subpath.\n *\n * \\param AppendPath Optional string to append to the System32 directory path.\n * \\return A pointer to a string containing the full path to the System32 directory (with optional appended path).\n */\nPPH_STRING PhGetSystemDirectoryWin32(\n    _In_opt_ PCPH_STRINGREF AppendPath\n    )\n{\n    static CONST PH_STRINGREF system32String = PH_STRINGREF_INIT(L\"\\\\System32\");\n    PH_STRINGREF systemRootString;\n\n    PhGetSystemRoot(&systemRootString);\n\n    if (AppendPath)\n    {\n        return PhConcatStringRef3(&systemRootString, &system32String, AppendPath);\n    }\n\n    return PhConcatStringRef2(&systemRootString, &system32String);\n}\n\n/**\n * Retrieves the Windows system root directory path.\n *\n * This function returns the system root directory path as a PH_STRINGREF.\n * The value is cached after the first call for subsequent use.\n * The returned string does not include a trailing backslash.\n */\nVOID PhGetSystemRoot(\n    _Out_ PPH_STRINGREF SystemRoot\n    )\n{\n    static PH_STRINGREF systemRoot;\n    PH_STRINGREF localSystemRoot;\n    SIZE_T count;\n\n    if (systemRoot.Buffer)\n    {\n        *SystemRoot = systemRoot;\n        return;\n    }\n\n    localSystemRoot.Buffer = RtlGetNtSystemRoot();\n    count = PhCountStringZ(localSystemRoot.Buffer);\n    localSystemRoot.Length = count * sizeof(WCHAR);\n\n    // Make sure the system root string doesn't have a trailing backslash.\n    if (localSystemRoot.Buffer[count - 1] == OBJ_NAME_PATH_SEPARATOR)\n        localSystemRoot.Length -= sizeof(WCHAR);\n\n    *SystemRoot = localSystemRoot;\n\n    systemRoot.Length = localSystemRoot.Length;\n    MemoryBarrier();\n    systemRoot.Buffer = localSystemRoot.Buffer;\n}\n\n/**\n * Retrieves the native NT path of the Windows system root directory.\n *\n * This function returns the system root directory path in native NT format as a PH_STRINGREF.\n * The value is cached after the first call for subsequent use.\n */\nVOID PhGetNtSystemRoot(\n    _Out_ PPH_STRINGREF NtSystemRoot\n    )\n{\n    static PPH_STRING systemRootNative;\n\n    if (PhIsNullOrEmptyString(systemRootNative))\n    {\n        PH_STRINGREF localSystemRoot;\n\n        PhGetSystemRoot(&localSystemRoot);\n        systemRootNative = PhDosPathNameToNtPathName(&localSystemRoot);\n    }\n\n    *NtSystemRoot = systemRootNative->sr;\n}\n\n/**\n * Retrieves the Windows directory path.\n */\nPPH_STRING PhGetWindowsDirectory(\n    _In_opt_ PCPH_STRINGREF AppendPath\n    )\n{\n    PH_STRINGREF systemRoot;\n    PPH_STRING systemRootNative;\n\n    PhGetSystemRoot(&systemRoot);\n    systemRootNative = PhDosPathNameToNtPathName(&systemRoot);\n\n    if (systemRootNative && AppendPath)\n    {\n        PhMoveReference(&systemRootNative, PhConcatStringRef2(&systemRootNative->sr, AppendPath));\n    }\n\n    return systemRootNative;\n}\n\n/**\n * Retrieves the Windows directory path.\n */\nPPH_STRING PhGetWindowsDirectoryWin32(\n    _In_opt_ PCPH_STRINGREF AppendPath\n    )\n{\n    PH_STRINGREF systemRoot;\n\n    PhGetSystemRoot(&systemRoot);\n\n    if (AppendPath)\n    {\n        return PhConcatStringRef2(&systemRoot, AppendPath);\n    }\n\n    return PhCreateString2(&systemRoot);\n}\n\n/**\n * Retrieves the native file name of the current process image.\n */\nPPH_STRING PhGetApplicationFileName(\n    VOID\n    )\n{\n    static PPH_STRING cachedFileName = NULL;\n    PPH_STRING fileName;\n\n    if (fileName = ReadPointerAcquire(&cachedFileName))\n    {\n        return PhReferenceObject(fileName);\n    }\n\n    if (!NT_SUCCESS(PhGetProcessImageFileName(NtCurrentProcess(), &fileName)))\n    {\n        if (!NT_SUCCESS(PhGetProcessImageFileNameByProcessId(NtCurrentProcessId(), &fileName)))\n        {\n            if (!NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), NtCurrentImageBase(), &fileName)))\n            {\n                if (fileName = PhGetDllFileName(NtCurrentImageBase(), NULL))\n                {\n                    PPH_STRING fullPath;\n\n                    if (NT_SUCCESS(PhGetFullPath(PhGetString(fileName), &fullPath, NULL)))\n                    {\n                        PhMoveReference(&fileName, fullPath);\n                    }\n\n                    PhMoveReference(&fileName, PhDosPathNameToNtPathName(&fileName->sr));\n                }\n            }\n        }\n    }\n\n    // Update the cached file name with atomic semantics (dmex)\n    if (!InterlockedCompareExchangePointer(\n        &cachedFileName,\n        fileName,\n        NULL\n        ))\n    {\n        PhReferenceObject(fileName);\n    }\n\n    return fileName;\n}\n\n/**\n * Retrieves the file name of the current process image.\n */\nPPH_STRING PhGetApplicationFileNameWin32(\n    VOID\n    )\n{\n    static PPH_STRING cachedFileName = NULL;\n    PPH_STRING fileName;\n    PPH_STRING string;\n\n    if (fileName = ReadPointerAcquire(&cachedFileName))\n    {\n        return PhReferenceObject(fileName);\n    }\n\n    if (fileName = PhGetDllFileName(NtCurrentImageBase(), NULL))\n    {\n        if (NT_SUCCESS(PhGetFullPath(PhGetString(fileName), &string, NULL)))\n        {\n            PhMoveReference(&fileName, string);\n        }\n    }\n\n    //if (NT_SUCCESS(PhGetProcessImageFileNameWin32(NtCurrentProcess(), &fileName)))\n    //    PhMoveReference(&fileName, PhGetFileName(fileName));\n    //\n    //if (!NT_SUCCESS(PhGetProcessImageFileNameWin32(NtCurrentProcess(), &fileName)))\n    //{\n    //    if (!NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), PhInstanceHandle, &fileName)))\n    //    {\n    //        if (!NT_SUCCESS(PhGetProcessImageFileNameByProcessId(NtCurrentProcessId(), &fileName)))\n    //        {\n    //            PhMoveReference(&fileName, PhGetFileName(fileName));\n    //        }\n    //    }\n\n    if (!InterlockedCompareExchangePointer(\n        &cachedFileName,\n        fileName,\n        NULL\n        ))\n    {\n        PhReferenceObject(fileName);\n    }\n\n    return fileName;\n}\n\n/**\n * Retrieves the directory path of the current process image (native NT path).\n *\n * This function returns the directory containing the executable image of the current process.\n * The result is cached for subsequent calls to improve performance.\n * \\return A pointer to a string containing the directory path.\n */\nPPH_STRING PhGetApplicationDirectory(\n    VOID\n    )\n{\n    static PPH_STRING cachedDirectoryPath = NULL;\n    PPH_STRING directoryPath;\n    PPH_STRING fileName;\n\n    // Read the cached directory path with acquire semantics\n    if (directoryPath = ReadPointerAcquire(&cachedDirectoryPath))\n    {\n        return PhReferenceObject(directoryPath);\n    }\n\n    // Get the application file name\n    if (fileName = PhGetApplicationFileName())\n    {\n        ULONG_PTR indexOfFileName;\n\n        // Find the last path separator in the file name\n        indexOfFileName = PhFindLastCharInString(fileName, 0, OBJ_NAME_PATH_SEPARATOR);\n\n        if (indexOfFileName != SIZE_MAX)\n            indexOfFileName++;\n        else\n            indexOfFileName = 0;\n\n        // Extract the directory path from the file name\n        if (indexOfFileName != 0)\n        {\n            directoryPath = PhSubstring(fileName, 0, indexOfFileName);\n        }\n\n        PhDereferenceObject(fileName);\n    }\n\n    // Atomically set the cached directory path if it is currently NULL\n    if (!InterlockedCompareExchangePointer(\n        &cachedDirectoryPath,\n        directoryPath,\n        NULL\n        ))\n    {\n        PhReferenceObject(directoryPath);\n    }\n\n    return directoryPath;\n}\n\n/**\n * Retrieves the directory path of the current process image (Win32 path).\n *\n * This function returns the directory containing the executable image of the current process,\n * using the Win32 path format. The result is cached for subsequent calls to improve performance.\n * \\return A pointer to a string containing the directory path.\n */\nPPH_STRING PhGetApplicationDirectoryWin32(\n    VOID\n    )\n{\n    static PPH_STRING cachedDirectoryPath = NULL;\n    PPH_STRING directoryPath;\n    PPH_STRING fileName;\n\n    if (directoryPath = ReadPointerAcquire(&cachedDirectoryPath))\n    {\n        return PhReferenceObject(directoryPath);\n    }\n\n    if (fileName = PhGetApplicationFileNameWin32())\n    {\n        ULONG_PTR indexOfFileName;\n\n        indexOfFileName = PhFindLastCharInString(fileName, 0, OBJ_NAME_PATH_SEPARATOR);\n\n        if (indexOfFileName != SIZE_MAX)\n            indexOfFileName++;\n        else\n            indexOfFileName = 0;\n\n        // Extract the directory path from the file name\n        if (indexOfFileName != 0)\n        {\n            directoryPath = PhSubstring(fileName, 0, indexOfFileName);\n        }\n\n        PhDereferenceObject(fileName);\n    }\n\n    // Atomically set the cached directory path if it is currently NULL\n    if (!InterlockedCompareExchangePointer(\n        &cachedDirectoryPath,\n        directoryPath,\n        NULL\n        ))\n    {\n        PhReferenceObject(directoryPath);\n    }\n\n    return directoryPath;\n}\n\n/**\n * Gets the full path to a file in the application's directory.\n *\n * \\param FileName The file name to append to the application directory.\n * \\param NativeFileName TRUE to use the native NT path, FALSE for Win32 path.\n * \\return A pointer to a string containing the full path, or NULL if the directory could not be determined.\n */\nPPH_STRING PhGetApplicationDirectoryFileName(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    PPH_STRING applicationFileName = NULL;\n    PPH_STRING applicationDirectory;\n\n    if (NativeFileName)\n        applicationDirectory = PhGetApplicationDirectory();\n    else\n        applicationDirectory = PhGetApplicationDirectoryWin32();\n\n    if (applicationDirectory)\n    {\n        applicationFileName = PhConcatStringRef2(&applicationDirectory->sr, FileName);\n        PhDereferenceObject(applicationDirectory);\n    }\n\n    return applicationFileName;\n}\n\n/**\n * Gets a temporary file name in the system temporary directory, using a random alpha string.\n *\n * \\return A pointer to a string containing the full path to the temporary file.\n */\nPPH_STRING PhGetTemporaryDirectoryRandomAlphaFileName(\n    VOID\n    )\n{\n    PH_STRINGREF randomAlphaString;\n    WCHAR randomAlphaStringBuffer[33] = L\"\";\n\n    PhGenerateRandomAlphaString(randomAlphaStringBuffer, RTL_NUMBER_OF(randomAlphaStringBuffer));\n    randomAlphaStringBuffer[0] = OBJ_NAME_PATH_SEPARATOR;\n    randomAlphaString.Buffer = randomAlphaStringBuffer;\n    randomAlphaString.Length = sizeof(randomAlphaStringBuffer) - sizeof(UNICODE_NULL);\n\n    return PhGetTemporaryDirectory(&randomAlphaString);\n}\n\n/**\n * Gets the local application data directory for System Informer, optionally appending a file name.\n *\n * \\param FileName The file name to append, or NULL to return the directory only.\n * \\param NativeFileName TRUE to use the native NT path, FALSE for Win32 path.\n * \\return A pointer to a string containing the full path, or NULL if the directory could not be determined.\n */\nPPH_STRING PhGetLocalAppDataDirectory(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    PPH_STRING localAppDataFileName = NULL;\n    PPH_STRING localAppDataDirectory;\n\n    if (localAppDataDirectory = PhGetKnownLocationZ(PH_FOLDERID_LocalAppData, L\"\\\\SystemInformer\\\\\", NativeFileName))\n    {\n        if (!FileName) return localAppDataDirectory;\n        localAppDataFileName = PhConcatStringRef2(&localAppDataDirectory->sr, FileName);\n        PhReferenceObject(localAppDataDirectory);\n    }\n\n    return localAppDataFileName;\n}\n\n/**\n * Gets the roaming application data directory for System Informer, optionally appending a file name.\n *\n * \\param FileName The file name to append, or NULL to return the directory only.\n * \\param NativeFileName TRUE to use the native NT path, FALSE for Win32 path.\n * \\return A pointer to a string containing the full path, or NULL if the directory could not be determined.\n */\nPPH_STRING PhGetRoamingAppDataDirectory(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    PPH_STRING roamingAppDataFileName = NULL;\n    PPH_STRING roamingAppDataDirectory;\n\n    if (roamingAppDataDirectory = PhGetKnownLocationZ(PH_FOLDERID_RoamingAppData, L\"\\\\SystemInformer\\\\\", NativeFileName))\n    {\n        if (!FileName) return roamingAppDataDirectory;\n        roamingAppDataFileName = PhConcatStringRef2(&roamingAppDataDirectory->sr, FileName);\n        PhReferenceObject(roamingAppDataDirectory);\n    }\n\n    return roamingAppDataFileName;\n}\n\n/**\n * Gets the full path to a file in the application's directory.\n *\n * \\param FileName The file name to append to the application directory.\n * \\param NativeFileName TRUE to use the native NT path, FALSE for Win32 path.\n * \\return A pointer to a string containing the full path, or NULL if the directory could not be determined.\n */\nPPH_STRING PhGetApplicationDataFileName(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    PPH_STRING applicationDataFileName;\n\n    // Check the current directory. (dmex)\n\n    if (applicationDataFileName = PhGetApplicationDirectoryFileName(FileName, NativeFileName))\n    {\n        if (NativeFileName)\n        {\n            if (PhDoesFileExist(&applicationDataFileName->sr))\n                return applicationDataFileName;\n        }\n        else\n        {\n            if (PhDoesFileExistWin32(PhGetString(applicationDataFileName)))\n                return applicationDataFileName;\n        }\n\n        PhClearReference(&applicationDataFileName);\n    }\n\n    // Return the appdata directory. (dmex)\n\n    applicationDataFileName = PhGetRoamingAppDataDirectory(FileName, NativeFileName);\n\n    return applicationDataFileName;\n}\n\n#if defined(PH_SHGETFOLDERPATH)\n/**\n * Gets a known location as a file name.\n *\n * \\param Folder A CSIDL value representing the known location.\n * \\param AppendPath A string to append to the folder path.\n */\n//PPH_STRING PhGetKnownLocation(\n//    _In_ ULONG Folder,\n//    _In_opt_ PWSTR AppendPath\n//    )\n//{\n//    PPH_STRING path;\n//    SIZE_T appendPathLength;\n//\n//    if (!SHGetFolderPathW_Import())\n//        return NULL;\n//\n//    if (AppendPath)\n//        appendPathLength = PhCountStringZ(AppendPath) * sizeof(WCHAR);\n//    else\n//        appendPathLength = 0;\n//\n//    path = PhCreateStringEx(NULL, MAX_PATH * sizeof(WCHAR) + appendPathLength);\n//\n//    if (SUCCEEDED(SHGetFolderPathW_Import()(\n//        NULL,\n//        Folder,\n//        NULL,\n//        SHGFP_TYPE_CURRENT,\n//        path->Buffer\n//        )))\n//    {\n//        PhTrimToNullTerminatorString(path);\n//\n//        if (AppendPath)\n//        {\n//            memcpy(&path->Buffer[path->Length / sizeof(WCHAR)], AppendPath, appendPathLength + sizeof(UNICODE_NULL)); // +2 for null terminator\n//            path->Length += appendPathLength;\n//        }\n//\n//        return path;\n//    }\n//\n//    PhDereferenceObject(path);\n//\n//    return NULL;\n//}\n#endif\n\n/**\n * Retrieves the full path of a known folder.\n *\n * \\param Folder A reference that identifies the folder.\n * \\param AppendPath The string to append to the path.\n * \\param NativeFileName A boolean to return the native path or Win32 path.\n */\nPPH_STRING PhGetKnownLocation(\n    _In_ ULONG Folder,\n    _In_opt_ PCPH_STRINGREF AppendPath,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n#if !defined(PH_BUILD_MSIX)\n    switch (Folder)\n    {\n    case PH_FOLDERID_LocalAppData:\n        {\n            static CONST PH_STRINGREF variableName = PH_STRINGREF_INIT(L\"LOCALAPPDATA\");\n            static CONST PH_STRINGREF variableNameProfile = PH_STRINGREF_INIT(L\"USERPROFILE\");\n            NTSTATUS status;\n            PH_STRINGREF variableValue;\n            WCHAR variableBuffer[DOS_MAX_PATH_LENGTH];\n\n            PhInitializeBufferStringRef(&variableValue, variableBuffer, sizeof(variableBuffer));\n\n            status = PhQueryEnvironmentVariableStringRef(\n                NULL,\n                &variableName,\n                &variableValue\n                );\n\n            if (!NT_SUCCESS(status))\n            {\n                status = PhQueryEnvironmentVariableStringRef(\n                    NULL,\n                    &variableNameProfile,\n                    &variableValue\n                    );\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                PPH_STRING fileName;\n\n                if (AppendPath)\n                {\n                    if (NativeFileName)\n                    {\n                        if (fileName = PhDosPathNameToNtPathName(&variableValue))\n                        {\n                            PhMoveReference(&fileName, PhConcatStringRef2(&fileName->sr, AppendPath));\n                        }\n                        else\n                        {\n                            fileName = NULL;\n                        }\n                    }\n                    else\n                    {\n                        fileName = PhConcatStringRef2(&variableValue, AppendPath);\n                    }\n                }\n                else\n                {\n                    if (NativeFileName)\n                        fileName = PhDosPathNameToNtPathName(&variableValue);\n                    else\n                        fileName = PhCreateString2(&variableValue);\n                }\n\n                return fileName;\n            }\n        }\n        break;\n    case PH_FOLDERID_RoamingAppData:\n        {\n            static CONST PH_STRINGREF variableName = PH_STRINGREF_INIT(L\"APPDATA\");\n            static CONST PH_STRINGREF variableNameProfile = PH_STRINGREF_INIT(L\"USERPROFILE\");\n            NTSTATUS status;\n            PH_STRINGREF variableValue;\n            WCHAR variableBuffer[DOS_MAX_PATH_LENGTH];\n\n            PhInitializeBufferStringRef(&variableValue, variableBuffer, sizeof(variableBuffer));\n\n            status = PhQueryEnvironmentVariableStringRef(\n                NULL,\n                &variableName,\n                &variableValue\n                );\n\n            if (!NT_SUCCESS(status))\n            {\n                status = PhQueryEnvironmentVariableStringRef(\n                    NULL,\n                    &variableNameProfile,\n                    &variableValue\n                    );\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                PPH_STRING fileName;\n\n                if (AppendPath)\n                {\n                    if (NativeFileName)\n                    {\n                        if (fileName = PhDosPathNameToNtPathName(&variableValue))\n                        {\n                            PhMoveReference(&fileName, PhConcatStringRef2(&fileName->sr, AppendPath));\n                        }\n                        else\n                        {\n                            fileName = NULL;\n                        }\n                    }\n                    else\n                    {\n                        fileName = PhConcatStringRef2(&variableValue, AppendPath);\n                    }\n                }\n                else\n                {\n                    if (NativeFileName)\n                    {\n                        fileName = PhDosPathNameToNtPathName(&variableValue);\n                    }\n                    else\n                    {\n                        fileName = PhCreateString2(&variableValue);\n                    }\n                }\n\n                return fileName;\n            }\n        }\n        break;\n    //case PH_FOLDERID_ProgramFiles:\n    //    {\n    //        PPH_STRING value;\n    //\n    //        if (value = PhExpandEnvironmentStringsZ(L\"%ProgramFiles%\"))\n    //        {\n    //            if (AppendPath)\n    //            {\n    //                PhMoveReference(&value, PhConcatStringRef2(&value->sr, AppendPath));\n    //            }\n    //\n    //            return value;\n    //        }\n    //    }\n    //    break;\n    case PH_FOLDERID_ProgramData:\n        {\n            static CONST PH_STRINGREF variableName = PH_STRINGREF_INIT(L\"PROGRAMDATA\");\n            NTSTATUS status;\n            PH_STRINGREF variableValue;\n            WCHAR variableBuffer[DOS_MAX_PATH_LENGTH];\n\n            PhInitializeBufferStringRef(&variableValue, variableBuffer, sizeof(variableBuffer));\n\n            status = PhQueryEnvironmentVariableStringRef(\n                NULL,\n                &variableName,\n                &variableValue\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                PPH_STRING fileName;\n\n                if (AppendPath)\n                {\n                    if (NativeFileName)\n                    {\n                        if (fileName = PhDosPathNameToNtPathName(&variableValue))\n                        {\n                            PhMoveReference(&fileName, PhConcatStringRef2(&fileName->sr, AppendPath));\n                        }\n                        else\n                        {\n                            fileName = NULL;\n                        }\n                    }\n                    else\n                    {\n                        fileName = PhConcatStringRef2(&variableValue, AppendPath);\n                    }\n                }\n                else\n                {\n                    if (NativeFileName)\n                    {\n                        fileName = PhDosPathNameToNtPathName(&variableValue);\n                    }\n                    else\n                    {\n                        fileName = PhCreateString2(&variableValue);\n                    }\n                }\n\n                return fileName;\n            }\n        }\n        break;\n    }\n#else\n    switch (Folder)\n    {\n    case PH_FOLDERID_LocalAppData:\n        {\n            PPH_STRING value;\n\n            if (value = PhGetKnownFolderPath(&FOLDERID_LocalAppData, AppendPath))\n            {\n                if (NativeFileName)\n                {\n                    PhMoveReference(&value, PhDosPathNameToNtPathName(&value->sr));\n                }\n\n                return value;\n            }\n        }\n        break;\n    case PH_FOLDERID_RoamingAppData:\n        {\n            PPH_STRING value;\n\n            if (value = PhGetKnownFolderPath(&FOLDERID_RoamingAppData, AppendPath))\n            {\n                if (NativeFileName)\n                {\n                    PhMoveReference(&value, PhDosPathNameToNtPathName(&value->sr));\n                }\n\n                return value;\n            }\n        }\n        break;\n    //case PH_FOLDERID_ProgramFiles:\n    //    return PhGetKnownFolderPath(&FOLDERID_ProgramFiles, AppendPath);\n    case PH_FOLDERID_ProgramData:\n        {\n            PPH_STRING value;\n\n            if (value = PhGetKnownFolderPath(&FOLDERID_ProgramData, AppendPath))\n            {\n                if (NativeFileName)\n                {\n                    PhMoveReference(&value, PhDosPathNameToNtPathName(&value->sr));\n                }\n\n                return value;\n            }\n        }\n        break;\n    }\n#endif\n    return NULL;\n}\n\n/**\n * Retrieves the full path of a known folder.\n *\n * \\param Folder A pointer to the GUID that identifies the known folder.\n * \\param AppendPath An optional string to append to the folder path.\n * \\return A pointer to a string containing the full path of the known folder, or NULL if the operation fails.\n */\nPPH_STRING PhGetKnownFolderPath(\n    _In_ PCGUID Folder,\n    _In_opt_ PCPH_STRINGREF AppendPath\n    )\n{\n    return PhGetKnownFolderPathEx(Folder, 0, NULL, AppendPath);\n}\n\n/**\n * Flag mapping table for known folder path retrieval.\n *\n * Maps PH_KF_FLAG_* values to corresponding KF_FLAG_* values for use with SHGetKnownFolderPath.\n */\nstatic const PH_FLAG_MAPPING PhpKnownFolderFlagMappings[] =\n{\n    { PH_KF_FLAG_FORCE_PACKAGE_REDIRECTION, KF_FLAG_FORCE_APP_DATA_REDIRECTION },\n    { PH_KF_FLAG_FORCE_APPCONTAINER_REDIRECTION, KF_FLAG_FORCE_APPCONTAINER_REDIRECTION },\n};\n\n/**\n * Retrieves the full path of a known folder optionally using a token handle and additional flags.\n *\n * \\param Folder A pointer to the GUID that identifies the known folder.\n * \\param Flags Flags controlling folder path retrieval (see PH_KF_FLAG_*).\n * \\param TokenHandle An optional token handle for user-specific folder resolution.\n * \\param AppendPath An optional string to append to the folder path.\n * \\return A pointer to a string containing the full path of the known folder, or NULL if the operation fails.\n */\nPPH_STRING PhGetKnownFolderPathEx(\n    _In_ PCGUID Folder,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _In_opt_ PCPH_STRINGREF AppendPath\n    )\n{\n    PPH_STRING path;\n    ULONG flags;\n    PWSTR knownFolderBuffer;\n    SIZE_T knownFolderLength;\n    SIZE_T knownAppendLength;\n\n    flags = 0;\n    PhMapFlags1(&flags, Flags, PhpKnownFolderFlagMappings, ARRAYSIZE(PhpKnownFolderFlagMappings));\n\n    if (FAILED(PhShellGetKnownFolderPath(\n        Folder,\n        flags | KF_FLAG_DONT_VERIFY,\n        TokenHandle,\n        &knownFolderBuffer\n        )))\n    {\n        return NULL;\n    }\n\n    knownFolderLength = PhCountStringZ(knownFolderBuffer) * sizeof(WCHAR);\n    knownAppendLength = AppendPath ? AppendPath->Length : 0;\n\n    path = PhCreateStringEx(NULL, knownFolderLength + knownAppendLength);\n    memcpy(\n        path->Buffer,\n        knownFolderBuffer,\n        knownFolderLength\n        );\n\n    if (AppendPath)\n    {\n        memcpy(\n            PTR_ADD_OFFSET(path->Buffer, knownFolderLength),\n            AppendPath->Buffer,\n            knownAppendLength\n            );\n    }\n\n    CoTaskMemFree(knownFolderBuffer);\n\n    return path;\n}\n\n// rev from GetTempPath2W (dmex)\n/**\n * Retrieves the path to the system temporary directory, optionally appending a subpath.\n *\n * This function determines the appropriate temporary directory for the current user or process context.\n * - If running as an elevated process with the LocalSystem SID, it returns the system root's \"SystemTemp\" directory if it exists.\n * - Otherwise, it checks the \"TMP\", \"TEMP\", and \"USERPROFILE\" environment variables in order, returning the first valid path found.\n * - If an AppendPath is provided, it is concatenated to the selected temporary directory.\n *\n * \\param AppendPath Optional string to append to the temporary directory path.\n * \\return A pointer to a string containing the full path to the temporary directory (with optional appended path),\n * \\remarks\n * - If running as LocalSystem, the function prefers the \"SystemTemp\" directory under the system root.\n * - The function checks environment variables in the order: \"TMP\", \"TEMP\", \"USERPROFILE\".\n * - If no environment variable yields a valid path, the function returns NULL.\n * - The returned path is suitable for creating temporary files or directories.\n * - The function supports both native NT paths and Win32 paths, depending on context.\n */\nPPH_STRING PhGetTemporaryDirectory(\n    _In_opt_ PCPH_STRINGREF AppendPath\n    )\n{\n    static CONST PH_STRINGREF variableNameTmp = PH_STRINGREF_INIT(L\"TMP\");\n    static CONST PH_STRINGREF variableNameTemp = PH_STRINGREF_INIT(L\"TEMP\");\n    static CONST PH_STRINGREF variableNameProfile = PH_STRINGREF_INIT(L\"USERPROFILE\");\n    NTSTATUS status;\n    PH_STRINGREF variableValue;\n    WCHAR variableBuffer[DOS_MAX_PATH_LENGTH];\n\n    if (\n        PhGetOwnTokenAttributes().Elevated &&\n        PhEqualSid(PhGetOwnTokenAttributes().TokenSid, &PhSeLocalSystemSid)\n        )\n    {\n        static CONST PH_STRINGREF systemTemp = PH_STRINGREF_INIT(L\"SystemTemp\");\n        PH_STRINGREF systemRoot;\n        PPH_STRING systemPath;\n\n        PhGetSystemRoot(&systemRoot);\n\n        if (AppendPath)\n        {\n            systemPath = PhConcatStringRef4(&systemRoot, &PhNtPathSeparatorString, &systemTemp, AppendPath);\n        }\n        else\n        {\n            systemPath = PhConcatStringRef3(&systemRoot, &PhNtPathSeparatorString, &systemTemp);\n        }\n\n        if (PhDoesDirectoryExistWin32(PhGetString(systemPath))) // Required for Windows 7/8 (dmex)\n        {\n            return systemPath;\n        }\n\n        PhDereferenceObject(systemPath);\n    }\n\n    PhInitializeBufferStringRef(&variableValue, variableBuffer, sizeof(variableBuffer));\n\n    status = PhQueryEnvironmentVariableStringRef(\n        NULL,\n        &variableNameTmp,\n        &variableValue\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhInitializeBufferStringRef(&variableValue, variableBuffer, sizeof(variableBuffer));\n\n        status = PhQueryEnvironmentVariableStringRef(\n            NULL,\n            &variableNameTemp,\n            &variableValue\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            PhInitializeBufferStringRef(&variableValue, variableBuffer, sizeof(variableBuffer));\n\n            status = PhQueryEnvironmentVariableStringRef(\n                NULL,\n                &variableNameProfile,\n                &variableValue\n                );\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (AppendPath)\n        {\n            return PhConcatStringRef2(&variableValue, AppendPath);\n        }\n\n        return PhCreateString2(&variableValue);\n    }\n\n    return NULL;\n}\n\n/**\n * Waits on multiple objects while processing window messages.\n *\n * \\param WindowHandle The window to process messages for, or NULL to process all messages for the current thread.\n * \\param NumberOfHandles The number of handles specified in \\a Handles. This must not be greater than MAXIMUM_WAIT_OBJECTS - 1.\n * \\param Handles An array of handles.\n * \\param Timeout The number of milliseconds to wait on the objects, or INFINITE for no timeout.\n * \\param WakeMask The input types for which an input event object handle will be added to the array of object handles.\n * \\remarks The wait is always in WaitAny mode. Passing a specific HWND to PeekMessage filters out thread messages\n * (e.g., WM_QUIT) and messages for other windows on the same thread. If you expect full pumping, the HWND must be NULL.\n */\nNTSTATUS PhWaitForMultipleObjectsAndPump(\n    _In_opt_ HWND WindowHandle,\n    _In_ ULONG NumberOfHandles,\n    _In_ PHANDLE Handles,\n    _In_ ULONG Timeout,\n    _In_ ULONG WakeMask\n    )\n{\n    NTSTATUS status;\n    ULONG64 startTickCount;\n    ULONG64 currentTickCount;\n    ULONG64 currentTimeout;\n\n    startTickCount = NtGetTickCount64();\n    currentTimeout = Timeout;\n\n    while (TRUE)\n    {\n        status = MsgWaitForMultipleObjects(\n            NumberOfHandles,\n            Handles,\n            FALSE,\n            (ULONG)currentTimeout,\n            WakeMask\n            );\n\n        if (\n            status >= STATUS_WAIT_0 && status < (NTSTATUS)(STATUS_WAIT_0 + NumberOfHandles) ||\n            status >= STATUS_ABANDONED_WAIT_0  && status < (NTSTATUS)(STATUS_ABANDONED_WAIT_0 + NumberOfHandles)\n            )\n        {\n            return status;\n        }\n        else if (status == (STATUS_WAIT_0 + NumberOfHandles))\n        {\n            MSG msg;\n\n            // Pump messages\n\n            while (PeekMessage(&msg, WindowHandle, 0, 0, PM_REMOVE))\n            {\n                TranslateMessage(&msg);\n                DispatchMessage(&msg);\n            }\n        }\n        else\n        {\n            return status;\n        }\n\n        // Recompute the timeout value.\n\n        if (Timeout != INFINITE)\n        {\n            currentTickCount = NtGetTickCount64();\n            currentTimeout = Timeout - (currentTickCount - startTickCount);\n\n            if ((LONG64)currentTimeout < 0)\n                return STATUS_TIMEOUT;\n        }\n    }\n}\n\n/**\n * Creates a native process and an initial thread.\n *\n * \\param FileName The Win32 file name of the image.\n * \\param CommandLine The command line string to pass to the process. This string cannot be used to\n * specify the image to execute.\n * \\param Environment The environment block for the process. Specify NULL to use the environment of\n * the current process.\n * \\param CurrentDirectory The current directory string to pass to the process.\n * \\param Information Additional parameters to pass to the process.\n * \\param Flags A combination of the following:\n * \\li \\c PH_CREATE_PROCESS_INHERIT_HANDLES Inheritable handles will be duplicated to the process\n * from the parent process.\n * \\li \\c PH_CREATE_PROCESS_SUSPENDED The initial thread will be created suspended.\n * \\li \\c PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB The process will not be assigned to the job object\n * associated with the parent process.\n * \\li \\c PH_CREATE_PROCESS_NEW_CONSOLE The process will have its own console, instead of inheriting\n * the console of the parent process.\n * \\param ParentProcessHandle The process from which the new process will inherit attributes.\n * Specify NULL for the current process.\n * \\param ClientId A variable which receives the identifier of the initial thread.\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param ThreadHandle A variable which receives a handle to the initial thread.\n */\nNTSTATUS PhCreateProcess(\n    _In_ PCWSTR FileName,\n    _In_opt_ PCPH_STRINGREF CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PCPH_STRINGREF CurrentDirectory,\n    _In_opt_ PPH_CREATE_PROCESS_INFO Information,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE ParentProcessHandle,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    NTSTATUS status;\n    RTL_USER_PROCESS_INFORMATION processInfo;\n    PRTL_USER_PROCESS_PARAMETERS parameters;\n    UNICODE_STRING fileName;\n    UNICODE_STRING commandLine;\n    UNICODE_STRING currentDirectory;\n    PUNICODE_STRING windowTitle;\n    PUNICODE_STRING desktopInfo;\n\n    status = PhDosLongPathNameToNtPathNameWithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (CommandLine)\n    {\n        if (!PhStringRefToUnicodeString(CommandLine, &commandLine))\n            return STATUS_NAME_TOO_LONG;\n    }\n\n    if (CurrentDirectory)\n    {\n        if (!PhStringRefToUnicodeString(CurrentDirectory, &currentDirectory))\n            return STATUS_NAME_TOO_LONG;\n    }\n\n    if (Information)\n    {\n        windowTitle = Information->WindowTitle;\n        desktopInfo = Information->DesktopInfo;\n    }\n    else\n    {\n        windowTitle = NULL;\n        desktopInfo = NULL;\n    }\n\n    if (!windowTitle)\n        windowTitle = &fileName;\n\n    if (!desktopInfo)\n        desktopInfo = &NtCurrentPeb()->ProcessParameters->DesktopInfo;\n\n    status = RtlCreateProcessParameters(\n        &parameters,\n        &fileName,\n        Information ? Information->DllPath : NULL,\n        CurrentDirectory ? &currentDirectory : NULL,\n        CommandLine ? &commandLine : &fileName,\n        Environment,\n        windowTitle,\n        desktopInfo,\n        Information ? Information->ShellInfo : NULL,\n        Information ? Information->RuntimeData : NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = RtlCreateUserProcess(\n            &fileName,\n            0,\n            parameters,\n            NULL,\n            NULL,\n            ParentProcessHandle,\n            !!(Flags & PH_CREATE_PROCESS_INHERIT_HANDLES),\n            NULL,\n            NULL,\n            &processInfo\n            );\n        RtlDestroyProcessParameters(parameters);\n    }\n\n    RtlFreeUnicodeString(&fileName);\n\n    if (NT_SUCCESS(status))\n    {\n        if (!(Flags & PH_CREATE_PROCESS_SUSPENDED))\n            NtResumeThread(processInfo.ThreadHandle, NULL);\n\n        if (ClientId)\n            *ClientId = processInfo.ClientId;\n\n        if (ProcessHandle)\n            *ProcessHandle = processInfo.ProcessHandle;\n        else\n            NtClose(processInfo.ProcessHandle);\n\n        if (ThreadHandle)\n            *ThreadHandle = processInfo.ThreadHandle;\n        else\n            NtClose(processInfo.ThreadHandle);\n    }\n\n    return status;\n}\n\n/**\n * Creates a Win32 process and an initial thread.\n *\n * \\param FileName The Win32 file name of the image.\n * \\param CommandLine The command line to execute. This can be specified instead of \\a FileName to\n * indicate the image to execute.\n * \\param Environment The environment block for the process. Specify NULL to use the environment of\n * the current process.\n * \\param CurrentDirectory The current directory string to pass to the process.\n * \\param Flags See PhCreateProcess().\n * \\param TokenHandle The token of the process. Specify NULL for the token of the parent process.\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param ThreadHandle A variable which receives a handle to the initial thread.\n */\nNTSTATUS PhCreateProcessWin32(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ PCWSTR CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PCWSTR CurrentDirectory,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    return PhCreateProcessWin32Ex(\n        FileName,\n        CommandLine,\n        Environment,\n        CurrentDirectory,\n        NULL,\n        Flags,\n        TokenHandle,\n        NULL,\n        ProcessHandle,\n        ThreadHandle\n        );\n}\n\nstatic const PH_FLAG_MAPPING PhpCreateProcessMappings[] =\n{\n    { PH_CREATE_PROCESS_DEBUG, DEBUG_PROCESS },\n    { PH_CREATE_PROCESS_DEBUG_ONLY_THIS_PROCESS, DEBUG_ONLY_THIS_PROCESS },\n    { PH_CREATE_PROCESS_SUSPENDED, CREATE_SUSPENDED },\n    { PH_CREATE_PROCESS_NEW_CONSOLE, CREATE_NEW_CONSOLE },\n    { PH_CREATE_PROCESS_UNICODE_ENVIRONMENT, CREATE_UNICODE_ENVIRONMENT },\n    { PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, EXTENDED_STARTUPINFO_PRESENT },\n    { PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB, CREATE_BREAKAWAY_FROM_JOB },\n    { PH_CREATE_PROCESS_DEFAULT_ERROR_MODE, CREATE_DEFAULT_ERROR_MODE },\n};\n\nFORCEINLINE VOID PhpConvertProcessInformation(\n    _In_ PPROCESS_INFORMATION ProcessInfo,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    if (ClientId)\n    {\n        ClientId->UniqueProcess = UlongToHandle(ProcessInfo->dwProcessId);\n        ClientId->UniqueThread = UlongToHandle(ProcessInfo->dwThreadId);\n    }\n\n    if (ProcessHandle)\n        *ProcessHandle = ProcessInfo->hProcess;\n    else if (ProcessInfo->hProcess)\n        NtClose(ProcessInfo->hProcess);\n\n    if (ThreadHandle)\n        *ThreadHandle = ProcessInfo->hThread;\n    else if (ProcessInfo->hThread)\n        NtClose(ProcessInfo->hThread);\n}\n\n/**\n * Creates a Win32 process and an initial thread.\n *\n * \\param FileName The Win32 file name of the image.\n * \\param CommandLine The command line to execute. This can be specified instead of \\a FileName to\n * indicate the image to execute.\n * \\param Environment The environment block for the process. Specify NULL to use the environment of\n * the current process.\n * \\param CurrentDirectory The current directory string to pass to the process.\n * \\param StartupInfo A STARTUPINFO structure containing additional parameters for the process.\n * \\param Flags See PhCreateProcess().\n * \\param TokenHandle The token of the process. Specify NULL for the token of the parent process.\n * \\param ClientId A variable which receives the identifier of the initial thread.\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param ThreadHandle A variable which receives a handle to the initial thread.\n */\nNTSTATUS PhCreateProcessWin32Ex(\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ PCWSTR CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PCWSTR CurrentDirectory,\n    _In_opt_ PVOID StartupInfo,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName = NULL;\n    PPH_STRING commandLine = NULL;\n    PPH_STRING currentDirectory = NULL;\n    STARTUPINFOEX startupInfo;\n    PROCESS_INFORMATION processInfo = { 0 };\n    ULONG newFlags;\n\n    if (CommandLine) // duplicate because CreateProcess modifies the string (wj32)\n        commandLine = PhCreateString(CommandLine);\n\n    if (FileName)\n        fileName = PhCreateString(FileName);\n    else\n    {\n        PH_STRINGREF commandLineFileName;\n        PH_STRINGREF commandLineArguments;\n\n        PhParseCommandLineFuzzy(&commandLine->sr, &commandLineFileName, &commandLineArguments, &fileName);\n\n        if (PhIsNullOrEmptyString(fileName))\n            PhMoveReference(&fileName, PhCreateString2(&commandLineFileName));\n\n        // Escape the commandline (or uncomment CommandLineToArgvW to clear the filename when it contains \\\\program files\\\\) (dmex)\n        {\n            static CONST PH_STRINGREF separator = PH_STRINGREF_INIT(L\"\\\"\");\n            static CONST PH_STRINGREF space = PH_STRINGREF_INIT(L\" \");\n            PPH_STRING escaped;\n\n            escaped = PhConcatStringRef3(&separator, &commandLineFileName, &separator);\n\n            if (commandLineArguments.Length)\n            {\n                PhMoveReference(&escaped, PhConcatStringRef3(&escaped->sr, &space, &commandLineArguments));\n            }\n\n            PhMoveReference(&commandLine, escaped);\n        }\n\n        //INT cmdlineArgCount;\n        //PWSTR* cmdlineArgList;\n        //\n        //// Try extract the filename or CreateProcess might execute the wrong executable. (dmex)\n        //if (commandLine && (cmdlineArgList = PhCommandLineToArgv(commandLine->Buffer, &cmdlineArgCount)))\n        //{\n        //    PhMoveReference(&fileName, PhCreateString(cmdlineArgList[0]));\n        //    LocalFree(cmdlineArgList);\n        //}\n\n        if (fileName && !PhDoesFileExistWin32(PhGetString(fileName)))\n        {\n            PPH_STRING filePath;\n\n            // The user typed a name without a path so attempt to locate the executable. (dmex)\n            if (filePath = PhSearchFilePath(PhGetString(fileName), L\".exe\"))\n                PhMoveReference(&fileName, filePath);\n            else\n                PhClearReference(&fileName);\n        }\n    }\n\n    // Set the current directory to the same location as the target executable\n    // or CreateProcess uses our current directory. (dmex)\n    if (CurrentDirectory)\n        currentDirectory = PhCreateString(CurrentDirectory);\n    else\n    {\n        if (!PhIsNullOrEmptyString(fileName))\n            currentDirectory = PhGetBaseDirectory(fileName);\n    }\n\n    newFlags = 0;\n    PhMapFlags1(&newFlags, Flags, PhpCreateProcessMappings, sizeof(PhpCreateProcessMappings) / sizeof(PH_FLAG_MAPPING));\n\n    if (!StartupInfo)\n    {\n        SetFlag(newFlags, EXTENDED_STARTUPINFO_PRESENT);\n        memset(&startupInfo, 0, sizeof(STARTUPINFOEX));\n        startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX);\n    }\n\n    if (TokenHandle)\n    {\n        if (CreateProcessAsUser(\n            TokenHandle,\n            PhGetString(fileName),\n            PhGetString(commandLine),\n            NULL,\n            NULL,\n            !!(Flags & PH_CREATE_PROCESS_INHERIT_HANDLES),\n            newFlags,\n            Environment,\n            PhGetString(currentDirectory),\n            StartupInfo ? StartupInfo : &startupInfo,\n            &processInfo\n            ))\n            status = STATUS_SUCCESS;\n        else\n            status = PhGetLastWin32ErrorAsNtStatus();\n    }\n    else\n    {\n        if (CreateProcess(\n            PhGetString(fileName),\n            PhGetString(commandLine),\n            NULL,\n            NULL,\n            !!(Flags & PH_CREATE_PROCESS_INHERIT_HANDLES),\n            newFlags,\n            Environment,\n            PhGetString(currentDirectory),\n            StartupInfo ? StartupInfo : &startupInfo,\n            &processInfo\n            ))\n            status = STATUS_SUCCESS;\n        else\n            status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    if (fileName)\n        PhDereferenceObject(fileName);\n    if (commandLine)\n        PhDereferenceObject(commandLine);\n    if (currentDirectory)\n        PhDereferenceObject(currentDirectory);\n\n    if (NT_SUCCESS(status))\n    {\n        if (ClientId)\n        {\n            ClientId->UniqueProcess = UlongToHandle(processInfo.dwProcessId);\n            ClientId->UniqueThread = UlongToHandle(processInfo.dwThreadId);\n        }\n\n        if (ProcessHandle)\n        {\n            *ProcessHandle = processInfo.hProcess;\n        }\n        else if (processInfo.hProcess)\n        {\n            NtClose(processInfo.hProcess);\n        }\n\n        if (ThreadHandle)\n        {\n            *ThreadHandle = processInfo.hThread;\n        }\n        else if (processInfo.hThread)\n        {\n            NtClose(processInfo.hThread);\n        }\n    }\n    else\n    {\n        if (processInfo.hProcess)\n            NtClose(processInfo.hProcess);\n        if (processInfo.hThread)\n            NtClose(processInfo.hThread);\n    }\n\n    return status;\n}\n\n/**\n * Creates a Win32 process and an initial thread under the specified user.\n *\n * \\param Information Parameters specifying how to create the process.\n * \\param Flags See PhCreateProcess(). Additional flags may be used:\n * \\li \\c PH_CREATE_PROCESS_USE_PROCESS_TOKEN Use the token of the process specified by\n * \\a ProcessIdWithToken in \\a Information.\n * \\li \\c PH_CREATE_PROCESS_USE_SESSION_TOKEN Use the token of the session specified by\n * \\a SessionIdWithToken in \\a Information.\n * \\li \\c PH_CREATE_PROCESS_USE_LINKED_TOKEN Use the linked token to create the process; this causes\n * the process to be elevated or unelevated depending on the specified options.\n * \\li \\c PH_CREATE_PROCESS_SET_SESSION_ID \\a SessionId is specified in \\a Information.\n * \\li \\c PH_CREATE_PROCESS_WITH_PROFILE Load the user profile, if supported.\n * \\param StartupInfo A STARTUPINFO structure containing additional parameters for the process.\n * \\param ClientId A variable which receives the identifier of the initial thread.\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param ThreadHandle A variable which receives a handle to the initial thread.\n */\nNTSTATUS PhCreateProcessAsUser(\n    _In_ PPH_CREATE_PROCESS_AS_USER_INFO Information,\n    _In_ ULONG Flags,\n    _In_opt_ PVOID StartupInfo,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    NTSTATUS status;\n    HANDLE tokenHandle;\n    BOOLEAN needsDuplicate = FALSE;\n    PVOID defaultEnvironment = NULL;\n    STARTUPINFOEX startupInfo;\n\n    if ((Flags & PH_CREATE_PROCESS_USE_PROCESS_TOKEN) && (Flags & PH_CREATE_PROCESS_USE_SESSION_TOKEN))\n        return STATUS_INVALID_PARAMETER_2;\n    if (!Information->ApplicationName && !Information->CommandLine)\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    if (!StartupInfo)\n    {\n        RtlZeroMemory(&startupInfo, sizeof(STARTUPINFOEX));\n        startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX);\n        startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;\n        startupInfo.StartupInfo.wShowWindow = SW_NORMAL;\n        startupInfo.StartupInfo.lpDesktop = (PWSTR)Information->DesktopName;\n    }\n\n    // Try to use CreateProcessWithLogonW if we need to load the user profile.\n    // This isn't compatible with some options.\n    if (Flags & PH_CREATE_PROCESS_WITH_PROFILE)\n    {\n        BOOLEAN useWithLogon;\n\n        useWithLogon = TRUE;\n\n        if (Flags & (PH_CREATE_PROCESS_USE_PROCESS_TOKEN | PH_CREATE_PROCESS_USE_SESSION_TOKEN))\n            useWithLogon = FALSE;\n\n        if (Flags & PH_CREATE_PROCESS_USE_LINKED_TOKEN)\n            useWithLogon = FALSE;\n\n        if (Flags & PH_CREATE_PROCESS_SET_SESSION_ID)\n        {\n            ULONG sessionId = ULONG_MAX;\n\n            PhGetProcessSessionId(NtCurrentProcess(), &sessionId);\n\n            if (Information->SessionId != sessionId)\n                useWithLogon = FALSE;\n        }\n\n        if (Information->LogonType && Information->LogonType != LOGON32_LOGON_INTERACTIVE)\n            useWithLogon = FALSE;\n\n        if (useWithLogon)\n        {\n            PPH_STRING applicationName = NULL;\n            PPH_STRING commandLine = NULL;\n            PPH_STRING currentDirectory = NULL;\n            PROCESS_INFORMATION processInfo = { NULL };\n            ULONG newFlags = 0;\n\n            if (!Information->LogonFlags)\n                Information->LogonFlags = LOGON_WITH_PROFILE;\n\n            if (Information->ApplicationName)\n            {\n                applicationName = PhCreateString(Information->ApplicationName);\n            }\n\n            if (Information->CommandLine) // duplicate because CreateProcess modifies the string\n            {\n                commandLine = PhCreateString(Information->CommandLine);\n            }\n\n            if (Information->CurrentDirectory)\n            {\n                currentDirectory = PhCreateString(Information->CurrentDirectory);\n            }\n\n            if (!Information->Environment)\n            {\n                SetFlag(Flags, PH_CREATE_PROCESS_UNICODE_ENVIRONMENT);\n            }\n\n            PhMapFlags1(&newFlags, Flags, PhpCreateProcessMappings, sizeof(PhpCreateProcessMappings) / sizeof(PH_FLAG_MAPPING));\n\n            if (CreateProcessWithLogonW(\n                Information->UserName,\n                Information->DomainName,\n                Information->Password,\n                Information->LogonFlags,\n                PhGetString(applicationName),\n                PhGetString(commandLine),\n                newFlags,\n                Information->Environment,\n                PhGetString(currentDirectory),\n                StartupInfo ? StartupInfo : &startupInfo,\n                &processInfo\n                ))\n                status = STATUS_SUCCESS;\n            else\n                status = PhGetLastWin32ErrorAsNtStatus();\n\n            if (applicationName)\n                PhDereferenceObject(applicationName);\n            if (commandLine)\n                PhDereferenceObject(commandLine);\n            if (currentDirectory)\n                PhDereferenceObject(currentDirectory);\n\n            if (NT_SUCCESS(status))\n            {\n                if (ClientId)\n                {\n                    ClientId->UniqueProcess = UlongToHandle(processInfo.dwProcessId);\n                    ClientId->UniqueThread = UlongToHandle(processInfo.dwThreadId);\n                }\n\n                if (ProcessHandle)\n                {\n                    *ProcessHandle = processInfo.hProcess;\n                }\n                else if (processInfo.hProcess)\n                {\n                    NtClose(processInfo.hProcess);\n                }\n\n                if (ThreadHandle)\n                {\n                    *ThreadHandle = processInfo.hThread;\n                }\n                else if (processInfo.hThread)\n                {\n                    NtClose(processInfo.hThread);\n                }\n            }\n            else\n            {\n                if (processInfo.hProcess)\n                    NtClose(processInfo.hProcess);\n                if (processInfo.hThread)\n                    NtClose(processInfo.hThread);\n            }\n\n            return status;\n        }\n    }\n\n    // Get the token handle. Various methods are supported.\n\n    if (Flags & PH_CREATE_PROCESS_USE_PROCESS_TOKEN)\n    {\n        HANDLE processHandle;\n\n        if (!NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            PROCESS_QUERY_LIMITED_INFORMATION,\n            Information->ProcessIdWithToken\n            )))\n            return status;\n\n        status = PhOpenProcessToken(\n            processHandle,\n            TOKEN_ALL_ACCESS,\n            &tokenHandle\n            );\n        NtClose(processHandle);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (Flags & PH_CREATE_PROCESS_SET_SESSION_ID)\n            needsDuplicate = TRUE; // can't set the session ID of a token in use by a process\n    }\n    else if (Flags & PH_CREATE_PROCESS_USE_SESSION_TOKEN)\n    {\n        WINSTATIONUSERTOKEN userToken;\n        ULONG returnLength;\n\n        memset(&userToken, 0, sizeof(WINSTATIONUSERTOKEN));\n        userToken.ProcessId = NtCurrentProcessId();\n        userToken.ThreadId = NtCurrentThreadId();\n\n        if (!WinStationQueryInformationW(\n            WINSTATION_CURRENT_SERVER,\n            Information->SessionIdWithToken,\n            WinStationUserToken,\n            &userToken,\n            sizeof(WINSTATIONUSERTOKEN),\n            &returnLength\n            ))\n        {\n            return PhGetLastWin32ErrorAsNtStatus();\n        }\n\n        tokenHandle = userToken.UserToken;\n\n        if (Flags & PH_CREATE_PROCESS_SET_SESSION_ID)\n            needsDuplicate = TRUE; // not sure if this is necessary\n    }\n    else\n    {\n        ULONG logonType;\n\n        if (Information->LogonType)\n        {\n            logonType = Information->LogonType;\n        }\n        else\n        {\n            logonType = LOGON32_LOGON_INTERACTIVE;\n\n            // Check if this is a service logon.\n            if (PhEqualStringZ(Information->DomainName, L\"NT AUTHORITY\", TRUE))\n            {\n                if (PhEqualStringZ(Information->UserName, L\"SYSTEM\", TRUE) ||\n                    PhEqualStringZ(Information->UserName, L\"LOCAL SERVICE\", TRUE) ||\n                    PhEqualStringZ(Information->UserName, L\"NETWORK SERVICE\", TRUE))\n                {\n                    logonType = LOGON32_LOGON_SERVICE;\n                }\n            }\n        }\n\n        if (!LogonUser(\n            Information->UserName,\n            Information->DomainName,\n            Information->Password,\n            logonType,\n            LOGON32_PROVIDER_DEFAULT,\n            &tokenHandle\n            ))\n            return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    if (Flags & PH_CREATE_PROCESS_USE_LINKED_TOKEN)\n    {\n        HANDLE linkedTokenHandle;\n        TOKEN_TYPE tokenType;\n\n        // NtQueryInformationToken normally returns an impersonation token with\n        // SecurityIdentification, but if the process is running with SeTcbPrivilege, it returns a\n        // primary token. We can never duplicate a SecurityIdentification impersonation token to\n        // make it a primary token, so we just check if the token is primary before using it.\n\n        if (NT_SUCCESS(PhGetTokenLinkedToken(tokenHandle, &linkedTokenHandle)))\n        {\n            if (NT_SUCCESS(PhGetTokenType(linkedTokenHandle, &tokenType)) && tokenType == TokenPrimary)\n            {\n                NtClose(tokenHandle);\n                tokenHandle = linkedTokenHandle;\n                needsDuplicate = FALSE; // the linked token that is returned is always a copy, so no need to duplicate\n            }\n            else\n            {\n                NtClose(linkedTokenHandle);\n            }\n        }\n    }\n\n    if (needsDuplicate)\n    {\n        HANDLE newTokenHandle;\n        OBJECT_ATTRIBUTES objectAttributes;\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            NULL,\n            0,\n            NULL,\n            NULL\n            );\n\n        status = NtDuplicateToken(\n            tokenHandle,\n            TOKEN_ALL_ACCESS,\n            &objectAttributes,\n            FALSE,\n            TokenPrimary,\n            &newTokenHandle\n            );\n        NtClose(tokenHandle);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        tokenHandle = newTokenHandle;\n    }\n\n    // Set the session ID if needed.\n\n    if (Flags & PH_CREATE_PROCESS_SET_SESSION_ID)\n    {\n        if (!NT_SUCCESS(status = PhSetTokenSessionId(\n            tokenHandle,\n            Information->SessionId\n            )))\n        {\n            NtClose(tokenHandle);\n            return status;\n        }\n    }\n\n    // Set the UIAccess flag if needed.\n\n    if (Flags & PH_CREATE_PROCESS_SET_UIACCESS)\n    {\n        if (!NT_SUCCESS(status = PhSetTokenUIAccess(\n            tokenHandle,\n            TRUE\n            )))\n        {\n            NtClose(tokenHandle);\n            return status;\n        }\n    }\n\n    if (!Information->Environment)\n    {\n        PhCreateEnvironmentBlock(&defaultEnvironment, tokenHandle, FALSE);\n\n        if (defaultEnvironment)\n            Flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT;\n    }\n\n    status = PhCreateProcessWin32Ex(\n        Information->ApplicationName,\n        Information->CommandLine,\n        Information->Environment ? Information->Environment : defaultEnvironment,\n        Information->CurrentDirectory,\n        StartupInfo ? StartupInfo : &startupInfo,\n        Flags,\n        tokenHandle,\n        ClientId,\n        ProcessHandle,\n        ThreadHandle\n        );\n\n    if (defaultEnvironment)\n    {\n        PhDestroyEnvironmentBlock(defaultEnvironment);\n    }\n\n    NtClose(tokenHandle);\n\n    return status;\n}\n\n/**\n * Filters a token to create a limited user security context.\n *\n * \\param TokenHandle A handle to an existing token. The handle must have TOKEN_DUPLICATE,\n * TOKEN_QUERY, TOKEN_ADJUST_GROUPS, TOKEN_ADJUST_DEFAULT, READ_CONTROL and WRITE_DAC access.\n * \\param NewTokenHandle A variable which receives a handle to the filtered token. The handle will\n * have the same granted access as \\a TokenHandle.\n */\nNTSTATUS PhFilterTokenForLimitedUser(\n    _In_ HANDLE TokenHandle,\n    _Out_ PHANDLE NewTokenHandle\n    )\n{\n    static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;\n    static const LUID_AND_ATTRIBUTES defaultAllowedPrivileges[] =\n    {\n        { { SE_SHUTDOWN_PRIVILEGE, 0 }, 0 },\n        { { SE_CHANGE_NOTIFY_PRIVILEGE, 0 }, 0 },\n        { { SE_UNDOCK_PRIVILEGE, 0 }, 0 },\n        { { SE_INC_WORKING_SET_PRIVILEGE, 0 }, 0 },\n        { { SE_TIME_ZONE_PRIVILEGE, 0 }, 0 }\n    };\n\n    NTSTATUS status;\n    PSID administratorsSid = PhSeAdministratorsSid();\n    PSID usersSid = PhSeUsersSid();\n    UCHAR sidsToDisableBuffer[FIELD_OFFSET(TOKEN_GROUPS, Groups) + sizeof(SID_AND_ATTRIBUTES)];\n    PTOKEN_GROUPS sidsToDisable;\n    ULONG i;\n    ULONG j;\n    ULONG deleteIndex;\n    BOOLEAN found;\n    PTOKEN_PRIVILEGES privilegesOfToken;\n    PTOKEN_PRIVILEGES privilegesOfUsers;\n    PTOKEN_PRIVILEGES privilegesToDelete;\n    UCHAR lowMandatoryLevelSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];\n    PSID lowMandatoryLevelSid;\n    TOKEN_MANDATORY_LABEL mandatoryLabel;\n    PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n    BOOLEAN currentDaclPresent;\n    BOOLEAN currentDaclDefaulted;\n    PACL currentDacl;\n    PH_TOKEN_USER currentUser;\n    PACE_HEADER currentAce;\n    ULONG newDaclLength;\n    PACL newDacl;\n    SECURITY_DESCRIPTOR newSecurityDescriptor;\n    TOKEN_DEFAULT_DACL newDefaultDacl;\n    HANDLE newTokenHandle;\n\n    // Set up the SIDs to Disable structure.\n\n    sidsToDisable = (PTOKEN_GROUPS)sidsToDisableBuffer;\n    sidsToDisable->GroupCount = 1;\n    sidsToDisable->Groups[0].Sid = administratorsSid;\n    sidsToDisable->Groups[0].Attributes = 0;\n\n    // Set up the Privileges to Delete structure.\n\n    // Get the privileges that the input token contains.\n    if (!NT_SUCCESS(status = PhGetTokenPrivileges(TokenHandle, &privilegesOfToken)))\n        return status;\n\n    // Get the privileges of the Users group - the privileges that we are going to allow.\n    if (!NT_SUCCESS(PhGetAccountPrivileges(usersSid, &privilegesOfUsers)))\n    {\n        // Unsuccessful, so use the default set of privileges.\n        privilegesOfUsers = PhAllocate(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(defaultAllowedPrivileges));\n        privilegesOfUsers->PrivilegeCount = sizeof(defaultAllowedPrivileges) / sizeof(LUID_AND_ATTRIBUTES);\n        memcpy(privilegesOfUsers->Privileges, defaultAllowedPrivileges, sizeof(defaultAllowedPrivileges));\n    }\n\n    // Allocate storage for the privileges we need to delete. The worst case scenario is that all\n    // privileges in the token need to be deleted.\n    privilegesToDelete = PhAllocate(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * privilegesOfToken->PrivilegeCount);\n    deleteIndex = 0;\n\n    // Compute the privileges that we need to delete.\n    for (i = 0; i < privilegesOfToken->PrivilegeCount; i++)\n    {\n        found = FALSE;\n\n        // Is the privilege allowed?\n        for (j = 0; j < privilegesOfUsers->PrivilegeCount; j++)\n        {\n            if (RtlIsEqualLuid(&privilegesOfToken->Privileges[i].Luid, &privilegesOfUsers->Privileges[j].Luid))\n            {\n                found = TRUE;\n                break;\n            }\n        }\n\n        if (!found)\n        {\n            // This privilege needs to be deleted.\n            privilegesToDelete->Privileges[deleteIndex].Attributes = 0;\n            privilegesToDelete->Privileges[deleteIndex].Luid = privilegesOfToken->Privileges[i].Luid;\n            deleteIndex++;\n        }\n    }\n\n    privilegesToDelete->PrivilegeCount = deleteIndex;\n\n    // Filter the token.\n\n    status = NtFilterToken(\n        TokenHandle,\n        0,\n        sidsToDisable,\n        privilegesToDelete,\n        NULL,\n        &newTokenHandle\n        );\n    PhFree(privilegesToDelete);\n    PhFree(privilegesOfUsers);\n    PhFree(privilegesOfToken);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Set the integrity level to Low if we're on Vista and above.\n    {\n        lowMandatoryLevelSid = (PSID)lowMandatoryLevelSidBuffer;\n        PhInitializeSid(lowMandatoryLevelSid, &mandatoryLabelAuthority, 1);\n        *PhSubAuthoritySid(lowMandatoryLevelSid, 0) = SECURITY_MANDATORY_LOW_RID;\n\n        mandatoryLabel.Label.Sid = lowMandatoryLevelSid;\n        mandatoryLabel.Label.Attributes = SE_GROUP_INTEGRITY;\n\n        NtSetInformationToken(newTokenHandle, TokenIntegrityLevel, &mandatoryLabel, sizeof(TOKEN_MANDATORY_LABEL));\n    }\n\n    // Fix up the security descriptor and default DACL.\n    if (NT_SUCCESS(PhGetObjectSecurity(newTokenHandle, DACL_SECURITY_INFORMATION, &currentSecurityDescriptor)))\n    {\n        if (NT_SUCCESS(PhGetTokenUser(TokenHandle, &currentUser)))\n        {\n            if (!NT_SUCCESS(PhGetDaclSecurityDescriptor(\n                currentSecurityDescriptor,\n                &currentDaclPresent,\n                &currentDacl,\n                &currentDaclDefaulted\n                )))\n            {\n                currentDaclPresent = FALSE;\n            }\n\n            newDaclLength = sizeof(ACL) + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + PhLengthSid(currentUser.User.Sid);\n\n            if (currentDaclPresent && currentDacl)\n                newDaclLength += currentDacl->AclSize - sizeof(ACL);\n\n            newDacl = PhAllocateZero(newDaclLength);\n            PhCreateAcl(newDacl, newDaclLength, ACL_REVISION);\n\n            // Add the existing DACL entries.\n            if (currentDaclPresent && currentDacl)\n            {\n                for (i = 0; i < currentDacl->AceCount; i++)\n                {\n                    if (NT_SUCCESS(PhGetAce(currentDacl, i, &currentAce)))\n                    {\n                        status = PhAddAce(newDacl, ACL_REVISION, ULONG_MAX, currentAce, currentAce->AceSize);\n\n                        if (!NT_SUCCESS(status))\n                            break;\n                    }\n                }\n            }\n\n            // Allow access for the current user.\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhAddAccessAllowedAce(newDacl, ACL_REVISION, GENERIC_ALL, currentUser.User.Sid);\n            }\n\n            // Set the security descriptor of the new token.\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhCreateSecurityDescriptor(&newSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                status = PhSetDaclSecurityDescriptor(&newSecurityDescriptor, TRUE, newDacl, FALSE);\n            }\n\n            if (NT_SUCCESS(status))\n            {\n                assert(RtlValidSecurityDescriptor(&newSecurityDescriptor));\n\n                status = PhSetObjectSecurity(newTokenHandle, DACL_SECURITY_INFORMATION, &newSecurityDescriptor);\n            }\n\n            // Set the default DACL.\n\n            newDefaultDacl.DefaultDacl = newDacl;\n            NtSetInformationToken(newTokenHandle, TokenDefaultDacl, &newDefaultDacl, sizeof(TOKEN_DEFAULT_DACL));\n\n            PhFree(newDacl);\n        }\n\n        PhFree(currentSecurityDescriptor);\n    }\n\n    *NewTokenHandle = newTokenHandle;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Converts a security descriptor to its string representation.\n *\n * \\param SecurityDescriptor The security descriptor.\n * \\param SecurityInformation The security information to include in the string.\n * \\param SecurityDescriptorString Receives the string representation of the security descriptor.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetSecurityDescriptorAsString(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PPH_STRING* SecurityDescriptorString\n    )\n{\n    ULONG stringSecurityDescriptorLength = 0;\n    PWSTR stringSecurityDescriptor = NULL;\n\n    if (!ConvertSecurityDescriptorToStringSecurityDescriptorW_Import())\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    if (ConvertSecurityDescriptorToStringSecurityDescriptorW_Import()(\n        SecurityDescriptor,\n        SDDL_REVISION,\n        SecurityInformation,\n        &stringSecurityDescriptor,\n        &stringSecurityDescriptorLength\n        ))\n    {\n        if (stringSecurityDescriptorLength & 1) // validate the string length\n        {\n            LocalFree(stringSecurityDescriptor);\n            return STATUS_FAIL_CHECK;\n        }\n\n        *SecurityDescriptorString = PhCreateStringEx(\n            stringSecurityDescriptor,\n            stringSecurityDescriptorLength * sizeof(WCHAR)\n            );\n        LocalFree(stringSecurityDescriptor);\n        return STATUS_SUCCESS;\n    }\n\n    return PhGetLastWin32ErrorAsNtStatus();\n}\n\n/**\n * Converts a string representation of a security descriptor to its binary representation.\n *\n * \\param SecurityDescriptorString The string representation of the security descriptor.\n * \\return A pointer to the security descriptor, or NULL if the operation fails.\n */\nPSECURITY_DESCRIPTOR PhGetSecurityDescriptorFromString(\n    _In_ PCWSTR SecurityDescriptorString\n    )\n{\n    PVOID securityDescriptor = NULL;\n    ULONG securityDescriptorLength = 0;\n    PSECURITY_DESCRIPTOR securityDescriptorBuffer = NULL;\n\n    if (!ConvertStringSecurityDescriptorToSecurityDescriptorW_Import())\n        return NULL;\n\n    if (ConvertStringSecurityDescriptorToSecurityDescriptorW_Import()(\n        SecurityDescriptorString,\n        SDDL_REVISION,\n        &securityDescriptorBuffer,\n        &securityDescriptorLength\n        ) &&\n        securityDescriptorBuffer &&\n        securityDescriptorLength\n        )\n    {\n        securityDescriptor = PhAllocateCopy(\n            securityDescriptorBuffer,\n            securityDescriptorLength\n            );\n        assert(securityDescriptorLength == RtlLengthSecurityDescriptor(securityDescriptor));\n\n        LocalFree(securityDescriptorBuffer);\n    }\n\n    return securityDescriptor;\n}\n\n/**\n * Retrieves the string representation of an object's security descriptor.\n *\n * \\param Handle A handle to the object.\n * \\param SecurityDescriptorString Receives the string representation of the security descriptor.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetObjectSecurityDescriptorAsString(\n    _In_ HANDLE Handle,\n    _Out_ PPH_STRING* SecurityDescriptorString\n    )\n{\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    PPH_STRING securityDescriptorString;\n\n    status = PhGetObjectSecurity(\n        Handle,\n        OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |\n        DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION |\n        ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION,\n        &securityDescriptor\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetSecurityDescriptorAsString(\n        securityDescriptor,\n        OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |\n        DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION |\n        ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION,\n        &securityDescriptorString\n        );\n\n    PhFree(securityDescriptor);\n\n    if (NT_SUCCESS(status))\n    {\n        *SecurityDescriptorString = securityDescriptorString;\n    }\n\n    return status;\n}\n\n/**\n * Opens a file or location through the shell.\n *\n * \\param ExecInfo A pointer to a SHELLEXECUTEINFO structure that contains and receives information about the application being executed.\n *\n * \\return Successful or errant status.\n */\nBOOLEAN PhShellExecuteWin32(\n    _Inout_ PSHELLEXECUTEINFOW ExecInfo\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&ShellExecuteExW) ShellExecuteExW_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"shell32.dll\"))\n        {\n            ShellExecuteExW_I = PhGetDllBaseProcedureAddress(baseAddress, \"ShellExecuteExW\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!ShellExecuteExW_I)\n        return FALSE;\n\n    return !!ShellExecuteExW_I(ExecInfo);\n}\n\n/**\n * Opens a file or location through the shell.\n *\n * \\param WindowHandle The window to display user interface components on.\n * \\param FileName A file name or location.\n * \\param Parameters The parameters to pass to the executed application.\n */\nVOID PhShellExecute(\n    _In_opt_ HWND WindowHandle,\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR Parameters\n    )\n{\n    SHELLEXECUTEINFO info;\n\n    memset(&info, 0, sizeof(SHELLEXECUTEINFO));\n    info.cbSize = sizeof(SHELLEXECUTEINFO);\n    info.lpFile = FileName;\n    info.lpParameters = Parameters;\n    info.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC;\n    info.nShow = SW_SHOW;\n    info.hwnd = WindowHandle;\n\n    if (!PhShellExecuteWin32(&info))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to execute the program.\", 0, PhGetLastError());\n    }\n}\n\n/**\n * Opens a file or location through the shell.\n *\n * \\param WindowHandle The window to display user interface components on.\n * \\param FileName A file name or location.\n * \\param Parameters The parameters to pass to the executed application.\n * \\param Directory The default working directory. If this value is NULL, the current process working directory is used.\n * \\param ShowWindowType A value specifying how to show the application.\n * \\param Flags A combination of the following:\n * \\li \\c PH_SHELL_EXECUTE_ADMIN Execute the application elevated.\n * \\li \\c PH_SHELL_EXECUTE_PUMP_MESSAGES Waits on the application while pumping messages, if\n * \\a Timeout is specified.\n * \\param Timeout The number of milliseconds to wait on the application, or 0 to return immediately\n * after the application is started.\n * \\param ProcessHandle A variable which receives a handle to the new process.\n */\nNTSTATUS PhShellExecuteEx(\n    _In_opt_ HWND WindowHandle,\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR Parameters,\n    _In_opt_ PCWSTR Directory,\n    _In_ LONG ShowWindowType,\n    _In_ ULONG Flags,\n    _In_opt_ ULONG Timeout,\n    _Out_opt_ PHANDLE ProcessHandle\n    )\n{\n    SHELLEXECUTEINFO info;\n\n    memset(&info, 0, sizeof(SHELLEXECUTEINFO));\n    info.cbSize = sizeof(SHELLEXECUTEINFO);\n    info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOZONECHECKS;\n    info.hwnd = WindowHandle;\n    info.lpFile = FileName;\n    info.lpParameters = Parameters;\n    info.lpDirectory = Directory;\n    info.nShow = ShowWindowType;\n\n    if (FlagOn(Flags, PH_SHELL_EXECUTE_ADMIN))\n    {\n        info.lpVerb = L\"runas\";\n    }\n\n    if (PhShellExecuteWin32(&info))\n    {\n        if (Timeout)\n        {\n            if (FlagOn(Flags, PH_SHELL_EXECUTE_PUMP_MESSAGES))\n            {\n                PhWaitForMultipleObjectsAndPump(NULL, 1, &info.hProcess, Timeout, QS_ALLEVENTS);\n            }\n            else\n            {\n                if (info.hProcess)\n                {\n                    PhWaitForSingleObject(info.hProcess, Timeout);\n                }\n            }\n        }\n\n        if (ProcessHandle)\n            *ProcessHandle = info.hProcess;\n        else if (info.hProcess)\n            NtClose(info.hProcess);\n\n        return STATUS_SUCCESS;\n    }\n    else\n    {\n        if (ProcessHandle)\n            *ProcessHandle = NULL;\n\n        return PhGetLastWin32ErrorAsNtStatus();\n    }\n}\n\n/**\n * Opens Windows Explorer with a file selected.\n *\n * \\param WindowHandle A handle to the parent window.\n * \\param FileName A file name.\n */\nVOID PhShellExploreFile(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR FileName\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&SHOpenFolderAndSelectItems) SHOpenFolderAndSelectItems_I = NULL;\n    static typeof(&SHParseDisplayName) SHParseDisplayName_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"shell32.dll\"))\n        {\n            SHOpenFolderAndSelectItems_I = PhGetDllBaseProcedureAddress(baseAddress, \"SHOpenFolderAndSelectItems\", 0);\n            SHParseDisplayName_I = PhGetDllBaseProcedureAddress(baseAddress, \"SHParseDisplayName\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (SHOpenFolderAndSelectItems_I && SHParseDisplayName_I)\n    {\n        LPITEMIDLIST item;\n\n        if (SUCCEEDED(SHParseDisplayName_I(FileName, NULL, &item, 0, NULL)))\n        {\n            SHOpenFolderAndSelectItems_I(item, 0, NULL, 0);\n            CoTaskMemFree(item);\n        }\n        else\n        {\n            PhShowError2(WindowHandle, L\"The location could not be found.\", L\"%s\", FileName);\n        }\n    }\n    else\n    {\n        PPH_STRING selectFileName;\n\n        selectFileName = PhConcatStrings2(L\"/select,\", FileName);\n        PhShellExecute(WindowHandle, L\"explorer.exe\", selectFileName->Buffer);\n        PhDereferenceObject(selectFileName);\n    }\n}\n\n/**\n * Shows properties for a file.\n *\n * \\param WindowHandle A handle to the parent window.\n * \\param FileName A file name.\n */\nVOID PhShellProperties(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR FileName\n    )\n{\n    SHELLEXECUTEINFO info;\n\n    memset(&info, 0, sizeof(SHELLEXECUTEINFO));\n    info.cbSize = sizeof(SHELLEXECUTEINFO);\n    info.lpFile = FileName;\n    info.nShow = SW_SHOW;\n    info.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI;\n    info.lpVerb = L\"properties\";\n    info.hwnd = WindowHandle;\n\n    if (!PhShellExecuteWin32(&info))\n    {\n        PhShowStatus(WindowHandle, L\"Unable to execute the program.\", 0, PhGetLastError());\n    }\n}\n\n/**\n * Sends a message to the taskbar's notification area.\n *\n * \\param Message A value that specifies the action to be taken by this function.\n * \\param NotifyIconData A pointer to a NOTIFYICONDATA structure. The content of the structure depends on the value of Message.\n *\n * \\return Successful or errant status.\n */\nBOOLEAN PhShellNotifyIcon(\n    _In_ ULONG Message,\n    _In_ PNOTIFYICONDATAW NotifyIconData\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&Shell_NotifyIconW) Shell_NotifyIconW_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"shell32.dll\"))\n        {\n            Shell_NotifyIconW_I = PhGetDllBaseProcedureAddress(baseAddress, \"Shell_NotifyIconW\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!Shell_NotifyIconW_I)\n        return FALSE;\n\n    return !!Shell_NotifyIconW_I(Message, NotifyIconData);\n}\n\n/**\n * Retrieves the full path of a known folder.\n *\n * \\param rfid A reference that identifies the folder.\n * \\param Flags Flags that control how the folder is retrieved.\n * \\param TokenHandle An access token that represents a particular user.\n * \\param FolderPath Receives the path of the known folder.\n * \\return Successful or errant status.\n */\nHRESULT PhShellGetKnownFolderPath(\n    _In_ PCGUID rfid,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Outptr_ PWSTR* FolderPath\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&SHGetKnownFolderPath) SHGetKnownFolderPath_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"shell32.dll\"))\n        {\n            SHGetKnownFolderPath_I = PhGetDllBaseProcedureAddress(baseAddress, \"SHGetKnownFolderPath\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!SHGetKnownFolderPath_I)\n        return E_FAIL;\n\n    return SHGetKnownFolderPath_I(rfid, Flags, TokenHandle, FolderPath);\n}\n\n/**\n * Retrieves an IShellItem object for a known folder.\n *\n * \\param rfid A reference that identifies the folder.\n * \\param Flags Flags that control how the folder is retrieved.\n * \\param TokenHandle An access token that represents a particular user.\n * \\param riid A reference to the IID of the requested interface.\n * \\param ppv Receives the interface pointer.\n * \\return Successful or errant status.\n */\nHRESULT PhShellGetKnownFolderItem(\n    _In_ PCGUID rfid,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _In_ REFIID riid,\n    _Outptr_ PVOID* ppv\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&SHGetKnownFolderItem) SHGetKnownFolderItem_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"shell32.dll\"))\n        {\n            SHGetKnownFolderItem_I = PhGetDllBaseProcedureAddress(baseAddress, \"SHGetKnownFolderItem\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!SHGetKnownFolderItem_I)\n        return E_FAIL;\n\n    return SHGetKnownFolderItem_I(rfid, Flags, TokenHandle, riid, ppv);\n}\n\n/**\n * Expands registry name abbreviations.\n *\n * \\param KeyName The key name.\n * \\param Computer TRUE to prepend \"Computer\" or \"My Computer\" for use with the Registry Editor.\n */\nPPH_STRING PhExpandKeyName(\n    _In_ PPH_STRING KeyName,\n    _In_ BOOLEAN Computer\n    )\n{\n    PPH_STRING keyName;\n    PPH_STRING tempString;\n\n    if (PhStartsWithString2(KeyName, L\"HKCU\", TRUE))\n    {\n        keyName = PhConcatStrings2(L\"HKEY_CURRENT_USER\", &KeyName->Buffer[4]);\n    }\n    else if (PhStartsWithString2(KeyName, L\"HKU\", TRUE))\n    {\n        keyName = PhConcatStrings2(L\"HKEY_USERS\", &KeyName->Buffer[3]);\n    }\n    else if (PhStartsWithString2(KeyName, L\"HKCR\", TRUE))\n    {\n        keyName = PhConcatStrings2(L\"HKEY_CLASSES_ROOT\", &KeyName->Buffer[4]);\n    }\n    else if (PhStartsWithString2(KeyName, L\"HKLM\", TRUE))\n    {\n        keyName = PhConcatStrings2(L\"HKEY_LOCAL_MACHINE\", &KeyName->Buffer[4]);\n    }\n    else\n    {\n        PhSetReference(&keyName, KeyName);\n    }\n\n    if (Computer)\n    {\n        tempString = PhConcatStrings2(L\"Computer\\\\\", keyName->Buffer);\n        PhDereferenceObject(keyName);\n        keyName = tempString;\n    }\n\n    return keyName;\n}\n\n/**\n * Gets a registry string value.\n *\n * \\param KeyHandle A handle to the key.\n * \\param ValueName The name of the value.\n * \\return A pointer to a string containing the value, or NULL if the function failed. You must free\n * the string using PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhQueryRegistryString(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName\n    )\n{\n    PPH_STRING string = NULL;\n    PKEY_VALUE_PARTIAL_INFORMATION buffer;\n\n    if (NT_SUCCESS(PhQueryValueKey(KeyHandle, ValueName, KeyValuePartialInformation, &buffer)))\n    {\n        if (buffer->Type == REG_SZ ||\n            buffer->Type == REG_MULTI_SZ ||\n            buffer->Type == REG_EXPAND_SZ)\n        {\n            if (!(buffer->DataLength & 1)) // validate the string length\n            {\n                if (buffer->DataLength >= sizeof(UNICODE_NULL))\n                    string = PhCreateStringEx((PWCHAR)buffer->Data, buffer->DataLength - sizeof(UNICODE_NULL));\n                else\n                    string = PhReferenceEmptyString();\n            }\n        }\n\n        PhFree(buffer);\n    }\n\n    return string;\n}\n\n/**\n * Gets a registry ULONG value.\n *\n * \\param KeyHandle A handle to the key.\n * \\param ValueName The name of the value.\n * \\return The value, or ULONG_MAX if the function failed.\n */\nULONG PhQueryRegistryUlong(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName\n    )\n{\n    ULONG ulong = ULONG_MAX;\n    PKEY_VALUE_PARTIAL_INFORMATION buffer;\n\n    if (NT_SUCCESS(PhQueryValueKey(KeyHandle, ValueName, KeyValuePartialInformation, &buffer)))\n    {\n        if (buffer->Type == REG_DWORD)\n        {\n            if (buffer->DataLength == sizeof(ULONG))\n                ulong = *(PULONG)buffer->Data;\n        }\n\n        PhFree(buffer);\n    }\n\n    return ulong;\n}\n\n/**\n * Gets a registry ULONG64 value.\n *\n * \\param KeyHandle A handle to the key.\n * \\param ValueName The name of the value.\n * \\return The value, or ULLONG_MAX if the function failed.\n */\nULONG64 PhQueryRegistryUlong64(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PCPH_STRINGREF ValueName\n    )\n{\n    ULONG64 ulong64 = ULLONG_MAX;\n    PKEY_VALUE_PARTIAL_INFORMATION buffer;\n\n    if (NT_SUCCESS(PhQueryValueKey(KeyHandle, ValueName, KeyValuePartialInformation, &buffer)))\n    {\n        if (buffer->Type == REG_DWORD)\n        {\n            if (buffer->DataLength == sizeof(ULONG))\n                ulong64 = *(PULONG)buffer->Data;\n        }\n        else if (buffer->Type == REG_QWORD)\n        {\n            if (buffer->DataLength == sizeof(ULONG64))\n                ulong64 = *(PULONG64)buffer->Data;\n        }\n\n        PhFree(buffer);\n    }\n\n    return ulong64;\n}\n\n/**\n * Maps flags from one set to another.\n *\n * \\param Value2 A pointer to the destination flags.\n * \\param Value1 The source flags.\n * \\param Mappings An array of flag mappings.\n * \\param NumberOfMappings The number of mappings.\n */\nVOID PhMapFlags1(\n    _Inout_ PULONG Value2,\n    _In_ ULONG Value1,\n    _In_ const PH_FLAG_MAPPING *Mappings,\n    _In_ ULONG NumberOfMappings\n    )\n{\n    ULONG i;\n    ULONG value2;\n\n    value2 = *Value2;\n\n    if (value2 != 0)\n    {\n        // There are existing flags. Map the flags we know about by clearing/setting them. The flags\n        // we don't know about won't be affected.\n\n        for (i = 0; i < NumberOfMappings; i++)\n        {\n            if (Value1 & Mappings[i].Flag1)\n                value2 |= Mappings[i].Flag2;\n            else\n                value2 &= ~Mappings[i].Flag2;\n        }\n    }\n    else\n    {\n        // There are no existing flags, which means we can build the value from scratch, with no\n        // clearing needed.\n\n        for (i = 0; i < NumberOfMappings; i++)\n        {\n            if (Value1 & Mappings[i].Flag1)\n                value2 |= Mappings[i].Flag2;\n        }\n    }\n\n    *Value2 = value2;\n}\n\n/**\n * Maps flags from one set to another.\n *\n * \\param Value1 A pointer to the destination flags.\n * \\param Value2 The source flags.\n * \\param Mappings An array of flag mappings.\n * \\param NumberOfMappings The number of mappings.\n */\nVOID PhMapFlags2(\n    _Inout_ PULONG Value1,\n    _In_ ULONG Value2,\n    _In_ const PH_FLAG_MAPPING *Mappings,\n    _In_ ULONG NumberOfMappings\n    )\n{\n    ULONG i;\n    ULONG value1;\n\n    value1 = *Value1;\n\n    if (value1 != 0)\n    {\n        for (i = 0; i < NumberOfMappings; i++)\n        {\n            if (Value2 & Mappings[i].Flag2)\n                value1 |= Mappings[i].Flag1;\n            else\n                value1 &= ~Mappings[i].Flag1;\n        }\n    }\n    else\n    {\n        for (i = 0; i < NumberOfMappings; i++)\n        {\n            if (Value2 & Mappings[i].Flag2)\n                value1 |= Mappings[i].Flag1;\n        }\n    }\n\n    *Value1 = value1;\n}\n\n/**\n * Internal hook procedure for the file dialog.\n *\n * \\param hdlg The handle to the file dialog.\n * \\param uiMsg The message.\n * \\param wParam The first message parameter.\n * \\param lParam The second message parameter.\n * \\return The message result.\n */\nUINT_PTR CALLBACK PhpOpenFileNameHookProc(\n    _In_ HWND hdlg,\n    _In_ UINT uiMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uiMsg)\n    {\n    case WM_NOTIFY:\n        {\n            LPOFNOTIFY header = (LPOFNOTIFY)lParam;\n\n            // We can't use CDN_FILEOK because it's not sent if the buffer is too small, defeating\n            // the entire purpose of this callback function.\n\n            switch (header->hdr.code)\n            {\n            case CDN_SELCHANGE:\n                {\n                    ULONG returnLength;\n\n                    returnLength = CommDlg_OpenSave_GetFilePath(\n                        header->hdr.hwndFrom,\n                        header->lpOFN->lpstrFile,\n                        header->lpOFN->nMaxFile\n                        );\n\n                    if ((LONG)returnLength > 0 && returnLength > header->lpOFN->nMaxFile)\n                    {\n                        PhFree(header->lpOFN->lpstrFile);\n                        header->lpOFN->nMaxFile = returnLength + 0x200; // pre-allocate some more\n                        header->lpOFN->lpstrFile = PhAllocate(header->lpOFN->nMaxFile * sizeof(WCHAR));\n\n                        returnLength = CommDlg_OpenSave_GetFilePath(\n                            header->hdr.hwndFrom,\n                            header->lpOFN->lpstrFile,\n                            header->lpOFN->nMaxFile\n                            );\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\n/**\n * Internal function to create an OPENFILENAME structure.\n *\n * \\return A pointer to the OPENFILENAME structure.\n */\nOPENFILENAME *PhpCreateOpenFileName(\n    VOID\n    )\n{\n    OPENFILENAME *ofn;\n\n    ofn = PhAllocateZero(sizeof(OPENFILENAME));\n    ofn->lStructSize = sizeof(OPENFILENAME);\n    ofn->nMaxFile = 0x400;\n    ofn->lpstrFile = PhAllocate(ofn->nMaxFile * sizeof(WCHAR));\n    ofn->lpstrFileTitle = NULL;\n    ofn->Flags = OFN_ENABLEHOOK | OFN_EXPLORER;\n    ofn->lpfnHook = PhpOpenFileNameHookProc;\n\n    ofn->lpstrFile[0] = UNICODE_NULL;\n\n    return ofn;\n}\n\n/**\n * Internal function to free an OPENFILENAME structure.\n *\n * \\param OpenFileName The structure to free.\n */\nVOID PhpFreeOpenFileName(\n    _In_ OPENFILENAME *OpenFileName\n    )\n{\n    if (OpenFileName->lpstrFilter) PhFree((PVOID)OpenFileName->lpstrFilter);\n    if (OpenFileName->lpstrFile) PhFree((PVOID)OpenFileName->lpstrFile);\n\n    PhFree(OpenFileName);\n}\n\ntypedef struct _PHP_FILE_DIALOG\n{\n    BOOLEAN UseIFileDialog;\n    BOOLEAN Save;\n    union\n    {\n        OPENFILENAME *OpenFileName;\n        IFileDialog *FileDialog;\n    } u;\n} PHP_FILE_DIALOG, *PPHP_FILE_DIALOG;\n\n/**\n * Internal function to create a PHP_FILE_DIALOG structure.\n *\n * \\param Save TRUE if this is a save dialog, FALSE for an open dialog.\n * \\param OpenFileName An optional OPENFILENAME structure.\n * \\param FileDialog An optional IFileDialog interface.\n * \\return A pointer to the PHP_FILE_DIALOG structure.\n */\nPPHP_FILE_DIALOG PhpCreateFileDialog(\n    _In_ BOOLEAN Save,\n    _In_opt_ OPENFILENAME *OpenFileName,\n    _In_opt_ IFileDialog *FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog;\n\n    assert(!!OpenFileName != !!FileDialog);\n    fileDialog = PhAllocate(sizeof(PHP_FILE_DIALOG));\n    fileDialog->Save = Save;\n\n    if (OpenFileName)\n    {\n        fileDialog->UseIFileDialog = FALSE;\n        fileDialog->u.OpenFileName = OpenFileName;\n    }\n    else if (FileDialog)\n    {\n        fileDialog->UseIFileDialog = TRUE;\n        fileDialog->u.FileDialog = FileDialog;\n    }\n    else\n    {\n        PhRaiseStatus(STATUS_INVALID_PARAMETER);\n    }\n\n    return fileDialog;\n}\n\n/**\n * Creates a file dialog for the user to select a file to open.\n *\n * \\return An opaque pointer representing the file dialog. You must free the file dialog using\n * PhFreeFileDialog() when you no longer need it.\n */\nPVOID PhCreateOpenFileDialog(\n    VOID\n    )\n{\n    IFileDialog *fileDialog;\n\n    if (SUCCEEDED(PhGetClassObject(\n        L\"comdlg32.dll\",\n        &CLSID_FileOpenDialog,\n        &IID_IFileDialog,\n        &fileDialog\n        )))\n    {\n        // The default options are fine.\n        return PhpCreateFileDialog(FALSE, NULL, fileDialog);\n    }\n\n    return NULL;\n}\n\n/**\n * Creates a file dialog for the user to select a file to save to.\n *\n * \\return An opaque pointer representing the file dialog. You must free the file dialog using\n * PhFreeFileDialog() when you no longer need it.\n */\nPVOID PhCreateSaveFileDialog(\n    VOID\n    )\n{\n    IFileDialog *fileDialog;\n\n    if (SUCCEEDED(PhGetClassObject(\n        L\"comdlg32.dll\",\n        &CLSID_FileSaveDialog,\n        &IID_IFileDialog,\n        &fileDialog\n        )))\n    {\n        // The default options are fine.\n        return PhpCreateFileDialog(TRUE, NULL, fileDialog);\n    }\n\n    return NULL;\n}\n\n/**\n * Frees a file dialog.\n *\n * \\param FileDialog The file dialog.\n */\nVOID PhFreeFileDialog(\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        IFileDialog_Release(fileDialog->u.FileDialog);\n    }\n    else\n    {\n        PhpFreeOpenFileName(fileDialog->u.OpenFileName);\n    }\n\n    PhFree(fileDialog);\n}\n\n/**\n * Shows a file dialog to the user.\n *\n * \\param WindowHandle A handle to the parent window.\n * \\param FileDialog The file dialog.\n *\n * \\return TRUE if the user selected a file, FALSE if the user cancelled the operation or an error\n * occurred.\n */\nBOOLEAN PhShowFileDialog(\n    _In_opt_ HWND WindowHandle,\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        // Set a blank default extension. This will have an effect when the user selects a different\n        // file type.\n        IFileDialog_SetDefaultExtension(fileDialog->u.FileDialog, L\"\");\n\n        return SUCCEEDED(IFileDialog_Show(fileDialog->u.FileDialog, WindowHandle));\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n\n        ofn->hwndOwner = WindowHandle;\n\n        // Determine whether the structure represents a open or save dialog and call the appropriate\n        // function.\n        if (!fileDialog->Save)\n        {\n            return GetOpenFileName(ofn);\n        }\n        else\n        {\n            return GetSaveFileName(ofn);\n        }\n    }\n}\n\nstatic const PH_FLAG_MAPPING PhpFileDialogIfdMappings[] =\n{\n    { PH_FILEDIALOG_CREATEPROMPT, FOS_CREATEPROMPT },\n    { PH_FILEDIALOG_PATHMUSTEXIST, FOS_PATHMUSTEXIST },\n    { PH_FILEDIALOG_FILEMUSTEXIST, FOS_FILEMUSTEXIST },\n    { PH_FILEDIALOG_SHOWHIDDEN, FOS_FORCESHOWHIDDEN },\n    { PH_FILEDIALOG_NODEREFERENCELINKS, FOS_NODEREFERENCELINKS },\n    { PH_FILEDIALOG_OVERWRITEPROMPT, FOS_OVERWRITEPROMPT },\n    { PH_FILEDIALOG_DEFAULTEXPANDED, FOS_DEFAULTNOMINIMODE },\n    { PH_FILEDIALOG_STRICTFILETYPES, FOS_STRICTFILETYPES },\n    { PH_FILEDIALOG_PICKFOLDERS, FOS_PICKFOLDERS },\n    { PH_FILEDIALOG_NOPATHVALIDATE, FOS_NOVALIDATE },\n    { PH_FILEDIALOG_DONTADDTORECENT, FOS_DONTADDTORECENT },\n};\n\nstatic const PH_FLAG_MAPPING PhpFileDialogOfnMappings[] =\n{\n    { PH_FILEDIALOG_CREATEPROMPT, OFN_CREATEPROMPT },\n    { PH_FILEDIALOG_PATHMUSTEXIST, OFN_PATHMUSTEXIST },\n    { PH_FILEDIALOG_FILEMUSTEXIST, OFN_FILEMUSTEXIST },\n    { PH_FILEDIALOG_SHOWHIDDEN, OFN_FORCESHOWHIDDEN },\n    { PH_FILEDIALOG_NODEREFERENCELINKS, OFN_NODEREFERENCELINKS },\n    { PH_FILEDIALOG_OVERWRITEPROMPT, OFN_OVERWRITEPROMPT },\n    { PH_FILEDIALOG_NOPATHVALIDATE, OFN_NOVALIDATE },\n    { PH_FILEDIALOG_DONTADDTORECENT, OFN_DONTADDTORECENT },\n};\n\n/**\n * Gets the options for a file dialog.\n *\n * \\param FileDialog The file dialog.\n *\n * \\return The currently enabled options. See the documentation for PhSetFileDialogOptions() for\n * details.\n */\nULONG PhGetFileDialogOptions(\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        FILEOPENDIALOGOPTIONS dialogOptions;\n        ULONG options;\n\n        if (SUCCEEDED(IFileDialog_GetOptions(fileDialog->u.FileDialog, &dialogOptions)))\n        {\n            options = 0;\n\n            PhMapFlags2(\n                &options,\n                dialogOptions,\n                PhpFileDialogIfdMappings,\n                sizeof(PhpFileDialogIfdMappings) / sizeof(PH_FLAG_MAPPING)\n                );\n\n            return options;\n        }\n        else\n        {\n            return 0;\n        }\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n        ULONG options;\n\n        options = 0;\n\n        PhMapFlags2(\n            &options,\n            ofn->Flags,\n            PhpFileDialogOfnMappings,\n            sizeof(PhpFileDialogOfnMappings) / sizeof(PH_FLAG_MAPPING)\n            );\n\n        return options;\n    }\n}\n\n/**\n * Sets the options for a file dialog.\n *\n * \\param FileDialog The file dialog.\n * \\param Options A combination of flags specifying the options.\n * \\li \\c PH_FILEDIALOG_CREATEPROMPT A prompt for creation will be displayed when the selected item\n * does not exist. This is only valid for Save dialogs.\n * \\li \\c PH_FILEDIALOG_PATHMUSTEXIST The selected item must be in an existing folder. This is\n * enabled by default.\n * \\li \\c PH_FILEDIALOG_FILEMUSTEXIST The selected item must exist. This is enabled by default and\n * is only valid for Open dialogs.\n * \\li \\c PH_FILEDIALOG_SHOWHIDDEN Items with the System and Hidden attributes will be displayed.\n * \\li \\c PH_FILEDIALOG_NODEREFERENCELINKS Shortcuts will not be followed, allowing .lnk files to be\n * opened.\n * \\li \\c PH_FILEDIALOG_OVERWRITEPROMPT An overwrite prompt will be displayed if an existing item is\n * selected. This is enabled by default and is only valid for Save dialogs.\n * \\li \\c PH_FILEDIALOG_DEFAULTEXPANDED The file dialog should be expanded by default (i.e. the\n * folder browser should be displayed). This is only valid for Save dialogs.\n */\nVOID PhSetFileDialogOptions(\n    _In_ PVOID FileDialog,\n    _In_ ULONG Options\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        FILEOPENDIALOGOPTIONS dialogOptions;\n\n        if (SUCCEEDED(IFileDialog_GetOptions(fileDialog->u.FileDialog, &dialogOptions)))\n        {\n            PhMapFlags1(\n                &dialogOptions,\n                Options,\n                PhpFileDialogIfdMappings,\n                sizeof(PhpFileDialogIfdMappings) / sizeof(PH_FLAG_MAPPING)\n                );\n\n            IFileDialog_SetOptions(fileDialog->u.FileDialog, dialogOptions);\n        }\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n\n        PhMapFlags1(\n            &ofn->Flags,\n            Options,\n            PhpFileDialogOfnMappings,\n            sizeof(PhpFileDialogOfnMappings) / sizeof(PH_FLAG_MAPPING)\n            );\n    }\n}\n\n/**\n * Gets the index of the currently selected file type filter for a file dialog.\n *\n * \\param FileDialog The file dialog.\n *\n * \\return The one-based index of the selected file type, or 0 if an error occurred.\n */\nULONG PhGetFileDialogFilterIndex(\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        ULONG index;\n\n        if (SUCCEEDED(IFileDialog_GetFileTypeIndex(fileDialog->u.FileDialog, &index)))\n        {\n            return index;\n        }\n        else\n        {\n            return 0;\n        }\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n\n        return ofn->nFilterIndex;\n    }\n}\n\n/**\n * Sets the file type filter for a file dialog.\n *\n * \\param FileDialog The file dialog.\n * \\param Filters A pointer to an array of file type structures.\n * \\param NumberOfFilters The number of file types.\n */\nVOID PhSetFileDialogFilter(\n    _In_ PVOID FileDialog,\n    _In_ PPH_FILETYPE_FILTER Filters,\n    _In_ ULONG NumberOfFilters\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        IFileDialog_SetFileTypes(\n            fileDialog->u.FileDialog,\n            NumberOfFilters,\n            (COMDLG_FILTERSPEC *)Filters\n            );\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n        PPH_STRING filterString;\n        PH_STRING_BUILDER filterBuilder;\n        ULONG i;\n\n        PhInitializeStringBuilder(&filterBuilder, 10);\n\n        for (i = 0; i < NumberOfFilters; i++)\n        {\n            PhAppendStringBuilder2(&filterBuilder, Filters[i].Name);\n            PhAppendCharStringBuilder(&filterBuilder, 0);\n            PhAppendStringBuilder2(&filterBuilder, Filters[i].Filter);\n            PhAppendCharStringBuilder(&filterBuilder, 0);\n        }\n\n        filterString = PhFinalStringBuilderString(&filterBuilder);\n\n        if (ofn->lpstrFilter)\n            PhFree((PVOID)ofn->lpstrFilter);\n\n        ofn->lpstrFilter = PhAllocateCopy(filterString->Buffer, filterString->Length + sizeof(UNICODE_NULL));\n        PhDereferenceObject(filterString);\n    }\n}\n\n/**\n * Gets the file name selected in a file dialog.\n *\n * \\param FileDialog The file dialog.\n *\n * \\return A pointer to a string containing the file name. You must free the string using\n * PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhGetFileDialogFileName(\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        IShellItem *result;\n        PPH_STRING fileName = NULL;\n\n        if (SUCCEEDED(IFileDialog_GetResult(fileDialog->u.FileDialog, &result)))\n        {\n            PWSTR name;\n\n            if (SUCCEEDED(IShellItem_GetDisplayName(result, SIGDN_FILESYSPATH, &name)))\n            {\n                fileName = PhCreateString(name);\n                CoTaskMemFree(name);\n            }\n\n            IShellItem_Release(result);\n        }\n\n        if (PhIsNullOrEmptyString(fileName))\n        {\n            PWSTR name;\n\n            if (SUCCEEDED(IFileDialog_GetFileName(fileDialog->u.FileDialog, &name)))\n            {\n                fileName = PhCreateString(name);\n                CoTaskMemFree(name);\n            }\n        }\n\n        if (PhIsNullOrEmptyString(fileName))\n        {\n            // NOTE: When the user selects IShellItem types with SIGDN_URL from the OpenFileDialog/SaveFileDialog\n            // the shell returns S_OK for the file dialog then immediately returns E_FAIL when we query the filename.\n            // This case was unexpected, and plugins/legacy callers will auto-dereference the filename when the dialog\n            // returns success, so return an empty string to prevent plugins/legacy callers referencing invalid memory. (dmex)\n            PhMoveReference(&fileName, PhReferenceEmptyString());\n        }\n\n        return fileName;\n    }\n    else\n    {\n        return PhCreateString(fileDialog->u.OpenFileName->lpstrFile);\n    }\n}\n\n/**\n * Sets the file name of a file dialog.\n *\n * \\param FileDialog The file dialog.\n * \\param FileName The new file name.\n */\nVOID PhSetFileDialogFileName(\n    _In_ PVOID FileDialog,\n    _In_ PCWSTR FileName\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&SHParseDisplayName) SHParseDisplayName_I = NULL;\n    static typeof(&SHCreateItemFromIDList) SHCreateItemFromIDList_I = NULL;\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n    PH_STRINGREF fileName;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"shell32.dll\"))\n        {\n            SHParseDisplayName_I = PhGetDllBaseProcedureAddress(baseAddress, \"SHParseDisplayName\", 0);\n            SHCreateItemFromIDList_I = PhGetDllBaseProcedureAddress(baseAddress, \"SHCreateItemFromIDList\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    PhInitializeStringRefLongHint(&fileName, FileName);\n\n    if (fileDialog->UseIFileDialog)\n    {\n        IShellItem *shellItem = NULL;\n        PH_STRINGREF pathNamePart;\n        PH_STRINGREF baseNamePart;\n\n        if (PhGetBasePath(&fileName, &pathNamePart, &baseNamePart) && SHParseDisplayName_I && SHCreateItemFromIDList_I)\n        {\n            LPITEMIDLIST item;\n            PPH_STRING pathName;\n\n            pathName = PhCreateString2(&pathNamePart);\n\n            if (SUCCEEDED(SHParseDisplayName_I(pathName->Buffer, NULL, &item, 0, NULL)))\n            {\n                SHCreateItemFromIDList_I(item, &IID_IShellItem, &shellItem);\n                CoTaskMemFree(item);\n            }\n\n            PhDereferenceObject(pathName);\n        }\n\n        if (shellItem)\n        {\n            IFileDialog_SetFolder(fileDialog->u.FileDialog, shellItem);\n            IFileDialog_SetFileName(fileDialog->u.FileDialog, baseNamePart.Buffer);\n            IShellItem_Release(shellItem);\n        }\n        else\n        {\n            IFileDialog_SetFileName(fileDialog->u.FileDialog, FileName);\n        }\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n\n        if (PhFindCharInStringRef(&fileName, L'/', FALSE) != SIZE_MAX || PhFindCharInStringRef(&fileName, L'\\\"', FALSE) != SIZE_MAX)\n        {\n            // It refuses to take any filenames with a slash or quotation mark.\n            return;\n        }\n\n        PhFree(ofn->lpstrFile);\n\n        ofn->nMaxFile = (ULONG)__max(fileName.Length / sizeof(WCHAR) + 1, 0x400);\n        ofn->lpstrFile = PhAllocate(ofn->nMaxFile * sizeof(WCHAR));\n        memcpy(ofn->lpstrFile, fileName.Buffer, fileName.Length + sizeof(UNICODE_NULL));\n    }\n}\n\n/**\n * Determines if an executable image is packed.\n *\n * \\param FileName The file name of the image.\n * \\param IsPacked A variable that receives TRUE if the image is packed, otherwise FALSE.\n * \\param NumberOfModules A variable that receives the number of DLLs that the image imports\n * functions from.\n * \\param NumberOfFunctions A variable that receives the number of functions that the image imports.\n */\nNTSTATUS PhIsExecutablePacked(\n    _In_ PPH_STRING FileName,\n    _Out_ PBOOLEAN IsPacked,\n    _Out_opt_ PULONG NumberOfModules,\n    _Out_opt_ PULONG NumberOfFunctions\n    )\n{\n    // An image is packed if:\n    //\n    // 1. It references fewer than 3 modules, and\n    // 2. It imports fewer than 5 functions, and\n    // 3. It does not use the Native subsystem.\n    //\n    // Or:\n    //\n    // 1. The function-to-module ratio is lower than 3 (on average fewer than 3 functions are\n    //    imported from each module), and\n    // 2. It references more than 2 modules but fewer than 6 modules.\n    //\n    // Or:\n    //\n    // 1. The function-to-module ratio is lower than 2 (on average fewer than 2 functions are\n    //    imported from each module), and\n    // 2. It references more than 5 modules but fewer than 31 modules.\n    //\n    // Or:\n    //\n    // 1. It does not have a section named \".text\".\n    //\n    // An image is not considered to be packed if it has only one import from a module named\n    // \"mscoree.dll\".\n\n    NTSTATUS status;\n    PH_MAPPED_IMAGE mappedImage;\n    PH_MAPPED_IMAGE_IMPORTS imports;\n    PH_MAPPED_IMAGE_IMPORT_DLL importDll;\n    ULONG i;\n    //ULONG limitNumberOfSections;\n    ULONG limitNumberOfModules;\n    ULONG numberOfModules;\n    ULONG numberOfFunctions = 0;\n    BOOLEAN hasTextSection = FALSE;\n    BOOLEAN isModuleMscoree = FALSE;\n    BOOLEAN isPacked;\n\n    status = PhLoadMappedImageEx(\n        &FileName->sr,\n        NULL,\n        &mappedImage\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Go through the sections and look for the \".text\" section.\n\n#if defined(PH_ISEXECUTABLEPACKED_SECTION)\n    limitNumberOfSections = min(mappedImage.NumberOfSections, 64);\n\n    for (i = 0; i < limitNumberOfSections; i++)\n    {\n        WCHAR sectionName[IMAGE_SIZEOF_SHORT_NAME + 1];\n\n        if (NT_SUCCESS(PhGetMappedImageSectionName(\n            &mappedImage.Sections[i],\n            sectionName,\n            RTL_NUMBER_OF(sectionName),\n            NULL\n            )))\n        {\n            if (PhEqualStringZ(sectionName, \".text\", TRUE))\n            {\n                hasTextSection = TRUE;\n                break;\n            }\n        }\n    }\n#else\n    hasTextSection = TRUE;\n#endif\n\n    status = PhGetMappedImageImports(\n        &imports,\n        &mappedImage\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Get the module and function totals.\n\n    numberOfModules = imports.NumberOfDlls;\n    limitNumberOfModules = __min(numberOfModules, 64);\n\n    for (i = 0; i < limitNumberOfModules; i++)\n    {\n        if (!NT_SUCCESS(status = PhGetMappedImageImportDll(\n            &imports,\n            i,\n            &importDll\n            )))\n            goto CleanupExit;\n\n        if (PhEqualBytesZ(importDll.Name, \"mscoree.dll\", TRUE))\n            isModuleMscoree = TRUE;\n\n        numberOfFunctions += importDll.NumberOfEntries;\n    }\n\n    // Determine if the image is packed.\n\n    if (\n        numberOfModules != 0 &&\n        (\n        // Rule 1\n        (numberOfModules < 3 && numberOfFunctions < 5 &&\n        mappedImage.NtHeaders->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) ||\n        // Rule 2\n        ((numberOfFunctions / numberOfModules) < 3 &&\n        numberOfModules > 2 && numberOfModules < 5) ||\n        // Rule 3\n        ((numberOfFunctions / numberOfModules) < 2 &&\n        numberOfModules > 4 && numberOfModules < 31) ||\n        // Rule 4\n        !hasTextSection\n        ) &&\n        // Additional .NET rule\n        !(numberOfModules == 1 && numberOfFunctions == 1 && isModuleMscoree)\n        )\n    {\n        isPacked = TRUE;\n    }\n    else\n    {\n        isPacked = FALSE;\n    }\n\n    *IsPacked = isPacked;\n\n    if (NumberOfModules)\n        *NumberOfModules = numberOfModules;\n    if (NumberOfFunctions)\n        *NumberOfFunctions = numberOfFunctions;\n\nCleanupExit:\n    PhUnloadMappedImage(&mappedImage);\n\n    return status;\n}\n\n/**\n * \\brief CRC-32 (Ethernet, ZIP - polynomial 0xedb88320 - TEST=0xEEEA93B8)\n *\n * \\param Crc Crc\n * \\param Buffer Buffer\n * \\param Length Length\n * \\return Crc\n */\nULONG PhCrc32(\n    _In_ ULONG Crc,\n    _In_reads_(Length) PUCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    Crc ^= 0xffffffff;\n\n    while (Length--)\n        Crc = (Crc >> 8) ^ PhCrc32Table[(Crc ^ *Buffer++) & 0xff];\n\n    return Crc ^ 0xffffffff;\n}\n\n/**\n * \\brief CRC-32C (iSCSI - polynomial 0x82f63b78 - TEST=0xEFF7F083)\n *\n * \\param Crc Crc\n * \\param Buffer Buffer\n * \\param Length Length\n * \\return Crc\n */\nULONG PhCrc32C(\n    _In_ ULONG Crc,\n    _In_reads_(Length) PVOID Buffer,\n    _In_ SIZE_T Length\n    )\n{\n#if defined(_WIN64)\n    SIZE_T u64_blocks = Length / sizeof(ULONG64);\n    SIZE_T u64_remaining = Length % sizeof(ULONG64);\n#else\n    SIZE_T u64_remaining = Length;\n#endif\n    SIZE_T u32_blocks = u64_remaining / sizeof(ULONG);\n    SIZE_T u32_remaining = u64_remaining % sizeof(ULONG);\n    SIZE_T u16_blocks = u32_remaining / sizeof(USHORT);\n    SIZE_T u8_blocks = u32_remaining % sizeof(UCHAR);\n\n    Crc ^= 0xffffffff;\n\n#if defined(_WIN64)\n    while (u64_blocks--)\n    {\n#if defined(_M_ARM64)\n        Crc = __crc32d(Crc, *(PULONG64)Buffer);\n#else\n        Crc = (ULONG)_mm_crc32_u64(Crc, *(PULONG64)Buffer);\n#endif\n        Buffer = (PULONG64)Buffer + 1;\n    }\n#endif\n\n    while (u32_blocks--)\n    {\n#if defined(_M_ARM64)\n        Crc = __crc32w(Crc, *(PULONG)Buffer);\n#else\n        Crc = _mm_crc32_u32(Crc, *(PULONG)Buffer);\n#endif\n        Buffer = (PULONG)Buffer + 1;\n    }\n\n    while (u16_blocks--)\n    {\n#if defined(_M_ARM64)\n        Crc = __crc32h(Crc, *(PUSHORT)Buffer);\n#else\n        Crc = _mm_crc32_u16(Crc, *(PUSHORT)Buffer);\n#endif\n        Buffer = (PUSHORT)Buffer + 1;\n    }\n\n    while (u8_blocks--)\n    {\n#if defined(_M_ARM64)\n        Crc = __crc32b(Crc, *(PUCHAR)Buffer);\n#else\n        Crc = _mm_crc32_u8(Crc, *(PUCHAR)Buffer);\n#endif\n        Buffer = (PUCHAR)Buffer + 1;\n    }\n\n    return Crc ^ 0xffffffff;\n}\n\nstatic_assert(RTL_FIELD_SIZE(PH_HASH_CONTEXT, Context) >= sizeof(MD5_CTX), \"RTL_FIELD_SIZE(PH_HASH_CONTEXT, Context) >= sizeof(MD5_CTX)\");\nstatic_assert(RTL_FIELD_SIZE(PH_HASH_CONTEXT, Context) >= sizeof(A_SHA_CTX), \"RTL_FIELD_SIZE(PH_HASH_CONTEXT, Context) >= sizeof(A_SHA_CTX)\");\nstatic_assert(RTL_FIELD_SIZE(PH_HASH_CONTEXT, Context) >= sizeof(sha256_context), \"RTL_FIELD_SIZE(PH_HASH_CONTEXT, Context) >= sizeof(sha256_context)\");\n\n/**\n * Initializes hashing.\n *\n * \\param Context A hashing context structure.\n * \\param Algorithm The hash algorithm to use:\n * \\li \\c Md5HashAlgorithm MD5 (128 bits)\n * \\li \\c Sha1HashAlgorithm SHA-1 (160 bits)\n * \\li \\c Crc32HashAlgorithm CRC-32-IEEE 802.3 (32 bits)\n * \\li \\c Sha256HashAlgorithm SHA-256 (256 bits)\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhInitializeHash(\n    _Out_ PPH_HASH_CONTEXT Context,\n    _In_ PH_HASH_ALGORITHM Algorithm\n    )\n{\n    Context->Algorithm = Algorithm;\n\n    switch (Algorithm)\n    {\n    case Crc32HashAlgorithm:\n    case Crc32CHashAlgorithm:\n        Context->Context[0] = 0;\n        return STATUS_SUCCESS;\n    case Md5HashAlgorithm:\n        MD5Init((MD5_CTX *)Context->Context);\n        return STATUS_SUCCESS;\n    case Sha1HashAlgorithm:\n        A_SHAInit((A_SHA_CTX *)Context->Context);\n        return STATUS_SUCCESS;\n    case Sha256HashAlgorithm:\n        sha256_starts((sha256_context *)Context->Context);\n        return STATUS_SUCCESS;\n    default:\n        return STATUS_INVALID_PARAMETER_2;\n    }\n}\n\n/**\n * Hashes a block of data.\n *\n * \\param Context A hashing context structure.\n * \\param Buffer The block of data.\n * \\param Length The number of bytes in the block.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhUpdateHash(\n    _In_ PPH_HASH_CONTEXT Context,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    )\n{\n    switch (Context->Algorithm)\n    {\n    case Crc32HashAlgorithm:\n        Context->Context[0] = PhCrc32(Context->Context[0], (PUCHAR)Buffer, Length);\n        return STATUS_SUCCESS;\n    case Crc32CHashAlgorithm:\n        Context->Context[0] = PhCrc32C(Context->Context[0], (PUCHAR)Buffer, Length);\n        return STATUS_SUCCESS;\n    case Md5HashAlgorithm:\n        MD5Update((MD5_CTX *)Context->Context, (PUCHAR)Buffer, Length);\n        return STATUS_SUCCESS;\n    case Sha1HashAlgorithm:\n        A_SHAUpdate((A_SHA_CTX *)Context->Context, (PUCHAR)Buffer, Length);\n        return STATUS_SUCCESS;\n    case Sha256HashAlgorithm:\n        sha256_update((sha256_context *)Context->Context, (PUCHAR)Buffer, Length);\n        return STATUS_SUCCESS;\n    default:\n        return STATUS_INVALID_PARAMETER;\n    }\n}\n\n/**\n * Computes the final hash value.\n *\n * \\param Context A hashing context structure.\n * \\param Hash A buffer which receives the final hash value.\n * \\param HashLength The size of the buffer, in bytes.\n * \\param ReturnLength A variable which receives the required size of the buffer, in bytes.\n */\nNTSTATUS PhFinalHash(\n    _In_ PPH_HASH_CONTEXT Context,\n    _Out_writes_bytes_(HashLength) PVOID Hash,\n    _In_ ULONG HashLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status;\n\n    switch (Context->Algorithm)\n    {\n    case Crc32HashAlgorithm:\n    case Crc32CHashAlgorithm:\n        {\n            if (HashLength >= PH_HASH_CRC32_LENGTH)\n            {\n                *(PULONG)Hash = Context->Context[0];\n                status = STATUS_SUCCESS;\n            }\n            else\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n            }\n\n            if (ReturnLength)\n            {\n                *ReturnLength = PH_HASH_CRC32_LENGTH;\n            }\n        }\n        break;\n    case Md5HashAlgorithm:\n        {\n            if (HashLength >= PH_HASH_MD5_LENGTH)\n            {\n                MD5Final((MD5_CTX*)Context->Context);\n                memcpy(Hash, ((MD5_CTX*)Context->Context)->digest, PH_HASH_MD5_LENGTH);\n                status = STATUS_SUCCESS;\n            }\n            else\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n            }\n\n            if (ReturnLength)\n            {\n                *ReturnLength = PH_HASH_MD5_LENGTH;\n            }\n        }\n        break;\n    case Sha1HashAlgorithm:\n        {\n            if (HashLength >= PH_HASH_SHA1_LENGTH)\n            {\n                A_SHAFinal((A_SHA_CTX*)Context->Context, (PUCHAR)Hash);\n                status = STATUS_SUCCESS;\n            }\n            else\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n            }\n\n            if (ReturnLength)\n                *ReturnLength = PH_HASH_SHA1_LENGTH;\n        }\n        break;\n    case Sha256HashAlgorithm:\n        {\n            if (HashLength >= PH_HASH_SHA256_LENGTH)\n            {\n                sha256_finish((sha256_context*)Context->Context, (PUCHAR)Hash);\n                status = STATUS_SUCCESS;\n            }\n            else\n            {\n                status = STATUS_BUFFER_TOO_SMALL;\n            }\n\n            if (ReturnLength)\n            {\n                *ReturnLength = PH_HASH_SHA256_LENGTH;\n            }\n        }\n        break;\n    default:\n        {\n            if (ReturnLength)\n            {\n                *ReturnLength = 0;\n            }\n\n            status = STATUS_INVALID_PARAMETER;\n        }\n        break;\n    }\n\n    return status;\n}\n\n/**\n * Parses one part of a command line string. Quotation marks and backslashes are handled\n * appropriately.\n *\n * \\param CommandLine The entire command line string.\n * \\param Index The starting index of the command line part to be parsed. There should be no leading\n * whitespace at this index. The index is updated to point to the end of the command line part.\n */\nPPH_STRING PhParseCommandLinePart(\n    _In_ PCPH_STRINGREF CommandLine,\n    _Inout_ PULONG_PTR Index\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    SIZE_T length;\n    SIZE_T i;\n\n    ULONG numberOfBackslashes;\n    BOOLEAN inQuote;\n    BOOLEAN endOfValue;\n\n    length = CommandLine->Length / sizeof(WCHAR);\n    i = *Index;\n\n    // This function follows the rules used by CommandLineToArgvW:\n    //\n    // * 2n backslashes and a quotation mark produces n backslashes and a quotation mark\n    //   (non-literal).\n    // * 2n + 1 backslashes and a quotation mark produces n and a quotation mark (literal).\n    // * n backslashes and no quotation mark produces n backslashes.\n\n    PhInitializeStringBuilder(&stringBuilder, 0x80);\n    numberOfBackslashes = 0;\n    inQuote = FALSE;\n    endOfValue = FALSE;\n\n    for (; i < length; i++)\n    {\n        switch (CommandLine->Buffer[i])\n        {\n        case L'\\\\':\n            numberOfBackslashes++;\n            break;\n        case L'\\\"':\n            if (numberOfBackslashes != 0)\n            {\n                if (numberOfBackslashes & 1)\n                {\n                    numberOfBackslashes /= 2;\n\n                    if (numberOfBackslashes != 0)\n                    {\n                        PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, numberOfBackslashes);\n                        numberOfBackslashes = 0;\n                    }\n\n                    PhAppendCharStringBuilder(&stringBuilder, L'\\\"');\n\n                    break;\n                }\n                else\n                {\n                    numberOfBackslashes /= 2;\n                    PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, numberOfBackslashes);\n                    numberOfBackslashes = 0;\n                }\n            }\n\n            if (!inQuote)\n                inQuote = TRUE;\n            else\n                inQuote = FALSE;\n\n            break;\n        default:\n            if (numberOfBackslashes != 0)\n            {\n                PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, numberOfBackslashes);\n                numberOfBackslashes = 0;\n            }\n\n            if (CommandLine->Buffer[i] == L' ' && !inQuote)\n            {\n                endOfValue = TRUE;\n            }\n            else\n            {\n                PhAppendCharStringBuilder(&stringBuilder, CommandLine->Buffer[i]);\n            }\n\n            break;\n        }\n\n        if (endOfValue)\n            break;\n    }\n\n    *Index = i;\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n/**\n * Parses a command line string.\n *\n * \\param CommandLine The command line string.\n * \\param Options An array of supported command line options.\n * \\param NumberOfOptions The number of elements in \\a Options.\n * \\param Flags A combination of flags.\n * \\li \\c PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS Unknown command line options are ignored instead of\n * failing the function.\n * \\li \\c PH_COMMAND_LINE_IGNORE_FIRST_PART The first part of the command line string is ignored.\n * This is used when the first part of the string contains the executable file name.\n * \\param Callback A callback function to execute for each command line option found.\n * \\param Context A user-defined value to pass to \\a Callback.\n */\nBOOLEAN PhParseCommandLine(\n    _In_ PCPH_STRINGREF CommandLine,\n    _In_opt_ PCPH_COMMAND_LINE_OPTION Options,\n    _In_ ULONG NumberOfOptions,\n    _In_ ULONG Flags,\n    _In_ PPH_COMMAND_LINE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    SIZE_T i;\n    SIZE_T j;\n    SIZE_T length;\n    BOOLEAN cont = TRUE;\n    BOOLEAN wasFirst = TRUE;\n\n    PH_STRINGREF optionName;\n    PCPH_COMMAND_LINE_OPTION option = NULL;\n    PPH_STRING optionValue;\n\n    if (CommandLine->Length == 0)\n        return TRUE;\n\n    i = 0;\n    length = CommandLine->Length / sizeof(WCHAR);\n\n    while (TRUE)\n    {\n        // Skip spaces.\n        while (i < length && CommandLine->Buffer[i] == L' ')\n            i++;\n\n        if (i >= length)\n            break;\n\n        if (option &&\n            (option->Type == MandatoryArgumentType ||\n            (option->Type == OptionalArgumentType && CommandLine->Buffer[i] != L'-')))\n        {\n            // Read the value and execute the callback function.\n\n            optionValue = PhParseCommandLinePart(CommandLine, &i);\n            cont = Callback(option, optionValue, Context);\n            PhDereferenceObject(optionValue);\n\n            if (!cont)\n                break;\n\n            option = NULL;\n        }\n        else if (CommandLine->Buffer[i] == L'-')\n        {\n            ULONG_PTR originalIndex;\n            SIZE_T optionNameLength;\n\n            // Read the option (only alphanumeric characters allowed).\n\n            // Skip the dash.\n            i++;\n\n            originalIndex = i;\n\n            for (; i < length; i++)\n            {\n                if (!iswalnum(CommandLine->Buffer[i]) && CommandLine->Buffer[i] != L'-')\n                    break;\n            }\n\n            optionNameLength = i - originalIndex;\n\n            optionName.Buffer = &CommandLine->Buffer[originalIndex];\n            optionName.Length = optionNameLength * sizeof(WCHAR);\n\n            // Take care of any pending optional argument.\n\n            if (option && option->Type == OptionalArgumentType)\n            {\n                cont = Callback(option, NULL, Context);\n\n                if (!cont)\n                    break;\n\n                option = NULL;\n            }\n\n            // Find the option descriptor.\n\n            option = NULL;\n\n            for (j = 0; j < NumberOfOptions; j++)\n            {\n                if (PhEqualStringRef2(&optionName, Options[j].Name, FALSE))\n                {\n                    option = &Options[j];\n                    break;\n                }\n            }\n\n            if (!option && !(Flags & PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS))\n                return FALSE;\n\n            if (option && option->Type == NoArgumentType)\n            {\n                cont = Callback(option, NULL, Context);\n\n                if (!cont)\n                    break;\n\n                option = NULL;\n            }\n\n            wasFirst = FALSE;\n        }\n        else\n        {\n            PPH_STRING value;\n\n            value = PhParseCommandLinePart(CommandLine, &i);\n\n            if ((Flags & PH_COMMAND_LINE_IGNORE_FIRST_PART) && wasFirst)\n            {\n                PhDereferenceObject(value);\n                value = NULL;\n            }\n\n            if (value)\n            {\n                cont = Callback(NULL, value, Context);\n                PhDereferenceObject(value);\n\n                if (!cont)\n                    break;\n            }\n\n            wasFirst = FALSE;\n        }\n    }\n\n    if (cont && option && option->Type == OptionalArgumentType)\n        Callback(option, NULL, Context);\n\n    return TRUE;\n}\n\n/**\n * Escapes a string for use in a command line.\n *\n * \\param String The string to escape.\n * \\return The escaped string.\n * \\remarks Only the double quotation mark is escaped.\n */\nPPH_STRING PhEscapeCommandLinePart(\n    _In_ PCPH_STRINGREF String\n    )\n{\n    static CONST PH_STRINGREF backslashAndQuote = PH_STRINGREF_INIT(L\"\\\\\\\"\");\n    PH_STRING_BUILDER stringBuilder;\n    ULONG numberOfBackslashes;\n    SIZE_T length;\n    ULONG i;\n\n    length = String->Length / sizeof(WCHAR);\n    PhInitializeStringBuilder(&stringBuilder, String->Length / sizeof(WCHAR) * 3);\n    numberOfBackslashes = 0;\n\n    // Simply replacing \" with \\\" won't work here. See PhParseCommandLinePart for the quoting rules.\n\n    for (i = 0; i < length; i++)\n    {\n        switch (String->Buffer[i])\n        {\n        case L'\\\\':\n            numberOfBackslashes++;\n            break;\n        case L'\\\"':\n            if (numberOfBackslashes != 0)\n            {\n                PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, UInt32x32To64(numberOfBackslashes, 2));\n                numberOfBackslashes = 0;\n            }\n\n            PhAppendStringBuilder(&stringBuilder, &backslashAndQuote);\n\n            break;\n        default:\n            if (numberOfBackslashes != 0)\n            {\n                PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, numberOfBackslashes);\n                numberOfBackslashes = 0;\n            }\n\n            PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);\n\n            break;\n        }\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n/**\n * Parses a command line string. If the string does not contain quotation marks around the file name\n * part, the function determines the file name to use.\n *\n * \\param CommandLine The command line string.\n * \\param FileName A variable which receives the part of \\a CommandLine that contains the file name.\n * \\param Arguments A variable which receives the part of \\a CommandLine that contains the arguments.\n * \\param FullFileName A variable which receives the full path and file name. This may be NULL if\n * the file was not found.\n */\nBOOLEAN PhParseCommandLineFuzzy(\n    _In_ PCPH_STRINGREF CommandLine,\n    _Out_ PPH_STRINGREF FileName,\n    _Out_ PPH_STRINGREF Arguments,\n    _Out_opt_ PPH_STRING *FullFileName\n    )\n{\n    static CONST PH_STRINGREF whitespace = PH_STRINGREF_INIT(L\" \\t\");\n    PH_STRINGREF commandLine;\n    PH_STRINGREF temp;\n    PH_STRINGREF currentPart;\n    PH_STRINGREF remainingPart;\n    PPH_STRING filePath;\n\n    commandLine = *CommandLine;\n    PhTrimStringRef(&commandLine, &whitespace, 0);\n\n    if (commandLine.Length == 0)\n    {\n        PhInitializeEmptyStringRef(FileName);\n        PhInitializeEmptyStringRef(Arguments);\n\n        if (FullFileName)\n            *FullFileName = NULL;\n\n        return FALSE;\n    }\n\n    if (*commandLine.Buffer == L'\"')\n    {\n        PH_STRINGREF arguments;\n\n        PhSkipStringRef(&commandLine, sizeof(WCHAR));\n\n        // Find the matching quote character and we have our file name.\n\n        if (!PhSplitStringRefAtChar(&commandLine, L'\"', &commandLine, &arguments))\n        {\n            PhSkipStringRef(&commandLine, -(LONG_PTR)sizeof(WCHAR)); // Unskip the initial quote character\n            *FileName = commandLine;\n            PhInitializeEmptyStringRef(Arguments);\n\n            if (FullFileName)\n                *FullFileName = NULL;\n\n            return FALSE;\n        }\n\n        PhTrimStringRef(&arguments, &whitespace, PH_TRIM_START_ONLY);\n        *FileName = commandLine;\n        *Arguments = arguments;\n\n        if (FullFileName)\n        {\n            PPH_STRING tempCommandLine;\n\n            tempCommandLine = PhCreateString2(&commandLine);\n\n            if (filePath = PhSearchFilePath(tempCommandLine->Buffer, L\".exe\"))\n            {\n                *FullFileName = filePath;\n            }\n            else\n            {\n                *FullFileName = NULL;\n            }\n\n            PhDereferenceObject(tempCommandLine);\n        }\n\n        return TRUE;\n    }\n\n    // Try to find an existing executable file, starting with the first part of the command line and\n    // successively restoring the rest of the command line.\n    // For example, in \"C:\\Program Files\\Internet   Explorer\\iexplore\", we try to match:\n    // * \"C:\\Program\"\n    // * \"C:\\Program Files\\Internet\"\n    // * \"C:\\Program Files\\Internet \"\n    // * \"C:\\Program Files\\Internet  \"\n    // * \"C:\\Program Files\\Internet   Explorer\\iexplore\"\n    //\n    // Note that we do not trim whitespace in each part because filenames can contain trailing\n    // whitespace before the extension (e.g. \"Internet  .exe\").\n\n    temp.Buffer = PhAllocate(commandLine.Length + sizeof(UNICODE_NULL));\n    memcpy(temp.Buffer, commandLine.Buffer, commandLine.Length);\n    temp.Buffer[commandLine.Length / sizeof(WCHAR)] = UNICODE_NULL;\n    temp.Length = commandLine.Length;\n    remainingPart = temp;\n\n    while (remainingPart.Length != 0)\n    {\n        WCHAR originalChar = UNICODE_NULL;\n        BOOLEAN found;\n\n        found = PhSplitStringRefAtChar(&remainingPart, L' ', &currentPart, &remainingPart);\n\n        if (found)\n        {\n            originalChar = *(remainingPart.Buffer - 1);\n            *(remainingPart.Buffer - 1) = UNICODE_NULL;\n        }\n\n        filePath = PhSearchFilePath(temp.Buffer, L\".exe\");\n\n        if (found)\n        {\n            *(remainingPart.Buffer - 1) = originalChar;\n        }\n\n        if (filePath)\n        {\n            FileName->Buffer = commandLine.Buffer;\n            FileName->Length = (SIZE_T)PTR_SUB_OFFSET(currentPart.Buffer, temp.Buffer) + currentPart.Length;\n\n            if (Arguments)\n            {\n                PhTrimStringRef(&remainingPart, &whitespace, PH_TRIM_START_ONLY);\n\n                if (remainingPart.Length)\n                {\n                    Arguments->Buffer = PTR_ADD_OFFSET(commandLine.Buffer, PTR_SUB_OFFSET(remainingPart.Buffer, temp.Buffer));\n                    Arguments->Length = commandLine.Length - (SIZE_T)PTR_SUB_OFFSET(remainingPart.Buffer, temp.Buffer);\n                }\n                else\n                {\n                    PhInitializeEmptyStringRef(Arguments);\n                }\n            }\n\n            if (FullFileName)\n                *FullFileName = filePath;\n            else\n                PhDereferenceObject(filePath);\n\n            PhFree(temp.Buffer);\n\n            return TRUE;\n        }\n    }\n\n    PhFree(temp.Buffer);\n\n    *FileName = *CommandLine;\n    PhInitializeEmptyStringRef(Arguments);\n\n    if (FullFileName)\n        *FullFileName = NULL;\n\n    return FALSE;\n}\n\n/**\n * Parses a Unicode command line string and returns an array of pointers to the command line arguments, along with a count of such arguments.\n *\n * \\param CommandLine Pointer to a null-terminated Unicode string that contains the full command line. If this parameter is an empty string the function returns the path to the current executable file.\n * \\param NumberOfArguments The number of array elements returned, similar to argc.\n * \\return A pointer to an array of LPWSTR values, similar to argv. If the function fails, the return value is NULL.\n */\n_Success_(return != NULL)\nPWSTR* PhCommandLineToArgv(\n    _In_ PCWSTR CommandLine,\n    _Out_ PLONG NumberOfArguments\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&CommandLineToArgvW) CommandLineToArgvW_I = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"shell32.dll\"))\n        {\n            CommandLineToArgvW_I = PhGetDllBaseProcedureAddress(baseAddress, \"CommandLineToArgvW\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!CommandLineToArgvW_I)\n        return NULL;\n\n    return CommandLineToArgvW_I(CommandLine, NumberOfArguments);\n}\n\n/**\n * Converts a command line string to a list of strings.\n *\n * \\param CommandLine The command line string.\n * \\return A pointer to a list containing the command line arguments.\n */\nPPH_LIST PhCommandLineToList(\n    _In_ PCWSTR CommandLine\n    )\n{\n    PPH_LIST commandLineList = NULL;\n    LONG commandLineCount;\n    PWSTR* commandLineArray;\n\n    if (commandLineArray = PhCommandLineToArgv(CommandLine, &commandLineCount))\n    {\n        commandLineList = PhCreateList(commandLineCount);\n\n        for (LONG i = 0; i < commandLineCount; i++)\n            PhAddItemList(commandLineList, PhCreateString(commandLineArray[i]));\n\n        LocalFree(commandLineArray);\n    }\n\n    return commandLineList;\n}\n\n/**\n * Quotes spaces in a command line string.\n *\n * \\param CommandLine The command line string.\n * \\return A pointer to a string containing the quoted command line.\n */\nPPH_STRING PhCommandLineQuoteSpaces(\n    _In_ PCPH_STRINGREF CommandLine\n    )\n{\n    static CONST PH_STRINGREF separator = PH_STRINGREF_INIT(L\"\\\"\");\n    static CONST PH_STRINGREF space = PH_STRINGREF_INIT(L\" \");\n    PH_STRINGREF commandLineFileName;\n    PH_STRINGREF commandLineArguments;\n    PPH_STRING fileNameEscaped;\n    PPH_STRING argumentsEscaped;\n\n    if (!PhParseCommandLineFuzzy(CommandLine, &commandLineFileName, &commandLineArguments, NULL))\n        return NULL;\n\n    fileNameEscaped = PhConcatStringRef3(&separator, &commandLineFileName, &separator);\n\n    if (commandLineArguments.Length)\n    {\n        argumentsEscaped = PhConcatStringRef3(&separator, &commandLineArguments, &separator);\n        PhMoveReference(&argumentsEscaped, PhConcatStringRef3(&fileNameEscaped->sr, &space, &argumentsEscaped->sr));\n        PhMoveReference(&fileNameEscaped, PhConcatStringRef3(&separator, &argumentsEscaped->sr, &separator));\n    }\n\n    return fileNameEscaped;\n}\n\n/**\n * Searches for a file in the system path.\n *\n * \\param FileName The name of the file to search for.\n * \\param Extension An optional extension to append to the file name.\n * \\return A pointer to a string containing the full path to the file, or NULL if not found.\n */\nPPH_STRING PhSearchFilePath(\n    _In_ PCWSTR FileName,\n    _In_opt_ PCWSTR Extension\n    )\n{\n    PPH_STRING fullPath;\n    ULONG bufferSize;\n    ULONG returnLength;\n    FILE_BASIC_INFORMATION basicInfo;\n\n    bufferSize = MAX_PATH;\n    fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR));\n\n    returnLength = SearchPath(\n        NULL,\n        FileName,\n        Extension,\n        (ULONG)fullPath->Length / sizeof(WCHAR),\n        fullPath->Buffer,\n        NULL\n        );\n\n    if (returnLength == 0 && returnLength <= bufferSize)\n        goto CleanupExit;\n\n    if (returnLength > bufferSize)\n    {\n        bufferSize = returnLength;\n        PhDereferenceObject(fullPath);\n        fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR));\n\n        returnLength = SearchPath(\n            NULL,\n            FileName,\n            Extension,\n            (ULONG)fullPath->Length / sizeof(WCHAR),\n            fullPath->Buffer,\n            NULL\n            );\n    }\n\n    if (returnLength == 0 && returnLength <= bufferSize)\n        goto CleanupExit;\n\n    PhTrimToNullTerminatorString(fullPath);\n\n    // Make sure this is not a directory.\n\n    if (!NT_SUCCESS(PhQueryAttributesFileWin32(fullPath->Buffer, &basicInfo)))\n        goto CleanupExit;\n\n    if (FlagOn(basicInfo.FileAttributes, FILE_ATTRIBUTE_DIRECTORY))\n        goto CleanupExit;\n\n    return fullPath;\n\nCleanupExit:\n    PhDereferenceObject(fullPath);\n    return NULL;\n}\n\n//PPH_STRING PhCreateCacheFile(\n//    _In_ PPH_STRING FileName\n//    )\n//{\n//    PPH_STRING tempFileName;\n//    PPH_STRING cachefileName;\n//\n//    if (tempFileName = PhGetTemporaryDirectoryRandomAlphaFileName())\n//    {\n//        cachefileName = PhConcatStringRef3(\n//            &tempFileName->sr,\n//            &PhNtPathSeparatorString,\n//            &FileName->sr\n//            );\n//\n//        if (NT_SUCCESS(PhCreateDirectoryFullPathWin32(&cachefileName->sr)))\n//        {\n//            PhDereferenceObject(tempFileName);\n//            return cachefileName;\n//        }\n//\n//        PhDereferenceObject(cachefileName);\n//        PhDereferenceObject(tempFileName);\n//    }\n//\n//    return NULL;\n//}\n\n/**\n * Creates a cache file.\n *\n * \\param PortableDirectory TRUE to use the application directory, FALSE to use the roaming app data directory.\n * \\param FileName The name of the file.\n * \\param NativeFileName TRUE to return a native path, FALSE for a Win32 path.\n * \\return A pointer to a string containing the full path to the cache file.\n */\nPPH_STRING PhCreateCacheFile(\n    _In_ BOOLEAN PortableDirectory,\n    _In_ PPH_STRING FileName,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    static CONST PH_STRINGREF settingsDirectory = PH_STRINGREF_INIT(L\"cache\");\n    PPH_STRING cacheDirectory;\n    PPH_STRING cacheFilePath;\n    PH_STRINGREF randomAlphaStringRef;\n    WCHAR randomAlphaString[32] = L\"\";\n\n    if (PortableDirectory)\n        cacheDirectory = PhGetApplicationDirectoryFileName(&settingsDirectory, TRUE);\n    else\n        cacheDirectory = PhGetRoamingAppDataDirectory(&settingsDirectory, TRUE);\n\n    if (PhIsNullOrEmptyString(cacheDirectory))\n        return NULL;\n\n    PhGenerateRandomAlphaString(randomAlphaString, RTL_NUMBER_OF(randomAlphaString));\n    randomAlphaStringRef.Buffer = randomAlphaString;\n    randomAlphaStringRef.Length = sizeof(randomAlphaString) - sizeof(UNICODE_NULL);\n\n    cacheFilePath = PhConcatStringRef3(\n        &cacheDirectory->sr,\n        &PhNtPathSeparatorString,\n        &randomAlphaStringRef\n        );\n\n    PhMoveReference(&cacheFilePath, PhConcatStringRef3(\n        &cacheFilePath->sr,\n        &PhNtPathSeparatorString,\n        &FileName->sr\n        ));\n\n    if (!NT_SUCCESS(PhCreateDirectoryFullPath(&cacheFilePath->sr)))\n    {\n        PhDereferenceObject(cacheFilePath);\n        PhDereferenceObject(cacheDirectory);\n        return NULL;\n    }\n\n    if (NativeFileName)\n    {\n        PPH_STRING cacheFileName;\n\n        if (cacheFileName = PhDosPathNameToNtPathName(&cacheFilePath->sr))\n        {\n            PhMoveReference(&cacheFilePath, cacheFileName);\n        }\n    }\n    else\n    {\n        PPH_STRING cacheFileName;\n\n        if (cacheFileName = PhResolveDevicePrefix(&cacheFilePath->sr))\n        {\n            PhMoveReference(&cacheFilePath, cacheFileName);\n        }\n    }\n\n    PhDereferenceObject(cacheDirectory);\n\n    return cacheFilePath;\n}\n\n//VOID PhDeleteCacheFile(\n//    _In_ PPH_STRING FileName\n//    )\n//{\n//    PPH_STRING cacheDirectory;\n//\n//    if (PhDoesFileExistWin32(PhGetString(FileName)))\n//    {\n//        PhDeleteFileWin32(PhGetString(FileName));\n//    }\n//\n//    if (cacheDirectory = PhGetBaseDirectory(FileName))\n//    {\n//        PhDeleteDirectoryWin32(&cacheDirectory->sr);\n//        PhDereferenceObject(cacheDirectory);\n//    }\n//}\n\n/**\n * Deletes a cache file and its containing directory.\n *\n * \\param FileName The name of the file.\n * \\param NativeFileName TRUE if the file name is a native path, FALSE otherwise.\n */\nVOID PhDeleteCacheFile(\n    _In_ PPH_STRING FileName,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    if (NativeFileName)\n    {\n        if (PhDoesFileExist(&FileName->sr))\n        {\n            PhDeleteDirectoryFullPath(&FileName->sr);\n        }\n    }\n    else\n    {\n        PPH_STRING cacheDirectory;\n        PPH_STRING cacheFullFilePath;\n        ULONG indexOfFileName = ULONG_MAX;\n\n        if (PhDoesFileExistWin32(PhGetString(FileName)))\n        {\n            PhDeleteFileWin32(PhGetString(FileName));\n        }\n\n        if (NT_SUCCESS(PhGetFullPath(PhGetString(FileName), &cacheFullFilePath, &indexOfFileName)))\n        {\n            if (indexOfFileName != ULONG_MAX && (cacheDirectory = PhSubstring(cacheFullFilePath, 0, indexOfFileName)))\n            {\n                PhDeleteDirectoryWin32(&cacheDirectory->sr);\n\n                PhDereferenceObject(cacheDirectory);\n            }\n\n            PhDereferenceObject(cacheFullFilePath);\n        }\n    }\n}\n\n/**\n * Clears the cache directory.\n *\n * \\param PortableDirectory TRUE if the application is in portable mode, FALSE otherwise.\n */\nVOID PhClearCacheDirectory(\n    _In_ BOOLEAN PortableDirectory\n    )\n{\n    static CONST PH_STRINGREF settingsDirectory = PH_STRINGREF_INIT(L\"cache\");\n    PPH_STRING cacheDirectory;\n\n    if (PortableDirectory)\n        cacheDirectory = PhGetApplicationDirectoryFileName(&settingsDirectory, TRUE);\n    else\n        cacheDirectory = PhGetRoamingAppDataDirectory(&settingsDirectory, TRUE);\n\n    if (cacheDirectory)\n    {\n        PhDeleteDirectory(&cacheDirectory->sr);\n\n        PhDereferenceObject(cacheDirectory);\n    }\n}\n\n/**\n * Retrieves a handle to the private namespace for System Informer.\n *\n * \\return A handle to the private namespace.\n */\nHANDLE PhGetNamespaceHandle(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static HANDLE directoryHandle = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        UCHAR securityDescriptorBuffer[SECURITY_DESCRIPTOR_MIN_LENGTH + 0x70];\n        PSID administratorsSid = PhSeAdministratorsSid();\n        UNICODE_STRING objectName;\n        OBJECT_ATTRIBUTES objectAttributes;\n        PSECURITY_DESCRIPTOR securityDescriptor;\n        ULONG sdAllocationLength;\n        PACL dacl;\n\n        // Create the default namespace DACL.\n\n        sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH +\n            (ULONG)sizeof(ACL) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            PhLengthSid(&PhSeLocalSid) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            PhLengthSid(administratorsSid) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            PhLengthSid(&PhSeInteractiveSid);\n\n        securityDescriptor = (PSECURITY_DESCRIPTOR)securityDescriptorBuffer;\n        dacl = PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH);\n\n        PhCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n        PhCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION);\n        PhAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, &PhSeLocalSid);\n        PhAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, administratorsSid);\n        PhAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT, &PhSeInteractiveSid);\n        PhSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE);\n\n        RtlInitUnicodeString(&objectName, L\"\\\\BaseNamedObjects\\\\SystemInformer\");\n        InitializeObjectAttributes(\n            &objectAttributes,\n            &objectName,\n            OBJ_OPENIF | (WindowsVersion < WINDOWS_10 ? 0 : OBJ_DONT_REPARSE),\n            NULL,\n            securityDescriptor\n            );\n\n        NtCreateDirectoryObject(&directoryHandle, MAXIMUM_ALLOWED, &objectAttributes);\n\n        assert(RtlValidSecurityDescriptor(securityDescriptor));\n        assert(sdAllocationLength < sizeof(securityDescriptorBuffer));\n        assert(RtlLengthSecurityDescriptor(securityDescriptor) < sizeof(securityDescriptorBuffer));\n        PhEndInitOnce(&initOnce);\n    }\n\n    return directoryHandle;\n}\n\n/**\n * Retrieves the hung window represented by a ghost window.\n * If the specified window is not a ghost window, the function returns NULL.\n *\n * \\param WindowHandle The handle to the ghost window.\n * \\return The handle to the original hung window if successful, otherwise NULL.\n */\nHWND PhHungWindowFromGhostWindow(\n    _In_ HWND WindowHandle\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    // This is an undocumented function exported by user32.dll that\n    // retrieves the hung window represented by a ghost window. (wj32)\n    static HWND (WINAPI *HungWindowFromGhostWindow_I)(\n        _In_ HWND GhostWindowHandle\n        );\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        HungWindowFromGhostWindow_I = PhGetDllProcedureAddressZ(L\"user32.dll\", \"HungWindowFromGhostWindow\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!HungWindowFromGhostWindow_I)\n        return NULL;\n\n    // The call will return NULL if the window wasn't actually a ghost window. (wj32)\n    return HungWindowFromGhostWindow_I(WindowHandle);\n}\n\n/**\n * Reads all data from a file into a buffer.\n *\n * \\param FileHandle A handle to the file.\n * \\param Buffer Receives a pointer to the buffer containing the file data.\n * \\param BufferLength Receives the length of the buffer.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetFileData(\n    _In_ HANDLE FileHandle,\n    _Out_ PVOID* Buffer,\n    _Out_ PULONG BufferLength\n    )\n{\n    NTSTATUS status;\n    PSTR data = NULL;\n    ULONG allocatedLength;\n    ULONG dataLength;\n    ULONG returnLength;\n    IO_STATUS_BLOCK isb;\n    BYTE buffer[PAGE_SIZE * 2];\n\n    allocatedLength = sizeof(buffer);\n    data = PhAllocate(allocatedLength);\n    dataLength = 0;\n\n    while (NT_SUCCESS(status = NtReadFile(\n        FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        buffer,\n        sizeof(buffer),\n        NULL,\n        NULL\n        )))\n    {\n        returnLength = (ULONG)isb.Information;\n\n        if (returnLength == 0)\n            break;\n\n        if (allocatedLength < dataLength + returnLength)\n        {\n            allocatedLength *= 2;\n            data = PhReAllocate(data, allocatedLength);\n        }\n\n        memcpy(data + dataLength, buffer, returnLength);\n\n        dataLength += returnLength;\n    }\n\n    if (status == STATUS_END_OF_FILE)\n    {\n        status = STATUS_SUCCESS;\n    }\n\n    if (status == STATUS_PIPE_BROKEN)\n    {\n        status = STATUS_SUCCESS;\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(data);\n\n        *Buffer = NULL;\n        *BufferLength = 0;\n\n        return status;\n    }\n\n    if (allocatedLength < dataLength + sizeof(ANSI_NULL))\n    {\n        allocatedLength++;\n        data = PhReAllocate(data, allocatedLength);\n    }\n\n    data[dataLength] = ANSI_NULL;\n\n    *Buffer = data;\n    *BufferLength = dataLength;\n\n    return status;\n}\n\n/**\n * Reads all text from a file.\n *\n * \\param String Receives a pointer to the string containing the file text.\n * \\param FileHandle A handle to the file.\n * \\param Unicode TRUE to return a Unicode string, FALSE to return an ANSI string.\n * \\return Successful or errant status.\n */\nNTSTATUS PhGetFileText(\n    _Out_ PVOID* String,\n    _In_ HANDLE FileHandle,\n    _In_ BOOLEAN Unicode\n    )\n{\n    NTSTATUS status;\n    ULONG dataLength;\n    PSTR data;\n\n    status = PhGetFileData(\n        FileHandle,\n        &data,\n        &dataLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (dataLength)\n        {\n            if (Unicode)\n                *String = PhConvertUtf8ToUtf16Ex(data, dataLength);\n            else\n                *String = PhCreateBytesEx(data, dataLength);\n        }\n        else\n        {\n            *String = PhReferenceEmptyString();\n        }\n\n        PhFree(data);\n    }\n\n    return status;\n}\n\n/**\n * Reads all text from a file.\n *\n * \\param String Receives a pointer to the string containing the file text.\n * \\param FileName The name of the file.\n * \\param Unicode TRUE to return a Unicode string, FALSE to return an ANSI string.\n * \\return Successful or errant status.\n */\nNTSTATUS PhFileReadAllText(\n    _Out_ PVOID* String,\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN Unicode\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n\n    status = PhCreateFile(\n        &fileHandle,\n        FileName,\n        FILE_GENERIC_READ,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetFileText(\n            String,\n            fileHandle,\n            Unicode\n            );\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\n/**\n * Reads all text from a file.\n *\n * \\param String Receives a pointer to the string containing the file text.\n * \\param FileName The Win32 name of the file.\n * \\param Unicode TRUE to return a Unicode string, FALSE to return an ANSI string.\n * \\return Successful or errant status.\n */\nNTSTATUS PhFileReadAllTextWin32(\n    _Out_ PVOID* String,\n    _In_ PCWSTR FileName,\n    _In_ BOOLEAN Unicode\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n\n    status = PhCreateFileWin32(\n        &fileHandle,\n        FileName,\n        FILE_GENERIC_READ,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhGetFileText(\n            String,\n            fileHandle,\n            Unicode\n            );\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\n/**\n * Writes text to a file.\n *\n * \\param FileName The name of the file.\n * \\param String The text to write.\n * \\return Successful or errant status.\n */\nNTSTATUS PhFileWriteAllText(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ PCPH_STRINGREF String\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n\n    status = PhCreateFile(\n        &fileHandle,\n        FileName,\n        FILE_GENERIC_WRITE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_WRITE,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhWriteFile(\n            fileHandle,\n            String->Buffer,\n            (ULONG)String->Length,\n            NULL,\n            NULL\n            );\n\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\n/**\n * Retrieves a class object from a DLL.\n *\n * \\param DllBase The base address of the DLL.\n * \\param Rclsid The class identifier.\n * \\param Riid The interface identifier.\n * \\param Ppv Receives the interface pointer.\n * \\return Successful or errant status.\n */\nHRESULT PhGetClassObjectDllBase(\n    _In_ PVOID DllBase,\n    _In_ REFCLSID Rclsid,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Ppv\n    )\n{\n    HRESULT (WINAPI* DllGetClassObject_I)(_In_ REFCLSID rclsid, _In_ REFIID riid, _COM_Outptr_ PVOID* ppv);\n    HRESULT status;\n    IClassFactory* classFactory;\n\n    if (!(DllGetClassObject_I = PhGetDllBaseProcedureAddress(DllBase, \"DllGetClassObject\", 0)))\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    status = DllGetClassObject_I(\n        Rclsid,\n        &IID_IClassFactory,\n        &classFactory\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IClassFactory_CreateInstance(\n            classFactory,\n            NULL,\n            Riid,\n            Ppv\n            );\n        IClassFactory_Release(classFactory);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Provides a pointer to an interface on a class object associated with a specified CLSID.\n * Most class objects implement the IClassFactory interface. You would then call CreateInstance to\n * create an uninitialized object. It is not always necessary to go through this process however.\n *\n * \\param DllName The file containing the object to initialize.\n * \\param Rclsid A pointer to the class identifier of the object to be created.\n * \\param Riid Reference to the identifier of the interface to communicate with the class object.\n * \\a Typically this value is IID_IClassFactory, although other values such as IID_IClassFactory2 which supports a form of licensing are allowed.\n * \\param Ppv The address of pointer variable that contains the requested interface.\n * \\return Successful or errant status.\n */\nHRESULT PhGetClassObject(\n    _In_ PCWSTR DllName,\n    _In_ REFCLSID Rclsid,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Ppv\n    )\n{\n#if defined(PH_BUILD_MSIX)\n    HRESULT status;\n    IClassFactory* classFactory;\n\n    status = CoGetClassObject(\n        Rclsid,\n        CLSCTX_INPROC_SERVER,\n        NULL,\n        &IID_IClassFactory,\n        &classFactory\n        );\n\n    if (HR_SUCCESS(status))\n    {\n        status = IClassFactory_CreateInstance(\n            classFactory,\n            NULL,\n            Riid,\n            Ppv\n            );\n        IClassFactory_Release(classFactory);\n    }\n\n    return status;\n#else\n    PVOID baseAddress;\n    PH_STRINGREF baseDllName;\n\n    PhInitializeStringRefLongHint(&baseDllName, DllName);\n\n    if (!(baseAddress = PhGetLoaderEntryDllBase(NULL, &baseDllName)))\n    {\n        if (!(baseAddress = PhLoadLibrary(DllName)))\n            return HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);\n    }\n\n    return PhGetClassObjectDllBase(baseAddress, Rclsid, Riid, Ppv);\n#endif\n}\n\n/**\n * Retrieves an activation factory from a DLL.\n *\n * \\param DllBase The base address of the DLL.\n * \\param RuntimeClass The runtime class name.\n * \\param Riid The interface identifier.\n * \\param Ppv Receives the interface pointer.\n * \\return Successful or errant status.\n */\nHRESULT PhGetActivationFactoryDllBase(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR RuntimeClass,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Ppv\n    )\n{\n    HRESULT (WINAPI* DllGetActivationFactory_I)(_In_ HSTRING RuntimeClassId, _Out_ PVOID* ActivationFactory);\n    HRESULT status;\n    HSTRING_REFERENCE string;\n    IActivationFactory* activationFactory;\n\n    if (FAILED(status = PhCreateWindowsRuntimeStringReference(RuntimeClass, &string)))\n        return status;\n\n    if (!(DllGetActivationFactory_I = PhGetDllBaseProcedureAddress(DllBase, \"DllGetActivationFactory\", 0)))\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    status = DllGetActivationFactory_I(\n        HSTRING_FROM_STRING(string),\n        &activationFactory\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IActivationFactory_QueryInterface(\n            activationFactory,\n            Riid,\n            Ppv\n            );\n        IActivationFactory_Release(activationFactory);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Activates the specified Windows Runtime class.\n *\n * \\param DllName The file containing the object to initialize.\n * \\param RuntimeClass The class identifier string that is associated with the activatable runtime class.\n * \\param Riid The reference ID of the interface.\n * \\param Ppv The activation factory.\n * \\return Successful or errant status.\n */\nHRESULT PhGetActivationFactory(\n    _In_ PCWSTR DllName,\n    _In_ PCWSTR RuntimeClass,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Ppv\n    )\n{\n#if defined(PH_BUILD_MSIX)\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&WindowsCreateStringReference) WindowsCreateStringReference_I = NULL;\n    static typeof(&RoGetActivationFactory) RoGetActivationFactory_I = NULL;\n    HRESULT status;\n    HSTRING runtimeClassStringHandle = NULL;\n    HSTRING_HEADER runtimeClassStringHeader;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"combase.dll\"))\n        {\n            WindowsCreateStringReference_I = PhGetDllBaseProcedureAddress(baseAddress, \"WindowsCreateStringReference\", 0);\n            RoGetActivationFactory_I = PhGetDllBaseProcedureAddress(baseAddress, \"RoGetActivationFactory\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!(WindowsCreateStringReference_I && RoGetActivationFactory_I))\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    status = WindowsCreateStringReference_I(\n        RuntimeClass,\n        (UINT32)PhCountStringZ(RuntimeClass),\n        &runtimeClassStringHeader,\n        &runtimeClassStringHandle\n        );\n\n    if (HR_SUCCESS(status))\n    {\n        status = RoGetActivationFactory_I(\n            runtimeClassStringHandle,\n            Riid,\n            Ppv\n            );\n    }\n\n    return status;\n#else\n    PVOID baseAddress;\n    PH_STRINGREF baseDllName;\n\n    PhInitializeStringRefLongHint(&baseDllName, DllName);\n\n    if (!(baseAddress = PhGetLoaderEntryDllBase(NULL, &baseDllName)))\n    {\n        if (!(baseAddress = PhLoadLibrary(DllName)))\n            return HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);\n    }\n\n    return PhGetActivationFactoryDllBase(baseAddress, RuntimeClass, Riid, Ppv);\n#endif\n}\n\n/**\n * Activates an instance of a Windows Runtime class from a specified DLL base address.\n *\n * This function attempts to create and return an instance of a Windows Runtime class (specified by\n * the class name) from a loaded DLL image. It uses the DllGetActivationFactory export if available\n * to obtain the activation factory, then calls IActivationFactory::ActivateInstance to create the\n * object and query the requested interface.\n *\n * \\param DllBase The base address of the loaded DLL containing the Windows Runtime class.\n * \\param RuntimeClass The name of the runtime class to activate (e.g., L\"Windows.Storage.StorageFile\").\n * \\param Riid The interface identifier (IID) of the interface to retrieve from the created instance.\n * \\param Ppv A pointer that receives the interface pointer requested in Riid.\n * \\return Returns an HRESULT indicating success or failure.\n *\n * \\remarks\n *      - This function is typically used for COM/WinRT activation scenarios where the class is not\n *        registered globally but is available in a specific DLL.\n *      - The function first creates an HSTRING reference for the class name, then calls the\n *        DllGetActivationFactory export to obtain an activation factory. It then calls\n *        IActivationFactory::ActivateInstance to create the object and queries the requested\n *        interface.\n *      - The caller must ensure that the DLL is loaded and that the class is available.\n *      - On success, the caller is responsible for releasing the returned interface pointer.\n */\nHRESULT PhActivateInstanceDllBase(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR RuntimeClass,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Ppv\n    )\n{\n    HRESULT (WINAPI* DllGetActivationFactory_I)(_In_ HSTRING RuntimeClassId, _Out_ PVOID * ActivationFactory);\n    HRESULT status;\n    HSTRING_REFERENCE string;\n    IActivationFactory* activationFactory;\n    IInspectable* inspectableObject;\n\n    if (FAILED(status = PhCreateWindowsRuntimeStringReference(RuntimeClass, &string)))\n        return status;\n\n    if (!(DllGetActivationFactory_I = PhGetDllBaseProcedureAddress(DllBase, \"DllGetActivationFactory\", 0)))\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    status = DllGetActivationFactory_I(\n        HSTRING_FROM_STRING(string),\n        &activationFactory\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = IActivationFactory_ActivateInstance(\n            activationFactory,\n            &inspectableObject\n            );\n\n        if (SUCCEEDED(status))\n        {\n            status = IInspectable_QueryInterface(\n                inspectableObject,\n                Riid,\n                Ppv\n                );\n\n            IInspectable_Release(inspectableObject);\n        }\n\n        IActivationFactory_Release(activationFactory);\n    }\n\n    return status;\n}\n\n/**\n * \\brief Activates the specified Windows Runtime class.\n *\n * \\param DllName The file containing the object to initialize.\n * \\param RuntimeClass The class identifier string that is associated with the activatable runtime class.\n * \\param Riid The reference ID of the interface.\n * \\param Ppv A pointer to the activated instance of the runtime class.\n * \\return Successful or errant status.\n */\nHRESULT PhActivateInstance(\n    _In_ PCWSTR DllName,\n    _In_ PCWSTR RuntimeClass,\n    _In_ REFIID Riid,\n    _Out_ PVOID* Ppv\n    )\n{\n#if defined(PH_BUILD_MSIX)\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&WindowsCreateStringReference) WindowsCreateStringReference_I = NULL;\n    static typeof(&RoActivateInstance) RoActivateInstance_I = NULL;\n    HRESULT status;\n    HSTRING runtimeClassStringHandle = NULL;\n    HSTRING_HEADER runtimeClassStringHeader;\n    IInspectable* inspectableObject;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"combase.dll\"))\n        {\n            WindowsCreateStringReference_I = PhGetDllBaseProcedureAddress(baseAddress, \"WindowsCreateStringReference\", 0);\n            RoActivateInstance_I = PhGetDllBaseProcedureAddress(baseAddress, \"RoActivateInstance\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!(WindowsCreateStringReference_I && RoActivateInstance_I))\n        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);\n\n    status = WindowsCreateStringReference_I(\n        RuntimeClass,\n        (UINT32)PhCountStringZ(RuntimeClass),\n        &runtimeClassStringHeader,\n        &runtimeClassStringHandle\n        );\n\n    if (HR_SUCCESS(status))\n    {\n        status = RoActivateInstance_I(\n            runtimeClassStringHandle,\n            &inspectableObject\n            );\n\n        if (HR_SUCCESS(status))\n        {\n            status = IInspectable_QueryInterface(\n                inspectableObject,\n                Riid,\n                Ppv\n                );\n            IInspectable_Release(inspectableObject);\n        }\n    }\n\n    return status;\n#else\n    PVOID baseAddress;\n    PH_STRINGREF baseDllName;\n\n    PhInitializeStringRefLongHint(&baseDllName, DllName);\n\n    if (!(baseAddress = PhGetLoaderEntryDllBase(NULL, &baseDllName)))\n    {\n        if (!(baseAddress = PhLoadLibrary(DllName)))\n            return HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);\n    }\n\n    return PhActivateInstanceDllBase(baseAddress, RuntimeClass, Riid, Ppv);\n#endif\n}\n\n#if defined(PH_NATIVE_RING_BUFFER)\n// This function creates a ring buffer by allocating a pagefile-backed section\n// and mapping two views of that section next to each other. This way if the\n// last record in the buffer wraps it can still be accessed in a linear fashion\n// using its base VA. (Win10 RS5 and above only) (dmex)\n// Based on Win32 version: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc2#examples\n/**\n * Creates a ring buffer.\n *\n * \\param BufferSize The size of the buffer.\n * \\param RingBuffer Receives a pointer to the ring buffer.\n * \\param SecondaryView Receives a pointer to the secondary view of the buffer.\n * \\return Successful or errant status.\n */\nNTSTATUS PhCreateRingBuffer(\n    _In_ SIZE_T BufferSize,\n    _Out_ PVOID* RingBuffer,\n    _Out_ PVOID* SecondaryView\n    )\n{\n    NTSTATUS status;\n    SIZE_T regionSize;\n    LARGE_INTEGER sectionSize;\n    HANDLE sectionHandle = NULL;\n    PVOID placeholder1 = NULL;\n    PVOID placeholder2 = NULL;\n    PVOID sectionView1 = NULL;\n    PVOID sectionView2 = NULL;\n\n    if ((BufferSize % PhSystemBasicInformation.AllocationGranularity) != 0)\n        return STATUS_UNSUCCESSFUL;\n\n    //\n    // Reserve a placeholder region where the buffer will be mapped.\n    //\n\n    regionSize = 2 * BufferSize;\n    status = NtAllocateVirtualMemoryEx(\n        NtCurrentProcess(),\n        &placeholder1,\n        &regionSize,\n        MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,\n        PAGE_NOACCESS,\n        NULL,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    //\n    // Split the placeholder region into two regions of equal size.\n    //\n\n    regionSize = BufferSize;\n    status = NtFreeVirtualMemory(\n        NtCurrentProcess(),\n        &placeholder1,\n        &regionSize,\n        MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    placeholder2 = PTR_ADD_OFFSET(placeholder1, BufferSize);\n\n    //\n    // Create a pagefile-backed section for the buffer.\n    //\n\n    sectionSize.QuadPart = BufferSize;\n    status = NtCreateSectionEx(\n        &sectionHandle,\n        SECTION_ALL_ACCESS,\n        NULL,\n        &sectionSize,\n        PAGE_READWRITE,\n        SEC_COMMIT,\n        NULL,\n        NULL,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    //\n    // Map the section into the first placeholder region.\n    //\n\n    regionSize = BufferSize;\n    sectionView1 = placeholder1;\n    status = NtMapViewOfSectionEx(\n        sectionHandle,\n        NtCurrentProcess(),\n        &sectionView1,\n        0,\n        &regionSize,\n        MEM_REPLACE_PLACEHOLDER,\n        PAGE_READWRITE,\n        NULL,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    //\n    // Ownership transferred, don't free this now.\n    //\n\n    placeholder1 = NULL;\n\n    //\n    // Map the section into the second placeholder region.\n    //\n\n    regionSize = BufferSize;\n    sectionView2 = placeholder2;\n    status = NtMapViewOfSectionEx(\n        sectionHandle,\n        NtCurrentProcess(),\n        &sectionView2,\n        0,\n        &regionSize,\n        MEM_REPLACE_PLACEHOLDER,\n        PAGE_READWRITE,\n        NULL,\n        0\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    //\n    // Success, return both mapped views to the caller.\n    //\n\n    *RingBuffer = sectionView1;\n    *SecondaryView = sectionView2;\n\n#ifdef DEBUG\n    // assert the buffer wraps properly.\n    ((PCHAR)sectionView1)[0] = 'a';\n    assert(((PCHAR)sectionView1)[BufferSize] == 'a');\n#endif\n\n    placeholder2 = NULL;\n    sectionView1 = NULL;\n    sectionView2 = NULL;\n\nCleanupExit:\n    if (sectionHandle)\n    {\n        NtClose(sectionHandle);\n    }\n\n    if (placeholder1)\n    {\n        regionSize = 0;\n        NtFreeVirtualMemory(NtCurrentProcess(), placeholder1, &regionSize, MEM_RELEASE);\n    }\n\n    if (placeholder2)\n    {\n        regionSize = 0;\n        NtFreeVirtualMemory(NtCurrentProcess(), placeholder2, &regionSize, MEM_RELEASE);\n    }\n\n    if (sectionView1)\n        PhUnmapViewOfSection(NtCurrentProcess(), sectionView1);\n    if (sectionView2)\n        PhUnmapViewOfSection(NtCurrentProcess(), sectionView2);\n\n    return status;\n}\n#endif\n\n/**\n * Suspends the current thread for a specified interval.\n *\n * This function delays execution for the given interval, optionally allowing the wait to be alertable.\n * On Windows 11 and later, it uses RtlDelayExecution if available; otherwise, it falls back to NtDelayExecution.\n *\n * \\param Alertable If TRUE, the wait is alertable and can be interrupted by an APC; otherwise, the wait is not alertable.\n * \\param DelayInterval A pointer to a LARGE_INTEGER that specifies the interval to wait, in 100-nanosecond units. A negative value indicates relative time.\n * \\return An NTSTATUS code indicating success or failure of the delay operation.\n * \\note\n * RtlDelayExecution is preferred on Windows 11 and later because it provides additional logic and optimizations\n * over NtDelayExecution and ensures more efficient and robust thread suspension on modern Windows versions plus\n * future compatibility with OS-level enhancements\n *\n * RtlDelayExecution:\n * - Wraps NtDelayExecution/ZwDelayExecution and adds additional logic before and after the system call.\n * - Spin-Wait Optimization: If the delay interval is zero (i.e., a \"yield\" or very short sleep), and certain internal\n * configuration variables are set, it may perform a short spin-wait (using _mm_pause()) before calling the system call.\n * This is to avoid excessive context switches and improve performance for very short waits.\n * - Performance Counter Tracking: Uses RtlQueryPerformanceCounter to track the time since the last sleep and adjust spin-waiting accordingly.\n * - TEB State Tracking: Updates fields in the thread environment block (TEB), such as SpinCallCount and LastSleepCounter, to manage spin-wait heuristics.\n * - Adaptive Backoff: The amount of spin-waiting can increase if the thread is calling delay execution in rapid succession, up to a configured maximum.\n * - Resets Spin Count on Real Wait: if the delay was not interrupted (STATUS_ALERTED), resets the spin count.\n */\nNTSTATUS PhDelayExecutionEx(\n    _In_ BOOLEAN Alertable,\n    _In_ PLARGE_INTEGER DelayInterval\n    )\n{\n    if (WindowsVersion >= WINDOWS_11 && RtlDelayExecution_Import())\n    {\n        return RtlDelayExecution_Import()(Alertable, DelayInterval);\n    }\n\n    return NtDelayExecution(Alertable, DelayInterval);\n}\n\n/**\n * Suspends the current thread for a specified number of milliseconds.\n *\n * This function delays execution for the specified number of milliseconds. If the value is INFINITE,\n * the thread is suspended indefinitely. Otherwise, the delay is converted to a negative relative interval\n * in 100-nanosecond units and passed to PhDelayExecutionEx.\n *\n * \\note\n * On Windows 11 and later, PhDelayExecutionEx uses RtlDelayExecution, which provides improved behavior\n * for short waits and better compatibility with future Windows updates.\n * \\param Milliseconds The number of milliseconds to delay. Use INFINITE to wait indefinitely.\n * \\return An NTSTATUS code indicating success or failure of the delay operation.\n */\nNTSTATUS PhDelayExecution(\n    _In_ ULONG Milliseconds\n    )\n{\n    if (Milliseconds == INFINITE)\n    {\n        LARGE_INTEGER interval;\n\n        interval.QuadPart = LLONG_MIN;\n\n        return PhDelayExecutionEx(FALSE, &interval);\n    }\n    else\n    {\n        LARGE_INTEGER interval;\n\n        interval.QuadPart = -(LONGLONG)UInt32x32To64(Milliseconds, PH_TIMEOUT_MS);\n\n        return PhDelayExecutionEx(FALSE, &interval);\n    }\n}\n\n/**\n * Computes a case-insensitive hash value for a Unicode string using a specified hash factor.\n *\n * This function is used for hashing API Set names in the Windows API Set schema resolution logic.\n * It iterates over each character in the string, normalizes uppercase ASCII letters to lowercase,\n * and accumulates the hash using the provided hash factor.\n *\n * \\param String A pointer to a PH_STRINGREF structure representing the Unicode string to hash.\n * \\param HashFactor The multiplier used in the hash calculation (typically provided by the schema).\n * \\return The computed hash value as an unsigned long.\n */\nFORCEINLINE\nULONG PhApiSetHashString(\n    _In_ PCPH_STRINGREF String,\n    _In_ ULONG HashFactor\n    )\n{\n    ULONG hash = 0;\n\n    for (ULONG i = 0; i < String->Length / sizeof(WCHAR); i++)\n    {\n        hash = hash * HashFactor + ((USHORT)(String->Buffer[i] - L'A') <= L'Z' - L'A' ? String->Buffer[i] + L'a' - L'A' : String->Buffer[i]);\n    }\n\n    return hash;\n}\n\n/**\n * Resolves an API Set name to a host DLL name.\n *\n * \\param[in] Schema The API Set definition, such as PEB->ApiSetMap.\n * \\param[in] ApiSetName The name of the API Set, with or without a .dll extension.\n * \\param[in] ParentName An optional name of the parent (importing) module.\n * \\param[out] HostBinary The resolved name of the DLL.\n * \\return Successful or errant status.\n */\nNTSTATUS PhApiSetResolveToHost(\n    _In_ PAPI_SET_NAMESPACE Schema,\n    _In_ PCPH_STRINGREF ApiSetName,\n    _In_opt_ PCPH_STRINGREF ParentName,\n    _Out_ PPH_STRINGREF HostBinary\n    )\n{\n    PH_STRINGREF parentNameFilePart;\n\n    if (ApiSetName->Length >= 4 * sizeof(WCHAR))\n    {\n        // Extract and downcase the first 4 characters\n        ULONGLONG apisetNameBufferPrefix = ((PULONGLONG)ApiSetName->Buffer)[0] & 0xFFFFFFDFFFDFFFDF;\n\n        // Verify the API Set prefixes\n        if (apisetNameBufferPrefix != 0x2D004900500041ULL && // L\"api-\"\n            apisetNameBufferPrefix != 0x2D005400580045ULL) // L\"ext-\"\n            return STATUS_INVALID_PARAMETER;\n    }\n    else\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    if (ParentName)\n    {\n        // If given a path, we are only interested in the file component\n        if (!PhGetBasePath(ParentName, NULL, &parentNameFilePart))\n        {\n            parentNameFilePart.Buffer = ParentName->Buffer;\n            parentNameFilePart.Length = ParentName->Length;\n        }\n    }\n\n    switch (Schema->Version)\n    {\n    case API_SET_SCHEMA_VERSION_V6:\n        {\n            PAPI_SET_NAMESPACE_ENTRY namespaceEntries = PTR_ADD_OFFSET(Schema, Schema->EntryOffset);\n            PAPI_SET_NAMESPACE_ENTRY namespaceEntry;\n            PAPI_SET_HASH_ENTRY hashEntries = PTR_ADD_OFFSET(Schema, Schema->HashOffset);\n            PAPI_SET_HASH_ENTRY hashEntry;\n            PAPI_SET_VALUE_ENTRY valueEntry;\n            PH_STRINGREF apisetNamespacePart;\n            PH_STRINGREF apisetNameHashedPart;\n            ULONG_PTR hyphenIndex;\n            ULONG hash;\n            LONG minIndex;\n            LONG maxIndex;\n            LONG midIndex;\n            LONG comparison;\n\n            if (!Schema->Count)\n                return STATUS_NOT_FOUND;\n\n            if (Schema->Count > MAXINT32)\n                return STATUS_INTEGER_OVERFLOW;\n\n            // The hash covers the length up to but not including the last hyphen\n            hyphenIndex = PhFindLastCharInStringRef(ApiSetName, L'-', FALSE);\n\n            // There must be a hyphen if it passed the prefix check\n            assert(hyphenIndex != SIZE_MAX);\n\n            apisetNameHashedPart.Buffer = ApiSetName->Buffer;\n            apisetNameHashedPart.Length = hyphenIndex * sizeof(WCHAR);\n            hash = PhApiSetHashString(&apisetNameHashedPart, Schema->HashFactor);\n\n            minIndex = 0;\n            maxIndex = Schema->Count - 1;\n\n            // Perform a binary search for the API Set name hash\n            do\n            {\n                midIndex = (maxIndex + minIndex) / 2;\n                hashEntry = &hashEntries[midIndex];\n\n                if (hash < hashEntry->Hash)\n                    maxIndex = midIndex - 1;\n                else if (hash > hashEntry->Hash)\n                    minIndex = midIndex + 1;\n                else\n                {\n                    namespaceEntry = &namespaceEntries[hashEntry->Index];\n\n                    // Verify the API Set name matches, in addition to its hash\n                    apisetNamespacePart.Buffer = PTR_ADD_OFFSET(Schema, namespaceEntry->NameOffset);\n                    apisetNamespacePart.Length = namespaceEntry->HashedLength;\n\n                    comparison = PhCompareStringRef(\n                        &apisetNameHashedPart,\n                        &apisetNamespacePart,\n                        TRUE\n                        );\n\n                    //comparison = RtlCompareUnicodeStrings(\n                    //    apiSetNameHashedPart.Buffer,\n                    //    apiSetNameHashedPart.Length / sizeof(WCHAR),\n                    //    PTR_ADD_OFFSET(Schema, namespaceEntry->NameOffset),\n                    //    namespaceEntry->HashedLength / sizeof(WCHAR),\n                    //    TRUE\n                    //    );\n\n                    if (comparison < 0)\n                        maxIndex = midIndex - 1;\n                    else if (comparison > 0)\n                        minIndex = midIndex + 1;\n                    else\n                        break;\n                }\n\n                if (minIndex > maxIndex)\n                    return STATUS_NOT_FOUND;\n\n            } while (TRUE);\n\n            valueEntry = PTR_ADD_OFFSET(Schema, namespaceEntry->ValueOffset);\n\n            // Try module-specific search\n            if (ParentName && namespaceEntry->ValueCount > 1)\n            {\n                if (namespaceEntry->ValueCount > MAXINT32)\n                    return STATUS_INTEGER_OVERFLOW;\n\n                minIndex = 0;\n                maxIndex = namespaceEntry->ValueCount - 1;\n\n                // Perform binary search for the parent name\n                do\n                {\n                    midIndex = (maxIndex + minIndex) / 2;\n\n                    apisetNamespacePart.Buffer = PTR_ADD_OFFSET(Schema, valueEntry[midIndex].NameOffset);\n                    apisetNamespacePart.Length = valueEntry[midIndex].NameLength;\n\n                    comparison = PhCompareStringRef(\n                        &parentNameFilePart,\n                        &apisetNamespacePart,\n                        TRUE\n                        );\n\n                    //comparison = RtlCompareUnicodeStrings(\n                    //    parentNameFilePart.Buffer,\n                    //    parentNameFilePart.Length / sizeof(WCHAR),\n                    //    PTR_ADD_OFFSET(Schema, valueEntry[midIndex].NameOffset),\n                    //    valueEntry[midIndex].NameLength / sizeof(WCHAR),\n                    //    TRUE\n                    //    );\n\n                    if (comparison < 0)\n                        maxIndex = midIndex - 1;\n                    else if (comparison > 0)\n                        minIndex = midIndex + 1;\n                    else\n                    {\n                        if (!valueEntry[midIndex].ValueLength)\n                            return STATUS_APISET_NOT_HOSTED;\n\n                        // Return the parent-specific result\n                        HostBinary->Buffer = PTR_ADD_OFFSET(Schema, valueEntry[midIndex].ValueOffset);\n                        HostBinary->Length = valueEntry[midIndex].ValueLength;\n                        return STATUS_SUCCESS;\n                    }\n\n                    // No match; fall back to the default value\n                    if (minIndex > maxIndex)\n                        break;\n\n                } while (TRUE);\n            }\n\n            // Use the default value\n            if (namespaceEntry->ValueCount)\n            {\n                if (!valueEntry[0].ValueLength)\n                    return STATUS_APISET_NOT_HOSTED;\n\n                HostBinary->Buffer = PTR_ADD_OFFSET(Schema, valueEntry[0].ValueOffset);\n                HostBinary->Length = valueEntry[0].ValueLength;\n                return STATUS_SUCCESS;\n            }\n\n            return STATUS_NOT_FOUND;\n        }\n        break;\n    case API_SET_SCHEMA_VERSION_V4:\n        {\n            PAPI_SET_NAMESPACE_ARRAY_V4 schema = (PAPI_SET_NAMESPACE_ARRAY_V4)Schema;\n            PAPI_SET_VALUE_ARRAY_V4 valueArray;\n            PH_STRINGREF apisetNamespacePart;\n            PH_STRINGREF apisetNameShort;\n            LONG comparison;\n            LONG minIndex;\n            LONG maxIndex;\n            LONG midIndex;\n\n            if (!schema->Count)\n                return STATUS_NOT_FOUND;\n\n            if (schema->Count > MAXINT32)\n                return STATUS_INTEGER_OVERFLOW;\n\n            // Should be covered by the prefix check\n            assert(ApiSetName->Length >= 4 * sizeof(WCHAR));\n\n            // Skip the \"api-\" and \"ext-\" prefixes\n            apisetNameShort.Buffer = ApiSetName->Buffer + 4;\n            apisetNameShort.Length = ApiSetName->Length - 4 * sizeof(WCHAR);\n\n            // Ignore file extension (when present)\n            if (apisetNameShort.Length >= 4 * sizeof(WCHAR) &&\n                apisetNameShort.Buffer[apisetNameShort.Length / sizeof(WCHAR) - 4] == L'.')\n                apisetNameShort.Length -= 4 * sizeof(WCHAR);\n\n            minIndex = 0;\n            maxIndex = schema->Count - 1;\n\n            // Perform a binary search for the API Set name\n            do\n            {\n                midIndex = (maxIndex + minIndex) / 2;\n\n                apisetNamespacePart.Buffer = PTR_ADD_OFFSET(schema, schema->Array[midIndex].NameOffset);\n                apisetNamespacePart.Length = schema->Array[midIndex].NameLength;\n\n                comparison = PhCompareStringRef(\n                    &apisetNameShort,\n                    &apisetNamespacePart,\n                    TRUE\n                    );\n\n                //comparison = RtlCompareUnicodeStrings(\n                //    apisetNameShort.Buffer,\n                //    apisetNameShort.Length / sizeof(WCHAR),\n                //    PTR_ADD_OFFSET(schema, schema->Array[midIndex].NameOffset),\n                //    schema->Array[midIndex].NameLength / sizeof(WCHAR),\n                //    TRUE\n                //    );\n\n                if (comparison < 0)\n                    maxIndex = midIndex - 1;\n                else if (comparison > 0)\n                    minIndex = midIndex + 1;\n                else\n                    break;\n\n                if (minIndex > maxIndex)\n                    return STATUS_NOT_FOUND;\n\n            } while (TRUE);\n\n            valueArray = PTR_ADD_OFFSET(schema, schema->Array[midIndex].DataOffset);\n\n            // Try module-specific search\n            if (ParentName && valueArray->Count > 1)\n            {\n                if (valueArray->Count > MAXINT32)\n                    return STATUS_INTEGER_OVERFLOW;\n\n                minIndex = 0;\n                maxIndex = valueArray->Count - 1;\n\n                // Perform binary search for the parent name\n                do\n                {\n                    midIndex = (maxIndex + minIndex) / 2;\n\n                    apisetNamespacePart.Buffer = PTR_ADD_OFFSET(schema, valueArray->Array[midIndex].NameOffset);\n                    apisetNamespacePart.Length = valueArray->Array[midIndex].NameLength;\n\n                    comparison = PhCompareStringRef(\n                        &parentNameFilePart,\n                        &apisetNamespacePart,\n                        TRUE\n                        );\n\n                    //comparison = RtlCompareUnicodeStrings(\n                    //    parentNameFilePart.Buffer,\n                    //    parentNameFilePart.Length / sizeof(WCHAR),\n                    //    PTR_ADD_OFFSET(schema, valueArray->Array[midIndex].NameOffset),\n                    //    valueArray->Array[midIndex].NameLength / sizeof(WCHAR),\n                    //    TRUE\n                    //    );\n\n                    if (comparison < 0)\n                        maxIndex = midIndex - 1;\n                    else if (comparison > 0)\n                        minIndex = midIndex + 1;\n                    else\n                    {\n                        if (!valueArray->Array[midIndex].ValueLength)\n                            return STATUS_APISET_NOT_HOSTED;\n\n                        // Return the parent-specific result\n                        HostBinary->Buffer = PTR_ADD_OFFSET(schema, valueArray->Array[midIndex].ValueOffset);\n                        HostBinary->Length = valueArray->Array[midIndex].ValueLength;\n                        return STATUS_SUCCESS;\n                    }\n\n                    // No match; fall back to the default value\n                    if (minIndex > maxIndex)\n                        break;\n\n                } while (TRUE);\n            }\n\n            // Use the default value\n            if (valueArray->Count)\n            {\n                if (!valueArray->Array[0].ValueLength)\n                    return STATUS_APISET_NOT_HOSTED;\n\n                HostBinary->Buffer = PTR_ADD_OFFSET(schema, valueArray->Array[0].ValueOffset);\n                HostBinary->Length = valueArray->Array[0].ValueLength;\n                return STATUS_SUCCESS;\n            }\n\n            return STATUS_NOT_FOUND;\n        }\n        break;\n    case API_SET_SCHEMA_VERSION_V2:\n        {\n            PAPI_SET_NAMESPACE_ARRAY_V2 schema = (PAPI_SET_NAMESPACE_ARRAY_V2)Schema;\n            PAPI_SET_VALUE_ARRAY_V2 valueArray;\n            PH_STRINGREF apisetNamespacePart;\n            PH_STRINGREF apiSetNameShort;\n            LONG comparison;\n            LONG minIndex;\n            LONG maxIndex;\n            LONG midIndex;\n\n            if (!schema->Count)\n                return STATUS_NOT_FOUND;\n\n            if (schema->Count > MAXINT32)\n                return STATUS_INTEGER_OVERFLOW;\n\n            // Should be covered by the prefix check\n            assert(ApiSetName->Length >= 4 * sizeof(WCHAR));\n\n            // Skip the \"api-\" and \"ext-\" prefixes\n            apiSetNameShort.Buffer = ApiSetName->Buffer + 4;\n            apiSetNameShort.Length = ApiSetName->Length - 4 * sizeof(WCHAR);\n\n            // Ignore file extension (when present)\n            if (apiSetNameShort.Length >= 4 * sizeof(WCHAR) &&\n                apiSetNameShort.Buffer[apiSetNameShort.Length / sizeof(WCHAR) - 4] == L'.')\n                apiSetNameShort.Length -= 4 * sizeof(WCHAR);\n\n            minIndex = 0;\n            maxIndex = schema->Count - 1;\n\n            // Perform a binary search for the API Set name\n            do\n            {\n                midIndex = (maxIndex + minIndex) / 2;\n\n                apisetNamespacePart.Buffer = PTR_ADD_OFFSET(schema, schema->Array[midIndex].NameOffset);\n                apisetNamespacePart.Length = schema->Array[midIndex].NameLength;\n\n                comparison = PhCompareStringRef(\n                    &apiSetNameShort,\n                    &apisetNamespacePart,\n                    TRUE\n                    );\n\n                //comparison = RtlCompareUnicodeStrings(\n                //    apiSetNameShort.Buffer,\n                //    apiSetNameShort.Length / sizeof(WCHAR),\n                //    PTR_ADD_OFFSET(schema, schema->Array[midIndex].NameOffset),\n                //    schema->Array[midIndex].NameLength / sizeof(WCHAR),\n                //    TRUE\n                //    );\n\n                if (comparison < 0)\n                    maxIndex = midIndex - 1;\n                else if (comparison > 0)\n                    minIndex = midIndex + 1;\n                else\n                    break;\n\n                if (minIndex > maxIndex)\n                    return STATUS_NOT_FOUND;\n\n            } while (TRUE);\n\n            valueArray = PTR_ADD_OFFSET(schema, schema->Array[midIndex].DataOffset);\n\n            // Try module-specific search\n            if (ParentName && valueArray->Count > 1)\n            {\n                if (valueArray->Count > MAXINT32)\n                    return STATUS_INTEGER_OVERFLOW;\n\n                minIndex = 0;\n                maxIndex = valueArray->Count - 1;\n\n                // Perform binary search for the parent name\n                do\n                {\n                    midIndex = (maxIndex + minIndex) / 2;\n\n                    apisetNamespacePart.Buffer = PTR_ADD_OFFSET(schema, valueArray->Array[midIndex].NameOffset);\n                    apisetNamespacePart.Length = valueArray->Array[midIndex].NameLength;\n\n                    comparison = PhCompareStringRef(\n                        &apiSetNameShort,\n                        &apisetNamespacePart,\n                        TRUE\n                        );\n\n                    //comparison = RtlCompareUnicodeStrings(\n                    //    parentNameFilePart.Buffer,\n                    //    parentNameFilePart.Length / sizeof(WCHAR),\n                    //    PTR_ADD_OFFSET(schema, valueArray->Array[midIndex].NameOffset),\n                    //    valueArray->Array[midIndex].NameLength / sizeof(WCHAR),\n                    //    TRUE\n                    //    );\n\n                    if (comparison < 0)\n                        maxIndex = midIndex - 1;\n                    else if (comparison > 0)\n                        minIndex = midIndex + 1;\n                    else\n                    {\n                        if (!valueArray->Array[midIndex].ValueLength)\n                            return STATUS_APISET_NOT_HOSTED;\n\n                        // Return the parent-specific result\n                        HostBinary->Buffer = PTR_ADD_OFFSET(schema, valueArray->Array[midIndex].ValueOffset);\n                        HostBinary->Length = valueArray->Array[midIndex].ValueLength;\n                        return STATUS_SUCCESS;\n                    }\n\n                    // No match; fall back to the default value\n                    if (minIndex > maxIndex)\n                        break;\n\n                } while (TRUE);\n            }\n\n            // Use the default value\n            if (valueArray->Count)\n            {\n                if (!valueArray->Array[0].ValueLength)\n                    return STATUS_APISET_NOT_HOSTED;\n\n                HostBinary->Buffer = PTR_ADD_OFFSET(schema, valueArray->Array[0].ValueOffset);\n                HostBinary->Length = valueArray->Array[0].ValueLength;\n                return STATUS_SUCCESS;\n            }\n\n            return STATUS_NOT_FOUND;\n        }\n        break;\n    }\n\n    return STATUS_UNKNOWN_REVISION;\n}\n\n/**\n * Creates a process as the interactive user using the Windows Desktop Controller (WDC) API.\n *\n * This function attempts to launch a process in the context of the currently active interactive user session.\n * It uses the undocumented WdcRunTaskAsInteractiveUser function from wdc.dll, if available, to perform the operation.\n *\n * \\param CommandLine The command line to execute. This should include the full path to the executable and any arguments.\n * \\param CurrentDirectory The working directory for the new process. May be NULL to use the default.\n * \\return HRESULT Returns S_OK on success, or an error HRESULT code on failure.\n * \\remarks This function is only available on Windows 10 and later, and requires wdc.dll to be present.\n */\nHRESULT PhCreateProcessAsInteractiveUser(\n    _In_ PCWSTR CommandLine,\n    _In_ PCWSTR CurrentDirectory\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static HRESULT (WINAPI* WdcRunTaskAsInteractiveUser_I)(\n        _In_ PCWSTR CommandLine,\n        _In_ PCWSTR CurrentDirectory,\n        _In_opt_ ULONG Flags\n        ) = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"wdc.dll\"))\n        {\n            WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(baseAddress, \"WdcRunTaskAsInteractiveUser\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (WdcRunTaskAsInteractiveUser_I)\n    {\n        return WdcRunTaskAsInteractiveUser_I(CommandLine, CurrentDirectory, 0);\n    }\n\n    return E_NOTIMPL;\n}\n\n/**\n * Clones a process by creating a new process object that is a copy of the specified process.\n *\n * This function opens the source process with PROCESS_CREATE_PROCESS access and uses NtCreateProcessEx\n * to create a new process that inherits from the specified process. The new process is created in a suspended state\n * and inherits handles and address space from the parent process.\n *\n * \\param[out] ProcessHandle A pointer that receives a handle to the newly created (cloned) process.\n * \\param[in] ProcessId The process ID (handle) of the process to clone.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhCreateProcessClone(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    HANDLE processHandle;\n    HANDLE cloneProcessHandle;\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    status = PhOpenProcess(\n        &processHandle,\n        PROCESS_CREATE_PROCESS,\n        ProcessId\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        NULL,\n        0,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateProcessEx(\n        &cloneProcessHandle,\n        PROCESS_ALL_ACCESS,\n        &objectAttributes,\n        processHandle,\n        PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT | PROCESS_CREATE_FLAGS_INHERIT_HANDLES | PROCESS_CREATE_FLAGS_CREATE_SUSPENDED,\n        NULL,\n        NULL,\n        NULL,\n        0\n        );\n\n    NtClose(processHandle);\n\n    if (NT_SUCCESS(status))\n    {\n        *ProcessHandle = cloneProcessHandle;\n    }\n\n    return status;\n}\n\n/**\n * Creates a reflection (clone) of a process using RtlCreateProcessReflection.\n *\n * \\param ReflectionInformation Pointer to a PROCESS_REFLECTION_INFORMATION structure that receives information about the reflected process.\n * \\param ProcessHandle Handle to the process to reflect.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks On success, the caller is responsible for releasing handles in the returned structure using PhFreeProcessReflection().\n */\nNTSTATUS PhCreateProcessReflection(\n    _Out_ PPROCESS_REFLECTION_INFORMATION ReflectionInformation,\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status;\n    PROCESS_REFLECTION_INFORMATION reflectionInfo = { 0 };\n\n    status = RtlCreateProcessReflection(\n        ProcessHandle,\n        RTL_PROCESS_REFLECTION_FLAGS_INHERIT_HANDLES,\n        NULL,\n        NULL,\n        NULL,\n        &reflectionInfo\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *ReflectionInformation = reflectionInfo;\n    }\n\n    return status;\n}\n\n/**\n * Frees resources associated with a process reflection created by PhCreateProcessReflection.\n *\n * \\param ReflectionInformation Pointer to a PROCESS_REFLECTION_INFORMATION structure previously initialized by PhCreateProcessReflection.\n * \\remarks This function closes the thread and process handles and terminates the reflected process.\n */\nVOID PhFreeProcessReflection(\n    _In_ PPROCESS_REFLECTION_INFORMATION ReflectionInformation\n    )\n{\n    if (ReflectionInformation->ReflectionThreadHandle)\n    {\n        NtClose(ReflectionInformation->ReflectionThreadHandle);\n    }\n\n    if (ReflectionInformation->ReflectionProcessHandle)\n    {\n        NtTerminateProcess(ReflectionInformation->ReflectionProcessHandle, STATUS_SUCCESS);\n        NtClose(ReflectionInformation->ReflectionProcessHandle);\n    }\n}\n\n/**\n * Captures a snapshot of a process using the Process Snapshotting API.\n *\n * \\param SnapshotHandle Receives a handle to the process snapshot.\n * \\param ProcessHandle Handle to the process to snapshot.\n * \\return NTSTATUS code indicating success or failure.\n * \\remarks The caller must release the snapshot using PhFreeProcessSnapshot().\n */\nNTSTATUS PhCreateProcessSnapshot(\n    _Out_ PHANDLE SnapshotHandle,\n    _In_ HANDLE ProcessHandle\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    HANDLE snapshotHandle = NULL;\n\n    if (!PssNtCaptureSnapshot_Import())\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    status = PssNtCaptureSnapshot_Import()(\n        &snapshotHandle,\n        ProcessHandle,\n        PSS_CAPTURE_VA_CLONE | PSS_CAPTURE_HANDLES | PSS_CAPTURE_HANDLE_NAME_INFORMATION |\n        PSS_CAPTURE_HANDLE_BASIC_INFORMATION | PSS_CAPTURE_HANDLE_TYPE_SPECIFIC_INFORMATION |\n        PSS_CAPTURE_HANDLE_TRACE | PSS_CAPTURE_THREADS | PSS_CAPTURE_THREAD_CONTEXT |\n        PSS_CAPTURE_THREAD_CONTEXT_EXTENDED | PSS_CAPTURE_VA_SPACE | PSS_CAPTURE_VA_SPACE_SECTION_INFORMATION |\n        PSS_CREATE_BREAKAWAY | PSS_CREATE_BREAKAWAY_OPTIONAL | PSS_CREATE_USE_VM_ALLOCATIONS,\n        CONTEXT_ALL // WOW64_CONTEXT_ALL?\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *SnapshotHandle = snapshotHandle;\n    }\n\n    return status;\n}\n\n/**\n * Frees a process snapshot and associated resources.\n *\n * \\param SnapshotHandle Handle to the process snapshot.\n * \\param ProcessHandle Handle to the original process.\n */\nVOID PhFreeProcessSnapshot(\n    _In_ HANDLE SnapshotHandle,\n    _In_ HANDLE ProcessHandle\n    )\n{\n    if (PssNtQuerySnapshot_Import())\n    {\n        PSS_VA_CLONE_INFORMATION processInfo = { 0 };\n        PSS_HANDLE_TRACE_INFORMATION handleInfo = { 0 };\n\n        if (NT_SUCCESS(PssNtQuerySnapshot_Import()(\n            SnapshotHandle,\n            PSSNT_QUERY_VA_CLONE_INFORMATION,\n            &processInfo,\n            sizeof(PSS_VA_CLONE_INFORMATION)\n            )))\n        {\n            if (processInfo.VaCloneHandle)\n            {\n                NtClose(processInfo.VaCloneHandle);\n            }\n        }\n\n        if (NT_SUCCESS(PssNtQuerySnapshot_Import()(\n            SnapshotHandle,\n            PSSNT_QUERY_HANDLE_TRACE_INFORMATION,\n            &handleInfo,\n            sizeof(PSS_HANDLE_TRACE_INFORMATION)\n            )))\n        {\n            if (handleInfo.SectionHandle)\n            {\n                NtClose(handleInfo.SectionHandle);\n            }\n        }\n    }\n\n    if (PssNtFreeRemoteSnapshot_Import())\n    {\n        PssNtFreeRemoteSnapshot_Import()(ProcessHandle, SnapshotHandle);\n    }\n\n    if (PssNtFreeSnapshot_Import())\n    {\n        PssNtFreeSnapshot_Import()(SnapshotHandle);\n    }\n}\n\n/**\n * Creates a process with redirected input/output, optionally providing input and capturing output.\n *\n * \\param CommandLine The command line to execute (as a PPH_STRING).\n * \\param CommandInput Optional input to write to the process's standard input.\n * \\param CommandOutput Optional pointer to receive the process's standard output as a PPH_STRING.\n * \\return NTSTATUS code indicating the process exit status or error.\n */\nNTSTATUS PhCreateProcessRedirection(\n    _In_opt_ PCPH_STRINGREF FileName,\n    _In_opt_ PCPH_STRINGREF CommandLine,\n    _In_opt_ PCPH_STRINGREF CommandInput,\n    _Out_opt_ PPH_STRING *CommandOutput\n    )\n{\n    static SECURITY_ATTRIBUTES securityAttributes = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };\n    NTSTATUS status;\n    PPH_STRING output = NULL;\n    STARTUPINFOEX startupInfo = { 0 };\n    HANDLE processHandle = NULL;\n    HANDLE outputReadHandle = NULL;\n    HANDLE outputWriteHandle = NULL;\n    HANDLE inputReadHandle = NULL;\n    HANDLE inputWriteHandle = NULL;\n    PPROC_THREAD_ATTRIBUTE_LIST attributeList = NULL;\n    HANDLE handleList[2];\n#if defined(PH_BUILD_MSIX)\n    ULONG appPolicy;\n#endif\n    PROCESS_BASIC_INFORMATION basicInfo;\n\n    status = PhCreatePipeEx(\n        &inputReadHandle,\n        &inputWriteHandle,\n        &securityAttributes,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreatePipeEx(\n        &outputReadHandle,\n        &outputWriteHandle,\n        NULL,\n        &securityAttributes\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n#if !defined(PH_BUILD_MSIX)\n    status = PhInitializeProcThreadAttributeList(&attributeList, 1);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    handleList[0] = inputReadHandle;\n    handleList[1] = outputWriteHandle;\n\n    status = PhUpdateProcThreadAttribute(\n        attributeList,\n        PROC_THREAD_ATTRIBUTE_HANDLE_LIST,\n        handleList,\n        sizeof(handleList)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n#else\n    status = PhInitializeProcThreadAttributeList(&attributeList, 2);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    handleList[0] = inputReadHandle;\n    handleList[1] = outputWriteHandle;\n\n    status = PhUpdateProcThreadAttribute(\n        attributeList,\n        PROC_THREAD_ATTRIBUTE_HANDLE_LIST,\n        handleList,\n        sizeof(handleList)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    appPolicy = PROCESS_CREATION_DESKTOP_APP_BREAKAWAY_OVERRIDE;\n\n    status = PhUpdateProcThreadAttribute(\n        attributeList,\n        PROC_THREAD_ATTRIBUTE_DESKTOP_APP_POLICY,\n        &appPolicy,\n        sizeof(ULONG)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n#endif\n\n    memset(&startupInfo, 0, sizeof(STARTUPINFOEX));\n    startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX);\n    startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES;\n    startupInfo.StartupInfo.wShowWindow = SW_HIDE;\n    startupInfo.StartupInfo.hStdInput = inputReadHandle;\n    startupInfo.StartupInfo.hStdOutput = outputWriteHandle;\n    startupInfo.StartupInfo.hStdError = outputWriteHandle;\n    startupInfo.lpAttributeList = attributeList;\n\n    status = PhCreateProcessWin32Ex(\n        PhGetStringRefZ(FileName),\n        PhGetStringRefZ(CommandLine),\n        NULL,\n        NULL,\n        &startupInfo,\n        PH_CREATE_PROCESS_INHERIT_HANDLES | PH_CREATE_PROCESS_NEW_CONSOLE |\n        PH_CREATE_PROCESS_DEFAULT_ERROR_MODE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO,\n        NULL,\n        NULL,\n        &processHandle,\n        NULL\n        );\n\n    NtClose(inputReadHandle);\n    inputReadHandle = NULL;\n    NtClose(outputWriteHandle);\n    outputWriteHandle = NULL;\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (CommandInput)\n    {\n        PhWriteFile(\n            inputWriteHandle,\n            CommandInput->Buffer,\n            (ULONG)CommandInput->Length,\n            NULL,\n            NULL\n            );\n    }\n\n    status = PhGetFileText(&output, outputReadHandle, TRUE);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    //if (PhIsNullOrEmptyString(output))\n    //{\n    //    status = STATUS_UNSUCCESSFUL;\n    //    goto CleanupExit;\n    //}\n\n    status = PhGetProcessBasicInformation(processHandle, &basicInfo);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = basicInfo.ExitStatus;\n\nCleanupExit:\n    if (processHandle)\n        NtClose(processHandle);\n    if (outputWriteHandle)\n        NtClose(outputWriteHandle);\n    if (outputReadHandle)\n        NtClose(outputReadHandle);\n    if (inputReadHandle)\n        NtClose(inputReadHandle);\n    if (inputWriteHandle)\n        NtClose(inputWriteHandle);\n    if (attributeList)\n        PhDeleteProcThreadAttributeList(attributeList);\n\n    if (CommandOutput)\n        *CommandOutput = output;\n    else\n        PhClearReference(&output);\n\n    return status;\n}\n\n// rev from InitializeProcThreadAttributeList (dmex)\n/**\n * Initializes a PROC_THREAD_ATTRIBUTE_LIST structure for process/thread attribute updates.\n *\n * \\param AttributeList Receives a pointer to the allocated attribute list.\n * \\param AttributeCount The number of attributes to reserve space for.\n * \\return NTSTATUS code indicating success or failure.\n * \\remarks The caller must free the attribute list using PhDeleteProcThreadAttributeList().\n */\nNTSTATUS PhInitializeProcThreadAttributeList(\n    _Out_ PPROC_THREAD_ATTRIBUTE_LIST* AttributeList,\n    _In_ ULONG AttributeCount\n    )\n{\n#if defined(PHNT_NATIVE_PROCATTRIBUTELIST)\n    PPROC_THREAD_ATTRIBUTE_LIST attributeList;\n    SIZE_T attributeListLength;\n\n    InitializeProcThreadAttributeList(NULL, AttributeCount, 0, &attributeListLength);\n\n    attributeList = PhAllocateZero(attributeListLength);\n    attributeList->AttributeCount = AttributeCount;\n    *AttributeList = attributeList;\n\n    return STATUS_SUCCESS;\n#else\n    PPROC_THREAD_ATTRIBUTE_LIST attributeList;\n    SIZE_T attributeListLength;\n\n    attributeListLength = FIELD_OFFSET(PROC_THREAD_ATTRIBUTE_LIST, Attributes);\n    attributeListLength += sizeof(PROC_THREAD_ATTRIBUTE) * AttributeCount;\n    attributeList = PhAllocateZero(attributeListLength);\n    attributeList->AttributeCount = AttributeCount;\n    *AttributeList = attributeList;\n\n    return STATUS_SUCCESS;\n#endif\n}\n\n// rev from DeleteProcThreadAttributeList (dmex)\n/**\n * Frees a PROC_THREAD_ATTRIBUTE_LIST structure previously allocated by PhInitializeProcThreadAttributeList.\n *\n * \\param AttributeList Pointer to the attribute list to free.\n * \\return NTSTATUS code indicating success or failure.\n */\nNTSTATUS PhDeleteProcThreadAttributeList(\n    _In_ PPROC_THREAD_ATTRIBUTE_LIST AttributeList\n    )\n{\n    PhFree(AttributeList);\n    return STATUS_SUCCESS;\n}\n\n// rev from UpdateProcThreadAttribute (dmex)\n/**\n * Updates a process/thread attribute in a PROC_THREAD_ATTRIBUTE_LIST.\n *\n * \\param AttributeList Pointer to the attribute list.\n * \\param AttributeNumber The attribute to update (e.g., PROC_THREAD_ATTRIBUTE_HANDLE_LIST).\n * \\param Buffer Pointer to the attribute data.\n * \\param BufferLength Size of the attribute data in bytes.\n * \\return NTSTATUS code indicating success or failure.\n */\nNTSTATUS PhUpdateProcThreadAttribute(\n    _In_ PPROC_THREAD_ATTRIBUTE_LIST AttributeList,\n    _In_ ULONG_PTR AttributeNumber,\n    _In_ PVOID Buffer,\n    _In_ SIZE_T BufferLength\n    )\n{\n#if defined(PHNT_NATIVE_PROCATTRIBUTELIST)\n    if (!UpdateProcThreadAttribute(AttributeList, 0, AttributeNumber, Buffer, BufferLength, NULL, NULL))\n        return STATUS_NO_MEMORY;\n\n    return STATUS_SUCCESS;\n#else\n    if (AttributeList->LastAttribute >= AttributeList->AttributeCount)\n        return STATUS_NO_MEMORY;\n\n    AttributeList->PresentFlags |= (1 << (AttributeNumber & PROC_THREAD_ATTRIBUTE_NUMBER));\n    AttributeList->Attributes[AttributeList->LastAttribute].Attribute = AttributeNumber;\n    AttributeList->Attributes[AttributeList->LastAttribute].Size = BufferLength;\n    AttributeList->Attributes[AttributeList->LastAttribute].Value = (ULONG_PTR)Buffer;\n    AttributeList->LastAttribute++;\n\n    return STATUS_SUCCESS;\n#endif\n}\n\n/**\n * Retrieves the active computer name from the registry.\n *\n * \\return A PPH_STRING containing the active computer name, or NULL if not found.\n */\nPPH_STRING PhGetActiveComputerName(\n    VOID\n    )\n{\n    //static PH_STRINGREF keyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Control\\\\ComputerName\\\\ActiveComputerName\");\n    PPH_STRING keyName;\n    PPH_STRING computerName = NULL;\n    HANDLE keyHandle;\n    PH_FORMAT format[8];\n\n    PhInitFormatS(&format[0], L\"System\\\\CurrentControlSet\\\\Control\");\n    PhInitFormatC(&format[1], OBJ_NAME_PATH_SEPARATOR);\n    PhInitFormatS(&format[2], L\"Computer\");\n    PhInitFormatS(&format[3], L\"Name\");\n    PhInitFormatC(&format[4], OBJ_NAME_PATH_SEPARATOR);\n    PhInitFormatS(&format[5], L\"Active\");\n    PhInitFormatS(&format[6], L\"Computer\");\n    PhInitFormatS(&format[7], L\"Name\");\n\n    keyName = PhFormat(format, RTL_NUMBER_OF(format), 0);\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &keyName->sr,\n        0\n        )))\n    {\n        computerName = PhQueryRegistryStringZ(keyHandle, L\"ComputerName\");\n        NtClose(keyHandle);\n    }\n\n    //WCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1];\n    //ULONG length = MAX_COMPUTERNAME_LENGTH + 1;\n    //\n    //if (GetComputerNameW(computerName, &length))\n    //{\n    //   return PhCreateStringEx(computerName, length * sizeof(WCHAR));\n    //}\n\n    PhDereferenceObject(keyName);\n\n    return computerName;\n}\n\n/**\n * Finds a property in an array of device properties.\n *\n * \\param Key The property key to find.\n * \\param Store The property store to find.\n * \\param PropertiesCount The number of properties in the array.\n * \\param Properties The array of properties.\n * \\return A pointer to the property, or NULL if not found.\n */\nPDEVPROPERTY PhDevFindProperty(\n    _In_ PDEVPROPKEY Key,\n    _In_ ULONG Store,\n    _In_ ULONG PropertiesCount,\n    _In_reads_(PropertiesCount) PDEVPROPERTY Properties\n    )\n{\n    for (ULONG i = 0; i < PropertiesCount; i++)\n    {\n        PDEVPROPERTY property = &Properties[i];\n\n        if (RtlEqualMemory(&property->CompKey.Key, Key, sizeof(DEVPROPKEY)) && property->CompKey.Store == Store)\n        {\n            return property;\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Queries device objects using the DevGetObjects API.\n *\n * \\param ObjectType The type of device object to query.\n * \\param QueryFlags Flags controlling the query.\n * \\param RequestedPropertiesCount Number of requested properties.\n * \\param RequestedProperties Array of requested property keys.\n * \\param FilterExpressionCount Number of filter expressions.\n * \\param FilterExpressions Array of filter expressions.\n * \\param ObjectCount Receives the number of objects returned.\n * \\param Objects Receives a pointer to the array of device objects.\n * \\return HRESULT indicating success or failure.\n * \\remarks The returned objects must be freed with PhDevFreeObjects().\n */\nHRESULT PhDevGetObjects(\n    _In_ DEV_OBJECT_TYPE ObjectType,\n    _In_ DEV_QUERY_FLAGS QueryFlags,\n    _In_ ULONG RequestedPropertiesCount,\n    _In_reads_opt_(RequestedPropertiesCount) const DEVPROPCOMPKEY* RequestedProperties,\n    _In_ ULONG FilterExpressionCount,\n    _In_reads_opt_(FilterExpressionCount) const DEVPROP_FILTER_EXPRESSION* FilterExpressions,\n    _Out_ PULONG ObjectCount,\n    _Outptr_result_buffer_(*ObjectCount) const DEV_OBJECT** Objects\n    )\n{\n    HRESULT status;\n\n    if (!DevGetObjects_Import())\n        return E_FAIL;\n\n    status = DevGetObjects_Import()(\n        ObjectType,\n        QueryFlags,\n        RequestedPropertiesCount,\n        RequestedProperties,\n        FilterExpressionCount,\n        FilterExpressions,\n        ObjectCount,\n        Objects\n        );\n\n    if (SUCCEEDED(status))\n    {\n        if (*ObjectCount == 0)\n        {\n            status = E_FAIL;\n        }\n    }\n\n    return status;\n}\n\n/**\n * Frees device objects previously returned by PhDevGetObjects.\n *\n * \\param ObjectCount Number of objects.\n * \\param Objects Pointer to the array of device objects.\n */\nVOID PhDevFreeObjects(\n    _In_ ULONG ObjectCount,\n    _In_reads_(ObjectCount) const DEV_OBJECT* Objects\n    )\n{\n    if (DevFreeObjects_Import())\n    {\n        DevFreeObjects_Import()(ObjectCount, Objects);\n    }\n}\n\n/**\n * Queries properties of a device object.\n *\n * \\param ObjectType The type of device object.\n * \\param ObjectId The object ID.\n * \\param QueryFlags Flags controlling the query.\n * \\param RequestedPropertiesCount Number of requested properties.\n * \\param RequestedProperties Array of requested property keys.\n * \\param PropertiesCount Receives the number of properties returned.\n * \\param Properties Receives a pointer to the array of properties.\n * \\return HRESULT indicating success or failure.\n * \\remarks The returned properties must be freed with PhDevFreeObjectProperties().\n */\nHRESULT PhDevGetObjectProperties(\n    _In_ DEV_OBJECT_TYPE ObjectType,\n    _In_ PCWSTR ObjectId,\n    _In_ DEV_QUERY_FLAGS QueryFlags,\n    _In_ ULONG RequestedPropertiesCount,\n    _In_reads_(RequestedPropertiesCount) const DEVPROPCOMPKEY* RequestedProperties,\n    _Out_ PULONG PropertiesCount,\n    _Outptr_result_buffer_(*PropertiesCount) const DEVPROPERTY** Properties\n    )\n{\n    if (!DevGetObjectProperties_Import())\n        return E_FAIL;\n\n    return DevGetObjectProperties_Import()(\n        ObjectType,\n        ObjectId,\n        QueryFlags,\n        RequestedPropertiesCount,\n        RequestedProperties,\n        PropertiesCount,\n        Properties\n        );\n}\n\n/**\n * Frees device object properties previously returned by PhDevGetObjectProperties.\n *\n * \\param PropertiesCount Number of properties.\n * \\param Properties Pointer to the array of properties.\n */\nVOID PhDevFreeObjectProperties(\n    _In_ ULONG PropertiesCount,\n    _In_reads_(PropertiesCount) const DEVPROPERTY* Properties\n    )\n{\n    if (DevFreeObjectProperties_Import())\n    {\n        DevFreeObjectProperties_Import()(PropertiesCount, Properties);\n    }\n}\n\n/**\n * Creates a device object query using the DevCreateObjectQuery API.\n *\n * \\param ObjectType The type of device object.\n * \\param QueryFlags Flags controlling the query.\n * \\param RequestedPropertiesCount Number of requested properties.\n * \\param RequestedProperties Array of requested property keys.\n * \\param FilterExpressionCount Number of filter expressions.\n * \\param Filter Array of filter expressions.\n * \\param Callback Callback function to receive query results.\n * \\param Context User-defined context for the callback.\n * \\param DevQuery Receives the query handle.\n * \\return HRESULT indicating success or failure.\n * \\remarks The query handle must be closed with PhDevCloseObjectQuery().\n */\nHRESULT PhDevCreateObjectQuery(\n    _In_ DEV_OBJECT_TYPE ObjectType,\n    _In_ DEV_QUERY_FLAGS QueryFlags,\n    _In_ ULONG RequestedPropertiesCount,\n    _In_reads_opt_(RequestedPropertiesCount) const DEVPROPCOMPKEY* RequestedProperties,\n    _In_ ULONG FilterExpressionCount,\n    _In_reads_opt_(FilterExpressionCount) const DEVPROP_FILTER_EXPRESSION* Filter,\n    _In_ PDEV_QUERY_RESULT_CALLBACK Callback,\n    _In_opt_ PVOID Context,\n    _Out_ PHDEVQUERY DevQuery\n    )\n{\n    *DevQuery = NULL;\n\n    if (!DevCreateObjectQuery_Import())\n        return E_FAIL;\n\n    return DevCreateObjectQuery_Import()(\n        ObjectType,\n        QueryFlags,\n        RequestedPropertiesCount,\n        RequestedProperties,\n        FilterExpressionCount,\n        Filter,\n        Callback,\n        Context,\n        DevQuery\n        );\n}\n\n/**\n * Closes a device object query handle.\n *\n * \\param QueryHandle The query handle to close.\n */\nVOID PhDevCloseObjectQuery(\n    _In_ HDEVQUERY QueryHandle\n    )\n{\n    if (DevCloseObjectQuery_Import())\n    {\n        DevCloseObjectQuery_Import()(QueryHandle);\n    }\n}\n\n/**\n * Modern replacement for CM_Open_DevInst_Key using PhDevGetObjects.\n *\n * \\param DeviceInstanceId The stable Device Instance ID string.\n * \\param DesiredAccess Registry access mask.\n * \\param Flags PH_DEVKEY_* flags.\n * \\param KeyHandle Pointer to receive the handle.\n */\nNTSTATUS PhDevOpenObjectKey(\n    _In_ PPH_STRING DeviceInstanceId,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG Flags,\n    _Out_ PHANDLE KeyHandle\n)\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    ULONG objectCount = 0;\n    const DEV_OBJECT* objects = NULL;\n    DEVPROP_FILTER_EXPRESSION filter[1];\n    DEVPROPCOMPKEY driverPropKey[1];\n\n    filter[0].Operator = DEVPROP_OPERATOR_EQUALS;\n    filter[0].Property.CompKey.Key = DEVPKEY_Device_InstanceId;\n    filter[0].Property.CompKey.Store = DEVPROP_STORE_SYSTEM;\n    filter[0].Property.CompKey.LocaleName = NULL;\n    filter[0].Property.Type = DEVPROP_TYPE_STRING;\n    filter[0].Property.BufferSize = (ULONG)DeviceInstanceId->Length + sizeof(UNICODE_NULL);\n    filter[0].Property.Buffer = DeviceInstanceId->Buffer;\n\n    // Request the Driver (Software) property if needed\n    driverPropKey[0].Key = DEVPKEY_Device_Driver;\n    driverPropKey[0].Store = DEVPROP_STORE_SYSTEM;\n    driverPropKey[0].LocaleName = NULL;\n\n    if (HR_SUCCESS(PhDevGetObjects(\n        DevObjectTypeDevice,\n        DevQueryFlagNone,\n        BooleanFlagOn(Flags, PH_DEVKEY_SOFTWARE) ? RTL_NUMBER_OF(driverPropKey) : 0,\n        BooleanFlagOn(Flags, PH_DEVKEY_SOFTWARE) ? driverPropKey : NULL,\n        RTL_NUMBER_OF(filter),\n        filter,\n        &objectCount,\n        &objects\n        )) && objectCount > 0)\n    {\n        PPH_STRING registryPath = NULL;\n\n        if (FlagOn(Flags, PH_DEVKEY_SOFTWARE))\n        {\n            // SOFTWARE (Driver) Key: \\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{GUID}\\xxxx\n            for (ULONG i = 0; i < objects[0].cPropertyCount; i++)\n            {\n                if (\n                    IsEqualGUID(&objects[0].pProperties[i].CompKey.Key.fmtid, &DEVPKEY_Device_Driver.fmtid) &&\n                    objects[0].pProperties[i].CompKey.Key.pid == DEVPKEY_Device_Driver.pid\n                    )\n                {\n                    if (objects[0].pProperties[i].Type == DEVPROP_TYPE_STRING)\n                    {\n                        static const PH_STRINGREF keyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Control\\\\Class\\\\\");\n                        PH_STRINGREF value;\n\n                        PhInitializeStringRefLongHint(&value, (PCWSTR)objects[0].pProperties[i].Buffer);\n                        registryPath = PhConcatStringRef2(&keyName, &value);\n                    }\n                    break;\n                }\n            }\n        }\n        else if (FlagOn(Flags, PH_DEVKEY_HARDWARE))\n        {\n            // HARDWARE Key: \\Registry\\Machine\\System\\CurrentControlSet\\Enum\\{InstanceID}\\Device Parameters\n            static const PH_STRINGREF base = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Enum\\\\\");\n            static const PH_STRINGREF suffix = PH_STRINGREF_INIT(L\"\\\\Device Parameters\");\n\n            registryPath = PhConcatStringRef3(&base, &DeviceInstanceId->sr, &suffix);\n        }\n        else if (FlagOn(Flags, PH_DEVKEY_USER))\n        {\n            // USER Key: \\Registry\\User\\{SID}\\Software\\Microsoft\\Windows\\CurrentVersion\\DeviceAccess\\{InstanceID}\n            PPH_STRING userSid;\n\n            if (userSid = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, FALSE))\n            {\n                status = PhOpenKey(\n                    KeyHandle,\n                    DesiredAccess,\n                    PH_KEY_USERS,\n                    &userSid->sr,\n                    OBJ_CASE_INSENSITIVE\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    static const PH_STRINGREF base = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\DeviceAccess\\\\\");\n                    HANDLE subKey;\n                    PPH_STRING subKeyPath;\n\n                    subKeyPath = PhConcatStringRef2(&base, &DeviceInstanceId->sr);\n\n                    status = PhOpenKey(\n                        &subKey,\n                        DesiredAccess,\n                        *KeyHandle,\n                        &subKeyPath->sr,\n                        OBJ_CASE_INSENSITIVE\n                        );\n\n                    NtClose(*KeyHandle);\n                    PhDereferenceObject(subKeyPath);\n\n                    if (NT_SUCCESS(status))\n                    {\n                        *KeyHandle = subKey;\n                    }\n                }\n\n                PhDereferenceObject(userSid);\n            }\n        }\n        else if (FlagOn(Flags, PH_DEVKEY_CONFIG))\n        {\n            static const PH_STRINGREF base = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Enum\\\\\");\n            static const PH_STRINGREF suffix = PH_STRINGREF_INIT(L\"\\\\Device Parameters\\\\Configuration\");\n\n            // CONFIG Key: \\Registry\\Machine\\System\\CurrentControlSet\\Enum\\{InstanceID}\\Device Parameters\\Configuration\n            registryPath = PhConcatStringRef3(&base, &DeviceInstanceId->sr, &suffix);\n        }\n\n        if (registryPath)\n        {\n            status = PhOpenKey(\n                KeyHandle,\n                DesiredAccess,\n                PH_KEY_LOCAL_MACHINE,\n                &registryPath->sr,\n                OBJ_CASE_INSENSITIVE\n                );\n\n            PhDereferenceObject(registryPath);\n        }\n\n        PhDevFreeObjects(objectCount, objects);\n    }\n\n    return status;\n}\n\n/**\n * Creates a taskbar list object for progress and overlay icon management.\n *\n * \\param TaskbarHandle Receives the ITaskbarList3 interface pointer as a HANDLE.\n * \\return HRESULT indicating success or failure.\n * \\remarks The returned handle must be released with PhTaskbarListDestroy().\n */\nHRESULT PhTaskbarListCreate(\n    _Out_ PHANDLE TaskbarHandle\n    )\n{\n    HRESULT status;\n    ITaskbarList3* taskbarListClass;\n\n    status = PhGetClassObject(\n        L\"explorerframe.dll\",\n        &CLSID_TaskbarList,\n        &IID_ITaskbarList3,\n        &taskbarListClass\n        );\n\n    if (SUCCEEDED(status))\n    {\n        status = ITaskbarList3_HrInit(taskbarListClass);\n\n        if (FAILED(status))\n        {\n            ITaskbarList3_Release(taskbarListClass);\n            taskbarListClass = NULL;\n        }\n    }\n\n    if (SUCCEEDED(status))\n    {\n        *TaskbarHandle = taskbarListClass;\n    }\n\n    return status;\n}\n\n/**\n * Releases a taskbar list object previously created by PhTaskbarListCreate.\n *\n * \\param TaskbarHandle The taskbar handle to release.\n */\nVOID PhTaskbarListDestroy(\n    _In_ HANDLE TaskbarHandle\n    )\n{\n    ITaskbarList3_Release((ITaskbarList3*)TaskbarHandle);\n}\n\n/**\n * Sets the progress value for a window on the taskbar.\n *\n * \\param TaskbarHandle The taskbar handle.\n * \\param WindowHandle The window handle.\n * \\param Completed The completed value.\n * \\param Total The total value.\n */\nVOID PhTaskbarListSetProgressValue(\n    _In_ HANDLE TaskbarHandle,\n    _In_ HWND WindowHandle,\n    _In_ ULONGLONG Completed,\n    _In_ ULONGLONG Total\n    )\n{\n    ITaskbarList3_SetProgressValue((ITaskbarList3*)TaskbarHandle, WindowHandle, Completed, Total);\n}\n\n/**\n * Sets the progress state for a window on the taskbar.\n *\n * \\param TaskbarHandle The taskbar handle.\n * \\param WindowHandle The window handle.\n * \\param Flags Progress state flags (PH_TBLF_*).\n */\nVOID PhTaskbarListSetProgressState(\n    _In_ HANDLE TaskbarHandle,\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags\n    )\n{\n    static CONST PH_FLAG_MAPPING PhTaskbarListFlagMappings[] =\n    {\n        { PH_TBLF_NOPROGRESS, TBPF_NOPROGRESS },\n        { PH_TBLF_INDETERMINATE, TBPF_INDETERMINATE },\n        { PH_TBLF_NORMAL, TBPF_NORMAL },\n        { PH_TBLF_ERROR, TBPF_ERROR },\n        { PH_TBLF_PAUSED, TBPF_PAUSED },\n    };\n    ULONG flags;\n\n    flags = 0;\n    PhMapFlags1(&flags, Flags, PhTaskbarListFlagMappings, RTL_NUMBER_OF(PhTaskbarListFlagMappings));\n\n    ITaskbarList3_SetProgressState((ITaskbarList3*)TaskbarHandle, WindowHandle, flags);\n}\n\n/**\n * Sets an overlay icon for a window on the taskbar.\n *\n * \\param TaskbarHandle The taskbar handle.\n * \\param WindowHandle The window handle.\n * \\param IconHandle The icon handle to set as overlay.\n * \\param IconDescription Optional description for accessibility.\n */\nVOID PhTaskbarListSetOverlayIcon(\n    _In_ HANDLE TaskbarHandle,\n    _In_ HWND WindowHandle,\n    _In_opt_ HICON IconHandle,\n    _In_opt_ PCWSTR IconDescription\n    )\n{\n    ITaskbarList3_SetOverlayIcon((ITaskbarList3*)TaskbarHandle, WindowHandle, IconHandle, IconDescription);\n}\n\n/**\n * Determines if DirectX is currently running in exclusive full-screen mode.\n *\n * \\return TRUE if DirectX is running full-screen, otherwise FALSE.\n */\nBOOLEAN PhIsDirectXRunningFullScreen(\n    VOID\n    )\n{\n    static typeof(&D3DKMTCheckExclusiveOwnership) D3DKMTCheckExclusiveOwnership_I = NULL;\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"gdi32.dll\"))\n        {\n            D3DKMTCheckExclusiveOwnership_I = PhGetDllBaseProcedureAddress(baseAddress, \"D3DKMTCheckExclusiveOwnership\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!D3DKMTCheckExclusiveOwnership_I)\n        return FALSE;\n\n    return D3DKMTCheckExclusiveOwnership_I();\n}\n\n/**\n * Releases exclusive ownership of the display from a DirectX full-screen process.\n *\n * \\param ProcessHandle Handle to the process to restore.\n * \\return NTSTATUS code indicating success or failure.\n */\nNTSTATUS PhRestoreFromDirectXRunningFullScreen(\n    _In_ HANDLE ProcessHandle\n    )\n{\n    static typeof(&D3DKMTReleaseProcessVidPnSourceOwners) D3DKMTReleaseProcessVidPnSourceOwners_I = NULL;\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"gdi32.dll\"))\n        {\n            D3DKMTReleaseProcessVidPnSourceOwners_I = PhGetDllBaseProcedureAddress(baseAddress, \"D3DKMTReleaseProcessVidPnSourceOwners\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!D3DKMTReleaseProcessVidPnSourceOwners_I)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    return D3DKMTReleaseProcessVidPnSourceOwners_I(ProcessHandle);\n}\n\n/**\n * Queries exclusive ownership information for DirectX video present network (VidPn) sources.\n *\n * \\param QueryExclusiveOwnership Pointer to a D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP structure.\n * \\return NTSTATUS code indicating success or failure.\n */\nNTSTATUS PhQueryDirectXExclusiveOwnership(\n    _Inout_ PD3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP QueryExclusiveOwnership\n    )\n{\n    static typeof(&D3DKMTQueryVidPnExclusiveOwnership) D3DKMTQueryVidPnExclusiveOwnership_I = NULL; // same typedef as NtGdiDdDDIQueryVidPnExclusiveOwnership\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID baseAddress;\n\n        if (baseAddress = PhLoadLibrary(L\"gdi32.dll\")) // win32u.dll\n        {\n            D3DKMTQueryVidPnExclusiveOwnership_I = PhGetDllBaseProcedureAddress(baseAddress, \"D3DKMTQueryVidPnExclusiveOwnership\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!D3DKMTQueryVidPnExclusiveOwnership_I)\n        return FALSE;\n\n    return D3DKMTQueryVidPnExclusiveOwnership_I(QueryExclusiveOwnership);\n}\n\ntypedef struct _PH_ENDSESSION_CONTEXT\n{\n    CLIENT_ID ClientId;\n    ULONG_PTR Result; // Result from the last successful PhSendMessageTimeout\n    BOOLEAN Valid; // TRUE if FinalResult contains a valid value\n} PH_ENDSESSION_CONTEXT, * PPH_ENDSESSION_CONTEXT;\n\n/**\n * Callback used to send WM_QUERYENDSESSION/WM_ENDSESSION to windows of a specific process.\n *\n * Enumerates all top-level windows and, for those belonging to the process specified by Context,\n * sends WM_QUERYENDSESSION and, if accepted, WM_ENDSESSION messages.\n *\n * \\param WindowHandle Handle to the window being enumerated.\n * \\param Context Pointer to the process ID (as CLIENT_ID) to match against window's process.\n * \\return TRUE to continue enumeration, FALSE to stop.\n */\n_Function_class_(PH_WINDOW_ENUM_CALLBACK)\nstatic BOOLEAN CALLBACK PhQueryEndSessionCallback(\n    _In_ HWND WindowHandle,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_ENDSESSION_CONTEXT context = (PPH_ENDSESSION_CONTEXT)Context;\n    CLIENT_ID processId;\n\n    // Skip invisible windows; they do not respond to session‑end queries.\n    if (!IsWindowVisible(WindowHandle))\n        return TRUE;\n\n    // Check whether this window belongs to the target process.\n    if (\n        NT_SUCCESS(PhGetWindowClientId(WindowHandle, &processId)) &&\n        processId.UniqueProcess == context->ClientId.UniqueProcess\n        )\n    {\n        ULONG_PTR result = 0;\n\n        // Ask the window whether it consents to session termination.\n        if (PhSendMessageTimeout(\n            WindowHandle,\n            WM_QUERYENDSESSION,\n            0,\n            ENDSESSION_CLOSEAPP,\n            5000,\n            &result\n            ))\n        {\n            // If the window agrees, notify it that the session is ending.\n            if (result)\n            {\n                if (PhSendMessageTimeout(\n                    WindowHandle,\n                    WM_ENDSESSION,\n                    TRUE,\n                    ENDSESSION_LOGOFF,\n                    5000,\n                    &result\n                    ))\n                {\n                    context->Result = result;\n                    context->Valid = TRUE;\n                }\n            }\n\n            return FALSE;\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Sends WM_QUERYENDSESSION/WM_ENDSESSION messages to all windows belonging to the specified process.\n *\n * \\param WindowHandle Handle to a window of the process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSTATUS PhEndWindowSession(\n    _In_ HWND WindowHandle\n    )\n{\n    NTSTATUS status;\n    CLIENT_ID clientId;\n    PH_ENDSESSION_CONTEXT context;\n\n    status = PhGetWindowClientId(WindowHandle, &clientId);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    RtlZeroMemory(&context, sizeof(PH_ENDSESSION_CONTEXT));\n    context.ClientId = clientId;\n\n    status = PhEnumWindows(PhQueryEndSessionCallback, &clientId);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (context.Valid && context.Result != 0)\n        return STATUS_SUCCESS;\n\n    return STATUS_FAIL_CHECK;\n}\n\nstatic CONST PPH_STRINGREF PhLuidKnownTypeStrings[] =\n{\n    SREF(L\"SYSTEM\"),\n    SREF(L\"PROTECTED_TO_SYSTEM\"),\n    SREF(L\"NETWORKSERVICE\"),\n    SREF(L\"LOCALSERVICE\"),\n    SREF(L\"ANONYMOUS_LOGON\"),\n    SREF(L\"IUSER\"),\n};\n\n/**\n * Returns a string representation for well‑known authentication LUIDs.\n *\n * \\param Luid Pointer to the LUID to classify.\n * \\return A PCPH_STRINGREF containing the name of the known LUID, or NULL if the\n * LUID is not one of the recognized well‑known identifiers.\n */\nPCPH_STRINGREF PhGetLuidKnownTypeToString(\n    _In_ PLUID Luid\n    )\n{\n    if (RtlIsEqualLuid(Luid, &((LUID)SYSTEM_LUID)))\n    {\n        return (PCPH_STRINGREF)&PhLuidKnownTypeStrings[0];\n    }\n    else if (RtlIsEqualLuid(Luid, &((LUID)PROTECTED_TO_SYSTEM_LUID)))\n    {\n        return (PCPH_STRINGREF)&PhLuidKnownTypeStrings[1];\n    }\n    else if (RtlIsEqualLuid(Luid, &((LUID)NETWORKSERVICE_LUID)))\n    {\n        return (PCPH_STRINGREF)&PhLuidKnownTypeStrings[2];\n    }\n    else if (RtlIsEqualLuid(Luid, &((LUID)LOCALSERVICE_LUID)))\n    {\n        return (PCPH_STRINGREF)&PhLuidKnownTypeStrings[3];\n    }\n    else if (RtlIsEqualLuid(Luid, &((LUID)ANONYMOUS_LOGON_LUID)))\n    {\n        return (PCPH_STRINGREF)&PhLuidKnownTypeStrings[4];\n    }\n    else if (RtlIsEqualLuid(Luid, &((LUID)IUSER_LUID)))\n    {\n        return (PCPH_STRINGREF)&PhLuidKnownTypeStrings[5];\n    }\n\n    return NULL;\n}\n\n"
  },
  {
    "path": "phlib/verify.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2013\n *     dmex    2016-2023\n *\n */\n\n#define PH_ENABLE_VERIFY_CACHE\n#include <ph.h>\n#include <appresolver.h>\n#include <mapldr.h>\n\n#define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS\n#include <wintrust.h>\n#include <softpub.h>\n\n#include <verify.h>\n#include <verifyp.h>\n\n_CryptCATAdminCalcHashFromFileHandle CryptCATAdminCalcHashFromFileHandle;\n_CryptCATAdminCalcHashFromFileHandle2 CryptCATAdminCalcHashFromFileHandle2;\n_CryptCATAdminAcquireContext CryptCATAdminAcquireContext;\n_CryptCATAdminAcquireContext2 CryptCATAdminAcquireContext2;\n_CryptCATAdminEnumCatalogFromHash CryptCATAdminEnumCatalogFromHash;\n_CryptCATCatalogInfoFromContext CryptCATCatalogInfoFromContext;\n_CryptCATAdminReleaseCatalogContext CryptCATAdminReleaseCatalogContext;\n_CryptCATAdminReleaseContext CryptCATAdminReleaseContext;\n//_WTHelperProvDataFromStateData WTHelperProvDataFromStateData_I;\n//_WTHelperGetProvSignerFromChain WTHelperGetProvSignerFromChain_I;\n_WinVerifyTrust WinVerifyTrust_I;\ntypeof(&CertNameToStrW) CertNameToStr_I;\ntypeof(&CertGetEnhancedKeyUsage) CertGetEnhancedKeyUsage_I;\ntypeof(&CertDuplicateCertificateContext) CertDuplicateCertificateContext_I;\ntypeof(&CertFreeCertificateContext) CertFreeCertificateContext_I;\n\nstatic PH_INITONCE PhpVerifyInitOnce = PH_INITONCE_INIT;\nstatic CONST GUID WinTrustActionGenericVerifyV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;\nstatic CONST GUID DriverActionVerify = DRIVER_ACTION_VERIFY;\n#ifdef PH_ENABLE_VERIFY_CACHE\nstatic PPH_HASHTABLE PhpVerifyCacheHashTable = NULL;\nstatic PH_QUEUED_LOCK PhpVerifyCacheLock = PH_QUEUED_LOCK_INIT;\n#endif\n\nstatic VOID PhpVerifyInitialization(\n    VOID\n    )\n{\n    PVOID wintrust;\n    PVOID crypt32;\n\n    if (wintrust = PhLoadLibrary(L\"wintrust.dll\"))\n    {\n        CryptCATAdminCalcHashFromFileHandle = PhGetDllBaseProcedureAddress(wintrust, \"CryptCATAdminCalcHashFromFileHandle\", 0);\n        CryptCATAdminCalcHashFromFileHandle2 = PhGetDllBaseProcedureAddress(wintrust, \"CryptCATAdminCalcHashFromFileHandle2\", 0);\n        CryptCATAdminAcquireContext = PhGetDllBaseProcedureAddress(wintrust, \"CryptCATAdminAcquireContext\", 0);\n        CryptCATAdminAcquireContext2 = PhGetDllBaseProcedureAddress(wintrust, \"CryptCATAdminAcquireContext2\", 0);\n        CryptCATAdminEnumCatalogFromHash = PhGetDllBaseProcedureAddress(wintrust, \"CryptCATAdminEnumCatalogFromHash\", 0);\n        CryptCATCatalogInfoFromContext = PhGetDllBaseProcedureAddress(wintrust, \"CryptCATCatalogInfoFromContext\", 0);\n        CryptCATAdminReleaseCatalogContext = PhGetDllBaseProcedureAddress(wintrust, \"CryptCATAdminReleaseCatalogContext\", 0);\n        CryptCATAdminReleaseContext = PhGetDllBaseProcedureAddress(wintrust, \"CryptCATAdminReleaseContext\", 0);\n        //WTHelperProvDataFromStateData_I = PhGetDllBaseProcedureAddress(wintrust, \"WTHelperProvDataFromStateData\", 0);\n        //WTHelperGetProvSignerFromChain_I = PhGetDllBaseProcedureAddress(wintrust, \"WTHelperGetProvSignerFromChain\", 0);\n        WinVerifyTrust_I = PhGetDllBaseProcedureAddress(wintrust, \"WinVerifyTrust\", 0);\n    }\n\n    if (crypt32 = PhLoadLibrary(L\"crypt32.dll\"))\n    {\n        CertNameToStr_I = PhGetDllBaseProcedureAddress(crypt32, \"CertNameToStrW\", 0);\n        CertGetEnhancedKeyUsage_I = PhGetDllBaseProcedureAddress(crypt32, \"CertGetEnhancedKeyUsage\", 0);\n        CertDuplicateCertificateContext_I = PhGetDllBaseProcedureAddress(crypt32, \"CertDuplicateCertificateContext\", 0);\n        CertFreeCertificateContext_I = PhGetDllBaseProcedureAddress(crypt32, \"CertFreeCertificateContext\", 0);\n    }\n\n    if (\n        CryptCATAdminCalcHashFromFileHandle &&\n        CryptCATAdminAcquireContext &&\n        CryptCATAdminEnumCatalogFromHash &&\n        CryptCATCatalogInfoFromContext &&\n        CryptCATAdminReleaseCatalogContext &&\n        CryptCATAdminReleaseContext &&\n        WinVerifyTrust_I &&\n        CertNameToStr_I &&\n        CertDuplicateCertificateContext_I &&\n        CertFreeCertificateContext_I\n        )\n    {\n        PhpVerifyCacheHashTable = PhCreateHashtable(\n            sizeof(PH_VERIFY_CACHE_ENTRY),\n            PhpVerifyCacheHashtableEqualFunction,\n            PhpVerifyCacheHashtableHashFunction,\n            100\n            );\n    }\n}\n\nVERIFY_RESULT PhpStatusToVerifyResult(\n    _In_ LONG Status\n    )\n{\n    switch (Status)\n    {\n    case 0:\n        return VrTrusted;\n    case TRUST_E_NOSIGNATURE:\n        return VrNoSignature;\n    case CERT_E_EXPIRED:\n        return VrExpired;\n    case CERT_E_REVOKED:\n        return VrRevoked;\n    case TRUST_E_EXPLICIT_DISTRUST:\n        return VrDistrust;\n    case CRYPT_E_SECURITY_SETTINGS:\n        return VrSecuritySettings;\n    case TRUST_E_BAD_DIGEST:\n        return VrBadSignature;\n    default:\n        return VrSecuritySettings;\n    }\n}\n\n// WTHelperProvDataFromStateData (dmex)\nPCRYPT_PROVIDER_DATA PhGetCryptProviderDataFromStateData(\n    _In_ HANDLE StateData\n    )\n{\n    return (PCRYPT_PROVIDER_DATA)StateData;\n}\n\n// WTHelperGetProvSignerFromChain (dmex)\nPCRYPT_PROVIDER_SGNR PhGetCryptProviderSignerFromChain(\n    _In_ PCRYPT_PROVIDER_DATA ProvData,\n    _In_ ULONG SignerIndex,\n    _In_ BOOLEAN CounterSigner,\n    _In_ ULONG CounterSignerIndex\n    )\n{\n    PCRYPT_PROVIDER_SGNR signer;\n\n    if (!ProvData || SignerIndex >= ProvData->csSigners)\n        return NULL;\n\n    signer = &ProvData->pasSigners[SignerIndex];\n\n    if (CounterSigner)\n    {\n        if (CounterSignerIndex < signer->csCounterSigners)\n        {\n            return &signer->pasCounterSigners[CounterSignerIndex];\n        }\n    }\n\n    return signer;\n}\n\n// rev from WTHelperIsChainedToMicrosoft (dmex)\nBOOLEAN PhIsChainedToMicrosoft(\n    _In_ PCCERT_CONTEXT Certificate,\n    _In_ HCERTSTORE SiblingStore,\n    _In_ BOOLEAN IncludeMicrosoftTestRootCerts\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static typeof(&CertOpenStore) CertOpenStore_I = NULL;\n    static typeof(&CertAddStoreToCollection) CertAddStoreToCollection_I = NULL;\n    static typeof(&CertGetCertificateChain) CertGetCertificateChain_I = NULL;\n    static typeof(&CertVerifyCertificateChainPolicy) CertVerifyCertificateChainPolicy_I = NULL;\n    static typeof(&CertFreeCertificateChain) CertFreeCertificateChain_I = NULL;\n    static typeof(&CertCloseStore) CertCloseStore_I = NULL;\n    BOOLEAN status = FALSE;\n    HCERTSTORE cryptStoreHandle;\n    CERT_CHAIN_POLICY_PARA policyPara = { sizeof(CERT_CHAIN_POLICY_PARA) };\n    CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(CERT_CHAIN_POLICY_STATUS) };\n    CERT_CHAIN_PARA chainPara = { sizeof(CERT_CHAIN_PARA) };\n    PCCERT_CHAIN_CONTEXT chainContext;\n\n    if (!(Certificate && SiblingStore))\n        return FALSE;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID crypt32;\n\n        if (crypt32 = PhLoadLibrary(L\"crypt32.dll\"))\n        {\n            CertOpenStore_I = PhGetDllBaseProcedureAddress(crypt32, \"CertOpenStore\", 0);\n            CertAddStoreToCollection_I = PhGetDllBaseProcedureAddress(crypt32, \"CertAddStoreToCollection\", 0);\n            CertGetCertificateChain_I = PhGetDllBaseProcedureAddress(crypt32, \"CertGetCertificateChain\", 0);\n            CertVerifyCertificateChainPolicy_I = PhGetDllBaseProcedureAddress(crypt32, \"CertVerifyCertificateChainPolicy\", 0);\n            CertFreeCertificateChain_I = PhGetDllBaseProcedureAddress(crypt32, \"CertFreeCertificateChain\", 0);\n            CertCloseStore_I = PhGetDllBaseProcedureAddress(crypt32, \"CertCloseStore\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!(\n        CertOpenStore_I &&\n        CertAddStoreToCollection_I &&\n        CertGetCertificateChain_I &&\n        CertVerifyCertificateChainPolicy_I &&\n        CertFreeCertificateChain_I &&\n        CertCloseStore_I\n        ))\n    {\n        return FALSE;\n    }\n\n    if (cryptStoreHandle = CertOpenStore_I(CERT_STORE_PROV_COLLECTION, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, 0))\n    {\n        if (CertAddStoreToCollection_I(cryptStoreHandle, SiblingStore, 0, 0))\n        {\n            //if (IncludeMicrosoftTestRootCerts)\n            //{\n            //    PVOID wintrust = PhGetLoaderEntryDllBaseZ(L\"wintrust.dll\");\n            //    ULONG resourceLength;\n            //    PVOID resourceBuffer;\n            //\n            //    policyPara.dwFlags = MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG;\n            //\n            //    if (PhLoadResource(wintrust, MAKEINTRESOURCE(1), L\"MSTESTROOT\", &resourceLength, &resourceBuffer))\n            //    {\n            //        CERT_BLOB certificateBlob = { resourceLength, resourceBuffer };\n            //        HCERTSTORE siblingStore = NULL;\n            //\n            //        if (CryptQueryObject(\n            //            CERT_QUERY_OBJECT_BLOB,\n            //            &certificateBlob,\n            //            CERT_QUERY_CONTENT_FLAG_CERT,\n            //            CERT_QUERY_FORMAT_FLAG_ALL,\n            //            0, 0, 0, 0,\n            //            &siblingStore,\n            //            0,\n            //            0\n            //            ))\n            //        {\n            //            CertAddStoreToCollection(cryptStoreHandle, siblingStore, 0, 0);\n            //        }\n            //    }\n            //\n            //    if (PhLoadResource(wintrust, MAKEINTRESOURCE(2), L\"MSTESTROOT\", &resourceLength, &resourceBuffer))\n            //    {\n            //        CERT_BLOB certificateBlob = { resourceLength, resourceBuffer };\n            //        HCERTSTORE siblingStore = NULL;\n            //\n            //        if (CryptQueryObject(\n            //            CERT_QUERY_OBJECT_BLOB,\n            //            &certificateBlob,\n            //            CERT_QUERY_CONTENT_FLAG_CERT,\n            //            CERT_QUERY_FORMAT_FLAG_ALL,\n            //            0, 0, 0, 0,\n            //            &siblingStore,\n            //            0,\n            //            0\n            //            ))\n            //        {\n            //            CertAddStoreToCollection(cryptStoreHandle, siblingStore, 0, 0);\n            //        }\n            //    }\n            //}\n\n            if (CertGetCertificateChain_I(\n                HCCE_CURRENT_USER,\n                Certificate,\n                0,\n                cryptStoreHandle,\n                &chainPara,\n                0,\n                0,\n                &chainContext\n                ))\n            {\n                if (CertVerifyCertificateChainPolicy_I(\n                    CERT_CHAIN_POLICY_MICROSOFT_ROOT,\n                    chainContext,\n                    &policyPara,\n                    &policyStatus\n                    ))\n                {\n                    status = (policyStatus.dwError == ERROR_SUCCESS);\n                }\n\n                CertFreeCertificateChain_I(chainContext);\n            }\n        }\n\n        CertCloseStore_I(cryptStoreHandle, 0);\n    }\n\n    return status;\n}\n\nNTSTATUS PhpGetSignaturesFromStateData(\n    _In_ HANDLE StateData,\n    _Out_ PCERT_CONTEXT **Signatures,\n    _Out_ PULONG NumberOfSignatures\n    )\n{\n    PCRYPT_PROVIDER_DATA provData;\n    PCRYPT_PROVIDER_SGNR sgnr;\n    PCERT_CONTEXT *signatures;\n    ULONG i;\n    ULONG numberOfSignatures;\n    ULONG index;\n\n    provData = PhGetCryptProviderDataFromStateData(StateData);\n\n    if (!provData)\n    {\n        *Signatures = NULL;\n        *NumberOfSignatures = 0;\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    i = 0;\n    numberOfSignatures = 0;\n\n    while (sgnr = PhGetCryptProviderSignerFromChain(provData, i, FALSE, 0))\n    {\n        if (sgnr->csCertChain != 0)\n            numberOfSignatures++;\n\n        i++;\n    }\n\n    if (numberOfSignatures != 0)\n    {\n        signatures = PhAllocate(numberOfSignatures * sizeof(PCERT_CONTEXT));\n        i = 0;\n        index = 0;\n\n        while (sgnr = PhGetCryptProviderSignerFromChain(provData, i, FALSE, 0))\n        {\n            if (sgnr->csCertChain != 0)\n                signatures[index++] = (PCERT_CONTEXT)CertDuplicateCertificateContext_I(sgnr->pasCertChain[0].pCert);\n\n            i++;\n        }\n    }\n    else\n    {\n        signatures = NULL;\n    }\n\n    *Signatures = signatures;\n    *NumberOfSignatures = numberOfSignatures;\n    return STATUS_SUCCESS;\n}\n\nVOID PhpViewSignerInfo(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _In_ HANDLE StateData\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static _CryptUIDlgViewSignerInfo cryptUIDlgViewSignerInfo;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        HMODULE cryptui;\n\n        if (cryptui = PhLoadLibrary(L\"cryptui.dll\"))\n        {\n            cryptUIDlgViewSignerInfo = PhGetDllBaseProcedureAddress(cryptui, \"CryptUIDlgViewSignerInfoW\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (cryptUIDlgViewSignerInfo)\n    {\n        CRYPTUI_VIEWSIGNERINFO_STRUCT viewSignerInfo = { sizeof(CRYPTUI_VIEWSIGNERINFO_STRUCT) };\n        PCRYPT_PROVIDER_DATA provData;\n        PCRYPT_PROVIDER_SGNR sgnr;\n\n        if (!(provData = PhGetCryptProviderDataFromStateData(StateData)))\n            return;\n        if (!(sgnr = PhGetCryptProviderSignerFromChain(provData, 0, FALSE, 0)))\n            return;\n\n        viewSignerInfo.hwndParent = Information->hWnd;\n        viewSignerInfo.pSignerInfo = sgnr->psSigner;\n        viewSignerInfo.hMsg = provData->hMsg;\n        viewSignerInfo.pszOID = szOID_PKIX_KP_CODE_SIGNING;\n        cryptUIDlgViewSignerInfo(&viewSignerInfo);\n    }\n}\n\nVERIFY_RESULT PhpVerifyFile(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _In_ ULONG UnionChoice,\n    _In_ PVOID UnionData,\n    _In_ PCGUID ActionId,\n    _In_opt_ PVOID PolicyCallbackData,\n    _Out_ PCERT_CONTEXT **Signatures,\n    _Out_ PULONG NumberOfSignatures\n    )\n{\n    LONG status;\n    WINTRUST_DATA trustData;\n\n    memset(&trustData, 0, sizeof(WINTRUST_DATA));\n    trustData.cbStruct = sizeof(WINTRUST_DATA);\n    trustData.pPolicyCallbackData = PolicyCallbackData;\n    trustData.dwUIChoice = WTD_UI_NONE;\n    trustData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;\n    trustData.dwUnionChoice = UnionChoice;\n    trustData.dwStateAction = WTD_STATEACTION_VERIFY;\n    trustData.dwProvFlags = WTD_SAFER_FLAG | WTD_DISABLE_MD2_MD4;\n\n    trustData.pFile = UnionData;\n\n    if (UnionChoice == WTD_CHOICE_CATALOG)\n        trustData.pCatalog = UnionData;\n\n    if (FlagOn(Information->Flags, PH_VERIFY_PREVENT_NETWORK_ACCESS))\n    {\n        trustData.fdwRevocationChecks = WTD_REVOKE_NONE;\n        trustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL;\n    }\n\n    status = WinVerifyTrust_I(INVALID_HANDLE_VALUE, ActionId, &trustData);\n    PhpGetSignaturesFromStateData(trustData.hWVTStateData, Signatures, NumberOfSignatures);\n\n    if (status == 0 && (Information->Flags & PH_VERIFY_VIEW_PROPERTIES))\n        PhpViewSignerInfo(Information, trustData.hWVTStateData);\n\n    // Close the state data.\n    trustData.dwStateAction = WTD_STATEACTION_CLOSE;\n    WinVerifyTrust_I(INVALID_HANDLE_VALUE, ActionId, &trustData);\n\n    return PhpStatusToVerifyResult(status);\n}\n\nNTSTATUS PhpCalculateFileHash(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PCWSTR HashAlgorithm,\n    _Out_ PUCHAR *FileHash,\n    _Out_ PULONG FileHashLength,\n    _Out_ HANDLE *CatAdminHandle\n    )\n{\n    HANDLE catAdminHandle;\n    PUCHAR fileHash;\n    ULONG fileHashLength;\n    CERT_STRONG_SIGN_PARA strongSigPolicy;\n\n    memset(&strongSigPolicy, 0, sizeof(CERT_STRONG_SIGN_PARA));\n    strongSigPolicy.cbSize = sizeof(CERT_STRONG_SIGN_PARA);\n    strongSigPolicy.dwInfoChoice = CERT_STRONG_SIGN_OID_INFO_CHOICE;\n    strongSigPolicy.pszOID = szOID_CERT_STRONG_SIGN_OS_CURRENT;\n\n    if (CryptCATAdminAcquireContext2)\n    {\n        if (!CryptCATAdminAcquireContext2(&catAdminHandle, &DriverActionVerify, HashAlgorithm, &strongSigPolicy, 0))\n            return PhGetLastWin32ErrorAsNtStatus();\n    }\n    else\n    {\n        if (!CryptCATAdminAcquireContext(&catAdminHandle, &DriverActionVerify, 0))\n            return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    fileHashLength = 32;\n    fileHash = PhAllocate(fileHashLength);\n\n    if (CryptCATAdminCalcHashFromFileHandle2)\n    {\n        if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0))\n        {\n            PhFree(fileHash);\n            fileHash = PhAllocate(fileHashLength);\n\n            if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0))\n            {\n                CryptCATAdminReleaseContext(catAdminHandle, 0);\n                PhFree(fileHash);\n                return PhGetLastWin32ErrorAsNtStatus();\n            }\n        }\n    }\n    else\n    {\n        if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0))\n        {\n            PhFree(fileHash);\n            fileHash = PhAllocate(fileHashLength);\n\n            if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0))\n            {\n                CryptCATAdminReleaseContext(catAdminHandle, 0);\n                PhFree(fileHash);\n                return PhGetLastWin32ErrorAsNtStatus();\n            }\n        }\n    }\n\n    *FileHash = fileHash;\n    *FileHashLength = fileHashLength;\n    *CatAdminHandle = catAdminHandle;\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhpVerifyGetHashFromFileHandle(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PCWSTR HashAlgorithm,\n    _Out_writes_bytes_(HashTagLength) PWSTR HashTagBuffer,\n    _In_ ULONG HashTagLength,\n    _Out_writes_bytes_to_(*FileHashLength, *FileHashLength) PUCHAR FileHashBuffer,\n    _Inout_ PULONG FileHashLength,\n    _Out_ HANDLE *CatAdminHandle\n    )\n{\n    HANDLE catAdminHandle;\n    CERT_STRONG_SIGN_PARA strongSigPolicy;\n\n    memset(&strongSigPolicy, 0, sizeof(CERT_STRONG_SIGN_PARA));\n    strongSigPolicy.cbSize = sizeof(CERT_STRONG_SIGN_PARA);\n    strongSigPolicy.dwInfoChoice = CERT_STRONG_SIGN_OID_INFO_CHOICE;\n    strongSigPolicy.pszOID = szOID_CERT_STRONG_SIGN_OS_CURRENT;\n\n    if (CryptCATAdminAcquireContext2)\n    {\n        if (!CryptCATAdminAcquireContext2(&catAdminHandle, &DriverActionVerify, HashAlgorithm, &strongSigPolicy, 0))\n        {\n            if (!CryptCATAdminAcquireContext(&catAdminHandle, &DriverActionVerify, 0))\n                return PhGetLastWin32ErrorAsNtStatus();\n        }\n    }\n    else\n    {\n        if (!CryptCATAdminAcquireContext(&catAdminHandle, &DriverActionVerify, 0))\n            return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    if (CryptCATAdminCalcHashFromFileHandle2)\n    {\n        if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, FileHashLength, FileHashBuffer, 0))\n        {\n            CryptCATAdminReleaseContext(catAdminHandle, 0);\n            return PhGetLastWin32ErrorAsNtStatus();\n        }\n    }\n    else\n    {\n        if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, FileHashLength, FileHashBuffer, 0))\n        {\n            CryptCATAdminReleaseContext(catAdminHandle, 0);\n            return PhGetLastWin32ErrorAsNtStatus();\n        }\n    }\n\n    if (!PhBufferToHexStringBuffer(FileHashBuffer, *FileHashLength, TRUE, HashTagBuffer, HashTagLength, NULL))\n    {\n        CryptCATAdminReleaseContext(catAdminHandle, 0);\n        return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    *CatAdminHandle = catAdminHandle;\n    return STATUS_SUCCESS;\n}\n\nVERIFY_RESULT PhpVerifyFileFromCatalog(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _In_ HANDLE FileHandle,\n    _In_opt_ PCWSTR HashAlgorithm,\n    _Out_ PCERT_CONTEXT **Signatures,\n    _Out_ PULONG NumberOfSignatures\n    )\n{\n    VERIFY_RESULT verifyResult = VrUnknown;\n    PCERT_CONTEXT *signatures;\n    ULONG numberOfSignatures;\n    WINTRUST_CATALOG_INFO catalogInfo;\n    LARGE_INTEGER fileSize;\n    ULONG fileSizeLimit;\n    ULONG fileHashLength = 32; // bytes\n    UCHAR fileHash[32];\n    ULONG fileHashTagLength = 128; // wchar\n    WCHAR fileHashTag[64 + 1];\n    HANDLE catAdminHandle;\n    HANDLE catInfoHandle;\n\n    *Signatures = NULL;\n    *NumberOfSignatures = 0;\n\n    if (!NT_SUCCESS(PhGetFileSize(FileHandle, &fileSize)))\n        return VrNoSignature;\n\n    signatures = NULL;\n    numberOfSignatures = 0;\n\n    if (Information->FileSizeLimitForHash != ULONG_MAX)\n    {\n        fileSizeLimit = PH_VERIFY_DEFAULT_SIZE_LIMIT;\n\n        if (Information->FileSizeLimitForHash != 0)\n            fileSizeLimit = Information->FileSizeLimitForHash;\n\n        if (fileSize.QuadPart > fileSizeLimit)\n            return VrNoSignature;\n    }\n\n    if (!NT_SUCCESS(PhpVerifyGetHashFromFileHandle(\n        FileHandle,\n        HashAlgorithm,\n        fileHashTag,\n        fileHashTagLength,\n        fileHash,\n        &fileHashLength,\n        &catAdminHandle\n        )))\n    {\n        return VrBadSignature;\n    }\n\n    // Search the system catalogs.\n\n    catInfoHandle = CryptCATAdminEnumCatalogFromHash(\n        catAdminHandle,\n        fileHash,\n        fileHashLength,\n        0,\n        NULL\n        );\n\n    if (catInfoHandle)\n    {\n        CATALOG_INFO ci = { sizeof(CATALOG_INFO) };\n        DRIVER_VER_INFO verInfo = { 0 };\n\n        if (CryptCATCatalogInfoFromContext(catInfoHandle, &ci, 0))\n        {\n            // Disable OS version checking by passing in a DRIVER_VER_INFO structure.\n            verInfo.cbStruct = sizeof(DRIVER_VER_INFO);\n\n            memset(&catalogInfo, 0, sizeof(catalogInfo));\n            catalogInfo.cbStruct = sizeof(catalogInfo);\n            catalogInfo.pcwszCatalogFilePath = ci.wszCatalogFile;\n            catalogInfo.pcwszMemberFilePath = NULL; // Information->FileName\n            catalogInfo.hMemberFile = FileHandle;\n            catalogInfo.pcwszMemberTag = fileHashTag;\n            catalogInfo.pbCalculatedFileHash = fileHash;\n            catalogInfo.cbCalculatedFileHash = fileHashLength;\n            catalogInfo.hCatAdmin = catAdminHandle;\n            verifyResult = PhpVerifyFile(Information, WTD_CHOICE_CATALOG, &catalogInfo, &DriverActionVerify, &verInfo, &signatures, &numberOfSignatures);\n\n            if (verInfo.pcSignerCertContext)\n                CertFreeCertificateContext_I(verInfo.pcSignerCertContext);\n        }\n\n        CryptCATAdminReleaseCatalogContext(catAdminHandle, catInfoHandle, 0);\n    }\n    else\n    {\n        // Search any user-supplied catalogs.\n\n        for (ULONG i = 0; i < Information->NumberOfCatalogFileNames; i++)\n        {\n            PhFreeVerifySignatures(signatures, numberOfSignatures);\n\n            memset(&catalogInfo, 0, sizeof(catalogInfo));\n            catalogInfo.cbStruct = sizeof(catalogInfo);\n            catalogInfo.pcwszCatalogFilePath = Information->CatalogFileNames[i];\n            catalogInfo.pcwszMemberFilePath = NULL; // Information->FileName\n            catalogInfo.hMemberFile = FileHandle;\n            catalogInfo.pcwszMemberTag = fileHashTag;\n            catalogInfo.pbCalculatedFileHash = fileHash;\n            catalogInfo.cbCalculatedFileHash = fileHashLength;\n            catalogInfo.hCatAdmin = catAdminHandle;\n            verifyResult = PhpVerifyFile(Information, WTD_CHOICE_CATALOG, &catalogInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures);\n\n            if (verifyResult == VrTrusted)\n                break;\n        }\n    }\n\n    CryptCATAdminReleaseContext(catAdminHandle, 0);\n\n    *Signatures = signatures;\n    *NumberOfSignatures = numberOfSignatures;\n\n    return verifyResult;\n}\n\nNTSTATUS PhVerifyFileEx(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _Out_ VERIFY_RESULT *VerifyResult,\n    _Out_opt_ PCERT_CONTEXT **Signatures,\n    _Out_opt_ PULONG NumberOfSignatures\n    )\n{\n    VERIFY_RESULT verifyResult;\n    PCERT_CONTEXT *signatures;\n    ULONG numberOfSignatures;\n    WINTRUST_FILE_INFO fileInfo;\n\n    if (PhBeginInitOnce(&PhpVerifyInitOnce))\n    {\n        PhpVerifyInitialization();\n        PhEndInitOnce(&PhpVerifyInitOnce);\n    }\n\n    if (!PhpVerifyCacheHashTable)\n        return STATUS_NOT_SUPPORTED;\n\n    memset(&fileInfo, 0, sizeof(WINTRUST_FILE_INFO));\n    fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);\n    fileInfo.pgKnownSubject = (PGUID)&WINTRUST_KNOWN_SUBJECT_PE_IMAGE;\n    fileInfo.hFile = Information->FileHandle;\n\n    verifyResult = PhpVerifyFile(\n        Information,\n        WTD_CHOICE_FILE,\n        &fileInfo,\n        &WinTrustActionGenericVerifyV2,\n        NULL,\n        &signatures,\n        &numberOfSignatures\n        );\n\n    if (verifyResult == VrNoSignature)\n    {\n        if (CryptCATAdminAcquireContext2 && CryptCATAdminCalcHashFromFileHandle2)\n        {\n            PhFreeVerifySignatures(signatures, numberOfSignatures);\n\n            verifyResult = PhpVerifyFileFromCatalog(\n                Information,\n                Information->FileHandle,\n                BCRYPT_SHA256_ALGORITHM,\n                &signatures,\n                &numberOfSignatures\n                );\n        }\n\n        if (verifyResult != VrTrusted)\n        {\n            PhFreeVerifySignatures(signatures, numberOfSignatures);\n\n            verifyResult = PhpVerifyFileFromCatalog(\n                Information,\n                Information->FileHandle,\n                BCRYPT_SHA1_ALGORITHM,\n                &signatures,\n                &numberOfSignatures\n                );\n\n            if (verifyResult == VrUnknown)\n                verifyResult = VrNoSignature;\n        }\n    }\n\n    *VerifyResult = verifyResult;\n\n    if (Signatures)\n        *Signatures = signatures;\n    else\n        PhFreeVerifySignatures(signatures, numberOfSignatures);\n\n    if (NumberOfSignatures)\n        *NumberOfSignatures = numberOfSignatures;\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhFreeVerifySignatures(\n    _In_opt_ PCERT_CONTEXT *Signatures,\n    _In_ ULONG NumberOfSignatures\n    )\n{\n    if (Signatures)\n    {\n        for (ULONG i = 0; i < NumberOfSignatures; i++)\n            CertFreeCertificateContext_I(Signatures[i]);\n\n        PhFree(Signatures);\n    }\n}\n\nPPH_STRING PhpGetCertNameString(\n    _In_ PCERT_NAME_BLOB Blob\n    )\n{\n    PPH_STRING string;\n    ULONG bufferSize;\n\n    // CertNameToStr doesn't give us the correct buffer size unless we don't provide a buffer at\n    // all.\n    bufferSize = CertNameToStr_I(\n        X509_ASN_ENCODING,\n        Blob,\n        CERT_X500_NAME_STR,\n        NULL,\n        0\n        );\n\n    string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR));\n    CertNameToStr_I(\n        X509_ASN_ENCODING,\n        Blob,\n        CERT_X500_NAME_STR,\n        string->Buffer,\n        bufferSize\n        );\n\n    if (string->Length > sizeof(UNICODE_NULL))\n        string->Length -= sizeof(UNICODE_NULL);\n    // PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\nPPH_STRING PhpGetX500Value(\n    _In_ PPH_STRINGREF String,\n    _In_ PPH_STRINGREF KeyName\n    )\n{\n    WCHAR keyNamePlusEqualsBuffer[10];\n    PH_STRINGREF keyNamePlusEquals;\n    SIZE_T keyNameLength;\n    PH_STRINGREF firstPart;\n    PH_STRINGREF remainingPart;\n\n    keyNameLength = KeyName->Length / sizeof(WCHAR);\n    assert(!(keyNameLength > sizeof(keyNamePlusEquals) / sizeof(WCHAR) - 1));\n    keyNamePlusEquals.Buffer = keyNamePlusEqualsBuffer;\n    keyNamePlusEquals.Length = (keyNameLength + 1) * sizeof(WCHAR);\n\n    memcpy(keyNamePlusEquals.Buffer, KeyName->Buffer, KeyName->Length);\n    keyNamePlusEquals.Buffer[keyNameLength] = L'=';\n\n    // Find \"Key=\".\n\n    if (!PhSplitStringRefAtString(String, &keyNamePlusEquals, FALSE, &firstPart, &remainingPart))\n        return NULL;\n    if (remainingPart.Length == 0)\n        return NULL;\n\n    // Is the value quoted? If so, return the part inside the quotes.\n    if (remainingPart.Buffer[0] == L'\"')\n    {\n        PhSkipStringRef(&remainingPart, sizeof(WCHAR));\n\n        if (!PhSplitStringRefAtChar(&remainingPart, L'\"', &firstPart, &remainingPart))\n            return NULL;\n\n        return PhCreateString2(&firstPart);\n    }\n    else\n    {\n        PhSplitStringRefAtChar(&remainingPart, L',', &firstPart, &remainingPart);\n\n        return PhCreateString2(&firstPart);\n    }\n}\n\nPPH_STRING PhGetSignerNameFromCertificate(\n    _In_ PCERT_CONTEXT Certificate\n    )\n{\n    PCERT_INFO certInfo;\n    PH_STRINGREF keyName;\n    PPH_STRING name;\n    PPH_STRING value;\n\n    // Cert context -> Cert info\n\n    certInfo = Certificate->pCertInfo;\n\n    if (!certInfo)\n        return NULL;\n\n    // Cert info subject -> Subject X.500 string\n\n    name = PhpGetCertNameString(&certInfo->Subject);\n\n    // Subject X.500 string -> CN or OU value\n\n    PhInitializeStringRef(&keyName, L\"CN\");\n    value = PhpGetX500Value(&name->sr, &keyName);\n\n    if (!value)\n    {\n        PhInitializeStringRef(&keyName, L\"OU\");\n        value = PhpGetX500Value(&name->sr, &keyName);\n    }\n\n    PhDereferenceObject(name);\n\n    return value;\n}\n\nNTSTATUS PhGetSystemComponentFromCertificate(\n    _In_ PCERT_CONTEXT Certificate\n    )\n{\n    UCHAR usageBuffer[256];\n    ULONG usageLength = sizeof(usageBuffer);\n    PCERT_ENHKEY_USAGE usage = (PCERT_ENHKEY_USAGE)usageBuffer;\n\n    if (!CertGetEnhancedKeyUsage_I(Certificate, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &usageLength))\n        return PhGetLastWin32ErrorAsNtStatus();\n\n    for (ULONG i = 0; i < usage->cUsageIdentifier; i++)\n    {\n        if (PhEqualBytesZ(usage->rgpszUsageIdentifier[i], szOID_NT5_CRYPTO, FALSE)) // Windows System Component Verification (dmex)\n        {\n            return STATUS_SUCCESS;\n        }\n    }\n\n    return STATUS_NOT_FOUND;\n}\n\nPH_STRINGREF PhVerifyResultToStringRef(\n    _In_ VERIFY_RESULT Result\n    )\n{\n    static CONST PH_STRINGREF Results[] =\n    {\n        { 0, NULL },\n        PH_STRINGREF_INIT(L\"No signature\"),\n        PH_STRINGREF_INIT(L\"Trusted\"),\n        PH_STRINGREF_INIT(L\"Expired certificate\"),\n        PH_STRINGREF_INIT(L\"Revoked certificate\"),\n        PH_STRINGREF_INIT(L\"Not trusted\"),\n        PH_STRINGREF_INIT(L\"Security policy failure\"),\n        PH_STRINGREF_INIT(L\"Invalid hash\"),\n    };\n\n    if (Result < RTL_NUMBER_OF(Results))\n        return Results[Result];\n    else\n        return Results[0];\n}\n\n/**\n * Verifies a file's digital signature.\n *\n * \\param FileName A file name.\n * \\param SignerName A variable which receives a pointer to a string containing the signer name. You\n * must free the string using PhDereferenceObject() when you no longer need it. Note that the signer\n * name may be NULL if it is not valid.\n *\n * \\return A VERIFY_RESULT value.\n */\nVERIFY_RESULT PhVerifyFile(\n    _In_ PCWSTR FileName,\n    _Out_opt_ PPH_STRING *SignerName\n    )\n{\n    PH_VERIFY_FILE_INFO info = { 0 };\n    HANDLE fileHandle;\n    VERIFY_RESULT verifyResult;\n    PCERT_CONTEXT *signatures;\n    ULONG numberOfSignatures;\n\n    if (!NT_SUCCESS(PhCreateFileWin32(\n        &fileHandle,\n        FileName,\n        FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        )))\n    {\n        if (SignerName)\n            *SignerName = NULL;\n\n        return VrUnknown;\n    }\n\n    info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS;\n    info.FileHandle = fileHandle;\n\n    if (NT_SUCCESS(PhVerifyFileEx(&info, &verifyResult, &signatures, &numberOfSignatures)))\n    {\n        if (SignerName)\n        {\n            *SignerName = NULL;\n\n            if (numberOfSignatures != 0)\n                *SignerName = PhGetSignerNameFromCertificate(signatures[0]);\n        }\n\n        PhFreeVerifySignatures(signatures, numberOfSignatures);\n\n        NtClose(fileHandle);\n\n        return verifyResult;\n    }\n    else\n    {\n        if (SignerName)\n            *SignerName = NULL;\n\n        NtClose(fileHandle);\n\n        return VrUnknown;\n    }\n}\n\nBOOLEAN PhVerifyFileIsChainedToMicrosoft(\n    _In_ PCPH_STRINGREF FileName,\n    _In_ BOOLEAN NativeFileName\n    )\n{\n    BOOLEAN result = FALSE;\n    PH_VERIFY_FILE_INFO info = { 0 };\n    HANDLE fileHandle;\n    VERIFY_RESULT verifyResult;\n    PCERT_CONTEXT *signatures;\n    ULONG numberOfSignatures;\n\n    if (NativeFileName)\n    {\n        if (!NT_SUCCESS(PhCreateFile(\n            &fileHandle,\n            FileName,\n            FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            )))\n        {\n            return FALSE;\n        }\n    }\n    else\n    {\n        if (!NT_SUCCESS(PhCreateFileWin32(\n            &fileHandle,\n            PhGetStringRefZ(FileName),\n            FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            )))\n        {\n            return FALSE;\n        }\n    }\n\n    info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS;\n    info.FileHandle = fileHandle;\n\n    if (NT_SUCCESS(PhVerifyFileEx(&info, &verifyResult, &signatures, &numberOfSignatures)))\n    {\n        if (verifyResult == VrTrusted && numberOfSignatures != 0)\n        {\n            result = PhIsChainedToMicrosoft(\n                signatures[0],\n                signatures[0]->hCertStore,\n                FALSE\n                );\n        }\n\n        PhFreeVerifySignatures(signatures, numberOfSignatures);\n    }\n\n    NtClose(fileHandle);\n\n    return result;\n}\n\n_Function_class_(PH_HASHTABLE_EQUAL_FUNCTION)\nBOOLEAN PhpVerifyCacheHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_VERIFY_CACHE_ENTRY entry1 = Entry1;\n    PPH_VERIFY_CACHE_ENTRY entry2 = Entry2;\n\n    return entry1->SequenceNumber == entry2->SequenceNumber &&\n        PhEqualString(entry1->FileName, entry2->FileName, FALSE);\n}\n\n_Function_class_(PH_HASHTABLE_HASH_FUNCTION)\nULONG PhpVerifyCacheHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_VERIFY_CACHE_ENTRY entry = Entry;\n\n    return PhHashInt64(entry->SequenceNumber) ^\n        PhHashStringRefEx(&entry->FileName->sr, FALSE, PH_STRING_HASH_XXH32);\n}\n\nVOID PhFlushVerifyCache(\n    VOID\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_VERIFY_CACHE_ENTRY entry;\n\n    if (!PhpVerifyCacheHashTable)\n        return;\n\n    PhAcquireQueuedLockExclusive(&PhpVerifyCacheLock);\n\n    PhBeginEnumHashtable(PhpVerifyCacheHashTable, &enumContext);\n\n    while (entry = PhNextEnumHashtable(&enumContext))\n    {\n        if (entry->FileName)\n            PhDereferenceObject(entry->FileName);\n        if (entry->VerifySignerName)\n            PhDereferenceObject(entry->VerifySignerName);\n    }\n\n    PhDereferenceObject(PhpVerifyCacheHashTable);\n    PhpVerifyCacheHashTable = PhCreateHashtable(\n        sizeof(PH_VERIFY_CACHE_ENTRY),\n        PhpVerifyCacheHashtableEqualFunction,\n        PhpVerifyCacheHashtableHashFunction,\n        100\n        );\n\n    PhReleaseQueuedLockExclusive(&PhpVerifyCacheLock);\n}\n\nVERIFY_RESULT PhVerifyFileWithAdditionalCatalog(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _In_opt_ PPH_STRING PackageFullName,\n    _Out_opt_ PPH_STRING *SignerName\n    )\n{\n    static CONST PH_STRINGREF codeIntegrityFileName = PH_STRINGREF_INIT(L\"\\\\AppxMetadata\\\\CodeIntegrity.cat\");\n    VERIFY_RESULT result;\n    PPH_STRING additionalCatalogFileName = NULL;\n    PCERT_CONTEXT *signatures;\n    ULONG numberOfSignatures;\n\n    if (PackageFullName)\n    {\n        PPH_STRING packagePath;\n\n        if (packagePath = PhGetPackagePath(PackageFullName))\n        {\n            additionalCatalogFileName = PhConcatStringRef2(&packagePath->sr, &codeIntegrityFileName);\n            PhDereferenceObject(packagePath);\n        }\n    }\n\n    if (additionalCatalogFileName)\n    {\n        Information->NumberOfCatalogFileNames = 1;\n        Information->CatalogFileNames = &additionalCatalogFileName->Buffer;\n    }\n\n    if (!NT_SUCCESS(PhVerifyFileEx(Information, &result, &signatures, &numberOfSignatures)))\n    {\n        result = VrUnknown;\n        signatures = NULL;\n        numberOfSignatures = 0;\n    }\n\n    if (additionalCatalogFileName)\n        PhDereferenceObject(additionalCatalogFileName);\n\n    if (SignerName)\n    {\n        if (numberOfSignatures != 0)\n            *SignerName = PhGetSignerNameFromCertificate(signatures[0]);\n        else\n            *SignerName = NULL;\n    }\n\n    PhFreeVerifySignatures(signatures, numberOfSignatures);\n\n    return result;\n}\n\n/**\n * Verifies a file's digital signature, using a cached result if possible.\n *\n * \\param FileName A file name.\n * \\param PackageFullName An associated package name.\n * \\param SignerName A variable which receives a pointer to a string containing the signer name. You\n * must free the string using PhDereferenceObject() when you no longer need it. Note that the signer\n * name may be NULL if it is not valid.\n * \\param NativeFileName Specify TRUE if the file name is a native path.\n * \\param CachedOnly Specify TRUE to fail the function when no cached result exists.\n *\n * \\return A VERIFY_RESULT value.\n */\nVERIFY_RESULT PhVerifyFileCached(\n    _In_ PPH_STRING FileName,\n    _In_opt_ PPH_STRING PackageFullName,\n    _Out_opt_ PPH_STRING *SignerName,\n    _In_ BOOLEAN NativeFileName,\n    _In_ BOOLEAN CachedOnly\n    )\n{\n#ifdef PH_ENABLE_VERIFY_CACHE\n    HANDLE fileHandle;\n    LONGLONG sequenceNumber = 0;\n\n    if (PhBeginInitOnce(&PhpVerifyInitOnce))\n    {\n        PhpVerifyInitialization();\n        PhEndInitOnce(&PhpVerifyInitOnce);\n    }\n\n    if (!PhpVerifyCacheHashTable)\n    {\n        if (SignerName) *SignerName = NULL;\n        return VrUnknown;\n    }\n\n    if (NativeFileName)\n    {\n        if (!NT_SUCCESS(PhCreateFile(\n            &fileHandle,\n            &FileName->sr,\n            FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            )))\n        {\n            if (SignerName) *SignerName = NULL;\n            return VrUnknown;\n        }\n    }\n    else\n    {\n        if (!NT_SUCCESS(PhCreateFileWin32(\n            &fileHandle,\n            FileName->Buffer,\n            FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            )))\n        {\n            if (SignerName) *SignerName = NULL;\n            return VrUnknown;\n        }\n    }\n\n    PhSetFileIoPriorityHint(fileHandle, IoPriorityVeryLow);\n\n    {\n        PPH_VERIFY_CACHE_ENTRY entry;\n        PH_VERIFY_CACHE_ENTRY lookupEntry;\n\n        PhGetFileUsn(fileHandle, &sequenceNumber);\n        lookupEntry.FileName = FileName;\n        lookupEntry.SequenceNumber = sequenceNumber;\n\n        PhAcquireQueuedLockShared(&PhpVerifyCacheLock);\n\n        if (entry = PhFindEntryHashtable(PhpVerifyCacheHashTable, &lookupEntry))\n        {\n            VERIFY_RESULT verifyResult = entry->VerifyResult;\n\n            if (SignerName)\n                PhSetReference(SignerName, entry->VerifySignerName);\n\n            PhReleaseQueuedLockShared(&PhpVerifyCacheLock);\n\n            NtClose(fileHandle);\n\n            return verifyResult;\n        }\n\n        PhReleaseQueuedLockShared(&PhpVerifyCacheLock);\n    }\n\n    {\n        VERIFY_RESULT result;\n        PPH_STRING signerName;\n\n        if (!CachedOnly)\n        {\n            PH_VERIFY_FILE_INFO info;\n\n            memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO));\n            info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS;\n            info.FileHandle = fileHandle;\n            result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName);\n\n            if (result != VrTrusted)\n                PhClearReference(&signerName);\n        }\n        else\n        {\n            result = VrUnknown;\n            signerName = NULL;\n        }\n\n        if (!CachedOnly) // if (result != VrUnknown)\n        {\n            PH_VERIFY_CACHE_ENTRY newEntry;\n\n            newEntry.FileName = FileName;\n            newEntry.SequenceNumber = sequenceNumber;\n            newEntry.VerifyResult = result;\n            newEntry.VerifySignerName = signerName;\n\n            PhAcquireQueuedLockExclusive(&PhpVerifyCacheLock);\n\n            if (PhAddEntryHashtable(PhpVerifyCacheHashTable, &newEntry))\n            {\n                // We successfully added the cache entry. Add references.\n                PhReferenceObject(FileName);\n\n                if (signerName)\n                    PhReferenceObject(signerName);\n            }\n\n            PhReleaseQueuedLockExclusive(&PhpVerifyCacheLock);\n        }\n\n        if (SignerName)\n        {\n            *SignerName = signerName;\n        }\n        else\n        {\n            if (signerName)\n                PhDereferenceObject(signerName);\n        }\n\n        NtClose(fileHandle);\n\n        return result;\n    }\n#else\n    VERIFY_RESULT result;\n    PPH_STRING signerName;\n    PH_VERIFY_FILE_INFO info;\n\n    memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO));\n    info.FileName = FileName->Buffer;\n    info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS;\n    result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName);\n\n    if (result != VrTrusted)\n        PhClearReference(&signerName);\n\n    if (SignerName)\n    {\n        *SignerName = signerName;\n    }\n    else\n    {\n        if (signerName)\n            PhDereferenceObject(signerName);\n    }\n\n    return result;\n#endif\n}\n\n#if (PH_VERIFY_FUTURE)\nVERIFY_RESULT PhpSignatureStateToVerifyResult(\n    _In_ LONG Status\n    )\n{\n    switch (Status)\n    {\n    case SIGNATURE_STATE_VALID:\n    case SIGNATURE_STATE_TRUSTED:\n        return VrTrusted;\n    case SIGNATURE_STATE_UNSIGNED_MISSING:\n        return VrNoSignature; // TRUST_E_NOSIGNATURE\n    case SIGNATURE_STATE_UNSIGNED_UNSUPPORTED:\n        return VrNoSignature; // TRUST_E_NOSIGNATURE\n    case SIGNATURE_STATE_UNSIGNED_POLICY:\n        return VrNoSignature; // TRUST_E_NOSIGNATURE\n    case SIGNATURE_STATE_INVALID_CORRUPT:\n        return VrBadSignature; // TRUST_E_BAD_DIGEST\n    case SIGNATURE_STATE_INVALID_POLICY:\n        return VrSecuritySettings; // CRYPT_E_BAD_MSG\n    case SIGNATURE_STATE_UNTRUSTED:\n        return VrDistrust; // TRUST_E_EXPLICIT_DISTRUST\n    default:\n        return VrSecuritySettings;\n    }\n}\n\nVERIFY_RESULT PhVerifyFileSignatureInfo(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _In_opt_ PCWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _Out_ PCERT_CONTEXT** Signatures,\n    _Out_ PULONG NumberOfSignatures\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static _WTGetSignatureInfo WTGetSignatureInfo_I = NULL;\n    VERIFY_RESULT verifyResult = VrNoSignature;\n    SIGNATURE_INFO signatureInfo = { sizeof(SIGNATURE_INFO) };\n    PVOID certificateContext = NULL;\n    HANDLE verifyTrustStateData = NULL;\n    HRESULT status;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        PVOID wintrust;\n\n        if (wintrust = PhLoadLibrary(L\"wintrust.dll\"))\n        {\n            WTGetSignatureInfo_I = PhGetDllBaseProcedureAddress(wintrust, \"WTGetSignatureInfo\", 0);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!WTGetSignatureInfo_I)\n    {\n        *Signatures = NULL;\n        *NumberOfSignatures = 0;\n        return VrUnknown;\n    }\n\n    status = WTGetSignatureInfo_I(\n        FileName,\n        FileHandle,\n        SIF_AUTHENTICODE_SIGNED | SIF_CATALOG_SIGNED | SIF_BASE_VERIFICATION,\n        &signatureInfo,\n        &certificateContext,\n        &verifyTrustStateData\n        );\n\n    if (!SUCCEEDED(status))\n    {\n        *Signatures = NULL;\n        *NumberOfSignatures = 0;\n        return VrUnknown;\n    }\n\n    verifyResult = PhpSignatureStateToVerifyResult(signatureInfo.nSignatureState);\n    PhpGetSignaturesFromStateData(verifyTrustStateData, Signatures, NumberOfSignatures);\n\n    if (status == S_OK && verifyTrustStateData && (Information->Flags & PH_VERIFY_VIEW_PROPERTIES))\n        PhpViewSignerInfo(Information, verifyTrustStateData);\n\n    if (verifyTrustStateData && WinVerifyTrust_I)\n    {\n        WINTRUST_DATA verifyTrustData;\n\n        memset(&verifyTrustData, 0, sizeof(WINTRUST_DATA));\n        verifyTrustData.cbStruct = sizeof(WINTRUST_DATA);\n        verifyTrustData.dwUIChoice = WTD_UI_NONE;\n        verifyTrustData.dwUnionChoice = WTD_CHOICE_BLOB;\n        verifyTrustData.dwStateAction = WTD_STATEACTION_CLOSE;\n        verifyTrustData.hWVTStateData = verifyTrustStateData;\n\n        WinVerifyTrust_I(INVALID_HANDLE_VALUE, &WinTrustActionGenericVerifyV2, &verifyTrustData);\n    }\n\n    if (certificateContext && CertFreeCertificateContext_I)\n    {\n        CertFreeCertificateContext_I(certificateContext);\n    }\n\n    return verifyResult;\n}\n\nPPH_STRING PhGetProgramNameFromMessage(\n    _In_ HCRYPTMSG CryptMsgHandle\n    )\n{\n    PPH_STRING signerName = NULL;\n    ULONG signerInfoLength = 0;\n    PCMSG_SIGNER_INFO signerInfo;\n\n    if (!CryptMsgGetParam(\n        CryptMsgHandle,\n        CMSG_SIGNER_INFO_PARAM,\n        0,\n        NULL,\n        &signerInfoLength\n        ))\n    {\n        return NULL;\n    }\n\n    signerInfo = PhAllocate(signerInfoLength);\n\n    if (!CryptMsgGetParam(\n        CryptMsgHandle,\n        CMSG_SIGNER_INFO_PARAM,\n        0,\n        signerInfo,\n        &signerInfoLength\n        ))\n    {\n        PhFree(signerInfo);\n        return NULL;\n    }\n\n    for (ULONG i = 0; i < signerInfo->AuthAttrs.cAttr; i++)\n    {\n        if (PhEqualBytesZ(SPC_SP_OPUS_INFO_OBJID, signerInfo->AuthAttrs.rgAttr[i].pszObjId, TRUE))\n        {\n            ULONG opusInfoLength = 0;\n            PSPC_SP_OPUS_INFO opusInfo;\n\n            if (!CryptDecodeObjectEx(\n                X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,\n                SPC_SP_OPUS_INFO_OBJID,\n                signerInfo->AuthAttrs.rgAttr[i].rgValue[0].pbData,\n                signerInfo->AuthAttrs.rgAttr[i].rgValue[0].cbData,\n                CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG,\n                NULL,\n                &opusInfo,\n                &opusInfoLength\n                ))\n            {\n                goto CleanupExit;\n            }\n\n            if (opusInfo->pwszProgramName)\n            {\n                signerName = PhCreateString(opusInfo->pwszProgramName);\n            }\n\n            LocalFree(opusInfo);\n            break;\n        }\n    }\n\nCleanupExit:\n    PhFree(signerInfo);\n\n    return signerName;\n}\n\n// rev from WTHelperIsChainedToMicrosoftFromStateData (dmex)\nBOOLEAN PhIsChainedToMicrosoftFromStateData(\n    _In_ HANDLE StateData,\n    _In_ BOOLEAN IncludeMicrosoftTestRootCerts\n    )\n{\n    BOOLEAN status = FALSE;\n    PCRYPT_PROVIDER_DATA provData;\n    PCRYPT_PROVIDER_SGNR provSigner;\n    HCERTSTORE cryptStoreHandle;\n\n    provData = PhGetCryptProviderDataFromStateData(StateData);\n\n    if (!provData)\n        return FALSE;\n\n    provSigner = PhGetCryptProviderSignerFromChain(provData, 0, FALSE, 0);\n\n    if (!provSigner)\n        return FALSE;\n\n    cryptStoreHandle = CertOpenStore(\n        CERT_STORE_PROV_MSG,\n        provData->dwEncoding,\n        0,\n        0,\n        provData->hMsg\n        );\n\n    if (!cryptStoreHandle)\n        return FALSE;\n\n    status = PhIsChainedToMicrosoft(\n        provSigner->pasCertChain->pCert,\n        cryptStoreHandle,\n        IncludeMicrosoftTestRootCerts\n        );\n\n    CertCloseStore(cryptStoreHandle, 0);\n\n    return status;\n}\n\n// rev from ChainToMicrosoftRoot (dmex)\nBOOLEAN PhVerifyCertificateChainToMicrosoftRoot(\n    _In_ PCCERT_CHAIN_CONTEXT ChainContext,\n    _In_ BOOLEAN CheckOsBinary\n    )\n{\n    CERT_CHAIN_POLICY_PARA policyPara = { sizeof(CERT_CHAIN_POLICY_PARA) };\n    CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(CERT_CHAIN_POLICY_STATUS) };\n\n    if (CheckOsBinary)\n    {\n        SetFlag(policyPara.dwFlags, MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG); // MicrosoftWindows vs MicrosoftCorporation\n    }\n\n    if (CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_MICROSOFT_ROOT, ChainContext, &policyPara, &policyStatus))\n    {\n        if (policyStatus.dwError == ERROR_SUCCESS)\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n// rev from IsMicrosoftRootChain (dmex)\nBOOLEAN PhVerifyCertificateIsMicrosoftRootChain(\n    _In_ PCCERT_CHAIN_CONTEXT ChainContext\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static BOOLEAN InsiderBuild = FALSE;\n    CERT_CHAIN_POLICY_PARA policyPara = { sizeof(CERT_CHAIN_POLICY_PARA) };\n    CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(CERT_CHAIN_POLICY_STATUS) };\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        SYSTEM_CODEINTEGRITY_INFORMATION integrityInfo;\n\n        if (NT_SUCCESS(NtQuerySystemInformation(\n            SystemCodeIntegrityInformation,\n            &integrityInfo,\n            sizeof(SYSTEM_CODEINTEGRITY_INFORMATION),\n            NULL\n            )))\n        {\n            if (BooleanFlagOn(integrityInfo.CodeIntegrityOptions, CODEINTEGRITY_OPTION_FLIGHTING_ENABLED) ||\n                BooleanFlagOn(integrityInfo.CodeIntegrityOptions, CODEINTEGRITY_OPTION_TEST_BUILD))\n            {\n                InsiderBuild = TRUE;\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (InsiderBuild)\n    {\n        policyPara.dwFlags = MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG; // required\n    }\n\n    if (CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_MICROSOFT_ROOT, ChainContext, &policyPara, &policyStatus))\n    {\n        if (policyStatus.dwError == ERROR_SUCCESS)\n            return TRUE;\n    }\n\n    return FALSE;\n}\n\n#include <mssip.h>\n#pragma comment(lib, \"crypt32.lib\")\n\n#include <pshpack1.h>\ntypedef struct _SPC_PE_IMAGE_PAGE_HASHES_V1\n{\n    ULONG PageOffset;\n    BYTE PageHash[20]; // SHA-1\n} SPC_PE_IMAGE_PAGE_HASHES_V1, *PSPC_PE_IMAGE_PAGE_HASHES_V1;\n\ntypedef struct _SPC_PE_IMAGE_PAGE_HASHES_V2\n{\n    ULONG PageOffset;\n    BYTE PageHash[32]; // SHA-256\n} SPC_PE_IMAGE_PAGE_HASHES_V2, *PSPC_PE_IMAGE_PAGE_HASHES_V2;\n#include <poppack.h>\n\n// Based on peview PvEnumSpcAuthenticodePageHashes (dmex)\nPPH_LIST PhEnumSpcAuthenticodePageHashesFromStateData(\n    _In_ HANDLE StateData\n    )\n{\n    PPH_LIST pageHashList = NULL;\n    PCRYPT_PROVIDER_DATA provData;\n    PPROVDATA_SIP provSipData;\n    PSIP_INDIRECT_DATA indirectData;\n    PSPC_PE_IMAGE_DATA spcPeImageDataBuffer = NULL;\n    ULONG spcPeImageDataLength = 0;\n\n    // WintrustSetDefaultIncludePEPageHashes(TRUE);\n\n    if (!(provData = PhGetCryptProviderDataFromStateData(StateData)))\n        return FALSE;\n    if (!(provSipData = provData->pPDSip))\n        return FALSE;\n    if (!(indirectData = provSipData->psIndirectData))\n        return FALSE;\n\n    if (!PhEqualBytesZ(indirectData->Data.pszObjId, SPC_PE_IMAGE_DATA_OBJID, FALSE))\n        return FALSE;\n\n    if (!CryptDecodeObjectEx(\n        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,\n        SPC_PE_IMAGE_DATA_STRUCT,\n        indirectData->Data.Value.pbData,\n        indirectData->Data.Value.cbData,\n        CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG,\n        NULL,\n        &spcPeImageDataBuffer,\n        &spcPeImageDataLength\n        ))\n    {\n        return FALSE;\n    }\n\n    if (\n        spcPeImageDataBuffer->pFile->dwLinkChoice == SPC_MONIKER_LINK_CHOICE &&\n        RtlEqualMemory(spcPeImageDataBuffer->pFile->Moniker.ClassId, (SPC_UUID)SpcSerializedObjectAttributesClassId, sizeof((SPC_UUID)SpcSerializedObjectAttributesClassId))\n        )\n    {\n        ULONG spcSerializedObjectAttributesLength = 0;\n        PCRYPT_ATTRIBUTES spcSerializedObjectAttributesBuffer = NULL;\n\n        if (CryptDecodeObjectEx(\n            X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,\n            PKCS_ATTRIBUTES,\n            spcPeImageDataBuffer->pFile->Moniker.SerializedData.pbData,\n            spcPeImageDataBuffer->pFile->Moniker.SerializedData.cbData,\n            CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG,\n            NULL,\n            &spcSerializedObjectAttributesBuffer,\n            &spcSerializedObjectAttributesLength\n            ))\n        {\n            for (ULONG i = 0; i < spcSerializedObjectAttributesBuffer->cAttr; i++)\n            {\n                CRYPT_ATTRIBUTE spcSerializedObjectBuffer = spcSerializedObjectAttributesBuffer->rgAttr[i];\n                PCRYPT_DATA_BLOB spcImagePageHashesBuffer = NULL;\n                ULONG spcImagePageHashesLength = 0;\n\n                // for (ULONG j = 0; j < spcSerializedObjectBuffer.cValue; j++)\n\n                if (CryptDecodeObjectEx(\n                    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,\n                    X509_OCTET_STRING,\n                    spcSerializedObjectBuffer.rgValue->pbData,\n                    spcSerializedObjectBuffer.rgValue->cbData,\n                    CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG,\n                    NULL,\n                    &spcImagePageHashesBuffer,\n                    &spcImagePageHashesLength\n                    ))\n                {\n                    if (PhEqualBytesZ(spcSerializedObjectBuffer.pszObjId, SPC_PE_IMAGE_PAGE_HASHES_V1_OBJID, FALSE))\n                    {\n                        ULONG count = spcImagePageHashesBuffer->cbData / sizeof(SPC_PE_IMAGE_PAGE_HASHES_V1);\n                        pageHashList = PhCreateList(count);\n\n                        for (ULONG k = 0; k < count; k++)\n                        {\n                            PSPC_PE_IMAGE_PAGE_HASHES_V1 entry = PTR_ADD_OFFSET(spcImagePageHashesBuffer->pbData, sizeof(SPC_PE_IMAGE_PAGE_HASHES_V1) * k);\n                            PSPC_PE_IMAGE_PAGE_HASHES_V2 thunk;\n\n                            thunk = PhAllocateZero(sizeof(SPC_PE_IMAGE_PAGE_HASHES_V2));\n                            thunk->PageOffset = entry->PageOffset;\n                            memcpy_s(thunk->PageHash, sizeof(thunk->PageHash), entry->PageHash, sizeof(entry->PageHash));\n                            PhAddItemList(pageHashList, thunk);\n                        }\n                    }\n                    else if (PhEqualBytesZ(spcSerializedObjectBuffer.pszObjId, SPC_PE_IMAGE_PAGE_HASHES_V2_OBJID, FALSE))\n                    {\n                        ULONG count = spcImagePageHashesBuffer->cbData / sizeof(SPC_PE_IMAGE_PAGE_HASHES_V2);\n                        pageHashList = PhCreateList(count);\n\n                        for (ULONG k = 0; k < count; k++)\n                        {\n                            PSPC_PE_IMAGE_PAGE_HASHES_V2 entry = PTR_ADD_OFFSET(spcImagePageHashesBuffer->pbData, sizeof(SPC_PE_IMAGE_PAGE_HASHES_V2) * k);\n\n                            PhAddItemList(pageHashList, PhAllocateCopy(entry, sizeof(SPC_PE_IMAGE_PAGE_HASHES_V2)));\n                        }\n                    }\n\n                    LocalFree(spcImagePageHashesBuffer);\n                }\n            }\n\n            LocalFree(spcSerializedObjectAttributesBuffer);\n        }\n    }\n\n    LocalFree(spcPeImageDataBuffer);\n\n    return pageHashList;\n}\n\n#endif\n"
  },
  {
    "path": "phlib/workqueue.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     wj32    2009-2016\n *\n */\n\n#include <phbase.h>\n#include <workqueue.h>\n\n#include <phintrnl.h>\n#include <phnativeinl.h>\n#include <phnative.h>\n\n#include <workqueuep.h>\n\nstatic PH_INITONCE PhWorkQueueInitOnce = PH_INITONCE_INIT;\nstatic PH_FREE_LIST PhWorkQueueItemFreeList;\nstatic PH_INITONCE PhGlobalWorkQueueInitOnce = PH_INITONCE_INIT;\nstatic PH_WORK_QUEUE PhGlobalWorkQueue;\n#ifdef DEBUG\nPPH_LIST PhDbgWorkQueueList;\nPH_QUEUED_LOCK PhDbgWorkQueueListLock = PH_QUEUED_LOCK_INIT;\n#endif\n\n/**\n * Initializes a work queue.\n *\n * \\param WorkQueue A work queue object.\n * \\param MinimumThreads The suggested minimum number of threads to keep alive, even when there is\n * no work to be performed.\n * \\param MaximumThreads The suggested maximum number of threads to create.\n * \\param NoWorkTimeout The number of milliseconds after which threads without work will terminate.\n */\nVOID PhInitializeWorkQueue(\n    _Out_ PPH_WORK_QUEUE WorkQueue,\n    _In_ ULONG MinimumThreads,\n    _In_ ULONG MaximumThreads,\n    _In_ ULONG NoWorkTimeout\n    )\n{\n    if (PhBeginInitOnce(&PhWorkQueueInitOnce))\n    {\n        PhInitializeFreeList(&PhWorkQueueItemFreeList, sizeof(PH_WORK_QUEUE_ITEM), 32);\n#ifdef DEBUG\n        PhDbgWorkQueueList = PhCreateList(4);\n#endif\n\n        PhEndInitOnce(&PhWorkQueueInitOnce);\n    }\n\n    PhInitializeRundownProtection(&WorkQueue->RundownProtect);\n    WorkQueue->Terminating = FALSE;\n\n    InitializeListHead(&WorkQueue->QueueListHead);\n    PhInitializeQueuedLock(&WorkQueue->QueueLock);\n    PhInitializeCondition(&WorkQueue->QueueEmptyCondition);\n\n    WorkQueue->MinimumThreads = MinimumThreads;\n    WorkQueue->MaximumThreads = MaximumThreads;\n    WorkQueue->NoWorkTimeout = NoWorkTimeout;\n\n    PhInitializeQueuedLock(&WorkQueue->StateLock);\n\n    WorkQueue->SemaphoreHandle = NULL;\n    WorkQueue->CurrentThreads = 0;\n    WorkQueue->BusyCount = 0;\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock);\n    PhAddItemList(PhDbgWorkQueueList, WorkQueue);\n    PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock);\n#endif\n}\n\n/**\n * Frees resources used by a work queue.\n *\n * \\param WorkQueue A work queue object.\n */\nVOID PhDeleteWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    )\n{\n    PLIST_ENTRY listEntry;\n    PPH_WORK_QUEUE_ITEM workQueueItem;\n#ifdef DEBUG\n    ULONG index;\n#endif\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock);\n    if ((index = PhFindItemList(PhDbgWorkQueueList, WorkQueue)) != ULONG_MAX)\n        PhRemoveItemList(PhDbgWorkQueueList, index);\n    PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock);\n#endif\n\n    // Wait for all worker threads to exit.\n\n    WorkQueue->Terminating = TRUE;\n    MemoryBarrier();\n\n    if (WorkQueue->SemaphoreHandle)\n        NtReleaseSemaphore(WorkQueue->SemaphoreHandle, WorkQueue->CurrentThreads, NULL);\n\n    PhWaitForRundownProtection(&WorkQueue->RundownProtect);\n\n    // Free all un-executed work items.\n\n    listEntry = WorkQueue->QueueListHead.Flink;\n\n    while (listEntry != &WorkQueue->QueueListHead)\n    {\n        workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry);\n        listEntry = listEntry->Flink;\n        PhpDestroyWorkQueueItem(workQueueItem);\n    }\n\n    if (WorkQueue->SemaphoreHandle)\n        NtClose(WorkQueue->SemaphoreHandle);\n}\n\n/**\n * Waits for all queued work items to be executed.\n *\n * \\param WorkQueue A work queue object.\n */\nVOID PhWaitForWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    )\n{\n    PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock);\n\n    while (!IsListEmpty(&WorkQueue->QueueListHead))\n        PhWaitForCondition(&WorkQueue->QueueEmptyCondition, &WorkQueue->QueueLock, NULL);\n\n    PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock);\n}\n\n/**\n * Queues a work item to a work queue.\n *\n * \\param WorkQueue A work queue object.\n * \\param Function A function to execute.\n * \\param Context A user-defined value to pass to the function.\n */\nVOID PhQueueItemWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue,\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context\n    )\n{\n    PhQueueItemWorkQueueEx(WorkQueue, Function, Context, NULL, NULL);\n}\n\n/**\n * Queues a work item to a work queue.\n *\n * \\param WorkQueue A work queue object.\n * \\param Function A function to execute.\n * \\param Context A user-defined value to pass to the function.\n * \\param DeleteFunction A callback function that is executed when the work queue item is about to\n * be freed.\n * \\param Environment Execution environment parameters (e.g. priority).\n */\nVOID PhQueueItemWorkQueueEx(\n    _Inout_ PPH_WORK_QUEUE WorkQueue,\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,\n    _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    )\n{\n    PPH_WORK_QUEUE_ITEM workQueueItem;\n\n    workQueueItem = PhpCreateWorkQueueItem(Function, Context, DeleteFunction, Environment);\n\n    // Enqueue the work item.\n    PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock);\n    InsertTailList(&WorkQueue->QueueListHead, &workQueueItem->ListEntry);\n    _InterlockedIncrement(&WorkQueue->BusyCount);\n    PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock);\n    // Signal the semaphore once to let a worker thread continue.\n    NtReleaseSemaphore(PhpGetSemaphoreWorkQueue(WorkQueue), 1, NULL);\n\n    PHLIB_INC_STATISTIC(WqWorkItemsQueued);\n\n    // Check if all worker threads are currently busy, and if we can create more threads.\n    if (WorkQueue->BusyCount >= WorkQueue->CurrentThreads &&\n        WorkQueue->CurrentThreads < WorkQueue->MaximumThreads)\n    {\n        // Lock and re-check.\n        PhAcquireQueuedLockExclusive(&WorkQueue->StateLock);\n\n        if (WorkQueue->CurrentThreads < WorkQueue->MaximumThreads)\n            PhpCreateWorkQueueThread(WorkQueue);\n\n        PhReleaseQueuedLockExclusive(&WorkQueue->StateLock);\n    }\n}\n\nVOID PhInitializeWorkQueueEnvironment(\n    _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    )\n{\n    PhpGetDefaultWorkQueueEnvironment(Environment);\n}\n\n/** Returns a pointer to the default shared work queue. */\nPPH_WORK_QUEUE PhGetGlobalWorkQueue(\n    VOID\n    )\n{\n    if (PhBeginInitOnce(&PhGlobalWorkQueueInitOnce))\n    {\n        PhInitializeWorkQueue(\n            &PhGlobalWorkQueue,\n            0,\n            3,\n            1000\n            );\n        PhEndInitOnce(&PhGlobalWorkQueueInitOnce);\n    }\n\n    return &PhGlobalWorkQueue;\n}\n\nVOID PhpGetDefaultWorkQueueEnvironment(\n    _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    )\n{\n    memset(Environment, 0, sizeof(PH_WORK_QUEUE_ENVIRONMENT));\n    Environment->BasePriority = THREAD_PRIORITY_NORMAL;\n    Environment->IoPriority = IoPriorityNormal;\n    Environment->PagePriority = MEMORY_PRIORITY_NORMAL;\n    Environment->ForceUpdate = FALSE;\n}\n\nVOID PhpUpdateWorkQueueEnvironment(\n    _Inout_ PPH_WORK_QUEUE_ENVIRONMENT CurrentEnvironment,\n    _In_ PPH_WORK_QUEUE_ENVIRONMENT NewEnvironment\n    )\n{\n    if (CurrentEnvironment->BasePriority != NewEnvironment->BasePriority || NewEnvironment->ForceUpdate)\n    {\n        LONG increment;\n\n        increment = NewEnvironment->BasePriority;\n\n        if (NT_SUCCESS(PhSetThreadBasePriority(NtCurrentThread(), increment)))\n        {\n            CurrentEnvironment->BasePriority = NewEnvironment->BasePriority;\n        }\n    }\n\n    if (CurrentEnvironment->IoPriority != NewEnvironment->IoPriority || NewEnvironment->ForceUpdate)\n    {\n        IO_PRIORITY_HINT ioPriority;\n\n        ioPriority = NewEnvironment->IoPriority;\n\n        if (NT_SUCCESS(PhSetThreadIoPriority(NtCurrentThread(), ioPriority)))\n        {\n            CurrentEnvironment->IoPriority = NewEnvironment->IoPriority;\n        }\n    }\n\n    if (CurrentEnvironment->PagePriority != NewEnvironment->PagePriority || NewEnvironment->ForceUpdate)\n    {\n        ULONG pagePriority;\n\n        pagePriority = NewEnvironment->PagePriority;\n\n        if (NT_SUCCESS(PhSetThreadPagePriority(NtCurrentThread(), pagePriority)))\n        {\n            CurrentEnvironment->PagePriority = NewEnvironment->PagePriority;\n        }\n    }\n}\n\nPPH_WORK_QUEUE_ITEM PhpCreateWorkQueueItem(\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,\n    _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    )\n{\n    PPH_WORK_QUEUE_ITEM workQueueItem;\n\n    workQueueItem = PhAllocateFromFreeList(&PhWorkQueueItemFreeList);\n    workQueueItem->Function = Function;\n    workQueueItem->Context = Context;\n    workQueueItem->DeleteFunction = DeleteFunction;\n\n    if (Environment)\n        workQueueItem->Environment = *Environment;\n    else\n        PhpGetDefaultWorkQueueEnvironment(&workQueueItem->Environment);\n\n    return workQueueItem;\n}\n\nVOID PhpDestroyWorkQueueItem(\n    _In_ PPH_WORK_QUEUE_ITEM WorkQueueItem\n    )\n{\n    if (WorkQueueItem->DeleteFunction)\n        WorkQueueItem->DeleteFunction(WorkQueueItem->Function, WorkQueueItem->Context);\n\n    PhFreeToFreeList(&PhWorkQueueItemFreeList, WorkQueueItem);\n}\n\nVOID PhpExecuteWorkQueueItem(\n    _Inout_ PPH_WORK_QUEUE_ITEM WorkQueueItem\n    )\n{\n    WorkQueueItem->Function(WorkQueueItem->Context);\n}\n\nHANDLE PhpGetSemaphoreWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    )\n{\n    HANDLE semaphoreHandle;\n\n    semaphoreHandle = WorkQueue->SemaphoreHandle;\n\n    if (!semaphoreHandle)\n    {\n        OBJECT_ATTRIBUTES objectAttributes;\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            NULL,\n            OBJ_EXCLUSIVE,\n            NULL,\n            NULL\n            );\n\n        NtCreateSemaphore(\n            &semaphoreHandle,\n            SEMAPHORE_ALL_ACCESS,\n            &objectAttributes,\n            0,\n            MAXLONG\n            );\n\n        assert(semaphoreHandle);\n\n        if (_InterlockedCompareExchangePointer(\n            &WorkQueue->SemaphoreHandle,\n            semaphoreHandle,\n            NULL\n            ) != NULL)\n        {\n            // Someone else created the semaphore before we did.\n            NtClose(semaphoreHandle);\n            semaphoreHandle = WorkQueue->SemaphoreHandle;\n        }\n    }\n\n    return semaphoreHandle;\n}\n\nBOOLEAN PhpCreateWorkQueueThread(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    )\n{\n    HANDLE threadHandle;\n\n    // Make sure the structure doesn't get deleted while the thread is running.\n    if (!PhAcquireRundownProtection(&WorkQueue->RundownProtect))\n        return FALSE;\n\n    if (NT_SUCCESS(PhCreateThreadEx(\n        &threadHandle,\n        PhpWorkQueueThreadStart,\n        WorkQueue\n        )))\n    {\n        PHLIB_INC_STATISTIC(WqWorkQueueThreadsCreated);\n        WorkQueue->CurrentThreads++;\n\n        NtClose(threadHandle);\n        return TRUE;\n    }\n    else\n    {\n        PHLIB_INC_STATISTIC(WqWorkQueueThreadsCreateFailed);\n        PhReleaseRundownProtection(&WorkQueue->RundownProtect);\n        return FALSE;\n    }\n}\n\n_Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS PhpWorkQueueThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_WORK_QUEUE workQueue = (PPH_WORK_QUEUE)Parameter;\n    PH_WORK_QUEUE_ENVIRONMENT currentEnvironment;\n\n    PhInitializeAutoPool(&autoPool);\n    PhpGetDefaultWorkQueueEnvironment(&currentEnvironment);\n\n    while (TRUE)\n    {\n        NTSTATUS status;\n        HANDLE semaphoreHandle;\n        LARGE_INTEGER timeout;\n        PPH_WORK_QUEUE_ITEM workQueueItem = NULL;\n\n        // Check if we have more threads than the limit.\n        if (workQueue->CurrentThreads > workQueue->MaximumThreads)\n        {\n            BOOLEAN terminate = FALSE;\n\n            // Lock and re-check.\n            PhAcquireQueuedLockExclusive(&workQueue->StateLock);\n\n            // Check the minimum as well.\n            if (workQueue->CurrentThreads > workQueue->MaximumThreads &&\n                workQueue->CurrentThreads > workQueue->MinimumThreads)\n            {\n                workQueue->CurrentThreads--;\n                terminate = TRUE;\n            }\n\n            PhReleaseQueuedLockExclusive(&workQueue->StateLock);\n\n            if (terminate)\n                break;\n        }\n\n        semaphoreHandle = PhpGetSemaphoreWorkQueue(workQueue);\n\n        if (!workQueue->Terminating)\n        {\n            // Wait for work.\n            status = NtWaitForSingleObject(\n                semaphoreHandle,\n                FALSE,\n                PhTimeoutFromMilliseconds(&timeout, workQueue->NoWorkTimeout)\n                );\n        }\n        else\n        {\n            status = STATUS_UNSUCCESSFUL;\n        }\n\n        if (status == STATUS_WAIT_0 && !workQueue->Terminating)\n        {\n            PLIST_ENTRY listEntry;\n\n            // Dequeue the work item.\n\n            PhAcquireQueuedLockExclusive(&workQueue->QueueLock);\n\n            listEntry = RemoveHeadList(&workQueue->QueueListHead);\n\n            if (IsListEmpty(&workQueue->QueueListHead))\n                PhPulseCondition(&workQueue->QueueEmptyCondition);\n\n            PhReleaseQueuedLockExclusive(&workQueue->QueueLock);\n\n            // Make sure we got work.\n            if (listEntry != &workQueue->QueueListHead)\n            {\n                workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry);\n\n                PhpUpdateWorkQueueEnvironment(&currentEnvironment, &workQueueItem->Environment);\n                PhpExecuteWorkQueueItem(workQueueItem);\n                _InterlockedDecrement(&workQueue->BusyCount);\n\n                PhpDestroyWorkQueueItem(workQueueItem);\n            }\n        }\n        else\n        {\n            BOOLEAN terminate = FALSE;\n\n            // No work arrived before the timeout passed, or we are terminating, or some error\n            // occurred. Terminate the thread.\n\n            PhAcquireQueuedLockExclusive(&workQueue->StateLock);\n\n            if (workQueue->Terminating || workQueue->CurrentThreads > workQueue->MinimumThreads)\n            {\n                workQueue->CurrentThreads--;\n                terminate = TRUE;\n            }\n\n            PhReleaseQueuedLockExclusive(&workQueue->StateLock);\n\n            if (terminate)\n                break;\n        }\n\n        PhDrainAutoPool(&autoPool);\n    }\n\n    PhReleaseRundownProtection(&workQueue->RundownProtect);\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "phlib/wslsup.c",
    "content": "/*\n * Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n *\n * This file is part of System Informer.\n *\n * Authors:\n *\n *     dmex    2019-2025\n *\n */\n\n#include <ph.h>\n#include <wslsup.h>\n\ntypedef struct _PH_WSL_ENUM_CONTEXT\n{\n    BOOLEAN Found;\n    PPH_STRINGREF FileName;\n    PPH_STRING DistributionGuid;\n    PPH_STRING DistributionName;\n    PPH_STRING DistributionPath;\n    PPH_STRING TranslatedPath;\n} PH_WSL_ENUM_CONTEXT, *PPH_WSL_ENUM_CONTEXT;\n\n_Function_class_(PH_ENUM_KEY_CALLBACK)\nBOOLEAN NTAPI PhWslDistributionNamesCallback(\n    _In_ HANDLE RootDirectory,\n    _In_ PVOID Information,\n    _In_ PVOID Context\n    )\n{\n    PKEY_BASIC_INFORMATION information = (PKEY_BASIC_INFORMATION)Information;\n    PPH_WSL_ENUM_CONTEXT context = (PPH_WSL_ENUM_CONTEXT)Context;\n    HANDLE keyHandle;\n    PH_STRINGREF keyName;\n\n    keyName.Buffer = information->Name;\n    keyName.Length = information->NameLength;\n\n    if (NT_SUCCESS(PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        RootDirectory,\n        &keyName,\n        0\n        )))\n    {\n        PPH_STRING lxssBasePathName;\n\n        if (lxssBasePathName = PhQueryRegistryStringZ(keyHandle, L\"BasePath\"))\n        {\n            PhMoveReference(&lxssBasePathName, PhDosPathNameToNtPathName(&lxssBasePathName->sr));\n\n            if (lxssBasePathName && PhStartsWithStringRef(context->FileName, &lxssBasePathName->sr, TRUE))\n            {\n                PPH_STRING lxssDistributionName;\n\n                if (lxssDistributionName = PhQueryRegistryStringZ(keyHandle, L\"DistributionName\"))\n                {\n                    context->Found = TRUE;\n                    context->DistributionGuid = PhCreateString2(&keyName);\n                    context->DistributionName = lxssDistributionName;\n                    context->DistributionPath = lxssBasePathName;\n\n                    if (context->TranslatedPath = PhCreateString2(context->FileName))\n                    {\n                        PhSkipStringRef(&context->TranslatedPath->sr, lxssBasePathName->Length);\n                        PhSkipStringRef(&context->TranslatedPath->sr, sizeof(L\"rootfs\"));\n                    }\n\n                    NtClose(keyHandle);\n                    return FALSE;\n                }\n            }\n\n            PhClearReference(&lxssBasePathName);\n        }\n\n        NtClose(keyHandle);\n    }\n\n    return TRUE;\n}\n\nNTSTATUS PhGetWslDistributionFromPath(\n    _In_ PPH_STRINGREF FileName,\n    _Out_opt_ PPH_STRING *DistributionGuid,\n    _Out_opt_ PPH_STRING *DistributionName,\n    _Out_opt_ PPH_STRING *DistributionPath,\n    _Out_opt_ PPH_STRING *TranslatedPath\n    )\n{\n    static CONST PH_STRINGREF lxssKeyPath = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Lxss\");\n    PH_WSL_ENUM_CONTEXT enumContext;\n    NTSTATUS status;\n    HANDLE keyHandle;\n\n    memset(&enumContext, 0, sizeof(PH_WSL_ENUM_CONTEXT));\n    enumContext.Found = FALSE;\n    enumContext.FileName = FileName;\n\n    status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_CURRENT_USER,\n        &lxssKeyPath,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhEnumerateKey(\n            keyHandle,\n            KeyBasicInformation,\n            PhWslDistributionNamesCallback,\n            &enumContext\n            );\n\n        NtClose(keyHandle);\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (enumContext.Found)\n        {\n            if (DistributionGuid)\n                *DistributionGuid = enumContext.DistributionGuid;\n            else\n                PhClearReference(&enumContext.DistributionGuid);\n\n            if (DistributionName)\n                *DistributionName = enumContext.DistributionName;\n            else\n                PhClearReference(&enumContext.DistributionName);\n\n            if (DistributionPath)\n                *DistributionPath = enumContext.DistributionPath;\n            else\n                PhClearReference(&enumContext.DistributionPath);\n\n            if (TranslatedPath)\n                *TranslatedPath = PhConvertNtPathSeperatorToAltSeperator(enumContext.TranslatedPath);\n            else\n                PhClearReference(&enumContext.TranslatedPath);\n        }\n        else\n        {\n            status = STATUS_NOT_FOUND;\n        }\n    }\n\n    return status;\n}\n\nPPH_STRING PhGetWslDistributionCommandLine(\n    _In_ PPH_STRING DistributionGuid,\n    _In_ PPH_STRING DistributionName,\n    _In_ PPH_STRING CommandLine\n    )\n{\n    PH_FORMAT format[4];\n    PPH_STRING systemDirectory;\n    PPH_STRING commandLine;\n\n    // \"wsl.exe -u root -d %s -e %s\"\n    if (DistributionGuid)\n    {\n        PhInitFormatS(&format[0], L\"wsl.exe --shell-type none --user root --distribution-id \");\n        PhInitFormatSR(&format[1], DistributionGuid->sr);\n    }\n    else\n    {\n        PhInitFormatS(&format[0], L\"wsl.exe --shell-type none --user root --distribution \");\n        PhInitFormatSR(&format[1], DistributionName->sr);\n    }\n\n    PhInitFormatS(&format[2], L\" -e \");\n    PhInitFormatSR(&format[3], CommandLine->sr);\n\n    if (commandLine = PhFormat(format, RTL_NUMBER_OF(format), 0))\n    {\n        if (systemDirectory = PhGetSystemDirectory())\n        {\n            PhMoveReference(&commandLine, PhConcatStringRef3(\n                &systemDirectory->sr,\n                &PhNtPathSeparatorString,\n                &commandLine->sr\n                ));\n            PhDereferenceObject(systemDirectory);\n        }\n\n        return commandLine;\n    }\n\n    return NULL;\n}\n\nPPH_STRING PhGetWslPathCommandLine(\n    _In_ PPH_STRING win32FileName\n    )\n{\n    PH_FORMAT format[3];\n\n    PhInitFormatS(&format[0], L\"wslpath -a -u \\\"\");\n    PhInitFormatSR(&format[1], win32FileName->sr);\n    PhInitFormatC(&format[2], L'\\\"');\n\n    return PhFormat(format, RTL_NUMBER_OF(format), 0x100);\n}\n\nNTSTATUS PhDosPathNameToWslPathName(\n    _In_ PPH_STRINGREF FileName,\n    _Out_ PPH_STRING* LxssFileName\n    )\n{\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\n    PPH_STRING win32FileName = NULL;\n    PPH_STRING distributionGuid = NULL;\n    PPH_STRING distributionName = NULL;\n    PPH_STRING commandLine = NULL;\n    PPH_STRING commandResult = NULL;\n\n    win32FileName = PhCreateString2(FileName);\n    PhMoveReference(&win32FileName, PhGetFileName(win32FileName));\n\n    if (PhIsNullOrEmptyString(win32FileName))\n        goto CleanupExit;\n\n    commandLine = PhGetWslPathCommandLine(win32FileName);\n\n    if (PhIsNullOrEmptyString(win32FileName))\n        goto CleanupExit;\n\n    status = PhGetWslDistributionFromPath(\n        FileName,\n        &distributionGuid,\n        &distributionName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreateProcessLxss(\n        distributionGuid,\n        distributionName,\n        commandLine,\n        &commandResult\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (PhEndsWithString2(commandResult, L\"\\n\", FALSE))\n    {\n        commandResult->Length -= sizeof(WCHAR[1]);\n        commandResult->Buffer[commandResult->Length / sizeof(WCHAR)] = UNICODE_NULL;\n    }\n\n    *LxssFileName = PhReferenceObject(commandResult);\n    status = STATUS_SUCCESS;\n\nCleanupExit:\n\n    PhClearReference(&commandResult);\n    PhClearReference(&commandLine);\n    PhClearReference(&distributionName);\n    PhClearReference(&distributionGuid);\n    PhClearReference(&win32FileName);\n\n    return status;\n}\n\nNTSTATUS PhWslQueryDistroProcessCommandLine(\n    _In_ PPH_STRINGREF FileName,\n    _In_ ULONG LxssProcessId,\n    _Out_ PPH_STRING* Result\n    )\n{\n    NTSTATUS status;\n    PPH_STRING distributionGuid = NULL;\n    PPH_STRING distributionName = NULL;\n    PPH_STRING distributionCommand = NULL;\n    PPH_STRING distributionResult = NULL;\n    PH_FORMAT format[5];\n\n    status = PhGetWslDistributionFromPath(\n        FileName,\n        &distributionGuid,\n        &distributionName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhInitFormatS(&format[0], L\"\\\\Device\\\\Mup\\\\wsl.localhost\\\\\");\n    PhInitFormatSR(&format[1], distributionName->sr);\n    PhInitFormatS(&format[2], L\"\\\\proc\\\\\");\n    PhInitFormatIU(&format[3], LxssProcessId);\n    PhInitFormatS(&format[4], L\"\\\\cmdline\");\n\n    if (distributionCommand = PhFormat(format, RTL_NUMBER_OF(format), 0x100))\n    {\n        HANDLE fileHandle;\n\n        status = PhCreateFile(\n            &fileHandle,\n            &distributionCommand->sr,\n            FILE_GENERIC_READ,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhGetFileText(\n                &distributionResult,\n                fileHandle,\n                TRUE\n                );\n            NtClose(fileHandle);\n        }\n\n        if (status == STATUS_ACCESS_DENIED)\n        {\n            PPH_STRING commandLine;\n            PPH_STRING commandResult;\n\n            // Note: The WSL P9 Multiple UNC Provider (MUP) doesn't allow administrators to read /proc unless the distro wsl.conf default user is root.\n            // Changing the default user to root fixes permission issues when accessing files from Windows but results in everything owned by root and inaccessible from WSL.\n            // We can workaround the issue by creating a root process using 'wsl.exe -u root' and pipe the /proc content via standard output.\n            // This is significantly slower (very slow) but works, and avoids hard requirements on user preferences and distro configuration.\n\n            PhInitFormatS(&format[0], L\"cat /proc/\");\n            PhInitFormatIU(&format[1], LxssProcessId);\n            PhInitFormatS(&format[2], L\"/cmdline\");\n\n            if (commandLine = PhFormat(format, 3, 0x100))\n            {\n                status = PhCreateProcessLxss(\n                    distributionGuid,\n                    distributionName,\n                    commandLine,\n                    &commandResult\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    distributionResult = commandResult;\n                }\n\n                PhDereferenceObject(commandLine);\n            }\n        }\n\n        PhDereferenceObject(distributionCommand);\n    }\n\n    PhDereferenceObject(distributionName);\n    PhDereferenceObject(distributionGuid);\n\n    if (distributionResult)\n    {\n        *Result = distributionResult;\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nNTSTATUS PhWslQueryDistroProcessEnvironment(\n    _In_ PPH_STRINGREF FileName,\n    _In_ ULONG LxssProcessId,\n    _Out_ PPH_STRING* Result\n    )\n{\n    NTSTATUS status;\n    PPH_STRING distributionGuid = NULL;\n    PPH_STRING distributionName = NULL;\n    PPH_STRING distributionCommand = NULL;\n    PPH_STRING distributionResult = NULL;\n    PH_FORMAT format[5];\n\n    status = PhGetWslDistributionFromPath(\n        FileName,\n        &distributionGuid,\n        &distributionName,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhInitFormatS(&format[0], L\"\\\\Device\\\\Mup\\\\wsl.localhost\\\\\");\n    PhInitFormatSR(&format[1], distributionName->sr);\n    PhInitFormatS(&format[2], L\"\\\\proc\\\\\");\n    PhInitFormatIU(&format[3], LxssProcessId);\n    PhInitFormatS(&format[4], L\"\\\\environ\");\n\n    if (distributionCommand = PhFormat(format, RTL_NUMBER_OF(format), 0x100))\n    {\n        HANDLE fileHandle;\n\n        status = PhCreateFile(\n            &fileHandle,\n            &distributionCommand->sr,\n            FILE_GENERIC_READ,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            status = PhGetFileText(\n                &distributionResult,\n                fileHandle,\n                TRUE\n                );\n            NtClose(fileHandle);\n        }\n\n        if (status == STATUS_ACCESS_DENIED)\n        {\n            PPH_STRING commandLine;\n            PPH_STRING commandResult;\n\n            // Note: The WSL P9 Multiple UNC Provider (MUP) doesn't allow administrators to read /proc unless the distro wsl.conf default user is root.\n            // Changing the default user to root fixes permission issues when accessing files from Windows but results in everything owned by root and inaccessible from WSL.\n            // We can workaround the issue by creating a root process using 'wsl.exe -u root' and pipe the /proc content via standard output.\n            // This is significantly slower (very slow) but works, and avoids hard requirements on user preferences and distro configuration.\n\n            PhInitFormatS(&format[0], L\"cat /proc/\");\n            PhInitFormatIU(&format[1], LxssProcessId);\n            PhInitFormatS(&format[2], L\"/environ\");\n\n            if (commandLine = PhFormat(format, 3, 0x100))\n            {\n                status = PhCreateProcessLxss(\n                    distributionGuid,\n                    distributionName,\n                    commandLine,\n                    &commandResult\n                    );\n\n                if (NT_SUCCESS(status))\n                {\n                    distributionResult = commandResult;\n                }\n\n                PhDereferenceObject(commandLine);\n            }\n        }\n\n        PhDereferenceObject(distributionCommand);\n    }\n\n    PhDereferenceObject(distributionName);\n    PhDereferenceObject(distributionGuid);\n\n    if (distributionResult)\n    {\n        *Result = distributionResult;\n        return STATUS_SUCCESS;\n    }\n\n    return STATUS_UNSUCCESSFUL;\n}\n\nNTSTATUS PhWslQueryRpmPackageFromFileName(\n    _In_ PPH_STRING DistributionGuid,\n    _In_ PPH_STRING DistributionName,\n    _In_ PPH_STRING LxssFileName,\n    _Out_ PPH_STRING* Result\n    )\n{\n    NTSTATUS status;\n    PPH_STRING commandLine;\n    PPH_STRING commandResult;\n    PH_FORMAT format[3];\n\n    // \"rpm -qf %s --queryformat \\\"%%{VERSION}|%%{VENDOR}|%%{SUMMARY}\\\"\"\n    PhInitFormatS(&format[0], L\"rpm -qf \\\"\");\n    PhInitFormatSR(&format[1], LxssFileName->sr);\n    PhInitFormatS(&format[2], L\"\\\" --queryformat \\\"%%{VERSION}|%%{VENDOR}|%%{SUMMARY}\\\"\");\n    commandLine = PhFormat(format, RTL_NUMBER_OF(format), 0x100);\n\n    status = PhCreateProcessLxss(\n        DistributionGuid,\n        DistributionName,\n        commandLine,\n        &commandResult\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Result = commandResult;\n    }\n\n    PhDereferenceObject(commandLine);\n    return status;\n}\n\nNTSTATUS PhWslQueryDebianPackageFromFileName(\n    _In_ PPH_STRING DistributionGuid,\n    _In_ PPH_STRING DistributionName,\n    _In_ PPH_STRING LxssFileName,\n    _Out_ PPH_STRING* Result\n    )\n{\n    NTSTATUS status;\n    PPH_STRING commandLine;\n    PPH_STRING lxssCommandResult = NULL;\n    PPH_STRING lxssPackageName = NULL;\n    PH_FORMAT format[3];\n\n    // \"dpkg -S %s\"\n    PhInitFormatS(&format[0], L\"dpkg -S \\\"\");\n    PhInitFormatSR(&format[1], LxssFileName->sr);\n    PhInitFormatS(&format[2], L\"\\\"\");\n    commandLine = PhFormat(format, RTL_NUMBER_OF(format), 0x100);\n\n    status = PhCreateProcessLxss(\n        DistributionGuid,\n        DistributionName,\n        commandLine,\n        &lxssCommandResult\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        // The dpkg metadata doesn't contain information for symbolic links\n        // from \"/usr/bin -> /bin\" so remove the /usr prefix and try again. (dmex)\n\n        if (PhStartsWithString2(LxssFileName, L\"/usr\", FALSE))\n        {\n            PhSkipStringRef(&LxssFileName->sr, sizeof(WCHAR[4]));\n\n            // \"dpkg -S %s\"\n            PhInitFormatS(&format[0], L\"dpkg -S \\\"\");\n            PhInitFormatSR(&format[1], LxssFileName->sr);\n            PhInitFormatS(&format[2], L\"\\\"\");\n            PhMoveReference(&commandLine, PhFormat(format, RTL_NUMBER_OF(format), 0x100));\n\n            status = PhCreateProcessLxss(\n                DistributionGuid,\n                DistributionName,\n                commandLine,\n                &lxssCommandResult\n                );\n\n            if (!NT_SUCCESS(status))\n            {\n                goto CleanupExit;\n            }\n        }\n        else\n        {\n            goto CleanupExit;\n        }\n    }\n\n    if (!PhIsNullOrEmptyString(lxssCommandResult))\n    {\n        PH_STRINGREF remainingPart;\n        PH_STRINGREF packagePart;\n\n        if (PhSplitStringRefAtChar(&lxssCommandResult->sr, L':', &packagePart, &remainingPart))\n        {\n            lxssPackageName = PhCreateString2(&packagePart);\n        }\n\n        PhClearReference(&lxssCommandResult);\n    }\n\n    if (PhIsNullOrEmptyString(lxssPackageName))\n        goto CleanupExit;\n\n    // \"dpkg-query -W -f=${Version}|${Maintainer}|${binary:Summary} %s\"\n    PhInitFormatS(&format[0], L\"dpkg-query -W -f=${Version}|${Maintainer}|${binary:Summary} \\\"\");\n    PhInitFormatSR(&format[1], lxssPackageName->sr);\n    PhInitFormatS(&format[2], L\"\\\"\");\n    PhMoveReference(&commandLine, PhFormat(format, RTL_NUMBER_OF(format), 0x100));\n\n    status = PhCreateProcessLxss(\n        DistributionGuid,\n        DistributionName,\n        commandLine,\n        &lxssCommandResult\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    *Result = PhReferenceObject(lxssCommandResult);\n\nCleanupExit:\n    if (lxssPackageName) PhDereferenceObject(lxssPackageName);\n    if (lxssCommandResult) PhDereferenceObject(lxssCommandResult);\n    if (commandLine) PhDereferenceObject(commandLine);\n\n    return status;\n}\n\nNTSTATUS PhWslParsePackageVersionInfo(\n    _Inout_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PPH_STRING LxssCommandResult\n    )\n{\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF companyPart;\n    PH_STRINGREF descriptionPart;\n    PH_STRINGREF versionPart;\n\n    if (PhIsNullOrEmptyString(LxssCommandResult))\n        return STATUS_UNSUCCESSFUL;\n\n    remainingPart = PhGetStringRef(LxssCommandResult);\n    PhSplitStringRefAtChar(&remainingPart, L'|', &versionPart, &remainingPart);\n    PhSplitStringRefAtChar(&remainingPart, L'|', &companyPart, &remainingPart);\n    PhSplitStringRefAtChar(&remainingPart, L'|', &descriptionPart, &remainingPart);\n\n    if (versionPart.Length != 0 && !ImageVersionInfo->FileVersion)\n    {\n        ImageVersionInfo->FileVersion = PhCreateString2(&versionPart);\n    }\n\n    if (companyPart.Length != 0 && !ImageVersionInfo->CompanyName)\n    {\n        ImageVersionInfo->CompanyName = PhCreateString2(&companyPart);\n    }\n\n    if (descriptionPart.Length != 0 && !ImageVersionInfo->FileDescription)\n    {\n        ImageVersionInfo->FileDescription = PhCreateString2(&descriptionPart);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhInitializeLxssImageVersionInfo(\n    _Inout_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PPH_STRINGREF FileName\n    )\n{\n    NTSTATUS success;\n    PPH_STRING distributionGuid = NULL;\n    PPH_STRING distributionName = NULL;\n    PPH_STRING distributionCommand = NULL;\n    PPH_STRING translatedPath = NULL;\n\n    success = PhGetWslDistributionFromPath(\n        FileName,\n        &distributionGuid,\n        &distributionName,\n        NULL,\n        &translatedPath\n        );\n\n    if (!NT_SUCCESS(success))\n        return success;\n\n    if (PhEqualString2(translatedPath, L\"/init\", FALSE))\n    {\n        success = STATUS_UNSUCCESSFUL;\n        goto CleanupExit;\n    }\n\n    success = PhWslQueryDebianPackageFromFileName(\n        distributionGuid,\n        distributionName,\n        translatedPath,\n        &distributionCommand\n        );\n\n    if (NT_SUCCESS(success))\n    {\n        success = PhWslParsePackageVersionInfo(ImageVersionInfo, distributionCommand);\n\n        if (NT_SUCCESS(success))\n            goto CleanupExit;\n    }\n\n    success = PhWslQueryRpmPackageFromFileName(\n        distributionGuid,\n        distributionName,\n        translatedPath,\n        &distributionCommand\n        );\n\n    if (NT_SUCCESS(success))\n    {\n        success = PhWslParsePackageVersionInfo(ImageVersionInfo, distributionCommand);\n\n        if (NT_SUCCESS(success))\n            goto CleanupExit;\n    }\n\nCleanupExit:\n    PhClearReference(&distributionCommand);\n    PhClearReference(&distributionName);\n    PhClearReference(&distributionGuid);\n    PhClearReference(&translatedPath);\n\n    return success;\n}\n\nNTSTATUS PhCreateProcessLxss(\n    _In_ PPH_STRING DistributionGuid,\n    _In_ PPH_STRING DistributionName,\n    _In_ PPH_STRING DistributionCommand,\n    _Out_ PPH_STRING *Result\n    )\n{\n    static SECURITY_ATTRIBUTES securityAttributes = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };\n#if defined(PH_WSL_PSEUDOCONSOLE)\n    static typeof(&CreatePseudoConsole) CreatePseudoConsole_I = NULL;\n    static typeof(&ClosePseudoConsole) ClosePseudoConsole_I = NULL;\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    HPCON pseudoConsoleHandle = NULL;\n#endif\n    NTSTATUS status;\n    PPH_STRING distributionCommand = NULL;\n    PPH_STRING distributionCommandLine;\n    HANDLE processHandle = NULL;\n    HANDLE outputReadHandle = NULL, outputWriteHandle = NULL;\n    HANDLE inputReadHandle = NULL, inputWriteHandle = NULL;\n    PPROC_THREAD_ATTRIBUTE_LIST attributeList = NULL;\n    HANDLE handleList[2];\n    STARTUPINFOEX startupInfo = { 0 };\n    PROCESS_BASIC_INFORMATION basicInfo;\n\n#if defined(PH_WSL_PSEUDOCONSOLE)\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion >= WINDOWS_10_RS5)\n        {\n            PVOID baseAddress;\n\n            if (baseAddress = PhGetLoaderEntryDllBaseZ(L\"kernelbase.dll\"))\n            {\n                CreatePseudoConsole_I = PhGetDllBaseProcedureAddress(baseAddress, \"CreatePseudoConsole\", 0);\n                ClosePseudoConsole_I = PhGetDllBaseProcedureAddress(baseAddress, \"ClosePseudoConsole\", 0);\n            }\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!CreatePseudoConsole_I || !ClosePseudoConsole_I)\n        return STATUS_PROCEDURE_NOT_FOUND;\n#endif\n\n    distributionCommandLine = PhGetWslDistributionCommandLine(\n        DistributionGuid,\n        DistributionName,\n        DistributionCommand\n        );\n\n    if (PhIsNullOrEmptyString(distributionCommandLine))\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n\n    status = PhCreatePipeEx(\n        &outputReadHandle,\n        &outputWriteHandle,\n        NULL,\n        &securityAttributes\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = PhCreatePipeEx(\n        &inputReadHandle,\n        &inputWriteHandle,\n        &securityAttributes,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n#if defined(PH_WSL_PSEUDOCONSOLE)\n    COORD coord = { 80, 25 };\n    if (HR_FAILED(CreatePseudoConsole_I(coord, inputReadHandle, outputWriteHandle, 0, &pseudoConsoleHandle)))\n    {\n        status = STATUS_UNSUCCESSFUL;\n        goto CleanupExit;\n    }\n#endif\n\n    status = PhInitializeProcThreadAttributeList(&attributeList, 2);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    handleList[0] = inputReadHandle;\n    handleList[1] = outputWriteHandle;\n\n    status = PhUpdateProcThreadAttribute(\n        attributeList,\n        PROC_THREAD_ATTRIBUTE_HANDLE_LIST,\n        handleList,\n        sizeof(handleList)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n#if defined(PH_WSL_PSEUDOCONSOLE)\n    status = PhUpdateProcThreadAttribute(\n        attributeList,\n        PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,\n        pseudoConsoleHandle,\n        sizeof(pseudoConsoleHandle)\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n#endif\n\n    memset(&startupInfo, 0, sizeof(STARTUPINFOEX));\n    startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX);\n    startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES;\n    startupInfo.StartupInfo.wShowWindow = SW_HIDE;\n    startupInfo.StartupInfo.hStdInput = inputReadHandle;\n    startupInfo.StartupInfo.hStdOutput = outputWriteHandle;\n    startupInfo.StartupInfo.hStdError = outputWriteHandle;\n    startupInfo.lpAttributeList = attributeList;\n\n    status = PhCreateProcessWin32Ex(\n        NULL,\n        PhGetString(distributionCommandLine),\n        NULL,\n        NULL,\n        &startupInfo,\n        PH_CREATE_PROCESS_INHERIT_HANDLES | PH_CREATE_PROCESS_NEW_CONSOLE |\n        PH_CREATE_PROCESS_DEFAULT_ERROR_MODE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO,\n        NULL,\n        NULL,\n        &processHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Close the handles. (dmex)\n    NtClose(inputReadHandle); inputReadHandle = NULL;\n    NtClose(outputWriteHandle); outputWriteHandle = NULL;\n\n    // Read the pipe data. (dmex)\n    status = PhGetFileText(&distributionCommand, outputReadHandle, TRUE);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Get the exit code after we finish reading the data from the pipe. (dmex)\n    status = PhGetProcessBasicInformation(processHandle, &basicInfo);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = basicInfo.ExitStatus;\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    *Result = PhReferenceObject(distributionCommand);\n\nCleanupExit:\n\n    if (processHandle)\n        NtClose(processHandle);\n\n#if defined(PH_WSL_PSEUDOCONSOLE)\n    if (pseudoConsoleHandle)\n        ClosePseudoConsole_I(pseudoConsoleHandle);\n#endif\n\n    if (outputWriteHandle)\n        NtClose(outputWriteHandle);\n    if (outputReadHandle)\n        NtClose(outputReadHandle);\n    if (inputReadHandle)\n        NtClose(inputReadHandle);\n    if (inputWriteHandle)\n        NtClose(inputWriteHandle);\n\n    if (attributeList)\n        PhDeleteProcThreadAttributeList(attributeList);\n\n    if (distributionCommand)\n        PhDereferenceObject(distributionCommand);\n    if (distributionCommandLine)\n        PhDereferenceObject(distributionCommandLine);\n\n    return status;\n}\n"
  },
  {
    "path": "phnt/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2022 Winsider Seminars & Solutions, Inc.  All rights reserved.\n#\n# This file is part of System Informer.\n#\n\nproject(phnt)\n\nadd_library(phnt INTERFACE)\n\ntarget_include_directories(phnt INTERFACE\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include\"\n)\n"
  },
  {
    "path": "phnt/README.md",
    "content": "This collection of Native API header files has been maintained since 2009 for the Process Hacker project, and is the most up-to-date set of Native API definitions that I know of. I have gathered these definitions from official Microsoft header files and symbol files, as well as a lot of reverse engineering and guessing. See `phnt.h` for more information.\n\n## Usage\n\nFirst make sure that your program is using the latest Windows SDK.\n\nThese header files are designed to be used by user-mode programs. Instead of `#include <windows.h>`, place\n\n```\n#include <phnt_windows.h>\n#include <phnt.h>\n```\n\nat the top of your program. The first line provides access to the Win32 API as well as the `NTSTATUS` values. The second line provides access to the entire Native API. By default, only definitions present in Windows XP are included into your program. To change this, use one of the following:\n\n```\n#define PHNT_VERSION PHNT_WINDOWS_XP // Windows XP\n#define PHNT_VERSION PHNT_WINDOWS_SERVER_2003 // Windows Server 2003\n#define PHNT_VERSION PHNT_WINDOWS_VISTA // Windows Vista\n#define PHNT_VERSION PHNT_WINDOWS_7 // Windows 7\n#define PHNT_VERSION PHNT_WINDOWS_8 // Windows 8\n#define PHNT_VERSION PHNT_WINDOWS_8_1 // Windows 8.1\n#define PHNT_VERSION PHNT_WINDOWS_10 // Windows 10\n#define PHNT_VERSION PHNT_WINDOWS_11 // Windows 11\n```\n"
  },
  {
    "path": "phnt/include/ntafd.h",
    "content": "/*\n * Ancillary Function Driver definitions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTAFD_H\n#define _NTAFD_H\n\n#include <WinSock2.h>\n#include <MSWSock.h>\n#include <tdi.h>\n\n// private\n#define AFD_DEVICE_NAME L\"\\\\Device\\\\Afd\"\n\n// private // Extended Attributes\n#define AfdOpenPacket      \"AfdOpenPacketXX\"    // AFD_OPEN_PACKET\n#define AfdSwOpenPacket    \"AfdSwOpenPacket\"    // AFD_SWITCH_OPEN_PACKET // rev\n#define AfdRioRDOpenPacket \"AfdRioRDOpenPacket\" // void // rev\n\n// private\ntypedef struct _AFD_ENDPOINT_FLAGS\n{\n    union\n    {\n        struct\n        {\n            UCHAR ConnectionLess : 1;\n            UCHAR : 3;\n            UCHAR MessageMode : 1;\n            UCHAR : 3;\n            UCHAR Raw : 1;\n            UCHAR : 3;\n            UCHAR Multipoint : 1;\n            UCHAR : 3;\n            UCHAR C_Root : 1;\n            UCHAR : 3;\n            UCHAR D_Root : 1;\n            UCHAR : 3;\n            UCHAR IgnoreTDI : 1;\n            UCHAR : 3;\n            UCHAR RioSocket : 1;\n            UCHAR : 3;\n        };\n        ULONG EndpointFlags;\n    };\n} AFD_ENDPOINT_FLAGS, *PAFD_ENDPOINT_FLAGS;\n\n// private // Transport device names\n#define DD_TCP_DEVICE_NAME      L\"\\\\Device\\\\Tcp\"\n#define DD_TCPV6_DEVICE_NAME    L\"\\\\Device\\\\Tcp6\"\n#define DD_UDP_DEVICE_NAME      L\"\\\\Device\\\\Udp\"\n#define DD_UDPV6_DEVICE_NAME    L\"\\\\Device\\\\Udp6\"\n#define DD_RAW_IP_DEVICE_NAME   L\"\\\\Device\\\\RawIp\"\n#define DD_RAW_IPV6_DEVICE_NAME L\"\\\\Device\\\\RawIp6\"\n\n// private\ntypedef struct _AFD_OPEN_PACKET\n{\n    _In_ AFD_ENDPOINT_FLAGS __f;\n    _In_opt_ GROUP GroupID;\n    _In_ LONG AddressFamily; // AF_*\n    _In_ LONG SocketType; // SOCK_*\n    _In_ LONG Protocol; // IPPROTO_*, BTHPROTO_*, HV_PROTOCOL_*, etc.\n    _In_opt_ ULONG TransportDeviceNameLength; // Note: specifying a device changes the transport mode\n    _Field_size_bytes_opt_(TransportDeviceNameLength) WCHAR TransportDeviceName[ANYSIZE_ARRAY];\n} AFD_OPEN_PACKET, *PAFD_OPEN_PACKET;\n\n// rev (FILE_FULL_EA_INFORMATION + AfdOpenPacket + AFD_OPEN_PACKET)\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _AFD_OPEN_PACKET_FULL_EA\n{\n    ULONG NextEntryOffset;\n    UCHAR Flags;\n    UCHAR EaNameLength; // sizeof(AfdOpenPacket) - sizeof(ANSI_NULL);\n    USHORT EaValueLength; // sizeof(AFD_OPEN_PACKET)\n    CHAR EaName[sizeof(AfdOpenPacket)];\n    AFD_OPEN_PACKET OpenPacket;\n} AFD_OPEN_PACKET_FULL_EA, *PAFD_OPEN_PACKET_FULL_EA;\n\n// private\ntypedef struct _AFD_SWITCH_OPEN_PACKET\n{\n    HANDLE CompletionPort;\n    HANDLE CompletionEvent;\n} AFD_SWITCH_OPEN_PACKET, *PAFD_SWITCH_OPEN_PACKET;\n\n//\n// Since Vista, sockets can use different modes of transport: TLI, TDI, and hybrid. The mode is selected\n// based on whether the caller specifies the transport device at socket creation and whether this device\n// is suitable for hybrid operation. No device means TLI, which is the most common choice.\n//\n// The transport mode affects which structures AFD uses for IOCTLs on the socket:\n//  - TLI sockets use *_TL structures (where applicable) and SOCKADDR for addresses.\n//  - TDI and hybrid sockets use non-TL structures and TDI_ADDRESS_INFO for addresses.\n//\n\n// private // IOCTL function numbers\n#define AFD_BIND                        0 // in: AFD_BIND_INFO_TL; out: SOCKADDR /or/ in: AFD_BIND_INFO; out: TDI_ADDRESS_INFO (depending on transport mode)\n#define AFD_CONNECT                     1 // in: AFD_CONNECT_JOIN_INFO_TL or AFD_CONNECT_JOIN_INFO (depending on transport mode); out (opt): IO_STATUS_BLOCK\n#define AFD_START_LISTEN                2 // in: AFD_LISTEN_INFO\n#define AFD_WAIT_FOR_LISTEN             3 // out: AFD_LISTEN_RESPONSE_INFO_TL or AFD_LISTEN_RESPONSE_INFO (depending on transport mode)\n#define AFD_ACCEPT                      4 // in: AFD_ACCEPT_INFO\n#define AFD_RECEIVE                     5 // in: AFD_RECV_INFO\n#define AFD_RECEIVE_DATAGRAM            6 // in: AFD_DATAGRAM_INFO\n#define AFD_SEND                        7 // in: AFD_SEND_INFO\n#define AFD_SEND_DATAGRAM               8 // in: AFD_SEND_DATAGRAM_INFO\n#define AFD_POLL                        9 // in, out: AFD_POLL_INFO\n#define AFD_PARTIAL_DISCONNECT          10 // in: AFD_PARTIAL_DISCONNECT_INFO\n#define AFD_GET_ADDRESS                 11 // out: AFD_ADDRESS (SOCKADDR or TDI_ADDRESS_INFO, depending on transport mode)\n#define AFD_QUERY_RECEIVE_INFO          12 // out: AFD_RECEIVE_INFORMATION\n#define AFD_QUERY_HANDLES               13 // in: ULONG (AFD_QUERY_*); out: AFD_HANDLE_INFO\n#define AFD_SET_INFORMATION             14 // in: AFD_INFORMATION\n#define AFD_GET_REMOTE_ADDRESS          15 // out: AFD_ADDRESS (SOCKADDR or TDI_ADDRESS_INFO, depending on transport mode)\n#define AFD_GET_CONTEXT                 16 // out: SOCK_SHARED_INFO (on Win32 level) or custom data\n#define AFD_SET_CONTEXT                 17 // in: SOCK_SHARED_INFO (on Win32 level) or custom data; out: AFD_ADDRESS (SOCKADDR or TDI_ADDRESS_INFO, depending on transport mode; output buffer must be inside the input buffer)\n#define AFD_SET_CONNECT_DATA            18 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_SET_CONNECT_OPTIONS         19 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_SET_DISCONNECT_DATA         20 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_SET_DISCONNECT_OPTIONS      21 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_GET_CONNECT_DATA            22 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_GET_CONNECT_OPTIONS         23 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_GET_DISCONNECT_DATA         24 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_GET_DISCONNECT_OPTIONS      25 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_SIZE_CONNECT_DATA           26 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_SIZE_CONNECT_OPTIONS        27 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_SIZE_DISCONNECT_DATA        28 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_SIZE_DISCONNECT_OPTIONS     29 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: payload\n#define AFD_GET_INFORMATION             30 // in, out: AFD_INFORMATION\n#define AFD_TRANSMIT_FILE               31 // in: AFD_TRANSMIT_FILE_INFO; out (opt): BOOLEAN\n#define AFD_SUPER_ACCEPT                32 // in: AFD_SUPER_ACCEPT_INFO; out: received data + local address + remote address (at offsets according to the input)\n#define AFD_EVENT_SELECT                33 // in: AFD_EVENT_SELECT_INFO\n#define AFD_ENUM_NETWORK_EVENTS         34 // in (opt): HANDLE; out: AFD_ENUM_NETWORK_EVENTS_INFO\n#define AFD_DEFER_ACCEPT                35 // in: AFD_DEFER_ACCEPT_INFO\n#define AFD_WAIT_FOR_LISTEN_LIFO        36 // out: AFD_LISTEN_RESPONSE_INFO_TL or AFD_LISTEN_RESPONSE_INFO (depending on transport mode)\n#define AFD_SET_QOS                     37 // in: AFD_QOS_INFO\n#define AFD_GET_QOS                     38 // out: AFD_QOS_INFO\n#define AFD_NO_OPERATION                39 // in (opt): IO_STATUS_BLOCK\n#define AFD_VALIDATE_GROUP              40 // in: AFD_VALIDATE_GROUP_INFO\n#define AFD_GET_UNACCEPTED_CONNECT_DATA 41 // in: AFD_UNACCEPTED_CONNECT_DATA_INFO; out: AFD_UNACCEPTED_CONNECT_DATA_INFO (when LengthOnly is set) or received data\n#define AFD_ROUTING_INTERFACE_QUERY     42 // in: TRANSPORT_ADDRESS; out: SOCKADDR\n#define AFD_ROUTING_INTERFACE_CHANGE    43 // in: AFD_TRANSPORT_IOCTL_INFO\n#define AFD_ADDRESS_LIST_QUERY          44 // in: USHORT (TDI_ADDRESS_TYPE_*/AF_*); out: TRANSPORT_ADDRESS\n#define AFD_ADDRESS_LIST_CHANGE         45 // in: AFD_TRANSPORT_IOCTL_INFO\n#define AFD_JOIN_LEAF                   46 // in: AFD_CONNECT_JOIN_INFO_TL or AFD_CONNECT_JOIN_INFO (depending on transport mode); out (opt): IO_STATUS_BLOCK\n#define AFD_TRANSPORT_IOCTL             47 // in: AFD_TL_IO_CONTROL_INFO; out: variable\n#define AFD_TRANSMIT_PACKETS            48 // in: AFD_TPACKETS_INFO; out (opt): BOOLEAN\n#define AFD_SUPER_CONNECT               49 // in: AFD_SUPER_CONNECT_INFO_TL or AFD_SUPER_CONNECT_INFO (depending on transport mode); out: payload\n#define AFD_SUPER_DISCONNECT            50 // in: AFD_SUPER_DISCONNECT_INFO\n#define AFD_RECEIVE_MESSAGE             51 // in: AFD_MESSAGE_INFO\n#define AFD_SEND_MESSAGE                52 // in: AFD_MESSAGE_INFO // rev // since VISTA // breaks layout; values below are different on XP\n#define AFD_SWITCH_CEMENT_SAN           53 // in: AFD_SWITCH_CONTEXT_INFO\n#define AFD_SWITCH_SET_EVENTS           54 // in: AFD_SWITCH_EVENT_INFO\n#define AFD_SWITCH_RESET_EVENTS         55 // in: AFD_SWITCH_EVENT_INFO\n#define AFD_SWITCH_CONNECT_IND          56 // in: AFD_SWITCH_CONNECT_INFO; out: AFD_SWITCH_ACCEPT_INFO\n#define AFD_SWITCH_CMPL_ACCEPT          57 // in: AFD_SWITCH_CONTEXT_INFO; out: payload\n#define AFD_SWITCH_CMPL_REQUEST         58 // in: AFD_SWITCH_REQUEST_INFO; out: payload\n#define AFD_SWITCH_CMPL_IO              59 // in: IO_STATUS_BLOCK\n#define AFD_SWITCH_REFRESH_ENDP         60 // in: AFD_SWITCH_CONTEXT_INFO\n#define AFD_SWITCH_GET_PHYSICAL_ADDR    61 // deprecated\n#define AFD_SWITCH_ACQUIRE_CTX          62 // in: AFD_SWITCH_ACQUIRE_CTX_INFO; out: payload\n#define AFD_SWITCH_TRANSFER_CTX         63 // in: AFD_SWITCH_TRANSFER_CTX_INFO\n#define AFD_SWITCH_GET_SERVICE_PID      64 // in/out: void; returns PID in IO_STATUS_BLOCK.Information\n#define AFD_SWITCH_SET_SERVICE_PROCESS  65 // in/out: void\n#define AFD_SWITCH_PROVIDER_CHANGE      66 // in/out: void\n#define AFD_SWITCH_ADDRLIST_CHANGE      67 // in: AFD_TRANSPORT_IOCTL_INFO\n#define AFD_UNBIND                      68 // in: AFD_UNBIND_INFO // rev // since VISTA\n#define AFD_SQM                         69 // in: AFD_SQM_INFO // rev // since WIN7\n#define AFD_RIO                         70 // in/out: AFD_RIO_COMMAND_HEADER // rev // since WIN8\n#define AFD_TRANSFER_BEGIN              71 // in/out: void // rev // since TH1\n#define AFD_TRANSFER_END                72 // in/out: void // rev // since TH1\n#define AFD_NOTIFY                      73 // rev // since 22H2\n\n// private // Note: different bit layout from CTL_CODE\n#define FSCTL_AFD_BASE  FILE_DEVICE_NETWORK\n#define _AFD_CONTROL_CODE(Request, Method) (FSCTL_AFD_BASE << 12 | (Request) << 2 | (Method))\n\n// private // IOCTLs\n#define IOCTL_AFD_BIND                        _AFD_CONTROL_CODE(AFD_BIND, METHOD_NEITHER) // 0x12003\n#define IOCTL_AFD_CONNECT                     _AFD_CONTROL_CODE(AFD_CONNECT, METHOD_NEITHER) // 0x12007\n#define IOCTL_AFD_START_LISTEN                _AFD_CONTROL_CODE(AFD_START_LISTEN, METHOD_NEITHER) // 0x1200B\n#define IOCTL_AFD_WAIT_FOR_LISTEN             _AFD_CONTROL_CODE(AFD_WAIT_FOR_LISTEN, METHOD_BUFFERED) // 0x1200C\n#define IOCTL_AFD_ACCEPT                      _AFD_CONTROL_CODE(AFD_ACCEPT, METHOD_BUFFERED) // 0x12010\n#define IOCTL_AFD_RECEIVE                     _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER) // 0x12017\n#define IOCTL_AFD_RECEIVE_DATAGRAM            _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER) // 0x1201B\n#define IOCTL_AFD_SEND                        _AFD_CONTROL_CODE(AFD_SEND, METHOD_NEITHER) // 0x1201F\n#define IOCTL_AFD_SEND_DATAGRAM               _AFD_CONTROL_CODE(AFD_SEND_DATAGRAM, METHOD_NEITHER) // 0x12023\n#define IOCTL_AFD_POLL                        _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) // 0x12024\n#define IOCTL_AFD_PARTIAL_DISCONNECT          _AFD_CONTROL_CODE(AFD_PARTIAL_DISCONNECT, METHOD_NEITHER) // 0x1202B\n#define IOCTL_AFD_GET_ADDRESS                 _AFD_CONTROL_CODE(AFD_GET_ADDRESS, METHOD_NEITHER) // 0x1202F\n#define IOCTL_AFD_QUERY_RECEIVE_INFO          _AFD_CONTROL_CODE(AFD_QUERY_RECEIVE_INFO, METHOD_NEITHER) // 0x12033\n#define IOCTL_AFD_QUERY_HANDLES               _AFD_CONTROL_CODE(AFD_QUERY_HANDLES, METHOD_NEITHER) // 0x12037\n#define IOCTL_AFD_SET_INFORMATION             _AFD_CONTROL_CODE(AFD_SET_INFORMATION, METHOD_NEITHER) // 0x1203B\n#define IOCTL_AFD_GET_REMOTE_ADDRESS          _AFD_CONTROL_CODE(AFD_GET_REMOTE_ADDRESS, METHOD_NEITHER) // 0x1203F\n#define IOCTL_AFD_GET_CONTEXT                 _AFD_CONTROL_CODE(AFD_GET_CONTEXT, METHOD_NEITHER) // 0x12043\n#define IOCTL_AFD_SET_CONTEXT                 _AFD_CONTROL_CODE(AFD_SET_CONTEXT, METHOD_NEITHER) // 0x12047\n#define IOCTL_AFD_SET_CONNECT_DATA            _AFD_CONTROL_CODE(AFD_SET_CONNECT_DATA, METHOD_NEITHER) // 0x1204B\n#define IOCTL_AFD_SET_CONNECT_OPTIONS         _AFD_CONTROL_CODE(AFD_SET_CONNECT_OPTIONS, METHOD_NEITHER) // 0x1204F\n#define IOCTL_AFD_SET_DISCONNECT_DATA         _AFD_CONTROL_CODE(AFD_SET_DISCONNECT_DATA, METHOD_NEITHER) // 0x12053\n#define IOCTL_AFD_SET_DISCONNECT_OPTIONS      _AFD_CONTROL_CODE(AFD_SET_DISCONNECT_OPTIONS, METHOD_NEITHER) // 0x12057\n#define IOCTL_AFD_GET_CONNECT_DATA            _AFD_CONTROL_CODE(AFD_GET_CONNECT_DATA, METHOD_NEITHER) // 0x1205B\n#define IOCTL_AFD_GET_CONNECT_OPTIONS         _AFD_CONTROL_CODE(AFD_GET_CONNECT_OPTIONS, METHOD_NEITHER) // 0x1205F\n#define IOCTL_AFD_GET_DISCONNECT_DATA         _AFD_CONTROL_CODE(AFD_GET_DISCONNECT_DATA, METHOD_NEITHER) // 0x12063\n#define IOCTL_AFD_GET_DISCONNECT_OPTIONS      _AFD_CONTROL_CODE(AFD_GET_DISCONNECT_OPTIONS, METHOD_NEITHER) // 0x12067\n#define IOCTL_AFD_SIZE_CONNECT_DATA           _AFD_CONTROL_CODE(AFD_SIZE_CONNECT_DATA, METHOD_NEITHER) // 0x1206B\n#define IOCTL_AFD_SIZE_CONNECT_OPTIONS        _AFD_CONTROL_CODE(AFD_SIZE_CONNECT_OPTIONS, METHOD_NEITHER) // 0x1206F\n#define IOCTL_AFD_SIZE_DISCONNECT_DATA        _AFD_CONTROL_CODE(AFD_SIZE_DISCONNECT_DATA, METHOD_NEITHER) // 0x12073\n#define IOCTL_AFD_SIZE_DISCONNECT_OPTIONS     _AFD_CONTROL_CODE(AFD_SIZE_DISCONNECT_OPTIONS, METHOD_NEITHER) // 0x12077\n#define IOCTL_AFD_GET_INFORMATION             _AFD_CONTROL_CODE(AFD_GET_INFORMATION, METHOD_NEITHER) // 0x1207B\n#define IOCTL_AFD_TRANSMIT_FILE               _AFD_CONTROL_CODE(AFD_TRANSMIT_FILE, METHOD_NEITHER) // 0x1207F\n#define IOCTL_AFD_SUPER_ACCEPT                _AFD_CONTROL_CODE(AFD_SUPER_ACCEPT, METHOD_NEITHER) // 0x12083\n#define IOCTL_AFD_EVENT_SELECT                _AFD_CONTROL_CODE(AFD_EVENT_SELECT, METHOD_NEITHER) // 0x12087\n#define IOCTL_AFD_ENUM_NETWORK_EVENTS         _AFD_CONTROL_CODE(AFD_ENUM_NETWORK_EVENTS, METHOD_NEITHER) // 0x1208B\n#define IOCTL_AFD_DEFER_ACCEPT                _AFD_CONTROL_CODE(AFD_DEFER_ACCEPT, METHOD_BUFFERED) // 0x1208C\n#define IOCTL_AFD_WAIT_FOR_LISTEN_LIFO        _AFD_CONTROL_CODE(AFD_WAIT_FOR_LISTEN_LIFO, METHOD_BUFFERED) // 0x12090\n#define IOCTL_AFD_SET_QOS                     _AFD_CONTROL_CODE(AFD_SET_QOS, METHOD_BUFFERED) // 0x12094\n#define IOCTL_AFD_GET_QOS                     _AFD_CONTROL_CODE(AFD_GET_QOS, METHOD_BUFFERED) // 0x12098\n#define IOCTL_AFD_NO_OPERATION                _AFD_CONTROL_CODE(AFD_NO_OPERATION, METHOD_NEITHER) // 0x1209F\n#define IOCTL_AFD_VALIDATE_GROUP              _AFD_CONTROL_CODE(AFD_VALIDATE_GROUP, METHOD_BUFFERED) // 0x120A0\n#define IOCTL_AFD_GET_UNACCEPTED_CONNECT_DATA _AFD_CONTROL_CODE(AFD_GET_UNACCEPTED_CONNECT_DATA, METHOD_NEITHER) // 0x120A7\n#define IOCTL_AFD_ROUTING_INTERFACE_QUERY     _AFD_CONTROL_CODE(AFD_ROUTING_INTERFACE_QUERY, METHOD_NEITHER) // 0x120AB\n#define IOCTL_AFD_ROUTING_INTERFACE_CHANGE    _AFD_CONTROL_CODE(AFD_ROUTING_INTERFACE_CHANGE, METHOD_BUFFERED) // 0x120AC\n#define IOCTL_AFD_ADDRESS_LIST_QUERY          _AFD_CONTROL_CODE(AFD_ADDRESS_LIST_QUERY, METHOD_NEITHER) // 0x120B3\n#define IOCTL_AFD_ADDRESS_LIST_CHANGE         _AFD_CONTROL_CODE(AFD_ADDRESS_LIST_CHANGE, METHOD_BUFFERED) // 0x120B4\n#define IOCTL_AFD_JOIN_LEAF                   _AFD_CONTROL_CODE(AFD_JOIN_LEAF, METHOD_NEITHER) // 0x120BB\n#define IOCTL_AFD_TRANSPORT_IOCTL             _AFD_CONTROL_CODE(AFD_TRANSPORT_IOCTL, METHOD_NEITHER) // 0x120BF\n#define IOCTL_AFD_TRANSMIT_PACKETS            _AFD_CONTROL_CODE(AFD_TRANSMIT_PACKETS, METHOD_NEITHER) // 0x120C3\n#define IOCTL_AFD_SUPER_CONNECT               _AFD_CONTROL_CODE(AFD_SUPER_CONNECT, METHOD_NEITHER) // 0x120C7\n#define IOCTL_AFD_SUPER_DISCONNECT            _AFD_CONTROL_CODE(AFD_SUPER_DISCONNECT, METHOD_NEITHER) // 0x120CB\n#define IOCTL_AFD_RECEIVE_MESSAGE             _AFD_CONTROL_CODE(AFD_RECEIVE_MESSAGE, METHOD_NEITHER) // 0x120CF\n#define IOCTL_AFD_SEND_MESSAGE                _AFD_CONTROL_CODE(AFD_SEND_MESSAGE, METHOD_NEITHER) // 0x120D3 // rev // since VISTA\n#define IOCTL_AFD_SWITCH_CEMENT_SAN           _AFD_CONTROL_CODE(AFD_SWITCH_CEMENT_SAN, METHOD_NEITHER) // 0x120D7\n#define IOCTL_AFD_SWITCH_SET_EVENTS           _AFD_CONTROL_CODE(AFD_SWITCH_SET_EVENTS, METHOD_NEITHER) // 0x120DB\n#define IOCTL_AFD_SWITCH_RESET_EVENTS         _AFD_CONTROL_CODE(AFD_SWITCH_RESET_EVENTS, METHOD_NEITHER) // 0x120DF\n#define IOCTL_AFD_SWITCH_CONNECT_IND          _AFD_CONTROL_CODE(AFD_SWITCH_CONNECT_IND, METHOD_OUT_DIRECT) // 0x120E2\n#define IOCTL_AFD_SWITCH_CMPL_ACCEPT          _AFD_CONTROL_CODE(AFD_SWITCH_CMPL_ACCEPT, METHOD_NEITHER) // 0x120E7\n#define IOCTL_AFD_SWITCH_CMPL_REQUEST         _AFD_CONTROL_CODE(AFD_SWITCH_CMPL_REQUEST, METHOD_NEITHER) // 0x120EB\n#define IOCTL_AFD_SWITCH_CMPL_IO              _AFD_CONTROL_CODE(AFD_SWITCH_CMPL_IO, METHOD_NEITHER) // 0x120EF\n#define IOCTL_AFD_SWITCH_REFRESH_ENDP         _AFD_CONTROL_CODE(AFD_SWITCH_REFRESH_ENDP, METHOD_NEITHER) // 0x120F3\n#define IOCTL_AFD_SWITCH_GET_PHYSICAL_ADDR    _AFD_CONTROL_CODE(AFD_SWITCH_GET_PHYSICAL_ADDR, METHOD_NEITHER) // 0x120F7\n#define IOCTL_AFD_SWITCH_ACQUIRE_CTX          _AFD_CONTROL_CODE(AFD_SWITCH_ACQUIRE_CTX, METHOD_NEITHER) // 0x120FB\n#define IOCTL_AFD_SWITCH_TRANSFER_CTX         _AFD_CONTROL_CODE(AFD_SWITCH_TRANSFER_CTX, METHOD_NEITHER) // 0x120FF\n#define IOCTL_AFD_SWITCH_GET_SERVICE_PID      _AFD_CONTROL_CODE(AFD_SWITCH_GET_SERVICE_PID, METHOD_NEITHER) // 0x12103\n#define IOCTL_AFD_SWITCH_SET_SERVICE_PROCESS  _AFD_CONTROL_CODE(AFD_SWITCH_SET_SERVICE_PROCESS, METHOD_NEITHER) // 0x12107\n#define IOCTL_AFD_SWITCH_PROVIDER_CHANGE      _AFD_CONTROL_CODE(AFD_SWITCH_PROVIDER_CHANGE, METHOD_NEITHER) // 0x1210B\n#define IOCTL_AFD_SWITCH_ADDRLIST_CHANGE      _AFD_CONTROL_CODE(AFD_SWITCH_ADDRLIST_CHANGE, METHOD_BUFFERED) // 0x1210C\n#define IOCTL_AFD_UNBIND                      _AFD_CONTROL_CODE(AFD_UNBIND, METHOD_NEITHER) // 0x12113 // rev\n#define IOCTL_AFD_SQM                         _AFD_CONTROL_CODE(AFD_SQM, METHOD_NEITHER) // 0x12117 // rev // since WIN7\n#define IOCTL_AFD_RIO                         _AFD_CONTROL_CODE(AFD_RIO, METHOD_NEITHER) // 0x1211B // rev // since WIN8\n#define IOCTL_AFD_TRANSFER_BEGIN              _AFD_CONTROL_CODE(AFD_TRANSFER_BEGIN, METHOD_NEITHER) // 0x1211F // rev // since TH1\n#define IOCTL_AFD_TRANSFER_END                _AFD_CONTROL_CODE(AFD_TRANSFER_END, METHOD_NEITHER) // 0x12123 // rev\n#define IOCTL_AFD_NOTIFY                      _AFD_CONTROL_CODE(AFD_NOTIFY, METHOD_NEITHER) // 0x12127 // rev // since 22H2\n\n#include <pshpack1.h>\n\n// rev - a union for TLI/TDI socket addresses\ntypedef union _AFD_ADDRESS\n{\n    SOCKADDR_STORAGE TliAddress;\n    TDI_ADDRESS_INFO TdiAddress;\n\n    struct\n    {\n        //\n        // TDI_ADDRESS_INFO includes an embedded socket address that starts at AddressType (which corresponds to sa_family).\n        //\n        // ---------------- | ------------------------- |\n        //                  | ULONG ActivityCount       |\n        //                  | ------------------------- | --------------------- |\n        //                  |                           | ULONG TAAddressCount  |\n        //                  |                           | --------------------- | ---------------------------- |\n        //                  |                           |                       | USHORT AddressLength         |\n        // TDI_ADDRESS_INFO | TRANSPORT_ADDRESS Address |                       | ---------------------------- | ---------- | ---------------- |\n        //                  |                           | TA_ADDRESS Address[1] | USHORT AddressType           |            | USHORT sa_family |\n        //                  |                           |                       | ---------------------------- |  SOCKADDR  | ---------------- |\n        //                  |                           |                       | UCHAR Address[AddressLength] | (embedded) |       ...        |\n        //                  |                           |                       |             ...              |            |                  |\n        // ---------------- | ------------------------- | --------------------- | ---------------------------- | ---------- | ---------------- |\n        //\n\n        UCHAR Padding[10]; // RTL_SIZEOF_THROUGH_FIELD(TDI_ADDRESS_INFO, Address.Address[0].AddressLength)\n        SOCKADDR_STORAGE EmbeddedAddress;\n    } TdiAddressUnpacked;\n} AFD_ADDRESS, *PAFD_ADDRESS;\n\n#include <poppack.h>\n\n// private // Bind share access\n#define AFD_NORMALADDRUSE    0\n#define AFD_REUSEADDRESS     1\n#define AFD_WILDCARDADDRESS  2\n#define AFD_EXCLUSIVEADDRUSE 3\n\n// private\ntypedef struct _AFD_BIND_INFO\n{\n    ULONG ShareAccess;\n    TRANSPORT_ADDRESS Address;\n} AFD_BIND_INFO, *PAFD_BIND_INFO;\n\n// private\ntypedef struct _AFD_BIND_INFO_TL\n{\n    ULONG ShareAccess;\n    SOCKADDR Address;\n} AFD_BIND_INFO_TL, *PAFD_BIND_INFO_TL;\n\n// private\ntypedef struct _AFD_CONNECT_JOIN_INFO\n{\n    BOOLEAN SanActive;\n    HANDLE RootEndpoint;\n    HANDLE ConnectEndpoint;\n    TRANSPORT_ADDRESS RemoteAddress;\n} AFD_CONNECT_JOIN_INFO, *PAFD_CONNECT_JOIN_INFO;\n\n// private\ntypedef struct _AFD_CONNECT_JOIN_INFO_TL\n{\n    BOOLEAN SanActive;\n    HANDLE RootEndpoint;\n    HANDLE ConnectEndpoint;\n    SOCKADDR RemoteAddress;\n} AFD_CONNECT_JOIN_INFO_TL, *PAFD_CONNECT_JOIN_INFO_TL;\n\n// private\ntypedef struct _AFD_LISTEN_INFO\n{\n    BOOLEAN SanActive;\n    ULONG MaximumConnectionQueue;\n    BOOLEAN UseDelayedAcceptance;\n} AFD_LISTEN_INFO, *PAFD_LISTEN_INFO;\n\n// private\ntypedef struct _AFD_LISTEN_RESPONSE_INFO\n{\n    LONG Sequence;\n    TRANSPORT_ADDRESS RemoteAddress;\n} AFD_LISTEN_RESPONSE_INFO, *PAFD_LISTEN_RESPONSE_INFO;\n\n// private\ntypedef struct _AFD_LISTEN_RESPONSE_INFO_TL\n{\n    LONG Sequence;\n    SOCKADDR RemoteAddress;\n} AFD_LISTEN_RESPONSE_INFO_TL, *PAFD_LISTEN_RESPONSE_INFO_TL;\n\n// private\ntypedef struct _AFD_ACCEPT_INFO\n{\n    BOOLEAN SanActive;\n    LONG Sequence;\n    HANDLE AcceptHandle;\n} AFD_ACCEPT_INFO, *PAFD_ACCEPT_INFO;\n\n// private // AfdFlags\n#define AFD_NO_FAST_IO 0x0001\n#define AFD_OVERLAPPED 0x0002\n\n// private\ntypedef struct _AFD_RECV_INFO\n{\n    _Field_size_(BufferCount) LPWSABUF BufferArray;\n    ULONG BufferCount;\n    ULONG AfdFlags;\n    ULONG TdiFlags; // TDI_RECEIVE_*\n} AFD_RECV_INFO, *PAFD_RECV_INFO;\n\n// private\ntypedef struct _AFD_DATAGRAM_INFO\n{\n    _Field_size_(BufferCount) LPWSABUF BufferArray;\n    ULONG BufferCount;\n    ULONG AfdFlags;\n    ULONG TdiFlags; // TDI_RECEIVE_*\n    PVOID Address;\n    PULONG AddressLength;\n} AFD_DATAGRAM_INFO, *PAFD_DATAGRAM_INFO;\n\n// private\ntypedef struct _AFD_SEND_INFO\n{\n    _Field_size_(BufferCount) LPWSABUF BufferArray;\n    ULONG BufferCount;\n    ULONG AfdFlags;\n    ULONG TdiFlags; // TDI_RECEIVE_*\n} AFD_SEND_INFO, *PAFD_SEND_INFO;\n\n// private\ntypedef struct _AFD_SEND_DATAGRAM_INFO\n{\n    _Field_size_(BufferCount) LPWSABUF BufferArray;\n    ULONG BufferCount;\n    ULONG AfdFlags;\n    TDI_REQUEST_SEND_DATAGRAM TdiRequest;\n    TDI_CONNECTION_INFORMATION TdiConnInfo;\n} AFD_SEND_DATAGRAM_INFO, *PAFD_SEND_DATAGRAM_INFO;\n\n// private // Poll event bit numbers\n#define AFD_POLL_RECEIVE_BIT             0\n#define AFD_POLL_RECEIVE_EXPEDITED_BIT   1\n#define AFD_POLL_SEND_BIT                2\n#define AFD_POLL_DISCONNECT_BIT          3\n#define AFD_POLL_ABORT_BIT               4\n#define AFD_POLL_LOCAL_CLOSE_BIT         5\n#define AFD_POLL_CONNECT_BIT             6\n#define AFD_POLL_ACCEPT_BIT              7\n#define AFD_POLL_CONNECT_FAIL_BIT        8\n#define AFD_POLL_QOS_BIT                 9\n#define AFD_POLL_GROUP_QOS_BIT           10\n#define AFD_POLL_ROUTING_IF_CHANGE_BIT   11\n#define AFD_POLL_ADDRESS_LIST_CHANGE_BIT 12\n#define AFD_NUM_POLL_EVENTS              13\n\n// private // Poll event flags\n#define AFD_POLL_RECEIVE             (1 << AFD_POLL_RECEIVE_BIT) // 0x0001\n#define AFD_POLL_RECEIVE_EXPEDITED   (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT) // 0x0002\n#define AFD_POLL_SEND                (1 << AFD_POLL_SEND_BIT) // 0x0004\n#define AFD_POLL_DISCONNECT          (1 << AFD_POLL_DISCONNECT_BIT) // 0x0008\n#define AFD_POLL_ABORT               (1 << AFD_POLL_ABORT_BIT) // 0x0010\n#define AFD_POLL_LOCAL_CLOSE         (1 << AFD_POLL_LOCAL_CLOSE_BIT) // 0x0020\n#define AFD_POLL_CONNECT             (1 << AFD_POLL_CONNECT_BIT) // 0x0040\n#define AFD_POLL_ACCEPT              (1 << AFD_POLL_ACCEPT_BIT) // 0x0080\n#define AFD_POLL_CONNECT_FAIL        (1 << AFD_POLL_CONNECT_FAIL_BIT) // 0x0100\n#define AFD_POLL_QOS                 (1 << AFD_POLL_QOS_BIT) // 0x0200\n#define AFD_POLL_GROUP_QOS           (1 << AFD_POLL_GROUP_QOS_BIT) // 0x0400\n#define AFD_POLL_ROUTING_IF_CHANGE   (1 << AFD_POLL_ROUTING_IF_CHANGE_BIT) // 0x0800\n#define AFD_POLL_ADDRESS_LIST_CHANGE (1 << AFD_POLL_ADDRESS_LIST_CHANGE_BIT) // 0x1000\n#define AFD_POLL_ALL                 ((1 << AFD_NUM_POLL_EVENTS) - 1) // 0x1FFF\n#define AFD_POLL_SANCOUNTS_UPDATED   0x80000000\n\n// private\ntypedef struct _AFD_POLL_HANDLE_INFO\n{\n    HANDLE Handle;\n    ULONG PollEvents; // AFD_POLL_*\n    NTSTATUS Status;\n} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;\n\n// private\ntypedef struct _AFD_POLL_INFO\n{\n    LARGE_INTEGER Timeout;\n    ULONG NumberOfHandles;\n    BOOLEAN Unique;\n    _Field_size_(NumberOfHandles) AFD_POLL_HANDLE_INFO Handles[ANYSIZE_ARRAY];\n} AFD_POLL_INFO, *PAFD_POLL_INFO;\n\n// private // Disconnect flags\n#define AFD_PARTIAL_DISCONNECT_SEND    0x01\n#define AFD_PARTIAL_DISCONNECT_RECEIVE 0x02\n#define AFD_ABORTIVE_DISCONNECT        0x04\n#define AFD_UNCONNECT_DATAGRAM         0x08\n\n// private\ntypedef struct _AFD_PARTIAL_DISCONNECT_INFO\n{\n    ULONG DisconnectMode;\n    LARGE_INTEGER Timeout;\n} AFD_PARTIAL_DISCONNECT_INFO, *PAFD_PARTIAL_DISCONNECT_INFO;\n\n// private\ntypedef struct _AFD_RECEIVE_INFORMATION\n{\n    ULONG BytesAvailable;\n    ULONG ExpeditedBytesAvailable;\n} AFD_RECEIVE_INFORMATION, *PAFD_RECEIVE_INFORMATION;\n\n// private // Handle query flags\n#define AFD_QUERY_ADDRESS_HANDLE    0x01\n#define AFD_QUERY_CONNECTION_HANDLE 0x02\n\n// private\ntypedef struct _AFD_HANDLE_INFO\n{\n    HANDLE TdiAddressHandle;\n    HANDLE TdiConnectionHandle;\n} AFD_HANDLE_INFO, *PAFD_HANDLE_INFO;\n\n// private // InformationType\n#define AFD_INLINE_MODE                1 // s: BOOLEAN\n#define AFD_NONBLOCKING_MODE           2 // s: BOOLEAN\n#define AFD_MAX_SEND_SIZE              3 // q: ULONG\n#define AFD_SENDS_PENDING              4 // q: ULONG\n#define AFD_MAX_PATH_SEND_SIZE         5 // q: ULONG\n#define AFD_RECEIVE_WINDOW_SIZE        6 // q; s: ULONG\n#define AFD_SEND_WINDOW_SIZE           7 // q; s: ULONG\n#define AFD_CONNECT_TIME               8 // q: ULONG (in seconds)\n#define AFD_CIRCULAR_QUEUEING          9 // s: BOOLEAN\n#define AFD_GROUP_ID_AND_TYPE          10 // q: AFD_GROUP_INFO\n#define AFD_REPORT_PORT_UNREACHABLE    11 // s: BOOLEAN\n#define AFD_REPORT_NETWORK_UNREACHABLE 12 // s: BOOLEAN // rev\n#define AFD_DELIVERY_STATUS            14 // q: SIO_DELIVERY_STATUS // rev\n#define AFD_CANCEL_TL                  15 // s: void // rev\n\n// private\ntypedef enum _AFD_GROUP_TYPE\n{\n    GroupTypeNeither = 0,\n    GroupTypeUnconstrained = SG_UNCONSTRAINED_GROUP,\n    GroupTypeConstrained = SG_CONSTRAINED_GROUP,\n} AFD_GROUP_TYPE, *PAFD_GROUP_TYPE;\n\n// private\ntypedef struct _AFD_GROUP_INFO\n{\n    GROUP GroupID;\n    AFD_GROUP_TYPE GroupType;\n} AFD_GROUP_INFO, *PAFD_GROUP_INFO;\n\n// private\ntypedef struct _SIO_DELIVERY_STATUS\n{\n    BOOLEAN DeliveryAvailable;\n    ULONG PendedReceiveRequests;\n} SIO_DELIVERY_STATUS, *PSIO_DELIVERY_STATUS;\n\n// private\ntypedef struct _AFD_INFORMATION\n{\n    ULONG InformationType;\n    union\n    {\n        BOOLEAN Boolean;\n        ULONG Ulong;\n        LARGE_INTEGER LargeInteger;\n        AFD_GROUP_INFO GroupInfo; // rev\n        SIO_DELIVERY_STATUS DeliveryStatus; // rev\n    } Information;\n} AFD_INFORMATION, *PAFD_INFORMATION;\n\n// private\ntypedef enum _SOCKET_STATE\n{\n  SocketStateInitializing = -1,\n  SocketStateOpen = 0,\n  SocketStateBound = 1,\n  SocketStateBoundSpecific = 2,\n  SocketStateConnected = 3,\n  SocketStateClosing = 4,\n} SOCKET_STATE, *PSOCKET_STATE;\n\n// private\ntypedef struct _SOCK_SHARED_INFO\n{\n    SOCKET_STATE State;\n    LONG AddressFamily; // AF_*\n    LONG SocketType; // SOCK_*\n    LONG Protocol; // IPPROTO_*, BTHPROTO_*, HV_PROTOCOL_*, etc.\n    LONG LocalAddressLength;\n    LONG RemoteAddressLength;\n    LINGER LingerInfo;\n    ULONG SendTimeout; // in milliseconds\n    ULONG ReceiveTimeout; // in milliseconds\n    ULONG ReceiveBufferSize;\n    ULONG SendBufferSize;\n    union\n    {\n        USHORT Flags;\n        struct\n        {\n            USHORT Listening : 1;\n            USHORT Broadcast : 1;\n            USHORT Debug : 1;\n            USHORT OobInline : 1;\n            USHORT ReuseAddresses : 1;\n            USHORT ExclusiveAddressUse : 1;\n            USHORT NonBlocking : 1;\n            USHORT DontUseWildcard : 1;\n            USHORT ReceiveShutdown : 1;\n            USHORT SendShutdown : 1;\n            USHORT ConditionalAccept : 1;\n            USHORT IsSANSocket : 1;\n            USHORT fIsTLI : 1;\n            USHORT Rio : 1;\n            USHORT ReceiveBufferSizeSet : 1;\n            USHORT SendBufferSizeSet : 1;\n        };\n    };\n    ULONG CreationFlags; // WSA_FLAG_*\n    ULONG CatalogEntryId;\n    ULONG ServiceFlags1; // XP1_*\n    ULONG ProviderFlags; // PFL_*\n    GROUP GroupID;\n    AFD_GROUP_TYPE GroupType;\n    LONG GroupPriority;\n    LONG LastError;\n    union\n    {\n        HWND AsyncSelecthWnd;\n        ULONGLONG AsyncSelectWnd64;\n    };\n    ULONG AsyncSelectSerialNumber;\n    ULONG AsyncSelectwMsg;\n    LONG AsyncSelectlEvent;\n    LONG DisabledAsyncSelectEvents;\n    GUID ProviderId;\n} SOCK_SHARED_INFO, *PSOCK_SHARED_INFO;\n\n// private\ntypedef struct _AFD_UNACCEPTED_CONNECT_DATA_INFO\n{\n    LONG Sequence;\n    ULONG ConnectDataLength;\n    BOOLEAN LengthOnly;\n} AFD_UNACCEPTED_CONNECT_DATA_INFO, *PAFD_UNACCEPTED_CONNECT_DATA_INFO;\n\n// private // Transmit flags\n#define AFD_TF_DISCONNECT         0x01\n#define AFD_TF_REUSE_SOCKET       0x02\n#define AFD_TF_WRITE_BEHIND       0x04\n#define AFD_TF_USE_DEFAULT_WORKER 0x00\n#define AFD_TF_USE_SYSTEM_THREAD  0x10\n#define AFD_TF_USE_KERNEL_APC     0x20\n#define AFD_TF_WORKER_KIND_MASK   0x30\n\n// private\ntypedef struct _AFD_TRANSMIT_FILE_INFO\n{\n    LARGE_INTEGER Offset;\n    LARGE_INTEGER WriteLength;\n    ULONG SendPacketLength;\n    HANDLE FileHandle;\n    PVOID Head;\n    ULONG HeadLength;\n    PVOID Tail;\n    ULONG TailLength;\n    ULONG Flags; // AFD_TF_*\n} AFD_TRANSMIT_FILE_INFO, *PAFD_TRANSMIT_FILE_INFO;\n\n// private\ntypedef struct _AFD_SUPER_ACCEPT_INFO\n{\n    BOOLEAN SanActive;\n    BOOLEAN FixAddressAlignment;\n    HANDLE AcceptHandle;\n    ULONG ReceiveDataLength;\n    ULONG LocalAddressLength;\n    ULONG RemoteAddressLength;\n} AFD_SUPER_ACCEPT_INFO, *PAFD_SUPER_ACCEPT_INFO;\n\n// private\ntypedef struct _AFD_EVENT_SELECT_INFO\n{\n    HANDLE Event;\n    ULONG PollEvents; // AFD_POLL_*\n} AFD_EVENT_SELECT_INFO, *PAFD_EVENT_SELECT_INFO;\n\n// private\ntypedef struct _AFD_ENUM_NETWORK_EVENTS_INFO\n{\n    ULONG PollEvents; // AFD_POLL_*\n    NTSTATUS EventStatus[AFD_NUM_POLL_EVENTS];\n} AFD_ENUM_NETWORK_EVENTS_INFO, *PAFD_ENUM_NETWORK_EVENTS_INFO;\n\n// private\ntypedef struct _AFD_DEFER_ACCEPT_INFO\n{\n    LONG Sequence;\n    BOOLEAN Reject;\n} AFD_DEFER_ACCEPT_INFO, *PAFD_DEFER_ACCEPT_INFO;\n\n// private\ntypedef struct _AFD_QOS_INFO\n{\n    QOS Qos;\n    BOOLEAN GroupQos;\n} AFD_QOS_INFO, *PAFD_QOS_INFO;\n\n// private\ntypedef struct _AFD_VALIDATE_GROUP_INFO\n{\n    GROUP GroupID;\n    TRANSPORT_ADDRESS RemoteAddress;\n} AFD_VALIDATE_GROUP_INFO, *PAFD_VALIDATE_GROUP_INFO;\n\n// private\ntypedef struct _AFD_TRANSPORT_IOCTL_INFO\n{\n    HANDLE Handle;\n    _Field_size_bytes_(InputBufferLength) PVOID InputBuffer;\n    ULONG InputBufferLength;\n    ULONG IoControlCode;\n    ULONG AfdFlags;\n    ULONG PollEvent;\n} AFD_TRANSPORT_IOCTL_INFO, *PAFD_TRANSPORT_IOCTL_INFO;\n\n// rev - HV_PROTOCOL_RAW-level option in addition to ones in hvsocket.h\n#define HVSOCKET_CONTAINER_PASSTHRU     0x02 // q: ULONG\n\n// private\ntypedef enum TL_IO_CONTROL_TYPE\n{\n    TlEndpointIoControlType = 0,   // not supported\n    TlSetSockOptIoControlType = 1, // setsockopt\n    TlGetSockOptIoControlType = 2, // getsockopt\n    TlSocketIoControlType = 3,     // ioctlsocket // Level must be 0\n} TL_IO_CONTROL_TYPE, *PTL_IO_CONTROL_TYPE;\n\n// private\ntypedef struct _AFD_TL_IO_CONTROL_INFO\n{\n    TL_IO_CONTROL_TYPE Type;\n    ULONG Level; // SOL_* or IPPROTO_* or HV_PROTOCOL_RAW\n    ULONG IoControlCode; // SIO_*, SO_*, IP_*, IPV6_*, TCP_*, UDP_*, HVSOCKET_*, etc. (depending on type and level)\n    BOOLEAN EndpointIoctl; // must be TRUE\n    _Field_size_bytes_(InputBufferLength) PVOID InputBuffer;\n    SIZE_T InputBufferLength;\n} AFD_TL_IO_CONTROL_INFO, *PAFD_TL_IO_CONTROL_INFO;\n\n// private\ntypedef struct _AFD_TPACKETS_INFO\n{\n    _Field_size_(ElementCount) PTRANSMIT_PACKETS_ELEMENT ElementArray;\n    ULONG ElementCount;\n    ULONG SendSize;\n    ULONG Flags;\n} AFD_TPACKETS_INFO, *PAFD_TPACKETS_INFO;\n\n// private\ntypedef struct _AFD_SUPER_CONNECT_INFO\n{\n    BOOLEAN SanActive;\n    TRANSPORT_ADDRESS RemoteAddress;\n} AFD_SUPER_CONNECT_INFO, *PAFD_SUPER_CONNECT_INFO;\n\n// rev\ntypedef struct _AFD_SUPER_CONNECT_INFO_TL\n{\n    BOOLEAN SanActive;\n    SOCKADDR RemoteAddress;\n} AFD_SUPER_CONNECT_INFO_TL, *PAFD_SUPER_CONNECT_INFO_TL;\n\n// private\ntypedef struct _AFD_SUPER_DISCONNECT_INFO\n{\n    ULONG Flags; // same as partial disconnect\n} AFD_SUPER_DISCONNECT_INFO, *PAFD_SUPER_DISCONNECT_INFO;\n\n// private\ntypedef struct _AFD_MESSAGE_INFO\n{\n    AFD_DATAGRAM_INFO dgi;\n    _Field_size_bytes_(ControlLength) PVOID ControlBuffer;\n    PULONG ControlLength;\n    PULONG MsgFlags;\n} AFD_MESSAGE_INFO, *PAFD_MESSAGE_INFO;\n\n// private\ntypedef struct _AFD_SWITCH_CONTEXT\n{\n    LONG EventsActive;\n    LONG RcvCount;\n    LONG ExpCount;\n    LONG SndCount;\n    BOOLEAN SelectFlag;\n} AFD_SWITCH_CONTEXT, *PAFD_SWITCH_CONTEXT;\n\n// private\ntypedef struct _AFD_SWITCH_CONTEXT_INFO\n{\n    HANDLE SocketHandle;\n    PAFD_SWITCH_CONTEXT SwitchContext;\n} AFD_SWITCH_CONTEXT_INFO, *PAFD_SWITCH_CONTEXT_INFO;\n\n// private\ntypedef struct _AFD_SWITCH_EVENT_INFO\n{\n    HANDLE SocketHandle;\n    PAFD_SWITCH_CONTEXT SwitchContext;\n    ULONG EventBit; // AFD_POLL_*_BIT\n    NTSTATUS Status;\n} AFD_SWITCH_EVENT_INFO, *PAFD_SWITCH_EVENT_INFO;\n\n// private\ntypedef struct _AFD_SWITCH_CONNECT_INFO\n{\n    HANDLE ListenHandle;\n    PAFD_SWITCH_CONTEXT SwitchContext;\n    TRANSPORT_ADDRESS RemoteAddress;\n} AFD_SWITCH_CONNECT_INFO, *PAFD_SWITCH_CONNECT_INFO;\n\n// private\ntypedef struct _AFD_SWITCH_ACCEPT_INFO\n{\n    HANDLE AcceptHandle;\n    ULONG ReceiveLength;\n} AFD_SWITCH_ACCEPT_INFO, *PAFD_SWITCH_ACCEPT_INFO;\n\n// private\ntypedef struct _AFD_SWITCH_REQUEST_INFO\n{\n    HANDLE SocketHandle;\n    PAFD_SWITCH_CONTEXT SwitchContext;\n    PVOID RequestContext;\n    NTSTATUS RequestStatus;\n    ULONG DataOffset;\n} AFD_SWITCH_REQUEST_INFO, *PAFD_SWITCH_REQUEST_INFO;\n\n// private\ntypedef struct _AFD_SWITCH_ACQUIRE_CTX_INFO\n{\n    HANDLE SocketHandle;\n    PAFD_SWITCH_CONTEXT SwitchContext;\n    PVOID SocketCtxBuf;\n    ULONG SocketCtxBufSize;\n} AFD_SWITCH_ACQUIRE_CTX_INFO, *PAFD_SWITCH_ACQUIRE_CTX_INFO;\n\n// private\ntypedef struct _AFD_SWITCH_TRANSFER_CTX_INFO\n{\n    HANDLE SocketHandle;\n    PAFD_SWITCH_CONTEXT SwitchContext;\n    PVOID RequestContext;\n    PVOID SocketCtxBuf;\n    ULONG SocketCtxBufSize;\n    _Field_size_(RcvBufferCount) LPWSABUF RcvBufferArray;\n    ULONG RcvBufferCount;\n    NTSTATUS Status;\n} AFD_SWITCH_TRANSFER_CTX_INFO, *PAFD_SWITCH_TRANSFER_CTX_INFO;\n\n// private\ntypedef struct _AFD_UNBIND_INFO\n{\n    LONG AddressFamily; // AF_*\n    LONG Protocol; // IPPROTO_*, BTHPROTO_*, HV_PROTOCOL_*, etc.\n} AFD_UNBIND_INFO, *PAFD_UNBIND_INFO;\n\n// rev // SQM Control Codes\n#define AFD_SQM_CONTROL_CODE_STORE 1\n#define AFD_SQM_CONTROL_CODE_SWEEP -1\n\n// private\ntypedef struct _AFD_SQM_CONTROL\n{\n    ULONG Code; // AFD_SQM_CONTROL_CODE_*\n} AFD_SQM_CONTROL, *PAFD_SQM_CONTROL;\n\n// private\ntypedef struct _WINSOCK_SQM_SOCKTYPE_DESC\n{\n    ULONG StreamTCP : 1;\n    ULONG StreamOther : 1;\n    ULONG DatagramUDP : 1;\n    ULONG DatagramUDPMulticast : 1;\n    ULONG DatagramOther : 1;\n    ULONG RawTCP : 1;\n    ULONG RawUDP : 1;\n    ULONG RawOther : 1;\n    ULONG OtherSocketTypes : 1;\n    ULONG IPv6Socket : 1;\n    ULONG ProviderLoadedWSD : 1;\n    ULONG ProviderLoadedLSP : 1;\n    ULONG ProviderLoadedMultiLSP : 1;\n    ULONG NonMswsockBSP : 1;\n} WINSOCK_SQM_SOCKTYPE_DESC, *PWINSOCK_SQM_SOCKTYPE_DESC;\n\n// private\ntypedef struct _WINSOCK_SQM_SOCKTYPE_COUNTS\n{\n    ULONG MaxStreamSocketsConn;\n    ULONG MaxStreamSocketsListen;\n    ULONG MaxDatagramSockets;\n    ULONG MaxRawSockets;\n    ULONG MaxOtherSockets;\n} WINSOCK_SQM_SOCKTYPE_COUNTS, *PWINSOCK_SQM_SOCKTYPE_COUNTS;\n\n// private\ntypedef struct _WINSOCK_SQM_NONCORE_FUNC\n{\n    ULONG Select : 1;\n    ULONG WSAPoll : 1;\n    ULONG StreamWSAEventSelect : 1;\n    ULONG StreamWSAAsyncSelect : 1;\n    ULONG TransmitFile : 1;\n    ULONG StreamTransmitPackets : 1;\n    ULONG DisconnectEx : 1;\n    ULONG SocketReuse : 1;\n    ULONG StreamDuplicateSocket : 1;\n    ULONG ReadWriteFile : 1;\n    ULONG OOBSendRecv : 1;\n    ULONG StreamSoSndTimeO : 1;\n    ULONG StreamSoRcvTimeO : 1;\n    ULONG MsgWaitAll : 1;\n    ULONG StreamNonCoreSOLOptions : 1;\n    ULONG StreamNonCoreTCPOptions : 1;\n    ULONG StreamNonCoreIPOptions : 1;\n    ULONG StreamNonCoreOtherOptions : 1;\n    ULONG StreamNonCoreIOCTLs : 1;\n    ULONG StreamNonCoreWSASocket : 1;\n    ULONG NonCoreRecv : 1;\n    ULONG NonCoreSend : 1;\n    ULONG StreamNonCoreWSAIoctl : 1;\n    ULONG NonCoreWSAAccept : 1;\n    ULONG StreamNonCoreWSAConnect : 1;\n    ULONG StreamWSAJoinLeaf : 1;\n    ULONG StreamWSAGetQoSByName : 1;\n    ULONG WSASendDisconnect : 1;\n    ULONG WSARecvDisconnect : 1;\n} WINSOCK_SQM_NONCORE_FUNC, *PWINSOCK_SQM_NONCORE_FUNC;\n\n// private\ntypedef struct _WINSOCK_SQM_DEPRECATION_LIST\n{\n    ULONG bEnumProtocols : 1;\n    ULONG bGetNameByType : 1;\n    ULONG bGetService : 1;\n    ULONG bGetTypeByName : 1;\n    ULONG bSetService : 1;\n    ULONG bWSACancelBlockingCall : 1;\n    ULONG bWSAIsBlocking : 1;\n    ULONG bWSASetBlockingHook : 1;\n    ULONG bWSAUnhookBlockingHook : 1;\n    ULONG bGetAddressByName : 1;\n    ULONG bGetHostByAddr : 1;\n    ULONG bGetHostByName : 1;\n    ULONG bGetHostName : 1;\n    ULONG bGetProtoByName : 1;\n    ULONG bGetProtoByNumber : 1;\n    ULONG bGetServByName : 1;\n    ULONG bGetServByPort : 1;\n    ULONG bInetAddr : 1;\n    ULONG bInetNtoa : 1;\n    ULONG bWSAAsyncGetHostByAddr : 1;\n    ULONG bWSAAsyncGetHostByName : 1;\n    ULONG bWSAAsyncGetProtoByName : 1;\n    ULONG bWSAAsyncGetProtoByNumber : 1;\n    ULONG bWSAAsyncGetServByName : 1;\n    ULONG bWSAAsyncGetServByPort : 1;\n    ULONG bWSACancelAsyncRequest : 1;\n    ULONG bWSARecvEx : 1;\n} WINSOCK_SQM_DEPRECATION_LIST, *PWINSOCK_SQM_DEPRECATION_LIST;\n\n// private\ntypedef struct _WINSOCK_SQM_SOCK_OPTIONS\n{\n    ULONG SoSndBuf : 1;\n    ULONG SoRcvBuf : 1;\n    ULONG SoSndBuf0 : 1;\n    ULONG SoRcvBuf0 : 1;\n    ULONG SoKeepAliveOn : 1;\n    ULONG SoReuseAddrOn : 1;\n    ULONG SoExclusiveAddrUseOn : 1;\n    ULONG SoLingerOn : 1;\n    ULONG SoLingerOn0 : 1;\n    ULONG SoRandomizePortOn : 1;\n    ULONG SoPortScaleOn : 1;\n    ULONG SoCondAcceptOn : 1;\n    ULONG SoOobInlineOn : 1;\n    ULONG SoOther : 1;\n    ULONG TCPNoDelayOn : 1;\n    ULONG TCPOther : 1;\n    ULONG IPV6V6OnlyOff : 1;\n    ULONG IPV6ProtectLevel : 1;\n    ULONG IPOther : 1;\n    ULONG LevelOther : 1;\n    ULONG ISBQuery : 1;\n    ULONG ISBNotify : 1;\n    ULONG AddressQuery : 1;\n    ULONG AddressNotify : 1;\n    ULONG RouteQuery : 1;\n    ULONG RouteNotify : 1;\n    ULONG FionbioOn : 1;\n    ULONG Fionread : 1;\n    ULONG Siocatmark : 1;\n    ULONG Siokeepalivevals : 1;\n    ULONG Siosetcompatmode : 1;\n    ULONG Sioportreserve : 1;\n} WINSOCK_SQM_SOCK_OPTIONS, *PWINSOCK_SQM_SOCK_OPTIONS;\n\n// private\ntypedef struct _WINSOCK_SQM_MISC_BEHAVIOR\n{\n    ULONG SendEverPended : 1;\n    ULONG RecvEverPended : 1;\n    ULONG ShutdownSend : 1;\n    ULONG ShutdownRecv : 1;\n    ULONG WSASocketProtocol : 1;\n} WINSOCK_SQM_MISC_BEHAVIOR, *PWINSOCK_SQM_MISC_BEHAVIOR;\n\n// private\ntypedef struct _AFD_SQM_INFO\n{\n    AFD_SQM_CONTROL Control;\n    WCHAR AppName[16];\n    WCHAR LSPName[16];\n    ULONG AppVersion;\n    WINSOCK_SQM_SOCKTYPE_DESC SocketTypeDescriptor;\n    WINSOCK_SQM_SOCKTYPE_COUNTS SocketTypeCounts;\n    WINSOCK_SQM_NONCORE_FUNC NonCoreFunctions;\n    WINSOCK_SQM_DEPRECATION_LIST DeprecationList;\n    WINSOCK_SQM_SOCK_OPTIONS SocketOptions;\n    WINSOCK_SQM_MISC_BEHAVIOR MiscBehavior;\n} AFD_SQM_INFO, *PAFD_SQM_INFO;\n\n// private\ntypedef enum _AFD_RIO_COMMAND\n{\n    AfdRioCommandIdCreateCq = 0,         // in: AFD_RIO_COMMAND_CREATE_CQ; out: AFD_RIO_COMMAND_CREATE_CQ_RESULT\n    AfdRioCommandIdDestroyCq = 1,        // in: AFD_RIO_COMMAND_DESTROY_CQ\n    AfdRioCommandIdNotifyCq = 2,         // in: AFD_RIO_COMMAND_NOTIFY_CQ\n    AfdRioCommandIdCreateRqPair = 3,     // in: AFD_RIO_COMMAND_CREATE_RQ_PAIR\n    AfdRioCommandIdRegisterBuffer = 4,   // in: AFD_RIO_COMMAND_REGISTER_BUFFER; out: AFD_RIO_COMMAND_REGISTER_BUFFER_RESULT\n    AfdRioCommandIdDeregisterBuffer = 5, // in: AFD_RIO_COMMAND_DEREGISTER_BUFFER\n    AfdRioCommandIdPokeSend = 6,         // in: AFD_RIO_COMMAND_POKE_SEND\n    AfdRioCommandIdPokeReceive = 7,      // in: AFD_RIO_COMMAND_POKE_RECEIVE\n    AfdRioCommandIdResizeCq = 8,         // in: AFD_RIO_COMMAND_RESIZE_CQ\n    AfdRioCommandIdResizeRqPair = 9,     // in: AFD_RIO_COMMAND_RESIZE_RQ_PAIR\n    AfdRioCommandIdMaximum = 10,\n} AFD_RIO_COMMAND, *PAFD_RIO_COMMAND;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_HEADER\n{\n    AFD_RIO_COMMAND Command;\n} AFD_RIO_COMMAND_HEADER, *PAFD_RIO_COMMAND_HEADER;\n\n// private\ntypedef enum _AFD_RIO_NOTIFICATION_COMPLETION_TYPE\n{\n    AfdRioNoCompletion = 0,\n    AfdRioEventCompletion = 1,\n    AfdRioIocpCompletion = 2,\n} AFD_RIO_NOTIFICATION_COMPLETION_TYPE, *PAFD_RIO_NOTIFICATION_COMPLETION_TYPE;\n\n// private\ntypedef struct _AFD_RIO_COMPLETION_QUEUE\n{\n    ULONG QHead;\n    ULONG QTail;\n    BOOLEAN Corrupted;\n    RIORESULT QEntry[ANYSIZE_ARRAY];\n} AFD_RIO_COMPLETION_QUEUE, *PAFD_RIO_COMPLETION_QUEUE;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_CREATE_CQ\n{\n    AFD_RIO_COMMAND_HEADER Header;\n    ULONG QSize;\n    AFD_RIO_NOTIFICATION_COMPLETION_TYPE NotificationType;\n    ULONGLONG NotificationHandle;\n    ULONGLONG NotificationContext;\n    ULONGLONG NotificationContext2;\n    ULONG BufferSize;\n    ULONGLONG Buffer; // PAFD_RIO_COMPLETION_QUEUE\n} AFD_RIO_COMMAND_CREATE_CQ, *PAFD_RIO_COMMAND_CREATE_CQ;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_CREATE_CQ_RESULT\n{\n    ULONG CqId;\n} AFD_RIO_COMMAND_CREATE_CQ_RESULT, *PAFD_RIO_COMMAND_CREATE_CQ_RESULT;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_DESTROY_CQ\n{\n    AFD_RIO_COMMAND_HEADER Header;\n    ULONG CqId;\n} AFD_RIO_COMMAND_DESTROY_CQ, *PAFD_RIO_COMMAND_DESTROY_CQ;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_NOTIFY_CQ\n{\n    AFD_RIO_COMMAND_HEADER Header;\n    ULONG Index;\n} AFD_RIO_COMMAND_NOTIFY_CQ, *PAFD_RIO_COMMAND_NOTIFY_CQ;\n\n// private\ntypedef struct _AFD_RIO_BUF\n{\n    ULONG BufferId;\n    ULONG Offset;\n    ULONG Length;\n} AFD_RIO_BUF, *PAFD_RIO_BUF;\n\n// private\ntypedef struct _AFD_RIO_REQUEST_QUEUE_ENTRY\n{\n    AFD_RIO_BUF Data;\n    AFD_RIO_BUF SourceAddress;\n    AFD_RIO_BUF DestinationAddress;\n    AFD_RIO_BUF Control;\n    AFD_RIO_BUF FlagsBuffer;\n    ULONG Flags;\n    ULONGLONG Context;\n} AFD_RIO_REQUEST_QUEUE_ENTRY, *PAFD_RIO_REQUEST_QUEUE_ENTRY;\n\n// private\ntypedef struct _AFD_RIO_REQUEST_QUEUE\n{\n    ULONG Start;\n    ULONG End;\n    BOOLEAN PokeRequired;\n    AFD_RIO_REQUEST_QUEUE_ENTRY Entries[ANYSIZE_ARRAY];\n} AFD_RIO_REQUEST_QUEUE, *PAFD_RIO_REQUEST_QUEUE;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_CREATE_RQ_PAIR\n{\n    AFD_RIO_COMMAND_HEADER Header;\n    ULONG SendCompletionQueue;\n    ULONG ReceiveCompletionQueue;\n    ULONG SendQueueEntryCount;\n    ULONG SendQueueBufferSize;\n    ULONGLONG SendQueueBuffer; // PAFD_RIO_REQUEST_QUEUE\n    ULONG ReceiveQueueEntryCount;\n    ULONG ReceiveQueueBufferSize;\n    ULONGLONG ReceiveQueueBuffer; // PAFD_RIO_REQUEST_QUEUE\n    ULONGLONG EndpointHandle;\n    ULONGLONG SocketContext;\n} AFD_RIO_COMMAND_CREATE_RQ_PAIR, *PAFD_RIO_COMMAND_CREATE_RQ_PAIR;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_REGISTER_BUFFER\n{\n    AFD_RIO_COMMAND_HEADER Header;\n    ULONGLONG Buffer;\n    ULONG BufferLength;\n} AFD_RIO_COMMAND_REGISTER_BUFFER, *PAFD_RIO_COMMAND_REGISTER_BUFFER;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_REGISTER_BUFFER_RESULT\n{\n    ULONG BufferId;\n} AFD_RIO_COMMAND_REGISTER_BUFFER_RESULT, *PAFD_RIO_COMMAND_REGISTER_BUFFER_RESULT;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_DEREGISTER_BUFFER\n{\n    AFD_RIO_COMMAND_HEADER Header;\n    ULONG BufferId;\n} AFD_RIO_COMMAND_DEREGISTER_BUFFER, *PAFD_RIO_COMMAND_DEREGISTER_BUFFER;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_POKE_SEND\n{\n    AFD_RIO_COMMAND_HEADER Header;\n} AFD_RIO_COMMAND_POKE_SEND, *PAFD_RIO_COMMAND_POKE_SEND;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_POKE_RECEIVE\n{\n    AFD_RIO_COMMAND_HEADER Header;\n} AFD_RIO_COMMAND_POKE_RECEIVE, *PAFD_RIO_COMMAND_POKE_RECEIVE;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_RESIZE_CQ\n{\n    AFD_RIO_COMMAND_HEADER Header;\n    ULONG CqId;\n    ULONG QSize;\n    ULONG BufferSize;\n    ULONGLONG Buffer;\n} AFD_RIO_COMMAND_RESIZE_CQ, *PAFD_RIO_COMMAND_RESIZE_CQ;\n\n// private\ntypedef struct _AFD_RIO_COMMAND_RESIZE_RQ_PAIR\n{\n    AFD_RIO_COMMAND_HEADER Header;\n    ULONG SendQueueEntryCount;\n    ULONG SendQueueBufferSize;\n    ULONGLONG SendQueueBuffer;\n    ULONG ReceiveQueueEntryCount;\n    ULONG ReceiveQueueBufferSize;\n    ULONGLONG ReceiveQueueBuffer;\n} AFD_RIO_COMMAND_RESIZE_RQ_PAIR, *PAFD_RIO_COMMAND_RESIZE_RQ_PAIR;\n\n#endif\n"
  },
  {
    "path": "phnt/include/ntdbg.h",
    "content": "/*\n * Debugger support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTDBG_H\n#define _NTDBG_H\n\n//\n// Debugging\n//\n\n/**\n * Causes a user-mode breakpoint to occur.\n */\nNTSYSAPI\nVOID\nNTAPI\nDbgUserBreakPoint(\n    VOID\n    );\n\n/**\n * Causes a breakpoint to occur.\n */\nNTSYSAPI\nVOID\nNTAPI\nDbgBreakPoint(\n    VOID\n    );\n\n/**\n * Causes a breakpoint to occur with a specific status.\n *\n * \\param Status The status code to be associated with the breakpoint.\n */\nNTSYSAPI\nVOID\nNTAPI\nDbgBreakPointWithStatus(\n    _In_ ULONG Status\n    );\n\n#define DBG_STATUS_CONTROL_C 1\n#define DBG_STATUS_SYSRQ 2\n#define DBG_STATUS_BUGCHECK_FIRST 3\n#define DBG_STATUS_BUGCHECK_SECOND 4\n#define DBG_STATUS_FATAL 5\n#define DBG_STATUS_DEBUG_CONTROL 6\n#define DBG_STATUS_WORKER 7\n\n/**\n * Sends a message to the kernel debugger.\n *\n * \\param Format A pointer to a printf-style format string.\n * \\param ... Arguments for the format string.\n * \\return ULONG The number of characters printed.\n */\nNTSYSAPI\nULONG\nSTDAPIVCALLTYPE\nDbgPrint(\n    _In_z_ _Printf_format_string_ PCCH Format,\n    ...\n    );\n\n/**\n * Sends a message to the kernel debugger with a component ID and level.\n *\n * \\param ComponentId The ID of the component that is sending the message.\n * \\param Level The importance level of the message.\n * \\param Format A pointer to a printf-style format string.\n * \\param ... Arguments for the format string.\n * \\return ULONG The number of characters printed.\n */\nNTSYSAPI\nULONG\nSTDAPIVCALLTYPE\nDbgPrintEx(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_z_ _Printf_format_string_ PCCH Format,\n    ...\n    );\n\n/**\n * Sends a message to the kernel debugger with a component ID and level (va_list version).\n *\n * \\param ComponentId The ID of the component that is sending the message.\n * \\param Level The importance level of the message.\n * \\param Format A pointer to a printf-style format string.\n * \\param arglist A list of arguments for the format string.\n * \\return ULONG The number of characters printed.\n */\nNTSYSAPI\nULONG\nNTAPI\nvDbgPrintEx(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_z_ PCCH Format,\n    _In_ va_list arglist\n    );\n\n/**\n * Sends a message to the kernel debugger with a prefix, component ID, and level.\n *\n * \\param Prefix A pointer to a string to be prefixed to the message.\n * \\param ComponentId The ID of the component that is sending the message.\n * \\param Level The importance level of the message.\n * \\param Format A pointer to a printf-style format string.\n * \\param arglist A list of arguments for the format string.\n * \\return ULONG The number of characters printed.\n */\nNTSYSAPI\nULONG\nNTAPI\nvDbgPrintExWithPrefix(\n    _In_z_ PCCH Prefix,\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_z_ PCCH Format,\n    _In_ va_list arglist\n    );\n\n/**\n * Sends a message to the kernel debugger and returns Control-C status.\n *\n * \\param Format A pointer to a printf-style format string.\n * \\param ... Arguments for the format string.\n * \\return ULONG The number of characters printed.\n */\nNTSYSAPI\nULONG\nSTDAPIVCALLTYPE\nDbgPrintReturnControlC(\n    _In_z_ _Printf_format_string_ PCCH Format,\n    ...\n    );\n\n/**\n * Queries the debug filter state for a component.\n *\n * \\param ComponentId The ID of the component.\n * \\param Level The importance level.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgQueryDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level\n    );\n\n/**\n * Sets the debug filter state for a component.\n *\n * \\param ComponentId The ID of the component.\n * \\param Level The importance level.\n * \\param State The new state for the filter.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgSetDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_ BOOLEAN State\n    );\n\n/**\n * Prompts the user for input.\n *\n * \\param Prompt A pointer to the prompt string.\n * \\param Response A pointer to the buffer that receives the user response.\n * \\param Length The length of the response buffer, in bytes.\n * \\return ULONG The number of characters in the response.\n */\nNTSYSAPI\nULONG\nNTAPI\nDbgPrompt(\n    _In_ PCCH Prompt,\n    _Out_writes_bytes_(Length) PCH Response,\n    _In_ ULONG Length\n    );\n\n//\n// Definitions\n//\n\n/**\n * The DBGKM_EXCEPTION structure contains exception information for a debug event.\n */\ntypedef struct _DBGKM_EXCEPTION\n{\n    EXCEPTION_RECORD ExceptionRecord;\n    ULONG FirstChance;\n} DBGKM_EXCEPTION, *PDBGKM_EXCEPTION;\n\n/**\n * The DBGKM_CREATE_THREAD structure contains information about a newly created thread.\n */\ntypedef struct _DBGKM_CREATE_THREAD\n{\n    ULONG SubSystemKey;\n    PVOID StartAddress;\n} DBGKM_CREATE_THREAD, *PDBGKM_CREATE_THREAD;\n\n/**\n * The DBGKM_CREATE_PROCESS structure contains information about a newly created process.\n */\ntypedef struct _DBGKM_CREATE_PROCESS\n{\n    ULONG SubSystemKey;\n    HANDLE FileHandle;\n    PVOID BaseOfImage;\n    ULONG DebugInfoFileOffset;\n    ULONG DebugInfoSize;\n    DBGKM_CREATE_THREAD InitialThread;\n} DBGKM_CREATE_PROCESS, *PDBGKM_CREATE_PROCESS;\n\n/**\n * The DBGKM_EXIT_THREAD structure contains the exit status of a thread.\n */\ntypedef struct _DBGKM_EXIT_THREAD\n{\n    NTSTATUS ExitStatus;\n} DBGKM_EXIT_THREAD, *PDBGKM_EXIT_THREAD;\n\n/**\n * The DBGKM_EXIT_PROCESS structure contains the exit status of a process.\n */\ntypedef struct _DBGKM_EXIT_PROCESS\n{\n    NTSTATUS ExitStatus;\n} DBGKM_EXIT_PROCESS, *PDBGKM_EXIT_PROCESS;\n\n/**\n * The DBGKM_LOAD_DLL structure contains information about a loaded DLL.\n */\ntypedef struct _DBGKM_LOAD_DLL\n{\n    HANDLE FileHandle;\n    PVOID BaseOfDll;\n    ULONG DebugInfoFileOffset;\n    ULONG DebugInfoSize;\n    PVOID NamePointer;\n} DBGKM_LOAD_DLL, *PDBGKM_LOAD_DLL;\n\n/**\n * The DBGKM_UNLOAD_DLL structure contains the base address of an unloaded DLL.\n */\ntypedef struct _DBGKM_UNLOAD_DLL\n{\n    PVOID BaseAddress;\n} DBGKM_UNLOAD_DLL, *PDBGKM_UNLOAD_DLL;\n\n/**\n * The DBG_STATE enumeration defines the state of a debug object.\n */\ntypedef enum _DBG_STATE\n{\n    DbgIdle,\n    DbgReplyPending,\n    DbgCreateThreadStateChange,\n    DbgCreateProcessStateChange,\n    DbgExitThreadStateChange,\n    DbgExitProcessStateChange,\n    DbgExceptionStateChange,\n    DbgBreakpointStateChange,\n    DbgSingleStepStateChange,\n    DbgLoadDllStateChange,\n    DbgUnloadDllStateChange\n} DBG_STATE, *PDBG_STATE;\n\n/**\n * The DBGUI_CREATE_THREAD structure contains UI-level information about a newly created thread.\n */\ntypedef struct _DBGUI_CREATE_THREAD\n{\n    HANDLE HandleToThread;\n    DBGKM_CREATE_THREAD NewThread;\n} DBGUI_CREATE_THREAD, *PDBGUI_CREATE_THREAD;\n\n/**\n * The DBGUI_CREATE_PROCESS structure contains UI-level information about a newly created process.\n */\ntypedef struct _DBGUI_CREATE_PROCESS\n{\n    HANDLE HandleToProcess;\n    HANDLE HandleToThread;\n    DBGKM_CREATE_PROCESS NewProcess;\n} DBGUI_CREATE_PROCESS, *PDBGUI_CREATE_PROCESS;\n\n/**\n * The DBGUI_WAIT_STATE_CHANGE structure contains information about a debug state change.\n */\ntypedef struct _DBGUI_WAIT_STATE_CHANGE\n{\n    DBG_STATE NewState;\n    CLIENT_ID AppClientId;\n    union\n    {\n        DBGKM_EXCEPTION Exception;\n        DBGUI_CREATE_THREAD CreateThread;\n        DBGUI_CREATE_PROCESS CreateProcessInfo;\n        DBGKM_EXIT_THREAD ExitThread;\n        DBGKM_EXIT_PROCESS ExitProcess;\n        DBGKM_LOAD_DLL LoadDll;\n        DBGKM_UNLOAD_DLL UnloadDll;\n    } StateInfo;\n} DBGUI_WAIT_STATE_CHANGE, *PDBGUI_WAIT_STATE_CHANGE;\n\n#define DEBUG_READ_EVENT 0x0001\n#define DEBUG_PROCESS_ASSIGN 0x0002\n#define DEBUG_SET_INFORMATION 0x0004\n#define DEBUG_QUERY_INFORMATION 0x0008\n#define DEBUG_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \\\n    DEBUG_READ_EVENT | DEBUG_PROCESS_ASSIGN | DEBUG_SET_INFORMATION | \\\n    DEBUG_QUERY_INFORMATION)\n\n#define DEBUG_KILL_ON_CLOSE 0x1\n\n/**\n * The DEBUGOBJECTINFOCLASS enumeration defines the information classes for debug objects.\n */\ntypedef enum _DEBUGOBJECTINFOCLASS\n{\n    DebugObjectUnusedInformation,\n    DebugObjectKillProcessOnExitInformation, // s: ULONG\n    MaxDebugObjectInfoClass\n} DEBUGOBJECTINFOCLASS, *PDEBUGOBJECTINFOCLASS;\n\n//\n// System calls\n//\n\n/**\n * Creates a debug object.\n *\n * \\param DebugObjectHandle A pointer to a variable that receives the debug object handle.\n * \\param DesiredAccess The access rights desired for the debug object.\n * \\param ObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the debug object.\n * \\param Flags Flags for the debug object creation. (DEBUG_KILL_ON_CLOSE)\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateDebugObject(\n    _Out_ PHANDLE DebugObjectHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG Flags\n    );\n\n/**\n * Attaches a debugger to an active process.\n *\n * \\param ProcessHandle A handle to the process to be debugged.\n * \\param DebugObjectHandle A handle to the debug object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDebugActiveProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE DebugObjectHandle\n    );\n\n/**\n * Continues a thread that was stopped by a debug event.\n *\n * \\param DebugObjectHandle A handle to the debug object.\n * \\param ClientId A pointer to a CLIENT_ID structure that identifies the thread to be continued.\n * \\param ContinueStatus The status code to use when continuing the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDebugContinue(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ PCLIENT_ID ClientId,\n    _In_ NTSTATUS ContinueStatus\n    );\n\n/**\n * Stops debugging a process.\n *\n * \\param ProcessHandle A handle to the process.\n * \\param DebugObjectHandle A handle to the debug object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRemoveProcessDebug(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE DebugObjectHandle\n    );\n\n/**\n * Sets information for a debug object.\n *\n * \\param DebugObjectHandle A handle to the debug object.\n * \\param DebugObjectInformationClass The information class to be set.\n * \\param DebugInformation A pointer to the buffer that contains the information.\n * \\param DebugInformationLength The length of the information buffer, in bytes.\n * \\param ReturnLength Optional. A pointer to a variable that receives the number of bytes returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationDebugObject(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ DEBUGOBJECTINFOCLASS DebugObjectInformationClass,\n    _In_reads_bytes_(DebugInformationLength) PVOID DebugInformation,\n    _In_ ULONG DebugInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n/**\n * Waits for a debug event to occur.\n *\n * \\param DebugObjectHandle A handle to the debug object.\n * \\param Alertable Specifies whether the wait is alertable.\n * \\param Timeout Optional. A pointer to a LARGE_INTEGER structure that specifies the timeout.\n * \\param WaitStateChange A pointer to a DBGUI_WAIT_STATE_CHANGE structure that receives information about the debug event.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForDebugEvent(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _Out_ PDBGUI_WAIT_STATE_CHANGE WaitStateChange\n    );\n\n//\n// Debugging UI\n//\n\n/**\n * Connects the current thread to the debugger.\n *\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiConnectToDbg(\n    VOID\n    );\n\n/**\n * Retrieves the debug object handle for the current thread.\n *\n * \\return HANDLE The debug object handle.\n */\nNTSYSAPI\nHANDLE\nNTAPI\nDbgUiGetThreadDebugObject(\n    VOID\n    );\n\n/**\n * Sets the debug object handle for the current thread.\n *\n * \\param DebugObject The debug object handle.\n */\nNTSYSAPI\nVOID\nNTAPI\nDbgUiSetThreadDebugObject(\n    _In_ HANDLE DebugObject\n    );\n\n/**\n * Waits for a debug state change.\n *\n * \\param StateChange A pointer to a DBGUI_WAIT_STATE_CHANGE structure that receives the state change information.\n * \\param Timeout Optional. A pointer to a LARGE_INTEGER structure that specifies the timeout.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiWaitStateChange(\n    _Out_ PDBGUI_WAIT_STATE_CHANGE StateChange,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n/**\n * Continues a debug state change.\n *\n * \\param AppClientId A pointer to a CLIENT_ID structure that identifies the thread to be continued.\n * \\param ContinueStatus The status code to use when continuing the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiContinue(\n    _In_ PCLIENT_ID AppClientId,\n    _In_ NTSTATUS ContinueStatus\n    );\n\n/**\n * Stops debugging a process.\n *\n * \\param Process A handle to the process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiStopDebugging(\n    _In_ HANDLE Process\n    );\n\n/**\n * Attaches a debugger to an active process.\n *\n * \\param Process A handle to the process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiDebugActiveProcess(\n    _In_ HANDLE Process\n    );\n\n/**\n * Remotely triggers a breakpoint in a process.\n *\n * \\param Context A pointer to the context for the breakpoint.\n */\nNTSYSAPI\nVOID\nNTAPI\nDbgUiRemoteBreakin(\n    _In_ PVOID Context\n    );\n\n/**\n * Issues a remote breakpoint in a process.\n *\n * \\param Process A handle to the process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiIssueRemoteBreakin(\n    _In_ HANDLE Process\n    );\n\n/**\n * Converts a state change structure to a debug event structure.\n *\n * \\param StateChange A pointer to a DBGUI_WAIT_STATE_CHANGE structure.\n * \\param DebugEvent A pointer to a DEBUG_EVENT structure that receives the converted information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiConvertStateChangeStructure(\n    _In_ PDBGUI_WAIT_STATE_CHANGE StateChange,\n    _Out_ LPDEBUG_EVENT DebugEvent\n    );\n\n/**\n * Converts a state change structure to a debug event structure (extended).\n *\n * \\param StateChange A pointer to a DBGUI_WAIT_STATE_CHANGE structure.\n * \\param DebugEvent A pointer to a DEBUG_EVENT structure that receives the converted information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiConvertStateChangeStructureEx(\n    _In_ PDBGUI_WAIT_STATE_CHANGE StateChange,\n    _Out_ LPDEBUG_EVENT DebugEvent\n    );\n\ntypedef struct _EVENT_FILTER_DESCRIPTOR *PEVENT_FILTER_DESCRIPTOR;\n\n/**\n * A callback function that receives event enabled notifications.\n */\ntypedef _Function_class_(ENABLECALLBACK)\nVOID NTAPI ENABLECALLBACK(\n    _In_ LPCGUID SourceId,\n    _In_ ULONG IsEnabled,\n    _In_ UCHAR Level,\n    _In_ ULONGLONG MatchAnyKeyword,\n    _In_ ULONGLONG MatchAllKeyword,\n    _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData,\n    _Inout_opt_ PVOID CallbackContext\n    );\ntypedef ENABLECALLBACK* PENABLECALLBACK;\n\ntypedef ULONGLONG REGHANDLE, *PREGHANDLE;\n\n/**\n * Registers an ETW event provider.\n *\n * \\param ProviderId A pointer to the provider ID.\n * \\param EnableCallback Optional. A pointer to the enable callback function.\n * \\param CallbackContext Optional. A pointer to the callback context.\n * \\param RegHandle A pointer to a variable that receives the registration handle.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nEtwEventRegister(\n    _In_ LPCGUID ProviderId,\n    _In_opt_ PENABLECALLBACK EnableCallback,\n    _In_opt_ PVOID CallbackContext,\n    _Out_ PREGHANDLE RegHandle\n    );\n\n#endif // _NTDBG_H\n"
  },
  {
    "path": "phnt/include/ntexapi.h",
    "content": "/*\n * Executive support library functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTEXAPI_H\n#define _NTEXAPI_H\n\ntypedef struct _TEB* PTEB;\ntypedef struct _COUNTED_REASON_CONTEXT* PCOUNTED_REASON_CONTEXT;\ntypedef struct _FILE_IO_COMPLETION_INFORMATION* PFILE_IO_COMPLETION_INFORMATION;\ntypedef struct _PORT_MESSAGE* PPORT_MESSAGE;\ntypedef struct _IMAGE_EXPORT_DIRECTORY* PIMAGE_EXPORT_DIRECTORY;\ntypedef struct _FILE_OBJECT* PFILE_OBJECT;\ntypedef struct _DEVICE_OBJECT* PDEVICE_OBJECT;\ntypedef struct _IRP* PIRP;\ntypedef struct _RTL_BITMAP* PRTL_BITMAP;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Thread execution\n//\n\n/**\n * The NtDelayExecution routine suspends the current thread until the specified condition is met.\n *\n * \\param Alertable The function returns when either the time-out period has elapsed or when the APC function is called.\n * \\param DelayInterval The time interval for which execution is to be suspended, in milliseconds.\n * - A value of zero causes the thread to relinquish the remainder of its time slice to any other thread that is ready to run.\n * - If there are no other threads ready to run, the function returns immediately, and the thread continues execution.\n * - A value of INFINITE indicates that the suspension should not time out.\n * \\return NTSTATUS Successful or errant status. The return value is STATUS_USER_APC when Alertable is TRUE, and the function returned due to one or more I/O completion callback functions.\n * \\remarks Note that a ready thread is not guaranteed to run immediately. Consequently, the thread will not run until some arbitrary time after the sleep interval elapses,\n * based upon the system \"tick\" frequency and the load factor from other processes.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepex\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDelayExecution(\n    _In_ BOOLEAN Alertable,\n    _In_ PLARGE_INTEGER DelayInterval\n    );\n\n//\n// Firmware environment values\n//\n\n/**\n * Retrieves the value of the specified firmware environment variable.\n * The user account that the app is running under must have the SE_SYSTEM_ENVIRONMENT_NAME privilege.\n *\n * \\param VariableName The name of the firmware environment variable. The pointer must not be NULL.\n * \\param VariableValue A pointer to a buffer that receives the value of the specified firmware environment variable.\n * \\param ValueLength The size of the \\c VariableValue buffer, in bytes.\n * \\param ReturnLength If the function succeeds, the return length is the number of bytes stored in the \\c VariableValue buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemEnvironmentValue(\n    _In_ PCUNICODE_STRING VariableName,\n    _Out_writes_bytes_(ValueLength) PWSTR VariableValue,\n    _In_ USHORT ValueLength,\n    _Out_opt_ PUSHORT ReturnLength\n    );\n\n// The firmware environment variable is stored in non-volatile memory (e.g. NVRAM).\n#define EFI_VARIABLE_NON_VOLATILE 0x00000001\n// The firmware environment variable can be accessed during boot service.\n#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002\n// The firmware environment variable can be accessed at runtime.\n#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004\n// Indicates hardware related errors encountered at runtime.\n#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008\n// Indicates an authentication requirement that must be met before writing to this firmware environment variable.\n#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010\n// Indicates authentication and time stamp requirements that must be met before writing to this firmware environment variable.\n// When this attribute is set, the buffer, represented by Buffer, will begin with an instance of a complete (and serialized) EFI_VARIABLE_AUTHENTICATION_2 descriptor.\n#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020\n// Append an existing environment variable with the value of Buffer. If the firmware does not support the operation, the function returns ERROR_INVALID_FUNCTION.\n#define EFI_VARIABLE_APPEND_WRITE 0x00000040\n// The firmware environment variable will return metadata in addition to variable data.\n#define EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS 0x00000080\n\n/**\n * Retrieves the value of the specified firmware environment variable and its attributes.\n * The user account that the app is running under must have the SE_SYSTEM_ENVIRONMENT_NAME privilege.\n *\n * \\param VariableName The name of the firmware environment variable. The pointer must not be NULL.\n * \\param VendorGuid The GUID that represents the namespace of the firmware environment variable.\n * \\param Buffer A pointer to a buffer that receives the value of the specified firmware environment variable.\n * \\param BufferLength The size of the \\c Buffer, in bytes.\n * \\param Attributes Bitmask identifying UEFI variable attributes associated with the variable.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemEnvironmentValueEx(\n    _In_ PCUNICODE_STRING VariableName,\n    _In_ PCGUID VendorGuid,\n    _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength,\n    _Out_opt_ PULONG Attributes // EFI_VARIABLE_*\n    );\n\n/**\n * Sets the value of the specified firmware environment variable.\n * The user account that the app is running under must have the SE_SYSTEM_ENVIRONMENT_NAME privilege.\n *\n * \\param VariableName The name of the firmware environment variable. The pointer must not be NULL.\n * \\param VariableValue A pointer to the new value for the firmware environment variable.\n * If this parameter is zero, the firmware environment variable is deleted.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSystemEnvironmentValue(\n    _In_ PCUNICODE_STRING VariableName,\n    _In_ PCUNICODE_STRING VariableValue\n    );\n\n/**\n * Sets the value of the specified firmware environment variable and the attributes that indicate how this variable is stored and maintained.\n * The user account that the app is running under must have the SE_SYSTEM_ENVIRONMENT_NAME privilege.\n *\n * \\param VariableName The name of the firmware environment variable. The pointer must not be NULL.\n * \\param VendorGuid The GUID that represents the namespace of the firmware environment variable.\n * \\param Buffer A pointer to the new value for the firmware environment variable.\n * \\param BufferLength The size of the pValue buffer, in bytes.\n * Unless the VARIABLE_ATTRIBUTE_APPEND_WRITE, VARIABLE_ATTRIBUTE_AUTHENTICATED_WRITE_ACCESS,\n * or VARIABLE_ATTRIBUTE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS variable attribute is set via dwAttributes,\n * setting this value to zero will result in the deletion of this variable.\n * \\param Attributes Bitmask to set UEFI variable attributes associated with the variable.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSystemEnvironmentValueEx(\n    _In_ PCUNICODE_STRING VariableName,\n    _In_ PCGUID VendorGuid,\n    _In_reads_bytes_opt_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength, // 0 = delete variable\n    _In_ ULONG Attributes // EFI_VARIABLE_*\n    );\n\ntypedef enum _SYSTEM_ENVIRONMENT_INFORMATION_CLASS\n{\n    SystemEnvironmentNameInformation = 1, // q: VARIABLE_NAME\n    SystemEnvironmentValueInformation = 2, // q: VARIABLE_NAME_AND_VALUE\n    MaxSystemEnvironmentInfoClass\n} SYSTEM_ENVIRONMENT_INFORMATION_CLASS;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _VARIABLE_NAME\n{\n    ULONG NextEntryOffset;\n    GUID VendorGuid;\n    WCHAR Name[ANYSIZE_ARRAY];\n} VARIABLE_NAME, *PVARIABLE_NAME;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _VARIABLE_NAME_AND_VALUE\n{\n    ULONG NextEntryOffset;\n    ULONG ValueOffset;\n    ULONG ValueLength;\n    ULONG Attributes;\n    GUID VendorGuid;\n    WCHAR Name[ANYSIZE_ARRAY];\n    //BYTE Value[ANYSIZE_ARRAY];\n} VARIABLE_NAME_AND_VALUE, *PVARIABLE_NAME_AND_VALUE;\n\n/**\n * The NtEnumerateSystemEnvironmentValuesEx routine enumerates system environment values with extended information.\n *\n * \\param InformationClass The class of system environment information to retrieve.\n * \\param Buffer Pointer to a buffer that receives the system environment values data.\n * \\param BufferLength Pointer to a ULONG variable that specifies the size of the Buffer on input.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnumerateSystemEnvironmentValuesEx(\n    _In_ ULONG InformationClass, // SYSTEM_ENVIRONMENT_INFORMATION_CLASS\n    _Out_ PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\n//\n// EFI\n//\n\n// private\ntypedef struct _BOOT_ENTRY\n{\n    ULONG Version;\n    ULONG Length;\n    ULONG Id;\n    ULONG Attributes;\n    ULONG FriendlyNameOffset;\n    ULONG BootFilePathOffset;\n    ULONG OsOptionsLength;\n    _Field_size_bytes_(OsOptionsLength) UCHAR OsOptions[1];\n} BOOT_ENTRY, *PBOOT_ENTRY;\n\n// private\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _BOOT_ENTRY_LIST\n{\n    ULONG NextEntryOffset;\n    BOOT_ENTRY BootEntry;\n} BOOT_ENTRY_LIST, *PBOOT_ENTRY_LIST;\n\n// private\ntypedef struct _BOOT_OPTIONS\n{\n    ULONG Version;\n    ULONG Length;\n    ULONG Timeout;\n    ULONG CurrentBootEntryId;\n    ULONG NextBootEntryId;\n    _Field_size_bytes_(Length) WCHAR HeadlessRedirection[1];\n} BOOT_OPTIONS, *PBOOT_OPTIONS;\n\n// private\ntypedef struct _FILE_PATH\n{\n    ULONG Version;\n    ULONG Length;\n    ULONG Type;\n    _Field_size_bytes_(Length) UCHAR FilePath[1];\n} FILE_PATH, *PFILE_PATH;\n\n// private\ntypedef struct _EFI_DRIVER_ENTRY\n{\n    ULONG Version;\n    ULONG Length;\n    ULONG Id;\n    ULONG FriendlyNameOffset;\n    ULONG DriverFilePathOffset;\n} EFI_DRIVER_ENTRY, *PEFI_DRIVER_ENTRY;\n\n// private\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _EFI_DRIVER_ENTRY_LIST\n{\n    ULONG NextEntryOffset;\n    EFI_DRIVER_ENTRY DriverEntry;\n} EFI_DRIVER_ENTRY_LIST, *PEFI_DRIVER_ENTRY_LIST;\n\n/**\n * The NtAddBootEntry routine adds a new boot entry to the system boot configuration.\n *\n * \\param BootEntry A pointer to a BOOT_ENTRY structure that specifies the boot entry to be added.\n * \\param Id A pointer to a variable that receives the identifier of the new boot entry.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAddBootEntry(\n    _In_ PBOOT_ENTRY BootEntry,\n    _Out_opt_ PULONG Id\n    );\n\n/**\n * The NtDeleteBootEntry routine deletes an existing boot entry from the system boot configuration.\n *\n * \\param Id The identifier of the boot entry to be deleted.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteBootEntry(\n    _In_ ULONG Id\n    );\n\n/**\n * The NtModifyBootEntry routine modifies an existing boot entry in the system boot configuration.\n *\n * \\param BootEntry A pointer to a BOOT_ENTRY structure that specifies the new boot entry information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtModifyBootEntry(\n    _In_ PBOOT_ENTRY BootEntry\n    );\n\n/**\n * The NtEnumerateBootEntries routine retrieves information about all boot entries in the system boot configuration.\n *\n * \\param Buffer A pointer to a buffer that receives the boot entries information.\n * \\param BufferLength A pointer to a variable that specifies the size of the buffer. On return, it contains the size of the data returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnumerateBootEntries(\n    _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\n/**\n * The NtQueryBootEntryOrder routine retrieves the current boot entry order.\n *\n * \\param Ids A pointer to a buffer that receives the identifiers of the boot entries in the current boot order.\n * \\param Count A pointer to a variable that specifies the number of entries in the buffer. On return, it contains the number of entries returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryBootEntryOrder(\n    _Out_writes_opt_(*Count) PULONG Ids,\n    _Inout_ PULONG Count\n    );\n\n/**\n * The NtSetBootEntryOrder routine sets the boot entry order.\n *\n * \\param Ids A pointer to a buffer that specifies the identifiers of the boot entries in the desired boot order.\n * \\param Count The number of entries in the buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetBootEntryOrder(\n    _In_reads_(Count) PULONG Ids,\n    _In_ ULONG Count\n    );\n\n/**\n * The NtQueryBootOptions routine retrieves the current boot options.\n *\n * \\param BootOptions A pointer to a buffer that receives the boot options.\n * \\param BootOptionsLength A pointer to a variable that specifies the size of the buffer. On return, it contains the size of the data returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryBootOptions(\n    _Out_writes_bytes_opt_(*BootOptionsLength) PBOOT_OPTIONS BootOptions,\n    _Inout_ PULONG BootOptionsLength\n    );\n\n/**\n * The NtSetBootOptions routine sets the boot options.\n *\n * \\param BootOptions A pointer to a BOOT_OPTIONS structure that specifies the new boot options.\n * \\param FieldsToChange A bitmask that specifies which fields in the BOOT_OPTIONS structure are to be changed.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetBootOptions(\n    _In_ PBOOT_OPTIONS BootOptions,\n    _In_ ULONG FieldsToChange\n    );\n\n/**\n * The NtTranslateFilePath routine translates a file path from one format to another.\n *\n * \\param InputFilePath A pointer to a FILE_PATH structure that specifies the input file path.\n * \\param OutputType The type of the output file path.\n * \\param OutputFilePath A pointer to a buffer that receives the translated file path.\n * \\param OutputFilePathLength A pointer to a variable that specifies the size of the buffer. On return, it contains the size of the data returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTranslateFilePath(\n    _In_ PFILE_PATH InputFilePath,\n    _In_ ULONG OutputType,\n    _Out_writes_bytes_opt_(*OutputFilePathLength) PFILE_PATH OutputFilePath,\n    _Inout_opt_ PULONG OutputFilePathLength\n    );\n\n/**\n * The NtAddDriverEntry routine adds a new driver entry to the system boot configuration.\n *\n * \\param DriverEntry A pointer to an EFI_DRIVER_ENTRY structure that specifies the driver entry to be added.\n * \\param Id A pointer to a variable that receives the identifier of the new driver entry.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAddDriverEntry(\n    _In_ PEFI_DRIVER_ENTRY DriverEntry,\n    _Out_opt_ PULONG Id\n    );\n\n/**\n * The NtDeleteDriverEntry routine deletes an existing driver entry from the system boot configuration.\n *\n * \\param Id The identifier of the driver entry to be deleted.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteDriverEntry(\n    _In_ ULONG Id\n    );\n\n/**\n * The NtModifyDriverEntry routine modifies an existing driver entry in the system boot configuration.\n *\n * \\param DriverEntry A pointer to an EFI_DRIVER_ENTRY structure that specifies the new driver entry information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtModifyDriverEntry(\n    _In_ PEFI_DRIVER_ENTRY DriverEntry\n    );\n\n/**\n * The NtEnumerateDriverEntries routine retrieves information about all driver entries in the system boot configuration.\n *\n * \\param Buffer A pointer to a buffer that receives the driver entries information.\n * \\param BufferLength A pointer to a variable that specifies the size of the buffer. On return, it contains the size of the data returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnumerateDriverEntries(\n    _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\n/**\n * The NtQueryDriverEntryOrder routine retrieves the current driver entry order.\n *\n * \\param Ids A pointer to a buffer that receives the identifiers of the driver entries in the current driver order.\n * \\param Count A pointer to a variable that specifies the number of entries in the buffer. On return, it contains the number of entries returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDriverEntryOrder(\n    _Out_writes_opt_(*Count) PULONG Ids,\n    _Inout_ PULONG Count\n    );\n\n/**\n * The NtSetDriverEntryOrder routine sets the driver entry order.\n *\n * \\param Ids A pointer to a buffer that specifies the identifiers of the driver entries in the desired driver order.\n * \\param Count The number of entries in the buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDriverEntryOrder(\n    _In_reads_(Count) PULONG Ids,\n    _In_ ULONG Count\n    );\n\ntypedef enum _FILTER_BOOT_OPTION_OPERATION\n{\n    FilterBootOptionOperationOpenSystemStore,\n    FilterBootOptionOperationSetElement,\n    FilterBootOptionOperationDeleteElement,\n    FilterBootOptionOperationMax\n} FILTER_BOOT_OPTION_OPERATION;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n/**\n * The NtFilterBootOption routine filters boot options based on the specified operation, object type, and element type.\n *\n * \\param FilterOperation The operation to be performed on the boot option. This can be one of the values from the FILTER_BOOT_OPTION_OPERATION enumeration.\n * \\param ObjectType The type of the object to be filtered.\n * \\param ElementType The type of the element within the object to be filtered.\n * \\param Data A pointer to a buffer that contains the data to be used in the filter operation. This parameter is optional and can be NULL.\n * \\param DataSize The size, in bytes, of the data buffer pointed to by the Data parameter.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFilterBootOption(\n    _In_ FILTER_BOOT_OPTION_OPERATION FilterOperation,\n    _In_ ULONG ObjectType,\n    _In_ ULONG ElementType,\n    _In_reads_bytes_opt_(DataSize) PVOID Data,\n    _In_ ULONG DataSize\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n//\n// Event\n//\n\n#ifndef EVENT_QUERY_STATE\n#define EVENT_QUERY_STATE 0x0001\n#endif\n\n#ifndef EVENT_MODIFY_STATE\n#define EVENT_MODIFY_STATE 0x0002\n#endif\n\n#ifndef EVENT_ALL_ACCESS\n#define EVENT_ALL_ACCESS (EVENT_QUERY_STATE|EVENT_MODIFY_STATE|STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE)\n#endif\n\n/**\n * The EVENT_INFORMATION_CLASS specifies the type of information to be retrieved about an event object.\n */\ntypedef enum _EVENT_INFORMATION_CLASS\n{\n    EventBasicInformation\n} EVENT_INFORMATION_CLASS;\n\n/**\n * The EVENT_BASIC_INFORMATION structure contains basic information about an event object.\n */\ntypedef struct _EVENT_BASIC_INFORMATION\n{\n    EVENT_TYPE EventType;   // The type of the event object (NotificationEvent or SynchronizationEvent).\n    LONG EventState;        // The current state of the event object. Nonzero if the event is signaled; zero if not signaled.\n} EVENT_BASIC_INFORMATION, *PEVENT_BASIC_INFORMATION;\n\n/**\n * The NtCreateEvent routine creates an event object, sets the initial state of the event to the specified value,\n * and opens a handle to the object with the specified desired access.\n *\n * \\param EventHandle A pointer to a variable that receives the event object handle.\n * \\param DesiredAccess The access mask that specifies the requested access to the event object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\param EventType The type of the event, which can be SynchronizationEvent or a NotificationEvent.\n * \\param InitialState The initial state of the event object.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwcreateevent\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateEvent(\n    _Out_ PHANDLE EventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ EVENT_TYPE EventType,\n    _In_ BOOLEAN InitialState\n    );\n\n/**\n * The NtOpenEvent routine opens a handle to an existing event object.\n *\n * \\param EventHandle A pointer to a variable that receives the event object handle.\n * \\param DesiredAccess The access mask that specifies the requested access to the event object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenEvent(\n    _Out_ PHANDLE EventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtSetEvent routine sets an event object to the signaled state.\n *\n * \\param EventHandle A handle to the event object.\n * \\param PreviousState A pointer to a variable that receives the previous state of the event object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetEvent(\n    _In_ HANDLE EventHandle,\n    _Out_opt_ PLONG PreviousState\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\n/**\n * The NtSetEventEx routine sets an event object to the signaled state and optionally acquires a lock.\n *\n * \\param ThreadId A handle to the thread.\n * \\param Lock A pointer to an RTL_SRWLOCK structure that specifies the lock to acquire.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetEventEx(\n    _In_ HANDLE ThreadId,\n    _In_opt_ PRTL_SRWLOCK Lock\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_11)\n\n/**\n * The NtSetEventBoostPriority routine sets an event object to the signaled state and boosts the priority of threads waiting on the event.\n *\n * \\param EventHandle A handle to the event object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetEventBoostPriority(\n    _In_ HANDLE EventHandle\n    );\n\n/**\n * The NtClearEvent routine sets an event object to the not-signaled state.\n *\n * \\param EventHandle A handle to the event object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtClearEvent(\n    _In_ HANDLE EventHandle\n    );\n\n/**\n * The NtResetEvent routine sets an event object to the not-signaled state and optionally returns the previous state.\n *\n * \\param EventHandle A handle to the event object.\n * \\param PreviousState A pointer to a variable that receives the previous state of the event object.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-resetevent\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtResetEvent(\n    _In_ HANDLE EventHandle,\n    _Out_opt_ PLONG PreviousState\n    );\n\n/**\n * The NtPulseEvent routine sets an event object to the signaled state and then resets it to the not-signaled state after releasing the appropriate number of waiting threads.\n *\n * \\param EventHandle A handle to the event object.\n * \\param PreviousState A pointer to a variable that receives the previous state of the event object.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-pulseevent\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPulseEvent(\n    _In_ HANDLE EventHandle,\n    _Out_opt_ PLONG PreviousState\n    );\n\n/**\n * The NtQueryEvent routine retrieves information about an event object.\n *\n * \\param EventHandle A handle to the event object.\n * \\param EventInformationClass The type of information to be retrieved.\n * \\param EventInformation A pointer to a buffer that receives the requested information.\n * \\param EventInformationLength The size of the buffer pointed to by EventInformation.\n * \\param ReturnLength A pointer to a variable that receives the size of the data returned in the buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryEvent(\n    _In_ HANDLE EventHandle,\n    _In_ EVENT_INFORMATION_CLASS EventInformationClass,\n    _Out_writes_bytes_(EventInformationLength) PVOID EventInformation,\n    _In_ ULONG EventInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n//\n// Event Pair\n//\n\n#define EVENT_PAIR_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE)\n\n/**\n * The NtCreateEventPair routine creates an event pair object and opens a handle to the object with the specified desired access.\n *\n * \\remark Event Pairs are used to communicate with protected subsystems (see Context Switches).\n * \\param EventPairHandle A pointer to a variable that receives the event pair object handle.\n * \\param DesiredAccess The access mask that specifies the requested access to the event pair object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateEventPair(\n    _Out_ PHANDLE EventPairHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtOpenEventPair routine opens a handle to an existing event pair object.\n *\n * \\param EventPairHandle A pointer to a variable that receives the event pair object handle.\n * \\param DesiredAccess The access mask that specifies the requested access to the event pair object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenEventPair(\n    _Out_ PHANDLE EventPairHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtSetLowEventPair routine sets the low event in an event pair to the signaled state.\n *\n * \\param EventPairHandle A handle to the event pair object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetLowEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\n/**\n * The NtSetHighEventPair routine sets the high event in an event pair to the signaled state.\n *\n * \\param EventPairHandle A handle to the event pair object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetHighEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\n/**\n * The NtWaitLowEventPair routine waits for the low event in an event pair to be set to the signaled state.\n *\n * \\param EventPairHandle A handle to the event pair object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitLowEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\n/**\n * The NtWaitHighEventPair routine waits for the high event in an event pair to be set to the signaled state.\n *\n * \\param EventPairHandle A handle to the event pair object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitHighEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\n/**\n * The NtSetLowWaitHighEventPair routine sets the low event in an event pair to the signaled state and waits for the high event to be set to the signaled state.\n *\n * \\param EventPairHandle A handle to the event pair object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetLowWaitHighEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\n/**\n * The NtSetHighWaitLowEventPair routine sets the high event in an event pair to the signaled state and waits for the low event to be set to the signaled state.\n *\n * \\param EventPairHandle A handle to the event pair object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetHighWaitLowEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\n//\n// Mutant\n//\n\n#ifndef MUTANT_QUERY_STATE\n#define MUTANT_QUERY_STATE 0x0001\n#endif\n\n#ifndef MUTANT_ALL_ACCESS\n#define MUTANT_ALL_ACCESS (MUTANT_QUERY_STATE|STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE)\n#endif\n\ntypedef enum _MUTANT_INFORMATION_CLASS\n{\n    MutantBasicInformation, // MUTANT_BASIC_INFORMATION\n    MutantOwnerInformation // MUTANT_OWNER_INFORMATION\n} MUTANT_INFORMATION_CLASS;\n\n/**\n * The MUTANT_BASIC_INFORMATION structure contains basic information about a mutant object.\n */\ntypedef struct _MUTANT_BASIC_INFORMATION\n{\n    LONG CurrentCount;\n    BOOLEAN OwnedByCaller;\n    BOOLEAN AbandonedState;\n} MUTANT_BASIC_INFORMATION, *PMUTANT_BASIC_INFORMATION;\n\n/**\n * The MUTANT_OWNER_INFORMATION structure contains information about the owner of a mutant object.\n */\ntypedef struct _MUTANT_OWNER_INFORMATION\n{\n    CLIENT_ID ClientId;\n} MUTANT_OWNER_INFORMATION, *PMUTANT_OWNER_INFORMATION;\n\n/**\n * The NtCreateMutant routine creates a mutant object, sets the initial state of the mutant to the specified value,\n * and opens a handle to the object with the specified desired access.\n *\n * \\param MutantHandle A pointer to a variable that receives the mutant object handle.\n * \\param DesiredAccess The access mask that specifies the requested access to the mutant object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\param InitialOwner If TRUE, the calling thread is the initial owner of the mutant object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateMutant(\n    _Out_ PHANDLE MutantHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ BOOLEAN InitialOwner\n    );\n\n/**\n * The NtOpenMutant routine opens a handle to an existing mutant object.\n *\n * \\param MutantHandle A pointer to a variable that receives the mutant object handle.\n * \\param DesiredAccess The access mask that specifies the requested access to the mutant object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenMutant(\n    _Out_ PHANDLE MutantHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtReleaseMutant routine releases ownership of a mutant object.\n *\n * \\param MutantHandle A handle to the mutant object.\n * \\param PreviousCount A pointer to a variable that receives the previous count of the mutant object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseMutant(\n    _In_ HANDLE MutantHandle,\n    _Out_opt_ PLONG PreviousCount\n    );\n\n/**\n * The NtQueryMutant routine retrieves information about a mutant object.\n *\n * \\param MutantHandle A handle to the mutant object.\n * \\param MutantInformationClass The type of information to be retrieved.\n * \\param MutantInformation A pointer to a buffer that receives the requested information.\n * \\param MutantInformationLength The size of the buffer pointed to by MutantInformation.\n * \\param ReturnLength A pointer to a variable that receives the size of the data returned in the buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryMutant(\n    _In_ HANDLE MutantHandle,\n    _In_ MUTANT_INFORMATION_CLASS MutantInformationClass,\n    _Out_writes_bytes_(MutantInformationLength) PVOID MutantInformation,\n    _In_ ULONG MutantInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n//\n// Semaphore\n//\n\n#ifndef SEMAPHORE_QUERY_STATE\n#define SEMAPHORE_QUERY_STATE 0x0001\n#endif\n\n#ifndef SEMAPHORE_MODIFY_STATE\n#define SEMAPHORE_MODIFY_STATE 0x0002\n#endif\n\n#ifndef SEMAPHORE_ALL_ACCESS\n#define SEMAPHORE_ALL_ACCESS (SEMAPHORE_QUERY_STATE|SEMAPHORE_MODIFY_STATE|STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE)\n#endif\n\ntypedef enum _SEMAPHORE_INFORMATION_CLASS\n{\n    SemaphoreBasicInformation\n} SEMAPHORE_INFORMATION_CLASS;\n\n/**\n * The SEMAPHORE_BASIC_INFORMATION structure contains basic information about a semaphore object.\n */\ntypedef struct _SEMAPHORE_BASIC_INFORMATION\n{\n    LONG CurrentCount;\n    LONG MaximumCount;\n} SEMAPHORE_BASIC_INFORMATION, *PSEMAPHORE_BASIC_INFORMATION;\n\n/**\n * The NtCreateSemaphore routine creates a semaphore object, sets the initial count of the semaphore to the specified value,\n * and opens a handle to the object with the specified desired access.\n *\n * \\param SemaphoreHandle A pointer to a variable that receives the semaphore object handle.\n * \\param DesiredAccess The access mask that specifies the requested access to the semaphore object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\param InitialCount The initial count of the semaphore object.\n * \\param MaximumCount The maximum count of the semaphore object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateSemaphore(\n    _Out_ PHANDLE SemaphoreHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ LONG InitialCount,\n    _In_ LONG MaximumCount\n    );\n\n/**\n * The NtOpenSemaphore routine opens a handle to an existing semaphore object.\n *\n * \\param SemaphoreHandle A pointer to a variable that receives the semaphore object handle.\n * \\param DesiredAccess The access mask that specifies the requested access to the semaphore object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenSemaphore(\n    _Out_ PHANDLE SemaphoreHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtReleaseSemaphore routine increases the count of the specified semaphore object by a specified amount.\n *\n * \\param SemaphoreHandle A handle to the semaphore object.\n * \\param ReleaseCount The amount by which the semaphore object's count is to be increased.\n * \\param PreviousCount A pointer to a variable that receives the previous count of the semaphore object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseSemaphore(\n    _In_ HANDLE SemaphoreHandle,\n    _In_ LONG ReleaseCount,\n    _Out_opt_ PLONG PreviousCount\n    );\n\n/**\n * The NtQuerySemaphore routine retrieves information about a semaphore object.\n *\n * \\param SemaphoreHandle A handle to the semaphore object.\n * \\param SemaphoreInformationClass The type of information to be retrieved.\n * \\param SemaphoreInformation A pointer to a buffer that receives the requested information.\n * \\param SemaphoreInformationLength The size of the buffer pointed to by SemaphoreInformation.\n * \\param ReturnLength A pointer to a variable that receives the size of the data returned in the buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySemaphore(\n    _In_ HANDLE SemaphoreHandle,\n    _In_ SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass,\n    _Out_writes_bytes_(SemaphoreInformationLength) PVOID SemaphoreInformation,\n    _In_ ULONG SemaphoreInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n//\n// Timer\n//\n\n#ifndef TIMER_QUERY_STATE\n#define TIMER_QUERY_STATE 0x0001\n#endif\n\n#ifndef TIMER_MODIFY_STATE\n#define TIMER_MODIFY_STATE 0x0002\n#endif\n\n#ifndef TIMER_ALL_ACCESS\n#define TIMER_ALL_ACCESS (TIMER_QUERY_STATE|TIMER_MODIFY_STATE|STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE)\n#endif\n\ntypedef enum _TIMER_INFORMATION_CLASS\n{\n    TimerBasicInformation // TIMER_BASIC_INFORMATION\n} TIMER_INFORMATION_CLASS;\n\ntypedef enum _TIMER_SET_INFORMATION_CLASS\n{\n    TimerSetCoalescableTimer, // TIMER_SET_COALESCABLE_TIMER_INFO\n    MaxTimerInfoClass\n} TIMER_SET_INFORMATION_CLASS;\n\n/**\n * The TIMER_BASIC_INFORMATION structure contains basic information about a timer object.\n */\ntypedef struct _TIMER_BASIC_INFORMATION\n{\n    LARGE_INTEGER RemainingTime;\n    BOOLEAN TimerState;\n} TIMER_BASIC_INFORMATION, *PTIMER_BASIC_INFORMATION;\n\ntypedef _Function_class_(TIMER_APC_ROUTINE)\nVOID NTAPI TIMER_APC_ROUTINE(\n    _In_ PVOID TimerContext,\n    _In_ ULONG TimerLowValue,\n    _In_ LONG TimerHighValue\n    );\ntypedef TIMER_APC_ROUTINE* PTIMER_APC_ROUTINE;\n\ntypedef struct _TIMER_SET_COALESCABLE_TIMER_INFO\n{\n    _In_ LARGE_INTEGER DueTime;\n    _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine;\n    _In_opt_ PVOID TimerContext;\n    _In_opt_ PCOUNTED_REASON_CONTEXT WakeContext;\n    _In_opt_ ULONG Period;\n    _In_ ULONG TolerableDelay;\n    _Out_opt_ PBOOLEAN PreviousState;\n} TIMER_SET_COALESCABLE_TIMER_INFO, *PTIMER_SET_COALESCABLE_TIMER_INFO;\n\n/**\n * The NtCreateTimer routine creates a timer object.\n *\n * \\param TimerHandle A pointer to a variable that receives the handle to the timer object.\n * \\param DesiredAccess The access mask that specifies the requested access to the timer object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\param TimerType The type of the timer object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateTimer(\n    _Out_ PHANDLE TimerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ TIMER_TYPE TimerType\n    );\n\n/**\n * The NtOpenTimer routine opens a handle to an existing timer object.\n *\n * \\param TimerHandle A pointer to a variable that receives the handle to the timer object.\n * \\param DesiredAccess The access mask that specifies the requested access to the timer object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenTimer(\n    _Out_ PHANDLE TimerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtSetTimer routine sets a timer object to the signaled state after a specified interval.\n *\n * \\param TimerHandle A handle to the timer object.\n * \\param DueTime A pointer to a LARGE_INTEGER that specifies the absolute or relative time at which the timer is to be set to the signaled state.\n * \\param TimerApcRoutine An optional pointer to a function to be called when the timer is signaled.\n * \\param TimerContext An optional pointer to a context to be passed to the APC routine.\n * \\param ResumeTimer If TRUE, resumes the timer; otherwise, sets a new timer.\n * \\param Period The period of the timer, in milliseconds. If zero, the timer is signaled once.\n * \\param PreviousState A pointer to a variable that receives the previous state of the timer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetTimer(\n    _In_ HANDLE TimerHandle,\n    _In_ PLARGE_INTEGER DueTime,\n    _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine,\n    _In_opt_ PVOID TimerContext,\n    _In_ BOOLEAN ResumeTimer,\n    _In_opt_ LONG Period,\n    _Out_opt_ PBOOLEAN PreviousState\n    );\n\n/**\n * The NtSetTimerEx routine sets extended information for a timer object.\n *\n * \\param TimerHandle A handle to the timer object.\n * \\param TimerSetInformationClass The class of information to set.\n * \\param TimerSetInformation A pointer to a buffer that contains the information to set.\n * \\param TimerSetInformationLength The size of the buffer, in bytes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetTimerEx(\n    _In_ HANDLE TimerHandle,\n    _In_ TIMER_SET_INFORMATION_CLASS TimerSetInformationClass,\n    _Inout_updates_bytes_opt_(TimerSetInformationLength) PVOID TimerSetInformation,\n    _In_ ULONG TimerSetInformationLength\n    );\n\n/**\n * The NtCancelTimer routine Cancels a timer object.\n *\n * \\param TimerHandle A handle to the timer object.\n * \\param CurrentState A pointer to a variable that receives the current state of the timer object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelTimer(\n    _In_ HANDLE TimerHandle,\n    _Out_opt_ PBOOLEAN CurrentState\n    );\n\n/**\n * The NtQueryTimer routine retrieves information about a timer object.\n *\n * \\param TimerHandle A handle to the timer object.\n * \\param TimerInformationClass The class of information to retrieve.\n * \\param TimerInformation A pointer to a buffer that receives the requested information.\n * \\param TimerInformationLength The size of the buffer, in bytes.\n * \\param ReturnLength A pointer to a variable that receives the size of the data returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryTimer(\n    _In_ HANDLE TimerHandle,\n    _In_ TIMER_INFORMATION_CLASS TimerInformationClass,\n    _Out_writes_bytes_(TimerInformationLength) PVOID TimerInformation,\n    _In_ ULONG TimerInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n// ExCheckValidIRTimerId\ntypedef enum _IR_TIMER_PROVIDER_INDEX\n{\n    IR_TIMER_PROVIDER_TESTIDENTIFIER, // Token(Service SID)\n    IR_TIMER_PROVIDER_BROKERINFRASTRUCTURE, // Token(Service SID)\n    IR_TIMER_PROVIDER_TIMEBROKERSVC, // Token(Service SID)\n    IR_TIMER_PROVIDER_LFSVC,\n    IR_TIMER_PROVIDER_WINLOGON,\n    IR_TIMER_PROVIDER_POWER,\n    IR_TIMER_PROVIDER_SENSORSERVICE,\n    IR_TIMER_PROVIDER_NTOSPO,\n    IR_TIMER_PROVIDER_ACPI,\n    IR_TIMER_PROVIDER_BUTTON,\n    IR_TIMER_PROVIDER_MSGPIOCLX,\n    IR_TIMER_PROVIDER_BUTTONCONVERTER,\n    IR_TIMER_PROVIDER_MSGPIOWIN32,\n    IR_TIMER_PROVIDER_KNETPWRDEPBROKER,\n    IR_TIMER_PROVIDER_CMBATT,\n    IR_TIMER_PROVIDER_BTHPORT,\n    IR_TIMER_PROVIDER_AUDIOSRV, // TOKEN(SERVICE SID)\n    IR_TIMER_PROVIDER_ARTESTIDENTIFIER, // TOKEN(SERVICE SID)\n    IR_TIMER_PROVIDER_BATTC,\n    IR_TIMER_PROVIDER_MAXINDEX\n} IR_TIMER_PROVIDER_INDEX;\n\n//CONST USHORT IR_TIMER_PROVIDER_ID_MAX[] =\n//{\n//    1,  // IR_TIMER_PROVIDER_TESTIDENTIFIER\n//    1,  // IR_TIMER_PROVIDER_BROKERINFRASTRUCTURE\n//    1,  // IR_TIMER_PROVIDER_TIMEBROKERSVC\n//    11, // IR_TIMER_PROVIDER_LFSVC (0x0B)\n//    1,  // IR_TIMER_PROVIDER_WINLOGON\n//    2,  // IR_TIMER_PROVIDER_POWER\n//    1,  // IR_TIMER_PROVIDER_SENSORSERVICE\n//    6,  // IR_TIMER_PROVIDER_NTOSPO\n//    1,  // IR_TIMER_PROVIDER_ACPI\n//    1,  // IR_TIMER_PROVIDER_BUTTON\n//    2,  // MsGpioClx\n//    1,  // ButtonConverter\n//    2,  // MsGpioWin32\n//    2,  // KNetPwrDepBroker\n//    1,  // Cmbatt\n//    2,  // Bthport\n//    1,  // AudioSrv\n//    1,  // ArTestIdentifier\n//    1   // Battc\n//};\n\n// rev\n#define IR_TIMERID_PROVIDER(TimerId) ((USHORT)HIWORD((ULONG)(TimerId)))\n#define IR_TIMERID_ID(TimerId) ((USHORT)LOWORD((ULONG)(TimerId)))\n#define IR_TIMERID_IS_NONZERO(TimerId) (IR_TIMERID_ID(TimerId) != 0)\n#define IR_TIMERID_ATTRIBUTES(ProviderIndex, ProviderId) \\\n    ((ULONG)MAKELONG((USHORT)(ProviderId), (USHORT)(ProviderIndex)))\n\n/**\n * The NtCreateIRTimer routine creates an IR timer object.\n * IR timers are interruptdriven and designed for high-resolution timing in system components.\n *\n * \\param TimerHandle A pointer to a variable that receives the handle to the IR timer object.\n * \\param TimerId A pointer to a timer identifier that specifies the provider.\n * \\param DesiredAccess The access mask that specifies the requested access to the timer object.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The TimerId must be non-NULL and point to a valid timer identifier.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateIRTimer(\n    _Out_ PHANDLE TimerHandle,\n    _In_ PULONG TimerId,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\n/**\n * The NtSetIRTimer routine sets an IR timer object.\n *\n * \\param TimerHandle A handle to the IR timer object.\n * \\param DueTime An optional pointer to a LARGE_INTEGER that specifies\n * the time at which the timer is to be set to the signaled state.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetIRTimer(\n    _In_ HANDLE TimerHandle,\n    _In_opt_ PLARGE_INTEGER DueTime\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n//\n// NtCreateTimer2 Attributes\n//\n#define TIMER2_ATTRIBUTE_IR_TIMER        0x00000002UL\n#define TIMER2_ATTRIBUTE_HIGH_RESOLUTION 0x00000004UL\n#define TIMER2_ATTRIBUTE_NOTIFICATION    0x80000000UL\n// rev\n#define TIMER2_ATTRIBUTE_KNOWN_MASK (TIMER2_ATTRIBUTE_IR_TIMER | TIMER2_ATTRIBUTE_HIGH_RESOLUTION | TIMER2_ATTRIBUTE_NOTIFICATION)\n#define TIMER2_ATTRIBUTE_RESERVED_MASK (~TIMER2_ATTRIBUTE_KNOWN_MASK)\n\n#define TIMER2_ATTRIBUTE_FOR_TYPE(T) \\\n    (((T) == NotificationTimer) ? TIMER2_ATTRIBUTE_NOTIFICATION : 0)\n\n// Build attributes for a *non-IR* timer\n//  - T: TIMER_TYPE (NotificationTimer/SynchronizationTimer)\n//  - R: bool for HighResolution\n//\n#define TIMER2_BUILD_ATTRIBUTES(T, R) \\\n    (TIMER2_ATTRIBUTE_FOR_TYPE(T) | ((R) ? TIMER2_ATTRIBUTE_HIGH_RESOLUTION : 0))\n\n// Build attributes for an *IR* timer\n//  - R: bool for HighResolution\n//\n#define TIMER2_BUILD_IR_ATTRIBUTES(R) \\\n    (TIMER2_ATTRIBUTE_IR_TIMER | ((R) ? TIMER2_ATTRIBUTE_HIGH_RESOLUTION : 0))\n\n// rev\ntypedef union _TIMER2_ATTRIBUTES\n{\n    ULONG Value;\n    struct\n    {\n        ULONG Reserved0 : 1;      // bit 0 (reserved)\n        ULONG IrTimer : 1;        // bit 1 == TIMER2_ATTRIBUTE_IR_TIMER\n        ULONG HighResolution : 1; // bit 2 == TIMER2_ATTRIBUTE_HIGH_RESOLUTION\n        ULONG Reserved1 : 28;     // bits [3..30] (reserved)\n        TIMER_TYPE NotificationType : 1; // bit 31 == TIMER2_ATTRIBUTE_NOTIFICATION\n    };\n} TIMER2_ATTRIBUTES;\n\n/**\n * The NtCreateTimer2 routine creates a timer object.\n *\n * \\param TimerHandle A pointer to a variable that receives the handle to the timer object.\n * \\param TimerId For IR timers: A pointer to ULONG TIMERID (non-NULL). For non-IR timers: must be NULL.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\param Attributes Timer attributes (TIMER_TYPE).\n * \\param DesiredAccess The access mask that specifies the requested access to the timer object.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createwaitabletimerexw\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateTimer2(\n    _Out_ PHANDLE TimerHandle,\n    _In_opt_ PULONG TimerId,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG Attributes,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n// rev\n#define TIMER2_SET_PARAMETERS_CURRENT_VERSION 0\n\n// rev\n/**\n * The T2_SET_PARAMETERS structure configures the high-resolution or coalescable timers,\n * and specify a \"no-wake tolerance\" value, which controls how much the kernel\n * may delay the timers for coalescing or power efficiency.\n * \\remarks Setting NoWakeTolerance to 0 requests **no coalescing** and the most precise\n * wake-up behavior the system can provide.\n */\ntypedef struct _T2_SET_PARAMETERS_V0\n{\n    /**\n     * Structure version. Must be set to zero.\n     */\n    ULONG Version;\n    /**\n     * Reserved.\n     */\n    ULONG Reserved;\n    /**\n     * Maximum tolerable delay (in 100-ns units) for timer coalescing.\n     * - Set to 0 for **no coalescing** (strict wake-up).\n     * - Set to a positive value to allow the kernel to delay the timer\n     *   by up to this amount for power efficiency.\n     * Example:\n     *   If NoWakeTolerance = 0 --> High-resolution, best precision, min jitter, zero coalescing, low power savings.\n     *   If NoWakeTolerance > 0 --> Normal-resolution, allow up to this value of coalescing, normal power savings.\n     *   If NoWakeTolerance = -1 --> Low-resolution, worst precision, max jitter, max coalescing, max power savings.\n     */\n    LONGLONG NoWakeTolerance;\n} T2_SET_PARAMETERS, *PT2_SET_PARAMETERS;\n\ntypedef PVOID PT2_CANCEL_PARAMETERS;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n/**\n * The NtSetTimer2 routine activates the timer object for a specified interval with optional periodic behavior.\n *\n * \\param TimerHandle A handle to the timer object to set.\n * \\param DueTime A pointer to a LARGE_INTEGER specifying the absolute or relative time when the timer should expire.\n * \\param Period An optional pointer to a LARGE_INTEGER specifying the period for periodic timer notifications, in 100-nanosecond intervals. If NULL, the timer is non-periodic.\n * \\param Parameters A pointer to a T2_SET_PARAMETERS structure containing additional timer configuration parameters.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setwaitabletimer\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetTimer2(\n    _In_ HANDLE TimerHandle,\n    _In_ PLARGE_INTEGER DueTime,\n    _In_opt_ PLARGE_INTEGER Period,\n    _In_opt_ PT2_SET_PARAMETERS Parameters\n    );\n\n/**\n * The NtCancelTimer2 routine sets the specified waitable timer to the inactive state.\n *\n * \\param TimerHandle A handle to the timer object to set.\n * \\param Parameters A pointer to a PT2_CANCEL_PARAMETERS structure containing additional parameters.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-cancelwaitabletimer\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelTimer2(\n    _In_ HANDLE TimerHandle,\n    _In_ PT2_CANCEL_PARAMETERS Parameters\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n//\n// Profile\n//\n\n#define PROFILE_CONTROL 0x0001\n#define PROFILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | PROFILE_CONTROL)\n\n/**\n * The NtCreateProfile routine creates a profile object for performance monitoring.\n *\n * \\param ProfileHandle A pointer to a variable that receives the handle to the profile object.\n * \\param Process Optional handle to the process to be profiled. If NULL, the current process is used.\n * \\param ProfileBase The base address of the region to be profiled.\n * \\param ProfileSize The size, in bytes, of the region to be profiled.\n * \\param BucketSize The size, in bytes, of each bucket in the profile buffer.\n * \\param Buffer A pointer to a buffer that receives the profile data.\n * \\param BufferSize The size, in bytes, of the buffer.\n * \\param ProfileSource The source of the profiling data (KPROFILE_SOURCE).\n * \\param Affinity The processor affinity mask indicating which processors to profile.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateProfile(\n    _Out_ PHANDLE ProfileHandle,\n    _In_opt_ HANDLE Process,\n    _In_ PVOID ProfileBase,\n    _In_ SIZE_T ProfileSize,\n    _In_ ULONG BucketSize,\n    _In_reads_bytes_(BufferSize) PULONG Buffer,\n    _In_ ULONG BufferSize,\n    _In_ KPROFILE_SOURCE ProfileSource,\n    _In_ KAFFINITY Affinity\n    );\n\n/**\n * The NtCreateProfileEx routine creates a profile object for performance monitoring with group affinity.\n *\n * \\param ProfileHandle A pointer to a variable that receives the handle to the profile object.\n * \\param Process Optional handle to the process to be profiled. If NULL, the current process is used.\n * \\param ProfileBase The base address of the region to be profiled.\n * \\param ProfileSize The size, in bytes, of the region to be profiled.\n * \\param BucketSize The size, in bytes, of each bucket in the profile buffer.\n * \\param Buffer A pointer to a buffer that receives the profile data.\n * \\param BufferSize The size, in bytes, of the buffer.\n * \\param ProfileSource The source of the profiling data (KPROFILE_SOURCE).\n * \\param GroupCount The number of group affinities provided.\n * \\param GroupAffinity A pointer to an array of GROUP_AFFINITY structures specifying processor groups to profile.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateProfileEx(\n    _Out_ PHANDLE ProfileHandle,\n    _In_opt_ HANDLE Process,\n    _In_ PVOID ProfileBase,\n    _In_ SIZE_T ProfileSize,\n    _In_ ULONG BucketSize,\n    _In_reads_bytes_(BufferSize) PULONG Buffer,\n    _In_ ULONG BufferSize,\n    _In_ KPROFILE_SOURCE ProfileSource,\n    _In_ USHORT GroupCount,\n    _In_reads_(GroupCount) PGROUP_AFFINITY GroupAffinity\n    );\n\n/**\n * The NtStartProfile routine starts the specified profile object.\n *\n * \\param ProfileHandle A handle to the profile object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtStartProfile(\n    _In_ HANDLE ProfileHandle\n    );\n\n/**\n * The NtStopProfile routine stops the specified profile object.\n *\n * \\param ProfileHandle A handle to the profile object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtStopProfile(\n    _In_ HANDLE ProfileHandle\n    );\n\n/**\n * The NtQueryIntervalProfile routine retrieves the interval for the specified profile source.\n *\n * \\param ProfileSource The profile source (KPROFILE_SOURCE) to query.\n * \\param Interval A pointer to a variable that receives the interval, in 100-nanosecond units.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryIntervalProfile(\n    _In_ KPROFILE_SOURCE ProfileSource,\n    _Out_ PULONG Interval\n    );\n\n/**\n * The NtSetIntervalProfile routine sets the interval for the specified profile source.\n *\n * \\param Interval The interval, in 100-nanosecond units, to set.\n * \\param Source The profile source (KPROFILE_SOURCE) to set the interval for.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetIntervalProfile(\n    _In_ ULONG Interval,\n    _In_ KPROFILE_SOURCE Source\n    );\n\n//\n// Keyed Event\n//\n\n#define KEYEDEVENT_WAIT 0x0001\n#define KEYEDEVENT_WAKE 0x0002\n#define KEYEDEVENT_ALL_ACCESS \\\n    (STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)\n\n/**\n * The NtCreateKeyedEvent routine creates a keyed event object and returns a handle to it.\n *\n * \\param KeyedEventHandle A pointer to a variable that receives the handle to the keyed event object.\n * \\param DesiredAccess The access mask that specifies the requested access to the keyed event object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\param Flags Reserved. Must be zero.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateKeyedEvent(\n    _Out_ PHANDLE KeyedEventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Reserved_ ULONG Flags\n    );\n\n/**\n * The NtOpenKeyedEvent routine opens a handle to an existing keyed event object.\n *\n * \\param KeyedEventHandle A pointer to a variable that receives the handle to the keyed event object.\n * \\param DesiredAccess The access mask that specifies the requested access to the keyed event object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the object attributes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenKeyedEvent(\n    _Out_ PHANDLE KeyedEventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtReleaseKeyedEvent routine releases a thread that is waiting on a keyed event with the specified key value.\n *\n * \\param KeyedEventHandle Optional handle to the keyed event object. If NULL, the default keyed event is used.\n * \\param KeyValue The key value that identifies the waiting thread to release.\n * \\param Alertable Specifies whether the call is alertable (can be interrupted by APCs).\n * \\param Timeout Optional pointer to a timeout value (in 100-nanosecond intervals). If NULL, waits indefinitely.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseKeyedEvent(\n    _In_opt_ HANDLE KeyedEventHandle,\n    _In_ PVOID KeyValue,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n/**\n *  The NtWaitForKeyedEvent routine waits for a keyed event to be released with the specified key value.\n *\n * \\param KeyedEventHandle Optional handle to the keyed event object. If NULL, the default keyed event is used.\n * \\param KeyValue The key value to wait for.\n * \\param Alertable Specifies whether the call is alertable (can be interrupted by APCs).\n * \\param Timeout Optional pointer to a timeout value (in 100-nanosecond intervals). If NULL, waits indefinitely.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForKeyedEvent(\n    _In_opt_ HANDLE KeyedEventHandle,\n    _In_ PVOID KeyValue,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n//\n// UMS\n//\n\n/**\n * The NtUmsThreadYield routine yields control to the user-mode scheduling (UMS) scheduler thread on which the calling UMS worker thread is running.\n * Note: As of Windows 11, user-mode scheduling is not supported. All calls fail with the error STATUS_NOT_SUPPORTED.\n *\n * \\param SchedulerParam Optional handle to the keyed event object. If NULL, the default keyed event is used.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-umsthreadyield\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUmsThreadYield(\n    _In_ PVOID SchedulerParam\n    );\n\n//\n// WNF\n//\n\n// begin_private\n\ntypedef struct _WNF_STATE_NAME\n{\n    union\n    {\n        ULONGLONG Value;\n        ULONG Data[2];\n        struct\n        {\n            ULONG64 Version : 4;\n            ULONG64 NameLifetime : 2;\n            ULONG64 DataScope : 4;\n            ULONG64 PermanentData : 1;\n            ULONG64 Unique : 53;\n        };\n    };\n} WNF_STATE_NAME, *PWNF_STATE_NAME;\n\ntypedef const WNF_STATE_NAME *PCWNF_STATE_NAME;\n\ntypedef enum _WNF_STATE_NAME_LIFETIME\n{\n    WnfWellKnownStateName,\n    WnfPermanentStateName,\n    WnfPersistentStateName,\n    WnfTemporaryStateName\n} WNF_STATE_NAME_LIFETIME;\n\ntypedef enum _WNF_STATE_NAME_INFORMATION\n{\n    WnfInfoStateNameExist,\n    WnfInfoSubscribersPresent,\n    WnfInfoIsQuiescent\n} WNF_STATE_NAME_INFORMATION;\n\ntypedef enum _WNF_DATA_SCOPE\n{\n    WnfDataScopeSystem,\n    WnfDataScopeSession,\n    WnfDataScopeUser,\n    WnfDataScopeProcess,\n    WnfDataScopeMachine, // REDSTONE3\n    WnfDataScopePhysicalMachine, // WIN11\n} WNF_DATA_SCOPE;\n\ntypedef struct _WNF_TYPE_ID\n{\n    GUID TypeId;\n} WNF_TYPE_ID, *PWNF_TYPE_ID;\n\ntypedef const WNF_TYPE_ID *PCWNF_TYPE_ID;\n\n// rev\ntypedef ULONG WNF_CHANGE_STAMP, *PWNF_CHANGE_STAMP;\n\ntypedef struct _WNF_DELIVERY_DESCRIPTOR\n{\n    ULONGLONG SubscriptionId;\n    WNF_STATE_NAME StateName;\n    WNF_CHANGE_STAMP ChangeStamp;\n    ULONG StateDataSize;\n    ULONG EventMask;\n    WNF_TYPE_ID TypeId;\n    ULONG StateDataOffset;\n} WNF_DELIVERY_DESCRIPTOR, *PWNF_DELIVERY_DESCRIPTOR;\n\n// end_private\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n/**\n * The NtCreateWnfStateName routine creates a new WNF (Windows Notification Facility) state name.\n *\n * \\param StateName Pointer to a WNF_STATE_NAME structure that receives the created state name.\n * \\param NameLifetime The lifetime of the state name (see WNF_STATE_NAME_LIFETIME).\n * \\param DataScope The data scope for the state name (see WNF_DATA_SCOPE).\n * \\param PersistData If TRUE, the state data is persistent.\n * \\param TypeId Optional pointer to a WNF_TYPE_ID structure specifying the type of the state data.\n * \\param MaximumStateSize The maximum size, in bytes, of the state data.\n * \\param SecurityDescriptor Pointer to a security descriptor for the state name.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateWnfStateName(\n    _Out_ PWNF_STATE_NAME StateName,\n    _In_ WNF_STATE_NAME_LIFETIME NameLifetime,\n    _In_ WNF_DATA_SCOPE DataScope,\n    _In_ BOOLEAN PersistData,\n    _In_opt_ PCWNF_TYPE_ID TypeId,\n    _In_ ULONG MaximumStateSize,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n/**\n * The NtDeleteWnfStateName routine deletes an existing WNF state name.\n *\n * \\param StateName Pointer to the WNF_STATE_NAME to delete.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteWnfStateName(\n    _In_ PCWNF_STATE_NAME StateName\n    );\n\n/**\n * The NtUpdateWnfStateData routine updates the data associated with a WNF state name.\n *\n * \\param StateName Pointer to the WNF_STATE_NAME to update.\n * \\param Buffer Pointer to the data buffer to write.\n * \\param Length Length, in bytes, of the data buffer.\n * \\param TypeId Optional pointer to a WNF_TYPE_ID structure specifying the type of the state data.\n * \\param ExplicitScope Optional pointer to a security identifier (SID) for explicit scope.\n * \\param MatchingChangeStamp The change stamp to match for update.\n * \\param CheckStamp If TRUE, the change stamp is checked before updating.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUpdateWnfStateData(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_reads_bytes_opt_(Length) const VOID* Buffer,\n    _In_opt_ ULONG Length,\n    _In_opt_ PCWNF_TYPE_ID TypeId,\n    _In_opt_ PCSID ExplicitScope,\n    _In_ WNF_CHANGE_STAMP MatchingChangeStamp,\n    _In_ LOGICAL CheckStamp\n    );\n\n/**\n * The NtDeleteWnfStateData routine deletes the data associated with a WNF state name.\n *\n * \\param StateName Pointer to the WNF_STATE_NAME whose data is to be deleted.\n * \\param ExplicitScope Optional pointer to a security identifier (SID) for explicit scope.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteWnfStateData(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_opt_ PCSID ExplicitScope\n    );\n\n/**\n * The NtQueryWnfStateData routine queries the data associated with a WNF state name.\n *\n * \\param StateName Pointer to the WNF_STATE_NAME to query.\n * \\param TypeId Optional pointer to a WNF_TYPE_ID structure specifying the type of the state data.\n * \\param ExplicitScope Optional pointer to a security identifier (SID) for explicit scope.\n * \\param ChangeStamp Pointer to a variable that receives the change stamp.\n * \\param Buffer Pointer to a buffer that receives the state data.\n * \\param BufferLength On input, the size of the buffer in bytes; on output, the number of bytes written.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryWnfStateData(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_opt_ PCWNF_TYPE_ID TypeId,\n    _In_opt_ PCSID ExplicitScope,\n    _Out_ PWNF_CHANGE_STAMP ChangeStamp,\n    _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\n/**\n * The NtQueryWnfStateNameInformation routine queries information about a WNF state name.\n *\n * \\param StateName Pointer to the WNF_STATE_NAME to query.\n * \\param NameInfoClass The information class to query (see WNF_STATE_NAME_INFORMATION).\n * \\param ExplicitScope Optional pointer to a security identifier (SID) for explicit scope.\n * \\param Buffer Pointer to a buffer that receives the requested information.\n * \\param BufferLength The size, in bytes, of the buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryWnfStateNameInformation(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_ WNF_STATE_NAME_INFORMATION NameInfoClass,\n    _In_opt_ PCSID ExplicitScope,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength\n    );\n\n/**\n * The NtSubscribeWnfStateChange routine subscribes to state change notifications for a WNF state name.\n *\n * \\param StateName Pointer to the WNF_STATE_NAME to subscribe to.\n * \\param ChangeStamp Optional change stamp to start receiving notifications from.\n * \\param EventMask Bitmask specifying which events to subscribe to.\n * \\param SubscriptionId Optional pointer to a variable that receives the subscription ID.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSubscribeWnfStateChange(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_opt_ WNF_CHANGE_STAMP ChangeStamp,\n    _In_ ULONG EventMask,\n    _Out_opt_ PULONG64 SubscriptionId\n    );\n\n/**\n * The NtUnsubscribeWnfStateChange routine unsubscribes from state change notifications for a WNF state name.\n *\n * \\param StateName Pointer to the WNF_STATE_NAME to unsubscribe from.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnsubscribeWnfStateChange(\n    _In_ PCWNF_STATE_NAME StateName\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n/**\n * The NtGetCompleteWnfStateSubscription routine retrieves the complete WNF state subscription information.\n *\n * \\param OldDescriptorStateName Optional pointer to the previous state name.\n * \\param OldSubscriptionId Optional pointer to the previous subscription ID.\n * \\param OldDescriptorEventMask Optional previous event mask.\n * \\param OldDescriptorStatus Optional previous descriptor status.\n * \\param NewDeliveryDescriptor Pointer to a buffer that receives the new delivery descriptor.\n * \\param DescriptorSize The size, in bytes, of the delivery descriptor buffer.\n * \\return NTSTATUS code indicating success or failure.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetCompleteWnfStateSubscription(\n    _In_opt_ PWNF_STATE_NAME OldDescriptorStateName,\n    _In_opt_ ULONG64 *OldSubscriptionId,\n    _In_opt_ ULONG OldDescriptorEventMask,\n    _In_opt_ ULONG OldDescriptorStatus,\n    _Out_writes_bytes_(DescriptorSize) PWNF_DELIVERY_DESCRIPTOR NewDeliveryDescriptor,\n    _In_ ULONG DescriptorSize\n    );\n\n/**\n * The NtSetWnfProcessNotificationEvent routine sets a process notification event for WNF state changes.\n *\n * \\param NotificationEvent Handle to the event object to be signaled on state change.\n * \\return NTSTATUS code indicating success or failure.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetWnfProcessNotificationEvent(\n    _In_ HANDLE NotificationEvent\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n//\n// Worker factory\n//\n\n// begin_rev\n\n#define WORKER_FACTORY_RELEASE_WORKER 0x0001\n#define WORKER_FACTORY_WAIT 0x0002\n#define WORKER_FACTORY_SET_INFORMATION 0x0004\n#define WORKER_FACTORY_QUERY_INFORMATION 0x0008\n#define WORKER_FACTORY_READY_WORKER 0x0010\n#define WORKER_FACTORY_SHUTDOWN 0x0020\n\n#define WORKER_FACTORY_ALL_ACCESS ( \\\n    STANDARD_RIGHTS_REQUIRED | \\\n    WORKER_FACTORY_RELEASE_WORKER | \\\n    WORKER_FACTORY_WAIT | \\\n    WORKER_FACTORY_SET_INFORMATION | \\\n    WORKER_FACTORY_QUERY_INFORMATION | \\\n    WORKER_FACTORY_READY_WORKER | \\\n    WORKER_FACTORY_SHUTDOWN \\\n    )\n\n// end_rev\n\n// begin_private\n\ntypedef enum _WORKERFACTORYINFOCLASS\n{\n    WorkerFactoryTimeout, // LARGE_INTEGER\n    WorkerFactoryRetryTimeout, // LARGE_INTEGER\n    WorkerFactoryIdleTimeout, // s: LARGE_INTEGER\n    WorkerFactoryBindingCount, // s: ULONG\n    WorkerFactoryThreadMinimum, // s: ULONG\n    WorkerFactoryThreadMaximum, // s: ULONG\n    WorkerFactoryPaused, // ULONG or BOOLEAN\n    WorkerFactoryBasicInformation, // q: WORKER_FACTORY_BASIC_INFORMATION\n    WorkerFactoryAdjustThreadGoal,\n    WorkerFactoryCallbackType,\n    WorkerFactoryStackInformation, // 10\n    WorkerFactoryThreadBasePriority, // s: ULONG\n    WorkerFactoryTimeoutWaiters, // s: ULONG, since THRESHOLD\n    WorkerFactoryFlags, // s: ULONG\n    WorkerFactoryThreadSoftMaximum, // s: ULONG\n    WorkerFactoryThreadCpuSets, // since REDSTONE5\n    MaxWorkerFactoryInfoClass\n} WORKERFACTORYINFOCLASS, *PWORKERFACTORYINFOCLASS;\n\ntypedef struct _WORKER_FACTORY_BASIC_INFORMATION\n{\n    LARGE_INTEGER Timeout;\n    LARGE_INTEGER RetryTimeout;\n    LARGE_INTEGER IdleTimeout;\n    BOOLEAN Paused;\n    BOOLEAN TimerSet;\n    BOOLEAN QueuedToExWorker;\n    BOOLEAN MayCreate;\n    BOOLEAN CreateInProgress;\n    BOOLEAN InsertedIntoQueue;\n    BOOLEAN Shutdown;\n    ULONG BindingCount;\n    ULONG ThreadMinimum;\n    ULONG ThreadMaximum;\n    ULONG PendingWorkerCount;\n    ULONG WaitingWorkerCount;\n    ULONG TotalWorkerCount;\n    ULONG ReleaseCount;\n    LONGLONG InfiniteWaitGoal;\n    PVOID StartRoutine;\n    PVOID StartParameter;\n    HANDLE ProcessId;\n    SIZE_T StackReserve;\n    SIZE_T StackCommit;\n    NTSTATUS LastThreadCreationStatus;\n} WORKER_FACTORY_BASIC_INFORMATION, *PWORKER_FACTORY_BASIC_INFORMATION;\n\n// end_private\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateWorkerFactory(\n    _Out_ PHANDLE WorkerFactoryHandleReturn,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE CompletionPortHandle,\n    _In_ HANDLE WorkerProcessHandle,\n    _In_ PVOID StartRoutine,\n    _In_opt_ PVOID StartParameter,\n    _In_opt_ ULONG MaxThreadCount,\n    _In_opt_ SIZE_T StackReserve,\n    _In_opt_ SIZE_T StackCommit\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass,\n    _Out_writes_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation,\n    _In_ ULONG WorkerFactoryInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass,\n    _In_reads_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation,\n    _In_ ULONG WorkerFactoryInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtShutdownWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _Inout_ volatile LONG *PendingWorkerCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseWorkerFactoryWorker(\n    _In_ HANDLE WorkerFactoryHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWorkerFactoryWorkerReady(\n    _In_ HANDLE WorkerFactoryHandle\n    );\n\ntypedef struct _WORKER_FACTORY_DEFERRED_WORK\n{\n    PPORT_MESSAGE AlpcSendMessage;\n    PVOID AlpcSendMessagePort;\n    ULONG AlpcSendMessageFlags;\n    ULONG Flags;\n} WORKER_FACTORY_DEFERRED_WORK, *PWORKER_FACTORY_DEFERRED_WORK;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForWorkViaWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _Out_writes_to_(Count, *PacketsReturned) PFILE_IO_COMPLETION_INFORMATION MiniPackets,\n    _In_ ULONG Count,\n    _Out_ PULONG PacketsReturned,\n    _In_ PVOID DeferredWork // PWORKER_FACTORY_DEFERRED_WORK\n    );\n\n#else\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForWorkViaWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _Out_ PFILE_IO_COMPLETION_INFORMATION MiniPacket\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n//\n// Time\n//\n\n/**\n * The NtQuerySystemTime routine obtains the current system time.\n *\n * \\param SystemTime A pointer to a LARGE_INTEGER structure that receives the system time. This is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysystemtime\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemTime(\n    _Out_ PLARGE_INTEGER SystemTime\n    );\n\n/**\n * The NtSetSystemTime routine sets the current system time and date. The system time is expressed in Coordinated Universal Time (UTC).\n *\n * \\param SystemTime A pointer to a LARGE_INTEGER structure that that contains the new system date and time.\n * \\param PreviousTime A pointer to a LARGE_INTEGER structure that that contains the previous system time.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The calling process must have the SE_SYSTEMTIME_NAME privilege.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-setsystemtime\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSystemTime(\n    _In_opt_ PLARGE_INTEGER SystemTime,\n    _Out_opt_ PLARGE_INTEGER PreviousTime\n    );\n\n/**\n * The NtQueryTimerResolution routine retrieves the range and current value of the system interrupt timer.\n *\n * \\param MaximumTime The maximum timer resolution, in 100-nanosecond units.\n * \\param MinimumTime The minimum timer resolution, in 100-nanosecond units.\n * \\param CurrentTime The current timer resolution, in 100-nanosecond units.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryTimerResolution(\n    _Out_ PULONG MaximumTime,\n    _Out_ PULONG MinimumTime,\n    _Out_ PULONG CurrentTime\n    );\n\n/**\n * The NtSetTimerResolution routine sets the system interrupt timer resolution to the specified value.\n *\n * \\param DesiredTime The desired timer resolution, in 100-nanosecond units.\n * \\param SetResolution If TRUE, the timer resolution is set to the value specified by DesiredTime. If FALSE, the timer resolution is reset to the default value.\n * \\param ActualTime The actual timer resolution, in 100-nanosecond units.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetTimerResolution(\n    _In_ ULONG DesiredTime,\n    _In_ BOOLEAN SetResolution,\n    _Out_ PULONG ActualTime\n    );\n\n//\n// Performance Counters\n//\n\n/**\n * The NtQueryPerformanceCounter routine retrieves the current value of the performance counter,\n * which is a high resolution (<1us) time stamp that can be used for time-interval measurements.\n *\n * \\param PerformanceCounter A pointer to a variable that receives the current performance-counter value, in 100-nanosecond units.\n * \\param PerformanceFrequency A pointer to a variable that receives the current performance-frequency value, in 100-nanosecond units.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks On systems that run Windows XP or later, the function will always succeed and will thus never return zero. Use RtlQueryPerformanceCounter instead since no system calls are required.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryPerformanceCounter(\n    _Out_ PLARGE_INTEGER PerformanceCounter,\n    _Out_opt_ PLARGE_INTEGER PerformanceFrequency\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS2)\n// rev\n/**\n * The NtQueryAuxiliaryCounterFrequency routine queries the auxiliary counter frequency. (The auxiliary counter is generally the HPET hardware timer).\n *\n * \\param AuxiliaryCounterFrequency A pointer to an output buffer that contains the specified auxiliary counter frequency. If the auxiliary counter is not supported, the value in the output buffer will be undefined.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryauxiliarycounterfrequency\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryAuxiliaryCounterFrequency(\n    _Out_ PULONG64 AuxiliaryCounterFrequency\n    );\n\n// rev\n/**\n * The NtConvertBetweenAuxiliaryCounterAndPerformanceCounter routine converts the specified performance counter value to the corresponding auxiliary counter value;\n * optionally provides the estimated conversion error in nanoseconds due to latencies and maximum possible drift.\n *\n * \\param ConvertAuxiliaryToPerformanceCounter  If TRUE, the value will be converted from AUX to QPC. If FALSE, the value will be converted from QPC to AUX.\n * \\param PerformanceOrAuxiliaryCounterValue The performance counter value to convert.\n * \\param ConvertedValue On success, contains the converted auxiliary counter value. Will be undefined if the function fails.\n * \\param ConversionError On success, contains the estimated conversion error, in nanoseconds. Will be undefined if the function fails.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-convertperformancecountertoauxiliarycounter\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtConvertBetweenAuxiliaryCounterAndPerformanceCounter(\n    _In_ BOOLEAN ConvertAuxiliaryToPerformanceCounter,\n    _In_ PULONG64 PerformanceOrAuxiliaryCounterValue,\n    _Out_ PULONG64 ConvertedValue,\n    _Out_opt_ PULONG64 ConversionError\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_RS2)\n\n//\n// LUIDs\n//\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateLocallyUniqueId(\n    _Out_ PLUID Luid\n    );\n\n//\n// UUIDs\n//\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetUuidSeed(\n    _In_ PCHAR Seed\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateUuids(\n    _Out_ PULARGE_INTEGER Time,\n    _Out_ PULONG Range,\n    _Out_ PULONG Sequence,\n    _Out_ PCHAR Seed\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// System Information\n//\n\n// rev\n// private\ntypedef enum _SYSTEM_INFORMATION_CLASS\n{\n    SystemBasicInformation,                                 // q: SYSTEM_BASIC_INFORMATION\n    SystemProcessorInformation,                             // q: SYSTEM_PROCESSOR_INFORMATION\n    SystemPerformanceInformation,                           // q: SYSTEM_PERFORMANCE_INFORMATION\n    SystemTimeOfDayInformation,                             // q: SYSTEM_TIMEOFDAY_INFORMATION\n    SystemPathInformation,                                  // q: not implemented\n    SystemProcessInformation,                               // q: SYSTEM_PROCESS_INFORMATION\n    SystemCallCountInformation,                             // q: SYSTEM_CALL_COUNT_INFORMATION\n    SystemDeviceInformation,                                // q: SYSTEM_DEVICE_INFORMATION\n    SystemProcessorPerformanceInformation,                  // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION (EX in: USHORT ProcessorGroup)\n    SystemFlagsInformation,                                 // qs: SYSTEM_FLAGS_INFORMATION\n    SystemCallTimeInformation,                              // q: SYSTEM_CALL_TIME_INFORMATION // not implemented // 10\n    SystemModuleInformation,                                // q: RTL_PROCESS_MODULES\n    SystemLocksInformation,                                 // q: RTL_PROCESS_LOCKS\n    SystemStackTraceInformation,                            // q: RTL_PROCESS_BACKTRACES\n    SystemPagedPoolInformation,                             // q: not implemented\n    SystemNonPagedPoolInformation,                          // q: not implemented\n    SystemHandleInformation,                                // q: SYSTEM_HANDLE_INFORMATION\n    SystemObjectInformation,                                // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION\n    SystemPageFileInformation,                              // q: SYSTEM_PAGEFILE_INFORMATION\n    SystemVdmInstemulInformation,                           // q: SYSTEM_VDM_INSTEMUL_INFO\n    SystemVdmBopInformation,                                // q: not implemented // 20\n    SystemFileCacheInformation,                             // qs: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache)\n    SystemPoolTagInformation,                               // q: SYSTEM_POOLTAG_INFORMATION\n    SystemInterruptInformation,                             // q: SYSTEM_INTERRUPT_INFORMATION (EX in: USHORT ProcessorGroup)\n    SystemDpcBehaviorInformation,                           // qs: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege)\n    SystemFullMemoryInformation,                            // q: SYSTEM_MEMORY_USAGE_INFORMATION // not implemented\n    SystemLoadGdiDriverInformation,                         // s: (kernel-mode only)\n    SystemUnloadGdiDriverInformation,                       // s: (kernel-mode only)\n    SystemTimeAdjustmentInformation,                        // qs: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege)\n    SystemSummaryMemoryInformation,                         // q: SYSTEM_MEMORY_USAGE_INFORMATION // not implemented\n    SystemMirrorMemoryInformation,                          // qs: (requires license value \"Kernel-MemoryMirroringSupported\") (requires SeShutdownPrivilege) // 30\n    SystemPerformanceTraceInformation,                      // qs: (type depends on EVENT_TRACE_INFORMATION_CLASS)\n    SystemObsolete0,                                        // q: not implemented\n    SystemExceptionInformation,                             // q: SYSTEM_EXCEPTION_INFORMATION\n    SystemCrashDumpStateInformation,                        // s: SYSTEM_CRASH_DUMP_STATE_INFORMATION (requires SeDebugPrivilege)\n    SystemKernelDebuggerInformation,                        // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION\n    SystemContextSwitchInformation,                         // q: SYSTEM_CONTEXT_SWITCH_INFORMATION\n    SystemRegistryQuotaInformation,                         // qs: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege)\n    SystemExtendServiceTableInformation,                    // s: (requires SeLoadDriverPrivilege) // loads win32k only\n    SystemPrioritySeparation,                               // s: (requires SeTcbPrivilege)\n    SystemVerifierAddDriverInformation,                     // s: UNICODE_STRING (requires SeDebugPrivilege) // 40\n    SystemVerifierRemoveDriverInformation,                  // s: UNICODE_STRING (requires SeDebugPrivilege)\n    SystemProcessorIdleInformation,                         // q: SYSTEM_PROCESSOR_IDLE_INFORMATION (EX in: USHORT ProcessorGroup)\n    SystemLegacyDriverInformation,                          // q: SYSTEM_LEGACY_DRIVER_INFORMATION\n    SystemCurrentTimeZoneInformation,                       // qs: RTL_TIME_ZONE_INFORMATION\n    SystemLookasideInformation,                             // q: SYSTEM_LOOKASIDE_INFORMATION\n    SystemTimeSlipNotification,                             // s: HANDLE (NtCreateEvent) (requires SeSystemtimePrivilege)\n    SystemSessionCreate,                                    // q: not implemented\n    SystemSessionDetach,                                    // q: not implemented\n    SystemSessionInformation,                               // q: not implemented (SYSTEM_SESSION_INFORMATION)\n    SystemRangeStartInformation,                            // q: SYSTEM_RANGE_START_INFORMATION // 50\n    SystemVerifierInformation,                              // qs: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege)\n    SystemVerifierThunkExtend,                              // qs: (kernel-mode only)\n    SystemSessionProcessInformation,                        // q: SYSTEM_SESSION_PROCESS_INFORMATION\n    SystemLoadGdiDriverInSystemSpace,                       // qs: SYSTEM_GDI_DRIVER_INFORMATION (kernel-mode only) (same as SystemLoadGdiDriverInformation)\n    SystemNumaProcessorMap,                                 // q: SYSTEM_NUMA_INFORMATION\n    SystemPrefetcherInformation,                            // qs: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation\n    SystemExtendedProcessInformation,                       // q: SYSTEM_EXTENDED_PROCESS_INFORMATION\n    SystemRecommendedSharedDataAlignment,                   // q: ULONG // KeGetRecommendedSharedDataAlignment\n    SystemComPlusPackage,                                   // qs: ULONG\n    SystemNumaAvailableMemory,                              // q: SYSTEM_NUMA_INFORMATION // 60\n    SystemProcessorPowerInformation,                        // q: SYSTEM_PROCESSOR_POWER_INFORMATION (EX in: USHORT ProcessorGroup)\n    SystemEmulationBasicInformation,                        // q: SYSTEM_BASIC_INFORMATION\n    SystemEmulationProcessorInformation,                    // q: SYSTEM_PROCESSOR_INFORMATION\n    SystemExtendedHandleInformation,                        // q: SYSTEM_HANDLE_INFORMATION_EX\n    SystemLostDelayedWriteInformation,                      // q: ULONG\n    SystemBigPoolInformation,                               // q: SYSTEM_BIGPOOL_INFORMATION\n    SystemSessionPoolTagInformation,                        // q: SYSTEM_SESSION_POOLTAG_INFORMATION\n    SystemSessionMappedViewInformation,                     // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION\n    SystemHotpatchInformation,                              // qs: SYSTEM_HOTPATCH_CODE_INFORMATION\n    SystemObjectSecurityMode,                               // q: ULONG // 70\n    SystemWatchdogTimerHandler,                             // s: SYSTEM_WATCHDOG_HANDLER_INFORMATION // (kernel-mode only)\n    SystemWatchdogTimerInformation,                         // qs: out: SYSTEM_WATCHDOG_TIMER_INFORMATION (EX in: ULONG WATCHDOG_INFORMATION_CLASS) // NtQuerySystemInformationEx\n    SystemLogicalProcessorInformation,                      // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION (EX in: USHORT ProcessorGroup) // NtQuerySystemInformationEx\n    SystemWow64SharedInformationObsolete,                   // q: not implemented\n    SystemRegisterFirmwareTableInformationHandler,          // s: SYSTEM_FIRMWARE_TABLE_HANDLER // (kernel-mode only)\n    SystemFirmwareTableInformation,                         // q: SYSTEM_FIRMWARE_TABLE_INFORMATION\n    SystemModuleInformationEx,                              // q: RTL_PROCESS_MODULE_INFORMATION_EX // since VISTA\n    SystemVerifierTriageInformation,                        // q: not implemented\n    SystemSuperfetchInformation,                            // qs: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation\n    SystemMemoryListInformation,                            // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80\n    SystemFileCacheInformationEx,                           // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation)\n    SystemThreadPriorityClientIdInformation,                // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege) // NtQuerySystemInformationEx\n    SystemProcessorIdleCycleTimeInformation,                // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup) // NtQuerySystemInformationEx\n    SystemVerifierCancellationInformation,                  // q: SYSTEM_VERIFIER_CANCELLATION_INFORMATION // name:wow64:whNT32QuerySystemVerifierCancellationInformation\n    SystemProcessorPowerInformationEx,                      // q: not implemented\n    SystemRefTraceInformation,                              // qs: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation\n    SystemSpecialPoolInformation,                           // qs: SYSTEM_SPECIAL_POOL_INFORMATION (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0\n    SystemProcessIdInformation,                             // q: SYSTEM_PROCESS_ID_INFORMATION\n    SystemErrorPortInformation,                             // s: HANDLE (requires SeTcbPrivilege)\n    SystemBootEnvironmentInformation,                       // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90\n    SystemHypervisorInformation,                            // q: SYSTEM_HYPERVISOR_QUERY_INFORMATION\n    SystemVerifierInformationEx,                            // qs: SYSTEM_VERIFIER_INFORMATION_EX\n    SystemTimeZoneInformation,                              // qs: RTL_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege)\n    SystemImageFileExecutionOptionsInformation,             // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege)\n    SystemCoverageInformation,                              // q: COVERAGE_MODULES s: COVERAGE_MODULE_REQUEST // ExpCovQueryInformation (requires SeDebugPrivilege)\n    SystemPrefetchPatchInformation,                         // q: SYSTEM_PREFETCH_PATCH_INFORMATION\n    SystemVerifierFaultsInformation,                        // s: SYSTEM_VERIFIER_FAULTS_INFORMATION (requires SeDebugPrivilege)\n    SystemSystemPartitionInformation,                       // q: SYSTEM_SYSTEM_PARTITION_INFORMATION\n    SystemSystemDiskInformation,                            // q: SYSTEM_SYSTEM_DISK_INFORMATION\n    SystemProcessorPerformanceDistribution,                 // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION (EX in: USHORT ProcessorGroup) // NtQuerySystemInformationEx // 100\n    SystemNumaProximityNodeInformation,                     // qs: SYSTEM_NUMA_PROXIMITY_MAP\n    SystemDynamicTimeZoneInformation,                       // qs: RTL_DYNAMIC_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege)\n    SystemCodeIntegrityInformation,                         // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation\n    SystemProcessorMicrocodeUpdateInformation,              // s: SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION (requires SeLoadDriverPrivilege)\n    SystemProcessorBrandString,                             // q: CHAR[] // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23\n    SystemVirtualAddressInformation,                        // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation\n    SystemLogicalProcessorAndGroupInformation,              // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX (EX in: LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType) // since WIN7 // NtQuerySystemInformationEx // KeQueryLogicalProcessorRelationship\n    SystemProcessorCycleTimeInformation,                    // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup) // NtQuerySystemInformationEx\n    SystemStoreInformation,                                 // qs: SYSTEM_STORE_INFORMATION (requires SeProfileSingleProcessPrivilege) // SmQueryStoreInformation\n    SystemRegistryAppendString,                             // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110\n    SystemAitSamplingValue,                                 // s: ULONG (requires SeProfileSingleProcessPrivilege)\n    SystemVhdBootInformation,                               // q: SYSTEM_VHD_BOOT_INFORMATION\n    SystemCpuQuotaInformation,                              // qs: PS_CPU_QUOTA_QUERY_INFORMATION\n    SystemNativeBasicInformation,                           // q: SYSTEM_BASIC_INFORMATION\n    SystemErrorPortTimeouts,                                // q: SYSTEM_ERROR_PORT_TIMEOUTS\n    SystemLowPriorityIoInformation,                         // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION\n    SystemTpmBootEntropyInformation,                        // q: BOOT_ENTROPY_NT_RESULT // ExQueryBootEntropyInformation\n    SystemVerifierCountersInformation,                      // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION\n    SystemPagedPoolInformationEx,                           // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool)\n    SystemSystemPtesInformationEx,                          // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120\n    SystemNodeDistanceInformation,                          // q: USHORT[4*NumaNodes] // (EX in: USHORT NodeNumber) // NtQuerySystemInformationEx\n    SystemAcpiAuditInformation,                             // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26\n    SystemBasicPerformanceInformation,                      // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation\n    SystemQueryPerformanceCounterInformation,               // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1\n    SystemSessionBigPoolInformation,                        // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8\n    SystemBootGraphicsInformation,                          // qs: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only)\n    SystemScrubPhysicalMemoryInformation,                   // qs: MEMORY_SCRUB_INFORMATION\n    SystemBadPageInformation,                               // q: SYSTEM_BAD_PAGE_INFORMATION\n    SystemProcessorProfileControlArea,                      // qs: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA\n    SystemCombinePhysicalMemoryInformation,                 // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130\n    SystemEntropyInterruptTimingInformation,                // qs: SYSTEM_ENTROPY_TIMING_INFORMATION\n    SystemConsoleInformation,                               // qs: SYSTEM_CONSOLE_INFORMATION // (requires SeLoadDriverPrivilege)\n    SystemPlatformBinaryInformation,                        // q: SYSTEM_PLATFORM_BINARY_INFORMATION (requires SeTcbPrivilege)\n    SystemPolicyInformation,                                // q: SYSTEM_POLICY_INFORMATION (Warbird/Encrypt/Decrypt/Execute)\n    SystemHypervisorProcessorCountInformation,              // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION\n    SystemDeviceDataInformation,                            // q: SYSTEM_DEVICE_DATA_INFORMATION\n    SystemDeviceDataEnumerationInformation,                 // q: SYSTEM_DEVICE_DATA_INFORMATION\n    SystemMemoryTopologyInformation,                        // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION\n    SystemMemoryChannelInformation,                         // q: SYSTEM_MEMORY_CHANNEL_INFORMATION\n    SystemBootLogoInformation,                              // q: SYSTEM_BOOT_LOGO_INFORMATION // 140\n    SystemProcessorPerformanceInformationEx,                // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // (EX in: USHORT ProcessorGroup) // NtQuerySystemInformationEx // since WINBLUE\n    SystemCriticalProcessErrorLogInformation,               // q: CRITICAL_PROCESS_EXCEPTION_DATA\n    SystemSecureBootPolicyInformation,                      // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION\n    SystemPageFileInformationEx,                            // q: SYSTEM_PAGEFILE_INFORMATION_EX\n    SystemSecureBootInformation,                            // q: SYSTEM_SECUREBOOT_INFORMATION\n    SystemEntropyInterruptTimingRawInformation,             // qs: SYSTEM_ENTROPY_TIMING_INFORMATION\n    SystemPortableWorkspaceEfiLauncherInformation,          // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION\n    SystemFullProcessInformation,                           // q: SYSTEM_EXTENDED_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin)\n    SystemKernelDebuggerInformationEx,                      // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX\n    SystemBootMetadataInformation,                          // q: (requires SeTcbPrivilege) // 150\n    SystemSoftRebootInformation,                            // q: ULONG\n    SystemElamCertificateInformation,                       // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION\n    SystemOfflineDumpConfigInformation,                     // q: OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2\n    SystemProcessorFeaturesInformation,                     // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION\n    SystemRegistryReconciliationInformation,                // s: NULL (requires admin) (flushes registry hives)\n    SystemEdidInformation,                                  // q: SYSTEM_EDID_INFORMATION\n    SystemManufacturingInformation,                         // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD\n    SystemEnergyEstimationConfigInformation,                // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION\n    SystemHypervisorDetailInformation,                      // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION\n    SystemProcessorCycleStatsInformation,                   // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION (EX in: USHORT ProcessorGroup) // NtQuerySystemInformationEx // 160\n    SystemVmGenerationCountInformation,                     // s: PHYSICAL_ADDRESS (kernel-mode only) (vmgencounter.sys)\n    SystemTrustedPlatformModuleInformation,                 // q: SYSTEM_TPM_INFORMATION\n    SystemKernelDebuggerFlags,                              // q: SYSTEM_KERNEL_DEBUGGER_FLAGS\n    SystemCodeIntegrityPolicyInformation,                   // qs: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION\n    SystemIsolatedUserModeInformation,                      // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION\n    SystemHardwareSecurityTestInterfaceResultsInformation,  // q:\n    SystemSingleModuleInformation,                          // q: SYSTEM_SINGLE_MODULE_INFORMATION\n    SystemAllowedCpuSetsInformation,                        // s: SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION\n    SystemVsmProtectionInformation,                         // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation)\n    SystemInterruptCpuSetsInformation,                      // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170\n    SystemSecureBootPolicyFullInformation,                  // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION\n    SystemCodeIntegrityPolicyFullInformation,               // q:\n    SystemAffinitizedInterruptProcessorInformation,         // q: KAFFINITY_EX // (requires SeIncreaseBasePriorityPrivilege)\n    SystemRootSiloInformation,                              // q: SYSTEM_ROOT_SILO_INFORMATION\n    SystemCpuSetInformation,                                // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2\n    SystemCpuSetTagInformation,                             // q: SYSTEM_CPU_SET_TAG_INFORMATION\n    SystemWin32WerStartCallout,                             // s:\n    SystemSecureKernelProfileInformation,                   // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION\n    SystemCodeIntegrityPlatformManifestInformation,         // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // NtQuerySystemInformationEx // since REDSTONE\n    SystemInterruptSteeringInformation,                     // q: in: SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT, out: SYSTEM_INTERRUPT_STEERING_INFORMATION_OUTPUT // NtQuerySystemInformationEx\n    SystemSupportedProcessorArchitectures,                  // p: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx // 180\n    SystemMemoryUsageInformation,                           // q: SYSTEM_MEMORY_USAGE_INFORMATION\n    SystemCodeIntegrityCertificateInformation,              // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION\n    SystemPhysicalMemoryInformation,                        // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2\n    SystemControlFlowTransition,                            // qs: (Warbird/Encrypt/Decrypt/Execute)\n    SystemKernelDebuggingAllowed,                           // s: ULONG\n    SystemActivityModerationExeState,                       // s: SYSTEM_ACTIVITY_MODERATION_EXE_STATE\n    SystemActivityModerationUserSettings,                   // q: SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS\n    SystemCodeIntegrityPoliciesFullInformation,             // qs: NtQuerySystemInformationEx\n    SystemCodeIntegrityUnlockInformation,                   // q: SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190\n    SystemIntegrityQuotaInformation,                        // s: SYSTEM_INTEGRITY_QUOTA_INFORMATION (requires SeDebugPrivilege)\n    SystemFlushInformation,                                 // q: SYSTEM_FLUSH_INFORMATION\n    SystemProcessorIdleMaskInformation,                     // q: ULONG_PTR[ActiveGroupCount] // since REDSTONE3\n    SystemSecureDumpEncryptionInformation,                  // qs: NtQuerySystemInformationEx // (q: requires SeDebugPrivilege) (s: requires SeTcbPrivilege)\n    SystemWriteConstraintInformation,                       // q: SYSTEM_WRITE_CONSTRAINT_INFORMATION\n    SystemKernelVaShadowInformation,                        // q: SYSTEM_KERNEL_VA_SHADOW_INFORMATION\n    SystemHypervisorSharedPageInformation,                  // q: SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4\n    SystemFirmwareBootPerformanceInformation,               // q:\n    SystemCodeIntegrityVerificationInformation,             // q: SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION\n    SystemFirmwarePartitionInformation,                     // q: SYSTEM_FIRMWARE_PARTITION_INFORMATION // 200\n    SystemSpeculationControlInformation,                    // q: SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above.\n    SystemDmaGuardPolicyInformation,                        // q: SYSTEM_DMA_GUARD_POLICY_INFORMATION\n    SystemEnclaveLaunchControlInformation,                  // q: SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION\n    SystemWorkloadAllowedCpuSetsInformation,                // q: SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5\n    SystemCodeIntegrityUnlockModeInformation,               // q: SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION\n    SystemLeapSecondInformation,                            // qs: SYSTEM_LEAP_SECOND_INFORMATION // (s: requires SeSystemtimePrivilege)\n    SystemFlags2Information,                                // q: SYSTEM_FLAGS_INFORMATION // (s: requires SeDebugPrivilege)\n    SystemSecurityModelInformation,                         // q: SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1\n    SystemCodeIntegritySyntheticCacheInformation,           // qs: NtQuerySystemInformationEx\n    SystemFeatureConfigurationInformation,                  // q: in: SYSTEM_FEATURE_CONFIGURATION_QUERY, out: SYSTEM_FEATURE_CONFIGURATION_INFORMATION; s: SYSTEM_FEATURE_CONFIGURATION_UPDATE // NtQuerySystemInformationEx // since 20H1 // 210\n    SystemFeatureConfigurationSectionInformation,           // q: in: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_REQUEST, out: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_INFORMATION // NtQuerySystemInformationEx\n    SystemFeatureUsageSubscriptionInformation,              // q: SYSTEM_FEATURE_USAGE_SUBSCRIPTION_DETAILS; s: SYSTEM_FEATURE_USAGE_SUBSCRIPTION_UPDATE\n    SystemSecureSpeculationControlInformation,              // q: SECURE_SPECULATION_CONTROL_INFORMATION\n    SystemSpacesBootInformation,                            // qs: // since 20H2\n    SystemFwRamdiskInformation,                             // q: SYSTEM_FIRMWARE_RAMDISK_INFORMATION\n    SystemWheaIpmiHardwareInformation,                      // q:\n    SystemDifSetRuleClassInformation,                       // s: SYSTEM_DIF_VOLATILE_INFORMATION (requires SeDebugPrivilege)\n    SystemDifClearRuleClassInformation,                     // s: NULL (requires SeDebugPrivilege)\n    SystemDifApplyPluginVerificationOnDriver,               // q: SYSTEM_DIF_PLUGIN_DRIVER_INFORMATION (requires SeDebugPrivilege)\n    SystemDifRemovePluginVerificationOnDriver,              // q: SYSTEM_DIF_PLUGIN_DRIVER_INFORMATION (requires SeDebugPrivilege) // 220\n    SystemShadowStackInformation,                           // q: SYSTEM_SHADOW_STACK_INFORMATION\n    SystemBuildVersionInformation,                          // q: in: ULONG (LayerNumber), out: SYSTEM_BUILD_VERSION_INFORMATION // NtQuerySystemInformationEx\n    SystemPoolLimitInformation,                             // q: SYSTEM_POOL_LIMIT_INFORMATION (requires SeIncreaseQuotaPrivilege) // NtQuerySystemInformationEx\n    SystemCodeIntegrityAddDynamicStore,                     // q: CodeIntegrity-AllowConfigurablePolicy-CustomKernelSigners\n    SystemCodeIntegrityClearDynamicStores,                  // q: CodeIntegrity-AllowConfigurablePolicy-CustomKernelSigners\n    SystemDifPoolTrackingInformation,                       // s: SYSTEM_DIF_POOL_TRACKING_INFORMATION (requires SeDebugPrivilege)\n    SystemPoolZeroingInformation,                           // q: SYSTEM_POOL_ZEROING_INFORMATION\n    SystemDpcWatchdogInformation,                           // qs: SYSTEM_DPC_WATCHDOG_CONFIGURATION_INFORMATION\n    SystemDpcWatchdogInformation2,                          // qs: SYSTEM_DPC_WATCHDOG_CONFIGURATION_INFORMATION_V2\n    SystemSupportedProcessorArchitectures2,                 // q: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx // 230\n    SystemSingleProcessorRelationshipInformation,           // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // (EX in: PROCESSOR_NUMBER Processor) // NtQuerySystemInformationEx\n    SystemXfgCheckFailureInformation,                       // q: SYSTEM_XFG_FAILURE_INFORMATION\n    SystemIommuStateInformation,                            // q: SYSTEM_IOMMU_STATE_INFORMATION // since 22H1\n    SystemHypervisorMinrootInformation,                     // q: SYSTEM_HYPERVISOR_MINROOT_INFORMATION\n    SystemHypervisorBootPagesInformation,                   // q: SYSTEM_HYPERVISOR_BOOT_PAGES_INFORMATION\n    SystemPointerAuthInformation,                           // q: SYSTEM_POINTER_AUTH_INFORMATION\n    SystemSecureKernelDebuggerInformation,                  // qs: NtQuerySystemInformationEx\n    SystemOriginalImageFeatureInformation,                  // q: in: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_INPUT, out: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_OUTPUT // NtQuerySystemInformationEx\n    SystemMemoryNumaInformation,                            // q: SYSTEM_MEMORY_NUMA_INFORMATION_INPUT, SYSTEM_MEMORY_NUMA_INFORMATION_OUTPUT // NtQuerySystemInformationEx\n    SystemMemoryNumaPerformanceInformation,                 // q: SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUT, SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_OUTPUT // since 24H2 // 240\n    SystemCodeIntegritySignedPoliciesFullInformation,       // qs: NtQuerySystemInformationEx\n    SystemSecureCoreInformation,                            // qs: SystemSecureSecretsInformation\n    SystemTrustedAppsRuntimeInformation,                    // q: SYSTEM_TRUSTEDAPPS_RUNTIME_INFORMATION\n    SystemBadPageInformationEx,                             // q: SYSTEM_BAD_PAGE_INFORMATION\n    SystemResourceDeadlockTimeout,                          // q: ULONG\n    SystemBreakOnContextUnwindFailureInformation,           // q: ULONG (requires SeDebugPrivilege)\n    SystemOslRamdiskInformation,                            // q: SYSTEM_OSL_RAMDISK_INFORMATION\n    SystemCodeIntegrityPolicyManagementInformation,         // q: SYSTEM_CODEINTEGRITYPOLICY_MANAGEMENT // since 25H2\n    SystemMemoryNumaCacheInformation,                       // q:\n    SystemProcessorFeaturesBitMapInformation,               // q: ULONG64[2] // RTL_BITMAP_EX // RtlInitializeBitMapEx // 250\n    SystemRefTraceInformationEx,                            // q: SYSTEM_REF_TRACE_INFORMATION_EX\n    SystemBasicProcessInformation,                          // q: SYSTEM_BASICPROCESS_INFORMATION\n    SystemHandleCountInformation,                           // q: SYSTEM_HANDLECOUNT_INFORMATION\n    SystemRuntimeAttestationReport,                         // q: SYSTEM_RUNTIME_REPORT_INPUT\n    SystemPoolTagInformation2,                              // q: SYSTEM_POOLTAG_INFORMATION2 // since 26H1\n    MaxSystemInfoClass\n} SYSTEM_INFORMATION_CLASS;\n\n/**\n * The SYSTEM_BASIC_INFORMATION structure contains basic information about the current system.\n */\ntypedef struct _SYSTEM_BASIC_INFORMATION\n{\n    ULONG Reserved;                                         // Reserved\n    ULONG TimerResolution;                                  // The resolution of the timer, in milliseconds. // NtQueryTimerResolution\n    ULONG PageSize;                                         // The page size and the granularity of page protection and commitment.\n    ULONG NumberOfPhysicalPages;                            // The number of physical pages in the system. // KUSER_SHARED_DATA->NumberOfPhysicalPages\n    ULONG LowestPhysicalPageNumber;                         // The lowest memory page accessible to applications and dynamic-link libraries (DLLs).\n    ULONG HighestPhysicalPageNumber;                        // The highest memory page accessible to applications and dynamic-link libraries (DLLs).\n    ULONG AllocationGranularity;                            // The granularity for the starting address at which virtual memory can be allocated.\n    ULONG_PTR MinimumUserModeAddress;                       // A pointer to the lowest memory address accessible to applications and dynamic-link libraries (DLLs).\n    ULONG_PTR MaximumUserModeAddress;                       // A pointer to the highest memory address accessible to applications and dynamic-link libraries (DLLs).\n    KAFFINITY ActiveProcessorsAffinityMask;                 // A mask representing the set of processors configured in the current processor group. // deprecated\n    UCHAR NumberOfProcessors;                               // The number of logical processors in the current processor group. // deprecated\n} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;\n\n// SYSTEM_PROCESSOR_INFORMATION // ProcessorFeatureBits (see also SYSTEM_PROCESSOR_FEATURES_INFORMATION)\n#define KF32_V86_VIS      0x00000001 // Virtual 8086 mode.\n#define KF32_RDTSC        0x00000002 // RDTSC (Read Time-Stamp Counter) instruction.\n#define KF32_CR4          0x00000004 // CR4 (Control Register 4) register.\n#define KF32_CMOV         0x00000008 // CMOV (Conditional Move) instruction.\n#define KF32_GLOBAL_PAGE  0x00000010 // Global memory pages.\n#define KF32_LARGE_PAGE   0x00000020 // Large memory pages.\n#define KF32_MTRR         0x00000040 // MTRR (Memory Type Range Registers).\n#define KF32_CMPXCHG8B    0x00000080 // CMPXCHG8B (CompareExchange) instruction.\n#define KF32_MMX          0x00000100 // MMX (MultiMedia eXtensions).\n#define KF32_WORKING_PTE  0x00000200 // PTE (Page Table Entries).\n#define KF32_PAT          0x00000400 // PAT (Page Attribute Table).\n#define KF32_FXSR         0x00000800 // FXSR (Floating Point Extended Save and Restore).\n#define KF32_FAST_SYSCALL 0x00001000 // Fast system calls.\n#define KF32_XMMI         0x00002000 // XMMI (Streaming SIMD Extensions - 32-bit).\n#define KF32_3DNOW        0x00004000 // AMD 3DNow! technology.\n#define KF32_AMDK6MTRR    0x00008000 // AMD K6 MTRR.\n#define KF32_XMMI64       0x00010000 // XMMI (Streaming SIMD Extensions - 64-bit).\n#define KF32_DTS          0x00020000 // DTS (Digital Thermal Sensor).\n#define KF32_TM2          0x00040000 // TM2 (Thermal Monitor 2).\n#define KF32_EST          0x00080000 // EST (Enhanced SpeedStep Technology).\n#define KF32_IA64         0x00100000 // Intel Itanium architecture.\n#define KF32_3DNOW2       0x00200000 // AMD 3DNow! technology, version 2.\n#define KF32_VMX          0x00400000 // VMX (Virtual Machine Extensions).\n#define KF32_SMX          0x00800000 // SMX (Safer Mode Extensions).\n#define KF32_EST2         0x01000000 // EST (Enhanced SpeedStep Technology), version 2.\n#define KF32_SSSE3        0x02000000 // SSSE3 (Supplemental Streaming SIMD Extensions 3).\n#define KF32_CX16         0x04000000 // CMPXCHG16B instruction.\n#define KF32_ETPRD        0x08000000 // ETPRD (Enhanced Time-Stamp Counter Priority Rotation Disable).\n#define KF32_PDCM         0x10000000 // PDCM (Performance and Debug Capability MSR).\n#define KF32_NOEXECUTE    0x20000000 // No-Execute (NX) bit.\n#define KF32_GLOBAL_32BIT_EXECUTE 0x40000000\n#define KF32_GLOBAL_32BIT_NOEXECUTE 0x80000000\n\n/**\n * The SYSTEM_PROCESSOR_INFORMATION structure contains information about the current processor.\n *\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info\n */\ntypedef struct _SYSTEM_PROCESSOR_INFORMATION\n{\n    USHORT ProcessorArchitecture;\n    USHORT ProcessorLevel;\n    USHORT ProcessorRevision;\n    USHORT MaximumProcessors;\n    ULONG ProcessorFeatureBits;\n} SYSTEM_PROCESSOR_INFORMATION, *PSYSTEM_PROCESSOR_INFORMATION;\n\n/**\n * The SYSTEM_PERFORMANCE_INFORMATION structure contains detailed system-wide performance statistics.\n */\ntypedef struct _SYSTEM_PERFORMANCE_INFORMATION\n{\n    LARGE_INTEGER IdleProcessTime;              // Total time spent by the idle process (in 100ns units). Used to calculate overall CPU idle percentage; combine with per-processor stats for system CPU usage.\n    LARGE_INTEGER IoReadTransferCount;          // Total bytes read by all I/O operations system-wide. Combine with IoWriteTransferCount and IoOtherTransferCount for total I/O throughput.\n    LARGE_INTEGER IoWriteTransferCount;         // Total bytes written by all I/O operations system-wide. Use with IoReadTransferCount for disk throughput analysis.\n    LARGE_INTEGER IoOtherTransferCount;         // Total bytes transferred by non-read/write I/O operations (e.g., device control). Add to above for total I/O.\n    ULONG IoReadOperationCount;                 // Number of read I/O operations. Use with IoReadTransferCount to get average read size per operation.\n    ULONG IoWriteOperationCount;                // Number of write I/O operations. Use with IoWriteTransferCount for average write size per operation.\n    ULONG IoOtherOperationCount;                // Number of non-read/write I/O operations. Combine with above for total I/O operation count. */\n    ULONG AvailablePages;                       // Number of free physical memory pages available for immediate allocation to processes. (Display: Value * PageSize for bytes). Indicates instantly available RAM.\n    ULONG CommittedPages;                       // Number of committed virtual memory pages (backed by RAM or pagefile). Use with CommitLimit to assess memory pressure and overcommit risk.\n    ULONG CommitLimit;                          // Maximum number of pages that can be committed (RAM + pagefile). Compare with CommittedPages to determine available commit space.\n    ULONG PeakCommitment;                       // Highest number of committed pages since boot. Tracks historical maximum memory commitment.\n    ULONG PageFaultCount;                       // Total number of page faults (both soft and hard) since boot. Includes all types of faults.\n    ULONG CopyOnWriteCount;                     // Number of page faults due to copy-on-write events. Subset of PageFaultCount. Indicates process memory sharing and forking activity.\n    ULONG TransitionCount;                      // Number of page faults due to transition from standby to active. Subset of PageFaultCount. Indicates memory reactivation from standby lists.\n    ULONG CacheTransitionCount;                 // Number of page faults due to cache transitions. Subset of TransitionCount. Indicates faults resolved from the system cache.\n    ULONG DemandZeroCount;                      // Number of page faults resolved by zeroing a page (demand-zero). Subset of PageFaultCount. Indicates new memory allocations.\n    ULONG PageReadCount;                        // Number of pages read from disk to resolve faults. Use with PageReadIoCount for read efficiency (pages per I/O).\n    ULONG PageReadIoCount;                      // Number of I/O operations for page reads. Compare with PageReadCount for average pages per I/O.\n    ULONG CacheReadCount;                       // Number of pages read from the system cache. Use with CacheIoCount for cache hit/miss analysis.\n    ULONG CacheIoCount;                         // Number of I/O operations for cache reads. Compare with CacheReadCount for average pages per cache I/O.\n    ULONG DirtyPagesWriteCount;                 // Number of dirty pages written to disk (writeback). Use with DirtyWriteIoCount for write efficiency.\n    ULONG DirtyWriteIoCount;                    // Number of I/O operations for dirty page writes. Compare with DirtyPagesWriteCount for average pages per write I/O.\n    ULONG MappedPagesWriteCount;                // Number of mapped pages written (e.g., memory-mapped files). Use with MappedWriteIoCount for mapped file activity.\n    ULONG MappedWriteIoCount;                   // Number of I/O operations for mapped page writes. Compare with MappedPagesWriteCount for average mapped write size.\n    ULONG PagedPoolPages;                       // Number of pages used by the paged pool (kernel memory that can be paged out). Combine with NonPagedPoolPages for total pool usage.\n    ULONG NonPagedPoolPages;                    // Number of pages used by the nonpaged pool (kernel memory that must remain resident). Combine with PagedPoolPages for total pool usage.\n    ULONG PagedPoolAllocs;                      // Number of paged pool allocations. Use with PagedPoolFrees for leak detection and pool usage trends.\n    ULONG PagedPoolFrees;                       // Number of paged pool frees. Compare with PagedPoolAllocs to detect leaks or fragmentation.\n    ULONG NonPagedPoolAllocs;                   // Number of nonpaged pool allocations. Use with NonPagedPoolFrees for leak detection.\n    ULONG NonPagedPoolFrees;                    // Number of nonpaged pool frees. Compare with NonPagedPoolAllocs for pool usage.\n    ULONG FreeSystemPtes;                       // Number of free system page table entries (PTEs). Low values may indicate kernel memory exhaustion or fragmentation.\n    ULONG ResidentSystemCodePage;               // Number of resident pages for system code (kernel and drivers). Use with TotalSystemCodePages for residency ratio.\n    ULONG TotalSystemDriverPages;               // Total pages used by system drivers. Combine with TotalSystemCodePages for total kernel code usage.\n    ULONG TotalSystemCodePages;                 // Total pages used by system code (kernel + drivers). Use with ResidentSystemCodePage for residency analysis.\n    ULONG NonPagedPoolLookasideHits;            // Hits in nonpaged pool lookaside lists. Higher values indicate efficient small nonpaged allocations.\n    ULONG PagedPoolLookasideHits;               // Hits in paged pool lookaside lists. Higher values indicate efficient small paged allocations.\n    ULONG AvailablePagedPoolPages;              // Number of free pages in the paged pool. Monitor for pool exhaustion or fragmentation.\n    ULONG ResidentSystemCachePage;              // Resident pages in the system cache. Use with ResidentPagedPoolPage for cache residency analysis.\n    ULONG ResidentPagedPoolPage;                // Resident pages in the paged pool. Indicates how much of the paged pool is currently resident in RAM.\n    ULONG ResidentSystemDriverPage;             // Resident pages for system drivers. Use with TotalSystemDriverPages for residency ratio.\n    ULONG CcFastReadNoWait;                     // Fast cache reads completed without waiting. Use with CcFastReadWait for cache performance analysis.\n    ULONG CcFastReadWait;                       // Fast cache reads that required waiting. Compare with CcFastReadNoWait to assess cache latency.\n    ULONG CcFastReadResourceMiss;               // Fast cache read misses due to resource contention. Indicates cache bottlenecks.\n    ULONG CcFastReadNotPossible;                // Fast cache reads not possible (e.g., file not cached). Indicates cache limitations or bypasses.\n    ULONG CcFastMdlReadNoWait;                  // Fast MDL (Memory Descriptor List) reads completed without waiting. Use with CcFastMdlReadWait.\n    ULONG CcFastMdlReadWait;                    // Fast MDL reads that required waiting. Compare with CcFastMdlReadNoWait.\n    ULONG CcFastMdlReadResourceMiss;            // Fast MDL read misses due to resource contention. Indicates MDL bottlenecks.\n    ULONG CcFastMdlReadNotPossible;             // Fast MDL reads not possible. Indicates MDL limitations or cache bypass.\n    ULONG CcMapDataNoWait;                      // Cache map data operations completed without waiting. Use with CcMapDataWait for mapping efficiency.\n    ULONG CcMapDataWait;                        // Cache map data operations that required waiting. Compare with CcMapDataNoWait.\n    ULONG CcMapDataNoWaitMiss;                  // Cache map data misses without waiting. Indicates mapping bottlenecks.\n    ULONG CcMapDataWaitMiss;                    // Cache map data misses with waiting. Indicates mapping bottlenecks under contention.\n    ULONG CcPinMappedDataCount;                 // Number of pinned mapped data pages. Indicates how much data is locked in cache for I/O.\n    ULONG CcPinReadNoWait;                      // Pin reads completed without waiting. Use with CcPinReadWait for pinning efficiency.\n    ULONG CcPinReadWait;                        // Pin reads that required waiting. Compare with CcPinReadNoWait.\n    ULONG CcPinReadNoWaitMiss;                  // Pin read misses without waiting. Indicates pinning bottlenecks.\n    ULONG CcPinReadWaitMiss;                    // Pin read misses with waiting. Indicates pinning bottlenecks under contention.\n    ULONG CcCopyReadNoWait;                     // Copy reads completed without waiting. Use with CcCopyReadWait for copy efficiency.\n    ULONG CcCopyReadWait;                       // Copy reads that required waiting. Compare with CcCopyReadNoWait.\n    ULONG CcCopyReadNoWaitMiss;                 // Copy read misses without waiting. Indicates copy bottlenecks.\n    ULONG CcCopyReadWaitMiss;                   // Copy read misses with waiting. Indicates copy bottlenecks under contention.\n    ULONG CcMdlReadNoWait;                      // MDL reads completed without waiting. Use with CcMdlReadWait for MDL efficiency.\n    ULONG CcMdlReadWait;                        // MDL reads that required waiting. Compare with CcMdlReadNoWait.\n    ULONG CcMdlReadNoWaitMiss;                  // MDL read misses without waiting. Indicates MDL bottlenecks.\n    ULONG CcMdlReadWaitMiss;                    // MDL read misses with waiting. Indicates MDL bottlenecks under contention.\n    ULONG CcReadAheadIos;                       // Number of read-ahead I/O operations. Indicates cache prefetching activity.\n    ULONG CcLazyWriteIos;                       // Number of lazy write I/O operations. Indicates deferred write activity by the cache manager.\n    ULONG CcLazyWritePages;                     // Number of pages written by the lazy writer. Use with CcLazyWriteIos for writeback efficiency.\n    ULONG CcDataFlushes;                        // Number of cache data flushes. Indicates cache consistency operations (e.g., file close).\n    ULONG CcDataPages;                          // Number of pages flushed from cache. Use with CcDataFlushes for average flush size.\n    ULONG ContextSwitches;                      // Number of context switches system-wide. Use for CPU scheduling and multitasking analysis.\n    ULONG FirstLevelTbFills;                    // First-level translation buffer (TLB) fills. Indicates TLB efficiency and memory access patterns.\n    ULONG SecondLevelTbFills;                   // Second-level TLB fills. Indicates deeper TLB misses and memory access patterns.\n    ULONG SystemCalls;                          // Number of system calls made. Use for syscall activity and system workload analysis.\n    ULONGLONG CcTotalDirtyPages;                // Total number of dirty pages in the cache (since Windows 10/Threshold). Use with CcDirtyPageThreshold for writeback policy. // since THRESHOLD\n    ULONGLONG CcDirtyPageThreshold;             // Dirty page threshold for the cache. Compare with CcTotalDirtyPages to determine if writeback is needed.\n    LONGLONG ResidentAvailablePages;            // Number of available pages that are resident in memory. Combine with AvailablePages for residency analysis.\n    ULONGLONG SharedCommittedPages;             // Number of committed pages that are shared (e.g., mapped by multiple processes). Useful for shared memory analysis.\n    ULONGLONG MdlPagesAllocated;                // Number of pages allocated for MDLs (since Windows 11 24H2). Indicates MDL resource usage. // since 24H2\n    ULONGLONG PfnDatabaseCommittedPages;        // Number of pages committed for the PFN (Page Frame Number) database. Kernel memory usage for tracking physical pages.\n    ULONGLONG SystemPageTableCommittedPages;    // Number of pages committed for system page tables. Kernel memory usage for virtual-to-physical mapping structures.\n    ULONGLONG ContiguousPagesAllocated;         // Number of contiguous pages allocated. Indicates large memory allocations (e.g., for DMA or drivers).\n} SYSTEM_PERFORMANCE_INFORMATION, *PSYSTEM_PERFORMANCE_INFORMATION;\n\n/**\n * The SYSTEM_TIMEOFDAY_INFORMATION structure contains information about the system uptime.\n */\ntypedef struct _SYSTEM_TIMEOFDAY_INFORMATION\n{\n    LARGE_INTEGER BootTime;                     // Number of 100-nanosecond intervals since the system was started.\n    LARGE_INTEGER CurrentTime;                  // The current system date and time.\n    LARGE_INTEGER TimeZoneBias;                 // Number of 100-nanosecond intervals between local time and Coordinated Universal Time (UTC).\n    ULONG TimeZoneId;                           // The current system time zone identifier.\n    ULONG Reserved;                             // Reserved\n    ULONGLONG BootTimeBias;                     // Number of 100-nanosecond intervals between the boot time and Coordinated Universal Time (UTC).\n    ULONGLONG SleepTimeBias;                    // Number of 100-nanosecond intervals between the sleep time and Coordinated Universal Time (UTC).\n} SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION;\n\n/**\n * The SYSTEM_THREAD_INFORMATION structure contains information about a thread running on a system.\n * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsts/e82d73e4-cedb-4077-9099-d58f3459722f\n */\ntypedef struct _SYSTEM_THREAD_INFORMATION\n{\n    LARGE_INTEGER KernelTime;                   // Number of 100-nanosecond intervals spent executing kernel code.\n    LARGE_INTEGER UserTime;                     // Number of 100-nanosecond intervals spent executing user code.\n    LARGE_INTEGER CreateTime;                   // The date and time when the thread was created.\n    ULONG WaitTime;                             // The current time spent in ready queue or waiting (depending on the thread state).\n    PVOID StartAddress;                         // The initial start address of the thread.\n    CLIENT_ID ClientId;                         // The identifier of the thread and the process owning the thread.\n    KPRIORITY Priority;                         // The dynamic priority of the thread.\n    KPRIORITY BasePriority;                     // The starting priority of the thread.\n    ULONG ContextSwitches;                      // The total number of context switches performed.\n    KTHREAD_STATE ThreadState;                  // The current state of the thread.\n    KWAIT_REASON WaitReason;                    // The current reason the thread is waiting.\n} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;\n\n/**\n * The SYSTEM_PROCESS_INFORMATION structure contains information about a process running on a system.\n */\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_PROCESS_INFORMATION\n{\n    ULONG NextEntryOffset;                      // The address of the previous item plus the value in the NextEntryOffset member. For the last item in the array, NextEntryOffset is 0.\n    ULONG NumberOfThreads;                      // The NumberOfThreads member contains the number of threads in the process.\n    ULONGLONG WorkingSetPrivateSize;            // The total private memory that a process currently has allocated and is physically resident in memory. // since VISTA\n    ULONG HardFaultCount;                       // The total number of hard faults for data from disk rather than from in-memory pages. // since WIN7\n    ULONG NumberOfThreadsHighWatermark;         // The peak number of threads that were running at any given point in time, indicative of potential performance bottlenecks related to thread management.\n    ULONGLONG CycleTime;                        // The sum of the cycle time of all threads in the process.\n    LARGE_INTEGER CreateTime;                   // Number of 100-nanosecond intervals since the creation time of the process. Not updated during system timezone changes.\n    LARGE_INTEGER UserTime;                     // Number of 100-nanosecond intervals the process has executed in user mode.\n    LARGE_INTEGER KernelTime;                   // Number of 100-nanosecond intervals the process has executed in kernel mode.\n    UNICODE_STRING ImageName;                   // The file name of the executable image.\n    KPRIORITY BasePriority;                     // The starting priority of the process.\n    HANDLE UniqueProcessId;                     // The identifier of the process.\n    HANDLE InheritedFromUniqueProcessId;        // The identifier of the process that created this process. Not updated and incorrectly refers to processes with recycled identifiers.\n    ULONG HandleCount;                          // The current number of open handles used by the process.\n    ULONG SessionId;                            // The identifier of the Remote Desktop Services session under which the specified process is running.\n    ULONG_PTR UniqueProcessKey;                 // since VISTA (requires SystemExtendedProcessInformation)\n    SIZE_T PeakVirtualSize;                     // The peak size, in bytes, of the virtual memory used by the process.\n    SIZE_T VirtualSize;                         // The current size, in bytes, of virtual memory used by the process.\n    ULONG PageFaultCount;                       // The total number of page faults for data that is not currently in memory. The value wraps around to zero on average 24 hours.\n    SIZE_T PeakWorkingSetSize;                  // The peak size, in kilobytes, of the working set of the process.\n    SIZE_T WorkingSetSize;                      // The number of pages visible to the process in physical memory. These pages are resident and available for use without triggering a page fault.\n    SIZE_T QuotaPeakPagedPoolUsage;             // The peak quota charged to the process for pool usage, in bytes.\n    SIZE_T QuotaPagedPoolUsage;                 // The quota charged to the process for paged pool usage, in bytes.\n    SIZE_T QuotaPeakNonPagedPoolUsage;          // The peak quota charged to the process for nonpaged pool usage, in bytes.\n    SIZE_T QuotaNonPagedPoolUsage;              // The current quota charged to the process for nonpaged pool usage.\n    SIZE_T PagefileUsage;                       // The total number of bytes of page file storage in use by the process.\n    SIZE_T PeakPagefileUsage;                   // The maximum number of bytes of page-file storage used by the process.\n    SIZE_T PrivatePageCount;                    // The number of memory pages allocated for the use by the process.\n    LARGE_INTEGER ReadOperationCount;           // The total number of read operations performed.\n    LARGE_INTEGER WriteOperationCount;          // The total number of write operations performed.\n    LARGE_INTEGER OtherOperationCount;          // The total number of I/O operations performed other than read and write operations.\n    LARGE_INTEGER ReadTransferCount;            // The total number of bytes read during a read operation.\n    LARGE_INTEGER WriteTransferCount;           // The total number of bytes written during a write operation.\n    LARGE_INTEGER OtherTransferCount;           // The total number of bytes transferred during operations other than read and write operations.\n    SYSTEM_THREAD_INFORMATION Threads[1];       // This type is not defined in the structure but was added for convenience.\n} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION\n{\n    union\n    {\n        SYSTEM_THREAD_INFORMATION ThreadInfo;\n        struct\n        {\n            ULONGLONG KernelTime;           // Number of 100-nanosecond intervals spent executing kernel code.\n            ULONGLONG UserTime;             // Number of 100-nanosecond intervals spent executing user code.\n            ULONGLONG CreateTime;           // The date and time when the thread was created.\n            ULONG WaitTime;                 // The current time spent in ready queue or waiting (depending on the thread state).\n            PVOID StartAddress;             // The initial start address of the thread.\n            CLIENT_ID ClientId;             // The identifier of the thread and the process owning the thread.\n            KPRIORITY Priority;             // The dynamic priority of the thread.\n            KPRIORITY BasePriority;         // The starting priority of the thread.\n            ULONG ContextSwitches;          // The total number of context switches performed.\n            KTHREAD_STATE ThreadState;      // The current state of the thread.\n            KWAIT_REASON WaitReason;        // The current reason the thread is waiting.\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n    PVOID StackBase;                        // The lower boundary of the current thread stack.\n    PVOID StackLimit;                       // The upper boundary of the current thread stack.\n    PVOID Win32StartAddress;                // The thread's Win32 start address.\n    PVOID TebBaseAddress;                   // The base address of the memory region containing the TEB structure. // since VISTA\n    ULONG_PTR Reserved2;\n    ULONG_PTR Reserved3;\n    ULONG_PTR Reserved4;\n} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;\n\n/**\n * The SYSTEM_EXTENDED_PROCESS_INFORMATION structure contains extended information about a process running on a system.\n * https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-system_extended_process_information\n */\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_EXTENDED_PROCESS_INFORMATION\n{\n    ULONG NextEntryOffset;                  // The address of the previous item plus the value in the NextEntryOffset member. For the last item in the array, NextEntryOffset is 0.\n    ULONG NumberOfThreads;                  // The NumberOfThreads member contains the number of threads in the process.\n    ULONGLONG WorkingSetPrivateSize;        // The total private memory that a process currently has allocated and is physically resident in memory. // since VISTA\n    ULONG HardFaultCount;                   // The total number of hard faults for data from disk rather than from in-memory pages. // since WIN7\n    ULONG NumberOfThreadsHighWatermark;     // The peak number of threads that were running at any given point in time, indicative of potential performance bottlenecks related to thread management.\n    ULONGLONG CycleTime;                    // The sum of the cycle time of all threads in the process.\n    ULONGLONG CreateTime;                   // Number of 100-nanosecond intervals since the creation time of the process. Not updated during system timezone changes.\n    ULONGLONG UserTime;                     // Number of 100-nanosecond intervals the process has executed in user mode.\n    ULONGLONG KernelTime;                   // Number of 100-nanosecond intervals the process has executed in kernel mode.\n    UNICODE_STRING ImageName;               // The file name of the executable image.\n    KPRIORITY BasePriority;                 // The starting priority of the process.\n    HANDLE UniqueProcessId;                 // The identifier of the process.\n    HANDLE InheritedFromUniqueProcessId;    // The identifier of the process that created this process. Not updated and incorrectly refers to processes with recycled identifiers.\n    ULONG HandleCount;                      // The current number of open handles used by the process.\n    ULONG SessionId;                        // The identifier of the Remote Desktop Services session under which the specified process is running.\n    HANDLE UniqueProcessKey;                // since VISTA (requires SystemExtendedProcessInformation)\n    SIZE_T PeakVirtualSize;                 // The peak size, in bytes, of the virtual memory used by the process.\n    SIZE_T VirtualSize;                     // The current size, in bytes, of virtual memory used by the process.\n    ULONG PageFaultCount;                   // The total number of page faults for data that is not currently in memory. The value wraps around to zero on average 24 hours.\n    SIZE_T PeakWorkingSetSize;              // The peak size, in kilobytes, of the working set of the process.\n    SIZE_T WorkingSetSize;                  // The number of pages visible to the process in physical memory. These pages are resident and available for use without triggering a page fault.\n    SIZE_T QuotaPeakPagedPoolUsage;         // The peak quota charged to the process for pool usage, in bytes.\n    SIZE_T QuotaPagedPoolUsage;             // The quota charged to the process for paged pool usage, in bytes.\n    SIZE_T QuotaPeakNonPagedPoolUsage;      // The peak quota charged to the process for nonpaged pool usage, in bytes.\n    SIZE_T QuotaNonPagedPoolUsage;          // The current quota charged to the process for nonpaged pool usage.\n    SIZE_T PagefileUsage;                   // The total number of bytes of page file storage in use by the process.\n    SIZE_T PeakPagefileUsage;               // The maximum number of bytes of page-file storage used by the process.\n    SIZE_T PrivatePageCount;                // The number of memory pages allocated for the use by the process.\n    ULONGLONG ReadOperationCount;           // The total number of read operations performed.\n    ULONGLONG WriteOperationCount;          // The total number of write operations performed.\n    ULONGLONG OtherOperationCount;          // The total number of I/O operations performed other than read and write operations.\n    ULONGLONG ReadTransferCount;            // The total number of bytes read during a read operation.\n    ULONGLONG WriteTransferCount;           // The total number of bytes written during a write operation.\n    ULONGLONG OtherTransferCount;           // The total number of bytes transferred during operations other than read and write operations.\n    SYSTEM_THREAD_INFORMATION Threads[1];   // This type is not defined in the structure but was added for convenience.\n    // SYSTEM_PROCESS_INFORMATION_EXTENSION // SystemFullProcessInformation\n} SYSTEM_EXTENDED_PROCESS_INFORMATION, *PSYSTEM_EXTENDED_PROCESS_INFORMATION;\n\ntypedef struct _SYSTEM_CALL_COUNT_INFORMATION\n{\n    ULONG Length;\n    ULONG NumberOfTables;\n} SYSTEM_CALL_COUNT_INFORMATION, *PSYSTEM_CALL_COUNT_INFORMATION;\n\ntypedef struct _SYSTEM_DEVICE_INFORMATION\n{\n    ULONG NumberOfDisks;\n    ULONG NumberOfFloppies;\n    ULONG NumberOfCdRoms;\n    ULONG NumberOfTapes;\n    ULONG NumberOfSerialPorts;\n    ULONG NumberOfParallelPorts;\n} SYSTEM_DEVICE_INFORMATION, *PSYSTEM_DEVICE_INFORMATION;\n\n/**\n * The SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION structure contains information about the performance of each processor installed in the system.\n * https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation#system_processor_performance_information\n */\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n{\n    LARGE_INTEGER IdleTime;         // The IdleTime member contains the amount of time that the system has been idle, in 100-nanosecond intervals.\n    LARGE_INTEGER KernelTime;       // The KernelTime member contains the amount of time that the system has spent executing in Kernel mode (including all threads in all processes, on all processors), in 100-nanosecond intervals.\n    LARGE_INTEGER UserTime;         // The UserTime member contains the amount of time that the system has spent executing in User mode (including all threads in all processes, on all processors), in 100-nanosecond intervals.\n    LARGE_INTEGER DpcTime;          // The DpcTime member contains the amount of time that the system has spent processing deferred procedure calls (DPCs), in 100-nanosecond intervals.\n    LARGE_INTEGER InterruptTime;    // The InterruptTime member contains the amount of time that the system has spent processing hardware interrupts, in 100-nanosecond intervals.\n    ULONG InterruptCount;           // The InterruptCount member contains the number of interrupts that have occurred, as counted by the system.\n    ULONG Spare0;\n} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;\n\ntypedef struct _SYSTEM_FLAGS_INFORMATION\n{\n    union\n    {\n        ULONG Flags; // NtGlobalFlag\n        struct\n        {\n            ULONG StopOnException : 1;          // FLG_STOP_ON_EXCEPTION\n            ULONG ShowLoaderSnaps : 1;          // FLG_SHOW_LDR_SNAPS\n            ULONG DebugInitialCommand : 1;      // FLG_DEBUG_INITIAL_COMMAND\n            ULONG StopOnHungGUI : 1;            // FLG_STOP_ON_HUNG_GUI\n            ULONG HeapEnableTailCheck : 1;      // FLG_HEAP_ENABLE_TAIL_CHECK\n            ULONG HeapEnableFreeCheck : 1;      // FLG_HEAP_ENABLE_FREE_CHECK\n            ULONG HeapValidateParameters : 1;   // FLG_HEAP_VALIDATE_PARAMETERS\n            ULONG HeapValidateAll : 1;          // FLG_HEAP_VALIDATE_ALL\n            ULONG ApplicationVerifier : 1;      // FLG_APPLICATION_VERIFIER\n            ULONG MonitorSilentProcessExit : 1; // FLG_MONITOR_SILENT_PROCESS_EXIT\n            ULONG PoolEnableTagging : 1;        // FLG_POOL_ENABLE_TAGGING\n            ULONG HeapEnableTagging : 1;        // FLG_HEAP_ENABLE_TAGGING\n            ULONG UserStackTraceDb : 1;         // FLG_USER_STACK_TRACE_DB\n            ULONG KernelStackTraceDb : 1;       // FLG_KERNEL_STACK_TRACE_DB\n            ULONG MaintainObjectTypeList : 1;   // FLG_MAINTAIN_OBJECT_TYPELIST\n            ULONG HeapEnableTagByDll : 1;       // FLG_HEAP_ENABLE_TAG_BY_DLL\n            ULONG DisableStackExtension : 1;    // FLG_DISABLE_STACK_EXTENSION\n            ULONG EnableCsrDebug : 1;           // FLG_ENABLE_CSRDEBUG\n            ULONG EnableKDebugSymbolLoad : 1;   // FLG_ENABLE_KDEBUG_SYMBOL_LOAD\n            ULONG DisablePageKernelStacks : 1;  // FLG_DISABLE_PAGE_KERNEL_STACKS\n            ULONG EnableSystemCritBreaks : 1;   // FLG_ENABLE_SYSTEM_CRIT_BREAKS\n            ULONG HeapDisableCoalescing : 1;    // FLG_HEAP_DISABLE_COALESCING\n            ULONG EnableCloseExceptions : 1;    // FLG_ENABLE_CLOSE_EXCEPTIONS\n            ULONG EnableExceptionLogging : 1;   // FLG_ENABLE_EXCEPTION_LOGGING\n            ULONG EnableHandleTypeTagging : 1;  // FLG_ENABLE_HANDLE_TYPE_TAGGING\n            ULONG HeapPageAllocs : 1;           // FLG_HEAP_PAGE_ALLOCS\n            ULONG DebugInitialCommandEx : 1;    // FLG_DEBUG_INITIAL_COMMAND_EX\n            ULONG DisableDbgPrint : 1;          // FLG_DISABLE_DBGPRINT\n            ULONG CritSecEventCreation : 1;     // FLG_CRITSEC_EVENT_CREATION\n            ULONG LdrTopDown : 1;               // FLG_LDR_TOP_DOWN\n            ULONG EnableHandleExceptions : 1;   // FLG_ENABLE_HANDLE_EXCEPTIONS\n            ULONG DisableProtDlls : 1;          // FLG_DISABLE_PROTDLLS\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n} SYSTEM_FLAGS_INFORMATION, *PSYSTEM_FLAGS_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_CALL_TIME_INFORMATION\n{\n    ULONG Length;\n    ULONG TotalCalls;\n    LARGE_INTEGER TimeOfCalls[1];\n} SYSTEM_CALL_TIME_INFORMATION, *PSYSTEM_CALL_TIME_INFORMATION;\n\n// RTL_PROCESS_LOCK_INFORMATION Type\n#define RTL_CRITSECT_TYPE 0\n#define RTL_RESOURCE_TYPE 1\n\n// private\ntypedef struct _RTL_PROCESS_LOCK_INFORMATION\n{\n    PVOID Address;\n    USHORT Type;\n    USHORT CreatorBackTraceIndex;\n    HANDLE OwningThread;\n    LONG LockCount;\n    ULONG ContentionCount;\n    ULONG EntryCount;\n    LONG RecursionCount;\n    ULONG NumberOfWaitingShared;\n    ULONG NumberOfWaitingExclusive;\n} RTL_PROCESS_LOCK_INFORMATION, *PRTL_PROCESS_LOCK_INFORMATION;\n\n// private\ntypedef struct _RTL_PROCESS_LOCKS\n{\n    ULONG NumberOfLocks;\n    _Field_size_(NumberOfLocks) RTL_PROCESS_LOCK_INFORMATION Locks[1];\n} RTL_PROCESS_LOCKS, *PRTL_PROCESS_LOCKS;\n\n// private\ntypedef struct _RTL_PROCESS_BACKTRACE_INFORMATION\n{\n    PCHAR SymbolicBackTrace;\n    ULONG TraceCount;\n    USHORT Index;\n    USHORT Depth;\n    PVOID BackTrace[32];\n} RTL_PROCESS_BACKTRACE_INFORMATION, *PRTL_PROCESS_BACKTRACE_INFORMATION;\n\n// private\ntypedef struct _RTL_PROCESS_BACKTRACES\n{\n    SIZE_T CommittedMemory;\n    SIZE_T ReservedMemory;\n    ULONG NumberOfBackTraceLookups;\n    ULONG NumberOfBackTraces;\n    _Field_size_(NumberOfBackTraces) RTL_PROCESS_BACKTRACE_INFORMATION BackTraces[1];\n} RTL_PROCESS_BACKTRACES, *PRTL_PROCESS_BACKTRACES;\n\n// Note: This information class is deprecated since values are limited to 65535. Use SystemExtendedHandleInformation instead.\ntypedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO\n{\n    USHORT UniqueProcessId;\n    USHORT CreatorBackTraceIndex;\n    UCHAR ObjectTypeIndex;\n    UCHAR HandleAttributes;\n    USHORT HandleValue;\n    PVOID Object;\n    ACCESS_MASK GrantedAccess;\n} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;\n\ntypedef struct _SYSTEM_HANDLE_INFORMATION\n{\n    ULONG NumberOfHandles;\n    _Field_size_(NumberOfHandles) SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];\n} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_OBJECTTYPE_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG NumberOfObjects;\n    ULONG NumberOfHandles;\n    ULONG TypeIndex;\n    ULONG InvalidAttributes;\n    GENERIC_MAPPING GenericMapping;\n    ACCESS_MASK ValidAccessMask;\n    ULONG PoolType;\n    BOOLEAN SecurityRequired;\n    BOOLEAN WaitableObject;\n    UNICODE_STRING TypeName;\n} SYSTEM_OBJECTTYPE_INFORMATION, *PSYSTEM_OBJECTTYPE_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_OBJECT_INFORMATION\n{\n    ULONG NextEntryOffset;\n    PVOID Object;\n    HANDLE CreatorUniqueProcess;\n    USHORT CreatorBackTraceIndex;\n    USHORT Flags;\n    LONG PointerCount;\n    LONG HandleCount;\n    ULONG PagedPoolCharge;\n    ULONG NonPagedPoolCharge;\n    HANDLE ExclusiveProcessId;\n    PSECURITY_DESCRIPTOR SecurityDescriptor;\n    UNICODE_STRING NameInfo;\n} SYSTEM_OBJECT_INFORMATION, *PSYSTEM_OBJECT_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_PAGEFILE_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG TotalSize;\n    ULONG TotalInUse;\n    ULONG PeakUsage;\n    UNICODE_STRING PageFileName;\n} SYSTEM_PAGEFILE_INFORMATION, *PSYSTEM_PAGEFILE_INFORMATION;\n\ntypedef struct _SYSTEM_VDM_INSTEMUL_INFO\n{\n    ULONG SegmentNotPresent;\n    ULONG VdmOpcode0F;\n    ULONG OpcodeESPrefix;\n    ULONG OpcodeCSPrefix;\n    ULONG OpcodeSSPrefix;\n    ULONG OpcodeDSPrefix;\n    ULONG OpcodeFSPrefix;\n    ULONG OpcodeGSPrefix;\n    ULONG OpcodeOPER32Prefix;\n    ULONG OpcodeADDR32Prefix;\n    ULONG OpcodeINSB;\n    ULONG OpcodeINSW;\n    ULONG OpcodeOUTSB;\n    ULONG OpcodeOUTSW;\n    ULONG OpcodePUSHF;\n    ULONG OpcodePOPF;\n    ULONG OpcodeINTnn;\n    ULONG OpcodeINTO;\n    ULONG OpcodeIRET;\n    ULONG OpcodeINBimm;\n    ULONG OpcodeINWimm;\n    ULONG OpcodeOUTBimm;\n    ULONG OpcodeOUTWimm;\n    ULONG OpcodeINB;\n    ULONG OpcodeINW;\n    ULONG OpcodeOUTB;\n    ULONG OpcodeOUTW;\n    ULONG OpcodeLOCKPrefix;\n    ULONG OpcodeREPNEPrefix;\n    ULONG OpcodeREPPrefix;\n    ULONG OpcodeHLT;\n    ULONG OpcodeCLI;\n    ULONG OpcodeSTI;\n    ULONG BopCount;\n} SYSTEM_VDM_INSTEMUL_INFO, *PSYSTEM_VDM_INSTEMUL_INFO;\n\n#define MM_WORKING_SET_MAX_HARD_ENABLE 0x1\n#define MM_WORKING_SET_MAX_HARD_DISABLE 0x2\n#define MM_WORKING_SET_MIN_HARD_ENABLE 0x4\n#define MM_WORKING_SET_MIN_HARD_DISABLE 0x8\n\ntypedef struct _SYSTEM_FILECACHE_INFORMATION\n{\n    SIZE_T CurrentSize;\n    SIZE_T PeakSize;\n    ULONG PageFaultCount;\n    SIZE_T MinimumWorkingSet;\n    SIZE_T MaximumWorkingSet;\n    SIZE_T CurrentSizeIncludingTransitionInPages;\n    SIZE_T PeakSizeIncludingTransitionInPages;\n    ULONG TransitionRePurposeCount;\n    ULONG Flags;\n} SYSTEM_FILECACHE_INFORMATION, *PSYSTEM_FILECACHE_INFORMATION;\n\n// Can be used instead of SYSTEM_FILECACHE_INFORMATION\ntypedef struct _SYSTEM_BASIC_WORKING_SET_INFORMATION\n{\n    SIZE_T CurrentSize;\n    SIZE_T PeakSize;\n    ULONG PageFaultCount;\n} SYSTEM_BASIC_WORKING_SET_INFORMATION, *PSYSTEM_BASIC_WORKING_SET_INFORMATION;\n\ntypedef struct _SYSTEM_POOLTAG\n{\n    union\n    {\n        UCHAR Tag[4];\n        ULONG TagUlong;\n    } DUMMYUNIONNAME;\n    ULONG PagedAllocs;\n    ULONG PagedFrees;\n    SIZE_T PagedUsed;\n    ULONG NonPagedAllocs;\n    ULONG NonPagedFrees;\n    SIZE_T NonPagedUsed;\n} SYSTEM_POOLTAG, *PSYSTEM_POOLTAG;\n\ntypedef struct _SYSTEM_POOLTAG_INFORMATION\n{\n    ULONG Count;\n    _Field_size_(Count) SYSTEM_POOLTAG TagInfo[1];\n} SYSTEM_POOLTAG_INFORMATION, *PSYSTEM_POOLTAG_INFORMATION;\n\ntypedef struct _SYSTEM_INTERRUPT_INFORMATION\n{\n    ULONG ContextSwitches;\n    ULONG DpcCount;\n    ULONG DpcRate;\n    ULONG TimeIncrement;\n    ULONG DpcBypassCount;\n    ULONG ApcBypassCount;\n} SYSTEM_INTERRUPT_INFORMATION, *PSYSTEM_INTERRUPT_INFORMATION;\n\ntypedef struct _SYSTEM_DPC_BEHAVIOR_INFORMATION\n{\n    ULONG Spare;\n    ULONG DpcQueueDepth;\n    ULONG MinimumDpcRate;\n    ULONG AdjustDpcThreshold;\n    ULONG IdealDpcRate;\n} SYSTEM_DPC_BEHAVIOR_INFORMATION, *PSYSTEM_DPC_BEHAVIOR_INFORMATION;\n\ntypedef struct _SYSTEM_QUERY_TIME_ADJUST_INFORMATION\n{\n    ULONG TimeAdjustment;\n    ULONG TimeIncrement;\n    BOOLEAN Enable;\n} SYSTEM_QUERY_TIME_ADJUST_INFORMATION, *PSYSTEM_QUERY_TIME_ADJUST_INFORMATION;\n\ntypedef struct _SYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE\n{\n    ULONGLONG TimeAdjustment;\n    ULONGLONG TimeIncrement;\n    BOOLEAN Enable;\n} SYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE, *PSYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE;\n\ntypedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION\n{\n    ULONG TimeAdjustment;\n    BOOLEAN Enable;\n} SYSTEM_SET_TIME_ADJUST_INFORMATION, *PSYSTEM_SET_TIME_ADJUST_INFORMATION;\n\ntypedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE\n{\n    ULONGLONG TimeAdjustment;\n    BOOLEAN Enable;\n} SYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE, *PSYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE;\n\ntypedef enum _EVENT_TRACE_INFORMATION_CLASS\n{\n    EventTraceKernelVersionInformation, // EVENT_TRACE_VERSION_INFORMATION\n    EventTraceGroupMaskInformation, // EVENT_TRACE_GROUPMASK_INFORMATION\n    EventTracePerformanceInformation, // EVENT_TRACE_PERFORMANCE_INFORMATION\n    EventTraceTimeProfileInformation, // EVENT_TRACE_TIME_PROFILE_INFORMATION\n    EventTraceSessionSecurityInformation, // EVENT_TRACE_SESSION_SECURITY_INFORMATION\n    EventTraceSpinlockInformation, // EVENT_TRACE_SPINLOCK_INFORMATION\n    EventTraceStackTracingInformation, // EVENT_TRACE_STACK_TRACING_INFORMATION\n    EventTraceExecutiveResourceInformation, // EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION\n    EventTraceHeapTracingInformation, // EVENT_TRACE_HEAP_TRACING_INFORMATION\n    EventTraceHeapSummaryTracingInformation, // EVENT_TRACE_HEAP_TRACING_INFORMATION\n    EventTracePoolTagFilterInformation, // EVENT_TRACE_POOLTAG_FILTER_INFORMATION\n    EventTracePebsTracingInformation, // EVENT_TRACE_PEBS_TRACING_INFORMATION\n    EventTraceProfileConfigInformation, // EVENT_TRACE_PROFILE_CONFIG_INFORMATION\n    EventTraceProfileSourceListInformation, // EVENT_TRACE_PROFILE_LIST_INFORMATION\n    EventTraceProfileEventListInformation, // EVENT_TRACE_PROFILE_EVENT_INFORMATION\n    EventTraceProfileCounterListInformation, // EVENT_TRACE_PROFILE_COUNTER_INFORMATION\n    EventTraceStackCachingInformation, // EVENT_TRACE_STACK_CACHING_INFORMATION\n    EventTraceObjectTypeFilterInformation, // EVENT_TRACE_OBJECT_TYPE_FILTER_INFORMATION\n    EventTraceSoftRestartInformation, // EVENT_TRACE_SOFT_RESTART_INFORMATION\n    EventTraceLastBranchConfigurationInformation, // REDSTONE3\n    EventTraceLastBranchEventListInformation, // EVENT_TRACE_PROFILE_EVENT_INFORMATION\n    EventTraceProfileSourceAddInformation, // EVENT_TRACE_PROFILE_ADD_INFORMATION // REDSTONE4\n    EventTraceProfileSourceRemoveInformation, // EVENT_TRACE_PROFILE_REMOVE_INFORMATION\n    EventTraceProcessorTraceConfigurationInformation,\n    EventTraceProcessorTraceEventListInformation, // EVENT_TRACE_PROFILE_EVENT_INFORMATION\n    EventTraceCoverageSamplerInformation, // EVENT_TRACE_COVERAGE_SAMPLER_INFORMATION\n    EventTraceUnifiedStackCachingInformation, // since 21H1\n    EventTraceContextRegisterTraceInformation, // TRACE_CONTEXT_REGISTER_INFO // 24H2\n    MaxEventTraceInfoClass\n} EVENT_TRACE_INFORMATION_CLASS;\n\ntypedef struct _EVENT_TRACE_VERSION_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG EventTraceKernelVersion;\n} EVENT_TRACE_VERSION_INFORMATION, *PEVENT_TRACE_VERSION_INFORMATION;\n\ntypedef struct _EVENT_TRACE_GROUPMASK_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    TRACEHANDLE TraceHandle;\n    ULONG Masks[8]; // PERFINFO_GROUPMASK\n} EVENT_TRACE_GROUPMASK_INFORMATION, *PEVENT_TRACE_GROUPMASK_INFORMATION;\n\ntypedef struct _EVENT_TRACE_PERFORMANCE_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    LARGE_INTEGER LogfileBytesWritten;\n} EVENT_TRACE_PERFORMANCE_INFORMATION, *PEVENT_TRACE_PERFORMANCE_INFORMATION;\n\ntypedef struct _EVENT_TRACE_TIME_PROFILE_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG ProfileInterval;\n} EVENT_TRACE_TIME_PROFILE_INFORMATION, *PEVENT_TRACE_TIME_PROFILE_INFORMATION;\n\ntypedef struct _EVENT_TRACE_SESSION_SECURITY_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG SecurityInformation;\n    TRACEHANDLE TraceHandle;\n    UCHAR SecurityDescriptor[1];\n} EVENT_TRACE_SESSION_SECURITY_INFORMATION, *PEVENT_TRACE_SESSION_SECURITY_INFORMATION;\n\ntypedef struct _EVENT_TRACE_SPINLOCK_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG SpinLockSpinThreshold;\n    ULONG SpinLockAcquireSampleRate;\n    ULONG SpinLockContentionSampleRate;\n    ULONG SpinLockHoldThreshold;\n} EVENT_TRACE_SPINLOCK_INFORMATION, *PEVENT_TRACE_SPINLOCK_INFORMATION;\n\ntypedef struct _EVENT_TRACE_SYSTEM_EVENT_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    TRACEHANDLE TraceHandle;\n    ULONG HookId[1];\n} EVENT_TRACE_SYSTEM_EVENT_INFORMATION, *PEVENT_TRACE_SYSTEM_EVENT_INFORMATION;\n\ntypedef EVENT_TRACE_SYSTEM_EVENT_INFORMATION EVENT_TRACE_STACK_TRACING_INFORMATION, *PEVENT_TRACE_STACK_TRACING_INFORMATION;\ntypedef EVENT_TRACE_SYSTEM_EVENT_INFORMATION EVENT_TRACE_PEBS_TRACING_INFORMATION, *PEVENT_TRACE_PEBS_TRACING_INFORMATION;\ntypedef EVENT_TRACE_SYSTEM_EVENT_INFORMATION EVENT_TRACE_PROFILE_EVENT_INFORMATION, *PEVENT_TRACE_PROFILE_EVENT_INFORMATION;\n\ntypedef struct _EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG ReleaseSamplingRate;\n    ULONG ContentionSamplingRate;\n    ULONG NumberOfExcessiveTimeouts;\n} EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION, *PEVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION;\n\ntypedef struct _EVENT_TRACE_HEAP_TRACING_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG ProcessId[1];\n} EVENT_TRACE_HEAP_TRACING_INFORMATION, *PEVENT_TRACE_HEAP_TRACING_INFORMATION;\n\ntypedef struct _EVENT_TRACE_TAG_FILTER_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    TRACEHANDLE TraceHandle;\n    ULONG Filter[1];\n} EVENT_TRACE_TAG_FILTER_INFORMATION, *PEVENT_TRACE_TAG_FILTER_INFORMATION;\n\ntypedef EVENT_TRACE_TAG_FILTER_INFORMATION EVENT_TRACE_POOLTAG_FILTER_INFORMATION, *PEVENT_TRACE_POOLTAG_FILTER_INFORMATION;\ntypedef EVENT_TRACE_TAG_FILTER_INFORMATION EVENT_TRACE_OBJECT_TYPE_FILTER_INFORMATION, *PEVENT_TRACE_OBJECT_TYPE_FILTER_INFORMATION;\n\n// ProfileSource\n#define ETW_MAX_PROFILING_SOURCES 4\n#define ETW_MAX_PMC_EVENTS        4\n#define ETW_MAX_PMC_COUNTERS      4\n\ntypedef struct _EVENT_TRACE_PROFILE_COUNTER_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    TRACEHANDLE TraceHandle;\n    ULONG ProfileSource[1];\n} EVENT_TRACE_PROFILE_COUNTER_INFORMATION, *PEVENT_TRACE_PROFILE_COUNTER_INFORMATION;\n\ntypedef EVENT_TRACE_PROFILE_COUNTER_INFORMATION EVENT_TRACE_PROFILE_CONFIG_INFORMATION, *PEVENT_TRACE_PROFILE_CONFIG_INFORMATION;\n\n//_Struct_size_bytes_(NextEntryOffset)\n//typedef struct _PROFILE_SOURCE_INFO\n//{\n//    ULONG NextEntryOffset;\n//    ULONG Source;\n//    ULONG MinInterval;\n//    ULONG MaxInterval;\n//    PVOID Reserved;\n//    WCHAR Description[1];\n//} PROFILE_SOURCE_INFO, *PPROFILE_SOURCE_INFO;\n\ntypedef struct _PROFILE_SOURCE_INFO *PPROFILE_SOURCE_INFO;\n\ntypedef struct _EVENT_TRACE_PROFILE_LIST_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG Spare;\n    PPROFILE_SOURCE_INFO Profile[1];\n} EVENT_TRACE_PROFILE_LIST_INFORMATION, *PEVENT_TRACE_PROFILE_LIST_INFORMATION;\n\ntypedef struct _EVENT_TRACE_STACK_CACHING_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    TRACEHANDLE TraceHandle;\n    BOOLEAN Enabled;\n    UCHAR Reserved[3];\n    ULONG CacheSize;\n    ULONG BucketCount;\n} EVENT_TRACE_STACK_CACHING_INFORMATION, *PEVENT_TRACE_STACK_CACHING_INFORMATION;\n\ntypedef struct _EVENT_TRACE_SOFT_RESTART_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    TRACEHANDLE TraceHandle;\n    BOOLEAN PersistTraceBuffers;\n    WCHAR FileName[1];\n} EVENT_TRACE_SOFT_RESTART_INFORMATION, *PEVENT_TRACE_SOFT_RESTART_INFORMATION;\n\ntypedef enum _EVENT_TRACE_PROFILE_ADD_INFORMATION_VERSIONS\n{\n    EventTraceProfileAddInformationMinVersion = 0x2,\n    EventTraceProfileAddInformationV2 = 0x2,\n    EventTraceProfileAddInformationV3 = 0x3,\n    EventTraceProfileAddInformationMaxVersion = 0x3,\n} EVENT_TRACE_PROFILE_ADD_INFORMATION_VERSIONS;\n\ntypedef union _EVENT_TRACE_PROFILE_ADD_INFORMATION_V2\n{\n    struct\n    {\n        UCHAR PerfEvtEventSelect;\n        UCHAR PerfEvtUnitSelect;\n        UCHAR PerfEvtCMask;\n        UCHAR PerfEvtCInv;\n        UCHAR PerfEvtAnyThread;\n        UCHAR PerfEvtEdgeDetect;\n    } Intel;\n    struct\n    {\n        UCHAR PerfEvtEventSelect;\n        UCHAR PerfEvtUnitSelect;\n    } Amd;\n    struct\n    {\n        ULONG PerfEvtType;\n        UCHAR AllowsHalt;\n    } Arm;\n} EVENT_TRACE_PROFILE_ADD_INFORMATION_V2;\n\ntypedef union _EVENT_TRACE_PROFILE_ADD_INFORMATION_V3\n{\n    struct\n    {\n        UCHAR PerfEvtEventSelect;\n        UCHAR PerfEvtUnitSelect;\n        UCHAR PerfEvtCMask;\n        UCHAR PerfEvtCInv;\n        UCHAR PerfEvtAnyThread;\n        UCHAR PerfEvtEdgeDetect;\n    } Intel;\n    struct\n    {\n        USHORT PerfEvtEventSelect;\n        UCHAR PerfEvtUnitSelect;\n        UCHAR PerfEvtCMask;\n        UCHAR PerfEvtCInv;\n        UCHAR PerfEvtEdgeDetect;\n        UCHAR PerfEvtHostGuest;\n        UCHAR PerfPmuType;\n    } Amd;\n    struct\n    {\n        ULONG PerfEvtType;\n        UCHAR AllowsHalt;\n    } Arm;\n} EVENT_TRACE_PROFILE_ADD_INFORMATION_V3;\n\ntypedef struct _EVENT_TRACE_PROFILE_ADD_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    UCHAR Version;\n    union\n    {\n        EVENT_TRACE_PROFILE_ADD_INFORMATION_V2 V2;\n        EVENT_TRACE_PROFILE_ADD_INFORMATION_V3 V3;\n    };\n    ULONG CpuInfoHierarchy[0x3];\n    ULONG InitialInterval;\n    BOOLEAN Persist;\n    WCHAR ProfileSourceDescription[0x1];\n} EVENT_TRACE_PROFILE_ADD_INFORMATION, *PEVENT_TRACE_PROFILE_ADD_INFORMATION;\n\ntypedef struct _EVENT_TRACE_PROFILE_REMOVE_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    KPROFILE_SOURCE ProfileSource;\n    ULONG CpuInfoHierarchy[0x3];\n} EVENT_TRACE_PROFILE_REMOVE_INFORMATION, *PEVENT_TRACE_PROFILE_REMOVE_INFORMATION;\n\ntypedef struct _EVENT_TRACE_COVERAGE_SAMPLER_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    UCHAR CoverageSamplerInformationClass;\n    UCHAR MajorVersion;\n    UCHAR MinorVersion;\n    UCHAR Reserved;\n    HANDLE SamplerHandle;\n} EVENT_TRACE_COVERAGE_SAMPLER_INFORMATION, *PEVENT_TRACE_COVERAGE_SAMPLER_INFORMATION;\n\n//typedef struct _TRACE_CONTEXT_REGISTER_INFO\n//{\n//    ETW_CONTEXT_REGISTER_TYPES RegisterTypes;\n//    ULONG Reserved;\n//} TRACE_CONTEXT_REGISTER_INFO, *PTRACE_CONTEXT_REGISTER_INFO;\n\ntypedef struct _SYSTEM_EXCEPTION_INFORMATION\n{\n    ULONG AlignmentFixupCount;\n    ULONG ExceptionDispatchCount;\n    ULONG FloatingEmulationCount;\n    ULONG ByteWordEmulationCount;\n} SYSTEM_EXCEPTION_INFORMATION, *PSYSTEM_EXCEPTION_INFORMATION;\n\ntypedef enum _SYSTEM_CRASH_DUMP_CONFIGURATION_CLASS\n{\n    SystemCrashDumpDisable,\n    SystemCrashDumpReconfigure,\n    SystemCrashDumpInitializationComplete\n} SYSTEM_CRASH_DUMP_CONFIGURATION_CLASS, *PSYSTEM_CRASH_DUMP_CONFIGURATION_CLASS;\n\ntypedef struct _SYSTEM_CRASH_DUMP_STATE_INFORMATION\n{\n    SYSTEM_CRASH_DUMP_CONFIGURATION_CLASS CrashDumpConfigurationClass;\n} SYSTEM_CRASH_DUMP_STATE_INFORMATION, *PSYSTEM_CRASH_DUMP_STATE_INFORMATION;\n\ntypedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION\n{\n    BOOLEAN KernelDebuggerEnabled;\n    BOOLEAN KernelDebuggerNotPresent;\n} SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION;\n\ntypedef struct _SYSTEM_CONTEXT_SWITCH_INFORMATION\n{\n    ULONG ContextSwitches;\n    ULONG FindAny;\n    ULONG FindLast;\n    ULONG FindIdeal;\n    ULONG IdleAny;\n    ULONG IdleCurrent;\n    ULONG IdleLast;\n    ULONG IdleIdeal;\n    ULONG PreemptAny;\n    ULONG PreemptCurrent;\n    ULONG PreemptLast;\n    ULONG SwitchToIdle;\n} SYSTEM_CONTEXT_SWITCH_INFORMATION, *PSYSTEM_CONTEXT_SWITCH_INFORMATION;\n\ntypedef struct _SYSTEM_REGISTRY_QUOTA_INFORMATION\n{\n    ULONG RegistryQuotaAllowed;\n    ULONG RegistryQuotaUsed;\n    SIZE_T PagedPoolSize;\n} SYSTEM_REGISTRY_QUOTA_INFORMATION, *PSYSTEM_REGISTRY_QUOTA_INFORMATION;\n\ntypedef struct _SYSTEM_PROCESSOR_IDLE_INFORMATION\n{\n    ULONGLONG IdleTime;\n    ULONGLONG C1Time;\n    ULONGLONG C2Time;\n    ULONGLONG C3Time;\n    ULONG C1Transitions;\n    ULONG C2Transitions;\n    ULONG C3Transitions;\n    ULONG Padding;\n} SYSTEM_PROCESSOR_IDLE_INFORMATION, *PSYSTEM_PROCESSOR_IDLE_INFORMATION;\n\ntypedef struct _SYSTEM_LEGACY_DRIVER_INFORMATION\n{\n    ULONG VetoType;\n    UNICODE_STRING VetoList;\n} SYSTEM_LEGACY_DRIVER_INFORMATION, *PSYSTEM_LEGACY_DRIVER_INFORMATION;\n\ntypedef struct _SYSTEM_LOOKASIDE_INFORMATION\n{\n    USHORT CurrentDepth;\n    USHORT MaximumDepth;\n    ULONG TotalAllocates;\n    ULONG AllocateMisses;\n    ULONG TotalFrees;\n    ULONG FreeMisses;\n    ULONG Type;\n    ULONG Tag;\n    ULONG Size;\n} SYSTEM_LOOKASIDE_INFORMATION, *PSYSTEM_LOOKASIDE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_RANGE_START_INFORMATION\n{\n    ULONG_PTR SystemRangeStart;\n} SYSTEM_RANGE_START_INFORMATION, *PSYSTEM_RANGE_START_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_VERIFIER_INFORMATION_LEGACY // pre-19H1\n{\n    ULONG NextEntryOffset;\n    ULONG Level;\n    UNICODE_STRING DriverName;\n    ULONG RaiseIrqls;\n    ULONG AcquireSpinLocks;\n    ULONG SynchronizeExecutions;\n    ULONG AllocationsAttempted;\n    ULONG AllocationsSucceeded;\n    ULONG AllocationsSucceededSpecialPool;\n    ULONG AllocationsWithNoTag;\n    ULONG TrimRequests;\n    ULONG Trims;\n    ULONG AllocationsFailed;\n    ULONG AllocationsFailedDeliberately;\n    ULONG Loads;\n    ULONG Unloads;\n    ULONG UnTrackedPool;\n    ULONG CurrentPagedPoolAllocations;\n    ULONG CurrentNonPagedPoolAllocations;\n    ULONG PeakPagedPoolAllocations;\n    ULONG PeakNonPagedPoolAllocations;\n    SIZE_T PagedPoolUsageInBytes;\n    SIZE_T NonPagedPoolUsageInBytes;\n    SIZE_T PeakPagedPoolUsageInBytes;\n    SIZE_T PeakNonPagedPoolUsageInBytes;\n} SYSTEM_VERIFIER_INFORMATION_LEGACY, *PSYSTEM_VERIFIER_INFORMATION_LEGACY;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_VERIFIER_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG Level;\n    ULONG RuleClasses[2];\n    ULONG TriageContext;\n    ULONG AreAllDriversBeingVerified;\n    UNICODE_STRING DriverName;\n    ULONG RaiseIrqls;\n    ULONG AcquireSpinLocks;\n    ULONG SynchronizeExecutions;\n    ULONG AllocationsAttempted;\n    ULONG AllocationsSucceeded;\n    ULONG AllocationsSucceededSpecialPool;\n    ULONG AllocationsWithNoTag;\n    ULONG TrimRequests;\n    ULONG Trims;\n    ULONG AllocationsFailed;\n    ULONG AllocationsFailedDeliberately;\n    ULONG Loads;\n    ULONG Unloads;\n    ULONG UnTrackedPool;\n    ULONG CurrentPagedPoolAllocations;\n    ULONG CurrentNonPagedPoolAllocations;\n    ULONG PeakPagedPoolAllocations;\n    ULONG PeakNonPagedPoolAllocations;\n    SIZE_T PagedPoolUsageInBytes;\n    SIZE_T NonPagedPoolUsageInBytes;\n    SIZE_T PeakPagedPoolUsageInBytes;\n    SIZE_T PeakNonPagedPoolUsageInBytes;\n} SYSTEM_VERIFIER_INFORMATION, *PSYSTEM_VERIFIER_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SESSION_PROCESS_INFORMATION\n{\n    ULONG SessionId;\n    ULONG BufferSize;\n    PVOID Buffer;\n} SYSTEM_SESSION_PROCESS_INFORMATION, *PSYSTEM_SESSION_PROCESS_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// private\ntypedef struct _SYSTEM_GDI_DRIVER_INFORMATION\n{\n    UNICODE_STRING DriverName;\n    PVOID ImageAddress;\n    PVOID SectionPointer;\n    PVOID EntryPoint;\n    PIMAGE_EXPORT_DIRECTORY ExportSectionPointer;\n    ULONG ImageLength;\n} SYSTEM_GDI_DRIVER_INFORMATION, *PSYSTEM_GDI_DRIVER_INFORMATION;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// geoffchappell\n#ifdef _WIN64\n#define MAXIMUM_NODE_COUNT 0x40\n#else\n#define MAXIMUM_NODE_COUNT 0x10\n#endif\n\n// private\ntypedef struct _SYSTEM_NUMA_INFORMATION\n{\n    ULONG HighestNodeNumber;\n    ULONG Reserved;\n    union\n    {\n        GROUP_AFFINITY ActiveProcessorsGroupAffinity[MAXIMUM_NODE_COUNT];\n        ULONGLONG AvailableMemory[MAXIMUM_NODE_COUNT];\n        ULONGLONG Pad[MAXIMUM_NODE_COUNT * 2];\n    } DUMMYUNIONNAME;\n} SYSTEM_NUMA_INFORMATION, *PSYSTEM_NUMA_INFORMATION;\n\ntypedef struct _SYSTEM_PROCESSOR_POWER_INFORMATION\n{\n    UCHAR CurrentFrequency;\n    UCHAR ThermalLimitFrequency;\n    UCHAR ConstantThrottleFrequency;\n    UCHAR DegradedThrottleFrequency;\n    UCHAR LastBusyFrequency;\n    UCHAR LastC3Frequency;\n    UCHAR LastAdjustedBusyFrequency;\n    UCHAR ProcessorMinThrottle;\n    UCHAR ProcessorMaxThrottle;\n    ULONG NumberOfFrequencies;\n    ULONG PromotionCount;\n    ULONG DemotionCount;\n    ULONG ErrorCount;\n    ULONG RetryCount;\n    ULONGLONG CurrentFrequencyTime;\n    ULONGLONG CurrentProcessorTime;\n    ULONGLONG CurrentProcessorIdleTime;\n    ULONGLONG LastProcessorTime;\n    ULONGLONG LastProcessorIdleTime;\n    ULONGLONG Energy;\n} SYSTEM_PROCESSOR_POWER_INFORMATION, *PSYSTEM_PROCESSOR_POWER_INFORMATION;\n\ntypedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX\n{\n    PVOID Object;\n    HANDLE UniqueProcessId;\n    HANDLE HandleValue;\n    ACCESS_MASK GrantedAccess;\n    USHORT CreatorBackTraceIndex;\n    USHORT ObjectTypeIndex;\n    ULONG HandleAttributes;\n    ULONG Reserved;\n} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;\n\ntypedef struct _SYSTEM_HANDLE_INFORMATION_EX\n{\n    ULONG_PTR NumberOfHandles;\n    ULONG_PTR Reserved;\n    _Field_size_(NumberOfHandles) SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];\n} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;\n\ntypedef struct _SYSTEM_BIGPOOL_ENTRY\n{\n    union\n    {\n        PVOID VirtualAddress;\n        ULONG_PTR NonPaged : 1;\n    };\n    SIZE_T SizeInBytes;\n    union\n    {\n        UCHAR Tag[4];\n        ULONG TagUlong;\n    };\n} SYSTEM_BIGPOOL_ENTRY, *PSYSTEM_BIGPOOL_ENTRY;\n\ntypedef struct _SYSTEM_BIGPOOL_INFORMATION\n{\n    ULONG Count;\n    _Field_size_(Count) SYSTEM_BIGPOOL_ENTRY AllocatedInfo[1];\n} SYSTEM_BIGPOOL_INFORMATION, *PSYSTEM_BIGPOOL_INFORMATION;\n\ntypedef struct _SYSTEM_POOL_ENTRY\n{\n    BOOLEAN Allocated;\n    BOOLEAN Spare0;\n    USHORT AllocatorBackTraceIndex;\n    ULONG Size;\n    union\n    {\n        UCHAR Tag[4];\n        ULONG TagUlong;\n        PVOID ProcessChargedQuota;\n    };\n} SYSTEM_POOL_ENTRY, *PSYSTEM_POOL_ENTRY;\n\ntypedef struct _SYSTEM_POOL_INFORMATION\n{\n    SIZE_T TotalSize;\n    PVOID FirstEntry;\n    USHORT EntryOverhead;\n    BOOLEAN PoolTagPresent;\n    BOOLEAN Spare0;\n    ULONG NumberOfEntries;\n    _Field_size_(NumberOfEntries) SYSTEM_POOL_ENTRY Entries[1];\n} SYSTEM_POOL_INFORMATION, *PSYSTEM_POOL_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_SESSION_POOLTAG_INFORMATION\n{\n    SIZE_T NextEntryOffset;\n    ULONG SessionId;\n    ULONG Count;\n    _Field_size_(Count) SYSTEM_POOLTAG TagInfo[1];\n} SYSTEM_SESSION_POOLTAG_INFORMATION, *PSYSTEM_SESSION_POOLTAG_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_SESSION_MAPPED_VIEW_INFORMATION\n{\n    SIZE_T NextEntryOffset;\n    ULONG SessionId;\n    ULONG ViewFailures;\n    SIZE_T NumberOfBytesAvailable;\n    SIZE_T NumberOfBytesAvailableContiguous;\n} SYSTEM_SESSION_MAPPED_VIEW_INFORMATION, *PSYSTEM_SESSION_MAPPED_VIEW_INFORMATION;\n\ntypedef enum _WATCHDOG_HANDLER_ACTION\n{\n    WdActionSetTimeoutValue,\n    WdActionQueryTimeoutValue,\n    WdActionResetTimer,\n    WdActionStopTimer,\n    WdActionStartTimer,\n    WdActionSetTriggerAction,\n    WdActionQueryTriggerAction,\n    WdActionQueryState\n} WATCHDOG_HANDLER_ACTION;\n\ntypedef _Function_class_(SYSTEM_WATCHDOG_HANDLER)\nNTSTATUS NTAPI SYSTEM_WATCHDOG_HANDLER(\n    _In_ WATCHDOG_HANDLER_ACTION Action,\n    _In_ PVOID Context,\n    _Inout_ PULONG DataValue,\n    _In_ BOOLEAN NoLocks\n    );\ntypedef SYSTEM_WATCHDOG_HANDLER* PSYSTEM_WATCHDOG_HANDLER;\n\n// private\ntypedef struct _SYSTEM_WATCHDOG_HANDLER_INFORMATION\n{\n    PSYSTEM_WATCHDOG_HANDLER WdHandler;\n    PVOID Context;\n} SYSTEM_WATCHDOG_HANDLER_INFORMATION, *PSYSTEM_WATCHDOG_HANDLER_INFORMATION;\n\ntypedef enum _WATCHDOG_INFORMATION_CLASS\n{\n    WdInfoTimeoutValue = 0,\n    WdInfoResetTimer = 1,\n    WdInfoStopTimer = 2,\n    WdInfoStartTimer = 3,\n    WdInfoTriggerAction = 4,\n    WdInfoState = 5,\n    WdInfoTriggerReset = 6,\n    WdInfoNop = 7,\n    WdInfoGeneratedLastReset = 8,\n    WdInfoInvalid = 9,\n} WATCHDOG_INFORMATION_CLASS;\n\n// private\ntypedef struct _SYSTEM_WATCHDOG_TIMER_INFORMATION\n{\n    WATCHDOG_INFORMATION_CLASS WdInfoClass;\n    ULONG DataValue;\n} SYSTEM_WATCHDOG_TIMER_INFORMATION, *PSYSTEM_WATCHDOG_TIMER_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n// private\ntypedef enum _SYSTEM_FIRMWARE_TABLE_ACTION\n{\n    SystemFirmwareTableEnumerate,\n    SystemFirmwareTableGet,\n    SystemFirmwareTableMax\n} SYSTEM_FIRMWARE_TABLE_ACTION;\n\n// private\ntypedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION\n{\n    ULONG ProviderSignature; // (same as the GetSystemFirmwareTable function)\n    SYSTEM_FIRMWARE_TABLE_ACTION Action;\n    ULONG TableID;\n    ULONG TableBufferLength;\n    _Field_size_bytes_(TableBufferLength) UCHAR TableBuffer[1];\n} SYSTEM_FIRMWARE_TABLE_INFORMATION, *PSYSTEM_FIRMWARE_TABLE_INFORMATION;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n// private\ntypedef _Function_class_(FNFTH)\nNTSTATUS STDAPIVCALLTYPE FNFTH(\n    _Inout_ PSYSTEM_FIRMWARE_TABLE_INFORMATION SystemFirmwareTableInfo\n    );\ntypedef FNFTH* PFNFTH;\n\n// private\ntypedef struct _SYSTEM_FIRMWARE_TABLE_HANDLER\n{\n    ULONG ProviderSignature;\n    BOOLEAN Register;\n    PFNFTH FirmwareTableHandler;\n    PVOID DriverObject;\n} SYSTEM_FIRMWARE_TABLE_HANDLER, *PSYSTEM_FIRMWARE_TABLE_HANDLER;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// private\ntypedef struct _SYSTEM_MEMORY_LIST_INFORMATION\n{\n    SIZE_T ZeroPageCount;\n    SIZE_T FreePageCount;\n    SIZE_T ModifiedPageCount;\n    SIZE_T ModifiedNoWritePageCount;\n    SIZE_T BadPageCount;\n    SIZE_T PageCountByPriority[8];\n    SIZE_T RepurposedPagesByPriority[8];\n    SIZE_T ModifiedPageCountPageFile;\n} SYSTEM_MEMORY_LIST_INFORMATION, *PSYSTEM_MEMORY_LIST_INFORMATION;\n\n// private\ntypedef enum _SYSTEM_MEMORY_LIST_COMMAND\n{\n    MemoryCaptureAccessedBits,\n    MemoryCaptureAndResetAccessedBits,\n    MemoryEmptyWorkingSets,\n    MemoryFlushModifiedList,\n    MemoryPurgeStandbyList,\n    MemoryPurgeLowPriorityStandbyList,\n    MemoryCommandMax\n} SYSTEM_MEMORY_LIST_COMMAND;\n\n/**\n * The SYSTEM_THREAD_CID_PRIORITY_INFORMATION structure is used with NtSetSystemInformation\n * to set the priority of a thread by its client ID (process ID and thread ID) without\n * requiring a thread handle.\n *\n * \\remarks This structure is used with the SystemThreadPriorityClientIdInformation\n * information class (0x52). The caller must have SeIncreaseBasePriorityPrivilege\n * to raise a thread's priority above normal.\n */\ntypedef struct _SYSTEM_THREAD_CID_PRIORITY_INFORMATION\n{\n    CLIENT_ID ClientId; // The process and thread identifiers of the target thread.\n    KPRIORITY Priority; // The new priority value to assign to the thread.\n} SYSTEM_THREAD_CID_PRIORITY_INFORMATION, *PSYSTEM_THREAD_CID_PRIORITY_INFORMATION;\n\n/**\n * The SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION structure contains the cumulative number of clock cycles a logical processor\n * has spent running its idle thread, deferred procedure calls (DPCs) and interrupt service routines (ISRs) since it became active.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryidleprocessorcycletimeex\n */\ntypedef struct _SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION\n{\n    ULONGLONG CycleTime;\n} SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION, *PSYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_VERIFIER_ISSUE\n{\n    ULONGLONG IssueType;\n    PVOID Address;\n    ULONGLONG Parameters[2];\n} SYSTEM_VERIFIER_ISSUE, *PSYSTEM_VERIFIER_ISSUE;\n\n// private\ntypedef struct _SYSTEM_VERIFIER_CANCELLATION_INFORMATION\n{\n    ULONG CancelProbability;\n    ULONG CancelThreshold;\n    ULONG CompletionThreshold;\n    ULONG CancellationVerifierDisabled;\n    ULONG AvailableIssues;\n    SYSTEM_VERIFIER_ISSUE Issues[128];\n} SYSTEM_VERIFIER_CANCELLATION_INFORMATION, *PSYSTEM_VERIFIER_CANCELLATION_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_REF_TRACE_INFORMATION\n{\n    BOOLEAN TraceEnable;\n    BOOLEAN TracePermanent;\n    UNICODE_STRING TraceProcessName;\n    UNICODE_STRING TracePoolTags;\n} SYSTEM_REF_TRACE_INFORMATION, *PSYSTEM_REF_TRACE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SPECIAL_POOL_INFORMATION\n{\n    ULONG PoolTag;\n    ULONG Flags;\n} SYSTEM_SPECIAL_POOL_INFORMATION, *PSYSTEM_SPECIAL_POOL_INFORMATION;\n\n/**\n * The SYSTEM_PROCESS_ID_INFORMATION structure retrieves the executable image\n * name associated with a specific process ID. The caller supplies a process ID,\n * and on return the system fills the UNICODE_STRING with the corresponding image path.\n */\ntypedef struct _SYSTEM_PROCESS_ID_INFORMATION\n{\n    HANDLE ProcessId;\n    UNICODE_STRING ImageName;\n} SYSTEM_PROCESS_ID_INFORMATION, *PSYSTEM_PROCESS_ID_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_HYPERVISOR_QUERY_INFORMATION\n{\n    BOOLEAN HypervisorConnected;\n    BOOLEAN HypervisorDebuggingEnabled;\n    BOOLEAN HypervisorPresent;\n    BOOLEAN Spare0[5];\n    ULONGLONG EnabledEnlightenments;\n} SYSTEM_HYPERVISOR_QUERY_INFORMATION, *PSYSTEM_HYPERVISOR_QUERY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION\n{\n    GUID BootIdentifier;\n    FIRMWARE_TYPE FirmwareType;\n    union\n    {\n        ULONGLONG BootFlags;\n        struct\n        {\n            ULONGLONG DbgMenuOsSelection : 1; // REDSTONE4\n            ULONGLONG DbgHiberBoot : 1;\n            ULONGLONG DbgSoftBoot : 1;\n            ULONGLONG DbgMeasuredLaunch : 1;\n            ULONGLONG DbgMeasuredLaunchCapable : 1; // 19H1\n            ULONGLONG DbgSystemHiveReplace : 1;\n            ULONGLONG DbgMeasuredLaunchSmmProtections : 1;\n            ULONGLONG DbgMeasuredLaunchSmmLevel : 7; // 20H1\n            ULONGLONG DbgBugCheckRecovery : 1; // 24H2\n            ULONGLONG DbgFASR : 1;\n            ULONGLONG DbgUseCachedBcd : 1;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n} SYSTEM_BOOT_ENVIRONMENT_INFORMATION, *PSYSTEM_BOOT_ENVIRONMENT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION\n{\n    ULONG FlagsToEnable;\n    ULONG FlagsToDisable;\n} SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION, *PSYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION;\n\n// private\ntypedef enum _COVERAGE_REQUEST_CODES\n{\n    CoverageAllModules = 0,\n    CoverageSearchByHash = 1,\n    CoverageSearchByName = 2\n} COVERAGE_REQUEST_CODES;\n\n// private\ntypedef struct _COVERAGE_MODULE_REQUEST\n{\n    COVERAGE_REQUEST_CODES RequestType;\n    union\n    {\n        UCHAR MD5Hash[16];\n        UNICODE_STRING ModuleName;\n    } SearchInfo;\n} COVERAGE_MODULE_REQUEST, *PCOVERAGE_MODULE_REQUEST;\n\n// private\ntypedef struct _COVERAGE_MODULE_INFO\n{\n    ULONG ModuleInfoSize;\n    ULONG IsBinaryLoaded;\n    UNICODE_STRING ModulePathName;\n    ULONG CoverageSectionSize;\n    UCHAR CoverageSection[1];\n} COVERAGE_MODULE_INFO, *PCOVERAGE_MODULE_INFO;\n\n// private\ntypedef struct _COVERAGE_MODULES\n{\n    ULONG ListAndReset;\n    ULONG NumberOfModules;\n    COVERAGE_MODULE_REQUEST ModuleRequestInfo;\n    COVERAGE_MODULE_INFO Modules[1];\n} COVERAGE_MODULES, *PCOVERAGE_MODULES;\n\n// private\ntypedef struct _SYSTEM_PREFETCH_PATCH_INFORMATION\n{\n    ULONG PrefetchPatchCount;\n} SYSTEM_PREFETCH_PATCH_INFORMATION, *PSYSTEM_PREFETCH_PATCH_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_VERIFIER_FAULTS_INFORMATION\n{\n    ULONG Probability;\n    ULONG MaxProbability;\n    UNICODE_STRING PoolTags;\n    UNICODE_STRING Applications;\n} SYSTEM_VERIFIER_FAULTS_INFORMATION, *PSYSTEM_VERIFIER_FAULTS_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_VERIFIER_INFORMATION_EX\n{\n    ULONG VerifyMode;\n    ULONG OptionChanges;\n    UNICODE_STRING PreviousBucketName;\n    ULONG IrpCancelTimeoutMsec;\n    ULONG VerifierExtensionEnabled;\n#ifdef _WIN64\n    ULONG Reserved[1];\n#else\n    ULONG Reserved[3];\n#endif\n} SYSTEM_VERIFIER_INFORMATION_EX, *PSYSTEM_VERIFIER_INFORMATION_EX;\n\n// private\ntypedef struct _SYSTEM_SYSTEM_PARTITION_INFORMATION\n{\n    UNICODE_STRING SystemPartition;\n} SYSTEM_SYSTEM_PARTITION_INFORMATION, *PSYSTEM_SYSTEM_PARTITION_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SYSTEM_DISK_INFORMATION\n{\n    UNICODE_STRING SystemDisk;\n} SYSTEM_SYSTEM_DISK_INFORMATION, *PSYSTEM_SYSTEM_DISK_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_NUMA_PROXIMITY_MAP\n{\n    ULONG NodeProximityId;\n    USHORT NodeNumber;\n} SYSTEM_NUMA_PROXIMITY_MAP, *PSYSTEM_NUMA_PROXIMITY_MAP;\n\n// private (Windows 8.1 and above)\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT\n{\n    ULONGLONG Hits;\n    UCHAR PercentFrequency;\n} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT;\n\n// private (Windows 8.1 and above)\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION\n{\n    ULONG ProcessorNumber;\n    ULONG StateCount;\n    _Field_size_(StateCount) SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT States[1];\n} SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION, *PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION;\n\n// private (Windows 7 and Windows 8)\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8\n{\n    ULONG Hits;\n    UCHAR PercentFrequency;\n} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8;\n\n// private (Windows 7 and Windows 8)\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION_WIN8\n{\n    ULONG ProcessorNumber;\n    ULONG StateCount;\n    _Field_size_(StateCount) SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 States[1];\n} SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION_WIN8, *PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION_WIN8;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION\n{\n    ULONG ProcessorCount;\n    ULONG Offsets[1];\n} SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION, *PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION;\n\n#define CODEINTEGRITY_OPTION_ENABLED 0x01\n#define CODEINTEGRITY_OPTION_TESTSIGN 0x02\n#define CODEINTEGRITY_OPTION_UMCI_ENABLED 0x04\n#define CODEINTEGRITY_OPTION_UMCI_AUDITMODE_ENABLED 0x08\n#define CODEINTEGRITY_OPTION_UMCI_EXCLUSIONPATHS_ENABLED 0x10\n#define CODEINTEGRITY_OPTION_TEST_BUILD 0x20\n#define CODEINTEGRITY_OPTION_PREPRODUCTION_BUILD 0x40\n#define CODEINTEGRITY_OPTION_DEBUGMODE_ENABLED 0x80\n#define CODEINTEGRITY_OPTION_FLIGHT_BUILD 0x100\n#define CODEINTEGRITY_OPTION_FLIGHTING_ENABLED 0x200\n#define CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED 0x400\n#define CODEINTEGRITY_OPTION_HVCI_KMCI_AUDITMODE_ENABLED 0x800\n#define CODEINTEGRITY_OPTION_HVCI_KMCI_STRICTMODE_ENABLED 0x1000\n#define CODEINTEGRITY_OPTION_HVCI_IUM_ENABLED 0x2000\n#define CODEINTEGRITY_OPTION_WHQL_ENFORCEMENT_ENABLED 0x4000\n#define CODEINTEGRITY_OPTION_WHQL_AUDITMODE_ENABLED 0x8000\n\n// private\ntypedef struct _SYSTEM_CODEINTEGRITY_INFORMATION\n{\n    ULONG Length;\n    union\n    {\n        ULONG CodeIntegrityOptions;\n        struct\n        {\n            ULONG Enabled : 1;                          // CODEINTEGRITY_OPTION_ENABLED\n            ULONG TestSign : 1;                         // CODEINTEGRITY_OPTION_TESTSIGN\n            ULONG UmciEnabled : 1;                      // CODEINTEGRITY_OPTION_UMCI_ENABLED\n            ULONG UmciAuditModeEnabled : 1;             // CODEINTEGRITY_OPTION_UMCI_AUDITMODE_ENABLED\n            ULONG UmciExclusionPathsEnabled : 1;        // CODEINTEGRITY_OPTION_UMCI_EXCLUSIONPATHS_ENABLED\n            ULONG TestBuild : 1;                        // CODEINTEGRITY_OPTION_TEST_BUILD\n            ULONG PreproductionBuild : 1;               // CODEINTEGRITY_OPTION_PREPRODUCTION_BUILD\n            ULONG DebugModeEnabled : 1;                 // CODEINTEGRITY_OPTION_DEBUGMODE_ENABLE\n            ULONG FlightBuild : 1;                      // CODEINTEGRITY_OPTION_FLIGHT_BUILD\n            ULONG FlightingEnabled : 1;                 // CODEINTEGRITY_OPTION_FLIGHTING_ENABLED\n            ULONG HvciKmciEnabled : 1;                  // CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED\n            ULONG HvciKmciAuditModeEnabled : 1;         // CODEINTEGRITY_OPTION_HVCI_KMCI_AUDITMODE_ENABLED\n            ULONG HvciKmciStrictModeEnabled : 1;        // CODEINTEGRITY_OPTION_HVCI_KMCI_STRICTMODE_ENABLED\n            ULONG HvciIumEnabled : 1;                   // CODEINTEGRITY_OPTION_HVCI_IUM_ENABLED\n            ULONG WhqlEnforcementEnabled : 1;           // CODEINTEGRITY_OPTION_WHQL_ENFORCEMENT_ENABLED\n            ULONG WhqlAuditModeEnabled : 1;             // CODEINTEGRITY_OPTION_WHQL_AUDITMODE_ENABLED\n            ULONG Spare : 16;\n        };\n    };\n} SYSTEM_CODEINTEGRITY_INFORMATION, *PSYSTEM_CODEINTEGRITY_INFORMATION;\n\n// rev\n// Loads mcupdate.dll via ntosext.sys to perform microcode updates.\n#define PROCESSOR_MICROCODE_OPERATION_LOAD 0x01\n// rev\n// Unloads mcupdate.dll via ntosext.sys to preform microcode updates.\n#define PROCESSOR_MICROCODE_OPERATION_UNLOAD 0x02\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION\n{\n    ULONG Operation;\n} SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION, *PSYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION;\n\n// private\ntypedef enum _SYSTEM_VA_TYPE\n{\n    SystemVaTypeAll,\n    SystemVaTypeNonPagedPool,\n    SystemVaTypePagedPool,\n    SystemVaTypeSystemCache,\n    SystemVaTypeSystemPtes,\n    SystemVaTypeSessionSpace,\n    SystemVaTypeMax\n} SYSTEM_VA_TYPE, *PSYSTEM_VA_TYPE;\n\n// private\ntypedef struct _SYSTEM_VA_LIST_INFORMATION\n{\n    SIZE_T VirtualSize;\n    SIZE_T VirtualPeak;\n    SIZE_T VirtualLimit;\n    SIZE_T AllocationFailures;\n} SYSTEM_VA_LIST_INFORMATION, *PSYSTEM_VA_LIST_INFORMATION;\n\n// private\n//typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP\n//{\n//    RelationProcessorCore,\n//    RelationNumaNode,\n//    RelationCache,\n//    RelationProcessorPackage,\n//    RelationGroup,\n//    RelationProcessorDie,\n//    RelationNumaNodeEx,\n//    RelationProcessorModule,\n//    RelationAll = 0xffff\n//} LOGICAL_PROCESSOR_RELATIONSHIP;\n//\n// private\n//typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION\n//{\n//    ULONG_PTR ProcessorMask;\n//    LOGICAL_PROCESSOR_RELATIONSHIP Relationship;\n//    union\n//    {\n//        struct\n//        {\n//            UCHAR Flags;\n//        } ProcessorCore;\n//        struct\n//        {\n//            ULONG NodeNumber;\n//        } NumaNode;\n//        CACHE_DESCRIPTOR Cache;\n//        ULONGLONG Reserved[2];\n//    };\n//} SYSTEM_LOGICAL_PROCESSOR_INFORMATION, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION;\n//\n// private\n//typedef struct _PROCESSOR_RELATIONSHIP\n//{\n//    UCHAR Flags;\n//    UCHAR EfficiencyClass;\n//    UCHAR Reserved[20];\n//    USHORT GroupCount;\n//    _Field_size_(GroupCount) GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];\n//} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;\n//\n// private\n//typedef struct _NUMA_NODE_RELATIONSHIP\n//{\n//    ULONG NodeNumber;\n//    UCHAR Reserved[18];\n//    USHORT GroupCount;\n//    union\n//    {\n//        GROUP_AFFINITY GroupMask;\n//        _Field_size_(GroupCount) GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];\n//    };\n//} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;\n//\n// private\n//typedef struct _CACHE_RELATIONSHIP\n//{\n//    UCHAR Level;\n//    UCHAR Associativity;\n//    USHORT LineSize;\n//    ULONG CacheSize;\n//    PROCESSOR_CACHE_TYPE Type;\n//    UCHAR Reserved[18];\n//    USHORT GroupCount;\n//    union\n//    {\n//        GROUP_AFFINITY GroupMask;\n//        _Field_size_(GroupCount) GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];\n//    };\n//} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;\n//\n// private\n//typedef struct _PROCESSOR_GROUP_INFO\n//{\n//    UCHAR MaximumProcessorCount;\n//    UCHAR ActiveProcessorCount;\n//    UCHAR Reserved[38];\n//    KAFFINITY ActiveProcessorMask;\n//} PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO;\n//\n// private\n//typedef struct _GROUP_RELATIONSHIP\n//{\n//    USHORT MaximumGroupCount;\n//    USHORT ActiveGroupCount;\n//    UCHAR Reserved[20];\n//    _Field_size_(ActiveGroupCount) PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY];\n//} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;\n//\n// private\n//typedef _Struct_size_bytes_(Size) struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX\n//{\n//    LOGICAL_PROCESSOR_RELATIONSHIP Relationship;\n//    ULONG Size;\n//    _Field_size_bytes_(Size - (sizeof(LOGICAL_PROCESSOR_RELATIONSHIP) + sizeof(ULONG))) union\n//    {\n//        PROCESSOR_RELATIONSHIP Processor;\n//        NUMA_NODE_RELATIONSHIP NumaNode;\n//        CACHE_RELATIONSHIP Cache;\n//        GROUP_RELATIONSHIP Group;\n//    };\n//} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;\n\n// rev\ntypedef enum _STORE_INFORMATION_CLASS\n{\n    StorePageRequest = 1,                       // q: Not implemented\n    StoreStatsRequest = 2,                      // q: SM_STATS_REQUEST // SmProcessStatsRequest\n    StoreCreateRequest = 3,                     // s: SM_CREATE_REQUEST (requires SeProfileSingleProcessPrivilege)\n    StoreDeleteRequest = 4,                     // s: SM_DELETE_REQUEST (requires SeProfileSingleProcessPrivilege)\n    StoreListRequest = 5,                       // q: SM_STORE_LIST_REQUEST // SM_STORE_LIST_REQUEST_EX // SmProcessListRequest\n\n    StoreEmptyRequest = 7,                      // q: Not implemented\n    CacheListRequest = 8,                       // q: SMC_CACHE_LIST_REQUEST // SmcProcessListRequest\n    CacheCreateRequest = 9,                     // s: SMC_CACHE_CREATE_REQUEST (requires SeProfileSingleProcessPrivilege) // SmcProcessCreateRequest\n    CacheDeleteRequest = 10,                    // s: SMC_CACHE_DELETE_REQUEST (requires SeProfileSingleProcessPrivilege) // SmcProcessDeleteRequest\n    CacheStoreCreateRequest = 11,               // s: SMC_STORE_CREATE_REQUEST (requires SeProfileSingleProcessPrivilege) // SmcProcessStoreCreateRequest\n    CacheStoreDeleteRequest = 12,               // s: SMC_STORE_DELETE_REQUEST (requires SeProfileSingleProcessPrivilege) // SmcProcessStoreDeleteRequest\n    CacheStatsRequest = 13,                     // q: SMC_CACHE_STATS_REQUEST // SmcProcessStatsRequest\n\n    RegistrationRequest = 15,                   // q: SM_REGISTRATION_REQUEST (requires SeProfileSingleProcessPrivilege) // SmProcessRegistrationRequest\n    GlobalCacheStatsRequest = 16,               // q: Not implemented\n    StoreResizeRequest = 17,                    // s: SM_STORE_RESIZE_REQUEST (requires SeProfileSingleProcessPrivilege) // SmProcessResizeRequest\n    CacheStoreResizeRequest = 18,               // s: SM_STORE_CACHE_RESIZE_REQUEST (requires SeProfileSingleProcessPrivilege) // SmcProcessResizeRequest\n    SmConfigRequest = 19,                       // s: SM_CONFIG_REQUEST (requires SeProfileSingleProcessPrivilege)\n    StoreHighMemoryPriorityRequest = 20,        // s: SM_STORE_HIGH_MEMORY_PRIORITY_REQUEST (requires SeProfileSingleProcessPrivilege)\n    SystemStoreTrimRequest = 21,                // s: SM_SYSTEM_STORE_TRIM_REQUEST (requires SeProfileSingleProcessPrivilege) // SmProcessSystemStoreTrimRequest\n    MemCompressionInfoRequest = 22,             // q: SM_STORE_COMPRESSION_INFORMATION_REQUEST // SmProcessCompressionInfoRequest\n    StoreExistsForProcess = 23,                 // q: SM_SYSTEM_STORE_EXISTS_FOR_PROCESS // SmProcessProcessStoreInfoRequest // 25H2\n    CompressionReadStatsRequest = 24,           // q: SM_COMPRESSION_READ_STATS_REQUEST // SmProcessCompressionReadStatsRequest\n    CompressionAcceleratorRequest = 25,         // q: SM_COMPRESSION_ACCELERATOR_REQUEST // SmProcessCompressionAcceleratorRequest\n    StoreInformationMax\n} STORE_INFORMATION_CLASS;\n\n// rev\n#define SYSTEM_STORE_INFORMATION_VERSION 1\n\n// rev\ntypedef struct _SYSTEM_STORE_INFORMATION\n{\n    _In_ ULONG Version;\n    _In_ STORE_INFORMATION_CLASS StoreInformationClass;\n    _Inout_ PVOID Data;\n    _Inout_ ULONG Length;\n} SYSTEM_STORE_INFORMATION, *PSYSTEM_STORE_INFORMATION;\n\n#define SYSTEM_STORE_STATS_INFORMATION_VERSION 2\n\ntypedef enum _ST_STATS_LEVEL\n{\n    StStatsLevelBasic = 0,\n    StStatsLevelIoStats = 1,\n    StStatsLevelRegionSpace = 2, // requires SeProfileSingleProcessPrivilege\n    StStatsLevelSpaceBitmap = 3, // requires SeProfileSingleProcessPrivilege\n    StStatsLevelMax = 4\n} ST_STATS_LEVEL;\n\ntypedef struct _SM_STATS_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_STATS_INFORMATION_VERSION\n    ULONG DetailLevel : 8; // ST_STATS_LEVEL\n    ULONG StoreId : 16;\n    ULONG BufferSize;\n    PVOID Buffer; // PST_STATS\n} SM_STATS_REQUEST, *PSM_STATS_REQUEST;\n\ntypedef struct _ST_DATA_MGR_STATS\n{\n    ULONG RegionCount;\n    ULONG PagesStored;\n    ULONG UniquePagesStored;\n    ULONG LazyCleanupRegionCount;\n    struct {\n        ULONG RegionsInUse;\n        ULONG SpaceUsed;\n    } Space[8];\n} ST_DATA_MGR_STATS, *PST_DATA_MGR_STATS;\n\ntypedef struct _ST_IO_STATS_PERIOD\n{\n    ULONG PageCounts[5];\n} ST_IO_STATS_PERIOD, *PST_IO_STATS_PERIOD;\n\ntypedef struct _ST_IO_STATS\n{\n    ULONG PeriodCount;\n    ST_IO_STATS_PERIOD Periods[64];\n} ST_IO_STATS, *PST_IO_STATS;\n\ntypedef struct _ST_READ_LATENCY_BUCKET\n{\n    ULONG LatencyUs;\n    ULONG Count;\n} ST_READ_LATENCY_BUCKET, *PST_READ_LATENCY_BUCKET;\n\ntypedef struct _ST_READ_LATENCY_STATS\n{\n    ST_READ_LATENCY_BUCKET Buckets[8];\n} ST_READ_LATENCY_STATS, *PST_READ_LATENCY_STATS;\n\n// rev\ntypedef struct _ST_STATS_REGION_INFO\n{\n    USHORT SpaceUsed;\n    UCHAR Priority;\n    UCHAR Spare;\n} ST_STATS_REGION_INFO, *PST_STATS_REGION_INFO;\n\n// rev\ntypedef struct _ST_STATS_SPACE_BITMAP\n{\n    SIZE_T CompressedBytes;\n    ULONG BytesPerBit;\n    UCHAR StoreBitmap[1];\n} ST_STATS_SPACE_BITMAP, *PST_STATS_SPACE_BITMAP;\n\n// rev\ntypedef struct _ST_STATS\n{\n    ULONG Version : 8;\n    ULONG Level : 4;\n    ULONG StoreType : 4;\n    ULONG NoDuplication : 1;\n    ULONG NoCompression : 1;\n    ULONG EncryptionStrength : 12;\n    ULONG VirtualRegions : 1;\n    ULONG Spare0 : 1;\n    ULONG Size;\n    USHORT CompressionFormat;\n    USHORT Spare;\n\n    struct\n    {\n        ULONG RegionSize;\n        ULONG RegionCount;\n        ULONG RegionCountMax;\n        ULONG Granularity;\n        ST_DATA_MGR_STATS UserData;\n        ST_DATA_MGR_STATS Metadata;\n    } Basic;\n\n    struct\n    {\n        ST_IO_STATS IoStats;\n        ST_READ_LATENCY_STATS ReadLatencyStats;\n    } Io;\n\n    // ST_STATS_REGION_INFO[RegionCountMax]\n    // ST_STATS_SPACE_BITMAP\n} ST_STATS, *PST_STATS;\n\n#define SYSTEM_STORE_CREATE_INFORMATION_VERSION 6\n\ntypedef enum _SM_STORE_TYPE\n{\n    StoreTypeInMemory=0,\n    StoreTypeFile=1,\n    StoreTypeMax=2\n} SM_STORE_TYPE;\n\ntypedef struct _SM_STORE_BASIC_PARAMS\n{\n    union\n    {\n        struct\n        {\n            ULONG StoreType : 8; // SM_STORE_TYPE\n            ULONG NoDuplication : 1;\n            ULONG FailNoCompression : 1;\n            ULONG NoCompression : 1 ;\n            ULONG NoEncryption : 1;\n            ULONG NoEvictOnAdd : 1;\n            ULONG PerformsFileIo : 1;\n            ULONG VdlNotSet : 1 ;\n            ULONG UseIntermediateAddBuffer : 1;\n            ULONG CompressNoHuff : 1;\n            ULONG LockActiveRegions : 1;\n            ULONG VirtualRegions : 1;\n            ULONG Spare : 13;\n        } DUMMYSTRUCTNAME;\n        ULONG StoreFlags;\n    } DUMMYUNIONNAME;\n    ULONG Granularity;\n    ULONG RegionSize;\n    ULONG RegionCountMax;\n} SM_STORE_BASIC_PARAMS, *PSM_STORE_BASIC_PARAMS;\n\ntypedef struct _SMKM_REGION_EXTENT\n{\n    ULONG RegionCount;\n    SIZE_T ByteOffset;\n} SMKM_REGION_EXTENT, *PSMKM_REGION_EXTENT;\n\ntypedef struct _SMKM_FILE_INFO\n{\n    HANDLE FileHandle;\n    PFILE_OBJECT FileObject;\n    PFILE_OBJECT VolumeFileObject;\n    PDEVICE_OBJECT VolumeDeviceObject;\n    HANDLE VolumePnpHandle;\n    PIRP UsageNotificationIrp;\n    PSMKM_REGION_EXTENT Extents;\n    ULONG ExtentCount;\n} SMKM_FILE_INFO, *PSMKM_FILE_INFO;\n\ntypedef struct _SM_STORE_CACHE_BACKED_PARAMS\n{\n    ULONG SectorSize;\n    PCHAR EncryptionKey;\n    ULONG EncryptionKeySize;\n    PSMKM_FILE_INFO FileInfo;\n    PVOID EtaContext;\n    PRTL_BITMAP StoreRegionBitmap;\n} SM_STORE_CACHE_BACKED_PARAMS, *PSM_STORE_CACHE_BACKED_PARAMS;\n\ntypedef struct _SM_STORE_PARAMETERS\n{\n    SM_STORE_BASIC_PARAMS Store;\n    ULONG Priority;\n    ULONG Flags;\n    SM_STORE_CACHE_BACKED_PARAMS CacheBacked;\n} SM_STORE_PARAMETERS, *PSM_STORE_PARAMETERS;\n\ntypedef struct _SM_CREATE_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_CREATE_INFORMATION_VERSION\n    ULONG AcquireReference : 1;\n    ULONG KeyedStore : 1;\n    ULONG Spare : 22;\n    SM_STORE_PARAMETERS Params;\n    ULONG StoreId;\n} SM_CREATE_REQUEST, *PSM_CREATE_REQUEST;\n\n#define SYSTEM_STORE_DELETE_INFORMATION_VERSION 1\n\ntypedef struct _SM_DELETE_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_DELETE_INFORMATION_VERSION\n    ULONG Spare : 24;\n    ULONG StoreId;\n} SM_DELETE_REQUEST, *PSM_DELETE_REQUEST;\n\n#define SYSTEM_STORE_LIST_INFORMATION_VERSION 2\n\ntypedef struct _SM_STORE_LIST_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_LIST_INFORMATION_VERSION\n    ULONG StoreCount : 8; // = 0\n    ULONG ExtendedRequest : 1; // SM_STORE_LIST_REQUEST_EX if set\n    ULONG Spare : 15;\n    ULONG StoreId[32];\n} SM_STORE_LIST_REQUEST, *PSM_STORE_LIST_REQUEST;\n\ntypedef struct _SM_STORE_LIST_REQUEST_EX\n{\n    SM_STORE_LIST_REQUEST Request;\n    WCHAR NameBuffer[32][64];\n} SM_STORE_LIST_REQUEST_EX, *PSM_STORE_LIST_REQUEST_EX;\n\n#define SYSTEM_CACHE_LIST_INFORMATION_VERSION 2\n\ntypedef struct _SMC_CACHE_LIST_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_CACHE_LIST_INFORMATION_VERSION\n    ULONG CacheCount : 8; // = 0\n    ULONG Spare : 16;\n    ULONG CacheId[16];\n} SMC_CACHE_LIST_REQUEST, *PSMC_CACHE_LIST_REQUEST;\n\n#define SYSTEM_CACHE_CREATE_INFORMATION_VERSION 3\n\ntypedef struct _SMC_CACHE_PARAMETERS\n{\n    SIZE_T CacheFileSize;\n    ULONG StoreAlignment;\n    ULONG PerformsFileIo : 1;\n    ULONG VdlNotSet : 1;\n    ULONG Spare : 30;\n    ULONG CacheFlags;\n    ULONG Priority;\n} SMC_CACHE_PARAMETERS, *PSMC_CACHE_PARAMETERS;\n\ntypedef struct _SMC_CACHE_CREATE_PARAMETERS\n{\n    SMC_CACHE_PARAMETERS CacheParameters;\n    WCHAR TemplateFilePath[512];\n} SMC_CACHE_CREATE_PARAMETERS, *PSMC_CACHE_CREATE_PARAMETERS;\n\ntypedef struct _SMC_CACHE_CREATE_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_CACHE_CREATE_INFORMATION_VERSION\n    ULONG Spare : 24;\n    ULONG CacheId;\n    SMC_CACHE_CREATE_PARAMETERS CacheCreateParams;\n} SMC_CACHE_CREATE_REQUEST, *PSMC_CACHE_CREATE_REQUEST;\n\n#define SYSTEM_CACHE_DELETE_INFORMATION_VERSION 1\n\ntypedef struct _SMC_CACHE_DELETE_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_CACHE_DELETE_INFORMATION_VERSION\n    ULONG Spare : 24;\n    ULONG CacheId;\n} SMC_CACHE_DELETE_REQUEST, *PSMC_CACHE_DELETE_REQUEST;\n\n#define SYSTEM_CACHE_STORE_CREATE_INFORMATION_VERSION 2\n\ntypedef enum _SM_STORE_MANAGER_TYPE\n{\n    SmStoreManagerTypePhysical = 0,\n    SmStoreManagerTypeVirtual = 1,\n    SmStoreManagerTypeMax = 2\n} SM_STORE_MANAGER_TYPE;\n\ntypedef struct _SMC_STORE_CREATE_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_CACHE_STORE_CREATE_INFORMATION_VERSION\n    ULONG Spare : 24;\n    SM_STORE_BASIC_PARAMS StoreParams;\n    ULONG CacheId;\n    SM_STORE_MANAGER_TYPE StoreManagerType;\n    ULONG StoreId;\n} SMC_STORE_CREATE_REQUEST, *PSMC_STORE_CREATE_REQUEST;\n\n#define SYSTEM_CACHE_STORE_DELETE_INFORMATION_VERSION 1\n\ntypedef struct _SMC_STORE_DELETE_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_CACHE_STORE_DELETE_INFORMATION_VERSION\n    ULONG Spare : 24;\n    ULONG CacheId;\n    SM_STORE_MANAGER_TYPE StoreManagerType;\n    ULONG StoreId;\n} SMC_STORE_DELETE_REQUEST, *PSMC_STORE_DELETE_REQUEST;\n\n#define SYSTEM_CACHE_STATS_INFORMATION_VERSION 3\n\ntypedef struct _SMC_CACHE_STATS\n{\n    SIZE_T TotalFileSize;\n    ULONG StoreCount;\n    ULONG RegionCount;\n    ULONG RegionSizeBytes;\n    ULONG FileCount : 6;\n    ULONG PerformsFileIo : 1;\n    ULONG Spare : 25;\n    ULONG StoreIds[16];\n    ULONG PhysicalStoreBitmap;\n    ULONG Priority;\n    WCHAR TemplateFilePath[512];\n} SMC_CACHE_STATS, *PSMC_CACHE_STATS;\n\ntypedef struct _SMC_CACHE_STATS_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_CACHE_STATS_INFORMATION_VERSION\n    ULONG NoFilePath : 1; // Skip TemplateFilePath when set\n    ULONG Spare : 23;\n    ULONG CacheId; // cache to query for statistics\n    SMC_CACHE_STATS CacheStats;\n} SMC_CACHE_STATS_REQUEST, *PSMC_CACHE_STATS_REQUEST;\n\n#define SYSTEM_STORE_REGISTRATION_INFORMATION_VERSION 2\n\ntypedef struct _SM_REGISTRATION_INFO\n{\n    HANDLE CachesUpdatedEvent;\n} SM_REGISTRATION_INFO, *PSM_REGISTRATION_INFO;\n\ntypedef struct _SM_REGISTRATION_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_REGISTRATION_INFORMATION_VERSION\n    ULONG Spare : 24;\n    SM_REGISTRATION_INFO RegInfo;\n} SM_REGISTRATION_REQUEST, *PSM_REGISTRATION_REQUEST;\n\n#define SYSTEM_STORE_RESIZE_INFORMATION_VERSION 6\n\ntypedef struct _SM_STORE_RESIZE_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_RESIZE_INFORMATION_VERSION\n    ULONG AddRegions : 1;\n    ULONG Spare : 23;\n    ULONG StoreId;\n    ULONG NumberOfRegions;\n    PRTL_BITMAP RegionBitmap;\n} SM_STORE_RESIZE_REQUEST, *PSM_STORE_RESIZE_REQUEST;\n\n#define SYSTEM_CACHE_STORE_RESIZE_INFORMATION_VERSION 1\n\ntypedef struct _SM_STORE_CACHE_RESIZE_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_CACHE_STORE_RESIZE_INFORMATION_VERSION\n    ULONG AddRegions : 1;\n    ULONG Spare : 23;\n    ULONG CacheId;\n    ULONG StoreId;\n    SM_STORE_MANAGER_TYPE StoreManagerType;\n    ULONG RegionCount;\n} SM_STORE_CACHE_RESIZE_REQUEST, *PSM_STORE_CACHE_RESIZE_REQUEST;\n\n#define SYSTEM_STORE_CONFIG_INFORMATION_VERSION 4\n\ntypedef enum _SM_CONFIG_TYPE\n{\n    SmConfigDirtyPageCompression = 0,\n    SmConfigAsyncInswap = 1,\n    SmConfigPrefetchSeekThreshold = 2,\n    SmConfigTypeMax = 3\n} SM_CONFIG_TYPE;\n\n// rev\ntypedef struct _SM_CONFIG_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_CONFIG_INFORMATION_VERSION\n    ULONG Spare : 16;\n    ULONG ConfigType : 8; // SM_CONFIG_TYPE\n    ULONG ConfigValue;\n} SM_CONFIG_REQUEST, *PSM_CONFIG_REQUEST;\n\n// rev\n#define SYSTEM_STORE_PRIORITY_REQUEST_VERSION 1\n// rev\n#define SYSTEM_STORE_PRIORITY_FLAG_REQUIRE_HANDLE 0x00000100u // required\n#define SYSTEM_STORE_PRIORITY_FLAG_SET_PRIORITY 0x00000200u\n\n// rev\ntypedef struct _SM_STORE_MEMORY_PRIORITY_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_PRIORITY_REQUEST_VERSION\n    ULONG Flags : 24;\n    HANDLE ProcessHandle; // in // PROCESS_SET_INFORMATION access required\n} SM_STORE_MEMORY_PRIORITY_REQUEST, *PSM_STORE_MEMORY_PRIORITY_REQUEST;\n\n// rev\ntypedef struct _SM_SYSTEM_STORE_TRIM_REQUEST\n{\n    ULONG Version : 8;  // SYSTEM_STORE_TRIM_INFORMATION_VERSION\n    ULONG Spare : 24;\n    SIZE_T PagesToTrim; // TrimFlags // must be non-zero\n    HANDLE PartitionHandle; // since 24H2\n} SM_SYSTEM_STORE_TRIM_REQUEST, *PSM_SYSTEM_STORE_TRIM_REQUEST;\n\n// rev\n#define SYSTEM_STORE_TRIM_INFORMATION_VERSION_V1 1 // WIN10\n#define SYSTEM_STORE_TRIM_INFORMATION_VERSION_V2 2 // 24H2\n#define SYSTEM_STORE_TRIM_INFORMATION_VERSION SYSTEM_STORE_TRIM_INFORMATION_VERSION_V1\n\n// rev\n#define SYSTEM_STORE_TRIM_INFORMATION_SIZE_V1 RTL_SIZEOF_THROUGH_FIELD(SM_SYSTEM_STORE_TRIM_REQUEST, PagesToTrim) // WIN10\n#define SYSTEM_STORE_TRIM_INFORMATION_SIZE_V2 RTL_SIZEOF_THROUGH_FIELD(SM_SYSTEM_STORE_TRIM_REQUEST, PartitionHandle) // 24H2\n#define SYSTEM_STORE_TRIM_INFORMATION_SIZE SYSTEM_STORE_TRIM_INFORMATION_SIZE_V2\n\n#ifdef _WIN64\nstatic_assert(SYSTEM_STORE_TRIM_INFORMATION_SIZE_V1 == 16, \"SYSTEM_STORE_TRIM_INFORMATION_SIZE_V1 must equal 16\");\nstatic_assert(SYSTEM_STORE_TRIM_INFORMATION_SIZE_V2 == 24, \"SYSTEM_STORE_TRIM_INFORMATION_SIZE_V2 must equal 24\");\n#else\nstatic_assert(SYSTEM_STORE_TRIM_INFORMATION_SIZE_V1 == 8, \"SYSTEM_STORE_TRIM_INFORMATION_SIZE_V1 must equal 8\");\nstatic_assert(SYSTEM_STORE_TRIM_INFORMATION_SIZE_V2 == 12, \"SYSTEM_STORE_TRIM_INFORMATION_SIZE_V2 must equal 12\");\n#endif\n\n// rev\ntypedef struct _SM_STORE_COMPRESSION_INFORMATION_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION\n    ULONG Spare : 24;\n    ULONG CompressionPid;\n    ULONG WorkingSetSize;\n    SIZE_T TotalDataCompressed;\n    SIZE_T TotalCompressedSize;\n    SIZE_T TotalUniqueDataCompressed;\n    HANDLE PartitionHandle; // since 24H2\n} SM_STORE_COMPRESSION_INFORMATION_REQUEST, *PSM_STORE_COMPRESSION_INFORMATION_REQUEST;\n\n// rev\n#define SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION_V1 3 // WIN10\n#define SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION_V2 4 // 24H2\n#define SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION_V2\n\n// rev\n#define SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V1 RTL_SIZEOF_THROUGH_FIELD(SM_STORE_COMPRESSION_INFORMATION_REQUEST, TotalUniqueDataCompressed) // WIN10\n#define SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V2 RTL_SIZEOF_THROUGH_FIELD(SM_STORE_COMPRESSION_INFORMATION_REQUEST, PartitionHandle) // 24H2\n#define SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V2\n\n#ifdef _WIN64\nstatic_assert(SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V1 == 40, \"SM_STORE_COMPRESSION_INFORMATION_REQUEST_V1 must equal 40\");\nstatic_assert(SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V2 == 48, \"SM_STORE_COMPRESSION_INFORMATION_REQUEST_V2 must equal 48\");\n#else\nstatic_assert(SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V1 == 24, \"SM_STORE_COMPRESSION_INFORMATION_REQUEST_V1 must equal 24\");\nstatic_assert(SYSTEM_STORE_COMPRESSION_INFORMATION_SIZE_V2 == 28, \"SM_STORE_COMPRESSION_INFORMATION_REQUEST_V2 must equal 28\");\n#endif\n\n// rev\n#define SYSTEM_STORE_EXISTS_FOR_PROCESS_VERSION 1\n\n// rev\ntypedef struct _SM_SYSTEM_STORE_EXISTS_FOR_PROCESS\n{\n    ULONG Version : 8;\n    ULONG Spare : 24;\n    HANDLE ProcessHandle; // in // PROCESS_QUERY_INFORMATION access required\n    BOOLEAN StoreExists; // out\n} SM_SYSTEM_STORE_EXISTS_FOR_PROCESS, *PSM_SYSTEM_STORE_EXISTS_FOR_PROCESS;\n\n// rev\ntypedef struct _SM_COMPRESSION_READ_STATS\n{\n    ULONGLONG Counters[17];\n    ULONGLONG TailValue;\n} SM_COMPRESSION_READ_STATS, * PSM_COMPRESSION_READ_STATS;\n\n// rev\n#define SYSTEM_STORE_COMPRESSION_READ_STATS_VERSION 1\n\n// rev\ntypedef struct _SM_COMPRESSION_READ_STATS_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_COMPRESSION_READ_STATS_VERSION\n    ULONG Spare : 24;\n    ULONG Flags; // must be zero\n    HANDLE PartitionHandle; // optional\n    SM_COMPRESSION_READ_STATS Stats; // output\n} SM_COMPRESSION_READ_STATS_REQUEST, *PSM_COMPRESSION_READ_STATS_REQUEST;\n\n// rev\n#define SYSTEM_STORE_ACCELERATOR_REQUEST_VERSION 1\n\n// rev\ntypedef struct _SM_COMPRESSION_ACCELERATOR_REQUEST\n{\n    ULONG Version : 8; // SYSTEM_STORE_ACCELERATOR_REQUEST_VERSION\n    ULONG Spare : 24;\n    ULONG Flags; // must be zero\n    HANDLE PartitionHandle; // optional\n    ULONG AcceleratorValue; // output\n} SM_COMPRESSION_ACCELERATOR_REQUEST, *PSM_COMPRESSION_ACCELERATOR_REQUEST;\n\n// private\ntypedef struct _SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS\n{\n    HANDLE KeyHandle;\n    PUNICODE_STRING ValueNamePointer;\n    PULONG RequiredLengthPointer;\n    PUCHAR Buffer;\n    ULONG BufferLength;\n    ULONG Type;\n    PUCHAR AppendBuffer;\n    ULONG AppendBufferLength;\n    BOOLEAN CreateIfDoesntExist;\n    BOOLEAN TruncateExistingValue;\n} SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS, *PSYSTEM_REGISTRY_APPEND_STRING_PARAMETERS;\n\n// msdn\ntypedef struct _SYSTEM_VHD_BOOT_INFORMATION\n{\n    BOOLEAN OsDiskIsVhd;\n    ULONG OsVhdFilePathOffset;\n    WCHAR OsVhdParentVolume[1];\n} SYSTEM_VHD_BOOT_INFORMATION, *PSYSTEM_VHD_BOOT_INFORMATION;\n\n// private\ntypedef struct _PS_CPU_QUOTA_QUERY_ENTRY\n{\n    ULONG SessionId;\n    ULONG Weight;\n} PS_CPU_QUOTA_QUERY_ENTRY, *PPS_CPU_QUOTA_QUERY_ENTRY;\n\n// private\ntypedef struct _PS_CPU_QUOTA_QUERY_INFORMATION\n{\n    ULONG SessionCount;\n    PS_CPU_QUOTA_QUERY_ENTRY SessionInformation[1];\n} PS_CPU_QUOTA_QUERY_INFORMATION, *PPS_CPU_QUOTA_QUERY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_ERROR_PORT_TIMEOUTS\n{\n    ULONG StartTimeout;\n    ULONG CommTimeout;\n} SYSTEM_ERROR_PORT_TIMEOUTS, *PSYSTEM_ERROR_PORT_TIMEOUTS;\n\n// private\ntypedef struct _SYSTEM_LOW_PRIORITY_IO_INFORMATION\n{\n    ULONG LowPriorityReadOperationCount;\n    ULONG LowPriorityWriteOperationCount;\n    ULONG KernelBumpedToNormalOperations;\n    ULONG LowPriorityPagingReadOperations;\n    ULONG KernelPagingReadsBumpedToNormal;\n    ULONG LowPriorityPagingWriteOperations;\n    ULONG KernelPagingWritesBumpedToNormal;\n    ULONG BoostedThreadedIrpCount;\n    ULONG BoostedPagingIrpCount;\n    ULONG BlanketBoostCount;\n} SYSTEM_LOW_PRIORITY_IO_INFORMATION, *PSYSTEM_LOW_PRIORITY_IO_INFORMATION;\n\n// symbols\ntypedef enum _BOOT_ENTROPY_SOURCE_RESULT_CODE\n{\n    BootEntropySourceStructureUninitialized,\n    BootEntropySourceDisabledByPolicy,\n    BootEntropySourceNotPresent,\n    BootEntropySourceError,\n    BootEntropySourceSuccess\n} BOOT_ENTROPY_SOURCE_RESULT_CODE;\n\ntypedef enum _BOOT_ENTROPY_SOURCE_ID\n{\n    BootEntropySourceNone = 0,\n    BootEntropySourceSeedfile = 1,\n    BootEntropySourceExternal = 2,\n    BootEntropySourceTpm = 3,\n    BootEntropySourceRdrand = 4,\n    BootEntropySourceTime = 5,\n    BootEntropySourceAcpiOem0 = 6,\n    BootEntropySourceUefi = 7,\n    BootEntropySourceCng = 8,\n    BootEntropySourceTcbTpm = 9,\n    BootEntropySourceTcbRdrand = 10,\n    BootMaxEntropySources = 10\n} BOOT_ENTROPY_SOURCE_ID, *PBOOT_ENTROPY_SOURCE_ID;\n\n// Contents of KeLoaderBlock->Extension->TpmBootEntropyResult (TPM_BOOT_ENTROPY_LDR_RESULT).\n// EntropyData is truncated to 40 bytes.\n\n// private\ntypedef struct _TPM_BOOT_ENTROPY_NT_RESULT\n{\n    ULONGLONG Policy;\n    BOOT_ENTROPY_SOURCE_RESULT_CODE ResultCode;\n    NTSTATUS ResultStatus;\n    ULONGLONG Time;\n    ULONG EntropyLength;\n    UCHAR EntropyData[40];\n} TPM_BOOT_ENTROPY_NT_RESULT, *PTPM_BOOT_ENTROPY_NT_RESULT;\n\n// private\ntypedef struct _BOOT_ENTROPY_SOURCE_NT_RESULT\n{\n    BOOT_ENTROPY_SOURCE_ID SourceId;\n    ULONG64 Policy;\n    BOOT_ENTROPY_SOURCE_RESULT_CODE ResultCode;\n    NTSTATUS ResultStatus;\n    ULONGLONG Time;\n    ULONG EntropyLength;\n    UCHAR EntropyData[64];\n} BOOT_ENTROPY_SOURCE_NT_RESULT, *PBOOT_ENTROPY_SOURCE_NT_RESULT;\n\n// private\ntypedef struct _BOOT_ENTROPY_NT_RESULT\n{\n    ULONG maxEntropySources;\n    BOOT_ENTROPY_SOURCE_NT_RESULT EntropySourceResult[10];\n    UCHAR SeedBytesForCng[48];\n} BOOT_ENTROPY_NT_RESULT, *PBOOT_ENTROPY_NT_RESULT;\n\n// private\ntypedef struct _SYSTEM_VERIFIER_COUNTERS_INFORMATION\n{\n    SYSTEM_VERIFIER_INFORMATION Legacy;\n    ULONG RaiseIrqls;\n    ULONG AcquireSpinLocks;\n    ULONG SynchronizeExecutions;\n    ULONG AllocationsWithNoTag;\n    ULONG AllocationsFailed;\n    ULONG AllocationsFailedDeliberately;\n    SIZE_T LockedBytes;\n    SIZE_T PeakLockedBytes;\n    SIZE_T MappedLockedBytes;\n    SIZE_T PeakMappedLockedBytes;\n    SIZE_T MappedIoSpaceBytes;\n    SIZE_T PeakMappedIoSpaceBytes;\n    SIZE_T PagesForMdlBytes;\n    SIZE_T PeakPagesForMdlBytes;\n    SIZE_T ContiguousMemoryBytes;\n    SIZE_T PeakContiguousMemoryBytes;\n    ULONG ExecutePoolTypes; // REDSTONE2\n    ULONG ExecutePageProtections;\n    ULONG ExecutePageMappings;\n    ULONG ExecuteWriteSections;\n    ULONG SectionAlignmentFailures;\n    ULONG UnsupportedRelocs;\n    ULONG IATInExecutableSection;\n} SYSTEM_VERIFIER_COUNTERS_INFORMATION, *PSYSTEM_VERIFIER_COUNTERS_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_ACPI_AUDIT_INFORMATION\n{\n    ULONG RsdpCount;\n    ULONG SameRsdt : 1;\n    ULONG SlicPresent : 1;\n    ULONG SlicDifferent : 1;\n} SYSTEM_ACPI_AUDIT_INFORMATION, *PSYSTEM_ACPI_AUDIT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_BASIC_PERFORMANCE_INFORMATION\n{\n    SIZE_T AvailablePages;\n    SIZE_T CommittedPages;\n    SIZE_T CommitLimit;\n    SIZE_T PeakCommitment;\n} SYSTEM_BASIC_PERFORMANCE_INFORMATION, *PSYSTEM_BASIC_PERFORMANCE_INFORMATION;\n\n// begin_msdn\n\ntypedef struct _QUERY_PERFORMANCE_COUNTER_FLAGS\n{\n    union\n    {\n        struct\n        {\n            ULONG KernelTransition : 1;\n            ULONG Reserved : 31;\n        };\n        ULONG ul;\n    };\n} QUERY_PERFORMANCE_COUNTER_FLAGS;\n\ntypedef struct _SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION\n{\n    ULONG Version;\n    QUERY_PERFORMANCE_COUNTER_FLAGS Flags;\n    QUERY_PERFORMANCE_COUNTER_FLAGS ValidFlags;\n} SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION, *PSYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION;\n\n// end_msdn\n\n// private\ntypedef enum _SYSTEM_PIXEL_FORMAT\n{\n    SystemPixelFormatUnknown,\n    SystemPixelFormatR8G8B8,\n    SystemPixelFormatR8G8B8X8,\n    SystemPixelFormatB8G8R8,\n    SystemPixelFormatB8G8R8X8\n} SYSTEM_PIXEL_FORMAT;\n\n// private\ntypedef struct _SYSTEM_BOOT_GRAPHICS_INFORMATION\n{\n    LARGE_INTEGER FrameBuffer;\n    ULONG Width;\n    ULONG Height;\n    ULONG PixelStride;\n    ULONG Flags;\n    SYSTEM_PIXEL_FORMAT Format;\n    ULONG DisplayRotation;\n} SYSTEM_BOOT_GRAPHICS_INFORMATION, *PSYSTEM_BOOT_GRAPHICS_INFORMATION;\n\n// private\ntypedef struct _MEMORY_SCRUB_INFORMATION\n{\n    HANDLE Handle;\n    SIZE_T PagesScrubbed;\n} MEMORY_SCRUB_INFORMATION, *PMEMORY_SCRUB_INFORMATION;\n\n// private\ntypedef union _SYSTEM_BAD_PAGE_INFORMATION\n{\n#ifdef _WIN64\n    ULONG_PTR PhysicalPageNumber : 52;\n#else\n    ULONG PhysicalPageNumber : 20;\n#endif\n    ULONG_PTR Reserved : 10;\n    ULONG_PTR Pending : 1;\n    ULONG_PTR Poisoned : 1;\n} SYSTEM_BAD_PAGE_INFORMATION, *PSYSTEM_BAD_PAGE_INFORMATION;\n\n// private\ntypedef struct _PEBS_DS_SAVE_AREA32\n{\n    ULONG BtsBufferBase;\n    ULONG BtsIndex;\n    ULONG BtsAbsoluteMaximum;\n    ULONG BtsInterruptThreshold;\n    ULONG PebsBufferBase;\n    ULONG PebsIndex;\n    ULONG PebsAbsoluteMaximum;\n    ULONG PebsInterruptThreshold;\n    ULONG PebsGpCounterReset[8];\n    ULONG PebsFixedCounterReset[4];\n} PEBS_DS_SAVE_AREA32, *PPEBS_DS_SAVE_AREA32;\n\n// private\ntypedef struct _PEBS_DS_SAVE_AREA64\n{\n    ULONGLONG BtsBufferBase;\n    ULONGLONG BtsIndex;\n    ULONGLONG BtsAbsoluteMaximum;\n    ULONGLONG BtsInterruptThreshold;\n    ULONGLONG PebsBufferBase;\n    ULONGLONG PebsIndex;\n    ULONGLONG PebsAbsoluteMaximum;\n    ULONGLONG PebsInterruptThreshold;\n    ULONGLONG PebsGpCounterReset[8];\n    ULONGLONG PebsFixedCounterReset[4];\n} PEBS_DS_SAVE_AREA64, *PPEBS_DS_SAVE_AREA64;\n\n// private\ntypedef union _PEBS_DS_SAVE_AREA\n{\n    PEBS_DS_SAVE_AREA32 As32Bit;\n    PEBS_DS_SAVE_AREA64 As64Bit;\n} PEBS_DS_SAVE_AREA, *PPEBS_DS_SAVE_AREA;\n\n// private\ntypedef struct _PROCESSOR_PROFILE_CONTROL_AREA\n{\n    PEBS_DS_SAVE_AREA PebsDsSaveArea;\n} PROCESSOR_PROFILE_CONTROL_AREA, *PPROCESSOR_PROFILE_CONTROL_AREA;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA\n{\n    PROCESSOR_PROFILE_CONTROL_AREA ProcessorProfileControlArea;\n    BOOLEAN Allocate;\n} SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA, *PSYSTEM_PROCESSOR_PROFILE_CONTROL_AREA;\n\n// private\ntypedef struct _MEMORY_COMBINE_INFORMATION\n{\n    HANDLE Handle;\n    SIZE_T PagesCombined;\n} MEMORY_COMBINE_INFORMATION, *PMEMORY_COMBINE_INFORMATION;\n\n// rev\n#define MEMORY_COMBINE_FLAGS_COMMON_PAGES_ONLY 0x4\n\n// private\ntypedef struct _MEMORY_COMBINE_INFORMATION_EX\n{\n    HANDLE Handle;\n    SIZE_T PagesCombined;\n    ULONG Flags;\n} MEMORY_COMBINE_INFORMATION_EX, *PMEMORY_COMBINE_INFORMATION_EX;\n\n// private\ntypedef struct _MEMORY_COMBINE_INFORMATION_EX2\n{\n    HANDLE Handle;\n    SIZE_T PagesCombined;\n    ULONG Flags;\n    HANDLE ProcessHandle;\n} MEMORY_COMBINE_INFORMATION_EX2, *PMEMORY_COMBINE_INFORMATION_EX2;\n\n// private\ntypedef struct _SYSTEM_ENTROPY_TIMING_INFORMATION\n{\n    VOID (NTAPI *EntropyRoutine)(PVOID, ULONG);\n    VOID (NTAPI *InitializationRoutine)(PVOID, ULONG, PVOID);\n    PVOID InitializationContext;\n} SYSTEM_ENTROPY_TIMING_INFORMATION, *PSYSTEM_ENTROPY_TIMING_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_CONSOLE_INFORMATION\n{\n    ULONG DriverLoaded : 1;\n    ULONG Spare : 31;\n} SYSTEM_CONSOLE_INFORMATION, *PSYSTEM_CONSOLE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PLATFORM_BINARY_INFORMATION\n{\n    ULONG64 PhysicalAddress;\n    PVOID HandoffBuffer;\n    PVOID CommandLineBuffer;\n    ULONG HandoffBufferSize;\n    ULONG CommandLineBufferSize;\n} SYSTEM_PLATFORM_BINARY_INFORMATION, *PSYSTEM_PLATFORM_BINARY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_POLICY_INFORMATION\n{\n    PVOID InputData;\n    PVOID OutputData;\n    ULONG InputDataSize;\n    ULONG OutputDataSize;\n    ULONG Version;\n} SYSTEM_POLICY_INFORMATION, *PSYSTEM_POLICY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION\n{\n    ULONG NumberOfLogicalProcessors;\n    ULONG NumberOfCores;\n} SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION, *PSYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_DEVICE_DATA_INFORMATION\n{\n    UNICODE_STRING DeviceId;\n    UNICODE_STRING DataName;\n    ULONG DataType;\n    ULONG DataBufferLength;\n    PVOID DataBuffer;\n} SYSTEM_DEVICE_DATA_INFORMATION, *PSYSTEM_DEVICE_DATA_INFORMATION;\n\n// private\ntypedef struct _PHYSICAL_CHANNEL_RUN\n{\n    ULONG NodeNumber;\n    ULONG ChannelNumber;\n    ULONGLONG BasePage;\n    ULONGLONG PageCount;\n    ULONG Flags;\n} PHYSICAL_CHANNEL_RUN, *PPHYSICAL_CHANNEL_RUN;\n\n// private\ntypedef struct _SYSTEM_MEMORY_TOPOLOGY_INFORMATION\n{\n    ULONGLONG NumberOfRuns;\n    ULONG NumberOfNodes;\n    ULONG NumberOfChannels;\n    PHYSICAL_CHANNEL_RUN Run[1];\n} SYSTEM_MEMORY_TOPOLOGY_INFORMATION, *PSYSTEM_MEMORY_TOPOLOGY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_MEMORY_CHANNEL_INFORMATION\n{\n    ULONG ChannelNumber;\n    ULONG ChannelHeatIndex;\n    ULONGLONG TotalPageCount;\n    ULONGLONG ZeroPageCount;\n    ULONGLONG FreePageCount;\n    ULONGLONG StandbyPageCount;\n} SYSTEM_MEMORY_CHANNEL_INFORMATION, *PSYSTEM_MEMORY_CHANNEL_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_BOOT_LOGO_INFORMATION\n{\n    ULONG Flags;\n    ULONG BitmapOffset;\n} SYSTEM_BOOT_LOGO_INFORMATION, *PSYSTEM_BOOT_LOGO_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX\n{\n    LARGE_INTEGER IdleTime;\n    LARGE_INTEGER KernelTime;\n    LARGE_INTEGER UserTime;\n    LARGE_INTEGER DpcTime;\n    LARGE_INTEGER InterruptTime;\n    ULONG InterruptCount;\n    ULONG Spare0;\n    LARGE_INTEGER AvailableTime;\n    LARGE_INTEGER Spare1;\n    LARGE_INTEGER Spare2;\n} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX;\n\n// private\ntypedef struct _CRITICAL_PROCESS_EXCEPTION_DATA\n{\n    GUID ReportId;\n    UNICODE_STRING ModuleName;\n    ULONG ModuleTimestamp;\n    ULONG ModuleSize;\n    ULONG_PTR Offset;\n} CRITICAL_PROCESS_EXCEPTION_DATA, *PCRITICAL_PROCESS_EXCEPTION_DATA;\n\n// private\ntypedef struct _SYSTEM_SECUREBOOT_POLICY_INFORMATION\n{\n    GUID PolicyPublisher;\n    ULONG PolicyVersion;\n    ULONG PolicyOptions;\n} SYSTEM_SECUREBOOT_POLICY_INFORMATION, *PSYSTEM_SECUREBOOT_POLICY_INFORMATION;\n\n// private\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_PAGEFILE_INFORMATION_EX\n{\n    union // union declaration for convenience (dmex)\n    {\n        SYSTEM_PAGEFILE_INFORMATION Info;\n        struct\n        {\n            ULONG NextEntryOffset;\n            ULONG TotalSize;\n            ULONG TotalInUse;\n            ULONG PeakUsage;\n            UNICODE_STRING PageFileName;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n\n    ULONG MinimumSize;\n    ULONG MaximumSize;\n} SYSTEM_PAGEFILE_INFORMATION_EX, *PSYSTEM_PAGEFILE_INFORMATION_EX;\n\n// private\ntypedef struct _SYSTEM_SECUREBOOT_INFORMATION\n{\n    BOOLEAN SecureBootEnabled;\n    BOOLEAN SecureBootCapable;\n} SYSTEM_SECUREBOOT_INFORMATION, *PSYSTEM_SECUREBOOT_INFORMATION;\n\n// private\ntypedef struct _PROCESS_DISK_COUNTERS\n{\n    ULONGLONG BytesRead;\n    ULONGLONG BytesWritten;\n    ULONGLONG ReadOperationCount;\n    ULONGLONG WriteOperationCount;\n    ULONGLONG FlushOperationCount;\n} PROCESS_DISK_COUNTERS, *PPROCESS_DISK_COUNTERS;\n\n// private\ntypedef union _ENERGY_STATE_DURATION\n{\n    ULONGLONG Value;\n    struct\n    {\n        ULONG LastChangeTime;\n        ULONG Duration : 31;\n        ULONG IsInState : 1;\n    } DUMMYSTRUCTNAME;\n} ENERGY_STATE_DURATION, *PENERGY_STATE_DURATION;\n\ntypedef struct _PROCESS_ENERGY_VALUES\n{\n    ULONGLONG Cycles[4][2];\n    ULONGLONG DiskEnergy;\n    ULONGLONG NetworkTailEnergy;\n    ULONGLONG MBBTailEnergy;\n    ULONGLONG NetworkTxRxBytes;\n    ULONGLONG MBBTxRxBytes;\n    union\n    {\n        ENERGY_STATE_DURATION Durations[3];\n        struct\n        {\n            ENERGY_STATE_DURATION ForegroundDuration;\n            ENERGY_STATE_DURATION DesktopVisibleDuration;\n            ENERGY_STATE_DURATION PSMForegroundDuration;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n    ULONG CompositionRendered;\n    ULONG CompositionDirtyGenerated;\n    ULONG CompositionDirtyPropagated;\n    ULONG Reserved1;\n    ULONGLONG AttributedCycles[4][2];\n    ULONGLONG WorkOnBehalfCycles[4][2];\n} PROCESS_ENERGY_VALUES, *PPROCESS_ENERGY_VALUES;\n\ntypedef union _TIMELINE_BITMAP\n{\n    ULONGLONG Value;\n    struct\n    {\n        ULONG EndTime;\n        ULONG Bitmap;\n    };\n} TIMELINE_BITMAP, *PTIMELINE_BITMAP;\n\ntypedef struct _PROCESS_ENERGY_VALUES_EXTENSION\n{\n    union\n    {\n        TIMELINE_BITMAP Timelines[14]; // 9 for REDSTONE2, 14 for REDSTONE3/4/5\n        struct\n        {\n            TIMELINE_BITMAP CpuTimeline;\n            TIMELINE_BITMAP DiskTimeline;\n            TIMELINE_BITMAP NetworkTimeline;\n            TIMELINE_BITMAP MBBTimeline;\n            TIMELINE_BITMAP ForegroundTimeline;\n            TIMELINE_BITMAP DesktopVisibleTimeline;\n            TIMELINE_BITMAP CompositionRenderedTimeline;\n            TIMELINE_BITMAP CompositionDirtyGeneratedTimeline;\n            TIMELINE_BITMAP CompositionDirtyPropagatedTimeline;\n            TIMELINE_BITMAP InputTimeline; // REDSTONE3\n            TIMELINE_BITMAP AudioInTimeline;\n            TIMELINE_BITMAP AudioOutTimeline;\n            TIMELINE_BITMAP DisplayRequiredTimeline;\n            TIMELINE_BITMAP KeyboardInputTimeline;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n\n    union // REDSTONE3\n    {\n        ENERGY_STATE_DURATION Durations[5];\n        struct\n        {\n            ENERGY_STATE_DURATION InputDuration;\n            ENERGY_STATE_DURATION AudioInDuration;\n            ENERGY_STATE_DURATION AudioOutDuration;\n            ENERGY_STATE_DURATION DisplayRequiredDuration;\n            ENERGY_STATE_DURATION PSMBackgroundDuration;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n\n    ULONG KeyboardInput;\n    ULONG MouseInput;\n} PROCESS_ENERGY_VALUES_EXTENSION, *PPROCESS_ENERGY_VALUES_EXTENSION;\n\ntypedef struct _PROCESS_EXTENDED_ENERGY_VALUES\n{\n    PROCESS_ENERGY_VALUES Base;\n    PROCESS_ENERGY_VALUES_EXTENSION Extension;\n} PROCESS_EXTENDED_ENERGY_VALUES, *PPROCESS_EXTENDED_ENERGY_VALUES;\n\ntypedef struct _PROCESS_EXTENDED_ENERGY_VALUES_V1\n{\n    PROCESS_ENERGY_VALUES Base;\n    PROCESS_ENERGY_VALUES_EXTENSION Extension;\n    ULONG64 NpuWorkUnits;\n} PROCESS_EXTENDED_ENERGY_VALUES_V1, *PPROCESS_EXTENDED_ENERGY_VALUES_V1;\n\n// private\ntypedef enum _SYSTEM_PROCESS_CLASSIFICATION\n{\n    SystemProcessClassificationNormal,\n    SystemProcessClassificationSystem,\n    SystemProcessClassificationSecureSystem,\n    SystemProcessClassificationMemCompression,\n    SystemProcessClassificationRegistry, // REDSTONE4\n    SystemProcessClassificationMaximum\n} SYSTEM_PROCESS_CLASSIFICATION;\n\n// private\ntypedef struct _SYSTEM_PROCESS_INFORMATION_EXTENSION\n{\n    PROCESS_DISK_COUNTERS DiskCounters;\n    ULONGLONG ContextSwitches;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG HasStrongId : 1;\n            ULONG Classification : 4; // SYSTEM_PROCESS_CLASSIFICATION\n            ULONG BackgroundActivityModerated : 1;\n            ULONG Spare : 26;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n    ULONG UserSidOffset;\n    ULONG PackageFullNameOffset; // since THRESHOLD\n    PROCESS_ENERGY_VALUES EnergyValues; // since THRESHOLD\n    ULONG AppIdOffset; // since THRESHOLD\n    SIZE_T SharedCommitCharge; // since THRESHOLD2\n    ULONG JobObjectId; // since REDSTONE\n    ULONG SpareUlong; // since REDSTONE\n    ULONGLONG ProcessSequenceNumber;\n} SYSTEM_PROCESS_INFORMATION_EXTENSION, *PSYSTEM_PROCESS_INFORMATION_EXTENSION;\n\n// private\ntypedef struct _SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION\n{\n    BOOLEAN EfiLauncherEnabled;\n} SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION, *PSYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX\n{\n    BOOLEAN DebuggerAllowed;\n    BOOLEAN DebuggerEnabled;\n    BOOLEAN DebuggerPresent;\n} SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION_EX;\n\n// private\ntypedef struct _SYSTEM_ELAM_CERTIFICATE_INFORMATION\n{\n    HANDLE ElamDriverFile;\n} SYSTEM_ELAM_CERTIFICATE_INFORMATION, *PSYSTEM_ELAM_CERTIFICATE_INFORMATION;\n\n// private\ntypedef struct _OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2\n{\n    ULONG Version;\n    ULONG AbnormalResetOccurred;\n    ULONG OfflineMemoryDumpCapable;\n    PVOID ResetDataAddress;\n    ULONG ResetDataSize;\n} OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2, *POFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2;\n\n// private\ntypedef struct _OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V1\n{\n    ULONG Version;\n    ULONG AbnormalResetOccurred;\n    ULONG OfflineMemoryDumpCapable;\n} OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V1, *POFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V1;\n\n// SYSTEM_PROCESSOR_FEATURES_INFORMATION // ProcessorFeatureBits\n#define KF64_SMEP              0x0000000000000001ULL // Supervisor Mode Execution Protection\n#define KF64_RDTSC             0x0000000000000002ULL // Read Time-Stamp Counter\n#define KF64_CR4               0x0000000000000004ULL // CR4 Register Features\n#define KF64_CMOV              0x0000000000000008ULL // Conditional Move Instructions\n#define KF64_GLOBAL_PAGE       0x0000000000000010ULL // Global Pages Support\n#define KF64_LARGE_PAGE        0x0000000000000020ULL // Large Page Support\n#define KF64_MTRR              0x0000000000000040ULL // Memory Type Range Registers\n#define KF64_CMPXCHG8B         0x0000000000000080ULL // CMPXCHG8B Instruction\n#define KF64_MMX               0x0000000000000100ULL // MMX Instructions\n#define KF64_DTS               0x0000000000000200ULL // Debug Store\n#define KF64_PAT               0x0000000000000400ULL // Page Attribute Table\n#define KF64_FXSR              0x0000000000000800ULL // FXSAVE and FXRSTOR Instructions\n#define KF64_FAST_SYSCALL      0x0000000000001000ULL // Fast System Call\n#define KF64_XMMI              0x0000000000002000ULL // Streaming SIMD Extensions\n#define KF64_3DNOW             0x0000000000004000ULL // 3DNow! Instructions\n#define KF64_AMDK6MTRR         0x0000000000008000ULL // AMD K6 Memory Type Range Registers\n#define KF64_XMMI64            0x0000000000010000ULL // Streaming SIMD Extensions 2\n#define KF64_BRANCH            0x0000000000020000ULL // Branch Prediction\n#define KF64_XSTATE            0x0000000000800000ULL // Extended States\n#define KF64_RDRAND            0x0000000100000000ULL // RDRAND Instruction\n#define KF64_SMAP              0x0000000200000000ULL // Supervisor Mode Access Prevention\n#define KF64_RDTSCP            0x0000000400000000ULL // RDTSCP Instruction\n#define KF64_HUGEPAGE          0x0000002000000000ULL // Huge Page Support\n#define KF64_XSAVES            0x0000004000000000ULL // XSAVES and XRSTORS Instructions\n#define KF64_FPU_LEAKAGE       0x0000020000000000ULL // FPU Data Leakage Mitigations\n#define KF64_CAT               0x0000100000000000ULL // Cache Allocation Technology\n#define KF64_CET_SS            0x0000400000000000ULL // Control-flow Enforcement Technology - Shadow Stack\n#define KF64_SSSE3             0x0000800000000000ULL // Supplemental Streaming SIMD Extensions 3\n#define KF64_SSE4_1            0x0001000000000000ULL // Streaming SIMD Extensions 4.1\n#define KF64_SSE4_2            0x0002000000000000ULL // Streaming SIMD Extensions 4.2\n#define KF64_XFD               0x0080000000000000ULL // eXtended FPU Data\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_FEATURES_INFORMATION\n{\n    ULONGLONG ProcessorFeatureBits;\n    ULONGLONG Reserved[3];\n} SYSTEM_PROCESSOR_FEATURES_INFORMATION, *PSYSTEM_PROCESSOR_FEATURES_INFORMATION;\n\n// EDID v1.4 detailed timing descriptor (18 bytes)\ntypedef struct _SYSTEM_EDID_DETAILED_TIMING_DESCRIPTOR\n{\n    USHORT PixelClock;           // Pixel clock in 10 kHz units\n    UCHAR HorizontalActiveLo;    // Horizontal active pixels (low 8 bits)\n    UCHAR HorizontalBlankLo;     // Horizontal blanking pixels (low 8 bits)\n    UCHAR HorizontalActiveBlankHi; // High bits for horizontal active/blanking\n    UCHAR VerticalActiveLo;      // Vertical active lines (low 8 bits)\n    UCHAR VerticalBlankLo;       // Vertical blanking lines (low 8 bits)\n    UCHAR VerticalActiveBlankHi; // High bits for vertical active/blanking\n    UCHAR HorizontalSyncOffsetLo;// Horizontal sync offset (low 8 bits)\n    UCHAR HorizontalSyncPulseWidthLo; // Horizontal sync pulse width (low 8 bits)\n    UCHAR VerticalSyncOffsetPulseWidthLo; // Vertical sync offset/pulse width (low 4 bits each)\n    UCHAR SyncOffsetPulseWidthHi; // High bits for sync offset/pulse width\n    UCHAR HorizontalImageSizeLo; // Horizontal image size in mm (low 8 bits)\n    UCHAR VerticalImageSizeLo;   // Vertical image size in mm (low 8 bits)\n    UCHAR ImageSizeHi;           // High bits for image size\n    UCHAR HorizontalBorder;      // Horizontal border in pixels\n    UCHAR VerticalBorder;        // Vertical border in lines\n    UCHAR Flags;                 // Flags (interlaced, stereo, sync, etc.)\n} SYSTEM_EDID_DETAILED_TIMING_DESCRIPTOR, *PSYSTEM_EDID_DETAILED_TIMING_DESCRIPTOR;\n\n// EDID v1.4 standard data format\ntypedef struct _SYSTEM_EDID_INFORMATION\n{\n    union\n    {\n        UCHAR Edid[128];\n        struct\n        {\n            UCHAR Header[8];                 // 00h: EDID header (00 FF FF FF FF FF FF 00)\n            UCHAR ManufacturerId[2];         // 08h: Manufacturer ID (big endian)\n            UCHAR ProductCode[2];            // 0Ah: Product code (little endian)\n            UCHAR SerialNumber[4];           // 0Ch: Serial number\n            UCHAR WeekOfManufacture;         // 10h: Week of manufacture\n            UCHAR YearOfManufacture;         // 11h: Year of manufacture (offset from 1990)\n            UCHAR EdidVersion;               // 12h: EDID version (should be 1)\n            UCHAR EdidRevision;              // 13h: EDID revision (should be 4)\n            UCHAR VideoInputDefinition;      // 14h: Video input parameters\n            UCHAR MaxHorizontalImageSize;    // 15h: Max horizontal image size (cm)\n            UCHAR MaxVerticalImageSize;      // 16h: Max vertical image size (cm)\n            UCHAR DisplayGamma;              // 17h: Display gamma (gamma*100 - 100)\n            UCHAR FeatureSupport;            // 18h: DPMS features, color encoding, etc.\n            UCHAR Chromaticity[10];          // 19h: Chromaticity coordinates\n            UCHAR EstablishedTimings[3];     // 23h: Established timings\n            UCHAR StandardTimings[16];       // 26h: Standard timings (8x2 bytes)\n            SYSTEM_EDID_DETAILED_TIMING_DESCRIPTOR DetailedTiming[4]; // 36h: 4 detailed timing descriptors (18 bytes each)\n            UCHAR ExtensionFlag;             // 7Eh: Number of (optional) 128-byte extension blocks\n            UCHAR Checksum;                  // 7Fh: Checksum (sum of all 128 bytes = 0)\n        };\n    };\n} SYSTEM_EDID_INFORMATION, *PSYSTEM_EDID_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_MANUFACTURING_INFORMATION\n{\n    ULONG Options;\n    UNICODE_STRING ProfileName;\n} SYSTEM_MANUFACTURING_INFORMATION, *PSYSTEM_MANUFACTURING_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION\n{\n    BOOLEAN Enabled;\n} SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION, *PSYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION;\n\n// private\ntypedef struct _HV_DETAILS\n{\n    ULONG Data[4];\n} HV_DETAILS, *PHV_DETAILS;\n\n// private\ntypedef struct _SYSTEM_HYPERVISOR_DETAIL_INFORMATION\n{\n    HV_DETAILS HvVendorAndMaxFunction;\n    HV_DETAILS HypervisorInterface;\n    HV_DETAILS HypervisorVersion;\n    HV_DETAILS HvFeatures;\n    HV_DETAILS HwFeatures;\n    HV_DETAILS EnlightenmentInfo;\n    HV_DETAILS ImplementationLimits;\n} SYSTEM_HYPERVISOR_DETAIL_INFORMATION, *PSYSTEM_HYPERVISOR_DETAIL_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION\n{\n    //\n    // First index is bucket (see: PoGetFrequencyBucket) selected based on latest frequency percent\n    // using _KPRCB.PowerState.FrequencyBucketThresholds.\n    //\n    // Second index is _KPRCB.PowerState.ArchitecturalEfficiencyClass, accounting for architecture\n    // dependent KeHeteroSystem and using _KPRCB.PowerState.EarlyBootArchitecturalEfficiencyClass\n    // instead, when appropriate.\n    //\n    ULONGLONG Cycles[4][2];\n} SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION, *PSYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_TPM_INFORMATION\n{\n    ULONG Flags;\n} SYSTEM_TPM_INFORMATION, *PSYSTEM_TPM_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_VSM_PROTECTION_INFORMATION\n{\n    BOOLEAN DmaProtectionsAvailable;\n    BOOLEAN DmaProtectionsInUse;\n    BOOLEAN HardwareMbecAvailable; // REDSTONE4 (CVE-2018-3639)\n    BOOLEAN ApicVirtualizationAvailable; // 20H1\n} SYSTEM_VSM_PROTECTION_INFORMATION, *PSYSTEM_VSM_PROTECTION_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_KERNEL_DEBUGGER_FLAGS\n{\n    BOOLEAN KernelDebuggerIgnoreUmExceptions;\n} SYSTEM_KERNEL_DEBUGGER_FLAGS, *PSYSTEM_KERNEL_DEBUGGER_FLAGS;\n\n// SYSTEM_CODEINTEGRITYPOLICY_INFORMATION Options\n#define CODEINTEGRITYPOLICY_OPTION_ENABLED 0x01\n#define CODEINTEGRITYPOLICY_OPTION_AUDIT 0x02\n#define CODEINTEGRITYPOLICY_OPTION_REQUIRE_WHQL 0x04\n#define CODEINTEGRITYPOLICY_OPTION_DISABLED_FLIGHTSIGNING 0x08\n#define CODEINTEGRITYPOLICY_OPTION_ENABLED_UMCI 0x10\n#define CODEINTEGRITYPOLICY_OPTION_ENABLED_UPDATE_POLICY_NOREBOOT 0x20\n#define CODEINTEGRITYPOLICY_OPTION_ENABLED_SECURE_SETTING_POLICY 0x40\n#define CODEINTEGRITYPOLICY_OPTION_ENABLED_UNSIGNED_SYSTEMINTEGRITY_POLICY 0x80\n#define CODEINTEGRITYPOLICY_OPTION_DYNAMIC_CODE_POLICY_ENABLED 0x100\n#define CODEINTEGRITYPOLICY_OPTION_RELOAD_POLICY_NO_REBOOT 0x10000000 // NtSetSystemInformation reloads SiPolicy.p7b\n#define CODEINTEGRITYPOLICY_OPTION_CONDITIONAL_LOCKDOWN 0x20000000\n#define CODEINTEGRITYPOLICY_OPTION_NOLOCKDOWN 0x40000000\n#define CODEINTEGRITYPOLICY_OPTION_LOCKDOWN 0x80000000\n\n// SYSTEM_CODEINTEGRITYPOLICY_INFORMATION HVCIOptions\n#define CODEINTEGRITYPOLICY_HVCIOPTION_ENABLED 0x01\n#define CODEINTEGRITYPOLICY_HVCIOPTION_STRICT 0x02\n#define CODEINTEGRITYPOLICY_HVCIOPTION_DEBUG 0x04\n\n// private\ntypedef struct _SYSTEM_CODEINTEGRITYPOLICY_INFORMATION\n{\n    union\n    {\n        ULONG Options;\n        struct\n        {\n            ULONG Enabled : 1;\n            ULONG Audit : 1;\n            ULONG RequireWHQL : 1;\n            ULONG DisabledFlightSigning : 1;\n            ULONG EnabledUMCI : 1;\n            ULONG EnabledUpdatePolicyNoReboot : 1;\n            ULONG EnabledSecureSettingPolicy : 1;\n            ULONG EnabledUnsignedSystemIntegrityPolicy : 1;\n            ULONG DynamicCodePolicyEnabled : 1;\n            ULONG Spare : 19;\n            ULONG ReloadPolicyNoReboot : 1;\n            ULONG ConditionalLockdown : 1;\n            ULONG NoLockdown : 1;\n            ULONG Lockdown : 1;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n    union\n    {\n        ULONG HVCIOptions;\n        struct\n        {\n            ULONG HVCIEnabled : 1;\n            ULONG HVCIStrict : 1;\n            ULONG HVCIDebug : 1;\n            ULONG HVCISpare : 29;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n    ULONGLONG Version;\n    GUID PolicyGuid;\n} SYSTEM_CODEINTEGRITYPOLICY_INFORMATION, *PSYSTEM_CODEINTEGRITYPOLICY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_ISOLATED_USER_MODE_INFORMATION\n{\n    BOOLEAN SecureKernelRunning : 1;\n    BOOLEAN HvciEnabled : 1;\n    BOOLEAN HvciStrictMode : 1;\n    BOOLEAN DebugEnabled : 1;\n    BOOLEAN FirmwarePageProtection : 1;\n    BOOLEAN EncryptionKeyAvailable : 1;\n    BOOLEAN SpareFlags : 2;\n    BOOLEAN TrustletRunning : 1;\n    BOOLEAN HvciDisableAllowed : 1;\n    BOOLEAN HardwareEnforcedVbs : 1;\n    BOOLEAN NoSecrets : 1;\n    BOOLEAN EncryptionKeyPersistent : 1;\n    BOOLEAN HardwareEnforcedHvpt : 1;\n    BOOLEAN HardwareHvptAvailable : 1;\n    BOOLEAN SpareFlags2 : 1;\n    BOOLEAN EncryptionKeyTpmBound : 1;\n    BOOLEAN Spare0[5];\n    ULONGLONG Spare1;\n} SYSTEM_ISOLATED_USER_MODE_INFORMATION, *PSYSTEM_ISOLATED_USER_MODE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SINGLE_MODULE_INFORMATION\n{\n    PVOID TargetModuleAddress;\n    RTL_PROCESS_MODULE_INFORMATION_EX ExInfo;\n} SYSTEM_SINGLE_MODULE_INFORMATION, *PSYSTEM_SINGLE_MODULE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_INTERRUPT_CPU_SET_INFORMATION\n{\n    ULONG Gsiv;\n    USHORT Group;\n    ULONGLONG CpuSets;\n} SYSTEM_INTERRUPT_CPU_SET_INFORMATION, *PSYSTEM_INTERRUPT_CPU_SET_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION\n{\n    SYSTEM_SECUREBOOT_POLICY_INFORMATION PolicyInformation;\n    ULONG PolicySize;\n    UCHAR Policy[1];\n} SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION, *PSYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION;\n\n// private\ntypedef struct _KAFFINITY_EX\n{\n    USHORT Count;\n    USHORT Size;\n    ULONG Reserved;\n    union\n    {\n        ULONG_PTR Bitmap[1];\n        ULONG_PTR StaticBitmap[32];\n    } DUMMYUNIONNAME;\n} KAFFINITY_EX, *PKAFFINITY_EX;\n\n// private\ntypedef struct _SYSTEM_ROOT_SILO_INFORMATION\n{\n    ULONG NumberOfSilos;\n    ULONG SiloIdList[1];\n} SYSTEM_ROOT_SILO_INFORMATION, *PSYSTEM_ROOT_SILO_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_CPU_SET_TAG_INFORMATION\n{\n    ULONGLONG Tag;\n    ULONGLONG CpuSets[1];\n} SYSTEM_CPU_SET_TAG_INFORMATION, *PSYSTEM_CPU_SET_TAG_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION\n{\n    ULONG ExtentCount;\n    ULONG ValidStructureSize;\n    ULONG NextExtentIndex;\n    ULONG ExtentRestart;\n    ULONG CycleCount;\n    ULONG TimeoutCount;\n    ULONGLONG CycleTime;\n    ULONGLONG CycleTimeMax;\n    ULONGLONG ExtentTime;\n    ULONG ExtentTimeIndex;\n    ULONG ExtentTimeMaxIndex;\n    ULONGLONG ExtentTimeMax;\n    ULONGLONG HyperFlushTimeMax;\n    ULONGLONG TranslateVaTimeMax;\n    ULONGLONG DebugExemptionCount;\n    ULONGLONG TbHitCount;\n    ULONGLONG TbMissCount;\n    ULONGLONG VinaPendingYield;\n    ULONGLONG HashCycles;\n    ULONG HistogramOffset;\n    ULONG HistogramBuckets;\n    ULONG HistogramShift;\n    ULONG Reserved1;\n    ULONGLONG PageNotPresentCount;\n} SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION, *PSYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION\n{\n    ULONG PlatformManifestSize;\n    UCHAR PlatformManifest[1];\n} SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION, *PSYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT\n{\n    ULONG Gsiv;\n    UCHAR ControllerInterrupt;\n    UCHAR EdgeInterrupt;\n    UCHAR IsPrimaryInterrupt;\n    GROUP_AFFINITY TargetAffinity;\n} SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT, *PSYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT;\n\n// private\ntypedef union _SYSTEM_INTERRUPT_STEERING_INFORMATION_OUTPUT\n{\n    ULONG AsULONG;\n    struct\n    {\n        ULONG Enabled : 1;\n        ULONG Reserved : 31;\n    };\n} SYSTEM_INTERRUPT_STEERING_INFORMATION_OUTPUT, *PSYSTEM_INTERRUPT_STEERING_INFORMATION_OUTPUT;\n\n#if !defined(NTDDI_WIN10_FE) || (NTDDI_VERSION < NTDDI_WIN10_FE)\n// private\ntypedef struct _SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION\n{\n    ULONG Machine : 16;\n    ULONG KernelMode : 1;\n    ULONG UserMode : 1;\n    ULONG Native : 1;\n    ULONG Process : 1;\n    ULONG WoW64Container : 1;\n    ULONG ReservedZero0 : 11;\n} SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION, *PSYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION;\n#endif // NTDDI_WIN10_FE\n\n// private\n/**\n * The SYSTEM_MEMORY_USAGE_INFORMATION structure contains information about the memory usage of the system.\n */\ntypedef struct _SYSTEM_MEMORY_USAGE_INFORMATION\n{\n    ULONGLONG TotalPhysicalBytes;\n    ULONGLONG AvailableBytes;\n    LONGLONG ResidentAvailableBytes;\n    ULONGLONG CommittedBytes;\n    ULONGLONG SharedCommittedBytes;\n    ULONGLONG CommitLimitBytes;\n    ULONGLONG PeakCommitmentBytes;\n} SYSTEM_MEMORY_USAGE_INFORMATION, *PSYSTEM_MEMORY_USAGE_INFORMATION;\n\n// rev\n/**\n * The SYSTEM_CODEINTEGRITY_IMAGE_TYPE constant is used for validating user-mode images (EXE/DLL).\n */\ntypedef enum _SYSTEM_CODEINTEGRITY_IMAGE_TYPE\n{\n    SystemCodeIntegrityImageTypeUser,\n    SystemCodeIntegrityImageTypeKernel,\n    SystemCodeIntegrityImageTypeBoot\n} SYSTEM_CODEINTEGRITY_IMAGE_TYPE;\n\n/**\n * The SYSTEM_CODEINTEGRITY_IMAGE_TYPE_USER constant is used for validating user-mode images (EXE/DLL).\n *\n * Validation includes:\n * - Digital signature\n * - User-mode certificate chain validity.\n * - Compliance policies for user-mode binaries.\n */\n#define SYSTEM_CODEINTEGRITY_IMAGE_TYPE_USER     0\n\n/**\n * The SYSTEM_CODEINTEGRITY_IMAGE_TYPE_KERNEL constant is used for validating kernel-mode images (SYS/Native).\n *\n * Validation includes:\n * - Signed by a trusted certificate authority (or cross-signed).\n * - Compliance policies for kernel-mode binaries.\n */\n#define SYSTEM_CODEINTEGRITY_IMAGE_TYPE_KERNEL   1\n\n/**\n * The SYSTEM_CODEINTEGRITY_IMAGE_TYPE_BOOT constant is used for validating boot-critical images (SYS/Native).\n *\n * Validation includes:\n * - Signed only by Microsoft.\n * - Compliance policies for boot-critical binaries (Strict WHQL, Secure Boot requirements).\n */\n#define SYSTEM_CODEINTEGRITY_IMAGE_TYPE_BOOT\n\n/**\n * The SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION structure contains information to validate the integrity of an image.\n *\n * \\note The return status of NtQuerySystemInformation indicates the result of the code integrity validation as determined by the type specified.\n */\ntypedef struct _SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION\n{\n    HANDLE ImageFile;   // in: Handle to a file or image to validate.\n    ULONG Type;         // in: The type of code integrity policy. // REDSTONE4\n} SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION, *PSYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION;\n\n/**\n * The SYSTEM_PHYSICAL_MEMORY_INFORMATION structure retrieves the physical memory layout of the system.\n *\n * \\remarks The addresses are physical, not virtual.\n */\ntypedef struct _SYSTEM_PHYSICAL_MEMORY_INFORMATION\n{\n    ULONGLONG TotalPhysicalBytes;           // Total amount of physical RAM present, in bytes.\n    ULONGLONG LowestPhysicalAddress;        // Lowest accessible physical address (byte address).\n    ULONGLONG HighestPhysicalAddress;       // Highest accessible physical address (byte address, inclusive).\n} SYSTEM_PHYSICAL_MEMORY_INFORMATION, *PSYSTEM_PHYSICAL_MEMORY_INFORMATION;\n\n/**\n * The SYSTEM_ACTIVITY_MODERATION_STATE type contains the moderation state applied to an application,\n * with respect to background throttling, resource reduction, and related heuristics.\n *\n * \\remarks The state may be assigned automatically by the system or explicitly overridden by the user.\n */\ntypedef enum _SYSTEM_ACTIVITY_MODERATION_STATE\n{\n    SystemActivityModerationStateSystemManaged, // The system applies heuristics based on the appropriate moderation behavior.\n    SystemActivityModerationStateUserManagedAllowThrottling, // User allows the system to throttle the application.\n    SystemActivityModerationStateUserManagedDisableThrottling, // User disables throttling for the application.\n    MaxSystemActivityModerationState // Upper bound for validation; not a real state.\n} SYSTEM_ACTIVITY_MODERATION_STATE;\n\n// private - REDSTONE2\ntypedef struct _SYSTEM_ACTIVITY_MODERATION_EXE_STATE // REDSTONE3: Renamed SYSTEM_ACTIVITY_MODERATION_INFO\n{\n    UNICODE_STRING ExePathNt;\n    SYSTEM_ACTIVITY_MODERATION_STATE ModerationState;\n} SYSTEM_ACTIVITY_MODERATION_EXE_STATE, *PSYSTEM_ACTIVITY_MODERATION_EXE_STATE;\n\ntypedef enum _SYSTEM_ACTIVITY_MODERATION_APP_TYPE\n{\n    SystemActivityModerationAppTypeClassic,\n    SystemActivityModerationAppTypePackaged,\n    MaxSystemActivityModerationAppType\n} SYSTEM_ACTIVITY_MODERATION_APP_TYPE;\n\n// private - REDSTONE3\ntypedef struct _SYSTEM_ACTIVITY_MODERATION_INFO\n{\n    UNICODE_STRING Identifier;\n    SYSTEM_ACTIVITY_MODERATION_STATE ModerationState;\n    SYSTEM_ACTIVITY_MODERATION_APP_TYPE AppType;\n} SYSTEM_ACTIVITY_MODERATION_INFO, *PSYSTEM_ACTIVITY_MODERATION_INFO;\n\n// rev\n/**\n * The SYSTEM_ACTIVITY_MODERATION_APP_SETTINGS structure describes the moderation state\n * and classification of an application as used by the system's activity moderation framework.\n * These settings influence how aggressively the system may throttle, defer, or\n * suppress certain background activities for the application.\n *\n * The structure maintains a stable binary layout because it is stored in\n * serialized policy blobs and consumed by system components that expect\n * fixed field offsets.\n */\ntypedef struct _SYSTEM_ACTIVITY_MODERATION_APP_SETTINGS\n{\n    LARGE_INTEGER LastUpdatedTime; // Timestamp of the last update to this settings block.\n    SYSTEM_ACTIVITY_MODERATION_STATE ModerationState; // Current moderation state assigned to the application.\n    UCHAR Reserved[4]; // Reserved for future expansion\n    SYSTEM_ACTIVITY_MODERATION_APP_TYPE AppType; // Current application type for moderation purposes.\n    ULONG Flags; // Additional moderation flags.\n} SYSTEM_ACTIVITY_MODERATION_APP_SETTINGS, *PSYSTEM_ACTIVITY_MODERATION_APP_SETTINGS;\n\n/**\n * The SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS structure provides the activity-moderation\n * registry location where moderation policies or overrides may be stored.\n */\ntypedef struct _SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS\n{\n    HANDLE UserKeyHandle; // Handle to the user registry key for activity moderation settings.\n} SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS, *PSYSTEM_ACTIVITY_MODERATION_USER_SETTINGS;\n\n// private\ntypedef struct _SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Locked : 1;\n            ULONG UnlockApplied : 1; // Unlockable field removed 19H1\n            ULONG UnlockIdValid : 1;\n            ULONG Reserved : 29;\n        };\n    };\n    UCHAR UnlockId[32]; // REDSTONE4\n} SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION, *PSYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_FLUSH_INFORMATION\n{\n    ULONG SupportedFlushMethods;\n    ULONG ProcessorCacheFlushSize;\n    ULONGLONG SystemFlushCapabilities;\n    ULONGLONG Reserved[2];\n} SYSTEM_FLUSH_INFORMATION, *PSYSTEM_FLUSH_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_WRITE_CONSTRAINT_INFORMATION\n{\n    ULONG WriteConstraintPolicy;\n    ULONG Reserved;\n} SYSTEM_WRITE_CONSTRAINT_INFORMATION, *PSYSTEM_WRITE_CONSTRAINT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION\n{\n    union\n    {\n        ULONG KvaShadowFlags;\n        struct\n        {\n            ULONG KvaShadowEnabled : 1;\n            ULONG KvaShadowUserGlobal : 1;\n            ULONG KvaShadowPcid : 1;\n            ULONG KvaShadowInvpcid : 1;\n            ULONG KvaShadowRequired : 1; // REDSTONE4\n            ULONG KvaShadowRequiredAvailable : 1;\n            ULONG InvalidPteBit : 6;\n            ULONG L1DataCacheFlushSupported : 1;\n            ULONG L1TerminalFaultMitigationPresent : 1;\n            ULONG Reserved : 18;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n} SYSTEM_KERNEL_VA_SHADOW_INFORMATION, *PSYSTEM_KERNEL_VA_SHADOW_INFORMATION;\n\n// private\n/**\n * The SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION structure contains information\n * required for code integrity verification of an image.\n */\ntypedef struct _SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION\n{\n    HANDLE FileHandle;\n    ULONG ImageSize;\n    PVOID Image;\n} SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION, *PSYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION;\n\n// rev\n/**\n * The SYSTEM_HYPERVISOR_USER_SHARED_DATA structure contains information shared with the hypervisor and user-mode.\n *\n * This structure is populated by the hypervisor (when present) to allow user-mode components to perform\n * high-resolution time calculations without requiring a hypercall or kernel transition.\n */\ntypedef struct _SYSTEM_HYPERVISOR_USER_SHARED_DATA\n{\n    /**\n     * Lock used to synchronize updates to the timing fields.\n     *\n     * The hypervisor increments this value before and after updating the\n     * QPC multiplier and bias. User-mode callers can sample this value\n     * before and after reading the timing fields to detect whether an\n     * update occurred mid-read and retry if necessary.\n     */\n    volatile ULONG TimeUpdateLock;\n\n    /**\n     * Reserved field - The hypervisor does not assign this field.\n     */\n    ULONG Reserved0;\n\n    /**\n     * Multiplier used to convert hypervisor QPC ticks to host time.\n     *\n     * This value is applied to the hypervisor's virtualized performance\n     * counter to compute a stable, high-resolution timebase. The multiplier\n     * is chosen by the hypervisor based on the underlying hardware timer\n     * source and virtualization mode.\n     */\n    ULONGLONG QpcMultiplier;\n\n    /**\n     * Bias applied after QPC multiplication to produce final time.\n     *\n     * The hypervisor uses this bias to align the virtualized QPC value with\n     * the host's notion of system time. Combined with QpcMultiplier, this\n     * allows user-mode components to compute consistent time values even\n     * under virtualization.\n     */\n    ULONGLONG QpcBias;\n} SYSTEM_HYPERVISOR_USER_SHARED_DATA, *PSYSTEM_HYPERVISOR_USER_SHARED_DATA;\n\n/**\n * The SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION structure describes\n * the user-mode mapping of the hypervisor shared page.\n *\n * This structure provides the virtual address at which the hypervisor's\n * user-accessible shared data page is mapped. When a hypervisor is present,\n * the kernel maps a read-only page into user mode containing timing and\n * virtualization-related information (see SYSTEM_HYPERVISOR_USER_SHARED_DATA).\n *\n * User-mode components can read this page directly to obtain high-resolution\n * time conversion parameters or other hypervisor-provided data without\n * requiring a hypercall or kernel transition.\n */\ntypedef struct _SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION\n{\n    /**\n     * User-mode virtual address of the hypervisor shared data page.\n     * If no hypervisor is present, this pointer is NULL.\n     */\n    PSYSTEM_HYPERVISOR_USER_SHARED_DATA HypervisorSharedUserVa;\n} SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION, *PSYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_FIRMWARE_PARTITION_INFORMATION\n{\n    UNICODE_STRING FirmwarePartition;\n} SYSTEM_FIRMWARE_PARTITION_INFORMATION, *PSYSTEM_FIRMWARE_PARTITION_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG BpbEnabled : 1;\n            ULONG BpbDisabledSystemPolicy : 1;\n            ULONG BpbDisabledNoHardwareSupport : 1;\n            ULONG SpecCtrlEnumerated : 1;\n            ULONG SpecCmdEnumerated : 1;\n            ULONG IbrsPresent : 1;\n            ULONG StibpPresent : 1;\n            ULONG SmepPresent : 1;\n            ULONG SpeculativeStoreBypassDisableAvailable : 1; // REDSTONE4 (CVE-2018-3639)\n            ULONG SpeculativeStoreBypassDisableSupported : 1;\n            ULONG SpeculativeStoreBypassDisabledSystemWide : 1;\n            ULONG SpeculativeStoreBypassDisabledKernel : 1;\n            ULONG SpeculativeStoreBypassDisableRequired : 1;\n            ULONG BpbDisabledKernelToUser : 1;\n            ULONG SpecCtrlRetpolineEnabled : 1;\n            ULONG SpecCtrlImportOptimizationEnabled : 1;\n            ULONG EnhancedIbrs : 1; // since 19H1\n            ULONG HvL1tfStatusAvailable : 1;\n            ULONG HvL1tfProcessorNotAffected : 1;\n            ULONG HvL1tfMigitationEnabled : 1;\n            ULONG HvL1tfMigitationNotEnabled_Hardware : 1;\n            ULONG HvL1tfMigitationNotEnabled_LoadOption : 1;\n            ULONG HvL1tfMigitationNotEnabled_CoreScheduler : 1;\n            ULONG EnhancedIbrsReported : 1;\n            ULONG MdsHardwareProtected : 1; // since 19H2\n            ULONG MbClearEnabled : 1;\n            ULONG MbClearReported : 1;\n            ULONG ReservedTaa : 4;\n            ULONG Reserved : 1;\n        };\n    } SpeculationControlFlags;\n    union\n    {\n        ULONG Flags; // since 23H2\n        struct\n        {\n            ULONG SbdrSsdpHardwareProtected : 1;\n            ULONG FbsdpHardwareProtected : 1;\n            ULONG PsdpHardwareProtected : 1;\n            ULONG FbClearEnabled : 1;\n            ULONG FbClearReported : 1;\n            ULONG BhbEnabled : 1;\n            ULONG BhbDisabledSystemPolicy : 1;\n            ULONG BhbDisabledNoHardwareSupport : 1;\n            ULONG BranchConfusionStatus : 2;\n            ULONG BranchConfusionReported : 1;\n            ULONG RdclHardwareProtectedReported : 1;\n            ULONG RdclHardwareProtected : 1;\n            ULONG Reserved3 : 4;\n            ULONG Reserved4 : 3;\n            ULONG DivideByZeroReported : 1;\n            ULONG DivideByZeroStatus : 1;\n            ULONG Reserved5 : 3;\n            ULONG Reserved : 7;\n        };\n    } SpeculationControlFlags2;\n} SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_DMA_GUARD_POLICY_INFORMATION\n{\n    BOOLEAN DmaGuardPolicyEnabled;\n} SYSTEM_DMA_GUARD_POLICY_INFORMATION, *PSYSTEM_DMA_GUARD_POLICY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION\n{\n    UCHAR EnclaveLaunchSigner[32];\n} SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION, *PSYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION\n{\n    ULONGLONG WorkloadClass;\n    ULONGLONG CpuSets[1];\n} SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION, *PSYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SECURITY_MODEL_INFORMATION\n{\n    union\n    {\n        ULONG SecurityModelFlags;\n        struct\n        {\n            ULONG ReservedFlag : 1; // SModeAdminlessEnabled\n            ULONG AllowDeviceOwnerProtectionDowngrade : 1;\n            ULONG Reserved : 30;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n} SYSTEM_SECURITY_MODEL_INFORMATION, *PSYSTEM_SECURITY_MODEL_INFORMATION;\n\n// private\ntypedef union _SECURE_SPECULATION_CONTROL_INFORMATION\n{\n    ULONG KvaShadowSupported : 1;\n    ULONG KvaShadowEnabled : 1;\n    ULONG KvaShadowUserGlobal : 1;\n    ULONG KvaShadowPcid : 1;\n    ULONG MbClearEnabled : 1;\n    ULONG L1TFMitigated : 1; // since 20H2\n    ULONG BpbEnabled : 1;\n    ULONG IbrsPresent : 1;\n    ULONG EnhancedIbrs : 1;\n    ULONG StibpPresent : 1;\n    ULONG SsbdSupported : 1;\n    ULONG SsbdRequired : 1;\n    ULONG BpbKernelToUser : 1;\n    ULONG BpbUserToKernel : 1;\n    ULONG ReturnSpeculate : 1;\n    ULONG BranchConfusionSafe : 1;\n    ULONG SsbsEnabledAlways : 1; // 24H2\n    ULONG SsbsEnabledKernel : 1;\n    ULONG Reserved : 14;\n} SECURE_SPECULATION_CONTROL_INFORMATION, *PSECURE_SPECULATION_CONTROL_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_FIRMWARE_RAMDISK_INFORMATION\n{\n    ULONG Version;\n    ULONG BlockSize;\n    ULONG_PTR BaseAddress;\n    SIZE_T Size;\n} SYSTEM_FIRMWARE_RAMDISK_INFORMATION, *PSYSTEM_FIRMWARE_RAMDISK_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SHADOW_STACK_INFORMATION\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG CetCapable : 1;\n            ULONG UserCetAllowed : 1;\n            ULONG ReservedForUserCet : 6;\n            ULONG KernelCetEnabled : 1;\n            ULONG KernelCetAuditModeEnabled : 1;\n            ULONG ReservedForKernelCet : 6; // since Windows 10 build 21387\n            ULONG Reserved : 16;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n} SYSTEM_SHADOW_STACK_INFORMATION, *PSYSTEM_SHADOW_STACK_INFORMATION;\n\n// private\ntypedef union _SYSTEM_BUILD_VERSION_INFORMATION_FLAGS\n{\n    ULONG Value32;\n    struct\n    {\n        ULONG IsTopLevel : 1;\n        ULONG IsChecked : 1;\n    };\n} SYSTEM_BUILD_VERSION_INFORMATION_FLAGS, *PSYSTEM_BUILD_VERSION_INFORMATION_FLAGS;\n\n// private\ntypedef struct _SYSTEM_BUILD_VERSION_INFORMATION\n{\n    USHORT LayerNumber;\n    USHORT LayerCount;\n    ULONG OsMajorVersion;\n    ULONG OsMinorVersion;\n    ULONG NtBuildNumber;\n    ULONG NtBuildQfe;\n    UCHAR LayerName[128];\n    UCHAR NtBuildBranch[128];\n    UCHAR NtBuildLab[128];\n    UCHAR NtBuildLabEx[128];\n    UCHAR NtBuildStamp[26];\n    UCHAR NtBuildArch[16];\n    SYSTEM_BUILD_VERSION_INFORMATION_FLAGS Flags;\n} SYSTEM_BUILD_VERSION_INFORMATION, *PSYSTEM_BUILD_VERSION_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_POOL_LIMIT_MEM_INFO\n{\n    ULONGLONG MemoryLimit;\n    ULONGLONG NotificationLimit;\n} SYSTEM_POOL_LIMIT_MEM_INFO, *PSYSTEM_POOL_LIMIT_MEM_INFO;\n\n// private\ntypedef struct _SYSTEM_POOL_LIMIT_INFO\n{\n    ULONG PoolTag;\n    SYSTEM_POOL_LIMIT_MEM_INFO MemLimits[2];\n    WNF_STATE_NAME NotificationHandle;\n} SYSTEM_POOL_LIMIT_INFO, *PSYSTEM_POOL_LIMIT_INFO;\n\n// private\ntypedef struct _SYSTEM_POOL_LIMIT_INFORMATION\n{\n    ULONG Version;\n    ULONG EntryCount;\n    _Field_size_(EntryCount) SYSTEM_POOL_LIMIT_INFO LimitEntries[1];\n} SYSTEM_POOL_LIMIT_INFORMATION, *PSYSTEM_POOL_LIMIT_INFORMATION;\n\n// private\n//typedef struct _SYSTEM_POOL_ZEROING_INFORMATION\n//{\n//    BOOLEAN PoolZeroingSupportPresent;\n//} SYSTEM_POOL_ZEROING_INFORMATION, *PSYSTEM_POOL_ZEROING_INFORMATION;\n\n// private\ntypedef struct _HV_MINROOT_NUMA_LPS\n{\n    ULONG NodeIndex;\n    ULONG_PTR Mask[16];\n} HV_MINROOT_NUMA_LPS, *PHV_MINROOT_NUMA_LPS;\n\n// private\ntypedef struct _SYSTEM_XFG_FAILURE_INFORMATION\n{\n    PVOID ReturnAddress;\n    PVOID TargetAddress;\n    ULONG DispatchMode;\n    ULONGLONG XfgValue;\n} SYSTEM_XFG_FAILURE_INFORMATION, *PSYSTEM_XFG_FAILURE_INFORMATION;\n\n// private\ntypedef enum _SYSTEM_IOMMU_STATE\n{\n    IommuStateBlock,\n    IommuStateUnblock\n} SYSTEM_IOMMU_STATE;\n\n// private\ntypedef struct _SYSTEM_IOMMU_STATE_INFORMATION\n{\n    SYSTEM_IOMMU_STATE State;\n    PVOID Pdo;\n} SYSTEM_IOMMU_STATE_INFORMATION, *PSYSTEM_IOMMU_STATE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_HYPERVISOR_MINROOT_INFORMATION\n{\n    ULONG NumProc;\n    ULONG RootProc;\n    ULONG RootProcNumaNodesSpecified;\n    USHORT RootProcNumaNodes[64];\n    ULONG RootProcPerCore;\n    ULONG RootProcPerNode;\n    ULONG RootProcNumaNodesLpsSpecified;\n    HV_MINROOT_NUMA_LPS RootProcNumaNodeLps[64];\n} SYSTEM_HYPERVISOR_MINROOT_INFORMATION, *PSYSTEM_HYPERVISOR_MINROOT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_HYPERVISOR_BOOT_PAGES_INFORMATION\n{\n    ULONG RangeCount;\n    ULONG_PTR RangeArray[1];\n} SYSTEM_HYPERVISOR_BOOT_PAGES_INFORMATION, *PSYSTEM_HYPERVISOR_BOOT_PAGES_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_POINTER_AUTH_INFORMATION\n{\n    union\n    {\n        USHORT SupportedFlags;\n        struct\n        {\n            USHORT AddressAuthSupported : 1;\n            USHORT AddressAuthQarma : 1;\n            USHORT GenericAuthSupported : 1;\n            USHORT GenericAuthQarma : 1;\n            USHORT AddressAuthFaulting : 1;\n            USHORT SupportedReserved : 11;\n        };\n    };\n    union\n    {\n        USHORT EnabledFlags;\n        struct\n        {\n            USHORT UserPerProcessIpAuthEnabled : 1;\n            USHORT UserGlobalIpAuthEnabled : 1;\n            USHORT UserEnabledReserved : 6;\n            USHORT KernelIpAuthEnabled : 1;\n            USHORT KernelEnabledReserved : 7;\n        };\n    };\n} SYSTEM_POINTER_AUTH_INFORMATION, *PSYSTEM_POINTER_AUTH_INFORMATION;\n\n// rev\n#define SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_VERSION 1\n\n// private\ntypedef struct _SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_INPUT\n{\n    ULONG Version;\n    PWSTR FeatureName;\n    ULONG BornOnVersion;\n} SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_INPUT, *PSYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_INPUT;\n\n// private\ntypedef struct _SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_OUTPUT\n{\n    ULONG Version;\n    BOOLEAN FeatureIsEnabled;\n} SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_OUTPUT, *PSYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_OUTPUT;\n\n// private\ntypedef struct _SYSTEM_MEMORY_NUMA_INFORMATION_INPUT\n{\n    ULONG Version;\n    ULONG TargetNodeNumber;\n    ULONG Flags;\n} SYSTEM_MEMORY_NUMA_INFORMATION_INPUT, *PSYSTEM_MEMORY_NUMA_INFORMATION_INPUT;\n\n// private\ntypedef struct _SYSTEM_MEMORY_NUMA_INFORMATION_OUTPUT\n{\n    ULONG Version;\n    ULONG Size;\n    ULONG InitiatorNode;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG IsAttached : 1;\n            ULONG Reserved : 31;\n        };\n    };\n} SYSTEM_MEMORY_NUMA_INFORMATION_OUTPUT, *PSYSTEM_MEMORY_NUMA_INFORMATION_OUTPUT;\n\n// private\ntypedef enum _SYSTEM_MEMORY_NUMA_PERFORMANCE_QUERY_DATA_TYPES\n{\n    SystemMemoryNumaPerformanceQuery_ReadLatency,\n    SystemMemoryNumaPerformanceQuery_ReadBandwidth,\n    SystemMemoryNumaPerformanceQuery_WriteLatency,\n    SystemMemoryNumaPerformanceQuery_WriteBandwidth,\n    SystemMemoryNumaPerformanceQuery_Latency,\n    SystemMemoryNumaPerformanceQuery_Bandwidth,\n    SystemMemoryNumaPerformanceQuery_AllDataTypes,\n    SystemMemoryNumaPerformanceQuery_MaxDataType\n} SYSTEM_MEMORY_NUMA_PERFORMANCE_QUERY_DATA_TYPES;\n\n// private\ntypedef struct _SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUT\n{\n    ULONG Version;\n    ULONG TargetNodeNumber;\n    SYSTEM_MEMORY_NUMA_PERFORMANCE_QUERY_DATA_TYPES QueryDataType;\n    ULONG Flags;\n} SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUT, *PSYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUT;\n\n// private\ntypedef struct _SYSTEM_MEMORY_NUMA_PERFORMANCE_ENTRY\n{\n    ULONG InitiatorNodeNumber;\n    ULONG TargetNodeNumber;\n    SYSTEM_MEMORY_NUMA_PERFORMANCE_QUERY_DATA_TYPES DataType;\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN MinTransferSizeToAchieveValues : 1;\n            BOOLEAN NonSequentialTransfers : 1;\n            BOOLEAN Reserved : 6;\n        };\n    };\n    SIZE_T MinTransferSizeInBytes;\n    ULONG_PTR EntryValue;\n} SYSTEM_MEMORY_NUMA_PERFORMANCE_ENTRY, *PSYSTEM_MEMORY_NUMA_PERFORMANCE_ENTRY;\n\n// private\ntypedef struct _SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_OUTPUT\n{\n    ULONG Version;\n    ULONG Size;\n    ULONG EntryCount;\n    SYSTEM_MEMORY_NUMA_PERFORMANCE_ENTRY PerformanceEntries[1];\n} SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_OUTPUT, *PSYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_OUTPUT;\n\n/**\n * The SYSTEM_OSL_RAMDISK_ENTRY structure describes a single RAM disk region\n * used by the operating system loader.\n */\ntypedef struct _SYSTEM_OSL_RAMDISK_ENTRY\n{\n    ULONG BlockSize;\n    ULONG_PTR BaseAddress;\n    SIZE_T Size;\n} SYSTEM_OSL_RAMDISK_ENTRY, *PSYSTEM_OSL_RAMDISK_ENTRY;\n\n/**\n * The SYSTEM_TRUSTEDAPPS_RUNTIME_INFORMATION structure describes runtime\n * information related to Trusted Apps support.\n */\ntypedef struct _SYSTEM_TRUSTEDAPPS_RUNTIME_INFORMATION\n{\n    union\n    {\n        ULONGLONG Flags;\n        struct\n        {\n            ULONGLONG Supported : 1;\n            ULONGLONG Spare : 63;\n        };\n    };\n    PVOID RemoteBreakingRoutine;\n} SYSTEM_TRUSTEDAPPS_RUNTIME_INFORMATION, *PSYSTEM_TRUSTEDAPPS_RUNTIME_INFORMATION;\n\n/**\n * The SYSTEM_OSL_RAMDISK_INFORMATION structure describes a variable-length\n * array of RAM disk entries used by the operating system loader.\n */\ntypedef struct _SYSTEM_OSL_RAMDISK_INFORMATION\n{\n    ULONG Version;\n    ULONG Count;\n    SYSTEM_OSL_RAMDISK_ENTRY Entries[1];\n} SYSTEM_OSL_RAMDISK_INFORMATION, *PSYSTEM_OSL_RAMDISK_INFORMATION;\n\n/**\n * The CI_POLICY_MGMT_OPERATION enumeration specifies the type of Code Integrity\n * policy management operation requested.\n */\ntypedef enum _CI_POLICY_MGMT_OPERATION\n{\n    CI_POLICY_MGMT_OPERATION_NONE = 0,\n    CI_POLICY_MGMT_OPERATION_OPEN_TX = 1,\n    CI_POLICY_MGMT_OPERATION_COMMIT_TX = 2,\n    CI_POLICY_MGMT_OPERATION_CLOSE_TX = 3,\n    CI_POLICY_MGMT_OPERATION_ADD_POLICY = 4,\n    CI_POLICY_MGMT_OPERATION_REMOVE_POLICY = 5,\n    CI_POLICY_MGMT_OPERATION_GET_POLICY = 6,\n    CI_POLICY_MGMT_OPERATION_GET_POLICY_IDS = 7,\n    CI_POLICY_MGMT_OPERATION_MAX = 8\n} CI_POLICY_MGMT_OPERATION;\n\n/**\n * The SYSTEM_CODEINTEGRITYPOLICY_MANAGEMENT structure describes parameters\n * used to manage Code Integrity policies through the system information\n * interface.\n */\ntypedef struct _SYSTEM_CODEINTEGRITYPOLICY_MANAGEMENT\n{\n    CI_POLICY_MGMT_OPERATION Operation;\n    UCHAR UseInProgressState;\n    ULONG Arg1Len;\n    PUCHAR Arg1;\n    ULONG Arg2Len;\n    PUCHAR Arg2;\n} SYSTEM_CODEINTEGRITYPOLICY_MANAGEMENT, *PSYSTEM_CODEINTEGRITYPOLICY_MANAGEMENT;\n\n/**\n * The SYSTEM_REF_TRACE_INFORMATION_EX structure describes configuration\n * parameters for object reference tracing.\n */\ntypedef struct _SYSTEM_REF_TRACE_INFORMATION_EX\n{\n    ULONG Version;\n    ULONGLONG MemoryLimits;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG TraceEnable        : 1;\n            ULONG TracePermanent     : 1;\n            ULONG UseTracePoolTags   : 1;\n            ULONG TraceByStacksOnly  : 1;\n            ULONG ReservedFlags      : 28;\n        };\n    };\n    UNICODE_STRING TraceProcessName;\n    UNICODE_STRING TracePoolTags;\n    ULONG MaxObjectRefTraces;\n    ULONG TracedObjectLimit;\n} SYSTEM_REF_TRACE_INFORMATION_EX, *PSYSTEM_REF_TRACE_INFORMATION_EX;\n\n/**\n * The SYSTEM_BASICPROCESS_INFORMATION structure describes basic process\n * information returned when enumerating processes.\n */\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _SYSTEM_BASICPROCESS_INFORMATION\n{\n    ULONG NextEntryOffset;\n    HANDLE UniqueProcessId;\n    HANDLE InheritedFromUniqueProcessId;\n    ULONG64 SequenceNumber;\n    UNICODE_STRING ImageName;\n} SYSTEM_BASICPROCESS_INFORMATION, *PSYSTEM_BASICPROCESS_INFORMATION;\n\n/**\n * The SYSTEM_HANDLECOUNT_INFORMATION structure provides global counts of\n * processes, threads, and handles in the system.\n */\ntypedef struct _SYSTEM_HANDLECOUNT_INFORMATION\n{\n    ULONG ProcessCount;\n    ULONG ThreadCount;\n    ULONG HandleCount;\n} SYSTEM_HANDLECOUNT_INFORMATION, *PSYSTEM_HANDLECOUNT_INFORMATION;\n\n//\n//  Runtime Report Definitions\n//\n\n#define SYSTEM_RUNTIME_REPORT_INPUT_VERSION_1 1\n#define SYSTEM_RUNTIME_REPORT_INPUT_PACKAGE_VERSION_1 1\n\n// private\ntypedef struct _SYSTEM_RUNTIME_REPORT_INPUT\n{\n    USHORT InputVersion;\n    USHORT PackageVersion;\n    ULONG Reserved;\n    ULONG_PTR ReportTypesBitmap;\n    UCHAR Nonce[32];\n} SYSTEM_RUNTIME_REPORT_INPUT, *PSYSTEM_RUNTIME_REPORT_INPUT;\n\n#if !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\n//\n// ===============================================\n// Runtime Report Package Format:\n//\n// ------------------------------------- Signed part Begin\n//\n//     RUNTIME_REPORT_PACKAGE_HEADER\n//\n//     BYTE Nonce[RUNTIME_REPORT_NONCE_SIZE]\n//\n//     RUNTIME_REPORT_DIGEST_HEADER_A\n//\n//     RUNTIME_REPORT_DIGEST_HEADER_B\n//     ...\n//     ...\n//\n// ------------------------------------- Signed part End\n//\n//     Signature Blob\n//\n// ------------------------------------- Authenticated part Begin\n//\n//     RUNTIME_REPORT_HEADER\n//     REPORT_A\n//\n//     RUNTIME_REPORT_HEADER\n//     REPORT_B\n//\n// ------------------------------------- Authenticated part End\n//\n// ===============================================\n//\n\n#define RUNTIME_REPORT_PACKAGE_MAGIC    0x52545250  // = \"RTRP\"\n#define RUNTIME_REPORT_PACKAGE_VERSION_CURRENT  (1)\n#define RUNTIME_REPORT_NONCE_SIZE   32\n#define RUNTIME_REPORT_DIGEST_MAX_SIZE  64\n#define RUNTIME_REPORT_SIGNATURE_SCHEME_SHA512_RSA_PSS_SHA512   (1)\n\n//\n// Runtime Report Type Enumeration\n//\n\ntypedef enum _RUNTIME_REPORT_TYPE\n{\n    RuntimeReportTypeDriver = 0,\n    RuntimeReportTypeCodeIntegrity = 1,\n    RuntimeReportTypeMax\n} RUNTIME_REPORT_TYPE;\n\n//\n// Macro to convert a report type enum value to a bitmap mask\n//\n\n#define RUNTIME_REPORT_TYPE_TO_MASK(type) (1ULL << (type))\n\n//\n// Bitmap mask containing all valid report types\n//\n\n#define RUNTIME_REPORT_TYPE_MASK_ALL ((1ULL << RuntimeReportTypeMax) - 1)\n\ntypedef struct _RUNTIME_REPORT_PACKAGE_HEADER\n{\n    //\n    // Set to RUNTIME_REPORT_PACKAGE_MAGIC = 0x52545250 (\"RTRP\")\n    //\n\n    ULONG Magic;\n\n    //\n    // The version of the package format\n    //\n\n    USHORT PackageVersion;\n\n    //\n    // Number of different report types contained in the package.\n    //\n\n    USHORT NumberOfReports;\n\n    //\n    // A bitmap of all the report types in the package.\n    //\n    // Use RUNTIME_REPORT_TYPE_TO_MASK macro to convert enum values to bitmap masks.\n    // Current valid report types:\n    //      RuntimeReportTypeDriver = 0\n    //      RuntimeReportTypeCodeIntegrity = 1\n    //\n\n    ULONG_PTR ReportTypesBitmap;\n\n    //\n    // The size of the total package including the package header,\n    // various runtime reports, their digests, and the signature blob.\n    //\n\n    ULONG PackageSize;\n\n    //\n    // The type of digest contained in the report digest headers.\n    //\n    // Current valid values:\n    //      CALG_SHA_512 (see wincrypt.h)\n    //\n\n    USHORT ReportDigestType;\n\n    //\n    // Total size of the signed runtime report digest headers\n    // following the package header.\n    //\n\n    USHORT TotalReportDigestsSize;\n\n    //\n    // Reserved field. Must be set to zero.\n    //\n\n    USHORT Reserved;\n\n    //\n    // The signature scheme used to sign the runtime reports.\n    //\n    // Current valid values:\n    //      RUNTIME_REPORT_SIGNATURE_SCHEME_SHA512_RSA_PSS_SHA512 = 1\n    //\n\n    USHORT SignatureScheme;\n\n    //\n    // Size of the signature blob following the runtime report digests.\n    //\n\n    ULONG SignatureSize;\n\n    //\n    // Total size of the authenticated (but unsigned) runtime reports\n    // following the signature blob.\n    //\n\n    ULONG TotalAuthenticatedReportsSize;\n\n} RUNTIME_REPORT_PACKAGE_HEADER, *PRUNTIME_REPORT_PACKAGE_HEADER;\n\ntypedef struct _RUNTIME_REPORT_DIGEST_HEADER\n{\n    //\n    // Indicates the type of report that was hashed.\n    //\n    // Current valid values:\n    //      RuntimeReportTypeDriver = 0\n    //      RuntimeReportTypeCodeIntegrity = 1\n    //\n\n    USHORT ReportType;\n\n    //\n    // Reserved field.\n    //\n\n    USHORT Reserved;\n\n    //\n    // Digest of the report including the report header.\n    // This is a SHA-512 digest.\n    //\n\n    UCHAR ReportDigest[RUNTIME_REPORT_DIGEST_MAX_SIZE];\n\n} RUNTIME_REPORT_DIGEST_HEADER, *PRUNTIME_REPORT_DIGEST_HEADER;\n\ntypedef struct _RUNTIME_REPORT_HEADER\n{\n    //\n    // Indicates the type of report.\n    //\n    // Current valid values:\n    //      RuntimeReportTypeDriver = 0\n    //      RuntimeReportTypeCodeIntegrity = 1\n    //\n\n    USHORT ReportType;\n\n    //\n    // Reserved field.\n    //\n\n    USHORT Reserved;\n\n    //\n    // The number of bytes consumed by this report, including the header.\n    //\n\n    ULONG ReportSize;\n\n} RUNTIME_REPORT_HEADER, *PRUNTIME_REPORT_HEADER;\n\n//\n//  Driver Report Definitions\n//\n\n#define DRIVER_REPORT_DIGEST_MAX_SIZE   RUNTIME_REPORT_DIGEST_MAX_SIZE\n#define DRIVER_REPORT_NAME_MAX_LENGTH   32\n\ntypedef struct _DRIVER_INFO_ENTRY\n{\n    //\n    // Internal name of the driver from the resource section.\n    //\n\n    CHAR InternalName[DRIVER_REPORT_NAME_MAX_LENGTH];\n\n    //\n    // Hash algorithm used to calculate the image digest.\n    //\n\n    USHORT ImageHashAlgorithm;\n\n    //\n    // Hash algorithm used to calculate the thumbprint of the leaf certificate\n    // that validates the entire image.\n    //\n\n    USHORT PublisherThumbprintHashAlgorithm;\n\n    //\n    // Offset from the start of the driver report to a buffer containing the\n    // digest of the driver image on disk.\n    //\n\n    ULONG ImageHashOffset;\n\n    //\n    // Offset from the start of the driver report to a buffer containing the\n    // thumbprint of the leaf certificate validating the entire image\n    //\n\n    ULONG PublisherThumbprintOffset;\n\n    //\n    // Number of times that this driver image has been loaded into the system.\n    //\n\n    USHORT NumberOfLoadingTimes;\n\n    //\n    // Size and Offset of a string indicating the OEM name stored in the\n    // authenticated OPUS block of the image digital signature.\n    // There is no OEM name for inbox Windows signed drivers. The size does *NOT*\n    // include the NULL terminator (even though the string is NULL-terminated).\n    //\n\n    USHORT OemNameSize;\n    ULONG OemNameOffset;\n\n    //\n    // Flags indicating various properties of the current driver image:\n    //      - Unloaded - Set to 1 in case the driver is current unloaded.\n    //\n    //      - BootDriver - Set to 1 in case the image is a Boot Driver;\n    //           0 otherwise (the image is a Runtime driver).\n    //\n    //      - HotPatch - Set to 1 in case the image can be also loaded as Hotpatch;\n    //\n    //      - Reserved - Reserved flags bits.\n    //\n\n    union\n    {\n        struct\n        {\n            USHORT Unloaded : 1;\n            USHORT BootDriver : 1;\n            USHORT HotPatch : 1;\n            USHORT Reserved : 13;\n        };\n        USHORT AsUInt16;\n    } Flags;\n\n    USHORT Padding;\n} DRIVER_INFO_ENTRY, *PDRIVER_INFO_ENTRY;\n\ntypedef struct _DRIVER_RUNTIME_REPORT\n{\n    //\n    // The driver runtime report header.\n    //\n\n    RUNTIME_REPORT_HEADER Header;\n\n    //\n    // The current number of unique drivers in the report.\n    //\n\n    USHORT NumberOfDrivers;\n\n    //\n    // Flags indicating various properties of the report:\n    //      - ReportOverflowed - Secure Kernel places a limit on the number of\n    //          drivers it can list in the report. If this is set, it indicates\n    //          that some loaded drivers might be missing from the report.\n    //\n    //      - PartialReport - Indicates whether the report contains only a\n    //          subset of NT loaded drivers.\n    //\n    //      - IncludeBootDrivers - Set to 1 in case the report includes\n    //          boot-loaded drivers; 0 otherwise (in that case the information\n    //          is stored in the TCG Log).\n    //\n    //      - Reserved - Reserved flags bits.\n    //\n\n    union\n    {\n        struct\n        {\n            USHORT ReportOverflowed : 1;\n            USHORT PartialReport : 1;\n            USHORT IncludeBootDrivers : 1;\n            USHORT Reserved : 13;\n        };\n        USHORT AsUInt16;\n    } Flags;\n\n    //\n    // A list, of size zero up to MaximumDriversRecorded, containing driver entries.\n    // Unloaded drivers are not removed from the list.\n    //\n\n    DRIVER_INFO_ENTRY DriverEntries[ANYSIZE_ARRAY];\n\n    //\n    // After the driver info array the driver runtime report store hashes,\n    // strings and information that are dynamic in size.\n    //\n    // BYTE DynamicBuffer[ANYSIZE_ARRAY];\n    //\n    // The dynamic buffer, for each driver is composed off:\n    // ImageHash - PublisherHash - OemName.\n    //\n\n} DRIVER_RUNTIME_REPORT, *PDRIVER_RUNTIME_REPORT;\n\n//\n// Code Integrity Report Definitions.\n//\n\ntypedef struct _CODE_INTEGRITY_RUNTIME_REPORT\n{\n    //\n    // The Code Integrity runtime report header.\n    //\n\n    RUNTIME_REPORT_HEADER Header;\n\n    //\n    // The number of generations (updates) of policy there have been since boot.\n    // The initial generation at boot is 1.\n    //\n\n    UINT64 CurrentGeneration;\n\n    //\n    // The number of generations of policy that are in this report. This is\n    // non-zero with the current generation reported first, followed by prior\n    // generations in order of ascending age.\n    //\n\n    ULONG NumberOfGenerations;\n\n} CODE_INTEGRITY_RUNTIME_REPORT;\n\n#define CODE_INTEGRITY_REPORT_GENERATION_VERSION_CURRENT    (1)\n\ntypedef struct _CODE_INTEGRITY_REPORT_GENERATION_HEADER\n{\n    //\n    // Version of this structure.\n    //\n\n    USHORT Version;\n\n    //\n    // Reserved Field.\n    //\n\n    USHORT Reserved;\n\n    //\n    // The number of bytes consumed by this generation, including this header\n    // and all CODE_INTEGRITY_REPORT_RECORD_HEADER structures and payloads.\n    //\n\n    ULONG RecordSize;\n\n    //\n    // Secure Kernel / Hypervisor secure time reference when this policy was\n    // commited.\n    //\n\n    ULONG64 CommitTime;\n\n} CODE_INTEGRITY_REPORT_GENERATION_HEADER;\n\n#define CODE_INTEGRITY_REPORT_RECORD_VERSION_CURRENT    (1)\n\ntypedef struct _CODE_INTEGRITY_REPORT_RECORD_HEADER\n{\n    //\n    // Version of this structure.\n    //\n\n    USHORT Version;\n\n    //\n    // Reserved Field.\n    //\n\n    USHORT Reserved;\n\n    //\n    // The number of bytes consumed by this record, including this header.\n    //\n\n    ULONG RecordSize;\n\n    //\n    // The event code (type) of this record. The same codes as the Measured\n    // Boot TCG Log are used, for example SIPAEVENT_OS_REVOCATION_LIST, and\n    // indicate the structure type of the payload that immediately follows\n    // this header.\n    //\n\n    ULONG SipaEventCode;\n\n} CODE_INTEGRITY_REPORT_RECORD_HEADER;\n#endif // #if !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\n\n/**\n * The SYSTEM_POOLTAG2 structure describes allocation statistics for a single\n * pool tag, including paged and nonpaged usage.\n */\ntypedef struct _SYSTEM_POOLTAG2\n{\n    union\n    {\n        UCHAR Tag[4];\n        ULONG TagUlong;\n    } DUMMYUNIONNAME;\n    SIZE_T PagedAllocs;\n    SIZE_T PagedFrees;\n    SIZE_T PagedUsed;\n    SIZE_T NonPagedAllocs;\n    SIZE_T NonPagedFrees;\n    SIZE_T NonPagedUsed;\n} SYSTEM_POOLTAG2, *PSYSTEM_POOLTAG2;\n\n/**\n * The SYSTEM_POOLTAG_INFORMATION2 structure describes a variable-length array\n * of SYSTEM_POOLTAG2 entries representing pool tag usage statistics.\n */\ntypedef struct _SYSTEM_POOLTAG_INFORMATION2\n{\n    ULONG Count;\n    _Field_size_(Count) SYSTEM_POOLTAG2 TagInfo[1];\n} SYSTEM_POOLTAG_INFORMATION2, *PSYSTEM_POOLTAG_INFORMATION2;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * The NtQuerySystemInformation routine queries information about the system.\n *\n * \\param SystemInformationClass The type of information to be retrieved.\n * \\param SystemInformation A pointer to a buffer that receives the requested information.\n * \\param SystemInformationLength The size of the buffer pointed to by SystemInformation.\n * \\param ReturnLength A pointer to a variable that receives the size of the data returned in the buffer.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/sysinfo/zwquerysysteminformation\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemInformation(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n/**\n * The NtQuerySystemInformationEx routine queries information about the system.\n *\n * \\param SystemInformationClass The type of information to be retrieved.\n * \\param InputBuffer Pointer to a caller-allocated input buffer that contains class-specific information.\n * \\param InputBufferLength The size of the buffer pointed to by InputBuffer.\n * \\param SystemInformation A pointer to a buffer that receives the requested information.\n * \\param SystemInformationLength The size of the buffer pointed to by SystemInformation.\n * \\param ReturnLength A pointer to a variable that receives the size of the data returned in the buffer.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/sysinfo/zwquerysysteminformation\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemInformationEx(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n/**\n * The NtSetSystemInformation routine sets information about the system.\n *\n * \\param SystemInformationClass The type of information to be set.\n * \\param SystemInformation A pointer to a buffer that receives the requested information.\n * \\param SystemInformationLength The size of the buffer pointed to by SystemInformation.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSystemInformation(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _In_reads_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength\n    );\n\n//\n// SysDbg APIs\n//\n\n/**\n * The SYSDBG_COMMAND enumeration specifies the type of system debugger\n * operation requested through NtSystemDebugControl.\n */\ntypedef enum _SYSDBG_COMMAND\n{\n    SysDbgQueryModuleInformation,       // q: DBGKD_DEBUG_DATA_HEADER64\n    SysDbgQueryTraceInformation,        // q: DBGKD_TRACE_DATA\n    SysDbgSetTracepoint,                // s: PVOID\n    SysDbgSetSpecialCall,               // s: PVOID\n    SysDbgClearSpecialCalls,            // s: void\n    SysDbgQuerySpecialCalls,            // q: PVOID[]\n    SysDbgBreakPoint,                   // s: void\n    SysDbgQueryVersion,                 // q: DBGKD_GET_VERSION64\n    SysDbgReadVirtual,                  // q: SYSDBG_VIRTUAL\n    SysDbgWriteVirtual,                 // s: SYSDBG_VIRTUAL\n    SysDbgReadPhysical,                 // q: SYSDBG_PHYSICAL // 10\n    SysDbgWritePhysical,                // s: SYSDBG_PHYSICAL\n    SysDbgReadControlSpace,             // q: SYSDBG_CONTROL_SPACE\n    SysDbgWriteControlSpace,            // s: SYSDBG_CONTROL_SPACE\n    SysDbgReadIoSpace,                  // q: SYSDBG_IO_SPACE\n    SysDbgWriteIoSpace,                 // s: SYSDBG_IO_SPACE\n    SysDbgReadMsr,                      // q: SYSDBG_MSR\n    SysDbgWriteMsr,                     // s: SYSDBG_MSR\n    SysDbgReadBusData,                  // q: SYSDBG_BUS_DATA\n    SysDbgWriteBusData,                 // s: SYSDBG_BUS_DATA\n    SysDbgCheckLowMemory,               // q: ULONG // 20\n    SysDbgEnableKernelDebugger,         // s: void\n    SysDbgDisableKernelDebugger,        // s: void\n    SysDbgGetAutoKdEnable,              // q: ULONG\n    SysDbgSetAutoKdEnable,              // s: ULONG\n    SysDbgGetPrintBufferSize,           // q: ULONG\n    SysDbgSetPrintBufferSize,           // s: ULONG\n    SysDbgGetKdUmExceptionEnable,       // q: ULONG\n    SysDbgSetKdUmExceptionEnable,       // s: ULONG\n    SysDbgGetTriageDump,                // q: SYSDBG_TRIAGE_DUMP\n    SysDbgGetKdBlockEnable,             // q: ULONG // 30\n    SysDbgSetKdBlockEnable,             // s: ULONG\n    SysDbgRegisterForUmBreakInfo,       // s: HANDLE\n    SysDbgGetUmBreakPid,                // q: ULONG\n    SysDbgClearUmBreakPid,              // s: void\n    SysDbgGetUmAttachPid,               // q: ULONG\n    SysDbgClearUmAttachPid,             // s: void\n    SysDbgGetLiveKernelDump,            // q: SYSDBG_LIVEDUMP_CONTROL\n    SysDbgKdPullRemoteFile,             // q: SYSDBG_KD_PULL_REMOTE_FILE\n    SysDbgMaxInfoClass\n} SYSDBG_COMMAND, *PSYSDBG_COMMAND;\n\n/**\n * The SYSDBG_VIRTUAL structure describes a request to read or write virtual\n * memory through the system debugger interface.\n */\ntypedef struct _SYSDBG_VIRTUAL\n{\n    PVOID Address;\n    PVOID Buffer;\n    ULONG Request;\n} SYSDBG_VIRTUAL, *PSYSDBG_VIRTUAL;\n\n/**\n * The SYSDBG_PHYSICAL structure describes a request to read or write physical\n * memory through the system debugger interface.\n */\ntypedef struct _SYSDBG_PHYSICAL\n{\n    PHYSICAL_ADDRESS Address;\n    PVOID Buffer;\n    ULONG Request;\n} SYSDBG_PHYSICAL, *PSYSDBG_PHYSICAL;\n\n/**\n * The SYSDBG_CONTROL_SPACE structure describes a request to access processor\n * control space through the system debugger interface.\n */\ntypedef struct _SYSDBG_CONTROL_SPACE\n{\n    ULONG64 Address;\n    PVOID Buffer;\n    ULONG Request;\n    ULONG Processor;\n} SYSDBG_CONTROL_SPACE, *PSYSDBG_CONTROL_SPACE;\n\ntypedef enum _INTERFACE_TYPE INTERFACE_TYPE;\n\n/**\n * The SYSDBG_IO_SPACE structure describes a request to access I/O space\n * through the system debugger interface.\n */\ntypedef struct _SYSDBG_IO_SPACE\n{\n    ULONG64 Address;\n    PVOID Buffer;\n    ULONG Request;\n    INTERFACE_TYPE InterfaceType;\n    ULONG BusNumber;\n    ULONG AddressSpace;\n} SYSDBG_IO_SPACE, *PSYSDBG_IO_SPACE;\n\n/**\n * The SYSDBG_MSR structure describes a request to read or write a model-specific\n * register (MSR) through the system debugger interface.\n */\ntypedef struct _SYSDBG_MSR\n{\n    ULONG Msr;\n    ULONG64 Data;\n} SYSDBG_MSR, *PSYSDBG_MSR;\n\ntypedef enum _BUS_DATA_TYPE BUS_DATA_TYPE;\n\n/**\n * The SYSDBG_BUS_DATA structure describes a request to access bus-specific\n * configuration data through the system debugger interface.\n */\ntypedef struct _SYSDBG_BUS_DATA\n{\n    ULONG Address;\n    PVOID Buffer;\n    ULONG Request;\n    BUS_DATA_TYPE BusDataType;\n    ULONG BusNumber;\n    ULONG SlotNumber;\n} SYSDBG_BUS_DATA, *PSYSDBG_BUS_DATA;\n\n/**\n * The SYSDBG_TRIAGE_DUMP structure describes parameters used when generating\n * a triage dump through the system debugger interface.\n */\ntypedef struct _SYSDBG_TRIAGE_DUMP\n{\n    ULONG Flags;\n    ULONG BugCheckCode;\n    ULONG_PTR BugCheckParam1;\n    ULONG_PTR BugCheckParam2;\n    ULONG_PTR BugCheckParam3;\n    ULONG_PTR BugCheckParam4;\n    ULONG ProcessHandles;\n    ULONG ThreadHandles;\n    PHANDLE Handles;\n} SYSDBG_TRIAGE_DUMP, *PSYSDBG_TRIAGE_DUMP;\n\n/**\n * The SYSDBG_LIVEDUMP_CONTROL_FLAGS union specifies control flags used when\n * generating a live kernel dump.\n */\ntypedef union _SYSDBG_LIVEDUMP_CONTROL_FLAGS\n{\n    struct\n    {\n        ULONG UseDumpStorageStack : 1;\n        ULONG CompressMemoryPagesData : 1;\n        ULONG IncludeUserSpaceMemoryPages : 1;\n        ULONG AbortIfMemoryPressure : 1; // REDSTONE4\n        ULONG SelectiveDump : 1; // WIN11\n        ULONG Reserved : 27;\n    };\n    ULONG AsUlong;\n} SYSDBG_LIVEDUMP_CONTROL_FLAGS, *PSYSDBG_LIVEDUMP_CONTROL_FLAGS;\n\n/**\n * The SYSDBG_LIVEDUMP_CONTROL_ADDPAGES union specifies additional page\n * categories to include when generating a live kernel dump.\n */\ntypedef union _SYSDBG_LIVEDUMP_CONTROL_ADDPAGES\n{\n    struct\n    {\n        ULONG HypervisorPages : 1;\n        ULONG NonEssentialHypervisorPages : 1; // since WIN11\n        ULONG Reserved : 30;\n    };\n    ULONG AsUlong;\n} SYSDBG_LIVEDUMP_CONTROL_ADDPAGES, *PSYSDBG_LIVEDUMP_CONTROL_ADDPAGES;\n\n#define SYSDBG_LIVEDUMP_SELECTIVE_CONTROL_VERSION 1\n\n// rev\n/**\n * The SYSDBG_LIVEDUMP_SELECTIVE_CONTROL structure specifies selective dump\n * options for live kernel dump generation.\n */\ntypedef struct _SYSDBG_LIVEDUMP_SELECTIVE_CONTROL\n{\n    ULONG Version;\n    ULONG Size;\n    union\n    {\n        ULONGLONG Flags;\n        struct\n        {\n            ULONGLONG ThreadKernelStacks : 1;\n            ULONGLONG ReservedFlags : 63;\n        };\n    };\n    ULONGLONG Reserved[4];\n} SYSDBG_LIVEDUMP_SELECTIVE_CONTROL, *PSYSDBG_LIVEDUMP_SELECTIVE_CONTROL;\n\n#define SYSDBG_LIVEDUMP_CONTROL_VERSION_1 1\n#define SYSDBG_LIVEDUMP_CONTROL_VERSION_2 2\n#define SYSDBG_LIVEDUMP_CONTROL_VERSION SYSDBG_LIVEDUMP_CONTROL_VERSION_2\n\n/**\n * The SYSDBG_LIVEDUMP_CONTROL_V1 structure describes parameters used when\n * generating a live kernel dump (version 1).\n */\ntypedef struct _SYSDBG_LIVEDUMP_CONTROL_V1\n{\n    ULONG Version;\n    ULONG BugCheckCode;\n    ULONG_PTR BugCheckParam1;\n    ULONG_PTR BugCheckParam2;\n    ULONG_PTR BugCheckParam3;\n    ULONG_PTR BugCheckParam4;\n    HANDLE DumpFileHandle;\n    HANDLE CancelEventHandle;\n    SYSDBG_LIVEDUMP_CONTROL_FLAGS Flags;\n    SYSDBG_LIVEDUMP_CONTROL_ADDPAGES AddPagesControl;\n} SYSDBG_LIVEDUMP_CONTROL_V1, *PSYSDBG_LIVEDUMP_CONTROL_V1;\n\n/**\n * The SYSDBG_LIVEDUMP_CONTROL structure describes parameters used when\n * generating a live kernel dump (current version).\n */\ntypedef struct _SYSDBG_LIVEDUMP_CONTROL\n{\n    ULONG Version;\n    ULONG BugCheckCode;\n    ULONG_PTR BugCheckParam1;\n    ULONG_PTR BugCheckParam2;\n    ULONG_PTR BugCheckParam3;\n    ULONG_PTR BugCheckParam4;\n    HANDLE DumpFileHandle;\n    HANDLE CancelEventHandle;\n    SYSDBG_LIVEDUMP_CONTROL_FLAGS Flags;\n    SYSDBG_LIVEDUMP_CONTROL_ADDPAGES AddPagesControl;\n    PSYSDBG_LIVEDUMP_SELECTIVE_CONTROL SelectiveControl; // since WIN11\n} SYSDBG_LIVEDUMP_CONTROL, *PSYSDBG_LIVEDUMP_CONTROL;\n\n/**\n * The SYSDBG_KD_PULL_REMOTE_FILE structure describes a request to retrieve\n * a remote file through the kernel debugger transport.\n */\ntypedef struct _SYSDBG_KD_PULL_REMOTE_FILE\n{\n    UNICODE_STRING ImageFileName;\n} SYSDBG_KD_PULL_REMOTE_FILE, *PSYSDBG_KD_PULL_REMOTE_FILE;\n\n/**\n * The NtSystemDebugControl routine provides system debugging and diagnostic control of the system.\n *\n * \\param[in] Command The debug control command to execute (of type SYSDBG_COMMAND).\n * \\param[in] InputBuffer Optional pointer to a buffer containing input data for the command.\n * \\param[in] InputBufferLength Length, in bytes, of the input buffer.\n * \\param[out] OutputBuffer Optional pointer to a buffer that receives output data from the command.\n * \\param[in] OutputBufferLength Length, in bytes, of the output buffer.\n * \\param[out] ReturnLength Optional pointer to a variable that receives the number of bytes returned in the output buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSystemDebugControl(\n    _In_ SYSDBG_COMMAND Command,\n    _Inout_updates_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n//\n// Hard errors\n//\n\n/**\n * The HARDERROR_RESPONSE_OPTION enumeration specifies the type of user\n * interface prompt that may be displayed when a hard error occurs.\n */\ntypedef enum _HARDERROR_RESPONSE_OPTION\n{\n    OptionAbortRetryIgnore,\n    OptionOk,\n    OptionOkCancel,\n    OptionRetryCancel,\n    OptionYesNo,\n    OptionYesNoCancel,\n    OptionShutdownSystem,\n    OptionOkNoWait,\n    OptionCancelTryContinue\n} HARDERROR_RESPONSE_OPTION;\n\n/**\n * The HARDERROR_RESPONSE enumeration specifies the response returned by the\n * caller or user when handling a hard error condition.\n */\ntypedef enum _HARDERROR_RESPONSE\n{\n    ResponseReturnToCaller,\n    ResponseNotHandled,\n    ResponseAbort,\n    ResponseCancel,\n    ResponseIgnore,\n    ResponseNo,\n    ResponseOk,\n    ResponseRetry,\n    ResponseYes,\n    ResponseTryAgain,\n    ResponseContinue\n} HARDERROR_RESPONSE;\n\n/**\n * HARDERROR_OVERRIDE_ERRORMODE indicates that the system should ignore the\n * calling process's error mode when processing a hard error.\n */\n#define HARDERROR_OVERRIDE_ERRORMODE 0x10000000\n\n/**\n * The NtRaiseHardError routine raises a hard error or serious error dialog box being displayed to the user.\n *\n * \\param[in] ErrorStatus The NTSTATUS code that describes the error condition.\n * \\param[in] NumberOfParameters The number of parameters in the Parameters array.\n * \\param[in] UnicodeStringParameterMask A bitmask indicating which entries in the Parameters array are Unicode strings.\n * \\param[in] Parameters An array of parameters to be used in the error message.\n * \\param[in] ValidResponseOptions Specifies the valid responses that the user can select in the error dialog.\n * \\param[out] Response Receives the user's response to the error dialog.\n * \\return NTSTATUS Successful or errant status.\n */\n_Analysis_noreturn_\nDECLSPEC_NORETURN\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRaiseHardError(\n    _In_ NTSTATUS ErrorStatus,\n    _In_ ULONG NumberOfParameters,\n    _In_ ULONG UnicodeStringParameterMask,\n    _In_reads_(NumberOfParameters) PULONG_PTR Parameters,\n    _In_ ULONG ValidResponseOptions,\n    _Out_ PULONG Response\n    );\n\n//\n// Kernel-user shared data\n//\n\n/**\n * The ALTERNATIVE_ARCHITECTURE_TYPE enumeration specifies the hardware\n * architecture variant used by the system.\n *\n * \\remarks NEC98x86 represents the NEC PC-98 architecture,\n * supported only on very early Windows releases.\n */\ntypedef enum _ALTERNATIVE_ARCHITECTURE_TYPE\n{\n    StandardDesign,\n    NEC98x86,\n    EndAlternatives\n} ALTERNATIVE_ARCHITECTURE_TYPE;\n\n/**\n * PROCESSOR_FEATURE_MAX defines the maximum number of processor feature flags\n * that may be reported by the system.\n */\n#define PROCESSOR_FEATURE_MAX 64\n\n/**\n * MAX_WOW64_SHARED_ENTRIES defines the number of shared entries available to\n * the WOW64 (Windows-on-Windows 64-bit) subsystem.\n */\n#define MAX_WOW64_SHARED_ENTRIES 16\n\n//\n// Define NX support policy values.\n//\n\n#define NX_SUPPORT_POLICY_ALWAYSOFF     0\n#define NX_SUPPORT_POLICY_ALWAYSON      1\n#define NX_SUPPORT_POLICY_OPTIN         2\n#define NX_SUPPORT_POLICY_OPTOUT        3\n\n//\n// SEH chain validation policies.\n//\n\n#define SEH_VALIDATION_POLICY_ON        0\n#define SEH_VALIDATION_POLICY_OFF       1\n#define SEH_VALIDATION_POLICY_TELEMETRY 2\n#define SEH_VALIDATION_POLICY_DEFER     3\n\n//\n// Global shared data flags and manipulation macros.\n//\n\n#define SHARED_GLOBAL_FLAGS_ERROR_PORT_V                0x0\n#define SHARED_GLOBAL_FLAGS_ERROR_PORT                  \\\n    (1UL << SHARED_GLOBAL_FLAGS_ERROR_PORT_V)\n\n#define SHARED_GLOBAL_FLAGS_ELEVATION_ENABLED_V         0x1\n#define SHARED_GLOBAL_FLAGS_ELEVATION_ENABLED           \\\n    (1UL << SHARED_GLOBAL_FLAGS_ELEVATION_ENABLED_V)\n\n#define SHARED_GLOBAL_FLAGS_VIRT_ENABLED_V              0x2\n#define SHARED_GLOBAL_FLAGS_VIRT_ENABLED                \\\n    (1UL << SHARED_GLOBAL_FLAGS_VIRT_ENABLED_V)\n\n#define SHARED_GLOBAL_FLAGS_INSTALLER_DETECT_ENABLED_V  0x3\n#define SHARED_GLOBAL_FLAGS_INSTALLER_DETECT_ENABLED    \\\n    (1UL << SHARED_GLOBAL_FLAGS_INSTALLER_DETECT_ENABLED_V)\n\n#define SHARED_GLOBAL_FLAGS_LKG_ENABLED_V               0x4\n#define SHARED_GLOBAL_FLAGS_LKG_ENABLED                 \\\n    (1UL << SHARED_GLOBAL_FLAGS_LKG_ENABLED_V)\n\n#define SHARED_GLOBAL_FLAGS_DYNAMIC_PROC_ENABLED_V      0x5\n#define SHARED_GLOBAL_FLAGS_DYNAMIC_PROC_ENABLED        \\\n    (1UL << SHARED_GLOBAL_FLAGS_DYNAMIC_PROC_ENABLED_V)\n\n#define SHARED_GLOBAL_FLAGS_CONSOLE_BROKER_ENABLED_V    0x6\n#define SHARED_GLOBAL_FLAGS_CONSOLE_BROKER_ENABLED      \\\n    (1UL << SHARED_GLOBAL_FLAGS_CONSOLE_BROKER_ENABLED_V)\n\n#define SHARED_GLOBAL_FLAGS_SECURE_BOOT_ENABLED_V       0x7\n#define SHARED_GLOBAL_FLAGS_SECURE_BOOT_ENABLED         \\\n    (1UL << SHARED_GLOBAL_FLAGS_SECURE_BOOT_ENABLED_V)\n\n#define SHARED_GLOBAL_FLAGS_MULTI_SESSION_SKU_V         0x8\n#define SHARED_GLOBAL_FLAGS_MULTI_SESSION_SKU           \\\n    (1UL << SHARED_GLOBAL_FLAGS_MULTI_SESSION_SKU_V)\n\n#define SHARED_GLOBAL_FLAGS_MULTIUSERS_IN_SESSION_SKU_V 0x9\n#define SHARED_GLOBAL_FLAGS_MULTIUSERS_IN_SESSION_SKU   \\\n    (1UL << SHARED_GLOBAL_FLAGS_MULTIUSERS_IN_SESSION_SKU_V)\n\n#define SHARED_GLOBAL_FLAGS_STATE_SEPARATION_ENABLED_V 0xA\n#define SHARED_GLOBAL_FLAGS_STATE_SEPARATION_ENABLED   \\\n    (1UL << SHARED_GLOBAL_FLAGS_STATE_SEPARATION_ENABLED_V)\n\n#define SHARED_GLOBAL_FLAGS_SET_GLOBAL_DATA_FLAG        0x40000000\n#define SHARED_GLOBAL_FLAGS_CLEAR_GLOBAL_DATA_FLAG      0x80000000\n\n//\n// Define legal values for the SystemCall member.\n//\n\n#define SYSTEM_CALL_SYSCALL 0\n#define SYSTEM_CALL_INT_2E  1\n\n//\n// Define flags for QPC bypass information. None of these flags may be set\n// unless bypass is enabled. This is for compat with existing code which\n// compares this value to zero to detect bypass enablement.\n//\n\n#define SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED (0x01)\n#define SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_HV_PAGE (0x02)\n#define SHARED_GLOBAL_FLAGS_QPC_BYPASS_DISABLE_32BIT (0x04)\n#define SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_MFENCE (0x10)\n#define SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_LFENCE (0x20)\n#define SHARED_GLOBAL_FLAGS_QPC_BYPASS_A73_ERRATA (0x40)\n#define SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_RDTSCP (0x80)\n\n/**\n * The KUSER_SHARED_DATA structure contains information shared with user-mode.\n *\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data\n */\ntypedef struct _KUSER_SHARED_DATA\n{\n    //\n    // Current low 32-bit of tick count and tick count multiplier.\n    //\n    // N.B. The tick count is updated each time the clock ticks.\n    //\n\n    ULONG TickCountLowDeprecated;\n    ULONG TickCountMultiplier;\n\n    //\n    // Current 64-bit interrupt time in 100ns units.\n    //\n\n    volatile KSYSTEM_TIME InterruptTime;\n\n    //\n    // Current 64-bit system time in 100ns units.\n    //\n\n    volatile KSYSTEM_TIME SystemTime;\n\n    //\n    // Current 64-bit time zone bias.\n    //\n\n    volatile KSYSTEM_TIME TimeZoneBias;\n\n    //\n    // Support image magic number range for the host system.\n    //\n    // N.B. This is an inclusive range.\n    //\n\n    USHORT ImageNumberLow;\n    USHORT ImageNumberHigh;\n\n    //\n    // Copy of system root in unicode.\n    //\n    // N.B. This field must be accessed via the RtlGetNtSystemRoot API for\n    //      an accurate result.\n    //\n\n    WCHAR NtSystemRoot[260];\n\n    //\n    // Maximum stack trace depth if tracing enabled.\n    //\n\n    ULONG MaxStackTraceDepth;\n\n    //\n    // Crypto exponent value.\n    //\n\n    ULONG CryptoExponent;\n\n    //\n    // Time zone ID.\n    //\n\n    ULONG TimeZoneId;\n\n    //\n    // Minimum size of a large page on the system, in bytes.\n    //\n    // N.B. Returned by GetLargePageMinimum() function.\n    //\n\n    ULONG LargePageMinimum;\n\n    //\n    // This value controls the Application Impact Telemetry (AIT) Sampling rate.\n    //\n    // This value determines how frequently the system records AIT events,\n    // which are used by the Application Experience and compatibility\n    // subsystems to evaluate application behavior, performance, and\n    // potential compatibility issues.\n    //\n    // Lower values increase sampling frequency, while higher values reduce it.\n    // The kernel updates this field as part of its internal telemetry and\n    // heuristics logic.\n    //\n\n    ULONG AitSamplingValue;\n\n    //\n    // This value controls Application Compatibility (AppCompat) switchback processing.\n    //\n\n    union\n    {\n        ULONG AppCompatFlag;\n        struct\n        {\n            ULONG SwitchbackEnabled : 1;    // Basic switchback processing\n            ULONG ExtendedHeuristics : 1;   // Extended switchback heuristics\n            ULONG TelemetryFallback : 1;    // Telemetry-driven fallback\n            ULONG Reserved : 29;\n        } AppCompatFlags;\n    };\n\n    //\n    // Current Kernel Root RNG state seed version\n    //\n\n    ULONGLONG RNGSeedVersion;\n\n    //\n    // This value controls assertion failure handling.\n    //\n    // Historically (prior to Windows 10), this value was also used by\n    // Code Integrity (CI), AppLocker, and related security components to\n    // determine the minimum validation requirements for executable images,\n    // drivers, and privileged operations.\n    //\n    // In modern Windows versions, this field is used primarily by the kernel's\n    // diagnostic and validation infrastructure to decide how assertion failures\n    // should be handled (e.g., logging, debugger break-in, or bugcheck).\n\n    ULONG GlobalValidationRunlevel;\n\n    //\n    // Monotonic stamp incremented by the kernel whenever the system's\n    // time zone bias value changes.\n    //\n    // N.B. This field must be accessed via the RtlGetSystemTimeAndBias API for\n    //      an accurate result.\n    // This value is read before and after accessing the bias fields to determine\n    // whether the time zone data changed during the read. If the stamp differs,\n    // the caller must re-read the bias values to ensure consistency.\n    //\n\n    volatile LONG TimeZoneBiasStamp;\n\n    //\n    // The shared collective build number undecorated with C or F.\n    // GetVersionEx hides the real number\n    //\n\n    ULONG NtBuildNumber;\n\n    //\n    // Product type.\n    //\n    // N.B. This field must be accessed via the RtlGetNtProductType API for\n    //      an accurate result.\n    //\n\n    NT_PRODUCT_TYPE NtProductType;\n    BOOLEAN ProductTypeIsValid;\n    BOOLEAN Reserved0[1];\n\n    //\n    // Native hardware processor architecture of the running system.\n    //\n    // N.B. User-mode components read this field to determine the true system\n    // architecture, especially in WOW64 scenarios where the process architecture\n    // differs from the native one.\n    //\n\n    USHORT NativeProcessorArchitecture;\n\n    //\n    // The NT Version.\n    //\n    // N. B. Note that each process sees a version from its PEB, but if the\n    //       process is running with an altered view of the system version,\n    //       the following two fields are used to correctly identify the\n    //       version\n    //\n\n    ULONG NtMajorVersion;\n    ULONG NtMinorVersion;\n\n    //\n    // Processor features.\n    //\n\n    BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX];\n\n    //\n    // Reserved fields - do not use.\n    //\n\n    ULONG MaximumUserModeAddressDeprecated; // Deprecated, use SystemBasicInformation instead.\n    ULONG SystemRangeStartDeprecated; // Deprecated, use SystemRangeStartInformation instead.\n\n    //\n    // Time slippage while in debugger.\n    //\n\n    volatile ULONG TimeSlip;\n\n    //\n    // Alternative system architecture, e.g., NEC PC98xx on x86.\n    //\n\n    ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;\n\n    //\n    // Boot sequence, incremented for each boot attempt by the OS loader.\n    //\n\n    ULONG BootId;\n\n    //\n    // If the system is an evaluation unit, the following field contains the\n    // date and time that the evaluation unit expires. A value of 0 indicates\n    // that there is no expiration. A non-zero value is the UTC absolute time\n    // that the system expires.\n    //\n\n    LARGE_INTEGER SystemExpirationDate;\n\n    //\n    // Suite support.\n    //\n    // N.B. This field must be accessed via the RtlGetSuiteMask API for\n    //      an accurate result.\n    //\n\n    ULONG SuiteMask;\n\n    //\n    // TRUE if a kernel debugger is connected/enabled.\n    //\n\n    BOOLEAN KdDebuggerEnabled;\n\n    //\n    // Mitigation policies.\n    //\n\n    union\n    {\n        UCHAR MitigationPolicies;\n        struct\n        {\n            UCHAR NXSupportPolicy : 2;\n            UCHAR SEHValidationPolicy : 2;\n            UCHAR CurDirDevicesSkippedForDlls : 2;\n            UCHAR Reserved : 2;\n        };\n    };\n\n    //\n    // Measured duration of a single processor yield, in cycles. This is used by\n    // lock packages to determine how many times to spin waiting for a state\n    // change before blocking.\n    //\n\n    USHORT CyclesPerYield;\n\n    //\n    // Current console session Id. Always zero on non-TS systems.\n    //\n    // N.B. This field must be accessed via the RtlGetActiveConsoleId API for an\n    //      accurate result.\n    //\n\n    volatile ULONG ActiveConsoleId;\n\n    //\n    // Force-dismounts cause handles to become invalid. Rather than always\n    // probe handles, a serial number of dismounts is maintained that clients\n    // can use to see if they need to probe handles.\n    //\n\n    volatile ULONG DismountCount;\n\n    //\n    // This field indicates the status of the 64-bit COM+ package on the\n    // system. It indicates whether the Intermediate Language (IL) COM+\n    // images need to use the 64-bit COM+ runtime or the 32-bit COM+ runtime.\n    //\n\n    ULONG ComPlusPackage;\n\n    //\n    // Time in tick count for system-wide last user input across all terminal\n    // sessions. For MP performance, it is not updated all the time (e.g. once\n    // a minute per session). It is used for idle detection.\n    //\n\n    ULONG LastSystemRITEventTickCount;\n\n    //\n    // Number of physical pages in the system. This can dynamically change as\n    // physical memory can be added or removed from a running system.  This\n    // cell is too small to hold the non-truncated value on very large memory\n    // machines so code that needs the full value should access\n    // FullNumberOfPhysicalPages instead.\n    //\n\n    ULONG NumberOfPhysicalPages;\n\n    //\n    // True if the system was booted in safe boot mode.\n    //\n\n    BOOLEAN SafeBootMode;\n\n    //\n    // Virtualization flags.\n    //\n\n    union\n    {\n        UCHAR VirtualizationFlags;\n\n#if defined(_ARM64_)\n\n        //\n        // N.B. Keep this bitfield in sync with the one in arc.w.\n        //\n\n        struct\n        {\n            UCHAR ArchStartedInEl2 : 1;\n            UCHAR QcSlIsSupported : 1;\n            UCHAR : 6;\n        };\n\n#endif\n\n    };\n\n    //\n    // Reserved (available for reuse).\n    //\n\n    UCHAR Reserved12[2];\n\n    //\n    // This is a packed bitfield that contains various flags concerning\n    // the system state. They must be manipulated using interlocked\n    // operations.\n    //\n    // N.B. DbgMultiSessionSku must be accessed via the RtlIsMultiSessionSku\n    //      API for an accurate result\n    //\n\n    union\n    {\n        ULONG SharedDataFlags;\n        struct\n        {\n            //\n            // The following bit fields are for the debugger only. Do not use.\n            // Use the bit definitions instead.\n            //\n\n            ULONG DbgErrorPortPresent       : 1;\n            ULONG DbgElevationEnabled       : 1;\n            ULONG DbgVirtEnabled            : 1;\n            ULONG DbgInstallerDetectEnabled : 1;\n            ULONG DbgLkgEnabled             : 1;\n            ULONG DbgDynProcessorEnabled    : 1;\n            ULONG DbgConsoleBrokerEnabled   : 1;\n            ULONG DbgSecureBootEnabled      : 1;\n            ULONG DbgMultiSessionSku        : 1;\n            ULONG DbgMultiUsersInSessionSku : 1;\n            ULONG DbgStateSeparationEnabled : 1;\n            ULONG DbgSplitTokenEnabled      : 1;\n            ULONG DbgShadowAdminEnabled     : 1;\n            ULONG SpareBits                 : 19;\n        } DUMMYSTRUCTNAME2;\n    } DUMMYUNIONNAME2;\n\n    //\n    // Reserved padding field to preserve structure alignment and compatibility.\n    //\n\n    ULONG DataFlagsPad[1];\n\n    //\n    // Depending on the processor, the code for fast system call will differ,\n    // Stub code is provided pointers below to access the appropriate code.\n    //\n    // N.B. The following field is only used on 32-bit systems.\n    //\n\n    ULONGLONG TestRetInstruction;\n\n    //\n    // Query-performance counter (QPC) frequency, in counts per second.\n    //\n    // N.B. This value represents the fixed frequency of the system's high-resolution\n    // performance counter. It is used by user-mode time routines to convert QPC\n    // ticks into elapsed time without requiring a system call. The frequency is\n    // constant for the lifetime of the system and reflects the hardware or\n    // virtualized timer source selected by the kernel.\n    //\n\n    LONGLONG QpcFrequency;\n\n    //\n    // On AMD64, this value is initialized to a nonzero value if the system\n    // operates with an altered view of the system service call mechanism.\n    //\n\n    ULONG SystemCall;\n\n    //\n    // Reserved field - do not use. Used to be UserCetAvailableEnvironments.\n    //\n\n    ULONG Reserved2;\n\n    //\n    // Full 64 bit version of the number of physical pages in the system.\n    // This can dynamically change as physical memory can be added or removed\n    // from a running system.\n    //\n\n    ULONGLONG FullNumberOfPhysicalPages;\n\n    //\n    // Reserved, available for reuse.\n    //\n\n    ULONGLONG SystemCallPad[1];\n\n    //\n    // The 64-bit tick count.\n    //\n\n    union\n    {\n        volatile KSYSTEM_TIME TickCount;\n        volatile ULONG64 TickCountQuad;\n        struct\n        {\n            ULONG ReservedTickCountOverlay[3];\n            ULONG TickCountPad[1];\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME3;\n\n    //\n    // Cookie for encoding pointers system wide.\n    //\n\n    ULONG Cookie;\n    ULONG CookiePad[1];\n\n    //\n    // Client id of the process having the focus in the current\n    // active console session id.\n    //\n    // N.B. This field must be accessed via the\n    //      RtlGetConsoleSessionForegroundProcessId API for an accurate result.\n    //\n\n    LONGLONG ConsoleSessionForegroundProcessId;\n\n    //\n    // N.B. The following data is used to implement the precise time\n    //      services. It is aligned on a 64-byte cache-line boundary and\n    //      arranged in the order of typical accesses.\n    //\n    // Placeholder for the (internal) time update lock.\n    //\n\n    ULONGLONG TimeUpdateLock;\n\n    //\n    // The performance counter value used to establish the current system time.\n    //\n\n    ULONGLONG BaselineSystemTimeQpc;\n\n    //\n    // The performance counter value used to compute the last interrupt time.\n    //\n\n    ULONGLONG BaselineInterruptTimeQpc;\n\n    //\n    // The scaled number of system time seconds represented by a single\n    // performance count (this value may vary to achieve time synchronization).\n    //\n\n    ULONGLONG QpcSystemTimeIncrement;\n\n    //\n    // The scaled number of interrupt time seconds represented by a single\n    // performance count (this value is constant after the system is booted).\n    //\n\n    ULONGLONG QpcInterruptTimeIncrement;\n\n    //\n    // The scaling shift count applied to the performance counter system time\n    // increment.\n    //\n\n    UCHAR QpcSystemTimeIncrementShift;\n\n    //\n    // The scaling shift count applied to the performance counter interrupt time\n    // increment.\n    //\n\n    UCHAR QpcInterruptTimeIncrementShift;\n\n    //\n    // The count of unparked processors.\n    //\n\n    USHORT UnparkedProcessorCount;\n\n    //\n    // A bitmask of enclave features supported on this system.\n    //\n    // N.B. This field must be accessed via the RtlIsEnclaveFeaturePresent API for an\n    //      accurate result.\n    //\n\n    ULONG EnclaveFeatureMask[4];\n\n    //\n    // Current coverage round for telemetry based coverage.\n    //\n\n    ULONG TelemetryCoverageRound;\n\n    //\n    // The following field is used for ETW user mode global logging\n    // (UMGL).\n    //\n\n    USHORT UserModeGlobalLogger[16];\n\n    //\n    // Settings that can enable the use of Image File Execution Options\n    // from HKCU in addition to the original HKLM.\n    //\n\n    ULONG ImageFileExecutionOptions;\n\n    //\n    // Generation of the kernel structure holding system language information\n    //\n\n    ULONG LangGenerationCount;\n\n    //\n    // Reserved (available for reuse).\n    //\n\n    ULONGLONG Reserved4;\n\n    //\n    // Current 64-bit interrupt time bias in 100ns units.\n    //\n\n    volatile ULONGLONG InterruptTimeBias;\n\n    //\n    // Current 64-bit performance counter bias, in performance counter units\n    // before the shift is applied.\n    //\n\n    volatile ULONGLONG QpcBias;\n\n    //\n    // Number of active logical processors.\n    //\n\n    ULONG ActiveProcessorCount;\n\n    //\n    // Number of active processor groups.\n    //\n    // N.B. This value is volatile because group membership and processor\n    // availability may change dynamically due to hot-add, hot-remove,\n    // or power management events.\n    //\n\n    volatile UCHAR ActiveGroupCount;\n\n    //\n    // Reserved (available for re-use).\n    //\n\n    UCHAR Reserved9;\n\n    union\n    {\n        USHORT QpcData;\n        struct\n        {\n            //\n            // A bitfield indicating whether performance counter queries can\n            // read the counter directly (bypassing the system call) and flags.\n            //\n\n            union\n            {\n\n                volatile UCHAR QpcBypassEnabled;\n\n                struct\n                {\n                    //\n                    // QPC may bypass the syscall and use a fast user-mode path.\n                    //\n                    volatile UCHAR BypassAllowed : 1;\n\n                    //\n                    // Hypervisor-assisted QPC conversion.\n                    //\n                    volatile UCHAR HypervisorAssist : 1;\n\n                    //\n                    // Reserved/unused\n                    //\n                    volatile UCHAR Reserved_2_3 : 2;\n\n                    //\n                    // MFENCE before RDTSC in relevant paths.\n                    //\n                    volatile UCHAR UseMfence : 1;\n\n                    //\n                    // LFENCE before RDTSC in relevant paths.\n                    //\n                    volatile UCHAR UseLfence : 1;\n\n                    //\n                    // Reserved/unused\n                    //\n                    volatile UCHAR Reserved_6 : 1;\n\n                    //\n                    // RDTSCP instead of RDTSC in the fast path.\n                    //\n                    volatile UCHAR UseRdtscp : 1;\n                };\n            };\n\n            //\n            // Reserved, leave as zero for backward compatibility. Was shift\n            // applied to the raw counter value to derive QPC count.\n            //\n\n            UCHAR QpcReserved;\n        };\n    };\n\n    //\n    // Reserved for future use.\n    //\n\n    LARGE_INTEGER TimeZoneBiasEffectiveStart;\n    LARGE_INTEGER TimeZoneBiasEffectiveEnd;\n\n    //\n    // Extended processor state configuration (AMD64 and x86).\n    //\n\n    XSTATE_CONFIGURATION XState;\n\n    //\n    // RtlQueryFeatureConfigurationChangeStamp\n    //\n\n    KSYSTEM_TIME FeatureConfigurationChangeStamp;\n\n    //\n    // Spare (available for re-use).\n    //\n\n    ULONG Spare;\n\n    //\n    // This field holds a mask that is used in the process of authenticating pointers in user mode.\n    // It helps in determining which bits of the pointer are used for authentication in user mode.\n    //\n\n    ULONG64 UserPointerAuthMask;\n\n    //\n    // Extended processor state configuration (ARM64). The reserved space for\n    // other architectures is not available for reuse.\n    //\n\n#if defined(_ARM64_)\n    XSTATE_CONFIGURATION XStateArm64;\n#else\n    ULONG Reserved10[210];\n#endif\n} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;\n\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountLowDeprecated)               == 0x000, \"KUSER_SHARED_DATA.TickCountLowDeprecated offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountMultiplier)                  == 0x004, \"KUSER_SHARED_DATA.TickCountMultiplier offset is incorrect\");\nstatic_assert(__alignof(KSYSTEM_TIME)                                               == 0X004, \"KSYSTEM_TIME alignment is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime)                        == 0x008, \"KUSER_SHARED_DATA.InterruptTime offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SystemTime)                           == 0x014, \"KUSER_SHARED_DATA.SystemTime offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneBias)                         == 0x020, \"KUSER_SHARED_DATA.TimeZoneBias offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ImageNumberLow)                       == 0x02c, \"KUSER_SHARED_DATA.ImageNumberLow offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ImageNumberHigh)                      == 0x02e, \"KUSER_SHARED_DATA.ImageNumberHigh offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NtSystemRoot)                         == 0x030, \"KUSER_SHARED_DATA.NtSystemRoot offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, MaxStackTraceDepth)                   == 0x238, \"KUSER_SHARED_DATA.MaxStackTraceDepth offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, CryptoExponent)                       == 0x23c, \"KUSER_SHARED_DATA.CryptoExponent offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneId)                           == 0x240, \"KUSER_SHARED_DATA.TimeZoneId offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, LargePageMinimum)                     == 0x244, \"KUSER_SHARED_DATA.LargePageMinimum offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, AitSamplingValue)                     == 0x248, \"KUSER_SHARED_DATA.AitSamplingValue offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, AppCompatFlag)                        == 0x24c, \"KUSER_SHARED_DATA.AppCompatFlag offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, RNGSeedVersion)                       == 0x250, \"KUSER_SHARED_DATA.RNGSeedVersion offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, GlobalValidationRunlevel)             == 0x258, \"KUSER_SHARED_DATA.GlobalValidationRunlevel offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneBiasStamp)                    == 0x25c, \"KUSER_SHARED_DATA.TimeZoneBiasStamp offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NtBuildNumber)                        == 0x260, \"KUSER_SHARED_DATA.NtBuildNumber offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NtProductType)                        == 0x264, \"KUSER_SHARED_DATA.NtProductType offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ProductTypeIsValid)                   == 0x268, \"KUSER_SHARED_DATA.ProductTypeIsValid offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NativeProcessorArchitecture)          == 0x26a, \"KUSER_SHARED_DATA.NativeProcessorArchitecture offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NtMajorVersion)                       == 0x26c, \"KUSER_SHARED_DATA.NtMajorVersion offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NtMinorVersion)                       == 0x270, \"KUSER_SHARED_DATA.NtMinorVersion offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ProcessorFeatures)                    == 0x274, \"KUSER_SHARED_DATA.ProcessorFeatures offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, MaximumUserModeAddressDeprecated)     == 0x2b4, \"KUSER_SHARED_DATA.MaximumUserModeAddressDeprecated offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SystemRangeStartDeprecated)           == 0x2b8, \"KUSER_SHARED_DATA.SystemRangeStartDeprecated offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeSlip)                             == 0x2bc, \"KUSER_SHARED_DATA.TimeSlip offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, AlternativeArchitecture)              == 0x2c0, \"KUSER_SHARED_DATA.AlternativeArchitecture offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SystemExpirationDate)                 == 0x2c8, \"KUSER_SHARED_DATA.SystemExpirationDate offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SuiteMask)                            == 0x2d0, \"KUSER_SHARED_DATA.SuiteMask offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, KdDebuggerEnabled)                    == 0x2d4, \"KUSER_SHARED_DATA.KdDebuggerEnabled offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, MitigationPolicies)                   == 0x2d5, \"KUSER_SHARED_DATA.MitigationPolicies offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, CyclesPerYield)                       == 0x2d6, \"KUSER_SHARED_DATA.CyclesPerYield offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ActiveConsoleId)                      == 0x2d8, \"KUSER_SHARED_DATA.ActiveConsoleId offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, DismountCount)                        == 0x2dc, \"KUSER_SHARED_DATA.DismountCount offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ComPlusPackage)                       == 0x2e0, \"KUSER_SHARED_DATA.ComPlusPackage offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, LastSystemRITEventTickCount)          == 0x2e4, \"KUSER_SHARED_DATA.LastSystemRITEventTickCount offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NumberOfPhysicalPages)                == 0x2e8, \"KUSER_SHARED_DATA.NumberOfPhysicalPages offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SafeBootMode)                         == 0x2ec, \"KUSER_SHARED_DATA.SafeBootMode offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, VirtualizationFlags)                  == 0x2ed, \"KUSER_SHARED_DATA.VirtualizationFlags offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved12)                           == 0x2ee, \"KUSER_SHARED_DATA.Reserved12 offset is incorrect\");\n#if defined(_MSC_EXTENSIONS)\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SharedDataFlags)                      == 0x2f0, \"KUSER_SHARED_DATA.SharedDataFlags offset is incorrect\");\n#endif\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TestRetInstruction)                   == 0x2f8, \"KUSER_SHARED_DATA.TestRetInstruction offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, QpcFrequency)                         == 0x300, \"KUSER_SHARED_DATA.QpcFrequency offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SystemCall)                           == 0x308, \"KUSER_SHARED_DATA.SystemCall offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved2)                            == 0x30c, \"KUSER_SHARED_DATA.Reserved2 offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SystemCallPad)                        == 0x318, \"KUSER_SHARED_DATA.SystemCallPad offset is incorrect (previously 0x310)\");\n#if defined(_MSC_EXTENSIONS)\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TickCount)                            == 0x320, \"KUSER_SHARED_DATA.TickCount offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountQuad)                        == 0x320, \"KUSER_SHARED_DATA.TickCountQuad offset is incorrect\");\n#endif\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, Cookie)                               == 0x330, \"KUSER_SHARED_DATA.Cookie offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ConsoleSessionForegroundProcessId)    == 0x338, \"KUSER_SHARED_DATA.ConsoleSessionForegroundProcessId offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeUpdateLock)                       == 0x340, \"KUSER_SHARED_DATA.TimeUpdateLock offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, BaselineSystemTimeQpc)                == 0x348, \"KUSER_SHARED_DATA.BaselineSystemTimeQpc offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, BaselineInterruptTimeQpc)             == 0x350, \"KUSER_SHARED_DATA.BaselineInterruptTimeQpc offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, QpcSystemTimeIncrement)               == 0x358, \"KUSER_SHARED_DATA.QpcSystemTimeIncrement offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, QpcInterruptTimeIncrement)            == 0x360, \"KUSER_SHARED_DATA.QpcInterruptTimeIncrement offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, QpcSystemTimeIncrementShift)          == 0x368, \"KUSER_SHARED_DATA.QpcSystemTimeIncrementShift offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, QpcInterruptTimeIncrementShift)       == 0x369, \"KUSER_SHARED_DATA.QpcInterruptTimeIncrementShift offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, UnparkedProcessorCount)               == 0x36a, \"KUSER_SHARED_DATA.UnparkedProcessorCount offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, EnclaveFeatureMask)                   == 0x36c, \"KUSER_SHARED_DATA.EnclaveFeatureMask offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TelemetryCoverageRound)               == 0x37c, \"KUSER_SHARED_DATA.TelemetryCoverageRound offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, UserModeGlobalLogger)                 == 0x380, \"KUSER_SHARED_DATA.UserModeGlobalLogger offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ImageFileExecutionOptions)            == 0x3a0, \"KUSER_SHARED_DATA.ImageFileExecutionOptions offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, LangGenerationCount)                  == 0x3a4, \"KUSER_SHARED_DATA.LangGenerationCount offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved4)                            == 0x3a8, \"KUSER_SHARED_DATA.Reserved4 offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTimeBias)                    == 0x3b0, \"KUSER_SHARED_DATA.InterruptTimeBias offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, QpcBias)                              == 0x3b8, \"KUSER_SHARED_DATA.QpcBias offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ActiveProcessorCount)                 == 0x3c0, \"KUSER_SHARED_DATA.ActiveProcessorCount offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ActiveGroupCount)                     == 0x3c4, \"KUSER_SHARED_DATA.ActiveGroupCount offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved9)                            == 0x3c5, \"KUSER_SHARED_DATA.Reserved9 offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, QpcData)                              == 0x3c6, \"KUSER_SHARED_DATA.QpcData offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, QpcBypassEnabled)                     == 0x3c6, \"KUSER_SHARED_DATA.QpcBypassEnabled offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, QpcReserved)                          == 0x3c7, \"KUSER_SHARED_DATA.QpcReserved offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneBiasEffectiveStart)           == 0x3c8, \"KUSER_SHARED_DATA.TimeZoneBiasEffectiveStart offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneBiasEffectiveEnd)             == 0x3d0, \"KUSER_SHARED_DATA.TimeZoneBiasEffectiveEnd offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, XState)                               == 0x3d8, \"KUSER_SHARED_DATA.XState offset is incorrect\");\n#if !defined(NTDDI_WIN10_FE) || (NTDDI_VERSION < NTDDI_WIN10_FE)\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, FeatureConfigurationChangeStamp)      == 0x710, \"KUSER_SHARED_DATA.FeatureConfigurationChangeStamp offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, UserPointerAuthMask)                  == 0x720, \"KUSER_SHARED_DATA.UserPointerAuthMask offset is incorrect\");\n#if defined(_ARM64_)\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, XStateArm64)                          == 0x728, \"KUSER_SHARED_DATA.XStateArm64 offset is incorrect\");\n#else\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved10)                           == 0x728, \"KUSER_SHARED_DATA.Reserved10 offset is incorrect\");\n#endif\n#if !defined(WINDOWS_IGNORE_PACKING_MISMATCH)\nstatic_assert(sizeof(KUSER_SHARED_DATA)                                             == 0xa70, \"KUSER_SHARED_DATA size is incorrect (expected 0xa70)\");\n#endif\n#else\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, FeatureConfigurationChangeStamp)      == 0x720, \"KUSER_SHARED_DATA.FeatureConfigurationChangeStamp offset is incorrect\");\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, UserPointerAuthMask)                  == 0x730, \"KUSER_SHARED_DATA.UserPointerAuthMask offset is incorrect\");\n#if defined(_ARM64_)\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, XStateArm64)                          == 0x738, \"KUSER_SHARED_DATA.XStateArm64 offset is incorrect\");\n#else\nstatic_assert(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved10)                           == 0x738, \"KUSER_SHARED_DATA.Reserved10 offset is incorrect\");\n#endif\n#if !defined(WINDOWS_IGNORE_PACKING_MISMATCH)\nstatic_assert(sizeof(KUSER_SHARED_DATA)                                             == 0xa80, \"KUSER_SHARED_DATA size is incorrect (expected 0xa80)\");\n#endif\n#endif\n\n/**\n * USER_SHARED_DATA pointer to the Windows KUSER_SHARED_DATA structure at its fixed\n * user-mode mapping address (0x7FFE0000).\n *\n * The Windows kernel exposes a read-only data structure, mapped into every user-mode\n * process at the fixed virtual address `0x7FFE0000`. This region contains frequently\n * accessed system information and avoids the overhead of system calls for data that\n * the kernel updates frequently. The mapping is always present and identical across\n * all user processes, it provides a fast and efficient way to retrieve system state.\n */\n#define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)0x7ffe0000)\n\n/**\n * The NtGetTickCount64 routine retrieves the number of milliseconds that have elapsed since the system was started.\n *\n * \\return ULONGLONG The return value is the number of milliseconds that have elapsed since the system was started.\n * \\remarks The resolution of the NtGetTickCount64 function is limited to the resolution of the system timer,\n * which is typically in the range of 10 milliseconds to 16 milliseconds. The resolution of the NtGetTickCount64\n * function is not affected by adjustments made by the GetSystemTimeAdjustment function.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount64\n */\nFORCEINLINE\nULONGLONG\nNtGetTickCount64(\n    VOID\n    )\n{\n    ULARGE_INTEGER tickCount;\n\n#ifdef _WIN64\n\n    tickCount.QuadPart = USER_SHARED_DATA->TickCountQuad;\n\n#else\n\n    while (TRUE)\n    {\n        tickCount.HighPart = (ULONG)USER_SHARED_DATA->TickCount.High1Time;\n        tickCount.LowPart = USER_SHARED_DATA->TickCount.LowPart;\n\n        if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time)\n            break;\n\n        YieldProcessor();\n    }\n\n#endif\n\n    return (UInt32x32To64(tickCount.LowPart, USER_SHARED_DATA->TickCountMultiplier) >> 24) +\n        (UInt32x32To64(tickCount.HighPart, USER_SHARED_DATA->TickCountMultiplier) << 8);\n}\n\n/**\n * The NtGetTickCount routine retrieves the number of milliseconds that have elapsed since the system was started, up to 49.7 days.\n *\n * \\return ULONG The return value is the number of milliseconds that have elapsed since the system was started.\n * \\remarks The elapsed time is stored as a ULONG value. Therefore, the time will wrap around to zero if the system\n * is run continuously for 49.7 days. To avoid this problem, use the NtGetTickCount64 function. Otherwise, check\n * for an overflow condition when comparing times. The resolution of the NtGetTickCount function is limited to\n * the resolution of the system timer, which is typically in the range of 10 milliseconds to 16 milliseconds.\n * The resolution of the NtGetTickCount function is not affected by adjustments made by the GetSystemTimeAdjustment function.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount\n */\nFORCEINLINE\nULONG\nNtGetTickCount(\n    VOID\n    )\n{\n#ifdef _WIN64\n\n    return (ULONG)((USER_SHARED_DATA->TickCountQuad * USER_SHARED_DATA->TickCountMultiplier) >> 24);\n\n#else\n\n    ULARGE_INTEGER tickCount;\n\n    while (TRUE)\n    {\n        tickCount.HighPart = (ULONG)USER_SHARED_DATA->TickCount.High1Time;\n        tickCount.LowPart = USER_SHARED_DATA->TickCount.LowPart;\n\n        if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time)\n            break;\n\n        YieldProcessor();\n    }\n\n    return (ULONG)((UInt32x32To64(tickCount.LowPart, USER_SHARED_DATA->TickCountMultiplier) >> 24) +\n        UInt32x32To64((tickCount.HighPart << 8) & 0xffffffff, USER_SHARED_DATA->TickCountMultiplier));\n\n#endif\n}\n\n//\n// Locale\n//\n\n/**\n * The NtQueryDefaultLocale routine retrieves the default locale identifier for either the user profile or the system.\n *\n * \\param UserProfile If TRUE, retrieves the user default locale; otherwise, retrieves the system default locale.\n * \\param DefaultLocaleId A pointer that receives the resulting locale identifier (LCID).\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocale\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserdefaultlocale\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDefaultLocale(\n    _In_ BOOLEAN UserProfile,\n    _Out_ PLCID DefaultLocaleId\n    );\n\n/**\n * The NtSetDefaultLocale routine sets the default locale identifier for either\n * the user profile or the system.\n *\n * \\param UserProfile If TRUE, sets the user default locale; otherwise, sets the system default locale.\n * \\param DefaultLocaleId The locale identifier (LCID) to set.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-setthreadlocale\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDefaultLocale(\n    _In_ BOOLEAN UserProfile,\n    _In_ LCID DefaultLocaleId\n    );\n\n/**\n * The NtQueryInstallUILanguage routine retrieves the system's installed UI language identifier.\n *\n * \\param InstallUILanguageId A pointer that receives the installed UI language identifier (LANGID).\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultuilanguage\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInstallUILanguage(\n    _Out_ LANGID *InstallUILanguageId\n    );\n\n/**\n * The NtFlushInstallUILanguage routine updates the system's installed UI\n * language and optionally commits the change.\n *\n * \\param InstallUILanguage The UI language identifier (LANGID) to set.\n * \\param SetComittedFlag If nonzero, commits the language change.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushInstallUILanguage(\n    _In_ LANGID InstallUILanguage,\n    _In_ ULONG SetComittedFlag\n    );\n\n/**\n * The NtQueryDefaultUILanguage routine retrieves the system's default UI language identifier.\n *\n * \\param DefaultUILanguageId A pointer that receives the default UI language identifier (LANGID).\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultuilanguage\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDefaultUILanguage(\n    _Out_ LANGID *DefaultUILanguageId\n    );\n\n/**\n * The NtSetDefaultUILanguage routine sets the system's default UI language identifier.\n *\n * \\param DefaultUILanguageId The UI language identifier (LANGID) to set.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDefaultUILanguage(\n    _In_ LANGID DefaultUILanguageId\n    );\n\n/**\n * The NtIsUILanguageComitted routine determines whether the system UI language has been committed.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtIsUILanguageComitted(\n    VOID\n    );\n\n//\n// NLS\n//\n\n// begin_private\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtInitializeNlsFiles(\n    _Out_ PVOID *BaseAddress,\n    _Out_ PLCID DefaultLocaleId,\n    _Out_ PLARGE_INTEGER DefaultCasingTableSize,\n    _Out_opt_ PULONG CurrentNLSVersion\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetNlsSectionPtr(\n    _In_ ULONG SectionType,\n    _In_ ULONG SectionData,\n    _In_ PVOID ContextData,\n    _Out_ PVOID *SectionPointer,\n    _Out_ PULONG SectionSize\n    );\n\n#if (PHNT_VERSION < PHNT_WINDOWS_7)\n/**\n * The NtAcquireCMFViewOwnership routine acquires ownership of the Code Map\n * File (CMF) view and optionally replaces an existing ownership token.\n *\n * \\param TimeStamp A pointer that receives the timestamp associated with the\n * CMF view ownership.\n * \\param tokenTaken A pointer that receives TRUE if the caller successfully\n * acquired the ownership token, or FALSE if another owner already held it.\n * \\param replaceExisting If TRUE, replaces any existing ownership token.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAcquireCMFViewOwnership(\n    _Out_ PULONGLONG TimeStamp,\n    _Out_ PBOOLEAN tokenTaken,\n    _In_ BOOLEAN replaceExisting\n    );\n\n/**\n * The NtReleaseCMFViewOwnership routine releases ownership of the Code Map\n * File (CMF) view previously acquired by NtAcquireCMFViewOwnership.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseCMFViewOwnership(\n    VOID\n    );\n#endif // PHNT_VERSION < PHNT_WINDOWS_7\n\n/**\n * The `What` flags for NtMapCMFModule.\n * The `What` parameter is a bitfield controlling:\n *   - Which CMF section to map\n *   - Access rights for CMFCheckAccess()\n *   - Whether to update CMF global flags\n *   - Page protection mode\n *   - CMF cache mode bits (propagate into CMFFlagsCache)\n *\n * These determine what access rights are checked and influence whether the mapping is allowed.\n */\n#define CMF_ACCESS_DIRECTORY 0x00000002     // Access check for directory section.\n#define CMF_ACCESS_SEGMENT 0x00000004       // Access check for segment section.\n#define CMF_ACCESS_HITS 0x00000008          // Access check for hits section.\n/**\n * The `What` flags for NtMapCMFModule.\n * These determine which CMF section is mapped and directly control the BaseAddress and ViewSizeOut outputs.\n */\n#define CMF_OP_DIRECTORY 0x00000010 // Map directory section (Index ignored) // Affects: BaseAddress, ViewSizeOut\n#define CMF_OP_SEGMENT 0x00000020   // Map segment section at Index // Affects: BaseAddress, ViewSizeOut\n#define CMF_OP_HITS 0x00000100      // Map hits section (Index ignored) // Affects: BaseAddress, ViewSizeOut\n/**\n * The `What` flags for NtMapCMFModule.\n * This affects the protection flags passed to MmMapViewOfSection,\n * which ultimately influences the memory protections of the BaseAddress parameter.\n */\n#define CMF_PROTECT_SPECIAL 0x00000040      // Changes protection from PAGE_READONLY to PAGE_WRITECOPY\n/**\n * The `What` flags for NtMapCMFModule.\n * When this bit is set, the function does not map anything.\n * Instead, it updates CMFFlagsCache and optionally modifies the directory header.\n */\n#define CMF_UPDATE_FLAGS 0x00020000      // Enter flag-update mode // CacheFlagsOut parameter\n/**\n * The `What` flags for NtMapCMFModule.\n * These bits are extracted from What and written into CMFFlagsCache.\n * They determine global CMF behavior, including which modules are valid.\n */\n#define CMF_FLAG_A 0x00040000 // May trigger directory header update\n#define CMF_FLAG_B 0x00080000 // Enables directory update path\n#define CMF_FLAG_C 0x00100000 // Enables segment unmap path\n/**\n * Flags for NtMapCMFModule.\n * These bits strip all bits outside this mask:\n */\n#define CMF_ALLOWED_MASK 0xFFFFFECF // All valid bits for What\n/**\n * Flags for NtMapCMFModule.\n */\ntypedef enum _CMF_WHAT_FLAGS\n{\n    // ---- Access rights (used by CMFCheckAccess) ----\n    CmfAccessDirectory = 0x00000002, // Access check for directory\n    CmfAccessSegment = 0x00000004, // Access check for segment[Index]\n    CmfAccessHits = 0x00000008, // Access check for hits\n    // ---- Operation selection (controls BaseAddress + ViewSizeOut) ----\n    CmfDirectoryOp = 0x00000010, // Map directory section\n    CmfSegmentOp = 0x00000020, // Map segment section at Index\n    CmfHitsOp = 0x00000100, // Map hits section\n    // ---- Memory protection modifier ----\n    CmfSpecialProtect = 0x00000040, // Changes protection for MmMapViewOfSection\n    // ---- Flag update mode (affects CacheFlagsOut only) ----\n    CmfUpdateFlags = 0x00020000, // Update CMFFlagsCache instead of mapping\n    // ---- CMF cache mode bits (propagate into CMFFlagsCache) ----\n    CmfFlagA = 0x00040000, // May trigger directory header update\n    CmfFlagB = 0x00080000, // Enables directory update path\n    CmfFlagC = 0x00100000, // Enables segment unmap path\n} CMF_WHAT_FLAGS;\nDEFINE_ENUM_FLAG_OPERATORS(CMF_WHAT_FLAGS);\n\n/**\n * The NtMapCMFModule routine maps a Code Map File (CMF) module into memory\n * and returns information about the cached view.\n *\n * \\param What Specifies the CMF operation to perform.\n * \\param Index The module index to map. Only valid for CmfSegmentOp operations.\n * \\param CacheIndexOut Optional pointer that receives the cache index.\n * \\param CacheFlagsOut Optional pointer that receives cache flags.\n * \\param ViewSizeOut Optional pointer that receives the size of the mapped view.\n * \\param BaseAddress Optional pointer that receives the base address of the mapped module.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMapCMFModule(\n    _In_ ULONG What,\n    _In_ ULONG Index,\n    _Out_opt_ PULONG CacheIndexOut,\n    _Out_opt_ PULONG CacheFlagsOut,\n    _Out_opt_ PULONG ViewSizeOut,\n    _Out_opt_ PVOID *BaseAddress\n    );\n\n/**\n * Flags for NtGetMUIRegistryInfo.\n * Only the values below are supported. Any other bit results in STATUS_INVALID_PARAMETER.\n */\ntypedef enum _MUI_REGISTRY_INFO_FLAGS\n{\n    MUIRegInfoQuery = 0x1,      // Query or load the MUI registry info.\n    MUIRegInfoClear = 0x2,      // Clear the cached MUI registry info.\n    MUIRegInfoCommit = 0x8      // Commit/update state (increments counter).\n} MUI_REGISTRY_INFO_FLAGS;\nDEFINE_ENUM_FLAG_OPERATORS(MUI_REGISTRY_INFO_FLAGS);\n\n/**\n * Flags for NtGetMUIRegistryInfo.\n * Only the values below are supported. Any other bit results in STATUS_INVALID_PARAMETER.\n */\n#define MUI_REGINFO_QUERY 0x1   // Query or load the MUI registry info.\n#define MUI_REGINFO_CLEAR 0x2   // Clear the cached MUI registry info.\n#define MUI_REGINFO_COMMIT 0x8  // Commit/update state (increments counter).\n\n/**\n * The NtGetMUIRegistryInfo routine retrieves Multilingual User Interface (MUI)\n * configuration data from the system registry.\n *\n * \\param Flags Flags that control the type of MUI information returned.\n * \\param DataSize On input, the size of the buffer pointed to by Data.\n * On output, the required or actual size of the data returned.\n * \\param Data A pointer to the MUI registry information.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This routine is private and subject to change.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetMUIRegistryInfo(\n    _In_ ULONG Flags,\n    _Inout_ PULONG DataSize,\n    _Out_ PVOID Data\n    );\n\n// end_private\n\n//\n// Global atoms\n//\n\n/**\n * The NtAddAtom routine adds a Unicode string to the system atom table and\n * returns the corresponding atom identifier.\n *\n * \\param AtomName A pointer to a Unicode string containing the atom name.\n * \\param Length The length, in bytes, of the string pointed to by AtomName.\n * \\param Atom An optional pointer that receives the resulting atom identifier.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks If the atom already exists, its reference count is incremented and\n * the existing atom identifier is returned.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-addatomw\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAddAtom(\n    _In_reads_bytes_opt_(Length) PCWSTR AtomName,\n    _In_ ULONG Length,\n    _Out_opt_ PRTL_ATOM Atom\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n/**\n * ATOM_FLAG_NONE indicates that the atom being created should be placed in\n * the session-local atom table rather than the global atom table.\n */\n#define ATOM_FLAG_NONE 0x0\n/**\n * ATOM_FLAG_GLOBAL indicates that the atom being created should be placed in\n * the global atom table rather than the session-local table.\n * \\remarks This flag is only valid starting with Windows 8 and later.\n */\n#define ATOM_FLAG_GLOBAL 0x2\n\n// rev\n/**\n * The NtAddAtomEx routine adds a Unicode string to the system atom table with\n * additional creation flags.\n *\n * \\param AtomName A pointer to a Unicode string containing the atom name.\n * \\param Length The length, in bytes, of the string pointed to by AtomName.\n * \\param Atom An optional pointer that receives the resulting atom identifier.\n * \\param Flags A set of flags that control atom creation behavior.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks ATOM_FLAG_GLOBAL may be used to create a global atom.\n * Only ATOM_FLAG_GLOBAL and ATOM_FLAG_NONE are currently supported.\n * Any other flag value results in STATUS_INVALID_PARAMETER.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-addatomw\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAddAtomEx(\n    _In_reads_bytes_opt_(Length) PCWSTR AtomName,\n    _In_ ULONG Length,\n    _Out_opt_ PRTL_ATOM Atom,\n    _In_ ULONG Flags\n    );\n\n#endif // PHNT_VERSION >= PHNT_WINDOWS_8\n\n/**\n * The NtFindAtom routine retrieves the atom identifier associated with a\n * Unicode string in the system atom table.\n *\n * \\param AtomName A pointer to a Unicode string containing the atom name.\n * \\param Length The length, in bytes, of the string pointed to by AtomName.\n * \\param Atom An optional pointer that receives the atom identifier if found.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-findatomw\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFindAtom(\n    _In_reads_bytes_opt_(Length) PCWSTR AtomName,\n    _In_ ULONG Length,\n    _Out_opt_ PRTL_ATOM Atom\n    );\n\n/**\n * The NtDeleteAtom routine decrements the reference count of an atom and\n * removes it from the system atom table when the count reaches zero.\n *\n * \\param Atom The atom identifier to delete.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks If the atom is still referenced elsewhere, it is not removed until\n * its reference count reaches zero.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-deleteatom\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteAtom(\n    _In_ RTL_ATOM Atom\n    );\n\n/**\n * The ATOM_INFORMATION_CLASS enumeration specifies the type of information\n * returned when querying atom table data.\n */\ntypedef enum _ATOM_INFORMATION_CLASS\n{\n    AtomBasicInformation,\n    AtomTableInformation\n} ATOM_INFORMATION_CLASS;\n\n/**\n * The ATOM_BASIC_INFORMATION structure contains basic information about an Atom.\n */\ntypedef struct _ATOM_BASIC_INFORMATION\n{\n    USHORT UsageCount;   // The number of times the atom is referenced.\n    USHORT Flags;        // Flags associated with the atom. */\n    USHORT NameLength;   // Length, in bytes, of the atom's name.\n    _Field_size_bytes_(NameLength) WCHAR Name[1]; // The atom's name (not null-terminated).\n} ATOM_BASIC_INFORMATION, *PATOM_BASIC_INFORMATION;\n\n/**\n * The ATOM_TABLE_INFORMATION structure contains information about all Atoms from the system atom table.\n */\ntypedef struct _ATOM_TABLE_INFORMATION\n{\n    ULONG NumberOfAtoms; // The number of atoms in the atom table.\n    _Field_size_(NumberOfAtoms) RTL_ATOM Atoms[1]; // Array of atom identifiers.\n} ATOM_TABLE_INFORMATION, *PATOM_TABLE_INFORMATION;\n\n/**\n * The NtQueryInformationAtom routine retrieves information about a specified atom in the system atom table.\n *\n * \\param Atom The atom identifier for which information is being queried.\n * \\param AtomInformationClass Specifies the type of information to retrieve. This is an ATOM_INFORMATION_CLASS value.\n * \\param AtomInformation A pointer to a buffer that receives the requested information.\n * \\param AtomInformationLength The size, in bytes, of the AtomInformation buffer.\n * \\param ReturnLength Optional pointer to a variable that receives the number of bytes written to the AtomInformation buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationAtom(\n    _In_ RTL_ATOM Atom,\n    _In_ ATOM_INFORMATION_CLASS AtomInformationClass,\n    _Out_writes_bytes_(AtomInformationLength) PVOID AtomInformation,\n    _In_ ULONG AtomInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n//\n// Global flags\n//\n\n#define FLG_STOP_ON_EXCEPTION 0x00000001 // uk\n#define FLG_SHOW_LDR_SNAPS 0x00000002 // uk\n#define FLG_DEBUG_INITIAL_COMMAND 0x00000004 // k\n#define FLG_STOP_ON_HUNG_GUI 0x00000008 // k\n#define FLG_HEAP_ENABLE_TAIL_CHECK 0x00000010 // u\n#define FLG_HEAP_ENABLE_FREE_CHECK 0x00000020 // u\n#define FLG_HEAP_VALIDATE_PARAMETERS 0x00000040 // u\n#define FLG_HEAP_VALIDATE_ALL 0x00000080 // u\n#define FLG_APPLICATION_VERIFIER 0x00000100 // u\n#define FLG_MONITOR_SILENT_PROCESS_EXIT 0x00000200 // uk\n#define FLG_POOL_ENABLE_TAGGING 0x00000400 // k\n#define FLG_HEAP_ENABLE_TAGGING 0x00000800 // u\n#define FLG_USER_STACK_TRACE_DB 0x00001000 // u,32\n#define FLG_KERNEL_STACK_TRACE_DB 0x00002000 // k,32\n#define FLG_MAINTAIN_OBJECT_TYPELIST 0x00004000 // k\n#define FLG_HEAP_ENABLE_TAG_BY_DLL 0x00008000 // u\n#define FLG_DISABLE_STACK_EXTENSION 0x00010000 // u\n#define FLG_ENABLE_CSRDEBUG 0x00020000 // k\n#define FLG_ENABLE_KDEBUG_SYMBOL_LOAD 0x00040000 // k\n#define FLG_DISABLE_PAGE_KERNEL_STACKS 0x00080000 // k\n#define FLG_ENABLE_SYSTEM_CRIT_BREAKS 0x00100000 // u\n#define FLG_HEAP_DISABLE_COALESCING 0x00200000 // u\n#define FLG_ENABLE_CLOSE_EXCEPTIONS 0x00400000 // k\n#define FLG_ENABLE_EXCEPTION_LOGGING 0x00800000 // k\n#define FLG_ENABLE_HANDLE_TYPE_TAGGING 0x01000000 // k\n#define FLG_HEAP_PAGE_ALLOCS 0x02000000 // u\n#define FLG_DEBUG_INITIAL_COMMAND_EX 0x04000000 // k\n#define FLG_DISABLE_DBGPRINT 0x08000000 // k\n#define FLG_CRITSEC_EVENT_CREATION 0x10000000 // u\n#define FLG_LDR_TOP_DOWN 0x20000000 // u,64\n#define FLG_ENABLE_HANDLE_EXCEPTIONS 0x40000000 // k\n#define FLG_DISABLE_PROTDLLS 0x80000000 // u\n#define FLG_VALID_BITS 0xfffffdff\n\n#define FLG_USERMODE_VALID_BITS (FLG_STOP_ON_EXCEPTION | \\\n    FLG_SHOW_LDR_SNAPS | \\\n    FLG_HEAP_ENABLE_TAIL_CHECK | \\\n    FLG_HEAP_ENABLE_FREE_CHECK | \\\n    FLG_HEAP_VALIDATE_PARAMETERS | \\\n    FLG_HEAP_VALIDATE_ALL | \\\n    FLG_APPLICATION_VERIFIER | \\\n    FLG_HEAP_ENABLE_TAGGING | \\\n    FLG_USER_STACK_TRACE_DB | \\\n    FLG_HEAP_ENABLE_TAG_BY_DLL | \\\n    FLG_DISABLE_STACK_EXTENSION | \\\n    FLG_ENABLE_SYSTEM_CRIT_BREAKS | \\\n    FLG_HEAP_DISABLE_COALESCING | \\\n    FLG_DISABLE_PROTDLLS | \\\n    FLG_HEAP_PAGE_ALLOCS | \\\n    FLG_CRITSEC_EVENT_CREATION | \\\n    FLG_LDR_TOP_DOWN)\n\n#define FLG_BOOTONLY_VALID_BITS (FLG_KERNEL_STACK_TRACE_DB | \\\n    FLG_MAINTAIN_OBJECT_TYPELIST | \\\n    FLG_ENABLE_CSRDEBUG | \\\n    FLG_DEBUG_INITIAL_COMMAND | \\\n    FLG_DEBUG_INITIAL_COMMAND_EX | \\\n    FLG_DISABLE_PAGE_KERNEL_STACKS)\n\n#define FLG_KERNELMODE_VALID_BITS (FLG_STOP_ON_EXCEPTION | \\\n    FLG_SHOW_LDR_SNAPS | \\\n    FLG_STOP_ON_HUNG_GUI | \\\n    FLG_POOL_ENABLE_TAGGING | \\\n    FLG_ENABLE_KDEBUG_SYMBOL_LOAD | \\\n    FLG_ENABLE_CLOSE_EXCEPTIONS | \\\n    FLG_ENABLE_EXCEPTION_LOGGING | \\\n    FLG_ENABLE_HANDLE_TYPE_TAGGING | \\\n    FLG_DISABLE_DBGPRINT | \\\n    FLG_ENABLE_HANDLE_EXCEPTIONS)\n\n//\n// Licensing\n//\n\n/**\n * The NtQueryLicenseValue routine retrieves a licensing-related value from the\n * system licensing database.\n *\n * \\param ValueName A pointer to a UNICODE_STRING structure that contains the name of the license value to query.\n * \\param Type An optional pointer that receives the type of the returned data.\n * \\param Data An optional buffer that receives the value data.\n * \\param DataSize The size, in bytes, of the buffer pointed to by Data.\n * \\param ResultDataSize A pointer that receives the number of bytes required to store the complete value data.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/slpublic/nf-slpublic-slquerylicensevaluefromapp\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryLicenseValue(\n    _In_ PCUNICODE_STRING ValueName,\n    _Out_opt_ PULONG Type,\n    _Out_writes_bytes_to_opt_(DataSize, *ResultDataSize) PVOID Data,\n    _In_ ULONG DataSize,\n    _Out_ PULONG ResultDataSize\n    );\n\n//\n// Misc.\n//\n\n/**\n * The NtSetDefaultHardErrorPort routine sets the system's default hard error\n * port, which is used by the kernel to deliver hard error notifications to a\n * user-mode process.\n *\n * \\param DefaultHardErrorPort A handle to a port object that will receive\n * hard error messages generated by the system.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDefaultHardErrorPort(\n    _In_ HANDLE DefaultHardErrorPort\n    );\n\n/**\n * The SHUTDOWN_ACTION enumeration specifies the type of system shutdown to perform.\n */\ntypedef enum _SHUTDOWN_ACTION\n{\n    ShutdownNoReboot,\n    ShutdownReboot,\n    ShutdownPowerOff,\n    ShutdownRebootForRecovery // since WIN11\n} SHUTDOWN_ACTION;\n\n/**\n * The NtShutdownSystem routine initiates a system shutdown using the specified\n * shutdown action.\n *\n * \\param Action A SHUTDOWN_ACTION value that specifies whether the system\n * should halt, reboot, power off, or reboot for recovery.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The calling process must have the SE_SHUTDOWN_NAME privilege.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtShutdownSystem(\n    _In_ SHUTDOWN_ACTION Action\n    );\n\n/**\n * The NtDisplayString routine displays a Unicode string on the system display\n * during early boot or in environments where a console is not yet available.\n *\n * \\param String A pointer to a UNICODE_STRING structure that contains the text to display.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDisplayString(\n    _In_ PCUNICODE_STRING String\n    );\n\n//\n// Boot graphics\n//\n\n// rev\n/**\n * The NtDrawText routine displays a Unicode string on the system display during\n * early boot or in environments where a standard console is not yet available.\n *\n * \\param Text A pointer to a UNICODE_STRING structure that contains the text to draw on the screen.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDrawText(\n    _In_ PCUNICODE_STRING Text\n    );\n\n//\n// Hot patching\n//\n\ntypedef enum _HOT_PATCH_INFORMATION_CLASS\n{\n    ManageHotPatchLoadPatch = 0, // MANAGE_HOT_PATCH_LOAD_PATCH\n    ManageHotPatchUnloadPatch = 1, // MANAGE_HOT_PATCH_UNLOAD_PATCH\n    ManageHotPatchQueryPatches = 2, // MANAGE_HOT_PATCH_QUERY_PATCHES\n    ManageHotPatchLoadPatchForUser = 3, // MANAGE_HOT_PATCH_LOAD_PATCH\n    ManageHotPatchUnloadPatchForUser = 4, // MANAGE_HOT_PATCH_UNLOAD_PATCH\n    ManageHotPatchQueryPatchesForUser = 5, // MANAGE_HOT_PATCH_QUERY_PATCHES\n    ManageHotPatchQueryActivePatches = 6, // MANAGE_HOT_PATCH_QUERY_ACTIVE_PATCHES\n    ManageHotPatchApplyImagePatch = 7, // MANAGE_HOT_PATCH_APPLY_IMAGE_PATCH\n    ManageHotPatchQuerySinglePatch = 8, // MANAGE_HOT_PATCH_QUERY_SINGLE_PATCH\n    ManageHotPatchCheckEnabled = 9, // MANAGE_HOT_PATCH_CHECK_ENABLED\n    ManageHotPatchCreatePatchSection = 10, // MANAGE_HOT_PATCH_CREATE_PATCH_SECTION\n    ManageHotPatchMax\n} HOT_PATCH_INFORMATION_CLASS;\n\n/**\n * The HOT_PATCH_IMAGE_INFO structure contains identifying information about a hot patch image.\n */\ntypedef struct _HOT_PATCH_IMAGE_INFO\n{\n    ULONG CheckSum;             // The checksum of the hot patch image.\n    ULONG TimeDateStamp;        // The time/date stamp of the hot patch image.\n} HOT_PATCH_IMAGE_INFO, *PHOT_PATCH_IMAGE_INFO;\n\n#define MANAGE_HOT_PATCH_LOAD_PATCH_VERSION 1\n\n/**\n * The MANAGE_HOT_PATCH_LOAD_PATCH structure describes parameters for loading a hot patch.\n */\ntypedef struct _MANAGE_HOT_PATCH_LOAD_PATCH\n{\n    ULONG Version;                              // Structure version. Must be MANAGE_HOT_PATCH_LOAD_PATCH_VERSION.\n    UNICODE_STRING PatchPath;                   // The path to the hot patch file.\n    union\n    {\n        SID Sid;                                // The SID of the user for whom the patch is being loaded.\n        UCHAR Buffer[SECURITY_MAX_SID_SIZE];    // Buffer for the SID.\n    } UserSid;\n    HOT_PATCH_IMAGE_INFO BaseInfo;              // Identifying information about the base image to patch.\n} MANAGE_HOT_PATCH_LOAD_PATCH, *PMANAGE_HOT_PATCH_LOAD_PATCH;\n\n#define MANAGE_HOT_PATCH_UNLOAD_PATCH_VERSION 1\n\n/**\n * The MANAGE_HOT_PATCH_UNLOAD_PATCH structure describes parameters for unloading a hot patch.\n */\ntypedef struct _MANAGE_HOT_PATCH_UNLOAD_PATCH\n{\n    ULONG Version;                  // Structure version. Must be MANAGE_HOT_PATCH_UNLOAD_PATCH_VERSION.\n    HOT_PATCH_IMAGE_INFO BaseInfo;  // Identifying information about the base image to unpatch.\n    union\n    {\n        SID Sid;                    // The SID of the user for whom the patch is being unloaded.\n        UCHAR Buffer[SECURITY_MAX_SID_SIZE]; // Buffer for the SID.\n    } UserSid;\n} MANAGE_HOT_PATCH_UNLOAD_PATCH, *PMANAGE_HOT_PATCH_UNLOAD_PATCH;\n\n#define MANAGE_HOT_PATCH_QUERY_PATCHES_VERSION 1\n\n/**\n * The MANAGE_HOT_PATCH_QUERY_PATCHES structure is used to query information about loaded hot patches.\n */\ntypedef struct _MANAGE_HOT_PATCH_QUERY_PATCHES\n{\n    ULONG Version;                           // Structure version. Must be MANAGE_HOT_PATCH_QUERY_PATCHES_VERSION.\n    union\n    {\n        SID Sid;                             // The SID of the user whose patches are being queried.\n        UCHAR Buffer[SECURITY_MAX_SID_SIZE]; // Buffer for the SID.\n    } UserSid;\n    ULONG PatchCount;                        // The number of patches found.\n    PUNICODE_STRING PatchPathStrings;        // Pointer to an array of patch path strings.\n    PHOT_PATCH_IMAGE_INFO BaseInfos;         // Pointer to an array of patch image info structures.\n} MANAGE_HOT_PATCH_QUERY_PATCHES, *PMANAGE_HOT_PATCH_QUERY_PATCHES;\n\n#define MANAGE_HOT_PATCH_QUERY_ACTIVE_PATCHES_VERSION 1\n\n/**\n * The MANAGE_HOT_PATCH_QUERY_ACTIVE_PATCHES structure is used to query active hot patches for a process.\n */\ntypedef struct _MANAGE_HOT_PATCH_QUERY_ACTIVE_PATCHES\n{\n    ULONG Version;                      // Structure version. Must be MANAGE_HOT_PATCH_QUERY_ACTIVE_PATCHES_VERSION.\n    HANDLE ProcessHandle;               // Handle to the process being queried.\n    ULONG PatchCount;                   // The number of active patches.\n    PUNICODE_STRING PatchPathStrings;   // Pointer to an array of patch path strings.\n    PHOT_PATCH_IMAGE_INFO BaseInfos;    // Pointer to an array of patch image info structures.\n    PULONG PatchSequenceNumbers;        // Pointer to an array of patch sequence numbers.\n} MANAGE_HOT_PATCH_QUERY_ACTIVE_PATCHES, *PMANAGE_HOT_PATCH_QUERY_ACTIVE_PATCHES;\n\n#define MANAGE_HOT_PATCH_APPLY_IMAGE_PATCH_VERSION 1\n\n/**\n * The MANAGE_HOT_PATCH_APPLY_IMAGE_PATCH structure describes parameters for applying a hot patch to an image.\n */\ntypedef struct _MANAGE_HOT_PATCH_APPLY_IMAGE_PATCH\n{\n    ULONG Version;                              // Structure version. Must be MANAGE_HOT_PATCH_APPLY_IMAGE_PATCH_VERSION.\n    union\n    {\n        ULONG AllFlags;                         // All flags as a ULONG.\n        struct\n        {\n            ULONG ApplyReversePatches : 1;      // If set, apply reverse patches.\n            ULONG ApplyForwardPatches : 1;      // If set, apply forward patches.\n            ULONG Spare : 29;\n        };\n    };\n    HANDLE ProcessHandle;                       // Handle to the process to patch.\n    PVOID BaseImageAddress;                     // Base address of the image to patch.\n    PVOID PatchImageAddress;                    // Address of the patch image.\n} MANAGE_HOT_PATCH_APPLY_IMAGE_PATCH, *PMANAGE_HOT_PATCH_APPLY_IMAGE_PATCH;\n\n#define MANAGE_HOT_PATCH_QUERY_SINGLE_PATCH_VERSION 1\n\n/**\n * The MANAGE_HOT_PATCH_QUERY_SINGLE_PATCH structure is used to query a single hot patch.\n */\ntypedef struct _MANAGE_HOT_PATCH_QUERY_SINGLE_PATCH\n{\n    ULONG Version;                  // Structure version. Must be MANAGE_HOT_PATCH_QUERY_SINGLE_PATCH_VERSION.\n    HANDLE ProcessHandle;           // Handle to the process being queried.\n    PVOID BaseAddress;              // Base address of the image being queried.\n    ULONG Flags;                    // Query flags.\n    UNICODE_STRING PatchPathString; // The path to the patch being queried.\n} MANAGE_HOT_PATCH_QUERY_SINGLE_PATCH, *PMANAGE_HOT_PATCH_QUERY_SINGLE_PATCH;\n\n#define MANAGE_HOT_PATCH_CHECK_ENABLED_VERSION 1\n\n/**\n * The MANAGE_HOT_PATCH_CHECK_ENABLED structure is used to check if hot patching is enabled.\n */\ntypedef struct _MANAGE_HOT_PATCH_CHECK_ENABLED\n{\n    ULONG Version;          // Structure version. Must be MANAGE_HOT_PATCH_CHECK_ENABLED_VERSION.\n    ULONG Flags;            // Flags for the check operation.\n} MANAGE_HOT_PATCH_CHECK_ENABLED, *PMANAGE_HOT_PATCH_CHECK_ENABLED;\n\n#define MANAGE_HOT_PATCH_CREATE_PATCH_SECTION_VERSION 1\n\n/**\n * The MANAGE_HOT_PATCH_CREATE_PATCH_SECTION structure describes parameters for creating a hot patch section.\n */\ntypedef struct _MANAGE_HOT_PATCH_CREATE_PATCH_SECTION\n{\n    ULONG Version;                  // Structure version. Must be MANAGE_HOT_PATCH_CREATE_PATCH_SECTION_VERSION.\n    ULONG Flags;                    // Creation flags.\n    ACCESS_MASK DesiredAccess;      // Desired access mask for the section.\n    ULONG PageProtection;           // Page protection flags.\n    ULONG AllocationAttributes;     // Allocation attributes.\n    PVOID BaseImageAddress;         // Base address of the image for the patch section.\n    HANDLE SectionHandle;           // Handle to the created section.\n} MANAGE_HOT_PATCH_CREATE_PATCH_SECTION, *PMANAGE_HOT_PATCH_CREATE_PATCH_SECTION;\n\n#if defined(_WIN64)\nstatic_assert(sizeof(MANAGE_HOT_PATCH_LOAD_PATCH) == 0x68, \"Size of MANAGE_HOT_PATCH_LOAD_PATCH is incorrect\");\nstatic_assert(sizeof(MANAGE_HOT_PATCH_UNLOAD_PATCH) == 0x50, \"Size of MANAGE_HOT_PATCH_UNLOAD_PATCH is incorrect\");\nstatic_assert(sizeof(MANAGE_HOT_PATCH_QUERY_PATCHES) == 0x60, \"Size of MANAGE_HOT_PATCH_QUERY_PATCHES is incorrect\");\nstatic_assert(sizeof(MANAGE_HOT_PATCH_QUERY_ACTIVE_PATCHES) == 0x30, \"Size of MANAGE_HOT_PATCH_QUERY_ACTIVE_PATCHES is incorrect\");\nstatic_assert(sizeof(MANAGE_HOT_PATCH_APPLY_IMAGE_PATCH) == 0x20, \"Size of MANAGE_HOT_PATCH_APPLY_IMAGE_PATCH is incorrect\");\nstatic_assert(sizeof(MANAGE_HOT_PATCH_QUERY_SINGLE_PATCH) == 0x30, \"Size of MANAGE_HOT_PATCH_QUERY_SINGLE_PATCH is incorrect\");\nstatic_assert(sizeof(MANAGE_HOT_PATCH_CHECK_ENABLED) == 0x8, \"Size of MANAGE_HOT_PATCH_CHECK_ENABLED is incorrect\");\nstatic_assert(sizeof(MANAGE_HOT_PATCH_CREATE_PATCH_SECTION) == 0x28, \"Size of MANAGE_HOT_PATCH_CREATE_PATCH_SECTION is incorrect\");\n#endif // WIN64\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\n// rev\n/**\n * The NtManageHotPatch routine manages hot patching operations in the system.\n *\n * \\param[in] HotPatchInformationClass Specifies the type of hot patch information being queried or set.\n * \\param[out] HotPatchInformation A pointer to a buffer that receives or contains the hot patch information, depending on the operation.\n * \\param[in] HotPatchInformationLength The size, in bytes, of the HotPatchInformation buffer.\n * \\param[out] ReturnLength Optional pointer to a variable that receives the number of bytes written to the HotPatchInformation buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtManageHotPatch(\n    _In_ HOT_PATCH_INFORMATION_CLASS HotPatchInformationClass,\n    _Out_writes_bytes_opt_(HotPatchInformationLength) PVOID HotPatchInformation,\n    _In_ ULONG HotPatchInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_11\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#endif // _NTEXAPI_H\n"
  },
  {
    "path": "phnt/include/ntgdi.h",
    "content": "/*\n * Graphics device interface support\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTGDI_H\n#define _NTGDI_H\n\n#define GDI_MAX_HANDLE_COUNT 0xFFFF // 0x4000\n\n#define GDI_HANDLE_INDEX_SHIFT 0\n#define GDI_HANDLE_INDEX_BITS 16\n#define GDI_HANDLE_INDEX_MASK 0xffff\n\n#define GDI_HANDLE_TYPE_SHIFT 16\n#define GDI_HANDLE_TYPE_BITS 5\n#define GDI_HANDLE_TYPE_MASK 0x1f\n\n#define GDI_HANDLE_ALTTYPE_SHIFT 21\n#define GDI_HANDLE_ALTTYPE_BITS 2\n#define GDI_HANDLE_ALTTYPE_MASK 0x3\n\n#define GDI_HANDLE_STOCK_SHIFT 23\n#define GDI_HANDLE_STOCK_BITS 1\n#define GDI_HANDLE_STOCK_MASK 0x1\n\n#define GDI_HANDLE_UNIQUE_SHIFT 24\n#define GDI_HANDLE_UNIQUE_BITS 8\n#define GDI_HANDLE_UNIQUE_MASK 0xff\n\n#define GDI_HANDLE_INDEX(Handle) ((ULONG)(Handle) & GDI_HANDLE_INDEX_MASK)\n#define GDI_HANDLE_TYPE(Handle) (((ULONG)(Handle) >> GDI_HANDLE_TYPE_SHIFT) & GDI_HANDLE_TYPE_MASK)\n#define GDI_HANDLE_ALTTYPE(Handle) (((ULONG)(Handle) >> GDI_HANDLE_ALTTYPE_SHIFT) & GDI_HANDLE_ALTTYPE_MASK)\n#define GDI_HANDLE_STOCK(Handle) (((ULONG)(Handle) >> GDI_HANDLE_STOCK_SHIFT)) & GDI_HANDLE_STOCK_MASK)\n\n#define GDI_MAKE_HANDLE(Index, Unique) ((ULONG)(((ULONG)(Unique) << GDI_HANDLE_INDEX_BITS) | (ULONG)(Index)))\n\n//\n// GDI server-side types\n//\n\n#define GDI_DEF_TYPE 0 // invalid handle\n#define GDI_DC_TYPE 1\n#define GDI_DD_DIRECTDRAW_TYPE 2\n#define GDI_DD_SURFACE_TYPE 3\n#define GDI_RGN_TYPE 4\n#define GDI_SURF_TYPE 5\n#define GDI_CLIENTOBJ_TYPE 6\n#define GDI_PATH_TYPE 7\n#define GDI_PAL_TYPE 8\n#define GDI_ICMLCS_TYPE 9\n#define GDI_LFONT_TYPE 10\n#define GDI_RFONT_TYPE 11\n#define GDI_PFE_TYPE 12\n#define GDI_PFT_TYPE 13\n#define GDI_ICMCXF_TYPE 14\n#define GDI_ICMDLL_TYPE 15\n#define GDI_BRUSH_TYPE 16\n#define GDI_PFF_TYPE 17 // unused\n#define GDI_CACHE_TYPE 18 // unused\n#define GDI_SPACE_TYPE 19\n#define GDI_DBRUSH_TYPE 20 // unused\n#define GDI_META_TYPE 21\n#define GDI_EFSTATE_TYPE 22\n#define GDI_BMFD_TYPE 23 // unused\n#define GDI_VTFD_TYPE 24 // unused\n#define GDI_TTFD_TYPE 25 // unused\n#define GDI_RC_TYPE 26 // unused\n#define GDI_TEMP_TYPE 27 // unused\n#define GDI_DRVOBJ_TYPE 28\n#define GDI_DCIOBJ_TYPE 29 // unused\n#define GDI_SPOOL_TYPE 30\n\n//\n// GDI client-side types\n//\n\n#define GDI_CLIENT_TYPE_FROM_HANDLE(Handle) ((ULONG)(Handle) & ((GDI_HANDLE_ALTTYPE_MASK << GDI_HANDLE_ALTTYPE_SHIFT) | \\\n    (GDI_HANDLE_TYPE_MASK << GDI_HANDLE_TYPE_SHIFT)))\n#define GDI_CLIENT_TYPE_FROM_UNIQUE(Unique) GDI_CLIENT_TYPE_FROM_HANDLE((ULONG)(Unique) << 16)\n\n#define GDI_ALTTYPE_1 (1 << GDI_HANDLE_ALTTYPE_SHIFT)\n#define GDI_ALTTYPE_2 (2 << GDI_HANDLE_ALTTYPE_SHIFT)\n#define GDI_ALTTYPE_3 (3 << GDI_HANDLE_ALTTYPE_SHIFT)\n\n#define GDI_CLIENT_BITMAP_TYPE (GDI_SURF_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_BRUSH_TYPE (GDI_BRUSH_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_CLIENTOBJ_TYPE (GDI_CLIENTOBJ_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_DC_TYPE (GDI_DC_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_FONT_TYPE (GDI_LFONT_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_PALETTE_TYPE (GDI_PAL_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_REGION_TYPE (GDI_RGN_TYPE << GDI_HANDLE_TYPE_SHIFT)\n\n#define GDI_CLIENT_ALTDC_TYPE (GDI_CLIENT_DC_TYPE | GDI_ALTTYPE_1)\n#define GDI_CLIENT_DIBSECTION_TYPE (GDI_CLIENT_BITMAP_TYPE | GDI_ALTTYPE_1)\n#define GDI_CLIENT_EXTPEN_TYPE (GDI_CLIENT_BRUSH_TYPE | GDI_ALTTYPE_2)\n#define GDI_CLIENT_METADC16_TYPE (GDI_CLIENT_CLIENTOBJ_TYPE | GDI_ALTTYPE_3)\n#define GDI_CLIENT_METAFILE_TYPE (GDI_CLIENT_CLIENTOBJ_TYPE | GDI_ALTTYPE_2)\n#define GDI_CLIENT_METAFILE16_TYPE (GDI_CLIENT_CLIENTOBJ_TYPE | GDI_ALTTYPE_1)\n#define GDI_CLIENT_PEN_TYPE (GDI_CLIENT_BRUSH_TYPE | GDI_ALTTYPE_1)\n\ntypedef struct _GDI_HANDLE_ENTRY\n{\n    union\n    {\n        PVOID Object;\n        PVOID NextFree;\n    };\n    union\n    {\n        struct\n        {\n            USHORT ProcessId;\n            USHORT Lock : 1;\n            USHORT Count : 15;\n        };\n        ULONG Value;\n    } Owner;\n    USHORT Unique;\n    UCHAR Type;\n    UCHAR Flags;\n    PVOID UserPointer;\n} GDI_HANDLE_ENTRY, *PGDI_HANDLE_ENTRY;\n\ntypedef struct _GDI_SHARED_MEMORY\n{\n    GDI_HANDLE_ENTRY Handles[GDI_MAX_HANDLE_COUNT];\n} GDI_SHARED_MEMORY, *PGDI_SHARED_MEMORY;\n\n#endif // _NTGDI_H\n"
  },
  {
    "path": "phnt/include/ntimage.h",
    "content": "/*\n * PE format support\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTIMAGE_H\n#define _NTIMAGE_H\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define IMAGE_FILE_MACHINE_CHPE_X86          0x3A64\n#define IMAGE_FILE_MACHINE_ARM64EC           0xA641\n#define IMAGE_FILE_MACHINE_ARM64X            0xA64E\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * The IMAGE_DEBUG_POGO_ENTRY structure represents a POGO (Profile Guided Optimization) entry.\n */\ntypedef struct _IMAGE_DEBUG_POGO_ENTRY\n{\n    ULONG Rva;\n    ULONG Size;\n    CHAR Name[1];\n} IMAGE_DEBUG_POGO_ENTRY, *PIMAGE_DEBUG_POGO_ENTRY;\n\n/**\n * The IMAGE_DEBUG_POGO_SIGNATURE structure represents a POGO signature.\n */\ntypedef struct _IMAGE_DEBUG_POGO_SIGNATURE\n{\n    ULONG Signature;\n} IMAGE_DEBUG_POGO_SIGNATURE, *PIMAGE_DEBUG_POGO_SIGNATURE;\n\n#define IMAGE_DEBUG_POGO_SIGNATURE_LTCG 'LTCG' // coffgrp LTCG (0x4C544347)\n#define IMAGE_DEBUG_POGO_SIGNATURE_PGI 'PGI\\0' // coffgrp PGI (0x50474900)\n#define IMAGE_DEBUG_POGO_SIGNATURE_PGO 'PGO\\0' // coffgrp PGO (0x50474F00)\n#define IMAGE_DEBUG_POGO_SIGNATURE_PGU 'PGU\\0' // coffgrp PGU (0x50475500)\n#define IMAGE_DEBUG_POGO_SIGNATURE_SPGO 'SPGO' // coffgrp SPGO (0x5350474F)\n\n/**\n * The IMAGE_RELOCATION_RECORD structure represents a relocation record.\n */\ntypedef struct _IMAGE_RELOCATION_RECORD\n{\n    USHORT Offset : 12;\n    USHORT Type : 4;\n} IMAGE_RELOCATION_RECORD, *PIMAGE_RELOCATION_RECORD;\n\n/**\n * The IMAGE_CHPE_METADATA_X86 structure represents CHPE (Compiled Hybrid Portable Executable) metadata for x86.\n */\ntypedef struct _IMAGE_CHPE_METADATA_X86\n{\n    ULONG Version;\n    ULONG CHPECodeAddressRangeOffset;\n    ULONG CHPECodeAddressRangeCount;\n    ULONG WowA64ExceptionHandlerFunctionPointer;\n    ULONG WowA64DispatchCallFunctionPointer;\n    ULONG WowA64DispatchIndirectCallFunctionPointer;\n    ULONG WowA64DispatchIndirectCallCfgFunctionPointer;\n    ULONG WowA64DispatchRetFunctionPointer;\n    ULONG WowA64DispatchRetLeafFunctionPointer;\n    ULONG WowA64DispatchJumpFunctionPointer;\n    ULONG CompilerIATPointer;         // Present if Version >= 2\n    ULONG WowA64RdtscFunctionPointer; // Present if Version >= 3\n} IMAGE_CHPE_METADATA_X86, *PIMAGE_CHPE_METADATA_X86;\n\n/**\n * The IMAGE_CHPE_RANGE_ENTRY structure represents a CHPE range entry.\n */\ntypedef struct _IMAGE_CHPE_RANGE_ENTRY\n{\n    union\n    {\n        ULONG StartOffset;\n        struct\n        {\n            ULONG NativeCode : 1;\n            ULONG AddressBits : 31;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n\n    ULONG Length;\n} IMAGE_CHPE_RANGE_ENTRY, *PIMAGE_CHPE_RANGE_ENTRY;\n\n/**\n * The IMAGE_ARM64EC_METADATA structure represents ARM64EC metadata.\n */\ntypedef struct _IMAGE_ARM64EC_METADATA\n{\n    ULONG Version;\n    ULONG CodeMap;\n    ULONG CodeMapCount;\n    ULONG CodeRangesToEntryPoints;\n    ULONG RedirectionMetadata;\n    ULONG tbd__os_arm64x_dispatch_call_no_redirect;\n    ULONG tbd__os_arm64x_dispatch_ret;\n    ULONG tbd__os_arm64x_dispatch_call;\n    ULONG tbd__os_arm64x_dispatch_icall;\n    ULONG tbd__os_arm64x_dispatch_icall_cfg;\n    ULONG AlternateEntryPoint;\n    ULONG AuxiliaryIAT;\n    ULONG CodeRangesToEntryPointsCount;\n    ULONG RedirectionMetadataCount;\n    ULONG GetX64InformationFunctionPointer;\n    ULONG SetX64InformationFunctionPointer;\n    ULONG ExtraRFETable;\n    ULONG ExtraRFETableSize;\n    ULONG __os_arm64x_dispatch_fptr;\n    ULONG AuxiliaryIATCopy;\n} IMAGE_ARM64EC_METADATA, *PIMAGE_ARM64EC_METADATA;\n\n// rev\n#define IMAGE_ARM64EC_CODE_MAP_TYPE_ARM64   0\n#define IMAGE_ARM64EC_CODE_MAP_TYPE_ARM64EC 1\n#define IMAGE_ARM64EC_CODE_MAP_TYPE_AMD64   2\n\n// rev\n/**\n * The IMAGE_ARM64EC_CODE_MAP_ENTRY structure represents an ARM64EC code map entry.\n */\ntypedef struct _IMAGE_ARM64EC_CODE_MAP_ENTRY\n{\n    union\n    {\n        ULONG StartOffset;\n        struct\n        {\n            ULONG Type : 2;\n            ULONG AddressBits : 30;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n\n    ULONG Length;\n} IMAGE_ARM64EC_CODE_MAP_ENTRY, *PIMAGE_ARM64EC_CODE_MAP_ENTRY;\n\n/**\n * The IMAGE_ARM64EC_REDIRECTION_ENTRY structure represents an ARM64EC redirection entry.\n */\ntypedef struct _IMAGE_ARM64EC_REDIRECTION_ENTRY\n{\n    ULONG Source;\n    ULONG Destination;\n} IMAGE_ARM64EC_REDIRECTION_ENTRY, *PIMAGE_ARM64EC_REDIRECTION_ENTRY;\n\n/**\n * The IMAGE_ARM64EC_CODE_RANGE_ENTRY_POINT structure represents an ARM64EC code range entry point.\n */\ntypedef struct _IMAGE_ARM64EC_CODE_RANGE_ENTRY_POINT\n{\n    ULONG StartRva;\n    ULONG EndRva;\n    ULONG EntryPoint;\n} IMAGE_ARM64EC_CODE_RANGE_ENTRY_POINT, *PIMAGE_ARM64EC_CODE_RANGE_ENTRY_POINT;\n\n#define IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL   0\n#define IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE      1\n#define IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA      2\n\n#define IMAGE_DVRT_ARM64X_FIXUP_SIZE_2BYTES     1\n#define IMAGE_DVRT_ARM64X_FIXUP_SIZE_4BYTES     2\n#define IMAGE_DVRT_ARM64X_FIXUP_SIZE_8BYTES     3\n\n/**\n * The IMAGE_DVRT_ARM64X_FIXUP_RECORD structure represents an ARM64X fixup record.\n */\ntypedef struct _IMAGE_DVRT_ARM64X_FIXUP_RECORD\n{\n    USHORT Offset : 12;\n    USHORT Type   :  2;\n    USHORT Size   :  2;\n    // Value of variable Size when IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE\n} IMAGE_DVRT_ARM64X_FIXUP_RECORD, *PIMAGE_DVRT_ARM64X_FIXUP_RECORD;\n\n/**\n * The IMAGE_DVRT_ARM64X_DELTA_FIXUP_RECORD structure represents an ARM64X delta fixup record.\n */\ntypedef struct _IMAGE_DVRT_ARM64X_DELTA_FIXUP_RECORD\n{\n    USHORT Offset : 12;\n    USHORT Type   :  2; // IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA\n    USHORT Sign   :  1; // 1 = -, 0 = +\n    USHORT Scale  :  1; // 1 = 8, 0 = 4\n    // USHORT Value; // Delta = Value * Scale * Sign\n} IMAGE_DVRT_ARM64X_DELTA_FIXUP_RECORD, *PIMAGE_DVRT_ARM64X_DELTA_FIXUP_RECORD;\n\n/**\n * The IMAGE_IMPORT_CONTROL_TRANSFER_ARM64_RELOCATION structure represents an ARM64 import control transfer relocation.\n *\n * \\remarks On ARM64, optimized imported functions use this structure for import control transfer relocations.\n * This is used with IMAGE_DYNAMIC_RELOCATION_ARM64_KERNEL_IMPORT_CALL_TRANSFER.\n */\n//typedef struct _IMAGE_IMPORT_CONTROL_TRANSFER_ARM64_RELOCATION\n//{\n//    ULONG PageRelativeOffset : 10;  ///< Offset to the call instruction shifted right by 2 (4-byte aligned instruction)\n//    ULONG IndirectCall       :  1;  ///< 0 if target instruction is a BR, 1 if BLR\n//    ULONG RegisterIndex      :  5;  ///< Register index used for the indirect call/jump\n//    ULONG ImportType         :  1;  ///< 0 if this refers to a static import, 1 for delayload import\n//    ULONG IATIndex           : 15;  ///< IAT index of the corresponding import (0x7FFF indicates no index)\n//} IMAGE_IMPORT_CONTROL_TRANSFER_ARM64_RELOCATION, *PIMAGE_IMPORT_CONTROL_TRANSFER_ARM64_RELOCATION;\n\n/**\n * The IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER structure represents a prologue dynamic relocation header.\n *\n * \\remarks This structure is followed by PrologueByteCount bytes containing the prologue code.\n * Used with IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE.\n */\n//#include <pshpack1.h>\n//typedef struct _IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER\n//{\n//    UCHAR PrologueByteCount;\n//    // UCHAR PrologueBytes[PrologueByteCount];\n//} IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER, UNALIGNED *PIMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER;\n//#include <poppack.h>\n\n/**\n * The IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER structure represents an epilogue dynamic relocation header.\n *\n * \\remarks This structure is followed by variable-length branch descriptor data.\n * Used with IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE.\n */\n//#include <pshpack1.h>\n//typedef struct _IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER\n//{\n//    ULONG EpilogueCount;\n//    UCHAR EpilogueByteCount;\n//    UCHAR BranchDescriptorElementSize;\n//    USHORT BranchDescriptorCount;\n//    // UCHAR BranchDescriptors[...];\n//    // UCHAR BranchDescriptorBitMap[...];\n//} IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER, UNALIGNED *PIMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER;\n//#include <poppack.h>\n\n#define IMAGE_DYNAMIC_RELOCATION_ARM64X                         0x00000006\n#define IMAGE_DYNAMIC_RELOCATION_ARM64_KERNEL_IMPORT_CALL_TRANSFER 0x00000008\n#define IMAGE_DYNAMIC_RELOCATION_MM_SHARED_USER_DATA_VA         0x7FFE0000\n#define IMAGE_DYNAMIC_RELOCATION_KI_USER_SHARED_DATA64          0xFFFFF78000000000UI64\n\n// Note: The Windows SDK defines UNALIGNED for PIMAGE_IMPORT_DESCRIPTOR but\n// doesn't include UNALIGNED for PIMAGE_THUNK_DATA (See GH#1694) (dmex)\ntypedef struct _IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA32;\ntypedef struct _IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA64;\ntypedef IMAGE_THUNK_DATA32 UNALIGNED* UNALIGNED_PIMAGE_THUNK_DATA32;\ntypedef IMAGE_THUNK_DATA64 UNALIGNED* UNALIGNED_PIMAGE_THUNK_DATA64;\n\n// Note: Required for legacy SDK support (dmex)\n#if !defined(NTDDI_WIN10_NI) || (NTDDI_VERSION < NTDDI_WIN10_NI)\n#define IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE   0x00000001\n#define IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE   0x00000002\n#define IMAGE_DYNAMIC_RELOCATION_GUARD_IMPORT_CONTROL_TRANSFER  0x00000003\n#define IMAGE_DYNAMIC_RELOCATION_GUARD_INDIR_CONTROL_TRANSFER   0x00000004\n#define IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH       0x00000005\n#define IMAGE_DYNAMIC_RELOCATION_FUNCTION_OVERRIDE              0x00000007\n\n/**\n * The IMAGE_FUNCTION_OVERRIDE_HEADER structure represents a function override header.\n */\ntypedef struct _IMAGE_FUNCTION_OVERRIDE_HEADER \n{\n    ULONG FuncOverrideSize;\n    // IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION  FuncOverrideInfo[ANYSIZE_ARRAY]; // FuncOverrideSize bytes in size\n    // IMAGE_BDD_INFO BDDInfo; // BDD region, size in bytes: DVRTEntrySize - sizeof(IMAGE_FUNCTION_OVERRIDE_HEADER) - FuncOverrideSize\n} IMAGE_FUNCTION_OVERRIDE_HEADER;\ntypedef IMAGE_FUNCTION_OVERRIDE_HEADER UNALIGNED *PIMAGE_FUNCTION_OVERRIDE_HEADER;\n\n/**\n * The IMAGE_BDD_INFO structure represents BDD (Binary Decision Diagram) information.\n */\ntypedef struct _IMAGE_BDD_INFO \n{\n    ULONG Version; // decides the semantics of serialized BDD\n    ULONG BDDSize;\n    // IMAGE_BDD_DYNAMIC_RELOCATION BDDNodes[ANYSIZE_ARRAY]; // BDDSize size in bytes.\n} IMAGE_BDD_INFO, *PIMAGE_BDD_INFO;\n\n/**\n * The IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION structure represents a function override dynamic relocation.\n */\ntypedef struct _IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION \n{\n    ULONG OriginalRva;          // RVA of original function\n    ULONG BDDOffset;            // Offset into the BDD region\n    ULONG RvaSize;              // Size in bytes taken by RVAs. Must be multiple of sizeof(ULONG).\n    ULONG BaseRelocSize;        // Size in bytes taken by BaseRelocs\n    // ULONG RVAs[RvaSize / sizeof(ULONG)];     // Array containing overriding func RVAs.\n    // IMAGE_BASE_RELOCATION  BaseRelocs[ANYSIZE_ARRAY];\n    // ^Base relocations (RVA + Size + TO)\n    // ^Padded with extra TOs for 4B alignment\n    // ^BaseRelocSize size in bytes\n} IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION, *PIMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION;\n\n/**\n * The IMAGE_BDD_DYNAMIC_RELOCATION structure represents a BDD dynamic relocation.\n */\ntypedef struct _IMAGE_BDD_DYNAMIC_RELOCATION \n{\n    USHORT Left;  // Index of FALSE edge in BDD array\n    USHORT Right; // Index of TRUE edge in BDD array\n    ULONG  Value; // Either FeatureNumber or Index into RVAs array\n} IMAGE_BDD_DYNAMIC_RELOCATION, *PIMAGE_BDD_DYNAMIC_RELOCATION;\n\n// Function override relocation types in DVRT records.\n#define IMAGE_FUNCTION_OVERRIDE_INVALID         0\n#define IMAGE_FUNCTION_OVERRIDE_X64_REL32       1  // 32-bit relative address from byte following reloc\n#define IMAGE_FUNCTION_OVERRIDE_ARM64_BRANCH26  2  // 26 bit offset << 2 & sign ext. for B & BL\n#define IMAGE_FUNCTION_OVERRIDE_ARM64_THUNK     3\n#endif // !defined(NTDDI_WIN10_NI) || (NTDDI_VERSION < NTDDI_WIN10_NI)\n\n#if !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\n#define IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT                          0x40\n#define IMAGE_DLLCHARACTERISTICS_EX_HOTPATCH_COMPATIBLE                         0x80\n#endif // !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\n\n#endif // _NTIMAGE_H\n"
  },
  {
    "path": "phnt/include/ntintsafe.h",
    "content": "/******************************************************************\n*                                                                 *\n*  ntintsafe.h -- This module defines helper functions to prevent *\n*                 integer overflow bugs for drivers. A similar    *\n*                 file, intsafe.h, is available for applications. *\n*                                                                 *\n*  Copyright (c) Microsoft Corp.  All rights reserved.            *\n*                                                                 *\n******************************************************************/\n\n#ifndef _NTINTSAFE_H_INCLUDED_\n#define _NTINTSAFE_H_INCLUDED_\n\n#include <winapifamily.h>\n\n\n#if (_MSC_VER > 1000)\n#pragma once\n#endif\n\n#pragma region Application Family or Games Family\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)\n\n#include <specstrings.h>    // for _In_, etc.\n\n#if _MSC_VER >= 1200\n#pragma warning(push)\n#pragma warning(disable:4668) // #if not_defined treated as #if 0\n#endif\n\n#if !defined(_W64)\n#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86) || defined(_ARM_) || defined(_M_ARM)) && (_MSC_VER >= 1300)\n#define _W64 __w64\n#else\n#define _W64\n#endif\n#endif\n\n//\n// typedefs\n//\ntypedef char                CHAR;\ntypedef signed char         INT8;\ntypedef unsigned char       UCHAR;\ntypedef unsigned char       UINT8;\ntypedef unsigned char       BYTE;\ntypedef short               SHORT;\ntypedef signed short        INT16;\ntypedef unsigned short      USHORT;\ntypedef unsigned short      UINT16;\ntypedef unsigned short      WORD;\ntypedef int                 INT;\ntypedef signed int          INT32;\ntypedef unsigned int        UINT;\ntypedef unsigned int        UINT32;\ntypedef long                LONG;\ntypedef unsigned long       ULONG;\ntypedef unsigned long       DWORD;\ntypedef __int64             LONGLONG;\ntypedef __int64             LONG64;\ntypedef signed __int64      RtlINT64;\ntypedef unsigned __int64    ULONGLONG;\ntypedef unsigned __int64    DWORDLONG;\ntypedef unsigned __int64    ULONG64;\ntypedef unsigned __int64    DWORD64;\ntypedef unsigned __int64    UINT64;\n\n#if (__midl > 501)\ntypedef [public]          __int3264 INT_PTR;\ntypedef [public] unsigned __int3264 UINT_PTR;\ntypedef [public]          __int3264 LONG_PTR;\ntypedef [public] unsigned __int3264 ULONG_PTR;\n#else\n#ifdef _WIN64\ntypedef __int64             INT_PTR;\ntypedef unsigned __int64    UINT_PTR;\ntypedef __int64             LONG_PTR;\ntypedef unsigned __int64    ULONG_PTR;\n#else\ntypedef _W64 int            INT_PTR;\ntypedef _W64 unsigned int   UINT_PTR;\ntypedef _W64 long           LONG_PTR;\ntypedef _W64 unsigned long  ULONG_PTR;\n#endif // WIN64\n#endif // (__midl > 501)\n\n#ifdef _WIN64\ntypedef __int64             ptrdiff_t;\ntypedef unsigned __int64    size_t;\n#else\ntypedef _W64 int            ptrdiff_t;\ntypedef _W64 unsigned int   size_t;\n#endif\n\ntypedef ULONG_PTR   DWORD_PTR;\ntypedef LONG_PTR    SSIZE_T;\ntypedef ULONG_PTR   SIZE_T;\n\n#undef _USE_INTRINSIC_MULTIPLY128\n\n#if !defined(_M_CEE) && ((defined(_AMD64_) && !defined(_ARM64EC_)) || (defined(_IA64_) && (_MSC_VER >= 1400)))\n#define _USE_INTRINSIC_MULTIPLY128\n#endif\n\n#if defined(_USE_INTRINSIC_MULTIPLY128)\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if !defined(_ARM64EC_)\n\n#define UnsignedMultiply128 _umul128\n\n#else\n\n#define _umul128 Multiply128\n\n#endif // defined(_ARM64EC_)\n\nULONG64\nUnsignedMultiply128(\n    _In_ ULONGLONG ullMultiplicand,\n    _In_ ULONGLONG ullMultiplier,\n    _Out_ ULONGLONG* pullResultHigh); // _Deref_out_range_(==, ullMultiplicand * ullMultiplier) \n\n#if !defined(_ARM64EC_)\n#pragma intrinsic(_umul128)\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n#endif // _USE_INTRINSIC_MULTIPLY128\n\n\n\ntypedef _Return_type_success_(return >= 0) long NTSTATUS;\n\n#define NT_SUCCESS(Status)  (((NTSTATUS)(Status)) >= 0)\n\n#define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)\n#ifndef SORTPP_PASS\n// compiletime asserts (failure results in error C2118: negative subscript)\n#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]\n#else\n#define C_ASSERT(e)\n#endif\n\n//\n// UInt32x32To64 macro\n//\n#ifndef UInt32x32To64\n#if defined(MIDL_PASS) || defined(RC_INVOKED) || defined(_M_CEE_PURE) \\\n    || defined(_68K_) || defined(_MPPC_) \\\n    || defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64) \\\n    || defined(_M_HYBRID_X86_ARM64)\n#define UInt32x32To64(a, b) (((unsigned __int64)((unsigned int)(a))) * ((unsigned __int64)((unsigned int)(b))))\n#elif defined(_M_IX86)\n#define UInt32x32To64(a, b) ((unsigned __int64)(((unsigned __int64)((unsigned int)(a))) * ((unsigned int)(b))))\n#else\n#error Must define a target architecture.\n#endif\n#endif\n\n//\n// Min/Max type values\n//\n#define INT8_MIN        (-127i8 - 1)\n#define SHORT_MIN       (-32768)\n#define INT16_MIN       (-32767i16 - 1)\n#ifndef INT_MIN\n#define INT_MIN         (-2147483647 - 1)\n#endif\n#define INT32_MIN       (-2147483647i32 - 1)\n#ifndef LONG_MIN\n#define LONG_MIN        (-2147483647L - 1)\n#endif\n#define LONGLONG_MIN    (-9223372036854775807i64 - 1)\n#define LONG64_MIN      (-9223372036854775807i64 - 1)\n#define INT64_MIN       (-9223372036854775807i64 - 1)\n#define INT128_MIN      (-170141183460469231731687303715884105727i128 - 1)\n\n#ifdef _WIN64\n#define INT_PTR_MIN     (-9223372036854775807i64 - 1)\n#define LONG_PTR_MIN    (-9223372036854775807i64 - 1)\n#define PTRDIFF_T_MIN   (-9223372036854775807i64 - 1)\n#define SSIZE_T_MIN     (-9223372036854775807i64 - 1)\n#else\n#define INT_PTR_MIN     (-2147483647 - 1)\n#define LONG_PTR_MIN    (-2147483647L - 1)\n#define PTRDIFF_T_MIN   (-2147483647 - 1)\n#define SSIZE_T_MIN     (-2147483647L - 1)\n#endif\n\n#define INT8_MAX        127i8\n#define UINT8_MAX       0xffui8\n#define BYTE_MAX        0xff\n#define SHORT_MAX       32767\n#define INT16_MAX       32767i16\n#define USHORT_MAX      0xffff\n#define UINT16_MAX      0xffffui16\n#define WORD_MAX        0xffff\n#ifndef INT_MAX\n#define INT_MAX         2147483647\n#endif\n#define INT32_MAX       2147483647i32\n#ifndef UINT_MAX\n#define UINT_MAX        0xffffffff\n#endif\n#define UINT32_MAX      0xffffffffui32\n#ifndef LONG_MAX\n#define LONG_MAX        2147483647L\n#endif\n#ifndef ULONG_MAX\n#define ULONG_MAX       0xffffffffUL\n#endif\n#define DWORD_MAX       0xffffffffUL\n#define LONGLONG_MAX    9223372036854775807i64\n#define LONG64_MAX      9223372036854775807i64\n#define INT64_MAX       9223372036854775807i64\n#define ULONGLONG_MAX   0xffffffffffffffffui64\n#define DWORDLONG_MAX   0xffffffffffffffffui64\n#define ULONG64_MAX     0xffffffffffffffffui64\n#define DWORD64_MAX     0xffffffffffffffffui64\n#define UINT64_MAX      0xffffffffffffffffui64\n#define INT128_MAX      170141183460469231731687303715884105727i128\n#define UINT128_MAX     0xffffffffffffffffffffffffffffffffui128\n\n#undef SIZE_T_MAX\n\n#ifdef _WIN64\n#define INT_PTR_MAX     9223372036854775807i64\n#define UINT_PTR_MAX    0xffffffffffffffffui64\n#define LONG_PTR_MAX    9223372036854775807i64\n#define ULONG_PTR_MAX   0xffffffffffffffffui64\n#define DWORD_PTR_MAX   0xffffffffffffffffui64\n#define PTRDIFF_T_MAX   9223372036854775807i64\n#define SIZE_T_MAX      0xffffffffffffffffui64\n#define SSIZE_T_MAX     9223372036854775807i64\n#define _SIZE_T_MAX     0xffffffffffffffffui64\n#else\n#define INT_PTR_MAX     2147483647\n#define UINT_PTR_MAX    0xffffffff\n#define LONG_PTR_MAX    2147483647L\n#define ULONG_PTR_MAX   0xffffffffUL\n#define DWORD_PTR_MAX   0xffffffffUL\n#define PTRDIFF_T_MAX   2147483647\n#define SIZE_T_MAX      0xffffffff\n#define SSIZE_T_MAX     2147483647L\n#define _SIZE_T_MAX     0xffffffffUL\n#endif\n\n\n//\n// It is common for -1 to be used as an error value\n//\n#define INT8_ERROR      (-1i8)\n#define UINT8_ERROR     0xffui8\n#define BYTE_ERROR      0xff\n#define SHORT_ERROR     (-1)\n#define INT16_ERROR     (-1i16)\n#define USHORT_ERROR    0xffff\n#define UINT16_ERROR    0xffffui16\n#define WORD_ERROR      0xffff\n#define INT_ERROR       (-1)\n#define INT32_ERROR     (-1i32)\n#define UINT_ERROR      0xffffffff\n#define UINT32_ERROR    0xffffffffui32\n#define LONG_ERROR      (-1L)\n#define ULONG_ERROR     0xffffffffUL\n#define DWORD_ERROR     0xffffffffUL\n#define LONGLONG_ERROR  (-1i64)\n#define LONG64_ERROR    (-1i64)\n#define INT64_ERROR     (-1i64)\n#define ULONGLONG_ERROR 0xffffffffffffffffui64\n#define DWORDLONG_ERROR 0xffffffffffffffffui64\n#define ULONG64_ERROR   0xffffffffffffffffui64\n#define UINT64_ERROR    0xffffffffffffffffui64\n\n#ifdef _WIN64\n#define INT_PTR_ERROR   (-1i64)\n#define UINT_PTR_ERROR  0xffffffffffffffffui64\n#define LONG_PTR_ERROR  (-1i64)\n#define ULONG_PTR_ERROR 0xffffffffffffffffui64\n#define DWORD_PTR_ERROR 0xffffffffffffffffui64\n#define PTRDIFF_T_ERROR (-1i64)\n#define SIZE_T_ERROR    0xffffffffffffffffui64\n#define SSIZE_T_ERROR   (-1i64)\n#define _SIZE_T_ERROR   0xffffffffffffffffui64\n#else\n#define INT_PTR_ERROR   (-1)\n#define UINT_PTR_ERROR  0xffffffff\n#define LONG_PTR_ERROR  (-1L)\n#define ULONG_PTR_ERROR 0xffffffffUL\n#define DWORD_PTR_ERROR 0xffffffffUL\n#define PTRDIFF_T_ERROR (-1)\n#define SIZE_T_ERROR    0xffffffff\n#define SSIZE_T_ERROR   (-1L)\n#define _SIZE_T_ERROR   0xffffffffUL\n#endif\n\n\n//\n// We make some assumptions about the sizes of various types. Let's be\n// explicit about those assumptions and check them.\n//\nC_ASSERT(sizeof(USHORT) == 2);\nC_ASSERT(sizeof(INT) == 4);\nC_ASSERT(sizeof(UINT) == 4);\nC_ASSERT(sizeof(LONG) == 4);\nC_ASSERT(sizeof(ULONG) == 4);\nC_ASSERT(sizeof(UINT_PTR) == sizeof(ULONG_PTR));\n\n\n//=============================================================================\n// Conversion functions\n//\n// There are three reasons for having conversion functions:\n//\n// 1. We are converting from a signed type to an unsigned type of the same\n//    size, or vice-versa.\n//\n//    Since we default to only having unsigned math functions,\n//    (see ENABLE_INTSAFE_SIGNED_FUNCTIONS below) we prefer people to convert\n//    to unsigned, do the math, and then convert back to signed.\n//\n// 2. We are converting to a smaller type, and we could therefore possibly\n//    overflow.\n//\n// 3. We are converting to a bigger type, and we are signed and the type we are\n//    converting to is unsigned.\n//\n//=============================================================================\n\n\n//\n// INT8 -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8ToUChar(\n    _In_ INT8 i8Operand,\n    _Out_ _Deref_out_range_(==, i8Operand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if (i8Operand >= 0)\n    {\n        *pch = (UCHAR)i8Operand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT8 -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8ToUInt8(\n    _In_ INT8 i8Operand,\n    _Out_ _Deref_out_range_(==, i8Operand) UINT8* pu8Result)\n{\n    NTSTATUS status;\n\n    if (i8Operand >= 0)\n    {\n        *pu8Result = (UINT8)i8Operand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pu8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT8 -> BYTE conversion\n//\n#define RtlInt8ToByte  RtlInt8ToUInt8\n\n//\n// INT8 -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8ToUShort(\n    _In_ INT8 i8Operand,\n    _Out_ _Deref_out_range_(==, i8Operand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if (i8Operand >= 0)\n    {\n        *pusResult = (USHORT)i8Operand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT8 -> UINT16 conversion\n//\n#define RtlInt8ToUInt16    RtlInt8ToUShort\n\n//\n// INT8 -> WORD conversion\n//\n#define RtlInt8ToWord  RtlInt8ToUShort\n\n//\n// INT8 -> UINT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8ToUInt(\n    _In_ INT8 i8Operand,\n    _Out_ _Deref_out_range_(==, i8Operand) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if (i8Operand >= 0)\n    {\n        *puResult = (UINT)i8Operand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT8 -> UINT32 conversion\n//\n#define RtlInt8ToUInt32    RtlInt8ToUInt\n\n//\n// INT8 -> UINT_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8ToUIntPtr(\n    _In_ INT8 i8Operand,\n    _Out_ _Deref_out_range_(==, i8Operand) UINT_PTR* puResult)\n{\n    NTSTATUS status;\n\n    if (i8Operand >= 0)\n    {\n        *puResult = (UINT_PTR)i8Operand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT8 -> ULONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8ToULong(\n    _In_ INT8 i8Operand,\n    _Out_ _Deref_out_range_(==, i8Operand) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if (i8Operand >= 0)\n    {\n        *pulResult = (ULONG)i8Operand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT8 -> ULONG_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8ToULongPtr(\n    _In_ INT8 i8Operand,\n    _Out_ _Deref_out_range_(==, i8Operand) ULONG_PTR* pulResult)\n{\n    NTSTATUS status;\n\n    if (i8Operand >= 0)\n    {\n        *pulResult = (ULONG_PTR)i8Operand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT8 -> DWORD conversion\n//\n#define RtlInt8ToDWord RtlInt8ToULong\n\n//\n// INT8 -> DWORD_PTR conversion\n//\n#define RtlInt8ToDWordPtr  RtlInt8ToULongPtr\n\n//\n// INT8 -> ULONGLONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8ToULongLong(\n    _In_ INT8 i8Operand,\n    _Out_ _Deref_out_range_(==, i8Operand) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n\n    if (i8Operand >= 0)\n    {\n        *pullResult = (ULONGLONG)i8Operand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT8 -> DWORDLONG conversion\n//\n#define RtlInt8ToDWordLong RtlInt8ToULongLong\n\n//\n// INT8 -> ULONG64 conversion\n//\n#define RtlInt8ToULong64   RtlInt8ToULongLong\n\n//\n// INT8 -> DWORD64 conversion\n//\n#define RtlInt8ToDWord64   RtlInt8ToULongLong\n\n//\n// INT8 -> UINT64 conversion\n//\n#define RtlInt8ToUInt64    RtlInt8ToULongLong\n\n//\n// INT8 -> size_t conversion\n//\n#define RtlInt8ToSizeT RtlInt8ToUIntPtr\n\n//\n// INT8 -> SIZE_T conversion\n//\n#define RtlInt8ToSIZET RtlInt8ToULongPtr\n\n//\n// UINT8 -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUInt8ToInt8(\n    _In_ UINT8 u8Operand,\n    _Out_ _Deref_out_range_(==, u8Operand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if (u8Operand <= INT8_MAX)\n    {\n        *pi8Result = (INT8)u8Operand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT8 -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlUInt8ToChar(\n    _In_ UINT8 u8Operand,\n    _Out_ _Deref_out_range_(==, u8Operand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    *pch = (CHAR)u8Operand;\n    return STATUS_SUCCESS;\n#else\n    return RtlUInt8ToInt8(u8Operand, (INT8*)pch);\n#endif\n}\n\n//\n// BYTE -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlByteToInt8(\n    _In_ BYTE bOperand,\n    _Out_ _Deref_out_range_(==, bOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if (bOperand <= INT8_MAX)\n    {\n        *pi8Result = (INT8)bOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// BYTE -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlByteToChar(\n    _In_ BYTE bOperand,\n    _Out_ _Deref_out_range_(==, bOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    *pch = (CHAR)bOperand;\n    return STATUS_SUCCESS;\n#else\n    return RtlByteToInt8(bOperand, (INT8*)pch);\n#endif\n}\n\n//\n// SHORT -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToInt8(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if ((sOperand >= INT8_MIN) && (sOperand <= INT8_MAX))\n    {\n        *pi8Result = (INT8)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToUChar(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if ((sOperand >= 0) && (sOperand <= 255))\n    {\n        *pch = (UCHAR)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlShortToChar(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlShortToUChar(sOperand, (UCHAR*)pch);\n#else\n    return RtlShortToInt8(sOperand, (INT8*)pch);\n#endif // _CHAR_UNSIGNED\n}\n\n//\n// SHORT -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToUInt8(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) UINT8* pui8Result)\n{\n    NTSTATUS status;\n\n    if ((sOperand >= 0) && (sOperand <= UINT8_MAX))\n    {\n        *pui8Result = (UINT8)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pui8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> BYTE conversion\n//\n#define RtlShortToByte  RtlShortToUInt8\n\n//\n// SHORT -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToUShort(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if (sOperand >= 0)\n    {\n        *pusResult = (USHORT)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> UINT16 conversion\n//\n#define RtlShortToUInt16   RtlShortToUShort\n\n//\n// SHORT -> WORD conversion\n//\n#define RtlShortToWord RtlShortToUShort\n\n//\n// SHORT -> UINT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToUInt(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if (sOperand >= 0)\n    {\n        *puResult = (UINT)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> UINT32 conversion\n//\n#define RtlShortToUInt32   RtlShortToUInt\n\n//\n// SHORT -> UINT_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToUIntPtr(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) UINT_PTR* puResult)\n{\n    NTSTATUS status;\n\n    if (sOperand >= 0)\n    {\n        *puResult = (UINT_PTR)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> ULONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToULong(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if (sOperand >= 0)\n    {\n        *pulResult = (ULONG)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> ULONG_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToULongPtr(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) ULONG_PTR* pulResult)\n{\n    NTSTATUS status;\n\n    if (sOperand >= 0)\n    {\n        *pulResult = (ULONG_PTR)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> DWORD conversion\n//\n#define RtlShortToDWord    RtlShortToULong\n\n//\n// SHORT -> DWORD_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToDWordPtr(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) DWORD_PTR* pdwResult)\n{\n    NTSTATUS status;\n\n    if (sOperand >= 0)\n    {\n        *pdwResult = (DWORD_PTR)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pdwResult = DWORD_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> ULONGLONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortToULongLong(\n    _In_ SHORT sOperand,\n    _Out_ _Deref_out_range_(==, sOperand) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n\n    if (sOperand >= 0)\n    {\n        *pullResult = (ULONGLONG)sOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SHORT -> DWORDLONG conversion\n//\n#define RtlShortToDWordLong    RtlShortToULongLong\n\n//\n// SHORT -> ULONG64 conversion\n//\n#define RtlShortToULong64  RtlShortToULongLong\n\n//\n// SHORT -> DWORD64 conversion\n//\n#define RtlShortToDWord64  RtlShortToULongLong\n\n//\n// SHORT -> UINT64 conversion\n//\n#define RtlShortToUInt64   RtlShortToULongLong\n\n//\n// SHORT -> size_t conversion\n//\n#define RtlShortToSizeT    RtlShortToUIntPtr\n\n//\n// SHORT -> SIZE_T conversion\n//\n#define RtlShortToSIZET    RtlShortToULongPtr\n\n//\n// INT16 -> CHAR conversion\n//\n#define RtlInt16ToChar RtlShortToChar\n\n//\n// INT16 -> INT8 conversion\n//\n#define RtlInt16ToInt8 RtlShortToInt8\n\n//\n// INT16 -> UCHAR conversion\n//\n#define RtlInt16ToUChar    RtlShortToUChar\n\n//\n// INT16 -> UINT8 conversion\n//\n#define RtlInt16ToUInt8    RtlShortToUInt8\n\n//\n// INT16 -> BYTE conversion\n//\n#define RtlInt16ToByte RtlShortToUInt8\n\n//\n// INT16 -> USHORT conversion\n//\n#define RtlInt16ToUShort   RtlShortToUShort\n\n//\n// INT16 -> UINT16 conversion\n//\n#define RtlInt16ToUInt16   RtlShortToUShort\n\n//\n// INT16 -> WORD conversion\n//\n#define RtlInt16ToWord RtlShortToUShort\n\n//\n// INT16 -> UINT conversion\n//\n#define RtlInt16ToUInt RtlShortToUInt\n\n//\n// INT16 -> UINT32 conversion\n//\n#define RtlInt16ToUInt32   RtlShortToUInt\n\n//\n// INT16 -> UINT_PTR conversion\n//\n#define RtlInt16ToUIntPtr  RtlShortToUIntPtr\n\n//\n// INT16 -> ULONG conversion\n//\n#define RtlInt16ToULong    RtlShortToULong\n\n//\n// INT16 -> ULONG_PTR conversion\n//\n#define RtlInt16ToULongPtr RtlShortToULongPtr\n\n//\n// INT16 -> DWORD conversion\n//\n#define RtlInt16ToDWord    RtlShortToULong\n\n//\n// INT16 -> DWORD_PTR conversion\n//\n#define RtlInt16ToDWordPtr RtlShortToULongPtr\n\n//\n// INT16 -> ULONGLONG conversion\n//\n#define RtlInt16ToULongLong    RtlShortToULongLong\n\n//\n// INT16 -> DWORDLONG conversion\n//\n#define RtlInt16ToDWordLong    RtlShortToULongLong\n\n//\n// INT16 -> ULONG64 conversion\n//\n#define RtlInt16ToULong64  RtlShortToULongLong\n\n//\n// INT16 -> DWORD64 conversion\n//\n#define RtlInt16ToDWord64  RtlShortToULongLong\n\n//\n// INT16 -> UINT64 conversion\n//\n#define RtlInt16ToUInt64   RtlShortToULongLong\n\n//\n// INT16 -> size_t conversion\n//\n#define RtlInt16ToSizeT    RtlShortToUIntPtr\n\n//\n// INT16 -> SIZE_T conversion\n//\n#define RtlInt16ToSIZET    RtlShortToULongPtr\n\n//\n// USHORT -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUShortToInt8(\n    _In_ USHORT usOperand,\n    _Out_ _Deref_out_range_(==, usOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if (usOperand <= INT8_MAX)\n    {\n        *pi8Result = (INT8)usOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// USHORT -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUShortToUChar(\n    _In_ USHORT usOperand,\n    _Out_ _Deref_out_range_(==, usOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if (usOperand <= 255)\n    {\n        *pch = (UCHAR)usOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// USHORT -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlUShortToChar(\n    _In_ USHORT usOperand,\n    _Out_ _Deref_out_range_(==, usOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlUShortToUChar(usOperand, (UCHAR*)pch);\n#else\n    return RtlUShortToInt8(usOperand, (INT8*)pch);\n#endif // _CHAR_UNSIGNED\n}\n\n//\n// USHORT -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUShortToUInt8(\n    _In_ USHORT usOperand,\n    _Out_ _Deref_out_range_(==, usOperand) UINT8* pui8Result)\n{\n    NTSTATUS status;\n\n    if (usOperand <= UINT8_MAX)\n    {\n        *pui8Result = (UINT8)usOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pui8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// USHORT -> BYTE conversion\n//\n#define RtlUShortToByte    RtlUShortToUInt8\n\n//\n// USHORT -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUShortToShort(\n    _In_ USHORT usOperand,\n    _Out_ _Deref_out_range_(==, usOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if (usOperand <= SHORT_MAX)\n    {\n        *psResult = (SHORT)usOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// USHORT -> INT16 conversion\n//\n#define RtlUShortToInt16   RtlUShortToShort\n\n//\n// UINT16 -> CHAR conversion\n//\n#define RtlUInt16ToChar    RtlUShortToChar\n\n//\n// UINT16 -> INT8 conversion\n//\n#define RtlUInt16ToInt8    RtlUShortToInt8\n\n//\n// UINT16 -> UCHAR conversion\n//\n#define RtlUInt16ToUChar   RtlUShortToUChar\n\n//\n// UINT16 -> UINT8 conversion\n//\n#define RtlUInt16ToUInt8   RtlUShortToUInt8\n\n//\n// UINT16 -> BYTE conversion\n//\n#define RtlUInt16ToByte    RtlUShortToUInt8\n\n//\n// UINT16 -> SHORT conversion\n//\n#define RtlUInt16ToShort   RtlUShortToShort\n\n//\n// UINT16 -> INT16 conversion\n//\n#define RtlUInt16ToInt16   RtlUShortToShort\n\n//\n// WORD -> INT8 conversion\n//\n#define RtlWordToInt8  RtlUShortToInt8\n\n//\n// WORD -> CHAR conversion\n//\n#define RtlWordToChar  RtlUShortToChar\n\n//\n// WORD -> UCHAR conversion\n//\n#define RtlWordToUChar RtlUShortToUChar\n\n//\n// WORD -> UINT8 conversion\n//\n#define RtlWordToUInt8 RtlUShortToUInt8\n\n//\n// WORD -> BYTE conversion\n//\n#define RtlWordToByte  RtlUShortToUInt8\n\n//\n// WORD -> SHORT conversion\n//\n#define RtlWordToShort RtlUShortToShort\n\n//\n// WORD -> INT16 conversion\n//\n#define RtlWordToInt16 RtlUShortToShort\n\n//\n// INT -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntToInt8(\n    _In_ INT iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= INT8_MIN) && (iOperand <= INT8_MAX))\n    {\n        *pi8Result = (INT8)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntToUChar(\n    _In_ INT iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= 0) && (iOperand <= 255))\n    {\n        *pch = (UCHAR)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlIntToChar(\n    _In_ INT iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlIntToUChar(iOperand, (UCHAR*)pch);\n#else\n    return RtlIntToInt8(iOperand, (INT8*)pch);\n#endif // _CHAR_UNSIGNED\n}\n\n//\n// INT -> BYTE conversion\n//\n#define RtlIntToByte   RtlIntToUInt8\n\n//\n// INT -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntToUInt8(\n    _In_ INT iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) UINT8* pui8Result)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= 0) && (iOperand <= UINT8_MAX))\n    {\n        *pui8Result = (UINT8)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pui8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntToShort(\n    _In_ INT iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= SHORT_MIN) && (iOperand <= SHORT_MAX))\n    {\n        *psResult = (SHORT)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT -> INT16 conversion\n//\n#define RtlIntToInt16  RtlIntToShort\n\n//\n// INT -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntToUShort(\n    _In_ INT iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= 0) && (iOperand <= USHORT_MAX))\n    {\n        *pusResult = (USHORT)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT -> UINT16 conversion\n//\n#define RtlIntToUInt16  RtlIntToUShort\n\n//\n// INT -> WORD conversion\n//\n#define RtlIntToWord   RtlIntToUShort\n\n//\n// INT -> UINT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntToUInt(\n    _In_ INT iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if (iOperand >= 0)\n    {\n        *puResult = (UINT)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT -> UINT_PTR conversion\n//\n#ifdef _WIN64\n#define RtlIntToUIntPtr    RtlIntToULongLong\n#else\n#define RtlIntToUIntPtr    RtlIntToUInt\n#endif\n\n//\n// INT -> ULONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntToULong(\n    _In_ INT iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if (iOperand >= 0)\n    {\n        *pulResult = (ULONG)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT -> ULONG_PTR conversion\n//\n#ifdef _WIN64\n#define RtlIntToULongPtr   RtlIntToULongLong\n#else\n#define RtlIntToULongPtr   RtlIntToULong\n#endif\n\n//\n// INT -> DWORD conversion\n//\n#define RtlIntToDWord  RtlIntToULong\n\n//\n// INT -> DWORD_PTR conversion\n//\n#define RtlIntToDWordPtr   RtlIntToULongPtr\n\n//\n// INT -> ULONGLONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntToULongLong(\n    _In_ INT iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n\n    if (iOperand >= 0)\n    {\n        *pullResult = (ULONGLONG)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT -> DWORDLONG conversion\n//\n#define RtlIntToDWordLong  RtlIntToULongLong\n\n//\n// INT -> ULONG64 conversion\n//\n#define RtlIntToULong64    RtlIntToULongLong\n\n//\n// INT -> DWORD64 conversion\n//\n#define RtlIntToDWord64    RtlIntToULongLong\n\n//\n// INT -> UINT64 conversion\n//\n#define RtlIntToUInt64 RtlIntToULongLong\n\n//\n// INT -> size_t conversion\n//\n#define RtlIntToSizeT  RtlIntToUIntPtr\n\n//\n// INT -> SIZE_T conversion\n//\n#define RtlIntToSIZET  RtlIntToULongPtr\n\n//\n// INT32 -> CHAR conversion\n//\n#define RtlInt32ToChar RtlIntToChar\n\n//\n// INT32 -> INT328 conversion\n//\n#define RtlInt32ToInt8 RtlIntToInt8\n\n//\n// INT32 -> UCHAR conversion\n//\n#define RtlInt32ToUChar    RtlIntToUChar\n\n//\n// INT32 -> BYTE conversion\n//\n#define RtlInt32ToByte RtlIntToUInt8\n\n//\n// INT32 -> UINT8 conversion\n//\n#define RtlInt32ToUInt8    RtlIntToUInt8\n\n//\n// INT32 -> SHORT conversion\n//\n#define RtlInt32ToShort    RtlIntToShort\n\n//\n// INT32 -> INT16 conversion\n//\n#define RtlInt32ToInt16    RtlIntToShort\n\n//\n// INT32 -> USHORT conversion\n//\n#define RtlInt32ToUShort   RtlIntToUShort\n\n//\n// INT32 -> UINT16 conversion\n//\n#define RtlInt32ToUInt16   RtlIntToUShort\n\n//\n// INT32 -> WORD conversion\n//\n#define RtlInt32ToWord RtlIntToUShort\n\n//\n// INT32 -> UINT conversion\n//\n#define RtlInt32ToUInt RtlIntToUInt\n\n//\n// INT32 -> UINT32 conversion\n//\n#define RtlInt32ToUInt32   RtlIntToUInt\n\n//\n// INT32 -> UINT_PTR conversion\n//\n#define RtlInt32ToUIntPtr  RtlIntToUIntPtr\n\n//\n// INT32 -> ULONG conversion\n//\n#define RtlInt32ToULong    RtlIntToULong\n\n//\n// INT32 -> ULONG_PTR conversion\n//\n#define RtlInt32ToULongPtr RtlIntToULongPtr\n\n//\n// INT32 -> DWORD conversion\n//\n#define RtlInt32ToDWord    RtlIntToULong\n\n//\n// INT32 -> DWORD_PTR conversion\n//\n#define RtlInt32ToDWordPtr RtlIntToULongPtr\n\n//\n// INT32 -> ULONGLONG conversion\n//\n#define RtlInt32ToULongLong    RtlIntToULongLong\n\n//\n// INT32 -> DWORDLONG conversion\n//\n#define RtlInt32ToDWordLong    RtlIntToULongLong\n\n//\n// INT32 -> ULONG64 conversion\n//\n#define RtlInt32ToULong64  RtlIntToULongLong\n\n//\n// INT32 -> DWORD64 conversion\n//\n#define RtlInt32ToDWord64  RtlIntToULongLong\n\n//\n// INT32 -> UINT64 conversion\n//\n#define RtlInt32ToUInt64   RtlIntToULongLong\n\n//\n// INT32 -> size_t conversion\n//\n#define RtlInt32ToSizeT    RtlIntToUIntPtr\n\n//\n// INT32 -> SIZE_T conversion\n//\n#define RtlInt32ToSIZET    RtlIntToULongPtr\n\n//\n// INT_PTR -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToInt8(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= INT8_MIN) && (iOperand <= INT8_MAX))\n    {\n        *pi8Result = (INT8)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT_PTR -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToUChar(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= 0) && (iOperand <= 255))\n    {\n        *pch = (UCHAR)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT_PTR -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlIntPtrToChar(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlIntPtrToUChar(iOperand, (UCHAR*)pch);\n#else\n    return RtlIntPtrToInt8(iOperand, (INT8*)pch);\n#endif // _CHAR_UNSIGNED\n}\n\n//\n// INT_PTR -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToUInt8(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) UINT8* pui8Result)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= 0) && (iOperand <= UINT8_MAX))\n    {\n        *pui8Result = (UINT8)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pui8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT_PTR -> BYTE conversion\n//\n#define RtlIntPtrToByte    RtlIntPtrToUInt8\n\n//\n// INT_PTR -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToShort(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= SHORT_MIN) && (iOperand <= SHORT_MAX))\n    {\n        *psResult = (SHORT)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT_PTR -> INT16 conversion\n//\n#define RtlIntPtrToInt16   RtlIntPtrToShort\n\n//\n// INT_PTR -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToUShort(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if ((iOperand >= 0) && (iOperand <= USHORT_MAX))\n    {\n        *pusResult = (USHORT)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// INT_PTR -> UINT16 conversion\n//\n#define RtlIntPtrToUInt16  RtlIntPtrToUShort\n\n//\n// INT_PTR -> WORD conversion\n//\n#define RtlIntPtrToWord    RtlIntPtrToUShort\n\n//\n// INT_PTR -> INT conversion\n//\n#ifdef _WIN64\n#define RtlIntPtrToInt RtlLongLongToInt\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToInt(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) INT* piResult)\n{\n    *piResult = (INT)iOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// INT_PTR -> INT32 conversion\n//\n#define RtlIntPtrToInt32   RtlIntPtrToInt\n\n//\n// INT_PTR -> UINT conversion\n//\n#ifdef _WIN64\n#define RtlIntPtrToUInt    RtlLongLongToUInt\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToUInt(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if (iOperand >= 0)\n    {\n        *puResult = (UINT)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif\n\n//\n// INT_PTR -> UINT32 conversion\n//\n#define RtlIntPtrToUInt32  RtlIntPtrToUInt\n\n//\n// INT_PTR -> UINT_PTR conversion\n//\n#ifdef _WIN64\n#define RtlIntPtrToUIntPtr RtlLongLongToULongLong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToUIntPtr(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) UINT_PTR* puResult)\n{\n    NTSTATUS status;\n\n    if (iOperand >= 0)\n    {\n        *puResult = (UINT_PTR)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif\n\n//\n// INT_PTR -> LONG conversion\n//\n#ifdef _WIN64\n#define RtlIntPtrToLong    RtlLongLongToLong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToLong(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) LONG* plResult)\n{\n    *plResult = (LONG)iOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// INT_PTR -> LONG_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToLongPtr(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) LONG_PTR* plResult)\n{\n    *plResult = (LONG_PTR)iOperand;\n    return STATUS_SUCCESS;\n}\n\n//\n// INT_PTR -> ULONG conversion\n//\n#ifdef _WIN64\n#define RtlIntPtrToULong   RtlLongLongToULong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToULong(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if (iOperand >= 0)\n    {\n        *pulResult = (ULONG)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif\n\n//\n// INT_PTR -> ULONG_PTR conversion\n//\n#ifdef _WIN64\n#define RtlIntPtrToULongPtr    RtlLongLongToULongLong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToULongPtr(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) ULONG_PTR* pulResult)\n{\n    NTSTATUS status;\n\n    if (iOperand >= 0)\n    {\n        *pulResult = (ULONG_PTR)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif\n\n//\n// INT_PTR -> DWORD conversion\n//\n#define RtlIntPtrToDWord   RtlIntPtrToULong\n\n//\n// INT_PTR -> DWORD_PTR conversion\n//\n#define RtlIntPtrToDWordPtr    RtlIntPtrToULongPtr\n\n//\n// INT_PTR -> ULONGLONG conversion\n//\n#ifdef _WIN64\n#define RtlIntPtrToULongLong   RtlLongLongToULongLong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrToULongLong(\n    _In_ INT_PTR iOperand,\n    _Out_ _Deref_out_range_(==, iOperand) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n\n    if (iOperand >= 0)\n    {\n        *pullResult = (ULONGLONG)iOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif\n\n//\n// INT_PTR -> DWORDLONG conversion\n//\n#define RtlIntPtrToDWordLong   RtlIntPtrToULongLong\n\n//\n// INT_PTR -> ULONG64 conversion\n//\n#define RtlIntPtrToULong64 RtlIntPtrToULongLong\n\n//\n// INT_PTR -> DWORD64 conversion\n//\n#define RtlIntPtrToDWord64 RtlIntPtrToULongLong\n\n//\n// INT_PTR -> UINT64 conversion\n//\n#define RtlIntPtrToUInt64  RtlIntPtrToULongLong\n\n//\n// INT_PTR -> size_t conversion\n//\n#define RtlIntPtrToSizeT   RtlIntPtrToUIntPtr\n\n//\n// INT_PTR -> SIZE_T conversion\n//\n#define RtlIntPtrToSIZET   RtlIntPtrToULongPtr\n\n//\n// UINT -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntToInt8(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if (uOperand <= INT8_MAX)\n    {\n        *pi8Result = (INT8)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntToUChar(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if (uOperand <= 255)\n    {\n        *pch = (UCHAR)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlUIntToChar(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlUIntToUChar(uOperand, (UCHAR*)pch);\n#else\n    return RtlUIntToInt8(uOperand, (INT8*)pch);\n#endif\n}\n\n//\n// UINT -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntToUInt8(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) UINT8* pui8Result)\n{\n    NTSTATUS status;\n\n    if (uOperand <= UINT8_MAX)\n    {\n        *pui8Result = (UINT8)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pui8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT -> BYTE conversion\n//\n#define RtlUIntToByte   RtlUIntToUInt8\n\n//\n// UINT -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntToShort(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= SHORT_MAX)\n    {\n        *psResult = (SHORT)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT -> INT16 conversion\n//\n#define RtlUIntToInt16 RtlUIntToShort\n\n//\n// UINT -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntToUShort(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= USHORT_MAX)\n    {\n        *pusResult = (USHORT)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT -> UINT16 conversion\n//\n#define RtlUIntToUInt16    RtlUIntToUShort\n\n//\n// UINT -> WORD conversion\n//\n#define RtlUIntToWord  RtlUIntToUShort\n\n//\n// UINT -> INT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntToInt(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) INT* piResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= INT_MAX)\n    {\n        *piResult = (INT)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *piResult = INT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT -> INT32 conversion\n//\n#define RtlUIntToInt32 RtlUIntToInt\n\n//\n// UINT -> INT_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntToIntPtr(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) INT_PTR* piResult)\n{\n    *piResult = uOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlUIntToIntPtr    RtlUIntToInt\n#endif\n\n//\n// UINT -> LONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntToLong(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) LONG* plResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= LONG_MAX)\n    {\n        *plResult = (LONG)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *plResult = LONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT -> LONG_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntToLongPtr(\n    _In_ UINT uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) LONG_PTR* plResult)\n{\n    *plResult = uOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlUIntToLongPtr   RtlUIntToLong\n#endif\n\n//\n// UINT -> ptrdiff_t conversion\n//\n#define RtlUIntToPtrdiffT  RtlUIntToIntPtr\n\n//\n// UINT -> SSIZE_T conversion\n//\n#define RtlUIntToSSIZET    RtlUIntToLongPtr\n\n//\n// UINT32 -> CHAR conversion\n//\n#define RtlUInt32ToChar    RtlUIntToChar\n\n//\n// UINT32 -> INT8 conversion\n//\n#define RtlUInt32ToInt8    RtlUIntToInt8\n\n//\n// UINT32 -> UCHAR conversion\n//\n#define RtlUInt32ToUChar   RtlUIntToUChar\n\n//\n// UINT32 -> UINT8 conversion\n//\n#define RtlUInt32ToUInt8   RtlUIntToUInt8\n\n//\n// UINT32 -> BYTE conversion\n//\n#define RtlUInt32ToByte    RtlUInt32ToUInt8\n\n//\n// UINT32 -> SHORT conversion\n//\n#define RtlUInt32ToShort   RtlUIntToShort\n\n//\n// UINT32 -> INT16 conversion\n//\n#define RtlUInt32ToInt16   RtlUIntToShort\n\n//\n// UINT32 -> USHORT conversion\n//\n#define RtlUInt32ToUShort  RtlUIntToUShort\n\n//\n// UINT32 -> UINT16 conversion\n//\n#define RtlUInt32ToUInt16  RtlUIntToUShort\n\n//\n// UINT32 -> WORD conversion\n//\n#define RtlUInt32ToWord    RtlUIntToUShort\n\n//\n// UINT32 -> INT conversion\n//\n#define RtlUInt32ToInt RtlUIntToInt\n\n//\n// UINT32 -> INT_PTR conversion\n//\n#define RtlUInt32ToIntPtr  RtlUIntToIntPtr\n\n//\n// UINT32 -> INT32 conversion\n//\n#define RtlUInt32ToInt32   RtlUIntToInt\n\n//\n// UINT32 -> LONG conversion\n//\n#define RtlUInt32ToLong    RtlUIntToLong\n\n//\n// UINT32 -> LONG_PTR conversion\n//\n#define RtlUInt32ToLongPtr RtlUIntToLongPtr\n\n//\n// UINT32 -> ptrdiff_t conversion\n//\n#define RtlUInt32ToPtrdiffT    RtlUIntToPtrdiffT\n\n//\n// UINT32 -> SSIZE_T conversion\n//\n#define RtlUInt32ToSSIZET  RtlUIntToSSIZET\n\n//\n// UINT_PTR -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToInt8(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if (uOperand <= INT8_MAX)\n    {\n        *pi8Result = (INT8)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToUChar(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if (uOperand <= 255)\n    {\n        *pch = (UCHAR)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlUIntPtrToChar(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlUIntPtrToUChar(uOperand, (UCHAR*)pch);\n#else\n    return RtlUIntPtrToInt8(uOperand, (INT8*)pch);\n#endif\n}\n\n//\n// UINT_PTR -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToUInt8(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==,uOperand) UINT8* pu8Result)\n{\n    NTSTATUS status;\n\n    if (uOperand <= UINT8_MAX)\n    {\n        *pu8Result = (UINT8)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pu8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> BYTE conversion\n//\n#define RtlUIntPtrToByte   RtlUIntPtrToUInt8\n\n//\n// UINT_PTR -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToShort(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= SHORT_MAX)\n    {\n        *psResult = (SHORT)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> INT16 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToInt16(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) INT16* pi16Result)\n{\n    NTSTATUS status;\n\n    if (uOperand <= INT16_MAX)\n    {\n        *pi16Result = (INT16)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi16Result = INT16_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToUShort(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= USHORT_MAX)\n    {\n        *pusResult = (USHORT)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> UINT16 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToUInt16(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) UINT16* pu16Result)\n{\n    NTSTATUS status;\n\n    if (uOperand <= UINT16_MAX)\n    {\n        *pu16Result = (UINT16)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pu16Result = UINT16_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> WORD conversion\n//\n#define RtlUIntPtrToWord   RtlUIntPtrToUShort\n\n//\n// UINT_PTR -> INT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToInt(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) INT* piResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= INT_MAX)\n    {\n        *piResult = (INT)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *piResult = INT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> INT32 conversion\n//\n#define RtlUIntPtrToInt32  RtlUIntPtrToInt\n\n//\n// UINT_PTR -> INT_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToIntPtr(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) INT_PTR* piResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= INT_PTR_MAX)\n    {\n        *piResult = (INT_PTR)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *piResult = INT_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> UINT conversion\n//\n#ifdef _WIN64\n#define RtlUIntPtrToUInt   RtlULongLongToUInt\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToUInt(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) UINT* puResult)\n{\n    *puResult = (UINT)uOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// UINT_PTR -> UINT32 conversion\n//\n#define RtlUIntPtrToUInt32 RtlUIntPtrToUInt\n\n//\n// UINT_PTR -> LONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToLong(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) LONG* plResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= LONG_MAX)\n    {\n        *plResult = (LONG)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *plResult = LONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> LONG_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToLongPtr(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) LONG_PTR* plResult)\n{\n    NTSTATUS status;\n\n    if (uOperand <= LONG_PTR_MAX)\n    {\n        *plResult = (LONG_PTR)uOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *plResult = LONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT_PTR -> ULONG conversion\n//\n#ifdef _WIN64\n#define RtlUIntPtrToULong  RtlULongLongToULong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToULong(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) ULONG* pulResult)\n{\n    *pulResult = (ULONG)uOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// UINT_PTR -> DWORD conversion\n//\n#define RtlUIntPtrToDWord  RtlUIntPtrToULong\n\n//\n// UINT_PTR -> LONGLONG conversion\n//\n#ifdef _WIN64\n#define RtlUIntPtrToLongLong   RtlULongLongToLongLong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrToLongLong(\n    _In_ UINT_PTR uOperand,\n    _Out_ _Deref_out_range_(==, uOperand) LONGLONG* pllResult)\n{\n    *pllResult = (LONGLONG)uOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// UINT_PTR -> LONG64 conversion\n//\n#define RtlUIntPtrToLong64 RtlUIntPtrToLongLong\n\n//\n// UINT_PTR -> RtlINT64 conversion\n//\n#define RtlUIntPtrToInt64  RtlUIntPtrToLongLong\n\n//\n// UINT_PTR -> ptrdiff_t conversion\n//\n#define RtlUIntPtrToPtrdiffT   RtlUIntPtrToIntPtr\n\n//\n// UINT_PTR -> SSIZE_T conversion\n//\n#define RtlUIntPtrToSSIZET RtlUIntPtrToLongPtr\n\n//\n// LONG -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToInt8(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= INT8_MIN) && (lOperand <= INT8_MAX))\n    {\n        *pi8Result = (INT8)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToUChar(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= 0) && (lOperand <= 255))\n    {\n        *pch = (UCHAR)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlLongToChar(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlLongToUChar(lOperand, (UCHAR*)pch);\n#else\n    return RtlLongToInt8(lOperand, (INT8*)pch);\n#endif\n}\n\n//\n// LONG -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToUInt8(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) UINT8* pui8Result)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= 0) && (lOperand <= UINT8_MAX))\n    {\n        *pui8Result = (UINT8)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pui8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG -> BYTE conversion\n//\n#define RtlLongToByte  RtlLongToUInt8\n\n//\n// LONG -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToShort(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= SHORT_MIN) && (lOperand <= SHORT_MAX))\n    {\n       *psResult = (SHORT)lOperand;\n       status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG -> INT16 conversion\n//\n#define RtlLongToInt16 RtlLongToShort\n\n//\n// LONG -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToUShort(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= 0) && (lOperand <= USHORT_MAX))\n    {\n        *pusResult = (USHORT)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG -> UINT16 conversion\n//\n#define RtlLongToUInt16    RtlLongToUShort\n\n//\n// LONG -> WORD conversion\n//\n#define RtlLongToWord  RtlLongToUShort\n\n//\n// LONG -> INT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToInt(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) INT* piResult)\n{\n    C_ASSERT(sizeof(INT) == sizeof(LONG));\n    *piResult = (INT)lOperand;\n    return STATUS_SUCCESS;\n}\n\n//\n// LONG -> INT32 conversion\n//\n#define RtlLongToInt32 RtlLongToInt\n\n//\n// LONG -> INT_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToIntPtr(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) INT_PTR* piResult)\n{\n    *piResult = lOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlLongToIntPtr    RtlLongToInt\n#endif\n\n//\n// LONG -> UINT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToUInt(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *puResult = (UINT)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG -> UINT32 conversion\n//\n#define RtlLongToUInt32    RtlLongToUInt\n\n//\n// LONG -> UINT_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToUIntPtr(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) UINT_PTR* puResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *puResult = (UINT_PTR)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#else\n#define RtlLongToUIntPtr   RtlLongToUInt\n#endif\n\n//\n// LONG -> ULONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToULong(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *pulResult = (ULONG)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG -> ULONG_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToULongPtr(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) ULONG_PTR* pulResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *pulResult = (ULONG_PTR)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#else\n#define RtlLongToULongPtr  RtlLongToULong\n#endif\n\n//\n// LONG -> DWORD conversion\n//\n#define RtlLongToDWord RtlLongToULong\n\n//\n// LONG -> DWORD_PTR conversion\n//\n#define RtlLongToDWordPtr  RtlLongToULongPtr\n\n//\n// LONG -> ULONGLONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongToULongLong(\n    _In_ LONG lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *pullResult = (ULONGLONG)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG -> DWORDLONG conversion\n//\n#define RtlLongToDWordLong RtlLongToULongLong\n\n//\n// LONG -> ULONG64 conversion\n//\n#define RtlLongToULong64   RtlLongToULongLong\n\n//\n// LONG -> DWORD64 conversion\n//\n#define RtlLongToDWord64   RtlLongToULongLong\n\n//\n// LONG -> UINT64 conversion\n//\n#define RtlLongToUInt64    RtlLongToULongLong\n\n//\n// LONG -> ptrdiff_t conversion\n//\n#define RtlLongToPtrdiffT  RtlLongToIntPtr\n\n//\n// LONG -> size_t conversion\n//\n#define RtlLongToSizeT RtlLongToUIntPtr\n\n//\n// LONG -> SIZE_T conversion\n//\n#define RtlLongToSIZET RtlLongToULongPtr\n\n//\n// LONG_PTR -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToInt8(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= INT8_MIN) && (lOperand <= INT8_MAX))\n    {\n        *pi8Result = (INT8)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG_PTR -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToUChar(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= 0) && (lOperand <= 255))\n    {\n        *pch = (UCHAR)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG_PTR -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlLongPtrToChar(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlLongPtrToUChar(lOperand, (UCHAR*)pch);\n#else\n    return RtlLongPtrToInt8(lOperand, (INT8*)pch);\n#endif\n}\n\n//\n// LONG_PTR -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToUInt8(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) UINT8* pui8Result)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= 0) && (lOperand <= UINT8_MAX))\n    {\n        *pui8Result = (UINT8)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pui8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG_PTR -> BYTE conversion\n//\n#define RtlLongPtrToByte   RtlLongPtrToUInt8\n\n//\n// LONG_PTR -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToShort(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= SHORT_MIN) && (lOperand <= SHORT_MAX))\n    {\n        *psResult = (SHORT)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG_PTR -> INT16 conversion\n//\n#define RtlLongPtrToInt16  RtlLongPtrToShort\n\n//\n// LONG_PTR -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToUShort(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if ((lOperand >= 0) && (lOperand <= USHORT_MAX))\n    {\n        *pusResult = (USHORT)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG_PTR -> UINT16 conversion\n//\n#define RtlLongPtrToUInt16 RtlLongPtrToUShort\n\n//\n// LONG_PTR -> WORD conversion\n//\n#define RtlLongPtrToWord   RtlLongPtrToUShort\n\n//\n// LONG_PTR -> INT conversion\n//\n#ifdef _WIN64\n#define RtlLongPtrToInt    RtlLongLongToInt\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToInt(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) INT* piResult)\n{\n    C_ASSERT(sizeof(INT) == sizeof(LONG_PTR));\n    *piResult = (INT)lOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// LONG_PTR -> INT32 conversion\n//\n#define RtlLongPtrToInt32  RtlLongPtrToInt\n\n//\n// LONG_PTR -> INT_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToIntPtr(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) INT_PTR* piResult)\n{\n    C_ASSERT(sizeof(LONG_PTR) == sizeof(INT_PTR));\n    *piResult = (INT_PTR)lOperand;\n    return STATUS_SUCCESS;\n}\n\n//\n// LONG_PTR -> UINT conversion\n//\n#ifdef _WIN64\n#define RtlLongPtrToUInt   RtlLongLongToUInt\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToUInt(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *puResult = (UINT)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif\n\n//\n// LONG_PTR -> UINT32 conversion\n//\n#define RtlLongPtrToUInt32 RtlLongPtrToUInt\n\n//\n// LONG_PTR -> UINT_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToUIntPtr(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) UINT_PTR* puResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *puResult = (UINT_PTR)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG_PTR -> LONG conversion\n//\n#ifdef _WIN64\n#define RtlLongPtrToLong   RtlLongLongToLong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToLong(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) LONG* plResult)\n{\n    *plResult = (LONG)lOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// LONG_PTR -> ULONG conversion\n//\n#ifdef _WIN64\n#define RtlLongPtrToULong  RtlLongLongToULong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToULong(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *pulResult = (ULONG)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif\n\n//\n// LONG_PTR -> ULONG_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToULongPtr(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) ULONG_PTR* pulResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *pulResult = (ULONG_PTR)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG_PTR -> DWORD conversion\n//\n#define RtlLongPtrToDWord  RtlLongPtrToULong\n\n//\n// LONG_PTR -> DWORD_PTR conversion\n//\n#define RtlLongPtrToDWordPtr   RtlLongPtrToULongPtr\n\n//\n// LONG_PTR -> ULONGLONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrToULongLong(\n    _In_ LONG_PTR lOperand,\n    _Out_ _Deref_out_range_(==, lOperand) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n\n    if (lOperand >= 0)\n    {\n        *pullResult = (ULONGLONG)lOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONG_PTR -> DWORDLONG conversion\n//\n#define RtlLongPtrToDWordLong  RtlLongPtrToULongLong\n\n//\n// LONG_PTR -> ULONG64 conversion\n//\n#define RtlLongPtrToULong64    RtlLongPtrToULongLong\n\n//\n// LONG_PTR -> DWORD64 conversion\n//\n#define RtlLongPtrToDWord64    RtlLongPtrToULongLong\n\n//\n// LONG_PTR -> UINT64 conversion\n//\n#define RtlLongPtrToUInt64 RtlLongPtrToULongLong\n\n//\n// LONG_PTR -> size_t conversion\n//\n#define RtlLongPtrToSizeT  RtlLongPtrToUIntPtr\n\n//\n// LONG_PTR -> SIZE_T conversion\n//\n#define RtlLongPtrToSIZET  RtlLongPtrToULongPtr\n\n//\n// ULONG -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToInt8(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= INT8_MAX)\n    {\n        *pi8Result = (INT8)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToUChar(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= 255)\n    {\n        *pch = (UCHAR)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlULongToChar(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlULongToUChar(ulOperand, (UCHAR*)pch);\n#else\n    return RtlULongToInt8(ulOperand, (INT8*)pch);\n#endif\n}\n\n//\n// ULONG -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToUInt8(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) UINT8* pui8Result)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= UINT8_MAX)\n    {\n        *pui8Result = (UINT8)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pui8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG -> BYTE conversion\n//\n#define RtlULongToByte RtlULongToUInt8\n\n//\n// ULONG -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToShort(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= SHORT_MAX)\n    {\n        *psResult = (SHORT)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG -> INT16 conversion\n//\n#define RtlULongToInt16    RtlULongToShort\n\n//\n// ULONG -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToUShort(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= USHORT_MAX)\n    {\n        *pusResult = (USHORT)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG -> UINT16 conversion\n//\n#define RtlULongToUInt16   RtlULongToUShort\n\n//\n// ULONG -> WORD conversion\n//\n#define RtlULongToWord RtlULongToUShort\n\n//\n// ULONG -> INT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToInt(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) INT* piResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= INT_MAX)\n    {\n        *piResult = (INT)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *piResult = INT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG -> INT32 conversion\n//\n#define RtlULongToInt32    RtlULongToInt\n\n//\n// ULONG -> INT_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToIntPtr(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) INT_PTR* piResult)\n{\n    *piResult = (INT_PTR)ulOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlULongToIntPtr   RtlULongToInt\n#endif\n\n//\n// ULONG -> UINT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToUInt(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) UINT* puResult)\n{\n    C_ASSERT(sizeof(ULONG) == sizeof(UINT));\n    *puResult = (UINT)ulOperand;\n    return STATUS_SUCCESS;\n}\n\n//\n// ULONG -> UINT32 conversion\n//\n#define RtlULongToUInt32   RtlULongToUInt\n\n//\n// ULONG -> UINT_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToUIntPtr(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) UINT_PTR* puiResult)\n{\n    C_ASSERT(sizeof(UINT_PTR) > sizeof(ULONG));\n    *puiResult = (UINT_PTR)ulOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlULongToUIntPtr  RtlULongToUInt\n#endif\n\n//\n// ULONG -> LONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToLong(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) LONG* plResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= LONG_MAX)\n    {\n        *plResult = (LONG)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *plResult = LONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG -> LONG_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongToLongPtr(\n    _In_ ULONG ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) LONG_PTR* plResult)\n{\n    C_ASSERT(sizeof(LONG_PTR) > sizeof(ULONG));\n    *plResult = (LONG_PTR)ulOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlULongToLongPtr  RtlULongToLong\n#endif\n\n//\n// ULONG -> ptrdiff_t conversion\n//\n#define RtlULongToPtrdiffT RtlULongToIntPtr\n\n//\n// ULONG -> SSIZE_T conversion\n//\n#define RtlULongToSSIZET   RtlULongToLongPtr\n\n//\n// ULONG_PTR -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToInt8(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= INT8_MAX)\n    {\n        *pi8Result = (INT8)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToUChar(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= 255)\n    {\n        *pch = (UCHAR)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlULongPtrToChar(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlULongPtrToUChar(ulOperand, (UCHAR*)pch);\n#else\n    return RtlULongPtrToInt8(ulOperand, (INT8*)pch);\n#endif\n}\n\n//\n// ULONG_PTR -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToUInt8(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) UINT8* pui8Result)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= UINT8_MAX)\n    {\n        *pui8Result = (UINT8)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pui8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR -> BYTE conversion\n//\n#define RtlULongPtrToByte  RtlULongPtrToUInt8\n\n//\n// ULONG_PTR -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToShort(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= SHORT_MAX)\n    {\n        *psResult = (SHORT)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR -> INT16 conversion\n//\n#define RtlULongPtrToInt16 RtlULongPtrToShort\n\n//\n// ULONG_PTR -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToUShort(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= USHORT_MAX)\n    {\n        *pusResult = (USHORT)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR -> UINT16 conversion\n//\n#define RtlULongPtrToUInt16    RtlULongPtrToUShort\n\n//\n// ULONG_PTR -> WORD conversion\n//\n#define RtlULongPtrToWord  RtlULongPtrToUShort\n\n//\n// ULONG_PTR -> INT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToInt(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) INT* piResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= INT_MAX)\n    {\n        *piResult = (INT)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *piResult = INT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR -> INT32 conversion\n//\n#define RtlULongPtrToInt32 RtlULongPtrToInt\n\n//\n// ULONG_PTR -> INT_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToIntPtr(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) INT_PTR* piResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= INT_PTR_MAX)\n    {\n        *piResult = (INT_PTR)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *piResult = INT_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR -> UINT conversion\n//\n#ifdef _WIN64\n#define RtlULongPtrToUInt  RtlULongLongToUInt\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToUInt(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) UINT* puResult)\n{\n    C_ASSERT(sizeof(ULONG_PTR) == sizeof(UINT));\n    *puResult = (UINT)ulOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// ULONG_PTR -> UINT32 conversion\n//\n#define RtlULongPtrToUInt32    RtlULongPtrToUInt\n\n//\n// ULONG_PTR -> UINT_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToUIntPtr(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) UINT_PTR* puResult)\n{\n    *puResult = (UINT_PTR)ulOperand;\n    return STATUS_SUCCESS;\n}\n\n//\n// ULONG_PTR -> LONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToLong(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) LONG* plResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= LONG_MAX)\n    {\n        *plResult = (LONG)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *plResult = LONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR -> LONG_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToLongPtr(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) LONG_PTR* plResult)\n{\n    NTSTATUS status;\n\n    if (ulOperand <= LONG_PTR_MAX)\n    {\n        *plResult = (LONG_PTR)ulOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *plResult = LONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR -> ULONG conversion\n//\n#ifdef _WIN64\n#define RtlULongPtrToULong RtlULongLongToULong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToULong(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) ULONG* pulResult)\n{\n    *pulResult = (ULONG)ulOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// ULONG_PTR -> DWORD conversion\n//\n#define RtlULongPtrToDWord RtlULongPtrToULong\n\n//\n// ULONG_PTR -> LONGLONG conversion\n//\n#ifdef _WIN64\n#define RtlULongPtrToLongLong  RtlULongLongToLongLong\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrToLongLong(\n    _In_ ULONG_PTR ulOperand,\n    _Out_ _Deref_out_range_(==, ulOperand) LONGLONG* pllResult)\n{\n    *pllResult = (LONGLONG)ulOperand;\n    return STATUS_SUCCESS;\n}\n#endif\n\n//\n// ULONG_PTR -> LONG64 conversion\n//\n#define RtlULongPtrToLong64    RtlULongPtrToLongLong\n\n//\n// ULONG_PTR -> RtlINT64\n//\n#define RtlULongPtrToInt64 RtlULongPtrToLongLong\n\n//\n// ULONG_PTR -> ptrdiff_t conversion\n//\n#define RtlULongPtrToPtrdiffT  RtlULongPtrToIntPtr\n\n//\n// ULONG_PTR -> SSIZE_T conversion\n//\n#define RtlULongPtrToSSIZET    RtlULongPtrToLongPtr\n\n//\n// DWORD -> INT8 conversion\n//\n#define RtlDWordToInt8 RtlULongToInt8\n\n//\n// DWORD -> CHAR conversion\n//\n#define RtlDWordToChar RtlULongToChar\n\n//\n// DWORD -> UCHAR conversion\n//\n#define RtlDWordToUChar    RtlULongToUChar\n\n//\n// DWORD -> UINT8 conversion\n//\n#define RtlDWordToUInt8    RtlULongToUInt8\n\n//\n// DWORD -> BYTE conversion\n//\n#define RtlDWordToByte RtlULongToUInt8\n\n//\n// DWORD -> SHORT conversion\n//\n#define RtlDWordToShort    RtlULongToShort\n\n//\n// DWORD -> INT16 conversion\n//\n#define RtlDWordToInt16    RtlULongToShort\n\n//\n// DWORD -> USHORT conversion\n//\n#define RtlDWordToUShort   RtlULongToUShort\n\n//\n// DWORD -> UINT16 conversion\n//\n#define RtlDWordToUInt16   RtlULongToUShort\n\n//\n// DWORD -> WORD conversion\n//\n#define RtlDWordToWord RtlULongToUShort\n\n//\n// DWORD -> INT conversion\n//\n#define RtlDWordToInt  RtlULongToInt\n\n//\n// DWORD -> INT32 conversion\n//\n#define RtlDWordToInt32    RtlULongToInt\n\n//\n// DWORD -> INT_PTR conversion\n//\n#define RtlDWordToIntPtr   RtlULongToIntPtr\n\n//\n// DWORD -> UINT conversion\n//\n#define RtlDWordToUInt RtlULongToUInt\n\n//\n// DWORD -> UINT32 conversion\n//\n#define RtlDWordToUInt32   RtlULongToUInt\n\n//\n// DWORD -> UINT_PTR conversion\n//\n#define RtlDWordToUIntPtr  RtlULongToUIntPtr\n\n//\n// DWORD -> LONG conversion\n//\n#define RtlDWordToLong RtlULongToLong\n\n//\n// DWORD -> LONG_PTR conversion\n//\n#define RtlDWordToLongPtr  RtlULongToLongPtr\n\n//\n// DWORD -> ptrdiff_t conversion\n//\n#define RtlDWordToPtrdiffT RtlULongToIntPtr\n\n//\n// DWORD -> SSIZE_T conversion\n//\n#define RtlDWordToSSIZET   RtlULongToLongPtr\n\n//\n// DWORD_PTR -> INT8 conversion\n//\n#define RtlDWordPtrToInt8  RtlULongPtrToInt8\n\n//\n// DWORD_PTR -> UCHAR conversion\n//\n#define RtlDWordPtrToUChar RtlULongPtrToUChar\n\n//\n// DWORD_PTR -> CHAR conversion\n//\n#define RtlDWordPtrToChar  RtlULongPtrToChar\n\n//\n// DWORD_PTR -> UINT8 conversion\n//\n#define RtlDWordPtrToUInt8 RtlULongPtrToUInt8\n\n//\n// DWORD_PTR -> BYTE conversion\n//\n#define RtlDWordPtrToByte  RtlULongPtrToUInt8\n\n//\n// DWORD_PTR -> SHORT conversion\n//\n#define RtlDWordPtrToShort RtlULongPtrToShort\n\n//\n// DWORD_PTR -> INT16 conversion\n//\n#define RtlDWordPtrToInt16 RtlULongPtrToShort\n\n//\n// DWORD_PTR -> USHORT conversion\n//\n#define RtlDWordPtrToUShort    RtlULongPtrToUShort\n\n//\n// DWORD_PTR -> UINT16 conversion\n//\n#define RtlDWordPtrToUInt16    RtlULongPtrToUShort\n\n//\n// DWORD_PTR -> WORD conversion\n//\n#define RtlDWordPtrToWord  RtlULongPtrToUShort\n\n//\n// DWORD_PTR -> INT conversion\n//\n#define RtlDWordPtrToInt   RtlULongPtrToInt\n\n//\n// DWORD_PTR -> INT32 conversion\n//\n#define RtlDWordPtrToInt32 RtlULongPtrToInt\n\n//\n// DWORD_PTR -> INT_PTR conversion\n//\n#define RtlDWordPtrToIntPtr    RtlULongPtrToIntPtr\n\n//\n// DWORD_PTR -> UINT conversion\n//\n#define RtlDWordPtrToUInt  RtlULongPtrToUInt\n\n//\n// DWORD_PTR -> UINT32 conversion\n//\n#define RtlDWordPtrToUInt32    RtlULongPtrToUInt\n\n//\n// DWODR_PTR -> UINT_PTR conversion\n//\n#define RtlDWordPtrToUIntPtr   RtlULongPtrToUIntPtr\n\n//\n// DWORD_PTR -> LONG conversion\n//\n#define RtlDWordPtrToLong  RtlULongPtrToLong\n\n//\n// DWORD_PTR -> LONG_PTR conversion\n//\n#define RtlDWordPtrToLongPtr   RtlULongPtrToLongPtr\n\n//\n// DWORD_PTR -> ULONG conversion\n//\n#define RtlDWordPtrToULong RtlULongPtrToULong\n\n//\n// DWORD_PTR -> DWORD conversion\n//\n#define RtlDWordPtrToDWord RtlULongPtrToULong\n\n//\n// DWORD_PTR -> LONGLONG conversion\n//\n#define RtlDWordPtrToLongLong  RtlULongPtrToLongLong\n\n//\n// DWORD_PTR -> LONG64 conversion\n//\n#define RtlDWordPtrToLong64    RtlULongPtrToLongLong\n\n//\n// DWORD_PTR -> RtlINT64 conversion\n//\n#define RtlDWordPtrToInt64 RtlULongPtrToLongLong\n\n//\n// DWORD_PTR -> ptrdiff_t conversion\n//\n#define RtlDWordPtrToPtrdiffT  RtlULongPtrToIntPtr\n\n//\n// DWORD_PTR -> SSIZE_T conversion\n//\n#define RtlDWordPtrToSSIZET    RtlULongPtrToLongPtr\n\n//\n// LONGLONG -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToInt8(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if ((llOperand >= INT8_MIN) && (llOperand <= INT8_MAX))\n    {\n        *pi8Result = (INT8)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToUChar(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if ((llOperand >= 0) && (llOperand <= 255))\n    {\n        *pch = (UCHAR)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlLongLongToChar(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlLongLongToUChar(llOperand, (UCHAR*)pch);\n#else\n    return RtlLongLongToInt8(llOperand, (INT8*)pch);\n#endif\n}\n\n//\n// LONGLONG -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToUInt8(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) UINT8* pu8Result)\n{\n    NTSTATUS status;\n\n    if ((llOperand >= 0) && (llOperand <= UINT8_MAX))\n    {\n        *pu8Result = (UINT8)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pu8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> BYTE conversion\n//\n#define RtlLongLongToByte  RtlLongLongToUInt8\n\n//\n// LONGLONG -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToShort(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if ((llOperand >= SHORT_MIN) && (llOperand <= SHORT_MAX))\n    {\n        *psResult = (SHORT)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> INT16 conversion\n//\n#define RtlLongLongToInt16 RtlLongLongToShort\n\n//\n// LONGLONG -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToUShort(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if ((llOperand >= 0) && (llOperand <= USHORT_MAX))\n    {\n        *pusResult = (USHORT)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> UINT16 conversion\n//\n#define RtlLongLongToUInt16    RtlLongLongToUShort\n\n//\n// LONGLONG -> WORD conversion\n//\n#define RtlLongLongToWord  RtlLongLongToUShort\n\n//\n// LONGLONG -> INT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToInt(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) INT* piResult)\n{\n    NTSTATUS status;\n\n    if ((llOperand >= INT_MIN) && (llOperand <= INT_MAX))\n    {\n        *piResult = (INT)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *piResult = INT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> INT32 conversion\n//\n#define RtlLongLongToInt32 RtlLongLongToInt\n\n//\n// LONGLONG -> INT_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToIntPtr(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) INT_PTR* piResult)\n{\n    *piResult = llOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlLongLongToIntPtr   RtlLongLongToInt\n#endif\n\n//\n// LONGLONG -> UINT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToUInt(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if ((llOperand >= 0) && (llOperand <= UINT_MAX))\n    {\n        *puResult = (UINT)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> UINT32 conversion\n//\n#define RtlLongLongToUInt32    RtlLongLongToUInt\n\n//\n// LONGLONG -> UINT_PTR conversion\n//\n#ifdef _WIN64\n#define RtlLongLongToUIntPtr  RtlLongLongToULongLong\n#else\n#define RtlLongLongToUIntPtr  RtlLongLongToUInt\n#endif\n\n//\n// LONGLONG -> LONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToLong(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) LONG* plResult)\n{\n    NTSTATUS status;\n\n    if ((llOperand >= LONG_MIN) && (llOperand <= LONG_MAX))\n    {\n        *plResult = (LONG)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *plResult = LONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> LONG_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToLongPtr(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) LONG_PTR* plResult)\n{\n    *plResult = (LONG_PTR)llOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlLongLongToLongPtr  RtlLongLongToLong\n#endif\n\n//\n// LONGLONG -> ULONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToULong(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if ((llOperand >= 0) && (llOperand <= ULONG_MAX))\n    {\n        *pulResult = (ULONG)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> ULONG_PTR conversion\n//\n#ifdef _WIN64\n#define RtlLongLongToULongPtr RtlLongLongToULongLong\n#else\n#define RtlLongLongToULongPtr RtlLongLongToULong\n#endif\n\n//\n// LONGLONG -> DWORD conversion\n//\n#define RtlLongLongToDWord    RtlLongLongToULong\n\n//\n// LONGLONG -> DWORD_PTR conversion\n//\n#define RtlLongLongToDWordPtr RtlLongLongToULongPtr\n\n//\n// LONGLONG -> ULONGLONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongToULongLong(\n    _In_ LONGLONG llOperand,\n    _Out_ _Deref_out_range_(==, llOperand) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n\n    if (llOperand >= 0)\n    {\n        *pullResult = (ULONGLONG)llOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// LONGLONG -> DWORDLONG conversion\n//\n#define RtlLongLongToDWordLong RtlLongLongToULongLong\n\n//\n// LONGLONG -> ULONG64 conversion\n//\n#define RtlLongLongToULong64   RtlLongLongToULongLong\n\n//\n// LONGLONG -> DWORD64 conversion\n//\n#define RtlLongLongToDWord64   RtlLongLongToULongLong\n\n//\n// LONGLONG -> UINT64 conversion\n//\n#define RtlLongLongToUInt64    RtlLongLongToULongLong\n\n//\n// LONGLONG -> ptrdiff_t conversion\n//\n#define RtlLongLongToPtrdiffT RtlLongLongToIntPtr\n\n//\n// LONGLONG -> size_t conversion\n//\n#define RtlLongLongToSizeT    RtlLongLongToUIntPtr\n\n//\n// LONGLONG -> SSIZE_T conversion\n//\n#define RtlLongLongToSSIZET   RtlLongLongToLongPtr\n\n//\n// LONGLONG -> SIZE_T conversion\n//\n#define RtlLongLongToSIZET    RtlLongLongToULongPtr\n\n//\n// LONG64 -> CHAR conversion\n//\n#define RtlLong64ToChar    RtlLongLongToChar\n\n//\n// LONG64 -> INT8 conversion\n//\n#define RtlLong64ToInt8    RtlLongLongToInt8\n\n//\n// LONG64 -> UCHAR conversion\n//\n#define RtlLong64ToUChar   RtlLongLongToUChar\n\n//\n// LONG64 -> UINT8 conversion\n//\n#define RtlLong64ToUInt8   RtlLongLongToUInt8\n\n//\n// LONG64 -> BYTE conversion\n//\n#define RtlLong64ToByte    RtlLongLongToUInt8\n\n//\n// LONG64 -> SHORT conversion\n//\n#define RtlLong64ToShort   RtlLongLongToShort\n\n//\n// LONG64 -> INT16 conversion\n//\n#define RtlLong64ToInt16   RtlLongLongToShort\n\n//\n// LONG64 -> USHORT conversion\n//\n#define RtlLong64ToUShort  RtlLongLongToUShort\n\n//\n// LONG64 -> UINT16 conversion\n//\n#define RtlLong64ToUInt16  RtlLongLongToUShort\n\n//\n// LONG64 -> WORD conversion\n//\n#define RtlLong64ToWord    RtlLongLongToUShort\n\n//\n// LONG64 -> INT conversion\n//\n#define RtlLong64ToInt RtlLongLongToInt\n\n//\n// LONG64 -> INT32 conversion\n//\n#define RtlLong64ToInt32   RtlLongLongToInt\n\n//\n// LONG64 -> INT_PTR conversion\n//\n#define RtlLong64ToIntPtr  RtlLongLongToIntPtr\n\n//\n// LONG64 -> UINT conversion\n//\n#define RtlLong64ToUInt    RtlLongLongToUInt\n\n//\n// LONG64 -> UINT32 conversion\n//\n#define RtlLong64ToUInt32  RtlLongLongToUInt\n\n//\n// LONG64 -> UINT_PTR conversion\n//\n#define RtlLong64ToUIntPtr RtlLongLongToUIntPtr\n\n//\n// LONG64 -> LONG conversion\n//\n#define RtlLong64ToLong    RtlLongLongToLong\n\n//\n// LONG64 -> LONG_PTR conversion\n//\n#define RtlLong64ToLongPtr RtlLongLongToLongPtr\n\n//\n// LONG64 -> ULONG conversion\n//\n#define RtlLong64ToULong   RtlLongLongToULong\n\n//\n// LONG64 -> ULONG_PTR conversion\n//\n#define RtlLong64ToULongPtr    RtlLongLongToULongPtr\n\n//\n// LONG64 -> DWORD conversion\n//\n#define RtlLong64ToDWord   RtlLongLongToULong\n\n//\n// LONG64 -> DWORD_PTR conversion\n//\n#define RtlLong64ToDWordPtr    RtlLongLongToULongPtr\n\n//\n// LONG64 -> ULONGLONG conversion\n//\n#define RtlLong64ToULongLong   RtlLongLongToULongLong\n\n//\n// LONG64 -> ptrdiff_t conversion\n//\n#define RtlLong64ToPtrdiffT    RtlLongLongToIntPtr\n\n//\n// LONG64 -> size_t conversion\n//\n#define RtlLong64ToSizeT   RtlLongLongToUIntPtr\n\n//\n// LONG64 -> SSIZE_T conversion\n//\n#define RtlLong64ToSSIZET  RtlLongLongToLongPtr\n\n//\n// LONG64 -> SIZE_T conversion\n//\n#define RtlLong64ToSIZET   RtlLongLongToULongPtr\n\n//\n// RtlINT64 -> CHAR conversion\n//\n#define RtlInt64ToChar RtlLongLongToChar\n\n//\n// RtlINT64 -> INT8 conversion\n//\n#define RtlInt64ToInt8 RtlLongLongToInt8\n\n//\n// RtlINT64 -> UCHAR conversion\n//\n#define RtlInt64ToUChar    RtlLongLongToUChar\n\n//\n// RtlINT64 -> UINT8 conversion\n//\n#define RtlInt64ToUInt8    RtlLongLongToUInt8\n\n//\n// RtlINT64 -> BYTE conversion\n//\n#define RtlInt64ToByte RtlLongLongToUInt8\n\n//\n// RtlINT64 -> SHORT conversion\n//\n#define RtlInt64ToShort    RtlLongLongToShort\n\n//\n// RtlINT64 -> INT16 conversion\n//\n#define RtlInt64ToInt16    RtlLongLongToShort\n\n//\n// RtlINT64 -> USHORT conversion\n//\n#define RtlInt64ToUShort   RtlLongLongToUShort\n\n//\n// RtlINT64 -> UINT16 conversion\n//\n#define RtlInt64ToUInt16   RtlLongLongToUShort\n\n//\n// RtlINT64 -> WORD conversion\n//\n#define RtlInt64ToWord RtlLongLongToUShort\n\n//\n// RtlINT64 -> INT conversion\n//\n#define RtlInt64ToInt  RtlLongLongToInt\n\n//\n// RtlINT64 -> INT32 conversion\n//\n#define RtlInt64ToInt32    RtlLongLongToInt\n\n//\n// RtlINT64 -> INT_PTR conversion\n//\n#define RtlInt64ToIntPtr   RtlLongLongToIntPtr\n\n//\n// RtlINT64 -> UINT conversion\n//\n#define RtlInt64ToUInt RtlLongLongToUInt\n\n//\n// RtlINT64 -> UINT32 conversion\n//\n#define RtlInt64ToUInt32   RtlLongLongToUInt\n\n//\n// RtlINT64 -> UINT_PTR conversion\n//\n#define RtlInt64ToUIntPtr  RtlLongLongToUIntPtr\n\n//\n// RtlINT64 -> LONG conversion\n//\n#define RtlInt64ToLong RtlLongLongToLong\n\n//\n// RtlINT64 -> LONG_PTR conversion\n//\n#define RtlInt64ToLongPtr  RtlLongLongToLongPtr\n\n//\n// RtlINT64 -> ULONG conversion\n//\n#define RtlInt64ToULong    RtlLongLongToULong\n\n//\n// RtlINT64 -> ULONG_PTR conversion\n//\n#define RtlInt64ToULongPtr RtlLongLongToULongPtr\n\n//\n// RtlINT64 -> DWORD conversion\n//\n#define RtlInt64ToDWord    RtlLongLongToULong\n\n//\n// RtlINT64 -> DWORD_PTR conversion\n//\n#define RtlInt64ToDWordPtr RtlLongLongToULongPtr\n\n//\n// RtlINT64 -> ULONGLONG conversion\n//\n#define RtlInt64ToULongLong    RtlLongLongToULongLong\n\n//\n// RtlINT64 -> DWORDLONG conversion\n//\n#define RtlInt64ToDWordLong    RtlLongLongToULongLong\n\n//\n// RtlINT64 -> ULONG64 conversion\n//\n#define RtlInt64ToULong64  RtlLongLongToULongLong\n\n//\n// RtlINT64 -> DWORD64 conversion\n//\n#define RtlInt64ToDWord64  RtlLongLongToULongLong\n\n//\n// RtlINT64 -> UINT64 conversion\n//\n#define RtlInt64ToUInt64   RtlLongLongToULongLong\n\n//\n// RtlINT64 -> ptrdiff_t conversion\n//\n#define RtlInt64ToPtrdiffT RtlLongLongToIntPtr\n\n//\n// RtlINT64 -> size_t conversion\n//\n#define RtlInt64ToSizeT    RtlLongLongToUIntPtr\n\n//\n// RtlINT64 -> SSIZE_T conversion\n//\n#define RtlInt64ToSSIZET   RtlLongLongToLongPtr\n\n//\n// RtlINT64 -> SIZE_T conversion\n//\n#define RtlInt64ToSIZET    RtlLongLongToULongPtr\n\n//\n// ULONGLONG -> INT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToInt8(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) INT8* pi8Result)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= INT8_MAX)\n    {\n        *pi8Result = (INT8)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pi8Result = INT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> UCHAR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToUChar(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) UCHAR* pch)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= 255)\n    {\n        *pch = (UCHAR)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pch = '\\0';\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> CHAR conversion\n//\n__forceinline\nNTSTATUS\nRtlULongLongToChar(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) CHAR* pch)\n{\n#ifdef _CHAR_UNSIGNED\n    return RtlULongLongToUChar(ullOperand, (UCHAR*)pch);\n#else\n    return RtlULongLongToInt8(ullOperand, (INT8*)pch);\n#endif\n}\n\n//\n// ULONGLONG -> UINT8 conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToUInt8(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) UINT8* pu8Result)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= UINT8_MAX)\n    {\n        *pu8Result = (UINT8)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pu8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> BYTE conversion\n//\n#define RtlULongLongToByte RtlULongLongToUInt8\n\n//\n// ULONGLONG -> SHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToShort(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) SHORT* psResult)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= SHORT_MAX)\n    {\n        *psResult = (SHORT)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *psResult = SHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> INT16 conversion\n//\n#define RtlULongLongToInt16    RtlULongLongToShort\n\n//\n// ULONGLONG -> USHORT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToUShort(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= USHORT_MAX)\n    {\n        *pusResult = (USHORT)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> UINT16 conversion\n//\n#define RtlULongLongToUInt16   RtlULongLongToUShort\n\n//\n// ULONGLONG -> WORD conversion\n//\n#define RtlULongLongToWord RtlULongLongToUShort\n\n//\n// ULONGLONG -> INT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToInt(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) INT* piResult)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= INT_MAX)\n    {\n        *piResult = (INT)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *piResult = INT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> INT32 conversion\n//\n#define RtlULongLongToInt32    RtlULongLongToInt\n\n//\n// ULONGLONG -> INT_PTR conversion\n//\n#ifdef _WIN64\n#define RtlULongLongToIntPtr   RtlULongLongToLongLong\n#else\n#define RtlULongLongToIntPtr   RtlULongLongToInt\n#endif\n\n//\n// ULONGLONG -> UINT conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToUInt(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= UINT_MAX)\n    {\n        *puResult = (UINT)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> UINT32 conversion\n//\n#define RtlULongLongToUInt32   RtlULongLongToUInt\n\n//\n// ULONGLONG -> UINT_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToUIntPtr(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) UINT_PTR* puResult)\n{\n    *puResult = ullOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlULongLongToUIntPtr  RtlULongLongToUInt\n#endif\n\n//\n// ULONGLONG -> LONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToLong(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) LONG* plResult)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= LONG_MAX)\n    {\n        *plResult = (LONG)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *plResult = LONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> LONG_PTR conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToLongPtr(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) LONG_PTR* plResult)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= LONG_PTR_MAX)\n    {\n        *plResult = (LONG_PTR)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *plResult = LONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> ULONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToULong(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= ULONG_MAX)\n    {\n        *pulResult = (ULONG)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> ULONG_PTR conversion\n//\n#ifdef _WIN64\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToULongPtr(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) ULONG_PTR* pulResult)\n{\n    *pulResult = ullOperand;\n    return STATUS_SUCCESS;\n}\n#else\n#define RtlULongLongToULongPtr RtlULongLongToULong\n#endif\n\n//\n// ULONGLONG -> DWORD conversion\n//\n#define RtlULongLongToDWord    RtlULongLongToULong\n\n//\n// ULONGLONG -> DWORD_PTR conversion\n//\n#define RtlULongLongToDWordPtr RtlULongLongToULongPtr\n\n//\n// ULONGLONG -> LONGLONG conversion\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongToLongLong(\n    _In_ ULONGLONG ullOperand,\n    _Out_ _Deref_out_range_(==, ullOperand) LONGLONG* pllResult)\n{\n    NTSTATUS status;\n\n    if (ullOperand <= LONGLONG_MAX)\n    {\n        *pllResult = (LONGLONG)ullOperand;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pllResult = LONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONGLONG -> RtlINT64 conversion\n//\n#define RtlULongLongToInt64    RtlULongLongToLongLong\n\n//\n// ULONGLONG -> LONG64 conversion\n//\n#define RtlULongLongToLong64   RtlULongLongToLongLong\n\n//\n// ULONGLONG -> ptrdiff_t conversion\n//\n#define RtlULongLongToPtrdiffT RtlULongLongToIntPtr\n\n//\n// ULONGLONG -> size_t conversion\n//\n#define RtlULongLongToSizeT    RtlULongLongToUIntPtr\n\n//\n// ULONGLONG -> SSIZE_T conversion\n//\n#define RtlULongLongToSSIZET   RtlULongLongToLongPtr\n\n//\n// ULONGLONG -> SIZE_T conversion\n//\n#define RtlULongLongToSIZET    RtlULongLongToULongPtr\n\n//\n// DWORDLONG -> CHAR conversion\n//\n#define RtlDWordLongToChar RtlULongLongToChar\n\n//\n// DWORDLONG -> INT8 conversion\n//\n#define RtlDWordLongToInt8 RtlULongLongToInt8\n\n//\n// DWORDLONG -> UCHAR conversion\n//\n#define RtlDWordLongToUChar    RtlULongLongToUChar\n\n//\n// DWORDLONG -> UINT8 conversion\n//\n#define RtlDWordLongToUInt8    RtlULongLongToUInt8\n\n//\n// DWORDLONG -> BYTE conversion\n//\n#define RtlDWordLongToByte RtlULongLongToUInt8\n\n//\n// DWORDLONG -> SHORT conversion\n//\n#define RtlDWordLongToShort    RtlULongLongToShort\n\n//\n// DWORDLONG -> INT16 conversion\n//\n#define RtlDWordLongToInt16    RtlULongLongToShort\n\n//\n// DWORDLONG -> USHORT conversion\n//\n#define RtlDWordLongToUShort   RtlULongLongToUShort\n\n//\n// DWORDLONG -> UINT16 conversion\n//\n#define RtlDWordLongToUInt16   RtlULongLongToUShort\n\n//\n// DWORDLONG -> WORD conversion\n//\n#define RtlDWordLongToWord RtlULongLongToUShort\n\n//\n// DWORDLONG -> INT conversion\n//\n#define RtlDWordLongToInt  RtlULongLongToInt\n\n//\n// DWORDLONG -> INT32 conversion\n//\n#define RtlDWordLongToInt32    RtlULongLongToInt\n\n//\n// DWORDLONG -> INT_PTR conversion\n//\n#define RtlDWordLongToIntPtr   RtlULongLongToIntPtr\n\n//\n// DWORDLONG -> UINT conversion\n//\n#define RtlDWordLongToUInt RtlULongLongToUInt\n\n//\n// DWORDLONG -> UINT32 conversion\n//\n#define RtlDWordLongToUInt32   RtlULongLongToUInt\n\n//\n// DWORDLONG -> UINT_PTR conversion\n//\n#define RtlDWordLongToUIntPtr  RtlULongLongToUIntPtr\n\n//\n// DWORDLONG -> LONG conversion\n//\n#define RtlDWordLongToLong RtlULongLongToLong\n\n//\n// DWORDLONG -> LONG_PTR conversion\n//\n#define RtlDWordLongToLongPtr  RtlULongLongToLongPtr\n\n//\n// DWORDLONG -> ULONG conversion\n//\n#define RtlDWordLongToULong    RtlULongLongToULong\n\n//\n// DWORDLONG -> ULONG_PTR conversion\n//\n#define RtlDWordLongToULongPtr RtlULongLongToULongPtr\n\n//\n// DWORDLONG -> DWORD conversion\n//\n#define RtlDWordLongToDWord    RtlULongLongToULong\n\n//\n// DWORDLONG -> DWORD_PTR conversion\n//\n#define RtlDWordLongToDWordPtr RtlULongLongToULongPtr\n\n//\n// DWORDLONG -> LONGLONG conversion\n//\n#define RtlDWordLongToLongLong RtlULongLongToLongLong\n\n//\n// DWORDLONG -> LONG64 conversion\n//\n#define RtlDWordLongToLong64   RtlULongLongToLongLong\n\n//\n// DWORDLONG -> RtlINT64 conversion\n//\n#define RtlDWordLongToInt64    RtlULongLongToLongLong\n\n//\n// DWORDLONG -> ptrdiff_t conversion\n//\n#define RtlDWordLongToPtrdiffT RtlULongLongToIntPtr\n\n//\n// DWORDLONG -> size_t conversion\n//\n#define RtlDWordLongToSizeT    RtlULongLongToUIntPtr\n\n//\n// DWORDLONG -> SSIZE_T conversion\n//\n#define RtlDWordLongToSSIZET   RtlULongLongToLongPtr\n\n//\n// DWORDLONG -> SIZE_T conversion\n//\n#define RtlDWordLongToSIZET    RtlULongLongToULongPtr\n\n//\n// ULONG64 -> CHAR conversion\n//\n#define RtlULong64ToChar   RtlULongLongToChar\n\n//\n// ULONG64 -> INT8 conversion\n//\n#define RtlULong64ToInt8   RtlULongLongToInt8\n\n//\n// ULONG64 -> UCHAR conversion\n//\n#define RtlULong64ToUChar  RtlULongLongToUChar\n\n//\n// ULONG64 -> UINT8 conversion\n//\n#define RtlULong64ToUInt8  RtlULongLongToUInt8\n\n//\n// ULONG64 -> BYTE conversion\n//\n#define RtlULong64ToByte   RtlULongLongToUInt8\n\n//\n// ULONG64 -> SHORT conversion\n//\n#define RtlULong64ToShort  RtlULongLongToShort\n\n//\n// ULONG64 -> INT16 conversion\n//\n#define RtlULong64ToInt16  RtlULongLongToShort\n\n//\n// ULONG64 -> USHORT conversion\n//\n#define RtlULong64ToUShort RtlULongLongToUShort\n\n//\n// ULONG64 -> UINT16 conversion\n//\n#define RtlULong64ToUInt16 RtlULongLongToUShort\n\n//\n// ULONG64 -> WORD conversion\n//\n#define RtlULong64ToWord   RtlULongLongToUShort\n\n//\n// ULONG64 -> INT conversion\n//\n#define RtlULong64ToInt    RtlULongLongToInt\n\n//\n// ULONG64 -> INT32 conversion\n//\n#define RtlULong64ToInt32  RtlULongLongToInt\n\n//\n// ULONG64 -> INT_PTR conversion\n//\n#define RtlULong64ToIntPtr RtlULongLongToIntPtr\n\n//\n// ULONG64 -> UINT conversion\n//\n#define RtlULong64ToUInt   RtlULongLongToUInt\n\n//\n// ULONG64 -> UINT32 conversion\n//\n#define RtlULong64ToUInt32 RtlULongLongToUInt\n\n//\n// ULONG64 -> UINT_PTR conversion\n//\n#define RtlULong64ToUIntPtr    RtlULongLongToUIntPtr\n\n//\n// ULONG64 -> LONG conversion\n//\n#define RtlULong64ToLong   RtlULongLongToLong\n\n//\n// ULONG64 -> LONG_PTR conversion\n//\n#define RtlULong64ToLongPtr    RtlULongLongToLongPtr\n\n//\n// ULONG64 -> ULONG conversion\n//\n#define RtlULong64ToULong  RtlULongLongToULong\n\n//\n// ULONG64 -> ULONG_PTR conversion\n//\n#define RtlULong64ToULongPtr   RtlULongLongToULongPtr\n\n//\n// ULONG64 -> DWORD conversion\n//\n#define RtlULong64ToDWord  RtlULongLongToULong\n\n//\n// ULONG64 -> DWORD_PTR conversion\n//\n#define RtlULong64ToDWordPtr   RtlULongLongToULongPtr\n\n//\n// ULONG64 -> LONGLONG conversion\n//\n#define RtlULong64ToLongLong   RtlULongLongToLongLong\n\n//\n// ULONG64 -> LONG64 conversion\n//\n#define RtlULong64ToLong64 RtlULongLongToLongLong\n\n//\n// ULONG64 -> RtlINT64 conversion\n//\n#define RtlULong64ToInt64  RtlULongLongToLongLong\n\n//\n// ULONG64 -> ptrdiff_t conversion\n//\n#define RtlULong64ToPtrdiffT   RtlULongLongToIntPtr\n\n//\n// ULONG64 -> size_t conversion\n//\n#define RtlULong64ToSizeT  RtlULongLongToUIntPtr\n\n//\n// ULONG64 -> SSIZE_T conversion\n//\n#define RtlULong64ToSSIZET RtlULongLongToLongPtr\n\n//\n// ULONG64 -> SIZE_T conversion\n//\n#define RtlULong64ToSIZET  RtlULongLongToULongPtr\n\n//\n// DWORD64 -> CHAR conversion\n//\n#define RtlDWord64ToChar   RtlULongLongToChar\n\n//\n// DWORD64 -> INT8 conversion\n//\n#define RtlDWord64ToInt8   RtlULongLongToInt8\n\n//\n// DWORD64 -> UCHAR conversion\n//\n#define RtlDWord64ToUChar  RtlULongLongToUChar\n\n//\n// DWORD64 -> UINT8 conversion\n//\n#define RtlDWord64ToUInt8  RtlULongLongToUInt8\n\n//\n// DWORD64 -> BYTE conversion\n//\n#define RtlDWord64ToByte   RtlULongLongToUInt8\n\n//\n// DWORD64 -> SHORT conversion\n//\n#define RtlDWord64ToShort  RtlULongLongToShort\n\n//\n// DWORD64 -> INT16 conversion\n//\n#define RtlDWord64ToInt16  RtlULongLongToShort\n\n//\n// DWORD64 -> USHORT conversion\n//\n#define RtlDWord64ToUShort RtlULongLongToUShort\n\n//\n// DWORD64 -> UINT16 conversion\n//\n#define RtlDWord64ToUInt16 RtlULongLongToUShort\n\n//\n// DWORD64 -> WORD conversion\n//\n#define RtlDWord64ToWord   RtlULongLongToUShort\n\n//\n// DWORD64 -> INT conversion\n//\n#define RtlDWord64ToInt    RtlULongLongToInt\n\n//\n// DWORD64 -> INT32 conversion\n//\n#define RtlDWord64ToInt32  RtlULongLongToInt\n\n//\n// DWORD64 -> INT_PTR conversion\n//\n#define RtlDWord64ToIntPtr RtlULongLongToIntPtr\n\n//\n// DWORD64 -> UINT conversion\n//\n#define RtlDWord64ToUInt   RtlULongLongToUInt\n\n//\n// DWORD64 -> UINT32 conversion\n//\n#define RtlDWord64ToUInt32 RtlULongLongToUInt\n\n//\n// DWORD64 -> UINT_PTR conversion\n//\n#define RtlDWord64ToUIntPtr    RtlULongLongToUIntPtr\n\n//\n// DWORD64 -> LONG conversion\n//\n#define RtlDWord64ToLong   RtlULongLongToLong\n\n//\n// DWORD64 -> LONG_PTR conversion\n//\n#define RtlDWord64ToLongPtr    RtlULongLongToLongPtr\n\n//\n// DWORD64 -> ULONG conversion\n//\n#define RtlDWord64ToULong  RtlULongLongToULong\n\n//\n// DWORD64 -> ULONG_PTR conversion\n//\n#define RtlDWord64ToULongPtr   RtlULongLongToULongPtr\n\n//\n// DWORD64 -> DWORD conversion\n//\n#define RtlDWord64ToDWord  RtlULongLongToULong\n\n//\n// DWORD64 -> DWORD_PTR conversion\n//\n#define RtlDWord64ToDWordPtr   RtlULongLongToULongPtr\n\n//\n// DWORD64 -> LONGLONG conversion\n//\n#define RtlDWord64ToLongLong   RtlULongLongToLongLong\n\n//\n// DWORD64 -> LONG64 conversion\n//\n#define RtlDWord64ToLong64 RtlULongLongToLongLong\n\n//\n// DWORD64 -> RtlINT64 conversion\n//\n#define RtlDWord64ToInt64  RtlULongLongToLongLong\n\n//\n// DWORD64 -> ptrdiff_t conversion\n//\n#define RtlDWord64ToPtrdiffT   RtlULongLongToIntPtr\n\n//\n// DWORD64 -> size_t conversion\n//\n#define RtlDWord64ToSizeT  RtlULongLongToUIntPtr\n\n//\n// DWORD64 -> SSIZE_T conversion\n//\n#define RtlDWord64ToSSIZET RtlULongLongToLongPtr\n\n//\n// DWORD64 -> SIZE_T conversion\n//\n#define RtlDWord64ToSIZET  RtlULongLongToULongPtr\n\n//\n// UINT64 -> CHAR conversion\n//\n#define RtlUInt64ToChar    RtlULongLongToChar\n\n//\n// UINT64 -> INT8 conversion\n//\n#define RtlUInt64ToInt8    RtlULongLongToInt8\n\n//\n// UINT64 -> UCHAR conversion\n//\n#define RtlUInt64ToUChar   RtlULongLongToUChar\n\n//\n// UINT64 -> UINT8 conversion\n//\n#define RtlUInt64ToUInt8   RtlULongLongToUInt8\n\n//\n// UINT64 -> BYTE conversion\n//\n#define RtlUInt64ToByte    RtlULongLongToUInt8\n\n//\n// UINT64 -> SHORT conversion\n//\n#define RtlUInt64ToShort   RtlULongLongToShort\n\n//\n// UINT64 -> INT16 conversion\n//\n//\n#define RtlUInt64ToInt16   RtlULongLongToShort\n\n//\n// UINT64 -> USHORT conversion\n//\n#define RtlUInt64ToUShort  RtlULongLongToUShort\n\n//\n// UINT64 -> UINT16 conversion\n//\n#define RtlUInt64ToUInt16  RtlULongLongToUShort\n\n//\n// UINT64 -> WORD conversion\n//\n#define RtlUInt64ToWord    RtlULongLongToUShort\n\n//\n// UINT64 -> INT conversion\n//\n#define RtlUInt64ToInt RtlULongLongToInt\n\n//\n// UINT64 -> INT32 conversion\n//\n#define RtlUInt64ToInt32   RtlULongLongToInt\n\n//\n// UINT64 -> INT_PTR conversion\n//\n#define RtlUInt64ToIntPtr  RtlULongLongToIntPtr\n\n//\n// UINT64 -> UINT conversion\n//\n#define RtlUInt64ToUInt    RtlULongLongToUInt\n\n//\n// UINT64 -> UINT32 conversion\n//\n#define RtlUInt64ToUInt32  RtlULongLongToUInt\n\n//\n// UINT64 -> UINT_PTR conversion\n//\n#define RtlUInt64ToUIntPtr RtlULongLongToUIntPtr\n\n//\n// UINT64 -> LONG conversion\n//\n#define RtlUInt64ToLong    RtlULongLongToLong\n\n//\n// UINT64 -> LONG_PTR conversion\n//\n#define RtlUInt64ToLongPtr RtlULongLongToLongPtr\n\n//\n// UINT64 -> ULONG conversion\n//\n#define RtlUInt64ToULong   RtlULongLongToULong\n\n//\n// UINT64 -> ULONG_PTR conversion\n//\n#define RtlUInt64ToULongPtr    RtlULongLongToULongPtr\n\n//\n// UINT64 -> DWORD conversion\n//\n#define RtlUInt64ToDWord   RtlULongLongToULong\n\n//\n// UINT64 -> DWORD_PTR conversion\n//\n#define RtlUInt64ToDWordPtr    RtlULongLongToULongPtr\n\n//\n// UINT64 -> LONGLONG conversion\n//\n#define RtlUInt64ToLongLong    RtlULongLongToLongLong\n\n//\n// UINT64 -> LONG64 conversion\n//\n#define RtlUInt64ToLong64  RtlULongLongToLongLong\n\n//\n// UINT64 -> RtlINT64 conversion\n//\n#define RtlUInt64ToInt64   RtlULongLongToLongLong\n\n//\n// UINT64 -> ptrdiff_t conversion\n//\n#define RtlUInt64ToPtrdiffT    RtlULongLongToIntPtr\n\n//\n// UINT64 -> size_t conversion\n//\n#define RtlUInt64ToSizeT   RtlULongLongToUIntPtr\n\n//\n// UINT64 -> SSIZE_T conversion\n//\n#define RtlUInt64ToSSIZET  RtlULongLongToLongPtr\n\n//\n// UINT64 -> SIZE_T conversion\n//\n#define RtlUInt64ToSIZET  RtlULongLongToULongPtr\n\n//\n// ptrdiff_t -> CHAR conversion\n//\n#define RtlPtrdiffTToChar  RtlIntPtrToChar\n\n//\n// ptrdiff_t -> INT8 conversion\n//\n#define RtlPtrdiffTToInt8  RtlIntPtrToInt8\n\n//\n// ptrdiff_t -> UCHAR conversion\n//\n#define RtlPtrdiffTToUChar RtlIntPtrToUChar\n\n//\n// ptrdiff_t -> UINT8 conversion\n//\n#define RtlPtrdiffTToUInt8 RtlIntPtrToUInt8\n\n//\n// ptrdiff_t -> BYTE conversion\n//\n#define RtlPtrdiffTToByte  RtlIntPtrToUInt8\n\n//\n// ptrdiff_t -> SHORT conversion\n//\n#define RtlPtrdiffTToShort RtlIntPtrToShort\n\n//\n// ptrdiff_t -> INT16 conversion\n//\n#define RtlPtrdiffTToInt16 RtlIntPtrToShort\n\n//\n// ptrdiff_t -> USHORT conversion\n//\n#define RtlPtrdiffTToUShort    RtlIntPtrToUShort\n\n//\n// ptrdiff_t -> UINT16 conversion\n//\n#define RtlPtrdiffTToUInt16    RtlIntPtrToUShort\n\n//\n// ptrdiff_t -> WORD conversion\n//\n#define RtlPtrdiffTToWord  RtlIntPtrToUShort\n\n//\n// ptrdiff_t -> INT conversion\n//\n#define RtlPtrdiffTToInt   RtlIntPtrToInt\n\n//\n// ptrdiff_t -> INT32 conversion\n//\n#define RtlPtrdiffTToInt32 RtlIntPtrToInt\n\n//\n// ptrdiff_t -> UINT conversion\n//\n#define RtlPtrdiffTToUInt  RtlIntPtrToUInt\n\n//\n// ptrdiff_t -> UINT32 conversion\n//\n#define RtlPtrdiffTToUInt32    RtlIntPtrToUInt\n\n//\n// ptrdiff_t -> UINT_PTR conversion\n//\n#define RtlPtrdiffTToUIntPtr   RtlIntPtrToUIntPtr\n\n//\n// ptrdiff_t -> LONG conversion\n//\n#define RtlPtrdiffTToLong  RtlIntPtrToLong\n\n//\n// ptrdiff_t -> LONG_PTR conversion\n//\n#define RtlPtrdiffTToLongPtr   RtlIntPtrToLongPtr\n\n//\n// ptrdiff_t -> ULONG conversion\n//\n#define RtlPtrdiffTToULong RtlIntPtrToULong\n\n//\n// ptrdiff_t -> ULONG_PTR conversion\n//\n#define RtlPtrdiffTToULongPtr  RtlIntPtrToULongPtr\n\n//\n// ptrdiff_t -> DWORD conversion\n//\n#define RtlPtrdiffTToDWord RtlIntPtrToULong\n\n//\n// ptrdiff_t -> DWORD_PTR conversion\n//\n#define RtlPtrdiffTToDWordPtr  RtlIntPtrToULongPtr\n\n//\n// ptrdiff_t -> ULONGLONG conversion\n//\n#define RtlPtrdiffTToULongLong RtlIntPtrToULongLong\n\n//\n// ptrdiff_t -> DWORDLONG conversion\n//\n#define RtlPtrdiffTToDWordLong RtlIntPtrToULongLong\n\n//\n// ptrdiff_t -> ULONG64 conversion\n//\n#define RtlPtrdiffTToULong64   RtlIntPtrToULongLong\n\n//\n// ptrdiff_t -> DWORD64 conversion\n//\n#define RtlPtrdiffTToDWord64   RtlIntPtrToULongLong\n\n//\n// ptrdiff_t -> UINT64 conversion\n//\n#define RtlPtrdiffTToUInt64    RtlIntPtrToULongLong\n\n//\n// ptrdiff_t -> size_t conversion\n//\n#define RtlPtrdiffTToSizeT RtlIntPtrToUIntPtr\n\n//\n// ptrdiff_t -> SIZE_T conversion\n//\n#define RtlPtrdiffTToSIZET RtlIntPtrToULongPtr\n\n//\n// size_t -> INT8 conversion\n//\n#define RtlSizeTToInt8 RtlUIntPtrToInt8\n\n//\n// size_t -> UCHAR conversion\n//\n#define RtlSizeTToUChar    RtlUIntPtrToUChar\n\n//\n// size_t -> CHAR conversion\n//\n#define RtlSizeTToChar RtlUIntPtrToChar\n\n//\n// size_t -> UINT8 conversion\n//\n#define RtlSizeTToUInt8    RtlUIntPtrToUInt8\n\n//\n// size_t -> BYTE conversion\n//\n#define RtlSizeTToByte RtlUIntPtrToUInt8\n\n//\n// size_t -> SHORT conversion\n//\n#define RtlSizeTToShort    RtlUIntPtrToShort\n\n//\n// size_t -> INT16 conversion\n//\n#define RtlSizeTToInt16    RtlUIntPtrToShort\n\n//\n// size_t -> USHORT conversion\n//\n#define RtlSizeTToUShort   RtlUIntPtrToUShort\n\n//\n// size_t -> UINT16 conversion\n//\n#define RtlSizeTToUInt16   RtlUIntPtrToUShort\n\n//\n// size_t -> WORD\n//\n#define RtlSizeTToWord RtlUIntPtrToUShort\n\n//\n// size_t -> INT conversion\n//\n#define RtlSizeTToInt  RtlUIntPtrToInt\n\n//\n// size_t -> INT32 conversion\n//\n#define RtlSizeTToInt32    RtlUIntPtrToInt\n\n//\n// size_t -> INT_PTR conversion\n//\n#define RtlSizeTToIntPtr   RtlUIntPtrToIntPtr\n\n//\n// size_t -> UINT conversion\n//\n#define RtlSizeTToUInt RtlUIntPtrToUInt\n\n//\n// size_t -> UINT32 conversion\n//\n#define RtlSizeTToUInt32   RtlUIntPtrToUInt\n\n//\n// size_t -> LONG conversion\n//\n#define RtlSizeTToLong RtlUIntPtrToLong\n\n//\n// size_t -> LONG_PTR conversion\n//\n#define RtlSizeTToLongPtr  RtlUIntPtrToLongPtr\n\n//\n// size_t -> ULONG conversion\n//\n#define RtlSizeTToULong    RtlUIntPtrToULong\n\n//\n// size_t -> DWORD conversion\n//\n#define RtlSizeTToDWord    RtlUIntPtrToULong\n\n//\n// size_t -> LONGLONG conversion\n//\n#define RtlSizeTToLongLong RtlUIntPtrToLongLong\n\n//\n// size_t -> LONG64 conversion\n//\n#define RtlSizeTToLong64   RtlUIntPtrToLongLong\n\n//\n// size_t -> RtlINT64\n//\n#define RtlSizeTToInt64    RtlUIntPtrToLongLong\n\n//\n// size_t -> ptrdiff_t conversion\n//\n#define RtlSizeTToPtrdiffT RtlUIntPtrToIntPtr\n\n//\n// size_t -> SSIZE_T conversion\n//\n#define RtlSizeTToSSIZET   RtlUIntPtrToLongPtr\n\n//\n// SSIZE_T -> INT8 conversion\n//\n#define RtlSSIZETToInt8    RtlLongPtrToInt8\n\n//\n// SSIZE_T -> UCHAR conversion\n//\n#define RtlSSIZETToUChar   RtlLongPtrToUChar\n\n//\n// SSIZE_T -> CHAR conversion\n//\n#define RtlSSIZETToChar    RtlLongPtrToChar\n\n//\n// SSIZE_T -> UINT8 conversion\n//\n#define RtlSSIZETToUInt8   RtlLongPtrToUInt8\n\n//\n// SSIZE_T -> BYTE conversion\n//\n#define RtlSSIZETToByte    RtlLongPtrToUInt8\n\n//\n// SSIZE_T -> SHORT conversion\n//\n#define RtlSSIZETToShort   RtlLongPtrToShort\n\n//\n// SSIZE_T -> INT16 conversion\n//\n#define RtlSSIZETToInt16   RtlLongPtrToShort\n\n//\n// SSIZE_T -> USHORT conversion\n//\n#define RtlSSIZETToUShort  RtlLongPtrToUShort\n\n//\n// SSIZE_T -> UINT16 conversion\n//\n#define RtlSSIZETToUInt16  RtlLongPtrToUShort\n\n//\n// SSIZE_T -> WORD conversion\n//\n#define RtlSSIZETToWord    RtlLongPtrToUShort\n\n//\n// SSIZE_T -> INT conversion\n//\n#define RtlSSIZETToInt RtlLongPtrToInt\n\n//\n// SSIZE_T -> INT32 conversion\n//\n#define RtlSSIZETToInt32   RtlLongPtrToInt\n\n//\n// SSIZE_T -> INT_PTR conversion\n//\n#define RtlSSIZETToIntPtr  RtlLongPtrToIntPtr\n\n//\n// SSIZE_T -> UINT conversion\n//\n#define RtlSSIZETToUInt    RtlLongPtrToUInt\n\n//\n// SSIZE_T -> UINT32 conversion\n//\n#define RtlSSIZETToUInt32  RtlLongPtrToUInt\n\n//\n// SSIZE_T -> UINT_PTR conversion\n//\n#define RtlSSIZETToUIntPtr RtlLongPtrToUIntPtr\n\n//\n// SSIZE_T -> LONG conversion\n//\n#define RtlSSIZETToLong    RtlLongPtrToLong\n\n//\n// SSIZE_T -> ULONG conversion\n//\n#define RtlSSIZETToULong   RtlLongPtrToULong\n\n//\n// SSIZE_T -> ULONG_PTR conversion\n//\n#define RtlSSIZETToULongPtr    RtlLongPtrToULongPtr\n\n//\n// SSIZE_T -> DWORD conversion\n//\n#define RtlSSIZETToDWord   RtlLongPtrToULong\n\n//\n// SSIZE_T -> DWORD_PTR conversion\n//\n#define RtlSSIZETToDWordPtr    RtlLongPtrToULongPtr\n\n//\n// SSIZE_T -> ULONGLONG conversion\n//\n#define RtlSSIZETToULongLong   RtlLongPtrToULongLong\n\n//\n// SSIZE_T -> DWORDLONG conversion\n//\n#define RtlSSIZETToDWordLong   RtlLongPtrToULongLong\n\n//\n// SSIZE_T -> ULONG64 conversion\n//\n#define RtlSSIZETToULong64 RtlLongPtrToULongLong\n\n//\n// SSIZE_T -> DWORD64 conversion\n//\n#define RtlSSIZETToDWord64 RtlLongPtrToULongLong\n\n//\n// SSIZE_T -> UINT64 conversion\n//\n#define RtlSSIZETToUInt64  RtlLongPtrToULongLong\n\n//\n// SSIZE_T -> size_t conversion\n//\n#define RtlSSIZETToSizeT   RtlLongPtrToUIntPtr\n\n//\n// SSIZE_T -> SIZE_T conversion\n//\n#define RtlSSIZETToSIZET   RtlLongPtrToULongPtr\n\n//\n// SIZE_T -> INT8 conversion\n//\n#define RtlSIZETToInt8 RtlULongPtrToInt8\n\n//\n// SIZE_T -> UCHAR conversion\n//\n#define RtlSIZETToUChar    RtlULongPtrToUChar\n\n//\n// SIZE_T -> CHAR conversion\n//\n#define RtlSIZETToChar RtlULongPtrToChar\n\n//\n// SIZE_T -> UINT8 conversion\n//\n#define RtlSIZETToUInt8    RtlULongPtrToUInt8\n\n//\n// SIZE_T -> BYTE conversion\n//\n#define RtlSIZETToByte RtlULongPtrToUInt8\n\n//\n// SIZE_T -> SHORT conversion\n//\n#define RtlSIZETToShort    RtlULongPtrToShort\n\n//\n// SIZE_T -> INT16 conversion\n//\n#define RtlSIZETToInt16    RtlULongPtrToShort\n\n//\n// SIZE_T -> USHORT conversion\n//\n#define RtlSIZETToUShort   RtlULongPtrToUShort\n\n//\n// SIZE_T -> UINT16 conversion\n//\n#define RtlSIZETToUInt16   RtlULongPtrToUShort\n\n//\n// SIZE_T -> WORD\n//\n#define RtlSIZETToWord RtlULongPtrToUShort\n\n//\n// SIZE_T -> INT conversion\n//\n#define RtlSIZETToInt  RtlULongPtrToInt\n\n//\n// SIZE_T -> INT32 conversion\n//\n#define RtlSIZETToInt32    RtlULongPtrToInt\n\n//\n// SIZE_T -> INT_PTR conversion\n//\n#define RtlSIZETToIntPtr   RtlULongPtrToIntPtr\n\n//\n// SIZE_T -> UINT conversion\n//\n#define RtlSIZETToUInt RtlULongPtrToUInt\n\n//\n// SIZE_T -> UINT32 conversion\n//\n#define RtlSIZETToUInt32   RtlULongPtrToUInt\n\n//\n// SIZE_T -> UINT_PTR conversion\n//\n#define RtlSIZETToUIntPtr  RtlULongPtrToUIntPtr\n\n//\n// SIZE_T -> LONG conversion\n//\n#define RtlSIZETToLong RtlULongPtrToLong\n\n//\n// SIZE_T -> LONG_PTR conversion\n//\n#define RtlSIZETToLongPtr  RtlULongPtrToLongPtr\n\n//\n// SIZE_T -> ULONG conversion\n//\n#define RtlSIZETToULong    RtlULongPtrToULong\n\n//\n// SIZE_T -> DWORD conversion\n//\n#define RtlSIZETToDWord    RtlULongPtrToULong\n\n//\n// SIZE_T -> LONGLONG conversion\n//\n#define RtlSIZETToLongLong RtlULongPtrToLongLong\n\n//\n// SIZE_T -> LONG64 conversion\n//\n#define RtlSIZETToLong64   RtlULongPtrToLongLong\n\n//\n// SIZE_T -> RtlINT64\n//\n#define RtlSIZETToInt64    RtlULongPtrToLongLong\n\n//\n// SIZE_T -> ptrdiff_t conversion\n//\n#define RtlSIZETToPtrdiffT RtlULongPtrToIntPtr\n\n//\n// SIZE_T -> SSIZE_T conversion\n//\n#define RtlSIZETToSSIZET   RtlULongPtrToLongPtr\n\n\n//=============================================================================\n// Addition functions\n//=============================================================================\n\n//\n// UINT8 addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUInt8Add(\n    _In_ UINT8 u8Augend,\n    _In_ UINT8 u8Addend,\n    _Out_ _Deref_out_range_(==, u8Augend + u8Addend) UINT8* pu8Result)\n{\n    NTSTATUS status;\n\n    if (((UINT8)(u8Augend + u8Addend)) >= u8Augend)\n    {\n        *pu8Result = (UINT8)(u8Augend + u8Addend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pu8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// USHORT addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUShortAdd(\n    _In_ USHORT usAugend,\n    _In_ USHORT usAddend,\n    _Out_ _Deref_out_range_(==, usAugend + usAddend) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if (((USHORT)(usAugend + usAddend)) >= usAugend)\n    {\n        *pusResult = (USHORT)(usAugend + usAddend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT16 addition\n//\n#define RtlUInt16Add   RtlUShortAdd\n\n//\n// WORD addition\n//\n#define RtlWordAdd     RtlUShortAdd\n\n//\n// UINT addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntAdd(\n    _In_ UINT uAugend,\n    _In_ UINT uAddend,\n    _Out_ _Deref_out_range_(==, uAugend + uAddend) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if ((uAugend + uAddend) >= uAugend)\n    {\n        *puResult = (uAugend + uAddend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT32 addition\n//\n#define RtlUInt32Add   RtlUIntAdd\n\n//\n// UINT_PTR addition\n//\n#ifdef _WIN64\n#define RtlUIntPtrAdd      RtlULongLongAdd\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrAdd(\n    _In_ UINT_PTR uAugend,\n    _In_ UINT_PTR uAddend,\n    _Out_ _Deref_out_range_(==, uAugend + uAddend) UINT_PTR* puResult)\n{\n    NTSTATUS status;\n\n    if ((uAugend + uAddend) >= uAugend)\n    {\n        *puResult = (uAugend + uAddend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif // _WIN64\n\n//\n// ULONG addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongAdd(\n    _In_ ULONG ulAugend,\n    _In_ ULONG ulAddend,\n    _Out_ _Deref_out_range_(==, ulAugend + ulAddend) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if ((ulAugend + ulAddend) >= ulAugend)\n    {\n        *pulResult = (ulAugend + ulAddend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR addition\n//\n#ifdef _WIN64\n#define RtlULongPtrAdd     RtlULongLongAdd\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrAdd(\n    _In_ ULONG_PTR ulAugend,\n    _In_ ULONG_PTR ulAddend,\n    _Out_ _Deref_out_range_(==, ulAugend + ulAddend) ULONG_PTR* pulResult)\n{\n    NTSTATUS status;\n\n    if ((ulAugend + ulAddend) >= ulAugend)\n    {\n        *pulResult = (ulAugend + ulAddend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif // _WIN64\n\n//\n// DWORD addition\n//\n#define RtlDWordAdd        RtlULongAdd\n\n//\n// DWORD_PTR addition\n//\n#ifdef _WIN64\n#define RtlDWordPtrAdd     RtlULongLongAdd\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlDWordPtrAdd(\n    _In_ DWORD_PTR dwAugend,\n    _In_ DWORD_PTR dwAddend,\n    _Out_ _Deref_out_range_(==, dwAugend + dwAddend) DWORD_PTR* pdwResult)\n{\n    NTSTATUS status;\n\n    if ((dwAugend + dwAddend) >= dwAugend)\n    {\n        *pdwResult = (dwAugend + dwAddend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pdwResult = DWORD_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif // _WIN64\n\n//\n// size_t addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlSizeTAdd(\n    _In_ size_t Augend,\n    _In_ size_t Addend,\n    _Out_ _Deref_out_range_(==, Augend + Addend) size_t* pResult)\n{\n    NTSTATUS status;\n\n    if ((Augend + Addend) >= Augend)\n    {\n        *pResult = (Augend + Addend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pResult = SIZE_T_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SIZE_T addition\n//\n#ifdef _WIN64\n#define RtlSIZETAdd      RtlULongLongAdd\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlSIZETAdd(\n    _In_ SIZE_T Augend,\n    _In_ SIZE_T Addend,\n    _Out_ _Deref_out_range_(==, Augend + Addend) SIZE_T* pResult)\n{\n    NTSTATUS status;\n\n    if ((Augend + Addend) >= Augend)\n    {\n        *pResult = (Augend + Addend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pResult = _SIZE_T_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif // _WIN64\n\n//\n// ULONGLONG addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongAdd(\n    _In_ ULONGLONG ullAugend,\n    _In_ ULONGLONG ullAddend,\n    _Out_ _Deref_out_range_(==, ullAugend + ullAddend) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n\n    if ((ullAugend + ullAddend) >= ullAugend)\n    {\n        *pullResult = (ullAugend + ullAddend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// DWORDLONG addition\n//\n#define RtlDWordLongAdd    RtlULongLongAdd\n\n//\n// ULONG64 addition\n//\n#define RtlULong64Add  RtlULongLongAdd\n\n//\n// DWORD64 addition\n//\n#define RtlDWord64Add  RtlULongLongAdd\n\n//\n// UINT64 addition\n//\n#define RtlUInt64Add   RtlULongLongAdd\n\n\n//=============================================================================\n// Subtraction functions\n//=============================================================================\n\n//\n// UINT8 subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUInt8Sub(\n    _In_ UINT8 u8Minuend,\n    _In_ UINT8 u8Subtrahend,\n    _Out_ _Deref_out_range_(==, u8Minuend - u8Subtrahend) UINT8* pu8Result)\n{\n    NTSTATUS status;\n\n    if (u8Minuend >= u8Subtrahend)\n    {\n        *pu8Result = (UINT8)(u8Minuend - u8Subtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pu8Result = UINT8_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// USHORT subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUShortSub(\n    _In_ USHORT usMinuend,\n    _In_ USHORT usSubtrahend,\n    _Out_ _Deref_out_range_(==, usMinuend - usSubtrahend) USHORT* pusResult)\n{\n    NTSTATUS status;\n\n    if (usMinuend >= usSubtrahend)\n    {\n        *pusResult = (USHORT)(usMinuend - usSubtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pusResult = USHORT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT16 subtraction\n//\n#define RtlUInt16Sub  RtlUShortSub\n\n//\n// WORD subtraction\n//\n#define RtlWordSub    RtlUShortSub\n\n\n//\n// UINT subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntSub(\n    _In_ UINT uMinuend,\n    _In_ UINT uSubtrahend,\n    _Out_ _Deref_out_range_(==, uMinuend - uSubtrahend) UINT* puResult)\n{\n    NTSTATUS status;\n\n    if (uMinuend >= uSubtrahend)\n    {\n        *puResult = (uMinuend - uSubtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// UINT32 subtraction\n//\n#define RtlUInt32Sub  RtlUIntSub\n\n//\n// UINT_PTR subtraction\n//\n#ifdef _WIN64\n#define RtlUIntPtrSub RtlULongLongSub\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrSub(\n    _In_ UINT_PTR uMinuend,\n    _In_ UINT_PTR uSubtrahend,\n    _Out_ _Deref_out_range_(==, uMinuend - uSubtrahend) UINT_PTR* puResult)\n{\n    NTSTATUS status;\n\n    if (uMinuend >= uSubtrahend)\n    {\n        *puResult = (uMinuend - uSubtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *puResult = UINT_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif // _WIN64\n\n//\n// ULONG subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongSub(\n    _In_ ULONG ulMinuend,\n    _In_ ULONG ulSubtrahend,\n    _Out_ _Deref_out_range_(==, ulMinuend - ulSubtrahend) ULONG* pulResult)\n{\n    NTSTATUS status;\n\n    if (ulMinuend >= ulSubtrahend)\n    {\n        *pulResult = (ulMinuend - ulSubtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// ULONG_PTR subtraction\n//\n#ifdef _WIN64\n#define RtlULongPtrSub RtlULongLongSub\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrSub(\n    _In_ ULONG_PTR ulMinuend,\n    _In_ ULONG_PTR ulSubtrahend,\n    _Out_ _Deref_out_range_(==, ulMinuend - ulSubtrahend) ULONG_PTR* pulResult)\n{\n    NTSTATUS status;\n\n    if (ulMinuend >= ulSubtrahend)\n    {\n        *pulResult = (ulMinuend - ulSubtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pulResult = ULONG_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif // _WIN64\n\n\n//\n// DWORD subtraction\n//\n#define RtlDWordSub       RtlULongSub\n\n//\n// DWORD_PTR subtraction\n//\n#ifdef _WIN64\n#define RtlDWordPtrSub    RtlULongLongSub\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlDWordPtrSub(\n    _In_ DWORD_PTR dwMinuend,\n    _In_ DWORD_PTR dwSubtrahend,\n    _Out_ _Deref_out_range_(==, dwMinuend - dwSubtrahend) DWORD_PTR* pdwResult)\n{\n    NTSTATUS status;\n\n    if (dwMinuend >= dwSubtrahend)\n    {\n        *pdwResult = (dwMinuend - dwSubtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pdwResult = DWORD_PTR_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif // _WIN64\n\n//\n// size_t subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlSizeTSub(\n    _In_ size_t Minuend,\n    _In_ size_t Subtrahend,\n    _Out_ _Deref_out_range_(==, Minuend - Subtrahend) size_t* pResult)\n{\n    NTSTATUS status;\n\n    if (Minuend >= Subtrahend)\n    {\n        *pResult = (Minuend - Subtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pResult = SIZE_T_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// SIZE_T subtraction\n//\n#ifdef _WIN64\n#define RtlSIZETSub   RtlULongLongSub\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlSIZETSub(\n    _In_ SIZE_T Minuend,\n    _In_ SIZE_T Subtrahend,\n    _Out_ _Deref_out_range_(==, Minuend - Subtrahend) SIZE_T* pResult)\n{\n    NTSTATUS status;\n\n    if (Minuend >= Subtrahend)\n    {\n        *pResult = (Minuend - Subtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pResult = _SIZE_T_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n#endif // _WIN64\n\n//\n// ULONGLONG subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongSub(\n    _In_ ULONGLONG ullMinuend,\n    _In_ ULONGLONG ullSubtrahend,\n    _Out_ _Deref_out_range_(==, ullMinuend - ullSubtrahend) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n\n    if (ullMinuend >= ullSubtrahend)\n    {\n        *pullResult = (ullMinuend - ullSubtrahend);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n\n    return status;\n}\n\n//\n// DWORDLONG subtraction\n//\n#define RtlDWordLongSub   RtlULongLongSub\n\n//\n// ULONG64 subtraction\n//\n#define RtlULong64Sub RtlULongLongSub\n\n//\n// DWORD64 subtraction\n//\n#define RtlDWord64Sub RtlULongLongSub\n\n//\n// UINT64 subtraction\n//\n#define RtlUInt64Sub  RtlULongLongSub\n\n\n//=============================================================================\n// Multiplication functions\n//=============================================================================\n\n//\n// UINT8 multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUInt8Mult(\n    _In_ UINT8 u8Multiplicand,\n    _In_ UINT8 u8Multiplier,\n    _Out_ _Deref_out_range_(==, u8Multiplicand * u8Multiplier) UINT8* pu8Result)\n{\n    UINT uResult = ((UINT)u8Multiplicand) * ((UINT)u8Multiplier);\n\n    return RtlUIntToUInt8(uResult, pu8Result);\n}\n\n//\n// USHORT multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUShortMult(\n    _In_ USHORT usMultiplicand,\n    _In_ USHORT usMultiplier,\n    _Out_ _Deref_out_range_(==, usMultiplicand * usMultiplier) USHORT* pusResult)\n{\n    ULONG ulResult = ((ULONG)usMultiplicand) * ((ULONG)usMultiplier);\n\n    return RtlULongToUShort(ulResult, pusResult);\n}\n\n//\n// UINT16 multiplication\n//\n#define RtlUInt16Mult  RtlUShortMult\n\n//\n// WORD multiplication\n//\n#define RtlWordMult    RtlUShortMult\n\n//\n// UINT multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntMult(\n    _In_ UINT uMultiplicand,\n    _In_ UINT uMultiplier,\n    _Out_ _Deref_out_range_(==, uMultiplicand * uMultiplier) UINT* puResult)\n{\n    ULONGLONG ull64Result = UInt32x32To64(uMultiplicand, uMultiplier);\n\n    return RtlULongLongToUInt(ull64Result, puResult);\n}\n\n//\n// UINT32 multiplication\n//\n#define RtlUInt32Mult  RtlUIntMult\n\n//\n// UINT_PTR multiplication\n//\n#ifdef _WIN64\n#define RtlUIntPtrMult     RtlULongLongMult\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlUIntPtrMult(\n    _In_ UINT_PTR uMultiplicand,\n    _In_ UINT_PTR uMultiplier,\n    _Out_ _Deref_out_range_(==, uMultiplicand * uMultiplier) UINT_PTR* puResult)\n{\n    ULONGLONG ull64Result = UInt32x32To64(uMultiplicand, uMultiplier);\n\n    return RtlULongLongToUIntPtr(ull64Result, puResult);\n}\n#endif // _WIN64\n\n//\n// ULONG multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongMult(\n    _In_ ULONG ulMultiplicand,\n    _In_ ULONG ulMultiplier,\n    _Out_ _Deref_out_range_(==, ulMultiplicand * ulMultiplier) ULONG* pulResult)\n{\n    ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier);\n\n    return RtlULongLongToULong(ull64Result, pulResult);\n}\n\n//\n// ULONG_PTR multiplication\n//\n#ifdef _WIN64\n#define RtlULongPtrMult    RtlULongLongMult\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongPtrMult(\n    _In_ ULONG_PTR ulMultiplicand,\n    _In_ ULONG_PTR ulMultiplier,\n    _Out_ _Deref_out_range_(==, ulMultiplicand * ulMultiplier) ULONG_PTR* pulResult)\n{\n    ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier);\n\n    return RtlULongLongToULongPtr(ull64Result, pulResult);\n}\n#endif // _WIN64\n\n//\n// DWORD multiplication\n//\n#define RtlDWordMult       RtlULongMult\n\n//\n// DWORD_PTR multiplication\n//\n#ifdef _WIN64\n#define RtlDWordPtrMult    RtlULongLongMult\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlDWordPtrMult(\n    _In_ DWORD_PTR dwMultiplicand,\n    _In_ DWORD_PTR dwMultiplier,\n    _Out_ _Deref_out_range_(==, dwMultiplicand * dwMultiplier) DWORD_PTR* pdwResult)\n{\n    ULONGLONG ull64Result = UInt32x32To64(dwMultiplicand, dwMultiplier);\n\n    return RtlULongLongToDWordPtr(ull64Result, pdwResult);\n}\n#endif // _WIN64\n\n//\n// size_t multiplication\n//\n\n#ifdef _WIN64\n#define RtlSizeTMult       RtlULongLongMult\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlSizeTMult(\n    _In_ size_t Multiplicand,\n    _In_ size_t Multiplier,\n    _Out_ _Deref_out_range_(==, Multiplicand * Multiplier) size_t* pResult)\n{\n    ULONGLONG ull64Result = UInt32x32To64(Multiplicand, Multiplier);\n\n    return RtlULongLongToSizeT(ull64Result, pResult);\n}\n#endif // _WIN64\n\n//\n// SIZE_T multiplication\n//\n#ifdef _WIN64\n#define RtlSIZETMult       RtlULongLongMult\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlSIZETMult(\n    _In_ SIZE_T Multiplicand,\n    _In_ SIZE_T Multiplier,\n    _Out_ _Deref_out_range_(==, Multiplicand * Multiplier) SIZE_T* pResult)\n{\n    ULONGLONG ull64Result = UInt32x32To64(Multiplicand, Multiplier);\n\n    return RtlULongLongToSIZET(ull64Result, pResult);\n}\n#endif // _WIN64\n\n//\n// ULONGLONG multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlULongLongMult(\n    _In_ ULONGLONG ullMultiplicand,\n    _In_ ULONGLONG ullMultiplier,\n    _Out_ _Deref_out_range_(==, ullMultiplicand * ullMultiplier) ULONGLONG* pullResult)\n{\n    NTSTATUS status;\n#if defined(_USE_INTRINSIC_MULTIPLY128)\n    ULONGLONG ullResultHigh;\n    ULONGLONG ullResultLow;\n\n    ullResultLow = UnsignedMultiply128(ullMultiplicand, ullMultiplier, &ullResultHigh);\n    if (ullResultHigh == 0)\n    {\n        _Analysis_assume_(ullMultiplicand * ullMultiplier == ullResultLow);\n        *pullResult = ullResultLow;\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        *pullResult = ULONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n#else\n    // 64x64 into 128 is like 32.32 x 32.32.\n    //\n    // a.b * c.d = a*(c.d) + .b*(c.d) = a*c + a*.d + .b*c + .b*.d\n    // back in non-decimal notation where A=a*2^32 and C=c*2^32:\n    // A*C + A*d + b*C + b*d\n    // So there are four components to add together.\n    //   result = (a*c*2^64) + (a*d*2^32) + (b*c*2^32) + (b*d)\n    //\n    // a * c must be 0 or there would be bits in the high 64-bits\n    // a * d must be less than 2^32 or there would be bits in the high 64-bits\n    // b * c must be less than 2^32 or there would be bits in the high 64-bits\n    // then there must be no overflow of the resulting values summed up.\n\n    ULONG dw_a;\n    ULONG dw_b;\n    ULONG dw_c;\n    ULONG dw_d;\n    ULONGLONG ad = 0;\n    ULONGLONG bc = 0;\n    ULONGLONG bd = 0;\n    ULONGLONG ullResult = 0;\n\n    status = STATUS_INTEGER_OVERFLOW;\n\n    dw_a = (ULONG)(ullMultiplicand >> 32);\n    dw_c = (ULONG)(ullMultiplier >> 32);\n\n    // common case -- if high dwords are both zero, no chance for overflow\n    if ((dw_a == 0) && (dw_c == 0))\n    {\n        dw_b = (DWORD)ullMultiplicand;\n        dw_d = (DWORD)ullMultiplier;\n\n        *pullResult = (((ULONGLONG)dw_b) * (ULONGLONG)dw_d);\n        status = STATUS_SUCCESS;\n    }\n    else\n    {\n        // a * c must be 0 or there would be bits set in the high 64-bits\n        if ((dw_a == 0) ||\n            (dw_c == 0))\n        {\n            dw_d = (DWORD)ullMultiplier;\n\n            // a * d must be less than 2^32 or there would be bits set in the high 64-bits\n            ad = (((ULONGLONG)dw_a) * (ULONGLONG)dw_d);\n            if ((ad & 0xffffffff00000000) == 0)\n            {\n                dw_b = (DWORD)ullMultiplicand;\n\n                // b * c must be less than 2^32 or there would be bits set in the high 64-bits\n                bc = (((ULONGLONG)dw_b) * (ULONGLONG)dw_c);\n                if ((bc & 0xffffffff00000000) == 0)\n                {\n                    // now sum them all up checking for overflow.\n                    // shifting is safe because we already checked for overflow above\n                    if (NT_SUCCESS(RtlULongLongAdd(bc << 32, ad << 32, &ullResult)))\n                    {\n                        // b * d\n                        bd = (((ULONGLONG)dw_b) * (ULONGLONG)dw_d);\n\n                        if (NT_SUCCESS(RtlULongLongAdd(ullResult, bd, &ullResult)))\n                        {\n                            *pullResult = ullResult;\n                            status = STATUS_SUCCESS;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        *pullResult = ULONGLONG_ERROR;\n    }\n#pragma warning(suppress:26071)\n#endif // _USE_INTRINSIC_MULTIPLY128\n    return status;\n}\n\n//\n// DWORDLONG multiplication\n//\n#define RtlDWordLongMult   RtlULongLongMult\n\n//\n// ULONG64 multiplication\n//\n#define RtlULong64Mult RtlULongLongMult\n\n//\n// DWORD64 multiplication\n//\n#define RtlDWord64Mult RtlULongLongMult\n\n//\n// UINT64 multiplication\n//\n#define RtlUInt64Mult  RtlULongLongMult\n\n\n/////////////////////////////////////////////////////////////////////////\n//\n// signed operations\n//\n// Strongly consider using unsigned numbers.\n//\n// Signed numbers are often used where unsigned numbers should be used.\n// For example file sizes and array indices should always be unsigned.\n// (File sizes should be 64bit integers; array indices should be size_t.)\n// Subtracting a larger positive signed number from a smaller positive\n// signed number with RtlIntSub will succeed, producing a negative number,\n// that then must not be used as an array index (but can occasionally be\n// used as a pointer index.) Similarly for adding a larger magnitude\n// negative number to a smaller magnitude positive number.\n//\n// intsafe.h does not protect you from such errors. It tells you if your\n// integer operations overflowed, not if you are doing the right thing\n// with your non-overflowed integers.\n//\n// Likewise you can overflow a buffer with a non-overflowed unsigned index.\n//\n#if defined(ENABLE_INTSAFE_SIGNED_FUNCTIONS)\n\n#if defined(_USE_INTRINSIC_MULTIPLY128)\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if !defined(_ARM64EC_)\n\n#define Multiply128 _mul128\n\n#else\n\n#define _mul128 Multiply128\n\n#endif // defined(_ARM64EC_)\n\nLONG64\nMultiply128(\n    _In_ LONG64 Multiplier,\n    _In_ LONG64  Multiplicand,\n    _Out_ LONG64 *HighProduct\n    );\n\n#if !defined(_ARM64EC_)\n\n#pragma intrinsic(_mul128)\n\n#endif // !defined(_ARM64EC_)\n\n#ifdef __cplusplus\n}\n#endif\n#endif // _USE_INTRINSIC_MULTIPLY128\n\n\n//=============================================================================\n// Signed addition functions\n//=============================================================================\n\n//\n// INT8 Addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8Add(\n    _In_ INT8 i8Augend,\n    _In_ INT8 i8Addend,\n    _Out_ _Deref_out_range_(==, i8Augend + i8Addend) INT8* pi8Result\n    )\n{\n    C_ASSERT(sizeof(LONG) > sizeof(INT8));\n    return RtlLongToInt8(((LONG)i8Augend) + ((LONG)i8Addend), pi8Result);\n}\n\n//\n// SHORT Addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortAdd(\n    _In_ SHORT sAugend,\n    _In_ SHORT sAddend,\n    _Out_ _Deref_out_range_(==, sAugend + sAddend) SHORT* psResult\n    )\n{\n    C_ASSERT(sizeof(LONG) > sizeof(SHORT));\n    return RtlLongToShort(((LONG)sAugend) + ((LONG)sAddend), psResult);\n}\n\n//\n// INT16 Addition\n//\n#define RtlInt16Add    RtlShortAdd\n\n//\n// INT Addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntAdd(\n    _In_ INT iAugend,\n    _In_ INT iAddend,\n    _Out_ _Deref_out_range_(==, iAugend + iAddend) INT* piResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(INT));\n    return RtlLongLongToInt(((LONGLONG)iAugend) + ((LONGLONG)iAddend), piResult);\n}\n\n//\n// INT32 Addition\n//\n#define RtlInt32Add    RtlIntAdd\n\n//\n// INT_PTR addition\n//\n#ifdef _WIN64\n#define RtlIntPtrAdd   RtlLongLongAdd\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrAdd(\n    _In_ INT_PTR iAugend,\n    _In_ INT_PTR iAddend,\n    _Out_ _Deref_out_range_(==, iAugend + iAddend) INT_PTR* piResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(INT_PTR));\n    return RtlLongLongToIntPtr(((LONGLONG)iAugend) + ((LONGLONG)iAddend), piResult);\n}\n#endif\n\n//\n// LONG Addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongAdd(\n    _In_ LONG lAugend,\n    _In_ LONG lAddend,\n    _Out_ _Deref_out_range_(==, lAugend + lAddend) LONG* plResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(LONG));\n    return RtlLongLongToLong(((LONGLONG)lAugend) + ((LONGLONG)lAddend), plResult);\n}\n\n//\n// LONG32 Addition\n//\n#define RtlLong32Add   RtlIntAdd\n\n//\n// LONG_PTR Addition\n//\n#ifdef _WIN64\n#define RtlLongPtrAdd   RtlLongLongAdd\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrAdd(\n    _In_ LONG_PTR lAugend,\n    _In_ LONG_PTR lAddend,\n    _Out_ _Deref_out_range_(==, lAugend + lAddend) LONG_PTR* plResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(LONG_PTR));\n    return RtlLongLongToLongPtr(((LONGLONG)lAugend) + ((LONGLONG)lAddend), plResult);\n}\n#endif\n\n//\n// LONGLONG Addition\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongAdd(\n    _In_ LONGLONG llAugend,\n    _In_ LONGLONG llAddend,\n    _Out_ _Deref_out_range_(==, llAugend + llAddend) LONGLONG* pllResult\n    )\n{\n    NTSTATUS status;\n    LONGLONG llResult = llAugend + llAddend;\n\n    //\n    // Adding positive to negative never overflows.\n    // If you add two positive numbers, you expect a positive result.\n    // If you add two negative numbers, you expect a negative result.\n    // Overflow if inputs are the same sign and output is not that sign.\n    //\n    if (((llAugend < 0) == (llAddend < 0))  &&\n        ((llAugend < 0) != (llResult < 0)))\n    {\n        *pllResult = LONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n    else\n    {\n        *pllResult = llResult;\n        status = STATUS_SUCCESS;\n    }\n\n    return status;\n}\n\n//\n// LONG64 Addition\n//\n#define RtlLong64Add   RtlLongLongAdd\n\n//\n// RtlINT64 Addition\n//\n#define RtlInt64Add    RtlLongLongAdd\n\n//\n// ptrdiff_t Addition\n//\n#ifdef _WIN64\n#define RtlPtrdiffTAdd RtlLongLongAdd\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlPtrdiffTAdd(\n    _In_ ptrdiff_t Augend,\n    _In_ ptrdiff_t Addend,\n    _Out_ _Deref_out_range_(==, Augend + Addend) ptrdiff_t* pResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(ptrdiff_t));\n    return RtlLongLongToPtrdiffT(((LONGLONG)Augend) + ((LONGLONG)Addend), pResult);\n}\n#endif\n\n//\n// SSIZE_T Addition\n//\n#ifdef _WIN64\n#define RtlSSIZETAdd   RtlLongLongAdd\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlSSIZETAdd(\n    _In_ SSIZE_T Augend,\n    _In_ SSIZE_T Addend,\n    _Out_ _Deref_out_range_(==, Augend + Addend) SSIZE_T* pResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(SSIZE_T));\n    return RtlLongLongToSSIZET(((LONGLONG)Augend) + ((LONGLONG)Addend), pResult);\n}\n#endif\n\n\n//=============================================================================\n// Signed subtraction functions\n//=============================================================================\n\n//\n// INT8 Subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8Sub(\n    _In_ INT8 i8Minuend,\n    _In_ INT8 i8Subtrahend,\n    _Out_ _Deref_out_range_(==, i8Minuend - i8Subtrahend) INT8* pi8Result\n    )\n{\n    C_ASSERT(sizeof(LONG) > sizeof(INT8));\n    return RtlLongToInt8(((LONG)i8Minuend) - ((LONG)i8Subtrahend), pi8Result);\n}\n\n//\n// SHORT Subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortSub(\n    _In_ SHORT sMinuend,\n    _In_ SHORT sSubtrahend,\n    _Out_ _Deref_out_range_(==, sMinuend - sSubtrahend) SHORT* psResult\n    )\n{\n    C_ASSERT(sizeof(LONG) > sizeof(SHORT));\n    return RtlLongToShort(((LONG)sMinuend) - ((LONG)sSubtrahend), psResult);\n}\n\n//\n// INT16 Subtraction\n//\n#define RtlInt16Sub   RtlShortSub\n\n//\n// INT Subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntSub(\n    _In_ INT iMinuend,\n    _In_ INT iSubtrahend,\n    _Out_ _Deref_out_range_(==, iMinuend - iSubtrahend) INT* piResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(INT));\n    return RtlLongLongToInt(((LONGLONG)iMinuend) - ((LONGLONG)iSubtrahend), piResult);\n}\n\n//\n// INT32 Subtraction\n//\n#define RtlInt32Sub   RtlIntSub\n\n//\n// INT_PTR Subtraction\n//\n#ifdef _WIN64\n#define RtlIntPtrSub  RtlLongLongSub\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrSub(\n    _In_ INT_PTR iMinuend,\n    _In_ INT_PTR iSubtrahend,\n    _Out_ _Deref_out_range_(==, iMinuend - iSubtrahend) INT_PTR* piResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(INT_PTR));\n    return RtlLongLongToIntPtr(((LONGLONG)iMinuend) - ((LONGLONG)iSubtrahend), piResult);\n}\n#endif\n\n//\n// LONG Subtraction\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongSub(\n    _In_ LONG lMinuend,\n    _In_ LONG lSubtrahend,\n    _Out_ _Deref_out_range_(==, lMinuend - lSubtrahend) LONG* plResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(LONG));\n    return RtlLongLongToLong(((LONGLONG)lMinuend) - ((LONGLONG)lSubtrahend), plResult);\n}\n\n//\n// LONG32 Subtraction\n//\n#define RtlLong32Sub  RtlIntSub\n\n//\n// LONG_PTR Subtraction\n//\n#ifdef _WIN64\n#define RtlLongPtrSub  RtlLongLongSub\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrSub(\n    _In_ LONG_PTR lMinuend,\n    _In_ LONG_PTR lSubtrahend,\n    _Out_ _Deref_out_range_(==, lMinuend - lSubtrahend) LONG_PTR* plResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(LONG_PTR));\n    return RtlLongLongToLongPtr(((LONGLONG)lMinuend) - ((LONGLONG)lSubtrahend), plResult);\n}\n#endif\n\n//\n// RtlLongLongSub\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongSub(\n    _In_ LONGLONG llMinuend,\n    _In_ LONGLONG llSubtrahend,\n    _Out_ _Deref_out_range_(==, llMinuend - llSubtrahend) LONGLONG* pllResult\n    )\n{\n    NTSTATUS status;\n    LONGLONG llResult = llMinuend - llSubtrahend;\n\n    //\n    // Subtracting a positive number from a positive number never overflows.\n    // Subtracting a negative number from a negative number never overflows.\n    // If you subtract a negative number from a positive number, you expect a positive result.\n    // If you subtract a positive number from a negative number, you expect a negative result.\n    // Overflow if inputs vary in sign and the output does not have the same sign as the first input.\n    //\n    if (((llMinuend < 0) != (llSubtrahend < 0)) &&\n        ((llMinuend < 0) != (llResult < 0)))\n    {\n        *pllResult = LONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n    else\n    {\n        *pllResult = llResult;\n        status = STATUS_SUCCESS;\n    }\n\n    return status;\n}\n\n//\n// LONG64 Subtraction\n//\n#define RtlLong64Sub  RtlLongLongSub\n\n//\n// RtlINT64 Subtraction\n//\n#define RtlInt64Sub   RtlLongLongSub\n\n//\n// ptrdiff_t Subtraction\n//\n#ifdef _WIN64\n#define RtlPtrdiffTSub RtlLongLongSub\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlPtrdiffTSub(\n    _In_ ptrdiff_t Minuend,\n    _In_ ptrdiff_t Subtrahend,\n    _Out_ _Deref_out_range_(==, Minuend - Subtrahend) ptrdiff_t* pResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(ptrdiff_t));\n    return RtlLongLongToPtrdiffT(((LONGLONG)Minuend) - ((LONGLONG)Subtrahend), pResult);\n}\n#endif\n\n//\n// SSIZE_T Subtraction\n//\n#ifdef _WIN64\n#define RtlSSIZETSub  RtlLongLongSub\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlSSIZETSub(\n    _In_ SSIZE_T Minuend,\n    _In_ SSIZE_T Subtrahend,\n    _Out_ _Deref_out_range_(==, Minuend - Subtrahend) SSIZE_T* pResult)\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(SSIZE_T));\n    return RtlLongLongToSSIZET(((LONGLONG)Minuend) - ((LONGLONG)Subtrahend), pResult);\n}\n#endif\n\n\n//=============================================================================\n// Signed multiplication functions\n//=============================================================================\n\n//\n// INT8 multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlInt8Mult(\n    _In_ INT8 i8Multiplicand,\n    _In_ INT8 i8Multiplier,\n    _Out_ _Deref_out_range_(==, i8Multiplicand * i8Multiplier) INT8* pi8Result\n    )\n{\n    C_ASSERT(sizeof(LONG) > sizeof(INT8));\n    return RtlLongToInt8(((LONG)i8Multiplier) * ((LONG)i8Multiplicand), pi8Result);\n}\n\n//\n// SHORT multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlShortMult(\n    _In_ SHORT sMultiplicand,\n    _In_ SHORT sMultiplier,\n    _Out_ _Deref_out_range_(==, sMultiplicand * sMultiplier) SHORT* psResult\n    )\n{\n    C_ASSERT(sizeof(LONG) > sizeof(SHORT));\n    return RtlLongToShort(((LONG)sMultiplicand) * ((LONG)sMultiplier), psResult);\n}\n\n//\n// INT16 multiplication\n//\n#define RtlInt16Mult   RtlShortMult\n\n//\n// INT multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntMult(\n    _In_ INT iMultiplicand,\n    _In_ INT iMultiplier,\n    _Out_ _Deref_out_range_(==, iMultiplicand * iMultiplier) INT* piResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(INT));\n    return RtlLongLongToInt(((LONGLONG)iMultiplicand) * ((LONGLONG)iMultiplier), piResult);\n}\n\n//\n// INT32 multiplication\n//\n#define RtlInt32Mult   RtlIntMult\n\n//\n// INT_PTR multiplication\n//\n#ifdef _WIN64\n#define RtlIntPtrMult   RtlLongLongMult\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlIntPtrMult(\n    _In_ INT_PTR iMultiplicand,\n    _In_ INT_PTR iMultiplier,\n    _Out_ _Deref_out_range_(==, iMultiplicand * iMultiplier) INT_PTR* piResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(INT_PTR));\n    return RtlLongLongToIntPtr(((LONGLONG)iMultiplicand) * ((LONGLONG)iMultiplier), piResult);\n}\n#endif\n\n//\n// LONG multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongMult(\n    _In_ LONG lMultiplicand,\n    _In_ LONG lMultiplier,\n    _Out_ _Deref_out_range_(==, lMultiplicand * lMultiplier) LONG* plResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(LONG));\n    return RtlLongLongToLong(((LONGLONG)lMultiplicand) * ((LONGLONG)lMultiplier), plResult);\n}\n\n//\n// LONG32 multiplication\n//\n#define RtlLong32Mult  RtlIntMult\n\n//\n// LONG_PTR multiplication\n//\n#ifdef _WIN64\n#define RtlLongPtrMult RtlLongLongMult\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongPtrMult(\n    _In_ LONG_PTR lMultiplicand,\n    _In_ LONG_PTR lMultiplier,\n    _Out_ _Deref_out_range_(==, lMultiplicand * lMultiplier) LONG_PTR* plResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(LONG_PTR));\n    return RtlLongLongToLongPtr(((LONGLONG)lMultiplicand) * ((LONGLONG)lMultiplier), plResult);\n}\n#endif\n\n//\n// LONGLONG multiplication\n//\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlLongLongMult(\n    _In_ LONGLONG llMultiplicand,\n    _In_ LONGLONG llMultiplier,\n    _Out_ _Deref_out_range_(==, llMultiplicand * llMultiplier) LONGLONG* pllResult\n    )\n{\n    NTSTATUS status;\n\n#if defined(_USE_INTRINSIC_MULTIPLY128)\n    LONGLONG llResultHigh;\n    LONGLONG llResultLow;\n\n    llResultLow = Multiply128(llMultiplicand, llMultiplier, &llResultHigh);\n\n    if (((llResultLow < 0) && (llResultHigh != -1))    ||\n        ((llResultLow >= 0) && (llResultHigh != 0)))\n    {\n        *pllResult = LONGLONG_ERROR;\n        status = STATUS_INTEGER_OVERFLOW;\n    }\n    else\n    {\n        *pllResult = llResultLow;\n        status = STATUS_SUCCESS;\n    }\n#else // _USE_INTRINSIC_MULTIPLY128\n    //\n    // Split into sign and magnitude, do unsigned operation, apply sign.\n    //\n\n    ULONGLONG ullMultiplicand;\n    ULONGLONG ullMultiplier;\n    ULONGLONG ullResult;\n    const ULONGLONG LONGLONG_MIN_MAGNITUDE = ((((ULONGLONG) - (LONGLONG_MIN + 1))) + 1);\n\n    if (llMultiplicand < 0)\n    {\n        //\n        // Avoid negating the most negative number.\n        //\n        ullMultiplicand = ((ULONGLONG)(- (llMultiplicand + 1))) + 1;\n    }\n    else\n    {\n        ullMultiplicand = (ULONGLONG)llMultiplicand;\n    }\n\n    if (llMultiplier < 0)\n    {\n        //\n        // Avoid negating the most negative number.\n        //\n        ullMultiplier = ((ULONGLONG)(- (llMultiplier + 1))) + 1;\n    }\n    else\n    {\n        ullMultiplier = (ULONGLONG)llMultiplier;\n    }\n\n    status = RtlULongLongMult(ullMultiplicand, ullMultiplier, &ullResult);\n    if (NT_SUCCESS(status))\n    {\n        if ((llMultiplicand < 0) != (llMultiplier < 0))\n        {\n            if (ullResult > LONGLONG_MIN_MAGNITUDE)\n            {\n                *pllResult = LONGLONG_ERROR;\n                status = STATUS_INTEGER_OVERFLOW;\n            }\n            else\n            {\n                *pllResult = - ((LONGLONG)ullResult);\n            }\n        }\n        else\n        {\n            if (ullResult > LONGLONG_MAX)\n            {\n                *pllResult = LONGLONG_ERROR;\n                status = STATUS_INTEGER_OVERFLOW;\n            }\n            else\n            {\n                *pllResult = (LONGLONG)ullResult;\n            }\n        }\n    }\n    else\n    {\n        *pllResult = LONGLONG_ERROR;\n    }\n#endif // _USE_INTRINSIC_MULTIPLY128\n\n    return status;\n}\n\n//\n// LONG64 multiplication\n//\n#define RtlLong64Mult  RtlLongLongMult\n\n//\n// RtlINT64 multiplication\n//\n#define RtlInt64Mult   RtlLongLongMult\n\n//\n// ptrdiff_t multiplication\n//\n#ifdef _WIN64\n#define RtlPtrdiffTMult    RtlLongLongMult\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlPtrdiffTMult(\n    _In_ ptrdiff_t Multiplicand,\n    _In_ ptrdiff_t Multiplier,\n    _Out_ _Deref_out_range_(==, Multiplicand * Multiplier) ptrdiff_t* pResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(ptrdiff_t));\n    return RtlLongLongToPtrdiffT(((LONGLONG)Multiplicand) * ((LONGLONG)Multiplier), pResult);\n}\n#endif\n\n//\n// SSIZE_T multiplication\n//\n#ifdef _WIN64\n#define RtlSSIZETMult  RtlLongLongMult\n#else\n_Must_inspect_result_\n__inline\nNTSTATUS\nRtlSSIZETMult(\n    _In_ SSIZE_T Multiplicand,\n    _In_ SSIZE_T Multiplier,\n    _Out_ _Deref_out_range_(==, Multiplicand * Multiplier) SSIZE_T* pResult\n    )\n{\n    C_ASSERT(sizeof(LONGLONG) > sizeof(SSIZE_T));\n    return RtlLongLongToSSIZET(((LONGLONG)Multiplicand) * ((LONGLONG)Multiplier), pResult);\n}\n#endif\n\n#endif // ENABLE_INTSAFE_SIGNED_FUNCTIONS\n\n//\n// Macros that are no longer used in this header but which clients may\n// depend on being defined here.\n//\n#ifndef LOWORD\n#define LOWORD(l)     ((WORD)(((DWORD_PTR)(l)) & 0xffff))\n#endif\n#ifndef HIWORD\n#define HIWORD(l)     ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))\n#endif\n#ifndef LODWORD\n#define LODWORD(_qw)    ((DWORD)(_qw))\n#endif\n#ifndef HIDWORD\n#define HIDWORD(_qw)    ((DWORD)(((_qw) >> 32) & 0xffffffff))\n#endif\n\n#if _MSC_VER >= 1200\n#pragma warning(pop)\n#endif\n\n#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) */\n#pragma endregion\n\n#endif // _NTINTSAFE_H_INCLUDED_\n"
  },
  {
    "path": "phnt/include/ntioapi.h",
    "content": "/*\n * File management support\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTIOAPI_H\n#define _NTIOAPI_H\n\n//\n// Sharing mode\n//\n\n#define FILE_SHARE_NONE                 0x00000000\n#define FILE_SHARE_READ                 0x00000001\n#define FILE_SHARE_WRITE                0x00000002\n#define FILE_SHARE_DELETE               0x00000004\n\n//\n// Create disposition\n//\n\n#define FILE_SUPERSEDE                      0x00000000\n#define FILE_OPEN                           0x00000001\n#define FILE_CREATE                         0x00000002\n#define FILE_OPEN_IF                        0x00000003\n#define FILE_OVERWRITE                      0x00000004\n#define FILE_OVERWRITE_IF                   0x00000005\n#define FILE_MAXIMUM_DISPOSITION            0x00000005\n\n//\n// Create/open flags\n//\n\n#define FILE_DIRECTORY_FILE                 0x00000001\n#define FILE_WRITE_THROUGH                  0x00000002\n#define FILE_SEQUENTIAL_ONLY                0x00000004\n#define FILE_NO_INTERMEDIATE_BUFFERING      0x00000008\n\n#define FILE_SYNCHRONOUS_IO_ALERT           0x00000010\n#define FILE_SYNCHRONOUS_IO_NONALERT        0x00000020\n#define FILE_NON_DIRECTORY_FILE             0x00000040\n#define FILE_CREATE_TREE_CONNECTION         0x00000080\n\n#define FILE_COMPLETE_IF_OPLOCKED           0x00000100\n#define FILE_NO_EA_KNOWLEDGE                0x00000200\n#define FILE_OPEN_REMOTE_INSTANCE           0x00000400\n#define FILE_RANDOM_ACCESS                  0x00000800\n\n#define FILE_DELETE_ON_CLOSE                0x00001000\n#define FILE_OPEN_BY_FILE_ID                0x00002000\n#define FILE_OPEN_FOR_BACKUP_INTENT         0x00004000\n#define FILE_NO_COMPRESSION                 0x00008000\n\n#define FILE_OPEN_REQUIRING_OPLOCK          0x00010000\n#define FILE_DISALLOW_EXCLUSIVE             0x00020000\n#define FILE_SESSION_AWARE                  0x00040000\n\n#define FILE_RESERVE_OPFILTER               0x00100000\n#define FILE_OPEN_REPARSE_POINT             0x00200000\n#define FILE_OPEN_NO_RECALL                 0x00400000\n#define FILE_OPEN_FOR_FREE_SPACE_QUERY      0x00800000\n\n#define TREE_CONNECT_WRITE_THROUGH          0x00000002\n#define TREE_CONNECT_NO_CLIENT_BUFFERING    0x00000008\n\n//\n// Extended create/open flags\n//\n\n#define FILE_CONTAINS_EXTENDED_CREATE_INFORMATION   0x10000000\n#define FILE_VALID_EXTENDED_OPTION_FLAGS            0x10000000\n\ntypedef struct _EXTENDED_CREATE_DUAL_OPLOCK_KEYS\n{\n    //\n    //  Parent oplock key.\n    //  All-zero if not set.\n    //\n    GUID ParentOplockKey;\n    //\n    //  Target oplock key.\n    //  All-zero if not set.\n    //\n    GUID TargetOplockKey;\n} EXTENDED_CREATE_DUAL_OPLOCK_KEYS, *PEXTENDED_CREATE_DUAL_OPLOCK_KEYS;\n\ntypedef struct _EXTENDED_CREATE_INFORMATION\n{\n    LONGLONG ExtendedCreateFlags;\n    PVOID EaBuffer;\n    ULONG EaLength;\n    //PEXTENDED_CREATE_DUAL_OPLOCK_KEYS DualOplockKeys; // since 24H2\n} EXTENDED_CREATE_INFORMATION, *PEXTENDED_CREATE_INFORMATION;\n\ntypedef struct _EXTENDED_CREATE_INFORMATION_32\n{\n    LONGLONG ExtendedCreateFlags;\n    void* POINTER_32 EaBuffer;\n    ULONG EaLength;\n    //PEXTENDED_CREATE_DUAL_OPLOCK_KEYS POINTER_32 DualOplockKeys; // since 24H2\n} EXTENDED_CREATE_INFORMATION_32, *PEXTENDED_CREATE_INFORMATION_32;\n\n#define EX_CREATE_FLAG_FILE_SOURCE_OPEN_FOR_COPY 0x00000001\n#define EX_CREATE_FLAG_FILE_DEST_OPEN_FOR_COPY   0x00000002\n\n#define FILE_VALID_OPTION_FLAGS             0x00ffffff\n#define FILE_VALID_PIPE_OPTION_FLAGS        0x00000032\n#define FILE_VALID_MAILSLOT_OPTION_FLAGS    0x00000032\n#define FILE_VALID_SET_FLAGS                0x00000036\n\n#define FILE_COPY_STRUCTURED_STORAGE        0x00000041\n#define FILE_STRUCTURED_STORAGE             0x00000441\n\n// I/O status information values for NtCreateFile/NtOpenFile\n\n#define FILE_SUPERSEDED                 0x00000000\n#define FILE_OPENED                     0x00000001\n#define FILE_CREATED                    0x00000002\n#define FILE_OVERWRITTEN                0x00000003\n#define FILE_EXISTS                     0x00000004\n#define FILE_DOES_NOT_EXIST             0x00000005\n\n// Special ByteOffset parameters\n\n#define FILE_WRITE_TO_END_OF_FILE       0xffffffff\n#define FILE_USE_FILE_POINTER_POSITION  0xfffffffe\n\n// Alignment requirement values\n\n#define FILE_BYTE_ALIGNMENT             0x00000000\n#define FILE_WORD_ALIGNMENT             0x00000001\n#define FILE_LONG_ALIGNMENT             0x00000003\n#define FILE_QUAD_ALIGNMENT             0x00000007\n#define FILE_OCTA_ALIGNMENT             0x0000000f\n#define FILE_32_BYTE_ALIGNMENT          0x0000001f\n#define FILE_64_BYTE_ALIGNMENT          0x0000003f\n#define FILE_128_BYTE_ALIGNMENT         0x0000007f\n#define FILE_256_BYTE_ALIGNMENT         0x000000ff\n#define FILE_512_BYTE_ALIGNMENT         0x000001ff\n\n// Maximum length of a filename string\n\n#define DOS_MAX_COMPONENT_LENGTH 255\n#define DOS_MAX_PATH_LENGTH (DOS_MAX_COMPONENT_LENGTH + 5)\n\n#define MAXIMUM_FILENAME_LENGTH 256\n\n//\n// Extended attributes\n//\n\n#define FILE_NEED_EA                    0x00000080\n\n#define FILE_EA_TYPE_BINARY             0xfffe\n#define FILE_EA_TYPE_ASCII              0xfffd\n#define FILE_EA_TYPE_BITMAP             0xfffb\n#define FILE_EA_TYPE_METAFILE           0xfffa\n#define FILE_EA_TYPE_ICON               0xfff9\n#define FILE_EA_TYPE_EA                 0xffee\n#define FILE_EA_TYPE_MVMT               0xffdf\n#define FILE_EA_TYPE_MVST               0xffde\n#define FILE_EA_TYPE_ASN1               0xffdd\n#define FILE_EA_TYPE_FAMILY_IDS         0xff01\n\n//\n// Device characteristics\n//\n\n#define FILE_REMOVABLE_MEDIA                        0x00000001\n#define FILE_READ_ONLY_DEVICE                       0x00000002\n#define FILE_FLOPPY_DISKETTE                        0x00000004\n#define FILE_WRITE_ONCE_MEDIA                       0x00000008\n#define FILE_REMOTE_DEVICE                          0x00000010\n#define FILE_DEVICE_IS_MOUNTED                      0x00000020\n#define FILE_VIRTUAL_VOLUME                         0x00000040\n#define FILE_AUTOGENERATED_DEVICE_NAME              0x00000080\n#define FILE_DEVICE_SECURE_OPEN                     0x00000100\n#define FILE_CHARACTERISTIC_PNP_DEVICE              0x00000800\n#define FILE_CHARACTERISTIC_TS_DEVICE               0x00001000\n#define FILE_CHARACTERISTIC_WEBDAV_DEVICE           0x00002000\n#define FILE_CHARACTERISTIC_CSV                     0x00010000\n#define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL    0x00020000\n#define FILE_PORTABLE_DEVICE                        0x00040000\n#define FILE_REMOTE_DEVICE_VSMB                     0x00080000\n#define FILE_DEVICE_REQUIRE_SECURITY_CHECK          0x00100000\n\n//\n// Named pipe values\n//\n\n// NamedPipeType for NtCreateNamedPipeFile\n#define FILE_PIPE_BYTE_STREAM_TYPE      0x00000000\n#define FILE_PIPE_MESSAGE_TYPE          0x00000001\n#define FILE_PIPE_ACCEPT_REMOTE_CLIENTS 0x00000000\n#define FILE_PIPE_REJECT_REMOTE_CLIENTS 0x00000002\n#define FILE_PIPE_TYPE_VALID_MASK       0x00000003\n\n// CompletionMode for NtCreateNamedPipeFile\n#define FILE_PIPE_QUEUE_OPERATION       0x00000000\n#define FILE_PIPE_COMPLETE_OPERATION    0x00000001\n\n// ReadMode for NtCreateNamedPipeFile\n#define FILE_PIPE_BYTE_STREAM_MODE      0x00000000\n#define FILE_PIPE_MESSAGE_MODE          0x00000001\n\n// NamedPipeConfiguration for NtQueryInformationFile\n#define FILE_PIPE_INBOUND               0x00000000\n#define FILE_PIPE_OUTBOUND              0x00000001\n#define FILE_PIPE_FULL_DUPLEX           0x00000002\n\n// NamedPipeState for NtQueryInformationFile\n#define FILE_PIPE_DISCONNECTED_STATE    0x00000001\n#define FILE_PIPE_LISTENING_STATE       0x00000002\n#define FILE_PIPE_CONNECTED_STATE       0x00000003\n#define FILE_PIPE_CLOSING_STATE         0x00000004\n\n// NamedPipeEnd for NtQueryInformationFile\n#define FILE_PIPE_CLIENT_END            0x00000000\n#define FILE_PIPE_SERVER_END            0x00000001\n\n// Win32 pipe instance limit (0xff)\n#define FILE_PIPE_UNLIMITED_INSTANCES   0xffffffff\n\n//\n// Mailslot values\n//\n\n#define MAILSLOT_SIZE_AUTO 0\n\ntypedef struct _IO_STATUS_BLOCK\n{\n    union\n    {\n        NTSTATUS Status;\n        PVOID Pointer;\n    };\n    ULONG_PTR Information;\n} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;\n\ntypedef _Function_class_(IO_APC_ROUTINE)\nVOID NTAPI IO_APC_ROUTINE(\n    _In_ PVOID ApcContext,\n    _In_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG Reserved\n    );\ntypedef IO_APC_ROUTINE* PIO_APC_ROUTINE;\n\n//\n// NtQueryInformationFile/NtSetInformationFile types\n//\n\ntypedef enum _FILE_INFORMATION_CLASS\n{\n    FileDirectoryInformation = 1,                   // q: FILE_DIRECTORY_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex])\n    FileFullDirectoryInformation,                   // q: FILE_FULL_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex])\n    FileBothDirectoryInformation,                   // q: FILE_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex])\n    FileBasicInformation,                           // qs: FILE_BASIC_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES)\n    FileStandardInformation,                        // q: FILE_STANDARD_INFORMATION, FILE_STANDARD_INFORMATION_EX\n    FileInternalInformation,                        // q: FILE_INTERNAL_INFORMATION\n    FileEaInformation,                              // q: FILE_EA_INFORMATION (requires FILE_READ_EA)\n    FileAccessInformation,                          // q: FILE_ACCESS_INFORMATION\n    FileNameInformation,                            // q: FILE_NAME_INFORMATION\n    FileRenameInformation,                          // s: FILE_RENAME_INFORMATION (requires DELETE) // 10\n    FileLinkInformation,                            // s: FILE_LINK_INFORMATION\n    FileNamesInformation,                           // q: FILE_NAMES_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex])\n    FileDispositionInformation,                     // s: FILE_DISPOSITION_INFORMATION (requires DELETE)\n    FilePositionInformation,                        // qs: FILE_POSITION_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES)\n    FileFullEaInformation,                          // q: FILE_FULL_EA_INFORMATION (requires FILE_READ_EA)\n    FileModeInformation,                            // qs: FILE_MODE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES)\n    FileAlignmentInformation,                       // q: FILE_ALIGNMENT_INFORMATION\n    FileAllInformation,                             // q: FILE_ALL_INFORMATION\n    FileAllocationInformation,                      // s: FILE_ALLOCATION_INFORMATION (requires FILE_WRITE_DATA)\n    FileEndOfFileInformation,                       // s: FILE_END_OF_FILE_INFORMATION (requires FILE_WRITE_DATA) // 20\n    FileAlternateNameInformation,                   // q: FILE_NAME_INFORMATION\n    FileStreamInformation,                          // q: FILE_STREAM_INFORMATION\n    FilePipeInformation,                            // qs: FILE_PIPE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES)\n    FilePipeLocalInformation,                       // q: FILE_PIPE_LOCAL_INFORMATION\n    FilePipeRemoteInformation,                      // qs: FILE_PIPE_REMOTE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES)\n    FileMailslotQueryInformation,                   // q: FILE_MAILSLOT_QUERY_INFORMATION\n    FileMailslotSetInformation,                     // s: FILE_MAILSLOT_SET_INFORMATION\n    FileCompressionInformation,                     // q: FILE_COMPRESSION_INFORMATION\n    FileObjectIdInformation,                        // q: FILE_OBJECTID_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex])\n    FileCompletionInformation,                      // s: FILE_COMPLETION_INFORMATION // 30\n    FileMoveClusterInformation,                     // s: FILE_MOVE_CLUSTER_INFORMATION (requires FILE_WRITE_DATA)\n    FileQuotaInformation,                           // q: FILE_QUOTA_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex])\n    FileReparsePointInformation,                    // q: FILE_REPARSE_POINT_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex])\n    FileNetworkOpenInformation,                     // q: FILE_NETWORK_OPEN_INFORMATION\n    FileAttributeTagInformation,                    // q: FILE_ATTRIBUTE_TAG_INFORMATION\n    FileTrackingInformation,                        // s: FILE_TRACKING_INFORMATION (requires FILE_WRITE_DATA)\n    FileIdBothDirectoryInformation,                 // q: FILE_ID_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex])\n    FileIdFullDirectoryInformation,                 // q: FILE_ID_FULL_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex])\n    FileValidDataLengthInformation,                 // s: FILE_VALID_DATA_LENGTH_INFORMATION (requires FILE_WRITE_DATA and/or SeManageVolumePrivilege)\n    FileShortNameInformation,                       // s: FILE_NAME_INFORMATION (requires DELETE) // 40\n    FileIoCompletionNotificationInformation,        // qs: FILE_IO_COMPLETION_NOTIFICATION_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) // since VISTA\n    FileIoStatusBlockRangeInformation,              // s: FILE_IOSTATUSBLOCK_RANGE_INFORMATION (requires SeLockMemoryPrivilege)\n    FileIoPriorityHintInformation,                  // qs: FILE_IO_PRIORITY_HINT_INFORMATION, FILE_IO_PRIORITY_HINT_INFORMATION_EX (q: requires FILE_READ_DATA)\n    FileSfioReserveInformation,                     // qs: FILE_SFIO_RESERVE_INFORMATION (q: requires FILE_READ_DATA)\n    FileSfioVolumeInformation,                      // q: FILE_SFIO_VOLUME_INFORMATION\n    FileHardLinkInformation,                        // q: FILE_LINKS_INFORMATION\n    FileProcessIdsUsingFileInformation,             // q: FILE_PROCESS_IDS_USING_FILE_INFORMATION\n    FileNormalizedNameInformation,                  // q: FILE_NAME_INFORMATION\n    FileNetworkPhysicalNameInformation,             // q: FILE_NETWORK_PHYSICAL_NAME_INFORMATION\n    FileIdGlobalTxDirectoryInformation,             // q: FILE_ID_GLOBAL_TX_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since WIN7 // 50\n    FileIsRemoteDeviceInformation,                  // q: FILE_IS_REMOTE_DEVICE_INFORMATION\n    FileUnusedInformation,                          // q:\n    FileNumaNodeInformation,                        // q: FILE_NUMA_NODE_INFORMATION\n    FileStandardLinkInformation,                    // q: FILE_STANDARD_LINK_INFORMATION\n    FileRemoteProtocolInformation,                  // q: FILE_REMOTE_PROTOCOL_INFORMATION\n    FileRenameInformationBypassAccessCheck,         // s: FILE_RENAME_INFORMATION // (kernel-mode only) // since WIN8\n    FileLinkInformationBypassAccessCheck,           // s: FILE_LINK_INFORMATION // (kernel-mode only)\n    FileVolumeNameInformation,                      // q: FILE_VOLUME_NAME_INFORMATION\n    FileIdInformation,                              // q: FILE_ID_INFORMATION\n    FileIdExtdDirectoryInformation,                 // q: FILE_ID_EXTD_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // 60\n    FileReplaceCompletionInformation,               // s: FILE_COMPLETION_INFORMATION // since WINBLUE\n    FileHardLinkFullIdInformation,                  // q: FILE_LINK_ENTRY_FULL_ID_INFORMATION // FILE_LINKS_FULL_ID_INFORMATION\n    FileIdExtdBothDirectoryInformation,             // q: FILE_ID_EXTD_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since THRESHOLD\n    FileDispositionInformationEx,                   // s: FILE_DISPOSITION_INFO_EX (requires DELETE) // since REDSTONE\n    FileRenameInformationEx,                        // s: FILE_RENAME_INFORMATION_EX\n    FileRenameInformationExBypassAccessCheck,       // s: FILE_RENAME_INFORMATION_EX // (kernel-mode only)\n    FileDesiredStorageClassInformation,             // qs: FILE_DESIRED_STORAGE_CLASS_INFORMATION // since REDSTONE2\n    FileStatInformation,                            // q: FILE_STAT_INFORMATION\n    FileMemoryPartitionInformation,                 // s: FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3\n    FileStatLxInformation,                          // q: FILE_STAT_LX_INFORMATION (requires FILE_READ_ATTRIBUTES and FILE_READ_EA) // since REDSTONE4 // 70\n    FileCaseSensitiveInformation,                   // qs: FILE_CASE_SENSITIVE_INFORMATION\n    FileLinkInformationEx,                          // s: FILE_LINK_INFORMATION_EX // since REDSTONE5\n    FileLinkInformationExBypassAccessCheck,         // s: FILE_LINK_INFORMATION_EX // (kernel-mode only)\n    FileStorageReserveIdInformation,                // qs: FILE_STORAGE_RESERVE_ID_INFORMATION\n    FileCaseSensitiveInformationForceAccessCheck,   // qs: FILE_CASE_SENSITIVE_INFORMATION\n    FileKnownFolderInformation,                     // qs: FILE_KNOWN_FOLDER_INFORMATION // since WIN11\n    FileStatBasicInformation,                       // qs: FILE_STAT_BASIC_INFORMATION // since 23H2\n    FileId64ExtdDirectoryInformation,               // q: FILE_ID_64_EXTD_DIR_INFORMATION\n    FileId64ExtdBothDirectoryInformation,           // q: FILE_ID_64_EXTD_BOTH_DIR_INFORMATION\n    FileIdAllExtdDirectoryInformation,              // q: FILE_ID_ALL_EXTD_DIR_INFORMATION\n    FileIdAllExtdBothDirectoryInformation,          // q: FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION\n    FileStreamReservationInformation,               // q: FILE_STREAM_RESERVATION_INFORMATION // since 24H2\n    FileMupProviderInfo,                            // qs: MUP_PROVIDER_INFORMATION\n    FileMaximumInformation\n} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;\n\n/**\n * The FILE_BASIC_INFORMATION structure contains timestamps and basic attributes of a file.\n * \\li If you specify a value of zero for any of the XxxTime members, the file system keeps a file's current value for that time.\n * \\li If you specify a value of -1 for any of the XxxTime members, time stamp updates are disabled for I/O operations performed on the file handle.\n * \\li If you specify a value of -2 for any of the XxxTime members, time stamp updates are enabled for I/O operations performed on the file handle.\n * \\remarks To set the members of this structure, the caller must have FILE_WRITE_ATTRIBUTES access to the file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_basic_information\n */\ntypedef struct _FILE_BASIC_INFORMATION\n{\n    LARGE_INTEGER CreationTime;         // Specifies the time that the file was created.\n    LARGE_INTEGER LastAccessTime;       // Specifies the time that the file was last accessed.\n    LARGE_INTEGER LastWriteTime;        // Specifies the time that the file was last written to.\n    LARGE_INTEGER ChangeTime;           // Specifies the last time the file was changed.\n    ULONG FileAttributes;               // Specifies one or more FILE_ATTRIBUTE_XXX flags.\n} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;\n\n/**\n * The FILE_STANDARD_INFORMATION structure contains standard information of a file.\n * \\remarks EndOfFile specifies the byte offset to the end of the file.\n * Because this value is zero-based, it actually refers to the first free byte in the file; that is, it is the offset to the byte immediately following the last valid byte in the file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_standard_information\n */\ntypedef struct _FILE_STANDARD_INFORMATION\n{\n    LARGE_INTEGER AllocationSize;       // The file allocation size in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device.\n    LARGE_INTEGER EndOfFile;            // The end of file location as a byte offset.\n    ULONG NumberOfLinks;                // The number of hard links to the file.\n    BOOLEAN DeletePending;              // The delete pending status. TRUE indicates that a file deletion has been requested.\n    BOOLEAN Directory;                  // The file directory status. TRUE indicates the file object represents a directory.\n} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;\n\n/**\n * The FILE_STANDARD_INFORMATION_EX structure is used as an argument to routines that query or set file information\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_standard_information_ex\n */\ntypedef struct _FILE_STANDARD_INFORMATION_EX\n{\n    LARGE_INTEGER AllocationSize;\n    LARGE_INTEGER EndOfFile;\n    ULONG NumberOfLinks;\n    BOOLEAN DeletePending;\n    BOOLEAN Directory;\n    BOOLEAN AlternateStream;\n    BOOLEAN MetadataAttribute;\n} FILE_STANDARD_INFORMATION_EX, *PFILE_STANDARD_INFORMATION_EX;\n\n/**\n * The FILE_INTERNAL_INFORMATION structure is used to query for the file system's 8-byte file reference number for a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_internal_information\n * \\remark The IndexNumber member is the same as the FileId member of the FILE_ID_BOTH_DIR_INFORMATION and FILE_ID_FULL_DIR_INFORMATION structures.\n */\ntypedef struct _FILE_INTERNAL_INFORMATION\n{\n    union\n    {\n        ULARGE_INTEGER IndexNumber;\n        struct\n        {\n            ULONGLONG MftRecordIndex : 48; // rev\n            ULONGLONG SequenceNumber : 16; // rev\n        };\n    };\n} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;\n\n/**\n * The FILE_EA_INFORMATION structure is used to query for the size of the extended attributes (EA) for a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_ea_information\n */\ntypedef struct _FILE_EA_INFORMATION\n{\n    ULONG EaSize;\n} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION;\n\n/**\n * The FILE_ACCESS_INFORMATION structure is used to query for or set the access rights of a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_access_information\n */\ntypedef struct _FILE_ACCESS_INFORMATION\n{\n    ACCESS_MASK AccessFlags;\n} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION;\n\n/**\n * The FILE_POSITION_INFORMATION structure is used as an argument to routines that query or set file information.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_position_information\n */\ntypedef struct _FILE_POSITION_INFORMATION\n{\n    LARGE_INTEGER CurrentByteOffset;\n} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;\n\n/**\n * The FILE_MODE_INFORMATION structure is used to query or set the access mode of a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_mode_information\n */\ntypedef struct _FILE_MODE_INFORMATION\n{\n    ULONG Mode;\n} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;\n\n/**\n * The FILE_ALIGNMENT_INFORMATION structure is used to query or set the buffer alignment required by the underlying device.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_alignment_information\n */\ntypedef struct _FILE_ALIGNMENT_INFORMATION\n{\n    ULONG AlignmentRequirement;\n} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION;\n\n/**\n * The FILE_NAME_INFORMATION structure is used to query or set the file name and/or new short name for a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_name_information\n */\ntypedef struct _FILE_NAME_INFORMATION\n{\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;\n\n/**\n * The FILE_ALL_INFORMATION structure is used as a container for several FILE_XXX_INFORMATION structures.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_all_information\n */\ntypedef struct _FILE_ALL_INFORMATION\n{\n    FILE_BASIC_INFORMATION BasicInformation;\n    FILE_STANDARD_INFORMATION StandardInformation;\n    FILE_INTERNAL_INFORMATION InternalInformation;\n    FILE_EA_INFORMATION EaInformation;\n    FILE_ACCESS_INFORMATION AccessInformation;\n    FILE_POSITION_INFORMATION PositionInformation;\n    FILE_MODE_INFORMATION ModeInformation;\n    FILE_ALIGNMENT_INFORMATION AlignmentInformation;\n    FILE_NAME_INFORMATION NameInformation;\n} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION;\n\n/**\n * The FILE_NETWORK_OPEN_INFORMATION structure is used to query for information that is commonly needed when a file is opened across a network.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_network_open_information\n */\ntypedef struct _FILE_NETWORK_OPEN_INFORMATION\n{\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER AllocationSize;\n    LARGE_INTEGER EndOfFile;\n    ULONG FileAttributes;\n} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION;\n\n/**\n * The FILE_ATTRIBUTE_TAG_INFORMATION structure is used to query for attribute and reparse tag information for a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_attribute_tag_information\n */\ntypedef struct _FILE_ATTRIBUTE_TAG_INFORMATION\n{\n    ULONG FileAttributes;\n    ULONG ReparseTag;\n} FILE_ATTRIBUTE_TAG_INFORMATION, *PFILE_ATTRIBUTE_TAG_INFORMATION;\n\n/**\n * The FILE_ALLOCATION_INFORMATION structure is used to set the allocation size for a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_allocation_information\n */\ntypedef struct _FILE_ALLOCATION_INFORMATION\n{\n    LARGE_INTEGER AllocationSize;\n} FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION;\n\n/**\n * The FILE_COMPRESSION_INFORMATION structure describes the state of a compressed data buffer.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_compression_information\n */\ntypedef struct _FILE_COMPRESSION_INFORMATION\n{\n    LARGE_INTEGER CompressedFileSize;\n    USHORT CompressionFormat;\n    UCHAR CompressionUnitShift;\n    UCHAR ChunkShift;\n    UCHAR ClusterShift;\n    UCHAR Reserved[3];\n} FILE_COMPRESSION_INFORMATION, *PFILE_COMPRESSION_INFORMATION;\n\n/**\n * The FILE_DISPOSITION_INFORMATION structure is used to mark a file for deletion.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information\n */\ntypedef struct _FILE_DISPOSITION_INFORMATION\n{\n    BOOLEAN DeleteFile;\n} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;\n\n/**\n * The FILE_END_OF_FILE_INFORMATION structure is used to set end-of-file information for a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_end_of_file_information\n */\ntypedef struct _FILE_END_OF_FILE_INFORMATION\n{\n    LARGE_INTEGER EndOfFile;\n} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION;\n\n#define FLAGS_END_OF_FILE_INFO_EX_EXTEND_PAGING             0x00000001\n#define FLAGS_END_OF_FILE_INFO_EX_NO_EXTRA_PAGING_EXTEND    0x00000002\n#define FLAGS_END_OF_FILE_INFO_EX_TIME_CONSTRAINED          0x00000004\n#define FLAGS_DELAY_REASONS_LOG_FILE_FULL                   0x00000001\n#define FLAGS_DELAY_REASONS_BITMAP_SCANNED                  0x00000002\n\ntypedef struct _FILE_END_OF_FILE_INFORMATION_EX\n{\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER PagingFileSizeInMM;\n    LARGE_INTEGER PagingFileMaxSize;\n    ULONG Flags;\n} FILE_END_OF_FILE_INFORMATION_EX, *PFILE_END_OF_FILE_INFORMATION_EX;\n\n/**\n * The FILE_VALID_DATA_LENGTH_INFORMATION structure is used to set the valid data length information for a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_valid_data_length_information\n */\ntypedef struct _FILE_VALID_DATA_LENGTH_INFORMATION\n{\n    LARGE_INTEGER ValidDataLength;\n} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION;\n\n#define FILE_LINK_REPLACE_IF_EXISTS 0x00000001 // since RS5\n#define FILE_LINK_POSIX_SEMANTICS   0x00000002\n\n#define FILE_LINK_SUPPRESS_STORAGE_RESERVE_INHERITANCE  0x00000008\n#define FILE_LINK_NO_INCREASE_AVAILABLE_SPACE           0x00000010\n#define FILE_LINK_NO_DECREASE_AVAILABLE_SPACE           0x00000020\n#define FILE_LINK_PRESERVE_AVAILABLE_SPACE              0x00000030\n#define FILE_LINK_IGNORE_READONLY_ATTRIBUTE             0x00000040\n#define FILE_LINK_FORCE_RESIZE_TARGET_SR                0x00000080 // since 19H1\n#define FILE_LINK_FORCE_RESIZE_SOURCE_SR                0x00000100\n#define FILE_LINK_FORCE_RESIZE_SR                       0x00000180\n\n/**\n * The FILE_LINK_INFORMATION structure is used to create an NTFS hard link to an existing file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_link_information\n */\ntypedef struct _FILE_LINK_INFORMATION\n{\n    BOOLEAN ReplaceIfExists;\n    HANDLE RootDirectory;\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;\n\ntypedef struct _FILE_LINK_INFORMATION_EX\n{\n    ULONG Flags;\n    HANDLE RootDirectory;\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_LINK_INFORMATION_EX, *PFILE_LINK_INFORMATION_EX;\n\ntypedef struct _FILE_MOVE_CLUSTER_INFORMATION\n{\n    ULONG ClusterCount;\n    HANDLE RootDirectory;\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_MOVE_CLUSTER_INFORMATION, *PFILE_MOVE_CLUSTER_INFORMATION;\n\n/**\n * The FILE_RENAME_INFORMATION structure is used to rename a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_rename_information\n */\ntypedef struct _FILE_RENAME_INFORMATION\n{\n    BOOLEAN ReplaceIfExists;\n    HANDLE RootDirectory;\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;\n\n#define FILE_RENAME_REPLACE_IF_EXISTS                       0x00000001 // since REDSTONE\n#define FILE_RENAME_POSIX_SEMANTICS                         0x00000002\n#define FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE          0x00000004 // since REDSTONE3\n#define FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE    0x00000008 // since REDSTONE5\n#define FILE_RENAME_NO_INCREASE_AVAILABLE_SPACE             0x00000010\n#define FILE_RENAME_NO_DECREASE_AVAILABLE_SPACE             0x00000020\n#define FILE_RENAME_PRESERVE_AVAILABLE_SPACE                0x00000030\n#define FILE_RENAME_IGNORE_READONLY_ATTRIBUTE               0x00000040\n#define FILE_RENAME_FORCE_RESIZE_TARGET_SR                  0x00000080 // since 19H1\n#define FILE_RENAME_FORCE_RESIZE_SOURCE_SR                  0x00000100\n#define FILE_RENAME_FORCE_RESIZE_SR                         0x00000180\n\n/**\n * The FILE_RENAME_INFORMATION_EX structure is used to rename a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_rename_information\n */\ntypedef struct _FILE_RENAME_INFORMATION_EX\n{\n    ULONG Flags;\n    HANDLE RootDirectory;\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_RENAME_INFORMATION_EX, *PFILE_RENAME_INFORMATION_EX;\n\n/**\n * The FILE_STREAM_INFORMATION structure contains information about a file stream.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_stream_information\n */\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_STREAM_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG StreamNameLength;\n    LARGE_INTEGER StreamSize;\n    LARGE_INTEGER StreamAllocationSize;\n    _Field_size_bytes_(StreamNameLength) WCHAR StreamName[1];\n} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;\n\n/**\n * The FILE_TRACKING_INFORMATION structure contains information used for tracking file operations.\n */\ntypedef struct _FILE_TRACKING_INFORMATION\n{\n    HANDLE DestinationFile;\n    ULONG ObjectInformationLength;\n    _Field_size_bytes_(ObjectInformationLength) CHAR ObjectInformation[1];\n} FILE_TRACKING_INFORMATION, *PFILE_TRACKING_INFORMATION;\n\n/**\n * The FILE_COMPLETION_INFORMATION structure contains the port handle and key for an I/O completion port created for a file handle.\n *\n * \\remarks he FILE_COMPLETION_INFORMATION structure is used to replace the completion information for a port handle set in Port.\n * Completion information is replaced with the ZwSetInformationFile routine with the FileInformationClass parameter set to FileReplaceCompletionInformation.\n * The Port and Key members of FILE_COMPLETION_INFORMATION are set to their new values. To remove an existing completion port for a file handle, Port is set to NULL.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_completion_information\n */\ntypedef struct _FILE_COMPLETION_INFORMATION\n{\n    HANDLE Port;\n    PVOID Key;\n} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION;\n\n/**\n * The FILE_PIPE_INFORMATION structure contains information about a named pipe that is not specific to the local or the remote end of the pipe.\n *\n * \\remarks If ReadMode is set to FILE_PIPE_BYTE_STREAM_MODE, any attempt to change it must fail with a STATUS_INVALID_PARAMETER error code.\n * When CompletionMode is set to FILE_PIPE_QUEUE_OPERATION, if the pipe is connected to, read to, or written from,\n * the operation is not completed until there is data to read, all data is written, or a client is connected.\n * When CompletionMode is set to FILE_PIPE_COMPLETE_OPERATION, if the pipe is being connected to, read to, or written from, the operation is completed immediately.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_pipe_information\n */\ntypedef struct _FILE_PIPE_INFORMATION\n{\n     ULONG ReadMode;\n     ULONG CompletionMode;\n} FILE_PIPE_INFORMATION, *PFILE_PIPE_INFORMATION;\n\n/**\n * The FILE_PIPE_LOCAL_INFORMATION structure contains information about the local end of a named pipe.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_pipe_local_information\n */\ntypedef struct _FILE_PIPE_LOCAL_INFORMATION\n{\n     ULONG NamedPipeType;\n     ULONG NamedPipeConfiguration;\n     ULONG MaximumInstances;\n     ULONG CurrentInstances;\n     ULONG InboundQuota;\n     ULONG ReadDataAvailable;\n     ULONG OutboundQuota;\n     ULONG WriteQuotaAvailable;\n     ULONG NamedPipeState;\n     ULONG NamedPipeEnd;\n} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;\n\n/**\n * The FILE_PIPE_REMOTE_INFORMATION structure contains information about the remote end of a named pipe.\n *\n * \\remarks Remote information is not available for local pipes or for the server end of a remote pipe.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_pipe_remote_information\n */\ntypedef struct _FILE_PIPE_REMOTE_INFORMATION\n{\n    LARGE_INTEGER CollectDataTime;  // The maximum amount of time, in 100-nanosecond intervals, that elapses before transmission of data from the client machine to the server.\n    ULONG MaximumCollectionCount;   // The maximum size, in bytes, of data that will be collected on the client machine before transmission to the server.\n} FILE_PIPE_REMOTE_INFORMATION, *PFILE_PIPE_REMOTE_INFORMATION;\n\n/**\n * The FILE_MAILSLOT_QUERY_INFORMATION structure contains information about a mailslot.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_mailslot_query_information\n */\ntypedef struct _FILE_MAILSLOT_QUERY_INFORMATION\n{\n    ULONG MaximumMessageSize;       // The maximum size, in bytes, of a single message that can be written to the mailslot, or 0 for a message of any size.\n    ULONG MailslotQuota;            // The size, in bytes, of the in-memory pool that is reserved for writes to this mailslot.\n    ULONG NextMessageSize;          // The next message size, in bytes.\n    ULONG MessagesAvailable;        // The total number of messages waiting to be read from the mailslot.\n    LARGE_INTEGER ReadTimeout;      // The time, in milliseconds, that a read operation can wait for a message to be written to the mailslot before a time-out occurs.\n} FILE_MAILSLOT_QUERY_INFORMATION, *PFILE_MAILSLOT_QUERY_INFORMATION;\n\n/**\n * The FILE_MAILSLOT_SET_INFORMATION structure is used to set a value on a mailslot.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_mailslot_set_information\n */\ntypedef struct _FILE_MAILSLOT_SET_INFORMATION\n{\n    PLARGE_INTEGER ReadTimeout;     // The time, in milliseconds, that a read operation can wait for a message to be written to the mailslot before a time-out occurs.\n} FILE_MAILSLOT_SET_INFORMATION, *PFILE_MAILSLOT_SET_INFORMATION;\n\n/**\n * The FILE_REPARSE_POINT_INFORMATION structure contains information about a reparse point.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_reparse_point_information\n */\ntypedef struct _FILE_REPARSE_POINT_INFORMATION\n{\n    LONGLONG FileReference;\n    ULONG Tag;\n} FILE_REPARSE_POINT_INFORMATION, *PFILE_REPARSE_POINT_INFORMATION;\n\n/**\n * The FILE_LINK_ENTRY_INFORMATION structure contains information about a file link entry.\n */\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_LINK_ENTRY_INFORMATION\n{\n    ULONG NextEntryOffset;\n    LONGLONG ParentFileId; // LARGE_INTEGER\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_LINK_ENTRY_INFORMATION, *PFILE_LINK_ENTRY_INFORMATION;\n\n/**\n * The FILE_LINKS_INFORMATION structure contains information about file links.\n */\ntypedef struct _FILE_LINKS_INFORMATION\n{\n    ULONG BytesNeeded;\n    ULONG EntriesReturned;\n    FILE_LINK_ENTRY_INFORMATION Entry;\n} FILE_LINKS_INFORMATION, *PFILE_LINKS_INFORMATION;\n\n/**\n * The FILE_NETWORK_PHYSICAL_NAME_INFORMATION structure contains information about the network physical name of a file.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_network_physical_name_information\n */\ntypedef struct _FILE_NETWORK_PHYSICAL_NAME_INFORMATION\n{\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_NETWORK_PHYSICAL_NAME_INFORMATION, *PFILE_NETWORK_PHYSICAL_NAME_INFORMATION;\n\n/**\n * The FILE_STANDARD_LINK_INFORMATION structure contains standard information about a file link.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-file_standard_link_information\n */\ntypedef struct _FILE_STANDARD_LINK_INFORMATION\n{\n    ULONG NumberOfAccessibleLinks;\n    ULONG TotalNumberOfLinks;\n    BOOLEAN DeletePending;\n    BOOLEAN Directory;\n} FILE_STANDARD_LINK_INFORMATION, *PFILE_STANDARD_LINK_INFORMATION;\n\ntypedef struct _FILE_SFIO_RESERVE_INFORMATION\n{\n    ULONG RequestsPerPeriod;\n    ULONG Period;\n    BOOLEAN RetryFailures;\n    BOOLEAN Discardable;\n    ULONG RequestSize;\n    ULONG NumOutstandingRequests;\n} FILE_SFIO_RESERVE_INFORMATION, *PFILE_SFIO_RESERVE_INFORMATION;\n\ntypedef struct _FILE_SFIO_VOLUME_INFORMATION\n{\n    ULONG MaximumRequestsPerPeriod;\n    ULONG MinimumPeriod;\n    ULONG MinimumTransferSize;\n} FILE_SFIO_VOLUME_INFORMATION, *PFILE_SFIO_VOLUME_INFORMATION;\n\n/**\n * The IO_PRIORITY_HINT enumeration type specifies the priority hint for an IRP.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-_io_priority_hint\n */\ntypedef enum _IO_PRIORITY_HINT\n{\n    IoPriorityVeryLow,     // Defragging, content indexing and other background I/Os.\n    IoPriorityLow,         // Prefetching for applications.\n    IoPriorityNormal,      // Normal I/Os.\n    IoPriorityHigh,        // Used by filesystems for checkpoint I/O.\n    IoPriorityCritical,    // Used by memory manager. Not available for applications.\n    MaxIoPriorityTypes\n} IO_PRIORITY_HINT;\n\n/**\n * The FILE_IO_PRIORITY_HINT_INFORMATION structure is used to query and set the default IRP priority hint for requests on the specified file handle.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_io_priority_hint_information\n */\ntypedef struct DECLSPEC_ALIGN(8) _FILE_IO_PRIORITY_HINT_INFORMATION\n{\n    IO_PRIORITY_HINT PriorityHint;\n} FILE_IO_PRIORITY_HINT_INFORMATION, *PFILE_IO_PRIORITY_HINT_INFORMATION;\n\n/**\n * The FILE_IO_PRIORITY_HINT_INFORMATION_EX structure is used to query and set the default IRP priority hint for requests on the specified file handle.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_io_priority_hint_information\n */\ntypedef struct _FILE_IO_PRIORITY_HINT_INFORMATION_EX\n{\n    IO_PRIORITY_HINT PriorityHint;\n    BOOLEAN BoostOutstanding;\n} FILE_IO_PRIORITY_HINT_INFORMATION_EX, *PFILE_IO_PRIORITY_HINT_INFORMATION_EX;\n\n/**\n * FILE_SKIP_COMPLETION_PORT_ON_SUCCESS\n * Skip posting a completion packet to the I/O completion port if the operation completes successfully.\n */\n#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1\n\n/**\n * FILE_SKIP_SET_EVENT_ON_HANDLE\n * Skip setting the event on the file handle when the operation completes.\n */\n#define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2\n\n/**\n * FILE_SKIP_SET_USER_EVENT_ON_FAST_IO\n * Skip setting the user event when a fast I/O operation completes.\n */\n#define FILE_SKIP_SET_USER_EVENT_ON_FAST_IO 0x4\n\ntypedef struct _FILE_IO_COMPLETION_NOTIFICATION_INFORMATION\n{\n    ULONG Flags;\n} FILE_IO_COMPLETION_NOTIFICATION_INFORMATION, *PFILE_IO_COMPLETION_NOTIFICATION_INFORMATION;\n\ntypedef struct _FILE_PROCESS_IDS_USING_FILE_INFORMATION\n{\n    ULONG NumberOfProcessIdsInList;\n    _Field_size_(NumberOfProcessIdsInList) HANDLE ProcessIdList[1];\n} FILE_PROCESS_IDS_USING_FILE_INFORMATION, *PFILE_PROCESS_IDS_USING_FILE_INFORMATION;\n\n/**\n * The FILE_IS_REMOTE_DEVICE_INFORMATION structure indicates whether the file system that contains the file is a remote file system.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_is_remote_device_information\n */\ntypedef struct _FILE_IS_REMOTE_DEVICE_INFORMATION\n{\n    BOOLEAN IsRemote; // A value that indicates whether the file system that contains the file is a remote file system.\n} FILE_IS_REMOTE_DEVICE_INFORMATION, *PFILE_IS_REMOTE_DEVICE_INFORMATION;\n\ntypedef struct _FILE_NUMA_NODE_INFORMATION\n{\n    USHORT NodeNumber;\n} FILE_NUMA_NODE_INFORMATION, *PFILE_NUMA_NODE_INFORMATION;\n\ntypedef struct _FILE_IOSTATUSBLOCK_RANGE_INFORMATION\n{\n    PUCHAR IoStatusBlockRange;\n    ULONG Length;\n} FILE_IOSTATUSBLOCK_RANGE_INFORMATION, *PFILE_IOSTATUSBLOCK_RANGE_INFORMATION;\n\n// Win32 FILE_REMOTE_PROTOCOL_INFO\ntypedef struct _FILE_REMOTE_PROTOCOL_INFORMATION\n{\n    // Structure Version\n    USHORT StructureVersion;     // 1 for Win7, 2 for Win8 SMB3, 3 for Blue SMB3, 4 for RS5\n    USHORT StructureSize;        // sizeof(FILE_REMOTE_PROTOCOL_INFORMATION)\n\n    ULONG Protocol;             // Protocol (WNNC_NET_*) defined in winnetwk.h or ntifs.h.\n\n    // Protocol Version & Type\n    USHORT ProtocolMajorVersion;\n    USHORT ProtocolMinorVersion;\n    USHORT ProtocolRevision;\n\n    USHORT Reserved;\n\n    // Protocol-Generic Information\n    ULONG Flags;\n\n    struct\n    {\n        ULONG Reserved[8];\n    } GenericReserved;\n\n    // Protocol specific information\n\n    union\n    {\n        struct\n        {\n            struct\n            {\n                ULONG Capabilities;\n            } Server;\n            struct\n            {\n                ULONG Capabilities;\n                ULONG ShareFlags; // previoulsly CachingFlags before 21H1\n                UCHAR ShareType; // RS5\n                UCHAR Reserved0[3];\n                ULONG Reserved1;\n            } Share;\n        } Smb2;\n        ULONG Reserved[16];\n    } ProtocolSpecific;\n} FILE_REMOTE_PROTOCOL_INFORMATION, *PFILE_REMOTE_PROTOCOL_INFORMATION;\n\n#define CHECKSUM_ENFORCEMENT_OFF 0x00000001\n\ntypedef struct _FILE_INTEGRITY_STREAM_INFORMATION\n{\n    USHORT ChecksumAlgorithm;\n    UCHAR ChecksumChunkShift;\n    UCHAR ClusterShift;\n    ULONG Flags;\n} FILE_INTEGRITY_STREAM_INFORMATION, *PFILE_INTEGRITY_STREAM_INFORMATION;\n\ntypedef struct _FILE_VOLUME_NAME_INFORMATION\n{\n    ULONG DeviceNameLength;\n    _Field_size_bytes_(DeviceNameLength) WCHAR DeviceName[1];\n} FILE_VOLUME_NAME_INFORMATION, *PFILE_VOLUME_NAME_INFORMATION;\n\n#ifndef FILE_INVALID_FILE_ID\n#define FILE_INVALID_FILE_ID ((LONGLONG)-1LL)\n#endif // FILE_INVALID_FILE_ID\n\n#define FILE_ID_IS_INVALID(FID) ((FID).QuadPart == FILE_INVALID_FILE_ID)\n\n#define FILE_ID_128_IS_INVALID(FID128) \\\n    (((FID128).Identifier[0] == (UCHAR)-1) && \\\n    ((FID128).Identifier[1] == (UCHAR)-1) && \\\n    ((FID128).Identifier[2] == (UCHAR)-1) && \\\n    ((FID128).Identifier[3] == (UCHAR)-1) && \\\n    ((FID128).Identifier[4] == (UCHAR)-1) && \\\n    ((FID128).Identifier[5] == (UCHAR)-1) && \\\n    ((FID128).Identifier[6] == (UCHAR)-1) && \\\n    ((FID128).Identifier[7] == (UCHAR)-1) && \\\n    ((FID128).Identifier[8] == (UCHAR)-1) && \\\n    ((FID128).Identifier[9] == (UCHAR)-1) && \\\n    ((FID128).Identifier[10] == (UCHAR)-1) && \\\n    ((FID128).Identifier[11] == (UCHAR)-1) && \\\n    ((FID128).Identifier[12] == (UCHAR)-1) && \\\n    ((FID128).Identifier[13] == (UCHAR)-1) && \\\n    ((FID128).Identifier[14] == (UCHAR)-1) && \\\n    ((FID128).Identifier[15] == (UCHAR)-1))\n\n#define MAKE_INVALID_FILE_ID_128(FID128) { \\\n    ((FID128).Identifier[0] = (UCHAR)-1); \\\n    ((FID128).Identifier[1] = (UCHAR)-1); \\\n    ((FID128).Identifier[2] = (UCHAR)-1); \\\n    ((FID128).Identifier[3] = (UCHAR)-1); \\\n    ((FID128).Identifier[4] = (UCHAR)-1); \\\n    ((FID128).Identifier[5] = (UCHAR)-1); \\\n    ((FID128).Identifier[6] = (UCHAR)-1); \\\n    ((FID128).Identifier[7] = (UCHAR)-1); \\\n    ((FID128).Identifier[8] = (UCHAR)-1); \\\n    ((FID128).Identifier[9] = (UCHAR)-1); \\\n    ((FID128).Identifier[10] = (UCHAR)-1); \\\n    ((FID128).Identifier[11] = (UCHAR)-1); \\\n    ((FID128).Identifier[12] = (UCHAR)-1); \\\n    ((FID128).Identifier[13] = (UCHAR)-1); \\\n    ((FID128).Identifier[14] = (UCHAR)-1); \\\n    ((FID128).Identifier[15] = (UCHAR)-1); \\\n}\n\n/**\n * The FILE_ID_INFORMATION structure is used to query file identification information.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-file_id_information\n */\ntypedef struct _FILE_ID_INFORMATION\n{\n    ULONGLONG VolumeSerialNumber;\n    union\n    {\n        FILE_ID_128 FileId;\n        struct\n        {\n            union\n            {\n                FILE_INTERNAL_INFORMATION FileInternal; // rev\n                LONGLONG FileIdLowPart; // rev\n            };\n            LONGLONG FileIdHighPart; // rev\n        };\n    };\n} FILE_ID_INFORMATION, *PFILE_ID_INFORMATION;\n\n/**\n * The FILE_ID_EXTD_DIR_INFORMATION structure is used to query 128-bit file reference number information for the files in a directory.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-file_id_extd_dir_information\n */\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_ID_EXTD_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    ULONG ReparsePointTag;\n    FILE_ID_128 FileId;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_ID_EXTD_DIR_INFORMATION, *PFILE_ID_EXTD_DIR_INFORMATION;\n\n#define FileIdExtdDirectoryInformationDefinition {                  \\\n    FileIdExtdDirectoryInformation,                                 \\\n    FIELD_OFFSET(FILE_ID_EXTD_DIR_INFORMATION, NextEntryOffset),    \\\n    FIELD_OFFSET(FILE_ID_EXTD_DIR_INFORMATION, FileName),           \\\n    FIELD_OFFSET(FILE_ID_EXTD_DIR_INFORMATION, FileNameLength)      \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_LINK_ENTRY_FULL_ID_INFORMATION\n{\n    ULONG NextEntryOffset;\n    FILE_ID_128 ParentFileId;\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_LINK_ENTRY_FULL_ID_INFORMATION, *PFILE_LINK_ENTRY_FULL_ID_INFORMATION;\n\ntypedef struct _FILE_LINKS_FULL_ID_INFORMATION\n{\n    ULONG BytesNeeded;\n    ULONG EntriesReturned;\n    FILE_LINK_ENTRY_FULL_ID_INFORMATION Entry;\n} FILE_LINKS_FULL_ID_INFORMATION, *PFILE_LINKS_FULL_ID_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    ULONG ReparsePointTag;\n    FILE_ID_128 FileId;\n    CCHAR ShortNameLength;\n    WCHAR ShortName[12];\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_ID_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_EXTD_BOTH_DIR_INFORMATION;\n\n#define FileIdExtdBothDirectoryInformationDefinition {                  \\\n    FileIdExtdBothDirectoryInformation,                                 \\\n    FIELD_OFFSET(FILE_ID_EXTD_BOTH_DIR_INFORMATION, NextEntryOffset),   \\\n    FIELD_OFFSET(FILE_ID_EXTD_BOTH_DIR_INFORMATION, FileName),          \\\n    FIELD_OFFSET(FILE_ID_EXTD_BOTH_DIR_INFORMATION, FileNameLength)     \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_ID_64_EXTD_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    ULONG ReparsePointTag;\n    union\n    {\n        LARGE_INTEGER FileId;\n        FILE_INTERNAL_INFORMATION FileInternal; // rev\n    };\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_ID_64_EXTD_DIR_INFORMATION, *PFILE_ID_64_EXTD_DIR_INFORMATION;\n\n#define FileId64ExtdDirectoryInformationDefinition {                    \\\n    FileId64ExtdDirectoryInformation,                                   \\\n    FIELD_OFFSET(FILE_ID_64_EXTD_DIR_INFORMATION, NextEntryOffset),     \\\n    FIELD_OFFSET(FILE_ID_64_EXTD_DIR_INFORMATION, FileName),            \\\n    FIELD_OFFSET(FILE_ID_64_EXTD_DIR_INFORMATION, FileNameLength)       \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_ID_64_EXTD_BOTH_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    ULONG ReparsePointTag;\n    union\n    {\n        LARGE_INTEGER FileId;\n        FILE_INTERNAL_INFORMATION FileInternal; // rev\n    };\n    CCHAR ShortNameLength;\n    WCHAR ShortName[12];\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_ID_64_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_64_EXTD_BOTH_DIR_INFORMATION;\n\n#define FileId64ExtdBothDirectoryInformationDefinition {                    \\\n    FileId64ExtdBothDirectoryInformation,                                   \\\n    FIELD_OFFSET(FILE_ID_64_EXTD_BOTH_DIR_INFORMATION, NextEntryOffset),    \\\n    FIELD_OFFSET(FILE_ID_64_EXTD_BOTH_DIR_INFORMATION, FileName),           \\\n    FIELD_OFFSET(FILE_ID_64_EXTD_BOTH_DIR_INFORMATION, FileNameLength)      \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_ID_ALL_EXTD_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    ULONG ReparsePointTag;\n    union\n    {\n        LARGE_INTEGER FileId;\n        FILE_INTERNAL_INFORMATION FileInternal; // rev\n    };\n    FILE_ID_128 FileId128;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_ID_ALL_EXTD_DIR_INFORMATION, *PFILE_ID_ALL_EXTD_DIR_INFORMATION;\n\n#define FileIdAllExtdDirectoryInformationDefinition {                    \\\n    FileIdAllExtdDirectoryInformation,                                   \\\n    FIELD_OFFSET(FILE_ID_ALL_EXTD_DIR_INFORMATION, NextEntryOffset),     \\\n    FIELD_OFFSET(FILE_ID_ALL_EXTD_DIR_INFORMATION, FileName),            \\\n    FIELD_OFFSET(FILE_ID_ALL_EXTD_DIR_INFORMATION, FileNameLength)       \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    ULONG ReparsePointTag;\n    union\n    {\n        LARGE_INTEGER FileId;\n        FILE_INTERNAL_INFORMATION FileInternal; // rev\n    };\n    FILE_ID_128 FileId128;\n    CCHAR ShortNameLength;\n    WCHAR ShortName[12];\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION;\n\n#define FileIdAllExtdBothDirectoryInformationDefinition {                    \\\n    FileIdAllExtdBothDirectoryInformation,                                   \\\n    FIELD_OFFSET(FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION, NextEntryOffset),    \\\n    FIELD_OFFSET(FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION, FileName),           \\\n    FIELD_OFFSET(FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION, FileNameLength)      \\\n}\n\n#if !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\ntypedef struct _FILE_STAT_INFORMATION\n{\n    LARGE_INTEGER FileId;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER AllocationSize;\n    LARGE_INTEGER EndOfFile;\n    ULONG FileAttributes;\n    ULONG ReparseTag;\n    ULONG NumberOfLinks;\n    ACCESS_MASK EffectiveAccess;\n} FILE_STAT_INFORMATION, *PFILE_STAT_INFORMATION;\n\ntypedef struct _FILE_STAT_BASIC_INFORMATION\n{\n    LARGE_INTEGER FileId;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER AllocationSize;\n    LARGE_INTEGER EndOfFile;\n    ULONG FileAttributes;\n    ULONG ReparseTag;\n    ULONG NumberOfLinks;\n    ULONG DeviceType;\n    ULONG DeviceCharacteristics;\n    ULONG Reserved;\n    LARGE_INTEGER VolumeSerialNumber;\n    FILE_ID_128 FileId128;\n} FILE_STAT_BASIC_INFORMATION, *PFILE_STAT_BASIC_INFORMATION;\n#endif // NTDDI_WIN11_GE\n\n/**\n * The FILE_MEMORY_PARTITION_INFORMATION structure is used to query information about a memory partition.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_memory_partition_information\n */\ntypedef struct _FILE_MEMORY_PARTITION_INFORMATION\n{\n    HANDLE OwnerPartitionHandle;\n    union\n    {\n        struct\n        {\n            UCHAR NoCrossPartitionAccess;\n            UCHAR Spare[3];\n        };\n        ULONG AllFlags;\n    } Flags;\n} FILE_MEMORY_PARTITION_INFORMATION, *PFILE_MEMORY_PARTITION_INFORMATION;\n\n// LxFlags\n#define LX_FILE_METADATA_HAS_UID 0x1\n#define LX_FILE_METADATA_HAS_GID 0x2\n#define LX_FILE_METADATA_HAS_MODE 0x4\n#define LX_FILE_METADATA_HAS_DEVICE_ID 0x8\n#define LX_FILE_CASE_SENSITIVE_DIR 0x10\n\n#if !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\ntypedef struct _FILE_STAT_LX_INFORMATION\n{\n    FILE_INTERNAL_INFORMATION FileId;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER AllocationSize;\n    LARGE_INTEGER EndOfFile;\n    ULONG FileAttributes;\n    ULONG ReparseTag;\n    ULONG NumberOfLinks;\n    ACCESS_MASK EffectiveAccess;\n    ULONG LxFlags;\n    ULONG LxUid;\n    ULONG LxGid;\n    ULONG LxMode;\n    ULONG LxDeviceIdMajor;\n    ULONG LxDeviceIdMinor;\n} FILE_STAT_LX_INFORMATION, *PFILE_STAT_LX_INFORMATION;\n#endif // NTDDI_WIN11_GE\n\ntypedef struct _FILE_STORAGE_RESERVE_ID_INFORMATION\n{\n    STORAGE_RESERVE_ID StorageReserveId;\n} FILE_STORAGE_RESERVE_ID_INFORMATION, *PFILE_STORAGE_RESERVE_ID_INFORMATION;\n\n#define FILE_CS_FLAG_CASE_SENSITIVE_DIR     0x00000001\n\n#if !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\ntypedef struct _FILE_CASE_SENSITIVE_INFORMATION\n{\n    ULONG Flags;\n} FILE_CASE_SENSITIVE_INFORMATION, *PFILE_CASE_SENSITIVE_INFORMATION;\n#endif // NTDDI_WIN11_GE\n\ntypedef enum _FILE_KNOWN_FOLDER_TYPE\n{\n    KnownFolderNone = 0,\n    KnownFolderDesktop,\n    KnownFolderDocuments,\n    KnownFolderDownloads,\n    KnownFolderMusic,\n    KnownFolderPictures,\n    KnownFolderVideos,\n    KnownFolderOther,\n    KnownFolderMax\n} FILE_KNOWN_FOLDER_TYPE;\n\ntypedef struct _FILE_KNOWN_FOLDER_INFORMATION\n{\n    FILE_KNOWN_FOLDER_TYPE Type;\n} FILE_KNOWN_FOLDER_INFORMATION, *PFILE_KNOWN_FOLDER_INFORMATION;\n\n// private\ntypedef struct _FILE_STREAM_RESERVATION_INFORMATION\n{\n    ULONG_PTR TrackedReservation;\n    ULONG_PTR EnforcedReservation;\n} FILE_STREAM_RESERVATION_INFORMATION, *PFILE_STREAM_RESERVATION_INFORMATION;\n\n// private\ntypedef struct _MUP_PROVIDER_INFORMATION\n{\n    ULONG Level;\n    PVOID Buffer;\n    PULONG BufferSize;\n} MUP_PROVIDER_INFORMATION, *PMUP_PROVIDER_INFORMATION;\n\n//\n// NtQueryDirectoryFile types\n//\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_INFORMATION_DEFINITION\n{\n    FILE_INFORMATION_CLASS Class;\n    ULONG NextEntryOffset;\n    ULONG FileNameOffset;\n    ULONG FileNameLengthOffset;\n} FILE_INFORMATION_DEFINITION, *PFILE_INFORMATION_DEFINITION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_DIRECTORY_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;\n\n#define FileDirectoryInformationDefinition {                    \\\n    FileDirectoryInformation,                                   \\\n    FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, NextEntryOffset),  \\\n    FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName),         \\\n    FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileNameLength)    \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_FULL_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;\n\n#define FileFullDirectoryInformationDefinition {                \\\n    FileFullDirectoryInformation,                               \\\n    FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, NextEntryOffset),   \\\n    FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName),          \\\n    FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileNameLength)     \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_ID_FULL_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    union\n    {\n        LARGE_INTEGER FileId;\n        FILE_INTERNAL_INFORMATION FileInternal; // rev\n    };\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;\n\n#define FileIdFullDirectoryInformationDefinition {              \\\n    FileIdFullDirectoryInformation,                             \\\n    FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, NextEntryOffset),\\\n    FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileName),       \\\n    FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileNameLength)  \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_BOTH_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    CCHAR ShortNameLength;\n    WCHAR ShortName[12];\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;\n\n#define FileBothDirectoryInformationDefinition {                \\\n    FileBothDirectoryInformation,                               \\\n    FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, NextEntryOffset),   \\\n    FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName),          \\\n    FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileNameLength)     \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_ID_BOTH_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    CCHAR ShortNameLength;\n    WCHAR ShortName[12];\n    union\n    {\n        LARGE_INTEGER FileId;\n        FILE_INTERNAL_INFORMATION FileInternal; // rev\n    };\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION;\n\n#define FileIdBothDirectoryInformationDefinition {              \\\n    FileIdBothDirectoryInformation,                             \\\n    FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, NextEntryOffset),\\\n    FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName),       \\\n    FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileNameLength)  \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_NAMES_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    ULONG FileNameLength;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;\n\n#define FileNamesInformationDefinition {                    \\\n    FileNamesInformation,                                   \\\n    FIELD_OFFSET(FILE_NAMES_INFORMATION, NextEntryOffset),  \\\n    FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName),         \\\n    FIELD_OFFSET(FILE_NAMES_INFORMATION, FileNameLength)    \\\n}\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_ID_GLOBAL_TX_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    union\n    {\n        LARGE_INTEGER FileId;\n        FILE_INTERNAL_INFORMATION FileInternal; // rev\n    };\n    GUID LockingTransactionId;\n    ULONG TxInfoFlags;\n    _Field_size_bytes_(FileNameLength) WCHAR FileName[1];\n} FILE_ID_GLOBAL_TX_DIR_INFORMATION, *PFILE_ID_GLOBAL_TX_DIR_INFORMATION;\n\n#define FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_WRITELOCKED 0x00000001\n#define FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_VISIBLE_TO_TX 0x00000002\n#define FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_VISIBLE_OUTSIDE_TX 0x00000004\n\n#define FileIdGlobalTxDirectoryInformationDefinition {                  \\\n    FileIdGlobalTxDirectoryInformation,                                 \\\n    FIELD_OFFSET(FILE_ID_GLOBAL_TX_DIR_INFORMATION, NextEntryOffset),   \\\n    FIELD_OFFSET(FILE_ID_GLOBAL_TX_DIR_INFORMATION, FileName),          \\\n    FIELD_OFFSET(FILE_ID_GLOBAL_TX_DIR_INFORMATION, FileNameLength)     \\\n}\n\ntypedef struct _FILE_OBJECTID_INFORMATION\n{\n    ULONGLONG FileReference;\n    UCHAR ObjectId[16]; // GUID\n    union\n    {\n        struct\n        {\n            UCHAR BirthVolumeId[16];\n            UCHAR BirthObjectId[16];\n            UCHAR DomainId[16];\n        };\n        UCHAR ExtendedInfo[48];\n    };\n} FILE_OBJECTID_INFORMATION, *PFILE_OBJECTID_INFORMATION;\n\ntypedef struct _FILE_DIRECTORY_NEXT_INFORMATION\n{\n    ULONG NextEntryOffset;\n} FILE_DIRECTORY_NEXT_INFORMATION, *PFILE_DIRECTORY_NEXT_INFORMATION;\n\n//\n// NtQueryEaFile/NtSetEaFile types\n//\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_FULL_EA_INFORMATION\n{\n    ULONG NextEntryOffset;\n    UCHAR Flags;\n    UCHAR EaNameLength;\n    USHORT EaValueLength;\n    _Field_size_bytes_(EaNameLength) CHAR EaName[1];\n    // ...\n    // UCHAR EaValue[1]\n} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_GET_EA_INFORMATION\n{\n    ULONG NextEntryOffset;\n    UCHAR EaNameLength;\n    _Field_size_bytes_(EaNameLength) CHAR EaName[1];\n} FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION;\n\n//\n// NtQueryQuotaInformationFile/NtSetQuotaInformationFile types\n//\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_GET_QUOTA_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG SidLength;\n    _Field_size_bytes_(SidLength) SID Sid;\n} FILE_GET_QUOTA_INFORMATION, *PFILE_GET_QUOTA_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_QUOTA_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG SidLength;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER QuotaUsed;\n    LARGE_INTEGER QuotaThreshold;\n    LARGE_INTEGER QuotaLimit;\n    _Field_size_bytes_(SidLength) SID Sid;\n} FILE_QUOTA_INFORMATION, *PFILE_QUOTA_INFORMATION;\n\ntypedef enum _FSINFOCLASS\n{\n    FileFsVolumeInformation = 1,            // q: FILE_FS_VOLUME_INFORMATION\n    FileFsLabelInformation,                 // s: FILE_FS_LABEL_INFORMATION // SeManageVolumePrivilege\n    FileFsSizeInformation,                  // q: FILE_FS_SIZE_INFORMATION\n    FileFsDeviceInformation,                // q: FILE_FS_DEVICE_INFORMATION\n    FileFsAttributeInformation,             // q: FILE_FS_ATTRIBUTE_INFORMATION\n    FileFsControlInformation,               // qs: FILE_FS_CONTROL_INFORMATION // SeManageVolumePrivilege\n    FileFsFullSizeInformation,              // q: FILE_FS_FULL_SIZE_INFORMATION\n    FileFsObjectIdInformation,              // qs: FILE_FS_OBJECTID_INFORMATION // SeRestorePrivilege\n    FileFsDriverPathInformation,            // q: FILE_FS_DRIVER_PATH_INFORMATION\n    FileFsVolumeFlagsInformation,           // qs: FILE_FS_VOLUME_FLAGS_INFORMATION // SeManageVolumePrivilege // 10\n    FileFsSectorSizeInformation,            // q: FILE_FS_SECTOR_SIZE_INFORMATION // since WIN8\n    FileFsDataCopyInformation,              // q: FILE_FS_DATA_COPY_INFORMATION\n    FileFsMetadataSizeInformation,          // q: FILE_FS_METADATA_SIZE_INFORMATION // since THRESHOLD\n    FileFsFullSizeInformationEx,            // q: FILE_FS_FULL_SIZE_INFORMATION_EX // since REDSTONE5\n    FileFsGuidInformation,                  // q: FILE_FS_GUID_INFORMATION // since 23H2\n    FileFsMaximumInformation\n} FSINFOCLASS, *PFSINFOCLASS;\ntypedef enum _FSINFOCLASS FS_INFORMATION_CLASS;\n\n//\n// NtQueryVolumeInformation/NtSetVolumeInformation types\n//\n\ntypedef struct _FILE_FS_VOLUME_INFORMATION\n{\n    LARGE_INTEGER VolumeCreationTime;\n    ULONG VolumeSerialNumber;\n    ULONG VolumeLabelLength;\n    BOOLEAN SupportsObjects;\n    _Field_size_bytes_(VolumeLabelLength) WCHAR VolumeLabel[1];\n} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION;\n\ntypedef struct _FILE_FS_LABEL_INFORMATION\n{\n    ULONG VolumeLabelLength;\n    _Field_size_bytes_(VolumeLabelLength) WCHAR VolumeLabel[1];\n} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION;\n\ntypedef struct _FILE_FS_SIZE_INFORMATION\n{\n    LARGE_INTEGER TotalAllocationUnits;\n    LARGE_INTEGER AvailableAllocationUnits;\n    ULONG SectorsPerAllocationUnit;\n    ULONG BytesPerSector;\n} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;\n\n// FileSystemControlFlags\n#define FILE_VC_QUOTA_NONE 0x00000000\n#define FILE_VC_QUOTA_TRACK 0x00000001\n#define FILE_VC_QUOTA_ENFORCE 0x00000002\n#define FILE_VC_QUOTA_MASK 0x00000003\n#define FILE_VC_CONTENT_INDEX_DISABLED 0x00000008\n#define FILE_VC_LOG_QUOTA_THRESHOLD 0x00000010\n#define FILE_VC_LOG_QUOTA_LIMIT 0x00000020\n#define FILE_VC_LOG_VOLUME_THRESHOLD 0x00000040\n#define FILE_VC_LOG_VOLUME_LIMIT 0x00000080\n#define FILE_VC_QUOTAS_INCOMPLETE 0x00000100\n#define FILE_VC_QUOTAS_REBUILDING 0x00000200\n#define FILE_VC_VALID_MASK 0x000003ff\n\ntypedef struct _FILE_FS_CONTROL_INFORMATION\n{\n    LARGE_INTEGER FreeSpaceStartFiltering;\n    LARGE_INTEGER FreeSpaceThreshold;\n    LARGE_INTEGER FreeSpaceStopFiltering;\n    LARGE_INTEGER DefaultQuotaThreshold;\n    LARGE_INTEGER DefaultQuotaLimit;\n    ULONG FileSystemControlFlags; // FILE_VC_*\n} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION;\n\ntypedef struct _FILE_FS_FULL_SIZE_INFORMATION\n{\n    LARGE_INTEGER TotalAllocationUnits;\n    LARGE_INTEGER CallerAvailableAllocationUnits;\n    LARGE_INTEGER ActualAvailableAllocationUnits;\n    ULONG SectorsPerAllocationUnit;\n    ULONG BytesPerSector;\n} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;\n\ntypedef struct _FILE_FS_OBJECTID_INFORMATION\n{\n    UCHAR ObjectId[16];\n    union\n    {\n        struct\n        {\n            UCHAR BirthVolumeId[16];\n            UCHAR BirthObjectId[16];\n            UCHAR DomainId[16];\n        };\n        UCHAR ExtendedInfo[48];\n    };\n} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION;\n\ntypedef struct _FILE_FS_DEVICE_INFORMATION\n{\n    DEVICE_TYPE DeviceType;\n    ULONG Characteristics;\n} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;\n\ntypedef struct _FILE_FS_ATTRIBUTE_INFORMATION\n{\n    ULONG FileSystemAttributes;\n    LONG MaximumComponentNameLength;\n    ULONG FileSystemNameLength;\n    _Field_size_bytes_(FileSystemNameLength) WCHAR FileSystemName[1];\n} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;\n\ntypedef struct _FILE_FS_DRIVER_PATH_INFORMATION\n{\n    BOOLEAN DriverInPath;\n    ULONG DriverNameLength;\n    _Field_size_bytes_(DriverNameLength) WCHAR DriverName[1];\n} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION;\n\ntypedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION\n{\n    ULONG Flags;\n} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION;\n\n#define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001\n#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002\n#define SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004\n#define SSINFO_FLAGS_TRIM_ENABLED 0x00000008\n#define SSINFO_FLAGS_BYTE_ADDRESSABLE 0x00000010 // since REDSTONE\n\n// If set for Sector and Partition fields, alignment is not known.\n#define SSINFO_OFFSET_UNKNOWN 0xffffffff\n\ntypedef struct _FILE_FS_SECTOR_SIZE_INFORMATION\n{\n    ULONG LogicalBytesPerSector;\n    ULONG PhysicalBytesPerSectorForAtomicity;\n    ULONG PhysicalBytesPerSectorForPerformance;\n    ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity;\n    ULONG Flags; // SSINFO_FLAGS_*\n    ULONG ByteOffsetForSectorAlignment;\n    ULONG ByteOffsetForPartitionAlignment;\n} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;\n\ntypedef struct _FILE_FS_DATA_COPY_INFORMATION\n{\n    ULONG NumberOfCopies;\n} FILE_FS_DATA_COPY_INFORMATION, *PFILE_FS_DATA_COPY_INFORMATION;\n\ntypedef struct _FILE_FS_METADATA_SIZE_INFORMATION\n{\n    LARGE_INTEGER TotalMetadataAllocationUnits;\n    ULONG SectorsPerAllocationUnit;\n    ULONG BytesPerSector;\n} FILE_FS_METADATA_SIZE_INFORMATION, *PFILE_FS_METADATA_SIZE_INFORMATION;\n\ntypedef struct _FILE_FS_FULL_SIZE_INFORMATION_EX\n{\n    ULONGLONG ActualTotalAllocationUnits;\n    ULONGLONG ActualAvailableAllocationUnits;\n    ULONGLONG ActualPoolUnavailableAllocationUnits;\n    ULONGLONG CallerTotalAllocationUnits;\n    ULONGLONG CallerAvailableAllocationUnits;\n    ULONGLONG CallerPoolUnavailableAllocationUnits;\n    ULONGLONG UsedAllocationUnits;\n    ULONGLONG TotalReservedAllocationUnits;\n    ULONGLONG VolumeStorageReserveAllocationUnits;\n    ULONGLONG AvailableCommittedAllocationUnits;\n    ULONGLONG PoolAvailableAllocationUnits;\n    ULONG SectorsPerAllocationUnit;\n    ULONG BytesPerSector;\n} FILE_FS_FULL_SIZE_INFORMATION_EX, *PFILE_FS_FULL_SIZE_INFORMATION_EX;\n\ntypedef struct _FILE_FS_GUID_INFORMATION\n{\n    GUID FsGuid;\n} FILE_FS_GUID_INFORMATION, *PFILE_FS_GUID_INFORMATION;\n\n//\n// System calls\n//\n\n/**\n * The NtCreateFile routine creates a new file or directory, or opens an existing file, device, directory, or volume.\n *\n * \\param[out] FileHandle Pointer to a variable that receives a handle to the pipe.\n * \\param[in] DesiredAccess The requested access to the object.\n * \\param[in] ObjectAttributes Pointer to an OBJECT_ATTRIBUTES structure that contains the object attributes, including pipe name.\n * \\param[out] IoStatusBlock Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the operation.\n * \\param[in] AllocationSize The initial allocation size in bytes for the file. Specify a non-zero value to eliminate disk fragmentation, since the file system pre-allocates the file using a contiguous block.\n * \\param[in] FileAttributes The file attributes. Explicitly specified attributes are applied only when the file is created, superseded, or, in some cases, overwritten.\n * \\param[in] ShareAccess The type of share access that the caller would like to use in the file.\n * \\param[in] CreateDisposition Specifies how the file should be handled when the file already exists.\n * \\param[in] CreateOptions Specifies the options to be applied when creating or opening the file.\n * \\param[in] EaBuffer Pointer to an EA buffer used to pass extended attributes.\n * \\param[in] EaLength Length of the EA buffer.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/Winternl/nf-winternl-ntcreatefile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,\n    _In_ ULONG EaLength\n    );\n\n/**\n * The NtCreateNamedPipeFile routine deletes the specified file.\n *\n * \\param[out] FileHandle Pointer to a variable that receives a handle to the pipe.\n * \\param[in] DesiredAccess The requested access to the object.\n * \\param[in] ObjectAttributes Pointer to an OBJECT_ATTRIBUTES structure that contains the object attributes, including pipe name.\n * \\param[out] IoStatusBlock Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the operation.\n * \\param[in] ShareAccess Specifies the type of share access for the file.\n * \\param[in] CreateDisposition Specifies how the file should be handled when the file already exists.\n * \\param[in] CreateOptions Specifies the options to be applied when creating or opening the file.\n * \\param[in] NamedPipeType Type of named pipe to create (byte-type or message-type).\n * \\param[in] ReadMode Mode in which to read the pipe (byte-type or message-type).\n * \\param[in] CompletionMode Specifies blocking or non-blocking mode of the pipe.\n * \\param[in] MaximumInstances Maximum number of simultaneous instances of the named pipe.\n * \\param[in] InboundQuota Specifies the pool quota that is reserved for writes to the inbound side of the named pipe.\n * \\param[in] OutboundQuota Specifies the pool quota that is reserved for writes to the inbound side of the named pipe.\n * \\param[in] DefaultTimeout An optional pointer to a timeout value that is used if a timeout value is not specified when waiting for an instance of a named pipe.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/devnotes/nt-create-named-pipe-file\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateNamedPipeFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_ ULONG NamedPipeType,\n    _In_ ULONG ReadMode,\n    _In_ ULONG CompletionMode,\n    _In_ ULONG MaximumInstances,\n    _In_ ULONG InboundQuota,\n    _In_ ULONG OutboundQuota,\n    _In_ PLARGE_INTEGER DefaultTimeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateMailslotFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG CreateOptions,\n    _In_ ULONG MailslotQuota,\n    _In_ ULONG MaximumMessageSize,\n    _In_ PLARGE_INTEGER ReadTimeout\n    );\n\n/**\n * The NtOpenFile routine opens an existing file, device, directory, or volume, and returns a handle for the file object.\n *\n * \\param[out] FileHandle Pointer to a variable that receives a handle to the file.\n * \\param[in] DesiredAccess The requested access to the object.\n * \\param[in] ObjectAttributes Pointer to an OBJECT_ATTRIBUTES structure that contains the file's attributes, including file name.\n * \\param[out] IoStatusBlock Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the operation.\n * \\param[in] ShareAccess Specifies the type of share access for the file.\n * \\param[in] OpenOptions Specifies the options to apply when opening the file.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntopenfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions\n    );\n\n/**\n * The NtDeleteFile routine deletes the specified file.\n *\n * \\param[in] ObjectAttributes Pointer to an OBJECT_ATTRIBUTES structure that contains the file's attributes, including file name.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwdeletefile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteFile(\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtFlushBuffersFile routine sends a flush request for the specified file to the file system.\n *\n * \\param[in] FileHandle A handle to the file whose buffers will be flushed.\n * \\param[out] IoStatusBlock Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the operation.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwflushbuffersfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushBuffersFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\n//  Flag definitions for NtFlushBuffersFileEx\n//\n//  If none of the below flags are specified the following will occur for a\n//  given file handle:\n//      - Write any modified data for the given file from the Windows in-memory\n//        cache.\n//      - Commit all pending metadata changes for the given file from the\n//        Windows in-memory cache.\n//      - Send a SYNC command to the underlying storage device to commit all\n//        written data in the devices cache to persistent storage.\n//\n//  If a volume handle is specified:\n//      - Write all modified data for all files on the volume from the Windows\n//        in-memory cache.\n//      - Commit all pending metadata changes for all files on the volume from\n//        the Windows in-memory cache.\n//      - Send a SYNC command to the underlying storage device to commit all\n//        written data in the devices cache to persistent storage.\n//\n//  This is equivalent to how NtFlushBuffersFile has always worked.\n\n\n// If set, File data and metadata in the file cache will be written, and the\n// underlying storage is synchronized to flush its cache.\n// Windows file systems supported: NTFS, ReFS, FAT, exFAT.\n//\n#define FLUSH_FLAGS_FILE_NORMAL 0x00000000\n//  If set, this operation will write the data for the given file from the\n//  Windows in-memory cache.  This will NOT commit any associated metadata\n//  changes.  This will NOT send a SYNC to the storage device to flush its\n//  cache.  Not supported on volume handles.\n//\n#define FLUSH_FLAGS_FILE_DATA_ONLY 0x00000001\n//\n//  If set, this operation will commit both the data and metadata changes for\n//  the given file from the Windows in-memory cache.  This will NOT send a SYNC\n//  to the storage device to flush its cache.  Not supported on volume handles.\n//\n#define FLUSH_FLAGS_NO_SYNC 0x00000002\n//\n//  If set, this operation will write the data for the given file from the\n//  Windows in-memory cache.  It will also try to skip updating the timestamp\n//  as much as possible.  This will send a SYNC to the storage device to flush its\n//  cache.  Not supported on volume or directory handles.\n//\n#define FLUSH_FLAGS_FILE_DATA_SYNC_ONLY 0x00000004 // REDSTONE1\n//\n//  If set, this operation will write the data for the given file from the\n//  Windows in-memory cache.  It will also try to skip updating the timestamp\n//  as much as possible.  This will send a SYNC to the storage device to flush its\n//  cache.  Not supported on volume or directory handles.\n//\n#define FLUSH_FLAGS_FLUSH_AND_PURGE 0x00000008 // 24H2\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n/**\n * The NtFlushBuffersFileEx routine sends a flush request for a given file to the file system. An optional flush operation flag can be set to control how file data is written to storage.\n *\n * \\param FileHandle A handle to the file object representing the file, directory, device or volume.\n * \\param Flags Flush operation flags.\n * \\param Parameters Pointer to a block with additional parameters. This parameter must currently be set to NULL.\n * \\param ParametersSize The size, in bytes, of the block that Parameters point to. This parameter must currently be set to 0.\n * \\param IoStatusBlock Address of the caller's I/O status block. This parameter is required and cannot be NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntflushbuffersfileex\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushBuffersFileEx(\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags,\n    _In_reads_bytes_(ParametersSize) PVOID Parameters,\n    _In_ ULONG ParametersSize,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_8\n\n/**\n * The NtQueryInformationFile routine returns various kinds of information about a file object.\n *\n * \\param FileHandle A handle to the file object representing the file or directory.\n * \\param IoStatusBlock A pointer to an IO_STATUS_BLOCK structure that receives the final completion status, and the number of bytes written to the buffer pointed to by FileInformation.\n * \\param FileInformation Pointer to a caller-allocated buffer into which the routine writes the requested information about the file object.\n * \\param Length The size, in bytes, of the buffer pointed to by FileInformation.\n * \\param FileInformationClass Specifies the type of information to be returned about the file, in the buffer that FileInformation points to.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS2)\n/**\n * The NtQueryInformationByName routine returns various kinds of information about a file object by file name.\n *\n * \\param ObjectAttributes Pointer to an OBJECT_ATTRIBUTES structure that contains the file's attributes, including file name.\n * \\param IoStatusBlock A pointer to an IO_STATUS_BLOCK structure that receives the final completion status, and the number of bytes written to the buffer pointed to by FileInformation.\n * \\param FileInformation Pointer to a caller-allocated buffer into which the routine writes the requested information about the file object.\n * \\param Length The size, in bytes, of the buffer pointed to by FileInformation.\n * \\param FileInformationClass Specifies the type of information to be returned about the file, in the buffer that FileInformation points to.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationbyname\n * \\remarks NtQueryInformationByName queries and returns the requested information without opening the actual file,\n * making it more efficient than NtQueryInformationFile, which requires a file open and subsequent file close.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationByName(\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_10_RS2\n\n/**\n * The NtSetInformationFile routine changes various kinds of information about a file object.\n *\n * \\param FileHandle A handle to the file object representing the file or directory.\n * \\param IoStatusBlock A pointer to an IO_STATUS_BLOCK structure that receives the final completion status, and the number of bytes written to the buffer pointed to by FileInformation.\n * \\param FileInformation Pointer to a buffer that contains the information to set for the file.\n * \\param Length The size, in bytes, of the buffer pointed to by FileInformation.\n * \\param FileInformationClass The type of information, supplied in the buffer pointed to by FileInformation, to set for the file.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntsetinformationfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass\n    );\n\n/**\n * The NtQueryDirectoryFile routine returns various kinds of information about files in the directory specified by a given file handle.\n *\n * \\param[in] FileHandle A handle for the file object that represents the directory for which information is being requested.\n * \\param[in] Event An optional handle for a caller-created event. The event is set to the Signaled state the requested operation is completed.\n * \\param[in] ApcRoutine An address of an optional, caller-supplied APC routine to be called when the requested operation completes.\n * \\param[in] ApcContext An address of an optional, caller-supplied APC or I/O completion object associated with the file object.\n * \\param[out] IoStatusBlock A pointer to an IO_STATUS_BLOCK structure that receives the final completion status, and the number of bytes written to the buffer pointed to by FileInformation.\n * \\param[out] FileInformation A pointer to a buffer that receives the desired information about the file.\n * \\param[in] Length The size, in bytes, of the buffer pointed to by FileInformation.\n * \\param[in] FileInformationClass The type of information to be returned about files in the directory.\n * \\param[in] ReturnSingleEntry Set to TRUE if only a single entry should be returned, FALSE otherwise.\n * \\param[in] FileName An optional pointer to a Unicode string search expression containing the name of a file (or multiple files, if wildcards are used) within the directory.\n * \\param[in] RestartScan Set to TRUE if the scan is to start at the first entry in the directory. Set to FALSE if resuming the scan from a previous call.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntquerydirectoryfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_opt_ PCUNICODE_STRING FileName,\n    _In_ BOOLEAN RestartScan\n    );\n\n// QueryFlags values for NtQueryDirectoryFileEx\n/**\n * The scan will start at the first entry in the directory. If this flag is not set, the scan will resume from where the last query ended.\n */\n#define FILE_QUERY_RESTART_SCAN 0x00000001\n/**\n * Normally the return buffer is packed with as many matching directory entries that fit.\n * If this flag is set, the file system will return only one directory entry at a time.\n * This does make the operation less efficient.\n */\n#define FILE_QUERY_RETURN_SINGLE_ENTRY 0x00000002\n/**\n * The scan should start at a specified indexed position in the directory.\n * This flag can only be set if you generate your own IRP_MJ_DIRECTORY_CONTROL IRP; the index is specified in the IRP.\n * How the position is specified varies from file system to file system.\n */\n#define FILE_QUERY_INDEX_SPECIFIED 0x00000004\n/**\n * Any file system filters that perform directory virtualization or just-in-time expansion should simply pass the request\n * through to the file system and return entries that are currently on disk. Not all file systems support this flag.\n */\n#define FILE_QUERY_RETURN_ON_DISK_ENTRIES_ONLY 0x00000008\n/**\n * File systems maintain per-FileObject directory cursor information. When multiple threads do queries using the same FileObject,\n * access to the per-FileObject structure is single threaded to prevent corruption of the cursor state.\n * This flag tells the file system to not update per-FileObject cursor state information thus allowing multiple threads\n * to query in parallel using the same handle. It behaves as if SL_RESTART_SCAN is specified on each call. If a wild card pattern\n * is given on the next call, the operation will not pick up where the last query ended.\n * This allows for true asynchronous directory query support. Not all file systems support this flag.\n */\n#define FILE_QUERY_NO_CURSOR_UPDATE 0x00000010 // RS5\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS3)\n/**\n * The NtQueryDirectoryFileEx routine returns various kinds of information about files in the directory specified by a given file handle.\n *\n * \\param[in] FileHandle A handle for the file object that represents the directory for which information is being requested.\n * \\param[in] Event An optional handle for a caller-created event. The event is set to the Signaled state the requested operation is completed.\n * \\param[in] ApcRoutine An address of an optional, caller-supplied APC routine to be called when the requested operation completes.\n * \\param[in] ApcContext An address of an optional, caller-supplied APC or I/O completion object associated with the file object.\n * \\param[out] IoStatusBlock A pointer to an IO_STATUS_BLOCK structure that receives the final completion status, and the number of bytes written to the buffer pointed to by FileInformation.\n * \\param[out] FileInformation A pointer to a buffer that receives the desired information about the file.\n * \\param[in] Length The size, in bytes, of the buffer pointed to by FileInformation.\n * \\param[in] FileInformationClass The type of information to be returned about files in the directory.\n * \\param[in] QueryFlags One or more of the flags contained in SL_QUERY_DIRECTORY_MASK\n * \\param[in] FileName An optional pointer to a Unicode string search expression containing the name of a file (or multiple files, if wildcards are used) within the directory.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntquerydirectoryfileex\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDirectoryFileEx(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _In_ ULONG QueryFlags,\n    _In_opt_ PCUNICODE_STRING FileName\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_10_RS3\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryEaFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_reads_bytes_opt_(EaListLength) PVOID EaList,\n    _In_ ULONG EaListLength,\n    _In_opt_ PULONG EaIndex,\n    _In_ BOOLEAN RestartScan\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetEaFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryQuotaInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_reads_bytes_opt_(SidListLength) PVOID SidList,\n    _In_ ULONG SidListLength,\n    _In_opt_ PSID StartSid,\n    _In_ BOOLEAN RestartScan\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetQuotaInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\n/**\n * The NtQueryVolumeInformationFile routine retrieves information about the volume associated with a given file, directory, storage device, or volume.\n *\n * \\param[in] FileHandle A handle to the file, directory, storage device, or volume for which volume information is being requested.\n * \\param[out] IoStatusBlock A pointer to an IO_STATUS_BLOCK structure that receives the final completion status, and the number of bytes written to the buffer pointed to by FsInformation.\n * \\param[out] FsInformation A pointer to a caller-allocated buffer that receives the desired information about the volume.\n * \\param[in] Length The size, in bytes, of the buffer pointed to by FsInformation.\n * \\param[in] FsInformationClass The type of information to be returned about the volume.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryvolumeinformationfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryVolumeInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FsInformation,\n    _In_ ULONG Length,\n    _In_ FSINFOCLASS FsInformationClass\n    );\n\n/**\n * The NtSetVolumeInformationFile routine modifies information about the volume associated with a given file, directory, storage device, or volume.\n *\n * \\param[in] FileHandle A handle to the file, directory, storage device, or volume for which volume information is being requested.\n * \\param[out] IoStatusBlock A pointer to an IO_STATUS_BLOCK structure that receives the final completion status, and the number of bytes written to the buffer pointed to by FsInformation.\n * \\param[in] FsInformation A pointer to a caller-allocated buffer containing the volume information to be modified.\n * \\param[in] Length The size, in bytes, of the buffer pointed to by FsInformation.\n * \\param[in] FsInformationClass The type of information to set about the volume.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwsetvolumeinformationfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetVolumeInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID FsInformation,\n    _In_ ULONG Length,\n    _In_ FSINFOCLASS FsInformationClass\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelIoFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelIoFileEx(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelSynchronousIoFile(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\n/**\n * The NtDeviceIoControlFile function sends a control code directly to a specified device driver, causing the corresponding driver to perform the specified operation.\n *\n * \\param[in] FileHandle A handle to the file object representing the file or directory on which the specified action is to be performed.\n * \\param[in] Event A handle for a caller-created event. This parameter is optional and can be NULL. It must be NULL if the caller will wait for the FileHandle to be set to the Signaled state.\n * \\param[in] ApcRoutine Address of a caller-supplied APC routine to be called when the requested operation completes. This parameter is optional and can be NULL.\n * \\param[in] ApcContext Pointer to a caller-determined context area. This parameter value is used as the APC context if the caller supplies an APC, or is used as the completion context if an I/O completion object has been associated with the file object.\n * \\param[out] IoStatusBlock Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the operation.\n * \\param[in] IoControlCode IOCTL_XXX code that indicates which device I/O control operation is to be carried out on, usually by the underlying device driver.\n * \\param[in] InputBuffer Pointer to a caller-allocated input buffer that contains device-specific information to be given to the target driver.\n * \\param[in] InputBufferLength Size, in bytes, of the buffer at InputBuffer. This value is ignored if InputBuffer is NULL.\n * \\param[out] OutputBuffer Pointer to a caller-allocated output buffer in which information is returned from the target driver.\n * \\param[in] OutputBufferLength Size, in bytes, of the buffer at OutputBuffer. This value is ignored if OutputBuffer is NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwdeviceiocontrolfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeviceIoControlFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG IoControlCode,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\n/**\n * The NtFsControlFile function sends a control code directly to a file system or filter driver, causing the corresponding driver to perform the specified action.\n *\n * \\param[in] FileHandle A handle to the file object representing the file or directory on which the specified action is to be performed.\n * \\param[in] Event A handle for a caller-created event. This parameter is optional and can be NULL. It must be NULL if the caller will wait for the FileHandle to be set to the Signaled state.\n * \\param[in] ApcRoutine Address of a caller-supplied APC routine to be called when the requested operation completes. This parameter is optional and can be NULL.\n * \\param[in] ApcContext Pointer to a caller-determined context area. This parameter value is used as the APC context if the caller supplies an APC, or is used as the completion context if an I/O completion object has been associated with the file object.\n * \\param[out] IoStatusBlock Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the operation.\n * \\param[in] FsControlCode FSCTL_XXX code that indicates which file system control operation is to be carried out.\n * \\param[in] InputBuffer Pointer to a caller-allocated input buffer that contains device-specific information to be given to the target driver.\n * \\param[in] InputBufferLength Size, in bytes, of the buffer at InputBuffer. This value is ignored if InputBuffer is NULL.\n * \\param[out] OutputBuffer Pointer to a caller-allocated output buffer in which information is returned from the target driver.\n * \\param[in] OutputBufferLength Size, in bytes, of the buffer at OutputBuffer. This value is ignored if OutputBuffer is NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwfscontrolfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFsControlFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG FsControlCode,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\n/**\n * The NtReadFile function reads data from an open file.\n *\n * \\param[in] FileHandle A handle to the file object representing the file or directory on which the specified action is to be performed.\n * \\param[in] Event A handle for a caller-created event. This parameter is optional and can be NULL. It must be NULL if the caller will wait for the FileHandle to be set to the Signaled state.\n * \\param[in] ApcRoutine Address of a caller-supplied APC routine to be called when the requested operation completes. This parameter is optional and can be NULL.\n * \\param[in] ApcContext Pointer to a caller-determined context area. This parameter value is used as the APC context if the caller supplies an APC, or is used as the completion context if an I/O completion object has been associated with the file object.\n * \\param[out] IoStatusBlock Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the operation.\n * \\param[out] Buffer Pointer to a caller-allocated buffer that receives the data read from the file.\n * \\param[in] Length The size, in bytes, of the buffer pointed to by Buffer.\n * \\param[in] ByteOffset Pointer to a variable that specifies the starting byte offset in the file where the read operation will begin.\n * \\param[in] Key Device and intermediate drivers should set this pointer to NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwreadfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\n/**\n * The NtWriteFile function writes data to an open file.\n *\n * \\param[in] FileHandle A handle to the file object representing the file or directory on which the specified action is to be performed.\n * \\param[in] Event A handle for a caller-created event. This parameter is optional and can be NULL. It must be NULL if the caller will wait for the FileHandle to be set to the Signaled state.\n * \\param[in] ApcRoutine Address of a caller-supplied APC routine to be called when the requested operation completes. This parameter is optional and can be NULL.\n * \\param[in] ApcContext Pointer to a caller-determined context area. This parameter value is used as the APC context if the caller supplies an APC, or is used as the completion context if an I/O completion object has been associated with the file object.\n * \\param[out] IoStatusBlock Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the operation.\n * \\param[in] Buffer Pointer to a caller-allocated buffer that contains the data to write to the file.\n * \\param[in] Length The size, in bytes, of the buffer pointed to by Buffer.\n * \\param[in] ByteOffset Pointer to a variable that specifies the starting byte offset in the file for beginning the write operation.\n * \\param[in] Key Device and intermediate drivers should set this pointer to NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwwritefile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWriteFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadFileScatter(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PFILE_SEGMENT_ELEMENT SegmentArray,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWriteFileGather(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PFILE_SEGMENT_ELEMENT SegmentArray,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLockFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PLARGE_INTEGER ByteOffset,\n    _In_ PLARGE_INTEGER Length,\n    _In_ ULONG Key,\n    _In_ BOOLEAN FailImmediately,\n    _In_ BOOLEAN ExclusiveLock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnlockFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PLARGE_INTEGER ByteOffset,\n    _In_ PLARGE_INTEGER Length,\n    _In_ ULONG Key\n    );\n\n/**\n * The NtQueryAttributesFile function retrieves basic attributes for the specified file.\n *\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that supplies the attributes to be used for the file object.\n * \\param FileInformation A pointer to a FILE_BASIC_INFORMATION structure to receive the returned file attribute information.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/devnotes/ntqueryattributesfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryAttributesFile(\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PFILE_BASIC_INFORMATION FileInformation\n    );\n\n/**\n * The NtQueryFullAttributesFile function retrieves network open information for the specified file.\n *\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that supplies the attributes to be used for the file object.\n * \\param FileInformation A pointer to a FILE_NETWORK_OPEN_INFORMATION structure that receives the returned file attributes information.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwqueryfullattributesfile\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryFullAttributesFile(\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    );\n\n//\n// NtNotifyChangeDirectoryFile information\n//\n\n#define FILE_NOTIFY_CHANGE_FILE_NAME    0x00000001   // winnt\n#define FILE_NOTIFY_CHANGE_DIR_NAME     0x00000002   // winnt\n#define FILE_NOTIFY_CHANGE_NAME         0x00000003\n#define FILE_NOTIFY_CHANGE_ATTRIBUTES   0x00000004   // winnt\n#define FILE_NOTIFY_CHANGE_SIZE         0x00000008   // winnt\n#define FILE_NOTIFY_CHANGE_LAST_WRITE   0x00000010   // winnt\n#define FILE_NOTIFY_CHANGE_LAST_ACCESS  0x00000020   // winnt\n#define FILE_NOTIFY_CHANGE_CREATION     0x00000040   // winnt\n#define FILE_NOTIFY_CHANGE_EA           0x00000080\n#define FILE_NOTIFY_CHANGE_SECURITY     0x00000100   // winnt\n#define FILE_NOTIFY_CHANGE_STREAM_NAME  0x00000200\n#define FILE_NOTIFY_CHANGE_STREAM_SIZE  0x00000400\n#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800\n#define FILE_NOTIFY_VALID_MASK          0x00000fff\n\n#define FILE_ACTION_ADDED                   0x00000001   // winnt\n#define FILE_ACTION_REMOVED                 0x00000002   // winnt\n#define FILE_ACTION_MODIFIED                0x00000003   // winnt\n#define FILE_ACTION_RENAMED_OLD_NAME        0x00000004   // winnt\n#define FILE_ACTION_RENAMED_NEW_NAME        0x00000005   // winnt\n#define FILE_ACTION_ADDED_STREAM            0x00000006\n#define FILE_ACTION_REMOVED_STREAM          0x00000007\n#define FILE_ACTION_MODIFIED_STREAM         0x00000008\n#define FILE_ACTION_REMOVED_BY_DELETE       0x00000009\n#define FILE_ACTION_ID_NOT_TUNNELLED        0x0000000A\n#define FILE_ACTION_TUNNELLED_ID_COLLISION  0x0000000B\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtNotifyChangeDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer, // FILE_NOTIFY_INFORMATION\n    _In_ ULONG Length,\n    _In_ ULONG CompletionFilter,\n    _In_ BOOLEAN WatchTree\n    );\n\n// private\ntypedef enum _DIRECTORY_NOTIFY_INFORMATION_CLASS\n{\n    DirectoryNotifyInformation = 1, // FILE_NOTIFY_INFORMATION\n    DirectoryNotifyExtendedInformation, // FILE_NOTIFY_EXTENDED_INFORMATION\n    DirectoryNotifyFullInformation, // FILE_NOTIFY_FULL_INFORMATION // since 22H2\n    DirectoryNotifyMaximumInformation\n} DIRECTORY_NOTIFY_INFORMATION_CLASS, *PDIRECTORY_NOTIFY_INFORMATION_CLASS;\n\n#if !defined(NTDDI_WIN10_RS5) || (NTDDI_VERSION < NTDDI_WIN10_RS5)\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_NOTIFY_INFORMATION\n{\n   ULONG NextEntryOffset;\n   ULONG Action;\n   ULONG FileNameLength;\n   WCHAR FileName[1];\n} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;\n\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_NOTIFY_EXTENDED_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG Action;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastModificationTime;\n    LARGE_INTEGER LastChangeTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER AllocatedLength;\n    LARGE_INTEGER FileSize;\n    ULONG FileAttributes;\n    union\n    {\n        ULONG ReparsePointTag;\n        ULONG EaSize;\n    };\n    FILE_INTERNAL_INFORMATION FileId;\n    FILE_INTERNAL_INFORMATION ParentFileId;\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_NOTIFY_EXTENDED_INFORMATION, *PFILE_NOTIFY_EXTENDED_INFORMATION;\n#endif // NTDDI_WIN10_RS5\n\n#define FILE_NAME_FLAG_HARDLINK      0    // not part of a name pair\n#define FILE_NAME_FLAG_NTFS          0x01 // NTFS name in a name pair\n#define FILE_NAME_FLAG_DOS           0x02 // DOS name in a name pair\n#define FILE_NAME_FLAG_BOTH          0x03 // NTFS+DOS combined name\n#define FILE_NAME_FLAGS_UNSPECIFIED  0x80 // not specified by file system (do not combine with other flags)\n\n#if !defined(NTDDI_WIN10_NI) || (NTDDI_VERSION < NTDDI_WIN10_NI)\n_Struct_size_bytes_(NextEntryOffset)\ntypedef struct _FILE_NOTIFY_FULL_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG Action;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastModificationTime;\n    LARGE_INTEGER LastChangeTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER AllocatedLength;\n    LARGE_INTEGER FileSize;\n    ULONG FileAttributes;\n    union\n    {\n        ULONG ReparsePointTag;\n        ULONG EaSize;\n    };\n    FILE_INTERNAL_INFORMATION FileId;\n    FILE_INTERNAL_INFORMATION ParentFileId;\n    USHORT FileNameLength;\n    BYTE FileNameFlags;\n    BYTE Reserved;\n    WCHAR FileName[1];\n} FILE_NOTIFY_FULL_INFORMATION, *PFILE_NOTIFY_FULL_INFORMATION;\n#endif // NTDDI_WIN10_NI\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS3)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtNotifyChangeDirectoryFileEx(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ ULONG CompletionFilter,\n    _In_ BOOLEAN WatchTree,\n    _In_opt_ DIRECTORY_NOTIFY_INFORMATION_CLASS DirectoryNotifyInformationClass\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_10_RS3\n\n/**\n * The NtLoadDriver function loads a driver specified by the DriverServiceName parameter.\n *\n * \\param DriverServiceName A pointer to a UNICODE_STRING structure that specifies the name of the driver service to load.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLoadDriver(\n    _In_ PCUNICODE_STRING DriverServiceName\n    );\n\n/**\n * The NtUnloadDriver function unloads a driver specified by the DriverServiceName parameter.\n *\n * \\param DriverServiceName A pointer to a UNICODE_STRING structure that specifies the name of the driver service to unload.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnloadDriver(\n    _In_ PCUNICODE_STRING DriverServiceName\n    );\n\n//\n// I/O completion port\n//\n\n#ifndef IO_COMPLETION_QUERY_STATE\n#define IO_COMPLETION_QUERY_STATE 0x0001\n#endif\n\n#ifndef IO_COMPLETION_MODIFY_STATE\n#define IO_COMPLETION_MODIFY_STATE 0x0002\n#endif\n\n#ifndef IO_COMPLETION_ALL_ACCESS\n#define IO_COMPLETION_ALL_ACCESS (IO_COMPLETION_QUERY_STATE|IO_COMPLETION_MODIFY_STATE|STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE)\n#endif\n\ntypedef enum _IO_COMPLETION_INFORMATION_CLASS\n{\n    IoCompletionBasicInformation\n} IO_COMPLETION_INFORMATION_CLASS;\n\ntypedef struct _IO_COMPLETION_BASIC_INFORMATION\n{\n    LONG Depth;\n} IO_COMPLETION_BASIC_INFORMATION, *PIO_COMPLETION_BASIC_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateIoCompletion(\n    _Out_ PHANDLE IoCompletionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ ULONG NumberOfConcurrentThreads\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenIoCompletion(\n    _Out_ PHANDLE IoCompletionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryIoCompletion(\n    _In_ HANDLE IoCompletionHandle,\n    _In_ IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,\n    _Out_writes_bytes_(IoCompletionInformationLength) PVOID IoCompletionInformation,\n    _In_ ULONG IoCompletionInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetIoCompletion(\n    _In_ HANDLE IoCompletionHandle,\n    _In_opt_ PVOID KeyContext,\n    _In_opt_ PVOID ApcContext,\n    _In_ NTSTATUS IoStatus,\n    _In_ ULONG_PTR IoStatusInformation\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetIoCompletionEx(\n    _In_ HANDLE IoCompletionHandle,\n    _In_ HANDLE IoCompletionPacketHandle,\n    _In_opt_ PVOID KeyContext,\n    _In_opt_ PVOID ApcContext,\n    _In_ NTSTATUS IoStatus,\n    _In_ ULONG_PTR IoStatusInformation\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRemoveIoCompletion(\n    _In_ HANDLE IoCompletionHandle,\n    _Out_ PVOID *KeyContext,\n    _Out_ PVOID *ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n// private\ntypedef struct _FILE_IO_COMPLETION_INFORMATION\n{\n    PVOID KeyContext;\n    PVOID ApcContext;\n    IO_STATUS_BLOCK IoStatusBlock;\n} FILE_IO_COMPLETION_INFORMATION, *PFILE_IO_COMPLETION_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRemoveIoCompletionEx(\n    _In_ HANDLE IoCompletionHandle,\n    _Out_writes_to_(Count, *NumEntriesRemoved) PFILE_IO_COMPLETION_INFORMATION IoCompletionInformation,\n    _In_ ULONG Count,\n    _Out_ PULONG NumEntriesRemoved,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _In_ BOOLEAN Alertable\n    );\n\n//\n// Wait completion packet\n//\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n/**\n * The NtCreateWaitCompletionPacket routine creates a wait completion packet object.\n *\n * A wait completion packet is a kernel object that can be associated with wait\n * or I/O completion sources and later queried via I/O completion mechanisms.\n *\n * \\param WaitCompletionPacketHandle Pointer to a variable that receives a handle\n *        to the newly created wait completion packet object.\n * \\param DesiredAccess The access mask that specifies the requested access to\n *        the wait completion packet object.\n * \\param ObjectAttributes Optional pointer to an OBJECT_ATTRIBUTES structure that\n *        supplies the object name and other attributes. May be NULL.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateWaitCompletionPacket(\n    _Out_ PHANDLE WaitCompletionPacketHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtAssociateWaitCompletionPacket routine associates a wait completion packet\n * with an I/O completion port or other target object so that a completion packet\n * will be queued when the target object becomes signaled or an I/O completes.\n *\n * This routine links the specified wait completion packet with the target\n * completion object so the packet will carry the supplied context and status\n * information when it is delivered.\n *\n * \\param[in] WaitCompletionPacketHandle Handle to the wait completion packet object.\n * \\param[in] IoCompletionHandle Handle to an I/O completion port (or compatible object)\n *        with which the wait completion packet should be associated.\n * \\param[in] TargetObjectHandle Handle to the object to watch for completion or\n *        signalling (for example, a waitable kernel object).\n * \\param[in] KeyContext Optional pointer to caller-specified context that will be\n *        stored in the completion packet and returned to the consumer.\n * \\param[in] ApcContext Optional pointer to caller-specified APC/context value that\n *        will be stored in the completion packet and returned to the consumer.\n * \\param[in] IoStatus The NTSTATUS value to be placed in the completion packet.\n * \\param[in] IoStatusInformation Additional information ( ULONG_PTR ) to be placed\n *        in the completion packet (commonly used for number of bytes transferred).\n * \\param[out] AlreadySignaled Optional pointer to a BOOLEAN that, on return, is set\n *        to TRUE if the packet was already signaled at the time of association;\n *        otherwise FALSE. May be NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Use this routine to arrange for notification of a target object's\n *          completion by queuing a wait completion packet containing the\n *          supplied context and status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAssociateWaitCompletionPacket(\n    _In_ HANDLE WaitCompletionPacketHandle,\n    _In_ HANDLE IoCompletionHandle,\n    _In_ HANDLE TargetObjectHandle,\n    _In_opt_ PVOID KeyContext,\n    _In_opt_ PVOID ApcContext,\n    _In_ NTSTATUS IoStatus,\n    _In_ ULONG_PTR IoStatusInformation,\n    _Out_opt_ PBOOLEAN AlreadySignaled\n    );\n\n/**\n * The NtCancelWaitCompletionPacket routine cancels a previously associated wait\n * completion packet or removes a signaled packet from its queue.\n *\n * \\param[in] WaitCompletionPacketHandle Handle to the wait completion packet object to cancel.\n * \\param[in] RemoveSignaledPacket If TRUE and the packet is already signaled, remove\n *        the signaled packet from the target queue; if FALSE, cancellation will\n *        prevent future signaling but will not remove an already queued packet.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks After successful cancellation, the wait completion packet will no\n *          longer be delivered as a result of the previously associated target.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelWaitCompletionPacket(\n    _In_ HANDLE WaitCompletionPacketHandle,\n    _In_ BOOLEAN RemoveSignaledPacket\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\n/**\n * The NtCopyFileChunk routine copies a contiguous range of bytes (a chunk)\n * from a source file to a destination file. The operation may be performed\n * synchronously or asynchronously depending on the file handles and flags.\n *\n * \\param[in] SourceHandle Handle to the source file. The handle must be opened\n *            with access that allows reading the specified range.\n * \\param[in] DestinationHandle Handle to the destination file. The handle must\n *            be opened with access that allows writing to the specified range.\n * \\param[in] EventHandle Optional handle to an event object. If provided,\n *            the event is set when the operation completes. May be NULL.\n * \\param[out] IoStatusBlock Pointer to an IO_STATUS_BLOCK structure that\n *            receives the final completion status and information about the operation.\n * \\param[in] Length The number of bytes to copy.\n * \\param[in] SourceOffset Pointer to a LARGE_INTEGER specifying the byte\n *            offset in the source file at which copying begins.\n * \\param[in] DestOffset Pointer to a LARGE_INTEGER specifying the byte\n *            offset in the destination file at which copying begins.\n * \\param[in] SourceKey Optional pointer to a source file key. May be NULL.\n * \\param[in] DestKey Optional pointer to a destination file key. May be NULL.\n * \\param[in] Flags Additional flags controlling copy semantics.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The exact meaning and required privileges for `Flags` and keys may\n *          depend on the Windows version and file system. Consumers should\n *          verify handle access rights and the platform's support for this call.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCopyFileChunk(\n    _In_ HANDLE SourceHandle,\n    _In_ HANDLE DestinationHandle,\n    _In_opt_ HANDLE EventHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG Length,\n    _In_ PLARGE_INTEGER SourceOffset,\n    _In_ PLARGE_INTEGER DestOffset,\n    _In_opt_ PULONG SourceKey,\n    _In_opt_ PULONG DestKey,\n    _In_ ULONG Flags\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_11)\n\n//\n// I/O Ring\n//\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateIoRing(\n    _Out_ PHANDLE IoRingHandle,\n    _In_ ULONG CreateParametersLength,\n    _In_ PVOID CreateParameters,\n    _In_ ULONG OutputParametersLength,\n    _Out_ PVOID OutputParameters\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSubmitIoRing(\n    _In_ HANDLE IoRingHandle,\n    _In_ ULONG Flags,\n    _In_opt_ ULONG WaitOperations,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryIoRingCapabilities(\n    _In_ SIZE_T IoRingCapabilitiesLength,\n    _Out_ PVOID IoRingCapabilities\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationIoRing(\n    _In_ HANDLE IoRingHandle,\n    _In_ ULONG IoRingInformationClass,\n    _In_ ULONG IoRingInformationLength,\n    _In_ PVOID IoRingInformation\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_11)\n\n//\n// Other types\n//\n\ntypedef enum _INTERFACE_TYPE\n{\n    InterfaceTypeUndefined = -1,\n    Internal = 0,\n    Isa = 1,\n    Eisa = 2,\n    MicroChannel = 3,\n    TurboChannel = 4,\n    PCIBus = 5,\n    VMEBus = 6,\n    NuBus = 7,\n    PCMCIABus = 8,\n    CBus = 9,\n    MPIBus = 10,\n    MPSABus = 11,\n    ProcessorInternal = 12,\n    InternalPowerBus = 13,\n    PNPISABus = 14,\n    PNPBus = 15,\n    Vmcs = 16,\n    ACPIBus = 17,\n    MaximumInterfaceType\n} INTERFACE_TYPE, *PINTERFACE_TYPE;\n\ntypedef enum _DMA_WIDTH\n{\n    Width8Bits,\n    Width16Bits,\n    Width32Bits,\n    Width64Bits,\n    WidthNoWrap,\n    MaximumDmaWidth\n} DMA_WIDTH, *PDMA_WIDTH;\n\ntypedef enum _DMA_SPEED\n{\n    Compatible,\n    TypeA,\n    TypeB,\n    TypeC,\n    TypeF,\n    MaximumDmaSpeed\n} DMA_SPEED, *PDMA_SPEED;\n\ntypedef enum _BUS_DATA_TYPE\n{\n    ConfigurationSpaceUndefined = -1,\n    Cmos,\n    EisaConfiguration,\n    Pos,\n    CbusConfiguration,\n    PCIConfiguration,\n    VMEConfiguration,\n    NuBusConfiguration,\n    PCMCIAConfiguration,\n    MPIConfiguration,\n    MPSAConfiguration,\n    PNPISAConfiguration,\n    SgiInternalConfiguration,\n    MaximumBusDataType\n} BUS_DATA_TYPE, *PBUS_DATA_TYPE;\n\n// Control structures\n\n// Reparse structure for FSCTL_SET_REPARSE_POINT, FSCTL_GET_REPARSE_POINT, FSCTL_DELETE_REPARSE_POINT\n\n#define SYMLINK_FLAG_RELATIVE 0x00000001\n#define SYMLINK_DIRECTORY 0x80000000 // If set then this is a directory symlink\n#define SYMLINK_FILE 0x40000000 // If set then this is a file symlink\n\ntypedef struct _REPARSE_DATA_BUFFER\n{\n    ULONG ReparseTag;\n    USHORT ReparseDataLength;\n    USHORT Reserved;\n\n    _Field_size_bytes_(ReparseDataLength)\n    union\n    {\n        struct\n        {\n            USHORT SubstituteNameOffset;\n            USHORT SubstituteNameLength;\n            USHORT PrintNameOffset;\n            USHORT PrintNameLength;\n            ULONG Flags;\n            WCHAR PathBuffer[1];\n        } SymbolicLinkReparseBuffer;\n        struct\n        {\n            USHORT SubstituteNameOffset;\n            USHORT SubstituteNameLength;\n            USHORT PrintNameOffset;\n            USHORT PrintNameLength;\n            WCHAR PathBuffer[1];\n        } MountPointReparseBuffer;\n        struct\n        {\n            ULONG StringCount;\n            WCHAR StringList[1];\n        } AppExecLinkReparseBuffer;\n        struct\n        {\n            UCHAR DataBuffer[1];\n        } GenericReparseBuffer;\n    };\n} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;\n\n#define REPARSE_DATA_BUFFER_HEADER_SIZE UFIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)\n\n// Reparse structure for FSCTL_SET_REPARSE_POINT_EX\n\ntypedef struct _REPARSE_DATA_BUFFER_EX\n{\n    ULONG Flags;\n\n    //\n    //  This is the existing reparse tag on the file if any,  if the\n    //  caller wants to replace the reparse tag too.\n    //\n    //    - To set the reparse data  along with the reparse tag that\n    //      could be different,  pass the current reparse tag of the\n    //      file.\n    //\n    //    - To update the reparse data while having the same reparse\n    //      tag,  the caller should give the existing reparse tag in\n    //      this ExistingReparseTag field.\n    //\n    //    - To set the reparse tag along with reparse data on a file\n    //      that doesn't have a reparse tag yet, set this to zero.\n    //\n    //  If the ExistingReparseTag  does not match the reparse tag on\n    //  the file,  the FSCTL_SET_REPARSE_POINT_EX  would  fail  with\n    //  STATUS_IO_REPARSE_TAG_MISMATCH. NOTE: If a file doesn't have\n    //  a reparse tag, ExistingReparseTag should be 0.\n    //\n\n    ULONG ExistingReparseTag;\n\n    //  For non-Microsoft reparse tags, this is the existing reparse\n    //  guid on the file if any,  if the caller wants to replace the\n    //  reparse tag and / or guid along with the data.\n    //\n    //  If ExistingReparseTag is 0, the file is not expected to have\n    //  any reparse tags, so ExistingReparseGuid is ignored. And for\n    //  non-Microsoft tags ExistingReparseGuid should match the guid\n    //  in the file if ExistingReparseTag is non zero.\n\n    GUID ExistingReparseGuid;\n\n    //\n    //  Reserved\n    //\n    ULONGLONG Reserved;\n\n    //\n    //  Reparse data to set\n    //\n    union\n    {\n        REPARSE_DATA_BUFFER ReparseDataBuffer;\n        REPARSE_GUID_DATA_BUFFER ReparseGuidDataBuffer;\n    };\n} REPARSE_DATA_BUFFER_EX, *PREPARSE_DATA_BUFFER_EX;\n\n//  REPARSE_DATA_BUFFER_EX Flags\n//\n//  REPARSE_DATA_EX_FLAG_GIVEN_TAG_OR_NONE - Forces the FSCTL to set the\n//  reparse tag if the file has no tag or the tag on the file is same as\n//  the one in  ExistingReparseTag.   NOTE: If the ExistingReparseTag is\n//  not a Microsoft tag then the ExistingReparseGuid should match if the\n//  file has the ExistingReparseTag.\n//\n#define REPARSE_DATA_EX_FLAG_GIVEN_TAG_OR_NONE              (0x00000001)\n\n#define REPARSE_GUID_DATA_BUFFER_EX_HEADER_SIZE \\\n    UFIELD_OFFSET(REPARSE_DATA_BUFFER_EX, ReparseGuidDataBuffer.GenericReparseBuffer)\n\n#define REPARSE_DATA_BUFFER_EX_HEADER_SIZE \\\n    UFIELD_OFFSET(REPARSE_DATA_BUFFER_EX, ReparseDataBuffer.GenericReparseBuffer)\n//\n// Named pipe FS control definitions\n//\n\n#define DEVICE_NAMED_PIPE L\"\\\\Device\\\\NamedPipe\\\\\"\n\n#define FSCTL_PIPE_ASSIGN_EVENT             CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_DISCONNECT               CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_LISTEN                   CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_PEEK                     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 3, METHOD_BUFFERED, FILE_READ_DATA)\n#define FSCTL_PIPE_QUERY_EVENT              CTL_CODE(FILE_DEVICE_NAMED_PIPE, 4, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_TRANSCEIVE               CTL_CODE(FILE_DEVICE_NAMED_PIPE, 5, METHOD_NEITHER,  FILE_READ_DATA | FILE_WRITE_DATA)\n#define FSCTL_PIPE_WAIT                     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_IMPERSONATE              CTL_CODE(FILE_DEVICE_NAMED_PIPE, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_SET_CLIENT_PROCESS       CTL_CODE(FILE_DEVICE_NAMED_PIPE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_QUERY_CLIENT_PROCESS     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_GET_PIPE_ATTRIBUTE       CTL_CODE(FILE_DEVICE_NAMED_PIPE, 10, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_SET_PIPE_ATTRIBUTE       CTL_CODE(FILE_DEVICE_NAMED_PIPE, 11, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_SET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_GET_HANDLE_ATTRIBUTE     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 14, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_SET_HANDLE_ATTRIBUTE     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_FLUSH                    CTL_CODE(FILE_DEVICE_NAMED_PIPE, 16, METHOD_BUFFERED, FILE_WRITE_DATA)\n#define FSCTL_PIPE_DISABLE_IMPERSONATE      CTL_CODE(FILE_DEVICE_NAMED_PIPE, 17, METHOD_BUFFERED, FILE_ANY_ACCESS) // since REDSTONE\n#define FSCTL_PIPE_SILO_ARRIVAL             CTL_CODE(FILE_DEVICE_NAMED_PIPE, 18, METHOD_BUFFERED, FILE_WRITE_DATA) // since REDSTONE3\n#define FSCTL_PIPE_CREATE_SYMLINK           CTL_CODE(FILE_DEVICE_NAMED_PIPE, 19, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // requires SeTcbPrivilege\n#define FSCTL_PIPE_DELETE_SYMLINK           CTL_CODE(FILE_DEVICE_NAMED_PIPE, 20, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)\n#define FSCTL_PIPE_QUERY_CLIENT_PROCESS_V2  CTL_CODE(FILE_DEVICE_NAMED_PIPE, 21, METHOD_BUFFERED, FILE_ANY_ACCESS) // since 19H1\n\n#define FSCTL_PIPE_INTERNAL_READ            CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2045, METHOD_BUFFERED, FILE_READ_DATA)\n#define FSCTL_PIPE_INTERNAL_WRITE           CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2046, METHOD_BUFFERED, FILE_WRITE_DATA)\n#define FSCTL_PIPE_INTERNAL_TRANSCEIVE      CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2047, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)\n#define FSCTL_PIPE_INTERNAL_READ_OVFLOW     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2048, METHOD_BUFFERED, FILE_READ_DATA)\n\n// Flags for query event\n\n#define FILE_PIPE_READ_DATA 0x00000000\n#define FILE_PIPE_WRITE_SPACE 0x00000001\n\n// Input for FSCTL_PIPE_ASSIGN_EVENT\ntypedef struct _FILE_PIPE_ASSIGN_EVENT_BUFFER\n{\n    HANDLE EventHandle;\n    ULONG KeyValue;\n} FILE_PIPE_ASSIGN_EVENT_BUFFER, *PFILE_PIPE_ASSIGN_EVENT_BUFFER;\n\n// Output for FILE_PIPE_PEEK_BUFFER\ntypedef struct _FILE_PIPE_PEEK_BUFFER\n{\n    ULONG NamedPipeState;\n    ULONG ReadDataAvailable;\n    ULONG NumberOfMessages;\n    ULONG MessageLength;\n    _Field_size_bytes_(MessageLength) CHAR Data[1];\n} FILE_PIPE_PEEK_BUFFER, *PFILE_PIPE_PEEK_BUFFER;\n\n// Output for FSCTL_PIPE_QUERY_EVENT\ntypedef struct _FILE_PIPE_EVENT_BUFFER\n{\n    ULONG NamedPipeState;\n    ULONG EntryType;\n    ULONG ByteCount;\n    ULONG KeyValue;\n    ULONG NumberRequests;\n} FILE_PIPE_EVENT_BUFFER, *PFILE_PIPE_EVENT_BUFFER;\n\n// Input for FSCTL_PIPE_WAIT\ntypedef struct _FILE_PIPE_WAIT_FOR_BUFFER\n{\n    LARGE_INTEGER Timeout;\n    ULONG NameLength;\n    BOOLEAN TimeoutSpecified;\n    _Field_size_bytes_(NameLength) WCHAR Name[1];\n} FILE_PIPE_WAIT_FOR_BUFFER, *PFILE_PIPE_WAIT_FOR_BUFFER;\n\n// Input for FSCTL_PIPE_SET_CLIENT_PROCESS, Output for FSCTL_PIPE_QUERY_CLIENT_PROCESS\ntypedef struct _FILE_PIPE_CLIENT_PROCESS_BUFFER\n{\n#if !defined(BUILD_WOW6432)\n    PVOID ClientSession;\n    PVOID ClientProcess;\n#else\n    ULONGLONG ClientSession;\n    ULONGLONG ClientProcess;\n#endif\n} FILE_PIPE_CLIENT_PROCESS_BUFFER, *PFILE_PIPE_CLIENT_PROCESS_BUFFER;\n\n// Control structure for FSCTL_PIPE_QUERY_CLIENT_PROCESS_V2\n\ntypedef struct _FILE_PIPE_CLIENT_PROCESS_BUFFER_V2\n{\n     ULONGLONG ClientSession;\n#if !defined(BUILD_WOW6432)\n     PVOID ClientProcess;\n#else\n     ULONGLONG ClientProcess;\n#endif\n} FILE_PIPE_CLIENT_PROCESS_BUFFER_V2, *PFILE_PIPE_CLIENT_PROCESS_BUFFER_V2;\n\n#define FILE_PIPE_COMPUTER_NAME_LENGTH 15\n\n// Input for FSCTL_PIPE_SET_CLIENT_PROCESS, Output for FSCTL_PIPE_QUERY_CLIENT_PROCESS\ntypedef struct _FILE_PIPE_CLIENT_PROCESS_BUFFER_EX\n{\n#if !defined(BUILD_WOW6432)\n    PVOID ClientSession;\n    PVOID ClientProcess;\n#else\n    ULONGLONG ClientSession;\n    ULONGLONG ClientProcess;\n#endif\n    USHORT ClientComputerNameLength; // in bytes\n    WCHAR ClientComputerBuffer[FILE_PIPE_COMPUTER_NAME_LENGTH + 1]; // null-terminated\n} FILE_PIPE_CLIENT_PROCESS_BUFFER_EX, *PFILE_PIPE_CLIENT_PROCESS_BUFFER_EX;\n\n// Control structure for FSCTL_PIPE_SILO_ARRIVAL\n\ntypedef struct _FILE_PIPE_SILO_ARRIVAL_INPUT\n{\n    HANDLE JobHandle;\n} FILE_PIPE_SILO_ARRIVAL_INPUT, *PFILE_PIPE_SILO_ARRIVAL_INPUT;\n\n//\n// Flags for create symlink\n//\n\n//\n// A global symlink will cause resolution of the symlink's target to occur in\n// the host silo (i.e. not in any current silo).  For example, if there is a\n// symlink at \\Device\\Silos\\37\\Device\\NamedPipe\\symlink then the target will be\n// resolved as \\Device\\NamedPipe\\target instead of \\Device\\Silos\\37\\Device\\NamedPipe\\target\n//\n#define FILE_PIPE_SYMLINK_FLAG_GLOBAL   0x1\n\n//\n// A relative symlink will cause resolution of the symlink's target to occur relative\n// to the root of the named pipe file system.  For example, if there is a symlink at\n// \\Device\\NamedPipe\\symlink that has a target called \"target\", then the target will\n// be resolved as \\Device\\NamedPipe\\target\n//\n#define FILE_PIPE_SYMLINK_FLAG_RELATIVE 0x2\n\n#define FILE_PIPE_SYMLINK_VALID_FLAGS \\\n    (FILE_PIPE_SYMLINK_FLAG_GLOBAL | FILE_PIPE_SYMLINK_FLAG_RELATIVE)\n\n// Control structure for FSCTL_PIPE_CREATE_SYMLINK\n\ntypedef struct _FILE_PIPE_CREATE_SYMLINK_INPUT\n{\n    USHORT NameOffset;\n    USHORT NameLength;\n    USHORT SubstituteNameOffset;\n    USHORT SubstituteNameLength;\n    ULONG Flags;\n} FILE_PIPE_CREATE_SYMLINK_INPUT, *PFILE_PIPE_CREATE_SYMLINK_INPUT;\n\n// Control structure for FSCTL_PIPE_DELETE_SYMLINK\n\ntypedef struct _FILE_PIPE_DELETE_SYMLINK_INPUT\n{\n    USHORT NameOffset;\n    USHORT NameLength;\n} FILE_PIPE_DELETE_SYMLINK_INPUT, *PFILE_PIPE_DELETE_SYMLINK_INPUT;\n\n// Mailslot FS control definitions\n\n#define MAILSLOT_CLASS_FIRSTCLASS 1\n#define MAILSLOT_CLASS_SECONDCLASS 2\n\n#define FSCTL_MAILSLOT_PEEK             CTL_CODE(FILE_DEVICE_MAILSLOT, 0, METHOD_NEITHER, FILE_READ_DATA)\n\n// Output for FSCTL_MAILSLOT_PEEK\ntypedef struct _FILE_MAILSLOT_PEEK_BUFFER\n{\n    ULONG ReadDataAvailable;\n    ULONG NumberOfMessages;\n    ULONG MessageLength;\n} FILE_MAILSLOT_PEEK_BUFFER, *PFILE_MAILSLOT_PEEK_BUFFER;\n\n//\n// Mount manager FS control definitions\n//\n\n#define MOUNTMGR_DEVICE_NAME L\"\\\\Device\\\\MountPointManager\"\n#define MOUNTMGRCONTROLTYPE 0x0000006D // 'm'\n#define MOUNTDEVCONTROLTYPE 0x0000004D // 'M'\n\n#define IOCTL_MOUNTMGR_CREATE_POINT                 CTL_CODE(MOUNTMGRCONTROLTYPE, 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_DELETE_POINTS                CTL_CODE(MOUNTMGRCONTROLTYPE, 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_QUERY_POINTS                 CTL_CODE(MOUNTMGRCONTROLTYPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY         CTL_CODE(MOUNTMGRCONTROLTYPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER            CTL_CODE(MOUNTMGRCONTROLTYPE, 4, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS          CTL_CODE(MOUNTMGRCONTROLTYPE, 5, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED   CTL_CODE(MOUNTMGRCONTROLTYPE, 6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED   CTL_CODE(MOUNTMGRCONTROLTYPE, 7, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_CHANGE_NOTIFY                CTL_CODE(MOUNTMGRCONTROLTYPE, 8, METHOD_BUFFERED, FILE_READ_ACCESS)\n#define IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE      CTL_CODE(MOUNTMGRCONTROLTYPE, 9, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES    CTL_CODE(MOUNTMGRCONTROLTYPE, 10, METHOD_BUFFERED, FILE_READ_ACCESS)\n#define IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION  CTL_CODE(MOUNTMGRCONTROLTYPE, 11, METHOD_BUFFERED, FILE_READ_ACCESS)\n#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH        CTL_CODE(MOUNTMGRCONTROLTYPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS       CTL_CODE(MOUNTMGRCONTROLTYPE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define IOCTL_MOUNTMGR_SCRUB_REGISTRY               CTL_CODE(MOUNTMGRCONTROLTYPE, 14, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT             CTL_CODE(MOUNTMGRCONTROLTYPE, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define IOCTL_MOUNTMGR_SET_AUTO_MOUNT               CTL_CODE(MOUNTMGRCONTROLTYPE, 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_BOOT_DL_ASSIGNMENT           CTL_CODE(MOUNTMGRCONTROLTYPE, 17, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) // since WIN7\n#define IOCTL_MOUNTMGR_TRACELOG_CACHE               CTL_CODE(MOUNTMGRCONTROLTYPE, 18, METHOD_BUFFERED, FILE_READ_ACCESS)\n#define IOCTL_MOUNTMGR_PREPARE_VOLUME_DELETE        CTL_CODE(MOUNTMGRCONTROLTYPE, 19, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\n#define IOCTL_MOUNTMGR_CANCEL_VOLUME_DELETE         CTL_CODE(MOUNTMGRCONTROLTYPE, 20, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) // since WIN8\n#define IOCTL_MOUNTMGR_SILO_ARRIVAL                 CTL_CODE(MOUNTMGRCONTROLTYPE, 21, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) // since RS1\n\n#define IOCTL_MOUNTDEV_QUERY_DEVICE_NAME            CTL_CODE(MOUNTDEVCONTROLTYPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n// Input structure for IOCTL_MOUNTMGR_CREATE_POINT.\ntypedef struct _MOUNTMGR_CREATE_POINT_INPUT\n{\n    USHORT SymbolicLinkNameOffset;\n    USHORT SymbolicLinkNameLength;\n    USHORT DeviceNameOffset;\n    USHORT DeviceNameLength;\n} MOUNTMGR_CREATE_POINT_INPUT, *PMOUNTMGR_CREATE_POINT_INPUT;\n\n// Input structure for IOCTL_MOUNTMGR_DELETE_POINTS, IOCTL_MOUNTMGR_QUERY_POINTS, and IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY.\ntypedef struct _MOUNTMGR_MOUNT_POINT\n{\n    ULONG SymbolicLinkNameOffset;\n    USHORT SymbolicLinkNameLength;\n    USHORT Reserved1;\n    ULONG UniqueIdOffset;\n    USHORT UniqueIdLength;\n    USHORT Reserved2;\n    ULONG DeviceNameOffset;\n    USHORT DeviceNameLength;\n    USHORT Reserved3;\n} MOUNTMGR_MOUNT_POINT, *PMOUNTMGR_MOUNT_POINT;\n\n// Output structure for IOCTL_MOUNTMGR_DELETE_POINTS, IOCTL_MOUNTMGR_QUERY_POINTS, and IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY.\n_Struct_size_bytes_(Size)\ntypedef struct _MOUNTMGR_MOUNT_POINTS\n{\n    ULONG Size;\n    ULONG NumberOfMountPoints;\n    _Field_size_(NumberOfMountPoints) MOUNTMGR_MOUNT_POINT MountPoints[1];\n} MOUNTMGR_MOUNT_POINTS, *PMOUNTMGR_MOUNT_POINTS;\n\n// Input structure for IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER.\ntypedef struct _MOUNTMGR_DRIVE_LETTER_TARGET\n{\n    USHORT DeviceNameLength;\n    _Field_size_bytes_(DeviceNameLength) WCHAR DeviceName[1];\n} MOUNTMGR_DRIVE_LETTER_TARGET, *PMOUNTMGR_DRIVE_LETTER_TARGET;\n\n// Output structure for IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER.\ntypedef struct _MOUNTMGR_DRIVE_LETTER_INFORMATION\n{\n    BOOLEAN DriveLetterWasAssigned;\n    UCHAR CurrentDriveLetter;\n} MOUNTMGR_DRIVE_LETTER_INFORMATION, *PMOUNTMGR_DRIVE_LETTER_INFORMATION;\n\n// Input structure for IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED and\n// IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED.\ntypedef struct _MOUNTMGR_VOLUME_MOUNT_POINT\n{\n    USHORT SourceVolumeNameOffset;\n    USHORT SourceVolumeNameLength;\n    USHORT TargetVolumeNameOffset;\n    USHORT TargetVolumeNameLength;\n} MOUNTMGR_VOLUME_MOUNT_POINT, *PMOUNTMGR_VOLUME_MOUNT_POINT;\n\n// Input structure for IOCTL_MOUNTMGR_CHANGE_NOTIFY.\n// Output structure for IOCTL_MOUNTMGR_CHANGE_NOTIFY.\ntypedef struct _MOUNTMGR_CHANGE_NOTIFY_INFO\n{\n    ULONG EpicNumber;\n} MOUNTMGR_CHANGE_NOTIFY_INFO, *PMOUNTMGR_CHANGE_NOTIFY_INFO;\n\n// Input structure for IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE,\n// IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,\n// IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, and\n// IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS.\n// IOCTL_MOUNTMGR_PREPARE_VOLUME_DELETE\n// IOCTL_MOUNTMGR_CANCEL_VOLUME_DELETE\ntypedef struct _MOUNTMGR_TARGET_NAME\n{\n    USHORT DeviceNameLength;\n    _Field_size_bytes_(DeviceNameLength) WCHAR DeviceName[1];\n} MOUNTMGR_TARGET_NAME, *PMOUNTMGR_TARGET_NAME;\n\n// Input / Output structure for querying / setting the auto-mount setting\ntypedef enum _MOUNTMGR_AUTO_MOUNT_STATE\n{\n    Disabled = 0,\n    Enabled\n} MOUNTMGR_AUTO_MOUNT_STATE;\n\n// IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT\ntypedef struct _MOUNTMGR_QUERY_AUTO_MOUNT\n{\n    MOUNTMGR_AUTO_MOUNT_STATE CurrentState;\n} MOUNTMGR_QUERY_AUTO_MOUNT, *PMOUNTMGR_QUERY_AUTO_MOUNT;\n\n// IOCTL_MOUNTMGR_SET_AUTO_MOUNT\ntypedef struct _MOUNTMGR_SET_AUTO_MOUNT\n{\n    MOUNTMGR_AUTO_MOUNT_STATE NewState;\n} MOUNTMGR_SET_AUTO_MOUNT, *PMOUNTMGR_SET_AUTO_MOUNT;\n\n// Input structure for IOCTL_MOUNTMGR_SILO_ARRIVAL.\ntypedef struct _MOUNTMGR_SILO_ARRIVAL_INPUT\n{\n    HANDLE JobHandle;\n} MOUNTMGR_SILO_ARRIVAL_INPUT, *PMOUNTMGR_SILO_ARRIVAL_INPUT;\n\n// Macro that defines what a \"drive letter\" mount point is.  This macro can\n// be used to scan the result from QUERY_POINTS to discover which mount points\n// are find \"drive letter\" mount points.\n#define MOUNTMGR_IS_DRIVE_LETTER(s) ( \\\n    (s)->Length == 28 && \\\n    (s)->Buffer[0] == '\\\\' && \\\n    (s)->Buffer[1] == 'D' && \\\n    (s)->Buffer[2] == 'o' && \\\n    (s)->Buffer[3] == 's' && \\\n    (s)->Buffer[4] == 'D' && \\\n    (s)->Buffer[5] == 'e' && \\\n    (s)->Buffer[6] == 'v' && \\\n    (s)->Buffer[7] == 'i' && \\\n    (s)->Buffer[8] == 'c' && \\\n    (s)->Buffer[9] == 'e' && \\\n    (s)->Buffer[10] == 's' && \\\n    (s)->Buffer[11] == '\\\\' && \\\n    (s)->Buffer[12] >= 'A' && \\\n    (s)->Buffer[12] <= 'Z' && \\\n    (s)->Buffer[13] == ':')\n\n// Macro that defines what a \"volume name\" mount point is.  This macro can\n// be used to scan the result from QUERY_POINTS to discover which mount points\n// are \"volume name\" mount points.\n#define MOUNTMGR_IS_VOLUME_NAME(s) ( \\\n     ((s)->Length == 96 || ((s)->Length == 98 && (s)->Buffer[48] == '\\\\')) && \\\n     (s)->Buffer[0] == '\\\\' && \\\n     ((s)->Buffer[1] == '?' || (s)->Buffer[1] == '\\\\') && \\\n     (s)->Buffer[2] == '?' && \\\n     (s)->Buffer[3] == '\\\\' && \\\n     (s)->Buffer[4] == 'V' && \\\n     (s)->Buffer[5] == 'o' && \\\n     (s)->Buffer[6] == 'l' && \\\n     (s)->Buffer[7] == 'u' && \\\n     (s)->Buffer[8] == 'm' && \\\n     (s)->Buffer[9] == 'e' && \\\n     (s)->Buffer[10] == '{' && \\\n     (s)->Buffer[19] == '-' && \\\n     (s)->Buffer[24] == '-' && \\\n     (s)->Buffer[29] == '-' && \\\n     (s)->Buffer[34] == '-' && \\\n     (s)->Buffer[47] == '}')\n\n// Output structure for IOCTL_MOUNTDEV_QUERY_DEVICE_NAME.\ntypedef struct _MOUNTDEV_NAME\n{\n    USHORT NameLength;\n    _Field_size_bytes_(NameLength) WCHAR Name[1];\n} MOUNTDEV_NAME, *PMOUNTDEV_NAME;\n\n// Output structure for IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH and IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS.\ntypedef struct _MOUNTMGR_VOLUME_PATHS\n{\n    ULONG MultiSzLength;\n    _Field_size_bytes_(MultiSzLength) WCHAR MultiSz[1];\n} MOUNTMGR_VOLUME_PATHS, *PMOUNTMGR_VOLUME_PATHS;\n\n#define MOUNTMGR_IS_DOS_VOLUME_NAME(s) ( \\\n     MOUNTMGR_IS_VOLUME_NAME(s) && \\\n     (s)->Length == 96 && \\\n     (s)->Buffer[1] == '\\\\')\n\n#define MOUNTMGR_IS_DOS_VOLUME_NAME_WB(s) ( \\\n     MOUNTMGR_IS_VOLUME_NAME(s) && \\\n     (s)->Length == 98 && \\\n     (s)->Buffer[1] == '\\\\')\n\n#define MOUNTMGR_IS_NT_VOLUME_NAME(s) ( \\\n     MOUNTMGR_IS_VOLUME_NAME(s) && \\\n     (s)->Length == 96 && \\\n     (s)->Buffer[1] == '?')\n\n#define MOUNTMGR_IS_NT_VOLUME_NAME_WB(s) ( \\\n     MOUNTMGR_IS_VOLUME_NAME(s) && \\\n     (s)->Length == 98 && \\\n     (s)->Buffer[1] == '?')\n\n//\n// Filter manager\n//\n\n#define FLT_PORT_CONNECT 0x0001\n#define FLT_PORT_ALL_ACCESS (FLT_PORT_CONNECT | STANDARD_RIGHTS_ALL)\n\n// rev\n#define FLT_SYMLINK_NAME     L\"\\\\Global??\\\\FltMgr\"\n#define FLT_MSG_SYMLINK_NAME L\"\\\\Global??\\\\FltMgrMsg\"\n#define FLT_DEVICE_NAME      L\"\\\\FileSystem\\\\Filters\\\\FltMgr\"\n#define FLT_MSG_DEVICE_NAME  L\"\\\\FileSystem\\\\Filters\\\\FltMgrMsg\"\n\n// private\ntypedef struct _FLT_CONNECT_CONTEXT\n{\n    PUNICODE_STRING PortName;\n    PUNICODE_STRING64 PortName64;\n    USHORT SizeOfContext;\n    UCHAR Padding[6]; // unused\n    _Field_size_bytes_(SizeOfContext) UCHAR Context[ANYSIZE_ARRAY];\n} FLT_CONNECT_CONTEXT, *PFLT_CONNECT_CONTEXT;\n\n// rev\n#define FLT_PORT_EA_NAME \"FLTPORT\"\n#define FLT_PORT_CONTEXT_MAX 0xFFE8\n\n// combined FILE_FULL_EA_INFORMATION and FLT_CONNECT_CONTEXT\ntypedef struct _FLT_PORT_FULL_EA\n{\n    ULONG NextEntryOffset; // 0\n    UCHAR Flags;           // 0\n    UCHAR EaNameLength;    // sizeof(FLT_PORT_EA_NAME) - sizeof(ANSI_NULL)\n    USHORT EaValueLength;  // RTL_SIZEOF_THROUGH_FIELD(FLT_CONNECT_CONTEXT, Padding) + SizeOfContext\n    CHAR EaName[8];        // FLTPORT\\0\n    FLT_CONNECT_CONTEXT EaValue;\n} FLT_PORT_FULL_EA, *PFLT_PORT_FULL_EA;\n\n#define FLT_PORT_FULL_EA_SIZE \\\n    (sizeof(FILE_FULL_EA_INFORMATION) + (sizeof(FLT_PORT_EA_NAME) - sizeof(ANSI_NULL)))\n#define FLT_PORT_FULL_EA_VALUE_SIZE \\\n    RTL_SIZEOF_THROUGH_FIELD(FLT_CONNECT_CONTEXT, Padding)\n\n// begin_rev\n\n// IOCTLs for unlinked FltMgr handles\n#define FLT_CTL_LOAD                CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 1, METHOD_BUFFERED, FILE_WRITE_ACCESS) // in: FLT_LOAD_PARAMETERS // requires SeLoadDriverPrivilege\n#define FLT_CTL_UNLOAD              CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 2, METHOD_BUFFERED, FILE_WRITE_ACCESS) // in: FLT_LOAD_PARAMETERS // requires SeLoadDriverPrivilege\n#define FLT_CTL_LINK_HANDLE         CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 3, METHOD_BUFFERED, FILE_READ_ACCESS)  // in: FLT_LINK // specializes the handle\n#define FLT_CTL_ATTACH              CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 4, METHOD_BUFFERED, FILE_WRITE_ACCESS) // in: FLT_ATTACH\n#define FLT_CTL_DETACH              CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 5, METHOD_BUFFERED, FILE_WRITE_ACCESS) // in: FLT_INSTANCE_PARAMETERS\n\n// IOCTLs for port-specific FltMgrMsg handles (opened using the extended attribute)\n#define FLT_CTL_SEND_MESSAGE        CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 6, METHOD_NEITHER, FILE_WRITE_ACCESS)  // in, out: filter-specific\n#define FLT_CTL_GET_MESSAGE         CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 7, METHOD_NEITHER, FILE_READ_ACCESS)   // out: filter-specific\n#define FLT_CTL_REPLY_MESSAGE       CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 8, METHOD_NEITHER, FILE_WRITE_ACCESS)  // in: filter-specific\n\n// IOCTLs for linked FltMgr handles; depend on previously used FLT_LINK_TYPE\n//\n// Find first/next:\n//   FILTER                - enumerates nested instances; in: INSTANCE_INFORMATION_CLASS\n//   FILTER_VOLUME         - enumerates nested instances; in: INSTANCE_INFORMATION_CLASS\n//   FILTER_MANAGER        - enumerates all filters;      in: FILTER_INFORMATION_CLASS\n//   FILTER_MANAGER_VOLUME - enumerates all volumes;      in: FILTER_VOLUME_INFORMATION_CLASS\n//\n// Get information:\n//   FILTER                - queries filter;              in: FILTER_INFORMATION_CLASS\n//   FILTER_INSTANCE       - queries instance;            in: INSTANCE_INFORMATION_CLASS\n//\n#define FLT_CTL_FIND_FIRST          CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 9, METHOD_BUFFERED, FILE_READ_ACCESS)  // in: *_INFORMATION_CLASS, out: *_INFORMATION (from fltUserStructures.h)\n#define FLT_CTL_FIND_NEXT           CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_READ_ACCESS) // in: *_INFORMATION_CLASS, out: *_INFORMATION (from fltUserStructures.h)\n#define FLT_CTL_GET_INFORMATION     CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_READ_ACCESS) // in: *_INFORMATION_CLASS, out: *_INFORMATION (from fltUserStructures.h)\n\n// end_rev\n\n// private\ntypedef struct _FLT_LOAD_PARAMETERS\n{\n    USHORT FilterNameSize;\n    _Field_size_bytes_(FilterNameSize) WCHAR FilterName[ANYSIZE_ARRAY];\n} FLT_LOAD_PARAMETERS, *PFLT_LOAD_PARAMETERS;\n\n// private\ntypedef enum _FLT_LINK_TYPE\n{\n    FILTER = 0,                // FLT_FILTER_PARAMETERS\n    FILTER_INSTANCE = 1,       // FLT_INSTANCE_PARAMETERS\n    FILTER_VOLUME = 2,         // FLT_VOLUME_PARAMETERS\n    FILTER_MANAGER = 3,        // nothing\n    FILTER_MANAGER_VOLUME = 4, // nothing\n} FLT_LINK_TYPE, *PFLT_LINK_TYPE;\n\n// private\ntypedef struct _FLT_LINK\n{\n    FLT_LINK_TYPE Type;\n    ULONG ParametersOffset; // from this struct\n} FLT_LINK, *PFLT_LINK;\n\n// rev\ntypedef struct _FLT_FILTER_PARAMETERS\n{\n    USHORT FilterNameSize;\n    USHORT FilterNameOffset; // to WCHAR[] from this struct\n} FLT_FILTER_PARAMETERS, *PFLT_FILTER_PARAMETERS;\n\n// private\ntypedef struct _FLT_INSTANCE_PARAMETERS\n{\n    USHORT FilterNameSize;\n    USHORT FilterNameOffset; // to WCHAR[] from this struct\n    USHORT VolumeNameSize;\n    USHORT VolumeNameOffset; // to WCHAR[] from this struct\n    USHORT InstanceNameSize;\n    USHORT InstanceNameOffset; // to WCHAR[] from this struct\n} FLT_INSTANCE_PARAMETERS, *PFLT_INSTANCE_PARAMETERS;\n\n// rev\ntypedef struct _FLT_VOLUME_PARAMETERS\n{\n    USHORT VolumeNameSize;\n    USHORT VolumeNameOffset; // to WCHAR[] from this struct\n} FLT_VOLUME_PARAMETERS, *PFLT_VOLUME_PARAMETERS;\n\n// private\ntypedef enum _ATTACH_TYPE\n{\n    AltitudeBased = 0,\n    InstanceNameBased = 1,\n} ATTACH_TYPE, *PATTACH_TYPE;\n\n// private\ntypedef struct _FLT_ATTACH\n{\n    USHORT FilterNameSize;\n    USHORT FilterNameOffset; // to WCHAR[] from this struct\n    USHORT VolumeNameSize;\n    USHORT VolumeNameOffset; // to WCHAR[] from this struct\n    ATTACH_TYPE Type;\n    USHORT InstanceNameSize;\n    USHORT InstanceNameOffset; // to WCHAR[] from this struct\n    USHORT AltitudeSize;\n    USHORT AltitudeOffset; // to WCHAR[] from this struct\n} FLT_ATTACH, *PFLT_ATTACH;\n\n//\n// Multiple UNC Provider\n//\n\n// rev // FSCTLs for \\Device\\Mup\n#define FSCTL_MUP_GET_UNC_CACHE_INFO                CTL_CODE(FILE_DEVICE_MULTI_UNC_PROVIDER, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) // out: MUP_FSCTL_UNC_CACHE_INFORMATION\n#define FSCTL_MUP_GET_UNC_PROVIDER_LIST             CTL_CODE(FILE_DEVICE_MULTI_UNC_PROVIDER, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) // out: MUP_FSCTL_UNC_PROVIDER_INFORMATION\n#define FSCTL_MUP_GET_SURROGATE_PROVIDER_LIST       CTL_CODE(FILE_DEVICE_MULTI_UNC_PROVIDER, 13, METHOD_BUFFERED, FILE_ANY_ACCESS) // out: MUP_FSCTL_SURROGATE_PROVIDER_INFORMATION\n#define FSCTL_MUP_GET_UNC_HARDENING_CONFIGURATION   CTL_CODE(FILE_DEVICE_MULTI_UNC_PROVIDER, 14, METHOD_BUFFERED, FILE_ANY_ACCESS) // out: MUP_FSCTL_UNC_HARDENING_PREFIX_TABLE_ENTRY[]\n#define FSCTL_MUP_GET_UNC_HARDENING_CONFIGURATION_FOR_PATH  CTL_CODE(FILE_DEVICE_MULTI_UNC_PROVIDER, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) // in: MUP_FSCTL_QUERY_UNC_HARDENING_CONFIGURATION_IN; out: MUP_FSCTL_QUERY_UNC_HARDENING_CONFIGURATION_OUT\n\n// private\ntypedef struct _MUP_FSCTL_UNC_CACHE_ENTRY\n{\n    ULONG TotalLength;\n    ULONG UncNameOffset; // to WCHAR[] from this struct\n    USHORT UncNameLength; // in bytes\n    ULONG ProviderNameOffset; // to WCHAR[] from this struct\n    USHORT ProviderNameLength; // in bytes\n    ULONG SurrogateNameOffset; // to WCHAR[] from this struct\n    USHORT SurrogateNameLength; // in bytes\n    ULONG ProviderPriority;\n    ULONG EntryTtl;\n    WCHAR Strings[ANYSIZE_ARRAY];\n} MUP_FSCTL_UNC_CACHE_ENTRY, *PMUP_FSCTL_UNC_CACHE_ENTRY;\n\n// private\ntypedef struct _MUP_FSCTL_UNC_CACHE_INFORMATION\n{\n    ULONG MaxCacheSize;\n    ULONG CurrentCacheSize;\n    ULONG EntryTimeout;\n    ULONG TotalEntries;\n    MUP_FSCTL_UNC_CACHE_ENTRY CacheEntry[ANYSIZE_ARRAY];\n} MUP_FSCTL_UNC_CACHE_INFORMATION, *PMUP_FSCTL_UNC_CACHE_INFORMATION;\n\n// private\ntypedef struct _MUP_FSCTL_UNC_PROVIDER_ENTRY\n{\n    ULONG TotalLength;\n    LONG ReferenceCount;\n    ULONG ProviderPriority;\n    ULONG ProviderState;\n    ULONG ProviderId;\n    USHORT ProviderNameLength; // in bytes\n    WCHAR ProviderName[ANYSIZE_ARRAY];\n} MUP_FSCTL_UNC_PROVIDER_ENTRY, *PMUP_FSCTL_UNC_PROVIDER_ENTRY;\n\n// private\ntypedef struct _MUP_FSCTL_UNC_PROVIDER_INFORMATION\n{\n    ULONG TotalEntries;\n    MUP_FSCTL_UNC_PROVIDER_ENTRY ProviderEntry[ANYSIZE_ARRAY];\n} MUP_FSCTL_UNC_PROVIDER_INFORMATION, *PMUP_FSCTL_UNC_PROVIDER_INFORMATION;\n\n// private\ntypedef struct _MUP_FSCTL_SURROGATE_PROVIDER_ENTRY\n{\n    ULONG TotalLength;\n    LONG ReferenceCount;\n    ULONG SurrogateType;\n    ULONG SurrogateState;\n    ULONG SurrogatePriority;\n    USHORT SurrogateNameLength; // in bytes\n    WCHAR SurrogateName[ANYSIZE_ARRAY];\n} MUP_FSCTL_SURROGATE_PROVIDER_ENTRY, *PMUP_FSCTL_SURROGATE_PROVIDER_ENTRY;\n\n// private\ntypedef struct _MUP_FSCTL_SURROGATE_PROVIDER_INFORMATION\n{\n    ULONG TotalEntries;\n    MUP_FSCTL_SURROGATE_PROVIDER_ENTRY SurrogateEntry[ANYSIZE_ARRAY];\n} MUP_FSCTL_SURROGATE_PROVIDER_INFORMATION, *PMUP_FSCTL_SURROGATE_PROVIDER_INFORMATION;\n\n// private\ntypedef struct _MUP_FSCTL_UNC_HARDENING_PREFIX_TABLE_ENTRY\n{\n    ULONG NextOffset; // from this struct\n    ULONG PrefixNameOffset; // to WCHAR[] from this struct\n    USHORT PrefixNameCbLength; // in bytes\n    union\n    {\n        ULONG RequiredHardeningCapabilities;\n        struct\n        {\n            ULONG RequiresMutualAuth : 1;\n            ULONG RequiresIntegrity : 1;\n            ULONG RequiresPrivacy : 1;\n        };\n    };\n    ULONGLONG OpenCount;\n} MUP_FSCTL_UNC_HARDENING_PREFIX_TABLE_ENTRY, *PMUP_FSCTL_UNC_HARDENING_PREFIX_TABLE_ENTRY;\n\n// private\ntypedef struct _MUP_FSCTL_QUERY_UNC_HARDENING_CONFIGURATION_IN\n{\n    ULONG Size;\n    ULONG UncPathOffset; // to WCHAR[] from this struct\n    USHORT UncPathCbLength; // in bytes\n} MUP_FSCTL_QUERY_UNC_HARDENING_CONFIGURATION_IN, *PMUP_FSCTL_QUERY_UNC_HARDENING_CONFIGURATION_IN;\n\n// private\ntypedef struct _MUP_FSCTL_QUERY_UNC_HARDENING_CONFIGURATION_OUT\n{\n    ULONG Size;\n    union\n    {\n        ULONG RequiredHardeningCapabilities;\n        struct\n        {\n            ULONG RequiresMutualAuth : 1;\n            ULONG RequiresIntegrity : 1;\n            ULONG RequiresPrivacy : 1;\n        };\n    };\n} MUP_FSCTL_QUERY_UNC_HARDENING_CONFIGURATION_OUT, *PMUP_FSCTL_QUERY_UNC_HARDENING_CONFIGURATION_OUT;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Major Function Codes\n//\n#define IRP_MJ_CREATE                                0x00\n#define IRP_MJ_CREATE_NAMED_PIPE                     0x01\n#define IRP_MJ_CLOSE                                 0x02\n#define IRP_MJ_READ                                  0x03\n#define IRP_MJ_WRITE                                 0x04\n#define IRP_MJ_QUERY_INFORMATION                     0x05\n#define IRP_MJ_SET_INFORMATION                       0x06\n#define IRP_MJ_QUERY_EA                              0x07\n#define IRP_MJ_SET_EA                                0x08\n#define IRP_MJ_FLUSH_BUFFERS                         0x09\n#define IRP_MJ_QUERY_VOLUME_INFORMATION              0x0a\n#define IRP_MJ_SET_VOLUME_INFORMATION                0x0b\n#define IRP_MJ_DIRECTORY_CONTROL                     0x0c\n#define IRP_MJ_FILE_SYSTEM_CONTROL                   0x0d\n#define IRP_MJ_DEVICE_CONTROL                        0x0e\n#define IRP_MJ_INTERNAL_DEVICE_CONTROL               0x0f\n#define IRP_MJ_SHUTDOWN                              0x10\n#define IRP_MJ_LOCK_CONTROL                          0x11\n#define IRP_MJ_CLEANUP                               0x12\n#define IRP_MJ_CREATE_MAILSLOT                       0x13\n#define IRP_MJ_QUERY_SECURITY                        0x14\n#define IRP_MJ_SET_SECURITY                          0x15\n#define IRP_MJ_POWER                                 0x16\n#define IRP_MJ_SYSTEM_CONTROL                        0x17\n#define IRP_MJ_DEVICE_CHANGE                         0x18\n#define IRP_MJ_QUERY_QUOTA                           0x19\n#define IRP_MJ_SET_QUOTA                             0x1a\n#define IRP_MJ_PNP                                   0x1b\n#define IRP_MJ_PNP_POWER                             IRP_MJ_PNP      // Obsolete....\n#define IRP_MJ_MAXIMUM_FUNCTION                      0x1b\n#define IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION   ((UCHAR)-1)\n#define IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION   ((UCHAR)-2)\n#define IRP_MJ_ACQUIRE_FOR_MOD_WRITE                 ((UCHAR)-3)\n#define IRP_MJ_RELEASE_FOR_MOD_WRITE                 ((UCHAR)-4)\n#define IRP_MJ_ACQUIRE_FOR_CC_FLUSH                  ((UCHAR)-5)\n#define IRP_MJ_RELEASE_FOR_CC_FLUSH                  ((UCHAR)-6)\n#define IRP_MJ_QUERY_OPEN                            ((UCHAR)-7)\n#define IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE             ((UCHAR)-13)\n#define IRP_MJ_NETWORK_QUERY_OPEN                    ((UCHAR)-14)\n#define IRP_MJ_MDL_READ                              ((UCHAR)-15)\n#define IRP_MJ_MDL_READ_COMPLETE                     ((UCHAR)-16)\n#define IRP_MJ_PREPARE_MDL_WRITE                     ((UCHAR)-17)\n#define IRP_MJ_MDL_WRITE_COMPLETE                    ((UCHAR)-18)\n#define IRP_MJ_VOLUME_MOUNT                          ((UCHAR)-19)\n#define IRP_MJ_VOLUME_DISMOUNT                       ((UCHAR)-20)\n#define FLT_INTERNAL_OPERATION_COUNT                 22\n\n//\n// Minor Function Codes\n//\n#define IRP_MN_SCSI_CLASS                   0x01\n// PNP minor function codes\n#define IRP_MN_START_DEVICE                 0x00\n#define IRP_MN_QUERY_REMOVE_DEVICE          0x01\n#define IRP_MN_REMOVE_DEVICE                0x02\n#define IRP_MN_CANCEL_REMOVE_DEVICE         0x03\n#define IRP_MN_STOP_DEVICE                  0x04\n#define IRP_MN_QUERY_STOP_DEVICE            0x05\n#define IRP_MN_CANCEL_STOP_DEVICE           0x06\n#define IRP_MN_QUERY_DEVICE_RELATIONS       0x07\n#define IRP_MN_QUERY_INTERFACE              0x08\n#define IRP_MN_QUERY_CAPABILITIES           0x09\n#define IRP_MN_QUERY_RESOURCES              0x0A\n#define IRP_MN_QUERY_RESOURCE_REQUIREMENTS  0x0B\n#define IRP_MN_QUERY_DEVICE_TEXT            0x0C\n#define IRP_MN_FILTER_RESOURCE_REQUIREMENTS 0x0D\n#define IRP_MN_READ_CONFIG                  0x0F\n#define IRP_MN_WRITE_CONFIG                 0x10\n#define IRP_MN_EJECT                        0x11\n#define IRP_MN_SET_LOCK                     0x12\n#define IRP_MN_QUERY_ID                     0x13\n#define IRP_MN_QUERY_PNP_DEVICE_STATE       0x14\n#define IRP_MN_QUERY_BUS_INFORMATION        0x15\n#define IRP_MN_DEVICE_USAGE_NOTIFICATION    0x16\n#define IRP_MN_SURPRISE_REMOVAL             0x17\n#define IRP_MN_DEVICE_ENUMERATED            0x19\n\n// POWER minor function codes\n#define IRP_MN_WAIT_WAKE                    0x00\n#define IRP_MN_POWER_SEQUENCE               0x01\n#define IRP_MN_SET_POWER                    0x02\n#define IRP_MN_QUERY_POWER                  0x03\n// WMI minor function codes under IRP_MJ_SYSTEM_CONTROL\n#define IRP_MN_QUERY_ALL_DATA               0x00\n#define IRP_MN_QUERY_SINGLE_INSTANCE        0x01\n#define IRP_MN_CHANGE_SINGLE_INSTANCE       0x02\n#define IRP_MN_CHANGE_SINGLE_ITEM           0x03\n#define IRP_MN_ENABLE_EVENTS                0x04\n#define IRP_MN_DISABLE_EVENTS               0x05\n#define IRP_MN_ENABLE_COLLECTION            0x06\n#define IRP_MN_DISABLE_COLLECTION           0x07\n#define IRP_MN_REGINFO                      0x08\n#define IRP_MN_EXECUTE_METHOD               0x09\n// Minor code 0x0a is reserved\n#define IRP_MN_REGINFO_EX                   0x0b\n// Minor code 0x0c is reserved\n// Minor code 0x0d is reserved\n\n//\n// Filter Manager Callback Data Flags\n//\n#define FLTFL_CALLBACK_DATA_REISSUE_MASK        0x0000FFFF\n#define FLTFL_CALLBACK_DATA_IRP_OPERATION       0x00000001 // Set for Irp operations\n#define FLTFL_CALLBACK_DATA_FAST_IO_OPERATION   0x00000002 // Set for Fast Io operations\n#define FLTFL_CALLBACK_DATA_FS_FILTER_OPERATION 0x00000004 // Set for Fs Filter operations\n#define FLTFL_CALLBACK_DATA_SYSTEM_BUFFER       0x00000008 // Set if the buffer passed in for the i/o was a system buffer\n#define FLTFL_CALLBACK_DATA_GENERATED_IO        0x00010000 // Set if this is I/O generated by a mini-filter\n#define FLTFL_CALLBACK_DATA_REISSUED_IO         0x00020000 // Set if this I/O was reissued\n#define FLTFL_CALLBACK_DATA_DRAINING_IO         0x00040000 // set if this operation is being drained. If set,\n#define FLTFL_CALLBACK_DATA_POST_OPERATION      0x00080000 // Set if this is a POST operation\n#define FLTFL_CALLBACK_DATA_NEW_SYSTEM_BUFFER   0x00100000\n#define FLTFL_CALLBACK_DATA_DIRTY               0x80000000 // Set by caller if parameters were changed\n\n//\n// IRP Flags\n//\n#define IRP_NOCACHE                     0x00000001\n#define IRP_PAGING_IO                   0x00000002\n#define IRP_MOUNT_COMPLETION            0x00000002\n#define IRP_SYNCHRONOUS_API             0x00000004\n#define IRP_ASSOCIATED_IRP              0x00000008\n#define IRP_BUFFERED_IO                 0x00000010\n#define IRP_DEALLOCATE_BUFFER           0x00000020\n#define IRP_INPUT_OPERATION             0x00000040\n#define IRP_SYNCHRONOUS_PAGING_IO       0x00000040\n#define IRP_CREATE_OPERATION            0x00000080\n#define IRP_READ_OPERATION              0x00000100\n#define IRP_WRITE_OPERATION             0x00000200\n#define IRP_CLOSE_OPERATION             0x00000400\n#define IRP_DEFER_IO_COMPLETION         0x00000800\n#define IRP_OB_QUERY_NAME               0x00001000\n#define IRP_HOLD_DEVICE_QUEUE           0x00002000\n#define IRP_UM_DRIVER_INITIATED_IO      0x00400000\n\n//\n// File Object Flags\n//\n#define FO_FILE_OPEN                    0x00000001\n#define FO_SYNCHRONOUS_IO               0x00000002\n#define FO_ALERTABLE_IO                 0x00000004\n#define FO_NO_INTERMEDIATE_BUFFERING    0x00000008\n#define FO_WRITE_THROUGH                0x00000010\n#define FO_SEQUENTIAL_ONLY              0x00000020\n#define FO_CACHE_SUPPORTED              0x00000040\n#define FO_NAMED_PIPE                   0x00000080\n#define FO_STREAM_FILE                  0x00000100\n#define FO_MAILSLOT                     0x00000200\n#define FO_GENERATE_AUDIT_ON_CLOSE      0x00000400\n#define FO_QUEUE_IRP_TO_THREAD          FO_GENERATE_AUDIT_ON_CLOSE\n#define FO_DIRECT_DEVICE_OPEN           0x00000800\n#define FO_FILE_MODIFIED                0x00001000\n#define FO_FILE_SIZE_CHANGED            0x00002000\n#define FO_CLEANUP_COMPLETE             0x00004000\n#define FO_TEMPORARY_FILE               0x00008000\n#define FO_DELETE_ON_CLOSE              0x00010000\n#define FO_OPENED_CASE_SENSITIVE        0x00020000\n#define FO_HANDLE_CREATED               0x00040000\n#define FO_FILE_FAST_IO_READ            0x00080000\n#define FO_RANDOM_ACCESS                0x00100000\n#define FO_FILE_OPEN_CANCELLED          0x00200000\n#define FO_VOLUME_OPEN                  0x00400000\n#define FO_BYPASS_IO_ENABLED            0x00800000  //when set BYPASS IO is enabled on this handle\n#define FO_REMOTE_ORIGIN                0x01000000\n#define FO_DISALLOW_EXCLUSIVE           0x02000000\n#define FO_SKIP_COMPLETION_PORT         FO_DISALLOW_EXCLUSIVE\n#define FO_SKIP_SET_EVENT               0x04000000\n#define FO_SKIP_SET_FAST_IO             0x08000000\n#define FO_INDIRECT_WAIT_OBJECT         0x10000000\n#define FO_SECTION_MINSTORE_TREATMENT   0x20000000\n\n//\n// Define stack location (IO_STACK_LOCATION) flags\n//\n#define SL_PENDING_RETURNED                0x01\n#define SL_ERROR_RETURNED                  0x02\n#define SL_INVOKE_ON_CANCEL                0x20\n#define SL_INVOKE_ON_SUCCESS               0x40\n#define SL_INVOKE_ON_ERROR                 0x80\n// Create / Create Named Pipe (IRP_MJ_CREATE/IRP_MJ_CREATE_NAMED_PIPE)\n#define SL_FORCE_ACCESS_CHECK              0x01\n#define SL_OPEN_PAGING_FILE                0x02\n#define SL_OPEN_TARGET_DIRECTORY           0x04\n#define SL_STOP_ON_SYMLINK                 0x08\n#define SL_IGNORE_READONLY_ATTRIBUTE       0x40\n#define SL_CASE_SENSITIVE                  0x80\n// Read / Write (IRP_MJ_READ/IRP_MJ_WRITE)\n#define SL_KEY_SPECIFIED                   0x01\n#define SL_OVERRIDE_VERIFY_VOLUME          0x02\n#define SL_WRITE_THROUGH                   0x04\n#define SL_FT_SEQUENTIAL_WRITE             0x08\n#define SL_FORCE_DIRECT_WRITE              0x10\n#define SL_REALTIME_STREAM                 0x20    // valid only with optical media\n#define SL_PERSISTENT_MEMORY_FIXED_MAPPING 0x20    // valid only with persistent memory device and IRP_MJ_WRITE\n#define SL_BYPASS_IO                       0x40\n//  IRP_MJ_FLUSH_BUFFERS\n#define SL_FORCE_ASYNCHRONOUS              0x01\n// Device I/O Control\n#define SL_READ_ACCESS_GRANTED             0x01\n#define SL_WRITE_ACCESS_GRANTED            0x04    // Gap for SL_OVERRIDE_VERIFY_VOLUME\n// Lock (IRP_MJ_LOCK_CONTROL)\n#define SL_FAIL_IMMEDIATELY                0x01\n#define SL_EXCLUSIVE_LOCK                  0x02\n// QueryDirectory / QueryEa / QueryQuota (IRP_MJ_DIRECTORY_CONTROL/IRP_MJ_QUERY_EA/IRP_MJ_QUERY_QUOTA))\n#define SL_RESTART_SCAN                    0x01\n#define SL_RETURN_SINGLE_ENTRY             0x02\n#define SL_INDEX_SPECIFIED                 0x04\n#define SL_RETURN_ON_DISK_ENTRIES_ONLY     0x08\n#define SL_NO_CURSOR_UPDATE                0x10\n#define SL_QUERY_DIRECTORY_MASK            0x1b\n// NotifyDirectory (IRP_MJ_DIRECTORY_CONTROL)\n#define SL_WATCH_TREE                      0x01\n// FileSystemControl (IRP_MJ_FILE_SYSTEM_CONTROL)\n#define SL_ALLOW_RAW_MOUNT                 0x01\n//  SetInformationFile (IRP_MJ_SET_INFORMATION) / QueryInformationFile\n#define SL_BYPASS_ACCESS_CHECK             0x01\n#define SL_INFO_FORCE_ACCESS_CHECK         0x01\n#define SL_INFO_IGNORE_READONLY_ATTRIBUTE  0x40  // same value as IO_IGNORE_READONLY_ATTRIBUTE\n\n//\n// Device Object (DO) flags\n//\n#define DO_VERIFY_VOLUME                0x00000002\n#define DO_BUFFERED_IO                  0x00000004\n#define DO_EXCLUSIVE                    0x00000008\n#define DO_DIRECT_IO                    0x00000010\n#define DO_MAP_IO_BUFFER                0x00000020\n#define DO_DEVICE_INITIALIZING          0x00000080\n#define DO_SHUTDOWN_REGISTERED          0x00000800\n#define DO_BUS_ENUMERATED_DEVICE        0x00001000\n#define DO_POWER_PAGABLE                0x00002000\n#define DO_POWER_INRUSH                 0x00004000\n#define DO_DEVICE_TO_BE_RESET           0x04000000\n#define DO_DAX_VOLUME                   0x10000000\n\n// pub\ntypedef enum _FS_FILTER_SECTION_SYNC_TYPE\n{\n    SyncTypeOther = 0,\n    SyncTypeCreateSection\n} FS_FILTER_SECTION_SYNC_TYPE, *PFS_FILTER_SECTION_SYNC_TYPE;\n\n//pub\ntypedef enum _CREATE_FILE_TYPE\n{\n    CreateFileTypeNone,\n    CreateFileTypeNamedPipe,\n    CreateFileTypeMailslot\n} CREATE_FILE_TYPE;\n\n// pub\ntypedef struct _NAMED_PIPE_CREATE_PARAMETERS\n{\n    ULONG NamedPipeType;\n    ULONG ReadMode;\n    ULONG CompletionMode;\n    ULONG MaximumInstances;\n    ULONG InboundQuota;\n    ULONG OutboundQuota;\n    LARGE_INTEGER DefaultTimeout;\n    BOOLEAN TimeoutSpecified;\n} NAMED_PIPE_CREATE_PARAMETERS, *PNAMED_PIPE_CREATE_PARAMETERS;\n\n// pub\ntypedef struct _MAILSLOT_CREATE_PARAMETERS\n{\n    ULONG MailslotQuota;\n    ULONG MaximumMessageSize;\n    LARGE_INTEGER ReadTimeout;\n    BOOLEAN TimeoutSpecified;\n} MAILSLOT_CREATE_PARAMETERS, *PMAILSLOT_CREATE_PARAMETERS;\n\n// pub\ntypedef struct _OPLOCK_KEY_ECP_CONTEXT\n{\n    GUID OplockKey;\n    ULONG Reserved;\n} OPLOCK_KEY_ECP_CONTEXT, *POPLOCK_KEY_ECP_CONTEXT;\n\n// pub\ntypedef struct _OPLOCK_KEY_CONTEXT\n{\n    USHORT Version;        //  OPLOCK_KEY_VERSION_*\n    USHORT Flags;          //  OPLOCK_KEY_FLAG_*\n    GUID ParentOplockKey;\n    GUID TargetOplockKey;\n    ULONG Reserved;\n} OPLOCK_KEY_CONTEXT, *POPLOCK_KEY_CONTEXT;\n\n#define OPLOCK_KEY_VERSION_WIN7    0x0001\n#define OPLOCK_KEY_VERSION_WIN8    0x0002\n\n#define OPLOCK_KEY_FLAG_PARENT_KEY 0x0001\n#define OPLOCK_KEY_FLAG_TARGET_KEY 0x0002\n\n// pub\n#define SUPPORTED_FS_FEATURES_OFFLOAD_READ    0x00000001\n#define SUPPORTED_FS_FEATURES_OFFLOAD_WRITE   0x00000002\n#define SUPPORTED_FS_FEATURES_QUERY_OPEN      0x00000004\n#define SUPPORTED_FS_FEATURES_BYPASS_IO       0x00000008\n\n// WIN11\n#define SUPPORTED_FS_FEATURES_VALID_MASK_V3 (SUPPORTED_FS_FEATURES_OFFLOAD_READ | \\\n                                               SUPPORTED_FS_FEATURES_OFFLOAD_WRITE | \\\n                                               SUPPORTED_FS_FEATURES_QUERY_OPEN | \\\n                                               SUPPORTED_FS_FEATURES_BYPASS_IO)\n// WIN10-RS2\n#define SUPPORTED_FS_FEATURES_VALID_MASK_V2 (SUPPORTED_FS_FEATURES_OFFLOAD_READ | \\\n                                               SUPPORTED_FS_FEATURES_OFFLOAD_WRITE | \\\n                                               SUPPORTED_FS_FEATURES_QUERY_OPEN)\n// WIN8\n#define SUPPORTED_FS_FEATURES_VALID_MASK_V1 (SUPPORTED_FS_FEATURES_OFFLOAD_READ | \\\n                                               SUPPORTED_FS_FEATURES_OFFLOAD_WRITE)\n\n#define SUPPORTED_FS_FEATURES_VALID_MASK SUPPORTED_FS_FEATURES_VALID_MASK_V3\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#endif // _NTIOAPI_H\n"
  },
  {
    "path": "phnt/include/ntkeapi.h",
    "content": "/*\n * Kernel executive support library\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTKEAPI_H\n#define _NTKEAPI_H\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define LOW_PRIORITY 0 // Lowest thread priority level\n#define LOW_REALTIME_PRIORITY 16 // Lowest realtime priority level\n#define HIGH_PRIORITY 31 // Highest thread priority level\n#define MAXIMUM_PRIORITY 32 // Number of thread priority levels\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\ntypedef enum _KTHREAD_STATE\n{\n    Initialized,\n    Ready,\n    Running,\n    Standby,\n    Terminated,\n    Waiting,\n    Transition,\n    DeferredReady,\n    GateWaitObsolete,\n    WaitingForProcessInSwap,\n    MaximumThreadState\n} KTHREAD_STATE, *PKTHREAD_STATE;\n\n// private\ntypedef enum _KHETERO_CPU_POLICY\n{\n    KHeteroCpuPolicyAll = 0,\n    KHeteroCpuPolicyLarge = 1,\n    KHeteroCpuPolicyLargeOrIdle = 2,\n    KHeteroCpuPolicySmall = 3,\n    KHeteroCpuPolicySmallOrIdle = 4,\n    KHeteroCpuPolicyDynamic = 5,\n    KHeteroCpuPolicyStaticMax = 5, // valid\n    KHeteroCpuPolicyBiasedSmall = 6,\n    KHeteroCpuPolicyBiasedLarge = 7,\n    KHeteroCpuPolicyDefault = 8,\n    KHeteroCpuPolicyMax = 9\n} KHETERO_CPU_POLICY, *PKHETERO_CPU_POLICY;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n/**\n * KWAIT_REASON identifies the reasons for context switches or the current waiting state.\n */\ntypedef enum _KWAIT_REASON\n{\n    Executive,               // Waiting for an executive event.\n    FreePage,                // Waiting for a free page.\n    PageIn,                  // Waiting for a page to be read in.\n    PoolAllocation,          // Waiting for a pool allocation.\n    DelayExecution,          // Waiting due to a delay execution.           // NtDelayExecution\n    Suspended,               // Waiting because the thread is suspended.    // NtSuspendThread\n    UserRequest,             // Waiting due to a user request.              // NtWaitForSingleObject\n    WrExecutive,             // Waiting for an executive event.\n    WrFreePage,              // Waiting for a free page.\n    WrPageIn,                // Waiting for a page to be read in.\n    WrPoolAllocation,        // Waiting for a pool allocation.              // 10\n    WrDelayExecution,        // Waiting due to a delay execution.\n    WrSuspended,             // Waiting because the thread is suspended.\n    WrUserRequest,           // Waiting due to a user request.\n    WrEventPair,             // Waiting for an event pair.                  // NtCreateEventPair\n    WrQueue,                 // Waiting for a queue.                        // NtRemoveIoCompletion\n    WrLpcReceive,            // Waiting for an LPC receive.                 // NtReplyWaitReceivePort\n    WrLpcReply,              // Waiting for an LPC reply.                   // NtRequestWaitReplyPort\n    WrVirtualMemory,         // Waiting for virtual memory.\n    WrPageOut,               // Waiting for a page to be written out.       // NtFlushVirtualMemory\n    WrRendezvous,            // Waiting for a rendezvous.                   // 20\n    WrKeyedEvent,            // Waiting for a keyed event.                  // NtCreateKeyedEvent\n    WrTerminated,            // Waiting for thread termination.\n    WrProcessInSwap,         // Waiting for a process to be swapped in.\n    WrCpuRateControl,        // Waiting for CPU rate control.\n    WrCalloutStack,          // Waiting for a callout stack.\n    WrKernel,                // Waiting for a kernel event.\n    WrResource,              // Waiting for a resource.\n    WrPushLock,              // Waiting for a push lock.\n    WrMutex,                 // Waiting for a mutex.\n    WrQuantumEnd,            // Waiting for the end of a quantum.           // 30\n    WrDispatchInt,           // Waiting for a dispatch interrupt.\n    WrPreempted,             // Waiting because the thread was preempted.\n    WrYieldExecution,        // Waiting to yield execution.\n    WrFastMutex,             // Waiting for a fast mutex.\n    WrGuardedMutex,          // Waiting for a guarded mutex.\n    WrRundown,               // Waiting for a rundown.\n    WrAlertByThreadId,       // Waiting for an alert by thread ID.\n    WrDeferredPreempt,       // Waiting for a deferred preemption.\n    WrPhysicalFault,         // Waiting for a physical fault.\n    WrIoRing,                // Waiting for an I/O ring.                    // 40\n    WrMdlCache,              // Waiting for an MDL cache.\n    WrRcu,                   // Waiting for read-copy-update (RCU) synchronization.\n    MaximumWaitReason\n} KWAIT_REASON, *PKWAIT_REASON;\n\ntypedef enum _KPROFILE_SOURCE\n{\n    ProfileTime,\n    ProfileAlignmentFixup,\n    ProfileTotalIssues,\n    ProfilePipelineDry,\n    ProfileLoadInstructions,\n    ProfilePipelineFrozen,\n    ProfileBranchInstructions,\n    ProfileTotalNonissues,\n    ProfileDcacheMisses,\n    ProfileIcacheMisses,\n    ProfileCacheMisses,\n    ProfileBranchMispredictions,\n    ProfileStoreInstructions,\n    ProfileFpInstructions,\n    ProfileIntegerInstructions,\n    Profile2Issue,\n    Profile3Issue,\n    Profile4Issue,\n    ProfileSpecialInstructions,\n    ProfileTotalCycles,\n    ProfileIcacheIssues,\n    ProfileDcacheAccesses,\n    ProfileMemoryBarrierCycles,\n    ProfileLoadLinkedIssues,\n    ProfileMaximum\n} KPROFILE_SOURCE;\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCallbackReturn(\n    _In_reads_bytes_opt_(OutputLength) PVOID OutputBuffer,\n    _In_ ULONG OutputLength,\n    _In_ NTSTATUS Status\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_ BOOLEAN State\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtYieldExecution(\n    VOID\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#endif // _NTKEAPI_H\n"
  },
  {
    "path": "phnt/include/ntldr.h",
    "content": "/*\n * Loader support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTLDR_H\n#define _NTLDR_H\n\ntypedef struct _ACTIVATION_CONTEXT *PACTIVATION_CONTEXT;\ntypedef struct _LDRP_LOAD_CONTEXT *PLDRP_LOAD_CONTEXT;\n\n//\n// DLLs\n//\n\ntypedef _Function_class_(DLL_INIT_ROUTINE)\nBOOLEAN NTAPI DLL_INIT_ROUTINE(\n    _In_ PVOID DllHandle,\n    _In_ ULONG Reason,\n    _In_opt_ PVOID Context\n    );\ntypedef DLL_INIT_ROUTINE* PDLL_INIT_ROUTINE;\n\n// private\ntypedef struct _LDR_SERVICE_TAG_RECORD\n{\n    struct _LDR_SERVICE_TAG_RECORD *Next;\n    ULONG ServiceTag;\n} LDR_SERVICE_TAG_RECORD, *PLDR_SERVICE_TAG_RECORD;\n\n// private\ntypedef struct _LDRP_CSLIST\n{\n    PSINGLE_LIST_ENTRY Tail;\n} LDRP_CSLIST, *PLDRP_CSLIST;\n\n// private\ntypedef enum _LDR_DDAG_STATE\n{\n    LdrModulesMerged = -5,\n    LdrModulesInitError = -4,\n    LdrModulesSnapError = -3,\n    LdrModulesUnloaded = -2,\n    LdrModulesUnloading = -1,\n    LdrModulesPlaceHolder = 0,\n    LdrModulesMapping = 1,\n    LdrModulesMapped = 2,\n    LdrModulesWaitingForDependencies = 3,\n    LdrModulesSnapping = 4,\n    LdrModulesSnapped = 5,\n    LdrModulesCondensed = 6,\n    LdrModulesReadyToInit = 7,\n    LdrModulesInitializing = 8,\n    LdrModulesReadyToRun = 9\n} LDR_DDAG_STATE;\n\n// private\ntypedef struct _LDR_DDAG_NODE\n{\n    LIST_ENTRY Modules;\n    PLDR_SERVICE_TAG_RECORD ServiceTagList;\n    ULONG LoadCount;\n    ULONG LoadWhileUnloadingCount; // ReferenceCount before WIN10\n    ULONG LowestLink; // DependencyCount before WIN10\n    union\n    {\n        LDRP_CSLIST Dependencies;\n        SINGLE_LIST_ENTRY RemovalLink;\n    };\n    LDRP_CSLIST IncomingDependencies;\n    LDR_DDAG_STATE State;\n    SINGLE_LIST_ENTRY CondenseLink;\n    ULONG PreorderNumber;\n} LDR_DDAG_NODE, *PLDR_DDAG_NODE;\n\n// private\ntypedef struct _LDRP_DEPENDENCY\n{\n    SINGLE_LIST_ENTRY Link;\n    PLDR_DDAG_NODE ChildNode;\n    SINGLE_LIST_ENTRY BackLink;\n    union\n    {\n        PLDR_DDAG_NODE ParentNode;\n        struct\n        {\n            ULONG ForwarderLink : 1;\n            ULONG SpareFlags : 2;\n        };\n    };\n} LDRP_DEPENDENCY, *PLDRP_DEPENDENCY;\n\n// LoadReason\ntypedef enum _LDR_DLL_LOAD_REASON\n{\n    LoadReasonUnknown = -1,\n    LoadReasonStaticDependency = 0,\n    LoadReasonStaticForwarderDependency = 1,\n    LoadReasonDynamicForwarderDependency = 2,\n    LoadReasonDelayloadDependency = 3,\n    LoadReasonDynamicLoad = 4,\n    LoadReasonAsImageLoad = 5,\n    LoadReasonAsDataLoad = 6,\n    LoadReasonEnclavePrimary = 7, // since REDSTONE3\n    LoadReasonEnclaveDependency = 8,\n    LoadReasonPatchImage = 9, // since WIN11\n} LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON;\n\n// HotPatchState\ntypedef enum _LDR_HOT_PATCH_STATE\n{\n    LdrHotPatchBaseImage,\n    LdrHotPatchNotApplied,\n    LdrHotPatchAppliedReverse,\n    LdrHotPatchAppliedForward,\n    LdrHotPatchFailedToPatch,\n    LdrHotPatchStateMax,\n} LDR_HOT_PATCH_STATE, *PLDR_HOT_PATCH_STATE;\n\n// LDR_DATA_TABLE_ENTRY->Flags\n#define LDRP_PACKAGED_BINARY 0x00000001\n#define LDRP_MARKED_FOR_REMOVAL 0x00000002\n#define LDRP_IMAGE_DLL 0x00000004\n#define LDRP_LOAD_NOTIFICATIONS_SENT 0x00000008\n#define LDRP_TELEMETRY_ENTRY_PROCESSED 0x00000010\n#define LDRP_PROCESS_STATIC_IMPORT 0x00000020\n#define LDRP_IN_LEGACY_LISTS 0x00000040\n#define LDRP_IN_INDEXES 0x00000080\n#define LDRP_SHIM_DLL 0x00000100\n#define LDRP_IN_EXCEPTION_TABLE 0x00000200\n#define LDRP_VERIFIER_PROVIDER 0x00000400 // reserved before WIN11 24H2\n#define LDRP_SHIM_ENGINE_CALLOUT_SENT 0x00000800 // reserved before WIN11 24H2\n#define LDRP_LOAD_IN_PROGRESS 0x00001000\n#define LDRP_LOAD_CONFIG_PROCESSED 0x00002000 // reserved before WIN10\n#define LDRP_ENTRY_PROCESSED 0x00004000\n#define LDRP_PROTECT_DELAY_LOAD 0x00008000 // reserved before WINBLUE\n#define LDRP_AUX_IAT_COPY_PRIVATE 0x00010000 // reserved before WIN11 24H2\n#define LDRP_DONT_CALL_FOR_THREADS 0x00040000\n#define LDRP_PROCESS_ATTACH_CALLED 0x00080000\n#define LDRP_PROCESS_ATTACH_FAILED 0x00100000\n#define LDRP_SCP_IN_EXCEPTION_TABLE 0x00200000 // LDRP_COR_DEFERRED_VALIDATE before WIN11 24H2\n#define LDRP_COR_IMAGE 0x00400000\n#define LDRP_DONT_RELOCATE 0x00800000\n#define LDRP_COR_IL_ONLY 0x01000000\n#define LDRP_CHPE_IMAGE 0x02000000 // reserved before REDSTONE4\n#define LDRP_CHPE_EMULATOR_IMAGE 0x04000000 // reserved before WIN11\n#define LDRP_REDIRECTED 0x10000000\n#define LDRP_COMPAT_DATABASE_PROCESSED 0x80000000\n\n#define LDR_DATA_TABLE_ENTRY_SIZE_WINXP FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DdagNode)\n#define LDR_DATA_TABLE_ENTRY_SIZE_WIN7 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, BaseNameHashValue)\n#define LDR_DATA_TABLE_ENTRY_SIZE_WIN8 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ImplicitPathOptions)\n#define LDR_DATA_TABLE_ENTRY_SIZE_WIN10 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, SigningLevel)\n#define LDR_DATA_TABLE_ENTRY_SIZE_WIN11 sizeof(LDR_DATA_TABLE_ENTRY)\n\n// symbols\ntypedef struct _LDR_DATA_TABLE_ENTRY\n{\n    LIST_ENTRY InLoadOrderLinks;\n    LIST_ENTRY InMemoryOrderLinks;\n    LIST_ENTRY InInitializationOrderLinks;\n    PVOID DllBase;\n    PVOID EntryPoint; // PDLL_INIT_ROUTINE\n    ULONG SizeOfImage;\n    UNICODE_STRING FullDllName;\n    UNICODE_STRING BaseDllName;\n    union\n    {\n        UCHAR FlagGroup[4];\n        ULONG Flags;\n        struct\n        {\n            ULONG PackagedBinary : 1;\n            ULONG MarkedForRemoval : 1;\n            ULONG ImageDll : 1;\n            ULONG LoadNotificationsSent : 1;\n            ULONG TelemetryEntryProcessed : 1;\n            ULONG ProcessStaticImport : 1;\n            ULONG InLegacyLists : 1;\n            ULONG InIndexes : 1;\n            ULONG ShimDll : 1;\n            ULONG InExceptionTable : 1;\n            ULONG VerifierProvider : 1; // 24H2\n            ULONG ShimEngineCalloutSent : 1; // 24H2\n            ULONG LoadInProgress : 1;\n            ULONG LoadConfigProcessed : 1; // WIN10\n            ULONG EntryProcessed : 1;\n            ULONG ProtectDelayLoad : 1; // WINBLUE\n            ULONG AuxIatCopyPrivate : 1; // 24H2\n            ULONG ReservedFlags3 : 1;\n            ULONG DontCallForThreads : 1;\n            ULONG ProcessAttachCalled : 1;\n            ULONG ProcessAttachFailed : 1;\n            ULONG ScpInExceptionTable : 1; // CorDeferredValidate before 24H2\n            ULONG CorImage : 1;\n            ULONG DontRelocate : 1;\n            ULONG CorILOnly : 1;\n            ULONG ChpeImage : 1; // RS4\n            ULONG ChpeEmulatorImage : 1; // WIN11\n            ULONG ReservedFlags5 : 1;\n            ULONG Redirected : 1;\n            ULONG ReservedFlags6 : 2;\n            ULONG CompatDatabaseProcessed : 1;\n        };\n    };\n    USHORT ObsoleteLoadCount;\n    USHORT TlsIndex;\n    LIST_ENTRY HashLinks;\n    ULONG TimeDateStamp;\n    PACTIVATION_CONTEXT EntryPointActivationContext;\n    PVOID Lock; // RtlAcquireSRWLockExclusive\n    PLDR_DDAG_NODE DdagNode;\n    LIST_ENTRY NodeModuleLink;\n    PLDRP_LOAD_CONTEXT LoadContext;\n    PVOID ParentDllBase;\n    PVOID SwitchBackContext;\n    RTL_BALANCED_NODE BaseAddressIndexNode;\n    RTL_BALANCED_NODE MappingInfoIndexNode;\n    PVOID OriginalBase;\n    LARGE_INTEGER LoadTime;\n    ULONG BaseNameHashValue;\n    LDR_DLL_LOAD_REASON LoadReason;\n    ULONG ImplicitPathOptions; // since WINBLUE\n    ULONG ReferenceCount; // since WIN10\n    ULONG DependentLoadFlags; // since RS1\n    UCHAR SigningLevel; // since RS2\n    ULONG CheckSum; // since WIN11\n    PVOID ActivePatchImageBase;\n    LDR_HOT_PATCH_STATE HotPatchState;\n} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;\n\ntypedef const LDR_DATA_TABLE_ENTRY* PCLDR_DATA_TABLE_ENTRY;\n\n#define LDR_IS_DATAFILE(DllHandle) (((ULONG_PTR)(DllHandle)) & (ULONG_PTR)1)\n#define LDR_IS_IMAGEMAPPING(DllHandle) (((ULONG_PTR)(DllHandle)) & (ULONG_PTR)2)\n#define LDR_IS_RESOURCE(DllHandle) (LDR_IS_IMAGEMAPPING(DllHandle) || LDR_IS_DATAFILE(DllHandle))\n#define LDR_MAPPEDVIEW_TO_DATAFILE(BaseAddress) ((PVOID)(((ULONG_PTR)(BaseAddress)) | (ULONG_PTR)1))\n#define LDR_MAPPEDVIEW_TO_IMAGEMAPPING(BaseAddress) ((PVOID)(((ULONG_PTR)(BaseAddress)) | (ULONG_PTR)2))\n#define LDR_DATAFILE_TO_MAPPEDVIEW(DllHandle) ((PVOID)(((ULONG_PTR)(DllHandle)) & ~(ULONG_PTR)1))\n#define LDR_IMAGEMAPPING_TO_MAPPEDVIEW(DllHandle) ((PVOID)(((ULONG_PTR)(DllHandle)) & ~(ULONG_PTR)2))\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// rev LdrLoadDll DllCharacteristics\n#define LDR_DONT_RESOLVE_DLL_REFERENCES       0x00000002 // IMAGE_FILE_EXECUTABLE_IMAGE maps to DONT_RESOLVE_DLL_REFERENCES\n#define LDR_PACKAGED_LIBRARY                  0x00000004 // LOAD_PACKAGED_LIBRARY\n#define LDR_REQUIRE_SIGNED_TARGET             0x00800000 // maps to LOAD_LIBRARY_REQUIRE_SIGNED_TARGET (requires /INTEGRITYCHECK)\n#define LDR_OS_INTEGRITY_CONTINUITY           0x80000000 // maps to LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY // since REDSTONE2\n// rev LdrLoadDll DllPath\n#define LDR_PATH_IS_FLAGS                     0x00000001\n#define LDR_PATH_VALID_FLAGS                  0x00007F08\n#define LDR_PATH_WITH_ALTERED_SEARCH_PATH     0x00000008 // LOAD_WITH_ALTERED_SEARCH_PATH\n#define LDR_PATH_SEARCH_DLL_LOAD_DIR          0x00000100 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR\n#define LDR_PATH_SEARCH_APPLICATION_DIR       0x00000200 // LOAD_LIBRARY_SEARCH_APPLICATION_DIR\n#define LDR_PATH_SEARCH_USER_DIRS             0x00000400 // LOAD_LIBRARY_SEARCH_USER_DIRS\n#define LDR_PATH_SEARCH_SYSTEM32              0x00000800 // LOAD_LIBRARY_SEARCH_SYSTEM32\n#define LDR_PATH_SEARCH_DEFAULT_DIRS          0x00001000 // LOAD_LIBRARY_SEARCH_DEFAULT_DIRS\n#define LDR_PATH_SAFE_CURRENT_DIRS            0x00002000 // LOAD_LIBRARY_SAFE_CURRENT_DIRS // since REDSTONE1\n#define LDR_PATH_SEARCH_SYSTEM32_NO_FORWARDER 0x00004000 // LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER // since REDSTONE1\n\n/**\n * The LdrLoadDll routine loads the specified DLL into the address space of the calling process.\n *\n * \\param DllPath A pointer to a Unicode string specifying the search path for the DLL or a combination of LDR_PATH_* flags. If NULL, the default search order is used.\n * \\param DllCharacteristics A pointer to a variable specifying DLL characteristics.\n * \\param DllName A pointer to a UNICODE_STRING structure containing the name of the DLL to load.\n * \\param DllHandle A pointer that receives the handle to module on success.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrLoadDll(\n    _In_opt_ PCWSTR DllPath,\n    _In_opt_ PULONG DllCharacteristics,\n    _In_ PCUNICODE_STRING DllName,\n    _Out_ PVOID *DllHandle\n    );\n\n/**\n * The LdrUnloadDll routine unloads the specified DLL from the address space of the calling process.\n *\n * \\param DllHandle A handle to the DLL module to unload, as returned by LdrLoadDll.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-freelibrary\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrUnloadDll(\n    _In_ PVOID DllHandle\n    );\n\n/**\n * The LdrGetDllHandle routine retrieves a handle to a module that is already loaded in the calling process.\n *\n * \\param DllPath A pointer to a Unicode string specifying the search path for the DLL or a combination of LDR_PATH_* flags. If NULL, the default search order is used.\n * \\param DllCharacteristics A pointer to a variable specifying DLL characteristics. Can be NULL.\n * \\param DllName A pointer to a UNICODE_STRING structure containing the name of the DLL to find.\n * \\param DllHandle A pointer that receives the handle to the loaded DLL module on success.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllHandle(\n    _In_opt_ PCWSTR DllPath,\n    _In_opt_ PULONG DllCharacteristics,\n    _In_ PCUNICODE_STRING DllName,\n    _Out_ PVOID *DllHandle\n    );\n\n// LdrGetDllHandleEx Flags\n#define LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT 0x00000001\n#define LDR_GET_DLL_HANDLE_EX_PIN 0x00000002\n\n/**\n * The LdrGetDllHandleEx routine retrieves a handle to a module that is already loaded in the calling process, with extended control over reference counting.\n *\n * \\param Flags A combination of flags that control behavior:\n *  - LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT: Do not modify the module's reference count.\n *  - LDR_GET_DLL_HANDLE_EX_PIN: Pin the module so it cannot be unloaded for the lifetime of the process.\n * \\param DllPath An optional semicolon-separated search path used to resolve DllName if needed. If NULL, the default module lookup is used.\n * \\param DllCharacteristics Optional pointer to the DLL characteristics (same values accepted by LdrLoadDll). Typically NULL for lookups.\n * \\param DllName The Unicode name of the module to find. Can be a base name (e.g., \"ntdll.dll\") or a fully-qualified path.\n * \\param DllHandle Receives the module handle on success.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllHandleEx(\n    _In_ ULONG Flags,\n    _In_opt_ PCWSTR DllPath,\n    _In_opt_ PULONG DllCharacteristics,\n    _In_ PCUNICODE_STRING DllName,\n    _Out_ PVOID *DllHandle\n    );\n\n// rev\n/**\n * The LdrGetDllHandleByMapping routine retrieves a module handle for an image that is already loaded in the calling process, identified by base address.\n *\n * \\param BaseAddress The base address of a mapped image (image or datafile view).\n * \\param DllHandle Receives the module handle corresponding to the base address.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllHandleByMapping(\n    _In_ PVOID BaseAddress,\n    _Out_ PVOID *DllHandle\n    );\n\n// rev\n/**\n * The LdrGetDllHandleByName routine retrieves a module handle by base name and/or full path for a DLL already loaded in the calling process.\n *\n * \\param BaseDllName Optional base file name (e.g., \"kernel32.dll\"). Note: Matching is case-insensitive.\n * \\param FullDllName Optional fully-qualified path of the module. Note: Matching is case-insensitive.\n * \\param DllHandle Receives the module handle on success.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks At least one of BaseDllName or FullDllName must be supplied. If both are supplied, they must refer to the same module.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllHandleByName(\n    _In_opt_ PCUNICODE_STRING BaseDllName,\n    _In_opt_ PCUNICODE_STRING FullDllName,\n    _Out_ PVOID *DllHandle\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllFullName(\n    _In_opt_ PVOID DllHandle,\n    _Out_ PUNICODE_STRING FullDllName\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllPath(\n    _In_  PCWSTR DllName,\n    _In_  ULONG  Flags, // LOAD_LIBRARY_SEARCH_*\n    _Out_ PWSTR* DllPath,\n    _Out_ PWSTR* SearchPaths\n    );\n\n// rev\n/**\n * The LdrGetDllDirectory routine retrieves the application-specific portion of the search path used to locate DLLs for the application.\n *\n * \\param PathName A pointer to a buffer that receives the application-specific portion of the search path.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getdlldirectoryw\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllDirectory(\n    _Out_ PUNICODE_STRING PathName\n    );\n\n// rev\n/**\n * The LdrSetDllDirectory routine adds a directory to the search path used to locate DLLs for the application.\n *\n * \\param PathName The directory to be added to the search path. If this parameter is NULL, the function restores the default search order.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setdlldirectoryw\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrSetDllDirectory(\n    _In_ PCUNICODE_STRING PathName\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n#define LDR_ADDREF_DLL_PIN 0x00000001\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrAddRefDll(\n    _In_ ULONG Flags,\n    _In_ PVOID DllHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetProcedureAddress(\n    _In_ PVOID DllHandle,\n    _In_opt_ PCANSI_STRING ProcedureName,\n    _In_opt_ ULONG ProcedureNumber,\n    _Out_ PVOID *ProcedureAddress\n    );\n\n// rev\n#define LDR_GET_PROCEDURE_ADDRESS_DONT_RECORD_FORWARDER 0x00000001\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetProcedureAddressEx(\n    _In_ PVOID DllHandle,\n    _In_opt_ PCANSI_STRING ProcedureName,\n    _In_opt_ ULONG ProcedureNumber,\n    _Out_ PVOID *ProcedureAddress,\n    _In_ ULONG Flags // LDR_GET_PROCEDURE_ADDRESS_*\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetKnownDllSectionHandle(\n    _In_ PCWSTR DllName,\n    _In_ BOOLEAN KnownDlls32,\n    _Out_ PHANDLE SectionHandle\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetProcedureAddressForCaller(\n    _In_ PVOID DllHandle,\n    _In_opt_ PCANSI_STRING ProcedureName,\n    _In_opt_ ULONG ProcedureNumber,\n    _Out_ PVOID *ProcedureAddress,\n    _In_ ULONG Flags, // LDR_GET_PROCEDURE_ADDRESS_*\n    _In_ PVOID CallerAddress\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n#define LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001\n#define LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY 0x00000002\n\n#define LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID 0\n#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED 1\n#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED 2\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrLockLoaderLock(\n    _In_ ULONG Flags,\n    _Out_opt_ PULONG Disposition,\n    _Out_ PVOID *Cookie\n    );\n\n#define LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrUnlockLoaderLock(\n    _In_ ULONG Flags,\n    _In_ PVOID Cookie\n    );\n\n// private\n_Must_inspect_result_\n_Maybenull_\nNTSYSAPI\nPIMAGE_BASE_RELOCATION\nNTAPI\nLdrProcessRelocationBlock(\n    _In_ ULONG_PTR VA,\n    _In_ ULONG SizeOfBlock,\n    _In_ PUSHORT NextOffset,\n    _In_ LONG_PTR Diff\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n// private\n_Must_inspect_result_\n_Maybenull_\nNTSYSAPI\nPIMAGE_BASE_RELOCATION\nNTAPI\nLdrProcessRelocationBlockEx(\n    _In_ ULONG Machine, // IMAGE_FILE_MACHINE_AMD64|IMAGE_FILE_MACHINE_ARM|IMAGE_FILE_MACHINE_THUMB|IMAGE_FILE_MACHINE_ARMNT\n    _In_ ULONG_PTR VA,\n    _In_ ULONG SizeOfBlock,\n    _In_ PUSHORT NextOffset,\n    _In_ LONG_PTR Diff\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\ntypedef _Function_class_(LDR_IMPORT_MODULE_CALLBACK)\nVOID NTAPI LDR_IMPORT_MODULE_CALLBACK(\n    _In_ PVOID Parameter,\n    _In_ PCSTR ModuleName\n    );\ntypedef LDR_IMPORT_MODULE_CALLBACK* PLDR_IMPORT_MODULE_CALLBACK;\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrVerifyImageMatchesChecksum(\n    _In_ HANDLE ImageFileHandle,\n    _In_opt_ PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine,\n    _In_ PVOID ImportCallbackParameter,\n    _Out_opt_ PUSHORT ImageCharacteristics\n    );\n\n// private\ntypedef struct _LDR_IMPORT_CALLBACK_INFO\n{\n    PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine;\n    PVOID ImportCallbackParameter;\n} LDR_IMPORT_CALLBACK_INFO, *PLDR_IMPORT_CALLBACK_INFO;\n\n// private\ntypedef struct _LDR_SECTION_INFO\n{\n    HANDLE SectionHandle;\n    ACCESS_MASK DesiredAccess;\n    POBJECT_ATTRIBUTES ObjA;\n    ULONG SectionPageProtection;\n    ULONG AllocationAttributes;\n} LDR_SECTION_INFO, *PLDR_SECTION_INFO;\n\n// rev\n#define LDR_VERIFY_IMAGE_FLAG_USE_CALLBACK 0x01\n#define LDR_VERIFY_IMAGE_FLAG_USE_SECTION_INFO 0x02\n#define LDR_VERIFY_IMAGE_FLAG_RETURN_IMAGE_CHARACTERISTICS 0x04\n\n// private\ntypedef struct _LDR_VERIFY_IMAGE_INFO\n{\n    ULONG Size;\n    ULONG Flags; // LDR_VERIFY_IMAGE_FLAG_*\n    LDR_IMPORT_CALLBACK_INFO CallbackInfo;\n    LDR_SECTION_INFO SectionInfo;\n    USHORT ImageCharacteristics;\n} LDR_VERIFY_IMAGE_INFO, *PLDR_VERIFY_IMAGE_INFO;\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrVerifyImageMatchesChecksumEx(\n    _In_ HANDLE ImageFileHandle,\n    _Inout_ PLDR_VERIFY_IMAGE_INFO VerifyInfo\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrQueryModuleServiceTags(\n    _In_ PVOID DllHandle,\n    _Out_writes_(*BufferSize) PULONG ServiceTagBuffer,\n    _Inout_ PULONG BufferSize\n    );\n\n// begin_msdn:\"DLL Load Notification\"\n\n#define LDR_DLL_NOTIFICATION_REASON_LOADED 1\n#define LDR_DLL_NOTIFICATION_REASON_UNLOADED 2\n\ntypedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA\n{\n    ULONG Flags;\n    PUNICODE_STRING FullDllName;\n    PUNICODE_STRING BaseDllName;\n    PVOID DllBase;\n    ULONG SizeOfImage;\n} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA;\n\ntypedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA\n{\n    ULONG Flags;\n    PCUNICODE_STRING FullDllName;\n    PCUNICODE_STRING BaseDllName;\n    PVOID DllBase;\n    ULONG SizeOfImage;\n} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;\n\ntypedef union _LDR_DLL_NOTIFICATION_DATA\n{\n    LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;\n    LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;\n} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA;\n\ntypedef const LDR_DLL_NOTIFICATION_DATA *PCLDR_DLL_NOTIFICATION_DATA;\n\ntypedef _Function_class_(LDR_DLL_NOTIFICATION_FUNCTION)\nVOID NTAPI LDR_DLL_NOTIFICATION_FUNCTION(\n    _In_ ULONG NotificationReason,\n    _In_ PCLDR_DLL_NOTIFICATION_DATA NotificationData,\n    _In_opt_ PVOID Context\n    );\ntypedef LDR_DLL_NOTIFICATION_FUNCTION* PLDR_DLL_NOTIFICATION_FUNCTION;\n\n/**\n * Registers for notification when a DLL is first loaded. This notification occurs before dynamic linking takes place.\n *\n * \\param Flags This parameter must be zero.\n * \\param NotificationFunction A pointer to an LdrDllNotification notification callback function to call when the DLL is loaded.\n * \\param Context A pointer to context data for the callback function.\n * \\param Cookie A pointer to a variable to receive an identifier for the callback function. This identifier is used to unregister the notification callback function.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/devnotes/ldrregisterdllnotification\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrRegisterDllNotification(\n    _In_ ULONG Flags,\n    _In_ PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction,\n    _In_opt_ PVOID Context,\n    _Out_ PVOID *Cookie\n    );\n\n/**\n * Cancels DLL load notification previously registered by calling the LdrRegisterDllNotification function.\n *\n * \\param Cookie A pointer to the callback identifier received from the LdrRegisterDllNotification call that registered for notification.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/devnotes/ldrunregisterdllnotification\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrUnregisterDllNotification(\n    _In_ PVOID Cookie\n    );\n\n// end_msdn\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n// deprecated\nNTSYSAPI\nPUNICODE_STRING\nNTAPI\nLdrStandardizeSystemPath(\n    _In_ PCUNICODE_STRING SystemPath\n    );\n#endif\n\ntypedef struct _LDR_FAILURE_DATA\n{\n    NTSTATUS Status;\n    WCHAR DllName[0x20];\n    WCHAR AdditionalInfo[0x20];\n} LDR_FAILURE_DATA, *PLDR_FAILURE_DATA;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_VISTA)\nNTSYSAPI\nPLDR_FAILURE_DATA\nNTAPI\nLdrGetFailureData(\n    VOID\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_VISTA)\n\n// WIN8 to REDSTONE\ntypedef struct _PS_MITIGATION_OPTIONS_MAP_V1\n{\n    ULONG64 Map[1];\n} PS_MITIGATION_OPTIONS_MAP_V1, *PPS_MITIGATION_OPTIONS_MAP_V1;\n\n// private // REDSTONE2 to 19H2\ntypedef struct _PS_MITIGATION_OPTIONS_MAP_V2\n{\n    ULONG64 Map[2];\n} PS_MITIGATION_OPTIONS_MAP_V2, *PPS_MITIGATION_OPTIONS_MAP_V2;\n\n// private // since 20H1\ntypedef struct _PS_MITIGATION_OPTIONS_MAP_V3\n{\n    ULONG64 Map[3];\n} PS_MITIGATION_OPTIONS_MAP_V3, *PPS_MITIGATION_OPTIONS_MAP_V3;\n\ntypedef PS_MITIGATION_OPTIONS_MAP_V3\n    PS_MITIGATION_OPTIONS_MAP, *PPS_MITIGATION_OPTIONS_MAP;\n\n// private // REDSTONE3 to 19H2\ntypedef struct _PS_MITIGATION_AUDIT_OPTIONS_MAP_V2\n{\n    ULONG64 Map[2];\n} PS_MITIGATION_AUDIT_OPTIONS_MAP_V2, *PPS_MITIGATION_AUDIT_OPTIONS_MAP_V2;\n\n// private // since 20H1\ntypedef struct _PS_MITIGATION_AUDIT_OPTIONS_MAP_V3\n{\n    ULONG64 Map[3];\n} PS_MITIGATION_AUDIT_OPTIONS_MAP_V3, *PPS_MITIGATION_AUDIT_OPTIONS_MAP_V3,\n    PS_MITIGATION_AUDIT_OPTIONS_MAP, *PPS_MITIGATION_AUDIT_OPTIONS_MAP;\n\n// private // WIN8 to REDSTONE\n_Struct_size_bytes_(Size)\ntypedef struct _PS_SYSTEM_DLL_INIT_BLOCK_V1\n{\n    ULONG Size;\n    ULONG SystemDllWowRelocation;\n    ULONG64 SystemDllNativeRelocation;\n    ULONG Wow64SharedInformation[16]; // use WOW64_SHARED_INFORMATION as index\n    ULONG RngData;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG CfgOverride : 1; // since REDSTONE\n            ULONG Reserved : 31;\n        };\n    };\n    ULONG64 MitigationOptions;\n    ULONG64 CfgBitMap; // since WINBLUE\n    ULONG64 CfgBitMapSize;\n    ULONG64 Wow64CfgBitMap; // since THRESHOLD\n    ULONG64 Wow64CfgBitMapSize;\n} PS_SYSTEM_DLL_INIT_BLOCK_V1, *PPS_SYSTEM_DLL_INIT_BLOCK_V1;\n\n// RS2 - 19H2\n_Struct_size_bytes_(Size)\ntypedef struct _PS_SYSTEM_DLL_INIT_BLOCK_V2\n{\n    ULONG Size;\n    ULONG64 SystemDllWowRelocation;\n    ULONG64 SystemDllNativeRelocation;\n    ULONG64 Wow64SharedInformation[16]; // use WOW64_SHARED_INFORMATION as index\n    ULONG RngData;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG CfgOverride : 1;\n            ULONG Reserved : 31;\n        };\n    };\n    PS_MITIGATION_OPTIONS_MAP_V2 MitigationOptionsMap;\n    ULONG64 CfgBitMap;\n    ULONG64 CfgBitMapSize;\n    ULONG64 Wow64CfgBitMap;\n    ULONG64 Wow64CfgBitMapSize;\n    PS_MITIGATION_AUDIT_OPTIONS_MAP_V2 MitigationAuditOptionsMap; // since REDSTONE3\n} PS_SYSTEM_DLL_INIT_BLOCK_V2, *PPS_SYSTEM_DLL_INIT_BLOCK_V2;\n\n// private // since 20H1\n_Struct_size_bytes_(Size)\ntypedef struct _PS_SYSTEM_DLL_INIT_BLOCK_V3\n{\n    ULONG Size;\n    ULONG64 SystemDllWowRelocation; // effectively since WIN8\n    ULONG64 SystemDllNativeRelocation;\n    ULONG64 Wow64SharedInformation[16]; // use WOW64_SHARED_INFORMATION as index\n    ULONG RngData;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG CfgOverride : 1; // effectively since REDSTONE\n            ULONG Reserved : 31;\n        };\n    };\n    PS_MITIGATION_OPTIONS_MAP_V3 MitigationOptionsMap;\n    ULONG64 CfgBitMap; // effectively since WINBLUE\n    ULONG64 CfgBitMapSize;\n    ULONG64 Wow64CfgBitMap; // effectively since THRESHOLD\n    ULONG64 Wow64CfgBitMapSize;\n    PS_MITIGATION_AUDIT_OPTIONS_MAP_V3 MitigationAuditOptionsMap; // effectively since REDSTONE3\n    ULONG64 ScpCfgCheckFunction; // since 24H2\n    ULONG64 ScpCfgCheckESFunction;\n    ULONG64 ScpCfgDispatchFunction;\n    ULONG64 ScpCfgDispatchESFunction;\n    ULONG64 ScpArm64EcCallCheck;\n    ULONG64 ScpArm64EcCfgCheckFunction;\n    ULONG64 ScpArm64EcCfgCheckESFunction;\n} PS_SYSTEM_DLL_INIT_BLOCK_V3, *PPS_SYSTEM_DLL_INIT_BLOCK_V3,\n    PS_SYSTEM_DLL_INIT_BLOCK, *PPS_SYSTEM_DLL_INIT_BLOCK;\n\n// private\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\nNTSYSAPI PS_SYSTEM_DLL_INIT_BLOCK LdrSystemDllInitBlock;\n#endif\n\n// rev see also MEMORY_IMAGE_EXTENSION_INFORMATION\ntypedef struct _RTL_SCPCFG_NTDLL_EXPORTS\n{\n    PVOID ScpCfgHeader_Nop;\n    PVOID ScpCfgEnd_Nop;\n    PVOID ScpCfgHeader;\n    PVOID ScpCfgEnd;\n    PVOID ScpCfgHeader_ES;\n    PVOID ScpCfgEnd_ES;\n    PVOID ScpCfgHeader_Fptr;\n    PVOID ScpCfgEnd_Fptr;\n    PVOID LdrpGuardDispatchIcallNoESFptr;\n    PVOID __guard_dispatch_icall_fptr;\n    PVOID LdrpGuardCheckIcallNoESFptr;\n    PVOID __guard_check_icall_fptr;\n    PVOID LdrpHandleInvalidUserCallTarget;\n    struct\n    {\n        PVOID NtOpenFile;\n        PVOID NtCreateSection;\n        PVOID NtQueryAttributesFile;\n        PVOID NtOpenSection;\n        PVOID NtMapViewOfSection;\n    } LdrpCriticalLoaderFunctions;\n} RTL_SCPCFG_NTDLL_EXPORTS, *PRTL_SCPCFG_NTDLL_EXPORTS;\n\n// rev\n#if (PHNT_VERSION >= PHNT_WINDOWS_11_24H2)\nNTSYSAPI RTL_SCPCFG_NTDLL_EXPORTS RtlpScpCfgNtdllExports;\n#endif\n\n//\n// Load as data table\n//\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrAddLoadAsDataTable(\n    _In_ PVOID DllHandle,\n    _In_opt_ PCWSTR FilePath,\n    _In_ SIZE_T FileSize,\n    _In_ HANDLE FileHandle,\n    _In_opt_ PACTIVATION_CONTEXT ActCtx\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrRemoveLoadAsDataTable(\n    _In_ PVOID DllHandle,\n    _Out_ PVOID *BaseModule,\n    _Out_opt_ PSIZE_T FileSize,\n    _In_ ULONG Flags\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetFileNameFromLoadAsDataTable(\n    _In_ PVOID DllHandle,\n    _Out_ PWSTR *FileName\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrDisableThreadCalloutsForDll(\n    _In_ PVOID DllHandle\n    );\n\n//\n// Resources\n//\n\n// NtCurrentTeb()->ResourceRetValue\n// LdrFindResource* and LdrAccessResource\ntypedef struct _LDR_RESLOADER_RET\n{\n    PVOID Module;\n    PVOID DataEntry;\n    PVOID TargetModule;\n} LDR_RESLOADER_RET, *PLDR_RESLOADER_RET;\n\n/**\n * The LdrAccessResource function returns a pointer to the first byte of the specified resource in memory.\n *\n * \\param DllHandle A handle to the DLL.\n * \\param ResourceDataEntry The resource information block.\n * \\param ResourceBuffer The pointer to the specified resource in memory.\n * \\param ResourceLength The size, in bytes, of the specified resource.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadresource\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrAccessResource(\n    _In_ PVOID DllHandle,\n    _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,\n    _Out_opt_ PVOID *ResourceBuffer,\n    _Out_opt_ ULONG *ResourceLength\n    );\n\n/**\n * The LdrFindResource_U function determines the location of a resource in a DLL.\n *\n * \\param DllHandle A handle to the DLL.\n * \\param ResourcePath A pointer to an array of Type/Name/Language/(optional)AlternateType.\n * \\param Count The number of elements in the ResourcePath array.\n * \\param ResourceDataEntry The resource information block.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-findresourceexw\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrFindResource_U(\n    _In_ PVOID DllHandle,\n    _In_reads_(Count) PULONG_PTR ResourcePath,\n    _In_ ULONG Count,\n    _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry\n    );\n\n/**\n * The LdrFindResourceEx_U function determines the location of a resource in a DLL.\n *\n * \\param Flags A handle to the DLL.\n * \\param DllHandle A handle to the DLL.\n * \\param ResourcePath A pointer to an array of Type/Name/Language/(optional)AlternateType.\n * \\param Count The number of elements in the ResourcePath array.\n * \\param ResourceDataEntry The resource information block.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-findresourceexw\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrFindResourceEx_U(\n    _In_ ULONG Flags,\n    _In_ PVOID DllHandle,\n    _In_reads_(Count) PULONG_PTR ResourcePath,\n    _In_ ULONG Count,\n    _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrFindResourceDirectory_U(\n    _In_ PVOID DllHandle,\n    _In_reads_(Count) PULONG_PTR ResourcePath,\n    _In_ ULONG Count,\n    _Out_ PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n// rev // Flags for LdrResFindResource, LdrpResGetResourceDirectory, LdrResSearchResource\n#define LDR_RES_REQUIRE_FOUR_KEYS_A      0x00000001u  // Enables 4-key mode (variant A) (requires Count==4)\n#define LDR_RES_ALLOW_ANY                0x00000002u  // Permit Count < 3 (else Count must be 3 or 4)\n#define LDR_RES_OPTIMIZE_SMALL_A         0x00000008u  // Cannot combine with LDR_RES_OPTIMIZE_SMALL_B\n#define LDR_RES_OPTIMIZE_SMALL_B         0x00000010u  // Required when using LDR_RES_SPECIAL_DEPENDENCY with LDR_RES_MODE_D_SEARCH\n//#define LDR_RES_ALT_RETRY                0x00000030u\n#define LDR_RES_REQUIRE_FOUR_KEYS_B      0x00000040u  // Enables 4-key mode (Enable alternate module message) (requires Count==4)\n\n// Search mode flags (if not specified, LDR_RES_MODE_A_SEARCH is the default)\n#define LDR_RES_MODE_A_SEARCH            0x00000100u  // Default mode for typical resource lookup. // Exclusive with B/C/D // LdrResRelease\n#define LDR_RES_MODE_B_SEARCH            0x00000200u  // When the resource is loaded as a datafile // LDR_IS_DATAFILE(DllHandle) // Exclusive with A/C/D // LdrResRelease\n#define LDR_RES_MODE_C_SEARCH            0x00000400u  // When precise control over mapping size is needed. // Exclusive with A/B/D // LdrResRelease\n#define LDR_RES_MODE_D_SEARCH            0x00000800u  // When dependency resolution or alternate resources are needed. // Used with LDR_RES_SPECIAL_DEPENDENCY // Exclusive with A/B/C // LdrResRelease\n\n// Mapping behavior flags (only valid with LDR_RES_MODE_C or LDR_RES_MODE_D)\n#define LDR_RES_MAPPING_STRICT           0x00001000u  // Default; Fail if mapping size query fails // LdrResRelease\n#define LDR_RES_MAPPING_LENIENT          0x00002000u  // Allow fallback if mapping size query fails // LdrResRelease\n#define LDR_RES_MAPPING_ALT_RESOURCE     0x00004000u  // When the primary resource search fails, try load and search the alternate resource // LdrResRelease\n\n// Small/fast lookup optimizations (only valid with LDR_RES_MODE_A or LDR_RES_MODE_B)\n#define LDR_RES_SPECIAL_DEPENDENCY       0x00008000u  // Only valid with (LDR_RES_MODE_D_SEARCH | LDR_RES_OPTIMIZE_SMALL_B)\n\n#define LDR_RES_SIZE_FROM_LENGTH_C       0x00020000u  // Use *ResourceLength as mapping size; requires LDR_RES_MODE_C\n#define LDR_RES_SIZE_FROM_LENGTH_AB      0x00080000u  // Use *ResourceLength as mapping size; requires LDR_RES_MODE_A or LDR_RES_MODE_B\n\n// Internal-only (set by loader on alternate resource retry; callers must not set)\n#define LDR_RES_INTERNAL_ALT_RETRY       0x01000000u\n\n// Group masks\n#define LDR_RES_MODE_MASK                0x00000F00u  // LDR_RES_MODE_A|LDR_RES_MODE_B|LDR_RES_MODE_C|LDR_RES_MODE_D\n#define LDR_RES_BEHAVIOR_MASK            0x00003000u  // LDR_RES_MAPPING_STRICT/LDR_RES_MAPPING_LENIENT\n#define LDR_RES_SIZEOVERRIDE_MASK        0x000A0000u  // LDR_RES_SIZE_FROM_LENGTH_* (0x20000|0x80000)\n#define LDR_RES_KEY4_MASK                (LDR_RES_REQUIRE_FOUR_KEYS_A | LDR_RES_REQUIRE_FOUR_KEYS_B)\n\n// Public/caller-visible bit mask (high bits must be zero for callers)\n#define LDR_RES_PUBLIC_MASK              0x000FFFFFu\n\n// Common invalid combinations (useful for validation)\n#define LDR_RES_INVALID_SMALL_OPT_PAIR           0x00000018u  // LDR_RES_OPTIMIZE_SMALL_A|LDR_RES_OPTIMIZE_SMALL_B\n#define LDR_RES_INVALID_MAPPING_BEHAVIOR_PAIR    0x00003000u  // LDR_RES_MAPPING_STRICT|LDR_RES_MAPPING_LENIENT?\n\n// rev\n/**\n * The LdrResFindResource function finds a resource in a DLL.\n *\n * \\param DllHandle A handle to the DLL.\n * \\param Type The type of the resource. This parameter can also be MAKEINTRESOURCE(ID), where ID is the integer identifier of the resource.\n * \\param Name The name of the resource. This parameter can also be MAKEINTRESOURCE(ID), where ID is the integer identifier of the resource.\n * \\param Language The language of the resource. This parameter can also be MAKEINTRESOURCE(ID), where ID is the integer identifier of the resource.\n * \\param ResourceBuffer An optional pointer to receive the resource buffer.\n * \\param ResourceLength An optional pointer to receive the resource length.\n * \\param CultureName An optional buffer to receive the culture name.\n * \\param CultureNameLength An optional pointer to receive the length of the culture name.\n * \\param Flags Flags to modify the resource search.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrResFindResource(\n    _In_ PVOID DllHandle,\n    _In_ PCWSTR Type,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Language,\n    _Out_opt_ PVOID* ResourceBuffer,\n    _Out_opt_ PSIZE_T ResourceLength,\n    _Out_writes_bytes_opt_(CultureNameLength) PVOID CultureName, // WCHAR buffer[6]\n    _Out_opt_ PULONG CultureNameLength,\n    _In_opt_ ULONG Flags\n    );\n\n// rev\n/**\n * The LdrResFindResourceDirectory function finds the resource directory containing the specified resource.\n *\n * \\param DllHandle A handle to the DLL.\n * \\param Type The type of the resource. This parameter can also be MAKEINTRESOURCE(ID), where ID is the integer identifier of the resource.\n * \\param Name The name of the resource. This parameter can also be MAKEINTRESOURCE(ID), where ID is the integer identifier of the resource.\n * \\param ResourceDirectory An optional pointer to receive the resource directory.\n * \\param CultureName An optional buffer to receive the culture name.\n * \\param CultureNameLength An optional pointer to receive the length of the culture name.\n * \\param Flags Flags for the resource search.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrResFindResourceDirectory(\n    _In_ PVOID DllHandle,\n    _In_ PCWSTR Type,\n    _In_ PCWSTR Name,\n    _Out_opt_ PIMAGE_RESOURCE_DIRECTORY* ResourceDirectory,\n    _Out_writes_bytes_opt_(CultureNameLength) PVOID CultureName, // WCHAR buffer[6]\n    _Out_opt_ PULONG CultureNameLength,\n    _In_opt_ ULONG Flags\n    );\n\n// rev\n/**\n * The LdrpResGetResourceDirectory function returns the resource directory for a DLL.\n *\n * \\param DllHandle A handle to the DLL.\n * \\param Size The size of the image mapping.\n * \\param Flags Flags for the resource search.\n * \\param ResourceDirectory An optional pointer to receive the resource directory.\n * \\param OutHeaders The NT headers of the image.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrpResGetResourceDirectory(\n    _In_ PVOID DllHandle,\n    _In_ SIZE_T Size,\n    _In_ ULONG Flags,\n    _Out_opt_ PIMAGE_RESOURCE_DIRECTORY* ResourceDirectory,\n    _Out_ PIMAGE_NT_HEADERS* OutHeaders\n    );\n\n// rev\n/**\n * The LdrResSearchResource function searches for a resource in a DLL.\n *\n * \\param DllHandle A handle to the DLL.\n * \\param ResourcePath A pointer to an array of Type/Name/Language/(optional)AlternateType.\n * \\param ResourcePathCount The number of elements in the ResourcePath array.\n * \\param Flags Flags for the resource search.\n * \\param ResourceBuffer An optional pointer to receive the resource buffer.\n * \\param ResourceLength An optional pointer to receive the resource length.\n * \\param CultureName An optional buffer to receive the culture name.\n * \\param CultureNameLength An optional pointer to receive the length of the culture name.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrResSearchResource(\n    _In_ PVOID DllHandle,\n    _In_ PULONG_PTR ResourcePath,\n    _In_ ULONG ResourcePathCount,\n    _In_ ULONG Flags,\n    _Out_opt_ PVOID* ResourceBuffer,\n    _Out_opt_ PSIZE_T ResourceLength,\n    _Out_writes_bytes_opt_(*CultureNameLength) PWSTR CultureName, // WCHAR buffer[6]\n    _Out_opt_ PULONG CultureNameLength\n    );\n\n// rev\ntypedef struct _MUI_RC_CONFIG\n{\n    ULONG Signature;          // Magic signature 0xFEEDFACE (-20054323 signed)\n    ULONG Size;               // Total size of this structure\n    ULONG Version;            // Version (0x10000 = 1.0)\n    ULONG Flags1;             // Primary flags field (validated with & 0xFFFFFFF8)\n    ULONG Flags2;             // Secondary flags field (validated with & 0xFFFFFFCC)\n    ULONG ValidationField;    // Additional validation field\n    ULONG Flags3;             // Tertiary flags field (validated with & 0xFFFFFFFC)\n    ULONG Reserved1;          // Reserved field\n    ULONG Reserved2;          // Reserved field\n    ULONG Reserved3;          // Reserved field\n    ULONG Reserved4;          // Reserved field\n    ULONG Reserved5;          // Reserved field\n    ULONG Reserved6;          // Reserved field\n    ULONG Reserved7;          // Reserved field\n    ULONG Reserved8;          // Reserved field\n    ULONG Reserved9;          // Reserved field\n    ULONG Reserved10;         // Reserved field\n\n    // Data section offset/size pairs (validated for bounds checking)\n    ULONG Section1Offset;     // First data section offset\n    ULONG Section1Size;       // First data section size\n    ULONG Section2Offset;     // Second data section offset\n    ULONG Section2Size;       // Second data section size\n    ULONG Section3Offset;     // Third data section offset\n    ULONG Section3Size;       // Third data section size\n    ULONG Section4Offset;     // Fourth data section offset\n    ULONG Section4Size;       // Fourth data section size\n    ULONG Section5Offset;     // Fifth data section offset\n    ULONG Section5Size;       // Fifth data section size\n    ULONG Section6Offset;     // Sixth data section offset\n    ULONG Section6Size;       // Sixth data section size\n    ULONG Section7Offset;     // Seventh data section offset\n    ULONG Section7Size;       // Seventh data section size\n    ULONG Section8Offset;     // Eighth data section offset\n    ULONG Section8Size;       // Eighth data section size\n    // Variable length data follows...\n    // The actual data sections referenced by the offset/size pairs above\n} MUI_RC_CONFIG, *PMUI_RC_CONFIG;\n\n// Magic signature constant\n#define MUI_RC_CONFIG_SIGNATURE 0xFEEDFACE\n#define MUI_RC_CONFIG_VERSION_1_0 0x10000\n// Flag validation masks\n#define MUI_FLAGS1_VALID_MASK 0xFFFFFFF8  // Only lower 3 bits allowed\n#define MUI_FLAGS2_VALID_MASK 0xFFFFFFCC  // Specific bit pattern\n#define MUI_FLAGS3_VALID_MASK 0xFFFFFFFC  // Only lower 2 bits allowed\n\n/**\n * The LdrResGetRCConfig function retrieves the MUI configuration (resource type 3) for a DLL.\n *\n * \\param DllHandle A handle to the DLL.\n * \\param Length The length of the configuration buffer.\n * \\param Config A buffer to receive the configuration.\n * \\param Flags Flags for the operation.\n * \\param AlternateResource Indicates if an alternate resource should be loaded.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrResGetRCConfig(\n    _In_ PVOID DllHandle,\n    _In_opt_ SIZE_T Length,\n    _Out_writes_bytes_opt_(Length) PMUI_RC_CONFIG* Config,\n    _In_ ULONG Flags,\n    _In_ BOOLEAN AlternateResource // LdrLoadAlternateResourceModule\n    );\n\n/**\n * The LdrResRelease function releases the alternate resource module or section of an associated DLL.\n *\n * \\param DllHandle A handle to the DLL.\n * \\param CultureNameOrId An optional culture name or ID.\n * \\param Flags Flags for the operation.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrResRelease(\n    _In_ PVOID DllHandle,\n    _In_opt_ PCWSTR CultureNameOrId, // MAKEINTRESOURCE\n    _In_ ULONG Flags\n    );\n\n// rev\nNTSYSAPI\nVOID\nNTAPI\nLdrpResGetMappingSize(\n    _In_ PVOID BaseAddress,\n    _Out_ PSIZE_T Size,\n    _In_ ULONG Flags,\n    _In_ BOOLEAN GetFileSizeFromLoadAsDataTable\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n// private\ntypedef struct _LDR_ENUM_RESOURCE_ENTRY\n{\n    union\n    {\n        ULONG_PTR NameOrId;\n        PIMAGE_RESOURCE_DIRECTORY_STRING Name;\n        struct\n        {\n            USHORT Id;\n            USHORT NameIsPresent;\n        };\n    } Path[3];\n    PVOID Data;\n    ULONG Size;\n    ULONG Reserved;\n} LDR_ENUM_RESOURCE_ENTRY, *PLDR_ENUM_RESOURCE_ENTRY;\n\n#define NAME_FROM_RESOURCE_ENTRY(RootDirectory, Entry) \\\n    ((Entry)->NameIsString ? (ULONG_PTR)((ULONG_PTR)(RootDirectory) + (ULONG_PTR)((Entry)->NameOffset)) : (Entry)->Id)\n\nFORCEINLINE\nULONG_PTR\nNTAPI\nLdrNameOrIdFromResourceEntry(\n    _In_ PIMAGE_RESOURCE_DIRECTORY ResourceDirectory,\n    _In_ PIMAGE_RESOURCE_DIRECTORY_ENTRY Entry)\n{\n    if (Entry->NameIsString)\n        return (ULONG_PTR)((ULONG_PTR)ResourceDirectory + (ULONG_PTR)Entry->NameOffset);\n    else\n        return (ULONG_PTR)Entry->Id;\n}\n\n/**\n * The LdrEnumResources routine enumerates resources of a specified DLL module.\n *\n * \\param DllHandle Handle to the loaded DLL module whose resources are to be enumerated.\n * \\param ResourceId A pointer to an array of Type/Name/Language/(optional)AlternateType.\n * \\param Count Specifies the number of elements in the ResourceId array.\n * \\param ResourceCount On input, specifies the maximum number of resources to enumerate. On output, receives the actual number of resources enumerated.\n * \\param Resources Pointer to a buffer that receives an array of LDR_ENUM_RESOURCE_ENTRY structures describing the resources.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrEnumResources(\n    _In_ PVOID DllHandle,\n    _In_reads_(Count) PULONG_PTR ResourceId,\n    _In_ ULONG Count,\n    _Inout_ ULONG *ResourceCount,\n    _Out_writes_to_opt_(*ResourceCount, *ResourceCount) PLDR_ENUM_RESOURCE_ENTRY Resources\n    );\n\n/**\n * The LdrFindEntryForAddress routine retrieves the loader data table entry for a given address within a loaded module.\n *\n * \\param DllHandle A pointer to an address within the loaded module (such as the base address of the DLL or any address inside the module).\n * \\param Entry On success, receives a pointer to the LDR_DATA_TABLE_ENTRY structure corresponding to the module containing the specified address.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrFindEntryForAddress(\n    _In_ PVOID DllHandle,\n    _Out_ PLDR_DATA_TABLE_ENTRY *Entry\n    );\n\n// rev\n/**\n * The LdrLoadAlternateResourceModule routine returns a handle to the language-specific dynamic-link library (DLL)\n * resource module associated with a DLL that is already loaded for the calling process.\n *\n * \\param DllHandle A handle to the DLL module to search for a MUI resource. If the language-specific DLL for the MUI is available,\n * loads the specified module into the address space of the calling process and returns a handle to the module.\n * \\param BaseAddress The base address of the mapped view.\n * \\param Size The size of the mapped view.\n * \\param Flags Reserved\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrLoadAlternateResourceModule(\n    _In_ PVOID DllHandle,\n    _Out_ PVOID *BaseAddress,\n    _Out_opt_ SIZE_T *Size,\n    _In_ ULONG Flags\n    );\n\n// Flags for LdrLoadAlternateResourceModuleEx\n#define LDR_LOAD_ALT_RESOURCE_MUN_MODE 0x01000000u // Use .mun files instead of .mui files\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrLoadAlternateResourceModuleEx(\n    _In_ PVOID DllHandle,\n    _In_ LANGID LanguageId,\n    _Out_ PVOID *BaseAddress,\n    _Out_opt_ SIZE_T *Size,\n    _In_ ULONG Flags\n    );\n\n// rev\nNTSYSAPI\nBOOLEAN\nNTAPI\nLdrUnloadAlternateResourceModule(\n    _In_ PVOID DllHandle\n    );\n\n// rev\nNTSYSAPI\nBOOLEAN\nNTAPI\nLdrUnloadAlternateResourceModuleEx(\n    _In_ PVOID DllHandle,\n    _In_ ULONG Flags\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Module information\n//\n\ntypedef struct _RTL_PROCESS_MODULE_INFORMATION\n{\n    PVOID Section;\n    PVOID MappedBase;\n    PVOID ImageBase;\n    ULONG ImageSize;\n    ULONG Flags;\n    USHORT LoadOrderIndex;\n    USHORT InitOrderIndex;\n    USHORT LoadCount;\n    USHORT OffsetToFileName;\n    UCHAR FullPathName[256];\n} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;\n\ntypedef struct _RTL_PROCESS_MODULES\n{\n    ULONG NumberOfModules;\n    _Field_size_(NumberOfModules) RTL_PROCESS_MODULE_INFORMATION Modules[1];\n} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;\n\n// private\ntypedef struct _RTL_PROCESS_MODULE_INFORMATION_EX\n{\n    USHORT NextOffset;\n    union\n    {\n        RTL_PROCESS_MODULE_INFORMATION BaseInfo;\n        struct\n        {\n            PVOID Section;\n            PVOID MappedBase;\n            PVOID ImageBase;\n            ULONG ImageSize;\n            ULONG Flags;\n            USHORT LoadOrderIndex;\n            USHORT InitOrderIndex;\n            USHORT LoadCount;\n            USHORT OffsetToFileName;\n            UCHAR FullPathName[256];\n        };\n    };\n    ULONG ImageChecksum;\n    ULONG TimeDateStamp;\n    PVOID DefaultBase;\n} RTL_PROCESS_MODULE_INFORMATION_EX, *PRTL_PROCESS_MODULE_INFORMATION_EX;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrQueryProcessModuleInformation(\n    _In_opt_ PRTL_PROCESS_MODULES ModuleInformation,\n    _In_opt_ ULONG Size,\n    _Out_opt_ PULONG ReturnedSize\n    );\n\ntypedef _Function_class_(LDR_ENUM_CALLBACK)\nVOID NTAPI LDR_ENUM_CALLBACK(\n    _In_ PLDR_DATA_TABLE_ENTRY ModuleInformation,\n    _In_ PVOID Parameter,\n    _Out_ PBOOLEAN Stop\n    );\ntypedef LDR_ENUM_CALLBACK* PLDR_ENUM_CALLBACK;\n\ntypedef _Function_class_(LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION)\nVOID NTAPI LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION(\n    _In_ PCLDR_DATA_TABLE_ENTRY DataTableEntry,\n    _In_opt_ PVOID Context,\n    _Inout_ BOOLEAN *StopEnumeration\n    );\ntypedef LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION* PLDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION;\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrEnumerateLoadedModules(\n    _In_ BOOLEAN ReservedFlag,\n    _In_ PLDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION EnumProc,\n    _In_opt_ PVOID Context\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrOpenImageFileOptionsKey(\n    _In_ PCUNICODE_STRING SubKey,\n    _In_ BOOLEAN Wow64,\n    _Out_ PHANDLE NewKeyHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrQueryImageFileKeyOption(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName,\n    _In_ ULONG Type,\n    _Out_ PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _Out_opt_ PULONG ReturnedLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrQueryImageFileExecutionOptions(\n    _In_ PCUNICODE_STRING SubKey,\n    _In_ PCWSTR ValueName,\n    _In_ ULONG ValueSize,\n    _Out_ PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _Out_opt_ PULONG ReturnedLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrQueryImageFileExecutionOptionsEx(\n    _In_ PCUNICODE_STRING SubKey,\n    _In_ PCWSTR ValueName,\n    _In_ ULONG Type,\n    _Out_ PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _Out_opt_ PULONG ReturnedLength,\n    _In_ BOOLEAN Wow64\n    );\n\n// private\ntypedef struct _DELAYLOAD_PROC_DESCRIPTOR\n{\n    ULONG ImportDescribedByName;\n    union\n    {\n        PCSTR Name;\n        ULONG Ordinal;\n    } Description;\n} DELAYLOAD_PROC_DESCRIPTOR, *PDELAYLOAD_PROC_DESCRIPTOR;\n\n// private\ntypedef struct _DELAYLOAD_INFO\n{\n    ULONG Size;\n    PCIMAGE_DELAYLOAD_DESCRIPTOR DelayloadDescriptor;\n    PIMAGE_THUNK_DATA ThunkAddress;\n    PCSTR TargetDllName;\n    DELAYLOAD_PROC_DESCRIPTOR TargetApiDescriptor;\n    PVOID TargetModuleBase;\n    PVOID Unused;\n    ULONG LastError;\n} DELAYLOAD_INFO, *PDELAYLOAD_INFO;\n\n// private\ntypedef _Function_class_(DELAYLOAD_FAILURE_DLL_CALLBACK)\nPVOID NTAPI DELAYLOAD_FAILURE_DLL_CALLBACK(\n    _In_ ULONG NotificationReason,\n    _In_ PDELAYLOAD_INFO DelayloadInfo\n    );\ntypedef DELAYLOAD_FAILURE_DLL_CALLBACK* PDELAYLOAD_FAILURE_DLL_CALLBACK;\n\n// rev\ntypedef _Function_class_(DELAYLOAD_FAILURE_SYSTEM_ROUTINE)\nPVOID NTAPI DELAYLOAD_FAILURE_SYSTEM_ROUTINE(\n    _In_ PCSTR DllName,\n    _In_ PCSTR ProcedureName\n    );\ntypedef DELAYLOAD_FAILURE_SYSTEM_ROUTINE* PDELAYLOAD_FAILURE_SYSTEM_ROUTINE;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n// rev from QueryOptionalDelayLoadedAPI\n/**\n * The LdrQueryOptionalDelayLoadedAPI routine determines whether the specified function in a delay-loaded DLL is available on the system.\n *\n * \\param ParentModuleBase A handle to the calling module. (NtCurrentImageBase)\n * \\param DllName The file name of the delay-loaded DLL that exports the specified function. This parameter is case-insensitive.\n * \\param ProcedureName The address of a delay-load failure callback function for the specified DLL and process.\n * \\param Flags Reserved; must be 0.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi2/nf-libloaderapi2-queryoptionaldelayloadedapi\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrQueryOptionalDelayLoadedAPI(\n    _In_ PVOID ParentModuleBase,\n    _In_ PCSTR DllName,\n    _In_ PCSTR ProcedureName,\n    _Reserved_ ULONG Flags\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n// rev from ResolveDelayLoadedAPI\n/**\n * The LdrResolveDelayLoadedAPI routine locates the target function of the specified import and replaces the function pointer in the import thunk with the target of the function implementation.\n *\n * \\param ParentModuleBase The address of the base of the module importing a delay-loaded function. (NtCurrentImageBase)\n * \\param DelayloadDescriptor The address of the image delay import directory for the module to be loaded.\n * \\param FailureDllHook The address of a delay-load failure callback function for the specified DLL and process.\n * \\param FailureSystemHook The address of a delay-load failure callback function for the specified DLL and process.\n * \\param ThunkAddress The thunk data for the target function. Used to find the specific name table entry of the function.\n * \\param Flags Reserved; must be 0.\n * \\return The address of the import, or the failure stub for it.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/devnotes/resolvedelayloadedapi\n */\nNTSYSAPI\nPVOID\nNTAPI\nLdrResolveDelayLoadedAPI(\n    _In_ PVOID ParentModuleBase,\n    _In_ PCIMAGE_DELAYLOAD_DESCRIPTOR DelayloadDescriptor,\n    _In_opt_ PDELAYLOAD_FAILURE_DLL_CALLBACK FailureDllHook,\n    _In_opt_ PDELAYLOAD_FAILURE_SYSTEM_ROUTINE FailureSystemHook, // kernel32.DelayLoadFailureHook\n    _Out_ PIMAGE_THUNK_DATA ThunkAddress,\n    _Reserved_ ULONG Flags\n    );\n\n// rev from ResolveDelayLoadsFromDll\n/**\n * The LdrResolveDelayLoadsFromDll routine forwards the work in resolving delay-loaded imports from the parent binary to a target binary.\n *\n * \\param [in] ParentModuleBase The base address of the module that delay loads another binary.\n * \\param [in] TargetDllName The name of the target DLL.\n * \\param [in] Flags Reserved; must be 0.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/devnotes/resolvedelayloadsfromdll\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrResolveDelayLoadsFromDll(\n    _In_ PVOID ParentModuleBase,\n    _In_ PCSTR TargetDllName,\n    _Reserved_ ULONG Flags\n    );\n\n// rev from SetDefaultDllDirectories\n/**\n * The LdrSetDefaultDllDirectories routine specifies a default set of directories to search when the calling process loads a DLL.\n *\n * \\param [in] DirectoryFlags The directories to search.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-setdefaultdlldirectories\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrSetDefaultDllDirectories(\n    _In_ ULONG DirectoryFlags\n    );\n\n// rev from AddDllDirectory\n/**\n * The LdrAddDllDirectory routine adds a directory to the process DLL search path.\n *\n * \\param [in] NewDirectory An absolute path to the directory to add to the search path. For example, to add the directory Dir2 to the process DLL search path, specify \\Dir2.\n * \\param [out] Cookie An opaque pointer that can be passed to RemoveDllDirectory to remove the DLL from the process DLL search path.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrAddDllDirectory(\n    _In_ PCUNICODE_STRING NewDirectory,\n    _Out_ PDLL_DIRECTORY_COOKIE Cookie\n    );\n\n// rev from RemoveDllDirectory\n/**\n * The LdrRemoveDllDirectory routine removes a directory that was added to the process DLL search path by using LdrAddDllDirectory.\n *\n * \\param [in] Cookie The cookie returned by LdrAddDllDirectory when the directory was added to the search path.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-removedlldirectory\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrRemoveDllDirectory(\n    _In_ DLL_DIRECTORY_COOKIE Cookie\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n// rev\n/**\n * The LdrShutdownProcess routine forcefully terminates the calling program if it is invoked inside a loader callout. Otherwise, it has no effect.\n */\n_Analysis_noreturn_\nDECLSPEC_NORETURN\nNTSYSAPI\nVOID\nNTAPI\nLdrShutdownProcess(\n    VOID\n    );\n\n// rev\n/**\n * The LdrShutdownThread routine forcefully terminates the calling thread if it is invoked inside a loader callout. Otherwise, it has no effect.\n */\n_Analysis_noreturn_\nDECLSPEC_NORETURN\nNTSYSAPI\nVOID\nNTAPI\nLdrShutdownThread(\n    VOID\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8_1)\n// rev\n/**\n * The LdrSetImplicitPathOptions routine sets implicit path options.\n *\n * \\param [in] ImplicitPathOptions The implicit path options to set.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrSetImplicitPathOptions(\n    _In_ ULONG ImplicitPathOptions\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10RS3)\n// private\n/**\n * The LdrControlFlowGuardEnforced routine checks if Control Flow Guard is enforced.\n *\n * \\return TRUE if Control Flow Guard is enforced, FALSE otherwise.\n */\nNTSYSAPI\nULONG\nNTAPI\nLdrControlFlowGuardEnforced(\n    VOID\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_19H1)\n// rev\n/**\n * The LdrIsModuleSxsRedirected routine determines whether the specified module is SxS-redirected.\n *\n * \\param [in] DllHandle A handle to the DLL\n */\nNTSYSAPI\nBOOLEAN\nNTAPI\nLdrIsModuleSxsRedirected(\n    _In_ PVOID DllHandle\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n// rev\n/**\n * The LdrUpdatePackageSearchPath routine updates the package search path used by the loader.\n *\n * \\param [in] SearchPath The new search path.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrUpdatePackageSearchPath(\n    _In_ PCWSTR SearchPath\n    );\n#endif\n\n// rev\n#define ENCLAVE_STATE_CREATED         0x00000000ul // LdrpCreateSoftwareEnclave initial state\n#define ENCLAVE_STATE_INITIALIZED     0x00000001ul // ZwInitializeEnclave successful (LdrInitializeEnclave)\n#define ENCLAVE_STATE_INITIALIZED_VBS 0x00000002ul // only for ENCLAVE_TYPE_VBS (LdrInitializeEnclave)\n\n// rev\ntypedef struct _LDR_SOFTWARE_ENCLAVE\n{\n    LIST_ENTRY Links; // ntdll!LdrpEnclaveList\n    RTL_CRITICAL_SECTION CriticalSection;\n    ULONG EnclaveType; // ENCLAVE_TYPE_*\n    LONG ReferenceCount;\n    ULONG EnclaveState; // ENCLAVE_STATE_*\n    PVOID BaseAddress;\n    SIZE_T Size;\n    PVOID PreviousBaseAddress;\n    LIST_ENTRY Modules; // LDR_DATA_TABLE_ENTRY.InLoadOrderLinks\n    PLDR_DATA_TABLE_ENTRY PrimaryModule;\n    PLDR_DATA_TABLE_ENTRY BCryptModule;\n    PLDR_DATA_TABLE_ENTRY BCryptPrimitivesModule;\n} LDR_SOFTWARE_ENCLAVE, *PLDR_SOFTWARE_ENCLAVE;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n// rev from CreateEnclave\n/**\n * The LdrCreateEnclave routine creates a new uninitialized enclave. An enclave is an isolated region of code and data within the address space for an application. Only code that runs within the enclave can access data within the same enclave.\n *\n * \\param ProcessHandle A handle to the process for which you want to create an enclave.\n * \\param BaseAddress The preferred base address of the enclave. Specify NULL to have the operating system assign the base address.\n * \\param Reserved Reserved.\n * \\param Size The size of the enclave that you want to create, including the size of the code that you will load into the enclave, in bytes.\n * \\param InitialCommitment The amount of memory to commit for the enclave, in bytes. This parameter is not used for virtualization-based security (VBS) enclaves.\n * \\param EnclaveType The architecture type of the enclave that you want to create. To verify that an enclave type is supported, call IsEnclaveTypeSupported.\n * \\param EnclaveInformation A pointer to the architecture-specific information to use to create the enclave.\n * \\param EnclaveInformationLength The length of the structure that the EnclaveInformation parameter points to, in bytes.\n * For the ENCLAVE_TYPE_SGX and ENCLAVE_TYPE_SGX2 enclave types, this value must be 4096. For the ENCLAVE_TYPE_VBS enclave type, this value must be sizeof(ENCLAVE_CREATE_INFO_VBS), which is 36 bytes.\n * \\param EnclaveError An optional pointer to a variable that receives an enclave error code that is architecture-specific.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-createenclave\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrCreateEnclave(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID* BaseAddress,\n    _In_ ULONG Reserved,\n    _In_ SIZE_T Size,\n    _In_ SIZE_T InitialCommitment,\n    _In_ ULONG EnclaveType,\n    _In_reads_bytes_(EnclaveInformationLength) PVOID EnclaveInformation,\n    _In_ ULONG EnclaveInformationLength,\n    _Out_ PULONG EnclaveError\n    );\n\n// rev from InitializeEnclave\n/**\n * The LdrInitializeEnclave routine initializes an enclave that you created and loaded with data.\n *\n * \\param ProcessHandle A handle to the process for which the enclave was created.\n * \\param BaseAddress Any address within the enclave.\n * \\param EnclaveInformation A pointer to the architecture-specific information to use to initialize the enclave.\n * \\param EnclaveInformationLength The length of the structure that the EnclaveInformation parameter points to, in bytes.\n * For the ENCLAVE_TYPE_SGX and ENCLAVE_TYPE_SGX2 enclave types, this value must be 4096. For the ENCLAVE_TYPE_VBS enclave type, this value must be sizeof(ENCLAVE_CREATE_INFO_VBS), which is 36 bytes.\n * \\param EnclaveError An optional pointer to a variable that receives an enclave error code that is architecture-specific.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-initializeenclave\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrInitializeEnclave(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_reads_bytes_(EnclaveInformationLength) PVOID EnclaveInformation,\n    _In_ ULONG EnclaveInformationLength,\n    _Out_ PULONG EnclaveError\n    );\n\n// rev from DeleteEnclave\n/**\n * The LdrDeleteEnclave routine deletes the specified enclave.\n *\n * \\param BaseAddress The base address of the enclave that you want to delete.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-deleteenclave\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrDeleteEnclave(\n    _In_ PVOID BaseAddress\n    );\n\n// rev from CallEnclave\n/**\n * The LdrCallEnclave routine calls a function within an enclave. LdrCallEnclave can also be called within an enclave to call a function outside of the enclave.\n *\n * \\param Routine The address of the function that you want to call.\n * \\param Flags The flags to modify the call function.\n * \\param RoutineParamReturn The parameter than you want to pass to the function.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-callenclave\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrCallEnclave(\n    _In_ PENCLAVE_ROUTINE Routine,\n    _In_ ULONG Flags, // ENCLAVE_CALL_FLAG_*\n    _Inout_ PVOID* RoutineParamReturn\n    );\n\n// rev from LoadEnclaveImage\n/**\n * The LdrLoadEnclaveModule routine loads an image and all of its imports into an enclave.\n *\n * \\param BaseAddress The base address of the enclave in which the module will be loaded.\n * This address must correspond to an enclave previously created by using LdrCreateEnclave.\n * \\param DllPath A NULL-terminated string that contains the path of the image to load.\n * \\param DllName A NULL-terminated string that contains the name of the image to load.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-loadenclaveimagew\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrLoadEnclaveModule(\n    _In_ PVOID BaseAddress,\n    _In_opt_ PCWSTR DllPath,\n    _In_ PCUNICODE_STRING DllName\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n/**\n * The LdrFastFailInLoaderCallout routine forcefully terminates the calling program if it is invoked inside a loader callout. Otherwise, it has no effect.\n *\n * \\remarks This routine does not catch all potential deadlock cases; it is possible for a thread inside a loader callout\n * to acquire a lock while some thread outside a loader callout holds the same lock and makes a call into the loader.\n * In other words, there can be a lock order inversion between the loader lock and a client lock.\n * https://learn.microsoft.com/en-us/windows/win32/devnotes/ldrfastfailinloadercallout\n */\nNTSYSAPI\nVOID\nNTAPI\nLdrFastFailInLoaderCallout(\n    VOID\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nLdrFlushAlternateResourceModules(\n    VOID\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrDllRedirectionCallback(\n    _In_ ULONG Flags,\n    _In_ PCWSTR DllName,\n    _In_opt_ PCWSTR DllPath,\n    _Inout_opt_ PULONG DllCharacteristics,\n    _In_ PVOID CallbackData,\n    _Out_ PCWSTR *EffectiveDllPath\n    );\n\n// rev\nNTSYSAPI\nVOID\nNTAPI\nLdrSetDllManifestProber(\n    _In_ PVOID Routine\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\nNTSYSAPI BOOLEAN LdrpChildNtdll; // DATA export\n#endif\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrAppxHandleIntegrityFailure(\n    _In_ NTSTATUS Status\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// Note: Keep the static asserts below at the end of the file to ensure the structure is correct.\n\n#if defined(_WIN64)\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks) == 0x10, \"LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks) == 0x20, \"LDR_DATA_TABLE_ENTRY.InInitializationOrderLinks offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DllBase) == 0x30, \"LDR_DATA_TABLE_ENTRY.DllBase offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, EntryPoint) == 0x38, \"LDR_DATA_TABLE_ENTRY.EntryPoint offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, SizeOfImage) == 0x40, \"LDR_DATA_TABLE_ENTRY.SizeOfImage offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ObsoleteLoadCount) == 0x6c, \"LDR_DATA_TABLE_ENTRY.ObsoleteLoadCount offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, TimeDateStamp) == 0x80, \"LDR_DATA_TABLE_ENTRY.TimeDateStamp offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DdagNode) == 0x98, \"LDR_DATA_TABLE_ENTRY.DdagNode offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ParentDllBase) == 0xb8, \"LDR_DATA_TABLE_ENTRY.ParentDllBase offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, OriginalBase) == 0xf8, \"LDR_DATA_TABLE_ENTRY.OriginalBase offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, BaseNameHashValue) == 0x108, \"LDR_DATA_TABLE_ENTRY.BaseNameHashValue offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, LoadReason) == 0x10c, \"LDR_DATA_TABLE_ENTRY.LoadReason offset incorrect\");\nstatic_assert(sizeof(LDR_DATA_TABLE_ENTRY) == 0x138, \"LDR_DATA_TABLE_ENTRY incorrect size\");\n#else\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks) == 0x8, \"LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks) == 0x10, \"LDR_DATA_TABLE_ENTRY.InInitializationOrderLinks offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DllBase) == 0x18, \"LDR_DATA_TABLE_ENTRY.DllBase offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, EntryPoint) == 0x1c, \"LDR_DATA_TABLE_ENTRY.EntryPoint offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, SizeOfImage) == 0x20, \"LDR_DATA_TABLE_ENTRY.SizeOfImage offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ObsoleteLoadCount) == 0x38, \"LDR_DATA_TABLE_ENTRY.ObsoleteLoadCount offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, TimeDateStamp) == 0x44, \"LDR_DATA_TABLE_ENTRY.TimeDateStamp offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DdagNode) == 0x50, \"LDR_DATA_TABLE_ENTRY.DdagNode offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ParentDllBase) == 0x60, \"LDR_DATA_TABLE_ENTRY.ParentDllBase offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, OriginalBase) == 0x80, \"LDR_DATA_TABLE_ENTRY.OriginalBase offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, BaseNameHashValue) == 0x90, \"LDR_DATA_TABLE_ENTRY.BaseNameHashValue offset incorrect\");\nstatic_assert(UFIELD_OFFSET(LDR_DATA_TABLE_ENTRY, LoadReason) == 0x94, \"LDR_DATA_TABLE_ENTRY.LoadReason offset incorrect\");\nstatic_assert(sizeof(LDR_DATA_TABLE_ENTRY) == 0xB8, \"LDR_DATA_TABLE_ENTRY incorrect size\");\n#endif\n\n#endif // _NTLDR_H\n"
  },
  {
    "path": "phnt/include/ntlpcapi.h",
    "content": "/*\n * Local Inter-process Communication support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTLPCAPI_H\n#define _NTLPCAPI_H\n\n //\n // ALPC Object Specific Access Rights\n //\n\n#define PORT_CONNECT 0x0001\n#define PORT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1)\n\n//\n// ALPC information structures\n//\n\ntypedef struct _PORT_MESSAGE\n{\n    union\n    {\n        struct\n        {\n            CSHORT DataLength;\n            CSHORT TotalLength;\n        } s1;\n        ULONG Length;\n    } u1;\n    union\n    {\n        struct\n        {\n            CSHORT Type;\n            CSHORT DataInfoOffset;\n        } s2;\n        ULONG ZeroInit;\n    } u2;\n    union\n    {\n        CLIENT_ID ClientId;\n        double DoNotUseThisField;\n    };\n    ULONG MessageId;\n    union\n    {\n        SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages\n        ULONG CallbackId; // only valid for LPC_REQUEST messages\n    };\n} PORT_MESSAGE, *PPORT_MESSAGE;\n\ntypedef struct _PORT_DATA_ENTRY\n{\n    PVOID Base;\n    ULONG Size;\n} PORT_DATA_ENTRY, *PPORT_DATA_ENTRY;\n\ntypedef struct _PORT_DATA_INFORMATION\n{\n    ULONG CountDataEntries;\n    _Field_size_(CountDataEntries) PORT_DATA_ENTRY DataEntries[1];\n} PORT_DATA_INFORMATION, *PPORT_DATA_INFORMATION;\n\n#define LPC_REQUEST 1\n#define LPC_REPLY 2\n#define LPC_DATAGRAM 3\n#define LPC_LOST_REPLY 4\n#define LPC_PORT_CLOSED 5\n#define LPC_CLIENT_DIED 6\n#define LPC_EXCEPTION 7\n#define LPC_DEBUG_EVENT 8\n#define LPC_ERROR_EVENT 9\n#define LPC_CONNECTION_REQUEST 10\n\n#define LPC_CONTINUATION_REQUIRED       0x2000\n#define LPC_NO_IMPERSONATE              0x4000\n#define LPC_KERNELMODE_MESSAGE          0x8000\n\n#define ALPC_REQUEST                (LPC_CONTINUATION_REQUIRED | LPC_REQUEST)\n#define ALPC_REPLY                  (LPC_CONTINUATION_REQUIRED | LPC_REPLY)\n#define ALPC_DATAGRAM               (LPC_CONTINUATION_REQUIRED | LPC_DATAGRAM)\n#define ALPC_LOST_REPLY             (LPC_CONTINUATION_REQUIRED | LPC_LOST_REPLY)\n#define ALPC_PORT_CLOSED            (LPC_CONTINUATION_REQUIRED | LPC_PORT_CLOSED)\n#define ALPC_CLIENT_DIED            (LPC_CONTINUATION_REQUIRED | LPC_CLIENT_DIED)\n#define ALPC_EXCEPTION              (LPC_CONTINUATION_REQUIRED | LPC_EXCEPTION)\n#define ALPC_DEBUG_EVENT            (LPC_CONTINUATION_REQUIRED | LPC_DEBUG_EVENT)\n#define ALPC_ERROR_EVENT            (LPC_CONTINUATION_REQUIRED | LPC_ERROR_EVENT)\n#define ALPC_CONNECTION_REQUEST     (LPC_CONTINUATION_REQUIRED | LPC_CONNECTION_REQUEST)\n\n#define PORT_VALID_OBJECT_ATTRIBUTES OBJ_CASE_INSENSITIVE\n\n#ifdef _WIN64\n#define PORT_MAXIMUM_MESSAGE_LENGTH 512\n#else\n#define PORT_MAXIMUM_MESSAGE_LENGTH 256\n#endif\n\n#define LPC_MAX_CONNECTION_INFO_SIZE (16 * sizeof(ULONG_PTR))\n\n#define PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH \\\n    ((PORT_MAXIMUM_MESSAGE_LENGTH + sizeof(PORT_MESSAGE) + LPC_MAX_CONNECTION_INFO_SIZE + 0xf) & ~0xf)\n\ntypedef struct _LPC_CLIENT_DIED_MSG\n{\n    PORT_MESSAGE PortMsg;\n    LARGE_INTEGER CreateTime;\n} LPC_CLIENT_DIED_MSG, *PLPC_CLIENT_DIED_MSG;\n\ntypedef struct _PORT_VIEW\n{\n    ULONG Length;\n    HANDLE SectionHandle;\n    ULONG SectionOffset;\n    SIZE_T ViewSize;\n    PVOID ViewBase;\n    PVOID ViewRemoteBase;\n} PORT_VIEW, *PPORT_VIEW;\n\ntypedef struct _REMOTE_PORT_VIEW\n{\n    ULONG Length;\n    SIZE_T ViewSize;\n    PVOID ViewBase;\n} REMOTE_PORT_VIEW, *PREMOTE_PORT_VIEW;\n\n// WOW64 definitions\n\n// Except in a small number of special cases, WOW64 programs using the LPC APIs must use the 64-bit versions of the\n// PORT_MESSAGE, PORT_VIEW and REMOTE_PORT_VIEW data structures. Note that we take a different approach than the\n// official NT headers, which produce 64-bit versions in a 32-bit environment when USE_LPC6432 is defined.\n\ntypedef struct _PORT_MESSAGE64\n{\n    union\n    {\n        struct\n        {\n            CSHORT DataLength;\n            CSHORT TotalLength;\n        } s1;\n        ULONG Length;\n    } u1;\n    union\n    {\n        struct\n        {\n            CSHORT Type;\n            CSHORT DataInfoOffset;\n        } s2;\n        ULONG ZeroInit;\n    } u2;\n    union\n    {\n        CLIENT_ID64 ClientId;\n        double DoNotUseThisField;\n    };\n    ULONG MessageId;\n    union\n    {\n        ULONGLONG ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages\n        ULONG CallbackId; // only valid for LPC_REQUEST messages\n    };\n} PORT_MESSAGE64, *PPORT_MESSAGE64;\n\ntypedef struct _LPC_CLIENT_DIED_MSG64\n{\n    PORT_MESSAGE64 PortMsg;\n    LARGE_INTEGER CreateTime;\n} LPC_CLIENT_DIED_MSG64, *PLPC_CLIENT_DIED_MSG64;\n\ntypedef struct _PORT_VIEW64\n{\n    ULONG Length;\n    ULONGLONG SectionHandle;\n    ULONG SectionOffset;\n    ULONGLONG ViewSize;\n    ULONGLONG ViewBase;\n    ULONGLONG ViewRemoteBase;\n} PORT_VIEW64, *PPORT_VIEW64;\n\ntypedef struct _REMOTE_PORT_VIEW64\n{\n    ULONG Length;\n    ULONGLONG ViewSize;\n    ULONGLONG ViewBase;\n} REMOTE_PORT_VIEW64, *PREMOTE_PORT_VIEW64;\n\n//\n// Port creation\n//\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreatePort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG MaxConnectionInfoLength,\n    _In_ ULONG MaxMessageLength,\n    _In_opt_ ULONG MaxPoolUsage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateWaitablePort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG MaxConnectionInfoLength,\n    _In_ ULONG MaxMessageLength,\n    _In_opt_ ULONG MaxPoolUsage\n    );\n\n//\n// Port connection (client)\n//\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PCUNICODE_STRING PortName,\n    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos,\n    _Inout_opt_ PPORT_VIEW ClientView,\n    _Inout_opt_ PREMOTE_PORT_VIEW ServerView,\n    _Out_opt_ PULONG MaxMessageLength,\n    _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation,\n    _Inout_opt_ PULONG ConnectionInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSecureConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PCUNICODE_STRING PortName,\n    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos,\n    _Inout_opt_ PPORT_VIEW ClientView,\n    _In_opt_ PSID RequiredServerSid,\n    _Inout_opt_ PREMOTE_PORT_VIEW ServerView,\n    _Out_opt_ PULONG MaxMessageLength,\n    _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation,\n    _Inout_opt_ PULONG ConnectionInformationLength\n    );\n\n//\n// Port connection (server)\n//\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtListenPort(\n    _In_ HANDLE PortHandle,\n    _Out_ PPORT_MESSAGE ConnectionRequest\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAcceptConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ PVOID PortContext,\n    _In_ PPORT_MESSAGE ConnectionRequest,\n    _In_ BOOLEAN AcceptConnection,\n    _Inout_opt_ PPORT_VIEW ServerView,\n    _Out_opt_ PREMOTE_PORT_VIEW ClientView\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCompleteConnectPort(\n    _In_ HANDLE PortHandle\n    );\n\n//\n// General\n//\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRequestPort(\n    _In_ HANDLE PortHandle,\n    _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRequestWaitReplyPort(\n    _In_ HANDLE PortHandle,\n    _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage,\n    _Out_ PPORT_MESSAGE ReplyMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplyPort(\n    _In_ HANDLE PortHandle,\n    _In_reads_bytes_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplyWaitReplyPort(\n    _In_ HANDLE PortHandle,\n    _Inout_ PPORT_MESSAGE ReplyMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplyWaitReceivePort(\n    _In_ HANDLE PortHandle,\n    _Out_opt_ PVOID *PortContext,\n    _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage,\n    _Out_ PPORT_MESSAGE ReceiveMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplyWaitReceivePortEx(\n    _In_ HANDLE PortHandle,\n    _Out_opt_ PVOID *PortContext,\n    _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage,\n    _Out_ PPORT_MESSAGE ReceiveMessage,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtImpersonateClientOfPort(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadRequestData(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ ULONG DataEntryIndex,\n    _Out_writes_bytes_to_(BufferSize, *NumberOfBytesRead) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWriteRequestData(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ ULONG DataEntryIndex,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesWritten\n    );\n\ntypedef enum _PORT_INFORMATION_CLASS\n{\n    PortBasicInformation,\n    PortDumpInformation\n} PORT_INFORMATION_CLASS;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationPort(\n    _In_ HANDLE PortHandle,\n    _In_ PORT_INFORMATION_CLASS PortInformationClass,\n    _Out_writes_bytes_to_(Length, *ReturnLength) PVOID PortInformation,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n//\n// Asynchronous Local Inter-process Communication\n//\n\n// rev\ntypedef HANDLE ALPC_HANDLE, *PALPC_HANDLE;\n\n#define ALPC_PORFLG_NONE                           0x0\n#define ALPC_PORFLG_LPC_MODE                       0x1000 // kernel only\n#define ALPC_PORFLG_ALLOW_IMPERSONATION            0x10000\n#define ALPC_PORFLG_ALLOW_LPC_REQUESTS             0x20000 // rev\n#define ALPC_PORFLG_WAITABLE_PORT                  0x40000 // dbg\n#define ALPC_PORFLG_ALLOW_DUP_OBJECT               0x80000\n#define ALPC_PORFLG_SYSTEM_PROCESS                 0x100000 // dbg\n#define ALPC_PORFLG_WAKE_POLICY1                   0x200000\n#define ALPC_PORFLG_WAKE_POLICY2                   0x400000\n#define ALPC_PORFLG_WAKE_POLICY3                   0x800000\n#define ALPC_PORFLG_DIRECT_MESSAGE                 0x1000000\n#define ALPC_PORFLG_ALLOW_MULTIHANDLE_ATTRIBUTE    0x2000000\n\n#define ALPC_PORFLG_OBJECT_TYPE_FILE 0x0001\n#define ALPC_PORFLG_OBJECT_TYPE_INVALID 0x0002\n#define ALPC_PORFLG_OBJECT_TYPE_THREAD 0x0004\n#define ALPC_PORFLG_OBJECT_TYPE_SEMAPHORE 0x0008\n#define ALPC_PORFLG_OBJECT_TYPE_EVENT 0x0010\n#define ALPC_PORFLG_OBJECT_TYPE_PROCESS 0X0020\n#define ALPC_PORFLG_OBJECT_TYPE_MUTEX 0x0040\n#define ALPC_PORFLG_OBJECT_TYPE_SECTION 0x0080\n#define ALPC_PORFLG_OBJECT_TYPE_REGKEY 0x0100\n#define ALPC_PORFLG_OBJECT_TYPE_TOKEN 0x0200\n#define ALPC_PORFLG_OBJECT_TYPE_COMPOSITION 0x0400\n#define ALPC_PORFLG_OBJECT_TYPE_JOB 0x0800\n#define ALPC_PORFLG_OBJECT_TYPE_ALL \\\n    (ALPC_PORFLG_OBJECT_TYPE_FILE | ALPC_PORFLG_OBJECT_TYPE_THREAD | \\\n     ALPC_PORFLG_OBJECT_TYPE_SEMAPHORE | ALPC_PORFLG_OBJECT_TYPE_EVENT | \\\n     ALPC_PORFLG_OBJECT_TYPE_PROCESS | ALPC_PORFLG_OBJECT_TYPE_MUTEX | \\\n     ALPC_PORFLG_OBJECT_TYPE_SECTION | ALPC_PORFLG_OBJECT_TYPE_REGKEY | \\\n     ALPC_PORFLG_OBJECT_TYPE_TOKEN | ALPC_PORFLG_OBJECT_TYPE_COMPOSITION | \\\n     ALPC_PORFLG_OBJECT_TYPE_JOB)\n\n// symbols\ntypedef struct _ALPC_PORT_ATTRIBUTES\n{\n    ULONG Flags;\n    SECURITY_QUALITY_OF_SERVICE SecurityQos;\n    SIZE_T MaxMessageLength;\n    SIZE_T MemoryBandwidth;\n    SIZE_T MaxPoolUsage;\n    SIZE_T MaxSectionSize;\n    SIZE_T MaxViewSize;\n    SIZE_T MaxTotalSectionSize;\n    ULONG DupObjectTypes;\n#ifdef _WIN64\n    ULONG Reserved;\n#endif\n} ALPC_PORT_ATTRIBUTES, *PALPC_PORT_ATTRIBUTES;\n\n// begin_rev\n#define ALPC_MESSAGE_HANDLE_ATTRIBUTE 0x10000000\n#define ALPC_MESSAGE_CONTEXT_ATTRIBUTE 0x20000000\n#define ALPC_MESSAGE_VIEW_ATTRIBUTE 0x40000000\n#define ALPC_MESSAGE_SECURITY_ATTRIBUTE 0x80000000\n\n// Convenience macro for all message attributes\n#define ALPC_MESSAGE_ATTRIBUTES_ALL \\\n    (ALPC_MESSAGE_HANDLE_ATTRIBUTE | \\\n     ALPC_MESSAGE_CONTEXT_ATTRIBUTE | \\\n     ALPC_MESSAGE_VIEW_ATTRIBUTE | \\\n     ALPC_MESSAGE_SECURITY_ATTRIBUTE)\n// end_rev\n\n// symbols\ntypedef struct _ALPC_MESSAGE_ATTRIBUTES\n{\n    ULONG AllocatedAttributes;\n    ULONG ValidAttributes;\n} ALPC_MESSAGE_ATTRIBUTES, *PALPC_MESSAGE_ATTRIBUTES;\n\n// symbols\ntypedef struct _ALPC_COMPLETION_LIST_STATE\n{\n    union\n    {\n        struct\n        {\n            ULONG64 Head : 24;\n            ULONG64 Tail : 24;\n            ULONG64 ActiveThreadCount : 16;\n        } s1;\n        ULONG64 Value;\n    } u1;\n} ALPC_COMPLETION_LIST_STATE, *PALPC_COMPLETION_LIST_STATE;\n\n#define ALPC_COMPLETION_LIST_BUFFER_GRANULARITY_MASK 0x3f // dbg\n\n// symbols\ntypedef struct DECLSPEC_ALIGN(128) _ALPC_COMPLETION_LIST_HEADER\n{\n    ULONG64 StartMagic;\n\n    ULONG TotalSize;\n    ULONG ListOffset;\n    ULONG ListSize;\n    ULONG BitmapOffset;\n    ULONG BitmapSize;\n    ULONG DataOffset;\n    ULONG DataSize;\n    ULONG AttributeFlags;\n    ULONG AttributeSize;\n\n    DECLSPEC_ALIGN(128) ALPC_COMPLETION_LIST_STATE State;\n    ULONG LastMessageId;\n    ULONG LastCallbackId;\n    DECLSPEC_ALIGN(128) ULONG PostCount;\n    DECLSPEC_ALIGN(128) ULONG ReturnCount;\n    DECLSPEC_ALIGN(128) ULONG LogSequenceNumber;\n    DECLSPEC_ALIGN(128) RTL_SRWLOCK UserLock;\n\n    ULONG64 EndMagic;\n} ALPC_COMPLETION_LIST_HEADER, *PALPC_COMPLETION_LIST_HEADER;\n\n// private\ntypedef struct _ALPC_CONTEXT_ATTR\n{\n    PVOID PortContext;\n    PVOID MessageContext;\n    ULONG Sequence;\n    ULONG MessageId;\n    ULONG CallbackId;\n} ALPC_CONTEXT_ATTR, *PALPC_CONTEXT_ATTR;\n\n// begin_rev\n#define ALPC_HANDLEFLG_DUPLICATE_SAME_ACCESS 0x10000\n#define ALPC_HANDLEFLG_DUPLICATE_SAME_ATTRIBUTES 0x20000\n#define ALPC_HANDLEFLG_DUPLICATE_INHERIT 0x80000\n// end_rev\n\n// private\ntypedef struct _ALPC_HANDLE_ATTR32\n{\n    ULONG Flags;\n    ULONG Reserved0;\n    ULONG SameAccess;\n    ULONG SameAttributes;\n    ULONG Indirect;\n    ULONG Inherit;\n    ULONG Reserved1;\n    ULONG Handle;\n    ULONG ObjectType; // ObjectTypeCode, not ObjectTypeIndex\n    ACCESS_MASK DesiredAccess;\n    ACCESS_MASK GrantedAccess;\n} ALPC_HANDLE_ATTR32, *PALPC_HANDLE_ATTR32;\n\n// private\ntypedef struct _ALPC_HANDLE_ATTR\n{\n    ULONG Flags;\n    ULONG Reserved0;\n    ULONG SameAccess;\n    ULONG SameAttributes;\n    ULONG Indirect;\n    ULONG Inherit;\n    ULONG Reserved1;\n    HANDLE Handle;\n    PALPC_HANDLE_ATTR32 HandleAttrArray;\n    ULONG ObjectType; // ObjectTypeCode, not ObjectTypeIndex\n    ULONG HandleCount;\n    ACCESS_MASK DesiredAccess;\n    ACCESS_MASK GrantedAccess;\n} ALPC_HANDLE_ATTR, *PALPC_HANDLE_ATTR;\n\n#define ALPC_SECFLG_CREATE_HANDLE 0x20000 // dbg\n#define ALPC_SECFLG_NOSECTIONHANDLE 0x40000\n\n// private\ntypedef struct _ALPC_SECURITY_ATTR\n{\n    ULONG Flags;\n    PSECURITY_QUALITY_OF_SERVICE QoS;\n    ALPC_HANDLE ContextHandle; // dbg\n} ALPC_SECURITY_ATTR, *PALPC_SECURITY_ATTR;\n\n// begin_rev\n#define ALPC_VIEWFLG_UNMAP_EXISTING     0x10000\n#define ALPC_VIEWFLG_AUTO_RELEASE       0x20000\n#define ALPC_VIEWFLG_NOT_SECURE         0x40000\n// end_rev\n\n// private\ntypedef struct _ALPC_DATA_VIEW_ATTR\n{\n    ULONG Flags;\n    ALPC_HANDLE SectionHandle;\n    PVOID ViewBase; // must be zero on input\n    SIZE_T ViewSize;\n} ALPC_DATA_VIEW_ATTR, *PALPC_DATA_VIEW_ATTR;\n\n// private\ntypedef enum _ALPC_PORT_INFORMATION_CLASS\n{\n    AlpcBasicInformation, // q: out ALPC_BASIC_INFORMATION\n    AlpcPortInformation, // s: in ALPC_PORT_ATTRIBUTES\n    AlpcAssociateCompletionPortInformation, // s: in ALPC_PORT_ASSOCIATE_COMPLETION_PORT\n    AlpcConnectedSIDInformation, // q: in SID\n    AlpcServerInformation, // q: inout ALPC_SERVER_INFORMATION\n    AlpcMessageZoneInformation, // s: in ALPC_PORT_MESSAGE_ZONE_INFORMATION\n    AlpcRegisterCompletionListInformation, // s: in ALPC_PORT_COMPLETION_LIST_INFORMATION\n    AlpcUnregisterCompletionListInformation, // s: VOID\n    AlpcAdjustCompletionListConcurrencyCountInformation, // s: in ULONG\n    AlpcRegisterCallbackInformation, // s: ALPC_REGISTER_CALLBACK // kernel-mode only\n    AlpcCompletionListRundownInformation, // s: VOID // 10\n    AlpcWaitForPortReferences,\n    AlpcServerSessionInformation // q: ALPC_SERVER_SESSION_INFORMATION // since 19H2\n} ALPC_PORT_INFORMATION_CLASS;\n\n// private\ntypedef struct _ALPC_BASIC_INFORMATION\n{\n    ULONG Flags;\n    ULONG SequenceNo;\n    PVOID PortContext;\n} ALPC_BASIC_INFORMATION, *PALPC_BASIC_INFORMATION;\n\n// private\ntypedef struct _ALPC_PORT_ASSOCIATE_COMPLETION_PORT\n{\n    PVOID CompletionKey;\n    HANDLE CompletionPort;\n} ALPC_PORT_ASSOCIATE_COMPLETION_PORT, *PALPC_PORT_ASSOCIATE_COMPLETION_PORT;\n\n// private\ntypedef struct _ALPC_SERVER_INFORMATION\n{\n    union\n    {\n        struct\n        {\n            HANDLE ThreadHandle;\n        } In;\n        struct\n        {\n            BOOLEAN ThreadBlocked;\n            HANDLE ConnectedProcessId;\n            UNICODE_STRING ConnectionPortName;\n        } Out;\n    };\n} ALPC_SERVER_INFORMATION, *PALPC_SERVER_INFORMATION;\n\n// private\ntypedef struct _ALPC_PORT_MESSAGE_ZONE_INFORMATION\n{\n    PVOID Buffer;\n    ULONG Size;\n} ALPC_PORT_MESSAGE_ZONE_INFORMATION, *PALPC_PORT_MESSAGE_ZONE_INFORMATION;\n\n// private\ntypedef struct _ALPC_PORT_COMPLETION_LIST_INFORMATION\n{\n    PVOID Buffer; // PALPC_COMPLETION_LIST_HEADER\n    ULONG Size;\n    ULONG ConcurrencyCount;\n    ULONG AttributeFlags;\n} ALPC_PORT_COMPLETION_LIST_INFORMATION, *PALPC_PORT_COMPLETION_LIST_INFORMATION;\n\n// private\ntypedef struct _ALPC_REGISTER_CALLBACK\n{\n    PVOID CallbackObject; // PCALLBACK_OBJECT\n    PVOID CallbackContext;\n} ALPC_REGISTER_CALLBACK, *PALPC_REGISTER_CALLBACK;\n\n// private\ntypedef struct _ALPC_SERVER_SESSION_INFORMATION\n{\n    ULONG SessionId;\n    ULONG ProcessId;\n} ALPC_SERVER_SESSION_INFORMATION, *PALPC_SERVER_SESSION_INFORMATION;\n\n// private\ntypedef enum _ALPC_MESSAGE_INFORMATION_CLASS\n{\n    AlpcMessageSidInformation, // q: out SID\n    AlpcMessageTokenModifiedIdInformation,  // q: out LUID\n    AlpcMessageDirectStatusInformation,\n    AlpcMessageHandleInformation, // ALPC_MESSAGE_HANDLE_INFORMATION\n    MaxAlpcMessageInfoClass\n} ALPC_MESSAGE_INFORMATION_CLASS, *PALPC_MESSAGE_INFORMATION_CLASS;\n\ntypedef struct _ALPC_MESSAGE_HANDLE_INFORMATION\n{\n    ULONG Index;\n    ULONG Flags;\n    ULONG Handle;\n    ULONG ObjectType;\n    ACCESS_MASK GrantedAccess;\n} ALPC_MESSAGE_HANDLE_INFORMATION, *PALPC_MESSAGE_HANDLE_INFORMATION;\n\n// begin_private\n\n//\n// System calls\n//\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreatePort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDisconnectPort(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcQueryInformation(\n    _In_opt_ HANDLE PortHandle,\n    _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass,\n    _Inout_updates_bytes_to_(Length, *ReturnLength) PVOID PortInformation,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcSetInformation(\n    _In_ HANDLE PortHandle,\n    _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass,\n    _In_reads_bytes_opt_(Length) PVOID PortInformation,\n    _In_ ULONG Length\n    );\n\n#define ALPC_CREATEPORTSECTIONFLG_SECURE 0x40000 // rev\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreatePortSection(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE SectionHandle,\n    _In_ SIZE_T SectionSize,\n    _Out_ PALPC_HANDLE AlpcSectionHandle,\n    _Out_ PSIZE_T ActualSectionSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDeletePortSection(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE SectionHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreateResourceReserve(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ SIZE_T MessageSize,\n    _Out_ PULONG ResourceId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDeleteResourceReserve(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ULONG ResourceId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreateSectionView(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _Inout_ PALPC_DATA_VIEW_ATTR ViewAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDeleteSectionView(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ PVOID ViewBase\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreateSecurityContext(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _Inout_ PALPC_SECURITY_ATTR SecurityAttribute\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDeleteSecurityContext(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE ContextHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcRevokeSecurityContext(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE ContextHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcQueryInformationMessage(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE PortMessage,\n    _In_ ALPC_MESSAGE_INFORMATION_CLASS MessageInformationClass,\n    _Out_writes_bytes_to_opt_(Length, *ReturnLength) PVOID MessageInformation,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#define ALPC_MSGFLG_REPLY_MESSAGE 0x1\n#define ALPC_MSGFLG_LPC_MODE 0x2\n#define ALPC_MSGFLG_RELEASE_MESSAGE 0x10000 // dbg\n#define ALPC_MSGFLG_SYNC_REQUEST 0x20000 // dbg\n#define ALPC_MSGFLG_TRACK_PORT_REFERENCES 0x40000\n#define ALPC_MSGFLG_WAIT_USER_MODE 0x100000\n#define ALPC_MSGFLG_WAIT_ALERTABLE 0x200000\n#define ALPC_MSGFLG_WOW64_CALL 0x80000000 // dbg\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PCUNICODE_STRING PortName,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_ ULONG Flags,\n    _In_opt_ PSID RequiredServerSid,\n    _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage,\n    _Inout_opt_ PSIZE_T BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcConnectPortEx(\n    _Out_ PHANDLE PortHandle,\n    _In_ POBJECT_ATTRIBUTES ConnectionPortObjectAttributes,\n    _In_opt_ POBJECT_ATTRIBUTES ClientPortObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_ ULONG Flags,\n    _In_opt_ PSECURITY_DESCRIPTOR ServerSecurityRequirements,\n    _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage,\n    _Inout_opt_ PSIZE_T BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcAcceptConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ HANDLE ConnectionPortHandle,\n    _In_ ULONG Flags,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_opt_ PVOID PortContext,\n    _In_reads_bytes_(ConnectionRequest->u1.s1.TotalLength) PPORT_MESSAGE ConnectionRequest,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ConnectionMessageAttributes,\n    _In_ BOOLEAN AcceptConnection\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcSendWaitReceivePort(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags,\n    _In_reads_bytes_opt_(SendMessage->u1.s1.TotalLength) PPORT_MESSAGE SendMessage,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,\n    _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ReceiveMessage,\n    _Inout_opt_ PSIZE_T BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#define ALPC_CANCELFLG_TRY_CANCEL 0x1 // dbg\n#define ALPC_CANCELFLG_NO_CONTEXT_CHECK 0x8\n#define ALPC_CANCELFLGP_FLUSH 0x10000 // dbg\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCancelMessage(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags,\n    _In_ PALPC_CONTEXT_ATTR MessageContext\n    );\n\n#define ALPC_IMPERSONATEFLG_ANONYMOUS 0x1\n#define ALPC_IMPERSONATEFLG_REQUIRE_IMPERSONATE 0x2\n//ALPC_IMPERSONATEFLG 0x3-0x10 (SECURITY_IMPERSONATION_LEVEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcImpersonateClientOfPort(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ PVOID Flags\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcImpersonateClientContainerOfPort(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _Reserved_ ULONG Flags\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcOpenSenderProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE PortMessage,\n    _Reserved_ ULONG Flags,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcOpenSenderThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE PortMessage,\n    _Reserved_ ULONG Flags,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n//\n// Support functions\n//\n\nNTSYSAPI\nULONG\nNTAPI\nAlpcMaxAllowedMessageLength(\n    VOID\n    );\n\n// ALPC message attribute flags (internal state)\n#define ALPC_ATTRFLG_ALLOCATEDATTR   0x20000000  // Attribute buffer was allocated\n#define ALPC_ATTRFLG_VALIDATTR       0x40000000  // Attribute buffer is valid\n#define ALPC_ATTRFLG_KEEPRUNNINGATTR 0x60000000  // Keep running attribute\n\nNTSYSAPI\nULONG\nNTAPI\nAlpcGetHeaderSize(\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcInitializeMessageAttribute(\n    _In_ ULONG AttributeFlags,\n    _Out_opt_ PALPC_MESSAGE_ATTRIBUTES Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_ PSIZE_T RequiredBufferSize\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nAlpcGetMessageAttribute(\n    _In_ PALPC_MESSAGE_ATTRIBUTES Buffer,\n    _In_ ULONG AttributeFlag\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcRegisterCompletionList(\n    _In_ HANDLE PortHandle,\n    _Out_ PALPC_COMPLETION_LIST_HEADER Buffer,\n    _In_ ULONG Size,\n    _In_ ULONG ConcurrencyCount,\n    _In_ ULONG AttributeFlags\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcUnregisterCompletionList(\n    _In_ HANDLE PortHandle\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcRundownCompletionList(\n    _In_ HANDLE PortHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcAdjustCompletionListConcurrencyCount(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG ConcurrencyCount\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nAlpcRegisterCompletionListWorkerThread(\n    _Inout_ PVOID CompletionList\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nAlpcUnregisterCompletionListWorkerThread(\n    _Inout_ PVOID CompletionList\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nAlpcGetCompletionListLastMessageInformation(\n    _In_ PVOID CompletionList,\n    _Out_ PULONG LastMessageId,\n    _Out_ PULONG LastCallbackId\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nAlpcGetOutstandingCompletionListMessageCount(\n    _In_ PVOID CompletionList\n    );\n\nNTSYSAPI\nPPORT_MESSAGE\nNTAPI\nAlpcGetMessageFromCompletionList(\n    _In_ PVOID CompletionList,\n    _Out_opt_ PALPC_MESSAGE_ATTRIBUTES *MessageAttributes\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nAlpcFreeCompletionListMessage(\n    _Inout_ PVOID CompletionList,\n    _In_ PPORT_MESSAGE Message\n    );\n\nNTSYSAPI\nPALPC_MESSAGE_ATTRIBUTES\nNTAPI\nAlpcGetCompletionListMessageAttributes(\n    _In_ PVOID CompletionList,\n    _In_ PPORT_MESSAGE Message\n    );\n\n// end_private\n\n#endif\n"
  },
  {
    "path": "phnt/include/ntmisc.h",
    "content": "/*\n * Trace Control support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTMISC_H\n#define _NTMISC_H\n\n//\n// Apphelp\n//\n\n_Enum_is_bitflag_\ntypedef enum _AHC_INFO_CLASS\n{\n    AhcInfoClassSdbQueryResult          = 0x00000001,\n    AhcInfoClassSdbSxsOverrideManifest  = 0x00000002,\n    AhcInfoClassSdbRunlevelFlags        = 0x00000004,\n    AhcInfoClassSdbFusionFlags          = 0x00000008,\n    AhcInfoClassSdbInstallerFlags       = 0x00000010,\n    AhcInfoClassFusionFlags             = 0x00000020,\n    AhcInfoClassTelemetryFlags          = 0x00000040,\n    AhcInfoClassInstallDetect           = 0x00000080,\n    AhcInfoClassRacEventSent            = 0x00000100,\n    AhcInfoClassIsSystemFile            = 0x00000200,\n    AhcInfoClassMonitoringFlags         = 0x00000400,\n    AhcInfoClassExeType                 = 0x00000800,\n} AHC_INFO_CLASS, *PAHC_INFO_CLASS;\n\n#define AHC_INFO_CLASS_FILTER_ON_FILETIME_CHANGE            \\\n    (AHC_INFO_CLASS)(AhcInfoClassSdbQueryResult |           \\\n                     AhcInfoClassSdbSxsOverrideManifest |   \\\n                     AhcInfoClassSdbRunlevelFlags |         \\\n                     AhcInfoClassSdbFusionFlags |           \\\n                     AhcInfoClassSdbInstallerFlags |        \\\n                     AhcInfoClassFusionFlags |              \\\n                     AhcInfoClassRacEventSent)\n\n#define AHC_INFO_CLASS_FILTER_ON_SDB_CHANGE                 \\\n    (AHC_INFO_CLASS)(AhcInfoClassSdbQueryResult |           \\\n                     AhcInfoClassSdbSxsOverrideManifest |   \\\n                     AhcInfoClassSdbRunlevelFlags |         \\\n                     AhcInfoClassSdbFusionFlags |           \\\n                     AhcInfoClassSdbInstallerFlags |        \\\n                     AhcInfoClassInstallDetect)\n\n#define AHC_INFO_CLASS_ALL                                  \\\n    (AHC_INFO_CLASS)(AhcInfoClassSdbQueryResult |           \\\n                     AhcInfoClassSdbSxsOverrideManifest |   \\\n                     AhcInfoClassSdbRunlevelFlags |         \\\n                     AhcInfoClassSdbFusionFlags |           \\\n                     AhcInfoClassSdbInstallerFlags |        \\\n                     AhcInfoClassFusionFlags |              \\\n                     AhcInfoClassTelemetryFlags |           \\\n                     AhcInfoClassInstallDetect |            \\\n                     AhcInfoClassRacEventSent |             \\\n                     AhcInfoClassIsSystemFile |             \\\n                     AhcInfoClassMonitoringFlags |          \\\n                     AhcInfoClassExeType)\n\n#define AHC_INFO_CLASS_INTERNALLY_COMPUTED                  \\\n    (AHC_INFO_CLASS)(AhcInfoClassSdbQueryResult |           \\\n                     AhcInfoClassSdbSxsOverrideManifest |   \\\n                     AhcInfoClassSdbRunlevelFlags |         \\\n                     AhcInfoClassSdbFusionFlags |           \\\n                     AhcInfoClassSdbInstallerFlags |        \\\n                     AhcInfoClassTelemetryFlags |           \\\n                     AhcInfoClassIsSystemFile |             \\\n                     AhcInfoClassMonitoringFlags |          \\\n                     AhcInfoClassExeType)\n\n#define AHC_INFO_CLASS_SAFE_FOR_UNPRIVILEGED_UPDATE         \\\n    (AHC_INFO_CLASS)(AhcInfoClassInstallDetect |            \\\n                     AhcInfoClassRacEventSent |             \\\n                     AhcInfoClassTelemetryFlags |           \\\n                     AhcInfoClassMonitoringFlags)\n\n//\n// Cache structures and APIs.\n//\n\ntypedef enum _AHC_SERVICE_CLASS\n{\n    ApphelpCacheServiceLookup = 0,\n    ApphelpCacheServiceRemove = 1,\n    ApphelpCacheServiceUpdate = 2,\n    ApphelpCacheServiceClear = 3,\n    ApphelpCacheServiceSnapStatistics = 4,\n    ApphelpCacheServiceSnapCache = 5,\n    ApphelpCacheServiceLookupCdb = 6,\n    ApphelpCacheServiceRefreshCdb = 7,\n    ApphelpCacheServiceMapQuirks = 8,\n    ApphelpCacheServiceHwIdQuery = 9,\n    ApphelpCacheServiceInitProcessData = 10,\n    ApphelpCacheServiceLookupAndWriteToProcess = 11,\n    ApphelpCacheServiceMax\n} AHC_SERVICE_CLASS;\n\ntypedef struct _AHC_SERVICE_LOOKUP\n{\n    AHC_INFO_CLASS InfoClass;                   // Information to lookup.\n    UINT HintFlags;                             // Hint flags about cache query.\n    UNICODE_STRING PackageAlias;                // Aliased package moniker in a packed string.\n    HANDLE FileHandle;                          // User space handle to file.\n    HANDLE ProcessHandle;                       // User space process handle.\n    USHORT ExeType;                             // Executable bitness.\n    USHORT Padding;                             // Padding to even USHORTs.\n    UNICODE_STRING ExeSignature;                // Executable file signature.\n    PCZZWSTR Environment;                       // Environment block.\n    UINT EnvironmentSize;                       // Size of environment block in bytes.\n} AHC_SERVICE_LOOKUP, *PAHC_SERVICE_LOOKUP;\n\ntypedef struct _AHC_SERVICE_REMOVE\n{\n    AHC_INFO_CLASS InfoClass;\n    UNICODE_STRING PackageAlias;\n    HANDLE FileHandle;\n    UNICODE_STRING ExeSignature;\n} AHC_SERVICE_REMOVE, *PAHC_SERVICE_REMOVE;\n\ntypedef struct _AHC_SERVICE_UPDATE\n{\n    AHC_INFO_CLASS InfoClass;\n    UNICODE_STRING PackageAlias;\n    HANDLE FileHandle;\n    UNICODE_STRING ExeSignature;\n    PVOID Data;\n    ULONG DataSize;\n} AHC_SERVICE_UPDATE, *PAHC_SERVICE_UPDATE;\n\ntypedef struct _AHC_SERVICE_CLEAR\n{\n    AHC_INFO_CLASS InfoClass;\n} AHC_SERVICE_CLEAR, *PAHC_SERVICE_CLEAR;\n\ntypedef struct _AHC_SERVICE_LOOKUP_CDB\n{\n    UNICODE_STRING Name;\n} AHC_SERVICE_LOOKUP_CDB, *PAHC_SERVICE_LOOKUP_CDB;\n\n//\n// AHC_HINT_* flags are used in the HintFlags variable.\n//\n\n#define AHC_HINT_FORCE_BYPASS                           0x00000001\n#define AHC_HINT_REMOVABLE_MEDIA                        0x00000002\n#define AHC_HINT_TEMPORARY_DIRECTORY                    0x00000004\n#define AHC_HINT_USER_PERM_LAYER                        0x00000008\n#define AHC_HINT_CREATE_PROCESS                         0x00000010\n#define AHC_HINT_NATIVE_EXE                             0x00000020\n\n#define SHIM_CACHE_MAIN_DATABASE_PATH32                 L\"\\\\AppPatch\\\\sysmain.sdb\"\n#define SHIM_CACHE_MAIN_DATABASE_PATH64                 L\"\\\\AppPatch\\\\AppPatch64\\\\sysmain.sdb\"\n\n//\n// Flag definitions for various flag-type information in cache.\n//\n\n#define AHC_CACHE_FLAG_MONITORING_IS_CANDIDATE          0x00000001 // Candidate for monitoring.\n#define AHC_CACHE_FLAG_MONITORING_IS_COMPLETE           0x00000002 // Monitoring has completed.\n#define AHC_CACHE_FLAG_MONITORING_VALID_MASK            (AHC_CACHE_FLAG_MONITORING_IS_CANDIDATE | \\\n                                                         AHC_CACHE_FLAG_MONITORING_IS_COMPLETE)\n\n#define AHC_CACHE_FLAG_TELEMETRY_IS_CANDIDATE           0x00000001 // Candidate for telemetry.\n#define AHC_CACHE_FLAG_TELEMETRY_HAS_SAMPLED            0x00000002 // Telemetry has run.\n#define AHC_CACHE_FLAG_TELEMETRY_VALID_MASK             (AHC_CACHE_FLAG_TELEMETRY_IS_CANDIDATE | \\\n                                                         AHC_CACHE_FLAG_TELEMETRY_HAS_SAMPLED)\n\n#define AHC_CACHE_FLAG_FUSION_HASDOTLOCAL               0x00000001 // Dot local file exists.\n#define AHC_CACHE_FLAG_FUSION_HASMANIFESTFILE           0x00000002 // Fusion manifest exists.\n#define AHC_CACHE_FLAG_FUSION_HASMANIFESTRESOURCE       0x00000004 // Fusion manifest resource exists.\n#define AHC_CACHE_FLAG_FUSION_VALID_MASK                (AHC_CACHE_FLAG_FUSION_HASDOTLOCAL | \\\n                                                         AHC_CACHE_FLAG_FUSION_HASMANIFESTFILE | \\\n                                                         AHC_CACHE_FLAG_FUSION_HASMANIFESTRESOURCE)\n\n#define AHC_CACHE_FLAG_RAC_EVENTSENT                    0x00000001 // Rac event has been sent.\n#define AHC_CACHE_FLAG_RAC_VALID_MASK                   (AHC_CACHE_FLAG_RAC_EVENTSENT)\n\n#define AHC_CACHE_FLAG_INSTALLDETECT_CLAIMED            0x00000001 // InstallDetect claimed.\n#define AHC_CACHE_FLAG_INSTALLDETECT_VALID_MASK         (AHC_CACHE_FLAG_RAC_EVENTSENT)\n\n//\n// Statistics.\n//\n\ntypedef struct _AHC_MAIN_STATISTICS\n{\n    ULONG Lookup;                               // Count of lookup calls.\n    ULONG Remove;                               // Count of remove calls.\n    ULONG Update;                               // Count of update calls.\n    ULONG Clear;                                // Count of clear calls.\n    ULONG SnapStatistics;                       // Count of snap statistics calls.\n    ULONG SnapCache;                            // Count of snap store calls.\n} AHC_MAIN_STATISTICS, *PAHC_MAIN_STATISTICS;\n\ntypedef struct _AHC_STORE_STATISTICS\n{\n    ULONG LookupHits;                           // Count of lookup hits.\n    ULONG LookupMisses;                         // Count of lookup misses.\n    ULONG Inserted;                             // Count of inserted.\n    ULONG Replaced;                             // Count of replaced.\n    ULONG Updated;                              // Count of updates.\n} AHC_STORE_STATISTICS, *PAHC_STORE_STATISTICS;\n\ntypedef struct _AHC_STATISTICS\n{\n    ULONG Size;                                 // Size of the structure.\n    AHC_MAIN_STATISTICS Main;                   // Main statistics.\n    AHC_STORE_STATISTICS Store;                 // Store statistics.\n} AHC_STATISTICS, *PAHC_STATISTICS;\n\ntypedef struct _AHC_SERVICE_DATAQUERY\n{\n    AHC_STATISTICS Stats;                       // Statistics.\n    ULONG DataSize;                             // Size of data.\n    PBYTE Data;                                 // Data.\n} AHC_SERVICE_DATAQUERY, *PAHC_SERVICE_DATAQUERY;\n\ntypedef struct _AHC_SERVICE_DATACACHE\n{\n    HANDLE FileHandle;                          // User space handle to file.\n    USHORT ExeType;                             // Executable bitness.\n    USHORT Padding;                             // Padding to even USHORTs.\n    UINT HintFlags;                             // Metadata flags about cache query.\n    HANDLE ProcessHandle;                       // User space process handle.\n    UNICODE_STRING FileName;                    // Executable file name.\n    UNICODE_STRING Environment;                 // Environment block.\n    UNICODE_STRING PackageAlias;                // Aliased package moniker in a packed string.\n    ULONG CustomDataSize;                       // Size of the custom data to cache.\n    PBYTE CustomData;                           // Pointer to the custom data.\n} AHC_SERVICE_DATACACHE, *PAHC_SERVICE_DATACACHE;\n\ntypedef struct _AHC_SERVICE_HWID_QUERY\n{\n    BOOLEAN QueryResult;                        // Query result\n    UNICODE_STRING HwId;                        // Query HwId; can contain wildcards\n} AHC_SERVICE_HWID_QUERY, *PAHC_SERVICE_HWID_QUERY;\n\ntypedef struct _AHC_SERVICE_DATA\n{\n    AHC_SERVICE_LOOKUP Lookup;                  // Lookup EXE/Package.\n    AHC_SERVICE_UPDATE Update;                  // Updating flags for a given exe/package.\n    AHC_SERVICE_DATACACHE Cache;                // For cache operations.\n    AHC_SERVICE_LOOKUP_CDB LookupCdb;           // Lookup cdb.\n    AHC_SERVICE_CLEAR Clear;                    // Clear flags for all exes/packages.\n    AHC_SERVICE_REMOVE Remove;                  // Remove EXE/Package.\n    AHC_SERVICE_HWID_QUERY HwIdQuery;           // For HWID cache queries.\n    NTSTATUS DriverStatus;                      // Receive the status from the cache driver. Set error code in IoStatus block causes driver verifier violation.\n    PVOID ParamsOut;                            // Parameters out data.\n    ULONG ParamsOutSize;                        // Parameters out size.\n} AHC_SERVICE_DATA, *PAHC_SERVICE_DATA;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtApphelpCacheControl(\n    _In_ AHC_SERVICE_CLASS ServiceClass,\n    _Inout_opt_ PVOID ServiceContext // AHC_SERVICE_DATA\n    );\n\n//\n// VDM\n//\n\ntypedef enum _VDMSERVICECLASS\n{\n    VdmStartExecution,\n    VdmQueueInterrupt,\n    VdmDelayInterrupt,\n    VdmInitialize,\n    VdmFeatures,\n    VdmSetInt21Handler,\n    VdmQueryDir,\n    VdmPrinterDirectIoOpen,\n    VdmPrinterDirectIoClose,\n    VdmPrinterInitialize,\n    VdmSetLdtEntries,\n    VdmSetProcessLdtInfo,\n    VdmAdlibEmulation,\n    VdmPMCliControl,\n    VdmQueryVdmProcess,\n    VdmPreInitialize\n} VDMSERVICECLASS, *PVDMSERVICECLASS;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtVdmControl(\n    _In_ VDMSERVICECLASS Service,\n    _Inout_ PVOID ServiceData\n    );\n\n//\n// Sessions\n//\n\ntypedef enum _IO_SESSION_EVENT\n{\n    IoSessionEventIgnore,\n    IoSessionEventCreated,\n    IoSessionEventTerminated,\n    IoSessionEventConnected,\n    IoSessionEventDisconnected,\n    IoSessionEventLogon,\n    IoSessionEventLogoff,\n    IoSessionEventMax\n} IO_SESSION_EVENT;\n\ntypedef enum _IO_SESSION_STATE\n{\n    IoSessionStateCreated = 1,\n    IoSessionStateInitialized = 2,\n    IoSessionStateConnected = 3,\n    IoSessionStateDisconnected = 4,\n    IoSessionStateDisconnectedLoggedOn = 5,\n    IoSessionStateLoggedOn = 6,\n    IoSessionStateLoggedOff = 7,\n    IoSessionStateTerminated = 8,\n    IoSessionStateMax\n} IO_SESSION_STATE;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenSession(\n    _Out_ PHANDLE SessionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtNotifyChangeSession(\n    _In_ HANDLE SessionHandle,\n    _In_ ULONG ChangeSequenceNumber,\n    _In_ PLARGE_INTEGER ChangeTimeStamp,\n    _In_ IO_SESSION_EVENT Event,\n    _In_ IO_SESSION_STATE NewState,\n    _In_ IO_SESSION_STATE PreviousState,\n    _In_reads_bytes_opt_(PayloadSize) PVOID Payload,\n    _In_ ULONG PayloadSize\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// ApiSet\n//\n\nNTSYSAPI\nBOOL\nNTAPI\nApiSetQueryApiSetPresence(\n    _In_ PCUNICODE_STRING Namespace,\n    _Out_ PBOOLEAN Present\n    );\n\nNTSYSAPI\nBOOL\nNTAPI\nApiSetQueryApiSetPresenceEx(\n    _In_ PCUNICODE_STRING Namespace,\n    _Out_ PBOOLEAN IsInSchema,\n    _Out_ PBOOLEAN Present\n    );\n\ntypedef enum _SECURE_SETTING_VALUE_TYPE\n{\n    SecureSettingValueTypeBoolean = 0,\n    SecureSettingValueTypeUlong = 1,\n    SecureSettingValueTypeBinary = 2,\n    SecureSettingValueTypeString = 3,\n    SecureSettingValueTypeUnknown = 4\n} SECURE_SETTING_VALUE_TYPE, *PSECURE_SETTING_VALUE_TYPE;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS1)\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySecurityPolicy(\n    _In_ PCUNICODE_STRING Policy,\n    _In_ PCUNICODE_STRING KeyName,\n    _In_ PCUNICODE_STRING ValueName,\n    _In_ SECURE_SETTING_VALUE_TYPE ValueType,\n    _Out_writes_bytes_opt_(*ValueSize) PVOID Value,\n    _Inout_ PULONG ValueSize\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_RS1)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_20H1)\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateCrossVmEvent(\n    _Out_ PHANDLE CrossVmEvent,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG CrossVmEventFlags,\n    _In_ LPCGUID VMID,\n    _In_ LPCGUID ServiceID\n    );\n\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateCrossVmMutant(\n    _Out_ PHANDLE EventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG CrossVmEventFlags,\n    _In_ LPCGUID VMID,\n    _In_ LPCGUID ServiceID\n    );\n\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAcquireCrossVmMutant(\n    _In_ HANDLE CrossVmMutant,\n    _In_ PLARGE_INTEGER Timeout\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_20H1)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_20H1)\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDirectGraphicsCall(\n    _In_ ULONG InputBufferLength,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _Out_ PULONG ReturnLength\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_20H1)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11_22H2)\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenCpuPartition(\n    _Out_ PHANDLE CpuPartitionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateCpuPartition(\n    _Out_ PHANDLE CpuPartitionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationCpuPartition(\n    _In_ HANDLE CpuPartitionHandle,\n    _In_ ULONG CpuPartitionInformationClass,\n    _In_reads_bytes_(CpuPartitionInformationLength) PVOID CpuPartitionInformation,\n    _In_ ULONG CpuPartitionInformationLength,\n    _Reserved_ PVOID,\n    _Reserved_ ULONG,\n    _Reserved_ ULONG\n    );\n\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationCpuPartition(\n    _In_ HANDLE CpuPartitionHandle,\n    _In_ ULONG CpuPartitionInformationClass,\n    _Out_writes_bytes_opt_(CpuPartitionInformationLength) PVOID CpuPartitionInformation,\n    _In_ ULONG CpuPartitionInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_11_22H2)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS2)\n//\n// Process KeepAlive (also WakeCounter)\n//\n\ntypedef enum _PROCESS_ACTIVITY_TYPE\n{\n    ProcessActivityTypeAudio = 0,\n    ProcessActivityTypeMax = 1\n} PROCESS_ACTIVITY_TYPE;\n\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAcquireProcessActivityReference(\n    _Out_ PHANDLE ActivityReferenceHandle,\n    _In_ HANDLE ParentProcessHandle,\n    _In_ ULONG ProcessActivityType // PROCESS_ACTIVITY_TYPE\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_RS2)\n\n//\n// Appx/Msix Packages\n//\n\n// private\ntypedef struct _PACKAGE_CONTEXT_REFERENCE\n{\n    PVOID reserved;\n} *PACKAGE_CONTEXT_REFERENCE;\n\n// private\ntypedef enum PackageProperty\n{\n    PackageProperty_Name = 1,                  // q: WCHAR[]\n    PackageProperty_Version = 2,               // q: WCHAR[]\n    PackageProperty_Architecture = 3,          // q: ULONG (PROCESSOR_ARCHITECTURE_*)\n    PackageProperty_ResourceId = 4,            // q: WCHAR[]\n    PackageProperty_Publisher = 5,             // q: WCHAR[]\n    PackageProperty_PublisherId = 6,           // q: WCHAR[]\n    PackageProperty_FamilyName = 7,            // q: WCHAR[]\n    PackageProperty_FullName = 8,              // q: WCHAR[]\n    PackageProperty_Flags = 9,                 // q: ULONG\n    PackageProperty_InstalledLocation = 10,    // q: WCHAR[]\n    PackageProperty_DisplayName = 11,          // q: WCHAR[]\n    PackageProperty_PublisherDisplayName = 12, // q: WCHAR[]\n    PackageProperty_Description = 13,          // q: WCHAR[]\n    PackageProperty_Logo = 14,                 // q: WCHAR[]\n    PackageProperty_PackageOrigin = 15         // q: PackageOrigin\n} PackageProperty;\n\n// private\ntypedef struct _PACKAGE_APPLICATION_CONTEXT_REFERENCE\n{\n    PVOID reserved;\n} *PACKAGE_APPLICATION_CONTEXT_REFERENCE;\n\n// private\ntypedef enum PackageApplicationProperty\n{\n    PackageApplicationProperty_Aumid = 1,                        // q: WCHAR[]\n    PackageApplicationProperty_Praid = 2,                        // q: WCHAR[]\n    PackageApplicationProperty_DisplayName = 3,                  // q: WCHAR[]\n    PackageApplicationProperty_Description = 4,                  // q: WCHAR[]\n    PackageApplicationProperty_Logo = 5,                         // q: WCHAR[]\n    PackageApplicationProperty_SmallLogo = 6,                    // q: WCHAR[]\n    PackageApplicationProperty_ForegroundText = 7,               // q: ULONG\n    PackageApplicationProperty_ForegroundTextString = 8,         // q: WCHAR[]\n    PackageApplicationProperty_BackgroundColor = 9,              // q: ULONG\n    PackageApplicationProperty_StartPage = 10,                   // q: WCHAR[]\n    PackageApplicationProperty_ContentURIRulesCount = 11,        // q: ULONG\n    PackageApplicationProperty_ContentURIRules = 12,             // q: WCHAR[] (multi-sz)\n    PackageApplicationProperty_StaticContentURIRulesCount = 13,  // q: ULONG\n    PackageApplicationProperty_StaticContentURIRules = 14,       // q: WCHAR[] (multi-sz)\n    PackageApplicationProperty_DynamicContentURIRulesCount = 15, // q: ULONG\n    PackageApplicationProperty_DynamicContentURIRules = 16       // q: WCHAR[] (multi-sz)\n} PackageApplicationProperty;\n\n// private\ntypedef struct _PACKAGE_RESOURCES_CONTEXT_REFERENCE\n{\n    PVOID reserved;\n} *PACKAGE_RESOURCES_CONTEXT_REFERENCE;\n\n// private\ntypedef enum PackageResourcesProperty\n{\n    PackageResourcesProperty_DisplayName = 1,\n    PackageResourcesProperty_PublisherDisplayName = 2,\n    PackageResourcesProperty_Description = 3,\n    PackageResourcesProperty_Logo = 4,\n    PackageResourcesProperty_SmallLogo = 5,\n    PackageResourcesProperty_StartPage = 6\n} PackageResourcesProperty;\n\n// private\ntypedef struct _PACKAGE_SECURITY_CONTEXT_REFERENCE\n{\n    PVOID reserved;\n} *PACKAGE_SECURITY_CONTEXT_REFERENCE;\n\n// private\ntypedef enum PackageSecurityProperty\n{\n    PackageSecurityProperty_SecurityFlags = 1,     // q: ULONG\n    PackageSecurityProperty_AppContainerSID = 2,   // q: Sid\n    PackageSecurityProperty_CapabilitiesCount = 3, // q: ULONG\n    PackageSecurityProperty_Capabilities = 4       // q: Sid[]\n} PackageSecurityProperty;\n\n// private\ntypedef struct _TARGET_PLATFORM_CONTEXT_REFERENCE\n{\n    PVOID reserved;\n} *TARGET_PLATFORM_CONTEXT_REFERENCE;\n\n// private\ntypedef enum TargetPlatformProperty\n{\n    TargetPlatformProperty_Platform = 1,   // q: ULONG\n    TargetPlatformProperty_MinVersion = 2, // q: PACKAGE_VERSION\n    TargetPlatformProperty_MaxVersion = 3  // q: PACKAGE_VERSION\n} TargetPlatformProperty;\n\n// private\ntypedef struct _PACKAGE_GLOBALIZATION_CONTEXT_REFERENCE\n{\n    PVOID reserved;\n} *PACKAGE_GLOBALIZATION_CONTEXT_REFERENCE;\n\n// private\ntypedef enum PackageGlobalizationProperty\n{\n    PackageGlobalizationProperty_ForceUtf8 = 1,                // q: ULONG\n    PackageGlobalizationProperty_UseWindowsDisplayLanguage = 2 // q: ULONG\n} PackageGlobalizationProperty;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8_1)\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetCurrentPackageContext(\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_CONTEXT_REFERENCE *PackageContext\n    );\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetPackageContext(\n    _In_ PVOID PackageInfoReference, // PACKAGE_INFO_REFERENCE\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_CONTEXT_REFERENCE *PackageContext\n    );\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetPackageProperty(\n    _In_ PACKAGE_CONTEXT_REFERENCE PackageContext,\n    _In_ PackageProperty PropertyId,\n    _Inout_ PULONG BufferSize,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer\n    );\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetPackagePropertyString(\n    _In_ PACKAGE_CONTEXT_REFERENCE PackageContext,\n    _In_ PackageProperty PropertyId,\n    _Inout_ PULONG BufferLength,\n    _Out_writes_(BufferLength) PWSTR Buffer\n    );\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetPackageOSMaxVersionTested(\n    _In_ PACKAGE_CONTEXT_REFERENCE PackageContext,\n    _Out_ ULONGLONG *OSMaxVersionTested // PACKAGE_VERSION\n    );\n\n//\n// Package Application Properties\n//\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetCurrentPackageApplicationContext(\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_APPLICATION_CONTEXT_REFERENCE *PackageApplicationContext\n    );\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetPackageApplicationContext(\n    _In_ PVOID PackageInfoReference, // PACKAGE_INFO_REFERENCE\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_APPLICATION_CONTEXT_REFERENCE *PackageApplicationContext\n    );\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetPackageApplicationProperty(\n    _In_ PACKAGE_APPLICATION_CONTEXT_REFERENCE PackageApplicationContext,\n    _In_ PackageApplicationProperty PropertyId,\n    _Inout_ PULONG BufferSize,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer\n    );\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetPackageApplicationPropertyString(\n    _In_ PACKAGE_APPLICATION_CONTEXT_REFERENCE PackageApplicationContext,\n    _In_ PackageApplicationProperty PropertyId,\n    _Inout_ PULONG BufferLength,\n    _Out_writes_(BufferLength) PWSTR Buffer\n    );\n\n//\n// Package Resource Properties\n//\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetCurrentPackageResourcesContext(\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_RESOURCES_CONTEXT_REFERENCE *PackageResourcesContext\n    );\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetPackageResourcesContext(\n    _In_ PVOID PackageInfoReference, // PACKAGE_INFO_REFERENCE\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_RESOURCES_CONTEXT_REFERENCE *PackageResourcesContext\n    );\n\n// rev\nWINBASEAPI\nULONG\nWINAPI\nGetCurrentPackageApplicationResourcesContext(\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_RESOURCES_CONTEXT_REFERENCE *PackageResourcesContext\n    );\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetPackageApplicationResourcesContext(\n    _In_ PVOID PackageInfoReference, // PACKAGE_INFO_REFERENCE\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_RESOURCES_CONTEXT_REFERENCE *PackageResourcesContext\n    );\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetPackageResourcesProperty(\n    _In_ PACKAGE_RESOURCES_CONTEXT_REFERENCE PackageResourcesContext,\n    _In_ PackageResourcesProperty PropertyId,\n    _Inout_ PULONG BufferSize,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _Out_opt_ PULONG Flags\n    );\n\n//\n// Package Security Properties\n//\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetCurrentPackageSecurityContext(\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_SECURITY_CONTEXT_REFERENCE *PackageSecurityContext\n    );\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetPackageSecurityContext(\n    _In_ PVOID PackageInfoReference, // PACKAGE_INFO_REFERENCE\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_SECURITY_CONTEXT_REFERENCE *PackageSecurityContext\n    );\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetPackageSecurityProperty(\n    _In_ PACKAGE_SECURITY_CONTEXT_REFERENCE PackageSecurityContext,\n    _In_ PackageSecurityProperty PropertyId,\n    _Inout_ PULONG BufferSize,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer\n    );\n\n#endif // PHNT_VERSION >= PHNT_WINDOWS_8_1\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n//\n// Target Platform Properties\n//\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetCurrentTargetPlatformContext(\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ TARGET_PLATFORM_CONTEXT_REFERENCE *TargetPlatformContext\n    );\n\nWINBASEAPI\nLONG\nWINAPI\nGetTargetPlatformContext(\n    _In_ PVOID PackageInfoReference, // PACKAGE_INFO_REFERENCE\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ TARGET_PLATFORM_CONTEXT_REFERENCE *TargetPlatformContext\n    );\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetPackageTargetPlatformProperty(\n    _In_ TARGET_PLATFORM_CONTEXT_REFERENCE TargetPlatformContext,\n    _In_ TargetPlatformProperty PropertyId,\n    _Inout_ PULONG BufferSize,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer\n    );\n\n#endif // PHNT_VERSION >= PHNT_WINDOWS_10\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_20H1)\n\n// rev\nWINBASEAPI\nHRESULT\nWINAPI\nGetCurrentPackageInfo3(\n    _In_ ULONG Flags,\n    _In_ ULONG PackagePathType, // PackagePathType\n    _Inout_ PULONG BufferLength,\n    _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n//\n// Package Globalization Properties\n//\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetCurrentPackageGlobalizationContext(\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_GLOBALIZATION_CONTEXT_REFERENCE *PackageGlobalizationContext\n    );\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetPackageGlobalizationContext(\n    _In_ PVOID PackageInfoReference, // PACKAGE_INFO_REFERENCE\n    _In_ ULONG Index,\n    _Reserved_ ULONG_PTR Unused,\n    _Out_ PACKAGE_GLOBALIZATION_CONTEXT_REFERENCE *PackageGlobalizationContext\n    );\n\n// rev\nWINBASEAPI\nLONG\nWINAPI\nGetPackageGlobalizationProperty(\n    _In_ PACKAGE_GLOBALIZATION_CONTEXT_REFERENCE PackageGlobalizationContext,\n    _In_ PackageGlobalizationProperty PropertyId,\n    _Inout_ PULONG BufferSize,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer\n    );\n\n#endif // PHNT_VERSION >= PHNT_WINDOWS_10_20H1\n\n//\n// COM\n//\n\n// private\n_Enum_is_bitflag_\ntypedef enum _MTA_HOST_USAGE_FLAGS\n{\n    MTA_HOST_USAGE_NONE = 0x0,\n    MTA_HOST_USAGE_MTAINITIALIZED = 0x1,\n    MTA_HOST_USAGE_ACTIVATORINITIALIZED = 0x2,\n    MTA_HOST_USAGE_UNLOADCALLED = 0x4,\n} MTA_HOST_USAGE_FLAGS, *PMTA_HOST_USAGE_FLAGS;\nDEFINE_ENUM_FLAG_OPERATORS(MTA_HOST_USAGE_FLAGS);\n\n// private\ntypedef struct _MTA_USAGE_GLOBALS\n{\n    _Reserved_ ULONG StackCapture;\n    PULONG MTAInits; // A pointer to the total number of MTA inits\n    PULONG MTAIncInits; // A pointer to the number of MTA inits from CoIncrementMTAUsage\n    PULONG MTAWaiters; // A pointer to the number of callers waiting inside CoWaitMTACompletion\n    PULONG MTAIncrementorSize; // A pointer to the size of the cookie returned by CoIncrementMTAUsage\n    ULONG CompletionTimeOut; // A timeout for CoWaitMTACompletion in milliseconds\n    _Reserved_ PLIST_ENTRY ListEntryHeadMTAUsageIncrementor;\n    _Reserved_ PULONG MTAIncrementorCompleted;\n    _Reserved_ PVOID* MTAUsageCompletedIncrementorHead;\n    PMTA_HOST_USAGE_FLAGS MTAHostUsageFlags; // A pointer to the MTA usage flags // since THRESHOLD\n} MTA_USAGE_GLOBALS, *PMTA_USAGE_GLOBALS;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n// private // combase.dll, ordinal 70\n_Success_(return != 0)\n_Must_inspect_result_\nWINBASEAPI\nPMTA_USAGE_GLOBALS\nWINAPI\nCoGetMTAUsageInfo(\n    VOID\n    );\n#endif\n\n//\n// COM/OLE\n//\n\n// OLETLSFLAGS\n#define OLETLS_LOCALTID 0x01 // This TID is in the current process.\n#define OLETLS_UUIDINITIALIZED 0x02 // This Logical thread is init'd.\n#define OLETLS_INTHREADDETACH 0x04 // This is in thread detach.\n#define OLETLS_CHANNELTHREADINITIALZED 0x08// This channel has been init'd\n#define OLETLS_WOWTHREAD 0x10 // This thread is a 16-bit WOW thread.\n#define OLETLS_THREADUNINITIALIZING 0x20 // This thread is in CoUninitialize.\n#define OLETLS_DISABLE_OLE1DDE 0x40 // This thread can't use a DDE window.\n#define OLETLS_APARTMENTTHREADED 0x80 // This is an STA apartment thread\n#define OLETLS_MULTITHREADED 0x100 // This is an MTA apartment thread\n#define OLETLS_IMPERSONATING 0x200 // This thread is impersonating\n#define OLETLS_DISABLE_EVENTLOGGER 0x400 // Prevent recursion in event logger\n#define OLETLS_INNEUTRALAPT 0x800 // This thread is in the NTA\n#define OLETLS_DISPATCHTHREAD 0x1000 // This is a dispatch thread\n#define OLETLS_HOSTTHREAD 0x2000 // This is a host thread\n#define OLETLS_ALLOWCOINIT 0x4000 // This thread allows inits\n#define OLETLS_PENDINGUNINIT 0x8000 // This thread has pending uninit\n#define OLETLS_FIRSTMTAINIT 0x10000// First thread to attempt an MTA init\n#define OLETLS_FIRSTNTAINIT 0x20000// First thread to attempt an NTA init\n#define OLETLS_APTINITIALIZING 0x40000 // Apartment Object is initializing\n#define OLETLS_UIMSGSINMODALLOOP 0x80000\n#define OLETLS_MARSHALING_ERROR_OBJECT 0x100000 // since WIN8\n#define OLETLS_WINRT_INITIALIZE 0x200000 // This thread called RoInitialize\n#define OLETLS_APPLICATION_STA 0x400000\n#define OLETLS_IN_SHUTDOWN_CALLBACKS 0x800000\n#define OLETLS_POINTER_INPUT_BLOCKED 0x1000000\n#define OLETLS_IN_ACTIVATION_FILTER 0x2000000 // since WINBLUE\n#define OLETLS_ASTATOASTAEXEMPT_QUIRK 0x4000000\n#define OLETLS_ASTATOASTAEXEMPT_PROXY 0x8000000\n#define OLETLS_ASTATOASTAEXEMPT_INDOUBT 0x10000000\n#define OLETLS_DETECTED_USER_INITIALIZED 0x20000000 // since RS3\n#define OLETLS_BRIDGE_STA 0x40000000 // since RS5\n#define OLETLS_NAINITIALIZING 0x80000000UL // since 19H1\n\n// private\ntypedef struct tagSOleTlsData\n{\n    PVOID ThreadBase;\n    PVOID SmAllocator;\n    ULONG ApartmentID;\n    ULONG Flags; // OLETLSFLAGS\n    LONG TlsMapIndex;\n    PVOID *TlsSlot;\n    ULONG ComInits;\n    ULONG OleInits;\n    ULONG Calls;\n    PVOID ServerCall; // previously CallInfo (before TH1)\n    PVOID CallObjectCache; // previously FreeAsyncCall (before TH1)\n    PVOID ContextStack; // previously FreeClientCall (before TH1)\n    PVOID ObjServer;\n    ULONG TIDCaller;\n    // ... (other fields are version-dependant)\n} SOleTlsData, *PSOleTlsData;\n\n// private // ole32.dll\nWINBASEAPI\nVOID\nWINAPI\nUpdateDCOMSettings(\n    VOID\n    );\n\n//\n// AppCompat\n//\n\ntypedef struct tagSDBQUERYRESULT\n{\n    ULONG Exes[16];\n    ULONG ExeFlags[16];\n    ULONG Layers[8];\n    ULONG LayerFlags;\n    ULONG AppHelp;\n    ULONG ExeCount;\n    ULONG LayerCount;\n    GUID ID;\n    ULONG ExtraFlags;\n    ULONG CustomSDBMap;\n    GUID DB[16];\n} SDBQUERYRESULT, *PSDBQUERYRESULT;\n\nstatic_assert(sizeof(SDBQUERYRESULT) == 0x1c8, \"SDBQUERYRESULT size mismatch\");\n\ntypedef struct tagSWITCH_CONTEXT_ATTRIBUTE\n{\n    ULONG_PTR ContextUpdateCounter;\n    BOOL AllowContextUpdate;\n    BOOL EnableTrace;\n    HANDLE EtwHandle;\n} SWITCH_CONTEXT_ATTRIBUTE, *PSWITCH_CONTEXT_ATTRIBUTE;\n\n#ifdef _WIN64\nstatic_assert(sizeof(SWITCH_CONTEXT_ATTRIBUTE) == 0x18, \"SWITCH_CONTEXT_ATTRIBUTE size mismatch\");\n#else\nstatic_assert(sizeof(SWITCH_CONTEXT_ATTRIBUTE) == 0x10, \"SWITCH_CONTEXT_ATTRIBUTE size mismatch\");\n#endif\n\ntypedef struct tagSWITCH_CONTEXT_DATA\n{\n    ULONGLONG OsMaxVersionTested;\n    ULONG TargetPlatform;\n    ULONGLONG ContextMinimum;\n    GUID Platform;\n    GUID MinPlatform;\n    ULONG ContextSource;\n    ULONG ElementCount;\n    GUID Elements[48];\n} SWITCH_CONTEXT_DATA, * PSWITCH_CONTEXT_DATA;\n\nstatic_assert(sizeof(SWITCH_CONTEXT_DATA) == 0x340, \"SWITCH_CONTEXT_DATA size mismatch\");\n\ntypedef struct tagSWITCH_CONTEXT\n{\n    SWITCH_CONTEXT_ATTRIBUTE Attribute;\n    SWITCH_CONTEXT_DATA Data;\n} SWITCH_CONTEXT, *PSWITCH_CONTEXT;\n\n#ifdef _WIN64\nstatic_assert(sizeof(SWITCH_CONTEXT) == 0x358, \"SWITCH_CONTEXT size mismatch\");\n#else\nstatic_assert(sizeof(SWITCH_CONTEXT) == 0x350, \"SWITCH_CONTEXT size mismatch\");\n#endif\n\ntypedef struct _SDB_CSTRUCT_COBALT_PROCFLAG\n{\n    KAFFINITY AffinityMask;\n    ULONG CPUIDEcxOverride;\n    ULONG CPUIDEdxOverride;\n    USHORT ProcessorGroup;\n    USHORT FastSelfModThreshold;\n    USHORT Reserved1;\n    UCHAR Reserved2;\n    UCHAR BackgroundWork : 5;\n    UCHAR CPUIDBrand : 4;\n    UCHAR Reserved3 : 4;\n    UCHAR RdtscScaling : 3;\n    UCHAR Reserved4 : 2;\n    UCHAR UnalignedAtomicApproach : 2;\n    UCHAR Win11Atomics : 2;\n    UCHAR RunOnSingleCore : 1;\n    UCHAR X64CPUID : 1;\n    UCHAR PatchUnaligned : 1;\n    UCHAR InterpreterOrJitter : 1;\n    UCHAR ForceSegmentHeap : 1;\n    UCHAR Reserved5 : 1;\n    UCHAR Reserved6 : 1;\n    union\n    {\n        ULONGLONG Group1AsUINT64;\n        struct _SDB_CSTRUCT_COBALT_PROCFLAG* Specified;\n    };\n} SDB_CSTRUCT_COBALT_PROCFLAG, *PSDB_CSTRUCT_COBALT_PROCFLAG;\n\n#ifdef _WIN64\nstatic_assert(sizeof(SDB_CSTRUCT_COBALT_PROCFLAG) == 0x28, \"SDB_CSTRUCT_COBALT_PROCFLAG size mismatch\");\n#else\nstatic_assert(sizeof(SDB_CSTRUCT_COBALT_PROCFLAG) == 0x20, \"SDB_CSTRUCT_COBALT_PROCFLAG size mismatch\");\n#endif\n\ntypedef struct _APPCOMPAT_EXE_DATA\n{\n    ULONG_PTR Reserved[65];\n    ULONG Size;\n    ULONG Magic;\n    BOOL LoadShimEngine;\n    USHORT ExeType;\n    SDBQUERYRESULT SdbQueryResult;\n    ULONG_PTR DbgLogChannels[128];\n    SWITCH_CONTEXT SwitchContext;\n    ULONG ParentProcessId;\n    WCHAR ParentImageName[260];\n    WCHAR ParentCompatLayers[256];\n    WCHAR ActiveCompatLayers[256];\n    ULONG ImageFileSize;\n    ULONG ImageCheckSum;\n    BOOL LatestOs;\n    BOOL PackageId;\n    BOOL SwitchBackManifest;\n    BOOL UacManifest;\n    BOOL LegacyInstaller;\n    ULONG RunLevel;\n    ULONG_PTR WinRTFlags;\n    PVOID HookCOM;\n    PVOID ComponentOnDemandEvent;\n    PVOID Quirks;\n    ULONG QuirksSize;\n    SDB_CSTRUCT_COBALT_PROCFLAG CobaltProcFlags;\n    ULONG FullMatchDbSizeCb;\n    ULONG FullMatchDbOffset;\n} APPCOMPAT_EXE_DATA;\n\n#ifdef _WIN64\nstatic_assert(sizeof(APPCOMPAT_EXE_DATA) == 0x11C0, \"APPCOMPAT_EXE_DATA size mismatch\");\n#else\nstatic_assert(sizeof(APPCOMPAT_EXE_DATA) == 0xE98, \"APPCOMPAT_EXE_DATA size mismatch\");\n#endif\n\n//\n// Direct3D Kernel Mode Thunk (D3DKMT)\n//\n\n/**\n * The D3DKMT_GET_PROCESS_LIST structure is used for retrieving a list of process handles using a graphics adapter.\n * \\remarks The caller is responsible for closing the returned process handles.\n */\n// rev\ntypedef struct _D3DKMT_GET_PROCESS_LIST\n{\n    LUID AdapterLuid;          // [in] The locally unique identifier (LUID) for the graphics adapter.\n    ULONG DesiredAccess;       // [in] The access rights to request for the process handles. This must be `PROCESS_QUERY_INFORMATION` (0x400).\n    ULONG ProcessHandleCount;  // [in, out] On input, specifies the number of handles the `ProcessHandle` member can hold. On output, receives the number of handles returned.\n    HANDLE ProcessHandle;      // [out] The first element of an array that receives the process handles.\n} D3DKMT_GET_PROCESS_LIST, *PD3DKMT_GET_PROCESS_LIST;\n\n// rev\n/**\n * The D3DKMTGetProcessList function retrieves a list of processes that are using a specific graphics adapter.\n *\n * \\param[in,out] GetProcessList A pointer to a \\ref D3DKMT_GET_PROCESS_LIST structure that contains the processes using the graphics adapter.\n * \\return NTSTATUS Successful or errant status.\n */\nEXTERN_C\nNTSTATUS\nNTAPI\nD3DKMTGetProcessList(\n    _Inout_ PD3DKMT_GET_PROCESS_LIST GetProcessList\n    );\n\n// rev\n/**\n * The D3DKMT_ENUM_PROCESS_LIST structure is used for retrieving a list of process identifiers using a graphics adapter.\n */\ntypedef struct _D3DKMT_ENUM_PROCESS_LIST\n{\n    LUID AdapterLuid;          // [in] The locally unique identifier (LUID) for the graphics adapter.\n    PULONG ProcessIdBuffer;    // [out] A pointer to a buffer that receives the list of process identifiers (PIDs).\n    SIZE_T ProcessIdCount;     // [in, out] On input, specifies the number of elements the `ProcessIdBuffer` can hold. On output, receives the number of process IDs returned.\n} D3DKMT_ENUM_PROCESS_LIST, *PD3DKMT_ENUM_PROCESS_LIST;\n\n// rev\n/**\n * The D3DKMTEnumProcesses function provides a list of process IDs (PIDs) rather than handles that are using a specific graphics adapter, \n * which can be more efficient for monitoring purposes.\n *\n * \\param[in,out] EnumProcessList A pointer to a \\ref D3DKMT_ENUM_PROCESS_LIST structure that contains the processes using the graphics adapter.\n * \\return NTSTATUS Successful or errant status.\n */\nEXTERN_C\nNTSTATUS\nNTAPI\nD3DKMTEnumProcesses(\n    _Inout_ PD3DKMT_ENUM_PROCESS_LIST EnumProcessList\n    );\n\n#endif // _NTMISC_H\n"
  },
  {
    "path": "phnt/include/ntmmapi.h",
    "content": "/*\n * Memory Manager Support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTMMAPI_H\n#define _NTMMAPI_H\n\ntypedef struct _IO_STATUS_BLOCK* PIO_STATUS_BLOCK;\n\n//\n// Memory Protection Constants\n//\n\n#define PAGE_NOACCESS 0x01              // Disables all access to the committed region of pages. An attempt to read from, write to, or execute the committed region results in an access violation.\n#define PAGE_READONLY 0x02              // Enables read-only access to the committed region of pages. An attempt to write or execute the committed region results in an access violation.\n#define PAGE_READWRITE 0x04             // Enables read-only or read/write access to the committed region of pages.\n#define PAGE_WRITECOPY 0x08             // Enables read-only or copy-on-write access to a mapped view of a file mapping object.\n#define PAGE_EXECUTE 0x10               // Enables execute access to the committed region of pages. An attempt to write to the committed region results in an access violation.\n#define PAGE_EXECUTE_READ 0x20          // Enables execute or read-only access to the committed region of pages. An attempt to write to the committed region results in an access violation.\n#define PAGE_EXECUTE_READWRITE 0x40     // Enables execute, read-only, or read/write access to the committed region of pages.\n#define PAGE_EXECUTE_WRITECOPY 0x80     // Enables execute, read-only, or copy-on-write access to a mapped view of a file mapping object.\n#define PAGE_GUARD 0x100                // Pages in the region become guard pages. Any attempt to access a guard page causes the system to raise a STATUS_GUARD_PAGE_VIOLATION exception.\n#define PAGE_NOCACHE 0x200              // Sets all pages to be non-cachable. Applications should not use this attribute. Using interlocked functions with memory that is mapped with SEC_NOCACHE can result in an EXCEPTION_ILLEGAL_INSTRUCTION exception.\n#define PAGE_WRITECOMBINE 0x400         // Sets all pages to be write-combined. Applications should not use this attribute. Using interlocked functions with memory that is mapped with SEC_NOCACHE can result in an EXCEPTION_ILLEGAL_INSTRUCTION exception.\n\n#define PAGE_REVERT_TO_FILE_MAP     0x80000000 // Pages in the region can revert modified copy-on-write pages to the original unmodified page when using the mapped view of a file mapping object.\n#define PAGE_ENCLAVE_THREAD_CONTROL 0x80000000 // Pages in the region contain a thread control structure (TCS) from the Intel Software Guard Extensions programming model.\n#define PAGE_TARGETS_NO_UPDATE      0x40000000 // Pages in the region will not update the CFG bitmap when the protection changes. The default behavior for VirtualProtect is to mark all locations as valid call targets for CFG.\n#define PAGE_TARGETS_INVALID        0x40000000 // Pages in the region are excluded from the CFG bitmap as valid targets. Any indirect call to locations in those pages will terminate the process using the __fastfail intrinsic.\n#define PAGE_ENCLAVE_UNVALIDATED    0x20000000 // Pages in the region are excluded from measurement with the EEXTEND instruction of the Intel Software Guard Extensions programming model.\n#define PAGE_ENCLAVE_NO_CHANGE      0x20000000\n#define PAGE_ENCLAVE_MASK           0x10000000\n#define PAGE_ENCLAVE_DECOMMIT       (PAGE_ENCLAVE_MASK | 0)\n#define PAGE_ENCLAVE_SS_FIRST       (PAGE_ENCLAVE_MASK | 1)\n#define PAGE_ENCLAVE_SS_REST        (PAGE_ENCLAVE_MASK | 2)\n\n//\n// Memory Region and Section Constants\n//\n\n#define MEM_COMMIT 0x00001000\n#define MEM_RESERVE 0x00002000\n#define MEM_DECOMMIT 0x00004000\n#define MEM_RELEASE 0x00008000\n#define MEM_FREE 0x00010000\n#define MEM_PRIVATE 0x00020000\n#define MEM_MAPPED 0x00040000\n#define MEM_RESET 0x00080000\n#define MEM_TOP_DOWN 0x00100000\n#define MEM_WRITE_WATCH 0x00200000\n#define MEM_PHYSICAL 0x00400000\n#define MEM_ROTATE 0x00800000\n#define MEM_DIFFERENT_IMAGE_BASE_OK 0x00800000\n#define MEM_RESET_UNDO 0x01000000\n#define MEM_LARGE_PAGES 0x20000000\n#define MEM_DOS_LIM 0x40000000\n#define MEM_4MB_PAGES 0x80000000\n#define MEM_64K_PAGES (MEM_LARGE_PAGES | MEM_PHYSICAL)\n\n#define MEM_UNMAP_WITH_TRANSIENT_BOOST 0x00000001\n#define MEM_COALESCE_PLACEHOLDERS 0x00000001\n#define MEM_PRESERVE_PLACEHOLDER 0x00000002\n#define MEM_REPLACE_PLACEHOLDER 0x00004000\n#define MEM_RESERVE_PLACEHOLDER 0x00040000\n\n#define SEC_HUGE_PAGES 0x00020000\n#define SEC_PARTITION_OWNER_HANDLE 0x00040000\n#define SEC_64K_PAGES 0x00080000\n#define SEC_DRIVER_IMAGE 0x00100000 // rev\n#define SEC_BASED 0x00200000\n#define SEC_NO_CHANGE 0x00400000\n#define SEC_FILE 0x00800000\n#define SEC_IMAGE 0x01000000\n#define SEC_PROTECTED_IMAGE 0x02000000\n#define SEC_RESERVE 0x04000000\n#define SEC_COMMIT 0x08000000\n#define SEC_NOCACHE 0x10000000\n#define SEC_GLOBAL 0x20000000\n#define SEC_WRITECOMBINE 0x40000000\n#define SEC_LARGE_PAGES 0x80000000\n#define SEC_IMAGE_NO_EXECUTE (SEC_IMAGE | SEC_NOCACHE)\n#if (PHNT_MODE == PHNT_MODE_KERNEL)\n#define MEM_IMAGE SEC_IMAGE\n#endif\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _MEMORY_INFORMATION_CLASS\n{\n    MemoryBasicInformation,                     // q: MEMORY_BASIC_INFORMATION\n    MemoryWorkingSetInformation,                // q: MEMORY_WORKING_SET_INFORMATION\n    MemoryMappedFilenameInformation,            // q: UNICODE_STRING\n    MemoryRegionInformation,                    // q: MEMORY_REGION_INFORMATION\n    MemoryWorkingSetExInformation,              // q: MEMORY_WORKING_SET_EX_INFORMATION // since VISTA\n    MemorySharedCommitInformation,              // q: MEMORY_SHARED_COMMIT_INFORMATION // since WIN8\n    MemoryImageInformation,                     // q: MEMORY_IMAGE_INFORMATION\n    MemoryRegionInformationEx,                  // q: MEMORY_REGION_INFORMATION\n    MemoryPrivilegedBasicInformation,           // q: MEMORY_BASIC_INFORMATION\n    MemoryEnclaveImageInformation,              // q: MEMORY_ENCLAVE_IMAGE_INFORMATION // since REDSTONE3\n    MemoryBasicInformationCapped,               // q: 10\n    MemoryPhysicalContiguityInformation,        // q: MEMORY_PHYSICAL_CONTIGUITY_INFORMATION // since 20H1\n    MemoryBadInformation,                       // q: MEMORY_BAD_INFORMATION // since WIN11\n    MemoryBadInformationAllProcesses,           // qs: not implemented // since 22H1\n    MemoryImageExtensionInformation,            // q: MEMORY_IMAGE_EXTENSION_INFORMATION // since 24H2\n    MaxMemoryInfoClass\n} MEMORY_INFORMATION_CLASS;\n#else\n#define MemoryBasicInformation 0x0\n#define MemoryWorkingSetInformation 0x1\n#define MemoryMappedFilenameInformation 0x2\n#define MemoryRegionInformation 0x3\n#define MemoryWorkingSetExInformation 0x4\n#define MemorySharedCommitInformation 0x5\n#define MemoryImageInformation 0x6\n#define MemoryRegionInformationEx 0x7\n#define MemoryPrivilegedBasicInformation 0x8\n#define MemoryEnclaveImageInformation 0x9\n#define MemoryBasicInformationCapped 0xA\n#define MemoryPhysicalContiguityInformation 0xB\n#define MemoryBadInformation 0xC\n#define MemoryBadInformationAllProcesses 0xD\n#define MemoryImageExtensionInformation 0xE\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// MEMORY_WORKING_SET_BLOCK->Protection\n#define MEMORY_BLOCK_NOT_ACCESSED 0\n#define MEMORY_BLOCK_READONLY 1\n#define MEMORY_BLOCK_EXECUTABLE 2\n#define MEMORY_BLOCK_EXECUTABLE_READONLY 3\n#define MEMORY_BLOCK_READWRITE 4\n#define MEMORY_BLOCK_COPYONWRITE 5\n#define MEMORY_BLOCK_EXECUTABLE_READWRITE 6\n#define MEMORY_BLOCK_EXECUTABLE_COPYONWRITE 7\n#define MEMORY_BLOCK_NOT_ACCESSED_2 8\n#define MEMORY_BLOCK_NON_CACHEABLE_READONLY 9\n#define MEMORY_BLOCK_NON_CACHEABLE_EXECUTABLE 10\n#define MEMORY_BLOCK_NON_CACHEABLE_EXECUTABLE_READONLY 11\n#define MEMORY_BLOCK_NON_CACHEABLE_READWRITE 12\n#define MEMORY_BLOCK_NON_CACHEABLE_COPYONWRITE 13\n#define MEMORY_BLOCK_NON_CACHEABLE_EXECUTABLE_READWRITE 14\n#define MEMORY_BLOCK_NON_CACHEABLE_EXECUTABLE_COPYONWRITE 15\n#define MEMORY_BLOCK_NOT_ACCESSED_3 16\n#define MEMORY_BLOCK_GUARD_READONLY 17\n#define MEMORY_BLOCK_GUARD_EXECUTABLE 18\n#define MEMORY_BLOCK_GUARD_EXECUTABLE_READONLY 19\n#define MEMORY_BLOCK_GUARD_READWRITE 20\n#define MEMORY_BLOCK_GUARD_COPYONWRITE 21\n#define MEMORY_BLOCK_GUARD_EXECUTABLE_READWRITE 22\n#define MEMORY_BLOCK_GUARD_EXECUTABLE_COPYONWRITE 23\n#define MEMORY_BLOCK_NOT_ACCESSED_4 24\n#define MEMORY_BLOCK_NON_CACHEABLE_GUARD_READONLY 25\n#define MEMORY_BLOCK_NON_CACHEABLE_GUARD_EXECUTABLE 26\n#define MEMORY_BLOCK_NON_CACHEABLE_GUARD_EXECUTABLE_READONLY 27\n#define MEMORY_BLOCK_NON_CACHEABLE_GUARD_READWRITE 28\n#define MEMORY_BLOCK_NON_CACHEABLE_GUARD_COPYONWRITE 29\n#define MEMORY_BLOCK_NON_CACHEABLE_GUARD_EXECUTABLE_READWRITE 30\n#define MEMORY_BLOCK_NON_CACHEABLE_GUARD_EXECUTABLE_COPYONWRITE 31\n\n/**\n * The MEMORY_WORKING_SET_BLOCK structure contains working set information for a page.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-psapi_working_set_block\n */\ntypedef struct _MEMORY_WORKING_SET_BLOCK\n{\n    ULONG_PTR Protection : 5;       // The protection attributes of the page. This member can be one of above MEMORY_BLOCK_* values.\n    ULONG_PTR ShareCount : 3;       // The number of processes that share this page. The maximum value of this member is 7.\n    ULONG_PTR Shared : 1;           // If this bit is 1, the page is sharable; otherwise, the page is not sharable.\n    ULONG_PTR Node : 3;             // The NUMA node where the physical memory should reside.\n#ifdef _WIN64\n    ULONG_PTR VirtualPage : 52;     // The address of the page in the virtual address space.\n#else\n    ULONG VirtualPage : 20;         // The address of the page in the virtual address space.\n#endif\n} MEMORY_WORKING_SET_BLOCK, *PMEMORY_WORKING_SET_BLOCK;\n\n/**\n * The MEMORY_WORKING_SET_INFORMATION structure contains working set information for a process.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-psapi_working_set_information\n */\ntypedef struct _MEMORY_WORKING_SET_INFORMATION\n{\n    ULONG_PTR NumberOfEntries;\n    _Field_size_(NumberOfEntries) MEMORY_WORKING_SET_BLOCK WorkingSetInfo[ANYSIZE_ARRAY];\n} MEMORY_WORKING_SET_INFORMATION, *PMEMORY_WORKING_SET_INFORMATION;\n\n// private\ntypedef struct _MEMORY_REGION_INFORMATION\n{\n    PVOID AllocationBase;                             // Base address of the allocation.\n    ULONG AllocationProtect;                          // Page protection when the allocation was created (individual pages can be different from this value).\n    union\n    {\n        ULONG RegionType;\n        struct\n        {\n            ULONG Private : 1;                        // Region is private to the process (not shared).\n            ULONG MappedDataFile : 1;                 // Region is a mapped view of a data file (read/write data mapping).\n            ULONG MappedImage : 1;                    // Region is a mapped view of an image file (executable/DLL mapping).\n            ULONG MappedPageFile : 1;                 // Region is a mapped view of a pagefile-backed section.\n            ULONG MappedPhysical : 1;                 // Region is a mapped view of the \\Device\\PhysicalMemory section.\n            ULONG DirectMapped : 1;                   // Region is a mapped view of a direct-mapped file.\n            ULONG SoftwareEnclave : 1;                // Region is a mapped view of a software enclave. // since REDSTONE3\n            ULONG PageSize64K : 1;                    // Region uses 64 KB page size.\n            ULONG PlaceholderReservation : 1;         // Region uses placeholder reservations. // since REDSTONE4\n            ULONG MappedAwe : 1; // 21H1              // Region uses Address Windowing Extensions (AWE).\n            ULONG MappedWriteWatch : 1;               // Region uses write-watch protection.\n            ULONG PageSizeLarge : 1;                  // Region uses large page size.\n            ULONG PageSizeHuge : 1;                   // Region uses huge page size.\n            ULONG Reserved : 19;\n        };\n    };\n    SIZE_T RegionSize;                                // The combined size of pages in the region.\n    SIZE_T CommitSize;                                // The commit charge associated with the allocation.\n    ULONG_PTR PartitionId; // 19H1\n    ULONG_PTR NodePreference; // 20H1\n} MEMORY_REGION_INFORMATION, *PMEMORY_REGION_INFORMATION;\n\n// private\ntypedef enum _MEMORY_WORKING_SET_EX_LOCATION\n{\n    MemoryLocationInvalid,\n    MemoryLocationResident,\n    MemoryLocationPagefile,\n    MemoryLocationReserved\n} MEMORY_WORKING_SET_EX_LOCATION;\n\n/**\n * The MEMORY_WORKING_SET_EX_BLOCK structure contains extended working set information for a page.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-psapi_working_set_ex_block\n */\ntypedef union _MEMORY_WORKING_SET_EX_BLOCK\n{\n    ULONG_PTR Flags;\n    union\n    {\n        struct\n        {\n            ULONG_PTR Valid : 1;                    // If this bit is 1, the subsequent members are valid; otherwise they should be ignored.\n            ULONG_PTR ShareCount : 3;               // The number of processes that share this page. The maximum value of this member is 7.\n            ULONG_PTR Win32Protection : 11;         // The memory protection attributes of the page.\n            ULONG_PTR Shared : 1;                   // If this bit is 1, the page can be shared.\n            ULONG_PTR Node : 6;                     // The NUMA node. The maximum value of this member is 63.\n            ULONG_PTR Locked : 1;                   // If this bit is 1, the virtual page is locked in physical memory.\n            ULONG_PTR LargePage : 1;                // If this bit is 1, the page is a large page.\n            ULONG_PTR Priority : 3;                 // The memory priority attributes of the page.\n            ULONG_PTR Reserved : 3;\n            ULONG_PTR SharedOriginal : 1;           // If this bit is 1, the page was not modified.\n            ULONG_PTR Bad : 1;                      // If this bit is 1, the page is has been reported as bad.\n#ifdef _WIN64\n            ULONG_PTR Win32GraphicsProtection : 4;  // The memory protection attributes of the page. // since 19H1\n            ULONG_PTR ReservedUlong : 28;\n#endif\n        };\n        struct\n        {\n            ULONG_PTR Valid : 1;                    // If this bit is 0, the subsequent members are valid; otherwise they should be ignored.\n            ULONG_PTR Reserved0 : 14;\n            ULONG_PTR Shared : 1;                   // If this bit is 1, the page can be shared.\n            ULONG_PTR Reserved1 : 5;\n            ULONG_PTR PageTable : 1;                // If this bit is 1, the page is a page table entry.\n            ULONG_PTR Location : 2;                 // The memory location of the page.  MEMORY_WORKING_SET_EX_LOCATION\n            ULONG_PTR Priority : 3;                 // The memory priority of the page.\n            ULONG_PTR ModifiedList : 1;             // If this bit is 1, the page is on the modified standby list.\n            ULONG_PTR Reserved2 : 2;\n            ULONG_PTR SharedOriginal : 1;           // If this bit is 1, the page was not modified.\n            ULONG_PTR Bad : 1;                      // If this bit is 1, the page is has been reported as bad.\n#ifdef _WIN64\n            ULONG_PTR ReservedUlong : 32;\n#endif\n        } Invalid;\n    };\n} MEMORY_WORKING_SET_EX_BLOCK, *PMEMORY_WORKING_SET_EX_BLOCK;\n\n/**\n * The MEMORY_WORKING_SET_EX_INFORMATION structure contains extended working set information for a process.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-psapi_working_set_ex_information\n */\ntypedef struct _MEMORY_WORKING_SET_EX_INFORMATION\n{\n    PVOID VirtualAddress;                             // The virtual address.\n    MEMORY_WORKING_SET_EX_BLOCK VirtualAttributes;    // The attributes of the page at VirtualAddress.\n} MEMORY_WORKING_SET_EX_INFORMATION, *PMEMORY_WORKING_SET_EX_INFORMATION;\n\n/**\n * The MEMORY_SHARED_COMMIT_INFORMATION structure contains the total commit size\n * for a region of memory that is shared between processes.\n */\ntypedef struct _MEMORY_SHARED_COMMIT_INFORMATION\n{\n    SIZE_T CommitSize;\n} MEMORY_SHARED_COMMIT_INFORMATION, *PMEMORY_SHARED_COMMIT_INFORMATION;\n\n// private\ntypedef struct _MEMORY_IMAGE_INFORMATION\n{\n    PVOID ImageBase;\n    SIZE_T SizeOfImage;\n    union\n    {\n        ULONG ImageFlags;\n        struct\n        {\n            ULONG ImagePartialMap : 1;\n            ULONG ImageNotExecutable : 1;\n            ULONG ImageSigningLevel : 4; // REDSTONE3\n            ULONG ImageExtensionPresent : 1; // since 24H2\n            ULONG Reserved : 25;\n        };\n    };\n} MEMORY_IMAGE_INFORMATION, *PMEMORY_IMAGE_INFORMATION;\n\n// private\ntypedef struct _MEMORY_ENCLAVE_IMAGE_INFORMATION\n{\n    MEMORY_IMAGE_INFORMATION ImageInfo;\n    UCHAR UniqueID[32]; // 32-byte unique identifier for the enclave image.\n    UCHAR AuthorID[32]; // 32-byte identifier for the author/creator of the enclave image.\n} MEMORY_ENCLAVE_IMAGE_INFORMATION, *PMEMORY_ENCLAVE_IMAGE_INFORMATION;\n\n/**\n * The MEMORY_PHYSICAL_CONTIGUITY_UNIT_STATE structure describes the eligibility state or contiguity unit.\n */\ntypedef enum _MEMORY_PHYSICAL_CONTIGUITY_UNIT_STATE\n{\n    MemoryNotContiguous,\n    MemoryAlignedAndContiguous,\n    MemoryNotResident,\n    MemoryNotEligibleToMakeContiguous,\n    MemoryContiguityStateMax,\n} MEMORY_PHYSICAL_CONTIGUITY_UNIT_STATE;\n\n/**\n * The MEMORY_PHYSICAL_CONTIGUITY_UNIT_INFORMATION structure describes the per-unit contiguity state.\n */\ntypedef struct _MEMORY_PHYSICAL_CONTIGUITY_UNIT_INFORMATION\n{\n    union\n    {\n        ULONG AllInformation;\n        struct\n        {\n            ULONG State : 2;\n            ULONG Reserved : 30;\n        };\n    };\n} MEMORY_PHYSICAL_CONTIGUITY_UNIT_INFORMATION, *PMEMORY_PHYSICAL_CONTIGUITY_UNIT_INFORMATION;\n\n/**\n * The MEMORY_PHYSICAL_CONTIGUITY_INFORMATION structure describes a virtual range and contiguity unit characteristics for physical contiguity queries.\n */\ntypedef struct _MEMORY_PHYSICAL_CONTIGUITY_INFORMATION\n{\n    PVOID VirtualAddress;\n    ULONG_PTR Size;\n    ULONG_PTR ContiguityUnitSize;\n    ULONG Flags;\n    PMEMORY_PHYSICAL_CONTIGUITY_UNIT_INFORMATION ContiguityUnitInformation;\n} MEMORY_PHYSICAL_CONTIGUITY_INFORMATION, *PMEMORY_PHYSICAL_CONTIGUITY_INFORMATION;\n\n// rev\n/**\n * The MEMORY_BAD_INFORMATION structure reports a range of memory that has been marked bad or otherwise problematic.\n */\ntypedef struct _MEMORY_BAD_INFORMATION\n{\n    PVOID BadAddress; // Starting address of the bad memory range.\n    ULONG_PTR Length; // Length in bytes of the bad range.\n    ULONG Flags;      // Flags describing the nature of the bad memory.\n    ULONG Reserved;\n} MEMORY_BAD_INFORMATION, *PMEMORY_BAD_INFORMATION;\n\n/**\n * The RTL_SCP_CFG_ARM64_HEADER structure contains ARM64 SCP/CFG descriptors; RVAs to handlers\n * and helper routines used when configuring CFG/SCP emulation on ARM64.\n */\ntypedef struct _RTL_SCP_CFG_ARM64_HEADER\n{\n    ULONG EcInvalidCallHandlerRva;        // RVA to invalid EC call handler.\n    ULONG EcCfgCheckRva;                  // RVA to EC CFG check routine.\n    ULONG EcCfgCheckESRva;                // RVA to EC CFG check exception stub RVA.\n    ULONG EcCallCheckRva;                 // RVA to EC call-check routine.\n    ULONG CpuInitializationCompleteLoadRva; // RVA related to CPU init completion load.\n    ULONG LdrpValidateEcCallTargetInitRva; // RVA used by loader validation init.\n    ULONG SyscallFfsSizeRva;               // RVA describing syscall FFS size.\n    ULONG SyscallFfsBaseRva;               // RVA describing syscall FFS base.\n} RTL_SCP_CFG_ARM64_HEADER, *PRTL_SCP_CFG_ARM64_HEADER;\n\n/**\n * The RTL_SCP_CFG_PAGE_TYPE enumeration describes page types used by SCP/CFG image extensions.\n */\ntypedef enum _RTL_SCP_CFG_PAGE_TYPE\n{\n    RtlScpCfgPageTypeNop,                 // No-op / placeholder page.\n    RtlScpCfgPageTypeDefault,             // Default handling page.\n    RtlScpCfgPageTypeExportSuppression,   // Export-suppression descriptor page.\n    RtlScpCfgPageTypeFptr,                // Page that contains function pointers.\n    RtlScpCfgPageTypeMax,                 // Upper bound for the enum.\n    RtlScpCfgPageTypeNone                 // Explicit 'none' value.\n} RTL_SCP_CFG_PAGE_TYPE;\n\n/**\n * The RTL_SCP_CFG_COMMON_HEADER structure contains RVAs to dispatch and check\n * routines used by SCP/CFG configuration blocks.\n */\ntypedef struct _RTL_SCP_CFG_COMMON_HEADER\n{\n    ULONG CfgDispatchRva;         // RVA to CFG dispatch routine.\n    ULONG CfgDispatchESRva;       // RVA to CFG dispatch exception stub.\n    ULONG CfgCheckRva;            // RVA to CFG checking routine.\n    ULONG CfgCheckESRva;          // RVA to CFG checking exception stub.\n    ULONG InvalidCallHandlerRva;  // RVA to invalid-call handler.\n    ULONG FnTableRva;             // RVA to function-pointer table.\n} RTL_SCP_CFG_COMMON_HEADER, *PRTL_SCP_CFG_COMMON_HEADER;\n\n/**\n * The RTL_SCP_CFG_HEADER structure contains the common SCP/CFG configuration header.\n */\ntypedef struct _RTL_SCP_CFG_HEADER\n{\n    RTL_SCP_CFG_COMMON_HEADER Common;\n} RTL_SCP_CFG_HEADER, *PRTL_SCP_CFG_HEADER;\n\n/**\n * The RTL_SCP_CFG_REGION_BOUNDS structure describes inclusive start/end\n * addresses of an SCP/CFG-protected region.\n */\ntypedef struct _RTL_SCP_CFG_REGION_BOUNDS\n{\n    PVOID StartAddress; // Inclusive start address of the region.\n    PVOID EndAddress;   // Inclusive end address of the region.\n} RTL_SCP_CFG_REGION_BOUNDS, *PRTL_SCP_CFG_REGION_BOUNDS;\n\n/**\n * The RTL_SCP_CFG_NTDLL_EXPORTS structure contains ntdll export descriptors and\n * region bounds used to implement or validate CFG/SCP behavior at runtime.\n */\ntypedef struct _RTL_SCP_CFG_NTDLL_EXPORTS\n{\n    RTL_SCP_CFG_REGION_BOUNDS ScpRegions[4]; // Array of SCP region bounds (max 4).\n    PVOID CfgDispatchFptr;                   // Pointer to CFG dispatch function.\n    PVOID CfgDispatchESFptr;                 // Pointer to CFG dispatch exception stub.\n    PVOID CfgCheckFptr;                      // Pointer to CFG check function.\n    PVOID CfgCheckESFptr;                    // Pointer to CFG check exception stub.\n    PVOID IllegalCallHandler;                // Pointer to handler invoked for illegal calls.\n} RTL_SCP_CFG_NTDLL_EXPORTS, *PRTL_SCP_CFG_NTDLL_EXPORTS;\n\n/**\n * The RTL_SCP_CFG_NTDLL_EXPORTS_ARM64EC structure contains ARM64-specific ntdll\n * export descriptors used for EC / ARM64EC handling.\n */\ntypedef struct _RTL_SCP_CFG_NTDLL_EXPORTS_ARM64EC\n{\n    PVOID EcInvalidCallHandler;           // Pointer to invalid EC call handler.\n    PVOID EcCfgCheckFptr;                 // Pointer to EC CFG check function.\n    PVOID EcCfgCheckESFptr;               // Pointer to EC CFG check exception stub.\n    PVOID EcCallCheckFptr;                // Pointer to EC call-check routine.\n    PVOID CpuInitializationComplete;      // Pointer to CPU initialization completion routine.\n    PVOID LdrpValidateEcCallTargetInit;   // Pointer to loader validation init routine.\n    struct\n    {\n        PVOID SyscallFfsSize;             // Pointer to syscall FFS size descriptor.\n        union\n        {\n            PVOID Ptr;                    // Pointer form of FFS size descriptor.\n            ULONG Value;                  // Value form of FFS size descriptor.\n        };\n    };\n    PVOID SyscallFfsBase;                 // Pointer to syscall FFS base.\n} RTL_SCP_CFG_NTDLL_EXPORTS_ARM64EC, *PRTL_SCP_CFG_NTDLL_EXPORTS_ARM64EC;\n\n/**\n * The RTL_RETPOLINE_ROUTINES structure contains indices/offsets and jump-table\n * descriptors used for retpoline/runtime patching.\n */\ntypedef struct _RTL_RETPOLINE_ROUTINES\n{\n    ULONG SwitchtableJump[16]; // Jump offsets for switchtable entries.\n    ULONG CfgIndirectRax;      // Index/offset for indirect calls using RAX under CFG.\n    ULONG NonCfgIndirectRax;   // Index/offset for indirect calls not under CFG.\n    ULONG ImportR10;           // Import slot/index for R10-based imports.\n    ULONG JumpHpat;            // Hot-spot jump table offset.\n} RTL_RETPOLINE_ROUTINES, *PRTL_RETPOLINE_ROUTINES;\n\n/**\n * The RTL_KSCP_ROUTINES structure contains the kernel-side\n * SCP-related routine descriptors used for XFG/CFG/retpoline support.\n */\ntypedef struct _RTL_KSCP_ROUTINES\n{\n    ULONG UnwindDataOffset;  // Offset to unwind data for the routines.\n    RTL_RETPOLINE_ROUTINES RetpolineRoutines;\n    ULONG CfgDispatchSmep;   // CFG dispatch variant when SMEP is enabled.\n    ULONG CfgDispatchNoSmep; // CFG dispatch variant when SMEP is not enabled.\n} RTL_KSCP_ROUTINES, *PRTL_KSCP_ROUTINES;\n\n/**\n * The MEMORY_IMAGE_EXTENSION_TYPE enumeration specifies the supported image extension types.\n */\ntypedef enum _MEMORY_IMAGE_EXTENSION_TYPE\n{\n    MemoryImageExtensionCfgScp,\n    MemoryImageExtensionCfgEmulatedScp,\n    MemoryImageExtensionTypeMax,\n} MEMORY_IMAGE_EXTENSION_TYPE;\n\n/**\n * The MEMORY_IMAGE_EXTENSION_INFORMATION structure describes an optional image extension\n * containing additional metadata or features (for example, CFG/SCP related extensions).\n */\ntypedef struct _MEMORY_IMAGE_EXTENSION_INFORMATION\n{\n    MEMORY_IMAGE_EXTENSION_TYPE ExtensionType; // Type of the image extension (MEMORY_IMAGE_EXTENSION_TYPE).\n    ULONG Flags;                               // Extension-specific flags.\n    PVOID ExtensionImageBaseRva;               // Relative virtual address of the extension image base.\n    SIZE_T ExtensionSize;                      // Size, in bytes, of the extension region.\n} MEMORY_IMAGE_EXTENSION_INFORMATION, *PMEMORY_IMAGE_EXTENSION_INFORMATION;\n\n#define MMPFNLIST_ZERO 0\n#define MMPFNLIST_FREE 1\n#define MMPFNLIST_STANDBY 2\n#define MMPFNLIST_MODIFIED 3\n#define MMPFNLIST_MODIFIEDNOWRITE 4\n#define MMPFNLIST_BAD 5\n#define MMPFNLIST_ACTIVE 6\n#define MMPFNLIST_TRANSITION 7\n\n//typedef enum _MMLISTS\n//{\n//    ZeroedPageList = 0,\n//    FreePageList = 1,\n//    StandbyPageList = 2,\n//    ModifiedPageList = 3,\n//    ModifiedNoWritePageList = 4,\n//    BadPageList = 5,\n//    ActiveAndValid = 6,\n//    TransitionPage = 7\n//} MMLISTS;\n\n#define MMPFNUSE_PROCESSPRIVATE 0\n#define MMPFNUSE_FILE 1\n#define MMPFNUSE_PAGEFILEMAPPED 2\n#define MMPFNUSE_PAGETABLE 3\n#define MMPFNUSE_PAGEDPOOL 4\n#define MMPFNUSE_NONPAGEDPOOL 5\n#define MMPFNUSE_SYSTEMPTE 6\n#define MMPFNUSE_SESSIONPRIVATE 7\n#define MMPFNUSE_METAFILE 8\n#define MMPFNUSE_AWEPAGE 9\n#define MMPFNUSE_DRIVERLOCKPAGE 10\n#define MMPFNUSE_KERNELSTACK 11\n\n//typedef enum _MMPFNUSE\n//{\n//    ProcessPrivatePage,\n//    MemoryMappedFilePage,\n//    PageFileMappedPage,\n//    PageTablePage,\n//    PagedPoolPage,\n//    NonPagedPoolPage,\n//    SystemPTEPage,\n//    SessionPrivatePage,\n//    MetafilePage,\n//    AWEPage,\n//    DriverLockedPage,\n//    KernelStackPage\n//} MMPFNUSE;\n\n// private\ntypedef struct _MEMORY_FRAME_INFORMATION\n{\n    ULONGLONG UseDescription : 4; // MMPFNUSE_*\n    ULONGLONG ListDescription : 3; // MMPFNLIST_*\n    ULONGLONG Cold : 1; // 19H1\n    ULONGLONG Pinned : 1; // 1 - pinned, 0 - not pinned\n    ULONGLONG DontUse : 48; // *_INFORMATION overlay\n    ULONGLONG Priority : 3;\n    ULONGLONG NonTradeable : 1;\n    ULONGLONG Reserved : 3;\n} MEMORY_FRAME_INFORMATION, *PMEMORY_FRAME_INFORMATION;\n\n// private\ntypedef struct _FILEOFFSET_INFORMATION\n{\n    ULONGLONG DontUse : 9; // MEMORY_FRAME_INFORMATION overlay\n    ULONGLONG Offset : 48; // mapped files\n    ULONGLONG Reserved : 7;\n} FILEOFFSET_INFORMATION, *PFILEOFFSET_INFORMATION;\n\n// private\ntypedef struct _PAGEDIR_INFORMATION\n{\n    ULONGLONG DontUse : 9; // MEMORY_FRAME_INFORMATION overlay\n    ULONGLONG PageDirectoryBase : 48; // private pages\n    ULONGLONG Reserved : 7;\n} PAGEDIR_INFORMATION, *PPAGEDIR_INFORMATION;\n\n// private\ntypedef struct _UNIQUE_PROCESS_INFORMATION\n{\n    ULONGLONG DontUse : 9; // MEMORY_FRAME_INFORMATION overlay\n    ULONGLONG UniqueProcessKey : 48; // ProcessId\n    ULONGLONG Reserved  : 7;\n} UNIQUE_PROCESS_INFORMATION, *PUNIQUE_PROCESS_INFORMATION;\n\n// private\ntypedef struct _MMPFN_IDENTITY\n{\n    union\n    {\n        MEMORY_FRAME_INFORMATION e1; // all\n        FILEOFFSET_INFORMATION e2; // mapped files\n        PAGEDIR_INFORMATION e3; // private pages\n        UNIQUE_PROCESS_INFORMATION e4; // owning process\n    } u1;\n    ULONG_PTR PageFrameIndex; // all\n    union\n    {\n        struct\n        {\n            ULONG_PTR Image : 1;\n            ULONG_PTR Mismatch : 1;\n        } e1;\n        struct\n        {\n            ULONG_PTR CombinedPage;\n        } e2;\n        ULONG_PTR FileObject; // mapped files\n        ULONG_PTR UniqueFileObjectKey;\n        ULONG_PTR ProtoPteAddress;\n        ULONG_PTR VirtualAddress;  // everything else\n    } u2;\n} MMPFN_IDENTITY, *PMMPFN_IDENTITY;\n\ntypedef struct _MMPFN_MEMSNAP_INFORMATION\n{\n    ULONG_PTR InitialPageFrameIndex;\n    ULONG_PTR Count;\n} MMPFN_MEMSNAP_INFORMATION, *PMMPFN_MEMSNAP_INFORMATION;\n\n// Flags directly correspond to KPROCESS.Flags, of type KEXECUTE_OPTIONS (named bitfields available).\n// Flags adjust OS behavior for 32-bit processes only. They are effectively ignored for ARM64 and x64 processes.\n// [nt!Mi]canGrantExecute = KF_GLOBAL_32BIT_EXECUTE || MEM_EXECUTE_OPTION_ENABLE || (!KF_GLOBAL_32BIT_NOEXECUTE && !MEM_EXECUTE_OPTION_DISABLE)\n#define MEM_EXECUTE_OPTION_DISABLE 0x1      // respect the NX bit: DEP on, only run code from executable pages\n#define MEM_EXECUTE_OPTION_ENABLE 0x2       // ignore the NX bit: DEP off, enable executing most of ro/rw memory; trumps over the _DISABLE option\n#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION 0x4  // do not emulate NX code sequences which look like ATL thunks\n#define MEM_EXECUTE_OPTION_PERMANENT 0x8                // changing any MEM_EXECUTE_* option for the process is not allowed [anymore]\n#define MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE 0x10 // allow non-executable exception handlers (ntdll!RtlIsValidHandler)\n#define MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE 0x20   // allow non-MEM_IMAGE exception handlers (ntdll!RtlIsValidHandler)\n#define MEM_EXECUTE_OPTION_DISABLE_EXCEPTION_CHAIN_VALIDATION 0x40  // don't invoke ntdll!RtlpIsValidExceptionChain to check SEH chain\n#define MEM_EXECUTE_OPTION_VALID_FLAGS 0x7f\n\n//\n// Virtual memory\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * The NtAllocateVirtualMemory routine reserves, commits, or both, a region of pages within the user-mode virtual address space of a specified process.\n *\n * \\param ProcessHandle A handle for the process for which the mapping should be done.\n * \\param BaseAddress A pointer to a variable that will receive the base address of the allocated region of pages.\n * If the initial value is not zero, the region is allocated at the specified virtual address.\n * \\param ZeroBits The number of high-order address bits that must be zero in the base address of the section view.\n * This value must be less than 21 and the initial value of BaseAddress must be zero.\n * \\param RegionSize A pointer to a variable that will receive the actual size, in bytes, of the allocated region of pages.\n * \\param AllocationType A bitmask containing flags that specify the type of allocation to be performed.\n * \\param PageProtection A bitmask containing page protection flags that specify the protection desired for the committed region of pages.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwallocatevirtualmemory\n */\n_Must_inspect_result_\n_When_(return == 0, __drv_allocatesMem(mem))\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID *BaseAddress,\n    _In_ ULONG_PTR ZeroBits,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG AllocationType,\n    _In_ ULONG PageProtection\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS5)\n/**\n * The NtAllocateVirtualMemoryEx routine reserves, commits, or both, a region of pages within the user-mode virtual address space of a specified process.\n *\n * \\param ProcessHandle A handle for the process for which the mapping should be done.\n * \\param BaseAddress A pointer to a variable that will receive the base address of the allocated region of pages. If the initial value is not zero, the region is allocated at the specified virtual address.\n * \\param RegionSize A pointer to a variable that will receive the actual size, in bytes, of the allocated region of pages.\n * \\param AllocationType A bitmask containing flags that specify the type of allocation to be performed.\n * \\param PageProtection A bitmask containing page protection flags that specify the protection desired for the committed region of pages.\n * \\param ExtendedParameters An optional pointer to one or more extended parameters of type MEM_EXTENDED_PARAMETER.\n * \\param ExtendedParameterCount Specifies the number of elements in the ExtendedParameters array.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwallocatevirtualmemory\n */\n_Must_inspect_result_\n_When_(return == 0, __drv_allocatesMem(Mem))\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateVirtualMemoryEx(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG AllocationType,\n    _In_ ULONG PageProtection,\n    _Inout_updates_opt_(ExtendedParameterCount) PMEM_EXTENDED_PARAMETER ExtendedParameters,\n    _In_ ULONG ExtendedParameterCount\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_RS5)\n\n/**\n * The NtFreeVirtualMemory routine frees virtual memory allocated for a process.\n *\n * \\param ProcessHandle A handle to the process whose virtual memory is to be freed.\n * \\param BaseAddress A pointer to the base address of the region of pages to be freed.\n * \\param RegionSize A pointer to a variable that specifies the size of the region of memory to be freed.\n * \\param FreeType The type of free operation. This parameter can be MEM_DECOMMIT or MEM_RELEASE.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFreeVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ __drv_freesMem(Mem) PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG FreeType\n    );\n\n /**\n * The NtReadVirtualMemory routine reads virtual memory from a process.\n *\n * \\param ProcessHandle A handle to the process whose memory is to be read.\n * \\param BaseAddress A pointer to the base address in the specified process from which to read.\n * \\param Buffer A pointer to a buffer that receives the contents from the address space of the specified process.\n * \\param NumberOfBytesToRead The number of bytes to be read from the specified process.\n * \\param NumberOfBytesRead A pointer to a variable that receives the number of bytes transferred into the specified buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _Out_writes_bytes_to_(NumberOfBytesToRead, *NumberOfBytesRead) PVOID Buffer,\n    _In_ SIZE_T NumberOfBytesToRead,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    );\n\n// rev\n/**\n * The NtWow64ReadVirtualMemory64 routine reads virtual memory of a 64-bit process from a 32-bit process.\n *\n * \\param ProcessHandle A handle to the process whose memory is to be read.\n * \\param BaseAddress A pointer to the base address in the specified process from which to read.\n * \\param Buffer A pointer to a buffer that receives the contents from the address space of the specified process.\n * \\param NumberOfBytesToRead The number of bytes to be read from the specified process.\n * \\param NumberOfBytesRead A pointer to a variable that receives the number of bytes transferred into the specified buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nNtWow64ReadVirtualMemory64(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ ULONGLONG BaseAddress,\n    _Out_writes_bytes_to_(NumberOfBytesToRead, *NumberOfBytesRead) PVOID Buffer,\n    _In_ ULONGLONG NumberOfBytesToRead,\n    _Out_opt_ PULONGLONG NumberOfBytesRead\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\n/**\n * The NtReadVirtualMemoryEx routine reads virtual memory from a process with extended options.\n *\n * \\param ProcessHandle A handle to the process whose memory is to be read.\n * \\param BaseAddress A pointer to the base address in the specified process from which to read.\n * \\param Buffer A pointer to a buffer that receives the contents from the address space of the specified process.\n * \\param NumberOfBytesToRead The number of bytes to be read from the specified process.\n * \\param NumberOfBytesRead A pointer to a variable that receives the number of bytes transferred into the specified buffer.\n * \\param Flags Additional flags for the read operation.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadVirtualMemoryEx(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _Out_writes_bytes_to_(NumberOfBytesToRead, *NumberOfBytesRead) PVOID Buffer,\n    _In_ SIZE_T NumberOfBytesToRead,\n    _Out_opt_ PSIZE_T NumberOfBytesRead,\n    _In_ ULONG Flags\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_11)\n\n/**\n * The NtWriteVirtualMemory routine writes virtual memory to a process.\n *\n * \\param ProcessHandle A handle to the process whose memory is to be written.\n * \\param BaseAddress A pointer to the base address in the specified process to which to write.\n * \\param Buffer A pointer to the buffer that contains the data to be written to the address space of the specified process.\n * \\param NumberOfBytesToWrite The number of bytes to be written to the specified process.\n * \\param NumberOfBytesWritten A pointer to a variable that receives the number of bytes transferred into the specified buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWriteVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_reads_bytes_(NumberOfBytesToWrite) PVOID Buffer,\n    _In_ SIZE_T NumberOfBytesToWrite,\n    _Out_opt_ PSIZE_T NumberOfBytesWritten\n    );\n\n// rev\n/**\n * The NtWow64WriteVirtualMemory64 routine writes virtual memory to a 64-bit process from a 32-bit process.\n *\n * \\param ProcessHandle A handle to the process whose memory is to be written.\n * \\param BaseAddress A pointer to the base address in the specified process to which to write.\n * \\param Buffer A pointer to the buffer that contains the data to be written to the address space of the specified process.\n * \\param NumberOfBytesToWrite The number of bytes to be written to the specified process.\n * \\param NumberOfBytesWritten A pointer to a variable that receives the number of bytes transferred into the specified buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nNtWow64WriteVirtualMemory64(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ ULONGLONG BaseAddress,\n    _In_reads_bytes_(NumberOfBytesToWrite) PVOID Buffer,\n    _In_ ULONGLONG NumberOfBytesToWrite,\n    _Out_opt_ PULONGLONG NumberOfBytesWritten\n    );\n\n/**\n * The NtProtectVirtualMemory routine changes the protection on a region of virtual memory.\n *\n * \\param ProcessHandle A handle to the process whose memory protection is to be changed.\n * \\param BaseAddress A pointer to the base address of the region of pages whose access protection attributes are to be changed.\n * \\param RegionSize A pointer to a variable that specifies the size of the region whose access protection attributes are to be changed.\n * \\param NewProtection The memory protection option. This parameter can be one of the memory protection constants.\n * \\param OldProtection A pointer to a variable that receives the previous access protection of the first page in the specified region of pages.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtProtectVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG NewProtection,\n    _Out_ PULONG OldProtection\n    );\n\n/**\n * The NtQueryVirtualMemory routine queries information about a region of virtual memory in a process.\n *\n * \\param ProcessHandle A handle to the process whose memory information is to be queried.\n * \\param BaseAddress A pointer to the base address of the region of pages to be queried.\n * \\param MemoryInformationClass The type of information to be queried.\n * \\param MemoryInformation A pointer to a buffer that receives the memory information.\n * \\param MemoryInformationLength The size of the buffer pointed to by the MemoryInformation parameter.\n * \\param ReturnLength A pointer to a variable that receives the number of bytes returned in the MemoryInformation buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ MEMORY_INFORMATION_CLASS MemoryInformationClass,\n    _Out_writes_bytes_(MemoryInformationLength) PVOID MemoryInformation,\n    _In_ SIZE_T MemoryInformationLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\n// rev\n/**\n * The NtWow64QueryVirtualMemory64 routine queries information about a region of virtual memory in a 64-bit process from a 32-bit process.\n *\n * \\param ProcessHandle A handle to the process whose memory information is to be queried.\n * \\param BaseAddress A pointer to the base address of the region of pages to be queried.\n * \\param MemoryInformationClass The type of information to be queried.\n * \\param MemoryInformation A pointer to a buffer that receives the memory information.\n * \\param MemoryInformationLength The size of the buffer pointed to by the MemoryInformation parameter.\n * \\param ReturnLength A pointer to a variable that receives the number of bytes returned in the MemoryInformation buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nNtWow64QueryVirtualMemory64(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ ULONGLONG BaseAddress,\n    _In_ MEMORY_INFORMATION_CLASS MemoryInformationClass,\n    _Out_writes_bytes_(MemoryInformationLength) PVOID MemoryInformation,\n    _In_ ULONGLONG MemoryInformationLength,\n    _Out_opt_ PULONGLONG ReturnLength\n    );\n\n/**\n * The NtFlushVirtualMemory routine flushes the instruction cache for a specified process.\n *\n * \\param ProcessHandle A handle to the process whose instruction cache is to be flushed.\n * \\param BaseAddress A pointer to the base address of the memory region to be flushed.\n * \\param RegionSize A pointer to a variable that specifies the size of the region to be flushed.\n * \\param IoStatus A pointer to an IO_STATUS_BLOCK structure that receives the status of the flush operation.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _Out_ PIO_STATUS_BLOCK IoStatus\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n// begin_private\ntypedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS\n{\n    VmPrefetchInformation,                      // s: MEMORY_PREFETCH_INFORMATION\n    VmPagePriorityInformation,                  // s: MEMORY_PAGE_PRIORITY_INFORMATION\n    VmCfgCallTargetInformation,                 // s: CFG_CALL_TARGET_LIST_INFORMATION // REDSTONE2\n    VmPageDirtyStateInformation,                // s: MEMORY_PAGE_DIRTY_STATE_INFORMATION // REDSTONE3\n    VmImageHotPatchInformation,                 // s: 19H1\n    VmPhysicalContiguityInformation,            // s: MEMORY_PHYSICAL_CONTIGUITY_INFORMATION // 20H1 // (requires SeLockMemoryPrivilege)\n    VmVirtualMachinePrepopulateInformation,\n    VmRemoveFromWorkingSetInformation,          // s: MEMORY_REMOVE_WORKING_SET_INFORMATION\n    MaxVmInfoClass\n} VIRTUAL_MEMORY_INFORMATION_CLASS;\n// end_private\n#else\n#define VmPrefetchInformation 0x0\n#define VmPagePriorityInformation 0x1\n#define VmCfgCallTargetInformation 0x2\n#define VmPageDirtyStateInformation 0x3\n#define VmImageHotPatchInformation 0x4\n#define VmPhysicalContiguityInformation 0x5\n#define VmVirtualMachinePrepopulateInformation 0x6\n#define VmRemoveFromWorkingSetInformation 0x7\n#define MaxVmInfoClass 0x8\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * Attempt to populate specified single or multiple address ranges\n * into the process working set (bring pages into physical memory).\n */\n#define VM_PREFETCH_TO_WORKING_SET 0x1 // since 24H4\n\n// rev\n/**\n * The MEMORY_PREFETCH_INFORMATION structure defines prefetch-control flags that\n * determine how prefetch operations are executed on the supplied address ranges.\n *\n * \\remarks The behavior and success of prefetch operations depend on OS policy,\n * working set limits, privileges, and presence of backing storage.\n * \\sa NtSetInformationVirtualMemory, VIRTUAL_MEMORY_INFORMATION_CLASS, VmPrefetchInformation\n */\ntypedef struct _MEMORY_PREFETCH_INFORMATION\n{\n    ULONG Flags;\n} MEMORY_PREFETCH_INFORMATION, *PMEMORY_PREFETCH_INFORMATION;\n\n//\n// Page/memory priorities.\n//\n\n#define MEMORY_PRIORITY_LOWEST           0\n#define MEMORY_PRIORITY_VERY_LOW         1\n#define MEMORY_PRIORITY_LOW              2\n#define MEMORY_PRIORITY_MEDIUM           3\n#define MEMORY_PRIORITY_BELOW_NORMAL     4\n#define MEMORY_PRIORITY_NORMAL           5\n#define MEMORY_PRIORITY_ABOVE_NORMAL     6 // rev\n#define MEMORY_PRIORITY_HIGH             7 // rev\n\n// VmPagePriorityInformation\ntypedef struct _MEMORY_PAGE_PRIORITY_INFORMATION\n{\n    ULONG PagePriority;\n} MEMORY_PAGE_PRIORITY_INFORMATION, *PMEMORY_PAGE_PRIORITY_INFORMATION;\n\n// VmCfgCallTargetInformation\ntypedef struct _CFG_CALL_TARGET_LIST_INFORMATION\n{\n    ULONG NumberOfEntries;\n    ULONG Reserved;\n    PULONG NumberOfEntriesProcessed;\n    PCFG_CALL_TARGET_INFO CallTargetInfo;\n    PVOID Section; // since REDSTONE5\n    ULONGLONG FileOffset;\n} CFG_CALL_TARGET_LIST_INFORMATION, *PCFG_CALL_TARGET_LIST_INFORMATION;\n\n// rev\n// VmPageDirtyStateInformation\ntypedef struct _MEMORY_PAGE_DIRTY_STATE_INFORMATION\n{\n    ULONG Flags;\n} MEMORY_PAGE_DIRTY_STATE_INFORMATION, *PMEMORY_PAGE_DIRTY_STATE_INFORMATION;\n\n// rev\ntypedef struct _MEMORY_REMOVE_WORKING_SET_INFORMATION\n{\n    ULONG Flags;\n} MEMORY_REMOVE_WORKING_SET_INFORMATION, *PMEMORY_REMOVE_WORKING_SET_INFORMATION;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n/**\n * The MEMORY_RANGE_ENTRY structure describes a contiguous region of virtual address space.\n */\ntypedef struct _MEMORY_RANGE_ENTRY\n{\n    PVOID VirtualAddress;        // A pointer to the starting virtual address of the region.\n    SIZE_T NumberOfBytes;        // The size, in bytes, of the region.\n} MEMORY_RANGE_ENTRY, *PMEMORY_RANGE_ENTRY;\n\n/**\n * The NtSetInformationVirtualMemory routine performs an operation on a specified list of address ranges in the user address space of a process.\n *\n * \\param ProcessHandle Specifies an open handle for the process in the context of which the operation is to be performed. This handle cannot be invalid.\n * \\param VmInformationClass Specifies the type of operation to perform.\n * \\param NumberOfEntries Number of entries in the array pointed to by the VirtualAddresses parameter. This parameter cannot be 0.\n * \\param VirtualAddresses Pointer to an array of MEMORY_RANGE_ENTRY structures in which each entry specifies a virtual address range to be processed.\n * The virtual address ranges may cover any part of the process address space accessible by the target process.\n * \\param VmInformation A pointer to a buffer that contains memory information.\n * Note: If VmInformationClass is VmPrefetchInformation, this parameter cannot be this parameter cannot be NULL and must point to a ULONG variable that is set to 0.\n * \\param VmInformationLength The size of the buffer pointed to by VmInformation.\n * If VmInformationClass is VmPrefetchInformation, this must be sizeof (ULONG).\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwsetinformationvirtualmemory\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ VIRTUAL_MEMORY_INFORMATION_CLASS VmInformationClass,\n    _In_ SIZE_T NumberOfEntries,\n    _In_reads_(NumberOfEntries) PMEMORY_RANGE_ENTRY VirtualAddresses,\n    _In_reads_bytes_(VmInformationLength) PVOID VmInformation,\n    _In_ ULONG VmInformationLength\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n#define MAP_PROCESS 1 // Process WorkingSet\n#define MAP_SYSTEM 2 // Physical Memory // (requires SeLockMemoryPrivilege)\n\n/**\n * The NtLockVirtualMemory routine locks the specified region of the process's virtual address space into physical memory,\n * ensuring that subsequent access to the region will not incur a page fault.\n *\n * \\param ProcessHandle A handle to the process whose virtual address space is to be locked.\n * \\param BaseAddress A pointer to the base address of the region of pages to be locked.\n * \\param RegionSize The size of the region to be locked, in bytes. The size is rounded up to the nearest multiple of PAGE_SIZE.\n * \\param MapType A bitmask containing one or more flags that specify the type of operations to be performed.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtuallock\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLockVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG MapType\n    );\n\n/**\n * The NtUnlockVirtualMemory routine unlocks a specified range of pages in the virtual address space of a process,\n * enabling the system to swap the pages out to the paging file if necessary.\n *\n * \\param ProcessHandle A handle to the process whose virtual address space is to be unlocked.\n * \\param BaseAddress A pointer to the base address of the region of pages to be unlocked.\n * \\param RegionSize The size of the region to be unlocked, in bytes. The size is rounded up to the nearest multiple of PAGE_SIZE.\n * \\param MapType A bitmask containing one or more flags that specify the type of operations to be performed.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualunlock\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnlockVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG MapType\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Sections\n//\n\ntypedef enum _SECTION_INFORMATION_CLASS\n{\n    SectionBasicInformation, // q; SECTION_BASIC_INFORMATION\n    SectionImageInformation, // q; SECTION_IMAGE_INFORMATION\n    SectionRelocationInformation, // q; ULONG_PTR RelocationDelta // name:wow64:whNtQuerySection_SectionRelocationInformation // since WIN7\n    SectionOriginalBaseInformation, // q; PVOID BaseAddress // since REDSTONE\n    SectionInternalImageInformation, // q; SECTION_INTERNAL_IMAGE_INFORMATION // since REDSTONE2\n    MaxSectionInfoClass\n} SECTION_INFORMATION_CLASS;\n\n/**\n * The SECTION_BASIC_INFORMATION structure contains basic information about an image section.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/devnotes/ntquerysection\n */\ntypedef struct _SECTION_BASIC_INFORMATION\n{\n    PVOID BaseAddress;              // The base virtual address of the section if the section is based.\n    ULONG AllocationAttributes;     // The allocation attributes flags.\n    LARGE_INTEGER MaximumSize;      // The maximum size of the section in bytes.\n} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;\n\n/**\n * The SECTION_IMAGE_INFORMATION structure contains detailed information about an image section.\n */\ntypedef struct _SECTION_IMAGE_INFORMATION\n{\n    PVOID TransferAddress;          // The address of the image entry point function.\n    ULONG ZeroBits;                 // The number of high-order address bits that must be zero in the image base address.\n    SIZE_T MaximumStackSize;        // The maximum stack size of threads from the PE file header.\n    SIZE_T CommittedStackSize;      // The initial stack size of threads from the PE file header.\n    ULONG SubSystemType;            // The image subsystem from the PE file header (e.g., Windows GUI, Windows CUI, POSIX).\n    union\n    {\n        struct\n        {\n            USHORT SubSystemMinorVersion;\n            USHORT SubSystemMajorVersion;\n        };\n        ULONG SubSystemVersion;\n    };\n    union\n    {\n        struct\n        {\n            USHORT MajorOperatingSystemVersion;\n            USHORT MinorOperatingSystemVersion;\n        };\n        ULONG OperatingSystemVersion;\n    };\n    USHORT ImageCharacteristics;    // The image characteristics from the PE file header.\n    USHORT DllCharacteristics;      // The DLL characteristics flags (e.g., ASLR, NX compatibility).\n    USHORT Machine;                 // The image architecture (e.g., x86, x64, ARM).\n    BOOLEAN ImageContainsCode;      // The image contains native executable code.\n    union\n    {\n        UCHAR ImageFlags;\n        struct\n        {\n            UCHAR ComPlusNativeReady : 1;           // The image contains precompiled .NET assembly generated by NGEN (Native Image Generator).\n            UCHAR ComPlusILOnly : 1;                // the image contains only Microsoft Intermediate Language (IL) assembly.\n            UCHAR ImageDynamicallyRelocated : 1;    // The image was mapped using a random base address rather than the preferred base address.\n            UCHAR ImageMappedFlat : 1;              // The image was mapped using a single contiguous region, rather than separate regions for each section.\n            UCHAR BaseBelow4gb : 1;                 // The image was mapped using a base address below the 4 GB boundary.\n            UCHAR ComPlusPrefer32bit : 1;           // The image prefers to run as a 32-bit process, even on a 64-bit system.\n            UCHAR Reserved : 2;\n        };\n    };\n    ULONG LoaderFlags;               // Reserved by ntdll.dll for the Windows loader.\n    ULONG ImageFileSize;             // The size of the image, in bytes, including all headers.\n    ULONG CheckSum;                  // The image file checksum, from the PE optional header.\n} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;\n\n/**\n * The SECTION_INTERNAL_IMAGE_INFORMATION structure contains information about Control Flow Guard (CFG) features required by the image section.\n */\ntypedef struct _SECTION_INTERNAL_IMAGE_INFORMATION\n{\n    SECTION_IMAGE_INFORMATION SectionInformation;\n    union\n    {\n        ULONG ExtendedFlags;\n        struct\n        {\n            ULONG ImageExportSuppressionEnabled : 1;\n            ULONG ImageCetShadowStacksReady : 1; // 20H1\n            ULONG ImageXfgEnabled : 1; // 20H2\n            ULONG ImageCetShadowStacksStrictMode : 1;\n            ULONG ImageCetSetContextIpValidationRelaxedMode : 1;\n            ULONG ImageCetDynamicApisAllowInProc : 1;\n            ULONG ImageCetDowngradeReserved1 : 1;\n            ULONG ImageCetDowngradeReserved2 : 1;\n            ULONG ImageExportSuppressionInfoPresent : 1;\n            ULONG ImageCfgEnabled : 1;\n            ULONG Reserved : 22;\n        };\n    };\n} SECTION_INTERNAL_IMAGE_INFORMATION, *PSECTION_INTERNAL_IMAGE_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n/**\n * The SECTION_INHERIT structure specifies how the mapped view of the section is to be shared with child processes.\n */\ntypedef enum _SECTION_INHERIT\n{\n    ViewShare = 1, // The mapped view of the section will be mapped into any child processes created by the process.\n    ViewUnmap = 2  // The mapped view of the section will not be mapped into any child processes created by the process.\n} SECTION_INHERIT;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n/**\n * The NtCreateSection routine creates a section object.\n *\n * \\param SectionHandle Pointer to a variable that receives a handle to the section object.\n * \\param DesiredAccess The access mask that specifies the requested access to the section object.\n * \\param ObjectAttributes Pointer to the base virtual address of the view to unmap. This value can be any virtual address within the view.\n * \\param MaximumSize The maximum size, in bytes, of the section. The actual size when backed by the paging file,\n * or the maximum the file can be extended or mapped when backed by an ordinary file.\n * \\param SectionPageProtection Specifies the protection to place on each page in the section.\n * \\param AllocationAttributes A bitmask of SEC_XXX flags that determines the allocation attributes of the section.\n * \\param FileHandle Optionally specifies a handle for an open file object. If the value of FileHandle is NULL,\n * the section is backed by the paging file. Otherwise, the section is backed by the specified file.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwcreatesection\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG SectionPageProtection,\n    _In_ ULONG AllocationAttributes,\n    _In_opt_ HANDLE FileHandle\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS5)\n/**\n * The NtCreateSectionEx routine creates a section object.\n *\n * \\param SectionHandle Pointer to a variable that receives a handle to the section object.\n * \\param DesiredAccess The access mask that specifies the requested access to the section object.\n * \\param ObjectAttributes Pointer to the base virtual address of the view to unmap. This value can be any virtual address within the view.\n * \\param MaximumSize The maximum size, in bytes, of the section. The actual size when backed by the paging file,\n * or the maximum the file can be extended or mapped when backed by an ordinary file.\n * \\param SectionPageProtection Specifies the protection to place on each page in the section.\n * \\param AllocationAttributes A bitmask of SEC_XXX flags that determines the allocation attributes of the section.\n * \\param FileHandle Optionally specifies a handle for an open file object. If the value of FileHandle is NULL,\n * the section is backed by the paging file. Otherwise, the section is backed by the specified file.\n * \\param ExtendedParameters An optional pointer to one or more extended parameters of type MEM_EXTENDED_PARAMETER.\n * \\param ExtendedParameterCount Specifies the number of elements in the ExtendedParameters array.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwcreatesection\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateSectionEx(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG SectionPageProtection,\n    _In_ ULONG AllocationAttributes,\n    _In_opt_ HANDLE FileHandle,\n    _Inout_updates_opt_(ExtendedParameterCount) PMEM_EXTENDED_PARAMETER ExtendedParameters,\n    _In_ ULONG ExtendedParameterCount\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_RS5)\n\n/**\n * The NtOpenSection routine opens a handle for an existing section object.\n *\n * \\param SectionHandle Handle to a process object that was previously passed to NtMapViewOfSection.\n * \\param DesiredAccess The access mask that specifies the requested access to the section object.\n * \\param ObjectAttributes Pointer to an OBJECT_ATTRIBUTES structure that specifies the object name and other attributes.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwopensection\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The NtMapViewOfSection routine maps a view of a section into the virtual address space of a subject process.\n *\n * \\param SectionHandle A handle to an existing section object.\n * \\param ProcessHandle A handle to the object that represents the process that the view should be mapped into. The handle must have been opened with PROCESS_VM_OPERATION access.\n * \\param BaseAddress A pointer to a variable that receives the base address of the view. If the value is not NULL, the view is allocated starting at the specified virtual address rounded down to the next 64-kilobyte address boundary.\n * \\param ZeroBits The number of high-order address bits that must be zero in the base address of the section view. The value of this parameter must be less than 21 and is used only if BaseAddress is NULL.\n * \\param CommitSize Specifies the size, in bytes, of the initially committed region of the view. CommitSize is meaningful only for page-file backed sections and is rounded up to the nearest multiple of PAGE_SIZE.\n * \\param SectionOffset A pointer to a variable that receives the offset, in bytes, from the beginning of the section to the view.\n * \\param ViewSize A pointer to a variable that specifies the size of the view in bytes. If the initial value is zero, NtMapViewOfSection maps a view of the section that starts at SectionOffset and continues to the end of the section.\n * \\param InheritDisposition A value that specifies how the view is to be shared with child processes.\n * \\param AllocationType Specifies the type of allocation to be performed for the specified region of pages. The valid flags are MEM_RESERVE, MEM_TOP_DOWN, MEM_LARGE_PAGES, MEM_DIFFERENT_IMAGE_BASE_OK and MEM_REPLACE_PLACEHOLDER. Although MEM_COMMIT is not allowed, it is implied unless MEM_RESERVE is specified.\n * \\param PageProtection Specifies the page protection to be applied to the mapped view. Not used with SEC_IMAGE, must be set to PAGE_READONLY for SEC_IMAGE_NO_EXECUTE. For non-image sections, the value must be compatible with the section's page protection from NtCreateSection.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwmapviewofsection\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMapViewOfSection(\n    _In_ HANDLE SectionHandle,\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress,\n    _In_ ULONG_PTR ZeroBits,\n    _In_ SIZE_T CommitSize,\n    _Inout_opt_ PLARGE_INTEGER SectionOffset,\n    _Inout_ PSIZE_T ViewSize,\n    _In_ SECTION_INHERIT InheritDisposition,\n    _In_ ULONG AllocationType,\n    _In_ ULONG PageProtection\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS5)\n/**\n * The NtMapViewOfSectionEx routine maps a view of a section into the virtual address space of a subject process.\n *\n * \\param SectionHandle A handle to an existing section object.\n * \\param ProcessHandle A handle to the object that represents the process that the view should be mapped into. The handle must have been opened with PROCESS_VM_OPERATION access.\n * \\param BaseAddress A pointer to a variable that receives the base address of the view. If the value is not NULL, the view is allocated starting at the specified virtual address rounded down to the next 64-kilobyte address boundary.\n * \\param SectionOffset A pointer to a variable that receives the offset, in bytes, from the beginning of the section to the view.\n * \\param ViewSize A pointer to a variable that specifies the size of the view in bytes. If the initial value is zero, NtMapViewOfSection maps a view of the section that starts at SectionOffset and continues to the end of the section.\n * \\param AllocationType Specifies the type of allocation to be performed for the specified region of pages. The valid flags are MEM_RESERVE, MEM_TOP_DOWN, MEM_LARGE_PAGES, MEM_DIFFERENT_IMAGE_BASE_OK and MEM_REPLACE_PLACEHOLDER. Although MEM_COMMIT is not allowed, it is implied unless MEM_RESERVE is specified.\n * \\param PageProtection Specifies the page protection to be applied to the mapped view. Not used with SEC_IMAGE, must be set to PAGE_READONLY for SEC_IMAGE_NO_EXECUTE. For non-image sections, the value must be compatible with the section's page protection from NtCreateSection.\n * \\param ExtendedParameters An optional pointer to one or more extended parameters of type MEM_EXTENDED_PARAMETER.\n * \\param ExtendedParameterCount Specifies the number of elements in the ExtendedParameters array.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwmapviewofsectionex\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMapViewOfSectionEx(\n    _In_ HANDLE SectionHandle,\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress,\n    _Inout_opt_ PLARGE_INTEGER SectionOffset,\n    _Inout_ PSIZE_T ViewSize,\n    _In_ ULONG AllocationType,\n    _In_ ULONG PageProtection,\n    _Inout_updates_opt_(ExtendedParameterCount) PMEM_EXTENDED_PARAMETER ExtendedParameters,\n    _In_ ULONG ExtendedParameterCount\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_RS5)\n\n/**\n * The NtUnmapViewOfSection routine unmaps a view of a section from the virtual address space of a subject process.\n *\n * \\param ProcessHandle Handle to a process object that was previously passed to NtMapViewOfSection.\n * \\param BaseAddress Pointer to the base virtual address of the view to unmap. This value can be any virtual address within the view.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwunmapviewofsection\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnmapViewOfSection(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n/**\n * The NtUnmapViewOfSectionEx routine unmaps a view of a section from the virtual address space of a subject process.\n *\n * \\param ProcessHandle Handle to a process object that was previously passed to NtMapViewOfSection.\n * \\param BaseAddress Pointer to the base virtual address of the view to unmap. This value can be any virtual address within the view.\n * \\param Flags Additional flags for the unmap operation.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwunmapviewofsection\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnmapViewOfSectionEx(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ ULONG Flags\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtExtendSection(\n    _In_ HANDLE SectionHandle,\n    _Inout_ PLARGE_INTEGER NewSectionSize\n    );\n\n/**\n * The NtQuerySection routine provides the capability to determine the base address, size, granted access, and allocation of an opened section object.\n *\n * \\param SectionHandle An open handle to a section object.\n * \\param SectionInformationClass The section information class about which to retrieve information.\n * \\param SectionInformation A pointer to a buffer that receives the specified information. The format and content of the buffer depend on the specified section class.\n * \\param SectionInformationLength Specifies the length in bytes of the section information buffer.\n * \\param ReturnLength An optional pointer which, if specified, receives the number of bytes placed in the section information buffer.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/devnotes/ntquerysection\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySection(\n    _In_ HANDLE SectionHandle,\n    _In_ SECTION_INFORMATION_CLASS SectionInformationClass,\n    _Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation,\n    _In_ SIZE_T SectionInformationLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\n/**\n * The NtAreMappedFilesTheSame routine determines whether two mapped files are the same.\n *\n * \\param File1MappedAsAnImage A pointer to the base address of the first file mapped as an image.\n * \\param File2MappedAsFile A pointer to the base address of the second file mapped as a file.\n * \\return NTSTATUS Returns STATUS_SUCCESS if the files are the same; otherwise, an appropriate NTSTATUS error code.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAreMappedFilesTheSame(\n    _In_ PVOID File1MappedAsAnImage,\n    _In_ PVOID File2MappedAsFile\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Memory Partitions\n//\n\n#ifndef MEMORY_CURRENT_PARTITION_HANDLE\n#define MEMORY_CURRENT_PARTITION_HANDLE         ((HANDLE)(LONG_PTR)-1)\n#endif // MEMORY_CURRENT_PARTITION_HANDLE\n\n#ifndef MEMORY_SYSTEM_PARTITION_HANDLE\n#define MEMORY_SYSTEM_PARTITION_HANDLE          ((HANDLE)(LONG_PTR)-2)\n#endif // MEMORY_SYSTEM_PARTITION_HANDLE\n\n#ifndef MEMORY_EXISTING_VAD_PARTITION_HANDLE\n#define MEMORY_EXISTING_VAD_PARTITION_HANDLE    ((HANDLE)(LONG_PTR)-3)\n#endif // MEMORY_EXISTING_VAD_PARTITION_HANDLE\n\n#ifndef MEMORY_PARTITION_QUERY_ACCESS\n#define MEMORY_PARTITION_QUERY_ACCESS 0x0001\n#define MEMORY_PARTITION_MODIFY_ACCESS 0x0002\n#define MEMORY_PARTITION_ALL_ACCESS \\\n    (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | MEMORY_PARTITION_QUERY_ACCESS | MEMORY_PARTITION_MODIFY_ACCESS)\n#endif // MEMORY_PARTITION_QUERY_ACCESS\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n// private\ntypedef enum _PARTITION_INFORMATION_CLASS\n{\n    SystemMemoryPartitionInformation, // q: MEMORY_PARTITION_CONFIGURATION_INFORMATION\n    SystemMemoryPartitionMoveMemory, // s: MEMORY_PARTITION_TRANSFER_INFORMATION\n    SystemMemoryPartitionAddPagefile, // s: MEMORY_PARTITION_PAGEFILE_INFORMATION\n    SystemMemoryPartitionCombineMemory, // q; s: MEMORY_PARTITION_PAGE_COMBINE_INFORMATION\n    SystemMemoryPartitionInitialAddMemory, // q; s: MEMORY_PARTITION_INITIAL_ADD_INFORMATION\n    SystemMemoryPartitionGetMemoryEvents, // MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION // since REDSTONE2\n    SystemMemoryPartitionSetAttributes,\n    SystemMemoryPartitionNodeInformation,\n    SystemMemoryPartitionCreateLargePages,\n    SystemMemoryPartitionDedicatedMemoryInformation,\n    SystemMemoryPartitionOpenDedicatedMemory, // 10\n    SystemMemoryPartitionMemoryChargeAttributes,\n    SystemMemoryPartitionClearAttributes,\n    SystemMemoryPartitionSetMemoryThresholds, // since WIN11\n    SystemMemoryPartitionMemoryListCommand, // since 24H2\n    SystemMemoryPartitionMax\n} PARTITION_INFORMATION_CLASS, *PPARTITION_INFORMATION_CLASS;\n#else\n#define SystemMemoryPartitionInformation 0x0\n#define SystemMemoryPartitionMoveMemory 0x1\n#define SystemMemoryPartitionAddPagefile 0x2\n#define SystemMemoryPartitionCombineMemory 0x3\n#define SystemMemoryPartitionInitialAddMemory 0x4\n#define SystemMemoryPartitionGetMemoryEvents 0x5\n#define SystemMemoryPartitionSetAttributes 0x6\n#define SystemMemoryPartitionNodeInformation 0x7\n#define SystemMemoryPartitionCreateLargePages 0x8\n#define SystemMemoryPartitionDedicatedMemoryInformation 0x9\n#define SystemMemoryPartitionOpenDedicatedMemory 0xA\n#define SystemMemoryPartitionMemoryChargeAttributes 0xB\n#define SystemMemoryPartitionClearAttributes 0xC\n#define SystemMemoryPartitionSetMemoryThresholds 0xD\n#define SystemMemoryPartitionMemoryListCommand 0xE\n#define SystemMemoryPartitionMax 0xF\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// private\ntypedef struct _MEMORY_PARTITION_CONFIGURATION_INFORMATION\n{\n    ULONG Flags;\n    ULONG NumaNode;\n    ULONG Channel;\n    ULONG NumberOfNumaNodes;\n    SIZE_T ResidentAvailablePages;\n    SIZE_T CommittedPages;\n    SIZE_T CommitLimit;\n    SIZE_T PeakCommitment;\n    SIZE_T TotalNumberOfPages;\n    SIZE_T AvailablePages;\n    SIZE_T ZeroPages;\n    SIZE_T FreePages;\n    SIZE_T StandbyPages;\n    SIZE_T StandbyPageCountByPriority[8]; // since REDSTONE2\n    SIZE_T RepurposedPagesByPriority[8];\n    SIZE_T MaximumCommitLimit;\n    SIZE_T Reserved; // DonatedPagesToPartitions\n    ULONG PartitionId; // since REDSTONE3\n} MEMORY_PARTITION_CONFIGURATION_INFORMATION, *PMEMORY_PARTITION_CONFIGURATION_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_TRANSFER_INFORMATION\n{\n    SIZE_T NumberOfPages;\n    ULONG NumaNode;\n    ULONG Flags;\n} MEMORY_PARTITION_TRANSFER_INFORMATION, *PMEMORY_PARTITION_TRANSFER_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_PAGEFILE_INFORMATION\n{\n    UNICODE_STRING PageFileName;\n    LARGE_INTEGER MinimumSize;\n    LARGE_INTEGER MaximumSize;\n    ULONG Flags;\n} MEMORY_PARTITION_PAGEFILE_INFORMATION, *PMEMORY_PARTITION_PAGEFILE_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_PAGE_COMBINE_INFORMATION\n{\n    HANDLE StopHandle;\n    ULONG Flags;\n    SIZE_T TotalNumberOfPages;\n} MEMORY_PARTITION_PAGE_COMBINE_INFORMATION, *PMEMORY_PARTITION_PAGE_COMBINE_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_PAGE_RANGE\n{\n    ULONG_PTR StartPage;\n    ULONG_PTR NumberOfPages;\n} MEMORY_PARTITION_PAGE_RANGE, *PMEMORY_PARTITION_PAGE_RANGE;\n\n// private\ntypedef struct _MEMORY_PARTITION_INITIAL_ADD_INFORMATION\n{\n    ULONG Flags;\n    ULONG NumberOfRanges;\n    SIZE_T NumberOfPagesAdded;\n    MEMORY_PARTITION_PAGE_RANGE PartitionRanges[1];\n} MEMORY_PARTITION_INITIAL_ADD_INFORMATION, *PMEMORY_PARTITION_INITIAL_ADD_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION\n{\n    union\n    {\n        struct\n        {\n            ULONG CommitEvents : 1;\n            ULONG Spare : 31;\n        };\n        ULONG AllFlags;\n    } Flags;\n\n    ULONG HandleAttributes;\n    ACCESS_MASK DesiredAccess;\n    HANDLE LowCommitCondition; // \\KernelObjects\\LowCommitCondition\n    HANDLE HighCommitCondition; // \\KernelObjects\\HighCommitCondition\n    HANDLE MaximumCommitCondition; // \\KernelObjects\\MaximumCommitCondition\n} MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION, *PMEMORY_PARTITION_MEMORY_EVENTS_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreatePartition(\n    _In_opt_ HANDLE ParentPartitionHandle,\n    _Out_ PHANDLE PartitionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenPartition(\n    _Out_ PHANDLE PartitionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtManagePartition(\n    _In_ HANDLE TargetHandle,\n    _In_opt_ HANDLE SourceHandle,\n    _In_ PARTITION_INFORMATION_CLASS PartitionInformationClass,\n    _Inout_updates_bytes_(PartitionInformationLength) PVOID PartitionInformation,\n    _In_ ULONG PartitionInformationLength\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n//\n// User physical pages\n//\n\n/**\n * Maps previously allocated physical memory pages at a specified address in an Address Windowing Extensions (AWE) region.\n *\n * \\param VirtualAddress A pointer to the starting address of the region of memory to remap. The value of VirtualAddress must be within the address range that the VirtualAlloc function returns when the Address Windowing Extensions (AWE) region is allocated.\n * \\param NumberOfPages The size of the physical memory and virtual address space for which to establish translations, in pages.\n * \\param UserPfnArray A pointer to an array of physical page frame numbers.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapuserphysicalpages\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMapUserPhysicalPages(\n    _In_ PVOID VirtualAddress,\n    _In_ SIZE_T NumberOfPages,\n    _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\n/**\n * Maps previously allocated physical memory pages at a specified address in an Address Windowing Extensions (AWE) region.\n *\n * \\param VirtualAddresses A pointer to an array of starting addresses of the regions of memory to remap. The value of VirtualAddress must be within the address range that the VirtualAlloc function returns when the Address Windowing Extensions (AWE) region is allocated.\n * \\param NumberOfPages The size of the physical memory and virtual address space for which to establish translations, in pages.\n * \\param UserPfnArray A pointer to an array of values that indicates how each corresponding page in VirtualAddresses should be treated. A 0 (zero) indicates the entry should be unmapped, and any nonzero value should be mapped.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-mapuserphysicalpagesscatter\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMapUserPhysicalPagesScatter(\n    _In_reads_(NumberOfPages) PVOID *VirtualAddresses,\n    _In_ SIZE_T NumberOfPages,\n    _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\n/**\n * Allocates physical memory pages to be mapped and unmapped within any Address Windowing Extensions (AWE) region of a specified process.\n *\n * \\param ProcessHandle A handle to the process whose physical memory pages are to be allocated within the virtual address space of this process.\n * \\param NumberOfPages The size of the physical memory to allocate, in pages.\n * \\param UserPfnArray A pointer to an array to store the page frame numbers of the allocated memory. Do not attempt to modify this buffer. It contains operating system data, and corruption could be catastrophic. The information in the buffer is not useful to an application.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-allocateuserphysicalpages\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateUserPhysicalPages(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PSIZE_T NumberOfPages,\n    _Out_writes_(*NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n/**\n * Allocates physical memory pages to be mapped and unmapped within any Address Windowing Extensions (AWE) region of a specified process, with extended parameters.\n *\n * \\param ProcessHandle A handle to the process whose physical memory pages are to be allocated within the virtual address space of this process.\n * \\param NumberOfPages The size of the physical memory to allocate, in pages.\n * \\param UserPfnArray A pointer to an array to store the page frame numbers of the allocated memory. Do not attempt to modify this buffer. It contains operating system data, and corruption could be catastrophic. The information in the buffer is not useful to an application.\n * \\param ExtendedParameters Pointer to an array of MEM_EXTENDED_PARAMETER structures.\n * \\param ExtendedParameterCount The number of MEM_EXTENDED_PARAMETER in the ExtendedParameters array.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-allocateuserphysicalpages\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateUserPhysicalPagesEx(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PULONG_PTR NumberOfPages,\n    _Out_writes_(*NumberOfPages) PULONG_PTR UserPfnArray,\n    _Inout_updates_opt_(ExtendedParameterCount) PMEM_EXTENDED_PARAMETER ExtendedParameters,\n    _In_ ULONG ExtendedParameterCount\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n/**\n * Frees physical memory pages that are allocated previously by using NtAllocateUserPhysicalPages.\n *\n * \\param ProcessHandle A handle to the process. The function frees memory within the virtual address space of this process.\n * \\param NumberOfPages The size of the physical memory to free, in pages. On return, if the function fails, this parameter indicates the number of pages that are freed.\n * \\param UserPfnArray A pointer to an array of page frame numbers of the allocated memory to be freed.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-freeuserphysicalpages\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFreeUserPhysicalPages(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PULONG_PTR NumberOfPages,\n    _In_reads_(*NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\n//\n// Misc.\n//\n\n/**\n * Retrieves the addresses of the pages that are written to in a region of virtual memory.\n *\n * \\param ProcessHandle A handle to the process whose watch information is to be queried.\n * \\param Flags Additional flags for the operation. To reset the write-tracking state, set this parameter to WRITE_WATCH_FLAG_RESET. Otherwise, set this parameter to zero.\n * \\param BaseAddress The base address of the memory region for which to retrieve write-tracking information. This address must a region that is allocated using MEM_WRITE_WATCH.\n * \\param RegionSize The size of the memory region for which to retrieve write-tracking information, in bytes.\n * \\param UserAddressArray A pointer to a buffer that receives an array of page addresses that have been written to since the region has been allocated or the write-tracking state has been reset.\n * \\param EntriesInUserAddressArray On input, this variable indicates the size of the UserAddressArray array. On output, the variable receives the number of page addresses that are returned in the array.\n * \\param Granularity A pointer to a variable that receives the page size, in bytes.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-getwritewatch\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetWriteWatch(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize,\n    _Out_writes_(*EntriesInUserAddressArray) PVOID *UserAddressArray,\n    _Inout_ PULONG_PTR EntriesInUserAddressArray,\n    _Out_ PULONG Granularity\n    );\n\n/**\n * Resets the write-tracking state for a region of virtual memory.\n *\n * \\param ProcessHandle A handle to the process whose watch information is to be reset.\n * \\param BaseAddress A pointer to the base address of the memory region for which to reset the write-tracking state.\n * \\param RegionSize The size of the memory region for which to reset the write-tracking information, in bytes.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-resetwritewatch\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtResetWriteWatch(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize\n    );\n\n/**\n * Creates or extends a paging file.\n *\n * \\param PageFileName The NT path of the paging file to create or extend.\n * \\param MinimumSize A pointer to the minimum size of the paging file, in bytes.\n * \\param MaximumSize A pointer to the maximum size of the paging file, in bytes.\n * \\param Priority The paging file priority.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The caller must have the SeCreatePagefilePrivilege privilege.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreatePagingFile(\n    _In_ PCUNICODE_STRING PageFileName,\n    _In_ PLARGE_INTEGER MinimumSize,\n    _In_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG Priority\n    );\n\n/**\n * Flushes the instruction cache for the specified process.\n *\n * \\param ProcessHandle A handle to the process whose instruction cache is to be flushed.\n * \\param BaseAddress A pointer to the base address of the memory region to be flushed. This parameter can be NULL.\n * \\param RegionSize The size of the memory region to be flushed, in bytes.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Applications should call NtFlushInstructionCache if they generate or modify code in memory. The CPU cannot detect the change, and may execute the old code it cached.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-flushinstructioncache\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushInstructionCache(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize\n    );\n\n/**\n * The NtFlushWriteBuffer routine flushes the write queue of the current processor that is running a thread of the current process.\n *\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushWriteBuffer(\n    VOID\n    );\n\n/**\n * The NtFlushProcessWriteBuffers routine flushes the write queue of each processor that is running a thread of the current process.\n *\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-flushprocesswritebuffers\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushProcessWriteBuffers(\n    VOID\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Enclave support\n//\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n/**\n * Creates a new uninitialized enclave. An enclave is an isolated region of code and data within the address space for an application.\n * Only code that runs within the enclave can access data within the same enclave.\n *\n * \\param ProcessHandle A handle to the process for which you want to create an enclave.\n * \\param BaseAddress The preferred base address of the enclave. Specify NULL to have the operating system assign the base address.\n * \\param ZeroBits The number of high-order address bits that must be zero in the base address of the section view. This value must be less than 21 and the initial value of BaseAddress must be zero.\n * \\param Size The size of the enclave that you want to create, including the size of the code that you will load into the enclave, in bytes. VBS enclaves must be a multiple of 2 MB in size.\n * SGX enclaves must be a power of 2 in size and must have their base aligned to the same power of 2 as the size, with a minimum alignment of 2 MB. As an example, if the enclave is 128 MB, then its base must be aligned to a 128 MB boundary.\n * \\param InitialCommitment The amount of memory to commit for the enclave, in bytes.\n * \\param EnclaveType The architecture type of the enclave that you want to create. To verify that an enclave type is supported, call IsEnclaveTypeSupported.\n * \\param EnclaveInformation A pointer to the architecture-specific information to use to create the enclave.\n * \\param EnclaveInformationLength The length of the structure that the EnclaveInformation parameter points to, in bytes.\n * For the ENCLAVE_TYPE_SGX and ENCLAVE_TYPE_SGX2 enclave types, this value must be 4096. For the ENCLAVE_TYPE_VBS enclave type, this value must be sizeof(ENCLAVE_CREATE_INFO_VBS), which is 36 bytes.\n * \\param EnclaveError An optional pointer to a variable that receives an enclave error code that is architecture-specific.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-createenclave\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateEnclave(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID* BaseAddress,\n    _In_ ULONG_PTR ZeroBits,\n    _In_ SIZE_T Size,\n    _In_ SIZE_T InitialCommitment,\n    _In_ ULONG EnclaveType,\n    _In_reads_bytes_(EnclaveInformationLength) PVOID EnclaveInformation,\n    _In_ ULONG EnclaveInformationLength,\n    _Out_opt_ PULONG EnclaveError\n    );\n\n/**\n * Loads data into an uninitialized enclave that you created by calling NtCreateEnclave.\n *\n * \\param ProcessHandle A handle to the process for which the enclave was created.\n * \\param BaseAddress The address in the enclave where you want to load the data.\n * \\param Buffer A pointer to the data the you want to load into the enclave.\n * \\param BufferSize The size of the data that you want to load into the enclave, in bytes. This value must be a whole-number multiple of the page size.\n * \\param Protect The memory protection to use for the pages that you want to add to the enclave.\n * \\param PageInformation A pointer to information that describes the pages that you want to add to the enclave.\n * \\param PageInformationLength The length of the structure that the PageInformation parameter points to, in bytes.\n * \\param NumberOfBytesWritten A pointer to a variable that receives the number of bytes that NtLoadEnclaveData copied into the enclave.\n * \\param EnclaveError An optional pointer to a variable that receives an enclave error code that is architecture-specific.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-loadenclavedata\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLoadEnclaveData(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _In_ ULONG Protect,\n    _In_reads_bytes_(PageInformationLength) PVOID PageInformation,\n    _In_ ULONG PageInformationLength,\n    _Out_opt_ PSIZE_T NumberOfBytesWritten,\n    _Out_opt_ PULONG EnclaveError\n    );\n\n/**\n * Initializes an enclave that you created and loaded with data.\n *\n * \\param ProcessHandle A handle to the process for which the enclave was created.\n * \\param BaseAddress Any address within the enclave.\n * \\param EnclaveInformation A pointer to architecture-specific information to use to initialize the enclave.\n * \\param EnclaveInformationLength The length of the structure that the EnclaveInformation parameter points to, in bytes.\n * \\param EnclaveError An optional pointer to a variable that receives an enclave error code that is architecture-specific.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-initializeenclave\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtInitializeEnclave(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_reads_bytes_(EnclaveInformationLength) PVOID EnclaveInformation,\n    _In_ ULONG EnclaveInformationLength,\n    _Out_opt_ PULONG EnclaveError\n    );\n\n// rev\n#define TERMINATE_ENCLAVE_VALID_FLAGS     0x00000005ul\n#define TERMINATE_ENCLAVE_FLAG_NO_WAIT    0x00000001ul\n#define TERMINATE_ENCLAVE_FLAG_WAIT_ERROR 0x00000004ul // STATUS_PENDING -> STATUS_ENCLAVE_NOT_TERMINATED\n\n// rev\n/**\n * Ends the execution of the threads that are running within an enclave.\n *\n * \\param BaseAddress The base address of the enclave in which to end the execution of the threads.\n * \\param Flags Additional flags for the termination operation.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-terminateenclave\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTerminateEnclave(\n    _In_ PVOID BaseAddress,\n    _In_ ULONG Flags // TERMINATE_ENCLAVE_FLAG_*\n    );\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n// rev\n#define ENCLAVE_CALL_VALID_FLAGS  0x00000001ul\n#define ENCLAVE_CALL_FLAG_NO_WAIT 0x00000001ul\n\n// rev\n/**\n * Calls a function within an enclave. NtCallEnclave can also be called within an enclave to call a function outside of the enclave.\n *\n * \\param Routine The address of the function that you want to call.\n * \\param Reserved Reserved for dispatch (RtlEnclaveCallDispatch)\n * \\param Flags Additional flags for the call operation.\n * \\param RoutineParamReturn The parameter than you want to pass to the function and return value of the function.\n * \\return NTSTATUS Successful or errant status.\n * \\see https://learn.microsoft.com/en-us/windows/win32/api/enclaveapi/nf-enclaveapi-callenclave\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCallEnclave(\n    _In_ PENCLAVE_ROUTINE Routine,\n    _In_ PVOID Reserved,              // SelectVsmEnclaveByNumber > 0 // reserved for dispatch (RtlEnclaveCallDispatch)\n    _In_ ULONG Flags,                 // ENCLAVE_CALL_FLAG_*\n    _Inout_ PVOID* RoutineParamReturn // input routine parameter, output routine return value\n    );\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n#endif // _NTMMAPI_H\n"
  },
  {
    "path": "phnt/include/ntnls.h",
    "content": "/*\n * National Language Support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTNLS_H\n#define _NTNLS_H\n\n#define MAXIMUM_LEADBYTES 12\n\n/**\n * Stores the NLS file formats.\n *\n * \\sa https://learn.microsoft.com/en-us/previous-versions/mt791523(v=vs.85)\n */\ntypedef struct _CPTABLEINFO\n{\n    USHORT CodePage;                        // Specifies the code page number.\n    USHORT MaximumCharacterSize;            // Specifies the maximum length in bytes of a character.\n    USHORT DefaultChar;                     // Specifies the default character (MB).\n    USHORT UniDefaultChar;                  // Specifies the default character (Unicode).\n    USHORT TransDefaultChar;                // Specifies the translation of the default character (Unicode).\n    USHORT TransUniDefaultChar;             // Specifies the translation of the Unicode default character (MB).\n    USHORT DBCSCodePage;                    // Specifies non-zero for DBCS code pages.\n    UCHAR LeadByte[MAXIMUM_LEADBYTES];      // Specifies the lead byte ranges.\n    PUSHORT MultiByteTable;                 // Specifies a pointer to a MB translation table.\n    PVOID WideCharTable;                    // Specifies a pointer to a WC translation table.\n    PUSHORT DBCSRanges;                     // Specifies a pointer to DBCS ranges.\n    PUSHORT DBCSOffsets;                    // Specifies a pointer to DBCS offsets.\n} CPTABLEINFO, *PCPTABLEINFO;\n\n/**\n * Stores the NLS file formats.\n *\n * \\sa https://learn.microsoft.com/en-us/previous-versions/mt791531(v=vs.85)\n */\ntypedef struct _NLSTABLEINFO\n{\n    CPTABLEINFO OemTableInfo;               // Specifies OEM table.\n    CPTABLEINFO AnsiTableInfo;              // Specifies an ANSI table.\n    PUSHORT UpperCaseTable;                 // Specifies an 844 format uppercase table.\n    PUSHORT LowerCaseTable;                 // Specifies an 844 format lowercase table.\n} NLSTABLEINFO, *PNLSTABLEINFO;\n\n//\n// Data exports (ntdll.lib/ntdllp.lib)\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\nNTSYSAPI USHORT NlsAnsiCodePage;\nNTSYSAPI BOOLEAN NlsMbCodePageTag;\nNTSYSAPI BOOLEAN NlsMbOemCodePageTag;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#endif // _NTNLS_H\n"
  },
  {
    "path": "phnt/include/ntobapi.h",
    "content": "/*\n * Object Manager support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTOBAPI_H\n#define _NTOBAPI_H\n\n//\n// Object Specific Access Rights\n//\n\n#ifndef OBJECT_TYPE_CREATE\n#define OBJECT_TYPE_CREATE 0x0001\n#endif\n\n#ifndef OBJECT_TYPE_ALL_ACCESS\n#define OBJECT_TYPE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | OBJECT_TYPE_CREATE)\n#endif\n\n//\n// Directory Object Specific Access Rights\n//\n\n#ifndef DIRECTORY_QUERY\n#define DIRECTORY_QUERY 0x0001\n#endif\n\n#ifndef DIRECTORY_TRAVERSE\n#define DIRECTORY_TRAVERSE 0x0002\n#endif\n\n#ifndef DIRECTORY_CREATE_OBJECT\n#define DIRECTORY_CREATE_OBJECT 0x0004\n#endif\n\n#ifndef DIRECTORY_CREATE_SUBDIRECTORY\n#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008\n#endif\n\n#ifndef DIRECTORY_ALL_ACCESS\n#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY)\n#endif\n\n//\n// Symbolic Link Specific Access Rights\n//\n\n#ifndef SYMBOLIC_LINK_QUERY\n#define SYMBOLIC_LINK_QUERY 0x0001\n#endif\n\n#ifndef SYMBOLIC_LINK_SET\n#define SYMBOLIC_LINK_SET 0x0002\n#endif\n\n#ifndef SYMBOLIC_LINK_ALL_ACCESS\n#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYMBOLIC_LINK_QUERY)\n#endif\n\n#ifndef SYMBOLIC_LINK_ALL_ACCESS_EX\n#define SYMBOLIC_LINK_ALL_ACCESS_EX (STANDARD_RIGHTS_REQUIRED | SPECIFIC_RIGHTS_ALL)\n#endif\n\n//\n// Object Attribute Flags\n//\n\n#ifndef OBJ_PROTECT_CLOSE\n#define OBJ_PROTECT_CLOSE 0x00000001\n#endif\n\n#ifndef OBJ_INHERIT\n#define OBJ_INHERIT 0x00000002\n#endif\n\n#ifndef OBJ_AUDIT_OBJECT_CLOSE\n#define OBJ_AUDIT_OBJECT_CLOSE 0x00000004\n#endif\n\n//\n// Object Information\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _OBJECT_INFORMATION_CLASS\n{\n    ObjectBasicInformation, // q: OBJECT_BASIC_INFORMATION\n    ObjectNameInformation, // q: OBJECT_NAME_INFORMATION\n    ObjectTypeInformation, // q: OBJECT_TYPE_INFORMATION\n    ObjectTypesInformation, // q: OBJECT_TYPES_INFORMATION\n    ObjectHandleFlagInformation, // qs: OBJECT_HANDLE_FLAG_INFORMATION\n    ObjectSessionInformation, // s: void // change object session // (requires SeTcbPrivilege)\n    ObjectSessionObjectInformation, // s: void // change object session // (requires SeTcbPrivilege)\n    ObjectSetRefTraceInformation, // since 25H2\n    MaxObjectInfoClass\n} OBJECT_INFORMATION_CLASS;\n#else\n#define ObjectBasicInformation 0\n#define ObjectNameInformation 1\n#define ObjectTypeInformation 2\n#define ObjectTypesInformation 3\n#define ObjectHandleFlagInformation 4\n#define ObjectSessionInformation 5\n#define ObjectSessionObjectInformation 6\n#define ObjectSetRefTraceInformation 7\n#define MaxObjectInfoClass 8\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * The OBJECT_BASIC_INFORMATION structure contains basic information about an object.\n */\ntypedef struct _OBJECT_BASIC_INFORMATION\n{\n    ULONG Attributes;               // The attributes of the object include whether the object is permanent, can be inherited, and other characteristics.\n    ACCESS_MASK GrantedAccess;      // Specifies a mask that represents the granted access when the object was created.\n    ULONG HandleCount;              // The number of handles that are currently open for the object.\n    ULONG PointerCount;             // The number of references to the object from both handles and other references, such as those from the system.\n    ULONG PagedPoolCharge;          // The amount of paged pool memory that the object is using.\n    ULONG NonPagedPoolCharge;       // The amount of non-paged pool memory that the object is using.\n    ULONG Reserved[3];              // Reserved for future use.\n    ULONG NameInfoSize;             // The size of the name information for the object.\n    ULONG TypeInfoSize;             // The size of the type information for the object.\n    ULONG SecurityDescriptorSize;   // The size of the security descriptor for the object.\n    LARGE_INTEGER CreationTime;     // The time when a symbolic link was created. Not supported for other types of objects.\n} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n/**\n * The OBJECT_NAME_INFORMATION structure contains the name, if there is one, of a given object.\n */\ntypedef struct _OBJECT_NAME_INFORMATION\n{\n    UNICODE_STRING Name; // The object name (when present) includes a NULL-terminator and all path separators \"\\\" in the name.\n} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * The OBJECT_NAME_INFORMATION structure contains various statistics and properties about an object type.\n */\ntypedef struct _OBJECT_TYPE_INFORMATION\n{\n    UNICODE_STRING TypeName;\n    ULONG TotalNumberOfObjects;\n    ULONG TotalNumberOfHandles;\n    ULONG TotalPagedPoolUsage;\n    ULONG TotalNonPagedPoolUsage;\n    ULONG TotalNamePoolUsage;\n    ULONG TotalHandleTableUsage;\n    ULONG HighWaterNumberOfObjects;\n    ULONG HighWaterNumberOfHandles;\n    ULONG HighWaterPagedPoolUsage;\n    ULONG HighWaterNonPagedPoolUsage;\n    ULONG HighWaterNamePoolUsage;\n    ULONG HighWaterHandleTableUsage;\n    ULONG InvalidAttributes;\n    GENERIC_MAPPING GenericMapping;\n    ULONG ValidAccessMask;\n    BOOLEAN SecurityRequired;\n    BOOLEAN MaintainHandleCount;\n    UCHAR TypeIndex; // since WINBLUE\n    CHAR ReservedByte;\n    ULONG PoolType;\n    ULONG DefaultPagedPoolCharge;\n    ULONG DefaultNonPagedPoolCharge;\n} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;\n\ntypedef struct _OBJECT_TYPES_INFORMATION\n{\n    ULONG NumberOfTypes;\n} OBJECT_TYPES_INFORMATION, *POBJECT_TYPES_INFORMATION;\n\ntypedef struct _OBJECT_HANDLE_FLAG_INFORMATION\n{\n    BOOLEAN Inherit;\n    BOOLEAN ProtectFromClose;\n} OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION;\n\n//\n// Objects, handles\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * The NtQueryObject routine retrieves various kinds of object information.\n *\n * \\param Handle The handle of the object for which information is being queried.\n * \\param ObjectInformationClass The information class indicating the kind of object information to be retrieved.\n * \\param ObjectInformation An optional pointer to a buffer where the requested information is to be returned.\n * \\param ObjectInformationLength The size of the buffer pointed to by the ObjectInformation parameter, in bytes.\n * \\param ReturnLength An optional pointer to a location where the function writes the actual size of the information requested.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryObject(\n    _In_opt_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n/**\n * The NtSetInformationObject routine changes various kinds of information about a object.\n *\n * \\param Handle The handle of the object for which information is being changed.\n * \\param ObjectInformationClass The type of information, supplied in the buffer pointed to by ObjectInformation, to set for the object.\n * \\param ObjectInformation Pointer to a buffer that contains the information to set for the object.\n * \\param ObjectInformationLength The size of the buffer pointed to by the ObjectInformation parameter, in bytes.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationObject(\n    _In_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength\n    );\n\n#define DUPLICATE_CLOSE_SOURCE 0x00000001       // Close the source handle.\n#define DUPLICATE_SAME_ACCESS 0x00000002        // Instead of using the DesiredAccess parameter, copy the access rights from the source handle to the target handle.\n#define DUPLICATE_SAME_ATTRIBUTES 0x00000004    // Instead of using the HandleAttributes parameter, copy the attributes from the source handle to the target handle.\n\n/**\n * The NtDuplicateObject routine creates a handle that is a duplicate of the specified source handle.\n *\n * \\param SourceProcessHandle A handle to the source process for the handle being duplicated.\n * \\param SourceHandle The handle to duplicate.\n * \\param TargetProcessHandle A handle to the target process that is to receive the new handle. This parameter is optional and can be specified as NULL if the DUPLICATE_CLOSE_SOURCE flag is set in Options.\n * \\param TargetHandle A pointer to a HANDLE variable into which the routine writes the new duplicated handle. The duplicated handle is valid in the specified target process. This parameter is optional and can be specified as NULL if no duplicate handle is to be created.\n * \\param DesiredAccess An ACCESS_MASK value that specifies the desired access for the new handle.\n * \\param HandleAttributes A ULONG that specifies the desired attributes for the new handle.\n * \\param Options A set of flags to control the behavior of the duplication operation.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwduplicateobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDuplicateObject(\n    _In_ HANDLE SourceProcessHandle,\n    _In_ HANDLE SourceHandle,\n    _In_opt_ HANDLE TargetProcessHandle,\n    _Out_opt_ PHANDLE TargetHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_ ULONG Options\n    );\n\n/**\n * The NtMakeTemporaryObject routine changes the attributes of an object to make it temporary.\n *\n * \\param Handle Handle to an object of any type.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwmaketemporaryobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMakeTemporaryObject(\n    _In_ HANDLE Handle\n    );\n\n/**\n * The NtMakePermanentObject routine changes the attributes of an object to make it permanent.\n *\n * \\param Handle Handle to an object of any type.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwmaketemporaryobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMakePermanentObject(\n    _In_ HANDLE Handle\n    );\n\n/**\n * The NtSignalAndWaitForSingleObject routine signals one object and waits on another object as a single operation.\n *\n * \\param SignalHandle A handle to the object to be signaled.\n * \\param WaitHandle A handle to the object to wait on. The SYNCHRONIZE access right is required.\n * \\param Alertable If this parameter is TRUE, the function returns when the system queues an I/O completion routine or APC function, and the thread calls the function.\n * \\param Timeout The time-out interval. The function returns if the interval elapses, even if the object's state is nonsignaled and no completion or APC objects are queued.\n * If zero, the function tests the object's state, checks for queued completion routines or APCs, and returns immediately.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-signalobjectandwait\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSignalAndWaitForSingleObject(\n    _In_ HANDLE SignalHandle,\n    _In_ HANDLE WaitHandle,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n/**\n * The NtWaitForSingleObject routine waits until the specified object is in the signaled state or the time-out interval elapses.\n *\n * \\param Handle The handle to the wait object.\n * \\param Alertable The function returns when either the time-out period has elapsed or when the APC function is called.\n * \\param Timeout A pointer to an absolute or relative time over which the wait is to occur. Can be null. If a timeout is specified,\n * and the object has not attained a state of signaled when the timeout expires, then the wait is automatically satisfied.\n * If an explicit timeout value of zero is specified, then no wait occurs if the wait cannot be satisfied immediately.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntwaitforsingleobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForSingleObject(\n    _In_ HANDLE Handle,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n/**\n * The NtWaitForMultipleObjects routine waits until one or all of the specified objects are in the signaled state, an I/O completion routine or asynchronous procedure call (APC) is queued to the thread, or the time-out interval elapses.\n *\n * \\param Count The number of object handles to wait for in the array pointed to by lpHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS. This parameter cannot be zero.\n * \\param Handles An array of object handles. The array can contain handles of objects of different types. It may not contain multiple copies of the same handle.\n * \\param WaitType If this parameter is WaitAll, the function returns when the state of all objects in the Handles array is set to signaled.\n * \\param Alertable f this parameter is TRUE and the thread is in the waiting state, the function returns when the system queues an I/O completion routine or APC, and the thread runs the routine or function.\n * \\param Timeout A pointer to an absolute or relative time over which the wait is to occur. Can be null. If a timeout is specified,\n * and the object has not attained a state of signaled when the timeout expires, then the wait is automatically satisfied.\n * If an explicit timeout value of zero is specified, then no wait occurs if the wait cannot be satisfied immediately.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjectsex\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForMultipleObjects(\n    _In_ ULONG Count,\n    _In_reads_(Count) HANDLE Handles[],\n    _In_ WAIT_TYPE WaitType,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForMultipleObjects32(\n    _In_ ULONG Count,\n    _In_reads_(Count) LONG Handles[],\n    _In_ WAIT_TYPE WaitType,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n/**\n * The NtSetSecurityObject routine sets an object's security state.\n *\n * \\param Handle Handle for the object whose security state is to be set.\n * \\param SecurityInformation A SECURITY_INFORMATION value specifying the information to be set.\n * \\param SecurityDescriptor Pointer to the security descriptor to be set for the object.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwsetsecurityobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n/**\n * The NtQuerySecurityObject routine retrieves a copy of an object's security descriptor.\n *\n * \\param Handle Handle for the object whose security descriptor is to be queried.\n * \\param SecurityInformation A SECURITY_INFORMATION value specifying the information to be queried.\n * \\param SecurityDescriptor Caller-allocated buffer that NtQuerySecurityObject fills with a copy of the specified security descriptor.\n * \\param Length Size, in bytes, of the buffer pointed to by SecurityDescriptor.\n * \\param LengthNeeded Pointer to a caller-allocated variable that receives the number of bytes required to store the copied security descriptor.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntquerysecurityobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_writes_bytes_to_opt_(Length, *LengthNeeded) PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ULONG Length,\n    _Out_ PULONG LengthNeeded\n    );\n\n/**\n * The NtClose routine closes the specified handle.\n *\n * \\param Handle The handle being closed.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwclose\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtClose(\n    _In_ _Post_ptr_invalid_ HANDLE Handle\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\n/**\n * Compares two object handles to determine if they refer to the same underlying kernel object.\n *\n * \\param FirstObjectHandle The first object handle to compare.\n * \\param SecondObjectHandle The second object handle to compare.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-compareobjecthandles\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCompareObjects(\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Directory objects\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * The NtCreateDirectoryObject routine creates or opens an object-directory object.\n *\n * \\param DirectoryHandle Pointer to a HANDLE variable that receives a handle to the object directory.\n * \\param DesiredAccess An ACCESS_MASK that specifies the requested access to the directory object.\n * \\param ObjectAttributes The attributes for the directory object.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwcreatedirectoryobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateDirectoryObject(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateDirectoryObjectEx(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ShadowDirectoryHandle,\n    _In_ ULONG Flags\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n/**\n * Opens an existing directory object.\n *\n * \\param DirectoryHandle A handle to the newly opened directory object.\n * \\param DesiredAccess An ACCESS_MASK that specifies the requested access to the directory object.\n * \\param ObjectAttributes The attributes for the directory object.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/devnotes/ntopendirectoryobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenDirectoryObject(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * The OBJECT_DIRECTORY_INFORMATION structure contains information about the directory object.\n */\ntypedef struct _OBJECT_DIRECTORY_INFORMATION\n{\n    UNICODE_STRING Name;\n    UNICODE_STRING TypeName;\n} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;\n\n/**\n * Retrieves information about the specified directory object.\n *\n * \\param DirectoryHandle A handle to the directory object. This handle must have been opened with the appropriate access rights.\n * \\param Buffer A pointer to a buffer that receives the directory information.\n * \\param Length The size, in bytes, of the buffer pointed to by the Buffer parameter.\n * \\param ReturnSingleEntry A BOOLEAN value that specifies whether to return a single entry or multiple entries.\n * \\param RestartScan A BOOLEAN value that specifies whether to restart the scan from the beginning of the directory.\n * \\param Context A pointer to a variable that maintains the context of the directory enumeration.\n * \\param ReturnLength An optional pointer to a variable that receives the number of bytes returned in the buffer.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/devnotes/ntquerydirectoryobject\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDirectoryObject(\n    _In_ HANDLE DirectoryHandle,\n    _Out_writes_bytes_opt_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_ BOOLEAN RestartScan,\n    _Inout_ PULONG Context,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Private namespaces\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// private\ntypedef enum _BOUNDARY_ENTRY_TYPE\n{\n    BOUNDARY_ENTRY_TYPE_INVALID,\n    BOUNDARY_ENTRY_TYPE_NAME,\n    BOUNDARY_ENTRY_TYPE_SID,\n    BOUNDARY_ENTRY_TYPE_IL\n} BOUNDARY_ENTRY_TYPE;\n\n// private\ntypedef union _OBJECT_BOUNDARY_VALUE\n{\n    WCHAR Name[1];\n    PSID Sid;\n    PSID IntegrityLabel;\n} OBJECT_BOUNDARY_VALUE, *POBJECT_BOUNDARY_VALUE;\n\n// private\ntypedef struct _OBJECT_BOUNDARY_ENTRY\n{\n    BOUNDARY_ENTRY_TYPE Type;\n    ULONG Size;\n    // OBJECT_BOUNDARY_VALUE Value;\n} OBJECT_BOUNDARY_ENTRY, *POBJECT_BOUNDARY_ENTRY;\n\n// rev\n#define OBJECT_BOUNDARY_DESCRIPTOR_VERSION 1\n\n// private\ntypedef struct _OBJECT_BOUNDARY_DESCRIPTOR\n{\n    ULONG Version;\n    ULONG Items;\n    ULONG TotalSize;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG AddAppContainerSid : 1;\n            ULONG Reserved : 31;\n        };\n    };\n    //OBJECT_BOUNDARY_ENTRY Entries[1];\n} OBJECT_BOUNDARY_DESCRIPTOR, *POBJECT_BOUNDARY_DESCRIPTOR;\n\n/**\n * Creates a private namespace.\n *\n * \\param NamespaceHandle A handle to the newly created private namespace.\n * \\param DesiredAccess An ACCESS_MASK that specifies the requested access to the private namespace.\n * \\param ObjectAttributes The attributes for the private namespace.\n * \\param BoundaryDescriptor A descriptor that defines how the namespace is to be isolated. The RtlCreateBoundaryDescriptor function creates a boundary descriptor.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprivatenamespacea\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreatePrivateNamespace(\n    _Out_ PHANDLE NamespaceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ POBJECT_BOUNDARY_DESCRIPTOR BoundaryDescriptor\n    );\n\n/**\n * Opens a private namespace.\n *\n * \\param NamespaceHandle A handle to the newly opened private namespace.\n * \\param DesiredAccess An ACCESS_MASK that specifies the requested access to the private namespace.\n * \\param ObjectAttributes The attributes for the private namespace.\n * \\param BoundaryDescriptor A descriptor that defines how the namespace is to be isolated. The RtlCreateBoundaryDescriptor function creates a boundary descriptor.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-openprivatenamespacea\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenPrivateNamespace(\n    _Out_ PHANDLE NamespaceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ POBJECT_BOUNDARY_DESCRIPTOR BoundaryDescriptor\n    );\n\n/**\n * Deletes an open namespace handle.\n *\n * \\param NamespaceHandle A handle to the private namespace.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/namespaceapi/nf-namespaceapi-closeprivatenamespace\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeletePrivateNamespace(\n    _In_ HANDLE NamespaceHandle\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Symbolic links\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateSymbolicLinkObject(\n    _Out_ PHANDLE LinkHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PCUNICODE_STRING LinkTarget\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenSymbolicLinkObject(\n    _Out_ PHANDLE LinkHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySymbolicLinkObject(\n    _In_ HANDLE LinkHandle,\n    _Inout_ PUNICODE_STRING LinkTarget,\n    _Out_opt_ PULONG ReturnedLength\n    );\n\ntypedef enum _SYMBOLIC_LINK_INFO_CLASS\n{\n    SymbolicLinkGlobalInformation = 1, // s: ULONG\n    SymbolicLinkAccessMask, // s: ACCESS_MASK\n    MaxnSymbolicLinkInfoClass\n} SYMBOLIC_LINK_INFO_CLASS;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationSymbolicLink(\n    _In_ HANDLE LinkHandle,\n    _In_ SYMBOLIC_LINK_INFO_CLASS SymbolicLinkInformationClass,\n    _In_reads_bytes_(SymbolicLinkInformationLength) PVOID SymbolicLinkInformation,\n    _In_ ULONG SymbolicLinkInformationLength\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#endif // _NTOBAPI_H\n"
  },
  {
    "path": "phnt/include/ntpebteb.h",
    "content": "/*\n * Process and Thread Environment Block support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTPEBTEB_H\n#define _NTPEBTEB_H\n\n#ifdef __has_include\n#if __has_include (<ntgdi.h>)\n#include <ntgdi.h>\n#endif // __has_include\n#if __has_include (<ntsxs.h>)\n#include <ntsxs.h>\n#endif // __has_include\n#endif // __has_include\n\ntypedef struct _APPCOMPAT_EXE_DATA APPCOMPAT_EXE_DATA, *PAPPCOMPAT_EXE_DATA;\ntypedef struct _RTL_USER_PROCESS_PARAMETERS *PRTL_USER_PROCESS_PARAMETERS;\ntypedef struct _RTL_CRITICAL_SECTION *PRTL_CRITICAL_SECTION;\ntypedef struct _SILO_USER_SHARED_DATA *PSILO_USER_SHARED_DATA;\ntypedef struct _LDR_RESLOADER_RET LDR_RESLOADER_RET, *PLDR_RESLOADER_RET;\ntypedef struct _LEAP_SECOND_DATA *PLEAP_SECOND_DATA;\ntypedef struct _PEB_LDR_DATA PEB_LDR_DATA, *PPEB_LDR_DATA;\ntypedef struct tagSOleTlsData SOleTlsData, *PSOleTlsData;\ntypedef struct _KERNEL_CALLBACK_TABLE KERNEL_CALLBACK_TABLE, *PKERNEL_CALLBACK_TABLE;\ntypedef struct _GDI_HANDLE_ENTRY GDI_HANDLE_ENTRY, *PGDI_HANDLE_ENTRY;\n\n// PEB->AppCompatFlags\n#define KACF_OLDGETSHORTPATHNAME                      0x00000001\n#define KACF_VERSIONLIE_NOT_USED                      0x00000002\n#define KACF_GETTEMPPATH_NOT_USED                     0x00000004\n#define KACF_GETDISKFREESPACE                         0x00000008\n#define KACF_FTMFROMCURRENTAPT                        0x00000020\n#define KACF_DISALLOWORBINDINGCHANGES                 0x00000040\n#define KACF_OLE32VALIDATEPTRS                        0x00000080\n#define KACF_DISABLECICERO                            0x00000100\n#define KACF_OLE32ENABLEASYNCDOCFILE                  0x00000200\n#define KACF_OLE32ENABLELEGACYEXCEPTIONHANDLING       0x00000400\n#define KACF_RPCDISABLENDRCLIENTHARDENING             0x00000800\n#define KACF_RPCDISABLENDRMAYBENULL_SIZEIS            0x00001000\n#define KACF_DISABLEALLDDEHACK_NOT_USED               0x00002000\n#define KACF_RPCDISABLENDR61_RANGE                    0x00004000\n#define KACF_RPC32ENABLELEGACYEXCEPTIONHANDLING       0x00008000\n#define KACF_OLE32DOCFILEUSELEGACYNTFSFLAGS           0x00010000\n#define KACF_RPCDISABLENDRCONSTIIDCHECK               0x00020000\n#define KACF_USERDISABLEFORWARDERPATCH                0x00040000\n#define KACF_OLE32DISABLENEW_WMPAINT_DISPATCH         0x00100000\n#define KACF_ADDRESTRICTEDSIDINCOINITIALIZESECURITY   0x00200000\n#define KACF_ALLOCDEBUGINFOFORCRITSECTIONS            0x00400000\n#define KACF_OLEAUT32ENABLEUNSAFELOADTYPELIBRELATIVE  0x00800000\n#define KACF_ALLOWMAXIMIZEDWINDOWGAMMA                0x01000000\n#define KACF_DONOTADDTOCACHE                          0x80000000\n#define KACF_DISABLEPOSIXDELETEFILE                   0x100000000 // rev KernelBase!InternalDeleteFileW\n#define KACF_ENABLE_PROCESS_SYSTEMDPIAWARENESS        0x20000000000000 // rev // Enable Per-Process System DPI Awareness and Opt-in to Per-Process System DPI mode.\n#define KACF_DISABLE_PROCESS_SYSTEMDPIAWARENESS       0x40000000000000 // rev // Disable Per-Process System DPI Awareness and force legacy DPI behavior.\n#define KACF_ENABLE_GDI_DPI_SCALING                   0x800000000000000\n#define KACF_FORCE_DISABLE_GDI_SCALING                0x4000000000000000\n\n// PEB->CrossProcessFlags\n#define PEB_FLAG_PROCESS_IN_JOB                       0x00000001 // Process is part of a job\n#define PEB_FLAG_PROCESS_INITIALIZING                 0x00000002 // Process is initializing\n#define PEB_FLAG_PROCESS_USING_VEH                    0x00000004 // Process is using VEH\n#define PEB_FLAG_PROCESS_USING_VCH                    0x00000008 // Process is using VCH\n#define PEB_FLAG_PROCESS_USING_FTH                    0x00000010 // Process is using FTH\n#define PEB_FLAG_PROCESS_PREVIOUSLY_THROTTLED         0x00000020 // Process was previously throttled\n#define PEB_FLAG_PROCESS_CURRENTLY_THROTTLED          0x00000040 // Process is currently throttled\n#define PEB_FLAG_PROCESS_IMAGES_HOT_PATCHED           0x00000080 // Process images are hot patched (RS5+)\n\n// private\n#define API_SET_SECTION_NAME \".apiset\"\n\n// private\n#define API_SET_SCHEMA_VERSION_V2 0x00000002 // WIN7, WIN8\n#define API_SET_SCHEMA_VERSION_V4 0x00000004 // WINBLUE\n#define API_SET_SCHEMA_VERSION_V6 0x00000006 // since THRESHOLD\n#define API_SET_SCHEMA_VERSION API_SET_SCHEMA_VERSION_V6\n\n// private\n#define API_SET_SCHEMA_FLAGS_SEALED 0x00000001\n#define API_SET_SCHEMA_FLAGS_HOST_EXTENSION 0x00000002\n\n// private\n#define API_SET_SCHEMA_ENTRY_FLAGS_SEALED 0x00000001\n#define API_SET_SCHEMA_ENTRY_FLAGS_EXTENSION 0x00000002\n\n// private\ntypedef struct _API_SET_VALUE_ENTRY_V2\n{\n    ULONG NameOffset; // to WCHAR[NameLength / sizeof(WCHAR)], from schema base\n    ULONG NameLength;\n    ULONG ValueOffset; // to WCHAR[ValueLength / sizeof(WCHAR)], from schema base\n    ULONG ValueLength;\n} API_SET_VALUE_ENTRY_V2, *PAPI_SET_VALUE_ENTRY_V2;\n\n// private\ntypedef struct _API_SET_VALUE_ARRAY_V2\n{\n    ULONG Count;\n    _Field_size_full_(Count) API_SET_VALUE_ENTRY_V2 Array[ANYSIZE_ARRAY];\n} API_SET_VALUE_ARRAY_V2, *PAPI_SET_VALUE_ARRAY_V2;\n\n// private\ntypedef struct _API_SET_NAMESPACE_ENTRY_V2\n{\n    ULONG NameOffset; // to WCHAR[NameLength / sizeof(WCHAR)], from schema base\n    ULONG NameLength;\n    ULONG DataOffset; // to API_SET_VALUE_ARRAY_V2, from schema base\n} API_SET_NAMESPACE_ENTRY_V2, *PAPI_SET_NAMESPACE_ENTRY_V2;\n\n// private // PEB->ApiSetMap on WIN7, WIN8\ntypedef struct _API_SET_NAMESPACE_ARRAY_V2\n{\n    ULONG Version; // API_SET_SCHEMA_VERSION_V2\n    ULONG Count;\n    _Field_size_full_(Count) API_SET_NAMESPACE_ENTRY_V2 Array[ANYSIZE_ARRAY];\n} API_SET_NAMESPACE_ARRAY_V2, *PAPI_SET_NAMESPACE_ARRAY_V2;\n\n// private\ntypedef struct _API_SET_VALUE_ENTRY_V4\n{\n    ULONG Flags;\n    ULONG NameOffset; // to WCHAR[NameLength / sizeof(WCHAR)], from schema base\n    ULONG NameLength;\n    ULONG ValueOffset; // to WCHAR[ValueLength / sizeof(WCHAR)], from schema base\n    ULONG ValueLength;\n} API_SET_VALUE_ENTRY_V4, *PAPI_SET_VALUE_ENTRY_V4;\n\n// private\ntypedef struct _API_SET_VALUE_ARRAY_V4\n{\n    ULONG Flags;\n    ULONG Count;\n    _Field_size_full_(Count) API_SET_VALUE_ENTRY_V4 Array[ANYSIZE_ARRAY];\n} API_SET_VALUE_ARRAY_V4, *PAPI_SET_VALUE_ARRAY_V4;\n\n// private\ntypedef struct _API_SET_NAMESPACE_ENTRY_V4\n{\n    ULONG Flags; // API_SET_SCHEMA_ENTRY_FLAGS_*\n    ULONG NameOffset; // to WCHAR[NameLength / sizeof(WCHAR)], from schema base\n    ULONG NameLength;\n    ULONG AliasOffset; // to WCHAR[AliasLength / sizeof(WCHAR)], from schema base\n    ULONG AliasLength;\n    ULONG DataOffset; // to API_SET_VALUE_ARRAY_V4, from schema base\n} API_SET_NAMESPACE_ENTRY_V4, *PAPI_SET_NAMESPACE_ENTRY_V4;\n\n// private // PEB->ApiSetMap on WINBLUE\ntypedef struct _API_SET_NAMESPACE_ARRAY_V4\n{\n    ULONG Version; // API_SET_SCHEMA_VERSION_V4\n    ULONG Size;\n    ULONG Flags; // API_SET_SCHEMA_FLAGS_*\n    ULONG Count;\n    _Field_size_full_(Count) API_SET_NAMESPACE_ENTRY_V4 Array[ANYSIZE_ARRAY];\n} API_SET_NAMESPACE_ARRAY_V4, *PAPI_SET_NAMESPACE_ARRAY_V4;\n\n// private\ntypedef struct _API_SET_VALUE_ENTRY\n{\n    ULONG Flags;\n    ULONG NameOffset; // to WCHAR[NameLength / sizeof(WCHAR)], from schema base\n    ULONG NameLength;\n    ULONG ValueOffset; // to WCHAR[ValueLength / sizeof(WCHAR)], from schema base\n    ULONG ValueLength;\n} API_SET_VALUE_ENTRY, *PAPI_SET_VALUE_ENTRY;\n\n// private\ntypedef struct _API_SET_NAMESPACE_ENTRY\n{\n    ULONG Flags; // API_SET_SCHEMA_ENTRY_FLAGS_*\n    ULONG NameOffset; // to WCHAR[NameLength / sizeof(WCHAR)], from schema base\n    ULONG NameLength;\n    ULONG HashedLength;\n    ULONG ValueOffset; // to API_SET_VALUE_ENTRY[ValueCount], from schema base\n    ULONG ValueCount;\n} API_SET_NAMESPACE_ENTRY, *PAPI_SET_NAMESPACE_ENTRY;\n\n// private\ntypedef struct _API_SET_HASH_ENTRY\n{\n    ULONG Hash;\n    ULONG Index;\n} API_SET_HASH_ENTRY, *PAPI_SET_HASH_ENTRY;\n\n// private // PEB->ApiSetMap since THRESHOLD\ntypedef struct _API_SET_NAMESPACE\n{\n    ULONG Version; // API_SET_SCHEMA_VERSION_V6\n    ULONG Size;\n    ULONG Flags; // API_SET_SCHEMA_FLAGS_*\n    ULONG Count;\n    ULONG EntryOffset; // to API_SET_NAMESPACE_ENTRY[Count], from this struct base\n    ULONG HashOffset; // to API_SET_HASH_ENTRY[Count], from this struct base\n    ULONG HashFactor;\n} API_SET_NAMESPACE, *PAPI_SET_NAMESPACE;\n\n// PEB->TelemetryCoverageHeader\ntypedef struct _TELEMETRY_COVERAGE_HEADER\n{\n    UCHAR MajorVersion;\n    UCHAR MinorVersion;\n    struct\n    {\n        USHORT TracingEnabled : 1;\n        USHORT Reserved1 : 15;\n    };\n    ULONG HashTableEntries;\n    ULONG HashIndexMask;\n    ULONG TableUpdateVersion;\n    ULONG TableSizeInBytes;\n    ULONG LastResetTick;\n    ULONG ResetRound;\n    ULONG Reserved2;\n    ULONG RecordedCount;\n    ULONG Reserved3[4];\n    ULONG HashTable[ANYSIZE_ARRAY];\n} TELEMETRY_COVERAGE_HEADER, *PTELEMETRY_COVERAGE_HEADER;\n\ntypedef struct _WER_RECOVERY_INFO\n{\n    ULONG Length;\n    PVOID Callback;\n    PVOID Parameter;\n    HANDLE Started;\n    HANDLE Finished;\n    HANDLE InProgress;\n    LONG LastError;\n    BOOL Successful;\n    ULONG PingInterval;\n    ULONG Flags;\n} WER_RECOVERY_INFO, *PWER_RECOVERY_INFO;\n\ntypedef struct _WER_FILE\n{\n    USHORT Flags;\n    WCHAR Path[MAX_PATH];\n} WER_FILE, *PWER_FILE;\n\ntypedef struct _WER_MEMORY\n{\n    PVOID Address;\n    ULONG Size;\n} WER_MEMORY, *PWER_MEMORY;\n\ntypedef struct _WER_GATHER\n{\n    PVOID Next;\n    USHORT Flags;\n    union\n    {\n      WER_FILE File;\n      WER_MEMORY Memory;\n    } v;\n} WER_GATHER, *PWER_GATHER;\n\ntypedef struct _WER_METADATA\n{\n    PVOID Next;\n    WCHAR Key[64];\n    WCHAR Value[128];\n} WER_METADATA, *PWER_METADATA;\n\ntypedef struct _WER_RUNTIME_DLL\n{\n    PVOID Next;\n    ULONG Length;\n    PVOID Context;\n    WCHAR CallbackDllPath[MAX_PATH];\n} WER_RUNTIME_DLL, *PWER_RUNTIME_DLL;\n\ntypedef struct _WER_DUMP_COLLECTION\n{\n    PVOID Next;\n    ULONG ProcessId;\n    ULONG ThreadId;\n} WER_DUMP_COLLECTION, *PWER_DUMP_COLLECTION;\n\ntypedef struct _WER_HEAP_MAIN_HEADER\n{\n    WCHAR Signature[16];\n    LIST_ENTRY Links;\n    HANDLE Mutex;\n    PVOID FreeHeap;\n    ULONG FreeCount;\n} WER_HEAP_MAIN_HEADER, *PWER_HEAP_MAIN_HEADER;\n\n#ifndef RESTART_MAX_CMD_LINE\n#define RESTART_MAX_CMD_LINE 1024\n#endif\n\ntypedef struct _WER_PEB_HEADER_BLOCK\n{\n    LONG Length;\n    WCHAR Signature[16];\n    WCHAR AppDataRelativePath[64];\n    WCHAR RestartCommandLine[RESTART_MAX_CMD_LINE];\n    WER_RECOVERY_INFO RecoveryInfo;\n    PWER_GATHER Gather;\n    PWER_METADATA MetaData;\n    PWER_RUNTIME_DLL RuntimeDll;\n    PWER_DUMP_COLLECTION DumpCollection;\n    LONG GatherCount;\n    LONG MetaDataCount;\n    LONG DumpCount;\n    LONG Flags;\n    WER_HEAP_MAIN_HEADER MainHeader;\n    PVOID Reserved;\n} WER_PEB_HEADER_BLOCK, *PWER_PEB_HEADER_BLOCK;\n\n#define GDI_HANDLE_BUFFER_SIZE32 34\n#define GDI_HANDLE_BUFFER_SIZE64 60\n\n#ifndef _WIN64\n#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32\n#else\n#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64\n#endif\n\ntypedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE];\n\ntypedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32];\ntypedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64];\n\ntypedef _Function_class_(PS_POST_PROCESS_INIT_ROUTINE)\nVOID NTAPI PS_POST_PROCESS_INIT_ROUTINE(\n    VOID\n    );\ntypedef PS_POST_PROCESS_INIT_ROUTINE* PPS_POST_PROCESS_INIT_ROUTINE;\n\n#ifndef RTL_FLS_MAXIMUM_AVAILABLE\n#define RTL_FLS_MAXIMUM_AVAILABLE 128\n#endif\n#ifndef FLS_MAXIMUM_AVAILABLE\n#define FLS_MAXIMUM_AVAILABLE 4080\n#endif\n#ifndef TLS_MINIMUM_AVAILABLE\n#define TLS_MINIMUM_AVAILABLE 64\n#endif\n#ifndef TLS_EXPANSION_SLOTS\n#define TLS_EXPANSION_SLOTS 1024\n#endif\n\n/**\n * Process Environment Block (PEB) structure.\n *\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb\n */\ntypedef struct _PEB\n{\n    //\n    // The process was cloned with an inherited address space.\n    //\n    BOOLEAN InheritedAddressSpace;\n\n    //\n    // The process has image file execution options (IFEO).\n    //\n    BOOLEAN ReadImageFileExecOptions;\n\n    //\n    // The process has a debugger attached.\n    //\n    BOOLEAN BeingDebugged;\n\n    union\n    {\n        BOOLEAN BitField;\n        struct\n        {\n            BOOLEAN ImageUsesLargePages : 1;            // The process uses large image regions (4 MB).\n            BOOLEAN IsProtectedProcess : 1;             // The process is a protected process.\n            BOOLEAN IsImageDynamicallyRelocated : 1;    // The process image base address was relocated.\n            BOOLEAN SkipPatchingUser32Forwarders : 1;   // The process skipped forwarders for User32.dll functions. 1 for 64-bit, 0 for 32-bit.\n            BOOLEAN IsPackagedProcess : 1;              // The process is a packaged store process (APPX/MSIX).\n            BOOLEAN IsAppContainerProcess : 1;          // The process has an AppContainer token.\n            BOOLEAN IsProtectedProcessLight : 1;        // The process is a protected process (light).\n            BOOLEAN IsLongPathAwareProcess : 1;         // The process is long path aware.\n        };\n    };\n\n    //\n    // Handle to a mutex for synchronization.\n    //\n    HANDLE Mutant;\n\n    //\n    // Pointer to the base address of the process image.\n    //\n    PVOID ImageBaseAddress;\n\n    //\n    // Pointer to the process loader data.\n    //\n    PPEB_LDR_DATA Ldr;\n\n    //\n    // Pointer to the process parameters.\n    //\n    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;\n\n    //\n    // Reserved.\n    //\n    PVOID SubSystemData;\n\n    //\n    // Pointer to the process default heap.\n    //\n    PVOID ProcessHeap;\n\n    //\n    // Pointer to a critical section used to synchronize access to the PEB.\n    //\n    PRTL_CRITICAL_SECTION FastPebLock;\n\n    //\n    // Pointer to a singly linked list used by ATL.\n    //\n    PSLIST_HEADER AtlThunkSListPtr;\n\n    //\n    // Handle to the Image File Execution Options key.\n    //\n    HANDLE IFEOKey;\n\n    //\n    // Cross process flags.\n    //\n    union\n    {\n        ULONG CrossProcessFlags;\n        struct\n        {\n            ULONG ProcessInJob : 1;                 // The process is part of a job.\n            ULONG ProcessInitializing : 1;          // The process is initializing.\n            ULONG ProcessUsingVEH : 1;              // The process is using VEH.\n            ULONG ProcessUsingVCH : 1;              // The process is using VCH.\n            ULONG ProcessUsingFTH : 1;              // The process is using FTH.\n            ULONG ProcessPreviouslyThrottled : 1;   // The process was previously throttled.\n            ULONG ProcessCurrentlyThrottled : 1;    // The process is currently throttled.\n            ULONG ProcessImagesHotPatched : 1;      // The process images are hot patched. // RS5\n            ULONG ReservedBits0 : 24;\n        };\n    };\n\n    //\n    // User32 KERNEL_CALLBACK_TABLE (ntuser.h)\n    //\n    union\n    {\n        PKERNEL_CALLBACK_TABLE KernelCallbackTable;\n        PVOID UserSharedInfoPtr;\n    };\n\n    //\n    // Reserved.\n    //\n    ULONG SystemReserved;\n\n    //\n    // Pointer to the Active Template Library (ATL) singly linked list (32-bit)\n    //\n    ULONG AtlThunkSListPtr32;\n\n    //\n    // Pointer to the API Set Schema.\n    //\n    PAPI_SET_NAMESPACE ApiSetMap;\n\n    //\n    // Counter for TLS expansion.\n    //\n    ULONG TlsExpansionCounter;\n\n    //\n    // Pointer to the TLS bitmap.\n    //\n    PRTL_BITMAP TlsBitmap;\n\n    //\n    // Bits for the TLS bitmap.\n    //\n    ULONG TlsBitmapBits[2];\n\n    //\n    // Reserved for CSRSS.\n    //\n    PVOID ReadOnlySharedMemoryBase;\n\n    //\n    // Pointer to the USER_SHARED_DATA for the current SILO.\n    //\n    PSILO_USER_SHARED_DATA SharedData;\n\n    //\n    // Reserved for CSRSS.\n    //\n    PVOID* ReadOnlyStaticServerData;\n\n    //\n    // Pointer to the ANSI code page data.\n    //\n    PCPTABLEINFO AnsiCodePageData;\n\n    //\n    // Pointer to the OEM code page data.\n    //\n    PCPTABLEINFO OemCodePageData;\n\n    //\n    // Pointer to the Unicode case table data.\n    //\n    PNLSTABLEINFO UnicodeCaseTableData;\n\n    //\n    // The total number of system processors.\n    //\n    ULONG NumberOfProcessors;\n\n    //\n    // Global flags for the system.\n    //\n    union\n    {\n        ULONG NtGlobalFlag;\n        struct\n        {\n            ULONG StopOnException : 1;          // FLG_STOP_ON_EXCEPTION\n            ULONG ShowLoaderSnaps : 1;          // FLG_SHOW_LDR_SNAPS\n            ULONG DebugInitialCommand : 1;      // FLG_DEBUG_INITIAL_COMMAND\n            ULONG StopOnHungGUI : 1;            // FLG_STOP_ON_HUNG_GUI\n            ULONG HeapEnableTailCheck : 1;      // FLG_HEAP_ENABLE_TAIL_CHECK\n            ULONG HeapEnableFreeCheck : 1;      // FLG_HEAP_ENABLE_FREE_CHECK\n            ULONG HeapValidateParameters : 1;   // FLG_HEAP_VALIDATE_PARAMETERS\n            ULONG HeapValidateAll : 1;          // FLG_HEAP_VALIDATE_ALL\n            ULONG ApplicationVerifier : 1;      // FLG_APPLICATION_VERIFIER\n            ULONG MonitorSilentProcessExit : 1; // FLG_MONITOR_SILENT_PROCESS_EXIT\n            ULONG PoolEnableTagging : 1;        // FLG_POOL_ENABLE_TAGGING\n            ULONG HeapEnableTagging : 1;        // FLG_HEAP_ENABLE_TAGGING\n            ULONG UserStackTraceDb : 1;         // FLG_USER_STACK_TRACE_DB\n            ULONG KernelStackTraceDb : 1;       // FLG_KERNEL_STACK_TRACE_DB\n            ULONG MaintainObjectTypeList : 1;   // FLG_MAINTAIN_OBJECT_TYPELIST\n            ULONG HeapEnableTagByDll : 1;       // FLG_HEAP_ENABLE_TAG_BY_DLL\n            ULONG DisableStackExtension : 1;    // FLG_DISABLE_STACK_EXTENSION\n            ULONG EnableCsrDebug : 1;           // FLG_ENABLE_CSRDEBUG\n            ULONG EnableKDebugSymbolLoad : 1;   // FLG_ENABLE_KDEBUG_SYMBOL_LOAD\n            ULONG DisablePageKernelStacks : 1;  // FLG_DISABLE_PAGE_KERNEL_STACKS\n            ULONG EnableSystemCritBreaks : 1;   // FLG_ENABLE_SYSTEM_CRIT_BREAKS\n            ULONG HeapDisableCoalescing : 1;    // FLG_HEAP_DISABLE_COALESCING\n            ULONG EnableCloseExceptions : 1;    // FLG_ENABLE_CLOSE_EXCEPTIONS\n            ULONG EnableExceptionLogging : 1;   // FLG_ENABLE_EXCEPTION_LOGGING\n            ULONG EnableHandleTypeTagging : 1;  // FLG_ENABLE_HANDLE_TYPE_TAGGING\n            ULONG HeapPageAllocs : 1;           // FLG_HEAP_PAGE_ALLOCS\n            ULONG DebugInitialCommandEx : 1;    // FLG_DEBUG_INITIAL_COMMAND_EX\n            ULONG DisableDbgPrint : 1;          // FLG_DISABLE_DBGPRINT\n            ULONG CritSecEventCreation : 1;     // FLG_CRITSEC_EVENT_CREATION\n            ULONG LdrTopDown : 1;               // FLG_LDR_TOP_DOWN\n            ULONG EnableHandleExceptions : 1;   // FLG_ENABLE_HANDLE_EXCEPTIONS\n            ULONG DisableProtDlls : 1;          // FLG_DISABLE_PROTDLLS\n        } NtGlobalFlags;\n    };\n\n    //\n    // Timeout for critical sections.\n    //\n    LARGE_INTEGER CriticalSectionTimeout;\n\n    //\n    // Reserved size for heap segments.\n    //\n    SIZE_T HeapSegmentReserve;\n\n    //\n    // Committed size for heap segments.\n    //\n    SIZE_T HeapSegmentCommit;\n\n    //\n    // Threshold for decommitting total free heap.\n    //\n    SIZE_T HeapDeCommitTotalFreeThreshold;\n\n    //\n    // Threshold for decommitting free heap blocks.\n    //\n    SIZE_T HeapDeCommitFreeBlockThreshold;\n\n    //\n    // Number of process heaps.\n    //\n    ULONG NumberOfHeaps;\n\n    //\n    // Maximum number of process heaps.\n    //\n    ULONG MaximumNumberOfHeaps;\n\n    //\n    // Pointer to an array of process heaps. ProcessHeaps is initialized\n    // to point to the first free byte after the PEB and MaximumNumberOfHeaps\n    // is computed from the page size used to hold the PEB, less the fixed\n    // size of this data structure.\n    //\n    PVOID* ProcessHeaps;\n\n    //\n    // Pointer to the system GDI shared handle table.\n    //\n    PGDI_HANDLE_ENTRY GdiSharedHandleTable;\n\n    //\n    // Pointer to the process starter helper.\n    //\n    PVOID ProcessStarterHelper;\n\n    //\n    // The maximum number of GDI function calls during batch operations (GdiSetBatchLimit)\n    //\n    ULONG GdiDCAttributeList;\n\n    //\n    // Pointer to the loader lock critical section.\n    //\n    PRTL_CRITICAL_SECTION LoaderLock;\n\n    //\n    // Major version of the operating system.\n    //\n    ULONG OSMajorVersion;\n\n    //\n    // Minor version of the operating system.\n    //\n    ULONG OSMinorVersion;\n\n    //\n    // Build number of the operating system.\n    //\n    USHORT OSBuildNumber;\n\n    //\n    // CSD version of the operating system.\n    //\n    USHORT OSCSDVersion;\n\n    //\n    // Platform ID of the operating system.\n    //\n    ULONG OSPlatformId;\n\n    //\n    // Subsystem version of the current process image (PE Headers).\n    //\n    ULONG ImageSubsystem;\n\n    //\n    // Major version of the current process image subsystem (PE Headers).\n    //\n    ULONG ImageSubsystemMajorVersion;\n\n    //\n    // Minor version of the current process image subsystem (PE Headers).\n    //\n    ULONG ImageSubsystemMinorVersion;\n\n    //\n    // Affinity mask for the current process.\n    //\n    KAFFINITY ActiveProcessAffinityMask;\n\n    //\n    // Temporary buffer for GDI handles accumulated in the current batch.\n    //\n    GDI_HANDLE_BUFFER GdiHandleBuffer;\n\n    //\n    // Pointer to the post-process initialization routine available for use by the application.\n    //\n    PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;\n\n    //\n    // Pointer to the TLS expansion bitmap.\n    //\n    PRTL_BITMAP TlsExpansionBitmap;\n\n    //\n    // Bits for the TLS expansion bitmap. TLS_EXPANSION_SLOTS\n    //\n    ULONG TlsExpansionBitmapBits[32];\n\n    //\n    // Session ID of the current process.\n    //\n    ULONG SessionId;\n\n    //\n    // Application compatibility flags. KACF_*\n    //\n    ULARGE_INTEGER AppCompatFlags;\n\n    //\n    // Application compatibility flags. KACF_*\n    //\n    ULARGE_INTEGER AppCompatFlagsUser;\n\n    //\n    // Pointer to the Application SwitchBack Compatibility Engine.\n    //\n    PVOID pShimData;\n\n    //\n    // Pointer to the Application Compatibility Engine.\n    //\n    PAPPCOMPAT_EXE_DATA AppCompatInfo;\n\n    //\n    // CSD version string of the operating system.\n    //\n    UNICODE_STRING CSDVersion;\n\n    //\n    // Pointer to the process activation context.\n    //\n    PACTIVATION_CONTEXT_DATA ActivationContextData;\n\n    //\n    // Pointer to the process assembly storage map.\n    //\n    PASSEMBLY_STORAGE_MAP ProcessAssemblyStorageMap;\n\n    //\n    // Pointer to the system default activation context.\n    //\n    PACTIVATION_CONTEXT_DATA SystemDefaultActivationContextData;\n\n    //\n    // Pointer to the system assembly storage map.\n    //\n    PASSEMBLY_STORAGE_MAP SystemAssemblyStorageMap;\n\n    //\n    // Minimum stack commit size.\n    //\n    SIZE_T MinimumStackCommit;\n\n    //\n    // since 19H1 (previously FlsCallback to FlsHighIndex)\n    //\n    PVOID SparePointers[2];\n\n    //\n    // Pointer to the patch loader data.\n    //\n    PVOID PatchLoaderData;\n\n    //\n    // Pointer to the CHPE V2 process information. CHPEV2_PROCESS_INFO\n    //\n    PVOID ChpeV2ProcessInfo;\n\n    //\n    // Packaged process feature state.\n    //\n    ULONG AppModelFeatureState;\n\n    //\n    // SpareUlongs\n    //\n    ULONG SpareUlongs[2];\n\n    //\n    // Active code page.\n    //\n    USHORT ActiveCodePage;\n\n    //\n    // OEM code page.\n    //\n    USHORT OemCodePage;\n\n    //\n    // Code page case mapping.\n    //\n    USHORT UseCaseMapping;\n\n    //\n    // Unused NLS field.\n    //\n    USHORT UnusedNlsField;\n\n    //\n    // Pointer to the application WER registration data.\n    //\n    PWER_PEB_HEADER_BLOCK WerRegistrationData;\n\n    //\n    // Pointer to the application WER assert pointer.\n    //\n    PVOID WerShipAssertPtr;\n\n    //\n    // Pointer to the EC bitmap on ARM64. (Windows 11 and above)\n    //\n    union\n    {\n        PVOID pContextData; // Pointer to the switchback compatibility engine (Windows 7 and below)\n        PVOID EcCodeBitMap; // Pointer to the EC bitmap on ARM64 (Windows 11 and above) // since WIN11\n    };\n\n    //\n    // Reserved.\n    //\n    PVOID ImageHeaderHash;\n\n    //\n    // ETW tracing flags.\n    //\n    union\n    {\n        ULONG TracingFlags;\n        struct\n        {\n            ULONG HeapTracingEnabled : 1;       // ETW heap tracing enabled.\n            ULONG CritSecTracingEnabled : 1;    // ETW lock tracing enabled.\n            ULONG LibLoaderTracingEnabled : 1;  // ETW loader tracing enabled.\n            ULONG SpareTracingBits : 29;\n        };\n    };\n\n    //\n    // Reserved for CSRSS.\n    //\n    ULONGLONG CsrServerReadOnlySharedMemoryBase;\n\n    //\n    // Pointer to the thread pool worker list lock.\n    //\n    PRTL_CRITICAL_SECTION TppWorkerpListLock;\n\n    //\n    // Pointer to the thread pool worker list.\n    //\n    LIST_ENTRY TppWorkerpList;\n\n    //\n    // Wait on address hash table. (RtlWaitOnAddress)\n    //\n    PVOID WaitOnAddressHashTable[128];\n\n    //\n    // Pointer to the telemetry coverage header. // since RS3\n    //\n    PTELEMETRY_COVERAGE_HEADER TelemetryCoverageHeader;\n\n    //\n    // Cloud file flags. (ProjFs and Cloud Files) // since RS4\n    //\n    ULONG CloudFileFlags;\n\n    //\n    // Cloud file diagnostic flags.\n    //\n    ULONG CloudFileDiagFlags;\n\n    //\n    // Placeholder compatibility mode. (ProjFs and Cloud Files)\n    //\n    CHAR PlaceholderCompatibilityMode;\n\n    //\n    // Reserved for placeholder compatibility mode.\n    //\n    CHAR PlaceholderCompatibilityModeReserved[7];\n\n    //\n    // Pointer to leap second data. // since RS5\n    //\n    PLEAP_SECOND_DATA LeapSecondData;\n\n    //\n    // Leap second flags.\n    //\n    union\n    {\n        ULONG LeapSecondFlags;\n        struct\n        {\n            ULONG SixtySecondEnabled : 1; // Leap seconds enabled.\n            ULONG Reserved : 31;\n        };\n    };\n\n    //\n    // Global flags for the process.\n    //\n    ULONG NtGlobalFlag2;\n\n    //\n    // Extended feature disable mask (AVX). // since WIN11\n    //\n    ULONGLONG ExtendedFeatureDisableMask;\n} PEB, *PPEB;\n\n#ifdef _WIN64\nstatic_assert(FIELD_OFFSET(PEB, SessionId) == 0x2C0, \"FIELD_OFFSET(PEB, SessionId) is incorrect\");\nstatic_assert(sizeof(PEB) == 0x7d0, \"Size of PEB is incorrect\"); // WIN11\n#else\nstatic_assert(FIELD_OFFSET(PEB, SessionId) == 0x1D4, \"FIELD_OFFSET(PEB, SessionId) is incorrect\");\nstatic_assert(sizeof(PEB) == 0x488, \"Size of PEB is incorrect\"); // WIN11\n#endif\n\n#define GDI_BATCH_BUFFER_SIZE 310\n\n/**\n * The GDI_TEB_BATCH structure is used to store information about GDI batch operations.\n */\ntypedef struct _GDI_TEB_BATCH\n{\n    ULONG Offset;\n    ULONG_PTR HDC;\n    ULONG Buffer[GDI_BATCH_BUFFER_SIZE];\n} GDI_TEB_BATCH, *PGDI_TEB_BATCH;\n\n#define TEB_ACTIVE_FRAME_CONTEXT_FLAG_EXTENDED (0x00000001)\n\n/**\n * The TEB_ACTIVE_FRAME_CONTEXT structure is used to store information about an active frame context.\n */\ntypedef struct _TEB_ACTIVE_FRAME_CONTEXT\n{\n    ULONG Flags;\n    PCSTR FrameName;\n} TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT;\n\n/**\n * The TEB_ACTIVE_FRAME_CONTEXT_EX structure extends TEB_ACTIVE_FRAME_CONTEXT with additional information.\n */\ntypedef struct _TEB_ACTIVE_FRAME_CONTEXT_EX\n{\n    TEB_ACTIVE_FRAME_CONTEXT BasicContext;\n    PCSTR SourceLocation;\n} TEB_ACTIVE_FRAME_CONTEXT_EX, *PTEB_ACTIVE_FRAME_CONTEXT_EX;\n\n#define TEB_ACTIVE_FRAME_FLAG_EXTENDED (0x00000001)\n\n/**\n * The TEB_ACTIVE_FRAME structure is used to store information about an active frame.\n */\ntypedef struct _TEB_ACTIVE_FRAME\n{\n    ULONG Flags;\n    struct _TEB_ACTIVE_FRAME *Previous;\n    PTEB_ACTIVE_FRAME_CONTEXT Context;\n} TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME;\n\n/**\n * The TEB_ACTIVE_FRAME_EX structure extends TEB_ACTIVE_FRAME with additional information.\n */\ntypedef struct _TEB_ACTIVE_FRAME_EX\n{\n    TEB_ACTIVE_FRAME BasicFrame;\n    PVOID ExtensionIdentifier;\n} TEB_ACTIVE_FRAME_EX, *PTEB_ACTIVE_FRAME_EX;\n\n#define STATIC_UNICODE_BUFFER_LENGTH 261\n#define WIN32_CLIENT_INFO_LENGTH 62\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n// private\ntypedef struct _CALLBACKWND\n{\n    HWND hwnd;\n    ULONG_PTR pwnd;\n    PACTIVATION_CONTEXT ActCtx;\n} CALLBACKWND, *PCALLBACKWND;\n\n// private\ntypedef struct tagDPICONTEXTINFO\n{\n    ULONG dpiContext;\n    LOGICAL Dirty;\n} DPICONTEXTINFO, *PDPICONTEXTINFO;\n\n// private + rev\ntypedef struct tagCLIENTINFO\n{\n    ULONG_PTR CI_flags;\n    ULONG_PTR Spins;\n    ULONG ExpWinVer;\n    ULONG CompatFlags;\n    ULONG CompatFlags2;\n    ULONG TIFlags;\n    struct tagDESKTOPINFO* DeskInfo;\n    PVOID DesktopBase; // ClientDelta before RS2\n    HHOOK hkCurrent;\n    ULONG Hooks;\n    CALLBACKWND CallbackWnd;\n    ULONG HookCurrent;\n    LONG InDDEMLCallback;\n    struct tagCLIENTTHREADINFO* ClientThreadInfo;\n    ULONG_PTR HookData;\n    ULONG KeyCache;\n    UCHAR KeyState[8];\n    ULONG AsyncKeyCache;\n    UCHAR AsyncKeyState[8];\n    UCHAR AsyncKeyStateRecentDown[8];\n    HKL hKL;\n    USHORT CodePage;\n    UCHAR DbcsCFOld[2];\n    UCHAR DbcsCFNew[2];\n    MSG msgDbcsCB;\n    PULONG RegisteredClasses;\n    HANDLE mmcssHandle;\n    ULONG_PTR CI_exflags;\n    DPICONTEXTINFO dci;\n} CLIENTINFO, *PCLIENTINFO;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// rev - xor key for ReservedForNtRpc\n#ifdef _WIN64\n#define RPC_THREAD_POINTER_KEY 0xABABABABDEDEDEDEui64\n#else\n#define RPC_THREAD_POINTER_KEY 0xABABABAB\n#endif\n\n/**\n * Thread Environment Block (TEB) structure.\n *\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-teb\n */\ntypedef struct _TEB\n{\n    //\n    // Thread Information Block (TIB) contains the thread's stack, base and limit addresses, the current stack pointer, and the exception list.\n    //\n    NT_TIB NtTib;\n\n    //\n    // Reserved.\n    //\n    PVOID EnvironmentPointer;\n\n    //\n    // Client ID for this thread.\n    //\n    CLIENT_ID ClientId;\n\n    //\n    // A handle to an active Remote Procedure Call (RPC) if the thread is currently involved in an RPC operation.\n    //\n    PVOID ActiveRpcHandle;\n\n    //\n    // A pointer to the __declspec(thread) local storage array.\n    //\n    PVOID ThreadLocalStoragePointer;\n\n    //\n    // A pointer to the Process Environment Block (PEB), which contains information about the process.\n    //\n    PPEB ProcessEnvironmentBlock;\n\n    //\n    // The previous Win32 error value for this thread.\n    //\n    ULONG LastErrorValue;\n\n    //\n    // The number of critical sections currently owned by this thread.\n    //\n    ULONG CountOfOwnedCriticalSections;\n\n    //\n    // Reserved.\n    //\n    PVOID CsrClientThread;\n\n    //\n    // Reserved for win32k.sys\n    //\n    PVOID Win32ThreadInfo;\n \n    //\n    // Reserved for user32.dll\n    //\n    ULONG User32Reserved[26];\n\n    //\n    // Reserved for winsrv.dll\n    //\n    ULONG UserReserved[5];\n\n    //\n    // Reserved.\n    //\n    PVOID WOW32Reserved;\n\n    //\n    // The LCID of the current thread. (Kernel32!GetThreadLocale)\n    //\n    LCID CurrentLocale;\n\n    //\n    // Reserved.\n    //\n    ULONG FpSoftwareStatusRegister;\n\n    //\n    // Reserved.\n    //\n    PVOID ReservedForDebuggerInstrumentation[16];\n\n#ifdef _WIN64\n    //\n    // Reserved for floating-point emulation.\n    //\n    PVOID SystemReserved1[25];\n\n    //\n    // Per-thread fiber local storage. (Teb->HasFiberData)\n    //\n    PVOID HeapFlsData;\n\n    //\n    // Reserved.\n    //\n    ULONG_PTR RngState[4];\n#else\n    //\n    // Reserved.\n    //\n    PVOID SystemReserved1[26];\n#endif\n\n    //\n    // Placeholder compatibility mode. (ProjFs and Cloud Files)\n    //\n    CHAR PlaceholderCompatibilityMode;\n\n    //\n    // Indicates whether placeholder hydration is always explicit.\n    //\n    BOOLEAN PlaceholderHydrationAlwaysExplicit;\n\n    //\n    // ProjFs and Cloud Files (reparse point) file virtualization.\n    //\n    CHAR PlaceholderReserved[10];\n\n    //\n    // The process ID (PID) that the current COM server thread is acting on behalf of.\n    //\n    ULONG ProxiedProcessId;\n\n    //\n    // Pointer to the activation context stack for the current thread.\n    //\n    ACTIVATION_CONTEXT_STACK ActivationStack;\n\n    //\n    // Opaque operation on behalf of another user or process.\n    //\n    UCHAR WorkingOnBehalfTicket[8];\n\n    //\n    // The last exception status for the current thread.\n    //\n    NTSTATUS ExceptionCode;\n\n    //\n    // Pointer to the activation context stack for the current thread.\n    //\n    PACTIVATION_CONTEXT_STACK ActivationContextStackPointer;\n\n    //\n    // The stack pointer (SP) of the current system call or exception during instrumentation.\n    //\n    ULONG_PTR InstrumentationCallbackSp;\n\n    //\n    // The program counter (PC) of the previous system call or exception during instrumentation.\n    //\n    ULONG_PTR InstrumentationCallbackPreviousPc;\n\n    //\n    // The stack pointer (SP) of the previous system call or exception during instrumentation.\n    //\n    ULONG_PTR InstrumentationCallbackPreviousSp;\n\n#ifdef _WIN64\n    //\n    // The miniversion ID of the current transacted file operation.\n    //\n    ULONG TxFsContext;\n#endif\n\n    //\n    // Indicates the state of the system call or exception instrumentation callback.\n    //\n    BOOLEAN InstrumentationCallbackDisabled;\n\n#ifdef _WIN64\n    //\n    // Indicates the state of alignment exceptions for unaligned load/store operations.\n    //\n    BOOLEAN UnalignedLoadStoreExceptions;\n#endif\n\n#ifndef _WIN64\n    //\n    // SpareBytes.\n    //\n    UCHAR SpareBytes[23];\n\n    //\n    // The miniversion ID of the current transacted file operation.\n    //\n    ULONG TxFsContext;\n#endif\n\n    //\n    // Reserved for GDI (Win32k).\n    //\n    GDI_TEB_BATCH GdiTebBatch;\n    CLIENT_ID RealClientId;\n    HANDLE GdiCachedProcessHandle;\n    ULONG GdiClientPID;\n    ULONG GdiClientTID;\n    PVOID GdiThreadLocalInfo;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n    union\n    {\n        //\n        // User32 (Win32k) thread information.\n        //\n        CLIENTINFO Win32ClientInfo;\n        ULONG_PTR Win32ClientInfoArea[WIN32_CLIENT_INFO_LENGTH];\n    };\n#else\n    ULONG_PTR Win32ClientInfo[WIN32_CLIENT_INFO_LENGTH];\n#endif\n\n    //\n    // Reserved for opengl32.dll\n    //\n    PVOID glDispatchTable[233];\n    ULONG_PTR glReserved1[29];\n    PVOID glReserved2;\n    PVOID glSectionInfo;\n    PVOID glSection;\n    PVOID glTable;\n    PVOID glCurrentRC;\n    PVOID glContext;\n\n    //\n    // The previous status value for this thread.\n    //\n    NTSTATUS LastStatusValue;\n\n    //\n    // A static string for use by the application.\n    //\n    UNICODE_STRING StaticUnicodeString;\n\n    //\n    // A static buffer for use by the application.\n    //\n    WCHAR StaticUnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];\n\n    //\n    // The maximum stack size and indicates the base of the stack.\n    //\n    PVOID DeallocationStack;\n\n    //\n    // Data for Thread Local Storage. (TlsGetValue)\n    //\n    PVOID TlsSlots[TLS_MINIMUM_AVAILABLE];\n\n    //\n    // Reserved for TLS.\n    //\n    LIST_ENTRY TlsLinks;\n\n    //\n    // Reserved for NTVDM.\n    //\n    PVOID Vdm;\n\n    //\n    // Reserved for RPC. The pointer is XOR'ed with RPC_THREAD_POINTER_KEY.\n    //\n    PVOID ReservedForNtRpc;\n\n    //\n    // Reserved for Debugging (DebugActiveProcess).\n    //\n    PVOID DbgSsReserved[2];\n\n    //\n    // The error mode for the current thread. (GetThreadErrorMode)\n    //\n    ULONG HardErrorMode;\n\n    //\n    // Reserved.\n    //\n#ifdef _WIN64\n    PVOID Instrumentation[11];\n#else\n    PVOID Instrumentation[9];\n#endif\n\n    //\n    // Reserved.\n    //\n    GUID ActivityId;\n\n    //\n    // The identifier of the service that created the thread. (svchost)\n    //\n    PVOID SubProcessTag;\n\n    //\n    // Reserved.\n    //\n    PVOID PerflibData;\n\n    //\n    // Reserved.\n    //\n    PVOID EtwTraceData;\n\n    //\n    // The address of a socket handle during a blocking socket operation. (WSAStartup)\n    //\n    HANDLE WinSockData;\n\n    //\n    // The number of function calls accumulated in the current GDI batch. (GdiSetBatchLimit)\n    //\n    ULONG GdiBatchCount;\n\n    //\n    // The preferred processor for the current thread. (SetThreadIdealProcessor/SetThreadIdealProcessorEx)\n    //\n    union\n    {\n        PROCESSOR_NUMBER CurrentIdealProcessor;\n        ULONG IdealProcessorValue;\n        struct\n        {\n            UCHAR ReservedPad0;\n            UCHAR ReservedPad1;\n            UCHAR ReservedPad2;\n            UCHAR IdealProcessor;\n        };\n    };\n\n    //\n    // The minimum size of the stack available during any stack overflow exceptions. (SetThreadStackGuarantee)\n    //\n    ULONG GuaranteedStackBytes;\n\n    //\n    // Reserved.\n    //\n    PVOID ReservedForPerf;\n\n    //\n    // Reserved for Object Linking and Embedding (OLE)\n    //\n    PSOleTlsData ReservedForOle;\n\n    //\n    // Indicates whether the thread is waiting on the loader lock.\n    //\n    ULONG WaitingOnLoaderLock;\n\n    //\n    // The saved priority state for the thread.\n    //\n    PVOID SavedPriorityState;\n\n    //\n    // Reserved.\n    //\n    ULONG_PTR ReservedForCodeCoverage;\n\n    //\n    // Reserved.\n    //\n    PVOID ThreadPoolData;\n\n    //\n    // Pointer to the TLS (Thread Local Storage) expansion slots for the thread.\n    //\n    PVOID *TlsExpansionSlots;\n\n#ifdef _WIN64\n    PVOID ChpeV2CpuAreaInfo; // CHPEV2_CPUAREA_INFO // previously DeallocationBStore\n    PVOID Unused; // previously BStoreLimit\n#endif\n\n    //\n    // The generation of the MUI (Multilingual User Interface) data.\n    //\n    ULONG MuiGeneration;\n\n    //\n    // Indicates whether the thread is impersonating another security context.\n    //\n    ULONG IsImpersonating;\n\n    //\n    // Pointer to the NLS (National Language Support) cache.\n    //\n    PVOID NlsCache;\n\n    //\n    // Pointer to the AppCompat/Shim Engine data.\n    //\n    PVOID pShimData;\n\n    //\n    // Reserved.\n    //\n    ULONG HeapData;\n\n    //\n    // Handle to the current transaction associated with the thread.\n    //\n    HANDLE CurrentTransactionHandle;\n\n    //\n    // Pointer to the active frame for the thread.\n    //\n    PTEB_ACTIVE_FRAME ActiveFrame;\n\n    //\n    // Reserved for FLS (RtlProcessFlsData).\n    //\n    PVOID FlsData;\n\n    //\n    // Pointer to the preferred languages for the current thread. (GetThreadPreferredUILanguages)\n    //\n    PVOID PreferredLanguages;\n\n    //\n    // Pointer to the user-preferred languages for the current thread. (GetUserPreferredUILanguages)\n    //\n    PVOID UserPrefLanguages;\n\n    //\n    // Pointer to the merged preferred languages for the current thread. (MUI_MERGE_USER_FALLBACK)\n    //\n    PVOID MergedPrefLanguages;\n\n    //\n    // Indicates whether the thread is impersonating another user's language settings.\n    //\n    ULONG MuiImpersonation;\n\n    //\n    // Reserved.\n    //\n    union\n    {\n        USHORT CrossTebFlags;\n        USHORT SpareCrossTebBits : 16;\n    };\n\n    //\n    // SameTebFlags modify the state and behavior of the current thread.\n    //\n    union\n    {\n        USHORT SameTebFlags;\n        struct\n        {\n            USHORT SafeThunkCall : 1;\n            USHORT InDebugPrint : 1;            // Indicates if the thread is currently in a debug print routine.\n            USHORT HasFiberData : 1;            // Indicates if the thread has local fiber-local storage (FLS).\n            USHORT SkipThreadAttach : 1;        // Indicates if the thread should suppress DLL_THREAD_ATTACH notifications.\n            USHORT WerInShipAssertCode : 1;\n            USHORT RanProcessInit : 1;          // Indicates if the thread has run process initialization code.\n            USHORT ClonedThread : 1;            // Indicates if the thread is a clone of a different thread.\n            USHORT SuppressDebugMsg : 1;        // Indicates if the thread should suppress LOAD_DLL_DEBUG_INFO notifications.\n            USHORT DisableUserStackWalk : 1;\n            USHORT RtlExceptionAttached : 1;\n            USHORT InitialThread : 1;           // Indicates if the thread is the initial thread of the process.\n            USHORT SessionAware : 1;\n            USHORT LoadOwner : 1;               // Indicates if the thread is the owner of the process loader lock.\n            USHORT LoaderWorker : 1;\n            USHORT SkipLoaderInit : 1;\n            USHORT SkipFileAPIBrokering : 1;\n        };\n    };\n\n    //\n    // Pointer to the callback function that is called when a KTM transaction scope is entered.\n    //\n    PVOID TxnScopeEnterCallback;\n\n    //\n    // Pointer to the callback function that is called when a KTM transaction scope is exited.\n    ///\n    PVOID TxnScopeExitCallback;\n\n    //\n    // Pointer to optional context data for use by the application when a KTM transaction scope callback is called.\n    //\n    PVOID TxnScopeContext;\n\n    //\n    // The lock count of critical sections for the current thread.\n    //\n    ULONG LockCount;\n\n    //\n    // The offset to the WOW64 (Windows on Windows) TEB for the current thread.\n    //\n    LONG WowTebOffset;\n\n    //\n    // Pointer to the DLL containing the resource (valid after LdrFindResource_U/LdrResFindResource/etc... returns).\n    //\n    PLDR_RESLOADER_RET ResourceRetValue;\n\n    //\n    // Reserved for Windows Driver Framework (WDF).\n    //\n    PVOID ReservedForWdf;\n\n    //\n    // Reserved for the Microsoft C runtime (CRT).\n    //\n    ULONGLONG ReservedForCrt;\n\n    //\n    // The Host Compute Service (HCS) container identifier.\n    //\n    GUID EffectiveContainerId;\n\n    //\n    // Reserved for Kernel32!Sleep (SpinWait).\n    //\n    ULONGLONG LastSleepCounter; // since Win11\n\n    //\n    // Reserved for Kernel32!Sleep (SpinWait).\n    //\n    ULONG SpinCallCount;\n\n    //\n    // Extended feature disable mask (AVX).\n    //\n    ULONGLONG ExtendedFeatureDisableMask;\n\n    //\n    // Reserved.\n    //\n    PVOID SchedulerSharedDataSlot; // since 24H2\n\n    //\n    // Reserved.\n    //\n    PVOID HeapWalkContext;\n\n    //\n    // The primary processor group affinity of the thread.\n    //\n    GROUP_AFFINITY PrimaryGroupAffinity;\n\n    //\n    // Read-copy-update (RCU) synchronization context.\n    //\n    ULONG Rcu[2];\n} TEB, *PTEB;\n\n#ifdef _WIN64\nstatic_assert(FIELD_OFFSET(TEB, SchedulerSharedDataSlot) == 0x1850, \"Size of TEB is incorrect\"); // WIN11\nstatic_assert(sizeof(TEB) == 0x1878, \"Size of TEB is incorrect\"); // 24H2\n#else\nstatic_assert(FIELD_OFFSET(TEB, SchedulerSharedDataSlot) == 0x1018, \"Size of TEB is incorrect\"); // WIN11\nstatic_assert(sizeof(TEB) == 0x1038, \"Size of TEB is incorrect\"); // 24H2\n#endif\n\n#endif\n"
  },
  {
    "path": "phnt/include/ntpfapi.h",
    "content": "/*\n * Prefetcher (Superfetch) support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTPFAPI_H\n#define _NTPFAPI_H\n\n// begin_private\n\n//\n// Prefetch\n//\n\ntypedef enum _PREFETCHER_INFORMATION_CLASS\n{\n    PrefetcherRetrieveTrace = 1,            // q: PF_RETRIEVE_TRACE\n    PrefetcherSystemParameters,             // q: PF_SYSTEM_PREFETCH_PARAMETERS\n    PrefetcherBootPhase,                    // s: PF_BOOT_PHASE_ID\n    PrefetcherSpare1,                       // q: PrefetcherRetrieveBootLoaderTrace\n    PrefetcherOperationProcess,             // s: PF_OPERATION_PROCESS\n    PrefetcherCacheEntryUpdate,             // s: PF_CACHE_ENTRY_UPDATE\n    PrefetcherSpare2,\n    PrefetcherAppLaunchScenarioControl,     // s: PF_APP_LAUNCH_SCENARIO_CONTROL\n    PrefetcherInformationMax\n} PREFETCHER_INFORMATION_CLASS;\n\n#define PREFETCHER_INFORMATION_VERSION 23 // rev\n#define PREFETCHER_INFORMATION_MAGIC ('kuhC') // rev\n\ntypedef struct _PREFETCHER_INFORMATION\n{\n    _In_ ULONG Version;\n    _In_ ULONG Magic;\n    _In_ PREFETCHER_INFORMATION_CLASS PrefetcherInformationClass;\n    _Inout_ PVOID PrefetcherInformation;\n    _Inout_ ULONG PrefetcherInformationLength;\n} PREFETCHER_INFORMATION, *PPREFETCHER_INFORMATION;\n\n// rev\ntypedef struct _PF_RETRIEVE_TRACE\n{\n    UCHAR Buffer[1];\n} PF_RETRIEVE_TRACE, *PPF_RETRIEVE_TRACE;\n\ntypedef enum _PF_ENABLE_STATUS\n{\n    PfSvNotSpecified,\n    PfSvEnabled,\n    PfSvDisabled,\n    PfSvMaxEnableStatus\n} PF_ENABLE_STATUS;\n\n// rev\ntypedef struct _PF_TRACE_LIMITS\n{\n    ULONG MaxNumPages;\n    ULONG MaxNumSections;\n    LONGLONG TimerPeriod;\n} PF_TRACE_LIMITS, *PPF_TRACE_LIMITS;\n\n// rev\ntypedef struct _PF_SYSTEM_PREFETCH_PARAMETERS\n{\n    PF_ENABLE_STATUS EnableStatus[2];\n    PF_TRACE_LIMITS TraceLimits[2];\n    ULONG MaxNumActiveTraces;\n    ULONG MaxNumSavedTraces;\n    WCHAR RootDirPath[32];\n    WCHAR HostingApplicationList[128];\n} PF_SYSTEM_PREFETCH_PARAMETERS, *PPF_SYSTEM_PREFETCH_PARAMETERS;\n\ntypedef enum _PF_BOOT_PHASE_ID\n{\n    PfKernelInitPhase = 0,\n    PfBootDriverInitPhase = 90,\n    PfSystemDriverInitPhase = 120,\n    PfSessionManagerInitPhase = 150,\n    PfSMRegistryInitPhase = 180,\n    PfVideoInitPhase = 210,\n    PfPostVideoInitPhase = 240,\n    PfBootAcceptedRegistryInitPhase = 270,\n    PfUserShellReadyPhase = 300,\n    PfMaxBootPhaseId = 900\n} PF_BOOT_PHASE_ID;\n\n#define PF_SN_OPERATION_PROCESS_VERSION 1\n\ntypedef enum _PF_OPERATION_PROCESS_ACTION\n{\n    PfSnOpProcessBegin = 0,\n    PfSnOpProcessEnd = 1,\n    PfSnOpProcessMax = 2\n} PF_OPERATION_PROCESS_ACTION;\n\ntypedef struct _PF_OPERATION_PROCESS\n{\n    UCHAR Version;\n    UCHAR Action; // PF_SYSTEM_OPERATION_PROCESS_ACTION\n    USHORT Reserved;\n    ULONG OpFlags;\n    ULONG Value;\n} PF_OPERATION_PROCESS, *PPF_OPERATION_PROCESS;\n\n#define PF_BOOT_CONTROL_VERSION 1\n\ntypedef struct _PF_BOOT_CONTROL\n{\n    ULONG Version;\n    ULONG DisableBootPrefetching;\n} PF_BOOT_CONTROL, *PPF_BOOT_CONTROL;\n\n#define PF_CACHE_ENTRY_UPDATE_VERSION 2\n\ntypedef struct _PF_CACHE_ENTRY_UPDATE\n{\n    ULONG Version;\n    UCHAR Name[64];\n    ULONG NewValue;\n} PF_CACHE_ENTRY_UPDATE, *PPF_CACHE_ENTRY_UPDATE;\n\n#define PF_APP_LAUNCH_SCENARIO_CONTROL_VERSION 1\n\ntypedef struct _PF_APP_LAUNCH_SCENARIO_CONTROL\n{\n    ULONG Version;\n    ULONG Enable; // must be non-zero\n    HANDLE ProcessHandle;\n} PF_APP_LAUNCH_SCENARIO_CONTROL, *PPF_APP_LAUNCH_SCENARIO_CONTROL;\n\n//\n// Superfetch\n//\n\n// rev\ntypedef enum _SUPERFETCH_INFORMATION_CLASS\n{\n    SuperfetchRetrieveTrace = 1,               // q: PF_SYSTEM_SUPERFETCH_RETRIEVE_TRACE // PfGetCompletedTrace\n    SuperfetchSystemParameters,                // q: PF_SYSTEM_SUPERFETCH_PARAMETERS\n    SuperfetchLogEvent,                        // s: PF_LOG_EVENT_DATA\n    SuperfetchGenerateTrace,                   // s: PF_GENERATE_TRACE_CONTROL\n    SuperfetchPrefetch,\n    SuperfetchPfnQuery,                        // q: PF_PFN_PRIO_REQUEST\n    SuperfetchPfnSetPriority,                  // s: PF_PFN_PRIO_REQUEST // MmSetPfnListInfo\n    SuperfetchPrivSourceQuery,                 // q: PF_PRIVSOURCE_QUERY_REQUEST\n    SuperfetchSequenceNumberQuery,             // q: ULONG\n    SuperfetchScenarioPhase,                   // s: PF_SCENARIO_PHASE_INFO // 10\n    SuperfetchWorkerPriority,                  // s: PF_WORKER_PRIORITY_CONTROL\n    SuperfetchScenarioQuery,                   // q: PF_SCENARIO_QUERY_INFO\n    SuperfetchScenarioPrefetch,                // s: PF_SCENARIO_PREFETCH_INFO\n    SuperfetchRobustnessControl,               // s: PF_ROBUSTNESS_CONTROL\n    SuperfetchTimeControl,                     // s: PF_TIME_CONTROL\n    SuperfetchMemoryListQuery,                 // q: PF_MEMORY_LIST_INFO\n    SuperfetchMemoryRangesQuery,               // q: PF_PHYSICAL_MEMORY_RANGE_INFO_V1/V2\n    SuperfetchTracingControl,                  // s: PF_ACCESS_TRACING_CONTROL\n    SuperfetchTrimWhileAgingControl,           // s: PF_TRIM_WHILE_AGING_CONTROL\n    SuperfetchRepurposedByPrefetch,            // q: PF_REPURPOSED_BY_PREFETCH_INFO // 20\n    SuperfetchChannelPowerRequest,\n    SuperfetchMovePages,                       // s: PF_PFN_PRIO_REQUEST // MmRelocatePfnList\n    SuperfetchVirtualQuery,                    // q: PF_VIRTUAL_QUERY\n    SuperfetchCombineStatsQuery,               // q: PF_PAGECOMBINE_AGGREGATE_STAT\n    SuperfetchSetMinWsAgeRate,                 // s: PF_MIN_WS_AGE_RATE_CONTROL\n    SuperfetchDeprioritizeOldPagesInWs,        // s: PF_DEPRIORITIZE_OLD_PAGES\n    SuperfetchFileExtentsQuery,                // q: PF_FILE_EXTENTS_INFO\n    SuperfetchGpuUtilizationQuery,             // q: PF_GPU_UTILIZATION_INFO\n    SuperfetchPfnSet,                          // s: PF_PFN_PRIO_REQUEST // since WIN11\n    SuperfetchInformationMax\n} SUPERFETCH_INFORMATION_CLASS;\n\n#define SUPERFETCH_INFORMATION_VERSION 45 // rev\n#define SUPERFETCH_INFORMATION_MAGIC ('kuhC') // rev\n\ntypedef struct _SUPERFETCH_INFORMATION\n{\n    _In_ ULONG Version;\n    _In_ ULONG Magic;\n    _In_ SUPERFETCH_INFORMATION_CLASS SuperfetchInformationClass;\n    _Inout_ PVOID SuperfetchInformation;\n    _Inout_ ULONG SuperfetchInformationLength;\n} SUPERFETCH_INFORMATION, *PSUPERFETCH_INFORMATION;\n\n// rev\ntypedef struct _PF_SYSTEM_SUPERFETCH_RETRIEVE_TRACE\n{\n    union\n    {\n        struct\n        {\n            ULONGLONG RequestType;     // Must be 2 for \"get completed trace\"\n            ULONGLONG Reserved;        // Ignored on input\n            HANDLE    PartitionHandle;\n        } Input;\n        struct\n        {\n            ULONGLONG TypeFlags;       // 0x0000000000180002 on success\n            ULONGLONG Timestamp;       // Scaled TSC value\n            HANDLE    PartitionHandle;\n        } Output;\n\n        //\n        // Raw view of the buffer for opaque access\n        //\n        UCHAR Buffer[ANYSIZE_ARRAY];\n    };\n} PF_SYSTEM_SUPERFETCH_RETRIEVE_TRACE, *PPF_SYSTEM_SUPERFETCH_RETRIEVE_TRACE;\n\n// rev\ntypedef struct _PF_SYSTEM_SUPERFETCH_PARAMETERS\n{\n    ULONG EnabledComponents;\n    ULONG BootID;\n    ULONG SavedSectInfoTracesMax;\n    ULONG SavedPageAccessTracesMax;\n    ULONG ScenarioPrefetchTimeoutStandby;\n    ULONG ScenarioPrefetchTimeoutHibernate;\n    ULONG ScenarioPrefetchTimeoutHiberBoot;\n} PF_SYSTEM_SUPERFETCH_PARAMETERS, *PPF_SYSTEM_SUPERFETCH_PARAMETERS;\n\n// rev\ntypedef enum _PF_EVENT_TYPE\n{\n    PfEventTypeImageLoad = 0,\n    PfEventTypeAppLaunch = 1,\n    PfEventTypeStartTrace = 2,\n    PfEventTypeEndTrace = 3,\n    PfEventTypeTimestamp = 4,\n    PfEventTypeOperation = 5,\n    PfEventTypeRepurpose = 6,\n    PfEventTypeForegroundProcess = 7,\n    PfEventTypeTimeRange = 8,\n    PfEventTypeUserInput = 9,\n    PfEventTypeFileAccess = 10,\n    PfEventTypeUnmap = 11,\n    PfEventTypeUtilization = 11,\n    PfEventTypeMemInfo = 12,\n    PfEventTypeFileDelete = 13,\n    PfEventTypeAppExit = 14,\n    PfEventTypeSystemTime = 15,\n    PfEventTypePower = 16,\n    PfEventTypeSessionChange = 17,\n    PfEventTypeHardFaultTimeStamp = 18,\n    PfEventTypeVirtualFree = 19,\n    PfEventTypePerfInfo = 20,\n    PfEventTypeProcessSnapshot = 21,\n    PfEventTypeUserSnapshot = 22,\n    PfEventTypeStreamSequenceNumber = 23,\n    PfEventTypeFileTruncate = 24,\n    PfEventTypeFileRename = 25,\n    PfEventTypeFileCreate = 26,\n    PfEventTypeAgCxContext = 27,\n    PfEventTypePowerAction = 28,\n    PfEventTypeHardFaultTS = 29,\n    PfEventTypeRobustInfo = 30,\n    PfEventTypeFileDefrag = 31,\n    PfEventTypeMax = 32\n} PF_EVENT_TYPE;\n\n#define PF_LOG_EVENT_DATA_VERSION 1\n\ntypedef struct _PF_LOG_EVENT_DATA\n{\n    ULONG Version; // PF_LOG_EVENT_DATA_VERSION\n    union\n    {\n        ULONG Packed; // [31:7]=DataSize, [6:5]=Flags, [4:0]=EventType (PF_EVENT_TYPE)\n        struct\n        {\n            ULONG DataSize : 25; // in bytes\n            ULONG Flags    : 2;\n            ULONG EventType: 5; // 2,3,5,27 accepted by the handler // PF_EVENT_TYPE\n        };\n    };\n    PVOID EventData;\n    HANDLE PartitionHandle;\n} PF_LOG_EVENT_DATA , *PPF_LOG_EVENT_DATA ;\n\ntypedef struct _PFN_TRIPLET\n{\n    ULONGLONG MaskOrKey;        // Compared against identity with 0x1FFFFFFFFFFFE00 mask\n    ULONGLONG Pfn;              // Page frame number\n    ULONGLONG Flags;            // Request/result flags\n} PFN_TRIPLET, *PPFN_TRIPLET;\n\n#define PF_PFN_PRIO_REQUEST_VERSION 1\n#define PF_PFN_PRIO_REQUEST_QUERY_MEMORY_LIST 0x1\n#define PF_PFN_PRIO_REQUEST_VALID_FLAGS 0x1\n\ntypedef struct _PF_PFN_PRIO_REQUEST\n{\n    ULONG Version;\n    ULONG RequestFlags;\n    SIZE_T PfnCount;\n    SYSTEM_MEMORY_LIST_INFORMATION MemInfo;\n    union\n    {\n        // Input: (class 6/16) MmQueryPfnList fills identities here\n        MMPFN_IDENTITY PageIdentities[256]; // ANYSIZE_ARRAY\n        // Output: (class 7/29/1D) caller supplies PFN_TRIPLETs here\n        PFN_TRIPLET Entries[256]; // ANYSIZE_ARRAY\n    };\n} PF_PFN_PRIO_REQUEST, *PPF_PFN_PRIO_REQUEST;\n\ntypedef enum _PFS_PRIVATE_PAGE_SOURCE_TYPE\n{\n    PfsPrivateSourceKernel,\n    PfsPrivateSourceSession,\n    PfsPrivateSourceProcess,\n    PfsPrivateSourceMax\n} PFS_PRIVATE_PAGE_SOURCE_TYPE;\n\ntypedef struct _PFS_PRIVATE_PAGE_SOURCE\n{\n    PFS_PRIVATE_PAGE_SOURCE_TYPE Type;\n    union\n    {\n        ULONG SessionId;\n        ULONG ProcessId;\n    };\n    ULONG ImagePathHash;\n    ULONG_PTR UniqueProcessHash;\n} PFS_PRIVATE_PAGE_SOURCE, *PPFS_PRIVATE_PAGE_SOURCE;\n\ntypedef struct _PF_PRIVSOURCE_INFO\n{\n    PFS_PRIVATE_PAGE_SOURCE DbInfo;\n    PVOID EProcess;\n    SIZE_T WsPrivatePages;\n    SIZE_T TotalPrivatePages;\n    ULONG SessionID;\n    UCHAR ImageName[16];\n    union\n    {\n        SIZE_T WsSwapPages;                 // process only PF_PRIVSOURCE_QUERY_WS_SWAP_PAGES.\n        SIZE_T SessionPagedPoolPages;       // session only.\n        SIZE_T StoreSizePages;              // process only PF_PRIVSOURCE_QUERY_STORE_INFO.\n    };\n    SIZE_T WsTotalPages;            // process/session only.\n    ULONG DeepFreezeTimeMs;         // process only.\n    ULONG ModernApp : 1;            // process only.\n    ULONG DeepFrozen : 1;           // process only. If set, DeepFreezeTimeMs contains the time at which the freeze occurred\n    ULONG Foreground : 1;           // process only.\n    ULONG PerProcessStore : 1;      // process only.\n    ULONG Spare : 28;\n} PF_PRIVSOURCE_INFO, *PPF_PRIVSOURCE_INFO;\n\n// rev\n#define PF_PRIVSOURCE_QUERY_REQUEST_VERSION 8\n#define PF_PRIVSOURCE_QUERY_REQUEST_FLAGS_QUERYWSPAGES 0x1\n#define PF_PRIVSOURCE_QUERY_REQUEST_FLAGS_QUERYCOMPRESSEDPAGES 0x2\n#define PF_PRIVSOURCE_QUERY_REQUEST_FLAGS_QUERYSKIPPAGES 0x4 // ??\n\n// rev\ntypedef struct _PF_PRIVSOURCE_QUERY_REQUEST\n{\n    ULONG Version;\n    ULONG Flags;\n    ULONG InfoCount;\n    PF_PRIVSOURCE_INFO InfoArray[1];\n} PF_PRIVSOURCE_QUERY_REQUEST, *PPF_PRIVSOURCE_QUERY_REQUEST;\n\n// rev\ntypedef enum _PF_PHASED_SCENARIO_TYPE\n{\n    PfScenarioTypeNone,\n    PfScenarioTypeStandby,\n    PfScenarioTypeHibernate,\n    PfScenarioTypeFUS,\n    PfScenarioTypeMax\n} PF_PHASED_SCENARIO_TYPE;\n\n// rev\n#define PF_SCENARIO_PHASE_INFO_VERSION 4\n\n// rev\ntypedef struct _PF_SCENARIO_PHASE_INFO\n{\n    ULONG Version;\n    PF_PHASED_SCENARIO_TYPE ScenType;\n    ULONG PhaseId;\n    ULONG SequenceNumber;\n    ULONG Flags;\n    ULONG FUSUserId;\n    ULONG Reserved0; // pad to 32 bytes (handler expects 32)\n    ULONG Reserved1;\n} PF_SCENARIO_PHASE_INFO, *PPF_SCENARIO_PHASE_INFO;\n\n// rev\ntypedef struct _PF_WORKER_PRIORITY_CONTROL\n{\n    ULONG Version;\n    KPRIORITY Priority; // 0..31 (STATUS_INVALID_PARAMETER if >31)\n    HANDLE PartitionHandle;\n} PF_WORKER_PRIORITY_CONTROL, *PPF_WORKER_PRIORITY_CONTROL;\n\n// rev\n#define PF_SCENARIO_QUERY_INFO_VERSION 4\n\n// rev\ntypedef struct _PF_SCENARIO_QUERY_INFO \n{\n    ULONG_PTR Version;\n    ULONG_PTR Field1;\n    ULONG_PTR Field2;\n    ULONG_PTR Field3;\n} PF_SCENARIO_QUERY_INFO , *PPF_SCENARIO_QUERY_INFO;\n\n// rev\ntypedef struct _PF_MEMORY_LIST_NODE\n{\n    ULONGLONG Node : 8;\n    ULONGLONG Spare : 56;\n    ULONGLONG StandbyLowPageCount;\n    ULONGLONG StandbyMediumPageCount;\n    ULONGLONG StandbyHighPageCount;\n    ULONGLONG FreePageCount;\n    ULONGLONG ModifiedPageCount;\n} PF_MEMORY_LIST_NODE, *PPF_MEMORY_LIST_NODE;\n\n// rev\ntypedef struct _PF_ROBUST_PROCESS_ENTRY\n{\n    ULONG ImagePathHash;\n    ULONG Pid;\n    ULONG Alignment;\n} PF_ROBUST_PROCESS_ENTRY, *PPF_ROBUST_PROCESS_ENTRY;\n\n// rev\ntypedef struct _PF_ROBUST_FILE_ENTRY\n{\n    ULONG FilePathHash;\n} PF_ROBUST_FILE_ENTRY, *PPF_ROBUST_FILE_ENTRY;\n\n// rev\ntypedef enum _PF_ROBUSTNESS_CONTROL_COMMAND\n{\n    PfRpControlUpdate = 0,\n    PfRpControlReset = 1,\n    PfRpControlRobustAllStart = 2,\n    PfRpControlRobustAllStop = 3,\n    PfRpControlCommandMax = 4\n} PF_ROBUSTNESS_CONTROL_COMMAND;\n\n// rev\n#define PF_ROBUSTNESS_CONTROL_VERSION 1\n\n// rev\ntypedef struct _PF_ROBUSTNESS_CONTROL\n{\n    ULONG Version;\n    PF_ROBUSTNESS_CONTROL_COMMAND Command;\n    ULONG DeprioProcessCount;\n    ULONG ExemptProcessCount;\n    ULONG DeprioFileCount;\n    ULONG ExemptFileCount;\n    PF_ROBUST_PROCESS_ENTRY ProcessEntries[1];\n    PF_ROBUST_FILE_ENTRY FileEntries[1];\n} PF_ROBUSTNESS_CONTROL, *PPF_ROBUSTNESS_CONTROL;\n\n// rev\ntypedef struct _PF_SCENARIO_PREFETCH_INFO\n{\n    ULONG Version;\n    ULONG State;\n} PF_SCENARIO_PREFETCH_INFO, *PPF_SCENARIO_PREFETCH_INFO;\n\n// rev\n#define PF_TRIM_WHILE_AGING_CONTROL_VERSION_1 1\n\n// rev\ntypedef enum _PF_TRIM_WHILE_AGING_STATE\n{\n    PfTrimWhileAgingOff = 0,\n    PfTrimWhileAgingLowPriority = 1,\n    PfTrimWhileAgingPassive = 2,\n    PfTrimWhileAgingNormal = 3,\n    PfTrimWhileAgingAggressive = 4,\n    PfTrimWhileAgingMax = 5,\n} PF_TRIM_WHILE_AGING_STATE, *PPF_TRIM_WHILE_AGING_STATE;\n\n// rev\ntypedef struct _PF_TRIM_WHILE_AGING_CONTROL_1\n{\n    ULONG Version;\n    PF_TRIM_WHILE_AGING_STATE TrimWhileAgingState;\n    BOOLEAN PrivatePageTrimAge;\n    BOOLEAN SharedPageTrimAge;\n    USHORT Spare;\n} PF_TRIM_WHILE_AGING_CONTROL_1, *PPF_TRIM_WHILE_AGING_CONTROL_1;\n\n#define PF_TRIM_WHILE_AGING_CONTROL_VERSION_2 2\n\n// rev\ntypedef struct _PF_TRIM_WHILE_AGING_CONTROL_2\n{\n    ULONG Version;\n    PF_TRIM_WHILE_AGING_STATE TrimWhileAgingState;\n    UCHAR PrivatePageTrimAge;      // 0..7\n    UCHAR SharedPageTrimAge;       // 0..7\n    USHORT Spare;                  // must be 0\n} PF_TRIM_WHILE_AGING_CONTROL_2, *PPF_TRIM_WHILE_AGING_CONTROL_2;\n\n// rev\ntypedef struct _PF_TIME_CONTROL\n{\n    LONG TimeAdjustment;\n} PF_TIME_CONTROL, *PPF_TIME_CONTROL;\n\n#define PF_MEMORY_LIST_INFO_VERSION 1\n\ntypedef struct _PF_MEMORY_LIST_INFO\n{\n    ULONG Version;\n    ULONG Size;\n    ULONG NodeCount;\n    PF_MEMORY_LIST_NODE Nodes[1];\n} PF_MEMORY_LIST_INFO, *PPF_MEMORY_LIST_INFO;\n\ntypedef struct _PF_PHYSICAL_MEMORY_RANGE\n{\n    ULONG_PTR BasePfn;\n    ULONG_PTR PageCount;\n} PF_PHYSICAL_MEMORY_RANGE, *PPF_PHYSICAL_MEMORY_RANGE;\n\n#define PF_PHYSICAL_MEMORY_RANGE_INFO_V1_VERSION 1\n\ntypedef struct _PF_PHYSICAL_MEMORY_RANGE_INFO_V1\n{\n    ULONG Version;\n    ULONG RangeCount;\n    PF_PHYSICAL_MEMORY_RANGE Ranges[1];\n} PF_PHYSICAL_MEMORY_RANGE_INFO_V1, *PPF_PHYSICAL_MEMORY_RANGE_INFO_V1;\n\n#define PF_PHYSICAL_MEMORY_RANGE_INFO_V2_VERSION 2\n\ntypedef struct _PF_PHYSICAL_MEMORY_RANGE_INFO_V2\n{\n    ULONG Version;\n    ULONG Flags;\n    SIZE_T RangeCount;\n    PF_PHYSICAL_MEMORY_RANGE Ranges[1];\n} PF_PHYSICAL_MEMORY_RANGE_INFO_V2, *PPF_PHYSICAL_MEMORY_RANGE_INFO_V2;\n\n// rev\ntypedef struct _PF_START_TRACE_CONTROL\n{\n    struct\n    {\n        ULONG Type;\n        ULONG Mode;\n        ULONG Flags;\n        ULONG Restart;\n    };\n    struct\n    {\n        HANDLE PartitionHandle; // in\n        HANDLE TraceHandleOut;  // out when Restart == 0\n    };\n} PF_START_TRACE_CONTROL, *PPF_START_TRACE_CONTROL;\n\n// rev\n#define PF_ACCESS_TRACING_CONTROL_VERSION 1\n\n// rev\ntypedef struct _PF_ACCESS_TRACING_CONTROL\n{\n    ULONG Version;\n    ULONG Command;\n    ULONG ComponentMask;\n} PF_ACCESS_TRACING_CONTROL, *PPF_ACCESS_TRACING_CONTROL;\n\n// rev\n#define PF_REPURPOSED_BY_PREFETCH_INFO_VERSION 1\n\n// rev\ntypedef struct _PF_REPURPOSED_BY_PREFETCH_INFO\n{\n    ULONG Version; // PF_REPURPOSED_BY_PREFETCH_INFO_VERSION\n    ULONG Reserved;\n    SIZE_T RepurposedByPrefetch;\n} PF_REPURPOSED_BY_PREFETCH_INFO, *PPF_REPURPOSED_BY_PREFETCH_INFO;\n\n// rev\n#define PF_VIRTUAL_QUERY_VERSION 1\n\n// rev\ntypedef struct _PF_VIRTUAL_QUERY\n{\n    ULONG Version;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG FaultInPageTables : 1;\n            ULONG ReportPageTables : 1;\n            ULONG Spare : 30;\n        };\n    };\n    PVOID QueryBuffer; // MEMORY_WORKING_SET_EX_INFORMATION[NumberOfPages] (input: VirtualAddress[], output: VirtualAttributes[])\n    SIZE_T QueryBufferSize; // NumberOfPages * sizeof(MEMORY_WORKING_SET_EX_INFORMATION)\n    HANDLE ProcessHandle;\n} PF_VIRTUAL_QUERY, *PPF_VIRTUAL_QUERY;\n\n// rev\n#define PF_PAGECOMBINE_AGGREGATE_STAT_VERSION 1\n\n// rev\ntypedef struct _PF_PAGECOMBINE_AGGREGATE_STAT\n{\n    ULONG Version;\n    ULONG CombineScanCount;\n    ULONG CombinedBlocksInUse;\n    ULONG SumCombinedBlocksReferenceCount;\n} PF_PAGECOMBINE_AGGREGATE_STAT, *PPF_PAGECOMBINE_AGGREGATE_STAT;\n\n// rev\n#define PF_MIN_WS_AGE_RATE_CONTROL_VERSION 1\n\n// rev\ntypedef struct _PF_MIN_WS_AGE_RATE_CONTROL\n{\n    ULONG Version;\n    ULONG SecondsToOldestAgeRate;\n} PF_MIN_WS_AGE_RATE_CONTROL, *PPF_MIN_WS_AGE_RATE_CONTROL;\n\n// rev\n#define PF_DEPRIORITIZE_OLD_PAGES_VERSION 3\n\n// rev\ntypedef struct _PF_DEPRIORITIZE_OLD_PAGES\n{\n    ULONG Version;\n    HANDLE ProcessHandle;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG TargetPriority : 4;\n            ULONG TrimPages : 2;\n            ULONG Spare : 26;\n        };\n    };\n} PF_DEPRIORITIZE_OLD_PAGES, *PPF_DEPRIORITIZE_OLD_PAGES;\n\n// rev\n#define PF_FILE_EXTENTS_INFO_VERSION 1\n\n// rev\ntypedef struct _PF_FILE_EXTENTS_INFO\n{\n    ULONG Version;\n    PWSTR FilePath;\n    ULONG FilePathSize;\n    ULONG VolumePathSize;\n    LARGE_INTEGER FileIndexNumber;\n    ULONG VolumeSerialNumber;\n    RETRIEVAL_POINTERS_BUFFER ExtentsBuffer;\n    ULONGLONG ExtentsBufferSize;\n} PF_FILE_EXTENTS_INFO, *PPF_FILE_EXTENTS_INFO;\n\n// rev\n#define PF_FILE_EXTENTS_INFO_VERSION2 2\n\ntypedef struct _PF_FILE_EXTENTS_INFO_V2\n{\n    ULONG Version;      // must be 2 \n    ULONG Reserved0;\n    PWSTR PathUtf16;\n\n    ULONG PathBytes;    // must be even, within bounds\n    ULONG PathMeta;     // used to compute an index (>>1) tested for '\\\\'\n    ULONG ParamA;       // must be nonzero and < PathBytes (per checks)\n    ULONG Reserved1;\n\n    PVOID OutMeta0;\n    PVOID OutBuffer;\n    ULONG OutBufferBytesRequested;\n    ULONG Reserved2;\n} PF_FILE_EXTENTS_INFO_V2, *PPF_FILE_EXTENTS_INFO_V2;\n\n// rev\n#define PF_GPU_UTILIZATION_INFO_VERSION 1\n\n// rev\ntypedef struct _PF_GPU_UTILIZATION_INFO\n{\n    ULONG Version;\n    ULONG SessionId;\n    ULONGLONG GpuTime;\n} PF_GPU_UTILIZATION_INFO, *PPF_GPU_UTILIZATION_INFO;\n\n// end_private\n\n#endif // _NTPFAPI_H\n"
  },
  {
    "path": "phnt/include/ntpnpapi.h",
    "content": "/*\n * Plug and Play support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTPNPAPI_H\n#define _NTPNPAPI_H\n\n#include <cfg.h>\n\ntypedef enum _PLUGPLAY_EVENT_CATEGORY\n{\n    HardwareProfileChangeEvent,\n    TargetDeviceChangeEvent,\n    DeviceClassChangeEvent,\n    CustomDeviceEvent,\n    DeviceInstallEvent,\n    DeviceArrivalEvent,\n    PowerEvent,\n    VetoEvent,\n    BlockedDriverEvent,\n    InvalidIDEvent,\n    MaxPlugEventCategory\n} PLUGPLAY_EVENT_CATEGORY, *PPLUGPLAY_EVENT_CATEGORY;\n\ntypedef struct _PLUGPLAY_EVENT_BLOCK\n{\n    GUID EventGuid;\n    PLUGPLAY_EVENT_CATEGORY EventCategory;\n    PULONG Result;\n    ULONG Flags;\n    ULONG TotalSize;\n    PVOID DeviceObject;\n\n    union\n    {\n        struct\n        {\n            GUID ClassGuid;\n            WCHAR SymbolicLinkName[1];\n        } DeviceClass;\n        struct\n        {\n            WCHAR DeviceIds[1];\n        } TargetDevice;\n        struct\n        {\n            WCHAR DeviceId[1];\n        } InstallDevice;\n        struct\n        {\n            PVOID NotificationStructure;\n            WCHAR DeviceIds[1];\n        } CustomNotification;\n        struct\n        {\n            PVOID Notification;\n        } ProfileNotification;\n        struct\n        {\n            ULONG NotificationCode;\n            ULONG NotificationData;\n        } PowerNotification;\n        struct\n        {\n            PNP_VETO_TYPE VetoType;\n            WCHAR DeviceIdVetoNameBuffer[1]; // DeviceId<null>VetoName<null><null>\n        } VetoNotification;\n        struct\n        {\n            GUID BlockedDriverGuid;\n        } BlockedDriverNotification;\n        struct\n        {\n            WCHAR ParentId[1];\n        } InvalidIDNotification;\n    } u;\n} PLUGPLAY_EVENT_BLOCK, *PPLUGPLAY_EVENT_BLOCK;\n\ntypedef enum _PLUGPLAY_CONTROL_CLASS\n{\n    PlugPlayControlEnumerateDevice, // PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA\n    PlugPlayControlRegisterNewDevice, // PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA\n    PlugPlayControlDeregisterDevice, // PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA\n    PlugPlayControlInitializeDevice, // PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA\n    PlugPlayControlStartDevice, // PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA\n    PlugPlayControlUnlockDevice, // PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA\n    PlugPlayControlQueryAndRemoveDevice, // PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA\n    PlugPlayControlUserResponse, // PLUGPLAY_CONTROL_USER_RESPONSE_DATA\n    PlugPlayControlGenerateLegacyDevice, // PLUGPLAY_CONTROL_LEGACY_DEVGEN_DATA\n    PlugPlayControlGetInterfaceDeviceList, // PLUGPLAY_CONTROL_INTERFACE_LIST_DATA\n    PlugPlayControlProperty, // PLUGPLAY_CONTROL_PROPERTY_DATA\n    PlugPlayControlDeviceClassAssociation, // PLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA\n    PlugPlayControlGetRelatedDevice, // PLUGPLAY_CONTROL_RELATED_DEVICE_DATA\n    PlugPlayControlGetInterfaceDeviceAlias, // PLUGPLAY_CONTROL_INTERFACE_ALIAS_DATA\n    PlugPlayControlDeviceStatus, // PLUGPLAY_CONTROL_STATUS_DATA\n    PlugPlayControlGetDeviceDepth, // PLUGPLAY_CONTROL_DEPTH_DATA\n    PlugPlayControlQueryDeviceRelations, // PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA\n    PlugPlayControlTargetDeviceRelation, // PLUGPLAY_CONTROL_TARGET_RELATION_DATA\n    PlugPlayControlQueryConflictList, // PLUGPLAY_CONTROL_CONFLICT_LIST\n    PlugPlayControlRetrieveDock, // PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA\n    PlugPlayControlResetDevice, // PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA\n    PlugPlayControlHaltDevice, // PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA\n    PlugPlayControlGetBlockedDriverList, // PLUGPLAY_CONTROL_BLOCKED_DRIVER_DATA\n    PlugPlayControlGetDeviceInterfaceEnabled, // PLUGPLAY_CONTROL_DEVICE_INTERFACE_ENABLED\n    MaxPlugPlayControl\n} PLUGPLAY_CONTROL_CLASS, *PPLUGPLAY_CONTROL_CLASS;\n\n// private\ntypedef enum _DEVICE_RELATION_TYPE\n{\n    BusRelations,\n    EjectionRelations,\n    PowerRelations,\n    RemovalRelations,\n    TargetDeviceRelation,\n    SingleBusRelations,\n    TransportRelations\n} DEVICE_RELATION_TYPE, *PDEVICE_RELATION_TYPE;\n\n// private\ntypedef enum _BUS_QUERY_ID_TYPE\n{\n    BusQueryDeviceID = 0,           // <Enumerator>\\<Enumerator-specific device id>\n    BusQueryHardwareIDs = 1,        // Hardware ids\n    BusQueryCompatibleIDs = 2,      // compatible device ids\n    BusQueryInstanceID = 3,         // persistent id for this instance of the device\n    BusQueryDeviceSerialNumber = 4, // serial number for this device\n    BusQueryContainerID = 5         // unique id of the device's physical container\n} BUS_QUERY_ID_TYPE, *PBUS_QUERY_ID_TYPE;\n\n// private\ntypedef enum _DEVICE_TEXT_TYPE\n{\n    DeviceTextDescription = 0,        // DeviceDesc property\n    DeviceTextLocationInformation = 1 // DeviceLocation property\n} DEVICE_TEXT_TYPE, *PDEVICE_TEXT_TYPE;\n\n// private\ntypedef enum _DEVICE_USAGE_NOTIFICATION_TYPE\n{\n    DeviceUsageTypeUndefined,\n    DeviceUsageTypePaging,\n    DeviceUsageTypeHibernation,\n    DeviceUsageTypeDumpFile,\n    DeviceUsageTypeBoot,\n    DeviceUsageTypePostDisplay,\n    DeviceUsageTypeGuestAssigned\n} DEVICE_USAGE_NOTIFICATION_TYPE, *PDEVICE_USAGE_NOTIFICATION_TYPE;\n\n#if (PHNT_VERSION < PHNT_WINDOWS_8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetPlugPlayEvent(\n    _In_ HANDLE EventHandle,\n    _In_opt_ PVOID Context,\n    _Out_writes_bytes_(EventBufferSize) PPLUGPLAY_EVENT_BLOCK EventBlock,\n    _In_ ULONG EventBufferSize\n    );\n#endif // (PHNT_VERSION < PHNT_WINDOWS_8)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPlugPlayControl(\n    _In_ PLUGPLAY_CONTROL_CLASS PnPControlClass,\n    _Inout_updates_bytes_(PnPControlDataLength) PVOID PnPControlData,\n    _In_ ULONG PnPControlDataLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSerializeBoot(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnableLastKnownGood(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDisableLastKnownGood(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplacePartitionUnit(\n    _In_ PCUNICODE_STRING TargetInstancePath,\n    _In_ PCUNICODE_STRING SpareInstancePath,\n    _In_ ULONG Flags\n    );\n\n#endif // _NTPNPAPI_H\n"
  },
  {
    "path": "phnt/include/ntpsapi.h",
    "content": "/*\n * Process support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTPSAPI_H\n#define _NTPSAPI_H\n\n#include <ntpebteb.h>\n\n//\n// Process Object Specific Access Rights\n//\n\n#ifndef PROCESS_TERMINATE\n#define PROCESS_TERMINATE 0x0001\n#endif\n#ifndef PROCESS_CREATE_THREAD\n#define PROCESS_CREATE_THREAD 0x0002\n#endif\n#ifndef PROCESS_SET_SESSIONID\n#define PROCESS_SET_SESSIONID 0x0004\n#endif\n#ifndef PROCESS_VM_OPERATION\n#define PROCESS_VM_OPERATION 0x0008\n#endif\n#ifndef PROCESS_VM_READ\n#define PROCESS_VM_READ 0x0010\n#endif\n#ifndef PROCESS_VM_WRITE\n#define PROCESS_VM_WRITE 0x0020\n#endif\n#ifndef PROCESS_DUP_HANDLE\n#define PROCESS_DUP_HANDLE 0x0040\n#endif\n#ifndef PROCESS_CREATE_PROCESS\n#define PROCESS_CREATE_PROCESS 0x0080\n#endif\n#ifndef PROCESS_SET_QUOTA\n#define PROCESS_SET_QUOTA 0x0100\n#endif\n#ifndef PROCESS_SET_INFORMATION\n#define PROCESS_SET_INFORMATION 0x0200\n#endif\n#ifndef PROCESS_QUERY_INFORMATION\n#define PROCESS_QUERY_INFORMATION 0x0400\n#endif\n#ifndef PROCESS_SET_PORT\n#define PROCESS_SET_PORT 0x0800\n#endif\n#ifndef PROCESS_SUSPEND_RESUME\n#define PROCESS_SUSPEND_RESUME 0x0800\n#endif\n#ifndef PROCESS_QUERY_LIMITED_INFORMATION\n#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000\n#endif\n#ifndef PROCESS_SET_LIMITED_INFORMATION\n#define PROCESS_SET_LIMITED_INFORMATION 0x2000\n#endif\n#ifndef PROCESS_ALL_ACCESS\n#if (PHNT_VERSION >= PHNT_WINDOWS_VISTA)\n#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | SPECIFIC_RIGHTS_ALL)\n#else\n#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)\n#endif\n#endif\n\n//\n// Thread Object Specific Access Rights\n//\n\n#ifndef THREAD_TERMINATE\n#define THREAD_TERMINATE 0x0001\n#endif\n#ifndef THREAD_SUSPEND_RESUME\n#define THREAD_SUSPEND_RESUME 0x0002\n#endif\n#ifndef THREAD_ALERT\n#define THREAD_ALERT 0x0004\n#endif\n#ifndef THREAD_GET_CONTEXT\n#define THREAD_GET_CONTEXT 0x0008\n#endif\n#ifndef THREAD_SET_CONTEXT\n#define THREAD_SET_CONTEXT 0x0010\n#endif\n#ifndef THREAD_SET_INFORMATION\n#define THREAD_SET_INFORMATION 0x0020\n#endif\n#ifndef THREAD_QUERY_INFORMATION\n#define THREAD_QUERY_INFORMATION 0x0040\n#endif\n#ifndef THREAD_SET_THREAD_TOKEN\n#define THREAD_SET_THREAD_TOKEN 0x0080\n#endif\n#ifndef THREAD_IMPERSONATE\n#define THREAD_IMPERSONATE 0x0100\n#endif\n#ifndef THREAD_DIRECT_IMPERSONATION\n#define THREAD_DIRECT_IMPERSONATION 0x0200\n#endif\n#ifndef THREAD_SET_LIMITED_INFORMATION\n#define THREAD_SET_LIMITED_INFORMATION 0x0400\n#endif\n#ifndef THREAD_QUERY_LIMITED_INFORMATION\n#define THREAD_QUERY_LIMITED_INFORMATION 0x0800\n#endif\n#ifndef THREAD_RESUME\n#define THREAD_RESUME 0x1000\n#endif\n#ifndef THREAD_ALL_ACCESS\n#if (PHNT_VERSION >= PHNT_WINDOWS_VISTA)\n#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | SPECIFIC_RIGHTS_ALL)\n#else\n#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF)\n#endif\n#endif\n\n//\n// Job Object Specific Access Rights\n//\n\n#ifndef JOB_OBJECT_ASSIGN_PROCESS\n#define JOB_OBJECT_ASSIGN_PROCESS 0x0001\n#endif\n#ifndef JOB_OBJECT_SET_ATTRIBUTES\n#define JOB_OBJECT_SET_ATTRIBUTES 0x0002\n#endif\n#ifndef JOB_OBJECT_QUERY\n#define JOB_OBJECT_QUERY 0x0004\n#endif\n#ifndef JOB_OBJECT_TERMINATE\n#define JOB_OBJECT_TERMINATE 0x0008\n#endif\n#ifndef JOB_OBJECT_SET_SECURITY_ATTRIBUTES\n#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES 0x0010\n#endif\n#ifndef JOB_OBJECT_ALL_ACCESS\n#if (PHNT_VERSION >= PHNT_WINDOWS_VISTA)\n#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3F)\n#else\n#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1f) // pre-Vista full access\n#endif\n#endif\n\n//\n// Process information structures\n//\n\n/**\n * The PEB_LDR_DATA structure contains information about the loaded modules for the process.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data\n */\ntypedef struct _PEB_LDR_DATA\n{\n    ULONG Length;\n    BOOLEAN Initialized;\n    HANDLE SsHandle;\n    LIST_ENTRY InLoadOrderModuleList;\n    LIST_ENTRY InMemoryOrderModuleList;\n    LIST_ENTRY InInitializationOrderModuleList;\n    PVOID EntryInProgress;\n    BOOLEAN ShutdownInProgress;\n    HANDLE ShutdownThreadId;\n} PEB_LDR_DATA, *PPEB_LDR_DATA;\n\n/**\n * The INITIAL_TEB structure contains information about the initial stack for a thread.\n * This structure is used when creating a new thread to specify the stack boundaries and allocation base.\n * It also contains information about the previous stack if the thread is being recreated.\n */\ntypedef struct _INITIAL_TEB\n{\n    struct\n    {\n        PVOID OldStackBase;     // Pointer to the base address of the previous stack.\n        PVOID OldStackLimit;    // Pointer to the limit address of the previous stack.\n    } OldInitialTeb;\n    PVOID StackBase;            // Pointer to the base address of the new stack.\n    PVOID StackLimit;           // Pointer to the limit address of the new stack.\n    PVOID StackAllocationBase;  // Pointer to the base address where the stack was allocated.\n} INITIAL_TEB, *PINITIAL_TEB;\n\n//\n// NtQueryInformationProcess/NtSetInformationProcess types\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _PROCESSINFOCLASS\n{\n    ProcessBasicInformation,                        // q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION\n    ProcessQuotaLimits,                             // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX\n    ProcessIoCounters,                              // q: IO_COUNTERS\n    ProcessVmCounters,                              // q: VM_COUNTERS, VM_COUNTERS_EX, VM_COUNTERS_EX2\n    ProcessTimes,                                   // q: KERNEL_USER_TIMES\n    ProcessBasePriority,                            // s: KPRIORITY\n    ProcessRaisePriority,                           // s: ULONG\n    ProcessDebugPort,                               // q: HANDLE\n    ProcessExceptionPort,                           // s: PROCESS_EXCEPTION_PORT (requires SeTcbPrivilege)\n    ProcessAccessToken,                             // s: PROCESS_ACCESS_TOKEN\n    ProcessLdtInformation,                          // qs: PROCESS_LDT_INFORMATION // 10\n    ProcessLdtSize,                                 // s: PROCESS_LDT_SIZE\n    ProcessDefaultHardErrorMode,                    // qs: ULONG\n    ProcessIoPortHandlers,                          // s: PROCESS_IO_PORT_HANDLER_INFORMATION // (kernel-mode only)\n    ProcessPooledUsageAndLimits,                    // q: POOLED_USAGE_AND_LIMITS\n    ProcessWorkingSetWatch,                         // q: PROCESS_WS_WATCH_INFORMATION[]; s: void\n    ProcessUserModeIOPL,                            // qs: ULONG (requires SeTcbPrivilege)\n    ProcessEnableAlignmentFaultFixup,               // s: BOOLEAN\n    ProcessPriorityClass,                           // qs: PROCESS_PRIORITY_CLASS\n    ProcessWx86Information,                         // qs: ULONG (requires SeTcbPrivilege) (VdmAllowed)\n    ProcessHandleCount,                             // q: ULONG, PROCESS_HANDLE_INFORMATION // 20\n    ProcessAffinityMask,                            // qs: KAFFINITY, qs: GROUP_AFFINITY\n    ProcessPriorityBoost,                           // qs: ULONG\n    ProcessDeviceMap,                               // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX\n    ProcessSessionInformation,                      // q: PROCESS_SESSION_INFORMATION\n    ProcessForegroundInformation,                   // s: PROCESS_FOREGROUND_BACKGROUND\n    ProcessWow64Information,                        // q: ULONG_PTR\n    ProcessImageFileName,                           // q: UNICODE_STRING\n    ProcessLUIDDeviceMapsEnabled,                   // q: ULONG\n    ProcessBreakOnTermination,                      // qs: ULONG\n    ProcessDebugObjectHandle,                       // q: HANDLE // 30\n    ProcessDebugFlags,                              // qs: ULONG\n    ProcessHandleTracing,                           // q: PROCESS_HANDLE_TRACING_QUERY; s: PROCESS_HANDLE_TRACING_ENABLE[_EX] or void to disable\n    ProcessIoPriority,                              // qs: IO_PRIORITY_HINT\n    ProcessExecuteFlags,                            // qs: ULONG (MEM_EXECUTE_OPTION_*)\n    ProcessTlsInformation,                          // qs: PROCESS_TLS_INFORMATION // ProcessResourceManagement\n    ProcessCookie,                                  // q: ULONG\n    ProcessImageInformation,                        // q: SECTION_IMAGE_INFORMATION\n    ProcessCycleTime,                               // q: PROCESS_CYCLE_TIME_INFORMATION // since VISTA\n    ProcessPagePriority,                            // qs: PAGE_PRIORITY_INFORMATION\n    ProcessInstrumentationCallback,                 // s: PVOID or PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION // 40\n    ProcessThreadStackAllocation,                   // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX\n    ProcessWorkingSetWatchEx,                       // q: PROCESS_WS_WATCH_INFORMATION_EX[]; s: void\n    ProcessImageFileNameWin32,                      // q: UNICODE_STRING\n    ProcessImageFileMapping,                        // q: HANDLE (input)\n    ProcessAffinityUpdateMode,                      // qs: PROCESS_AFFINITY_UPDATE_MODE\n    ProcessMemoryAllocationMode,                    // qs: PROCESS_MEMORY_ALLOCATION_MODE\n    ProcessGroupInformation,                        // q: USHORT[]\n    ProcessTokenVirtualizationEnabled,              // s: ULONG\n    ProcessConsoleHostProcess,                      // qs: ULONG_PTR // ProcessOwnerInformation\n    ProcessWindowInformation,                       // q: PROCESS_WINDOW_INFORMATION // 50\n    ProcessHandleInformation,                       // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8\n    ProcessMitigationPolicy,                        // s: PROCESS_MITIGATION_POLICY_INFORMATION\n    ProcessDynamicFunctionTableInformation,         // s: PROCESS_DYNAMIC_FUNCTION_TABLE_INFORMATION\n    ProcessHandleCheckingMode,                      // qs: ULONG; s: 0 disables, otherwise enables\n    ProcessKeepAliveCount,                          // q: PROCESS_KEEPALIVE_COUNT_INFORMATION\n    ProcessRevokeFileHandles,                       // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION\n    ProcessWorkingSetControl,                       // s: PROCESS_WORKING_SET_CONTROL\n    ProcessHandleTable,                             // q: ULONG[] // since WINBLUE\n    ProcessCheckStackExtentsMode,                   // qs: ULONG // KPROCESS->CheckStackExtents (CFG)\n    ProcessCommandLineInformation,                  // q: UNICODE_STRING // 60\n    ProcessProtectionInformation,                   // q: PS_PROTECTION\n    ProcessMemoryExhaustion,                        // s: PROCESS_MEMORY_EXHAUSTION_INFO // since THRESHOLD\n    ProcessFaultInformation,                        // s: PROCESS_FAULT_INFORMATION\n    ProcessTelemetryIdInformation,                  // q: PROCESS_TELEMETRY_ID_INFORMATION\n    ProcessCommitReleaseInformation,                // qs: PROCESS_COMMIT_RELEASE_INFORMATION\n    ProcessDefaultCpuSetsInformation,               // qs: SYSTEM_CPU_SET_INFORMATION[5] // ProcessReserved1Information\n    ProcessAllowedCpuSetsInformation,               // qs: SYSTEM_CPU_SET_INFORMATION[5] // ProcessReserved2Information\n    ProcessSubsystemProcess,                        // s: void // EPROCESS->SubsystemProcess\n    ProcessJobMemoryInformation,                    // q: PROCESS_JOB_MEMORY_INFO\n    ProcessInPrivate,                               // q: BOOLEAN; s: void // ETW // since THRESHOLD2 // 70\n    ProcessRaiseUMExceptionOnInvalidHandleClose,    // qs: ULONG; s: 0 disables, otherwise enables\n    ProcessIumChallengeResponse,                    // q: PROCESS_IUM_CHALLENGE_RESPONSE\n    ProcessChildProcessInformation,                 // q: PROCESS_CHILD_PROCESS_INFORMATION\n    ProcessHighGraphicsPriorityInformation,         // q: BOOLEAN; s: BOOLEAN (requires SeTcbPrivilege)\n    ProcessSubsystemInformation,                    // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2\n    ProcessEnergyValues,                            // q: PROCESS_ENERGY_VALUES, PROCESS_EXTENDED_ENERGY_VALUES, PROCESS_EXTENDED_ENERGY_VALUES_V1\n    ProcessPowerThrottlingState,                    // qs: POWER_THROTTLING_PROCESS_STATE\n    ProcessActivityThrottlePolicy,                  // qs: PROCESS_ACTIVITY_THROTTLE_POLICY // ProcessReserved3Information\n    ProcessWin32kSyscallFilterInformation,          // q: WIN32K_SYSCALL_FILTER\n    ProcessDisableSystemAllowedCpuSets,             // s: BOOLEAN // 80\n    ProcessWakeInformation,                         // q: PROCESS_WAKE_INFORMATION // (kernel-mode only)\n    ProcessEnergyTrackingState,                     // qs: PROCESS_ENERGY_TRACKING_STATE\n    ProcessManageWritesToExecutableMemory,          // s: MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3\n    ProcessCaptureTrustletLiveDump,                 // q: ULONG\n    ProcessTelemetryCoverage,                       // q: TELEMETRY_COVERAGE_HEADER; s: TELEMETRY_COVERAGE_POINT\n    ProcessEnclaveInformation,\n    ProcessEnableReadWriteVmLogging,                // qs: PROCESS_READWRITEVM_LOGGING_INFORMATION\n    ProcessUptimeInformation,                       // q: PROCESS_UPTIME_INFORMATION\n    ProcessImageSection,                            // q: HANDLE\n    ProcessDebugAuthInformation,                    // s: CiTool.exe --device-id // PplDebugAuthorization // since RS4 // 90\n    ProcessSystemResourceManagement,                // s: PROCESS_SYSTEM_RESOURCE_MANAGEMENT\n    ProcessSequenceNumber,                          // q: ULONGLONG\n    ProcessLoaderDetour,                            // qs: Obsolete // since RS5\n    ProcessSecurityDomainInformation,               // q: PROCESS_SECURITY_DOMAIN_INFORMATION\n    ProcessCombineSecurityDomainsInformation,       // s: PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION\n    ProcessEnableLogging,                           // qs: PROCESS_LOGGING_INFORMATION\n    ProcessLeapSecondInformation,                   // qs: PROCESS_LEAP_SECOND_INFORMATION\n    ProcessFiberShadowStackAllocation,              // s: PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION // since 19H1\n    ProcessFreeFiberShadowStackAllocation,          // s: PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION\n    ProcessAltSystemCallInformation,                // s: PROCESS_SYSCALL_PROVIDER_INFORMATION // since 20H1 // 100\n    ProcessDynamicEHContinuationTargets,            // s: PROCESS_DYNAMIC_EH_CONTINUATION_TARGETS_INFORMATION\n    ProcessDynamicEnforcedCetCompatibleRanges,      // s: PROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGE_INFORMATION // since 20H2\n    ProcessCreateStateChange,                       // s: Obsolete // since WIN11\n    ProcessApplyStateChange,                        // s: Obsolete\n    ProcessEnableOptionalXStateFeatures,            // s: ULONG64 // EnableProcessOptionalXStateFeatures\n    ProcessAltPrefetchParam,                        // qs: OVERRIDE_PREFETCH_PARAMETER // App Launch Prefetch (ALPF) // since 22H1\n    ProcessAssignCpuPartitions,                     // s: HANDLE\n    ProcessPriorityClassEx,                         // s: PROCESS_PRIORITY_CLASS_EX\n    ProcessMembershipInformation,                   // q: PROCESS_MEMBERSHIP_INFORMATION\n    ProcessEffectiveIoPriority,                     // q: IO_PRIORITY_HINT // 110\n    ProcessEffectivePagePriority,                   // q: ULONG\n    ProcessSchedulerSharedData,                     // q: SCHEDULER_SHARED_DATA_SLOT_INFORMATION // since 24H2\n    ProcessSlistRollbackInformation,\n    ProcessNetworkIoCounters,                       // q: PROCESS_NETWORK_COUNTERS\n    ProcessFindFirstThreadByTebValue,               // q: PROCESS_TEB_VALUE_INFORMATION // NtCurrentProcess\n    ProcessEnclaveAddressSpaceRestriction,          // qs: // since 25H2\n    ProcessAvailableCpus,                           // q: PROCESS_AVAILABLE_CPUS_INFORMATION\n    MaxProcessInfoClass\n} PROCESSINFOCLASS;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// NtQueryInformationThread/NtSetInformationThread types\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _THREADINFOCLASS\n{\n    ThreadBasicInformation,                         // q: THREAD_BASIC_INFORMATION\n    ThreadTimes,                                    // q: KERNEL_USER_TIMES\n    ThreadPriority,                                 // s: KPRIORITY (requires SeIncreaseBasePriorityPrivilege)\n    ThreadBasePriority,                             // s: KPRIORITY\n    ThreadAffinityMask,                             // s: KAFFINITY\n    ThreadImpersonationToken,                       // s: HANDLE\n    ThreadDescriptorTableEntry,                     // q: DESCRIPTOR_TABLE_ENTRY (or WOW64_DESCRIPTOR_TABLE_ENTRY)\n    ThreadEnableAlignmentFaultFixup,                // s: BOOLEAN\n    ThreadEventPair,                                // q: Obsolete\n    ThreadQuerySetWin32StartAddress,                // q: PVOID\n    ThreadZeroTlsCell,                              // s: ULONG // TlsIndex // 10\n    ThreadPerformanceCount,                         // q: LARGE_INTEGER\n    ThreadAmILastThread,                            // q: ULONG\n    ThreadIdealProcessor,                           // s: ULONG\n    ThreadPriorityBoost,                            // qs: ULONG\n    ThreadSetTlsArrayAddress,                       // s: ULONG_PTR\n    ThreadIsIoPending,                              // q: ULONG\n    ThreadHideFromDebugger,                         // q: BOOLEAN; s: void\n    ThreadBreakOnTermination,                       // qs: ULONG\n    ThreadSwitchLegacyState,                        // s: void // NtCurrentThread // NPX/FPU\n    ThreadIsTerminated,                             // q: ULONG // 20\n    ThreadLastSystemCall,                           // q: THREAD_LAST_SYSCALL_INFORMATION\n    ThreadIoPriority,                               // qs: IO_PRIORITY_HINT (requires SeIncreaseBasePriorityPrivilege)\n    ThreadCycleTime,                                // q: THREAD_CYCLE_TIME_INFORMATION (requires THREAD_QUERY_LIMITED_INFORMATION)\n    ThreadPagePriority,                             // qs: PAGE_PRIORITY_INFORMATION\n    ThreadActualBasePriority,                       // s: LONG (requires SeIncreaseBasePriorityPrivilege)\n    ThreadTebInformation,                           // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_SET_CONTEXT)\n    ThreadCSwitchMon,                               // q: Obsolete\n    ThreadCSwitchPmu,                               // q: Obsolete\n    ThreadWow64Context,                             // qs: WOW64_CONTEXT, ARM_NT_CONTEXT since 20H1\n    ThreadGroupInformation,                         // qs: GROUP_AFFINITY // 30\n    ThreadUmsInformation,                           // q: THREAD_UMS_INFORMATION // Obsolete\n    ThreadCounterProfiling,                         // q: BOOLEAN; s: THREAD_PROFILING_INFORMATION?\n    ThreadIdealProcessorEx,                         // qs: PROCESSOR_NUMBER; s: previous PROCESSOR_NUMBER on return\n    ThreadCpuAccountingInformation,                 // q: BOOLEAN; s: HANDLE (NtOpenSession) // NtCurrentThread // since WIN8\n    ThreadSuspendCount,                             // q: ULONG // since WINBLUE\n    ThreadHeterogeneousCpuPolicy,                   // q: KHETERO_CPU_POLICY // since THRESHOLD\n    ThreadContainerId,                              // q: GUID\n    ThreadNameInformation,                          // qs: THREAD_NAME_INFORMATION (requires THREAD_SET_LIMITED_INFORMATION)\n    ThreadSelectedCpuSets,                          // q: ULONG[]\n    ThreadSystemThreadInformation,                  // q: SYSTEM_THREAD_INFORMATION // 40\n    ThreadActualGroupAffinity,                      // q: GROUP_AFFINITY // since THRESHOLD2\n    ThreadDynamicCodePolicyInfo,                    // q: ULONG; s: ULONG (NtCurrentThread)\n    ThreadExplicitCaseSensitivity,                  // qs: ULONG; s: 0 disables, otherwise enables // (requires SeDebugPrivilege and PsProtectedSignerAntimalware)\n    ThreadWorkOnBehalfTicket,                       // q: ALPC_WORK_ON_BEHALF_TICKET // RTL_WORK_ON_BEHALF_TICKET_EX // NtCurrentThread\n    ThreadSubsystemInformation,                     // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2\n    ThreadDbgkWerReportActive,                      // s: ULONG; s: 0 disables, otherwise enables\n    ThreadAttachContainer,                          // s: HANDLE (job object) // NtCurrentThread\n    ThreadManageWritesToExecutableMemory,           // s: MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3\n    ThreadPowerThrottlingState,                     // qs: POWER_THROTTLING_THREAD_STATE // since REDSTONE3 (set), WIN11 22H2 (query)\n    ThreadWorkloadClass,                            // q: THREAD_WORKLOAD_CLASS // since REDSTONE5 // 50\n    ThreadCreateStateChange,                        // s: Obsolete // since WIN11\n    ThreadApplyStateChange,                         // s: Obsolete\n    ThreadStrongerBadHandleChecks,                  // s: ULONG // NtCurrentThread // since 22H1\n    ThreadEffectiveIoPriority,                      // q: IO_PRIORITY_HINT\n    ThreadEffectivePagePriority,                    // q: ULONG\n    ThreadUpdateLockOwnership,                      // s: THREAD_LOCK_OWNERSHIP // since 24H2\n    ThreadSchedulerSharedDataSlot,                  // q: SCHEDULER_SHARED_DATA_SLOT_INFORMATION\n    ThreadTebInformationAtomic,                     // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_QUERY_INFORMATION)\n    ThreadIndexInformation,                         // q: THREAD_INDEX_INFORMATION\n    MaxThreadInfoClass\n} THREADINFOCLASS;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// Use with both ProcessPagePriority and ThreadPagePriority\ntypedef struct _PAGE_PRIORITY_INFORMATION\n{\n    ULONG PagePriority;\n} PAGE_PRIORITY_INFORMATION, *PPAGE_PRIORITY_INFORMATION;\n\n//\n// Process information structures\n//\n\n/**\n * The PROCESS_BASIC_INFORMATION structure contains basic information about a process.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess#process_basic_information\n */\ntypedef struct _PROCESS_BASIC_INFORMATION\n{\n    NTSTATUS ExitStatus;                    // The exit status of the process. (GetExitCodeProcess)\n    PPEB PebBaseAddress;                    // A pointer to the process environment block (PEB) of the process.\n    KAFFINITY AffinityMask;                 // The affinity mask of the process. (GetProcessAffinityMask) (deprecated)\n    KPRIORITY BasePriority;                 // The base priority of the process. (GetPriorityClass)\n    HANDLE UniqueProcessId;                 // The unique identifier of the process. (GetProcessId)\n    HANDLE InheritedFromUniqueProcessId;    // The unique identifier of the parent process.\n} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;\n\n/**\n * The PROCESS_EXTENDED_BASIC_INFORMATION structure contains extended basic information about a process.\n */\n_Struct_size_bytes_(Size)\ntypedef struct _PROCESS_EXTENDED_BASIC_INFORMATION\n{\n    _In_ SIZE_T Size; // The size of the structure, in bytes. This member must be set to sizeof(PROCESS_EXTENDED_BASIC_INFORMATION).\n    union\n    {\n        PROCESS_BASIC_INFORMATION BasicInfo;\n        struct\n        {\n            NTSTATUS ExitStatus;                    // The exit status of the process. (GetExitCodeProcess)\n            PPEB PebBaseAddress;                    // A pointer to the process environment block (PEB) of the process.\n            KAFFINITY AffinityMask;                 // The affinity mask of the process. (GetProcessAffinityMask) (deprecated)\n            KPRIORITY BasePriority;                 // The base priority of the process. (GetPriorityClass)\n            HANDLE UniqueProcessId;                 // The unique identifier of the process. (GetProcessId)\n            HANDLE InheritedFromUniqueProcessId;    // The unique identifier of the parent process.\n        };\n    };\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG IsProtectedProcess : 1;\n            ULONG IsWow64Process : 1;\n            ULONG IsProcessDeleting : 1;\n            ULONG IsCrossSessionCreate : 1;\n            ULONG IsFrozen : 1;\n            ULONG IsBackground : 1; // WIN://BGKD\n            ULONG IsStronglyNamed : 1; // WIN://SYSAPPID\n            ULONG IsSecureProcess : 1;\n            ULONG IsSubsystemProcess : 1;\n            ULONG IsTrustedApp : 1; // since 24H2\n            ULONG SpareBits : 22;\n        };\n    };\n} PROCESS_EXTENDED_BASIC_INFORMATION, *PPROCESS_EXTENDED_BASIC_INFORMATION;\n\n/**\n * The VM_COUNTERS structure contains various memory usage statistics for a process.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-process_memory_counters\n */\ntypedef struct _VM_COUNTERS\n{\n    SIZE_T PeakVirtualSize;             // The peak virtual address space size of this process, in bytes.\n    SIZE_T VirtualSize;                 // The virtual address space size of this process, in bytes.\n    ULONG PageFaultCount;               // The number of page faults.\n    SIZE_T PeakWorkingSetSize;          // The peak working set size, in bytes.\n    SIZE_T WorkingSetSize;              // The current working set size, in bytes\n    SIZE_T QuotaPeakPagedPoolUsage;     // The peak paged pool usage, in bytes.\n    SIZE_T QuotaPagedPoolUsage;         // The current paged pool usage, in bytes.\n    SIZE_T QuotaPeakNonPagedPoolUsage;  // The peak non-paged pool usage, in bytes.\n    SIZE_T QuotaNonPagedPoolUsage;      // The current non-paged pool usage, in bytes.\n    SIZE_T PagefileUsage;               // The Commit Charge value in bytes for this process. Commit Charge is the total amount of private memory that the memory manager has committed for a running process.\n    SIZE_T PeakPagefileUsage;           // The peak value in bytes of the Commit Charge during the lifetime of this process.\n} VM_COUNTERS, *PVM_COUNTERS;\n\n/**\n * The VM_COUNTERS_EX structure extends VM_COUNTERS to include private memory usage.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-process_memory_counters_ex2\n */\ntypedef struct _VM_COUNTERS_EX\n{\n    SIZE_T PeakVirtualSize;             // The peak virtual address space size of this process, in bytes.\n    SIZE_T VirtualSize;                 // The virtual address space size of this process, in bytes.\n    ULONG PageFaultCount;               // The number of page faults.\n    SIZE_T PeakWorkingSetSize;          // The peak working set size, in bytes.\n    SIZE_T WorkingSetSize;              // The current working set size, in bytes\n    SIZE_T QuotaPeakPagedPoolUsage;     // The peak paged pool usage, in bytes.\n    SIZE_T QuotaPagedPoolUsage;         // The current paged pool usage, in bytes.\n    SIZE_T QuotaPeakNonPagedPoolUsage;  // The peak non-paged pool usage, in bytes.\n    SIZE_T QuotaNonPagedPoolUsage;      // The current non-paged pool usage, in bytes.\n    SIZE_T PagefileUsage;               // The Commit Charge value in bytes for this process. Commit Charge is the total amount of private memory that the memory manager has committed for a running process.\n    SIZE_T PeakPagefileUsage;           // The peak value in bytes of the Commit Charge during the lifetime of this process.\n    SIZE_T PrivateUsage;                // Same as PagefileUsage. The Commit Charge value in bytes for this process. Commit Charge is the total amount of private memory that the memory manager has committed for a running process.\n} VM_COUNTERS_EX, *PVM_COUNTERS_EX;\n\n/**\n * The VM_COUNTERS_EX2 structure extends VM_COUNTERS_EX to include private working set size and shared commit usage.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-process_memory_counters_ex2\n */\ntypedef struct _VM_COUNTERS_EX2\n{\n    union\n    {\n        VM_COUNTERS_EX CountersEx;\n        struct\n        {\n            SIZE_T PeakVirtualSize;             // The peak virtual address space size of this process, in bytes.\n            SIZE_T VirtualSize;                 // The virtual address space size of this process, in bytes.\n            ULONG PageFaultCount;               // The number of page faults.\n            SIZE_T PeakWorkingSetSize;          // The peak working set size, in bytes.\n            SIZE_T WorkingSetSize;              // The current working set size, in bytes\n            SIZE_T QuotaPeakPagedPoolUsage;     // The peak paged pool usage, in bytes.\n            SIZE_T QuotaPagedPoolUsage;         // The current paged pool usage, in bytes.\n            SIZE_T QuotaPeakNonPagedPoolUsage;  // The peak non-paged pool usage, in bytes.\n            SIZE_T QuotaNonPagedPoolUsage;      // The current non-paged pool usage, in bytes.\n            SIZE_T PagefileUsage;               // The Commit Charge value in bytes for this process. Commit Charge is the total amount of private memory that the memory manager has committed for a running process.\n            SIZE_T PeakPagefileUsage;           // The peak value in bytes of the Commit Charge during the lifetime of this process.\n            SIZE_T PrivateUsage;                // Same as PagefileUsage. The Commit Charge value in bytes for this process. Commit Charge is the total amount of private memory that the memory manager has committed for a running process.\n        };\n    };\n    SIZE_T PrivateWorkingSetSize;               // The current private working set size, in bytes.\n    SIZE_T SharedCommitUsage;                   // The current shared commit usage, in bytes.\n} VM_COUNTERS_EX2, *PVM_COUNTERS_EX2;\n\n/**\n * The KERNEL_USER_TIMES structure contains timing information for a process or thread.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes\n */\ntypedef struct _KERNEL_USER_TIMES\n{\n    LARGE_INTEGER CreateTime;        // The creation time of the process or thread.\n    LARGE_INTEGER ExitTime;          // The exit time of the process or thread.\n    LARGE_INTEGER KernelTime;        // The amount of time the process has executed in kernel mode.\n    LARGE_INTEGER UserTime;          // The amount of time the process has executed in user mode.\n} KERNEL_USER_TIMES, *PKERNEL_USER_TIMES;\n\n/**\n * The POOLED_USAGE_AND_LIMITS structure contains information about the usage and limits of paged and non-paged pool memory.\n */\ntypedef struct _POOLED_USAGE_AND_LIMITS\n{\n    SIZE_T PeakPagedPoolUsage;       // The peak paged pool usage.\n    SIZE_T PagedPoolUsage;           // The current paged pool usage.\n    SIZE_T PagedPoolLimit;           // The limit on paged pool usage.\n    SIZE_T PeakNonPagedPoolUsage;    // The peak non-paged pool usage.\n    SIZE_T NonPagedPoolUsage;        // The current non-paged pool usage.\n    SIZE_T NonPagedPoolLimit;        // The limit on non-paged pool usage.\n    SIZE_T PeakPagefileUsage;        // The peak pagefile usage.\n    SIZE_T PagefileUsage;            // The current pagefile usage.\n    SIZE_T PagefileLimit;            // The limit on pagefile usage.\n} POOLED_USAGE_AND_LIMITS, *PPOOLED_USAGE_AND_LIMITS;\n\n#define PROCESS_EXCEPTION_PORT_ALL_STATE_BITS 0x00000003\n#define PROCESS_EXCEPTION_PORT_ALL_STATE_FLAGS ((ULONG_PTR)((1UL << PROCESS_EXCEPTION_PORT_ALL_STATE_BITS) - 1))\n\n/**\n * The PROCESS_EXCEPTION_PORT structure is used to manage exception ports for a process.\n */\ntypedef struct _PROCESS_EXCEPTION_PORT\n{\n    //\n    // Handle to the exception port. No particular access required.\n    //\n    _In_ HANDLE ExceptionPortHandle;\n\n    //\n    // Miscellaneous state flags to be cached along with the exception\n    // port in the kernel.\n    //\n    _Inout_ ULONG StateFlags;\n\n} PROCESS_EXCEPTION_PORT, *PPROCESS_EXCEPTION_PORT;\n\n/**\n * The PROCESS_ACCESS_TOKEN structure is used to manage the security context of a process or thread.\n *\n * A process's access token can only be changed if the process has no threads or a single thread that has not yet begun execution.\n */\ntypedef struct _PROCESS_ACCESS_TOKEN\n{\n    //\n    // Handle to Primary token to assign to the process.\n    // TOKEN_ASSIGN_PRIMARY access to this token is needed.\n    //\n    HANDLE Token;\n\n    //\n    // Handle to the initial thread of the process.\n    // THREAD_QUERY_INFORMATION access to this thread is needed.\n    //\n    // N.B. This field is unused.\n    //\n    HANDLE Thread;\n\n} PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN;\n\n#ifndef _LDT_ENTRY_DEFINED\n#define _LDT_ENTRY_DEFINED\ntypedef struct _LDT_ENTRY\n{\n    USHORT LimitLow;\n    USHORT BaseLow;\n    union\n    {\n        struct\n        {\n            UCHAR BaseMid;\n            UCHAR Flags1;\n            UCHAR Flags2;\n            UCHAR BaseHi;\n        } Bytes;\n        struct\n        {\n            ULONG BaseMid : 8;\n            ULONG Type : 5;\n            ULONG Dpl : 2;\n            ULONG Pres : 1;\n            ULONG LimitHi : 4;\n            ULONG Sys : 1;\n            ULONG Reserved_0 : 1;\n            ULONG Default_Big : 1;\n            ULONG Granularity : 1;\n            ULONG BaseHi : 8;\n        } Bits;\n    } HighWord;\n} LDT_ENTRY, *PLDT_ENTRY;\n#endif // _LDT_ENTRY_DEFINED\n\n/**\n * The PROCESS_LDT_INFORMATION structure is used to manage Local Descriptor Table (LDT) entries for a process.\n */\ntypedef struct _PROCESS_LDT_INFORMATION\n{\n    ULONG Start;\n    ULONG Length;\n    LDT_ENTRY LdtEntries[1];\n} PROCESS_LDT_INFORMATION, *PPROCESS_LDT_INFORMATION;\n\n/**\n * The PROCESS_LDT_SIZE structure is used to specify the size of the Local Descriptor Table (LDT) for a process.\n */\ntypedef struct _PROCESS_LDT_SIZE\n{\n    ULONG Length;\n} PROCESS_LDT_SIZE, *PPROCESS_LDT_SIZE;\n\n/**\n * The PROCESS_WS_WATCH_INFORMATION structure is used to store information about working set watch events for a process.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-psapi_ws_watch_information\n */\ntypedef struct _PROCESS_WS_WATCH_INFORMATION\n{\n    PVOID FaultingPc; // A pointer to the instruction that caused the page fault.\n    PVOID FaultingVa; // A pointer to the page that was added to the working set.\n} PROCESS_WS_WATCH_INFORMATION, *PPROCESS_WS_WATCH_INFORMATION;\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * The PROCESS_WS_WATCH_INFORMATION_EX structure contains extended information about a page added to a process working set.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-psapi_ws_watch_information_ex\n */\ntypedef struct _PROCESS_WS_WATCH_INFORMATION_EX\n{\n    union\n    {\n        PROCESS_WS_WATCH_INFORMATION BasicInfo;\n        struct\n        {\n            PVOID FaultingPc;   // The address of the instruction that caused the page fault.\n            PVOID FaultingVa;   // The virtual address that caused the page fault.\n        };\n    };\n    HANDLE FaultingThreadId;    // The identifier of the thread that caused the page fault.\n    ULONG_PTR Flags;            // This member is reserved for future use.\n} PROCESS_WS_WATCH_INFORMATION_EX, *PPROCESS_WS_WATCH_INFORMATION_EX;\n\n#define PROCESS_PRIORITY_CLASS_UNKNOWN 0\n#define PROCESS_PRIORITY_CLASS_IDLE 1\n#define PROCESS_PRIORITY_CLASS_NORMAL 2\n#define PROCESS_PRIORITY_CLASS_HIGH 3\n#define PROCESS_PRIORITY_CLASS_REALTIME 4\n#define PROCESS_PRIORITY_CLASS_BELOW_NORMAL 5\n#define PROCESS_PRIORITY_CLASS_ABOVE_NORMAL 6\n\n/**\n * The PROCESS_PRIORITY_CLASS structure is used to manage the priority class of a process.\n */\ntypedef struct _PROCESS_PRIORITY_CLASS\n{\n    BOOLEAN Foreground;\n    UCHAR PriorityClass;\n} PROCESS_PRIORITY_CLASS, *PPROCESS_PRIORITY_CLASS;\n\n/**\n * The PROCESS_PRIORITY_CLASS_EX structure extends PROCESS_PRIORITY_CLASS to include validity flags.\n */\ntypedef struct _PROCESS_PRIORITY_CLASS_EX\n{\n    union\n    {\n        struct\n        {\n            USHORT ForegroundValid : 1;\n            USHORT PriorityClassValid : 1;\n        };\n        USHORT AllFlags;\n    };\n    UCHAR PriorityClass;\n    BOOLEAN Foreground;\n} PROCESS_PRIORITY_CLASS_EX, *PPROCESS_PRIORITY_CLASS_EX;\n\n/**\n * The PROCESS_FOREGROUND_BACKGROUND structure is used to manage the priority class of a process, specifically whether it runs in the foreground or background.\n */\ntypedef struct _PROCESS_FOREGROUND_BACKGROUND\n{\n    BOOLEAN Foreground;\n} PROCESS_FOREGROUND_BACKGROUND, *PPROCESS_FOREGROUND_BACKGROUND;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// DriveType\n#define DRIVE_UNKNOWN     0\n#define DRIVE_NO_ROOT_DIR 1\n#define DRIVE_REMOVABLE   2\n#define DRIVE_FIXED       3\n#define DRIVE_REMOTE      4\n#define DRIVE_CDROM       5\n#define DRIVE_RAMDISK     6\n\n/**\n * The PROCESS_DEVICEMAP_INFORMATION structure contains information about a process's device map.\n */\ntypedef struct _PROCESS_DEVICEMAP_INFORMATION\n{\n    union\n    {\n        struct\n        {\n            HANDLE DirectoryHandle; // A handle to a directory object that can be set as the new device map for the process. This handle must have DIRECTORY_TRAVERSE access.\n        } Set;\n        struct\n        {\n            ULONG DriveMap;         // A bitmask that indicates which drive letters are currently in use in the process's device map.\n            UCHAR DriveType[32];    // A value that indicates the type of each drive (e.g., local disk, network drive, etc.). // DRIVE_* WinBase.h\n        } Query;\n    };\n} PROCESS_DEVICEMAP_INFORMATION, *PPROCESS_DEVICEMAP_INFORMATION;\n\n/**\n * The PROCESS_LUID_DOSDEVICES_ONLY flag limits the device map to only devices from the current process or logon session.\n */\n#define PROCESS_LUID_DOSDEVICES_ONLY 0x00000001\n\n/**\n * The PROCESS_DEVICEMAP_INFORMATION_EX structure contains information about a process's device map.\n */\ntypedef struct _PROCESS_DEVICEMAP_INFORMATION_EX\n{\n    union\n    {\n        struct\n        {\n            HANDLE DirectoryHandle; // A handle to a directory object that can be set as the new device map for the process. This handle must have DIRECTORY_TRAVERSE access.\n        } Set;\n        struct\n        {\n            ULONG DriveMap;         // A bitmask that indicates which drive letters are currently in use in the process's device map.\n            UCHAR DriveType[32];    // A value that indicates the type of each drive (e.g., local disk, network drive, etc.). // DRIVE_* WinBase.h\n        } Query;\n    };\n    ULONG Flags; // PROCESS_LUID_DOSDEVICES_ONLY\n} PROCESS_DEVICEMAP_INFORMATION_EX, *PPROCESS_DEVICEMAP_INFORMATION_EX;\n\n/**\n * The PROCESS_SESSION_INFORMATION structure is used to store information about the session ID of a process.\n */\ntypedef struct _PROCESS_SESSION_INFORMATION\n{\n    ULONG SessionId;\n} PROCESS_SESSION_INFORMATION, *PPROCESS_SESSION_INFORMATION;\n\n#define PROCESS_HANDLE_EXCEPTIONS_ENABLED 0x00000001\n#define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_DISABLED 0x00000000\n#define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_ENABLED 0x00000001\n\n/**\n * The PROCESS_HANDLE_TRACING_ENABLE structure is used to enable handle tracing for a process.\n */\ntypedef struct _PROCESS_HANDLE_TRACING_ENABLE\n{\n    ULONG Flags;        // Flags that control handle tracing.\n} PROCESS_HANDLE_TRACING_ENABLE, *PPROCESS_HANDLE_TRACING_ENABLE;\n\n/**\n * The PROCESS_HANDLE_TRACING_MAX_SLOTS macro specifies the maximum number of slots.\n */\n#define PROCESS_HANDLE_TRACING_MAX_SLOTS 0x20000\n\n/**\n * The PROCESS_HANDLE_TRACING_ENABLE_EX structure extends PROCESS_HANDLE_TRACING_ENABLE to include the total number of slots.\n */\ntypedef struct _PROCESS_HANDLE_TRACING_ENABLE_EX\n{\n    ULONG Flags;        // Flags that control handle tracing.\n    ULONG TotalSlots;   // Total number of handle tracing slots.\n} PROCESS_HANDLE_TRACING_ENABLE_EX, *PPROCESS_HANDLE_TRACING_ENABLE_EX;\n\n#define PROCESS_HANDLE_TRACE_TYPE_OPEN 1\n#define PROCESS_HANDLE_TRACE_TYPE_CLOSE 2\n#define PROCESS_HANDLE_TRACE_TYPE_BADREF 3\n\n/**\n * The PROCESS_HANDLE_TRACING_ENTRY structure contains information about the handle operation associated with the event.\n */\ntypedef struct _PROCESS_HANDLE_TRACING_ENTRY\n{\n    HANDLE Handle;          // The handle associated with the event.\n    CLIENT_ID ClientId;     // The process and thread associated with the event.\n    ULONG Type;             // The type of handle operation associated with the event.\n    PVOID Stacks[16];\n} PROCESS_HANDLE_TRACING_ENTRY, *PPROCESS_HANDLE_TRACING_ENTRY;\n\n/**\n * The PROCESS_HANDLE_TRACING_QUERY structure is used to query all handle events or a specific handle event for a process.\n */\ntypedef struct _PROCESS_HANDLE_TRACING_QUERY\n{\n    _In_opt_ HANDLE Handle;\n    _Out_ ULONG TotalTraces;\n    _Out_ _Field_size_(TotalTraces) PROCESS_HANDLE_TRACING_ENTRY HandleTrace[1];\n} PROCESS_HANDLE_TRACING_QUERY, *PPROCESS_HANDLE_TRACING_QUERY;\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * The THREAD_TLS_INFORMATION structure contains information about the Thread Local Storage (TLS) data for a thread.\n */\ntypedef struct _THREAD_TLS_INFORMATION\n{\n    ULONG Flags;         // Flags that provide additional information about the TLS data.\n    PVOID NewTlsData;    // Pointer to the new TLS data.\n    PVOID OldTlsData;    // Pointer to the old TLS data.\n    HANDLE ThreadId;     // Handle to the thread associated with the TLS data.\n} THREAD_TLS_INFORMATION, *PTHREAD_TLS_INFORMATION;\n\n/**\n * The PROCESS_TLS_INFORMATION_TYPE enumeration defines the types of TLS operations that can be performed on a process.\n */\ntypedef enum _PROCESS_TLS_INFORMATION_TYPE\n{\n    ProcessTlsReplaceIndex,     // Replace the TLS index.\n    ProcessTlsReplaceVector,    // Replace the TLS vector.\n    MaxProcessTlsOperation      // Maximum value for the enumeration.\n} PROCESS_TLS_INFORMATION_TYPE, *PPROCESS_TLS_INFORMATION_TYPE;\n\n/**\n * The PROCESS_TLS_INFORMATION structure contains information about the TLS operations for a process.\n */\ntypedef struct _PROCESS_TLS_INFORMATION\n{\n    ULONG Flags;                // Flags that provide additional information about the TLS operation.\n    ULONG OperationType;        // The type of TLS operation to be performed.\n    ULONG ThreadDataCount;      // The number of THREAD_TLS_INFORMATION structures in the ThreadData array.\n    ULONG TlsIndex;             // The TLS index to be replaced.\n    ULONG PreviousCount;        // The previous count of TLS data.\n    _Field_size_(ThreadDataCount) THREAD_TLS_INFORMATION ThreadData[1]; // Array of THREAD_TLS_INFORMATION structures.\n} PROCESS_TLS_INFORMATION, *PPROCESS_TLS_INFORMATION;\n\n/**\n * The PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION structure contains information about the instrumentation callback for a process.\n */\ntypedef struct _PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION\n{\n    ULONG Version;  // The version of the instrumentation callback information.\n    ULONG Reserved; // Reserved for future use.\n    PVOID Callback; // Pointer to the callback function.\n} PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION, *PPROCESS_INSTRUMENTATION_CALLBACK_INFORMATION;\n\n/**\n * The PROCESS_STACK_ALLOCATION_INFORMATION structure contains information about the stack allocation for a process.\n */\ntypedef struct _PROCESS_STACK_ALLOCATION_INFORMATION\n{\n    SIZE_T ReserveSize; // The size of the stack to be reserved.\n    SIZE_T ZeroBits;    // The number of zero bits in the stack base address.\n    PVOID StackBase;    // Pointer to the base of the stack.\n} PROCESS_STACK_ALLOCATION_INFORMATION, *PPROCESS_STACK_ALLOCATION_INFORMATION;\n\n/**\n * The PROCESS_STACK_ALLOCATION_INFORMATION_EX structure extends PROCESS_STACK_ALLOCATION_INFORMATION to include additional fields.\n */\ntypedef struct _PROCESS_STACK_ALLOCATION_INFORMATION_EX\n{\n    ULONG PreferredNode; // The preferred NUMA node for the stack allocation.\n    ULONG Reserved0;     // Reserved for future use.\n    ULONG Reserved1;     // Reserved for future use.\n    ULONG Reserved2;     // Reserved for future use.\n    PROCESS_STACK_ALLOCATION_INFORMATION AllocInfo; // The stack allocation information.\n} PROCESS_STACK_ALLOCATION_INFORMATION_EX, *PPROCESS_STACK_ALLOCATION_INFORMATION_EX;\n\n/**\n * The PROCESS_AFFINITY_UPDATE_MODE union is used to specify the affinity update mode for a process.\n */\ntypedef struct _PROCESS_AFFINITY_UPDATE_MODE\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG EnableAutoUpdate : 1; // Indicates whether auto-update of affinity is enabled.\n            ULONG Permanent : 1;        // Indicates whether the affinity update is permanent.\n            ULONG Reserved : 30;        // Reserved for future use.\n        };\n    };\n} PROCESS_AFFINITY_UPDATE_MODE, *PPROCESS_AFFINITY_UPDATE_MODE;\n\n/**\n * The PROCESS_MEMORY_ALLOCATION_MODE union is used to specify the memory allocation mode for a process.\n */\ntypedef struct _PROCESS_MEMORY_ALLOCATION_MODE\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG TopDown : 1;      // Indicates whether memory allocation should be top-down.\n            ULONG Reserved : 31;    // Reserved for future use.\n        };\n    };\n} PROCESS_MEMORY_ALLOCATION_MODE, *PPROCESS_MEMORY_ALLOCATION_MODE;\n\n/**\n * The PROCESS_HANDLE_INFORMATION structure contains information about the handles of a process.\n */\ntypedef struct _PROCESS_HANDLE_INFORMATION\n{\n    ULONG HandleCount;              // The number of handles in the process.\n    ULONG HandleCountHighWatermark; // The highest number of handles that the process has had.\n} PROCESS_HANDLE_INFORMATION, *PPROCESS_HANDLE_INFORMATION;\n\n/**\n * The PROCESS_CYCLE_TIME_INFORMATION structure contains information about the cycle time of a process.\n */\ntypedef struct _PROCESS_CYCLE_TIME_INFORMATION\n{\n    ULONGLONG AccumulatedCycles; // The total number of cycles accumulated by the process.\n    ULONGLONG CurrentCycleCount; // The current cycle count of the process.\n} PROCESS_CYCLE_TIME_INFORMATION, *PPROCESS_CYCLE_TIME_INFORMATION;\n\n/**\n * The PROCESS_WINDOW_INFORMATION structure contains information about the windows of a process.\n */\ntypedef struct _PROCESS_WINDOW_INFORMATION\n{\n    ULONG WindowFlags;          // Flags that provide information about the window.\n    USHORT WindowTitleLength;   // The length of the window title.\n    _Field_size_bytes_(WindowTitleLength) WCHAR WindowTitle[1]; // The title of the window.\n} PROCESS_WINDOW_INFORMATION, *PPROCESS_WINDOW_INFORMATION;\n\n/**\n * The PROCESS_HANDLE_TABLE_ENTRY_INFO structure contains information about a handle table entry of a process.\n */\ntypedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO\n{\n    HANDLE HandleValue;         // The value of the handle.\n    SIZE_T HandleCount;         // The number of references to the handle.\n    SIZE_T PointerCount;        // The number of pointers to the handle.\n    ACCESS_MASK GrantedAccess;  // The access rights granted to the handle.\n    ULONG ObjectTypeIndex;      // The index of the object type.\n    ULONG HandleAttributes;     // The attributes of the handle.\n    ULONG Reserved;             // Reserved for future use.\n} PROCESS_HANDLE_TABLE_ENTRY_INFO, *PPROCESS_HANDLE_TABLE_ENTRY_INFO;\n\n/**\n * The PROCESS_HANDLE_SNAPSHOT_INFORMATION structure contains information about the handle snapshot of a process.\n */\ntypedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION\n{\n    ULONG_PTR NumberOfHandles;\n    ULONG_PTR Reserved;\n    _Field_size_(NumberOfHandles) PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1];\n} PROCESS_HANDLE_SNAPSHOT_INFORMATION, *PPROCESS_HANDLE_SNAPSHOT_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if !defined(NTDDI_WIN10_FE) || (NTDDI_VERSION < NTDDI_WIN10_FE)\ntypedef struct _PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY\n{\n    union {\n        ULONG Flags;\n        struct {\n            ULONG EnforceRedirectionTrust : 1;\n            ULONG AuditRedirectionTrust : 1;\n            ULONG ReservedFlags : 30;\n        };\n    };\n} PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY, *PPROCESS_MITIGATION_REDIRECTION_TRUST_POLICY;\n#endif // NTDDI_WIN10_FE\n\n#if !defined(NTDDI_WIN10_NI) || (NTDDI_VERSION < NTDDI_WIN10_NI)\ntypedef struct _PROCESS_MITIGATION_USER_POINTER_AUTH_POLICY {\n    union {\n        ULONG Flags;\n        struct {\n            ULONG EnablePointerAuthUserIp : 1;\n            ULONG ReservedFlags : 31;\n        };\n    };\n} PROCESS_MITIGATION_USER_POINTER_AUTH_POLICY, *PPROCESS_MITIGATION_USER_POINTER_AUTH_POLICY;\n\ntypedef struct _PROCESS_MITIGATION_SEHOP_POLICY {\n    union {\n        ULONG Flags;\n        struct {\n            ULONG EnableSehop : 1;\n            ULONG ReservedFlags : 31;\n        };\n    };\n} PROCESS_MITIGATION_SEHOP_POLICY, *PPROCESS_MITIGATION_SEHOP_POLICY;\n#endif // NTDDI_WIN10_NI\n\ntypedef struct _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY2\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG AssemblyManifestRedirectionTrust : 1;\n            ULONG ReservedFlags : 31;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n} PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY2, *PPROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY2;\n\n#if defined(_PHLIB_)\n// enum PROCESS_MITIGATION_POLICY\n#define PROCESS_MITIGATION_POLICY ULONG\n#define ProcessDEPPolicy 0                      // The data execution prevention (DEP) policy of the process.\n#define ProcessASLRPolicy 1                     // The Address Space Layout Randomization (ASLR) policy of the process.\n#define ProcessDynamicCodePolicy 2              // Disables the ability to generate dynamic code or modify existing executable code.\n#define ProcessStrictHandleCheckPolicy 3        // Enables the ability to generate a fatal error if the process manipulates an invalid handle.\n#define ProcessSystemCallDisablePolicy 4        // Disables the ability of the process to use NTUser/GDI functions at the lowest layer.\n#define ProcessMitigationOptionsMask 5          // Returns the mask of valid bits for all the mitigation options on the system.\n#define ProcessExtensionPointDisablePolicy 6    // Disables the ability of the process to load legacy extension point DLLs.\n#define ProcessControlFlowGuardPolicy 7\n#define ProcessSignaturePolicy 8                // Disables the ability of the process to load images not signed by Microsoft, the Windows Store and the Windows Hardware Quality Labs (WHQL).\n#define ProcessFontDisablePolicy 9              // Disables the ability of the process to load non-system fonts.\n#define ProcessImageLoadPolicy 10               // Disables the ability of the process to load images from some locations, such a remote devices or files that have the low mandatory label.\n#define ProcessSystemCallFilterPolicy 11\n#define ProcessPayloadRestrictionPolicy 12\n#define ProcessChildProcessPolicy 13            // Disables the ability to create child processes.\n#define ProcessSideChannelIsolationPolicy 14\n#define ProcessUserShadowStackPolicy 15         // since 20H1\n#define ProcessRedirectionTrustPolicy 16\n#define ProcessUserPointerAuthPolicy 17\n#define ProcessSEHOPPolicy 18\n#define ProcessActivationContextTrustPolicy 19\n#define MaxProcessMitigationPolicy 20\n#endif // _PHLIB_\n\n/**\n * The PROCESS_MITIGATION_POLICY_INFORMATION structure represents the different process mitigation policies.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-process_mitigation_policy\n */\ntypedef struct _PROCESS_MITIGATION_POLICY_INFORMATION\n{\n    PROCESS_MITIGATION_POLICY Policy;\n    union\n    {\n        PROCESS_MITIGATION_ASLR_POLICY ASLRPolicy;\n        PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY StrictHandleCheckPolicy;\n        PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY SystemCallDisablePolicy;\n        PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY ExtensionPointDisablePolicy;\n        PROCESS_MITIGATION_DYNAMIC_CODE_POLICY DynamicCodePolicy;\n        PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY ControlFlowGuardPolicy;\n        PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY SignaturePolicy;\n        PROCESS_MITIGATION_FONT_DISABLE_POLICY FontDisablePolicy;\n        PROCESS_MITIGATION_IMAGE_LOAD_POLICY ImageLoadPolicy;\n        PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy;\n        PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy;\n        PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy;\n        PROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY SideChannelIsolationPolicy;\n        PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY UserShadowStackPolicy;\n        PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY RedirectionTrustPolicy;\n        PROCESS_MITIGATION_USER_POINTER_AUTH_POLICY UserPointerAuthPolicy;\n        PROCESS_MITIGATION_SEHOP_POLICY SEHOPPolicy;\n        PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY2 ActivationContextTrustPolicy;\n    };\n} PROCESS_MITIGATION_POLICY_INFORMATION, *PPROCESS_MITIGATION_POLICY_INFORMATION;\n\n// private\ntypedef struct _DYNAMIC_FUNCTION_TABLE DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE;\n\n/**\n * The PROCESS_DYNAMIC_FUNCTION_TABLE_INFORMATION structure is used to manage dynamic function tables for a process.\n */\ntypedef struct _PROCESS_DYNAMIC_FUNCTION_TABLE_INFORMATION\n{\n    PDYNAMIC_FUNCTION_TABLE DynamicFunctionTable; // Pointer to the dynamic function table.\n    BOOLEAN Remove; // Indicates whether to remove (TRUE) or add (FALSE) the dynamic function table.\n} PROCESS_DYNAMIC_FUNCTION_TABLE_INFORMATION, *PPROCESS_DYNAMIC_FUNCTION_TABLE_INFORMATION;\n\n/**\n * The PROCESS_KEEPALIVE_COUNT_INFORMATION structure contains information about the wake and no-wake counts for a process.\n */\ntypedef struct _PROCESS_KEEPALIVE_COUNT_INFORMATION\n{\n    ULONG WakeCount;    // The number of times the process has been awakened.\n    ULONG NoWakeCount;  // The number of times the process was not awakened when expected.\n} PROCESS_KEEPALIVE_COUNT_INFORMATION, *PPROCESS_KEEPALIVE_COUNT_INFORMATION;\n\n/**\n * The PROCESS_REVOKE_FILE_HANDLES_INFORMATION structure revokes handles to the specified device from a process.\n */\ntypedef struct _PROCESS_REVOKE_FILE_HANDLES_INFORMATION\n{\n    UNICODE_STRING TargetDevicePath;\n} PROCESS_REVOKE_FILE_HANDLES_INFORMATION, *PPROCESS_REVOKE_FILE_HANDLES_INFORMATION;\n\n// rev\n#define PROCESS_WORKING_SET_CONTROL_VERSION 3\n\n/**\n * The PROCESS_WORKING_SET_OPERATION enumeration defines the operation to perform on a process's working set.\n */\ntypedef enum _PROCESS_WORKING_SET_OPERATION\n{\n    ProcessWorkingSetSwap,              // Swap the working set of a process to disk. // (requires SeDebugPrivilege)\n    ProcessWorkingSetEmpty,             // Remove all pages from the working set of a process.\n    ProcessWorkingSetEmptyPrivatePages, // Remove private pages from the working set of a process.\n    ProcessWorkingSetOperationMax\n} PROCESS_WORKING_SET_OPERATION;\n\n/**\n * The PROCESS_WORKING_SET_FLAG_EMPTY_PRIVATE_PAGES flag indicates that the operation should target private pages in the working set.\n * Private pages are those that are not shared with other processes.\n */\n#define PROCESS_WORKING_SET_FLAG_EMPTY_PRIVATE_PAGES 0x01\n/**\n * The PROCESS_WORKING_SET_FLAG_EMPTY_SHARED_PAGES flag indicates that the operation should target shared pages in the working set.\n * Shared pages are those that are shared between multiple processes.\n */\n#define PROCESS_WORKING_SET_FLAG_EMPTY_SHARED_PAGES  0x02\n /**\n  * The PROCESS_WORKING_SET_FLAG_EMPTY_PAGES flag indicates that the operation should target pages in the working set.\n  */\n#define PROCESS_WORKING_SET_FLAG_EMPTY_PAGES         0x04\n/**\n * The PROCESS_WORKING_SET_FLAG_COMPRESS flag indicates that the operation should compress the pages before they are removed from the working set.\n * Compression is typically used in conjunction with other flags to specify that the pages should be compressed as part of the operation.\n */\n#define PROCESS_WORKING_SET_FLAG_COMPRESS            0x08\n/**\n * The PROCESS_WORKING_SET_FLAG_STORE flag indicates that the operation should store the compressed pages.\n * This is useful when the compressed data might be needed later, allowing for efficient retrieval and decompression when required.\n * This flag is typically used in conjunction with the PROCESS_WORKING_SET_FLAG_COMPRESS flag to specify that the compressed pages should be stored.\n */\n#define PROCESS_WORKING_SET_FLAG_STORE               0x10\n\n/**\n * The PROCESS_WORKING_SET_CONTROL structure is used to control the working set of a process.\n */\ntypedef struct _PROCESS_WORKING_SET_CONTROL\n{\n    ULONG Version;\n    PROCESS_WORKING_SET_OPERATION Operation;\n    ULONG Flags;\n} PROCESS_WORKING_SET_CONTROL, *PPROCESS_WORKING_SET_CONTROL;\n\n/**\n * The PS_PROTECTED_TYPE enumeration defines the types of protection that can be applied to a process.\n */\ntypedef enum _PS_PROTECTED_TYPE\n{\n    PsProtectedTypeNone,            // No protection.\n    PsProtectedTypeProtectedLight,  // Light protection.\n    PsProtectedTypeProtected,       // Full protection.\n    PsProtectedTypeMax\n} PS_PROTECTED_TYPE;\n\n/**\n * The PS_PROTECTED_SIGNER enumeration defines the types of signers that can be associated with a protected process.\n */\ntypedef enum _PS_PROTECTED_SIGNER\n{\n    PsProtectedSignerNone,          // No signer.\n    PsProtectedSignerAuthenticode,  // Authenticode signer.\n    PsProtectedSignerCodeGen,       // Code generation signer.\n    PsProtectedSignerAntimalware,   // Antimalware signer.\n    PsProtectedSignerLsa,           // Local Security Authority signer.\n    PsProtectedSignerWindows,       // Windows signer.\n    PsProtectedSignerWinTcb,        // Windows Trusted Computing Base signer.\n    PsProtectedSignerWinSystem,     // Windows system signer.\n    PsProtectedSignerApp,           // Application signer.\n    PsProtectedSignerMax\n} PS_PROTECTED_SIGNER;\n\n#define PS_PROTECTED_SIGNER_MASK 0xFF\n#define PS_PROTECTED_AUDIT_MASK 0x08\n#define PS_PROTECTED_TYPE_MASK 0x07\n\n// ProtectionLevel.Level = PsProtectedValue(PsProtectedSignerCodeGen, FALSE, PsProtectedTypeProtectedLight)\n#define PsProtectedValue(PsSigner, PsAudit, PsType) ( \\\n    (((PsSigner) & PS_PROTECTED_SIGNER_MASK) << 4) | \\\n    (((PsAudit) & PS_PROTECTED_AUDIT_MASK) << 3) | \\\n    (((PsType) & PS_PROTECTED_TYPE_MASK)) \\\n    )\n\n// InitializePsProtection(&ProtectionLevel, PsProtectedSignerCodeGen, FALSE, PsProtectedTypeProtectedLight)\n#define InitializePsProtection(PsProtectionLevel, PsSigner, PsAudit, PsType) { \\\n    (PsProtectionLevel)->Signer = (PsSigner); \\\n    (PsProtectionLevel)->Audit = (PsAudit); \\\n    (PsProtectionLevel)->Type = (PsType); \\\n    }\n\n/**\n * The PS_PROTECTION structure is used to define the protection level of a process.\n */\ntypedef struct _PS_PROTECTION\n{\n    union\n    {\n        UCHAR Level;\n        struct\n        {\n            UCHAR Type : 3;\n            UCHAR Audit : 1;\n            UCHAR Signer : 4;\n        };\n    };\n} PS_PROTECTION, *PPS_PROTECTION;\n\n/**\n * The PROCESS_MEMORY_EXHAUSTION_TYPE enumeration defines the different memory exhaustion types.\n *\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ne-processthreadsapi-process_memory_exhaustion_type\n */\n//typedef enum _PROCESS_MEMORY_EXHAUSTION_TYPE\n//{\n//    // Anytime memory management fails an allocation due to an inability to commit memory,\n//    // it will cause the process to trigger a Windows Error Reporting report and then terminate immediately with STATUS_COMMITMENT_LIMIT.\n//    // The failure cannot be caught and handled by the app.\n//    PMETypeFailFastOnCommitFailure,\n//    PMETypeMax\n//} PROCESS_MEMORY_EXHAUSTION_TYPE, *PPROCESS_MEMORY_EXHAUSTION_TYPE;\n\n/**\n * The PROCESS_MEMORY_EXHAUSTION_INFO structure allows applications to configure\n * termination if an allocation fails to commit memory.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_memory_exhaustion_info\n */\n//typedef struct _PROCESS_MEMORY_EXHAUSTION_INFO\n//{\n//    USHORT Version; // Version should be set to PME_CURRENT_VERSION.\n//    USHORT Reserved; // Reserved\n//    PROCESS_MEMORY_EXHAUSTION_TYPE Type; // Type of failure.\n//    ULONG_PTR Value; // Used to turn the feature on or off.\n//} PROCESS_MEMORY_EXHAUSTION_INFO, *PPROCESS_MEMORY_EXHAUSTION_INFO;\n\n// rev PROCESS_FAULT_INFORMATION->FaultFlags\n#define PROCESS_FAULT_FLAG_MARK_CRASHED 0x00000001 // sets Flags3.Crashed (bit 2) via atomic OR\n#define PROCESS_FAULT_FLAG_SET_STATE_CRASHED 0x00000002 // sets HangCount to 0x7\n#define PROCESS_FAULT_FLAG_ESCALATE_SEVERITY 0x00000004 // sets GhostCount to 0x7 (mask 0x38)\n#define PROCESS_FAULT_FLAG_SET_TERMINAL_BIT 0x00000008 // sets PrefilterException (bit 6)\n\n/**\n * The PROCESS_FAULT_INFORMATION structure contains information about process faults.\n */\ntypedef struct _PROCESS_FAULT_INFORMATION\n{\n    union\n    {\n        ULONG FaultFlags;\n        struct\n        {\n            ULONG MarkCrashed : 1;         // PROCESS_FAULT_FLAG_MARK_CRASHED (0x00000001)\n            ULONG SetStateCrashed : 1;     // PROCESS_FAULT_FLAG_SET_STATE_CRASHED (0x00000002)\n            ULONG EscalateSeverity : 1;    // PROCESS_FAULT_FLAG_ESCALATE_SEVERITY (0x00000004)\n            ULONG SetTerminalBit : 1;      // PROCESS_FAULT_FLAG_SET_TERMINAL_BIT (0x00000008)\n            ULONG Reserved : 28;\n        };\n    };\n    ULONG AdditionalInfo; // Reserved for future use.\n} PROCESS_FAULT_INFORMATION, *PPROCESS_FAULT_INFORMATION;\n\n/**\n * The PROCESS_TELEMETRY_ID_INFORMATION structure contains telemetry information about a process.\n */\n_Struct_size_bytes_(HeaderSize)\ntypedef struct _PROCESS_TELEMETRY_ID_INFORMATION\n{\n    ULONG HeaderSize;                       // The size of the structure, in bytes.\n    ULONG ProcessId;                        // The ID of the process.\n    ULONG64 ProcessStartKey;                // The start key of the process.\n    ULONG64 CreateTime;                     // The creation time of the process.\n    ULONG64 CreateInterruptTime;            // The interrupt time at creation.\n    ULONG64 CreateUnbiasedInterruptTime;    // The unbiased interrupt time at creation.\n    ULONG64 ProcessSequenceNumber;          // The monotonic sequence number of the process.\n    ULONG64 SessionCreateTime;              // The session creation time.\n    ULONG SessionId;                        // The ID of the session.\n    ULONG BootId;                           // The boot ID.\n    ULONG ImageChecksum;                    // The checksum of the process image.\n    ULONG ImageTimeDateStamp;               // The timestamp of the process image.\n    ULONG UserSidOffset;                    // The offset to the user SID.\n    ULONG ImagePathOffset;                  // The offset to the image path.\n    ULONG PackageNameOffset;                // The offset to the package name.\n    ULONG RelativeAppNameOffset;            // The offset to the relative application name.\n    ULONG CommandLineOffset;                // The offset to the command line.\n} PROCESS_TELEMETRY_ID_INFORMATION, *PPROCESS_TELEMETRY_ID_INFORMATION;\n\n/**\n * The PROCESS_COMMIT_RELEASE_INFORMATION structure contains information about the commit and release of memory for a process.\n */\ntypedef struct _PROCESS_COMMIT_RELEASE_INFORMATION\n{\n    ULONG Version;\n    struct\n    {\n        ULONG Eligible : 1;\n        ULONG ReleaseRepurposedMemResetCommit : 1;\n        ULONG ForceReleaseMemResetCommit : 1;\n        ULONG Spare : 29;\n    };\n    SIZE_T CommitDebt;\n    SIZE_T CommittedMemResetSize;\n    SIZE_T RepurposedMemResetSize;\n} PROCESS_COMMIT_RELEASE_INFORMATION, *PPROCESS_COMMIT_RELEASE_INFORMATION;\n\n/**\n * The PROCESS_JOB_MEMORY_INFO structure represents app memory usage at a single point in time.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-app_memory_information\n */\ntypedef struct _PROCESS_JOB_MEMORY_INFO\n{\n    ULONG64 SharedCommitUsage;        // The current shared commit usage, in bytes.\n    ULONG64 PrivateCommitUsage;       // The current private commit usage, in bytes.\n    ULONG64 PeakPrivateCommitUsage;   // The peak private commit usage, in bytes.\n    ULONG64 PrivateCommitLimit;       // The private commit limit, in bytes.\n    ULONG64 TotalCommitLimit;         // The total commit limit, in bytes.\n} PROCESS_JOB_MEMORY_INFO, *PPROCESS_JOB_MEMORY_INFO;\n\n// rev\ntypedef struct _PROCESS_IUM_CHALLENGE_RESPONSE\n{\n    BYTE Buffer[0x1000]; // Challenge response buffer.\n} PROCESS_IUM_CHALLENGE_RESPONSE, *PPROCESS_IUM_CHALLENGE_RESPONSE;\n\n/**\n * The PROCESS_CHILD_PROCESS_INFORMATION structure contains information about child process policies.\n */\ntypedef struct _PROCESS_CHILD_PROCESS_INFORMATION\n{\n    BOOLEAN ProhibitChildProcesses;         // Child processes are prohibited.\n    BOOLEAN AlwaysAllowSecureChildProcess;  // Secure child processes are always allowed.\n    BOOLEAN AuditProhibitChildProcesses;    // Child processes are audited.\n} PROCESS_CHILD_PROCESS_INFORMATION, *PPROCESS_CHILD_PROCESS_INFORMATION;\n\n/**\n * Defines the current version of the power throttling structure.\n */\n#define POWER_THROTTLING_PROCESS_CURRENT_VERSION 1\n/**\n * Limits the CPU execution speed of the process to reduce power consumption.\n */\n#define POWER_THROTTLING_PROCESS_EXECUTION_SPEED 0x1\n/**\n * The POWER_THROTTLING_PROCESS_DELAYTIMERS flag delays the expiration of waits and timers for the process.\n * When this flag is set, the process's wait and timer expiration events may be postponed,\n * which can help reduce power consumption by allowing the system to remain in low-power states longer.\n */\n#define POWER_THROTTLING_PROCESS_DELAYTIMERS 0x2\n/**\n * The POWER_THROTTLING_PROCESS_IGNORE_TIMER_RESOLUTION flag controls whether calls made by the\n * process to adjust the system timer resolution (such as timeBeginPeriod or NtSetTimerResolution)\n * are honored. When this flag is enabled, such requests are ignored.\n *\n * This behavior is part of Windows power-throttling mechanism introduced in Windows 11 and is\n * enabled by default for all processes. Changes to the system timer resolution can alter the\n * behavior of system timers, wait timeouts, and sleep durations, often causing unintended\n * side effects in applications. Higher-precision timer resolutions also negatively impact\n * battery life and overall system performance.\n *\n * \\note Enabled by default since Windows 11. This may cause performance issues for legacy\n *       applications and games that rely on modifying the system tick resolution.\n */\n#define POWER_THROTTLING_PROCESS_IGNORE_TIMER_RESOLUTION 0x4 // since WIN11\n/**\n * Valid flags for power throttling process control and state masks.\n */\n#define POWER_THROTTLING_PROCESS_VALID_FLAGS \\\n    ((POWER_THROTTLING_PROCESS_EXECUTION_SPEED | POWER_THROTTLING_PROCESS_DELAYTIMERS | POWER_THROTTLING_PROCESS_IGNORE_TIMER_RESOLUTION))\n\n/**\n * The POWER_THROTTLING_PROCESS_STATE structure is used to manage the power throttling state of a process.\n */\ntypedef struct _POWER_THROTTLING_PROCESS_STATE\n{\n    ULONG Version;       // The version of the structure.\n    ULONG ControlMask;   // A mask that specifies the control settings for power throttling.\n    ULONG StateMask;     // A mask that specifies the current state of power throttling.\n} POWER_THROTTLING_PROCESS_STATE, *PPOWER_THROTTLING_PROCESS_STATE;\n\n// private\n#ifndef PROCESS_POWER_THROTTLING_CURRENT_VERSION\n#define PROCESS_POWER_THROTTLING_CURRENT_VERSION 1\n#endif\n#ifndef PROCESS_POWER_THROTTLING_EXECUTION_SPEED\n#define PROCESS_POWER_THROTTLING_EXECUTION_SPEED 0x1\n#endif\n#ifndef PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION\n#define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x4\n#endif\n#ifndef PROCESS_POWER_THROTTLING_VALID_FLAGS\n#define PROCESS_POWER_THROTTLING_VALID_FLAGS \\\n    ((PROCESS_POWER_THROTTLING_EXECUTION_SPEED | PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION))\n#endif\n\n// private\n//typedef struct _PROCESS_POWER_THROTTLING_STATE\n//{\n//    ULONG Version;\n//    ULONG ControlMask;\n//    ULONG StateMask;\n//} PROCESS_POWER_THROTTLING_STATE, *PPROCESS_POWER_THROTTLING_STATE;\n\n// private\ntypedef enum _PROCESS_ACTIVITY_THROTTLE_POLICY_OP\n{\n    ProcessActivityThrottlePolicyDisable = 0,\n    ProcessActivityThrottlePolicyEnable = 1,\n    ProcessActivityThrottlePolicyDefault = 2,\n    MaxProcessActivityThrottlePolicy\n} PROCESS_ACTIVITY_THROTTLE_POLICY_OP;\n\n// PROCESS_ACTIVITY_THROTTLE_POLICY PolicyFlags\n#define PROCESS_ACTIVITY_THROTTLE_EXECUTIONSPEED 0x1\n#define PROCESS_ACTIVITY_THROTTLE_DELAYTIMERS 0x2\n#define PROCESS_ACTIVITY_THROTTLE_ALL \\\n    ((PROCESS_ACTIVITY_THROTTLE_EXECUTIONSPEED | PROCESS_ACTIVITY_THROTTLE_DELAYTIMERS))\n\n/**\n * The PROCESS_ACTIVITY_THROTTLE_POLICY structure is used to manage the activity throttle of a process.\n */\ntypedef struct _PROCESS_ACTIVITY_THROTTLE_POLICY\n{\n    PROCESS_ACTIVITY_THROTTLE_POLICY_OP Operation;\n    ULONG PolicyFlags;\n} PROCESS_ACTIVITY_THROTTLE_POLICY, *PPROCESS_ACTIVITY_THROTTLE_POLICY;\n\n// rev (tyranid)\n#define WIN32K_SYSCALL_FILTER_STATE_ENABLE 0x1\n#define WIN32K_SYSCALL_FILTER_STATE_AUDIT 0x2\n\n/**\n * The WIN32K_SYSCALL_FILTER structure is used to specify filtering options for Win32k system calls.\n */\ntypedef struct _WIN32K_SYSCALL_FILTER\n{\n    ULONG FilterState; // The state of the Win32k syscall filter (e.g., enable, audit).\n    ULONG FilterSet;   // The set of Win32k syscalls to be filtered.\n} WIN32K_SYSCALL_FILTER, *PWIN32K_SYSCALL_FILTER;\n\n// private\ntypedef struct _JOBOBJECT_WAKE_FILTER\n{\n    ULONG HighEdgeFilter;\n    ULONG LowEdgeFilter;\n} JOBOBJECT_WAKE_FILTER, *PJOBOBJECT_WAKE_FILTER;\n\n// private\ntypedef enum _PS_WAKE_REASON\n{\n    PsWakeReasonUser = 0,\n    PsWakeReasonExecutionRequired = 1,\n    PsWakeReasonKernel = 2,\n    PsWakeReasonInstrumentation = 3,\n    PsWakeReasonPreserveProcess = 4,\n    PsWakeReasonActivityReference = 5,\n    PsWakeReasonWorkOnBehalf = 6,\n    PsMaxWakeReasons = 7,\n} PS_WAKE_REASON, *PPS_WAKE_REASON;\n\ntypedef struct _PROCESS_WAKE_INFORMATION\n{\n    ULONG64 NotificationChannel;\n    ULONG WakeCounters[PsMaxWakeReasons];\n    JOBOBJECT_WAKE_FILTER WakeFilter;\n} PROCESS_WAKE_INFORMATION, *PPROCESS_WAKE_INFORMATION;\n\ntypedef struct _PROCESS_ENERGY_TRACKING_STATE\n{\n    ULONG StateUpdateMask;\n    ULONG StateDesiredValue;\n    ULONG StateSequence;\n    ULONG UpdateTag : 1;\n    WCHAR Tag[64];\n} PROCESS_ENERGY_TRACKING_STATE, *PPROCESS_ENERGY_TRACKING_STATE;\n\n/**\n * The MANAGE_WRITES_TO_EXECUTABLE_MEMORY structure controls write permissions to executable memory\n * for processes and threads, and provides a signal for kernel write events.\n */\ntypedef struct _MANAGE_WRITES_TO_EXECUTABLE_MEMORY\n{\n    ULONG Version : 8;                         // The version of the structure.\n    ULONG ProcessEnableWriteExceptions : 1;    // Enables write exceptions for the process.\n    ULONG ThreadAllowWrites : 1;               // Allows the thread to write to executable memory.\n    ULONG Spare : 22;                          // Reserved for future use.\n    HANDLE KernelWriteToExecutableSignal;      // Pointer to kernel signal for write-to-executable events (19H1+).\n} MANAGE_WRITES_TO_EXECUTABLE_MEMORY, *PMANAGE_WRITES_TO_EXECUTABLE_MEMORY;\n\n#define POWER_THROTTLING_THREAD_CURRENT_VERSION 1\n#define POWER_THROTTLING_THREAD_EXECUTION_SPEED 0x1\n#define POWER_THROTTLING_THREAD_VALID_FLAGS (POWER_THROTTLING_THREAD_EXECUTION_SPEED)\n\n/**\n * The POWER_THROTTLING_THREAD_STATE structure contains the throttling policies of a thread subject to power management.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_power_throttling_thread_state\n */\ntypedef struct _POWER_THROTTLING_THREAD_STATE\n{\n    ULONG Version;          // The version of this structure. Set to THREAD_POWER_THROTTLING_CURRENT_VERSION.\n    ULONG ControlMask;      // Flags that enable the caller to take control of the power throttling mechanism.\n    ULONG StateMask;        // Flags that manage the power throttling mechanism on/off state.\n} POWER_THROTTLING_THREAD_STATE, *PPOWER_THROTTLING_THREAD_STATE;\n\n#define PROCESS_READWRITEVM_LOGGING_ENABLE_READVM 1\n#define PROCESS_READWRITEVM_LOGGING_ENABLE_WRITEVM 2\n#define PROCESS_READWRITEVM_LOGGING_ENABLE_READVM_V 1UL\n#define PROCESS_READWRITEVM_LOGGING_ENABLE_WRITEVM_V 2UL\n\n/**\n * The PROCESS_READWRITEVM_LOGGING_INFORMATION structure provides flags to enable logging\n * of read and write operations to a process's virtual memory.\n */\ntypedef struct _PROCESS_READWRITEVM_LOGGING_INFORMATION\n{\n    union\n    {\n        UCHAR Flags;\n        struct\n        {\n            UCHAR EnableReadVmLogging : 1;  // Enable logging of read operations to virtual memory.\n            UCHAR EnableWriteVmLogging : 1; // Enable logging of write operations to virtual memory.\n            UCHAR Unused : 6;\n        };\n    };\n} PROCESS_READWRITEVM_LOGGING_INFORMATION, *PPROCESS_READWRITEVM_LOGGING_INFORMATION;\n\n/**\n * The PROCESS_UPTIME_INFORMATION structure contains information about the uptime of a process and diagnostic information.\n */\ntypedef struct _PROCESS_UPTIME_INFORMATION\n{\n    ULONGLONG QueryInterruptTime;      // The interrupt time when the query was made.\n    ULONGLONG QueryUnbiasedTime;       // The unbiased time when the query was made.\n    ULONGLONG EndInterruptTime;        // The interrupt time when the process ended.\n    ULONGLONG TimeSinceCreation;       // The total time elapsed since the process was created.\n    ULONGLONG Uptime;                  // The total uptime of the process.\n    ULONGLONG SuspendedTime;           // The total time the process was in a suspended state.\n    struct\n    {\n        ULONG HangCount : 4;           // The number of times the process was detected as hanging.\n        ULONG GhostCount : 4;          // The number of times the process was detected as a ghost process.\n        ULONG Crashed : 1;             // Indicates whether the process has crashed (1 if true, 0 otherwise).\n        ULONG Terminated : 1;          // Indicates whether the process has been terminated (1 if true, 0 otherwise).\n    };\n} PROCESS_UPTIME_INFORMATION, *PPROCESS_UPTIME_INFORMATION;\n\n/**\n * The PROCESS_SYSTEM_RESOURCE_MANAGEMENT union is used to specify system resource management flags for a process.\n */\ntypedef struct _PROCESS_SYSTEM_RESOURCE_MANAGEMENT\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Foreground : 1; // Indicates if the process is a foreground process (1 = foreground, 0 = background).\n            ULONG Reserved : 31;\n        };\n    };\n} PROCESS_SYSTEM_RESOURCE_MANAGEMENT, *PPROCESS_SYSTEM_RESOURCE_MANAGEMENT;\n\n/**\n * The PROCESS_SECURITY_DOMAIN_INFORMATION structure contains the security domain identifier for a process.\n *\n * This structure is used to query or set the security domain of a process, which can be used for isolation\n * and security boundary purposes in Windows. The SecurityDomain field is a 64-bit value that uniquely\n * identifies the security domain associated with the process.\n */\ntypedef struct _PROCESS_SECURITY_DOMAIN_INFORMATION\n{\n    ULONGLONG SecurityDomain; // The unique identifier of the process's security domain.\n} PROCESS_SECURITY_DOMAIN_INFORMATION, *PPROCESS_SECURITY_DOMAIN_INFORMATION;\n\n/**\n * The PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION structure combines the security domain of a process.\n *\n * This structure contains information required to combine the security domains\n * of a specified process. It is typically used in system-level or security-related\n * operations where process security contexts need to be merged or managed.\n */\ntypedef struct _PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION\n{\n    HANDLE ProcessHandle; // The Handle to the process whose security domains are to be combined.\n} PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION, *PPROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION;\n\n/**\n * The PROCESS_LOGGING_INFORMATION structure provides flags to enable or disable logging\n * for specific process and thread events, such as virtual memory access, suspend/resume,\n * execution protection, and impersonation.\n */\ntypedef struct _PROCESS_LOGGING_INFORMATION\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG EnableReadVmLogging : 1;                  // Enables logging of read operations to process virtual memory.\n            ULONG EnableWriteVmLogging : 1;                 // Enables logging of write operations to process virtual memory.\n            ULONG EnableProcessSuspendResumeLogging : 1;    // Enables logging of process suspend and resume events.\n            ULONG EnableThreadSuspendResumeLogging : 1;     // Enables logging of thread suspend and resume events.\n            ULONG EnableLocalExecProtectVmLogging : 1;      // Enables logging of local execution protection for virtual memory.\n            ULONG EnableRemoteExecProtectVmLogging : 1;     // Enables logging of remote execution protection for virtual memory.\n            ULONG EnableImpersonationLogging : 1;           // Enables logging of impersonation events.\n            ULONG Reserved : 25;\n        };\n    };\n} PROCESS_LOGGING_INFORMATION, *PPROCESS_LOGGING_INFORMATION;\n\n/**\n * This value changes the seconds field during a positive leap second adjustment by the system.\n * If enabled, then the seconds field returns any positive leap second (For example: 23:59:59 -> 23:59:60 -> 00:00:00).\n * If not enabled, then the 59th second preceding a positive leap second will be shown for 2 seconds with the milliseconds\n * value ticking twice as slow. (For example: 23:59:59 -> 23:59:59.500 -> 00:00:00, which takes 2 seconds in wall clock time).\n * Note: Leap second adjustments are disabled by default for each process, this flag also does not persist if the process is restarted.\n */\n#define PROCESS_LEAP_SECOND_FLAG_ENABLE_SIXTY_SECOND 0x1\n#define PROCESS_LEAP_SECOND_VALID_FLAGS (PROCESS_LEAP_SECOND_INFO_FLAG_ENABLE_SIXTY_SECOND)\n\n/**\n * The PROCESS_LEAP_SECOND_INFORMATION structure contains information about leap second adjustments for a process.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_leap_second_info\n */\ntypedef struct _PROCESS_LEAP_SECOND_INFORMATION\n{\n    ULONG Flags;\n    ULONG Reserved;\n} PROCESS_LEAP_SECOND_INFORMATION, *PPROCESS_LEAP_SECOND_INFORMATION;\n\ntypedef struct _PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION\n{\n    ULONGLONG ReserveSize;\n    ULONGLONG CommitSize;\n    ULONG PreferredNode;\n    ULONG Reserved;\n    PVOID Ssp;\n} PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION, *PPROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION;\n\ntypedef struct _PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION\n{\n    PVOID Ssp;\n} PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION, *PPROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION;\n\n/**\n * The PROCESS_SYSCALL_PROVIDER_INFORMATION structure contains information about a system call provider\n * and level for system call filtering or instrumentation.\n */\ntypedef struct _PROCESS_SYSCALL_PROVIDER_INFORMATION\n{\n    GUID ProviderId; // The unique identifier of the system call provider.\n    UCHAR Level;     // The level or mode of the provider.\n} PROCESS_SYSCALL_PROVIDER_INFORMATION, *PPROCESS_SYSCALL_PROVIDER_INFORMATION;\n\n/**\n * Contains dynamic enforced address ranges used by various features related to user-mode Hardware-enforced Stack Protection (HSP).\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-process_dynamic_enforced_address_range\n */\n//typedef struct _PROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGE\n//{\n//    ULONG_PTR BaseAddress;\n//    SIZE_T Size;\n//    ULONG Flags;\n//} PROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGE, *PPROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGE;\n//\n//typedef struct _PROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGES_INFORMATION\n//{\n//    USHORT NumberOfRanges;\n//    USHORT Reserved;\n//    ULONG Reserved2;\n//    PPROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGE Ranges;\n//} PROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGES_INFORMATION, *PPROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGES_INFORMATION;\n\n/**\n * The PROCESS_MEMBERSHIP_INFORMATION structure contains the Silo identifier of the process.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-process_membership_information\n */\ntypedef struct _PROCESS_MEMBERSHIP_INFORMATION\n{\n    ULONG ServerSiloId;\n} PROCESS_MEMBERSHIP_INFORMATION, *PPROCESS_MEMBERSHIP_INFORMATION;\n\n#if !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\n/**\n * The PROCESS_NETWORK_COUNTERS structure contains network usage statistics for a process.\n */\ntypedef struct _PROCESS_NETWORK_COUNTERS\n{\n    ULONG64 BytesIn; // The total number of bytes received by the process.\n    ULONG64 BytesOut; // The total number of bytes sent by the process.\n} PROCESS_NETWORK_COUNTERS, *PPROCESS_NETWORK_COUNTERS;\n#endif\n\n/**\n * The PROCESS_TEB_VALUE_INFORMATION structure contains information from the Thread Environment Block (TEB) for a specific thread.\n */\ntypedef struct _PROCESS_TEB_VALUE_INFORMATION\n{\n    ULONG ThreadId; // The identifier of the thread whose TEB is being queried or modified.\n    ULONG TebOffset; // The offset within the TEB where the value is located.\n    ULONG_PTR Value; // The value at the specified offset in the TEB.\n} PROCESS_TEB_VALUE_INFORMATION, *PPROCESS_TEB_VALUE_INFORMATION;\n\n// rev\ntypedef struct _PROCESS_AVAILABLE_CPUS_INFORMATION\n{\n    ULONG64 ObservedSequenceNumber;\n    ULONG64 SequenceNumber;\n    ULONG AvailableCpusCount;\n    PKAFFINITY_EX Affinity;\n} PROCESS_AVAILABLE_CPUS_INFORMATION, *PPROCESS_AVAILABLE_CPUS_INFORMATION;\n\n/**\n * The NtQueryPortInformationProcess function retrieves the status of the current process exception port.\n *\n * \\return LOGICAL If TRUE, the process exception port is valid.\n */\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtQueryPortInformationProcess(\n    VOID\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Thread information structures\n//\n\n/**\n * The THREAD_BASIC_INFORMATION structure contains basic information about the thread.\n */\ntypedef struct _THREAD_BASIC_INFORMATION\n{\n    NTSTATUS ExitStatus;        // The exit status of the thread or STATUS_PENDING when the thread has not terminated. (GetExitCodeThread)\n    PTEB TebBaseAddress;        // The base address of the memory region containing the TEB structure. (NtCurrentTeb)\n    CLIENT_ID ClientId;         // The process and thread identifier of the thread.\n    KAFFINITY AffinityMask;     // The affinity mask of the thread. (deprecated) (SetThreadAffinityMask)\n    KPRIORITY Priority;         // The current priority of the thread. (GetThreadPriority)\n    KPRIORITY BasePriority;     // The current base priority of the thread determined by the thread priority and process priority class.\n} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;\n\n/**\n * The THREAD_LAST_SYSCALL_INFORMATION structure contains information about the last system call made by a thread.\n */\ntypedef struct _THREAD_LAST_SYSCALL_INFORMATION\n{\n    PVOID FirstArgument;        // Pointer to the first argument of the last system call.\n    USHORT SystemCallNumber;    // The system call number of the last system call made by the thread.\n    ULONG64 WaitTime;           // The time spent waiting for the system call to complete, in milliseconds.\n} THREAD_LAST_SYSCALL_INFORMATION, *PTHREAD_LAST_SYSCALL_INFORMATION;\n\n/**\n * The THREAD_CYCLE_TIME_INFORMATION structure contains information about the cycle time of a thread.\n */\ntypedef struct _THREAD_CYCLE_TIME_INFORMATION\n{\n    ULONG64 AccumulatedCycles;        // The total number of cycles accumulated by the thread.\n    ULONG64 CurrentCycleCount;        // The current cycle count of the thread.\n} THREAD_CYCLE_TIME_INFORMATION, *PTHREAD_CYCLE_TIME_INFORMATION;\n\n// RtlAbPostRelease / ReleaseAllUserModeAutoBoostLockHandles\ntypedef struct _THREAD_LOCK_OWNERSHIP\n{\n    ULONG SrwLock[1];\n} THREAD_LOCK_OWNERSHIP, *PTHREAD_LOCK_OWNERSHIP;\n\ntypedef enum _SCHEDULER_SHARED_DATA_SLOT_ACTION\n{\n    SchedulerSharedSlotAssign,\n    SchedulerSharedSlotFree,\n    SchedulerSharedSlotQuery\n} SCHEDULER_SHARED_DATA_SLOT_ACTION;\n\ntypedef struct _SCHEDULER_SHARED_DATA_SLOT_INFORMATION\n{\n    SCHEDULER_SHARED_DATA_SLOT_ACTION Action;\n    PVOID SchedulerSharedDataHandle;\n    PVOID Slot;\n} SCHEDULER_SHARED_DATA_SLOT_INFORMATION, *PSCHEDULER_SHARED_DATA_SLOT_INFORMATION;\n\ntypedef struct _THREAD_TEB_INFORMATION\n{\n    _Inout_bytecount_(BytesToRead) PVOID TebInformation; // Buffer to write data into.\n    _In_ ULONG TebOffset;                                // Offset in TEB to begin reading from.\n    _In_ ULONG BytesToRead;                              // Number of bytes to read.\n} THREAD_TEB_INFORMATION, *PTHREAD_TEB_INFORMATION;\n\n/**\n * The COUNTER_READING structure is used to store individual counter data from a hardware counter.\n *\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-hardware_counter_data\n */\ntypedef struct _COUNTER_READING\n{\n    HARDWARE_COUNTER_TYPE Type;     // Specifies the type of hardware counter data collected.\n    ULONG Index;                    // An identifier for the specific counter.\n    ULONG64 Start;                  // The initial value of the counter when measurement started.\n    ULONG64 Total;                  // The accumulated value of the counter over the measurement period.\n} COUNTER_READING, *PCOUNTER_READING;\n\n#ifndef THREAD_PERFORMANCE_DATA_VERSION\n#define THREAD_PERFORMANCE_DATA_VERSION 1\n#endif\n\n/**\n * The THREAD_PERFORMANCE_DATA structure aggregates various performance metrics for a thread.\n *\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-performance_data\n */\n_Struct_size_bytes_(Size)\ntypedef struct _THREAD_PERFORMANCE_DATA\n{\n    USHORT Size;                                    // The size of the structure.\n    USHORT Version;                                 // The version of the structure. Must be set to \\ref THREAD_PERFORMANCE_DATA_VERSION.\n    PROCESSOR_NUMBER ProcessorNumber;               // The processor number that identifies where the thread is running.\n    ULONG ContextSwitches;                          // The number of context switches that occurred from the time profiling was enabled.\n    ULONG HwCountersCount;                          // The number of array elements in the HwCounters array that contain hardware counter data.\n    ULONG64 UpdateCount;                            // The number of times that the read operation read the data to ensure a consistent snapshot of the data.\n    ULONG64 WaitReasonBitMap;                       // A bitmask of \\ref KWAIT_REASON that identifies the reasons for the context switches that occurred since the last time the data was read.\n    ULONG64 HardwareCounters;                       // A bitmask of hardware counters used to collect counter data.\n    COUNTER_READING CycleTime;                      // The cycle time of the thread (excludes the time spent interrupted) from the time profiling was enabled.\n    COUNTER_READING HwCounters[MAX_HW_COUNTERS];    // The \\ref COUNTER_READING structure that contains hardware counter data.\n} THREAD_PERFORMANCE_DATA, *PTHREAD_PERFORMANCE_DATA;\n\n#ifndef THREAD_PROFILING_FLAG_DISPATCH\n#define THREAD_PROFILING_FLAG_DISPATCH 0x00000001\n#endif\n\n#ifndef THREAD_PROFILING_FLAG_HARDWARE_COUNTERS\n#define THREAD_PROFILING_FLAG_HARDWARE_COUNTERS 0x00000002\n#endif\n\n/**\n * The THREAD_PROFILING_INFORMATION structure contains profiling information and references to performance data.\n *\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readthreadprofilingdata\n */\ntypedef struct _THREAD_PROFILING_INFORMATION\n{\n    // To receive hardware performance counter data, set this parameter to a bitmask that identifies the hardware counters to collect.\n    // You can specify up to 16 performance counters. Each bit relates directly to the zero-based hardware counter index for the hardware\n    // performance counters that you configured. Set to zero if you are not collecting hardware counter data.\n    // If you set a bit for a hardware counter that has not been configured, the counter value that is read for that counter is zero.\n    ULONG64 HardwareCounters;\n    // To receive thread profiling data such as context switch count, set this parameter to \\ref THREAD_PROFILING_FLAG_DISPATCH.\n    ULONG Flags;\n    // Enable or disable thread profiling on the specified thread.\n    ULONG Enable;\n    // The PERFORMANCE_DATA structure that contains thread profiling and hardware counter data.\n    PTHREAD_PERFORMANCE_DATA PerformanceData;\n} THREAD_PROFILING_INFORMATION, *PTHREAD_PROFILING_INFORMATION;\n\ntypedef struct _RTL_UMS_CONTEXT\n{\n    SINGLE_LIST_ENTRY Link;\n    CONTEXT Context;\n    PVOID Teb;\n    PVOID UserContext;\n    volatile ULONG ScheduledThread : 1;\n    volatile ULONG Suspended : 1;\n    volatile ULONG VolatileContext : 1;\n    volatile ULONG Terminated : 1;\n    volatile ULONG DebugActive : 1;\n    volatile ULONG RunningOnSelfThread : 1;\n    volatile ULONG DenyRunningOnSelfThread : 1;\n    volatile LONG Flags;\n    volatile ULONG64 KernelUpdateLock : 2;\n    volatile ULONG64 PrimaryClientID : 62;\n    volatile ULONG64 ContextLock;\n    struct _RTL_UMS_CONTEXT* PrimaryUmsContext;\n    ULONG SwitchCount;\n    ULONG KernelYieldCount;\n    ULONG MixedYieldCount;\n    ULONG YieldCount;\n} RTL_UMS_CONTEXT, *PRTL_UMS_CONTEXT;\n\ntypedef enum _THREAD_UMS_INFORMATION_COMMAND\n{\n    UmsInformationCommandInvalid,\n    UmsInformationCommandAttach,\n    UmsInformationCommandDetach,\n    UmsInformationCommandQuery\n} THREAD_UMS_INFORMATION_COMMAND;\n\ntypedef struct _RTL_UMS_COMPLETION_LIST\n{\n    PSINGLE_LIST_ENTRY ThreadListHead;\n    PVOID CompletionEvent;\n    ULONG CompletionFlags;\n    SINGLE_LIST_ENTRY InternalListHead;\n} RTL_UMS_COMPLETION_LIST, *PRTL_UMS_COMPLETION_LIST;\n\ntypedef struct _THREAD_UMS_INFORMATION\n{\n    THREAD_UMS_INFORMATION_COMMAND Command;\n    PRTL_UMS_COMPLETION_LIST CompletionList;\n    PRTL_UMS_CONTEXT UmsContext;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG IsUmsSchedulerThread : 1;\n            ULONG IsUmsWorkerThread : 1;\n            ULONG SpareBits : 30;\n        };\n    };\n} THREAD_UMS_INFORMATION, *PTHREAD_UMS_INFORMATION;\n\n/**\n * The THREAD_NAME_INFORMATION structure assigns a description to a thread.\n *\n * \\remarks The handle must have THREAD_SET_LIMITED_INFORMATION access.\n * \\remarks https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription\n */\ntypedef struct _THREAD_NAME_INFORMATION\n{\n    UNICODE_STRING ThreadName;\n} THREAD_NAME_INFORMATION, *PTHREAD_NAME_INFORMATION;\n\ntypedef struct _ALPC_WORK_ON_BEHALF_TICKET\n{\n    ULONG ThreadId;\n    ULONG ThreadCreationTimeLow;\n} ALPC_WORK_ON_BEHALF_TICKET, *PALPC_WORK_ON_BEHALF_TICKET;\n\ntypedef struct _RTL_WORK_ON_BEHALF_TICKET_EX\n{\n    ALPC_WORK_ON_BEHALF_TICKET Ticket;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG CurrentThread : 1;\n            ULONG Reserved1 : 31;\n        };\n    };\n    ULONG Reserved2;\n} RTL_WORK_ON_BEHALF_TICKET_EX, *PRTL_WORK_ON_BEHALF_TICKET_EX;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _SUBSYSTEM_INFORMATION_TYPE\n{\n    SubsystemInformationTypeWin32,\n    SubsystemInformationTypeWSL,\n    MaxSubsystemInformationType\n} SUBSYSTEM_INFORMATION_TYPE;\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\ntypedef enum _THREAD_WORKLOAD_CLASS\n{\n    ThreadWorkloadClassDefault,\n    ThreadWorkloadClassGraphics,\n    MaxThreadWorkloadClass\n} THREAD_WORKLOAD_CLASS;\n\n#if defined(_ARM64_)\n\n#define CONTEXT_ARM   0x00200000L\n\n#define CONTEXT_ARM_CONTROL (CONTEXT_ARM | 0x1L)\n#define CONTEXT_ARM_INTEGER (CONTEXT_ARM | 0x2L)\n#define CONTEXT_ARM_FLOATING_POINT  (CONTEXT_ARM | 0x4L)\n#define CONTEXT_ARM_DEBUG_REGISTERS (CONTEXT_ARM | 0x8L)\n#define CONTEXT_ARM_FULL (CONTEXT_ARM_CONTROL | CONTEXT_ARM_INTEGER | CONTEXT_ARM_FLOATING_POINT)\n#define CONTEXT_ARM_ALL (CONTEXT_ARM_CONTROL | CONTEXT_ARM_INTEGER | CONTEXT_ARM_FLOATING_POINT | CONTEXT_ARM_DEBUG_REGISTERS)\n\n#define ARM_MAX_BREAKPOINTS     8\n#define ARM_MAX_WATCHPOINTS     1\n\ntypedef struct _ARM_NT_NEON128 {\n    ULONGLONG Low;\n    LONGLONG High;\n} ARM_NT_NEON128, *PARM_NT_NEON128;\n\ntypedef struct DECLSPEC_ALIGN(8) DECLSPEC_NOINITALL _ARM_NT_CONTEXT {\n\n    //\n    // Control flags.\n    //\n\n    ULONG ContextFlags;\n\n    //\n    // Integer registers\n    //\n\n    ULONG R0;\n    ULONG R1;\n    ULONG R2;\n    ULONG R3;\n    ULONG R4;\n    ULONG R5;\n    ULONG R6;\n    ULONG R7;\n    ULONG R8;\n    ULONG R9;\n    ULONG R10;\n    ULONG R11;\n    ULONG R12;\n\n    //\n    // Control Registers\n    //\n\n    ULONG Sp;\n    ULONG Lr;\n    ULONG Pc;\n    ULONG Cpsr;\n\n    //\n    // Floating Point/NEON Registers\n    //\n\n    ULONG Fpscr;\n    ULONG Padding;\n    union {\n        ARM_NT_NEON128 Q[16];\n        ULONGLONG D[32];\n        ULONG S[32];\n    } DUMMYUNIONNAME;\n\n    //\n    // Debug registers\n    //\n\n    ULONG Bvr[ARM_MAX_BREAKPOINTS];\n    ULONG Bcr[ARM_MAX_BREAKPOINTS];\n    ULONG Wvr[ARM_MAX_WATCHPOINTS];\n    ULONG Wcr[ARM_MAX_WATCHPOINTS];\n\n    ULONG Padding2[2];\n\n} ARM_NT_CONTEXT, *PARM_NT_CONTEXT;\n\n#endif // _ARM64_\n\n// private\ntypedef struct _THREAD_INDEX_INFORMATION\n{\n    ULONG Index;\n    ULONG Sequence;\n} THREAD_INDEX_INFORMATION, *PTHREAD_INDEX_INFORMATION;\n\n//\n// Processes\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n/**\n * Creates a new process.\n *\n * \\param ProcessHandle A pointer to a handle that receives the process object handle.\n * \\param DesiredAccess The access rights desired for the process object.\n * \\param ObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new process.\n * \\param ParentProcess A handle to the parent process.\n * \\param InheritObjectTable If TRUE, the new process inherits the object table of the parent process.\n * \\param SectionHandle Optional. A handle to a section object to be used for the new process.\n * \\param DebugPort Optional. A handle to a debug port to be used for the new process.\n * \\param TokenHandle Optional. A handle to an access token to be used for the new process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ParentProcess,\n    _In_ BOOLEAN InheritObjectTable,\n    _In_opt_ HANDLE SectionHandle,\n    _In_opt_ HANDLE DebugPort,\n    _In_opt_ HANDLE TokenHandle\n    );\n\n// begin_rev\n#define PROCESS_CREATE_FLAGS_NONE 0x00000000\n#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001                               // NtCreateProcessEx & NtCreateUserProcess\n#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002                        // NtCreateProcessEx & NtCreateUserProcess\n#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004                         // NtCreateProcessEx & NtCreateUserProcess\n#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008                  // NtCreateProcessEx only\n#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010                             // NtCreateProcessEx only (requires SeLockMemoryPrivilege)\n#define PROCESS_CREATE_FLAGS_LARGE_PAGE_SYSTEM_DLL 0x00000020                   // NtCreateProcessEx only (requires SeLockMemoryPrivilege)\n#define PROCESS_CREATE_FLAGS_PROTECTED_PROCESS 0x00000040                       // NtCreateUserProcess only\n#define PROCESS_CREATE_FLAGS_CREATE_SESSION 0x00000080                          // NtCreateProcessEx & NtCreateUserProcess (requires SeLoadDriverPrivilege)\n#define PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT 0x00000100                     // NtCreateProcessEx & NtCreateUserProcess\n#define PROCESS_CREATE_FLAGS_CREATE_SUSPENDED 0x00000200                        // NtCreateProcessEx & NtCreateUserProcess\n#define PROCESS_CREATE_FLAGS_FORCE_BREAKAWAY 0x00000400                         // NtCreateProcessEx & NtCreateUserProcess (requires SeTcbPrivilege)\n#define PROCESS_CREATE_FLAGS_MINIMAL_PROCESS 0x00000800                         // NtCreateProcessEx only\n#define PROCESS_CREATE_FLAGS_RELEASE_SECTION 0x00001000                         // NtCreateProcessEx & NtCreateUserProcess\n#define PROCESS_CREATE_FLAGS_CLONE_MINIMAL 0x00002000                           // NtCreateProcessEx only\n#define PROCESS_CREATE_FLAGS_CLONE_MINIMAL_REDUCED_COMMIT 0x00004000\n#define PROCESS_CREATE_FLAGS_AUXILIARY_PROCESS 0x00008000                       // NtCreateProcessEx & NtCreateUserProcess (requires SeTcbPrivilege)\n#define PROCESS_CREATE_FLAGS_CREATE_STORE 0x00020000                            // NtCreateProcessEx & NtCreateUserProcess\n#define PROCESS_CREATE_FLAGS_USE_PROTECTED_ENVIRONMENT 0x00040000               // NtCreateProcessEx & NtCreateUserProcess\n#define PROCESS_CREATE_FLAGS_IMAGE_EXPANSION_MITIGATION_DISABLE 0x00080000\n#define PROCESS_CREATE_FLAGS_PARTITION_CREATE_SLAB_IDENTITY 0x00400000          // NtCreateProcessEx & NtCreateUserProcess (requires SeLockMemoryPrivilege)\n// end_rev\n\n/**\n * Creates a new process with extended options.\n *\n * \\param ProcessHandle A pointer to a handle that receives the process object handle.\n * \\param DesiredAccess The access rights desired for the process object.\n * \\param ObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new process.\n * \\param ParentProcess A handle to the parent process.\n * \\param Flags Flags that control the creation of the process. These flags are defined as PROCESS_CREATE_FLAGS_*.\n * \\param SectionHandle Optional. A handle to a section object to be used for the new process.\n * \\param DebugPort Optional. A handle to a debug port to be used for the new process.\n * \\param TokenHandle Optional. A handle to an access token to be used for the new process.\n * \\param Reserved Reserved for future use. Must be zero.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateProcessEx(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ParentProcess,\n    _In_ ULONG Flags, // PROCESS_CREATE_FLAGS_*\n    _In_opt_ HANDLE SectionHandle,\n    _In_opt_ HANDLE DebugPort,\n    _In_opt_ HANDLE TokenHandle,\n    _Reserved_ ULONG Reserved // JobMemberLevel\n    );\n\n/**\n * Opens an existing process object.\n *\n * \\param ProcessHandle A pointer to a handle that receives the process object handle.\n * \\param DesiredAccess The access rights desired for the process object.\n * \\param ObjectAttributes A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new process.\n * \\param ClientId Optional. A pointer to a CLIENT_ID structure that specifies the client ID of the process to be opened.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-ntopenprocess\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PCLIENT_ID ClientId\n    );\n\n/**\n * Terminates the specified process.\n *\n * \\param ProcessHandle Optional. A handle to the process to be terminated. If this parameter is NULL, the calling process is terminated.\n * \\param ExitStatus The exit status to be used by the process and the process's termination status.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-zwterminateprocess\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTerminateProcess(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\n/**\n * Suspends the specified process.\n *\n * \\param ProcessHandle A handle to the process to be suspended.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Use NtCreateProcessStateChange instead.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSuspendProcess(\n    _In_ HANDLE ProcessHandle\n    );\n\n/**\n * Resumes the specified process.\n *\n * \\param ProcessHandle A handle to the process to be resumed.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks Use NtCreateProcessStateChange instead.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtResumeProcess(\n    _In_ HANDLE ProcessHandle\n    );\n\n//\n// Macros\n//\n\n#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)\n#define ZwCurrentProcess() NtCurrentProcess()\n#define NtCurrentThread() ((HANDLE)(LONG_PTR)-2)\n#define ZwCurrentThread() NtCurrentThread()\n#define NtCurrentSession() ((HANDLE)(LONG_PTR)-3)\n#define ZwCurrentSession() NtCurrentSession()\n\n#define NtCurrentPeb() (NtCurrentTeb()->ProcessEnvironmentBlock)\n\n#define NtCurrentProcessId() (NtCurrentTeb()->ClientId.UniqueProcess)\n#define NtCurrentThreadId() (NtCurrentTeb()->ClientId.UniqueThread)\n\n// Windows 8 and above\n#define NtCurrentProcessToken() ((HANDLE)(LONG_PTR)-4) // NtOpenProcessToken(NtCurrentProcess())\n#define NtCurrentThreadToken() ((HANDLE)(LONG_PTR)-5) // NtOpenThreadToken(NtCurrentThread())\n#define NtCurrentThreadEffectiveToken() ((HANDLE)(LONG_PTR)-6) // NtOpenThreadToken(NtCurrentThread()) + NtOpenProcessToken(NtCurrentProcess())\n#define NtCurrentSilo() ((HANDLE)(LONG_PTR)-1)\n\nEXTERN_C IMAGE_DOS_HEADER __ImageBase;\n#define NtCurrentImageBase() ((PVOID)((PIMAGE_DOS_HEADER)&__ImageBase))\n\n#define NtCurrentSessionId() (RtlGetActiveConsoleId()) // USER_SHARED_DATA->ActiveConsoleId\n//#define NtCurrentLogonId() (NtCurrentPeb()->LogonId)\n\n/**\n * The NtQueryInformationProcess routine retrieves information about the specified process.\n *\n * \\param ProcessHandle A handle to the process.\n * \\param ProcessInformationClass The type of process information to be retrieved.\n * \\param ProcessInformation A pointer to a buffer that receives the process information.\n * \\param ProcessInformationLength The size of the buffer pointed to by the ProcessInformation parameter.\n * \\param ReturnLength An optional pointer to a variable that receives the size of the data returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// rev\n/**\n * The NtWow64QueryInformationProcess64 routine retrieves information about the specified process.\n *\n * \\param ProcessHandle A handle to the process.\n * \\param ProcessInformationClass The type of process information to be retrieved.\n * \\param ProcessInformation A pointer to a buffer that receives the process information.\n * \\param ProcessInformationLength The size of the buffer pointed to by the ProcessInformation parameter.\n * \\param ReturnLength An optional pointer to a variable that receives the size of the data returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nNtWow64QueryInformationProcess64(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n/**\n * The NtSetInformationProcess routine sets information for the specified process.\n *\n * \\param ProcessHandle A handle to the process.\n * \\param ProcessInformationClass The type of process information to be set.\n * \\param ProcessInformation A pointer to a buffer that contains the process information.\n * \\param ProcessInformationLength The size of the buffer pointed to by the ProcessInformation parameter.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength\n    );\n\n/**\n * The PROCESS_GET_NEXT_FLAGS_PREVIOUS_PROCESS flag retrieves the previous process in the system.\n *\n * When calling NtGetNextProcess, this flag can be specified in the Flags parameter to indicate\n * that the function should return the previous process in the system enumeration order,\n * rather than the next process. This can be useful for iterating through processes in reverse order.\n */\n#ifndef PROCESS_GET_NEXT_FLAGS_PREVIOUS_PROCESS\n#define PROCESS_GET_NEXT_FLAGS_PREVIOUS_PROCESS 0x00000001\n#endif\n\n/**\n * Retrieves a handle to the next process in the system.\n *\n * \\param ProcessHandle An optional handle to a process. If this parameter is NULL, the function retrieves the first process in the system.\n * \\param DesiredAccess The access rights desired for the new process handle.\n * \\param HandleAttributes The attributes for the new process handle.\n * \\param Flags Flags that modify the behavior of the function. This can be a combination of the following flags:\n * - \\ref PROCESS_GET_NEXT_FLAGS_PREVIOUS_PROCESS (0x00000001): Retrieve the previous process in the system.\n * \\param NewProcessHandle A pointer to a variable that receives the handle to the next process.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetNextProcess(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_ ULONG Flags,\n    _Out_ PHANDLE NewProcessHandle\n    );\n\n/**\n * Retrieves a handle to the next thread in the system.\n *\n * \\param ProcessHandle A handle to the process for enumeration of threads.\n * \\param ThreadHandle An optional handle to a thread. If this parameter is NULL, the function retrieves the first thread in the process.\n * \\param DesiredAccess The access rights desired for the new thread handle.\n * \\param HandleAttributes The attributes for the new thread handle.\n * \\param Flags Flags that modify the behavior of the function. Unused and should be zero.\n * \\param NewThreadHandle A pointer to a variable that receives the handle to the next thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetNextThread(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_opt_ _Reserved_ ULONG Flags,\n    _Out_ PHANDLE NewThreadHandle\n    );\n\n#endif // PHNT_MODE != PHNT_MODE_KERNEL\n\n#define STATECHANGE_SET_ATTRIBUTES 0x0001\n\ntypedef enum _PROCESS_STATE_CHANGE_TYPE\n{\n    ProcessStateChangeSuspend,\n    ProcessStateChangeResume,\n    ProcessStateChangeMax,\n} PROCESS_STATE_CHANGE_TYPE, *PPROCESS_STATE_CHANGE_TYPE;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\n/**\n * Creates a state change handle for changing the suspension state of a process.\n *\n * \\param ProcessStateChangeHandle A pointer to a variable that receives the handle.\n * \\param DesiredAccess The access rights desired for the handle.\n * \\param ObjectAttributes Optional attributes for the handle.\n * \\param ProcessHandle A handle to the process.\n * \\param Reserved Reserved for future use.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateProcessStateChange(\n    _Out_ PHANDLE ProcessStateChangeHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ _Reserved_ ULONG Reserved\n    );\n\n/**\n * Changes the suspension state of a process.\n *\n * \\param ProcessStateChangeHandle A handle to the process state change object.\n * \\param ProcessHandle A handle to the process.\n * \\param StateChangeType The type of state change.\n * \\param ExtendedInformation Optional extended information.\n * \\param ExtendedInformationLength The length of the extended information.\n * \\param Reserved Reserved for future use.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtChangeProcessState(\n    _In_ HANDLE ProcessStateChangeHandle,\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESS_STATE_CHANGE_TYPE StateChangeType,\n    _In_opt_ _Reserved_ PVOID ExtendedInformation,\n    _In_opt_ _Reserved_ SIZE_T ExtendedInformationLength,\n    _In_opt_ _Reserved_ ULONG Reserved\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_11\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\n/**\n * Creates a state change handle for changing the suspension state of a thread.\n *\n * \\param ThreadStateChangeHandle A pointer to a variable that receives the handle.\n * \\param DesiredAccess The access rights desired for the handle.\n * \\param ObjectAttributes Optional attributes for the handle.\n * \\param ThreadHandle A handle to the thread.\n * \\param Reserved Reserved for future use.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateThreadStateChange(\n    _Out_ PHANDLE ThreadStateChangeHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ _Reserved_ ULONG Reserved\n    );\n\ntypedef enum _THREAD_STATE_CHANGE_TYPE\n{\n    ThreadStateChangeSuspend,\n    ThreadStateChangeResume,\n    ThreadStateChangeMax,\n} THREAD_STATE_CHANGE_TYPE, *PTHREAD_STATE_CHANGE_TYPE;\n\n/**\n * Changes the suspension state of a thread.\n *\n * \\param ThreadStateChangeHandle A handle to the thread state change object.\n * \\param ThreadHandle A handle to the thread.\n * \\param StateChangeType The type of state change.\n * \\param ExtendedInformation Optional extended information.\n * \\param ExtendedInformationLength The length of the extended information.\n * \\param Reserved Reserved for future use.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtChangeThreadState(\n    _In_ HANDLE ThreadStateChangeHandle,\n    _In_ HANDLE ThreadHandle,\n    _In_ THREAD_STATE_CHANGE_TYPE StateChangeType,\n    _In_opt_ PVOID ExtendedInformation,\n    _In_opt_ SIZE_T ExtendedInformationLength,\n    _In_opt_ ULONG Reserved\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_11\n\n//\n// Threads\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n/**\n * Creates a new thread in the specified process.\n *\n * \\param ThreadHandle A pointer to a handle that receives the thread object handle.\n * \\param DesiredAccess The access rights desired for the thread object.\n * \\param ObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new thread.\n * \\param ProcessHandle A handle to the process in which the thread is to be created.\n * \\param ClientId A pointer to a CLIENT_ID structure that receives the client ID of the new thread.\n * \\param ThreadContext A pointer to a CONTEXT structure that specifies the initial context of the new thread.\n * \\param InitialTeb A pointer to an INITIAL_TEB structure that specifies the initial stack limits of the new thread.\n * \\param CreateSuspended If TRUE, the thread is created in a suspended state.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PCLIENT_ID ClientId,\n    _In_ PCONTEXT ThreadContext,\n    _In_ PINITIAL_TEB InitialTeb,\n    _In_ BOOLEAN CreateSuspended\n    );\n\n/**\n * Opens an existing thread object.\n *\n * \\param ThreadHandle A pointer to a handle that receives the thread object handle.\n * \\param DesiredAccess The access rights desired for the thread object.\n * \\param ObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new thread.\n * \\param ClientId Optional. A pointer to a CLIENT_ID structure that specifies the client ID of the thread to be opened.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PCLIENT_ID ClientId\n    );\n\n/**\n * Terminates the specified thread.\n *\n * \\param ThreadHandle Optional. A handle to the thread to be terminated. If this parameter is NULL, the calling thread is terminated.\n * \\param ExitStatus The exit status to be used by the thread and the thread's termination status.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTerminateThread(\n    _In_opt_ HANDLE ThreadHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\n/**\n * Suspends the specified thread.\n *\n * \\param ThreadHandle A handle to the thread to be suspended.\n * \\param PreviousSuspendCount Optional. A pointer to a variable that receives the thread's previous suspend count.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSuspendThread(\n    _In_ HANDLE ThreadHandle,\n    _Out_opt_ PULONG PreviousSuspendCount\n    );\n\n/**\n * Resumes the specified thread.\n *\n * \\param ThreadHandle A handle to the thread to be resumed.\n * \\param PreviousSuspendCount Optional. A pointer to a variable that receives the thread's previous suspend count.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtResumeThread(\n    _In_ HANDLE ThreadHandle,\n    _Out_opt_ PULONG PreviousSuspendCount\n    );\n\n/**\n * Retrieves the number of the current processor.\n *\n * \\return ULONG The number of the current processor.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/procthread/ntgetcurrentprocessornumber\n */\nNTSYSCALLAPI\nULONG\nNTAPI\nNtGetCurrentProcessorNumber(\n    VOID\n    );\n\n/**\n * Retrieves the number of the current processor.\n *\n * \\param ProcessorNumber An optional pointer to a PROCESSOR_NUMBER structure that receives the processor number.\n * \\return ULONG The number of the current processor.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-kegetcurrentprocessornumberex\n */\nNTSYSCALLAPI\nULONG\nNTAPI\nNtGetCurrentProcessorNumberEx(\n    _Out_opt_ PPROCESSOR_NUMBER ProcessorNumber\n    );\n\n/**\n * Retrieves the context of the specified thread.\n *\n * \\param ThreadHandle A handle to the thread.\n * \\param ThreadContext A pointer to a CONTEXT structure that receives the thread context.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetContextThread(\n    _In_ HANDLE ThreadHandle,\n    _Inout_ PCONTEXT ThreadContext\n    );\n\n/**\n * Sets the context of the specified thread.\n *\n * \\param ThreadHandle A handle to the thread.\n * \\param ThreadContext A pointer to a CONTEXT structure that specifies the thread context.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetContextThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ PCONTEXT ThreadContext\n    );\n\n/**\n * Retrieves information about the specified thread.\n *\n * \\param ThreadHandle A handle to the thread.\n * \\param ThreadInformationClass The type of thread information to be retrieved.\n * \\param ThreadInformation A pointer to a buffer that receives the thread information.\n * \\param ThreadInformationLength The size of the buffer pointed to by the ThreadInformation parameter.\n * \\param ReturnLength An optional pointer to a variable that receives the size of the data returned.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ THREADINFOCLASS ThreadInformationClass,\n    _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n/**\n * Sets information for the specified thread.\n *\n * \\param ThreadHandle A handle to the thread.\n * \\param ThreadInformationClass The type of thread information to be set.\n * \\param ThreadInformation A pointer to a buffer that contains the thread information.\n * \\param ThreadInformationLength The size of the buffer pointed to by the ThreadInformation parameter.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ THREADINFOCLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength\n    );\n\n/**\n * The NtAlertThread routine alerts the specified thread.\n *\n * \\param[in] ThreadHandle A handle to the thread to be alerted.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlertThread(\n    _In_ HANDLE ThreadHandle\n    );\n\n/**\n * The NtAlertResumeThread routine resumes a specified thread that was previously suspended and alerts the thread.\n *\n * \\param[in] ThreadHandle A handle to the thread to be resumed and alerted.\n * \\param[out, optional] PreviousSuspendCount An optional pointer to a variable that receives the thread's previous suspend count.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlertResumeThread(\n    _In_ HANDLE ThreadHandle,\n    _Out_opt_ PULONG PreviousSuspendCount\n    );\n\n/**\n * The NtTestAlert routine indicates whether the current thread has an alert pending\n * and executes asynchronous procedure calls (APCs) queued to the current thread.\n *\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTestAlert(\n    VOID\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n// rev\n/**\n * The NtAlertThreadByThreadId routine sends an alert to the specified thread.\n *\n * \\param ThreadId The thread ID of the thread to be alerted.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlertThreadByThreadId(\n    _In_ HANDLE ThreadId\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_8\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\n/**\n * The NtAlertThreadByThreadIdEx routine sends an alert to the specified thread by its thread ID, with an optional lock.\n *\n * \\param ThreadId The thread ID of the thread to be alerted.\n * \\param Lock An optional pointer to an SRW lock to be used during the alert.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlertThreadByThreadIdEx(\n    _In_ HANDLE ThreadId,\n    _In_opt_ PRTL_SRWLOCK Lock\n    );\n\n/**\n * Identifies the interpretation of a PS_ALERT_THREAD_EXTENDED_PARAMETER record.\n *\n * The current kernel implementation for NtAlertMultipleThreadByThreadId accepts only\n * PsAlertMultipleExtendedParameterAutoBoostContext (0). Other values are rejected with\n * STATUS_INVALID_PARAMETER.\n */\ntypedef enum _PS_ALERT_THREAD_EXTENDED_PARAMETER_TYPE\n{\n    /**\n     * AutoBoost context token passed into the kernel's AutoBoost (Ab) bookkeeping.\n     *\n     * The payload (ULong64/Pointer/etc.) is forwarded to internal routines and may be used to\n     * associate the wakeup with a particular synchronization/ownership handoff context.\n     */\n    PsAlertMultipleExtendedParameterAutoBoostContext = 0,\n    /**\n     * Sentinel / upper bound (not a usable type).\n     */\n    PsAlertMultipleExtendedParameterMax = 1,\n} PS_ALERT_THREAD_EXTENDED_PARAMETER_TYPE, *PPS_ALERT_THREAD_EXTENDED_PARAMETER_TYPE;\n\n/**\n * Extended parameter record for NtAlertMultipleThreadByThreadId.\n *\n * In the analyzed NtAlertMultipleThreadByThreadId implementation:\n * - Type must be 0 (PsAlertMultipleExtendedParameterAutoBoostContext).\n * - The union payload at offset +0x8 is forwarded as an opaque 64-bit context value.\n */\ntypedef struct _PS_ALERT_THREAD_EXTENDED_PARAMETER\n{\n    /**\n     * Parameter type (8-bit)\n     */\n    ULONGLONG Type : 8;\n    /**\n     * Reserved bits; should be zero.\n     */\n    ULONGLONG Reserved : 56;\n    /**\n     * Payload value whose meaning depends on Type.\n     *\n     * For Type == PsAlertMultipleExtendedParameterAutoBoostContext, this is treated as an\n     * opaque \"AutoBoostContext\" token. It may be pointer-like and may use low-bit tagging.\n     */\n    union\n    {\n        ULONGLONG ULong64;\n        PVOID Pointer;\n        SIZE_T Size;\n        HANDLE Handle;\n        ULONG ULong;\n        UCHAR Boolean;\n    };\n} PS_ALERT_THREAD_EXTENDED_PARAMETER, *PPS_ALERT_THREAD_EXTENDED_PARAMETER;\n\n/**\n * The NtAlertMultipleThreadByThreadId routine alerts each target thread specified by thread ID.\n * Target threads must belong to the caller's current process (cross-process targets fail STATUS_ACCESS_DENIED).\n *\n * \\param MultipleThreadId A pointer to an array of thread IDs to be alerted.\n * \\param Count The number of thread IDs in the array.\n * \\param ExtendedParameters An optional pointer to one or more extended parameters of type PS_ALERT_THREAD_EXTENDED_PARAMETER.\n * \\param ExtendedParameterCount Specifies the number of elements in the ExtendedParameters array.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks STATUS_ACCESS_DENIED may be returned when the thread belongs to another process.\n * \\note\n * - Only PS_ALERT_THREAD_EXTENDED_PARAMETER.Type == 0 is currently accepted.\n * - If multiple extended parameters are provided, the implementation consumes them in order and\n *   the *last* parameter's payload is the one forwarded to the internal alert logic.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlertMultipleThreadByThreadId(\n    _In_ PHANDLE MultipleThreadId,\n    _In_ ULONG Count,\n    _Inout_updates_opt_(ExtendedParameterCount) PPS_ALERT_THREAD_EXTENDED_PARAMETER ExtendedParameters,\n    _In_ ULONG ExtendedParameterCount\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_11\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n// rev\n/**\n * The NtWaitForAlertByThreadId routine blocks the calling thread until another thread calls NtAlertThreadByThreadId\n * with a matching address, or until the timeout expires.\n *\n * \\param Address A unique address used to identify this wait operation. Other threads call\n *                NtAlertThreadByThreadId with this same address to wake the waiting thread.\n *                Can be NULL to wait on the thread ID itself.\n * \\param Timeout Optional timeout value. If NULL, waits indefinitely. If present, specifies\n *                the absolute or relative time to wait before returning STATUS_TIMEOUT.\n * \\return STATUS_SUCCESS if alerted successfully.\n * \\return STATUS_TIMEOUT if the timeout expired before being alerted.\n * \\return STATUS_ALERTED if woken by NtAlertThreadByThreadId.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForAlertByThreadId(\n    _In_opt_ PVOID Address,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n#endif // PHNT_VERSION >= PHNT_WINDOWS_8\n\n/**\n * Impersonates a client thread.\n *\n * \\param ServerThreadHandle A handle to the server thread.\n * \\param ClientThreadHandle A handle to the client thread.\n * \\param SecurityQos A pointer to a SECURITY_QUALITY_OF_SERVICE structure that specifies the impersonation level and context tracking mode.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtImpersonateThread(\n    _In_ HANDLE ServerThreadHandle,\n    _In_ HANDLE ClientThreadHandle,\n    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos\n    );\n\n/**\n * Registers a thread termination port.\n *\n * \\param PortHandle A handle to the port to be registered.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRegisterThreadTerminatePort(\n    _In_ HANDLE PortHandle\n    );\n\n/**\n * Sets LDT (Local Descriptor Table) entries.\n *\n * \\param Selector0 The first selector.\n * \\param Entry0Low The low part of the first entry.\n * \\param Entry0Hi The high part of the first entry.\n * \\param Selector1 The second selector.\n * \\param Entry1Low The low part of the second entry.\n * \\param Entry1Hi The high part of the second entry.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetLdtEntries(\n    _In_ ULONG Selector0,\n    _In_ ULONG Entry0Low,\n    _In_ ULONG Entry0Hi,\n    _In_ ULONG Selector1,\n    _In_ ULONG Entry1Low,\n    _In_ ULONG Entry1Hi\n    );\n\n/**\n * Dispatches the Asynchronous Procedure Call (APC) from the NtQueueApc* functions to the specified routine.\n *\n * \\param ApcRoutine A pointer to the APC routine to be executed.\n * \\param Parameter Optional. A pointer to a parameter to be passed to the APC routine.\n * \\param ActxContext Optional. A handle to an activation context.\n */\nNTSYSAPI\nVOID\nNTAPI\nRtlDispatchAPC(\n    _In_ PAPCFUNC ApcRoutine,\n    _In_opt_ PVOID Parameter,\n    _In_opt_ HANDLE ActxContext\n    );\n\n/**\n * A pointer to a function that serves as an APC routine.\n *\n * \\param ApcArgument1 Optional. A pointer to the first argument to be passed to the APC routine.\n * \\param ApcArgument2 Optional. A pointer to the second argument to be passed to the APC routine.\n * \\param ApcArgument3 Optional. A pointer to the third argument to be passed to the APC routine.\n */\ntypedef _Function_class_(PS_APC_ROUTINE)\nVOID NTAPI PS_APC_ROUTINE(\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\ntypedef PS_APC_ROUTINE* PPS_APC_ROUTINE;\n\n/**\n * Encodes an APC routine pointer for use in a WOW64 environment.\n *\n * \\param ApcRoutine The APC routine pointer to be encoded.\n * \\return PVOID The encoded APC routine pointer.\n */\n#define Wow64EncodeApcRoutine(ApcRoutine) \\\n    ((PVOID)((0 - ((LONG_PTR)(ApcRoutine))) << 2))\n\n/**\n * Decodes an APC routine pointer that was encoded for use in a WOW64 environment.\n *\n * \\param ApcRoutine The encoded APC routine pointer to be decoded.\n * \\return PVOID The decoded APC routine pointer.\n */\n#define Wow64DecodeApcRoutine(ApcRoutine) \\\n    ((PVOID)(0 - (((LONG_PTR)(ApcRoutine)) >> 2)))\n\n/**\n * Queues an APC (Asynchronous Procedure Call) to a thread.\n *\n * \\param ThreadHandle Handle to the thread to which the APC is to be queued.\n * \\param ApcRoutine A pointer to the RtlDispatchAPC function or custom APC routine to be executed.\n * \\param ApcArgument1 Optional first argument to be passed to the APC routine.\n * \\param ApcArgument2 Optional second argument to be passed to the APC routine.\n * \\param ApcArgument3 Optional third argument to be passed to the APC routine.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The APC will be executed in the context of the specified thread when the thread enters an alertable wait state or when any\n * process calls the NtTestAlert, NtAlertThread, NtAlertResumeThread or NtAlertThreadByThreadId functions.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueueApcThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ PPS_APC_ROUTINE ApcRoutine, // RtlDispatchAPC\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\n\n/**\n * A special handle value used to queue a user APC (Asynchronous Procedure Call).\n */\n#define QUEUE_USER_APC_SPECIAL_USER_APC ((HANDLE)0x1)\n\n/**\n * Queues an APC (Asynchronous Procedure Call) to a thread.\n *\n * \\param ThreadHandle Handle to the thread to which the APC is to be queued.\n * \\param ReserveHandle Optional handle to a reserve object. This can be QUEUE_USER_APC_SPECIAL_USER_APC or a handle returned by NtAllocateReserveObject.\n * \\param ApcRoutine A pointer to the RtlDispatchAPC function or custom APC routine to be executed.\n * \\param ApcArgument1 Optional first argument to be passed to the APC routine.\n * \\param ApcArgument2 Optional second argument to be passed to the APC routine.\n * \\param ApcArgument3 Optional third argument to be passed to the APC routine.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The APC will be executed in the context of the specified thread after the thread enters an alertable wait state or immediately\n * when QUEUE_USER_APC_SPECIAL_USER_APC is used or NtTestAlert, NtAlertThread, NtAlertResumeThread or NtAlertThreadByThreadId are called.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueueApcThreadEx(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE ReserveHandle, // NtAllocateReserveObject // QUEUE_USER_APC_SPECIAL_USER_APC\n    _In_ PPS_APC_ROUTINE ApcRoutine, // RtlDispatchAPC\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\n\n/**\n * The APC_CALLBACK_DATA_CONTEXT structure is used to pass information to the APC callback routine.\n */\ntypedef struct _APC_CALLBACK_DATA_CONTEXT\n{\n    ULONG_PTR Parameter;\n    PCONTEXT ContextRecord;\n    ULONG_PTR Reserved0;\n    ULONG_PTR Reserved1;\n} APC_CALLBACK_DATA_CONTEXT, *PAPC_CALLBACK_DATA_CONTEXT;\n\n#define QUEUE_USER_APC_FLAGS_NONE 0x00000000\n#define QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC 0x00000001\n#define QUEUE_USER_APC_FLAGS_CALLBACK_DATA_CONTEXT 0x00010000 // APC_CALLBACK_DATA_CONTEXT\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\n/**\n * Queues an Asynchronous Procedure Call (APC) to a specified thread.\n *\n * \\param ThreadHandle A handle to the thread to which the APC is to be queued.\n * \\param ReserveHandle An optional handle to a reserve object. This can be obtained using NtAllocateReserveObject.\n * \\param ApcFlags Flags that control the behavior of the APC. These flags are defined in QUEUE_USER_APC_FLAGS.\n * \\param ApcRoutine A pointer to the RtlDispatchAPC function or custom APC routine to be executed.\n * \\param ApcArgument1 An optional argument to be passed to the APC routine.\n * \\param ApcArgument2 An optional argument to be passed to the APC routine.\n * \\param ApcArgument3 An optional argument to be passed to the APC routine.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks The APC will be executed in the context of the specified thread when the thread enters an alertable wait state or immediately\n * when QUEUE_USER_APC_SPECIAL_USER_APC is used or any process calls the NtTestAlert, NtAlertThread,\n * NtAlertResumeThread or NtAlertThreadByThreadId functions.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueueApcThreadEx2(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE ReserveHandle, // NtAllocateReserveObject\n    _In_ ULONG ApcFlags, // QUEUE_USER_APC_FLAGS\n    _In_ PPS_APC_ROUTINE ApcRoutine, // RtlDispatchAPC\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\n\n#endif // PHNT_VERSION >= PHNT_WINDOWS_11\n\n#endif // PHNT_MODE != PHNT_MODE_KERNEL\n\n//\n// User processes and threads\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// Attributes (Win32 CreateProcess)\n\n// PROC_THREAD_ATTRIBUTE_NUM (dmex)\n#define ProcThreadAttributeParentProcess 0                      // in HANDLE\n#define ProcThreadAttributeExtendedFlags 1                      // in ULONG (EXTENDED_PROCESS_CREATION_FLAG_*)\n#define ProcThreadAttributeHandleList 2                         // in HANDLE[]\n#define ProcThreadAttributeGroupAffinity 3                      // in GROUP_AFFINITY // since WIN7\n#define ProcThreadAttributePreferredNode 4                      // in USHORT\n#define ProcThreadAttributeIdealProcessor 5                     // in PROCESSOR_NUMBER\n#define ProcThreadAttributeUmsThread 6                          // in UMS_CREATE_THREAD_ATTRIBUTES\n#define ProcThreadAttributeMitigationPolicy 7                   // in ULONG, ULONG64, or ULONG64[2]\n#define ProcThreadAttributePackageFullName 8                    // in WCHAR[] // since WIN8\n#define ProcThreadAttributeSecurityCapabilities 9               // in SECURITY_CAPABILITIES\n#define ProcThreadAttributeConsoleReference 10                  // BaseGetConsoleReference (kernelbase.dll)\n#define ProcThreadAttributeProtectionLevel 11                   // in ULONG (PROTECTION_LEVEL_*) // since WINBLUE\n#define ProcThreadAttributeOsMaxVersionTested 12                // in MAXVERSIONTESTED_INFO // since THRESHOLD // (from exe.manifest)\n#define ProcThreadAttributeJobList 13                           // in HANDLE[]\n#define ProcThreadAttributeChildProcessPolicy 14                // in ULONG (PROCESS_CREATION_CHILD_PROCESS_*) // since THRESHOLD2\n#define ProcThreadAttributeAllApplicationPackagesPolicy 15      // in ULONG (PROCESS_CREATION_ALL_APPLICATION_PACKAGES_*) // since REDSTONE\n#define ProcThreadAttributeWin32kFilter 16                      // in WIN32K_SYSCALL_FILTER\n#define ProcThreadAttributeSafeOpenPromptOriginClaim 17         // in SE_SAFE_OPEN_PROMPT_RESULTS\n#define ProcThreadAttributeDesktopAppPolicy 18                  // in ULONG (PROCESS_CREATION_DESKTOP_APP_*) // since RS2\n#define ProcThreadAttributeBnoIsolation 19                      // in PROC_THREAD_BNOISOLATION_ATTRIBUTE\n#define ProcThreadAttributePseudoConsole 22                     // in HANDLE (HPCON) // since RS5\n#define ProcThreadAttributeIsolationManifest 23                 // in ISOLATION_MANIFEST_PROPERTIES // rev (diversenok) // since 19H2+\n#define ProcThreadAttributeMitigationAuditPolicy 24             // in ULONG, ULONG64, or ULONG64[2] // since 21H1\n#define ProcThreadAttributeMachineType 25                       // in USHORT // since 21H2\n#define ProcThreadAttributeComponentFilter 26                   // in ULONG\n#define ProcThreadAttributeEnableOptionalXStateFeatures 27      // in ULONG64 // since WIN11\n#define ProcThreadAttributeCreateStore 28                       // ULONG // rev (diversenok)\n#define ProcThreadAttributeTrustedApp 29\n#define ProcThreadAttributeSveVectorLength 30\n#define ProcThreadAttributeSmeVectorLength 31                   // since 25H2\n\n#ifndef PROC_THREAD_ATTRIBUTE_EXTENDED_FLAGS\n#define PROC_THREAD_ATTRIBUTE_EXTENDED_FLAGS \\\n    ProcThreadAttributeValue(ProcThreadAttributeExtendedFlags, FALSE, TRUE, TRUE)\n#endif\n#ifndef PROC_THREAD_ATTRIBUTE_PACKAGE_FULL_NAME\n#define PROC_THREAD_ATTRIBUTE_PACKAGE_FULL_NAME \\\n    ProcThreadAttributeValue(ProcThreadAttributePackageFullName, FALSE, TRUE, FALSE)\n#endif\n#ifndef PROC_THREAD_ATTRIBUTE_CONSOLE_REFERENCE\n#define PROC_THREAD_ATTRIBUTE_CONSOLE_REFERENCE \\\n    ProcThreadAttributeValue(ProcThreadAttributeConsoleReference, FALSE, TRUE, FALSE)\n#endif\n#ifndef PROC_THREAD_ATTRIBUTE_OSMAXVERSIONTESTED\n#define PROC_THREAD_ATTRIBUTE_OSMAXVERSIONTESTED \\\n    ProcThreadAttributeValue(ProcThreadAttributeOsMaxVersionTested, FALSE, TRUE, FALSE)\n#endif\n#ifndef PROC_THREAD_ATTRIBUTE_SAFE_OPEN_PROMPT_ORIGIN_CLAIM\n#define PROC_THREAD_ATTRIBUTE_SAFE_OPEN_PROMPT_ORIGIN_CLAIM \\\n    ProcThreadAttributeValue(ProcThreadAttributeSafeOpenPromptOriginClaim, FALSE, TRUE, FALSE)\n#endif\n#ifndef PROC_THREAD_ATTRIBUTE_BNO_ISOLATION\n#define PROC_THREAD_ATTRIBUTE_BNO_ISOLATION \\\n    ProcThreadAttributeValue(ProcThreadAttributeBnoIsolation, FALSE, TRUE, FALSE)\n#endif\n#ifndef PROC_THREAD_ATTRIBUTE_ISOLATION_MANIFEST\n#define PROC_THREAD_ATTRIBUTE_ISOLATION_MANIFEST \\\n    ProcThreadAttributeValue(ProcThreadAttributeIsolationManifest, FALSE, TRUE, FALSE)\n#endif\n#ifndef PROC_THREAD_ATTRIBUTE_CREATE_STORE\n#define PROC_THREAD_ATTRIBUTE_CREATE_STORE \\\n    ProcThreadAttributeValue(ProcThreadAttributeCreateStore, FALSE, TRUE, FALSE)\n#endif\n#ifndef PROC_THREAD_ATTRIBUTE_TRUSTED_APP\n#define PROC_THREAD_ATTRIBUTE_TRUSTED_APP \\\n    ProcThreadAttributeValue(ProcThreadAttributeTrustedApp, FALSE, TRUE, FALSE)\n#endif\n\n// private\ntypedef struct _PROC_THREAD_ATTRIBUTE\n{\n    ULONG_PTR Attribute;\n    SIZE_T Size;\n    ULONG_PTR Value;\n} PROC_THREAD_ATTRIBUTE, *PPROC_THREAD_ATTRIBUTE;\n\n/**\n * The PROC_THREAD_ATTRIBUTE_LIST structure contains the list of attributes for process and thread creation.\n */\ntypedef struct _PROC_THREAD_ATTRIBUTE_LIST\n{\n    ULONG PresentFlags;             // A bitmask of flags that indicate the attributes for process and thread creation.\n    ULONG AttributeCount;           // The number of attributes in the list.\n    ULONG LastAttribute;            // The index of the last attribute in the list.\n    ULONG SpareUlong0;              // Reserved for future use.\n    PPROC_THREAD_ATTRIBUTE ExtendedFlagsAttribute; // A pointer to the extended flags attribute.\n    _Field_size_(AttributeCount) PROC_THREAD_ATTRIBUTE Attributes[1]; // An array of attributes.\n} PROC_THREAD_ATTRIBUTE_LIST, *PPROC_THREAD_ATTRIBUTE_LIST;\n\n// private\n#define EXTENDED_PROCESS_CREATION_FLAG_ELEVATION_HANDLED 0x00000001\n#define EXTENDED_PROCESS_CREATION_FLAG_FORCELUA 0x00000002\n#define EXTENDED_PROCESS_CREATION_FLAG_FORCE_BREAKAWAY 0x00000004 // requires SeTcbPrivilege // since WINBLUE\n\n#define PROTECTION_LEVEL_WINTCB_LIGHT       0x00000000\n#define PROTECTION_LEVEL_WINDOWS            0x00000001\n#define PROTECTION_LEVEL_WINDOWS_LIGHT      0x00000002\n#define PROTECTION_LEVEL_ANTIMALWARE_LIGHT  0x00000003\n#define PROTECTION_LEVEL_LSA_LIGHT          0x00000004\n#define PROTECTION_LEVEL_WINTCB             0x00000005\n#define PROTECTION_LEVEL_CODEGEN_LIGHT      0x00000006\n#define PROTECTION_LEVEL_AUTHENTICODE       0x00000007\n#define PROTECTION_LEVEL_PPL_APP            0x00000008\n\n#define PROTECTION_LEVEL_SAME               0xFFFFFFFF\n#define PROTECTION_LEVEL_NONE               0xFFFFFFFE\n\n// private\ntypedef enum _SE_SAFE_OPEN_PROMPT_EXPERIENCE_RESULTS\n{\n    SeSafeOpenExperienceNone = 0x00,\n    SeSafeOpenExperienceCalled = 0x01,\n    SeSafeOpenExperienceAppRepCalled = 0x02,\n    SeSafeOpenExperiencePromptDisplayed = 0x04,\n    SeSafeOpenExperienceUAC = 0x08,\n    SeSafeOpenExperienceUninstaller = 0x10,\n    SeSafeOpenExperienceIgnoreUnknownOrBad = 0x20,\n    SeSafeOpenExperienceDefenderTrustedInstaller = 0x40,\n    SeSafeOpenExperienceMOTWPresent = 0x80,\n    SeSafeOpenExperienceElevatedNoPropagation = 0x100\n} SE_SAFE_OPEN_PROMPT_EXPERIENCE_RESULTS;\n\n// private\ntypedef struct _SE_SAFE_OPEN_PROMPT_RESULTS\n{\n    SE_SAFE_OPEN_PROMPT_EXPERIENCE_RESULTS Results;\n    WCHAR Path[MAX_PATH];\n} SE_SAFE_OPEN_PROMPT_RESULTS, *PSE_SAFE_OPEN_PROMPT_RESULTS;\n\ntypedef struct _PROC_THREAD_BNOISOLATION_ATTRIBUTE\n{\n    BOOL IsolationEnabled;\n    WCHAR IsolationPrefix[0x88];\n} PROC_THREAD_BNOISOLATION_ATTRIBUTE, *PPROC_THREAD_BNOISOLATION_ATTRIBUTE;\n\n// private\ntypedef struct _ISOLATION_MANIFEST_PROPERTIES\n{\n    UNICODE_STRING InstancePath;\n    UNICODE_STRING FriendlyName;\n    UNICODE_STRING Description;\n    ULONG_PTR Level;\n} ISOLATION_MANIFEST_PROPERTIES, *PISOLATION_MANIFEST_PROPERTIES;\n\n//\n// Attributes (Native)\n//\n\n// private\ntypedef enum _PS_ATTRIBUTE_NUM\n{\n    PsAttributeParentProcess, // in HANDLE\n    PsAttributeDebugObject, // in HANDLE\n    PsAttributeToken, // in HANDLE\n    PsAttributeClientId, // out PCLIENT_ID\n    PsAttributeTebAddress, // out PTEB *\n    PsAttributeImageName, // in PWSTR\n    PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION\n    PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE\n    PsAttributePriorityClass, // in UCHAR\n    PsAttributeErrorMode, // in ULONG\n    PsAttributeStdHandleInfo, // in PPS_STD_HANDLE_INFO // 10\n    PsAttributeHandleList, // in HANDLE[]\n    PsAttributeGroupAffinity, // in PGROUP_AFFINITY\n    PsAttributePreferredNode, // in PUSHORT\n    PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER\n    PsAttributeUmsThread, // in PUMS_CREATE_THREAD_ATTRIBUTES\n    PsAttributeMitigationOptions, // in PPS_MITIGATION_OPTIONS_MAP (PROCESS_CREATION_MITIGATION_POLICY_*) // since WIN8\n    PsAttributeProtectionLevel, // in PS_PROTECTION // since WINBLUE\n    PsAttributeSecureProcess, // in PPS_TRUSTLET_CREATE_ATTRIBUTES, since THRESHOLD\n    PsAttributeJobList, // in HANDLE[]\n    PsAttributeChildProcessPolicy, // in PULONG (PROCESS_CREATION_CHILD_PROCESS_*) // since THRESHOLD2 // 20\n    PsAttributeAllApplicationPackagesPolicy, // in PULONG (PROCESS_CREATION_ALL_APPLICATION_PACKAGES_*) // since REDSTONE\n    PsAttributeWin32kFilter, // in PWIN32K_SYSCALL_FILTER\n    PsAttributeSafeOpenPromptOriginClaim, // in SE_SAFE_OPEN_PROMPT_RESULTS\n    PsAttributeBnoIsolation, // in PPS_BNO_ISOLATION_PARAMETERS // since REDSTONE2\n    PsAttributeDesktopAppPolicy, // in PULONG (PROCESS_CREATION_DESKTOP_APP_*)\n    PsAttributeChpe, // in BOOLEAN // since REDSTONE3\n    PsAttributeMitigationAuditOptions, // in PPS_MITIGATION_AUDIT_OPTIONS_MAP (PROCESS_CREATION_MITIGATION_AUDIT_POLICY_*) // since 21H1\n    PsAttributeMachineType, // in USHORT // since 21H2\n    PsAttributeComponentFilter, // in COMPONENT_FILTER\n    PsAttributeEnableOptionalXStateFeatures, // in ULONG64 // since WIN11 // 30\n    PsAttributeSupportedMachines, // in ULONG // since 24H2\n    PsAttributeSveVectorLength, // PPS_PROCESS_CREATION_SVE_VECTOR_LENGTH\n    PsAttributeMax\n} PS_ATTRIBUTE_NUM;\n\n// private\n#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff\n#define PS_ATTRIBUTE_THREAD 0x00010000 // may be used with thread creation\n#define PS_ATTRIBUTE_INPUT 0x00020000 // input only\n#define PS_ATTRIBUTE_ADDITIVE 0x00040000 // \"accumulated\" e.g. bitmasks, counters, etc.\n\n// begin_rev\n\n#define PsAttributeValue(Number, Thread, Input, Additive) \\\n    (((Number) & PS_ATTRIBUTE_NUMBER_MASK) | \\\n    ((Thread) ? PS_ATTRIBUTE_THREAD : 0) | \\\n    ((Input) ? PS_ATTRIBUTE_INPUT : 0) | \\\n    ((Additive) ? PS_ATTRIBUTE_ADDITIVE : 0))\n\n#define PS_ATTRIBUTE_PARENT_PROCESS \\\n    PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_DEBUG_OBJECT \\\n    PsAttributeValue(PsAttributeDebugObject, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_TOKEN \\\n    PsAttributeValue(PsAttributeToken, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_CLIENT_ID \\\n    PsAttributeValue(PsAttributeClientId, TRUE, FALSE, FALSE)\n#define PS_ATTRIBUTE_TEB_ADDRESS \\\n    PsAttributeValue(PsAttributeTebAddress, TRUE, FALSE, FALSE)\n#define PS_ATTRIBUTE_IMAGE_NAME \\\n    PsAttributeValue(PsAttributeImageName, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_IMAGE_INFO \\\n    PsAttributeValue(PsAttributeImageInfo, FALSE, FALSE, FALSE)\n#define PS_ATTRIBUTE_MEMORY_RESERVE \\\n    PsAttributeValue(PsAttributeMemoryReserve, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_PRIORITY_CLASS \\\n    PsAttributeValue(PsAttributePriorityClass, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_ERROR_MODE \\\n    PsAttributeValue(PsAttributeErrorMode, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_STD_HANDLE_INFO \\\n    PsAttributeValue(PsAttributeStdHandleInfo, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_HANDLE_LIST \\\n    PsAttributeValue(PsAttributeHandleList, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_GROUP_AFFINITY \\\n    PsAttributeValue(PsAttributeGroupAffinity, TRUE, TRUE, FALSE)\n#define PS_ATTRIBUTE_PREFERRED_NODE \\\n    PsAttributeValue(PsAttributePreferredNode, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_IDEAL_PROCESSOR \\\n    PsAttributeValue(PsAttributeIdealProcessor, TRUE, TRUE, FALSE)\n#define PS_ATTRIBUTE_UMS_THREAD \\\n    PsAttributeValue(PsAttributeUmsThread, TRUE, TRUE, FALSE)\n#define PS_ATTRIBUTE_MITIGATION_OPTIONS \\\n    PsAttributeValue(PsAttributeMitigationOptions, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_PROTECTION_LEVEL \\\n    PsAttributeValue(PsAttributeProtectionLevel, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_SECURE_PROCESS \\\n    PsAttributeValue(PsAttributeSecureProcess, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_JOB_LIST \\\n    PsAttributeValue(PsAttributeJobList, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_CHILD_PROCESS_POLICY \\\n    PsAttributeValue(PsAttributeChildProcessPolicy, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY \\\n    PsAttributeValue(PsAttributeAllApplicationPackagesPolicy, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_WIN32K_FILTER \\\n    PsAttributeValue(PsAttributeWin32kFilter, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_SAFE_OPEN_PROMPT_ORIGIN_CLAIM \\\n    PsAttributeValue(PsAttributeSafeOpenPromptOriginClaim, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_BNO_ISOLATION \\\n    PsAttributeValue(PsAttributeBnoIsolation, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_DESKTOP_APP_POLICY \\\n    PsAttributeValue(PsAttributeDesktopAppPolicy, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_CHPE \\\n    PsAttributeValue(PsAttributeChpe, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_MITIGATION_AUDIT_OPTIONS \\\n    PsAttributeValue(PsAttributeMitigationAuditOptions, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_MACHINE_TYPE \\\n    PsAttributeValue(PsAttributeMachineType, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_COMPONENT_FILTER \\\n    PsAttributeValue(PsAttributeComponentFilter, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_ENABLE_OPTIONAL_XSTATE_FEATURES \\\n    PsAttributeValue(PsAttributeEnableOptionalXStateFeatures, TRUE, TRUE, FALSE)\n\n// end_rev\n\n// begin_private\n\ntypedef struct _PS_ATTRIBUTE\n{\n    ULONG_PTR Attribute;\n    SIZE_T Size;\n    union\n    {\n        ULONG_PTR Value;\n        PVOID ValuePtr;\n    };\n    PSIZE_T ReturnLength;\n} PS_ATTRIBUTE, *PPS_ATTRIBUTE;\n\n_Struct_size_bytes_(TotalLength)\ntypedef struct _PS_ATTRIBUTE_LIST\n{\n    SIZE_T TotalLength;\n    PS_ATTRIBUTE Attributes[1];\n} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;\n\ntypedef struct _PS_MEMORY_RESERVE\n{\n    PVOID ReserveAddress;\n    SIZE_T ReserveSize;\n} PS_MEMORY_RESERVE, *PPS_MEMORY_RESERVE;\n\ntypedef enum _PS_STD_HANDLE_STATE\n{\n    PsNeverDuplicate,\n    PsRequestDuplicate, // duplicate standard handles specified by PseudoHandleMask, and only if StdHandleSubsystemType matches the image subsystem\n    PsAlwaysDuplicate, // always duplicate standard handles\n    PsMaxStdHandleStates\n} PS_STD_HANDLE_STATE;\n\n// begin_rev\n#define PS_STD_INPUT_HANDLE 0x1\n#define PS_STD_OUTPUT_HANDLE 0x2\n#define PS_STD_ERROR_HANDLE 0x4\n// end_rev\n\ntypedef struct _PS_STD_HANDLE_INFO\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG StdHandleState : 2; // PS_STD_HANDLE_STATE\n            ULONG PseudoHandleMask : 3; // PS_STD_*\n        };\n    };\n    ULONG StdHandleSubsystemType;\n} PS_STD_HANDLE_INFO, *PPS_STD_HANDLE_INFO;\n\ntypedef union _PS_TRUSTLET_ATTRIBUTE_ACCESSRIGHTS\n{\n    UCHAR Trustlet : 1;\n    UCHAR Ntos : 1;\n    UCHAR WriteHandle : 1;\n    UCHAR ReadHandle : 1;\n    UCHAR Reserved : 4;\n    UCHAR AccessRights;\n} PS_TRUSTLET_ATTRIBUTE_ACCESSRIGHTS, *PPS_TRUSTLET_ATTRIBUTE_ACCESSRIGHTS;\n\ntypedef union _PS_TRUSTLET_ATTRIBUTE_TYPE\n{\n    ULONG AttributeType;\n    struct\n    {\n        UCHAR Version;\n        UCHAR DataCount;\n        UCHAR SemanticType;\n        PS_TRUSTLET_ATTRIBUTE_ACCESSRIGHTS AccessRights;\n    } DUMMYSTRUCTNAME;\n} PS_TRUSTLET_ATTRIBUTE_TYPE, *PPS_TRUSTLET_ATTRIBUTE_TYPE;\n\ntypedef struct _PS_TRUSTLET_ATTRIBUTE_HEADER\n{\n    PS_TRUSTLET_ATTRIBUTE_TYPE AttributeType;\n    ULONG InstanceNumber : 8;\n    ULONG Reserved : 24;\n} PS_TRUSTLET_ATTRIBUTE_HEADER, *PPS_TRUSTLET_ATTRIBUTE_HEADER;\n\ntypedef struct _PS_TRUSTLET_ATTRIBUTE_DATA\n{\n    PS_TRUSTLET_ATTRIBUTE_HEADER Header;\n    ULONGLONG Data[1];\n} PS_TRUSTLET_ATTRIBUTE_DATA, *PPS_TRUSTLET_ATTRIBUTE_DATA;\n\ntypedef struct _PS_TRUSTLET_CREATE_ATTRIBUTES\n{\n    ULONGLONG TrustletIdentity;\n    PS_TRUSTLET_ATTRIBUTE_DATA Attributes[1];\n} PS_TRUSTLET_CREATE_ATTRIBUTES, *PPS_TRUSTLET_CREATE_ATTRIBUTES;\n\n// private\ntypedef struct _PS_BNO_ISOLATION_PARAMETERS\n{\n    UNICODE_STRING IsolationPrefix;\n    ULONG HandleCount;\n    PVOID *Handles;\n    BOOLEAN IsolationEnabled;\n} PS_BNO_ISOLATION_PARAMETERS, *PPS_BNO_ISOLATION_PARAMETERS;\n\n// private\ntypedef union _PS_PROCESS_CREATION_SVE_VECTOR_LENGTH\n{\n    ULONG VectorLength : 24;\n    ULONG FlagsReserved : 8;\n} PS_PROCESS_CREATION_SVE_VECTOR_LENGTH, *PPS_PROCESS_CREATION_SVE_VECTOR_LENGTH;\n\n// private\ntypedef enum _PS_MITIGATION_OPTION\n{\n    PS_MITIGATION_OPTION_NX,\n    PS_MITIGATION_OPTION_SEHOP,\n    PS_MITIGATION_OPTION_FORCE_RELOCATE_IMAGES,\n    PS_MITIGATION_OPTION_HEAP_TERMINATE,\n    PS_MITIGATION_OPTION_BOTTOM_UP_ASLR,\n    PS_MITIGATION_OPTION_HIGH_ENTROPY_ASLR,\n    PS_MITIGATION_OPTION_STRICT_HANDLE_CHECKS,\n    PS_MITIGATION_OPTION_WIN32K_SYSTEM_CALL_DISABLE,\n    PS_MITIGATION_OPTION_EXTENSION_POINT_DISABLE,\n    PS_MITIGATION_OPTION_PROHIBIT_DYNAMIC_CODE,\n    PS_MITIGATION_OPTION_CONTROL_FLOW_GUARD,\n    PS_MITIGATION_OPTION_BLOCK_NON_MICROSOFT_BINARIES,\n    PS_MITIGATION_OPTION_FONT_DISABLE,\n    PS_MITIGATION_OPTION_IMAGE_LOAD_NO_REMOTE,\n    PS_MITIGATION_OPTION_IMAGE_LOAD_NO_LOW_LABEL,\n    PS_MITIGATION_OPTION_IMAGE_LOAD_PREFER_SYSTEM32,\n    PS_MITIGATION_OPTION_RETURN_FLOW_GUARD,\n    PS_MITIGATION_OPTION_LOADER_INTEGRITY_CONTINUITY,\n    PS_MITIGATION_OPTION_STRICT_CONTROL_FLOW_GUARD,\n    PS_MITIGATION_OPTION_RESTRICT_SET_THREAD_CONTEXT,\n    PS_MITIGATION_OPTION_ROP_STACKPIVOT, // since REDSTONE3\n    PS_MITIGATION_OPTION_ROP_CALLER_CHECK,\n    PS_MITIGATION_OPTION_ROP_SIMEXEC,\n    PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER,\n    PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER_PLUS,\n    PS_MITIGATION_OPTION_RESTRICT_CHILD_PROCESS_CREATION,\n    PS_MITIGATION_OPTION_IMPORT_ADDRESS_FILTER,\n    PS_MITIGATION_OPTION_MODULE_TAMPERING_PROTECTION,\n    PS_MITIGATION_OPTION_RESTRICT_INDIRECT_BRANCH_PREDICTION,\n    PS_MITIGATION_OPTION_SPECULATIVE_STORE_BYPASS_DISABLE, // since REDSTONE5\n    PS_MITIGATION_OPTION_ALLOW_DOWNGRADE_DYNAMIC_CODE_POLICY,\n    PS_MITIGATION_OPTION_CET_USER_SHADOW_STACKS,\n    PS_MITIGATION_OPTION_USER_CET_SET_CONTEXT_IP_VALIDATION, // since 21H1\n    PS_MITIGATION_OPTION_BLOCK_NON_CET_BINARIES,\n    PS_MITIGATION_OPTION_CET_DYNAMIC_APIS_OUT_OF_PROC_ONLY,\n    PS_MITIGATION_OPTION_REDIRECTION_TRUST, // since 22H1\n    PS_MITIGATION_OPTION_RESTRICT_CORE_SHARING,\n    PS_MITIGATION_OPTION_FSCTL_SYSTEM_CALL_DISABLE, // since 24H2\n} PS_MITIGATION_OPTION;\n\n// windows-internals-book:\"Chapter 5\"\ntypedef enum _PS_CREATE_STATE\n{\n    PsCreateInitialState,\n    PsCreateFailOnFileOpen,\n    PsCreateFailOnSectionCreate,\n    PsCreateFailExeFormat,\n    PsCreateFailMachineMismatch,\n    PsCreateFailExeName, // Debugger specified\n    PsCreateSuccess,\n    PsCreateMaximumStates\n} PS_CREATE_STATE;\n\n_Struct_size_bytes_(Size)\ntypedef struct _PS_CREATE_INFO\n{\n    SIZE_T Size;\n    PS_CREATE_STATE State;\n    union\n    {\n        // PsCreateInitialState\n        struct\n        {\n            union\n            {\n                ULONG InitFlags;\n                struct\n                {\n                    UCHAR WriteOutputOnExit : 1;\n                    UCHAR DetectManifest : 1;\n                    UCHAR IFEOSkipDebugger : 1;\n                    UCHAR IFEODoNotPropagateKeyState : 1;\n                    UCHAR SpareBits1 : 4;\n                    UCHAR SpareBits2 : 8;\n                    USHORT ProhibitedImageCharacteristics : 16;\n                };\n            };\n            ACCESS_MASK AdditionalFileAccess;\n        } InitState;\n\n        // PsCreateFailOnSectionCreate\n        struct\n        {\n            HANDLE FileHandle;\n        } FailSection;\n\n        // PsCreateFailExeFormat\n        struct\n        {\n            USHORT DllCharacteristics;\n        } ExeFormat;\n\n        // PsCreateFailExeName\n        struct\n        {\n            HANDLE IFEOKey;\n        } ExeName;\n\n        // PsCreateSuccess\n        struct\n        {\n            union\n            {\n                ULONG OutputFlags;\n                struct\n                {\n                    UCHAR ProtectedProcess : 1;\n                    UCHAR AddressSpaceOverride : 1;\n                    UCHAR DevOverrideEnabled : 1; // from Image File Execution Options\n                    UCHAR ManifestDetected : 1;\n                    UCHAR ProtectedProcessLight : 1;\n                    UCHAR SpareBits1 : 3;\n                    UCHAR SpareBits2 : 8;\n                    USHORT SpareBits3 : 16;\n                };\n            };\n            HANDLE FileHandle;\n            HANDLE SectionHandle;\n            ULONGLONG UserProcessParametersNative;\n            ULONG UserProcessParametersWow64;\n            ULONG CurrentParameterFlags;\n            ULONGLONG PebAddressNative;\n            ULONG PebAddressWow64;\n            ULONGLONG ManifestAddress;\n            ULONG ManifestSize;\n        } SuccessState;\n    };\n} PS_CREATE_INFO, *PPS_CREATE_INFO;\n\n// end_private\n\n/**\n * Creates a new process and primary thread.\n *\n * \\param ProcessHandle A pointer to a handle that receives the process object handle.\n * \\param ThreadHandle A pointer to a handle that receives the thread object handle.\n * \\param ProcessDesiredAccess The access rights desired for the process object.\n * \\param ThreadDesiredAccess The access rights desired for the thread object.\n * \\param ProcessObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new process.\n * \\param ThreadObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new thread.\n * \\param ProcessFlags Flags that control the creation of the process. These flags are defined as PROCESS_CREATE_FLAGS_*.\n * \\param ThreadFlags Flags that control the creation of the thread. These flags are defined as THREAD_CREATE_FLAGS_*.\n * \\param ProcessParameters Optional. A pointer to a RTL_USER_PROCESS_PARAMETERS structure that specifies the parameters for the new process.\n * \\param CreateInfo A pointer to a PS_CREATE_INFO structure that specifies additional information for the process creation.\n * \\param AttributeList Optional. A pointer to a list of attributes for the process and thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateUserProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK ProcessDesiredAccess,\n    _In_ ACCESS_MASK ThreadDesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ProcessObjectAttributes,\n    _In_opt_ PCOBJECT_ATTRIBUTES ThreadObjectAttributes,\n    _In_ ULONG ProcessFlags, // PROCESS_CREATE_FLAGS_*\n    _In_ ULONG ThreadFlags, // THREAD_CREATE_FLAGS_*\n    _In_opt_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters,\n    _Inout_ PPS_CREATE_INFO CreateInfo,\n    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList\n    );\n\n// begin_rev\n#define THREAD_CREATE_FLAGS_NONE 0x00000000\n#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001 // NtCreateUserProcess & NtCreateThreadEx\n#define THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH 0x00000002 // NtCreateThreadEx only\n#define THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER 0x00000004 // NtCreateThreadEx only\n#define THREAD_CREATE_FLAGS_LOADER_WORKER 0x00000010 // NtCreateThreadEx only // since THRESHOLD\n#define THREAD_CREATE_FLAGS_SKIP_LOADER_INIT 0x00000020 // NtCreateThreadEx only // since REDSTONE2\n#define THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE 0x00000040 // NtCreateThreadEx only // since 19H1\n// end_rev\n\n/**\n * A pointer to a user-defined function that serves as the starting routine for a new thread.\n *\n * \\param ThreadParameter A pointer to a variable that is passed to the thread.\n * \\return NTSTATUS Successful or errant status.\n */\ntypedef _Function_class_(USER_THREAD_START_ROUTINE)\nNTSTATUS NTAPI USER_THREAD_START_ROUTINE(\n    _In_ PVOID ThreadParameter\n    );\ntypedef USER_THREAD_START_ROUTINE* PUSER_THREAD_START_ROUTINE;\n\n/**\n * Creates a new thread in the specified process.\n *\n * \\param ThreadHandle A pointer to a handle that receives the thread object handle.\n * \\param DesiredAccess The access rights desired for the thread object.\n * \\param ObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new thread.\n * \\param ProcessHandle A handle to the process in which the thread is to be created.\n * \\param StartRoutine A pointer to the application-defined function to be executed by the thread.\n * \\param Argument Optional. A pointer to a variable that is passed to the thread.\n * \\param CreateFlags Flags that control the creation of the thread. These flags are defined as THREAD_CREATE_FLAGS_*.\n * \\param ZeroBits The number of zero bits in the starting address of the thread's stack.\n * \\param StackSize The initial size of the thread's stack, in bytes.\n * \\param MaximumStackSize The maximum size of the thread's stack, in bytes.\n * \\param AttributeList Optional. A pointer to a list of attributes for the thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateThreadEx(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ProcessHandle,\n    _In_ PUSER_THREAD_START_ROUTINE StartRoutine,\n    _In_opt_ PVOID Argument,\n    _In_ ULONG CreateFlags, // THREAD_CREATE_FLAGS_*\n    _In_ SIZE_T ZeroBits,\n    _In_ SIZE_T StackSize,\n    _In_ SIZE_T MaximumStackSize,\n    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList\n    );\n\n#endif // PHNT_MODE != PHNT_MODE_KERNEL\n\n//\n// Job objects\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// JOBOBJECTINFOCLASS\n// Note: We don't use an enum since it conflicts with the Windows SDK.\n#define JOBOBJECTINFOCLASS ULONG\n#define JobObjectBasicAccountingInformation 1                       // q: JOBOBJECT_BASIC_ACCOUNTING_INFORMATION\n#define JobObjectBasicLimitInformation 2                            // qs: JOBOBJECT_BASIC_LIMIT_INFORMATION\n#define JobObjectBasicProcessIdList 3                               // q: JOBOBJECT_BASIC_PROCESS_ID_LIST\n#define JobObjectBasicUIRestrictions 4                              // qs: JOBOBJECT_BASIC_UI_RESTRICTIONS\n#define JobObjectSecurityLimitInformation 5                         // qs: JOBOBJECT_SECURITY_LIMIT_INFORMATION\n#define JobObjectEndOfJobTimeInformation 6                          // qs: JOBOBJECT_END_OF_JOB_TIME_INFORMATION\n#define JobObjectAssociateCompletionPortInformation 7               // s: JOBOBJECT_ASSOCIATE_COMPLETION_PORT\n#define JobObjectBasicAndIoAccountingInformation 8                  // q: JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION\n#define JobObjectExtendedLimitInformation 9                         // qs: JOBOBJECT_EXTENDED_LIMIT_INFORMATION[V2]\n#define JobObjectJobSetInformation 10                               // q: JOBOBJECT_JOBSET_INFORMATION\n#define JobObjectGroupInformation 11                                // q: USHORT\n#define JobObjectNotificationLimitInformation 12                    // q: JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION\n#define JobObjectLimitViolationInformation 13                       // q: JOBOBJECT_LIMIT_VIOLATION_INFORMATION\n#define JobObjectGroupInformationEx 14                              // qs: GROUP_AFFINITY (ARRAY)\n#define JobObjectCpuRateControlInformation 15                       // qs: JOBOBJECT_CPU_RATE_CONTROL_INFORMATION\n#define JobObjectCompletionFilter 16                                // qs: ULONG\n#define JobObjectCompletionCounter 17                               // qs: ULONG\n#define JobObjectFreezeInformation 18                               // qs: JOBOBJECT_FREEZE_INFORMATION\n#define JobObjectExtendedAccountingInformation 19                   // qs: JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION\n#define JobObjectWakeInformation 20                                 // qs: JOBOBJECT_WAKE_INFORMATION\n#define JobObjectBackgroundInformation 21                           // s: BOOLEAN\n#define JobObjectSchedulingRankBiasInformation 22                   // s: JOBOBJECT_SCHEDULING_RANK_BIAS_INFORMATION\n#define JobObjectTimerVirtualizationInformation 23                  // s: JOBOBJECT_TIMER_VIRTUALIZATION_INFORMATION\n#define JobObjectCycleTimeNotification 24                           // s: JOBOBJECT_CYCLE_TIME_NOTIFICATION\n#define JobObjectClearEvent 25                                      // s: HANDLE\n#define JobObjectInterferenceInformation 26                         // q: JOBOBJECT_INTERFERENCE_INFORMATION\n#define JobObjectClearPeakJobMemoryUsed 27                          // s: NULL\n#define JobObjectMemoryUsageInformation 28                          // q: JOBOBJECT_MEMORY_USAGE_INFORMATION // JOBOBJECT_MEMORY_USAGE_INFORMATION_V2\n#define JobObjectSharedCommit 29                                    // q: JOBOBJECT_SHARED_COMMIT\n#define JobObjectContainerId 30                                     // q: JOBOBJECT_CONTAINER_IDENTIFIER_V2\n#define JobObjectIoRateControlInformation 31                        // qs: JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE, JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE_V2, JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE_V3\n#define JobObjectNetRateControlInformation 32                       // qs: JOBOBJECT_NET_RATE_CONTROL_INFORMATION\n#define JobObjectNotificationLimitInformation2 33                   // qs: JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2\n#define JobObjectLimitViolationInformation2 34                      // qs: JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2\n#define JobObjectCreateSilo 35                                      // s: NULL\n#define JobObjectSiloBasicInformation 36                            // q: SILOOBJECT_BASIC_INFORMATION\n#define JobObjectSiloRootDirectory 37                               // q: SILOOBJECT_ROOT_DIRECTORY\n#define JobObjectServerSiloBasicInformation 38                      // q: SERVERSILO_BASIC_INFORMATION\n#define JobObjectServerSiloUserSharedData 39                        // q: SILO_USER_SHARED_DATA // NtQueryInformationJobObject(NULL, 39, Buffer, sizeof(SILO_USER_SHARED_DATA), 0);\n#define JobObjectServerSiloInitialize 40                            // qs: SERVERSILO_INIT_INFORMATION\n#define JobObjectServerSiloRunningState 41                          // s: BOOLEAN\n#define JobObjectIoAttribution 42                                   // q: JOBOBJECT_IO_ATTRIBUTION_INFORMATION\n#define JobObjectMemoryPartitionInformation 43                      // qs: JOBOBJECT_MEMORY_PARTITION_INFORMATION\n#define JobObjectContainerTelemetryId 44                            // s: GUID // NtSetInformationJobObject(_In_ PGUID, 44, _In_ PGUID, sizeof(GUID)); // daxexec\n#define JobObjectSiloSystemRoot 45                                  // s: UNICODE_STRING\n#define JobObjectEnergyTrackingState 46                             // q: JOBOBJECT_ENERGY_TRACKING_STATE\n#define JobObjectThreadImpersonationInformation 47                  // qs: BOOLEAN\n#define JobObjectIoPriorityLimit 48                                 // qs: JOBOBJECT_IO_PRIORITY_LIMIT\n#define JobObjectPagePriorityLimit 49                               // qs: JOBOBJECT_PAGE_PRIORITY_LIMIT\n#define JobObjectServerSiloDiagnosticInformation 50                 // q: SERVERSILO_DIAGNOSTIC_INFORMATION // since 24H2\n#define JobObjectNetworkAccountingInformation 51                    // q: JOBOBJECT_NETWORK_ACCOUNTING_INFORMATION\n#define JobObjectCpuPartition 52                                    // qs: JOBOBJECT_CPU_PARTITION_INFORMATION // since 25H2\n#define MaxJobObjectInfoClass 53\n\n// rev // extended limit v2\n#define JOB_OBJECT_LIMIT_SILO_READY 0x00400000\n\n/**\n * The JOBOBJECT_EXTENDED_LIMIT_INFORMATION_V2 structure contains basic and extended limit information for a job object.\n *\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_extended_limit_information\n */\ntypedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_V2\n{\n    JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;\n    IO_COUNTERS IoInfo;\n    SIZE_T ProcessMemoryLimit;\n    SIZE_T JobMemoryLimit;\n    SIZE_T PeakProcessMemoryUsed;\n    SIZE_T PeakJobMemoryUsed;\n    SIZE_T JobTotalMemoryLimit;\n} JOBOBJECT_EXTENDED_LIMIT_INFORMATION_V2, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION_V2;\n\n// private\ntypedef struct _JOBOBJECT_SCHEDULING_RANK_BIAS_INFORMATION\n{\n    ULONG SchedulingRankBias;\n} JOBOBJECT_SCHEDULING_RANK_BIAS_INFORMATION, *PJOBOBJECT_SCHEDULING_RANK_BIAS_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_TIMER_VIRTUALIZATION_INFORMATION\n{\n    ULONG TimerVirtualizationEnabled;\n} JOBOBJECT_TIMER_VIRTUALIZATION_INFORMATION, *PJOBOBJECT_TIMER_VIRTUALIZATION_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_CYCLE_TIME_NOTIFICATION\n{\n    HANDLE NotificationChannel;\n    ULONG64 CycleTime;\n} JOBOBJECT_CYCLE_TIME_NOTIFICATION, *PJOBOBJECT_CYCLE_TIME_NOTIFICATION;\n\n// private\ntypedef struct _JOBOBJECT_SHARED_COMMIT\n{\n    ULONG64 SharedCommit;\n} JOBOBJECT_SHARED_COMMIT, *PJOBOBJECT_SHARED_COMMIT;\n\n// private\ntypedef struct _JOBOBJECT_MEMORY_PARTITION_INFORMATION\n{\n    ULONG_PTR PartitionId;\n} JOBOBJECT_MEMORY_PARTITION_INFORMATION, *PJOBOBJECT_MEMORY_PARTITION_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_CPU_PARTITION_INFORMATION\n{\n    ULONG_PTR PartitionId;\n} JOBOBJECT_CPU_PARTITION_INFORMATION, *PJOBOBJECT_CPU_PARTITION_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION\n{\n    JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo;\n    IO_COUNTERS IoInfo;\n    PROCESS_DISK_COUNTERS DiskIoInfo;\n    ULONG64 ContextSwitches;\n    LARGE_INTEGER TotalCycleTime;\n    ULONG64 ReadyTime;\n    PROCESS_ENERGY_VALUES EnergyValues;\n} JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION, *PJOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_WAKE_INFORMATION\n{\n    HANDLE NotificationChannel;\n    ULONG64 WakeCounters[PsMaxWakeReasons];\n} JOBOBJECT_WAKE_INFORMATION, *PJOBOBJECT_WAKE_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_WAKE_INFORMATION_V1\n{\n    HANDLE NotificationChannel;\n    ULONG64 WakeCounters[4];\n} JOBOBJECT_WAKE_INFORMATION_V1, *PJOBOBJECT_WAKE_INFORMATION_V1;\n\n// private\ntypedef struct _JOBOBJECT_INTERFERENCE_INFORMATION\n{\n    ULONG64 Count;\n} JOBOBJECT_INTERFERENCE_INFORMATION, *PJOBOBJECT_INTERFERENCE_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_FREEZE_INFORMATION\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG FreezeOperation : 1;\n            ULONG FilterOperation : 1;\n            ULONG SwapOperation : 1;\n            ULONG Reserved : 29;\n        };\n    };\n    BOOLEAN Freeze;\n    BOOLEAN Swap;\n    UCHAR Reserved0[2];\n    JOBOBJECT_WAKE_FILTER WakeFilter;\n} JOBOBJECT_FREEZE_INFORMATION, *PJOBOBJECT_FREEZE_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_CONTAINER_IDENTIFIER_V2\n{\n    GUID ContainerId;\n    GUID ContainerTelemetryId;\n    ULONG JobId;\n} JOBOBJECT_CONTAINER_IDENTIFIER_V2, *PJOBOBJECT_CONTAINER_IDENTIFIER_V2;\n\n// private\ntypedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION\n{\n    ULONG64 JobMemory;\n    ULONG64 PeakJobMemoryUsed;\n} JOBOBJECT_MEMORY_USAGE_INFORMATION, *PJOBOBJECT_MEMORY_USAGE_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION_V2\n{\n    JOBOBJECT_MEMORY_USAGE_INFORMATION BasicInfo;\n    ULONG64 JobSharedMemory;\n    ULONG64 Reserved[2];\n} JOBOBJECT_MEMORY_USAGE_INFORMATION_V2, *PJOBOBJECT_MEMORY_USAGE_INFORMATION_V2;\n\n// private\ntypedef struct _SILO_USER_SHARED_DATA\n{\n    ULONG ServiceSessionId;\n    ULONG ActiveConsoleId;\n    LONGLONG ConsoleSessionForegroundProcessId;\n    NT_PRODUCT_TYPE NtProductType;\n    ULONG SuiteMask;\n    ULONG SharedUserSessionId; // since RS2\n    BOOLEAN IsMultiSessionSku;\n    BOOLEAN IsStateSeparationEnabled;\n    WCHAR NtSystemRoot[260];\n    USHORT UserModeGlobalLogger[16];\n    ULONG TimeZoneId; // since 21H2\n    LONG TimeZoneBiasStamp;\n    KSYSTEM_TIME TimeZoneBias;\n    LARGE_INTEGER TimeZoneBiasEffectiveStart;\n    LARGE_INTEGER TimeZoneBiasEffectiveEnd;\n} SILO_USER_SHARED_DATA, *PSILO_USER_SHARED_DATA;\n\n// rev\n#define SILO_OBJECT_ROOT_DIRECTORY_SHADOW_ROOT 0x00000001\n#define SILO_OBJECT_ROOT_DIRECTORY_INITIALIZE 0x00000002\n#define SILO_OBJECT_ROOT_DIRECTORY_SHADOW_DOS_DEVICES 0x00000004\n\n// private\ntypedef struct _SILOOBJECT_ROOT_DIRECTORY\n{\n    union\n    {\n        ULONG ControlFlags; // SILO_OBJECT_ROOT_DIRECTORY_*\n        UNICODE_STRING Path;\n    };\n} SILOOBJECT_ROOT_DIRECTORY, *PSILOOBJECT_ROOT_DIRECTORY;\n\n// private\ntypedef struct _SERVERSILO_INIT_INFORMATION\n{\n    HANDLE DeleteEvent;\n    BOOLEAN IsDownlevelContainer;\n} SERVERSILO_INIT_INFORMATION, *PSERVERSILO_INIT_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_ENERGY_TRACKING_STATE\n{\n    ULONG64 Value;\n    ULONG UpdateMask;\n    ULONG DesiredState;\n} JOBOBJECT_ENERGY_TRACKING_STATE, *PJOBOBJECT_ENERGY_TRACKING_STATE;\n\n// private\n_Enum_is_bitflag_\ntypedef enum _JOBOBJECT_IO_PRIORITY_LIMIT_FLAGS\n{\n    JOBOBJECT_IO_PRIORITY_LIMIT_ENABLE = 0x1,\n    JOBOBJECT_IO_PRIORITY_LIMIT_VALID_FLAGS = 0x1,\n} JOBOBJECT_IO_PRIORITY_LIMIT_FLAGS;\nDEFINE_ENUM_FLAG_OPERATORS(JOBOBJECT_IO_PRIORITY_LIMIT_FLAGS);\n\n// private\ntypedef struct _JOBOBJECT_IO_PRIORITY_LIMIT\n{\n    JOBOBJECT_IO_PRIORITY_LIMIT_FLAGS Flags;\n    ULONG Priority;\n} JOBOBJECT_IO_PRIORITY_LIMIT, *PJOBOBJECT_IO_PRIORITY_LIMIT;\n\n// private\n_Enum_is_bitflag_\ntypedef enum _JOBOBJECT_PAGE_PRIORITY_LIMIT_FLAGS\n{\n    JOBOBJECT_PAGE_PRIORITY_LIMIT_ENABLE = 0x1,\n    JOBOBJECT_PAGE_PRIORITY_LIMIT_VALID_FLAGS = 0x1,\n} JOBOBJECT_PAGE_PRIORITY_LIMIT_FLAGS;\nDEFINE_ENUM_FLAG_OPERATORS(JOBOBJECT_PAGE_PRIORITY_LIMIT_FLAGS);\n\n// private\ntypedef struct _JOBOBJECT_PAGE_PRIORITY_LIMIT\n{\n    JOBOBJECT_PAGE_PRIORITY_LIMIT_FLAGS Flags;\n    ULONG Priority;\n} JOBOBJECT_PAGE_PRIORITY_LIMIT, *PJOBOBJECT_PAGE_PRIORITY_LIMIT;\n\n#if !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\n// private\ntypedef struct _SERVERSILO_DIAGNOSTIC_INFORMATION\n{\n    NTSTATUS ExitStatus;\n    WCHAR CriticalProcessName[15];\n} SERVERSILO_DIAGNOSTIC_INFORMATION, *PSERVERSILO_DIAGNOSTIC_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_NETWORK_ACCOUNTING_INFORMATION\n{\n    ULONG64 DataBytesIn;\n    ULONG64 DataBytesOut;\n} JOBOBJECT_NETWORK_ACCOUNTING_INFORMATION, *PJOBOBJECT_NETWORK_ACCOUNTING_INFORMATION;\n#endif // !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\n\n/**\n * Creates or opens a job object.\n *\n * \\param JobHandle A handle to the job object.\n * \\param DesiredAccess The access rights desired for the thread object.\n * \\param ObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateJobObject(\n    _Out_ PHANDLE JobHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * Opens an existing job object.\n *\n * \\param JobHandle A handle to the job object.\n * \\param DesiredAccess The access rights desired for the thread object.\n * \\param ObjectAttributes Optional. A pointer to an OBJECT_ATTRIBUTES structure that specifies the attributes of the new thread.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenJobObject(\n    _Out_ PHANDLE JobHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n/**\n * Assigns a process to an existing job object.\n *\n * \\param JobHandle A handle to the job object to which the process will be associated. The handle must have the JOB_OBJECT_ASSIGN_PROCESS access right.\n * \\param ProcessHandle A handle to the process to associate with the job object. The handle must have the PROCESS_SET_QUOTA and PROCESS_TERMINATE access rights.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAssignProcessToJobObject(\n    _In_ HANDLE JobHandle,\n    _In_ HANDLE ProcessHandle\n    );\n\n/**\n * Terminates all processes associated with the job object. If the job is nested, all processes currently associated with the job and all child jobs in the hierarchy are terminated.\n *\n * \\param JobHandle A handle to the job whose processes will be terminated. The handle must have the JOB_OBJECT_TERMINATE access right.\n * \\param ExitStatus The exit status to be used by all processes and threads in the job object.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTerminateJobObject(\n    _In_ HANDLE JobHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\n/**\n * Checks if a process is associated with a job object.\n *\n * \\param ProcessHandle A handle to the process to be checked.\n * \\param JobHandle An optional handle to the job object. If this parameter is NULL, the function checks if the process is associated with any job object.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function can be used to determine if a process is running within a job object, which can be useful for managing process resources and constraints.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtIsProcessInJob(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ HANDLE JobHandle\n    );\n\n/**\n * Retrieves information about a job object.\n *\n * \\param JobHandle An optional handle to the job object. If this parameter is NULL, the function retrieves information about the job object associated with the calling process.\n * \\param JobObjectInformationClass The type of job object information to be retrieved.\n * \\param JobObjectInformation A pointer to a buffer that receives the job object information.\n * \\param JobObjectInformationLength The size of the buffer pointed to by the JobObjectInformation parameter.\n * \\param ReturnLength An optional pointer to a variable that receives the size of the data returned.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function can be used to query various types of information about a job object, such as accounting information, limit information, and process ID list.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationJobObject(\n    _In_opt_ HANDLE JobHandle,\n    _In_ JOBOBJECTINFOCLASS JobObjectInformationClass,\n    _Out_writes_bytes_(JobObjectInformationLength) PVOID JobObjectInformation,\n    _In_ ULONG JobObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n/**\n * Sets information for a job object.\n *\n * \\param JobHandle A handle to the job object.\n * \\param JobObjectInformationClass The type of job object information to be set.\n * \\param JobObjectInformation A pointer to a buffer that contains the job object information.\n * \\param JobObjectInformationLength The size of the buffer pointed to by the JobObjectInformation parameter.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function can be used to set various types of information for a job object, such as limit information, UI restrictions, and security limit information.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationJobObject(\n    _In_ HANDLE JobHandle,\n    _In_ JOBOBJECTINFOCLASS JobObjectInformationClass,\n    _In_reads_bytes_(JobObjectInformationLength) PVOID JobObjectInformation,\n    _In_ ULONG JobObjectInformationLength\n    );\n\n/**\n * Creates a set of job objects.\n *\n * \\param NumJob The number of job objects in the set.\n * \\param UserJobSet A pointer to an array of JOB_SET_ARRAY structures that specify the job objects in the set.\n * \\param Flags Reserved for future use. Must be zero.\n * \\return NTSTATUS Successful or errant status.\n * \\remarks This function can be used to create a set of job objects, which can be useful for managing groups of related processes.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateJobSet(\n    _In_ ULONG NumJob,\n    _In_reads_(NumJob) PJOB_SET_ARRAY UserJobSet,\n    _In_ ULONG Flags\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRevertContainerImpersonation(\n    VOID\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10)\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n//\n// Reserve objects\n//\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// private\ntypedef enum _MEMORY_RESERVE_TYPE\n{\n    MemoryReserveUserApc,\n    MemoryReserveIoCompletion,\n    MemoryReserveTypeMax\n} MEMORY_RESERVE_TYPE;\n\n/**\n * Allocates a memory reserve object.\n *\n * \\param MemoryReserveHandle Pointer to a variable that receives the memory reserve object handle.\n * \\param ObjectAttributes Pointer to an object attributes structure.\n * \\param Type The type of memory reserve.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateReserveObject(\n    _Out_ PHANDLE MemoryReserveHandle,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ MEMORY_RESERVE_TYPE Type\n    );\n\n//\n// Process snapshotting\n//\n\n// Capture/creation flags.\n_Enum_is_bitflag_\ntypedef enum _PSSNT_CAPTURE_FLAGS\n{\n    PSSNT_CAPTURE_NONE                                = 0x00000000,\n    PSSNT_CAPTURE_VA_CLONE                            = 0x00000001,\n    PSSNT_CAPTURE_RESERVED_00000002                   = 0x00000002,\n    PSSNT_CAPTURE_HANDLES                             = 0x00000004,\n    PSSNT_CAPTURE_HANDLE_NAME_INFORMATION             = 0x00000008,\n    PSSNT_CAPTURE_HANDLE_BASIC_INFORMATION            = 0x00000010,\n    PSSNT_CAPTURE_HANDLE_TYPE_SPECIFIC_INFORMATION    = 0x00000020,\n    PSSNT_CAPTURE_HANDLE_TRACE                        = 0x00000040,\n    PSSNT_CAPTURE_THREADS                             = 0x00000080,\n    PSSNT_CAPTURE_THREAD_CONTEXT                      = 0x00000100,\n    PSSNT_CAPTURE_THREAD_CONTEXT_EXTENDED             = 0x00000200,\n    PSSNT_CAPTURE_RESERVED_00000400                   = 0x00000400,\n    PSSNT_CAPTURE_VA_SPACE                            = 0x00000800,\n    PSSNT_CAPTURE_VA_SPACE_SECTION_INFORMATION        = 0x00001000,\n    PSSNT_CAPTURE_IPT_TRACE                           = 0x00002000,\n    PSSNT_CAPTURE_RESERVED_00004000                   = 0x00004000,\n\n    PSSNT_CREATE_BREAKAWAY_OPTIONAL                   = 0x04000000,\n    PSSNT_CREATE_BREAKAWAY                            = 0x08000000,\n    PSSNT_CREATE_FORCE_BREAKAWAY                      = 0x10000000,\n    PSSNT_CREATE_USE_VM_ALLOCATIONS                   = 0x20000000,\n    PSSNT_CREATE_MEASURE_PERFORMANCE                  = 0x40000000,\n    PSSNT_CREATE_RELEASE_SECTION                      = 0x80000000\n} PSSNT_CAPTURE_FLAGS;\nDEFINE_ENUM_FLAG_OPERATORS(PSSNT_CAPTURE_FLAGS);\n\n_Enum_is_bitflag_\ntypedef enum _PSSNT_DUPLICATE_FLAGS\n{\n    PSSNT_DUPLICATE_NONE         = 0x00,\n    PSSNT_DUPLICATE_CLOSE_SOURCE = 0x01\n} PSSNT_DUPLICATE_FLAGS;\nDEFINE_ENUM_FLAG_OPERATORS(PSSNT_DUPLICATE_FLAGS);\n\ntypedef enum _PSSNT_QUERY_INFORMATION_CLASS\n{\n    PSSNT_QUERY_PROCESS_INFORMATION = 0, // PSS_PROCESS_INFORMATION\n    PSSNT_QUERY_VA_CLONE_INFORMATION = 1, // PSS_VA_CLONE_INFORMATION\n    PSSNT_QUERY_AUXILIARY_PAGES_INFORMATION = 2, // PSS_AUXILIARY_PAGES_INFORMATION\n    PSSNT_QUERY_VA_SPACE_INFORMATION = 3, // PSS_VA_SPACE_INFORMATION\n    PSSNT_QUERY_HANDLE_INFORMATION = 4, // PSS_HANDLE_INFORMATION\n    PSSNT_QUERY_THREAD_INFORMATION = 5, // PSS_THREAD_INFORMATION\n    PSSNT_QUERY_HANDLE_TRACE_INFORMATION = 6, // PSS_HANDLE_TRACE_INFORMATION\n    PSSNT_QUERY_PERFORMANCE_COUNTERS = 7 // PSS_PERFORMANCE_COUNTERS\n} PSSNT_QUERY_INFORMATION_CLASS;\n\n#define PSSNT_SIGNATURE_PSSD 'PSSD' // 0x50535344\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8_1)\n// rev\n/**\n * The PssNtCaptureSnapshot routine captures a snapshot of the specified process.\n *\n * \\param SnapshotHandle Pointer to a variable that receives the snapshot handle.\n * \\param ProcessHandle Handle to the process.\n * \\param CaptureFlags Flags indicating what to capture.\n * \\param ThreadContextFlags Optional flags for capturing thread context.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nPssNtCaptureSnapshot(\n    _Out_ PHANDLE SnapshotHandle,\n    _In_ HANDLE ProcessHandle,\n    _In_ PSSNT_CAPTURE_FLAGS CaptureFlags,\n    _In_opt_ ULONG ThreadContextFlags\n    );\n\n// rev\n/**\n * The PssNtDuplicateSnapshot routine duplicates a process snapshot from one process to another.\n *\n * \\param SourceProcessHandle Handle to the source process.\n * \\param SnapshotHandle Handle to the snapshot to duplicate.\n * \\param TargetProcessHandle Handle to the target process.\n * \\param TargetSnapshotHandle Pointer to a variable that receives the duplicated snapshot handle.\n * \\param Flags Optional flags for duplication.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nPssNtDuplicateSnapshot(\n    _In_ HANDLE SourceProcessHandle,\n    _In_ HANDLE SnapshotHandle,\n    _In_ HANDLE TargetProcessHandle,\n    _Out_ PHANDLE TargetSnapshotHandle,\n    _In_opt_ PSSNT_DUPLICATE_FLAGS Flags\n    );\n\n// rev\n/**\n * The PssNtFreeSnapshot routine frees a snapshot.\n *\n * \\param SnapshotHandle Handle to the snapshot to free.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nPssNtFreeSnapshot(\n    _In_ HANDLE SnapshotHandle\n    );\n\n// rev\n/**\n * The PssNtFreeRemoteSnapshot routine frees a remote process snapshot.\n *\n * \\param ProcessHandle A handle to the process that contains the snapshot. The handle must have PROCESS_VM_READ, PROCESS_VM_OPERATION, and PROCESS_DUP_HANDLE rights.\n * \\param SnapshotHandle Handle to the snapshot to free.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nPssNtFreeRemoteSnapshot(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE SnapshotHandle\n    );\n\n// rev\n/**\n * The PssNtQuerySnapshot routine queries information from the specified snapshot.\n *\n * \\param SnapshotHandle Handle to the snapshot.\n * \\param InformationClass The information class to query.\n * \\param Buffer Pointer to a buffer that receives the queried information.\n * \\param BufferLength Length of the buffer.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nPssNtQuerySnapshot(\n    _In_ HANDLE SnapshotHandle,\n    _In_ PSSNT_QUERY_INFORMATION_CLASS InformationClass,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength\n    );\n\n// rev\ntypedef struct _PSSNT_WALK_MARKER_INFO\n{\n    ULONG Signature; // Win32: 0x4D575350 // 'PSSM'\n    HANDLE SectionHandle;\n} PSSNT_WALK_MARKER_INFO, *PPSSNT_WALK_MARKER_INFO;\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nPssNtWalkSnapshot(\n    _In_ HANDLE SnapshotHandle,\n    _In_ ULONG InformationClass,\n    _In_ HANDLE WalkMarkerHandle,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nPssNtFreeWalkMarker(\n    _Inout_ PHANDLE WalkMarkerHandle\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nPssNtValidateDescriptor(\n    _In_ HANDLE SnapshotHandle,\n    _In_opt_ PVOID ExceptionAddress\n    );\n\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8_1)\n\n// rev\n/**\n * Flag indicating the type of bulk information to query.\n */\n#define MEMORY_BULK_INFORMATION_FLAG_BASIC 0x00000001\n\n// rev\n/**\n * The NTPSS_MEMORY_BULK_INFORMATION structure is used to query basic memory information in bulk for a process.\n */\ntypedef struct _NTPSS_MEMORY_BULK_INFORMATION\n{\n    ULONG QueryFlags;\n    ULONG NumberOfEntries;\n    PVOID NextValidAddress;\n} NTPSS_MEMORY_BULK_INFORMATION, *PNTPSS_MEMORY_BULK_INFORMATION;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_20H1)\n// rev\n/**\n * Captures virtual address space bulk information for a process.\n *\n * \\param ProcessHandle Handle to the process.\n * \\param BaseAddress Optional base address to start the capture.\n * \\param BulkInformation Pointer to the memory bulk information structure.\n * \\param BulkInformationLength Length of the memory bulk information structure.\n * \\param ReturnLength Optional pointer to a variable that receives the length of the captured information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPssCaptureVaSpaceBulk(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ PNTPSS_MEMORY_BULK_INFORMATION BulkInformation,\n    _In_ SIZE_T BulkInformationLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_20H1)\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#endif // _NTPSAPI_H\n"
  },
  {
    "path": "phnt/include/ntsam.h",
    "content": "/*\n * Security Account Manager support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTSAM_H\n#define _NTSAM_H\n\n//\n// Types\n//\n\n#define SAM_MAXIMUM_LOOKUP_COUNT (1000)\n#define SAM_MAXIMUM_LOOKUP_LENGTH (32000)\n#define SAM_MAX_PASSWORD_LENGTH (256)\n#define SAM_PASSWORD_ENCRYPTION_SALT_LEN (16)\n\ntypedef PVOID SAM_HANDLE, *PSAM_HANDLE;\ntypedef ULONG SAM_ENUMERATE_HANDLE, *PSAM_ENUMERATE_HANDLE;\n\ntypedef struct _SAM_RID_ENUMERATION\n{\n    ULONG RelativeId;\n    UNICODE_STRING Name;\n} SAM_RID_ENUMERATION, *PSAM_RID_ENUMERATION;\n\ntypedef struct _SAM_SID_ENUMERATION\n{\n    PSID Sid;\n    UNICODE_STRING Name;\n} SAM_SID_ENUMERATION, *PSAM_SID_ENUMERATION;\n\ntypedef struct _SAM_BYTE_ARRAY\n{\n    ULONG Size;\n    _Field_size_bytes_(Size) PUCHAR Data;\n} SAM_BYTE_ARRAY, *PSAM_BYTE_ARRAY;\n\ntypedef struct _SAM_BYTE_ARRAY_32K\n{\n    ULONG Size;\n    _Field_size_bytes_(Size) PUCHAR Data;\n} SAM_BYTE_ARRAY_32K, *PSAM_BYTE_ARRAY_32K;\n\ntypedef SAM_BYTE_ARRAY_32K SAM_SHELL_OBJECT_PROPERTIES, *PSAM_SHELL_OBJECT_PROPERTIES;\n\n//\n// Basic\n//\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamFreeMemory(\n    _In_ PVOID Buffer\n    );\n\n/**\n * The SamCloseHandle method closes (that is, releases server-side resources used by) any handle.\n *\n * \\param SamHandle The object handle.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/55d134df-e257-48ad-8afa-cb2ca45cd3cc\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamCloseHandle(\n    _In_ SAM_HANDLE SamHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamSetSecurityObject(\n    _In_ SAM_HANDLE ObjectHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n/**\n * The SamQuerySecurityObject method queries the access control on a server, domain, user, group, or alias object.\n *\n * \\param ObjectHandle The \"Domain\", \"User\", \"Group\", or \"Alias\" object handle.\n * \\param SecurityInformation A bit field that specifies which fields of SecurityDescriptor the client is requesting to be returned.\n * \\param SecurityDescriptor A security descriptor expressing accesses that are specific to the ObjectHandle and the owner and group of the object.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/0ecf8fec-d17e-4a88-b7f1-e0f0f66790db\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamQuerySecurityObject(\n    _In_ SAM_HANDLE ObjectHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Outptr_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    );\n\n/**\n * The SamRidToSid method obtains the SID of an account, given a RID.\n *\n * \\param ObjectHandle The \"Domain\", \"User\", \"Group\", or \"Alias\" object handle.\n * \\param Rid The RID of the object.\n * \\param Sid The SID of the object referenced by Rid.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/00ff8192-a4f6-45ba-9f65-917e46b6a693\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamRidToSid(\n    _In_ SAM_HANDLE ObjectHandle,\n    _In_ ULONG Rid,\n    _Outptr_ PSID *Sid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamQueryLapsManagedAccount(\n    _In_ SAM_HANDLE ObjectHandle,\n    _Outptr_ PSID *AccountSid\n    );\n\n//\n// Server\n//\n\n#define SAM_SERVER_CONNECT 0x0001\n#define SAM_SERVER_SHUTDOWN 0x0002\n#define SAM_SERVER_INITIALIZE 0x0004\n#define SAM_SERVER_CREATE_DOMAIN 0x0008\n#define SAM_SERVER_ENUMERATE_DOMAINS 0x0010\n#define SAM_SERVER_LOOKUP_DOMAIN 0x0020\n\n#define SAM_SERVER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED     | \\\n    SAM_SERVER_CONNECT | \\\n    SAM_SERVER_INITIALIZE | \\\n    SAM_SERVER_CREATE_DOMAIN | \\\n    SAM_SERVER_SHUTDOWN | \\\n    SAM_SERVER_ENUMERATE_DOMAINS | \\\n    SAM_SERVER_LOOKUP_DOMAIN)\n\n#define SAM_SERVER_READ (STANDARD_RIGHTS_READ | \\\n    SAM_SERVER_ENUMERATE_DOMAINS)\n\n#define SAM_SERVER_WRITE (STANDARD_RIGHTS_WRITE | \\\n    SAM_SERVER_INITIALIZE | \\\n    SAM_SERVER_CREATE_DOMAIN | \\\n    SAM_SERVER_SHUTDOWN)\n\n#define SAM_SERVER_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    SAM_SERVER_CONNECT | \\\n    SAM_SERVER_LOOKUP_DOMAIN)\n\ntypedef struct _RPC_AUTH_IDENTITY_HANDLE *PRPC_AUTH_IDENTITY_HANDLE;\n\n//\n// Functions\n//\n\n/**\n * The SamConnect method returns a handle to a server.\n *\n * \\param ServerName The NETBIOS name of the server; this parameter MAY be ignored on receipt.\n * \\param ServerHandle A handle representing a server.\n * \\param DesiredAccess The access requested for ServerHandle upon output. \n * \\param ObjectAttributes The OBJECT_ATTRIBUTES structure that specifies the properties of the server handle to be opened.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/47492d59-e095-4398-b03e-8a062b989123\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamConnect(\n    _In_opt_ PCUNICODE_STRING ServerName,\n    _Out_ PSAM_HANDLE ServerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamConnectWithCreds(\n    _In_ PCUNICODE_STRING ServerName,\n    _Out_ PSAM_HANDLE ServerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PRPC_AUTH_IDENTITY_HANDLE Creds,\n    _In_ PWCHAR Spn,\n    _Out_ PBOOL DestinationIsWindows2K\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamShutdownSamServer(\n    _In_ SAM_HANDLE ServerHandle\n    );\n\n//\n// Domain\n//\n\n#define DOMAIN_READ_PASSWORD_PARAMETERS 0x0001\n#define DOMAIN_WRITE_PASSWORD_PARAMS 0x0002\n#define DOMAIN_READ_OTHER_PARAMETERS 0x0004\n#define DOMAIN_WRITE_OTHER_PARAMETERS 0x0008\n#define DOMAIN_CREATE_USER 0x0010\n#define DOMAIN_CREATE_GROUP 0x0020\n#define DOMAIN_CREATE_ALIAS 0x0040\n#define DOMAIN_GET_ALIAS_MEMBERSHIP 0x0080\n#define DOMAIN_LIST_ACCOUNTS 0x0100\n#define DOMAIN_LOOKUP 0x0200\n#define DOMAIN_ADMINISTER_SERVER 0x0400\n\n#define DOMAIN_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \\\n    DOMAIN_READ_OTHER_PARAMETERS | \\\n    DOMAIN_WRITE_OTHER_PARAMETERS | \\\n    DOMAIN_WRITE_PASSWORD_PARAMS | \\\n    DOMAIN_CREATE_USER | \\\n    DOMAIN_CREATE_GROUP | \\\n    DOMAIN_CREATE_ALIAS | \\\n    DOMAIN_GET_ALIAS_MEMBERSHIP | \\\n    DOMAIN_LIST_ACCOUNTS | \\\n    DOMAIN_READ_PASSWORD_PARAMETERS | \\\n    DOMAIN_LOOKUP | \\\n    DOMAIN_ADMINISTER_SERVER)\n\n#define DOMAIN_READ (STANDARD_RIGHTS_READ | \\\n    DOMAIN_GET_ALIAS_MEMBERSHIP | \\\n    DOMAIN_READ_OTHER_PARAMETERS)\n\n#define DOMAIN_WRITE (STANDARD_RIGHTS_WRITE | \\\n    DOMAIN_WRITE_OTHER_PARAMETERS | \\\n    DOMAIN_WRITE_PASSWORD_PARAMS | \\\n    DOMAIN_CREATE_USER | \\\n    DOMAIN_CREATE_GROUP | \\\n    DOMAIN_CREATE_ALIAS | \\\n    DOMAIN_ADMINISTER_SERVER)\n\n#define DOMAIN_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    DOMAIN_READ_PASSWORD_PARAMETERS | \\\n    DOMAIN_LIST_ACCOUNTS | \\\n    DOMAIN_LOOKUP)\n\n#define DOMAIN_PROMOTION_INCREMENT { 0x0, 0x10 }\n#define DOMAIN_PROMOTION_MASK { 0x0, 0xfffffff0 }\n\n//\n// SamQueryInformationDomain/SamSetInformationDomain types\n//\n\ntypedef enum _DOMAIN_INFORMATION_CLASS\n{\n    DomainPasswordInformation = 1,      // qs: DOMAIN_PASSWORD_INFORMATION\n    DomainGeneralInformation,           // q: DOMAIN_GENERAL_INFORMATION\n    DomainLogoffInformation,            // qs: DOMAIN_LOGOFF_INFORMATION\n    DomainOemInformation,               // qs: DOMAIN_OEM_INFORMATION\n    DomainNameInformation,              // q: DOMAIN_NAME_INFORMATION\n    DomainReplicationInformation,       // qs: DOMAIN_REPLICATION_INFORMATION\n    DomainServerRoleInformation,        // qs: DOMAIN_SERVER_ROLE_INFORMATION\n    DomainModifiedInformation,          // q: DOMAIN_MODIFIED_INFORMATION\n    DomainStateInformation,             // qs: DOMAIN_STATE_INFORMATION\n    DomainUasInformation,               // qs: DOMAIN_UAS_INFORMATION\n    DomainGeneralInformation2,          // q: DOMAIN_GENERAL_INFORMATION2\n    DomainLockoutInformation,           // qs: DOMAIN_LOCKOUT_INFORMATION\n    DomainModifiedInformation2,         // q: DOMAIN_MODIFIED_INFORMATION2\n    DomainMaxInformation\n} DOMAIN_INFORMATION_CLASS;\n\ntypedef enum _DOMAIN_SERVER_ENABLE_STATE\n{\n    DomainServerEnabled = 1,\n    DomainServerDisabled\n} DOMAIN_SERVER_ENABLE_STATE, *PDOMAIN_SERVER_ENABLE_STATE;\n\ntypedef enum _DOMAIN_SERVER_ROLE\n{\n    DomainServerRoleBackup = 2,\n    DomainServerRolePrimary\n} DOMAIN_SERVER_ROLE, *PDOMAIN_SERVER_ROLE;\n\ntypedef struct _DOMAIN_GENERAL_INFORMATION\n{\n    LARGE_INTEGER ForceLogoff;\n    UNICODE_STRING OemInformation;\n    UNICODE_STRING DomainName;\n    UNICODE_STRING ReplicaSourceNodeName;\n    LARGE_INTEGER DomainModifiedCount;\n    DOMAIN_SERVER_ENABLE_STATE DomainServerState;\n    DOMAIN_SERVER_ROLE DomainServerRole;\n    BOOLEAN UasCompatibilityRequired;\n    ULONG UserCount;\n    ULONG GroupCount;\n    ULONG AliasCount;\n} DOMAIN_GENERAL_INFORMATION, *PDOMAIN_GENERAL_INFORMATION;\n\ntypedef struct _DOMAIN_GENERAL_INFORMATION2\n{\n    DOMAIN_GENERAL_INFORMATION I1;\n    LARGE_INTEGER LockoutDuration; // delta time\n    LARGE_INTEGER LockoutObservationWindow; // delta time\n    USHORT LockoutThreshold;\n} DOMAIN_GENERAL_INFORMATION2, *PDOMAIN_GENERAL_INFORMATION2;\n\ntypedef struct _DOMAIN_UAS_INFORMATION\n{\n    BOOLEAN UasCompatibilityRequired;\n} DOMAIN_UAS_INFORMATION;\n\n#ifndef _DOMAIN_PASSWORD_INFORMATION_DEFINED // defined in ntsecapi.h\n#define _DOMAIN_PASSWORD_INFORMATION_DEFINED\n\ntypedef struct _DOMAIN_PASSWORD_INFORMATION\n{\n    USHORT MinPasswordLength;\n    USHORT PasswordHistoryLength;\n    ULONG PasswordProperties;\n    LARGE_INTEGER MaxPasswordAge;\n    LARGE_INTEGER MinPasswordAge;\n} DOMAIN_PASSWORD_INFORMATION, *PDOMAIN_PASSWORD_INFORMATION;\n\n//\n// PasswordProperties flags\n//\n\n#define DOMAIN_PASSWORD_COMPLEX 0x00000001L\n#define DOMAIN_PASSWORD_NO_ANON_CHANGE 0x00000002L\n#define DOMAIN_PASSWORD_NO_CLEAR_CHANGE 0x00000004L\n#define DOMAIN_LOCKOUT_ADMINS 0x00000008L\n#define DOMAIN_PASSWORD_STORE_CLEARTEXT 0x00000010L\n#define DOMAIN_REFUSE_PASSWORD_CHANGE 0x00000020L\n#define DOMAIN_NO_LM_OWF_CHANGE 0x00000040L\n\n#endif // _DOMAIN_PASSWORD_INFORMATION_DEFINED\n\ntypedef enum _DOMAIN_PASSWORD_CONSTRUCTION\n{\n    DomainPasswordSimple = 1,\n    DomainPasswordComplex\n} DOMAIN_PASSWORD_CONSTRUCTION;\n\ntypedef struct _DOMAIN_LOGOFF_INFORMATION\n{\n    LARGE_INTEGER ForceLogoff;\n} DOMAIN_LOGOFF_INFORMATION, *PDOMAIN_LOGOFF_INFORMATION;\n\ntypedef struct _DOMAIN_OEM_INFORMATION\n{\n    UNICODE_STRING OemInformation;\n} DOMAIN_OEM_INFORMATION, *PDOMAIN_OEM_INFORMATION;\n\ntypedef struct _DOMAIN_NAME_INFORMATION\n{\n    UNICODE_STRING DomainName;\n} DOMAIN_NAME_INFORMATION, *PDOMAIN_NAME_INFORMATION;\n\ntypedef struct _DOMAIN_SERVER_ROLE_INFORMATION\n{\n    DOMAIN_SERVER_ROLE DomainServerRole;\n} DOMAIN_SERVER_ROLE_INFORMATION, *PDOMAIN_SERVER_ROLE_INFORMATION;\n\ntypedef struct _DOMAIN_REPLICATION_INFORMATION\n{\n    UNICODE_STRING ReplicaSourceNodeName;\n} DOMAIN_REPLICATION_INFORMATION, *PDOMAIN_REPLICATION_INFORMATION;\n\ntypedef struct _DOMAIN_MODIFIED_INFORMATION\n{\n    LARGE_INTEGER DomainModifiedCount;\n    LARGE_INTEGER CreationTime;\n} DOMAIN_MODIFIED_INFORMATION, *PDOMAIN_MODIFIED_INFORMATION;\n\ntypedef struct _DOMAIN_MODIFIED_INFORMATION2\n{\n    LARGE_INTEGER DomainModifiedCount;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER ModifiedCountAtLastPromotion;\n} DOMAIN_MODIFIED_INFORMATION2, *PDOMAIN_MODIFIED_INFORMATION2;\n\ntypedef struct _DOMAIN_STATE_INFORMATION\n{\n    DOMAIN_SERVER_ENABLE_STATE DomainServerState;\n} DOMAIN_STATE_INFORMATION, *PDOMAIN_STATE_INFORMATION;\n\ntypedef struct _DOMAIN_LOCKOUT_INFORMATION\n{\n    LARGE_INTEGER LockoutDuration; // delta time\n    LARGE_INTEGER LockoutObservationWindow; // delta time\n    USHORT LockoutThreshold; // zero means no lockout\n} DOMAIN_LOCKOUT_INFORMATION, *PDOMAIN_LOCKOUT_INFORMATION;\n\n//\n// SamQueryDisplayInformation types\n//\n\ntypedef enum _DOMAIN_DISPLAY_INFORMATION\n{\n    DomainDisplayUser = 1,      // DOMAIN_DISPLAY_USER\n    DomainDisplayMachine,       // DOMAIN_DISPLAY_MACHINE\n    DomainDisplayGroup,         // DOMAIN_DISPLAY_GROUP\n    DomainDisplayOemUser,       // DOMAIN_DISPLAY_OEM_USER\n    DomainDisplayOemGroup,      // DOMAIN_DISPLAY_OEM_GROUP\n    DomainDisplayServer,        // DOMAIN_DISPLAY_MACHINE\n    DomainDisplayMax\n} DOMAIN_DISPLAY_INFORMATION, *PDOMAIN_DISPLAY_INFORMATION;\n\ntypedef struct _DOMAIN_DISPLAY_USER\n{\n    ULONG Index;\n    ULONG Rid;\n    ULONG AccountControl;\n    UNICODE_STRING LogonName;\n    UNICODE_STRING AdminComment;\n    UNICODE_STRING FullName;\n} DOMAIN_DISPLAY_USER, *PDOMAIN_DISPLAY_USER;\n\ntypedef struct _DOMAIN_DISPLAY_MACHINE\n{\n    ULONG Index;\n    ULONG Rid;\n    ULONG AccountControl;\n    UNICODE_STRING Machine;\n    UNICODE_STRING Comment;\n} DOMAIN_DISPLAY_MACHINE, *PDOMAIN_DISPLAY_MACHINE;\n\ntypedef struct _DOMAIN_DISPLAY_GROUP\n{\n    ULONG Index;\n    ULONG Rid;\n    ULONG Attributes;\n    UNICODE_STRING Group;\n    UNICODE_STRING Comment;\n} DOMAIN_DISPLAY_GROUP, *PDOMAIN_DISPLAY_GROUP;\n\ntypedef struct _DOMAIN_DISPLAY_OEM_USER\n{\n    ULONG Index;\n    OEM_STRING User;\n} DOMAIN_DISPLAY_OEM_USER, *PDOMAIN_DISPLAY_OEM_USER;\n\ntypedef struct _DOMAIN_DISPLAY_OEM_GROUP\n{\n    ULONG Index;\n    OEM_STRING Group;\n} DOMAIN_DISPLAY_OEM_GROUP, *PDOMAIN_DISPLAY_OEM_GROUP;\n\n//\n// SamQueryLocalizableAccountsInDomain types\n//\n\ntypedef enum _DOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION\n{\n    DomainLocalizableAccountsBasic = 1,\n} DOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION, *PDOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION;\n\ntypedef struct _DOMAIN_LOCALIZABLE_ACCOUNTS_ENTRY\n{\n    ULONG Rid;\n    SID_NAME_USE Use;\n    UNICODE_STRING Name;\n    UNICODE_STRING AdminComment;\n} DOMAIN_LOCALIZABLE_ACCOUNT_ENTRY, *PDOMAIN_LOCALIZABLE_ACCOUNT_ENTRY;\n\ntypedef struct _DOMAIN_LOCALIZABLE_ACCOUNTS\n{\n    ULONG Count;\n    _Field_size_(Count) DOMAIN_LOCALIZABLE_ACCOUNT_ENTRY *Entries;\n} DOMAIN_LOCALIZABLE_ACCOUNTS_BASIC, *PDOMAIN_LOCALIZABLE_ACCOUNTS_BASIC;\n\ntypedef union _DOMAIN_LOCALIZABLE_INFO_BUFFER\n{\n    DOMAIN_LOCALIZABLE_ACCOUNTS_BASIC Basic;\n} DOMAIN_LOCALIZABLE_ACCOUNTS_INFO_BUFFER, *PDOMAIN_LOCALIZABLE_ACCOUNTS_INFO_BUFFER;\n\n//\n// Functions\n//\n\n/**\n * The SamLookupDomainInSamServer method obtains the SID of a domain, given the object's name.\n *\n * \\param ServerHandle A handle representing a server.\n * \\param Name A UTF-16 encoded string.\n * \\param DomainId A SID value of a domain that corresponds to the Name.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/47492d59-e095-4398-b03e-8a062b989123\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamLookupDomainInSamServer(\n    _In_ SAM_HANDLE ServerHandle,\n    _In_ PCUNICODE_STRING Name,\n    _Outptr_ PSID *DomainId\n    );\n\n/**\n * The SamEnumerateDomainsInSamServer method obtains a listing of all domains hosted by the server side of this protocol.\n *\n * \\param ServerHandle A handle representing a server.\n * \\param EnumerationContext An opaque value that the server can use to continue an enumeration on a subsequent call.\n * \\param Buffer A listing of domain information.\n * \\param PreferedMaximumLength The requested maximum number of bytes to return in Buffer.\n * \\param CountReturned The count of domain elements returned in Buffer.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/2142fd2d-0854-42c1-a9fb-2fe964e381ce\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamEnumerateDomainsInSamServer(\n    _In_ SAM_HANDLE ServerHandle,\n    _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext,\n    _Outptr_ PVOID *Buffer, // PSAM_SID_ENUMERATION *Buffer\n    _In_ ULONG PreferedMaximumLength,\n    _Out_ PULONG CountReturned\n    );\n\n/**\n * The SamOpenDomain method obtains a handle to a domain, given a SID.\n *\n * \\param ServerHandle A handle representing a server.\n * \\param DesiredAccess The desired access to the domain.\n * \\param DomainId A SID value of a domain hosted by the server.\n * \\param DomainHandle A handle to the requested domain.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/ba710c90-5b12-42f8-9e5a-d4aacc1329fa\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamOpenDomain(\n    _In_ SAM_HANDLE ServerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PSID DomainId,\n    _Out_ PSAM_HANDLE DomainHandle\n    );\n\n/**\n * The SamQueryInformationDomain method obtains attributes from a domain object.\n *\n * \\param DomainHandle A handle representing a domain.\n * \\param DomainInformationClass An enumeration indicating which attributes to return.\n * \\param Buffer The requested attributes on output.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/5d6a2817-caa9-41ca-a269-fd13ecbb4fa8\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamQueryInformationDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ DOMAIN_INFORMATION_CLASS DomainInformationClass,\n    _Outptr_ PVOID *Buffer\n    );\n\n/**\n * The SamSetInformationDomain method updates attributes of a domain object.\n *\n * \\param DomainHandle A handle representing a domain.\n * \\param DomainInformationClass An enumeration indicating which attributes to update.\n * \\param Buffer The provided attributes on output.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamSetInformationDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ DOMAIN_INFORMATION_CLASS DomainInformationClass,\n    _In_ PVOID Buffer\n    );\n\n/**\n * The SamLookupNamesInDomain method translates a set of account names into a set of RIDs.\n *\n * \\param DomainHandle A handle representing a domain.\n * \\param Count The number of elements in Names.\n * \\param Names An array of strings that are to be mapped to RIDs.\n * \\param RelativeIds An array of RIDs of accounts that correspond to the elements in Names.\n * \\param Use An array of SID_NAME_USE enumeration values that describe the type of account for each entry in RelativeIds.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/d91271c6-7b2e-4194-9927-8fabfa429f90\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamLookupNamesInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ULONG Count,\n    _In_reads_(Count) PCUNICODE_STRING Names,\n    _Out_ _Deref_post_count_(Count) PULONG *RelativeIds,\n    _Out_ _Deref_post_count_(Count) PSID_NAME_USE *Use\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamLookupNamesInDomain2(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ULONG Count,\n    _In_reads_(Count) PCUNICODE_STRING Names,\n    _Out_ _Deref_post_count_(Count) PSID* Sids,\n    _Out_ _Deref_post_count_(Count) PSID_NAME_USE* Use\n    );\n\n/**\n * The SamLookupIdsInDomain method translates a set of RIDs into account names.\n *\n * \\param DomainHandle A handle representing a domain.\n * \\param Count The number of elements in RelativeIds.\n * \\param RelativeIds An array of RIDs that are to be mapped to account names.\n * \\param Names An array of account names that correspond to the elements in RelativeIds.\n * \\param Use An array of SID_NAME_USE enumeration values that describe the type of account for each entry in RelativeIds.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/c870951c-74b3-4714-9857-224595ffc61a\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamLookupIdsInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ULONG Count,\n    _In_reads_(Count) PULONG RelativeIds,\n    _Out_ _Deref_post_count_(Count) PUNICODE_STRING *Names,\n    _Out_ _Deref_post_opt_count_(Count) PSID_NAME_USE *Use\n    );\n\n/**\n * The SamRemoveMemberFromForeignDomain method removes a member from all aliases.\n *\n * \\param DomainHandle A handle representing a domain.\n * \\param MemberId The SID to remove from the membership.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/03afc843-584d-473b-834a-3f5a1ac86cce\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamRemoveMemberFromForeignDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PSID MemberId\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamQueryLocalizableAccountsInDomain(\n    _In_ SAM_HANDLE Domain,\n    _In_ ULONG Flags,\n    _In_ ULONG LanguageId,\n    _In_ DOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION Class,\n    _Outptr_ PVOID *Buffer\n    );\n\n//\n// Group\n//\n\n#define GROUP_READ_INFORMATION 0x0001\n#define GROUP_WRITE_ACCOUNT 0x0002\n#define GROUP_ADD_MEMBER 0x0004\n#define GROUP_REMOVE_MEMBER 0x0008\n#define GROUP_LIST_MEMBERS 0x0010\n\n#define GROUP_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \\\n    GROUP_LIST_MEMBERS | \\\n    GROUP_WRITE_ACCOUNT | \\\n    GROUP_ADD_MEMBER | \\\n    GROUP_REMOVE_MEMBER | \\\n    GROUP_READ_INFORMATION)\n\n#define GROUP_READ (STANDARD_RIGHTS_READ | \\\n    GROUP_LIST_MEMBERS)\n\n#define GROUP_WRITE (STANDARD_RIGHTS_WRITE | \\\n    GROUP_WRITE_ACCOUNT | \\\n    GROUP_ADD_MEMBER | \\\n    GROUP_REMOVE_MEMBER)\n\n#define GROUP_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    GROUP_READ_INFORMATION)\n\ntypedef struct _GROUP_MEMBERSHIP\n{\n    ULONG RelativeId;\n    ULONG Attributes;\n} GROUP_MEMBERSHIP, *PGROUP_MEMBERSHIP;\n\n//\n// SamQueryInformationGroup/SamSetInformationGroup types\n//\n\ntypedef enum _GROUP_INFORMATION_CLASS\n{\n    GroupGeneralInformation = 1,        // q: GROUP_GENERAL_INFORMATION\n    GroupNameInformation,               // qs: GROUP_NAME_INFORMATION\n    GroupAttributeInformation,          // qs: GROUP_ATTRIBUTE_INFORMATION\n    GroupAdminCommentInformation,       // qs: GROUP_ADM_COMMENT_INFORMATION\n    GroupReplicationInformation,        // q: GROUP_REPLICATION_INFORMATION\n    GroupMaxInformation\n} GROUP_INFORMATION_CLASS;\n\ntypedef struct _GROUP_GENERAL_INFORMATION\n{\n    UNICODE_STRING Name;\n    ULONG Attributes;\n    ULONG MemberCount;\n    UNICODE_STRING AdminComment;\n} GROUP_GENERAL_INFORMATION, *PGROUP_GENERAL_INFORMATION;\n\ntypedef struct _GROUP_NAME_INFORMATION\n{\n    UNICODE_STRING Name;\n} GROUP_NAME_INFORMATION, *PGROUP_NAME_INFORMATION;\n\ntypedef struct _GROUP_ATTRIBUTE_INFORMATION\n{\n    ULONG Attributes;\n} GROUP_ATTRIBUTE_INFORMATION, *PGROUP_ATTRIBUTE_INFORMATION;\n\ntypedef struct _GROUP_ADM_COMMENT_INFORMATION\n{\n    UNICODE_STRING AdminComment;\n} GROUP_ADM_COMMENT_INFORMATION, *PGROUP_ADM_COMMENT_INFORMATION;\n\ntypedef struct _GROUP_REPLICATION_INFORMATION\n{\n    LARGE_INTEGER LastWriteTime;\n} GROUP_REPLICATION_INFORMATION, *PGROUP_REPLICATION_INFORMATION;\n\n//\n// Functions\n//\n\n/**\n * The SamEnumerateGroupsInDomain method enumerates all groups.\n *\n * \\param DomainHandle A handle representing a domain.\n * \\param EnumerationContext An opaque value that the server can use to continue an enumeration on a subsequent call.\n * \\param Buffer A listing of group information.\n * \\param PreferedMaximumLength The requested maximum number of bytes to return in Buffer.\n * \\param CountReturned The count of domain elements returned in Buffer.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/e0b7a4b7-ecfc-405f-9d7d-32b3cd2cd6c8\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamEnumerateGroupsInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext,\n    _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION *\n    _In_ ULONG PreferedMaximumLength,\n    _Out_ PULONG CountReturned\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamCreateGroupInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PCUNICODE_STRING AccountName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE GroupHandle,\n    _Out_ PULONG RelativeId\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamOpenGroup(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG GroupId,\n    _Out_ PSAM_HANDLE GroupHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamDeleteGroup(\n    _In_ SAM_HANDLE GroupHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamQueryInformationGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ GROUP_INFORMATION_CLASS GroupInformationClass,\n    _Outptr_ PVOID *Buffer\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamSetInformationGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ GROUP_INFORMATION_CLASS GroupInformationClass,\n    _In_ PVOID Buffer\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamAddMemberToGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ ULONG MemberId,\n    _In_ ULONG Attributes\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamRemoveMemberFromGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ ULONG MemberId\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamGetMembersInGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _Out_ _Deref_post_count_(*MemberCount) PULONG *MemberIds,\n    _Out_ _Deref_post_count_(*MemberCount) PULONG *Attributes,\n    _Out_ PULONG MemberCount\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamSetMemberAttributesOfGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ ULONG MemberId,\n    _In_ ULONG Attributes\n    );\n\n//\n// Alias\n//\n\n#define ALIAS_ADD_MEMBER 0x0001\n#define ALIAS_REMOVE_MEMBER 0x0002\n#define ALIAS_LIST_MEMBERS 0x0004\n#define ALIAS_READ_INFORMATION 0x0008\n#define ALIAS_WRITE_ACCOUNT 0x0010\n\n#define ALIAS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \\\n    ALIAS_READ_INFORMATION | \\\n    ALIAS_WRITE_ACCOUNT | \\\n    ALIAS_LIST_MEMBERS | \\\n    ALIAS_ADD_MEMBER | \\\n    ALIAS_REMOVE_MEMBER)\n\n#define ALIAS_READ (STANDARD_RIGHTS_READ | \\\n    ALIAS_LIST_MEMBERS)\n\n#define ALIAS_WRITE (STANDARD_RIGHTS_WRITE | \\\n    ALIAS_WRITE_ACCOUNT | \\\n    ALIAS_ADD_MEMBER | \\\n    ALIAS_REMOVE_MEMBER)\n\n#define ALIAS_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    ALIAS_READ_INFORMATION)\n\n//\n// SamQueryInformationAlias/SamSetInformationAlias types\n//\n\ntypedef enum _ALIAS_INFORMATION_CLASS\n{\n    AliasGeneralInformation = 1,        // q: ALIAS_GENERAL_INFORMATION\n    AliasNameInformation,               // qs: ALIAS_NAME_INFORMATION\n    AliasAdminCommentInformation,       // qs: ALIAS_ADM_COMMENT_INFORMATION\n    AliasReplicationInformation,        // q: ALIAS_REPLICATION_INFORMATION\n    AliasExtendedInformation,           // q: ALIAS_EXTENDED_INFORMATION\n    AliasMaxInformation\n} ALIAS_INFORMATION_CLASS;\n\ntypedef struct _ALIAS_GENERAL_INFORMATION\n{\n    UNICODE_STRING Name;\n    ULONG MemberCount;\n    UNICODE_STRING AdminComment;\n} ALIAS_GENERAL_INFORMATION, *PALIAS_GENERAL_INFORMATION;\n\ntypedef struct _ALIAS_NAME_INFORMATION\n{\n    UNICODE_STRING Name;\n} ALIAS_NAME_INFORMATION, *PALIAS_NAME_INFORMATION;\n\ntypedef struct _ALIAS_ADM_COMMENT_INFORMATION\n{\n    UNICODE_STRING AdminComment;\n} ALIAS_ADM_COMMENT_INFORMATION, *PALIAS_ADM_COMMENT_INFORMATION;\n\ntypedef struct _ALIAS_REPLICATION_INFORMATION\n{\n    LARGE_INTEGER LastWriteTime;\n} ALIAS_REPLICATION_INFORMATION, *PALIAS_REPLICATION_INFORMATION;\n\n#define ALIAS_ALL_NAME (0x00000001L)\n#define ALIAS_ALL_MEMBER_COUNT (0x00000002L)\n#define ALIAS_ALL_ADMIN_COMMENT (0x00000004L)\n#define ALIAS_ALL_SHELL_ADMIN_OBJECT_PROPERTIES (0x00000008L)\n\ntypedef struct _ALIAS_EXTENDED_INFORMATION\n{\n    ULONG WhichFields;\n    SAM_SHELL_OBJECT_PROPERTIES ShellAdminObjectProperties;\n} ALIAS_EXTENDED_INFORMATION, *PALIAS_EXTENDED_INFORMATION;\n\n//\n// Functions\n//\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamEnumerateAliasesInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext,\n    _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION *Buffer\n    _In_ ULONG PreferedMaximumLength,\n    _Out_ PULONG CountReturned\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamCreateAliasInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PCUNICODE_STRING AccountName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE AliasHandle,\n    _Out_ PULONG RelativeId\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamOpenAlias(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG AliasId,\n    _Out_ PSAM_HANDLE AliasHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamDeleteAlias(\n    _In_ SAM_HANDLE AliasHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamQueryInformationAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_ ALIAS_INFORMATION_CLASS AliasInformationClass,\n    _Outptr_ PVOID *Buffer\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamSetInformationAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_ ALIAS_INFORMATION_CLASS AliasInformationClass,\n    _In_ PVOID Buffer\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamAddMemberToAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_ PSID MemberId\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamAddMultipleMembersToAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_reads_(MemberCount) PSID *MemberIds,\n    _In_ ULONG MemberCount\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamRemoveMemberFromAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_ PSID MemberId\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamRemoveMultipleMembersFromAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_reads_(MemberCount) PSID *MemberIds,\n    _In_ ULONG MemberCount\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamGetMembersInAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _Out_ _Deref_post_count_(*MemberCount) PSID **MemberIds,\n    _Out_ PULONG MemberCount\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamGetAliasMembership(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ULONG PassedCount,\n    _In_reads_(PassedCount) PSID *Sids,\n    _Out_ PULONG MembershipCount,\n    _Out_ _Deref_post_count_(*MembershipCount) PULONG *Aliases\n    );\n//\n// Group types\n//\n\n#define GROUP_TYPE_BUILTIN_LOCAL_GROUP 0x00000001\n#define GROUP_TYPE_ACCOUNT_GROUP 0x00000002\n#define GROUP_TYPE_RESOURCE_GROUP 0x00000004\n#define GROUP_TYPE_UNIVERSAL_GROUP 0x00000008\n#define GROUP_TYPE_APP_BASIC_GROUP 0x00000010\n#define GROUP_TYPE_APP_QUERY_GROUP 0x00000020\n#define GROUP_TYPE_SECURITY_ENABLED 0x80000000\n\n#define GROUP_TYPE_RESOURCE_BEHAVOIR (GROUP_TYPE_RESOURCE_GROUP | \\\n    GROUP_TYPE_APP_BASIC_GROUP | \\\n    GROUP_TYPE_APP_QUERY_GROUP)\n\n//\n// User\n//\n\n#define USER_READ_GENERAL 0x0001\n#define USER_READ_PREFERENCES 0x0002\n#define USER_WRITE_PREFERENCES 0x0004\n#define USER_READ_LOGON 0x0008\n#define USER_READ_ACCOUNT 0x0010\n#define USER_WRITE_ACCOUNT 0x0020\n#define USER_CHANGE_PASSWORD 0x0040\n#define USER_FORCE_PASSWORD_CHANGE 0x0080\n#define USER_LIST_GROUPS 0x0100\n#define USER_READ_GROUP_INFORMATION 0x0200\n#define USER_WRITE_GROUP_INFORMATION 0x0400\n\n#define USER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \\\n    USER_READ_PREFERENCES | \\\n    USER_READ_LOGON | \\\n    USER_LIST_GROUPS | \\\n    USER_READ_GROUP_INFORMATION | \\\n    USER_WRITE_PREFERENCES | \\\n    USER_CHANGE_PASSWORD | \\\n    USER_FORCE_PASSWORD_CHANGE | \\\n    USER_READ_GENERAL | \\\n    USER_READ_ACCOUNT | \\\n    USER_WRITE_ACCOUNT | \\\n    USER_WRITE_GROUP_INFORMATION)\n\n#define USER_READ (STANDARD_RIGHTS_READ | \\\n    USER_READ_PREFERENCES | \\\n    USER_READ_LOGON | \\\n    USER_READ_ACCOUNT | \\\n    USER_LIST_GROUPS | \\\n    USER_READ_GROUP_INFORMATION)\n\n#define USER_WRITE (STANDARD_RIGHTS_WRITE | \\\n    USER_WRITE_PREFERENCES | \\\n    USER_CHANGE_PASSWORD)\n\n#define USER_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    USER_READ_GENERAL | \\\n    USER_CHANGE_PASSWORD)\n\n//\n// User account control flags\n//\n\n#define USER_ACCOUNT_DISABLED (0x00000001)\n#define USER_HOME_DIRECTORY_REQUIRED (0x00000002)\n#define USER_PASSWORD_NOT_REQUIRED (0x00000004)\n#define USER_TEMP_DUPLICATE_ACCOUNT (0x00000008)\n#define USER_NORMAL_ACCOUNT (0x00000010)\n#define USER_MNS_LOGON_ACCOUNT (0x00000020)\n#define USER_INTERDOMAIN_TRUST_ACCOUNT (0x00000040)\n#define USER_WORKSTATION_TRUST_ACCOUNT (0x00000080)\n#define USER_SERVER_TRUST_ACCOUNT (0x00000100)\n#define USER_DONT_EXPIRE_PASSWORD (0x00000200)\n#define USER_ACCOUNT_AUTO_LOCKED (0x00000400)\n#define USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED (0x00000800)\n#define USER_SMARTCARD_REQUIRED (0x00001000)\n#define USER_TRUSTED_FOR_DELEGATION (0x00002000)\n#define USER_NOT_DELEGATED (0x00004000)\n#define USER_USE_DES_KEY_ONLY (0x00008000)\n#define USER_DONT_REQUIRE_PREAUTH (0x00010000)\n#define USER_PASSWORD_EXPIRED (0x00020000)\n#define USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION (0x00040000)\n#define USER_NO_AUTH_DATA_REQUIRED (0x00080000)\n#define USER_PARTIAL_SECRETS_ACCOUNT (0x00100000)\n#define USER_USE_AES_KEYS (0x00200000)\n\n#define NEXT_FREE_ACCOUNT_CONTROL_BIT (USER_USE_AES_KEYS << 1)\n\n#define USER_MACHINE_ACCOUNT_MASK ( \\\n    USER_INTERDOMAIN_TRUST_ACCOUNT | \\\n    USER_WORKSTATION_TRUST_ACCOUNT | \\\n    USER_SERVER_TRUST_ACCOUNT \\\n    )\n\n#define USER_ACCOUNT_TYPE_MASK ( \\\n    USER_TEMP_DUPLICATE_ACCOUNT | \\\n    USER_NORMAL_ACCOUNT | \\\n    USER_MACHINE_ACCOUNT_MASK \\\n    )\n\n#define USER_COMPUTED_ACCOUNT_CONTROL_BITS ( \\\n    USER_ACCOUNT_AUTO_LOCKED | \\\n    USER_PASSWORD_EXPIRED \\\n    )\n\n// Logon times may be expressed in day, hour, or minute granularity.\n\n#define SAM_DAYS_PER_WEEK (7)\n#define SAM_HOURS_PER_WEEK (24 * SAM_DAYS_PER_WEEK)\n#define SAM_MINUTES_PER_WEEK (60 * SAM_HOURS_PER_WEEK)\n\ntypedef struct _LOGON_HOURS\n{\n    USHORT UnitsPerWeek;\n\n    // UnitsPerWeek is the number of equal length time units the week is\n    // divided into. This value is used to compute the length of the bit\n    // string in logon_hours. Must be less than or equal to\n    // SAM_UNITS_PER_WEEK (10080) for this release.\n    //\n    // LogonHours is a bit map of valid logon times. Each bit represents\n    // a unique division in a week. The largest bit map supported is 1260\n    // bytes (10080 bits), which represents minutes per week. In this case\n    // the first bit (bit 0, byte 0) is Sunday, 00:00:00 - 00-00:59; bit 1,\n    // byte 0 is Sunday, 00:01:00 - 00:01:59, etc. A NULL pointer means\n    // DONT_CHANGE for SamSetInformationUser() calls.\n\n    PUCHAR LogonHours;\n} LOGON_HOURS, *PLOGON_HOURS;\n\n/**\n * The SR_SECURITY_DESCRIPTOR structure contains information about the security privileges of the user.\n *\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/subauth/ns-subauth-sr_security_descriptor\n */\ntypedef struct _SR_SECURITY_DESCRIPTOR\n{\n    ULONG Length;                   // Indicates the size in bytes of the structure.\n    PUCHAR SecurityDescriptor;      // Indicates the user's security privileges.\n} SR_SECURITY_DESCRIPTOR, *PSR_SECURITY_DESCRIPTOR;\n\n//\n// SamQueryInformationUser/SamSetInformationUser types\n//\n\ntypedef enum _USER_INFORMATION_CLASS\n{\n    UserGeneralInformation = 1,     // q: USER_GENERAL_INFORMATION\n    UserPreferencesInformation,     // qs: USER_PREFERENCES_INFORMATION\n    UserLogonInformation,           // q: USER_LOGON_INFORMATION\n    UserLogonHoursInformation,      // qs: USER_LOGON_HOURS_INFORMATION\n    UserAccountInformation,         // q: USER_ACCOUNT_INFORMATION\n    UserNameInformation,            // qs: USER_NAME_INFORMATION\n    UserAccountNameInformation,     // qs: USER_ACCOUNT_NAME_INFORMATION\n    UserFullNameInformation,        // qs: USER_FULL_NAME_INFORMATION\n    UserPrimaryGroupInformation,    // qs: USER_PRIMARY_GROUP_INFORMATION\n    UserHomeInformation,            // qs: USER_HOME_INFORMATION // 10\n    UserScriptInformation,          // qs: USER_SCRIPT_INFORMATION\n    UserProfileInformation,         // qs: USER_PROFILE_INFORMATION\n    UserAdminCommentInformation,    // qs: USER_ADMIN_COMMENT_INFORMATION\n    UserWorkStationsInformation,    // qs: USER_WORKSTATIONS_INFORMATION\n    UserSetPasswordInformation,     // s: USER_SET_PASSWORD_INFORMATION\n    UserControlInformation,         // qs: USER_CONTROL_INFORMATION\n    UserExpiresInformation,         // qs: USER_EXPIRES_INFORMATION\n    UserInternal1Information,       // qs: USER_INTERNAL1_INFORMATION\n    UserInternal2Information,       // qs: USER_INTERNAL2_INFORMATION\n    UserParametersInformation,      // qs: USER_PARAMETERS_INFORMATION // 20\n    UserAllInformation,             // qs: USER_ALL_INFORMATION\n    UserInternal3Information,       // qs: USER_INTERNAL3_INFORMATION\n    UserInternal4Information,       // qs: USER_INTERNAL4_INFORMATION\n    UserInternal5Information,       // qs: USER_INTERNAL5_INFORMATION\n    UserInternal4InformationNew,    // qs: USER_INTERNAL4_INFORMATION_NEW\n    UserInternal5InformationNew,    // qs: USER_INTERNAL5_INFORMATION_NEW\n    UserInternal6Information,       // qs: USER_INTERNAL6_INFORMATION\n    UserExtendedInformation,        // qs: USER_EXTENDED_INFORMATION\n    UserLogonUIInformation,         // q: USER_LOGON_UI_INFORMATION // since VISTA\n    UserAuthInformation,            // qs: USER_AUTH_INFORMATION // since WIN10 // 30\n    UserInternal7Information,       // qs: USER_INTERNAL7_INFORMATION // since 20H1\n    UserInternal8Information,       // qs: USER_INTERNAL8_INFORMATION\n    UserMaxInformation\n} USER_INFORMATION_CLASS, *PUSER_INFORMATION_CLASS;\n\ntypedef struct _USER_GENERAL_INFORMATION\n{\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n    ULONG PrimaryGroupId;\n    UNICODE_STRING AdminComment;\n    UNICODE_STRING UserComment;\n} USER_GENERAL_INFORMATION, *PUSER_GENERAL_INFORMATION;\n\ntypedef struct _USER_PREFERENCES_INFORMATION\n{\n    UNICODE_STRING UserComment;\n    UNICODE_STRING Reserved1;\n    USHORT CountryCode;\n    USHORT CodePage;\n} USER_PREFERENCES_INFORMATION, *PUSER_PREFERENCES_INFORMATION;\n\ntypedef struct _USER_LOGON_INFORMATION\n{\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n    ULONG UserId;\n    ULONG PrimaryGroupId;\n    UNICODE_STRING HomeDirectory;\n    UNICODE_STRING HomeDirectoryDrive;\n    UNICODE_STRING ScriptPath;\n    UNICODE_STRING ProfilePath;\n    UNICODE_STRING WorkStations;\n    LARGE_INTEGER LastLogon;\n    LARGE_INTEGER LastLogoff;\n    LARGE_INTEGER PasswordLastSet;\n    LARGE_INTEGER PasswordCanChange;\n    LARGE_INTEGER PasswordMustChange;\n    LOGON_HOURS LogonHours;\n    USHORT BadPasswordCount;\n    USHORT LogonCount;\n    ULONG UserAccountControl;\n} USER_LOGON_INFORMATION, *PUSER_LOGON_INFORMATION;\n\ntypedef struct _USER_LOGON_HOURS_INFORMATION\n{\n    LOGON_HOURS LogonHours;\n} USER_LOGON_HOURS_INFORMATION, *PUSER_LOGON_HOURS_INFORMATION;\n\ntypedef struct _USER_ACCOUNT_INFORMATION\n{\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n    ULONG UserId;\n    ULONG PrimaryGroupId;\n    UNICODE_STRING HomeDirectory;\n    UNICODE_STRING HomeDirectoryDrive;\n    UNICODE_STRING ScriptPath;\n    UNICODE_STRING ProfilePath;\n    UNICODE_STRING AdminComment;\n    UNICODE_STRING WorkStations;\n    LARGE_INTEGER LastLogon;\n    LARGE_INTEGER LastLogoff;\n    LOGON_HOURS LogonHours;\n    USHORT BadPasswordCount;\n    USHORT LogonCount;\n    LARGE_INTEGER PasswordLastSet;\n    LARGE_INTEGER AccountExpires;\n    ULONG UserAccountControl;\n} USER_ACCOUNT_INFORMATION, *PUSER_ACCOUNT_INFORMATION;\n\ntypedef struct _USER_NAME_INFORMATION\n{\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n} USER_NAME_INFORMATION, *PUSER_NAME_INFORMATION;\n\ntypedef struct _USER_ACCOUNT_NAME_INFORMATION\n{\n    UNICODE_STRING UserName;\n} USER_ACCOUNT_NAME_INFORMATION, *PUSER_ACCOUNT_NAME_INFORMATION;\n\ntypedef struct _USER_FULL_NAME_INFORMATION\n{\n    UNICODE_STRING FullName;\n} USER_FULL_NAME_INFORMATION, *PUSER_FULL_NAME_INFORMATION;\n\ntypedef struct _USER_PRIMARY_GROUP_INFORMATION\n{\n    ULONG PrimaryGroupId;\n} USER_PRIMARY_GROUP_INFORMATION, *PUSER_PRIMARY_GROUP_INFORMATION;\n\ntypedef struct _USER_HOME_INFORMATION\n{\n    UNICODE_STRING HomeDirectory;\n    UNICODE_STRING HomeDirectoryDrive;\n} USER_HOME_INFORMATION, *PUSER_HOME_INFORMATION;\n\ntypedef struct _USER_SCRIPT_INFORMATION\n{\n    UNICODE_STRING ScriptPath;\n} USER_SCRIPT_INFORMATION, *PUSER_SCRIPT_INFORMATION;\n\ntypedef struct _USER_PROFILE_INFORMATION\n{\n    UNICODE_STRING ProfilePath;\n} USER_PROFILE_INFORMATION, *PUSER_PROFILE_INFORMATION;\n\ntypedef struct _USER_ADMIN_COMMENT_INFORMATION\n{\n    UNICODE_STRING AdminComment;\n} USER_ADMIN_COMMENT_INFORMATION, *PUSER_ADMIN_COMMENT_INFORMATION;\n\ntypedef struct _USER_WORKSTATIONS_INFORMATION\n{\n    UNICODE_STRING WorkStations;\n} USER_WORKSTATIONS_INFORMATION, *PUSER_WORKSTATIONS_INFORMATION;\n\ntypedef struct _USER_SET_PASSWORD_INFORMATION\n{\n    UNICODE_STRING Password;\n    BOOLEAN PasswordExpired;\n} USER_SET_PASSWORD_INFORMATION, *PUSER_SET_PASSWORD_INFORMATION;\n\ntypedef struct _USER_CONTROL_INFORMATION\n{\n    ULONG UserAccountControl;\n} USER_CONTROL_INFORMATION, *PUSER_CONTROL_INFORMATION;\n\ntypedef struct _USER_EXPIRES_INFORMATION\n{\n    LARGE_INTEGER AccountExpires;\n} USER_EXPIRES_INFORMATION, *PUSER_EXPIRES_INFORMATION;\n\n#define CYPHER_BLOCK_LENGTH 8\n\ntypedef struct _CYPHER_BLOCK\n{\n    CHAR data[CYPHER_BLOCK_LENGTH];\n} CYPHER_BLOCK, *PCYPHER_BLOCK;\n\ntypedef struct _ENCRYPTED_NT_OWF_PASSWORD\n{\n    CYPHER_BLOCK data[2];\n} ENCRYPTED_NT_OWF_PASSWORD, *PENCRYPTED_NT_OWF_PASSWORD;\n\ntypedef struct _ENCRYPTED_LM_OWF_PASSWORD\n{\n    CYPHER_BLOCK data[2];\n} ENCRYPTED_LM_OWF_PASSWORD, *PENCRYPTED_LM_OWF_PASSWORD;\n\ntypedef struct _USER_INTERNAL1_INFORMATION\n{\n    ENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword;\n    ENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword;\n    BOOLEAN NtPasswordPresent;\n    BOOLEAN LmPasswordPresent;\n    BOOLEAN PasswordExpired;\n} USER_INTERNAL1_INFORMATION, *PUSER_INTERNAL1_INFORMATION;\n\ntypedef struct _USER_INTERNAL2_INFORMATION\n{\n    ULONG StatisticsToApply;\n    LARGE_INTEGER LastLogon;\n    LARGE_INTEGER LastLogoff;\n    USHORT BadPasswordCount;\n    USHORT LogonCount;\n} USER_INTERNAL2_INFORMATION, *PUSER_INTERNAL2_INFORMATION;\n\ntypedef struct _USER_PARAMETERS_INFORMATION\n{\n    UNICODE_STRING Parameters;\n} USER_PARAMETERS_INFORMATION, *PUSER_PARAMETERS_INFORMATION;\n\n//\n// Flags for WhichFields in USER_ALL_INFORMATION\n//\n\n#define USER_ALL_USERNAME 0x00000001\n#define USER_ALL_FULLNAME 0x00000002\n#define USER_ALL_USERID 0x00000004\n#define USER_ALL_PRIMARYGROUPID 0x00000008\n#define USER_ALL_ADMINCOMMENT 0x00000010\n#define USER_ALL_USERCOMMENT 0x00000020\n#define USER_ALL_HOMEDIRECTORY 0x00000040\n#define USER_ALL_HOMEDIRECTORYDRIVE 0x00000080\n#define USER_ALL_SCRIPTPATH 0x00000100\n#define USER_ALL_PROFILEPATH 0x00000200\n#define USER_ALL_WORKSTATIONS 0x00000400\n#define USER_ALL_LASTLOGON 0x00000800\n#define USER_ALL_LASTLOGOFF 0x00001000\n#define USER_ALL_LOGONHOURS 0x00002000\n#define USER_ALL_BADPASSWORDCOUNT 0x00004000\n#define USER_ALL_LOGONCOUNT 0x00008000\n#define USER_ALL_PASSWORDCANCHANGE 0x00010000\n#define USER_ALL_PASSWORDMUSTCHANGE 0x00020000\n#define USER_ALL_PASSWORDLASTSET 0x00040000\n#define USER_ALL_ACCOUNTEXPIRES 0x00080000\n#define USER_ALL_USERACCOUNTCONTROL 0x00100000\n#define USER_ALL_PARAMETERS 0x00200000\n#define USER_ALL_COUNTRYCODE 0x00400000\n#define USER_ALL_CODEPAGE 0x00800000\n#define USER_ALL_NTPASSWORDPRESENT 0x01000000 // field AND boolean\n#define USER_ALL_LMPASSWORDPRESENT 0x02000000 // field AND boolean\n#define USER_ALL_PRIVATEDATA 0x04000000 // field AND boolean\n#define USER_ALL_PASSWORDEXPIRED 0x08000000\n#define USER_ALL_SECURITYDESCRIPTOR 0x10000000\n#define USER_ALL_OWFPASSWORD 0x20000000 // boolean\n\n#define USER_ALL_UNDEFINED_MASK 0xc0000000\n\n// Fields that require USER_READ_GENERAL access to read.\n\n#define USER_ALL_READ_GENERAL_MASK \\\n    (USER_ALL_USERNAME | \\\n    USER_ALL_FULLNAME | \\\n    USER_ALL_USERID | \\\n    USER_ALL_PRIMARYGROUPID | \\\n    USER_ALL_ADMINCOMMENT | \\\n    USER_ALL_USERCOMMENT)\n\n// Fields that require USER_READ_LOGON access to read.\n\n#define USER_ALL_READ_LOGON_MASK \\\n   (USER_ALL_HOMEDIRECTORY | \\\n    USER_ALL_HOMEDIRECTORYDRIVE | \\\n    USER_ALL_SCRIPTPATH | \\\n    USER_ALL_PROFILEPATH | \\\n    USER_ALL_WORKSTATIONS | \\\n    USER_ALL_LASTLOGON | \\\n    USER_ALL_LASTLOGOFF | \\\n    USER_ALL_LOGONHOURS | \\\n    USER_ALL_BADPASSWORDCOUNT | \\\n    USER_ALL_LOGONCOUNT | \\\n    USER_ALL_PASSWORDCANCHANGE | \\\n    USER_ALL_PASSWORDMUSTCHANGE)\n\n// Fields that require USER_READ_ACCOUNT access to read.\n\n#define USER_ALL_READ_ACCOUNT_MASK \\\n    (USER_ALL_PASSWORDLASTSET | \\\n    USER_ALL_ACCOUNTEXPIRES | \\\n    USER_ALL_USERACCOUNTCONTROL | \\\n    USER_ALL_PARAMETERS)\n\n// Fields that require USER_READ_PREFERENCES access to read.\n\n#define USER_ALL_READ_PREFERENCES_MASK \\\n    (USER_ALL_COUNTRYCODE | USER_ALL_CODEPAGE)\n\n// Fields that can only be read by trusted clients.\n\n#define USER_ALL_READ_TRUSTED_MASK \\\n    (USER_ALL_NTPASSWORDPRESENT | \\\n    USER_ALL_LMPASSWORDPRESENT | \\\n    USER_ALL_PASSWORDEXPIRED | \\\n    USER_ALL_SECURITYDESCRIPTOR | \\\n    USER_ALL_PRIVATEDATA)\n\n// Fields that can't be read.\n\n#define USER_ALL_READ_CANT_MASK USER_ALL_UNDEFINED_MASK\n\n// Fields that require USER_WRITE_ACCOUNT access to write.\n\n#define USER_ALL_WRITE_ACCOUNT_MASK \\\n    (USER_ALL_USERNAME | \\\n    USER_ALL_FULLNAME | \\\n    USER_ALL_PRIMARYGROUPID | \\\n    USER_ALL_HOMEDIRECTORY | \\\n    USER_ALL_HOMEDIRECTORYDRIVE | \\\n    USER_ALL_SCRIPTPATH | \\\n    USER_ALL_PROFILEPATH | \\\n    USER_ALL_ADMINCOMMENT | \\\n    USER_ALL_WORKSTATIONS | \\\n    USER_ALL_LOGONHOURS | \\\n    USER_ALL_ACCOUNTEXPIRES | \\\n    USER_ALL_USERACCOUNTCONTROL | \\\n    USER_ALL_PARAMETERS)\n\n// Fields that require USER_WRITE_PREFERENCES access to write.\n\n#define USER_ALL_WRITE_PREFERENCES_MASK \\\n    (USER_ALL_USERCOMMENT | USER_ALL_COUNTRYCODE | USER_ALL_CODEPAGE)\n\n// Fields that require USER_FORCE_PASSWORD_CHANGE access to write.\n//\n// Note that non-trusted clients only set the NT password as a\n// UNICODE string. The wrapper will convert it to an LM password,\n// OWF and encrypt both versions. Trusted clients can pass in OWF\n// versions of either or both.\n\n#define USER_ALL_WRITE_FORCE_PASSWORD_CHANGE_MASK \\\n    (USER_ALL_NTPASSWORDPRESENT | \\\n    USER_ALL_LMPASSWORDPRESENT | \\\n    USER_ALL_PASSWORDEXPIRED)\n\n// Fields that can only be written by trusted clients.\n\n#define USER_ALL_WRITE_TRUSTED_MASK \\\n    (USER_ALL_LASTLOGON | \\\n    USER_ALL_LASTLOGOFF | \\\n    USER_ALL_BADPASSWORDCOUNT | \\\n    USER_ALL_LOGONCOUNT | \\\n    USER_ALL_PASSWORDLASTSET | \\\n    USER_ALL_SECURITYDESCRIPTOR | \\\n    USER_ALL_PRIVATEDATA)\n\n// Fields that can't be written.\n\n#define USER_ALL_WRITE_CANT_MASK \\\n    (USER_ALL_USERID | \\\n    USER_ALL_PASSWORDCANCHANGE | \\\n    USER_ALL_PASSWORDMUSTCHANGE | \\\n    USER_ALL_UNDEFINED_MASK)\n\ntypedef struct _USER_ALL_INFORMATION\n{\n    LARGE_INTEGER LastLogon;\n    LARGE_INTEGER LastLogoff;\n    LARGE_INTEGER PasswordLastSet;\n    LARGE_INTEGER AccountExpires;\n    LARGE_INTEGER PasswordCanChange;\n    LARGE_INTEGER PasswordMustChange;\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n    UNICODE_STRING HomeDirectory;\n    UNICODE_STRING HomeDirectoryDrive;\n    UNICODE_STRING ScriptPath;\n    UNICODE_STRING ProfilePath;\n    UNICODE_STRING AdminComment;\n    UNICODE_STRING WorkStations;\n    UNICODE_STRING UserComment;\n    UNICODE_STRING Parameters;\n    UNICODE_STRING LmPassword;\n    UNICODE_STRING NtPassword;\n    UNICODE_STRING PrivateData;\n    SR_SECURITY_DESCRIPTOR SecurityDescriptor;\n    ULONG UserId;\n    ULONG PrimaryGroupId;\n    ULONG UserAccountControl;\n    ULONG WhichFields;\n    LOGON_HOURS LogonHours;\n    USHORT BadPasswordCount;\n    USHORT LogonCount;\n    USHORT CountryCode;\n    USHORT CodePage;\n    BOOLEAN LmPasswordPresent;\n    BOOLEAN NtPasswordPresent;\n    BOOLEAN PasswordExpired;\n    BOOLEAN PrivateDataSensitive;\n} USER_ALL_INFORMATION, *PUSER_ALL_INFORMATION;\n\ntypedef struct _USER_INTERNAL3_INFORMATION\n{\n    USER_ALL_INFORMATION I1;\n    LARGE_INTEGER LastBadPasswordTime;\n} USER_INTERNAL3_INFORMATION, *PUSER_INTERNAL3_INFORMATION;\n\ntypedef struct _ENCRYPTED_USER_PASSWORD\n{\n    UCHAR Buffer[(SAM_MAX_PASSWORD_LENGTH * 2) + 4];\n} ENCRYPTED_USER_PASSWORD, *PENCRYPTED_USER_PASSWORD;\n\ntypedef struct _USER_INTERNAL4_INFORMATION\n{\n    USER_ALL_INFORMATION I1;\n    ENCRYPTED_USER_PASSWORD UserPassword;\n} USER_INTERNAL4_INFORMATION, *PUSER_INTERNAL4_INFORMATION;\n\ntypedef struct _USER_INTERNAL5_INFORMATION\n{\n    ENCRYPTED_USER_PASSWORD UserPassword;\n    BOOLEAN PasswordExpired;\n} USER_INTERNAL5_INFORMATION, *PUSER_INTERNAL5_INFORMATION;\n\ntypedef struct _ENCRYPTED_USER_PASSWORD_NEW\n{\n    UCHAR Buffer[(SAM_MAX_PASSWORD_LENGTH * 2) + 4 + SAM_PASSWORD_ENCRYPTION_SALT_LEN];\n} ENCRYPTED_USER_PASSWORD_NEW, *PENCRYPTED_USER_PASSWORD_NEW;\n\ntypedef struct _USER_INTERNAL4_INFORMATION_NEW\n{\n    USER_ALL_INFORMATION I1;\n    ENCRYPTED_USER_PASSWORD_NEW UserPassword;\n} USER_INTERNAL4_INFORMATION_NEW, *PUSER_INTERNAL4_INFORMATION_NEW;\n\ntypedef struct _USER_INTERNAL5_INFORMATION_NEW\n{\n    ENCRYPTED_USER_PASSWORD_NEW UserPassword;\n    BOOLEAN PasswordExpired;\n} USER_INTERNAL5_INFORMATION_NEW, *PUSER_INTERNAL5_INFORMATION_NEW;\n\ntypedef struct _USER_ALLOWED_TO_DELEGATE_TO_LIST\n{\n    ULONG Size;\n    ULONG NumSPNs;\n    UNICODE_STRING SPNList[ANYSIZE_ARRAY];\n} USER_ALLOWED_TO_DELEGATE_TO_LIST, *PUSER_ALLOWED_TO_DELEGATE_TO_LIST;\n\n#define USER_EXTENDED_FIELD_UPN 0x00000001L\n#define USER_EXTENDED_FIELD_A2D2 0x00000002L\n\ntypedef struct _USER_INTERNAL6_INFORMATION\n{\n    USER_ALL_INFORMATION I1;\n    LARGE_INTEGER LastBadPasswordTime;\n    ULONG ExtendedFields;\n    BOOLEAN UPNDefaulted;\n    UNICODE_STRING UPN;\n    PUSER_ALLOWED_TO_DELEGATE_TO_LIST A2D2List;\n} USER_INTERNAL6_INFORMATION, *PUSER_INTERNAL6_INFORMATION;\n\ntypedef SAM_BYTE_ARRAY_32K SAM_USER_TILE, *PSAM_USER_TILE;\n\n// 0xff000fff is reserved for internal callers and implementation.\n\n#define USER_EXTENDED_FIELD_USER_TILE (0x00001000L)\n#define USER_EXTENDED_FIELD_PASSWORD_HINT (0x00002000L)\n#define USER_EXTENDED_FIELD_DONT_SHOW_IN_LOGON_UI (0x00004000L)\n#define USER_EXTENDED_FIELD_SHELL_ADMIN_OBJECT_PROPERTIES (0x00008000L)\n\ntypedef struct _USER_EXTENDED_INFORMATION\n{\n    ULONG ExtendedWhichFields;\n    SAM_USER_TILE UserTile;\n    UNICODE_STRING PasswordHint;\n    BOOLEAN DontShowInLogonUI;\n    SAM_SHELL_OBJECT_PROPERTIES ShellAdminObjectProperties;\n} USER_EXTENDED_INFORMATION, *PUSER_EXTENDED_INFORMATION;\n\n// For local callers only.\ntypedef struct _USER_LOGON_UI_INFORMATION\n{\n    BOOLEAN PasswordIsBlank;\n    BOOLEAN AccountIsDisabled;\n} USER_LOGON_UI_INFORMATION, *PUSER_LOGON_UI_INFORMATION;\n\ntypedef struct _USER_AUTH_INFORMATION\n{\n    SAM_BYTE_ARRAY_32K AuthData;\n} USER_AUTH_INFORMATION, *PUSER_AUTH_INFORMATION;\n\ntypedef struct _ENCRYPTED_PASSWORD_AES\n{\n    UCHAR AuthData[64];\n    UCHAR Salt[SAM_PASSWORD_ENCRYPTION_SALT_LEN];\n    ULONG cbCipher;\n    PUCHAR Cipher;\n    ULONGLONG PBKDF2Iterations;\n} ENCRYPTED_PASSWORD_AES, *PENCRYPTED_PASSWORD_AES;\n\ntypedef struct _USER_INTERNAL7_INFORMATION\n{\n    ENCRYPTED_PASSWORD_AES UserPassword;\n    BOOLEAN PasswordExpired;\n} USER_INTERNAL7_INFORMATION, *PUSER_INTERNAL7_INFORMATION;\n\ntypedef struct _USER_INTERNAL8_INFORMATION\n{\n    USER_ALL_INFORMATION I1;\n    ENCRYPTED_PASSWORD_AES UserPassword;\n} USER_INTERNAL8_INFORMATION, *PUSER_INTERNAL8_INFORMATION;\n\n// SamChangePasswordUser3 types\n\n// Error values:\n// * SAM_PWD_CHANGE_NO_ERROR\n// * SAM_PWD_CHANGE_PASSWORD_TOO_SHORT\n// * SAM_PWD_CHANGE_PWD_IN_HISTORY\n// * SAM_PWD_CHANGE_USERNAME_IN_PASSWORD\n// * SAM_PWD_CHANGE_FULLNAME_IN_PASSWORD\n// * SAM_PWD_CHANGE_MACHINE_PASSWORD_NOT_DEFAULT\n// * SAM_PWD_CHANGE_FAILED_BY_FILTER\n\ntypedef struct _USER_PWD_CHANGE_FAILURE_INFORMATION\n{\n    ULONG ExtendedFailureReason;\n    UNICODE_STRING FilterModuleName;\n} USER_PWD_CHANGE_FAILURE_INFORMATION, *PUSER_PWD_CHANGE_FAILURE_INFORMATION;\n\n//\n// ExtendedFailureReason values\n//\n\n#define SAM_PWD_CHANGE_NO_ERROR 0\n#define SAM_PWD_CHANGE_PASSWORD_TOO_SHORT 1\n#define SAM_PWD_CHANGE_PWD_IN_HISTORY 2\n#define SAM_PWD_CHANGE_USERNAME_IN_PASSWORD 3\n#define SAM_PWD_CHANGE_FULLNAME_IN_PASSWORD 4\n#define SAM_PWD_CHANGE_NOT_COMPLEX 5\n#define SAM_PWD_CHANGE_MACHINE_PASSWORD_NOT_DEFAULT 6\n#define SAM_PWD_CHANGE_FAILED_BY_FILTER 7\n#define SAM_PWD_CHANGE_PASSWORD_TOO_LONG 8\n#define SAM_PWD_CHANGE_FAILURE_REASON_MAX 8\n\n//\n// Functions\n//\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamEnumerateUsersInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext,\n    _In_ ULONG UserAccountControl,\n    _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION *\n    _In_ ULONG PreferedMaximumLength,\n    _Out_ PULONG CountReturned\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamEnumerateUsersInDomain2(\n    _In_ SAM_HANDLE DomainHandle,\n    _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext,\n    _In_ ULONG UserAccountControl,\n    _In_ ULONG Flags,\n    _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION *\n    _In_ ULONG PreferedMaximumLength,\n    _Out_ PULONG CountReturned\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamCreateUserInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PCUNICODE_STRING AccountName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE UserHandle,\n    _Out_ PULONG RelativeId\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamCreateUser2InDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PCUNICODE_STRING AccountName,\n    _In_ ULONG AccountType,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE UserHandle,\n    _Out_ PULONG GrantedAccess,\n    _Out_ PULONG RelativeId\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamOpenUser(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG UserId,\n    _Out_ PSAM_HANDLE UserHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamDeleteUser(\n    _In_ SAM_HANDLE UserHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamQueryInformationUser(\n    _In_ SAM_HANDLE UserHandle,\n    _In_ USER_INFORMATION_CLASS UserInformationClass,\n    _Outptr_ PVOID *Buffer\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamSetInformationUser(\n    _In_ SAM_HANDLE UserHandle,\n    _In_ USER_INFORMATION_CLASS UserInformationClass,\n    _In_ PVOID Buffer\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamGetGroupsForUser(\n    _In_ SAM_HANDLE UserHandle,\n    _Out_ _Deref_post_count_(*MembershipCount) PGROUP_MEMBERSHIP *Groups,\n    _Out_ PULONG MembershipCount\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamChangePasswordUser(\n    _In_ SAM_HANDLE UserHandle,\n    _In_ PCUNICODE_STRING OldPassword,\n    _In_ PCUNICODE_STRING NewPassword\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamChangePasswordUser2(\n    _In_ PCUNICODE_STRING ServerName,\n    _In_ PCUNICODE_STRING UserName,\n    _In_ PCUNICODE_STRING OldPassword,\n    _In_ PCUNICODE_STRING NewPassword\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamChangePasswordUser3(\n    _In_ PCUNICODE_STRING ServerName,\n    _In_ PCUNICODE_STRING UserName,\n    _In_ PCUNICODE_STRING OldPassword,\n    _In_ PCUNICODE_STRING NewPassword,\n    _Outptr_ PDOMAIN_PASSWORD_INFORMATION *EffectivePasswordPolicy,\n    _Outptr_ PUSER_PWD_CHANGE_FAILURE_INFORMATION *PasswordChangeFailureInfo\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamQueryDisplayInformation(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ DOMAIN_DISPLAY_INFORMATION DisplayInformation,\n    _In_ ULONG Index,\n    _In_ ULONG EntryCount,\n    _In_ ULONG PreferredMaximumLength,\n    _Out_ PULONG TotalAvailable,\n    _Out_ PULONG TotalReturned,\n    _Out_ PULONG ReturnedEntryCount,\n    _Outptr_ PVOID *SortedBuffer\n    );\n\n/**\n * The SamGetDisplayEnumerationIndex method obtains an index into an ascending account-name–sorted list of accounts.\n *\n * \\param DomainHandle A handle representing a domain.\n * \\param DisplayInformation An enumeration indicating which set of objects to return an index.\n * \\param Prefix A string matched against the account name to find a starting point for an enumeration.\n * \\param Index A value to use as input to SamQueryDisplayInformation in order to control the accounts that are returned from that method.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/bd429624-f2d5-4717-8aa2-659952c3e209\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamGetDisplayEnumerationIndex(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ DOMAIN_DISPLAY_INFORMATION DisplayInformation,\n    _In_ PCUNICODE_STRING Prefix,\n    _Out_ PULONG Index\n    );\n\n//\n// Database replication\n//\n\ntypedef enum _SECURITY_DB_DELTA_TYPE\n{\n    SecurityDbNew = 1,\n    SecurityDbRename,\n    SecurityDbDelete,\n    SecurityDbChangeMemberAdd,\n    SecurityDbChangeMemberSet,\n    SecurityDbChangeMemberDel,\n    SecurityDbChange,\n    SecurityDbChangePassword\n} SECURITY_DB_DELTA_TYPE, *PSECURITY_DB_DELTA_TYPE;\n\ntypedef enum _SECURITY_DB_OBJECT_TYPE\n{\n    SecurityDbObjectSamDomain = 1,\n    SecurityDbObjectSamUser,\n    SecurityDbObjectSamGroup,\n    SecurityDbObjectSamAlias,\n    SecurityDbObjectLsaPolicy,\n    SecurityDbObjectLsaTDomain,\n    SecurityDbObjectLsaAccount,\n    SecurityDbObjectLsaSecret\n} SECURITY_DB_OBJECT_TYPE, *PSECURITY_DB_OBJECT_TYPE;\n\ntypedef enum _SAM_ACCOUNT_TYPE\n{\n    SamObjectUser = 1,\n    SamObjectGroup,\n    SamObjectAlias\n} SAM_ACCOUNT_TYPE, *PSAM_ACCOUNT_TYPE;\n\n#define SAM_USER_ACCOUNT (0x00000001)\n#define SAM_GLOBAL_GROUP_ACCOUNT (0x00000002)\n#define SAM_LOCAL_GROUP_ACCOUNT (0x00000004)\n\ntypedef struct _SAM_GROUP_MEMBER_ID\n{\n    ULONG MemberRid;\n} SAM_GROUP_MEMBER_ID, *PSAM_GROUP_MEMBER_ID;\n\ntypedef struct _SAM_ALIAS_MEMBER_ID\n{\n    PSID MemberSid;\n} SAM_ALIAS_MEMBER_ID, *PSAM_ALIAS_MEMBER_ID;\n\ntypedef union _SAM_DELTA_DATA\n{\n    SAM_GROUP_MEMBER_ID GroupMemberId;\n    SAM_ALIAS_MEMBER_ID AliasMemberId;\n    ULONG AccountControl;\n} SAM_DELTA_DATA, *PSAM_DELTA_DATA;\n\ntypedef _Function_class_(SAM_DELTA_NOTIFICATION_ROUTINE)\nNTSTATUS NTAPI SAM_DELTA_NOTIFICATION_ROUTINE(\n    _In_ PSID DomainSid,\n    _In_ SECURITY_DB_DELTA_TYPE DeltaType,\n    _In_ SECURITY_DB_OBJECT_TYPE ObjectType,\n    _In_ ULONG ObjectRid,\n    _In_opt_ PCUNICODE_STRING ObjectName,\n    _In_ PLARGE_INTEGER ModifiedCount,\n    _In_opt_ PSAM_DELTA_DATA DeltaData\n    );\ntypedef SAM_DELTA_NOTIFICATION_ROUTINE* PSAM_DELTA_NOTIFICATION_ROUTINE;\n\n#define SAM_DELTA_NOTIFY_ROUTINE \"DeltaNotify\"\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamRegisterObjectChangeNotification(\n    _In_ SECURITY_DB_OBJECT_TYPE ObjectType,\n    _In_ HANDLE NotificationEventHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamUnregisterObjectChangeNotification(\n    _In_ SECURITY_DB_OBJECT_TYPE ObjectType,\n    _In_ HANDLE NotificationEventHandle\n    );\n\n//\n// Compatibility mode\n//\n\n#define SAM_SID_COMPATIBILITY_ALL 0\n#define SAM_SID_COMPATIBILITY_LAX 1\n#define SAM_SID_COMPATIBILITY_STRICT 2\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamGetCompatibilityMode(\n    _In_ SAM_HANDLE ObjectHandle,\n    _Out_ ULONG *Mode\n    );\n\n//\n// Password validation\n//\n\ntypedef enum _PASSWORD_POLICY_VALIDATION_TYPE\n{\n    SamValidateAuthentication = 1,\n    SamValidatePasswordChange,\n    SamValidatePasswordReset\n} PASSWORD_POLICY_VALIDATION_TYPE;\n\ntypedef struct _SAM_VALIDATE_PASSWORD_HASH\n{\n    ULONG Length;\n    _Field_size_bytes_(Length) PUCHAR Hash;\n} SAM_VALIDATE_PASSWORD_HASH, *PSAM_VALIDATE_PASSWORD_HASH;\n\n// Flags for PresentFields in SAM_VALIDATE_PERSISTED_FIELDS\n\n#define SAM_VALIDATE_PASSWORD_LAST_SET 0x00000001\n#define SAM_VALIDATE_BAD_PASSWORD_TIME 0x00000002\n#define SAM_VALIDATE_LOCKOUT_TIME 0x00000004\n#define SAM_VALIDATE_BAD_PASSWORD_COUNT 0x00000008\n#define SAM_VALIDATE_PASSWORD_HISTORY_LENGTH 0x00000010\n#define SAM_VALIDATE_PASSWORD_HISTORY 0x00000020\n\ntypedef struct _SAM_VALIDATE_PERSISTED_FIELDS\n{\n    ULONG PresentFields;\n    LARGE_INTEGER PasswordLastSet;\n    LARGE_INTEGER BadPasswordTime;\n    LARGE_INTEGER LockoutTime;\n    ULONG BadPasswordCount;\n    ULONG PasswordHistoryLength;\n    _Field_size_bytes_(PasswordHistoryLength) PSAM_VALIDATE_PASSWORD_HASH PasswordHistory;\n} SAM_VALIDATE_PERSISTED_FIELDS, *PSAM_VALIDATE_PERSISTED_FIELDS;\n\ntypedef enum _SAM_VALIDATE_VALIDATION_STATUS\n{\n    SamValidateSuccess = 0,\n    SamValidatePasswordMustChange,\n    SamValidateAccountLockedOut,\n    SamValidatePasswordExpired,\n    SamValidatePasswordIncorrect,\n    SamValidatePasswordIsInHistory,\n    SamValidatePasswordTooShort,\n    SamValidatePasswordTooLong,\n    SamValidatePasswordNotComplexEnough,\n    SamValidatePasswordTooRecent,\n    SamValidatePasswordFilterError\n} SAM_VALIDATE_VALIDATION_STATUS, *PSAM_VALIDATE_VALIDATION_STATUS;\n\ntypedef struct _SAM_VALIDATE_STANDARD_OUTPUT_ARG\n{\n    SAM_VALIDATE_PERSISTED_FIELDS ChangedPersistedFields;\n    SAM_VALIDATE_VALIDATION_STATUS ValidationStatus;\n} SAM_VALIDATE_STANDARD_OUTPUT_ARG, *PSAM_VALIDATE_STANDARD_OUTPUT_ARG;\n\ntypedef struct _SAM_VALIDATE_AUTHENTICATION_INPUT_ARG\n{\n    SAM_VALIDATE_PERSISTED_FIELDS InputPersistedFields;\n    BOOLEAN PasswordMatched;\n} SAM_VALIDATE_AUTHENTICATION_INPUT_ARG, *PSAM_VALIDATE_AUTHENTICATION_INPUT_ARG;\n\ntypedef struct _SAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG\n{\n    SAM_VALIDATE_PERSISTED_FIELDS InputPersistedFields;\n    UNICODE_STRING ClearPassword;\n    UNICODE_STRING UserAccountName;\n    SAM_VALIDATE_PASSWORD_HASH HashedPassword;\n    BOOLEAN PasswordMatch; // denotes if the old password supplied by user matched or not\n} SAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG, *PSAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG;\n\ntypedef struct _SAM_VALIDATE_PASSWORD_RESET_INPUT_ARG\n{\n    SAM_VALIDATE_PERSISTED_FIELDS InputPersistedFields;\n    UNICODE_STRING ClearPassword;\n    UNICODE_STRING UserAccountName;\n    SAM_VALIDATE_PASSWORD_HASH HashedPassword;\n    BOOLEAN PasswordMustChangeAtNextLogon; // looked at only for password reset\n    BOOLEAN ClearLockout; // can be used clear user account lockout\n} SAM_VALIDATE_PASSWORD_RESET_INPUT_ARG, *PSAM_VALIDATE_PASSWORD_RESET_INPUT_ARG;\n\ntypedef union _SAM_VALIDATE_INPUT_ARG\n{\n    SAM_VALIDATE_AUTHENTICATION_INPUT_ARG ValidateAuthenticationInput;\n    SAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG ValidatePasswordChangeInput;\n    SAM_VALIDATE_PASSWORD_RESET_INPUT_ARG ValidatePasswordResetInput;\n} SAM_VALIDATE_INPUT_ARG, *PSAM_VALIDATE_INPUT_ARG;\n\ntypedef union _SAM_VALIDATE_OUTPUT_ARG\n{\n    SAM_VALIDATE_STANDARD_OUTPUT_ARG ValidateAuthenticationOutput;\n    SAM_VALIDATE_STANDARD_OUTPUT_ARG ValidatePasswordChangeOutput;\n    SAM_VALIDATE_STANDARD_OUTPUT_ARG ValidatePasswordResetOutput;\n} SAM_VALIDATE_OUTPUT_ARG, *PSAM_VALIDATE_OUTPUT_ARG;\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamValidatePassword(\n    _In_opt_ PCUNICODE_STRING ServerName,\n    _In_ PASSWORD_POLICY_VALIDATION_TYPE ValidationType,\n    _In_ PSAM_VALIDATE_INPUT_ARG InputArg,\n    _Out_ PSAM_VALIDATE_OUTPUT_ARG *OutputArg\n    );\n\n//\n// Generic operation\n//\n\ntypedef enum _SAM_GENERIC_OPERATION_TYPE\n{\n    SamObjectChangeNotificationOperation\n} SAM_GENERIC_OPERATION_TYPE, *PSAM_GENERIC_OPERATION_TYPE;\n\ntypedef struct _SAM_OPERATION_OBJCHG_INPUT\n{\n    BOOLEAN Register;\n    ULONG64 EventHandle;\n    SECURITY_DB_OBJECT_TYPE ObjectType;\n    ULONG ProcessID;\n} SAM_OPERATION_OBJCHG_INPUT, *PSAM_OPERATION_OBJCHG_INPUT;\n\ntypedef struct _SAM_OPERATION_OBJCHG_OUTPUT\n{\n    ULONG Reserved;\n} SAM_OPERATION_OBJCHG_OUTPUT, *PSAM_OPERATION_OBJCHG_OUTPUT;\n\ntypedef union _SAM_GENERIC_OPERATION_INPUT\n{\n    SAM_OPERATION_OBJCHG_INPUT ObjChangeIn;\n} SAM_GENERIC_OPERATION_INPUT, *PSAM_GENERIC_OPERATION_INPUT;\n\ntypedef union _SAM_GENERIC_OPERATION_OUTPUT\n{\n    SAM_OPERATION_OBJCHG_OUTPUT ObjChangeOut;\n} SAM_GENERIC_OPERATION_OUTPUT, *PSAM_GENERIC_OPERATION_OUTPUT;\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nSamPerformGenericOperation(\n    _In_opt_ PCWSTR ServerName,\n    _In_ SAM_GENERIC_OPERATION_TYPE OperationType,\n    _In_ PSAM_GENERIC_OPERATION_INPUT OperationIn,\n    _Out_ PSAM_GENERIC_OPERATION_OUTPUT *OperationOut\n    );\n\n#endif // _NTSAM_H\n"
  },
  {
    "path": "phnt/include/ntseapi.h",
    "content": "/*\n * Authorization functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTSEAPI_H\n#define _NTSEAPI_H\n\n//\n// Privileges\n//\n\n#define SE_MIN_WELL_KNOWN_PRIVILEGE (2L)\n#define SE_CREATE_TOKEN_PRIVILEGE (2L)              // Required to create a primary token.\n#define SE_ASSIGNPRIMARYTOKEN_PRIVILEGE (3L)        // Required to assign the primary token of a process.\n#define SE_LOCK_MEMORY_PRIVILEGE (4L)               // Required to lock physical pages in memory.\n#define SE_INCREASE_QUOTA_PRIVILEGE (5L)            // Required to increase the quota assigned to a process.\n#define SE_MACHINE_ACCOUNT_PRIVILEGE (6L)           // Required to create a computer account.\n#define SE_TCB_PRIVILEGE (7L)                       // Required to act as part of the Trusted Computer Base.\n#define SE_SECURITY_PRIVILEGE (8L)                  // Required to perform a number of security-related functions, such as controlling and viewing audit messages. // Security operator.\n#define SE_TAKE_OWNERSHIP_PRIVILEGE (9L)            // Required to take ownership of an object without being granted discretionary access.\n#define SE_LOAD_DRIVER_PRIVILEGE (10L)              // Required to load or unload a device driver.\n#define SE_SYSTEM_PROFILE_PRIVILEGE (11L)           // Required to gather profiling information for the entire system.\n#define SE_SYSTEMTIME_PRIVILEGE (12L)               // Required to modify the system time.\n#define SE_PROF_SINGLE_PROCESS_PRIVILEGE (13L)      // Required to gather profiling information for a single process.\n#define SE_INC_BASE_PRIORITY_PRIVILEGE (14L)        // Required to increase the base priority of a process.\n#define SE_CREATE_PAGEFILE_PRIVILEGE (15L)          // Required to create a paging file.\n#define SE_CREATE_PERMANENT_PRIVILEGE (16L)         // Required to create a permanent object.\n#define SE_BACKUP_PRIVILEGE (17L)                   // Required to perform backup operations. This privilege causes the system to grant all read access control to any file.\n#define SE_RESTORE_PRIVILEGE (18L)                  // Required to perform restore operations. This privilege causes the system to grant all write access control to any file.\n#define SE_SHUTDOWN_PRIVILEGE (19L)                 // Required to shut down a local system.\n#define SE_DEBUG_PRIVILEGE (20L)                    // Required to debug and adjust memory of any process, ignoring the DACL for the process.\n#define SE_AUDIT_PRIVILEGE (21L)                    // Required to generate audit-log entries.\n#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L)       // Required to modify UEFI variables of systems that use this type of memory to store configuration information.\n#define SE_CHANGE_NOTIFY_PRIVILEGE (23L)            // Required to receive notifications of changes to files or directories and skip all traversal access checks. It is enabled by default for all users.\n#define SE_REMOTE_SHUTDOWN_PRIVILEGE (24L)          // Required to shut down a system using a network request.\n#define SE_UNDOCK_PRIVILEGE (25L)                   // Required to undock a laptop.\n#define SE_SYNC_AGENT_PRIVILEGE (26L)               // Required for a domain controller to use the Lightweight Directory Access Protocol (LDAP) directory synchronization services.\n#define SE_ENABLE_DELEGATION_PRIVILEGE (27L)        // Required to mark user and computer accounts as trusted for delegation.\n#define SE_MANAGE_VOLUME_PRIVILEGE (28L)            // Required to enable volume management privileges.\n#define SE_IMPERSONATE_PRIVILEGE (29L)              // Required to impersonate a client after authentication.\n#define SE_CREATE_GLOBAL_PRIVILEGE (30L)            // Required to create named file mapping objects in the global namespace during Terminal Services sessions. It is enabled by default for all administrators.\n#define SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE (31L)   // Required to access Credential Manager as a trusted caller.\n#define SE_RELABEL_PRIVILEGE (32L)                  // Required to modify the mandatory integrity level of an object.\n#define SE_INC_WORKING_SET_PRIVILEGE (33L)          // Required to allocate more memory for applications that run in the context of users.\n#define SE_TIME_ZONE_PRIVILEGE (34L)                // Required to adjust the time zone associated with the computer's internal clock.\n#define SE_CREATE_SYMBOLIC_LINK_PRIVILEGE (35L)     // Required to create a symbolic link.\n#define SE_DELEGATE_SESSION_USER_IMPERSONATE_PRIVILEGE (36L) // Required to obtain an impersonation token for another user in the same session.\n#define SE_MAX_WELL_KNOWN_PRIVILEGE SE_DELEGATE_SESSION_USER_IMPERSONATE_PRIVILEGE\n\n//\n// Authz\n//\n\n// begin_rev\n\n#if (PHNT_MODE == PHNT_MODE_KERNEL)\n/**\n * The TOKEN_INFORMATION_CLASS enumeration contains values that specify the type of information\n * being assigned to or retrieved from an access token.\n *\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-token_information_class\n */\ntypedef enum _TOKEN_INFORMATION_CLASS\n{\n    TokenUser = 1,                        // q: TOKEN_USER, SE_TOKEN_USER\n    TokenGroups,                          // q: TOKEN_GROUPS\n    TokenPrivileges,                      // q: TOKEN_PRIVILEGES\n    TokenOwner,                           // qs: TOKEN_OWNER\n    TokenPrimaryGroup,                    // qs: TOKEN_PRIMARY_GROUP\n    TokenDefaultDacl,                     // qs: TOKEN_DEFAULT_DACL\n    TokenSource,                          // q: TOKEN_SOURCE\n    TokenType,                            // q: TOKEN_TYPE\n    TokenImpersonationLevel,              // q: SECURITY_IMPERSONATION_LEVEL\n    TokenStatistics,                      // q: TOKEN_STATISTICS // 10\n    TokenRestrictedSids,                  // q: TOKEN_GROUPS\n    TokenSessionId,                       // qs: ULONG (requires SeTcbPrivilege)\n    TokenGroupsAndPrivileges,             // q: TOKEN_GROUPS_AND_PRIVILEGES\n    TokenSessionReference,                // s: ULONG (requires SeTcbPrivilege)\n    TokenSandBoxInert,                    // q: ULONG\n    TokenAuditPolicy,                     // qs: TOKEN_AUDIT_POLICY (requires SeSecurityPrivilege/SeTcbPrivilege)\n    TokenOrigin,                          // qs: TOKEN_ORIGIN (requires SeTcbPrivilege)\n    TokenElevationType,                   // q: TOKEN_ELEVATION_TYPE\n    TokenLinkedToken,                     // qs: TOKEN_LINKED_TOKEN (requires SeCreateTokenPrivilege)\n    TokenElevation,                       // q: TOKEN_ELEVATION // 20\n    TokenHasRestrictions,                 // q: ULONG\n    TokenAccessInformation,               // q: TOKEN_ACCESS_INFORMATION\n    TokenVirtualizationAllowed,           // qs: ULONG (requires SeCreateTokenPrivilege)\n    TokenVirtualizationEnabled,           // qs: ULONG\n    TokenIntegrityLevel,                  // qs: TOKEN_MANDATORY_LABEL\n    TokenUIAccess,                        // qs: ULONG (requires SeTcbPrivilege)\n    TokenMandatoryPolicy,                 // qs: TOKEN_MANDATORY_POLICY (requires SeTcbPrivilege)\n    TokenLogonSid,                        // q: TOKEN_GROUPS\n    TokenIsAppContainer,                  // q: ULONG // since WIN8\n    TokenCapabilities,                    // q: TOKEN_GROUPS // 30\n    TokenAppContainerSid,                 // q: TOKEN_APPCONTAINER_INFORMATION\n    TokenAppContainerNumber,              // q: ULONG\n    TokenUserClaimAttributes,             // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION\n    TokenDeviceClaimAttributes,           // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION\n    TokenRestrictedUserClaimAttributes,   // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION\n    TokenRestrictedDeviceClaimAttributes, // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION\n    TokenDeviceGroups,                    // q: TOKEN_GROUPS\n    TokenRestrictedDeviceGroups,          // q: TOKEN_GROUPS\n    TokenSecurityAttributes,              // qs: TOKEN_SECURITY_ATTRIBUTES_[AND_OPERATION_]INFORMATION (requires SeTcbPrivilege)\n    TokenIsRestricted,                    // q: ULONG // 40\n    TokenProcessTrustLevel,               // q: TOKEN_PROCESS_TRUST_LEVEL // since WINBLUE\n    TokenPrivateNameSpace,                // qs: ULONG (requires SeTcbPrivilege) // since THRESHOLD\n    TokenSingletonAttributes,             // q: TOKEN_SECURITY_ATTRIBUTES_INFORMATION // since REDSTONE\n    TokenBnoIsolation,                    // q: TOKEN_BNO_ISOLATION_INFORMATION // since REDSTONE2\n    TokenChildProcessFlags,               // s: ULONG  (requires SeTcbPrivilege) // since REDSTONE3\n    TokenIsLessPrivilegedAppContainer,    // q: ULONG // since REDSTONE5\n    TokenIsSandboxed,                     // q: ULONG // since 19H1\n    TokenIsAppSilo,                       // q: ULONG // since WIN11 22H2 // previously TokenOriginatingProcessTrustLevel // q: TOKEN_PROCESS_TRUST_LEVEL\n    TokenLoggingInformation,              // q: TOKEN_LOGGING_INFORMATION // since 24H2\n    TokenLearningMode,                    // q: // since 25H2\n    MaxTokenInfoClass\n} TOKEN_INFORMATION_CLASS, *PTOKEN_INFORMATION_CLASS;\n\n//\n// Token information structures\n//\n\n/**\n * The TOKEN_USER structure identifies the user associated with an access token.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_user\n */\ntypedef struct _TOKEN_USER\n{\n    SID_AND_ATTRIBUTES User;\n} TOKEN_USER, *PTOKEN_USER;\n\ntypedef struct _SE_TOKEN_USER\n{\n    union\n    {\n        TOKEN_USER TokenUser;\n        SID_AND_ATTRIBUTES User;\n    } DUMMYUNIONNAME;\n    union\n    {\n        SID Sid;\n        BYTE Buffer[SECURITY_MAX_SID_SIZE];\n    } DUMMYUNIONNAME2;\n} SE_TOKEN_USER, PSE_TOKEN_USER;\n\n#define TOKEN_USER_MAX_SIZE (sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE)\n\n/**\n * The TOKEN_GROUPS structure contains information about the group security identifiers (SIDs) in an access token.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_groups\n */\ntypedef struct _TOKEN_GROUPS\n{\n    ULONG GroupCount;\n    SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY];\n} TOKEN_GROUPS, *PTOKEN_GROUPS;\n\n/**\n * The TOKEN_PRIVILEGES structure contains information about a set of privileges for an access token.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_privileges\n */\ntypedef struct _TOKEN_PRIVILEGES\n{\n    ULONG PrivilegeCount;\n    LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];\n} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;\n\n/**\n * The TOKEN_OWNER structure contains the default owner security identifier (SID) that will be applied to newly created objects.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_owner\n */\ntypedef struct _TOKEN_OWNER\n{\n    PSID Owner;\n} TOKEN_OWNER, *PTOKEN_OWNER;\n\n#define TOKEN_OWNER_MAX_SIZE (sizeof(TOKEN_OWNER) + SECURITY_MAX_SID_SIZE)\n\n/**\n * The TOKEN_PRIMARY_GROUP structure specifies a group security identifier (SID) for an access token.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_primary_group\n */\ntypedef struct _TOKEN_PRIMARY_GROUP\n{\n    PSID PrimaryGroup;\n} TOKEN_PRIMARY_GROUP, *PTOKEN_PRIMARY_GROUP;\n\n/**\n * The TOKEN_DEFAULT_DACL structure specifies a discretionary access control list (DACL).\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_default_dacl\n */\ntypedef struct _TOKEN_DEFAULT_DACL\n{\n    PACL DefaultDacl;\n} TOKEN_DEFAULT_DACL, *PTOKEN_DEFAULT_DACL;\n\n#define TOKEN_SOURCE_LENGTH 8\n\n/**\n * The TOKEN_SOURCE structure identifies the source of an access token.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_source\n */\ntypedef struct _TOKEN_SOURCE\n{\n    CHAR SourceName[TOKEN_SOURCE_LENGTH];\n    LUID SourceIdentifier;\n} TOKEN_SOURCE, *PTOKEN_SOURCE;\n\n/**\n * The TOKEN_TYPE enumeration contains values that differentiate between a primary token and an impersonation token.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-token_type\n */\ntypedef enum _TOKEN_TYPE\n{\n    TokenPrimary = 1,\n    TokenImpersonation\n} TOKEN_TYPE;\n\ntypedef struct _TOKEN_USER_CLAIMS\n{\n    PCLAIMS_BLOB UserClaims;\n} TOKEN_USER_CLAIMS, *PTOKEN_USER_CLAIMS;\n\ntypedef struct _TOKEN_DEVICE_CLAIMS\n{\n    PCLAIMS_BLOB DeviceClaims;\n} TOKEN_DEVICE_CLAIMS, *PTOKEN_DEVICE_CLAIMS;\n\ntypedef struct _TOKEN_GROUPS_AND_PRIVILEGES\n{\n    ULONG SidCount;\n    ULONG SidLength;\n    PSID_AND_ATTRIBUTES Sids;\n    ULONG RestrictedSidCount;\n    ULONG RestrictedSidLength;\n    PSID_AND_ATTRIBUTES RestrictedSids;\n    ULONG PrivilegeCount;\n    ULONG PrivilegeLength;\n    PLUID_AND_ATTRIBUTES Privileges;\n    LUID AuthenticationId;\n} TOKEN_GROUPS_AND_PRIVILEGES, *PTOKEN_GROUPS_AND_PRIVILEGES;\n\ntypedef struct _TOKEN_LINKED_TOKEN\n{\n    HANDLE LinkedToken;\n} TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;\n\ntypedef struct _TOKEN_ELEVATION\n{\n    ULONG TokenIsElevated;\n} TOKEN_ELEVATION, *PTOKEN_ELEVATION;\n\n/**\n * The TOKEN_MANDATORY_POLICY structure specifies the mandatory integrity policy for a token.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_mandatory_policy\n */\ntypedef struct _TOKEN_MANDATORY_LABEL\n{\n    SID_AND_ATTRIBUTES Label;\n} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;\n\n#define TOKEN_MANDATORY_POLICY_OFF             0x0\n#define TOKEN_MANDATORY_POLICY_NO_WRITE_UP     0x1\n#define TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN 0x2\n#define TOKEN_MANDATORY_POLICY_VALID_MASK      (TOKEN_MANDATORY_POLICY_NO_WRITE_UP | \\\n                                                TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN)\n\n#define TOKEN_INTEGRITY_LEVEL_MAX_SIZE \\\n    ((((ULONG)(sizeof(TOKEN_MANDATORY_LABEL)) + sizeof(PVOID) - 1) & ~(sizeof(PVOID)-1)) + SECURITY_MAX_SID_SIZE)\n\ntypedef struct _TOKEN_MANDATORY_POLICY\n{\n    ULONG Policy;\n} TOKEN_MANDATORY_POLICY, *PTOKEN_MANDATORY_POLICY;\n\ntypedef PVOID PSECURITY_ATTRIBUTES_OPAQUE;\n\ntypedef struct _TOKEN_ACCESS_INFORMATION\n{\n    PSID_AND_ATTRIBUTES_HASH SidHash;\n    PSID_AND_ATTRIBUTES_HASH RestrictedSidHash;\n    PTOKEN_PRIVILEGES Privileges;\n    LUID AuthenticationId;\n    TOKEN_TYPE TokenType;\n    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;\n    TOKEN_MANDATORY_POLICY MandatoryPolicy;\n    ULONG Flags;\n    ULONG AppContainerNumber;\n    PSID PackageSid;\n    PSID_AND_ATTRIBUTES_HASH CapabilitiesHash;\n    PSID TrustLevelSid;\n    PSECURITY_ATTRIBUTES_OPAQUE SecurityAttributes;\n} TOKEN_ACCESS_INFORMATION, *PTOKEN_ACCESS_INFORMATION;\n\ntypedef struct _TOKEN_LOGGING_INFORMATION\n{\n    TOKEN_TYPE TokenType;\n    TOKEN_ELEVATION TokenElevation;\n    TOKEN_ELEVATION_TYPE TokenElevationType;\n    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;\n    ULONG IntegrityLevel;\n    SID_AND_ATTRIBUTES User;\n    PSID TrustLevelSid;\n    ULONG SessionId;\n    ULONG AppContainerNumber;\n    LUID AuthenticationId;\n    ULONG GroupCount;\n    ULONG GroupsLength;\n    PSID_AND_ATTRIBUTES Groups;\n} TOKEN_LOGGING_INFORMATION, *PTOKEN_LOGGING_INFORMATION;\n\n#endif // (PHNT_MODE == PHNT_MODE_KERNEL)\n\n//\n// Types\n//\n\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_INVALID 0x00\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64 0x01\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64 0x02\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING 0x03 // Case insensitive attribute value string by default. Unless the flag TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE is set.\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN 0x04 // Fully-qualified binary name.\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_SID 0x05\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN 0x06\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING 0x10\n\n//\n// Flags\n//\n\n// Attribute must not be inherited across process spawns.\n#define TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE 0x0001\n// Attribute value is compared in a case sensitive way. It is valid with string value\n// or composite type containing string value. For other types of value, this flag\n// will be ignored. Currently, it is valid with the two types:\n// TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING and TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN.\n#define TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE 0x0002\n#define TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY 0x0004 // Attribute is considered only for Deny Aces.\n#define TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT 0x0008 // Attribute is disabled by default.\n#define TOKEN_SECURITY_ATTRIBUTE_DISABLED 0x0010 // Attribute is disabled.\n#define TOKEN_SECURITY_ATTRIBUTE_MANDATORY 0x0020 // Attribute is mandatory.\n#define TOKEN_SECURITY_ATTRIBUTE_COMPARE_IGNORE 0x0040 // Attribute is ignored.\n\n#define TOKEN_SECURITY_ATTRIBUTE_VALID_FLAGS ( \\\n    TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE | \\\n    TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE | \\\n    TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY | \\\n    TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT | \\\n    TOKEN_SECURITY_ATTRIBUTE_DISABLED | \\\n    TOKEN_SECURITY_ATTRIBUTE_MANDATORY)\n\n// Reserve upper 16 bits for custom flags. These should be preserved but not\n// validated as they do not affect security in any way.\n#define TOKEN_SECURITY_ATTRIBUTE_CUSTOM_FLAGS 0xffff0000\n\n// end_rev\n\n// private // CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE\ntypedef struct _TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE\n{\n    ULONG64 Version;\n    UNICODE_STRING Name;\n} TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE, *PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE;\n\n// private // CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE\ntypedef struct _TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE\n{\n    PVOID Value; // Pointer is BYTE aligned.\n    ULONG ValueLength; // In bytes\n} TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE, *PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE;\n\n// private\ntypedef struct _TOKEN_SECURITY_ATTRIBUTE_V1\n{\n    UNICODE_STRING Name;\n    USHORT ValueType;\n    USHORT Reserved;\n    ULONG Flags;\n    ULONG ValueCount;\n    union\n    {\n        PLONG64 Int64;\n        PULONG64 Uint64;\n        PUNICODE_STRING String;\n        PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE Fqbn;\n        PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE OctetString;\n    } Values;\n} TOKEN_SECURITY_ATTRIBUTE_V1, *PTOKEN_SECURITY_ATTRIBUTE_V1;\n\n// private\ntypedef struct _TOKEN_SECURITY_ATTRIBUTE_RELATIVE_V1\n{\n    UNICODE_STRING Name;\n    USHORT ValueType;\n    USHORT Reserved;\n    ULONG Flags;\n    ULONG ValueCount;\n    union\n    {\n        ULONG Int64[ANYSIZE_ARRAY];\n        ULONG Uint64[ANYSIZE_ARRAY];\n        ULONG String[ANYSIZE_ARRAY];\n        ULONG Fqbn[ANYSIZE_ARRAY];\n        ULONG OctetString[ANYSIZE_ARRAY];\n    } Values;\n} TOKEN_SECURITY_ATTRIBUTE_RELATIVE_V1, *PTOKEN_SECURITY_ATTRIBUTE_RELATIVE_V1;\n\n// rev\n#define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 1\n// rev\n#define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1\n\n// private\ntypedef struct _TOKEN_SECURITY_ATTRIBUTES_INFORMATION\n{\n    USHORT Version;\n    USHORT Reserved;\n    ULONG AttributeCount;\n    union\n    {\n        PTOKEN_SECURITY_ATTRIBUTE_V1 AttributeV1;\n    };\n} TOKEN_SECURITY_ATTRIBUTES_INFORMATION, *PTOKEN_SECURITY_ATTRIBUTES_INFORMATION;\n\n// private\ntypedef enum _TOKEN_SECURITY_ATTRIBUTE_OPERATION\n{\n    TOKEN_SECURITY_ATTRIBUTE_OPERATION_NONE,\n    TOKEN_SECURITY_ATTRIBUTE_OPERATION_REPLACE_ALL,\n    TOKEN_SECURITY_ATTRIBUTE_OPERATION_ADD,\n    TOKEN_SECURITY_ATTRIBUTE_OPERATION_DELETE,\n    TOKEN_SECURITY_ATTRIBUTE_OPERATION_REPLACE\n} TOKEN_SECURITY_ATTRIBUTE_OPERATION, *PTOKEN_SECURITY_ATTRIBUTE_OPERATION;\n\n// private\ntypedef struct _TOKEN_SECURITY_ATTRIBUTES_AND_OPERATION_INFORMATION\n{\n    PTOKEN_SECURITY_ATTRIBUTES_INFORMATION Attributes;\n    PTOKEN_SECURITY_ATTRIBUTE_OPERATION Operations;\n} TOKEN_SECURITY_ATTRIBUTES_AND_OPERATION_INFORMATION, *PTOKEN_SECURITY_ATTRIBUTES_AND_OPERATION_INFORMATION;\n\n// rev\n/**\n * The TOKEN_PROCESS_TRUST_LEVEL structure contains information about\n * the trust level assigned to a process token. The trust level is\n * represented by a SID (Security Identifier) pointed to by TrustLevelSid.\n */\ntypedef struct _TOKEN_PROCESS_TRUST_LEVEL\n{\n    PSID TrustLevelSid;\n} TOKEN_PROCESS_TRUST_LEVEL, *PTOKEN_PROCESS_TRUST_LEVEL;\n\n#if !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\ntypedef struct _TOKEN_LOGGING_INFORMATION\n{\n    TOKEN_TYPE TokenType;\n    TOKEN_ELEVATION TokenElevation;\n    TOKEN_ELEVATION_TYPE TokenElevationType;\n    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;\n    ULONG IntegrityLevel;\n    SID_AND_ATTRIBUTES User;\n    PSID TrustLevelSid;\n    ULONG SessionId;\n    ULONG AppContainerNumber;\n    LUID AuthenticationId;\n    ULONG GroupCount;\n    ULONG GroupsLength;\n    PSID_AND_ATTRIBUTES Groups;\n} TOKEN_LOGGING_INFORMATION, *PTOKEN_LOGGING_INFORMATION;\n#endif // !defined(NTDDI_WIN11_GE) || (NTDDI_VERSION < NTDDI_WIN11_GE)\n\n//\n// Tokens\n//\n/**\n * The NtCreateToken routine creates a new access token.\n *\n * \\param TokenHandle Pointer to a variable that receives the handle to the newly created token.\n * \\param DesiredAccess Specifies the requested access rights for the new token.\n * \\param ObjectAttributes Optional pointer to an OBJECT_ATTRIBUTES structure specifying object attributes.\n * \\param Type Specifies the type of token to be created (primary or impersonation).\n * \\param AuthenticationId Pointer to a locally unique identifier (LUID) for the token.\n * \\param ExpirationTime Pointer to a LARGE_INTEGER specifying the expiration time of the token.\n * \\param User Pointer to a TOKEN_USER structure specifying the user account for the token.\n * \\param Groups Pointer to a TOKEN_GROUPS structure specifying the group accounts for the token.\n * \\param Privileges Pointer to a TOKEN_PRIVILEGES structure specifying the privileges for the token.\n * \\param Owner Optional pointer to a TOKEN_OWNER structure specifying the owner SID for the token.\n * \\param PrimaryGroup Pointer to a TOKEN_PRIMARY_GROUP structure specifying the primary group SID for the token.\n * \\param DefaultDacl Optional pointer to a TOKEN_DEFAULT_DACL structure specifying the default DACL for the token.\n * \\param Source Pointer to a TOKEN_SOURCE structure specifying the source of the token.\n * \\return NTSTATUS code indicating success or failure.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateToken(\n    _Out_ PHANDLE TokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ TOKEN_TYPE Type,\n    _In_ PLUID AuthenticationId,\n    _In_ PLARGE_INTEGER ExpirationTime,\n    _In_ PTOKEN_USER User,\n    _In_ PTOKEN_GROUPS Groups,\n    _In_ PTOKEN_PRIVILEGES Privileges,\n    _In_opt_ PTOKEN_OWNER Owner,\n    _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup,\n    _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl,\n    _In_ PTOKEN_SOURCE Source\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n/**\n * The NtCreateLowBoxToken routine creates a new lowbox access token based on an existing token.\n *\n * \\param TokenHandle Pointer to a variable that receives the handle to the newly created lowbox token.\n * \\param ExistingTokenHandle Handle to an existing token to base the new token on.\n * \\param DesiredAccess Specifies the requested access rights for the new token.\n * \\param ObjectAttributes Optional pointer to an OBJECT_ATTRIBUTES structure specifying object attributes.\n * \\param PackageSid Pointer to a SID structure specifying the package SID for the lowbox token.\n * \\param CapabilityCount Number of capabilities in the Capabilities array.\n * \\param Capabilities Optional pointer to an array of SID_AND_ATTRIBUTES structures specifying capabilities.\n * \\param HandleCount Number of handles in the Handles array.\n * \\param Handles Optional pointer to an array of handles to be associated with the token.\n * \\return NTSTATUS code indicating success or failure.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/secauthz/ntcreatelowboxtoken\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateLowBoxToken(\n    _Out_ PHANDLE TokenHandle,\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PSID PackageSid,\n    _In_ ULONG CapabilityCount,\n    _In_reads_opt_(CapabilityCount) PSID_AND_ATTRIBUTES Capabilities,\n    _In_ ULONG HandleCount,\n    _In_reads_opt_(HandleCount) HANDLE *Handles\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n/**\n * The NtCreateTokenEx routine creates a new access token with extended attributes.\n *\n * \\param TokenHandle Pointer to a variable that receives the handle to the newly created token.\n * \\param DesiredAccess Specifies the requested access rights for the new token.\n * \\param ObjectAttributes Optional pointer to an OBJECT_ATTRIBUTES structure specifying object attributes.\n * \\param Type Specifies the type of token to be created (primary or impersonation).\n * \\param AuthenticationId Pointer to a locally unique identifier (LUID) for the token.\n * \\param ExpirationTime Pointer to a LARGE_INTEGER specifying the expiration time of the token.\n * \\param User Pointer to a TOKEN_USER structure specifying the user account for the token.\n * \\param Groups Pointer to a TOKEN_GROUPS structure specifying the group accounts for the token.\n * \\param Privileges Pointer to a TOKEN_PRIVILEGES structure specifying the privileges for the token.\n * \\param UserAttributes Optional pointer to a TOKEN_SECURITY_ATTRIBUTES_INFORMATION structure specifying user claims.\n * \\param DeviceAttributes Optional pointer to a TOKEN_SECURITY_ATTRIBUTES_INFORMATION structure specifying device claims.\n * \\param DeviceGroups Optional pointer to a TOKEN_GROUPS structure specifying device groups.\n * \\param MandatoryPolicy Optional pointer to a TOKEN_MANDATORY_POLICY structure specifying the mandatory policy.\n * \\param Owner Optional pointer to a TOKEN_OWNER structure specifying the owner SID for the token.\n * \\param PrimaryGroup Pointer to a TOKEN_PRIMARY_GROUP structure specifying the primary group SID for the token.\n * \\param DefaultDacl Optional pointer to a TOKEN_DEFAULT_DACL structure specifying the default DACL for the token.\n * \\param Source Pointer to a TOKEN_SOURCE structure specifying the source of the token.\n * \\return NTSTATUS code indicating success or failure.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateTokenEx(\n    _Out_ PHANDLE TokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ TOKEN_TYPE Type,\n    _In_ PLUID AuthenticationId,\n    _In_ PLARGE_INTEGER ExpirationTime,\n    _In_ PTOKEN_USER User,\n    _In_ PTOKEN_GROUPS Groups,\n    _In_ PTOKEN_PRIVILEGES Privileges,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION UserAttributes,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION DeviceAttributes,\n    _In_opt_ PTOKEN_GROUPS DeviceGroups,\n    _In_opt_ PTOKEN_MANDATORY_POLICY MandatoryPolicy,\n    _In_opt_ PTOKEN_OWNER Owner,\n    _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup,\n    _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl,\n    _In_ PTOKEN_SOURCE Source\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n/**\n * The NtOpenProcessToken routine opens the access token associated with a process, and returns a handle that can be used to access that token.\n *\n * \\param ProcessHandle Handle to the process whose access token is to be opened. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param DesiredAccess ACCESS_MASK structure specifying the requested types of access to the access token.\n * \\param TokenHandle Pointer to a caller-allocated variable that receives a handle to the newly opened access token.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntopenprocesstoken\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    );\n\n/**\n * The NtOpenProcessTokenEx routine opens the access token associated with a process, and returns a handle that can be used to access that token.\n *\n * \\param ProcessHandle Handle to the process whose access token is to be opened. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param DesiredAccess ACCESS_MASK structure specifying the requested types of access to the access token.\n * \\param HandleAttributes Attributes for the created handle. Only OBJ_KERNEL_HANDLE is currently supported.\n * \\param TokenHandle Pointer to a caller-allocated variable that receives a handle to the newly opened access token.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntopenprocesstokenex\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenProcessTokenEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _Out_ PHANDLE TokenHandle\n    );\n\n/**\n * The NtOpenThreadToken routine opens the access token associated with a thread, and returns a handle that can be used to access that token.\n *\n * \\param ThreadHandle Handle to the thread whose access token is to be opened. The handle must have THREAD_QUERY_INFORMATION access.\n * \\param DesiredAccess ACCESS_MASK structure specifying the requested types of access to the access token.\n * \\param OpenAsSelf Boolean value specifying whether the access check is to be made against the security context of the thread calling NtOpenThreadToken or against the security context of the process for the calling thread.\n * \\param TokenHandle Pointer to a caller-allocated variable that receives a handle to the newly opened access token.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntopenthreadtoken\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenThreadToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ BOOLEAN OpenAsSelf,\n    _Out_ PHANDLE TokenHandle\n    );\n\n/**\n * The NtOpenThreadTokenEx routine opens the access token associated with a thread, and returns a handle that can be used to access that token.\n *\n * \\param ThreadHandle Handle to the thread whose access token is to be opened. The handle must have THREAD_QUERY_INFORMATION access.\n * \\param DesiredAccess ACCESS_MASK structure specifying the requested types of access to the access token.\n * \\param OpenAsSelf Boolean value specifying whether the access check is to be made against the security context of the thread calling NtOpenThreadToken or against the security context of the process for the calling thread.\n * \\param HandleAttributes Attributes for the created handle. Only OBJ_KERNEL_HANDLE is currently supported.\n * \\param TokenHandle Pointer to a caller-allocated variable that receives a handle to the newly opened access token.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntopenthreadtokenex\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenThreadTokenEx(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ BOOLEAN OpenAsSelf,\n    _In_ ULONG HandleAttributes,\n    _Out_ PHANDLE TokenHandle\n    );\n\n/**\n * The NtDuplicateToken function creates a handle to a new access token that duplicates an existing token.\n *\n * \\param ExistingTokenHandle A handle to an existing access token that was opened with the TOKEN_DUPLICATE access right.\n * \\param DesiredAccess ACCESS_MASK structure specifying the requested types of access to the access token.\n * \\param ObjectAttributes Pointer to an OBJECT_ATTRIBUTES structure that describes the requested properties for the new token.\n * \\param EffectiveOnly A Boolean value that indicates whether the entire existing token should be duplicated into the new token or just the effective (currently enabled) part of the token.\n * \\param Type Specifies the type of token to create either a primary token or an impersonation token.\n * \\param NewTokenHandle Pointer to a caller-allocated variable that receives a handle to the newly duplicated token.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntduplicatetoken\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDuplicateToken(\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ BOOLEAN EffectiveOnly,\n    _In_ TOKEN_TYPE Type,\n    _Out_ PHANDLE NewTokenHandle\n    );\n\n/**\n * The NtQueryInformationToken routine retrieves a specified type of information about an access token. The calling process must have appropriate access rights to obtain the information.\n *\n * \\param TokenHandle A handle to an existing access token from which information is to be retrieved. If TokenInformationClass is set to TokenSource, the handle must have TOKEN_QUERY_SOURCE access.\n * For all other TokenInformationClass values, the handle must have TOKEN_QUERY access.\n * \\param TokenInformationClass A value from the TOKEN_INFORMATION_CLASS enumerated type identifying the type of information to be retrieved.\n * \\param TokenInformation Pointer to a caller-allocated buffer that receives the requested information about the token.\n * \\param TokenInformationLength Length, in bytes, of the caller-allocated TokenInformation buffer.\n * \\param ReturnLength Pointer to a caller-allocated variable that receives the actual length, in bytes, of the information returned in the TokenInformation buffer.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationtoken\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationToken(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength) PVOID TokenInformation,\n    _In_ ULONG TokenInformationLength,\n    _Out_ PULONG ReturnLength\n    );\n\n/**\n * The NtSetInformationToken routine modifies information in a specified token. The calling process must have appropriate access rights to set the information.\n *\n * \\param TokenHandle A handle to an existing access token which information is to be modified.\n * \\param TokenInformationClass A value from the TOKEN_INFORMATION_CLASS enumerated type identifying the type of information to be modified.\n * \\param TokenInformation Pointer to a caller-allocated buffer containing the information to be modified in the token.\n * \\param TokenInformationLength Length, in bytes, of the caller-allocated TokenInformation buffer.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntsetinformationtoken\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationToken(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation,\n    _In_ ULONG TokenInformationLength\n    );\n\n/**\n * The NtAdjustPrivilegesToken routine enables or disables privileges in the specified access token.\n *\n * \\param TokenHandle Handle to the token that contains the privileges to be modified. The handle must have TOKEN_ADJUST_PRIVILEGES access.\n * \\param DisableAllPrivileges Specifies whether the function disables all of the token's privileges. If this value is TRUE, the function disables all privileges and ignores the NewState parameter.\n * If it is FALSE, the function modifies privileges based on the information pointed to by the NewState parameter.\n * \\param NewState A pointer to a TOKEN_PRIVILEGES structure that specifies an array of privileges and their attributes. If DisableAllPrivileges is TRUE, the function ignores this parameter.\n * \\param BufferLength Specifies the size, in bytes, of the buffer pointed to by the PreviousState parameter. This parameter can be zero if the PreviousState parameter is NULL.\n * \\param PreviousState A pointer to a buffer that the function fills with a TOKEN_PRIVILEGES structure that contains the previous state of any privileges that the function modifies.\n * \\param ReturnLength A pointer to a variable that receives the required size, in bytes, of the buffer pointed to by the PreviousState parameter. This parameter can be NULL if PreviousState is NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokenprivileges\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAdjustPrivilegesToken(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN DisableAllPrivileges,\n    _In_opt_ PTOKEN_PRIVILEGES NewState,\n    _In_ ULONG BufferLength,\n    _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n/**\n * The NtAdjustGroupsToken routine enables or disables groups in the specified access token.\n *\n * \\param TokenHandle Handle to the token that contains the groups to be modified. The handle must have TOKEN_ADJUST_GROUPS access.\n * \\param ResetToDefault Specifies whether the function resets the groups to the default state. If this value is TRUE, the function resets all groups to their default state and ignores the NewState parameter.\n * \\param NewState A pointer to a TOKEN_GROUPS structure that specifies an array of groups and their attributes. If ResetToDefault is TRUE, the function ignores this parameter.\n * \\param BufferLength Specifies the size, in bytes, of the buffer pointed to by the PreviousState parameter. This parameter can be zero if the PreviousState parameter is NULL.\n * \\param PreviousState A pointer to a buffer that the function fills with a TOKEN_GROUPS structure that contains the previous state of any groups that the function modifies.\n * \\param ReturnLength A pointer to a variable that receives the required size, in bytes, of the buffer pointed to by the PreviousState parameter. This parameter can be NULL if PreviousState is NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokengroups\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAdjustGroupsToken(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN ResetToDefault,\n    _In_opt_ PTOKEN_GROUPS NewState,\n    _In_opt_ ULONG BufferLength,\n    _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_GROUPS PreviousState,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAdjustTokenClaimsAndDeviceGroups(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN UserResetToDefault,\n    _In_ BOOLEAN DeviceResetToDefault,\n    _In_ BOOLEAN DeviceGroupsResetToDefault,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewUserState,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewDeviceState,\n    _In_opt_ PTOKEN_GROUPS NewDeviceGroupsState,\n    _In_ ULONG UserBufferLength,\n    _Out_writes_bytes_to_opt_(UserBufferLength, *UserReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousUserState,\n    _In_ ULONG DeviceBufferLength,\n    _Out_writes_bytes_to_opt_(DeviceBufferLength, *DeviceReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousDeviceState,\n    _In_ ULONG DeviceGroupsBufferLength,\n    _Out_writes_bytes_to_opt_(DeviceGroupsBufferLength, *DeviceGroupsReturnBufferLength) PTOKEN_GROUPS PreviousDeviceGroups,\n    _Out_opt_ PULONG UserReturnLength,\n    _Out_opt_ PULONG DeviceReturnLength,\n    _Out_opt_ PULONG DeviceGroupsReturnBufferLength\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n// NtFilterToken Flags\n#define DISABLE_MAX_PRIVILEGE   0x1 // Disables all privileges in the new token except SE_CHANGE_NOTIFY_PRIVILEGE.\n#define SANDBOX_INERT           0x2 // Stores the TOKEN_SANDBOX_INERT flag in the token.\n#define LUA_TOKEN               0x4\n#define WRITE_RESTRICTED        0x8\n\n/**\n * The NtFilterToken routine creates a new access token that is a restricted version of an existing access token.\n *\n * \\param ExistingTokenHandle Handle to a primary or impersonation token. The token can also be a restricted token. This token must already be open for TOKEN_DUPLICATE access.\n * \\param Flags Specifies additional privilege options.\n * \\param SidsToDisable The deny-only SIDs to include in the restricted token. The system uses a deny-only SID to deny access to a securable object. The absence of a deny-only SID does not allow access.\n * \\param PrivilegesToDelete The privileges to delete in the restricted token. This parameter is optional and can be NULL.\n * \\param RestrictedSids The list of restricting SIDs for the new token. This parameter is optional and can be NULL.\n * \\param NewTokenHandle The new restricted token. The new token is the same type, primary or impersonation, as the existing token.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-sefiltertoken\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFilterToken(\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ULONG Flags,\n    _In_opt_ PTOKEN_GROUPS SidsToDisable,\n    _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,\n    _In_opt_ PTOKEN_GROUPS RestrictedSids,\n    _Out_ PHANDLE NewTokenHandle\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFilterTokenEx(\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ULONG Flags,\n    _In_opt_ PTOKEN_GROUPS SidsToDisable,\n    _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,\n    _In_opt_ PTOKEN_GROUPS RestrictedSids,\n    _In_ ULONG DisableUserClaimsCount,\n    _In_opt_ PCUNICODE_STRING UserClaimsToDisable,\n    _In_ ULONG DisableDeviceClaimsCount,\n    _In_opt_ PCUNICODE_STRING DeviceClaimsToDisable,\n    _In_opt_ PTOKEN_GROUPS DeviceGroupsToDisable,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedUserAttributes,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedDeviceAttributes,\n    _In_opt_ PTOKEN_GROUPS RestrictedDeviceGroups,\n    _Out_ PHANDLE NewTokenHandle\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n/**\n * The NtCompareTokens routine compares two access tokens to determine whether they are equivalent.\n *\n * \\param FirstTokenHandle Handle to the first access token to compare. The handle must have TOKEN_QUERY access.\n * \\param SecondTokenHandle Handle to the second access token to compare. The handle must have TOKEN_QUERY access.\n * \\param Equal Pointer to a BOOLEAN variable that receives TRUE if the tokens are equivalent, or FALSE otherwise.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/secauthz/ntcomparetokens\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCompareTokens(\n    _In_ HANDLE FirstTokenHandle,\n    _In_ HANDLE SecondTokenHandle,\n    _Out_ PBOOLEAN Equal\n    );\n\n/**\n * The NtPrivilegeCheck routine determines whether a specified set of privileges are enabled in the access token of a client.\n *\n * \\param ClientToken Handle to the access token of the client whose privileges are to be checked. The handle must have TOKEN_QUERY access.\n * \\param RequiredPrivileges Pointer to a PRIVILEGE_SET structure that specifies the set of privileges to be checked. On input, this structure contains the privileges to check.\n * \\param Result Pointer to a BOOLEAN variable that receives TRUE if all specified privileges are enabled, or FALSE otherwise.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-privilegecheck\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrivilegeCheck(\n    _In_ HANDLE ClientToken,\n    _Inout_ PPRIVILEGE_SET RequiredPrivileges,\n    _Out_ PBOOLEAN Result\n    );\n\n/**\n * The NtImpersonateAnonymousToken routine causes a thread to impersonate the anonymous token.\n *\n * \\param ThreadHandle Handle to the thread that will impersonate the anonymous token. The handle must have THREAD_DIRECT_IMPERSONATION access.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtImpersonateAnonymousToken(\n    _In_ HANDLE ThreadHandle\n    );\n\n/**\n * The NtQuerySecurityAttributesToken routine retrieves security attribute information from an access token.\n *\n * \\param TokenHandle Handle to the access token from which to retrieve security attributes. The handle must have TOKEN_QUERY access.\n * \\param Attributes Pointer to an array of UNICODE_STRING structures specifying the names of the attributes to query. This parameter can be NULL if NumberOfAttributes is zero.\n * \\param NumberOfAttributes The number of attributes specified in the Attributes array.\n * \\param Buffer Pointer to a buffer that receives the security attribute information. The buffer receives a TOKEN_SECURITY_ATTRIBUTES_INFORMATION structure.\n * \\param Length The size, in bytes, of the Buffer parameter.\n * \\param ReturnLength Pointer to a variable that receives the number of bytes required to store the complete security attribute information.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySecurityAttributesToken(\n    _In_ HANDLE TokenHandle,\n    _In_reads_opt_(NumberOfAttributes) PCUNICODE_STRING Attributes,\n    _In_ ULONG NumberOfAttributes,\n    _Out_writes_bytes_(Length) PVOID Buffer, // PTOKEN_SECURITY_ATTRIBUTES_INFORMATION\n    _In_ ULONG Length,\n    _Out_ PULONG ReturnLength\n    );\n\n//\n// Access checking\n//\n/**\n * The NtAccessCheck routine determines whether a security descriptor grants a specified set of access rights to the client represented by an access token.\n *\n * \\param SecurityDescriptor Pointer to the SECURITY_DESCRIPTOR structure against which access is checked.\n * \\param ClientToken Handle to the access token representing the client. The handle must have TOKEN_QUERY access.\n * \\param DesiredAccess Access mask that specifies the access rights to check.\n * \\param GenericMapping Pointer to the GENERIC_MAPPING structure associated with the object for which access is being checked.\n * \\param PrivilegeSet Pointer to a PRIVILEGE_SET structure that receives the privileges required to access the object. The buffer must be large enough to hold the privilege set.\n * \\param PrivilegeSetLength Pointer to a variable that specifies the size, in bytes, of the PrivilegeSet buffer. On input, this is the size of the buffer; on output, it receives the number of bytes required.\n * \\param GrantedAccess Pointer to an access mask that receives the granted access rights.\n * \\param AccessStatus Pointer to a variable that receives the results of the access check.\n * \\return NTSTATUS code indicating success or failure.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-accesscheck\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheck(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,\n    _Inout_ PULONG PrivilegeSetLength,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus\n    );\n\n/**\n * The NtAccessCheckByType routine determines whether a security descriptor grants a specified set of access rights to the client represented by an access token, taking into account object type information.\n *\n * \\param SecurityDescriptor Pointer to the SECURITY_DESCRIPTOR structure against which access is checked.\n * \\param PrincipalSelfSid Optional pointer to a SID structure representing the principal self SID, or NULL.\n * \\param ClientToken Handle to the access token representing the client. The handle must have TOKEN_QUERY access.\n * \\param DesiredAccess Access mask that specifies the access rights to check.\n * \\param ObjectTypeList Pointer to an array of OBJECT_TYPE_LIST structures that specify the hierarchy of object types for the object being accessed.\n * \\param ObjectTypeListLength The number of elements in the ObjectTypeList array.\n * \\param GenericMapping Pointer to the GENERIC_MAPPING structure associated with the object for which access is being checked.\n * \\param PrivilegeSet Pointer to a PRIVILEGE_SET structure that receives the privileges required to access the object. The buffer must be large enough to hold the privilege set.\n * \\param PrivilegeSetLength Pointer to a variable that specifies the size, in bytes, of the PrivilegeSet buffer. On input, this is the size of the buffer; on output, it receives the number of bytes required.\n * \\param GrantedAccess Pointer to an access mask that receives the granted access rights.\n * \\param AccessStatus Pointer to a variable that receives the results of the access check.\n * \\return NTSTATUS code indicating success or failure.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-accesscheckbytype\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByType(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,\n    _Inout_ PULONG PrivilegeSetLength,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus\n    );\n\n/**\n * The NtAccessCheckByTypeResultList routine determines whether a security descriptor grants a specified set of access rights to the client represented by an access token, and returns the results for each object type in a list.\n *\n * \\param SecurityDescriptor Pointer to the SECURITY_DESCRIPTOR structure against which access is checked.\n * \\param PrincipalSelfSid Optional pointer to a SID structure representing the principal self SID, or NULL.\n * \\param ClientToken Handle to the access token representing the client. The handle must have TOKEN_QUERY access.\n * \\param DesiredAccess Access mask that specifies the access rights to check.\n * \\param ObjectTypeList Pointer to an array of OBJECT_TYPE_LIST structures that specify the hierarchy of object types for the object being accessed.\n * \\param ObjectTypeListLength The number of elements in the ObjectTypeList array.\n * \\param GenericMapping Pointer to the GENERIC_MAPPING structure associated with the object for which access is being checked.\n * \\param PrivilegeSet Pointer to a PRIVILEGE_SET structure that receives the privileges required to access the object. The buffer must be large enough to hold the privilege set.\n * \\param PrivilegeSetLength Pointer to a variable that specifies the size, in bytes, of the PrivilegeSet buffer. On input, this is the size of the buffer; on output, it receives the number of bytes required.\n * \\param GrantedAccess Pointer to an array of access masks that receive the granted access rights for each object type.\n * \\param AccessStatus Pointer to an array of NTSTATUS values that receive the results of the access check for each object type.\n * \\return NTSTATUS code indicating success or failure.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-accesscheckbytyperesultlist\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByTypeResultList(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,\n    _Inout_ PULONG PrivilegeSetLength,\n    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,\n    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus\n    );\n\n//\n// Signing\n//\n\n#define SIGNING_LEVEL_FILE_CACHE_FLAG_NOT_VALIDATED  0x01\n#define SIGNING_LEVEL_FILE_CACHE_FLAG_VALIDATE_ONLY  0x04\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n/**\n * The NtGetCachedSigningLevel routine retrieves the cached signing level of a file.\n *\n * \\param File Handle to a file.\n * \\param Flags Pointer to the flags set on the file.\n * \\param SigningLevel Pointer to the signing level.\n * \\param Thumbprint Pointer to the thumbprint.\n * \\param ThumbprintSize Pointer to the thumbprint size.\n * \\param ThumbprintAlgorithm Pointer to the thumbprint algorithm.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-getcachedsigninglevel\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetCachedSigningLevel(\n    _In_ HANDLE File,\n    _Out_ PULONG Flags,\n    _Out_ PSE_SIGNING_LEVEL SigningLevel,\n    _Out_writes_bytes_to_opt_(*ThumbprintSize, *ThumbprintSize) PUCHAR Thumbprint,\n    _Inout_opt_ PULONG ThumbprintSize,\n    _Out_opt_ PULONG ThumbprintAlgorithm\n    );\n\n/**\n * The NtSetCachedSigningLevel routine sets the cached signing level of a file.\n *\n * \\param Flags Pointer to the flags set on the file.\n * \\param InputSigningLevel Pointer to the signing level.\n * \\param SourceFiles Pointer to a set of source file handles.\n * \\param SourceFileCount The source file count.\n * \\param TargetFile The target file.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-setcachedsigninglevel\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetCachedSigningLevel(\n    _In_ ULONG Flags,\n    _In_ SE_SIGNING_LEVEL InputSigningLevel,\n    _In_reads_(SourceFileCount) PHANDLE SourceFiles,\n    _In_ ULONG SourceFileCount,\n    _In_opt_ HANDLE TargetFile\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_8)\n\n// rev\ntypedef struct _SE_FILE_CACHE_CLAIM_INFORMATION\n{\n    ULONG Size;\n    PVOID Claim;\n} SE_FILE_CACHE_CLAIM_INFORMATION, *PSE_FILE_CACHE_CLAIM_INFORMATION;\n\n// rev\ntypedef struct _SE_SET_FILE_CACHE_INFORMATION\n{\n    ULONG Size;\n    UNICODE_STRING CatalogDirectoryPath;\n    SE_FILE_CACHE_CLAIM_INFORMATION OriginClaimInfo;\n} SE_SET_FILE_CACHE_INFORMATION, *PSE_SET_FILE_CACHE_INFORMATION;\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS1)\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetCachedSigningLevel2(\n    _In_ ULONG Flags,\n    _In_ SE_SIGNING_LEVEL InputSigningLevel,\n    _In_reads_(SourceFileCount) PHANDLE SourceFiles,\n    _In_ ULONG SourceFileCount,\n    _In_opt_ HANDLE TargetFile,\n    _In_opt_ SE_SET_FILE_CACHE_INFORMATION* CacheInformation\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_RS1)\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS2)\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCompareSigningLevels(\n    _In_ SE_SIGNING_LEVEL FirstSigningLevel,\n    _In_ SE_SIGNING_LEVEL SecondSigningLevel\n    );\n#endif // (PHNT_VERSION >= PHNT_WINDOWS_10_RS2)\n\n//\n// Audit alarm\n//\n\n/**\n * The NtAccessCheckAndAuditAlarm routine determines whether a security descriptor grants a specified set of access rights to the client being impersonated by the calling thread.\n * If the security descriptor has a SACL with ACEs that apply to the client, the function generates any necessary audit messages in the security event log.\n *\n * \\param SubsystemName A pointer to a null-terminated string specifying the name of the subsystem calling the function.\n * \\param HandleId A pointer to a unique value representing the client's handle to the object.\n * \\param ObjectTypeName A pointer to a null-terminated string specifying the type of object being created or accessed.\n * \\param ObjectName A pointer to a null-terminated string specifying the name of the object being created or accessed.\n * \\param SecurityDescriptor A pointer to the SECURITY_DESCRIPTOR structure against which access is checked.\n * \\param DesiredAccess Access mask that specifies the access rights to check. This mask must have been mapped by the MapGenericMask function to contain no generic access rights.\n * \\param GenericMapping A pointer to the GENERIC_MAPPING structure associated with the object for which access is being checked.\n * \\param ObjectCreation Specifies a flag that determines whether the calling application will create a new object when access is granted.\n * \\param GrantedAccess A pointer to an access mask that receives the granted access rights.\n * \\param AccessStatus A pointer to a variable that receives the results of the access check.\n * \\param GenerateOnClose A pointer to a flag set by the audit-generation routine when the function returns.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-accesscheckandauditalarma\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckAndAuditAlarm(\n    _In_ PCUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PCUNICODE_STRING ObjectTypeName,\n    _In_ PCUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\n/**\n * The NtAccessCheckByTypeAndAuditAlarm routine determines whether a security descriptor grants a specified set of access rights to the client being impersonated by the calling thread.\n * If the security descriptor has a SACL with ACEs that apply to the client, the function generates any necessary audit messages in the security event log.\n *\n * \\param SubsystemName A pointer to a UNICODE_STRING specifying the name of the subsystem calling the function.\n * \\param HandleId A pointer to a unique value representing the client's handle to the object.\n * \\param ObjectTypeName A pointer to a UNICODE_STRING specifying the type of object being created or accessed.\n * \\param ObjectName A pointer to a UNICODE_STRING specifying the name of the object being created or accessed.\n * \\param SecurityDescriptor A pointer to the SECURITY_DESCRIPTOR structure against which access is checked.\n * \\param PrincipalSelfSid A pointer to a SID structure representing the principal self SID, or NULL.\n * \\param DesiredAccess Access mask that specifies the access rights to check. This mask must have been mapped by the MapGenericMask function to contain no generic access rights.\n * \\param AuditType Specifies the type of audit event to be generated.\n * \\param Flags Audit event flags.\n * \\param ObjectTypeList A pointer to an array of OBJECT_TYPE_LIST structures that specify the hierarchy of object types for the object being accessed.\n * \\param ObjectTypeListLength The number of elements in the ObjectTypeList array.\n * \\param GenericMapping A pointer to the GENERIC_MAPPING structure associated with the object for which access is being checked.\n * \\param ObjectCreation Specifies a flag that determines whether the calling application will create a new object when access is granted.\n * \\param GrantedAccess A pointer to an access mask that receives the granted access rights.\n * \\param AccessStatus A pointer to a variable that receives the results of the access check.\n * \\param GenerateOnClose A pointer to a flag set by the audit-generation routine when the function returns.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-accesscheckbytypeandauditalarma\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByTypeAndAuditAlarm(\n    _In_ PCUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PCUNICODE_STRING ObjectTypeName,\n    _In_ PCUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ AUDIT_EVENT_TYPE AuditType,\n    _In_ ULONG Flags,\n    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\n/**\n * The NtAccessCheckByTypeResultListAndAuditAlarm routine determines whether a security descriptor grants a specified set of access rights to the client being impersonated by the calling thread.\n * It also generates audit messages for each object type in the hierarchy, and returns the results for each object type in a list.\n *\n * \\param SubsystemName A pointer to a UNICODE_STRING specifying the name of the subsystem calling the function.\n * \\param HandleId A pointer to a unique value representing the client's handle to the object.\n * \\param ObjectTypeName A pointer to a UNICODE_STRING specifying the type of object being created or accessed.\n * \\param ObjectName A pointer to a UNICODE_STRING specifying the name of the object being created or accessed.\n * \\param SecurityDescriptor A pointer to the SECURITY_DESCRIPTOR structure against which access is checked.\n * \\param PrincipalSelfSid A pointer to a SID structure representing the principal self SID, or NULL.\n * \\param DesiredAccess Access mask that specifies the access rights to check.\n * \\param AuditType Specifies the type of audit event to be generated.\n * \\param Flags Audit event flags.\n * \\param ObjectTypeList A pointer to an array of OBJECT_TYPE_LIST structures that specify the hierarchy of object types for the object being accessed.\n * \\param ObjectTypeListLength The number of elements in the ObjectTypeList array.\n * \\param GenericMapping A pointer to the GENERIC_MAPPING structure associated with the object for which access is being checked.\n * \\param ObjectCreation Specifies a flag that determines whether the calling application will create a new object when access is granted.\n * \\param GrantedAccess A pointer to an array of access masks that receive the granted access rights for each object type.\n * \\param AccessStatus A pointer to an array of NTSTATUS values that receive the results of the access check for each object type.\n * \\param GenerateOnClose A pointer to a flag set by the audit-generation routine when the function returns.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-accesscheckbytyperesultlistandauditalarma\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByTypeResultListAndAuditAlarm(\n    _In_ PCUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PCUNICODE_STRING ObjectTypeName,\n    _In_ PCUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ AUDIT_EVENT_TYPE AuditType,\n    _In_ ULONG Flags,\n    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,\n    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\n/**\n * The NtAccessCheckByTypeResultListAndAuditAlarmByHandle routine determines whether a security descriptor grants a specified set of access rights to the client represented by a specified access token.\n * It also generates audit messages for each object type in the hierarchy, and returns the results for each object type in a list.\n *\n * \\param SubsystemName A pointer to a UNICODE_STRING specifying the name of the subsystem calling the function.\n * \\param HandleId A pointer to a unique value representing the client's handle to the object.\n * \\param ClientToken Handle to the access token representing the client.\n * \\param ObjectTypeName A pointer to a UNICODE_STRING specifying the type of object being created or accessed.\n * \\param ObjectName A pointer to a UNICODE_STRING specifying the name of the object being created or accessed.\n * \\param SecurityDescriptor A pointer to the SECURITY_DESCRIPTOR structure against which access is checked.\n * \\param PrincipalSelfSid A pointer to a SID structure representing the principal self SID, or NULL.\n * \\param DesiredAccess Access mask that specifies the access rights to check.\n * \\param AuditType Specifies the type of audit event to be generated.\n * \\param Flags Audit event flags.\n * \\param ObjectTypeList A pointer to an array of OBJECT_TYPE_LIST structures that specify the hierarchy of object types for the object being accessed.\n * \\param ObjectTypeListLength The number of elements in the ObjectTypeList array.\n * \\param GenericMapping A pointer to the GENERIC_MAPPING structure associated with the object for which access is being checked.\n * \\param ObjectCreation Specifies a flag that determines whether the calling application will create a new object when access is granted.\n * \\param GrantedAccess A pointer to an array of access masks that receive the granted access rights for each object type.\n * \\param AccessStatus A pointer to an array of NTSTATUS values that receive the results of the access check for each object type.\n * \\param GenerateOnClose A pointer to a flag set by the audit-generation routine when the function returns.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-accesscheckbytyperesultlistandauditalarmbyhandlea\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByTypeResultListAndAuditAlarmByHandle(\n    _In_ PCUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ HANDLE ClientToken,\n    _In_ PCUNICODE_STRING ObjectTypeName,\n    _In_ PCUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ AUDIT_EVENT_TYPE AuditType,\n    _In_ ULONG Flags,\n    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,\n    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\n/**\n * The NtOpenObjectAuditAlarm routine generates an audit message in the security event log when an object is opened.\n *\n * \\param SubsystemName A pointer to a UNICODE_STRING specifying the name of the subsystem calling the function.\n * \\param HandleId A pointer to a unique value representing the client's handle to the object.\n * \\param ObjectTypeName A pointer to a UNICODE_STRING specifying the type of object being opened.\n * \\param ObjectName A pointer to a UNICODE_STRING specifying the name of the object being opened.\n * \\param SecurityDescriptor A pointer to the SECURITY_DESCRIPTOR structure for the object.\n * \\param ClientToken Handle to the access token representing the client.\n * \\param DesiredAccess Access mask that specifies the access rights requested.\n * \\param GrantedAccess Access mask that specifies the access rights granted.\n * \\param Privileges A pointer to a PRIVILEGE_SET structure that specifies the privileges used to gain access, or NULL.\n * \\param ObjectCreation Specifies a flag that determines whether the object is being created.\n * \\param AccessGranted Specifies a flag that determines whether access was granted.\n * \\param GenerateOnClose A pointer to a flag set by the audit-generation routine when the function returns.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenObjectAuditAlarm(\n    _In_ PCUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PCUNICODE_STRING ObjectTypeName,\n    _In_ PCUNICODE_STRING ObjectName,\n    _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ACCESS_MASK GrantedAccess,\n    _In_opt_ PPRIVILEGE_SET Privileges,\n    _In_ BOOLEAN ObjectCreation,\n    _In_ BOOLEAN AccessGranted,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\n/**\n * The NtPrivilegeObjectAuditAlarm routine generates an audit message in the security event log when a privilege is used to access an object.\n *\n * \\param SubsystemName A pointer to a UNICODE_STRING specifying the name of the subsystem calling the function.\n * \\param HandleId A pointer to a unique value representing the client's handle to the object.\n * \\param ClientToken Handle to the access token representing the client.\n * \\param DesiredAccess Access mask that specifies the access rights requested.\n * \\param Privileges A pointer to a PRIVILEGE_SET structure that specifies the privileges used to gain access.\n * \\param AccessGranted Specifies a flag that determines whether access was granted.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrivilegeObjectAuditAlarm(\n    _In_ PCUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPRIVILEGE_SET Privileges,\n    _In_ BOOLEAN AccessGranted\n    );\n\n/**\n * The NtCloseObjectAuditAlarm routine generates an audit message in the security event log when an object handle is closed.\n *\n * \\param SubsystemName A pointer to a UNICODE_STRING specifying the name of the subsystem calling the function.\n * \\param HandleId A pointer to a unique value representing the client's handle to the object.\n * \\param GenerateOnClose Specifies a flag that determines whether to generate an audit on close.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCloseObjectAuditAlarm(\n    _In_ PCUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ BOOLEAN GenerateOnClose\n    );\n\n/**\n * The NtDeleteObjectAuditAlarm routine generates an audit message in the security event log when an object is deleted.\n *\n * \\param SubsystemName A pointer to a UNICODE_STRING specifying the name of the subsystem calling the function.\n * \\param HandleId A pointer to a unique value representing the client's handle to the object.\n * \\param GenerateOnClose Specifies a flag that determines whether to generate an audit on close.\n * \\return NTSTATUS Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteObjectAuditAlarm(\n    _In_ PCUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ BOOLEAN GenerateOnClose\n    );\n\n/**\n * The NtPrivilegedServiceAuditAlarm routine generates an audit message in the security event log when a privileged service is accessed.\n *\n * \\param SubsystemName A pointer to a UNICODE_STRING specifying the name of the subsystem calling the function.\n * \\param ServiceName A pointer to a UNICODE_STRING specifying the name of the service being accessed.\n * \\param ClientToken Handle to the access token representing the client.\n * \\param Privileges A pointer to a PRIVILEGE_SET structure that specifies the privileges used to access the service.\n * \\param AccessGranted Specifies a flag that determines whether access was granted.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-privilegedserviceauditalarma\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrivilegedServiceAuditAlarm(\n    _In_ PCUNICODE_STRING SubsystemName,\n    _In_ PCUNICODE_STRING ServiceName,\n    _In_ HANDLE ClientToken,\n    _In_ PPRIVILEGE_SET Privileges,\n    _In_ BOOLEAN AccessGranted\n    );\n\n//\n// KSecDD FS control definitions\n//\n#define KSEC_DEVICE_NAME L\"\\\\Device\\\\KSecDD\"\n#define IOCTL_KSEC_CONNECT_LSA                      CTL_CODE(FILE_DEVICE_KSEC,  0, METHOD_BUFFERED,     FILE_WRITE_ACCESS )\n#define IOCTL_KSEC_RNG                              CTL_CODE(FILE_DEVICE_KSEC,  1, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_RNG_REKEY                        CTL_CODE(FILE_DEVICE_KSEC,  2, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_ENCRYPT_MEMORY                   CTL_CODE(FILE_DEVICE_KSEC,  3, METHOD_OUT_DIRECT,   FILE_ANY_ACCESS )\n#define IOCTL_KSEC_DECRYPT_MEMORY                   CTL_CODE(FILE_DEVICE_KSEC,  4, METHOD_OUT_DIRECT,   FILE_ANY_ACCESS )\n#define IOCTL_KSEC_ENCRYPT_MEMORY_CROSS_PROC        CTL_CODE(FILE_DEVICE_KSEC,  5, METHOD_OUT_DIRECT,   FILE_ANY_ACCESS )\n#define IOCTL_KSEC_DECRYPT_MEMORY_CROSS_PROC        CTL_CODE(FILE_DEVICE_KSEC,  6, METHOD_OUT_DIRECT,   FILE_ANY_ACCESS )\n#define IOCTL_KSEC_ENCRYPT_MEMORY_SAME_LOGON        CTL_CODE(FILE_DEVICE_KSEC,  7, METHOD_OUT_DIRECT,   FILE_ANY_ACCESS )\n#define IOCTL_KSEC_DECRYPT_MEMORY_SAME_LOGON        CTL_CODE(FILE_DEVICE_KSEC,  8, METHOD_OUT_DIRECT,   FILE_ANY_ACCESS )\n#define IOCTL_KSEC_FIPS_GET_FUNCTION_TABLE          CTL_CODE(FILE_DEVICE_KSEC,  9, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_ALLOC_POOL                       CTL_CODE(FILE_DEVICE_KSEC, 10, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_FREE_POOL                        CTL_CODE(FILE_DEVICE_KSEC, 11, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_COPY_POOL                        CTL_CODE(FILE_DEVICE_KSEC, 12, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_DUPLICATE_HANDLE                 CTL_CODE(FILE_DEVICE_KSEC, 13, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_REGISTER_EXTENSION               CTL_CODE(FILE_DEVICE_KSEC, 14, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_CLIENT_CALLBACK                  CTL_CODE(FILE_DEVICE_KSEC, 15, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_GET_BCRYPT_EXTENSION             CTL_CODE(FILE_DEVICE_KSEC, 16, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_GET_SSL_EXTENSION                CTL_CODE(FILE_DEVICE_KSEC, 17, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_GET_DEVICECONTROL_EXTENSION      CTL_CODE(FILE_DEVICE_KSEC, 18, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_ALLOC_VM                         CTL_CODE(FILE_DEVICE_KSEC, 19, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_FREE_VM                          CTL_CODE(FILE_DEVICE_KSEC, 20, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_COPY_VM                          CTL_CODE(FILE_DEVICE_KSEC, 21, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_CLIENT_FREE_VM                   CTL_CODE(FILE_DEVICE_KSEC, 22, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_INSERT_PROTECTED_PROCESS_ADDRESS CTL_CODE(FILE_DEVICE_KSEC, 23, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_REMOVE_PROTECTED_PROCESS_ADDRESS CTL_CODE(FILE_DEVICE_KSEC, 24, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_GET_BCRYPT_EXTENSION2            CTL_CODE(FILE_DEVICE_KSEC, 25, METHOD_BUFFERED,     FILE_ANY_ACCESS )\n#define IOCTL_KSEC_IPC_GET_QUEUED_FUNCTION_CALLS    CTL_CODE(FILE_DEVICE_KSEC, 26, METHOD_OUT_DIRECT,   FILE_ANY_ACCESS)\n#define IOCTL_KSEC_IPC_SET_FUNCTION_RETURN          CTL_CODE(FILE_DEVICE_KSEC, 27, METHOD_NEITHER,      FILE_ANY_ACCESS)\n\n#endif // _NTSEAPI_H\n"
  },
  {
    "path": "phnt/include/nttp.h",
    "content": "/*\n * Thread Pool support functions\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTTP_H\n#define _NTTP_H\n\n// Some types are already defined in winnt.h.\n\ntypedef struct _TP_ALPC TP_ALPC, *PTP_ALPC;\n\n// private\ntypedef _Function_class_(TP_ALPC_CALLBACK)\nVOID NTAPI TP_ALPC_CALLBACK(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context,\n    _In_ PTP_ALPC Alpc\n    );\ntypedef TP_ALPC_CALLBACK *PTP_ALPC_CALLBACK;\n\n// rev\ntypedef _Function_class_(TP_ALPC_CALLBACK_EX)\nVOID NTAPI TP_ALPC_CALLBACK_EX(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context,\n    _In_ PTP_ALPC Alpc,\n    _In_ PVOID ApcContext\n    );\ntypedef TP_ALPC_CALLBACK_EX *PTP_ALPC_CALLBACK_EX;\n\n// winbase:CreateThreadpool\n/**\n * Allocates a new pool of threads to execute callbacks.\n *\n * \\param[out] PoolReturn Pointer to a variable that receives the address of the newly allocated thread pool.\n * \\param[in] Reserved Reserved for future use. Must be NULL.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/threadpoolapiset/nf-threadpoolapiset-createthreadpool\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocPool(\n    _Out_ PTP_POOL *PoolReturn,\n    _Reserved_ PVOID Reserved\n    );\n\n// winbase:CloseThreadpool\n/**\n * Closes the specified thread pool.\n *\n * \\param[in,out] Pool A pointer to a TP_POOL structure that defines the thread pool.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/threadpoolapiset/nf-threadpoolapiset-closethreadpool\n */\nNTSYSAPI\nVOID\nNTAPI\nTpReleasePool(\n    _Inout_ PTP_POOL Pool\n    );\n\n// winbase:SetThreadpoolThreadMaximum\n/**\n * Sets the maximum number of threads that the specified thread pool can allocate to process callbacks.\n *\n * \\param[in,out] Pool A pointer to a TP_POOL structure that defines the thread pool.\n * \\param[in] MaxThreads The maximum number of threads.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/threadpoolapiset/nf-threadpoolapiset-setthreadpoolthreadmaximum\n */\nNTSYSAPI\nVOID\nNTAPI\nTpSetPoolMaxThreads(\n    _Inout_ PTP_POOL Pool,\n    _In_ ULONG MaxThreads\n    );\n\n// winbase:SetThreadpoolThreadMinimum\n/**\n * Sets the minimum number of threads that the specified thread pool must make available to process callbacks.\n *\n * \\param[in,out] Pool A pointer to a TP_POOL structure that defines the thread pool.\n * \\param[in] MinThreads The minimum number of threads.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/threadpoolapiset/nf-threadpoolapiset-setthreadpoolthreadminimum\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpSetPoolMinThreads(\n    _Inout_ PTP_POOL Pool,\n    _In_ ULONG MinThreads\n    );\n\n// winbase:QueryThreadpoolStackInformation\n/**\n * Retrieves the stack reserve and commit sizes for threads in the specified thread pool.\n *\n * \\param[in] Pool A pointer to a TP_POOL structure that defines the thread pool.\n * \\param[out] PoolStackInformation A pointer to a TP_POOL_STACK_INFORMATION structure that receives the stack reserve and commit size.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/threadpoolapiset/nf-threadpoolapiset-querythreadpoolstackinformation\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpQueryPoolStackInformation(\n    _In_ PTP_POOL Pool,\n    _Out_ PTP_POOL_STACK_INFORMATION PoolStackInformation\n    );\n\n// winbase:SetThreadpoolStackInformation\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpSetPoolStackInformation(\n    _Inout_ PTP_POOL Pool,\n    _In_ PTP_POOL_STACK_INFORMATION PoolStackInformation\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpSetPoolThreadBasePriority(\n    _Inout_ PTP_POOL Pool,\n    _In_ ULONG BasePriority\n    );\n\n// winbase:CreateThreadpoolCleanupGroup\n/**\n * Creates a cleanup group that applications can use to track one or more thread pool callbacks.\n *\n * \\param[out] CleanupGroup A pointer to a TP_CLEANUP_GROUP structure of the newly allocated cleanup group.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/threadpoolapiset/nf-threadpoolapiset-createthreadpoolcleanupgroup\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocCleanupGroup(\n    _Out_ PTP_CLEANUP_GROUP *CleanupGroup\n    );\n\n// winbase:CloseThreadpoolCleanupGroup\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseCleanupGroup(\n    _Inout_ PTP_CLEANUP_GROUP CleanupGroup\n    );\n\n// winbase:CloseThreadpoolCleanupGroupMembers\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseCleanupGroupMembers(\n    _Inout_ PTP_CLEANUP_GROUP CleanupGroup,\n    _In_ LOGICAL CancelPendingCallbacks,\n    _Inout_opt_ PVOID CleanupParameter\n    );\n\n// winbase:SetEventWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackSetEventOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _In_ HANDLE Event\n    );\n\n// winbase:ReleaseSemaphoreWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackReleaseSemaphoreOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _In_ HANDLE Semaphore,\n    _In_ ULONG ReleaseCount\n    );\n\n// winbase:ReleaseMutexWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackReleaseMutexOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _In_ HANDLE Mutex\n    );\n\n// winbase:LeaveCriticalSectionWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackLeaveCriticalSectionOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\n// winbase:FreeLibraryWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackUnloadDllOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _In_ PVOID DllHandle\n    );\n\n// winbase:CallbackMayRunLong\n/**\n * Indicates that the callback may not return quickly.\n *\n * \\param[in,out] Instance A pointer to a TP_CALLBACK_INSTANCE structure that defines the callback instance.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/threadpoolapiset/nf-threadpoolapiset-callbackmayrunlong\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpCallbackMayRunLong(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance\n    );\n\n// winbase:DisassociateCurrentThreadFromCallback\nNTSYSAPI\nVOID\nNTAPI\nTpDisassociateCallback(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance\n    );\n\ntypedef _Function_class_(TP_CALLBACK_ROUTINE)\nVOID NTAPI TP_CALLBACK_ROUTINE(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context\n    );\ntypedef TP_CALLBACK_ROUTINE* PTP_CALLBACK_ROUTINE;\n\n// winbase:TrySubmitThreadpoolCallback\n/**\n * Requests that a thread pool worker thread call the specified callback function.\n *\n * \\param[in] Callback The callback function.\n * \\param[in,out] Context Optional application-defined data to pass to the callback function.\n * \\param[in] CallbackEnviron A pointer to a TP_CALLBACK_ENVIRON structure that defines the environment in which to execute the callback function.\n * \\return NTSTATUS Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/threadpoolapiset/nf-threadpoolapiset-trysubmitthreadpoolcallback\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpSimpleTryPost(\n    _In_ PTP_CALLBACK_ROUTINE Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// winbase:CreateThreadpoolWork\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocWork(\n    _Out_ PTP_WORK *WorkReturn,\n    _In_ PTP_WORK_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// winbase:CloseThreadpoolWork\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseWork(\n    _Inout_ PTP_WORK Work\n    );\n\n// winbase:SubmitThreadpoolWork\nNTSYSAPI\nVOID\nNTAPI\nTpPostWork(\n    _Inout_ PTP_WORK Work\n    );\n\n// winbase:WaitForThreadpoolWorkCallbacks\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForWork(\n    _Inout_ PTP_WORK Work,\n    _In_ LOGICAL CancelPendingCallbacks\n    );\n\n// winbase:CreateThreadpoolTimer\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocTimer(\n    _Out_ PTP_TIMER *Timer,\n    _In_ PTP_TIMER_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// winbase:CloseThreadpoolTimer\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseTimer(\n    _Inout_ PTP_TIMER Timer\n    );\n\n// winbase:SetThreadpoolTimer\nNTSYSAPI\nVOID\nNTAPI\nTpSetTimer(\n    _Inout_ PTP_TIMER Timer,\n    _In_opt_ PLARGE_INTEGER DueTime,\n    _In_ ULONG Period,\n    _In_opt_ ULONG WindowLength\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n// winbase:SetThreadpoolTimerEx\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpSetTimerEx(\n    _Inout_ PTP_TIMER Timer,\n    _In_opt_ PLARGE_INTEGER DueTime,\n    _In_ ULONG Period,\n    _In_opt_ ULONG WindowLength\n    );\n#endif\n\n// winbase:IsThreadpoolTimerSet\nNTSYSAPI\nLOGICAL\nNTAPI\nTpIsTimerSet(\n    _In_ PTP_TIMER Timer\n    );\n\n// winbase:WaitForThreadpoolTimerCallbacks\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForTimer(\n    _Inout_ PTP_TIMER Timer,\n    _In_ LOGICAL CancelPendingCallbacks\n    );\n\n// winbase:CreateThreadpoolWait\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocWait(\n    _Out_ PTP_WAIT *WaitReturn,\n    _In_ PTP_WAIT_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// winbase:CloseThreadpoolWait\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseWait(\n    _Inout_ PTP_WAIT Wait\n    );\n\n// winbase:SetThreadpoolWait\nNTSYSAPI\nVOID\nNTAPI\nTpSetWait(\n    _Inout_ PTP_WAIT Wait,\n    _In_opt_ HANDLE Handle,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n// winbase:SetThreadpoolWaitEx\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpSetWaitEx(\n    _Inout_ PTP_WAIT Wait,\n    _In_opt_ HANDLE Handle,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _In_opt_ PVOID Reserved\n    );\n#endif\n\n// winbase:WaitForThreadpoolWaitCallbacks\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForWait(\n    _Inout_ PTP_WAIT Wait,\n    _In_ LOGICAL CancelPendingCallbacks\n    );\n\n// private\ntypedef _Function_class_(TP_IO_CALLBACK)\nVOID NTAPI TP_IO_CALLBACK(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context,\n    _In_ PVOID ApcContext,\n    _In_ PIO_STATUS_BLOCK IoSB,\n    _In_ PTP_IO Io\n    );\ntypedef TP_IO_CALLBACK *PTP_IO_CALLBACK;\n\n// winbase:CreateThreadpoolIo\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocIoCompletion(\n    _Out_ PTP_IO *IoReturn,\n    _In_ HANDLE File,\n    _In_ PTP_IO_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// winbase:CloseThreadpoolIo\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseIoCompletion(\n    _Inout_ PTP_IO Io\n    );\n\n// winbase:StartThreadpoolIo\nNTSYSAPI\nVOID\nNTAPI\nTpStartAsyncIoOperation(\n    _Inout_ PTP_IO Io\n    );\n\n// winbase:CancelThreadpoolIo\nNTSYSAPI\nVOID\nNTAPI\nTpCancelAsyncIoOperation(\n    _Inout_ PTP_IO Io\n    );\n\n// winbase:WaitForThreadpoolIoCallbacks\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForIoCompletion(\n    _Inout_ PTP_IO Io,\n    _In_ LOGICAL CancelPendingCallbacks\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocAlpcCompletion(\n    _Out_ PTP_ALPC *AlpcReturn,\n    _In_ HANDLE AlpcPort,\n    _In_ PTP_ALPC_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocAlpcCompletionEx(\n    _Out_ PTP_ALPC *AlpcReturn,\n    _In_ HANDLE AlpcPort,\n    _In_ PTP_ALPC_CALLBACK_EX Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseAlpcCompletion(\n    _Inout_ PTP_ALPC Alpc\n    );\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForAlpcCompletion(\n    _Inout_ PTP_ALPC Alpc\n    );\n\n// rev\nNTSYSAPI\nVOID\nNTAPI\nTpAlpcRegisterCompletionList(\n    _Inout_ PTP_ALPC Alpc\n    );\n\n// rev\nNTSYSAPI\nVOID\nNTAPI\nTpAlpcUnregisterCompletionList(\n    _Inout_ PTP_ALPC Alpc\n    );\n\n// private\ntypedef enum _TP_TRACE_TYPE\n{\n    TpTraceThreadPriority = 1,\n    TpTraceThreadAffinity,\n    MaxTpTraceType\n} TP_TRACE_TYPE;\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nTpCaptureCaller(\n    _In_ TP_TRACE_TYPE Type\n    );\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nTpCheckTerminateWorker(\n    _In_ HANDLE Thread\n    );\n\n#endif // _NTTP_H\n"
  },
  {
    "path": "phnt/include/ntuser.h",
    "content": "/*\n * Win32k NT User definitions.\n *\n * This file is part of System Informer.\n */\n\n#ifndef _NTUSER_H\n#define _NTUSER_H\n\ntypedef enum _USERTHREADINFOCLASS USERTHREADINFOCLASS;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserAttachThreadInput(\n    _In_ ULONG IdAttach,\n    _In_ ULONG IdAttachTo,\n    _In_ BOOL Attach\n    );\n\nNTSYSCALLAPI\nHDC\nNTAPI\nNtUserBeginPaint(\n    _In_ HWND WindowHandle,\n    _Inout_ LPPAINTSTRUCT lpPaint\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserBlockInput(\n    _In_ BOOL BlockInput\n    );\n\n#define FW_BOTH 0\n#define FW_16BIT 1\n#define FW_32BIT 2\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserFindWindowEx(\n    _In_opt_ HWND hwndParent,\n    _In_opt_ HWND hwndChild,\n    _In_ PCUNICODE_STRING ClassName,\n    _In_ PCUNICODE_STRING WindowName,\n    _In_ ULONG Type // FW_*\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserBuildHwndList(\n    _In_opt_ HANDLE DesktopHandle,\n    _In_opt_ HWND ParentWindowHandle,\n    _In_opt_ BOOL IncludeChildren,\n    _In_opt_ BOOL ExcludeImmersive,\n    _In_opt_ ULONG ThreadId,\n    _In_ ULONG HwndListInformationLength,\n    _Out_writes_bytes_(HwndListInformationLength) PVOID HwndListInformation,\n    _Out_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserBuildNameList(\n    _In_ HWINSTA WindowStationHandle, // GetProcessWindowStation\n    _In_ ULONG NameListInformationLength,\n    _Out_writes_bytes_(NameListInformationLength) PVOID NameListInformation,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserBuildPropList(\n    _In_ HWINSTA WindowStationHandle,\n    _In_ ULONG PropListInformationLength,\n    _Out_writes_bytes_(PropListInformationLength) PVOID PropListInformation,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserCanCurrentThreadChangeForeground(\n    VOID\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserCalculatePopupWindowPosition(\n    _In_ const POINT* anchorPoint,\n    _In_ const SIZE* windowSize,\n    _In_ ULONG flags,\n    _Inout_ RECT* excludeRect,\n    _Inout_ RECT* popupWindowPosition\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserCheckAccessForIntegrityLevel(\n    _In_ ULONG ProcessIdFirst,\n    _In_ ULONG ProcessIdSecond,\n    _Out_ PBOOLEAN GrantedAccess\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserCheckProcessForClipboardAccess(\n    _In_ ULONG ProcessId,\n    _Out_ PULONG GrantedAccess\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserCloseWindowStation(\n    _In_ HWINSTA WindowStationHandle\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_8)\n/**\n * The NtUserDisableProcessWindowFiltering routine disables window filtering\n * so you can enumerate immersive windows from the desktop.\n *\n * \\return Successful or errant status.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests#disableWindowFiltering\n */\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserDisableProcessWindowFiltering(\n    VOID\n    );\n#endif\n\nNTSYSCALLAPI\nHANDLE\nNTAPI\nNtUserGetProp(\n    _In_ HWND WindowHandle,\n    _In_ PCWSTR String\n    );\n\nNTSYSCALLAPI\nHANDLE\nNTAPI\nNtUserGetProp2(\n    _In_ HWND WindowHandle,\n    _In_ PCUNICODE_STRING String\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserCreateWindowStation(\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE KeyboardLayoutHandle,\n    _In_opt_ PVOID KeyboardLayoutOffset,\n    _In_opt_ PVOID NlsTableOffset,\n    _In_opt_ PVOID KeyboardDescriptor,\n    _In_opt_ PCUNICODE_STRING LanguageIdString,\n    _In_opt_ ULONG KeyboardLocale\n    );\n\ntypedef enum _CONSOLECONTROL\n{\n    ConsoleSetVDMCursorBounds = 0, // RECT\n    ConsoleNotifyConsoleApplication = 1, // CONSOLE_PROCESS_INFO\n    ConsoleFullscreenSwitch = 2,\n    ConsoleSetCaretInfo = 3, // CONSOLE_CARET_INFO\n    ConsoleSetReserveKeys = 4,\n    ConsoleSetForeground = 5, // CONSOLESETFOREGROUND\n    ConsoleSetWindowOwner = 6, // CONSOLEWINDOWOWNER\n    ConsoleEndTask = 7, // CONSOLEENDTASK\n} CONSOLECONTROL;\n\n#define CPI_NEWPROCESSWINDOW 0x0001\n\ntypedef struct _CONSOLE_PROCESS_INFO\n{\n    ULONG ProcessID;\n    ULONG Flags;\n} CONSOLE_PROCESS_INFO, *PCONSOLE_PROCESS_INFO;\n\ntypedef struct _CONSOLE_CARET_INFO\n{\n    HWND WindowHandle;\n    RECT Rect;\n} CONSOLE_CARET_INFO, *PCONSOLE_CARET_INFO;\n\ntypedef struct _CONSOLESETFOREGROUND\n{\n    HANDLE ProcessHandle;\n    BOOL Foreground;\n} CONSOLESETFOREGROUND, *PCONSOLESETFOREGROUND;\n\ntypedef struct _CONSOLEWINDOWOWNER\n{\n    HWND WindowHandle;\n    ULONG ProcessId;\n    ULONG ThreadId;\n} CONSOLEWINDOWOWNER, *PCONSOLEWINDOWOWNER;\n\ntypedef struct _CONSOLEENDTASK\n{\n    HANDLE ProcessId;\n    HWND WindowHandle;\n    ULONG ConsoleEventCode;\n    ULONG ConsoleFlags;\n} CONSOLEENDTASK, *PCONSOLEENDTASK;\n\n/**\n * Performs special kernel operations for console host applications. (win32u.dll)\n *\n * This includes reparenting the console window, allowing the console to pass foreground rights\n * on to launched console subsystem applications and terminating attached processes.\n *\n * \\param Command One of the CONSOLECONTROL values indicating which console control function should be executed.\n * \\param ConsoleInformation A pointer to one of the  structures specifying additional data for the requested console control function.\n * \\param ConsoleInformationLength The size of the structure pointed to by the ConsoleInformation parameter.\n * \\return Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserConsoleControl(\n    _In_ CONSOLECONTROL Command,\n    _In_reads_bytes_(ConsoleInformationLength) PVOID ConsoleInformation,\n    _In_ ULONG ConsoleInformationLength\n    );\n\n/**\n * Performs special kernel operations for console host applications. (user32.dll)\n *\n * This includes reparenting the console window, allowing the console to pass foreground rights\n * on to launched console subsystem applications and terminating attached processes.\n *\n * \\param Command One of the CONSOLECONTROL values indicating which console control function should be executed.\n * \\param ConsoleInformation A pointer to one of the  structures specifying additional data for the requested console control function.\n * \\param ConsoleInformationLength The size of the structure pointed to by the ConsoleInformation parameter.\n * \\return Successful or errant status.\n */\nNTSYSAPI\nNTSTATUS\nNTAPI\nConsoleControl(\n    _In_ CONSOLECONTROL Command,\n    _In_reads_bytes_(ConsoleInformationLength) PVOID ConsoleInformation,\n    _In_ ULONG ConsoleInformationLength\n    );\n\n/**\n * The NtUserGetClassName routine retrieves a string that specifies the window type.\n *\n * \\param WindowHandle A handle to the window and, indirectly, the class to which the window belongs.\n * \\param RealClassName Return the superclass or baseclass name when the window is a superclass.\n * \\param ClassName A pointer to a string that receives the window type.\n * \\return A handle to the foreground window, or NULL if no foreground window exists.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-realgetwindowclassw\n */\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetClassName(\n    _In_ HWND WindowHandle,\n    _In_ BOOL RealClassName,\n    _Out_ PUNICODE_STRING ClassName\n    );\n\n/**\n * The NtUserGetForegroundWindow routine retrieves a handle to the foreground window.\n *\n * \\return A handle to the foreground window, or NULL if no foreground window exists.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getforegroundwindow\n */\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserGetForegroundWindow(\n    VOID\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetIconInfo(\n    _In_ HICON IconOrCursorHandle,\n    _Out_ PICONINFO Iconinfo,\n    _Inout_opt_ PUNICODE_STRING Name,\n    _Inout_opt_ PUNICODE_STRING ResourceId,\n    _Out_opt_ PULONG ColorBits,\n    _In_ LOGICAL IsCursorHandle\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetIconSize(\n    _In_ HGDIOBJ IconOrCursorHandle,\n    _In_ LOGICAL IsCursorHandle,\n    _Out_ PULONG XX,\n    _Out_ PULONG YY\n    );\n\n/**\n * The NtUserGetProcessWindowStation routine retrieves the window station handle associated with the current process.\n *\n * \\return A handle to the window station, or NULL if the operation fails.\n * \\sa https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getprocesswindowstation\n */\nNTSYSCALLAPI\nHWINSTA\nNTAPI\nNtUserGetProcessWindowStation(\n    VOID\n    );\n\ntypedef enum _PROCESS_UICONTEXT\n{\n    PROCESS_UICONTEXT_DESKTOP,\n    PROCESS_UICONTEXT_IMMERSIVE,\n    PROCESS_UICONTEXT_IMMERSIVE_BROKER,\n    PROCESS_UICONTEXT_IMMERSIVE_BROWSER\n} PROCESS_UICONTEXT;\n\ntypedef enum _PROCESS_UI_FLAGS\n{\n    PROCESS_UIF_NONE,\n    PROCESS_UIF_AUTHORING_MODE,\n    PROCESS_UIF_RESTRICTIONS_DISABLED\n} PROCESS_UI_FLAGS;\nDEFINE_ENUM_FLAG_OPERATORS(PROCESS_UI_FLAGS);\n\ntypedef struct _PROCESS_UICONTEXT_INFORMATION\n{\n    PROCESS_UICONTEXT ProcessUIContext;\n    PROCESS_UI_FLAGS Flags;\n} PROCESS_UICONTEXT_INFORMATION, *PPROCESS_UICONTEXT_INFORMATION;\n    \nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserGetProcessUIContextInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_UICONTEXT_INFORMATION UIContext\n    );\n    \nNTSYSCALLAPI\nBOOL\nNTAPI\nGetProcessUIContextInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_UICONTEXT_INFORMATION UIContext\n    );\n\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserGetThreadState(\n    _In_ ULONG UserThreadState\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserGhostWindowFromHungWindow(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSAPI\nHWND\nNTAPI\nGhostWindowFromHungWindow(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserHungWindowFromGhostWindow(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSAPI\nHWND\nNTAPI\nHungWindowFromGhostWindow(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserInternalGetWindowText(\n    _In_ HWND WindowHandle,\n    _Out_writes_to_(cchMaxCount, return + 1) LPWSTR pString,\n    _In_ ULONG cchMaxCount\n    );\n\nNTSYSCALLAPI\nHICON\nNTAPI\nNtUserInternalGetWindowIcon(\n    _In_ HWND WindowHandle,\n    _In_ ULONG IconType\n    );\n\nNTSYSCALLAPI\nHANDLE\nNTAPI\nNtUserOpenDesktop(\n    _In_ PCOBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG Flags,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\n/**\n * Opens the specified window station.\n *\n * \\param ObjectAttributes The name of the window station to be opened. Window station names are case-insensitive. This window station must belong to the current session.\n * \\param DesiredAccess The access to the window station.\n * \\return Successful or errant status.\n */\nNTSYSCALLAPI\nHWINSTA\nNTAPI\nNtUserOpenWindowStation(\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\ntypedef enum _WINDOWINFOCLASS\n{\n    WindowProcess = 0, // q: ULONG (Process ID)\n    WindowRealProcess = 1, // q: ULONG (Process ID)\n    WindowThread = 2, // q: ULONG (Thread ID)\n    WindowActiveWindow = 3, // q: HWND\n    WindowFocusWindow = 4, // q: HWND\n    WindowIsHung = 5, // q: BOOLEAN\n    WindowClientBase = 6, // q: PVOID\n    WindowIsForegroundThread = 7, // q: BOOLEAN\n    WindowDefaultImeWindow = 8, // q: HWND\n    WindowDefaultInputContext = 9, // q: HIMC\n} WINDOWINFOCLASS, *PWINDOWINFOCLASS;\n\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserQueryWindow(\n    _In_ HWND WindowHandle,\n    _In_ WINDOWINFOCLASS WindowInfo\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserSetActiveWindow(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserSetChildWindowNoActivate(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserSetFocus(\n    _In_ HWND WindowHandle\n    );\n\n// User32 ordinal 2005\nNTSYSAPI\nBOOL\nNTAPI\nSetChildWindowNoActivate(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ USERTHREADINFOCLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserSetProcessWindowStation(\n    _In_ HWINSTA WindowStationHandle\n    );\n\n// rev // Valid bit masks enforced by NtUserSetProcessWin32Capabilities\n#define PROC_CAP_FLAGS1_VALID_MASK     0x00000007u    // bits 0-2\n#define PROC_CAP_FLAGS2_VALID_MASK     0x00000007u    // bits 0-2\n#define PROC_CAP_ENABLE_VALID_MASK     0x00000001u    // bit 0\n#define PROC_CAP_DISABLE_VALID_MASK    0x00000001u    // bit 0\n\n#define PROC_CAP_FLAGS1_BIT0           0x00000001u\n#define PROC_CAP_FLAGS1_BIT1           0x00000002u\n#define PROC_CAP_FLAGS1_BIT2           0x00000004u\n\n#define PROC_CAP_FLAGS2_BIT0           0x00000001u\n#define PROC_CAP_FLAGS2_BIT1           0x00000002u\n#define PROC_CAP_FLAGS2_BIT2           0x00000004u\n\n#define PROC_CAP_ENABLE_BIT0           0x00000001u\n#define PROC_CAP_DISABLE_BIT0          0x00000001u\n\n#define PROC_CAP_FLAGS1_INVALID(x)     (((x) & ~PROC_CAP_FLAGS1_VALID_MASK) != 0)\n#define PROC_CAP_FLAGS2_INVALID(x)     (((x) & ~PROC_CAP_FLAGS2_VALID_MASK) != 0)\n#define PROC_CAP_ENABLE_INVALID(x)     (((x) & ~PROC_CAP_ENABLE_VALID_MASK) != 0)\n#define PROC_CAP_DISABLE_INVALID(x)    (((x) & ~PROC_CAP_DISABLE_VALID_MASK) != 0)\n\n// rev\ntypedef struct _USER_PROCESS_CAP_ENTRY\n{\n    HANDLE ProcessHandle;\n    ULONG Flags1;\n    ULONG Flags2;\n    ULONG EnableMask;\n    ULONG DisableMask;\n} USER_PROCESS_CAP_ENTRY, *PUSER_PROCESS_CAP_ENTRY;\n\n// rev\ntypedef struct _USER_PROCESS_CAP_INTERNAL\n{\n    PVOID ProcessObject;\n    ULONG SessionId;\n    ULONG Reserved;\n    ULONGLONG FlagsPacked;\n    ULONGLONG CapabilityPacked;\n} USER_PROCESS_CAP_INTERNAL, *PUSER_PROCESS_CAP_INTERNAL;\n\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserSetProcessWin32Capabilities(\n    _In_reads_(Count) const USER_PROCESS_CAP_ENTRY* Capabilities,\n    _In_ ULONG Count\n    );\n\n// rev\n/**\n * The NtUserSetProcessRestrictionExemption routine marks the current process as exempt from certain win32k/user restrictions.\n * Note: This requires a developer mode/license check.\n *\n * \\param Enable Indicates whether to enable or disable the exemption.\n * \\return Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserSetProcessRestrictionExemption(\n    _In_ BOOL EnableExemption\n    );\n\n// rev\n/**\n * The NtUserSetProcessUIAccessZorder routine tweaks window z-order behavior for UIAccess scenarios.\n * Note: Set only when the process is not elevated.\n *\n * \\return Successful or errant status.\n */\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserSetProcessUIAccessZorder(\n    VOID\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserSetWindowPlacement(\n    _In_  HWND WindowHandle,\n    _Inout_ const WINDOWPLACEMENT* lpwndpl\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserSetWindowStationUser(\n    _In_ HWINSTA WindowStationHandle,\n    _In_ PLUID UserLogonId,\n    _In_ PSID UserSid,\n    _In_ ULONG UserSidLength\n    );\n\nNTSYSAPI\nBOOL\nNTAPI\nSetWindowStationUser(\n    _In_ HWINSTA WindowStationHandle,\n    _In_ PLUID UserLogonId,\n    _In_ PSID UserSid,\n    _In_ ULONG UserSidLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserTestForInteractiveUser(\n    _In_ PLUID AuthenticationId\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserSwitchDesktop(\n    _In_ HDESK DesktopHandle,\n    _In_opt_ ULONG Flags,\n    _In_opt_ ULONG FadeTime\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserSetThreadDesktop(\n    _In_ HDESK DesktopHandle\n    );\n\nNTSYSAPI\nHWND\nNTAPI\nChildWindowFromPoint(\n    _In_ HWND WindowHandle,\n    _In_ POINT pt\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserChildWindowFromPointEx(\n    _In_ HWND WindowHandle,\n    _In_ POINT pt,\n    _In_ ULONG flags\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserClipCursor(\n    _In_ const RECT* lpRect\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserCloseDesktop(\n    _In_ HDESK DesktopHandle\n    );\n\nNTSYSCALLAPI\nLONG\nNTAPI\nNtUserCopyAcceleratorTable(\n    _In_ HACCEL hAccelSrc,\n    _In_ LPACCEL lpAccelDst,\n    _In_ LONG cAccelEntries\n    );\n\nNTSYSCALLAPI\nHACCEL\nNTAPI\nNtUserCreateAcceleratorTable(\n    _In_ LPACCEL paccel,\n    _In_ LONG cAccel\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserDeleteMenu(\n    _In_ HMENU MenuHandle,\n    _In_ ULONG Position,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserDestroyMenu(\n    _In_ HMENU MenuHandle\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserDestroyWindow(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserDragDetect(\n    _In_ HWND WindowHandle,\n    _In_ POINT pt\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserDragObject(\n    _In_ HWND WindowHandleParent,\n    _In_ HWND WindowHandleFrom,\n    _In_ ULONG fmt,\n    _In_ ULONG_PTR data,\n    _In_ HCURSOR hcur\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserDrawAnimatedRects(\n    _In_ HWND WindowHandle,\n    _In_ int idAni,\n    _In_ const RECT* lprcFrom,\n    _In_ const RECT* lprcTo\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserEndMenu(\n    VOID\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserEndPaint(\n    _In_ HWND WindowHandle,\n    _Inout_ const PAINTSTRUCT* lpPaint\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserEnumDisplayMonitors(\n    _In_ HDC hdc,\n    _In_ LPCRECT lprcClip,\n    _In_ MONITORENUMPROC lpfnEnum,\n    _In_ LPARAM dwData\n    );\n\nNTSYSCALLAPI\nHRGN\nNTAPI\nNtUserExcludeUpdateRgn(\n    _In_ HDC hDC,\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserFlashWindowEx(\n    _In_ PFLASHWINFO pfwi\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserGetAncestor(\n    _In_ HWND WindowHandle,\n    _In_ ULONG gaFlags\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetCaretBlinkTime(\n    VOID\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetCaretPos(\n    _In_ LPPOINT lpPoint\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetClipCursor(\n    _In_ LPRECT lpRect\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetComboBoxInfo(\n    _In_ HWND WindowHandleCombo,\n    _Inout_ PCOMBOBOXINFO pcbi\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetCurrentInputMessageSource(\n    _Inout_ INPUT_MESSAGE_SOURCE* InputMessageSource\n    );\n\nNTSYSCALLAPI\nHCURSOR\nNTAPI\nNtUserGetCursor(\n    VOID\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetCursorInfo(\n    _In_ PCURSORINFO pci\n    );\n\nNTSYSCALLAPI\nHDC\nNTAPI\nNtUserGetDCEx(\n    _In_ HWND WindowHandle,\n    _In_ HRGN hrgnClip,\n    _In_ ULONG flags\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetDisplayAutoRotationPreferences(\n    _In_ ORIENTATION_PREFERENCE* pOrientation\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetDoubleClickTime(\n    VOID\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetGUIThreadInfo(\n    _In_ ULONG idThread,\n    _In_ PGUITHREADINFO pgui\n    );\n\n#ifndef GR_GDIOBJECTS\n#define GR_GDIOBJECTS 0\n#endif\n#ifndef GR_USEROBJECTS\n#define GR_USEROBJECTS 1\n#endif\n#ifndef GR_GDIOBJECTS_PEAK\n#define GR_GDIOBJECTS_PEAK 2\n#endif\n#ifndef GR_USEROBJECTS_PEAK\n#define GR_USEROBJECTS_PEAK 4\n#endif\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetGuiResources(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetLayeredWindowAttributes(\n    _In_ HWND WindowHandle,\n    _Out_opt_ COLORREF* Key,\n    _Out_opt_ PBYTE Alpha,\n    _Out_opt_ PULONG Flags\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetListBoxInfo(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetMenuBarInfo(\n    _In_ HWND WindowHandle,\n    _In_ LONG idObject,\n    _In_ LONG idItem,\n    _In_ PMENUBARINFO pmbi\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetMenuItemRect(\n    _In_ HWND WindowHandle,\n    _In_ HMENU MenuHandle,\n    _In_ ULONG MenuIndex,\n    _In_ PRECT MenuRect\n    );\n\nNTSYSCALLAPI\nLONG\nNTAPI\nNtUserGetMouseMovePointsEx(\n    _In_ ULONG MouseMovePointsSize,\n    _In_ LPMOUSEMOVEPOINT InputBuffer,\n    _Out_ LPMOUSEMOVEPOINT OutputBuffer,\n    _In_ LONG OutputBufferCount,\n    _In_ ULONG Resolution\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetRawInputData(\n    _In_ HRAWINPUT RawInputData,\n    _In_ ULONG RawInputCommand,\n    _Out_opt_ PVOID RawInputBuffer,\n    _Inout_ PULONG RawInputBufferSize,\n    _In_ ULONG RawInputHeaderSize\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetRawInputDeviceList(\n    _In_ PRAWINPUTDEVICELIST RawInputDeviceList,\n    _Inout_ PULONG RawInputDeviceCount,\n    _In_ ULONG RawInputDeviceSize\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetRegisteredRawInputDevices(\n    _Out_opt_ PRAWINPUTDEVICE RawInputDevices,\n    _Inout_ PULONG RawInputDeviceCount,\n    _In_ ULONG RawInputDeviceSize\n    );\n\nNTSYSAPI\nHWND\nNTAPI\nGetSendMessageReceiver(\n    _In_ HANDLE ThreadId\n    );\n\nNTSYSCALLAPI\nHMENU\nNTAPI\nNtUserGetSystemMenu(\n    _In_ HWND WindowHandle,\n    _In_ BOOL Revert\n    );\n\nNTSYSCALLAPI\nHDESK\nNTAPI\nNtUserGetThreadDesktop(\n    _In_ ULONG ThreadId\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetTitleBarInfo(\n    _In_ HWND WindowHandle,\n    _In_ PTITLEBARINFO pti\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetObjectInformation(\n    _In_ HANDLE ObjectHandle,\n    _In_ LONG Index,\n    _In_ PVOID vInfo,\n    _In_ ULONG Length,\n    _In_ PULONG LengthNeeded\n    );\n\nNTSYSCALLAPI\nHDC\nNTAPI\nNtUserGetWindowDC(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserGetWindowPlacement(\n    _In_ HWND WindowHandle,\n    _Inout_ PWINDOWPLACEMENT WindowPlacement\n    );\n\nNTSYSCALLAPI\nHANDLE\nNTAPI\nGetWindowProcessHandle(\n    _In_ HWND WindowHandle,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nNTSYSCALLAPI\nHANDLE\nNTAPI\nNtUserGetWindowProcessHandle(\n    _In_ HWND WindowHandle,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserHiliteMenuItem(\n    _In_ HWND WindowHandle,\n    _In_ HMENU MenuHandle,\n    _In_ ULONG IDHiliteItem,\n    _In_ ULONG Hilite\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserInvalidateRect(\n    _In_ HWND WindowHandle,\n    _In_ const RECT* Rect,\n    _In_ BOOL Erase\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserInvalidateRgn(\n    _In_ HWND WindowHandle,\n    _In_ HRGN RgnHandle,\n    _In_ BOOL Erase\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserIsTouchWindow(\n    _In_ HWND WindowHandle,\n    _In_ PULONG Flags\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserKillTimer(\n    _In_ HWND WindowHandle,\n    _In_ ULONG_PTR IDEvent\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserLockWorkStation(\n    VOID\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserLogicalToPhysicalPoint(\n    _In_ HWND WindowHandle,\n    _In_ LPPOINT lpPoint\n    );\n\nNTSYSCALLAPI\nLONG\nNTAPI\nNtUserMenuItemFromPoint(\n    _In_ HWND WindowHandle,\n    _In_ HMENU MenuHandle,\n    _In_ POINT ptScreen\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserMoveWindow(\n    _In_ HWND WindowHandle,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _In_ LONG Width,\n    _In_ LONG Height,\n    _In_ BOOL Repaint\n    );\n\nNTSYSCALLAPI\nHDESK\nNTAPI\nNtUserOpenInputDesktop(\n    _In_ ULONG Flags,\n    _In_ BOOL Inherit,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserPhysicalToLogicalPoint(\n    _In_ HWND WindowHandle,\n    _In_ LPPOINT Point\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserPrintWindow(\n    _In_ HWND WindowHandle,\n    _In_ HDC Hdc,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ USERTHREADINFOCLASS ThreadInformationClass,\n    _Out_writes_bytes_(*ReturnLength) PVOID ThreadInformation,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ USERTHREADINFOCLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength\n    );\n\nNTSYSAPI\nBOOL\nNTAPI\nNtUserQuerySendMessage(\n    _Inout_ PMSG Message\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRaiseLowerShellWindow(\n    _In_ HWND WindowHandle,\n    _In_ BOOLEAN SetWithOptions\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserRedrawWindow(\n    _In_ HWND WindowHandle,\n    _In_ const PRECT lprcUpdate,\n    _In_ HRGN hrgnUpdate,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserRealChildWindowFromPoint(\n    _In_ HWND WindowHandleParent,\n    _In_ POINT ptParentClientCoords\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserRegisterHotKey(\n    _In_ HWND WindowHandle,\n    _In_ LONG Id,\n    _In_ ULONG fsModifiers,\n    _In_ ULONG vk\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserRemoveMenu(\n    _In_ HMENU MenuHandle,\n    _In_ ULONG Position,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserSendInput(\n    _In_ ULONG Count,\n    _In_ LPINPUT Inputs,\n    _In_ LONG Size\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserSetActiveWindow(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserSetCapture(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserSetTimer(\n    _In_ HWND WindowHandle,\n    _In_ ULONG_PTR IDEvent,\n    _In_ ULONG Elapse,\n    _In_ TIMERPROC TimerFunc,\n    _In_ ULONG ToleranceDelay\n    );\n\nNTSYSCALLAPI\nUSHORT\nNTAPI\nNtUserSetClassWord(\n    _In_ HWND WindowHandle,\n    _In_ LONG Index,\n    _In_ USHORT NewWord\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserSetCursorPos(\n    _In_ LONG X,\n    _In_ LONG Y\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserSetFocus(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserSetLayeredWindowAttributes(\n    _In_ HWND WindowHandle,\n    _In_ COLORREF Key,\n    _In_ BYTE Alpha,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserSetWindowPos(\n    _In_ HWND WindowHandle,\n    _In_opt_ HWND WindowHandleInsertAfter,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _In_ LONG cx,\n    _In_ LONG cy,\n    _In_ ULONG Flags\n    );\n\nFORCEINLINE\nBOOL\nNTAPI\nNtUserBringWindowToTop(\n    _In_ HWND WindowHandle\n    )\n{\n    return NtUserSetWindowPos(\n        WindowHandle,\n        NULL,\n        0, 0, 0, 0,\n        3\n        );\n}\n\n// Send to the window registered with NtUserRegisterCloakedNotification\n// when cloak state of the window has changed\n// wParam - if window cloak state changed contains cloaking value\n//          which can be one/all of the below\n//          DWM_CLOAKED_APP(0x0000001).The window was cloaked by its owner application.\n//          DWM_CLOAKED_SHELL(0x0000002).The window was cloaked by the Shell.\n//          0 - window is not cloaked\n//\n// lParam - 0 (unused)\n//\n#define WM_CLOAKED_STATE_CHANGED 0x0347\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserRegisterCloakedNotification(\n    _In_ HWND WindowHandle,\n    _In_ BOOL Register\n    );\n\nNTSYSCALLAPI\nUSHORT\nNTAPI\nNtUserSetWindowWord(\n    _In_ HWND WindowHandle,\n    _In_ LONG Index,\n    _In_ USHORT NewWord\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserSetForegroundWindowForApplication(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserShellForegroundBoostProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserSetAdditionalForegroundBoostProcesses(\n    _In_ HWND WindowHandle\n    );\n\n// rev\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserSetAdditionalPowerThrottlingProcess(\n    _In_ HWND WindowHandle,\n    _In_ ULONG ProcessHandlesCount,\n    _In_reads_(ProcessHandlesCount) PHANDLE ProcessHandles\n    );\n\nNTSYSCALLAPI\nLONG\nNTAPI\nNtUserShowCursor(\n    _In_ BOOL Show\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserShowWindow(\n    _In_ HWND WindowHandle,\n    _In_ LONG CmdShow\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserShowWindowAsync(\n    _In_ HWND WindowHandle,\n    _In_ LONG CmdShow\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserShutdownBlockReasonQuery(\n    _In_ HWND WindowHandle,\n    _Out_ PWSTR Buffer,\n    _Inout_ PULONG BufferCount\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserShutdownReasonDestroy(\n    _In_ HWND WindowHandle\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserTrackMouseEvent(\n    _In_ LPTRACKMOUSEEVENT EventTrack\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserTrackPopupMenuEx(\n    _In_ HMENU MenuHandle,\n    _In_ ULONG Flags,\n    _In_ LONG x,\n    _In_ LONG y,\n    _In_ HWND WindowHandle,\n    _In_ LPTPMPARAMS lptpm\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserUnhookWinEvent(\n    _In_ HWINEVENTHOOK WinEventHookHandle\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserUnregisterHotKey(\n    _In_ HWND WindowHandle,\n    _In_ LONG Id\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserUserHandleGrantAccess(\n    _In_ HANDLE UserHandle,\n    _In_ HANDLE Job,\n    _In_ BOOL Grant\n    );\n\nNTSYSCALLAPI\nBOOL\nNTAPI\nNtUserValidateRect(\n    _In_ HWND WindowHandle,\n    _In_ const RECT* Rect\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserWindowFromDC(\n    _In_ HDC Hdc\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserWindowFromPhysicalPoint(\n    _In_ POINT Point\n    );\n\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserWindowFromPoint(\n    _In_ POINT Point\n    );\n\n// rev // valid since 20H1\n#define SFI_CREATEMENU                              0 // NtUserCallNoParam\n#define SFI_CREATEPOPUPMENU                         1 // NtUserCallNoParam\n#define SFI_ALLOWFOREGROUNDACTIVATION               2 // NtUserCallNoParam\n#define SFI_CANCELQUEUEEVENTCOMPLETIONPACKET        3 // NtUserCallNoParam\n#define SFI_CLEARWAKEMASK                           4 // NtUserCallNoParam\n#define SFI_CREATESYSTEMTHREADS                     5 // NtUserCallNoParam\n#define SFI_DESTROYCARET                            6 // NtUserCallNoParam\n#define SFI_DISABLEPROCESSWINDOWSGHOSTING           7 // NtUserCallNoParam\n#define SFI_DRAINTHREADCOREMESSAGINGCOMPLETIONS     8 // NtUserCallNoParam\n#define SFI_GETDEVICECHANGEINFO                     9 // NtUserCallNoParam\n#define SFI_GETIMESHOWSTATUS                        10 // NtUserCallNoParam\n#define SFI_GETINPUTDESKTOP                         11 // NtUserCallNoParam\n#define SFI_GETMESSAGEPOS                           12 // NtUserCallNoParam\n#define SFI_GETQUEUEIOCP                            13 // NtUserCallNoParam\n#define SFI_GETUNPREDICTEDMESSAGEPOS                14 // NtUserCallNoParam\n#define SFI_HANDLESYSTEMTHREADCREATIONFAILURE       15 // NtUserCallNoParam\n#define SFI_HIDECURSORNOCAPTURE                     16 // NtUserCallNoParam\n#define SFI_ISQUEUEATTACHED                         17 // NtUserCallNoParam\n#define SFI_LOADCURSORSANDICONS                     18 // NtUserCallNoParam\n#define SFI_LOADUSERAPIHOOK                         19 // NtUserCallNoParam\n#define SFI_PREPAREFORLOGOFF                        20 // NtUserCallNoParam\n#define SFI_REASSOCIATEQUEUEEVENTCOMPLETIONPACKET   21 // NtUserCallNoParam\n#define SFI_RELEASECAPTURE                          22 // NtUserCallNoParam\n#define SFI_REMOVEQUEUECOMPLETION                   23 // NtUserCallNoParam\n#define SFI_RESETDBLCLK                             24 // NtUserCallNoParam\n#define SFI_ZAPACTIVEANDFOCUS                       25 // NtUserCallNoParam\n#define SFI_REMOTECONSOLESHADOWSTOP                 26 // NtUserCallNoParam\n#define SFI_REMOTEDISCONNECT                        27 // NtUserCallNoParam\n#define SFI_REMOTESHADOWSETUP                       30 // NtUserCallNoParam\n#define SFI_REMOTESHADOWSTOP                        31 // NtUserCallNoParam\n#define SFI_REMOTEPASSTHRUENABLE                    32 // NtUserCallNoParam\n#define SFI_REMOTEPASSTHRUDISABLE                   33 // NtUserCallNoParam\n#define SFI_REMOTECONNECTSTATE                      34 // NtUserCallNoParam\n#define SFI_UPDATEPERUSERIMMENABLING                36 // NtUserCallNoParam\n#define SFI_USERPOWERCALLOUTWORKER                  37 // NtUserCallNoParam\n#define SFI_WAKERITFORSHUTDOWN                      38 // NtUserCallNoParam\n#define SFI_DOINITMESSAGEPUMPHOOK                   39 // NtUserCallNoParam\n#define SFI_DOUNINITMESSAGEPUMPHOOK                 40 // NtUserCallNoParam\n#define SFI_ENABLEMOUSEINPOINTERFORTHREAD           41 // NtUserCallNoParam\n#define SFI_DEFERREDDESKTOPROTATION                 42 // NtUserCallNoParam\n#define SFI_ENABLEPERMONITORMENUSCALING             43 // NtUserCallNoParam\n#define SFI_BEGINDEFERWINDOWPOS                     44 // NtUserCallOneParam\n#define SFI_GETSENDMESSAGERECEIVER                  45 // NtUserCallOneParam\n#define SFI_ALLOWSETFOREGROUNDWINDOW                46 // NtUserCallOneParam\n#define SFI_CSDDEUNINITIALIZE                       47 // NtUserCallOneParam\n#define SFI_ENUMCLIPBOARDFORMATS                    49 // NtUserCallOneParam\n#define SFI_GETINPUTEVENT                           50 // NtUserCallOneParam\n#define SFI_GETKEYBOARDTYPE                         51 // NtUserCallOneParam\n#define SFI_GETPROCESSDEFAULTLAYOUT                 52 // NtUserCallOneParam\n#define SFI_GETWINSTATIONINFO                       53 // NtUserCallOneParam\n#define SFI_LOCKSETFOREGROUNDWINDOW                 54 // NtUserCallOneParam\n#define SFI_LW_LOADFONTS                            55 // NtUserCallOneParam\n#define SFI_MAPDESKTOPOBJECT                        56 // NtUserCallOneParam\n#define SFI_MESSAGEBEEP                             57 // NtUserCallOneParam\n#define SFI_PLAYEVENTSOUND                          58 // NtUserCallOneParam\n#define SFI_POSTQUITMESSAGE                         59 // NtUserCallOneParam\n#define SFI_REALIZEPALETTE                          60 // NtUserCallOneParam\n#define SFI_REGISTERLPK                             61 // NtUserCallOneParam\n#define SFI_REGISTERSYSTEMTHREAD                    62 // NtUserCallOneParam\n#define SFI_REMOTERECONNECT                         63 // NtUserCallOneParam\n#define SFI_REMOTETHINWIRESTATS                     64 // NtUserCallOneParam\n#define SFI_REMOTENOTIFY                            65 // NtUserCallOneParam\n#define SFI_REPLYMESSAGE                            66 // NtUserCallOneParam\n#define SFI_SETCARETBLINKTIME                       67 // NtUserCallOneParam\n#define SFI_SETDOUBLECLICKTIME                      68 // NtUserCallOneParam\n#define SFI_SETMESSAGEEXTRAINFO                     69 // NtUserCallOneParam\n#define SFI_SETPROCESSDEFAULTLAYOUT                 70 // NtUserCallOneParam\n#define SFI_SETWATERMARKSTRINGS                     71 // NtUserCallOneParam\n#define SFI_SHOWSTARTGLASS                          72 // NtUserCallOneParam\n#define SFI_SWAPMOUSEBUTTON                         73 // NtUserCallOneParam\n#define SFI_WOWMODULEUNLOAD                         74 // NtUserCallOneParam\n#define SFI_DWMLOCKSCREENUPDATES                    75 // NtUserCallOneParam\n#define SFI_ENABLESESSIONFORMMCSS                   76 // NtUserCallOneParam\n#define SFI_SETWAITFORQUEUEATTACH                   77 // NtUserCallOneParam\n#define SFI_THREADMESSAGEQUEUEATTACHED              78 // NtUserCallOneParam\n#define SFI_ENSUREDPIDEPSYSMETCACHEFORPLATEAU       80 // NtUserCallOneParam\n#define SFI_FORCEENABLENUMPADTRANSLATION            81 // NtUserCallOneParam\n#define SFI_SETTSFEVENTSTATE                        82 // NtUserCallOneParam\n#define SFI_SETSHELLCHANGENOTIFYHWND                83 // NtUserCallOneParam\n#define SFI_DEREGISTERSHELLHOOKWINDOW               84 // NtUserCallHwnd\n#define SFI_DWP_GETENABLEDPOPUPOFFSET               85 // NtUserCallHwnd\n#define SFI_GETMODERNAPPWINDOW                      86 // NtUserCallHwnd\n#define SFI_GETWINDOWCONTEXTHELPID                  87 // NtUserCallHwnd\n#define SFI_REGISTERSHELLHOOKWINDOW                 88 // NtUserCallHwnd\n#define SFI_SETMSGBOX                               89 // NtUserCallHwnd\n#define SFI_INITTHREADCOREMESSAGINGIOCP             90 // NtUserCallHwnd, NtUserCallHwndSafe\n#define SFI_SCHEDULEDISPATCHNOTIFICATION            91 // NtUserCallHwnd, NtUserCallHwndSafe\n#define SFI_SETPROGMANWINDOW                        92 // NtUserCallHwndOpt\n#define SFI_SETTASKMANWINDOW                        93 // NtUserCallHwndOpt\n#define SFI_GETCLASSICOCUR                          94 // NtUserCallHwndParam\n#define SFI_CLEARWINDOWSTATE                        95 // NtUserCallHwndParam\n#define SFI_KILLSYSTEMTIMER                         96 // NtUserCallHwndParam\n#define SFI_NOTIFYOVERLAYWINDOW                     97 // NtUserCallHwndParam\n#define SFI_SETDIALOGPOINTER                        99 // NtUserCallHwndParam\n#define SFI_SETVISIBLE                              100 // NtUserCallHwndParam\n#define SFI_SETWINDOWCONTEXTHELPID                  101 // NtUserCallHwndParam\n#define SFI_SETWINDOWSTATE                          102 // NtUserCallHwndParam\n#define SFI_REGISTERWINDOWARRANGEMENTCALLOUT        103 // NtUserCallHwndParam\n#define SFI_ENABLEMODERNAPPWINDOWKEYBOARDINTERCEPT  104 // NtUserCallHwndParam\n#define SFI_ARRANGEICONICWINDOWS                    105 // NtUserCallHwndLock\n#define SFI_DRAWMENUBAR                             106 // NtUserCallHwndLock\n#define SFI_CHECKIMESHOWSTATUSINTHREAD              107 // NtUserCallHwndLock, NtUserCallHwndLockSafe\n#define SFI_GETSYSMENUOFFSET                        108 // NtUserCallHwndLock\n#define SFI_REDRAWFRAME                             109 // NtUserCallHwndLock\n#define SFI_REDRAWFRAMEANDHOOK                      110 // NtUserCallHwndLock\n#define SFI_SETDIALOGSYSTEMMENU                     111 // NtUserCallHwndLock\n#define SFI_SETFOREGROUNDWINDOW                     112 // NtUserCallHwndLock\n#define SFI_SETSYSMENU                              113 // NtUserCallHwndLock\n#define SFI_UPDATECLIENTRECT                        114 // NtUserCallHwndLock\n#define SFI_UPDATEWINDOW                            115 // NtUserCallHwndLock\n#define SFI_SETCANCELROTATIONDELAYHINTWINDOW        116 // NtUserCallHwndLock\n#define SFI_GETWINDOWTRACKINFOASYNC                 117 // NtUserCallHwndLock\n#define SFI_BROADCASTIMESHOWSTATUSCHANGE            118 // NtUserCallHwndParamLock\n#define SFI_SETMODERNAPPWINDOW                      119 // NtUserCallHwndParamLock\n#define SFI_REDRAWTITLE                             120 // NtUserCallHwndParamLock\n#define SFI_SHOWOWNEDPOPUPS                         121 // NtUserCallHwndParamLock\n#define SFI_SWITCHTOTHISWINDOW                      122 // NtUserCallHwndParamLock\n#define SFI_UPDATEWINDOWS                           123 // NtUserCallHwndParamLock\n#define SFI_VALIDATERGN                             124 // NtUserCallHwndParamLock\n#define SFI_ENABLEWINDOW                            125 // NtUserCallHwndParamLock, NtUserCallHwndParamLockSafe\n#define SFI_CHANGEWINDOWMESSAGEFILTER               126 // NtUserCallTwoParam\n#define SFI_GETCURSORPOS                            127 // NtUserCallTwoParam\n#define SFI_INITANSIOEM                             128 // NtUserCallTwoParam\n#define SFI_NLSKBDSENDIMENOTIFICATION               129 // NtUserCallTwoParam\n#define SFI_REGISTERGHOSTWINDOW                     130 // NtUserCallTwoParam\n#define SFI_REGISTERLOGONPROCESS                    131 // NtUserCallTwoParam\n#define SFI_REGISTERSIBLINGFROSTWINDOW              132 // NtUserCallTwoParam\n#define SFI_REGISTERUSERHUNGAPPHANDLERS             133 // NtUserCallTwoParam\n#define SFI_REMOTESHADOWCLEANUP                     134 // NtUserCallTwoParam\n#define SFI_REMOTESHADOWSTART                       135 // NtUserCallTwoParam\n#define SFI_SETCARETPOS                             136 // NtUserCallTwoParam\n#define SFI_SETTHREADQUEUEMERGESETTING              137 // NtUserCallTwoParam\n#define SFI_UNHOOKWINDOWSHOOK                       138 // NtUserCallTwoParam\n#define SFI_ENABLESHELLWINDOWMANAGEMENTBEHAVIOR     139 // NtUserCallTwoParam\n#define SFI_CITSETINFO                              140 // NtUserCallTwoParam\n#define SFI_SCALESYSTEMMETRICFORDPIWITHOUTCACHE     141 // NtUserCallTwoParam\n\n// N.B.\n// Windows 10 uses NtUserCall* dispatch routines to invoke ~140 functions\n// by index (note that our index table is valid only since 20H1).\n// Windows 11 uses the newly introduced syscalls for each function instead.\n\n// private // before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallNoParam(\n    _In_ ULONG xpfnProc\n    );\n\n// private // before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallOneParam(\n    _In_ ULONG_PTR Param,\n    _In_ ULONG xpfnProc\n    );\n\n// private // before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallHwnd(\n    _In_ HWND hwnd,\n    _In_ ULONG xpfnProc\n    );\n\n// private // before WIN11\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS5)\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallHwndSafe(\n    _In_ HWND hwnd,\n    _In_ ULONG xpfnProc\n    );\n#endif\n\n// private // before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallHwndOpt(\n    _In_opt_ HWND hwnd,\n    _In_ ULONG xpfnProc\n    );\n\n// private // before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallHwndParam(\n    _In_ HWND hwnd,\n    _In_ ULONG_PTR Param,\n    _In_ ULONG xpfnProc\n    );\n\n// private // before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallHwndLock(\n    _In_ HWND hwnd,\n    _In_ ULONG xpfnProc\n    );\n\n// private // before WIN11\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS5)\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallHwndLockSafe(\n    _In_ HWND hwnd,\n    _In_ ULONG xpfnProc\n    );\n#endif\n\n// private // before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallHwndParamLock(\n    _In_ HWND hwnd,\n    _In_ ULONG_PTR Param,\n    _In_ ULONG xpfnProc\n    );\n\n// private // before WIN11\n#if (PHNT_VERSION >= PHNT_WINDOWS_10_RS5)\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallHwndParamLockSafe(\n    _In_ HWND hwnd,\n    _In_ ULONG_PTR Param,\n    _In_ ULONG xpfnProc\n    );\n#endif\n\n// private // before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserCallTwoParam(\n    _In_ ULONG_PTR Param1,\n    _In_ ULONG_PTR Param2,\n    _In_ ULONG xpfnProc\n    );\n\n#if (PHNT_VERSION >= PHNT_WINDOWS_11)\n\n// private // NtUserCallNoParam(SFI_CREATEMENU) before WIN11\n_Success_(return != NULL)\n_Must_inspect_result_\nNTSYSCALLAPI\nHMENU\nNTAPI\nNtUserCreateMenu(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_CREATEPOPUPMENU) before WIN11\n_Success_(return != NULL)\n_Must_inspect_result_\nNTSYSCALLAPI\nHMENU\nNTAPI\nNtUserCreatePopupMenu(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_ALLOWFOREGROUNDACTIVATION) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserAllowForegroundActivation(\n    VOID\n    );\n\n// rev // NtUserCallNoParam(SFI_CANCELQUEUEEVENTCOMPLETIONPACKET) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserCancelQueueEventCompletionPacket(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_CLEARWAKEMASK) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserClearWakeMask(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_CREATESYSTEMTHREADS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserCreateSystemThreads(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_DESTROYCARET) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserDestroyCaret(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_DISABLEPROCESSWINDOWSGHOSTING) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserDisableProcessWindowsGhosting(\n    VOID\n    );\n\n// rev // NtUserCallNoParam(SFI_DRAINTHREADCOREMESSAGINGCOMPLETIONS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserDrainThreadCoreMessagingCompletions(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_GETDEVICECHANGEINFO) before WIN11\n_Success_(return != 0)\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetDeviceChangeInfo(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_GETIMESHOWSTATUS) before WIN11\n_Success_(return != 0)\n_Must_inspect_result_\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserGetIMEShowStatus(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_GETINPUTDESKTOP) before WIN11\n_Success_(return != NULL)\n_Must_inspect_result_\nNTSYSCALLAPI\nHDESK\nNTAPI\nNtUserGetInputDesktop(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_GETMESSAGEPOS) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetMessagePos(\n    VOID\n    );\n\n// rev // NtUserCallNoParam(SFI_GETQUEUEIOCP) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserGetQueueIocp(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_GETUNPREDICTEDMESSAGEPOS) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetUnpredictedMessagePos(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_HANDLESYSTEMTHREADCREATIONFAILURE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserHandleSystemThreadCreationFailure(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_HIDECURSORNOCAPTURE) before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserHideCursorNoCapture(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_ISQUEUEATTACHED) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserIsQueueAttached(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_LOADCURSORSANDICONS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserLoadCursorsAndIcons(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_LOADUSERAPIHOOK) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserLoadUserApiHook(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_PREPAREFORLOGOFF) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserPrepareForLogoff(\n    VOID\n    );\n\n// rev // NtUserCallNoParam(SFI_REASSOCIATEQUEUEEVENTCOMPLETIONPACKET) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserReassociateQueueEventCompletionPacket(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_RELEASECAPTURE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserReleaseCapture(\n    VOID\n    );\n\n// rev // NtUserCallNoParam(SFI_REMOVEQUEUECOMPLETION) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRemoveQueueCompletion(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_RESETDBLCLK) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserResetDblClk(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_ZAPACTIVEANDFOCUS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserZapActiveAndFocus(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_REMOTECONSOLESHADOWSTOP) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemoteConsoleShadowStop(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_REMOTEDISCONNECT) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemoteDisconnect(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_REMOTESHADOWSETUP) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemoteShadowSetup(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_REMOTESHADOWSTOP) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemoteShadowStop(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_REMOTEPASSTHRUENABLE) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemotePassthruEnable(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_REMOTEPASSTHRUDISABLE) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemotePassthruDisable(\n    VOID\n    );\n\n// private\n#define CTX_W32_CONNECT_STATE_CONSOLE           0\n#define CTX_W32_CONNECT_STATE_IDLE              1\n#define CTX_W32_CONNECT_STATE_EXIT_IN_PROGRESS  2\n#define CTX_W32_CONNECT_STATE_CONNECTED         3\n#define CTX_W32_CONNECT_STATE_DISCONNECTED      4\n\n// private // NtUserCallNoParam(SFI_REMOTECONNECTSTATE) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserRemoteConnectState(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_UPDATEPERUSERIMMENABLING) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserUpdatePerUserImmEnabling(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_USERPOWERCALLOUTWORKER) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserUserPowerCalloutWorker(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_WAKERITFORSHUTDOWN) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserWakeRITForShutdown(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_DOINITMESSAGEPUMPHOOK) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserDoInitMessagePumpHook(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_DOUNINITMESSAGEPUMPHOOK) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserDoUninitMessagePumpHook(\n    VOID\n    );\n\n// rev // NtUserCallNoParam(SFI_ENABLEMOUSEINPOINTERFORTHREAD) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserEnableMouseInPointerForThread(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_DEFERREDDESKTOPROTATION) before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserDeferredDesktopRotation(\n    VOID\n    );\n\n// private // NtUserCallNoParam(SFI_ENABLEPERMONITORMENUSCALING) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserEnablePerMonitorMenuScaling(\n    VOID\n    );\n\n// private // NtUserCallOneParam(SFI_BEGINDEFERWINDOWPOS) before WIN11\n_Success_(return != NULL)\n_Must_inspect_result_\nNTSYSCALLAPI\nHDWP\nNTAPI\nNtUserBeginDeferWindowPos(\n    _In_ ULONG NumWindowsHint\n    );\n\n// private // NtUserCallOneParam(SFI_GETSENDMESSAGERECEIVER) before WIN11\n_Success_(return != NULL)\n_Must_inspect_result_\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserGetSendMessageReceiver(\n    _In_ ULONG ThreadIdSender\n    );\n\n// private // NtUserCallOneParam(SFI_ALLOWSETFOREGROUNDWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserAllowSetForegroundWindow(\n    _In_ ULONG ProcessId\n    );\n\n// private // NtUserCallOneParam(SFI_CSDDEUNINITIALIZE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserCsDdeUninitialize(\n    _In_ HANDLE hInst\n    );\n\n// private // NtUserCallOneParam(SFI_ENUMCLIPBOARDFORMATS) before WIN11\n_Success_(return != 0)\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserEnumClipboardFormats(\n    _In_ ULONG Format\n    );\n\n// private // NtUserCallOneParam(SFI_GETINPUTEVENT) before WIN11\n_Success_(return != NULL)\n_Must_inspect_result_\nNTSYSCALLAPI\nHANDLE\nNTAPI\nNtUserGetInputEvent(\n    _In_ ULONG WakeMask // QS_* WinUser.h\n    );\n\n// rev (MSDN)\n#define KEYBOARD_TYPE           0\n#define KEYBOARD_SUBTYPE        1\n#define KEYBOARD_FUNCTION_KEY   2\n\n// private // NtUserCallOneParam(SFI_GETKEYBOARDTYPE) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetKeyboardType(\n    _In_ ULONG TypeFlag // KEYBOARD_*\n    );\n\n// private // NtUserCallOneParam(SFI_GETPROCESSDEFAULTLAYOUT) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserGetProcessDefaultLayout(\n    _Out_ PULONG DefaultLayout\n    );\n\n// private\n#define WPROTOCOLNAME_LENGTH    10\n#define WAUDIONAME_LENGTH       10\n\n// private\ntypedef struct tagWSINFO\n{\n    WCHAR ProtocolName[WPROTOCOLNAME_LENGTH];\n    WCHAR AudioDriverName[WAUDIONAME_LENGTH];\n} WSINFO, *PWSINFO;\n\n// private // NtUserCallOneParam(SFI_GETWINSTATIONINFO) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserGetWinStationInfo(\n    _Out_ PWSINFO WsInfo\n    );\n\n// private // NtUserCallOneParam(SFI_LOCKSETFOREGROUNDWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserLockSetForegroundWindow(\n    _In_ ULONG LockCode // LSFW_* WinUser.h\n    );\n\n// private // NtUserCallOneParam(SFI_LW_LOADFONTS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserLW_LoadFonts(\n    _In_ LOGICAL Remote\n    );\n\n// private // NtUserCallOneParam(SFI_MAPDESKTOPOBJECT) before WIN11\n_Success_(return != NULL)\n_Must_inspect_result_\n_Ret_maybenull_\nNTSYSCALLAPI\nPVOID\nNTAPI\nNtUserMapDesktopObject(\n    _In_ HANDLE h\n    );\n\n// private // NtUserCallOneParam(SFI_MESSAGEBEEP) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserMessageBeep(\n    _In_ ULONG Type // MB_* (MB_ICONMASK) WinUser.h\n    );\n\n// private\n#define USER_SOUND_DEFAULT              0\n#define USER_SOUND_SYSTEMHAND           1\n#define USER_SOUND_SYSTEMQUESTION       2\n#define USER_SOUND_SYSTEMEXCLAMATION    3\n#define USER_SOUND_SYSTEMASTERISK       4\n#define USER_SOUND_MENUPOPUP            5\n#define USER_SOUND_MENUCOMMAND          6\n#define USER_SOUND_OPEN                 7\n#define USER_SOUND_CLOSE                8\n#define USER_SOUND_RESTOREUP            9\n#define USER_SOUND_RESTOREDOWN          10\n#define USER_SOUND_MINIMIZE             11\n#define USER_SOUND_MAXIMIZE             12\n#define USER_SOUND_SNAPSHOT             13\n\n// private // NtUserCallOneParam(SFI_PLAYEVENTSOUND) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserPlayEventSound(\n    _In_ ULONG idSound // USER_SOUND_*\n    );\n\n// private // NtUserCallOneParam(SFI_POSTQUITMESSAGE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserPostQuitMessage(\n    _In_ LONG ExitCode\n    );\n\n// private // NtUserCallOneParam(SFI_REALIZEPALETTE) before WIN11\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserRealizePalette(\n    _In_ HDC hdc\n    );\n\n// private\n#define LPK_TABBED_TEXT_OUT 0\n#define LPK_PSM_TEXT_OUT    1\n#define LPK_DRAW_TEXT_EX    2\n#define LPK_EDIT_CONTROL    3\n\n// rev\n#define LPK_FLAG_TABBED_TEXT_OUT (1 << LPK_TABBED_TEXT_OUT)\n#define LPK_FLAG_PSM_TEXT_OUT    (1 << LPK_PSM_TEXT_OUT)\n#define LPK_FLAG_DRAW_TEXT_EX    (1 << LPK_DRAW_TEXT_EX)\n#define LPK_FLAG_EDIT_CONTROL    (1 << LPK_EDIT_CONTROL)\n\n// private // NtUserCallOneParam(SFI_REGISTERLPK) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRegisterLPK(\n    _In_ ULONG LpkEntryPoints // LPK_FLAG_*\n    );\n\n// private\n#define RST_DONTATTACHQUEUE     0x00000001\n#define RST_DONTJOURNALATTACH   0x00000002\n\n// private // NtUserCallOneParam(SFI_REGISTERSYSTEMTHREAD) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRegisterSystemThread(\n    _In_ ULONG Flags // RST_*\n    );\n\n// private // NtUserCallOneParam(SFI_REMOTERECONNECT) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemoteReconnect(\n    _In_ struct _DOCONNECTDATA* DoConnectData\n    );\n\n// private // NtUserCallOneParam(SFI_REMOTETHINWIRESTATS) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemoteThinwireStats(\n    _Out_ struct CACHE_STATISTICS* Stats\n    );\n\n// private // NtUserCallOneParam(SFI_REMOTENOTIFY) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemoteNotify(\n    _In_ struct _DONOTIFYDATA* DoNotifyData\n    );\n\n// private // NtUserCallOneParam(SFI_REPLYMESSAGE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserReplyMessage(\n    _In_ LRESULT Result\n    );\n\n// private // NtUserCallOneParam(SFI_SETCARETBLINKTIME) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetCaretBlinkTime(\n    _In_ ULONG Milliseconds\n    );\n\n// private // NtUserCallOneParam(SFI_SETDOUBLECLICKTIME) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetDoubleClickTime(\n    _In_ ULONG Milliseconds\n    );\n\n// private // NtUserCallOneParam(SFI_SETMESSAGEEXTRAINFO) before WIN11\nNTSYSCALLAPI\nLPARAM\nNTAPI\nNtUserSetMessageExtraInfo(\n    _In_ LPARAM Param\n    );\n\n// private // NtUserCallOneParam(SFI_SETPROCESSDEFAULTLAYOUT) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetProcessDefaultLayout(\n    _In_ ULONG DefaultLayout // LAYOUT_* wingdi.h\n    );\n\n// private // NtUserCallOneParam(SFI_SETWATERMARKSTRINGS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetWatermarkStrings(\n    _In_ PCUNICODE_STRING StringTable\n    );\n\n// private // NtUserCallOneParam(SFI_SHOWSTARTGLASS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserShowStartGlass(\n    _In_ ULONG Timeout\n    );\n\n// private // NtUserCallOneParam(SFI_SWAPMOUSEBUTTON) before WIN11\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSwapMouseButton(\n    _In_ LOGICAL SwapButtons\n    );\n\n// private // NtUserCallOneParam(SFI_WOWMODULEUNLOAD) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserWOWModuleUnload(\n    _In_ HANDLE Module\n    );\n\n// private // NtUserCallOneParam(SFI_DWMLOCKSCREENUPDATES) before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserDwmLockScreenUpdates(\n    _In_ LOGICAL LockUpdates\n    );\n\n// private // NtUserCallOneParam(SFI_ENABLESESSIONFORMMCSS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserEnableSessionForMMCSS(\n    _In_ LOGICAL Enable\n    );\n\n// private // NtUserCallOneParam(SFI_SETWAITFORQUEUEATTACH) before WIN11\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetWaitForQueueAttach(\n    _In_ LOGICAL Waiting\n    );\n\n// private // NtUserCallOneParam(SFI_THREADMESSAGEQUEUEATTACHED) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserThreadMessageQueueAttached(\n    _In_opt_ ULONG ThreadId\n    );\n\n// private // NtUserCallOneParam(SFI_ENSUREDPIDEPSYSMETCACHEFORPLATEAU) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserEnsureDpiDepSysMetCacheForPlateau(\n    _In_ ULONG Dpi\n    );\n\n// private // NtUserCallOneParam(SFI_FORCEENABLENUMPADTRANSLATION) before WIN11\nNTSYSCALLAPI\nUINT_PTR\nNTAPI\nNtUserForceEnableNumpadTranslation(\n    _In_ LOGICAL ForceNumlockTranslation\n    );\n\n// rev // NtUserCallOneParam(SFI_SETTSFEVENTSTATE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetTSFEventState(\n    _In_ ULONG StateFlags\n    );\n\n// rev // NtUserCallOneParam(SFI_SETSHELLCHANGENOTIFYHWND) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetShellChangeNotifyHWND(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwnd(SFI_DEREGISTERSHELLHOOKWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserDeregisterShellHookWindow(\n    _In_ HWND hwnd\n    );\n\n// rev // NtUserCallHwnd(SFI_DWP_GETENABLEDPOPUPOFFSET) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserDWP_GetEnabledPopupOffset(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwnd(SFI_GETMODERNAPPWINDOW) before WIN11\n_Success_(return != NULL)\n_Must_inspect_result_\nNTSYSCALLAPI\nHWND\nNTAPI\nNtUserGetModernAppWindow(\n    _In_ HWND ShellFrame\n    );\n\n// private // NtUserCallHwnd(SFI_GETWINDOWCONTEXTHELPID) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserGetWindowContextHelpId(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwnd(SFI_REGISTERSHELLHOOKWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRegisterShellHookWindow(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwnd(SFI_SETMSGBOX) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetMsgBox(\n    _In_ HWND hwnd\n    );\n\n// rev // NtUserCallHwnd[Safe](SFI_INITTHREADCOREMESSAGINGIOCP) before WIN11\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserInitThreadCoreMessagingIocp(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwnd[Safe](SFI_SCHEDULEDISPATCHNOTIFICATION) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserScheduleDispatchNotification(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndOpt(SFI_SETPROGMANWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetProgmanWindow(\n    _In_opt_ HWND hwnd\n    );\n\n// private // NtUserCallHwndOpt(SFI_SETTASKMANWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetTaskmanWindow(\n    _In_opt_ HWND hwnd\n    );\n\n// private // NtUserCallHwndParam(SFI_GETCLASSICOCUR) before WIN11\n_Success_(return != NULL)\n_Must_inspect_result_\nNTSYSCALLAPI\nHCURSOR\nNTAPI\nNtUserGetClassIcoCur(\n    _In_ HWND hwnd,\n    _In_ ULONG Index\n    );\n\n// private\n#define WFWIN40COMPAT           0x0502\n#define WFNOANIMATE             0x0710\n#define WEFWINDOWEDGE           0x0901\n#define WEFCLIENTEDGE           0x0902\n#define WEFSTATICEDGE           0x0A02\n#define BFRIGHTBUTTON           0x0C20\n#define BFRIGHT                 0x0D02\n#define BFBOTTOM                0x0D08\n#define DFLOCALEDIT             0x0C20\n#define CBFOWNERDRAWVAR         0x0C20\n#define CBFHASSTRINGS           0x0D02\n#define CBFDISABLENOSCROLL      0x0D08\n#define EFPASSWORD              0x0C20\n#define EFCOMBOBOX              0x0D02\n#define EFREADONLY              0x0D08\n#define SFWIDELINESPACING       0x0C20\n#define SFCENTERIMAGE           0x0D02\n#define SFREALSIZEIMAGE         0x0D08\n#define WFMAXBOX                0x0E01\n#define WFTABSTOP               0x0E01\n#define WFSYSMENU               0x0E08\n#define WFHSCROLL               0x0E10\n#define WFVSCROLL               0x0E20\n#define WFBORDER                0x0E80\n#define WFCLIPCHILDREN          0x0F02\n\n// private // NtUserCallHwndParam(SFI_CLEARWINDOWSTATE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserClearWindowState(\n    _In_ HWND hwnd,\n    _In_ ULONG Flag // WF*, WEF*, BF*, DF*, CBF*, EF*, SF*\n    );\n\n// private // NtUserCallHwndParam(SFI_SETWINDOWSTATE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetWindowState(\n    _In_ HWND hwnd,\n    _In_ ULONG Flag // WF*, WEF*, BF*, DF*, CBF*, EF*, SF*\n    );\n\n// private // NtUserCallHwndParam(SFI_KILLSYSTEMTIMER) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserKillSystemTimer(\n    _In_ HWND hwnd,\n    _In_ UINT_PTR IDEvent\n    );\n\n// private // NtUserCallHwndParam(SFI_NOTIFYOVERLAYWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserNotifyOverlayWindow(\n    _In_ HWND hwnd,\n    _In_ LOGICAL Enable\n    );\n\n// private // NtUserCallHwndParam(SFI_SETDIALOGPOINTER) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetDialogPointer(\n    _In_ HWND hwnd,\n    _In_ ULONG_PTR Ptr\n    );\n\n// private\n#define SV_UNSET            0x0000\n#define SV_SET              0x0001\n#define SV_CLRFTRUEVIS      0x0002\n#define SV_SKIPCOMPOSE      0x0004 // rev\n#define SV_CLRFULLSCREEN    0x0008 // rev\n#define SV_CLRGHOSTVIS      0x0010 // rev\n\n// private // NtUserCallHwndParam(SFI_SETVISIBLE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetVisible(\n    _In_ HWND hwnd,\n    _In_ ULONG Flags // SV_*\n    );\n\n// private // NtUserCallHwndParam(SFI_SETWINDOWCONTEXTHELPID) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetWindowContextHelpId(\n    _In_ HWND hwnd,\n    _In_ ULONG ContextId\n    );\n\n// private // NtUserCallHwndParam(SFI_REGISTERWINDOWARRANGEMENTCALLOUT) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRegisterWindowArrangementCallout(\n    _In_ HWND hwnd,\n    _In_ LOGICAL Register\n    );\n\n// private // NtUserCallHwndParam(SFI_ENABLEMODERNAPPWINDOWKEYBOARDINTERCEPT) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserEnableModernAppWindowKeyboardIntercept(\n    _In_ HWND hwnd,\n    _In_ LOGICAL Enable\n    );\n\n// private // NtUserCallHwndLock(SFI_ARRANGEICONICWINDOWS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nULONG\nNTAPI\nNtUserArrangeIconicWindows(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_DRAWMENUBAR) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserDrawMenuBar(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock[Safe](SFI_CHECKIMESHOWSTATUSINTHREAD) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserCheckImeShowStatusInThread(\n    _In_ HWND Ime\n    );\n\n// rev // NtUserCallHwndLock(SFI_GETSYSMENUOFFSET) before WIN11\n_Success_(return != 0)\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserGetSysMenuOffset(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_REDRAWFRAME) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRedrawFrame(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_REDRAWFRAMEANDHOOK) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRedrawFrameAndHook(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_SETDIALOGSYSTEMMENU) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetDialogSystemMenu(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_SETFOREGROUNDWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetForegroundWindow(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_SETSYSMENU) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetSysMenu(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_UPDATECLIENTRECT) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserUpdateClientRect(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_UPDATEWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserUpdateWindow(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_SETCANCELROTATIONDELAYHINTWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetCancelRotationDelayHintWindow(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndLock(SFI_GETWINDOWTRACKINFOASYNC) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserGetWindowTrackInfoAsync(\n    _In_ HWND hwnd\n    );\n\n// private // NtUserCallHwndParamLock(SFI_BROADCASTIMESHOWSTATUSCHANGE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserBroadcastImeShowStatusChange(\n    _In_ HWND Ime,\n    _In_ LOGICAL Show\n    );\n\n// private // NtUserCallHwndParamLock(SFI_SETMODERNAPPWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetModernAppWindow(\n    _In_ HWND ShellFrame,\n    _In_ HWND App\n    );\n\n// private\n// #define DC_ACTIVE    0x0001 // WinUser.h\n// #define DC_SMALLCAP  0x0002 // WinUser.h\n// #define DC_ICON      0x0004 // WinUser.h\n// #define DC_TEXT      0x0008 // WinUser.h\n// #define DC_INBUTTON  0x0010 // WinUser.h\n// #define DC_GRADIENT  0x0020 // WinUser.h\n#define DC_LAMEBUTTON   0x0400\n#define DC_NOVISIBLE    0x0800\n// #define DC_BUTTONS   0x1000 // WinUser.h\n#define DC_NOSENDMSG    0x2000\n#define DC_CENTER       0x4000\n#define DC_FRAME        0x8000\n\n// private // NtUserCallHwndParamLock(SFI_REDRAWTITLE) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRedrawTitle(\n    _In_ HWND hwnd,\n    _In_ ULONG Flags // DC_*\n    );\n\n// private // NtUserCallHwndParamLock(SFI_SHOWOWNEDPOPUPS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserShowOwnedPopups(\n    _In_ HWND Owner,\n    _In_ LOGICAL Show\n    );\n\n// private // NtUserCallHwndParamLock(SFI_SWITCHTOTHISWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSwitchToThisWindow(\n    _In_ HWND hwnd,\n    _In_ LOGICAL AltTab\n    );\n\n// private // NtUserCallHwndParamLock(SFI_UPDATEWINDOWS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserUpdateWindows(\n    _In_ HWND hwnd,\n    _In_ HRGN hrgn\n    );\n\n// private // NtUserCallHwndParamLock(SFI_VALIDATERGN) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserValidateRgn(\n    _In_ HWND hwnd,\n    _In_ HRGN hrgn\n    );\n\n// private // NtUserCallHwndParamLock[Safe](SFI_ENABLEWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserEnableWindow(\n    _In_ HWND hwnd,\n    _In_ LOGICAL Enable\n    );\n\n// private // NtUserCallTwoParam(SFI_CHANGEWINDOWMESSAGEFILTER) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserChangeWindowMessageFilter(\n    _In_ ULONG Message,\n    _In_ ULONG Flag // MSGFLT_* WinUser.h\n    );\n\n// rev\n#define CURSOR_POS_TYPE_LOGICAL 1\n#define CURSOR_POS_TYPE_SAVED   2\n\n// private // NtUserCallTwoParam(SFI_GETCURSORPOS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserGetCursorPos(\n    _Out_ PPOINT Point,\n    _In_ ULONG CursorPosType // CURSOR_POS_TYPE_*\n    );\n\n// private // NtUserCallTwoParam(SFI_INITANSIOEM) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserInitAnsiOem(\n    _In_reads_(256) PCHAR OemToAnsi,\n    _In_reads_(256) PCHAR AnsiToOem\n    );\n\n// private // NtUserCallTwoParam(SFI_NLSKBDSENDIMENOTIFICATION) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserNlsKbdSendIMENotification(\n    _In_ ULONG ImeOpen,\n    _In_ ULONG ImeConversion\n    );\n\n// private // NtUserCallTwoParam(SFI_REGISTERGHOSTWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRegisterGhostWindow(\n    _In_ HWND Ghost,\n    _In_ HWND Hung\n    );\n\n// private // NtUserCallTwoParam(SFI_REGISTERLOGONPROCESS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRegisterLogonProcess(\n    _In_ ULONG ProcessId,\n    _In_ PLUID LuidConnect\n    );\n\n// private // NtUserCallTwoParam(SFI_REGISTERSIBLINGFROSTWINDOW) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRegisterSiblingFrostWindow(\n    _In_ HWND hwndFrost,\n    _In_ HWND hwnd\n    );\n\n// rev\ntypedef _Function_class_(FNW32ET)\nVOID APIENTRY FNW32ET(VOID);\ntypedef FNW32ET* PFNW32ET;\n\n// private // NtUserCallTwoParam(SFI_REGISTERUSERHUNGAPPHANDLERS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserRegisterUserHungAppHandlers(\n    _In_ PFNW32ET W32EndTask,\n    _In_ HANDLE EventWowExec\n    );\n\n// private // NtUserCallTwoParam(SFI_REMOTESHADOWCLEANUP) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemoteShadowCleanup(\n    _In_reads_bytes_(ThinwireDataLength) PVOID ThinwireData,\n    _In_ ULONG ThinwireDataLength\n    );\n\n// private // NtUserCallTwoParam(SFI_REMOTESHADOWSTART) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserRemoteShadowStart(\n    _In_reads_bytes_(ThinwireDataLength) PVOID ThinwireData,\n    _In_ ULONG ThinwireDataLength\n    );\n\n// private // NtUserCallTwoParam(SFI_SETCARETPOS) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetCaretPos(\n    _In_ LONG x,\n    _In_ LONG y\n    );\n\n// private // NtUserCallTwoParam(SFI_SETTHREADQUEUEMERGESETTING) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserSetThreadQueueMergeSetting(\n    _In_ ULONG ThreadId,\n    _In_ ULONG Flags\n    );\n\n// private // NtUserCallTwoParam(SFI_UNHOOKWINDOWSHOOK) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserUnhookWindowsHook(\n    _In_ LONG FilterType,\n    _In_ HOOKPROC FilterProc\n    );\n\n// private // NtUserCallTwoParam(SFI_ENABLESHELLWINDOWMANAGEMENTBEHAVIOR) before WIN11\n_Success_(return != 0)\nNTSYSCALLAPI\nLOGICAL\nNTAPI\nNtUserEnableShellWindowManagementBehavior(\n    _In_ ULONG_PTR Param1,\n    _In_ ULONG_PTR Param2\n    );\n\n// private // NtUserCallTwoParam(SFI_CITSETINFO) before WIN11\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUserCitSetInfo(\n    _In_ ULONG_PTR InfoFlags,\n    _In_ ULONG_PTR Info\n    );\n\n// private // NtUserCallTwoParam(SFI_SCALESYSTEMMETRICFORDPIWITHOUTCACHE) before WIN11\n_Must_inspect_result_\nNTSYSCALLAPI\nULONG_PTR\nNTAPI\nNtUserScaleSystemMetricForDPIWithoutCache(\n    _In_ ULONG Metric,\n    _In_ ULONG ToDpi\n    );\n\n#endif // PHNT_VERSION >= PHNT_WINDOWS_11\n\ntypedef _Function_class_(FN_DISPATCH)\nNTSTATUS NTAPI FN_DISPATCH(\n    _In_opt_ PVOID Context\n    );\ntypedef FN_DISPATCH* PFN_DISPATCH;\n\n// Peb!KernelCallbackTable = user32.dll!apfnDispatch\ntypedef struct _KERNEL_CALLBACK_TABLE\n{\n    PFN_DISPATCH __fnCOPYDATA;\n    PFN_DISPATCH __fnCOPYGLOBALDATA;\n    PFN_DISPATCH __fnEMPTY1;\n    PFN_DISPATCH __fnNCDESTROY;\n    PFN_DISPATCH __fnDWORDOPTINLPMSG;\n    PFN_DISPATCH __fnINOUTDRAG;\n    PFN_DISPATCH __fnGETTEXTLENGTHS1;\n    PFN_DISPATCH __fnINCNTOUTSTRING;\n    PFN_DISPATCH __fnINCNTOUTSTRINGNULL;\n    PFN_DISPATCH __fnINLPCOMPAREITEMSTRUCT;\n    PFN_DISPATCH __fnINLPCREATESTRUCT;\n    PFN_DISPATCH __fnINLPDELETEITEMSTRUCT;\n    PFN_DISPATCH __fnINLPDRAWITEMSTRUCT;\n    PFN_DISPATCH __fnPOPTINLPUINT1;\n    PFN_DISPATCH __fnPOPTINLPUINT2;\n    PFN_DISPATCH __fnINLPMDICREATESTRUCT;\n    PFN_DISPATCH __fnINOUTLPMEASUREITEMSTRUCT;\n    PFN_DISPATCH __fnINLPWINDOWPOS;\n    PFN_DISPATCH __fnINOUTLPPOINT51;\n    PFN_DISPATCH __fnINOUTLPSCROLLINFO;\n    PFN_DISPATCH __fnINOUTLPRECT;\n    PFN_DISPATCH __fnINOUTNCCALCSIZE;\n    PFN_DISPATCH __fnINOUTLPPOINT52;\n    PFN_DISPATCH __fnINPAINTCLIPBRD;\n    PFN_DISPATCH __fnINSIZECLIPBRD;\n    PFN_DISPATCH __fnINDESTROYCLIPBRD;\n    PFN_DISPATCH __fnINSTRINGNULL1;\n    PFN_DISPATCH __fnINSTRINGNULL2;\n    PFN_DISPATCH __fnINDEVICECHANGE;\n    PFN_DISPATCH __fnPOWERBROADCAST;\n    PFN_DISPATCH __fnINLPUAHDRAWMENU1;\n    PFN_DISPATCH __fnOPTOUTLPDWORDOPTOUTLPDWORD1;\n    PFN_DISPATCH __fnOPTOUTLPDWORDOPTOUTLPDWORD2;\n    PFN_DISPATCH __fnOUTDWORDINDWORD;\n    PFN_DISPATCH __fnOUTLPRECT;\n    PFN_DISPATCH __fnOUTSTRING;\n    PFN_DISPATCH __fnPOPTINLPUINT3;\n    PFN_DISPATCH __fnPOUTLPINT;\n    PFN_DISPATCH __fnSENTDDEMSG;\n    PFN_DISPATCH __fnINOUTSTYLECHANGE1;\n    PFN_DISPATCH __fnHkINDWORD;\n    PFN_DISPATCH __fnHkINLPCBTACTIVATESTRUCT;\n    PFN_DISPATCH __fnHkINLPCBTCREATESTRUCT;\n    PFN_DISPATCH __fnHkINLPDEBUGHOOKSTRUCT;\n    PFN_DISPATCH __fnHkINLPMOUSEHOOKSTRUCTEX1;\n    PFN_DISPATCH __fnHkINLPKBDLLHOOKSTRUCT;\n    PFN_DISPATCH __fnHkINLPMSLLHOOKSTRUCT;\n    PFN_DISPATCH __fnHkINLPMSG;\n    PFN_DISPATCH __fnHkINLPRECT;\n    PFN_DISPATCH __fnHkOPTINLPEVENTMSG;\n    PFN_DISPATCH __xxxClientCallDelegateThread;\n    PFN_DISPATCH __ClientCallDummyCallback1;\n    PFN_DISPATCH __ClientCallDummyCallback2;\n    PFN_DISPATCH __fnSHELLWINDOWMANAGEMENTCALLOUT;\n    PFN_DISPATCH __fnSHELLWINDOWMANAGEMENTNOTIFY;\n    PFN_DISPATCH __ClientCallDummyCallback3;\n    PFN_DISPATCH __xxxClientCallDitThread;\n    PFN_DISPATCH __xxxClientEnableMMCSS;\n    PFN_DISPATCH __xxxClientUpdateDpi;\n    PFN_DISPATCH __xxxClientExpandStringW;\n    PFN_DISPATCH __ClientCopyDDEIn1;\n    PFN_DISPATCH __ClientCopyDDEIn2;\n    PFN_DISPATCH __ClientCopyDDEOut1;\n    PFN_DISPATCH __ClientCopyDDEOut2;\n    PFN_DISPATCH __ClientCopyImage;\n    PFN_DISPATCH __ClientEventCallback;\n    PFN_DISPATCH __ClientFindMnemChar;\n    PFN_DISPATCH __ClientFreeDDEHandle;\n    PFN_DISPATCH __ClientFreeLibrary;\n    PFN_DISPATCH __ClientGetCharsetInfo;\n    PFN_DISPATCH __ClientGetDDEFlags;\n    PFN_DISPATCH __ClientGetDDEHookData;\n    PFN_DISPATCH __ClientGetListboxString;\n    PFN_DISPATCH __ClientGetMessageMPH;\n    PFN_DISPATCH __ClientLoadImage;\n    PFN_DISPATCH __ClientLoadLibrary;\n    PFN_DISPATCH __ClientLoadMenu;\n    PFN_DISPATCH __ClientLoadLocalT1Fonts;\n    PFN_DISPATCH __ClientPSMTextOut;\n    PFN_DISPATCH __ClientLpkDrawTextEx;\n    PFN_DISPATCH __ClientExtTextOutW;\n    PFN_DISPATCH __ClientGetTextExtentPointW;\n    PFN_DISPATCH __ClientCharToWchar;\n    PFN_DISPATCH __ClientAddFontResourceW;\n    PFN_DISPATCH __ClientThreadSetup;\n    PFN_DISPATCH __ClientDeliverUserApc;\n    PFN_DISPATCH __ClientNoMemoryPopup;\n    PFN_DISPATCH __ClientMonitorEnumProc;\n    PFN_DISPATCH __ClientCallWinEventProc;\n    PFN_DISPATCH __ClientWaitMessageExMPH;\n    PFN_DISPATCH __ClientCallDummyCallback4;\n    PFN_DISPATCH __ClientCallDummyCallback5;\n    PFN_DISPATCH __ClientImmLoadLayout;\n    PFN_DISPATCH __ClientImmProcessKey;\n    PFN_DISPATCH __fnIMECONTROL;\n    PFN_DISPATCH __fnINWPARAMDBCSCHAR;\n    PFN_DISPATCH __fnGETTEXTLENGTHS2;\n    PFN_DISPATCH __ClientCallDummyCallback6;\n    PFN_DISPATCH __ClientLoadStringW;\n    PFN_DISPATCH __ClientLoadOLE;\n    PFN_DISPATCH __ClientRegisterDragDrop;\n    PFN_DISPATCH __ClientRevokeDragDrop;\n    PFN_DISPATCH __fnINOUTMENUGETOBJECT;\n    PFN_DISPATCH __ClientPrinterThunk;\n    PFN_DISPATCH __fnOUTLPCOMBOBOXINFO;\n    PFN_DISPATCH __fnOUTLPSCROLLBARINFO;\n    PFN_DISPATCH __fnINLPUAHDRAWMENU2;\n    PFN_DISPATCH __fnINLPUAHDRAWMENUITEM;\n    PFN_DISPATCH __fnINLPUAHDRAWMENU3;\n    PFN_DISPATCH __fnINOUTLPUAHMEASUREMENUITEM;\n    PFN_DISPATCH __fnINLPUAHDRAWMENU4;\n    PFN_DISPATCH __fnOUTLPTITLEBARINFOEX;\n    PFN_DISPATCH __fnTOUCH;\n    PFN_DISPATCH __fnGESTURE;\n    PFN_DISPATCH __fnPOPTINLPUINT4;\n    PFN_DISPATCH __fnPOPTINLPUINT5;\n    PFN_DISPATCH __xxxClientCallDefaultInputHandler;\n    PFN_DISPATCH __fnEMPTY2;\n    PFN_DISPATCH __ClientRimDevCallback;\n    PFN_DISPATCH __xxxClientCallMinTouchHitTestingCallback;\n    PFN_DISPATCH __ClientCallLocalMouseHooks;\n    PFN_DISPATCH __xxxClientBroadcastThemeChange;\n    PFN_DISPATCH __xxxClientCallDevCallbackSimple;\n    PFN_DISPATCH __xxxClientAllocWindowClassExtraBytes;\n    PFN_DISPATCH __xxxClientFreeWindowClassExtraBytes;\n    PFN_DISPATCH __fnGETWINDOWDATA;\n    PFN_DISPATCH __fnINOUTSTYLECHANGE2;\n    PFN_DISPATCH __fnHkINLPMOUSEHOOKSTRUCTEX2;\n    PFN_DISPATCH __xxxClientCallDefWindowProc;\n    PFN_DISPATCH __fnSHELLSYNCDISPLAYCHANGED;\n    PFN_DISPATCH __fnHkINLPCHARHOOKSTRUCT;\n    PFN_DISPATCH __fnINTERCEPTEDWINDOWACTION;\n    PFN_DISPATCH __xxxTooltipCallback;\n    PFN_DISPATCH __xxxClientInitPSBInfo;\n    PFN_DISPATCH __xxxClientDoScrollMenu;\n    PFN_DISPATCH __xxxClientEndScroll;\n    PFN_DISPATCH __xxxClientDrawSize;\n    PFN_DISPATCH __xxxClientDrawScrollBar;\n    PFN_DISPATCH __xxxClientHitTestScrollBar;\n    PFN_DISPATCH __xxxClientTrackInit;\n} KERNEL_CALLBACK_TABLE, *PKERNEL_CALLBACK_TABLE;\n\n#endif // _NTUSER_H\n"
  }
]